Merge "jquery.tablesorter: Fix pre-JS selector to match wikitext-generated sortable...
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 22 May 2019 17:11:17 +0000 (17:11 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 22 May 2019 17:11:17 +0000 (17:11 +0000)
2133 files changed:
.fresnel.yml
.gitignore
.phan/config.php [new file with mode: 0644]
.phan/internal_stubs/memcached.phan_php [new file with mode: 0644]
.phan/internal_stubs/oci8.phan_php [new file with mode: 0644]
.phan/internal_stubs/sqlsrv.phan_php [new file with mode: 0644]
.phan/internal_stubs/tideways.phan_php [new file with mode: 0644]
.phan/stubs/README [new file with mode: 0644]
.phan/stubs/excimer.php [new file with mode: 0644]
.phan/stubs/hhvm.php [new file with mode: 0644]
.phan/stubs/mail.php [new file with mode: 0644]
.phan/stubs/password.php [new file with mode: 0644]
.phan/stubs/phpunit4.php [new file with mode: 0644]
.phan/stubs/wikidiff.php [new file with mode: 0644]
.phpcs.xml
.stylelintrc.json
.travis.yml
Gruntfile.js
HISTORY
RELEASE-NOTES-1.33
RELEASE-NOTES-1.34 [new file with mode: 0644]
autoload.php
composer.json
docs/export-0.10.xsd
docs/extension.schema.v1.json
docs/extension.schema.v2.json
docs/hooks.txt
docs/kss/package.json
docs/scripts.txt
img_auth.php
includes/ActorMigration.php
includes/AjaxResponse.php
includes/AutoLoader.php
includes/Autopromote.php
includes/Block.php
includes/Category.php
includes/CommentStore.php
includes/ConfiguredReadOnlyMode.php
includes/ContentSecurityPolicy.php
includes/DefaultSettings.php
includes/Defines.php
includes/DevelopmentSettings.php
includes/EditPage.php
includes/Feed.php [deleted file]
includes/ForeignResourceManager.php
includes/ForkController.php
includes/FormOptions.php
includes/GlobalFunctions.php
includes/HistoryBlob.php [deleted file]
includes/Html.php
includes/Linker.php
includes/MWGrants.php
includes/MWNamespace.php
includes/MagicWord.php
includes/MagicWordArray.php
includes/MediaWiki.php
includes/MediaWikiServices.php
includes/MergeHistory.php
includes/Message.php
includes/MovePage.php
includes/OutputHandler.php
includes/OutputPage.php
includes/PHPVersionCheck.php
includes/PageProps.php
includes/PathRouter.php
includes/Permissions/PermissionManager.php [new file with mode: 0644]
includes/Pingback.php
includes/Preferences.php [deleted file]
includes/PrefixSearch.php [deleted file]
includes/ProtectionForm.php
includes/ReadOnlyMode.php
includes/Revision.php
includes/Revision/MainSlotRoleHandler.php
includes/Revision/RenderedRevision.php
includes/Revision/RevisionLookup.php
includes/Revision/RevisionStore.php
includes/RevisionList.php [deleted file]
includes/ServiceWiring.php
includes/Setup.php
includes/SiteConfiguration.php
includes/SiteStatsInit.php
includes/Storage/BlobStoreFactory.php
includes/Storage/DerivedPageDataUpdater.php
includes/Storage/NameTableStore.php
includes/Storage/PageEditStash.php [new file with mode: 0644]
includes/StubObject.php
includes/StubUserLang.php [new file with mode: 0644]
includes/TemplateParser.php
includes/Title.php
includes/TrackingCategories.php
includes/WebRequest.php
includes/WebRequestUpload.php
includes/WebStart.php
includes/WikiMap.php
includes/Xml.php
includes/actions/CreditsAction.php
includes/actions/HistoryAction.php
includes/actions/InfoAction.php
includes/actions/McrUndoAction.php
includes/actions/RawAction.php
includes/actions/RollbackAction.php
includes/actions/WatchAction.php
includes/actions/pagers/HistoryPager.php
includes/api/ApiAuthManagerHelper.php
includes/api/ApiBase.php
includes/api/ApiBlock.php
includes/api/ApiBlockInfoTrait.php [new file with mode: 0644]
includes/api/ApiComparePages.php
includes/api/ApiContinuationManager.php
includes/api/ApiDelete.php
includes/api/ApiErrorFormatter.php
includes/api/ApiErrorFormatter_BackCompat.php [new file with mode: 0644]
includes/api/ApiExpandTemplates.php
includes/api/ApiFeedRecentChanges.php
includes/api/ApiFeedWatchlist.php
includes/api/ApiFormatBase.php
includes/api/ApiFormatFeedWrapper.php
includes/api/ApiFormatRaw.php
includes/api/ApiFormatXmlRsd.php [new file with mode: 0644]
includes/api/ApiHelp.php
includes/api/ApiImageRotate.php
includes/api/ApiImport.php
includes/api/ApiImportReporter.php [new file with mode: 0644]
includes/api/ApiLogin.php
includes/api/ApiLogout.php
includes/api/ApiMain.php
includes/api/ApiOpenSearch.php
includes/api/ApiOpenSearchFormatJson.php [new file with mode: 0644]
includes/api/ApiPageSet.php
includes/api/ApiParse.php
includes/api/ApiQueryAllDeletedRevisions.php
includes/api/ApiQueryAllImages.php
includes/api/ApiQueryAllLinks.php
includes/api/ApiQueryAllPages.php
includes/api/ApiQueryAllRevisions.php
includes/api/ApiQueryAllUsers.php
includes/api/ApiQueryBase.php
includes/api/ApiQueryBlocks.php
includes/api/ApiQueryImageInfo.php
includes/api/ApiQueryInfo.php
includes/api/ApiQueryLogEvents.php
includes/api/ApiQueryRevisions.php
includes/api/ApiQueryRevisionsBase.php
includes/api/ApiQuerySearch.php
includes/api/ApiQuerySiteinfo.php
includes/api/ApiQueryUserContribs.php
includes/api/ApiQueryUserInfo.php
includes/api/ApiQueryWatchlist.php
includes/api/ApiResult.php
includes/api/ApiRevisionDelete.php
includes/api/ApiRsd.php
includes/api/ApiSetNotificationTimestamp.php
includes/api/ApiStashEdit.php
includes/api/ApiTag.php
includes/api/ApiUnblock.php
includes/api/ApiUndelete.php
includes/api/ApiUpload.php
includes/api/ApiUserrights.php
includes/api/i18n/ar.json
includes/api/i18n/ba.json
includes/api/i18n/cs.json
includes/api/i18n/de.json
includes/api/i18n/en-gb.json
includes/api/i18n/en.json
includes/api/i18n/es.json
includes/api/i18n/et.json
includes/api/i18n/fa.json
includes/api/i18n/fr.json
includes/api/i18n/gl.json
includes/api/i18n/he.json
includes/api/i18n/hu.json
includes/api/i18n/it.json
includes/api/i18n/ja.json
includes/api/i18n/ko.json
includes/api/i18n/ksh.json
includes/api/i18n/lb.json
includes/api/i18n/lt.json
includes/api/i18n/mk.json
includes/api/i18n/nb.json
includes/api/i18n/nl.json
includes/api/i18n/pl.json
includes/api/i18n/pt-br.json
includes/api/i18n/pt.json
includes/api/i18n/qqq.json
includes/api/i18n/ru.json
includes/api/i18n/sv.json
includes/api/i18n/uk.json
includes/api/i18n/zh-hans.json
includes/api/i18n/zh-hant.json
includes/auth/AuthManager.php
includes/auth/AuthenticationRequest.php
includes/auth/CheckBlocksSecondaryAuthenticationProvider.php
includes/auth/LegacyHookPreAuthenticationProvider.php [deleted file]
includes/auth/LocalPasswordPrimaryAuthenticationProvider.php
includes/auth/TemporaryPasswordPrimaryAuthenticationProvider.php
includes/block/AbstractBlock.php [new file with mode: 0644]
includes/block/BlockManager.php [new file with mode: 0644]
includes/block/BlockRestriction.php [deleted file]
includes/block/BlockRestrictionStore.php [new file with mode: 0644]
includes/block/Restriction/AbstractRestriction.php
includes/block/Restriction/Restriction.php
includes/block/SystemBlock.php [new file with mode: 0644]
includes/cache/CacheHelper.php
includes/cache/GenderCache.php
includes/cache/HTMLFileCache.php
includes/cache/LinkCache.php
includes/cache/MessageBlobStore.php [deleted file]
includes/cache/MessageCache.php
includes/cache/dependency/FileDependency.php
includes/cache/localisation/LCStoreCDB.php
includes/cache/localisation/LCStoreStaticArray.php
includes/cache/localisation/LocalisationCache.php
includes/changes/AtomFeed.php [new file with mode: 0644]
includes/changes/ChangesFeed.php
includes/changes/ChangesList.php
includes/changes/ChannelFeed.php [new file with mode: 0644]
includes/changes/EnhancedChangesList.php
includes/changes/FeedItem.php [new file with mode: 0644]
includes/changes/RCCacheEntry.php
includes/changes/RCCacheEntryFactory.php
includes/changes/RSSFeed.php [new file with mode: 0644]
includes/changes/RecentChange.php
includes/changetags/ChangeTags.php
includes/changetags/ChangeTagsLogList.php
includes/clientpool/SquidPurgeClient.php
includes/collation/Collation.php
includes/collation/IcuCollation.php
includes/compat/ObjectFactory.php [deleted file]
includes/compat/XMPReader.php [deleted file]
includes/composer/ComposerVersionNormalizer.php
includes/config/ConfigRepository.php
includes/config/ServiceOptions.php [new file with mode: 0644]
includes/content/ContentHandler.php
includes/content/CssContent.php
includes/content/JavaScriptContent.php
includes/content/JsonContent.php
includes/content/TextContent.php
includes/content/WikiTextStructure.php
includes/content/WikitextContent.php
includes/context/DerivativeContext.php
includes/context/RequestContext.php
includes/dao/DBAccessBase.php
includes/db/CloneDatabase.php
includes/db/DatabaseOracle.php
includes/db/MWLBFactory.php
includes/debug/DeprecationHelper.php
includes/debug/logger/MonologSpi.php
includes/debug/logger/monolog/MwlogHandler.php [new file with mode: 0644]
includes/deferred/AtomicSectionUpdate.php
includes/deferred/AutoCommitUpdate.php
includes/deferred/CdnCacheUpdate.php
includes/deferred/DeferredUpdates.php
includes/deferred/EnqueueableDataUpdate.php
includes/deferred/LinksDeletionUpdate.php
includes/deferred/LinksUpdate.php
includes/deferred/MWCallableUpdate.php
includes/diff/DairikiDiff.php [deleted file]
includes/diff/Diff.php [new file with mode: 0644]
includes/diff/DiffEngine.php
includes/diff/DiffOp.php [new file with mode: 0644]
includes/diff/DiffOpAdd.php [new file with mode: 0644]
includes/diff/DiffOpChange.php [new file with mode: 0644]
includes/diff/DiffOpCopy.php [new file with mode: 0644]
includes/diff/DiffOpDelete.php [new file with mode: 0644]
includes/diff/DifferenceEngine.php
includes/diff/TextSlotDiffRenderer.php
includes/edit/PreparedEdit.php
includes/editpage/TextConflictHelper.php
includes/editpage/TextboxBuilder.php
includes/exception/MWException.php
includes/exception/MWExceptionHandler.php
includes/exception/MWExceptionRenderer.php
includes/exception/UserBlockedError.php
includes/export/Dump7ZipOutput.php
includes/export/DumpLBZip2Output.php [new file with mode: 0644]
includes/export/DumpNotalkFilter.php
includes/export/DumpPipeOutput.php
includes/export/WikiExporter.php
includes/export/XmlDumpWriter.php
includes/externalstore/ExternalStore.php
includes/externalstore/ExternalStoreDB.php
includes/externalstore/ExternalStoreHttp.php
includes/filebackend/FileBackendGroup.php
includes/filebackend/filejournal/DBFileJournal.php
includes/filebackend/lockmanager/LockManagerGroup.php
includes/filerepo/FileBackendDBRepoWrapper.php
includes/filerepo/FileRepo.php
includes/filerepo/FileRepoStatus.php [deleted file]
includes/filerepo/ForeignAPIRepo.php
includes/filerepo/RepoGroup.php
includes/filerepo/file/File.php
includes/filerepo/file/ForeignAPIFile.php
includes/filerepo/file/ForeignDBFile.php
includes/filerepo/file/LocalFile.php
includes/filerepo/file/LocalFileDeleteBatch.php [new file with mode: 0644]
includes/filerepo/file/LocalFileLockError.php [new file with mode: 0644]
includes/filerepo/file/LocalFileMoveBatch.php [new file with mode: 0644]
includes/filerepo/file/LocalFileRestoreBatch.php [new file with mode: 0644]
includes/filerepo/file/OldLocalFile.php
includes/gallery/PackedHoverImageGallery.php [new file with mode: 0644]
includes/gallery/PackedOverlayImageGallery.php
includes/gallery/TraditionalImageGallery.php
includes/historyblob/ConcatenatedGzipHistoryBlob.php [new file with mode: 0644]
includes/historyblob/DiffHistoryBlob.php [new file with mode: 0644]
includes/historyblob/HistoryBlob.php [new file with mode: 0644]
includes/historyblob/HistoryBlobCurStub.php [new file with mode: 0644]
includes/historyblob/HistoryBlobStub.php [new file with mode: 0644]
includes/htmlform/HTMLForm.php
includes/htmlform/HTMLFormActionFieldLayout.php [new file with mode: 0644]
includes/htmlform/HTMLFormElement.php
includes/htmlform/HTMLFormField.php
includes/htmlform/HTMLFormFieldLayout.php [new file with mode: 0644]
includes/htmlform/OOUIHTMLForm.php
includes/htmlform/fields/HTMLCheckField.php
includes/htmlform/fields/HTMLDateTimeField.php
includes/htmlform/fields/HTMLFormFieldWithButton.php
includes/htmlform/fields/HTMLNamespacesMultiselectField.php
includes/htmlform/fields/HTMLSelectAndOtherField.php
includes/htmlform/fields/HTMLTextField.php
includes/htmlform/fields/HTMLTitlesMultiselectField.php
includes/htmlform/fields/HTMLUserTextField.php
includes/http/CurlHttpRequest.php
includes/http/GuzzleHttpRequest.php
includes/http/Http.php
includes/http/HttpRequestFactory.php
includes/http/MWHttpRequest.php
includes/http/PhpHttpRequest.php
includes/import/ImportStreamSource.php
includes/import/ImportableUploadRevisionImporter.php
includes/import/UploadSourceAdapter.php
includes/import/WikiImporter.php
includes/import/WikiRevision.php
includes/installer/CliInstaller.php
includes/installer/DatabaseInstaller.php
includes/installer/DatabaseUpdater.php
includes/installer/Installer.php
includes/installer/MssqlInstaller.php
includes/installer/MssqlUpdater.php
includes/installer/MysqlInstaller.php
includes/installer/MysqlUpdater.php
includes/installer/PhpBugTests.php [deleted file]
includes/installer/PhpXmlBugTester.php [new file with mode: 0644]
includes/installer/PostgresInstaller.php
includes/installer/PostgresUpdater.php
includes/installer/SqliteInstaller.php
includes/installer/WebInstaller.php
includes/installer/WebInstallerComplete.php
includes/installer/WebInstallerDocument.php
includes/installer/WebInstallerName.php
includes/installer/WebInstallerOptions.php
includes/installer/WebInstallerWelcome.php
includes/installer/i18n/ar.json
includes/installer/i18n/ast.json
includes/installer/i18n/ba.json
includes/installer/i18n/be-tarask.json
includes/installer/i18n/bg.json
includes/installer/i18n/bn.json
includes/installer/i18n/br.json
includes/installer/i18n/bs.json
includes/installer/i18n/ca.json
includes/installer/i18n/ckb.json
includes/installer/i18n/cs.json
includes/installer/i18n/csb.json
includes/installer/i18n/da.json
includes/installer/i18n/de.json
includes/installer/i18n/diq.json
includes/installer/i18n/el.json
includes/installer/i18n/en.json
includes/installer/i18n/eo.json
includes/installer/i18n/es.json
includes/installer/i18n/eu.json
includes/installer/i18n/fa.json
includes/installer/i18n/fi.json
includes/installer/i18n/fr.json
includes/installer/i18n/frp.json
includes/installer/i18n/gl.json
includes/installer/i18n/gsw.json
includes/installer/i18n/he.json
includes/installer/i18n/hi.json
includes/installer/i18n/hrx.json
includes/installer/i18n/hsb.json
includes/installer/i18n/hu.json
includes/installer/i18n/ia.json
includes/installer/i18n/id.json
includes/installer/i18n/io.json
includes/installer/i18n/is.json
includes/installer/i18n/it.json
includes/installer/i18n/ja.json
includes/installer/i18n/ka.json
includes/installer/i18n/ko.json
includes/installer/i18n/ksh.json
includes/installer/i18n/ku-latn.json
includes/installer/i18n/lb.json
includes/installer/i18n/lij.json
includes/installer/i18n/lt.json
includes/installer/i18n/lv.json
includes/installer/i18n/mk.json
includes/installer/i18n/mr.json
includes/installer/i18n/ms.json
includes/installer/i18n/mzn.json
includes/installer/i18n/nap.json
includes/installer/i18n/nb.json
includes/installer/i18n/nl.json
includes/installer/i18n/oc.json
includes/installer/i18n/olo.json
includes/installer/i18n/pl.json
includes/installer/i18n/pms.json
includes/installer/i18n/ps.json
includes/installer/i18n/pt-br.json
includes/installer/i18n/pt.json
includes/installer/i18n/qqq.json
includes/installer/i18n/ro.json
includes/installer/i18n/ru.json
includes/installer/i18n/sco.json
includes/installer/i18n/sh.json
includes/installer/i18n/sl.json
includes/installer/i18n/sr-ec.json
includes/installer/i18n/sr-el.json
includes/installer/i18n/sv.json
includes/installer/i18n/te.json
includes/installer/i18n/th.json
includes/installer/i18n/tl.json
includes/installer/i18n/tr.json
includes/installer/i18n/tt-cyrl.json
includes/installer/i18n/uk.json
includes/installer/i18n/vi.json
includes/installer/i18n/yi.json
includes/installer/i18n/zh-hans.json
includes/installer/i18n/zh-hant.json
includes/interwiki/Interwiki.php
includes/jobqueue/GenericParameterJob.php [new file with mode: 0644]
includes/jobqueue/IJobSpecification.php
includes/jobqueue/Job.php
includes/jobqueue/JobQueue.php
includes/jobqueue/JobQueueDB.php
includes/jobqueue/JobQueueFederated.php
includes/jobqueue/JobQueueGroup.php
includes/jobqueue/JobQueueMemory.php
includes/jobqueue/JobQueueRedis.php
includes/jobqueue/JobSpecification.php
includes/jobqueue/RunnableJob.php [new file with mode: 0644]
includes/jobqueue/aggregator/JobQueueAggregator.php [deleted file]
includes/jobqueue/aggregator/JobQueueAggregatorNull.php [deleted file]
includes/jobqueue/aggregator/JobQueueAggregatorRedis.php [deleted file]
includes/jobqueue/jobs/ActivityUpdateJob.php
includes/jobqueue/jobs/CdnPurgeJob.php
includes/jobqueue/jobs/ClearUserWatchlistJob.php
includes/jobqueue/jobs/ClearWatchlistNotificationsJob.php
includes/jobqueue/jobs/DeletePageJob.php
includes/jobqueue/jobs/DoubleRedirectJob.php
includes/jobqueue/jobs/DuplicateJob.php
includes/jobqueue/jobs/EnqueueJob.php
includes/jobqueue/jobs/NullJob.php
includes/jobqueue/jobs/RefreshLinksJob.php
includes/jobqueue/jobs/ThumbnailRenderJob.php
includes/jobqueue/jobs/UserGroupExpiryJob.php
includes/jobqueue/jobs/UserOptionsUpdateJob.php [new file with mode: 0644]
includes/libs/ArrayUtils.php
includes/libs/CSSMin.php
includes/libs/CryptRand.php [deleted file]
includes/libs/DeferredStringifier.php
includes/libs/IP.php
includes/libs/MWMessagePack.php
includes/libs/MemoizedCallable.php
includes/libs/MultiHttpClient.php
includes/libs/filebackend/FSFileBackend.php
includes/libs/filebackend/FileBackend.php
includes/libs/filebackend/FileBackendError.php [deleted file]
includes/libs/filebackend/FileBackendMultiWrite.php
includes/libs/filebackend/FileBackendStore.php
includes/libs/filebackend/SwiftFileBackend.php
includes/libs/filebackend/exception/FileBackendError.php [new file with mode: 0644]
includes/libs/filebackend/fileiteration/FSFileBackendDirList.php [new file with mode: 0644]
includes/libs/filebackend/fileiteration/FSFileBackendFileList.php [new file with mode: 0644]
includes/libs/filebackend/fileiteration/FSFileBackendList.php [new file with mode: 0644]
includes/libs/filebackend/fileiteration/FileBackendStoreShardDirIterator.php [new file with mode: 0644]
includes/libs/filebackend/fileiteration/FileBackendStoreShardFileIterator.php [new file with mode: 0644]
includes/libs/filebackend/fileiteration/FileBackendStoreShardListIterator.php [new file with mode: 0644]
includes/libs/filebackend/fileiteration/SwiftFileBackendDirList.php [new file with mode: 0644]
includes/libs/filebackend/fileiteration/SwiftFileBackendFileList.php [new file with mode: 0644]
includes/libs/filebackend/fileiteration/SwiftFileBackendList.php [new file with mode: 0644]
includes/libs/filebackend/fileophandle/FSFileOpHandle.php [new file with mode: 0644]
includes/libs/filebackend/fileophandle/FileBackendStoreOpHandle.php [new file with mode: 0644]
includes/libs/filebackend/fileophandle/SwiftFileOpHandle.php [new file with mode: 0644]
includes/libs/filebackend/fsfile/TempFSFile.php
includes/libs/jsminplus.php
includes/libs/mime/MimeAnalyzer.php
includes/libs/mime/XmlTypeCheck.php
includes/libs/objectcache/APCBagOStuff.php
includes/libs/objectcache/APCUBagOStuff.php
includes/libs/objectcache/BagOStuff.php
includes/libs/objectcache/CachedBagOStuff.php
includes/libs/objectcache/EmptyBagOStuff.php
includes/libs/objectcache/HashBagOStuff.php
includes/libs/objectcache/IExpiringStore.php
includes/libs/objectcache/MemcachedBagOStuff.php
includes/libs/objectcache/MemcachedClient.php
includes/libs/objectcache/MemcachedPeclBagOStuff.php
includes/libs/objectcache/MultiWriteBagOStuff.php
includes/libs/objectcache/RESTBagOStuff.php
includes/libs/objectcache/RedisBagOStuff.php
includes/libs/objectcache/ReplicatedBagOStuff.php
includes/libs/objectcache/WANObjectCache.php
includes/libs/objectcache/WinCacheBagOStuff.php
includes/libs/rdbms/ChronologyProtector.php
includes/libs/rdbms/TransactionProfiler.php
includes/libs/rdbms/database/AtomicSectionIdentifier.php [deleted file]
includes/libs/rdbms/database/DBConnRef.php
includes/libs/rdbms/database/Database.php
includes/libs/rdbms/database/DatabaseDomain.php [deleted file]
includes/libs/rdbms/database/DatabaseMssql.php
includes/libs/rdbms/database/DatabaseMysqlBase.php
includes/libs/rdbms/database/DatabaseMysqli.php
includes/libs/rdbms/database/DatabasePostgres.php
includes/libs/rdbms/database/DatabaseSqlite.php
includes/libs/rdbms/database/IDatabase.php
includes/libs/rdbms/database/MaintainableDBConnRef.php
includes/libs/rdbms/database/domain/DatabaseDomain.php [new file with mode: 0644]
includes/libs/rdbms/database/resultwrapper/ResultWrapper.php
includes/libs/rdbms/database/utils/AtomicSectionIdentifier.php [new file with mode: 0644]
includes/libs/rdbms/database/utils/GeneralizedSql.php [new file with mode: 0644]
includes/libs/rdbms/database/utils/SavepointPostgres.php [deleted file]
includes/libs/rdbms/encasing/MssqlBlob.php
includes/libs/rdbms/exception/DBQueryDisconnectedError.php [new file with mode: 0644]
includes/libs/rdbms/exception/DBQueryError.php
includes/libs/rdbms/exception/DBReadOnlyRoleError.php [new file with mode: 0644]
includes/libs/rdbms/lbfactory/ILBFactory.php
includes/libs/rdbms/lbfactory/LBFactory.php
includes/libs/rdbms/lbfactory/LBFactoryMulti.php
includes/libs/rdbms/loadbalancer/ILoadBalancer.php
includes/libs/rdbms/loadbalancer/LoadBalancer.php
includes/libs/redis/RedisConnectionPool.php
includes/libs/services/ServiceContainer.php
includes/linkeddata/PageDataRequestHandler.php
includes/linker/LinkRenderer.php
includes/linker/LinkRendererFactory.php
includes/logging/DatabaseLogEntry.php [new file with mode: 0644]
includes/logging/LegacyLogFormatter.php [new file with mode: 0644]
includes/logging/LogEntry.php
includes/logging/LogEntryBase.php [new file with mode: 0644]
includes/logging/LogEventsList.php
includes/logging/LogFormatter.php
includes/logging/LogPage.php
includes/logging/LogPager.php
includes/logging/ManualLogEntry.php [new file with mode: 0644]
includes/logging/RCDatabaseLogEntry.php [new file with mode: 0644]
includes/mail/EmailNotification.php
includes/media/BitmapHandler.php
includes/media/BitmapMetadataHandler.php
includes/media/DjVuHandler.php
includes/media/DjVuImage.php
includes/media/Exif.php
includes/media/FormatMetadata.php
includes/media/GIFHandler.php
includes/media/JpegHandler.php
includes/media/MediaHandler.php
includes/media/MediaHandlerFactory.php
includes/media/MediaTransformError.php [new file with mode: 0644]
includes/media/MediaTransformOutput.php
includes/media/SVGMetadataExtractor.php
includes/media/SVGReader.php [new file with mode: 0644]
includes/media/SvgHandler.php
includes/media/ThumbnailImage.php [new file with mode: 0644]
includes/media/TransformParameterError.php [new file with mode: 0644]
includes/media/TransformTooBigImageAreaError.php [new file with mode: 0644]
includes/media/TransformationalImageHandler.php
includes/media/XCFHandler.php
includes/objectcache/ObjectCache.php
includes/objectcache/SqlBagOStuff.php
includes/page/Article.php
includes/page/ImagePage.php
includes/page/PageArchive.php
includes/page/WikiPage.php
includes/pager/Pager.php
includes/parser/BlockLevelPass.php
includes/parser/CoreParserFunctions.php
includes/parser/DateFormatter.php
includes/parser/DateFormatterFactory.php [new file with mode: 0644]
includes/parser/LinkHolderArray.php
includes/parser/PPCustomFrame_DOM.php [new file with mode: 0644]
includes/parser/PPCustomFrame_Hash.php [new file with mode: 0644]
includes/parser/PPDPart.php [new file with mode: 0644]
includes/parser/PPDPart_Hash.php [new file with mode: 0644]
includes/parser/PPDStack.php [new file with mode: 0644]
includes/parser/PPDStackElement.php [new file with mode: 0644]
includes/parser/PPDStackElement_Hash.php [new file with mode: 0644]
includes/parser/PPDStack_Hash.php [new file with mode: 0644]
includes/parser/PPFrame.php [new file with mode: 0644]
includes/parser/PPFrame_DOM.php [new file with mode: 0644]
includes/parser/PPFrame_Hash.php [new file with mode: 0644]
includes/parser/PPNode.php [new file with mode: 0644]
includes/parser/PPNode_DOM.php [new file with mode: 0644]
includes/parser/PPNode_Hash_Array.php [new file with mode: 0644]
includes/parser/PPNode_Hash_Attr.php [new file with mode: 0644]
includes/parser/PPNode_Hash_Text.php [new file with mode: 0644]
includes/parser/PPNode_Hash_Tree.php [new file with mode: 0644]
includes/parser/PPTemplateFrame_DOM.php [new file with mode: 0644]
includes/parser/PPTemplateFrame_Hash.php [new file with mode: 0644]
includes/parser/Parser.php
includes/parser/ParserCache.php
includes/parser/ParserFactory.php
includes/parser/ParserOptions.php
includes/parser/ParserOutput.php
includes/parser/Preprocessor.php
includes/parser/Preprocessor_DOM.php
includes/parser/Preprocessor_Hash.php
includes/parser/RemexStripTagHandler.php
includes/parser/Sanitizer.php
includes/password/Argon2Password.php
includes/password/InvalidPassword.php
includes/password/Password.php
includes/poolcounter/PoolCounter.php
includes/poolcounter/PoolCounterNull.php [new file with mode: 0644]
includes/poolcounter/PoolWorkArticleView.php
includes/preferences/DefaultPreferencesFactory.php
includes/preferences/PreferencesFactory.php
includes/profiler/ProfilerStub.php
includes/profiler/SectionProfileCallback.php [new file with mode: 0644]
includes/profiler/SectionProfiler.php
includes/rcfeed/FormattedRCFeed.php
includes/rcfeed/IRCColourfulRCFeedFormatter.php
includes/rcfeed/RedisPubSubFeedEngine.php
includes/rcfeed/UDPRCFeedEngine.php
includes/registration/ExtensionDependencyError.php
includes/registration/ExtensionJsonValidator.php
includes/registration/ExtensionProcessor.php
includes/registration/ExtensionRegistry.php
includes/registration/Processor.php
includes/registration/VersionChecker.php
includes/resourceloader/MessageBlobStore.php [new file with mode: 0644]
includes/resourceloader/ResourceLoader.php
includes/resourceloader/ResourceLoaderClientHtml.php
includes/resourceloader/ResourceLoaderContext.php
includes/resourceloader/ResourceLoaderFileModule.php
includes/resourceloader/ResourceLoaderImage.php
includes/resourceloader/ResourceLoaderImageModule.php
includes/resourceloader/ResourceLoaderModule.php
includes/resourceloader/ResourceLoaderOOUIFileModule.php
includes/resourceloader/ResourceLoaderOOUIModule.php
includes/resourceloader/ResourceLoaderSkinModule.php
includes/resourceloader/ResourceLoaderStartUpModule.php
includes/resourceloader/ResourceLoaderWikiModule.php
includes/revisiondelete/RevDelList.php
includes/revisionlist/RevisionItem.php [new file with mode: 0644]
includes/revisionlist/RevisionItemBase.php [new file with mode: 0644]
includes/revisionlist/RevisionList.php [new file with mode: 0644]
includes/revisionlist/RevisionListBase.php [new file with mode: 0644]
includes/search/NullIndexField.php
includes/search/PrefixSearch.php [new file with mode: 0644]
includes/search/SearchDatabase.php
includes/search/SearchEngine.php
includes/search/SearchEngineDummy.php [new file with mode: 0644]
includes/search/SearchIndexField.php
includes/search/SearchIndexFieldDefinition.php
includes/search/SearchMySQL.php
includes/search/SearchNearMatcher.php
includes/search/SearchOracle.php
includes/search/SearchPostgres.php
includes/search/SearchResult.php
includes/search/SearchResultSet.php
includes/search/SearchSqlite.php
includes/search/StringPrefixSearch.php [new file with mode: 0644]
includes/search/TitlePrefixSearch.php [new file with mode: 0644]
includes/session/Session.php
includes/session/SessionBackend.php
includes/session/SessionProvider.php
includes/shell/Command.php
includes/shell/CommandFactory.php
includes/shell/FirejailCommand.php
includes/shell/Shell.php
includes/skins/BaseTemplate.php
includes/skins/QuickTemplate.php
includes/skins/Skin.php
includes/skins/SkinTemplate.php
includes/specialpage/AuthManagerSpecialPage.php
includes/specialpage/ChangesListSpecialPage.php
includes/specialpage/FormSpecialPage.php
includes/specialpage/ImageQueryPage.php
includes/specialpage/QueryPage.php
includes/specialpage/RedirectSpecialPage.php
includes/specialpage/SpecialPage.php
includes/specialpage/SpecialPageFactory.php
includes/specials/SpecialActiveUsers.php [new file with mode: 0644]
includes/specials/SpecialActiveusers.php [deleted file]
includes/specials/SpecialAllMessages.php
includes/specials/SpecialAncientpages.php
includes/specials/SpecialAutoblockList.php
includes/specials/SpecialBlock.php
includes/specials/SpecialBlockList.php
includes/specials/SpecialBookSources.php [new file with mode: 0644]
includes/specials/SpecialBooksources.php [deleted file]
includes/specials/SpecialComparePages.php
includes/specials/SpecialContributions.php
includes/specials/SpecialDeadendpages.php
includes/specials/SpecialDeletedContributions.php
includes/specials/SpecialEditTags.php
includes/specials/SpecialEditWatchlist.php
includes/specials/SpecialEmailUser.php [new file with mode: 0644]
includes/specials/SpecialEmailuser.php [deleted file]
includes/specials/SpecialExpandTemplates.php
includes/specials/SpecialFewestrevisions.php
includes/specials/SpecialImport.php
includes/specials/SpecialListFiles.php [new file with mode: 0644]
includes/specials/SpecialListGrants.php [new file with mode: 0644]
includes/specials/SpecialListGroupRights.php [new file with mode: 0644]
includes/specials/SpecialListUsers.php [new file with mode: 0644]
includes/specials/SpecialListfiles.php [deleted file]
includes/specials/SpecialListgrants.php [deleted file]
includes/specials/SpecialListgrouprights.php [deleted file]
includes/specials/SpecialListusers.php [deleted file]
includes/specials/SpecialLog.php
includes/specials/SpecialLonelypages.php
includes/specials/SpecialMIMEsearch.php
includes/specials/SpecialMostcategories.php
includes/specials/SpecialMostinterwikis.php
includes/specials/SpecialMovepage.php
includes/specials/SpecialNewpages.php
includes/specials/SpecialPageLanguage.php
includes/specials/SpecialPasswordPolicies.php
includes/specials/SpecialPreferences.php
includes/specials/SpecialRandompage.php
includes/specials/SpecialRecentChanges.php [new file with mode: 0644]
includes/specials/SpecialRecentChangesLinked.php [new file with mode: 0644]
includes/specials/SpecialRecentchanges.php [deleted file]
includes/specials/SpecialRecentchangeslinked.php [deleted file]
includes/specials/SpecialRedirect.php
includes/specials/SpecialRevisionDelete.php [new file with mode: 0644]
includes/specials/SpecialRevisiondelete.php [deleted file]
includes/specials/SpecialSearch.php
includes/specials/SpecialShortpages.php
includes/specials/SpecialStatistics.php
includes/specials/SpecialUnblock.php
includes/specials/SpecialUncategorizedpages.php
includes/specials/SpecialUndelete.php
includes/specials/SpecialUpload.php
includes/specials/SpecialUploadStash.php
includes/specials/SpecialUserLogout.php
includes/specials/SpecialUserrights.php
includes/specials/SpecialVersion.php
includes/specials/SpecialWatchlist.php
includes/specials/SpecialWhatLinksHere.php [new file with mode: 0644]
includes/specials/SpecialWhatlinkshere.php [deleted file]
includes/specials/SpecialWithoutinterwiki.php
includes/specials/forms/PreferencesFormLegacy.php [deleted file]
includes/specials/forms/PreferencesFormOOUI.php
includes/specials/forms/UploadForm.php
includes/specials/helpers/ImportReporter.php
includes/specials/pagers/ActiveUsersPager.php
includes/specials/pagers/BlockListPager.php
includes/specials/pagers/ContribsPager.php
includes/specials/pagers/DeletedContribsPager.php
includes/specials/pagers/ImageListPager.php
includes/specials/pagers/NewFilesPager.php
includes/specials/pagers/ProtectedPagesPager.php
includes/specials/pagers/UsersPager.php
includes/templates/EnhancedChangesListGroup.mustache
includes/tidy/RemexCompatFormatter.php
includes/tidy/RemexCompatMunger.php
includes/title/MediaWikiTitleCodec.php
includes/title/NaiveImportTitleFactory.php
includes/title/NamespaceImportTitleFactory.php
includes/title/NamespaceInfo.php [new file with mode: 0644]
includes/title/SubpageImportTitleFactory.php
includes/title/TitleParser.php
includes/title/TitleValue.php
includes/upload/UploadBase.php
includes/upload/UploadStash.php
includes/upload/UploadStashFile.php [new file with mode: 0644]
includes/upload/exception/UploadChunkVerificationException.php
includes/user/ExternalUserNames.php
includes/user/PasswordReset.php
includes/user/User.php
includes/user/UserGroupMembership.php
includes/user/UserIdentity.php
includes/user/UserIdentityValue.php
includes/utils/AutoloadGenerator.php
includes/utils/BatchRowUpdate.php
includes/utils/ClassCollector.php [new file with mode: 0644]
includes/utils/MWCryptRand.php
includes/utils/UIDGenerator.php
includes/watcheditem/NoWriteWatchedItemStore.php
includes/watcheditem/WatchedItem.php
includes/watcheditem/WatchedItemQueryService.php
includes/watcheditem/WatchedItemQueryServiceExtension.php
includes/watcheditem/WatchedItemStore.php
includes/watcheditem/WatchedItemStoreInterface.php
includes/widget/ExpiryInputWidget.php
includes/widget/SearchInputWidget.php
includes/widget/search/InterwikiSearchResultSetWidget.php
includes/widget/search/InterwikiSearchResultWidget.php
includes/widget/search/SearchFormWidget.php
jsduck.json
languages/Language.php
languages/LanguageConverter.php
languages/classes/LanguageKk_cyrl.php
languages/data/Names.php
languages/data/ZhConversion.php
languages/i18n/abs.json
languages/i18n/ace.json
languages/i18n/aeb-arab.json
languages/i18n/af.json
languages/i18n/ais.json
languages/i18n/am.json
languages/i18n/ami.json
languages/i18n/an.json
languages/i18n/ang.json
languages/i18n/ar.json
languages/i18n/arn.json
languages/i18n/ary.json
languages/i18n/arz.json
languages/i18n/as.json
languages/i18n/ast.json
languages/i18n/avk.json
languages/i18n/awa.json
languages/i18n/az.json
languages/i18n/azb.json
languages/i18n/ba.json
languages/i18n/ban.json
languages/i18n/bar.json
languages/i18n/bcc.json
languages/i18n/bcl.json
languages/i18n/be-tarask.json
languages/i18n/be.json
languages/i18n/bg.json
languages/i18n/bgn.json
languages/i18n/bho.json
languages/i18n/bjn.json
languages/i18n/bn.json
languages/i18n/bqi.json
languages/i18n/br.json
languages/i18n/bs.json
languages/i18n/ca.json
languages/i18n/cdo.json
languages/i18n/ce.json
languages/i18n/ch.json
languages/i18n/ckb.json
languages/i18n/co.json
languages/i18n/crh-cyrl.json
languages/i18n/crh-latn.json
languages/i18n/cs.json
languages/i18n/csb.json
languages/i18n/cv.json
languages/i18n/cy.json
languages/i18n/da.json
languages/i18n/de-ch.json
languages/i18n/de-formal.json
languages/i18n/de.json
languages/i18n/diq.json
languages/i18n/dsb.json
languages/i18n/dty.json
languages/i18n/ee.json
languages/i18n/egl.json
languages/i18n/el.json
languages/i18n/en.json
languages/i18n/eo.json
languages/i18n/es.json
languages/i18n/et.json
languages/i18n/eu.json
languages/i18n/exif/ast.json
languages/i18n/exif/bjn.json
languages/i18n/exif/diq.json
languages/i18n/exif/eo.json
languages/i18n/exif/fa.json
languages/i18n/exif/hr.json
languages/i18n/exif/it.json
languages/i18n/exif/ja.json
languages/i18n/exif/jv.json
languages/i18n/exif/ko.json
languages/i18n/exif/lb.json
languages/i18n/exif/lrc.json
languages/i18n/exif/mk.json
languages/i18n/exif/sah.json
languages/i18n/exif/te.json
languages/i18n/ext.json
languages/i18n/fa.json
languages/i18n/fi.json
languages/i18n/fo.json
languages/i18n/fr.json
languages/i18n/frp.json
languages/i18n/frr.json
languages/i18n/fur.json
languages/i18n/fy.json
languages/i18n/ga.json
languages/i18n/gan-hans.json
languages/i18n/gan-hant.json
languages/i18n/gcr.json
languages/i18n/gd.json
languages/i18n/gl.json
languages/i18n/glk.json
languages/i18n/gom-latn.json
languages/i18n/grc.json
languages/i18n/gsw.json
languages/i18n/gu.json
languages/i18n/ha.json
languages/i18n/hak.json
languages/i18n/he.json
languages/i18n/hi.json
languages/i18n/hif-latn.json
languages/i18n/hil.json
languages/i18n/hr.json
languages/i18n/hrx.json
languages/i18n/hsb.json
languages/i18n/hu.json
languages/i18n/hy.json
languages/i18n/hyw.json
languages/i18n/ia.json
languages/i18n/id.json
languages/i18n/ig.json
languages/i18n/ilo.json
languages/i18n/inh.json
languages/i18n/io.json
languages/i18n/is.json
languages/i18n/it.json
languages/i18n/ja.json
languages/i18n/jv.json
languages/i18n/ka.json
languages/i18n/kaa.json
languages/i18n/kab.json
languages/i18n/kk-arab.json
languages/i18n/kk-cyrl.json
languages/i18n/kk-latn.json
languages/i18n/km.json
languages/i18n/kn.json
languages/i18n/ko.json
languages/i18n/krc.json
languages/i18n/ksh.json
languages/i18n/ku-latn.json
languages/i18n/kum.json
languages/i18n/la.json
languages/i18n/lb.json
languages/i18n/lfn.json
languages/i18n/li.json
languages/i18n/lij.json
languages/i18n/lki.json
languages/i18n/lmo.json
languages/i18n/lrc.json
languages/i18n/lt.json
languages/i18n/lus.json
languages/i18n/lv.json
languages/i18n/lzh.json
languages/i18n/mai.json
languages/i18n/map-bms.json
languages/i18n/mdf.json
languages/i18n/mg.json
languages/i18n/min.json
languages/i18n/mk.json
languages/i18n/ml.json
languages/i18n/mn.json
languages/i18n/mnw.json
languages/i18n/mr.json
languages/i18n/ms.json
languages/i18n/mt.json
languages/i18n/my.json
languages/i18n/myv.json
languages/i18n/nah.json
languages/i18n/nan.json
languages/i18n/nap.json
languages/i18n/nb.json
languages/i18n/nds-nl.json
languages/i18n/nds.json
languages/i18n/ne.json
languages/i18n/nl-informal.json
languages/i18n/nl.json
languages/i18n/nn.json
languages/i18n/nqo.json [new file with mode: 0644]
languages/i18n/nys.json
languages/i18n/oc.json
languages/i18n/olo.json
languages/i18n/or.json
languages/i18n/pa.json
languages/i18n/pam.json
languages/i18n/pl.json
languages/i18n/pms.json
languages/i18n/pnb.json
languages/i18n/prg.json
languages/i18n/ps.json
languages/i18n/pt-br.json
languages/i18n/pt.json
languages/i18n/qqq.json
languages/i18n/qu.json
languages/i18n/rm.json
languages/i18n/ro.json
languages/i18n/roa-tara.json
languages/i18n/ru.json
languages/i18n/rue.json
languages/i18n/sa.json
languages/i18n/sah.json
languages/i18n/sat.json
languages/i18n/sc.json
languages/i18n/scn.json
languages/i18n/sco.json
languages/i18n/sd.json
languages/i18n/sdc.json
languages/i18n/se.json
languages/i18n/sei.json
languages/i18n/ses.json
languages/i18n/sgs.json
languages/i18n/sh.json
languages/i18n/shi.json
languages/i18n/shn.json
languages/i18n/si.json
languages/i18n/sk.json
languages/i18n/skr-arab.json
languages/i18n/sl.json
languages/i18n/sli.json
languages/i18n/so.json
languages/i18n/sq.json
languages/i18n/sr-ec.json
languages/i18n/sr-el.json
languages/i18n/stq.json
languages/i18n/su.json
languages/i18n/sv.json
languages/i18n/sw.json
languages/i18n/szl.json
languages/i18n/ta.json
languages/i18n/tay.json
languages/i18n/tcy.json
languages/i18n/te.json
languages/i18n/tg-cyrl.json
languages/i18n/tg-latn.json
languages/i18n/th.json
languages/i18n/tk.json
languages/i18n/tl.json
languages/i18n/tly.json
languages/i18n/to.json
languages/i18n/tr.json
languages/i18n/trv.json
languages/i18n/tt-cyrl.json
languages/i18n/tt-latn.json
languages/i18n/tyv.json
languages/i18n/ug-arab.json
languages/i18n/uk.json
languages/i18n/ur.json
languages/i18n/uz.json
languages/i18n/vec.json
languages/i18n/vep.json
languages/i18n/vi.json
languages/i18n/vo.json
languages/i18n/vro.json
languages/i18n/wa.json
languages/i18n/war.json
languages/i18n/wo.json
languages/i18n/wuu.json
languages/i18n/xmf.json
languages/i18n/xsy.json
languages/i18n/yi.json
languages/i18n/yo.json
languages/i18n/yue.json
languages/i18n/zea.json
languages/i18n/zh-hans.json
languages/i18n/zh-hant.json
languages/i18n/zh-hk.json
languages/messages/MessagesBn.php
languages/messages/MessagesCs.php
languages/messages/MessagesEn.php
languages/messages/MessagesJv.php
languages/messages/MessagesNqo.php
languages/messages/MessagesSe.php
languages/messages/MessagesSk.php
languages/messages/MessagesSr_ec.php
maintenance/7zip.inc [deleted file]
maintenance/Maintenance.php
maintenance/archives/patch-job-params-mediumblob.sql [new file with mode: 0644]
maintenance/archives/patch-linktables.sql
maintenance/benchmarks/bench_HTTP_HTTPS.php
maintenance/benchmarks/benchmarkParse.php
maintenance/cleanupCaps.php
maintenance/cleanupInvalidDbKeys.php
maintenance/cleanupSpam.php
maintenance/cleanupTitles.php
maintenance/cleanupUsersWithNoId.php
maintenance/convertLinks.php
maintenance/deleteBatch.php
maintenance/dev/includes/router.php
maintenance/dev/installphp.sh
maintenance/dictionary/mediawiki.dic
maintenance/doMaintenance.php
maintenance/dumpBackup.php
maintenance/dumpTextPass.php
maintenance/edit.php
maintenance/findHooks.php
maintenance/findOrphanedFiles.php
maintenance/generateSitemap.php
maintenance/getConfiguration.php
maintenance/hhvm/makeRepo.php
maintenance/hhvm/run-server
maintenance/importDump.php
maintenance/importImages.php
maintenance/importSiteScripts.php
maintenance/includes/BackupDumper.php
maintenance/includes/MigrateActors.php
maintenance/includes/SevenZipStream.php [new file with mode: 0644]
maintenance/includes/TextPassDumper.php [new file with mode: 0644]
maintenance/install.php
maintenance/jsparse.php
maintenance/language/generateCollationData.php
maintenance/language/generateNormalizerDataAr.php
maintenance/language/generateNormalizerDataMl.php
maintenance/language/generateUcfirstOverrides.php [new file with mode: 0644]
maintenance/language/generateUpperCharTable.php [new file with mode: 0644]
maintenance/language/zhtable/simp2trad.manual
maintenance/language/zhtable/toCN.manual
maintenance/language/zhtable/toHK.manual
maintenance/language/zhtable/toSimp.manual
maintenance/language/zhtable/toTW.manual
maintenance/language/zhtable/toTrad.manual
maintenance/language/zhtable/trad2simp.manual
maintenance/language/zhtable/tradphrases.manual
maintenance/language/zhtable/tradphrases_exclude.manual
maintenance/manageForeignResources.php [new file with mode: 0644]
maintenance/mctest.php
maintenance/mediawiki.Title/generateJsToUpperCaseList.js [new file with mode: 0644]
maintenance/mediawiki.Title/generatePhpCharToUpperMappings.php [new file with mode: 0755]
maintenance/moveBatch.php
maintenance/mwdocgen.php
maintenance/mysql.php
maintenance/namespaceDupes.php
maintenance/nukePage.php
maintenance/pageExists.php
maintenance/populateArchiveRevId.php
maintenance/populateImageSha1.php
maintenance/populateInterwiki.php
maintenance/populatePPSortKey.php
maintenance/preprocessDump.php
maintenance/preprocessorFuzzTest.php
maintenance/protect.php
maintenance/purgeChangedPages.php
maintenance/rebuildFileCache.php
maintenance/removeInvalidEmails.php
maintenance/resources/foreign-resources.yaml [deleted file]
maintenance/resources/manageForeignResources.php [deleted file]
maintenance/runJobs.php
maintenance/storage/checkStorage.php
maintenance/storage/compressOld.php
maintenance/storage/dumpRev.php
maintenance/storage/recompressTracked.php
maintenance/storage/testCompression.php
maintenance/storage/trackBlobs.php
maintenance/tables.sql
maintenance/undelete.php
maintenance/update.php
maintenance/updateCollation.php
maintenance/validateRegistrationFile.php
maintenance/view.php
maintenance/wrapOldPasswords.php
mw-config/config-cc.css
mw-config/config.css
mw-config/index.php
package.json
profileinfo.php
resources/Resources.php
resources/lib/foreign-resources.yaml [new file with mode: 0644]
resources/lib/jquery.async.js [deleted file]
resources/lib/jquery.ba-throttle-debounce.js [deleted file]
resources/lib/jquery.form.js [deleted file]
resources/lib/jquery.form/jquery.form.js [new file with mode: 0644]
resources/lib/jquery.fullscreen.js [deleted file]
resources/lib/jquery.fullscreen/jquery.fullscreen.js [new file with mode: 0644]
resources/lib/jquery.hoverIntent.js [deleted file]
resources/lib/jquery.hoverIntent/jquery.hoverIntent.js [new file with mode: 0644]
resources/lib/jquery.jStorage.js [deleted file]
resources/lib/jquery.jStorage/jstorage.js [new file with mode: 0644]
resources/lib/jquery.throttle-debounce/jquery.ba-throttle-debounce.js [new file with mode: 0644]
resources/lib/jquery.ui/jquery.ui.spinner.js [deleted file]
resources/lib/jquery.ui/themes/smoothness/jquery.ui.spinner.css [deleted file]
resources/lib/mustache/LICENSE
resources/lib/mustache/mustache.js
resources/lib/ooui/History.md
resources/lib/ooui/i18n/fa.json
resources/lib/ooui/i18n/gl.json
resources/lib/ooui/i18n/hy.json
resources/lib/ooui/i18n/jv.json
resources/lib/ooui/i18n/nb.json
resources/lib/ooui/oojs-ui-apex.js
resources/lib/ooui/oojs-ui-core-apex.css
resources/lib/ooui/oojs-ui-core-wikimediaui.css
resources/lib/ooui/oojs-ui-core.js
resources/lib/ooui/oojs-ui-core.js.map.json
resources/lib/ooui/oojs-ui-toolbars-apex.css
resources/lib/ooui/oojs-ui-toolbars-wikimediaui.css
resources/lib/ooui/oojs-ui-toolbars.js
resources/lib/ooui/oojs-ui-toolbars.js.map.json
resources/lib/ooui/oojs-ui-widgets-apex.css
resources/lib/ooui/oojs-ui-widgets-wikimediaui.css
resources/lib/ooui/oojs-ui-widgets.js
resources/lib/ooui/oojs-ui-widgets.js.map.json
resources/lib/ooui/oojs-ui-wikimediaui.js
resources/lib/ooui/oojs-ui-wikimediaui.js.map.json
resources/lib/ooui/oojs-ui-windows-apex.css
resources/lib/ooui/oojs-ui-windows-wikimediaui.css
resources/lib/ooui/oojs-ui-windows.js
resources/lib/ooui/themes/apex/icons-alerts.json
resources/lib/ooui/themes/apex/icons-interactions.json
resources/lib/ooui/themes/apex/icons-wikimedia.json
resources/lib/ooui/themes/apex/textures.json
resources/lib/ooui/themes/wikimediaui/icons-alerts.json
resources/lib/ooui/themes/wikimediaui/icons-content.json
resources/lib/ooui/themes/wikimediaui/icons-interactions.json
resources/lib/ooui/themes/wikimediaui/images/icons/add-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/add-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/add.svg
resources/lib/ooui/themes/wikimediaui/images/icons/alert-error.png [deleted file]
resources/lib/ooui/themes/wikimediaui/images/icons/alert-error.svg [deleted file]
resources/lib/ooui/themes/wikimediaui/images/icons/alert-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/alert-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/alert-warning.svg
resources/lib/ooui/themes/wikimediaui/images/icons/alert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/arrowNext-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/arrowNext-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/arrowNext-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/arrowPrevious-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/arrowPrevious-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/arrowPrevious-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/article-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/article-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/article-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/article-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/article-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/article-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/articleAdd-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/articleAdd-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/articleAdd.svg
resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-ltr-invert.png [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-ltr-invert.svg [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-ltr-progressive.png [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-ltr-progressive.svg [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-ltr.png [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-ltr.svg [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-rtl-invert.png [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-rtl-invert.svg [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-rtl-progressive.png [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-rtl-progressive.svg [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-rtl.png [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-rtl.svg [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-ltr-invert.png [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-ltr-invert.svg [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-ltr-progressive.png [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-ltr-progressive.svg [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-ltr.png [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-ltr.svg [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-rtl-invert.png [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-rtl-invert.svg [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-rtl-progressive.png [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-rtl-progressive.svg [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-rtl.png [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-rtl.svg [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/articleRedirect-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/articleRedirect-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/articleRedirect-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/articleRedirect-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/articleRedirect-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/articleRedirect-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/articles-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/articles-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/articles-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/articles-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/articles-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/articles-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/beaker-invert.png
resources/lib/ooui/themes/wikimediaui/images/icons/beaker-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/beaker-progressive.png
resources/lib/ooui/themes/wikimediaui/images/icons/beaker-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/beaker.png
resources/lib/ooui/themes/wikimediaui/images/icons/beaker.svg
resources/lib/ooui/themes/wikimediaui/images/icons/bigger-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/bigger-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/bigger.svg
resources/lib/ooui/themes/wikimediaui/images/icons/bold-l-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/bold-l-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/bold-l.svg
resources/lib/ooui/themes/wikimediaui/images/icons/bold-n-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/bold-n-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/bold-n.svg
resources/lib/ooui/themes/wikimediaui/images/icons/bold-v-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/bold-v-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/bold-v.svg
resources/lib/ooui/themes/wikimediaui/images/icons/bookmark-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/bookmark-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/bookmark.svg
resources/lib/ooui/themes/wikimediaui/images/icons/bookmarkOutline-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/bookmarkOutline-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/bookmarkOutline.svg
resources/lib/ooui/themes/wikimediaui/images/icons/browser-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/browser-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/browser-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/browser-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/browser-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/browser-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/calendar-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/calendar-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/calendar.svg
resources/lib/ooui/themes/wikimediaui/images/icons/chart-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/chart-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/chart.svg
resources/lib/ooui/themes/wikimediaui/images/icons/check-destructive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/check-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/check-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/check-success.svg
resources/lib/ooui/themes/wikimediaui/images/icons/check.svg
resources/lib/ooui/themes/wikimediaui/images/icons/checkAll-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/checkAll-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/checkAll.svg
resources/lib/ooui/themes/wikimediaui/images/icons/collapse-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/collapse-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/collapse.svg
resources/lib/ooui/themes/wikimediaui/images/icons/die-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/die-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/die.svg
resources/lib/ooui/themes/wikimediaui/images/icons/downTriangle-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/downTriangle-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/downTriangle.svg
resources/lib/ooui/themes/wikimediaui/images/icons/download-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/download-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/download.svg
resources/lib/ooui/themes/wikimediaui/images/icons/draggable-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/draggable-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/draggable.svg
resources/lib/ooui/themes/wikimediaui/images/icons/edit-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/edit-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/edit.svg
resources/lib/ooui/themes/wikimediaui/images/icons/editUndo-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/editUndo-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/editUndo-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/editUndo-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/editUndo-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/editUndo-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/error-error.png [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/error-error.svg [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/error-invert.png [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/error-invert.svg [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/error-progressive.png [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/error-progressive.svg [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/error.png [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/error.svg [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/exitFullscreen-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/exitFullscreen-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/exitFullscreen.svg
resources/lib/ooui/themes/wikimediaui/images/icons/expand-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/expand-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/expand.svg
resources/lib/ooui/themes/wikimediaui/images/icons/eyeClosed-invert.png
resources/lib/ooui/themes/wikimediaui/images/icons/eyeClosed-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/eyeClosed-progressive.png
resources/lib/ooui/themes/wikimediaui/images/icons/eyeClosed-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/eyeClosed.png
resources/lib/ooui/themes/wikimediaui/images/icons/eyeClosed.svg
resources/lib/ooui/themes/wikimediaui/images/icons/feedback-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/feedback-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/feedback-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/flag-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/flag-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/flag-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/flag-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/flag-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/flag-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-ltr-invert.png
resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-ltr-progressive.png
resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-ltr.png
resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-rtl-invert.png
resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-rtl-progressive.png
resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-rtl.png
resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/fullScreen-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/fullScreen-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/fullScreen.svg
resources/lib/ooui/themes/wikimediaui/images/icons/funnel-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/funnel-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/funnel-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/halfBright-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/halfBright-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/halfBright-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/halfStar-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/halfStar-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/halfStar-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-ltr-invert.png [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-ltr-invert.svg [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-ltr-progressive.png [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-ltr-progressive.svg [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-ltr.png [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-ltr.svg [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-rtl-invert.png [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-rtl-invert.svg [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-rtl-progressive.png [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-rtl-progressive.svg [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-rtl.png [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-rtl.svg [new file with mode: 0644]
resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-ltr-invert.png [deleted file]
resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-ltr-invert.svg [deleted file]
resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-ltr-progressive.png [deleted file]
resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-ltr-progressive.svg [deleted file]
resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-ltr.png [deleted file]
resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-ltr.svg [deleted file]
resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-rtl-invert.png [deleted file]
resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-rtl-invert.svg [deleted file]
resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-rtl-progressive.png [deleted file]
resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-rtl-progressive.svg [deleted file]
resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-rtl.png [deleted file]
resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-rtl.svg [deleted file]
resources/lib/ooui/themes/wikimediaui/images/icons/highlight-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/highlight-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/highlight.svg
resources/lib/ooui/themes/wikimediaui/images/icons/history-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/history-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/history.svg
resources/lib/ooui/themes/wikimediaui/images/icons/image-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/image-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/image.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageAdd-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageAdd-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageAdd-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageAdd-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageAdd-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageAdd-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageBroken-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageBroken-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageBroken.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageGallery-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageGallery-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageGallery.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageLayoutBasic-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageLayoutBasic-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageLayoutBasic.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageLayoutFrame-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageLayoutFrame-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageLayoutFrame.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageLayoutFrameless-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageLayoutFrameless-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageLayoutFrameless.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageLayoutThumbnail-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageLayoutThumbnail-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageLayoutThumbnail.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageLock-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageLock-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/imageLock-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/indent-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/indent-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/indent-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/italic-e-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/italic-e-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/italic-e.svg
resources/lib/ooui/themes/wikimediaui/images/icons/journal-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/journal-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/journal-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/journal-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/journal-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/journal-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/keyboard-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/keyboard-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/keyboard.svg
resources/lib/ooui/themes/wikimediaui/images/icons/layout-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/layout-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/layout-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/layout-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/layout-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/layout-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/linkExternal-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/linkExternal-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/linkExternal-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/linkExternal-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/linkExternal-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/linkExternal-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/listNumbered-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/listNumbered-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/listNumbered-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/listNumbered-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/listNumbered-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/listNumbered-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/logOut-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/logOut-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/logOut-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/logOut-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/logOut-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/logOut-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/mapTrail-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/mapTrail-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/mapTrail.svg
resources/lib/ooui/themes/wikimediaui/images/icons/markup-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/markup-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/markup.svg
resources/lib/ooui/themes/wikimediaui/images/icons/mathematics-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/mathematics-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/mathematics.svg
resources/lib/ooui/themes/wikimediaui/images/icons/mathematicsDisplayBlock-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/mathematicsDisplayBlock-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/mathematicsDisplayBlock.svg
resources/lib/ooui/themes/wikimediaui/images/icons/mathematicsDisplayDefault-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/mathematicsDisplayDefault-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/mathematicsDisplayDefault.svg
resources/lib/ooui/themes/wikimediaui/images/icons/mathematicsDisplayInline-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/mathematicsDisplayInline-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/mathematicsDisplayInline.svg
resources/lib/ooui/themes/wikimediaui/images/icons/message-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/message-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/message.svg
resources/lib/ooui/themes/wikimediaui/images/icons/move-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/move-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/move.svg
resources/lib/ooui/themes/wikimediaui/images/icons/moveFirst-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/moveFirst-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/moveFirst-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/moveFirst-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/moveFirst-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/moveFirst-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/moveLast-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/moveLast-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/moveLast-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/moveLast-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/moveLast-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/moveLast-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/newWindow-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/newWindow-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/newWindow-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/newWindow-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/newWindow-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/newWindow-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/newline-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/newline-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/newline-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/newspaper-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/newspaper-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/newspaper-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/newspaper-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/newspaper-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/newspaper-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/noWikiText-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/noWikiText-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/noWikiText.svg
resources/lib/ooui/themes/wikimediaui/images/icons/ongoingConversation-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/ongoingConversation-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/ongoingConversation-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/ongoingConversation-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/ongoingConversation-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/ongoingConversation-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/outdent-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/outdent-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/outdent-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/outline-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/outline-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/outline-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/play-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/play-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/play.svg
resources/lib/ooui/themes/wikimediaui/images/icons/printer-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/printer-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/printer.svg
resources/lib/ooui/themes/wikimediaui/images/icons/pushPin-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/pushPin-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/pushPin.svg
resources/lib/ooui/themes/wikimediaui/images/icons/quotes-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/quotes-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/quotes-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/redo-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/redo-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/redo-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/redo-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/redo-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/redo-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/reference-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/reference-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/reference.svg
resources/lib/ooui/themes/wikimediaui/images/icons/referenceExisting-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/referenceExisting-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/referenceExisting-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/referenceExisting-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/referenceExisting-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/referenceExisting-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/robot-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/robot-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/robot.svg
resources/lib/ooui/themes/wikimediaui/images/icons/settings-invert.png
resources/lib/ooui/themes/wikimediaui/images/icons/settings-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/settings-progressive.png
resources/lib/ooui/themes/wikimediaui/images/icons/settings-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/settings.png
resources/lib/ooui/themes/wikimediaui/images/icons/settings.svg
resources/lib/ooui/themes/wikimediaui/images/icons/smaller-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/smaller-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/smaller.svg
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-ltr-invert.png
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-ltr-progressive.png
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-ltr.png
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-rtl-invert.png
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-rtl-progressive.png
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-rtl.png
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbleAdd-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbleAdd-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbleAdd-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbleAdd-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbleAdd-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbleAdd-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-ltr-invert.png
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-ltr-progressive.png
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-ltr.png
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-rtl-invert.png
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-rtl-progressive.png
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-rtl.png
resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/strikethrough-a-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/strikethrough-a-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/strikethrough-a.svg
resources/lib/ooui/themes/wikimediaui/images/icons/strikethrough-y-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/strikethrough-y-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/strikethrough-y.svg
resources/lib/ooui/themes/wikimediaui/images/icons/subscript-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/subscript-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/subscript-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/superscript-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/superscript-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/superscript-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/superscript-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/superscript-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/superscript-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/table-invert.png
resources/lib/ooui/themes/wikimediaui/images/icons/table-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/table-progressive.png
resources/lib/ooui/themes/wikimediaui/images/icons/table-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/table.png
resources/lib/ooui/themes/wikimediaui/images/icons/table.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableAddColumnAfter-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableAddColumnAfter-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableAddColumnAfter.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableAddRowAfter-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableAddRowAfter-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableAddRowAfter.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableAddRowBefore-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableAddRowBefore-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableAddRowBefore.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableCaption-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableCaption-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableCaption.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableMergeCells-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableMergeCells-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableMergeCells.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableMoveColumnAfter-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableMoveColumnAfter-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableMoveColumnAfter.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableMoveColumnBefore-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableMoveColumnBefore-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableMoveColumnBefore.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableMoveRowAfter-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableMoveRowAfter-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableMoveRowAfter.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableMoveRowBefore-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableMoveRowBefore-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tableMoveRowBefore.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tag-ltr-destructive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tag-ltr-error.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tag-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tag-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tag-ltr-warning.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tag-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tag-rtl-destructive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tag-rtl-error.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tag-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tag-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tag-rtl-warning.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tag-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/templateAdd-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/templateAdd-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/templateAdd-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/textDirLTR-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/textDirLTR-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/textDirLTR.svg
resources/lib/ooui/themes/wikimediaui/images/icons/textDirRTL-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/textDirRTL-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/textDirRTL.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tray-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tray-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/tray.svg
resources/lib/ooui/themes/wikimediaui/images/icons/unBlock-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/unBlock-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/unBlock.svg
resources/lib/ooui/themes/wikimediaui/images/icons/unFlag-ltr-invert.png
resources/lib/ooui/themes/wikimediaui/images/icons/unFlag-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/unFlag-ltr-progressive.png
resources/lib/ooui/themes/wikimediaui/images/icons/unFlag-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/unFlag-ltr.png
resources/lib/ooui/themes/wikimediaui/images/icons/unFlag-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/unLock-destructive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/unLock-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/unLock-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/unLock.svg
resources/lib/ooui/themes/wikimediaui/images/icons/unTrash-invert.png
resources/lib/ooui/themes/wikimediaui/images/icons/unTrash-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/unTrash-progressive.png
resources/lib/ooui/themes/wikimediaui/images/icons/unTrash-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/unTrash.png
resources/lib/ooui/themes/wikimediaui/images/icons/unTrash.svg
resources/lib/ooui/themes/wikimediaui/images/icons/undo-ltr-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/undo-ltr-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/undo-ltr.svg
resources/lib/ooui/themes/wikimediaui/images/icons/undo-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/undo-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/undo-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/upTriangle-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/upTriangle-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/upTriangle.svg
resources/lib/ooui/themes/wikimediaui/images/icons/upload-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/upload-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/upload.svg
resources/lib/ooui/themes/wikimediaui/images/icons/userAnonymous-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/userAnonymous-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/userAnonymous.svg
resources/lib/ooui/themes/wikimediaui/images/icons/viewDetails-rtl-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/viewDetails-rtl-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/viewDetails-rtl.svg
resources/lib/ooui/themes/wikimediaui/images/icons/web-invert.png
resources/lib/ooui/themes/wikimediaui/images/icons/web-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/web-progressive.png
resources/lib/ooui/themes/wikimediaui/images/icons/web-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/web.png
resources/lib/ooui/themes/wikimediaui/images/icons/web.svg
resources/lib/ooui/themes/wikimediaui/images/icons/wikiText-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/wikiText-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/wikiText.svg
resources/lib/ooui/themes/wikimediaui/images/icons/window-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/window-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/window.svg
resources/lib/ooui/themes/wikimediaui/images/icons/zoomIn-invert.svg
resources/lib/ooui/themes/wikimediaui/images/icons/zoomIn-progressive.svg
resources/lib/ooui/themes/wikimediaui/images/icons/zoomIn.svg
resources/lib/ooui/themes/wikimediaui/images/indicators/down-invert.svg
resources/lib/ooui/themes/wikimediaui/images/indicators/down.svg
resources/lib/ooui/themes/wikimediaui/images/indicators/up-invert.svg
resources/lib/ooui/themes/wikimediaui/images/indicators/up.svg
resources/lib/ooui/themes/wikimediaui/images/textures/transparency.svg
resources/lib/ooui/themes/wikimediaui/textures.json
resources/src/jquery.spinner/images/spinner-large.gif [deleted file]
resources/src/jquery.spinner/images/spinner.gif [deleted file]
resources/src/jquery.spinner/spinner.css [deleted file]
resources/src/jquery.spinner/spinner.js
resources/src/jquery.spinner/spinner.less [new file with mode: 0644]
resources/src/jquery.tablesorter.styles/jquery.tablesorter.styles.less
resources/src/jquery.tipsy/jquery.tipsy.css
resources/src/jquery/jquery.confirmable.css
resources/src/jquery/jquery.confirmable.js
resources/src/jquery/jquery.lengthLimit.js
resources/src/jquery/jquery.makeCollapsible.styles.less
resources/src/jquery/jquery.suggestions.css
resources/src/jquery/jquery.suggestions.js
resources/src/mediawiki.String.js
resources/src/mediawiki.Title/.eslintrc.json [new file with mode: 0644]
resources/src/mediawiki.Title/Title.js
resources/src/mediawiki.Title/phpCharToUpper.js [deleted file]
resources/src/mediawiki.Title/phpCharToUpper.json [new file with mode: 0644]
resources/src/mediawiki.action/mediawiki.action.delete.file.js
resources/src/mediawiki.action/mediawiki.action.delete.js
resources/src/mediawiki.action/mediawiki.action.edit.collapsibleFooter.css
resources/src/mediawiki.action/mediawiki.action.edit.styles.less
resources/src/mediawiki.action/mediawiki.action.history.css
resources/src/mediawiki.action/mediawiki.action.history.styles.css [deleted file]
resources/src/mediawiki.action/mediawiki.action.history.styles.less [new file with mode: 0644]
resources/src/mediawiki.action/mediawiki.action.view.categoryPage.less
resources/src/mediawiki.action/mediawiki.action.view.filepage.css
resources/src/mediawiki.action/mediawiki.action.view.metadata.css
resources/src/mediawiki.action/mediawiki.action.view.metadata.js
resources/src/mediawiki.action/mediawiki.action.view.postEdit.less
resources/src/mediawiki.action/mediawiki.action.view.postEdit.monobook.css
resources/src/mediawiki.action/mediawiki.action.view.redirectPage.css
resources/src/mediawiki.api/parse.js
resources/src/mediawiki.api/upload.js
resources/src/mediawiki.apihelp.css
resources/src/mediawiki.apipretty.css
resources/src/mediawiki.base/mediawiki.base.js
resources/src/mediawiki.content.json.less
resources/src/mediawiki.cookie/.eslintrc.json [new file with mode: 0644]
resources/src/mediawiki.cookie/index.js
resources/src/mediawiki.debug/debug.js
resources/src/mediawiki.debug/debug.less
resources/src/mediawiki.diff.styles/diff.css
resources/src/mediawiki.diff.styles/print.css
resources/src/mediawiki.feedback/feedback.css
resources/src/mediawiki.feedback/feedback.js
resources/src/mediawiki.feedback/images/spinner.gif [deleted file]
resources/src/mediawiki.feedlink/feedlink.css
resources/src/mediawiki.filewarning/filewarning.less
resources/src/mediawiki.helplink/helplink.less
resources/src/mediawiki.helplink/images/help.png [deleted file]
resources/src/mediawiki.helplink/images/help.svg [deleted file]
resources/src/mediawiki.helplink/images/helpNotice.png [new file with mode: 0644]
resources/src/mediawiki.helplink/images/helpNotice.svg [new file with mode: 0644]
resources/src/mediawiki.hlist/default.css
resources/src/mediawiki.hlist/hlist.less
resources/src/mediawiki.htmlform.ooui.styles.less
resources/src/mediawiki.interface.helpers.styles.less
resources/src/mediawiki.jqueryMsg/.eslintrc.json [new file with mode: 0644]
resources/src/mediawiki.jqueryMsg/mediawiki.jqueryMsg.js
resources/src/mediawiki.legacy/commonPrint.css
resources/src/mediawiki.legacy/oldshared.css
resources/src/mediawiki.legacy/protect.js
resources/src/mediawiki.legacy/shared.css
resources/src/mediawiki.less/mediawiki.mixins.less
resources/src/mediawiki.less/mediawiki.ui/mixins.buttons.less [new file with mode: 0644]
resources/src/mediawiki.page.gallery.slideshow.js
resources/src/mediawiki.page.gallery.styles/gallery.css [deleted file]
resources/src/mediawiki.page.gallery.styles/gallery.less [new file with mode: 0644]
resources/src/mediawiki.page.gallery.styles/print.css
resources/src/mediawiki.page.ready.js
resources/src/mediawiki.page.rollback.js [deleted file]
resources/src/mediawiki.pager.tablePager/TablePager.less
resources/src/mediawiki.rcfilters/.eslintrc.json [new file with mode: 0644]
resources/src/mediawiki.rcfilters/Controller.js
resources/src/mediawiki.rcfilters/HighlightColors.js
resources/src/mediawiki.rcfilters/UriProcessor.js
resources/src/mediawiki.rcfilters/dm/ChangesListViewModel.js
resources/src/mediawiki.rcfilters/dm/FilterGroup.js
resources/src/mediawiki.rcfilters/dm/FilterItem.js
resources/src/mediawiki.rcfilters/dm/FiltersViewModel.js
resources/src/mediawiki.rcfilters/dm/ItemModel.js
resources/src/mediawiki.rcfilters/dm/SavedQueriesModel.js
resources/src/mediawiki.rcfilters/dm/SavedQueryItemModel.js
resources/src/mediawiki.rcfilters/mw.rcfilters.init.js
resources/src/mediawiki.rcfilters/mw.rcfilters.js
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less
resources/src/mediawiki.rcfilters/ui/ChangesLimitAndDateButtonWidget.js
resources/src/mediawiki.rcfilters/ui/ChangesLimitPopupWidget.js
resources/src/mediawiki.rcfilters/ui/ChangesListWrapperWidget.js
resources/src/mediawiki.rcfilters/ui/CheckboxInputWidget.js
resources/src/mediawiki.rcfilters/ui/DatePopupWidget.js
resources/src/mediawiki.rcfilters/ui/FilterItemHighlightButton.js
resources/src/mediawiki.rcfilters/ui/FilterMenuHeaderWidget.js
resources/src/mediawiki.rcfilters/ui/FilterMenuOptionWidget.js
resources/src/mediawiki.rcfilters/ui/FilterMenuSectionOptionWidget.js
resources/src/mediawiki.rcfilters/ui/FilterTagItemWidget.js
resources/src/mediawiki.rcfilters/ui/FilterTagMultiselectWidget.js
resources/src/mediawiki.rcfilters/ui/FilterWrapperWidget.js
resources/src/mediawiki.rcfilters/ui/FormWrapperWidget.js
resources/src/mediawiki.rcfilters/ui/GroupWidget.js
resources/src/mediawiki.rcfilters/ui/HighlightColorPickerWidget.js
resources/src/mediawiki.rcfilters/ui/HighlightPopupWidget.js
resources/src/mediawiki.rcfilters/ui/ItemMenuOptionWidget.js
resources/src/mediawiki.rcfilters/ui/LiveUpdateButtonWidget.js
resources/src/mediawiki.rcfilters/ui/MainWrapperWidget.js
resources/src/mediawiki.rcfilters/ui/MarkSeenButtonWidget.js
resources/src/mediawiki.rcfilters/ui/MenuSelectWidget.js
resources/src/mediawiki.rcfilters/ui/RcTopSectionWidget.js
resources/src/mediawiki.rcfilters/ui/RclTargetPageWidget.js
resources/src/mediawiki.rcfilters/ui/RclToOrFromWidget.js
resources/src/mediawiki.rcfilters/ui/RclTopSectionWidget.js
resources/src/mediawiki.rcfilters/ui/SaveFiltersPopupButtonWidget.js
resources/src/mediawiki.rcfilters/ui/SavedLinksListItemWidget.js
resources/src/mediawiki.rcfilters/ui/SavedLinksListWidget.js
resources/src/mediawiki.rcfilters/ui/TagItemWidget.js
resources/src/mediawiki.rcfilters/ui/ValuePickerWidget.js
resources/src/mediawiki.rcfilters/ui/ViewSwitchWidget.js
resources/src/mediawiki.rcfilters/ui/WatchlistTopSectionWidget.js
resources/src/mediawiki.rollback.confirmation.js [new file with mode: 0644]
resources/src/mediawiki.searchSuggest/searchSuggest.css
resources/src/mediawiki.skinning/content.css
resources/src/mediawiki.skinning/content.externallinks.less
resources/src/mediawiki.skinning/content.parsoid.less
resources/src/mediawiki.skinning/elements.css
resources/src/mediawiki.skinning/interface.css
resources/src/mediawiki.special.apisandbox/apisandbox.css
resources/src/mediawiki.special.block.js
resources/src/mediawiki.special.changeslist.enhanced.less
resources/src/mediawiki.special.changeslist.less [deleted file]
resources/src/mediawiki.special.changeslist/changeslist.less [new file with mode: 0644]
resources/src/mediawiki.special.changeslist/default.less [new file with mode: 0644]
resources/src/mediawiki.special.preferences.ooui/tabs.js
resources/src/mediawiki.special.preferences.styles.ooui.less
resources/src/mediawiki.special.revisionDelete.js
resources/src/mediawiki.special.search.interwikiwidget.styles.less
resources/src/mediawiki.special.search.styles.css
resources/src/mediawiki.special.upload/upload.js
resources/src/mediawiki.special.userlogin.common.styles/userlogin.css
resources/src/mediawiki.special.userlogin.signup.styles/signup.css
resources/src/mediawiki.special/apisandbox.css
resources/src/mediawiki.special/block.less
resources/src/mediawiki.special/blocklist.less [new file with mode: 0644]
resources/src/mediawiki.special/comparepages.less
resources/src/mediawiki.special/edittags.css
resources/src/mediawiki.special/movePage.css
resources/src/mediawiki.special/newpages.less
resources/src/mediawiki.special/pagesWithProp.css
resources/src/mediawiki.special/special.less
resources/src/mediawiki.special/upload.css
resources/src/mediawiki.special/userrights.css
resources/src/mediawiki.special/watchlist.css
resources/src/mediawiki.storage.js
resources/src/mediawiki.toc.styles/common.css
resources/src/mediawiki.toc.styles/print.css
resources/src/mediawiki.toc.styles/screen.less
resources/src/mediawiki.ui/components/buttons.less
resources/src/mediawiki.ui/components/checkbox.less
resources/src/mediawiki.ui/components/forms.less
resources/src/mediawiki.user.js
resources/src/mediawiki.widgets.datetime/DiscordianDateTimeFormatter.js
resources/src/mediawiki.widgets.visibleLengthLimit/mediawiki.widgets.visibleLengthLimit.js
resources/src/mediawiki.widgets/MediaSearch/mw.widgets.MediaResultWidget.js
resources/src/mediawiki.widgets/images/page-disambiguation-ltr.svg [deleted file]
resources/src/mediawiki.widgets/images/page-disambiguation-rtl.svg [deleted file]
resources/src/mediawiki.widgets/images/page-existing-ltr.svg [deleted file]
resources/src/mediawiki.widgets/images/page-existing-rtl.svg [deleted file]
resources/src/mediawiki.widgets/images/page-not-found-he-yi.svg [deleted file]
resources/src/mediawiki.widgets/images/page-not-found-ltr.svg [deleted file]
resources/src/mediawiki.widgets/images/page-not-found-rtl.svg [deleted file]
resources/src/mediawiki.widgets/images/page-redirect-ltr.svg [deleted file]
resources/src/mediawiki.widgets/images/page-redirect-rtl.svg [deleted file]
resources/src/mediawiki.widgets/mw.widgets.DateInputWidget.js
resources/src/mediawiki.widgets/mw.widgets.DateInputWidget.styles.less
resources/src/mediawiki.widgets/mw.widgets.SearchInputWidget.js
resources/src/mediawiki.widgets/mw.widgets.TitleOptionWidget.js
resources/src/mediawiki.widgets/mw.widgets.TitleWidget.js
resources/src/mediawiki.widgets/mw.widgets.TitleWidget.less
resources/src/startup/mediawiki.js
resources/src/startup/startup.js
skins/README
tests/common/TestsAutoLoader.php
tests/integration/includes/http/CurlHttpRequestTest.php
tests/integration/includes/http/MWHttpRequestTest.php [new file with mode: 0644]
tests/integration/includes/http/MWHttpRequestTestCase.php
tests/integration/includes/shell/FirejailCommandIntegrationTest.php
tests/parser/ParserTestPrinter.php
tests/parser/ParserTestRunner.php
tests/parser/parserTests.txt
tests/phan/bin/postprocess-phan.php
tests/phan/config.php [deleted file]
tests/phan/stubs/README [deleted file]
tests/phan/stubs/excimer.php [deleted file]
tests/phan/stubs/hhvm.php [deleted file]
tests/phan/stubs/mail.php [deleted file]
tests/phan/stubs/memcached.php [deleted file]
tests/phan/stubs/phpunit4.php [deleted file]
tests/phan/stubs/tideways.php [deleted file]
tests/phan/stubs/wikidiff.php [deleted file]
tests/phpunit/MediaWikiLoggerPHPUnitTestListener.php
tests/phpunit/MediaWikiTestCase.php
tests/phpunit/PHPUnit4And6Compat.php
tests/phpunit/ResourceLoaderTestCase.php
tests/phpunit/bootstrap.php
tests/phpunit/documentation/ReleaseNotesTest.php
tests/phpunit/includes/ActorMigrationTest.php
tests/phpunit/includes/BlockTest.php
tests/phpunit/includes/CategoryTest.php [new file with mode: 0644]
tests/phpunit/includes/ContentSecurityPolicyTest.php
tests/phpunit/includes/EditPageTest.php
tests/phpunit/includes/FauxRequestTest.php
tests/phpunit/includes/FormOptionsTest.php
tests/phpunit/includes/GlobalFunctions/GlobalTest.php
tests/phpunit/includes/GlobalFunctions/wfArrayFilterTest.php [deleted file]
tests/phpunit/includes/LinkerTest.php
tests/phpunit/includes/MWNamespaceTest.php [deleted file]
tests/phpunit/includes/MagicWordFactoryTest.php
tests/phpunit/includes/MediaWikiServicesTest.php
tests/phpunit/includes/MediaWikiVersionFetcherTest.php
tests/phpunit/includes/MessageTest.php
tests/phpunit/includes/OutputPageTest.php
tests/phpunit/includes/PagePropsTest.php
tests/phpunit/includes/Permissions/PermissionManagerTest.php [new file with mode: 0644]
tests/phpunit/includes/ReadOnlyModeTest.php
tests/phpunit/includes/Revision/RevisionStoreDbTestBase.php
tests/phpunit/includes/Revision/RevisionStoreTest.php
tests/phpunit/includes/RevisionDbTestBase.php
tests/phpunit/includes/RevisionMcrWriteBothDbTest.php
tests/phpunit/includes/RevisionNoContentModelDbTest.php
tests/phpunit/includes/RevisionPreMcrDbTest.php
tests/phpunit/includes/RevisionTest.php
tests/phpunit/includes/ServiceWiringTest.php
tests/phpunit/includes/SiteStatsTest.php
tests/phpunit/includes/Storage/DerivedPageDataUpdaterTest.php
tests/phpunit/includes/Storage/NameTableStoreTest.php
tests/phpunit/includes/Storage/PreparedEditTest.php [new file with mode: 0644]
tests/phpunit/includes/SystemBlockTest.php [new file with mode: 0644]
tests/phpunit/includes/TestUserRegistry.php
tests/phpunit/includes/TitleMethodsTest.php
tests/phpunit/includes/TitlePermissionTest.php
tests/phpunit/includes/TitleTest.php
tests/phpunit/includes/WebRequestTest.php
tests/phpunit/includes/WikiMapTest.php
tests/phpunit/includes/actions/WatchActionTest.php
tests/phpunit/includes/api/ApiBaseTest.php
tests/phpunit/includes/api/ApiBlockInfoTraitTest.php [new file with mode: 0644]
tests/phpunit/includes/api/ApiBlockTest.php
tests/phpunit/includes/api/ApiLogoutTest.php [new file with mode: 0644]
tests/phpunit/includes/api/ApiMoveTest.php
tests/phpunit/includes/api/ApiParseTest.php
tests/phpunit/includes/api/ApiQueryRecentChangesIntegrationTest.php
tests/phpunit/includes/api/ApiQuerySiteinfoTest.php
tests/phpunit/includes/api/ApiQueryUserInfoTest.php
tests/phpunit/includes/api/ApiQueryWatchlistIntegrationTest.php
tests/phpunit/includes/api/ApiStashEditTest.php
tests/phpunit/includes/api/query/ApiQueryAllRevisionsTest.php [new file with mode: 0644]
tests/phpunit/includes/api/query/ApiQueryTestBase.php
tests/phpunit/includes/api/query/ApiQueryUserContribsTest.php
tests/phpunit/includes/auth/AuthManagerTest.php
tests/phpunit/includes/auth/TemporaryPasswordPrimaryAuthenticationProviderTest.php
tests/phpunit/includes/auth/UserDataAuthenticationRequestTest.php
tests/phpunit/includes/block/BlockManagerTest.php [new file with mode: 0644]
tests/phpunit/includes/block/BlockRestrictionStoreTest.php [new file with mode: 0644]
tests/phpunit/includes/block/BlockRestrictionTest.php [deleted file]
tests/phpunit/includes/cache/MessageCacheTest.php
tests/phpunit/includes/changes/CategoryMembershipChangeTest.php
tests/phpunit/includes/changes/EnhancedChangesListTest.php
tests/phpunit/includes/changes/OldChangesListTest.php
tests/phpunit/includes/changes/RCCacheEntryFactoryTest.php
tests/phpunit/includes/config/GlobalVarConfigTest.php
tests/phpunit/includes/config/ServiceOptionsTest.php [new file with mode: 0644]
tests/phpunit/includes/content/ContentHandlerTest.php
tests/phpunit/includes/content/JsonContentTest.php
tests/phpunit/includes/content/TextContentHandlerTest.php
tests/phpunit/includes/db/DatabasePostgresTest.php
tests/phpunit/includes/db/DatabaseSqliteTest.php
tests/phpunit/includes/db/DatabaseTestHelper.php
tests/phpunit/includes/db/LBFactoryTest.php
tests/phpunit/includes/db/LoadBalancerTest.php
tests/phpunit/includes/debug/DeprecationHelperTest.php
tests/phpunit/includes/debug/TestDeprecatedSubclass.php
tests/phpunit/includes/diff/DifferenceEngineTest.php
tests/phpunit/includes/diff/TextSlotDiffRendererTest.php
tests/phpunit/includes/editpage/TextboxBuilderTest.php
tests/phpunit/includes/filebackend/FileBackendTest.php
tests/phpunit/includes/filerepo/FileBackendDBRepoWrapperTest.php
tests/phpunit/includes/filerepo/MigrateFileRepoLayoutTest.php
tests/phpunit/includes/filerepo/RepoGroupTest.php
tests/phpunit/includes/http/HttpRequestFactoryTest.php [new file with mode: 0644]
tests/phpunit/includes/http/HttpTest.php
tests/phpunit/includes/jobqueue/JobQueueMemoryTest.php
tests/phpunit/includes/jobqueue/JobQueueTest.php
tests/phpunit/includes/jobqueue/JobTest.php
tests/phpunit/includes/jobqueue/jobs/ClearUserWatchlistJobTest.php
tests/phpunit/includes/libs/ArrayUtilsTest.php
tests/phpunit/includes/libs/CSSMinTest.php
tests/phpunit/includes/libs/CookieTest.php [new file with mode: 0644]
tests/phpunit/includes/libs/MWMessagePackTest.php
tests/phpunit/includes/libs/objectcache/BagOStuffTest.php
tests/phpunit/includes/libs/objectcache/CachedBagOStuffTest.php
tests/phpunit/includes/libs/objectcache/MultiWriteBagOStuffTest.php
tests/phpunit/includes/libs/objectcache/ReplicatedBagOStuffTest.php
tests/phpunit/includes/libs/rdbms/database/DBConnRefTest.php
tests/phpunit/includes/libs/rdbms/database/DatabaseDomainTest.php
tests/phpunit/includes/libs/rdbms/database/DatabaseMssqlTest.php
tests/phpunit/includes/libs/rdbms/database/DatabaseSQLTest.php
tests/phpunit/includes/libs/rdbms/database/DatabaseTest.php
tests/phpunit/includes/linkeddata/PageDataRequestHandlerTest.php
tests/phpunit/includes/linker/LinkRendererFactoryTest.php
tests/phpunit/includes/linker/LinkRendererTest.php
tests/phpunit/includes/logging/LogFormatterTest.php
tests/phpunit/includes/media/MediaWikiMediaTestCase.php
tests/phpunit/includes/objectcache/RESTBagOStuffTest.php
tests/phpunit/includes/page/PageArchiveMcrTest.php
tests/phpunit/includes/page/PageArchivePreMcrTest.php
tests/phpunit/includes/page/PageArchiveTestBase.php
tests/phpunit/includes/page/WikiPageDbTestBase.php
tests/phpunit/includes/parser/ParserFactoryTest.php
tests/phpunit/includes/parser/ParserMethodsTest.php
tests/phpunit/includes/parser/ParserOptionsTest.php
tests/phpunit/includes/parser/ParserTest.php [new file with mode: 0644]
tests/phpunit/includes/password/PasswordTestCase.php
tests/phpunit/includes/poolcounter/PoolCounterTest.php
tests/phpunit/includes/preferences/DefaultPreferencesFactoryTest.php
tests/phpunit/includes/registration/VersionCheckerTest.php
tests/phpunit/includes/resourceloader/DerivativeResourceLoaderContextTest.php
tests/phpunit/includes/resourceloader/MessageBlobStoreTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderClientHtmlTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderContextTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderImageTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderOOUIImageModuleTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderSkinModuleTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderStartUpModuleTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderWikiModuleTest.php
tests/phpunit/includes/search/SearchEngineTest.php
tests/phpunit/includes/session/SessionProviderTest.php
tests/phpunit/includes/shell/ShellTest.php
tests/phpunit/includes/site/CachingSiteStoreTest.php
tests/phpunit/includes/specialpage/ChangesListSpecialPageTest.php
tests/phpunit/includes/specialpage/SpecialPageTest.php
tests/phpunit/includes/specials/ContribsPagerTest.php
tests/phpunit/includes/specials/QueryAllSpecialPagesTest.php
tests/phpunit/includes/specials/SpecialBlockTest.php
tests/phpunit/includes/specials/SpecialWatchlistTest.php
tests/phpunit/includes/specials/pagers/BlockListPagerTest.php
tests/phpunit/includes/title/MediaWikiTitleCodecTest.php
tests/phpunit/includes/title/NamespaceInfoTest.php [new file with mode: 0644]
tests/phpunit/includes/title/TitleValueTest.php
tests/phpunit/includes/user/BotPasswordTest.php
tests/phpunit/includes/user/PasswordResetTest.php
tests/phpunit/includes/user/UserTest.php
tests/phpunit/includes/watcheditem/NoWriteWatchedItemStoreUnitTest.php
tests/phpunit/includes/watcheditem/WatchedItemQueryServiceUnitTest.php
tests/phpunit/includes/watcheditem/WatchedItemStoreIntegrationTest.php
tests/phpunit/includes/watcheditem/WatchedItemStoreUnitTest.php
tests/phpunit/languages/LanguageTest.php
tests/phpunit/languages/classes/LanguageSrTest.php
tests/phpunit/languages/classes/LanguageUzTest.php
tests/phpunit/maintenance/DumpAsserter.php [new file with mode: 0644]
tests/phpunit/maintenance/DumpTestCase.php
tests/phpunit/maintenance/backupTextPassTest.php
tests/phpunit/maintenance/backup_LogTest.php
tests/phpunit/maintenance/backup_PageTest.php
tests/phpunit/maintenance/xml.xsd [new file with mode: 0644]
tests/phpunit/mocks/filebackend/MockFileBackend.php
tests/phpunit/mocks/filerepo/MockLocalRepo.php
tests/phpunit/mocks/search/MockSearchResult.php
tests/phpunit/structure/ApiStructureTest.php
tests/phpunit/structure/AutoLoaderStructureTest.php
tests/phpunit/structure/AvailableRightsTest.php
tests/phpunit/structure/SpecialPageFatalTest.php
tests/phpunit/suites/ParserTestTopLevelSuite.php
tests/phpunit/suites/UploadFromUrlTestSuite.php
tests/phpunit/tests/MediaWikiTestCaseTest.php
tests/qunit/data/load.mock.php
tests/qunit/suites/resources/mediawiki.api/mediawiki.api.parse.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.loader.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.storage.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.user.test.js
tests/qunit/suites/resources/startup.test.js
tests/selenium/.eslintrc.json
tests/selenium/pageobjects/history.page.js
tests/selenium/specs/page.js
tests/selenium/specs/rollback.js [new file with mode: 0644]
tests/selenium/wdio-mediawiki/Api.js
tests/selenium/wdio-mediawiki/Util.js
tests/selenium/wdio.conf.js

index e694294..334f971 100644 (file)
@@ -1,10 +1,10 @@
 warmup: true
-runs: 5
+runs: 7
 scenarios:
-  Load a page:
+  Read a page:
     # The only page that exists by default is the main page.
-    # But, its actual name is configurable/unknown (T216791).
-    # Omit 'title' to let MediaWiki show the defaul (which is the main page),
+    # But its actual name is configurable/unknown (T216791).
+    # Omit 'title' to let MediaWiki show the default (which is the main page),
     # and a query string to prevent a normalization redirect.
     url: "{MW_SERVER}{MW_SCRIPT_PATH}/index.php?noredirectplz"
     viewport:
@@ -29,6 +29,18 @@ scenarios:
     probes:
       - screenshot
       - trace
+  View history of a page:
+    url: "{MW_SERVER}{MW_SCRIPT_PATH}/index.php?action=history"
+    viewport:
+      width: 1100
+      height: 700
+    reports:
+      - navtiming
+      - paint
+      - transfer
+    probes:
+      - screenshot
+      - trace
   View recent changes:
     url: "{MW_SERVER}{MW_SCRIPT_PATH}/index.php?title=Special:RecentChanges"
     viewport:
index def5a08..8cacb1e 100644 (file)
@@ -50,6 +50,7 @@ sftp-config.json
 # Building & testing
 npm-debug.log
 node_modules/
+/resources/lib/.foreign
 /tests/phpunit/phpunit.phar
 /tests/selenium/log
 .eslintcache
diff --git a/.phan/config.php b/.phan/config.php
new file mode 100644 (file)
index 0000000..3478977
--- /dev/null
@@ -0,0 +1,142 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+$cfg = require __DIR__ . '/../vendor/mediawiki/mediawiki-phan-config/src/config.php';
+
+$cfg['file_list'] = array_merge(
+       $cfg['file_list'],
+       function_exists( 'register_postsend_function' ) ? [] : [ '.phan/stubs/hhvm.php' ],
+       function_exists( 'wikidiff2_do_diff' ) ? [] : [ '.phan/stubs/wikidiff.php' ],
+       class_exists( PEAR::class ) ? [] : [ '.phan/stubs/mail.php' ],
+       defined( 'PASSWORD_ARGON2I' ) ? [] : [ '.phan/stubs/password.php' ],
+       // Per composer.json, PHPUnit 6 is used for PHP 7.0+, PHPUnit 4 otherwise.
+       // Load the interface for the version of PHPUnit that isn't installed.
+       // Phan only supports PHP 7.0+ (and not HHVM), so we only need to stub PHPUnit 4.
+       class_exists( PHPUnit_TextUI_Command::class ) ? [] : [ '.phan/stubs/phpunit4.php' ],
+       class_exists( ProfilerExcimer::class ) ? [] : [ '.phan/stubs/excimer.php' ],
+       [
+               'maintenance/cleanupTable.inc',
+               'maintenance/CodeCleanerGlobalsPass.inc',
+               'maintenance/commandLine.inc',
+               'maintenance/sqlite.inc',
+               'maintenance/userDupes.inc',
+               'maintenance/language/checkLanguage.inc',
+               'maintenance/language/languages.inc',
+       ]
+);
+
+$cfg['autoload_internal_extension_signatures'] = [
+       'memcached' => '.phan/internal_stubs/memcached.phan_php',
+       'oci8' => '.phan/internal_stubs/oci8.phan_php',
+       'sqlsrv' => '.phan/internal_stubs/sqlsrv.phan_php',
+       'tideways' => '.phan/internal_stubs/tideways.phan_php',
+];
+
+$cfg['directory_list'] = [
+       'includes/',
+       'languages/',
+       'maintenance/',
+       'mw-config/',
+       'resources/',
+       'vendor/',
+       '.phan/stubs/',
+];
+
+$cfg['exclude_analysis_directory_list'] = [
+       'vendor/',
+       '.phan/stubs/',
+       // The referenced classes are not available in vendor, only when
+       // included from composer.
+       'includes/composer/',
+       // Directly references classes that only exist in Translate extension
+       'maintenance/language/',
+       // External class
+       'includes/libs/jsminplus.php',
+];
+
+$cfg['suppress_issue_types'] = array_merge( $cfg['suppress_issue_types'], [
+       // approximate error count: 18
+       "PhanAccessMethodInternal",
+       // approximate error count: 17
+       "PhanCommentParamOnEmptyParamList",
+       // approximate error count: 29
+       "PhanCommentParamWithoutRealParam",
+       // approximate error count: 2
+       "PhanCompatibleNegativeStringOffset",
+       // approximate error count: 21
+       "PhanParamReqAfterOpt",
+       // approximate error count: 26
+       "PhanParamSignatureMismatch",
+       // approximate error count: 4
+       "PhanParamSignatureMismatchInternal",
+       // approximate error count: 127
+       "PhanParamTooMany",
+       // approximate error count: 2
+       "PhanTraitParentReference",
+       // approximate error count: 30
+       "PhanTypeArraySuspicious",
+       // approximate error count: 27
+       "PhanTypeArraySuspiciousNullable",
+       // approximate error count: 26
+       "PhanTypeComparisonFromArray",
+       // approximate error count: 63
+       "PhanTypeInvalidDimOffset",
+       // approximate error count: 7
+       "PhanTypeInvalidLeftOperandOfIntegerOp",
+       // approximate error count: 2
+       "PhanTypeInvalidRightOperandOfIntegerOp",
+       // approximate error count: 154
+       "PhanTypeMismatchArgument",
+       // approximate error count: 27
+       "PhanTypeMismatchArgumentInternal",
+       // approximate error count: 2
+       "PhanTypeMismatchDimEmpty",
+       // approximate error count: 27
+       "PhanTypeMismatchDimFetch",
+       // approximate error count: 10
+       "PhanTypeMismatchForeach",
+       // approximate error count: 77
+       "PhanTypeMismatchProperty",
+       // approximate error count: 84
+       "PhanTypeMismatchReturn",
+       // approximate error count: 12
+       "PhanTypeObjectUnsetDeclaredProperty",
+       // approximate error count: 9
+       "PhanTypeSuspiciousNonTraversableForeach",
+       // approximate error count: 3
+       "PhanTypeSuspiciousStringExpression",
+       // approximate error count: 22
+       "PhanUndeclaredConstant",
+       // approximate error count: 3
+       "PhanUndeclaredInvokeInCallable",
+       // approximate error count: 237
+       "PhanUndeclaredMethod",
+       // approximate error count: 846
+       "PhanUndeclaredProperty",
+       // approximate error count: 2
+       "PhanUndeclaredVariableAssignOp",
+       // approximate error count: 55
+       "PhanUndeclaredVariableDim",
+] );
+
+$cfg['ignore_undeclared_variables_in_global_scope'] = true;
+$cfg['globals_type_map']['IP'] = 'string';
+
+return $cfg;
diff --git a/.phan/internal_stubs/memcached.phan_php b/.phan/internal_stubs/memcached.phan_php
new file mode 100644 (file)
index 0000000..8a85baf
--- /dev/null
@@ -0,0 +1,180 @@
+<?php
+// These stubs were generated by the phan stub generator.
+// @phan-stub-for-extension memcached@3.0.1
+
+namespace {
+class Memcached {
+
+    // constants
+    const LIBMEMCACHED_VERSION_HEX = 16777240;
+    const OPT_COMPRESSION = -1001;
+    const OPT_COMPRESSION_TYPE = -1004;
+    const OPT_PREFIX_KEY = -1002;
+    const OPT_SERIALIZER = -1003;
+    const OPT_USER_FLAGS = -1006;
+    const OPT_STORE_RETRY_COUNT = -1005;
+    const HAVE_IGBINARY = true;
+    const HAVE_JSON = true;
+    const HAVE_MSGPACK = true;
+    const HAVE_SESSION = true;
+    const HAVE_SASL = true;
+    const OPT_HASH = 2;
+    const HASH_DEFAULT = 0;
+    const HASH_MD5 = 1;
+    const HASH_CRC = 2;
+    const HASH_FNV1_64 = 3;
+    const HASH_FNV1A_64 = 4;
+    const HASH_FNV1_32 = 5;
+    const HASH_FNV1A_32 = 6;
+    const HASH_HSIEH = 7;
+    const HASH_MURMUR = 8;
+    const OPT_DISTRIBUTION = 9;
+    const DISTRIBUTION_MODULA = 0;
+    const DISTRIBUTION_CONSISTENT = 1;
+    const DISTRIBUTION_VIRTUAL_BUCKET = 6;
+    const OPT_LIBKETAMA_COMPATIBLE = 16;
+    const OPT_LIBKETAMA_HASH = 17;
+    const OPT_TCP_KEEPALIVE = 32;
+    const OPT_BUFFER_WRITES = 10;
+    const OPT_BINARY_PROTOCOL = 18;
+    const OPT_NO_BLOCK = 0;
+    const OPT_TCP_NODELAY = 1;
+    const OPT_SOCKET_SEND_SIZE = 4;
+    const OPT_SOCKET_RECV_SIZE = 5;
+    const OPT_CONNECT_TIMEOUT = 14;
+    const OPT_RETRY_TIMEOUT = 15;
+    const OPT_DEAD_TIMEOUT = 36;
+    const OPT_SEND_TIMEOUT = 19;
+    const OPT_RECV_TIMEOUT = 20;
+    const OPT_POLL_TIMEOUT = 8;
+    const OPT_CACHE_LOOKUPS = 6;
+    const OPT_SERVER_FAILURE_LIMIT = 21;
+    const OPT_AUTO_EJECT_HOSTS = 28;
+    const OPT_HASH_WITH_PREFIX_KEY = 25;
+    const OPT_NOREPLY = 26;
+    const OPT_SORT_HOSTS = 12;
+    const OPT_VERIFY_KEY = 13;
+    const OPT_USE_UDP = 27;
+    const OPT_NUMBER_OF_REPLICAS = 29;
+    const OPT_RANDOMIZE_REPLICA_READ = 30;
+    const OPT_REMOVE_FAILED_SERVERS = 35;
+    const OPT_SERVER_TIMEOUT_LIMIT = 37;
+    const RES_SUCCESS = 0;
+    const RES_FAILURE = 1;
+    const RES_HOST_LOOKUP_FAILURE = 2;
+    const RES_UNKNOWN_READ_FAILURE = 7;
+    const RES_PROTOCOL_ERROR = 8;
+    const RES_CLIENT_ERROR = 9;
+    const RES_SERVER_ERROR = 10;
+    const RES_WRITE_FAILURE = 5;
+    const RES_DATA_EXISTS = 12;
+    const RES_NOTSTORED = 14;
+    const RES_NOTFOUND = 16;
+    const RES_PARTIAL_READ = 18;
+    const RES_SOME_ERRORS = 19;
+    const RES_NO_SERVERS = 20;
+    const RES_END = 21;
+    const RES_ERRNO = 26;
+    const RES_BUFFERED = 32;
+    const RES_TIMEOUT = 31;
+    const RES_BAD_KEY_PROVIDED = 33;
+    const RES_STORED = 15;
+    const RES_DELETED = 22;
+    const RES_STAT = 24;
+    const RES_ITEM = 25;
+    const RES_NOT_SUPPORTED = 28;
+    const RES_FETCH_NOTFINISHED = 30;
+    const RES_SERVER_MARKED_DEAD = 35;
+    const RES_UNKNOWN_STAT_KEY = 36;
+    const RES_INVALID_HOST_PROTOCOL = 34;
+    const RES_MEMORY_ALLOCATION_FAILURE = 17;
+    const RES_CONNECTION_SOCKET_CREATE_FAILURE = 11;
+    const RES_E2BIG = 37;
+    const RES_KEY_TOO_BIG = 39;
+    const RES_SERVER_TEMPORARILY_DISABLED = 47;
+    const RES_SERVER_MEMORY_ALLOCATION_FAILURE = 48;
+    const RES_AUTH_PROBLEM = 40;
+    const RES_AUTH_FAILURE = 41;
+    const RES_AUTH_CONTINUE = 42;
+    const RES_PAYLOAD_FAILURE = -1001;
+    const SERIALIZER_PHP = 1;
+    const SERIALIZER_IGBINARY = 2;
+    const SERIALIZER_JSON = 3;
+    const SERIALIZER_JSON_ARRAY = 4;
+    const SERIALIZER_MSGPACK = 5;
+    const COMPRESSION_FASTLZ = 2;
+    const COMPRESSION_ZLIB = 1;
+    const GET_PRESERVE_ORDER = 1;
+    const GET_EXTENDED = 2;
+    const GET_ERROR_RETURN_VALUE = false;
+
+    // methods
+    public function __construct($persistent_id = null, $callback = null) {}
+    public function getResultCode() {}
+    public function getResultMessage() {}
+    public function get($key, $cache_cb = null, $get_flags = null) {}
+    public function getByKey($server_key, $key, $cache_cb = null, $get_flags = null) {}
+    public function getMulti(array $keys, $get_flags = null) {}
+    public function getMultiByKey($server_key, array $keys, $get_flags = null) {}
+    public function getDelayed(array $keys, $with_cas = null, $value_cb = null) {}
+    public function getDelayedByKey($server_key, array $keys, $with_cas = null, $value_cb = null) {}
+    public function fetch() {}
+    public function fetchAll() {}
+    public function set($key, $value, $expiration = null) {}
+    public function setByKey($server_key, $key, $value, $expiration = null) {}
+    public function touch($key, $expiration) {}
+    public function touchByKey($server_key, $key, $expiration) {}
+    public function setMulti(array $items, $expiration = null) {}
+    public function setMultiByKey($server_key, array $items, $expiration = null) {}
+    public function cas($cas_token, $key, $value, $expiration = null) {}
+    public function casByKey($cas_token, $server_key, $key, $value, $expiration = null) {}
+    public function add($key, $value, $expiration = null) {}
+    public function addByKey($server_key, $key, $value, $expiration = null) {}
+    public function append($key, $value, $expiration = null) {}
+    public function appendByKey($server_key, $key, $value, $expiration = null) {}
+    public function prepend($key, $value, $expiration = null) {}
+    public function prependByKey($server_key, $key, $value, $expiration = null) {}
+    public function replace($key, $value, $expiration = null) {}
+    public function replaceByKey($server_key, $key, $value, $expiration = null) {}
+    public function delete($key, $time = null) {}
+    public function deleteMulti($keys, $time = null) {}
+    public function deleteByKey($server_key, $key, $time = null) {}
+    public function deleteMultiByKey($server_key, $keys, $time = null) {}
+    public function increment($key, $offset = null, $initial_value = null, $expiry = null) {}
+    public function decrement($key, $offset = null, $initial_value = null, $expiry = null) {}
+    public function incrementByKey($server_key, $key, $offset = null, $initial_value = null, $expiry = null) {}
+    public function decrementByKey($server_key, $key, $offset = null, $initial_value = null, $expiry = null) {}
+    public function addServer($host, $port, $weight = null) {}
+    public function addServers(array $servers) {}
+    public function getServerList() {}
+    public function getServerByKey($server_key) {}
+    public function resetServerList() {}
+    public function quit() {}
+    public function flushBuffers() {}
+    public function getLastErrorMessage() {}
+    public function getLastErrorCode() {}
+    public function getLastErrorErrno() {}
+    public function getLastDisconnectedServer() {}
+    public function getStats($args) {}
+    public function getVersion() {}
+    public function getAllKeys() {}
+    public function flush($delay = null) {}
+    public function getOption($option) {}
+    public function setOption($option, $value) {}
+    public function setOptions($options) {}
+    public function setBucket($host_map, $forward_map, $replicas) {}
+    public function setSaslAuthData($username, $password) {}
+    public function isPersistent() {}
+    public function isPristine() {}
+}
+
+class MemcachedException extends \RuntimeException {
+
+    // properties
+    protected $message;
+    protected $code;
+    protected $file;
+    protected $line;
+}
+
+}
diff --git a/.phan/internal_stubs/oci8.phan_php b/.phan/internal_stubs/oci8.phan_php
new file mode 100644 (file)
index 0000000..78f334e
--- /dev/null
@@ -0,0 +1,589 @@
+<?php
+
+// @phan-stub-for-extension oci8@2.0.7
+
+
+class OCI_Lob  {
+
+       
+       public function load () {}
+
+       
+       public function tell () {}
+
+       
+       public function truncate ($length = 0) {}
+
+       
+       public function erase ($offset = null, $length = null) {}
+
+       
+       public function flush ($flag = null) {}
+
+       
+       public function setbuffering ($on_off) {}
+
+       
+       public function getbuffering () {}
+
+       
+       public function rewind () {}
+
+       
+       public function read ($length) {}
+
+       
+       public function eof () {}
+
+       
+       public function seek ($offset, $whence = OCI_SEEK_SET) {}
+
+       
+       public function write ($data, $length = null) {}
+
+       
+       public function append (OCI_Lob $lob_from) {}
+
+       
+       public function size () {}
+
+       
+       public function writetofile ($filename, $start, $length) {}
+
+       
+       public function export ($filename, $start = null, $length = null) {}
+
+       
+       public function import ($filename) {}
+
+       
+       public function writeTemporary ($data, $lob_type = OCI_TEMP_CLOB) {}
+
+       
+       public function close () {}
+
+       
+       public function save ($data, $offset = null) {}
+
+       
+       public function savefile ($filename) {}
+
+       
+       public function free () {}
+
+}
+
+
+class OCI_Collection  {
+
+       
+       public function append ($value) {}
+
+       
+       public function getelem ($index) {}
+
+       
+       public function assignelem ($index, $value) {}
+
+       
+       public function assign (OCI_Collection $from) {}
+
+       
+       public function size () {}
+
+       
+       public function max () {}
+
+       
+       public function trim ($num) {}
+
+       
+       public function free () {}
+
+}
+
+
+function oci_define_by_name ($statement, $column_name, &$variable, $type = SQLT_CHR) {}
+
+
+function oci_bind_by_name ($statement, $bv_name, &$variable, $maxlength = -1, $type = SQLT_CHR) {}
+
+
+function oci_bind_array_by_name ($statement, $name, array &$var_array, $max_table_length, $max_item_length = -1, $type = SQLT_AFC) {}
+
+
+function oci_field_is_null ($statement, $field) {}
+
+
+function oci_field_name ($statement, $field) {}
+
+
+function oci_field_size ($statement, $field) {}
+
+
+function oci_field_scale ($statement, $field) {}
+
+
+function oci_field_precision ($statement, $field) {}
+
+
+function oci_field_type ($statement, $field) {}
+
+
+function oci_field_type_raw ($statement, $field) {}
+
+
+function oci_execute ($statement, $mode = OCI_COMMIT_ON_SUCCESS) {}
+
+
+function oci_cancel ($statement) {}
+
+
+function oci_fetch ($statement) {}
+
+
+function oci_fetch_object ($statement) {}
+
+
+function oci_fetch_row ($statement) {}
+
+
+function oci_fetch_assoc ($statement) {}
+
+
+function oci_fetch_array ($statement, $mode = null) {}
+
+
+function ocifetchinto ($statement_resource, &$result, $mode = null) {}
+
+
+function oci_fetch_all ($statement, array &$output, $skip = 0, $maxrows = -1, $flags = OCI_FETCHSTATEMENT_BY_COLUMN | OCI_ASSOC) {}
+
+
+function oci_free_statement ($statement) {}
+
+
+function oci_internal_debug ($onoff) {}
+
+
+function oci_num_fields ($statement) {}
+
+
+function oci_parse ($connection, $sql_text) {}
+
+
+function oci_get_implicit_resultset ($statement) {}
+
+
+function oci_new_cursor ($connection) {}
+
+
+function oci_result ($statement, $field) {}
+
+
+function oci_client_version () {}
+
+
+function oci_server_version ($connection) {}
+
+
+function oci_statement_type ($statement) {}
+
+
+function oci_num_rows ($statement) {}
+
+
+function oci_close ($connection) {}
+
+
+function oci_connect ($username, $password, $connection_string = null, $character_set = null, $session_mode = null) {}
+
+
+function oci_new_connect ($username, $password, $connection_string = null, $character_set = null, $session_mode = null) {}
+
+
+function oci_pconnect ($username, $password, $connection_string = null, $character_set = null, $session_mode = null) {}
+
+
+function oci_error ($resource = null) {}
+
+
+function oci_free_descriptor ($descriptor) {}
+
+
+function oci_lob_is_equal (OCI_Lob $lob1, OCI_Lob $lob2) {}
+
+
+function oci_lob_copy (OCI_Lob $lob_to, OCI_Lob $lob_from, $length = 0) {}
+
+
+function oci_commit ($connection) {}
+
+
+function oci_rollback ($connection) {}
+
+
+function oci_new_descriptor ($connection, $type = OCI_DTYPE_LOB) {}
+
+
+function oci_set_prefetch ($statement, $rows) {}
+
+
+function oci_set_client_identifier ($connection, $client_identifier) {}
+
+
+function oci_set_edition ($edition) {}
+
+
+function oci_set_module_name ($connection, $module_name) {}
+
+
+function oci_set_action ($connection, $action_name) {}
+
+
+function oci_set_client_info ($connection, $client_info) {}
+
+
+function oci_password_change ($connection, $username, $old_password, $new_password) {}
+
+
+function oci_new_collection ($connection, $tdo, $schema = null) {}
+
+
+function oci_free_cursor ($statement_resource) {}
+
+
+function ocifreecursor ($statement_resource) {}
+
+
+function ocibindbyname ($statement, $column_name, &$variable, $maximum_length = -1, $type = SQLT_CHR) {}
+
+
+function ocidefinebyname ($statement, $column_name, &$variable, $type = SQLT_CHR) {}
+
+
+function ocicolumnisnull ($statement, $column_number_or_name) {}
+
+
+function ocicolumnname ($statement, $column_number) {}
+
+
+function ocicolumnsize ($statement, $column_number_or_name) {}
+
+
+function ocicolumnscale ($statement_resource, $column_number) {}
+
+
+function ocicolumnprecision ($statement_resource, $column_number) {}
+
+
+function ocicolumntype ($statement_resource, $column_number) {}
+
+
+function ocicolumntyperaw ($statement_resource, $column_number) {}
+
+
+function ociexecute ($statement_resource, $mode = OCI_COMMIT_ON_SUCCESS) {}
+
+
+function ocicancel ($statement_resource) {}
+
+
+function ocifetch ($statement_resource) {}
+
+
+function ocifetchstatement ($statement_resource, &$output, $skip, $maximum_rows, $flags) {}
+
+
+function ocifreestatement ($statement_resource) {}
+
+
+function ociinternaldebug ($mode) {}
+
+
+function ocinumcols ($statement_resource) {}
+
+
+function ociparse ($connection_resource, $sql_text) {}
+
+
+function ocinewcursor ($connection_resource) {}
+
+
+function ociresult ($statement_resource, $column_number_or_name) {}
+
+
+function ociserverversion ($connection_resource) {}
+
+
+function ocistatementtype ($statement_resource) {}
+
+
+function ocirowcount ($statement_resource) {}
+
+
+function ocilogoff ($connection_resource) {}
+
+
+function ocilogon ($username, $password, $connection_string, $character_set, $session_mode) {}
+
+
+function ocinlogon ($username, $password, $connection_string, $character_set, $session_mode) {}
+
+
+function ociplogon ($username, $password, $connection_string, $character_set, $session_mode) {}
+
+
+function ocierror ($connection_or_statement_resource) {}
+
+
+function ocifreedesc ($lob_descriptor) {}
+
+
+function ocisavelob ($lob_descriptor, $data, $offset) {}
+
+
+function ocisavelobfile ($lob_descriptor, $filename) {}
+
+
+function ociwritelobtofile ($lob_descriptor, $filename, $start, $length) {}
+
+
+function ociloadlob ($lob_descriptor) {}
+
+
+function ocicommit ($connection_resource) {}
+
+
+function ocirollback ($connection_resource) {}
+
+
+function ocinewdescriptor ($connection_resource, $type = OCI_DTYPE_LOB) {}
+
+
+function ocisetprefetch ($statement_resource, $number_of_rows) {}
+
+
+function ocipasswordchange ($connection_resource_or_connection_string_or_dbname, $username, $old_password, $new_password) {}
+
+
+function ocifreecollection ($collection) {}
+
+
+function ocinewcollection ($connection_resource, $tdo, $schema = null) {}
+
+
+function ocicollappend ($collection, $value) {}
+
+
+function ocicollgetelem ($collection, $index) {}
+
+
+function ocicollassignelem ($collection, $index, $value) {}
+
+
+function ocicollsize ($collection) {}
+
+
+function ocicollmax ($collection) {}
+
+
+function ocicolltrim ($collection, $number) {}
+
+
+
+function ociwritetemporarylob($lob_descriptor, $data, $lob_type = OCI_TEMP_CLOB ) {}
+
+
+function ocicloselob($lob_descriptor){}
+
+
+function ocicollassign($to, $from ) {}
+
+define ('OCI_DEFAULT', 0);
+
+
+define ('OCI_SYSOPER', 4);
+
+
+define ('OCI_SYSDBA', 2);
+
+
+define ('OCI_CRED_EXT', -2147483648);
+
+
+define ('OCI_DESCRIBE_ONLY', 16);
+
+
+define ('OCI_COMMIT_ON_SUCCESS', 32);
+
+
+define ('OCI_NO_AUTO_COMMIT', 0);
+
+
+define ('OCI_EXACT_FETCH', 2);
+
+
+define ('OCI_SEEK_SET', 0);
+
+
+define ('OCI_SEEK_CUR', 1);
+
+
+define ('OCI_SEEK_END', 2);
+
+
+define ('OCI_LOB_BUFFER_FREE', 1);
+
+
+define ('SQLT_BFILEE', 114);
+
+
+define ('SQLT_CFILEE', 115);
+
+
+define ('SQLT_CLOB', 112);
+
+
+define ('SQLT_BLOB', 113);
+
+
+define ('SQLT_RDD', 104);
+
+
+define ('SQLT_INT', 3);
+
+
+define ('SQLT_NUM', 2);
+
+
+define ('SQLT_RSET', 116);
+
+
+define ('SQLT_AFC', 96);
+
+
+define ('SQLT_CHR', 1);
+
+
+define ('SQLT_VCS', 9);
+
+
+define ('SQLT_AVC', 97);
+
+
+define ('SQLT_STR', 5);
+
+
+define ('SQLT_LVC', 94);
+
+
+define ('SQLT_FLT', 4);
+
+
+define ('SQLT_UIN', 68);
+
+
+define ('SQLT_LNG', 8);
+
+
+define ('SQLT_LBI', 24);
+
+
+define ('SQLT_BIN', 23);
+
+
+define ('SQLT_ODT', 156);
+
+
+define ('SQLT_BDOUBLE', 22);
+
+
+define ('SQLT_BFLOAT', 21);
+
+
+define ('OCI_B_NTY', 108);
+
+
+define ('SQLT_NTY', 108);
+
+
+define ('OCI_SYSDATE', "SYSDATE");
+
+
+define ('OCI_B_BFILE', 114);
+
+
+define ('OCI_B_CFILEE', 115);
+
+
+define ('OCI_B_CLOB', 112);
+
+
+define ('OCI_B_BLOB', 113);
+
+
+define ('OCI_B_ROWID', 104);
+
+
+define ('OCI_B_CURSOR', 116);
+
+
+define ('OCI_B_BIN', 23);
+
+
+define ('OCI_B_INT', 3);
+
+
+define ('OCI_B_NUM', 2);
+
+
+define ('OCI_FETCHSTATEMENT_BY_COLUMN', 16);
+
+
+define ('OCI_FETCHSTATEMENT_BY_ROW', 32);
+
+
+define ('OCI_ASSOC', 1);
+
+
+define ('OCI_NUM', 2);
+
+
+define ('OCI_BOTH', 3);
+
+
+define ('OCI_RETURN_NULLS', 4);
+
+
+define ('OCI_RETURN_LOBS', 8);
+
+
+define ('OCI_DTYPE_FILE', 56);
+
+
+define ('OCI_DTYPE_LOB', 50);
+
+
+define ('OCI_DTYPE_ROWID', 54);
+
+
+define ('OCI_D_FILE', 56);
+
+
+define ('OCI_D_LOB', 50);
+
+
+define ('OCI_D_ROWID', 54);
+
+
+define ('OCI_TEMP_CLOB', 2);
+
+
+define ('OCI_TEMP_BLOB', 1);
+
+
+define ('SQLT_BOL', 252);
+
+
+define ('OCI_B_BOL', 252);
diff --git a/.phan/internal_stubs/sqlsrv.phan_php b/.phan/internal_stubs/sqlsrv.phan_php
new file mode 100644 (file)
index 0000000..3fea0af
--- /dev/null
@@ -0,0 +1,276 @@
+<?php
+// @phan-stub-for-extension sqlsrv@3.0.1
+
+define('SQLSRV_ERR_ERRORS', 0);
+
+
+define('SQLSRV_ERR_WARNINGS', 1);
+
+
+define('SQLSRV_ERR_ALL', 2);
+
+
+define('SQLSRV_LOG_SYSTEM_ALL',-1);
+
+
+define('SQLSRV_LOG_SYSTEM_OFF', 0);
+
+
+define('SQLSRV_LOG_SYSTEM_INIT', 1);
+
+
+define('SQLSRV_LOG_SYSTEM_CONN', 2);
+
+
+define('SQLSRV_LOG_SYSTEM_STMT', 4);
+
+
+define('SQLSRV_LOG_SYSTEM_UTIL', 8);
+
+
+define('SQLSRV_LOG_SEVERITY_ALL', -1);
+
+
+define('SQLSRV_LOG_SEVERITY_ERROR', 1);
+
+
+define('SQLSRV_LOG_SEVERITY_NOTICE', 4);
+
+
+define('SQLSRV_LOG_SEVERITY_WARNING', 2);
+
+
+define('SQLSRV_FETCH_NUMERIC', 1);
+
+
+define('SQLSRV_FETCH_ASSOC', 2);
+
+
+define('SQLSRV_FETCH_BOTH', 3);
+
+
+define('SQLSRV_PHPTYPE_NULL', 1);
+
+
+define('SQLSRV_PHPTYPE_INT', 2);
+
+
+define('SQLSRV_PHPTYPE_FLOAT', 3);
+
+
+define('SQLSRV_PHPTYPE_DATETIME', 4);
+
+
+define('SQLSRV_ENC_BINARY', 'binary');
+
+
+define('SQLSRV_ENC_CHAR','char');
+
+
+define('SQLSRV_NULLABLE_NO', 0);
+
+
+define('SQLSRV_NULLABLE_YES', 1);
+
+
+define('SQLSRV_NULLABLE_UNKNOWN', 2);
+
+
+define('SQLSRV_SQLTYPE_BIGINT', -5);
+
+define('SQLSRV_SQLTYPE_BIT', -7);
+
+define('SQLSRV_SQLTYPE_DATETIME', 25177693);
+
+define('SQLSRV_SQLTYPE_FLOAT', 6);
+
+define('SQLSRV_SQLTYPE_IMAGE', -4);
+
+define('SQLSRV_SQLTYPE_INT', 4);
+
+define('SQLSRV_SQLTYPE_MONEY', 33564163);
+
+define('SQLSRV_SQLTYPE_NTEXT', -10);
+
+define('SQLSRV_SQLTYPE_TEXT', -1);
+
+define('SQLSRV_SQLTYPE_REAL', 7);
+
+define('SQLSRV_SQLTYPE_SMALLDATETIME', 8285);
+
+define('SQLSRV_SQLTYPE_SMALLINT', 5);
+
+define('SQLSRV_SQLTYPE_SMALLMONEY', 33559555);
+
+define('SQLSRV_SQLTYPE_TIMESTAMP', 4606);
+
+define('SQLSRV_SQLTYPE_TINYINT', -6);
+
+define('SQLSRV_SQLTYPE_UDT', -151);
+
+define('SQLSRV_SQLTYPE_UNIQUEIDENTIFIER', -11);
+
+define('SQLSRV_SQLTYPE_XML', -152);
+
+define('SQLSRV_SQLTYPE_DATE', 5211);
+
+define('SQLSRV_SQLTYPE_TIME', 58728806);
+
+define('SQLSRV_SQLTYPE_DATETIMEOFFSET', 58738021);
+
+define('SQLSRV_SQLTYPE_DATETIME2', 58734173);
+
+
+define('SQLSRV_PARAM_IN', 1);
+
+
+define('SQLSRV_PARAM_INOUT', 2);
+
+
+define('SQLSRV_PARAM_OUT', 4);
+
+
+define('SQLSRV_TXN_READ_UNCOMMITTED', 1);
+
+define('SQLSRV_TXN_READ_COMMITTED', 2);
+
+define('SQLSRV_TXN_REPEATABLE_READ', 4);
+
+define('SQLSRV_TXN_SERIALIZABLE', 8);
+
+define('SQLSRV_TXN_SNAPSHOT', 32);
+
+
+define('SQLSRV_SCROLL_NEXT', 1);
+
+define('SQLSRV_SCROLL_PRIOR', 4);
+
+define('SQLSRV_SCROLL_FIRST', 2);
+
+define('SQLSRV_SCROLL_LAST', 3);
+
+define('SQLSRV_SCROLL_ABSOLUTE', 5);
+
+define('SQLSRV_SCROLL_RELATIVE', 6);
+
+
+define('SQLSRV_CURSOR_FORWARD', 'forward');
+
+define('SQLSRV_CURSOR_STATIC', 'static');
+
+define('SQLSRV_CURSOR_DYNAMIC', 'dynamic');
+
+define('SQLSRV_CURSOR_KEYSET', 'keyset');
+
+define('SQLSRV_CURSOR_CLIENT_BUFFERED', 'buffered');
+
+
+
+function sqlsrv_connect($server_name, $connection_info = array()){}
+
+
+function sqlsrv_close($conn){}
+
+
+function sqlsrv_commit($conn){}
+
+
+function sqlsrv_begin_transaction($conn){}
+
+
+function sqlsrv_rollback($conn){}
+
+
+function sqlsrv_errors($errorsAndOrWarnings = SQLSRV_ERR_ALL){}
+
+
+function sqlsrv_configure($setting, $value){}
+
+
+function sqlsrv_get_config($setting){}
+
+
+function sqlsrv_prepare($conn, $tsql, $params=array(), $options=array()){}
+
+
+function sqlsrv_execute($stmt){}
+
+
+function sqlsrv_query($conn, $tsql, $params=array(), $options=array()){}
+
+
+function sqlsrv_fetch($stmt, $row=null, $offset=null){}
+
+
+function sqlsrv_get_field($stmt, $field_index, $get_as_type){}
+
+
+function sqlsrv_fetch_array($stmt, $fetch_type = null, $row=null, $offset=null){}
+
+
+function sqlsrv_fetch_object($stmt, $class_name=null, $ctor_params=null, $row=null, $offset=null){}
+
+
+function sqlsrv_has_rows($stmt){}
+
+
+function sqlsrv_num_fields($stmt){}
+
+
+function sqlsrv_next_result($stmt){}
+
+
+function sqlsrv_num_rows($stmt){}
+
+
+function sqlsrv_rows_affected($stmt){}
+
+
+function sqlsrv_client_info($conn){}
+
+
+function sqlsrv_server_info($conn){}
+
+
+function sqlsrv_cancel($stmt){}
+
+
+function sqlsrv_free_stmt($stmt){}
+
+
+function sqlsrv_field_metadata($stmt){}
+
+
+function sqlsrv_send_stream_data($stmt){}
+
+
+function SQLSRV_PHPTYPE_STREAM($encoding){}
+
+
+function SQLSRV_PHPTYPE_STRING($encoding){}
+
+
+function SQLSRV_SQLTYPE_BINARY($byteCount){}
+
+
+function SQLSRV_SQLTYPE_VARBINARY($byteCount){}
+
+
+
+function SQLSRV_SQLTYPE_VARCHAR($charCount) {}
+
+
+function SQLSRV_SQLTYPE_CHAR($charCount){}
+
+
+function SQLSRV_SQLTYPE_NCHAR($charCount){}
+
+
+function SQLSRV_SQLTYPE_NVARCHAR($charCount){}
+
+
+function SQLSRV_SQLTYPE_DECIMAL($precision, $scale){}
+
+
+function SQLSRV_SQLTYPE_NUMERIC($precision, $scale){}
+
diff --git a/.phan/internal_stubs/tideways.phan_php b/.phan/internal_stubs/tideways.phan_php
new file mode 100644 (file)
index 0000000..d87a6e4
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+// These stubs were generated by the phan stub generator.
+// @phan-stub-for-extension tideways@4.0.7
+
+namespace {
+function tideways_disable() {}
+function tideways_enable($flags = null, $options = null) {}
+function tideways_fatal_backtrace() {}
+function tideways_get_spans() {}
+function tideways_last_detected_exception() {}
+function tideways_last_fatal_error() {}
+function tideways_prepend_overwritten() {}
+function tideways_span_annotate($span = null, $annotations = null) {}
+function tideways_span_callback($name = null, $callback = null) {}
+function tideways_span_create($category = null) {}
+function tideways_span_timer_start($span = null) {}
+function tideways_span_timer_stop($span = null) {}
+function tideways_span_watch($name = null, $category = null) {}
+function tideways_sql_minify($sql = null) {}
+function tideways_transaction_name() {}
+const TIDEWAYS_FLAGS_CPU = 2;
+const TIDEWAYS_FLAGS_MEMORY = 4;
+const TIDEWAYS_FLAGS_NO_BUILTINS = 1;
+const TIDEWAYS_FLAGS_NO_COMPILE = 16;
+const TIDEWAYS_FLAGS_NO_HIERACHICAL = 64;
+const TIDEWAYS_FLAGS_NO_SPANS = 32;
+const TIDEWAYS_FLAGS_NO_USERLAND = 8;
+}
diff --git a/.phan/stubs/README b/.phan/stubs/README
new file mode 100644 (file)
index 0000000..c458ab5
--- /dev/null
@@ -0,0 +1,3 @@
+These stubs describe how code that is not available at analysis time should be
+used. No implementations are necessary, just define the classes and their
+methods and use phpdoc to describe what arguments are allowed.
diff --git a/.phan/stubs/excimer.php b/.phan/stubs/excimer.php
new file mode 100644 (file)
index 0000000..e87d4cd
--- /dev/null
@@ -0,0 +1,89 @@
+<?php
+
+// phpcs:ignoreFile
+
+define( 'EXCIMER_REAL', 0 );
+define( 'EXCIMER_CPU', 1 );
+
+class ExcimerProfiler {
+       public function __construct() {
+       }
+       public function setPeriod( $period ) {
+       }
+       public function setEventType( $event_type ) {
+       }
+       public function setMaxDepth( $maxDepth ) {
+       }
+       public function setFlushCallback( $callback, $max_samples ) {
+       }
+       public function clearFlushCallback() {
+       }
+       public function start() {
+       }
+       public function stop() {
+       }
+       public function getLog() {
+       }
+       public function flush() {
+       }
+}
+
+class ExcimerLog {
+       private final function __construct() {
+       }
+       function formatCollapsed() {
+       }
+       function aggregateByFunction() {
+       }
+       function getEventCount() {
+       }
+       function current() {
+       }
+       function key() {
+       }
+       function next() {
+       }
+       function rewind() {
+       }
+       function valid() {
+       }
+       function count() {
+       }
+       function offsetExists( $offset ) {
+       }
+       function offsetGet( $offset ) {
+       }
+       function offsetSet( $offset, $value ) {
+       }
+       function offsetUnset( $offset ) {
+       }
+
+}
+
+class ExcimerLogEntry {
+       private final function __construct() {
+       }
+       function getTimestamp() {
+       }
+       function getEventCount() {
+       }
+       function getTrace() {
+       }
+}
+
+class ExcimerTimer {
+       function setEventType( $event_type ) {
+       }
+       function setInterval( $interval ) {
+       }
+       function setPeriod( $period ) {
+       }
+       function setCallback( $callback ) {
+       }
+       function start() {
+       }
+       function stop() {
+       }
+       function getTime() {
+       }
+}
diff --git a/.phan/stubs/hhvm.php b/.phan/stubs/hhvm.php
new file mode 100644 (file)
index 0000000..090bdfe
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+// phpcs:ignoreFile
+
+define( 'HHVM_VERSION', '3.18.6-dev' );
+
+/**
+ * @param callable $callback
+ * @param mixed ...$parameters
+ */
+function register_postsend_function( $callback ) {
+}
diff --git a/.phan/stubs/mail.php b/.phan/stubs/mail.php
new file mode 100644 (file)
index 0000000..ba1efb9
--- /dev/null
@@ -0,0 +1,89 @@
+<?php
+
+/**
+ * Minimal set of classes necessary for UserMailer to be happy. Types
+ * taken from documentation at pear.php.net.
+ * phpcs:ignoreFile
+ */
+
+class PEAR {
+       /**
+        * @param mixed $data
+        * @return bool
+        */
+       public static function isError( $data ) {
+       }
+}
+
+class PEAR_Error {
+       /**
+        * @return string
+        */
+       public function getMessage() {
+       }
+}
+
+class Mail {
+       /**
+        * @param string $driver
+        * @param array $params
+        * @return self
+        */
+       static public function factory( $driver, array $params = [] ) {
+       }
+
+       /**
+        * @param mixed $recipients
+        * @param array $headers
+        * @param string $body
+        * @return bool|PEAR_Error
+        */
+       public function send( $recipients, array $headers, $body ) {
+       }
+}
+
+class Mail_smtp extends Mail {
+}
+
+class Mail_mime {
+       /**
+        * @param mixed $params
+        */
+       public function __construct( $params = [] ) {
+       }
+
+       /**
+        * @param string $data
+        * @param bool $isfile
+        * @param bool $append
+        * @return bool|PEAR_Error
+        */
+       public function setTXTBody( $data, $isfile = false, $append = false ) {
+       }
+
+       /**
+        * @param string $data
+        * @param bool $isfile
+        * @return bool|PEAR_Error
+        */
+       public function setHTMLBody( $data, $isfile = false ) {
+       }
+
+       /**
+        * @param array|null $parms
+        * @param mixed $filename
+        * @param bool $skip_head
+        * @return string|bool|PEAR_Error
+        */
+       public function get( $params = null, $filename = null, $skip_head = false ) {
+       }
+
+       /**
+        * @param array|null $xtra_headers
+        * @param bool $overwrite
+        * @param bool $skip_content
+        * @return array
+        */
+       public function headers( array $xtra_headers = null, $overwrite = false, $skip_content = false ) {
+       }
+}
diff --git a/.phan/stubs/password.php b/.phan/stubs/password.php
new file mode 100644 (file)
index 0000000..dd9cba4
--- /dev/null
@@ -0,0 +1,11 @@
+<?php
+// phpcs:ignoreFile
+
+// Password constants added in PHP 7.2 & 7.3
+
+const PASSWORD_ARGON2I = 2;
+const PASSWORD_ARGON2ID = 3;
+const PASSWORD_ARGON2_DEFAULT_MEMORY_COST = 1024;
+const PASSWORD_ARGON2_DEFAULT_THREADS = 2;
+const PASSWORD_ARGON2_DEFAULT_TIME_COST = 2;
+
diff --git a/.phan/stubs/phpunit4.php b/.phan/stubs/phpunit4.php
new file mode 100644 (file)
index 0000000..e5e88e6
--- /dev/null
@@ -0,0 +1,11 @@
+<?php
+
+/**
+ * Some old classes from PHPUnit 4 that MediaWiki (conditionally) references.
+ *
+ * phpcs:ignoreFile
+ */
+
+class PHPUnit_TextUI_Command {
+
+}
diff --git a/.phan/stubs/wikidiff.php b/.phan/stubs/wikidiff.php
new file mode 100644 (file)
index 0000000..02bcd1f
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+// phpcs:ignoreFile
+
+/**
+ * @param string $text1
+ * @param string $text2
+ * @param int $numContextLines
+ * @param int $movedParagraphDetectionCutoff
+ * @return string
+ */
+function wikidiff2_do_diff( $text1, $text2, $numContextLines, $movedParagraphDetectionCutoff = 0 ) {
+}
+
+/**
+ * @param string $text1
+ * @param string $text2
+ * @param int $numContextLines
+ * @param int $maxMovedLines
+ * @return string
+ */
+function wikidiff2_inline_diff( $text1, $text2, $numContextLines, $maxMovedLines = 25 ) {
+}
index f4d6177..22b74b5 100644 (file)
@@ -14,7 +14,6 @@
                <exclude name="MediaWiki.NamingConventions.LowerCamelFunctionsName.FunctionName" />
                <exclude name="MediaWiki.Usage.DbrQueryUsage.DbrQueryFound" />
                <exclude name="MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgContLang" />
-               <exclude name="MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgParser" />
                <exclude name="MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgTitle" />
                <exclude name="MediaWiki.Usage.ForbiddenFunctions.passthru" />
                <exclude name="MediaWiki.WhiteSpace.SpaceBeforeSingleLineComment.NewLineComment" />
                        Whitelist existing violations, but enable the sniff to prevent
                        any new occurrences.
                -->
-               <exclude-pattern>*/includes/Feed\.php</exclude-pattern>
-               <exclude-pattern>*/includes/RevisionList\.php</exclude-pattern>
-               <exclude-pattern>*/includes/installer/PhpBugTests\.php</exclude-pattern>
                <exclude-pattern>*/includes/specials/SpecialMostinterwikis\.php</exclude-pattern>
-               <exclude-pattern>*/includes/compat/XMPReader\.php</exclude-pattern>
-               <exclude-pattern>*/includes/diff/DairikiDiff\.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/SpecialWantedpages\.php</exclude-pattern>
                <exclude-pattern>*/includes/specials/SpecialWantedtemplates\.php</exclude-pattern>
                <exclude-pattern>*/includes/specials/SpecialWithoutinterwiki\.php</exclude-pattern>
-               <exclude-pattern>*/maintenance/7zip.inc</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>
                <exclude-pattern>*/maintenance/cleanupTable.inc</exclude-pattern>
                <exclude-pattern>*/maintenance/cleanupTitles\.php</exclude-pattern>
                <exclude-pattern>*/maintenance/commandLine.inc</exclude-pattern>
-               <exclude-pattern>*/maintenance/dumpTextPass\.php</exclude-pattern>
                <exclude-pattern>*/maintenance/edit\.php</exclude-pattern>
                <exclude-pattern>*/maintenance/findDeprecated\.php</exclude-pattern>
                <exclude-pattern>*/maintenance/getText\.php</exclude-pattern>
                        Whitelist existing violations, but enable the sniff to prevent
                        any new occurrences.
                -->
-               <exclude-pattern>*/includes/specials/SpecialActiveusers\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialBooksources\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialEmailuser\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialListfiles\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialListgrants\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialListgrouprights\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialListusers.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialRecentchanges\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialRecentchangeslinked\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialRevisiondelete\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialWhatlinkshere\.php</exclude-pattern>
                <exclude-pattern>*/maintenance/language/alltrans\.php</exclude-pattern>
                <exclude-pattern>*/maintenance/language/digit2html\.php</exclude-pattern>
                <exclude-pattern>*/maintenance/language/langmemusage\.php</exclude-pattern>
                        Whitelist existing violations, but enable the sniff to prevent
                        any new occurrences.
                -->
-               <exclude-pattern>*/includes/api/ApiErrorFormatter\.php</exclude-pattern>
-               <exclude-pattern>*/includes/api/ApiImport\.php</exclude-pattern>
-               <exclude-pattern>*/includes/api/ApiMessage\.php</exclude-pattern>
-               <exclude-pattern>*/includes/api/ApiOpenSearch\.php</exclude-pattern>
-               <exclude-pattern>*/includes/api/ApiRsd\.php</exclude-pattern>
-               <exclude-pattern>*/includes/compat/XMPReader\.php</exclude-pattern>
-               <exclude-pattern>*/includes/diff/DairikiDiff\.php</exclude-pattern>
-               <exclude-pattern>*/includes/Feed\.php</exclude-pattern>
-               <exclude-pattern>*/includes/filerepo/file/LocalFile\.php</exclude-pattern>
-               <exclude-pattern>*/includes/gallery/PackedOverlayImageGallery\.php</exclude-pattern>
-               <exclude-pattern>*/includes/HistoryBlob\.php</exclude-pattern>
-               <exclude-pattern>*/includes/htmlform/HTMLFormElement\.php</exclude-pattern>
-               <exclude-pattern>*/includes/libs/filebackend/FileBackendStore\.php</exclude-pattern>
-               <exclude-pattern>*/includes/libs/filebackend/FSFileBackend\.php</exclude-pattern>
-               <exclude-pattern>*/includes/libs/filebackend/SwiftFileBackend\.php</exclude-pattern>
-               <exclude-pattern>*/includes/logging/LogEntry\.php</exclude-pattern>
-               <exclude-pattern>*/includes/logging/LogFormatter\.php</exclude-pattern>
-               <exclude-pattern>*/includes/media/MediaTransformOutput\.php</exclude-pattern>
-               <exclude-pattern>*/includes/media/SVGMetadataExtractor\.php</exclude-pattern>
-               <exclude-pattern>*/includes/parser/Preprocessor_DOM\.php</exclude-pattern>
-               <exclude-pattern>*/includes/parser/Preprocessor_Hash\.php</exclude-pattern>
-               <exclude-pattern>*/includes/parser/Preprocessor\.php</exclude-pattern>
-               <exclude-pattern>*/includes/PathRouter\.php</exclude-pattern>
-               <exclude-pattern>*/includes/poolcounter/PoolCounter\.php</exclude-pattern>
-               <exclude-pattern>*/includes/PrefixSearch\.php</exclude-pattern>
-               <exclude-pattern>*/includes/profiler/SectionProfiler\.php</exclude-pattern>
-               <exclude-pattern>*/includes/RevisionList\.php</exclude-pattern>
-               <exclude-pattern>*/includes/search/SearchEngine\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specialpage/LoginSignupSpecialPage\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/forms/PreferencesFormLegacy\.php</exclude-pattern>
-               <exclude-pattern>*/includes/StubObject\.php</exclude-pattern>
-               <exclude-pattern>*/includes/upload/UploadStash\.php</exclude-pattern>
-               <exclude-pattern>*/includes/utils/AutoloadGenerator\.php</exclude-pattern>
                <exclude-pattern>*/maintenance/dumpIterator\.php</exclude-pattern>
                <exclude-pattern>*/maintenance/Maintenance\.php</exclude-pattern>
                <exclude-pattern>*/maintenance/findDeprecated\.php</exclude-pattern>
        </rule>
        <rule ref="PSR2.Methods.MethodDeclaration.Underscore">
                <exclude-pattern>*/includes/StubObject\.php</exclude-pattern>
+               <exclude-pattern>*/includes/StubUserLang\.php</exclude-pattern>
        </rule>
        <rule ref="MediaWiki.Usage.AssignmentInReturn.AssignmentInReturn">
                <exclude-pattern>*/tests/phpunit/*\.php</exclude-pattern>
                -->
                <exclude-pattern>*/includes/GlobalFunctions\.php</exclude-pattern>
                <exclude-pattern>*/includes/libs/filebackend/FSFileBackend\.php</exclude-pattern>
-               <exclude-pattern>*/maintenance/7zip\.inc</exclude-pattern>
+               <exclude-pattern>*/maintenance/includes/SevenZipStream\.php</exclude-pattern>
                <exclude-pattern>*/maintenance/populateImageSha1\.php</exclude-pattern>
        </rule>
        <rule ref="MediaWiki.Usage.ForbiddenFunctions.proc_open">
                <exclude-pattern>includes/export/DumpPipeOutput\.php</exclude-pattern>
                <exclude-pattern>includes/resourceloader/ResourceLoaderImage\.php</exclude-pattern>
                <exclude-pattern>includes/shell/Command\.php</exclude-pattern>
-               <exclude-pattern>maintenance/dumpTextPass\.php</exclude-pattern>
+               <exclude-pattern>maintenance/includes/TextPassDumper\.php</exclude-pattern>
                <exclude-pattern>maintenance/mysql\.php</exclude-pattern>
                <exclude-pattern>maintenance/storage/recompressTracked\.php</exclude-pattern>
                <exclude-pattern>tests/parser/editTests\.php</exclude-pattern>
index 60c8f36..43f499b 100644 (file)
@@ -1,8 +1,8 @@
 {
        "extends": "stylelint-config-wikimedia",
        "rules": {
+               "selector-class-pattern": "^((mw|oo-ui)-|(wikitable|(toc(|toggle|hidden))|client-(no)?js)$)",
                "no-descending-specificity": null,
-
                "selector-max-id": null
        }
 }
index 9dc2ef7..e4a173d 100644 (file)
@@ -13,10 +13,6 @@ language: php
 # - Required for non-buggy xml library for XmlTypeCheck/UploadBaseTest (T75176).
 dist: trusty
 
-git:
-  depth: 3
-  quiet: true
-
 # Cache NPM and Composer directories
 # <https://docs.travis-ci.com/user/caching/>
 cache:
index fbb93bf..f3950f6 100644 (file)
@@ -9,7 +9,6 @@ module.exports = function ( grunt ) {
        grunt.loadNpmTasks( 'grunt-banana-checker' );
        grunt.loadNpmTasks( 'grunt-contrib-copy' );
        grunt.loadNpmTasks( 'grunt-eslint' );
-       grunt.loadNpmTasks( 'grunt-jsonlint' );
        grunt.loadNpmTasks( 'grunt-karma' );
        grunt.loadNpmTasks( 'grunt-stylelint' );
        grunt.loadNpmTasks( 'grunt-svgmin' );
@@ -23,10 +22,11 @@ module.exports = function ( grunt ) {
                eslint: {
                        options: {
                                reportUnusedDisableDirectives: true,
+                               extensions: [ '.js', '.json' ],
                                cache: true
                        },
                        all: [
-                               '**/*.js',
+                               '**/*.js{,on}',
                                '!docs/**',
                                '!node_modules/**',
                                '!resources/lib/**',
@@ -36,18 +36,13 @@ module.exports = function ( grunt ) {
                                '!tests/coverage/**',
                                '!vendor/**',
                                // Explicitly say "**/*.js" here in case of symlinks
-                               '!extensions/**/*.js',
-                               '!skins/**/*.js'
-                       ]
-               },
-               jsonlint: {
-                       all: [
-                               '**/*.json',
-                               '!{docs/js,extensions,node_modules,skins,vendor}/**'
+                               '!extensions/**/*.js{,on}',
+                               '!skins/**/*.js{,on}'
                        ]
                },
                banana: {
                        options: {
+                               requireLowerCase: false,
                                disallowBlankTranslations: false
                        },
                        core: 'languages/i18n/',
diff --git a/HISTORY b/HISTORY
index a926069..426eb17 100644 (file)
--- a/HISTORY
+++ b/HISTORY
@@ -1,7 +1,26 @@
-Change notes from older releases. For current info see RELEASE-NOTES-1.33.
+Change notes from older releases. For current info see RELEASE-NOTES-1.34.
 
 = MediaWiki 1.32 =
 
+== MediaWiki 1.32.1 ==
+
+=== Changes since MediaWiki 1.32.0 ===
+* (T213577) rdbms: avoid transaction status errors from ping() in rollback().
+* rdbms: Pass required parameter.
+* rdbms: do not treat SAVEPOINT and RELEASE SAVEPOINT as write queries.
+* (T204531) rdbms: reduce LoadBalancer replication log spam.
+* (T213489) Avoid session double-start in Setup.php.
+* (T213717) Correct namespace 'Template' for gom-deva
+* (T198054) Fix login page crash caused by unknown language via ?uselang
+* (T215324) (T210937) list=users mistakenly reports user as missing.
+* (T209483) Add ILBFactory::redefineLocalDomain method. This is intended for
+use with scripts like addWiki.php to avoid mismatched domain errors.
+* (T208871) The hard-coded Google search form on the database error page was
+removed.
+* (T204800) Fix Title::getFragmentForURL for bad interwiki prefix
+* (T215566) Fix installer being unable to determine if the database exists
+during a fresh installation.
+
 == MediaWiki 1.32.0 ==
 
 === Changes since MediaWiki 1.32.0-rc.2 ===
@@ -731,7 +750,8 @@ This is a security and maintenance release of the MediaWiki 1.31 branch.
 * (T196185) Don't allow setting $wgDBmysql5 in the installer.
 * (T196125) php-memcached 3.0 (provided with PHP 7.0) is now supported.
 * (T182366) UploadBase::checkXMLEncodingMissmatch() now works on PHP 7.1+
-* (T118683) Fix exception from &$user deref on HHVM in the TitleMoveComplete hook.
+* (T118683) Fix exception from &$user deref on HHVM in the TitleMoveComplete
+  hook.
 * (T196672) The mtime of extension.json files is now able to be zero
 * (T180403) Validate $length in padleft/padright parser functions.
 * (T143790) Make $wgEmailConfirmToEdit only affect edit actions.
@@ -755,7 +775,8 @@ This is a security and maintenance release of the MediaWiki 1.31 branch.
   apply patch-drop-ar_text.sql manually, you'll have to apply a default value
   to the ar_text and ar_flags columns of the archive table or make those
   columns nullable before upgrading to MediaWiki 1.31.
-  maintenance/archives/patch-nullable-ar_text.sql shows how to do this for MySQL.
+  maintenance/archives/patch-nullable-ar_text.sql shows how to do this for
+  MySQL.
 
 === Configuration changes in 1.31 ===
 * $wgEnableAPI and $wgEnableWriteAPI are now deprecated and will be removed in
@@ -1077,7 +1098,8 @@ changes to languages because of Phabricator reports.
 * Passing a ParserOptions object to OutputPage::parserOptions() is deprecated.
 * The RevisionInsertComplete hook is now deprecated; use instead the hook
   RevisionRecordInserted. RevisionInsertComplete is still called, but the second
-  and third parameter will always be null. Hard deprecation is scheduled for 1.32.
+  and third parameter will always be null. Hard deprecation is scheduled for
+  1.32.
 * The following methods that get and set ParserOutput state are deprecated.
   Callers should use the new stateless $options parameter to
   ParserOutput::getText() instead.
@@ -1218,20 +1240,23 @@ This is a security and maintenance release of the MediaWiki 1.30 branch.
   'newbie'.
 * (T194605, CVE-2018-0505) SECURITY: BotPasswords can bypass CentralAuth's
   account lock.
-* (T87572) Make FormatMetadata::flattenArrayReal() work for an associative array.
+* (T87572) Make FormatMetadata::flattenArrayReal() work for an associative
+  array.
 * Updated composer/spdx-licenses from 1.1.4 to 1.3.0 (development dependency).
 * (T189567) the CLI installer (maintenance/install.php) learned to detect and
   include extensions. Pass --with-extensions to enable that feature.
 * (T190503) Let built-in web server (maintenance/dev) handle .php requests.
 * (T167507) selenium: Run Chrome headlessly.
 * selenium: Pass -no-sandbox to Chrome under Docker.
-* (T179190) selenium: Move logic for running tests from package.json to selenium.sh
+* (T179190) selenium: Move logic for running tests from package.json to
+  selenium.sh
 * (T192584) Stop incorrectly passing USE INDEX to RecentChange::newFromConds().
 * Add default edit rate limit of 90 edits/minute for all users.
 * (T186565) Fix PHP Notice from `ob_end_flush()` in `FileRepo::streamFile()`.
 * oojs/oojs-ui updated to remove an unnecessary dependancy.
 * (T196125) php-memcached 3.0 (provided with PHP 7.0) is now supported.
-* (T118683) Fix exception from &$user deref on HHVM in the TitleMoveComplete hook.
+* (T118683) Fix exception from &$user deref on HHVM in the TitleMoveComplete
+  hook.
 * (T196672) The mtime of extension.json files is now able to be zero
 * (T180403) Validate $length in padleft/padright parser functions.
 * (T143790) Make $wgEmailConfirmToEdit only affect edit actions.
@@ -1279,19 +1304,19 @@ section).
 * (T163562) $wgRangeContributionsCIDRLimit was introduced to control the size
   of IP ranges that can be queried at Special:Contributions.
 * (T45547) $wgUsePigLatinVariant added (off by default).
-* (T152540) MediaWiki now supports a section ID escaping style that allows to display
-  non-Latin characters verbatim on many modern browsers. This is controlled by the
-  new configuration setting, $wgFragmentMode.
-* $wgExperimentalHtmlIds is now deprecated and will be removed in a future version,
-  use $wgFragmentMode to migrate off it to a modern alternative.
+* (T152540) MediaWiki now supports a section ID escaping style that allows to
+  display non-Latin characters verbatim on many modern browsers. This is
+  controlled by the new configuration setting, $wgFragmentMode.
+* $wgExperimentalHtmlIds is now deprecated and will be removed in a future
+  version, use $wgFragmentMode to migrate off it to a modern alternative.
 * $wgExternalInterwikiFragmentMode was introduced to control how fragments in
   sinterwikis going outside of current wiki farm are encoded.
-* (T120333) Soft-deprecated the use of PHP extension 'mysql' in favor of 'mysqli'.
-  This PHP extension was deprecated in PHP 5.5 and removed in PHP 7.0. MediaWiki
-  auto-selects the 'mysqli' driver since MediaWiki 1.22, except if explicitly
-  requested through the configuration parameter $wgDBservers.
-* $wgOOUIEditPage was removed, as it is now the default. This was documented as a
-  temporary variable during the migration period.
+* (T120333) Soft-deprecated the use of PHP extension 'mysql' in favor of
+  'mysqli'. This PHP extension was deprecated in PHP 5.5 and removed in PHP 7.0.
+  MediaWiki auto-selects the 'mysqli' driver since MediaWiki 1.22, except if
+  explicitly requested through the configuration parameter $wgDBservers.
+* $wgOOUIEditPage was removed, as it is now the default. This was documented as
+  temporary variable during the migration period.
 
 === New features in 1.30 ===
 * (T37247) Output from Parser::parse() will now be wrapped in a div with
@@ -1324,9 +1349,9 @@ section).
 * (T138166) Added ability for users to prohibit other users from sending them
   emails with Special:Emailuser. Can be enabled by setting
   $wgEnableUserEmailBlacklist to true.
-* (T67297) $wgBrowserBlacklist is deprecated, and changing it will have no effect.
-  Instead, users using browsers that do not support Unicode will be unable to edit
-  and should upgrade to a modern browser instead.
+* (T67297) $wgBrowserBlacklist is deprecated, and changing it will have no
+  effect. Instead, users using browsers that do not support Unicode will be
+  unable to edit and should upgrade to a modern browser instead.
 
 === External library changes in 1.30 ===
 
@@ -1417,9 +1442,10 @@ changes to languages because of Phabricator reports.
 * Two new hooks, LogEventsListLineEnding and NewPagesLineEnding, were added for
   manipulating Special:Log and Special:NewPages lines.
 * The OldChangesListRecentChangesLine, EnhancedChangesListModifyLineData,
-  PageHistoryLineEnding, ContributionsLineEnding and DeletedContributionsLineEnding
-  hooks have an additional parameter, for manipulating HTML data attributes of
-  RC/history lines. EnhancedChangesListModifyBlockLineData can do that via the
+  PageHistoryLineEnding, ContributionsLineEnding and
+  DeletedContributionsLineEnding hooks have an additional parameter, for
+  manipulating HTML data attributes of RC/history lines.
+  EnhancedChangesListModifyBlockLineData can do that via the
   $data['attribs'] subarray.
 * (T130632) The OutputPage::enableTOC() method was removed.
 * WikiPage::getParserOutput() will now throw an exception if passed
@@ -1430,10 +1456,10 @@ changes to languages because of Phabricator reports.
 * IP::isValidBlock() was deprecated. Use the equivalent IP::isValidRange().
 * DeprecatedGlobal no longer supports passing in a direct value, it requires a
   callable factory function or a class name.
-* The $parserMemc global, wfGetParserCacheStorage(), and ParserCache::singleton()
-  are all deprecated. The main ParserCache instance should be obtained from
-  MediaWikiServices instead. Access to the underlying BagOStuff is possible
-  through the new ParserCache::getCacheStorage() method.
+* The $parserMemc global, wfGetParserCacheStorage(), and
+  ParserCache::singleton() are all deprecated. The main ParserCache instance
+  should be obtained from MediaWikiServices instead. Access to the underlying
+  BagOStuff is possible through the new ParserCache::getCacheStorage() method.
 * .mw-ui-constructive CSS class (deprecated in 1.27) was removed.
 * Sanitizer::escapeId() was deprecated, use escapeIdForAttribute(),
   escapeIdForLink() or escapeIdForExternalInterwiki() instead.
@@ -1444,9 +1470,9 @@ changes to languages because of Phabricator reports.
 * mw.util.escapeId() was deprecated, use escapeIdForAttribute() or
   escapeIdForLink().
 * MagicWord::replaceMultiple() (deprecated in 1.25) was removed.
-* WikiImporter now requires the second parameter to be an instance of the Config,
-  class. Prior to that, the Config parameter was optional (a behavior deprecated in
-  1.25).
+* WikiImporter now requires the second parameter to be an instance of the
+  Config, class. Prior to that, the Config parameter was optional (a behavior
+  deprecated in 1.25).
 * Removed 'jquery.mwExtension' module. (deprecated since 1.26)
 * mediawiki.ui: Deprecate greys, which are not part of WikimediaUI color palette
   any more.
@@ -1456,55 +1482,60 @@ changes to languages because of Phabricator reports.
   should be used instead.
 * RunningStat class (deprecated in 1.27) was removed. The namespaced
   RunningStat\RunningStat should be used instead.
-* MWMemcached and MemCachedClientforWiki classes (deprecated in 1.27) were removed.
+* MWMemcached and MemCachedClientforWiki classes (deprecated in 1.27) were
+  removed.
   The MemcachedClient class should be used instead.
 * EditPage underwent some refactoring and deprecations:
   * EditPage::isOouiEnabled() is deprecated and will always return true.
-  * EditPage::getSummaryInput() and ::getSummaryInputOOUI() are deprecated. Please
-    use ::getSummaryInputWidget() instead.
+  * EditPage::getSummaryInput() and ::getSummaryInputOOUI() are deprecated.
+    Please use ::getSummaryInputWidget() instead.
   * EditPage::getCheckboxes() and ::getCheckboxesOOUI() are deprecated. Please
     use ::getCheckboxesWidget() instead.
-  * Creating an EditPage instance without calling EditPage::setContextTitle() should
-    be avoided and will be deprecated in a future release.
-  * EditPage::safeUnicodeInput() and ::safeUnicodeOutput() are deprecated and no-ops.
-  * EditPage::$isCssJsSubpage, ::$isCssSubpage, and ::$isJsSubpage are deprecated. The
-    corresponding methods from Title should be used instead.
+  * Creating an EditPage instance without calling EditPage::setContextTitle()
+    should be avoided and will be deprecated in a future release.
+  * EditPage::safeUnicodeInput() and ::safeUnicodeOutput() are deprecated and
+    no-ops.
+  * EditPage::$isCssJsSubpage, ::$isCssSubpage, and ::$isJsSubpage are
+    deprecated. The corresponding methods from Title should be used instead.
   * EditPage::$isWrongCaseCssJsPage is deprecated. There is no replacement.
-  * EditPage::$mArticle and ::$mTitle are deprecated for public usage. The getters
-    ::getArticle() and ::getTitle() should be used instead.
-  * Trying to control or fake EditPage context by overriding $wgUser, $wgRequest, $wgOut,
-    and $wgLang is no longer supported and won't work. The IContextSource returned from
-    EditPage::getContext() must be modified instead.
+  * EditPage::$mArticle and ::$mTitle are deprecated for public usage. The
+    getters ::getArticle() and ::getTitle() should be used instead.
+  * Trying to control or fake EditPage context by overriding $wgUser,
+    $wgRequest, $wgOut, and $wgLang is no longer supported and won't work. The
+    IContextSource returned from EditPage::getContext() must be modified
+    instead.
 * Parser::getRandomString() (deprecated in 1.26) was removed.
 * Parser::uniqPrefix() (deprecated in 1.26) was removed.
 * Parser::extractTagsAndParams() now only accepts three arguments. The fourth,
   $uniq_prefix was deprecated in 1.26 and has now been removed.
-* (T172514) The following tables have had their UNIQUE indexes turned into proper
-  PRIMARY KEYs for increased maintainability: categorylinks, imagelinks, iwlinks,
-  langlinks, log_search, module_deps, objectcache, pagelinks, query_cache, site_stats,
-  templatelinks, text, transcache, user_former_groups, user_properties.
+* (T172514) The following tables have had their UNIQUE indexes turned into
+  proper PRIMARY KEYs for increased maintainability: categorylinks, imagelinks,
+  iwlinks, langlinks, log_search, module_deps, objectcache, pagelinks,
+  query_cache, site_stats, templatelinks, text, transcache, user_former_groups,
+  user_properties.
 * IDatabase::nextSequenceValue() is no longer needed by any database backends
   (formerly it was needed by PostgreSQL and Oracle), and is now deprecated.
-* (T146591) The lc_lang_key index on the l10n_cache table has been changed into a
-  PRIMARY KEY.
+* (T146591) The lc_lang_key index on the l10n_cache table has been changed into
+  PRIMARY KEY.
 * (T157227) bot_password.bp_user, change_tag.ct_log_id, change_tag.ct_rev_id,
   page_restrictions.pr_user, tag_summary.ts_log_id, tag_summary.ts_rev_id and
   user_properties.up_user have all been made unsigned on MySQL.
 * DB_SLAVE is deprecated. DB_REPLICA should be used instead.
 * wfUsePHP() is deprecated.
 * wfFixSessionID() was removed.
-* wfShellExec() and related functions are deprecated, use Shell::command(). This also
-  slightly changes the behavior of how execution time limits are calculated when only
-  some of defaults are overridden per-call. When in doubt, always override both wall
-  clock and CPU time.
-* (T138166) SpecialEmailUser::getTarget() now requires a second argument, the sending
-  user object. Using the method without the second argument is deprecated.
+* wfShellExec() and related functions are deprecated, use Shell::command(). This
+  also slightly changes the behavior of how execution time limits are calculated
+  when only some of defaults are overridden per-call. When in doubt, always
+  override both wall clock and CPU time.
+* (T138166) SpecialEmailUser::getTarget() now requires a second argument, the
+  sending user object. Using the method without the second argument is
+  deprecated.
 * (T67297) Browsers that don't support Unicode will have their edits rejected.
-* (T178450) The module 'jquery.badge' is deprecated and will be removed in a future
-  release. For notifying the user of an event, the Notifications ("Echo") system
-  should be used instead.
-* (T178451) SECURITY: Potential XSS when $wgShowExceptionDetails = false and browser
-  sends non-standard url escaping.
+* (T178450) The module 'jquery.badge' is deprecated and will be removed in a
+  future release. For notifying the user of an event, the Notifications ("Echo")
+  system should be used instead.
+* (T178451) SECURITY: Potential XSS when $wgShowExceptionDetails = false and
+  browser sends non-standard url escaping.
 * (T165846) SECURITY: BotPassword login attempts weren't throttled.
 
 = MediaWiki 1.29 =
@@ -1557,7 +1588,8 @@ This is a security and maintenance release of the MediaWiki 1.29 branch.
 This is a security and maintenance release of the MediaWiki 1.29 branch.
 
 === Changes since 1.29.1 ===
-* (T166757) Avoid scoped lock errors in Category::refreshCounts() due to nesting.
+* (T166757) Avoid scoped lock errors in Category::refreshCounts() due to
+  nesting.
 * (T175439) Unbreak Postgres Updater when setting defaults for a column.
 * (T160298) Remove use of implicitGroupBy() in ActiveUsersPager.
 * Fixed login button label to accept RawMessage.
@@ -1566,19 +1598,20 @@ This is a security and maintenance release of the MediaWiki 1.29 branch.
 * (T163646) Pass a string not an int to mysql_real_escape_string().
 * (T180143) Bump justinrainbow/json-schema development dependency to ~5.2.
 * Updated dev dependancy phpunit/phpunit from v4.8.35 to v4.8.36.
-* (T178451) SECURITY: Potential XSS when $wgShowExceptionDetails = false and browser
-  sends non-standard url escaping.
+* (T178451) SECURITY: Potential XSS when $wgShowExceptionDetails = false and
+  browser sends non-standard url escaping.
 * (T165846) SECURITY: BotPassword login attempts weren't throttled.
 * (T128209) SECURITY: Reflected File Download from api.php.
 * (T134100) SECURITY: Do not reveal if user exists during login failure.
 * (T176247) SECURITY: Ensure Message::rawParams can't lead to XSS.
 * (T125163) SECURITY: Make anchor for headlines escape > and <.
 * (T180237) SECURITY: Protect vendor folder with .htaccess.
-* (T180231) SECURITY: Remove PHPUnit file with known RCE if exists in update.php.
+* (T180231) SECURITY: Remove PHPUnit file with known RCE if exists in
+  update.php.
 * (T124404) SECURITY: XSS in langconverter when regex hits pcre.backtrack_limit.
 * (T119158) SECURITY: Handle -{}- syntax in attributes safely.
-* (T180488) (T125177) "api.log contains passwords in plaintext" wasn't correctly fixed in all
-  branches in the previous security release.
+* (T180488) (T125177) "api.log contains passwords in plaintext" wasn't correctly
+  fixed in all branches in the previous security release.
 
 == MediaWiki 1.29.1 ==
 
@@ -1617,7 +1650,8 @@ packages.
 * $wgRunJobsAsync is now false by default (T142751). This change only affects
   wikis with $wgJobRunRate > 0.
 * (T158474) "Unknown user" has been added to $wgReservedUsernames.
-* (T156983) $wgRateLimitsExcludedIPs now accepts CIDR ranges as well as single IPs.
+* (T156983) $wgRateLimitsExcludedIPs now accepts CIDR ranges as well as single
+  IPs.
 * $wgDummyLanguageCodes is deprecated. Additional language code mappings may be
   added to $wgExtraLanguageCodes instead.
 * (T161453) LocalisationCache will no longer use the temporary directory in it's
@@ -1676,30 +1710,32 @@ packages.
 ==== Removed and replaced external libraries ====
 
 === Bug fixes in 1.29 ===
-* (T62604) Core parser functions returning a number now format the number according
-  to the page content language, not wiki content language.
-* (T27187) Search suggestions based on jquery.suggestions will now correctly only
-  highlight prefix matches in the results.
+* (T62604) Core parser functions returning a number now format the number
+  according to the page content language, not wiki content language.
+* (T27187) Search suggestions based on jquery.suggestions will now correctly
+  only highlight prefix matches in the results.
 * (T157035) "new mw.Uri()" was ignoring options when using default URI.
 * Special:Allpages can no longer be filtered by redirect in miser mode.
-* (T160519) CACHE_ANYTHING will not be CACHE_ACCEL if no accelerator is installed.
-* (T109140) (T122209) SECURITY: Special:UserLogin and Special:Search allow redirect
-  to interwiki links.
+* (T160519) CACHE_ANYTHING will not be CACHE_ACCEL if no accelerator is
+  installed.
+* (T109140) (T122209) SECURITY: Special:UserLogin and Special:Search allow
+  redirect to interwiki links.
 * (T144845) SECURITY: XSS in SearchHighlighter::highlightText() when
   $wgAdvancedSearchHighlighting is true.
 * (T125177) SECURITY: API parameters may now be marked as "sensitive" to keep
   their values out of the logs.
-* (T150044) SECURITY: "Mark all pages visited" on the watchlist now requires a CSRF
-  token.
+* (T150044) SECURITY: "Mark all pages visited" on the watchlist now requires a
+  CSRF token.
 * (T156184) SECURITY: Escape content model/format url parameter in message.
 * (T151735) SECURITY: SVG filter evasion using default attribute values in DTD
   declaration.
-* (T161453) SECURITY: LocalisationCache will no longer use the temporary directory
-  in it's fallback chain when trying to work out where to write the cache.
-* (T48143) SECURITY: Spam blacklist ineffective on encoded URLs inside file inclusion
-  syntax's link parameter.
-* (T108138) SECURITY: Sysops can undelete pages, although the page is protected against
-  it.
+* (T161453) SECURITY: LocalisationCache will no longer use the temporary
+  directory in it's fallback chain when trying to work out where to write the
+  cache.
+* (T48143) SECURITY: Spam blacklist ineffective on encoded URLs inside file
+  inclusion syntax's link parameter.
+* (T108138) SECURITY: Sysops can undelete pages, although the page is protected
+  against it.
 
 === Action API changes in 1.29 ===
 * Submitting sensitive authentication request parameters to action=login,
@@ -1714,8 +1750,8 @@ packages.
   parameter prefixes (e.g. all query submodules) will no longer be prefixed.
 * ApiPageSet-using modules will report the 'invalidreason' using the specified
   'errorformat'.
-* action=emailuser may return a "Warnings" status, and now returns 'warnings' and
-  'errors' subelements (as applicable) instead of 'message'.
+* action=emailuser may return a "Warnings" status, and now returns 'warnings'
+  and 'errors' subelements (as applicable) instead of 'message'.
 * action=imagerotate returns an 'errors' subelement rather than 'errormessage'.
 * action=move now reports errors when moving the talk page as an array under
   key 'talkmove-errors', rather than using 'talkmove-error-code' and
@@ -1785,8 +1821,8 @@ changes to languages because of Phabricator reports.
 
 ==== No fallback for Ukrainian ====
 * (T39314) The fallback from Ukrainian to Russian was removed. The Ukrainian
-  language will now use the default fallback language: English. When a translation
-  to Ukrainian is not available, an English string will be shown.
+  language will now use the default fallback language: English. When a
+  translation to Ukrainian is not available, an English string will be shown.
 
 === Other changes in 1.29 ===
 * Database::getSearchEngine() (deprecated in 1.28) was removed. Use
@@ -1801,8 +1837,8 @@ changes to languages because of Phabricator reports.
   were removed.
 * Article::getAutosummary() and WikiPage::getAutosummary() (deprecated in 1.21)
   were removed.
-* Hook ArticleViewCustom (deprecated in 1.21) was removed. Use ArticleContentViewCustom
-  instead.
+* Hook ArticleViewCustom (deprecated in 1.21) was removed. Use
+  ArticleContentViewCustom instead.
 * Hooks EditPageGetDiffText and ShowRawCssJs (deprecated in 1.21) were removed.
 * Class RevisiondeleteAction (deprecated in 1.25) was removed.
 * WikiPage::prepareTextForEdit() (deprecated in 1.21) was removed.
@@ -1813,13 +1849,16 @@ changes to languages because of Phabricator reports.
 * User::isPasswordReminderThrottled() (deprecated in 1.27) was removed.
 * Class FSRepo (deprecated in 1.19) was removed.
 * WebRequest::checkSessionCookie() (deprecated in 1.27) was removed. Use
-  \MediaWiki\Session\SessionManager::singleton()->getPersistedSessionId() instead.
+  \MediaWiki\Session\SessionManager::singleton()->getPersistedSessionId()
+  instead.
 * Class ImageGallery (deprecated in 1.22) was removed.
   Use ImageGalleryBase::factory instead.
-* Title::moveNoAuth() (deprecated in 1.25) was removed. Use MovePage class instead.
+* Title::moveNoAuth() (deprecated in 1.25) was removed. Use MovePage class
+  instead.
 * Hook UnknownAction (deprecated in 1.19) was actually deprecated (it will now
   emit warnings). Create a subclass of Action and add it to $wgActions instead.
-* WikiRevision::getText() (deprecated since 1.21) is no longer marked deprecated.
+* WikiRevision::getText() (deprecated since 1.21) is no longer marked
+  deprecated.
 * Linker::getInterwikiLinkAttributes() (deprecated since 1.25) was removed.
 * Linker::getInternalLinkAttributes() (deprecated since 1.25) was removed.
 * Linker::getInternalLinkAttributesObj() (deprecated since 1.25) was removed.
@@ -1827,9 +1866,10 @@ changes to languages because of Phabricator reports.
 * RedisConnectionPool::handleException (deprecated since 1.23) was removed.
 * The static properties mw.Api.errors and mw.Api.warnings, containing incomplete
   and outdated lists of errors/warnings returned by the API, are now deprecated.
-* wiki.phtml entry point was removed.  Refer to index.php instead. If you want "wiki.phtml"
-  URLs to continue to work, set up redirects. In Apache, this can be done by enabling
-  mod_rewrite and adding the following rules to your configuration:
+* wiki.phtml entry point was removed.  Refer to index.php instead. If you want
+  "wiki.phtml" URLs to continue to work, set up redirects. In Apache, this can
+  be done by enabling mod_rewrite and adding the following rules to your
+  configuration:
 
     RewriteEngine On
     RewriteBase /
@@ -1857,8 +1897,8 @@ changes to languages because of Phabricator reports.
 * Article::doEditContent() was marked as deprecated, to be removed in 1.30
   or later.
 * ContentHandler::runLegacyHooks() was removed.
-* refreshLinks.php now can be limited to a particular category with --category=...
-  or a tracking category with --tracking-category=...
+* refreshLinks.php now can be limited to a particular category with
+  --category=... or a tracking category with --tracking-category=...
 * User-like objects that are passed to SpecialUserRights and its subclasses are
   now required to have a getGroupMemberships() method. See UserRightsProxy for
   an example.
@@ -1932,28 +1972,34 @@ This is a security and maintenance release of the MediaWiki 1.28 branch.
 === Changes since 1.28.2 ==
 * (T168856) Allow SVGs created by Dia to be uploaded.
 * (T157545) Add missing doUpdates() call to refreshLinks.php.
-* (T165714) (T100085) Better handling of jobs execution in post-connection shutdown.
-* (T154425) (T154438) (T157679) Use AutoCommitUpdate instead of Database->onTransactionIdle.
+* (T165714) (T100085) Better handling of jobs execution in post-connection
+  shutdown.
+* (T154425) (T154438) (T157679) Use AutoCommitUpdate instead of
+  Database->onTransactionIdle.
 * (T154425) Make DeferredUpdates detect LBFactory transaction rounds.
-* (T149454) Restore erroneously removed realTableName call from DatabasePostgres.
+* (T149454) Restore erroneously removed realTableName call from
+  DatabasePostgres.
 * (T167798) Fix phrase search and highlighting for phrase queries.
 * (T151136) Provide credits information to callbacks in extension registration.
-* (T160462) Allow namespaces defined in extension.json to be overwritten locally.
+* (T160462) Allow namespaces defined in extension.json to be overwritten
+  locally.
 * (T168337) Fix ErrorPageError to work from non-UI contexts.
 * (T143788) Backports for PHP 7.0 and 7.1 support.
 * (T175439) Unbreak Postgres Updater when setting defaults for a column.
 * (T160298) Remove use of implicitGroupBy() in ActiveUsersPager.
 * (T174255) Declare uploadCount property in importDump.php.
-* (T180231) SECURITY: Updated dev dependancy phpunit/phpunit from v4.8.24 to v4.8.36.
-* (T178451) SECURITY: Potential XSS when $wgShowExceptionDetails = false and browser
-  sends non-standard url escaping.
+* (T180231) SECURITY: Updated dev dependancy phpunit/phpunit from v4.8.24 to
+  v4.8.36.
+* (T178451) SECURITY: Potential XSS when $wgShowExceptionDetails = false and
+  browser sends non-standard url escaping.
 * (T165846) SECURITY: BotPassword login attempts weren't throttled.
 * (T128209) SECURITY: Reflected File Download from api.php.
 * (T134100) SECURITY: Do not reveal if user exists during login failure.
 * (T176247) SECURITY: Ensure Message::rawParams can't lead to XSS.
 * (T125163) SECURITY: Make anchor for headlines escape > and <.
 * (T180237) SECURITY: Protect vendor folder with .htaccess.
-* (T180231) SECURITY: Remove PHPUnit file with known RCE if exists in update.php.
+* (T180231) SECURITY: Remove PHPUnit file with known RCE if exists in
+  update.php.
 * (T124404) SECURITY: XSS in langconverter when regex hits pcre.backtrack_limit.
 * (T119158) SECURITY: Handle -{}- syntax in attributes safely.
 
@@ -1972,8 +2018,8 @@ This is a security and maintenance release of the MediaWiki 1.28 branch.
 
 * $wgRunJobsAsync is now false by default (T142751). This change only affects
   wikis with $wgJobRunRate > 0.
-* Fix fatal from "WaitConditionLoop" not being found, experienced when a wiki has
-  more than one database server setup.
+* Fix fatal from "WaitConditionLoop" not being found, experienced when a wiki
+  has more than one database server setup.
 * (T152717) Better escaping for PHP mail() command,
 * (T154670) A missing method causing the MySQL installer to fatal in rare
   circumstances was restored.
@@ -1981,25 +2027,28 @@ This is a security and maintenance release of the MediaWiki 1.28 branch.
 * (T158766) Avoid SQL error on MSSQL when using selectRowCount().
 * (T145635) Fix too long index error when installing with MSSQL.
 * (T156184) $wgRawHtml will no longer apply to internationalization messages.
-* (T160519) CACHE_ANYTHING will not be CACHE_ACCEL if no accelerator is installed.
-* (T154872) Fix incorrect ar_usertext_timestamp index names in new 1.28 installs.
-* (T109140) (T122209) SECURITY: Special:UserLogin and Special:Search allow redirect
-  to interwiki links.
+* (T160519) CACHE_ANYTHING will not be CACHE_ACCEL if no accelerator is
+  installed.
+* (T154872) Fix incorrect ar_usertext_timestamp index names in new 1.28
+  installs.
+* (T109140) (T122209) SECURITY: Special:UserLogin and Special:Search allow
+  redirect to interwiki links.
 * (T144845) SECURITY: XSS in SearchHighlighter::highlightText() when
   $wgAdvancedSearchHighlighting is true.
 * (T125177) SECURITY: API parameters may now be marked as "sensitive" to keep
   their values out of the logs.
-* (T150044) SECURITY: "Mark all pages visited" on the watchlist now requires a CSRF
-  token.
+* (T150044) SECURITY: "Mark all pages visited" on the watchlist now requires a
+  CSRF token.
 * (T156184) SECURITY: Escape content model/format url parameter in message.
 * (T151735) SECURITY: SVG filter evasion using default attribute values in DTD
   declaration.
-* (T161453) SECURITY: LocalisationCache will no longer use the temporary directory
-  in it's fallback chain when trying to work out where to write the cache.
-* (T48143) SECURITY: Spam blacklist ineffective on encoded URLs inside file inclusion
-  syntax's link parameter.
-* (T108138) SECURITY: Sysops can undelete pages, although the page is protected against
-  it.
+* (T161453) SECURITY: LocalisationCache will no longer use the temporary
+  directory in it's fallback chain when trying to work out where to write the
+  cache.
+* (T48143) SECURITY: Spam blacklist ineffective on encoded URLs inside file
+  inclusion syntax's link parameter.
+* (T108138) SECURITY: Sysops can undelete pages, although the page is protected
+  against it.
 
 == MediaWiki 1.28 ==
 
@@ -2026,7 +2075,8 @@ This is a security and maintenance release of the MediaWiki 1.28 branch.
 * (T149759) manifest_version: 2 was removed.
 
 === Configuration changes in 1.28 ===
-* $wgSend404Code now affects status code of action=history if the page is not there.
+* $wgSend404Code now affects status code of action=history if the page is not
+  there.
 * BREAKING CHANGE: $wgHTTPProxy is now *required* for all external requests
   made by MediaWiki via a proxy. Relying on the http_proxy environment
   variable is no longer supported.
@@ -2050,16 +2100,19 @@ This is a security and maintenance release of the MediaWiki 1.28 branch.
 * When $wgEditSubmitButtonLabelPublish is true, MediaWiki will label the button
   to store-to-database-and-show-to-others as "Publish page"/"Publish changes";
   if false, the default, they will be "Save page"/"Save changes".
-* The 'editcontentmodel' permission is now granted to all logged-in users ('user').
+* The 'editcontentmodel' permission is now granted to all logged-in users
+  ('user').
   instead of just administrators ('sysop'). Documentation for this feature is
   available at <https://www.mediawiki.org/wiki/Help:ChangeContentModel>.
-* $wgRevisionCacheExpiry is now set to one week by default instead of being disabled.
-* Magic links are now disabled by default, and can be re-enabled by modifying the value
-  of $wgEnableMagicLinks. Their usage is discouraged, but if they are manually enabled,
-  a tracking category will be added to help identify usage and make it easier to migrate
-  away from. If you depend upon magic link functionality, it is requested that you comment
-  on <https://www.mediawiki.org/wiki/Requests_for_comment/Future_of_magic_links> and
-  explain your use case(s).
+* $wgRevisionCacheExpiry is now set to one week by default instead of being
+  disabled.
+* Magic links are now disabled by default, and can be re-enabled by modifying
+  the value of $wgEnableMagicLinks. Their usage is discouraged, but if they are
+  manually enabled, a tracking category will be added to help identify usage and
+  make it easier to migrate away from. If you depend upon magic link
+  functionality, it is requested that you comment on
+  <https://www.mediawiki.org/wiki/Requests_for_comment/Future_of_magic_links>
+  and explain your use case(s).
 * New config variable $wgCSPFalsePositiveUrls to control what URLs to ignore
   in upcoming Content-Security-Policy feature's reporting.
 
@@ -2074,21 +2127,24 @@ This is a security and maintenance release of the MediaWiki 1.28 branch.
   and the file description page, but does not run for uploads to stash.
 * (T141604) Extensions can now provide a better error message when their
   maintenance scripts are run without the extension being installed.
-* (T8948) Numeric sorting in categories is now supported by setting $wgCategoryCollation
-  to 'uca-default-u-kn' or 'uca-<langcode>-u-kn'. If you can't use UCA collations,
-  a 'numeric' collation is also available. If migrating from another
-  collation, you will need to run the updateCollation.php maintenance script.
-* Two new codes have been added to #time parser function: "xit" for days in current
-  month, and "xiz" for days passed in the year, both in Iranian calendar.
+* (T8948) Numeric sorting in categories is now supported by setting
+  $wgCategoryCollation to 'uca-default-u-kn' or 'uca-<langcode>-u-kn'. If you
+  can't use UCA collations, a 'numeric' collation is also available. If
+  migrating from another collation, you will need to run the updateCollation.php
+  maintenance script.
+* Two new codes have been added to #time parser function: "xit" for days in
+  current month, and "xiz" for days passed in the year, both in Iranian
+  calendar.
 * mw.Api has a new option, useUS, to use U+001F (Unit Separator) when
   appropriate for sending multi-valued parameters. This defaults to true when
   the mw.Api instance seems to be for the local wiki.
-* After a client performs an action which alters a database that has replica databases,
-  MediaWiki will wait for the replica databases to synchronize with the master database
-  while it renders the HTML output. However, if the output is a redirect to another wiki
-  on the wiki farm with a different domain, MediaWiki will instead alter the redirect
-  URL to include a ?cpPosTime parameter that triggers the database synchronization when
-  the URL is followed by the client. The same-domain case uses a new cpPosTime cookie.
+* After a client performs an action which alters a database that has replica
+  databases, MediaWiki will wait for the replica databases to synchronize with
+  the master database while it renders the HTML output. However, if the output
+  is a redirect to another wiki on the wiki farm with a different domain,
+  MediaWiki will instead alter the redirect URL to include a ?cpPosTime
+  parameter that triggers the database synchronization when the URL is followed
+  by the client. The same-domain case uses a new cpPosTime cookie.
 * Added new hooks, 'ApiQueryBaseBeforeQuery', 'ApiQueryBaseAfterQuery', and
   'ApiQueryBaseProcessRow', to make it easier for extensions to add 'prop' and
   'show' parameters to existing API query modules.
@@ -2105,7 +2161,8 @@ This is a security and maintenance release of the MediaWiki 1.28 branch.
 * Added wikimedia/wait-condition-loop v1.0.1
 
 === Bug fixes in 1.28 ===
-* (T146496) action=history pages should return 404 HTTP error code if the page does not exist
+* (T146496) action=history pages should return 404 HTTP error code if the page
+  does not exist
 * (T137264) SECURITY: XSS in unclosed internal links
 * (T133147) SECURITY: Escape '<' and ']]>' in inline <style> blocks
 * (T133147) SECURITY: Require login to preview user CSS pages
@@ -2132,9 +2189,9 @@ This is a security and maintenance release of the MediaWiki 1.28 branch.
   action=createaccount, action=linkaccount, and action=changeauthenticationdata
   in the query string is now deprecated and outputs a warning. They should be
   submitted in the POST body instead.
-* (T141960) Multi-valued parameters may now be separated using U+001F (Unit Separator)
-  instead of the pipe character. This will be useful if some of the multiple
-  values need to contain pipes, e.g. for action=options.
+* (T141960) Multi-valued parameters may now be separated using U+001F
+  (Unit Separator) instead of the pipe character. This will be useful if some of
+  the multiple values need to contain pipes, e.g. for action=options.
 * The API will now warn if input is not NFC-normalized Unicode or if it
   contains invalid characters.
 * The 'normalized' list output by action=query and other modules that use
@@ -2152,7 +2209,8 @@ This is a security and maintenance release of the MediaWiki 1.28 branch.
 * Added a new hook, 'ApiMakeParserOptions', to allow extensions to better
   interact with ApiParse and ApiExpandTemplates.
 * (T139565) SECURITY: API: Generate head items in the context of the given title
-* (T115333) SECURITY: Check read permission when loading page content in ApiParse
+* (T115333) SECURITY: Check read permission when loading page content in
+  ApiParse
 * ApiBase::getResultData() was removed (deprecated since 1.25)
 * ApiBase::makeHelpArrayToString() was removed (deprecated since 1.25)
 * ApiBase::makeHelpMsgParameters() was removed (deprecated since 1.25)
@@ -2202,7 +2260,8 @@ changes to languages because of Phabricator reports.
 * (T135867) shn (Shan), thanks to translators Khun Sar, Piangpha,
   Saiddzone Saimawnkham, Saosukham, and Sengwan.
 * Czech (cs) and Slovak (sk) set as reciprocal fallbacks.
-* (T146744) Livvi-Karelian (olo) namespace messages created thanks to translator Ilja.mos.
+* (T146744) Livvi-Karelian (olo) namespace messages created thanks to translator
+  Ilja.mos.
 
 === Other changes in 1.28 ===
 * (T128697) Improved handling of large diffs.
@@ -2211,8 +2270,8 @@ changes to languages because of Phabricator reports.
 * Deprecated APIEditBeforeSave hook in favor of EditFilterMergedContent.
 * The 'UploadVerification' hook is deprecated. Use 'UploadVerifyFile' instead.
 * SiteConfiguration::isLocalVHost() was removed (deprecated since 1.25).
-* The 'UserLoginComplete' hook has a new parameter to differentiate between actual
-  login and visiting the login page while already logged in.
+* The 'UserLoginComplete' hook has a new parameter to differentiate between
+  actual login and visiting the login page while already logged in.
 * ResourceLoader::makeLoaderURL() was removed (deprecated since 1.24).
 * $.fn.liveAndTestAtStart was removed (deprecated since 1.24).
 * mw.util.tooltipAccessKeyPrefix was removed (deprecated since 1.24).
@@ -2220,7 +2279,8 @@ changes to languages because of Phabricator reports.
 * Linker::link() and Linker::linkKnown() were deprecated; please instead use
   MediaWiki\Linker\LinkRenderer. In addition, the LinkBegin and LinkEnd hooks
   were replaced by HtmlPageLinkRendererBegin and HtmlPageLinkRendererEnd
-  respectively. See docs/hooks.txt for the specific changes needed for those hooks.
+  respectively. See docs/hooks.txt for the specific changes needed for those
+  hooks.
 * Linker::formatSize() was deprecated. Use Language::formatSize() directly.
 * Aliases for Linker methods, deprecated since 1.21, were removed from Skin:
   * Skin::commentBlock() (use Linker::commentBlock() instead)
@@ -2236,8 +2296,9 @@ changes to languages because of Phabricator reports.
   Use ...->stashFile()->getFileKey() instead.
 * "Public domain" was removed as a wiki license option from the installer, in
   favour of CC-0.
-* AuthenticationRequest::$required is now changed from REQUIRED to PRIMARY_REQUIRED
-  on requests needed by primary providers even if all primaries need them.
+* AuthenticationRequest::$required is now changed from REQUIRED to
+  PRIMARY_REQUIRED on requests needed by primary providers even if all primaries
+  need them.
   Primary providers are discouraged from returning multiple REQUIRED requests.
 * OOjs UI PHP widgets constructed with the `'infusable' => true` config option
   will no longer be automatically infused. You should call `OO.ui.infuse()`
@@ -2251,13 +2312,14 @@ changes to languages because of Phabricator reports.
 * IP::isConfiguredProxy() and IP::isTrustedProxy() were removed. Callers should
   migrate to using the same functions on a ProxyLookup instance, obtainable from
   MediaWikiServices.
-* The ArticleAfterFetchContent, ArticleInsertComplete, ArticleSave, ArticleSaveComplete,
-  ArticleViewCustom, EditFilterMerged, EditPageGetDiffText, EditPageGetPreviewText and
-  ShowRawCssJs hooks will now emit deprecation warnings if used.
+* The ArticleAfterFetchContent, ArticleInsertComplete, ArticleSave,
+  ArticleSaveComplete, ArticleViewCustom, EditFilterMerged, EditPageGetDiffText,
+  EditPageGetPreviewText and ShowRawCssJs hooks will now emit deprecation
+  warnings if used.
 * (T68404) CSS3 attr() function with url type is no longer allowed
   in inline styles.
-* Database::getSearchEngine() is deprecated, use SearchEngineFactory::getSearchEngineClass
-  instead.
+* Database::getSearchEngine() is deprecated, use
+  SearchEngineFactory::getSearchEngineClass instead.
 
 == Compatibility ==
 
@@ -2338,7 +2400,8 @@ This is a security and maintenance release of the MediaWiki 1.27 branch.
   account lock.
 * Upgraded Moment.js from v2.8.4 to v2.19.3.
 * (T160298) Fixed Special:ActiveUsers due to bad backport.
-* (T87572) Make FormatMetadata::flattenArrayReal() work for an associative array.
+* (T87572) Make FormatMetadata::flattenArrayReal() work for an associative
+  array.
 * Updated list of SPDX licenses for extensions.
 * (T189567) the CLI installer (maintenance/install.php) learned to detect and
   include extensions. Pass --with-extensions to enable that feature.
@@ -2346,7 +2409,8 @@ This is a security and maintenance release of the MediaWiki 1.27 branch.
 * Add default edit rate limit of 90 edits/minute for all users.
 * (T196125) php-memcached 3.0 (provided with PHP 7.0) is now supported.
 * (T196672) The mtime of extension.json files is now able to be zero.
-* (T118683) Fix exception from &$user deref on HHVM in the TitleMoveComplete hook.
+* (T118683) Fix exception from &$user deref on HHVM in the TitleMoveComplete
+  hook.
 * (T180403) Validate $length in padleft/padright parser functions.
 * (T143790) Make $wgEmailConfirmToEdit only affect edit actions.
 * Special:BotPasswords now requires reauthentication.
@@ -2363,27 +2427,30 @@ This is a security and maintenance release of the MediaWiki 1.27 branch.
 * (T141604) Support conditionally registered namespaces.
 * (T167798) Fix highlighting for phrase queries and phrase search.
 * (T151136) Provide credits information to callbacks.
-* (T160462) Allow namespaces defined in extension.json to be overwritten locally.
+* (T160462) Allow namespaces defined in extension.json to be overwritten
+  locally.
 * (T168856) Allow SVGs created by Dia to be uploaded.
-* (T144705) (T148662) Password reset link is no longer shown when no reset options are
-  available.
+* (T144705) (T148662) Password reset link is no longer shown when no reset
+  options are available.
 * (T143788) (T174262) Various backports for PHP 7.0 and 7.1 support.
-* (T66795) $wgUserEmailUseReplyTo is now true by default to work around restrictive DMARC
-  policies.
-* DB_REPLICA constant added from REL1_28+ to ease backports to extensions and core.
+* (T66795) $wgUserEmailUseReplyTo is now true by default to work around
+  restrictive DMARC policies.
+* DB_REPLICA constant added from REL1_28+ to ease backports to extensions and
+  core.
 * (T175439) Unbreak Postgres Updater when setting defaults for a column.
 * (T160298) Remove use of implicitGroupBy() in ActiveUsersPager.
 * (T142304) Allow putting the app ID in the password for bot passwords.
 * Updated dev dependancy phpunit/phpunit from v4.8.24 to v4.8.36.
-* (T178451) SECURITY: Potential XSS when $wgShowExceptionDetails = false and browser
-  sends non-standard url escaping.
+* (T178451) SECURITY: Potential XSS when $wgShowExceptionDetails = false and
+  browser sends non-standard url escaping.
 * (T165846) SECURITY: BotPassword login attempts weren't throttled.
 * (T128209) SECURITY: Reflected File Download from api.php.
 * (T134100) SECURITY: Do not reveal if user exists during login failure.
 * (T176247) SECURITY: Ensure Message::rawParams can't lead to XSS.
 * (T125163) SECURITY: Make anchor for headlines escape > and <.
 * (T180237) SECURITY: Protect vendor folder with .htaccess.
-* (T180231) SECURITY: Remove PHPUnit file with known RCE if exists in update.php.
+* (T180231) SECURITY: Remove PHPUnit file with known RCE if exists in
+  update.php.
 * (T124404) SECURITY: XSS in langconverter when regex hits pcre.backtrack_limit.
 * (T119158) SECURITY: Handle -{}- syntax in attributes safely.
 
@@ -2402,8 +2469,8 @@ MediaWiki itself since 1.27.2, but none of them were security relevant.
 This is a security and maintenance release of the MediaWiki 1.27 branch.
 
 ApiCreateAccount was removed in 1.27.0. It was incorrectly still marked as
-deprecated (rather than already removed) in the RELEASE-NOTES at the point 1.27.0
-was released.
+deprecated (rather than already removed) in the RELEASE-NOTES at the point
+1.27.0 was released.
 
 === Changes since 1.27.1 ===
 
@@ -2422,24 +2489,26 @@ was released.
 * (T158766) Avoid SQL error on MSSQL when using selectRowCount()
 * (T145635) Fix too long index error when installing with MSSQL.
 * (T156184) $wgRawHtml will no longer apply to internationalization messages.
-* (T160519) CACHE_ANYTHING will not be CACHE_ACCEL if no accelerator is installed.
-* (T109140) (T122209) SECURITY: Special:UserLogin and Special:Search allow redirect
-  to interwiki links.
+* (T160519) CACHE_ANYTHING will not be CACHE_ACCEL if no accelerator is
+  installed.
+* (T109140) (T122209) SECURITY: Special:UserLogin and Special:Search allow
+  redirect to interwiki links.
 * (T144845) SECURITY: XSS in SearchHighlighter::highlightText() when
   $wgAdvancedSearchHighlighting is true.
 * (T125177) SECURITY: API parameters may now be marked as "sensitive" to keep
   their values out of the logs.
-* (T150044) SECURITY: "Mark all pages visited" on the watchlist now requires a CSRF
-  token.
+* (T150044) SECURITY: "Mark all pages visited" on the watchlist now requires a
+  CSRF token.
 * (T156184) SECURITY: Escape content model/format url parameter in message.
 * (T151735) SECURITY: SVG filter evasion using default attribute values in DTD
   declaration.
-* (T161453) SECURITY: LocalisationCache will no longer use the temporary directory
-  in it's fallback chain when trying to work out where to write the cache.
-* (T48143) SECURITY: Spam blacklist ineffective on encoded URLs inside file inclusion
-  syntax's link parameter.
-* (T108138) SECURITY: Sysops can undelete pages, although the page is protected against
-  it.
+* (T161453) SECURITY: LocalisationCache will no longer use the temporary
+  directory in it's fallback chain when trying to work out where to write the
+ cache.
+* (T48143) SECURITY: Spam blacklist ineffective on encoded URLs inside file
+  inclusion syntax's link parameter.
+* (T108138) SECURITY: Sysops can undelete pages, although the page is protected
+  against it.
 
 == MediaWiki 1.27.1 ==
 
@@ -2458,9 +2527,12 @@ This is a maintenance release of the MediaWiki 1.27 branch.
 * (T129738) SECURITY: Make $wgBlockDisablesLogin also restrict logged in
   permissions
 * (T129738) SECURITY: Make blocks log users out if $wgBlockDisablesLogin is true
-* (T115333) SECURITY: Check read permission when loading page content in ApiParse
-* (T57548) Remove support for $wgWellFormedXml = false, all output is now well formed
-* (T139670) Move 'UserGetRights' call before application of Session::getAllowedUserRights()
+* (T115333) SECURITY: Check read permission when loading page content in
+  ApiParse
+* (T57548) Remove support for $wgWellFormedXml = false, all output is now well
+  formed
+* (T139670) Move 'UserGetRights' call before application of
+  Session::getAllowedUserRights()
 
 == MediaWiki 1.27.0 ==
 
@@ -2587,11 +2659,15 @@ The following PHP extensions are strongly recommended:
 *** AbortLogin (create a MediaWiki\Auth\PreAuthenticationProvider instead)
 *** AbortNewAccount (create a MediaWiki\Auth\PreAuthenticationProvider instead)
 *** AddNewAccount (use LocalUserCreated instead)
-*** AuthPluginSetup (create a MediaWiki\Auth\PrimaryAuthenticationProvider instead)
+*** AuthPluginSetup (create a MediaWiki\Auth\PrimaryAuthenticationProvider
+    instead)
 *** ChangePasswordForm (use AuthChangeFormFields instead, or security levels)
-*** LoginUserMigrated (create a MediaWiki\Auth\PreAuthenticationProvider instead)
-*** UserCreateForm (create a MediaWiki\Auth\AuthenticationProvider of some type instead)
-*** UserLoginForm (create a MediaWiki\Auth\AuthenticationProvider of some type instead)
+*** LoginUserMigrated (create a MediaWiki\Auth\PreAuthenticationProvider
+    instead)
+*** UserCreateForm (create a MediaWiki\Auth\AuthenticationProvider of some type
+    instead)
+*** UserLoginForm (create a MediaWiki\Auth\AuthenticationProvider of some type
+    instead)
 ** The following hooks are removed:
 *** AbortChangePassword
 *** LoginPasswordResetMessage
@@ -2666,14 +2742,15 @@ The following PHP extensions are strongly recommended:
 * Added $wgAuthenticationTokenVersion, which if non-null prevents the
   user_token database field from being exposed in cookies. Setting this would
   be a good idea, but will log out all current sessions.
-* $wgEventRelayerConfig was added, for managing PubSub event relay configuration,
-  specifically for reliable CDN url purges.
+* $wgEventRelayerConfig was added, for managing PubSub event relay
+  configuration, specifically for reliable CDN url purges.
 * Requests have unique IDs, equal to the UNIQUE_ID environment variable (when
   MediaWiki is behind Apache+mod_unique_id or something similar) or a randomly-
   generated 24-character string. This request ID is used to annotate log records
-  and error messages. It is available client-side via mw.config.get( 'wgRequestId' ).
-  The request ID supplants exception IDs. Accordingly, MWExceptionHandler::getLogId()
-  is deprecated.
+  and error messages. It is available client-side via
+  mw.config.get( 'wgRequestId' ).
+  The request ID supplants exception IDs. Accordingly,
+  MWExceptionHandler::getLogId() is deprecated.
 * (T33313) Add a preference for watching uploads by default, also applies
   to API-based upload tools.
 * $wgJpegPixelFormat was added to override chroma subsampling for JPEG image
@@ -2683,7 +2760,8 @@ The following PHP extensions are strongly recommended:
   configuration of multiple authentication pieces that was possible with
   AuthPlugin. For example, it's now easy to plug in second-factor
   authentication, or add additional checks to the login process, or to support
-  multiple login methods at once, or to support non-password-based login methods.
+  multiple login methods at once, or to support non-password-based login
+  methods.
 ** Providers are configured via the global setting $wgAuthManagerConfig.
 ** A global, $wgDisableAuthManager, is temporarily available to disable
    AuthManager until extensions are ready to support it.
@@ -2696,8 +2774,9 @@ The following PHP extensions are strongly recommended:
 ** New hook, SecuritySensitiveOperationStatus, to work with the new mechanism
    for requiring a recent login before taking security-sensitive operations
    like changing a password.
-** Two new globals, $wgChangeCredentialsBlacklist and $wgRemoveCredentialsBlacklist
-   can be used to prevent the web UI and the API changing certain authentication data.
+** Two new globals, $wgChangeCredentialsBlacklist and
+   $wgRemoveCredentialsBlacklist can be used to prevent the web UI and the API
+   changing certain authentication data.
 * The file upload dialog (available if you install WikiEditor or VisualEditor)
   can now be configured using $wgUploadDialog.
 
@@ -2766,10 +2845,13 @@ The following PHP extensions are strongly recommended:
 * ApiBase::addTokenProperties() was removed (deprecated since 1.24).
 * ApiBase::getFinalPossibleErrors() was removed (deprecated since 1.24).
 * ApiBase::getFinalResultProperties() was removed (deprecated since 1.24).
-* ApiBase::getRequireAtLeastOneParameterErrorMessages() was removed (deprecated since 1.24).
+* ApiBase::getRequireAtLeastOneParameterErrorMessages() was removed (deprecated
+  since 1.24).
 * ApiBase::getPossibleErrors() was removed (deprecated since 1.24).
-* ApiBase::getRequireMaxOneParameterErrorMessages() was removed (deprecated since 1.24).
-* ApiBase::getRequireOnlyOneParameterErrorMessages() was removed (deprecated since 1.24).
+* ApiBase::getRequireMaxOneParameterErrorMessages() was removed (deprecated
+  since 1.24).
+* ApiBase::getRequireOnlyOneParameterErrorMessages() was removed (deprecated
+  since 1.24).
 * ApiBase::getResultProperties() was removed (deprecated since 1.24).
 * ApiBase::getTitleOrPageIdErrorMessage() was removed (deprecated since 1.24).
 * ApiBase::parseErrors() was removed (deprecated since 1.24).
@@ -2800,7 +2882,8 @@ changes to languages because of Phabricator reports.
 * (T116020) Aliases of magic words in MessagesXx.php are sorted by usage.
 
 === Other changes in 1.27 ===
-* Added dependency injection (DI) infrastructure, see docs/injection.txt for details.
+* Added dependency injection (DI) infrastructure, see docs/injection.txt for
+  details.
   It is planned to incrementally move MediaWiki code towards using DI, using the
   service locator (SL) pattern as a stepping stone.
 * ProfilerOutputUdp was removed. Note that there is a ProfilerOutputStats class.
@@ -2888,18 +2971,21 @@ changes to languages because of Phabricator reports.
   together but instead pick the final one, similar to image syntax.
 * XML-like parser tags (such as <gallery>), when unclosed, will be left unparsed
   rather than consume everything until the end of the page.
-* New maintenance script resetUserEmail.php allows sysadmins to reset user emails in case
-  a user forgot password/account was stolen.
+* New maintenance script resetUserEmail.php allows sysadmins to reset user
+  emails in case a user forgot password/account was stolen.
 * wfCheckEntropy() was removed (deprecated in 1.27).
 * Browser support for Internet Explorer 8 lowered from Grade A to Grade C.
 * ContentHandler::supportsCategories method added. Default is true.
   CategoryMembershipChangeJob updates are skipped for content that
   does not support categories.
-* wikidiff difference engine is no longer supported, anyone still using it are encouraged
-  to upgrade to wikidiff2 which is actively maintained and has better package availability.
-* Database logic was removed from WatchedItem and a WatchedItemStore was created:
-** WatchedItem::IGNORE_USER_RIGHTS and WatchedItem::CHECK_USER_RIGHTS were deprecated.
-   User::IGNORE_USER_RIGHTS and User::CHECK_USER_RIGHTS were introduced.
+* wikidiff difference engine is no longer supported, anyone still using it are
+  encouraged to upgrade to wikidiff2 which is actively maintained and has better
+  package availability.
+* Database logic was removed from WatchedItem and a WatchedItemStore was
+  created:
+** WatchedItem::IGNORE_USER_RIGHTS and WatchedItem::CHECK_USER_RIGHTS were
+   deprecated. User::IGNORE_USER_RIGHTS and User::CHECK_USER_RIGHTS were
+   introduced.
 ** WatchedItem::fromUserTitle was deprecated in favour of the constructor.
 ** WatchedItem::resetNotificationTimestamp was deprecated.
 ** WatchedItem::batchAddWatch was deprecated.
@@ -2909,8 +2995,9 @@ changes to languages because of Phabricator reports.
 ** WatchedItem::duplicateEntries was deprecated.
 ** EmailNotification::updateWatchlistTimestamp was deprecated.
 ** User::getWatchedItem was removed.
-* Unit tests don't work with external PHPUnit anymore, Composer is now the only supported
-  way. Run `composer install` to install it and other dev dependencies to run unit tests.
+* Unit tests don't work with external PHPUnit anymore, Composer is now the only
+  supported way. Run `composer install` to install it and other dev dependencies
+  to run unit tests.
 * wl_id field added to the watchlist table.
 * Revision::getRawText() was removed (deprecated since 1.21).
 * WikiPage::replaceSection() was removed (deprecated since 1.21).
@@ -2933,12 +3020,12 @@ changes to languages because of Phabricator reports.
 * Skin::newFromKey() was removed (deprecated since 1.24).
 * Skin::getUsableSkins() was removed (deprecated since 1.23).
 * LoadBalancer::pickRandom() was removed (deprecated in 1.21).
-* Article::getUndoText() and WikiPage::getUndoText were removed (deprecated since
-  1.21).
+* Article::getUndoText() and WikiPage::getUndoText were removed (deprecated
+  since 1.21).
 * DifferenceEngine::setText() was removed (deprecated in 1.21).
 * Title::newFromRedirectArray() was removed (deprecated in 1.21).
-* UserMailer::send() no longer accepts $replyto as the 5th argument and $contentType
-  as the 6th. These must be passed in the options array now.
+* UserMailer::send() no longer accepts $replyto as the 5th argument and
+  $contentType as the 6th. These must be passed in the options array now.
 * Title::newFromRedirectRecurse() was removed (deprecated in 1.21).
 * Skin::accesskey was removed (deprecated since 1.21).
 * Skin::blockLink was removed (deprecated since 1.21).
@@ -2989,15 +3076,15 @@ changes to languages because of Phabricator reports.
 * Skin::tooltipAndAccesskeyAttribs was removed (deprecated since 1.21).
 * Skin::userTalkLink was removed (deprecated since 1.21).
 * Skin::userToolLinksRedContribs was removed (deprecated since 1.21).
-* wikidiff3 is now the default and only PHP diff engine. It provides improved diff
-  performance on complex changes. $wgExternalDiffEngine = 'wikidiff3' therefore
-  makes no difference now. Users are still recommended to use wikidiff2 if possible,
-  though.
+* wikidiff3 is now the default and only PHP diff engine. It provides improved
+  diff performance on complex changes. $wgExternalDiffEngine = 'wikidiff3'
+  therefore makes no difference now. Users are still recommended to use
+  wikidiff2 if possible, though.
 * User::addNewUserLogEntry() was deprecated.
 * User::addNewUserLogEntryAutoCreate() was deprecated.
 * User::isPasswordReminderThrottled() was deprecated.
-* Bot-oriented parameters to Special:UserLogin (wpCookieCheck, wpSkipCookieCheck)
-  were removed.
+* Bot-oriented parameters to Special:UserLogin (wpCookieCheck,
+  wpSkipCookieCheck) were removed.
 * Installer can now be customized without patching MediaWiki code, see
   mw-config/overrides/README for details.
 
@@ -3063,7 +3150,8 @@ This is a maintenance release of the MediaWiki 1.26 branch.
 * (T129738) SECURITY: Make $wgBlockDisablesLogin also restrict logged in
   permissions
 * (T129738) SECURITY: Make blocks log users out if $wgBlockDisablesLogin is true
-* (T115333) SECURITY: Check read permission when loading page content in ApiParse
+* (T115333) SECURITY: Check read permission when loading page content in
+  ApiParse
 * Remove support for $wgWellFormedXml = false, all output is now well formed
 
 == MediaWiki 1.26.3 ==
@@ -3311,8 +3399,8 @@ changes to languages because of Phabricator reports.
 ** dty (डोटेली/Doteli), thanks to translators जनक राज भट्ट, बिप्लब आनन्द,
    मेश सिंह बोहरा, and राम प्रसाद जोशी
 ** luz (لئری دوٙمینی / Southern Luri)
-** olo (Livvinкarjala / Livvi-Karelian), thanks to translators Denö, Hiloin Natoi,
-   Ilja.mos, and Mashoi7
+** olo (Livvinкarjala / Livvi-Karelian), thanks to translators Denö, Hiloin
+   Natoi, Ilja.mos, and Mashoi7
 
 === Other changes in 1.26 ===
 * ChangeTags::tagDescription() will return false if the interface message
@@ -3348,8 +3436,8 @@ changes to languages because of Phabricator reports.
   - The $uniq_prefix argument for Parser::extractTagsAndParams() and the
     $prefix argument for StripState::_construct() are deprecated and their
     value is ignored.
-* wfSuppressWarnings() and wfRestoreWarnings() were split into a separate library,
-  mediawiki/at-ease, and are now deprecated. Callers should use
+* wfSuppressWarnings() and wfRestoreWarnings() were split into a separate
+  library, mediawiki/at-ease, and are now deprecated. Callers should use
   MediaWiki\suppressWarnings() and MediaWiki\restoreWarnings() directly.
 * The Block class constructor now takes an associative array of parameters
   instead of many optional positional arguments. Calling the constructor the old
@@ -3525,8 +3613,9 @@ This is a bug fix release of the MediaWiki 1.25 branch.
   be installed and running for any such queues to work.
 * $wgAutopromoteOnce no longer supports the 'view' event. For keeping some
   compatibility, any 'view' event triggers will still trigger on 'edit'.
-* $wgExtensionDirectory was added for when your extensions directory is somewhere
-  other than $IP/extensions (as $wgStyleDirectory does with the skins directory).
+* $wgExtensionDirectory was added for when your extensions directory is
+  somewhere other than $IP/extensions (as $wgStyleDirectory does with the skins
+  directory).
 
 === New features in 1.25 ===
 * (T64861) Updated plural rules to CLDR 26. Includes incompatible changes
@@ -3534,11 +3623,11 @@ This is a bug fix release of the MediaWiki 1.25 branch.
   that fall back to Russian.
 * (T60139) ResourceLoaderFileModule now supports language fallback
   for 'languageScripts'.
-* Added a new hook, "ContentAlterParserOutput", to allow extensions to modify the
-  parser output for a content object before links update.
+* Added a new hook, "ContentAlterParserOutput", to allow extensions to modify
+  the parser output for a content object before links update.
 * (T37785) Enhanced recent changes and extended watchlist are now default.
-  Documentation: https://meta.wikimedia.org/wiki/Special:MyLanguage/Help:Enhanced_recent_changes
-  and https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgDefaultUserOptions.
+  Documentation: https://meta.wikimedia.org/wiki/Help:Enhanced_recent_changes
+  and https://www.mediawiki.org/wiki/Manual:$wgDefaultUserOptions
 * (T69341) SVG images will no longer be base64-encoded when being embedded
   in CSS. This results in slight size increase before gzip compression (due to
   percent-encoding), but up to 20% decrease after it.
@@ -3547,10 +3636,12 @@ This is a bug fix release of the MediaWiki 1.25 branch.
   snippets) usually displayed in the top-right corner of the page. They have
   been in use on Wikipedia for a long time, implemented using templates and CSS
   absolute positioning.
-  - Basic wikitext syntax: <indicator name="foo">[[File:Foo.svg|20px]]</indicator>
-  - Usage instructions: https://www.mediawiki.org/wiki/Help:Page_status_indicators
+  - Basic wikitext syntax:
+    <indicator name="foo">[[File:Foo.svg|20px]]</indicator>
+  - Usage instructions:
+    https://www.mediawiki.org/wiki/Help:Page_status_indicators
   - Adjusting custom skins to support indicators:
-    https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Skinning#Page_status_indicators
+    https://www.mediawiki.org/wiki/Manual:Skinning#Page_status_indicators
 * Edit tokens may now be time-limited: passing a maximum age to
   User::matchEditToken will reject any older tokens.
 * The debug logging internals have been overhauled, and are now using the
@@ -3584,10 +3675,11 @@ This is a bug fix release of the MediaWiki 1.25 branch.
   dynamically-compiled Mustache templates (currently uses lightncandy library).
 * Clickable anchors for each section heading in the content are now generated
   and appear in the gutter on hovering over the heading.
-* Added 'CategoryViewer::doCategoryQuery' and 'CategoryViewer::generateLink' hooks
-  to allow extensions to override how links to pages are rendered within NS_CATEGORY
-* (T19665) Special:WantedPages only lists page which having at least one red link
-  pointing to it.
+* Added 'CategoryViewer::doCategoryQuery' and 'CategoryViewer::generateLink'
+  hooks to allow extensions to override how links to pages are rendered within
+  NS_CATEGORY
+* (T19665) Special:WantedPages only lists page which having at least one red
+  link pointing to it.
 * New hooks 'ApiMain::moduleManager' and 'ApiQuery::moduleManager', can be
   used for conditional registration of API modules.
 * New hook 'EnhancedChangesList::getLogText' to alter, remove or add to the
@@ -3596,8 +3688,8 @@ This is a bug fix release of the MediaWiki 1.25 branch.
   interface, reachable via IContextSource::getStats().
 * Move the jQuery Client library from being mastered in MediaWiki as v0.1.0 to a
   proper, published library, which is now tagged as v1.0.0.
-* A new message (defaulting to blank), 'editnotice-notext', can be shown to users
-  when they are editing if no edit notices apply to the page being edited.
+* A new message (defaulting to blank), 'editnotice-notext', can be shown to
+  users when they are editing if no edit notices apply to the page being edited.
 * (T94536) You can now make the sitenotice appear to logged-in users only by
   editing MediaWiki:Anonnotice and replacing its content with "". Setting it to
   "-" (default) will continue disable it and fallback to MediaWiki:Sitenotice.
@@ -3612,18 +3704,19 @@ This is a bug fix release of the MediaWiki 1.25 branch.
 ==== External libraries ====
 * MediaWiki now requires certain external libraries to be installed. In the past
   these were bundled inside the Git repository of MediaWiki core, but now they
-  need to be installed separately. For users using the tarball, this will be taken
-  care of and no action will be required. Users using Git will either need to use
-  composer to fetch dependencies or use the mediawiki/vendor repository which includes
-  all dependencies for MediaWiki core and ones used in Wikimedia deployment. Detailed
-  instructions can be found at:
+  need to be installed separately. For users using the tarball, this will be
+  taken care of and no action will be required. Users using Git will either need
+  to use composer to fetch dependencies or use the mediawiki/vendor repository
+  which includes all dependencies for MediaWiki core and ones used in Wikimedia
+  deployment. Detailed instructions can be found at:
   https://www.mediawiki.org/wiki/Download_from_Git#Fetch_external_libraries
 * The following libraries are now required:
 ** psr/log
-   This library provides the interfaces set by the PSR-3 standard (http://www.php-fig.org/psr/psr-3/)
-   which are used by MediaWiki internally via the
-   MediaWiki\Logger\LoggerFactory class.
-   See the structured logging RfC (https://www.mediawiki.org/wiki/Special:MyLanguage/Requests_for_comment/Structured_logging)
+   This library provides the interfaces set by the PSR-3 standard
+   (http://www.php-fig.org/psr/psr-3/) which are used by MediaWiki internally
+   via the MediaWiki\Logger\LoggerFactory class.
+   See the structured logging RfC
+   <https://www.mediawiki.org/wiki/Requests_for_comment/Structured_logging>
    for more background information.
 ** cssjanus/cssjanus
    This library was formerly bundled with MediaWiki core and has been removed.
@@ -3632,11 +3725,13 @@ This is a bug fix release of the MediaWiki 1.25 branch.
    This library was formerly bundled with MediaWiki core and has been removed.
    It compiles LESS files into CSS.
 ** wikimedia/cdb
-   This library was formerly a part of MediaWiki core, and has been moved into a separate library.
-   It provides CDB functions which are used in the Interwiki and Localization caches.
-   More information about the library can be found at https://www.mediawiki.org/wiki/Special:MyLanguage/CDB.
+   This library was formerly a part of MediaWiki core, and has been moved into a
+   separate library. It provides CDB functions which are used in the Interwiki
+   and Localization caches. More information about the library can be found at
+   https://www.mediawiki.org/wiki/CDB.
 ** liuggio/statsd-php-client
-   This library provides a StatsD client API for logging application metrics to a remote server.
+   This library provides a StatsD client API for logging application metrics to
+   a remote server.
 
 === Bug fixes in 1.25 ===
 * (T73003) No additional code will be generated to try to load CSS-embedded
@@ -3657,21 +3752,27 @@ This is a bug fix release of the MediaWiki 1.25 branch.
 * (T70361) Autocomments containing "/*" are parsed correctly.
 * The Special:WhatLinksHere page linked from 'Number of redirects to this page'
   on action=info about a file page does not list file links anymore.
-* (T78637) Search bar is not autofocused unless it is empty so that proper scrolling using arrow keys is possible.
-* (T50853) Database::makeList() modified to handle 'NULL' separately when building IN clause
+* (T78637) Search bar is not autofocused unless it is empty so that proper
+  scrolling using arrow keys is possible.
+* (T50853) Database::makeList() modified to handle 'NULL' separately when
+  building IN clause
 * (T85192) Captcha position modified in Usercreate template. As a result:
 ** extrafields parameter added to Usercreate.php to insert additional data
-** 'extend' method added to QuickTemplate to append additional values to any field of data array
+** 'extend' method added to QuickTemplate to append additional values to any
+  field of data array
 * (T86974) Several Title methods now load from the database when necessary
   (instead of returning incorrect results) even when the page ID is known.
-* (T74070) Duplicate search for archived files on file upload now omits the extension.
+* (T74070) Duplicate search for archived files on file upload now omits the
+  extension.
   This requires the fa_sha1 field being populated.
 * Removed rel="archives" from the "View history" link, as it did not pass
   HTML validation.
 * $wgUseTidy is now set when parserTests are run with the tidy option to match
   output on wiki.
-* (T37472) update.php will purge ResourceLoader cache unless --nopurge is passed to it.
-* (T72109) mediawiki.language should respect $wgTranslateNumerals in convertNumber().
+* (T37472) update.php will purge ResourceLoader cache unless --nopurge is passed
+  to it.
+* (T72109) mediawiki.language should respect $wgTranslateNumerals in
+  convertNumber().
 
 === Action API changes in 1.25 ===
 * (T67403) XML tag highlighting is now only performed for formats
@@ -3730,7 +3831,8 @@ This is a bug fix release of the MediaWiki 1.25 branch.
   log entry is not implemented yet.
 * list=tags has additional properties to indicate 'active' status and tag
   sources.
-* siprop=libraries was added to ApiQuerySiteInfo to list installed external libraries.
+* siprop=libraries was added to ApiQuerySiteInfo to list installed external
+  libraries.
 * (T88010) Added action=checktoken, to test a CSRF token's validity.
 * (T88010) Added intestactions to prop=info, to allow querying of
   Title::userCan() via the API.
@@ -3758,7 +3860,8 @@ This is a bug fix release of the MediaWiki 1.25 branch.
 * ApiHelp has been rewritten to support i18n and paginated HTML output.
   Most existing modules should continue working without changes, but should do
   the following:
-  * Add an i18n message "apihelp-{$moduleName}-description" to replace getDescription().
+  * Add an i18n message "apihelp-{$moduleName}-description" to replace
+    getDescription().
   * Add i18n messages "apihelp-{$moduleName}-param-{$param}" for each parameter
     to replace getParamDescription(). If necessary, the settings array returned
     by getParams() can use the new ApiBase::PARAM_HELP_MSG key to override the
@@ -3777,7 +3880,8 @@ This is a bug fix release of the MediaWiki 1.25 branch.
   has been removed.
 * ApiFormatBase now always buffers. Output is done when
   ApiFormatBase::closePrinter is called.
-* Much of the logic in ApiQueryRevisions has been split into ApiQueryRevisionsBase.
+* Much of the logic in ApiQueryRevisions has been split into
+  ApiQueryRevisionsBase.
 * The 'revids' parameter supplied by ApiPageSet will now count deleted
   revisions as "good" if the user has the 'deletedhistory' right. New methods
   ApiPageSet::getLiveRevisionIDs() and ApiPageSet::getDeletedRevisionIDs() are
@@ -3885,7 +3989,8 @@ changes to languages because of Bugzilla reports.
 * Removed XmlDumpWriter::schemaVersion(). (deprecated since 1.20)
 * Removed LogEventsList::getDisplayTitle(). (deprecated since 1.20)
 * Removed Preferences::trySetUserEmail(). (deprecated since 1.20)
-* Removed mw.user.name() and mw.user.anonymous() methods. (deprecated since 1.20)
+* Removed mw.user.name() and mw.user.anonymous() methods. (deprecated since
+  1.20)
 * Removed 'ok' and 'err' parameters in the mediawiki.api modules. (deprecated
   since 1.20)
 * Removed 'async' parameter from the  mw.Api#getCategories() method. (deprecated
@@ -3909,7 +4014,8 @@ changes to languages because of Bugzilla reports.
 * Deprecated the getInternalLinkAttributes, getInternalLinkAttributesObj,
   and getInternalLinkAttributes methods in Linker, and removed
   getExternalLinkAttributes method, which was deprecated in MediaWiki 1.18.
-* Removed Sites class, which was deprecated in 1.21 and replaced by SiteSQLStore.
+* Removed Sites class, which was deprecated in 1.21 and replaced by
+  SiteSQLStore.
 * Added wgRelevantArticleId to the client-side config, for use on special pages.
 * Deprecated the TitleIsCssOrJsPage hook. Superseded by the
   ContentHandlerDefaultModelFor hook since MediaWiki 1.21.
@@ -3943,7 +4049,8 @@ changes to languages because of Bugzilla reports.
       $form->setDisplayFormat( 'vform' ); // throws exception
     Instead, do this:
       $form = HTMLForm::factory( 'vform', … );
-* Deprecated Revision methods getRawUser(), getRawUserText() and getRawComment().
+* Deprecated Revision methods getRawUser(), getRawUserText() and
+  getRawComment().
 * BREAKING CHANGE: mediawiki.user.generateRandomSessionId:
   The alphabet of the prior string returned was A-Za-z0-9 and now it is 0-9A-F
 * (T87504) Avoid serving SVG background-images in CSS for Opera 12, which
@@ -3951,16 +4058,18 @@ changes to languages because of Bugzilla reports.
 * Removed maintenance script dumpSisterSites.php.
 * DatabaseBase class constructors must be called using the array argument style.
   Ideally, DatabaseBase:factory() should be used instead in most cases.
-* Deprecated ParserOutput::addSecondaryDataUpdate and ParserOutput::getSecondaryDataUpdates.
-  This is a hard deprecation, with getSecondaryDataUpdates returning an empty array and
-  addSecondaryDataUpdate throwing an exception. These functions will be removed in 1.26,
-  since they interfere with caching of ParserOutput objects.
-* Introduced new hook 'SecondaryDataUpdates' that allows extensions to inject custom updates.
-* Introduced new hook 'OpportunisticLinksUpdate' that allows extensions to perform
-  updates when a page is re-rendered.
+* Deprecated ParserOutput::addSecondaryDataUpdate and
+  ParserOutput::getSecondaryDataUpdates.
+  This is a hard deprecation, with getSecondaryDataUpdates returning an empty
+  array and addSecondaryDataUpdate throwing an exception. These functions will
+  be removed in 1.26, since they interfere with caching of ParserOutput objects.
+* Introduced new hook 'SecondaryDataUpdates' that allows extensions to inject
+  custom updates.
+* Introduced new hook 'OpportunisticLinksUpdate' that allows extensions to
+  perform updates when a page is re-rendered.
 * EditPage::attemptSave has been modified not to call handleStatus itself and
-  instead just returns the Status object. Extension calling it should be aware of
-  this.
+  instead just returns the Status object. Extension calling it should be aware
+  of this.
 * Removed class DBObject. (unused since 1.10)
 * wfDiff() is deprecated.
 * The -m (maximum replication lag) option of refreshLinks.php was removed.
@@ -3971,8 +4080,8 @@ changes to languages because of Bugzilla reports.
   retrievedfrom, thisisdeleted, viewsourcelink, lastmodifiedat, laggedslavemode,
   protect-summary-cascade
 * All BloomCache related code has been removed. This was largely experimental.
-* $wgResourceModuleSkinStyles no longer supports per-module local or remote paths. They
-  can only be set for the entire skin.
+* $wgResourceModuleSkinStyles no longer supports per-module local or remote
+  paths. They can only be set for the entire skin.
 * Removed global function swap(). (deprecated since 1.24)
 * Deprecated the ".php5" file extension entry points and the $wgScriptExtension
   configuration variable. Refer to the ".php" files instead. If you want
@@ -4130,30 +4239,33 @@ This is a security and maintenance release of the MediaWiki 1.24 branch.
 * $wgCompiledFiles has been removed.
 * $wgSortSpecialPages was removed, the listing on Special:SpecialPages is
   now always sorted.
-* $wgSpecialPages may now use callback functions as an alternative to plain class names.
-  This allows more control over constructor parameters.
+* $wgSpecialPages may now use callback functions as an alternative to plain
+  class names. This allows more control over constructor parameters.
 * $wgHTCPMulticastAddress, $wgHTCPMulticastRouting and $wgHTCPPort were removed.
 * $wgRC2UDPAddress, $wgRC2UDPInterwikiPrefix, $wgRC2UDPOmitBots, $wgRC2UDPPort
   and $wgRC2UDPPrefix have been removed.
 * The default password type for MediaWiki has been changed from MD5 to PBKDF2.
-  Password hashes will automatically be updated as users log in. If necessary, the
-  old MD5 hashing can be restored by changing $wgPasswordDefault to 'B'. In addition,
-  there is a maintenance script wrapOldPassword.php that can wrap all passwords in
-  PBKDF2 (or the hashing algorithm of your choice) if you don't want to wait for your
-  users to log in.
+  Password hashes will automatically be updated as users log in. If necessary,
+  the old MD5 hashing can be restored by changing $wgPasswordDefault to 'B'.
+  In addition, there is a maintenance script wrapOldPassword.php that can wrap
+  all passwords in PBKDF2 (or the hashing algorithm of your choice) if you don't
+  want to wait for your users to log in.
 * $wgImportSources can now either be a regular array, or an associative map
   specifying subprojects on the interwiki map of the target wiki, or a mix of
   the two. Existing configurations will still work.
-* Users must be able to edit through a page's protection to be able to delete it.
-* The default thumb size ($wgDefaultUserOptions['thumbsize']) is now 300px, up from
-  180px. If you have altered the number of entries in $wgThumbLimits for your wiki, you
-  may need to adjust your default user settings to compensate for the index change.
-* $wgDeferredUpdateList is now deprecated, you should use DeferredUpdates::addUpdate()
-  instead.
+* Users must be able to edit through a page's protection to be able to delete
+  it.
+* The default thumb size ($wgDefaultUserOptions['thumbsize']) is now 300px, up
+  from 180px. If you have altered the number of entries in $wgThumbLimits for
+  your wiki, you may need to adjust your default user settings to compensate for
+  the index change.
+* $wgDeferredUpdateList is now deprecated, you should use
+  DeferredUpdates::addUpdate() instead.
 * $wgCanonicalLanguageLinks has been removed. Per Google recommendations, we
   will not send a rel=canonical pointing to a variant-neutral page, however
   we will send rel=alternate.
-* $wgResourceLoaderLESSFunctions has been deprecated and will be removed in the future.
+* $wgResourceLoaderLESSFunctions has been deprecated and will be removed in the
+  future.
 * $wgGoToEdit has been removed. Use the SpecialSearchNogomatch hook for similar
   functionality.
 
@@ -4224,7 +4336,8 @@ This is a security and maintenance release of the MediaWiki 1.24 branch.
   specified for backwards-compatibility and to define the path Special:Version
   uses to find extension license information.
 * Browser tests are now included to verify basic wiki functionality in developer
-  environments. For details on running tests, see tests/browser/README.mediawiki.
+  environments. For details on running tests, see
+  tests/browser/README.mediawiki.
 * Upgrade jStorage to v0.4.10.
 * {{!}} is now a magic word that produces the | character. This removes the need
   for Template:! for purposes such as passing pipes inside of parameters.
@@ -4260,8 +4373,8 @@ This is a security and maintenance release of the MediaWiki 1.24 branch.
 * (bug 4488) There is now a preference to watch pages where the user has
   rollbacked an edit by default.
 * (bug 15484) Users will now be redirected to the login page when they need to
-  log in, rather than being shown a page asking them to log in and having to click
-  another link to actually get to the login page.
+  log in, rather than being shown a page asking them to log in and having to
+  click another link to actually get to the login page.
 * A JsonContent and JsonContentHandler were added for extensions to extend.
 * (bug 35045) Redirects to sections will now update the URL in browser's address
   bar using the HTML5 History API. When [[Dog]] redirects to [[Animals#Dog]],
@@ -4271,14 +4384,15 @@ This is a security and maintenance release of the MediaWiki 1.24 branch.
 * Added HTMLAutoCompleteSelectField.
 * Added a new hook, "SkinPreloadExistence", to allow extensions to add titles to
   link existence cache before the page is rendered.
-* Config::set() was moved to its own interface, MutableConfig. GlobalVarConfig::set()
-  is now deprecated, does not implement MutableConfig.
-* A MutableConfig named HashConfig was added, that stores an array of configuration
-  settings.
+* Config::set() was moved to its own interface, MutableConfig.
+  GlobalVarConfig::set() is now deprecated, does not implement MutableConfig.
+* A MutableConfig named HashConfig was added, that stores an array of
+  configuration settings.
 * (bug 69418) A MultiConfig implementation was added that supports fallback
   to multiple Config instances.
 * Update CSSJanus to v1.1.0.
-* Added FormatJson::parse() returning status with result or localized error message
+* Added FormatJson::parse() returning status with result or localized error
+  message
 * Added DeletedContribsPager::reallyDoQuery hook allowing extensions to data to
   Special:DeletedContributions
 * Added DeletedContributionsLineEnding hook allowing extensions to format
@@ -4382,14 +4496,15 @@ This is a security and maintenance release of the MediaWiki 1.24 branch.
   $wgAPIPropModules, and $wgAPIListModules settings) now allow API modules
   to be specified using a "module spec" array instead of a plain class name.
   A "module spec" is an associative array containing at least the 'class' key
-  for the module's class, and optionally a 'factory' key for the factory function
-  to use for the module. This is intended for extensions that want control over
-  the instantiation of their API modules, to allow for proper dependency
-  injection.
+  for the module's class, and optionally a 'factory' key for the factory
+  function to use for the module. This is intended for extensions that want
+  control over the instantiation of their API modules, to allow for proper
+  dependency injection.
 * A new param type 'submodule' is available. Parameters of this type will take
   the list of valid values from the module's ApiModuleManager for the group
   corresponding to the parameter name.
-* The 'APIGetPossibleErrors' and 'APIGetResultProperties' hooks are no longer used.
+* The 'APIGetPossibleErrors' and 'APIGetResultProperties' hooks are no longer
+  used.
 * API token handling has been rewritten. Any API module using tokens will need
   to be updated:
   * ApiBase::needsToken now returns a token type instead of boolean true when a
@@ -4545,7 +4660,8 @@ changes to languages because of Bugzilla reports.
   is unused by any modern extension.
 * Removed maintenance/nextJobDB.php; no longer in use.
 * Removed global function wfViewPrevNext(). (deprecated since 1.19)
-* Removed global function xmlsafe() from Export.php. (moved to OAIRepo extension)
+* Removed global function xmlsafe() from Export.php. (moved to OAIRepo
+  extension)
 * Removed Title::userCanRead(). (deprecated since 1.19)
 * Removed maintenance script importTextFile.php. Use edit.php script instead.
 * A _from_namespace field has been added to the templatelinks, pagelinks,
@@ -4556,13 +4672,13 @@ changes to languages because of Bugzilla reports.
   userNotLoggedInPage() from EditPage.php. (deprecated since 1.19)
 * Removed functions getContent(), getPreloadedText(), mergeChangesInto() and
   setPreloadedText() from EditPage.php. (deprecated since 1.21)
-* Removed global functions wfArrayLookup(), wfArrayMerge(), wfDebugDieBacktrace()
-  and wfTime(). (deprecated since 1.22)
+* Removed global functions wfArrayLookup(), wfArrayMerge(),
+  wfDebugDieBacktrace() and wfTime(). (deprecated since 1.22)
 * Browser support for Internet Explorer 6 and 7 lowered from Grade A to Grade C,
   meaning that JavaScript is no longer executed in these browser versions.
 * Browser support for Opera 11 lowered from Grade A to Grade C.
-* Removed IEFixes module which existed purely to provide support for MSIE versions
-  below 7 (conditionally loaded only for those browsers).
+* Removed IEFixes module which existed purely to provide support for MSIE
+  versions below 7 (conditionally loaded only for those browsers).
 * Deprecated SpecialPageFactory::getList() in favor of
   SpecialPageFactory::getNames()
 * Action::checkCanExecute() no longer has a return value.
@@ -4785,6 +4901,11 @@ of files that are no longer available follows.
 
 = MediaWiki 1.23 =
 
+== MediaWiki 1.23.17 ==
+
+=== Changes since 1.23.16 === <!--T:69-->
+* Fix syntax errors introduced in 1.23.16 when running PHP 5.3.
+
 == MediaWiki 1.23.16 ==
 This is a security and maintenance release of the MediaWiki 1.23 branch.
 
@@ -4795,21 +4916,21 @@ This is a security and maintenance release of the MediaWiki 1.23 branch.
 * Submitting the lgtoken and lgpassword parameters in the query string to
   action=login is now deprecated and outputs a warning. They should be submitted
   in the POST body instead.
-* (T109140) (T122209) SECURITY: Special:UserLogin and Special:Search allow redirect
-  to interwiki links.
+* (T109140) (T122209) SECURITY: Special:UserLogin and Special:Search allow
+  redirect to interwiki links.
 * (T144845) SECURITY: XSS in SearchHighlighter::highlightText() when
   $wgAdvancedSearchHighlighting is true.
 * (T125177) SECURITY: API parameters may now be marked as "sensitive" to keep
   their values out of the logs.
-* (T150044) SECURITY: "Mark all pages visited" on the watchlist now requires a CSRF
-  token.
+* (T150044) SECURITY: "Mark all pages visited" on the watchlist now requires a
+  CSRF token.
 * (T156184) SECURITY: Escape content model/format url parameter in message.
 * (T151735) SECURITY: SVG filter evasion using default attribute values in DTD
   declaration.
-* (T48143) SECURITY: Spam blacklist ineffective on encoded URLs inside file inclusion
-  syntax's link parameter.
-* (T108138) SECURITY: Sysops can undelete pages, although the page is protected against
-  it.
+* (T48143) SECURITY: Spam blacklist ineffective on encoded URLs inside file
+  inclusion syntax's link parameter.
+* (T108138) SECURITY: Sysops can undelete pages, although the page is protected
+  against it.
 
 == MediaWiki 1.23.15 ==
 
@@ -4828,7 +4949,8 @@ This is a maintenance release of the MediaWiki 1.23 branch.
 * (T129738) SECURITY: Make $wgBlockDisablesLogin also restrict logged in
   permissions
 * (T129738) SECURITY: Make blocks log users out if $wgBlockDisablesLogin is true
-* (T115333) SECURITY: Check read permission when loading page content in ApiParse
+* (T115333) SECURITY: Check read permission when loading page content in
+  ApiParse
 * Remove support for $wgWellFormedXml = false, all output is now well formed
 
 == MediaWiki 1.23.13 ==
@@ -5020,7 +5142,8 @@ This is a security and maintenance release of the MediaWiki 1.23 branch.
 
 * (bug 65839) SECURITY: Prevent external resources in SVG files.
 * (bug 67025) Special:Watchlist: Don't try to render empty row.
-* (bug 66922) Don't allow some E_NOTICE messages to end up in the LocalSettings.php.
+* (bug 66922) Don't allow some E_NOTICE messages to end up in the
+  LocalSettings.php.
 * (bug 66467) FileBackend: Avoid using popen() when "parallelize" is disabled.
 * (bug 66428) MimeMagic: Don't seek before BOF. This has weird side effects
   like only extracting the tail of the file partially or not at all.
@@ -5161,7 +5284,8 @@ This is a security and maintenance release of the MediaWiki 1.23 branch.
   buttons.
 * Special:UserLogin/signup now does AJAX checks for invalid and taken usernames,
   displaying the error live.
-* Added BaseTemplateAfterPortlet hook to allow injecting html after portlets in skins.
+* Added BaseTemplateAfterPortlet hook to allow injecting html after portlets in
+  skins.
 * Support has been added for a JSON based localisation file format. The
   installer has been updated to use it.
 * Changes to content typography (colors, line-height etc.). See
@@ -5170,11 +5294,12 @@ This is a security and maintenance release of the MediaWiki 1.23 branch.
   single icon (from nine). This should not affect local rules unless they were
   re-using these icons, which have now been deleted.
 * ResourceLoader: mw.loader.using() now implements a Promise interface.
-* Add new hook ChangesListInitRows accessed via ChangesList::initChangesListRows.
+* Add new hook ChangesListInitRows accessed via
+  ChangesList::initChangesListRows.
   If called by the ChangesList consumer this gives extensions a chance to batch
   process the result set prior to rendering.
-* A PoolCounterRedis class was added which can be make use of in $wgPoolCounterConf.
-  This requires at least one Redis 2.6+ server.
+* A PoolCounterRedis class was added which can be make use of in
+  $wgPoolCounterConf. This requires at least one Redis 2.6+ server.
 * $wgProfileToDatabase was removed. Set $wgProfiler to ProfilerSimpleDB
   in StartProfiler.php instead of using this.
 * (bug 63444) Made it possible to change the indent string (default: 4 spaces)
@@ -5546,28 +5671,43 @@ This is a maintenance release of the MediaWiki 1.22 branch.
 This is a security release of the MediaWiki 1.22 branch.
 
 === Changes since 1.22.11 ===
-* (bug 70672) SECURITY: OutputPage: Remove separation of css and js module allowance.
+* (bug 70672) SECURITY: OutputPage: Remove separation of css and js module
+  allowance.
 
 == MediaWiki 1.22.11 ==
 This is a security release of the MediaWiki 1.22 branch.
 
 === Changes since 1.22.10 ===
-* (bug 69008) SECURITY: Enhance CSS filtering in SVG files. Filter <style> elements; normalize style elements and attributes before filtering; add checks for attributes that contain css; add unit tests for html5sec and reported bugs.
+* (bug 69008) SECURITY: Enhance CSS filtering in SVG files. Filter <style>
+  elements; normalize style elements and attributes before filtering; add checks
+  for attributes that contain css; add unit tests for html5sec and reported
+  bugs.
 
 == MediaWiki 1.22.10 ==
 This is a maintenance release of the MediaWiki 1.22 branch.
 
 === Changes since 1.22.9 ===
 * (bug 64970) Fix support for blobs on DatabaseOracle::update
-* (bug 60719) In MediaWiki 1.22, the job queue execution on each page request was changed (Gerrit change 59797) so, instead of executing the job inside the same PHP process that's rendering the page, a new PHP cli command is spawned to execute runJobs.php in the background. It will only work if $wgPhpCli is set to an actual path or safe mode is off, otherwise, the old method will be used. https://www.mediawiki.org/wiki/Manual:Job_queue#Changes_introduced_in_MediaWiki_1.22 for more information. This change was in earlier releases of 1.22 but was not noted here until now.
+* (bug 60719) In MediaWiki 1.22, the job queue execution on each page request
+  was changed (Gerrit change 59797) so, instead of executing the job inside the
+  same PHP process that's rendering the page, a new PHP cli command is spawned
+  to execute runJobs.php in the background. It will only work if $wgPhpCli is
+  set to an actual path or safe mode is off, otherwise, the old method will be
+  used. See
+  https://www.mediawiki.org/wiki/Manual:Job_queue#Changes_in_MediaWiki_1.22
+  for more information. This change was in earlier releases of 1.22 but was not
+  noted here until now.
 
 == MediaWiki 1.22.9 ==
 This is a security and maintenance release of the MediaWiki 1.22 branch.
 
 === Changes since 1.22.8 ===
 * (bug 68187) SECURITY: Prepend jsonp callback with comment.
-* (bug 66608) SECURITY: Fix for XSS issue in bug 66608: Generate the URL used for loading a new page in Javascript,instead of relying on the URL in the link that has been clicked.
-* (bug 65778) SECURITY: Copy prevent-clickjacking between OutputPage and ParserOutput.
+* (bug 66608) SECURITY: Fix for XSS issue in bug 66608: Generate the URL used
+  for loading a new page in Javascript,instead of relying on the URL in the
+  link that has been clicked.
+* (bug 65778) SECURITY: Copy prevent-clickjacking between OutputPage and
+  ParserOutput.
 * (bug 59147) The img_metadata field was not being decoded from bytea into text.
 
 == MediaWiki 1.22.8 ==
@@ -5575,16 +5715,24 @@ This is a security and maintenance release of the MediaWiki 1.22 branch.
 
 === Changes since 1.22.7 ===
 * (bug 65839) SECURITY: Prevent external resources in SVG files.
-* (bug 66428) MimeMagic: Don't seek before BOF. This has weird side effects like only extracting the tail of the file partially or not at all.
+* (bug 66428) MimeMagic: Don't seek before BOF. This has weird side effects like
+  only extracting the tail of the file partially or not at all.
 
 == MediaWiki 1.22.7 ==
 This is a security and maintenance release of the MediaWiki 1.22 branch.
 
 === Changes since 1.22.6 ===
-* (bug 65501) SECURITY: Don't parse usernames as wikitext on Special:PasswordReset.
+* (bug 65501) SECURITY: Don't parse usernames as wikitext on
+  Special:PasswordReset.
 * (bug 36356) Add space between two feed links.
-* (bug 63269) Email notifications were not correctly handling the MediaWiki:Helppage message being set to a full URL. This is a regression from the 1.22.5 point release, which made the default value for it a URL. If you customized MediaWiki:Enotif body (the text of email notifications), you'll need to edit it locally to include the URL via the new variable $HELPPAGE instead of the parser functions fullurl and canonicalurl; otherwise you don't have to do anything.
-Add missing uploadstash.us_props for PostgreSQL.
+* (bug 63269) Email notifications were not correctly handling the
+  MediaWiki:Helppage message being set to a full URL. This is a regression from
+  the 1.22.5 point release, which made the default value for it a URL. If you
+  customized MediaWiki:Enotif body (the text of email notifications), you'll
+  need to edit it locally to include the URL via the new variable $HELPPAGE
+  instead of the parser functions fullurl and canonicalurl; otherwise you don't
+  have to do anything.
+* Add missing uploadstash.us_props for PostgreSQL.
 * (bug 56047) Fixed stream wrapper in PhpHttpRequest.
 
 == MediaWiki 1.22.6 ==
@@ -5602,8 +5750,17 @@ This is a security and maintenance release of the MediaWiki 1.22 branch.
 * Fix custom local MediaWiki:Helppage values.
 * mediawiki.js: Fix documentation breakage.
 * (bug 58153) Make MySQLi work with non standard port.
-* (bug 53887) Reintroduced a link to help pages in the default sidebar, that any sysop can customize by editing MediaWiki:Sidebar locally. The link now points to a mediawiki.org page which is guaranteed to exist. Nothing needs to be done on your end, but remember to adjust MediaWiki:Sidebar for the needs of your wikis. Everyone can help with the shared documentation by translating: https://www.mediawiki.org/wiki/Special:Translate/agg-Help_pages .
-* (bug 53888) Corrected a regression in 1.22 which introduced red links on the login page. If you previously installed 1.22.x and have created a local page to make the red link blue, write its title as in MediaWiki:helplogin-url if you didn't already. Otherwise, you don't need to do anything, but you can translate the help page at https://www.mediawiki.org/wiki/Help:Logging_in .
+* (bug 53887) Reintroduced a link to help pages in the default sidebar, that any
+  sysop can customize by editing MediaWiki:Sidebar locally. The link now points
+  to a mediawiki.org page which is guaranteed to exist. Nothing needs to be done
+  on your end, but remember to adjust MediaWiki:Sidebar for the needs of your
+  wikis. Everyone can help with the shared documentation by translating:
+  https://www.mediawiki.org/wiki/Special:Translate/agg-Help_pages .
+* (bug 53888) Corrected a regression in 1.22 which introduced red links on the
+  login page. If you previously installed 1.22.x and have created a local page
+  to make the red link blue, write its title as in MediaWiki:helplogin-url if
+  you didn't already. Otherwise, you don't need to do anything, but you can
+  translate the help page at <https://www.mediawiki.org/wiki/Help:Logging_in>.
 
 == MediaWiki 1.22.4 ==
 This is a maintenance release of the MediaWiki 1.22 branch.
@@ -5615,13 +5772,22 @@ This is a maintenance release of the MediaWiki 1.22 branch.
 This is a security and bugfix release of the MediaWiki 1.22 branch.
 
 === Changes since 1.22.2 ===
-* (bug 60771) SECURITY: Disallow uploading SVG files using non-whitelisted namespaces. Also disallow iframe elements. * User will get an error including the namespace name if they use a non- whitelisted namespace.
-* (bug 61346) SECURITY: Make token comparison use constant time. It seems like our token comparison would be vulnerable to timing attacks. This will take constant time.
+* (bug 60771) SECURITY: Disallow uploading SVG files using non-whitelisted
+  namespaces. Also disallow iframe elements. * User will get an error including
+  the namespace name if they use a non- whitelisted namespace.
+* (bug 61346) SECURITY: Make token comparison use constant time. It seems like
+  our token comparison would be vulnerable to timing attacks. This will take
+  constant time.
 * (bug 61362) SECURITY: API: Don't find links in the middle of api.php links.
-* (bug 53710) Add sequence support for upsert in DatabaseOracle in the same way as in selectInsert
-* (bug 60231, bug 58719) Various fixes to job running code in Wiki.php: Make it async on Windows. Fixed possible "invalid filename" errors on Windows. Redirect output to dev/null to avoid hanging PHP.
-* (bug 60083) Correct sequence name for fresh Postgres installation. Spotted by gebhkla
-* (bug 60531) Avoid variable naming conflicts in DatabasePostgres::selectSQLText. Spotted by gebhkla
+* (bug 53710) Add sequence support for upsert in DatabaseOracle in the same way
+  as in selectInsert
+* (bug 60231, bug 58719) Various fixes to job running code in Wiki.php: Make it
+  async on Windows. Fixed possible "invalid filename" errors on Windows.
+  Redirect output to dev/null to avoid hanging PHP.
+* (bug 60083) Correct sequence name for fresh Postgres installation. Spotted by
+  gebhkla
+* (bug 60531) Avoid variable naming conflicts in
+  DatabasePostgres::selectSQLText. Spotted by gebhkla
 * (bug 60094) Fix rebuildall.php fatal error with PostgreSQL.
 * (bug 43817) Add error handling if descriptionmsg isn't defined for extension.
 * (bug 60543) Special:PrefixIndex omits stripprefix=1 for "Next page" link.
@@ -5630,7 +5796,8 @@ This is a security and bugfix release of the MediaWiki 1.22 branch.
 This is a security and bugfix release of the MediaWiki 1.22 branch.
 
 === Changes since 1.22.1 ===
-* (bug 60339) SECURITY: Sanitize shell arguments to DjVu files, and other media formats
+* (bug 60339) SECURITY: Sanitize shell arguments to DjVu files, and other media
+  formats
 * (bug 58253) Check for very old PCRE versions in installer and updater
 * (bug 60054) Make WikiPage::$mPreparedEdit public
 
@@ -5644,10 +5811,17 @@ This is a security and maintenance release of the MediaWiki 1.22 branch.
 * (bug 58553) SECURITY: Return error on invalid XML for SVG Uploads
 * (bug 58699) SECURITY: Fix RevDel log entry information leaks
 * (bug 58178) Restore compatibility with curl < 7.16.2.
-* (bug 56931) Updated the plural rules to CLDR 24. They are in new format which is detailed in UTS 35 Rev 33. The PHP parser and evaluator as well as the JavaScript evaluator were updated to support the new format. Plural rules for some languages have changed, most notably Russian. Affected software messages have been updated and marked for review at translatewiki.net. This change is backported from the development branch of MediaWiki 1.23.
+* (bug 56931) Updated the plural rules to CLDR 24. They are in new format which
+  is detailed in UTS 35 Rev 33. The PHP parser and evaluator as well as the
+  JavaScript evaluator were updated to support the new format. Plural rules for
+  some languages have changed, most notably Russian. Affected software messages
+  have been updated and marked for review at translatewiki.net. This change is
+  backported from the development branch of MediaWiki 1.23.
 * (bug 58434) The broken installer for database backend Oracle was fixed.
-* (bug 58167) The web installer no longer throws an exception when PHP is compiled without support for MySQL yet with support for another DBMS.
-* (bug 58640) Fixed a compatibility issue with PCRE 8.34 that caused pages to appear blank or with missing text.
+* (bug 58167) The web installer no longer throws an exception when PHP is
+  compiled without support for MySQL yet with support for another DBMS.
+* (bug 58640) Fixed a compatibility issue with PCRE 8.34 that caused pages to
+  appear blank or with missing text.
 * (bug 47055) Changed FOR UPDATE handling in Postgresql
 * (bug 57026) Avoid extra parsing in prepareContentForEdit()
 
@@ -5660,17 +5834,21 @@ This is a security and maintenance release of the MediaWiki 1.22 branch.
 * $wgCascadingRestrictionLevels was added.
 * ftps, ssh, sftp, xmpp, sip, sips, tel, sms, bitcoin, magnet, urn, and geo
   have been whitelisted inside of $wgUrlProtocols.
-* $wgDocType and $wgDTD have been removed and are no longer used for the DOCTYPE.
-* $wgHtml5 is no longer used by core. Setting it to false will no longer disable HTML5.
-  It is still set to true for extension compatibility but doing so in extensions is deprecated.
-* $wgXhtmlDefaultNamespace is no longer used by core. Setting it will no longer change the
-  xmlns used by MediaWiki. Reliance on this variable by extensions is deprecated.
+* $wgDocType and $wgDTD have been removed and are no longer used for the
+  DOCTYPE.
+* $wgHtml5 is no longer used by core. Setting it to false will no longer disable
+  HTML5. It is still set to true for extension compatibility but doing so in
+  extensions is deprecated.
+* $wgXhtmlDefaultNamespace is no longer used by core. Setting it will no longer
+  change the xmlns used by MediaWiki. Reliance on this variable by extensions
+  is deprecated.
 * $wgHandheldStyle was removed.
 * $wgHandheldForIPhone was removed.
 * $wgJsMimeType is no longer used by core. Most usage has been removed since
   HTML output is now exclusively HTML5.
 * $wgDBOracleDRCP added. True enables persistent connection with DRCP on Oracle.
-* $wgLogAutopatrol added to allow disabling logging of autopatrol edits in the logging table.
+* $wgLogAutopatrol added to allow disabling logging of autopatrol edits in the
+  logging table.
   Default for $wgLogAutopatrol is true.
 * The 'edit' right no longer allows for editing a user's own CSS and JS.
 * New rights 'editmyusercss', 'editmyuserjs', 'viewmywatchlist',
@@ -5686,26 +5864,27 @@ This is a security and maintenance release of the MediaWiki 1.22 branch.
 * (bug 40866) wgOldChangeTagsIndex removed.
 * $wgNoFollowDomainExceptions now only matches entire domains. For example,
   an entry for 'bar.com' will still match 'foo.bar.com' but not 'foobar.com'.
-* $wgCopyUploadTimeout and $wgCopyUploadAsyncTimeout added to change the timeout times for
-  fetching the file during upload by url.
+* $wgCopyUploadTimeout and $wgCopyUploadAsyncTimeout added to change the timeout
+  times for fetching the file during upload by url.
 * New key added to $wgGalleryOptions - $wgGalleryOptions['mode'] to set
   default gallery mode.
 * New hook 'GalleryGetModes' to allow extensions to make new gallery modes.
-* The checkbox for staying in HTTPS displayed on the login form when $wgSecureLogin is
-  enabled has been removed. Instead, whether the user stays in HTTPS will be determined
+* The checkbox for staying in HTTPS displayed on the login form when
+  $wgSecureLogin is enabled has been removed. Instead, whether the user stays in
+  HTTPS will be determined
   based on the user's preferences, and whether they came from HTTPS or not.
 * $wgRC2UDPAddress, $wgRC2UDPInterwikiPrefix, $wgRC2UDPOmitBots, $wgRC2UDPPort,
   and $wgRC2UDPPrefix configuration options have been deprecated in favor of a
   $wgRCFeeds configuration array. $wgRCFeeds makes both the format and
   destination of recent change notifications customizable, and allows for
   multiple destinations to be specified.
-* (bug 53862) portal-url, currentevents-url and helppage have been removed from the
-  default Sidebar.
+* (bug 53862) portal-url, currentevents-url and helppage have been removed from
+  the default Sidebar.
 * The 'vector-simplesearch' preference is now enabled by default. Previously
   it was only enabled if the Vector extension was installed.
-* The precise format of metric datagrams produced by the UDP profiler and stats counter
-  may now be specified as $wgUDPProfilerFormatString and $wgStatsFormatString,
-  respectively.
+* The precise format of metric datagrams produced by the UDP profiler and stats
+  counter may now be specified as $wgUDPProfilerFormatString and
+  $wgStatsFormatString, respectively.
 * (bug 54597) $wgBlockOpenProxies, $wgProxyPorts, $wgProxyScriptPath, and
   $wgProxyMemcExpiry have been removed, along with the open proxy scanner
   script they were added for.
@@ -5714,7 +5893,8 @@ This is a security and maintenance release of the MediaWiki 1.22 branch.
 === New features in 1.22 ===
 * You can now install extensions using Composer.
   See https://www.mediawiki.org/wiki/Composer
-* (bug 44525) mediawiki.jqueryMsg can now parse (whitelisted) HTML elements and attributes.
+* (bug 44525) mediawiki.jqueryMsg can now parse (whitelisted) HTML elements and
+  attributes.
 * (bug 33454) Language::sprintfDate now has a timezone parameter, and supports
   the "eIOPTZ" formatting characters.
 * EditWarning: A warning is shown when an editor leaves the edit form without
@@ -5724,16 +5904,18 @@ This is a security and maintenance release of the MediaWiki 1.22 branch.
   version of the Vector extension as this feature may conflict.
 * New 'mediawiki.ui' CSS module providing mw-ui-* styles for buttons and a
   compact vertical form layout.
-* HTMLForm supports a new display format 'vform' which applies this compact vertical
+* HTMLForm supports a new display format 'vform' which applies this compact
+  vertical
   layout and button styling. Special:PasswordReset uses this format.
 * New versions of login (Special:UserLogin) and create account
-  (Special:UserLogin/signup) forms using the "vform" compact vertical form layout.
-  These forms use new messages that assume a "Help logging in" link, see
+  (Special:UserLogin/signup) forms using the "vform" compact vertical form
+  layout. These forms use new messages that assume a "Help logging in" link, see
   https://www.mediawiki.org/wiki/Manual:Page_customizations;
-  https://www.mediawiki.org/wiki/Account_creation_user_experience/Strings lists the
-  message key changes.
-* (bug 23343) Implemented ability to apply IP blocks to the contents of X-Forwarded-For headers
-  by adding a new configuration variable $wgApplyIpBlocksToXff (disabled by default).
+  https://www.mediawiki.org/wiki/Account_creation_user_experience/Strings lists
+  the message key changes.
+* (bug 23343) Implemented ability to apply IP blocks to the contents of
+  X-Forwarded-For headers by adding a new configuration variable
+  $wgApplyIpBlocksToXff (disabled by default).
 * The new hook 'APIGetPossibleErrors' to modify the list of possible errors was
   added.
 * (bug 25592) LogEventsList::showLogExtract() will now ignore various
@@ -5755,8 +5937,10 @@ This is a security and maintenance release of the MediaWiki 1.22 branch.
   well.
 * (bug 45535) introduced the new 'LanguageLinks' hook for manipulating the
   language links associated with a page before display.
-* Chosen (http://harvesthq.github.io/chosen/) was added as module 'jquery.chosen'
-* HTMLForm will turn multiselect checkboxes into a Chosen interface when setting cssclass 'mw-chosen'
+* Chosen (http://harvesthq.github.io/chosen/) was added as module
+  'jquery.chosen'
+* HTMLForm will turn multiselect checkboxes into a Chosen interface when setting
+  cssclass 'mw-chosen'
 * rebuildLocalisationCache learned --lang option. Let you rebuild l10n caches
   of the specified languages instead of all of them.
 * New GetNewMessagesAlert hook allowing extensions to disable or modify the new
@@ -5768,22 +5952,25 @@ This is a security and maintenance release of the MediaWiki 1.22 branch.
 * mediawiki.log: Added log.warn wrapper (uses console.warn and console.trace).
 * mediawiki.log: Implemented log.deprecate. This method defines a property and
   uses ES5 getter/setter to emit a warning when they are used.
-* $wgCascadingRestrictionLevels was added, allowing one to specify restriction levels
-  which can be cascading (previously 'sysop' was hard-coded as the only one).
-* XHTML5 support has been improved. If you set $wgMimeType = 'application/xhtml+xml'
-  MediaWiki will try outputting markup according to XHTML5 rules.
+* $wgCascadingRestrictionLevels was added, allowing one to specify restriction
+  levels which can be cascading (previously 'sysop' was hard-coded as the only
+  one).
+* XHTML5 support has been improved. If you set
+  $wgMimeType = 'application/xhtml+xml' MediaWiki will try outputting markup
+  according to XHTML5 rules.
 * Altered hook 'ProtectionForm::save', adding the reason page protection is
   changed as third parameter.
 * New hook 'TitleSquidURLs' for manipulating the list of URLs to be purged from
   HTTP caches when a page is changed.
-* Changed the patrolling system to always show the link for patrolling in case the
-  current revision is patrollable. This also removed the usage of the rcid URI parameters.
+* Changed the patrolling system to always show the link for patrolling in case
+  the current revision is patrollable. This also removed the usage of the rcid
+  URI parameters.
 * Oracle DB backend now supports Database Resident Connection Pooling (DRCP).
   Can be enabled by setting $wgDBOracleDRCP=true.
   Requires Oracle DB 11gR1 or above, enabled DRCP inside the DB itself and a
   propper connect string.
   More about DRCP can be found at:
-  http://www.oracle-base.com/articles/11g/database-resident-connection-pool-11gr1.php
+  https://oracle-base.com/articles/11g/database-resident-connection-pool-11gr1
 * Add a new parameter $patrolFooterShown to hook ArticleViewFooter so the hook
   handlers can take further action based on the status of the patrol footer
 * A new hook TitleQuickPermissions was added to allow overriding of quick
@@ -5836,8 +6023,8 @@ This is a security and maintenance release of the MediaWiki 1.22 branch.
   right?" check is used to avoid more expensive checks.
 * (bug 14431) Display "(No difference)" instead of an empty diff (when comparing
   revisions in the history or when previewing changes while editing).
-* New hook 'IsUploadAllowedFromUrl' is added which can be used to intercept uploads by
-  URL, useful for blacklisting specific URLs
+* New hook 'IsUploadAllowedFromUrl' is added which can be used to intercept
+  uploads by URL, useful for blacklisting specific URLs
 * (bug 21912) Watchlist token implementation has been refactored and
   Special:ResetTokens was added to allow users to reset their tokens
   instead of presenting them in Preferences.
@@ -5854,7 +6041,8 @@ This is a security and maintenance release of the MediaWiki 1.22 branch.
   too. Can be used whenever several multicast group could be interested by a
   specific purge.
 * (bug 25931) Add Special:RandomInCategory.
-* mediawiki.util: addPortletLink now supports passing a jQuery object as nextnode.
+* mediawiki.util: addPortletLink now supports passing a jQuery object as
+  nextnode.
 * <wbr> can now be used inside WikiText.
 * WebResponse::setcookie is much more featureful. Callers using PHP's
   setcookie() or setrawcookie() should begin using this instead.
@@ -5867,8 +6055,8 @@ This is a security and maintenance release of the MediaWiki 1.22 branch.
 * (bug 30607) Special:ListFiles can now show old versions of files. Additionally
   Special:AllMyUploads was introduced so the user can get a list of all things
   they have ever uploaded, even if it was subsequently overridden.
-* Introduced Special:MyFiles and Special:AllMyFiles as an alias for Special:MyUploads
-  and Special:AllMyUploads respectively.
+* Introduced Special:MyFiles and Special:AllMyFiles as an alias for
+  Special:MyUploads and Special:AllMyUploads respectively.
 * IPv6 addresses in X-Forwarded-For headers are now normalised before checking
   against allowed proxy lists.
 * Add deferrable update support for callback/closure.
@@ -5884,7 +6072,8 @@ This is a security and maintenance release of the MediaWiki 1.22 branch.
    declared for all LESS files. Additional variables may be registered by
    adding keys to the array.
 ** $wgResourceLoaderLESSFunctions is an associative array of custom LESS
-   function names to PHP callables. See <http://leafo.net/lessphp/docs/#custom_functions>
+   function names to PHP callables. See
+   <http://leafo.net/lessphp/docs/#custom_functions>
    for more details regarding custom functions.
 ** $wgResourceLoaderLESSImportPaths is an array of file system paths. Files
    referenced in LESS '@import' statements are looked up here first.
@@ -5895,16 +6084,16 @@ This is a security and maintenance release of the MediaWiki 1.22 branch.
   the output of the API query meta=siteinfo&siprop=statistics
 * Primary keys have been added to both the archive table and the externallinks
   tables.
-* Added $wgEnableParserLimitReporting to control whether the NewPP limit report is
-  output in a HTML comment.
+* Added $wgEnableParserLimitReporting to control whether the NewPP limit report
+  is output in a HTML comment.
 * The 'UnwatchArticle' and 'WatchArticle' hooks now support a Status object
   instead of just a boolean return value to abort the hook.
 * Added a hook, SpecialWatchlistGetNonRevisionTypes, to allow extensions
   with custom recentchanges entries to hook into the Watchlist without
   clobbering each other.
-* A hidden, empty input field was added to the edit form, and any edit that fills
-  it in will be rejected. This prevents against the simplest form of spambots.
-  Previously in the "SimpleAntiSpam" extension by Ryan Schmidt.
+* A hidden, empty input field was added to the edit form, and any edit that
+  fills it in will be rejected. This prevents against the simplest form of
+  spambots. Previously in the "SimpleAntiSpam" extension by Ryan Schmidt.
 * populateRevisionLength.php maintenance script updated to also populate
   archive.ar_len field.
 * (bug 43571) DatabaseMySQLBase learned to list views, optionally filtered by a
@@ -5926,7 +6115,8 @@ This is a security and maintenance release of the MediaWiki 1.22 branch.
 * Pager's properly validate which fields are allowed to be sorted on.
 * mw.util.tooltipAccessKeyRegexp: The regex now matches "option-" as well.
   Support for Mac "option" was added in 1.16, but the regex was never updated.
-* (bug 46768) Usernames of blocking users now display correctly, even if numeric.
+* (bug 46768) Usernames of blocking users now display correctly, even if
+  numeric.
 * (bug 39590) Self-transclusions now show the most up to date result always
   after save instead of being a revision behind.
 * A bias in wfRandomString() toward digits 1-7 has been corrected. Generated
@@ -5951,8 +6141,10 @@ This is a security and maintenance release of the MediaWiki 1.22 branch.
   warning will instead be issued if 'title' is non-default, unless no props are
   requested.
 * Special:Recentchangeslinked will now include upload log entries
-* (bug 41281) Fixed ugly output if file size could not be extracted for multi-page media.
-* (bug 50315) list=logevents API module will now output log entries by anonymous users.
+* (bug 41281) Fixed ugly output if file size could not be extracted for
+  multi-page media.
+* (bug 50315) list=logevents API module will now output log entries by anonymous
+  users.
 * (bug 38911) Handle headers with rowspan in jquery.tablesorter
 * (bug 658) Converted the table of contents on wiki pages from <table> to <div>
   and adjusted skin CSS accordingly. The CSS was carefully crafted to be
@@ -6092,8 +6284,8 @@ changes to languages because of Bugzilla reports.
   part of the Nostalgia extension.
 * Event namespace used by jquery.makeCollapsible has been changed from
   'mw-collapse' to 'mw-collapsible' for consistency with the module name.
-* BREAKING CHANGE: The "ExternalAuth" authentication subsystem was removed, along
-  with its associated globals of $wgExternalAuthType, $wgExternalAuthConf,
+* BREAKING CHANGE: The "ExternalAuth" authentication subsystem was removed,
+  along with its associated globals of $wgExternalAuthType, $wgExternalAuthConf,
   $wgAutocreatePolicy and $wgAllowPrefChange. Affected users are encouraged to
   use AuthPlugin for external authentication/authorization needs.
 * The Quickbar feature of the legacy skin model and the last remnants of it
@@ -6121,8 +6313,9 @@ changes to languages because of Bugzilla reports.
 * (bug 40785) mediawiki.legacy.ajax has been marked as deprecated. The following
   properties now emit mw.log.warn when accessed: sajax_debug, sajax_init_object,
   sajax_do_call and wfSupportsAjax.
-* BREAKING CHANGE: meta keywords are no longer supported. A <meta name="keywords"
-  will no longer be output and OutputPage::addKeyword no longer exists.
+* BREAKING CHANGE: meta keywords are no longer supported. A
+  <meta name="keywords" will no longer be output and OutputPage::addKeyword no
+  longer exists.
 * Methods Title::userCanEditCssSubpage and Title::userCanEditJsSubpage,
   deprecated since 1.19, have been removed.
 * (bug 50134) Hook functions are no longer required to return a value. When a
@@ -6159,23 +6352,24 @@ changes to languages because of Bugzilla reports.
   35981).
 * BREAKING CHANGE: The 'mediawiki.legacy.wikiprintable' module has been removed.
   The skins/common/wikiprintable.css file no longer exists. Return value of
-  Skin#commonPrintStylesheet is ignored. Please use the 'mediawiki.legacy.commonPrint'
-  module instead or base your skin on SkinTemplate.
+  Skin#commonPrintStylesheet is ignored. Please use the
+  'mediawiki.legacy.commonPrint' module instead or base your skin on
+  SkinTemplate.
 * (bug 49629) The hook ExtractThumbParameters has been deprecated in favour
   of media handler overriding MediaHandler::parseParamString.
-* (bug 46512) The collapsibleNav feature from the Vector extension has been moved
-  to the Vector skin in core.
+* (bug 46512) The collapsibleNav feature from the Vector extension has been
+  moved to the Vector skin in core.
 * SpecialRecentChanges::addRecentChangesJS() function has been renamed
   to addModules() and made protected.
 * Methods WatchAction::doWatch and WatchAction::doUnwatch now return a Status
   object instead of a boolean.
 * Information boxes (CSS classes errorbox, warningbox, successbox) have been
   made more subtle.
-* BREAKING CHANGE: The module 'mediawiki.legacy.IEFixes' has been removed as it was
-  unused. The file skins/common/IEFixes.js remains but is only used by wikibits.
-  The file never contained any re-usable components. To use it in a skin, load
-  'mediawiki.legacy.wikibits' (which IEFixes depends on) and that will import
-  IEFixes automatically if user agent conditions are met.
+* BREAKING CHANGE: The module 'mediawiki.legacy.IEFixes' has been removed as it
+  was unused. The file skins/common/IEFixes.js remains but is only used by
+  wikibits. The file never contained any re-usable components. To use it in a
+  skin, load 'mediawiki.legacy.wikibits' (which IEFixes depends on) and that
+  will import IEFixes automatically if user agent conditions are met.
 * Code specific to the Math extension was marked as deprecated.
 * mediawiki.util: mw.util.wikiGetlink has been renamed to getUrl. (The old name
   still works, but is deprecated.)
@@ -6187,13 +6381,15 @@ This is a security and maintenance release of the MediaWiki 1.21 branch.
 
 === Changes since 1.21.10 ===
 * (bug 65839) SECURITY: Prevent external resources in SVG files.
-* (bug 66428) MimeMagic: Don't seek before BOF. This has weird side effects like only extracting the tail of the file partially or not at all.
+* (bug 66428) MimeMagic: Don't seek before BOF. This has weird side effects like
+  only extracting the tail of the file partially or not at all.
 
 == MediaWiki 1.21.10 ==
 This is a security and maintenance release of the MediaWiki 1.21 branch.
 
 === Changes since 1.21.9 ===
-* (bug 65501) SECURITY: Don't parse usernames as wikitext on Special:PasswordReset.
+* (bug 65501) SECURITY: Don't parse usernames as wikitext on
+  Special:PasswordReset.
 * (bug 36356) Add space between two feed links.
 
 == MediaWiki 1.21.9 ==
@@ -6201,7 +6397,8 @@ This is a security and maintenance release of the MediaWiki 1.21 branch.
 
 === Changes since 1.21.8 ===
 * (bug 63251) SECURITY: Escape sortKey in pageInfo.
-* (bug 58640) Fixed a compatibility issue with PCRE 8.34 that caused pages to appear blank or with missing text.
+* (bug 58640) Fixed a compatibility issue with PCRE 8.34 that caused pages to
+  appear blank or with missing text.
 
 == MediaWiki 1.21.8 ==
 This is a security and maintenance release of the MediaWiki 1.21 branch.
@@ -6220,15 +6417,21 @@ This is a maintenance release of the MediaWiki 1.21 branch.
 This is a security release of the MediaWiki 1.21 branch.
 
 === Changes since 1.21.5 ===
-* (bug 60771) SECURITY: Disallow uploading SVG files using non-whitelisted namespaces. Also disallow iframe elements. * User will get an error including the namespace name if they use a non- whitelisted namespace.
-* (bug 61346) SECURITY: Make token comparison use constant time. It seems like our token comparison would be vulnerable to timing attacks. This will take constant time.
+* (bug 60771) SECURITY: Disallow uploading SVG files using non-whitelisted
+  namespaces. Also disallow iframe elements.
+* User will get an error including the namespace name if they use a
+  non-whitelisted namespace.
+* (bug 61346) SECURITY: Make token comparison use constant time. It seems like
+  our token comparison would be vulnerable to timing attacks. This will take
+  constant time.
 * (bug 61362) SECURITY: API: Don't find links in the middle of api.php links.
 
 == MediaWiki 1.21.5 ==
 This is a security release of the MediaWiki 1.21 branch.
 
 === Changes since 1.21.4 ===
-* (bug 60339) SECURITY: Sanitize shell arguments to DjVu files, and other media formats
+* (bug 60339) SECURITY: Sanitize shell arguments to DjVu files, and other media
+  formats
 
 == MediaWiki 1.21.4 ==
 This is a security release of the MediaWiki 1.21 branch.
@@ -6255,16 +6458,19 @@ This is a security and maintenance release of the MediaWiki 1.21 branch.
 
 === Changes since 1.21.1 ===
 * SECURITY: Fix extension detection with 2 .'s
-* SECURITY: Support for the 'gettoken' parameter to action=block and action=unblock, deprecated since 1.20, has been removed.
+* SECURITY: Support for the 'gettoken' parameter to action=block and
+  action=unblock, deprecated since 1.20, has been removed.
 * SECURITY: Sanitize ResourceLoader exception messages
 * Purge upstream caches when deleting file assets.
-* Unit test suite now runs the AutoLoader tests. Also fixed the autoloading entry for the PageORMTableForTesting class though it had no impact.
+* Unit test suite now runs the AutoLoader tests. Also fixed the autoloading
+  entry for the PageORMTableForTesting class though it had no impact.
 
 == MediaWiki 1.21.1 ==
 This is a maintenance release of the MediaWiki 1.21 branch.
 
 === Changes since 1.21.0 ===
-* An incorrect version number was used for 1.21.0. 1.21.1 has the correct number.
+* An incorrect version number was used for 1.21.0. 1.21.1 has the correct
+  number.
 * A problem with the Oracle SQL table creation was fixed.
 * (PdfHandler extension) Fix warning if pdfinfo fails but pdftext succeeds.
 
@@ -6366,7 +6572,8 @@ This is a maintenance release of the MediaWiki 1.21 branch.
 * maintenance/sql.php learned the --cluster option. Let you run the script
   on some external cluster instead of the primary cluster for a given wiki.
 * (bug 20281) test the parsing of inline URLs.
-* Added Special:PagesWithProp, which lists pages using a particular page property.
+* Added Special:PagesWithProp, which lists pages using a particular page
+  property.
 * Implemented language-specific collations for category sorting for 67 languages
   based in latin, greek and cyrillic alphabets. This allows one to *finally* get
   articles to be correctly sorted on category pages. They are named
@@ -6447,7 +6654,8 @@ This is a maintenance release of the MediaWiki 1.21 branch.
 * (bug 43379) Gracefully fail if rev_len is unavailable for a revision on the
   History page.
 * (bug 42949) API no longer assumes all exceptions are MWException.
-* (bug 41733) Hide "New user message" (.usermessage) element from printable view.
+* (bug 41733) Hide "New user message" (.usermessage) element from printable
+  view.
 * (bug 39062) Special:Contributions will display changes that don't have
   a parent id instead of just an empty bullet item.
 * (bug 37209) "LinkCache doesn't currently know about this title" error fixed.
@@ -6465,7 +6673,8 @@ This is a maintenance release of the MediaWiki 1.21 branch.
   extensions) performed using Git 1.7.8+ should now appear.
 * (bug 42184) $wgUploadSizeWarning missing second variable
 * (bug 40326) Check if files exist with a different extension during uploading
-* (bug 34798) Updated CSS for Atom/RSS recent changes feeds to match on-wiki diffs.
+* (bug 34798) Updated CSS for Atom/RSS recent changes feeds to match on-wiki
+  diffs.
 * (bug 42430) Calling numRows on MySQL no longer propagates unrelated errors.
 * (bug 44719) Removed mention of non-existing maintenance/migrateCurStubs.php
   script in includes/DefaultSettings.php
@@ -6479,13 +6688,14 @@ This is a maintenance release of the MediaWiki 1.21 branch.
 * action=edit and action=parse now support contentmodel and contentformat
   parameters to control the interpretation of page content.
   See docs/contenthandler.txt for details.
-* (bug 35693) ApiQueryImageInfo now suppresses errors when unserializing metadata.
+* (bug 35693) ApiQueryImageInfo now suppresses errors when unserializing
+  metadata.
 * (bug 40111) Disable minor edit for page/section creation by API.
 * (bug 41042) Revert change to action=parse&page=... behavior when the page
   does not exist.
 * (bug 27202) Add timestamp sort to list=allimages.
-* (bug 43137) Don't return the sha1 of revisions through the API if the content is
-  revision-deleted.
+* (bug 43137) Don't return the sha1 of revisions through the API if the content
+  is revision-deleted.
 * ApiQueryImageInfo now also returns imageinfo for redirects.
 * list=alltransclusions added to enumerate every instance of page embedding
 * list=alllinks & alltransclusions now allow both 'from' and 'continue' in
@@ -6507,14 +6717,16 @@ This is a maintenance release of the MediaWiki 1.21 branch.
   a redirect and its target.
 * (bug 43849) ApiQueryImageInfo no longer throws exceptions with ForeignDBRepo
   redirects.
-* On error, any warnings generated before that error will be shown in the result.
-* action=help supports generalized submodules (modules=query+value), querymodules obsolete
+* On error, any warnings generated before that error will be shown in the
+  result.
+* action=help supports generalized submodules (modules=query+value),
+  querymodules obsolete
 * ApiQueryImageInfo continuation is more reliable. The only major change is
   that the imagerepository property will no longer be set on page objects not
   processed in the current query (i.e. non-images or those skipped due to
   iicontinue).
-* Add supports for all pageset capabilities - generators, redirects, converttitles to
-  action=purge and action=setnotificationtimestamp.
+* Add supports for all pageset capabilities - generators, redirects,
+  converttitles to action=purge and action=setnotificationtimestamp.
 * (bug 43251) prop=pageprops&ppprop= now accepts multiple props to query.
 * ApiQueryImageInfo will now limit the number of calls to File::transform made
   in any one query. If there are too many, iicontinue will be returned.
@@ -6528,7 +6740,8 @@ This is a maintenance release of the MediaWiki 1.21 branch.
   HTTP OPTIONS request.
 * (bug 44923) action=upload works correctly if the entire file is uploaded in
   the first chunk.
-* Added 'continue=' parameter to streamline client iteration over complex query results
+* Added 'continue=' parameter to streamline client iteration over complex query
+  results
 * (bug 44909) API parameters may now be marked as type "upload", which is now
   used for action=upload's 'file' and 'chunk' parameters. This type will raise
   an error during parameter validation if the parameter is given but not
@@ -6545,15 +6758,20 @@ This is a maintenance release of the MediaWiki 1.21 branch.
   longer be), and will no longer choke on booleans.
 
 === API internal changes in 1.21 ===
-* For debugging only, a new global $wgDebugAPI removes many API restrictions when true.
+* For debugging only, a new global $wgDebugAPI removes many API restrictions
+  when true.
   Never use on the production servers, as this flag introduces security holes.
   Whenever enabled, a warning will also be added to all output.
-* ApiModuleManager now handles all submodules (actions,props,lists) and instantiation
+* ApiModuleManager now handles all submodules (actions,props,lists) and
+  instantiation
 * Query stores prop/list/meta as submodules
-* ApiPageSet can now be used in any action to process titles/pageids/revids or any generator.
-* BREAKING CHANGE: ApiPageSet constructor now has two params instead of three, with only the
-  first one keeping its meaning. ApiPageSet is now derived from ApiBase.
-* BREAKING CHANGE: ApiQuery::newGenerator() and executeGeneratorModule() were deleted.
+* ApiPageSet can now be used in any action to process titles/pageids/revids or
+  any generator.
+* BREAKING CHANGE: ApiPageSet constructor now has two params instead of three,
+  with only the first one keeping its meaning. ApiPageSet is now derived from
+  ApiBase.
+* BREAKING CHANGE: ApiQuery::newGenerator() and executeGeneratorModule() were
+  deleted.
 * ApiQueryGeneratorBase::setGeneratorMode() now requires a pageset param.
 * $wgAPIGeneratorModules is now obsolete and will be ignored.
 * Added flags ApiResult::OVERRIDE and ADD_ON_TOP to setElement() and addValue()
@@ -6581,7 +6799,8 @@ changes to languages because of Bugzilla reports.
   were using it, you have to either copy it to your extension, or install the
   Vector extension (and possibly disable its features using config settings if
   you don't want them).
-* Experimental IBM DB2 support was removed due to lack of interest and maintainership
+* Experimental IBM DB2 support was removed due to lack of interest and
+  maintainership
 * BREAKING CHANGE: Filenames of maintenance scripts were standardized into
   lowerCamelCase format, and made more explicit:
   - clear_stats.php -> clearCacheStats.php
@@ -6623,8 +6842,10 @@ This is a security release of the MediaWiki 1.20 branch.
 This is a security and maintenance release of the MediaWiki 1.20 branch.
 
 === Changes since 1.20.5 ===
-* (bug 48306) SECURITY: Run file validation checks on chunked uploads, and chunks of upload, during the upload process.
-* (bug 44327) mediawiki.user: Use session ID instead of 1-year cross-session cookies
+* (bug 48306) SECURITY: Run file validation checks on chunked uploads, and
+  chunks of upload, during the upload process.
+* (bug 44327) mediawiki.user: Use session ID instead of 1-year cross-session
+  cookies
 * (bug 47202) wikibits: FF2Fixes.css should not be loaded in Firefox 20.
 * (bug 31044) Make ResourceLoader behave in read-only mode
 
@@ -6652,14 +6873,17 @@ This is a security release of the MediaWiki 1.20 branch.
 This is a security and maintenance release of the MediaWiki 1.20 branch.
 
 === Changes since MediaWiki 1.20.2 ===
-* New preference type - 'api'. Preferences of this type are not shown on Special:Preferences, but are still available via the action=options API. (Unbreaks MLEB.)
+* New preference type - 'api'. Preferences of this type are not shown on
+  Special:Preferences, but are still available via the action=options API.
+  (Unbreaks MLEB.)
 * (bug 44010) Context is passed to UserGetLanguageObject.
 * The recursion guard on RequestContext::getLanguage() was weakened.
 * (bug 40585) Don't drop 'step="any"' in HTML input fields.
 * (bug 44024) Fixed problems in ObjectCache when using XCache.
 * (bug 44010) FauxRequest leaked cookie data from primary request.
 * (bug 44135/bug 42441) Pass '2' instead of 'true' to CURLOPT_SSL_VERIFYHOST
-* (bug 43518) API action=unblock should return the user name, not the full user object
+* (bug 43518) API action=unblock should return the user name, not the full user
+  object
 * (bug 45355) Prevent read of arbitrary files through mwdoc-filter.php
 
 == MediaWiki 1.20.2 ==
@@ -6667,7 +6891,9 @@ This is a maintenance release of the MediaWiki 1.20 branch
 
 === Changes since MediaWiki 1.20.1 ===
 * (bug 42638) Fix API action=options&reset=1 & unit tests.
-* (bug 42370) Fixed backport of 60cc060 to use mDoneWrites — caused * (bug 42592) User rights, preferences and other things are not saving in 1.20.1.
+* (bug 42370) Fixed backport of 60cc060 to use mDoneWrites — caused
+* (bug 42592) User rights, preferences and other things are not saving in
+  1.20.1.
 
 == MediaWiki 1.20.1 ==
 This is a security release of the MediaWiki 1.20 branch
@@ -6689,51 +6915,59 @@ upgrade PHP if you have not done so prior to upgrading MediaWiki.
 === Configuration changes in 1.20 ===
 * $wgGitRepositoryViewers defines a mapping from Git remote repository to the
   Gitweb instance URL used in Special:Version.
-* `$wgUsePathInfo = true;` is no longer needed to make $wgArticlePath work on servers
-  using like nginx, lighttpd, and apache over fastcgi. MediaWiki now always extracts
-  path info from REQUEST_URI if it's available.
+* `$wgUsePathInfo = true;` is no longer needed to make $wgArticlePath work on
+  servers using like nginx, lighttpd, and apache over fastcgi. MediaWiki now
+  always extracts path info from REQUEST_URI if it's available.
 * The user right 'upload_by_url' is no longer given to sysops by default.
   This only affects installations which have $wgAllowCopyUploads set to true.
 * Removed f-prot support from $wgAntivirusSetup.
 * New variable $wgDBerrorLogTZ to provide dates in the error log in a
   different timezone than the wiki timezone set by $wgLocaltimezone.
-* New variables $wgDBssl and $wgDBcompress to enable SSL and compression for database
-  connections, if either are available for the selected DB type.
-* $wgUseCombinedLoginLink now defaults to false, making MediaWiki output separate
-  login and create account links by default.
+* New variables $wgDBssl and $wgDBcompress to enable SSL and compression for
+  database connections, if either are available for the selected DB type.
+* $wgUseCombinedLoginLink now defaults to false, making MediaWiki output
+  separate login and create account links by default.
 
 === New features in 1.20 ===
-* Added TitleIsAlwaysKnown hook which gets called when determining if a page exists.
+* Added TitleIsAlwaysKnown hook which gets called when determining if a page
+  exists.
 * Added NamespaceIsMovable hook which gets called when determining if pages in a
   certain namespace can be moved.
-* Added SpecialPageBeforeExecute hook which gets called before SpecialPage::execute.
-* Added SpecialPageAfterExecute hook which gets called after SpecialPage::execute.
+* Added SpecialPageBeforeExecute hook which gets called before
+  SpecialPage::execute.
+* Added SpecialPageAfterExecute hook which gets called after
+  SpecialPage::execute.
 * Added ORMTable, ORMRow and ORMResult classes for additional abstraction of
   database interaction.
-* Added CacheHelper and associated SpecialCachedPage and CachedAction helper classes.
+* Added CacheHelper and associated SpecialCachedPage and CachedAction helper
+  classes.
 * (bug 32341) Add upload by URL domain limitation.
-* &useskin=default will now always display the default skin. Useful for users with a
-  preference for the non-default skin to look at something using the default skin.
+* &useskin=default will now always display the default skin. Useful for users
+  with a preference for the non-default skin to look at something using the
+  default skin.
 * (bug 27619) Remove preference option to display broken links as link?
 * (bug 34896) jQuery JSON plugin upgraded to v2.3 (2011-09-17).
 * (bug 34302) Add CSS classes to email fields in user preferences.
-* Introduced $wgDebugDBTransactions to trace transaction status (currently PostgreSQL only).
+* Introduced $wgDebugDBTransactions to trace transaction status (currently
+  PostgreSQL only).
 * (bug 23795) Add parser itself to ParserMakeImageParams hook.
 * Introduce a cryptographic random number generator source api for use when
   generating various tokens.
-* (bug 30963) Option on Special:Prefixindex and Special:Allpages to not show redirects.
+* (bug 30963) Option on Special:Prefixindex and Special:Allpages to not show
+  redirects.
 * (bug 18062) New message when edit or create the local page of a shared file.
 * (bug 22870) Separate interface message when creating a page.
 * (bug 17615) nosummary option should be reassigned on preview/captcha.
 * (bug 34355) Add a variable and parser function for the namespace number.
-* (bug 35649) Special:Version now shows hashes of extensions checked out from git.
+* (bug 35649) Special:Version now shows hashes of extensions checked out from
+  git.
 * (bug 35728) Git revisions are now linked on Special:Version.
 * "Show Changes" on default messages shows now diff against default message text
 * (bug 23006) create #speciale parser function.
 * generateSitemap can now optionally skip redirect pages.
 * (bug 27757) New API command just for retrieving tokens (not page-based).
-* Added GitViewers hook for extensions using external git repositories to have a web-based
-  repository viewer linked to from Special:Version.
+* Added GitViewers hook for extensions using external git repositories to have a
+  web-based repository viewer linked to from Special:Version.
 * Memcached debug logs can now be sent to their own file logs by setting
   $wgDebugLogFile['memcached'] to some filepath.
 * (bug 35685) api.php URL and other entry point URLs are now listed on
@@ -6749,15 +6983,17 @@ upgrade PHP if you have not done so prior to upgrading MediaWiki.
 * Added $wgLogExceptionBacktrace, on by default, to allow logging of exception
   backtraces.
 * Added device detection for determining device capabilities.
-* QUnit.newMwEnvironment now supports passing a custom setup and/or teardown function.
-  Arguments signature has changed. First arguments is now an options object of which
-  'config' can be a property. Previously 'config' itself was the first and only argument.
+* QUnit.newMwEnvironment now supports passing a custom setup and/or teardown
+  function. Arguments signature has changed. First arguments is now an options
+  object of which 'config' can be a property. Previously 'config' itself was the
+  first and only argument.
 * New getCreator and getOldestRevision methods added to WikiPage class
 * (bug 4220) the XML dump format schema now have unique identity constraints
   for page and revision identifiers. Patch by Elvis Stansvik.
-* cleanupSpam.php now can delete spam pages if --delete was specified instead of blanking
-  them.
-* Added new hook ChangePasswordForm to allow adding of additional fields in Special:ChangePassword
+* cleanupSpam.php now can delete spam pages if --delete was specified instead of
+  blanking them.
+* Added new hook ChangePasswordForm to allow adding of additional fields in
+  Special:ChangePassword
 * Added new function getDomain to AuthPlugin for getting a user's domain
 * (bug 23427) New magic word {{PAGEID}} which gives the current page ID.
   Will be null on previewing a page being created.
@@ -6767,21 +7003,23 @@ upgrade PHP if you have not done so prior to upgrading MediaWiki.
   tags with class "mw-watched". Instead, each line now has a class
   "mw-changeslist-line-watched" or "mw-changeslist-line-not-watched", and the
   title itself is surrounded by <span></span> tags with class "mw-title".
-* Added ContribsPager::reallyDoQuery hook allowing extensions to data to MyContribs
+* Added ContribsPager::reallyDoQuery hook allowing extensions to data to
+  MyContribs
 * Added new hook ParserAfterParse to allow extensions to affect parsed output
   after the parse is complete but before block level processing, link holder
   replacement, and so on.
-* (bug 34678) Added InternalParseBeforeSanitize hook which gets called during Parser's
-  internalParse method just before the parser removes unwanted/dangerous HTML tags.
-* Added new hook AfterFinalPageOutput to allow modifications to buffered page output before sent
-  to the client.
+* (bug 34678) Added InternalParseBeforeSanitize hook which gets called during
+  Parser's internalParse method just before the parser removes
+  unwanted/dangerous HTML tags.
+* Added new hook AfterFinalPageOutput to allow modifications to buffered page
+  output before sent to the client.
 * (bug 36783) Implement jQuery Promise interface in mediawiki.api module.
 * Make dates in sortable tables sort according to the page content language
   instead of the site content language
 * (bug 37926) Deleterevision will no longer allow users to delete log entries,
   the new deletelogentry permission is required for this.
-* (bug 14237) Allow PAGESINCATEGORY to distinguish between 'all', 'pages', 'files'
-  and 'subcats'
+* (bug 14237) Allow PAGESINCATEGORY to distinguish between 'all', 'pages',
+  'files' and 'subcats'
 * (bug 38362) Make Special:Listuser includeable on wiki pages.
 * Added support in jquery.localize for placeholder attributes.
 * (bug 38151) Implemented mw.user.getRights for getting and caching the current
@@ -6798,12 +7036,15 @@ upgrade PHP if you have not done so prior to upgrading MediaWiki.
 * HTMLForm mutators can now be chained (they return $this)
 * A new message, "api-error-filetype-banned-type", is available for formatting
   API upload errors due to the file extension blacklist.
-* New hook 'ParserTestGlobals' allows to set globals before running parser tests.
+* New hook 'ParserTestGlobals' allows to set globals before running parser
+  tests.
 * Allow importing pages as subpage.
 * Add lang and hreflang attributes to language links on Login page.
 * (bug 22749) Create Special:MostInterwikis.
-* Show change tags when transclude Special:Recentchanges(linked) or Special:Newpages.
-* (bug 23226) Add |class= parameter to image links in order to add class(es) to HTML img tag.
+* Show change tags when transclude Special:Recentchanges(linked) or
+  Special:Newpages.
+* (bug 23226) Add |class= parameter to image links in order to add class(es) to
+  HTML img tag.
 * (bug 39431) SVG animated status is now shown in long description.
 * (bug 39376) jquery.form upgraded to 3.14.
 * SVG files will now show the actual width in the SVG's specified units
@@ -6811,10 +7052,11 @@ upgrade PHP if you have not done so prior to upgrading MediaWiki.
 * Added ResourceLoader module "jquery.jStorage" (v0.3.0, http://jStorage.info/).
 * (bug 39273) Added AJAX support for "Show changes" (diff) in LivePreview.
 * Added ResourceLoader module "jquery.badge".
-* mw.util.$content now points to the overall content area in the skin rather than just
-  page text content area. If you need the old behavior please use $( '#mw-content-text').
-* jsMessage has been replaced with a floating bubble notification system complete
-  with auto-hide, multi-message support, and message replacement tags.
+* mw.util.$content now points to the overall content area in the skin rather
+  than just page text content area. If you need the old behavior please use
+  $( '#mw-content-text').
+* jsMessage has been replaced with a floating bubble notification system
+  complete with auto-hide, multi-message support, and message replacement tags.
 * jquery.messageBox which appears to be unused by both core and extensions has
   been removed.
 * (bug 34939) Made link parsing insensitive ([HttP://]).
@@ -6833,12 +7075,14 @@ milestone in Bugzilla.
 * (bug 35894): Reports of secret key generation "hanging" on windows
     This is probably a bug that has been fixed in PHP.  If you run
     into this, try upgrading your PHP.
-* (bug 38334): PHP Notice:  Undefined index: href in /www/w/skins/Vector.php on line 416
+* (bug 38334): PHP Notice:  Undefined index: href in /www/w/skins/Vector.php on
+  line 416
     We think this is a problem in some extension.  If you see this,
     try disabling your extensions and check out the logging patch on
     this bug.  Or try this patch:
     <https://gerrit.wikimedia.org/r/#/c/27937/1/skins/Vector.php>
-* (bug 39268): [Regression] Toolbar inserts in main textarea only (instead of the focussed textarea)
+* (bug 39268): [Regression] Toolbar inserts in main textarea only (instead of
+  the focussed textarea)
     This should only be an issue if you are using the ProofreadPage
     extension.
 * (bug 40641): Clicking "others" in Special:Version asks to download a file
@@ -6846,8 +7090,10 @@ milestone in Bugzilla.
     CREDITS file with text/plain MIME type to fix it.
 
 === Bug fixes in 1.20 ===
-* (bug 40939): [Regression] InfoAction: Call to a member function getUserText() on a non-object
-* (bug 40780): searchsuggest-containing line ("containing...") doesn't include the entered text
+* (bug 40939): [Regression] InfoAction: Call to a member function getUserText()
+  on a non-object
+* (bug 40780): searchsuggest-containing line ("containing...") doesn't include
+  the entered text
 * (bug 37714): [Regression] Incomplete log entries
 * (bug 27202): API: Add timestamp sort to list=allimages
 * (bug 30245) Use the correct way to construct a log page title.
@@ -6856,14 +7102,17 @@ milestone in Bugzilla.
 * (bug 32210) New edit emails for watched pages always provide a link to the
   edit which triggered the mail.
 * (bug 12021) Added user talk link on Special:Listusers.
-* (bug 34445) section edit and TOC hide/show links are excluded from selection and
-  copy/paste on supporting browsers.
+* (bug 34445) section edit and TOC hide/show links are excluded from selection
+  and copy/paste on supporting browsers.
 * (bug 34428) Fixed incorrect hash mismatch errors in the DiffHistoryBlob
   history compression method.
 * (bug 34702) Localised parentheses are now used in more special pages.
-* (bug 34723) When editing a script page on a RTL wiki the textbox should be LTR.
-* (bug 34762) Calling close() on a DatabaseBase object now clears the connection.
-* (bug 34863) Show deletion log extract on non-existent file pages if applicable.
+* (bug 34723) When editing a script page on a RTL wiki the textbox should be
+  LTR.
+* (bug 34762) Calling close() on a DatabaseBase object now clears the
+  connection.
+* (bug 34863) Show deletion log extract on non-existent file pages if
+  applicable.
 * (bug 28019) Let ?preloadtitle=foo be passed on to target of
   Special:MyPage and Special:MyTalk.
 * (bug 34929) Show the correct diff when a section edit is rejected by the spam
@@ -6885,13 +7134,16 @@ milestone in Bugzilla.
   Subversion when invoked with the --modified option.
 * (bug 35069) On history pages, the " . . " separator after the number of
   characters changed in a revision is now suppressed if no text would follow.
-* (bug 18704) Add a unique CSS class or ID to the tagfilter table row at RecentChanges
+* (bug 18704) Add a unique CSS class or ID to the tagfilter table row at
+  RecentChanges
 * (bug 33564) transwiki import sometimes result in invalid title.
-* (bug 35572) Blocks appear to succeed even if query fails due to wrong DB structure
+* (bug 35572) Blocks appear to succeed even if query fails due to wrong DB
+  structure
 * (bug 31757) Add a word-separator between help-messages in HTMLForm
 * (bug 30410) Removed deprecated $wgFilterCallback and the 'filtered' API error.
 * (bug 32604) Some messages needs escaping of wikitext inside username.
-* (bug 36537) Rename wfArrayToCGI to wfArrayToCgi for consistency with wfCgiToArray.
+* (bug 36537) Rename wfArrayToCGI to wfArrayToCgi for consistency with
+  wfCgiToArray.
 * (bug 25946) The message on the top of Special:RecentChanges is now displayed
   in user language instead of content language.
 * (bug 35264) Wrong type used for <ns> in export.xsd
@@ -6926,8 +7178,8 @@ milestone in Bugzilla.
 * (bug 38953) --memory-limit switch not working for runJobs.php.
 * (bug 33037) Make subpage of Special:newfiles control how many files
   are returned, like in previous versions.
-* (bug 36524) "Show" options on Special:RecentChanges and Special:RecentChangesLinked
-  are now remembered between successive clicks.
+* (bug 36524) "Show" options on Special:RecentChanges and
+  Special:RecentChangesLinked are now remembered between successive clicks.
 * (bug 26069) Page title is no longer "Error" for all error pages.
 * (bug 39297) Show warning if thumbnail of animated image will not be animated.
 * (bug 38249) Parser will throw an exception instead of outputting gibberish if
@@ -6935,26 +7187,33 @@ milestone in Bugzilla.
 * (bug 30390) Suggested file name on Special:Upload should not contain
   illegal characters.
 * EXIF below sea level GPS altitude data is now shown correctly.
-* (bug 39284) jquery.tablesorter should not consider "."" or "?"" to be a currency.
-* (bug 39273) "Show changes" should not be incorrectly displayed in the Live Preview state.
+* (bug 39284) jquery.tablesorter should not consider "."" or "?"" to be a
+  currency.
+* (bug 39273) "Show changes" should not be incorrectly displayed in the Live
+  Preview state.
 * Made body-content lang attribute honor the variant language when it is set.
-* (bug 36761) "Mark pages as visited" now submits previously established filter options.
+* (bug 36761) "Mark pages as visited" now submits previously established filter
+  options.
 * (bug 39635) PostgreSQL LOCK IN SHARE MODE option is a syntax error.
-* (bug 36329) Accesskey tooltips for Firefox 14 on Mac should use "ctrl-option-" prefix.
+* (bug 36329) Accesskey tooltips for Firefox 14 on Mac should use "ctrl-option-"
+  prefix.
 * (bug 32552) Drop unused database field cat_hidden from table category.
 * (bug 24502) Do not allow multiple language links to the same language.
 * (bug 40214) Category pages no longer use deprecated "width" HTML attribute.
 * (bug 39941) Add missing stylesheets to the installer pages
 * In HTML5 mode, allow new input element types values (such as color, range..)
 * (bug 36151) mw.Title: Don't limit extension in title parsing.
-* (bug 38158) jquery.byteLimit sometimes causes an unexpected 0 maxLength being enforced.
-* (bug 38163) jquery.byteLimit incorrectly limits input when using methods other than
-  basic per-char typing.
+* (bug 38158) jquery.byteLimit sometimes causes an unexpected 0 maxLength being
+  enforced.
+* (bug 38163) jquery.byteLimit incorrectly limits input when using methods other
+  than basic per-char typing.
 * (bug 34495) patrol log now credit the user patrolling (instead of patrolled
   user).
 * (bug 31676) ResourceLoader should work around IE stylesheet limit.
-* (bug 40498) ResourceLoader should not output an empty "@media print { }" block.
-* (bug 40500) ResourceLoader should not ignore media-type for urls in debug mode.
+* (bug 40498) ResourceLoader should not output an empty "@media print { }"
+  block.
+* (bug 40500) ResourceLoader should not ignore media-type for urls in debug
+  mode.
 * (bug 40660) ResourceLoaderWikiModule should not convert "&nbsp;" to a space
   for pages from the MediaWiki-namespace.
 * (bug 40329) (bug 40632) Removed CleanupPresentationalAttributes feature.
@@ -6969,33 +7228,40 @@ milestone in Bugzilla.
 * (bug 32492) API now allows editing using pageid.
 * (bug 32497) API now allows changing of protection level using pageid.
 * (bug 32498) API now allows comparing pages using pageids.
-* (bug 30975) API import of pages with invalid characters in this wiki leads to Fatal Error.
-* (bug 30488) API now allows listing of backlinks/embeddedin/imageusage per pageid.
+* (bug 30975) API import of pages with invalid characters in this wiki leads to
+  Fatal Error.
+* (bug 30488) API now allows listing of backlinks/embeddedin/imageusage per
+  pageid.
 * (bug 34927) Output media_type for list=filearchive.
 * (bug 28814) add properties to output of action=parse.
 * (bug 33224) add variants of content language to meta=siteinfo.
-* (bug 32643) action=purge with forcelinkupdate no longer crashes when ratelimit is reached.
+* (bug 32643) action=purge with forcelinkupdate no longer crashes when ratelimit
+  is reached.
 * The paraminfo module now also contains result properties for most modules.
 * (bug 32348) Allow descending order for list=alllinks.
 * (bug 31777) Upload unknown error ``fileexists-forbidden''.
 * (bug 32382) Allow descending order for list=iwbacklinks.
-* (bug 32381) Allow descending order for list=backlinks, list=embeddedin and list=imageusage.
+* (bug 32381) Allow descending order for list=backlinks, list=embeddedin and
+  list=imageusage.
 * (bug 32383) Allow descending order for list=langbacklinks.
 * API meta=siteinfo can now return the list of known variable IDs.
-* (bug 35980) list=deletedrevs now honors drdir correctly in "all" mode (mode #3).
+* (bug 35980) list=deletedrevs now honors drdir correctly in "all" mode
+  (mode #3).
 * (bug 29290) API avoids mangling fields in continuation parameters
 * (bug 36987) API avoids mangling fields in continuation parameters
-* (bug 30836) siteinfo prop=specialpagealiases will no longer return nonexistent special pages
+* (bug 30836) siteinfo prop=specialpagealiases will no longer return nonexistent
+  special pages
 * (bug 38190) Add "required" flag to some token params for hint in api docs.
 * (bug 27567) Add file repo support to prop=duplicatefiles.
 * (bug 27610) Add archivename for non-latest image version to list=filearchive
 * (bug 38231) Add xml parse tree to action=parse.
-* Watchlist notification timestamp may be queried by page and may be updated via the API.
+* Watchlist notification timestamp may be queried by page and may be updated via
+  the API.
 * (bug 38904) prop=revisions&rvstart=... no longer blows up when continuing.
 * (bug 39032) ApiQuery generates help in constructor.
 * (bug 11142) Improve file extension blacklist error reporting in API upload.
-* (bug 39665) List of query generators is now not built using reflection, instead it is
-  defined in code.
+* (bug 39665) List of query generators is now not built using reflection,
+  instead it is defined in code.
 * (bug 35993) Deprecated gettoken parameter - support will be removed in 1.22.
 
 === Languages updated in 1.20 ===
@@ -7034,8 +7300,8 @@ changes to languages because of Bugzilla reports.
 * OutputPage::wrapWikiMsg() no longer supports the 'options' parameter. It was
   not used and complicated migration to Message class.
 * Live preview functionality has been improved and moved into the
- 'mediawiki.action.edit.preview' module. The old 'mediawiki.legacy.preview' module
-  has been removed.
+ 'mediawiki.action.edit.preview' module. The old 'mediawiki.legacy.preview'
+  module has been removed.
 * (bug 40448) Removed mediawiki.legacy.mwsuggest module, and removed the
   following that has become obsolete:
   - globals $wgEnableMWSuggest and $wgMWSuggestTemplate.
@@ -7044,52 +7310,111 @@ changes to languages because of Bugzilla reports.
 
 == MediaWiki 1.19 ==
 
+== MediaWiki 1.19.24 ==
+
+This is a security and maintenance release of the MediaWiki 1.19 branch.
+
+=== Changes since 1.19.23 ===
+
+* ({{bug|T85848}}, {{bug|T71210}}) SECURITY: Don't parse XMP blocks that
+contain XML entities, to prevent various DoS attacks.
+* ({{bug|T88310}}) SECURITY: Always expand xml entities when checking SVG's.
+* ({{bug|T73394}}) SECURITY: Escape > in Html::expandAttributes to prevent XSS.
+* ({{bug|T85855}}) SECURITY: Don't execute another user's CSS or JS on preview.
+* ({{bug|T85349}}, {{bug|T85850}}, {{bug|T86711}}) SECURITY: Multiple issues
+fixed in SVG filtering to prevent XSS and protect viewer's privacy.
+
+== MediaWiki 1.19.23 ==
+
+This is a security and maintenance release of the MediaWiki 1.19 branch.
+
+=== Changes since 1.19.22 ===
+
+* (bug T76686) [SECURITY] thumb.php outputs wikitext message as raw HTML, which
+could lead to xss. Permission to edit MediaWiki namespace is required to
+exploit this.
+* (bug T74222) The original patch for T74222 was reverted as unnecessary.
+* Add missing $ in front of variable in OutputPage.php
+
+== MediaWiki 1.19.22 ==
+
+This is a security and maintenance release of the MediaWiki 1.19 branch.
+
+=== Changes since 1.19.21 ===
+
+* ({{bug|66776}}, {{bug|71478}}) SECURITY:  User PleaseStand reported a way to
+inject code into API clients that used format=php to process pages that
+underwent flash policy mangling. This was fixed along with improving how the
+mangling was done for format=json, and allowing sites to disable the mangling
+using $wgMangleFlashPolicy.
+* ({{bug|72222}}) SECURITY: Do not show log action when the entry is revdeleted
+with DELETED_ACTION. NOTICE: this may be reverted in a future release pending a
+public RFC about the desired functionality. This issue was reported by user
+Bawolff.
+* ({{bug|71621}}) Make allowing site-wide styles on restricted special pages a
+config option.
+* $wgMangleFlashPolicy was added to make MediaWiki's mangling of anything that
+might be a flash policy directive configurable.
+
 == MediaWiki 1.19.21 ==
 This is a maintenance release of the MediaWiki 1.19 branch.
 
 === Changes since 1.19.20 ===
 * (bug 67440) Allow classes to be registered properly from installer.
-* (bug 47281) Fixed a dumpBackup.php error with --uploads --include-filesoptions: Unable to find the wrapper "mwstore". * System administrators are encouraged to upgrade to this release or 1.22+ and produce a full data dump. https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Backing_up_a_wiki
-* (bug 63049) Removed anonymous functions from ApiFormatBase, added in1.19.13 as part of the fix for bug 61362, for PHP 5.2 compatibility.
+* (bug 47281) Fixed a dumpBackup.php error with --uploads
+ --include-filesoptions: Unable to find the wrapper "mwstore".
+* System administrators are encouraged to upgrade to this release or 1.22+ and
+  produce a full data dump.
+  https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Backing_up_a_wiki
+* (bug 63049) Removed anonymous functions from ApiFormatBase, added in1.19.13 as
+  part of the fix for bug 61362, for PHP 5.2 compatibility.
 
 == MediaWiki 1.19.20 ==
 This is a security release of the MediaWiki 1.19 branch.
 
 === Changes since 1.19.19 ===
-* (bug 70672) SECURITY: OutputPage: Remove separation of css and js module allowance.
+* (bug 70672) SECURITY: OutputPage: Remove separation of css and js module
+  allowance.
 
 == MediaWiki 1.19.19 ==
 This is a security release of the MediaWiki 1.19 branch.
 
 === Changes since 1.19.18 ===
-* (bug 69008) SECURITY: Enhance CSS filtering in SVG files. Filter <style> elements; normalize style elements and attributes before filtering; add checks for attributes that contain css; add unit tests for html5sec and reported bugs.
+* (bug 69008) SECURITY: Enhance CSS filtering in SVG files. Filter <style>
+  elements; normalize style elements and attributes before filtering; add checks
+  for attributes that contain css; add unit tests for html5sec and reported
+  bugs.
 
 == MediaWiki 1.19.18 ==
 This is a security release of the MediaWiki 1.19 branch.
 
 === Changes since 1.19.17 ===
 * (bug 68187) SECURITY: Prepend jsonp callback with comment.
-* (bug 65778) SECURITY: Copy prevent-clickjacking between OutputPage and ParserOutput.
+* (bug 65778) SECURITY: Copy prevent-clickjacking between OutputPage and
+  ParserOutput.
 
 == MediaWiki 1.19.17 ==
 This is a security and maintenance release of the MediaWiki 1.19 branch.
 
 === Changes since 1.19.16 ===
 * (bug 65839) SECURITY: Prevent external resources in SVG files.
-* (bug 66428) MimeMagic: Don't seek before BOF. This has weird side effects like only extracting the tail of the file partially or not at all.
+* (bug 66428) MimeMagic: Don't seek before BOF. This has weird side effects like
+  only extracting the tail of the file partially or not at all.
 
 == MediaWiki 1.19.16 ==
 This is a security release of the MediaWiki 1.19 branch.
 
 === Changes since 1.19.15 ===
-* (bug 65501) SECURITY: Don't parse usernames as wikitext on Special:PasswordReset.
+* (bug 65501) SECURITY: Don't parse usernames as wikitext on
+  Special:PasswordReset.
 
 == MediaWiki 1.19.15 ==
 This is a security and maintenance release of the MediaWiki 1.19 branch.
 
 === Changes since 1.19.14 ===
 Fixed resetting passwords.
-* (bug 58640) Fixed a compatibility issue with PCRE 8.34 that caused pages to appear blank or with missing text.
+* (bug 58640) Fixed a compatibility issue with PCRE 8.34 that caused pages to
+  appear blank or with missing text.
 
 == MediaWiki 1.19.14 ==
 This is a security and maintenance release of the MediaWiki 1.19 branch.
@@ -7109,14 +7434,19 @@ This is a security and maintenance release of the MediaWiki 1.19 branch.
 This is a security release of the MediaWiki 1.19 branch.
 
 === Changes since 1.19.11 ===
-* (bug 60771) SECURITY: Disallow uploading SVG files using non-whitelisted namespaces. Also disallow iframe elements. * User will get an error including the namespace name if they use a non- whitelisted namespace.
-* (bug 61346) SECURITY: Make token comparison use constant time. It seems like our token comparison would be vulnerable to timing attacks. This will take constant time.
+* (bug 60771) SECURITY: Disallow uploading SVG files using non-whitelisted
+  namespaces. Also disallow iframe elements. * User will get an error including
+  the namespace name if they use a non- whitelisted namespace.
+* (bug 61346) SECURITY: Make token comparison use constant time. It seems like
+  our token comparison would be vulnerable to timing attacks. This will take
+  constant time.
 
 == MediaWiki 1.19.11 ==
 This is a security release of the MediaWiki 1.19 branch.
 
 === Changes since 1.19.10 ===
-* (bug 60339) SECURITY: Sanitize shell arguments to DjVu files, and other media formats
+* (bug 60339) SECURITY: Sanitize shell arguments to DjVu files, and other media
+  formats
 
 == MediaWiki 1.19.10 ==
 This is a security release of the MediaWiki 1.19 branch.
@@ -7156,7 +7486,8 @@ This is a security and maintenance release of the MediaWiki 1.19 branch.
 This is a security release of the MediaWiki 1.19 branch
 
 === Changes since 1.19.6 ===
-* (bug 48306) SECURITY: Run file validation checks on chunked uploads, and chunks of upload, during the upload process.
+* (bug 48306) SECURITY: Run file validation checks on chunked uploads, and
+  chunks of upload, during the upload process.
 
 == MediaWiki 1.19.6 ==
 2013-04-30
@@ -7165,7 +7496,8 @@ This is a security and maintenance release of the MediaWiki 1.19 branch
 
 === Changes since 1.19.5 ===
 * (bug 47304) SECURITY: Check SVG xml encoding against whitelist
-* (bug 46590) Added AbortChangePassword hook to allow extensions to abort password changes from Special:ChangePassword
+* (bug 46590) Added AbortChangePassword hook to allow extensions to abort
+  password changes from Special:ChangePassword
 * Localisation updates from http://translatewiki.net.
 * mwdocgen.php: Implement --version option.
 * Remove svnstat stuff used in Doxygen generation
@@ -7189,11 +7521,13 @@ This is a security and maintenance release of the MediaWiki 1.19 branch
 This is a security release of the MediaWiki 1.19 branch
 
 === Changes since 1.19.3 ===
-* New preference type - 'api'. Preferences of this type are not shown on Special:Preferences, but are still available via the action=options API.
+* New preference type - 'api'. Preferences of this type are not shown on
+  Special:Preferences, but are still available via the action=options API.
 * (bug 44010) Context is passed to UserGetLanguageObject.
 * The recursion guard on RequestContext::getLanguage() was weakened.
 * (bug 44135/bug 42441) Pass '2' instead of 'true' to CURLOPT_SSL_VERIFYHOST
-* (bug 43518) API action=unblock should return the user name, not the full user object
+* (bug 43518) API action=unblock should return the user name, not the full user
+  object
 
 == MediaWiki 1.19.3 ==
 2012-11-30
@@ -7203,7 +7537,8 @@ This is a security release of the MediaWiki 1.19 branch
 === Changes since 1.19.2 ===
 * (bug 40995) Prevent session fixation in Special:UserLogin (CVE-2012-5391)
 * (bug 41400) Prevent linker regex from exceeding PCRE backtrack limit
-* Increase permitted runtime for testParserTest (only used for continuous integration).
+* Increase permitted runtime for testParserTest (only used for continuous
+  integration).
 * Updated messages translations from http://translatewiki.net/
 
 == MediaWiki 1.19.2 ==
@@ -7257,8 +7592,9 @@ release and submitting bug reports.
 * (bug 34889) User name should be normalized on Special:Contributions
 * (bug 35051) If heading has a trailing space after == then its name is not
   preloaded into edit summary on section edit
-* (bug 31417) New ID mw-content-text around the actual page text, without categories,
-  contentSub, ... The same div often also contains the class mw-content-ltr/rtl.
+* (bug 31417) New ID mw-content-text around the actual page text, without
+  categories, contentSub, ... The same div often also contains the class
+  mw-content-ltr/rtl.
 * (bug 35303) Proxy and DNS blacklist blocking works again
 * (bug 22555) Remove or skip strip markers from tag hooks like &lt;nowiki&gt; in
   core parser functions which operate on strings, such as padleft.
@@ -7266,8 +7602,8 @@ release and submitting bug reports.
   inside a heading.
 * (bug 34212) ApiBlock/ApiUnblock allow action to take place without a token
   parameter present.
-* (bug 34907) Fixed exposure of tokens through load.php that could have facilitated
-  CSRF attacks.
+* (bug 34907) Fixed exposure of tokens through load.php that could have
+  facilitated CSRF attacks.
 * (bug 35317) CSRF in Special:Upload.
 
 === Configuration changes in 1.19 ===
@@ -7337,7 +7673,8 @@ release and submitting bug reports.
   converted to css.
 * (bug 31297) Add support for namespaces in Special:RecentChanges subpage filter
   syntax.
-* The default user signature now contains a talk link in addition to the user link.
+* The default user signature now contains a talk link in addition to the user
+  link.
 * (bug 25306) Add link of old page title to MediaWiki:Delete_and_move_reason.
 * Added hook BitmapHandlerCheckImageArea.
 * (bug 30062) Add $wgDBprefix option to cli installer.
@@ -7352,8 +7689,8 @@ release and submitting bug reports.
   containing HTML or JS. DISABLING THESE CHECKS IS VERY DANGEROUS.
 * New path mappings can be added using the WebRequestPathInfoRouter hook
   and adding paths to the PathRouter.
-* (bug 32666) Special:ActiveUsers now allows a subpage to be used as value for the
-  "target" query parameter (eg. Special:ActiveUsers/Username).
+* (bug 32666) Special:ActiveUsers now allows a subpage to be used as value for
+  the "target" query parameter (eg. Special:ActiveUsers/Username).
 * New JavaScript variable wgPageContentLanguage.
 * Added new debugging toolbar, enabled with $wgDebugToolbar.
 * Differences in the history page now uses slightly better colors for people
@@ -7365,16 +7702,18 @@ release and submitting bug reports.
 * (bug 32512) Add 'Associated namespace' checkbox to Special:Contributions.
 * Added $wgSend404Code, true by default, which can be set to false to send a
   200 status code instead of 404 for nonexistent articles.
-* (bug 33447) Link to the broken image tracking category from Special:Wantedfiles.
+* (bug 33447) Link to the broken image tracking category from
+  Special:Wantedfiles.
 * (bug 27724) Add timestamp to job queue.
-* (bug 30339) Implement SpecialPage for running javascript tests. Disabled by default, due to
-  tests potentially being harmful, not to be run on a production wiki.
-  Enable by setting $wgEnableJavaScriptTest to true.
+* (bug 30339) Implement SpecialPage for running javascript tests. Disabled by
+  default, due to tests potentially being harmful, not to be run on a production
+  wiki. Enable by setting $wgEnableJavaScriptTest to true.
 * Extensions can use the RequestContextCreateSkin hook to override what skin is
   loaded in some contexts.
 * (bug 33456) Show $wgQueryCacheLimit on cached query pages.
 * (bug 10574) Add an option to allow all pages to be exported by Special:Export.
-* mediawiki.js Message object constructor is now publicly available as mw.Message.
+* mediawiki.js Message object constructor is now publicly available as
+  mw.Message.
 * (bug 29309) Allow CSS class per tooltip (tipsy).
 * (bug 33565) Add accesskey/tooltip to submit buttons on Special:EditWatchlist.
 * (bug 17959) Inline rendering/thumbnailing for Gimp XCF images.
@@ -7392,9 +7731,9 @@ release and submitting bug reports.
   until the second was introduced in 1.17.
 * BREAKING CHANGE:  Style rules for wikitable are now more specific and prevent
   inheritance to nested tables which caused various issues (bug 30485 and bug
-  33434). If your wiki has overridden rules for ".wikitable", please revise them and
-  adjust where necessary. For comparison, use the "table.wikitable" section in
-  skins/common/shared.css as base.
+  33434). If your wiki has overridden rules for ".wikitable", please revise them
+  and adjust where necessary. For comparison, use the "table.wikitable" section
+  in skins/common/shared.css as base.
 * $wgUploadNavigationUrl is now used for file redlinks if
   $wgUploadMissingFileUrl is not set. The former was used for this until the
   second was introduced in 1.17.
@@ -7416,8 +7755,8 @@ release and submitting bug reports.
 * Show --batch-size option in help of maintenance scripts that support it.
 * (bug 4381) Magic quotes cleaning was not comprehensive, key strings were not
   unescaped.
-* (bug 23057) Importers no longer can 'edit' or 'create' a fully-protected page by
-  importing a new revision into it.
+* (bug 23057) Importers no longer can 'edit' or 'create' a fully-protected page
+  by importing a new revision into it.
 * Allow moving the associated talk pages of subpages even if the base page
   has no subpage.
 * Per page edit-notices now work in namespaces without subpages enabled.
@@ -7448,7 +7787,8 @@ release and submitting bug reports.
 * (bug 30368) Special:Newpages now shows the new page name for moved pages.
 * (bug 1697) The way to search blocked usernames in block log should be clearer.
 * (bug 29747) eAccelerator shared memory caching has been removed since it is
-  now disabled by default and is buggy. APC, XCache and WinCache are not affected.
+  now disabled by default and is buggy. APC, XCache and WinCache are not
+  affected.
 * Installer now refuses to install if php was not compiled with Ctype support.
 * (bug 29475) Remove "trackback" feature entirely from core.
 * (bug 32665) Special:BlockList prefills the username in the input field if
@@ -7493,28 +7833,33 @@ release and submitting bug reports.
 * Files with IPTC blocks we can't read no longer prevent extraction of exif
   or other metadata.
 * (bug 33587) Remove action "historysubmit" from history pages.
-* (bug 25800) mw.config wgAction should contain the actually performed action instead
-  of whatever the query value contains.
+* (bug 25800) mw.config wgAction should contain the actually performed action
+  instead of whatever the query value contains.
 * (bug 4438) Add CSS hook for current WikiPage action.
-* (bug 33703) Common border-bottom color for <abbr> should inherit default (text) color.
+* (bug 33703) Common border-bottom color for <abbr> should inherit default
+  (text) color.
 * (bug 33819) Display file sizes in appropriate units.
-* (bug 32948) {{REVISIONID}} and related variables are no longer blank after doing
-  a null edit.
-* (bug 33880) $wgUsersNotifiedOnAllChanges should not send e-mail to user who made
-  the edit.
+* (bug 32948) {{REVISIONID}} and related variables are no longer blank after
+  doing a null edit.
+* (bug 33880) $wgUsersNotifiedOnAllChanges should not send e-mail to user who
+  made the edit.
 * (bug 33902) Decoding %2B with mw.Uri.decode results in ' ' instead of +.
 * (bug 33762) QueryPage-based special pages no longer misses *-summary message.
-* Other sizes links are no longer generated for wikis without a 404 thumbnail handler.
+* Other sizes links are no longer generated for wikis without a 404 thumbnail
+  handler.
 * (bug 29454) Enforce byteLimit for page title input on Special:MovePage.
 * (bug 34114) CSSMin::remap() doesn't respect its $embed parameter.
-* Special:Contributions/newbies now shows the contributions for the user "newbies".
-  New user contributions are obtained using the form or using ?contribs=newbie in URL.
-* It is now possible to delete images that have no corresponding description pages.
+* Special:Contributions/newbies now shows the contributions for the user
+  "newbies". New user contributions are obtained using the form or using
+  ?contribs=newbie in URL.
+* It is now possible to delete images that have no corresponding description
+  pages.
 * (bug 33165) GlobalFunctions.php line 1312: Call to a member function
   getText() on a non-object.
 * (bug 31676) Group dynamically inserted CSS into a single <style> tag, to work
   around a bug where not all styles were applied in Internet Explorer.
-* (bug 28936, bug 5280) Broken or invalid titles can't be removed from watchlist.
+* (bug 28936, bug 5280) Broken or invalid titles can't be removed from
+  watchlist.
 * (bug 34600) Older skins using useHeadElement=false were broken in 1.18.
 * (bug 34604) [mw.config] wgActionPaths should be an object instead of a numeral
   array.
@@ -7527,8 +7872,8 @@ release and submitting bug reports.
   [[Special:WhatLinksHere/Example]]
 
 === API changes in 1.19 ===
-* Made action=edit less likely to return "unknownerror", by returning the actual error
-  message (which may have come from a hook call or similar).
+* Made action=edit less likely to return "unknownerror", by returning the actual
+  error message (which may have come from a hook call or similar).
 * (bug 19838) siprop=interwikimap can now use the interwiki cache.
 * (bug 29748) Add API search prefix support.
 * (bug 29684) Set forgotten parameter types in ApiQueryIWLinks.
@@ -7590,34 +7935,50 @@ changes to languages because of Bugzilla reports.
 * jquery.mwPrototypes module was renamed to jquery.mwExtension.
 * The maintenance script populateSha1.php was renamed to the more concise
   populateImageSha1.php.
-* The Client-IP header is no longer checked for when trying to resolve a client's
-  real IP address.
-* (bug 22096) Although IE5.x and below was already unsupported officially, stylesheets
-  existing exclusively for IE5.0 and IE5.5 have now been removed (which were in skins
-  'chick' and 'monobook').
+* The Client-IP header is no longer checked for when trying to resolve a
+  client's real IP address.
+* (bug 22096) Although IE5.x and below was already unsupported officially,
+  stylesheets existing exclusively for IE5.0 and IE5.5 have now been removed
+  (which were in skins 'chick' and 'monobook').
 * The constructor for CategoryView has changed, the second parameter is now a
   Context source and is required.
 * The Title::escape{Local,Full,Canonical}URL methods are deprecated, please use
   proper html building methods to escape the normal get{...}URL methods instead.
 * The $variant arguments in the Title::get{Local,Full,Link,Canonical}URL methods
   have been replaced with a secondary query argument.
-* The $variant argument in the hooks for the Title::get{Local,Full,Link,Canonical}URL
-  methods have been removed, the variant is now part of the $query argument.
+* The $variant argument in the hooks for the
+  Title::get{Local,Full,Link,Canonical}URL methods have been removed, the
+  variant is now part of the $query argument.
 * Removed Title::isValidCssJsSubpage(), deprecated since 1.17 in favor of
   using Title::isCssJsSubpage() or checking Title::isWrongCaseCssJsPage().
 * Support for the deprecated hook MagicWordMagicWords was removed.
 * The Xml::namespaceSelector method has been deprecated, please use
   Html::namespaceSelector instead (note that the parameters have changed also).
-* (bug 33746) Preload popular ResourceLoader modules (mediawiki.util) as stop-gap
-  for scripts missing dependencies.
-  New configuration variable $wgPreloadJavaScriptMwUtil has been introduced for this
-  (set to false by default for new installations). Set to true if your wiki has a large
-  amount of user/site scripts that are lacking dependency information. In the short to
-  medium term these user/site scripts should be fixed by adding the used modules to the
-  dependencies in the module registry and/or wrapping them in a callback to mw.loader.using.
+* (bug 33746) Preload popular ResourceLoader modules (mediawiki.util) as
+  stop-gap for scripts missing dependencies.
+  New configuration variable $wgPreloadJavaScriptMwUtil has been introduced for
+  this (set to false by default for new installations). Set to true if your wiki
+  has a large amount of user/site scripts that are lacking dependency
+  information. In the short to medium term these user/site scripts should be
+  fixed by adding the used modules to the dependencies in the module registry
+  and/or wrapping them in a callback to mw.loader.using.
 
 == MediaWiki 1.18 ==
 
+== MediaWiki 1.18.6 ==
+2012-11-29
+
+This is a maintenance and security release of the MediaWiki 1.18 branch
+
+=== Changes since 1.18.5 ===
+* ([[bugzilla:40995|bug 40995]]) Prevent session fixation in Special:UserLogin
+(CVE-2012-5391)
+* ([[bugzilla:41400|bug 41400]]) Prevent linker regex from exceeding PCRE
+backtrack limit
+* Localisation updates
+* Increase permitted runtime for testParserTest
+* ([[bugzilla:36179|bug 36179]]) Unquote 'null' for PostgreSQL.
+
 == MediaWiki 1.18.5 ==
 2012-08-30
 
@@ -7648,7 +8009,8 @@ This is a maintenance release of the MediaWiki 1.18 branch.
 === Changes since 1.18.2 ===
 * (bug 35446) Using "{{nse:}}" with an invalid namespace name no longer throws
   a PHP warning.
-* (bug 35567) The whole password reminder e-mail is now sent in the same language.
+* (bug 35567) The whole password reminder e-mail is now sent in the same
+  language.
 * (bug 35961) Hash comparison should always be strict.
 * (bug 35671) PHP Notice: Undefined index: gettoken in includes/api/ApiMain.php
   on line 598.
@@ -7674,8 +8036,8 @@ This is a maintenance and security release of the MediaWiki 1.18 branch.
   core parser functions which operate on strings, such as formatnum.
 * (bug 34212) ApiBlock/ApiUnblock allow action to take place without a token
   parameter present.
-* (bug 34907) Fixed exposure of tokens through load.php that could have facilitated
-  CSRF attacks.
+* (bug 34907) Fixed exposure of tokens through load.php that could have
+  facilitated CSRF attacks.
 * (bug 35317) CSRF in Special:Upload.
 
 == MediaWiki 1.18.1 ==
@@ -7684,13 +8046,16 @@ This is a maintenance and security release of the MediaWiki 1.18 branch.
 This a maintenance and security release of the MediaWiki 1.18 branch.
 
 === Changes since 1.18.0 ===
-* (bug 32712) Fix for search indexing of pages with certain unicode chars following URL.
-* (bug 3901) Lang, hreflang attribs added to sidebar interlanguage links for screen readers.
+* (bug 32712) Fix for search indexing of pages with certain unicode chars
+  following URL.
+* (bug 3901) Lang, hreflang attribs added to sidebar interlanguage links for
+  screen readers.
 * (bug 30774) mediawiki.html: Add support for numbers and booleans in the
   attribute values and element contents.
 * (bug 32473) [[Special:PasswordReset]] can not be used on private wiki.
 * (bug 32853) Fixed CACHE_DBA object cache type.
-* (bug 32786) Backward compatibility for extension using 1.17's Database::newFromType().
+* (bug 32786) Backward compatibility for extension using 1.17's
+  Database::newFromType().
 * Fixed exception when using Special:WhatLinksHere on a Media: file.
 * (bug 32709) Private Wiki users were always taken to Special:Badtitle on login.
 * (bug 33240) Sort images are missing but referenced in css.
@@ -7699,17 +8064,20 @@ This a maintenance and security release of the MediaWiki 1.18 branch.
 * (bug 32702) Removed method Skin::makeGlobalVariablesScript() has been readded
   for backward compatibility.
 * (bug 30172) The check for posix_isatty() in maintenance scripts did not detect
-  when the function exists but is disabled. Introduced Maintenance::posix_isatty().
+  when the function exists but is disabled. Introduced
+  Maintenance::posix_isatty().
 * (bug 33305) Make mw.util.addCSS resistant to IE's @font-face bug by setting
   cssText after DOM insertion.
-* (bug 29102) Upgrades no longer fail with the error "Unknown character set: 'mysql4'.
+* (bug 29102) Upgrades no longer fail with the error "Unknown character set:
+  'mysql4'.
 * (bug 25355) Parser generates edit section links for special pages.
-* (bug 33321) Adding a line to MediaWiki:Sidebar that contains a pipe, but doesn't
-  have any pipes after being transformed by MessageCache, causes exception on
-  all pages.
-* Fixed recentchanges FK violation on page delete and cache purge error in updater
-  for Oracle DB.
-* (bug 33117) prop=revisions allows deleted text to be exposed through cache pollution.
+* (bug 33321) Adding a line to MediaWiki:Sidebar that contains a pipe, but
+  doesn't have any pipes after being transformed by MessageCache, causes
+  exception on all pages.
+* Fixed recentchanges FK violation on page delete and cache purge error in
+  updater for Oracle DB.
+* (bug 33117) prop=revisions allows deleted text to be exposed through cache
+  pollution.
 
 == MediaWiki 1.18.0 ==
 2011-11-24
@@ -7721,37 +8089,40 @@ This is the first stable release of the MediaWiki 1.18 branch.
 Selected changes since MediaWiki 1.17 that may be of interest:
 
 * Some of the more commonly used MediaWiki extensions are now included in the
-  release tarball. These extensions are ConfirmEdit, Gadgets, Nuke, ParserFunctions,
-  Renameuser, Vector and WikiEditor.
+  release tarball. These extensions are ConfirmEdit, Gadgets, Nuke,
+  ParserFunctions, Renameuser, Vector and WikiEditor.
 
-* Gender support has been improved, meaning user pages can display the correct gender
-  variant of "User" can now be used.
+* Gender support has been improved, meaning user pages can display the correct
+  gender variant of "User" can now be used.
 
-* MediaWiki can now detect the camera orientation of an image from the Exif metadata, and
-  can rotate the image thumbnail appropriately. Metadata support has been generally
-  improved, and can now extract IPTC and XMP metadata.
+* MediaWiki can now detect the camera orientation of an image from the Exif
+  metadata, and can rotate the image thumbnail appropriately. Metadata support
+  has been generally improved, and can now extract IPTC and XMP metadata.
 
-* Improved directionality support in 1.18 means that MediaWiki is better to use for
-  RTL users.
+* Improved directionality support in 1.18 means that MediaWiki is better to use
+  for RTL users.
 
-* MediaWiki now supports protocol - relative URLs in links, interwiki targets and $wgServer
+* MediaWiki now supports protocol - relative URLs in links, interwiki targets
+  and $wgServer
 
 * Math support has been removed from core
 
 === Changes since 1.18.0rc1 ===
-* (bug 32228) regression in Special:Search which did not conserve profile on new search
+* (bug 32228) regression in Special:Search which did not conserve profile on
+  new search
 * (bug 32460) Categories were improperly aligned in Simple and CologneBlue
 * (bug 32412) TOC links on [[Special:EditWatchlist]] points to the fieldsets
 * (bug 32582) Fix TOC show/hide link regression on IE 8
 
 === Changes since 1.18 beta 1 ===
-* (bug 31886) Wrong titles redirecting to Special:Badtitle in the 1.18 deployment.
+* (bug 31886) Wrong titles redirecting to Special:Badtitle in the 1.18
+  deployment.
 * (bug 32051) Fix description for wlprop=sizes.
 * (bug 31913) Special:MostLinkedTemplates had an incorrect GROUP BY clause
   under Microsoft SQL.
 * (bug 32100) installer complains about suhosin GET limit.
-* (bug 31933) fix 1.18 regression in Monobook sidebar: huge spacing between portlets
-  on IE 7 and IE 8/9 in compatibility view.
+* (bug 31933) fix 1.18 regression in Monobook sidebar: huge spacing between
+  portlets on IE 7 and IE 8/9 in compatibility view.
 * (bug 32126) Fix 1.18 regression in watchlist editor when items already removed
   from watchlist.
 * (bug 32183) remove the client-* classes added from user-agent-sniffing onto
@@ -7826,7 +8197,8 @@ Selected changes since MediaWiki 1.17 that may be of interest:
 * $wgProto has been removed. You now only need to set $wgServer to change the
   URL protocol.
 * $wgRateLimitsExcludedGroups (deprecated in 1.13) has been removed.
-* $wgInputEncoding and $wgOutputEncoding (deprecated in 1.5) have now been removed.
+* $wgInputEncoding and $wgOutputEncoding (deprecated in 1.5) have now been
+  removed.
 * $wgAllowUserSkin (deprecated in 1.16) has now been removed.
 * $wgExtraRandompageSQL (deprecated in 1.16) has now been removed.
 * LogReader and LogViewer classes (deprecated in 1.14) have now been removed.
@@ -7836,9 +8208,10 @@ Selected changes since MediaWiki 1.17 that may be of interest:
   and the functionality has been moved to the relevant extensions. See
   https://www.mediawiki.org/wiki/Extension:DublinCoreRdf and
   https://www.mediawiki.org/wiki/Extension:CreativeCommonsRdf as appropriate.
-* (bug 21107) Split error "customcssjsprotected" into separate messages for JS and CSS
-* Removed $wgCheckCopyrightUpload from DefaultSettings, since the relevant feature
-  was removed in about 1.5.
+* (bug 21107) Split error "customcssjsprotected" into separate messages for JS
+  and CSS
+* Removed $wgCheckCopyrightUpload from DefaultSettings, since the relevant
+  feature was removed in about 1.5.
 * LogPageValidTypes, LogPageLogName, LogPageLogHeader and LogPageActionText
   hooks have been removed.
 * New hook "Collation::factory" to allow extensions to create custom
@@ -7850,9 +8223,10 @@ Selected changes since MediaWiki 1.17 that may be of interest:
 === New features in 1.18 ===
 * BREAKING CHANGE: action=watch / action=unwatch now requires a token.
 * BREAKING CHANGE: Article class hierarchy split into WikiPage (backend)
-  and Article (frontend) hierarchies. Several hooks now pass a WikiPage object instead
-  of an Article object. These hooks all use an $article parameter as documented in hooks.txt.
-  Extensions should be updated to account for this, though most won't require any changes.
+  and Article (frontend) hierarchies. Several hooks now pass a WikiPage object
+  instead of an Article object. These hooks all use an $article parameter as
+  documented in hooks.txt. Extensions should be updated to account for this,
+  though most won't require any changes.
 * (bug 27860) Minor edit after clicking 'new section' tab
   Now the "This is a minor edit" checkbox is not available when you
   create a page or new section.
@@ -7880,8 +8254,8 @@ Selected changes since MediaWiki 1.17 that may be of interest:
   (maintenance/fixDoubleRedirects.php).
 * (bug 23315) New body classes to allow easier styling of special pages.
 * (bug 27159) Make email confirmation code expiration time configurable.
-* (bug 29047) CSS/JS for each user group is imported from MediaWiki:Group-sysop.js,
-  MediaWiki:Group-autoconfirmed.css, etc.
+* (bug 29047) CSS/JS for each user group is imported from
+  MediaWiki:Group-sysop.js, MediaWiki:Group-autoconfirmed.css, etc.
 * (bug 24230) Uploads of ZIP types, such as MS Office or OpenOffice can now be
   safely enabled. A ZIP file reader was added which can scan a ZIP file for
   potentially dangerous Java applets. This allows applets to be blocked
@@ -7939,7 +8313,8 @@ Selected changes since MediaWiki 1.17 that may be of interest:
 * (bug 29067) Expose user.tokens (like we do user.options) in ResourceLoader.
 * New 'Debug' hook used by wfDebug() and wfDebugLog().
 * (bug 27655) Require token for watching/unwatching pages)
-* (bug 28904) (bug 29773) Update jQuery version from 1.4.4 to 1.6.2 (the latest version)
+* (bug 28904) (bug 29773) Update jQuery version from 1.4.4 to 1.6.2 (the latest
+  version)
 * (bug 29441) Expose CapitalLinks config in JS to allow modules to properly
   handle titles on case-sensitive wikis.
 * (bug 29397) Implement mw.Title module in core.
@@ -7966,16 +8341,18 @@ Selected changes since MediaWiki 1.17 that may be of interest:
   Suggests possible categories when typing, all saves are done via AJAX.
   Supports editing of multiple categories and then saving them in one batch.
 * $wgAutopromoteOnce was added, allowing for users to be automatically promoted
-  to explicit usergroups. If a group is removed from a user via Special:UserRights,
-  it will not automatically be re-added. Configuration is similar to
-  $wgAutopromote (see DefaultSettings.php).
-* The PerformRetroactiveAutoblock hook was added to allow overriding or complementing
-  retroactive autoblock handling. This runs when blocking a user with the 'autoblock' option.
+  to explicit usergroups. If a group is removed from a user via
+  Special:UserRights, it will not automatically be re-added. Configuration is
+  similar to $wgAutopromote (see DefaultSettings.php).
+* The PerformRetroactiveAutoblock hook was added to allow overriding or
+  complementing retroactive autoblock handling. This runs when blocking a user
+  with the 'autoblock' option.
 * MediaWiki now supports using protocol-relative URLs in links, interwiki
   targets and $wgServer.
 * Introduced $wgVaryOnXFPForAPI which will cause the API to send
   Vary: X-Forwarded-Proto headers.
-* New maintenance script to refresh image metadata (maintenance/refreshImageMetadata.php).
+* New maintenance script to refresh image metadata
+  (maintenance/refreshImageMetadata.php).
 * (bug 16428) Include permalink in printable version.
 * (bug 30722) Add an identity collation that sorts things based on what the
   unicode code point is (aka pre-1.17 behavior).
@@ -7984,16 +8361,17 @@ Selected changes since MediaWiki 1.17 that may be of interest:
   values for preferences a hook has been introduced in User:getDefaultOptions().
   Setting preferences in $wgDefaultUserOptions still work fine, but when reading
   them (i.e. with array_keys) to get a list of all preferences, then
-  $wgDefaultUserOptions should no longer be used as it will contain those set via
-  User:getDefaultOptions().
+  $wgDefaultUserOptions should no longer be used as it will contain those set
+  via User:getDefaultOptions().
 * (bug 30497) Add client-nojs and client-js classes on document element
   to let styles easily hide or show things based on general JS availability.
 * (bug 31293) If Special:Userlogin is loaded over HTTPS, display
   MediaWiki:loginend-https instead of MediaWiki:loginend, if it's not empty.
   Same for signupend on the account creation page.
-* (bug 31233) New OutputPage::addJsConfigVars() method to make the output page specific
-  mw.config map extendable.
-* mw.util.wikiScript has been implemented (like wfScript in GlobalFunctions.php).
+* (bug 31233) New OutputPage::addJsConfigVars() method to make the output page
+  specific mw.config map extendable.
+* mw.util.wikiScript has been implemented (like wfScript in
+  GlobalFunctions.php).
 
 === Bug fixes in 1.18 ===
 * (bug 27860) Minor edit after clicking 'new section' tab.
@@ -8147,8 +8525,8 @@ Selected changes since MediaWiki 1.17 that may be of interest:
   LTR/RTL screen layout.
 * (bug 28992) Revision numbers in the patrol log are transformed in the user
   language.
-* (bug 27073) ResourceLoaderDynamicStyles marker should be dynamically appended to
-  the document head if it doesn't exist.
+* (bug 27073) ResourceLoaderDynamicStyles marker should be dynamically appended
+  to the document head if it doesn't exist.
 * (bug 27023) After the document is ready, mw.loader is broken (calls callback
   before module is parsed).
 * (bug 4330) External URLs without a custom title should be treated as LTR,
@@ -8165,7 +8543,8 @@ Selected changes since MediaWiki 1.17 that may be of interest:
 * The class JpegOrTiffHandler was renamed ExifBitmapHandler.
 * (bug 29443) Special:Undelete should use JavaScript to invert all checkboxes
   instead of reloading the page.
-* (bug 29325) Setting $wgStrictFileExtensions to false no longer gives incorrect warning.
+* (bug 29325) Setting $wgStrictFileExtensions to false no longer gives incorrect
+  warning.
 * (bug 29437) Multiple apostrophes in deleted article title cause odd rendering.
 * (bug 29485) RSS feed of Special:RecentChange grouped together multiple
   consecutive edits by same user in included diff, but then linked to
@@ -8173,7 +8552,8 @@ Selected changes since MediaWiki 1.17 that may be of interest:
 * Do not try to group together a page creation and edit in the RSS feed of RC.
 * (bug 29342) Patrol preferences shouldn't be visible to users who don't have
   patrol permissions.
-* (bug 29471) Exception no longer thrown for files with invalid date in metadata.
+* (bug 29471) Exception no longer thrown for files with invalid date in
+  metadata.
 * (bug 29492) Long-running steps in the installer (such as Upgrade and Install)
   no longer cause timeouts.
 * (bug 29507) Change 'image link' to 'file link' in Special:Whatlinkshere.
@@ -8188,8 +8568,8 @@ Selected changes since MediaWiki 1.17 that may be of interest:
 * Use content language in formatting of dates in revertpage message
   (rollback revert edit summary) and do not adjust for user timezone.
 * (bug 29277) MediaWiki:Filepage.css is also shown on the local wiki
-* Make sure Backlink cache does not retrieve interwiki redirects when looking for
-  redirects to a local page.
+* Make sure Backlink cache does not retrieve interwiki redirects when looking
+  for redirects to a local page.
 * (bug 6100) Allow different directionality (LTR/RTL) for user interface
   and wiki content, along with many other RTL and directionality improvements
   (such as bugs 28030, 12406, 28349).
@@ -8220,24 +8600,26 @@ Selected changes since MediaWiki 1.17 that may be of interest:
 * Installer checked for magic_quotes_runtime instead of register_globals.
 * (bug 30131) XCache with variable caching disabled no longer used for variable
   caching (CACHE_ACCEL)
-* $wgSVGMaxSize is now applied to the smaller of width or height, making very wide
-  pano/timeline/diagram SVGs renderable at saner sizes.
+* $wgSVGMaxSize is now applied to the smaller of width or height, making very
+  wide pano/timeline/diagram SVGs renderable at saner sizes.
 * (bug 30219) The page shown when LocalSettings.php does not exist was broken on
   Windows servers.
 * (bug 30074) Moving user JS subpages resulted in JS errors because
   #REDIRECT [[Foo]] is invalid JS.
 * (bug 30335) Fix for HTMLForms using GET breaking when non-friendly URLs
   are used.
-* (bug 30264) Changed installer-generated LocalSettings.php to use require_once()
-  instead of require() for included extensions.
+* (bug 30264) Changed installer-generated LocalSettings.php to use
+  require_once() instead of require() for included extensions.
 * Tracking categories are no longer shown in footer for special pages.
-* (bug 30684) Fix bad escaping in mw.message for inexistent messages (i.e. <key>).
+* (bug 30684) Fix bad escaping in mw.message for inexistent messages (i.e.
+  <key>).
 * $wgOverrideSiteFeed no longer double escapes urls.
 * The preprocessor no longer fails with a PHP warning about XML_PARSE_HUGE when
   processing complex pages using newer versions of libxml2.
 * (bug 30907) Special:Unusedcategories should sort ascendingly.
 * (bug 28545) When using the uca-default collation, sortkey's starting with a
-  space (U+20) will sort under an invisible header like in 1.16 rather than a U+6DE.
+  space (U+20) will sort under an invisible header like in 1.16 rather than a
+  U+6DE.
 * (bug 30192) Thumbnails of archived files are now deleted.
 * (bug 30843) mediawiki.Title should not convert extensions (anything after the
   last full stop) to lower case).
@@ -8491,12 +8873,13 @@ Selected changes since MediaWiki 1.16 that may be of interest:
   core parser functions which operate on strings, such as padleft.
 * (bug 34212) ApiBlock/ApiUnblock allow action to take place without a token
   parameter present.
-* (bug 34907) Fixed exposure of tokens through load.php that could have facilitated
-  CSRF attacks.
+* (bug 34907) Fixed exposure of tokens through load.php that could have
+  facilitated CSRF attacks.
 * (bug 35317) CSRF in Special:Upload.
 
 === Changes since 1.17.1 ===
-* (bug 33117) prop=revisions allows deleted text to be exposed through cache pollution.
+* (bug 33117) prop=revisions allows deleted text to be exposed through cache
+  pollution.
 * (bug 32709) Private Wiki users were always taken to Special:Badtitle on login.
 
 === Changes since 1.17.0 ===
@@ -8522,16 +8905,17 @@ Selected changes since MediaWiki 1.16 that may be of interest:
 * Installer checked for magic_quotes_runtime instead of register_globals
 * (bug 30131) XCache with variable caching disabled no longer used for variable
   caching (CACHE_ACCEL)
-* (bug 30264) Changed installer-generated LocalSettings.php to use require_once()
-  instead require() for included extensions.
+* (bug 30264) Changed installer-generated LocalSettings.php to use
+  require_once() instead require() for included extensions.
 * (bug 26486) ResourceLoader modules with paths to nonexistent files cause PHP
   warnings/notices to be thrown
 * (bug 30907) Special:Unusedcategories should sort ascendingly.
 * (bug 30219) The page shown when LocalSettings.php does not exist was broken on
   Windows servers.
-* Hardcoded NLS_NUMERIC_CHARACTERS for Oracle DB to prevent type conversion errors.
-* Fixed recentchanges FK violation on page delete and cache purge error in updater
-  for Oracle DB.
+* Hardcoded NLS_NUMERIC_CHARACTERS for Oracle DB to prevent type conversion
+  errors.
+* Fixed recentchanges FK violation on page delete and cache purge error in
+  updater for Oracle DB.
 * (bug 32276) Skins were generating output using the internal page title which
   would allow anonymous users to determine whether a page exists, potentially
   leaking private data. In fact, the curid and oldid request parameters would
@@ -8590,11 +8974,12 @@ Selected changes since MediaWiki 1.16 that may be of interest:
 * Fixed JS error due to missing dependency for jquery.suggestions.
 * Exposed $wgExtensionAssetsPath in JavaScript.
 * (bug 28738) Made ResourceLoader support environments with small URL length
-  limits. The length limit can be configured via $wgResourceLoaderMaxQueryLength,
-  and this is set automatically in the generated LocalSettings.php when the
-  php.ini variable "suhosin.get.max_value_length" is set. When a URL exceeds
-  this limit, the request is split up. Also, reduced the average length of
-  load.php URLs by using a more compact parameter format.
+  limits. The length limit can be configured via
+  $wgResourceLoaderMaxQueryLength, and this is set automatically in the
+  generated LocalSettings.php when the php.ini variable
+  "suhosin.get.max_value_length" is set. When a URL exceeds this limit, the
+  request is split up. Also, reduced the average length of load.php URLs by
+  using a more compact parameter format.
 * (bug 25262) Fix for minification of hardcoded data: URIs in CSS.
 * (bug 25124) Respect $wgStyleDirectory in ResourceLoader.
 * Allow installation when no HTTP client is available, don't throw an exception.
@@ -8718,7 +9103,8 @@ Selected changes since MediaWiki 1.16 that may be of interest:
 * Non-file pages can no longer be moved to the file namespace, nor vice versa.
 * (bug 671) The <dfn>, <kbd> and <samp> elements have been whitelisted in user
   input.
-* (bug 21503) There's now a "reason" field when creating account for other users.
+* (bug 21503) There's now a "reason" field when creating account for other
+  users.
 * (bug 24418) action=markpatrolled now requires a token.
 * A variety of category sort-related fixes, including:
 ** (bug 164) In English, lowercase and uppercase letters now sort the same.
@@ -8923,7 +9309,8 @@ Selected changes since MediaWiki 1.16 that may be of interest:
 * (bug 23747) Make sure that on History pages, the RevDel button is not
   accidentally activated when hitting enter.
 * (bug 23845) Special:ListFiles now uses correct file names without underscores.
-* Ask for permanent login in Special:Preferences only if $wgCookieExpiration > 0.
+* Ask for permanent login in Special:Preferences only if $wgCookieExpiration >
+  0.
 * (bug 16356) Repair dumpInterwiki.inc to use proper normalization.
 * (bug 24006) deleteArchivedRevisions.php maintenance script now longer throws
   a fatal error.
@@ -8991,7 +9378,8 @@ Selected changes since MediaWiki 1.16 that may be of interest:
   $wgGroupPermissions now appear on Special:ListGroupRights.
 * (bug 23923) Special:Prefixindex no longer shows results if nothing was
   requested.
-* (bug 22308) Search now finds text in default main page immediately after setup.
+* (bug 22308) Search now finds text in default main page immediately after
+  setup.
 * (bug 25697) Make sure empty lines render in diff view.
 * Use an actual minus sign in diff views, instead of a hyphen.
 * (bug 23732) Clarified "n links" message on Special:MostLinkedFiles.
@@ -9013,7 +9401,8 @@ Selected changes since MediaWiki 1.16 that may be of interest:
   parameters.
 * (bug 25175) HTML file cache now honor $wgCacheDirectory if
   $wgFileCacheDirectory is not set.
-* (bug 13353) Diff3 version checks were too strict, did not detect working diff3.
+* (bug 13353) Diff3 version checks were too strict, did not detect working
+  diff3.
 * (bug 25843) Links to special pages using link= attribute on images are now
   normalised like normal links to special pages.
 * (bug 21364) External links using link= attribute on images now respect
@@ -9040,7 +9429,8 @@ Selected changes since MediaWiki 1.16 that may be of interest:
   absolute URLs in the sitemap index (as required e.g. by Google).
 * Partial workaround for bug 6220: at least make files on shared repositories
   show up as (struck-out) bluelinks instead of redlinks on Special:WantedFiles.
-* rebuildFileCache.php no longer creates inappropriate cache files for redirects.
+* rebuildFileCache.php no longer creates inappropriate cache files for
+  redirects.
 * (bug 25512) Subcategory list should not include category prefix for members.
 * (bug 10871) Javascript and CSS pages in MediaWiki namespace are no longer
   treated as wikitext on preview.
@@ -9049,31 +9439,35 @@ Selected changes since MediaWiki 1.16 that may be of interest:
 * (bug 22753) Output from update.php is more clear when things changed, entries
   indicating nothing changed are now all prefixed by "..."
 * (bug 16019) $wgArticlePath = "/$1" no longer breaks API edit/watch actions.
-* (bug 18372) File types blacklisted by $wgFileBlacklist will no longer be shown as
-  "Permitted file types" on the upload form.
+* (bug 18372) File types blacklisted by $wgFileBlacklist will no longer be shown
+  as "Permitted file types" on the upload form.
 * (bug 26540) Fixed wrong call to applyPatch in MysqlUpdater.
 * (bug 26034) Make the "View / Read" tab in content_navigation style tabs remain
   selected when the action is "purge".
 * (bug 26733) Wrap initial table creation in transaction.
 * (bug 26208) Mark directionality of some interlanguage links.
-* (bug 26716) Provide link to instructions for external editor related preferences.
+* (bug 26716) Provide link to instructions for external editor related
+  preferences.
 * (bug 26961) Hide anon edits in watchlist preference now actually works.
 * (bug 1379) Installer directory conflicts with some hosts' configuration panel.
-* (bug 27781) Installer does not warn about 5.1.x. Added a compatibility function
-  for array_key_exists().
+* (bug 27781) Installer does not warn about 5.1.x. Added a compatibility
+  function for array_key_exists().
 * Fix XML well-formedness on a few pages when $wgHtml5 is true (the default).
 * (bug 28069) MediaWiki fails streaming files when mod_deflate and ob_gzhandler
   are also set.
 * (bug 26223) Concurrently moving an article to different titles leaks a
   redirect revision with no page.
 * (bug 15641) Fixed permissions checks in Special:Import which allowed users
-  without the 'import' permission to import pages from configured import sources.
+  without the 'import' permission to import pages from configured import
+  sources.
 * (bug 26449) Keep underlines from headings outside of tables and thumbs by
   adding overflow:hidden to h1,h2,h3,h4,h5,h6 (also fixes editsection bunching).
 * (bug 26708) Remove background-color:white from tables in Monobook and Vector.
-* (bug 26781) {{PAGENAME}} and related parser functions escape their output better.
-* (bug 26716) Provide link to instructions for external editor related preferences
-  and add a comment to the ini control file explaining what is going on.
+* (bug 26781) {{PAGENAME}} and related parser functions escape their output
+  better.
+* (bug 26716) Provide link to instructions for external editor related
+  preferences and add a comment to the ini control file explaining what is going
+  on.
 * (bug 28422) Remove color:black from tables in Monobook and Vector. And add it
   to table.wikitable instead.
 * (bug 27560) Search queries no longer fail in walloon language.
@@ -9101,7 +9495,8 @@ Selected changes since MediaWiki 1.16 that may be of interest:
 * (bug 27508) SVGMetadataExtractor takes too much resources on huge svgs.
 * (bug 27465) SVG thumbnail generation.
 * (bug 27467) preload can leave UNIQ.
-* (bug 27539) Allow attributes beginning with a digit in wikitext tag parameters.
+* (bug 27539) Allow attributes beginning with a digit in wikitext tag
+  parameters.
 * (bug 27328) using relative paths in CSS imports in MediaWiki:Common.css broken
   in 1.17.
 * (bug 27333) Fix repetitive last-seen time queries on page history.
@@ -9289,8 +9684,8 @@ Other significant changes to MediaWiki's language support:
 * Removed $wgRemoteUploads. It was not well supported and superseded by
   $wgUploadNavigationUrl.
 * (bug 26253) $wgPostCommitUpdateList has been removed
-* The PHPUnit test suite has been removed from this release due to serious issues
-  which should be resolved by the 1.18 release.
+* The PHPUnit test suite has been removed from this release due to serious
+  issues which should be resolved by the 1.18 release.
 * Oracle DB now uses the __destruct function to commit/close connection as it
   doesn't commit on close if transation is triggered in OCI.
 
@@ -10142,10 +10537,11 @@ comment from another wiki.
   skin-specific JS pages
 * (bug 5061) Use the more precise thumbcaption thumbimage and thumbinner classes
   for image divs.
-* (bug 22096) IE50Fixes.css and IE55Fixes.css have been dropped from the Monobook
-  and Chick skins
+* (bug 22096) IE50Fixes.css and IE55Fixes.css have been dropped from the
+  Monobook and Chick skins
 * Fixed bug involving unclosed "-{" markup in the language converter
-* (bug 21870) No longer include Google logo from an external server on wiki error.
+* (bug 21870) No longer include Google logo from an external server on wiki
+  error.
 * (bug 22181) Do not truncate if the ellipsis actually make the string longer
 * (bug 16039) Text disappearing after a bad image
 * (bug 18784) Internal links like [[File:Foo|caption]] should read 'caption',
@@ -10244,10 +10640,12 @@ comment from another wiki.
 * (bug 20233) ApiLogin::execute() doesn't handle LoginForm :: RESET_PASS
 * (bug 22061) API: add prop=headitems to action=parse
 * (bug 22240) API: include time in siteinfo
-* (bug 22241) Quick edit is still using the deprecated watch parameter (API: Setting default for watch/unwatch wrongly set)
+* (bug 22241) Quick edit is still using the deprecated watch parameter (API:
+  Setting default for watch/unwatch wrongly set)
 * (bug 22245) blfilterredirect=nonredirects in blredirect mode wrongly filtering
 * (bug 22248) Output extension URLs in meta=siteinfo&siprop=extensions
-* Support key-params arrays in 'descriptionmsg' in meta=siteinfo&siprop=extensions
+* Support key-params arrays in 'descriptionmsg' in
+  meta=siteinfo&siprop=extensions
 * (bug 21922) YAML output should quote asterisk when used as key
 * (bug 22297) safesubst: to allow substitution without breaking transclusion
 * (bug 18758) API read of watchlist's wl_notificationtimestamp
@@ -10481,26 +10879,28 @@ changes to languages because of Bugzilla reports.
   with class 'mw-specialpage-summary'
 * $wgSummarySpamRegex added to handle edit summary spam. This is used *instead*
   of $wgSpamRegex for edit summary checks. Text checks still use $wgSpamRegex.
-* New function to convert content text to specified language (only applies on wiki with
-  LanguageConverter class)
+* New function to convert content text to specified language (only applies on
+  wiki with LanguageConverter class)
 * (bug 17844) Redirect users to a specific page when they log in, see
   $wgRedirectOnLogin
-* Added a link to Special:UserRights on Special:Contributions for privileged users
+* Added a link to Special:UserRights on Special:Contributions for privileged
+  users
 * (bug 10336) Added new magic word {{REVISIONUSER}}, which displays the editor
   of the displayed revision
 * LinkerMakeExternalLink now has an $attribs parameter for link attributes and
   a $linkType parameter for the type of external link being made
-* (bug 17785) Dynamic dates surrounded with a <span> tag, fixing sortable tables with
-  dynamic dates.
-* (bug 4582) Provide preference-based autoformatting of unlinked dates with the dateformat
-  parser function.
-* (bug 17886) Special:Export now allows you to export a whole namespace (limited to 5000 pages)
+* (bug 17785) Dynamic dates surrounded with a <span> tag, fixing sortable tables
+  with dynamic dates.
+* (bug 4582) Provide preference-based autoformatting of unlinked dates with the
+  dateformat parser function.
+* (bug 17886) Special:Export now allows you to export a whole namespace (limited
+  to 5000 pages)
 * (bug 17714) Limited TIFF upload support now built in if 'tif' extension is
-  enabled. Image width and height are now recognized, and when using ImageMagick,
-  optional flattening to PNG or JPEG for inline display can be enabled by setting
-  $wgTiffThumbnailType
-* Renamed two input IDs on Special:Log from 'page' and 'user' to 'mw-log-page' and
-  'mw-log-user', respectively
+  enabled. Image width and height are now recognized, and when using
+  ImageMagick, optional flattening to PNG or JPEG for inline display can be
+  enabled by setting $wgTiffThumbnailType
+* Renamed two input IDs on Special:Log from 'page' and 'user' to 'mw-log-page'
+  and 'mw-log-user', respectively
 * Added $wgInvalidUsernameCharacters to disallow certain characters in
   usernames during registration (such as "@")
 * Added $wgUserrightsInterwikiDelimiter to allow changing the delimiter
@@ -10508,10 +10908,10 @@ changes to languages because of Bugzilla reports.
   on a different database
 * Add a class if 'missingsummary' is triggered to allow styling of the summary
   line
-* Title attributes are now always blank on framed and thumbnailed images, and default to blank
-  on inline images instead of defaulting to the image's filename. Additionally, the alt
-  attribute now defaults to the filename on framed and thumbnailed images if no caption or alt
-  attribute is specified.
+* Title attributes are now always blank on framed and thumbnailed images, and
+  default to blank on inline images instead of defaulting to the image's
+  filename. Additionally, the alt attribute now defaults to the filename on
+  framed and thumbnailed images if no caption or alt attribute is specified.
 
 === Bug fixes in 1.15 ===
 * (bug 16968) Special:Upload no longer throws useless warnings.
@@ -10622,7 +11022,8 @@ changes to languages because of Bugzilla reports.
   queue
 * (bug 17761) "show/hide" link in page history in now works for the first
   displayed revision if it's not the current one
-* (bug 17722) Fix regression where users are unable to change temporary passwords
+* (bug 17722) Fix regression where users are unable to change temporary
+  passwords
 * (bug 17799) Special:Random no longer throws a database error when a non-
   namespace is given, silently falls back to NS_MAIN
 * (bug 17751) The message for bad titles in WantedPages is now localized
@@ -10644,11 +11045,14 @@ changes to languages because of Bugzilla reports.
   IS NULL
 * (bug 18018) Deleting a file redirect leaves behind a malfunctioning redirect
 * (bug 17537) Disable bad zlib.output_compression output on HTTP 304 responses
-* (bug 11213) [edit] section links in printable version no longer appear when you cut-and-paste article text
+* (bug 11213) [edit] section links in printable version no longer appear when
+  you cut-and-paste article text
 * (bug 17405) "Did you mean" to mirror Go/Search behavior of original request
 * (bug 18116) 'edittools' is now output identically on edit and upload pages
-* (bug 17241) The diffonly URI parameter should cascade to "Next edit" and "Previous edit" diff links
-* (bug 16823) 'Sidebar search form should not use Special:Search view URL as target'
+* (bug 17241) The diffonly URI parameter should cascade to "Next edit" and
+  "Previous edit" diff links
+* (bug 16823) Sidebar search form should not use Special:Search view URL as
+  target
 * (bug 16343) Non-existing, but in use, category pages can be "go" match hits
 * Fixed a CSS validation issue which allowed external images to be included
   into wikis where that is disallowed by configuration.
@@ -10731,8 +11135,8 @@ changes to languages because of Bugzilla reports.
 * (bug 17288) Messages improved for default language (English)
 * (bug 12937) Update native name for Afar
 * (bug 16909) 'histlegend' now reuses messages instead of copying them
-* (bug 17832) action=delete returns 'unknownerror' instead of 'permissiondenied' when
-  the user is blocked
+* (bug 17832) action=delete returns 'unknownerror' instead of 'permissiondenied'
+  when the user is blocked
 * Traditional/Simplified Gan Chinese conversion support
 
 == MediaWiki 1.14 ==
@@ -10958,18 +11362,20 @@ The following extensions are migrated into MediaWiki 1.14:
 * Dropped old Paser_OldPP class. Only new parser with preprocessor is used.
 * Moved password reset form from Special:Preferences to Special:ResetPass
 * Added Special:ChangePassword as a special page alias for Special:ResetPass
-* Added complementary function for addHandler() called removeHandler() for removing events
+* Added complementary function for addHandler() called removeHandler() for
+  removing events
 * Improved security of file uploads for IE clients, using a reverse-engineered
   algorithm very similar to IE's content detection algorithm.
 * Cascading protection no longer requires that both edit and move are restricted
   to sysop, just edit=sysop is enough
-* (bug 2391) A warning is now shown for invalid ISBN numbers on Special:Booksources.
-* Installer has been updated to reflect the release of the GFDL 1.3. The URL for 1.2
-  has been updated, and the 1.3 URL has been given. 1.2 is still Wikipedia-compatible.
-  RightsCode was changed from 'gfdl' to 'gfdl1_2', so we can now support 1.2 as well
-  as 1.3 (gfdl1_3).
-* (bug 16293) PD URL was changed to the CreativeCommons site on PD (which auto-detects
-  your language) instead of Wikipedia.
+* (bug 2391) A warning is now shown for invalid ISBN numbers on
+  Special:Booksources.
+* Installer has been updated to reflect the release of the GFDL 1.3. The URL for
+  1.2 has been updated, and the 1.3 URL has been given. 1.2 is still
+  Wikipedia-compatible. RightsCode was changed from 'gfdl' to 'gfdl1_2', so we
+  can now support 1.2 as well as 1.3 (gfdl1_3).
+* (bug 16293) PD URL was changed to the CreativeCommons site on PD (which
+  auto-detects your language) instead of Wikipedia.
 * (bug 16635) The "view and edit watchlist" page (Special:Watchlist/edit) now
   includes a table of contents
 * File objects returned by wfFindFile() are now cached by default
@@ -10979,8 +11385,8 @@ The following extensions are migrated into MediaWiki 1.14:
 * (bug 16459) Use native getElementsByClassName where possible, for better
   performance in modern browsers
 * Enable \cancel and \cancelto in texvc (recompile required)
-* Added 'UserCryptPassword' and 'UserComparePasswords' hooks to allow extensions to implement
-  their own password hashing methods.
+* Added 'UserCryptPassword' and 'UserComparePasswords' hooks to allow extensions
+  to implement their own password hashing methods.
 * (bug 16760) Add CSS-class to action links of Special:Log
 * (bug 505) Time zones can now be specified by location in user preferences,
   avoiding the need to manually update for DST. Patch by Brad Jorsch.
@@ -11341,6 +11747,43 @@ regularly. Below only new and removed languages are listed.
 
 == MediaWiki 1.13 ==
 
+== MediaWiki 1.13.5 ==
+
+February 22, 2009
+
+This is a maintenance update to the Summer 2008 snapshot release of MediaWiki.
+
+MediaWiki is now using a "continuous integration" development model with
+quarterly snapshot releases. The latest development code is always kept
+"ready to run", and in fact runs our own sites on Wikipedia.
+
+Release branches will continue to receive security updates for about a year
+from first release, but nonessential bugfixes and feature developments
+will be made on the development trunk and appear in the next quarterly release.
+
+Those wishing to use the latest code instead of a branch release can obtain
+it from source control: http://www.mediawiki.org/wiki/Download_from_SVN
+
+== Changes since 1.13.4 ==
+
+* (bug 17449) Fixed PostgreSQL installation
+* (bug 17527) Fixed missing MySQL-specific options in installer
+
+== Changes since 1.13.3 ==
+
+A number of cross-site scripting (XSS) security vulnerabilities were discovered
+in the web-based installer (config/index.php). These vulnerabilities all
+require a live installer -- once the installer has been used to install a wiki,
+it is deactivated.
+
+Note that cross-site scripting vulnerabilities can be used to attack any website
+in the same cookie domain. So if you have an uninstalled copy of MediaWiki on
+the same site as an active web service, MediaWiki could be used to attack the
+active service.
+
+If you are hosting an old copy of MediaWiki that you have never installed, you
+are advised to remove it from the web.
+
 == Changes since 1.13.2 ==
 
 David Remahl of Apple's Product Security team has identified a number of
@@ -11442,8 +11885,8 @@ Other changes in this release:
   checked
 * (bug 13376) Use $wgPasswordSender, not $wgEmergencyContact, as return
   address for page update notification mails.
-* API: Registration time of users registered before the DB field was created is now
-  shown as empty instead of the current time.
+* API: Registration time of users registered before the DB field was created is
+  now shown as empty instead of the current time.
 * (bug 14904): fragments were lost when redirects were fixed.
 * Added magic word __STATICREDIRECT__ to suppress the redirect fixer
 * (bug 15035) Revert English linkTrail to /^([a-z]+)(.*)$/sD, as it was before
@@ -11469,15 +11912,16 @@ Other changes in this release:
     $wgAutopromote['emailconfirmed'] = APCOND_EMAILCONFIRMED;
   in your LocalSettings.php.
 * (bug 2396) New shared database configuration variables. $wgSharedPrefix allows
-  you to use a shared database with a different prefix. Or you can now use a local
-  database and use prefixes to separate wiki and the shared tables. And the new
-  $wgSharedTables variable allows you to specify a list of tables to share.
+  you to use a shared database with a different prefix. Or you can now use a
+  local database and use prefixes to separate wiki and the shared tables. And
+  the new $wgSharedTables variable allows you to specify a list of tables to
+  share.
 * Automatic edit summaries can be disabled with $wgUseAutomaticEditSummaries
 * Duplicates of images are now shown on the image page
-* $wgRCFilterByAge allows for the list of dates in recent changes special pages to
-  be filtered to only those within the range of $wgRCMaxAge
-* $wgRCLinkLimits and $wgRCLinkDays allow for customization of the list and limits
-  displayed on the recent changes special pages
+* $wgRCFilterByAge allows for the list of dates in recent changes special pages
+  to be filtered to only those within the range of $wgRCMaxAge
+* $wgRCLinkLimits and $wgRCLinkDays allow for customization of the list and
+  limits displayed on the recent changes special pages
 * The "createpage" permission is no longer required when uploading if the target
   image page already exists
 * $wgMaximumMovedPages restricts the number of pages that can be moved at once
@@ -11495,8 +11939,8 @@ Other changes in this release:
   Default: false
 * Removed $wgEnableCascadingProtection option. Disabling cascading protection
   is no longer possible.
-* $wgMessageCacheType defines now the type of cache used by the MessageCache class,
-  previously it was choosen based on $wgParserCacheType
+* $wgMessageCacheType defines now the type of cache used by the MessageCache
+  class, previously it was choosen based on $wgParserCacheType
 * $wgExtensionAliasesFiles option to simplify adding aliases to special pages
   provided by extensions, in a similar way to $wgExtensionMessagesFiles
 * Added $wgXMLMimeTypes, an array of XML mimetypes we can check for
@@ -11586,8 +12030,8 @@ Other changes in this release:
   'import-upload' instead of 'upload'
 * Add information about user group membership to Special:Preferences
 * (bug 14146) Wrap usage section on imagepages into <div>s.
-* New layout for Special:Specialpages. Restricted pages are marked but not separated
-  from other pages in their group.
+* New layout for Special:Specialpages. Restricted pages are marked but not
+  separated from other pages in their group.
 * (bug 14263) Show a diff of the revert on rollback notification page.
 * (bug 13434) Show a warning when hash identical files exist
 * Sidebar is now cached for all languages
@@ -11596,15 +12040,16 @@ Other changes in this release:
   edits in the last $wgActiveUserDays days.
 * SpecialSearchResults hook now passes results by reference, so they can be
   changed by extensions.
-* Add a new hook LinkerMakeExternalLink to allow extensions to modify the output of
-  external links.
+* Add a new hook LinkerMakeExternalLink to allow extensions to modify the output
+  of external links.
 * (bug 14132) Allow user to disable bot edits from being output to UDP.
-* (bug 14328) jsMsg() within Wikibits now accepts a DOM object, not just a string
+* (bug 14328) jsMsg() within Wikibits now accepts a DOM object, not just a
+  string
 * (bug 14558) New system message (emailuserfooter) is now added to the footer of
   e-mails sent with Special:Emailuser
 * Add support for Hijri (Islamic) calendar
-* Add a new hook LinkerMakeExternalImage to allow extensions to modify the output
-  of external (hotlinked) images.
+* Add a new hook LinkerMakeExternalImage to allow extensions to modify the
+  output of external (hotlinked) images.
 * (bug 14604) Introduced the following features for the LanguageConverter:
   Multi-tag support, single conversion flag, remove conversion flag on a single
   page, description flag, variant name, multi-variant fallbacks.
@@ -11621,13 +12066,13 @@ Other changes in this release:
 * Allow the search box, toolbox and languages box in the Monobook sidebar to be
   moved around arbitrarily using special sections in [[MediaWiki:Sidebar]]:
   SEARCH, TOOLBOX and LANGUAGES
-* Add a new hook NormalizeMessageKey to allow extensions to replace messages before
-  the database is potentially queried
+* Add a new hook NormalizeMessageKey to allow extensions to replace messages
+  before the database is potentially queried
 * (bug 9736) Redirects on Special:Fewestrevisions are now marked as such.
 * New date/time formats in Cs localization according to ČSN and PČP.
 * Special:Recentchangeslinked now includes changes to transcluded pages and
-  displayed images; also, the "Show changes to pages linked" checkbox now works on
-  category pages too, showing all links that are not categorizations
+  displayed images; also, the "Show changes to pages linked" checkbox now works
+  on category pages too, showing all links that are not categorizations
 * (bug 4578) Automatically fix redirects broken by a page move
 
 === Bug fixes in 1.13 ===
@@ -11640,7 +12085,8 @@ Other changes in this release:
 * Make the default filepageexists message accurate
 * (bug 12988) $wgMinimalPasswordLength no longer breaks create user by email
 * (bug 13022) Fix upload from URL on PHP 5.0.x
-* (bug 13132) Unable to unprotect pages protected with earlier versions of MediaWiki
+* (bug 13132) Unable to unprotect pages protected with earlier versions of
+  MediaWiki
 * (bug 12723) OpenSearch description name now uses more compact language code
   to avoid passing the length limit as often, is customizable per site via
   'opensearch-desc' message.
@@ -11649,7 +12095,8 @@ Other changes in this release:
 * (bug 12575) Prevent duplicate patrol log entries from being created
 * (bug 13174) __HIDDENCAT__ now applies only to category pages
 * (bug 13031) Add links to user pages in e-mail form
-* (bug 13147) Description for categoriespagetext (used in Special:Categories) reworded
+* (bug 13147) Description for categoriespagetext (used in Special:Categories)
+  reworded
 * (bug 11561) Fix fatal error when calling action=revert to non-image page
 * (bug 12430) Fix call to private method LinkFilter::makeRegex fatal error in
   maintenance/cleanupSpam.php
@@ -11664,7 +12111,8 @@ Other changes in this release:
 * (bug 13274) Change links for messages to ucfirst
 * (bug 13273) Un-hardcode some punctuation (add new messages colon-separator,
   autocomment-prefix)
-* Parse MediaWiki message translations with a correct language setting on preview
+* Parse MediaWiki message translations with a correct language setting on
+  preview
 * (bug 13281) Treat X-Forwarded-For, Client-ip and User-Agent headers as
   case-insensitive names.
 * Adding the fix for lists in RTL wikis to more skins, and fixing the image toc
@@ -11718,7 +12166,8 @@ Other changes in this release:
 * (bug 13576) maintenance/rebuildrecentchanges.php fails
 * (bug 13441) Allow Special:Recentchanges to show bots only
 * (bug 13431) Show true message source in Special:Allmessages&ot=php / xml
-* (bug 13463) Login successful page doesn't use user's preferred interface language
+* (bug 13463) Login successful page doesn't use user's preferred interface
+  language
 * (bug 13630) Fixed warnings for pass by reference at call time in
   Special:Revisiondelete when generating the log entry.
 * (bug 12064) BeforePageDisplay hook is now called for all skins
@@ -11748,7 +12197,8 @@ Other changes in this release:
 * Do not display empty columns on Special:UserRights if all groups are
   changeable or all unchangeable
 * Fix fatal error on calling PAGESINCATEGORY with invalid category name
-* (bug 13793) Special:Whatlinkshere filters wrong - after paginating instead of before
+* (bug 13793) Special:Whatlinkshere filters wrong - after paginating instead of
+  before
 * (bug 13796) Show links to parent pages even if some of them are missing
 * (bug 13816) Filter by main namespace doesn't work on WhatLinksHere
 * (bug 13822) Fatal error on some pages when calculating subpage subtitle
@@ -11774,12 +12224,15 @@ Other changes in this release:
 * (bug 13934) Fixing the link to GNU General Public License Version 2
 * Show correct accesskey prefix for Firefox 3 beta (Alt-Shift-, not Alt-)
 * (bug 13949) Special:PrefixIndex/AllPages paging links contain invalid XML
-* (bug 13770) Use Preprocessor_Hash by default to avoid missing DOM module errors
+* (bug 13770) Use Preprocessor_Hash by default to avoid missing DOM module
+  errors
 * (bug 13982) Disable ccmeonemails preference when user-to-user mails disabled
 * (bug 13615) Update case mappings and normalization to Unicode 5.1.0
-  Note that case mappings will only be used if mbstring extension is not present.
+  Note that case mappings will only be used if mbstring extension is not
+  present.
 * (bug 14044) Don't increment page view counters on views from bot users
-* (bug 14042) Calling Database::limitResult() misplaced the comment in the log file
+* (bug 14042) Calling Database::limitResult() misplaced the comment in the log
+  file
 * (bug 14047) Fix regression in installer which hid DB-specific options
   Also makes SQLite path configurable in the installer.
 * (bug 13546) Follow image redirects on image page
@@ -11983,9 +12436,143 @@ Other changes in this release:
   the page
 * list=exturlusage in "list all links" mode can now filter by protocol
 
+== MediaWiki 1.12 ==
+
+== MediaWiki 1.12.4 ==
 
+February 7, 2009
 
-== MediaWiki 1.12 ==
+A number of cross-site scripting (XSS) security vulnerabilities were discovered
+in the web-based installer (config/index.php). These vulnerabilities all
+require a live installer -- once the installer has been used to install a wiki,
+it is deactivated.
+
+Note that cross-site scripting vulnerabilities can be used to attack any
+website in the same cookie domain. So if you have an uninstalled copy of
+MediaWiki on the same site as an active web service, MediaWiki could be used to
+attack the active service.
+
+If you are hosting an old copy of MediaWiki that you have never installed, you
+are advised to remove it from the web.
+
+== MediaWiki 1.12.3 ==
+
+* Fixed packaging/distribution error. Many files were missing from the
+distributed tarball.
+
+== MediaWiki 1.12.2 ==
+
+David Remahl of Apple's Product Security team has identified a number of
+security issues in previous releases of MediaWiki. Subsequent analysis by the
+MediaWiki development team expanded the scope of these vulnerabilities. The
+issues with a significant impact are as follows:
+
+* A local script injection vulnerability affecting Internet Explorer clients
+for all MediaWiki installations with uploads enabled. [CVE-2008-5250]
+* A local script injection vulnerability affecting clients with SVG scripting
+capability (such as Firefox 1.5+), for all MediaWiki installations with SVG
+uploads enabled. [CVE-2008-5250]
+* A CSRF vulnerability affecting the Special:Import feature, for all MediaWiki
+installations since the feature was introduced in 1.3.0. [CVE-2008-5252]
+
+A local script injection vulnerability allows an attacker with a wiki account
+to steal another user's login session, and to act as that user on the wiki. The
+attacker uploads a malicious script file, and tricks the victim into executing
+it.
+
+CSRF vulnerabilities allow an attacker to act as an authorised user on the
+wiki, but unlike an XSS vulnerability, the attacker can only act as the user in
+a specific and restricted way. The present CSRF vulnerability allows pages to
+be edited, with forged revision histories. Like an XSS vulnerability, the
+authorised user must visit the malicious web page to activate the attack.
+
+These three vulnerabilities are all fixed in this release.
+
+David Remahl also reminded us of some security-related configuration issues:
+
+* By default, MediaWiki stores a backup of deleted images in the images/deleted
+directory. If you do not want these images to be publically accessible, make
+sure this directory is not accessible from the web. MediaWiki takes some steps
+to avoid leaking these images, but these measures are not perfect.
+* Set display_errors=off in your php.ini to avoid path disclosure via PHP fatal
+errors. This is the default on most shared web hosts.
+* Enabling MediaWiki's debugging features, such as $wgShowExceptionDetails, may
+lead to path disclosure.
+
+Other changes in this release:
+
+* Avoid fatal error in profileinfo.php when not configured.
+* Add a .htaccess to deleted images directory for additional protection against
+exposure of deleted files with known SHA-1 hashes on default installations.
+* Avoid streaming uploaded files to the user via index.php. This allows
+security-conscious users to serve uploaded files via a different domain, and
+thus client-side scripts executed from that domain cannot access the login
+cookies. Affects Special:Undelete, img_auth.php and thumb.php.
+* When streaming files via index.php, use the MIME type detected from the file
+extension, not from the data. This reduces the XSS attack surface.
+* Blacklist redirects via Special:Filepath. Such redirects exacerbate any XSS
+vulnerabilities involving uploads of files containing scripts.
+* Internationalisation updates.
+
+== MediaWiki 1.12.1 ==
+
+Changes since 1.12.0:
+* (bug [[bugzilla:13522|13522]]) Fix fatal error in Parser::extractTagsAndParams
+* (bug [[bugzilla:12077|12077]]) Fix HTML nesting for TOC
+* (bug [[bugzilla:13532|13532]]) Use proper timestamp call when reverting images
+* (bug [[bugzilla:13649|13649]], [[bugzilla:14084|14084]]) Bad call to
+wfTimestamp()
+* (bug [[bugzilla:13770|13770]]) Use Preprocessor_Hash by default to avoid
+missing DOM module errors
+* (bug [[bugzilla:13442|13442]]) API: Missing pages in prop=langlinks and
+prop=extlinks are now handled properly.
+* (bug [[bugzilla:13482|13482]]) API: Disabled search types handled properly
+* (bug [[bugzilla:13836|13836]]) API: Fixed fatal errors resulting from
+combining iiprop=metadata  with format=xml
+* (bug [[bugzilla:11633|11633]]) API: Explicitly convert redirect titles to
+strings due to PHP's very weak typing on array keys.
+* API: Fixing main page display in meta=siteinfo
+* (bug [[bugzilla:11719|11719]]) API: Remove trailing blanks in YAML output.
+* (bug [[bugzilla:13718|13718]]) API: Return the proper continue parameter for
+cmsort=timestamp
+* Security: Work around misconfiguration by requiring strict comparisons for
+in_array in User::isAllowed().
+* Security: Fixed XSS vulnerability in useskin parameter.
+
+== MediaWiki 1.12.0 ==
+
+This is the quarterly branch release of [[MediaWiki]] for Winter 2008.
+
+MediaWiki is now using a "continuous integration" development model with
+quarterly snapshot releases. The latest development code is always kept "ready
+to run", and in fact runs our own sites on [[wikipedia:|Wikipedia]].
+
+Release branches will continue to receive security updates for about a year
+from first release, but nonessential bugfixes and feature developments will be
+made on the development trunk and appear in the next quarterly release.
+
+Those wishing to use the latest code instead of a branch release can obtain it
+from source control: [[Download from SVN]].
+
+Changes since 1.12.0rc1:
+*(bug [[bugzilla:13359|13359]]) Double-escaping in [[Special:Allpages]].
+*Localization updates.
+
+== MediaWiki 1.12.0rc1 ==
+
+This is a release candidate of the Winter 2008 quarterly snapshot release of
+[[MediaWiki]].
+
+MediaWiki is now using a "continuous integration" development model with
+quarterly snapshot releases. The latest development code is always kept "ready
+to run", and in fact runs our own sites on [[wikipedia:|Wikipedia]].
+
+Release branches will continue to receive security updates for about a year
+from first release, but nonessential bugfixes and feature developments will be
+made on the development trunk and appear in the next quarterly release.
+
+Those wishing to use the latest code instead of a branch release can obtain it
+from source control: [[Download from SVN]].
 
 This is the Winter 2007 quarterly release.
 
@@ -12143,7 +12730,8 @@ it from source control: https://www.mediawiki.org/wiki/Download_from_SVN
 * (bug 12857) Patrol link on new pages should clear floats
 * (bug 12968) Render redirect wikilinks in a redirect class for customization
   via user/site CSS.
-* EditPageBeforeEditButtons hook added for altering the edit buttons below the edit box
+* EditPageBeforeEditButtons hook added for altering the edit buttons below the
+  edit box
 
 === Bug fixes in 1.12 ===
 
@@ -12363,9 +12951,11 @@ it from source control: https://www.mediawiki.org/wiki/Download_from_SVN
 * Fixing message cache updates for MediaWiki messages moves
 * (bug 12815) Signature timestamps were always in UTC, even if the timezone code
   in parentheses after them claimed otherwise
-* (bug 12732) Fix installer and searching to handle built-in tsearch2 for Postgres.
+* (bug 12732) Fix installer and searching to handle built-in tsearch2 for
+  Postgres.
 * (bug 12784) Change "bool" types to smallint to handle Postgres 8.3 strictness.
-* (bug 12301) Allow maintenance/findhooks.php to search hooks in multiple directories.
+* (bug 12301) Allow maintenance/findhooks.php to search hooks in multiple
+  directories.
 * (bug 7681, 11559) Cookie values no longer override GET and POST variables.
 * (bug 5262) Fully-qualified $wgStylePath no longer corrupted on XML feeds
 * (bug 3269) Inaccessible titles ending in '/.' or '/..' now forbidden.
@@ -12374,8 +12964,8 @@ it from source control: https://www.mediawiki.org/wiki/Download_from_SVN
 * (bug 11567) Fix error checking for PEAR::Mail. UserMailer::send() now returns
   true-or-WikiError, which seems to be the calling convention expected by half
   its callers already
-* (bug 12846) IE rtl.css issue in RTL wikis special:Preferences when selecting an
-  LTR user language
+* (bug 12846) IE rtl.css issue in RTL wikis special:Preferences when selecting
+  an LTR user language
 * (bug 13005) DISPLAYTITLE does not work on preview
 * (bug 13004) Fix error on Postgres searches that return too many results.
 
@@ -12539,6 +13129,76 @@ Full API documentation is available at https://www.mediawiki.org/wiki/API
 
 == MediaWiki 1.11 ==
 
+== MediaWiki 1.11.2 ==
+
+March 2, 2008
+
+This is a security release of the Fall 2007 snapshot release of MediaWiki.
+Possible cross-site information leaks using the callback parameter for
+JSON-formatted results in the API are prevented by dropping user credentials.
+
+MediaWiki release versions prior to 1.11 are not vulnerable, as they do not
+include the callback feature which allows client-side JavaScript on other sites
+to reach API data.
+
+Changes in this release:
+
+* User credentials are dropped for API JSON requests using a callback
+* Edit tokens are not reported for API JSON requests using a callback
+
+== MediaWiki 1.11.1 ==
+
+January 23, 2008
+
+This is a security and bugfix release of the Fall 2007 snapshot release of
+ MediaWiki. A potential XSS injection vector affecting api.php only for
+ Microsoft Internet Explorer users has been closed.
+
+Changes in this release:
+* (bug [[bugzilla:11450|11450]]) Fix creation of objectcache table on upgrade
+* (bug [[bugzilla:11462|11462]]) Fix typo in LanguageGetSpecialPageAliases hook
+name
+* Fix regression in LinkBatch.php breaking PHP 5.0
+* Security fix for API on MSIE
+
+To work around the vulnerability without upgrading, you may disable the API if
+you don't need it:
+:[[Manual:$wgEnableAPI|$wgEnableAPI]] = false;
+
+Not vulnerable versions:
+* 1.12 or later
+* 1.11 >= 1.11.1
+* 1.10 >= 1.10.3
+* 1.9 >= 1.9.5
+* 1.8 any version (if $wgEnableAPI has been left off)
+
+Vulnerable versions:
+* 1.11 <= 1.11.0rc1
+* 1.10 <= 1.10.2
+* 1.9 <= 1.9.4
+* 1.8 any version (if $wgEnableAPI has been switched on)
+
+MediaWiki 1.7 and below are not affected as they do not include the API
+functionality, however the BotQuery extension is similarly vulnerable unless
+updated to the latest SVN version.
+
+== MediaWiki 1.11.0 ==
+
+September 10, 2007
+
+This is the Fall 2007 snapshot release of MediaWiki.
+
+MediaWiki is now using a "continuous integration" development model with
+quarterly snapshot releases. The latest development code is always kept "ready
+to run", and in fact runs our own sites on Wikipedia.
+
+Release branches will continue to receive security updates for about a year
+from first release, but nonessential bugfixes and feature developments will be
+made on the development trunk and appear in the next quarterly release.
+
+Those wishing to use the latest code instead of a branch release can obtain it
+from source control: [[Download from SVN]]
+
 This is the Summer 2007 branch release of MediaWiki.
 
 MediaWiki is now using a "continuous integration" development model with
@@ -12552,6 +13212,33 @@ will be made on the development trunk and appear in the next quarterly release.
 Those wishing to use the latest code instead of a branch release can obtain
 it from source control: https://www.mediawiki.org/wiki/Download_from_SVN
 
+== Changes since 1.11.0rc1 ==
+
+A possible HTML/XSS injection vector in the API pretty-printing mode has been
+found and fixed.
+
+The vulnerability may be worked around in an unfixed version by simply
+disabling the API interface if it is not in use, by adding this to
+[[Manual:LocalSettings.php|LocalSettings.php]]:<br />
+<code>[[Manual:$wgEnableAPI|$wgEnableAPI]] = false;</code> <br />
+(This is the default setting in 1.8.x.)
+
+Not vulnerable versions:
+* 1.11 >= 1.11.0
+* 1.10 >= 1.10.2
+* 1.9 >= 1.9.4
+* 1.8 >= 1.8.5
+
+Vulnerable versions:
+* 1.11 <= 1.11.0rc1
+* 1.10 <= 1.10.1
+* 1.9 <= 1.9.3
+* 1.8 <= 1.8.4 (if [[Manual:$wgEnableAPI|$wgEnableAPI]] has been switched on)
+
+MediaWiki 1.7 and below are not affected as they do not include the faulty
+function, however the [[Extension:BotQuery|BotQuery extension]] is similarly
+vulnerable unless updated to the latest SVN version.
+
 == Configuration changes since 1.10 ==
 
 * $wgThumbUpright - Adjust width of upright images when parameter 'upright' is
@@ -12560,7 +13247,8 @@ it from source control: https://www.mediawiki.org/wiki/Download_from_SVN
   usergroups
 * $wgEnotifImpersonal, $wgEnotifUseJobQ - Bulk mail options for large sites
 * $wgShowHostnames - Expose server host names through the API and HTML comments
-* $wgSaveDeletedFiles has been removed, the feature is now enabled unconditionally
+* $wgSaveDeletedFiles has been removed, the feature is now enabled
+unconditionally
 
 == New features since 1.10 ==
 
@@ -12681,8 +13369,8 @@ it from source control: https://www.mediawiki.org/wiki/Download_from_SVN
   than good.  Proper handheld support will be added at a future date.  For now,
   display should be acceptable either with CSS turned off or when using a so-
   phisticated handheld browser.
-* (bug 3173) Option to offer exported pages as a download, rather than displaying
-  inline, as in most browsers
+* (bug 3173) Option to offer exported pages as a download, rather than
+  displaying inline, as in most browsers
 * Pass the user as an argument to 'isValidPassword' hook callbacks; see
   docs/hooks.txt for more information
 * Introduce 'UserGetRights' hook; see docs/hooks.txt for more information
@@ -12878,7 +13566,8 @@ it from source control: https://www.mediawiki.org/wiki/Download_from_SVN
 * (bug 6965) Cannot include "Template:R" with {{R}} (magic word conflict)
 * Padding parser functions now work with strings like '0' that evaluate to false
 * (bug 10332) Title->userCan( 'edit' ) may return false positive
-* Fix bug with <nowiki> in front of links for wikis where linkPrefixExtension is true
+* Fix bug with <nowiki> in front of links for wikis where linkPrefixExtension is
+  true
 * (bug 10552) Suppress rollback link in history for single-revision pages
 * (bug 10538) Gracefully handle invalid input on move success page
 * Fix for Esperanto double-x-encoding in move success page
@@ -13008,8 +13697,9 @@ Full API documentation is available at https://www.mediawiki.org/wiki/API
 * (bug 10392) Include MediaWiki version details in version output
 * (bug 10411) Site language in meta=siteinfo
 * (bug 10391) action=help doesn't return help if format is fancy markup
-* backlinks, embeddedin and imageusage lists should use (bl|ei|iu)title parameter
-  instead of titles. Titles for these lists is obsolete and might stop working soon.
+* backlinks, embeddedin and imageusage lists should use (bl|ei|iu)title
+  parameter instead of titles. Titles for these lists is obsolete and might stop
+  working soon.
 * Added prop=imageinfo - gets image properties and upload history
 * (bug 10211) Added db server replication lag information in meta=siteinfo
 * Added external url search within wiki pages (list=exturlusage)
@@ -13017,9 +13707,12 @@ Full API documentation is available at https://www.mediawiki.org/wiki/API
 * Added registered users enumeration (list=allusers)
 * Added full text search in titles and content (list=search)
 * (bug 10684) Expanded list=allusers functionality
-* Possible breaking change: prop=revisions no longer includes pageid for rvprop=ids
-* Added rvprop=size to prop=revisions (The size will not be shown if it is NULL in the database)
-* list=allpages now allows to filter by article min/max size and protection status
+* Possible breaking change: prop=revisions no longer includes pageid for
+  rvprop=ids
+* Added rvprop=size to prop=revisions (The size will not be shown if it is NULL
+  in the database)
+* list=allpages now allows to filter by article min/max size and protection
+  status
 * Added site statistics (siprop=statistics for meta=siteinfo)
 * (bug 10902) Unable to fetch user contributions from IP addresses
 * `list=usercontribs` no longer requires that the user exist
@@ -13033,7 +13726,8 @@ Full API documentation is available at https://www.mediawiki.org/wiki/API
 * (bug 10898) API does not return an edit token for non-existent pages
 * (bug 10890) Timestamp support for categorymembers query
 * (bug 10980) Add exclude redirects on backlinks
-* IPv6 titles in User namespace are normalized (run cleanupTitles.php to fix any old stray pages)
+* IPv6 titles in User namespace are normalized (run cleanupTitles.php to fix any
+  old stray pages)
 
 == Maintenance script changes since 1.10 ==
 
@@ -13127,6 +13821,121 @@ Full API documentation is available at https://www.mediawiki.org/wiki/API
 
 == MediaWiki 1.10 ==
 
+== MediaWiki 1.10.4 ==
+
+March 2, 2008
+
+* Correction for API path fix, broken in 1.10.3
+
+== MediaWiki 1.10.3 ==
+
+January 23, 2008
+
+This is a security update to the Winter 2007 quarterly release. A potential
+XSS injection vector affecting api.php only for Microsoft Internet Explorer
+users has been closed.
+
+
+To work around the vulnerability without upgrading, you may disable the API if
+you don't need it:
+
+:[[Manual:$wgEnableAPI|$wgEnableAPI]] = false;
+
+Not vulnerable versions:
+* 1.12 or later
+* 1.11 >= 1.11.1
+* 1.10 >= 1.10.3
+* 1.9 >= 1.9.5
+* 1.8 any version (if $wgEnableAPI has been left off)
+
+Vulnerable versions:
+* 1.11 <= 1.11.0rc1
+* 1.10 <= 1.10.2
+* 1.9 <= 1.9.4
+* 1.8 any version (if $wgEnableAPI has been switched on)
+
+MediaWiki 1.7 and below are not affected as they do not include the API
+functionality, however the BotQuery extension is similarly vulnerable unless
+updated to the latest SVN version.
+
+== MediaWiki 1.10.2 ==
+September 10, 2007
+
+This is a security fix update to the Spring 2007 quarterly release snapshot. A
+possible HTML/XSS injection vector in the API pretty-printing mode has been
+found and fixed.
+
+The vulnerability may be worked around in an unfixed version by simply
+disabling the API interface if it is not in use, by adding this to
+LocalSettings.php:
+:[[Manual:$wgEnableAPI|$wgEnableAPI]] = false;
+
+Not vulnerable versions:
+* 1.11 >= 1.11.0
+* 1.10 >= 1.10.2
+* 1.9 >= 1.9.4
+* 1.8 >= 1.8.5
+
+Vulnerable versions:
+* 1.11 <= 1.11.0rc1
+* 1.10 <= 1.10.1
+* 1.9 <= 1.9.3
+* 1.8 <= 1.8.4 (if $wgEnableAPI has been switched on)
+
+MediaWiki 1.7 and below are not affected as they do not include the faulty
+function, however the BotQuery extension is similarly vulnerable unless updated
+to the latest SVN version.
+
+== MediaWiki 1.10.1 ==
+July 13, 2007
+
+This is a bugfix update to the Spring 2007 quarterly release snapshot. A number
+of fixes to improve compatibility with PostgreSQL, some versions of MySQL, and
+some PHP configurations are included.
+
+Changes since 1.10.0:
+
+* (bug [[bugzilla:9417|9417]]) Uploading new versions of images when using
+Postgres no longer  throws warnings.
+* (bug [[bugzilla:9908|9908]]) Using tsearch2 with Postgres 8.1 no longer gives
+an error.
+* (bug [[bugzilla:9973|9973]]) Changed size was shown in advanced recentchanges
+collapsible items with $wgRCShowChangedSized = false.
+* Fixed installation on MyISAM or old InnoDB with charset=utf8, was giving
+overlong key errors.
+* Fixed zero-padding issues with MySQL 5 binary schema
+* (bug [[bugzilla:9820|9820]]) session.save_path check no longer halts
+installation, but warns of possible bad values
+* (bug [[bugzilla:9978|9978]]) Fixed session.save_path validation when using
+extended configuration format, e.g. "5;/tmp"
+
+== MediaWiki 1.10.0 ==
+May 9, 2007
+
+This is the quarterly release snapshot for Spring 2007. See below for a full
+list of changes since the 1.9.x series.
+
+Changes since 1.10.0rc2:
+
+* (bug [[bugzilla:9808|9808]]) Fix regression that ignored user 'rclimit'
+option for Special:Contributions
+
+== MediaWiki 1.10.0rc2 ==
+May 4, 2007
+
+THIS IS A RELEASE CANDIDATE MADE AVAILABLE FOR TESTING!
+A FINAL 1.10.0 RELEASE WILL APPEAR WITHIN A FEW DAYS.
+
+Changes since 1.10.0rc1:
+* Various l10n fixes and updates
+* Fix for upgrade of page_restrictions table
+* (bug [[bugzilla:9780|9780]]) Fix normalization of titles with initial colon
+followed by whitespace
+* Fix for regression in upload: wrong size info saved into image table
+* Avoid cyclic stub problems when authorization hooks do funny things with the
+user and the database at load time
+
+== MediaWiki 1.10.0rc1 ==
 This is the Spring 2007 branch release of MediaWiki.
 
 MediaWiki is now using a "continuous integration" development model with
@@ -13142,14 +13951,14 @@ it from source control: https://www.mediawiki.org/wiki/Download_from_SVN
 
 == Configuration changes ==
 
-* A new switch $wgCommandLineDarkBg used by maintenance scripts (parserTests.php).
-  It lets you specify if your terminal use a dark background, the colorized
-  output will be made lighter making things easier to read.
+* A new switch $wgCommandLineDarkBg used by maintenance scripts
+  (parserTests.php). It lets you specify if your terminal use a dark background,
+  the colorized output will be made lighter making things easier to read.
 * The minimum permissions needed to edit a page in each namespace can now be
   customized via the $wgNamespaceProtection array. By default, editing pages in
   the MediaWiki namespace requires "editinterface" permission, as before.
-* Allow restriction of autoconfirmed permission by edit count. New global setting
-  $wgAutoConfirmCount (defaulting to zero, naturally).
+* Allow restriction of autoconfirmed permission by edit count. New global
+  setting $wgAutoConfirmCount (defaulting to zero, naturally).
 * Added rate limiter for Special:Emailuser
 * Private logs can now be created using $wgLogRestrictions
 * (Bug 8590) limited HTML is now always enabled ($wgUserHtml = true).
@@ -13216,7 +14025,8 @@ it from source control: https://www.mediawiki.org/wiki/Download_from_SVN
 * (bug 6997) Link from Special:log/block to unblock form
 * (bug 9117) Link from Special:log/delete to undelete form
 * Link from Special:log/protect to change protection form
-* (bug 1196) Add IPv6 support added to blocks, more consistancy for IPv6 contribs
+* (bug 1196) Add IPv6 support added to blocks, more consistancy for IPv6
+  contribs
 * (bug 3984) Searching in logs by title%
 * Show thumbnail of existing image if image exists already under this filename
 * (bug 5546) Watchlist reflects logged actions like move, protection, undelete
@@ -13225,19 +14035,21 @@ it from source control: https://www.mediawiki.org/wiki/Download_from_SVN
 * Warning on upload of images with uppercase extension if image with lowercase
   extension exists
 * (bug 4624) Namespace selection for Special:Whatlinkshere
-* Introduce PageHistoryBeforeList and PageHistoryLineEnding hooks; see docs/hooks.txt
-  for more information
-* (bug 9397) Introduce "sp-contributions-footer" and "sp-contributions-footer-anon"
-  messages, shown at the end of Special:Contributions as appropriate for the target
+* Introduce PageHistoryBeforeList and PageHistoryLineEnding hooks; see
+  docs/hooks.txt for more information
+* (bug 9397) Introduce "sp-contributions-footer" and
+  "sp-contributions-footer-anon" messages, shown at the end of
+  Special:Contributions as appropriate for the target
 * (bug 8421) Expose current action in JavaScript globals (as 'wgAction')
 * (bug 9069) Use galleries in query pages dedicated to images
-* (bug 9177) Installer now warns of various conditions affecting session.save_path
-  which can lead to broken session storage
+* (bug 9177) Installer now warns of various conditions affecting
+  session.save_path which can lead to broken session storage
 * (bug 9046) Special page to list pages without language links
 * (bug 9508) Special page to list articles with the fewest revisions
 * Introduce 'FileUpload' hook; see docs/hooks.txt for more information
 * Introduce 'SearchUpdate' hook; see docs/hooks.txt for more information
-* Introduce 'mywatchlist' message; used on personal menu to link to watchlist page
+* Introduce 'mywatchlist' message; used on personal menu to link to watchlist
+  page
 * Introduce magic word {{NUMBEROFEDITS}}
 * Introduced media handlers for file-type specific operations.
 * Improved error reporting for image thumbnailing
@@ -13246,7 +14058,8 @@ it from source control: https://www.mediawiki.org/wiki/Download_from_SVN
   500 characters
 * Predefined block reasons added to Special:Blockip
 * (bug 9196) Installer now check that zend.ze1_compatibility_mode is off
-* (bug 9697) Introduce 'InternalParseBeforeLinks' hook; see docs/hooks.txt for more information
+* (bug 9697) Introduce 'InternalParseBeforeLinks' hook; see docs/hooks.txt for
+  more information
 * 'contribsub' message changed to 'contribsub2' with two parameters to permit
   better localization.  Change is reverse-compatible and can be ignored for
   most wikis.
@@ -13304,8 +14117,8 @@ it from source control: https://www.mediawiki.org/wiki/Download_from_SVN
 * Ignore self closing on closing tags ( '</div />' now gives '</div>')
 * (bug 8673) Minor fix for web service API content-type header
 * Fix API revision list on PHP 5.2.1; bad reference assignment
-* (bug 8688) Handle underscores/spaces in Special:Blockip and Special:Ipblocklist
-  in a consistent manner
+* (bug 8688) Handle underscores/spaces in Special:Blockip and
+  Special:Ipblocklist in a consistent manner
 * (bug 8701) Check database lock status when blocking/unblocking users
 * ParserOptions and ParserOutput classes are now in their own files
 * (bug 8708) Namespace translations for Zealandic language
@@ -13508,8 +14321,8 @@ it from source control: https://www.mediawiki.org/wiki/Download_from_SVN
 * (bug 8780) Clarify message for command-line scripts if LocalSettings.php
   exists but is not readable
 * dumpBackup / importDump now work with PostgreSQL
-* (bug 8975) Use "Maintenance script" as the default username for importImages.php
-  and importTextFile.php scripts
+* (bug 8975) Use "Maintenance script" as the default username for
+  importImages.php and importTextFile.php scripts
 * (bug 8933) Fix maintenance/reassignEdits.php script
 * (bug 9440) Added "mediawikiwiki" interwiki prefix to MediaWiki.org
 * (bug 2979) Import now gracefully skips invalid titles with a warning
@@ -13616,21 +14429,170 @@ break. Don't forget to always back up your database before upgrading!
 See the file UPGRADE for more detailed upgrade instructions.
 
 = MediaWiki release notes =
-
 Security reminder: MediaWiki does not require PHP's register_globals
 setting since version 1.2.0. If you have it on, turn it *off* if you can.
 
+= MediaWiki 1.9 =
 
-== Changes since 1.8 ==
+== MediaWiki 1.9.6 ==
 
-* (bug 8200) Make category lists sorted by name when using Postgres.
-* (bug 7841) Support 'IGNORE' inserts for Postgres, fixes watchlist
-  adding problem.
-* (bug 6835) Removing the includes/Parser.php::getTemplateArgs() function,
-  because it seems to be unused.
-* (bug 7139) Increasing the visual width of the edit summary field on larger
-  screen sizes, for the default monobook skin.
-* Fix PHP notice and estimates for dumpBackup.php and friends
+March 2, 2008
+
+* Correction for API path fix, broken in 1.9.5
+
+== MediaWiki 1.9.5 ==
+
+January 23, 2008
+
+This is a security update to the Winter 2007 quarterly release. A potential XSS
+injection vector affecting api.php only for Microsoft Internet Explorer users
+has been closed.
+
+
+To work around the vulnerability without upgrading, you may disable the API if
+you don't need it:
+
+:[[Manual:$wgEnableAPI|$wgEnableAPI]] = false;
+
+Not vulnerable versions:
+* 1.12 or later
+* 1.11 >= 1.11.1
+* 1.10 >= 1.10.3
+* 1.9 >= 1.9.5
+* 1.8 any version (if $wgEnableAPI has been left off)
+
+Vulnerable versions:
+* 1.11 <= 1.11.0rc1
+* 1.10 <= 1.10.2
+* 1.9 <= 1.9.4
+* 1.8 any version (if $wgEnableAPI has been switched on)
+
+MediaWiki 1.7 and below are not affected as they do not include the API
+functionality, however the BotQuery extension is similarly vulnerable unless
+updated to the latest SVN version.
+
+== MediaWiki 1.9.4 ==
+
+September 10, 2007
+
+This is a security and bug fix update to the Winter 2007 quarterly release.
+Minor compatibility fixes for IIS 5 are included.
+
+* (bug [[bugzilla:8847|8847]]) Strip spurious #fragments from request URI to
+fix redirect loops on some server configurations
+* A possible HTML/XSS injection vector in the API pretty-printing mode has been
+found and fixed.
+
+The vulnerability may be worked around in an unfixed version by simply
+disabling the API interface if it is not in use, by adding this to
+LocalSettings.php:
+
+:[[Manual:$wgEnableAPI|$wgEnableAPI]] = false;
+
+Not vulnerable versions:
+* 1.11 >= 1.11.0
+* 1.10 >= 1.10.2
+* 1.9 >= 1.9.4
+* 1.8 >= 1.8.5
+
+Vulnerable versions:
+* 1.11 <= 1.11.0rc1
+* 1.10 <= 1.10.1
+* 1.9 <= 1.9.3
+* 1.8 <= 1.8.4 (if $wgEnableAPI has been switched on)
+
+MediaWiki 1.7 and below are not affected as they do not include the faulty
+function, however the BotQuery extension is similarly vulnerable unless updated
+to the latest SVN version.
+
+== MediaWiki 1.9.3 ==
+
+February 20, 2007
+
+This is a security and bug-fix update to the Winter 2007 quarterly release.
+Minor compatibility fixes for IIS and PostgreSQL are included.
+
+An XSS injection vulnerability based on Microsoft Internet Explorer's UTF-7
+charset autodetection was located in the AJAX support module, affecting MSIE
+users on MediaWiki 1.6.x and up when the optional setting $wgUseAjax is enabled.
+
+If you are using an extension based on the optional Ajax module, either disable
+it or upgrade to a version containing the fix:
+
+* 1.9: fixed in 1.9.3
+* 1.8: fixed in 1.8.4
+* 1.7: fixed in 1.7.3
+* 1.6: fixed in 1.6.10
+
+There is no known danger in the default configuration, with ''$wgUseAjax'' off.
+
+* ([[mediazilla:8992|8992]]) Fix a remaining raw use of REQUEST_URI in history
+* ([[mediazilla:8984|8984]]) Fix a database error in
+Special:Recentchangeslinked when using the PostgreSQL database.
+* Add ''charset'' to Content-Type headers on various HTTP error responses to
+forestall additional UTF-7-autodetect XSS issues. PHP sends only ''text/html''
+by default when the script didn't specify more details, which some
+inconsiderate browsers consider a license to autodetect the deadly,
+hard-to-escape UTF-7. This fixes an issue with the Ajax interface error message
+on MSIE when ''$wgUseAjax'' is enabled (not default configuration); this UTF-7
+variant on a previously fixed attack vector was discovered by Moshe BA from
+BugSec: [http://www.bugsec.com/articles.php?Security=24
+http://www.bugsec.com/articles.php?Security=24]
+* Trackback responses now specify XML content type
+
+== MediaWiki 1.9.2 ==
+
+February 4, 2007
+
+This is a bug-fix update that fixes some installation and other minor issues
+with the 1.9.1 release as well as a security issue which was introduced in the
+1.9 branch.
+
+JavaScript code which regenerated the "sortable tables" feature did not
+properly sanitize input, leading to an HTML injection vulnerability.
+
+* ([[mediazilla:8774|8774]]) Fix path for GNU FDL rights icon on new installs
+* ([[mediazilla:8819|8819]]) Fix full path disclosure with skins dependencies
+* ([[mediazilla:8819|8819]]) Fixed data-loss bug in compressOld batch text
+compression affecting pages which had null edits (move, protect, etc) as second
+edit in a batch group. Isolated and patched by Travis Derouin.
+* Security fix for sortable tables JavaScript
+
+== MediaWiki 1.9.1 ==
+
+January 24, 2007
+
+This is a bug-fix update that fixes some installation and upgrade issues with
+the original 1.9.0 release.
+
+* ([[mediazilla:3000|3000]]) Fall back to SCRIPT_NAME plus QUERY_STRING when
+REQUEST_URI is not available, as on IIS with PHP-CGI
+* Security fix for DjVu images. (Only affects servers where .djvu file  uploads
+are enabled and ''$wgDjvuToXML'' is set.)
+* ([[mediazilla:8638|8638]]) Fix update from 1.4 and earlier
+* ([[mediazilla:8641|8641]]) Fix order of updates to ipblocks table for updates
+from <=1.7
+* ([[mediazilla:8673|8673]]) Minor fix for web service API content-type header
+* Fix API revision list on PHP 5.2.1; bad reference assignment
+* Fixed up the AjaxSearch
+* Exclude settings files when generating documentation. That could expose the
+database user and password to remote users.
+* ar: fix the 'create a new page' on search page when no exact match found
+* Correct tooltip accesskey hint for Opera on the Macintosh (uses Shift-Esc-,
+not Ctrl-).
+* ([[mediazilla:8719|8719]]) Firefox release notes lie! Fix tooltips for
+Firefox 2 on x11; accesskeys default settings appear to be same as Windows.
+
+== Changes since 1.8 ==
+
+* (bug 8200) Make category lists sorted by name when using Postgres.
+* (bug 7841) Support 'IGNORE' inserts for Postgres, fixes watchlist
+  adding problem.
+* (bug 6835) Removing the includes/Parser.php::getTemplateArgs() function,
+  because it seems to be unused.
+* (bug 7139) Increasing the visual width of the edit summary field on larger
+  screen sizes, for the default monobook skin.
+* Fix PHP notice and estimates for dumpBackup.php and friends
 * Improved register_globals paranoia checks
 * (bug 7545) Fix PHP version check on install
 * Disable PHP exception backtrace printing unless $wgShowExceptionDetails
@@ -13670,7 +14632,8 @@ setting since version 1.2.0. If you have it on, turn it *off* if you can.
 * (bug 6427) Block blocked IPs from using the mail password function
   to allow blocking of flooders
 * Include common.css from classic-style skins in main HTML with the bump URL
-* (bug 7607) Add Karakalpak (kaa) to Names.php and stub message file for linktrail
+* (bug 7607) Add Karakalpak (kaa) to Names.php and stub message file for
+  linktrail
 * (bug 7582) Add 'tog-nolangconversion' to MessagesEn.php.
   This key is need for languages with variants (zh, sr, kk)
 * (bug 7606) MediaWiki messages for "rss" and "atom" missing
@@ -13699,7 +14662,7 @@ setting since version 1.2.0. If you have it on, turn it *off* if you can.
 * (bug 7741) MATH: fixed broken syntax of underbrace etc. Fixed arrays
 * Fix purging for updated SVG files
 * (bug 7745) Add id attribute to search button in Monobook
-* (bug 7749) MATH: added some more LaTeX symbols, e.g. parallel, diamond, ast...
+* (bug 7749) MATH: added some more LaTeX symbols, e.g. parallel, diamond, ast...
 * (bug 7304) Added code in Article.php to keep redirect table up to date.
 * Made special page names case-insensitive and localisable. Care has been taken
   to maintain backwards compatibility.
@@ -13723,7 +14686,8 @@ setting since version 1.2.0. If you have it on, turn it *off* if you can.
 * Remove entries from redirect table on article deletion
 * (bug 7788) Force section headers in new section links for users who have
   'prompt for blank edit summaries' on.
-* (bug 1133) Special:Emailuser: add an option to send yourself a copy of your mail.
+* (bug 1133) Special:Emailuser: add an option to send yourself a copy of your
+  mail.
 * (bug 461) Allow "Categories:" link at bottom of pages to be customized via
   pagecategorieslink message.
 * Sort the list of skins in "My Preferences" -> Skins by alphabetical order.
@@ -13736,7 +14700,8 @@ setting since version 1.2.0. If you have it on, turn it *off* if you can.
   without the ipb_enable_autoblock option no longer show up as "autoblock
   disabled" on Special:Ipblocklist.
 * (bug 7774) MATH: aded more amstex functions
-* (bug 1182) MATH: fixed inconsistent rendering of upper case Greek letters in TeX
+* (bug 1182) MATH: fixed inconsistent rendering of upper case Greek letters in
+  TeX
 * Fix regression in streaming page dump generation
 * (bug 7801) Add support for parser function hooks in parser tests
 * checkUsernames.php now uses wfDebugLog instead of hardcoded path to log
@@ -13749,12 +14714,14 @@ setting since version 1.2.0. If you have it on, turn it *off* if you can.
 * (bug 7826) Fix typos in two English messages.
 * (bug 5365) Stop users being prompted to enter an edit summary for null edits,
   if they have selected that option in preferences.
-* (bug 5936) Show an 'm' to the left of the edit summary on diff pages for minor edits.
+* (bug 5936) Show an 'm' to the left of the edit summary on diff pages for minor
+  edits.
 * (bug 7820) Improve error reporting for uploads via URL.
-* (bug 5149) When autoblocks are enabled, retroactively apply an autoblock to the most
-  recently used IP of a user when they are blocked.
-* Add an index on (rc_user_text,rc_timestamp) on the recentchanges table. This will
-  make CheckUser.php and the new retroactive autoblock functionality faster.
+* (bug 5149) When autoblocks are enabled, retroactively apply an autoblock to
+  the most recently used IP of a user when they are blocked.
+* Add an index on (rc_user_text,rc_timestamp) on the recentchanges table. This
+  will make CheckUser.php and the new retroactive autoblock functionality
+  faster.
 * Fix regression in Special:Undelete for revisions deleted under MediaWiki 1.4
   with compression or legacy encoding
 * (bug 6737) Fixes for MySQL 5 schema in strict mode
@@ -13774,13 +14741,15 @@ setting since version 1.2.0. If you have it on, turn it *off* if you can.
 * Do a check for the PHP 5.0.x 64-bit bug, since this is much more disruptive
   as of MW 1.8 than it used to be. Install or upgrade now aborts with a
   warning and a request to upgrade.
-* (bug 6440) Updated indexes to improve backlinking queries (links, templates, images)
+* (bug 6440) Updated indexes to improve backlinking queries (links, templates,
+  images)
 * Switched 'anon-only' block mode to default for IP blocks
 * (bug 3687, 7892) Add distinct heading for media files in category display,
   with count.
 * (bug 1578) Add different icons for external links to audio, video, or PDF in
   Monobook.
-* Made autoblocks block account creation if the user block has that option enabled.
+* Made autoblocks block account creation if the user block has that option
+  enabled.
 * Add auto-summaries to blankings and large removals without summaries.
 * (bug 7811) Allow preview of edit summaries.
 * (bug 6839) Wikibits.js minor changes to make JS-lint happier.
@@ -13806,16 +14775,19 @@ setting since version 1.2.0. If you have it on, turn it *off* if you can.
 * (bug 7554) The correct MIME type for SVG images is now displayed on the
   image page (image/svg+xml, not image/svg).
 * (bug 7883) Added autoblock whitelisting feature, using which specific ranges
-   can be protected from autoblocking. These ranges are specified, in list format,
-   in the autoblock_whitelist system message.
+   can be protected from autoblocking. These ranges are specified, in list
+  format, in the autoblock_whitelist system message.
 * Added placeholders for text injection by hooks to EditPage.php
-* (bug 8009) Automatic edit summary for redirects is not filled for edits in existing pages
+* (bug 8009) Automatic edit summary for redirects is not filled for edits in
+  existing pages
 * Installer support for experimental MySQL 4.1/5.0 binary-safe schema
 * Use INSERT IGNORE for db-based BagOStuff add/insert, for more memcache-like
   behavior when keys already exist on add (instead of dying with an error...)
 * Add a hook 'UploadForm:initial' before the upload form is generated, and two
-  member variable for text injection into the form, which can be filled by the hooks.
-* (bug 6295) Add a "revision patching" functionality, where an edit can be undone
+  member variable for text injection into the form, which can be filled by the
+  hooks.
+* (bug 6295) Add a "revision patching" functionality, where an edit can be
+  undone
   (with a functionality similar to diff rev1 rev2 | patch -R rev3 -o rev3).
   This is triggered by including &undo=revid in an edit URL. A link to a URL
   that will undo a given edit is shown on NEW revision headers on diff pages.
@@ -13852,12 +14824,14 @@ setting since version 1.2.0. If you have it on, turn it *off* if you can.
 * Added a configuration variable allowing the "break out of framesets" feature
   to be switched on and off ($wgBreakFrames). Off by default.
 * Allow Xml::check() $attribs parameter to override 'value' attribute
-* DB schema change: added two columns (rc_old_len and rc_new_len) to the recentchanges table to store
-  the text lengths before and after the edit
-* (bug 1085) Made Special:Recentchanges show the character difference between the changed revisions
-* Removed a redundant <strong> tag from diff pages that was causing display issues for some users
-* (bug 8203) The keyboard shortcut for "log out" was removed, because users were pressing it
-  when they intended to press the shortcut for "preview".
+* DB schema change: added two columns (rc_old_len and rc_new_len) to the
+  recentchanges table to store the text lengths before and after the edit
+* (bug 1085) Made Special:Recentchanges show the character difference between
+  the changed revisions
+* Removed a redundant <strong> tag from diff pages that was causing display
+  issues for some users
+* (bug 8203) The keyboard shortcut for "log out" was removed, because users
+  were pressing it when they intended to press the shortcut for "preview".
 * (bug 8148) Handle non-removable output buffers gracefully when cleaning
   buffers for HTTP 304 responses, StreamFile, and Special:Export.
   Duplicated code merged into wfResetOutputBuffers() and wfClearOutputBuffers()
@@ -13987,8 +14961,8 @@ setting since version 1.2.0. If you have it on, turn it *off* if you can.
   revisions
 * (bug 8214) Output file size limit and actual file size in appropriate units
   on Special:Upload
-* (bug 8016) Purge objectcache table during upgrade processes - use the --nopurge
-  option to prevent this when running maintenance/update.php
+* (bug 8016) Purge objectcache table during upgrade processes - use the
+  --nopurge option to prevent this when running maintenance/update.php
 * (bug 7612) Remove superfluous link to Special:Categories from result items
   on Special:Mostcategories
 * {{PLURAL:}} now handles formatted numbers correctly
@@ -14071,8 +15045,9 @@ setting since version 1.2.0. If you have it on, turn it *off* if you can.
 * (bug 8372) Return nothing on empty <math> tags.
 * New maintenance script to show the cached statistics : showStats.php.
 * Count deleted edits when regenerating total edits in maintenance/initStats.php
-* (bug 3706) Allow users to be exempted from IP blocks. The ipblock-exempt permission
-  key has been added to enable this behavior, by default assigned to sysops.
+* (bug 3706) Allow users to be exempted from IP blocks. The ipblock-exempt
+  permission key has been added to enable this behavior, by default assigned to
+  sysops.
 * (bug 7948) importDump.php now warn that Recentchanges need to be rebuild.
 * (bug 7667) allow XHTML namespaces customization
 * (bug 8531) Correct local name of Lingála (patch by Raymond)
@@ -14310,6 +15285,154 @@ MediaWiki's parser test suite can now be expanded with additional test
 files. Custom extensions can add their test files to this array, and
 they will be run along with the main tests by maintenance/parserTests.php
 
+= MediaWiki 1.8=
+
+== MediaWiki 1.8.5 ==
+
+September 10, 2007
+
+This is a security fix update to the Fall 2006 quarterly release snapshot. A
+possible HTML/XSS injection vector in the API pretty-printing mode has been
+found and fixed.
+
+The vulnerability may be worked around in an unfixed version by simply
+disabling the API interface if it is not in use, by adding this to
+LocalSettings.php:
+
+:[[Manual:$wgEnableAPI|$wgEnableAPI]] = false;
+
+(This is the default setting in 1.8.x.)
+
+Not vulnerable versions:
+* 1.11 >= 1.11.0
+* 1.10 >= 1.10.2
+* 1.9 >= 1.9.4
+* 1.8 >= 1.8.5
+
+Vulnerable versions:
+* 1.11 <= 1.11.0rc1
+* 1.10 <= 1.10.1
+* 1.9 <= 1.9.3
+* 1.8 <= 1.8.4 (if $wgEnableAPI has been switched on)
+
+MediaWiki 1.7 and below are not affected as they do not include the faulty
+function, however the BotQuery extension is similarly vulnerable unless updated
+to the latest SVN version.
+
+== MediaWiki 1.8.4 ==
+
+February 20, 2007
+
+This is a security and bug-fix update to the Fall 2006 quarterly release.
+
+An XSS injection vulnerability based on Microsoft Internet Explorer's UTF-7
+charset autodetection was located in the AJAX support module, affecting MSIE
+users on MediaWiki 1.6.x and up when the optional setting
+[[Manual:$wgUseAjax|$wgUseAjax]] is enabled.
+
+If you are using an extension based on the optional Ajax module, either disable
+it or upgrade to a version containing the fix:
+* 1.9: fixed in 1.9.3
+* 1.8: fixed in 1.8.4
+* 1.7: fixed in 1.7.3
+* 1.6: fixed in 1.6.10
+
+There is no known danger in the default configuration, with $wgUseAjax off.
+
+* (bug [[bugzilla:8819|8819]]) Fix full path disclosure with skins dependencies
+* Add 'charset' to Content-Type headers on various HTTP error responses to
+forestall additional UTF-7-autodetect XSS issues. PHP sends only 'text/html' by
+default when the script didn't specify more details, which some inconsiderate
+browsers consider a license to autodetect the deadly, hard-to-escape UTF-7.
+This fixes an issue with the Ajax interface error message on MSIE when
+[[Manual:$wgUseAjax|$wgUseAjax]] is enabled (not default configuration); this
+UTF-7 variant on a previously fixed attack vector was discovered by Moshe BA
+from BugSec: http://www.bugsec.com/articles.php?Security=24
+* Trackback responses now specify XML content type
+
+== MediaWiki 1.8.3 ==
+
+January 9, 2007
+
+MediaWiki 1.8.3 fixes several issues in the Fall 2006 snapshot release:
+
+* ([[mediazilla:7831|7831]]) Regression in AutoAuthenticate hook
+* Run PHP install version checks on update.php so command-line updaters see new
+version requirements
+* Do a check for the PHP 5.0.x 64-bit bug, since this is much more disruptive
+as of MW 1.8 than it used to be. Install or upgrade now aborts with a warning
+and a request to upgrade.
+* XSS fix in AJAX module
+
+An XSS injection vulnerability was located in the AJAX support module,
+affecting MediaWiki 1.6.x and up when the optional setting $wgUseAjax is
+enabled.
+
+There is no danger in the default configuration, with $wgUseAjax off.
+
+If you are using an extension based on the optional AJAX module, either disable
+it or upgrade to a version containing the fix:
+
+== MediaWiki 1.8.2 ==
+
+October 13, 2006
+
+MediaWiki 1.8.2 fixes several issues in the Fall 2006 snapshot release:
+
+* ([[mediazilla:7565|7565]]) Fixed typos in German localisation
+* ([[mediazilla:7562|7562]]) Fix non-ASCII namespaces on Windows/XAMPP servers
+
+== MediaWiki 1.8.1 ==
+
+October 11, 2006
+
+MediaWiki 1.8.1 fixes several issues in the Fall 2006 snapshot release:
+
+* Fix PHP notice and estimates for dumpBackup.php and friends
+* Improved register_globals paranoia checks
+* ([[mediazilla:7545|7545]]) Fix PHP version check on install
+* Experimental web API disabled by default
+* Disable PHP exception backtrace printing unless $wgShowExceptionDetails is
+set. Backtraces may contain sensitive information in function call parameters.
+
+== MediaWiki 1.8.0 ==
+
+October 10, 2006
+
+This is the quarterly release snapshot for Fall 2006. While the code has been
+running on Wikipedia for some time, installation and upgrade bits may be less
+well tested. Bug fix releases may follow in the coming days or weeks.
+
+MediaWiki is now using a "continuous integration" development model with
+quarterly snapshot releases. The latest development code is always kept "ready
+to run", and in fact runs our own sites on Wikipedia.
+
+Release branches will continue to receive security updates for about a year
+from first release, but nonessential bugfixes and feature development happen
+will be made on the development trunk and appear in the next quarterly release.
+
+Those wishing to use the latest code instead of a branch release can obtain it
+from source control: [[Download from SVN]]
+
+== Configuration changes ==
+* $wgUseETag, to enable/disable sending of HTTP ETag headers (default: disabled)
+* $wgLegalTitleChars now includes '+' by default for better compatibility with
+importing data dumps from Wikipedia
+* $wgDefaultUserOptions now includes all default option settings instead of
+only overrides.
+
+== Major new features ==
+* ([[mediazilla:7098|7098]]) Add an option to disable/enable sending of HTTP
+ETag headers, as it seems to result in broken behaviour in combination with
+Squid 2.6 (disabled by default).
+* ([[mediazilla:550|550]]) Allow blocks on anonymous users only.
+* ([[mediazilla:6420|6420]]) Render thumbnails for DJVU images, support
+multipage DJVU display on image pages. Added new 'page=' thumbnail option to
+select a page from a multipage djvu for thumbnail generation.
+* Full Postgres support is now enabled. It requires version 8.1 or better, and
+needs to have both plpgsql and tsearch2 already installed.
+* ([[mediazilla:6386|6386]]) fix grammatical errors in danish naming of talk
+namespaces.
 
 == Changes since 1.7 ==
 
@@ -14356,7 +15479,8 @@ they will be run along with the main tests by maintenance/parserTests.php
   (blocked mid-edit) and the page doesn't exist
 * Improve default value of "blockedtext"
 * (bug 6680) Added localisation for Dutch bookstore list (nl)
-* Renamed maintainace script redundanttrans.php to unusedMessages.php - clearer usage
+* Renamed maintainace script redundanttrans.php to unusedMessages.php - clearer
+  usage
 * Fix regression which allowed some blocked users to create additional accounts
 * (bug 6657) Fix Hungarian linktrail
 * (bug 6751) Fix preview of blanked section with edit on first preview option
@@ -14390,8 +15514,8 @@ they will be run along with the main tests by maintenance/parserTests.php
 * Added "serialized" directory, for storing precompiled data in serialized form.
 * Fix regression in auto-set NS_PROJECT_TALK namespace
 * Fix regression in ordering of namespaces
-* (bug 6806, 6030) Added several global JS variables for article path, user name,
-  page title, etc.
+* (bug 6806, 6030) Added several global JS variables for article path, user
+  name, page title, etc.
 * hooks registered with addOnloadHook are now called at the one of the html body
   by all skins.
 * Split ajax aided search from core ajax framework. Use wgUseAjax to enable the
@@ -14404,12 +15528,15 @@ they will be run along with the main tests by maintenance/parserTests.php
 * (bug 6919) Add English alias magic words for Tatar (tt) language file.
 * (bug 6753) Fixed broken Kazakh linktrail (kk)
 * (bug 6700) Added Kazakh language variants to Names.php
-* (bug 6827) some i18n specific maintenance scripts fails after merge of localisation-work branch
-* Throwed an exception for the deprecated functions OutputPage::sysopRequired and
-  OutputPage::developerRequired - use OutputPage::permissionRequired instead.
-* Removed the deprecated functions User::isSysop, User::isBureaucrat and User::isDeveloper -
-  use User::isAllowed instead.
-* (bug 769) OutputPage::permissionRequired() should suggest groups with the needed permission
+* (bug 6827) some i18n specific maintenance scripts fails after merge of
+  localisation-work branch
+* Throwed an exception for the deprecated functions OutputPage::sysopRequired
+  and OutputPage::developerRequired - use OutputPage::permissionRequired
+  instead.
+* Removed the deprecated functions User::isSysop, User::isBureaucrat and
+  User::isDeveloper - use User::isAllowed instead.
+* (bug 769) OutputPage::permissionRequired() should suggest groups with the
+  needed permission
 * (bug 6971) Fix regression in Special:Export history view
 * Revamped Special:Imagelist
 * (bug 7000) updated MessagesPl.php
@@ -14431,8 +15558,10 @@ they will be run along with the main tests by maintenance/parserTests.php
 * (bug 7044) Introduce "padleft" and "padright" colon functions
 * Pass page title as parameters to "linkshere" and "nolinkshere" and update
   default message text
-* Allows to upload from publicy accessible URL. Set $wgAllowCopyUploads = true ; in LocalSettings.php
-  Limited to $wgMaxUploadSize (default:100MB); URL upload is limited to sysops by default, and displayed as a second line if appropriate
+* Allows to upload from publicy accessible URL. Set $wgAllowCopyUploads = true;
+  in LocalSettings.php
+  Limited to $wgMaxUploadSize (default:100MB); URL upload is limited to sysops
+  by default, and displayed as a second line if appropriate
 * (bug 832) Return to user page after emailing a user
 * (bug 366) Add local-system-timezone equivalents for date/time variables
 * (bug 7109) Fix Atom feed version number in header links
@@ -14442,17 +15571,18 @@ they will be run along with the main tests by maintenance/parserTests.php
 * Fix bug in wfRunHooks which caused corruption of objects in the hook list
 * (bug 4979) Use simplified email addresses when running on Windows
 * (bug 4434) Show block log fragment on Special:Blockip
-* [[MediaWiki:Disambiguationspage]] may optionally contain wiki links to any number
-  of disambiguation templates.
-* [[Special:Disambiguations]] now shows pages in NS:0 that link to any pages that embed
-  any of the templates listed at [[MediaWiki:Disambiguationspage]].
+* [[MediaWiki:Disambiguationspage]] may optionally contain wiki links to any
+  number of disambiguation templates.
+* [[Special:Disambiguations]] now shows pages in NS:0 that link to any pages
+  that embed any of the templates listed at [[MediaWiki:Disambiguationspage]].
 * Fix formatting of titles on Special:Undelete
 * (bug 7026) Fix action=raw&templates=expand
 * (bug 6976) Add namespace and direction classes to classic skins
-* (bug 7144) Don't "return to main" from OutputPage::loginToUse() if the user can't
-  read the main page in the first place
+* (bug 7144) Don't "return to main" from OutputPage::loginToUse() if the user
+  can't read the main page in the first place
 * (bug 7188) Fix minor borkage in HTMLForm
-* (bug 6675) Replaced message 'watchthis' with new message 'watchthisupload in Special:Upload
+* (bug 6675) Replaced message 'watchthis' with new message 'watchthisupload in
+  Special:Upload
 * Add a quickie script dumpSisterSites.php for generating a page list in the
   format for WSR-1 SisterSites support
 * (bug 7223) Monobook.js is used for site content, should not be localized
@@ -14460,11 +15590,15 @@ they will be run along with the main tests by maintenance/parserTests.php
 * Added Xml::option() for generating <option>s easily
 * Localized page numbers in drop-down for DjVu page selection
 * Fixed linktrail for vi
-* (bug 6893) "Call to a member function exists() on a non-object" on trackback.php with bad input
+* (bug 6893) "Call to a member function exists() on a non-object" on
+  trackback.php with bad input
 * (bug 6886) PHP undefined offset on bad input to Special:Revisiondelete
-* (bug 6887) PHP error for call to getId() on bad input to Special:Revisiondelete
-* (bug 6888) PHP error for call to getTimestamp() on bad input to Special:Revisiondelete
-* (bug 7252) Use dvipng support in texvc math rastrization. dvipng is required if texvc is rebuilt.
+* (bug 6887) PHP error for call to getId() on bad input to
+  Special:Revisiondelete
+* (bug 6888) PHP error for call to getTimestamp() on bad input to
+  Special:Revisiondelete
+* (bug 7252) Use dvipng support in texvc math rastrization. dvipng is required
+  if texvc is rebuilt.
 * (bug 7279) Use wfBaseName in place of basename() in more places
 * Clear newtalk marker on diff links with explicit current revision number
 * (bug 7064) Replace hard-coded empty message checks with wfEmptyMsg calls
@@ -14479,7 +15613,8 @@ they will be run along with the main tests by maintenance/parserTests.php
 * Set Vary: Cookie on action=raw generated CSS and JS, to ensure that user
   preferences don't get stuck in proxy caches for other people
 * (bug 7324) Fix error message for failure of Database::sourceFile()
-* (bug 7309) Plurals: use singular form for zero in French and Brazilian Portuguese
+* (bug 7309) Plurals: use singular form for zero in French and Brazilian
+  Portuguese
 * Add page_no_title_convert field to support language variant conversion
   for page titles which shouldn't be converted on display/linking
 * Lazy extraction of text chunks in Revision objects, may reduce hits to
@@ -14488,16 +15623,19 @@ they will be run along with the main tests by maintenance/parserTests.php
   in $wgMemc, to further reduce hits to external storage.
   Set to 0 (disabled) by default.
 * Minor changes to the installer.
-* Remove ":" for 'youremail' and 'yourrealname' in includes/templates/Userlogin.php
-  so that ":" could be used in i18n for Special:Preferences (like 'username' and 'uid').
-* Fix layout for Special:Preferences->Date and Time (position for 'timezonetext').
+* Remove ":" for 'youremail' and 'yourrealname' in
+  includes/templates/Userlogin.php so that ":" could be used in i18n for
+  Special:Preferences (like 'username' and 'uid').
+* Fix layout for Special:Preferences->Date and Time (position for
+  'timezonetext').
 * Updates to language variant code for Serbian et al
 * (bug 6756) Enabling RTL direction for kk-cn
 * (bug 6701) Kazakh language variants in MessagesEn.php
 * (bug 7335) SVN revision check in Special:Version fails on SVN 1.4 working copy
-* (bug 6518) Replaced 'lastmodified' with 'lastmodifiedat' and 'lastmodifiedby' with 'lastmodifiedatby'
-  with separated parameters for date and time to allow better localisation. Updated all message files
-  to display the old format for compatibility.
+* (bug 6518) Replaced 'lastmodified' with 'lastmodifiedat' and 'lastmodifiedby'
+  with 'lastmodifiedatby' with separated parameters for date and time to allow
+  better localisation. Updated all message files to display the old format for
+  compatibility.
 * (bug 7357) Make supposedly static methods of Skin actually static
 * Added info text to Special:Deadendpages and Special:Lonelypages
 * Fix regression in cachability of generated CSS and JS for MonoBook skin,
@@ -14505,21 +15643,22 @@ they will be run along with the main tests by maintenance/parserTests.php
 * (bug 6849) Block @ from usernames; interferes with multi-database tools and
   was meant to be banned years ago... For now existing accounts will not be
   prevented fromm login.
-* (bug 6092) Introduce magic words {{REVISIONDAY}}, {{REVISIONDAY2}, {{REVISIONMONTH}},
-  {{REVISIONYEAR}} and {{REVISIONTIMESTAMP}}
+* (bug 6092) Introduce magic words {{REVISIONDAY}}, {{REVISIONDAY2},
+  {{REVISIONMONTH}}, {{REVISIONYEAR}} and {{REVISIONTIMESTAMP}}
 * (bug 7425) Preceeding whitespace in [[...]] breaks subpages
 * Try to reconnect after transitory database errors in dumpTextPass.php
-* (bug 6023) Fixed mismatch of 0/NULL for wl_notificationtimestamp; now notification
-  mails are working after 'Mark all pages visited' button on Special:Watchlist is clicked
+* (bug 6023) Fixed mismatch of 0/NULL for wl_notificationtimestamp; now
+  notification mails are working after 'Mark all pages visited' button on
+  Special:Watchlist is clicked
 * Made {{INT:}} a core parser function instead of a special case. The syntax
   and behavior is largely unchanged.
 * (bug 7448) Fixing the native name for Ewe (ee)
-* (bug 6864) Replace message 'editing' with new message 'editinguser' in Special:Userrights
-  to allow better localisation
-* Add '*-summary' for special pages to MessagesEn.php to allow customizing/translation
-  directly through Special:Allmessages
-* (bug 6130, bug 5818) Replaced message 'go'  with the new message 'searcharticle' in skins
-  to allow better localisation
+* (bug 6864) Replace message 'editing' with new message 'editinguser' in
+  Special:Userrights to allow better localisation
+* Add '*-summary' for special pages to MessagesEn.php to allow
+  customizing/translation directly through Special:Allmessages
+* (bug 6130, bug 5818) Replaced message 'go'  with the new message
+  'searcharticle' in skins to allow better localisation
 * Add + to $wgLegalTitleChars by default. Some sites may have occasional
   problems with hard-to-reach pages, but it should be less trouble than
   "I can't import dumps from Wikipedia" complaints
@@ -14552,14 +15691,184 @@ they will be run along with the main tests by maintenance/parserTests.php
 * (bug 7520) Update article counts on XML import
 * (bug 7526) Make $wgDefaultUserOptions work again
 * (bug 7472) Localize Help namespace for Basque
-* (bug 7529) Including a non-existent category in an article places that article in the category
+* (bug 7529) Including a non-existent category in an article places that article
+  in the category
 * (bug 4528) Lack of important LaTeX functions stackrel, rightleftharpoon
-* (bug 6721) missing symbols ulcorner, urcorner, llcorner, lrcorner, twoheadrightarrow, twoheadleftarrow
-* (bug 7367) Hyphens sometimes erroneously appended to equations when not converted to PNG
-* Add "title" to the opensearch link to allow automatic adding of the search engine in Firefox 2
+* (bug 6721) missing symbols ulcorner, urcorner, llcorner, lrcorner,
+  twoheadrightarrow, twoheadleftarrow
+* (bug 7367) Hyphens sometimes erroneously appended to equations when not
+  converted to PNG
+* Add "title" to the opensearch link to allow automatic adding of the search
+  engine in Firefox 2
 * (bug 7537) Add php5 to $wgFileBlacklist
 * (bug 6929) Restore AutoAuthenticate hook
 
+== Languages updated ==
+* Albanian (sq)
+* Bashkir (ba)
+* Bavarian (bar) stub file
+* Belarusian (be)
+* Bishnupriya (bpy) stub file
+* Brazilian Portuguese (pt-br)
+* Cantonese (zh-yue)
+* Catalan (ca)
+* Czech (cs)
+* Dutch (nl)
+* English (en)
+* Finnish (fi)
+* French (fr)
+* Georgian (ka)
+* German (de)
+* Hebrew (he)
+* Hungarian (hu)
+* Indonesian (id)
+* Japanese (ja)
+* Korean (ko)
+* Latin (la)
+* Lojban (jbo)
+* Macedonian (mk)
+* Mazandarani (mzn)
+* Polish (pl)
+* Portuguese (pt)
+* Ripuarian (ksh)
+* Romani (rmy)
+* Russian (ru)
+* Slovak (sk)
+* Spanish (es)
+* Tajic (tg)
+* Tatar (tt)
+* Telugu (te)
+* Uzbek (uz)
+* Yiddish (yi)
+
+== Compatibility ==
+MediaWiki 1.8 requires PHP 5 (5.1 recommended). PHP 4 is no longer supported.
+
+MySQL 3.23.x is no longer supported; some older hosts may need to upgrade. At
+this time we still recommend 4.0, but 4.1/5.0 will work fine in most cases.
+
+== Upgrading ==
+Some minor database changes have been made since 1.7:
+* new fields and indexes on ipblocks
+* index change on recentchanges
+
+Several changes from 1.5 and 1.6 do require updates to be run on upgrade. To
+ensure that these tables are filled with data, run refreshLinks.php after the
+upgrade.
+
+If you are upgrading from MediaWiki 1.4.x or earlier, some major database
+changes are made, and there is a slightly higher chance that things could
+break. Don't forget to always back up your database before upgrading!
+
+=== Caveats ===
+Some output, particularly involving user-supplied inline HTML, may not produce
+100% valid or well-formed XHTML output. Testers are welcome to set $wgMimeType
+= "application/xhtml+xml"; to test for remaining problem cases, but this is not
+recommended on live sites. (This must be set for MathML to display properly in
+Mozilla.)
+
+= MediaWiki 1.7=
+
+== MediaWiki 1.7.3 ==
+
+February 20, 2007
+
+This is a security and bug-fix update to the Summer 2006 quarterly release.
+
+An XSS injection vulnerability based on Microsoft Internet Explorer's UTF-7
+charset autodetection was located in the AJAX support module, affecting MSIE
+users on MediaWiki 1.6.x and up when the optional setting
+[[Manual:$wgUseAjax|$wgUseAjax]] is enabled.
+
+If you are using an extension based on the optional Ajax module, either disable
+it or upgrade to a version containing the fix:
+
+* 1.9: fixed in 1.9.3
+* 1.8: fixed in 1.8.4
+* 1.7: fixed in 1.7.3
+* 1.6: fixed in 1.6.10
+
+There is no known danger in the default configuration, with
+[[Manual:$wgUseAjax|$wgUseAjax]] off.
+
+* Add 'charset' to Content-Type headers on various HTTP error responses to
+forestall additional UTF-7-autodetect XSS issues. PHP sends only 'text/html' by
+default when the script didn't specify more details, which some inconsiderate
+browsers consider a license to autodetect the deadly, hard-to-escape UTF-7.
+This fixes an issue with the Ajax interface error message on MSIE when
+[[Manual:$wgUseAjax|$wgUseAjax]] is enabled (not default configuration); this
+UTF-7 variant on a previously fixed attack vector was discovered by Moshe BA
+from BugSec: http://www.bugsec.com/articles.php?Security=24
+* Trackback responses now specify XML content type
+
+== MediaWiki 1.7.2 ==
+
+January 9, 2007
+
+* Note about $wgUploadSizeWarning using byte
+* Update to German bookstore list (de)
+* (bug [[bugzilla:6680|6680]]) Added localisation for Dutch bookstore list (nl)
+* (bug [[bugzilla:6708|6708]]) Minor updates to Russian translation (ru)
+* (bug [[bugzilla:6730|6730]]) Clearer usage of message 'titlematch' in German
+translation (de)
+* Added direction mark to Special:Listredirects
+* XSS fix in AJAX module
+
+An XSS injection vulnerability was located in the AJAX support module,
+affecting MediaWiki 1.6.x and up when the optional setting
+[[Manual:$wgUseAjax|$wgUseAjax]] is enabled.
+
+There is no danger in the default configuration, with
+[[Manual:$wgUseAjax|$wgUseAjax]] off.
+
+If you are using an extension based on the optional AJAX module, either disable
+it or upgrade to a version containing the fix:
+
+* 1.9: fixed in 1.9.0rc2
+* 1.8: fixed in 1.8.3
+* 1.7: fixed in 1.7.2
+* 1.6: fixed in 1.6.9
+
+
+== MediaWiki 1.7.1 ==
+
+July 8, 2006
+
+MediaWiki 1.7.1 is a security and bugfix maintenance release of the Summer 2006
+snapshot:
+
+A potential HTML/JavaScript-injection vulnerability in a debugging script has
+been fixed. Only versions and configurations of PHP vulnerable to the $GLOBALS
+overwrite vulnerability are affected.
+
+As a workaround for existing installs, profileinfo.php may simply be deleted if
+it's not being used.
+
+* Fix for 'emailconfirmed' implicit user group
+* Fix for upgrades on some versions of MySQL 4.0.x
+* Fixed potential XSS in profileinfo.php
+* Installer now shows clear error message about old PHP versions rather than a
+confusing parse error
+
+== MediaWiki 1.7.0 ==
+July 6, 2006
+
+This is the quarterly release snapshot for Summer 2006. While the code
+has been running on Wikipedia for some time, installation and upgrade
+bits may be less well tested. Bug fix releases may follow in the coming
+days or weeks.
+
+MediaWiki is now using a "[[w:en:Continuous_integration|continuous
+integration]]" development model with
+quarterly snapshot releases. The latest development code is always kept
+"ready to run", and in fact runs our own sites on Wikipedia.
+
+Release branches will continue to receive security updates for about a year
+from first release, but nonessential bugfixes and feature development happen
+will be made on the development trunk and appear in the next quarterly release.
+
+Those wishing to use the latest code instead of a branch release can obtain
+it from source control: [[Download from SVN]]
 
 == Changes since 1.6 ==
 
@@ -14715,18 +16024,21 @@ they will be run along with the main tests by maintenance/parserTests.php
 * (bug 5593) Change "bureaucrat log" to "rights log"
 * Show a boilerplate "(none)" in place of a blank within the log action text for
   user rights
-* (bug 137) Commented out translations for copyrightwarning which mention GNU FDL
-* (bug 5723) Don't count pages linked to from the MediaWiki namespace as "wanted"
+* (bug 137) Commented out translations for copyrightwarning which mention GNU
+  FDL
+* (bug 5723) Don't count pages linked to from the MediaWiki namespace as
+  "wanted"
 * (bug 5696) Add a third parameter, $3, to "rcnote", passing the current time
   formatted according to the current user's settings
 * (bug 5780) Thousands and decimal separators for Norwegian
 * Updated initStats maintenance script
 * (bug 5767) Fix date formats in Vietnamese locale
 * (bug 361) URL in URL, they were almost fixed. Now they are.
-* (bug 4876) Add __NEWSECTIONLINK__ magic word to force the "new section" link/tab to
-  show up on specific pages on demand
+* (bug 4876) Add __NEWSECTIONLINK__ magic word to force the "new section"
+  link/tab to show up on specific pages on demand
 * Bidi-aid on list pages
-* (bug 5782) Allow entries in the bad image list to use canonical namespace names
+* (bug 5782) Allow entries in the bad image list to use canonical namespace
+  names
 * (bug 5789) Treat "loginreqpagetext" as wikitext
 * Sanitizer: now handles nested <li> in <ul> or <ol>
 * (bug 5796) We require MySQL >=4.0.14
@@ -14737,9 +16049,10 @@ they will be run along with the main tests by maintenance/parserTests.php
 * Clean up Special:Listusers; add an "(all)" label to the group selection box
 * (bug 5812) Use appropriate link colour in Special:Mostlinked
 * (bug 5802) {{CURRENTMONTHNAME}} variable broken in Vietnamese locale
-* (bug 5817) Appropriate handling for Special:Recentchangeslinked where the target
-  page doesn't exist
-* Special:Randompage now additionally accepts English namespace name as parameter
+* (bug 5817) Appropriate handling for Special:Recentchangeslinked where the
+  target page doesn't exist
+* Special:Randompage now additionally accepts English namespace name as
+  parameter
 * (bug 2981) Really fixed linktrail for Tamil (ta)
 * Disallow substituting Special pages when included into a page
 * (bug 5587) Clean up the languages from references to the Groups special page
@@ -14747,10 +16060,12 @@ they will be run along with the main tests by maintenance/parserTests.php
 * Rewritten removeUnusedAccounts to be more efficient, print names of inactive
   accounts
 * Redirect Special:Userlist to Special:Listusers
-* Introduce $wgAllowTitlesInSVG, which allows the <title> attribute in uploaded files
-  bearing the image/svg MIME type. Disabled by default due to the vast majority of
-  web servers being hideously misconfigured. See DefaultSettings.php for more details.
-* Changed default LocalSettings.php to append the previous include path when setting it
+* Introduce $wgAllowTitlesInSVG, which allows the <title> attribute in uploaded
+  files bearing the image/svg MIME type. Disabled by default due to the vast
+  majority of web servers being hideously misconfigured. See DefaultSettings.php
+  for more details.
+* Changed default LocalSettings.php to append the previous include path when
+  setting it
 * (bug 5837) Use "members" for the value descriptor in Special:Categories,
   Special:Wantedcategories and Special:Mostlinkedcategories.
 * (bug 3309) Allow comments when undeleting pages
@@ -14759,7 +16074,8 @@ they will be run along with the main tests by maintenance/parserTests.php
 * Clean up Special:Imagelist a bit
 * (bug 5838) Namespace names for Nds-NL
 * (bug 5749) Added Tyvan language files
-* (bug 5791) Fix SQL syntax in Special:BrokenRedirects, was causing incorrect data to show
+* (bug 5791) Fix SQL syntax in Special:BrokenRedirects, was causing incorrect
+  data to show
 * (bug 5839) Prevent access to Special:Confirmemail for logged-out users
 * (bug 5853) Update for Portuguese messages (pt)
 * (bug 5851) Use Cyrillic for Kirghiz language name
@@ -14798,7 +16114,8 @@ they will be run along with the main tests by maintenance/parserTests.php
 * Ignore the user and user talk namespaces on Special:Wantedpages
 * Introduce NUMBEROFPAGES magic word
 * (bug 5833) Introduce CURRENTVERSION magic word
-* (bug 5370) Allow throttling of password reminder requests with the rate limiter
+* (bug 5370) Allow throttling of password reminder requests with the rate
+  limiter
 * (bug 5683) Respect parser output marked as uncacheable when saving
 * (bug 5918) Links autonumbering now work for all defined protocols
 * (bug 5935) Improvement to German localisation (de)
@@ -14822,22 +16139,24 @@ they will be run along with the main tests by maintenance/parserTests.php
 * (bug 5849) Remove some hard-coded references to "Wikipedia" in messages
 * (bug 5967) Improvement to German localisation (de)
 * (bug 5962) Update for Italian language (it)
-* Suppress images in galleries which appear on the bad image list (when rendering
-  for a wiki page; galleries in special pages and categories are unaffected)
+* Suppress images in galleries which appear on the bad image list (when
+  rendering for a wiki page; galleries in special pages and categories are
+  unaffected)
 * Maintenance script to remove orphaned revisions from the database
 * (bug 5991) Update for Russian language (ru)
-* (bug 6001) PAGENAMEE and FULLPAGENAMEE don't work in FULLURL and LOCALURL magic
-  words
+* (bug 6001) PAGENAMEE and FULLPAGENAMEE don't work in FULLURL and LOCALURL
+  magic words
 * (bug 5958) Switch Uzbek language name to use latin script
 * (bug 839) Add URLENCODE magic word
 * (bug 6004) Update for Polish language (pl)
 * (bug 5971) Improvement to German localisation (de)
-* (bug 4873) Don't overwrite the subtitle navigation when viewing a redirect page
-  that isn't current
+* (bug 4873) Don't overwrite the subtitle navigation when viewing a redirect
+  page that isn't current
 * (bug 2203) Namespace updates for Thai
-* Fix breakage in parser test suite which caused incorrect reporting of the failure of
-  {{NUMBEROFFILES}}. Now initialises the site_stats table with some dumb data. Updated
-  the expected output for {{NUMBEROFARTICLES}} to reflect this.
+* Fix breakage in parser test suite which caused incorrect reporting of the
+  failure of {{NUMBEROFFILES}}. Now initialises the site_stats table with some
+  dumb data. Updated the expected output for {{NUMBEROFARTICLES}} to reflect
+  this.
 * (bug 6009) Use {{ns:project}} in messages where appropriate
 * (bug 6012) Update to Indonesian localisation (id)
 * (bug 6017) Update list of bookstores in German localisation files
@@ -14852,13 +16171,14 @@ they will be run along with the main tests by maintenance/parserTests.php
 * (bug 6039) Update for Portuguese localisation (pt)
 * (bug 764) Add CREATE TEMPORARY TABLES to default database permissions
 * Big update to Swedish localisation (sv)
-* Use appropriate HTML functions to create the tool links on image pages, so they don't
-  look garbled when tidy isn't on
+* Use appropriate HTML functions to create the tool links on image pages, so
+  they don't look garbled when tidy isn't on
 * (bug 5511) Fix URL-encoding of usernames in links on Special:Ipblocklist
 * (bug 6046) Update to Indonesian localisation (id) #15
 * (bug 5523) $wgNoFollowNsExceptions to allow disabling rel="nofollow" in
   specially-selected namespaces.
-* (bug 6055) Fix for HTML/JS injection bug in variable handler (found by Nick Jenkins)
+* (bug 6055) Fix for HTML/JS injection bug in variable handler (found by Nick
+  Jenkins)
 * Reordered wiki table handling and __TOC__ extraction in the parser to better
   handle some overlapping tag cases.
 * Only the first __TOC__ is now turned into a TOC
@@ -14909,7 +16229,8 @@ they will be run along with the main tests by maintenance/parserTests.php
 * (bug 1017) fixed thumbnails of animated gifs.
 * Add APC as object caching option
 * Update to Albanian localization (sq)
-* (bug 6099) Introduce {{DIRECTIONMARK}} magic word (with {{DIRMARK}} as an alias)
+* (bug 6099) Introduce {{DIRECTIONMARK}} magic word (with {{DIRMARK}} as an
+  alias)
 * Use optimized php5-only microtime()
 * Add possibility to store local message cache as PHP executable script
 * Fix profiling table definition
@@ -15003,8 +16324,9 @@ they will be run along with the main tests by maintenance/parserTests.php
 * (bug 5945) Introduce {{CONTENTLANGUAGE}} magic word
 * {{PLURAL}} can now take up to five forms
 * (bug 6243) Fix email for usernames containing dots when using PEAR::Mail
-* Remove a number of needless {{ns:project}}-type transforms from messages files. These
-  usages already have separate label text. Such transforms are wasteful on each page view.
+* Remove a number of needless {{ns:project}}-type transforms from messages
+  files. These usages already have separate label text. Such transforms are
+  wasteful on each page view.
 * Update to Yiddish localization (yi)
 * (bug 6254) Update to Indonesian translation (id) #20
 * (bug 6255) Fix transclusions starting with "#" or "*" in HTML attributes
@@ -15017,13 +16339,15 @@ they will be run along with the main tests by maintenance/parserTests.php
 * Avoid some notices in page history with bad input
 * Use double quoted consistently on attributes in linker output; preparing
   for new normalization code when tidy not in use
-* Replace "nogomatch" with "noexactmatch" and place the magic colon in the messages
-  themselves. Some minor tweaks to the actual message content.
-* Introduce $wgContentNamespaces which allows for articles to exist in namespaces other
-  than the main namespace, and still be counted as valid content in the site statistics.
+* Replace "nogomatch" with "noexactmatch" and place the magic colon in the
+  messages themselves. Some minor tweaks to the actual message content.
+* Introduce $wgContentNamespaces which allows for articles to exist in
+  namespaces other than the main namespace, and still be counted as valid
+  content in the site statistics.
 * (bug 5932) Introduce {{PAGESINNAMESPACE}} magic word
 * Disable $wgAllowExternalImages by default.
-* (bug 2700) Nice things like link completion and signatures now work in <gallery> tags.
+* (bug 2700) Nice things like link completion and signatures now work in
+  <gallery> tags.
 * Cancel output buffering in StreamFile; when used inside gzip buffering this
   could cause funny timeout behavior as the Content-Length was wrong.
 * Return correct content-type header with 304 responses for StreamFile;
@@ -15058,7 +16382,8 @@ they will be run along with the main tests by maintenance/parserTests.php
 * (bug 6345) Update to Indonesian localisation (id) #22
 * (bug 6279) Add genitive month names to Slovenian localisation
 * (bug 6351) Update to German translation (de)
-* Respect language directionality when displaying arrow in Special:Brokenredirects
+* Respect language directionality when displaying arrow in
+  Special:Brokenredirects
 * Remove unused "validation" table definitions from the schema files
 * (bug 6398) Work around apparent PCRE bug breaking section editing when
   massively-indented preformatted text immediately followed a header
@@ -15082,12 +16407,14 @@ they will be run along with the main tests by maintenance/parserTests.php
 * (bug 6423) Don't update newtalk flag if page content didn't change (null edits
   were causing the newtalk flag to trigger inappropriately)
 * Parser functions are now set using magic words.
-* (bug 6428) Incorrect form action URL on Special:Newimages with hidebots = 0 set
-* (bug 4990) Show page source to blocked users on edits, or their modified version
-  if blocked during an edit
+* (bug 6428) Incorrect form action URL on Special:Newimages with hidebots = 0
+  set
+* (bug 4990) Show page source to blocked users on edits, or their modified
+  version if blocked during an edit
 * (bug 5903) When requesting the raw source of a non-existent message page,
   return blank content (as opposed to the message key)
-* Improve default blank content of MediaWiki:Common.css and MediaWiki:Monobook.css
+* Improve default blank content of MediaWiki:Common.css and
+  MediaWiki:Monobook.css
 * (bug 6434) Allow customisation of submit button text on Special:Export
 * (bug 6314) Add user tool links on page histories
 * Fix display of file-type icons in galleries when $wgIgnoreImageErrors is off
@@ -15096,8 +16423,8 @@ they will be run along with the main tests by maintenance/parserTests.php
   localizble extensions magic words.
 * Update to Romanian translation (ro)
 * Update to Esperanto translation (eo)
-* Check for preg_match() existence when installing and die out whining about PCRE
-  if it's not there, instead of throwing a fatal error
+* Check for preg_match() existence when installing and die out whining about
+  PCRE if it's not there, instead of throwing a fatal error
 * (bug 672) Add MathAfterTexvc hook
 * Update to Piedmontese localization (pms)
 * dumpBackup can optionally compress via dbzip2
@@ -15114,7 +16441,8 @@ they will be run along with the main tests by maintenance/parserTests.php
 * Fix transwiki import of pages with space in name
 * Save null edit when importing pages through Special:Import
 * Update to Korean translation (ko)
-* Show a more specific message when an anonymous user tries to access Special:Watchlist
+* Show a more specific message when an anonymous user tries to access
+  Special:Watchlist
 * (bug 3278) Paging links in Special:Prefixindex
 * Added Latvian localization (lv)
 * (bug 6472) Fix regression in Special:Export with multiple pages
@@ -15125,9 +16453,11 @@ they will be run along with the main tests by maintenance/parserTests.php
 * Show some error results in moveBatch.php
 * (bug 6479) Allow specification of the skin to use during HTML dumps
 * (bug 6461) Link to page histories in Special:Newpages
-* (bug 6484) Don't do message transformations when preloading messages for editing
+* (bug 6484) Don't do message transformations when preloading messages for
+  editing
 * (bug 6201) Treat spaces as underscores in parameters to {{ns:}}
-* (bug 6006) Allow hiding the password change fields using an authentication plugin
+* (bug 6006) Allow hiding the password change fields using an authentication
+  plugin
 * (bug 6489) Use appropriate link colour on Special:Shortpages
 * Added formatnum magic word
 * Added Javanese localization (jv)
@@ -15150,7 +16480,8 @@ they will be run along with the main tests by maintenance/parserTests.php
 * (bug 6506) Update to German localisation (de)
 * (bug 502) Avoid silly tabs on bad title by using virtual special page
 * (bug 6511) Add diff links to old revision navigation bar
-* (bug 6511) Replace 'oldrevisionnavigation' message with 'old-revision-navigation'
+* (bug 6511) Replace 'oldrevisionnavigation' message with
+  'old-revision-navigation'
 * Fix regression in Polish genitive month forms
 * (bug 4037) Make input handling in Special:Allpages and Special:Prefixindex
   more consistent: Accept just a namespace prefix and a colon, reject input
@@ -15180,10 +16511,416 @@ they will be run along with the main tests by maintenance/parserTests.php
 * (bug 6560) Avoid PHP notice when trimming ISBN whitespace
 * Added namespace translation to Kannada (ka)
 * (bug 6566) Improve input validation on timestamp conversion
-* Implicit group "emailconfirmed" for all users whose email addresses are confirmed
+* Implicit group "emailconfirmed" for all users whose email addresses are
+  confirmed
 * (bug 6577) Avoid multiline parser breakage on <pre> with newline in attribute
 * (bug 6771) Make old revisions of MediaWiki pages available with action=raw
 
+
+== Compatibility ==
+MediaWiki 1.7 requires PHP 5 (5.1 recommended). PHP 4 is no longer supported.
+
+If you are unable to run PHP 5, you may have to stick with 1.6 for now.
+
+MySQL 3.23.x is no longer supported; some older hosts may need to upgrade.
+At this time we still recommend 4.0, but 4.1/5.0 will work fine in most cases.
+
+Experimental Oracle support has been dropped as it is unmaintained.
+
+== Upgrading ==
+Several changes to the database have been made from 1.6:
+
+* A new "langlinks" table tracks interlanguage links
+* A new "filearchive" table stores information on deleted files
+* A new "querycache_info" table stores information on query page updates
+
+To ensure that these tables are filled with data, run refreshLinks.php after
+the upgrade.
+
+If you are upgrading from MediaWiki 1.4.x or earlier, some major database
+changes are made, and there is a slightly higher chance that things could
+break. Don't forget to always back up your database before upgrading!
+
+== Configuration changes ==
+
+Some configuration options have changed:
+* $wgAllowExternalImages now defaults to off for increased security.
+* $wgLocalTZoffset was in hours, it is now using minutes.
+* Extensions may register special pages via the $wgSpecialPages array without
+forcing an early load of the SpecialPage.php class file.
+
+== Major new features ==
+
+* Deleted files can now be archived and undeleted, if you set up an appropriate
+non-web-accessible directory. Set $wgSaveDeletedFiles on and an appropriate
+directory path in $wgFileStore['deleted']['directory']
+* Experimental PostgreSQL support has been updated. It may or may not be in
+usable shape; those interested in PostgreSQL are encouraged to follow 1.8
+development.
+
+=== Caveats ===
+Some output, particularly involving user-supplied inline HTML, may not
+produce 100% valid or well-formed XHTML output. Testers are welcome to
+set $wgMimeType = "application/xhtml+xml"; to test for remaining problem
+cases, but this is not recommended on live sites. (This must be set for
+MathML to display properly in Mozilla.)
+
+= MediaWiki 1.6 =
+
+== MediaWiki 1.6.12 ==
+
+February 7, 2009
+
+This is a security update to the Spring 2006 quarterly release.
+
+A number of cross-site scripting (XSS) security vulnerabilities were discovered
+in the web-based installer (config/index.php). These vulnerabilities all
+require a live installer -- once the installer has been used to install a
+wiki,  it is deactivated.
+
+Note that cross-site scripting vulnerabilities can be used to attack any
+website in the same cookie domain. So if you have an uninstalled copy of
+MediaWiki on the same site as an active web service, MediaWiki could be used to
+attack the active service.
+
+If you are hosting an old copy of MediaWiki that you have never installed, you
+are advised to remove it from the web.
+
+== MediaWiki 1.6.11 ==
+
+December 15, 2008
+
+This is a security update to the Spring 2006 quarterly release.
+
+David Remahl of Apple's Product Security team has identified a number of
+security issues in previous releases of MediaWiki. Subsequent analysis by the
+MediaWiki development team expanded the scope of these vulnerabilities. The
+issues with a significant impact are as follows:
+
+* An XSS vulnerability affecting Internet Explorer clients for all MediaWiki
+installations with uploads enabled. [CVE-2008-5250]
+* An XSS vulnerability affecting clients with SVG scripting capability (such as
+Firefox 1.5+), for all MediaWiki installations with SVG uploads enabled.
+[CVE-2008-5250]
+* A CSRF vulnerability affecting the Special:Import feature, for all MediaWiki
+installations since the feature was introduced in 1.3.0. [CVE-2008-5252]
+
+XSS (cross-site scripting) vulnerabilities allow an attacker to steal an
+authorised user's login session, and to act as that user on the wiki. The
+authorised user must visit a web page controlled by the attacker in order to
+activate the attack. Intranet wikis are vulnerable if the attacker can
+determine the intranet URL, even if the attacker cannot access it.
+
+CSRF vulnerabilities allow an attacker to act as an authorised user on the
+wiki, but unlike an XSS vulnerability, the attacker can only act as the user in
+a specific and restricted way. The present CSRF vulnerability allows pages to
+be edited, with forged revision histories. Like an XSS vulnerability, the
+authorised user must visit the malicious web page to activate the attack.
+
+Rather than backport our SVG validation code to this ancient branch, we have
+instead disabled SVG uploads. To enable SVG uploads, please upgrade to
+MediaWiki 1.13.3 or later.
+
+The other two issues have been fixed.
+
+== MediaWiki 1.6.10 ==
+
+February 20, 2007
+
+This is a security and bug-fix update to the Spring 2006 quarterly release.
+
+An XSS injection vulnerability based on Microsoft Internet Explorer's UTF-7
+charset autodetection was located in the AJAX support module, affecting MSIE
+users on MediaWiki 1.6.x and up when the optional setting $wgUseAjax is enabled.
+
+If you are using an extension based on the optional Ajax module, either disable
+it or upgrade to a version containing the fix:
+
+* 1.9: fixed in 1.9.3
+* 1.8: fixed in 1.8.4
+* 1.7: fixed in 1.7.3
+* 1.6: fixed in 1.6.10
+
+There is no known danger in the default configuration, with $wgUseAjax off.
+
+* ([[mediazilla:8819|bug 8819]]) Fix full path disclosure with skins
+dependencies
+* Add 'charset' to Content-Type headers on various HTTP error responses to
+forestall additional UTF-7-autodetect XSS issues. PHP sends only 'text/html' by
+default when the script didn't specify more details, which some inconsiderate
+browsers consider a license to autodetect the deadly, hard-to-escape UTF-7.
+This fixes an issue with the Ajax interface error message on MSIE when
+$wgUseAjax is enabled (not default configuration); this UTF-7 variant on a
+previously fixed attack vector was discovered by Moshe BA from BugSec:
+http://www.bugsec.com/articles.php?Security=24
+* Trackback responses now specify XML content type
+
+== MediaWiki 1.6.9 ==
+
+January 9, 2007
+
+* ([[mediazilla:6621|bug 6621]]) Backported German translation for
+'eauthentsent'
+
+* ([[mediazilla:6680|bug 6680]]) Added localisation for Dutch bookstore list
+(nl)
+* ([[mediazilla:6730|bug 6730]]) Clearer usage of message 'titlematch' in
+German translation (de)
+* XSS fix in AJAX module
+
+An XSS injection vulnerability was located in the AJAX support module,
+affecting MediaWiki 1.6.x and up when the optional setting $wgUseAjax is
+enabled.
+
+There is no danger in the default configuration, with $wgUseAjax off.
+
+If you are using an extension based on the optional AJAX module, either disable
+it or upgrade to a version containing the fix:
+
+* 1.9: fixed in 1.9.0rc2
+* 1.8: fixed in 1.8.3
+* 1.7: fixed in 1.7.2
+* 1.6: fixed in 1.6.9
+
+== MediaWiki 1.6.8 ==
+
+July 8, 2006
+
+MediaWiki 1.6.8 is a security and bugfix maintenance release of the Spring 2006
+snapshot:
+
+A potential HTML/JavaScript-injection vulnerability in a debugging script has
+been fixed. Only versions and configurations of PHP vulnerable to the $GLOBALS
+overwrite vulnerability are affected.
+
+As a workaround for existing installs, profileinfo.php may simply be deleted if
+it's not being used.
+
+* ([[mediazilla:5957|bug 5957]]) Updates to Hebrew translation (he)
+* Respect language directionality when displaying arrow in
+Special:Brokenredirects
+* ([[mediazilla:6415|bug 6415]]) Typo in Parser.php
+* Fixed potential XSS in profileinfo.php
+
+== MediaWiki 1.6.7 ==
+
+June 6, 2006
+
+MediaWiki 1.6.7 is a security and bugfix maintenance release of the Spring 2006
+snapshot:
+
+An HTML/JavaScript-injection vulnerability in the edit form has been closed.
+This vulnerability was new in 1.6.0; MediaWiki versions 1.5.x or earlier are
+not affected.
+
+Extensions, comments, and <nowiki><nowiki></nowiki> sections are now handled in
+a one-pass way which is more reliable and safer. Under earlier versions of
+MediaWiki, certain extensions could be abused to inject HTML/JavaScript into
+the page.
+
+Additional precautions are made against offsite form submissions when the
+restricted raw HTML mode is enabled.
+
+Some small localization and user interface updates are also included.
+
+*([[MediaZilla:6051|bug 6051]]) Improvement to German localisation (de)
+*([[MediaZilla:6017|bug 6017]]) Update bookstore list for German language (de)
+*([[MediaZilla:6138|bug 6138]]) Minor grammar tweak in "loginreqlink"
+*([[MediaZilla:5957|bug 5957]]) Update for Hebrew language (he)
+*Increase robustness of parser placeholders; fixes some glitches when adjacent
+to identifier-ish constructs such as URLs.
+*([[MediaZilla:5384|bug 5384]]) Fix <nowiki><!-- comments --> in <ref></nowiki>
+extension
+*Nesting of different tag extensions and comments should now work more
+consistently and more safely. A cleaner, one-pass tag strip lets the 'outer'
+tag either take source (<nowiki><nowiki></nowiki>-style) or pass it down to
+further parsing (<nowiki><ref></nowiki>-style). There should no longer be
+surprise expansion of foreign extensions inside HTML output, or differences in
+behavior based on the order tags are loaded.
+*([[MediaZilla:885|bug 885]]) Pre-save transform no longer silently appends
+close tags
+*Pre-save transform no longer changes the case of close tags
+*Edit security precautions in raw HTML mode, etc
+
+== MediaWiki 1.6.6 ==
+
+May 23, 2006
+
+MediaWiki 1.6.6 is a security and bugfix maintenance release.
+
+An XSS injection vector in brace replacement has been fixed, as have some
+potential problems with table parsing. Upgrading is strongly recommended for
+all users of 1.6. MediaWiki versions 1.5 and earlier are not affected.
+
+Additionally some localization and user interface updates are included.
+
+* Correct "revertpage" message in English
+* ([[MediaZilla:5507|bug 5507]]) Logouttext now uses wiki markup
+* (bugs [[MediaZilla:5857|5857]], [[MediaZilla:5957|5957]]) Update for German
+localisation (de)
+* ([[MediaZilla:5586|bug 5586]]) <nowiki><gallery></nowiki> treated text as
+links
+* ([[MediaZilla:5957|bug 5957]]) Update for Hebrew language (he)
+* ([[MediaZilla:6025|bug 6025]]) SpecialImport: wrong message when no file
+selected
+* ([[MediaZilla:6015|bug 6015]]) EditPage: add spacing in the boxes "edit is
+minor" and "watch this"
+* ([[MediaZilla:6018|bug 6018]]) Userrights: new message when no user specified
+('nouserspecified')
+* ([[MediaZilla:6055|bug 6055]]) Fix for HTML/JS injection bug in variable
+handler (found by Nick Jenkins)
+* Reordered wiki table handling and <nowiki>__TOC__</nowiki> extraction in the
+parser to better handle some overlapping tag cases.
+* Only the first <nowiki>__TOC__</nowiki> is now turned into a TOC.
+* ([[MediaZilla:361|bug 361]]) URL in URL, they were almost fixed. Now they are.
+
+== MediaWiki 1.6.5 ==
+
+May 2, 2006
+
+* Rolled back the buggy patch for [[MediaZilla:5497|bug 5497]].
+
+== MediaWiki 1.6.4 ==
+
+May 2, 2006
+
+* Further improvements to Hebrew localisation
+* ([[MediaZilla:5544|bug 5544]]) Fix redirect arrow in Special:Listredirects
+for right-to-left languages
+* Replace "doubleredirectsarrow" with a content language check that picks the
+appropriate arrow
+* Remove live debugging hack which caused errors with certain database names
+* ([[MediaZilla:5510|bug 5510]]) Warning produced when using
+<nowiki>{{SUBPAGENAME}}</nowiki> in some namespaces
+* ([[MediaZilla:5548|bug 5548]]) Improvements to Indonesian localisation
+[patch: Ivan Lanin]
+* ([[MediaZilla:5403|bug 5403]]) Fix Special:Newpages RSS/Atom feeds
+* ([[MediaZilla:3359|bug 3359]]) Add hooks on completion of file upload
+* ([[MediaZilla:5184|bug 5184]]) CSS misapplied to elements in
+Special:Allmessages due to conflicting anchor identifiers
+* ([[MediaZilla:5519|bug 5519]]) Allow sidebar cache to be disabled; disable it
+by default.
+* Add $wgReservedUsernames configuration directive to block account creation/use
+* ([[MediaZilla:5576|bug 5576]]) Remove debugging hack in session check
+* ([[MediaZilla:5181|bug 5181]]) Update "nogomatch" for Slovak
+* ([[MediaZilla:5594|bug 5594]]) Id translation up to '# Login and logout
+pages' section
+* ([[MediaZilla:5536|bug 5536]]) Use content language for editing help link
+* Minor improvements to English language files
+* Improvements to German localisation files
+* ([[MediaZilla:5628|bug 5628]]) Translations for MessagesHr.php
+* (bugs [[MediaZilla:5595|5595]], [[MediaZilla:5644|5644]]) Localisation for
+Bosnian language (bs)
+* ([[MediaZilla:5592|bug 5592]]) Actions are logged with the default language
+for the wiki, not the language of the user performing the operation.
+* ([[MediaZilla:5646|bug 5646]]) Compare for identical types in wfElement()
+* Fix for concurrency problem in job queue (image description page invalidation)
+* ([[MediaZilla:5497|bug 5497]]) regeression in HTML normalization in 1.6
+(unclosed <nowiki><li>,<dd>,<dt></nowiki>)
+* ([[MediaZilla:5709|bug 5709]]) Allow customisation of separator for categories
+* ([[MediaZilla:4834|bug 4834]]) Fix XHTML output when using $wgMaxTocLevel
+* Improvements to update scripts; print out the version, check for superuser
+credentials before attempting a connection, and produce a friendlier error if
+the connection fails
+* ([[MediaZilla:5005|bug 5005]]): Fix XHTML <nowiki><gallery></nowiki> output.
+* ([[MediaZilla:5315|bug 5315]]) "Expires: -1" HTTP header made strictly valid
+(using 1970 date).
+* ([[MediaZilla:4825|bug 4825]]): note in DefaultSettings.php about 'profiling'
+table creation
+* Remove unneeded extra whitespace at top of Special:Categories
+* Rewrite reassignEdits script to be more efficient; support optional updates
+to recent changes table; add reporting and silent modes
+* Updated initStats maintenance script
+* ([[MediaZilla:5723|bug 5723]]) Don't count pages linked to from the MediaWiki
+namespace as "wanted"
+* ([[MediaZilla:5789|bug 5789]]) Treat "loginreqpagetext" as wikitext
+* ([[MediaZilla:5796|bug 5796]]) We require MySQL >=4.0.14
+
+== MediaWiki 1.6.3 ==
+
+April 10, 2006
+
+* Fix disappearing red-linked items in the watchlist editing view
+* ([[MediaZilla:5512|bug 5512]]) Spacing in "page has a history" deletion
+warning
+* ([[MediaZilla:5508|bug 5508]]) Switch ENGINE in table statements back to
+TYPE; fixes regression where some versions of MySQL 4.0.x wouldn't work
+* Added note about [[Manual:$wgUrlProtocols|$wgUrlProtocols]] format change
+
+== MediaWiki 1.6.2 ==
+
+April 8, 2006
+
+* Further improvements to Hebrew localisation
+* Fix 'copyright' message for Romanian
+* ([[MediaZilla:5476|bug 5476]]) Invalid xhtml in German localization
+* ([[MediaZilla:5479|bug 5479]]) Id translation for preferences tabs caption
+* ([[MediaZilla:5493|bug 5493]]) Id translation for special pages
+* Additional path fixes in the updater
+* ([[MediaZilla:5344|bug 5344]]) Fix regression that broke slashes in extension
+tag parameters
+
+== MediaWiki 1.6.1 ==
+
+April 5, 2006
+
+Some minor issues in the 1.6.0 release have been corrected:
+* ([[MediaZilla:5458|bug 5458]]) Fix double-URL encoding in block log link in
+contribs and contribs link in block log
+* ([[MediaZilla:5462|bug 5462]]) Bogus missing patch warning in updater
+* ([[MediaZilla:5461|bug 5461]]) Use of deprecated "showhideminor" in
+Special:Recentchangeslinked
+* PHP warning when allow_call_time_pass_reference is off
+* Update to Finnish localization
+
+== MediaWiki 1.6.0 ==
+
+April 5, 2006
+
+MediaWiki is now using a "continuous integration" development model with
+quarterly snapshot releases. The latest development code is always kept "ready
+to run", and in fact runs our own sites on Wikipedia.
+
+Release branches will continue to receive security updates for about a year
+from first release, but nonessential bugfixes and feature development will take
+place on the development trunk and will appear in the next quarterly release.
+
+Those wishing to use the latest code instead of a branch release can [[Download
+from SVN|obtain it from source control]].
+
+=== What's new in 1.6 ===
+
+'''User interface:'''
+* The account creation form has been separated from the user login form.
+* Page protection/unprotection uses a new, expanded form
+
+'''Templates:'''
+* Categories and "what links here" now update as expected when adding or
+removing links in a template.
+* Template parameters can now have default values, as <nowiki>{{{name|default
+value}}}</nowiki>
+
+'''Uploads:'''
+* Optional support for rasterizing SVG images to PNG for inline display
+
+'''Feeds:'''
+* Feed generation upgraded to Atom 1.0
+* Diffs in RSS and Atom feeds are now colored for improved readability.
+
+'''Database:'''
+* MySQL 3.23.x support dropped; 4.0 or later required
+* Experimental support for Unicode mode of MySQL 4.1/5.0 (moderately tested)
+* Experimental Oracle support (not well tested!)
+
+'''Anti-spam extension support:'''
+* [[meta:SpamBlacklist extension|SpamBlacklist extension]] now has support for
+automated cleanup.
+* Support for a [[meta:ConfirmEdit extension|captcha extension]] to restrict
+automated spam edits.
+
+Numerous bug fixes and other behind-the-scenes changes have been made; see the
+file HISTORY for a complete change list.
+
 == Changes since 1.5 ==
 
 * (bug 2885) More PHP 5.1 fixes: skin, search, log, undelete
@@ -15304,15 +17041,16 @@ Installer:
 * Add basic check for session support in PHP and die if not present
 
 Maintenance:
-* Fix problem reported on mailing list where re-initialising stats didn't work (can't insert
-  duplicate rows with the same id field)
+* Fix problem reported on mailing list where re-initialising stats didn't work
+  (can't insert duplicate rows with the same id field)
 * Added --conf option to command line scripts, allowing the user to specify a
   different LocalSettings.php.
 * Maintenance script to delete unused text records
 * Maintenance script to delete non-current revisions
 * Maintenance script to wipe a page and all revisions from the database
 * Maintenance script to reassign edits from one user to another
-* Maintenance script to find and remove links to a given domain (cleanupSpam.php)
+* Maintenance script to find and remove links to a given domain
+  (cleanupSpam.php)
 * Fix --report interval option for dumpTextPass
 
 i18n / Languages:
@@ -15353,7 +17091,8 @@ i18n / Languages:
 * (bug 2981) Linktrail for Tamil (ta)
 * (bug 3722) Update of Arabic language (ar) Namespace changes
 * Removed hardcoded Norwegian (no) project namespaces
-* (bug 2324) image for redirects should be without text and oriented according to content language
+* (bug 2324) image for redirects should be without text and oriented according
+  to content language
 * (bug 3666) Don't spew PHP warnings in prefs on unrecognized site language
 * (bug 3817) Use localized date formats in preferences; 'no preference' option
   localizable as 'datedefault' message. Tweaked lots of languages files...
@@ -15425,7 +17164,8 @@ i18n / Languages:
 * Typo in English messages file
 * (bug 4114) Spacing in watchlist rows (in editing mode)
 * Update default "exporttext" to reflect that Special:Import exists
-* (bug 4960) Add additional namespaces variants to Yi projects: Yiddish Wikinews fix
+* (bug 4960) Add additional namespaces variants to Yi projects: Yiddish Wikinews
+  fix
 * (bug 5357) Add the icon near the user name also in RTL interfaces
 * (bug 5156) Update for Hebrew language (he)
 * (bug 4497,4704,5010) Added some new language codes.
@@ -15473,7 +17213,8 @@ Upload:
 * (bug 2527) Always set destination filename when new file is selected
 * (bug 3076) Support MacBinary-encoded uploads from IE/Mac
 * (bug 2554) Tell users they are uploading too large file
-* Support for a license selection box on Special:Upload, configurable from MediaWiki:Licenses
+* Support for a license selection box on Special:Upload, configurable from
+  MediaWiki:Licenses
 * Add 'reupload' and 'reupload-shared' permission keys to restrict new uploads
   overwriting existing files; default is the old behavior (allowed).
 
@@ -15508,10 +17249,12 @@ Security:
   MIME type to the default blacklist. Prevented inline display of images
   which are not of known image types. This is in response to
   http://en.wikipedia.org/wiki/Windows_Metafile_vulnerability
-* Blocked users can no longer roll back, change the protection of, or delete/undelete pages
+* Blocked users can no longer roll back, change the protection of, or
+  delete/undelete pages
 * Protect against spoofing of X-Forwarded-For header
 * XSS issue : now sanitize search query input (fixed in 1.5rc3)
-* Remove deprecated $wgOnlySysopsCanPatrol references; use User::isAllowed( 'patrol' )
+* Remove deprecated $wgOnlySysopsCanPatrol references; use
+  User::isAllowed( 'patrol' )
   per bug 5282. Patch by Alan Harder.
 * Prevent registration/login with the username "MediaWiki default"
 
@@ -15566,15 +17309,18 @@ Special Pages:
 * JavaScript filter for Special:Allmessages
 * (bug 3047) Don't mention talk pages on Special:Movepage when there isn't one
 * Show links to user page, talk page and contributions page on Special:Newpages
-* Special:Export can now export a list of all contributors to an article (off by default)
+* Special:Export can now export a list of all contributors to an article (off by
+  default)
 * (bug 5372) Add number of files to Special:Statistics
 * (bug 2871) Links to talk pages in watchlist editing view
 * (bug 5385) Allow hiding anonymous edits on Special:Recentchanges
 * (bug 2544) Illogical error reporting order in Special:Userlogin
-* (bug 5409) Hide "show/hide patrolled edits" in Special:Recentchanges if patrolling
-  is disabled
-* (bug 5447) Convert first letter of username to uppercase before searching in Special:Listusers
-* (bug 759) Wrap redirects on the watchlist editing page in a span, class "watchlistredir"
+* (bug 5409) Hide "show/hide patrolled edits" in Special:Recentchanges if
+  patrolling is disabled
+* (bug 5447) Convert first letter of username to uppercase before searching in
+  Special:Listusers
+* (bug 759) Wrap redirects on the watchlist editing page in a span, class
+  "watchlistredir"
 * (bug 1862) Namespace filtering in watchlists
 
 Misc.:
@@ -15611,8 +17357,10 @@ fully support the editing toolbar, but was found to be too confusing.
   dumpBackup.php
 * (bug 3595) Warn and abort if importDump.php called in read-only mode.
 * (bug 3598) Update message cache on message page deletion, patch by Tietew
-* Added separate noarticletext and newarticletext messages for logged in and anon users.
-* (bug 3332) Installation now uses Monobook, validates, plus usability improvements.
+* Added separate noarticletext and newarticletext messages for logged in and
+  anon users.
+* (bug 3332) Installation now uses Monobook, validates, plus usability
+  improvements.
 * (bug 3660) Update diff3 detection to work with Windows/Cygwin
 * (bug 2330) Don't do funny thinks with "links" in MediaWiki:Undeletedtext
 * Two-pass data dump for friendliness to the DB (--stub, then dumpTextPass.php)
@@ -15734,8 +17482,8 @@ fully support the editing toolbar, but was found to be too confusing.
 * Cleanup and error checking on Special:Listredirects
 * Clear up some instances of old OutputPage::sysopRequired() function usage
 * Improve "upload disabled" notice
-* Move parts of index.php to include/Wiki.php in an attempt to both cleanup index.php
-  and create a MediaWiki-class mediaWiki base object
+* Move parts of index.php to include/Wiki.php in an attempt to both cleanup
+  index.php and create a MediaWiki-class mediaWiki base object
 * (bug 4104) Added OutputPageBeforeHTML hook for tweaking primary wiki output
   HTML on final output (cached or not)
 * Avoid PHP notice on command-line scripts if empty argument is passed ('')
@@ -15768,10 +17516,10 @@ fully support the editing toolbar, but was found to be too confusing.
 * (bug 3990) Use existing session name if session.auto_start is on
   Fixes checks for open sessions, such as the cookie warning on login.
   Patch by Zbigniew Braniecki.
-* Add cache-safe alternate sitenotice for anonymous users. (MediaWiki:Anonnotice)
-  This is displayed instead of the regular sitenotice, if it exists. If not, the
-  regular sitenotice shows. If that doesn't exist, the value of $wgSiteNotice is used,
-  and if that's null, then nothing is shown.
+* Add cache-safe alternate sitenotice for anonymous users.
+  (MediaWiki:Anonnotice) This is displayed instead of the regular sitenotice,
+  if it exists. If not, the regular sitenotice shows. If that doesn't exist,
+  the value of $wgSiteNotice is used, and if that's null, then nothing is shown.
 * Spit the generated LocalSettings code out during the installer as an aid
   to debugging issues. (Keep this?)
 * Use __FILE__ to form path in new LocalSettings.php, so it stays accurate
@@ -15860,12 +17608,15 @@ fully support the editing toolbar, but was found to be too confusing.
 * Fix explicit s-maxage=0 on raw pages; should help with proxy issues in
   generated stylesheets... hopefully...
 * (bug 4685) More fixes for Slovenian project namespace
-* Fixed and enhanced a little the Live Preview, which had been broken for some time
+* Fixed and enhanced a little the Live Preview, which had been broken for some
+  time
 * Added article size limit, $wgMaxArticleSize
 * (bug 4974) Don't follow redirected talk page on "new messages" link
 * (bug 4970) Make category paging limits configurable
-* (bug 4535) Warn user when editing CSS or JS subpage of a skin that doesn't exist
-* Make Live Preview an user preference, still controllable by the global variable
+* (bug 4535) Warn user when editing CSS or JS subpage of a skin that doesn't
+  exist
+* Make Live Preview an user preference, still controllable by the global
+  variable
 * Rename the stub LanguageAls / LanguageGem_alsation to LanguageGsw to follow
   updated language code assignments
 * (bug 5081) Remove bogus fix for invalid characters in links which simply
@@ -15882,7 +17633,8 @@ fully support the editing toolbar, but was found to be too confusing.
 * (bug 5141) Gracefully handle the new account link when createaccount off
 * (bug 5150 and related) Fix missing ID attribute in HTML namespace selector
 * (bug 5152) Proper HTML escaping on subpage breadcrumbs
-* (bug 4855) Section edit links now have the section name in the title attribute.
+* (bug 4855) Section edit links now have the section name in the title
+  attribute.
 * (bug 2115) Support shift-selecting multiple checkboxes with JavaScript.
 * (bug 5161) Don't try to load template list for nonexistent pages
 * (bug 5228) Workaround for broken LanguageConverter title overrides; avoid
@@ -15905,14 +17657,18 @@ fully support the editing toolbar, but was found to be too confusing.
   reliable beyond the hostname where it's used for the spam bulk checker.
 * Don't URL-decode in the title attribute for URL links; it can produce false
   results that don't code back to their original values.
-* (bug 4611) Add user preference (default on) to add new pages to creators's watchlist
+* (bug 4611) Add user preference (default on) to add new pages to creators's
+  watchlist
 * (bug 5286) Fix regression in display of missing/bad revision IDs
-* (bug 4729) Add user preference that marks a user's edits as patrolled if user is able to
-* (bug 4630) Add user preference to prompt users when entering blank edit summaries
+* (bug 4729) Add user preference that marks a user's edits as patrolled if user
+  is able to
+* (bug 4630) Add user preference to prompt users when entering blank edit
+  summaries
 * Added optional suggest feature for the search box. Set wgUseAjax to true to
   enable it.
 * (bug 5277) Use audio/midi rather that audio/mid
-* (bug 5410) Use namespace name when a custom namespace's nstab-NS message is nonexistent
+* (bug 5410) Use namespace name when a custom namespace's nstab-NS message is
+  nonexistent
 * (bug 5432) Fix inconsistencies in cookie names when using table prefixes
 * Additional protections against HTML breakage in table parsing
 * (bug 5355) Include skin name and style JS settings in page source;
@@ -15923,14 +17679,54 @@ fully support the editing toolbar, but was found to be too confusing.
 * (bug 5195) rebuildrecentchanges.php works again; Database::insertSelect now
   has a parameter for select options.
 * Fix updateSearchIndex.php for new schema
-* Fix bogus "filename too short" error when uploading files with a period in the base
-  name, e.g. "Mr. Zee.png"
+* Fix bogus "filename too short" error when uploading files with a period in the
+  base name, e.g. "Mr. Zee.png"
 * (bug 2139) Show page title in subtitle when viewing "read only" page
 * (bug 5452) Update language name for Cree
 
+== Compatibility ==
+
+Older PHP 4.2 and 4.1 releases are no longer supported; PHP 4 users must
+upgrade to 4.3 or later.
 
+MediaWiki 1.6 is the last major version to support PHP 4; future versions will
+require PHP 5.
 
-----
+MySQL 3.23.x is no longer supported; some older hosts may need to upgrade.
+At this time we still recommend 4.0, but 4.1/5.0 will work fine in most cases.
+
+== Upgrading ==
+
+Several changes to the database have been made from 1.5; these are relatively
+minor but do require that the update process be run before the new code will
+work properly:
+
+* A new "templatelinks" table tracks template inclusions.
+* A new "externallinks" table tracks URL links; this can be used by a mass
+spam-cleanup tool in the SpamBlacklist extension.
+* A new "jobs" table stores a queue of pages to update in the background; this
+is used to update links in including pages when templates are edited.
+
+To ensure that these tables are filled with data, run refreshLinks.php after
+the upgrade.
+
+If you are upgrading from MediaWiki 1.4.x or earlier, some major database
+changes are made, and there is a slightly higher chance that things could
+break. Don't forget to always back up your database before upgrading!
+
+=== Caveats ===
+
+Some output, particularly involving user-supplied inline HTML, may not produce
+100% valid or well-formed XHTML output. Testers are welcome to set $wgMimeType
+= "application/xhtml+xml"; to test for remaining problem cases, but this is not
+recommended on live sites. (This must be set for MathML to display properly in
+Mozilla.)
+
+
+= MediaWiki 1.5 =
+
+== MediaWiki 1.5.9 ==
+* (bug 3359) Add hooks on completion of file upload
 
 == MediaWiki 1.5.8 ==
 
@@ -16141,7 +17937,8 @@ Uploads:
   It's now possible to specify the final filename of an upload distinct
   from the original filename on your disk.
 
-  An image link for a missing file will now take you straight to the upload page.
+  An image link for a missing file will now take you straight to the upload
+  page.
 
   More metadata is pre-extracted from uploaded images, which will ease pressure
   on disk or NFS volumes used to store images. EXIF metadata is displayed on
@@ -16407,31 +18204,41 @@ Various bugfixes, small features, and a few experimental things:
 * 'live preview' reduces preview reload burden on supported browsers
 * support for external editors for files and wiki pages:
   https://www.mediawiki.org/wiki/Manual:External_editors
-* Schema reworking: https://www.mediawiki.org/wiki/Proposed_Database_Schema_Changes/October_2004
-* (bug 15) Allow editors to view diff of their change before actually submitting an edit
+* Schema reworking:
+  https://www.mediawiki.org/wiki/Proposed_Database_Schema_Changes/October_2004
+* (bug 15) Allow editors to view diff of their change before actually submitting
+  an edit
 * (bug 190) Hide your own edits on the watchlist
 * (bug 510): Special:Randompage now works for other namespaces than NS_MAIN.
 * (bug 1015) support for the full wikisyntax in <gallery> captions.
 * (bug 1105) A "Destination filename" (save as) added to Special:Upload Upload.
-* (bug 1352) Images on description pages now get thumbnailed regardless of whether the thumbnail is larger than the original.
-* (bug 1662) A new magicword, {{CURRENTMONTHABBREV}} returns the abbreviation of the current month
+* (bug 1352) Images on description pages now get thumbnailed regardless of
+  whether the thumbnail is larger than the original.
+* (bug 1662) A new magicword, {{CURRENTMONTHABBREV}} returns the abbreviation of
+  the current month
 * (bug 1668) 'Date format' supported for other languages than English, see:
   http://mail.wikipedia.org/pipermail/wikitech-l/2005-March/028364.html
-* (bug 1739) A new magicword, {{REVISIONID}} give you the article or diff database
-  revision id, useful for proper citation.
+* (bug 1739) A new magicword, {{REVISIONID}} give you the article or diff
+  database revision id, useful for proper citation.
 * (bug 1998) Updated the Russian translation.
 * (bug 2064) Configurable JavaScript mimetype with $wgJsMimeType
-* (bug 2084) Fixed a regular expression in includes/Title.php that was accepting invalid syntax like #REDIRECT [[foo] in redirects
-* It's now possible to invert the namespace selection at Special:Allpages and Special:Contributions
+* (bug 2084) Fixed a regular expression in includes/Title.php that was accepting
+  invalid syntax like #REDIRECT [[foo] in redirects
+* It's now possible to invert the namespace selection at Special:Allpages and
+  Special:Contributions
 * No longer using sorbs.net to check for open proxies by default.
-* What was $wgDisableUploads is now $wgEnableUploads, and should be set to true if one wishes to enable uploads.
+* What was $wgDisableUploads is now $wgEnableUploads, and should be set to true
+  if one wishes to enable uploads.
 * Supplying a reason for a block is no longer mandatory
 * Language conversion support for category pages
 * $wgStyleSheetDirectory is no longer an alias for $wgStyleDirectory;
 * Special:Movepage can now take parameters like Special:Movepage/Page_to_move
-  (used to just be able to take parameters via a GET request like index.php?title=Special:Movepage&target=Page_to_move)
-* (bug 2151) The delete summary now includes editor name, if only one has edited the article.
-* (bug 2105) Fixed from argument to the PHP mail() function. A missing space could prevent sending mail with some versions of sendmail.
+  (used to just be able to take parameters via a GET request like
+  index.php?title=Special:Movepage&target=Page_to_move)
+* (bug 2151) The delete summary now includes editor name, if only one has edited
+  the article.
+* (bug 2105) Fixed from argument to the PHP mail() function. A missing space
+  could prevent sending mail with some versions of sendmail.
 * (bug 2228) Updated the Slovak translation
 * ...and more!
 
@@ -16447,7 +18254,8 @@ Various bugfixes, small features, and a few experimental things:
 * (bug 898) The wiki can now do advanced sanity check on uploaded files
   including virus checks using external programs.
 * (bug 1692) Fix margin on unwatch tab
-* (bug 1906) Generalize project namespace for Latin localization, update namespaces
+* (bug 1906) Generalize project namespace for Latin localization, update
+  namespaces
 * (bug 1975) The name for Limburgish (li) changed from "Lèmburgs" to "Limburgs
 * (bug 2019) Wrapped the output of Special:Version in <div dir='ltr'> in order
   to preserve the correct flow of text on RTL wikis.
@@ -16456,7 +18264,8 @@ Various bugfixes, small features, and a few experimental things:
 * (bug 2079) Removed links to Special:Maintenance from movepagetext message
 * (bug 2094) Multiple use of a template produced wrong results in some cases
 * (bug 2095) Triple-closing-bracket thing partly fixed
-* (bug 2110) "noarticletext" should not display on Image page for "sharedupload" media
+* (bug 2110) "noarticletext" should not display on Image page for "sharedupload"
+  media
 * (bug 2150) Fix tab indexes on edit form
 * (bug 2152) Add missing bgcolor to attribute whitelist for <td> and <th>
 * (bug 2176) Section edit 'show changes' button works correctly now
@@ -16507,7 +18316,8 @@ Various bugfixes, small features, and a few experimental things:
 * (bug 2053) Move comment whitespace trimming from edit page to save;
   leaves the whitespace from the section comment there on preview.
 * (bug 2274) Respect stub threshold in category page list
-* (bug 2173) Fatal error when removing an article with an empty title from the watchlist
+* (bug 2173) Fatal error when removing an article with an empty title from the
+  watchlist
 * Removed -f parameter from mail() usage, likely to cause failures and bounces.
 * (bug 2130) Fixed interwiki links with fragments
 * (bug 684) Accept an attribute parameter array on parser hook tags
@@ -16554,7 +18364,8 @@ Various bugfixes, small features, and a few experimental things:
 * (bug 1120) Updated the Czech translation
 * A new magic word, {{SCRIPTPATH}}, returns $wgScriptPath
 * A new magic word, {{SERVERNAME}}, returns $wgServerName
-* A new magic word, {{NUMBEROFFILES}}, returns the number of rows in the image table
+* A new magic word, {{NUMBEROFFILES}}, returns the number of rows in the image
+  table
 * Special:Imagelist displays titles with " " instead of "_"
 * Less gratuitous munging of content sample in delete summary
 * badaccess/badaccesstext to supercede sysop*, developer* messages
@@ -16699,8 +18510,10 @@ of MediaWiki:Newpagetext) to &action=edit, if page is new.
 * (bug 1170) Fixed linktrail for da: and ru:
 * (bug 2683) Really fix apostrophe escaping for toolbox tips
 * (bug 923) Fix title and subtitle for rclinked special page
-* (bug 2642) watchdetails message in several languages used  <a></a> instead of [ ]
-* (bug 2181) basic CSB language localisation by Tomasz G. Sienicki (thanks for the patch)
+* (bug 2642) watchdetails message in several languages used  <a></a> instead of
+  [ ]
+* (bug 2181) basic CSB language localisation by Tomasz G. Sienicki (thanks for
+  the patch)
 * Fix correct use of escaping in edit toolbar bits
 * Removed language conversion support from Icelandic
 * (bug 2616) Fix proportional image scaling, giving correct height
@@ -16715,7 +18528,8 @@ of MediaWiki:Newpagetext) to &action=edit, if page is new.
 == Changes since 1.5beta2 ==
 
 * Escaped & correctly in Special:Contributions
-* (bug 2534) Hide edit sections with CSS to make right click to edit section work
+* (bug 2534) Hide edit sections with CSS to make right click to edit section
+  work
 * (bug 2708) Avoid undefined notice on cookieless login attempt
 * (bug 2188) Correct template namespace for Greek localization
 * Fixed number formatting for Dutch
@@ -16724,15 +18538,18 @@ of MediaWiki:Newpagetext) to &action=edit, if page is new.
 * Massive update for Arab (ar) language using Wikipédia
 * (bug 1560) Massive update for Kurdish (ku) language using Wikipédia
 * (bug 2709) Some messages were not read from database
-* (bug 2416) Don't allow search engine robots to index or follow nonexisting articles
+* (bug 2416) Don't allow search engine robots to index or follow nonexisting
+  articles
 * Fix escaping in page move template.
 * (bug 153) Discrepancy between thumbnail size and <img> height attribute
 
 == Changes since 1.5beta3 ==
 
 * Fix talk page move handling
-* (bug 2721) New language file for Vietnamese with the Vietnamese number notation
-* (bug 2749) &nbsp; would appear as a literal in image galleries for Cs, Fr, Fur, Pl and Sv
+* (bug 2721) New language file for Vietnamese with the Vietnamese number
+  notation
+* (bug 2749) &nbsp; would appear as a literal in image galleries for Cs, Fr,
+  Fur, Pl and Sv
 * (bug 787) external links being rendered when they only have one slash
 * Fixed a missing typecast in Language::dateFormat() that would cause some
   interesting errors with signitures.
@@ -17034,7 +18851,8 @@ of MediaWiki:Newpagetext) to &action=edit, if page is new.
 === Changes since 1.5.7 ===
 
 * (bug 5180) User login page shows inappropriate email blurb
-* Add the "AbortNewAccount" hook on account creation; see hooks.txt for more info.
+* Add the "AbortNewAccount" hook on account creation; see hooks.txt for more
+  info.
 * Update default "exporttext" to reflect that Special:Import exists
 * Add links to useful material to the default main page content
 * Fix fragment HTML injection
@@ -17056,7 +18874,141 @@ set $wgMimeType = "application/xhtml+xml"; to test for remaining problem
 cases, but this is not recommended on live sites. (This must be set for
 MathML to display properly in Mozilla.)
 
-----
+= MediaWiki 1.4 =
+
+== MediaWiki 1.4.15 ==
+
+(released March 26, 2006) MediaWiki 1.4.15 is a security maintenance release. A
+bug in decoding of certain encoded links could allow injection of raw HTML into
+page output; this could potentially lead to XSS attacks. Additionally, this
+release may display more correctly in IE7 betas.
+
+== MediaWiki 1.4.14 ==
+(released January 19, 2006) MediaWiki 1.4.14 is a security and bugfix
+maintenance release. A bug in edit comment formatting could send PHP into an
+infinite loop if certain malformed links were included. In most installations,
+this would cause the script to fail after PHP's 30-second failsafe timeout. For
+several other minor fixes, see the complete changelog at the end of this file.
+
+== MediaWiki 1.4.13 ==
+(released January 5, 2006) MediaWiki 1.4.13 is a security maintenance
+release.Detection for uploads of Windows Metafile (.wmf) images has been added
+to help protect against a client-side vulnerability in unpatched Microsoft
+Windows operating systems. Sites which have enabled uploads and added
+non-standard file types (such as .ogg, .doc, or .pdf) should upgrade to this
+release to ensure that malicious .wmf files can't be uploaded with a fake
+extension; such files could put visitors to the site at risk. For more details
+on this, see: http://en.wikipedia.org/wiki/Windows_Metafile_vulnerability
+
+== MediaWiki 1.4.12 ==
+(released 2005-11-02) MediaWiki 1.4.12 is a bugfix and security maintenance
+release. A change in PHP 4.4.1 broke handling of extension and
+<nowiki><pre></nowiki> sections, causing garbage data to be inserted in output
+and saved edits. This version works around the change. This release includes
+further corrections to the inline CSS style sanitation which works around a
+JavaScript "feature" on Microsoft Internet Explorer. Users of Microsoft
+Internet Explorer for Windows may be vulnerable to XSS injections on prior 1.4
+releases; users of standards-compliant browsers are not vulnerable.
+
+== MediaWiki 1.4.11 ==
+(released 2005-10-05) MediaWiki 1.4.11 is a security maintenance release.
+Unsafe handling of CSS by Microsoft Internet Explorer could be exploited to
+produce cross-site scripting attacks by JavaScript injection to clients running
+that browser. This release blacklists several additional variants from use in
+HTML inline style attributes. All publicly accessible wikis are recommended to
+upgrade to reduce the risk to visitors using Microsoft web browsers. Note: the
+MediaWiki 1.4.x series is not compatible with PHP 5.0.5 or higher. Upgrade to
+the 1.5.0 release if you require this version of PHP 5.
+
+== MediaWiki 1.4.10 ==
+(released 2005-09-21) MediaWiki 1.4.10 is a security maintenance release. A bug
+in edit submission handling could cause corruption of the previous revision in
+the database if an abnormal URL was used, such as those used by some spambots.
+Affected releases:
+* 1.4.x <= 1.4.9; fixed in 1.4.10
+* 1.3.x <= 1.3.15; fixed in 1.3.16
+1.5 release candidates are not affected by this problem. All publicly editable
+wikis are strongly recommended to upgrade immediately.
+1.4 releases can be manually patched by changing this bit in EditPage.php:
+
+<syntaxhighlight lang="php">
+function importFormData( &$request ) {
+        if( $request->wasPosted() ) {
+</syntaxhighlight>
+to:
+<syntaxhighlight lang="php">
+    function importFormData( &$request ) {
+        if( $request->getVal( 'action' ) == 'submit' && $request->wasPosted() )
+        {
+</syntaxhighlight>
+== MediaWiki 1.4.9 ==
+(released 2005-08-29) MediaWiki 1.4.9 is a security maintenance release. It
+corrects two cross-site scripting security bugs:
+* <nowiki><math></nowiki> tags were handled incorrectly when TeX rendering
+support is off, as in the default configuration.
+* Extension or <nowiki><nowiki></nowiki> sections in Wiki table syntax could
+bypass HTML style attribute restrictions for cross-site scripting attacks
+against Microsoft Internet Explorer Wikis where the optional math support has
+been *enabled* are not vulnerable to the first, but are vulnerable to the
+second.
+
+== MediaWiki 1.4.8 ==
+(released 2005-08-23) MediaWiki 1.4.8 is a bug fix and security maintenance
+release. A flaw in the interaction between extensions and HTML attribute
+sanitization was discovered which could allow unauthorized use of offsite
+resources in style sheets, and possible exploitation of a JavaScript injection
+feature on Microsoft Internet Explorer. This version expands the returned text
+and properly checks it before output. Additionally, an update to
+skins/MonoBook.php ensures that sites using the default MonoBook skin will
+display correctly in the Internet Explorer 7 beta. (1.3 and 1.5 are not
+affected by this bug.)
+
+== MediaWiki 1.4.7 ==
+(released 2005-07-16)
+MediaWiki 1.4.7 is a bug fix release. Those affected by the following problems
+in 1.4.6 should upgrade:
+* Watchlist breakage on MySQL 3.23.x and with table prefix enabled
+* Possible breakage in watchlist, some image resizing modes on PHP 4.1.2 1.4.6
+included a fix for a cross-site scripting vulnerability, so anyone running
+older 1.4 releases is very strongly encouraged to upgrade as well. Note to
+upgraders: this version of MediaWiki is known to produce a large number of
+notice-level warnings under the newly released PHP 4.4.0. These appear however
+to be harmless; if you encounter them add this to your LocalSettings.php to
+suppress the notices: error_reporting( E_ALL & ~E_NOTICE ); PHP 5.1.0beta3 is
+known to be incompatible at this time.
+
+== MediaWiki 1.4.6 ==
+(released 2005-07-07) MediaWiki 1.4.6 is a bug fix and security update release.
+Incorrect escaping of a parameter in the page move template could
+be used to inject JavaScript code by getting a victim to visit a maliciously
+constructed URL. Users of vulnerable releases are recommended to upgrade to
+this release. Vulnerable versions:
+* 1.5 preview series: n <= 1.5beta2 vulnerable, fixed in 1.5beta3
+* 1.4 stable series: 1.4beta6 <= n <= 1.4.5 vulnerable, fixed in 1.4.6
+* 1.3 legacy series: not vulnerable This release also includes fixes for some
+rare bug annoying HTTP errors, a PHP 4.1.2 breakage bug, and works around some
+template limitations introduced in 1.4.5. See the changelog at the end of this
+file for a detailed list of bugs fixed.
+
+== MediaWiki 1.4.5 ==
+(released 2005-06-03) MediaWiki 1.4.5 is a security update and bugfix release.
+Incorrect handling of page template inclusions made it possible to inject
+JavaScript code into HTML attributes, which could lead to cross-site scripting
+attacks on a publicly editable wiki. Vulnerable releases and fix:
+* 1.5 prerelease: fixed in 1.5alpha2
+* 1.4 stable series: fixed in 1.4.5
+* 1.3 legacy series: fixed in 1.3.13
+* 1.2 series no longer supported; upgrade to 1.4.5 strongly recommended This
+release also includes a number of bug fixes (see changelog below) and merges
+some large-server load balancing patches from Wikipedia. An experimental rate
+limiter for page edits and moves can be enabled with global, per-IP,
+per-subnet, or per-user bases. See configuration options in
+includes/DefaultSettings.php
+
+== MediaWiki 1.4.4 ==
+(released 2005-05-04) MediaWiki 1.4.4 is a bugfix release for the 1.4 stable
+release series. Some bugs in the installer/updater and refreshLinks maintenance
+script were introduced in the last release and have been corrected.
 
 == MediaWiki 1.4.3 ==
 
@@ -17273,8 +19225,8 @@ pages for purposes of page relevancy ranking.
 === Misc bugs fixed in beta 1 ===
 
 * (bug 95) Templates no longer limited to 5 inclusions per page
-* New user preference for limiting the image size for images on image description
-  pages
+* New user preference for limiting the image size for images on image
+  description pages
 * (bug 530) Allow user to preview article on first edit
 * (bug 479) [[RFC 1234]] will now make an internal link
 * (bug 511) PhpTal skins shown bogus 'What links here' etc on special pages
@@ -17391,7 +19343,8 @@ pages for purposes of page relevancy ranking.
   in diff-view
 * Use user's local timezone in Special:Log display
 * Show filename for images in gallery by default (restore beta 3 behavior)
-* (bug 1201) Double-escaping in brokenlinks, imagelinks, categorylinks, searchindex
+* (bug 1201) Double-escaping in brokenlinks, imagelinks, categorylinks,
+  searchindex
 * When using squid reverse proxy, cache the redirect to the Main_Page
 * (bug 1302) Fix Norwegian language file
 * (bug 1205) Fix broken article saving in PHP 5.1
@@ -17448,7 +19401,8 @@ pages for purposes of page relevancy ranking.
 * Add fur/Furlan/Friulian to language names list
 * Add TitleMoveComplete hook on page renames
 * Allow simple comments for each translation rules in MW:Zhconversiontable
-* (bug 1402) Make link color of tab subject page link on talk page indicate whether article exists
+* (bug 1402) Make link color of tab subject page link on talk page indicate
+  whether article exists
 * (bug 1368) Fix SQL error on stopword/short word search w/ MySQL 3.x
 * Translated Hebrew namespace names
 * (bug 1429) Stop double-escaping of block comments; fix formatting
@@ -17507,7 +19461,8 @@ pages for purposes of page relevancy ranking.
 * (bug 563) Fix UTF-8 interwiki URL redirects via Latin-1 wikis
 * (bug 1536) Fix page info
 * Support os (Ossetic) as language code, using Russian localization base
-* (bug 1610) Support non (Old Norse) as language code, using Icelandic localization base
+* (bug 1610) Support non (Old Norse) as language code, using Icelandic
+  localization base
 * (bug 1618) Properly list custom namespaces in Special:Allpages
 * (bug 1622) Remove trailing' >' when using category browser
 * (bug 1570) Fix php 4.2.x error on conflict merging
@@ -17649,3 +19604,384 @@ going to run a public MediaWiki, so you can be notified of security fixes.
 === IRC help ===
 
 There's usually someone online in #mediawiki on irc.freenode.net
+
+=MediaWiki 1.3=
+
+== MediaWiki 1.3.18 ==
+(released 2005-11-02)
+MediaWiki 1.3.18 is a bugfix and security maintenance release. A change in PHP
+4.4.1 broke handling of extension and <nowiki><pre></nowiki> sections, causing
+garbage data to be inserted in output and saved edits. This version works
+around the change. This release includes further corrections to the inline CSS
+style sanitation which works around a JavaScript "feature" on Microsoft
+Internet Explorer. Users of Microsoft Internet Explorer for Windows may be
+vulnerable to XSS injections on prior 1.3 releases; users of
+standards-compliant browsers are not vulnerable.
+
+== MediaWiki 1.3.17 ==
+(released 2005-10-05)
+MediaWiki 1.3.17 is a security maintenance release. Unsafe handling of CSS by
+Microsoft Internet Explorer could be exploited to produce cross-site scripting
+attacks by JavaScript injection to clients running that browser. This release
+blacklists several additional variants from use in HTML inline style
+attributes. All publicly accessible wikis are recommended to upgrade to reduce
+the risk to visitors using Microsoft web browsers.Note: the MediaWiki 1.3.x
+series is not compatible with PHP 5.0.5 or higher. Upgrade to the 1.5.0 release
+if you require this version of PHP 5.
+
+== MediaWiki 1.3.16 ==
+(released 2005-09-21)
+MediaWiki 1.3.16 is a security maintenance release. A bug in edit submission
+handling could cause corruption of the previous revision in the database if an
+abnormal URL was used, such as those used by some spambots. Affected releases:
+* 1.4.x <= 1.4.9; fixed in 1.4.10
+* 1.3.x <= 1.3.15; fixed in 1.3.16
+1.5 release candidates are not affected by this problem. All publicly editable
+wikis are strongly recommended to upgrade immediately.
+1.3 releases can be manually patched by changing this bit in
+{{manual|EditPage.php}}:
+<syntaxhighlight lang="php">
+    if( $this->tokenOk( $request ) ) {
+        $this->save    = $request->wasPosted() && !$this->preview;
+    } else {
+</syntaxhighlight>
+to:
+<syntaxhighlight lang="php">
+    if( $this->tokenOk( $request ) ) {
+        $this->save    = $request->getVal( 'action' ) == 'submit' &&
+                         $request->wasPosted() && !$this->preview;
+    } else {
+</syntaxhighlight>
+
+== MediaWiki 1.3.15, 2005-08-29 ==
+MediaWiki 1.3.15 is a security maintenance release. It corrects across-site
+scripting security bug:
+* <nowiki><math></nowiki> tags were handled incorrectly when TeX rendering
+support is off, as in the default configuration. Wikis where the optional math
+support has been *enabled* are not vulnerable. The 1.3.x series is no longer
+maintained except for security fixes; new users and those seeking bug fixes
+should upgrade to 1.4.9 or 1.5.0.
+
+== MediaWiki 1.3.14, 2005-08-23 ==
+MediaWiki 1.3.14 is a security maintenance release. A flaw in the interaction
+between extensions and HTML attribute sanitization was discovered which could
+allow unauthorized use of offsite resources in style sheets, and possible
+exploitation of a JavaScript injection feature on Microsoft Internet Explorer.
+The 1.3.x series is no longer maintained except for security fixes; new users
+and those seeking bug fixes should upgrade to 1.4.8 or 1.5.0. Existing 1.3.x
+installations not willing to upgrade to the current stable release should apply
+the change manually:
+In includes/Parser.php, function {{code|inline=y|lang=php|fixTagAttributes()}}
+add:
+<syntaxhighlight lang="php">
+       # Any placeholder items should have been unstripped already before
+       # we got to this point. Raw text inserted later could be dangerous.
+       if( strpos( $t, UNIQ_PREFIX ) !== false ) {
+           wfDebug( "Parser::fixTagAttributes found stripped data placeholder;
+           dropping attributes\n" );
+           $t = '';
+       }
+</syntaxhighlight>
+If you are actively using extensions to generate HTML attribute values, upgrade
+to 1.4 or 1.5 for a more thorough fix.
+
+== MediaWiki 1.3.13, 2005-06-03 ==
+MediaWiki 1.3.13 is a security maintenance release. Incorrect handling of page
+template inclusions made it possible to inject JavaScript code into HTML
+attributes, which could lead to cross-site scripting attacks on a publicly
+editable wiki. Vulnerable releases and fix:
+* 1.5 prerelease: fixed in 1.5alpha2
+* 1.4 stable series: fixed in 1.4.5
+* 1.3 legacy series: fixed in 1.3.13
+* 1.2 series no longer supported; upgrade to 1.4.5 strongly recommended The
+1.3.x series is no longer maintained except for security fixes; new users and
+those seeking general bug fixes should install 1.4.5. Existing 1.3.x
+installations not willing or able to upgrade to the current stable relase
+should update the installation to 1.3.13; only includes/Parser.php has changed
+from 1.3.12.
+
+== MediaWiki 1.3.12, 2005-02-20 ==
+MediaWiki 1.3.12 is a security maintenance release. A cross-site scripting
+injection vulnerability was discovered, which affects only MSIE clients and is
+only open if MediaWiki has been manually configured to run output through HTML
+Tidy ($wgUseTidy). The 1.3.x series is no longer maintained except for security
+fixes; new users and those seeking bug fixes should upgrade to 1.4.2. Existing
+1.3.x installations using Tidy not willing to upgrade to the current stable
+relase should either turn off Tidy or update the installation to 1.3.12.
+
+== MediaWiki 1.3.11, 2005-02-20 ==
+MediaWiki 1.3.11 is a security release.
+A security audit found and fixed a number of problems. Users of MediaWiki
+1.3.10 and earlier should upgrade to 1.3.11; users of 1.4 beta releases should
+upgrade to 1.4rc1.
+
+=== Cross-site scripting vulnerability ===
+XSS injection points can be used to hijack session and authentication cookies
+as well as more serious attacks.
+* Media: links output raw text into an attribute value, potentially abusable
+for JavaScript injection. This has been corrected.
+* Additional checks added to file upload to protect against MSIE and Safari
+MIME-type autodetection bugs.
+As of <code>1.3.10/1.4beta6</code>, per-user customized CSS and JavaScript is
+disabled by default as a general precaution. Sites which want this ability may
+set {{wg|AllowUserCss}} and {{wg|AllowUserJs}} in LocalSettings.php.
+
+=== Cross-site request forgery ===
+An attacker could use JavaScript-submitted forms to perform various restricted
+actions by tricking an authenticated user into visiting a malicious web page. A
+fix for page editing in 1.3.10/1.4beta6 has been expanded in this release to
+other forms and functions. Authors of bot tools may need to update their code
+to include the additional fields.
+
+=== Directory traversal ===
+An unchecked parameter in image deletion could allow an authenticated
+administrator to delete arbitary files in directories writable by the web
+server, and confirm existence of files not deletable.
+
+== MediaWiki 1.3.10, 2005-02-03 ==
+MediaWiki 1.3.10 is a security release.
+An attacker could craft a URL which, when visited by a particular logged-in
+user, would execute arbitrary JavaScript code on the user's browser in the
+wiki's site context. This attack has been blocked, and as an extra precaution
+the user CSS and JavaScript subpage support is now disabled by default. Sites
+which want this ability may set {{wg|AllowUserCss}} and {{wg|AllowUserJs}} in
+{{manual|LocalSettings.php}}. Additional protections have been added against
+off-site form submissions
+hijacking user credentials. Authors of bot tools may need to update their code
+to include additional fields. All wikis running 1.3.x are strongly urged to
+upgrade to 1.3.10.
+Changes from 1.3.9:
+* Logged-in edits and preview of user CSS/JS are now locked to a session token.
+* Per-user CSS and JavaScript subpage customizations now disabled by default.
+They can be re-enabled via {{wg|AllowUserJs}} and {{wg|AllowUserCss}}.
+* Removed .ogg from the default uploads whitelist as an extra precaution. If
+your web server is configured to serve Ogg files with the correct Content-Type
+header, you can re-add it in LocalSettings.php: {{wg|FileExtensions}}<code>[] =
+'ogg'</code>
+
+== MediaWiki 1.3.9, 2004-12-12 ==
+MediaWiki 1.3.9 is a security and bug fix release.
+A flaw in upload handling has been found which may allow upload and  execution
+of arbitrary scripts with the permissions of the web server. Only wikis that
+have enabled uploads and have a vulnerable Apache  configuration will be
+affected, but to be safe all wikis should upgrade. Wikis with uploads available
+should either disable uploads or upgrade to 1.3.9 immediately; if other files
+are customized and require merging changes,
+includes/{{manual|SpecialUpload.php}} may be replaced individually to add the
+fix. (It is also recommended to configure your web server to disable script
+execution in the 'images' subdirectory where uploads are placed, which prevents
+most attacks even if the wiki fails.)
+Changes from 1.3.8:
+* Backported "Templates used in this page"-feature of EditPage
+* Allow "MySkin" as a default skin.
+* ({{bugzilla|938}}) Parse namespaces correctly on self-interwiki links
+* ({{bugzilla|1010}}) fix broken Commons image link on [[Skin:Classic|Classic]]
+& [[Skin:Cologne Blue|Cologne Blue]]
+* ({{bugzilla|1004}}) Norsk language names for interwiki links changed, Nauruan
+language name changed
+* Enhance upload extension blacklist to protect against vulnerable Apache
+configurations
+
+== MediaWiki 1.3.8, 2004-11-15 ==
+MediaWiki 1.3.8 is a bugfix release. Those running wikis with uploads enabled
+are strongly recommended to upgrade as this fixes several problems with
+overwriting previously-uploaded files.
+Changes from 1.3.7:
+* ({{bugzilla|506}}) fix {{code|inline=y|lang=html|array_key_exists()}} warning
+for IIS servers using ISAPI mode
+* ({{bugzilla|718}}) fix bad charset in (file) cached pages
+* use local numerals in category page (for Hindi et al)
+* alias month abbreviations to month names in Hindi
+* add localized numerals for Gujarati and Kannada
+* fix Category and project namespaces for Hindi
+* Don't output bogus timestamp on [[Special:RecentChanges]] if no entries
+* Correct template include path which broke some but not all Windows installs
+* Fix edit form submission problem with some PHP versions
+* Disallow unreachable titles with %XX hex codes
+* Allow page [[0]] to be renamed
+* ({{bugzilla|774}}) when saving with <code>section=new</code>, return to the
+anchor as with existing numbered section edits
+* Experimental shared upload overlay area (disabled by default)
+* ({{bugzilla|806}}) Removed some "Wikipedia" hardcoding in German localization
+* User option localization fix for some extensions
+* ({{bugzilla|809}}) now try to load the mysql php extension if it isn't loaded
+* ({{bugzilla|848}}) fix error message in [[Special:Newpages]] RSS and Atom
+feeds
+* ({{bugzilla|26}}) fix cache headers on anon talk page notification
+* ({{bugzilla|874}}) added 'cgi' to {{wg|FileBlacklist}}
+* ({{bugzilla|862}}) localize date and time format for Finnish
+* ({{bugzilla|548}}) Don't overwrite images until the user confirms it
+
+== MediaWiki 1.3.7, 2004-10-18 ==
+Changes from 1.3.6:
+* Fix protected-page related security issue.
+
+== MediaWiki 1.3.6, 2004-10-14 ==
+Changes from 1.3.5:
+* ({{bugzilla|296}}) Variables in user interface messages are no longer
+substituted at install time, so changes to the site name etc should be easier
+to make
+* ({{bugzilla|149}}) [[Special:RecentChanges]] "changes from" link preserves
+limit
+* ({{bugzilla|433}}) tooltip for "Undelete" tab now labeled correctly
+* ({{bugzilla|439}}) unclickable "Move" tab no longer displays on protected
+pages
+* ({{bugzilla|484}}) graceful deletion of images where the actual file is
+missing
+* ({{bugzilla|686}}) fixed [[plural]]s in Catalan localization
+* Fixed potential HTML/JavaScript injection attack in the
+[[Extension:UnicodeConverter|UnicodeConverter]] extension. (This extension is
+not enabled by default.)
+* Fixed potential HTML/JavaScript injection attack via raw page views to a
+maliciously crafted wiki page.
+* ({{bugzilla|187}}, {{bugzilla|669}}) Fixed centered thumbnails, using
+{{code|inline=y|lang=html|<div>}} instead of {{code|inline=y|lang=html|<span>}}.
+* catch MySQL error 2000 during installation.
+* ({{bugzilla|704}}) Removed misleading LocalSettings.sample
+* Fix cross site scripting bugs in [[Special:Ipblocklist]],
+[[Special:EmailUser]]
+* Fix SQL injection and cross site scripting bugs in Special:Maintenance
+* Fix cross site scripting bugs and possible filename validation vulnerability
+in ImagePage.
+* and more of that sort
+
+== MediaWiki 1.3.5, 2004-09-30 ==
+Changes from 1.3.4:
+* Clean up input validation in 'raw' page output mode which was a potential
+cross-site scripting opportunity.
+
+== MediaWiki 1.3.4, 2004-09-28 ==
+=== SECURITY NOTE ===
+As of 1.3.4, MediaWiki performs some screening of newly uploaded files for
+validity. (Some)  corrupt image files, and HTML files mistakenly or maliciously
+masquerading as images, should now be rejected. These checks protect against
+Internet Explorer security holes relating to type autodetection which are a
+potential cross-site scripting attack vector, and also rejects at least one
+known version of the "JPEG virus" which might attack unpatched clients. If you
+already have invalid files uploaded this will not protect against them. If you
+have expanded the <code>filetype</code> whitelist or disabled the strict type
+checking, other dangerous file types may still get through. You should always
+be careful when allowing uploads!
+Changes from 1.3.3:
+* Fixed lots of template-related bugs, esp. for cases where template variables
+are used for links, images, etc.
+* Fixed transformation of page messages when viewing [[Special:Allmessages]]
+* Handle "ISBN ISBN 1234" correctly
+* Fixed warning on Category pages
+* Fixed some bad error messages on login page
+* Fixed history entry for initial main page on install
+* Removed problematic <code>{</code> and <code>}</code> from legal title
+characters
+* Strip leading blank from output in preformatted text.
+* Fixed problem when moving pages to titles with '#' in
+* Optional {{wg|RawHtml}} for raw {{code|inline=y|lang=html|<html>}} sections.
+Use only on limited- participation 'trusted' wikis, as it does not protect
+against cross-site scripting attacks. For security, this option can only be
+enabled if in {{wg|WhitelistEdit}} mode.
+* Fixed problem where pages which were created as a redirect following a move
+never showed on [[Special:Randompage]].
+* Fixed line spacing on printed table of contents
+* Allow links to pages with names of the form [[RFC 1234]]
+* Fixed broken edit links being shown for sections from included templates
+* Verify that uploaded image files are of the claimed type.
+
+== MediaWiki 1.3.3, 2004-09-09 ==
+Changes from 1.3.2:
+* Fix for long numeric page titles
+* Fix Go search for "0", numeric almost-self-links
+* Avoid caching of pages with "You have new messages" headers
+* Fix for upgrades as non-root users from 1.2 command-line installs.
+* Fix for {{wg|DebugDumpSql}} debug mode.
+* {{wg|ExtraNamespaces}} setting for configuring additional namespaces (see
+note in {{manual|DefaultSettings.php}})
+* 'recache' on query pages now disabled when miser mode is on; special case the
+global settings in your {{manual|LocalSettings.php}} to do automatic updates.
+* Don't block UTF-8 titles containing byte 0xA0 (bug added in 1.3.2)
+* Watch/unwatch tabs now shown on edit pages in MonoBook.
+* Fix default skin in Irish localization (ga)
+* Add Traditional Chinese localization (zh-tw)
+* Changed default sortkey of subcategories. Don't include "Category:"-prefix
+any longer
+* More helpful info on spam catcher.
+* Allow larger offsets for queries such as [[Special:Listusers]]
+* Semicolon (;) added to French non-break space rules
+* Possible fix for some install errors with path names permission problems.
+* Removed [[Project:All system messages]], which has been superseded by the
+much faster [[Special:Allmessages]]. This speeds up installation considerably.
+
+== MediaWiki 1.3.2, 2004-08-30 ==
+Changes from 1.3.1:
+* Fix namespaced page creation links when no go match
+* When cookies are disabled, don't show login screen twice
+* Install should no longer die when PHP is pre-configured to compress output
+* Fixed bug that caused long Japanese pages to time out with Tidy active
+* When session.handler is set incorrectly, try automatic override to 'files'
+* Watch/Unwatch links back to the affected page instead of Main Page
+* Upload link no longer displayed on Monobook if uploading is disabled
+* Special:Allmessages faster, shows correct original text, works in safe mode
+
+== MediaWiki 1.3.1, 2004-08-14 ==
+Changes from 1.3.0:
+* Watchlist parameters now work with register_globals off
+* Fixed parsing of ''italics'' and '''bold''' mark-up (again)
+* Special:Allpages display is more sensible on smaller wikis
+* Fixed XHTML parsing error in classic skins
+* Moved pages update watchlist correctly
+* Fixed rebuildall.php on case-sensitive Unix filesystems
+* Disabled file cache compression by default due to incompatibility with output
+buffer compression (ob_gzhandler)
+* New magic word {{code|inline=y|PAGENAMEE}} (URL-escaped version of
+{{code|inline=y|PAGENAME}})
+* Installation avoids blank username; better message on missing XML module
+* {{wg|WhitelistAccount}} no longer breaks all logins.
+
+== MediaWiki 1.3.0, 2004-08-11 ==
+Look & layout:
+* New default layout '[[Skin:MonoBook|MonoBook]]' (available on PHP4 only
+currently)
+* Print stylesheet now built-in to every page
+* More or less correct XHTML 1.0 (served as text/html by default)
+Wiki features:
+* Image captions can now include links and other basic formatting
+* Image bounding box can be specified instead of width, e.g. as 100x100px,
+making the image not wider than 100px and not higher than 100px, keeping aspect
+ratio.
+* Templates have been expanded with parameters, and separated from the
+MediaWiki: localization scheme.
+* Categories more or less work
+* added a special page for listing users with sysop rights.
+Editing:
+* Automatic merging of edit conflicts that don't directly interfere
+* Edit summaries can now include basic formatting and links
+Metadata and output:
+* Linked Creative Commons copyright metadata (optional)
+* RSS 2.0 & Atom 0.3 feeds for Recent Changes, New Pages
+Optional modules:
+* WikiHiero hieroglyphic module can be added (separate download)
+* Timeline module can be added (separate download). Requires ploticus.
+* TeX now has an experimental MathML output mode (incomplete!)
+Installation and upgrading:
+* The old install.php and update.php have been removed. In-place installation
+introduced in 1.2 is now the standard installation and upgrade method, see
+INSTALL and UPGRADE for directions.
+Database:
+* The links table has been changed to use a cur_id for l_from. The link tables
+must be converted on upgrade, which may entail some downtime.
+Code and compatibility:
+* Should now run clean with error reporting set to E_ALL.
+* register_globals hack from 1.2 has been replaced with safer code
+* Bundled PHPTAL 0.7.0 from http://phptal.sourceforge.net/ (with some patches)
+* Most image-related code moved to Image.php
+* More fixes for PHP 4.1.2 (thanks to Asheesh Laroia)
+* URL encoding fix for anchors
+* All languages now available in UTF-8 mode
+* Various other fixes
+
+=== Caveats ===
+Some output, particularly involving user-supplied inline HTML, may not produce
+100% valid or well-formed XHTML output. Testers are welcome to set $wgMimeType
+= "application/xhtml+xml"; to test for remaining problem cases, but this is not
+recommended on live sites. (This must be set for MathML to display properly in
+Mozilla.) The new 'MonoBook' skin is not compatible with PHP 5 due to bugs in
+the underlying PHPTAL library. It will be automatically disabled when running
+on PHP5; the older look and feel will be used instead.
index 646a9c2..f9826e2 100644 (file)
@@ -4,8 +4,8 @@
 
 THIS IS NOT A RELEASE YET
 
-MediaWiki 1.33 is an alpha-quality branch and is not recommended for use in
-production.
+MediaWiki 1.33 is a pre-release testing branch, and is not recommended for use
+in production.
 
 == Upgrading notes for 1.33 ==
 1.33 has several database changes since 1.32, and will not work without schema
@@ -27,10 +27,17 @@ Some specific notes for MediaWiki 1.33 upgrades are below:
   run your wiki with $wgActorTableSchemaMigrationStage SCHEMA_COMPAT_READ_OLD,
   note that log_search rows needed to find revision deletions by target user
   were incorrectly deleted. See T215464 for details.
+* If revision deletions were performed when the wiki was configured with
+  $wgActorTableSchemaMigrationStage SCHEMA_COMPAT_WRITE_BOTH and without
+  migrateActors.php having been run, the log_search table may contain rows with
+  empty values for "target_author_actor" which will prevent log searches for
+  revision deletions by target user from finding those log entries. These rows
+  may be corrected by (re-)running migrateActors.php.
 
 For notes on 1.32.x and older releases, see HISTORY.
 
 === Configuration changes for system administrators in 1.33 ===
+
 ==== New configuration ====
 * $wgEnablePartialBlocks – This enables the Partial Blocks feature, which gives
   accounts with block permissions the ability to block users, IPs, and IP ranges
@@ -51,6 +58,10 @@ For notes on 1.32.x and older releases, see HISTORY.
   argon2 to be used, by default, it will automatically choose the best available
   algorithm depending on which version of PHP you have available. To use this,
   you can set `$wgPasswordDefault = 'argon2';`.
+* $wgActorTableSchemaMigrationStage now defaults to reading the new schema.
+  update.php will back-populate the new database fields due to the changed
+  setting, which may take some time on large wikis. You can avoid downtime by
+  following a process like that described in T188327.
 
 ==== Removed configuration ====
 * $wgTagStatisticsNewTable (T199334) — This temporary setting, added in
@@ -78,6 +89,8 @@ For notes on 1.32.x and older releases, see HISTORY.
   is no longer a problem, because the code now ensures the timestamp is always
   higher than the previous one. The writes are guarded with CAS logic (check
   and set), which prevents updates that would overlap.
+* $wgDBmysql5 (T196185) - This experimental setting, deprecated in 1.31, has
+  been removed.
 
 === New user-facing features in 1.33 ===
 * (T96041) __EXPECTUNUSEDCATEGORY__ on a category page causes the category
@@ -101,15 +114,21 @@ For notes on 1.32.x and older releases, see HISTORY.
   Content::getNativeData() for text-based content models.
 * (T214706) LinksUpdate::getAddedExternalLinks() and
   LinksUpdate::getRemovedExternalLinks() were introduced.
+* (T213893) Added 'MaintenanceUpdateAddParams' hook
+* (T219655) The MarkPatrolled hook has a new parameter for the tags
+  associated with this entry in the patrol log.
+* (T212472) Extensions can now specify platform abilities they require to work,
+  limited to shell access for now.
 
 === External library changes in 1.33 ===
+
 ==== New external libraries ====
 * Added wikimedia/password-blacklist 0.1.4.
 * Added guzzlehttp/guzzle 6.3.3.
 * Added jakub-onderka/php-console-highlighter 0.3.2 explicitly (dev-only).
 
 ==== Changed external libraries ====
-* Updated OOUI from v0.29.2 to v0.31.0.
+* Updated OOUI from v0.29.2 to v0.31.2.
 * Updated OOjs Router from pre-release to v0.2.0.
 * Updated moment from v2.19.3 to v2.24.0.
 * Updated wikimedia/xmp-reader from 0.6.0 to 0.6.2.
@@ -126,7 +145,7 @@ For notes on 1.32.x and older releases, see HISTORY.
 * Updated wikimedia/php-session-serializer from 1.0.6 to 1.0.7.
 
 ==== Removed external libraries ====
-* 
+* (T219403) jquery.ui.spinner, deprecated since 1.31, was removed.
 
 === Bug fixes in 1.33 ===
 * (T164211) Special:UserRights could sometimes fail with a
@@ -150,6 +169,9 @@ For notes on 1.32.x and older releases, see HISTORY.
   if entirewatchlist is set, so updates may not be visible immediately
 * Block info will be added to "blocked" errors from more modules.
 * (T216245) Autoblocks will now be spread by action=edit and action=move.
+* action=query&meta=userinfo has a new uiprop, 'latestcontrib', that returns
+  the date of user's latest contribution.
+* (T25227) action=logout now requires to be posted and have a csrf token.
 
 === Action API internal changes in 1.33 ===
 * A number of deprecated methods for API documentation, intended for overriding
@@ -181,6 +203,7 @@ because of Phabricator reports.
   for NS_TEMPLATE.
 * (T212221) Added $digitTransformTable for Santali (sat).
 * (T216479) Added language support for Saisiyat (xsy).
+* (T219728) Added support for new Japanese era name "Reiwa"
 
 === Breaking changes in 1.33 ===
 * The parameteter $lang in DifferenceEngine::setTextLanguage must be of type
@@ -331,6 +354,17 @@ because of Phabricator reports.
   Use ParserOutput::allCacheVaryingOptions instead.
 * CdnCacheUpdate::newSimplePurge, deprecated in 1.27, has been removed.
   Use CdnCacheUpdate::newFromTitles() instead.
+* Handling of multiple arguments by the Block constructor, deprecated in 1.26,
+  has been removed.
+* The translation of main page in Sardinian (sc) was changed from "Pàgina Base"
+  to "Pàgina printzipale". Existing wikis using this content language need to
+  move the main page or change the name through MediaWiki:Mainpage page.
+* wfSplitWikiID(), deprecated in 1.32, has been removed.
+* MessageBlobStore::getBlob(), deprecated in 1.27, has been removed.
+  Use ::getBlobs() instead.
+* The .background-size() LESS mixin, deprecated in 1.27, has been removed.
+* ReadOnlyMode::clearCache() and ConfiguredReadOnlyMode::clearCache() have been
+  removed. Use MediaWikiTestCase::overrideMwServices() instead.
 
 === Deprecations in 1.33 ===
 * The configuration option $wgUseESI has been deprecated, and is expected
@@ -391,9 +425,16 @@ because of Phabricator reports.
   deprecated and will be removed in the future.
 * The FileBasedSiteLookup class has been deprecated. For a cacheable SiteLookup
   implementation, use CachingSiteStore instead.
+* Language::viewPrevNext function is deprecated, use
+  SpecialPage::buildPrevNextNavigation instead
 * ManualLogEntry::setTags() is deprecated, use ManualLogEntry::addTags()
   instead. The setTags() method was overriding the tags, addTags() doesn't
   override, only adds new tags.
+* Block::isValid is deprecated, since it is no longer needed in core.
+* Calling Maintenance::hasArg() as well as Maintenance::getArg() with no
+  parameter has been deprecated. Please pass the argument number 0.
+* ResourceLoaderContext::expandModuleNames has been deprecated.
+  Use ResourceLoader::expandModuleNames instead.
 
 === Other changes in 1.33 ===
 * (T201747) Html::openElement() warns if given an element name with a space
@@ -402,6 +443,15 @@ because of Phabricator reports.
   changed to explicitly cast. Subclasses relying on the base-class
   implementation should check whether they need to override it now.
 * BagOStuff::add is now abstract and must explicitly be defined in subclasses.
+* LinksDeletionUpdate is now a subclass of LinksUpdate. As a consequence,
+  the following hooks will now be triggered upon page deletion in addition
+  to page updates: LinksUpdateConstructed, LinksUpdate, LinksUpdateComplete.
+  LinksUpdateAfterInsert is not triggered since deletions do not cause
+  insertions into links tables.
+* Category::newFromID( $id )->getID() will now return $id without any
+  validation, to avoid a mostly unnecessary DB query.
+* On Special:Version, the name for an extension can no longer be arbitrary
+  html when no link is specified.
 
 == Compatibility ==
 MediaWiki 1.33 requires PHP 7.0.13 or later. Although HHVM 3.18.5 or later is
diff --git a/RELEASE-NOTES-1.34 b/RELEASE-NOTES-1.34
new file mode 100644 (file)
index 0000000..7a74427
--- /dev/null
@@ -0,0 +1,261 @@
+= MediaWiki 1.34 =
+
+== MediaWiki 1.34.0-PRERELEASE ==
+
+THIS IS NOT A RELEASE YET
+
+MediaWiki 1.34 is an alpha-quality development branch, and is not recommended
+for use in production.
+
+== Upgrading notes for 1.34 ==
+1.34 has several database changes since 1.33, and will not work without schema
+updates. Note that due to changes to some very large tables like the revision
+table, the schema update may take quite long (minutes on a medium sized site,
+many hours on a large site).
+
+Don't forget to always back up your database before upgrading!
+
+See the file UPGRADE for more detailed upgrade instructions, including
+important information when upgrading from versions prior to 1.11.
+
+Some specific notes for MediaWiki 1.34 upgrades are below:
+
+* …
+
+For notes on 1.33.x and older releases, see HISTORY.
+
+=== Configuration changes for system administrators in 1.34 ===
+
+==== New configuration ====
+* $wgAllowExternalReqID (T201409) - This configuration setting controls whether
+  Mediawiki accepts the request ID set by the incoming request via the
+  `X-Request-Id` header. If set to `true`, that value will be used throughout
+  the code as the request identificator. Otherwise, the sent header will be
+  ignored and the request ID will either be taken from Apache's mod_unique
+  module or will be generated by Mediawiki itself (depending on the set-up).
+
+==== Changed configuration ====
+* …
+
+==== Removed configuration ====
+* $wgWikiDiff2MovedParagraphDetectionCutoff — If you still want a custom change
+  size threshold, please specify in php.ini, using the configuration variable
+  wikidiff2.moved_paragraph_detection_cutoff.
+
+=== New user-facing features in 1.34 ===
+* …
+
+=== New developer features in 1.34 ===
+* Language::formatTimePeriod now supports the new 'avoidhours' option to output
+  strings like "5 days ago" instead of "5 days 13 hours ago".
+
+=== External library changes in 1.34 ===
+
+==== New external libraries ====
+* …
+
+==== Changed external libraries ====
+* Updated Mustache from 1.0.0 to v3.0.1.
+* Updated OOUI from v0.31.3 to v0.31.5.
+* Updated composer/semver from 1.4.2 to 1.5.0.
+* Updated composer/spdx-licenses from 1.4.0 to 1.5.1 (dev-only).
+* Updated mediawiki/codesniffer from 25.0.0 to 26.0.0 (dev-only).
+* Updated cssjanus/cssjanus from 1.2.1 to 1.3.0.
+* Updated wikimedia/at-ease from 1.2.0 to 2.0.0.
+* …
+
+==== Removed external libraries ====
+* The jquery.async module, deprecated in 1.33, was removed.
+* …
+
+=== Bug fixes in 1.34 ===
+* (T222529) If a log entry or page revision is recorded in the database with an
+  empty username, attempting to display it will log an error and return a "no
+  username available" to the user instead of silently displaying nothing or
+  invalid links.
+
+=== Action API changes in 1.34 ===
+* The 'recenteditcount' response property from action=query list=allusers,
+  deprecated in 1.25, has been removed.
+
+=== Action API internal changes in 1.34 ===
+* …
+
+=== Languages updated in 1.34 ===
+MediaWiki supports over 350 languages. Many localisations are updated regularly.
+Below only new and removed languages are listed, as well as changes to languages
+because of Phabricator reports.
+
+* (T152908) Added language support for N'Ko (nqo).
+
+=== Breaking changes in 1.34 ===
+* The global functions wfSuppressWarnings and wfRestoreWarnings, deprecated in
+  1.26, have been removed. Use Wikimedia\AtEase\AtEase::suppressWarnings() and
+  Wikimedia\AtEase\AtEase::restoreWarnings() directly.
+* Preferences class, deprecated in 1.31, has been removed.
+* The following parts of code, deprecated in 1.32, were removed in favor of
+  built-in PHP functions:
+  * CryptRand class
+  * CryptRand service
+  * Functions of the MWCryptRand class: singleton(), wasStrong() and generate().
+* 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
+  to MWNamespace::getCanonicalNamespaces(), which was deprecated since 1.31.
+  Instead, reset services, such as by calling $this->overrideMwServices() (if
+  your test extends MediaWikiTestCase). Services will generally not pick up
+  configuration changes from after they were created, so you must reset
+  services after any configuration change. Even if your code works now, it is
+  likely to break in future versions as more code is moved to services.
+* The ill-defined "DatabaseOraclePostInit" hook has been removed.
+* PreferencesFormLegacy and PreferencesForm classes, deprecated in 1.32, have
+  been removed.
+* ObjectFactory class, deprecated in 1.31, has been removed.
+* HWLDFWordAccumudlator class, deprecated in 1.28, has been removed.
+* XMPInfo, XMPReader and XMPValidate, deprecated in 1.32, have been removed.
+* The RedirectSpecialPage::execute method could sometimes return a Title object.
+  This behavior was removed, and the method now matches the parent signature
+  (SpecialPage::execute) which is to return HTML string or void.
+  To obtain the destination title, use RedirectSpecialPage::getRedirect.
+* The 'recenteditcount' response property from action API action=query
+  list=allusers, deprecated in 1.25, has been removed.
+* SearchEngine::userNamespaces(), SearchEngine::namespacesAsText(),
+  SearchEngine::create(), SearchEngine::getSearchTypes() and
+  SearchEngine::getNearMatch(), methods deprecated in 1.27, have been removed.
+* FileRepo::streamFile(), deprecated in 1.26, has been removed.
+* User::randomPassword() method, deprecated in 1.27, have been removed.
+* MWNamespace::canTalk(), deprecated in 1.30, have been removed.
+* Parser class property $mUniqPrefix, deprecated in 1.26, has been removed.
+* wfArrayFilter() and wfArrayFilterByKey(), deprecated in 1.32, have been
+  removed.
+* wfMakeUrlIndexes() function, deprecated in 1.33, have been removed.
+* Method signatures in WatchedItemQueryServiceExtension have changed from taking
+  User objects to taking UserIdentity objects. Extensions implementing this
+  interface need to be changed accordingly.
+* User::getGroupPage() and ::makeGroupLinkHTML(), deprecated in 1.29, have been
+  removed. Use UserGroupMembership::getGroupPage and ::getLink instead.
+* User::makeGroupLinkWiki(), deprecated in 1.29, has been removed. Use
+  UserGroupMembership::getLink() instead.
+* SavepointPostgres, deprecated in 1.31, has been removed.
+* Output::sectionEditLinksEnabled(), ParserOutput::getEditSectionTokens,
+  ::getTOCEnabled, ::setEditSectionTokens, ::setTOCEnabled, deprecated in 1.31,
+  have been removed.
+* EditPage::safeUnicodeInput() and ::safeUnicodeOutput(), deprecated in 1.30,
+  have been removed.
+* Four methods in OutputPage, deprecated in 1.32, have been removed. You should
+  use OutputPage::showFatalError or throw a FatalError instead. The methods are
+  ::showFileCopyError(), ::showFileRenameError(), ::showFileDeleteError(), and
+  ::showFileNotFoundError().
+* ApiBase::truncateArray(), deprecated in 1.32, has been removed.
+* IcuCollation::getICUVersion(), deprecated in 1.32, has been removed. Use PHP's
+  INTL_ICU_VERSION constant directly.
+* HTMLForm::setSubmitProgressive(), deprecated in 1.32, has been removed.
+* ResourceLoaderStartUpModules::getStartupModules() and ::getLegacyModules(),
+  both deprecated in 1.32, have been removed.
+* BaseTemplate::msgHtml() and QuickTemplate::msgHtml(), deprecated in 1.32, have
+  been removed. Use ->msg() or ->getMsg() instead.
+* WatchAction::getUnwatchToken(), deprecated in 1.32, has been removed. Instead,
+  use WatchAction::getWatchToken() with action 'unwatch' directly.
+* Language::initEncoding(), ::recodeForEdit(), and recodeInput(), deprecated in
+  1.28, have been removed.
+* PageArchive::getTextFromRow(), ::listAllPages(), and ::getLastRevisionText(),
+  deprecated in 1.32, have been removed.
+* OutputPage::getModuleScripts(), ParserOutput::getModuleScripts(), deprecated
+  in 1.33, have been removed.
+* User::getPasswordValidity(), deprecated in 1.33, has been removed.
+* ApiQueryBase::prepareUrlQuerySearchString(), deprecated in 1.33, has been
+  removed.
+* ChangeTags::purgeTagUsageCache(), deprecated in 1.33, has been removed.
+* JobQueueGroup::pushLazyJobs(), deprecated in 1.33, has been removed.
+* MediaWikiTestCase::stashMwGlobals(), deprecated in 1.32, has been removed.
+* SearchEngine::transformSearchTerm(), deprecated in 1.32, has been removed.
+* The Block typehint only refers to blocks stored in the database. It should be
+  updated to AbstractBlock in cases where any type of block could be expected.
+* FileRepoStatus, deprecated in 1.25, has been removed.
+* The LegacyHookPreAuthenticationProvider class, deprecated since its creation
+  in 1.27, has been removed.
+* IP::isValidBlock(), deprecated in 1.30, has been removed.
+* WikiPage::prepareContentForEdit now doesn't accept an integer for $revision,
+  was deprecated in 1.25.
+* …
+
+=== Deprecations in 1.34 ===
+* The MWNamespace class is deprecated. Use NamespaceInfo.
+* ExtensionRegistry->load() is deprecated, as it breaks dependency checking.
+  Instead, use ->queue().
+* User::isBlocked() is deprecated since it does not tell you if the user is
+  blocked from editing a particular page. Use User::getBlock() or
+  PermissionManager::isBlockedFrom() or PermissionManager::userCan() instead.
+* User::isLocallyBlockedProxy and User::inDnsBlacklist are deprecated and moved
+  to the BlockManager as private helper methods.
+* User::isDnsBlacklisted is deprecated. Use BlockManager::isDnsBlacklisted
+  instead.
+* The Config argument to ChangesListSpecialPage::checkStructuredFilterUiEnabled
+  is deprecated. Pass only the User argument.
+* WatchedItem::getUser is deprecated. Use getUserIdentity.
+* Passing a Title as the first parameter to the getTimestampById method of
+  RevisionStore is deprecated. Omit it, passing only the remaining parameters.
+* Title::getPreviousRevisionId and Title::getNextRevisionId are deprecated. Use
+  RevisionLookup::getPreviousRevision and RevisionLookup::getNextRevision.
+* The Title parameter to RevisionLookup::getPreviousRevision and
+  RevisionLookup::getNextRevision is deprecated and should be omitted.
+* MWHttpRequest::factory is deprecated. Use HttpRequestFactory.
+* The Http class is deprecated. For the request, get, and post methods, use
+  HttpRequestFactory. For isValidURI, use MWHttpRequest::isValidURI.  For
+  getProxy, use (string)$wgHTTPProxy. For createMultiClient, construct a
+  MultiHttpClient directly.
+* Http::$httpEngine is deprecated and has no replacement. The default 'guzzle'
+  engine will eventually be made the only engine for HTTP requests.
+* RepoGroup::singleton(), RepoGroup::destroySingleton(),
+  RepoGroup::setSingleton(), wfFindFile(), and wfLocalFile() are all
+  deprecated. Use MediaWikiServices instead.
+* The getSubjectPage, getTalkPage, and getOtherPage of Title are deprecated.
+  Use NamespaceInfo's getSubjectPage, getTalkPage, and getAssociatedPage.
+* MWMessagePack class, no longer used, has been deprecated in 1.34.
+* The Block class is separated into Block (for blocks stored in the database),
+  and SystemBlock (for temporary blocks created by the system). SystemBlock
+  should be used when creating any temporary blocks.
+* Parser::$mConf is deprecated. It will be removed entirely in a later version.
+* Constructing Parser directly is deprecated. Obtain one from ParserFactory.
+
+=== Other changes in 1.34 ===
+* …
+
+== Compatibility ==
+MediaWiki 1.34 requires PHP 7.0.13 or later. Although HHVM 3.18.5 or later is
+supported, it is generally advised to use PHP 7.0.13 or later for long term
+support.
+
+MySQL/MariaDB is the recommended DBMS. PostgreSQL or SQLite can also be used,
+but support for them is somewhat less mature. There is experimental support for
+Oracle and Microsoft SQL Server.
+
+The supported versions are:
+
+* MySQL 5.5.8 or later
+* PostgreSQL 9.2 or later
+* SQLite 3.8.0 or later
+* Oracle 9.0.1 or later
+* Microsoft SQL Server 2005 (9.00.1399)
+
+== Online documentation ==
+Documentation for both end-users and site administrators is available on
+MediaWiki.org, and is covered under the GNU Free Documentation License (except
+for pages that explicitly state that their contents are in the public domain):
+
+       https://www.mediawiki.org/wiki/Special:MyLanguage/Documentation
+
+== Mailing list ==
+A mailing list is available for MediaWiki user support and discussion:
+
+       https://lists.wikimedia.org/mailman/listinfo/mediawiki-l
+
+A low-traffic announcements-only list is also available:
+
+       https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce
+
+It's highly recommended that you sign up for one of these lists if you're
+going to run a public MediaWiki, so you can be notified of security fixes.
+
+== IRC help ==
+There's usually someone online in #mediawiki on irc.freenode.net.
index 4172ed3..4c8f5a4 100644 (file)
@@ -27,6 +27,7 @@ $wgAutoloadLocalClasses = [
        'ApiAuthManagerHelper' => __DIR__ . '/includes/api/ApiAuthManagerHelper.php',
        'ApiBase' => __DIR__ . '/includes/api/ApiBase.php',
        'ApiBlock' => __DIR__ . '/includes/api/ApiBlock.php',
+       'ApiBlockInfoTrait' => __DIR__ . '/includes/api/ApiBlockInfoTrait.php',
        'ApiCSPReport' => __DIR__ . '/includes/api/ApiCSPReport.php',
        'ApiChangeAuthenticationData' => __DIR__ . '/includes/api/ApiChangeAuthenticationData.php',
        'ApiCheckToken' => __DIR__ . '/includes/api/ApiCheckToken.php',
@@ -39,7 +40,7 @@ $wgAutoloadLocalClasses = [
        'ApiEditPage' => __DIR__ . '/includes/api/ApiEditPage.php',
        'ApiEmailUser' => __DIR__ . '/includes/api/ApiEmailUser.php',
        'ApiErrorFormatter' => __DIR__ . '/includes/api/ApiErrorFormatter.php',
-       'ApiErrorFormatter_BackCompat' => __DIR__ . '/includes/api/ApiErrorFormatter.php',
+       'ApiErrorFormatter_BackCompat' => __DIR__ . '/includes/api/ApiErrorFormatter_BackCompat.php',
        'ApiExpandTemplates' => __DIR__ . '/includes/api/ApiExpandTemplates.php',
        'ApiFeedContributions' => __DIR__ . '/includes/api/ApiFeedContributions.php',
        'ApiFeedRecentChanges' => __DIR__ . '/includes/api/ApiFeedRecentChanges.php',
@@ -52,12 +53,12 @@ $wgAutoloadLocalClasses = [
        'ApiFormatPhp' => __DIR__ . '/includes/api/ApiFormatPhp.php',
        'ApiFormatRaw' => __DIR__ . '/includes/api/ApiFormatRaw.php',
        'ApiFormatXml' => __DIR__ . '/includes/api/ApiFormatXml.php',
-       'ApiFormatXmlRsd' => __DIR__ . '/includes/api/ApiRsd.php',
+       'ApiFormatXmlRsd' => __DIR__ . '/includes/api/ApiFormatXmlRsd.php',
        'ApiHelp' => __DIR__ . '/includes/api/ApiHelp.php',
        'ApiHelpParamValueMessage' => __DIR__ . '/includes/api/ApiHelpParamValueMessage.php',
        'ApiImageRotate' => __DIR__ . '/includes/api/ApiImageRotate.php',
        'ApiImport' => __DIR__ . '/includes/api/ApiImport.php',
-       'ApiImportReporter' => __DIR__ . '/includes/api/ApiImport.php',
+       'ApiImportReporter' => __DIR__ . '/includes/api/ApiImportReporter.php',
        'ApiLinkAccount' => __DIR__ . '/includes/api/ApiLinkAccount.php',
        'ApiLogin' => __DIR__ . '/includes/api/ApiLogin.php',
        'ApiLogout' => __DIR__ . '/includes/api/ApiLogout.php',
@@ -69,7 +70,7 @@ $wgAutoloadLocalClasses = [
        'ApiModuleManager' => __DIR__ . '/includes/api/ApiModuleManager.php',
        'ApiMove' => __DIR__ . '/includes/api/ApiMove.php',
        'ApiOpenSearch' => __DIR__ . '/includes/api/ApiOpenSearch.php',
-       'ApiOpenSearchFormatJson' => __DIR__ . '/includes/api/ApiOpenSearch.php',
+       'ApiOpenSearchFormatJson' => __DIR__ . '/includes/api/ApiOpenSearchFormatJson.php',
        'ApiOptions' => __DIR__ . '/includes/api/ApiOptions.php',
        'ApiPageSet' => __DIR__ . '/includes/api/ApiPageSet.php',
        'ApiParamInfo' => __DIR__ . '/includes/api/ApiParamInfo.php',
@@ -161,7 +162,7 @@ $wgAutoloadLocalClasses = [
        'ArrayUtils' => __DIR__ . '/includes/libs/ArrayUtils.php',
        'Article' => __DIR__ . '/includes/page/Article.php',
        'AssembleUploadChunksJob' => __DIR__ . '/includes/jobqueue/jobs/AssembleUploadChunksJob.php',
-       'AtomFeed' => __DIR__ . '/includes/Feed.php',
+       'AtomFeed' => __DIR__ . '/includes/changes/AtomFeed.php',
        'AtomicSectionUpdate' => __DIR__ . '/includes/deferred/AtomicSectionUpdate.php',
        'AttachLatest' => __DIR__ . '/maintenance/attachLatest.php',
        'AugmentPageProps' => __DIR__ . '/includes/search/AugmentPageProps.php',
@@ -253,7 +254,7 @@ $wgAutoloadLocalClasses = [
        'ChangesListSpecialPage' => __DIR__ . '/includes/specialpage/ChangesListSpecialPage.php',
        'ChangesListStringOptionsFilter' => __DIR__ . '/includes/changes/ChangesListStringOptionsFilter.php',
        'ChangesListStringOptionsFilterGroup' => __DIR__ . '/includes/changes/ChangesListStringOptionsFilterGroup.php',
-       'ChannelFeed' => __DIR__ . '/includes/Feed.php',
+       'ChannelFeed' => __DIR__ . '/includes/changes/ChannelFeed.php',
        'CheckBadRedirects' => __DIR__ . '/maintenance/checkBadRedirects.php',
        'CheckComposerLockUpToDate' => __DIR__ . '/maintenance/checkComposerLockUpToDate.php',
        'CheckExtensionsCLI' => __DIR__ . '/maintenance/language/checkLanguage.inc',
@@ -262,7 +263,7 @@ $wgAutoloadLocalClasses = [
        'CheckLess' => __DIR__ . '/maintenance/checkLess.php',
        'CheckStorage' => __DIR__ . '/maintenance/storage/checkStorage.php',
        'CheckUsernames' => __DIR__ . '/maintenance/checkUsernames.php',
-       'ClassCollector' => __DIR__ . '/includes/utils/AutoloadGenerator.php',
+       'ClassCollector' => __DIR__ . '/includes/utils/ClassCollector.php',
        'CleanupAncientTables' => __DIR__ . '/maintenance/cleanupAncientTables.php',
        'CleanupBlocks' => __DIR__ . '/maintenance/cleanupBlocks.php',
        'CleanupCaps' => __DIR__ . '/maintenance/cleanupCaps.php',
@@ -298,7 +299,7 @@ $wgAutoloadLocalClasses = [
        'ComposerVendorHtaccessCreator' => __DIR__ . '/includes/composer/ComposerVendorHtaccessCreator.php',
        'ComposerVersionNormalizer' => __DIR__ . '/includes/composer/ComposerVersionNormalizer.php',
        'CompressOld' => __DIR__ . '/maintenance/storage/compressOld.php',
-       'ConcatenatedGzipHistoryBlob' => __DIR__ . '/includes/HistoryBlob.php',
+       'ConcatenatedGzipHistoryBlob' => __DIR__ . '/includes/historyblob/ConcatenatedGzipHistoryBlob.php',
        'Config' => __DIR__ . '/includes/config/Config.php',
        'ConfigException' => __DIR__ . '/includes/config/ConfigException.php',
        'ConfigFactory' => __DIR__ . '/includes/config/ConfigFactory.php',
@@ -327,7 +328,6 @@ $wgAutoloadLocalClasses = [
        'CreditsAction' => __DIR__ . '/includes/actions/CreditsAction.php',
        'CrhConverter' => __DIR__ . '/languages/classes/LanguageCrh.php',
        'CryptHKDF' => __DIR__ . '/includes/libs/CryptHKDF.php',
-       'CryptRand' => __DIR__ . '/includes/libs/CryptRand.php',
        'CssContent' => __DIR__ . '/includes/content/CssContent.php',
        'CssContentHandler' => __DIR__ . '/includes/content/CssContentHandler.php',
        'CsvStatsOutput' => __DIR__ . '/maintenance/language/StatOutputs.php',
@@ -354,7 +354,7 @@ $wgAutoloadLocalClasses = [
        'DatabaseBase' => __DIR__ . '/includes/libs/rdbms/database/Database.php',
        'DatabaseInstaller' => __DIR__ . '/includes/installer/DatabaseInstaller.php',
        'DatabaseLag' => __DIR__ . '/maintenance/lag.php',
-       'DatabaseLogEntry' => __DIR__ . '/includes/logging/LogEntry.php',
+       'DatabaseLogEntry' => __DIR__ . '/includes/logging/DatabaseLogEntry.php',
        'DatabaseMssql' => __DIR__ . '/includes/libs/rdbms/database/DatabaseMssql.php',
        'DatabaseMysqlBase' => __DIR__ . '/includes/libs/rdbms/database/DatabaseMysqlBase.php',
        'DatabaseMysqli' => __DIR__ . '/includes/libs/rdbms/database/DatabaseMysqli.php',
@@ -364,6 +364,7 @@ $wgAutoloadLocalClasses = [
        'DatabaseUpdater' => __DIR__ . '/includes/installer/DatabaseUpdater.php',
        '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',
@@ -395,15 +396,15 @@ $wgAutoloadLocalClasses = [
        'DerivativeRequest' => __DIR__ . '/includes/DerivativeRequest.php',
        'DerivativeResourceLoaderContext' => __DIR__ . '/includes/resourceloader/DerivativeResourceLoaderContext.php',
        'DescribeFileOp' => __DIR__ . '/includes/libs/filebackend/fileop/DescribeFileOp.php',
-       'Diff' => __DIR__ . '/includes/diff/DairikiDiff.php',
+       'Diff' => __DIR__ . '/includes/diff/Diff.php',
        'DiffEngine' => __DIR__ . '/includes/diff/DiffEngine.php',
        'DiffFormatter' => __DIR__ . '/includes/diff/DiffFormatter.php',
-       'DiffHistoryBlob' => __DIR__ . '/includes/HistoryBlob.php',
-       'DiffOp' => __DIR__ . '/includes/diff/DairikiDiff.php',
-       'DiffOpAdd' => __DIR__ . '/includes/diff/DairikiDiff.php',
-       'DiffOpChange' => __DIR__ . '/includes/diff/DairikiDiff.php',
-       'DiffOpCopy' => __DIR__ . '/includes/diff/DairikiDiff.php',
-       'DiffOpDelete' => __DIR__ . '/includes/diff/DairikiDiff.php',
+       'DiffHistoryBlob' => __DIR__ . '/includes/historyblob/DiffHistoryBlob.php',
+       'DiffOp' => __DIR__ . '/includes/diff/DiffOp.php',
+       'DiffOpAdd' => __DIR__ . '/includes/diff/DiffOpAdd.php',
+       'DiffOpChange' => __DIR__ . '/includes/diff/DiffOpChange.php',
+       'DiffOpCopy' => __DIR__ . '/includes/diff/DiffOpCopy.php',
+       'DiffOpDelete' => __DIR__ . '/includes/diff/DiffOpDelete.php',
        'DifferenceEngine' => __DIR__ . '/includes/diff/DifferenceEngine.php',
        'DifferenceEngineSlotDiffRenderer' => __DIR__ . '/includes/diff/DifferenceEngineSlotDiffRenderer.php',
        'Digit2Html' => __DIR__ . '/maintenance/language/digit2html.php',
@@ -426,6 +427,7 @@ $wgAutoloadLocalClasses = [
        'DumpFilter' => __DIR__ . '/includes/export/DumpFilter.php',
        'DumpGZipOutput' => __DIR__ . '/includes/export/DumpGZipOutput.php',
        'DumpIterator' => __DIR__ . '/maintenance/dumpIterator.php',
+       'DumpLBZip2Output' => __DIR__ . '/includes/export/DumpLBZip2Output.php',
        'DumpLatestFilter' => __DIR__ . '/includes/export/DumpLatestFilter.php',
        'DumpLinks' => __DIR__ . '/maintenance/dumpLinks.php',
        'DumpMessages' => __DIR__ . '/maintenance/language/dumpMessages.php',
@@ -486,10 +488,10 @@ $wgAutoloadLocalClasses = [
        'ExternalUserNames' => __DIR__ . '/includes/user/ExternalUserNames.php',
        'FSFile' => __DIR__ . '/includes/libs/filebackend/fsfile/FSFile.php',
        'FSFileBackend' => __DIR__ . '/includes/libs/filebackend/FSFileBackend.php',
-       'FSFileBackendDirList' => __DIR__ . '/includes/libs/filebackend/FSFileBackend.php',
-       'FSFileBackendFileList' => __DIR__ . '/includes/libs/filebackend/FSFileBackend.php',
-       'FSFileBackendList' => __DIR__ . '/includes/libs/filebackend/FSFileBackend.php',
-       'FSFileOpHandle' => __DIR__ . '/includes/libs/filebackend/FSFileBackend.php',
+       'FSFileBackendDirList' => __DIR__ . '/includes/libs/filebackend/fileiteration/FSFileBackendDirList.php',
+       'FSFileBackendFileList' => __DIR__ . '/includes/libs/filebackend/fileiteration/FSFileBackendFileList.php',
+       'FSFileBackendList' => __DIR__ . '/includes/libs/filebackend/fileiteration/FSFileBackendList.php',
+       'FSFileOpHandle' => __DIR__ . '/includes/libs/filebackend/fileophandle/FSFileOpHandle.php',
        'FSLockManager' => __DIR__ . '/includes/libs/lockmanager/FSLockManager.php',
        'FakeConverter' => __DIR__ . '/languages/FakeConverter.php',
        'FakeMaintenance' => __DIR__ . '/maintenance/Maintenance.php',
@@ -497,7 +499,7 @@ $wgAutoloadLocalClasses = [
        'FatalError' => __DIR__ . '/includes/exception/FatalError.php',
        'FauxRequest' => __DIR__ . '/includes/FauxRequest.php',
        'FauxResponse' => __DIR__ . '/includes/FauxResponse.php',
-       'FeedItem' => __DIR__ . '/includes/Feed.php',
+       'FeedItem' => __DIR__ . '/includes/changes/FeedItem.php',
        'FeedUtils' => __DIR__ . '/includes/FeedUtils.php',
        'FetchText' => __DIR__ . '/maintenance/fetchText.php',
        'FewestrevisionsPage' => __DIR__ . '/includes/specials/SpecialFewestrevisions.php',
@@ -506,14 +508,14 @@ $wgAutoloadLocalClasses = [
        'FileAwareNodeVisitor' => __DIR__ . '/maintenance/findDeprecated.php',
        'FileBackend' => __DIR__ . '/includes/libs/filebackend/FileBackend.php',
        'FileBackendDBRepoWrapper' => __DIR__ . '/includes/filerepo/FileBackendDBRepoWrapper.php',
-       'FileBackendError' => __DIR__ . '/includes/libs/filebackend/FileBackendError.php',
+       'FileBackendError' => __DIR__ . '/includes/libs/filebackend/exception/FileBackendError.php',
        'FileBackendGroup' => __DIR__ . '/includes/filebackend/FileBackendGroup.php',
        'FileBackendMultiWrite' => __DIR__ . '/includes/libs/filebackend/FileBackendMultiWrite.php',
        'FileBackendStore' => __DIR__ . '/includes/libs/filebackend/FileBackendStore.php',
-       'FileBackendStoreOpHandle' => __DIR__ . '/includes/libs/filebackend/FileBackendStore.php',
-       'FileBackendStoreShardDirIterator' => __DIR__ . '/includes/libs/filebackend/FileBackendStore.php',
-       'FileBackendStoreShardFileIterator' => __DIR__ . '/includes/libs/filebackend/FileBackendStore.php',
-       'FileBackendStoreShardListIterator' => __DIR__ . '/includes/libs/filebackend/FileBackendStore.php',
+       'FileBackendStoreOpHandle' => __DIR__ . '/includes/libs/filebackend/fileophandle/FileBackendStoreOpHandle.php',
+       'FileBackendStoreShardDirIterator' => __DIR__ . '/includes/libs/filebackend/fileiteration/FileBackendStoreShardDirIterator.php',
+       'FileBackendStoreShardFileIterator' => __DIR__ . '/includes/libs/filebackend/fileiteration/FileBackendStoreShardFileIterator.php',
+       'FileBackendStoreShardListIterator' => __DIR__ . '/includes/libs/filebackend/fileiteration/FileBackendStoreShardListIterator.php',
        'FileBasedSiteLookup' => __DIR__ . '/includes/site/FileBasedSiteLookup.php',
        'FileCacheBase' => __DIR__ . '/includes/cache/FileCacheBase.php',
        'FileContentHandler' => __DIR__ . '/includes/content/FileContentHandler.php',
@@ -526,7 +528,6 @@ $wgAutoloadLocalClasses = [
        'FileOpBatch' => __DIR__ . '/includes/libs/filebackend/FileOpBatch.php',
        'FileOpPerfTest' => __DIR__ . '/maintenance/fileOpPerfTest.php',
        'FileRepo' => __DIR__ . '/includes/filerepo/FileRepo.php',
-       'FileRepoStatus' => __DIR__ . '/includes/filerepo/FileRepoStatus.php',
        'FindDeprecated' => __DIR__ . '/maintenance/findDeprecated.php',
        'FindHooks' => __DIR__ . '/maintenance/findHooks.php',
        'FindMissingFiles' => __DIR__ . '/maintenance/findMissingFiles.php',
@@ -562,8 +563,12 @@ $wgAutoloadLocalClasses = [
        'GenerateJsonI18n' => __DIR__ . '/maintenance/generateJsonI18n.php',
        'GenerateNormalizerDataAr' => __DIR__ . '/maintenance/language/generateNormalizerDataAr.php',
        'GenerateNormalizerDataMl' => __DIR__ . '/maintenance/language/generateNormalizerDataMl.php',
+       'GeneratePhpCharToUpperMappings' => __DIR__ . '/maintenance/mediawiki.Title/generatePhpCharToUpperMappings.php',
        'GenerateSitemap' => __DIR__ . '/maintenance/generateSitemap.php',
+       'GenerateUcfirstOverrides' => __DIR__ . '/maintenance/language/generateUcfirstOverrides.php',
+       'GenerateUpperCharTable' => __DIR__ . '/maintenance/language/generateUpperCharTable.php',
        'GenericArrayObject' => __DIR__ . '/includes/libs/GenericArrayObject.php',
+       'GenericParameterJob' => __DIR__ . '/includes/jobqueue/GenericParameterJob.php',
        'GetConfiguration' => __DIR__ . '/maintenance/getConfiguration.php',
        'GetLagTimes' => __DIR__ . '/maintenance/getLagTimes.php',
        'GetReplicaServer' => __DIR__ . '/maintenance/getReplicaServer.php',
@@ -587,11 +592,11 @@ $wgAutoloadLocalClasses = [
        'HTMLFileCache' => __DIR__ . '/includes/cache/HTMLFileCache.php',
        'HTMLFloatField' => __DIR__ . '/includes/htmlform/fields/HTMLFloatField.php',
        'HTMLForm' => __DIR__ . '/includes/htmlform/HTMLForm.php',
-       'HTMLFormActionFieldLayout' => __DIR__ . '/includes/htmlform/HTMLFormElement.php',
+       'HTMLFormActionFieldLayout' => __DIR__ . '/includes/htmlform/HTMLFormActionFieldLayout.php',
        'HTMLFormElement' => __DIR__ . '/includes/htmlform/HTMLFormElement.php',
        'HTMLFormField' => __DIR__ . '/includes/htmlform/HTMLFormField.php',
        'HTMLFormFieldCloner' => __DIR__ . '/includes/htmlform/fields/HTMLFormFieldCloner.php',
-       'HTMLFormFieldLayout' => __DIR__ . '/includes/htmlform/HTMLFormElement.php',
+       'HTMLFormFieldLayout' => __DIR__ . '/includes/htmlform/HTMLFormFieldLayout.php',
        'HTMLFormFieldRequiredOptionsException' => __DIR__ . '/includes/htmlform/HTMLFormFieldRequiredOptionsException.php',
        'HTMLFormFieldWithButton' => __DIR__ . '/includes/htmlform/fields/HTMLFormFieldWithButton.php',
        'HTMLHiddenField' => __DIR__ . '/includes/htmlform/fields/HTMLHiddenField.php',
@@ -620,16 +625,15 @@ $wgAutoloadLocalClasses = [
        'HTMLUserTextField' => __DIR__ . '/includes/htmlform/fields/HTMLUserTextField.php',
        'HTMLUsersMultiselectField' => __DIR__ . '/includes/htmlform/fields/HTMLUsersMultiselectField.php',
        'HTTPFileStreamer' => __DIR__ . '/includes/libs/filebackend/HTTPFileStreamer.php',
-       'HWLDFWordAccumulator' => __DIR__ . '/includes/diff/DairikiDiff.php',
        'HashBagOStuff' => __DIR__ . '/includes/libs/objectcache/HashBagOStuff.php',
        'HashConfig' => __DIR__ . '/includes/config/HashConfig.php',
        'HashRing' => __DIR__ . '/includes/libs/HashRing.php',
        'HashSiteStore' => __DIR__ . '/includes/site/HashSiteStore.php',
        'HashtableReplacer' => __DIR__ . '/includes/libs/replacers/HashtableReplacer.php',
        'HistoryAction' => __DIR__ . '/includes/actions/HistoryAction.php',
-       'HistoryBlob' => __DIR__ . '/includes/HistoryBlob.php',
-       'HistoryBlobCurStub' => __DIR__ . '/includes/HistoryBlob.php',
-       'HistoryBlobStub' => __DIR__ . '/includes/HistoryBlob.php',
+       'HistoryBlob' => __DIR__ . '/includes/historyblob/HistoryBlob.php',
+       'HistoryBlobCurStub' => __DIR__ . '/includes/historyblob/HistoryBlobCurStub.php',
+       'HistoryBlobStub' => __DIR__ . '/includes/historyblob/HistoryBlobStub.php',
        'HistoryPager' => __DIR__ . '/includes/actions/pagers/HistoryPager.php',
        'Hooks' => __DIR__ . '/includes/Hooks.php',
        'Html' => __DIR__ . '/includes/Html.php',
@@ -704,9 +708,6 @@ $wgAutoloadLocalClasses = [
        'JavaScriptMinifier' => __DIR__ . '/includes/libs/JavaScriptMinifier.php',
        'Job' => __DIR__ . '/includes/jobqueue/Job.php',
        'JobQueue' => __DIR__ . '/includes/jobqueue/JobQueue.php',
-       'JobQueueAggregator' => __DIR__ . '/includes/jobqueue/aggregator/JobQueueAggregator.php',
-       'JobQueueAggregatorNull' => __DIR__ . '/includes/jobqueue/aggregator/JobQueueAggregatorNull.php',
-       'JobQueueAggregatorRedis' => __DIR__ . '/includes/jobqueue/aggregator/JobQueueAggregatorRedis.php',
        'JobQueueConnectionError' => __DIR__ . '/includes/jobqueue/exception/JobQueueConnectionError.php',
        'JobQueueDB' => __DIR__ . '/includes/jobqueue/JobQueueDB.php',
        'JobQueueEnqueueUpdate' => __DIR__ . '/includes/deferred/JobQueueEnqueueUpdate.php',
@@ -773,7 +774,7 @@ $wgAutoloadLocalClasses = [
        'LanguageZh_hans' => __DIR__ . '/languages/classes/LanguageZh_hans.php',
        'Languages' => __DIR__ . '/maintenance/language/languages.inc',
        'LayeredParameterizedPassword' => __DIR__ . '/includes/password/LayeredParameterizedPassword.php',
-       'LegacyLogFormatter' => __DIR__ . '/includes/logging/LogFormatter.php',
+       'LegacyLogFormatter' => __DIR__ . '/includes/logging/LegacyLogFormatter.php',
        'License' => __DIR__ . '/includes/specials/helpers/License.php',
        'Licenses' => __DIR__ . '/includes/specials/formfields/Licenses.php',
        'LinkBatch' => __DIR__ . '/includes/cache/LinkBatch.php',
@@ -791,10 +792,10 @@ $wgAutoloadLocalClasses = [
        'LoadBalancer' => __DIR__ . '/includes/libs/rdbms/loadbalancer/LoadBalancer.php',
        'LoadBalancerSingle' => __DIR__ . '/includes/libs/rdbms/loadbalancer/LoadBalancerSingle.php',
        'LocalFile' => __DIR__ . '/includes/filerepo/file/LocalFile.php',
-       'LocalFileDeleteBatch' => __DIR__ . '/includes/filerepo/file/LocalFile.php',
-       'LocalFileLockError' => __DIR__ . '/includes/filerepo/file/LocalFile.php',
-       'LocalFileMoveBatch' => __DIR__ . '/includes/filerepo/file/LocalFile.php',
-       'LocalFileRestoreBatch' => __DIR__ . '/includes/filerepo/file/LocalFile.php',
+       'LocalFileDeleteBatch' => __DIR__ . '/includes/filerepo/file/LocalFileDeleteBatch.php',
+       'LocalFileLockError' => __DIR__ . '/includes/filerepo/file/LocalFileLockError.php',
+       'LocalFileMoveBatch' => __DIR__ . '/includes/filerepo/file/LocalFileMoveBatch.php',
+       'LocalFileRestoreBatch' => __DIR__ . '/includes/filerepo/file/LocalFileRestoreBatch.php',
        'LocalIdLookup' => __DIR__ . '/includes/user/LocalIdLookup.php',
        'LocalRepo' => __DIR__ . '/includes/filerepo/LocalRepo.php',
        'LocalSettingsGenerator' => __DIR__ . '/includes/installer/LocalSettingsGenerator.php',
@@ -804,7 +805,7 @@ $wgAutoloadLocalClasses = [
        'LockManager' => __DIR__ . '/includes/libs/lockmanager/LockManager.php',
        'LockManagerGroup' => __DIR__ . '/includes/filebackend/lockmanager/LockManagerGroup.php',
        'LogEntry' => __DIR__ . '/includes/logging/LogEntry.php',
-       'LogEntryBase' => __DIR__ . '/includes/logging/LogEntry.php',
+       'LogEntryBase' => __DIR__ . '/includes/logging/LogEntryBase.php',
        'LogEventsList' => __DIR__ . '/includes/logging/LogEventsList.php',
        'LogFormatter' => __DIR__ . '/includes/logging/LogFormatter.php',
        'LogPage' => __DIR__ . '/includes/logging/LogPage.php',
@@ -850,9 +851,9 @@ $wgAutoloadLocalClasses = [
        'Maintenance' => __DIR__ . '/maintenance/Maintenance.php',
        'MakeTestEdits' => __DIR__ . '/maintenance/makeTestEdits.php',
        'MalformedTitleException' => __DIR__ . '/includes/title/MalformedTitleException.php',
-       'ManageForeignResources' => __DIR__ . '/maintenance/resources/manageForeignResources.php',
+       'ManageForeignResources' => __DIR__ . '/maintenance/manageForeignResources.php',
        'ManageJobs' => __DIR__ . '/maintenance/manageJobs.php',
-       'ManualLogEntry' => __DIR__ . '/includes/logging/LogEntry.php',
+       'ManualLogEntry' => __DIR__ . '/includes/logging/ManualLogEntry.php',
        'MapCacheLRU' => __DIR__ . '/includes/libs/MapCacheLRU.php',
        'MappedIterator' => __DIR__ . '/includes/libs/MappedIterator.php',
        'MarkpatrolledAction' => __DIR__ . '/includes/actions/MarkpatrolledAction.php',
@@ -862,7 +863,7 @@ $wgAutoloadLocalClasses = [
        'MediaHandler' => __DIR__ . '/includes/media/MediaHandler.php',
        'MediaHandlerFactory' => __DIR__ . '/includes/media/MediaHandlerFactory.php',
        'MediaStatisticsPage' => __DIR__ . '/includes/specials/SpecialMediaStatistics.php',
-       'MediaTransformError' => __DIR__ . '/includes/media/MediaTransformOutput.php',
+       'MediaTransformError' => __DIR__ . '/includes/media/MediaTransformError.php',
        'MediaTransformInvalidParametersException' => __DIR__ . '/includes/media/MediaTransformInvalidParametersException.php',
        'MediaTransformOutput' => __DIR__ . '/includes/media/MediaTransformOutput.php',
        'MediaWiki' => __DIR__ . '/includes/MediaWiki.php',
@@ -872,6 +873,7 @@ $wgAutoloadLocalClasses = [
        'MediaWikiVersionFetcher' => __DIR__ . '/includes/MediaWikiVersionFetcher.php',
        'MediaWiki\\ChangeTags\\Taggable' => __DIR__ . '/includes/changetags/Taggable.php',
        'MediaWiki\\Config\\ConfigRepository' => __DIR__ . '/includes/config/ConfigRepository.php',
+       'MediaWiki\\Config\\ServiceOptions' => __DIR__ . '/includes/config/ServiceOptions.php',
        'MediaWiki\\DB\\PatchFileLocation' => __DIR__ . '/includes/db/PatchFileLocation.php',
        'MediaWiki\\Diff\\ComplexityException' => __DIR__ . '/includes/diff/ComplexityException.php',
        'MediaWiki\\Diff\\WordAccumulator' => __DIR__ . '/includes/diff/WordAccumulator.php',
@@ -899,6 +901,7 @@ $wgAutoloadLocalClasses = [
        'MediaWiki\\Logger\\Monolog\\LegacyHandler' => __DIR__ . '/includes/debug/logger/monolog/LegacyHandler.php',
        'MediaWiki\\Logger\\Monolog\\LineFormatter' => __DIR__ . '/includes/debug/logger/monolog/LineFormatter.php',
        'MediaWiki\\Logger\\Monolog\\LogstashFormatter' => __DIR__ . '/includes/debug/logger/monolog/LogstashFormatter.php',
+       'MediaWiki\\Logger\\Monolog\\MwlogHandler' => __DIR__ . '/includes/debug/logger/monolog/MwlogHandler.php',
        'MediaWiki\\Logger\\Monolog\\SyslogHandler' => __DIR__ . '/includes/debug/logger/monolog/SyslogHandler.php',
        'MediaWiki\\Logger\\Monolog\\WikiProcessor' => __DIR__ . '/includes/debug/logger/monolog/WikiProcessor.php',
        'MediaWiki\\Logger\\NullSpi' => __DIR__ . '/includes/debug/logger/NullSpi.php',
@@ -973,7 +976,7 @@ $wgAutoloadLocalClasses = [
        'MergeMessageFileList' => __DIR__ . '/maintenance/mergeMessageFileList.php',
        'MergeableUpdate' => __DIR__ . '/includes/deferred/MergeableUpdate.php',
        'Message' => __DIR__ . '/includes/Message.php',
-       'MessageBlobStore' => __DIR__ . '/includes/cache/MessageBlobStore.php',
+       'MessageBlobStore' => __DIR__ . '/includes/resourceloader/MessageBlobStore.php',
        'MessageCache' => __DIR__ . '/includes/cache/MessageCache.php',
        'MessageCacheUpdate' => __DIR__ . '/includes/deferred/MessageCacheUpdate.php',
        'MessageContent' => __DIR__ . '/includes/content/MessageContent.php',
@@ -1016,6 +1019,7 @@ $wgAutoloadLocalClasses = [
        'NamespaceAwareForeignTitleFactory' => __DIR__ . '/includes/title/NamespaceAwareForeignTitleFactory.php',
        'NamespaceDupes' => __DIR__ . '/maintenance/namespaceDupes.php',
        'NamespaceImportTitleFactory' => __DIR__ . '/includes/title/NamespaceImportTitleFactory.php',
+       'NamespaceInfo' => __DIR__ . '/includes/title/NamespaceInfo.php',
        'NewFilesPager' => __DIR__ . '/includes/specials/pagers/NewFilesPager.php',
        'NewPagesPager' => __DIR__ . '/includes/specials/pagers/NewPagesPager.php',
        'NewUsersLogFormatter' => __DIR__ . '/includes/logging/NewUsersLogFormatter.php',
@@ -1036,7 +1040,6 @@ $wgAutoloadLocalClasses = [
        'ORAField' => __DIR__ . '/includes/db/ORAField.php',
        'ORAResult' => __DIR__ . '/includes/db/ORAResult.php',
        'ObjectCache' => __DIR__ . '/includes/objectcache/ObjectCache.php',
-       'ObjectFactory' => __DIR__ . '/includes/compat/ObjectFactory.php',
        'OldChangesList' => __DIR__ . '/includes/changes/OldChangesList.php',
        'OldLocalFile' => __DIR__ . '/includes/filerepo/file/OldLocalFile.php',
        'OldRevisionImporter' => __DIR__ . '/includes/import/OldRevisionImporter.php',
@@ -1049,29 +1052,29 @@ $wgAutoloadLocalClasses = [
        'PHPVersionCheck' => __DIR__ . '/includes/PHPVersionCheck.php',
        'PNGHandler' => __DIR__ . '/includes/media/PNGHandler.php',
        'PNGMetadataExtractor' => __DIR__ . '/includes/media/PNGMetadataExtractor.php',
-       'PPCustomFrame_DOM' => __DIR__ . '/includes/parser/Preprocessor_DOM.php',
-       'PPCustomFrame_Hash' => __DIR__ . '/includes/parser/Preprocessor_Hash.php',
-       'PPDPart' => __DIR__ . '/includes/parser/Preprocessor_DOM.php',
-       'PPDPart_Hash' => __DIR__ . '/includes/parser/Preprocessor_Hash.php',
-       'PPDStack' => __DIR__ . '/includes/parser/Preprocessor_DOM.php',
-       'PPDStackElement' => __DIR__ . '/includes/parser/Preprocessor_DOM.php',
-       'PPDStackElement_Hash' => __DIR__ . '/includes/parser/Preprocessor_Hash.php',
-       'PPDStack_Hash' => __DIR__ . '/includes/parser/Preprocessor_Hash.php',
-       'PPFrame' => __DIR__ . '/includes/parser/Preprocessor.php',
-       'PPFrame_DOM' => __DIR__ . '/includes/parser/Preprocessor_DOM.php',
-       'PPFrame_Hash' => __DIR__ . '/includes/parser/Preprocessor_Hash.php',
+       'PPCustomFrame_DOM' => __DIR__ . '/includes/parser/PPCustomFrame_DOM.php',
+       'PPCustomFrame_Hash' => __DIR__ . '/includes/parser/PPCustomFrame_Hash.php',
+       'PPDPart' => __DIR__ . '/includes/parser/PPDPart.php',
+       'PPDPart_Hash' => __DIR__ . '/includes/parser/PPDPart_Hash.php',
+       'PPDStack' => __DIR__ . '/includes/parser/PPDStack.php',
+       'PPDStackElement' => __DIR__ . '/includes/parser/PPDStackElement.php',
+       'PPDStackElement_Hash' => __DIR__ . '/includes/parser/PPDStackElement_Hash.php',
+       'PPDStack_Hash' => __DIR__ . '/includes/parser/PPDStack_Hash.php',
+       'PPFrame' => __DIR__ . '/includes/parser/PPFrame.php',
+       'PPFrame_DOM' => __DIR__ . '/includes/parser/PPFrame_DOM.php',
+       'PPFrame_Hash' => __DIR__ . '/includes/parser/PPFrame_Hash.php',
        'PPFuzzTest' => __DIR__ . '/maintenance/preprocessorFuzzTest.php',
        'PPFuzzTester' => __DIR__ . '/maintenance/preprocessorFuzzTest.php',
        'PPFuzzUser' => __DIR__ . '/maintenance/preprocessorFuzzTest.php',
-       'PPNode' => __DIR__ . '/includes/parser/Preprocessor.php',
-       'PPNode_DOM' => __DIR__ . '/includes/parser/Preprocessor_DOM.php',
-       'PPNode_Hash_Array' => __DIR__ . '/includes/parser/Preprocessor_Hash.php',
-       'PPNode_Hash_Attr' => __DIR__ . '/includes/parser/Preprocessor_Hash.php',
-       'PPNode_Hash_Text' => __DIR__ . '/includes/parser/Preprocessor_Hash.php',
-       'PPNode_Hash_Tree' => __DIR__ . '/includes/parser/Preprocessor_Hash.php',
-       'PPTemplateFrame_DOM' => __DIR__ . '/includes/parser/Preprocessor_DOM.php',
-       'PPTemplateFrame_Hash' => __DIR__ . '/includes/parser/Preprocessor_Hash.php',
-       'PackedHoverImageGallery' => __DIR__ . '/includes/gallery/PackedOverlayImageGallery.php',
+       'PPNode' => __DIR__ . '/includes/parser/PPNode.php',
+       'PPNode_DOM' => __DIR__ . '/includes/parser/PPNode_DOM.php',
+       'PPNode_Hash_Array' => __DIR__ . '/includes/parser/PPNode_Hash_Array.php',
+       'PPNode_Hash_Attr' => __DIR__ . '/includes/parser/PPNode_Hash_Attr.php',
+       'PPNode_Hash_Text' => __DIR__ . '/includes/parser/PPNode_Hash_Text.php',
+       'PPNode_Hash_Tree' => __DIR__ . '/includes/parser/PPNode_Hash_Tree.php',
+       'PPTemplateFrame_DOM' => __DIR__ . '/includes/parser/PPTemplateFrame_DOM.php',
+       'PPTemplateFrame_Hash' => __DIR__ . '/includes/parser/PPTemplateFrame_Hash.php',
+       'PackedHoverImageGallery' => __DIR__ . '/includes/gallery/PackedHoverImageGallery.php',
        'PackedImageGallery' => __DIR__ . '/includes/gallery/PackedImageGallery.php',
        'PackedOverlayImageGallery' => __DIR__ . '/includes/gallery/PackedOverlayImageGallery.php',
        'Page' => __DIR__ . '/includes/page/Page.php',
@@ -1104,13 +1107,13 @@ $wgAutoloadLocalClasses = [
        'PerRowAugmentor' => __DIR__ . '/includes/search/PerRowAugmentor.php',
        'PermissionsError' => __DIR__ . '/includes/exception/PermissionsError.php',
        'PhpHttpRequest' => __DIR__ . '/includes/http/PhpHttpRequest.php',
-       'PhpXmlBugTester' => __DIR__ . '/includes/installer/PhpBugTests.php',
+       'PhpXmlBugTester' => __DIR__ . '/includes/installer/PhpXmlBugTester.php',
        'Pingback' => __DIR__ . '/includes/Pingback.php',
        'PoolCounter' => __DIR__ . '/includes/poolcounter/PoolCounter.php',
+       'PoolCounterNull' => __DIR__ . '/includes/poolcounter/PoolCounterNull.php',
        'PoolCounterRedis' => __DIR__ . '/includes/poolcounter/PoolCounterRedis.php',
        'PoolCounterWork' => __DIR__ . '/includes/poolcounter/PoolCounterWork.php',
        'PoolCounterWorkViaCallback' => __DIR__ . '/includes/poolcounter/PoolCounterWorkViaCallback.php',
-       'PoolCounter_Stub' => __DIR__ . '/includes/poolcounter/PoolCounter.php',
        'PoolWorkArticleView' => __DIR__ . '/includes/poolcounter/PoolWorkArticleView.php',
        'PopulateArchiveRevId' => __DIR__ . '/maintenance/populateArchiveRevId.php',
        'PopulateBacklinkNamespace' => __DIR__ . '/maintenance/populateBacklinkNamespace.php',
@@ -1133,11 +1136,8 @@ $wgAutoloadLocalClasses = [
        'PostgreSqlLockManager' => __DIR__ . '/includes/libs/lockmanager/PostgreSqlLockManager.php',
        'PostgresInstaller' => __DIR__ . '/includes/installer/PostgresInstaller.php',
        'PostgresUpdater' => __DIR__ . '/includes/installer/PostgresUpdater.php',
-       'Preferences' => __DIR__ . '/includes/Preferences.php',
-       'PreferencesForm' => __DIR__ . '/includes/specials/forms/PreferencesFormLegacy.php',
-       'PreferencesFormLegacy' => __DIR__ . '/includes/specials/forms/PreferencesFormLegacy.php',
        'PreferencesFormOOUI' => __DIR__ . '/includes/specials/forms/PreferencesFormOOUI.php',
-       'PrefixSearch' => __DIR__ . '/includes/PrefixSearch.php',
+       'PrefixSearch' => __DIR__ . '/includes/search/PrefixSearch.php',
        'PrefixingStatsdDataFactoryProxy' => __DIR__ . '/includes/libs/stats/PrefixingStatsdDataFactoryProxy.php',
        'PreprocessDump' => __DIR__ . '/maintenance/preprocessDump.php',
        'Preprocessor' => __DIR__ . '/includes/parser/Preprocessor.php',
@@ -1179,12 +1179,12 @@ $wgAutoloadLocalClasses = [
        'QuorumLockManager' => __DIR__ . '/includes/libs/lockmanager/QuorumLockManager.php',
        'RCCacheEntry' => __DIR__ . '/includes/changes/RCCacheEntry.php',
        'RCCacheEntryFactory' => __DIR__ . '/includes/changes/RCCacheEntryFactory.php',
-       'RCDatabaseLogEntry' => __DIR__ . '/includes/logging/LogEntry.php',
+       'RCDatabaseLogEntry' => __DIR__ . '/includes/logging/RCDatabaseLogEntry.php',
        'RCFeed' => __DIR__ . '/includes/rcfeed/RCFeed.php',
        'RCFeedEngine' => __DIR__ . '/includes/rcfeed/RCFeedEngine.php',
        'RCFeedFormatter' => __DIR__ . '/includes/rcfeed/RCFeedFormatter.php',
        'RESTBagOStuff' => __DIR__ . '/includes/libs/objectcache/RESTBagOStuff.php',
-       'RSSFeed' => __DIR__ . '/includes/Feed.php',
+       'RSSFeed' => __DIR__ . '/includes/changes/RSSFeed.php',
        'RandomPage' => __DIR__ . '/includes/specials/SpecialRandompage.php',
        'RangeChronologicalPager' => __DIR__ . '/includes/pager/RangeChronologicalPager.php',
        'RangeDifference' => __DIR__ . '/includes/diff/RangeDifference.php',
@@ -1278,10 +1278,10 @@ $wgAutoloadLocalClasses = [
        'Revision' => __DIR__ . '/includes/Revision.php',
        'RevisionDeleteUser' => __DIR__ . '/includes/revisiondelete/RevisionDeleteUser.php',
        'RevisionDeleter' => __DIR__ . '/includes/revisiondelete/RevisionDeleter.php',
-       'RevisionItem' => __DIR__ . '/includes/RevisionList.php',
-       'RevisionItemBase' => __DIR__ . '/includes/RevisionList.php',
-       'RevisionList' => __DIR__ . '/includes/RevisionList.php',
-       'RevisionListBase' => __DIR__ . '/includes/RevisionList.php',
+       'RevisionItem' => __DIR__ . '/includes/revisionlist/RevisionItem.php',
+       'RevisionItemBase' => __DIR__ . '/includes/revisionlist/RevisionItemBase.php',
+       'RevisionList' => __DIR__ . '/includes/revisionlist/RevisionList.php',
+       'RevisionListBase' => __DIR__ . '/includes/revisionlist/RevisionListBase.php',
        'RiffExtractor' => __DIR__ . '/includes/libs/RiffExtractor.php',
        'RightsLogFormatter' => __DIR__ . '/includes/logging/RightsLogFormatter.php',
        'RollbackAction' => __DIR__ . '/includes/actions/RollbackAction.php',
@@ -1289,8 +1289,9 @@ $wgAutoloadLocalClasses = [
        'RowUpdateGenerator' => __DIR__ . '/includes/utils/RowUpdateGenerator.php',
        'RunBatchedQuery' => __DIR__ . '/maintenance/runBatchedQuery.php',
        'RunJobs' => __DIR__ . '/maintenance/runJobs.php',
+       'RunnableJob' => __DIR__ . '/includes/jobqueue/RunnableJob.php',
        'SVGMetadataExtractor' => __DIR__ . '/includes/media/SVGMetadataExtractor.php',
-       'SVGReader' => __DIR__ . '/includes/media/SVGMetadataExtractor.php',
+       'SVGReader' => __DIR__ . '/includes/media/SVGReader.php',
        'SamplingStatsdClient' => __DIR__ . '/includes/libs/stats/SamplingStatsdClient.php',
        'Sanitizer' => __DIR__ . '/includes/parser/Sanitizer.php',
        'ScopedLock' => __DIR__ . '/includes/libs/lockmanager/ScopedLock.php',
@@ -1299,7 +1300,7 @@ $wgAutoloadLocalClasses = [
        'SearchDump' => __DIR__ . '/maintenance/dumpIterator.php',
        'SearchEngine' => __DIR__ . '/includes/search/SearchEngine.php',
        'SearchEngineConfig' => __DIR__ . '/includes/search/SearchEngineConfig.php',
-       'SearchEngineDummy' => __DIR__ . '/includes/search/SearchEngine.php',
+       'SearchEngineDummy' => __DIR__ . '/includes/search/SearchEngineDummy.php',
        'SearchEngineFactory' => __DIR__ . '/includes/search/SearchEngineFactory.php',
        'SearchExactMatchRescorer' => __DIR__ . '/includes/search/SearchExactMatchRescorer.php',
        'SearchHighlighter' => __DIR__ . '/includes/search/SearchHighlighter.php',
@@ -1317,9 +1318,9 @@ $wgAutoloadLocalClasses = [
        'SearchSuggestion' => __DIR__ . '/includes/search/SearchSuggestion.php',
        'SearchSuggestionSet' => __DIR__ . '/includes/search/SearchSuggestionSet.php',
        'SearchUpdate' => __DIR__ . '/includes/deferred/SearchUpdate.php',
-       'SectionProfileCallback' => __DIR__ . '/includes/profiler/SectionProfiler.php',
+       'SectionProfileCallback' => __DIR__ . '/includes/profiler/SectionProfileCallback.php',
        'SectionProfiler' => __DIR__ . '/includes/profiler/SectionProfiler.php',
-       'SevenZipStream' => __DIR__ . '/maintenance/7zip.inc',
+       'SevenZipStream' => __DIR__ . '/maintenance/includes/SevenZipStream.php',
        'ShiConverter' => __DIR__ . '/languages/classes/LanguageShi.php',
        'ShortPagesPage' => __DIR__ . '/includes/specials/SpecialShortpages.php',
        'ShowJobs' => __DIR__ . '/maintenance/showJobs.php',
@@ -1344,7 +1345,7 @@ $wgAutoloadLocalClasses = [
        'SkinTemplate' => __DIR__ . '/includes/skins/SkinTemplate.php',
        'SlideshowImageGallery' => __DIR__ . '/includes/gallery/SlideshowImageGallery.php',
        'SlotDiffRenderer' => __DIR__ . '/includes/diff/SlotDiffRenderer.php',
-       'SpecialActiveUsers' => __DIR__ . '/includes/specials/SpecialActiveusers.php',
+       'SpecialActiveUsers' => __DIR__ . '/includes/specials/SpecialActiveUsers.php',
        'SpecialAllMessages' => __DIR__ . '/includes/specials/SpecialAllMessages.php',
        'SpecialAllMyUploads' => __DIR__ . '/includes/specials/redirects/SpecialAllMyUploads.php',
        'SpecialAllPages' => __DIR__ . '/includes/specials/SpecialAllPages.php',
@@ -1354,7 +1355,7 @@ $wgAutoloadLocalClasses = [
        'SpecialBlankpage' => __DIR__ . '/includes/specials/SpecialBlankpage.php',
        'SpecialBlock' => __DIR__ . '/includes/specials/SpecialBlock.php',
        'SpecialBlockList' => __DIR__ . '/includes/specials/SpecialBlockList.php',
-       'SpecialBookSources' => __DIR__ . '/includes/specials/SpecialBooksources.php',
+       'SpecialBookSources' => __DIR__ . '/includes/specials/SpecialBookSources.php',
        'SpecialBotPasswords' => __DIR__ . '/includes/specials/SpecialBotPasswords.php',
        'SpecialCachedPage' => __DIR__ . '/includes/specials/SpecialCachedPage.php',
        'SpecialCategories' => __DIR__ . '/includes/specials/SpecialCategories.php',
@@ -1368,7 +1369,7 @@ $wgAutoloadLocalClasses = [
        'SpecialDiff' => __DIR__ . '/includes/specials/SpecialDiff.php',
        'SpecialEditTags' => __DIR__ . '/includes/specials/SpecialEditTags.php',
        'SpecialEditWatchlist' => __DIR__ . '/includes/specials/SpecialEditWatchlist.php',
-       'SpecialEmailUser' => __DIR__ . '/includes/specials/SpecialEmailuser.php',
+       'SpecialEmailUser' => __DIR__ . '/includes/specials/SpecialEmailUser.php',
        'SpecialExpandTemplates' => __DIR__ . '/includes/specials/SpecialExpandTemplates.php',
        'SpecialExport' => __DIR__ . '/includes/specials/SpecialExport.php',
        'SpecialFilepath' => __DIR__ . '/includes/specials/SpecialFilepath.php',
@@ -1378,10 +1379,10 @@ $wgAutoloadLocalClasses = [
        'SpecialLinkAccounts' => __DIR__ . '/includes/specials/SpecialLinkAccounts.php',
        'SpecialListAdmins' => __DIR__ . '/includes/specials/redirects/SpecialListAdmins.php',
        'SpecialListBots' => __DIR__ . '/includes/specials/redirects/SpecialListBots.php',
-       'SpecialListFiles' => __DIR__ . '/includes/specials/SpecialListfiles.php',
-       'SpecialListGrants' => __DIR__ . '/includes/specials/SpecialListgrants.php',
-       'SpecialListGroupRights' => __DIR__ . '/includes/specials/SpecialListgrouprights.php',
-       'SpecialListUsers' => __DIR__ . '/includes/specials/SpecialListusers.php',
+       'SpecialListFiles' => __DIR__ . '/includes/specials/SpecialListFiles.php',
+       'SpecialListGrants' => __DIR__ . '/includes/specials/SpecialListGrants.php',
+       'SpecialListGroupRights' => __DIR__ . '/includes/specials/SpecialListGroupRights.php',
+       'SpecialListUsers' => __DIR__ . '/includes/specials/SpecialListUsers.php',
        'SpecialLockdb' => __DIR__ . '/includes/specials/SpecialLockdb.php',
        'SpecialLog' => __DIR__ . '/includes/specials/SpecialLog.php',
        'SpecialMergeHistory' => __DIR__ . '/includes/specials/SpecialMergeHistory.php',
@@ -1408,13 +1409,13 @@ $wgAutoloadLocalClasses = [
        'SpecialRandomInCategory' => __DIR__ . '/includes/specials/SpecialRandomInCategory.php',
        'SpecialRandomredirect' => __DIR__ . '/includes/specials/SpecialRandomredirect.php',
        'SpecialRandomrootpage' => __DIR__ . '/includes/specials/SpecialRandomrootpage.php',
-       'SpecialRecentChanges' => __DIR__ . '/includes/specials/SpecialRecentchanges.php',
-       'SpecialRecentChangesLinked' => __DIR__ . '/includes/specials/SpecialRecentchangeslinked.php',
+       'SpecialRecentChanges' => __DIR__ . '/includes/specials/SpecialRecentChanges.php',
+       'SpecialRecentChangesLinked' => __DIR__ . '/includes/specials/SpecialRecentChangesLinked.php',
        'SpecialRedirect' => __DIR__ . '/includes/specials/SpecialRedirect.php',
        'SpecialRedirectToSpecial' => __DIR__ . '/includes/specialpage/SpecialRedirectToSpecial.php',
        'SpecialRemoveCredentials' => __DIR__ . '/includes/specials/SpecialRemoveCredentials.php',
        'SpecialResetTokens' => __DIR__ . '/includes/specials/SpecialResetTokens.php',
-       'SpecialRevisionDelete' => __DIR__ . '/includes/specials/SpecialRevisiondelete.php',
+       'SpecialRevisionDelete' => __DIR__ . '/includes/specials/SpecialRevisionDelete.php',
        'SpecialRunJobs' => __DIR__ . '/includes/specials/SpecialRunJobs.php',
        'SpecialSearch' => __DIR__ . '/includes/specials/SpecialSearch.php',
        'SpecialSpecialpages' => __DIR__ . '/includes/specials/SpecialSpecialpages.php',
@@ -1432,7 +1433,7 @@ $wgAutoloadLocalClasses = [
        'SpecialUserLogout' => __DIR__ . '/includes/specials/SpecialUserLogout.php',
        'SpecialVersion' => __DIR__ . '/includes/specials/SpecialVersion.php',
        'SpecialWatchlist' => __DIR__ . '/includes/specials/SpecialWatchlist.php',
-       'SpecialWhatLinksHere' => __DIR__ . '/includes/specials/SpecialWhatlinkshere.php',
+       'SpecialWhatLinksHere' => __DIR__ . '/includes/specials/SpecialWhatLinksHere.php',
        'SqlBagOStuff' => __DIR__ . '/includes/objectcache/SqlBagOStuff.php',
        'SqlSearchResultSet' => __DIR__ . '/includes/search/SqlSearchResultSet.php',
        'Sqlite' => __DIR__ . '/maintenance/sqlite.inc',
@@ -1449,19 +1450,19 @@ $wgAutoloadLocalClasses = [
        'StorageTypeStats' => __DIR__ . '/maintenance/storage/storageTypeStats.php',
        'StoreFileOp' => __DIR__ . '/includes/libs/filebackend/fileop/StoreFileOp.php',
        'StreamFile' => __DIR__ . '/includes/StreamFile.php',
-       'StringPrefixSearch' => __DIR__ . '/includes/PrefixSearch.php',
+       'StringPrefixSearch' => __DIR__ . '/includes/search/StringPrefixSearch.php',
        'StringUtils' => __DIR__ . '/includes/libs/StringUtils.php',
        'StripState' => __DIR__ . '/includes/parser/StripState.php',
        'StubObject' => __DIR__ . '/includes/StubObject.php',
-       'StubUserLang' => __DIR__ . '/includes/StubObject.php',
+       'StubUserLang' => __DIR__ . '/includes/StubUserLang.php',
        'SubmitAction' => __DIR__ . '/includes/actions/SubmitAction.php',
        'SubpageImportTitleFactory' => __DIR__ . '/includes/title/SubpageImportTitleFactory.php',
        'SvgHandler' => __DIR__ . '/includes/media/SvgHandler.php',
        'SwiftFileBackend' => __DIR__ . '/includes/libs/filebackend/SwiftFileBackend.php',
-       'SwiftFileBackendDirList' => __DIR__ . '/includes/libs/filebackend/SwiftFileBackend.php',
-       'SwiftFileBackendFileList' => __DIR__ . '/includes/libs/filebackend/SwiftFileBackend.php',
-       'SwiftFileBackendList' => __DIR__ . '/includes/libs/filebackend/SwiftFileBackend.php',
-       'SwiftFileOpHandle' => __DIR__ . '/includes/libs/filebackend/SwiftFileBackend.php',
+       'SwiftFileBackendDirList' => __DIR__ . '/includes/libs/filebackend/fileiteration/SwiftFileBackendDirList.php',
+       'SwiftFileBackendFileList' => __DIR__ . '/includes/libs/filebackend/fileiteration/SwiftFileBackendFileList.php',
+       'SwiftFileBackendList' => __DIR__ . '/includes/libs/filebackend/fileiteration/SwiftFileBackendList.php',
+       'SwiftFileOpHandle' => __DIR__ . '/includes/libs/filebackend/fileophandle/SwiftFileOpHandle.php',
        'SwiftVirtualRESTService' => __DIR__ . '/includes/libs/virtualrest/SwiftVirtualRESTService.php',
        'SyncFileBackend' => __DIR__ . '/maintenance/syncFileBackend.php',
        'TableCleanup' => __DIR__ . '/maintenance/cleanupTable.inc',
@@ -1474,12 +1475,12 @@ $wgAutoloadLocalClasses = [
        'TemplatesOnThisPageFormatter' => __DIR__ . '/includes/TemplatesOnThisPageFormatter.php',
        'TextContent' => __DIR__ . '/includes/content/TextContent.php',
        'TextContentHandler' => __DIR__ . '/includes/content/TextContentHandler.php',
-       'TextPassDumper' => __DIR__ . '/maintenance/dumpTextPass.php',
+       'TextPassDumper' => __DIR__ . '/maintenance/includes/TextPassDumper.php',
        'TextSlotDiffRenderer' => __DIR__ . '/includes/diff/TextSlotDiffRenderer.php',
        'TextStatsOutput' => __DIR__ . '/maintenance/language/StatOutputs.php',
        'TgConverter' => __DIR__ . '/languages/classes/LanguageTg.php',
        'ThrottledError' => __DIR__ . '/includes/exception/ThrottledError.php',
-       'ThumbnailImage' => __DIR__ . '/includes/media/MediaTransformOutput.php',
+       'ThumbnailImage' => __DIR__ . '/includes/media/ThumbnailImage.php',
        'ThumbnailRenderJob' => __DIR__ . '/includes/jobqueue/jobs/ThumbnailRenderJob.php',
        'TidyUpT39714' => __DIR__ . '/maintenance/tidyUpT39714.php',
        'TiffHandler' => __DIR__ . '/includes/media/TiffHandler.php',
@@ -1490,14 +1491,14 @@ $wgAutoloadLocalClasses = [
        'TitleCleanup' => __DIR__ . '/maintenance/cleanupTitles.php',
        'TitleFormatter' => __DIR__ . '/includes/title/TitleFormatter.php',
        'TitleParser' => __DIR__ . '/includes/title/TitleParser.php',
-       'TitlePrefixSearch' => __DIR__ . '/includes/PrefixSearch.php',
+       'TitlePrefixSearch' => __DIR__ . '/includes/search/TitlePrefixSearch.php',
        'TitleValue' => __DIR__ . '/includes/title/TitleValue.php',
        'TrackBlobs' => __DIR__ . '/maintenance/storage/trackBlobs.php',
        'TrackingCategories' => __DIR__ . '/includes/TrackingCategories.php',
        'TraditionalImageGallery' => __DIR__ . '/includes/gallery/TraditionalImageGallery.php',
        'TransactionRoundDefiningUpdate' => __DIR__ . '/includes/deferred/TransactionRoundDefiningUpdate.php',
-       'TransformParameterError' => __DIR__ . '/includes/media/MediaTransformOutput.php',
-       'TransformTooBigImageAreaError' => __DIR__ . '/includes/media/MediaTransformOutput.php',
+       'TransformParameterError' => __DIR__ . '/includes/media/TransformParameterError.php',
+       'TransformTooBigImageAreaError' => __DIR__ . '/includes/media/TransformTooBigImageAreaError.php',
        'TransformationalImageHandler' => __DIR__ . '/includes/media/TransformationalImageHandler.php',
        'UDPRCFeedEngine' => __DIR__ . '/includes/rcfeed/UDPRCFeedEngine.php',
        'UDPTransport' => __DIR__ . '/includes/libs/UDPTransport.php',
@@ -1542,7 +1543,7 @@ $wgAutoloadLocalClasses = [
        'UploadStash' => __DIR__ . '/includes/upload/UploadStash.php',
        'UploadStashBadPathException' => __DIR__ . '/includes/upload/exception/UploadStashBadPathException.php',
        'UploadStashException' => __DIR__ . '/includes/upload/exception/UploadStashException.php',
-       'UploadStashFile' => __DIR__ . '/includes/upload/UploadStash.php',
+       'UploadStashFile' => __DIR__ . '/includes/upload/UploadStashFile.php',
        'UploadStashFileException' => __DIR__ . '/includes/upload/exception/UploadStashFileException.php',
        'UploadStashFileNotFoundException' => __DIR__ . '/includes/upload/exception/UploadStashFileNotFoundException.php',
        'UploadStashNoSuchKeyException' => __DIR__ . '/includes/upload/exception/UploadStashNoSuchKeyException.php',
@@ -1563,6 +1564,7 @@ $wgAutoloadLocalClasses = [
        'UserNamePrefixSearch' => __DIR__ . '/includes/user/UserNamePrefixSearch.php',
        'UserNotLoggedIn' => __DIR__ . '/includes/exception/UserNotLoggedIn.php',
        'UserOptionsMaintenance' => __DIR__ . '/maintenance/userOptions.php',
+       'UserOptionsUpdateJob' => __DIR__ . '/includes/jobqueue/jobs/UserOptionsUpdateJob.php',
        'UserPasswordPolicy' => __DIR__ . '/includes/password/UserPasswordPolicy.php',
        'UserRightsProxy' => __DIR__ . '/includes/user/UserRightsProxy.php',
        'UserrightsPage' => __DIR__ . '/includes/specials/SpecialUserrights.php',
@@ -1624,7 +1626,7 @@ $wgAutoloadLocalClasses = [
        'WikiTextStructure' => __DIR__ . '/includes/content/WikiTextStructure.php',
        'Wikimedia\\Http\\HttpAcceptNegotiator' => __DIR__ . '/includes/libs/http/HttpAcceptNegotiator.php',
        'Wikimedia\\Http\\HttpAcceptParser' => __DIR__ . '/includes/libs/http/HttpAcceptParser.php',
-       'Wikimedia\\Rdbms\\AtomicSectionIdentifier' => __DIR__ . '/includes/libs/rdbms/database/AtomicSectionIdentifier.php',
+       'Wikimedia\\Rdbms\\AtomicSectionIdentifier' => __DIR__ . '/includes/libs/rdbms/database/utils/AtomicSectionIdentifier.php',
        'Wikimedia\\Rdbms\\Blob' => __DIR__ . '/includes/libs/rdbms/encasing/Blob.php',
        'Wikimedia\\Rdbms\\ChronologyProtector' => __DIR__ . '/includes/libs/rdbms/ChronologyProtector.php',
        'Wikimedia\\Rdbms\\ConnectionManager' => __DIR__ . '/includes/libs/rdbms/connectionmanager/ConnectionManager.php',
@@ -1634,16 +1636,18 @@ $wgAutoloadLocalClasses = [
        'Wikimedia\\Rdbms\\DBError' => __DIR__ . '/includes/libs/rdbms/exception/DBError.php',
        'Wikimedia\\Rdbms\\DBExpectedError' => __DIR__ . '/includes/libs/rdbms/exception/DBExpectedError.php',
        'Wikimedia\\Rdbms\\DBMasterPos' => __DIR__ . '/includes/libs/rdbms/database/position/DBMasterPos.php',
+       'Wikimedia\\Rdbms\\DBQueryDisconnectedError' => __DIR__ . '/includes/libs/rdbms/exception/DBQueryDisconnectedError.php',
        'Wikimedia\\Rdbms\\DBQueryError' => __DIR__ . '/includes/libs/rdbms/exception/DBQueryError.php',
        'Wikimedia\\Rdbms\\DBQueryTimeoutError' => __DIR__ . '/includes/libs/rdbms/exception/DBQueryTimeoutError.php',
        'Wikimedia\\Rdbms\\DBReadOnlyError' => __DIR__ . '/includes/libs/rdbms/exception/DBReadOnlyError.php',
+       'Wikimedia\\Rdbms\\DBReadOnlyRoleError' => __DIR__ . '/includes/libs/rdbms/exception/DBReadOnlyRoleError.php',
        'Wikimedia\\Rdbms\\DBReplicationWaitError' => __DIR__ . '/includes/libs/rdbms/exception/DBReplicationWaitError.php',
        'Wikimedia\\Rdbms\\DBTransactionError' => __DIR__ . '/includes/libs/rdbms/exception/DBTransactionError.php',
        'Wikimedia\\Rdbms\\DBTransactionSizeError' => __DIR__ . '/includes/libs/rdbms/exception/DBTransactionSizeError.php',
        'Wikimedia\\Rdbms\\DBTransactionStateError' => __DIR__ . '/includes/libs/rdbms/exception/DBTransactionStateError.php',
        'Wikimedia\\Rdbms\\DBUnexpectedError' => __DIR__ . '/includes/libs/rdbms/exception/DBUnexpectedError.php',
        'Wikimedia\\Rdbms\\Database' => __DIR__ . '/includes/libs/rdbms/database/Database.php',
-       'Wikimedia\\Rdbms\\DatabaseDomain' => __DIR__ . '/includes/libs/rdbms/database/DatabaseDomain.php',
+       'Wikimedia\\Rdbms\\DatabaseDomain' => __DIR__ . '/includes/libs/rdbms/database/domain/DatabaseDomain.php',
        'Wikimedia\\Rdbms\\DatabaseMssql' => __DIR__ . '/includes/libs/rdbms/database/DatabaseMssql.php',
        'Wikimedia\\Rdbms\\DatabaseMysqlBase' => __DIR__ . '/includes/libs/rdbms/database/DatabaseMysqlBase.php',
        'Wikimedia\\Rdbms\\DatabaseMysqli' => __DIR__ . '/includes/libs/rdbms/database/DatabaseMysqli.php',
@@ -1651,6 +1655,7 @@ $wgAutoloadLocalClasses = [
        'Wikimedia\\Rdbms\\DatabaseSqlite' => __DIR__ . '/includes/libs/rdbms/database/DatabaseSqlite.php',
        'Wikimedia\\Rdbms\\FakeResultWrapper' => __DIR__ . '/includes/libs/rdbms/database/resultwrapper/FakeResultWrapper.php',
        'Wikimedia\\Rdbms\\Field' => __DIR__ . '/includes/libs/rdbms/field/Field.php',
+       'Wikimedia\\Rdbms\\GeneralizedSql' => __DIR__ . '/includes/libs/rdbms/database/utils/GeneralizedSql.php',
        'Wikimedia\\Rdbms\\IBlob' => __DIR__ . '/includes/libs/rdbms/encasing/IBlob.php',
        'Wikimedia\\Rdbms\\IDatabase' => __DIR__ . '/includes/libs/rdbms/database/IDatabase.php',
        'Wikimedia\\Rdbms\\ILBFactory' => __DIR__ . '/includes/libs/rdbms/lbfactory/ILBFactory.php',
@@ -1679,7 +1684,6 @@ $wgAutoloadLocalClasses = [
        'Wikimedia\\Rdbms\\PostgresField' => __DIR__ . '/includes/libs/rdbms/field/PostgresField.php',
        'Wikimedia\\Rdbms\\ResultWrapper' => __DIR__ . '/includes/libs/rdbms/database/resultwrapper/ResultWrapper.php',
        'Wikimedia\\Rdbms\\SQLiteField' => __DIR__ . '/includes/libs/rdbms/field/SQLiteField.php',
-       'Wikimedia\\Rdbms\\SavepointPostgres' => __DIR__ . '/includes/libs/rdbms/database/utils/SavepointPostgres.php',
        'Wikimedia\\Rdbms\\SessionConsistentConnectionManager' => __DIR__ . '/includes/libs/rdbms/connectionmanager/SessionConsistentConnectionManager.php',
        'Wikimedia\\Rdbms\\Subquery' => __DIR__ . '/includes/libs/rdbms/encasing/Subquery.php',
        'Wikimedia\\Rdbms\\TransactionProfiler' => __DIR__ . '/includes/libs/rdbms/TransactionProfiler.php',
@@ -1693,9 +1697,6 @@ $wgAutoloadLocalClasses = [
        'WrapOldPasswords' => __DIR__ . '/maintenance/wrapOldPasswords.php',
        'XCFHandler' => __DIR__ . '/includes/media/XCFHandler.php',
        'XMLRCFeedFormatter' => __DIR__ . '/includes/rcfeed/XMLRCFeedFormatter.php',
-       'XMPInfo' => __DIR__ . '/includes/compat/XMPReader.php',
-       'XMPReader' => __DIR__ . '/includes/compat/XMPReader.php',
-       'XMPValidate' => __DIR__ . '/includes/compat/XMPReader.php',
        'Xhprof' => __DIR__ . '/includes/libs/Xhprof.php',
        'XhprofData' => __DIR__ . '/includes/libs/XhprofData.php',
        'Xml' => __DIR__ . '/includes/Xml.php',
@@ -1706,8 +1707,8 @@ $wgAutoloadLocalClasses = [
        'ZhConverter' => __DIR__ . '/languages/classes/LanguageZh.php',
        'ZipDirectoryReader' => __DIR__ . '/includes/utils/ZipDirectoryReader.php',
        'ZipDirectoryReaderError' => __DIR__ . '/includes/utils/ZipDirectoryReaderError.php',
-       'concatenatedgziphistoryblob' => __DIR__ . '/includes/HistoryBlob.php',
-       'historyblobcurstub' => __DIR__ . '/includes/HistoryBlob.php',
-       'historyblobstub' => __DIR__ . '/includes/HistoryBlob.php',
+       'concatenatedgziphistoryblob' => __DIR__ . '/includes/historyblob/ConcatenatedGzipHistoryBlob.php',
+       'historyblobcurstub' => __DIR__ . '/includes/historyblob/HistoryBlobCurStub.php',
+       'historyblobstub' => __DIR__ . '/includes/historyblob/HistoryBlobStub.php',
        'profile_point' => __DIR__ . '/profileinfo.php',
 ];
index 8c9dc3f..11680ff 100644 (file)
@@ -17,8 +17,8 @@
                "wiki": "https://www.mediawiki.org/"
        },
        "require": {
-               "composer/semver": "1.4.2",
-               "cssjanus/cssjanus": "1.2.1",
+               "composer/semver": "1.5.0",
+               "cssjanus/cssjanus": "1.3.0",
                "ext-ctype": "*",
                "ext-fileinfo": "*",
                "ext-iconv": "*",
                "ext-xml": "*",
                "guzzlehttp/guzzle": "6.3.3",
                "liuggio/statsd-php-client": "1.0.18",
-               "oojs/oojs-ui": "0.31.0",
+               "oojs/oojs-ui": "0.31.6",
                "pear/mail": "1.4.1",
                "pear/mail_mime": "1.10.2",
                "pear/net_smtp": "1.8.1",
                "php": ">=5.6.99",
                "psr/log": "1.0.2",
                "wikimedia/assert": "0.2.2",
-               "wikimedia/at-ease": "1.2.0",
+               "wikimedia/at-ease": "2.0.0",
                "wikimedia/base-convert": "2.0.0",
                "wikimedia/cdb": "1.4.1",
                "wikimedia/cldr-plural-rule-parser": "1.0.0",
        },
        "require-dev": {
                "cache/integration-tests": "0.16.0",
-               "composer/spdx-licenses": "1.4.0",
+               "composer/spdx-licenses": "1.5.1",
                "giorgiosironi/eris": "^0.10.0",
                "hamcrest/hamcrest-php": "^2.0",
                "jakub-onderka/php-console-highlighter": "0.3.2",
                "jakub-onderka/php-parallel-lint": "0.9.2",
-               "jetbrains/phpstorm-stubs": "dev-master#38ff1a581b297f7901e961b8c923862ea80c3b96",
                "justinrainbow/json-schema": "~5.2",
-               "mediawiki/mediawiki-codesniffer": "24.0.0",
+               "mediawiki/mediawiki-codesniffer": "26.0.0",
                "monolog/monolog": "~1.22.1",
                "nikic/php-parser": "3.1.5",
                "seld/jsonlint": "1.7.1",
@@ -75,7 +74,8 @@
                "psy/psysh": "0.9.9",
                "wikimedia/avro": "1.8.0",
                "wikimedia/testing-access-wrapper": "~1.0",
-               "wmde/hamcrest-html-matchers": "^0.1.0"
+               "wmde/hamcrest-html-matchers": "^0.1.0",
+               "mediawiki/mediawiki-phan-config": "0.6.0"
        },
        "replace": {
                "symfony/polyfill-ctype": "1.99",
index 9d5d49e..6291bfc 100644 (file)
                                <!-- This isn't a good idea; we should be using "ID" instead of "NMTOKEN" -->
                                <!-- However, "NMTOKEN" is strictest definition that is both compatible with existing -->
                                <!-- usage ([0-9]+) and with the "ID" type. -->
-                               <attribute name="id" type="NMTOKEN" />
+                               <attribute name="id" use="optional" type="NMTOKEN" />
                                <attribute name="bytes" use="optional" type="nonNegativeInteger" />
                        </extension>
                </simpleContent>
index 8cd4e71..32946d3 100644 (file)
                                                "php": {
                                                        "type": "string",
                                                        "description": "Version constraint string against PHP."
+                                               },
+                                               "ability-shell": {
+                                                       "type": "boolean",
+                                                       "default": false,
+                                                       "description": "Whether this extension requires shell access."
                                                }
                                        },
                                        "patternProperties": {
                                                "^ext-": {
                                                        "type": "string",
                                                        "description": "Required PHP extension.",
-                                                       "const": "*"
+                                                       "enum": ["*"]
                                                }
                                        }
                                },
index 1d64095..42b34b7 100644 (file)
                                                "php": {
                                                        "type": "string",
                                                        "description": "Version constraint string against PHP."
+                                               },
+                                               "ability-shell": {
+                                                       "type": "boolean",
+                                                       "default": false,
+                                                       "description": "Whether this extension requires shell access."
                                                }
                                        },
                                        "patternProperties": {
                                                "^ext-": {
                                                        "type": "string",
                                                        "description": "Required PHP extension.",
-                                                       "const": "*"
+                                                       "enum": ["*"]
                                                }
                                        }
                                },
index 4ef680a..7f8b192 100644 (file)
@@ -1193,9 +1193,6 @@ a custom editor, e.g. for a special namespace, etc.
 $article: Article being edited
 $user: User performing the edit
 
-'DatabaseOraclePostInit': Called after initialising an Oracle database
-$db: the DatabaseOracle object
-
 'DeletedContribsPager::reallyDoQuery': Called before really executing the query
 for Special:DeletedContributions
 Similar to ContribsPager::reallyDoQuery
@@ -1612,7 +1609,7 @@ $out: OutputPage object
 notifications.
 &$title: Title object of page
 &$url: string value as output (out parameter, can modify)
-$query: query options passed to Title::getCanonicalURL()
+$query: query options as string passed to Title::getCanonicalURL()
 
 'GetContentModels': Add content models to the list of available models.
 &$models: array containing current model list, as strings. Extensions should add to this list.
@@ -1650,7 +1647,7 @@ $single: Only extract the current language; if false, the prop value should
 'GetFullURL': Modify fully-qualified URLs used in redirects/export/offsite data.
 &$title: Title object of page
 &$url: string value as output (out parameter, can modify)
-$query: query options passed to Title::getFullURL()
+$query: query options as string passed to Title::getFullURL()
 
 'GetHumanTimestamp': Pre-emptively override the human-readable timestamp
 generated by MWTimestamp::getHumanTimestamp(). Return false in this hook to use
@@ -1664,7 +1661,7 @@ $lang: Language that will be used to render the timestamp
 'GetInternalURL': Modify fully-qualified URLs used for squid cache purging.
 &$title: Title object of page
 &$url: string value as output (out parameter, can modify)
-$query: query options passed to Title::getInternalURL()
+$query: query options as string passed to Title::getInternalURL()
 
 'GetIP': modify the ip of the current user (called only once).
 &$ip: string holding the ip as determined so far
@@ -1689,7 +1686,7 @@ be buggy for internal urls on render if you do not re-implement the horrible
 hack that Title::getLocalURL uses in your own extension.
 &$title: Title object of page
 &$url: string value as output (out parameter, can modify)
-$query: query options passed to Title::getLocalURL()
+$query: query options as string passed to Title::getLocalURL()
 
 'GetLocalURL::Article': Modify local URLs specifically pointing to article paths
 without any fancy queries or variants.
@@ -1699,7 +1696,7 @@ without any fancy queries or variants.
 'GetLocalURL::Internal': Modify local URLs to internal pages.
 &$title: Title object of page
 &$url: string value as output (out parameter, can modify)
-$query: query options passed to Title::getLocalURL()
+$query: query options as string passed to Title::getLocalURL()
 
 'GetLogTypesOnUser': Add log types where the target is a userpage
 &$types: Array of log types
@@ -2198,6 +2195,16 @@ Special:LonelyPages.
 'MagicWordwgVariableIDs': When defining new magic words IDs.
 &$variableIDs: array of strings
 
+'MaintenanceUpdateAddParams': allow extensions to add params to the update.php
+maintenance script.
+&$params: array to populate with the params to be added. Array elements are keyed by
+the param name. Each param is an associative array that must include the following keys:
+  - desc The description of the param to show on --help
+  - require Is the param required? Defaults to false if not set.
+  - withArg Is an argument required with this option?  Defaults to false if not set.
+  - shortName Character to use as short name, or false if none.  Defaults to false if not set.
+  - multiOccurrence Can this option be passed multiple times?  Defaults to false if not set.
+
 'MaintenanceRefreshLinksInit': before executing the refreshLinks.php maintenance
 script.
 $refreshLinks: RefreshLinks object
@@ -2220,6 +2227,7 @@ $rcid: ID of the revision to be marked patrolled
 $wcOnlySysopsCanPatrol: config setting indicating whether the user needs to be a
   sysop in order to mark an edit patrolled.
 $auto: true if the edit is being marked as patrolled automatically
+&$tags: the tags to be applied to the patrol log entry
 
 'MarkPatrolledComplete': After an edit is marked patrolled.
 $rcid: ID of the revision marked as patrolled
@@ -2322,7 +2330,7 @@ namespace.
 $index: Integer; the index of the namespace being checked.
 &$result: Boolean; whether MediaWiki currently thinks that pages in this
   namespace are movable. Hooks may change this value to override the return
-  value of MWNamespace::isMovable().
+  value of NamespaceInfo::isMovable().
 
 'NewDifferenceEngine': Called when a new DifferenceEngine object is made
 $title: the diff page title (nullable)
@@ -2440,16 +2448,20 @@ $title: Title object
 &$pageLang: the page content language. Input can be anything (under control of
   hook subscribers), but hooks should return Language objects. Language code
   strings are deprecated.
-$userLang: the user language (Language or StubUserLang object)
+$userLang: the user language (Language object)
 
 'PageContentSave': Before an article is saved.
 $wikiPage: the WikiPage (object) being saved
 $user: the user (object) saving the article
 $content: the new article content, as a Content object
-$summary: the article summary (comment)
-$isminor: minor flag
-$iswatch: watch flag
-$section: section #
+&$summary: CommentStoreComment object containing the edit comment. Can be replaced with a new one.
+$isminor: Boolean flag specifying if the edit was marked as minor.
+$iswatch: Previously a watch flag. Currently unused, always null.
+$section: Previously the section number being edited. Currently unused, always null.
+$flags: All EDIT_… flags (including EDIT_MINOR) as an integer number. See WikiPage::doEditContent
+  documentation for flags' definition.
+$status: StatusValue object for the hook handlers resulting status. Either set $status->fatal() or
+  return false to abort the save action.
 
 'PageContentSaveComplete': After an article has been updated.
 $wikiPage: WikiPage modified
@@ -3056,7 +3068,6 @@ $tooltip: The default tooltip.  Escape before using.
     - text - String for the text
     - attribs - Array of attributes
     - query - Array of query parameters to add to the URL
-    - options - Array of options for Linker::link
 $lang: The language code to use for the link in the wfMessage function
 
 'SkinGetPoweredBy': TODO
@@ -3557,7 +3568,10 @@ hook. If your extension absolutely, positively must prevent some files from
 being uploaded, use UploadVerifyFile or UploadVerifyUpload.
 $upload: (object) An instance of UploadBase, with all info about the upload
 $user: (object) An instance of User, the user uploading this file
-$props: (array) File properties, as returned by FSFile::getPropsFromPath()
+$props: (array|null) File properties, as returned by
+  MWFileProps::getPropsFromPath(). Note this is not always guaranteed to be set,
+  e.g. in test scenarios. Call MWFileProps::getPropsFromPath() yourself in case
+  you need the information.
 &$error: output: If the file stashing should be prevented, set this to the
   reason in the form of [ messagename, param1, param2, ... ] or a
   MessageSpecifier instance (you might want to use ApiMessage to provide machine
@@ -3586,7 +3600,10 @@ MIME type (same as UploadVerifyFile) and the information entered by the user
 (upload comment, file page contents etc.).
 $upload: (object) An instance of UploadBase, with all info about the upload
 $user: (object) An instance of User, the user uploading this file
-$props: (array) File properties, as returned by FSFile::getPropsFromPath()
+$props: (array|null) File properties, as returned by
+  MWFileProps::getPropsFromPath(). Note this is not always guaranteed to be set,
+  e.g. in test scenarios. Call MWFileProps::getPropsFromPath() yourself in case
+  you need the information.
 $comment: (string) Upload log comment (also used as edit summary)
 $pageText: (string) File description page text (only used for new uploads)
 &$error: output: If the file upload should be prevented, set this to the reason
index 7106d2e..a703e1f 100644 (file)
@@ -7,7 +7,7 @@
        },
        "repository" : {
                "type" : "git",
-               "url" : "https://gerrit.wikimedia.org/r/p/mediawiki/core.git"
+               "url" : "https://gerrit.wikimedia.org/r/mediawiki/core.git"
        }
 
 }
index b2501d4..d97c8d1 100644 (file)
@@ -14,7 +14,7 @@ Primary scripts:
   api.php
     Script to provide an API for bots to fetch content and informations about
     the site and also modify it. See https://www.mediawiki.org/wiki/API
-    for more informations.
+    for more information.
 
   img_auth.php
     Script that only serve images to logged in users. To configure the wiki
index ca69d31..ba4ed74 100644 (file)
@@ -148,7 +148,7 @@ function wfImageAuthMain() {
                }
 
                // Run hook for extension authorization plugins
-               /** @var $result array */
+               /** @var array $result */
                $result = null;
                if ( !Hooks::run( 'ImgAuthBeforeStream', [ &$title, &$path, &$name, &$result ] ) ) {
                        wfForbidden( $result[0], $result[1], array_slice( $result, 2 ) );
@@ -177,7 +177,7 @@ function wfImageAuthMain() {
 
        // Stream the requested file
        wfDebugLog( 'img_auth', "Streaming `" . $filename . "`." );
-       $repo->streamFile( $filename, $headers, $options );
+       $repo->streamFileWithStatus( $filename, $headers, $options );
 }
 
 /**
@@ -186,13 +186,12 @@ function wfImageAuthMain() {
  * subsequent arguments to $msg2 will be passed as parameters only for replacing in $msg2
  * @param string $msg1
  * @param string $msg2
+ * @param mixed ...$args To pass as params to wfMessage() with $msg2. Either variadic, or a single
+ *   array argument.
  */
-function wfForbidden( $msg1, $msg2 ) {
+function wfForbidden( $msg1, $msg2, ...$args ) {
        global $wgImgAuthDetails;
 
-       $args = func_get_args();
-       array_shift( $args );
-       array_shift( $args );
        $args = ( isset( $args[0] ) && is_array( $args[0] ) ) ? $args[0] : $args;
 
        $msgHdr = wfMessage( $msg1 )->escaped();
index 0c33eb9..597b8e7 100644 (file)
@@ -136,11 +136,7 @@ class ActorMigration {
         * @return string[] [ $text, $actor ]
         */
        private static function getFieldNames( $key ) {
-               if ( isset( self::$specialFields[$key] ) ) {
-                       return self::$specialFields[$key];
-               }
-
-               return [ $key . '_text', substr( $key, 0, -5 ) . '_actor' ];
+               return self::$specialFields[$key] ?? [ $key . '_text', substr( $key, 0, -5 ) . '_actor' ];
        }
 
        /**
index 8f4ed40..5f889ad 100644 (file)
@@ -162,7 +162,7 @@ class AjaxResponse {
                        // For back-compat, it is supported that mResponseCode be a string like " 200 OK"
                        // (with leading space and the status message after). Cast response code to an integer
                        // to take advantage of PHP's conversion rules which will turn "  200 OK" into 200.
-                       // https://secure.php.net/manual/en/language.types.string.php#language.types.string.conversion
+                       // https://www.php.net/manual/en/language.types.string.php#language.types.string.conversion
                        $n = intval( trim( $this->mResponseCode ) );
                        HttpStatus::header( $n );
                }
index f8fbf83..fa11bcb 100644 (file)
@@ -134,6 +134,7 @@ class AutoLoader {
                        'MediaWiki\\Edit\\' => __DIR__ . '/edit/',
                        'MediaWiki\\EditPage\\' => __DIR__ . '/editpage/',
                        'MediaWiki\\Linker\\' => __DIR__ . '/linker/',
+                       'MediaWiki\\Permissions\\' => __DIR__ . '/Permissions/',
                        'MediaWiki\\Preferences\\' => __DIR__ . '/preferences/',
                        'MediaWiki\\Revision\\' => __DIR__ . '/Revision/',
                        'MediaWiki\\Session\\' => __DIR__ . '/session/',
index a01465e..02c9d01 100644 (file)
@@ -198,7 +198,8 @@ class Autopromote {
                        case APCOND_IPINRANGE:
                                return IP::isInRange( $user->getRequest()->getIP(), $cond[1] );
                        case APCOND_BLOCKED:
-                               return $user->isBlocked();
+                               // @TODO Should partial blocks prevent auto promote?
+                               return (bool)$user->getBlock();
                        case APCOND_ISBOT:
                                return in_array( 'bot', User::getGroupPermissions( $user->getGroups() ) );
                        default:
index 65408f6..5b0d256 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * Blocks and bans object
+ * Class for blocks stored in the database.
  *
  * 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
 
 use Wikimedia\Rdbms\Database;
 use Wikimedia\Rdbms\IDatabase;
-use MediaWiki\Block\BlockRestriction;
+use MediaWiki\Block\AbstractBlock;
+use MediaWiki\Block\BlockRestrictionStore;
 use MediaWiki\Block\Restriction\Restriction;
 use MediaWiki\Block\Restriction\NamespaceRestriction;
 use MediaWiki\Block\Restriction\PageRestriction;
 use MediaWiki\MediaWikiServices;
 
-class Block {
-       /** @var string */
-       public $mReason;
-
-       /** @var string */
-       public $mTimestamp;
-
+/**
+ * Blocks (as opposed to system blocks) are stored in the database, may
+ * give rise to autoblocks and may be tracked with cookies. Blocks are
+ * more customizable than system blocks: they may be hardblocks, and
+ * they may be sitewide or partial.
+ */
+class Block extends AbstractBlock {
        /** @var bool */
        public $mAuto;
 
-       /** @var string */
-       public $mExpiry;
-
-       /** @var bool */
-       public $mHideName;
-
        /** @var int */
        public $mParentBlockId;
 
@@ -53,61 +48,23 @@ class Block {
        /** @var bool */
        private $mFromMaster;
 
-       /** @var bool */
-       private $mBlockEmail;
-
-       /** @var bool */
-       private $allowUsertalk;
-
-       /** @var bool */
-       private $blockCreateAccount;
-
-       /** @var User|string */
-       private $target;
-
        /** @var int Hack for foreign blocking (CentralAuth) */
        private $forcedTargetID;
 
-       /**
-        * @var int Block::TYPE_ constant. After the block has been loaded
-        * from the database, this can only be USER, IP or RANGE.
-        */
-       private $type;
-
-       /** @var User */
-       private $blocker;
-
        /** @var bool */
        private $isHardblock;
 
        /** @var bool */
        private $isAutoblocking;
 
-       /** @var string|null */
-       private $systemBlockType;
-
-       /** @var bool */
-       private $isSitewide;
-
        /** @var Restriction[] */
        private $restrictions;
 
-       # TYPE constants
-       const TYPE_USER = 1;
-       const TYPE_IP = 2;
-       const TYPE_RANGE = 3;
-       const TYPE_AUTO = 4;
-       const TYPE_ID = 5;
-
        /**
-        * Create a new block with specified parameters on a user, IP or IP range.
+        * Create a new block with specified option parameters on a user, IP or IP range.
         *
         * @param array $options Parameters of the block:
-        *     address string|User  Target user name, User object, IP address or IP range
         *     user int             Override target user ID (for foreign users)
-        *     by int               User ID of the blocker
-        *     reason string        Reason of the block
-        *     timestamp string     The time at which the block comes into effect
         *     auto bool            Is this an automatic block?
         *     expiry string        Timestamp of expiration of the block or 'infinity'
         *     anonOnly bool        Only disallow anonymous actions
@@ -116,25 +73,17 @@ class Block {
         *     hideName bool        Hide the target user name
         *     blockEmail bool      Disallow sending emails
         *     allowUsertalk bool   Allow the target to edit its own talk page
-        *     byText string        Username of the blocker (for foreign users)
-        *     systemBlock string   Indicate that this block is automatically
-        *                          created by MediaWiki rather than being stored
-        *                          in the database. Value is a string to return
-        *                          from self::getSystemBlockType().
         *     sitewide bool        Disallow editing all pages and all contribution
         *                          actions, except those specifically allowed by
         *                          other block flags
         *
-        * @since 1.26 accepts $options array instead of individual parameters; order
-        * of parameters above reflects the original order
+        * @since 1.26 $options array
         */
-       function __construct( $options = [] ) {
+       public function __construct( array $options = [] ) {
+               parent::__construct( $options );
+
                $defaults = [
-                       'address'         => '',
                        'user'            => null,
-                       'by'              => null,
-                       'reason'          => '',
-                       'timestamp'       => '',
                        'auto'            => false,
                        'expiry'          => '',
                        'anonOnly'        => false,
@@ -143,43 +92,21 @@ class Block {
                        'hideName'        => false,
                        'blockEmail'      => false,
                        'allowUsertalk'   => false,
-                       'byText'          => '',
-                       'systemBlock'     => null,
                        'sitewide'        => true,
                ];
 
-               if ( func_num_args() > 1 || !is_array( $options ) ) {
-                       $options = array_combine(
-                               array_slice( array_keys( $defaults ), 0, func_num_args() ),
-                               func_get_args()
-                       );
-                       wfDeprecated( __METHOD__ . ' with multiple arguments', '1.26' );
-               }
-
                $options += $defaults;
 
-               $this->setTarget( $options['address'] );
-
                if ( $this->target instanceof User && $options['user'] ) {
                        # Needed for foreign users
                        $this->forcedTargetID = $options['user'];
                }
 
-               if ( $options['by'] ) {
-                       # Local user
-                       $this->setBlocker( User::newFromId( $options['by'] ) );
-               } else {
-                       # Foreign user
-                       $this->setBlocker( $options['byText'] );
-               }
-
-               $this->mReason = $options['reason'];
-               $this->mTimestamp = wfTimestamp( TS_MW, $options['timestamp'] );
-               $this->mExpiry = wfGetDB( DB_REPLICA )->decodeExpiry( $options['expiry'] );
+               $this->setExpiry( wfGetDB( DB_REPLICA )->decodeExpiry( $options['expiry'] ) );
 
                # Boolean settings
                $this->mAuto = (bool)$options['auto'];
-               $this->mHideName = (bool)$options['hideName'];
+               $this->setHideName( (bool)$options['hideName'] );
                $this->isHardblock( !$options['anonOnly'] );
                $this->isAutoblocking( (bool)$options['enableAutoblock'] );
                $this->isSitewide( (bool)$options['sitewide'] );
@@ -188,7 +115,6 @@ class Block {
                $this->isUsertalkEditAllowed( (bool)$options['allowUsertalk'] );
 
                $this->mFromMaster = false;
-               $this->systemBlockType = $options['systemBlock'];
        }
 
        /**
@@ -304,16 +230,18 @@ class Block {
                        && $this->mAuto == $block->mAuto
                        && $this->isHardblock() == $block->isHardblock()
                        && $this->isCreateAccountBlocked() == $block->isCreateAccountBlocked()
-                       && $this->mExpiry == $block->mExpiry
+                       && $this->getExpiry() == $block->getExpiry()
                        && $this->isAutoblocking() == $block->isAutoblocking()
-                       && $this->mHideName == $block->mHideName
+                       && $this->getHideName() == $block->getHideName()
                        && $this->isEmailBlocked() == $block->isEmailBlocked()
                        && $this->isUsertalkEditAllowed() == $block->isUsertalkEditAllowed()
-                       && $this->mReason == $block->mReason
+                       && $this->getReason() == $block->getReason()
                        && $this->isSitewide() == $block->isSitewide()
                        // Block::getRestrictions() may perform a database query, so keep it at
                        // the end.
-                       && BlockRestriction::equals( $this->getRestrictions(), $block->getRestrictions() )
+                       && $this->getBlockRestrictionStore()->equals(
+                               $this->getRestrictions(), $block->getRestrictions()
+                       )
                );
        }
 
@@ -394,13 +322,13 @@ class Block {
                        if ( $block->getType() == self::TYPE_RANGE ) {
                                # This is the number of bits that are allowed to vary in the block, give
                                # or take some floating point errors
-                               $end = Wikimedia\base_convert( $block->getRangeEnd(), 16, 10 );
-                               $start = Wikimedia\base_convert( $block->getRangeStart(), 16, 10 );
-                               $size = log( $end - $start + 1, 2 );
+                               $target = $block->getTarget();
+                               $max = IP::isIPv6( $target ) ? 128 : 32;
+                               list( $network, $bits ) = IP::parseCIDR( $target );
+                               $size = $max - $bits;
 
-                               # This has the nice property that a /32 block is ranked equally with a
-                               # single-IP block, which is exactly what it is...
-                               $score = self::TYPE_RANGE - 1 + ( $size / 128 );
+                               # Rank a range block covering a single IP equally with a single-IP block
+                               $score = self::TYPE_RANGE - 1 + ( $size / $max );
 
                        } else {
                                $score = $block->getType();
@@ -479,18 +407,20 @@ class Block {
                        $row->ipb_by, $row->ipb_by_text, $row->ipb_by_actor ?? null
                ) );
 
-               $this->mTimestamp = wfTimestamp( TS_MW, $row->ipb_timestamp );
+               $this->setTimestamp( wfTimestamp( TS_MW, $row->ipb_timestamp ) );
                $this->mAuto = $row->ipb_auto;
-               $this->mHideName = $row->ipb_deleted;
+               $this->setHideName( $row->ipb_deleted );
                $this->mId = (int)$row->ipb_id;
                $this->mParentBlockId = $row->ipb_parent_block_id;
 
                // I wish I didn't have to do this
                $db = wfGetDB( DB_REPLICA );
-               $this->mExpiry = $db->decodeExpiry( $row->ipb_expiry );
-               $this->mReason = CommentStore::getStore()
+               $this->setExpiry( $db->decodeExpiry( $row->ipb_expiry ) );
+               $this->setReason(
+                       CommentStore::getStore()
                        // Legacy because $row may have come from self::selectFields()
-                       ->getCommentLegacy( $db, 'ipb_reason', $row )->text;
+                       ->getCommentLegacy( $db, 'ipb_reason', $row )->text
+               );
 
                $this->isHardblock( !$row->ipb_anon_only );
                $this->isAutoblocking( $row->ipb_enable_autoblock );
@@ -529,10 +459,10 @@ class Block {
 
                $dbw = wfGetDB( DB_MASTER );
 
-               BlockRestriction::deleteByParentBlockId( $this->getId() );
+               $this->getBlockRestrictionStore()->deleteByParentBlockId( $this->getId() );
                $dbw->delete( 'ipblocks', [ 'ipb_parent_block_id' => $this->getId() ], __METHOD__ );
 
-               BlockRestriction::deleteByBlockId( $this->getId() );
+               $this->getBlockRestrictionStore()->deleteByBlockId( $this->getId() );
                $dbw->delete( 'ipblocks', [ 'ipb_id' => $this->getId() ], __METHOD__ );
 
                return $dbw->affectedRows() > 0;
@@ -549,9 +479,6 @@ class Block {
        public function insert( $dbw = null ) {
                global $wgBlockDisablesLogin;
 
-               if ( $this->getSystemBlockType() !== null ) {
-                       throw new MWException( 'Cannot insert a system block into the database' );
-               }
                if ( !$this->getBlocker() || $this->getBlocker()->getName() === '' ) {
                        throw new MWException( 'Cannot insert a block without a blocker set' );
                }
@@ -571,7 +498,7 @@ class Block {
                if ( $affected ) {
                        $this->setId( $dbw->insertId() );
                        if ( $this->restrictions ) {
-                               BlockRestriction::insert( $this->restrictions );
+                               $this->getBlockRestrictionStore()->insert( $this->restrictions );
                        }
                }
 
@@ -591,12 +518,12 @@ class Block {
                        );
                        if ( $ids ) {
                                $dbw->delete( 'ipblocks', [ 'ipb_id' => $ids ], __METHOD__ );
-                               BlockRestriction::deleteByBlockId( $ids );
+                               $this->getBlockRestrictionStore()->deleteByBlockId( $ids );
                                $dbw->insert( 'ipblocks', $row, __METHOD__, [ 'IGNORE' ] );
                                $affected = $dbw->affectedRows();
                                $this->setId( $dbw->insertId() );
                                if ( $this->restrictions ) {
-                                       BlockRestriction::insert( $this->restrictions );
+                                       $this->getBlockRestrictionStore()->insert( $this->restrictions );
                                }
                        }
                }
@@ -640,9 +567,9 @@ class Block {
                if ( $this->restrictions !== null ) {
                        // An empty array should remove all of the restrictions.
                        if ( empty( $this->restrictions ) ) {
-                               $success = BlockRestriction::deleteByBlockId( $this->getId() );
+                               $success = $this->getBlockRestrictionStore()->deleteByBlockId( $this->getId() );
                        } else {
-                               $success = BlockRestriction::update( $this->restrictions );
+                               $success = $this->getBlockRestrictionStore()->update( $this->restrictions );
                        }
                        // Update the result. The first false is the result, otherwise, true.
                        $result = $result && $success;
@@ -659,11 +586,11 @@ class Block {
 
                        // Only update the restrictions if they have been modified.
                        if ( $this->restrictions !== null ) {
-                               BlockRestriction::updateByParentBlockId( $this->getId(), $this->restrictions );
+                               $this->getBlockRestrictionStore()->updateByParentBlockId( $this->getId(), $this->restrictions );
                        }
                } else {
                        // autoblock no longer required, delete corresponding autoblock(s)
-                       BlockRestriction::deleteByParentBlockId( $this->getId() );
+                       $this->getBlockRestrictionStore()->deleteByParentBlockId( $this->getId() );
                        $dbw->delete(
                                'ipblocks',
                                [ 'ipb_parent_block_id' => $this->getId() ],
@@ -687,7 +614,7 @@ class Block {
         * @return array
         */
        protected function getDatabaseArray( IDatabase $dbw ) {
-               $expiry = $dbw->encodeExpiry( $this->mExpiry );
+               $expiry = $dbw->encodeExpiry( $this->getExpiry() );
 
                if ( $this->forcedTargetID ) {
                        $uid = $this->forcedTargetID;
@@ -698,7 +625,7 @@ class Block {
                $a = [
                        'ipb_address'          => (string)$this->target,
                        'ipb_user'             => $uid,
-                       'ipb_timestamp'        => $dbw->timestamp( $this->mTimestamp ),
+                       'ipb_timestamp'        => $dbw->timestamp( $this->getTimestamp() ),
                        'ipb_auto'             => $this->mAuto,
                        'ipb_anon_only'        => !$this->isHardblock(),
                        'ipb_create_account'   => $this->isCreateAccountBlocked(),
@@ -706,12 +633,12 @@ class Block {
                        'ipb_expiry'           => $expiry,
                        'ipb_range_start'      => $this->getRangeStart(),
                        'ipb_range_end'        => $this->getRangeEnd(),
-                       'ipb_deleted'          => intval( $this->mHideName ), // typecast required for SQLite
+                       'ipb_deleted'          => intval( $this->getHideName() ), // typecast required for SQLite
                        'ipb_block_email'      => $this->isEmailBlocked(),
                        'ipb_allow_usertalk'   => $this->isUsertalkEditAllowed(),
                        'ipb_parent_block_id'  => $this->mParentBlockId,
                        'ipb_sitewide'         => $this->isSitewide(),
-               ] + CommentStore::getStore()->insert( $dbw, 'ipb_reason', $this->mReason )
+               ] + CommentStore::getStore()->insert( $dbw, 'ipb_reason', $this->getReason() )
                        + ActorMigration::newMigration()->getInsertValues( $dbw, 'ipb_by', $this->getBlocker() );
 
                return $a;
@@ -724,10 +651,10 @@ class Block {
        protected function getAutoblockUpdateArray( IDatabase $dbw ) {
                return [
                        'ipb_create_account'   => $this->isCreateAccountBlocked(),
-                       'ipb_deleted'          => (int)$this->mHideName, // typecast required for SQLite
+                       'ipb_deleted'          => (int)$this->getHideName(), // typecast required for SQLite
                        'ipb_allow_usertalk'   => $this->isUsertalkEditAllowed(),
                        'ipb_sitewide'         => $this->isSitewide(),
-               ] + CommentStore::getStore()->insert( $dbw, 'ipb_reason', $this->mReason )
+               ] + CommentStore::getStore()->insert( $dbw, 'ipb_reason', $this->getReason() )
                        + ActorMigration::newMigration()->getInsertValues( $dbw, 'ipb_by', $this->getBlocker() );
        }
 
@@ -865,11 +792,6 @@ class Block {
                        return false;
                }
 
-               # Don't autoblock for system blocks
-               if ( $this->getSystemBlockType() !== null ) {
-                       throw new MWException( 'Cannot autoblock from a system block' );
-               }
-
                # Check for presence on the autoblock whitelist.
                if ( self::isWhitelistedFromAutoblocks( $autoblockIP ) ) {
                        return false;
@@ -891,7 +813,7 @@ class Block {
                        # Check if the block is an autoblock and would exceed the user block
                        # if renewed. If so, do nothing, otherwise prolong the block time...
                        if ( $ipblock->mAuto && // @todo Why not compare $ipblock->mExpiry?
-                               $this->mExpiry > self::getAutoblockExpiry( $ipblock->mTimestamp )
+                               $this->getExpiry() > self::getAutoblockExpiry( $ipblock->getTimestamp() )
                        ) {
                                # Reset block timestamp to now and its expiry to
                                # $wgAutoblockExpiry in the future
@@ -905,26 +827,28 @@ class Block {
                wfDebug( "Autoblocking {$this->getTarget()}@" . $autoblockIP . "\n" );
                $autoblock->setTarget( $autoblockIP );
                $autoblock->setBlocker( $this->getBlocker() );
-               $autoblock->mReason = wfMessage( 'autoblocker', $this->getTarget(), $this->mReason )
-                       ->inContentLanguage()->plain();
+               $autoblock->setReason(
+                       wfMessage( 'autoblocker', $this->getTarget(), $this->getReason() )
+                               ->inContentLanguage()->plain()
+               );
                $timestamp = wfTimestampNow();
-               $autoblock->mTimestamp = $timestamp;
+               $autoblock->setTimestamp( $timestamp );
                $autoblock->mAuto = 1;
                $autoblock->isCreateAccountBlocked( $this->isCreateAccountBlocked() );
                # Continue suppressing the name if needed
-               $autoblock->mHideName = $this->mHideName;
+               $autoblock->setHideName( $this->getHideName() );
                $autoblock->isUsertalkEditAllowed( $this->isUsertalkEditAllowed() );
                $autoblock->mParentBlockId = $this->mId;
                $autoblock->isSitewide( $this->isSitewide() );
                $autoblock->setRestrictions( $this->getRestrictions() );
 
-               if ( $this->mExpiry == 'infinity' ) {
+               if ( $this->getExpiry() == 'infinity' ) {
                        # Original block was indefinite, start an autoblock now
-                       $autoblock->mExpiry = self::getAutoblockExpiry( $timestamp );
+                       $autoblock->setExpiry( self::getAutoblockExpiry( $timestamp ) );
                } else {
                        # If the user is already blocked with an expiry date, we don't
                        # want to pile on top of that.
-                       $autoblock->mExpiry = min( $this->mExpiry, self::getAutoblockExpiry( $timestamp ) );
+                       $autoblock->setExpiry( min( $this->getExpiry(), self::getAutoblockExpiry( $timestamp ) ) );
                }
 
                # Insert the block...
@@ -959,18 +883,21 @@ class Block {
                $timestamp = wfTimestampNow();
                wfDebug( "Block::isExpired() checking current " . $timestamp . " vs $this->mExpiry\n" );
 
-               if ( !$this->mExpiry ) {
+               if ( !$this->getExpiry() ) {
                        return false;
                } else {
-                       return $timestamp > $this->mExpiry;
+                       return $timestamp > $this->getExpiry();
                }
        }
 
        /**
         * Is the block address valid (i.e. not a null string?)
+        *
+        * @deprecated since 1.33 No longer needed in core.
         * @return bool
         */
        public function isValid() {
+               wfDeprecated( __METHOD__, '1.33' );
                return $this->getTarget() != null;
        }
 
@@ -979,14 +906,14 @@ class Block {
         */
        public function updateTimestamp() {
                if ( $this->mAuto ) {
-                       $this->mTimestamp = wfTimestamp();
-                       $this->mExpiry = self::getAutoblockExpiry( $this->mTimestamp );
+                       $this->setTimestamp( wfTimestamp() );
+                       $this->setExpiry( self::getAutoblockExpiry( $this->getTimestamp() ) );
 
                        $dbw = wfGetDB( DB_MASTER );
                        $dbw->update( 'ipblocks',
                                [ /* SET */
-                                       'ipb_timestamp' => $dbw->timestamp( $this->mTimestamp ),
-                                       'ipb_expiry' => $dbw->timestamp( $this->mExpiry ),
+                                       'ipb_timestamp' => $dbw->timestamp( $this->getTimestamp() ),
+                                       'ipb_expiry' => $dbw->timestamp( $this->getExpiry() ),
                                ],
                                [ /* WHERE */
                                        'ipb_id' => $this->getId(),
@@ -1035,32 +962,7 @@ class Block {
        }
 
        /**
-        * Get the user id of the blocking sysop
-        *
-        * @return int (0 for foreign users)
-        */
-       public function getBy() {
-               $blocker = $this->getBlocker();
-               return ( $blocker instanceof User )
-                       ? $blocker->getId()
-                       : 0;
-       }
-
-       /**
-        * Get the username of the blocking sysop
-        *
-        * @return string
-        */
-       public function getByName() {
-               $blocker = $this->getBlocker();
-               return ( $blocker instanceof User )
-                       ? $blocker->getName()
-                       : (string)$blocker; // username
-       }
-
-       /**
-        * Get the block ID
-        * @return int
+        * @inheritDoc
         */
        public function getId() {
                return $this->mId;
@@ -1076,21 +978,14 @@ class Block {
                $this->mId = (int)$blockId;
 
                if ( is_array( $this->restrictions ) ) {
-                       $this->restrictions = BlockRestriction::setBlockId( $blockId, $this->restrictions );
+                       $this->restrictions = $this->getBlockRestrictionStore()->setBlockId(
+                               $blockId, $this->restrictions
+                       );
                }
 
                return $this;
        }
 
-       /**
-        * Get the system block type, if any
-        * @since 1.29
-        * @return string|null
-        */
-       public function getSystemBlockType() {
-               return $this->systemBlockType;
-       }
-
        /**
         * Get/set a flag determining whether the master is used for reads
         *
@@ -1129,165 +1024,6 @@ class Block {
                        : false;
        }
 
-       /**
-        * Indicates that the block is a sitewide block. This means the user is
-        * prohibited from editing any page on the site (other than their own talk
-        * page).
-        *
-        * @since 1.33
-        * @param null|bool $x
-        * @return bool
-        */
-       public function isSitewide( $x = null ) {
-               return wfSetVar( $this->isSitewide, $x );
-       }
-
-       /**
-        * Get or set the flag indicating whether this block blocks the target from
-        * creating an account. (Note that the flag may be overridden depending on
-        * global configs.)
-        *
-        * @since 1.33
-        * @param null|bool $x Value to set (if null, just get the property value)
-        * @return bool Value of the property
-        */
-       public function isCreateAccountBlocked( $x = null ) {
-               return wfSetVar( $this->blockCreateAccount, $x );
-       }
-
-       /**
-        * Get or set the flag indicating whether this block blocks the target from
-        * sending emails. (Note that the flag may be overridden depending on
-        * global configs.)
-        *
-        * @since 1.33
-        * @param null|bool $x Value to set (if null, just get the property value)
-        * @return bool Value of the property
-        */
-       public function isEmailBlocked( $x = null ) {
-               return wfSetVar( $this->mBlockEmail, $x );
-       }
-
-       /**
-        * Get or set the flag indicating whether this block blocks the target from
-        * editing their own user talk page. (Note that the flag may be overridden
-        * depending on global configs.)
-        *
-        * @since 1.33
-        * @param null|bool $x Value to set (if null, just get the property value)
-        * @return bool Value of the property
-        */
-       public function isUsertalkEditAllowed( $x = null ) {
-               return wfSetVar( $this->allowUsertalk, $x );
-       }
-
-       /**
-        * Determine whether the Block prevents a given right. A right
-        * may be blacklisted or whitelisted, or determined from a
-        * property on the Block object. For certain rights, the property
-        * may be overridden according to global configs.
-        *
-        * @since 1.33
-        * @param string $right Right to check
-        * @return bool|null null if unrecognized right or unset property
-        */
-       public function appliesToRight( $right ) {
-               $config = RequestContext::getMain()->getConfig();
-               $blockDisablesLogin = $config->get( 'BlockDisablesLogin' );
-
-               $res = null;
-               switch ( $right ) {
-                       case 'edit':
-                               // TODO: fix this case to return proper value
-                               $res = true;
-                               break;
-                       case 'createaccount':
-                               $res = $this->isCreateAccountBlocked();
-                               break;
-                       case 'sendemail':
-                               $res = $this->isEmailBlocked();
-                               break;
-                       case 'upload':
-                               // Until T6995 is completed
-                               $res = $this->isSitewide();
-                               break;
-                       case 'read':
-                               $res = false;
-                               break;
-                       case 'purge':
-                               $res = false;
-                               break;
-               }
-               if ( !$res && $blockDisablesLogin ) {
-                       // If a block would disable login, then it should
-                       // prevent any right that all users cannot do
-                       $anon = new User;
-                       $res = $anon->isAllowed( $right ) ? $res : true;
-               }
-
-               return $res;
-       }
-
-       /**
-        * Get/set whether the Block prevents a given action
-        *
-        * @deprecated since 1.33, use appliesToRight to determine block
-        *  behaviour, and specific methods to get/set properties
-        * @param string $action Action to check
-        * @param bool|null $x Value for set, or null to just get value
-        * @return bool|null Null for unrecognized rights.
-        */
-       public function prevents( $action, $x = null ) {
-               $config = RequestContext::getMain()->getConfig();
-               $blockDisablesLogin = $config->get( 'BlockDisablesLogin' );
-               $blockAllowsUTEdit = $config->get( 'BlockAllowsUTEdit' );
-
-               $res = null;
-               switch ( $action ) {
-                       case 'edit':
-                               # For now... <evil laugh>
-                               $res = true;
-                               break;
-                       case 'createaccount':
-                               $res = wfSetVar( $this->blockCreateAccount, $x );
-                               break;
-                       case 'sendemail':
-                               $res = wfSetVar( $this->mBlockEmail, $x );
-                               break;
-                       case 'upload':
-                               // Until T6995 is completed
-                               $res = $this->isSitewide();
-                               break;
-                       case 'editownusertalk':
-                               // NOTE: this check is not reliable on partial blocks
-                               // since partially blocked users are always allowed to edit
-                               // their own talk page unless a restriction exists on the
-                               // page or User_talk: namespace
-                               wfSetVar( $this->allowUsertalk, $x === null ? null : !$x );
-                               $res = !$this->isUserTalkEditAllowed();
-
-                               // edit own user talk can be disabled by config
-                               if ( !$blockAllowsUTEdit ) {
-                                       $res = true;
-                               }
-                               break;
-                       case 'read':
-                               $res = false;
-                               break;
-                       case 'purge':
-                               $res = false;
-                               break;
-               }
-               if ( !$res && $blockDisablesLogin ) {
-                       // If a block would disable login, then it should
-                       // prevent any action that all users cannot do
-                       $anon = new User;
-                       $res = $anon->isAllowed( $action ) ? $res : true;
-               }
-
-               return $res;
-       }
-
        /**
         * Get the block name, but with autoblocked IPs hidden as per standard privacy policy
         * @return string Text is escaped
@@ -1334,7 +1070,9 @@ class Block {
                                        $fname
                                );
                                if ( $ids ) {
-                                       BlockRestriction::deleteByBlockId( $ids );
+                                       $blockRestrictionStore = MediaWikiServices::getInstance()->getBlockRestrictionStore();
+                                       $blockRestrictionStore->deleteByBlockId( $ids );
+
                                        $dbw->delete( 'ipblocks', [ 'ipb_id' => $ids ], $fname );
                                }
                        }
@@ -1575,139 +1313,15 @@ class Block {
        }
 
        /**
-        * From an existing Block, get the target and the type of target.
-        * Note that, except for null, it is always safe to treat the target
-        * as a string; for User objects this will return User::__toString()
-        * which in turn gives User::getName().
+        * @inheritDoc
         *
-        * @param string|int|User|null $target
-        * @return array [ User|String|null, Block::TYPE_ constant|null ]
-        */
-       public static function parseTarget( $target ) {
-               # We may have been through this before
-               if ( $target instanceof User ) {
-                       if ( IP::isValid( $target->getName() ) ) {
-                               return [ $target, self::TYPE_IP ];
-                       } else {
-                               return [ $target, self::TYPE_USER ];
-                       }
-               } elseif ( $target === null ) {
-                       return [ null, null ];
-               }
-
-               $target = trim( $target );
-
-               if ( IP::isValid( $target ) ) {
-                       # We can still create a User if it's an IP address, but we need to turn
-                       # off validation checking (which would exclude IP addresses)
-                       return [
-                               User::newFromName( IP::sanitizeIP( $target ), false ),
-                               self::TYPE_IP
-                       ];
-
-               } elseif ( IP::isValidRange( $target ) ) {
-                       # Can't create a User from an IP range
-                       return [ IP::sanitizeRange( $target ), self::TYPE_RANGE ];
-               }
-
-               # Consider the possibility that this is not a username at all
-               # but actually an old subpage (T31797)
-               if ( strpos( $target, '/' ) !== false ) {
-                       # An old subpage, drill down to the user behind it
-                       $target = explode( '/', $target )[0];
-               }
-
-               $userObj = User::newFromName( $target );
-               if ( $userObj instanceof User ) {
-                       # Note that since numbers are valid usernames, a $target of "12345" will be
-                       # considered a User.  If you want to pass a block ID, prepend a hash "#12345",
-                       # since hash characters are not valid in usernames or titles generally.
-                       return [ $userObj, self::TYPE_USER ];
-
-               } elseif ( preg_match( '/^#\d+$/', $target ) ) {
-                       # Autoblock reference in the form "#12345"
-                       return [ substr( $target, 1 ), self::TYPE_AUTO ];
-
-               } else {
-                       # WTF?
-                       return [ null, null ];
-               }
-       }
-
-       /**
-        * Get the type of target for this particular block. Autoblocks have whichever type
-        * corresponds to their target, so to detect if a block is an autoblock, we have to
-        * check the mAuto property instead.
-        * @return int Block::TYPE_ constant, will never be TYPE_ID
+        * Autoblocks have whichever type corresponds to their target, so to detect if a block is an
+        * autoblock, we have to check the mAuto property instead.
         */
        public function getType() {
                return $this->mAuto
                        ? self::TYPE_AUTO
-                       : $this->type;
-       }
-
-       /**
-        * Get the target and target type for this particular Block.  Note that for autoblocks,
-        * this returns the unredacted name; frontend functions need to call $block->getRedactedName()
-        * in this situation.
-        * @return array [ User|String, Block::TYPE_ constant ]
-        * @todo FIXME: This should be an integral part of the Block member variables
-        */
-       public function getTargetAndType() {
-               return [ $this->getTarget(), $this->getType() ];
-       }
-
-       /**
-        * Get the target for this particular Block.  Note that for autoblocks,
-        * this returns the unredacted name; frontend functions need to call $block->getRedactedName()
-        * in this situation.
-        * @return User|string
-        */
-       public function getTarget() {
-               return $this->target;
-       }
-
-       /**
-        * @since 1.19
-        *
-        * @return mixed|string
-        */
-       public function getExpiry() {
-               return $this->mExpiry;
-       }
-
-       /**
-        * Set the target for this block, and update $this->type accordingly
-        * @param mixed $target
-        */
-       public function setTarget( $target ) {
-               list( $this->target, $this->type ) = self::parseTarget( $target );
-       }
-
-       /**
-        * Get the user who implemented this block
-        * @return User User object. May name a foreign user.
-        */
-       public function getBlocker() {
-               return $this->blocker;
-       }
-
-       /**
-        * Set the user who implemented (or will implement) this block
-        * @param User|string $user Local User object or username string
-        */
-       public function setBlocker( $user ) {
-               if ( is_string( $user ) ) {
-                       $user = User::newFromName( $user, false );
-               }
-
-               if ( $user->isAnon() && User::isUsableName( $user->getName() ) ) {
-                       throw new InvalidArgumentException(
-                               'Blocker must be a local user or a name that cannot be a local user'
-                       );
-               }
-
-               $this->blocker = $user;
+                       : parent::getType();
        }
 
        /**
@@ -1799,19 +1413,15 @@ class Block {
        }
 
        /**
-        * Get the key and parameters for the corresponding error message.
+        * @inheritDoc
         *
-        * @since 1.22
-        * @param IContextSource $context
-        * @return array
+        * Build different messages for autoblocks and partial blocks.
         */
        public function getPermissionsError( IContextSource $context ) {
                $params = $this->getBlockErrorParams( $context );
 
                $msg = 'blockedtext';
-               if ( $this->getSystemBlockType() !== null ) {
-                       $msg = 'systemblockedtext';
-               } elseif ( $this->mAuto ) {
+               if ( $this->mAuto ) {
                        $msg = 'autoblockedtext';
                } elseif ( !$this->isSitewide() ) {
                        $msg = 'blockedtext-partial';
@@ -1822,45 +1432,6 @@ class Block {
                return $params;
        }
 
-       /**
-        * Get block information used in different block error messages
-        *
-        * @since 1.33
-        * @param IContextSource $context
-        * @return array
-        */
-       public function getBlockErrorParams( IContextSource $context ) {
-               $blocker = $this->getBlocker();
-               if ( $blocker instanceof User ) { // local user
-                       $blockerUserpage = $blocker->getUserPage();
-                       $link = "[[{$blockerUserpage->getPrefixedText()}|{$blockerUserpage->getText()}]]";
-               } else { // foreign user
-                       $link = $blocker;
-               }
-
-               $reason = $this->mReason;
-               if ( $reason == '' ) {
-                       $reason = $context->msg( 'blockednoreason' )->text();
-               }
-
-               /* $ip returns who *is* being blocked, $intended contains who was meant to be blocked.
-                * This could be a username, an IP range, or a single IP. */
-               $intended = $this->getTarget();
-               $systemBlockType = $this->getSystemBlockType();
-               $lang = $context->getLanguage();
-
-               return [
-                       $link,
-                       $reason,
-                       $context->getRequest()->getIP(),
-                       $this->getByName(),
-                       $systemBlockType ?? $this->getId(),
-                       $lang->formatExpiry( $this->mExpiry ),
-                       (string)$intended,
-                       $lang->userTimeAndDate( $this->mTimestamp, $context->getUser() ),
-               ];
-       }
-
        /**
         * Get Restrictions.
         *
@@ -1877,7 +1448,7 @@ class Block {
                        if ( !$this->mId ) {
                                return [];
                        }
-                       $this->restrictions = BlockRestriction::loadByBlockId( $this->mId );
+                       $this->restrictions = $this->getBlockRestrictionStore()->loadByBlockId( $this->mId );
                }
 
                return $this->restrictions;
@@ -1899,76 +1470,7 @@ class Block {
        }
 
        /**
-        * Determine whether the block allows the user to edit their own
-        * user talk page. This is done separately from Block::appliesToRight
-        * because there is no right for editing one's own user talk page
-        * and because the user's talk page needs to be passed into the
-        * Block object, which is unaware of the user.
-        *
-        * The ipb_allow_usertalk flag (which corresponds to the property
-        * allowUsertalk) is used on sitewide blocks and partial blocks
-        * that contain a namespace restriction on the user talk namespace,
-        * but do not contain a page restriction on the user's talk page.
-        * For all other (i.e. most) partial blocks, the flag is ignored,
-        * and the user can always edit their user talk page unless there
-        * is a page restriction on their user talk page, in which case
-        * they can never edit it. (Ideally the flag would be stored as
-        * null in these cases, but the database field isn't nullable.)
-        *
-        * This method does not validate that the passed in talk page belongs to the
-        * block target since the target (an IP) might not be the same as the user's
-        * talk page (if they are logged in).
-        *
-        * @since 1.33
-        * @param Title|null $usertalk The user's user talk page. If null,
-        *  and if the target is a User, the target's userpage is used
-        * @return bool The user can edit their talk page
-        */
-       public function appliesToUsertalk( Title $usertalk = null ) {
-               if ( !$usertalk ) {
-                       if ( $this->target instanceof User ) {
-                               $usertalk = $this->target->getTalkPage();
-                       } else {
-                               throw new InvalidArgumentException(
-                                       '$usertalk must be provided if block target is not a user/IP'
-                               );
-                       }
-               }
-
-               if ( $usertalk->getNamespace() !== NS_USER_TALK ) {
-                       throw new InvalidArgumentException(
-                               '$usertalk must be a user talk page'
-                       );
-               }
-
-               if ( !$this->isSitewide() ) {
-                       if ( $this->appliesToPage( $usertalk->getArticleID() ) ) {
-                               return true;
-                       }
-                       if ( !$this->appliesToNamespace( NS_USER_TALK ) ) {
-                               return false;
-                       }
-               }
-
-               // This is a type of block which uses the ipb_allow_usertalk
-               // flag. The flag can still be overridden by global configs.
-               $config = RequestContext::getMain()->getConfig();
-               if ( !$config->get( 'BlockAllowsUTEdit' ) ) {
-                       return true;
-               }
-               return !$this->isUsertalkEditAllowed();
-       }
-
-       /**
-        * Checks if a block applies to a particular title
-        *
-        * This check does not consider whether `$this->isUsertalkEditAllowed`
-        * returns false, as the identity of the user making the hypothetical edit
-        * isn't known here (particularly in the case of IP hardblocks, range
-        * blocks, and auto-blocks).
-        *
-        * @param Title $title
-        * @return bool
+        * @inheritDoc
         */
        public function appliesToTitle( Title $title ) {
                if ( $this->isSitewide() ) {
@@ -1986,12 +1488,7 @@ class Block {
        }
 
        /**
-        * Checks if a block applies to a particular namespace
-        *
-        * @since 1.33
-        *
-        * @param int $ns
-        * @return bool
+        * @inheritDoc
         */
        public function appliesToNamespace( $ns ) {
                if ( $this->isSitewide() ) {
@@ -2009,17 +1506,7 @@ class Block {
        }
 
        /**
-        * Checks if a block applies to a particular page
-        *
-        * This check does not consider whether `$this->isUsertalkEditAllowed`
-        * returns false, as the identity of the user making the hypothetical edit
-        * isn't known here (particularly in the case of IP hardblocks, range
-        * blocks, and auto-blocks).
-        *
-        * @since 1.33
-        *
-        * @param int $pageId
-        * @return bool
+        * @inheritDoc
         */
        public function appliesToPage( $pageId ) {
                if ( $this->isSitewide() ) {
@@ -2057,4 +1544,29 @@ class Block {
 
                return null;
        }
+
+       /**
+        * @inheritDoc
+        */
+       public function shouldTrackWithCookie( $isAnon ) {
+               $config = RequestContext::getMain()->getConfig();
+               switch ( $this->getType() ) {
+                       case self::TYPE_IP:
+                       case self::TYPE_RANGE:
+                               return $isAnon && $config->get( 'CookieSetOnIpBlock' );
+                       case self::TYPE_USER:
+                               return !$isAnon && $config->get( 'CookieSetOnAutoblock' ) && $this->isAutoblocking();
+                       default:
+                               return false;
+               }
+       }
+
+       /**
+        * Get a BlockRestrictionStore instance
+        *
+        * @return BlockRestrictionStore
+        */
+       private function getBlockRestrictionStore() : BlockRestrictionStore {
+               return MediaWikiServices::getInstance()->getBlockRestrictionStore();
+       }
 }
index 3352c2c..34ac0e1 100644 (file)
@@ -25,8 +25,6 @@
  * Category objects are immutable, strictly speaking. If you call methods that change the database,
  * like to refresh link counts, the objects will be appropriately reinitialized.
  * Member variables are lazy-initialized.
- *
- * @todo Move some stuff from CategoryPage.php to here, and use that.
  */
 class Category {
        /** Name of the category, normalized to DB-key form */
@@ -43,6 +41,8 @@ class Category {
        const LOAD_ONLY = 0;
        const LAZY_INIT_ROW = 1;
 
+       const ROW_COUNT_SMALL = 100;
+
        private function __construct() {
        }
 
@@ -299,10 +299,10 @@ class Category {
        /**
         * Generic accessor
         * @param string $key
-        * @return bool
+        * @return mixed
         */
        private function getX( $key ) {
-               if ( !$this->initialize( self::LAZY_INIT_ROW ) ) {
+               if ( $this->{$key} === null && !$this->initialize( self::LAZY_INIT_ROW ) ) {
                        return false;
                }
                return $this->{$key};
@@ -433,28 +433,57 @@ class Category {
         * @since 1.32
         */
        public function refreshCountsIfEmpty() {
+               return $this->refreshCountsIfSmall( 0 );
+       }
+
+       /**
+        * Call refreshCounts() if there are few entries in the categorylinks table
+        *
+        * Due to lock errors or other failures, the precomputed counts can get out of sync,
+        * making it hard to know when to delete the category row without checking the
+        * categorylinks table.
+        *
+        * This method will do a non-locking select first to reduce contention.
+        *
+        * @param int $maxSize Only refresh if there are this or less many backlinks
+        * @return bool Whether links were refreshed
+        * @since 1.34
+        */
+       public function refreshCountsIfSmall( $maxSize = self::ROW_COUNT_SMALL ) {
                $dbw = wfGetDB( DB_MASTER );
+               $dbw->startAtomic( __METHOD__ );
 
-               $hasLink = $dbw->selectField(
+               $typeOccurances = $dbw->selectFieldValues(
                        'categorylinks',
-                       '1',
+                       'cl_type',
                        [ 'cl_to' => $this->getName() ],
-                       __METHOD__
+                       __METHOD__,
+                       [ 'LIMIT' => $maxSize + 1 ]
                );
-               if ( !$hasLink ) {
-                       $this->refreshCounts(); // delete any category table entry
 
-                       return true;
+               if ( !$typeOccurances ) {
+                       $doRefresh = true; // delete any category table entry
+               } elseif ( count( $typeOccurances ) <= $maxSize ) {
+                       $countByType = array_count_values( $typeOccurances );
+                       $doRefresh = !$dbw->selectField(
+                               'category',
+                               '1',
+                               [
+                                       'cat_title' => $this->getName(),
+                                       'cat_pages' => $countByType['page'] ?? 0,
+                                       'cat_subcats' => $countByType['subcat'] ?? 0,
+                                       'cat_files' => $countByType['file'] ?? 0
+                               ],
+                               __METHOD__
+                       );
+               } else {
+                       $doRefresh = false; // category is too big
                }
 
-               $hasBadRow = $dbw->selectField(
-                       'category',
-                       '1',
-                       [ 'cat_title' => $this->getName(), 'cat_pages <= 0' ],
-                       __METHOD__
-               );
-               if ( $hasBadRow ) {
-                       $this->refreshCounts(); // clean up this row
+               $dbw->endAtomic( __METHOD__ );
+
+               if ( $doRefresh ) {
+                       $this->refreshCounts(); // update the row
 
                        return true;
                }
index 1a60bb7..4a673c4 100644 (file)
@@ -202,6 +202,7 @@ class CommentStore {
         *   - fields: (string[]) to include in the `$vars` to `IDatabase->select()`
         *   - joins: (array) to include in the `$join_conds` to `IDatabase->select()`
         *  All tables, fields, and joins are aliased, so `+` is safe to use.
+        * @phan-return array{tables:string[],fields:string[],joins:array}
         */
        public function getJoin( $key = null ) {
                $key = $this->getKey( $key );
index 17c28ec..f8ba5b1 100644 (file)
@@ -7,17 +7,28 @@
  * @since 1.29
  */
 class ConfiguredReadOnlyMode {
-       /** @var Config */
-       private $config;
-
-       /** @var string|bool|null */
-       private $fileReason;
+       /** @var string|boolean|null */
+       private $reason;
 
        /** @var string|null */
-       private $overrideReason;
+       private $reasonFile;
 
-       public function __construct( Config $config ) {
-               $this->config = $config;
+       /**
+        * @param string|bool|null $reason Current reason for read-only mode, if known. null means look
+        *   in $reasonFile instead.
+        * @param string|null $reasonFile A file to look in for a reason, if $reason is null. If it
+        *   exists and is non-empty, its contents are treated as the reason for read-only mode.
+        *   Otherwise, the wiki is not read-only.
+        */
+       public function __construct( $reason, $reasonFile = null ) {
+               if ( $reason instanceof Config ) {
+                       // Before 1.34 we passed a whole Config object, which was overkill
+                       wfDeprecated( __METHOD__ . ' with Config passed to constructor', '1.34' );
+                       $reason = $reason->get( 'ReadOnly' );
+                       $reasonFile = $reason->get( 'ReadOnlyFile' );
+               }
+               $this->reason = $reason;
+               $this->reasonFile = $reasonFile;
        }
 
        /**
@@ -35,23 +46,19 @@ class ConfiguredReadOnlyMode {
         * @return string|bool String when in read-only mode; false otherwise
         */
        public function getReason() {
-               if ( $this->overrideReason !== null ) {
-                       return $this->overrideReason;
+               if ( $this->reason !== null ) {
+                       return $this->reason;
                }
-               $confReason = $this->config->get( 'ReadOnly' );
-               if ( $confReason !== null ) {
-                       return $confReason;
+               if ( $this->reasonFile === null ) {
+                       return false;
                }
-               if ( $this->fileReason === null ) {
-                       // Cache for faster access next time
-                       $readOnlyFile = $this->config->get( 'ReadOnlyFile' );
-                       if ( is_file( $readOnlyFile ) && filesize( $readOnlyFile ) > 0 ) {
-                               $this->fileReason = file_get_contents( $readOnlyFile );
-                       } else {
-                               $this->fileReason = false;
-                       }
+               // Try the reason file
+               if ( is_file( $this->reasonFile ) && filesize( $this->reasonFile ) > 0 ) {
+                       $this->reason = file_get_contents( $this->reasonFile );
                }
-               return $this->fileReason;
+               // No need to try the reason file again
+               $this->reasonFile = null;
+               return $this->reason ?? false;
        }
 
        /**
@@ -61,13 +68,6 @@ class ConfiguredReadOnlyMode {
         * @param string|null $msg
         */
        public function setReason( $msg ) {
-               $this->overrideReason = $msg;
-       }
-
-       /**
-        * Clear the cache of the read only file
-        */
-       public function clearCache() {
-               $this->fileReason = null;
+               $this->reason = $msg;
        }
 }
index 6216046..be598ea 100644 (file)
@@ -98,11 +98,14 @@ class ContentSecurityPolicy {
         *
         * @param int $reportOnly Either self::REPORT_ONLY_MODE or self::FULL_MODE
         * @return string Name of http header
+        * @throws UnexpectedValueException
         */
        private function getHeaderName( $reportOnly ) {
                if ( $reportOnly === self::REPORT_ONLY_MODE ) {
                        return 'Content-Security-Policy-Report-Only';
-               } elseif ( $reportOnly === self::FULL_MODE ) {
+               }
+
+               if ( $reportOnly === self::FULL_MODE ) {
                        return 'Content-Security-Policy';
                }
                throw new UnexpectedValueException( $reportOnly );
@@ -111,7 +114,8 @@ class ContentSecurityPolicy {
        /**
         * Determine what CSP policies to set for this page
         *
-        * @param array|bool $config Policy configuration (Either $wgCSPHeader or $wgCSPReportOnlyHeader)
+        * @param array|bool $policyConfig Policy configuration
+        *   (Either $wgCSPHeader or $wgCSPReportOnlyHeader)
         * @param int $mode self::REPORT_ONLY_MODE, self::FULL_MODE
         * @return string Policy directives, or empty string for no policy.
         */
@@ -152,8 +156,8 @@ class ContentSecurityPolicy {
                        }
                }
                // Note: default on if unspecified.
-               if ( !isset( $policyConfig['unsafeFallback'] )
-                       || $policyConfig['unsafeFallback'] )
+               if ( !isset( $policyConfig['unsafeFallback'] )
+                       || $policyConfig['unsafeFallback']
                ) {
                        // unsafe-inline should be ignored on browsers
                        // that support 'nonce-foo' sources.
index 68d7846..9efcfb4 100644 (file)
@@ -72,7 +72,7 @@ $wgConfigRegistry = [
  * MediaWiki version number
  * @since 1.2
  */
-$wgVersion = '1.33.0-alpha';
+$wgVersion = '1.34.0-alpha';
 
 /**
  * Name of the site. It must be changed in LocalSettings.php
@@ -749,7 +749,7 @@ $wgUploadDialog = [
  *   - a) Whether it is fully qualified or wiki-relative.
  *        By default, the paths of files are relative to the current wiki,
  *        which works via prefixing them with the current wiki ID when accessed.
- *        Setting 'wikiId' forces the backend to be fully qualified by prefixing
+ *        Setting 'domainId' forces the backend to be fully qualified by prefixing
  *        all paths with the specified value instead. This can be useful if
  *        multiple wikis need to share the same data. Note that 'name' is *not*
  *        part of any prefix and thus should not be relied upon for namespacing.
@@ -782,7 +782,7 @@ $wgLockManagers = [];
 
 /**
  * Show Exif data, on by default if available.
- * Requires PHP's Exif extension: https://secure.php.net/manual/en/ref.exif.php
+ * Requires PHP's Exif extension: https://www.php.net/manual/en/ref.exif.php
  *
  * @note FOR WINDOWS USERS:
  * To enable Exif functions, add the following line to the "Windows
@@ -1935,7 +1935,8 @@ $wgSearchType = null;
 $wgSearchTypeAlternatives = null;
 
 /**
- * Table name prefix; this should be alphanumeric and not contain spaces nor hyphens
+ * Table name prefix.
+ * This should be alphanumeric, contain neither spaces nor hyphens, and end in "_"
  */
 $wgDBprefix = '';
 
@@ -2099,7 +2100,7 @@ $wgDBerrorLog = false;
  * Defaults to the wiki timezone ($wgLocaltimezone).
  *
  * A list of usable timezones can found at:
- * https://secure.php.net/manual/en/timezones.php
+ * https://www.php.net/manual/en/timezones.php
  *
  * @par Examples:
  * @code
@@ -2114,26 +2115,6 @@ $wgDBerrorLog = false;
  */
 $wgDBerrorLogTZ = false;
 
-/**
- * Set to true to engage MySQL 4.1/5.0 charset-related features;
- * for now will just cause sending of 'SET NAMES=utf8' on connect.
- *
- * @warning THIS IS EXPERIMENTAL!
- *
- * May break if you're not using the table defs from mysql5/tables.sql.
- * May break if you're upgrading an existing wiki if set differently.
- * Broken symptoms likely to include incorrect behavior with page titles,
- * usernames, comments etc containing non-ASCII characters.
- * Might also cause failures on the object cache and other things.
- *
- * Even correct usage may cause failures with Unicode supplementary
- * characters (those not in the Basic Multilingual Plane) unless MySQL
- * has enhanced their Unicode support.
- *
- * @deprecated since 1.31
- */
-$wgDBmysql5 = false;
-
 /**
  * Set true to enable Oracle DCRP (supported from 11gR1 onward)
  *
@@ -2582,26 +2563,35 @@ $wgUseLocalMessageCache = false;
 $wgAdaptiveMessageCache = false;
 
 /**
- * Localisation cache configuration. Associative array with keys:
- * class:       The class to use. May be overridden by extensions.
+ * Localisation cache configuration.
+ *
+ * Used by Language::getLocalisationCache() to decide how to construct the
+ * LocalisationCache instance. Associative array with keys:
  *
- * store:       The location to store cache data. May be 'files', 'array', 'db' or
- *              'detect'. If set to "files", data will be in CDB files. If set
- *              to "db", data will be stored to the database. If set to
- *              "detect", files will be used if $wgCacheDirectory is set,
- *              otherwise the database will be used.
- *              "array" is an experimental option that uses PHP files that
- *              store static arrays.
+ * class:       The class to use for constructing the LocalisationCache object.
+ *              This may be overridden by extensions to a subclass of LocalisationCache.
+ *              Sub classes are expected to still honor the 'storeClass', 'storeDirectory'
+ *              and 'manualRecache' options where applicable.
  *
- * storeClass:  The class name for the underlying storage. If set to a class
- *              name, it overrides the "store" setting.
+ * storeClass:  Which LCStore class implementation to use. This is optional.
+ *              The default LocalisationCache class offers the 'store' option
+ *              as abstraction for this.
  *
- * storeDirectory:  If the store class puts its data in files, this is the
- *                  directory it will use. If this is false, $wgCacheDirectory
- *                  will be used.
+ * store:       How and where to store localisation cache data.
+ *              This option is ignored if 'storeClass' is explicitly set to a class name.
+ *              Must be one of:
+ *              - 'detect' (default): Automatically select 'files' if 'storeDirectory'
+ *                 or $wgCacheDirectory is set, and fall back to 'db' otherwise.
+ *              - 'files': Store in $wgCacheDirectory as CDB files.
+ *              - 'array': Store in $wgCacheDirectory as PHP static array files.
+ *              - 'db': Store in the l10n_cache database table.
  *
- * manualRecache:   Set this to true to disable cache updates on web requests.
- *                  Use maintenance/rebuildLocalisationCache.php instead.
+ * storeDirectory: If the selected LCStore class puts its data in files, then it
+ *                 will use this directory. If set to false (default), then
+ *                 $wgCacheDirectory is used instead.
+ *
+ * manualRecache: Set this to true to disable cache updates on web requests.
+ *                Use maintenance/rebuildLocalisationCache.php instead.
  */
 $wgLocalisationCacheConf = [
        'class' => LocalisationCache::class,
@@ -3189,7 +3179,7 @@ $wgForceUIMsgAsContentMsg = [];
  * timezone-nameinlowercase like timezone-utc.
  *
  * A list of usable timezones can found at:
- * https://secure.php.net/manual/en/timezones.php
+ * https://www.php.net/manual/en/timezones.php
  *
  * @par Examples:
  * @code
@@ -3213,6 +3203,19 @@ $wgLocaltimezone = null;
  */
 $wgLocalTZoffset = null;
 
+/**
+ * List of Unicode characters for which capitalization is overridden in
+ * Language::ucfirst. The characters should be
+ * represented as char_to_convert => conversion_override. See T219279 for details
+ * on why this is useful during php version transitions.
+ *
+ * @warning: EXPERIMENTAL!
+ *
+ * @since 1.34
+ * @var array
+ */
+$wgOverrideUcfirstCharacters = [];
+
 /** @} */ # End of language/charset settings
 
 /*************************************************************************//**
@@ -3494,7 +3497,7 @@ $wgFooterIcons = [
                        // "$wgResourceBasePath/resources/assets/poweredby_mediawiki_88x31.png"
                        // plus srcset for 1.5x, 2x resolution variants.
                        "src" => null,
-                       "url" => "//www.mediawiki.org/",
+                       "url" => "https://www.mediawiki.org/",
                        "alt" => "Powered by MediaWiki",
                ]
        ],
@@ -4011,13 +4014,12 @@ $wgRedirectSources = false;
 $wgCapitalLinks = true;
 
 /**
- * @since 1.16 - This can now be set per-namespace. Some special namespaces (such
- * as Special, see MWNamespace::$alwaysCapitalizedNamespaces for the full list) must be
- * true by default (and setting them has no effect), due to various things that
- * require them to be so. Also, since Talk namespaces need to directly mirror their
- * associated content namespaces, the values for those are ignored in favor of the
- * subject namespace's setting. Setting for NS_MEDIA is taken automatically from
- * NS_FILE.
+ * @since 1.16 - This can now be set per-namespace. Some special namespaces (such as Special, see
+ * NamespaceInfo::$alwaysCapitalizedNamespaces for the full list) must be true by default (and
+ * setting them has no effect), due to various things that require them to be so. Also, since Talk
+ * namespaces need to directly mirror their associated content namespaces, the values for those are
+ * ignored in favor of the subject namespace's setting. Setting for NS_MEDIA is taken automatically
+ * from NS_FILE.
  *
  * @par Example:
  * @code
@@ -4131,7 +4133,7 @@ $wgInvalidRedirectTargets = [ 'Filepath', 'Mypage', 'Mytalk', 'Redirect' ];
  *
  * The entire associative array will be passed through to the constructor as
  * the first parameter. Note that only Setup.php can use this variable --
- * the configuration will change at runtime via $wgParser member functions, so
+ * the configuration will change at runtime via Parser member functions, so
  * the contents of this variable will be out-of-date. The variable can only be
  * changed during LocalSettings.php, in particular, it can't be changed during
  * an extension setup function.
@@ -4871,12 +4873,12 @@ $wgDefaultUserOptions = [
        'previewonfirst' => 0,
        'previewontop' => 1,
        'rcdays' => 7,
-       'rcenhancedfilters' => 0,
        'rcenhancedfilters-disable' => 0,
        'rclimit' => 50,
        'rows' => 25, // @deprecated since 1.29 No longer used in core
        'showhiddencats' => 0,
        'shownumberswatching' => 1,
+       'showrollbackconfirmation' => 0,
        'skin' => false,
        'stubthreshold' => 0,
        'thumbsize' => 5,
@@ -6858,7 +6860,7 @@ $wgRCLinkDays = [ 1, 3, 7, 14, 30 ];
  * FormattedRCFeed-specific options:
  * - 'uri' -- [required] The address to which the messages are sent.
  *   The uri scheme of this string will be looked up in $wgRCEngines
- *   to determine which RCFeedEngine class to use.
+ *   to determine which FormattedRCFeed class to use.
  * - 'formatter' -- [required] The class (implementing RCFeedFormatter) which will
  *   produce the text to send. This can also be an object of the class.
  *   Formatters available by default: JSONRCFeedFormatter, XMLRCFeedFormatter,
@@ -7512,6 +7514,7 @@ $wgServiceWiringFiles = [
  * can add to this to provide custom jobs.
  * A job handler should either be a class name to be instantiated,
  * or (since 1.30) a callback to use for creating the job object.
+ * The callback takes (Title, array map of parameters) as arguments.
  */
 $wgJobClasses = [
        'deletePage' => DeletePageJob::class,
@@ -7536,6 +7539,7 @@ $wgJobClasses = [
        'cdnPurge' => CdnPurgeJob::class,
        'userGroupExpiry' => UserGroupExpiryJob::class,
        'clearWatchlistNotifications' => ClearWatchlistNotificationsJob::class,
+       'userOptionsUpdate' => UserOptionsUpdateJob::class,
        'enqueue' => EnqueueJob::class, // local queue for multi-DC setups
        'null' => NullJob::class,
 ];
@@ -7589,14 +7593,6 @@ $wgJobTypeConf = [
        'default' => [ 'class' => JobQueueDB::class, 'order' => 'random', 'claimTTL' => 3600 ],
 ];
 
-/**
- * Which aggregator to use for tracking which queues have jobs.
- * These settings should be global to all wikis.
- */
-$wgJobQueueAggregator = [
-       'class' => JobQueueAggregatorNull::class
-];
-
 /**
  * Whether to include the number of jobs that are queued
  * for the API's maxlag parameter.
@@ -7667,7 +7663,7 @@ $wgCategoryPagingLimit = 200;
  *     all languages in a mediocre way. However, it is better than "uppercase".
  *
  * To use the uca-default collation, you must have PHP's intl extension
- * installed. See https://secure.php.net/manual/en/intl.setup.php . The details of the
+ * installed. See https://www.php.net/manual/en/intl.setup.php . The details of the
  * resulting collation will depend on the version of ICU installed on the
  * server.
  *
@@ -8411,7 +8407,7 @@ $wgAsyncHTTPTimeout = 25;
 /**
  * Proxy to use for CURL requests.
  */
-$wgHTTPProxy = false;
+$wgHTTPProxy = '';
 
 /**
  * Local virtual hosts.
@@ -8434,6 +8430,13 @@ $wgLocalVirtualHosts = [];
  */
 $wgHTTPConnectTimeout = 5e0;
 
+/**
+ * Whether to respect/honour the request ID provided by the incoming request
+ * via the `X-Request-Id` header. Set to `true` if the entity sitting in front
+ * of Mediawiki sanitises external requests. Default: `false`.
+ */
+$wgAllowExternalReqID = false;
+
 /** @} */ # End HTTP client }
 
 /************************************************************************//**
@@ -8494,6 +8497,7 @@ $wgExternalDiffEngine = false;
  * See $wgExternalDiffEngine.
  *
  * @since 1.30
+ * @deprecated since 1.34
  */
 $wgWikiDiff2MovedParagraphDetectionCutoff = 0;
 
@@ -8976,6 +8980,12 @@ $wgInterwikiPrefixDisplayTypes = [];
  */
 $wgMultiContentRevisionSchemaMigrationStage = SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW;
 
+/**
+ * The schema to use per default when generating XML dumps. This allows sites to control
+ * explicitly when to make breaking changes to their export and dump format.
+ */
+$wgXmlDumpSchemaVersion = XML_DUMP_SCHEMA_VERSION_10;
+
 /**
  * Actor table schema migration stage.
  *
@@ -8992,7 +9002,7 @@ $wgMultiContentRevisionSchemaMigrationStage = SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_
  * @since 1.32 changed allowed flags
  * @var int An appropriate combination of SCHEMA_COMPAT_XXX flags.
  */
-$wgActorTableSchemaMigrationStage = SCHEMA_COMPAT_OLD;
+$wgActorTableSchemaMigrationStage = SCHEMA_COMPAT_NEW;
 
 /**
  * Flag to enable Partial Blocks. This allows an admin to prevent a user from editing specific pages
@@ -9005,41 +9015,73 @@ $wgActorTableSchemaMigrationStage = SCHEMA_COMPAT_OLD;
 $wgEnablePartialBlocks = false;
 
 /**
- * Enable confirmation prompt for rollback actions to prevent accidental rollbacks.
- * May be disabled to reduce number of clicks needed to perform rollbacks.
+ * Origin Trials tokens.
+ *
+ * @since 1.33
+ * @var array
+ */
+$wgOriginTrials = [];
+
+/**
+ * Enable client-side Priority Hints.
+ *
+ * @warning EXPERIMENTAL!
  *
  * @since 1.33
  * @var bool
  */
-$wgEnableRollbackConfirmationPrompt = true;
+$wgPriorityHints = false;
 
 /**
- * Enable stats monitoring when Block Notices are displayed in different places around core
- * and extensions.
+ * Ratio of requests that should get Priority Hints when the feature is enabled.
+ *
+ * @warning EXPERIMENTAL!
  *
  * @since 1.34
- * @deprecated 1.34
+ * @var float
+ */
+$wgPriorityHintsRatio = 1.0;
+
+/**
+ * Enable Element Timing.
+ *
+ * @warning EXPERIMENTAL!
+ *
+ * @since 1.33
  * @var bool
  */
-$wgEnableBlockNoticeStats = false;
+$wgElementTiming = false;
 
 /**
- * Origin Trials tokens.
+ * Expiry of the endpoint definition for the Reporting API.
+ *
+ * @warning EXPERIMENTAL!
+ *
+ * @since 1.34
+ * @var int
+ */
+$wgReportToExpiry = 86400;
+
+/**
+ * List of endpoints for the Reporting API.
+ *
+ * @warning EXPERIMENTAL!
  *
  * @since 1.34
  * @var array
  */
-$wgOriginTrials = [];
+$wgReportToEndpoints = [];
 
 /**
- * Enable client-side Priority Hints.
+ * List of Feature Policy Reporting types to enable.
+ * Each entry is turned into a Feature-Policy-Report-Only header.
  *
  * @warning EXPERIMENTAL!
  *
  * @since 1.34
- * @var bool
+ * @var array
  */
-$wgPriorityHints = false;
+$wgFeaturePolicyReportOnly = [];
 
 /**
  * For really cool vim folding this needs to be at the end:
index 720e8d0..5f98b44 100644 (file)
@@ -317,3 +317,13 @@ define( 'MIGRATION_WRITE_BOTH', 0x10000000 | SCHEMA_COMPAT_READ_BOTH | SCHEMA_CO
 define( 'MIGRATION_WRITE_NEW', 0x20000000 | SCHEMA_COMPAT_READ_BOTH | SCHEMA_COMPAT_WRITE_NEW );
 define( 'MIGRATION_NEW', 0x30000000 | SCHEMA_COMPAT_NEW );
 /**@}*/
+
+/**@{
+ * XML dump schema versions, for use with XmlDumpWriter.
+ * See also the corresponding export-nnnn.xsd files in the docs directory,
+ * which are also listed at <https://www.mediawiki.org/xml/>.
+ * Note that not all old schema versions are represented here, as several
+ * were already unsupported at the time these constants were introduced.
+ */
+define( 'XML_DUMP_SCHEMA_VERSION_10', '0.10' );
+/**@}*/
index 8b32de4..4bf00d0 100644 (file)
@@ -25,8 +25,8 @@ ini_set( 'display_errors', 1 );
  * Debugging: MediaWiki
  */
 global $wgDevelopmentWarnings, $wgShowExceptionDetails, $wgShowHostnames,
-       $wgDebugRawPage, $wgDebugComments, $wgDebugDumpSql, $wgDebugTimestamps,
-       $wgCommandLineMode, $wgDebugLogFile, $wgDBerrorLog, $wgDebugLogGroups;
+       $wgDebugRawPage, $wgSQLMode, $wgCommandLineMode, $wgDebugLogFile,
+       $wgDBerrorLog, $wgDebugLogGroups;
 
 // Use of wfWarn() should cause tests to fail
 $wgDevelopmentWarnings = true;
@@ -36,6 +36,9 @@ $wgShowExceptionDetails = true;
 $wgShowHostnames = true;
 $wgDebugRawPage = true; // T49960
 
+// Enable MariaDB/MySQL strict mode
+$wgSQLMode = 'TRADITIONAL';
+
 // Enable log files
 $logDir = getenv( 'MW_LOG_DIR' );
 if ( $logDir ) {
index 23cdc3b..47a8b5b 100644 (file)
@@ -637,13 +637,6 @@ class EditPage {
                                                $this->context->getUser()->spreadAnyEditBlock();
                                        } );
                                }
-
-                               $config = $this->context->getConfig();
-                               if ( $config->get( 'EnableBlockNoticeStats' ) ) {
-                                       $wiki = $config->get( 'DBname' );
-                                       $statsd = MediaWikiServices::getInstance()->getStatsdDataFactory();
-                                       $statsd->increment( 'BlockNotices.' . $wiki . '.WikitextEditor.shown' );
-                               }
                        }
                        $this->displayPermissionsError( $permErrors );
 
@@ -869,7 +862,7 @@ class EditPage {
                } elseif ( $this->section == 'new' ) {
                        // Nothing *to* preview for new sections
                        return false;
-               } elseif ( ( $request->getVal( 'preload' ) !== null || $this->mTitle->exists() )
+               } elseif ( ( $request->getCheck( 'preload' ) || $this->mTitle->exists() )
                        && $this->context->getUser()->getOption( 'previewonfirst' )
                ) {
                        // Standard preference behavior
@@ -975,7 +968,7 @@ class EditPage {
 
                        $this->scrolltop = $request->getIntOrNull( 'wpScrolltop' );
 
-                       if ( $this->textbox1 === '' && $request->getVal( 'wpTextbox1' ) === null ) {
+                       if ( $this->textbox1 === '' && !$request->getCheck( 'wpTextbox1' ) ) {
                                // wpTextbox1 field is missing, possibly due to being "too big"
                                // according to some filter rules such as Suhosin's setting for
                                // suhosin.request.max_value_length (d'oh)
@@ -1214,149 +1207,147 @@ class EditPage {
                                $content = $this->getPreloadedContent( $preload, $params );
                        }
                // For existing pages, get text based on "undo" or section parameters.
-               } else {
-                       if ( $this->section != '' ) {
-                               // Get section edit text (returns $def_text for invalid sections)
-                               $orig = $this->getOriginalContent( $user );
-                               $content = $orig ? $orig->getSection( $this->section ) : null;
+               } elseif ( $this->section != '' ) {
+                       // Get section edit text (returns $def_text for invalid sections)
+                       $orig = $this->getOriginalContent( $user );
+                       $content = $orig ? $orig->getSection( $this->section ) : null;
 
-                               if ( !$content ) {
-                                       $content = $def_content;
-                               }
-                       } else {
-                               $undoafter = $request->getInt( 'undoafter' );
-                               $undo = $request->getInt( 'undo' );
-
-                               if ( $undo > 0 && $undoafter > 0 ) {
-                                       $undorev = Revision::newFromId( $undo );
-                                       $oldrev = Revision::newFromId( $undoafter );
-                                       $undoMsg = null;
-
-                                       # Sanity check, make sure it's the right page,
-                                       # the revisions exist and they were not deleted.
-                                       # Otherwise, $content will be left as-is.
-                                       if ( !is_null( $undorev ) && !is_null( $oldrev ) &&
-                                               !$undorev->isDeleted( Revision::DELETED_TEXT ) &&
-                                               !$oldrev->isDeleted( Revision::DELETED_TEXT )
+                       if ( !$content ) {
+                               $content = $def_content;
+                       }
+               } else {
+                       $undoafter = $request->getInt( 'undoafter' );
+                       $undo = $request->getInt( 'undo' );
+
+                       if ( $undo > 0 && $undoafter > 0 ) {
+                               $undorev = Revision::newFromId( $undo );
+                               $oldrev = Revision::newFromId( $undoafter );
+                               $undoMsg = null;
+
+                               # Sanity check, make sure it's the right page,
+                               # the revisions exist and they were not deleted.
+                               # Otherwise, $content will be left as-is.
+                               if ( !is_null( $undorev ) && !is_null( $oldrev ) &&
+                                       !$undorev->isDeleted( Revision::DELETED_TEXT ) &&
+                                       !$oldrev->isDeleted( Revision::DELETED_TEXT )
+                               ) {
+                                       if ( WikiPage::hasDifferencesOutsideMainSlot( $undorev, $oldrev )
+                                               || !$this->isSupportedContentModel( $oldrev->getContentModel() )
                                        ) {
-                                               if ( WikiPage::hasDifferencesOutsideMainSlot( $undorev, $oldrev )
-                                                       || !$this->isSupportedContentModel( $oldrev->getContentModel() )
-                                               ) {
-                                                       // Hack for undo while EditPage can't handle multi-slot editing
-                                                       $this->context->getOutput()->redirect( $this->mTitle->getFullURL( [
-                                                               'action' => 'mcrundo',
-                                                               'undo' => $undo,
-                                                               'undoafter' => $undoafter,
-                                                       ] ) );
-                                                       return false;
-                                               } else {
-                                                       $content = $this->page->getUndoContent( $undorev, $oldrev );
+                                               // Hack for undo while EditPage can't handle multi-slot editing
+                                               $this->context->getOutput()->redirect( $this->mTitle->getFullURL( [
+                                                       'action' => 'mcrundo',
+                                                       'undo' => $undo,
+                                                       'undoafter' => $undoafter,
+                                               ] ) );
+                                               return false;
+                                       } else {
+                                               $content = $this->page->getUndoContent( $undorev, $oldrev );
 
-                                                       if ( $content === false ) {
-                                                               # Warn the user that something went wrong
-                                                               $undoMsg = 'failure';
-                                                       }
+                                               if ( $content === false ) {
+                                                       # Warn the user that something went wrong
+                                                       $undoMsg = 'failure';
                                                }
+                                       }
 
-                                               if ( $undoMsg === null ) {
-                                                       $oldContent = $this->page->getContent( Revision::RAW );
-                                                       $popts = ParserOptions::newFromUserAndLang(
-                                                               $user, MediaWikiServices::getInstance()->getContentLanguage() );
-                                                       $newContent = $content->preSaveTransform( $this->mTitle, $user, $popts );
-                                                       if ( $newContent->getModel() !== $oldContent->getModel() ) {
-                                                               // The undo may change content
-                                                               // model if its reverting the top
-                                                               // edit. This can result in
-                                                               // mismatched content model/format.
-                                                               $this->contentModel = $newContent->getModel();
-                                                               $this->contentFormat = $oldrev->getContentFormat();
-                                                       }
+                                       if ( $undoMsg === null ) {
+                                               $oldContent = $this->page->getContent( Revision::RAW );
+                                               $popts = ParserOptions::newFromUserAndLang(
+                                                       $user, MediaWikiServices::getInstance()->getContentLanguage() );
+                                               $newContent = $content->preSaveTransform( $this->mTitle, $user, $popts );
+                                               if ( $newContent->getModel() !== $oldContent->getModel() ) {
+                                                       // The undo may change content
+                                                       // model if its reverting the top
+                                                       // edit. This can result in
+                                                       // mismatched content model/format.
+                                                       $this->contentModel = $newContent->getModel();
+                                                       $this->contentFormat = $oldrev->getContentFormat();
+                                               }
 
-                                                       if ( $newContent->equals( $oldContent ) ) {
-                                                               # Tell the user that the undo results in no change,
-                                                               # i.e. the revisions were already undone.
-                                                               $undoMsg = 'nochange';
-                                                               $content = false;
-                                                       } else {
-                                                               # Inform the user of our success and set an automatic edit summary
-                                                               $undoMsg = 'success';
-
-                                                               # If we just undid one rev, use an autosummary
-                                                               $firstrev = $oldrev->getNext();
-                                                               if ( $firstrev && $firstrev->getId() == $undo ) {
-                                                                       $userText = $undorev->getUserText();
-                                                                       if ( $userText === '' ) {
-                                                                               $undoSummary = $this->context->msg(
-                                                                                       'undo-summary-username-hidden',
-                                                                                       $undo
-                                                                               )->inContentLanguage()->text();
-                                                                       } else {
-                                                                               $undoSummary = $this->context->msg(
-                                                                                       'undo-summary',
-                                                                                       $undo,
-                                                                                       $userText
-                                                                               )->inContentLanguage()->text();
-                                                                       }
-                                                                       if ( $this->summary === '' ) {
-                                                                               $this->summary = $undoSummary;
-                                                                       } else {
-                                                                               $this->summary = $undoSummary . $this->context->msg( 'colon-separator' )
-                                                                                       ->inContentLanguage()->text() . $this->summary;
-                                                                       }
-                                                                       $this->undidRev = $undo;
+                                               if ( $newContent->equals( $oldContent ) ) {
+                                                       # Tell the user that the undo results in no change,
+                                                       # i.e. the revisions were already undone.
+                                                       $undoMsg = 'nochange';
+                                                       $content = false;
+                                               } else {
+                                                       # Inform the user of our success and set an automatic edit summary
+                                                       $undoMsg = 'success';
+
+                                                       # If we just undid one rev, use an autosummary
+                                                       $firstrev = $oldrev->getNext();
+                                                       if ( $firstrev && $firstrev->getId() == $undo ) {
+                                                               $userText = $undorev->getUserText();
+                                                               if ( $userText === '' ) {
+                                                                       $undoSummary = $this->context->msg(
+                                                                               'undo-summary-username-hidden',
+                                                                               $undo
+                                                                       )->inContentLanguage()->text();
+                                                               } else {
+                                                                       $undoSummary = $this->context->msg(
+                                                                               'undo-summary',
+                                                                               $undo,
+                                                                               $userText
+                                                                       )->inContentLanguage()->text();
+                                                               }
+                                                               if ( $this->summary === '' ) {
+                                                                       $this->summary = $undoSummary;
+                                                               } else {
+                                                                       $this->summary = $undoSummary . $this->context->msg( 'colon-separator' )
+                                                                               ->inContentLanguage()->text() . $this->summary;
                                                                }
-                                                               $this->formtype = 'diff';
+                                                               $this->undidRev = $undo;
                                                        }
+                                                       $this->formtype = 'diff';
                                                }
-                                       } else {
-                                               // Failed basic sanity checks.
-                                               // Older revisions may have been removed since the link
-                                               // was created, or we may simply have got bogus input.
-                                               $undoMsg = 'norev';
                                        }
-
-                                       $out = $this->context->getOutput();
-                                       // Messages: undo-success, undo-failure, undo-main-slot-only, undo-norev,
-                                       // undo-nochange.
-                                       $class = ( $undoMsg == 'success' ? '' : 'error ' ) . "mw-undo-{$undoMsg}";
-                                       $this->editFormPageTop .= Html::rawElement(
-                                               'div', [ 'class' => $class ],
-                                               $out->parseAsInterface(
-                                                       $this->context->msg( 'undo-' . $undoMsg )->plain()
-                                               )
-                                       );
+                               } else {
+                                       // Failed basic sanity checks.
+                                       // Older revisions may have been removed since the link
+                                       // was created, or we may simply have got bogus input.
+                                       $undoMsg = 'norev';
                                }
 
-                               if ( $content === false ) {
-                                       // Hack for restoring old revisions while EditPage
-                                       // can't handle multi-slot editing.
+                               $out = $this->context->getOutput();
+                               // Messages: undo-success, undo-failure, undo-main-slot-only, undo-norev,
+                               // undo-nochange.
+                               $class = ( $undoMsg == 'success' ? '' : 'error ' ) . "mw-undo-{$undoMsg}";
+                               $this->editFormPageTop .= Html::rawElement(
+                                       'div', [ 'class' => $class ],
+                                       $out->parseAsInterface(
+                                               $this->context->msg( 'undo-' . $undoMsg )->plain()
+                                       )
+                               );
+                       }
 
-                                       $curRevision = $this->page->getRevision();
-                                       $oldRevision = $this->mArticle->getRevisionFetched();
+                       if ( $content === false ) {
+                               // Hack for restoring old revisions while EditPage
+                               // can't handle multi-slot editing.
 
-                                       if ( $curRevision
-                                               && $oldRevision
-                                               && $curRevision->getId() !== $oldRevision->getId()
-                                               && ( WikiPage::hasDifferencesOutsideMainSlot( $oldRevision, $curRevision )
-                                                       || !$this->isSupportedContentModel( $oldRevision->getContentModel() ) )
-                                       ) {
-                                               $this->context->getOutput()->redirect(
-                                                       $this->mTitle->getFullURL(
-                                                               [
-                                                                       'action' => 'mcrrestore',
-                                                                       'restore' => $oldRevision->getId(),
-                                                               ]
-                                                       )
-                                               );
+                               $curRevision = $this->page->getRevision();
+                               $oldRevision = $this->mArticle->getRevisionFetched();
 
-                                               return false;
-                                       }
-                               }
+                               if ( $curRevision
+                                       && $oldRevision
+                                       && $curRevision->getId() !== $oldRevision->getId()
+                                       && ( WikiPage::hasDifferencesOutsideMainSlot( $oldRevision, $curRevision )
+                                               || !$this->isSupportedContentModel( $oldRevision->getContentModel() ) )
+                               ) {
+                                       $this->context->getOutput()->redirect(
+                                               $this->mTitle->getFullURL(
+                                                       [
+                                                               'action' => 'mcrrestore',
+                                                               'restore' => $oldRevision->getId(),
+                                                       ]
+                                               )
+                                       );
 
-                               if ( $content === false ) {
-                                       $content = $this->getOriginalContent( $user );
+                                       return false;
                                }
                        }
+
+                       if ( $content === false ) {
+                               $content = $this->getOriginalContent( $user );
+                       }
                }
 
                return $content;
@@ -1492,8 +1483,9 @@ class EditPage {
 
                $user = $this->context->getUser();
                $title = Title::newFromText( $preload );
+
                # Check for existence to avoid getting MediaWiki:Noarticletext
-               if ( $title === null || !$title->exists() || !$title->userCan( 'read', $user ) ) {
+               if ( !$this->isPageExistingAndViewable( $title, $user ) ) {
                        // TODO: somehow show a warning to the user!
                        return $handler->makeEmptyContent();
                }
@@ -1502,7 +1494,7 @@ class EditPage {
                if ( $page->isRedirect() ) {
                        $title = $page->getRedirectTarget();
                        # Same as before
-                       if ( $title === null || !$title->exists() || !$title->userCan( 'read', $user ) ) {
+                       if ( !$this->isPageExistingAndViewable( $title, $user ) ) {
                                // TODO: somehow show a warning to the user!
                                return $handler->makeEmptyContent();
                        }
@@ -1535,6 +1527,21 @@ class EditPage {
                return $content->preloadTransform( $title, $parserOptions, $params );
        }
 
+       /**
+        * Verify if a given title exists and the given user is allowed to view it
+        *
+        * @see EditPage::getPreloadedContent()
+        * @param Title|null $title
+        * @param User $user
+        * @return bool
+        * @throws Exception
+        */
+       private function isPageExistingAndViewable( $title, User $user ) {
+               $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+
+               return $title && $title->exists() && $permissionManager->userCan( 'read', $user, $title );
+       }
+
        /**
         * Make sure the form isn't faking a user's credentials.
         *
@@ -1818,15 +1825,14 @@ ERROR;
         * @return string
         */
        private function newSectionSummary( &$sectionanchor = null ) {
-               global $wgParser;
-
                if ( $this->sectiontitle !== '' ) {
                        $sectionanchor = $this->guessSectionName( $this->sectiontitle );
                        // If no edit summary was specified, create one automatically from the section
                        // title and have it link to the new section. Otherwise, respect the summary as
                        // passed.
                        if ( $this->summary === '' ) {
-                               $cleanSectionTitle = $wgParser->stripSectionName( $this->sectiontitle );
+                               $cleanSectionTitle = MediaWikiServices::getInstance()->getParser()
+                                       ->stripSectionName( $this->sectiontitle );
                                return $this->context->msg( 'newsectionsummary' )
                                        ->plaintextParams( $cleanSectionTitle )->inContentLanguage()->text();
                        }
@@ -1834,7 +1840,8 @@ ERROR;
                        $sectionanchor = $this->guessSectionName( $this->summary );
                        # This is a new section, so create a link to the new section
                        # in the revision summary.
-                       $cleanSummary = $wgParser->stripSectionName( $this->summary );
+                       $cleanSummary = MediaWikiServices::getInstance()->getParser()
+                               ->stripSectionName( $this->summary );
                        return $this->context->msg( 'newsectionsummary' )
                                ->plaintextParams( $cleanSummary )->inContentLanguage()->text();
                }
@@ -1997,6 +2004,8 @@ ERROR;
                        }
                }
 
+               $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+
                $changingContentModel = false;
                if ( $this->contentModel !== $this->mTitle->getContentModel() ) {
                        if ( !$config->get( 'ContentHandlerUseDB' ) ) {
@@ -2010,10 +2019,19 @@ ERROR;
                        // Make sure the user can edit the page under the new content model too
                        $titleWithNewContentModel = clone $this->mTitle;
                        $titleWithNewContentModel->setContentModel( $this->contentModel );
-                       if ( !$titleWithNewContentModel->userCan( 'editcontentmodel', $user )
-                               || !$titleWithNewContentModel->userCan( 'edit', $user )
+
+                       $canEditModel = $permissionManager->userCan(
+                               'editcontentmodel',
+                               $user,
+                               $titleWithNewContentModel
+                       );
+
+                       if (
+                               !$canEditModel
+                               || !$permissionManager->userCan( 'edit', $user, $titleWithNewContentModel )
                        ) {
                                $status->setResult( false, self::AS_NO_CHANGE_CONTENT_MODEL );
+
                                return $status;
                        }
 
@@ -2057,7 +2075,7 @@ ERROR;
 
                if ( $new ) {
                        // Late check for create permission, just in case *PARANOIA*
-                       if ( !$this->mTitle->userCan( 'create', $user ) ) {
+                       if ( !$permissionManager->userCan( 'create', $user, $this->mTitle ) ) {
                                $status->fatal( 'nocreatetext' );
                                $status->value = self::AS_NO_CREATE_PERMISSION;
                                wfDebug( __METHOD__ . ": no create permission\n" );
@@ -2618,7 +2636,8 @@ ERROR;
                                LogEventsList::showLogExtract(
                                        $out,
                                        'block',
-                                       MWNamespace::getCanonicalName( NS_USER ) . ':' . $block->getTarget(),
+                                       MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                               getCanonicalName( NS_USER ) . ':' . $block->getTarget(),
                                        '',
                                        [
                                                'lim' => 1,
@@ -2680,7 +2699,7 @@ ERROR;
        protected function showCustomIntro() {
                if ( $this->editintro ) {
                        $title = Title::newFromText( $this->editintro );
-                       if ( $title instanceof Title && $title->exists() && $title->userCan( 'read' ) ) {
+                       if ( $this->isPageExistingAndViewable( $title, $this->context->getUser() ) ) {
                                // Added using template syntax, to take <noinclude>'s into account.
                                $this->context->getOutput()->addWikiTextAsContent(
                                        '<div class="mw-editintro">{{:' . $title->getFullText() . '}}</div>',
@@ -2804,11 +2823,9 @@ ERROR;
 
                $out->addHTML( $this->editFormTextTop );
 
-               if ( $this->wasDeletedSinceLastEdit() ) {
-                       if ( $this->formtype !== 'save' ) {
-                               $out->wrapWikiMsg( "<div class='error mw-deleted-while-editing'>\n$1\n</div>",
-                                       'deletedwhileediting' );
-                       }
+               if ( $this->wasDeletedSinceLastEdit() && $this->formtype !== 'save' ) {
+                       $out->wrapWikiMsg( "<div class='error mw-deleted-while-editing'>\n$1\n</div>",
+                               'deletedwhileediting' );
                }
 
                // @todo add EditForm plugin interface and use it here!
@@ -2944,7 +2961,7 @@ ERROR;
                }
 
                if ( !$this->mTitle->isUserConfigPage() ) {
-                       $out->addHTML( self::getEditToolbar( $this->mTitle ) );
+                       $out->addHTML( self::getEditToolbar() );
                }
 
                if ( $this->blankArticle ) {
@@ -3062,8 +3079,8 @@ ERROR;
        public static function extractSectionTitle( $text ) {
                preg_match( "/^(=+)(.+)\\1\\s*(\n|$)/i", $text, $matches );
                if ( !empty( $matches[2] ) ) {
-                       global $wgParser;
-                       return $wgParser->stripSectionName( trim( $matches[2] ) );
+                       return MediaWikiServices::getInstance()->getParser()
+                               ->stripSectionName( trim( $matches[2] ) );
                } else {
                        return false;
                }
@@ -3076,12 +3093,12 @@ ERROR;
                        $this->addExplainConflictHeader( $out );
                        $this->editRevId = $this->page->getLatest();
                } else {
-                       if ( $this->section != '' && $this->section != 'new' ) {
-                               if ( !$this->summary && !$this->preview && !$this->diff ) {
-                                       $sectionTitle = self::extractSectionTitle( $this->textbox1 ); // FIXME: use Content object
-                                       if ( $sectionTitle !== false ) {
-                                               $this->summary = "/* $sectionTitle */ ";
-                                       }
+                       if ( $this->section != '' && $this->section != 'new' && !$this->summary &&
+                               !$this->preview && !$this->diff
+                       ) {
+                               $sectionTitle = self::extractSectionTitle( $this->textbox1 ); // FIXME: use Content object
+                               if ( $sectionTitle !== false ) {
+                                       $this->summary = "/* $sectionTitle */ ";
                                }
                        }
 
@@ -3188,44 +3205,42 @@ ERROR;
                                        'anonpreviewwarning'
                                );
                        }
-               } else {
-                       if ( $this->mTitle->isUserConfigPage() ) {
-                               # Check the skin exists
-                               if ( $this->isWrongCaseUserConfigPage() ) {
-                                       $out->wrapWikiMsg(
-                                               "<div class='error' id='mw-userinvalidconfigtitle'>\n$1\n</div>",
-                                               [ 'userinvalidconfigtitle', $this->mTitle->getSkinFromConfigSubpage() ]
-                                       );
-                               }
-                               if ( $this->getTitle()->isSubpageOf( $user->getUserPage() ) ) {
-                                       $isUserCssConfig = $this->mTitle->isUserCssConfigPage();
-                                       $isUserJsonConfig = $this->mTitle->isUserJsonConfigPage();
-                                       $isUserJsConfig = $this->mTitle->isUserJsConfigPage();
-
-                                       $warning = $isUserCssConfig
-                                               ? 'usercssispublic'
-                                               : ( $isUserJsonConfig ? 'userjsonispublic' : 'userjsispublic' );
-
-                                       $out->wrapWikiMsg( '<div class="mw-userconfigpublic">$1</div>', $warning );
-
-                                       if ( $this->formtype !== 'preview' ) {
-                                               $config = $this->context->getConfig();
-                                               if ( $isUserCssConfig && $config->get( 'AllowUserCss' ) ) {
-                                                       $out->wrapWikiMsg(
-                                                               "<div id='mw-usercssyoucanpreview'>\n$1\n</div>",
-                                                               [ 'usercssyoucanpreview' ]
-                                                       );
-                                               } elseif ( $isUserJsonConfig /* No comparable 'AllowUserJson' */ ) {
-                                                       $out->wrapWikiMsg(
-                                                               "<div id='mw-userjsonyoucanpreview'>\n$1\n</div>",
-                                                               [ 'userjsonyoucanpreview' ]
-                                                       );
-                                               } elseif ( $isUserJsConfig && $config->get( 'AllowUserJs' ) ) {
-                                                       $out->wrapWikiMsg(
-                                                               "<div id='mw-userjsyoucanpreview'>\n$1\n</div>",
-                                                               [ 'userjsyoucanpreview' ]
-                                                       );
-                                               }
+               } elseif ( $this->mTitle->isUserConfigPage() ) {
+                       # Check the skin exists
+                       if ( $this->isWrongCaseUserConfigPage() ) {
+                               $out->wrapWikiMsg(
+                                       "<div class='error' id='mw-userinvalidconfigtitle'>\n$1\n</div>",
+                                       [ 'userinvalidconfigtitle', $this->mTitle->getSkinFromConfigSubpage() ]
+                               );
+                       }
+                       if ( $this->getTitle()->isSubpageOf( $user->getUserPage() ) ) {
+                               $isUserCssConfig = $this->mTitle->isUserCssConfigPage();
+                               $isUserJsonConfig = $this->mTitle->isUserJsonConfigPage();
+                               $isUserJsConfig = $this->mTitle->isUserJsConfigPage();
+
+                               $warning = $isUserCssConfig
+                                       ? 'usercssispublic'
+                                       : ( $isUserJsonConfig ? 'userjsonispublic' : 'userjsispublic' );
+
+                               $out->wrapWikiMsg( '<div class="mw-userconfigpublic">$1</div>', $warning );
+
+                               if ( $this->formtype !== 'preview' ) {
+                                       $config = $this->context->getConfig();
+                                       if ( $isUserCssConfig && $config->get( 'AllowUserCss' ) ) {
+                                               $out->wrapWikiMsg(
+                                                       "<div id='mw-usercssyoucanpreview'>\n$1\n</div>",
+                                                       [ 'usercssyoucanpreview' ]
+                                               );
+                                       } elseif ( $isUserJsonConfig /* No comparable 'AllowUserJson' */ ) {
+                                               $out->wrapWikiMsg(
+                                                       "<div id='mw-userjsonyoucanpreview'>\n$1\n</div>",
+                                                       [ 'userjsonyoucanpreview' ]
+                                               );
+                                       } elseif ( $isUserJsConfig && $config->get( 'AllowUserJs' ) ) {
+                                               $out->wrapWikiMsg(
+                                                       "<div id='mw-userjsyoucanpreview'>\n$1\n</div>",
+                                                       [ 'userjsyoucanpreview' ]
+                                               );
                                        }
                                }
                        }
@@ -3309,10 +3324,8 @@ ERROR;
                        if ( $this->nosummary ) {
                                return;
                        }
-               } else {
-                       if ( !$this->mShowSummaryField ) {
-                               return;
-                       }
+               } elseif ( !$this->mShowSummaryField ) {
+                       return;
                }
 
                $labelText = $this->context->msg( $isSubjectPreview ? 'subject' : 'summary' )->parse();
@@ -3337,11 +3350,10 @@ ERROR;
                        return "";
                }
 
-               global $wgParser;
-
                if ( $isSubjectPreview ) {
                        $summary = $this->context->msg( 'newsectionsummary' )
-                               ->rawParams( $wgParser->stripSectionName( $summary ) )
+                               ->rawParams( MediaWikiServices::getInstance()->getParser()
+                                       ->stripSectionName( $summary ) )
                                ->inContentLanguage()->text();
                }
 
@@ -4116,10 +4128,9 @@ ERROR;
        /**
         * Allow extensions to provide a toolbar.
         *
-        * @param Title|null $title Title object for the page being edited (optional)
         * @return string|null
         */
-       public static function getEditToolbar( $title = null ) {
+       public static function getEditToolbar() {
                $startingToolbar = '<div id="toolbar"></div>';
                $toolbar = $startingToolbar;
 
@@ -4375,33 +4386,6 @@ ERROR;
                $out->addReturnTo( $this->getContextTitle(), [ 'action' => 'edit' ] );
        }
 
-       /**
-        * Filter an input field through a Unicode de-armoring process if it
-        * came from an old browser with known broken Unicode editing issues.
-        *
-        * @deprecated since 1.30, does nothing
-        *
-        * @param WebRequest $request
-        * @param string $field
-        * @return string
-        */
-       protected function safeUnicodeInput( $request, $field ) {
-               return rtrim( $request->getText( $field ) );
-       }
-
-       /**
-        * Filter an output field through a Unicode armoring process if it is
-        * going to an old browser with known broken Unicode editing issues.
-        *
-        * @deprecated since 1.30, does nothing
-        *
-        * @param string $text
-        * @return string
-        */
-       protected function safeUnicodeOutput( $text ) {
-               return $text;
-       }
-
        /**
         * @since 1.29
         */
@@ -4450,16 +4434,14 @@ ERROR;
                                        $lang->formatNum( $maxArticleSize )
                                ]
                        );
-               } else {
-                       if ( !$this->context->msg( 'longpage-hint' )->isDisabled() ) {
-                               $out->wrapWikiMsg( "<div id='mw-edit-longpage-hint'>\n$1\n</div>",
-                                       [
-                                               'longpage-hint',
-                                               $lang->formatSize( strlen( $this->textbox1 ) ),
-                                               strlen( $this->textbox1 )
-                                       ]
-                               );
-                       }
+               } elseif ( !$this->context->msg( 'longpage-hint' )->isDisabled() ) {
+                       $out->wrapWikiMsg( "<div id='mw-edit-longpage-hint'>\n$1\n</div>",
+                               [
+                                       'longpage-hint',
+                                       $lang->formatSize( strlen( $this->textbox1 ) ),
+                                       strlen( $this->textbox1 )
+                               ]
+                       );
                }
        }
 
@@ -4469,7 +4451,9 @@ ERROR;
        protected function addPageProtectionWarningHeaders() {
                $out = $this->context->getOutput();
                if ( $this->mTitle->isProtected( 'edit' ) &&
-                       MWNamespace::getRestrictionLevels( $this->mTitle->getNamespace() ) !== [ '' ]
+                       MediaWikiServices::getInstance()->getNamespaceInfo()->getRestrictionLevels(
+                               $this->mTitle->getNamespace()
+                       ) !== [ '' ]
                ) {
                        # Is the title semi-protected?
                        if ( $this->mTitle->isSemiProtected() ) {
@@ -4548,16 +4532,15 @@ ERROR;
         * @return string
         */
        private function guessSectionName( $text ) {
-               global $wgParser;
-
                // Detect Microsoft browsers
                $userAgent = $this->context->getRequest()->getHeader( 'User-Agent' );
+               $parser = MediaWikiServices::getInstance()->getParser();
                if ( $userAgent && preg_match( '/MSIE|Edge/', $userAgent ) ) {
                        // ...and redirect them to legacy encoding, if available
-                       return $wgParser->guessLegacySectionNameFromWikiText( $text );
+                       return $parser->guessLegacySectionNameFromWikiText( $text );
                }
                // Meanwhile, real browsers get real anchors
-               $name = $wgParser->guessSectionNameFromWikiText( $text );
+               $name = $parser->guessSectionNameFromWikiText( $text );
                // With one little caveat: per T216029, fragments in HTTP redirects need to be urlencoded,
                // otherwise Chrome double-escapes the rest of the URL.
                return '#' . urlencode( mb_substr( $name, 1 ) );
diff --git a/includes/Feed.php b/includes/Feed.php
deleted file mode 100644 (file)
index 86e9bee..0000000
+++ /dev/null
@@ -1,494 +0,0 @@
-<?php
-/**
- * Basic support for outputting syndication feeds in RSS, other formats.
- *
- * Contain a feed class as well as classes to build rss / atom ... feeds
- * Available feeds are defined in Defines.php
- *
- * Copyright © 2004 Brion Vibber <brion@pobox.com>
- * https://www.mediawiki.org/
- *
- * 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
- */
-
-/**
- * @defgroup Feed Feed
- */
-
-/**
- * A base class for basic support for outputting syndication feeds in RSS and other formats.
- *
- * @ingroup Feed
- */
-class FeedItem {
-       /** @var Title */
-       public $title;
-
-       public $description;
-
-       public $url;
-
-       public $date;
-
-       public $author;
-
-       public $uniqueId;
-
-       public $comments;
-
-       public $rssIsPermalink = false;
-
-       /**
-        * @param string|Title $title Item's title
-        * @param string $description
-        * @param string $url URL uniquely designating the item.
-        * @param string $date Item's date
-        * @param string $author Author's user name
-        * @param string $comments
-        */
-       function __construct( $title, $description, $url, $date = '', $author = '', $comments = '' ) {
-               $this->title = $title;
-               $this->description = $description;
-               $this->url = $url;
-               $this->uniqueId = $url;
-               $this->date = $date;
-               $this->author = $author;
-               $this->comments = $comments;
-       }
-
-       /**
-        * Encode $string so that it can be safely embedded in a XML document
-        *
-        * @param string $string String to encode
-        * @return string
-        */
-       public function xmlEncode( $string ) {
-               $string = str_replace( "\r\n", "\n", $string );
-               $string = preg_replace( '/[\x00-\x08\x0b\x0c\x0e-\x1f]/', '', $string );
-               return htmlspecialchars( $string );
-       }
-
-       /**
-        * Get the unique id of this item; already xml-encoded
-        * @return string
-        */
-       public function getUniqueID() {
-               $id = $this->getUniqueIdUnescaped();
-               if ( $id ) {
-                       return $this->xmlEncode( $id );
-               }
-       }
-
-       /**
-        * Get the unique id of this item, without any escaping
-        * @return string
-        */
-       public function getUniqueIdUnescaped() {
-               if ( $this->uniqueId ) {
-                       return wfExpandUrl( $this->uniqueId, PROTO_CURRENT );
-               }
-       }
-
-       /**
-        * Set the unique id of an item
-        *
-        * @param string $uniqueId Unique id for the item
-        * @param bool $rssIsPermalink Set to true if the guid (unique id) is a permalink (RSS feeds only)
-        */
-       public function setUniqueId( $uniqueId, $rssIsPermalink = false ) {
-               $this->uniqueId = $uniqueId;
-               $this->rssIsPermalink = $rssIsPermalink;
-       }
-
-       /**
-        * Get the title of this item; already xml-encoded
-        *
-        * @return string
-        */
-       public function getTitle() {
-               return $this->xmlEncode( $this->title );
-       }
-
-       /**
-        * Get the URL of this item; already xml-encoded
-        *
-        * @return string
-        */
-       public function getUrl() {
-               return $this->xmlEncode( $this->url );
-       }
-
-       /** Get the URL of this item without any escaping
-        *
-        * @return string
-        */
-       public function getUrlUnescaped() {
-               return $this->url;
-       }
-
-       /**
-        * Get the description of this item; already xml-encoded
-        *
-        * @return string
-        */
-       public function getDescription() {
-               return $this->xmlEncode( $this->description );
-       }
-
-       /**
-        * Get the description of this item without any escaping
-        *
-        * @return string
-        */
-       public function getDescriptionUnescaped() {
-               return $this->description;
-       }
-
-       /**
-        * Get the language of this item
-        *
-        * @return string
-        */
-       public function getLanguage() {
-               global $wgLanguageCode;
-               return LanguageCode::bcp47( $wgLanguageCode );
-       }
-
-       /**
-        * Get the date of this item
-        *
-        * @return string
-        */
-       public function getDate() {
-               return $this->date;
-       }
-
-       /**
-        * Get the author of this item; already xml-encoded
-        *
-        * @return string
-        */
-       public function getAuthor() {
-               return $this->xmlEncode( $this->author );
-       }
-
-       /**
-        * Get the author of this item without any escaping
-        *
-        * @return string
-        */
-       public function getAuthorUnescaped() {
-               return $this->author;
-       }
-
-       /**
-        * Get the comment of this item; already xml-encoded
-        *
-        * @return string
-        */
-       public function getComments() {
-               return $this->xmlEncode( $this->comments );
-       }
-
-       /**
-        * Get the comment of this item without any escaping
-        *
-        * @return string
-        */
-       public function getCommentsUnescaped() {
-               return $this->comments;
-       }
-
-       /**
-        * Quickie hack... strip out wikilinks to more legible form from the comment.
-        *
-        * @param string $text Wikitext
-        * @return string
-        */
-       public static function stripComment( $text ) {
-               return preg_replace( '/\[\[([^]]*\|)?([^]]+)\]\]/', '\2', $text );
-       }
-       /**#@-*/
-}
-
-/**
- * Class to support the outputting of syndication feeds in Atom and RSS format.
- *
- * @ingroup Feed
- */
-abstract class ChannelFeed extends FeedItem {
-
-       /** @var TemplateParser */
-       protected $templateParser;
-
-       /**
-        * @param string|Title $title Feed's title
-        * @param string $description
-        * @param string $url URL uniquely designating the feed.
-        * @param string $date Feed's date
-        * @param string $author Author's user name
-        * @param string $comments
-        */
-       function __construct( $title, $description, $url, $date = '', $author = '', $comments = '' ) {
-               parent::__construct( $title, $description, $url, $date, $author, $comments );
-               $this->templateParser = new TemplateParser();
-       }
-
-       /**
-        * Generate Header of the feed
-        * @par Example:
-        * @code
-        * print "<feed>";
-        * @endcode
-        */
-       abstract public function outHeader();
-
-       /**
-        * Generate an item
-        * @par Example:
-        * @code
-        * print "<item>...</item>";
-        * @endcode
-        * @param FeedItem $item
-        */
-       abstract public function outItem( $item );
-
-       /**
-        * Generate Footer of the feed
-        * @par Example:
-        * @code
-        * print "</feed>";
-        * @endcode
-        */
-       abstract public function outFooter();
-
-       /**
-        * Setup and send HTTP headers. Don't send any content;
-        * content might end up being cached and re-sent with
-        * these same headers later.
-        *
-        * This should be called from the outHeader() method,
-        * but can also be called separately.
-        */
-       public function httpHeaders() {
-               global $wgOut, $wgVaryOnXFP;
-
-               # We take over from $wgOut, excepting its cache header info
-               $wgOut->disable();
-               $mimetype = $this->contentType();
-               header( "Content-type: $mimetype; charset=UTF-8" );
-
-               // Set a sane filename
-               $exts = MediaWiki\MediaWikiServices::getInstance()->getMimeAnalyzer()
-                       ->getExtensionsForType( $mimetype );
-               $ext = $exts ? strtok( $exts, ' ' ) : 'xml';
-               header( "Content-Disposition: inline; filename=\"feed.{$ext}\"" );
-
-               if ( $wgVaryOnXFP ) {
-                       $wgOut->addVaryHeader( 'X-Forwarded-Proto' );
-               }
-               $wgOut->sendCacheControl();
-       }
-
-       /**
-        * Return an internet media type to be sent in the headers.
-        *
-        * @return string
-        */
-       private function contentType() {
-               global $wgRequest;
-
-               $ctype = $wgRequest->getVal( 'ctype', 'application/xml' );
-               $allowedctypes = [
-                       'application/xml',
-                       'text/xml',
-                       'application/rss+xml',
-                       'application/atom+xml'
-               ];
-
-               return ( in_array( $ctype, $allowedctypes ) ? $ctype : 'application/xml' );
-       }
-
-       /**
-        * Output the initial XML headers.
-        */
-       protected function outXmlHeader() {
-               $this->httpHeaders();
-               echo '<?xml version="1.0"?>' . "\n";
-       }
-}
-
-/**
- * Generate a RSS feed
- *
- * @ingroup Feed
- */
-class RSSFeed extends ChannelFeed {
-
-       /**
-        * Format a date given a timestamp. If a timestamp is not given, nothing is returned
-        *
-        * @param int|null $ts Timestamp
-        * @return string|null Date string
-        */
-       function formatTime( $ts ) {
-               if ( $ts ) {
-                       return gmdate( 'D, d M Y H:i:s \G\M\T', wfTimestamp( TS_UNIX, $ts ) );
-               }
-       }
-
-       /**
-        * Output an RSS 2.0 header
-        */
-       function outHeader() {
-               global $wgVersion;
-
-               $this->outXmlHeader();
-               // Manually escaping rather than letting Mustache do it because Mustache
-               // uses htmlentities, which does not work with XML
-               $templateParams = [
-                       'title' => $this->getTitle(),
-                       'url' => $this->xmlEncode( wfExpandUrl( $this->getUrlUnescaped(), PROTO_CURRENT ) ),
-                       'description' => $this->getDescription(),
-                       'language' => $this->xmlEncode( $this->getLanguage() ),
-                       'version' => $this->xmlEncode( $wgVersion ),
-                       'timestamp' => $this->xmlEncode( $this->formatTime( wfTimestampNow() ) )
-               ];
-               print $this->templateParser->processTemplate( 'RSSHeader', $templateParams );
-       }
-
-       /**
-        * Output an RSS 2.0 item
-        * @param FeedItem $item Item to be output
-        */
-       function outItem( $item ) {
-               // Manually escaping rather than letting Mustache do it because Mustache
-               // uses htmlentities, which does not work with XML
-               $templateParams = [
-                       "title" => $item->getTitle(),
-                       "url" => $this->xmlEncode( wfExpandUrl( $item->getUrlUnescaped(), PROTO_CURRENT ) ),
-                       "permalink" => $item->rssIsPermalink,
-                       "uniqueID" => $item->getUniqueID(),
-                       "description" => $item->getDescription(),
-                       "date" => $this->xmlEncode( $this->formatTime( $item->getDate() ) ),
-                       "author" => $item->getAuthor()
-               ];
-               $comments = $item->getCommentsUnescaped();
-               if ( $comments ) {
-                       $commentsEscaped = $this->xmlEncode( wfExpandUrl( $comments, PROTO_CURRENT ) );
-                       $templateParams["comments"] = $commentsEscaped;
-               }
-               print $this->templateParser->processTemplate( 'RSSItem', $templateParams );
-       }
-
-       /**
-        * Output an RSS 2.0 footer
-        */
-       function outFooter() {
-               print "</channel></rss>";
-       }
-}
-
-/**
- * Generate an Atom feed
- *
- * @ingroup Feed
- */
-class AtomFeed extends ChannelFeed {
-       /**
-        * Format a date given timestamp, if one is given.
-        *
-        * @param string|int|null $timestamp
-        * @return string|null
-        */
-       function formatTime( $timestamp ) {
-               if ( $timestamp ) {
-                       // need to use RFC 822 time format at least for rss2.0
-                       return gmdate( 'Y-m-d\TH:i:s', wfTimestamp( TS_UNIX, $timestamp ) );
-               }
-       }
-
-       /**
-        * Outputs a basic header for Atom 1.0 feeds.
-        */
-       function outHeader() {
-               global $wgVersion;
-               $this->outXmlHeader();
-               // Manually escaping rather than letting Mustache do it because Mustache
-               // uses htmlentities, which does not work with XML
-               $templateParams = [
-                       'language' => $this->xmlEncode( $this->getLanguage() ),
-                       'feedID' => $this->getFeedId(),
-                       'title' => $this->getTitle(),
-                       'url' => $this->xmlEncode( wfExpandUrl( $this->getUrlUnescaped(), PROTO_CURRENT ) ),
-                       'selfUrl' => $this->getSelfUrl(),
-                       'timestamp' => $this->xmlEncode( $this->formatTime( wfTimestampNow() ) ),
-                       'description' => $this->getDescription(),
-                       'version' => $this->xmlEncode( $wgVersion ),
-               ];
-               print $this->templateParser->processTemplate( 'AtomHeader', $templateParams );
-       }
-
-       /**
-        * Atom 1.0 requires a unique, opaque IRI as a unique identifier
-        * for every feed we create. For now just use the URL, but who
-        * can tell if that's right? If we put options on the feed, do we
-        * have to change the id? Maybe? Maybe not.
-        *
-        * @return string
-        */
-       private function getFeedId() {
-               return $this->getSelfUrl();
-       }
-
-       /**
-        * Atom 1.0 requests a self-reference to the feed.
-        * @return string
-        */
-       private function getSelfUrl() {
-               global $wgRequest;
-               return htmlspecialchars( $wgRequest->getFullRequestURL() );
-       }
-
-       /**
-        * Output a given item.
-        * @param FeedItem $item
-        */
-       function outItem( $item ) {
-               global $wgMimeType;
-               // Manually escaping rather than letting Mustache do it because Mustache
-               // uses htmlentities, which does not work with XML
-               $templateParams = [
-                       "uniqueID" => $item->getUniqueID(),
-                       "title" => $item->getTitle(),
-                       "mimeType" => $this->xmlEncode( $wgMimeType ),
-                       "url" => $this->xmlEncode( wfExpandUrl( $item->getUrlUnescaped(), PROTO_CURRENT ) ),
-                       "date" => $this->xmlEncode( $this->formatTime( $item->getDate() ) ),
-                       "description" => $item->getDescription(),
-                       "author" => $item->getAuthor()
-               ];
-               print $this->templateParser->processTemplate( 'AtomItem', $templateParams );
-       }
-
-       /**
-        * Outputs the footer for Atom 1.0 feed (basically '\</feed\>').
-        */
-       function outFooter() {
-               print "</feed>";
-       }
-}
index e0d088a..dddbad5 100644 (file)
@@ -30,10 +30,12 @@ class ForeignResourceManager {
        private $registryFile;
        private $libDir;
        private $tmpParentDir;
+       private $cacheDir;
        private $infoPrinter;
        private $errorPrinter;
        private $verbosePrinter;
        private $action;
+       private $registry;
 
        /**
         * @param string $registryFile Path to YAML file
@@ -60,8 +62,11 @@ class ForeignResourceManager {
 
                // Use a temporary directory under the destination directory instead
                // of wfTempDir() because PHP's rename() does not work across file
-               // systems, as the user's /tmp and $IP may be on different filesystems.
-               $this->tmpParentDir = "{$this->libDir}/.tmp";
+               // systems, and the user's /tmp and $IP may be on different filesystems.
+               $this->tmpParentDir = "{$this->libDir}/.foreign/tmp";
+
+               $cacheHome = getenv( 'XDG_CACHE_HOME' ) ? realpath( getenv( 'XDG_CACHE_HOME' ) ) : false;
+               $this->cacheDir = $cacheHome ? "$cacheHome/mw-foreign" : "{$this->libDir}/.foreign/cache";
        }
 
        /**
@@ -69,18 +74,24 @@ class ForeignResourceManager {
         * @throws Exception
         */
        public function run( $action, $module ) {
-               if ( !in_array( $action, [ 'update', 'verify', 'make-sri' ] ) ) {
-                       throw new Exception( 'Invalid action parameter.' );
+               $actions = [ 'update', 'verify', 'make-sri' ];
+               if ( !in_array( $action, $actions ) ) {
+                       $this->error( "Invalid action.\n\nMust be one of " . implode( ', ', $actions ) . '.' );
+                       return false;
                }
                $this->action = $action;
 
-               $registry = $this->parseBasicYaml( file_get_contents( $this->registryFile ) );
+               $this->registry = $this->parseBasicYaml( file_get_contents( $this->registryFile ) );
                if ( $module === 'all' ) {
-                       $modules = $registry;
-               } elseif ( isset( $registry[ $module ] ) ) {
-                       $modules = [ $module => $registry[ $module ] ];
+                       $modules = $this->registry;
+               } elseif ( isset( $this->registry[ $module ] ) ) {
+                       $modules = [ $module => $this->registry[ $module ] ];
                } else {
-                       throw new Exception( 'Unknown module name.' );
+                       $this->error( "Unknown module name.\n\nMust be one of:\n" .
+                               wordwrap( implode( ', ', array_keys( $this->registry ) ), 80 ) .
+                               '.'
+                       );
+                       return false;
                }
 
                foreach ( $modules as $moduleName => $info ) {
@@ -121,8 +132,8 @@ class ForeignResourceManager {
                        }
                }
 
-               $this->cleanUp();
                $this->output( "\nDone!\n" );
+               $this->cleanUp();
                if ( $this->hasErrors ) {
                        // The verify mode should check all modules/files and fail after, not during.
                        return false;
@@ -131,7 +142,29 @@ class ForeignResourceManager {
                return true;
        }
 
+       private function cacheKey( $src, $integrity ) {
+               $key = basename( $src ) . '_' . substr( $integrity, -12 );
+               $key = preg_replace( '/[.\/+?=_-]+/', '_', $key );
+               return rtrim( $key, '_' );
+       }
+
+       /** @return string|false */
+       private function cacheGet( $key ) {
+               return Wikimedia\quietCall( 'file_get_contents', "{$this->cacheDir}/$key.data" );
+       }
+
+       private function cacheSet( $key, $data ) {
+               wfMkdirParents( $this->cacheDir );
+               file_put_contents( "{$this->cacheDir}/$key.data", $data, LOCK_EX );
+       }
+
        private function fetch( $src, $integrity ) {
+               $key = $this->cacheKey( $src, $integrity );
+               $data = $this->cacheGet( $key );
+               if ( $data ) {
+                       return $data;
+               }
+
                $req = MWHttpRequest::factory( $src, [ 'method' => 'GET', 'followRedirects' => false ] );
                if ( !$req->execute()->isOK() ) {
                        throw new Exception( "Failed to download resource at {$src}" );
@@ -144,15 +177,14 @@ class ForeignResourceManager {
                $actualIntegrity = $algo . '-' . base64_encode( hash( $algo, $data, true ) );
                if ( $integrity === $actualIntegrity ) {
                        $this->verbose( "... passed integrity check for {$src}\n" );
+                       $this->cacheSet( $key, $data );
+               } elseif ( $this->action === 'make-sri' ) {
+                       $this->output( "Integrity for {$src}\n\tintegrity: ${actualIntegrity}\n" );
                } else {
-                       if ( $this->action === 'make-sri' ) {
-                               $this->output( "Integrity for {$src}\n\tintegrity: ${actualIntegrity}\n" );
-                       } else {
-                               throw new Exception( "Integrity check failed for {$src}\n" .
-                                       "\tExpected: {$integrity}\n" .
-                                       "\tActual: {$actualIntegrity}"
-                               );
-                       }
+                       throw new Exception( "Integrity check failed for {$src}\n" .
+                               "\tExpected: {$integrity}\n" .
+                               "\tActual: {$actualIntegrity}"
+                       );
                }
                return $data;
        }
@@ -271,6 +303,23 @@ class ForeignResourceManager {
 
        private function cleanUp() {
                wfRecursiveRemoveDir( $this->tmpParentDir );
+
+               // Prune the cache of files we don't recognise.
+               $knownKeys = [];
+               foreach ( $this->registry as $info ) {
+                       if ( $info['type'] === 'file' || $info['type'] === 'tar' ) {
+                               $knownKeys[] = $this->cacheKey( $info['src'], $info['integrity'] );
+                       } elseif ( $info['type'] === 'multi-file' ) {
+                               foreach ( $info['files'] as $file ) {
+                                       $knownKeys[] = $this->cacheKey( $file['src'], $file['integrity'] );
+                               }
+                       }
+               }
+               foreach ( glob( "{$this->cacheDir}/*" ) as $cacheFile ) {
+                       if ( !in_array( basename( $cacheFile, '.data' ), $knownKeys ) ) {
+                               unlink( $cacheFile );
+                       }
+               }
        }
 
        /**
index cc16964..85f3a7d 100644 (file)
@@ -123,6 +123,7 @@ class ForkController {
                                pcntl_signal_dispatch();
                        } else {
                                declare( ticks = 1 ) {
+                                       // @phan-suppress-next-line PhanPluginDuplicateExpressionAssignment
                                        $status = $status;
                                }
                        }
index 53ddac9..0131855 100644 (file)
@@ -381,9 +381,10 @@ class FormOptions implements ArrayAccess {
 
        /** @name ArrayAccess functions
         * These functions implement the ArrayAccess PHP interface.
-        * @see https://secure.php.net/manual/en/class.arrayaccess.php
+        * @see https://www.php.net/manual/en/class.arrayaccess.php
         */
        /* @{ */
+
        /**
         * Whether the option exists.
         * @param string $name
index 319bf63..7256eab 100644 (file)
@@ -24,13 +24,15 @@ if ( !defined( 'MEDIAWIKI' ) ) {
        die( "This file is part of MediaWiki, it is not a valid entry point" );
 }
 
+use MediaWiki\Linker\LinkTarget;
 use MediaWiki\Logger\LoggerFactory;
+use MediaWiki\MediaWikiServices;
 use MediaWiki\ProcOpenError;
 use MediaWiki\Session\SessionManager;
-use MediaWiki\MediaWikiServices;
 use MediaWiki\Shell\Shell;
 use Wikimedia\ScopedCallback;
 use Wikimedia\WrappedString;
+use Wikimedia\AtEase\AtEase;
 
 /**
  * Load an extension
@@ -139,32 +141,6 @@ function wfArrayDiff2_cmp( $a, $b ) {
        }
 }
 
-/**
- * @deprecated since 1.32, use array_filter() with ARRAY_FILTER_USE_BOTH directly
- *
- * @param array $arr
- * @param callable $callback Will be called with the array value and key (in that order) and
- *   should return a bool which will determine whether the array element is kept.
- * @return array
- */
-function wfArrayFilter( array $arr, callable $callback ) {
-       wfDeprecated( __FUNCTION__, '1.32' );
-       return array_filter( $arr, $callback, ARRAY_FILTER_USE_BOTH );
-}
-
-/**
- * @deprecated since 1.32, use array_filter() with ARRAY_FILTER_USE_KEY directly
- *
- * @param array $arr
- * @param callable $callback Will be called with the array key and should return a bool which
- *   will determine whether the array element is kept.
- * @return array
- */
-function wfArrayFilterByKey( array $arr, callable $callback ) {
-       wfDeprecated( __FUNCTION__, '1.32' );
-       return array_filter( $arr, $callback, ARRAY_FILTER_USE_KEY );
-}
-
 /**
  * Appends to second array if $value differs from that in $default
  *
@@ -334,6 +310,7 @@ function wfUrlencode( $s ) {
        static $needle;
 
        if ( is_null( $s ) ) {
+               // Reset $needle for testing.
                $needle = null;
                return '';
        }
@@ -823,9 +800,9 @@ function wfParseUrl( $url ) {
        if ( $wasRelative ) {
                $url = "http:$url";
        }
-       Wikimedia\suppressWarnings();
+       AtEase::suppressWarnings();
        $bits = parse_url( $url );
-       Wikimedia\restoreWarnings();
+       AtEase::restoreWarnings();
        // parse_url() returns an array without scheme for some invalid URLs, e.g.
        // parse_url("%0Ahttp://example.com") == [ 'host' => '%0Ahttp', 'path' => 'example.com' ]
        if ( !$bits || !isset( $bits['scheme'] ) ) {
@@ -893,18 +870,6 @@ function wfExpandIRI( $url ) {
        );
 }
 
-/**
- * Make URL indexes, appropriate for the el_index field of externallinks.
- *
- * @deprecated since 1.33, use LinkFilter::makeIndexes() instead
- * @param string $url
- * @return array
- */
-function wfMakeUrlIndexes( $url ) {
-       wfDeprecated( __FUNCTION__, '1.33' );
-       return LinkFilter::makeIndexes( $url );
-}
-
 /**
  * Check whether a given URL has a domain that occurs in a given set of domains
  * @param string $url
@@ -1749,13 +1714,11 @@ function wfResetOutputBuffers( $resetGzipEncoding = true ) {
                        // to avoid getting in some kind of infinite loop.
                        break;
                }
-               if ( $resetGzipEncoding ) {
-                       if ( $status['name'] == 'ob_gzhandler' ) {
-                               // Reset the 'Content-Encoding' field set by this handler
-                               // so we can start fresh.
-                               header_remove( 'Content-Encoding' );
-                               break;
-                       }
+               if ( $resetGzipEncoding && $status['name'] == 'ob_gzhandler' ) {
+                       // Reset the 'Content-Encoding' field set by this handler
+                       // so we can start fresh.
+                       header_remove( 'Content-Encoding' );
+                       break;
                }
        }
 }
@@ -1884,24 +1847,6 @@ function wfNegotiateType( $cprefs, $sprefs ) {
        return $besttype;
 }
 
-/**
- * Reference-counted warning suppression
- *
- * @deprecated since 1.26, use Wikimedia\suppressWarnings() directly
- * @param bool $end
- */
-function wfSuppressWarnings( $end = false ) {
-       Wikimedia\suppressWarnings( $end );
-}
-
-/**
- * @deprecated since 1.26, use Wikimedia\restoreWarnings() directly
- * Restore error level to previous value
- */
-function wfRestoreWarnings() {
-       Wikimedia\restoreWarnings();
-}
-
 /**
  * Get a timestamp string in one of various formats
  *
@@ -2028,9 +1973,9 @@ function wfMkdirParents( $dir, $mode = null, $caller = null ) {
        }
 
        // Turn off the normal warning, we're doing our own below
-       Wikimedia\suppressWarnings();
+       AtEase::suppressWarnings();
        $ok = mkdir( $dir, $mode, true ); // PHP5 <3
-       Wikimedia\restoreWarnings();
+       AtEase::restoreWarnings();
 
        if ( !$ok ) {
                // directory may have been created on another request since we last checked
@@ -2051,7 +1996,7 @@ function wfMkdirParents( $dir, $mode = null, $caller = null ) {
  */
 function wfRecursiveRemoveDir( $dir ) {
        wfDebug( __FUNCTION__ . "( $dir )\n" );
-       // taken from https://secure.php.net/manual/en/function.rmdir.php#98622
+       // taken from https://www.php.net/manual/en/function.rmdir.php#98622
        if ( is_dir( $dir ) ) {
                $objects = scandir( $dir );
                foreach ( $objects as $object ) {
@@ -2137,7 +2082,7 @@ function wfStringToBool( $val ) {
  * @param string|string[] ...$args strings to escape and glue together,
  *  or a single array of strings parameter
  * @return string
- * @deprecated since 1.30 use MediaWiki\Shell::escape()
+ * @deprecated since 1.30 use MediaWiki\Shell\Shell::escape()
  */
 function wfEscapeShellArg( ...$args ) {
        return Shell::escape( ...$args );
@@ -2268,9 +2213,9 @@ function wfMerge( $old, $mine, $yours, &$result, &$mergeAttemptResult = null ) {
 
        # This check may also protect against code injection in
        # case of broken installations.
-       Wikimedia\suppressWarnings();
+       AtEase::suppressWarnings();
        $haveDiff3 = $wgDiff3 && file_exists( $wgDiff3 );
-       Wikimedia\restoreWarnings();
+       AtEase::restoreWarnings();
 
        if ( !$haveDiff3 ) {
                wfDebug( "diff3 not found\n" );
@@ -2352,9 +2297,9 @@ function wfDiff( $before, $after, $params = '-u' ) {
        }
 
        global $wgDiff;
-       Wikimedia\suppressWarnings();
+       AtEase::suppressWarnings();
        $haveDiff = $wgDiff && file_exists( $wgDiff );
-       Wikimedia\restoreWarnings();
+       AtEase::restoreWarnings();
 
        # This check may also protect against code injection in
        # case of broken installations.
@@ -2530,7 +2475,7 @@ function wfSetupSession( $sessionId = false ) {
        if ( session_id() !== $session->getId() ) {
                session_id( $session->getId() );
        }
-       Wikimedia\quietCall( 'session_start' );
+       AtEase::quietCall( 'session_start' );
 }
 
 /**
@@ -2609,22 +2554,6 @@ function wfWikiID() {
        }
 }
 
-/**
- * Split a wiki ID into DB name and table prefix
- *
- * @param string $wiki
- *
- * @return array
- * @deprecated 1.32
- */
-function wfSplitWikiID( $wiki ) {
-       $bits = explode( '-', $wiki, 2 );
-       if ( count( $bits ) < 2 ) {
-               $bits[] = '';
-       }
-       return $bits;
-}
-
 /**
  * Get a Database object.
  *
@@ -2676,34 +2605,36 @@ function wfGetLB( $wiki = false ) {
  * Get the load balancer factory object
  *
  * @deprecated since 1.27, use MediaWikiServices::getInstance()->getDBLoadBalancerFactory() instead.
+ * TODO: Remove in MediaWiki 1.35
  *
  * @return \Wikimedia\Rdbms\LBFactory
  */
 function wfGetLBFactory() {
+       wfDeprecated( __METHOD__, '1.27' );
        return MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
 }
 
 /**
  * Find a file.
- * Shortcut for RepoGroup::singleton()->findFile()
- *
- * @param string|Title $title String or Title object
+ * @deprecated since 1.34, use MediaWikiServices
+ * @param string|LinkTarget $title String or LinkTarget object
  * @param array $options Associative array of options (see RepoGroup::findFile)
  * @return File|bool File, or false if the file does not exist
  */
 function wfFindFile( $title, $options = [] ) {
-       return RepoGroup::singleton()->findFile( $title, $options );
+       return MediaWikiServices::getInstance()->getRepoGroup()->findFile( $title, $options );
 }
 
 /**
  * Get an object referring to a locally registered file.
  * Returns a valid placeholder object if the file does not exist.
  *
+ * @deprecated since 1.34, use MediaWikiServices
  * @param Title|string $title
  * @return LocalFile|null A File, or null if passed an invalid Title
  */
 function wfLocalFile( $title ) {
-       return RepoGroup::singleton()->getLocalRepo()->newFile( $title );
+       return MediaWikiServices::getInstance()->getRepoGroup()->getLocalRepo()->newFile( $title );
 }
 
 /**
diff --git a/includes/HistoryBlob.php b/includes/HistoryBlob.php
deleted file mode 100644 (file)
index bca6c7e..0000000
+++ /dev/null
@@ -1,711 +0,0 @@
-<?php
-/**
- * Efficient concatenated text storage.
- *
- * 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
- */
-
-/**
- * Base class for general text storage via the "object" flag in old_flags, or
- * two-part external storage URLs. Used for represent efficient concatenated
- * storage, and migration-related pointer objects.
- */
-interface HistoryBlob {
-       /**
-        * Adds an item of text, returns a stub object which points to the item.
-        * You must call setLocation() on the stub object before storing it to the
-        * database
-        *
-        * @param string $text
-        *
-        * @return string The key for getItem()
-        */
-       function addItem( $text );
-
-       /**
-        * Get item by key, or false if the key is not present
-        *
-        * @param string $key
-        *
-        * @return string|bool
-        */
-       function getItem( $key );
-
-       /**
-        * Set the "default text"
-        * This concept is an odd property of the current DB schema, whereby each text item has a revision
-        * associated with it. The default text is the text of the associated revision. There may, however,
-        * be other revisions in the same object.
-        *
-        * Default text is not required for two-part external storage URLs.
-        *
-        * @param string $text
-        */
-       function setText( $text );
-
-       /**
-        * Get default text. This is called from Revision::getRevisionText()
-        *
-        * @return string
-        */
-       function getText();
-}
-
-/**
- * Concatenated gzip (CGZ) storage
- * Improves compression ratio by concatenating like objects before gzipping
- */
-class ConcatenatedGzipHistoryBlob implements HistoryBlob {
-       public $mVersion = 0, $mCompressed = false, $mItems = [], $mDefaultHash = '';
-       public $mSize = 0;
-       public $mMaxSize = 10000000;
-       public $mMaxCount = 100;
-
-       public function __construct() {
-               if ( !function_exists( 'gzdeflate' ) ) {
-                       throw new MWException( "Need zlib support to read or write this "
-                               . "kind of history object (ConcatenatedGzipHistoryBlob)\n" );
-               }
-       }
-
-       /**
-        * @param string $text
-        * @return string
-        */
-       public function addItem( $text ) {
-               $this->uncompress();
-               $hash = md5( $text );
-               if ( !isset( $this->mItems[$hash] ) ) {
-                       $this->mItems[$hash] = $text;
-                       $this->mSize += strlen( $text );
-               }
-               return $hash;
-       }
-
-       /**
-        * @param string $hash
-        * @return array|bool
-        */
-       public function getItem( $hash ) {
-               $this->uncompress();
-               if ( array_key_exists( $hash, $this->mItems ) ) {
-                       return $this->mItems[$hash];
-               } else {
-                       return false;
-               }
-       }
-
-       /**
-        * @param string $text
-        * @return void
-        */
-       public function setText( $text ) {
-               $this->uncompress();
-               $this->mDefaultHash = $this->addItem( $text );
-       }
-
-       /**
-        * @return array|bool
-        */
-       public function getText() {
-               $this->uncompress();
-               return $this->getItem( $this->mDefaultHash );
-       }
-
-       /**
-        * Remove an item
-        *
-        * @param string $hash
-        */
-       public function removeItem( $hash ) {
-               $this->mSize -= strlen( $this->mItems[$hash] );
-               unset( $this->mItems[$hash] );
-       }
-
-       /**
-        * Compress the bulk data in the object
-        */
-       public function compress() {
-               if ( !$this->mCompressed ) {
-                       $this->mItems = gzdeflate( serialize( $this->mItems ) );
-                       $this->mCompressed = true;
-               }
-       }
-
-       /**
-        * Uncompress bulk data
-        */
-       public function uncompress() {
-               if ( $this->mCompressed ) {
-                       $this->mItems = unserialize( gzinflate( $this->mItems ) );
-                       $this->mCompressed = false;
-               }
-       }
-
-       /**
-        * @return array
-        */
-       function __sleep() {
-               $this->compress();
-               return [ 'mVersion', 'mCompressed', 'mItems', 'mDefaultHash' ];
-       }
-
-       function __wakeup() {
-               $this->uncompress();
-       }
-
-       /**
-        * Helper function for compression jobs
-        * Returns true until the object is "full" and ready to be committed
-        *
-        * @return bool
-        */
-       public function isHappy() {
-               return $this->mSize < $this->mMaxSize
-                       && count( $this->mItems ) < $this->mMaxCount;
-       }
-}
-
-/**
- * Pointer object for an item within a CGZ blob stored in the text table.
- */
-class HistoryBlobStub {
-       /**
-        * @var array One-step cache variable to hold base blobs; operations that
-        * pull multiple revisions may often pull multiple times from the same
-        * blob. By keeping the last-used one open, we avoid redundant
-        * unserialization and decompression overhead.
-        */
-       protected static $blobCache = [];
-
-       /** @var int */
-       public $mOldId;
-
-       /** @var string */
-       public $mHash;
-
-       /** @var string */
-       public $mRef;
-
-       /**
-        * @param string $hash The content hash of the text
-        * @param int $oldid The old_id for the CGZ object
-        */
-       function __construct( $hash = '', $oldid = 0 ) {
-               $this->mHash = $hash;
-       }
-
-       /**
-        * Sets the location (old_id) of the main object to which this object
-        * points
-        * @param int $id
-        */
-       function setLocation( $id ) {
-               $this->mOldId = $id;
-       }
-
-       /**
-        * Sets the location (old_id) of the referring object
-        * @param string $id
-        */
-       function setReferrer( $id ) {
-               $this->mRef = $id;
-       }
-
-       /**
-        * Gets the location of the referring object
-        * @return string
-        */
-       function getReferrer() {
-               return $this->mRef;
-       }
-
-       /**
-        * @return string|false
-        */
-       function getText() {
-               if ( isset( self::$blobCache[$this->mOldId] ) ) {
-                       $obj = self::$blobCache[$this->mOldId];
-               } else {
-                       $dbr = wfGetDB( DB_REPLICA );
-                       $row = $dbr->selectRow(
-                               'text',
-                               [ 'old_flags', 'old_text' ],
-                               [ 'old_id' => $this->mOldId ]
-                       );
-
-                       if ( !$row ) {
-                               return false;
-                       }
-
-                       $flags = explode( ',', $row->old_flags );
-                       if ( in_array( 'external', $flags ) ) {
-                               $url = $row->old_text;
-                               $parts = explode( '://', $url, 2 );
-                               if ( !isset( $parts[1] ) || $parts[1] == '' ) {
-                                       return false;
-                               }
-                               $row->old_text = ExternalStore::fetchFromURL( $url );
-
-                       }
-
-                       if ( !in_array( 'object', $flags ) ) {
-                               return false;
-                       }
-
-                       if ( in_array( 'gzip', $flags ) ) {
-                               // This shouldn't happen, but a bug in the compress script
-                               // may at times gzip-compress a HistoryBlob object row.
-                               $obj = unserialize( gzinflate( $row->old_text ) );
-                       } else {
-                               $obj = unserialize( $row->old_text );
-                       }
-
-                       if ( !is_object( $obj ) ) {
-                               // Correct for old double-serialization bug.
-                               $obj = unserialize( $obj );
-                       }
-
-                       // Save this item for reference; if pulling many
-                       // items in a row we'll likely use it again.
-                       $obj->uncompress();
-                       self::$blobCache = [ $this->mOldId => $obj ];
-               }
-
-               return $obj->getItem( $this->mHash );
-       }
-
-       /**
-        * Get the content hash
-        *
-        * @return string
-        */
-       function getHash() {
-               return $this->mHash;
-       }
-}
-
-/**
- * To speed up conversion from 1.4 to 1.5 schema, text rows can refer to the
- * leftover cur table as the backend. This avoids expensively copying hundreds
- * of megabytes of data during the conversion downtime.
- *
- * Serialized HistoryBlobCurStub objects will be inserted into the text table
- * on conversion if $wgLegacySchemaConversion is set to true.
- */
-class HistoryBlobCurStub {
-       /** @var int */
-       public $mCurId;
-
-       /**
-        * @param int $curid The cur_id pointed to
-        */
-       function __construct( $curid = 0 ) {
-               $this->mCurId = $curid;
-       }
-
-       /**
-        * Sets the location (cur_id) of the main object to which this object
-        * points
-        *
-        * @param int $id
-        */
-       function setLocation( $id ) {
-               $this->mCurId = $id;
-       }
-
-       /**
-        * @return string|bool
-        */
-       function getText() {
-               $dbr = wfGetDB( DB_REPLICA );
-               $row = $dbr->selectRow( 'cur', [ 'cur_text' ], [ 'cur_id' => $this->mCurId ] );
-               if ( !$row ) {
-                       return false;
-               }
-               return $row->cur_text;
-       }
-}
-
-/**
- * Diff-based history compression
- * Requires xdiff 1.5+ and zlib
- */
-class DiffHistoryBlob implements HistoryBlob {
-       /** @var array Uncompressed item cache */
-       public $mItems = [];
-
-       /** @var int Total uncompressed size */
-       public $mSize = 0;
-
-       /**
-        * @var array Array of diffs. If a diff D from A to B is notated D = B - A,
-        * and Z is an empty string:
-        *
-        *              { item[map[i]] - item[map[i-1]]   where i > 0
-        *    diff[i] = {
-        *              { item[map[i]] - Z                where i = 0
-        */
-       public $mDiffs;
-
-       /** @var array The diff map, see above */
-       public $mDiffMap;
-
-       /** @var int The key for getText()
-        */
-       public $mDefaultKey;
-
-       /** @var string Compressed storage */
-       public $mCompressed;
-
-       /** @var bool True if the object is locked against further writes */
-       public $mFrozen = false;
-
-       /**
-        * @var int The maximum uncompressed size before the object becomes sad
-        * Should be less than max_allowed_packet
-        */
-       public $mMaxSize = 10000000;
-
-       /** @var int The maximum number of text items before the object becomes sad */
-       public $mMaxCount = 100;
-
-       /** Constants from xdiff.h */
-       const XDL_BDOP_INS = 1;
-       const XDL_BDOP_CPY = 2;
-       const XDL_BDOP_INSB = 3;
-
-       function __construct() {
-               if ( !function_exists( 'gzdeflate' ) ) {
-                       throw new MWException( "Need zlib support to read or write DiffHistoryBlob\n" );
-               }
-       }
-
-       /**
-        * @throws MWException
-        * @param string $text
-        * @return int
-        */
-       function addItem( $text ) {
-               if ( $this->mFrozen ) {
-                       throw new MWException( __METHOD__ . ": Cannot add more items after sleep/wakeup" );
-               }
-
-               $this->mItems[] = $text;
-               $this->mSize += strlen( $text );
-               $this->mDiffs = null; // later
-               return count( $this->mItems ) - 1;
-       }
-
-       /**
-        * @param string $key
-        * @return string
-        */
-       function getItem( $key ) {
-               return $this->mItems[$key];
-       }
-
-       /**
-        * @param string $text
-        */
-       function setText( $text ) {
-               $this->mDefaultKey = $this->addItem( $text );
-       }
-
-       /**
-        * @return string
-        */
-       function getText() {
-               return $this->getItem( $this->mDefaultKey );
-       }
-
-       /**
-        * @throws MWException
-        */
-       function compress() {
-               if ( !function_exists( 'xdiff_string_rabdiff' ) ) {
-                       throw new MWException( "Need xdiff 1.5+ support to write DiffHistoryBlob\n" );
-               }
-               if ( isset( $this->mDiffs ) ) {
-                       // Already compressed
-                       return;
-               }
-               if ( $this->mItems === [] ) {
-                       return;
-               }
-
-               // Create two diff sequences: one for main text and one for small text
-               $sequences = [
-                       'small' => [
-                               'tail' => '',
-                               'diffs' => [],
-                               'map' => [],
-                       ],
-                       'main' => [
-                               'tail' => '',
-                               'diffs' => [],
-                               'map' => [],
-                       ],
-               ];
-               $smallFactor = 0.5;
-
-               $mItemsCount = count( $this->mItems );
-               for ( $i = 0; $i < $mItemsCount; $i++ ) {
-                       $text = $this->mItems[$i];
-                       if ( $i == 0 ) {
-                               $seqName = 'main';
-                       } else {
-                               $mainTail = $sequences['main']['tail'];
-                               if ( strlen( $text ) < strlen( $mainTail ) * $smallFactor ) {
-                                       $seqName = 'small';
-                               } else {
-                                       $seqName = 'main';
-                               }
-                       }
-                       $seq =& $sequences[$seqName];
-                       $tail = $seq['tail'];
-                       $diff = $this->diff( $tail, $text );
-                       $seq['diffs'][] = $diff;
-                       $seq['map'][] = $i;
-                       $seq['tail'] = $text;
-               }
-               unset( $seq ); // unlink dangerous alias
-
-               // Knit the sequences together
-               $tail = '';
-               $this->mDiffs = [];
-               $this->mDiffMap = [];
-               foreach ( $sequences as $seq ) {
-                       if ( $seq['diffs'] === [] ) {
-                               continue;
-                       }
-                       if ( $tail === '' ) {
-                               $this->mDiffs[] = $seq['diffs'][0];
-                       } else {
-                               $head = $this->patch( '', $seq['diffs'][0] );
-                               $this->mDiffs[] = $this->diff( $tail, $head );
-                       }
-                       $this->mDiffMap[] = $seq['map'][0];
-                       $diffsCount = count( $seq['diffs'] );
-                       for ( $i = 1; $i < $diffsCount; $i++ ) {
-                               $this->mDiffs[] = $seq['diffs'][$i];
-                               $this->mDiffMap[] = $seq['map'][$i];
-                       }
-                       $tail = $seq['tail'];
-               }
-       }
-
-       /**
-        * @param string $t1
-        * @param string $t2
-        * @return string
-        */
-       function diff( $t1, $t2 ) {
-               # Need to do a null concatenation with warnings off, due to bugs in the current version of xdiff
-               # "String is not zero-terminated"
-               Wikimedia\suppressWarnings();
-               $diff = xdiff_string_rabdiff( $t1, $t2 ) . '';
-               Wikimedia\restoreWarnings();
-               return $diff;
-       }
-
-       /**
-        * @param string $base
-        * @param string $diff
-        * @return bool|string
-        */
-       function patch( $base, $diff ) {
-               if ( function_exists( 'xdiff_string_bpatch' ) ) {
-                       Wikimedia\suppressWarnings();
-                       $text = xdiff_string_bpatch( $base, $diff ) . '';
-                       Wikimedia\restoreWarnings();
-                       return $text;
-               }
-
-               # Pure PHP implementation
-
-               $header = unpack( 'Vofp/Vcsize', substr( $diff, 0, 8 ) );
-
-               # Check the checksum if hash extension is available
-               $ofp = $this->xdiffAdler32( $base );
-               if ( $ofp !== false && $ofp !== substr( $diff, 0, 4 ) ) {
-                       wfDebug( __METHOD__ . ": incorrect base checksum\n" );
-                       return false;
-               }
-               if ( $header['csize'] != strlen( $base ) ) {
-                       wfDebug( __METHOD__ . ": incorrect base length\n" );
-                       return false;
-               }
-
-               $p = 8;
-               $out = '';
-               while ( $p < strlen( $diff ) ) {
-                       $x = unpack( 'Cop', substr( $diff, $p, 1 ) );
-                       $op = $x['op'];
-                       ++$p;
-                       switch ( $op ) {
-                               case self::XDL_BDOP_INS:
-                                       $x = unpack( 'Csize', substr( $diff, $p, 1 ) );
-                                       $p++;
-                                       $out .= substr( $diff, $p, $x['size'] );
-                                       $p += $x['size'];
-                                       break;
-                               case self::XDL_BDOP_INSB:
-                                       $x = unpack( 'Vcsize', substr( $diff, $p, 4 ) );
-                                       $p += 4;
-                                       $out .= substr( $diff, $p, $x['csize'] );
-                                       $p += $x['csize'];
-                                       break;
-                               case self::XDL_BDOP_CPY:
-                                       $x = unpack( 'Voff/Vcsize', substr( $diff, $p, 8 ) );
-                                       $p += 8;
-                                       $out .= substr( $base, $x['off'], $x['csize'] );
-                                       break;
-                               default:
-                                       wfDebug( __METHOD__ . ": invalid op\n" );
-                                       return false;
-                       }
-               }
-               return $out;
-       }
-
-       /**
-        * Compute a binary "Adler-32" checksum as defined by LibXDiff, i.e. with
-        * the bytes backwards and initialised with 0 instead of 1. See T36428.
-        *
-        * @param string $s
-        * @return string|bool False if the hash extension is not available
-        */
-       function xdiffAdler32( $s ) {
-               if ( !function_exists( 'hash' ) ) {
-                       return false;
-               }
-
-               static $init;
-               if ( $init === null ) {
-                       $init = str_repeat( "\xf0", 205 ) . "\xee" . str_repeat( "\xf0", 67 ) . "\x02";
-               }
-
-               // The real Adler-32 checksum of $init is zero, so it initialises the
-               // state to zero, as it is at the start of LibXDiff's checksum
-               // algorithm. Appending the subject string then simulates LibXDiff.
-               return strrev( hash( 'adler32', $init . $s, true ) );
-       }
-
-       function uncompress() {
-               if ( !$this->mDiffs ) {
-                       return;
-               }
-               $tail = '';
-               $mDiffsCount = count( $this->mDiffs );
-               for ( $diffKey = 0; $diffKey < $mDiffsCount; $diffKey++ ) {
-                       $textKey = $this->mDiffMap[$diffKey];
-                       $text = $this->patch( $tail, $this->mDiffs[$diffKey] );
-                       $this->mItems[$textKey] = $text;
-                       $tail = $text;
-               }
-       }
-
-       /**
-        * @return array
-        */
-       function __sleep() {
-               $this->compress();
-               if ( $this->mItems === [] ) {
-                       $info = false;
-               } else {
-                       // Take forward differences to improve the compression ratio for sequences
-                       $map = '';
-                       $prev = 0;
-                       foreach ( $this->mDiffMap as $i ) {
-                               if ( $map !== '' ) {
-                                       $map .= ',';
-                               }
-                               $map .= $i - $prev;
-                               $prev = $i;
-                       }
-                       $info = [
-                               'diffs' => $this->mDiffs,
-                               'map' => $map
-                       ];
-               }
-               if ( isset( $this->mDefaultKey ) ) {
-                       $info['default'] = $this->mDefaultKey;
-               }
-               $this->mCompressed = gzdeflate( serialize( $info ) );
-               return [ 'mCompressed' ];
-       }
-
-       function __wakeup() {
-               // addItem() doesn't work if mItems is partially filled from mDiffs
-               $this->mFrozen = true;
-               $info = unserialize( gzinflate( $this->mCompressed ) );
-               unset( $this->mCompressed );
-
-               if ( !$info ) {
-                       // Empty object
-                       return;
-               }
-
-               if ( isset( $info['default'] ) ) {
-                       $this->mDefaultKey = $info['default'];
-               }
-               $this->mDiffs = $info['diffs'];
-               if ( isset( $info['base'] ) ) {
-                       // Old format
-                       $this->mDiffMap = range( 0, count( $this->mDiffs ) - 1 );
-                       array_unshift( $this->mDiffs,
-                               pack( 'VVCV', 0, 0, self::XDL_BDOP_INSB, strlen( $info['base'] ) ) .
-                               $info['base'] );
-               } else {
-                       // New format
-                       $map = explode( ',', $info['map'] );
-                       $cur = 0;
-                       $this->mDiffMap = [];
-                       foreach ( $map as $i ) {
-                               $cur += $i;
-                               $this->mDiffMap[] = $cur;
-                       }
-               }
-               $this->uncompress();
-       }
-
-       /**
-        * Helper function for compression jobs
-        * Returns true until the object is "full" and ready to be committed
-        *
-        * @return bool
-        */
-       function isHappy() {
-               return $this->mSize < $this->mMaxSize
-                       && count( $this->mItems ) < $this->mMaxCount;
-       }
-
-}
-
-// phpcs:ignore Generic.CodeAnalysis.UnconditionalIfStatement.Found
-if ( false ) {
-       // Blobs generated by MediaWiki < 1.5 on PHP 4 were serialized with the
-       // class name coerced to lowercase. We can improve efficiency by adding
-       // autoload entries for the lowercase variants of these classes (T166759).
-       // The code below is never executed, but it is picked up by the AutoloadGenerator
-       // parser, which scans for class_alias() calls.
-       class_alias( ConcatenatedGzipHistoryBlob::class, 'concatenatedgziphistoryblob' );
-       class_alias( HistoryBlobCurStub::class, 'historyblobcurstub' );
-       class_alias( HistoryBlobStub::class, 'historyblobstub' );
-}
index 61785d5..aa51243 100644 (file)
@@ -574,10 +574,8 @@ class Html {
                $attrs = [];
                if ( $nonce !== null ) {
                        $attrs['nonce'] = $nonce;
-               } else {
-                       if ( ContentSecurityPolicy::isNonceRequired( RequestContext::getMain()->getConfig() ) ) {
-                               wfWarn( "no nonce set on script. CSP will break it" );
-                       }
+               } elseif ( ContentSecurityPolicy::isNonceRequired( RequestContext::getMain()->getConfig() ) ) {
+                       wfWarn( "no nonce set on script. CSP will break it" );
                }
 
                if ( preg_match( '/<\/?script/i', $contents ) ) {
@@ -600,10 +598,8 @@ class Html {
                $attrs = [ 'src' => $url ];
                if ( $nonce !== null ) {
                        $attrs['nonce'] = $nonce;
-               } else {
-                       if ( ContentSecurityPolicy::isNonceRequired( RequestContext::getMain()->getConfig() ) ) {
-                               wfWarn( "no nonce set on script. CSP will break it" );
-                       }
+               } elseif ( ContentSecurityPolicy::isNonceRequired( RequestContext::getMain()->getConfig() ) ) {
+                       wfWarn( "no nonce set on script. CSP will break it" );
                }
 
                return self::element( 'script', $attrs );
index 3e50ac6..4d684b5 100644 (file)
@@ -41,12 +41,12 @@ class Linker {
        /**
         * This function returns an HTML link to the given target.  It serves a few
         * purposes:
-        *   1) If $target is a Title, the correct URL to link to will be figured
+        *   1) If $target is a LinkTarget, the correct URL to link to will be figured
         *      out automatically.
         *   2) It automatically adds the usual classes for various types of link
         *      targets: "new" for red links, "stub" for short articles, etc.
         *   3) It escapes all attribute values safely so there's no risk of XSS.
-        *   4) It provides a default tooltip if the target is a Title (the page
+        *   4) It provides a default tooltip if the target is a LinkTarget (the page
         *      name of the target).
         * link() replaces the old functions in the makeLink() family.
         *
@@ -57,7 +57,7 @@ class Linker {
         *   change to support Images, literal URLs, etc.
         * @param string $html The HTML contents of the <a> element, i.e.,
         *   the link text.  This is raw HTML and will not be escaped.  If null,
-        *   defaults to the prefixed text of the Title; or if the Title is just a
+        *   defaults to the prefixed text of the LinkTarget; or if the LinkTarget is just a
         *   fragment, the contents of the fragment.
         * @param array $customAttribs A key => value array of extra HTML attributes,
         *   such as title and class.  (href is ignored.)  Classes will be
@@ -136,7 +136,7 @@ class Linker {
         * @since 1.16.3
         * @deprecated since 1.28, use MediaWiki\Linker\LinkRenderer instead
         * @see Linker::link
-        * @param Title $target
+        * @param LinkTarget $target
         * @param string $html
         * @param array $customAttribs
         * @param array $query
@@ -157,7 +157,7 @@ class Linker {
         * make*LinkObj static functions, but $query is not used.
         *
         * @since 1.16.3
-        * @param Title $nt
+        * @param LinkTarget $nt
         * @param string $html [optional]
         * @param string $query [optional]
         * @param string $trail [optional]
@@ -166,6 +166,7 @@ class Linker {
         * @return string
         */
        public static function makeSelfLinkObj( $nt, $html = '', $query = '', $trail = '', $prefix = '' ) {
+               $nt = Title::newFromLinkTarget( $nt );
                $ret = "<a class=\"mw-selflink selflink\">{$prefix}{$html}</a>{$trail}";
                if ( !Hooks::run( 'SelfLinkBegin', [ $nt, &$html, &$trail, &$prefix, &$ret ] ) ) {
                        return $ret;
@@ -190,7 +191,7 @@ class Linker {
         */
        public static function getInvalidTitleDescription( IContextSource $context, $namespace, $title ) {
                // First we check whether the namespace exists or not.
-               if ( MWNamespace::exists( $namespace ) ) {
+               if ( MediaWikiServices::getInstance()->getNamespaceInfo()->exists( $namespace ) ) {
                        if ( $namespace == NS_MAIN ) {
                                $name = $context->msg( 'blanknamespace' )->text();
                        } else {
@@ -272,7 +273,7 @@ class Linker {
         * HTML that that syntax inserts in the page.
         *
         * @param Parser $parser
-        * @param Title $title Title object of the file (not the currently viewed page)
+        * @param LinkTarget $title LinkTarget object of the file (not the currently viewed page)
         * @param File $file File object, or false if it doesn't exist
         * @param array $frameParams Associative array of parameters external to the media handler.
         *     Boolean parameters are indicated by presence or absence, the value is arbitrary and
@@ -291,7 +292,7 @@ class Linker {
         *          class           HTML for image classes. Plain text.
         *          caption         HTML for image caption.
         *          link-url        URL to link to
-        *          link-title      Title object to link to
+        *          link-title      LinkTarget object to link to
         *          link-target     Value for the target attribute, only with link-url
         *          no-link         Boolean, suppress description link
         *          targetlang      (optional) Target language code, see Parser::getTargetLanguage()
@@ -304,10 +305,11 @@ class Linker {
         * @since 1.20
         * @return string HTML for an image, with links, wrappers, etc.
         */
-       public static function makeImageLink( Parser $parser, Title $title,
+       public static function makeImageLink( Parser $parser, LinkTarget $title,
                $file, $frameParams = [], $handlerParams = [], $time = false,
                $query = "", $widthOption = null
        ) {
+               $title = Title::newFromLinkTarget( $title );
                $res = null;
                $dummy = new DummyLinker;
                if ( !Hooks::run( 'ImageBeforeProduceHTML', [ &$dummy, &$title,
@@ -483,7 +485,7 @@ class Linker {
 
        /**
         * Make HTML for a thumbnail including image, border and caption
-        * @param Title $title
+        * @param LinkTarget $title
         * @param File|bool $file File object or false if it doesn't exist
         * @param string $label
         * @param string $alt
@@ -493,7 +495,7 @@ class Linker {
         * @param string $manualthumb
         * @return string
         */
-       public static function makeThumbLinkObj( Title $title, $file, $label = '', $alt = '',
+       public static function makeThumbLinkObj( LinkTarget $title, $file, $label = '', $alt = '',
                $align = 'right', $params = [], $framed = false, $manualthumb = ""
        ) {
                $frameParams = [
@@ -511,7 +513,7 @@ class Linker {
        }
 
        /**
-        * @param Title $title
+        * @param LinkTarget $title
         * @param File $file
         * @param array $frameParams
         * @param array $handlerParams
@@ -519,7 +521,7 @@ class Linker {
         * @param string $query
         * @return string
         */
-       public static function makeThumbLink2( Title $title, $file, $frameParams = [],
+       public static function makeThumbLink2( LinkTarget $title, $file, $frameParams = [],
                $handlerParams = [], $time = false, $query = ""
        ) {
                $exists = $file && $file->exists();
@@ -585,7 +587,7 @@ class Linker {
                # ThumbnailImage::toHtml() already adds page= onto the end of DjVu URLs
                # So we don't need to pass it here in $query. However, the URL for the
                # zoom icon still needs it, so we make a unique query for it. See T16771
-               $url = $title->getLocalURL( $query );
+               $url = Title::newFromLinkTarget( $title )->getLocalURL( $query );
                if ( $page ) {
                        $url = wfAppendQuery( $url, [ 'page' => $page ] );
                }
@@ -668,7 +670,7 @@ class Linker {
         * Make a "broken" link to an image
         *
         * @since 1.16.3
-        * @param Title $title
+        * @param LinkTarget $title
         * @param string $label Link label (plain text)
         * @param string $query Query string
         * @param string $unused1 Unused parameter kept for b/c
@@ -679,11 +681,13 @@ class Linker {
        public static function makeBrokenImageLinkObj( $title, $label = '',
                $query = '', $unused1 = '', $unused2 = '', $time = false
        ) {
-               if ( !$title instanceof Title ) {
-                       wfWarn( __METHOD__ . ': Requires $title to be a Title object.' );
+               if ( !$title instanceof LinkTarget ) {
+                       wfWarn( __METHOD__ . ': Requires $title to be a LinkTarget object.' );
                        return "<!-- ERROR -->" . htmlspecialchars( $label );
                }
 
+               $title = Title::castFromLinkTarget( $title );
+
                global $wgEnableUploads, $wgUploadMissingFileUrl, $wgUploadNavigationUrl;
                if ( $label == '' ) {
                        $label = $title->getPrefixedText();
@@ -722,13 +726,13 @@ class Linker {
         * Get the URL to upload a certain file
         *
         * @since 1.16.3
-        * @param Title $destFile Title object of the file to upload
+        * @param LinkTarget $destFile LinkTarget object of the file to upload
         * @param string $query Urlencoded query string to prepend
         * @return string Urlencoded URL
         */
        protected static function getUploadUrl( $destFile, $query = '' ) {
                global $wgUploadMissingFileUrl, $wgUploadNavigationUrl;
-               $q = 'wpDestFile=' . $destFile->getPartialURL();
+               $q = 'wpDestFile=' . Title::castFromLinkTarget( $destFile )->getPartialURL();
                if ( $query != '' ) {
                        $q .= '&' . $query;
                }
@@ -750,7 +754,7 @@ class Linker {
         * Create a direct link to a given uploaded file.
         *
         * @since 1.16.3
-        * @param Title $title
+        * @param LinkTarget $title
         * @param string $html Pre-sanitized HTML
         * @param string $time MW timestamp of file creation time
         * @return string HTML
@@ -765,14 +769,14 @@ class Linker {
         * This will make a broken link if $file is false.
         *
         * @since 1.16.3
-        * @param Title $title
+        * @param LinkTarget $title
         * @param File|bool $file File object or false
         * @param string $html Pre-sanitized HTML
         * @return string HTML
         *
         * @todo Handle invalid or missing images better.
         */
-       public static function makeMediaLinkFile( Title $title, $file, $html = '' ) {
+       public static function makeMediaLinkFile( LinkTarget $title, $file, $html = '' ) {
                if ( $file && $file->exists() ) {
                        $url = $file->getUrl();
                        $class = 'internal';
@@ -794,7 +798,7 @@ class Linker {
                ];
 
                if ( !Hooks::run( 'LinkerMakeMediaLinkFile',
-                       [ $title, $file, &$html, &$attribs, &$ret ] ) ) {
+                       [ Title::castFromLinkTarget( $title ), $file, &$html, &$attribs, &$ret ] ) ) {
                        wfDebug( "Hook LinkerMakeMediaLinkFile changed the output of link "
                                . "with url {$url} and text {$html} to {$ret}\n", true );
                        return $ret;
@@ -835,7 +839,7 @@ class Linker {
         * @param-taint $linktype escapes_html
         * @param array $attribs Array of extra attributes to <a>
         * @param-taint $attribs escapes_html
-        * @param Title|null $title Title object used for title specific link attributes
+        * @param LinkTarget|null $title LinkTarget object used for title specific link attributes
         * @param-taint $title none
         * @return string
         */
@@ -890,6 +894,12 @@ class Linker {
         * @since 1.16.3. $altUserName was added in 1.19.
         */
        public static function userLink( $userId, $userName, $altUserName = false ) {
+               if ( $userName === '' ) {
+                       wfLogWarning( __METHOD__ . ' received an empty username. Are there database errors ' .
+                               'that need to be fixed?' );
+                       return wfMessage( 'empty-username' )->parse();
+               }
+
                $classes = 'mw-userlink';
                $page = null;
                if ( $userId == 0 ) {
@@ -902,7 +912,7 @@ class Linker {
                        }
                        $classes .= ' mw-anonuserlink'; // Separate link class for anons (T45179)
                } else {
-                       $page = Title::makeTitle( NS_USER, $userName );
+                       $page = new TitleValue( NS_USER, strtr( $userName, ' ', '_' ) );
                }
 
                // Wrap the output with <bdi> tags for directionality isolation
@@ -932,6 +942,12 @@ class Linker {
                $userId, $userText, $redContribsWhenNoEdits = false, $flags = 0, $edits = null,
                $useParentheses = true
        ) {
+               if ( $userText === '' ) {
+                       wfLogWarning( __METHOD__ . ' received an empty username. Are there database errors ' .
+                               'that need to be fixed?' );
+                       return ' ' . wfMessage( 'empty-username' )->parse();
+               }
+
                global $wgUser, $wgDisableAnonTalk, $wgLang;
                $talkable = !( $wgDisableAnonTalk && $userId == 0 );
                $blockable = !( $flags & self::TOOL_LINKS_NOBLOCK );
@@ -998,10 +1014,13 @@ class Linker {
         * @param int $userId User identifier
         * @param string $userText User name or IP address
         * @param int|null $edits User edit count (optional, for performance)
+        * @param bool $useParentheses (optional) Wrap comments in parentheses where needed
         * @return string
         */
-       public static function userToolLinksRedContribs( $userId, $userText, $edits = null ) {
-               return self::userToolLinks( $userId, $userText, true, 0, $edits );
+       public static function userToolLinksRedContribs(
+               $userId, $userText, $edits = null, $useParentheses = true
+       ) {
+               return self::userToolLinks( $userId, $userText, true, 0, $edits, $useParentheses );
        }
 
        /**
@@ -1011,7 +1030,13 @@ class Linker {
         * @return string HTML fragment with user talk link
         */
        public static function userTalkLink( $userId, $userText ) {
-               $userTalkPage = Title::makeTitle( NS_USER_TALK, $userText );
+               if ( $userText === '' ) {
+                       wfLogWarning( __METHOD__ . ' received an empty username. Are there database errors ' .
+                               'that need to be fixed?' );
+                       return wfMessage( 'empty-username' )->parse();
+               }
+
+               $userTalkPage = new TitleValue( NS_USER_TALK, strtr( $userText, ' ', '_' ) );
                $moreLinkAttribs['class'] = 'mw-usertoollinks-talk';
 
                return self::link( $userTalkPage,
@@ -1027,6 +1052,12 @@ class Linker {
         * @return string HTML fragment with block link
         */
        public static function blockLink( $userId, $userText ) {
+               if ( $userText === '' ) {
+                       wfLogWarning( __METHOD__ . ' received an empty username. Are there database errors ' .
+                               'that need to be fixed?' );
+                       return wfMessage( 'empty-username' )->parse();
+               }
+
                $blockPage = SpecialPage::getTitleFor( 'Block', $userText );
                $moreLinkAttribs['class'] = 'mw-usertoollinks-block';
 
@@ -1042,6 +1073,12 @@ class Linker {
         * @return string HTML fragment with e-mail user link
         */
        public static function emailLink( $userId, $userText ) {
+               if ( $userText === '' ) {
+                       wfLogWarning( __METHOD__ . ' received an empty username. Are there database errors ' .
+                               'that need to be fixed?' );
+                       return wfMessage( 'empty-username' )->parse();
+               }
+
                $emailPage = SpecialPage::getTitleFor( 'Emailuser', $userText );
                $moreLinkAttribs['class'] = 'mw-usertoollinks-mail';
                return self::link( $emailPage,
@@ -1077,21 +1114,23 @@ class Linker {
         * @since 1.16.3
         * @param Revision $rev
         * @param bool $isPublic Show only if all users can see it
+        * @param bool $useParentheses (optional) Wrap comments in parentheses where needed
         * @return string HTML
         */
-       public static function revUserTools( $rev, $isPublic = false ) {
+       public static function revUserTools( $rev, $isPublic = false, $useParentheses = true ) {
                if ( $rev->isDeleted( Revision::DELETED_USER ) && $isPublic ) {
                        $link = wfMessage( 'rev-deleted-user' )->escaped();
                } elseif ( $rev->userCan( Revision::DELETED_USER ) ) {
                        $userId = $rev->getUser( Revision::FOR_THIS_USER );
                        $userText = $rev->getUserText( Revision::FOR_THIS_USER );
                        $link = self::userLink( $userId, $userText )
-                               . self::userToolLinks( $userId, $userText );
+                               . self::userToolLinks( $userId, $userText, false, 0, null,
+                                       $useParentheses );
                } else {
                        $link = wfMessage( 'rev-deleted-user' )->escaped();
                }
                if ( $rev->isDeleted( Revision::DELETED_USER ) ) {
-                       return ' <span class="history-deleted">' . $link . '</span>';
+                       return ' <span class="history-deleted mw-userlink">' . $link . '</span>';
                }
                return $link;
        }
@@ -1106,8 +1145,8 @@ class Linker {
         * @since 1.16.3. $wikiId added in 1.26
         *
         * @param string $comment
-        * @param Title|null $title Title object (to generate link to the section in autocomment)
-        *  or null
+        * @param LinkTarget|null $title LinkTarget object (to generate link to the section in
+        *  autocomment) or null
         * @param bool $local Whether section links should refer to local page
         * @param string|null $wikiId Id (as used by WikiMap) of the wiki to generate links to.
         *  For use with external changes.
@@ -1137,7 +1176,7 @@ class Linker {
         * Called by Linker::formatComment.
         *
         * @param string $comment Comment text
-        * @param Title|null $title An optional title object used to links to sections
+        * @param LinkTarget|null $title An optional LinkTarget object used to links to sections
         * @param bool $local Whether section links should refer to local page
         * @param string|null $wikiId Id of the wiki to link to (if not the local wiki),
         *  as used by WikiMap.
@@ -1173,7 +1212,8 @@ class Linker {
 
                                Hooks::run(
                                        'FormatAutocomments',
-                                       [ &$comment, $pre, $auto, $post, $title, $local, $wikiId ]
+                                       [ &$comment, $pre, $auto, $post, Title::castFromLinkTarget( $title ), $local,
+                                       $wikiId ]
                                );
 
                                if ( $comment === null ) {
@@ -1192,11 +1232,18 @@ class Linker {
                                                $sectionText = str_replace( '[[', '&#91;[', $auto );
 
                                                $section = substr( Parser::guessSectionNameFromStrippedText( $section ), 1 );
+                                               // Support: HHVM (T222857)
+                                               // The guessSectionNameFromStrippedText method returns a non-empty string
+                                               // that starts with "#". Before PHP 7 (and still on HHVM) substr() would
+                                               // return false if the start offset is the end of the string.
+                                               // On PHP 7+, it gracefully returns empty string instead.
+                                               if ( $section === false ) {
+                                                       $section = '';
+                                               }
                                                if ( $local ) {
-                                                       $sectionTitle = Title::makeTitleSafe( NS_MAIN, '', $section );
+                                                       $sectionTitle = new TitleValue( NS_MAIN, '', $section );
                                                } else {
-                                                       $sectionTitle = Title::makeTitleSafe( $title->getNamespace(),
-                                                               $title->getDBkey(), $section );
+                                                       $sectionTitle = $title->createFragmentTarget( $section );
                                                }
                                                if ( $sectionTitle ) {
                                                        $auto = Linker::makeCommentLink(
@@ -1237,7 +1284,7 @@ class Linker {
         *      function is html, $comment must be sanitized for use as html. You probably want
         *      to pass $comment through Sanitizer::escapeHtmlAllowEntities() before calling
         *      this function.
-        * @param Title|null $title An optional title object used to links to sections
+        * @param LinkTarget|null $title An optional LinkTarget object used to links to sections
         * @param bool $local Whether section links should refer to local page
         * @param string|null $wikiId Id of the wiki to link to (if not the local wiki),
         *  as used by WikiMap.
@@ -1263,7 +1310,12 @@ class Linker {
                                ([^[]*) # 3. link trail (the text up until the next link)
                        /x',
                        function ( $match ) use ( $title, $local, $wikiId ) {
-                               $medians = '(?:' . preg_quote( MWNamespace::getCanonicalName( NS_MEDIA ), '/' ) . '|';
+                               $services = MediaWikiServices::getInstance();
+
+                               $medians = '(?:';
+                               $medians .= preg_quote(
+                                       $services->getNamespaceInfo()->getCanonicalName( NS_MEDIA ), '/' );
+                               $medians .= '|';
                                $medians .= preg_quote(
                                        MediaWikiServices::getInstance()->getContentLanguage()->getNsText( NS_MEDIA ),
                                        '/'
@@ -1316,8 +1368,11 @@ class Linker {
                                                $linkText = $text;
                                                $linkTarget = Linker::normalizeSubpageLink( $title, $match[1], $linkText );
 
-                                               $target = Title::newFromText( $linkTarget );
-                                               if ( $target ) {
+                                               Title::newFromText( $linkTarget );
+                                               try {
+                                                       $target = MediaWikiServices::getInstance()->getTitleParser()->
+                                                               parseTitle( $linkTarget );
+
                                                        if ( $target->getText() == '' && !$target->isExternal()
                                                                && !$local && $title
                                                        ) {
@@ -1325,6 +1380,8 @@ class Linker {
                                                        }
 
                                                        $thelink = Linker::makeCommentLink( $target, $linkText . $inside, $wikiId ) . $trail;
+                                               } catch ( MalformedTitleException $e ) {
+                                                       // Fall through
                                                }
                                        }
                                }
@@ -1345,7 +1402,7 @@ class Linker {
        }
 
        /**
-        * Generates a link to the given Title
+        * Generates a link to the given LinkTarget
         *
         * @note This is only public for technical reasons. It's not intended for use outside Linker.
         *
@@ -1366,8 +1423,9 @@ class Linker {
                                        $wikiId,
                                        $linkTarget->getNamespace() === 0
                                                ? $linkTarget->getDBkey()
-                                               : MWNamespace::getCanonicalName( $linkTarget->getNamespace() ) . ':'
-                                                       . $linkTarget->getDBkey(),
+                                               : MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                                       getCanonicalName( $linkTarget->getNamespace() ) .
+                                                       ':' . $linkTarget->getDBkey(),
                                        $linkTarget->getFragment()
                                ),
                                $text,
@@ -1381,7 +1439,7 @@ class Linker {
        }
 
        /**
-        * @param Title $contextTitle
+        * @param LinkTarget $contextTitle
         * @param string $target
         * @param string &$text
         * @return string
@@ -1402,7 +1460,10 @@ class Linker {
 
                # Some namespaces don't allow subpages,
                # so only perform processing if subpages are allowed
-               if ( $contextTitle && MWNamespace::hasSubpages( $contextTitle->getNamespace() ) ) {
+               if (
+                       $contextTitle && MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       hasSubpages( $contextTitle->getNamespace() )
+               ) {
                        $hash = strpos( $target, '#' );
                        if ( $hash !== false ) {
                                $suffix = substr( $target, $hash );
@@ -1412,6 +1473,8 @@ class Linker {
                        }
                        # T9425
                        $target = trim( $target );
+                       $contextPrefixedText = MediaWikiServices::getInstance()->getTitleFormatter()->
+                               getPrefixedText( $contextTitle );
                        # Look at the first character
                        if ( $target != '' && $target[0] === '/' ) {
                                # / at end means we don't want the slash to be shown
@@ -1423,7 +1486,7 @@ class Linker {
                                        $noslash = substr( $target, 1 );
                                }
 
-                               $ret = $contextTitle->getPrefixedText() . '/' . trim( $noslash ) . $suffix;
+                               $ret = $contextPrefixedText . '/' . trim( $noslash ) . $suffix;
                                if ( $text === '' ) {
                                        $text = $target . $suffix;
                                } # this might be changed for ugliness reasons
@@ -1436,7 +1499,7 @@ class Linker {
                                        $nodotdot = substr( $nodotdot, 3 );
                                }
                                if ( $dotdotcount > 0 ) {
-                                       $exploded = explode( '/', $contextTitle->getPrefixedText() );
+                                       $exploded = explode( '/', $contextPrefixedText );
                                        if ( count( $exploded ) > $dotdotcount ) { # not allowed to go below top level page
                                                $ret = implode( '/', array_slice( $exploded, 0, -$dotdotcount ) );
                                                # / at the end means don't show full path
@@ -1465,7 +1528,8 @@ class Linker {
         *
         * @since 1.16.3. $wikiId added in 1.26
         * @param string $comment
-        * @param Title|null $title Title object (to generate link to section in autocomment) or null
+        * @param LinkTarget|null $title LinkTarget object (to generate link to section in autocomment)
+        *  or null
         * @param bool $local Whether section links should refer to local page
         * @param string|null $wikiId Id (as used by WikiMap) of the wiki to generate links to.
         *  For use with external changes.
@@ -1517,7 +1581,7 @@ class Linker {
                        $block = " <span class=\"comment\">" . wfMessage( 'rev-deleted-comment' )->escaped() . "</span>";
                }
                if ( $rev->isDeleted( Revision::DELETED_COMMENT ) ) {
-                       return " <span class=\"history-deleted\">$block</span>";
+                       return " <span class=\"history-deleted comment\">$block</span>";
                }
                return $block;
        }
@@ -1532,9 +1596,8 @@ class Linker {
                        $stxt = wfMessage( 'historyempty' )->escaped();
                } else {
                        $stxt = wfMessage( 'nbytes' )->numParams( $size )->escaped();
-                       $stxt = wfMessage( 'parentheses' )->rawParams( $stxt )->escaped();
                }
-               return "<span class=\"history-size\">$stxt</span>";
+               return "<span class=\"history-size mw-diff-bytes\">$stxt</span>";
        }
 
        /**
@@ -1710,12 +1773,8 @@ class Linker {
        static function splitTrail( $trail ) {
                $regex = MediaWikiServices::getInstance()->getContentLanguage()->linkTrail();
                $inside = '';
-               if ( $trail !== '' ) {
-                       $m = [];
-                       if ( preg_match( $regex, $trail, $m ) ) {
-                               $inside = $m[1];
-                               $trail = $m[2];
-                       }
+               if ( $trail !== '' && preg_match( $regex, $trail, $m ) ) {
+                       list( , $inside, $trail ) = $m;
                }
                return [ $inside, $trail ];
        }
@@ -1768,6 +1827,12 @@ class Linker {
                        $inner = $context->msg( 'brackets' )->rawParams( $inner )->escaped();
                }
 
+               if ( $context->getUser()->getBoolOption( 'showrollbackconfirmation' ) ) {
+                       $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
+                       $stats->increment( 'rollbackconfirmation.event.load' );
+                       $context->getOutput()->addModules( 'mediawiki.page.rollback.confirmation' );
+               }
+
                return '<span class="mw-rollback-link">' . $inner . '</span>';
        }
 
@@ -1861,20 +1926,24 @@ class Linker {
                }
 
                $title = $rev->getTitle();
+
                $query = [
                        'action' => 'rollback',
                        'from' => $rev->getUserText(),
                        'token' => $context->getUser()->getEditToken( 'rollback' ),
                ];
+
                $attrs = [
                        'data-mw' => 'interface',
-                       'title' => $context->msg( 'tooltip-rollback' )->text(),
+                       'title' => $context->msg( 'tooltip-rollback' )->text()
                ];
+
                $options = [ 'known', 'noclasses' ];
 
                if ( $context->getRequest()->getBool( 'bot' ) ) {
+                       //T17999
+                       $query['hidediff'] = '1';
                        $query['bot'] = '1';
-                       $query['hidediff'] = '1'; // T17999
                }
 
                $disableRollbackEditCount = false;
@@ -2033,10 +2102,10 @@ class Linker {
         *
         * @param User $user
         * @param Revision $rev
-        * @param Title $title
+        * @param LinkTarget $title
         * @return string HTML fragment
         */
-       public static function getRevDeleteLink( User $user, Revision $rev, Title $title ) {
+       public static function getRevDeleteLink( User $user, Revision $rev, LinkTarget $title ) {
                $canHide = $user->isAllowed( 'deleterevision' );
                if ( !$canHide && !( $rev->getVisibility() && $user->isAllowed( 'deletedhistory' ) ) ) {
                        return '';
@@ -2045,12 +2114,14 @@ class Linker {
                if ( !$rev->userCan( Revision::DELETED_RESTRICTED, $user ) ) {
                        return self::revDeleteLinkDisabled( $canHide ); // revision was hidden from sysops
                }
+               $prefixedDbKey = MediaWikiServices::getInstance()->getTitleFormatter()->
+                       getPrefixedDBkey( $title );
                if ( $rev->getId() ) {
                        // RevDelete links using revision ID are stable across
                        // page deletion and undeletion; use when possible.
                        $query = [
                                'type' => 'revision',
-                               'target' => $title->getPrefixedDBkey(),
+                               'target' => $prefixedDbKey,
                                'ids' => $rev->getId()
                        ];
                } else {
@@ -2058,7 +2129,7 @@ class Linker {
                        // We have to refer to these by timestamp, ick!
                        $query = [
                                'type' => 'archive',
-                               'target' => $title->getPrefixedDBkey(),
+                               'target' => $prefixedDbKey,
                                'ids' => $rev->getTimestamp()
                        ];
                }
index 3079c65..cbe5a1a 100644 (file)
@@ -86,10 +86,8 @@ class MWGrants {
         * @return string[] Corresponding grant descriptions
         */
        public static function grantNames( array $grants, $lang = null ) {
-               if ( $lang !== null ) {
-                       if ( is_string( $lang ) ) {
-                               $lang = Language::factory( $lang );
-                       }
+               if ( $lang !== null && is_string( $lang ) ) {
+                       $lang = Language::factory( $lang );
                }
 
                $ret = [];
index b40da00..0121bd5 100644 (file)
 use MediaWiki\MediaWikiServices;
 
 /**
- * This is a utility class with only static functions
- * for dealing with namespaces that encodes all the
- * "magic" behaviors of them based on index.  The textual
- * names of the namespaces are handled by Language.php.
- *
- * These are synonyms for the names given in the language file
- * Users and translators should not change them
+ * @deprecated since 1.34, use NamespaceInfo instead
  */
 class MWNamespace {
-
-       /**
-        * These namespaces should always be first-letter capitalized, now and
-        * forevermore. Historically, they could've probably been lowercased too,
-        * but some things are just too ingrained now. :)
-        */
-       private static $alwaysCapitalizedNamespaces = [ NS_SPECIAL, NS_USER, NS_MEDIAWIKI ];
-
-       /** @var string[]|null Canonical namespaces cache */
-       private static $canonicalNamespaces = null;
-
-       /** @var array|false Canonical namespaces index cache */
-       private static $namespaceIndexes = false;
-
-       /** @var int[]|null Valid namespaces cache */
-       private static $validNamespaces = null;
-
-       /**
-        * Throw an exception when trying to get the subject or talk page
-        * for a given namespace where it does not make sense.
-        * Special namespaces are defined in includes/Defines.php and have
-        * a value below 0 (ex: NS_SPECIAL = -1 , NS_MEDIA = -2)
-        *
-        * @param int $index
-        * @param string $method
-        *
-        * @throws MWException
-        * @return bool
-        */
-       private static function isMethodValidFor( $index, $method ) {
-               if ( $index < NS_MAIN ) {
-                       throw new MWException( "$method does not make any sense for given namespace $index" );
-               }
-               return true;
-       }
-
-       /**
-        * Clear internal caches
-        *
-        * For use in unit testing when namespace configuration is changed.
-        *
-        * @since 1.31
-        */
-       public static function clearCaches() {
-               self::$canonicalNamespaces = null;
-               self::$namespaceIndexes = false;
-               self::$validNamespaces = null;
-       }
-
        /**
         * Can pages in the given namespace be moved?
         *
@@ -87,16 +32,7 @@ class MWNamespace {
         * @return bool
         */
        public static function isMovable( $index ) {
-               global $wgAllowImageMoving;
-
-               $result = !( $index < NS_MAIN || ( $index == NS_FILE && !$wgAllowImageMoving ) );
-
-               /**
-                * @since 1.20
-                */
-               Hooks::run( 'NamespaceIsMovable', [ $index, &$result ] );
-
-               return $result;
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->isMovable( $index );
        }
 
        /**
@@ -107,7 +43,7 @@ class MWNamespace {
         * @since 1.19
         */
        public static function isSubject( $index ) {
-               return !self::isTalk( $index );
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->isSubject( $index );
        }
 
        /**
@@ -117,8 +53,7 @@ class MWNamespace {
         * @return bool
         */
        public static function isTalk( $index ) {
-               return $index > NS_MAIN
-                       && $index % 2;
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->isTalk( $index );
        }
 
        /**
@@ -128,10 +63,7 @@ class MWNamespace {
         * @return int
         */
        public static function getTalk( $index ) {
-               self::isMethodValidFor( $index, __METHOD__ );
-               return self::isTalk( $index )
-                       ? $index
-                       : $index + 1;
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->getTalk( $index );
        }
 
        /**
@@ -142,14 +74,7 @@ class MWNamespace {
         * @return int
         */
        public static function getSubject( $index ) {
-               # Handle special namespaces
-               if ( $index < NS_MAIN ) {
-                       return $index;
-               }
-
-               return self::isTalk( $index )
-                       ? $index - 1
-                       : $index;
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->getSubject( $index );
        }
 
        /**
@@ -161,15 +86,7 @@ class MWNamespace {
         * @return int|null If no associated namespace could be found
         */
        public static function getAssociated( $index ) {
-               self::isMethodValidFor( $index, __METHOD__ );
-
-               if ( self::isSubject( $index ) ) {
-                       return self::getTalk( $index );
-               } elseif ( self::isTalk( $index ) ) {
-                       return self::getSubject( $index );
-               } else {
-                       return null;
-               }
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->getAssociated( $index );
        }
 
        /**
@@ -181,8 +98,7 @@ class MWNamespace {
         * @since 1.19
         */
        public static function exists( $index ) {
-               $nslist = self::getCanonicalNamespaces();
-               return isset( $nslist[$index] );
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->exists( $index );
        }
 
        /**
@@ -200,7 +116,7 @@ class MWNamespace {
         * @since 1.19
         */
        public static function equals( $ns1, $ns2 ) {
-               return $ns1 == $ns2;
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->equals( $ns1, $ns2 );
        }
 
        /**
@@ -215,36 +131,19 @@ class MWNamespace {
         * @since 1.19
         */
        public static function subjectEquals( $ns1, $ns2 ) {
-               return self::getSubject( $ns1 ) == self::getSubject( $ns2 );
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       subjectEquals( $ns1, $ns2 );
        }
 
        /**
         * Returns array of all defined namespaces with their canonical
         * (English) names.
         *
-        * @param bool $rebuild Rebuild namespace list (default = false). Used for testing.
-        *  Deprecated since 1.31, use self::clearCaches() instead.
-        *
         * @return array
         * @since 1.17
         */
-       public static function getCanonicalNamespaces( $rebuild = false ) {
-               if ( $rebuild ) {
-                       self::clearCaches();
-               }
-
-               if ( self::$canonicalNamespaces === null ) {
-                       global $wgExtraNamespaces, $wgCanonicalNamespaceNames;
-                       self::$canonicalNamespaces = [ NS_MAIN => '' ] + $wgCanonicalNamespaceNames;
-                       // Add extension namespaces
-                       self::$canonicalNamespaces +=
-                               ExtensionRegistry::getInstance()->getAttribute( 'ExtensionNamespaces' );
-                       if ( is_array( $wgExtraNamespaces ) ) {
-                               self::$canonicalNamespaces += $wgExtraNamespaces;
-                       }
-                       Hooks::run( 'CanonicalNamespaces', [ &self::$canonicalNamespaces ] );
-               }
-               return self::$canonicalNamespaces;
+       public static function getCanonicalNamespaces() {
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->getCanonicalNamespaces();
        }
 
        /**
@@ -254,8 +153,7 @@ class MWNamespace {
         * @return string|bool If no canonical definition.
         */
        public static function getCanonicalName( $index ) {
-               $nslist = self::getCanonicalNamespaces();
-               return $nslist[$index] ?? false;
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->getCanonicalName( $index );
        }
 
        /**
@@ -266,17 +164,7 @@ class MWNamespace {
         * @return int
         */
        public static function getCanonicalIndex( $name ) {
-               if ( self::$namespaceIndexes === false ) {
-                       self::$namespaceIndexes = [];
-                       foreach ( self::getCanonicalNamespaces() as $i => $text ) {
-                               self::$namespaceIndexes[strtolower( $text )] = $i;
-                       }
-               }
-               if ( array_key_exists( $name, self::$namespaceIndexes ) ) {
-                       return self::$namespaceIndexes[$name];
-               } else {
-                       return null;
-               }
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->getCanonicalIndex( $name );
        }
 
        /**
@@ -285,30 +173,7 @@ class MWNamespace {
         * @return array
         */
        public static function getValidNamespaces() {
-               if ( is_null( self::$validNamespaces ) ) {
-                       foreach ( array_keys( self::getCanonicalNamespaces() ) as $ns ) {
-                               if ( $ns >= 0 ) {
-                                       self::$validNamespaces[] = $ns;
-                               }
-                       }
-                       // T109137: sort numerically
-                       sort( self::$validNamespaces, SORT_NUMERIC );
-               }
-
-               return self::$validNamespaces;
-       }
-
-       /**
-        * Does this namespace ever have a talk namespace?
-        *
-        * @deprecated since 1.30, use hasTalkNamespace() instead.
-        *
-        * @param int $index Namespace index
-        * @return bool True if this namespace either is or has a corresponding talk namespace.
-        */
-       public static function canTalk( $index ) {
-               wfDeprecated( __METHOD__, '1.30' );
-               return self::hasTalkNamespace( $index );
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->getValidNamespaces();
        }
 
        /**
@@ -320,7 +185,7 @@ class MWNamespace {
         * @return bool True if this namespace either is or has a corresponding talk namespace.
         */
        public static function hasTalkNamespace( $index ) {
-               return $index >= NS_MAIN;
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->hasTalkNamespace( $index );
        }
 
        /**
@@ -331,8 +196,7 @@ class MWNamespace {
         * @return bool
         */
        public static function isContent( $index ) {
-               global $wgContentNamespaces;
-               return $index == NS_MAIN || in_array( $index, $wgContentNamespaces );
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->isContent( $index );
        }
 
        /**
@@ -343,8 +207,7 @@ class MWNamespace {
         * @return bool
         */
        public static function wantSignatures( $index ) {
-               global $wgExtraSignatureNamespaces;
-               return self::isTalk( $index ) || in_array( $index, $wgExtraSignatureNamespaces );
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->wantSignatures( $index );
        }
 
        /**
@@ -354,7 +217,7 @@ class MWNamespace {
         * @return bool
         */
        public static function isWatchable( $index ) {
-               return $index >= NS_MAIN;
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->isWatchable( $index );
        }
 
        /**
@@ -364,8 +227,7 @@ class MWNamespace {
         * @return bool
         */
        public static function hasSubpages( $index ) {
-               global $wgNamespacesWithSubpages;
-               return !empty( $wgNamespacesWithSubpages[$index] );
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->hasSubpages( $index );
        }
 
        /**
@@ -373,15 +235,7 @@ class MWNamespace {
         * @return array Array of namespace indices
         */
        public static function getContentNamespaces() {
-               global $wgContentNamespaces;
-               if ( !is_array( $wgContentNamespaces ) || $wgContentNamespaces === [] ) {
-                       return [ NS_MAIN ];
-               } elseif ( !in_array( NS_MAIN, $wgContentNamespaces ) ) {
-                       // always force NS_MAIN to be part of array (to match the algorithm used by isContent)
-                       return array_merge( [ NS_MAIN ], $wgContentNamespaces );
-               } else {
-                       return $wgContentNamespaces;
-               }
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces();
        }
 
        /**
@@ -391,10 +245,7 @@ class MWNamespace {
         * @return array Array of namespace indices
         */
        public static function getSubjectNamespaces() {
-               return array_filter(
-                       self::getValidNamespaces(),
-                       'MWNamespace::isSubject'
-               );
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->getSubjectNamespaces();
        }
 
        /**
@@ -404,10 +255,7 @@ class MWNamespace {
         * @return array Array of namespace indices
         */
        public static function getTalkNamespaces() {
-               return array_filter(
-                       self::getValidNamespaces(),
-                       'MWNamespace::isTalk'
-               );
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->getTalkNamespaces();
        }
 
        /**
@@ -417,23 +265,7 @@ class MWNamespace {
         * @return bool
         */
        public static function isCapitalized( $index ) {
-               global $wgCapitalLinks, $wgCapitalLinkOverrides;
-               // Turn NS_MEDIA into NS_FILE
-               $index = $index === NS_MEDIA ? NS_FILE : $index;
-
-               // Make sure to get the subject of our namespace
-               $index = self::getSubject( $index );
-
-               // Some namespaces are special and should always be upper case
-               if ( in_array( $index, self::$alwaysCapitalizedNamespaces ) ) {
-                       return true;
-               }
-               if ( isset( $wgCapitalLinkOverrides[$index] ) ) {
-                       // $wgCapitalLinkOverrides is explicitly set
-                       return $wgCapitalLinkOverrides[$index];
-               }
-               // Default to the global setting
-               return $wgCapitalLinks;
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->isCapitalized( $index );
        }
 
        /**
@@ -445,7 +277,8 @@ class MWNamespace {
         * @return bool
         */
        public static function hasGenderDistinction( $index ) {
-               return $index == NS_USER || $index == NS_USER_TALK;
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       hasGenderDistinction( $index );
        }
 
        /**
@@ -456,8 +289,7 @@ class MWNamespace {
         * @return bool
         */
        public static function isNonincludable( $index ) {
-               global $wgNonincludableNamespaces;
-               return $wgNonincludableNamespaces && in_array( $index, $wgNonincludableNamespaces );
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->isNonincludable( $index );
        }
 
        /**
@@ -472,9 +304,8 @@ class MWNamespace {
         * @return null|string Default model name for the given namespace, if set
         */
        public static function getNamespaceContentModel( $index ) {
-               $config = MediaWikiServices::getInstance()->getMainConfig();
-               $models = $config->get( 'NamespaceContentModels' );
-               return $models[$index] ?? null;
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       getNamespaceContentModel( $index );
        }
 
        /**
@@ -487,64 +318,8 @@ class MWNamespace {
         * @return array
         */
        public static function getRestrictionLevels( $index, User $user = null ) {
-               global $wgNamespaceProtection, $wgRestrictionLevels;
-
-               if ( !isset( $wgNamespaceProtection[$index] ) ) {
-                       // All levels are valid if there's no namespace restriction.
-                       // But still filter by user, if necessary
-                       $levels = $wgRestrictionLevels;
-                       if ( $user ) {
-                               $levels = array_values( array_filter( $levels, function ( $level ) use ( $user ) {
-                                       $right = $level;
-                                       if ( $right == 'sysop' ) {
-                                               $right = 'editprotected'; // BC
-                                       }
-                                       if ( $right == 'autoconfirmed' ) {
-                                               $right = 'editsemiprotected'; // BC
-                                       }
-                                       return ( $right == '' || $user->isAllowed( $right ) );
-                               } ) );
-                       }
-                       return $levels;
-               }
-
-               // First, get the list of groups that can edit this namespace.
-               $namespaceGroups = [];
-               $combine = 'array_merge';
-               foreach ( (array)$wgNamespaceProtection[$index] as $right ) {
-                       if ( $right == 'sysop' ) {
-                               $right = 'editprotected'; // BC
-                       }
-                       if ( $right == 'autoconfirmed' ) {
-                               $right = 'editsemiprotected'; // BC
-                       }
-                       if ( $right != '' ) {
-                               $namespaceGroups = call_user_func( $combine, $namespaceGroups,
-                                       User::getGroupsWithPermission( $right ) );
-                               $combine = 'array_intersect';
-                       }
-               }
-
-               // Now, keep only those restriction levels where there is at least one
-               // group that can edit the namespace but would be blocked by the
-               // restriction.
-               $usableLevels = [ '' ];
-               foreach ( $wgRestrictionLevels as $level ) {
-                       $right = $level;
-                       if ( $right == 'sysop' ) {
-                               $right = 'editprotected'; // BC
-                       }
-                       if ( $right == 'autoconfirmed' ) {
-                               $right = 'editsemiprotected'; // BC
-                       }
-                       if ( $right != '' && ( !$user || $user->isAllowed( $right ) ) &&
-                               array_diff( $namespaceGroups, User::getGroupsWithPermission( $right ) )
-                       ) {
-                               $usableLevels[] = $level;
-                       }
-               }
-
-               return $usableLevels;
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       getRestrictionLevels( $index, $user );
        }
 
        /**
@@ -558,14 +333,7 @@ class MWNamespace {
         * @return string One of 'subcat', 'file', 'page'
         */
        public static function getCategoryLinkType( $index ) {
-               self::isMethodValidFor( $index, __METHOD__ );
-
-               if ( $index == NS_CATEGORY ) {
-                       return 'subcat';
-               } elseif ( $index == NS_FILE ) {
-                       return 'file';
-               } else {
-                       return 'page';
-               }
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       getCategoryLinkType( $index );
        }
 }
index 4420d1d..0984786 100644 (file)
@@ -109,11 +109,7 @@ class MagicWord {
                $this->mId = $id;
                $this->mSynonyms = (array)$syn;
                $this->mCaseSensitive = $cs;
-               $this->contLang = $contLang;
-
-               if ( !$contLang ) {
-                       $this->contLang = MediaWikiServices::getInstance()->getContentLanguage();
-               }
+               $this->contLang = $contLang ?: MediaWikiServices::getInstance()->getContentLanguage();
        }
 
        /**
@@ -125,6 +121,7 @@ class MagicWord {
         * @deprecated since 1.32, use MagicWordFactory::get
         */
        public static function get( $id ) {
+               wfDeprecated( __METHOD__, '1.32' );
                return MediaWikiServices::getInstance()->getMagicWordFactory()->get( $id );
        }
 
@@ -135,6 +132,7 @@ class MagicWord {
         * @deprecated since 1.32, use MagicWordFactory::getVariableIDs
         */
        public static function getVariableIDs() {
+               wfDeprecated( __METHOD__, '1.32' );
                return MediaWikiServices::getInstance()->getMagicWordFactory()->getVariableIDs();
        }
 
@@ -144,6 +142,7 @@ class MagicWord {
         * @deprecated since 1.32, use MagicWordFactory::getSubstIDs
         */
        public static function getSubstIDs() {
+               wfDeprecated( __METHOD__, '1.32' );
                return MediaWikiServices::getInstance()->getMagicWordFactory()->getSubstIDs();
        }
 
@@ -155,6 +154,7 @@ class MagicWord {
         * @deprecated since 1.32, use MagicWordFactory::getCacheTTL
         */
        public static function getCacheTTL( $id ) {
+               wfDeprecated( __METHOD__, '1.32' );
                return MediaWikiServices::getInstance()->getMagicWordFactory()->getCacheTTL( $id );
        }
 
@@ -165,6 +165,7 @@ class MagicWord {
         * @deprecated since 1.32, use MagicWordFactory::getDoubleUnderscoreArray
         */
        public static function getDoubleUnderscoreArray() {
+               wfDeprecated( __METHOD__, '1.32' );
                return MediaWikiServices::getInstance()->getMagicWordFactory()->getDoubleUnderscoreArray();
        }
 
index fde32ce..73d5173 100644 (file)
@@ -49,10 +49,7 @@ class MagicWordArray {
         */
        public function __construct( $names = [], MagicWordFactory $factory = null ) {
                $this->names = $names;
-               $this->factory = $factory;
-               if ( !$factory ) {
-                       $this->factory = MediaWikiServices::getInstance()->getMagicWordFactory();
-               }
+               $this->factory = $factory ?: MediaWikiServices::getInstance()->getMagicWordFactory();
        }
 
        /**
@@ -268,10 +265,7 @@ class MagicWordArray {
                        return $hash[1][$text];
                }
                $lc = $this->factory->getContentLanguage()->lc( $text );
-               if ( isset( $hash[0][$lc] ) ) {
-                       return $hash[0][$lc];
-               }
-               return false;
+               return $hash[0][$lc] ?? false;
        }
 
        /**
index 43512e1..69bafaf 100644 (file)
@@ -262,7 +262,7 @@ class MediaWiki {
                                                $target = $specialPage->getRedirect( $subpage );
                                                // target can also be true. We let that case fall through to normal processing.
                                                if ( $target instanceof Title ) {
-                                                       $query = $specialPage->getRedirectQuery() ?: [];
+                                                       $query = $specialPage->getRedirectQuery( $subpage ) ?: [];
                                                        $request = new DerivativeRequest( $this->context->getRequest(), $query );
                                                        $request->setRequestURL( $this->context->getRequest()->getRequestURL() );
                                                        $this->context->setRequest( $request );
@@ -330,7 +330,7 @@ class MediaWiki {
 
                if ( $request->getVal( 'action', 'view' ) != 'view'
                        || $request->wasPosted()
-                       || ( $request->getVal( 'title' ) !== null
+                       || ( $request->getCheck( 'title' )
                                && $title->getPrefixedDBkey() == $request->getVal( 'title' ) )
                        || count( $request->getValueNames( [ 'action', 'title' ] ) )
                        || !Hooks::run( 'TestCanonicalRedirect', [ $request, $title, $output ] )
@@ -428,11 +428,9 @@ class MediaWiki {
                        if ( !$ignoreRedirect && ( $target || $page->isRedirect() ) ) {
                                // Is the target already set by an extension?
                                $target = $target ?: $page->followRedirect();
-                               if ( is_string( $target ) ) {
-                                       if ( !$this->config->get( 'DisableHardRedirects' ) ) {
-                                               // we'll need to redirect
-                                               return $target;
-                                       }
+                               if ( is_string( $target ) && !$this->config->get( 'DisableHardRedirects' ) ) {
+                                       // we'll need to redirect
+                                       return $target;
                                }
                                if ( is_object( $target ) ) {
                                        // Rewrite environment to redirected article
@@ -937,7 +935,7 @@ class MediaWiki {
        ) {
                if ( $config->get( 'StatsdServer' ) && $stats->hasData() ) {
                        try {
-                               $statsdServer = explode( ':', $config->get( 'StatsdServer' ) );
+                               $statsdServer = explode( ':', $config->get( 'StatsdServer' ), 2 );
                                $statsdHost = $statsdServer[0];
                                $statsdPort = $statsdServer[1] ?? 8125;
                                $statsdSender = new SocketSender( $statsdHost, $statsdPort );
index 292e8df..eca5b9d 100644 (file)
@@ -6,14 +6,17 @@ use CommentStore;
 use Config;
 use ConfigFactory;
 use CryptHKDF;
-use CryptRand;
+use DateFormatterFactory;
 use EventRelayerGroup;
 use GenderCache;
 use GlobalVarConfig;
 use Hooks;
 use IBufferingStatsdDataFactory;
 use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface;
+use MediaWiki\Block\BlockManager;
+use MediaWiki\Block\BlockRestrictionStore;
 use MediaWiki\Http\HttpRequestFactory;
+use MediaWiki\Permissions\PermissionManager;
 use MediaWiki\Preferences\PreferencesFactory;
 use MediaWiki\Shell\CommandFactory;
 use MediaWiki\Revision\RevisionRenderer;
@@ -38,12 +41,14 @@ use MediaWiki\Linker\LinkRenderer;
 use MediaWiki\Linker\LinkRendererFactory;
 use MWException;
 use MimeAnalyzer;
+use NamespaceInfo;
 use ObjectCache;
 use Parser;
 use ParserCache;
 use ParserFactory;
 use PasswordFactory;
 use ProxyLookup;
+use RepoGroup;
 use ResourceLoader;
 use SearchEngine;
 use SearchEngineConfig;
@@ -61,6 +66,7 @@ use Wikimedia\Services\ServiceContainer;
 use Wikimedia\Services\NoSuchServiceException;
 use MediaWiki\Interwiki\InterwikiLookup;
 use MagicWordFactory;
+use MediaWiki\Storage\PageEditStash;
 
 /**
  * Service locator for MediaWiki core services.
@@ -219,6 +225,8 @@ class MediaWikiServices extends ServiceContainer {
                }
        }
 
+       /** @noinspection PhpDocSignatureInspection */
+
        /**
         * Salvages the state of any salvageable service instances in $other.
         *
@@ -433,6 +441,22 @@ class MediaWikiServices extends ServiceContainer {
                return $this->getService( 'BlobStoreFactory' );
        }
 
+       /**
+        * @since 1.34
+        * @return BlockManager
+        */
+       public function getBlockManager() : BlockManager {
+               return $this->getService( 'BlockManager' );
+       }
+
+       /**
+        * @since 1.33
+        * @return BlockRestrictionStore
+        */
+       public function getBlockRestrictionStore() : BlockRestrictionStore {
+               return $this->getService( 'BlockRestrictionStore' );
+       }
+
        /**
         * Returns the Config object containing the bootstrap configuration.
         * Bootstrap configuration would typically include database credentials
@@ -515,13 +539,11 @@ class MediaWikiServices extends ServiceContainer {
        }
 
        /**
-        * @since 1.28
-        * @deprecated since 1.32, use random_bytes()/random_int()
-        * @return CryptRand
+        * @since 1.33
+        * @return DateFormatterFactory
         */
-       public function getCryptRand() {
-               wfDeprecated( __METHOD__, '1.32' );
-               return $this->getService( 'CryptRand' );
+       public function getDateFormatterFactory() {
+               return $this->getService( 'DateFormatterFactory' );
        }
 
        /**
@@ -666,6 +688,14 @@ class MediaWikiServices extends ServiceContainer {
                return $this->getService( 'MimeAnalyzer' );
        }
 
+       /**
+        * @since 1.34
+        * @return NamespaceInfo
+        */
+       public function getNamespaceInfo() : NamespaceInfo {
+               return $this->getService( 'NamespaceInfo' );
+       }
+
        /**
         * @since 1.32
         * @return NameTableStoreFactory
@@ -675,12 +705,21 @@ class MediaWikiServices extends ServiceContainer {
        }
 
        /**
+        * @since 1.32
         * @return OldRevisionImporter
         */
        public function getOldRevisionImporter() {
                return $this->getService( 'OldRevisionImporter' );
        }
 
+       /**
+        * @return PageEditStash
+        * @since 1.34
+        */
+       public function getPageEditStash() {
+               return $this->getService( 'PageEditStash' );
+       }
+
        /**
         * @since 1.29
         * @return Parser
@@ -721,6 +760,14 @@ class MediaWikiServices extends ServiceContainer {
                return $this->getService( 'PerDbNameStatsdDataFactory' );
        }
 
+       /**
+        * @since 1.33
+        * @return PermissionManager
+        */
+       public function getPermissionManager() {
+               return $this->getService( 'PermissionManager' );
+       }
+
        /**
         * @since 1.31
         * @return PreferencesFactory
@@ -745,6 +792,14 @@ class MediaWikiServices extends ServiceContainer {
                return $this->getService( 'ReadOnlyMode' );
        }
 
+       /**
+        * @since 1.34
+        * @return RepoGroup
+        */
+       public function getRepoGroup() : RepoGroup {
+               return $this->getService( 'RepoGroup' );
+       }
+
        /**
         * @since 1.33
         * @return ResourceLoader
index 0914a9b..6bd4471 100644 (file)
@@ -32,7 +32,7 @@ use Wikimedia\Rdbms\IDatabase;
  */
 class MergeHistory {
 
-       /** @const int Maximum number of revisions that can be merged at once */
+       /** Maximum number of revisions that can be merged at once */
        const REVISION_LIMIT = 5000;
 
        /** @var Title Page from which history will be merged */
index 4049e11..0b3113f 100644 (file)
@@ -1163,14 +1163,11 @@ class Message implements MessageSpecifier, Serializable {
                                        // escaped, breaking the replacement and avoiding XSS.
                                        $replacementKeys['$' . ( $n + 1 )] = $marker . ( $n + 1 );
                                }
-                       } else {
-                               if ( $paramType === 'after' ) {
-                                       $replacementKeys[$marker . ( $n + 1 )] = $value;
-                               }
+                       } elseif ( $paramType === 'after' ) {
+                               $replacementKeys[$marker . ( $n + 1 )] = $value;
                        }
                }
-               $message = strtr( $message, $replacementKeys );
-               return $message;
+               return strtr( $message, $replacementKeys );
        }
 
        /**
index bcec0a1..004ca07 100644 (file)
@@ -106,7 +106,7 @@ class MovePage {
 
                $oldid = $this->oldTitle->getArticleID();
 
-               if ( strlen( $this->newTitle->getDBkey() ) < 1 ) {
+               if ( $this->newTitle->getDBkey() === '' ) {
                        $status->fatal( 'articleexists' );
                }
                if (
@@ -233,14 +233,69 @@ class MovePage {
        }
 
        /**
+        * Move a page without taking user permissions into account. Only checks if the move is itself
+        * invalid, e.g., trying to move a special page or trying to move a page onto one that already
+        * exists.
+        *
+        * @param User $user
+        * @param string|null $reason
+        * @param bool|null $createRedirect
+        * @param string[] $changeTags Change tags to apply to the entry in the move log
+        * @return Status
+        */
+       public function move(
+               User $user, $reason = null, $createRedirect = true, array $changeTags = []
+       ) {
+               $status = $this->isValidMove();
+               if ( !$status->isOK() ) {
+                       return $status;
+               }
+
+               return $this->moveUnsafe( $user, $reason, $createRedirect, $changeTags );
+       }
+
+       /**
+        * Same as move(), but with permissions checks.
+        *
+        * @param User $user
+        * @param string|null $reason
+        * @param bool|null $createRedirect Ignored if user doesn't have suppressredirect permission
+        * @param string[] $changeTags Change tags to apply to the entry in the move log
+        * @return Status
+        */
+       public function moveIfAllowed(
+               User $user, $reason = null, $createRedirect = true, array $changeTags = []
+       ) {
+               $status = $this->isValidMove();
+               $status->merge( $this->checkPermissions( $user, $reason ) );
+               if ( $changeTags ) {
+                       $status->merge( ChangeTags::canAddTagsAccompanyingChange( $changeTags, $user ) );
+               }
+
+               if ( !$status->isOK() ) {
+                       // Auto-block user's IP if the account was "hard" blocked
+                       $user->spreadAnyEditBlock();
+                       return $status;
+               }
+
+               // Check suppressredirect permission
+               if ( !$user->isAllowed( 'suppressredirect' ) ) {
+                       $createRedirect = true;
+               }
+
+               return $this->moveUnsafe( $user, $reason, $createRedirect, $changeTags );
+       }
+
+       /**
+        * Moves *without* any sort of safety or sanity checks. Hooks can still fail the move, however.
+        *
         * @param User $user
         * @param string $reason
         * @param bool $createRedirect
-        * @param string[] $changeTags Change tags to apply to the entry in the move log. Caller
-        *  should perform permission checks with ChangeTags::canAddTagsAccompanyingChange
+        * @param string[] $changeTags Change tags to apply to the entry in the move log
         * @return Status
         */
-       public function move( User $user, $reason, $createRedirect, array $changeTags = [] ) {
+       private function moveUnsafe( User $user, $reason, $createRedirect, array $changeTags ) {
                global $wgCategoryCollation;
 
                $status = Status::newGood();
@@ -272,7 +327,9 @@ class MovePage {
                        [ 'cl_from' => $pageid ],
                        __METHOD__
                );
-               $type = MWNamespace::getCategoryLinkType( $this->newTitle->getNamespace() );
+               $services = MediaWikiServices::getInstance();
+               $type = $services->getNamespaceInfo()->
+                       getCategoryLinkType( $this->newTitle->getNamespace() );
                foreach ( $prefixes as $prefixRow ) {
                        $prefix = $prefixRow->cl_sortkey_prefix;
                        $catTo = $prefixRow->cl_to;
@@ -372,11 +429,13 @@ class MovePage {
                # Update watchlists
                $oldtitle = $this->oldTitle->getDBkey();
                $newtitle = $this->newTitle->getDBkey();
-               $oldsnamespace = MWNamespace::getSubject( $this->oldTitle->getNamespace() );
-               $newsnamespace = MWNamespace::getSubject( $this->newTitle->getNamespace() );
+               $oldsnamespace = $services->getNamespaceInfo()->
+                       getSubject( $this->oldTitle->getNamespace() );
+               $newsnamespace = $services->getNamespaceInfo()->
+                       getSubject( $this->newTitle->getNamespace() );
                if ( $oldsnamespace != $newsnamespace || $oldtitle != $newtitle ) {
-                       $store = MediaWikiServices::getInstance()->getWatchedItemStore();
-                       $store->duplicateAllAssociatedEntries( $this->oldTitle, $this->newTitle );
+                       $services->getWatchedItemStore()->duplicateAllAssociatedEntries(
+                               $this->oldTitle, $this->newTitle );
                }
 
                // If it is a file then move it last.
@@ -427,8 +486,8 @@ class MovePage {
         * Can also be used to revert after a DB failure.
         *
         * @private
-        * @param Title Old location to move the file from.
-        * @param Title New location to move the file to.
+        * @param Title $oldTitle Old location to move the file from.
+        * @param Title $newTitle New location to move the file to.
         * @return Status
         */
        private function moveFile( $oldTitle, $newTitle ) {
index 16c3784..ba9e2d7 100644 (file)
@@ -62,7 +62,7 @@ class OutputHandler {
                /// @todo FIXME: this sort of dupes some code in WebRequest::getRequestUrl()
                if ( isset( $_SERVER['REQUEST_URI'] ) ) {
                        // Strip the query string...
-                       list( $path ) = explode( '?', $_SERVER['REQUEST_URI'], 2 );
+                       $path = explode( '?', $_SERVER['REQUEST_URI'], 2 )[0];
                } elseif ( isset( $_SERVER['SCRIPT_NAME'] ) ) {
                        // Probably IIS. QUERY_STRING appears separately.
                        $path = $_SERVER['SCRIPT_NAME'];
index cb90ccf..edffc3b 100644 (file)
@@ -548,15 +548,6 @@ class OutputPage extends ContextSource {
                $this->mModules = array_merge( $this->mModules, (array)$modules );
        }
 
-       /**
-        * @deprecated since 1.33 Use getModules() instead.
-        * @return array
-        */
-       public function getModuleScripts() {
-               wfDeprecated( __METHOD__, '1.33' );
-               return [];
-       }
-
        /**
         * Get the list of style-only modules to load on this page.
         *
@@ -1487,7 +1478,7 @@ class OutputPage extends ContextSource {
                        $helpUrl = $to;
                } else {
                        $toUrlencoded = wfUrlencode( str_replace( ' ', '_', $to ) );
-                       $helpUrl = "//www.mediawiki.org/wiki/Special:MyLanguage/$toUrlencoded";
+                       $helpUrl = "https://www.mediawiki.org/wiki/Special:MyLanguage/$toUrlencoded";
                }
 
                $link = Html::rawElement(
@@ -2187,7 +2178,7 @@ class OutputPage extends ContextSource {
         * Parse wikitext and return the HTML (internal implementation helper)
         *
         * @param string $text
-        * @param Title The title to use
+        * @param Title $title The title to use
         * @param bool $linestart Is this the start of a line?
         * @param bool $tidy Whether the output should be tidied
         * @param bool $interface Use interface language (instead of content language) while parsing
@@ -2198,8 +2189,6 @@ class OutputPage extends ContextSource {
         * @return ParserOutput
         */
        private function parseInternal( $text, $title, $linestart, $tidy, $interface, $language ) {
-               global $wgParser;
-
                if ( is_null( $title ) ) {
                        throw new MWException( 'Empty $mTitle in ' . __METHOD__ );
                }
@@ -2212,7 +2201,7 @@ class OutputPage extends ContextSource {
                        $oldLang = $popts->setTargetLanguage( $language );
                }
 
-               $parserOutput = $wgParser->getFreshParser()->parse(
+               $parserOutput = MediaWikiServices::getInstance()->getParser()->getFreshParser()->parse(
                        $text, $title, $popts,
                        $linestart, true, $this->mRevisionId
                );
@@ -2527,6 +2516,37 @@ class OutputPage extends ContextSource {
                return $config->get( 'OriginTrials' );
        }
 
+       private function getReportTo() {
+               $config = $this->getConfig();
+
+               $expiry = $config->get( 'ReportToExpiry' );
+
+               if ( !$expiry ) {
+                       return false;
+               }
+
+               $endpoints = $config->get( 'ReportToEndpoints' );
+
+               if ( !$endpoints ) {
+                       return false;
+               }
+
+               $output = [ 'max_age' => $expiry, 'endpoints' => [] ];
+
+               foreach ( $endpoints as $endpoint ) {
+                       $output['endpoints'][] = [ 'url' => $endpoint ];
+               }
+
+               return json_encode( $output, JSON_UNESCAPED_SLASHES );
+       }
+
+       private function getFeaturePolicyReportOnly() {
+               $config = $this->getConfig();
+
+               $features = $config->get( 'FeaturePolicyReportOnly' );
+               return implode( ';', $features );
+       }
+
        /**
         * Send cache control HTTP headers
         */
@@ -2678,10 +2698,6 @@ class OutputPage extends ContextSource {
                $response->header( 'Content-language: ' .
                        MediaWikiServices::getInstance()->getContentLanguage()->getHtmlCode() );
 
-               if ( !$this->mArticleBodyOnly ) {
-                       $sk = $this->getSkin();
-               }
-
                $linkHeader = $this->getLinkHeader();
                if ( $linkHeader ) {
                        $response->header( $linkHeader );
@@ -2698,6 +2714,16 @@ class OutputPage extends ContextSource {
                        $response->header( "Origin-Trial: $originTrial", false );
                }
 
+               $reportTo = $this->getReportTo();
+               if ( $reportTo ) {
+                       $response->header( "Report-To: $reportTo" );
+               }
+
+               $featurePolicyReportOnly = $this->getFeaturePolicyReportOnly();
+               if ( $featurePolicyReportOnly ) {
+                       $response->header( "Feature-Policy-Report-Only: $featurePolicyReportOnly" );
+               }
+
                ContentSecurityPolicy::sendHeaders( $this );
 
                if ( $this->mArticleBodyOnly ) {
@@ -2963,46 +2989,6 @@ class OutputPage extends ContextSource {
                $this->addHTML( $message );
        }
 
-       /**
-        * @deprecated 1.32 Use OutputPage::showFatalError or throw FatalError instead.
-        */
-       public function showUnexpectedValueError( $name, $val ) {
-               wfDeprecated( __METHOD__, '1.32' );
-               $this->showFatalError( $this->msg( 'unexpected', $name, $val )->escaped() );
-       }
-
-       /**
-        * @deprecated 1.32 Use OutputPage::showFatalError or throw FatalError instead.
-        */
-       public function showFileCopyError( $old, $new ) {
-               wfDeprecated( __METHOD__, '1.32' );
-               $this->showFatalError( $this->msg( 'filecopyerror', $old, $new )->escaped() );
-       }
-
-       /**
-        * @deprecated 1.32 Use OutputPage::showFatalError or throw FatalError instead.
-        */
-       public function showFileRenameError( $old, $new ) {
-               wfDeprecated( __METHOD__, '1.32' );
-               $this->showFatalError( $this->msg( 'filerenameerror', $old, $new )->escpaed() );
-       }
-
-       /**
-        * @deprecated 1.32 Use OutputPage::showFatalError or throw FatalError instead.
-        */
-       public function showFileDeleteError( $name ) {
-               wfDeprecated( __METHOD__, '1.32' );
-               $this->showFatalError( $this->msg( 'filedeleteerror', $name )->escaped() );
-       }
-
-       /**
-        * @deprecated 1.32 Use OutputPage::showFatalError or throw FatalError instead.
-        */
-       public function showFileNotFoundError( $name ) {
-               wfDeprecated( __METHOD__, '1.32' );
-               $this->showFatalError( $this->msg( 'filenotfound', $name )->escaped() );
-       }
-
        /**
         * Add a "return to" link pointing to a specified title
         *
@@ -3223,7 +3209,10 @@ class OutputPage extends ContextSource {
                // Use an IE conditional comment to serve the script only to old IE
                $pieces[] = '<!--[if lt IE 9]>' .
                        ResourceLoaderClientHtml::makeLoad(
-                               ResourceLoaderContext::newDummyContext(),
+                               new ResourceLoaderContext(
+                                       $this->getResourceLoader(),
+                                       new FauxRequest( [] )
+                               ),
                                [ 'html5shiv' ],
                                ResourceLoaderModule::TYPE_SCRIPTS,
                                [ 'sync' => true ],
@@ -3392,8 +3381,9 @@ class OutputPage extends ContextSource {
 
                $title = $this->getTitle();
                $ns = $title->getNamespace();
-               $canonicalNamespace = MWNamespace::exists( $ns )
-                       ? MWNamespace::getCanonicalName( $ns )
+               $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
+               $canonicalNamespace = $nsInfo->exists( $ns )
+                       ? $nsInfo->getCanonicalName( $ns )
                        : $title->getNsText();
 
                $sk = $this->getSkin();
@@ -3785,26 +3775,24 @@ class OutputPage extends ContextSource {
                if ( $config->get( 'EnableCanonicalServerLink' ) ) {
                        if ( $canonicalUrl !== false ) {
                                $canonicalUrl = wfExpandUrl( $canonicalUrl, PROTO_CANONICAL );
-                       } else {
-                               if ( $this->isArticleRelated() ) {
-                                       // This affects all requests where "setArticleRelated" is true. This is
-                                       // typically all requests that show content (query title, curid, oldid, diff),
-                                       // and all wikipage actions (edit, delete, purge, info, history etc.).
-                                       // It does not apply to File pages and Special pages.
-                                       // 'history' and 'info' actions address page metadata rather than the page
-                                       // content itself, so they may not be canonicalized to the view page url.
-                                       // TODO: this ought to be better encapsulated in the Action class.
-                                       $action = Action::getActionName( $this->getContext() );
-                                       if ( in_array( $action, [ 'history', 'info' ] ) ) {
-                                               $query = "action={$action}";
-                                       } else {
-                                               $query = '';
-                                       }
-                                       $canonicalUrl = $this->getTitle()->getCanonicalURL( $query );
+                       } elseif ( $this->isArticleRelated() ) {
+                               // This affects all requests where "setArticleRelated" is true. This is
+                               // typically all requests that show content (query title, curid, oldid, diff),
+                               // and all wikipage actions (edit, delete, purge, info, history etc.).
+                               // It does not apply to File pages and Special pages.
+                               // 'history' and 'info' actions address page metadata rather than the page
+                               // content itself, so they may not be canonicalized to the view page url.
+                               // TODO: this ought to be better encapsulated in the Action class.
+                               $action = Action::getActionName( $this->getContext() );
+                               if ( in_array( $action, [ 'history', 'info' ] ) ) {
+                                       $query = "action={$action}";
                                } else {
-                                       $reqUrl = $this->getRequest()->getRequestURL();
-                                       $canonicalUrl = wfExpandUrl( $reqUrl, PROTO_CANONICAL );
+                                       $query = '';
                                }
+                               $canonicalUrl = $this->getTitle()->getCanonicalURL( $query );
+                       } else {
+                               $reqUrl = $this->getRequest()->getRequestURL();
+                               $canonicalUrl = wfExpandUrl( $reqUrl, PROTO_CANONICAL );
                        }
                }
                if ( $canonicalUrl !== false ) {
@@ -3948,10 +3936,8 @@ class OutputPage extends ContextSource {
         * @return string HTML fragment
         */
        protected function styleLink( $style, array $options ) {
-               if ( isset( $options['dir'] ) ) {
-                       if ( $this->getLanguage()->getDir() != $options['dir'] ) {
-                               return '';
-                       }
+               if ( isset( $options['dir'] ) && $this->getLanguage()->getDir() != $options['dir'] ) {
+                       return '';
                }
 
                if ( isset( $options['media'] ) ) {
@@ -4196,16 +4182,6 @@ class OutputPage extends ContextSource {
                wfDeprecated( __METHOD__, '1.31' );
        }
 
-       /**
-        * @return bool
-        * @since 1.23
-        * @deprecated since 1.31, use $poOptions to addParserOutput() instead.
-        */
-       public function sectionEditLinksEnabled() {
-               wfDeprecated( __METHOD__, '1.31' );
-               return true;
-       }
-
        /**
         * Helper function to setup the PHP implementation of OOUI to use in this request.
         *
index cbe63a3..2d9216d 100644 (file)
@@ -20,6 +20,7 @@
 
 // phpcs:disable Generic.Arrays.DisallowLongArraySyntax,PSR2.Classes.PropertyDeclaration,MediaWiki.Usage.DirUsage
 // phpcs:disable Squiz.Scope.MemberVarScope.Missing,Squiz.Scope.MethodScope.Missing
+// @phan-file-suppress PhanPluginDuplicateConditionalNullCoalescing
 /**
  * Check PHP Version, as well as for composer dependencies in entry points,
  * and display something vaguely comprehensible in the event of a totally
@@ -35,7 +36,7 @@
  */
 class PHPVersionCheck {
        /* @var string The number of the MediaWiki version used. */
-       var $mwVersion = '1.33';
+       var $mwVersion = '1.34';
 
        /* @var array A mapping of PHP functions to PHP extensions. */
        var $functionsExtensionsMapping = array(
@@ -111,7 +112,7 @@ class PHPVersionCheck {
                        'vendor' => 'the PHP Group',
                        'upstreamSupported' => '5.6.0',
                        'minSupported' => '7.0.13',
-                       'upgradeURL' => 'https://secure.php.net/downloads.php',
+                       'upgradeURL' => 'https://www.php.net/downloads.php',
                );
        }
 
@@ -205,7 +206,7 @@ HTML;
 
                        $missingExtText = '';
                        $missingExtHtml = '';
-                       $baseUrl = 'https://secure.php.net';
+                       $baseUrl = 'https://www.php.net';
                        foreach ( $missingExtensions as $ext ) {
                                $missingExtText .= " * $ext <$baseUrl/$ext>\n";
                                $missingExtHtml .= "<li><b>$ext</b> "
index df2451c..a84370f 100644 (file)
@@ -129,12 +129,10 @@ class PageProps {
                                if ( $propertyValue === false ) {
                                        $queryIDs[] = $pageID;
                                        break;
+                               } elseif ( $gotArray ) {
+                                       $values[$pageID][$propertyName] = $propertyValue;
                                } else {
-                                       if ( $gotArray ) {
-                                               $values[$pageID][$propertyName] = $propertyValue;
-                                       } else {
-                                               $values[$pageID] = $propertyValue;
-                                       }
+                                       $values[$pageID] = $propertyValue;
                                }
                        }
                }
index db12e74..eb52d7c 100644 (file)
@@ -133,10 +133,8 @@ class PathRouter {
                // Loop over our options and convert any single value $# restrictions
                // into an array so we only have to do in_array tests.
                foreach ( $options as $optionName => $optionData ) {
-                       if ( preg_match( '/^\$\d+$/u', $optionName ) ) {
-                               if ( !is_array( $optionData ) ) {
-                                       $options[$optionName] = [ $optionData ];
-                               }
+                       if ( preg_match( '/^\$\d+$/u', $optionName ) && !is_array( $optionData ) ) {
+                               $options[$optionName] = [ $optionData ];
                        }
                }
 
diff --git a/includes/Permissions/PermissionManager.php b/includes/Permissions/PermissionManager.php
new file mode 100644 (file)
index 0000000..e443803
--- /dev/null
@@ -0,0 +1,1055 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+namespace MediaWiki\Permissions;
+
+use Action;
+use Exception;
+use FatalError;
+use Hooks;
+use MediaWiki\Linker\LinkTarget;
+use MediaWiki\Special\SpecialPageFactory;
+use MessageSpecifier;
+use MWException;
+use NamespaceInfo;
+use RequestContext;
+use SpecialPage;
+use Title;
+use User;
+use WikiPage;
+
+/**
+ * A service class for checking permissions
+ * To obtain an instance, use MediaWikiServices::getInstance()->getPermissionManager().
+ *
+ * @since 1.33
+ */
+class PermissionManager {
+
+       /** @var string Does cheap permission checks from replica DBs (usable for GUI creation) */
+       const RIGOR_QUICK = 'quick';
+
+       /** @var string Does cheap and expensive checks possibly from a replica DB */
+       const RIGOR_FULL = 'full';
+
+       /** @var string Does cheap and expensive checks, using the master as needed */
+       const RIGOR_SECURE = 'secure';
+
+       /** @var SpecialPageFactory */
+       private $specialPageFactory;
+
+       /** @var string[] List of pages names anonymous user may see */
+       private $whitelistRead;
+
+       /** @var string[] Whitelists publicly readable titles with regular expressions */
+       private $whitelistReadRegexp;
+
+       /** @var bool Require users to confirm email address before they can edit */
+       private $emailConfirmToEdit;
+
+       /** @var bool If set to true, blocked users will no longer be allowed to log in */
+       private $blockDisablesLogin;
+
+       /** @var NamespaceInfo */
+       private $nsInfo;
+
+       /**
+        * @param SpecialPageFactory $specialPageFactory
+        * @param string[] $whitelistRead
+        * @param string[] $whitelistReadRegexp
+        * @param bool $emailConfirmToEdit
+        * @param bool $blockDisablesLogin
+        * @param NamespaceInfo $nsInfo
+        */
+       public function __construct(
+               SpecialPageFactory $specialPageFactory,
+               $whitelistRead,
+               $whitelistReadRegexp,
+               $emailConfirmToEdit,
+               $blockDisablesLogin,
+               NamespaceInfo $nsInfo
+       ) {
+               $this->specialPageFactory = $specialPageFactory;
+               $this->whitelistRead = $whitelistRead;
+               $this->whitelistReadRegexp = $whitelistReadRegexp;
+               $this->emailConfirmToEdit = $emailConfirmToEdit;
+               $this->blockDisablesLogin = $blockDisablesLogin;
+               $this->nsInfo = $nsInfo;
+       }
+
+       /**
+        * Can $user perform $action on a page?
+        *
+        * The method is intended to replace Title::userCan()
+        * The $user parameter need to be superseded by UserIdentity value in future
+        * The $title parameter need to be superseded by PageIdentity value in future
+        *
+        * @see Title::userCan()
+        *
+        * @param string $action
+        * @param User $user
+        * @param LinkTarget $page
+        * @param string $rigor One of PermissionManager::RIGOR_ constants
+        *   - RIGOR_QUICK  : does cheap permission checks from replica DBs (usable for GUI creation)
+        *   - RIGOR_FULL   : does cheap and expensive checks possibly from a replica DB
+        *   - RIGOR_SECURE : does cheap and expensive checks, using the master as needed
+        *
+        * @return bool
+        * @throws Exception
+        */
+       public function userCan( $action, User $user, LinkTarget $page, $rigor = self::RIGOR_SECURE ) {
+               return !count( $this->getPermissionErrorsInternal( $action, $user, $page, $rigor, true ) );
+       }
+
+       /**
+        * Can $user perform $action on a page?
+        *
+        * @todo FIXME: This *does not* check throttles (User::pingLimiter()).
+        *
+        * @param string $action Action that permission needs to be checked for
+        * @param User $user User to check
+        * @param LinkTarget $page
+        * @param string $rigor One of PermissionManager::RIGOR_ constants
+        *   - RIGOR_QUICK  : does cheap permission checks from replica DBs (usable for GUI creation)
+        *   - RIGOR_FULL   : does cheap and expensive checks possibly from a replica DB
+        *   - RIGOR_SECURE : does cheap and expensive checks, using the master as needed
+        * @param array $ignoreErrors Array of Strings Set this to a list of message keys
+        *   whose corresponding errors may be ignored.
+        *
+        * @return array Array of arrays of the arguments to wfMessage to explain permissions problems.
+        * @throws Exception
+        */
+       public function getPermissionErrors(
+               $action,
+               User $user,
+               LinkTarget $page,
+               $rigor = self::RIGOR_SECURE,
+               $ignoreErrors = []
+       ) {
+               $errors = $this->getPermissionErrorsInternal( $action, $user, $page, $rigor );
+
+               // Remove the errors being ignored.
+               foreach ( $errors as $index => $error ) {
+                       $errKey = is_array( $error ) ? $error[0] : $error;
+
+                       if ( in_array( $errKey, $ignoreErrors ) ) {
+                               unset( $errors[$index] );
+                       }
+                       if ( $errKey instanceof MessageSpecifier && in_array( $errKey->getKey(), $ignoreErrors ) ) {
+                               unset( $errors[$index] );
+                       }
+               }
+
+               return $errors;
+       }
+
+       /**
+        * Check if user is blocked from editing a particular article
+        *
+        * @param User $user
+        * @param LinkTarget $page Title to check
+        * @param bool $fromReplica Whether to check the replica DB instead of the master
+        *
+        * @return bool
+        * @throws FatalError
+        * @throws MWException
+        */
+       public function isBlockedFrom( User $user, LinkTarget $page, $fromReplica = false ) {
+               $blocked = $user->isHidden();
+
+               // TODO: remove upon further migration to LinkTarget
+               $page = Title::newFromLinkTarget( $page );
+
+               if ( !$blocked ) {
+                       $block = $user->getBlock( $fromReplica );
+                       if ( $block ) {
+                               // Special handling for a user's own talk page. The block is not aware
+                               // of the user, so this must be done here.
+                               if ( $page->equals( $user->getTalkPage() ) ) {
+                                       $blocked = $block->appliesToUsertalk( $page );
+                               } else {
+                                       $blocked = $block->appliesToTitle( $page );
+                               }
+                       }
+               }
+
+               // only for the purpose of the hook. We really don't need this here.
+               $allowUsertalk = $user->isAllowUsertalk();
+
+               Hooks::run( 'UserIsBlockedFrom', [ $user, $page, &$blocked, &$allowUsertalk ] );
+
+               return $blocked;
+       }
+
+       /**
+        * Can $user perform $action on a page? This is an internal function,
+        * with multiple levels of checks depending on performance needs; see $rigor below.
+        * It does not check wfReadOnly().
+        *
+        * @param string $action Action that permission needs to be checked for
+        * @param User $user User to check
+        * @param LinkTarget $page
+        * @param string $rigor One of PermissionManager::RIGOR_ constants
+        *   - RIGOR_QUICK  : does cheap permission checks from replica DBs (usable for GUI creation)
+        *   - RIGOR_FULL   : does cheap and expensive checks possibly from a replica DB
+        *   - RIGOR_SECURE : does cheap and expensive checks, using the master as needed
+        * @param bool $short Set this to true to stop after the first permission error.
+        *
+        * @return array Array of arrays of the arguments to wfMessage to explain permissions problems.
+        * @throws Exception
+        */
+       private function getPermissionErrorsInternal(
+               $action,
+               User $user,
+               LinkTarget $page,
+               $rigor = self::RIGOR_SECURE,
+               $short = false
+       ) {
+               if ( !in_array( $rigor, [ self::RIGOR_QUICK, self::RIGOR_FULL, self::RIGOR_SECURE ] ) ) {
+                       throw new Exception( "Invalid rigor parameter '$rigor'." );
+               }
+
+               # Read has special handling
+               if ( $action == 'read' ) {
+                       $checks = [
+                               'checkPermissionHooks',
+                               'checkReadPermissions',
+                               'checkUserBlock', // for wgBlockDisablesLogin
+                       ];
+                       # Don't call checkSpecialsAndNSPermissions, checkSiteConfigPermissions
+                       # or checkUserConfigPermissions here as it will lead to duplicate
+                       # error messages. This is okay to do since anywhere that checks for
+                       # create will also check for edit, and those checks are called for edit.
+               } elseif ( $action == 'create' ) {
+                       $checks = [
+                               'checkQuickPermissions',
+                               'checkPermissionHooks',
+                               'checkPageRestrictions',
+                               'checkCascadingSourcesRestrictions',
+                               'checkActionPermissions',
+                               'checkUserBlock'
+                       ];
+               } else {
+                       $checks = [
+                               'checkQuickPermissions',
+                               'checkPermissionHooks',
+                               'checkSpecialsAndNSPermissions',
+                               'checkSiteConfigPermissions',
+                               'checkUserConfigPermissions',
+                               'checkPageRestrictions',
+                               'checkCascadingSourcesRestrictions',
+                               'checkActionPermissions',
+                               'checkUserBlock'
+                       ];
+               }
+
+               $errors = [];
+               foreach ( $checks as $method ) {
+                       $errors = $this->$method( $action, $user, $errors, $rigor, $short, $page );
+
+                       if ( $short && $errors !== [] ) {
+                               break;
+                       }
+               }
+
+               return $errors;
+       }
+
+       /**
+        * Check various permission hooks
+        *
+        * @param string $action The action to check
+        * @param User $user User to check
+        * @param array $errors List of current errors
+        * @param string $rigor One of PermissionManager::RIGOR_ constants
+        *   - RIGOR_QUICK  : does cheap permission checks from replica DBs (usable for GUI creation)
+        *   - RIGOR_FULL   : does cheap and expensive checks possibly from a replica DB
+        *   - RIGOR_SECURE : does cheap and expensive checks, using the master as needed
+        * @param bool $short Short circuit on first error
+        *
+        * @param LinkTarget $page
+        *
+        * @return array List of errors
+        * @throws FatalError
+        * @throws MWException
+        */
+       private function checkPermissionHooks(
+               $action,
+               User $user,
+               $errors,
+               $rigor,
+               $short,
+               LinkTarget $page
+       ) {
+               // TODO: remove when LinkTarget usage will expand further
+               $page = Title::newFromLinkTarget( $page );
+               // Use getUserPermissionsErrors instead
+               $result = '';
+               if ( !Hooks::run( 'userCan', [ &$page, &$user, $action, &$result ] ) ) {
+                       return $result ? [] : [ [ 'badaccess-group0' ] ];
+               }
+               // Check getUserPermissionsErrors hook
+               if ( !Hooks::run( 'getUserPermissionsErrors', [ &$page, &$user, $action, &$result ] ) ) {
+                       $errors = $this->resultToError( $errors, $result );
+               }
+               // Check getUserPermissionsErrorsExpensive hook
+               if (
+                       $rigor !== self::RIGOR_QUICK
+                       && !( $short && count( $errors ) > 0 )
+                       && !Hooks::run( 'getUserPermissionsErrorsExpensive', [ &$page, &$user, $action, &$result ] )
+               ) {
+                       $errors = $this->resultToError( $errors, $result );
+               }
+
+               return $errors;
+       }
+
+       /**
+        * Add the resulting error code to the errors array
+        *
+        * @param array $errors List of current errors
+        * @param array $result Result of errors
+        *
+        * @return array List of errors
+        */
+       private function resultToError( $errors, $result ) {
+               if ( is_array( $result ) && count( $result ) && !is_array( $result[0] ) ) {
+                       // A single array representing an error
+                       $errors[] = $result;
+               } elseif ( is_array( $result ) && is_array( $result[0] ) ) {
+                       // A nested array representing multiple errors
+                       $errors = array_merge( $errors, $result );
+               } elseif ( $result !== '' && is_string( $result ) ) {
+                       // A string representing a message-id
+                       $errors[] = [ $result ];
+               } elseif ( $result instanceof MessageSpecifier ) {
+                       // A message specifier representing an error
+                       $errors[] = [ $result ];
+               } elseif ( $result === false ) {
+                       // a generic "We don't want them to do that"
+                       $errors[] = [ 'badaccess-group0' ];
+               }
+               return $errors;
+       }
+
+       /**
+        * Check that the user is allowed to read this page.
+        *
+        * @param string $action The action to check
+        * @param User $user User to check
+        * @param array $errors List of current errors
+        * @param string $rigor One of PermissionManager::RIGOR_ constants
+        *   - RIGOR_QUICK  : does cheap permission checks from replica DBs (usable for GUI creation)
+        *   - RIGOR_FULL   : does cheap and expensive checks possibly from a replica DB
+        *   - RIGOR_SECURE : does cheap and expensive checks, using the master as needed
+        * @param bool $short Short circuit on first error
+        *
+        * @param LinkTarget $page
+        *
+        * @return array List of errors
+        * @throws FatalError
+        * @throws MWException
+        */
+       private function checkReadPermissions(
+               $action,
+               User $user,
+               $errors,
+               $rigor,
+               $short,
+               LinkTarget $page
+       ) {
+               // TODO: remove when LinkTarget usage will expand further
+               $page = Title::newFromLinkTarget( $page );
+
+               $whitelisted = false;
+               if ( User::isEveryoneAllowed( 'read' ) ) {
+                       # Shortcut for public wikis, allows skipping quite a bit of code
+                       $whitelisted = true;
+               } elseif ( $user->isAllowed( 'read' ) ) {
+                       # If the user is allowed to read pages, he is allowed to read all pages
+                       $whitelisted = true;
+               } elseif ( $this->isSameSpecialPage( 'Userlogin', $page )
+                                  || $this->isSameSpecialPage( 'PasswordReset', $page )
+                                  || $this->isSameSpecialPage( 'Userlogout', $page )
+               ) {
+                       # Always grant access to the login page.
+                       # Even anons need to be able to log in.
+                       $whitelisted = true;
+               } elseif ( is_array( $this->whitelistRead ) && count( $this->whitelistRead ) ) {
+                       # Time to check the whitelist
+                       # Only do these checks is there's something to check against
+                       $name = $page->getPrefixedText();
+                       $dbName = $page->getPrefixedDBkey();
+
+                       // Check for explicit whitelisting with and without underscores
+                       if ( in_array( $name, $this->whitelistRead, true )
+                                || in_array( $dbName, $this->whitelistRead, true ) ) {
+                               $whitelisted = true;
+                       } elseif ( $page->getNamespace() == NS_MAIN ) {
+                               # Old settings might have the title prefixed with
+                               # a colon for main-namespace pages
+                               if ( in_array( ':' . $name, $this->whitelistRead ) ) {
+                                       $whitelisted = true;
+                               }
+                       } elseif ( $page->isSpecialPage() ) {
+                               # If it's a special page, ditch the subpage bit and check again
+                               $name = $page->getDBkey();
+                               list( $name, /* $subpage */ ) =
+                                       $this->specialPageFactory->resolveAlias( $name );
+                               if ( $name ) {
+                                       $pure = SpecialPage::getTitleFor( $name )->getPrefixedText();
+                                       if ( in_array( $pure, $this->whitelistRead, true ) ) {
+                                               $whitelisted = true;
+                                       }
+                               }
+                       }
+               }
+
+               if ( !$whitelisted && is_array( $this->whitelistReadRegexp )
+                        && !empty( $this->whitelistReadRegexp ) ) {
+                       $name = $page->getPrefixedText();
+                       // Check for regex whitelisting
+                       foreach ( $this->whitelistReadRegexp as $listItem ) {
+                               if ( preg_match( $listItem, $name ) ) {
+                                       $whitelisted = true;
+                                       break;
+                               }
+                       }
+               }
+
+               if ( !$whitelisted ) {
+                       # If the title is not whitelisted, give extensions a chance to do so...
+                       Hooks::run( 'TitleReadWhitelist', [ $page, $user, &$whitelisted ] );
+                       if ( !$whitelisted ) {
+                               $errors[] = $this->missingPermissionError( $action, $short );
+                       }
+               }
+
+               return $errors;
+       }
+
+       /**
+        * Get a description array when the user doesn't have the right to perform
+        * $action (i.e. when User::isAllowed() returns false)
+        *
+        * @param string $action The action to check
+        * @param bool $short Short circuit on first error
+        * @return array Array containing an error message key and any parameters
+        */
+       private function missingPermissionError( $action, $short ) {
+               // We avoid expensive display logic for quickUserCan's and such
+               if ( $short ) {
+                       return [ 'badaccess-group0' ];
+               }
+
+               // TODO: it would be a good idea to replace the method below with something else like
+               //  maybe callback injection
+               return User::newFatalPermissionDeniedStatus( $action )->getErrorsArray()[0];
+       }
+
+       /**
+        * Returns true if this title resolves to the named special page
+        *
+        * @param string $name The special page name
+        * @param LinkTarget $page
+        *
+        * @return bool
+        */
+       private function isSameSpecialPage( $name, LinkTarget $page ) {
+               if ( $page->getNamespace() == NS_SPECIAL ) {
+                       list( $thisName, /* $subpage */ ) =
+                               $this->specialPageFactory->resolveAlias( $page->getDBkey() );
+                       if ( $name == $thisName ) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       /**
+        * Check that the user isn't blocked from editing.
+        *
+        * @param string $action The action to check
+        * @param User $user User to check
+        * @param array $errors List of current errors
+        * @param string $rigor One of PermissionManager::RIGOR_ constants
+        *   - RIGOR_QUICK  : does cheap permission checks from replica DBs (usable for GUI creation)
+        *   - RIGOR_FULL   : does cheap and expensive checks possibly from a replica DB
+        *   - RIGOR_SECURE : does cheap and expensive checks, using the master as needed
+        * @param bool $short Short circuit on first error
+        *
+        * @param LinkTarget $page
+        *
+        * @return array List of errors
+        * @throws MWException
+        */
+       private function checkUserBlock(
+               $action,
+               User $user,
+               $errors,
+               $rigor,
+               $short,
+               LinkTarget $page
+       ) {
+               // Account creation blocks handled at userlogin.
+               // Unblocking handled in SpecialUnblock
+               if ( $rigor === self::RIGOR_QUICK || in_array( $action, [ 'createaccount', 'unblock' ] ) ) {
+                       return $errors;
+               }
+
+               // Optimize for a very common case
+               if ( $action === 'read' && !$this->blockDisablesLogin ) {
+                       return $errors;
+               }
+
+               if ( $this->emailConfirmToEdit
+                        && !$user->isEmailConfirmed()
+                        && $action === 'edit'
+               ) {
+                       $errors[] = [ 'confirmedittext' ];
+               }
+
+               $useReplica = ( $rigor !== self::RIGOR_SECURE );
+               $block = $user->getBlock( $useReplica );
+
+               // If the user does not have a block, or the block they do have explicitly
+               // allows the action (like "read" or "upload").
+               if ( !$block || $block->appliesToRight( $action ) === false ) {
+                       return $errors;
+               }
+
+               // Determine if the user is blocked from this action on this page.
+               // What gets passed into this method is a user right, not an action name.
+               // There is no way to instantiate an action by restriction. However, this
+               // will get the action where the restriction is the same. This may result
+               // in actions being blocked that shouldn't be.
+               $actionObj = null;
+               if ( Action::exists( $action ) ) {
+                       // TODO: this drags a ton of dependencies in, would be good to avoid WikiPage
+                       //  instantiation and decouple it creating an ActionPermissionChecker interface
+                       $wikiPage = WikiPage::factory( Title::newFromLinkTarget( $page, 'clone' ) );
+                       // Creating an action will perform several database queries to ensure that
+                       // the action has not been overridden by the content type.
+                       // FIXME: avoid use of RequestContext since it drags in User and Title dependencies
+                       //  probably we may use fake context object since it's unlikely that Action uses it
+                       //  anyway. It would be nice if we could avoid instantiating the Action at all.
+                       $actionObj = Action::factory( $action, $wikiPage, RequestContext::getMain() );
+                       // Ensure that the retrieved action matches the restriction.
+                       if ( $actionObj && $actionObj->getRestriction() !== $action ) {
+                               $actionObj = null;
+                       }
+               }
+
+               // If no action object is returned, assume that the action requires unblock
+               // which is the default.
+               if ( !$actionObj || $actionObj->requiresUnblock() ) {
+                       if ( $this->isBlockedFrom( $user, $page, $useReplica ) ) {
+                               // @todo FIXME: Pass the relevant context into this function.
+                               $errors[] = $block->getPermissionsError( RequestContext::getMain() );
+                       }
+               }
+
+               return $errors;
+       }
+
+       /**
+        * Permissions checks that fail most often, and which are easiest to test.
+        *
+        * @param string $action The action to check
+        * @param User $user User to check
+        * @param array $errors List of current errors
+        * @param string $rigor One of PermissionManager::RIGOR_ constants
+        *   - RIGOR_QUICK  : does cheap permission checks from replica DBs (usable for GUI creation)
+        *   - RIGOR_FULL   : does cheap and expensive checks possibly from a replica DB
+        *   - RIGOR_SECURE : does cheap and expensive checks, using the master as needed
+        * @param bool $short Short circuit on first error
+        *
+        * @param LinkTarget $page
+        *
+        * @return array List of errors
+        * @throws FatalError
+        * @throws MWException
+        */
+       private function checkQuickPermissions(
+               $action,
+               User $user,
+               $errors,
+               $rigor,
+               $short,
+               LinkTarget $page
+       ) {
+               // TODO: remove when LinkTarget usage will expand further
+               $page = Title::newFromLinkTarget( $page );
+
+               if ( !Hooks::run( 'TitleQuickPermissions',
+                       [ $page, $user, $action, &$errors, ( $rigor !== self::RIGOR_QUICK ), $short ] )
+               ) {
+                       return $errors;
+               }
+
+               $isSubPage = $this->nsInfo->hasSubpages( $page->getNamespace() ) ?
+                       strpos( $page->getText(), '/' ) !== false : false;
+
+               if ( $action == 'create' ) {
+                       if (
+                               ( $this->nsInfo->isTalk( $page->getNamespace() ) &&
+                                       !$user->isAllowed( 'createtalk' ) ) ||
+                               ( !$this->nsInfo->isTalk( $page->getNamespace() ) &&
+                                       !$user->isAllowed( 'createpage' ) )
+                       ) {
+                               $errors[] = $user->isAnon() ? [ 'nocreatetext' ] : [ 'nocreate-loggedin' ];
+                       }
+               } elseif ( $action == 'move' ) {
+                       if ( !$user->isAllowed( 'move-rootuserpages' )
+                                && $page->getNamespace() == NS_USER && !$isSubPage ) {
+                               // Show user page-specific message only if the user can move other pages
+                               $errors[] = [ 'cant-move-user-page' ];
+                       }
+
+                       // Check if user is allowed to move files if it's a file
+                       if ( $page->getNamespace() == NS_FILE && !$user->isAllowed( 'movefile' ) ) {
+                               $errors[] = [ 'movenotallowedfile' ];
+                       }
+
+                       // Check if user is allowed to move category pages if it's a category page
+                       if ( $page->getNamespace() == NS_CATEGORY && !$user->isAllowed( 'move-categorypages' ) ) {
+                               $errors[] = [ 'cant-move-category-page' ];
+                       }
+
+                       if ( !$user->isAllowed( 'move' ) ) {
+                               // User can't move anything
+                               $userCanMove = User::groupHasPermission( 'user', 'move' );
+                               $autoconfirmedCanMove = User::groupHasPermission( 'autoconfirmed', 'move' );
+                               if ( $user->isAnon() && ( $userCanMove || $autoconfirmedCanMove ) ) {
+                                       // custom message if logged-in users without any special rights can move
+                                       $errors[] = [ 'movenologintext' ];
+                               } else {
+                                       $errors[] = [ 'movenotallowed' ];
+                               }
+                       }
+               } elseif ( $action == 'move-target' ) {
+                       if ( !$user->isAllowed( 'move' ) ) {
+                               // User can't move anything
+                               $errors[] = [ 'movenotallowed' ];
+                       } elseif ( !$user->isAllowed( 'move-rootuserpages' )
+                                          && $page->getNamespace() == NS_USER && !$isSubPage ) {
+                               // Show user page-specific message only if the user can move other pages
+                               $errors[] = [ 'cant-move-to-user-page' ];
+                       } elseif ( !$user->isAllowed( 'move-categorypages' )
+                                          && $page->getNamespace() == NS_CATEGORY ) {
+                               // Show category page-specific message only if the user can move other pages
+                               $errors[] = [ 'cant-move-to-category-page' ];
+                       }
+               } elseif ( !$user->isAllowed( $action ) ) {
+                       $errors[] = $this->missingPermissionError( $action, $short );
+               }
+
+               return $errors;
+       }
+
+       /**
+        * Check against page_restrictions table requirements on this
+        * page. The user must possess all required rights for this
+        * action.
+        *
+        * @param string $action The action to check
+        * @param User $user User to check
+        * @param array $errors List of current errors
+        * @param string $rigor One of PermissionManager::RIGOR_ constants
+        *   - RIGOR_QUICK  : does cheap permission checks from replica DBs (usable for GUI creation)
+        *   - RIGOR_FULL   : does cheap and expensive checks possibly from a replica DB
+        *   - RIGOR_SECURE : does cheap and expensive checks, using the master as needed
+        * @param bool $short Short circuit on first error
+        *
+        * @param LinkTarget $page
+        *
+        * @return array List of errors
+        */
+       private function checkPageRestrictions(
+               $action,
+               User $user,
+               $errors,
+               $rigor,
+               $short,
+               LinkTarget $page
+       ) {
+               // TODO: remove & rework upon further use of LinkTarget
+               $page = Title::newFromLinkTarget( $page );
+               foreach ( $page->getRestrictions( $action ) as $right ) {
+                       // Backwards compatibility, rewrite sysop -> editprotected
+                       if ( $right == 'sysop' ) {
+                               $right = 'editprotected';
+                       }
+                       // Backwards compatibility, rewrite autoconfirmed -> editsemiprotected
+                       if ( $right == 'autoconfirmed' ) {
+                               $right = 'editsemiprotected';
+                       }
+                       if ( $right == '' ) {
+                               continue;
+                       }
+                       if ( !$user->isAllowed( $right ) ) {
+                               $errors[] = [ 'protectedpagetext', $right, $action ];
+                       } elseif ( $page->areRestrictionsCascading() && !$user->isAllowed( 'protect' ) ) {
+                               $errors[] = [ 'protectedpagetext', 'protect', $action ];
+                       }
+               }
+
+               return $errors;
+       }
+
+       /**
+        * Check restrictions on cascading pages.
+        *
+        * @param string $action The action to check
+        * @param User $user User to check
+        * @param array $errors List of current errors
+        * @param string $rigor One of PermissionManager::RIGOR_ constants
+        *   - RIGOR_QUICK  : does cheap permission checks from replica DBs (usable for GUI creation)
+        *   - RIGOR_FULL   : does cheap and expensive checks possibly from a replica DB
+        *   - RIGOR_SECURE : does cheap and expensive checks, using the master as needed
+        * @param bool $short Short circuit on first error
+        *
+        * @param LinkTarget $page
+        *
+        * @return array List of errors
+        */
+       private function checkCascadingSourcesRestrictions(
+               $action,
+               User $user,
+               $errors,
+               $rigor,
+               $short,
+               LinkTarget $page
+       ) {
+               // TODO: remove & rework upon further use of LinkTarget
+               $page = Title::newFromLinkTarget( $page );
+               if ( $rigor !== self::RIGOR_QUICK && !$page->isUserConfigPage() ) {
+                       # We /could/ use the protection level on the source page, but it's
+                       # fairly ugly as we have to establish a precedence hierarchy for pages
+                       # included by multiple cascade-protected pages. So just restrict
+                       # it to people with 'protect' permission, as they could remove the
+                       # protection anyway.
+                       list( $cascadingSources, $restrictions ) = $page->getCascadeProtectionSources();
+                       # Cascading protection depends on more than this page...
+                       # Several cascading protected pages may include this page...
+                       # Check each cascading level
+                       # This is only for protection restrictions, not for all actions
+                       if ( isset( $restrictions[$action] ) ) {
+                               foreach ( $restrictions[$action] as $right ) {
+                                       // Backwards compatibility, rewrite sysop -> editprotected
+                                       if ( $right == 'sysop' ) {
+                                               $right = 'editprotected';
+                                       }
+                                       // Backwards compatibility, rewrite autoconfirmed -> editsemiprotected
+                                       if ( $right == 'autoconfirmed' ) {
+                                               $right = 'editsemiprotected';
+                                       }
+                                       if ( $right != '' && !$user->isAllowedAll( 'protect', $right ) ) {
+                                               $wikiPages = '';
+                                               foreach ( $cascadingSources as $wikiPage ) {
+                                                       $wikiPages .= '* [[:' . $wikiPage->getPrefixedText() . "]]\n";
+                                               }
+                                               $errors[] = [ 'cascadeprotected', count( $cascadingSources ), $wikiPages, $action ];
+                                       }
+                               }
+                       }
+               }
+
+               return $errors;
+       }
+
+       /**
+        * Check action permissions not already checked in checkQuickPermissions
+        *
+        * @param string $action The action to check
+        * @param User $user User to check
+        * @param array $errors List of current errors
+        * @param string $rigor One of PermissionManager::RIGOR_ constants
+        *   - RIGOR_QUICK  : does cheap permission checks from replica DBs (usable for GUI creation)
+        *   - RIGOR_FULL   : does cheap and expensive checks possibly from a replica DB
+        *   - RIGOR_SECURE : does cheap and expensive checks, using the master as needed
+        * @param bool $short Short circuit on first error
+        *
+        * @param LinkTarget $page
+        *
+        * @return array List of errors
+        * @throws Exception
+        */
+       private function checkActionPermissions(
+               $action,
+               User $user,
+               $errors,
+               $rigor,
+               $short,
+               LinkTarget $page
+       ) {
+               global $wgDeleteRevisionsLimit, $wgLang;
+
+               // TODO: remove & rework upon further use of LinkTarget
+               $page = Title::newFromLinkTarget( $page );
+
+               if ( $action == 'protect' ) {
+                       if ( count( $this->getPermissionErrorsInternal( 'edit', $user, $page, $rigor, true ) ) ) {
+                               // If they can't edit, they shouldn't protect.
+                               $errors[] = [ 'protect-cantedit' ];
+                       }
+               } elseif ( $action == 'create' ) {
+                       $title_protection = $page->getTitleProtection();
+                       if ( $title_protection ) {
+                               if ( $title_protection['permission'] == ''
+                                        || !$user->isAllowed( $title_protection['permission'] )
+                               ) {
+                                       $errors[] = [
+                                               'titleprotected',
+                                               // TODO: get rid of the User dependency
+                                               User::whoIs( $title_protection['user'] ),
+                                               $title_protection['reason']
+                                       ];
+                               }
+                       }
+               } elseif ( $action == 'move' ) {
+                       // Check for immobile pages
+                       if ( !$this->nsInfo->isMovable( $page->getNamespace() ) ) {
+                               // Specific message for this case
+                               $errors[] = [ 'immobile-source-namespace', $page->getNsText() ];
+                       } elseif ( !$page->isMovable() ) {
+                               // Less specific message for rarer cases
+                               $errors[] = [ 'immobile-source-page' ];
+                       }
+               } elseif ( $action == 'move-target' ) {
+                       if ( !$this->nsInfo->isMovable( $page->getNamespace() ) ) {
+                               $errors[] = [ 'immobile-target-namespace', $page->getNsText() ];
+                       } elseif ( !$page->isMovable() ) {
+                               $errors[] = [ 'immobile-target-page' ];
+                       }
+               } elseif ( $action == 'delete' ) {
+                       $tempErrors = $this->checkPageRestrictions( 'edit', $user, [], $rigor, true, $page );
+                       if ( !$tempErrors ) {
+                               $tempErrors = $this->checkCascadingSourcesRestrictions( 'edit',
+                                       $user, $tempErrors, $rigor, true, $page );
+                       }
+                       if ( $tempErrors ) {
+                               // If protection keeps them from editing, they shouldn't be able to delete.
+                               $errors[] = [ 'deleteprotected' ];
+                       }
+                       if ( $rigor !== self::RIGOR_QUICK && $wgDeleteRevisionsLimit
+                                && !$this->userCan( 'bigdelete', $user, $page ) && $page->isBigDeletion()
+                       ) {
+                               $errors[] = [ 'delete-toobig', $wgLang->formatNum( $wgDeleteRevisionsLimit ) ];
+                       }
+               } elseif ( $action === 'undelete' ) {
+                       if ( count( $this->getPermissionErrorsInternal( 'edit', $user, $page, $rigor, true ) ) ) {
+                               // Undeleting implies editing
+                               $errors[] = [ 'undelete-cantedit' ];
+                       }
+                       if ( !$page->exists()
+                                && count( $this->getPermissionErrorsInternal( 'create', $user, $page, $rigor, true ) )
+                       ) {
+                               // Undeleting where nothing currently exists implies creating
+                               $errors[] = [ 'undelete-cantcreate' ];
+                       }
+               }
+               return $errors;
+       }
+
+       /**
+        * Check permissions on special pages & namespaces
+        *
+        * @param string $action The action to check
+        * @param User $user User to check
+        * @param array $errors List of current errors
+        * @param string $rigor One of PermissionManager::RIGOR_ constants
+        *   - RIGOR_QUICK  : does cheap permission checks from replica DBs (usable for GUI creation)
+        *   - RIGOR_FULL   : does cheap and expensive checks possibly from a replica DB
+        *   - RIGOR_SECURE : does cheap and expensive checks, using the master as needed
+        * @param bool $short Short circuit on first error
+        *
+        * @param LinkTarget $page
+        *
+        * @return array List of errors
+        */
+       private function checkSpecialsAndNSPermissions(
+               $action,
+               User $user,
+               $errors,
+               $rigor,
+               $short,
+               LinkTarget $page
+       ) {
+               // TODO: remove & rework upon further use of LinkTarget
+               $page = Title::newFromLinkTarget( $page );
+
+               # Only 'createaccount' can be performed on special pages,
+               # which don't actually exist in the DB.
+               if ( $page->getNamespace() == NS_SPECIAL && $action !== 'createaccount' ) {
+                       $errors[] = [ 'ns-specialprotected' ];
+               }
+
+               # Check $wgNamespaceProtection for restricted namespaces
+               if ( $page->isNamespaceProtected( $user ) ) {
+                       $ns = $page->getNamespace() == NS_MAIN ?
+                               wfMessage( 'nstab-main' )->text() : $page->getNsText();
+                       $errors[] = $page->getNamespace() == NS_MEDIAWIKI ?
+                               [ 'protectedinterface', $action ] : [ 'namespaceprotected', $ns, $action ];
+               }
+
+               return $errors;
+       }
+
+       /**
+        * Check sitewide CSS/JSON/JS permissions
+        *
+        * @param string $action The action to check
+        * @param User $user User to check
+        * @param array $errors List of current errors
+        * @param string $rigor One of PermissionManager::RIGOR_ constants
+        *   - RIGOR_QUICK  : does cheap permission checks from replica DBs (usable for GUI creation)
+        *   - RIGOR_FULL   : does cheap and expensive checks possibly from a replica DB
+        *   - RIGOR_SECURE : does cheap and expensive checks, using the master as needed
+        * @param bool $short Short circuit on first error
+        *
+        * @param LinkTarget $page
+        *
+        * @return array List of errors
+        */
+       private function checkSiteConfigPermissions(
+               $action,
+               User $user,
+               $errors,
+               $rigor,
+               $short,
+               LinkTarget $page
+       ) {
+               // TODO: remove & rework upon further use of LinkTarget
+               $page = Title::newFromLinkTarget( $page );
+
+               if ( $action != 'patrol' ) {
+                       $error = null;
+                       // Sitewide CSS/JSON/JS changes, like all NS_MEDIAWIKI changes, also require the
+                       // editinterface right. That's implemented as a restriction so no check needed here.
+                       if ( $page->isSiteCssConfigPage() && !$user->isAllowed( 'editsitecss' ) ) {
+                               $error = [ 'sitecssprotected', $action ];
+                       } elseif ( $page->isSiteJsonConfigPage() && !$user->isAllowed( 'editsitejson' ) ) {
+                               $error = [ 'sitejsonprotected', $action ];
+                       } elseif ( $page->isSiteJsConfigPage() && !$user->isAllowed( 'editsitejs' ) ) {
+                               $error = [ 'sitejsprotected', $action ];
+                       } elseif ( $page->isRawHtmlMessage() ) {
+                               // Raw HTML can be used to deploy CSS or JS so require rights for both.
+                               if ( !$user->isAllowed( 'editsitejs' ) ) {
+                                       $error = [ 'sitejsprotected', $action ];
+                               } elseif ( !$user->isAllowed( 'editsitecss' ) ) {
+                                       $error = [ 'sitecssprotected', $action ];
+                               }
+                       }
+
+                       if ( $error ) {
+                               if ( $user->isAllowed( 'editinterface' ) ) {
+                                       // Most users / site admins will probably find out about the new, more restrictive
+                                       // permissions by failing to edit something. Give them more info.
+                                       // TODO remove this a few release cycles after 1.32
+                                       $error = [ 'interfaceadmin-info', wfMessage( $error[0], $error[1] ) ];
+                               }
+                               $errors[] = $error;
+                       }
+               }
+
+               return $errors;
+       }
+
+       /**
+        * Check CSS/JSON/JS sub-page permissions
+        *
+        * @param string $action The action to check
+        * @param User $user User to check
+        * @param array $errors List of current errors
+        * @param string $rigor One of PermissionManager::RIGOR_ constants
+        *   - RIGOR_QUICK  : does cheap permission checks from replica DBs (usable for GUI creation)
+        *   - RIGOR_FULL   : does cheap and expensive checks possibly from a replica DB
+        *   - RIGOR_SECURE : does cheap and expensive checks, using the master as needed
+        * @param bool $short Short circuit on first error
+        *
+        * @param LinkTarget $page
+        *
+        * @return array List of errors
+        */
+       private function checkUserConfigPermissions(
+               $action,
+               User $user,
+               $errors,
+               $rigor,
+               $short,
+               LinkTarget $page
+       ) {
+               // TODO: remove & rework upon further use of LinkTarget
+               $page = Title::newFromLinkTarget( $page );
+
+               # Protect css/json/js subpages of user pages
+               # XXX: this might be better using restrictions
+
+               if ( $action === 'patrol' ) {
+                       return $errors;
+               }
+
+               if ( preg_match( '/^' . preg_quote( $user->getName(), '/' ) . '\//', $page->getText() ) ) {
+                       // Users need editmyuser* to edit their own CSS/JSON/JS subpages.
+                       if (
+                               $page->isUserCssConfigPage()
+                               && !$user->isAllowedAny( 'editmyusercss', 'editusercss' )
+                       ) {
+                               $errors[] = [ 'mycustomcssprotected', $action ];
+                       } elseif (
+                               $page->isUserJsonConfigPage()
+                               && !$user->isAllowedAny( 'editmyuserjson', 'edituserjson' )
+                       ) {
+                               $errors[] = [ 'mycustomjsonprotected', $action ];
+                       } elseif (
+                               $page->isUserJsConfigPage()
+                               && !$user->isAllowedAny( 'editmyuserjs', 'edituserjs' )
+                       ) {
+                               $errors[] = [ 'mycustomjsprotected', $action ];
+                       }
+               } else {
+                       // Users need editmyuser* to edit their own CSS/JSON/JS subpages, except for
+                       // deletion/suppression which cannot be used for attacks and we want to avoid the
+                       // situation where an unprivileged user can post abusive content on their subpages
+                       // and only very highly privileged users could remove it.
+                       if ( !in_array( $action, [ 'delete', 'deleterevision', 'suppressrevision' ], true ) ) {
+                               if (
+                                       $page->isUserCssConfigPage()
+                                       && !$user->isAllowed( 'editusercss' )
+                               ) {
+                                       $errors[] = [ 'customcssprotected', $action ];
+                               } elseif (
+                                       $page->isUserJsonConfigPage()
+                                       && !$user->isAllowed( 'edituserjson' )
+                               ) {
+                                       $errors[] = [ 'customjsonprotected', $action ];
+                               } elseif (
+                                       $page->isUserJsConfigPage()
+                                       && !$user->isAllowed( 'edituserjs' )
+                               ) {
+                                       $errors[] = [ 'customjsprotected', $action ];
+                               }
+                       }
+               }
+
+               return $errors;
+       }
+
+}
index 8d7c3b6..f4e85ad 100644 (file)
@@ -22,6 +22,7 @@
 
 use Psr\Log\LoggerInterface;
 use MediaWiki\Logger\LoggerFactory;
+use MediaWiki\MediaWikiServices;
 
 /**
  * Send information about this MediaWiki instance to MediaWiki.org.
@@ -229,7 +230,7 @@ class Pingback {
                $json = FormatJson::encode( $data );
                $queryString = rawurlencode( str_replace( ' ', '\u0020', $json ) ) . ';';
                $url = 'https://www.mediawiki.org/beacon/event?' . $queryString;
-               return Http::post( $url ) !== false;
+               return MediaWikiServices::getInstance()->getHttpRequestFactory()->post( $url ) !== null;
        }
 
        /**
diff --git a/includes/Preferences.php b/includes/Preferences.php
deleted file mode 100644 (file)
index 70f7060..0000000
+++ /dev/null
@@ -1,273 +0,0 @@
-<?php
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-use MediaWiki\Auth\AuthManager;
-use MediaWiki\MediaWikiServices;
-use MediaWiki\Preferences\DefaultPreferencesFactory;
-
-/**
- * This class has been replaced by the PreferencesFactory service.
- *
- * @deprecated since 1.31 use the PreferencesFactory service instead.
- */
-class Preferences {
-
-       /**
-        * A shim to maintain backwards-compatibility of this class, basically replicating the
-        * default behaviour of the PreferencesFactory service but not permitting overriding.
-        * @return DefaultPreferencesFactory
-        */
-       protected static function getDefaultPreferencesFactory() {
-               $services = MediaWikiServices::getInstance();
-               $authManager = AuthManager::singleton();
-               $linkRenderer = $services->getLinkRenderer();
-               $config = $services->getMainConfig();
-               $preferencesFactory = new DefaultPreferencesFactory(
-                       $config, $services->getContentLanguage(), $authManager,
-                       $linkRenderer
-               );
-               return $preferencesFactory;
-       }
-
-       /**
-        * @throws MWException
-        * @param User $user
-        * @param IContextSource $context
-        * @return array|null
-        */
-       public static function getPreferences( $user, IContextSource $context ) {
-               wfDeprecated( __METHOD__, '1.31' );
-               $preferencesFactory = self::getDefaultPreferencesFactory();
-               return $preferencesFactory->getFormDescriptor( $user, $context );
-       }
-
-       /**
-        * Loads existing values for a given array of preferences
-        * @throws MWException
-        * @param User $user
-        * @param IContextSource $context
-        * @param array &$defaultPreferences Array to load values for
-        * @return array|null
-        */
-       public static function loadPreferenceValues( $user, $context, &$defaultPreferences ) {
-               throw new Exception( __METHOD__ . '() is deprecated and does nothing' );
-       }
-
-       /**
-        * Pull option from a user account. Handles stuff like array-type preferences.
-        *
-        * @param string $name
-        * @param array $info
-        * @param User $user
-        * @return array|string
-        */
-       public static function getOptionFromUser( $name, $info, $user ) {
-               throw new Exception( __METHOD__ . '() is deprecated and does nothing' );
-       }
-
-       /**
-        * @param User $user
-        * @param IContextSource $context
-        * @param array &$defaultPreferences
-        * @return void
-        */
-       public static function profilePreferences(
-               $user, IContextSource $context, &$defaultPreferences
-       ) {
-               wfDeprecated( __METHOD__, '1.31' );
-               $defaultPreferences = self::getPreferences( $user, $context );
-       }
-
-       /**
-        * @param User $user
-        * @param IContextSource $context
-        * @param array &$defaultPreferences
-        * @return void
-        */
-       public static function skinPreferences( $user, IContextSource $context, &$defaultPreferences ) {
-               wfDeprecated( __METHOD__, '1.31' );
-               $defaultPreferences = self::getPreferences( $user, $context );
-       }
-
-       /**
-        * @param User $user
-        * @param IContextSource $context
-        * @param array &$defaultPreferences
-        */
-       public static function filesPreferences(
-               $user, IContextSource $context, &$defaultPreferences
-       ) {
-               wfDeprecated( __METHOD__, '1.31' );
-               $defaultPreferences = self::getPreferences( $user, $context );
-       }
-
-       /**
-        * @param User $user
-        * @param IContextSource $context
-        * @param array &$defaultPreferences
-        * @return void
-        */
-       public static function datetimePreferences(
-               $user, IContextSource $context, &$defaultPreferences
-       ) {
-               wfDeprecated( __METHOD__, '1.31' );
-               $defaultPreferences = self::getPreferences( $user, $context );
-       }
-
-       /**
-        * @param User $user
-        * @param IContextSource $context
-        * @param array &$defaultPreferences
-        */
-       public static function renderingPreferences(
-               $user, IContextSource $context, &$defaultPreferences
-       ) {
-               wfDeprecated( __METHOD__, '1.31' );
-               $defaultPreferences = self::getPreferences( $user, $context );
-       }
-
-       /**
-        * @param User $user
-        * @param IContextSource $context
-        * @param array &$defaultPreferences
-        */
-       public static function editingPreferences(
-               $user, IContextSource $context, &$defaultPreferences
-       ) {
-               wfDeprecated( __METHOD__, '1.31' );
-               $defaultPreferences = self::getPreferences( $user, $context );
-       }
-
-       /**
-        * @param User $user
-        * @param IContextSource $context
-        * @param array &$defaultPreferences
-        */
-       public static function rcPreferences( $user, IContextSource $context, &$defaultPreferences ) {
-               wfDeprecated( __METHOD__, '1.31' );
-               $defaultPreferences = self::getPreferences( $user, $context );
-       }
-
-       /**
-        * @param User $user
-        * @param IContextSource $context
-        * @param array &$defaultPreferences
-        */
-       public static function watchlistPreferences(
-               $user, IContextSource $context, &$defaultPreferences
-       ) {
-               wfDeprecated( __METHOD__, '1.31' );
-               $defaultPreferences = self::getPreferences( $user, $context );
-       }
-
-       /**
-        * @param User $user
-        * @param IContextSource $context
-        * @param array &$defaultPreferences
-        */
-       public static function searchPreferences(
-               $user, IContextSource $context, &$defaultPreferences
-       ) {
-               wfDeprecated( __METHOD__, '1.31' );
-               $defaultPreferences = self::getPreferences( $user, $context );
-       }
-
-       /**
-        * Dummy, kept for backwards-compatibility.
-        * @param User $user
-        * @param IContextSource $context
-        * @param array &$defaultPreferences
-        */
-       public static function miscPreferences( $user, IContextSource $context, &$defaultPreferences ) {
-               wfDeprecated( __METHOD__, '1.31' );
-       }
-
-       /**
-        * @param User $user
-        * @param IContextSource $context
-        * @return array Text/links to display as key; $skinkey as value
-        */
-       public static function generateSkinOptions( $user, IContextSource $context ) {
-               wfDeprecated( __METHOD__, '1.31' );
-               return self::getPreferences( $user, $context );
-       }
-
-       /**
-        * @param IContextSource $context
-        * @return array
-        */
-       static function getDateOptions( IContextSource $context ) {
-               throw new Exception( __METHOD__ . '() is deprecated and does nothing' );
-       }
-
-       /**
-        * @param IContextSource $context
-        * @return array
-        */
-       public static function getImageSizes( IContextSource $context ) {
-               throw new Exception( __METHOD__ . '() is deprecated and does nothing' );
-       }
-
-       /**
-        * @param IContextSource $context
-        * @return array
-        */
-       public static function getThumbSizes( IContextSource $context ) {
-               throw new Exception( __METHOD__ . '() is deprecated and does nothing' );
-       }
-
-       /**
-        * @param string $signature
-        * @param array $alldata
-        * @param HTMLForm $form
-        * @return bool|string
-        */
-       public static function validateSignature( $signature, $alldata, $form ) {
-               throw new Exception( __METHOD__ . '() is deprecated and does nothing' );
-       }
-
-       /**
-        * @param string $signature
-        * @param array $alldata
-        * @param HTMLForm $form
-        * @return string
-        */
-       public static function cleanSignature( $signature, $alldata, $form ) {
-               throw new Exception( __METHOD__ . '() is deprecated and does nothing now' );
-       }
-
-       /**
-        * @param User $user
-        * @param IContextSource $context
-        * @param string $formClass
-        * @param array $remove Array of items to remove
-        * @return PreferencesFormLegacy|HTMLForm
-        */
-       public static function getFormObject(
-               $user,
-               IContextSource $context,
-               $formClass = PreferencesFormLegacy::class,
-               array $remove = []
-       ) {
-               wfDeprecated( __METHOD__, '1.31' );
-               $preferencesFactory = self::getDefaultPreferencesFactory();
-               return $preferencesFactory->getForm( $user, $context, $formClass, $remove );
-       }
-}
diff --git a/includes/PrefixSearch.php b/includes/PrefixSearch.php
deleted file mode 100644 (file)
index 7bc7a08..0000000
+++ /dev/null
@@ -1,365 +0,0 @@
-<?php
-/**
- * Prefix search of page names.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-use MediaWiki\MediaWikiServices;
-
-/**
- * Handles searching prefixes of titles and finding any page
- * names that match. Used largely by the OpenSearch implementation.
- * @deprecated Since 1.27, Use SearchEngine::defaultPrefixSearch or SearchEngine::completionSearch
- *
- * @ingroup Search
- */
-abstract class PrefixSearch {
-       /**
-        * Do a prefix search of titles and return a list of matching page names.
-        * @deprecated Since 1.23, use TitlePrefixSearch or StringPrefixSearch classes
-        *
-        * @param string $search
-        * @param int $limit
-        * @param array $namespaces Used if query is not explicitly prefixed
-        * @param int $offset How many results to offset from the beginning
-        * @return array Array of strings
-        */
-       public static function titleSearch( $search, $limit, $namespaces = [], $offset = 0 ) {
-               $prefixSearch = new StringPrefixSearch;
-               return $prefixSearch->search( $search, $limit, $namespaces, $offset );
-       }
-
-       /**
-        * Do a prefix search of titles and return a list of matching page names.
-        *
-        * @param string $search
-        * @param int $limit
-        * @param array $namespaces Used if query is not explicitly prefixed
-        * @param int $offset How many results to offset from the beginning
-        * @return array Array of strings or Title objects
-        */
-       public function search( $search, $limit, $namespaces = [], $offset = 0 ) {
-               $search = trim( $search );
-               if ( $search == '' ) {
-                       return []; // Return empty result
-               }
-
-               $hasNamespace = SearchEngine::parseNamespacePrefixes( $search, false, true );
-               if ( $hasNamespace !== false ) {
-                       list( $search, $namespaces ) = $hasNamespace;
-               }
-
-               return $this->searchBackend( $namespaces, $search, $limit, $offset );
-       }
-
-       /**
-        * Do a prefix search for all possible variants of the prefix
-        * @param string $search
-        * @param int $limit
-        * @param array $namespaces
-        * @param int $offset How many results to offset from the beginning
-        *
-        * @return array
-        */
-       public function searchWithVariants( $search, $limit, array $namespaces, $offset = 0 ) {
-               $searches = $this->search( $search, $limit, $namespaces, $offset );
-
-               // if the content language has variants, try to retrieve fallback results
-               $fallbackLimit = $limit - count( $searches );
-               if ( $fallbackLimit > 0 ) {
-                       $fallbackSearches = MediaWikiServices::getInstance()->getContentLanguage()->
-                               autoConvertToAllVariants( $search );
-                       $fallbackSearches = array_diff( array_unique( $fallbackSearches ), [ $search ] );
-
-                       foreach ( $fallbackSearches as $fbs ) {
-                               $fallbackSearchResult = $this->search( $fbs, $fallbackLimit, $namespaces );
-                               $searches = array_merge( $searches, $fallbackSearchResult );
-                               $fallbackLimit -= count( $fallbackSearchResult );
-
-                               if ( $fallbackLimit == 0 ) {
-                                       break;
-                               }
-                       }
-               }
-               return $searches;
-       }
-
-       /**
-        * When implemented in a descendant class, receives an array of Title objects and returns
-        * either an unmodified array or an array of strings corresponding to titles passed to it.
-        *
-        * @param array $titles
-        * @return array
-        */
-       abstract protected function titles( array $titles );
-
-       /**
-        * When implemented in a descendant class, receives an array of titles as strings and returns
-        * either an unmodified array or an array of Title objects corresponding to strings received.
-        *
-        * @param array $strings
-        *
-        * @return array
-        */
-       abstract protected function strings( array $strings );
-
-       /**
-        * Do a prefix search of titles and return a list of matching page names.
-        * @param array $namespaces
-        * @param string $search
-        * @param int $limit
-        * @param int $offset How many results to offset from the beginning
-        * @return array Array of strings
-        */
-       protected function searchBackend( $namespaces, $search, $limit, $offset ) {
-               if ( count( $namespaces ) == 1 ) {
-                       $ns = $namespaces[0];
-                       if ( $ns == NS_MEDIA ) {
-                               $namespaces = [ NS_FILE ];
-                       } elseif ( $ns == NS_SPECIAL ) {
-                               return $this->titles( $this->specialSearch( $search, $limit, $offset ) );
-                       }
-               }
-               $srchres = [];
-               if ( Hooks::run(
-                       'PrefixSearchBackend',
-                       [ $namespaces, $search, $limit, &$srchres, $offset ]
-               ) ) {
-                       return $this->titles( $this->defaultSearchBackend( $namespaces, $search, $limit, $offset ) );
-               }
-               return $this->strings(
-                       $this->handleResultFromHook( $srchres, $namespaces, $search, $limit, $offset ) );
-       }
-
-       private function handleResultFromHook( $srchres, $namespaces, $search, $limit, $offset ) {
-               if ( $offset === 0 ) {
-                       // Only perform exact db match if offset === 0
-                       // This is still far from perfect but at least we avoid returning the
-                       // same title afain and again when the user is scrolling with a query
-                       // that matches a title in the db.
-                       $rescorer = new SearchExactMatchRescorer();
-                       $srchres = $rescorer->rescore( $search, $namespaces, $srchres, $limit );
-               }
-               return $srchres;
-       }
-
-       /**
-        * Prefix search special-case for Special: namespace.
-        *
-        * @param string $search Term
-        * @param int $limit Max number of items to return
-        * @param int $offset Number of items to offset
-        * @return array
-        */
-       protected function specialSearch( $search, $limit, $offset ) {
-               $searchParts = explode( '/', $search, 2 );
-               $searchKey = $searchParts[0];
-               $subpageSearch = $searchParts[1] ?? null;
-
-               // Handle subpage search separately.
-               $spFactory = MediaWikiServices::getInstance()->getSpecialPageFactory();
-               if ( $subpageSearch !== null ) {
-                       // Try matching the full search string as a page name
-                       $specialTitle = Title::makeTitleSafe( NS_SPECIAL, $searchKey );
-                       if ( !$specialTitle ) {
-                               return [];
-                       }
-                       $special = $spFactory->getPage( $specialTitle->getText() );
-                       if ( $special ) {
-                               $subpages = $special->prefixSearchSubpages( $subpageSearch, $limit, $offset );
-                               return array_map( function ( $sub ) use ( $specialTitle ) {
-                                       return $specialTitle->getSubpage( $sub );
-                               }, $subpages );
-                       } else {
-                               return [];
-                       }
-               }
-
-               # normalize searchKey, so aliases with spaces can be found - T27675
-               $contLang = MediaWikiServices::getInstance()->getContentLanguage();
-               $searchKey = str_replace( ' ', '_', $searchKey );
-               $searchKey = $contLang->caseFold( $searchKey );
-
-               // Unlike SpecialPage itself, we want the canonical forms of both
-               // canonical and alias title forms...
-               $keys = [];
-               foreach ( $spFactory->getNames() as $page ) {
-                       $keys[$contLang->caseFold( $page )] = [ 'page' => $page, 'rank' => 0 ];
-               }
-
-               foreach ( $contLang->getSpecialPageAliases() as $page => $aliases ) {
-                       if ( !in_array( $page, $spFactory->getNames() ) ) {# T22885
-                               continue;
-                       }
-
-                       foreach ( $aliases as $key => $alias ) {
-                               $keys[$contLang->caseFold( $alias )] = [ 'page' => $alias, 'rank' => $key ];
-                       }
-               }
-               ksort( $keys );
-
-               $matches = [];
-               foreach ( $keys as $pageKey => $page ) {
-                       if ( $searchKey === '' || strpos( $pageKey, $searchKey ) === 0 ) {
-                               // T29671: Don't use SpecialPage::getTitleFor() here because it
-                               // localizes its input leading to searches for e.g. Special:All
-                               // returning Spezial:MediaWiki-Systemnachrichten and returning
-                               // Spezial:Alle_Seiten twice when $wgLanguageCode == 'de'
-                               $matches[$page['rank']][] = Title::makeTitleSafe( NS_SPECIAL, $page['page'] );
-
-                               if ( isset( $matches[0] ) && count( $matches[0] ) >= $limit + $offset ) {
-                                       // We have enough items in primary rank, no use to continue
-                                       break;
-                               }
-                       }
-
-               }
-
-               // Ensure keys are in order
-               ksort( $matches );
-               // Flatten the array
-               $matches = array_reduce( $matches, 'array_merge', [] );
-
-               return array_slice( $matches, $offset, $limit );
-       }
-
-       /**
-        * Unless overridden by PrefixSearchBackend hook...
-        * This is case-sensitive (First character may
-        * be automatically capitalized by Title::secureAndSpit()
-        * later on depending on $wgCapitalLinks)
-        *
-        * @param array|null $namespaces Namespaces to search in
-        * @param string $search Term
-        * @param int $limit Max number of items to return
-        * @param int $offset Number of items to skip
-        * @return Title[] Array of Title objects
-        */
-       public function defaultSearchBackend( $namespaces, $search, $limit, $offset ) {
-               // Backwards compatability with old code. Default to NS_MAIN if no namespaces provided.
-               if ( $namespaces === null ) {
-                       $namespaces = [];
-               }
-               if ( !$namespaces ) {
-                       $namespaces[] = NS_MAIN;
-               }
-
-               // Construct suitable prefix for each namespace. They differ in cases where
-               // some namespaces always capitalize and some don't.
-               $prefixes = [];
-               foreach ( $namespaces as $namespace ) {
-                       // For now, if special is included, ignore the other namespaces
-                       if ( $namespace == NS_SPECIAL ) {
-                               return $this->specialSearch( $search, $limit, $offset );
-                       }
-
-                       $title = Title::makeTitleSafe( $namespace, $search );
-                       // Why does the prefix default to empty?
-                       $prefix = $title ? $title->getDBkey() : '';
-                       $prefixes[$prefix][] = $namespace;
-               }
-
-               $dbr = wfGetDB( DB_REPLICA );
-               // Often there is only one prefix that applies to all requested namespaces,
-               // but sometimes there are two if some namespaces do not always capitalize.
-               $conds = [];
-               foreach ( $prefixes as $prefix => $namespaces ) {
-                       $condition = [
-                               'page_namespace' => $namespaces,
-                               'page_title' . $dbr->buildLike( $prefix, $dbr->anyString() ),
-                       ];
-                       $conds[] = $dbr->makeList( $condition, LIST_AND );
-               }
-
-               $table = 'page';
-               $fields = [ 'page_id', 'page_namespace', 'page_title' ];
-               $conds = $dbr->makeList( $conds, LIST_OR );
-               $options = [
-                       'LIMIT' => $limit,
-                       'ORDER BY' => [ 'page_title', 'page_namespace' ],
-                       'OFFSET' => $offset
-               ];
-
-               $res = $dbr->select( $table, $fields, $conds, __METHOD__, $options );
-
-               return iterator_to_array( TitleArray::newFromResult( $res ) );
-       }
-
-       /**
-        * Validate an array of numerical namespace indexes
-        *
-        * @param array $namespaces
-        * @return array (default: contains only NS_MAIN)
-        */
-       protected function validateNamespaces( $namespaces ) {
-               // We will look at each given namespace against content language namespaces
-               $validNamespaces = MediaWikiServices::getInstance()->getContentLanguage()->getNamespaces();
-               if ( is_array( $namespaces ) && count( $namespaces ) > 0 ) {
-                       $valid = [];
-                       foreach ( $namespaces as $ns ) {
-                               if ( is_numeric( $ns ) && array_key_exists( $ns, $validNamespaces ) ) {
-                                       $valid[] = $ns;
-                               }
-                       }
-                       if ( count( $valid ) > 0 ) {
-                               return $valid;
-                       }
-               }
-
-               return [ NS_MAIN ];
-       }
-}
-
-/**
- * Performs prefix search, returning Title objects
- * @deprecated Since 1.27, Use SearchEngine::defaultPrefixSearch or SearchEngine::completionSearch
- * @ingroup Search
- */
-class TitlePrefixSearch extends PrefixSearch {
-
-       protected function titles( array $titles ) {
-               return $titles;
-       }
-
-       protected function strings( array $strings ) {
-               $titles = array_map( 'Title::newFromText', $strings );
-               $lb = new LinkBatch( $titles );
-               $lb->setCaller( __METHOD__ );
-               $lb->execute();
-               return $titles;
-       }
-}
-
-/**
- * Performs prefix search, returning strings
- * @deprecated Since 1.27, Use SearchEngine::prefixSearchSubpages or SearchEngine::completionSearch
- * @ingroup Search
- */
-class StringPrefixSearch extends PrefixSearch {
-
-       protected function titles( array $titles ) {
-               return array_map( function ( Title $t ) {
-                       return $t->getPrefixedText();
-               }, $titles );
-       }
-
-       protected function strings( array $strings ) {
-               return $strings;
-       }
-}
index 7972a1e..2f10598 100644 (file)
@@ -90,7 +90,7 @@ class ProtectionForm {
         * Loads the current state of protection into the object.
         */
        function loadData() {
-               $levels = MWNamespace::getRestrictionLevels(
+               $levels = MediaWikiServices::getInstance()->getNamespaceInfo()->getRestrictionLevels(
                        $this->mTitle->getNamespace(), $this->mContext->getUser()
                );
                $this->mCascade = $this->mTitle->areRestrictionsCascading();
@@ -179,7 +179,11 @@ class ProtectionForm {
         * Main entry point for action=protect and action=unprotect
         */
        function execute() {
-               if ( MWNamespace::getRestrictionLevels( $this->mTitle->getNamespace() ) === [ '' ] ) {
+               if (
+                       MediaWikiServices::getInstance()->getNamespaceInfo()->getRestrictionLevels(
+                               $this->mTitle->getNamespace()
+                       ) === [ '' ]
+               ) {
                        throw new ErrorPageError( 'protect-badnamespace-title', 'protect-badnamespace-text' );
                }
 
@@ -581,7 +585,8 @@ class ProtectionForm {
        function buildSelector( $action, $selected ) {
                // If the form is disabled, display all relevant levels. Otherwise,
                // just show the ones this user can use.
-               $levels = MWNamespace::getRestrictionLevels( $this->mTitle->getNamespace(),
+               $levels = MediaWikiServices::getInstance()->getNamespaceInfo()->getRestrictionLevels(
+                       $this->mTitle->getNamespace(),
                        $this->disabled ? null : $this->mContext->getUser()
                );
 
index e767359..1a09290 100644 (file)
@@ -58,11 +58,4 @@ class ReadOnlyMode {
        public function setReason( $msg ) {
                $this->configuredReadOnly->setReason( $msg );
        }
-
-       /**
-        * Clear the cache of the read only file
-        */
-       public function clearCache() {
-               $this->configuredReadOnly->clearCache();
-       }
 }
index cbaff90..de3c299 100644 (file)
@@ -1008,9 +1008,8 @@ class Revision implements IDBAccessObject {
         * @return Revision|null
         */
        public function getPrevious() {
-               $title = $this->getTitle();
-               $rec = self::getRevisionLookup()->getPreviousRevision( $this->mRecord, $title );
-               return $rec ? new Revision( $rec, self::READ_NORMAL, $title ) : null;
+               $rec = self::getRevisionLookup()->getPreviousRevision( $this->mRecord );
+               return $rec ? new Revision( $rec, self::READ_NORMAL, $this->getTitle() ) : null;
        }
 
        /**
@@ -1019,9 +1018,8 @@ class Revision implements IDBAccessObject {
         * @return Revision|null
         */
        public function getNext() {
-               $title = $this->getTitle();
-               $rec = self::getRevisionLookup()->getNextRevision( $this->mRecord, $title );
-               return $rec ? new Revision( $rec, self::READ_NORMAL, $title ) : null;
+               $rec = self::getRevisionLookup()->getNextRevision( $this->mRecord );
+               return $rec ? new Revision( $rec, self::READ_NORMAL, $this->getTitle() ) : null;
        }
 
        /**
@@ -1256,13 +1254,13 @@ class Revision implements IDBAccessObject {
        /**
         * Get rev_timestamp from rev_id, without loading the rest of the row
         *
-        * @param Title $title
+        * @param Title $title (ignored since 1.34)
         * @param int $id
         * @param int $flags
         * @return string|bool False if not found
         */
        static function getTimestampFromId( $title, $id, $flags = 0 ) {
-               return self::getRevisionStore()->getTimestampFromId( $title, $id, $flags );
+               return self::getRevisionStore()->getTimestampFromId( $id, $flags );
        }
 
        /**
index f3e5a85..0139103 100644 (file)
@@ -86,10 +86,8 @@ class MainSlotRoleHandler extends SlotRoleHandler {
 
                // Hook can determine default model
                $title = Title::newFromLinkTarget( $page );
-               if ( !Hooks::run( 'ContentHandlerDefaultModelFor', [ $title, &$model ] ) ) {
-                       if ( !is_null( $model ) ) {
-                               return $model;
-                       }
+               if ( !Hooks::run( 'ContentHandlerDefaultModelFor', [ $title, &$model ] ) && !is_null( $model ) ) {
+                       return $model;
                }
 
                // Could this page contain code based on the title?
index 094105a..c4a0054 100644 (file)
@@ -380,9 +380,9 @@ class RenderedRevision implements SlotRenderingProvider {
                $method = __METHOD__;
 
                if ( $out->getFlag( 'vary-revision' ) ) {
-                       // XXX: Would be just keep the output if the speculative revision ID was correct,
-                       // but that can go wrong for some edge cases, like {{PAGEID}} during page creation.
-                       // For that specific case, it would perhaps nice to have a vary-page flag.
+                       // If {{PAGEID}} resolved to 0 or {{REVISIONTIMESTAMP}} used the current
+                       // timestamp rather than that of an actual revision, then those words need
+                       // to resolve to the actual page ID or revision timestamp, respectively.
                        $this->saveParseLogger->info(
                                "$method: Prepared output has vary-revision...\n"
                        );
@@ -395,6 +395,14 @@ class RenderedRevision implements SlotRenderingProvider {
                                "$method: Prepared output has vary-revision-id with wrong ID...\n"
                        );
                        return true;
+               } elseif ( $out->getFlag( 'vary-revision-exists' ) ) {
+                       // If {{REVISIONID}} resolved to '', it now needs to resolve to '-'.
+                       // Note that edit stashing always uses '-', which can be used for both
+                       // edit filter checks and canonical parser cache.
+                       $this->saveParseLogger->info(
+                               "$method: Prepared output has vary-revision-exists...\n"
+                       );
+                       return true;
                } else {
                        // NOTE: In the original fix for T135261, the output was discarded if 'vary-user' was
                        // set for a null-edit. The reason was that the original rendering in that case was
index db6c7c3..17cafc6 100644 (file)
@@ -85,11 +85,12 @@ interface RevisionLookup extends IDBAccessObject {
         * MCR migration note: this replaces Revision::getPrevious
         *
         * @param RevisionRecord $rev
-        * @param Title|null $title if known (optional)
+        * @param int $flags (optional) $flags include:
+        *      IDBAccessObject::READ_LATEST: Select the data from the master
         *
         * @return RevisionRecord|null
         */
-       public function getPreviousRevision( RevisionRecord $rev, Title $title = null );
+       public function getPreviousRevision( RevisionRecord $rev, $flags = 0 );
 
        /**
         * Get next revision for this title
@@ -97,11 +98,24 @@ interface RevisionLookup extends IDBAccessObject {
         * MCR migration note: this replaces Revision::getNext
         *
         * @param RevisionRecord $rev
-        * @param Title|null $title if known (optional)
+        * @param int $flags (optional) $flags include:
+        *      IDBAccessObject::READ_LATEST: Select the data from the master
         *
         * @return RevisionRecord|null
         */
-       public function getNextRevision( RevisionRecord $rev, Title $title = null );
+       public function getNextRevision( RevisionRecord $rev, $flags = 0 );
+
+       /**
+        * Get rev_timestamp from rev_id, without loading the rest of the row.
+        *
+        * MCR migration note: this replaces Revision::getTimestampFromId
+        *
+        * @param int $id
+        * @param int $flags
+        * @return string|bool False if not found
+        * @since 1.34 (present earlier in RevisionStore)
+        */
+       public function getTimestampFromId( $id, $flags = 0 );
 
        /**
         * Load a revision based on a known page ID and current revision ID from the DB
index 632bd31..29d7848 100644 (file)
@@ -278,12 +278,13 @@ class RevisionStore
 
        /**
         * @param int $mode DB_MASTER or DB_REPLICA
+        * @param array $groups
         *
         * @return IDatabase
         */
-       private function getDBConnection( $mode ) {
+       private function getDBConnection( $mode, $groups = [] ) {
                $lb = $this->getDBLoadBalancer();
-               return $lb->getConnection( $mode, [], $this->wikiId );
+               return $lb->getConnection( $mode, $groups, $this->wikiId );
        }
 
        /**
@@ -827,11 +828,11 @@ class RevisionStore
                                        // And we have to use raw SQL to bypass the "aggregation used with a locking SELECT" warning
                                        // that's for non-MySQL DBs.
                                        $row1 = $dbw->query(
-                                               $dbw->selectSqlText( 'archive', [ 'v' => "MAX(ar_rev_id)" ], '', __METHOD__ ) . ' FOR UPDATE'
+                                               $dbw->selectSQLText( 'archive', [ 'v' => "MAX(ar_rev_id)" ], '', __METHOD__ ) . ' FOR UPDATE'
                                        )->fetchObject();
                                        if ( $this->hasMcrSchemaFlags( SCHEMA_COMPAT_WRITE_NEW ) ) {
                                                $row2 = $dbw->query(
-                                                       $dbw->selectSqlText( 'slots', [ 'v' => "MAX(slot_revision_id)" ], '', __METHOD__ )
+                                                       $dbw->selectSQLText( 'slots', [ 'v' => "MAX(slot_revision_id)" ], '', __METHOD__ )
                                                                . ' FOR UPDATE'
                                                )->fetchObject();
                                        } else {
@@ -1508,9 +1509,11 @@ class RevisionStore
         * @return RevisionRecord|null
         */
        public function getRevisionByTitle( LinkTarget $linkTarget, $revId = 0, $flags = 0 ) {
+               // TODO should not require Title in future (T206498)
+               $title = Title::newFromLinkTarget( $linkTarget );
                $conds = [
-                       'page_namespace' => $linkTarget->getNamespace(),
-                       'page_title' => $linkTarget->getDBkey()
+                       'page_namespace' => $title->getNamespace(),
+                       'page_title' => $title->getDBkey()
                ];
                if ( $revId ) {
                        // Use the specified revision ID.
@@ -1519,7 +1522,7 @@ class RevisionStore
                        // Since the caller supplied a revision ID, we are pretty sure the revision is
                        // supposed to exist, so we should try hard to find it.
                        $conds['rev_id'] = $revId;
-                       return $this->newRevisionFromConds( $conds, $flags );
+                       return $this->newRevisionFromConds( $conds, $flags, $title );
                } else {
                        // Use a join to get the latest revision.
                        // Note that we don't use newRevisionFromConds here because we don't want to retry
@@ -1529,7 +1532,7 @@ class RevisionStore
                        $db = $this->getDBConnectionRefForQueryFlags( $flags );
 
                        $conds[] = 'rev_id=page_latest';
-                       $rev = $this->loadRevisionFromConds( $db, $conds, $flags );
+                       $rev = $this->loadRevisionFromConds( $db, $conds, $flags, $title );
 
                        return $rev;
                }
@@ -1668,6 +1671,7 @@ class RevisionStore
        ) {
                if ( !$this->hasMcrSchemaFlags( SCHEMA_COMPAT_READ_NEW ) ) {
                        $mainSlot = $this->emulateMainSlot_1_29( $revisionRow, $queryFlags, $title );
+                       // @phan-suppress-next-line PhanTypeInvalidCallableArraySize false positive
                        $slots = new RevisionSlots( [ SlotRecord::MAIN => $mainSlot ] );
                } else {
                        // XXX: do we need the same kind of caching here
@@ -1736,7 +1740,8 @@ class RevisionStore
                        $user = User::newFromAnyId(
                                $row->ar_user ?? null,
                                $row->ar_user_text ?? null,
-                               $row->ar_actor ?? null
+                               $row->ar_actor ?? null,
+                               $this->wikiId
                        );
                } catch ( InvalidArgumentException $ex ) {
                        wfWarn( __METHOD__ . ': ' . $title->getPrefixedDBkey() . ': ' . $ex->getMessage() );
@@ -1790,7 +1795,8 @@ class RevisionStore
                        $user = User::newFromAnyId(
                                $row->rev_user ?? null,
                                $row->rev_user_text ?? null,
-                               $row->rev_actor ?? null
+                               $row->rev_actor ?? null,
+                               $this->wikiId
                        );
                } catch ( InvalidArgumentException $ex ) {
                        wfWarn( __METHOD__ . ': ' . $title->getPrefixedDBkey() . ': ' . $ex->getMessage() );
@@ -1861,12 +1867,12 @@ class RevisionStore
                }
 
                // if we have a content object, use it to set the model and type
-               if ( !empty( $fields['content'] ) ) {
-                       if ( !( $fields['content'] instanceof Content ) && !is_array( $fields['content'] ) ) {
-                               throw new MWException(
-                                       'content field must contain a Content object or an array of Content objects.'
-                               );
-                       }
+               if ( !empty( $fields['content'] ) && !( $fields['content'] instanceof Content )
+                       && !is_array( $fields['content'] )
+               ) {
+                       throw new MWException(
+                               'content field must contain a Content object or an array of Content objects.'
+                       );
                }
 
                if ( !empty( $fields['text_id'] ) ) {
@@ -1906,6 +1912,7 @@ class RevisionStore
                $this->initializeMutableRevisionFromArray( $revision, $fields );
 
                if ( isset( $fields['content'] ) && is_array( $fields['content'] ) ) {
+                       // @phan-suppress-next-line PhanTypeNoPropertiesForeach
                        foreach ( $fields['content'] as $role => $content ) {
                                $revision->setContent( $role, $content );
                        }
@@ -1928,14 +1935,21 @@ class RevisionStore
                /** @var UserIdentity $user */
                $user = null;
 
-               if ( isset( $fields['user'] ) && ( $fields['user'] instanceof UserIdentity ) ) {
+               // If a user is passed in, use it if possible. We cannot use a user from a
+               // remote wiki with unsuppressed ids, due to issues described in T222212.
+               if ( isset( $fields['user'] ) &&
+                       ( $fields['user'] instanceof UserIdentity ) &&
+                       ( $this->wikiId === false ||
+                               ( !$fields['user']->getId() && !$fields['user']->getActorId() ) )
+               ) {
                        $user = $fields['user'];
                } else {
                        try {
                                $user = User::newFromAnyId(
                                        $fields['user'] ?? null,
                                        $fields['user_text'] ?? null,
-                                       $fields['actor'] ?? null
+                                       $fields['actor'] ?? null,
+                                       $this->wikiId
                                );
                        } catch ( InvalidArgumentException $ex ) {
                                $user = null;
@@ -2545,20 +2559,17 @@ class RevisionStore
        }
 
        /**
-        * Get the revision before $rev in the page's history, if any.
-        * Will return null for the first revision but also for deleted or unsaved revisions.
-        *
-        * MCR migration note: this replaces Revision::getPrevious
-        *
-        * @see Title::getPreviousRevisionID
-        * @see PageArchive::getPreviousRevision
+        * Implementation of getPreviousRevision and getNextRevision.
         *
         * @param RevisionRecord $rev
-        * @param Title|null $title if known (optional)
-        *
+        * @param int $flags
+        * @param string $dir 'next' or 'prev'
         * @return RevisionRecord|null
         */
-       public function getPreviousRevision( RevisionRecord $rev, Title $title = null ) {
+       private function getRelativeRevision( RevisionRecord $rev, $flags, $dir ) {
+               $op = $dir === 'next' ? '>' : '<';
+               $sort = $dir === 'next' ? 'ASC' : 'DESC';
+
                if ( !$rev->getId() || !$rev->getPageId() ) {
                        // revision is unsaved or otherwise incomplete
                        return null;
@@ -2569,54 +2580,86 @@ class RevisionStore
                        return null;
                }
 
-               if ( $title === null ) {
-                       // this would fail for deleted revisions
-                       $title = $this->getTitle( $rev->getPageId(), $rev->getId() );
+               list( $dbType, ) = DBAccessObjectUtils::getDBOptions( $flags );
+               $db = $this->getDBConnection( $dbType, [ 'contributions' ] );
+
+               $ts = $this->getTimestampFromId( $rev->getId(), $flags );
+               if ( $ts === false ) {
+                       // XXX Should this be moved into getTimestampFromId?
+                       $ts = $db->selectField( 'archive', 'ar_timestamp',
+                               [ 'ar_rev_id' => $rev->getId() ], __METHOD__ );
+                       if ( $ts === false ) {
+                               // XXX Is this reachable? How can we have a page id but no timestamp?
+                               return null;
+                       }
                }
+               $ts = $db->addQuotes( $db->timestamp( $ts ) );
+
+               $revId = $db->selectField( 'revision', 'rev_id',
+                       [
+                               'rev_page' => $rev->getPageId(),
+                               "rev_timestamp $op $ts OR (rev_timestamp = $ts AND rev_id $op {$rev->getId()})"
+                       ],
+                       __METHOD__,
+                       [
+                               'ORDER BY' => "rev_timestamp $sort, rev_id $sort",
+                               'IGNORE INDEX' => 'rev_timestamp', // Probably needed for T159319
+                       ]
+               );
 
-               $prev = $title->getPreviousRevisionID( $rev->getId() );
-               if ( !$prev ) {
+               if ( $revId === false ) {
                        return null;
                }
 
-               return $this->getRevisionByTitle( $title, $prev );
+               return $this->getRevisionById( intval( $revId ) );
        }
 
        /**
-        * Get the revision after $rev in the page's history, if any.
-        * Will return null for the latest revision but also for deleted or unsaved revisions.
+        * Get the revision before $rev in the page's history, if any.
+        * Will return null for the first revision but also for deleted or unsaved revisions.
         *
-        * MCR migration note: this replaces Revision::getNext
+        * MCR migration note: this replaces Revision::getPrevious
         *
-        * @see Title::getNextRevisionID
+        * @see Title::getPreviousRevisionID
+        * @see PageArchive::getPreviousRevision
         *
         * @param RevisionRecord $rev
-        * @param Title|null $title if known (optional)
+        * @param int $flags (optional) $flags include:
+        *      IDBAccessObject::READ_LATEST: Select the data from the master
         *
         * @return RevisionRecord|null
         */
-       public function getNextRevision( RevisionRecord $rev, Title $title = null ) {
-               if ( !$rev->getId() || !$rev->getPageId() ) {
-                       // revision is unsaved or otherwise incomplete
-                       return null;
+       public function getPreviousRevision( RevisionRecord $rev, $flags = 0 ) {
+               if ( $flags instanceof Title ) {
+                       // Old calling convention, we don't use Title here anymore
+                       wfDeprecated( __METHOD__ . ' with Title', '1.34' );
+                       $flags = 0;
                }
 
-               if ( $rev instanceof RevisionArchiveRecord ) {
-                       // revision is deleted, so it's not part of the page history
-                       return null;
-               }
-
-               if ( $title === null ) {
-                       // this would fail for deleted revisions
-                       $title = $this->getTitle( $rev->getPageId(), $rev->getId() );
-               }
+               return $this->getRelativeRevision( $rev, $flags, 'prev' );
+       }
 
-               $next = $title->getNextRevisionID( $rev->getId() );
-               if ( !$next ) {
-                       return null;
+       /**
+        * Get the revision after $rev in the page's history, if any.
+        * Will return null for the latest revision but also for deleted or unsaved revisions.
+        *
+        * MCR migration note: this replaces Revision::getNext
+        *
+        * @see Title::getNextRevisionID
+        *
+        * @param RevisionRecord $rev
+        * @param int $flags (optional) $flags include:
+        *      IDBAccessObject::READ_LATEST: Select the data from the master
+        * @return RevisionRecord|null
+        */
+       public function getNextRevision( RevisionRecord $rev, $flags = 0 ) {
+               if ( $flags instanceof Title ) {
+                       // Old calling convention, we don't use Title here anymore
+                       wfDeprecated( __METHOD__ . ' with Title', '1.34' );
+                       $flags = 0;
                }
 
-               return $this->getRevisionByTitle( $title, $next );
+               return $this->getRelativeRevision( $rev, $flags, 'next' );
        }
 
        /**
@@ -2655,21 +2698,27 @@ class RevisionStore
        }
 
        /**
-        * Get rev_timestamp from rev_id, without loading the rest of the row
+        * Get rev_timestamp from rev_id, without loading the rest of the row.
+        *
+        * Historically, there was an extra Title parameter that was passed before $id. This is no
+        * longer needed and is deprecated in 1.34.
         *
         * MCR migration note: this replaces Revision::getTimestampFromId
         *
-        * @param Title $title
         * @param int $id
         * @param int $flags
         * @return string|bool False if not found
         */
-       public function getTimestampFromId( $title, $id, $flags = 0 ) {
+       public function getTimestampFromId( $id, $flags = 0 ) {
+               if ( $id instanceof Title ) {
+                       // Old deprecated calling convention supported for backwards compatibility
+                       $id = $flags;
+                       $flags = func_num_args() > 2 ? func_get_arg( 2 ) : 0;
+               }
                $db = $this->getDBConnectionRefForQueryFlags( $flags );
 
-               $conds = [ 'rev_id' => $id ];
-               $conds['rev_page'] = $title->getArticleID();
-               $timestamp = $db->selectField( 'revision', 'rev_timestamp', $conds, __METHOD__ );
+               $timestamp =
+                       $db->selectField( 'revision', 'rev_timestamp', [ 'rev_id' => $id ], __METHOD__ );
 
                return ( $timestamp !== false ) ? wfTimestamp( TS_MW, $timestamp ) : false;
        }
diff --git a/includes/RevisionList.php b/includes/RevisionList.php
deleted file mode 100644 (file)
index 5243cc6..0000000
+++ /dev/null
@@ -1,447 +0,0 @@
-<?php
-/**
- * Holders of revision list for a single page
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-use MediaWiki\MediaWikiServices;
-use Wikimedia\Rdbms\ResultWrapper;
-use Wikimedia\Rdbms\IDatabase;
-
-/**
- * List for revision table items for a single page
- */
-abstract class RevisionListBase extends ContextSource implements Iterator {
-       /** @var Title */
-       public $title;
-
-       /** @var array */
-       protected $ids;
-
-       /** @var ResultWrapper|bool */
-       protected $res;
-
-       /** @var bool|Revision */
-       protected $current;
-
-       /**
-        * Construct a revision list for a given title
-        * @param IContextSource $context
-        * @param Title $title
-        */
-       function __construct( IContextSource $context, Title $title ) {
-               $this->setContext( $context );
-               $this->title = $title;
-       }
-
-       /**
-        * Select items only where the ID is any of the specified values
-        * @param array $ids
-        */
-       function filterByIds( array $ids ) {
-               $this->ids = $ids;
-       }
-
-       /**
-        * Get the internal type name of this list. Equal to the table name.
-        * Override this function.
-        * @return null
-        */
-       public function getType() {
-               return null;
-       }
-
-       /**
-        * Initialise the current iteration pointer
-        */
-       protected function initCurrent() {
-               $row = $this->res->current();
-               if ( $row ) {
-                       $this->current = $this->newItem( $row );
-               } else {
-                       $this->current = false;
-               }
-       }
-
-       /**
-        * Start iteration. This must be called before current() or next().
-        * @return Revision First list item
-        */
-       public function reset() {
-               if ( !$this->res ) {
-                       $this->res = $this->doQuery( wfGetDB( DB_REPLICA ) );
-               } else {
-                       $this->res->rewind();
-               }
-               $this->initCurrent();
-               return $this->current;
-       }
-
-       public function rewind() {
-               $this->reset();
-       }
-
-       /**
-        * Get the current list item, or false if we are at the end
-        * @return Revision
-        */
-       public function current() {
-               return $this->current;
-       }
-
-       /**
-        * Move the iteration pointer to the next list item, and return it.
-        * @return Revision
-        */
-       public function next() {
-               $this->res->next();
-               $this->initCurrent();
-               return $this->current;
-       }
-
-       public function key() {
-               return $this->res ? $this->res->key() : 0;
-       }
-
-       public function valid() {
-               return $this->res ? $this->res->valid() : false;
-       }
-
-       /**
-        * Get the number of items in the list.
-        * @return int
-        */
-       public function length() {
-               if ( !$this->res ) {
-                       return 0;
-               } else {
-                       return $this->res->numRows();
-               }
-       }
-
-       /**
-        * Do the DB query to iterate through the objects.
-        * @param IDatabase $db DB object to use for the query
-        */
-       abstract public function doQuery( $db );
-
-       /**
-        * Create an item object from a DB result row
-        * @param object $row
-        */
-       abstract public function newItem( $row );
-}
-
-/**
- * Abstract base class for revision items
- */
-abstract class RevisionItemBase {
-       /** @var RevisionListBase The parent */
-       protected $list;
-
-       /** The database result row */
-       protected $row;
-
-       /**
-        * @param RevisionListBase $list
-        * @param object $row DB result row
-        */
-       public function __construct( $list, $row ) {
-               $this->list = $list;
-               $this->row = $row;
-       }
-
-       /**
-        * Get the DB field name associated with the ID list.
-        * Override this function.
-        * @return null
-        */
-       public function getIdField() {
-               return null;
-       }
-
-       /**
-        * Get the DB field name storing timestamps.
-        * Override this function.
-        * @return bool
-        */
-       public function getTimestampField() {
-               return false;
-       }
-
-       /**
-        * Get the DB field name storing user ids.
-        * Override this function.
-        * @return bool
-        */
-       public function getAuthorIdField() {
-               return false;
-       }
-
-       /**
-        * Get the DB field name storing user names.
-        * Override this function.
-        * @return bool
-        */
-       public function getAuthorNameField() {
-               return false;
-       }
-
-       /**
-        * Get the DB field name storing actor ids.
-        * Override this function.
-        * @since 1.31
-        * @return bool
-        */
-       public function getAuthorActorField() {
-               return false;
-       }
-
-       /**
-        * Get the ID, as it would appear in the ids URL parameter
-        * @return int
-        */
-       public function getId() {
-               $field = $this->getIdField();
-               return $this->row->$field;
-       }
-
-       /**
-        * Get the date, formatted in user's language
-        * @return string
-        */
-       public function formatDate() {
-               return $this->list->getLanguage()->userDate( $this->getTimestamp(),
-                       $this->list->getUser() );
-       }
-
-       /**
-        * Get the time, formatted in user's language
-        * @return string
-        */
-       public function formatTime() {
-               return $this->list->getLanguage()->userTime( $this->getTimestamp(),
-                       $this->list->getUser() );
-       }
-
-       /**
-        * Get the timestamp in MW 14-char form
-        * @return mixed
-        */
-       public function getTimestamp() {
-               $field = $this->getTimestampField();
-               return wfTimestamp( TS_MW, $this->row->$field );
-       }
-
-       /**
-        * Get the author user ID
-        * @return int
-        */
-       public function getAuthorId() {
-               $field = $this->getAuthorIdField();
-               return intval( $this->row->$field );
-       }
-
-       /**
-        * Get the author user name
-        * @return string
-        */
-       public function getAuthorName() {
-               $field = $this->getAuthorNameField();
-               return strval( $this->row->$field );
-       }
-
-       /**
-        * Get the author actor ID
-        * @since 1.31
-        * @return string
-        */
-       public function getAuthorActor() {
-               $field = $this->getAuthorActorField();
-               return strval( $this->row->$field );
-       }
-
-       /**
-        * Returns true if the current user can view the item
-        */
-       abstract public function canView();
-
-       /**
-        * Returns true if the current user can view the item text/file
-        */
-       abstract public function canViewContent();
-
-       /**
-        * Get the HTML of the list item. Should be include "<li></li>" tags.
-        * This is used to show the list in HTML form, by the special page.
-        */
-       abstract public function getHTML();
-
-       /**
-        * Returns an instance of LinkRenderer
-        * @return \MediaWiki\Linker\LinkRenderer
-        */
-       protected function getLinkRenderer() {
-               return MediaWikiServices::getInstance()->getLinkRenderer();
-       }
-}
-
-class RevisionList extends RevisionListBase {
-       public function getType() {
-               return 'revision';
-       }
-
-       /**
-        * @param IDatabase $db
-        * @return mixed
-        */
-       public function doQuery( $db ) {
-               $conds = [ 'rev_page' => $this->title->getArticleID() ];
-               if ( $this->ids !== null ) {
-                       $conds['rev_id'] = array_map( 'intval', $this->ids );
-               }
-               $revQuery = Revision::getQueryInfo( [ 'page', 'user' ] );
-               return $db->select(
-                       $revQuery['tables'],
-                       $revQuery['fields'],
-                       $conds,
-                       __METHOD__,
-                       [ 'ORDER BY' => 'rev_id DESC' ],
-                       $revQuery['joins']
-               );
-       }
-
-       public function newItem( $row ) {
-               return new RevisionItem( $this, $row );
-       }
-}
-
-/**
- * Item class for a live revision table row
- */
-class RevisionItem extends RevisionItemBase {
-       /** @var Revision */
-       protected $revision;
-
-       /** @var RequestContext */
-       protected $context;
-
-       public function __construct( $list, $row ) {
-               parent::__construct( $list, $row );
-               $this->revision = new Revision( $row );
-               $this->context = $list->getContext();
-       }
-
-       public function getIdField() {
-               return 'rev_id';
-       }
-
-       public function getTimestampField() {
-               return 'rev_timestamp';
-       }
-
-       public function getAuthorIdField() {
-               return 'rev_user';
-       }
-
-       public function getAuthorNameField() {
-               return 'rev_user_text';
-       }
-
-       public function canView() {
-               return $this->revision->userCan( Revision::DELETED_RESTRICTED, $this->context->getUser() );
-       }
-
-       public function canViewContent() {
-               return $this->revision->userCan( Revision::DELETED_TEXT, $this->context->getUser() );
-       }
-
-       public function isDeleted() {
-               return $this->revision->isDeleted( Revision::DELETED_TEXT );
-       }
-
-       /**
-        * Get the HTML link to the revision text.
-        * @todo Essentially a copy of RevDelRevisionItem::getRevisionLink. That class
-        * should inherit from this one, and implement an appropriate interface instead
-        * of extending RevDelItem
-        * @return string
-        */
-       protected function getRevisionLink() {
-               $date = $this->list->getLanguage()->userTimeAndDate(
-                       $this->revision->getTimestamp(), $this->list->getUser() );
-
-               if ( $this->isDeleted() && !$this->canViewContent() ) {
-                       return htmlspecialchars( $date );
-               }
-               $linkRenderer = $this->getLinkRenderer();
-               return $linkRenderer->makeKnownLink(
-                       $this->list->title,
-                       $date,
-                       [],
-                       [
-                               'oldid' => $this->revision->getId(),
-                               'unhide' => 1
-                       ]
-               );
-       }
-
-       /**
-        * Get the HTML link to the diff.
-        * @todo Essentially a copy of RevDelRevisionItem::getDiffLink. That class
-        * should inherit from this one, and implement an appropriate interface instead
-        * of extending RevDelItem
-        * @return string
-        */
-       protected function getDiffLink() {
-               if ( $this->isDeleted() && !$this->canViewContent() ) {
-                       return $this->context->msg( 'diff' )->escaped();
-               } else {
-                       $linkRenderer = $this->getLinkRenderer();
-                       return $linkRenderer->makeKnownLink(
-                                       $this->list->title,
-                                       $this->list->msg( 'diff' )->text(),
-                                       [],
-                                       [
-                                               'diff' => $this->revision->getId(),
-                                               'oldid' => 'prev',
-                                               'unhide' => 1
-                                       ]
-                               );
-               }
-       }
-
-       /**
-        * @todo Essentially a copy of RevDelRevisionItem::getHTML. That class
-        * should inherit from this one, and implement an appropriate interface instead
-        * of extending RevDelItem
-        * @return string
-        */
-       public function getHTML() {
-               $difflink = $this->context->msg( 'parentheses' )
-                       ->rawParams( $this->getDiffLink() )->escaped();
-               $revlink = $this->getRevisionLink();
-               $userlink = Linker::revUserLink( $this->revision );
-               $comment = Linker::revComment( $this->revision );
-               if ( $this->isDeleted() ) {
-                       $revlink = "<span class=\"history-deleted\">$revlink</span>";
-               }
-               return "<li>$difflink $revlink $userlink $comment</li>";
-       }
-}
index 12e782d..c9db5a8 100644 (file)
 
 use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface;
 use MediaWiki\Auth\AuthManager;
+use MediaWiki\Block\BlockManager;
+use MediaWiki\Block\BlockRestrictionStore;
 use MediaWiki\Config\ConfigRepository;
+use MediaWiki\Config\ServiceOptions;
+use MediaWiki\Http\HttpRequestFactory;
 use MediaWiki\Interwiki\ClassicInterwikiLookup;
 use MediaWiki\Interwiki\InterwikiLookup;
 use MediaWiki\Linker\LinkRenderer;
 use MediaWiki\Linker\LinkRendererFactory;
 use MediaWiki\Logger\LoggerFactory;
 use MediaWiki\MediaWikiServices;
+use MediaWiki\Permissions\PermissionManager;
 use MediaWiki\Preferences\PreferencesFactory;
 use MediaWiki\Preferences\DefaultPreferencesFactory;
 use MediaWiki\Revision\MainSlotRoleHandler;
@@ -61,6 +66,7 @@ use MediaWiki\Storage\BlobStore;
 use MediaWiki\Storage\BlobStoreFactory;
 use MediaWiki\Storage\NameTableStoreFactory;
 use MediaWiki\Storage\SqlBlobStore;
+use MediaWiki\Storage\PageEditStash;
 
 return [
        'ActorMigration' => function ( MediaWikiServices $services ) : ActorMigration {
@@ -77,11 +83,35 @@ return [
                return new BlobStoreFactory(
                        $services->getDBLoadBalancerFactory(),
                        $services->getMainWANObjectCache(),
-                       $services->getMainConfig(),
+                       new ServiceOptions( BlobStoreFactory::$constructorOptions,
+                               $services->getMainConfig() ),
                        $services->getContentLanguage()
                );
        },
 
+       'BlockManager' => function ( MediaWikiServices $services ) : BlockManager {
+               $config = $services->getMainConfig();
+               $context = RequestContext::getMain();
+               return new BlockManager(
+                       $context->getUser(),
+                       $context->getRequest(),
+                       $config->get( 'ApplyIpBlocksToXff' ),
+                       $config->get( 'CookieSetOnAutoblock' ),
+                       $config->get( 'CookieSetOnIpBlock' ),
+                       $config->get( 'DnsBlacklistUrls' ),
+                       $config->get( 'EnableDnsBlacklist' ),
+                       $config->get( 'ProxyList' ),
+                       $config->get( 'ProxyWhitelist' ),
+                       $config->get( 'SoftBlockRanges' )
+               );
+       },
+
+       'BlockRestrictionStore' => function ( MediaWikiServices $services ) : BlockRestrictionStore {
+               return new BlockRestrictionStore(
+                       $services->getDBLoadBalancer()
+               );
+       },
+
        'CommentStore' => function ( MediaWikiServices $services ) : CommentStore {
                return new CommentStore(
                        $services->getContentLanguage(),
@@ -105,7 +135,11 @@ return [
        },
 
        'ConfiguredReadOnlyMode' => function ( MediaWikiServices $services ) : ConfiguredReadOnlyMode {
-               return new ConfiguredReadOnlyMode( $services->getMainConfig() );
+               $config = $services->getMainConfig();
+               return new ConfiguredReadOnlyMode(
+                       $config->get( 'ReadOnly' ),
+                       $config->get( 'ReadOnlyFile' )
+               );
        },
 
        'ContentLanguage' => function ( MediaWikiServices $services ) : Language {
@@ -133,11 +167,11 @@ return [
                return new CryptHKDF( $secret, $config->get( 'HKDFAlgorithm' ), $cache, $context );
        },
 
-       'CryptRand' => function () : CryptRand {
-               return new CryptRand();
+       'DateFormatterFactory' => function () : DateFormatterFactory {
+               return new DateFormatterFactory;
        },
 
-       'DBLoadBalancer' => function ( MediaWikiServices $services ) : Wikimedia\Rdbms\LoadBalancer {
+       'DBLoadBalancer' => function ( MediaWikiServices $services ) : Wikimedia\Rdbms\ILoadBalancer {
                // just return the default LB from the DBLoadBalancerFactory service
                return $services->getDBLoadBalancerFactory()->getMainLB();
        },
@@ -148,13 +182,16 @@ return [
 
                $lbConf = MWLBFactory::applyDefaultConfig(
                        $mainConfig->get( 'LBFactoryConf' ),
-                       $mainConfig,
-                       $services->getConfiguredReadOnlyMode()
+                       new ServiceOptions( MWLBFactory::$applyDefaultConfigOptions, $mainConfig ),
+                       $services->getConfiguredReadOnlyMode(),
+                       $services->getLocalServerObjectCache(),
+                       $services->getMainObjectStash(),
+                       $services->getMainWANObjectCache()
                );
                $class = MWLBFactory::getLBFactoryClass( $lbConf );
 
                $instance = new $class( $lbConf );
-               MWLBFactory::setSchemaAliases( $instance, $mainConfig );
+               MWLBFactory::setSchemaAliases( $instance, $mainConfig->get( 'DBtype' ) );
 
                return $instance;
        },
@@ -172,12 +209,12 @@ return [
        },
 
        'GenderCache' => function ( MediaWikiServices $services ) : GenderCache {
-               return new GenderCache();
+               return new GenderCache( $services->getNamespaceInfo() );
        },
 
        'HttpRequestFactory' =>
-       function ( MediaWikiServices $services ) : \MediaWiki\Http\HttpRequestFactory {
-               return new \MediaWiki\Http\HttpRequestFactory();
+       function ( MediaWikiServices $services ) : HttpRequestFactory {
+               return new HttpRequestFactory();
        },
 
        'InterwikiLookup' => function ( MediaWikiServices $services ) : InterwikiLookup {
@@ -195,24 +232,26 @@ return [
        'LinkCache' => function ( MediaWikiServices $services ) : LinkCache {
                return new LinkCache(
                        $services->getTitleFormatter(),
-                       $services->getMainWANObjectCache()
+                       $services->getMainWANObjectCache(),
+                       $services->getNamespaceInfo()
                );
        },
 
        'LinkRenderer' => function ( MediaWikiServices $services ) : LinkRenderer {
-               global $wgUser;
-
                if ( defined( 'MW_NO_SESSION' ) ) {
                        return $services->getLinkRendererFactory()->create();
                } else {
-                       return $services->getLinkRendererFactory()->createForUser( $wgUser );
+                       return $services->getLinkRendererFactory()->createForUser(
+                               RequestContext::getMain()->getUser()
+                       );
                }
        },
 
        'LinkRendererFactory' => function ( MediaWikiServices $services ) : LinkRendererFactory {
                return new LinkRendererFactory(
                        $services->getTitleFormatter(),
-                       $services->getLinkCache()
+                       $services->getLinkCache(),
+                       $services->getNamespaceInfo()
                );
        },
 
@@ -326,6 +365,11 @@ return [
                return new MimeAnalyzer( $params );
        },
 
+       'NamespaceInfo' => function ( MediaWikiServices $services ) : NamespaceInfo {
+               return new NamespaceInfo( new ServiceOptions( NamespaceInfo::$constructorOptions,
+                       $services->getMainConfig() ) );
+       },
+
        'NameTableStoreFactory' => function ( MediaWikiServices $services ) : NameTableStoreFactory {
                return new NameTableStoreFactory(
                        $services->getDBLoadBalancerFactory(),
@@ -342,6 +386,20 @@ return [
                );
        },
 
+       'PageEditStash' => function ( MediaWikiServices $services ) : PageEditStash {
+               $config = $services->getMainConfig();
+
+               return new PageEditStash(
+                       ObjectCache::getLocalClusterInstance(),
+                       $services->getDBLoadBalancer(),
+                       LoggerFactory::getInstance( 'StashEdit' ),
+                       $services->getStatsdDataFactory(),
+                       defined( 'MEDIAWIKI_JOB_RUNNER' ) || $config->get( 'CommandLineMode' )
+                               ? PageEditStash::INITIATOR_JOB_OR_CLI
+                               : PageEditStash::INITIATOR_USER
+               );
+       },
+
        'Parser' => function ( MediaWikiServices $services ) : Parser {
                return $services->getParserFactory()->create();
        },
@@ -358,13 +416,24 @@ return [
        },
 
        'ParserFactory' => function ( MediaWikiServices $services ) : ParserFactory {
-               return new ParserFactory(
+               $options = new ServiceOptions( Parser::$constructorOptions,
+                       // 'class' and 'preprocessorClass'
                        $services->getMainConfig()->get( 'ParserConf' ),
+                       // Make sure to have defaults in case someone overrode ParserConf with something silly
+                       [ 'class' => Parser::class,
+                               'preprocessorClass' => Parser::getDefaultPreprocessorClass() ],
+                       // Plus a buch of actual config options
+                       $services->getMainConfig()
+               );
+
+               return new ParserFactory(
+                       $options,
                        $services->getMagicWordFactory(),
                        $services->getContentLanguage(),
                        wfUrlProtocols(),
                        $services->getSpecialPageFactory(),
-                       $services->getMainConfig()
+                       $services->getLinkRendererFactory(),
+                       $services->getNamespaceInfo()
                );
        },
 
@@ -386,12 +455,26 @@ return [
                );
        },
 
+       'PermissionManager' => function ( MediaWikiServices $services ) : PermissionManager {
+               $config = $services->getMainConfig();
+               return new PermissionManager(
+                       $services->getSpecialPageFactory(),
+                       $config->get( 'WhitelistRead' ),
+                       $config->get( 'WhitelistReadRegexp' ),
+                       $config->get( 'EmailConfirmToEdit' ),
+                       $config->get( 'BlockDisablesLogin' ),
+                       $services->getNamespaceInfo()
+               );
+       },
+
        'PreferencesFactory' => function ( MediaWikiServices $services ) : PreferencesFactory {
                $factory = new DefaultPreferencesFactory(
-                       $services->getMainConfig(),
+                       new ServiceOptions(
+                               DefaultPreferencesFactory::$constructorOptions, $services->getMainConfig() ),
                        $services->getContentLanguage(),
                        AuthManager::singleton(),
-                       $services->getLinkRendererFactory()->create()
+                       $services->getLinkRendererFactory()->create(),
+                       $services->getNamespaceInfo()
                );
                $factory->setLogger( LoggerFactory::getInstance( 'preferences' ) );
 
@@ -413,11 +496,38 @@ return [
                );
        },
 
+       'RepoGroup' => function ( MediaWikiServices $services ) : RepoGroup {
+               $config = $services->getMainConfig();
+               return new RepoGroup(
+                       $config->get( 'LocalFileRepo' ),
+                       $config->get( 'ForeignFileRepos' ),
+                       $services->getMainWANObjectCache()
+               );
+       },
+
        'ResourceLoader' => function ( MediaWikiServices $services ) : ResourceLoader {
-               return new ResourceLoader(
-                       $services->getMainConfig(),
+               // @todo This should not take a Config object, but it's not so easy to remove because it
+               // exposes it in a getter, which is actually used.
+               global $IP;
+               $config = $services->getMainConfig();
+
+               $rl = new ResourceLoader(
+                       $config,
                        LoggerFactory::getInstance( 'resourceloader' )
                );
+
+               $rl->addSource( $config->get( 'ResourceLoaderSources' ) );
+
+               // Core modules, then extension/skin modules
+               $rl->register( include "$IP/resources/Resources.php" );
+               $rl->register( $config->get( 'ResourceModules' ) );
+               Hooks::run( 'ResourceLoaderRegisterModules', [ &$rl ] );
+
+               if ( $config->get( 'EnableJavaScriptTest' ) === true ) {
+                       $rl->registerTestModules();
+               }
+
+               return $rl;
        },
 
        'RevisionFactory' => function ( MediaWikiServices $services ) : RevisionFactory {
@@ -461,6 +571,8 @@ return [
        },
 
        'SearchEngineConfig' => function ( MediaWikiServices $services ) : SearchEngineConfig {
+               // @todo This should not take a Config object, but it's not so easy to remove because it
+               // exposes it in a getter, which is actually used.
                return new SearchEngineConfig( $services->getMainConfig(),
                        $services->getContentLanguage() );
        },
@@ -546,7 +658,8 @@ return [
 
        'SpecialPageFactory' => function ( MediaWikiServices $services ) : SpecialPageFactory {
                return new SpecialPageFactory(
-                       $services->getMainConfig(),
+                       new ServiceOptions(
+                               SpecialPageFactory::$constructorOptions, $services->getMainConfig() ),
                        $services->getContentLanguage()
                );
        },
@@ -606,7 +719,9 @@ return [
                        $services->getMainObjectStash(),
                        new HashBagOStuff( [ 'maxKeys' => 100 ] ),
                        $services->getReadOnlyMode(),
-                       $services->getMainConfig()->get( 'UpdateRowsPerQuery' )
+                       $services->getMainConfig()->get( 'UpdateRowsPerQuery' ),
+                       $services->getNamespaceInfo(),
+                       $services->getRevisionLookup()
                );
                $store->setStatsdDataFactory( $services->getStatsdDataFactory() );
 
@@ -631,7 +746,8 @@ return [
                        $services->getContentLanguage(),
                        $services->getGenderCache(),
                        $services->getMainConfig()->get( 'LocalInterwikis' ),
-                       $services->getInterwikiLookup()
+                       $services->getInterwikiLookup(),
+                       $services->getNamespaceInfo()
                );
        },
 
index bcdc1d5..071b7c6 100644 (file)
@@ -736,9 +736,10 @@ $cpPosInfo = LBFactory::getCPInfoFromCookieValue(
 MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->setRequestInfo( [
        'IPAddress' => $wgRequest->getIP(),
        'UserAgent' => $wgRequest->getHeader( 'User-Agent' ),
-       'ChronologyProtection' => $wgRequest->getHeader( 'ChronologyProtection' ),
+       'ChronologyProtection' => $wgRequest->getHeader( 'MediaWiki-Chronology-Protection' ),
        'ChronologyPositionIndex' => $wgRequest->getInt( 'cpPosIndex', $cpPosInfo['index'] ),
        'ChronologyClientId' => $cpPosInfo['clientId']
+               ?? $wgRequest->getHeader( 'MediaWiki-Chronology-Client-Id' )
 ] );
 unset( $cpPosInfo );
 // Make sure that object caching does not undermine the ChronologyProtector improvements
index 7af80dc..cab98a7 100644 (file)
@@ -562,7 +562,7 @@ class SiteConfiguration {
                                ->execute();
 
                        $data = trim( $result->getStdout() );
-                       if ( $result->getExitCode() != 0 || !strlen( $data ) ) {
+                       if ( $result->getExitCode() || $data === '' ) {
                                throw new MWException( "Failed to run getConfiguration.php: {$result->getStdout()}" );
                        }
                        $res = unserialize( $data );
@@ -582,14 +582,14 @@ class SiteConfiguration {
         * which is not fun
         *
         * @param array $array1
+        * @param array ...$arrays
         *
         * @return array
         */
-       static function arrayMerge( $array1/* ... */ ) {
+       static function arrayMerge( array $array1, ...$arrays ) {
                $out = $array1;
-               $argsCount = func_num_args();
-               for ( $i = 1; $i < $argsCount; $i++ ) {
-                       foreach ( func_get_arg( $i ) as $key => $value ) {
+               foreach ( $arrays as $array ) {
+                       foreach ( $array as $key => $value ) {
                                if ( isset( $out[$key] ) && is_array( $out[$key] ) && is_array( $value ) ) {
                                        $out[$key] = self::arrayMerge( $out[$key], $value );
                                } elseif ( !isset( $out[$key] ) || !$out[$key] && !is_numeric( $key ) ) {
index 8adb218..e97db2d 100644 (file)
@@ -68,15 +68,15 @@ class SiteStatsInit {
         * @return int
         */
        public function articles() {
-               $config = MediaWikiServices::getInstance()->getMainConfig();
+               $services = MediaWikiServices::getInstance();
 
                $tables = [ 'page' ];
                $conds = [
-                       'page_namespace' => MWNamespace::getContentNamespaces(),
+                       'page_namespace' => $services->getNamespaceInfo()->getContentNamespaces(),
                        'page_is_redirect' => 0,
                ];
 
-               if ( $config->get( 'ArticleCountMethod' ) == 'link' ) {
+               if ( $services->getMainConfig()->get( 'ArticleCountMethod' ) == 'link' ) {
                        $tables[] = 'pagelinks';
                        $conds[] = 'pl_from=page_id';
                }
index 4e1f97f..5e99454 100644 (file)
@@ -20,8 +20,8 @@
 
 namespace MediaWiki\Storage;
 
-use Config;
 use Language;
+use MediaWiki\Config\ServiceOptions;
 use WANObjectCache;
 use Wikimedia\Rdbms\LBFactory;
 
@@ -45,24 +45,39 @@ class BlobStoreFactory {
        private $cache;
 
        /**
-        * @var Config
+        * @var ServiceOptions
         */
-       private $config;
+       private $options;
 
        /**
         * @var Language
         */
        private $contLang;
 
+       /**
+        * TODO Make this a const when HHVM support is dropped (T192166)
+        *
+        * @var array
+        * @since 1.34
+        */
+       public static $constructorOptions = [
+               'CompressRevisions',
+               'DefaultExternalStore',
+               'LegacyEncoding',
+               'RevisionCacheExpiry',
+       ];
+
        public function __construct(
                LBFactory $lbFactory,
                WANObjectCache $cache,
-               Config $mainConfig,
+               ServiceOptions $options,
                Language $contLang
        ) {
+               $options->assertRequiredOptions( self::$constructorOptions );
+
                $this->lbFactory = $lbFactory;
                $this->cache = $cache;
-               $this->config = $mainConfig;
+               $this->options = $options;
                $this->contLang = $contLang;
        }
 
@@ -92,12 +107,12 @@ class BlobStoreFactory {
                        $wikiId
                );
 
-               $store->setCompressBlobs( $this->config->get( 'CompressRevisions' ) );
-               $store->setCacheExpiry( $this->config->get( 'RevisionCacheExpiry' ) );
-               $store->setUseExternalStore( $this->config->get( 'DefaultExternalStore' ) !== false );
+               $store->setCompressBlobs( $this->options->get( 'CompressRevisions' ) );
+               $store->setCacheExpiry( $this->options->get( 'RevisionCacheExpiry' ) );
+               $store->setUseExternalStore( $this->options->get( 'DefaultExternalStore' ) !== false );
 
-               if ( $this->config->get( 'LegacyEncoding' ) ) {
-                       $store->setLegacyEncoding( $this->config->get( 'LegacyEncoding' ), $this->contLang );
+               if ( $this->options->get( 'LegacyEncoding' ) ) {
+                       $store->setLegacyEncoding( $this->options->get( 'LegacyEncoding' ), $this->contLang );
                }
 
                return $store;
index 9ce12b4..bc48a0e 100644 (file)
@@ -22,7 +22,6 @@
 
 namespace MediaWiki\Storage;
 
-use ApiStashEdit;
 use CategoryMembershipChangeJob;
 use Content;
 use ContentHandler;
@@ -38,6 +37,7 @@ use LinksDeletionUpdate;
 use LinksUpdate;
 use LogicException;
 use MediaWiki\Edit\PreparedEdit;
+use MediaWiki\MediaWikiServices;
 use MediaWiki\Revision\MutableRevisionRecord;
 use MediaWiki\Revision\RenderedRevision;
 use MediaWiki\Revision\RevisionRecord;
@@ -750,17 +750,17 @@ class DerivedPageDataUpdater implements IDBAccessObject {
 
                $parentRevision = $this->grabCurrentRevision();
 
-               $this->slotsOutput = [];
-               $this->canonicalParserOutput = null;
-
                // The edit may have already been prepared via api.php?action=stashedit
                $stashedEdit = false;
 
                // TODO: MCR: allow output for all slots to be stashed.
                if ( $useStash && $slotsUpdate->isModifiedSlot( SlotRecord::MAIN ) ) {
-                       $mainContent = $slotsUpdate->getModifiedSlot( SlotRecord::MAIN )->getContent();
-                       $legacyUser = User::newFromIdentity( $user );
-                       $stashedEdit = ApiStashEdit::checkCache( $title, $mainContent, $legacyUser );
+                       $editStash = MediaWikiServices::getInstance()->getPageEditStash();
+                       $stashedEdit = $editStash->checkCache(
+                               $title,
+                               $slotsUpdate->getModifiedSlot( SlotRecord::MAIN )->getContent(),
+                               User::newFromIdentity( $user )
+                       );
                }
 
                $userPopts = ParserOptions::newFromUserAndLang( $user, $this->contLang );
@@ -1242,7 +1242,7 @@ class DerivedPageDataUpdater implements IDBAccessObject {
                $preparedEdit = new PreparedEdit();
 
                $preparedEdit->popts = $this->getCanonicalParserOptions();
-               $preparedEdit->output = $this->getCanonicalParserOutput();
+               $preparedEdit->parserOutputCallback = [ $this, 'getCanonicalParserOutput' ];
                $preparedEdit->pstContent = $this->revision->getContent( SlotRecord::MAIN );
                $preparedEdit->newContent =
                        $slotsUpdate->isModifiedSlot( SlotRecord::MAIN )
@@ -1404,13 +1404,31 @@ class DerivedPageDataUpdater implements IDBAccessObject {
                $legacyUser = User::newFromIdentity( $this->user );
                $legacyRevision = new Revision( $this->revision );
 
-               $this->doParserCacheUpdate();
+               $userParserOptions = ParserOptions::newFromUser( $legacyUser );
+               // Decide whether to save the final canonical parser ouput based on the fact that
+               // users are typically redirected to viewing pages right after they edit those pages.
+               // Due to vary-revision-id, getting/saving that output here might require a reparse.
+               if ( $userParserOptions->matchesForCacheKey( $this->getCanonicalParserOptions() ) ) {
+                       // Whether getting the final output requires a reparse or not, the user will
+                       // need canonical output anyway, since that is what their parser options use.
+                       // A reparse now at least has the benefit of various warm process caches.
+                       $this->doParserCacheUpdate();
+               } else {
+                       // If the user does not have canonical parse options, then don't risk another parse
+                       // to make output they cannot use on the page refresh that typically occurs after
+                       // editing. Doing the parser output save post-send will still benefit *other* users.
+                       DeferredUpdates::addCallableUpdate( function () {
+                               $this->doParserCacheUpdate();
+                       } );
+               }
 
-               $this->doSecondaryDataUpdates( [
-                       // T52785 do not update any other pages on a null edit
-                       'recursive' => $this->options['changed'],
-                       'defer' => DeferredUpdates::POSTSEND,
-               ] );
+               // Defer the getCannonicalParserOutput() call triggered by getSecondaryDataUpdates()
+               DeferredUpdates::addCallableUpdate( function () {
+                       $this->doSecondaryDataUpdates( [
+                               // T52785 do not update any other pages on a null edit
+                               'recursive' => $this->options['changed']
+                       ] );
+               } );
 
                // TODO: MCR: check if *any* changed slot supports categories!
                if ( $this->rcWatchCategoryMembership
@@ -1430,8 +1448,11 @@ class DerivedPageDataUpdater implements IDBAccessObject {
                }
 
                // TODO: replace legacy hook! Use a listener on PageEventEmitter instead!
+               // @note: Extensions should *avoid* calling getCannonicalParserOutput() when using
+               // this hook whenever possible in order to avoid unnecessary additional parses.
                $editInfo = $this->getPreparedEdit();
-               Hooks::run( 'ArticleEditUpdates', [ &$wikiPage, &$editInfo, $this->options['changed'] ] );
+               Hooks::run( 'ArticleEditUpdates',
+                       [ &$wikiPage, &$editInfo, $this->options['changed'] ] );
 
                // TODO: replace legacy hook! Use a listener on PageEventEmitter instead!
                if ( Hooks::run( 'ArticleEditUpdatesDeleteFromRecentchanges', [ &$wikiPage ] ) ) {
@@ -1453,27 +1474,30 @@ class DerivedPageDataUpdater implements IDBAccessObject {
                        return;
                }
 
-               if ( $this->options['oldcountable'] === 'no-change' ||
-                       ( !$this->options['changed'] && !$this->options['moved'] )
-               ) {
-                       $good = 0;
-               } elseif ( $this->options['created'] ) {
-                       $good = (int)$this->isCountable();
-               } elseif ( $this->options['oldcountable'] !== null ) {
-                       $good = (int)$this->isCountable()
-                               - (int)$this->options['oldcountable'];
-               } elseif ( isset( $this->pageState['oldCountable'] ) ) {
-                       $good = (int)$this->isCountable()
-                               - (int)$this->pageState['oldCountable'];
-               } else {
-                       $good = 0;
-               }
-               $edits = $this->options['changed'] ? 1 : 0;
-               $pages = $this->options['created'] ? 1 : 0;
+               DeferredUpdates::addCallableUpdate( function () {
+                       if (
+                               $this->options['oldcountable'] === 'no-change' ||
+                               ( !$this->options['changed'] && !$this->options['moved'] )
+                       ) {
+                               $good = 0;
+                       } elseif ( $this->options['created'] ) {
+                               $good = (int)$this->isCountable();
+                       } elseif ( $this->options['oldcountable'] !== null ) {
+                               $good = (int)$this->isCountable()
+                                       - (int)$this->options['oldcountable'];
+                       } elseif ( isset( $this->pageState['oldCountable'] ) ) {
+                               $good = (int)$this->isCountable()
+                                       - (int)$this->pageState['oldCountable'];
+                       } else {
+                               $good = 0;
+                       }
+                       $edits = $this->options['changed'] ? 1 : 0;
+                       $pages = $this->options['created'] ? 1 : 0;
 
-               DeferredUpdates::addUpdate( SiteStatsUpdate::factory(
-                       [ 'edits' => $edits, 'articles' => $good, 'pages' => $pages ]
-               ) );
+                       DeferredUpdates::addUpdate( SiteStatsUpdate::factory(
+                               [ 'edits' => $edits, 'articles' => $good, 'pages' => $pages ]
+                       ) );
+               } );
 
                // TODO: make search infrastructure aware of slots!
                $mainSlot = $this->revision->getSlot( SlotRecord::MAIN );
@@ -1590,8 +1614,9 @@ class DerivedPageDataUpdater implements IDBAccessObject {
                                $update->setRevision( $legacyRevision );
                                $update->setTriggeringUser( $triggeringUser );
                        }
+
                        if ( $options['defer'] === false ) {
-                               if ( $options['transactionTicket'] !== null ) {
+                               if ( $update instanceof DataUpdate && $options['transactionTicket'] !== null ) {
                                        $update->setTransactionTicket( $options['transactionTicket'] );
                                }
                                $update->doUpdate();
index 3016e99..a14e339 100644 (file)
@@ -47,7 +47,7 @@ class NameTableStore {
        private $tableCache = null;
 
        /** @var bool|string */
-       private $wikiId = false;
+       private $domain = false;
 
        /** @var int */
        private $cacheTTL;
@@ -77,7 +77,7 @@ class NameTableStore {
         * @param string $nameField
         * @param callable|null $normalizationCallback Normalization to be applied to names before being
         * saved or queried. This should be a callback that accepts and returns a single string.
-        * @param bool|string $wikiId The ID of the target wiki database. Use false for the local wiki.
+        * @param bool|string $dbDomain Database domain ID. Use false for the local database domain.
         * @param callable|null $insertCallback Callback to change insert fields accordingly.
         * This parameter was introduced in 1.32
         */
@@ -89,7 +89,7 @@ class NameTableStore {
                $idField,
                $nameField,
                callable $normalizationCallback = null,
-               $wikiId = false,
+               $dbDomain = false,
                callable $insertCallback = null
        ) {
                $this->loadBalancer = $dbLoadBalancer;
@@ -99,7 +99,7 @@ class NameTableStore {
                $this->idField = $idField;
                $this->nameField = $nameField;
                $this->normalizationCallback = $normalizationCallback;
-               $this->wikiId = $wikiId;
+               $this->domain = $dbDomain;
                $this->cacheTTL = IExpiringStore::TTL_MONTH;
                $this->insertCallback = $insertCallback;
        }
@@ -111,7 +111,7 @@ class NameTableStore {
         * @return IDatabase
         */
        private function getDBConnection( $index, $flags = 0 ) {
-               return $this->loadBalancer->getConnection( $index, [], $this->wikiId, $flags );
+               return $this->loadBalancer->getConnection( $index, [], $this->domain, $flags );
        }
 
        /**
@@ -126,7 +126,7 @@ class NameTableStore {
                return $this->cache->makeGlobalKey(
                        'NameTableSqlStore',
                        $this->table,
-                       $this->loadBalancer->resolveDomainID( $this->wikiId )
+                       $this->loadBalancer->resolveDomainID( $this->domain )
                );
        }
 
@@ -183,11 +183,10 @@ class NameTableStore {
                                $searchResult = $id;
 
                                // As store returned an ID we know we inserted so delete from WAN cache
-                               $this->purgeWANCache(
-                                       function () {
-                                               $this->cache->delete( $this->getCacheKey() );
-                                       }
-                               );
+                               $dbw = $this->getDBConnection( DB_MASTER );
+                               $dbw->onTransactionPreCommitOrIdle( function () {
+                                       $this->cache->delete( $this->getCacheKey() );
+                               } );
                        }
                        $this->tableCache = $table;
                }
@@ -208,14 +207,11 @@ class NameTableStore {
         * @return string[] The freshly reloaded name map
         */
        public function reloadMap( $connFlags = 0 ) {
-               $this->tableCache = $this->loadTable(
-                       $this->getDBConnection( DB_MASTER, $connFlags )
-               );
-               $this->purgeWANCache(
-                       function () {
-                               $this->cache->reap( $this->getCacheKey(), INF );
-                       }
-               );
+               $dbw = $this->getDBConnection( DB_MASTER, $connFlags );
+               $this->tableCache = $this->loadTable( $dbw );
+               $dbw->onTransactionPreCommitOrIdle( function () {
+                       $this->cache->reap( $this->getCacheKey(), INF );
+               } );
 
                return $this->tableCache;
        }
@@ -342,22 +338,6 @@ class NameTableStore {
                return $table;
        }
 
-       /**
-        * Reap the WANCache entry for this table.
-        *
-        * @param callable $purgeCallback Callback to 'purge' the WAN cache
-        */
-       private function purgeWANCache( $purgeCallback ) {
-               // If the LB has no DB changes don't bother with onTransactionPreCommitOrIdle
-               if ( !$this->loadBalancer->hasOrMadeRecentMasterChanges() ) {
-                       $purgeCallback();
-                       return;
-               }
-
-               $this->getDBConnection( DB_MASTER )
-                       ->onTransactionPreCommitOrIdle( $purgeCallback, __METHOD__ );
-       }
-
        /**
         * Gets the table from the db
         *
diff --git a/includes/Storage/PageEditStash.php b/includes/Storage/PageEditStash.php
new file mode 100644 (file)
index 0000000..46f957f
--- /dev/null
@@ -0,0 +1,513 @@
+<?php
+/**
+ * Predictive edit preparation system for MediaWiki page.
+ *
+ * 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
+ */
+
+namespace MediaWiki\Storage;
+
+use ActorMigration;
+use BagOStuff;
+use Content;
+use Hooks;
+use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface;
+use ParserOutput;
+use Psr\Log\LoggerInterface;
+use stdClass;
+use Title;
+use User;
+use Wikimedia\Rdbms\ILoadBalancer;
+use Wikimedia\ScopedCallback;
+use WikiPage;
+
+/**
+ * Class for managing stashed edits used by the page updater classes
+ *
+ * @since 1.34
+ */
+class PageEditStash {
+       /** @var BagOStuff */
+       private $cache;
+       /** @var ILoadBalancer */
+       private $lb;
+       /** @var LoggerInterface */
+       private $logger;
+       /** @var StatsdDataFactoryInterface */
+       private $stats;
+       /** @var int */
+       private $initiator;
+
+       const ERROR_NONE = 'stashed';
+       const ERROR_PARSE = 'error_parse';
+       const ERROR_CACHE = 'error_cache';
+       const ERROR_UNCACHEABLE = 'uncacheable';
+       const ERROR_BUSY = 'busy';
+
+       const PRESUME_FRESH_TTL_SEC = 30;
+       const MAX_CACHE_TTL = 300; // 5 minutes
+       const MAX_SIGNATURE_TTL = 60;
+
+       const MAX_CACHE_RECENT = 2;
+
+       const INITIATOR_USER = 1;
+       const INITIATOR_JOB_OR_CLI = 2;
+
+       /**
+        * @param BagOStuff $cache
+        * @param ILoadBalancer $lb
+        * @param LoggerInterface $logger
+        * @param StatsdDataFactoryInterface $stats
+        * @param int $initiator Class INITIATOR__* constant
+        */
+       public function __construct(
+               BagOStuff $cache,
+               ILoadBalancer $lb,
+               LoggerInterface $logger,
+               StatsdDataFactoryInterface $stats,
+               $initiator
+       ) {
+               $this->cache = $cache;
+               $this->lb = $lb;
+               $this->logger = $logger;
+               $this->stats = $stats;
+               $this->initiator = $initiator;
+       }
+
+       /**
+        * @param WikiPage $page
+        * @param Content $content Edit content
+        * @param User $user
+        * @param string $summary Edit summary
+        * @return string Class ERROR_* constant
+        */
+       public function parseAndCache( WikiPage $page, Content $content, User $user, $summary ) {
+               $logger = $this->logger;
+
+               $title = $page->getTitle();
+               $key = $this->getStashKey( $title, $this->getContentHash( $content ), $user );
+               $fname = __METHOD__;
+
+               // Use the master DB to allow for fast blocking locks on the "save path" where this
+               // value might actually be used to complete a page edit. If the edit submission request
+               // happens before this edit stash requests finishes, then the submission will block until
+               // the stash request finishes parsing. For the lock acquisition below, there is not much
+               // need to duplicate parsing of the same content/user/summary bundle, so try to avoid
+               // blocking at all here.
+               $dbw = $this->lb->getConnection( DB_MASTER );
+               if ( !$dbw->lock( $key, $fname, 0 ) ) {
+                       // De-duplicate requests on the same key
+                       return self::ERROR_BUSY;
+               }
+               /** @noinspection PhpUnusedLocalVariableInspection */
+               $unlocker = new ScopedCallback( function () use ( $dbw, $key, $fname ) {
+                       $dbw->unlock( $key, $fname );
+               } );
+
+               $cutoffTime = time() - self::PRESUME_FRESH_TTL_SEC;
+
+               // Reuse any freshly build matching edit stash cache
+               $editInfo = $this->getStashValue( $key );
+               if ( $editInfo && wfTimestamp( TS_UNIX, $editInfo->timestamp ) >= $cutoffTime ) {
+                       $alreadyCached = true;
+               } else {
+                       $format = $content->getDefaultFormat();
+                       $editInfo = $page->prepareContentForEdit( $content, null, $user, $format, false );
+                       $editInfo->output->setCacheTime( $editInfo->timestamp );
+                       $alreadyCached = false;
+               }
+
+               $context = [ 'cachekey' => $key, 'title' => $title->getPrefixedText() ];
+
+               if ( $editInfo && $editInfo->output ) {
+                       // Let extensions add ParserOutput metadata or warm other caches
+                       Hooks::run( 'ParserOutputStashForEdit',
+                               [ $page, $content, $editInfo->output, $summary, $user ] );
+
+                       if ( $alreadyCached ) {
+                               $logger->debug( "Parser output for key '{cachekey}' already cached.", $context );
+
+                               return self::ERROR_NONE;
+                       }
+
+                       $code = $this->storeStashValue(
+                               $key,
+                               $editInfo->pstContent,
+                               $editInfo->output,
+                               $editInfo->timestamp,
+                               $user
+                       );
+
+                       if ( $code === true ) {
+                               $logger->debug( "Cached parser output for key '{cachekey}'.", $context );
+
+                               return self::ERROR_NONE;
+                       } elseif ( $code === 'uncacheable' ) {
+                               $logger->info(
+                                       "Uncacheable parser output for key '{cachekey}' [{code}].",
+                                       $context + [ 'code' => $code ]
+                               );
+
+                               return self::ERROR_UNCACHEABLE;
+                       } else {
+                               $logger->error(
+                                       "Failed to cache parser output for key '{cachekey}'.",
+                                       $context + [ 'code' => $code ]
+                               );
+
+                               return self::ERROR_CACHE;
+                       }
+               }
+
+               return self::ERROR_PARSE;
+       }
+
+       /**
+        * Check that a prepared edit is in cache and still up-to-date
+        *
+        * This method blocks if the prepared edit is already being rendered,
+        * waiting until rendering finishes before doing final validity checks.
+        *
+        * The cache is rejected if template or file changes are detected.
+        * Note that foreign template or file transclusions are not checked.
+        *
+        * This returns an object with the following fields:
+        *   - pstContent: the Content after pre-save-transform
+        *   - output: the ParserOutput instance
+        *   - timestamp: the timestamp of the parse
+        *   - edits: author edit count if they are logged in or NULL otherwise
+        *
+        * @param Title $title
+        * @param Content $content
+        * @param User $user User to get parser options from
+        * @return stdClass|bool Returns edit stash object or false on cache miss
+        */
+       public function checkCache( Title $title, Content $content, User $user ) {
+               if (
+                       // The context is not an HTTP POST request
+                       !$user->getRequest()->wasPosted() ||
+                       // The context is a CLI script or a job runner HTTP POST request
+                       $this->initiator !== self::INITIATOR_USER ||
+                       // The editor account is a known bot
+                       $user->isBot()
+               ) {
+                       // Avoid wasted queries and statsd pollution
+                       return false;
+               }
+
+               $logger = $this->logger;
+
+               $key = $this->getStashKey( $title, $this->getContentHash( $content ), $user );
+               $context = [
+                       'key' => $key,
+                       'title' => $title->getPrefixedText(),
+                       'user' => $user->getName()
+               ];
+
+               $editInfo = $this->getAndWaitForStashValue( $key );
+               if ( !is_object( $editInfo ) || !$editInfo->output ) {
+                       $this->incrStatsByContent( 'cache_misses.no_stash', $content );
+                       if ( $this->recentStashEntryCount( $user ) > 0 ) {
+                               $logger->info( "Empty cache for key '{key}' but not for user.", $context );
+                       } else {
+                               $logger->debug( "Empty cache for key '{key}'.", $context );
+                       }
+
+                       return false;
+               }
+
+               $age = time() - wfTimestamp( TS_UNIX, $editInfo->output->getCacheTime() );
+               $context['age'] = $age;
+
+               $isCacheUsable = true;
+               if ( $age <= self::PRESUME_FRESH_TTL_SEC ) {
+                       // Assume nothing changed in this time
+                       $this->incrStatsByContent( 'cache_hits.presumed_fresh', $content );
+                       $logger->debug( "Timestamp-based cache hit for key '{key}'.", $context );
+               } elseif ( $user->isAnon() ) {
+                       $lastEdit = $this->lastEditTime( $user );
+                       $cacheTime = $editInfo->output->getCacheTime();
+                       if ( $lastEdit < $cacheTime ) {
+                               // Logged-out user made no local upload/template edits in the meantime
+                               $this->incrStatsByContent( 'cache_hits.presumed_fresh', $content );
+                               $logger->debug( "Edit check based cache hit for key '{key}'.", $context );
+                       } else {
+                               $isCacheUsable = false;
+                               $this->incrStatsByContent( 'cache_misses.proven_stale', $content );
+                               $logger->info( "Stale cache for key '{key}' due to outside edits.", $context );
+                       }
+               } else {
+                       if ( $editInfo->edits === $user->getEditCount() ) {
+                               // Logged-in user made no local upload/template edits in the meantime
+                               $this->incrStatsByContent( 'cache_hits.presumed_fresh', $content );
+                               $logger->debug( "Edit count based cache hit for key '{key}'.", $context );
+                       } else {
+                               $isCacheUsable = false;
+                               $this->incrStatsByContent( 'cache_misses.proven_stale', $content );
+                               $logger->info( "Stale cache for key '{key}'due to outside edits.", $context );
+                       }
+               }
+
+               if ( !$isCacheUsable ) {
+                       return false;
+               }
+
+               if ( $editInfo->output->getFlag( 'vary-revision' ) ) {
+                       // This can be used for the initial parse, e.g. for filters or doEditContent(),
+                       // but a second parse will be triggered in doEditUpdates(). This is not optimal.
+                       $logger->info(
+                               "Cache for key '{key}' has vary_revision; post-insertion parse inevitable.",
+                               $context
+                       );
+               } elseif ( $editInfo->output->getFlag( 'vary-revision-id' ) ) {
+                       // Similar to the above if we didn't guess the ID correctly.
+                       $logger->debug(
+                               "Cache for key '{key}' has vary_revision_id; post-insertion parse possible.",
+                               $context
+                       );
+               }
+
+               return $editInfo;
+       }
+
+       /**
+        * @param string $subkey
+        * @param Content $content
+        */
+       private function incrStatsByContent( $subkey, Content $content ) {
+               $this->stats->increment( 'editstash.' . $subkey ); // overall for b/c
+               $this->stats->increment( 'editstash_by_model.' . $content->getModel() . '.' . $subkey );
+       }
+
+       /**
+        * @param string $key
+        * @return bool|stdClass
+        */
+       private function getAndWaitForStashValue( $key ) {
+               $editInfo = $this->getStashValue( $key );
+
+               if ( !$editInfo ) {
+                       $start = microtime( true );
+                       // We ignore user aborts and keep parsing. Block on any prior parsing
+                       // so as to use its results and make use of the time spent parsing.
+                       // Skip this logic if there no master connection in case this method
+                       // is called on an HTTP GET request for some reason.
+                       $dbw = $this->lb->getAnyOpenConnection( $this->lb->getWriterIndex() );
+                       if ( $dbw && $dbw->lock( $key, __METHOD__, 30 ) ) {
+                               $editInfo = $this->getStashValue( $key );
+                               $dbw->unlock( $key, __METHOD__ );
+                       }
+
+                       $timeMs = 1000 * max( 0, microtime( true ) - $start );
+                       $this->stats->timing( 'editstash.lock_wait_time', $timeMs );
+               }
+
+               return $editInfo;
+       }
+
+       /**
+        * @param string $textHash
+        * @return string|bool Text or false if missing
+        */
+       public function fetchInputText( $textHash ) {
+               $textKey = $this->cache->makeKey( 'stashedit', 'text', $textHash );
+
+               return $this->cache->get( $textKey );
+       }
+
+       /**
+        * @param string $text
+        * @param string $textHash
+        * @return bool Success
+        */
+       public function stashInputText( $text, $textHash ) {
+               $textKey = $this->cache->makeKey( 'stashedit', 'text', $textHash );
+
+               return $this->cache->set( $textKey, $text, self::MAX_CACHE_TTL );
+       }
+
+       /**
+        * @param User $user
+        * @return string|null TS_MW timestamp or null
+        */
+       private function lastEditTime( User $user ) {
+               $db = $this->lb->getConnection( DB_REPLICA );
+               $actorQuery = ActorMigration::newMigration()->getWhere( $db, 'rc_user', $user, false );
+               $time = $db->selectField(
+                       [ 'recentchanges' ] + $actorQuery['tables'],
+                       'MAX(rc_timestamp)',
+                       [ $actorQuery['conds'] ],
+                       __METHOD__,
+                       [],
+                       $actorQuery['joins']
+               );
+
+               return wfTimestampOrNull( TS_MW, $time );
+       }
+
+       /**
+        * Get hash of the content, factoring in model/format
+        *
+        * @param Content $content
+        * @return string
+        */
+       private function getContentHash( Content $content ) {
+               return sha1( implode( "\n", [
+                       $content->getModel(),
+                       $content->getDefaultFormat(),
+                       $content->serialize( $content->getDefaultFormat() )
+               ] ) );
+       }
+
+       /**
+        * Get the temporary prepared edit stash key for a user
+        *
+        * This key can be used for caching prepared edits provided:
+        *   - a) The $user was used for PST options
+        *   - b) The parser output was made from the PST using cannonical matching options
+        *
+        * @param Title $title
+        * @param string $contentHash Result of getContentHash()
+        * @param User $user User to get parser options from
+        * @return string
+        */
+       private function getStashKey( Title $title, $contentHash, User $user ) {
+               return $this->cache->makeKey(
+                       'stashed-edit-info',
+                       md5( $title->getPrefixedDBkey() ),
+                       // Account for the edit model/text
+                       $contentHash,
+                       // Account for user name related variables like signatures
+                       md5( $user->getId() . "\n" . $user->getName() )
+               );
+       }
+
+       /**
+        * @param string $hash
+        * @return string
+        */
+       private function getStashParserOutputKey( $hash ) {
+               return $this->cache->makeKey( 'stashed-edit-output', $hash );
+       }
+
+       /**
+        * @param string $key
+        * @return stdClass|bool Object map (pstContent,output,outputID,timestamp,edits) or false
+        */
+       private function getStashValue( $key ) {
+               $stashInfo = $this->cache->get( $key );
+               if ( !is_object( $stashInfo ) ) {
+                       return false;
+               }
+
+               $parserOutputKey = $this->getStashParserOutputKey( $stashInfo->outputID );
+               $parserOutput = $this->cache->get( $parserOutputKey );
+               if ( $parserOutput instanceof ParserOutput ) {
+                       $stashInfo->output = $parserOutput;
+
+                       return $stashInfo;
+               }
+
+               return false;
+       }
+
+       /**
+        * Build a value to store in memcached based on the PST content and parser output
+        *
+        * This makes a simple version of WikiPage::prepareContentForEdit() as stash info
+        *
+        * @param string $key
+        * @param Content $pstContent Pre-Save transformed content
+        * @param ParserOutput $parserOutput
+        * @param string $timestamp TS_MW
+        * @param User $user
+        * @return string|bool True or an error code
+        */
+       private function storeStashValue(
+               $key,
+               Content $pstContent,
+               ParserOutput $parserOutput,
+               $timestamp,
+               User $user
+       ) {
+               // If an item is renewed, mind the cache TTL determined by config and parser functions.
+               // Put an upper limit on the TTL for sanity to avoid extreme template/file staleness.
+               $age = time() - wfTimestamp( TS_UNIX, $parserOutput->getCacheTime() );
+               $ttl = min( $parserOutput->getCacheExpiry() - $age, self::MAX_CACHE_TTL );
+               // Avoid extremely stale user signature timestamps (T84843)
+               if ( $parserOutput->getFlag( 'user-signature' ) ) {
+                       $ttl = min( $ttl, self::MAX_SIGNATURE_TTL );
+               }
+
+               if ( $ttl <= 0 ) {
+                       return 'uncacheable'; // low TTL due to a tag, magic word, or signature?
+               }
+
+               // Store what is actually needed and split the output into another key (T204742)
+               $parserOutputID = md5( $key );
+               $stashInfo = (object)[
+                       'pstContent' => $pstContent,
+                       'outputID'   => $parserOutputID,
+                       'timestamp'  => $timestamp,
+                       'edits'      => $user->getEditCount()
+               ];
+
+               $ok = $this->cache->set( $key, $stashInfo, $ttl );
+               if ( $ok ) {
+                       $ok = $this->cache->set(
+                               $this->getStashParserOutputKey( $parserOutputID ),
+                               $parserOutput,
+                               $ttl
+                       );
+               }
+
+               if ( $ok ) {
+                       // These blobs can waste slots in low cardinality memcached slabs
+                       $this->pruneExcessStashedEntries( $user, $key );
+               }
+
+               return $ok ? true : 'store_error';
+       }
+
+       /**
+        * @param User $user
+        * @param string $newKey
+        */
+       private function pruneExcessStashedEntries( User $user, $newKey ) {
+               $key = $this->cache->makeKey( 'stash-edit-recent', sha1( $user->getName() ) );
+
+               $keyList = $this->cache->get( $key ) ?: [];
+               if ( count( $keyList ) >= self::MAX_CACHE_RECENT ) {
+                       $oldestKey = array_shift( $keyList );
+                       $this->cache->delete( $oldestKey );
+               }
+
+               $keyList[] = $newKey;
+               $this->cache->set( $key, $keyList, 2 * self::MAX_CACHE_TTL );
+       }
+
+       /**
+        * @param User $user
+        * @return int
+        */
+       private function recentStashEntryCount( User $user ) {
+               $key = $this->cache->makeKey( 'stash-edit-recent', sha1( $user->getName() ) );
+
+               return count( $this->cache->get( $key ) ?: [] );
+       }
+}
index 9213076..2052c44 100644 (file)
@@ -79,7 +79,7 @@ class StubObject {
         * @return bool True if $obj is not an instance of StubObject class.
         */
        public static function isRealObject( $obj ) {
-               return is_object( $obj ) && !$obj instanceof StubObject;
+               return is_object( $obj ) && !$obj instanceof self;
        }
 
        /**
@@ -91,7 +91,7 @@ class StubObject {
         * @return void
         */
        public static function unstub( &$obj ) {
-               if ( $obj instanceof StubObject ) {
+               if ( $obj instanceof self ) {
                        $obj = $obj->_unstub( 'unstub', 3 );
                }
        }
@@ -153,7 +153,7 @@ class StubObject {
        public function _unstub( $name = '_unstub', $level = 2 ) {
                static $recursionLevel = 0;
 
-               if ( !$GLOBALS[$this->global] instanceof StubObject ) {
+               if ( !$GLOBALS[$this->global] instanceof self ) {
                        return $GLOBALS[$this->global]; // already unstubbed.
                }
 
@@ -171,38 +171,3 @@ class StubObject {
                }
        }
 }
-
-/**
- * Stub object for the user language. Assigned to the $wgLang global.
- */
-class StubUserLang extends StubObject {
-
-       public function __construct() {
-               parent::__construct( 'wgLang' );
-       }
-
-       /**
-        * Call Language::findVariantLink after unstubbing $wgLang.
-        *
-        * This method is implemented with a full signature rather than relying on
-        * __call so that the pass-by-reference signature of the proxied method is
-        * honored.
-        *
-        * @param string &$link The name of the link
-        * @param Title &$nt The title object of the link
-        * @param bool $ignoreOtherCond To disable other conditions when
-        *   we need to transclude a template or update a category's link
-        */
-       public function findVariantLink( &$link, &$nt, $ignoreOtherCond = false ) {
-               global $wgLang;
-               $this->_unstub( 'findVariantLink', 3 );
-               $wgLang->findVariantLink( $link, $nt, $ignoreOtherCond );
-       }
-
-       /**
-        * @return Language
-        */
-       public function _newObject() {
-               return RequestContext::getMain()->getLanguage();
-       }
-}
diff --git a/includes/StubUserLang.php b/includes/StubUserLang.php
new file mode 100644 (file)
index 0000000..6f7bed6
--- /dev/null
@@ -0,0 +1,54 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * Stub object for the user language. Assigned to the $wgLang global.
+ */
+class StubUserLang extends StubObject {
+
+       public function __construct() {
+               parent::__construct( 'wgLang' );
+       }
+
+       /**
+        * Call Language::findVariantLink after unstubbing $wgLang.
+        *
+        * This method is implemented with a full signature rather than relying on
+        * __call so that the pass-by-reference signature of the proxied method is
+        * honored.
+        *
+        * @param string &$link The name of the link
+        * @param Title &$nt The title object of the link
+        * @param bool $ignoreOtherCond To disable other conditions when
+        *   we need to transclude a template or update a category's link
+        */
+       public function findVariantLink( &$link, &$nt, $ignoreOtherCond = false ) {
+               global $wgLang;
+               $this->_unstub( 'findVariantLink', 3 );
+               $wgLang->findVariantLink( $link, $nt, $ignoreOtherCond );
+       }
+
+       /**
+        * @return Language
+        */
+       public function _newObject() {
+               return RequestContext::getMain()->getLanguage();
+       }
+}
index 11a8e85..fd856be 100644 (file)
@@ -62,9 +62,9 @@ class TemplateParser {
         */
        public function enableRecursivePartials( $enable ) {
                if ( $enable ) {
-                       $this->compileFlags = $this->compileFlags | LightnCandy::FLAG_RUNTIMEPARTIAL;
+                       $this->compileFlags |= LightnCandy::FLAG_RUNTIMEPARTIAL;
                } else {
-                       $this->compileFlags = $this->compileFlags & ~LightnCandy::FLAG_RUNTIMEPARTIAL;
+                       $this->compileFlags &= ~LightnCandy::FLAG_RUNTIMEPARTIAL;
                }
        }
 
index d8aeb62..866f041 100644 (file)
@@ -22,6 +22,7 @@
  * @file
  */
 
+use MediaWiki\Permissions\PermissionManager;
 use Wikimedia\Rdbms\Database;
 use Wikimedia\Rdbms\IDatabase;
 use MediaWiki\Linker\LinkTarget;
@@ -53,6 +54,15 @@ class Title implements LinkTarget, IDBAccessObject {
         */
        const GAID_FOR_UPDATE = 1;
 
+       /**
+        * Flag for use with factory methods like newFromLinkTarget() that have
+        * a $forceClone parameter. If set, the method must return a new instance.
+        * Without this flag, some factory methods may return existing instances.
+        *
+        * @since 1.33
+        */
+       const NEW_CLONE = 'clone';
+
        /**
         * @name Private member variables
         * Please use the accessor functions instead.
@@ -231,27 +241,41 @@ class Title implements LinkTarget, IDBAccessObject {
        }
 
        /**
-        * Create a new Title from a TitleValue
+        * Returns a Title given a TitleValue.
+        * If the given TitleValue is already a Title instance, that instance is returned,
+        * unless $forceClone is "clone". If $forceClone is "clone" and the given TitleValue
+        * is already a Title instance, that instance is copied using the clone operator.
+        *
+        * @deprecated since 1.34, use newFromLinkTarget or castFromLinkTarget
         *
         * @param TitleValue $titleValue Assumed to be safe.
+        * @param string $forceClone set to NEW_CLONE to ensure a fresh instance is returned.
         *
         * @return Title
         */
-       public static function newFromTitleValue( TitleValue $titleValue ) {
-               return self::newFromLinkTarget( $titleValue );
+       public static function newFromTitleValue( TitleValue $titleValue, $forceClone = '' ) {
+               return self::newFromLinkTarget( $titleValue, $forceClone );
        }
 
        /**
-        * Create a new Title from a LinkTarget
+        * Returns a Title given a LinkTarget.
+        * If the given LinkTarget is already a Title instance, that instance is returned,
+        * unless $forceClone is "clone". If $forceClone is "clone" and the given LinkTarget
+        * is already a Title instance, that instance is copied using the clone operator.
         *
         * @param LinkTarget $linkTarget Assumed to be safe.
+        * @param string $forceClone set to NEW_CLONE to ensure a fresh instance is returned.
         *
         * @return Title
         */
-       public static function newFromLinkTarget( LinkTarget $linkTarget ) {
+       public static function newFromLinkTarget( LinkTarget $linkTarget, $forceClone = '' ) {
                if ( $linkTarget instanceof Title ) {
                        // Special case if it's already a Title object
-                       return $linkTarget;
+                       if ( $forceClone === self::NEW_CLONE ) {
+                               return clone $linkTarget;
+                       } else {
+                               return $linkTarget;
+                       }
                }
                return self::makeTitle(
                        $linkTarget->getNamespace(),
@@ -261,6 +285,17 @@ class Title implements LinkTarget, IDBAccessObject {
                );
        }
 
+       /**
+        * Same as newFromLinkTarget, but if passed null, returns null.
+        *
+        * @param LinkTarget|null $linkTarget Assumed to be safe (if not null).
+        *
+        * @return Title|null
+        */
+       public static function castFromLinkTarget( $linkTarget ) {
+               return $linkTarget ? self::newFromLinkTarget( $linkTarget ) : null;
+       }
+
        /**
         * Create a new Title from text, such as what one would find in a link. De-
         * codes any HTML entities in the text.
@@ -268,6 +303,10 @@ class Title implements LinkTarget, IDBAccessObject {
         * Title objects returned by this method are guaranteed to be valid, and
         * thus return true from the isValid() method.
         *
+        * @note The Title instance returned by this method is not guaranteed to be a fresh instance.
+        * It may instead be a cached instance created previously, with references to it remaining
+        * elsewhere.
+        *
         * @param string|int|null $text The link text; spaces, prefixes, and an
         *   initial ':' indicating the main namespace are accepted.
         * @param int $defaultNamespace The namespace to use if none is specified
@@ -302,6 +341,10 @@ class Title implements LinkTarget, IDBAccessObject {
         * Title objects returned by this method are guaranteed to be valid, and
         * thus return true from the isValid() method.
         *
+        * @note The Title instance returned by this method is not guaranteed to be a fresh instance.
+        * It may instead be a cached instance created previously, with references to it remaining
+        * elsewhere.
+        *
         * @see Title::newFromText
         *
         * @since 1.25
@@ -575,7 +618,7 @@ class Title implements LinkTarget, IDBAccessObject {
                // NOTE: ideally, this would just call makeTitle() and then isValid(),
                // but presently, that means more overhead on a potential performance hotspot.
 
-               if ( !MWNamespace::exists( $ns ) ) {
+               if ( !MediaWikiServices::getInstance()->getNamespaceInfo()->exists( $ns ) ) {
                        return null;
                }
 
@@ -593,11 +636,33 @@ class Title implements LinkTarget, IDBAccessObject {
        /**
         * Create a new Title for the Main Page
         *
-        * @return Title The new object
+        * This uses the 'mainpage' interface message, which could be specified in
+        * `$wgForceUIMsgAsContentMsg`. If that is the case, then calling this method
+        * will use the user language, which would involve initialising the session
+        * via `RequestContext::getMain()->getLanguage()`. For session-less endpoints,
+        * be sure to pass in a MessageLocalizer (such as your own RequestContext,
+        * or ResourceloaderContext) to prevent an error.
+        *
+        * @note The Title instance returned by this method is not guaranteed to be a fresh instance.
+        * It may instead be a cached instance created previously, with references to it remaining
+        * elsewhere.
+        *
+        * @param MessageLocalizer|null $localizer An optional context to use (since 1.34)
+        * @return Title
         */
-       public static function newMainPage() {
-               $title = self::newFromText( wfMessage( 'mainpage' )->inContentLanguage()->text() );
-               // Don't give fatal errors if the message is broken
+       public static function newMainPage( MessageLocalizer $localizer = null ) {
+               if ( $localizer ) {
+                       $msg = $localizer->msg( 'mainpage' );
+               } else {
+                       $msg = wfMessage( 'mainpage' );
+               }
+
+               $title = self::newFromText( $msg->inContentLanguage()->text() );
+
+               // Every page renders at least one link to the Main Page (e.g. sidebar).
+               // If the localised value is invalid, don't produce fatal errors that
+               // would make the wiki inaccessible (and hard to fix the invalid message).
+               // Gracefully fallback...
                if ( !$title ) {
                        $title = self::newFromText( 'Main Page' );
                }
@@ -699,6 +764,7 @@ class Title implements LinkTarget, IDBAccessObject {
                                // Allow unicode if a single high-bit character appears
                                $r0 = sprintf( '\x%02x', $ord0 );
                                $allowUnicode = true;
+                               // @phan-suppress-next-line PhanParamSuspiciousOrder false positive
                        } elseif ( strpos( '-\\[]^', $d0 ) !== false ) {
                                $r0 = '\\' . $d0;
                        } else {
@@ -754,7 +820,8 @@ class Title implements LinkTarget, IDBAccessObject {
                $canonicalNamespace = false
        ) {
                if ( $canonicalNamespace ) {
-                       $namespace = MWNamespace::getCanonicalName( $ns );
+                       $namespace = MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               getCanonicalName( $ns );
                } else {
                        $namespace = MediaWikiServices::getInstance()->getContentLanguage()->getNsText( $ns );
                }
@@ -796,13 +863,13 @@ class Title implements LinkTarget, IDBAccessObject {
         * @return bool
         */
        public function isValid() {
-               if ( !MWNamespace::exists( $this->mNamespace ) ) {
+               $services = MediaWikiServices::getInstance();
+               if ( !$services->getNamespaceInfo()->exists( $this->mNamespace ) ) {
                        return false;
                }
 
                try {
-                       $parser = MediaWikiServices::getInstance()->getTitleParser();
-                       $parser->parseTitle( $this->mDbkeyform, $this->mNamespace );
+                       $services->getTitleParser()->parseTitle( $this->mDbkeyform, $this->mNamespace );
                        return true;
                } catch ( MalformedTitleException $ex ) {
                        return false;
@@ -1020,7 +1087,8 @@ class Title implements LinkTarget, IDBAccessObject {
                if ( $this->isExternal() ) {
                        // This probably shouldn't even happen, except for interwiki transclusion.
                        // If possible, use the canonical name for the foreign namespace.
-                       $nsText = MWNamespace::getCanonicalName( $this->mNamespace );
+                       $nsText = MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               getCanonicalName( $this->mNamespace );
                        if ( $nsText !== false ) {
                                return $nsText;
                        }
@@ -1041,8 +1109,9 @@ class Title implements LinkTarget, IDBAccessObject {
         * @return string Namespace text
         */
        public function getSubjectNsText() {
-               return MediaWikiServices::getInstance()->getContentLanguage()->
-                       getNsText( MWNamespace::getSubject( $this->mNamespace ) );
+               $services = MediaWikiServices::getInstance();
+               return $services->getContentLanguage()->
+                       getNsText( $services->getNamespaceInfo()->getSubject( $this->mNamespace ) );
        }
 
        /**
@@ -1051,20 +1120,22 @@ class Title implements LinkTarget, IDBAccessObject {
         * @return string Namespace text
         */
        public function getTalkNsText() {
-               return MediaWikiServices::getInstance()->getContentLanguage()->
-                       getNsText( MWNamespace::getTalk( $this->mNamespace ) );
+               $services = MediaWikiServices::getInstance();
+               return $services->getContentLanguage()->
+                       getNsText( $services->getNamespaceInfo()->getTalk( $this->mNamespace ) );
        }
 
        /**
         * Can this title have a corresponding talk page?
         *
-        * @see MWNamespace::hasTalkNamespace
+        * @see NamespaceInfo::hasTalkNamespace
         * @since 1.30
         *
         * @return bool True if this title either is a talk page or can have a talk page associated.
         */
        public function canHaveTalkPage() {
-               return MWNamespace::hasTalkNamespace( $this->mNamespace );
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       hasTalkNamespace( $this->mNamespace );
        }
 
        /**
@@ -1082,7 +1153,8 @@ class Title implements LinkTarget, IDBAccessObject {
         * @return bool
         */
        public function isWatchable() {
-               return !$this->isExternal() && MWNamespace::isWatchable( $this->mNamespace );
+               return !$this->isExternal() && MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       isWatchable( $this->mNamespace );
        }
 
        /**
@@ -1143,7 +1215,8 @@ class Title implements LinkTarget, IDBAccessObject {
         * @since 1.19
         */
        public function inNamespace( $ns ) {
-               return MWNamespace::equals( $this->mNamespace, $ns );
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       equals( $this->mNamespace, $ns );
        }
 
        /**
@@ -1182,7 +1255,8 @@ class Title implements LinkTarget, IDBAccessObject {
         * @return bool
         */
        public function hasSubjectNamespace( $ns ) {
-               return MWNamespace::subjectEquals( $this->mNamespace, $ns );
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       subjectEquals( $this->mNamespace, $ns );
        }
 
        /**
@@ -1193,7 +1267,8 @@ class Title implements LinkTarget, IDBAccessObject {
         * @return bool
         */
        public function isContentPage() {
-               return MWNamespace::isContent( $this->mNamespace );
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       isContent( $this->mNamespace );
        }
 
        /**
@@ -1203,7 +1278,10 @@ class Title implements LinkTarget, IDBAccessObject {
         * @return bool
         */
        public function isMovable() {
-               if ( !MWNamespace::isMovable( $this->mNamespace ) || $this->isExternal() ) {
+               if (
+                       !MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               isMovable( $this->mNamespace ) || $this->isExternal()
+               ) {
                        // Interwiki title or immovable namespace. Hooks don't get to override here
                        return false;
                }
@@ -1233,7 +1311,8 @@ class Title implements LinkTarget, IDBAccessObject {
         * @return bool
         */
        public function isSubpage() {
-               return MWNamespace::hasSubpages( $this->mNamespace )
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       hasSubpages( $this->mNamespace )
                        ? strpos( $this->getText(), '/' ) !== false
                        : false;
        }
@@ -1429,16 +1508,19 @@ class Title implements LinkTarget, IDBAccessObject {
         * @return bool
         */
        public function isTalkPage() {
-               return MWNamespace::isTalk( $this->mNamespace );
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       isTalk( $this->mNamespace );
        }
 
        /**
         * Get a Title object associated with the talk page of this article
         *
+        * @deprecated since 1.34, use NamespaceInfo::getTalkPage
         * @return Title The object for the talk page
         */
        public function getTalkPage() {
-               return self::makeTitle( MWNamespace::getTalk( $this->mNamespace ), $this->mDbkeyform );
+               return self::castFromLinkTarget(
+                       MediaWikiServices::getInstance()->getNamespaceInfo()->getTalkPage( $this ) );
        }
 
        /**
@@ -1462,37 +1544,26 @@ class Title implements LinkTarget, IDBAccessObject {
         * Get a title object associated with the subject page of this
         * talk page
         *
+        * @deprecated since 1.34, use NamespaceInfo::getSubjectPage
         * @return Title The object for the subject page
         */
        public function getSubjectPage() {
-               // Is this the same title?
-               $subjectNS = MWNamespace::getSubject( $this->mNamespace );
-               if ( $this->mNamespace == $subjectNS ) {
-                       return $this;
-               }
-               return self::makeTitle( $subjectNS, $this->mDbkeyform );
+               return self::castFromLinkTarget(
+                       MediaWikiServices::getInstance()->getNamespaceInfo()->getSubjectPage( $this ) );
        }
 
        /**
         * Get the other title for this page, if this is a subject page
         * get the talk page, if it is a subject page get the talk page
         *
+        * @deprecated since 1.34, use NamespaceInfo::getAssociatedPage
         * @since 1.25
         * @throws MWException If the page doesn't have an other page
         * @return Title
         */
        public function getOtherPage() {
-               if ( $this->isSpecialPage() ) {
-                       throw new MWException( 'Special pages cannot have other pages' );
-               }
-               if ( $this->isTalkPage() ) {
-                       return $this->getSubjectPage();
-               } else {
-                       if ( !$this->canHaveTalkPage() ) {
-                               throw new MWException( "{$this->getPrefixedText()} does not have an other page" );
-                       }
-                       return $this->getTalkPage();
-               }
+               return self::castFromLinkTarget(
+                       MediaWikiServices::getInstance()->getNamespaceInfo()->getAssociatedPage( $this ) );
        }
 
        /**
@@ -1667,7 +1738,10 @@ class Title implements LinkTarget, IDBAccessObject {
         * @since 1.20
         */
        public function getRootText() {
-               if ( !MWNamespace::hasSubpages( $this->mNamespace ) ) {
+               if (
+                       !MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               hasSubpages( $this->mNamespace )
+               ) {
                        return $this->getText();
                }
 
@@ -1702,16 +1776,21 @@ class Title implements LinkTarget, IDBAccessObject {
         * @return string Base name
         */
        public function getBaseText() {
-               if ( !MWNamespace::hasSubpages( $this->mNamespace ) ) {
-                       return $this->getText();
+               $text = $this->getText();
+               if (
+                       !MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               hasSubpages( $this->mNamespace )
+               ) {
+                       return $text;
                }
 
-               $parts = explode( '/', $this->getText() );
-               # Don't discard the real title if there's no subpage involved
-               if ( count( $parts ) > 1 ) {
-                       unset( $parts[count( $parts ) - 1] );
+               $lastSlashPos = strrpos( $text, '/' );
+               // Don't discard the real title if there's no subpage involved
+               if ( $lastSlashPos === false ) {
+                       return $text;
                }
-               return implode( '/', $parts );
+
+               return substr( $text, 0, $lastSlashPos );
        }
 
        /**
@@ -1742,7 +1821,10 @@ class Title implements LinkTarget, IDBAccessObject {
         * @return string Subpage name
         */
        public function getSubpageText() {
-               if ( !MWNamespace::hasSubpages( $this->mNamespace ) ) {
+               if (
+                       !MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               hasSubpages( $this->mNamespace )
+               ) {
                        return $this->mTextform;
                }
                $parts = explode( '/', $this->mTextform );
@@ -2028,8 +2110,8 @@ class Title implements LinkTarget, IDBAccessObject {
         * protocol-relative, the URL will be expanded to http://
         *
         * @see self::getLocalURL for the arguments.
-        * @param string $query
-        * @param string|bool $query2
+        * @param string|string[] $query
+        * @param string|bool $query2 Deprecated
         * @return string The URL
         */
        public function getInternalURL( $query = '', $query2 = false ) {
@@ -2051,8 +2133,8 @@ class Title implements LinkTarget, IDBAccessObject {
         * NOTE: Unlike getInternalURL(), the canonical URL includes the fragment
         *
         * @see self::getLocalURL for the arguments.
-        * @param string $query
-        * @param string|bool $query2
+        * @param string|string[] $query
+        * @param string|bool $query2 Deprecated
         * @return string The URL
         * @since 1.18
         */
@@ -2091,7 +2173,13 @@ class Title implements LinkTarget, IDBAccessObject {
         *
         * @param string $action Action that permission needs to be checked for
         * @param User|null $user User to check (since 1.19); $wgUser will be used if not provided.
+        *
         * @return bool
+        * @throws Exception
+        *
+        * @deprecated since 1.33,
+        * use MediaWikiServices::getInstance()->getPermissionManager()->quickUserCan(..) instead
+        *
         */
        public function quickUserCan( $action, $user = null ) {
                return $this->userCan( $action, $user, false );
@@ -2104,15 +2192,29 @@ class Title implements LinkTarget, IDBAccessObject {
         * @param User|null $user User to check (since 1.19); $wgUser will be used if not
         *   provided.
         * @param string $rigor Same format as Title::getUserPermissionsErrors()
+        *
         * @return bool
+        * @throws Exception
+        *
+        * @deprecated since 1.33,
+        * use MediaWikiServices::getInstance()->getPermissionManager()->userCan(..) instead
+        *
         */
-       public function userCan( $action, $user = null, $rigor = 'secure' ) {
+       public function userCan( $action, $user = null, $rigor = PermissionManager::RIGOR_SECURE ) {
                if ( !$user instanceof User ) {
                        global $wgUser;
                        $user = $wgUser;
                }
 
-               return !count( $this->getUserPermissionsErrorsInternal( $action, $user, $rigor, true ) );
+               // TODO: this is for b/c, eventually will be removed
+               if ( $rigor === true ) {
+                       $rigor = PermissionManager::RIGOR_SECURE; // b/c
+               } elseif ( $rigor === false ) {
+                       $rigor = PermissionManager::RIGOR_QUICK; // b/c
+               }
+
+               return MediaWikiServices::getInstance()->getPermissionManager()
+                       ->userCan( $action, $user, $this, $rigor );
        }
 
        /**
@@ -2128,99 +2230,26 @@ class Title implements LinkTarget, IDBAccessObject {
         *   - secure : does cheap and expensive checks, using the master as needed
         * @param array $ignoreErrors Array of Strings Set this to a list of message keys
         *   whose corresponding errors may be ignored.
+        *
         * @return array Array of arrays of the arguments to wfMessage to explain permissions problems.
-        */
-       public function getUserPermissionsErrors(
-               $action, $user, $rigor = 'secure', $ignoreErrors = []
-       ) {
-               $errors = $this->getUserPermissionsErrorsInternal( $action, $user, $rigor );
-
-               // Remove the errors being ignored.
-               foreach ( $errors as $index => $error ) {
-                       $errKey = is_array( $error ) ? $error[0] : $error;
-
-                       if ( in_array( $errKey, $ignoreErrors ) ) {
-                               unset( $errors[$index] );
-                       }
-                       if ( $errKey instanceof MessageSpecifier && in_array( $errKey->getKey(), $ignoreErrors ) ) {
-                               unset( $errors[$index] );
-                       }
-               }
-
-               return $errors;
-       }
-
-       /**
-        * Permissions checks that fail most often, and which are easiest to test.
+        * @throws Exception
         *
-        * @param string $action The action to check
-        * @param User $user User to check
-        * @param array $errors List of current errors
-        * @param string $rigor Same format as Title::getUserPermissionsErrors()
-        * @param bool $short Short circuit on first error
+        * @deprecated since 1.33,
+        * use MediaWikiServices::getInstance()->getPermissionManager()->getUserPermissionsErrors()
         *
-        * @return array List of errors
         */
-       private function checkQuickPermissions( $action, $user, $errors, $rigor, $short ) {
-               if ( !Hooks::run( 'TitleQuickPermissions',
-                       [ $this, $user, $action, &$errors, ( $rigor !== 'quick' ), $short ] )
-               ) {
-                       return $errors;
-               }
-
-               if ( $action == 'create' ) {
-                       if (
-                               ( $this->isTalkPage() && !$user->isAllowed( 'createtalk' ) ) ||
-                               ( !$this->isTalkPage() && !$user->isAllowed( 'createpage' ) )
-                       ) {
-                               $errors[] = $user->isAnon() ? [ 'nocreatetext' ] : [ 'nocreate-loggedin' ];
-                       }
-               } elseif ( $action == 'move' ) {
-                       if ( !$user->isAllowed( 'move-rootuserpages' )
-                                       && $this->mNamespace == NS_USER && !$this->isSubpage() ) {
-                               // Show user page-specific message only if the user can move other pages
-                               $errors[] = [ 'cant-move-user-page' ];
-                       }
-
-                       // Check if user is allowed to move files if it's a file
-                       if ( $this->mNamespace == NS_FILE && !$user->isAllowed( 'movefile' ) ) {
-                               $errors[] = [ 'movenotallowedfile' ];
-                       }
-
-                       // Check if user is allowed to move category pages if it's a category page
-                       if ( $this->mNamespace == NS_CATEGORY && !$user->isAllowed( 'move-categorypages' ) ) {
-                               $errors[] = [ 'cant-move-category-page' ];
-                       }
-
-                       if ( !$user->isAllowed( 'move' ) ) {
-                               // User can't move anything
-                               $userCanMove = User::groupHasPermission( 'user', 'move' );
-                               $autoconfirmedCanMove = User::groupHasPermission( 'autoconfirmed', 'move' );
-                               if ( $user->isAnon() && ( $userCanMove || $autoconfirmedCanMove ) ) {
-                                       // custom message if logged-in users without any special rights can move
-                                       $errors[] = [ 'movenologintext' ];
-                               } else {
-                                       $errors[] = [ 'movenotallowed' ];
-                               }
-                       }
-               } elseif ( $action == 'move-target' ) {
-                       if ( !$user->isAllowed( 'move' ) ) {
-                               // User can't move anything
-                               $errors[] = [ 'movenotallowed' ];
-                       } elseif ( !$user->isAllowed( 'move-rootuserpages' )
-                                       && $this->mNamespace == NS_USER && !$this->isSubpage() ) {
-                               // Show user page-specific message only if the user can move other pages
-                               $errors[] = [ 'cant-move-to-user-page' ];
-                       } elseif ( !$user->isAllowed( 'move-categorypages' )
-                                       && $this->mNamespace == NS_CATEGORY ) {
-                               // Show category page-specific message only if the user can move other pages
-                               $errors[] = [ 'cant-move-to-category-page' ];
-                       }
-               } elseif ( !$user->isAllowed( $action ) ) {
-                       $errors[] = $this->missingPermissionError( $action, $short );
+       public function getUserPermissionsErrors(
+               $action, $user, $rigor = PermissionManager::RIGOR_SECURE, $ignoreErrors = []
+       ) {
+               // TODO: this is for b/c, eventually will be removed
+               if ( $rigor === true ) {
+                       $rigor = PermissionManager::RIGOR_SECURE; // b/c
+               } elseif ( $rigor === false ) {
+                       $rigor = PermissionManager::RIGOR_QUICK; // b/c
                }
 
-               return $errors;
+               return MediaWikiServices::getInstance()->getPermissionManager()
+                       ->getPermissionErrors( $action, $user, $this, $rigor, $ignoreErrors );
        }
 
        /**
@@ -2251,582 +2280,6 @@ class Title implements LinkTarget, IDBAccessObject {
                return $errors;
        }
 
-       /**
-        * Check various permission hooks
-        *
-        * @param string $action The action to check
-        * @param User $user User to check
-        * @param array $errors List of current errors
-        * @param string $rigor Same format as Title::getUserPermissionsErrors()
-        * @param bool $short Short circuit on first error
-        *
-        * @return array List of errors
-        */
-       private function checkPermissionHooks( $action, $user, $errors, $rigor, $short ) {
-               // Use getUserPermissionsErrors instead
-               $result = '';
-               // Avoid PHP 7.1 warning from passing $this by reference
-               $titleRef = $this;
-               if ( !Hooks::run( 'userCan', [ &$titleRef, &$user, $action, &$result ] ) ) {
-                       return $result ? [] : [ [ 'badaccess-group0' ] ];
-               }
-               // Check getUserPermissionsErrors hook
-               // Avoid PHP 7.1 warning from passing $this by reference
-               $titleRef = $this;
-               if ( !Hooks::run( 'getUserPermissionsErrors', [ &$titleRef, &$user, $action, &$result ] ) ) {
-                       $errors = $this->resultToError( $errors, $result );
-               }
-               // Check getUserPermissionsErrorsExpensive hook
-               if (
-                       $rigor !== 'quick'
-                       && !( $short && count( $errors ) > 0 )
-                       && !Hooks::run( 'getUserPermissionsErrorsExpensive', [ &$titleRef, &$user, $action, &$result ] )
-               ) {
-                       $errors = $this->resultToError( $errors, $result );
-               }
-
-               return $errors;
-       }
-
-       /**
-        * Check permissions on special pages & namespaces
-        *
-        * @param string $action The action to check
-        * @param User $user User to check
-        * @param array $errors List of current errors
-        * @param string $rigor Same format as Title::getUserPermissionsErrors()
-        * @param bool $short Short circuit on first error
-        *
-        * @return array List of errors
-        */
-       private function checkSpecialsAndNSPermissions( $action, $user, $errors, $rigor, $short ) {
-               # Only 'createaccount' can be performed on special pages,
-               # which don't actually exist in the DB.
-               if ( $this->isSpecialPage() && $action !== 'createaccount' ) {
-                       $errors[] = [ 'ns-specialprotected' ];
-               }
-
-               # Check $wgNamespaceProtection for restricted namespaces
-               if ( $this->isNamespaceProtected( $user ) ) {
-                       $ns = $this->mNamespace == NS_MAIN ?
-                               wfMessage( 'nstab-main' )->text() : $this->getNsText();
-                       $errors[] = $this->mNamespace == NS_MEDIAWIKI ?
-                               [ 'protectedinterface', $action ] : [ 'namespaceprotected', $ns, $action ];
-               }
-
-               return $errors;
-       }
-
-       /**
-        * Check sitewide CSS/JSON/JS permissions
-        *
-        * @param string $action The action to check
-        * @param User $user User to check
-        * @param array $errors List of current errors
-        * @param string $rigor Same format as Title::getUserPermissionsErrors()
-        * @param bool $short Short circuit on first error
-        *
-        * @return array List of errors
-        */
-       private function checkSiteConfigPermissions( $action, $user, $errors, $rigor, $short ) {
-               if ( $action != 'patrol' ) {
-                       $error = null;
-                       // Sitewide CSS/JSON/JS changes, like all NS_MEDIAWIKI changes, also require the
-                       // editinterface right. That's implemented as a restriction so no check needed here.
-                       if ( $this->isSiteCssConfigPage() && !$user->isAllowed( 'editsitecss' ) ) {
-                               $error = [ 'sitecssprotected', $action ];
-                       } elseif ( $this->isSiteJsonConfigPage() && !$user->isAllowed( 'editsitejson' ) ) {
-                               $error = [ 'sitejsonprotected', $action ];
-                       } elseif ( $this->isSiteJsConfigPage() && !$user->isAllowed( 'editsitejs' ) ) {
-                               $error = [ 'sitejsprotected', $action ];
-                       } elseif ( $this->isRawHtmlMessage() ) {
-                               // Raw HTML can be used to deploy CSS or JS so require rights for both.
-                               if ( !$user->isAllowed( 'editsitejs' ) ) {
-                                       $error = [ 'sitejsprotected', $action ];
-                               } elseif ( !$user->isAllowed( 'editsitecss' ) ) {
-                                       $error = [ 'sitecssprotected', $action ];
-                               }
-                       }
-
-                       if ( $error ) {
-                               if ( $user->isAllowed( 'editinterface' ) ) {
-                                       // Most users / site admins will probably find out about the new, more restrictive
-                                       // permissions by failing to edit something. Give them more info.
-                                       // TODO remove this a few release cycles after 1.32
-                                       $error = [ 'interfaceadmin-info', wfMessage( $error[0], $error[1] ) ];
-                               }
-                               $errors[] = $error;
-                       }
-               }
-
-               return $errors;
-       }
-
-       /**
-        * Check CSS/JSON/JS sub-page permissions
-        *
-        * @param string $action The action to check
-        * @param User $user User to check
-        * @param array $errors List of current errors
-        * @param string $rigor Same format as Title::getUserPermissionsErrors()
-        * @param bool $short Short circuit on first error
-        *
-        * @return array List of errors
-        */
-       private function checkUserConfigPermissions( $action, $user, $errors, $rigor, $short ) {
-               # Protect css/json/js subpages of user pages
-               # XXX: this might be better using restrictions
-
-               if ( $action === 'patrol' ) {
-                       return $errors;
-               }
-
-               if ( preg_match( '/^' . preg_quote( $user->getName(), '/' ) . '\//', $this->mTextform ) ) {
-                       // Users need editmyuser* to edit their own CSS/JSON/JS subpages.
-                       if (
-                               $this->isUserCssConfigPage()
-                               && !$user->isAllowedAny( 'editmyusercss', 'editusercss' )
-                       ) {
-                               $errors[] = [ 'mycustomcssprotected', $action ];
-                       } elseif (
-                               $this->isUserJsonConfigPage()
-                               && !$user->isAllowedAny( 'editmyuserjson', 'edituserjson' )
-                       ) {
-                               $errors[] = [ 'mycustomjsonprotected', $action ];
-                       } elseif (
-                               $this->isUserJsConfigPage()
-                               && !$user->isAllowedAny( 'editmyuserjs', 'edituserjs' )
-                       ) {
-                               $errors[] = [ 'mycustomjsprotected', $action ];
-                       }
-               } else {
-                       // Users need editmyuser* to edit their own CSS/JSON/JS subpages, except for
-                       // deletion/suppression which cannot be used for attacks and we want to avoid the
-                       // situation where an unprivileged user can post abusive content on their subpages
-                       // and only very highly privileged users could remove it.
-                       if ( !in_array( $action, [ 'delete', 'deleterevision', 'suppressrevision' ], true ) ) {
-                               if (
-                                       $this->isUserCssConfigPage()
-                                       && !$user->isAllowed( 'editusercss' )
-                               ) {
-                                       $errors[] = [ 'customcssprotected', $action ];
-                               } elseif (
-                                       $this->isUserJsonConfigPage()
-                                       && !$user->isAllowed( 'edituserjson' )
-                               ) {
-                                       $errors[] = [ 'customjsonprotected', $action ];
-                               } elseif (
-                                       $this->isUserJsConfigPage()
-                                       && !$user->isAllowed( 'edituserjs' )
-                               ) {
-                                       $errors[] = [ 'customjsprotected', $action ];
-                               }
-                       }
-               }
-
-               return $errors;
-       }
-
-       /**
-        * Check against page_restrictions table requirements on this
-        * page. The user must possess all required rights for this
-        * action.
-        *
-        * @param string $action The action to check
-        * @param User $user User to check
-        * @param array $errors List of current errors
-        * @param string $rigor Same format as Title::getUserPermissionsErrors()
-        * @param bool $short Short circuit on first error
-        *
-        * @return array List of errors
-        */
-       private function checkPageRestrictions( $action, $user, $errors, $rigor, $short ) {
-               foreach ( $this->getRestrictions( $action ) as $right ) {
-                       // Backwards compatibility, rewrite sysop -> editprotected
-                       if ( $right == 'sysop' ) {
-                               $right = 'editprotected';
-                       }
-                       // Backwards compatibility, rewrite autoconfirmed -> editsemiprotected
-                       if ( $right == 'autoconfirmed' ) {
-                               $right = 'editsemiprotected';
-                       }
-                       if ( $right == '' ) {
-                               continue;
-                       }
-                       if ( !$user->isAllowed( $right ) ) {
-                               $errors[] = [ 'protectedpagetext', $right, $action ];
-                       } elseif ( $this->mCascadeRestriction && !$user->isAllowed( 'protect' ) ) {
-                               $errors[] = [ 'protectedpagetext', 'protect', $action ];
-                       }
-               }
-
-               return $errors;
-       }
-
-       /**
-        * Check restrictions on cascading pages.
-        *
-        * @param string $action The action to check
-        * @param User $user User to check
-        * @param array $errors List of current errors
-        * @param string $rigor Same format as Title::getUserPermissionsErrors()
-        * @param bool $short Short circuit on first error
-        *
-        * @return array List of errors
-        */
-       private function checkCascadingSourcesRestrictions( $action, $user, $errors, $rigor, $short ) {
-               if ( $rigor !== 'quick' && !$this->isUserConfigPage() ) {
-                       # We /could/ use the protection level on the source page, but it's
-                       # fairly ugly as we have to establish a precedence hierarchy for pages
-                       # included by multiple cascade-protected pages. So just restrict
-                       # it to people with 'protect' permission, as they could remove the
-                       # protection anyway.
-                       list( $cascadingSources, $restrictions ) = $this->getCascadeProtectionSources();
-                       # Cascading protection depends on more than this page...
-                       # Several cascading protected pages may include this page...
-                       # Check each cascading level
-                       # This is only for protection restrictions, not for all actions
-                       if ( isset( $restrictions[$action] ) ) {
-                               foreach ( $restrictions[$action] as $right ) {
-                                       // Backwards compatibility, rewrite sysop -> editprotected
-                                       if ( $right == 'sysop' ) {
-                                               $right = 'editprotected';
-                                       }
-                                       // Backwards compatibility, rewrite autoconfirmed -> editsemiprotected
-                                       if ( $right == 'autoconfirmed' ) {
-                                               $right = 'editsemiprotected';
-                                       }
-                                       if ( $right != '' && !$user->isAllowedAll( 'protect', $right ) ) {
-                                               $pages = '';
-                                               foreach ( $cascadingSources as $page ) {
-                                                       $pages .= '* [[:' . $page->getPrefixedText() . "]]\n";
-                                               }
-                                               $errors[] = [ 'cascadeprotected', count( $cascadingSources ), $pages, $action ];
-                                       }
-                               }
-                       }
-               }
-
-               return $errors;
-       }
-
-       /**
-        * Check action permissions not already checked in checkQuickPermissions
-        *
-        * @param string $action The action to check
-        * @param User $user User to check
-        * @param array $errors List of current errors
-        * @param string $rigor Same format as Title::getUserPermissionsErrors()
-        * @param bool $short Short circuit on first error
-        *
-        * @return array List of errors
-        */
-       private function checkActionPermissions( $action, $user, $errors, $rigor, $short ) {
-               global $wgDeleteRevisionsLimit, $wgLang;
-
-               if ( $action == 'protect' ) {
-                       if ( count( $this->getUserPermissionsErrorsInternal( 'edit', $user, $rigor, true ) ) ) {
-                               // If they can't edit, they shouldn't protect.
-                               $errors[] = [ 'protect-cantedit' ];
-                       }
-               } elseif ( $action == 'create' ) {
-                       $title_protection = $this->getTitleProtection();
-                       if ( $title_protection ) {
-                               if ( $title_protection['permission'] == ''
-                                       || !$user->isAllowed( $title_protection['permission'] )
-                               ) {
-                                       $errors[] = [
-                                               'titleprotected',
-                                               User::whoIs( $title_protection['user'] ),
-                                               $title_protection['reason']
-                                       ];
-                               }
-                       }
-               } elseif ( $action == 'move' ) {
-                       // Check for immobile pages
-                       if ( !MWNamespace::isMovable( $this->mNamespace ) ) {
-                               // Specific message for this case
-                               $errors[] = [ 'immobile-source-namespace', $this->getNsText() ];
-                       } elseif ( !$this->isMovable() ) {
-                               // Less specific message for rarer cases
-                               $errors[] = [ 'immobile-source-page' ];
-                       }
-               } elseif ( $action == 'move-target' ) {
-                       if ( !MWNamespace::isMovable( $this->mNamespace ) ) {
-                               $errors[] = [ 'immobile-target-namespace', $this->getNsText() ];
-                       } elseif ( !$this->isMovable() ) {
-                               $errors[] = [ 'immobile-target-page' ];
-                       }
-               } elseif ( $action == 'delete' ) {
-                       $tempErrors = $this->checkPageRestrictions( 'edit', $user, [], $rigor, true );
-                       if ( !$tempErrors ) {
-                               $tempErrors = $this->checkCascadingSourcesRestrictions( 'edit',
-                                       $user, $tempErrors, $rigor, true );
-                       }
-                       if ( $tempErrors ) {
-                               // If protection keeps them from editing, they shouldn't be able to delete.
-                               $errors[] = [ 'deleteprotected' ];
-                       }
-                       if ( $rigor !== 'quick' && $wgDeleteRevisionsLimit
-                               && !$this->userCan( 'bigdelete', $user ) && $this->isBigDeletion()
-                       ) {
-                               $errors[] = [ 'delete-toobig', $wgLang->formatNum( $wgDeleteRevisionsLimit ) ];
-                       }
-               } elseif ( $action === 'undelete' ) {
-                       if ( count( $this->getUserPermissionsErrorsInternal( 'edit', $user, $rigor, true ) ) ) {
-                               // Undeleting implies editing
-                               $errors[] = [ 'undelete-cantedit' ];
-                       }
-                       if ( !$this->exists()
-                               && count( $this->getUserPermissionsErrorsInternal( 'create', $user, $rigor, true ) )
-                       ) {
-                               // Undeleting where nothing currently exists implies creating
-                               $errors[] = [ 'undelete-cantcreate' ];
-                       }
-               }
-               return $errors;
-       }
-
-       /**
-        * Check that the user isn't blocked from editing.
-        *
-        * @param string $action The action to check
-        * @param User $user User to check
-        * @param array $errors List of current errors
-        * @param string $rigor Same format as Title::getUserPermissionsErrors()
-        * @param bool $short Short circuit on first error
-        *
-        * @return array List of errors
-        */
-       private function checkUserBlock( $action, $user, $errors, $rigor, $short ) {
-               global $wgEmailConfirmToEdit, $wgBlockDisablesLogin;
-               // Account creation blocks handled at userlogin.
-               // Unblocking handled in SpecialUnblock
-               if ( $rigor === 'quick' || in_array( $action, [ 'createaccount', 'unblock' ] ) ) {
-                       return $errors;
-               }
-
-               // Optimize for a very common case
-               if ( $action === 'read' && !$wgBlockDisablesLogin ) {
-                       return $errors;
-               }
-
-               if ( $wgEmailConfirmToEdit
-                       && !$user->isEmailConfirmed()
-                       && $action === 'edit'
-               ) {
-                       $errors[] = [ 'confirmedittext' ];
-               }
-
-               $useReplica = ( $rigor !== 'secure' );
-               $block = $user->getBlock( $useReplica );
-
-               // If the user does not have a block, or the block they do have explicitly
-               // allows the action (like "read" or "upload").
-               if ( !$block || $block->appliesToRight( $action ) === false ) {
-                       return $errors;
-               }
-
-               // Determine if the user is blocked from this action on this page.
-               // What gets passed into this method is a user right, not an action name.
-               // There is no way to instantiate an action by restriction. However, this
-               // will get the action where the restriction is the same. This may result
-               // in actions being blocked that shouldn't be.
-               $actionObj = null;
-               if ( Action::exists( $action ) ) {
-                       // Clone the title to prevent mutations to this object which is done
-                       // by Title::loadFromRow() in WikiPage::loadFromRow().
-                       $page = WikiPage::factory( clone $this );
-                       // Creating an action will perform several database queries to ensure that
-                       // the action has not been overridden by the content type.
-                       // @todo FIXME: Pass the relevant context into this function.
-                       $actionObj = Action::factory( $action, $page, RequestContext::getMain() );
-                       // Ensure that the retrieved action matches the restriction.
-                       if ( $actionObj && $actionObj->getRestriction() !== $action ) {
-                               $actionObj = null;
-                       }
-               }
-
-               // If no action object is returned, assume that the action requires unblock
-               // which is the default.
-               if ( !$actionObj || $actionObj->requiresUnblock() ) {
-                       if ( $user->isBlockedFrom( $this, $useReplica ) ) {
-                               // @todo FIXME: Pass the relevant context into this function.
-                               $errors[] = $block->getPermissionsError( RequestContext::getMain() );
-                       }
-               }
-
-               return $errors;
-       }
-
-       /**
-        * Check that the user is allowed to read this page.
-        *
-        * @param string $action The action to check
-        * @param User $user User to check
-        * @param array $errors List of current errors
-        * @param string $rigor Same format as Title::getUserPermissionsErrors()
-        * @param bool $short Short circuit on first error
-        *
-        * @return array List of errors
-        */
-       private function checkReadPermissions( $action, $user, $errors, $rigor, $short ) {
-               global $wgWhitelistRead, $wgWhitelistReadRegexp;
-
-               $whitelisted = false;
-               if ( User::isEveryoneAllowed( 'read' ) ) {
-                       # Shortcut for public wikis, allows skipping quite a bit of code
-                       $whitelisted = true;
-               } elseif ( $user->isAllowed( 'read' ) ) {
-                       # If the user is allowed to read pages, he is allowed to read all pages
-                       $whitelisted = true;
-               } elseif ( $this->isSpecial( 'Userlogin' )
-                       || $this->isSpecial( 'PasswordReset' )
-                       || $this->isSpecial( 'Userlogout' )
-               ) {
-                       # Always grant access to the login page.
-                       # Even anons need to be able to log in.
-                       $whitelisted = true;
-               } elseif ( is_array( $wgWhitelistRead ) && count( $wgWhitelistRead ) ) {
-                       # Time to check the whitelist
-                       # Only do these checks is there's something to check against
-                       $name = $this->getPrefixedText();
-                       $dbName = $this->getPrefixedDBkey();
-
-                       // Check for explicit whitelisting with and without underscores
-                       if ( in_array( $name, $wgWhitelistRead, true ) || in_array( $dbName, $wgWhitelistRead, true ) ) {
-                               $whitelisted = true;
-                       } elseif ( $this->mNamespace == NS_MAIN ) {
-                               # Old settings might have the title prefixed with
-                               # a colon for main-namespace pages
-                               if ( in_array( ':' . $name, $wgWhitelistRead ) ) {
-                                       $whitelisted = true;
-                               }
-                       } elseif ( $this->isSpecialPage() ) {
-                               # If it's a special page, ditch the subpage bit and check again
-                               $name = $this->mDbkeyform;
-                               list( $name, /* $subpage */ ) =
-                                       MediaWikiServices::getInstance()->getSpecialPageFactory()->
-                                               resolveAlias( $name );
-                               if ( $name ) {
-                                       $pure = SpecialPage::getTitleFor( $name )->getPrefixedText();
-                                       if ( in_array( $pure, $wgWhitelistRead, true ) ) {
-                                               $whitelisted = true;
-                                       }
-                               }
-                       }
-               }
-
-               if ( !$whitelisted && is_array( $wgWhitelistReadRegexp ) && !empty( $wgWhitelistReadRegexp ) ) {
-                       $name = $this->getPrefixedText();
-                       // Check for regex whitelisting
-                       foreach ( $wgWhitelistReadRegexp as $listItem ) {
-                               if ( preg_match( $listItem, $name ) ) {
-                                       $whitelisted = true;
-                                       break;
-                               }
-                       }
-               }
-
-               if ( !$whitelisted ) {
-                       # If the title is not whitelisted, give extensions a chance to do so...
-                       Hooks::run( 'TitleReadWhitelist', [ $this, $user, &$whitelisted ] );
-                       if ( !$whitelisted ) {
-                               $errors[] = $this->missingPermissionError( $action, $short );
-                       }
-               }
-
-               return $errors;
-       }
-
-       /**
-        * Get a description array when the user doesn't have the right to perform
-        * $action (i.e. when User::isAllowed() returns false)
-        *
-        * @param string $action The action to check
-        * @param bool $short Short circuit on first error
-        * @return array Array containing an error message key and any parameters
-        */
-       private function missingPermissionError( $action, $short ) {
-               // We avoid expensive display logic for quickUserCan's and such
-               if ( $short ) {
-                       return [ 'badaccess-group0' ];
-               }
-
-               return User::newFatalPermissionDeniedStatus( $action )->getErrorsArray()[0];
-       }
-
-       /**
-        * Can $user perform $action on this page? This is an internal function,
-        * with multiple levels of checks depending on performance needs; see $rigor below.
-        * It does not check wfReadOnly().
-        *
-        * @param string $action Action that permission needs to be checked for
-        * @param User $user User to check
-        * @param string $rigor One of (quick,full,secure)
-        *   - quick  : does cheap permission checks from replica DBs (usable for GUI creation)
-        *   - full   : does cheap and expensive checks possibly from a replica DB
-        *   - secure : does cheap and expensive checks, using the master as needed
-        * @param bool $short Set this to true to stop after the first permission error.
-        * @return array Array of arrays of the arguments to wfMessage to explain permissions problems.
-        */
-       protected function getUserPermissionsErrorsInternal(
-               $action, $user, $rigor = 'secure', $short = false
-       ) {
-               if ( $rigor === true ) {
-                       $rigor = 'secure'; // b/c
-               } elseif ( $rigor === false ) {
-                       $rigor = 'quick'; // b/c
-               } elseif ( !in_array( $rigor, [ 'quick', 'full', 'secure' ] ) ) {
-                       throw new Exception( "Invalid rigor parameter '$rigor'." );
-               }
-
-               # Read has special handling
-               if ( $action == 'read' ) {
-                       $checks = [
-                               'checkPermissionHooks',
-                               'checkReadPermissions',
-                               'checkUserBlock', // for wgBlockDisablesLogin
-                       ];
-               # Don't call checkSpecialsAndNSPermissions, checkSiteConfigPermissions
-               # or checkUserConfigPermissions here as it will lead to duplicate
-               # error messages. This is okay to do since anywhere that checks for
-               # create will also check for edit, and those checks are called for edit.
-               } elseif ( $action == 'create' ) {
-                       $checks = [
-                               'checkQuickPermissions',
-                               'checkPermissionHooks',
-                               'checkPageRestrictions',
-                               'checkCascadingSourcesRestrictions',
-                               'checkActionPermissions',
-                               'checkUserBlock'
-                       ];
-               } else {
-                       $checks = [
-                               'checkQuickPermissions',
-                               'checkPermissionHooks',
-                               'checkSpecialsAndNSPermissions',
-                               'checkSiteConfigPermissions',
-                               'checkUserConfigPermissions',
-                               'checkPageRestrictions',
-                               'checkCascadingSourcesRestrictions',
-                               'checkActionPermissions',
-                               'checkUserBlock'
-                       ];
-               }
-
-               $errors = [];
-               foreach ( $checks as $method ) {
-                       $errors = $this->$method( $action, $user, $errors, $rigor, $short );
-
-                       if ( $short && $errors !== [] ) {
-                               break;
-                       }
-               }
-
-               return $errors;
-       }
-
        /**
         * Get a filtered list of all restriction types supported by this wiki.
         * @param bool $exists True to get all restriction types that apply to
@@ -3324,7 +2777,7 @@ class Title implements LinkTarget, IDBAccessObject {
                $id = $this->getArticleID();
                if ( $id ) {
                        $fname = __METHOD__;
-                       $loadRestrictionsFromDb = function ( Database $dbr ) use ( $fname, $id ) {
+                       $loadRestrictionsFromDb = function ( IDatabase $dbr ) use ( $fname, $id ) {
                                return iterator_to_array(
                                        $dbr->select(
                                                'page_restrictions',
@@ -3438,7 +2891,10 @@ class Title implements LinkTarget, IDBAccessObject {
         * @return bool
         */
        public function hasSubpages() {
-               if ( !MWNamespace::hasSubpages( $this->mNamespace ) ) {
+               if (
+                       !MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               hasSubpages( $this->mNamespace )
+               ) {
                        # Duh
                        return false;
                }
@@ -3466,7 +2922,10 @@ class Title implements LinkTarget, IDBAccessObject {
         *  doesn't allow subpages
         */
        public function getSubpages( $limit = -1 ) {
-               if ( !MWNamespace::hasSubpages( $this->mNamespace ) ) {
+               if (
+                       !MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               hasSubpages( $this->mNamespace )
+               ) {
                        return [];
                }
 
@@ -3554,10 +3013,8 @@ class Title implements LinkTarget, IDBAccessObject {
                        $linkCache->clearLink( $this );
                        $this->mArticleID = $linkCache->addLinkObj( $this );
                        $linkCache->forUpdate( $oldUpdate );
-               } else {
-                       if ( $this->mArticleID == -1 ) {
-                               $this->mArticleID = $linkCache->addLinkObj( $this );
-                       }
+               } elseif ( $this->mArticleID == -1 ) {
+                       $this->mArticleID = $linkCache->addLinkObj( $this );
                }
                return $this->mArticleID;
        }
@@ -3702,7 +3159,8 @@ class Title implements LinkTarget, IDBAccessObject {
         * @return string Containing capitalized title
         */
        public static function capitalize( $text, $ns = NS_MAIN ) {
-               if ( MWNamespace::isCapitalized( $ns ) ) {
+               $services = MediaWikiServices::getInstance();
+               if ( $services->getNamespaceInfo()->isCapitalized( $ns ) ) {
                        return MediaWikiServices::getInstance()->getContentLanguage()->ucfirst( $text );
                } else {
                        return $text;
@@ -3727,6 +3185,7 @@ class Title implements LinkTarget, IDBAccessObject {
                // @todo: get rid of secureAndSplit, refactor parsing code.
                // @note: getTitleParser() returns a TitleParser implementation which does not have a
                //        splitTitleString method, but the only implementation (MediaWikiTitleCodec) does
+               /** @var MediaWikiTitleCodec $titleCodec */
                $titleCodec = MediaWikiServices::getInstance()->getTitleParser();
                // MalformedTitleException can be thrown here
                $parts = $titleCodec->splitTitleString( $this->mDbkeyform, $this->mDefaultNamespace );
@@ -4007,19 +3466,10 @@ class Title implements LinkTarget, IDBAccessObject {
                array $changeTags = []
        ) {
                global $wgUser;
-               $err = $this->isValidMoveOperation( $nt, $auth, $reason );
-               if ( is_array( $err ) ) {
-                       // Auto-block user's IP if the account was "hard" blocked
-                       $wgUser->spreadAnyEditBlock();
-                       return $err;
-               }
-               // Check suppressredirect permission
-               if ( $auth && !$wgUser->isAllowed( 'suppressredirect' ) ) {
-                       $createRedirect = true;
-               }
 
                $mp = new MovePage( $this, $nt );
-               $status = $mp->move( $wgUser, $reason, $createRedirect, $changeTags );
+               $method = $auth ? 'moveIfAllowed' : 'move';
+               $status = $mp->$method( $wgUser, $reason, $createRedirect, $changeTags );
                if ( $status->isOK() ) {
                        return true;
                } else {
@@ -4052,14 +3502,15 @@ class Title implements LinkTarget, IDBAccessObject {
                        ];
                }
                // Do the source and target namespaces support subpages?
-               if ( !MWNamespace::hasSubpages( $this->mNamespace ) ) {
+               $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
+               if ( !$nsInfo->hasSubpages( $this->mNamespace ) ) {
                        return [
-                               [ 'namespace-nosubpages', MWNamespace::getCanonicalName( $this->mNamespace ) ],
+                               [ 'namespace-nosubpages', $nsInfo->getCanonicalName( $this->mNamespace ) ],
                        ];
                }
-               if ( !MWNamespace::hasSubpages( $nt->getNamespace() ) ) {
+               if ( !$nsInfo->hasSubpages( $nt->getNamespace() ) ) {
                        return [
-                               [ 'namespace-nosubpages', MWNamespace::getCanonicalName( $nt->getNamespace() ) ],
+                               [ 'namespace-nosubpages', $nsInfo->getCanonicalName( $nt->getNamespace() ) ],
                        ];
                }
 
@@ -4292,57 +3743,25 @@ class Title implements LinkTarget, IDBAccessObject {
         * @return int|bool New revision ID, or false if none exists
         */
        private function getRelativeRevisionID( $revId, $flags, $dir ) {
-               $revId = (int)$revId;
-               if ( $dir === 'next' ) {
-                       $op = '>';
-                       $sort = 'ASC';
-               } elseif ( $dir === 'prev' ) {
-                       $op = '<';
-                       $sort = 'DESC';
-               } else {
-                       throw new InvalidArgumentException( '$dir must be "next" or "prev"' );
-               }
-
-               if ( $flags & self::GAID_FOR_UPDATE ) {
-                       $db = wfGetDB( DB_MASTER );
-               } else {
-                       $db = wfGetDB( DB_REPLICA, 'contributions' );
-               }
-
-               // Intentionally not caring if the specified revision belongs to this
-               // page. We only care about the timestamp.
-               $ts = $db->selectField( 'revision', 'rev_timestamp', [ 'rev_id' => $revId ], __METHOD__ );
-               if ( $ts === false ) {
-                       $ts = $db->selectField( 'archive', 'ar_timestamp', [ 'ar_rev_id' => $revId ], __METHOD__ );
-                       if ( $ts === false ) {
-                               // Or should this throw an InvalidArgumentException or something?
-                               return false;
-                       }
+               $rl = MediaWikiServices::getInstance()->getRevisionLookup();
+               $rlFlags = $flags === self::GAID_FOR_UPDATE ? IDBAccessObject::READ_LATEST : 0;
+               $rev = $rl->getRevisionById( $revId, $rlFlags );
+               if ( !$rev ) {
+                       return false;
                }
-               $ts = $db->addQuotes( $ts );
-
-               $revId = $db->selectField( 'revision', 'rev_id',
-                       [
-                               'rev_page' => $this->getArticleID( $flags ),
-                               "rev_timestamp $op $ts OR (rev_timestamp = $ts AND rev_id $op $revId)"
-                       ],
-                       __METHOD__,
-                       [
-                               'ORDER BY' => "rev_timestamp $sort, rev_id $sort",
-                               'IGNORE INDEX' => 'rev_timestamp', // Probably needed for T159319
-                       ]
-               );
-
-               if ( $revId === false ) {
+               $oldRev = $dir === 'next'
+                       ? $rl->getNextRevision( $rev, $rlFlags )
+                       : $rl->getPreviousRevision( $rev, $rlFlags );
+               if ( !$oldRev ) {
                        return false;
-               } else {
-                       return intval( $revId );
                }
+               return $oldRev->getId();
        }
 
        /**
         * Get the revision ID of the previous revision
         *
+        * @deprecated since 1.34, use RevisionLookup::getPreviousRevision
         * @param int $revId Revision ID. Get the revision that was before this one.
         * @param int $flags Title::GAID_FOR_UPDATE
         * @return int|bool Old revision ID, or false if none exists
@@ -4354,6 +3773,7 @@ class Title implements LinkTarget, IDBAccessObject {
        /**
         * Get the revision ID of the next revision
         *
+        * @deprecated since 1.34, use RevisionLookup::getNextRevision
         * @param int $revId Revision ID. Get the revision that was after this one.
         * @param int $flags Title::GAID_FOR_UPDATE
         * @return int|bool Next revision ID, or false if none exists
@@ -4593,14 +4013,14 @@ class Title implements LinkTarget, IDBAccessObject {
        /**
         * Compare with another title.
         *
-        * @param Title $title
+        * @param LinkTarget $title
         * @return bool
         */
-       public function equals( Title $title ) {
+       public function equals( LinkTarget $title ) {
                // Note: === is necessary for proper matching of number-like titles.
-               return $this->mInterwiki === $title->mInterwiki
-                       && $this->mNamespace == $title->mNamespace
-                       && $this->mDbkeyform === $title->mDbkeyform;
+               return $this->mInterwiki === $title->getInterwiki()
+                       && $this->mNamespace == $title->getNamespace()
+                       && $this->mDbkeyform === $title->getDBkey();
        }
 
        /**
@@ -4803,7 +4223,7 @@ class Title implements LinkTarget, IDBAccessObject {
                $dbw->onTransactionPreCommitOrIdle(
                        function () use ( $dbw ) {
                                ResourceLoaderWikiModule::invalidateModuleCache(
-                                       $this, null, null, $dbw->getDomainId() );
+                                       $this, null, null, $dbw->getDomainID() );
                        },
                        __METHOD__
                );
@@ -4904,9 +4324,10 @@ class Title implements LinkTarget, IDBAccessObject {
         */
        public function getNamespaceKey( $prepend = 'nstab-' ) {
                // Gets the subject namespace of this title
-               $subjectNS = MWNamespace::getSubject( $this->mNamespace );
+               $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
+               $subjectNS = $nsInfo->getSubject( $this->mNamespace );
                // Prefer canonical namespace name for HTML IDs
-               $namespaceKey = MWNamespace::getCanonicalName( $subjectNS );
+               $namespaceKey = $nsInfo->getCanonicalName( $subjectNS );
                if ( $namespaceKey === false ) {
                        // Fallback to localised text
                        $namespaceKey = $this->getSubjectNsText();
@@ -5002,7 +4423,8 @@ class Title implements LinkTarget, IDBAccessObject {
        public function canUseNoindex() {
                global $wgExemptFromUserRobotsControl;
 
-               $bannedNamespaces = $wgExemptFromUserRobotsControl ?? MWNamespace::getContentNamespaces();
+               $bannedNamespaces = $wgExemptFromUserRobotsControl ??
+                       MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces();
 
                return !in_array( $this->mNamespace, $bannedNamespaces );
        }
@@ -5169,7 +4591,10 @@ class Title implements LinkTarget, IDBAccessObject {
                        }
                }
 
-               if ( MWNamespace::hasSubpages( $this->mNamespace ) ) {
+               if (
+                       MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               hasSubpages( $this->mNamespace )
+               ) {
                        // Optional notice for page itself and any parent page
                        $editnotice_base = $editnotice_ns;
                        foreach ( explode( '/', $this->mDbkeyform ) as $part ) {
index b3a49c7..ebdbc42 100644 (file)
@@ -19,6 +19,8 @@
  * @ingroup Categories
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * This class performs some operations related to tracking categories, such as creating
  * a list of all such categories.
@@ -80,6 +82,7 @@ class TrackingCategories {
                }
 
                $trackingCategories = [];
+               $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
                foreach ( $categories as $catMsg ) {
                        /*
                         * Check if the tracking category varies by namespace
@@ -96,7 +99,7 @@ class TrackingCategories {
                        // Match things like {{NAMESPACE}} and {{NAMESPACENUMBER}}.
                        // False positives are ok, this is just an efficiency shortcut
                        if ( strpos( $msgObj->plain(), '{{' ) !== false ) {
-                               $ns = MWNamespace::getValidNamespaces();
+                               $ns = $nsInfo->getValidNamespaces();
                                foreach ( $ns as $namesp ) {
                                        $tempTitle = Title::makeTitleSafe( $namesp, $catMsg );
                                        if ( !$tempTitle ) {
index e5cdda6..76d94b2 100644 (file)
@@ -275,8 +275,18 @@ class WebRequest {
        public static function getRequestId() {
                // This method is called from various error handlers and should be kept simple.
 
-               if ( !self::$reqId ) {
-                       self::$reqId = $_SERVER['UNIQUE_ID'] ?? wfRandomString( 24 );
+               if ( self::$reqId ) {
+                       return self::$reqId;
+               }
+
+               global $wgAllowExternalReqID;
+
+               self::$reqId = $_SERVER['UNIQUE_ID'] ?? wfRandomString( 24 );
+               if ( $wgAllowExternalReqID ) {
+                       $id = RequestContext::getMain()->getRequest()->getHeader( 'X-Request-Id' );
+                       if ( $id ) {
+                               self::$reqId = $id;
+                       }
                }
 
                return self::$reqId;
@@ -382,17 +392,15 @@ class WebRequest {
         */
        private function getGPCVal( $arr, $name, $default ) {
                # PHP is so nice to not touch input data, except sometimes:
-               # https://secure.php.net/variables.external#language.variables.external.dot-in-names
+               # https://www.php.net/variables.external#language.variables.external.dot-in-names
                # Work around PHP *feature* to avoid *bugs* elsewhere.
                $name = strtr( $name, '.', '_' );
                if ( isset( $arr[$name] ) ) {
                        $data = $arr[$name];
-                       if ( isset( $_GET[$name] ) && !is_array( $data ) ) {
+                       if ( isset( $_GET[$name] ) && is_string( $data ) ) {
                                # Check for alternate/legacy character encoding.
                                $contLang = MediaWikiServices::getInstance()->getContentLanguage();
-                               if ( $contLang ) {
-                                       $data = $contLang->checkTitleEncoding( $data );
-                               }
+                               $data = $contLang->checkTitleEncoding( $data );
                        }
                        $data = $this->normalizeUnicode( $data );
                        return $data;
@@ -851,12 +859,19 @@ class WebRequest {
         * in HTML or other output.
         *
         * If $wgServer is protocol-relative, this will return a fully
-        * qualified URL with the protocol that was used for this request.
+        * qualified URL with the protocol of this request object.
         *
         * @return string
         */
        public function getFullRequestURL() {
-               return wfGetServerUrl( PROTO_CURRENT ) . $this->getRequestURL();
+               // Pass an explicit PROTO constant instead of PROTO_CURRENT so that we
+               // do not rely on state from the global $wgRequest object (which it would,
+               // via wfGetServerUrl/wfExpandUrl/$wgRequest->protocol).
+               if ( $this->getProtocol() === 'http' ) {
+                       return wfGetServerUrl( PROTO_HTTP ) . $this->getRequestURL();
+               } else {
+                       return wfGetServerUrl( PROTO_HTTPS ) . $this->getRequestURL();
+               }
        }
 
        /**
index 34c6062..c2d08b8 100644 (file)
@@ -103,7 +103,7 @@ class WebRequestUpload {
 
        /**
         * Return the upload error. See link for explanation
-        * https://secure.php.net/manual/en/features.file-upload.errors.php
+        * https://www.php.net/manual/en/features.file-upload.errors.php
         *
         * @return int One of the UPLOAD_ constants, 0 if non-existent
         */
index 878dd3e..c83fdea 100644 (file)
@@ -50,6 +50,7 @@ if ( !defined( 'MW_CONFIG_CALLBACK' ) ) {
                define( 'MW_CONFIG_FILE', "$IP/LocalSettings.php" );
        }
        if ( !is_readable( MW_CONFIG_FILE ) ) {
+
                function wfWebStartNoLocalSettings() {
                        # LocalSettings.php is the per-site customization file. If it does not exist
                        # the wiki installer needs to be launched or the generated file uploaded to
@@ -58,12 +59,14 @@ if ( !defined( 'MW_CONFIG_CALLBACK' ) ) {
                        require_once "$IP/includes/NoLocalSettings.php";
                        die();
                }
+
                define( 'MW_CONFIG_CALLBACK', 'wfWebStartNoLocalSettings' );
        }
 }
 
 // Custom setup for WebStart entry point
 if ( !defined( 'MW_SETUP_CALLBACK' ) ) {
+
        function wfWebStartSetup() {
                // Initialise output buffering
                // Check for previously set up buffers, to avoid a mix of gzip and non-gzip output.
@@ -71,6 +74,7 @@ if ( !defined( 'MW_SETUP_CALLBACK' ) ) {
                        ob_start( 'MediaWiki\\OutputHandler::handle' );
                }
        }
+
        define( 'MW_SETUP_CALLBACK', 'wfWebStartSetup' );
 }
 
index 628fbc0..23b0e3e 100644 (file)
@@ -221,19 +221,29 @@ class WikiMap {
         * @since 1.30
         */
        public static function getWikiFromUrl( $url ) {
+               global $wgCanonicalServer;
+
+               if ( strpos( $url, "$wgCanonicalServer/" ) === 0 ) {
+                       // Optimisation: Handle the the common case.
+                       // (Duplicates self::getCanonicalServerInfoForAllWikis)
+                       return self::getWikiIdFromDbDomain( self::getCurrentWikiDbDomain() );
+               }
+
                $urlPartsCheck = wfParseUrl( $url );
                if ( $urlPartsCheck === false ) {
                        return false;
                }
 
-               $urlPartsCheck = array_intersect_key( $urlPartsCheck, [ 'host' => 1, 'port' => 1 ] );
+               static $relevantKeys = [ 'host' => 1, 'port' => 1 ];
+               $urlPartsCheck = array_intersect_key( $urlPartsCheck, $relevantKeys );
+
                foreach ( self::getCanonicalServerInfoForAllWikis() as $wikiId => $info ) {
                        $urlParts = $info['parts'];
                        if ( $urlParts === false ) {
                                continue; // sanity
                        }
 
-                       $urlParts = array_intersect_key( $urlParts, [ 'host' => 1, 'port' => 1 ] );
+                       $urlParts = array_intersect_key( $urlParts, $relevantKeys );
                        if ( $urlParts == $urlPartsCheck ) {
                                return $wikiId;
                        }
@@ -245,8 +255,12 @@ class WikiMap {
        /**
         * Get the wiki ID of a database domain
         *
-        * This is like DatabaseDomain::getId() without encoding (for legacy reasons)
-        * and without the schema if it merely set to the generic value "mediawiki"
+        * This is like DatabaseDomain::getId() without encoding (for legacy reasons) and
+        * without the schema if it is the generic installer default of "mediawiki"/"dbo"
+        *
+        * @see $wgDBmwschema
+        * @see PostgresInstaller
+        * @see MssqlInstaller
         *
         * @param string|DatabaseDomain $domain
         * @return string
@@ -254,15 +268,17 @@ class WikiMap {
         */
        public static function getWikiIdFromDbDomain( $domain ) {
                $domain = DatabaseDomain::newFromId( $domain );
-
-               if ( !in_array( $domain->getSchema(), [ null, 'mediawiki' ], true ) ) {
-                       // Include the schema if it is set and is not the default placeholder.
+               // Since the schema was not always part of the wiki ID, try to maintain backwards
+               // compatibility with some common cases. Assume that if the DB domain schema is just
+               // the installer default then it is probably the case that the schema is the same for
+               // all wikis in the farm. Historically, any wiki farm had to make the database/prefix
+               // combination unique per wiki. Ommit the schema if it does not seem wiki specific.
+               if ( !in_array( $domain->getSchema(), [ null, 'mediawiki', 'dbo' ], true ) ) {
                        // This means a site admin may have specifically taylored the schemas.
-                       // Domain IDs might use the form <DB>-<project>-<language>, meaning that
-                       // the schema portion must be accounted for to disambiguate wikis.
+                       // Domain IDs might use the form <DB>-<project>- or <DB>-<project>-<language>_,
+                       // meaning that the schema portion must be accounted for to disambiguate wikis.
                        return "{$domain->getDatabase()}-{$domain->getSchema()}-{$domain->getTablePrefix()}";
                }
-
                // Note that if this wiki ID is passed a a domain ID to LoadBalancer, then it can
                // handle the schema by assuming the generic "mediawiki" schema if needed.
                return strlen( $domain->getTablePrefix() )
@@ -291,30 +307,16 @@ class WikiMap {
 
        /**
         * @param DatabaseDomain|string $domain
-        * @return bool Whether $domain has the same DB/prefix as the current wiki
+        * @return bool Whether $domain matches the DB domain of the current wiki
         * @since 1.33
         */
        public static function isCurrentWikiDbDomain( $domain ) {
-               $domain = DatabaseDomain::newFromId( $domain );
-               $curDomain = self::getCurrentWikiDbDomain();
-
-               if ( !in_array( $curDomain->getSchema(), [ null, 'mediawiki' ], true ) ) {
-                       // Include the schema if it is set and is not the default placeholder.
-                       // This means a site admin may have specifically taylored the schemas.
-                       // Domain IDs might use the form <DB>-<project>-<language>, meaning that
-                       // the schema portion must be accounted for to disambiguate wikis.
-                       return $curDomain->equals( $domain );
-               }
-
-               return (
-                       $curDomain->getDatabase() === $domain->getDatabase() &&
-                       $curDomain->getTablePrefix() === $domain->getTablePrefix()
-               );
+               return self::getCurrentWikiDbDomain()->equals( DatabaseDomain::newFromId( $domain ) );
        }
 
        /**
         * @param string $wikiId
-        * @return bool Whether $wikiId has the same DB/prefix as the current wiki
+        * @return bool Whether $wikiId matches the wiki ID of the current wiki
         * @since 1.33
         */
        public static function isCurrentWikiId( $wikiId ) {
index d1a56bf..febf03e 100644 (file)
@@ -47,12 +47,10 @@ class Xml {
                }
                if ( is_null( $contents ) ) {
                        $out .= '>';
+               } elseif ( $allowShortTag && $contents === '' ) {
+                       $out .= ' />';
                } else {
-                       if ( $allowShortTag && $contents === '' ) {
-                               $out .= ' />';
-                       } else {
-                               $out .= '>' . htmlspecialchars( $contents, ENT_NOQUOTES ) . "</$element>";
-                       }
+                       $out .= '>' . htmlspecialchars( $contents, ENT_NOQUOTES ) . "</$element>";
                }
                return $out;
        }
index ed58686..4cb7dda 100644 (file)
@@ -222,12 +222,10 @@ class CreditsAction extends FormlessAction {
                $link = $this->link( $user );
                if ( $user->isAnon() ) {
                        return $this->msg( 'anonuser' )->rawParams( $link )->parse();
+               } elseif ( $this->canShowRealUserName() && $user->getRealName() ) {
+                       return $link;
                } else {
-                       if ( $this->canShowRealUserName() && $user->getRealName() ) {
-                               return $link;
-                       } else {
-                               return $this->msg( 'siteuser' )->rawParams( $link )->params( $user->getName() )->escaped();
-                       }
+                       return $this->msg( 'siteuser' )->rawParams( $link )->params( $user->getName() )->escaped();
                }
        }
 
index fbf43e0..538b0a1 100644 (file)
@@ -78,7 +78,7 @@ class HistoryAction extends FormlessAction {
                                        ->rawParams( $this->getLanguage()->pipeList( $links ) )
                                        ->escaped();
                }
-               return $subtitle;
+               return Html::rawElement( 'div', [ 'class' => 'mw-history-subtitle' ], $subtitle );
        }
 
        /**
@@ -102,6 +102,44 @@ class HistoryAction extends FormlessAction {
                }
        }
 
+       /**
+        * @param WebRequest $request
+        * @return string
+        */
+       private function getTimestampFromRequest( WebRequest $request ) {
+               // Backwards compatibility checks for URIs with only year and/or month.
+               $year = $request->getInt( 'year' );
+               $month = $request->getInt( 'month' );
+               $day = null;
+               if ( $year !== 0 || $month !== 0 ) {
+                       if ( $year === 0 ) {
+                               $year = MWTimestamp::getLocalInstance()->format( 'Y' );
+                       }
+                       if ( $month < 1 || $month > 12 ) {
+                               // month is invalid so treat as December (all months)
+                               $month = 12;
+                       }
+                       // month is valid so check day
+                       $day = cal_days_in_month( CAL_GREGORIAN, $month, $year );
+
+                       // Left pad the months and days
+                       $month = str_pad( $month, 2, "0", STR_PAD_LEFT );
+                       $day = str_pad( $day, 2, "0", STR_PAD_LEFT );
+               }
+
+               $before = $request->getVal( 'date-range-to' );
+               if ( $before ) {
+                       $parts = explode( '-', $before );
+                       $year = $parts[0];
+                       // check date input is valid
+                       if ( count( $parts ) === 3 ) {
+                               $month = $parts[1];
+                               $day = $parts[2];
+                       }
+               }
+               return $year && $month && $day ? $year . '-' . $month . '-' . $day : '';
+       }
+
        /**
         * Print the history page for an article.
         */
@@ -144,14 +182,16 @@ class HistoryAction extends FormlessAction {
                }
 
                // Handle atom/RSS feeds.
-               $feedType = $request->getVal( 'feed' );
-               if ( $feedType ) {
+               $feedType = $request->getRawVal( 'feed' );
+               if ( $feedType !== null ) {
                        $this->feed( $feedType );
-
                        return;
                }
 
-               $this->addHelpLink( '//meta.wikimedia.org/wiki/Special:MyLanguage/Help:Page_history', true );
+               $this->addHelpLink(
+                       'https://meta.wikimedia.org/wiki/Special:MyLanguage/Help:Page_history',
+                       true
+               );
 
                // Fail nicely if article doesn't exist.
                if ( !$this->page->exists() ) {
@@ -179,13 +219,8 @@ class HistoryAction extends FormlessAction {
                        return;
                }
 
-               /**
-                * Add date selector to quickly get to a certain time
-                */
-               $year = $request->getInt( 'year' );
-               $month = $request->getInt( 'month' );
+               $ts = $this->getTimestampFromRequest( $request );
                $tagFilter = $request->getVal( 'tagfilter' );
-               $tagSelector = ChangeTags::buildTagFilterSelector( $tagFilter, false, $this->getContext() );
 
                /**
                 * Option to show only revisions that have been (partially) hidden via RevisionDelete
@@ -195,41 +230,70 @@ class HistoryAction extends FormlessAction {
                } else {
                        $conds = [];
                }
+
+               // Add the general form.
+               $fields = [
+                       [
+                               'name' => 'title',
+                               'type' => 'hidden',
+                               'default' => $this->getTitle()->getPrefixedDBkey(),
+                       ],
+                       [
+                               'name' => 'action',
+                               'type' => 'hidden',
+                               'default' => 'history',
+                       ],
+                       [
+                               'type' => 'date',
+                               'default' => $ts,
+                               'label' => $this->msg( 'date-range-to' )->text(),
+                               'name' => 'date-range-to',
+                       ],
+                       [
+                               'label-raw' => $this->msg( 'tag-filter' )->parse(),
+                               'type' => 'tagfilter',
+                               'id' => 'tagfilter',
+                               'name' => 'tagfilter',
+                               'value' => $tagFilter,
+                       ]
+               ];
                if ( $this->getUser()->isAllowed( 'deletedhistory' ) ) {
-                       $checkDeleted = Xml::checkLabel( $this->msg( 'history-show-deleted' )->text(),
-                               'deleted', 'mw-show-deleted-only', $request->getBool( 'deleted' ) ) . "\n";
-               } else {
-                       $checkDeleted = '';
+                       $fields[] = [
+                               'type' => 'check',
+                               'label' => $this->msg( 'history-show-deleted' )->text(),
+                               'default' => $request->getBool( 'deleted' ),
+                               'name' => 'deleted',
+                       ];
                }
 
-               // Add the general form
-               $action = htmlspecialchars( wfScript() );
-               $content = Html::hidden( 'title', $this->getTitle()->getPrefixedDBkey() ) . "\n";
-               $content .= Html::hidden( 'action', 'history' ) . "\n";
-               $content .= Xml::dateMenu(
-                       ( $year == null ? MWTimestamp::getLocalInstance()->format( 'Y' ) : $year ),
-                       $month
-               ) . "\u{00A0}";
-               $content .= $tagSelector ? ( implode( "\u{00A0}", $tagSelector ) . "\u{00A0}" ) : '';
-               $content .= $checkDeleted . Html::submitButton(
-                       $this->msg( 'historyaction-submit' )->text(),
-                       [],
-                       [ 'mw-ui-progressive' ]
-               );
-               $out->addHTML(
-                       "<form action=\"$action\" method=\"get\" id=\"mw-history-searchform\">" .
-                       Xml::fieldset(
-                               $this->msg( 'history-fieldset-title' )->text(),
-                               $content,
-                               [ 'id' => 'mw-history-search' ]
-                       ) .
-                       '</form>'
-               );
+               $out->enableOOUI();
+               $htmlForm = HTMLForm::factory( 'ooui', $fields, $this->getContext() );
+               $htmlForm
+                       ->setMethod( 'get' )
+                       ->setAction( wfScript() )
+                       ->setCollapsibleOptions( true )
+                       ->setId( 'mw-history-searchform' )
+                       ->setSubmitText( $this->msg( 'historyaction-submit' )->text() )
+                       ->setWrapperAttributes( [ 'id' => 'mw-history-search' ] )
+                       ->setWrapperLegend( $this->msg( 'history-fieldset-title' )->text() );
+               $htmlForm->loadData();
+
+               $out->addHTML( $htmlForm->getHTML( false ) );
 
                Hooks::run( 'PageHistoryBeforeList', [ &$this->page, $this->getContext() ] );
 
                // Create and output the list.
-               $pager = new HistoryPager( $this, $year, $month, $tagFilter, $conds );
+               $dateComponents = explode( '-', $ts );
+               if ( count( $dateComponents ) > 1 ) {
+                       $y = $dateComponents[0];
+                       $m = $dateComponents[1];
+                       $d = $dateComponents[2];
+               } else {
+                       $y = '';
+                       $m = '';
+                       $d = '';
+               }
+               $pager = new HistoryPager( $this, $y, $m, $tagFilter, $conds, $d );
                $out->addHTML(
                        $pager->getNavigationBar() .
                        $pager->getBody() .
index 49a6bb5..bfba59a 100644 (file)
@@ -399,7 +399,7 @@ class InfoAction extends FormlessAction {
                }
 
                // Subpages of this page, if subpages are enabled for the current NS
-               if ( MWNamespace::hasSubpages( $title->getNamespace() ) ) {
+               if ( $services->getNamespaceInfo()->hasSubpages( $title->getNamespace() ) ) {
                        $prefixIndex = SpecialPage::getTitleFor(
                                'Prefixindex', $title->getPrefixedText() . '/' );
                        $pageInfo['header-basic'][] = [
@@ -730,12 +730,13 @@ class InfoAction extends FormlessAction {
        protected function pageCounts( Page $page ) {
                $fname = __METHOD__;
                $config = $this->context->getConfig();
-               $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
+               $services = MediaWikiServices::getInstance();
+               $cache = $services->getMainWANObjectCache();
 
                return $cache->getWithSetCallback(
                        self::getCacheKey( $cache, $page->getTitle(), $page->getLatest() ),
                        WANObjectCache::TTL_WEEK,
-                       function ( $oldValue, &$ttl, &$setOpts ) use ( $page, $config, $fname ) {
+                       function ( $oldValue, &$ttl, &$setOpts ) use ( $page, $config, $fname, $services ) {
                                global $wgActorTableSchemaMigrationStage;
 
                                $title = $page->getTitle();
@@ -759,7 +760,7 @@ class InfoAction extends FormlessAction {
                                        $joins = [];
                                }
 
-                               $watchedItemStore = MediaWikiServices::getInstance()->getWatchedItemStore();
+                               $watchedItemStore = $services->getWatchedItemStore();
 
                                $result = [];
                                $result['watchers'] = $watchedItemStore->countWatchers( $title );
@@ -824,7 +825,7 @@ class InfoAction extends FormlessAction {
                                );
 
                                // Subpages (if enabled)
-                               if ( MWNamespace::hasSubpages( $title->getNamespace() ) ) {
+                               if ( $services->getNamespaceInfo()->hasSubpages( $title->getNamespace() ) ) {
                                        $conds = [ 'page_namespace' => $title->getNamespace() ];
                                        $conds[] = 'page_title ' .
                                                $dbr->buildLike( $title->getDBkey() . '/', $dbr->anyString() );
index 47bbdc0..e9de846 100644 (file)
@@ -30,7 +30,7 @@ class McrUndoAction extends FormAction {
 
        protected $undo = 0, $undoafter = 0, $cur = 0;
 
-       /** @param RevisionRecord|null */
+       /** @var RevisionRecord|null */
        protected $curRev = null;
 
        public function getName() {
@@ -298,7 +298,7 @@ class McrUndoAction extends FormAction {
                        'class' => 'mw-content-' . $pageViewLang->getDir() ];
                $previewHTML = Html::rawElement( 'div', $attribs, $previewHTML );
 
-               $out->addHtml( $previewhead . $previewHTML );
+               $out->addHTML( $previewhead . $previewHTML );
        }
 
        public function onSubmit( $data ) {
index c8f1a8d..14f7603 100644 (file)
@@ -27,6 +27,7 @@
  */
 
 use MediaWiki\Logger\LoggerFactory;
+use MediaWiki\MediaWikiServices;
 
 /**
  * A simple method to retrieve the plain source of an article,
@@ -119,7 +120,7 @@ class RawAction extends FormlessAction {
                                        "Unsafe JS/CSS/Json {$elevatedText}load - {user} loaded {title} with {ctype}",
                                        [
                                                'user' => $this->getUser()->getName(),
-                                               'title' => $title->getPrefixedDBKey(),
+                                               'title' => $title->getPrefixedDBkey(),
                                                'ctype' => $contentType,
                                                'elevated' => $elevated
                                        ]
@@ -147,7 +148,7 @@ class RawAction extends FormlessAction {
                        $log->info( "Blocked loading unprotected JS {title} for {user}",
                                [
                                        'user' => $this->getUser()->getName(),
-                                       'title' => $title->getPrefixedDBKey(),
+                                       'title' => $title->getPrefixedDBkey(),
                                ]
                        );
                        throw new HttpError( 403, wfMessage( 'unprotected-js' ) );
@@ -181,8 +182,6 @@ class RawAction extends FormlessAction {
         * @return string|bool
         */
        public function getRawText() {
-               global $wgParser;
-
                $text = false;
                $title = $this->getTitle();
                $request = $this->getRequest();
@@ -221,7 +220,7 @@ class RawAction extends FormlessAction {
                }
 
                if ( $text !== false && $text !== '' && $request->getRawVal( 'templates' ) === 'expand' ) {
-                       $text = $wgParser->preprocess(
+                       $text = MediaWikiServices::getInstance()->getParser()->preprocess(
                                $text,
                                $title,
                                ParserOptions::newFromContext( $this->getContext() )
index 03a5bc8..e2fc265 100644 (file)
@@ -25,7 +25,7 @@
  *
  * @ingroup Actions
  */
-class RollbackAction extends FormlessAction {
+class RollbackAction extends FormAction {
 
        public function getName() {
                return 'rollback';
@@ -35,21 +35,59 @@ class RollbackAction extends FormlessAction {
                return 'rollback';
        }
 
-       /**
-        * Temporarily unused message keys due to T88044/T136375:
-        * - confirm-rollback-top
-        * - confirm-rollback-button
-        * - rollbackfailed
-        * - rollback-missingparam
-        * - rollback-success-notify
-        */
+       protected function usesOOUI() {
+               return true;
+       }
+
+       protected function getDescription() {
+               return '';
+       }
+
+       public function doesWrites() {
+               return true;
+       }
+
+       public function onSuccess() {
+               return false;
+       }
+
+       public function onSubmit( $data ) {
+               return false;
+       }
+
+       protected function alterForm( HTMLForm $form ) {
+               $form->setWrapperLegendMsg( 'confirm-rollback-top' );
+               $form->setSubmitTextMsg( 'confirm-rollback-button' );
+               $form->setTokenSalt( 'rollback' );
+
+               $from = $this->getRequest()->getVal( 'from' );
+               if ( $from === null ) {
+                       throw new BadRequestError( 'rollbackfailed', 'rollback-missingparam' );
+               }
+               foreach ( [ 'from', 'bot', 'hidediff', 'summary', 'token' ] as $param ) {
+                       $val = $this->getRequest()->getVal( $param );
+                       if ( $val !== null ) {
+                               $form->addHiddenField( $param, $val );
+                       }
+               }
+       }
 
        /**
         * @throws ErrorPageError
+        * @throws ReadOnlyError
+        * @throws ThrottledError
         */
-       public function onView() {
-               // TODO: use $this->useTransactionalTimeLimit(); when POST only
-               wfTransactionalTimeLimit();
+       public function show() {
+               if ( $this->getUser()->getOption( 'showrollbackconfirmation' ) == false ||
+                        $this->getRequest()->wasPosted() ) {
+                       $this->handleRollbackRequest();
+               } else {
+                       $this->showRollbackConfirmationForm();
+               }
+       }
+
+       public function handleRollbackRequest() {
+               $this->enableTransactionalTimelimit();
 
                $request = $this->getRequest();
                $user = $this->getUser();
@@ -69,15 +107,6 @@ class RollbackAction extends FormlessAction {
                        ] );
                }
 
-               // @TODO: remove this hack once rollback uses POST (T88044)
-               $fname = __METHOD__;
-               $trxLimits = $this->context->getConfig()->get( 'TrxProfilerLimits' );
-               $trxProfiler = Profiler::instance()->getTransactionProfiler();
-               $trxProfiler->redefineExpectations( $trxLimits['POST'], $fname );
-               DeferredUpdates::addCallableUpdate( function () use ( $trxProfiler, $trxLimits, $fname ) {
-                       $trxProfiler->redefineExpectations( $trxLimits['PostSend-POST'], $fname );
-               } );
-
                $data = null;
                $errors = $this->page->doRollback(
                        $from,
@@ -92,9 +121,7 @@ class RollbackAction extends FormlessAction {
                        throw new ThrottledError;
                }
 
-               if ( isset( $errors[0][0] ) &&
-                       ( $errors[0][0] == 'alreadyrolled' || $errors[0][0] == 'cantrollback' )
-               ) {
+               if ( $this->hasRollbackRelatedErrors( $errors ) ) {
                        $this->getOutput()->setPageTitle( $this->msg( 'rollbackfailed' ) );
                        $errArray = $errors[0];
                        $errMsg = array_shift( $errArray );
@@ -166,11 +193,51 @@ class RollbackAction extends FormlessAction {
                }
        }
 
-       protected function getDescription() {
-               return '';
+       /**
+        * Enables transactional time limit for POST and GET requests to RollbackAction
+        * @throws ConfigException
+        */
+       private function enableTransactionalTimelimit() {
+               // If Rollbacks are made POST-only, use $this->useTransactionalTimeLimit()
+               wfTransactionalTimeLimit();
+               if ( !$this->getRequest()->wasPosted() ) {
+                       /**
+                        * We apply the higher POST limits on GET requests
+                        * to prevent logstash.wikimedia.org from being spammed
+                        */
+                       $fname = __METHOD__;
+                       $trxLimits = $this->context->getConfig()->get( 'TrxProfilerLimits' );
+                       $trxProfiler = Profiler::instance()->getTransactionProfiler();
+                       $trxProfiler->redefineExpectations( $trxLimits['POST'], $fname );
+                       DeferredUpdates::addCallableUpdate( function () use ( $trxProfiler, $trxLimits, $fname
+                       ) {
+                               $trxProfiler->redefineExpectations( $trxLimits['PostSend-POST'], $fname );
+                       } );
+               }
        }
 
-       public function doesWrites() {
-               return true;
+       private function showRollbackConfirmationForm() {
+               $form = $this->getForm();
+               if ( $form->show() ) {
+                       $this->onSuccess();
+               }
+       }
+
+       protected function getFormFields() {
+               return [
+                       'intro' => [
+                               'type' => 'info',
+                               'vertical-label' => true,
+                               'raw' => true,
+                               'default' => $this->msg( 'confirm-rollback-bottom' )->parse()
+                       ]
+               ];
+       }
+
+       private function hasRollbackRelatedErrors( array $errors ) {
+               return isset( $errors[0][0] ) &&
+                       ( $errors[0][0] == 'alreadyrolled' ||
+                               $errors[0][0] == 'cantrollback'
+                       );
        }
 }
index aaccc0c..0eba613 100644 (file)
@@ -173,21 +173,6 @@ class WatchAction extends FormAction {
                return $user->getEditToken( $action );
        }
 
-       /**
-        * Get token to unwatch (or watch) a page for a user
-        *
-        * @param Title $title Title object of page to unwatch
-        * @param User $user User for whom the action is going to be performed
-        * @param string $action Optionally override the action to 'watch'
-        * @return string Token
-        * @since 1.18
-        * @deprecated since 1.32 Use WatchAction::getWatchToken() with action 'unwatch' directly.
-        */
-       public static function getUnwatchToken( Title $title, User $user, $action = 'unwatch' ) {
-               wfDeprecated( __METHOD__, '1.32' );
-               return self::getWatchToken( $title, $user, $action );
-       }
-
        public function doesWrites() {
                return true;
        }
index d3a32d0..c9c1b51 100644 (file)
@@ -55,18 +55,20 @@ class HistoryPager extends ReverseChronologicalPager {
         * @param string $month
         * @param string $tagFilter
         * @param array $conds
+        * @param string $day
         */
        public function __construct(
                HistoryAction $historyPage,
                $year = '',
                $month = '',
                $tagFilter = '',
-               array $conds = []
+               array $conds = [],
+               $day = ''
        ) {
                parent::__construct( $historyPage->getContext() );
                $this->historyPage = $historyPage;
                $this->tagFilter = $tagFilter;
-               $this->getDateCond( $year, $month );
+               $this->getDateCond( $year, $month, $day );
                $this->conds = $conds;
                $this->showTagEditUI = ChangeTags::showTagEditingUI( $this->getUser() );
        }
@@ -183,7 +185,7 @@ class HistoryPager extends ReverseChronologicalPager {
                $s .= Html::hidden( 'type', 'revision' ) . "\n";
 
                // Button container stored in $this->buttons for re-use in getEndBody()
-               $this->buttons = '<div>';
+               $this->buttons = Html::openElement( 'div', [ 'class' => 'mw-history-compareselectedversions' ] );
                $className = 'historysubmit mw-history-compareselectedversions-button';
                $attrs = [ 'class' => $className ]
                        + Linker::tooltipAndAccesskeyAttribs( 'compareselectedversions' );
@@ -310,11 +312,12 @@ class HistoryPager extends ReverseChronologicalPager {
 
                $curlink = $this->curLink( $rev, $latest );
                $lastlink = $this->lastLink( $rev, $next );
-               $curLastlinks = $curlink . $this->historyPage->message['pipe-separator'] . $lastlink;
+               $curLastlinks = Html::rawElement( 'span', [], $curlink ) .
+                       Html::rawElement( 'span', [], $lastlink );
                $histLinks = Html::rawElement(
                        'span',
-                       [ 'class' => 'mw-history-histlinks' ],
-                       $this->msg( 'parentheses' )->rawParams( $curLastlinks )->escaped()
+                       [ 'class' => 'mw-history-histlinks mw-changeslist-links' ],
+                       $curLastlinks
                );
 
                $diffButtons = $this->diffButtons( $rev, $firstInList );
@@ -362,7 +365,7 @@ class HistoryPager extends ReverseChronologicalPager {
                $s .= " $link";
                $s .= $dirmark;
                $s .= " <span class='history-user'>" .
-                       Linker::revUserTools( $rev, true ) . "</span>";
+                       Linker::revUserTools( $rev, true, false ) . "</span>";
                $s .= $dirmark;
 
                if ( $rev->isMinor() ) {
@@ -374,12 +377,12 @@ class HistoryPager extends ReverseChronologicalPager {
                        # Size is always public data
                        $prevSize = $this->parentLens[$row->rev_parent_id] ?? 0;
                        $sDiff = ChangesList::showCharacterDifference( $prevSize, $rev->getSize() );
-                       $fSize = Linker::formatRevisionSize( $rev->getSize() );
-                       $s .= ' <span class="mw-changeslist-separator">. .</span> ' . "$fSize $sDiff";
+                       $fSize = Linker::formatRevisionSize( $rev->getSize(), false );
+                       $s .= ' <span class="mw-changeslist-separator"></span> ' . "$fSize $sDiff";
                }
 
                # Text following the character difference is added just before running hooks
-               $s2 = Linker::revComment( $rev, false, true );
+               $s2 = Linker::revComment( $rev, false, true, false );
 
                if ( $notificationtimestamp && ( $row->rev_timestamp >= $notificationtimestamp ) ) {
                        $s2 .= ' <span class="updatedmarker">' . $this->msg( 'updatedmarker' )->escaped() . '</span>';
@@ -427,7 +430,11 @@ class HistoryPager extends ReverseChronologicalPager {
                Hooks::run( 'HistoryRevisionTools', [ $rev, &$tools, $prevRev, $user ] );
 
                if ( $tools ) {
-                       $s2 .= ' ' . $this->msg( 'parentheses' )->rawParams( $lang->pipeList( $tools ) )->escaped();
+                       $s2 .= ' ' . Html::openElement( 'span', [ 'class' => 'mw-changeslist-links' ] );
+                       foreach ( $tools as $tool ) {
+                               $s2 .= Html::rawElement( 'span', [], $tool );
+                       }
+                       $s2 .= Html::closeElement( 'span' );
                }
 
                # Tags
@@ -443,7 +450,7 @@ class HistoryPager extends ReverseChronologicalPager {
 
                # Include separator between character difference and following text
                if ( $s2 !== '' ) {
-                       $s .= ' <span class="mw-changeslist-separator">. .</span> ' . $s2;
+                       $s .= ' <span class="mw-changeslist-separator"></span> ' . $s2;
                }
 
                $attribs = [ 'data-mw-revid' => $rev->getId() ];
@@ -468,22 +475,8 @@ class HistoryPager extends ReverseChronologicalPager {
         * @return string
         */
        function revLink( $rev ) {
-               $date = $this->getLanguage()->userTimeAndDate( $rev->getTimestamp(), $this->getUser() );
-               if ( $rev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) {
-                       $link = MediaWikiServices::getInstance()->getLinkRenderer()->makeKnownLink(
-                               $this->getTitle(),
-                               $date,
-                               [ 'class' => 'mw-changeslist-date' ],
-                               [ 'oldid' => $rev->getId() ]
-                       );
-               } else {
-                       $link = htmlspecialchars( $date );
-               }
-               if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
-                       $link = "<span class=\"history-deleted\">$link</span>";
-               }
-
-               return $link;
+               return ChangesList::revDateLink( $rev, $this->getUser(), $this->getLanguage(),
+                       $this->getTitle() );
        }
 
        /**
@@ -609,6 +602,15 @@ class HistoryPager extends ReverseChronologicalPager {
                }
        }
 
+       /**
+        * @inheritDoc
+        */
+       function getDefaultQuery() {
+               parent::getDefaultQuery();
+               unset( $this->mDefaultQuery['date-range-to'] );
+               return $this->mDefaultQuery;
+       }
+
        /**
         * This is called if a write operation is possible from the generated HTML
         * @param bool $enable
index e37b4d4..2f66277 100644 (file)
@@ -345,10 +345,10 @@ class ApiAuthManagerHelper {
        /**
         * Fetch the standard parameters this helper recognizes
         * @param string $action AuthManager action
-        * @param string $param,... Parameters to use
+        * @param string ...$wantedParams Parameters to use
         * @return array
         */
-       public static function getStandardParams( $action, $param /* ... */ ) {
+       public static function getStandardParams( $action, ...$wantedParams ) {
                $params = [
                        'requests' => [
                                ApiBase::PARAM_TYPE => 'string',
@@ -384,8 +384,6 @@ class ApiAuthManagerHelper {
                ];
 
                $ret = [];
-               $wantedParams = func_get_args();
-               array_shift( $wantedParams );
                foreach ( $wantedParams as $name ) {
                        if ( isset( $params[$name] ) ) {
                                $ret[$name] = $params[$name];
index 9b3d116..7cb2dbf 100644 (file)
@@ -20,8 +20,9 @@
  * @file
  */
 
-use Wikimedia\Rdbms\IDatabase;
+use MediaWiki\Block\AbstractBlock;
 use MediaWiki\MediaWikiServices;
+use Wikimedia\Rdbms\IDatabase;
 
 /**
  * This abstract class implements many basic API functions, and is the base of
@@ -37,6 +38,8 @@ use MediaWiki\MediaWikiServices;
  */
 abstract class ApiBase extends ContextSource {
 
+       use ApiBlockInfoTrait;
+
        /**
         * @name Constants for ::getAllowedParams() arrays
         * These constants are keys in the arrays returned by ::getAllowedParams()
@@ -800,6 +803,7 @@ abstract class ApiBase extends ContextSource {
                                        // $results if all are done.
                                        unset( $targets[$placeholder] );
                                        $placeholder = '{' . $placeholder . '}';
+                                       // @phan-suppress-next-line PhanTypeNoAccessiblePropertiesForeach
                                        foreach ( $results[$target] as $value ) {
                                                if ( !preg_match( '/^[^{}]*$/', $value ) ) {
                                                        // Skip values that make invalid parameter names.
@@ -1196,7 +1200,8 @@ abstract class ApiBase extends ContextSource {
                        $provided = $this->getMain()->getCheck( $encParamName );
 
                        if ( isset( $value ) && $type == 'namespace' ) {
-                               $type = MWNamespace::getValidNamespaces();
+                               $type = MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                       getValidNamespaces();
                                if ( isset( $paramSettings[self::PARAM_EXTRA_NAMESPACES] ) &&
                                        is_array( $paramSettings[self::PARAM_EXTRA_NAMESPACES] )
                                ) {
@@ -1811,7 +1816,7 @@ abstract class ApiBase extends ContextSource {
                        if ( is_string( $error[0] ) && isset( self::$blockMsgMap[$error[0]] ) && $user->getBlock() ) {
                                list( $msg, $code ) = self::$blockMsgMap[$error[0]];
                                $status->fatal( ApiMessage::create( $msg, $code,
-                                       [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $user->getBlock() ) ]
+                                       [ 'blockinfo' => $this->getBlockDetails( $user->getBlock() ) ]
                                ) );
                        } else {
                                $status->fatal( ...$error );
@@ -1834,7 +1839,7 @@ abstract class ApiBase extends ContextSource {
                foreach ( self::$blockMsgMap as $msg => list( $apiMsg, $code ) ) {
                        if ( $status->hasMessage( $msg ) && $user->getBlock() ) {
                                $status->replaceMessage( $msg, ApiMessage::create( $apiMsg, $code,
-                                       [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $user->getBlock() ) ]
+                                       [ 'blockinfo' => $this->getBlockDetails( $user->getBlock() ) ]
                                ) );
                        }
                }
@@ -2024,28 +2029,28 @@ abstract class ApiBase extends ContextSource {
         * error handler and die with an error message including block info.
         *
         * @since 1.27
-        * @param Block $block The block used to generate the ApiUsageException
+        * @param AbstractBlock $block The block used to generate the ApiUsageException
         * @throws ApiUsageException always
         */
-       public function dieBlocked( Block $block ) {
+       public function dieBlocked( AbstractBlock $block ) {
                // Die using the appropriate message depending on block type
                if ( $block->getType() == Block::TYPE_AUTO ) {
                        $this->dieWithError(
                                'apierror-autoblocked',
                                'autoblocked',
-                               [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $block ) ]
+                               [ 'blockinfo' => $this->getBlockDetails( $block ) ]
                        );
                } elseif ( !$block->isSitewide() ) {
                        $this->dieWithError(
                                'apierror-blocked-partial',
                                'blocked',
-                               [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $block ) ]
+                               [ 'blockinfo' => $this->getBlockDetails( $block ) ]
                        );
                } else {
                        $this->dieWithError(
                                'apierror-blocked',
                                'blocked',
-                               [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $block ) ]
+                               [ 'blockinfo' => $this->getBlockDetails( $block ) ]
                        );
                }
        }
@@ -2137,11 +2142,6 @@ abstract class ApiBase extends ContextSource {
                }
 
                if ( $errors ) {
-                       // track block notices
-                       if ( $this->getConfig()->get( 'EnableBlockNoticeStats' ) ) {
-                               $this->trackBlockNotices( $errors );
-                       }
-
                        if ( !empty( $options['autoblock'] ) ) {
                                $user->spreadAnyEditBlock();
                        }
@@ -2150,30 +2150,6 @@ abstract class ApiBase extends ContextSource {
                }
        }
 
-       /**
-        * Keep track of errors messages resulting from a block
-        *
-        * @param array $errors
-        */
-       private function trackBlockNotices( array $errors ) {
-               $errorMessageKeys = [
-                       'blockedtext',
-                       'blockedtext-partial',
-                       'autoblockedtext',
-                       'systemblockedtext',
-               ];
-
-               $statsd = MediaWikiServices::getInstance()->getStatsdDataFactory();
-
-               foreach ( $errors as $error ) {
-                       if ( in_array( $error[0], $errorMessageKeys ) ) {
-                               $wiki = $this->getConfig()->get( 'DBname' );
-                               $statsd->increment( 'BlockNotices.' . $wiki . '.MediaWikiApi.returned' );
-                               break;
-                       }
-               }
-       }
-
        /**
         * Will only set a warning instead of failing if the global $wgDebugAPI
         * is set to true. Otherwise behaves exactly as self::dieWithError().
@@ -2709,24 +2685,6 @@ abstract class ApiBase extends ContextSource {
                ] ];
        }
 
-       /**
-        * Truncate an array to a certain length.
-        * @deprecated since 1.32, no replacement
-        * @param array &$arr Array to truncate
-        * @param int $limit Maximum length
-        * @return bool True if the array was truncated, false otherwise
-        */
-       public static function truncateArray( &$arr, $limit ) {
-               wfDeprecated( __METHOD__, '1.32' );
-               $modified = false;
-               while ( count( $arr ) > $limit ) {
-                       array_pop( $arr );
-                       $modified = true;
-               }
-
-               return $modified;
-       }
-
        /**@}*/
 }
 
index 14177ed..f7c2bce 100644 (file)
@@ -28,6 +28,8 @@
  */
 class ApiBlock extends ApiBase {
 
+       use ApiBlockInfoTrait;
+
        /**
         * Blocks the user specified in the parameters for the given expiry, with the
         * given reason, and with all other settings provided in the params. If the block
@@ -43,13 +45,14 @@ class ApiBlock extends ApiBase {
                $this->requireOnlyOneParameter( $params, 'user', 'userid' );
 
                # T17810: blocked admins should have limited access here
-               if ( $user->isBlocked() ) {
+               $block = $user->getBlock();
+               if ( $block ) {
                        $status = SpecialBlock::checkUnblockSelf( $params['user'], $user );
                        if ( $status !== true ) {
                                $this->dieWithError(
                                        $status,
                                        null,
-                                       [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $user->getBlock() ) ]
+                                       [ 'blockinfo' => $this->getBlockDetails( $block ) ]
                                );
                        }
                }
@@ -135,7 +138,7 @@ class ApiBlock extends ApiBase {
 
                $block = Block::newFromTarget( $target, null, true );
                if ( $block instanceof Block ) {
-                       $res['expiry'] = ApiResult::formatExpiry( $block->mExpiry, 'infinite' );
+                       $res['expiry'] = ApiResult::formatExpiry( $block->getExpiry(), 'infinite' );
                        $res['id'] = $block->getId();
                } else {
                        # should be unreachable
diff --git a/includes/api/ApiBlockInfoTrait.php b/includes/api/ApiBlockInfoTrait.php
new file mode 100644 (file)
index 0000000..587a51f
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+use MediaWiki\Block\AbstractBlock;
+use MediaWiki\Block\SystemBlock;
+
+/**
+ * @ingroup API
+ */
+trait ApiBlockInfoTrait {
+
+       /**
+        * Get basic info about a given block
+        * @param AbstractBlock $block
+        * @return array Array containing several keys:
+        *  - blockid - ID of the block
+        *  - blockedby - username of the blocker
+        *  - blockedbyid - user ID of the blocker
+        *  - blockreason - reason provided for the block
+        *  - blockedtimestamp - timestamp for when the block was placed/modified
+        *  - blockexpiry - expiry time of the block
+        *  - systemblocktype - system block type, if any
+        */
+       private function getBlockDetails( AbstractBlock $block ) {
+               $vals = [];
+               $vals['blockid'] = $block->getId();
+               $vals['blockedby'] = $block->getByName();
+               $vals['blockedbyid'] = $block->getBy();
+               $vals['blockreason'] = $block->getReason();
+               $vals['blockedtimestamp'] = wfTimestamp( TS_ISO_8601, $block->getTimestamp() );
+               $vals['blockexpiry'] = ApiResult::formatExpiry( $block->getExpiry(), 'infinite' );
+               $vals['blockpartial'] = !$block->isSitewide();
+               if ( $block instanceof SystemBlock ) {
+                       $vals['systemblocktype'] = $block->getSystemBlockType();
+               }
+               return $vals;
+       }
+
+}
index 4ba30ab..1eb5e8d 100644 (file)
@@ -307,10 +307,8 @@ class ApiComparePages extends ApiBase {
                foreach ( [ 'from', 'to' ] as $prefix ) {
                        if ( $params["{$prefix}rev"] !== null ) {
                                $rev = $this->getRevisionById( $params["{$prefix}rev"] );
-                               if ( $rev ) {
-                                       if ( $rev->hasSlot( $role ) ) {
-                                               return $rev->getSlot( $role, RevisionRecord::RAW )->getModel();
-                                       }
+                               if ( $rev && $rev->hasSlot( $role ) ) {
+                                       return $rev->getSlot( $role, RevisionRecord::RAW )->getModel();
                                }
                        }
                }
index 7da8ed9..e4c52dd 100644 (file)
@@ -217,6 +217,8 @@ class ApiContinuationManager {
                        // Some modules are unfinished: include those params, and copy
                        // the generator params.
                        foreach ( $continuationData as $module => $kvp ) {
+                               // XXX: Not sure why phan is complaining here...
+                               // @phan-suppress-next-line PhanTypeInvalidLeftOperand
                                $data += $kvp;
                        }
                        $generatorParams = [];
index 7e8041d..0e13d70 100644 (file)
@@ -75,7 +75,7 @@ class ApiDelete extends ApiBase {
                        $status = self::delete( $pageObj, $user, $reason, $params['tags'] );
                }
 
-               if ( !$status->isOk() ) {
+               if ( !$status->isOK() ) {
                        $this->dieStatus( $status );
                }
                $this->addMessagesFromStatus( $status, [ 'warning' ], [ 'delete-scheduled' ] );
index 9669464..8049cd8 100644 (file)
@@ -388,111 +388,3 @@ class ApiErrorFormatter {
                }
        }
 }
-
-/**
- * Format errors and warnings in the old style, for backwards compatibility.
- * @since 1.25
- * @deprecated Only for backwards compatibility, do not use
- * @ingroup API
- */
-// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
-class ApiErrorFormatter_BackCompat extends ApiErrorFormatter {
-
-       /**
-        * @param ApiResult $result Into which data will be added
-        */
-       public function __construct( ApiResult $result ) {
-               parent::__construct( $result, Language::factory( 'en' ), 'none', false );
-       }
-
-       public function getFormat() {
-               return 'bc';
-       }
-
-       public function arrayFromStatus( StatusValue $status, $type = 'error', $format = null ) {
-               if ( $status->isGood() || !$status->getErrors() ) {
-                       return [];
-               }
-
-               $result = [];
-               foreach ( $status->getErrorsByType( $type ) as $error ) {
-                       $msg = ApiMessage::create( $error );
-                       $error = [
-                               'message' => $msg->getKey(),
-                               'params' => $msg->getParams(),
-                               'code' => $msg->getApiCode(),
-                       ] + $error;
-                       ApiResult::setIndexedTagName( $error['params'], 'param' );
-                       $result[] = $error;
-               }
-               ApiResult::setIndexedTagName( $result, $type );
-
-               return $result;
-       }
-
-       protected function formatMessageInternal( $msg, $format ) {
-               return [
-                       'code' => $msg->getApiCode(),
-                       'info' => $msg->text(),
-               ] + $msg->getApiData();
-       }
-
-       /**
-        * Format an exception as an array
-        * @since 1.29
-        * @param Exception|Throwable $exception
-        * @param array $options See parent::formatException(), plus
-        *  - bc: (bool) Return only the string, not an array
-        * @return array|string
-        */
-       public function formatException( $exception, array $options = [] ) {
-               $ret = parent::formatException( $exception, $options );
-               return empty( $options['bc'] ) ? $ret : $ret['info'];
-       }
-
-       protected function addWarningOrError( $tag, $modulePath, $msg ) {
-               $value = self::stripMarkup( $msg->text() );
-
-               if ( $tag === 'error' ) {
-                       // In BC mode, only one error
-                       $existingError = $this->result->getResultData( [ 'error' ] );
-                       if ( !is_array( $existingError ) ||
-                               !isset( $existingError['code'] ) || !isset( $existingError['info'] )
-                       ) {
-                               $value = [
-                                       'code' => $msg->getApiCode(),
-                                       'info' => $value,
-                               ] + $msg->getApiData();
-                               $this->result->addValue( null, 'error', $value,
-                                       ApiResult::OVERRIDE | ApiResult::ADD_ON_TOP | ApiResult::NO_SIZE_CHECK );
-                       }
-               } else {
-                       if ( $modulePath === null ) {
-                               $moduleName = 'unknown';
-                       } else {
-                               $i = strrpos( $modulePath, '+' );
-                               $moduleName = $i === false ? $modulePath : substr( $modulePath, $i + 1 );
-                       }
-
-                       // Don't add duplicate warnings
-                       $tag .= 's';
-                       $path = [ $tag, $moduleName ];
-                       $oldWarning = $this->result->getResultData( [ $tag, $moduleName, $tag ] );
-                       if ( $oldWarning !== null ) {
-                               $warnPos = strpos( $oldWarning, $value );
-                               // If $value was found in $oldWarning, check if it starts at 0 or after "\n"
-                               if ( $warnPos !== false && ( $warnPos === 0 || $oldWarning[$warnPos - 1] === "\n" ) ) {
-                                       // Check if $value is followed by "\n" or the end of the $oldWarning
-                                       $warnPos += strlen( $value );
-                                       if ( strlen( $oldWarning ) <= $warnPos || $oldWarning[$warnPos] === "\n" ) {
-                                               return;
-                                       }
-                               }
-                               // If there is a warning already, append it to the existing one
-                               $value = "$oldWarning\n$value";
-                       }
-                       $this->result->addContentValue( $path, $tag, $value,
-                               ApiResult::OVERRIDE | ApiResult::ADD_ON_TOP | ApiResult::NO_SIZE_CHECK );
-               }
-       }
-}
diff --git a/includes/api/ApiErrorFormatter_BackCompat.php b/includes/api/ApiErrorFormatter_BackCompat.php
new file mode 100644 (file)
index 0000000..6aee4cb
--- /dev/null
@@ -0,0 +1,127 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * Format errors and warnings in the old style, for backwards compatibility.
+ * @since 1.25
+ * @deprecated Only for backwards compatibility, do not use
+ * @ingroup API
+ */
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
+class ApiErrorFormatter_BackCompat extends ApiErrorFormatter {
+
+       /**
+        * @param ApiResult $result Into which data will be added
+        */
+       public function __construct( ApiResult $result ) {
+               parent::__construct( $result, Language::factory( 'en' ), 'none', false );
+       }
+
+       public function getFormat() {
+               return 'bc';
+       }
+
+       public function arrayFromStatus( StatusValue $status, $type = 'error', $format = null ) {
+               if ( $status->isGood() || !$status->getErrors() ) {
+                       return [];
+               }
+
+               $result = [];
+               foreach ( $status->getErrorsByType( $type ) as $error ) {
+                       $msg = ApiMessage::create( $error );
+                       $error = [
+                               'message' => $msg->getKey(),
+                               'params' => $msg->getParams(),
+                               'code' => $msg->getApiCode(),
+                       ] + $error;
+                       ApiResult::setIndexedTagName( $error['params'], 'param' );
+                       $result[] = $error;
+               }
+               ApiResult::setIndexedTagName( $result, $type );
+
+               return $result;
+       }
+
+       protected function formatMessageInternal( $msg, $format ) {
+               return [
+                       'code' => $msg->getApiCode(),
+                       'info' => $msg->text(),
+               ] + $msg->getApiData();
+       }
+
+       /**
+        * Format an exception as an array
+        * @since 1.29
+        * @param Exception|Throwable $exception
+        * @param array $options See parent::formatException(), plus
+        *  - bc: (bool) Return only the string, not an array
+        * @return array|string
+        */
+       public function formatException( $exception, array $options = [] ) {
+               $ret = parent::formatException( $exception, $options );
+               return empty( $options['bc'] ) ? $ret : $ret['info'];
+       }
+
+       protected function addWarningOrError( $tag, $modulePath, $msg ) {
+               $value = self::stripMarkup( $msg->text() );
+
+               if ( $tag === 'error' ) {
+                       // In BC mode, only one error
+                       $existingError = $this->result->getResultData( [ 'error' ] );
+                       if ( !is_array( $existingError ) ||
+                               !isset( $existingError['code'] ) || !isset( $existingError['info'] )
+                       ) {
+                               $value = [
+                                       'code' => $msg->getApiCode(),
+                                       'info' => $value,
+                               ] + $msg->getApiData();
+                               $this->result->addValue( null, 'error', $value,
+                                       ApiResult::OVERRIDE | ApiResult::ADD_ON_TOP | ApiResult::NO_SIZE_CHECK );
+                       }
+               } else {
+                       if ( $modulePath === null ) {
+                               $moduleName = 'unknown';
+                       } else {
+                               $i = strrpos( $modulePath, '+' );
+                               $moduleName = $i === false ? $modulePath : substr( $modulePath, $i + 1 );
+                       }
+
+                       // Don't add duplicate warnings
+                       $tag .= 's';
+                       $path = [ $tag, $moduleName ];
+                       $oldWarning = $this->result->getResultData( [ $tag, $moduleName, $tag ] );
+                       if ( $oldWarning !== null ) {
+                               $warnPos = strpos( $oldWarning, $value );
+                               // If $value was found in $oldWarning, check if it starts at 0 or after "\n"
+                               if ( $warnPos !== false && ( $warnPos === 0 || $oldWarning[$warnPos - 1] === "\n" ) ) {
+                                       // Check if $value is followed by "\n" or the end of the $oldWarning
+                                       $warnPos += strlen( $value );
+                                       if ( strlen( $oldWarning ) <= $warnPos || $oldWarning[$warnPos] === "\n" ) {
+                                               return;
+                                       }
+                               }
+                               // If there is a warning already, append it to the existing one
+                               $value = "$oldWarning\n$value";
+                       }
+                       $this->result->addContentValue( $path, $tag, $value,
+                               ApiResult::OVERRIDE | ApiResult::ADD_ON_TOP | ApiResult::NO_SIZE_CHECK );
+               }
+       }
+}
index 22f5235..851373d 100644 (file)
@@ -86,7 +86,6 @@ class ApiExpandTemplates extends ApiBase {
                $result = $this->getResult();
 
                // Parse text
-               global $wgParser;
                $options = ParserOptions::newFromContext( $this->getContext() );
 
                if ( $params['includecomments'] ) {
@@ -100,9 +99,10 @@ class ApiExpandTemplates extends ApiBase {
 
                $retval = [];
 
+               $parser = MediaWikiServices::getInstance()->getParser();
                if ( isset( $prop['parsetree'] ) || $params['generatexml'] ) {
-                       $wgParser->startExternalParse( $titleObj, $options, Parser::OT_PREPROCESS );
-                       $dom = $wgParser->preprocessToDom( $params['text'] );
+                       $parser->startExternalParse( $titleObj, $options, Parser::OT_PREPROCESS );
+                       $dom = $parser->preprocessToDom( $params['text'] );
                        if ( is_callable( [ $dom, 'saveXML' ] ) ) {
                                $xml = $dom->saveXML();
                        } else {
@@ -121,14 +121,14 @@ class ApiExpandTemplates extends ApiBase {
                // if they didn't want any output except (probably) the parse tree,
                // then don't bother actually fully expanding it
                if ( $prop || $params['prop'] === null ) {
-                       $wgParser->startExternalParse( $titleObj, $options, Parser::OT_PREPROCESS );
-                       $frame = $wgParser->getPreprocessor()->newFrame();
-                       $wikitext = $wgParser->preprocess( $params['text'], $titleObj, $options, $revid, $frame );
+                       $parser->startExternalParse( $titleObj, $options, Parser::OT_PREPROCESS );
+                       $frame = $parser->getPreprocessor()->newFrame();
+                       $wikitext = $parser->preprocess( $params['text'], $titleObj, $options, $revid, $frame );
                        if ( $params['prop'] === null ) {
                                // the old way
                                ApiResult::setContentValue( $retval, 'wikitext', $wikitext );
                        } else {
-                               $p_output = $wgParser->getOutput();
+                               $p_output = $parser->getOutput();
                                if ( isset( $prop['categories'] ) ) {
                                        $categories = $p_output->getCategories();
                                        if ( $categories ) {
index e5dba8f..678b97b 100644 (file)
@@ -101,7 +101,7 @@ class ApiFeedRecentChanges extends ApiBase {
                                $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $this->params['target'] ) ] );
                        }
 
-                       $feed = new ChangesFeed( $feedFormat, false );
+                       $feed = new ChangesFeed( $feedFormat );
                        $feedObj = $feed->getFeedObject(
                                $this->msg( 'recentchangeslinked-title', $title->getPrefixedText() )
                                        ->inContentLanguage()->text(),
@@ -109,7 +109,7 @@ class ApiFeedRecentChanges extends ApiBase {
                                SpecialPage::getTitleFor( 'Recentchangeslinked' )->getFullURL()
                        );
                } else {
-                       $feed = new ChangesFeed( $feedFormat, 'rcfeed' );
+                       $feed = new ChangesFeed( $feedFormat );
                        $feedObj = $feed->getFeedObject(
                                $this->msg( 'recentchanges' )->inContentLanguage()->text(),
                                $this->msg( 'recentchanges-feed-description' )->inContentLanguage()->text(),
index 11b5d91..c4977f4 100644 (file)
@@ -20,6 +20,8 @@
  * @file
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * This action allows users to get their watchlist items in RSS/Atom formats.
  * When executed, it performs a nested call to the API to get the needed data,
@@ -209,8 +211,8 @@ class ApiFeedWatchlist extends ApiBase {
                if ( $this->linkToSections && $comment !== null &&
                        preg_match( '!(.*)/\*\s*(.*?)\s*\*/(.*)!', $comment, $matches )
                ) {
-                       global $wgParser;
-                       $titleUrl .= $wgParser->guessSectionNameFromWikiText( $matches[ 2 ] );
+                       $titleUrl .= MediaWikiServices::getInstance()->getParser()
+                               ->guessSectionNameFromWikiText( $matches[ 2 ] );
                }
 
                $timestamp = $info['timestamp'];
index e033525..bff9fd0 100644 (file)
@@ -158,11 +158,9 @@ abstract class ApiFormatBase extends ApiBase {
 
                if ( !is_array( $paramSettings ) ) {
                        return $paramSettings;
-               } elseif ( isset( $paramSettings[self::PARAM_DFLT] ) ) {
-                       return $paramSettings[self::PARAM_DFLT];
-               } else {
-                       return null;
                }
+
+               return $paramSettings[self::PARAM_DFLT] ?? null;
        }
 
        /**
index 262eb1f..40cc738 100644 (file)
@@ -79,7 +79,9 @@ class ApiFormatFeedWrapper extends ApiFormatBase {
 
                $data = $this->getResult()->getResultData();
                if ( isset( $data['_feed'] ) && isset( $data['_feeditems'] ) ) {
-                       $data['_feed']->httpHeaders();
+                       /** @var ChannelFeed $feed */
+                       $feed = $data['_feed'];
+                       $feed->httpHeaders();
                } else {
                        // Error has occurred, print something useful
                        ApiBase::dieDebug( __METHOD__, 'Invalid feed class/item' );
@@ -94,6 +96,7 @@ class ApiFormatFeedWrapper extends ApiFormatBase {
        public function execute() {
                $data = $this->getResult()->getResultData();
                if ( isset( $data['_feed'] ) && isset( $data['_feeditems'] ) ) {
+                       /** @var ChannelFeed $feed */
                        $feed = $data['_feed'];
                        $items = $data['_feeditems'];
 
index 9ec4a2c..1d83f73 100644 (file)
@@ -35,11 +35,8 @@ class ApiFormatRaw extends ApiFormatBase {
         */
        public function __construct( ApiMain $main, ApiFormatBase $errorFallback = null ) {
                parent::__construct( $main, 'raw' );
-               if ( $errorFallback === null ) {
-                       $this->errorFallback = $main->createPrinterByName( $main->getParameter( 'format' ) );
-               } else {
-                       $this->errorFallback = $errorFallback;
-               }
+               $this->errorFallback = $errorFallback ?:
+                       $main->createPrinterByName( $main->getParameter( 'format' ) );
        }
 
        public function getMimeType() {
diff --git a/includes/api/ApiFormatXmlRsd.php b/includes/api/ApiFormatXmlRsd.php
new file mode 100644 (file)
index 0000000..6b892fa
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * Copyright © 2010 Bryan Tong Minh and Brion Vibber
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+class ApiFormatXmlRsd extends ApiFormatXml {
+       public function __construct( ApiMain $main, $format ) {
+               parent::__construct( $main, $format );
+               $this->setRootElement( 'rsd' );
+       }
+
+       public function getMimeType() {
+               return 'application/rsd+xml';
+       }
+
+       public static function recXmlPrint( $name, $value, $indent, $attributes = [] ) {
+               unset( $attributes['_idx'] );
+               return parent::recXmlPrint( $name, $value, $indent, $attributes );
+       }
+}
index 886dbcc..78efe41 100644 (file)
@@ -559,11 +559,9 @@ class ApiHelp extends ApiBase {
                                                                                $arr = &$submodules;
                                                                                try {
                                                                                        $submod = $module->getModuleFromPath( $m );
-                                                                                       if ( $submod ) {
-                                                                                               if ( $submod->isDeprecated() ) {
-                                                                                                       $arr = &$deprecatedSubmodules;
-                                                                                                       $attrs['class'] = 'apihelp-deprecated-value';
-                                                                                               }
+                                                                                       if ( $submod && $submod->isDeprecated() ) {
+                                                                                               $arr = &$deprecatedSubmodules;
+                                                                                               $attrs['class'] = 'apihelp-deprecated-value';
                                                                                        }
                                                                                } catch ( ApiUsageException $ex ) {
                                                                                        // Ignore
@@ -585,7 +583,8 @@ class ApiHelp extends ApiBase {
                                                                        break;
 
                                                                case 'namespace':
-                                                                       $namespaces = MWNamespace::getValidNamespaces();
+                                                                       $namespaces = MediaWikiServices::getInstance()->
+                                                                               getNamespaceInfo()->getValidNamespaces();
                                                                        if ( isset( $settings[ApiBase::PARAM_EXTRA_NAMESPACES] ) &&
                                                                                is_array( $settings[ApiBase::PARAM_EXTRA_NAMESPACES] )
                                                                        ) {
index 21e2694..7045138 100644 (file)
@@ -33,8 +33,6 @@ class ApiImageRotate extends ApiBase {
                $pageSet = $this->getPageSet();
                $pageSet->execute();
 
-               $result = [];
-
                $result = $pageSet->getInvalidTitlesAndRevisions( [
                        'invalidTitles', 'special', 'missingIds', 'missingRevIds', 'interwikiTitles',
                ] );
index 596ab75..b36045e 100644 (file)
@@ -181,42 +181,3 @@ class ApiImport extends ApiBase {
                return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Import';
        }
 }
-
-/**
- * Import reporter for the API
- * @ingroup API
- */
-class ApiImportReporter extends ImportReporter {
-       private $mResultArr = [];
-
-       /**
-        * @param Title $title
-        * @param Title $origTitle
-        * @param int $revisionCount
-        * @param int $successCount
-        * @param array $pageInfo
-        * @return void
-        */
-       public function reportPage( $title, $origTitle, $revisionCount, $successCount, $pageInfo ) {
-               // Add a result entry
-               $r = [];
-
-               if ( $title === null ) {
-                       # Invalid or non-importable title
-                       $r['title'] = $pageInfo['title'];
-                       $r['invalid'] = true;
-               } else {
-                       ApiQueryBase::addTitleInfo( $r, $title );
-                       $r['revisions'] = (int)$successCount;
-               }
-
-               $this->mResultArr[] = $r;
-
-               // Piggyback on the parent to do the logging
-               parent::reportPage( $title, $origTitle, $revisionCount, $successCount, $pageInfo );
-       }
-
-       public function getData() {
-               return $this->mResultArr;
-       }
-}
diff --git a/includes/api/ApiImportReporter.php b/includes/api/ApiImportReporter.php
new file mode 100644 (file)
index 0000000..21d9d23
--- /dev/null
@@ -0,0 +1,60 @@
+<?php
+/**
+ * Copyright © 2009 Roan Kattouw "<Firstname>.<Lastname>@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
+ */
+
+/**
+ * Import reporter for the API
+ * @ingroup API
+ */
+class ApiImportReporter extends ImportReporter {
+       private $mResultArr = [];
+
+       /**
+        * @param Title $title
+        * @param Title $origTitle
+        * @param int $revisionCount
+        * @param int $successCount
+        * @param array $pageInfo
+        * @return void
+        */
+       public function reportPage( $title, $origTitle, $revisionCount, $successCount, $pageInfo ) {
+               // Add a result entry
+               $r = [];
+
+               if ( $title === null ) {
+                       # Invalid or non-importable title
+                       $r['title'] = $pageInfo['title'];
+                       $r['invalid'] = true;
+               } else {
+                       ApiQueryBase::addTitleInfo( $r, $title );
+                       $r['revisions'] = (int)$successCount;
+               }
+
+               $this->mResultArr[] = $r;
+
+               // Piggyback on the parent to do the logging
+               parent::reportPage( $title, $origTitle, $revisionCount, $successCount, $pageInfo );
+       }
+
+       public function getData() {
+               return $this->mResultArr;
+       }
+}
index 133f0ce..c3c5318 100644 (file)
@@ -107,7 +107,6 @@ class ApiLogin extends ApiBase {
                }
 
                $authRes = false;
-               $context = new DerivativeContext( $this->getContext() );
                $loginType = 'N/A';
 
                // Check login token
@@ -268,8 +267,6 @@ class ApiLogin extends ApiBase {
 
        protected function getExamplesMessages() {
                return [
-                       'action=login&lgname=user&lgpassword=password'
-                               => 'apihelp-login-example-gettoken',
                        'action=login&lgname=user&lgpassword=password&lgtoken=123ABC'
                                => 'apihelp-login-example-login',
                ];
index c663d1e..d549e75 100644 (file)
@@ -59,13 +59,25 @@ class ApiLogout extends ApiBase {
                Hooks::run( 'UserLogoutComplete', [ &$user, &$injected_html, $oldName ] );
        }
 
+       public function mustBePosted() {
+               return true;
+       }
+
+       public function needsToken() {
+               return 'csrf';
+       }
+
+       protected function getWebUITokenSalt( array $params ) {
+               return 'logoutToken';
+       }
+
        public function isReadMode() {
                return false;
        }
 
        protected function getExamplesMessages() {
                return [
-                       'action=logout'
+                       'action=logout&token=123ABC'
                                => 'apihelp-logout-example-logout',
                ];
        }
index 295d5d0..1a7175a 100644 (file)
@@ -218,7 +218,7 @@ class ApiMain extends ApiBase {
                                                'cookies' => $sessionCookies,
                                                'ip' => $request->getIP(),
                                                'userAgent' => $this->getUserAgent(),
-                                               'wiki' => wfWikiID(),
+                                               'wiki' => WikiMap::getCurrentWikiDbDomain()->getId(),
                                        ]
                                );
                        }
@@ -321,7 +321,7 @@ class ApiMain extends ApiBase {
                $request = $this->getRequest();
 
                // JSONP mode
-               if ( $request->getVal( 'callback' ) !== null ) {
+               if ( $request->getCheck( 'callback' ) ) {
                        $this->lacksSameOriginSecurity = true;
                        return true;
                }
@@ -1117,19 +1117,17 @@ class ApiMain extends ApiBase {
                                        . $this->msg( 'api-usage-mailinglist-ref' )->inLanguage( $formatter->getLanguage() )->text()
                                )
                        );
-               } else {
-                       if ( $config->get( 'ShowExceptionDetails' ) ) {
-                               $result->addContentValue(
-                                       $path,
-                                       'trace',
-                                       $this->msg( 'api-exception-trace',
-                                               get_class( $e ),
-                                               $e->getFile(),
-                                               $e->getLine(),
-                                               MWExceptionHandler::getRedactedTraceAsString( $e )
-                                       )->inLanguage( $formatter->getLanguage() )->text()
-                               );
-                       }
+               } elseif ( $config->get( 'ShowExceptionDetails' ) ) {
+                       $result->addContentValue(
+                               $path,
+                               'trace',
+                               $this->msg( 'api-exception-trace',
+                                       get_class( $e ),
+                                       $e->getFile(),
+                                       $e->getLine(),
+                                       MWExceptionHandler::getRedactedTraceAsString( $e )
+                               )->inLanguage( $formatter->getLanguage() )->text()
+                       );
                }
 
                // Add the id and such
@@ -1633,7 +1631,7 @@ class ApiMain extends ApiBase {
                        'ts' => time(),
                        'ip' => $request->getIP(),
                        'userAgent' => $this->getUserAgent(),
-                       'wiki' => wfWikiID(),
+                       'wiki' => WikiMap::getCurrentWikiDbDomain()->getId(),
                        'timeSpentBackend' => (int)round( $time * 1000 ),
                        'hadError' => $e !== null,
                        'errorCodes' => [],
@@ -1653,7 +1651,7 @@ class ApiMain extends ApiBase {
                                'method' => $request->getMethod(),
                                'client_ip' => $request->getIP()
                        ],
-                       'database' => wfWikiID(),
+                       'database' => WikiMap::getCurrentWikiDbDomain()->getId(),
                        'backend_time_ms' => (int)round( $time * 1000 ),
                ];
 
@@ -1840,7 +1838,7 @@ class ApiMain extends ApiBase {
         */
        protected function printResult( $httpCode = 0 ) {
                if ( $this->getConfig()->get( 'DebugAPI' ) !== false ) {
-                       $this->addWarning( 'apiwarn-wgDebugAPI' );
+                       $this->addWarning( 'apiwarn-wgdebugapi' );
                }
 
                $printer = $this->mPrinter;
index 416fc7f..8e2837b 100644 (file)
@@ -379,41 +379,3 @@ class ApiOpenSearch extends ApiBase {
                }
        }
 }
-
-/**
- * @ingroup API
- */
-class ApiOpenSearchFormatJson extends ApiFormatJson {
-       private $warningsAsError = false;
-
-       public function __construct( ApiMain $main, $fm, $warningsAsError ) {
-               parent::__construct( $main, "json$fm" );
-               $this->warningsAsError = $warningsAsError;
-       }
-
-       public function execute() {
-               $result = $this->getResult();
-               if ( !$result->getResultData( 'error' ) && !$result->getResultData( 'errors' ) ) {
-                       // Ignore warnings or treat as errors, as requested
-                       $warnings = $result->removeValue( 'warnings', null );
-                       if ( $this->warningsAsError && $warnings ) {
-                               $this->dieWithError(
-                                       'apierror-opensearch-json-warnings',
-                                       'warnings',
-                                       [ 'warnings' => $warnings ]
-                               );
-                       }
-
-                       // Ignore any other unexpected keys (e.g. from $wgDebugToolbar)
-                       $remove = array_keys( array_diff_key(
-                               $result->getResultData(),
-                               [ 0 => 'search', 1 => 'terms', 2 => 'descriptions', 3 => 'urls' ]
-                       ) );
-                       foreach ( $remove as $key ) {
-                               $result->removeValue( $key, null );
-                       }
-               }
-
-               parent::execute();
-       }
-}
diff --git a/includes/api/ApiOpenSearchFormatJson.php b/includes/api/ApiOpenSearchFormatJson.php
new file mode 100644 (file)
index 0000000..b1903f2
--- /dev/null
@@ -0,0 +1,61 @@
+<?php
+/**
+ * Copyright © 2006 Yuri Astrakhan "<Firstname><Lastname>@gmail.com"
+ * Copyright © 2008 Brion Vibber <brion@wikimedia.org>
+ * Copyright © 2014 Wikimedia Foundation and contributors
+ *
+ * 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 API
+ */
+class ApiOpenSearchFormatJson extends ApiFormatJson {
+       private $warningsAsError = false;
+
+       public function __construct( ApiMain $main, $fm, $warningsAsError ) {
+               parent::__construct( $main, "json$fm" );
+               $this->warningsAsError = $warningsAsError;
+       }
+
+       public function execute() {
+               $result = $this->getResult();
+               if ( !$result->getResultData( 'error' ) && !$result->getResultData( 'errors' ) ) {
+                       // Ignore warnings or treat as errors, as requested
+                       $warnings = $result->removeValue( 'warnings', null );
+                       if ( $this->warningsAsError && $warnings ) {
+                               $this->dieWithError(
+                                       'apierror-opensearch-json-warnings',
+                                       'warnings',
+                                       [ 'warnings' => $warnings ]
+                               );
+                       }
+
+                       // Ignore any other unexpected keys (e.g. from $wgDebugToolbar)
+                       $remove = array_keys( array_diff_key(
+                               $result->getResultData(),
+                               [ 0 => 'search', 1 => 'terms', 2 => 'descriptions', 3 => 'urls' ]
+                       ) );
+                       foreach ( $remove as $key ) {
+                               $result->removeValue( $key, null );
+                       }
+               }
+
+               parent::execute();
+       }
+}
index 450ebb6..64c6f45 100644 (file)
@@ -866,6 +866,8 @@ class ApiPageSet extends ApiBase {
                        ApiBase::dieDebug( __METHOD__, 'Missing $processTitles parameter when $remaining is provided' );
                }
 
+               $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
+
                $usernames = [];
                if ( $res ) {
                        foreach ( $res as $row ) {
@@ -884,7 +886,7 @@ class ApiPageSet extends ApiBase {
                                $this->processDbRow( $row );
 
                                // Need gender information
-                               if ( MWNamespace::hasGenderDistinction( $row->page_namespace ) ) {
+                               if ( $nsInfo->hasGenderDistinction( $row->page_namespace ) ) {
                                        $usernames[] = $row->page_title;
                                }
                        }
@@ -907,7 +909,7 @@ class ApiPageSet extends ApiBase {
                                                $this->mTitles[] = $title;
 
                                                // need gender information
-                                               if ( MWNamespace::hasGenderDistinction( $ns ) ) {
+                                               if ( $nsInfo->hasGenderDistinction( $ns ) ) {
                                                        $usernames[] = $dbkey;
                                                }
                                        }
@@ -1249,7 +1251,10 @@ class ApiPageSet extends ApiBase {
                        }
 
                        // Need gender information
-                       if ( MWNamespace::hasGenderDistinction( $titleObj->getNamespace() ) ) {
+                       if (
+                               MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                       hasGenderDistinction( $titleObj->getNamespace() )
+                       ) {
                                $usernames[] = $titleObj->getText();
                        }
                }
@@ -1398,10 +1403,10 @@ class ApiPageSet extends ApiBase {
                                                $data[$toPageId],
                                                $this->mGeneratorData[$fromNs][$fromDBkey]
                                        );
-                                       if ( $result instanceof ApiResult ) {
-                                               if ( !$result->addValue( $path, $toPageId, $data[$toPageId], ApiResult::OVERRIDE ) ) {
-                                                       return false;
-                                               }
+                                       if ( $result instanceof ApiResult &&
+                                               !$result->addValue( $path, $toPageId, $data[$toPageId], ApiResult::OVERRIDE )
+                                       ) {
+                                               return false;
                                        }
                                }
                        }
index 5e4639d..84fff96 100644 (file)
@@ -83,7 +83,7 @@ class ApiParse extends ApiBase {
                // The parser needs $wgTitle to be set, apparently the
                // $title parameter in Parser::parse isn't enough *sigh*
                // TODO: Does this still need $wgTitle?
-               global $wgParser, $wgTitle;
+               global $wgTitle;
 
                $redirValues = null;
 
@@ -488,8 +488,9 @@ class ApiParse extends ApiBase {
                                $this->dieWithError( 'apierror-parsetree-notwikitext', 'notwikitext' );
                        }
 
-                       $wgParser->startExternalParse( $titleObj, $popts, Parser::OT_PREPROCESS );
-                       $xml = $wgParser->preprocessToDom( $this->content->getText() )->__toString();
+                       $parser = MediaWikiServices::getInstance()->getParser();
+                       $parser->startExternalParse( $titleObj, $popts, Parser::OT_PREPROCESS );
+                       $xml = $parser->preprocessToDom( $this->content->getText() )->__toString();
                        $result_array['parsetree'] = $xml;
                        $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'parsetree';
                }
@@ -631,7 +632,6 @@ class ApiParse extends ApiBase {
         * @return Content|bool
         */
        private function formatSummary( $title, $params ) {
-               global $wgParser;
                $summary = $params['summary'] ?? '';
                $sectionTitle = $params['sectiontitle'] ?? '';
 
@@ -641,8 +641,9 @@ class ApiParse extends ApiBase {
                        }
                        if ( $summary !== '' ) {
                                $summary = wfMessage( 'newsectionsummary' )
-                                       ->rawParams( $wgParser->stripSectionName( $summary ) )
-                                               ->inContentLanguage()->text();
+                                       ->rawParams( MediaWikiServices::getInstance()->getParser()
+                                               ->stripSectionName( $summary ) )
+                                       ->inContentLanguage()->text();
                        }
                }
                return Linker::formatComment( $summary, $title, $this->section === 'new' );
index bb50185..beaad43 100644 (file)
@@ -49,7 +49,8 @@ class ApiQueryAllDeletedRevisions extends ApiQueryRevisionsBase {
                $user = $this->getUser();
                $db = $this->getDB();
                $params = $this->extractRequestParams( false );
-               $revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
+               $services = MediaWikiServices::getInstance();
+               $revisionStore = $services->getRevisionStore();
 
                $result = $this->getResult();
 
@@ -156,7 +157,8 @@ class ApiQueryAllDeletedRevisions extends ApiQueryRevisionsBase {
                $miser_ns = null;
 
                if ( $mode == 'all' ) {
-                       $namespaces = $params['namespace'] ?? MWNamespace::getValidNamespaces();
+                       $namespaces = $params['namespace'] ??
+                               $services->getNamespaceInfo()->getValidNamespaces();
                        $this->addWhereFld( 'ar_namespace', $namespaces );
 
                        // For from/to/prefix, we have to consider the potential
index acd11fd..40cd149 100644 (file)
@@ -406,7 +406,7 @@ class ApiQueryAllImages extends ApiQueryGeneratorBase {
        protected function getExamplesMessages() {
                return [
                        'action=query&list=allimages&aifrom=B'
-                               => 'apihelp-query+allimages-example-B',
+                               => 'apihelp-query+allimages-example-b',
                        'action=query&list=allimages&aiprop=user|timestamp|url&' .
                                'aisort=timestamp&aidir=older'
                                => 'apihelp-query+allimages-example-recent',
index fc23caa..1fc5ece 100644 (file)
@@ -291,7 +291,7 @@ class ApiQueryAllLinks extends ApiQueryGeneratorBase {
 
                return [
                        "action=query&list={$name}&{$p}from=B&{$p}prop=ids|title"
-                               => "apihelp-$path-example-B",
+                               => "apihelp-$path-example-b",
                        "action=query&list={$name}&{$p}unique=&{$p}from=B"
                                => "apihelp-$path-example-unique",
                        "action=query&generator={$name}&g{$p}unique=&g{$p}from=B"
index 1940600..ba830ae 100644 (file)
@@ -211,12 +211,13 @@ class ApiQueryAllPages extends ApiQueryGeneratorBase {
                $res = $this->select( __METHOD__ );
 
                // Get gender information
-               if ( MWNamespace::hasGenderDistinction( $params['namespace'] ) ) {
+               $services = MediaWikiServices::getInstance();
+               if ( $services->getNamespaceInfo()->hasGenderDistinction( $params['namespace'] ) ) {
                        $users = [];
                        foreach ( $res as $row ) {
                                $users[] = $row->page_title;
                        }
-                       MediaWikiServices::getInstance()->getGenderCache()->doQuery( $users, __METHOD__ );
+                       $services->getGenderCache()->doQuery( $users, __METHOD__ );
                        $res->rewind(); // reset
                }
 
@@ -341,7 +342,7 @@ class ApiQueryAllPages extends ApiQueryGeneratorBase {
        protected function getExamplesMessages() {
                return [
                        'action=query&list=allpages&apfrom=B'
-                               => 'apihelp-query+allpages-example-B',
+                               => 'apihelp-query+allpages-example-b',
                        'action=query&generator=allpages&gaplimit=4&gapfrom=T&prop=info'
                                => 'apihelp-query+allpages-example-generator',
                        'action=query&generator=allpages&gaplimit=2&' .
index 75d75ec..050bc0f 100644 (file)
@@ -44,7 +44,8 @@ class ApiQueryAllRevisions extends ApiQueryRevisionsBase {
 
                $db = $this->getDB();
                $params = $this->extractRequestParams( false );
-               $revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
+               $services = MediaWikiServices::getInstance();
+               $revisionStore = $services->getRevisionStore();
 
                $result = $this->getResult();
 
@@ -70,7 +71,7 @@ class ApiQueryAllRevisions extends ApiQueryRevisionsBase {
                if ( $params['namespace'] !== null ) {
                        $params['namespace'] = array_unique( $params['namespace'] );
                        sort( $params['namespace'] );
-                       if ( $params['namespace'] != MWNamespace::getValidNamespaces() ) {
+                       if ( $params['namespace'] != $services->getNamespaceInfo()->getValidNamespaces() ) {
                                $needPageTable = true;
                                if ( $this->getConfig()->get( 'MiserMode' ) ) {
                                        $miser_ns = $params['namespace'];
@@ -82,9 +83,7 @@ class ApiQueryAllRevisions extends ApiQueryRevisionsBase {
 
                if ( $resultPageSet === null ) {
                        $this->parseParameters( $params );
-                       $revQuery = $revisionStore->getQueryInfo(
-                               $this->fetchContent ? [ 'page', 'text' ] : [ 'page' ]
-                       );
+                       $revQuery = $revisionStore->getQueryInfo( [ 'page' ] );
                } else {
                        $this->limit = $this->getParameter( 'limit' ) ?: 10;
                        $revQuery = [
index 8b3d864..59e92e1 100644 (file)
@@ -285,8 +285,6 @@ class ApiQueryAllUsers extends ApiQueryBase {
                        }
                        if ( $params['activeusers'] ) {
                                $data['recentactions'] = (int)$row->recentactions;
-                               // @todo 'recenteditcount' is set for BC, remove in 1.25
-                               $data['recenteditcount'] = $data['recentactions'];
                        }
                        if ( $fld_registration ) {
                                $data['registration'] = $row->user_registration ?
@@ -395,7 +393,7 @@ class ApiQueryAllUsers extends ApiQueryBase {
        protected function getExamplesMessages() {
                return [
                        'action=query&list=allusers&aufrom=Y'
-                               => 'apihelp-query+allusers-example-Y',
+                               => 'apihelp-query+allusers-example-y',
                ];
        }
 
index 3070665..122e02f 100644 (file)
@@ -157,16 +157,14 @@ abstract class ApiQueryBase extends ApiBase {
         */
        protected function addTables( $tables, $alias = null ) {
                if ( is_array( $tables ) ) {
-                       if ( !is_null( $alias ) ) {
+                       if ( $alias !== null ) {
                                ApiBase::dieDebug( __METHOD__, 'Multiple table aliases not supported' );
                        }
                        $this->tables = array_merge( $this->tables, $tables );
+               } elseif ( $alias !== null ) {
+                       $this->tables[$alias] = $tables;
                } else {
-                       if ( !is_null( $alias ) ) {
-                               $this->tables[$alias] = $tables;
-                       } else {
-                               $this->tables[] = $tables;
-                       }
+                       $this->tables[] = $tables;
                }
        }
 
@@ -425,35 +423,6 @@ abstract class ApiQueryBase extends ApiBase {
                return Hooks::run( 'ApiQueryBaseProcessRow', [ $this, $row, &$data, &$hookData ] );
        }
 
-       /**
-        * @deprecated since 1.33, use LinkFilter::getQueryConditions() instead
-        * @param string|null $query
-        * @param string|null $protocol
-        * @return null|string
-        */
-       public function prepareUrlQuerySearchString( $query = null, $protocol = null ) {
-               wfDeprecated( __METHOD__, '1.33' );
-               $db = $this->getDB();
-               if ( $query !== null && $query !== '' ) {
-                       if ( is_null( $protocol ) ) {
-                               $protocol = 'http://';
-                       }
-
-                       $likeQuery = LinkFilter::makeLikeArray( $query, $protocol );
-                       if ( !$likeQuery ) {
-                               $this->dieWithError( 'apierror-badquery' );
-                       }
-
-                       $likeQuery = LinkFilter::keepOneWildcard( $likeQuery );
-
-                       return 'el_index ' . $db->buildLike( $likeQuery );
-               } elseif ( !is_null( $protocol ) ) {
-                       return 'el_index ' . $db->buildLike( "$protocol", $db->anyString() );
-               }
-
-               return null;
-       }
-
        /**
         * Filters hidden users (where the user doesn't have the right to view them)
         * Also adds relevant block information
index 8aff2aa..5615f46 100644 (file)
@@ -21,7 +21,7 @@
  */
 
 use Wikimedia\Rdbms\IResultWrapper;
-use MediaWiki\Block\BlockRestriction;
+use MediaWiki\MediaWikiServices;
 
 /**
  * Query module to enumerate all user blocks
@@ -292,7 +292,8 @@ class ApiQueryBlocks extends ApiQueryBase {
                        }
                }
 
-               $restrictions = BlockRestriction::loadByBlockId( $partialIds );
+               $blockRestrictionStore = MediaWikiServices::getInstance()->getBlockRestrictionStore();
+               $restrictions = $blockRestrictionStore->loadByBlockId( $partialIds );
 
                $data = [];
                $keys = [
index 333b769..051e127 100644 (file)
@@ -249,13 +249,11 @@ class ApiQueryImageInfo extends ApiQueryBase {
                        // Don't set $scale['width']; this signals mergeThumbParams() to fill it with the image's width
                        $scale = [];
                        $scale['height'] = $params['urlheight'];
+               } elseif ( $params['urlparam'] ) {
+                       // Audio files might not have a width/height.
+                       $scale = [];
                } else {
-                       if ( $params['urlparam'] ) {
-                               // Audio files might not have a width/height.
-                               $scale = [];
-                       } else {
-                               $scale = null;
-                       }
+                       $scale = null;
                }
 
                return $scale;
index 3d358b9..276aafb 100644 (file)
@@ -515,10 +515,8 @@ class ApiQueryInfo extends ApiQueryBase {
                        }
                }
 
-               if ( $this->fld_varianttitles ) {
-                       if ( isset( $this->variantTitles[$pageid] ) ) {
-                               $pageInfo['varianttitles'] = $this->variantTitles[$pageid];
-                       }
+               if ( $this->fld_varianttitles && isset( $this->variantTitles[$pageid] ) ) {
+                       $pageInfo['varianttitles'] = $this->variantTitles[$pageid];
                }
 
                if ( $this->params['testactions'] ) {
@@ -710,10 +708,11 @@ class ApiQueryInfo extends ApiQueryBase {
         */
        private function getTSIDs() {
                $getTitles = $this->talkids = $this->subjectids = [];
+               $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
 
                /** @var Title $t */
                foreach ( $this->everything as $t ) {
-                       if ( MWNamespace::isTalk( $t->getNamespace() ) ) {
+                       if ( $nsInfo->isTalk( $t->getNamespace() ) ) {
                                if ( $this->fld_subjectid ) {
                                        $getTitles[] = $t->getSubjectPage();
                                }
@@ -736,12 +735,12 @@ class ApiQueryInfo extends ApiQueryBase {
                $this->addWhere( $lb->constructSet( 'page', $db ) );
                $res = $this->select( __METHOD__ );
                foreach ( $res as $row ) {
-                       if ( MWNamespace::isTalk( $row->page_namespace ) ) {
-                               $this->talkids[MWNamespace::getSubject( $row->page_namespace )][$row->page_title] =
-                                       (int)$row->page_id;
+                       if ( $nsInfo->isTalk( $row->page_namespace ) ) {
+                               $this->talkids[$nsInfo->getSubject( $row->page_namespace )][$row->page_title] =
+                                       (int)( $row->page_id );
                        } else {
-                               $this->subjectids[MWNamespace::getTalk( $row->page_namespace )][$row->page_title] =
-                                       (int)$row->page_id;
+                               $this->subjectids[$nsInfo->getTalk( $row->page_namespace )][$row->page_title] =
+                                       (int)( $row->page_id );
                        }
                }
        }
index 7798688..962d956 100644 (file)
@@ -238,6 +238,14 @@ class ApiQueryLogEvents extends ApiQueryBase {
                        }
                }
 
+               // T220999: MySQL/MariaDB (10.1.37) can sometimes irrationally decide that querying `actor` before
+               // `logging` and filesorting is somehow better than querying $limit+1 rows from `logging`.
+               // Tell it not to reorder the query. But not when `letag` was used, as it seems as likely
+               // to be harmed as helped in that case.
+               if ( $params['tag'] === null ) {
+                       $this->addOption( 'STRAIGHT_JOIN' );
+               }
+
                $count = 0;
                $res = $this->select( __METHOD__ );
                $result = $this->getResult();
index 3781ab0..fc50289 100644 (file)
@@ -153,9 +153,6 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
                        if ( $this->token !== null || $pageCount > 0 ) {
                                $opts[] = 'page';
                        }
-                       if ( $this->fetchContent ) {
-                               $opts[] = 'text';
-                       }
                        if ( $this->fld_user ) {
                                $opts[] = 'user';
                        }
@@ -268,7 +265,7 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
                                                [ 'ar_rev_id' => $revids ],
                                                __METHOD__
                                        ),
-                               ], false );
+                               ], $db::UNION_DISTINCT );
                                $res = $db->query( $sql, __METHOD__ );
                                foreach ( $res as $row ) {
                                        if ( (int)$row->id === (int)$params['startid'] ) {
index 51f4d41..d0b152e 100644 (file)
@@ -20,6 +20,7 @@
  * @file
  */
 
+use MediaWiki\Logger\LoggerFactory;
 use MediaWiki\Revision\RevisionAccessException;
 use MediaWiki\Revision\RevisionRecord;
 use MediaWiki\Revision\SlotRecord;
@@ -292,69 +293,27 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                        }
                }
 
-               if ( $this->fld_roles ) {
-                       $vals['roles'] = $revision->getSlotRoles();
-               }
-
-               if ( $this->needSlots ) {
-                       $revDel = $this->checkRevDel( $revision, RevisionRecord::DELETED_TEXT );
-                       if ( ( $this->fld_slotsha1 || $this->fetchContent ) && ( $revDel & self::IS_DELETED ) ) {
-                               $anyHidden = true;
+               try {
+                       if ( $this->fld_roles ) {
+                               $vals['roles'] = $revision->getSlotRoles();
                        }
-                       if ( $this->slotRoles === null ) {
-                               try {
-                                       $slot = $revision->getSlot( SlotRecord::MAIN, RevisionRecord::RAW );
-                               } catch ( RevisionAccessException $e ) {
-                                       // Back compat: If there's no slot, there's no content, so set 'textmissing'
-                                       // @todo: Gergő says to mention T198099 as a "todo" here.
-                                       $vals['textmissing'] = true;
-                                       $slot = null;
-                               }
 
-                               if ( $slot ) {
-                                       $content = null;
-                                       $vals += $this->extractSlotInfo( $slot, $revDel, $content );
-                                       if ( !empty( $vals['nosuchsection'] ) ) {
-                                               $this->dieWithError(
-                                                       [
-                                                               'apierror-nosuchsection-what',
-                                                               wfEscapeWikiText( $this->section ),
-                                                               $this->msg( 'revid', $revision->getId() )
-                                                       ],
-                                                       'nosuchsection'
-                                               );
-                                       }
-                                       if ( $content ) {
-                                               $vals += $this->extractDeprecatedContent( $content, $revision );
-                                       }
+                       if ( $this->needSlots ) {
+                               $revDel = $this->checkRevDel( $revision, RevisionRecord::DELETED_TEXT );
+                               if ( ( $this->fld_slotsha1 || $this->fetchContent ) && ( $revDel & self::IS_DELETED ) ) {
+                                       $anyHidden = true;
                                }
-                       } else {
-                               $roles = array_intersect( $this->slotRoles, $revision->getSlotRoles() );
-                               $vals['slots'] = [
-                                       ApiResult::META_KVP_MERGE => true,
-                               ];
-                               foreach ( $roles as $role ) {
-                                       try {
-                                               $slot = $revision->getSlot( $role, RevisionRecord::RAW );
-                                       } catch ( RevisionAccessException $e ) {
-                                               // Don't error out here so the client can still process other slots/revisions.
-                                               // @todo: Gergő says to mention T198099 as a "todo" here.
-                                               $vals['slots'][$role]['missing'] = true;
-                                               continue;
-                                       }
-                                       $content = null;
-                                       $vals['slots'][$role] = $this->extractSlotInfo( $slot, $revDel, $content );
-                                       // @todo Move this into extractSlotInfo() (and remove its $content parameter)
-                                       // when extractDeprecatedContent() is no more.
-                                       if ( $content ) {
-                                               $vals['slots'][$role]['contentmodel'] = $content->getModel();
-                                               $vals['slots'][$role]['contentformat'] = $content->getDefaultFormat();
-                                               ApiResult::setContentValue( $vals['slots'][$role], 'content', $content->serialize() );
-                                       }
-                               }
-                               ApiResult::setArrayType( $vals['slots'], 'kvp', 'role' );
-                               ApiResult::setIndexedTagName( $vals['slots'], 'slot' );
+                               $vals = array_merge( $vals, $this->extractAllSlotInfo( $revision, $revDel ) );
                        }
+               } catch ( RevisionAccessException $ex ) {
+                       // This is here so T212428 doesn't spam the log.
+                       // TODO: find out why T212428 happens in the first place!
+                       $vals['slotsmissing'] = true;
+
+                       LoggerFactory::getInstance( 'api-warning' )->error(
+                               'Failed to access revision slots',
+                               [ 'revision' => $revision->getId(), 'exception' => $ex, ]
+                       );
                }
 
                if ( $this->fld_comment || $this->fld_parsedcomment ) {
@@ -396,6 +355,79 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                return $vals;
        }
 
+       /**
+        * Extracts information about all relevant slots.
+        *
+        * @param RevisionRecord $revision
+        * @param int $revDel
+        *
+        * @return array
+        * @throws ApiUsageException
+        */
+       private function extractAllSlotInfo( RevisionRecord $revision, $revDel ): array {
+               $vals = [];
+
+               if ( $this->slotRoles === null ) {
+                       try {
+                               $slot = $revision->getSlot( SlotRecord::MAIN, RevisionRecord::RAW );
+                       } catch ( RevisionAccessException $e ) {
+                               // Back compat: If there's no slot, there's no content, so set 'textmissing'
+                               // @todo: Gergő says to mention T198099 as a "todo" here.
+                               $vals['textmissing'] = true;
+                               $slot = null;
+                       }
+
+                       if ( $slot ) {
+                               $content = null;
+                               $vals += $this->extractSlotInfo( $slot, $revDel, $content );
+                               if ( !empty( $vals['nosuchsection'] ) ) {
+                                       $this->dieWithError(
+                                               [
+                                                       'apierror-nosuchsection-what',
+                                                       wfEscapeWikiText( $this->section ),
+                                                       $this->msg( 'revid', $revision->getId() )
+                                               ],
+                                               'nosuchsection'
+                                       );
+                               }
+                               if ( $content ) {
+                                       $vals += $this->extractDeprecatedContent( $content, $revision );
+                               }
+                       }
+               } else {
+                       $roles = array_intersect( $this->slotRoles, $revision->getSlotRoles() );
+                       $vals['slots'] = [
+                               ApiResult::META_KVP_MERGE => true,
+                       ];
+                       foreach ( $roles as $role ) {
+                               try {
+                                       $slot = $revision->getSlot( $role, RevisionRecord::RAW );
+                               } catch ( RevisionAccessException $e ) {
+                                       // Don't error out here so the client can still process other slots/revisions.
+                                       // @todo: Gergő says to mention T198099 as a "todo" here.
+                                       $vals['slots'][$role]['missing'] = true;
+                                       continue;
+                               }
+                               $content = null;
+                               $vals['slots'][$role] = $this->extractSlotInfo( $slot, $revDel, $content );
+                               // @todo Move this into extractSlotInfo() (and remove its $content parameter)
+                               // when extractDeprecatedContent() is no more.
+                               if ( $content ) {
+                                       $vals['slots'][$role]['contentmodel'] = $content->getModel();
+                                       $vals['slots'][$role]['contentformat'] = $content->getDefaultFormat();
+                                       ApiResult::setContentValue(
+                                               $vals['slots'][$role],
+                                               'content',
+                                               $content->serialize()
+                                       );
+                               }
+                       }
+                       ApiResult::setArrayType( $vals['slots'], 'kvp', 'role' );
+                       ApiResult::setIndexedTagName( $vals['slots'], 'slot' );
+               }
+               return $vals;
+       }
+
        /**
         * Extract information from the SlotRecord
         *
@@ -464,8 +496,6 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
         * @return array
         */
        private function extractDeprecatedContent( Content $content, RevisionRecord $revision ) {
-               global $wgParser;
-
                $vals = [];
                $title = Title::newFromLinkTarget( $revision->getPageAsLinkTarget() );
 
@@ -473,12 +503,13 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                        if ( $content->getModel() === CONTENT_MODEL_WIKITEXT ) {
                                $t = $content->getText(); # note: don't set $text
 
-                               $wgParser->startExternalParse(
+                               $parser = MediaWikiServices::getInstance()->getParser();
+                               $parser->startExternalParse(
                                        $title,
                                        ParserOptions::newFromContext( $this->getContext() ),
                                        Parser::OT_PREPROCESS
                                );
-                               $dom = $wgParser->preprocessToDom( $t );
+                               $dom = $parser->preprocessToDom( $t );
                                if ( is_callable( [ $dom, 'saveXML' ] ) ) {
                                        $xml = $dom->saveXML();
                                } else {
@@ -505,7 +536,7 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                                if ( $content->getModel() === CONTENT_MODEL_WIKITEXT ) {
                                        $text = $content->getText();
 
-                                       $text = $wgParser->preprocess(
+                                       $text = MediaWikiServices::getInstance()->getParser()->preprocess(
                                                $text,
                                                $title,
                                                ParserOptions::newFromContext( $this->getContext() )
index b90dd5d..98c6551 100644 (file)
@@ -67,13 +67,6 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
                $search->setFeatureData( 'rewrite', (bool)$params['enablerewrites'] );
                $search->setFeatureData( 'interwiki', (bool)$interwiki );
 
-               $nquery = $search->transformSearchTerm( $query );
-               if ( $nquery !== $query ) {
-                       $query = $nquery;
-                       wfDeprecated( 'SearchEngine::transformSearchTerm() (overridden by ' .
-                               get_class( $search ) . ')', '1.32' );
-               }
-
                $nquery = $search->replacePrefixes( $query );
                if ( $nquery !== $query ) {
                        $query = $nquery;
@@ -157,7 +150,6 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
                        convertForSearchResult( $matches->termMatches() );
                $titles = [];
                $count = 0;
-               $limit = $params['limit'];
 
                if ( $matches->hasMoreResults() ) {
                        $this->setContinueEnumParameter( 'offset', $params['offset'] + $params['limit'] );
index 96fa8a1..7e4a891 100644 (file)
@@ -236,7 +236,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
                $data[ApiResult::META_BC_BOOLS][] = 'variantarticlepath';
                $data['server'] = $config->get( 'Server' );
                $data['servername'] = $config->get( 'ServerName' );
-               $data['wikiid'] = wfWikiID();
+               $data['wikiid'] = WikiMap::getWikiIdFromDbDomain( WikiMap::getCurrentWikiDbDomain() );
                $data['time'] = wfTimestamp( TS_ISO_8601, time() );
 
                $data['misermode'] = (bool)$config->get( 'MiserMode' );
@@ -282,27 +282,28 @@ class ApiQuerySiteinfo extends ApiQueryBase {
                $data = [
                        ApiResult::META_TYPE => 'assoc',
                ];
+               $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
                foreach (
                        MediaWikiServices::getInstance()->getContentLanguage()->getFormattedNamespaces()
                        as $ns => $title
                ) {
                        $data[$ns] = [
                                'id' => (int)$ns,
-                               'case' => MWNamespace::isCapitalized( $ns ) ? 'first-letter' : 'case-sensitive',
+                               'case' => $nsInfo->isCapitalized( $ns ) ? 'first-letter' : 'case-sensitive',
                        ];
                        ApiResult::setContentValue( $data[$ns], 'name', $title );
-                       $canonical = MWNamespace::getCanonicalName( $ns );
+                       $canonical = $nsInfo->getCanonicalName( $ns );
 
-                       $data[$ns]['subpages'] = MWNamespace::hasSubpages( $ns );
+                       $data[$ns]['subpages'] = $nsInfo->hasSubpages( $ns );
 
                        if ( $canonical ) {
                                $data[$ns]['canonical'] = strtr( $canonical, '_', ' ' );
                        }
 
-                       $data[$ns]['content'] = MWNamespace::isContent( $ns );
-                       $data[$ns]['nonincludable'] = MWNamespace::isNonincludable( $ns );
+                       $data[$ns]['content'] = $nsInfo->isContent( $ns );
+                       $data[$ns]['nonincludable'] = $nsInfo->isNonincludable( $ns );
 
-                       $contentmodel = MWNamespace::getNamespaceContentModel( $ns );
+                       $contentmodel = $nsInfo->getNamespaceContentModel( $ns );
                        if ( $contentmodel ) {
                                $data[$ns]['defaultcontentmodel'] = $contentmodel;
                        }
@@ -664,8 +665,8 @@ class ApiQuerySiteinfo extends ApiQueryBase {
                }
 
                $data = [
-                       'url' => strlen( $url ) ? $url : '',
-                       'text' => strlen( $text ) ? $text : '',
+                       'url' => (string)$url,
+                       'text' => (string)$text,
                ];
 
                return $this->getResult()->addValue( 'query', $property, $data );
@@ -787,12 +788,11 @@ class ApiQuerySiteinfo extends ApiQueryBase {
        }
 
        public function appendExtensionTags( $property ) {
-               global $wgParser;
                $tags = array_map(
                        function ( $item ) {
                                return "<$item>";
                        },
-                       $wgParser->getTags()
+                       MediaWikiServices::getInstance()->getParser()->getTags()
                );
                ApiResult::setArrayType( $tags, 'BCarray' );
                ApiResult::setIndexedTagName( $tags, 't' );
@@ -801,8 +801,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
        }
 
        public function appendFunctionHooks( $property ) {
-               global $wgParser;
-               $hooks = $wgParser->getFunctionHooks();
+               $hooks = MediaWikiServices::getInstance()->getParser()->getFunctionHooks();
                ApiResult::setArrayType( $hooks, 'BCarray' );
                ApiResult::setIndexedTagName( $hooks, 'h' );
 
index 5b178b7..379f1af 100644 (file)
@@ -331,9 +331,6 @@ class ApiQueryUserContribs extends ApiQueryBase {
                $db = $this->getDB();
 
                $revQuery = MediaWikiServices::getInstance()->getRevisionStore()->getQueryInfo( [ 'page' ] );
-               $this->addTables( $revQuery['tables'] );
-               $this->addJoinConds( $revQuery['joins'] );
-               $this->addFields( $revQuery['fields'] );
 
                if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) {
                        $revWhere = ActorMigration::newMigration()->getWhere( $db, 'rev_user', $users );
@@ -341,6 +338,24 @@ class ApiQueryUserContribs extends ApiQueryBase {
                        $userField = $this->orderBy === 'actor' ? 'revactor_actor' : 'actor_name';
                        $tsField = 'revactor_timestamp';
                        $idField = 'revactor_rev';
+
+                       // T221511: MySQL/MariaDB (10.1.37) can sometimes irrationally decide that querying `actor`
+                       // before `revision_actor_temp` and filesorting is somehow better than querying $limit+1 rows
+                       // from `revision_actor_temp`. Tell it not to reorder the query (and also reorder it ourselves
+                       // because as generated by RevisionStore it'll have `revision` first rather than
+                       // `revision_actor_temp`). But not when uctag is used, as it seems as likely to be harmed as
+                       // helped in that case, and not when there's only one User because in that case it fetches
+                       // the one `actor` row as a constant and doesn't filesort.
+                       if ( count( $users ) > 1 && !isset( $this->params['tag'] ) ) {
+                               $revQuery['joins']['revision'] = $revQuery['joins']['temp_rev_user'];
+                               unset( $revQuery['joins']['temp_rev_user'] );
+                               $this->addOption( 'STRAIGHT_JOIN' );
+                               // It isn't actually necesssary to reorder $revQuery['tables'] as Database does the right thing
+                               // when join conditions are given for all joins, but Gergő is wary of relying on that so pull
+                               // `revision_actor_temp` to the start.
+                               $revQuery['tables'] =
+                                       [ 'temp_rev_user' => $revQuery['tables']['temp_rev_user'] ] + $revQuery['tables'];
+                       }
                } else {
                        // If we're dealing with user names (rather than IDs) in read-old mode,
                        // pass false for ActorMigration::getWhere()'s $useId parameter so
@@ -353,6 +368,9 @@ class ApiQueryUserContribs extends ApiQueryBase {
                        $idField = 'rev_id';
                }
 
+               $this->addTables( $revQuery['tables'] );
+               $this->addJoinConds( $revQuery['joins'] );
+               $this->addFields( $revQuery['fields'] );
                $this->addWhere( $revWhere['conds'] );
 
                // Handle continue parameter
index a38d877..ba7280d 100644 (file)
@@ -20,6 +20,7 @@
  * @file
  */
 
+use MediaWiki\Block\AbstractBlock;
 use MediaWiki\MediaWikiServices;
 
 /**
@@ -29,6 +30,8 @@ use MediaWiki\MediaWikiServices;
  */
 class ApiQueryUserInfo extends ApiQueryBase {
 
+       use ApiBlockInfoTrait;
+
        const WL_UNREAD_LIMIT = 1000;
 
        private $params = [];
@@ -52,29 +55,22 @@ class ApiQueryUserInfo extends ApiQueryBase {
 
        /**
         * Get basic info about a given block
-        * @param Block $block
-        * @return array Array containing several keys:
-        *  - blockid - ID of the block
-        *  - blockedby - username of the blocker
-        *  - blockedbyid - user ID of the blocker
-        *  - blockreason - reason provided for the block
-        *  - blockedtimestamp - timestamp for when the block was placed/modified
-        *  - blockexpiry - expiry time of the block
-        *  - systemblocktype - system block type, if any
+        *
+        * @deprecated since 1.34 Use ApiBlockInfoTrait::getBlockDetails() instead.
+        * @param AbstractBlock $block
+        * @return array See ApiBlockInfoTrait::getBlockDetails
         */
-       public static function getBlockInfo( Block $block ) {
-               $vals = [];
-               $vals['blockid'] = $block->getId();
-               $vals['blockedby'] = $block->getByName();
-               $vals['blockedbyid'] = $block->getBy();
-               $vals['blockreason'] = $block->mReason;
-               $vals['blockedtimestamp'] = wfTimestamp( TS_ISO_8601, $block->mTimestamp );
-               $vals['blockexpiry'] = ApiResult::formatExpiry( $block->getExpiry(), 'infinite' );
-               $vals['blockpartial'] = !$block->isSitewide();
-               if ( $block->getSystemBlockType() !== null ) {
-                       $vals['systemblocktype'] = $block->getSystemBlockType();
-               }
-               return $vals;
+       public static function getBlockInfo( AbstractBlock $block ) {
+               wfDeprecated( __METHOD__, '1.34' );
+
+               // Hack to access a private method from a trait:
+               $dummy = new class {
+                       use ApiBlockInfoTrait {
+                               getBlockDetails as public;
+                       }
+               };
+
+               return $dummy->getBlockDetails( $block );
        }
 
        /**
@@ -126,8 +122,11 @@ class ApiQueryUserInfo extends ApiQueryBase {
                        $vals['anon'] = true;
                }
 
-               if ( isset( $this->prop['blockinfo'] ) && $user->isBlocked() ) {
-                       $vals = array_merge( $vals, self::getBlockInfo( $user->getBlock() ) );
+               if ( isset( $this->prop['blockinfo'] ) ) {
+                       $block = $user->getBlock();
+                       if ( $block ) {
+                               $vals = array_merge( $vals, $this->getBlockDetails( $block ) );
+                       }
                }
 
                if ( isset( $this->prop['hasmsg'] ) ) {
@@ -202,13 +201,11 @@ class ApiQueryUserInfo extends ApiQueryBase {
                        $vals['realname'] = $user->getRealName();
                }
 
-               if ( $user->isAllowed( 'viewmyprivateinfo' ) ) {
-                       if ( isset( $this->prop['email'] ) ) {
-                               $vals['email'] = $user->getEmail();
-                               $auth = $user->getEmailAuthenticationTimestamp();
-                               if ( !is_null( $auth ) ) {
-                                       $vals['emailauthenticated'] = wfTimestamp( TS_ISO_8601, $auth );
-                               }
+               if ( $user->isAllowed( 'viewmyprivateinfo' ) && isset( $this->prop['email'] ) ) {
+                       $vals['email'] = $user->getEmail();
+                       $auth = $user->getEmailAuthenticationTimestamp();
+                       if ( $auth !== null ) {
+                               $vals['emailauthenticated'] = wfTimestamp( TS_ISO_8601, $auth );
                        }
                }
 
@@ -251,6 +248,13 @@ class ApiQueryUserInfo extends ApiQueryBase {
                        );
                }
 
+               if ( isset( $this->prop['latestcontrib'] ) ) {
+                       $ts = $this->getLatestContributionTime();
+                       if ( $ts !== null ) {
+                               $vals['latestcontrib'] = $ts;
+                       }
+               }
+
                return $vals;
        }
 
@@ -293,6 +297,40 @@ class ApiQueryUserInfo extends ApiQueryBase {
                return $retval;
        }
 
+       /**
+        * @return string|null ISO 8601 timestamp of current user's last contribution or null if none
+        */
+       protected function getLatestContributionTime() {
+               global $wgActorTableSchemaMigrationStage;
+
+               $user = $this->getUser();
+               $dbr = $this->getDB();
+
+               if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) {
+                       if ( $user->getActorId() === null ) {
+                               return null;
+                       }
+                       $res = $dbr->selectField( 'revision_actor_temp',
+                               'MAX(revactor_timestamp)',
+                               [ 'revactor_actor' => $user->getActorId() ],
+                               __METHOD__
+                       );
+               } else {
+                       if ( $user->isLoggedIn() ) {
+                               $conds = [ 'rev_user' => $user->getId() ];
+                       } else {
+                               $conds = [ 'rev_user_text' => $user->getName() ];
+                       }
+                       $res = $dbr->selectField( 'revision',
+                               'MAX(rev_timestamp)',
+                               $conds,
+                               __METHOD__
+                       );
+               }
+
+               return $res ? wfTimestamp( TS_ISO_8601, $res ) : null;
+       }
+
        public function getAllowedParams() {
                return [
                        'prop' => [
@@ -315,6 +353,7 @@ class ApiQueryUserInfo extends ApiQueryBase {
                                        'unreadcount',
                                        'centralids',
                                        'preferencestoken',
+                                       'latestcontrib',
                                ],
                                ApiBase::PARAM_HELP_MSG_PER_VALUE => [
                                        'unreadcount' => [
index 236f6e0..578a908 100644 (file)
@@ -81,10 +81,8 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
                        $this->fld_loginfo = isset( $prop['loginfo'] );
                        $this->fld_tags = isset( $prop['tags'] );
 
-                       if ( $this->fld_patrol ) {
-                               if ( !$user->useRCPatrol() && !$user->useNPPatrol() ) {
-                                       $this->dieWithError( 'apierror-permissiondenied-patrolflag', 'patrol' );
-                               }
+                       if ( $this->fld_patrol && !$user->useRCPatrol() && !$user->useNPPatrol() ) {
+                               $this->dieWithError( 'apierror-permissiondenied-patrolflag', 'patrol' );
                        }
 
                        if ( $this->fld_comment || $this->fld_parsedcomment ) {
@@ -180,7 +178,6 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
                ] );
 
                $ids = [];
-               $count = 0;
                $watchedItemQuery = MediaWikiServices::getInstance()->getWatchedItemQueryService();
                $items = $watchedItemQuery->getWatchedItemsWithRecentChangeInfo( $wlowner, $options, $startFrom );
 
@@ -193,12 +190,10 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
                                        $startFrom = [ $recentChangeInfo['rc_timestamp'], $recentChangeInfo['rc_id'] ];
                                        break;
                                }
+                       } elseif ( $params['allrev'] ) {
+                               $ids[] = (int)$recentChangeInfo['rc_this_oldid'];
                        } else {
-                               if ( $params['allrev'] ) {
-                                       $ids[] = (int)$recentChangeInfo['rc_this_oldid'];
-                               } else {
-                                       $ids[] = (int)$recentChangeInfo['rc_cur_id'];
-                               }
+                               $ids[] = (int)$recentChangeInfo['rc_cur_id'];
                        }
                }
 
index c4a31c7..c27b10e 100644 (file)
@@ -498,7 +498,7 @@ class ApiResult implements ApiSerializable {
                        throw new InvalidArgumentException( 'Content value must be named' );
                }
                $this->addContentField( $path, $name, $flags );
-               $this->addValue( $path, $name, $value, $flags );
+               return $this->addValue( $path, $name, $value, $flags );
        }
 
        /**
index 6e37774..1ee91c2 100644 (file)
@@ -38,8 +38,10 @@ class ApiRevisionDelete extends ApiBase {
                $user = $this->getUser();
                $this->checkUserRightsAny( RevisionDeleter::getRestriction( $params['type'] ) );
 
-               if ( $user->isBlocked() ) {
-                       $this->dieBlocked( $user->getBlock() );
+               // @TODO Use PermissionManager::isBlockedFrom() instead.
+               $block = $user->getBlock();
+               if ( $block ) {
+                       $this->dieBlocked( $block );
                }
 
                if ( !$params['ids'] ) {
index 71bab36..00ab77b 100644 (file)
@@ -149,19 +149,3 @@ class ApiRsd extends ApiBase {
                return $outputData;
        }
 }
-
-class ApiFormatXmlRsd extends ApiFormatXml {
-       public function __construct( ApiMain $main, $format ) {
-               parent::__construct( $main, $format );
-               $this->setRootElement( 'rsd' );
-       }
-
-       public function getMimeType() {
-               return 'application/rsd+xml';
-       }
-
-       public static function recXmlPrint( $name, $value, $indent, $attributes = [] ) {
-               unset( $attributes['_idx'] );
-               return parent::recXmlPrint( $name, $value, $indent, $attributes );
-       }
-}
index c9ebfa8..d2bbe7b 100644 (file)
@@ -77,8 +77,9 @@ class ApiSetNotificationTimestamp extends ApiBase {
                        $titles = $pageSet->getGoodTitles();
                        $title = reset( $titles );
                        if ( $title ) {
+                               // XXX $title isn't actually used, can we just get rid of the previous six lines?
                                $timestamp = MediaWikiServices::getInstance()->getRevisionStore()
-                                       ->getTimestampFromId( $title, $params['torevid'], IDBAccessObject::READ_LATEST );
+                                       ->getTimestampFromId( $params['torevid'], IDBAccessObject::READ_LATEST );
                                if ( $timestamp ) {
                                        $timestamp = $dbw->timestamp( $timestamp );
                                } else {
@@ -108,14 +109,7 @@ class ApiSetNotificationTimestamp extends ApiBase {
                $result = [];
                if ( $params['entirewatchlist'] ) {
                        // Entire watchlist mode: Just update the thing and return a success indicator
-                       if ( is_null( $timestamp ) ) {
-                               $watchedItemStore->resetAllNotificationTimestampsForUser( $user );
-                       } else {
-                               $watchedItemStore->setNotificationTimestampsForUser(
-                                       $user,
-                                       $timestamp
-                               );
-                       }
+                       $watchedItemStore->resetAllNotificationTimestampsForUser( $user, $timestamp );
 
                        $result['notificationtimestamp'] = is_null( $timestamp )
                                ? ''
index 455ff45..c3cf5f1 100644 (file)
@@ -18,9 +18,8 @@
  * @file
  */
 
-use MediaWiki\Logger\LoggerFactory;
 use MediaWiki\MediaWikiServices;
-use Wikimedia\ScopedCallback;
+use MediaWiki\Storage\PageEditStash;
 
 /**
  * Prepare an edit in shared cache so that it can be reused on edit
@@ -36,15 +35,11 @@ use Wikimedia\ScopedCallback;
  * @since 1.25
  */
 class ApiStashEdit extends ApiBase {
-       const ERROR_NONE = 'stashed';
-       const ERROR_PARSE = 'error_parse';
-       const ERROR_CACHE = 'error_cache';
-       const ERROR_UNCACHEABLE = 'uncacheable';
-       const ERROR_BUSY = 'busy';
-
-       const PRESUME_FRESH_TTL_SEC = 30;
-       const MAX_CACHE_TTL = 300; // 5 minutes
-       const MAX_SIGNATURE_TTL = 60;
+       const ERROR_NONE = PageEditStash::ERROR_NONE; // b/c
+       const ERROR_PARSE = PageEditStash::ERROR_PARSE; // b/c
+       const ERROR_CACHE = PageEditStash::ERROR_CACHE; // b/c
+       const ERROR_UNCACHEABLE = PageEditStash::ERROR_UNCACHEABLE; // b/c
+       const ERROR_BUSY = PageEditStash::ERROR_BUSY; // b/c
 
        public function execute() {
                $user = $this->getUser();
@@ -54,7 +49,7 @@ class ApiStashEdit extends ApiBase {
                        $this->dieWithError( 'apierror-botsnotsupported' );
                }
 
-               $cache = ObjectCache::getLocalClusterInstance();
+               $editStash = MediaWikiServices::getInstance()->getPageEditStash();
                $page = $this->getTitleOrPageId( $params );
                $title = $page->getTitle();
 
@@ -77,8 +72,7 @@ class ApiStashEdit extends ApiBase {
                        if ( !preg_match( '/^[0-9a-f]{40}$/', $textHash ) ) {
                                $this->dieWithError( 'apierror-stashedit-missingtext', 'missingtext' );
                        }
-                       $textKey = $cache->makeKey( 'stashedit', 'text', $textHash );
-                       $text = $cache->get( $textKey );
+                       $text = $editStash->fetchInputText( $textHash );
                        if ( !is_string( $text ) ) {
                                $this->dieWithError( 'apierror-stashedit-missingtext', 'missingtext' );
                        }
@@ -143,9 +137,8 @@ class ApiStashEdit extends ApiBase {
                if ( $user->pingLimiter( 'stashedit' ) ) {
                        $status = 'ratelimited';
                } else {
-                       $status = self::parseAndStash( $page, $content, $user, $params['summary'] );
-                       $textKey = $cache->makeKey( 'stashedit', 'text', $textHash );
-                       $cache->set( $textKey, $text, self::MAX_CACHE_TTL );
+                       $status = $editStash->parseAndCache( $page, $content, $user, $params['summary'] );
+                       $editStash->stashInputText( $text, $textHash );
                }
 
                $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
@@ -167,301 +160,12 @@ class ApiStashEdit extends ApiBase {
         * @param string $summary Edit summary
         * @return string ApiStashEdit::ERROR_* constant
         * @since 1.25
+        * @deprecated Since 1.34
         */
-       public static function parseAndStash( WikiPage $page, Content $content, User $user, $summary ) {
-               $logger = LoggerFactory::getInstance( 'StashEdit' );
-
-               $title = $page->getTitle();
-               $key = self::getStashKey( $title, self::getContentHash( $content ), $user );
-               $fname = __METHOD__;
-
-               // Use the master DB to allow for fast blocking locks on the "save path" where this
-               // value might actually be used to complete a page edit. If the edit submission request
-               // happens before this edit stash requests finishes, then the submission will block until
-               // the stash request finishes parsing. For the lock acquisition below, there is not much
-               // need to duplicate parsing of the same content/user/summary bundle, so try to avoid
-               // blocking at all here.
-               $dbw = wfGetDB( DB_MASTER );
-               if ( !$dbw->lock( $key, $fname, 0 ) ) {
-                       // De-duplicate requests on the same key
-                       return self::ERROR_BUSY;
-               }
-               /** @noinspection PhpUnusedLocalVariableInspection */
-               $unlocker = new ScopedCallback( function () use ( $dbw, $key, $fname ) {
-                       $dbw->unlock( $key, $fname );
-               } );
-
-               $cutoffTime = time() - self::PRESUME_FRESH_TTL_SEC;
-
-               // Reuse any freshly build matching edit stash cache
-               $editInfo = self::getStashValue( $key );
-               if ( $editInfo && wfTimestamp( TS_UNIX, $editInfo->timestamp ) >= $cutoffTime ) {
-                       $alreadyCached = true;
-               } else {
-                       $format = $content->getDefaultFormat();
-                       $editInfo = $page->prepareContentForEdit( $content, null, $user, $format, false );
-                       $alreadyCached = false;
-               }
-
-               if ( $editInfo && $editInfo->output ) {
-                       // Let extensions add ParserOutput metadata or warm other caches
-                       Hooks::run( 'ParserOutputStashForEdit',
-                               [ $page, $content, $editInfo->output, $summary, $user ] );
-
-                       $titleStr = (string)$title;
-                       if ( $alreadyCached ) {
-                               $logger->debug( "Already cached parser output for key '{cachekey}' ('{title}').",
-                                       [ 'cachekey' => $key, 'title' => $titleStr ] );
-                               return self::ERROR_NONE;
-                       }
-
-                       $code = self::storeStashValue(
-                               $key,
-                               $editInfo->pstContent,
-                               $editInfo->output,
-                               $editInfo->timestamp,
-                               $user
-                       );
-
-                       if ( $code === true ) {
-                               $logger->debug( "Cached parser output for key '{cachekey}' ('{title}').",
-                                       [ 'cachekey' => $key, 'title' => $titleStr ] );
-                               return self::ERROR_NONE;
-                       } elseif ( $code === 'uncacheable' ) {
-                               $logger->info(
-                                       "Uncacheable parser output for key '{cachekey}' ('{title}') [{code}].",
-                                       [ 'cachekey' => $key, 'title' => $titleStr, 'code' => $code ] );
-                               return self::ERROR_UNCACHEABLE;
-                       } else {
-                               $logger->error( "Failed to cache parser output for key '{cachekey}' ('{title}').",
-                                       [ 'cachekey' => $key, 'title' => $titleStr, 'code' => $code ] );
-                               return self::ERROR_CACHE;
-                       }
-               }
-
-               return self::ERROR_PARSE;
-       }
-
-       /**
-        * Check that a prepared edit is in cache and still up-to-date
-        *
-        * This method blocks if the prepared edit is already being rendered,
-        * waiting until rendering finishes before doing final validity checks.
-        *
-        * The cache is rejected if template or file changes are detected.
-        * Note that foreign template or file transclusions are not checked.
-        *
-        * The result is a map (pstContent,output,timestamp) with fields
-        * extracted directly from WikiPage::prepareContentForEdit().
-        *
-        * @param Title $title
-        * @param Content $content
-        * @param User $user User to get parser options from
-        * @return stdClass|bool Returns false on cache miss
-        */
-       public static function checkCache( Title $title, Content $content, User $user ) {
-               if ( $user->isBot() ) {
-                       return false; // bots never stash - don't pollute stats
-               }
-
-               $logger = LoggerFactory::getInstance( 'StashEdit' );
-               $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
-
-               $key = self::getStashKey( $title, self::getContentHash( $content ), $user );
-               $editInfo = self::getStashValue( $key );
-               if ( !is_object( $editInfo ) ) {
-                       $start = microtime( true );
-                       // We ignore user aborts and keep parsing. Block on any prior parsing
-                       // so as to use its results and make use of the time spent parsing.
-                       // Skip this logic if there no master connection in case this method
-                       // is called on an HTTP GET request for some reason.
-                       $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
-                       $dbw = $lb->getAnyOpenConnection( $lb->getWriterIndex() );
-                       if ( $dbw && $dbw->lock( $key, __METHOD__, 30 ) ) {
-                               $editInfo = self::getStashValue( $key );
-                               $dbw->unlock( $key, __METHOD__ );
-                       }
-
-                       $timeMs = 1000 * max( 0, microtime( true ) - $start );
-                       $stats->timing( 'editstash.lock_wait_time', $timeMs );
-               }
-
-               if ( !is_object( $editInfo ) || !$editInfo->output ) {
-                       $stats->increment( 'editstash.cache_misses.no_stash' );
-                       $logger->debug( "Empty cache for key '$key' ('$title'); user '{$user->getName()}'." );
-                       return false;
-               }
-
-               $age = time() - wfTimestamp( TS_UNIX, $editInfo->output->getCacheTime() );
-               if ( $age <= self::PRESUME_FRESH_TTL_SEC ) {
-                       // Assume nothing changed in this time
-                       $stats->increment( 'editstash.cache_hits.presumed_fresh' );
-                       $logger->debug( "Timestamp-based cache hit for key '$key' (age: $age sec)." );
-               } elseif ( isset( $editInfo->edits ) && $editInfo->edits === $user->getEditCount() ) {
-                       // Logged-in user made no local upload/template edits in the meantime
-                       $stats->increment( 'editstash.cache_hits.presumed_fresh' );
-                       $logger->debug( "Edit count based cache hit for key '$key' (age: $age sec)." );
-               } elseif ( $user->isAnon()
-                       && self::lastEditTime( $user ) < $editInfo->output->getCacheTime()
-               ) {
-                       // Logged-out user made no local upload/template edits in the meantime
-                       $stats->increment( 'editstash.cache_hits.presumed_fresh' );
-                       $logger->debug( "Edit check based cache hit for key '$key' (age: $age sec)." );
-               } else {
-                       // User may have changed included content
-                       $editInfo = false;
-               }
-
-               if ( !$editInfo ) {
-                       $stats->increment( 'editstash.cache_misses.proven_stale' );
-                       $logger->info( "Stale cache for key '$key'; old key with outside edits. (age: $age sec)" );
-               } elseif ( $editInfo->output->getFlag( 'vary-revision' ) ) {
-                       // This can be used for the initial parse, e.g. for filters or doEditContent(),
-                       // but a second parse will be triggered in doEditUpdates(). This is not optimal.
-                       $logger->info( "Cache for key '$key' ('$title') has vary_revision." );
-               } elseif ( $editInfo->output->getFlag( 'vary-revision-id' ) ) {
-                       // Similar to the above if we didn't guess the ID correctly.
-                       $logger->info( "Cache for key '$key' ('$title') has vary_revision_id." );
-               }
-
-               return $editInfo;
-       }
-
-       /**
-        * @param User $user
-        * @return string|null TS_MW timestamp or null
-        */
-       private static function lastEditTime( User $user ) {
-               $db = wfGetDB( DB_REPLICA );
-               $actorQuery = ActorMigration::newMigration()->getWhere( $db, 'rc_user', $user, false );
-               $time = $db->selectField(
-                       [ 'recentchanges' ] + $actorQuery['tables'],
-                       'MAX(rc_timestamp)',
-                       [ $actorQuery['conds'] ],
-                       __METHOD__,
-                       [],
-                       $actorQuery['joins']
-               );
-
-               return wfTimestampOrNull( TS_MW, $time );
-       }
-
-       /**
-        * Get hash of the content, factoring in model/format
-        *
-        * @param Content $content
-        * @return string
-        */
-       private static function getContentHash( Content $content ) {
-               return sha1( implode( "\n", [
-                       $content->getModel(),
-                       $content->getDefaultFormat(),
-                       $content->serialize( $content->getDefaultFormat() )
-               ] ) );
-       }
-
-       /**
-        * Get the temporary prepared edit stash key for a user
-        *
-        * This key can be used for caching prepared edits provided:
-        *   - a) The $user was used for PST options
-        *   - b) The parser output was made from the PST using cannonical matching options
-        *
-        * @param Title $title
-        * @param string $contentHash Result of getContentHash()
-        * @param User $user User to get parser options from
-        * @return string
-        */
-       private static function getStashKey( Title $title, $contentHash, User $user ) {
-               return ObjectCache::getLocalClusterInstance()->makeKey(
-                       'stashed-edit-info',
-                       md5( $title->getPrefixedDBkey() ),
-                       // Account for the edit model/text
-                       $contentHash,
-                       // Account for user name related variables like signatures
-                       md5( $user->getId() . "\n" . $user->getName() )
-               );
-       }
-
-       /**
-        * @param string $uuid
-        * @return string
-        */
-       private static function getStashParserOutputKey( $uuid ) {
-               return ObjectCache::getLocalClusterInstance()->makeKey( 'stashed-edit-output', $uuid );
-       }
-
-       /**
-        * @param string $key
-        * @return stdClass|bool Object map (pstContent,output,outputID,timestamp,edits) or false
-        */
-       private static function getStashValue( $key ) {
-               $cache = ObjectCache::getLocalClusterInstance();
-
-               $stashInfo = $cache->get( $key );
-               if ( !is_object( $stashInfo ) ) {
-                       return false;
-               }
-
-               $parserOutputKey = self::getStashParserOutputKey( $stashInfo->outputID );
-               $parserOutput = $cache->get( $parserOutputKey );
-               if ( $parserOutput instanceof ParserOutput ) {
-                       $stashInfo->output = $parserOutput;
-
-                       return $stashInfo;
-               }
-
-               return false;
-       }
-
-       /**
-        * Build a value to store in memcached based on the PST content and parser output
-        *
-        * This makes a simple version of WikiPage::prepareContentForEdit() as stash info
-        *
-        * @param string $key
-        * @param Content $pstContent Pre-Save transformed content
-        * @param ParserOutput $parserOutput
-        * @param string $timestamp TS_MW
-        * @param User $user
-        * @return string|bool True or an error code
-        */
-       private static function storeStashValue(
-               $key, Content $pstContent, ParserOutput $parserOutput, $timestamp, User $user
-       ) {
-               // If an item is renewed, mind the cache TTL determined by config and parser functions.
-               // Put an upper limit on the TTL for sanity to avoid extreme template/file staleness.
-               $age = time() - wfTimestamp( TS_UNIX, $parserOutput->getCacheTime() );
-               $ttl = min( $parserOutput->getCacheExpiry() - $age, self::MAX_CACHE_TTL );
-               // Avoid extremely stale user signature timestamps (T84843)
-               if ( $parserOutput->getFlag( 'user-signature' ) ) {
-                       $ttl = min( $ttl, self::MAX_SIGNATURE_TTL );
-               }
-
-               if ( $ttl <= 0 ) {
-                       return 'uncacheable'; // low TTL due to a tag, magic word, or signature?
-               }
-
-               // Store what is actually needed and split the output into another key (T204742)
-               $parseroutputID = md5( $key );
-               $stashInfo = (object)[
-                       'pstContent' => $pstContent,
-                       'outputID'   => $parseroutputID,
-                       'timestamp'  => $timestamp,
-                       'edits'      => $user->getEditCount()
-               ];
-
-               $cache = ObjectCache::getLocalClusterInstance();
-               $ok = $cache->set( $key, $stashInfo, $ttl );
-               if ( $ok ) {
-                       $ok = $cache->set(
-                               self::getStashParserOutputKey( $parseroutputID ),
-                               $parserOutput,
-                               $ttl
-                       );
-               }
+       public function parseAndStash( WikiPage $page, Content $content, User $user, $summary ) {
+               $editStash = MediaWikiServices::getInstance()->getPageEditStash();
 
-               return $ok ? true : 'store_error';
+               return $editStash->parseAndCache( $page, $content, $user, $summary );
        }
 
        public function getAllowedParams() {
index 82cf986..aff0183 100644 (file)
@@ -40,8 +40,10 @@ class ApiTag extends ApiBase {
                // make sure the user is allowed
                $this->checkUserRightsAny( 'changetags' );
 
-               if ( $user->isBlocked() ) {
-                       $this->dieBlocked( $user->getBlock() );
+               // @TODO Use PermissionManager::isBlockedFrom() instead.
+               $block = $user->getBlock();
+               if ( $block ) {
+                       $this->dieBlocked( $block );
                }
 
                // Check if user can add tags
index b748cb3..1c72b67 100644 (file)
@@ -28,6 +28,8 @@
  */
 class ApiUnblock extends ApiBase {
 
+       use ApiBlockInfoTrait;
+
        /**
         * Unblocks the specified user or provides the reason the unblock failed.
         */
@@ -41,13 +43,14 @@ class ApiUnblock extends ApiBase {
                        $this->dieWithError( 'apierror-permissiondenied-unblock', 'permissiondenied' );
                }
                # T17810: blocked admins should have limited access here
-               if ( $user->isBlocked() ) {
+               $block = $user->getBlock();
+               if ( $block ) {
                        $status = SpecialBlock::checkUnblockSelf( $params['user'], $user );
                        if ( $status !== true ) {
                                $this->dieWithError(
                                        $status,
                                        null,
-                                       [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $user->getBlock() ) ]
+                                       [ 'blockinfo' => $this->getBlockDetails( $block ) ]
                                );
                        }
                }
index 07a6aae..5f9b97c 100644 (file)
@@ -31,7 +31,8 @@ class ApiUndelete extends ApiBase {
                $params = $this->extractRequestParams();
 
                $user = $this->getUser();
-               if ( $user->isBlocked() ) {
+               $block = $user->getBlock();
+               if ( $block && $block->isSitewide() ) {
                        $this->dieBlocked( $user->getBlock() );
                }
 
index 2c5b583..fc41e4e 100644 (file)
@@ -417,7 +417,7 @@ class ApiUpload extends ApiBase {
                if ( $this->mParams['filekey'] && $this->mParams['checkstatus'] ) {
                        $progress = UploadBase::getSessionStatus( $this->getUser(), $this->mParams['filekey'] );
                        if ( !$progress ) {
-                               $this->dieWithError( 'api-upload-missingresult', 'missingresult' );
+                               $this->dieWithError( 'apierror-upload-missingresult', 'missingresult' );
                        } elseif ( !$progress['status']->isGood() ) {
                                $this->dieStatusWithCode( $progress['status'], 'stashfailed' );
                        }
@@ -542,7 +542,7 @@ class ApiUpload extends ApiBase {
                }
 
                // Check blocks
-               if ( $user->isBlocked() ) {
+               if ( $user->isBlockedFromUpload() ) {
                        $this->dieBlocked( $user->getBlock() );
                }
 
index e251fe6..acb3da8 100644 (file)
@@ -51,8 +51,13 @@ class ApiUserrights extends ApiBase {
 
                // Deny if the user is blocked and doesn't have the full 'userrights' permission.
                // This matches what Special:UserRights does for the web UI.
-               if ( $pUser->isBlocked() && !$pUser->isAllowed( 'userrights' ) ) {
-                       $this->dieBlocked( $pUser->getBlock() );
+               if ( !$pUser->isAllowed( 'userrights' ) ) {
+                       // @TODO Should the user be blocked from changing user rights if they
+                       //       are partially blocked?
+                       $block = $pUser->getBlock();
+                       if ( $block ) {
+                               $this->dieBlocked( $block );
+                       }
                }
 
                $params = $this->extractRequestParams();
index 0912dc0..0701829 100644 (file)
        "apihelp-edit-param-text": "محتوى الصفحة",
        "apihelp-edit-param-summary": "ملخص التعديل. أيضا عنوان القسم عند عدم تعيين $1section=new and $1sectiontitle.",
        "apihelp-edit-param-tags": "عدل الوسوم لتطبيق المراجعة.",
-       "apihelp-edit-param-minor": "تعدÙ\8aÙ\84 Ø·Ù\81Ù\8aÙ\81",
-       "apihelp-edit-param-notminor": "تعدÙ\8aÙ\84 ØºÙ\8aر Ø·Ù\81Ù\8aÙ\81.",
+       "apihelp-edit-param-minor": "اÙ\84تعÙ\84Ù\8aÙ\85 Ø¹Ù\84Ù\89 Ù\87ذا Ø§Ù\84تعدÙ\8aÙ\84 Ù\83تعدÙ\8aÙ\84 Ø·Ù\81Ù\8aÙ\81.",
+       "apihelp-edit-param-notminor": "عدÙ\85 Ø§Ù\84تعÙ\84Ù\8aÙ\85 Ø¹Ù\84Ù\89 Ù\87ذا Ø§Ù\84تعدÙ\8aÙ\84 Ù\83تعدÙ\8aÙ\84 Ø·Ù\81Ù\8aÙ\81 Ø­ØªÙ\89 Ø¥Ø°Ø§ ØªÙ\85 ØªØ¹Ù\8aÙ\8aÙ\86 ØªÙ\81ضÙ\8aÙ\84 Ø§Ù\84Ù\85ستخدÙ\85 \"{{int:tog-minordefault}}\".",
        "apihelp-edit-param-bot": "علم على هذا التعديل كتعديل بوت.",
        "apihelp-edit-param-basetimestamp": "الطابع الزمني للمراجعة الأساسية، ويُستخدَم للكشف عن الحروب التحريرية، ويمكن الحصول عليها من خلال [[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]].",
        "apihelp-edit-param-starttimestamp": "الطابع الزمني عند بدء عملية التحرير، ويُستخدَم للكشف عن الحروب التحريرية، ويمكن الحصول عليها من خلال <var>[[Special:ApiHelp/main|curtimestamp]]</var> when beginning the edit process (e.g. when loading the page content to edit).",
        "apihelp-login-param-password": "كلمة السر",
        "apihelp-login-param-domain": "النطاق (اختياري).",
        "apihelp-login-param-token": "تم الحصول على رمز الدخول في الطلب الأول.",
-       "apihelp-login-example-gettoken": "استرداد رمز تسجيل الدخول.",
        "apihelp-login-example-login": "تسجيل الدخول",
        "apihelp-logout-summary": "تسجيل الخروج ومسح بيانات الجلسة.",
        "apihelp-logout-example-logout": "تسجيل خروج المستخدم الحالي.",
        "apihelp-parse-paramvalue-prop-revid": "يضيف معرِف المراجعة للصفحة التي تم تحليلها.",
        "apihelp-parse-paramvalue-prop-displaytitle": "يضيف العنوان في تحليل نصوص الويكي.",
        "apihelp-parse-paramvalue-prop-headitems": "يعطي عناصر لوضعها في <code>&lt;head&gt;</code> الصفحة.",
-       "apihelp-parse-paramvalue-prop-headhtml": "يعطي تحليل <code>&lt;head&gt;</code> الصفحة.",
+       "apihelp-parse-paramvalue-prop-headhtml": "يمنح نوع مستند محلولا، ويفتح عنصر <code>&lt;html&gt;</code>، <code>&lt;head&gt;</code> ويفتح <code>&lt;body&gt;</code> الصفحة.",
        "apihelp-parse-paramvalue-prop-modules": "يعطي وحدات ResourceLoader المستخدمة في الصفحة، للتحميل; استخدم <code>mw.loader.using()</code>، يجب طلب <kbd>jsconfigvars</kbd> أو <kbd>encodedjsconfigvars</kbd> بشكل مشترك مع <kbd>modules</kbd>.",
        "apihelp-parse-paramvalue-prop-jsconfigvars": "يعطي متغيرات تكوين جافا سكريبت الخاصة بهذه الصفحة. للتطبيق; استخدم <code>mw.config.set()</code>.",
        "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "يعطي متغيرات تكوين جافا سكريبت الخاصة بهذه الصفحة كسلسلة JSON.",
        "apihelp-query+allfileusages-paramvalue-prop-title": "تضيف عنوان الملف.",
        "apihelp-query+allfileusages-param-limit": "كم عدد مجموع البنود للعودة.",
        "apihelp-query+allfileusages-param-dir": "الاتجاه للإدراج فيه.",
-       "apihelp-query+allfileusages-example-B": "سرد عناوين الملفات، بما في ذلك العناوين المفقودة، مع معرفات الصفحات التي تنتمي إليها، بدءا من <kbd>B</kbd.",
+       "apihelp-query+allfileusages-example-b": "سرد عناوين الملفات، بما في ذلك العناوين المفقودة، مع معرفات الصفحات التي تنتمي إليها، بدءا من <kbd>B</kbd.",
        "apihelp-query+allfileusages-example-unique": "سرد عناوين الملفات الفريدة.",
        "apihelp-query+allfileusages-example-unique-generator": "الحصول على جميع عناوين الملفات، والتعليم على المفقودة.",
        "apihelp-query+allfileusages-example-generator": "الحصول على الصفحات التي تحتوي على الملفات.",
        "apihelp-query+allimages-param-filterbots": "كيفية تصفية الملفات التي تم تحميلها بواسطة بوتات. يمكن استخدامها مع $1sort=timestamp فقط. لا يمكن أن تُستخدَم بجانب $1user.",
        "apihelp-query+allimages-param-mime": "عن أي أنواع MIME تبحث، على سبيل المثال <kbd>image/jpeg</kbd>.",
        "apihelp-query+allimages-param-limit": "كم عدد الصور الإجمالي للعودة.",
-       "apihelp-query+allimages-example-B": "أظهر قائمة الملفات التي تبدأ ب<kbd>B</kbd>.",
+       "apihelp-query+allimages-example-b": "أظهر قائمة الملفات التي تبدأ ب<kbd>B</kbd>.",
        "apihelp-query+allimages-example-recent": "أظهر قائمة الملفات التي تم تحميلها مؤخرا، على غرار [[Special:NewFiles|خاص:ملفات جديدة]].",
        "apihelp-query+allimages-example-mimetypes": "أظهر قائمة الملفات من نوع MIME <kbd>image/png</kbd> أو <kbd>image/gif</kbd>",
        "apihelp-query+allimages-example-generator": "عرض معلومات حول 4 ملفات تبدأ بالحرف <kbd>T</kbd>.",
        "apihelp-query+alllinks-param-namespace": "نطاق للتعداد.",
        "apihelp-query+alllinks-param-limit": "كم عدد مجموع البنود للعودة.",
        "apihelp-query+alllinks-param-dir": "الاتجاه للإدراج فيه.",
-       "apihelp-query+alllinks-example-B": "سرد العناوين المرتبطة، بما في ذلك المفقودة، مع معرفات الصفحات التي تنتمي إليها، بدءا من <kbd>B</kbd.",
+       "apihelp-query+alllinks-example-b": "سرد العناوين المرتبطة، بما في ذلك المفقودة، مع معرفات الصفحات التي تنتمي إليها، بدءا من <kbd>B</kbd.",
        "apihelp-query+alllinks-example-unique": "سرد العناوين المرتبطة الفريدة.",
        "apihelp-query+alllinks-example-unique-generator": "الحصول على جميع العناوين المرتبطة، والتعليم على المفقودة.",
        "apihelp-query+alllinks-example-generator": "يحصل على الصفحات التي تحتوي على وصلات.",
        "apihelp-query+allpages-param-dir": "الاتجاه للإدراج فيه.",
        "apihelp-query+allpages-param-filterlanglinks": "التصفية استنادا إلى ما إذا كانت الصفحة تحتوي على وصلات لغات، لاحظ أن هذا قد لا يفكر في  وصلات اللغات المضافة بواسطة الإضافات.",
        "apihelp-query+allpages-param-prexpiry": "مدة انتهاء الحماية لتصفية الصفحة فيها: \n; غير محددة: احصل على الصفحات التي لها تاريخ انتهاء غير محدود للحماية. \n; واضح: احصل على صفحات ذات مدة حماية محددة فقط.\n; الكل: الحصول على صفحات بأي انتهاء صلاحية للحماية.",
-       "apihelp-query+allpages-example-B": "عرض  قائمة من الصفحات التي تبدأ بالحرف <kbd>B</kbd>.",
+       "apihelp-query+allpages-example-b": "عرض  قائمة من الصفحات التي تبدأ بالحرف <kbd>B</kbd>.",
        "apihelp-query+allpages-example-generator": "عرض معلومات حول 4 صفحات تبدأ بالحرف <kbd>T</kbd>.",
        "apihelp-query+allpages-example-generator-revisions": "عرض محتوى أول صفحتين غير تحويلتين  التي تبدأ من <kbd>Re</kbd.",
        "apihelp-query+allredirects-summary": "أدرج جميع التحويلات إلى نطاق.",
        "apihelp-query+allredirects-param-namespace": "نطاق للتعداد.",
        "apihelp-query+allredirects-param-limit": "كم عدد مجموع البنود للعودة.",
        "apihelp-query+allredirects-param-dir": "الاتجاه للإدراج فيه.",
-       "apihelp-query+allredirects-example-B": "سرد الصفحات الهدف، بما في ذلك المفقودة، مع معرفات الصفحات التي تنتمي إليها، بدءا من <kbd>B</kbd.",
+       "apihelp-query+allredirects-example-b": "سرد الصفحات الهدف، بما في ذلك المفقودة، مع معرفات الصفحات التي تنتمي إليها، بدءا من <kbd>B</kbd.",
        "apihelp-query+allredirects-example-unique": "سرد الصفحات الهدف الفريدة.",
        "apihelp-query+allredirects-example-unique-generator": "الحصول على جميع الصفحات المستهدفة، والتعليم على المفقودة.",
        "apihelp-query+allredirects-example-generator": "يحصل على الصفحات التي تحتوي على تحويلات.",
        "apihelp-query+alltransclusions-param-namespace": "النطاق للتعداد.",
        "apihelp-query+alltransclusions-param-limit": "كم عدد العناصر لإرجاعها.",
        "apihelp-query+alltransclusions-param-dir": "الاتجاه للإدراج فيه.",
-       "apihelp-query+alltransclusions-example-B": "سرد العناوين المعطلة، بما في ذلك المفقودة، مع معرفات الصفحات التي تنتمي إليها، بدءا من <kbd>B</ kbd>.",
+       "apihelp-query+alltransclusions-example-b": "سرد العناوين المعطلة، بما في ذلك المفقودة، مع معرفات الصفحات التي تنتمي إليها، بدءا من <kbd>B</ kbd>.",
        "apihelp-query+alltransclusions-example-unique": "إدراج عناوين مضمنة فريدة.",
        "apihelp-query+alltransclusions-example-unique-generator": "الحصول على جميع العناوين المضمنة، والتعليم على المفقودة.",
        "apihelp-query+alltransclusions-example-generator": "يحصل على الصفحات التي تحتوي على تضمينات.",
        "apihelp-query+allusers-param-witheditsonly": "سرد المستخدمين الذين قاموا بتحريرات فقط.",
        "apihelp-query+allusers-param-activeusers": "سرد المستخدمين النشطين في آخر $1 {{PLURAL:$1|يوم|أيام}} فقط.",
        "apihelp-query+allusers-param-attachedwiki": "باستخدام <kbd>$1prop=centralids</kbd>، أشر أيضا إلى ما إذا كان المستخدم مرتبطا بالويكي المحدد بواسطة هذا المعرف.",
-       "apihelp-query+allusers-example-Y": "سرد المستخدمين ابتداء من <kbd>Y</kbd>.",
+       "apihelp-query+allusers-example-y": "سرد المستخدمين ابتداء من <kbd>Y</kbd>.",
        "apihelp-query+authmanagerinfo-summary": "استرداد معلومات حول حالة المصادقة الحالية.",
        "apihelp-query+authmanagerinfo-param-securitysensitiveoperation": "اختبار ما إذا كانت حالة المصادقة الحالية للمستخدم كافية للعملية الحساسة للأمان المحددة أم لا.",
        "apihelp-query+authmanagerinfo-param-requestsfor": "إحضار معلومات حول طلبات المصادقة المطلوبة لإجراء المصادقة المحدد.",
        "apihelp-query+userinfo-paramvalue-prop-registrationdate": "يضيف تاريخ تسجيل المستخدم.",
        "apihelp-query+userinfo-paramvalue-prop-unreadcount": "يضيف عدد الصفحات غير المقروءة في قائمة مراقبة المستخدم (بحد أقصى $1; ترجع <samp>$2</samp> إذا كان أكثر).",
        "apihelp-query+userinfo-paramvalue-prop-centralids": "يضيف المعرفات المركزية وحالة المرفقات للمستخدم.",
+       "apihelp-query+userinfo-paramvalue-prop-latestcontrib": "يضيف تاريخ آخر مساهمة للمستخدم.",
        "apihelp-query+userinfo-param-attachedwiki": "باستخدام <kbd>$1prop=centralids</kbd>، حدد ما إذا كان المستخدم مرتبطا بالويكي المحدد بواسطة هذا المعرف.",
        "apihelp-query+userinfo-example-simple": "الحصول على معلومات حول المستخدم الحالي.",
        "apihelp-query+userinfo-example-data": "الحصول على معلومات حول المستخدم الحالي.",
        "apiwarn-validationfailed-cannotset": "لا يمكن ضبطها بواسطة هذه الوحدة.",
        "apiwarn-validationfailed-keytoolong": "المفتاح طويل جدًا (لا يُسمَح بأكثر من $1 بايت).",
        "apiwarn-validationfailed": "خطأ في التحقق من <kbd>$1</kbd>: $2",
-       "apiwarn-wgDebugAPI": "<strong>تحذير الأمان</strong>: تم تمكين <var>$wgDebugAPI</var>.",
+       "apiwarn-wgdebugapi": "<strong>تحذير الأمان</strong>: تم تمكين <var>$wgDebugAPI</var>.",
        "api-feed-error-title": "خطأ ($1)",
        "api-usage-docref": "راجع $1 لاستخدام API.",
        "api-usage-mailinglist-ref": "اشترك في القائمة البريدية لإعلان api ميدياويكي في &lt;https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce&gt ; للحصول على إشعار بإيقاف API وإيقاف التغييرات.",
index c401ec7..e7f3fa5 100644 (file)
        "apihelp-login-param-password": "Серһүҙ.",
        "apihelp-login-param-domain": "Домен (мотлаҡ түгел).",
        "apihelp-login-param-token": "Беренсе һорау ваҡытынла алынған логин маркер",
-       "apihelp-login-example-gettoken": "Системаға инеү маркерын алыу.",
        "apihelp-login-example-login": "Танылыу.",
        "apihelp-logout-summary": "Сығырға һәм сессия мәғлүмәтен юйырға.",
        "apihelp-logout-example-logout": "Ағымдағы ҡулланыусының киткән саҡта инеүе",
        "apihelp-query+allimages-param-minsize": "Һүрәттәр лимиты (байттарҙа).",
        "apihelp-query+allimages-param-maxsize": "Бар һүрәттәр лимиты (байттарҙа).",
        "apihelp-query+allimages-param-limit": "Кире ҡайтыу өсөн образдар һаны.",
-       "apihelp-query+allimages-example-B": "<kbd>Б</kbd> хәрефенән башланған файлдар исемлеген күрһәтергә.",
+       "apihelp-query+allimages-example-b": "<kbd>Б</kbd> хәрефенән башланған файлдар исемлеген күрһәтергә.",
        "apihelp-query+allimages-example-generator": "<kbd>Б</kbd> хәрефенән башланған файлдар исемлеген күрһәтергә.",
        "apihelp-query+alllinks-summary": "Бирелгән исемдәр арауығына йүнәлткән барлыҡ һылтанмаларҙы һанап сығырға.",
        "apihelp-query+alllinks-param-from": "Һанауҙы башлау өсөн һылтанма атамаһы.",
        "apihelp-query+allpages-param-minsize": "Һүрәттәр лимиты (байттарҙа).",
        "apihelp-query+allpages-param-limit": "Нисә битте тергеҙергә?",
        "apihelp-query+allpages-param-dir": "Һанау йүнәлеше.",
-       "apihelp-query+allpages-example-B": "<kbd>Б</kbd> хәрефенән башланған файлдар исемлеген күрһәтергә.",
+       "apihelp-query+allpages-example-b": "<kbd>Б</kbd> хәрефенән башланған файлдар исемлеген күрһәтергә.",
        "apihelp-query+allpages-example-generator": "<kbd>Б</kbd> хәрефенән башланған файлдар исемлеген күрһәтергә.",
        "apihelp-query+allredirects-param-from": "Һанауҙы туҡтатыу файлы атамаһы.",
        "apihelp-query+allredirects-param-to": "Һанауҙы туҡтатыу файлы атамаһы.",
index 91fecc1..731e401 100644 (file)
@@ -13,7 +13,8 @@
                        "Dvorapa",
                        "Matěj Suchánek",
                        "Ilimanaq29",
-                       "Patriccck"
+                       "Patriccck",
+                       "Ján Kepler"
                ]
        },
        "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|Dokumentace]]\n* [[mw:Special:MyLanguage/API:FAQ|Otázky a odpovědi]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api E-mailová konference]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Oznámení k API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Chyby a požadavky]\n</div>\n<strong>Stav:</strong> Všechny funkce uvedené na této stránce by měly fungovat, ale API se stále aktivně vyvíjí a může se kdykoli změnit. Upozornění na změny získáte přihlášením se k [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ e-mailové konferenci mediawiki-api-announce].\n\n<strong>Chybné požadavky:</strong> Pokud jsou do API zaslány chybné požadavky, bude vrácena HTTP hlavička s klíčem „MediaWiki-API-Error“ a hodnota této hlavičky a chybový kód budou nastaveny na stejnou hodnotu. Více informací najdete [[mw:Special:MyLanguage/API:Errors_and_warnings|v dokumentaci]].\n\n<p class=\"mw-apisandbox-link\"><strong>Testování:</strong> Pro jednoduché testování požadavků na API zkuste [[Special:ApiSandbox]].</p>",
@@ -67,7 +68,7 @@
        "apihelp-edit-param-pageid": "ID stránky, která se má editovat. Není možné použít společně s <var>$1title</var>.",
        "apihelp-edit-param-sectiontitle": "Název nové sekce.",
        "apihelp-edit-param-text": "Obsah stránky.",
-       "apihelp-edit-param-minor": "Malá editace.",
+       "apihelp-edit-param-minor": "Označit toto jako malou editaci",
        "apihelp-edit-param-notminor": "Nemalá editace.",
        "apihelp-edit-param-bot": "Označit tuto editaci jako editaci robota.",
        "apihelp-edit-param-createonly": "Needitovat stránku, pokud již existuje.",
        "apihelp-query+allpages-param-filterredir": "Které stránky uvést na seznam.",
        "apihelp-query+allpages-param-minsize": "Omezit na stránky s určitým počtem bajtů.",
        "apihelp-query+allpages-param-prtype": "Omezit jen na zamčené stránky.",
-       "apihelp-query+allpages-example-B": "Zobrazit seznam stránek začínajících na písmeno <kbd>B</kbd>.",
+       "apihelp-query+allpages-example-b": "Zobrazit seznam stránek začínajících na písmeno <kbd>B</kbd>.",
        "apihelp-query+allredirects-summary": "Seznam všech přesměrování pro jmenný prostor.",
        "apihelp-query+allredirects-example-unique": "Seznam unikátních cílových stránek.",
        "apihelp-query+allredirects-example-generator": "Získat stránky obsahující přesměrování.",
        "apihelp-query+alltransclusions-param-limit": "Kolik položek zobrazit celkem.",
        "apihelp-query+alltransclusions-example-unique": "Seznam unikátně vložených titulů.",
-       "apihelp-query+allusers-example-Y": "Zobrazit uživatele počínaje písmenem <kbd>Y</kbd>.",
+       "apihelp-query+allusers-example-y": "Zobrazit uživatele počínaje písmenem <kbd>Y</kbd>.",
        "apihelp-query+backlinks-summary": "Najít všechny stránky, které odkazují na danou stránku.",
        "apihelp-query+backlinks-example-simple": "Zobrazit odkazy na <kbd>Main page</kbd>.",
        "apihelp-query+blocks-example-simple": "Vypsat zablokování.",
        "api-help-flag-generator": "Tento modul lze využívat jako generátor.",
        "api-help-source": "Zdroj: $1",
        "api-help-license": "Licence: [[$1|$2]]",
-       "api-help-license-noname": "Licence: [[$1|Vizte odkaz]]",
+       "api-help-license-noname": "Licence: [[$1|Viz odkaz]]",
        "api-help-license-unknown": "Licence: <span class=\"apihelp-unknown\">neznámá</span>",
        "api-help-parameters": "{{PLURAL:$1|Parametr|Parametry}}:",
        "api-help-param-deprecated": "Zastaralý.",
index b7892f0..2493349 100644 (file)
@@ -20,7 +20,8 @@
                        "Eddie",
                        "Zenith",
                        "Tacsipacsi",
-                       "FF11"
+                       "FF11",
+                       "DerHexer"
                ]
        },
        "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|Dokumentation]]\n* [[mw:Special:MyLanguage/API:FAQ|Häufig gestellte Fragen]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Mailingliste]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API-Ankündigungen]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Fehlerberichte und Anfragen]\n</div>\n<strong>Status:</strong> Die MediaWiki-API ist eine ausgereifte und stabile Schnittstelle, die aktiv unterstützt und verbessert wird. Während wir versuchen, dies zu vermeiden, können wir gelegentlich Breaking Changes erforderlich machen. Abonniere die [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ MediaWiki-API-Ankündigungs-Mailingliste] für Mitteilungen zu Aktualisierungen.\n\n<strong>Fehlerhafte Anfragen:</strong> Wenn fehlerhafte Anfragen an die API gesendet werden, wird ein HTTP-Header mit dem Schlüssel „MediaWiki-API-Error“ gesendet. Der Wert des Headers und der Fehlercode werden auf den gleichen Wert gesetzt. Für weitere Informationen siehe [[mw:Special:MyLanguage/API:Errors_and_warnings|API: Fehler und Warnungen]].\n\n<p class=\"mw-apisandbox-link\"><strong>Testen:</strong> Zum einfachen Testen von API-Anfragen, siehe [[Special:ApiSandbox]].</p>",
        "apihelp-compare-param-fromtitle": "Erster zu vergleichender Titel.",
        "apihelp-compare-param-fromid": "Erste zu vergleichende Seitennummer.",
        "apihelp-compare-param-fromrev": "Erste zu vergleichende Version.",
+       "apihelp-compare-param-frompst": "Führt eine Vorspeicherungsumwandlung für <var>fromtext-&#x7B;slot}</var> aus.",
+       "apihelp-compare-param-fromsection": "Nur den angegebenen Abschnitt des angegebenen „from“-Inhalts verwenden.",
        "apihelp-compare-param-totitle": "Zweiter zu vergleichender Titel.",
        "apihelp-compare-param-toid": "Zweite zu vergleichende Seitennummer.",
        "apihelp-compare-param-torev": "Zweite zu vergleichende Version.",
+       "apihelp-compare-param-topst": "Führt eine Vorspeicherungsumwandlung für <var>totext</var> aus.",
+       "apihelp-compare-param-prop": "Welche Informationen abgerufen werden sollen.",
        "apihelp-compare-paramvalue-prop-diff": "Das Unterschieds-HTML.",
        "apihelp-compare-paramvalue-prop-diffsize": "Die Größe des Unterschieds-HTML in Bytes.",
        "apihelp-compare-paramvalue-prop-title": "Die Seitentitel der Versionen „Von“ und „Nach“.",
+       "apihelp-compare-paramvalue-prop-user": "Der Benutzername und die -kennung der „from“- und „to“-Versionen.",
+       "apihelp-compare-paramvalue-prop-comment": "Der Kommentar zu den „from“- und „to“-Versionen.",
+       "apihelp-compare-paramvalue-prop-parsedcomment": "Der geparste Kommentar zu den „from“- und „to“-Versionen.",
        "apihelp-compare-paramvalue-prop-size": "Die Größe der Versionen „from“ und „to“.",
        "apihelp-compare-example-1": "Unterschied zwischen Version 1 und 2 abrufen",
        "apihelp-createaccount-summary": "Erstellt ein neues Benutzerkonto.",
        "apihelp-createaccount-param-preservestate": "Falls <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> für <samp>hasprimarypreservedstate</samp> wahr ausgegeben hat, sollten Anfragen, die als <samp>primary-required</samp> markiert wurden, ausgelassen werden. Falls ein nicht-leerer Wert für <samp>preservedusername</samp> zurückgegeben wurde, muss dieser Benutzername für den Parameter <var>username</var> verwendet werden.",
+       "apihelp-cspreport-param-source": "Was der CSP-Header erzeugt hat, der diesen Bericht ausgelöst hat.",
        "apihelp-delete-summary": "Löscht eine Seite.",
        "apihelp-delete-param-title": "Titel der Seite, die gelöscht werden soll. Kann nicht zusammen mit <var>$1pageid</var> verwendet werden.",
        "apihelp-delete-param-pageid": "Seitennummer der Seite, die gelöscht werden soll. Kann nicht zusammen mit <var>$1title</var> verwendet werden.",
        "apihelp-edit-param-text": "Seiteninhalt.",
        "apihelp-edit-param-summary": "Bearbeitungszusammenfassung. Auch Abschnittsüberschrift, wenn $1section=new und $1sectiontitle nicht festgelegt ist.",
        "apihelp-edit-param-tags": "Auf die Version anzuwendende Änderungsmarkierungen.",
-       "apihelp-edit-param-minor": "Kleine Bearbeitung.",
-       "apihelp-edit-param-notminor": "Nicht-kleine Bearbeitung.",
+       "apihelp-edit-param-minor": "Markiert diese Bearbeitung als geringfügig.",
+       "apihelp-edit-param-notminor": "Diese Bearbeitung nicht als geringfügig markieren, auch wenn die Benutzereinstellung „{{int:tog-minordefault}}“ festgelegt ist.",
        "apihelp-edit-param-bot": "Diese Bearbeitung als Bot-Bearbeitung markieren.",
        "apihelp-edit-param-basetimestamp": "Zeitstempel der Basisversion, wird verwendet zum Aufspüren von Bearbeitungskonflikten. Kann abgerufen werden durch [[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]].",
        "apihelp-edit-param-starttimestamp": "Zeitstempel, an dem der Bearbeitungsprozess begonnen wurde. Er wird zum Aufspüren von Bearbeitungskonflikten verwendet. Ein geeigneter Wert kann mithilfe von <var>[[Special:ApiHelp/main|curtimestamp]]</var> beim Beginn des Bearbeitungsprozesses (z.&nbsp;B. beim Laden des Seiteninhalts zum Bearbeiten) abgerufen werden.",
        "apihelp-login-param-password": "Passwort.",
        "apihelp-login-param-domain": "Domain (optional).",
        "apihelp-login-param-token": "Anmeldetoken, den du in der ersten Anfrage erhalten hast.",
-       "apihelp-login-example-gettoken": "Ruft einen Anmelde-Token ab",
        "apihelp-login-example-login": "Anmelden",
        "apihelp-logout-summary": "Abmelden und alle Sitzungsdaten löschen.",
        "apihelp-logout-example-logout": "Meldet den aktuellen Benutzer ab",
        "apihelp-parse-paramvalue-prop-sections": "Gibt die Abschnitte im geparsten Wikitext zurück.",
        "apihelp-parse-paramvalue-prop-revid": "Ergänzt die Versionskennung der geparsten Seite.",
        "apihelp-parse-paramvalue-prop-displaytitle": "Ergänzt den Titel des geparsten Wikitextes.",
-       "apihelp-parse-paramvalue-prop-headhtml": "Gibt geparsten <code>&lt;head&gt;</code> der Seite zurück.",
+       "apihelp-parse-paramvalue-prop-headhtml": "Gibt geparsten doctype, offenes <code>&lt;html&gt;</code>, das Element <code>&lt;head&gt;</code> und offenes <code>&lt;body&gt;</code> der Seite aus.",
        "apihelp-parse-paramvalue-prop-jsconfigvars": "Gibt die JavaScript-Konfigurationsvariablen speziell für die Seite aus. Zur Anwendung verwende <code>mw.config.set()</code>.",
        "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "Gibt die JavaScript-Konfigurationsvariablen speziell für die Seite als JSON-Zeichenfolge aus.",
        "apihelp-parse-paramvalue-prop-indicators": "Gibt das HTML der Seitenstatusindikatoren zurück, die auf der Seite verwendet werden.",
        "apihelp-query+allfileusages-paramvalue-prop-title": "Ergänzt den Titel der Datei.",
        "apihelp-query+allfileusages-param-limit": "Wie viele Gesamtobjekte zurückgegeben werden sollen.",
        "apihelp-query+allfileusages-param-dir": "Aufzählungsrichtung.",
-       "apihelp-query+allfileusages-example-B": "Liste Dateititel, einschließlich fehlender, mit den Seiten-IDs von denen sie stammen, beginne bei <kbd>B</kbd>.",
+       "apihelp-query+allfileusages-example-b": "Liste Dateititel, einschließlich fehlender, mit den Seiten-IDs von denen sie stammen, beginne bei <kbd>B</kbd>.",
        "apihelp-query+allfileusages-example-unique": "Einheitliche Dateititel auflisten",
        "apihelp-query+allfileusages-example-unique-generator": "Ruft alle Dateititel ab und markiert die fehlenden.",
        "apihelp-query+allfileusages-example-generator": "Seiten abrufen, die die Dateien enthalten",
        "apihelp-query+allimages-param-filterbots": "Wie Dateien, die von Bots hochgeladen wurden, gefiltert werden sollen. Darf nur mit $1sort=Zeitstempel verwendet werden. Darf nicht zusammen mit $1user verwendet werden.",
        "apihelp-query+allimages-param-mime": "Nach welchem MIME-Typ gesucht werden soll, z.B. <kbd>image/jpeg</kbd>.",
        "apihelp-query+allimages-param-limit": "Wie viele Gesamtbilder zurückgegeben werden sollen.",
-       "apihelp-query+allimages-example-B": "Zeigt eine Liste der Dateien an, die mit dem Buchstaben <kbd>B</kbd> beginnen.",
+       "apihelp-query+allimages-example-b": "Zeigt eine Liste der Dateien an, die mit dem Buchstaben <kbd>B</kbd> beginnen.",
        "apihelp-query+allimages-example-recent": "Zeigt eine Liste von kürzlich hochgeladenen Dateien ähnlich zu [[Special:NewFiles]].",
        "apihelp-query+allimages-example-mimetypes": "Zeige eine Liste von Dateien mit den MIME-Typen  <kbd>image/png</kbd> oder <kbd>image/gif</kbd>",
        "apihelp-query+allimages-example-generator": "Zeige Informationen über 4 Dateien beginnend mit dem Buchstaben <kbd>T</kbd>.",
        "apihelp-query+alllinks-param-namespace": "Der aufzulistende Namensraum.",
        "apihelp-query+alllinks-param-limit": "Wie viele Gesamtobjekte zurückgegeben werden sollen.",
        "apihelp-query+alllinks-param-dir": "Aufzählungsrichtung.",
-       "apihelp-query+alllinks-example-B": "Liste verknüpfte Titel, einschließlich fehlender, mit den Seiten-IDs von denen sie stammen, beginne bei <kbd>B</kbd>.",
+       "apihelp-query+alllinks-example-b": "Liste verknüpfte Titel, einschließlich fehlender, mit den Seiten-IDs von denen sie stammen, beginne bei <kbd>B</kbd>.",
        "apihelp-query+alllinks-example-unique": "Einheitlich verlinkte Titel auflisten",
        "apihelp-query+alllinks-example-unique-generator": "Ruft alle verknüpften Titel ab und markiert die fehlenden.",
        "apihelp-query+alllinks-example-generator": "Ruft Seiten ab welche die Verknüpfungen beinhalten.",
        "apihelp-query+allpages-param-dir": "Aufzählungsrichtung.",
        "apihelp-query+allpages-param-filterlanglinks": "Nur Seiten auflisten, die Sprachlinks haben. Beachte, dass von Erweiterungen gesetzte Sprachlinks möglicherweise nicht beachtet werden.",
        "apihelp-query+allpages-param-prexpiry": "Ablaufzeit des Seitenschutzes, nach dem die Auflistung gefiltert werden soll:\n; indefinite: Nur unbeschränkt geschützte Seiten auflisten.\n; definite: Nur für einen bestimmten Zeitraum geschützte Seiten auflisten.\n; all: geschützte Seiten unabhängig von der Schutzlänge auflisten.",
-       "apihelp-query+allpages-example-B": "Bezieht eine Liste von Seiten, die mit dem Buchstaben <kbd>B</kbd> beginnen.",
+       "apihelp-query+allpages-example-b": "Bezieht eine Liste von Seiten, die mit dem Buchstaben <kbd>B</kbd> beginnen.",
        "apihelp-query+allpages-example-generator": "Gibt Informationen über vier Seiten mit dem Anfangsbuchstaben <kbd>T</kbd> zurück.",
        "apihelp-query+allpages-example-generator-revisions": "Übermittelt den Inhalt der ersten beiden Seiten, die mit <kbd>Re</kbd> beginnen und keine Weiterleitungen sind.",
        "apihelp-query+allredirects-summary": "Bezieht alle Weiterleitungen in einem Namensraum.",
        "apihelp-query+allredirects-param-namespace": "Der zu untersuchende Namensraum.",
        "apihelp-query+allredirects-param-limit": "Gesamtanzahl der aufzulistenden Einträge.",
        "apihelp-query+allredirects-param-dir": "Aufzählungsrichtung.",
-       "apihelp-query+allredirects-example-B": "Listet Zielseiten, auch fehlende, mit den Seitenkennungen der Weiterleitung auf, beginnend bei <kbd>B</kbd>.",
+       "apihelp-query+allredirects-example-b": "Listet Zielseiten, auch fehlende, mit den Seitenkennungen der Weiterleitung auf, beginnend bei <kbd>B</kbd>.",
        "apihelp-query+allredirects-example-unique": "Einzigartige Zielseiten auflisten.",
        "apihelp-query+allredirects-example-unique-generator": "Bezieht alle Zielseiten und markiert die Fehlenden.",
        "apihelp-query+allredirects-example-generator": "Seiten abrufen, die die Weiterleitungen enthalten",
        "apihelp-query+alltransclusions-param-namespace": "Der aufzulistende Namensraum.",
        "apihelp-query+alltransclusions-param-limit": "Wie viele Gesamtobjekte zurückgegeben werden sollen.",
        "apihelp-query+alltransclusions-param-dir": "Die Auflistungsrichtung.",
-       "apihelp-query+alltransclusions-example-B": "Liste transkludierte Titel, einschließlich fehlender, mit den Seiten-IDs von denen sie stammen, beginne bei <kbd>B</kbd>.",
+       "apihelp-query+alltransclusions-example-b": "Liste transkludierte Titel, einschließlich fehlender, mit den Seiten-IDs von denen sie stammen, beginne bei <kbd>B</kbd>.",
        "apihelp-query+alltransclusions-example-unique": "Einzigartige eingebundene Titel auflisten.",
        "apihelp-query+alltransclusions-example-unique-generator": "Ruft alle transkludierten Titel ab und markiert die fehlenden.",
        "apihelp-query+alltransclusions-example-generator": "Ruft Seiten ab welche die Transklusionen beinhalten.",
        "apihelp-query+allusers-param-limit": "Wie viele Benutzernamen insgesamt zurückgegeben werden sollen.",
        "apihelp-query+allusers-param-witheditsonly": "Listet nur Benutzer auf, die Bearbeitungen vorgenommen haben.",
        "apihelp-query+allusers-param-activeusers": "Listet nur Benutzer auf, die in den letzten $1 {{PLURAL:$1|Tag|Tagen}} aktiv waren.",
-       "apihelp-query+allusers-example-Y": "Benutzer ab <kbd>Y</kbd> auflisten.",
+       "apihelp-query+allusers-example-y": "Benutzer ab <kbd>Y</kbd> auflisten.",
        "apihelp-query+authmanagerinfo-example-login": "Ruft die Anfragen ab, die beim Beginnen einer Anmeldung verwendet werden können.",
        "apihelp-query+authmanagerinfo-example-login-merged": "Ruft die Anfragen ab, die beim Beginnen einer Anmeldung verwendet werden können, mit zusammengeführten Formularfeldern.",
        "apihelp-query+authmanagerinfo-example-securitysensitiveoperation": "Testet, ob die Authentifizierung für die Aktion <kbd>foo</kbd> ausreichend ist.",
        "apihelp-query+filearchive-paramvalue-prop-archivename": "Fügt den Dateinamen der Archivversion für die nicht-neuesten Versionen hinzu.",
        "apihelp-query+filearchive-example-simple": "Eine Liste aller gelöschten Dateien auflisten",
        "apihelp-query+filerepoinfo-summary": "Gebe Metainformationen über Bild-Repositorien zurück, die im Wiki eingerichtet sind.",
+       "apihelp-query+filerepoinfo-paramvalue-prop-apiurl": "URL zur Repositoriums-API. Nützlich zum Abruf von Bildinformationen vom Host.",
        "apihelp-query+filerepoinfo-paramvalue-prop-displayname": "Der menschenlesbare Name des Repositoriumwikis.",
        "apihelp-query+filerepoinfo-paramvalue-prop-initialCapital": "Ob Dateinamen implizit mit einem Großbuchstaben beginnen.",
        "apihelp-query+filerepoinfo-paramvalue-prop-local": "Ob dieses Repositorium das lokale ist oder nicht.",
        "apihelp-query+userinfo-paramvalue-prop-options": "Listet alle Einstellungen auf, die der aktuelle Benutzer festgelegt hat.",
        "apihelp-query+userinfo-paramvalue-prop-editcount": "Ergänzt den Bearbeitungszähler des aktuellen Benutzers.",
        "apihelp-query+userinfo-paramvalue-prop-realname": "Fügt den bürgerlichen Namen des Benutzers hinzu.",
+       "apihelp-query+userinfo-paramvalue-prop-latestcontrib": "Ergänzt das Datum des letzten Benutzerbeitrags.",
        "apihelp-query+userinfo-example-simple": "Informationen über den aktuellen Benutzer abrufen",
        "apihelp-query+userinfo-example-data": "Ruft zusätzliche Informationen über den aktuellen Benutzer ab.",
        "apihelp-query+users-summary": "Informationen über eine Liste von Benutzern abrufen.",
        "apierror-maxbytes": "Der Parameter <var>$1</var> kann nicht länger sein als {{PLURAL:$2|ein Byte|$2 Bytes}}",
        "apierror-maxchars": "Der Parameter <var>$1</var> kann nicht länger sein als {{PLURAL:$2|ein|$2}} Zeichen",
        "apierror-missingcontent-revid-role": "Fehlender Inhalt für die Versionskennung $1 für die Rolle $2.",
+       "apierror-mustbeloggedin": "Du musst eingeloggt sein, um $1.",
        "apierror-nosuchsection": "Es gibt keinen Abschnitt $1.",
        "apierror-nosuchuserid": "Es gibt keinen Benutzer mit der Kennung $1.",
        "apierror-offline": "Aufgrund von Problemen bei der Netzwerkverbindung kannst du nicht weitermachen. Stelle sicher, dass du eine funktionierende Internetverbindung hast und versuche es erneut.",
        "apierror-systemblocked": "Du wurdest von MediaWiki automatisch gesperrt.",
        "apierror-timeout": "Der Server hat nicht innerhalb der erwarteten Zeit reagiert.",
        "apierror-toomanyvalues": "Es wurden zu viele Werte für den Parameter <var>$1</var> angegeben. Die Obergrenze liegt bei $2.",
+       "apierror-unknownerror-editpage": "Unbekannter EditPage-Fehler: $1.",
        "apierror-unknownerror-nocode": "Unbekannter Fehler.",
        "apierror-unknownerror": "Unbekannter Fehler: „$1“.",
        "apierror-unknownformat": "Nicht erkanntes Format „$1“.",
+       "apierror-upload-missingresult": "Kein Ergebnis in den Statusdaten.",
        "apiwarn-compare-no-next": "Die Version $2 ist die aktuelle Version von $1. Es gibt keine zu vergleichende Version für <kbd>torelative=next</kbd>.",
        "apiwarn-compare-no-prev": "Die Version $2 ist die aktuelle Version von $1. Es gibt keine zu vergleichende Version für <kbd>torelative=prev</kbd>.",
        "apiwarn-deprecation-missingparam": "Da <var>$1</var> nicht angegeben wurde, wurde ein veraltetes Format für die Ausgabe verwendet. Dieses Format ist veraltet und in Zukunft wird immer das neue Format benutzt.",
+       "apiwarn-deprecation-parameter": "Der Parameter <var>$1</var> ist veraltet.",
        "apiwarn-ignoring-invalid-templated-value": "Ignorieren des Wertes <kbd>$2</kbd> in <var>$1</var> bei der Verarbeitung von Vorlagenparametern.",
        "apiwarn-invalidcategory": "„$1“ ist keine Kategorie.",
        "apiwarn-invalidtitle": "„$1“ ist kein gültiger Titel.",
        "api-feed-error-title": "Fehler ($1)",
        "api-usage-docref": "Siehe $1 zur Verwendung der API.",
        "api-usage-mailinglist-ref": "Abonniere die Mailingliste „mediawiki-api-announce“ auf &lt;https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce&gt; zum Feststellen von API-Veralterungen und „Breaking Changes“.",
+       "api-exception-trace": "$1 bei $2($3)\n$4",
        "api-credits-header": "Danksagungen",
        "api-credits": "API-Entwickler:\n* Roan Kattouw (Hauptentwickler von September 2007 bis 2009)\n* Victor Vasiliev\n* Bryan Tong Minh\n* Sam Reed\n* Yuri Astrakhan (Autor, Hauptentwickler von September 2006 bis September 2007)\n* Brad Jorsch (Hauptentwickler seit 2013)\n\nBitte sende deine Kommentare, Vorschläge und Fragen an mediawiki-api@lists.wikimedia.org\noder reiche einen Fehlerbericht auf https://phabricator.wikimedia.org/ ein."
 }
index 7204d27..836768e 100644 (file)
@@ -32,7 +32,6 @@
        "apihelp-help-example-query": "Help for two query submodules.",
        "apihelp-import-summary": "Import a page from another wiki, or an XML file.",
        "apihelp-import-extended-description": "Note that the HTTP POST must be done as a file upload (i.e. using multipart/form-data) when sending a file for the <var>xml</var> parameter.",
-       "apihelp-login-example-gettoken": "Retrieve a login token.",
        "apihelp-logout-example-logout": "Log the current user out.",
        "apihelp-move-param-to": "Title to rename the page to.",
        "apihelp-move-param-reason": "Reason for the rename.",
        "apihelp-query+allcategories-example-generator": "Retrieve information about the category page for categories beginning <kbd>List</kbd>.",
        "apihelp-query+allfileusages-example-unique-generator": "Gets all file titles, marking the missing ones.",
        "apihelp-query+alllinks-param-unique": "Only show distinct linked titles. Cannot be used with <kbd>$1prop=ids</kbd>.\nWhen used as a generator, yields target pages instead of source pages.",
-       "apihelp-query+alllinks-example-B": "List linked titles, including missing ones, with page IDs they are from, starting at <kbd>B</kbd>.",
+       "apihelp-query+alllinks-example-b": "List linked titles, including missing ones, with page IDs they are from, starting at <kbd>B</kbd>.",
        "apihelp-query+alllinks-example-unique": "List unique linked titles.",
        "apihelp-query+allmessages-example-ipb": "Show messages starting with <kbd>ipb-</kbd>.",
        "apihelp-query+allmessages-example-de": "Show messages <kbd>august</kbd> and <kbd>mainpage</kbd> in German.",
-       "apihelp-query+allpages-example-B": "Show a list of pages starting at the letter <kbd>B</kbd>.",
-       "apihelp-query+allredirects-example-B": "List target pages, including missing ones, with page IDs they are from, starting at <kbd>B</kbd>.",
+       "apihelp-query+allpages-example-b": "Show a list of pages starting at the letter <kbd>B</kbd>.",
+       "apihelp-query+allredirects-example-b": "List target pages, including missing ones, with page IDs they are from, starting at <kbd>B</kbd>.",
        "apihelp-query+allredirects-example-generator": "Gets pages containing the redirects.",
        "apihelp-query+alltransclusions-example-unique": "List unique transcluded titles.",
        "apihelp-query+alltransclusions-example-generator": "Gets pages containing the transclusions.",
index 25df749..380627d 100644 (file)
        "apihelp-edit-param-text": "Page content.",
        "apihelp-edit-param-summary": "Edit summary. Also section title when $1section=new and $1sectiontitle is not set.",
        "apihelp-edit-param-tags": "Change tags to apply to the revision.",
-       "apihelp-edit-param-minor": "Minor edit.",
-       "apihelp-edit-param-notminor": "Non-minor edit.",
+       "apihelp-edit-param-minor": "Mark this edit as a minor edit.",
+       "apihelp-edit-param-notminor": "Do not mark this edit as a minor edit even if the \"{{int:tog-minordefault}}\" user preference is set.",
        "apihelp-edit-param-bot": "Mark this edit as a bot edit.",
        "apihelp-edit-param-basetimestamp": "Timestamp of the base revision, used to detect edit conflicts. May be obtained through [[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]].",
        "apihelp-edit-param-starttimestamp": "Timestamp when the editing process began, used to detect edit conflicts. An appropriate value may be obtained using <var>[[Special:ApiHelp/main|curtimestamp]]</var> when beginning the edit process (e.g. when loading the page content to edit).",
        "apihelp-login-param-password": "Password.",
        "apihelp-login-param-domain": "Domain (optional).",
        "apihelp-login-param-token": "Login token obtained in first request.",
-       "apihelp-login-example-gettoken": "Retrieve a login token.",
        "apihelp-login-example-login": "Log in.",
 
        "apihelp-logout-summary": "Log out and clear session data.",
        "apihelp-parse-paramvalue-prop-revid": "Adds the revision ID of the parsed page.",
        "apihelp-parse-paramvalue-prop-displaytitle": "Adds the title of the parsed wikitext.",
        "apihelp-parse-paramvalue-prop-headitems": "Gives items to put in the <code>&lt;head&gt;</code> of the page.",
-       "apihelp-parse-paramvalue-prop-headhtml": "Gives parsed <code>&lt;head&gt;</code> of the page.",
+       "apihelp-parse-paramvalue-prop-headhtml": "Gives parsed doctype, opening <code>&lt;html&gt;</code>, <code>&lt;head&gt;</code> element and opening <code>&lt;body&gt;</code> of the page.",
        "apihelp-parse-paramvalue-prop-modules": "Gives the ResourceLoader modules used on the page. To load, use <code>mw.loader.using()</code>. Either <kbd>jsconfigvars</kbd> or <kbd>encodedjsconfigvars</kbd> must be requested jointly with <kbd>modules</kbd>.",
        "apihelp-parse-paramvalue-prop-jsconfigvars": "Gives the JavaScript configuration variables specific to the page. To apply, use <code>mw.config.set()</code>.",
        "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "Gives the JavaScript configuration variables specific to the page as a JSON string.",
        "apihelp-query+allfileusages-paramvalue-prop-title": "Adds the title of the file.",
        "apihelp-query+allfileusages-param-limit": "How many total items to return.",
        "apihelp-query+allfileusages-param-dir": "The direction in which to list.",
-       "apihelp-query+allfileusages-example-B": "List file titles, including missing ones, with page IDs they are from, starting at <kbd>B</kbd>.",
+       "apihelp-query+allfileusages-example-b": "List file titles, including missing ones, with page IDs they are from, starting at <kbd>B</kbd>.",
        "apihelp-query+allfileusages-example-unique": "List unique file titles.",
        "apihelp-query+allfileusages-example-unique-generator": "Gets all file titles, marking the missing ones.",
        "apihelp-query+allfileusages-example-generator": "Gets pages containing the files.",
        "apihelp-query+allimages-param-filterbots": "How to filter files uploaded by bots. Can only be used with $1sort=timestamp. Cannot be used together with $1user.",
        "apihelp-query+allimages-param-mime": "What MIME types to search for, e.g. <kbd>image/jpeg</kbd>.",
        "apihelp-query+allimages-param-limit": "How many images in total to return.",
-       "apihelp-query+allimages-example-B": "Show a list of files starting at the letter <kbd>B</kbd>.",
+       "apihelp-query+allimages-example-b": "Show a list of files starting at the letter <kbd>B</kbd>.",
        "apihelp-query+allimages-example-recent": "Show a list of recently uploaded files, similar to [[Special:NewFiles]].",
        "apihelp-query+allimages-example-mimetypes": "Show a list of files with MIME type <kbd>image/png</kbd> or <kbd>image/gif</kbd>",
        "apihelp-query+allimages-example-generator": "Show info about 4 files starting at the letter <kbd>T</kbd>.",
        "apihelp-query+alllinks-param-namespace": "The namespace to enumerate.",
        "apihelp-query+alllinks-param-limit": "How many total items to return.",
        "apihelp-query+alllinks-param-dir": "The direction in which to list.",
-       "apihelp-query+alllinks-example-B": "List linked titles, including missing ones, with page IDs they are from, starting at <kbd>B</kbd>.",
+       "apihelp-query+alllinks-example-b": "List linked titles, including missing ones, with page IDs they are from, starting at <kbd>B</kbd>.",
        "apihelp-query+alllinks-example-unique": "List unique linked titles.",
        "apihelp-query+alllinks-example-unique-generator": "Gets all linked titles, marking the missing ones.",
        "apihelp-query+alllinks-example-generator": "Gets pages containing the links.",
        "apihelp-query+allpages-param-dir": "The direction in which to list.",
        "apihelp-query+allpages-param-filterlanglinks": "Filter based on whether a page has langlinks. Note that this may not consider langlinks added by extensions.",
        "apihelp-query+allpages-param-prexpiry": "Which protection expiry to filter the page on:\n;indefinite:Get only pages with indefinite protection expiry.\n;definite:Get only pages with a definite (specific) protection expiry.\n;all:Get pages with any protections expiry.",
-       "apihelp-query+allpages-example-B": "Show a list of pages starting at the letter <kbd>B</kbd>.",
+       "apihelp-query+allpages-example-b": "Show a list of pages starting at the letter <kbd>B</kbd>.",
        "apihelp-query+allpages-example-generator": "Show info about 4 pages starting at the letter <kbd>T</kbd>.",
        "apihelp-query+allpages-example-generator-revisions": "Show content of first 2 non-redirect pages beginning at <kbd>Re</kbd>.",
 
        "apihelp-query+allredirects-param-namespace": "The namespace to enumerate.",
        "apihelp-query+allredirects-param-limit": "How many total items to return.",
        "apihelp-query+allredirects-param-dir": "The direction in which to list.",
-       "apihelp-query+allredirects-example-B": "List target pages, including missing ones, with page IDs they are from, starting at <kbd>B</kbd>.",
+       "apihelp-query+allredirects-example-b": "List target pages, including missing ones, with page IDs they are from, starting at <kbd>B</kbd>.",
        "apihelp-query+allredirects-example-unique": "List unique target pages.",
        "apihelp-query+allredirects-example-unique-generator": "Gets all target pages, marking the missing ones.",
        "apihelp-query+allredirects-example-generator": "Gets pages containing the redirects.",
        "apihelp-query+alltransclusions-param-namespace": "The namespace to enumerate.",
        "apihelp-query+alltransclusions-param-limit": "How many total items to return.",
        "apihelp-query+alltransclusions-param-dir": "The direction in which to list.",
-       "apihelp-query+alltransclusions-example-B": "List transcluded titles, including missing ones, with page IDs they are from, starting at <kbd>B</kbd>.",
+       "apihelp-query+alltransclusions-example-b": "List transcluded titles, including missing ones, with page IDs they are from, starting at <kbd>B</kbd>.",
        "apihelp-query+alltransclusions-example-unique": "List unique transcluded titles.",
        "apihelp-query+alltransclusions-example-unique-generator": "Gets all transcluded titles, marking the missing ones.",
        "apihelp-query+alltransclusions-example-generator": "Gets pages containing the transclusions.",
        "apihelp-query+allusers-param-witheditsonly": "Only list users who have made edits.",
        "apihelp-query+allusers-param-activeusers": "Only list users active in the last $1 {{PLURAL:$1|day|days}}.",
        "apihelp-query+allusers-param-attachedwiki": "With <kbd>$1prop=centralids</kbd>, also indicate whether the user is attached with the wiki identified by this ID.",
-       "apihelp-query+allusers-example-Y": "List users starting at <kbd>Y</kbd>.",
+       "apihelp-query+allusers-example-y": "List users starting at <kbd>Y</kbd>.",
 
        "apihelp-query+authmanagerinfo-summary": "Retrieve information about the current authentication status.",
        "apihelp-query+authmanagerinfo-param-securitysensitiveoperation": "Test whether the user's current authentication status is sufficient for the specified security-sensitive operation.",
        "apihelp-query+userinfo-paramvalue-prop-registrationdate": "Adds the user's registration date.",
        "apihelp-query+userinfo-paramvalue-prop-unreadcount": "Adds the count of unread pages on the user's watchlist (maximum $1; returns <samp>$2</samp> if more).",
        "apihelp-query+userinfo-paramvalue-prop-centralids": "Adds the central IDs and attachment status for the user.",
+       "apihelp-query+userinfo-paramvalue-prop-latestcontrib": "Adds the date of user's latest contribution.",
        "apihelp-query+userinfo-param-attachedwiki": "With <kbd>$1prop=centralids</kbd>, indicate whether the user is attached with the wiki identified by this ID.",
        "apihelp-query+userinfo-example-simple": "Get information about the current user.",
        "apihelp-query+userinfo-example-data": "Get additional information about the current user.",
        "apiwarn-validationfailed-cannotset": "cannot be set by this module.",
        "apiwarn-validationfailed-keytoolong": "key too long (no more than $1 bytes allowed).",
        "apiwarn-validationfailed": "Validation error for <kbd>$1</kbd>: $2",
-       "apiwarn-wgDebugAPI": "<strong>Security Warning</strong>: <var>$wgDebugAPI</var> is enabled.",
+       "apiwarn-wgdebugapi": "<strong>Security Warning</strong>: <var>$wgDebugAPI</var> is enabled.",
 
        "api-feed-error-title": "Error ($1)",
        "api-usage-docref": "See $1 for API usage.",
index 6862e63..d4ffd44 100644 (file)
@@ -40,8 +40,8 @@
        "apihelp-main-param-action": "Qué acción se realizará.",
        "apihelp-main-param-format": "El formato de la salida.",
        "apihelp-main-param-maxlag": "Se puede usar el retardo máximo cuando se instala MediaWiki en un clúster replicado de base de datos. Para evitar acciones que causen más retardo en la replicación del sitio, este parámetro puede hacer que el cliente espere hasta que el retardo en la replicación sea menor que el valor especificado. En caso de retardo excesivo, se devuelve el código de error <samp>maxlag</samp> con un mensaje como <samp>Esperando a $host: $lag segundos de retardo</samp>.<br />Consulta [[mw:Special:MyLanguage/Manual:Maxlag_parameter|Manual: parámetro Maxlag]] para más información.",
-       "apihelp-main-param-smaxage": "Establece la cabecera HTTP <code>s-maxage</code> de control de antememoria a esta cantidad de segundos. Los errores nunca se almacenan en la antememoria.",
-       "apihelp-main-param-maxage": "Establece la cabecera HTTP <code>max-age</code> de control de antememoria a esta cantidad de segundos. Los errores nunca se almacenan en la antememoria.",
+       "apihelp-main-param-smaxage": "Establece la cabecera HTTP <code>s-maxage</code> de control de caché a esta cantidad de segundos. Los errores nunca se almacenan en caché.",
+       "apihelp-main-param-maxage": "Establece la cabecera HTTP <code>max-age</code> de control de caché a esta cantidad de segundos. Los errores nunca se almacenan en la caché.",
        "apihelp-main-param-assert": "Comprobar que el usuario haya iniciado sesión si el valor es <kbd>user</kbd> o si tiene el permiso de bot si es <kbd>bot</kbd>.",
        "apihelp-main-param-assertuser": "Verificar el usuario actual es el usuario nombrado.",
        "apihelp-main-param-requestid": "Cualquier valor dado aquí se incluirá en la respuesta. Se puede utilizar para distinguir solicitudes.",
        "apihelp-login-param-password": "Contraseña.",
        "apihelp-login-param-domain": "Dominio (opcional).",
        "apihelp-login-param-token": "La clave de inicio de sesión se obtiene en la primera solicitud.",
-       "apihelp-login-example-gettoken": "Recuperar clave de inicio de sesión.",
        "apihelp-login-example-login": "Acceder.",
        "apihelp-logout-summary": "Salir y vaciar los datos de la sesión.",
        "apihelp-logout-example-logout": "Cerrar la sesión del usuario actual.",
        "apihelp-query+allfileusages-paramvalue-prop-title": "Agrega el título del archivo.",
        "apihelp-query+allfileusages-param-limit": "Cuántos elementos en total se devolverán.",
        "apihelp-query+allfileusages-param-dir": "La dirección en la que se listará.",
-       "apihelp-query+allfileusages-example-B": "Listar títulos de archivos, incluyendo los desaparecidos, con las ID de páginas a las que pertenecen, empezando por la <kbd>B</kbd>.",
+       "apihelp-query+allfileusages-example-b": "Listar títulos de archivos, incluyendo los desaparecidos, con las ID de páginas a las que pertenecen, empezando por la <kbd>B</kbd>.",
        "apihelp-query+allfileusages-example-unique": "Listar títulos de archivos únicos.",
        "apihelp-query+allfileusages-example-unique-generator": "Recupera los títulos de todos los archivos y marca los faltantes.",
        "apihelp-query+allfileusages-example-generator": "Recupera las páginas que contienen los archivos.",
        "apihelp-query+allimages-param-filterbots": "Cómo filtrar archivos subidos por bots. Solo se puede usar con $1sort=timestamp. No se puede usar junto con $1user.",
        "apihelp-query+allimages-param-mime": "Tipos MIME que buscar, como, por ejemplo, <kbd>image/jpeg</kbd>.",
        "apihelp-query+allimages-param-limit": "Cuántas imágenes en total se devolverán.",
-       "apihelp-query+allimages-example-B": "Mostrar una lista de archivos que empiecen por la letra <kbd>B</kbd>.",
+       "apihelp-query+allimages-example-b": "Mostrar una lista de archivos que empiecen por la letra <kbd>B</kbd>.",
        "apihelp-query+allimages-example-recent": "Mostrar una lista de archivos subidos recientemente, similar a [[Special:NewFiles]].",
        "apihelp-query+allimages-example-mimetypes": "Mostrar una lista de archivos tipo MIME <kbd>image/png</kbd> o <kbd>image/gif</kbd>",
        "apihelp-query+allimages-example-generator": "Mostrar información acerca de 4 archivos que empiecen por la letra <kbd>T</kbd>.",
        "apihelp-query+alllinks-param-namespace": "El espacio de nombres que enumerar.",
        "apihelp-query+alllinks-param-limit": "Cuántos elementos en total se devolverán.",
        "apihelp-query+alllinks-param-dir": "La dirección en la que se listará.",
-       "apihelp-query+alllinks-example-B": "Enumera los títulos enlazados, incluyendo los títulos faltantes, con los ID de página de los que provienen, empezando por <kbd>B</kbd>.",
+       "apihelp-query+alllinks-example-b": "Enumera los títulos enlazados, incluyendo los títulos faltantes, con los ID de página de los que provienen, empezando por <kbd>B</kbd>.",
        "apihelp-query+alllinks-example-unique": "Lista de títulos vinculados únicamente.",
        "apihelp-query+alllinks-example-unique-generator": "Obtiene todos los títulos enlazados, marcando los que falten.",
        "apihelp-query+alllinks-example-generator": "Obtiene páginas que contienen los enlaces.",
        "apihelp-query+allpages-param-dir": "La dirección en la que se listará.",
        "apihelp-query+allpages-param-filterlanglinks": "Filtrar en función de si una página tiene langlinks. Tenga en cuenta que esto no puede considerar langlinks agregados por extensiones.",
        "apihelp-query+allpages-param-prexpiry": "¿Cuál término de protección para filtrar la página en:\n; Indefinida: Obtener sólo páginas con protección de vencimiento indefinida.\n; Definida: Obtener sólo las páginas con un definitivo (específico) vencimiento.\n; Todos: Obtener páginas con cualquier caducidad.",
-       "apihelp-query+allpages-example-B": "Mostrar una lista de páginas que empiecen con la letra <kbd>B</kbd>.",
+       "apihelp-query+allpages-example-b": "Mostrar una lista de páginas que empiecen con la letra <kbd>B</kbd>.",
        "apihelp-query+allpages-example-generator": "Mostrar información acerca de 4 páginas que empiecen por la letra <kbd>T</kbd>.",
        "apihelp-query+allpages-example-generator-revisions": "Mostrar el contenido de las 2 primeras páginas que no redirijan y empiecen por <kbd>Re</kbd>.",
        "apihelp-query+allredirects-summary": "Obtener la lista de todas las redirecciones a un espacio de nombres.",
        "apihelp-query+allredirects-param-namespace": "El espacio de nombres a enumerar.",
        "apihelp-query+allredirects-param-limit": "Cuántos elementos se devolverán.",
        "apihelp-query+allredirects-param-dir": "La dirección en la que se listará.",
-       "apihelp-query+allredirects-example-B": "Enumera las páginas de destino, incluyendo las páginas desaparecidas, con los identificadores de las páginas de las que provienen, empezando por <kbd>B</kbd>.",
+       "apihelp-query+allredirects-example-b": "Enumera las páginas de destino, incluyendo las páginas desaparecidas, con los identificadores de las páginas de las que provienen, empezando por <kbd>B</kbd>.",
        "apihelp-query+allredirects-example-unique": "La lista de páginas de destino.",
        "apihelp-query+allredirects-example-unique-generator": "Obtiene todas las páginas de destino, marcando los que faltan.",
        "apihelp-query+allredirects-example-generator": "Obtiene páginas que contienen las redirecciones.",
        "apihelp-query+alltransclusions-param-namespace": "El espacio de nombres que enumerar.",
        "apihelp-query+alltransclusions-param-limit": "Número de elementos que se desea obtener.",
        "apihelp-query+alltransclusions-param-dir": "La dirección en que ordenar la lista.",
-       "apihelp-query+alltransclusions-example-B": "Enumerar los títulos transcluidos, incluyendo los faltantes, junto con los identificadores de las páginas de las que provienen, empezando por <kbd>B</kbd>.",
+       "apihelp-query+alltransclusions-example-b": "Enumerar los títulos transcluidos, incluyendo los faltantes, junto con los identificadores de las páginas de las que provienen, empezando por <kbd>B</kbd>.",
        "apihelp-query+alltransclusions-example-unique": "Listar títulos transcluidos de forma única.",
        "apihelp-query+alltransclusions-example-unique-generator": "Obtiene todos los títulos transcluidos, marcando los que faltan.",
        "apihelp-query+alltransclusions-example-generator": "Obtiene las páginas que contienen las transclusiones.",
        "apihelp-query+allusers-param-witheditsonly": "Mostrar solo los usuarios que han realizado ediciones.",
        "apihelp-query+allusers-param-activeusers": "Solo listar usuarios activos en {{PLURAL:$1|el último día|los $1 últimos días}}.",
        "apihelp-query+allusers-param-attachedwiki": "Con <kbd>$1prop=centralids</kbd>, indicar también si el usuario está conectado con el wiki identificado por el ID.",
-       "apihelp-query+allusers-example-Y": "Listar usuarios que empiecen por <kbd>Y</kbd>.",
+       "apihelp-query+allusers-example-y": "Listar usuarios que empiecen por <kbd>Y</kbd>.",
        "apihelp-query+authmanagerinfo-summary": "Recuperar información sobre el estado de autenticación actual.",
        "apihelp-query+authmanagerinfo-param-securitysensitiveoperation": "Compruebe si el estado de autenticación actual del usuario es suficiente para la operación  sensible-seguridad especificada.",
        "apihelp-query+authmanagerinfo-param-requestsfor": "Obtener información sobre las peticiones de autentificación requeridas para la acción de autentificación especificada.",
        "apiwarn-validationfailed-cannotset": "no puede ser establecido por este módulo.",
        "apiwarn-validationfailed-keytoolong": "clave demasiado larga (no puede tener más de $1 bytes).",
        "apiwarn-validationfailed": "Error de validación de <kbd>$1</kbd>: $2",
-       "apiwarn-wgDebugAPI": "<strong>Aviso de seguridad</strong>: <var>$wgDebugAPI</var> está habilitado.",
+       "apiwarn-wgdebugapi": "<strong>Aviso de seguridad</strong>: <var>$wgDebugAPI</var> está habilitado.",
        "api-feed-error-title": "Error ($1)",
        "api-usage-docref": "Véase $1 para el uso de la API.",
        "api-exception-trace": "$1 en $2($3)\n$4",
index 64107fc..30c73ce 100644 (file)
@@ -4,6 +4,135 @@
                        "Pikne"
                ]
        },
+       "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|Dokumentatsioon]]\n* [[mw:Special:MyLanguage/API:FAQ|KKK]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Postiloend]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API teadaanded]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Vead ja taotlused]\n</div>\n<strong>Olek:</strong> MediaWiki API on kasutusküps ja stabiilne liides, millel on olemas tugi ja mida täiustatakse aktiivselt. Püüame seda küll vältida, aga mõnikord võib olla vajalik teha muudatusi, mille järel liides ei toimi enam varasemal kujul. Telli postiloend [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ mediawiki-api-announce], et saada teavitusi uuenduste kohta.\n\n<strong>Vigased päringud:</strong> Kui API-le saadetakse vigane päring, saadetakse HTTP päis võtmega \"MediaWiki-API-Error\" ning päisele ja tagastatavale veakoodile määratakse sama väärtus. Täpsemalt loe dokumentatsioonist: [[mw:Special:MyLanguage/API:Errors_and_warnings|API: veateated ja hoiatused]].\n\n<p class=\"mw-apisandbox-link\"><strong>Katsetamine:</strong> Et API päringuid lihtsamini katsetada, saad kasutada lehekülge [[Special:ApiSandbox]].</p>",
+       "apihelp-main-param-action": "Sooritatav toiming.",
+       "apihelp-main-param-format": "Väljundi vorming.",
+       "apihelp-compare-param-prop": "Millised teabe elemendid hankida.",
+       "apihelp-edit-param-bot": "Märgi see muudatus robotimuudatuseks.",
+       "apihelp-expandtemplates-param-prop": "Millised teabe elemendid hankida.\n\nPane tähele, et kui väärtusi pole valitud, siis sisaldab tulemus vikiteksti, aga väljund on ebasoovitatavas vormingus.",
+       "apihelp-feedcontributions-param-feedformat": "Voo väljund.",
+       "apihelp-feedcontributions-param-user": "Milliste kasutajate kaastöö hankida.",
+       "apihelp-feedcontributions-param-namespace": "Millise nimeruumi järgi kaastöö filtreerida.",
+       "apihelp-feedrecentchanges-param-feedformat": "Voo väljund.",
+       "apihelp-feedwatchlist-param-feedformat": "Voo väljund.",
+       "apihelp-help-param-helpformat": "Abiväljundi vorming.",
+       "apihelp-help-example-main": "Põhimooduli abi.",
+       "apihelp-opensearch-param-format": "Väljundi vorming.",
+       "apihelp-parse-param-prop": "Millised teabe elemendid hankida:",
+       "apihelp-query-param-prop": "Millised atribuudid päritavate lehekülgede kohta hankida.",
+       "apihelp-query-param-list": "Millised loendid hankida.",
+       "apihelp-query-param-meta": "Millised metaandmed hankida.",
+       "apihelp-query+allcategories-summary": "Loetle kõik kategooriad.",
+       "apihelp-query+allcategories-param-from": "Kategooria, millest alates loetleda.",
+       "apihelp-query+allcategories-param-to": "Kategooria, milleni loetleda.",
+       "apihelp-query+allcategories-param-dir": "Järjestuse suund.",
+       "apihelp-query+allcategories-param-limit": "Kui palju kategooriaid tagastada.",
+       "apihelp-query+allcategories-param-prop": "Millised atribuudid hankida:",
+       "apihelp-query+alldeletedrevisions-param-start": "Ajatempel, millest alates loetleda.",
+       "apihelp-query+alldeletedrevisions-param-end": "Ajatempel, milleni loetleda.",
+       "apihelp-query+alldeletedrevisions-param-tag": "Loetle ainult redaktsioonid, mille küljes on see märgis.",
+       "apihelp-query+alldeletedrevisions-param-excludeuser": "Ära loetle selle kasutaja redaktsioone.",
+       "apihelp-query+alldeletedrevisions-param-namespace": "Loetle ainult leheküljed selles nimeruumis.",
+       "apihelp-query+allfileusages-param-from": "Faili pealkiri, millest alates loetleda.",
+       "apihelp-query+allfileusages-param-to": "Faili pealkiri, milleni loetleda.",
+       "apihelp-query+allfileusages-param-prop": "Millised teabe elemendid hankida:",
+       "apihelp-query+allfileusages-param-limit": "Kui palju üksusi kokku tagastada.",
+       "apihelp-query+allfileusages-param-dir": "Järjestuse suund.",
+       "apihelp-query+allimages-summary": "Loetle kõik pildid järjestatult.",
+       "apihelp-query+allimages-param-dir": "Järjestuse suund.",
+       "apihelp-query+allimages-param-from": "Pildi pealkiri, millest alates loetleda. Saab kasutada ainult parameetriga $1sort=name.",
+       "apihelp-query+allimages-param-to": "Pildi pealkiri, milleni loetleda. Saab kasutada ainult parameetriga $1sort=name.",
+       "apihelp-query+allimages-param-start": "Ajatempel, millest alates loetleda. Saab kasutada ainult parameetriga $1sort=timestamp.",
+       "apihelp-query+allimages-param-end": "Ajatempel, milleni loetleda. Saab kasutada ainult parameetriga $1sort=timestamp.",
+       "apihelp-query+allimages-param-limit": "Kui palju pilte kokku tagastada.",
+       "apihelp-query+alllinks-summary": "Loetle kõik lingid, mis viitavad teatud nimeruumi.",
+       "apihelp-query+alllinks-param-from": "Lingi pealkiri, millest alates loetleda.",
+       "apihelp-query+alllinks-param-to": "Lingi pealkiri, milleni loetleda.",
+       "apihelp-query+alllinks-param-prop": "Millised teabe elemendid hankida:",
+       "apihelp-query+alllinks-param-namespace": "Loetlemise nimeruum.",
+       "apihelp-query+alllinks-param-limit": "Kui palju üksusi kokku tagastada.",
+       "apihelp-query+alllinks-param-dir": "Järjestuse suund.",
+       "apihelp-query+allmessages-param-prop": "Millised atribuudid hankida.",
+       "apihelp-query+allpages-summary": "Loetle kõik leheküljed järjestatult teatud nimeruumis.",
+       "apihelp-query+allpages-param-from": "Lehekülje pealkiri, millest alates loetleda.",
+       "apihelp-query+allpages-param-to": "Lehekülje pealkiri, milleni loetleda.",
+       "apihelp-query+allpages-param-namespace": "Loetlemise nimeruum.",
+       "apihelp-query+allpages-param-filterredir": "Millised leheküljed loetleda.",
+       "apihelp-query+allpages-param-limit": "Kui palju lehekülgi kokku tagastada.",
+       "apihelp-query+allpages-param-dir": "Järjestuse suund.",
+       "apihelp-query+allredirects-param-from": "Ümbersuunamise pealkiri, millest alates loetleda.",
+       "apihelp-query+allredirects-param-to": "Ümbersuunamise pealkiri, milleni loetleda.",
+       "apihelp-query+allredirects-param-prop": "Millised teabe elemendid hankida:",
+       "apihelp-query+allredirects-param-namespace": "Loetlemise nimeruum.",
+       "apihelp-query+allredirects-param-limit": "Kui palju üksusi kokku tagastada.",
+       "apihelp-query+allredirects-param-dir": "Järjestuse suund.",
+       "apihelp-query+allrevisions-param-start": "Ajatempel, millest alates loetleda.",
+       "apihelp-query+allrevisions-param-end": "Ajatempel, milleni loetleda.",
+       "apihelp-query+allrevisions-param-user": "Loetle ainult selle kasutaja redaktsioonid.",
+       "apihelp-query+allrevisions-param-excludeuser": "Ära loetle selle kasutaja redaktsioone.",
+       "apihelp-query+allrevisions-param-namespace": "Loetle ainult leheküljed selles nimeruumis.",
+       "apihelp-query+mystashedfiles-param-prop": "Millised atribuudid failide kohta hankida.",
+       "apihelp-query+mystashedfiles-param-limit": "Kui palju faile hankida.",
+       "apihelp-query+alltransclusions-param-from": "Mallina kasutatava lehekülje pealkiri, millest alates loetleda.",
+       "apihelp-query+alltransclusions-param-to": "Mallina kasutatava lehekülje pealkiri, milleni loetleda.",
+       "apihelp-query+alltransclusions-param-prop": "Millised teabe elemendid hankida:",
+       "apihelp-query+alltransclusions-param-namespace": "Loetlemise nimeruum.",
+       "apihelp-query+alltransclusions-param-limit": "Kui palju üksusi kokku tagastada.",
+       "apihelp-query+alltransclusions-param-dir": "Järjestuse suund.",
+       "apihelp-query+allusers-summary": "Loetle kõik registreeritud kasutajad.",
+       "apihelp-query+allusers-param-from": "Kasutajanimi, millest alates loetleda.",
+       "apihelp-query+allusers-param-to": "Kasutajanimi, milleni loetleda.",
+       "apihelp-query+allusers-param-dir": "Järjestuse suund.",
+       "apihelp-query+allusers-param-excludegroup": "Välja arvatud kasutajad, kes on neis rühmades.",
+       "apihelp-query+allusers-param-prop": "Millised teabe elemendid hankida:",
+       "apihelp-query+allusers-param-limit": "Kui palju kasutajanimesid kokku tagastada.",
+       "apihelp-query+allusers-param-witheditsonly": "Loetle ainult kasutajad, kes on teinud muudatusi.",
+       "apihelp-query+backlinks-param-namespace": "Loetlemise nimeruum.",
+       "apihelp-query+backlinks-param-dir": "Järjestuse suund.",
+       "apihelp-query+backlinks-param-limit": "Kui palju lehekülgi kokku tagastada. Kui <var>$1redirect</var> on lubatud, siis rakendub piirang mõlemal tasemel eraldi (see tähendab, et tagastada võidakse kuni 2 × <var>$1limit</var> tulemust).",
+       "apihelp-query+blocks-param-start": "Ajatempel, millest alates loetleda.",
+       "apihelp-query+blocks-param-end": "Ajatempel, milleni loetleda.",
+       "apihelp-query+blocks-param-prop": "Millised atribuudid hankida:",
+       "apihelp-query+blocks-param-show": "Näita ainult üksusi, mis vastavad neile kriteeriumitele.\nNäiteks, et näidata ainult IP-aadresside suhtes rakendatud tähtajatuid blokeeringuid, määra <kbd>$1show=ip|!temp</kbd>.",
+       "apihelp-query+categories-param-prop": "Millised lisaatribuudid iga kategooria kohta hankida:",
+       "apihelp-query+categories-param-show": "Milliseid kategooriaid näidata.",
+       "apihelp-query+categories-param-limit": "Kui palju kategooriaid tagastada.",
+       "apihelp-query+categories-param-categories": "Loetle ainult need kategooriad. Kasulik, kui vaja kontrollida, kas teatud lehekülg on teatud kategoorias.",
+       "apihelp-query+categories-param-dir": "Järjestuse suund.",
+       "apihelp-query+categorymembers-param-title": "Loetlemise kategooria (nõutav). Peab sisaldama eesliidet <kbd>{{ns:category}}:</kbd>. Ei saa kasutada parameetriga <var>$1pageid</var>.",
+       "apihelp-query+categorymembers-param-pageid": "Loetlemise kategooria lehekülje identifikaator. Ei saa kasutada parameetriga <var>$1title</var>.",
+       "apihelp-query+categorymembers-param-prop": "Millised teabe elemendid hankida:",
+       "apihelp-query+categorymembers-param-type": "Mis tüüpi liikmed kategooriatest hankida. Eiratakse, kui määratud on <kbd>$1sort=timestamp</kbd>.",
+       "apihelp-query+categorymembers-param-dir": "Järjestuse suund.",
+       "apihelp-query+contributors-param-limit": "Kui palju kaastöölisi tagastada.",
+       "apihelp-query+deletedrevisions-param-start": "Ajatempel, millest alates loetleda. Eiratakse, kui töötlusel on redaktsioonide identifikaatorite loend.",
+       "apihelp-query+deletedrevisions-param-end": "Ajatempel, milleni loetleda. Eiratakse, kui töötlusel on redaktsioonide identifikaatorite loend.",
+       "apihelp-query+deletedrevisions-param-tag": "Loetle ainult redaktsioonid, mille küljes on see märgis.",
+       "apihelp-query+deletedrevisions-param-excludeuser": "Ära loetle selle kasutaja redaktsioone.",
+       "apihelp-query+deletedrevs-param-start": "Ajatempel, millest alates loetleda.",
+       "apihelp-query+deletedrevs-param-end": "Ajatempel, milleni loetleda.",
+       "apihelp-query+deletedrevs-param-tag": "Loetle ainult redaktsioonid, mille küljes on see märgis.",
+       "apihelp-query+deletedrevs-param-excludeuser": "Ära loetle selle kasutaja redaktsioone.",
+       "apihelp-query+deletedrevs-param-namespace": "Loetle ainult leheküljed selles nimeruumis.",
+       "apihelp-query+duplicatefiles-param-limit": "Kui palju duplikaatfaile tagastada.",
+       "apihelp-query+duplicatefiles-param-dir": "Järjestuse suund.",
+       "apihelp-query+embeddedin-param-namespace": "Loetlemise nimeruum.",
+       "apihelp-query+embeddedin-param-dir": "Järjestuse suund.",
+       "apihelp-query+embeddedin-param-limit": "Kui palju lehekülgi kokku tagastada.",
+       "apihelp-query+extlinks-param-limit": "Kui palju linke tagastada.",
+       "apihelp-query+exturlusage-summary": "Loetle leheküljed, mis sisaldavad teatud internetiaadressi.",
+       "apihelp-query+exturlusage-param-prop": "Millised teabe elemendid hankida:",
+       "apihelp-query+exturlusage-param-namespace": "Lehekülgede loetlemise nimeruumid.",
+       "apihelp-query+exturlusage-param-limit": "Kui palju lehekülgi tagastada.",
+       "apihelp-query+filearchive-summary": "Loetle kõik kustutatud failid järjestatult.",
+       "apihelp-query+filearchive-param-from": "Pildi pealkiri, millest alates loetleda.",
+       "apihelp-query+filearchive-param-to": "Pildi pealkiri, milleni loetleda.",
+       "apihelp-query+filearchive-param-limit": "Kui palju pilte kokku tagastada.",
+       "apihelp-query+filearchive-param-dir": "Järjestuse suund.",
+       "apihelp-query+filearchive-param-prop": "Milline pilditeave hankida:",
+       "apihelp-query+fileusage-param-prop": "Millised atribuudid hankida:",
+       "apihelp-query+fileusage-param-limit": "Kui palju tagastada.",
+       "apihelp-query+fileusage-param-show": "Näita ainult üksusi, mis vastavad neile kriteeriumitele:\n;redirect:Näita ainult ümbersuunamisi.\n;!redirect:Näita ainult üksusi, mis pole ümbersuunamised.",
        "apihelp-query+imageinfo-summary": "Tagastab failiteabe ja üleslaadimisajaloo.",
        "apihelp-query+imageinfo-param-prop": "Millist teavet faili kohta hankida:",
        "apihelp-query+imageinfo-paramvalue-prop-timestamp": "Lisab üles laaditud versiooni ajatempli.",
        "apihelp-query+imageinfo-param-localonly": "Kaasa päringusse ainult kohaliku hoidla failid.",
        "apihelp-query+imageinfo-example-simple": "Faili [[:File:Albert Einstein Head.jpg|Albert Einstein Head.jpg]] praeguse versiooni teabe väljavõtt.",
        "apihelp-query+imageinfo-example-dated": "Faili [[:File:Test.jpg|Test.jpg]] teabe väljavõtt alates 2008. aasta versioonidest.",
-       "api-help-param-continue": "Kui saadaval on rohkem tulemusi, kasuta seda jätkamiseks."
+       "apihelp-query+images-param-limit": "Kui palju faile tagastada.",
+       "apihelp-query+images-param-images": "Loetle ainult need failid. Kasulik, kui vaja kontrollida, kas teatud leheküljel on teatud fail.",
+       "apihelp-query+images-param-dir": "Järjestuse suund.",
+       "apihelp-query+imageusage-param-namespace": "Loetlemise nimeruum.",
+       "apihelp-query+imageusage-param-dir": "Järjestuse suund.",
+       "apihelp-query+imageusage-param-limit": "Kui palju lehekülgi kokku tagastada. Kui <var>$1redirect</var> on lubatud, siis rakendub piirang mõlemal tasemel eraldi (see tähendab, et tagastada võidakse kuni 2 × <var>$1limit</var> tulemust).",
+       "apihelp-query+info-param-prop": "Millised lisaatribuudid hankida:",
+       "apihelp-query+iwbacklinks-param-limit": "Kui palju lehekülgi kokku tagastada.",
+       "apihelp-query+iwbacklinks-param-prop": "Millised atribuudid hankida:",
+       "apihelp-query+iwbacklinks-param-dir": "Järjestuse suund.",
+       "apihelp-query+iwlinks-param-prop": "Millised lisaatribuudid iga intervikilingi kohta hankida:",
+       "apihelp-query+iwlinks-param-limit": "Kui palju intervikilinke tagastada.",
+       "apihelp-query+iwlinks-param-dir": "Järjestuse suund.",
+       "apihelp-query+langbacklinks-param-limit": "Kui palju lehekülgi kokku tagastada.",
+       "apihelp-query+langbacklinks-param-prop": "Millised atribuudid hankida:",
+       "apihelp-query+langbacklinks-param-dir": "Järjestuse suund.",
+       "apihelp-query+langlinks-param-limit": "Kui palju keelelinke tagastada.",
+       "apihelp-query+langlinks-param-prop": "Millised lisaatribuudid iga intervikilingi kohta hankida:",
+       "apihelp-query+langlinks-param-dir": "Järjestuse suund.",
+       "apihelp-query+links-param-limit": "Kui palju linke tagastada.",
+       "apihelp-query+links-param-titles": "Loetle ainult lingid, mis viitavad neile pealkirjadele. Kasulik, kui vaja kontrollida, kas teatud lehekülg lingib teatud leheküljele.",
+       "apihelp-query+links-param-dir": "Järjestuse suund.",
+       "apihelp-query+linkshere-param-prop": "Millised atribuudid hankida:",
+       "apihelp-query+linkshere-param-limit": "Kui palju tagastada.",
+       "apihelp-query+linkshere-param-show": "Näita ainult üksusi, mis vastavad neile kriteeriumitele:\n;redirect:Näita ainult ümbersuunamisi.\n;!redirect:Näita ainult üksusi, mis pole ümbersuunamised.",
+       "apihelp-query+logevents-param-prop": "Millised atribuudid hankida:",
+       "apihelp-query+logevents-param-type": "Loetle ainult seda tüüpi logisündmused.",
+       "apihelp-query+logevents-param-action": "Loetle ainult logisündmused selle toimingu kohta. Kirjutab üle parameetri <var>$1type</var>. Väärtused, milles on võimalike väärtuste loetelus metamärk asterisk (<kbd>toiming/*</kbd>), võib kaldkriipsu (/) järel olla erinev sõne.",
+       "apihelp-query+logevents-param-start": "Ajatempel, millest alates loetleda.",
+       "apihelp-query+logevents-param-end": "Ajatempel, milleni loetleda.",
+       "apihelp-query+logevents-param-user": "Loetle ainult selle kasutaja sissekanded.",
+       "apihelp-query+logevents-param-namespace": "Loetle ainult sissekanded, mis on selles nimeruumis.",
+       "apihelp-query+logevents-param-tag": "Loetle ainult logisündmused, mille küljes on see märgis.",
+       "apihelp-query+logevents-param-limit": "Kui palju logisündmusi kokku tagastada.",
+       "apihelp-query+pagepropnames-example-simple": "Hangi esimese 10 atribuudi nimi.",
+       "apihelp-query+pageprops-param-prop": "Loetle ainult need leheatribuudid (<kbd>[[Special:ApiHelp/query+pagepropnames|action=query&list=pagepropnames]]</kbd> tagastab kasutatavate atribuutide nimed). Kasulik, kui vaja kontrollida, kas leheküljed kasutavad teatud leheatribuuti.",
+       "apihelp-query+pageswithprop-summary": "Loetle kõik leheküljed, mis kasutavad teatud leheatribuuti.",
+       "apihelp-query+pageswithprop-param-propname": "Leheatribuut, mille kohta lehekülgi loetleda (<kbd>[[Special:ApiHelp/query+pagepropnames|action=query&list=pagepropnames]]</kbd> tagastab kasutatavate atribuutide nimed).",
+       "apihelp-query+pageswithprop-param-prop": "Millised teabe elemendid hankida:",
+       "apihelp-query+pageswithprop-paramvalue-prop-value": "Lisab leheatribuudi väärtuse.",
+       "apihelp-query+pageswithprop-param-dir": "Järjestuse suund.",
+       "apihelp-query+protectedtitles-param-namespace": "Loetle ainult pealkirjad nendes nimeruumides.",
+       "apihelp-query+protectedtitles-param-limit": "Kui palju lehekülgi kokku tagastada.",
+       "apihelp-query+protectedtitles-param-prop": "Millised atribuudid hankida:",
+       "apihelp-query+random-param-limit": "Kui palju juhuslikke lehekülgi tagastada.",
+       "apihelp-query+recentchanges-summary": "Loetle viimased muudatused.",
+       "apihelp-query+recentchanges-param-start": "Ajatempel, millest alates loetleda.",
+       "apihelp-query+recentchanges-param-end": "Ajatempel, milleni loetleda.",
+       "apihelp-query+recentchanges-param-namespace": "Loetle muudatusi ainult neist nimeruumidest.",
+       "apihelp-query+recentchanges-param-user": "Loetle ainult selle kasutaja muudatused.",
+       "apihelp-query+recentchanges-param-excludeuser": "Ära loetle selle kasutaja muudatusi.",
+       "apihelp-query+recentchanges-param-tag": "Loetle ainult muudatused, mille küljes on see märgis.",
+       "apihelp-query+recentchanges-param-prop": "Hangi teabe lisaelemendid:",
+       "apihelp-query+recentchanges-param-show": "Näita ainult üksusi, mis vastavad neile kriteeriumitele. Näiteks, et näha ainult pisimuudatusi, mille on teinud sisseloginud kasutajad, määra $1show=minor|!anon.",
+       "apihelp-query+recentchanges-param-limit": "Kui palju muudatusi kokku tagastada.",
+       "apihelp-query+recentchanges-param-type": "Mis tüüpi muudatusi näidata.",
+       "apihelp-query+recentchanges-param-toponly": "Loetle ainult muudatused, millele vastab viimane redaktsioon.",
+       "apihelp-query+recentchanges-param-title": "Loetle ainult sissekanded, mis on seotud leheküljega.",
+       "apihelp-query+redirects-param-prop": "Millised atribuudid hankida:",
+       "apihelp-query+redirects-param-limit": "Kui palju ümbersuunamisi tagastada.",
+       "apihelp-query+redirects-param-show": "Näita ainult üksusi, mis vastavad neile kriteeriumitele:\n;redirect:Näita ainult fragmendiga ümbersuunamisi.\n;!redirect:Näita ainult ümbersuunamisi, millel pole fragmenti.",
+       "apihelp-query+revisions-param-startid": "Redaktsioon, mille ajatemplist alates loetleda. Redaktsioon peab olemas olema, aga ei pea kuuluma selle lehekülje juurde.",
+       "apihelp-query+revisions-param-endid": "Redaktsioon, mille ajatemplini loetleda. Redaktsioon peab olemas olema, aga ei pea kuuluma selle lehekülje juurde.",
+       "apihelp-query+revisions-param-start": "Redaktsiooni ajatempel, millest alates loetleda.",
+       "apihelp-query+revisions-param-end": "Ajatempel, milleni loetleda.",
+       "apihelp-query+revisions-param-tag": "Loetle ainult redaktsioonid, mille küljes on see märgis.",
+       "apihelp-query+revisions+base-param-prop": "Millised atribuudid iga redaktsiooni kohta hankida:",
+       "apihelp-query+revisions+base-param-limit": "Kui palju redaktsioone tagastada.",
+       "apihelp-query+search-summary": "Soorita täisteksti otsing.",
+       "apihelp-query+search-param-search": "Otsi lehekülgede pealkirju või sisu, mis vastab sellele väärtusele. Saad otsisõnes kasutada neid erifunktsioone, mida otsing selles vikis võimaldab.",
+       "apihelp-query+search-param-namespace": "Otsi ainult neist nimeruumidest.",
+       "apihelp-query+search-param-what": "Mis tüüpi otsing sooritada.",
+       "apihelp-query+search-param-info": "Millised metaandmed tagastada.",
+       "apihelp-query+search-param-prop": "Millised atribuudid hankida:",
+       "apihelp-query+search-param-limit": "Kui palju lehekülgi kokku tagastada.",
+       "apihelp-query+siteinfo-param-prop": "Milline teave hankida:",
+       "apihelp-query+tags-param-prop": "Millised atribuudid hankida:",
+       "apihelp-query+templates-param-limit": "Kui palju malle tagastada.",
+       "apihelp-query+templates-param-templates": "Loetle ainult need mallid. Kasulik, kui vaja kontrollida, kas teatud lehekülg kasutab teatud malli.",
+       "apihelp-query+templates-param-dir": "Järjestuse suund.",
+       "apihelp-query+transcludedin-param-prop": "Millised atribuudid hankida:",
+       "apihelp-query+transcludedin-param-limit": "Kui palju tagastada.",
+       "apihelp-query+transcludedin-param-show": "Näita ainult üksusi, mis vastavad neile kriteeriumitele:\n;redirect:Näita ainult ümbersuunamisi.\n;!redirect:Näita ainult üksusi, mis pole ümbersuunamised.",
+       "apihelp-query+usercontribs-param-namespace": "Loetle ainult kaastöö nendes nimeruumides.",
+       "apihelp-query+usercontribs-param-prop": "Hangi teabe lisaelemendid:",
+       "apihelp-query+usercontribs-param-show": "Näita ainult üksusi, mis vastavad neile kriteeriumitele. Näiteks ainult muudatused, mis pole pisimuudatused: <kbd>$2show=!minor</kbd>.\n\nKui määratud on <kbd>$2show=patrolled</kbd> või <kbd>$2show=!patrolled</kbd>, siis ei näidata muudatusi, mis on vanemad kui <var>[[mw:Special:MyLanguage/Manual:$wgRCMaxAge|$wgRCMaxAge]]</var> ($1 {{PLURAL:$1|sekund|sekundit}}).",
+       "apihelp-query+usercontribs-param-tag": "Loetle ainult redaktsioonid, mille küljes on see märgis.",
+       "apihelp-query+usercontribs-param-toponly": "Loetle ainult muudatused, millele vastab viimane redaktsioon.",
+       "apihelp-query+userinfo-param-prop": "Millised teabe elemendid hankida:",
+       "apihelp-query+users-param-prop": "Millised teabe elemendid hankida:",
+       "apihelp-query+watchlist-param-start": "Ajatempel, millest alates loetleda.",
+       "apihelp-query+watchlist-param-end": "Ajatempel, milleni loetleda.",
+       "apihelp-query+watchlist-param-namespace": "Loetle ainult muudatused neis nimeruumides.",
+       "apihelp-query+watchlist-param-user": "Loetle ainult selle kasutaja muudatused.",
+       "apihelp-query+watchlist-param-excludeuser": "Ära loetle selle kasutaja muudatusi.",
+       "apihelp-query+watchlist-param-limit": "Kui palju tulemusi päringu kohta kokku tagastada.",
+       "apihelp-query+watchlist-param-prop": "Millised lisaatribuudid hankida:",
+       "apihelp-query+watchlist-param-show": "Näita ainult üksusi, mis vastavad neile kriteeriumitele. Näiteks, et näha ainult pisimuudatusi, mille on teinud sisseloginud kasutajad, määra $1show=minor|!anon.",
+       "apihelp-query+watchlist-param-type": "Mis tüüpi muudatusi näidata:",
+       "apihelp-query+watchlistraw-param-namespace": "Loetle ainult leheküljed nendes nimeruumides.",
+       "apihelp-query+watchlistraw-param-limit": "Kui palju tulemusi päringu kohta kokku tagastada.",
+       "apihelp-query+watchlistraw-param-prop": "Millised lisaatribuudid hankida:",
+       "apihelp-query+watchlistraw-param-show": "Loetle ainult üksused, mis vastavad neile kriteeriumitele.",
+       "apihelp-query+watchlistraw-param-dir": "Järjestuse suund.",
+       "apihelp-query+watchlistraw-param-fromtitle": "Pealkiri (nimeruumi eesliitega), millest alates loetleda.",
+       "apihelp-query+watchlistraw-param-totitle": "Pealkiri (nimeruumi eesliitega), milleni loetleda.",
+       "api-help-main-header": "Põhimoodul.",
+       "api-help-param-limit": "Lubatud pole üle $1.",
+       "api-help-param-limit2": "Lubatud pole üle $1 (robotitele $2).",
+       "api-help-param-direction": "Loetlemise suund:\n;newer:Vanemad enne. Märkus: element $1start peab olema enne elementi $1end.\n;older:Uuemad enne (vaikimisi). Märkus: element $1start peab olema pärast elementi $1end.",
+       "api-help-param-continue": "Kui saadaval on rohkem tulemusi, kasuta seda jätkamiseks.",
+       "apierror-mustbeloggedin": "Pead olema sisse logitud, et $1.",
+       "apierror-timeout": "Server ei vastanud oodatud aja sees."
 }
index 319b2d6..993e75c 100644 (file)
        "apihelp-login-param-password": "گذرواژه.",
        "apihelp-login-param-domain": "دامنه (اختیاری)",
        "apihelp-login-param-token": "بلیط ورود به سامانه که در اولین درخواست دریافت شد.",
-       "apihelp-login-example-gettoken": "دریافت توکن ورود",
        "apihelp-login-example-login": "ورود",
        "apihelp-logout-summary": "خروج به همراه پاک نمودن اطلاعات این نشست",
        "apihelp-logout-example-logout": "خروج کاربر فعلی",
index 73eb145..51e17ff 100644 (file)
                        "Thibaut120094",
                        "KATRINE1992",
                        "Kenjiraw",
-                       "Framawiki"
+                       "Framawiki",
+                       "Epok"
                ]
        },
-       "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|Documentation]]\n* [[mw:Special:MyLanguage/API:FAQ|FAQ]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Liste de diffusion]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Annonces de l’API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Bogues et demandes]\n</div>\n<strong>État :</strong> L’API MédiaWiki est une interface stable et mature qui est supportée et améliorée de façon active. Bien que nous essayions de l’éviter, nous pouvons avoir parfois besoin de faire des modifications impactantes ; inscrivez-vous à [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ la liste de diffusion mediawiki-api-announce] pour être informé des mises à jour.\n\n<strong>Requêtes erronées :</strong> Si des requêtes erronées sont envoyées à l’API, un entête HTTP sera renvoyé avec la clé « MediaWiki-API-Error ». La valeur de cet entête et le code d’erreur renvoyé prendront la même valeur. Pour plus d’information, voyez [[mw:Special:MyLanguage/API:Errors_and_warnings|API: Errors and warnings]].\n\n<p class=\"mw-apisandbox-link\"><strong>Test :</strong> Pour faciliter le test des requêtes de l’API, voyez [[Special:ApiSandbox]].</p>",
+       "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|Documentation]]\n* [[mw:Special:MyLanguage/API:FAQ|FAQ]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Liste de diffusion]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Annonces de l’API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Bogues et demandes]\n</div>\n<strong>État :</strong> L’API MediaWiki est une interface stable et mature qui est supportée et améliorée de façon active. Bien que nous essayions de l’éviter, nous pouvons avoir parfois besoin de faire des modifications impactantes ; inscrivez-vous à [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ la liste de diffusion mediawiki-api-announce] pour être informé des mises à jour.\n\n<strong>Requêtes erronées :</strong> Si des requêtes erronées sont envoyées à l’API, un entête HTTP sera renvoyé avec la clé « MediaWiki-API-Error ». La valeur de cet entête et le code d’erreur renvoyé prendront la même valeur. Pour plus d’information, voyez [[mw:Special:MyLanguage/API:Errors_and_warnings|API: Errors and warnings]].\n\n<p class=\"mw-apisandbox-link\"><strong>Test :</strong> Pour faciliter le test des requêtes à l’API, voyez [[Special:ApiSandbox]].</p>",
        "apihelp-main-param-action": "Quelle action effectuer.",
        "apihelp-main-param-format": "Le format de sortie.",
        "apihelp-main-param-maxlag": "La latence maximale peut être utilisée quand MédiaWiki est installé sur un cluster de base de données répliqué. Pour éviter des actions provoquant un supplément de latence de réplication de site, ce paramètre peut faire attendre le client jusqu’à ce que la latence de réplication soit inférieure à une valeur spécifiée. En cas de latence excessive, le code d’erreur <samp>maxlag</samp> est renvoyé avec un message tel que <samp>Attente de $host : $lag secondes de délai</samp>.<br />Voyez [[mw:Special:MyLanguage/Manual:Maxlag_parameter|Manuel: paramètre Maxlag]] pour plus d’information.",
@@ -79,7 +80,7 @@
        "apihelp-checktoken-example-simple": "Tester la validité d'un jeton de <kbd>csrf</kbd>.",
        "apihelp-clearhasmsg-summary": "Efface le drapeau <code>hasmsg</code> pour l’utilisateur courant.",
        "apihelp-clearhasmsg-example-1": "Effacer le drapeau <code>hasmsg</code> pour l’utilisateur courant",
-       "apihelp-clientlogin-summary": "Se connecter au wiki en utilisant le flux interactif.",
+       "apihelp-clientlogin-summary": "Se connecter au wiki en utilisant la procédure interactive.",
        "apihelp-clientlogin-example-login": "Commencer le processus de connexion au wiki en tant qu’utilisateur <kbd>Exemple</kbd> avec le mot de passe <kbd>ExempleMotDePasse</kbd>.",
        "apihelp-clientlogin-example-login2": "Continuer la connexion après une réponse de l’<samp>IHM</samp> pour l’authentification à deux facteurs, en fournissant un <var>OATHToken</var> valant <kbd>987654</kbd>.",
        "apihelp-compare-summary": "Obtenir la différence entre deux pages.",
        "apihelp-edit-param-text": "Contenu de la page.",
        "apihelp-edit-param-summary": "Modifier le résumé. Également le titre de la section quand $1section=new et $1sectiontitle n’est pas défini.",
        "apihelp-edit-param-tags": "Modifier les balises à appliquer à la version.",
-       "apihelp-edit-param-minor": "Modification mineure.",
-       "apihelp-edit-param-notminor": "Modification non mineure.",
+       "apihelp-edit-param-minor": "Marquer cette modification comme étant mineure.",
+       "apihelp-edit-param-notminor": "Ne pas marquer cette modification comme mineure, même si la préférence utilisateur « {{int:tog-minordefault}} » est positionnée.",
        "apihelp-edit-param-bot": "Marquer cette modification comme effectuée par un robot.",
        "apihelp-edit-param-basetimestamp": "Horodatage de la révision de base, utilisé pour détecter les conflits de modification. Peut être obtenu via [[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]].",
        "apihelp-edit-param-starttimestamp": "L'horodatage, lorsque le processus d'édition est démarré, est utilisé pour détecter les conflits de modification. Une valeur appropriée peut être obtenue en utilisant <var>[[Special:ApiHelp/main|curtimestamp]]</var> lors du démarrage du processus d'édition (par ex. en chargeant le contenu de la page à modifier).",
        "apihelp-emailuser-param-text": "Corps du courriel.",
        "apihelp-emailuser-param-ccme": "M’envoyer une copie de ce courriel.",
        "apihelp-emailuser-example-email": "Envoyer un courriel à l’utilisateur <kbd>WikiSysop</kbd> avec le texte <kbd>Content</kbd>.",
-       "apihelp-expandtemplates-summary": "Développe tous les modèles avec du wikitexte.",
+       "apihelp-expandtemplates-summary": "Réalise l’expansion des modèles en wikitexte.",
        "apihelp-expandtemplates-param-title": "Titre de la page.",
        "apihelp-expandtemplates-param-text": "Wikitexte à convertir.",
        "apihelp-expandtemplates-param-revid": "ID de révision, pour <code><nowiki>{{REVISIONID}}</nowiki></code> et les variables semblables.",
        "apihelp-import-example-import": "Importer [[meta:Help:ParserFunctions]] vers l’espace de noms 100 avec tout l’historique.",
        "apihelp-linkaccount-summary": "Lier un compte d’un fournisseur tiers à l’utilisateur actuel.",
        "apihelp-linkaccount-example-link": "Commencer le processus de liaison d’un compte depuis <kbd>Exemple</kbd>.",
-       "apihelp-login-summary": "Reconnecte et récupère les témoins (cookies) d'authentification.",
+       "apihelp-login-summary": "Se connecter et récupérer les témoins (cookies) d'authentification.",
        "apihelp-login-extended-description": "Cette action ne devrait être utilisée qu’en lien avec [[Special:BotPasswords]] ; l’utiliser pour la connexion du compte principal est désuet et peut échouer sans avertissement. Pour se connecter sans problème au compte principal, utiliser <kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>.",
        "apihelp-login-extended-description-nobotpasswords": "Cette action est désuète et peut échouer sans prévenir. Pour se connecter sans problème, utiliser <kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>.",
        "apihelp-login-param-name": "Nom d’utilisateur.",
        "apihelp-login-param-password": "Mot de passe.",
        "apihelp-login-param-domain": "Domaine (facultatif).",
        "apihelp-login-param-token": "Jeton de connexion obtenu à la première requête.",
-       "apihelp-login-example-gettoken": "Récupérer un jeton de connexion",
        "apihelp-login-example-login": "Se connecter",
        "apihelp-logout-summary": "Se déconnecter et effacer les données de session.",
        "apihelp-logout-example-logout": "Déconnecter l’utilisateur actuel.",
-       "apihelp-managetags-summary": "Effectuer des tâches de gestion relatives à la modification des balises.",
+       "apihelp-managetags-summary": "Effectuer des tâches de gestion relatives aux balises de modification.",
        "apihelp-managetags-param-operation": "Quelle opération effectuer :\n;create:Créer une nouvelle balise de modification pour un usage manuel.\n;delete:Supprimer une balise de modification de la base de données, y compris la suppression de la marque de toutes les révisions, entrées de modification récente et entrées de journal dans lesquelles elle serait utilisée.\n;activate:Activer une balise de modification, permettant aux utilisateurs de l’appliquer manuellement.\n;deactivate:Désactiver une balise de modification, empêchant les utilisateurs de l’appliquer manuellement.",
        "apihelp-managetags-param-tag": "Balise à créer, supprimer, activer ou désactiver. Pour la création de balise, elle ne doit pas exister. Pour la suppression de balise, elle doit exister. Pour l’activation de balise, elle doit exister et ne pas être utilisée par une extension. Pour la désactivation de balise, elle doit être actuellement active et définie manuellement.",
        "apihelp-managetags-param-reason": "Un motif facultatif pour créer, supprimer, activer ou désactiver la balise.",
        "apihelp-parse-paramvalue-prop-revid": "Ajoute l’ID de révision de la page analysée.",
        "apihelp-parse-paramvalue-prop-displaytitle": "Ajoute le titre du wikitexte analysé.",
        "apihelp-parse-paramvalue-prop-headitems": "Fournit les éléments à mettre dans le <code>&lt;head&gt;</code> de la page.",
-       "apihelp-parse-paramvalue-prop-headhtml": "Fournit le <code>&lt;head&gt;</code> analysé de la page.",
+       "apihelp-parse-paramvalue-prop-headhtml": "Fournit le type de document, à partir de l'analyse des éléments <code>&lt;html&gt;</code>, <code>&lt;head&gt;</code> et <code>&lt;body&gt;</code> de la page.",
        "apihelp-parse-paramvalue-prop-modules": "Fournit les modules ResourceLoader utilisés sur la page. Pour les charger, utiliser <code>mw.loader.using()</code>. Soit <kbd>jsconfigvars</kbd> soit <kbd>encodedjsconfigvars</kbd> doit être demandé avec <kbd>modules</kbd>.",
        "apihelp-parse-paramvalue-prop-jsconfigvars": "Fournit les variables de configuration JavaScript spécifiques à la page. Pour les appliquer, utiliser <code>mw.config.set()</code>.",
        "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "Fournit les variables de configuration JavaScript spécifiques à la page comme chaîne JSON.",
        "apihelp-purge-param-forcerecursivelinkupdate": "Mettre à jour la table des liens, et mettre à jour les tables de liens pour toute page qui utilise cette page comme modèle",
        "apihelp-purge-example-simple": "Purger les pages <kbd>Main Page</kbd> et <kbd>API</kbd>.",
        "apihelp-purge-example-generator": "Purger les 10 premières pages de l’espace de noms principal",
-       "apihelp-query-summary": "Extraire des données de et sur MediaWiki.",
+       "apihelp-query-summary": "Extraire des données de MediaWiki et à propos de celui-ci.",
        "apihelp-query-extended-description": "Toutes les modifications de données devront d’abord utiliser une requête pour obtenir un jeton, afin d’éviter les abus de la part de sites malveillants.",
        "apihelp-query-param-prop": "Quelles propriétés obtenir pour les pages demandées.",
        "apihelp-query-param-list": "Quelles listes obtenir.",
        "apihelp-query+alldeletedrevisions-param-generatetitles": "Utilisé comme générateur, générer des titres plutôt que des IDs de révision.",
        "apihelp-query+alldeletedrevisions-example-user": "Lister les 50 dernières contributions supprimées par l'utilisateur <kbd>Example</kbd>.",
        "apihelp-query+alldeletedrevisions-example-ns-main": "Lister les 50 premières révisions supprimées dans l’espace de noms principal.",
-       "apihelp-query+allfileusages-summary": "Lister toutes les utilisations de fichiers, y compris celles n’existant pas.",
+       "apihelp-query+allfileusages-summary": "Lister toutes les utilisations de fichiers, y compris ceux n’existant pas.",
        "apihelp-query+allfileusages-param-from": "Le titre du fichier depuis lequel commencer l’énumération.",
        "apihelp-query+allfileusages-param-to": "Le titre du fichier auquel arrêter l’énumération.",
        "apihelp-query+allfileusages-param-prefix": "Rechercher tous les fichiers dont le titre commence par cette valeur.",
        "apihelp-query+allfileusages-paramvalue-prop-title": "Ajoute le titre du fichier.",
        "apihelp-query+allfileusages-param-limit": "Combien d’éléments renvoyer au total.",
        "apihelp-query+allfileusages-param-dir": "L'ordre dans lequel lister.",
-       "apihelp-query+allfileusages-example-B": "Lister les titres des fichiers, y compris ceux manquants, avec les IDs de page d’où ils proviennent, en commençant à <kbd>B</kbd>.",
+       "apihelp-query+allfileusages-example-b": "Lister les titres des fichiers, y compris ceux manquants, avec les IDs de page d’où ils proviennent, en commençant à <kbd>B</kbd>.",
        "apihelp-query+allfileusages-example-unique": "Lister les titres de fichier uniques.",
        "apihelp-query+allfileusages-example-unique-generator": "Obtient tous les titres de fichier, en marquant les manquants.",
        "apihelp-query+allfileusages-example-generator": "Obtient les pages contenant les fichiers.",
        "apihelp-query+allimages-param-filterbots": "Comment filtrer les fichiers téléversés par des robots. Peut être utilisé uniquement avec $1sort=timestamp. Impossible à utiliser avec $1user.",
        "apihelp-query+allimages-param-mime": "Quels types MIME rechercher, par ex. <kbd>image/jpeg</kbd>.",
        "apihelp-query+allimages-param-limit": "Combien d’images renvoyer au total.",
-       "apihelp-query+allimages-example-B": "Afficher une liste des fichiers commençant par la lettre <kbd>B</kbd>.",
+       "apihelp-query+allimages-example-b": "Afficher une liste des fichiers commençant par la lettre <kbd>B</kbd>.",
        "apihelp-query+allimages-example-recent": "Afficher une liste de fichiers récemment téléversés, semblable à [[Special:NewFiles]].",
        "apihelp-query+allimages-example-mimetypes": "Afficher une liste de fichiers avec le type MIME <kbd>image/png</kbd> ou <kbd>image/gif</kbd>",
        "apihelp-query+allimages-example-generator": "Afficher l’information sur 4 fichiers commençant par la lettre <kbd>T</kbd>.",
        "apihelp-query+alllinks-param-namespace": "L’espace de noms à énumérer.",
        "apihelp-query+alllinks-param-limit": "Combien d’éléments renvoyer au total.",
        "apihelp-query+alllinks-param-dir": "L'ordre dans lequel lister.",
-       "apihelp-query+alllinks-example-B": "Lister les titres liés, y compris ceux manquants, avec les IDs des pages d’où ils proviennent, en démarrant à <kbd>B</kbd>.",
+       "apihelp-query+alllinks-example-b": "Lister les titres liés, y compris ceux manquants, avec les IDs des pages d’où ils proviennent, en démarrant à <kbd>B</kbd>.",
        "apihelp-query+alllinks-example-unique": "Lister les titres liés uniques",
        "apihelp-query+alllinks-example-unique-generator": "Obtient tous les titres liés, en marquant les manquants",
        "apihelp-query+alllinks-example-generator": "Obtient les pages contenant les liens",
        "apihelp-query+allpages-param-dir": "L'ordre dans lequel lister.",
        "apihelp-query+allpages-param-filterlanglinks": "Filtrer si une page a des liens de langue. Noter que cela ne prend pas en compte les liens de langue ajoutés par des extensions.",
        "apihelp-query+allpages-param-prexpiry": "Quelle expiration de protection sur laquelle filtrer la page :\n;indefinite:N’obtenir que les pages avec une expiration de protection infinie.\n;definite:N’obtenir que les pages avec une expiration de protection définie (spécifique).\n;all:Obtenir toutes les pages avec une expiration de protection quelconque.",
-       "apihelp-query+allpages-example-B": "Afficher une liste des pages commençant par la lettre <kbd>B</kbd>.",
+       "apihelp-query+allpages-example-b": "Afficher une liste des pages commençant par la lettre <kbd>B</kbd>.",
        "apihelp-query+allpages-example-generator": "Afficher l’information sur 4 pages commençant par la lettre <kbd>T</kbd>.",
        "apihelp-query+allpages-example-generator-revisions": "Afficher le contenu des 2 premières pages hors redirections commençant par <kbd>Re</kbd>.",
        "apihelp-query+allredirects-summary": "Lister toutes les redirections vers un espace de noms.",
        "apihelp-query+allredirects-param-namespace": "L’espace de noms à énumérer.",
        "apihelp-query+allredirects-param-limit": "Combien d’éléments renvoyer au total.",
        "apihelp-query+allredirects-param-dir": "La direction dans laquelle lister.",
-       "apihelp-query+allredirects-example-B": "Lister les pages cible, y compris celles manquantes, avec les IDs de page d’où ils proviennent, en commençant à <kbd>B</kbd>.",
+       "apihelp-query+allredirects-example-b": "Lister les pages cible, y compris celles manquantes, avec les IDs de page d’où ils proviennent, en commençant à <kbd>B</kbd>.",
        "apihelp-query+allredirects-example-unique": "Lister les pages cible unique",
        "apihelp-query+allredirects-example-unique-generator": "Obtient toutes les pages cible, en marquant les manquantes",
        "apihelp-query+allredirects-example-generator": "Obtient les pages contenant les redirections",
        "apihelp-query+alltransclusions-param-namespace": "L’espace de noms à énumérer.",
        "apihelp-query+alltransclusions-param-limit": "Combien d’éléments renvoyer au total.",
        "apihelp-query+alltransclusions-param-dir": "L'ordre dans lequel lister.",
-       "apihelp-query+alltransclusions-example-B": "Lister les titres inclus, y compris les manquants, avec les IDs des pages d’où ils viennent, en commençant à <kbd>B</kbd>.",
+       "apihelp-query+alltransclusions-example-b": "Lister les titres inclus, y compris les manquants, avec les IDs des pages d’où ils viennent, en commençant à <kbd>B</kbd>.",
        "apihelp-query+alltransclusions-example-unique": "Lister les titres inclus uniques",
        "apihelp-query+alltransclusions-example-unique-generator": "Obtient tous les titres inclus, en marquant les manquants.",
        "apihelp-query+alltransclusions-example-generator": "Obtient les pages contenant les transclusions.",
        "apihelp-query+allusers-param-witheditsonly": "Ne lister que les utilisateurs qui ont fait des modifications.",
        "apihelp-query+allusers-param-activeusers": "Lister uniquement les utilisateurs actifs durant {{PLURAL:$1|le dernier jour|les $1 derniers jours}}.",
        "apihelp-query+allusers-param-attachedwiki": "Avec <kbd>$1prop=centralids</kbd>, indiquer aussi si l’utilisateur est attaché avec le wiki identifié par cet ID.",
-       "apihelp-query+allusers-example-Y": "Lister les utilisateurs en commençant à <kbd>Y</kbd>.",
+       "apihelp-query+allusers-example-y": "Lister les utilisateurs en commençant à <kbd>Y</kbd>.",
        "apihelp-query+authmanagerinfo-summary": "Récupérer les informations concernant l’état d’authentification actuel.",
        "apihelp-query+authmanagerinfo-param-securitysensitiveoperation": "Tester si l’état d’authentification actuel de l’utilisateur est suffisant pour l’opération spécifiée comme sensible du point de vue sécurité.",
        "apihelp-query+authmanagerinfo-param-requestsfor": "Récupérer les informations sur les requêtes d’authentification nécessaires pour l’action d’authentification spécifiée.",
        "apihelp-query+categoryinfo-summary": "Renvoie les informations sur les catégories données.",
        "apihelp-query+categoryinfo-example-simple": "Obtenir des informations sur <kbd>Category:Foo</kbd> et <kbd>Category:Bar</kbd>.",
        "apihelp-query+categorymembers-summary": "Lister toutes les pages d’une catégorie donnée.",
-       "apihelp-query+categorymembers-param-title": "Quelle catégorie énumérer (obligatoire). Doit comprendre le préfixe <kbd>{{ns:category}}:</kbd>. Impossible à utiliser avec <var>$1pageid</var>.",
-       "apihelp-query+categorymembers-param-pageid": "ID de la page de la catégorie à énumérer. Impossible à utiliser avec <var>$1title</var>.",
+       "apihelp-query+categorymembers-param-title": "Quelle catégorie énumérer (obligatoire). Doit comprendre le préfixe <kbd>{{ns:category}}:</kbd>. Incompatible avec <var>$1pageid</var>.",
+       "apihelp-query+categorymembers-param-pageid": "ID de la page de la catégorie à énumérer. Incompatible avec <var>$1title</var>.",
        "apihelp-query+categorymembers-param-prop": "Quelles informations inclure :",
        "apihelp-query+categorymembers-paramvalue-prop-ids": "Ajoute l’ID de la page.",
        "apihelp-query+categorymembers-paramvalue-prop-title": "Ajoute le titre et l’ID de l’espace de noms de la page.",
        "apihelp-query+categorymembers-paramvalue-prop-sortkey": "Ajoute la clé de tri utilisée pour trier dans la catégorie (chaîne hexadécimale).",
        "apihelp-query+categorymembers-paramvalue-prop-sortkeyprefix": "Ajoute le préfixe de la clé de tri utilisé pour trier dans la catégorie (partie lisible de la clé de tri).",
-       "apihelp-query+categorymembers-paramvalue-prop-type": "Ajoute le type dans lequel a été catégorisée la page (<samp>page</samp>, <samp>subcat</samp> ou <samp>file</samp>).",
+       "apihelp-query+categorymembers-paramvalue-prop-type": "Ajoute le type avec lequel a été catégorisée la page (<samp>page</samp>, <samp>subcat</samp> ou <samp>file</samp>).",
        "apihelp-query+categorymembers-paramvalue-prop-timestamp": "Ajoute l’horodatage de l’inclusion de la page.",
        "apihelp-query+categorymembers-param-namespace": "Inclure uniquement les pages dans ces espaces de nom. Remarquez que <kbd>$1type=subcat</kbd> ou <kbd>$1type=file</kbd> peuvent  être utilisés à la place de <kbd>$1namespace=14</kbd> ou <kbd>6</kbd>.",
-       "apihelp-query+categorymembers-param-type": "Quel type de membres de la catégorie inclure. Ignoré quand <kbd>$1sort=timestamp</kbd> est positionné.",
+       "apihelp-query+categorymembers-param-type": "Quel type de membres de la catégorie inclure. Ignoré quand <kbd>$1sort=timestamp</kbd> est défini.",
        "apihelp-query+categorymembers-param-limit": "Le nombre maximal de pages à renvoyer.",
        "apihelp-query+categorymembers-param-sort": "Propriété par laquelle trier.",
        "apihelp-query+categorymembers-param-dir": "Dans quelle direction trier.",
        "apihelp-query+categorymembers-param-startsortkey": "Utiliser plutôt $1starthexsortkey.",
        "apihelp-query+categorymembers-param-endsortkey": "Utiliser plutôt $1endhexsortkey.",
        "apihelp-query+categorymembers-example-simple": "Obtenir les 10 premières pages de <kbd>Category:Physics</kbd>.",
-       "apihelp-query+categorymembers-example-generator": "Obtenir l’information sur les 10 premières pages de <kbd>Category:Physics</kbd>.",
+       "apihelp-query+categorymembers-example-generator": "Obtenir des informations sur les 10 premières pages de <kbd>Category:Physics</kbd>.",
        "apihelp-query+contributors-summary": "Obtenir la liste des contributeurs connectés et le nombre de contributeurs anonymes d’une page.",
        "apihelp-query+contributors-param-group": "Inclut uniquement les utilisateurs dans les groupes donnés. N'inclut pas les groupes implicites ou auto-promus comme *, user ou autoconfirmed.",
        "apihelp-query+contributors-param-excludegroup": "Exclure les utilisateurs des groupes donnés. Ne pas inclure les groupes implicites ou auto-promus comme *, user ou autoconfirmed.",
        "apihelp-query+contributors-param-excluderights": "Exclure les utilisateurs ayant les droits donnés. Ne pas inclure les droits accordés par les groupes implicites ou auto-promus comme *, user ou autoconfirmed.",
        "apihelp-query+contributors-param-limit": "Combien de contributeurs renvoyer.",
        "apihelp-query+contributors-example-simple": "Afficher les contributeurs dans la <kbd>Main Page</kbd>.",
-       "apihelp-query+deletedrevisions-summary": "Obtenir des informations sur la révision supprimée.",
+       "apihelp-query+deletedrevisions-summary": "Obtenir des informations sur une révision supprimée.",
        "apihelp-query+deletedrevisions-extended-description": "Peut être utilisé de différentes manières :\n# Obtenir les révisions supprimées pour un ensemble de pages, en donnant les titres ou les ids de page. Ordonné par titre  et horodatage.\n# Obtenir des données sur un ensemble de révisions supprimées en donnant leurs IDs et leurs ids de révision. Ordonné par ID de révision.",
        "apihelp-query+deletedrevisions-param-start": "L’horodatage auquel démarrer l’énumération. Ignoré lors du traitement d’une liste d’IDs de révisions.",
        "apihelp-query+deletedrevisions-param-end": "L’horodatage auquel arrêter l’énumération. Ignoré lors du traitement d’une liste d’IDs de révisions.",
        "apihelp-query+recentchanges-summary": "Énumérer les modifications récentes.",
        "apihelp-query+recentchanges-param-start": "L’horodatage auquel démarrer l’énumération.",
        "apihelp-query+recentchanges-param-end": "L’horodatage auquel arrêter l’énumération.",
-       "apihelp-query+recentchanges-param-namespace": "Filtrer les modifications uniquement sur ces espaces de noms.",
+       "apihelp-query+recentchanges-param-namespace": "Liste uniquement les modifications dans ces espaces de noms.",
        "apihelp-query+recentchanges-param-user": "Lister uniquement les modifications faites par cet utilisateur.",
        "apihelp-query+recentchanges-param-excludeuser": "Ne pas lister les modifications faites par cet utilisateur.",
        "apihelp-query+recentchanges-param-tag": "Lister uniquement les modifications marquées avec cette balise.",
        "apihelp-query+recentchanges-param-prop": "Inclure des informations supplémentaires :",
-       "apihelp-query+recentchanges-paramvalue-prop-user": "Ajoute l’utilisateur responsable de la modification et marque s'il s'agit d'une adresse IP.",
+       "apihelp-query+recentchanges-paramvalue-prop-user": "Ajoute l’utilisateur responsable de la modification, ainsi qu’un marqueur s’il s'agit d'une adresse IP.",
        "apihelp-query+recentchanges-paramvalue-prop-userid": "Ajoute l’ID de l’utilisateur responsable de la modification.",
        "apihelp-query+recentchanges-paramvalue-prop-comment": "Ajoute le commentaire de la modification.",
        "apihelp-query+recentchanges-paramvalue-prop-parsedcomment": "Ajoute le commentaire analysé pour la modification.",
        "apihelp-query+recentchanges-param-limit": "Combien de modifications renvoyer au total.",
        "apihelp-query+recentchanges-param-type": "Quels types de modification afficher.",
        "apihelp-query+recentchanges-param-toponly": "Lister uniquement les modifications qui sont de la dernière révision.",
-       "apihelp-query+recentchanges-param-title": "Filtrer les entrées vers celles relatives à une page.",
+       "apihelp-query+recentchanges-param-title": "Lister uniquement les entrées concernant une page donnée.",
        "apihelp-query+recentchanges-param-generaterevisions": "Utilisé comme générateur, générer des IDs de révision plutôt que des titres.\nLes entrées de modification récentes sans IDs de révision associé (par ex. la plupart des entrées de journaux) ne généreront rien.",
        "apihelp-query+recentchanges-example-simple": "Lister les modifications récentes",
        "apihelp-query+recentchanges-example-generator": "Obtenir l’information de page sur les modifications récentes non relues.",
        "apihelp-query+redirects-param-show": "Afficher uniquement les éléments correspondant à ces critères :\n;fragment:Afficher uniquement les redirections avec un fragment.\n;!fragment:Afficher uniquement les redirections sans fragment.",
        "apihelp-query+redirects-example-simple": "Obtenir une liste des redirections vers [[Main Page]]",
        "apihelp-query+redirects-example-generator": "Obtenir des informations sur toutes les redirections vers [[Main Page]]",
-       "apihelp-query+revisions-summary": "Récupèrer les informations de relecture.",
-       "apihelp-query+revisions-extended-description": "Peut être utilisé de différentes manières :\n# Obtenir des données sur un ensemble de pages (dernière révision), en mettant les titres ou les ids de page.\n# Obtenir les révisions d’une page donnée, en utilisant les titres ou les ids de page avec un début, une fin, ou une limite.\n# Obtenir des données sur un ensemble de révisions en donnant leurs IDs avec revids.",
+       "apihelp-query+revisions-summary": "Obtenir des informations sur une révision.",
+       "apihelp-query+revisions-extended-description": "Peut être utilisé de différentes manières :\n# Obtenir des données sur un ensemble de pages (dernière révision), en mettant les titres ou les ids de page.\n# Obtenir les révisions d’une page donnée, en utilisant les titres ou les ids de page avec un début, une fin ou une limite.\n# Obtenir des données sur un ensemble de révisions en donnant leurs IDs avec revids.",
        "apihelp-query+revisions-paraminfo-singlepageonly": "Utilisable uniquement avec une seule page (mode #2).",
-       "apihelp-query+revisions-param-startid": "Commencer l'énumération à partir de la date de cette revue. La revue doit exister, mais ne concerne pas forcément cette page.",
-       "apihelp-query+revisions-param-endid": "Arrêter l’énumération à la date de cette revue. La revue doit exister mais ne concerne pas forcément cette page.",
+       "apihelp-query+revisions-param-startid": "Commencer l’énumération à partir de la date de cette révision. La révision doit exister mais il n’est pas nécessaire que ce soit une révision de cette page.",
+       "apihelp-query+revisions-param-endid": "Arrêter l’énumération à la date de cette révision. La révision doit exister mais il n’est pas nécessaire que ce soit une révision de cette page.",
        "apihelp-query+revisions-param-start": "À quel horodatage de révision démarrer l’énumération.",
        "apihelp-query+revisions-param-end": "Énumérer jusqu’à cet horodatage.",
-       "apihelp-query+revisions-param-user": "Inclure uniquement les révisions faites par l’utilisateur.",
-       "apihelp-query+revisions-param-excludeuser": "Exclure les révisions faites par l’utilisateur.",
+       "apihelp-query+revisions-param-user": "Inclure uniquement les révisions faites par un utilisateur donné.",
+       "apihelp-query+revisions-param-excludeuser": "Exclure les révisions faites par un utilisateur donné.",
        "apihelp-query+revisions-param-tag": "Lister uniquement les révisions marquées avec cette balise.",
        "apihelp-query+revisions-param-token": "Quels jetons obtenir pour chaque révision.",
-       "apihelp-query+revisions-example-content": "Obtenir des données avec le contenu pour la dernière révision des titres <kbd>API</kbd> et <kbd>Main Page</kbd>.",
-       "apihelp-query+revisions-example-last5": "Obtenir les 5 dernières révisions de la <kbd>Main Page</kbd>.",
-       "apihelp-query+revisions-example-first5": "Obtenir les 5 premières révisions de la <kbd>Page principale</kbd>.",
-       "apihelp-query+revisions-example-first5-after": "Obtenir les 5 premières révisions de la <kbd>Page principale</kbd> faites après le 01/05/2006.",
-       "apihelp-query+revisions-example-first5-not-localhost": "Obtenir les 5 premières révisions de la <kbd>Page principale</kbd> qui n’ont pas été faites par l’utilisateur anonyme <kbd>127.0.0.1</kbd>.",
-       "apihelp-query+revisions-example-first5-user": "Obtenir les 5 premières révisions de la <kbd>Page principale</kbd> qui ont été faites par l’utilisateur <kbd>MédiaWiki par défaut</kbd>.",
+       "apihelp-query+revisions-example-content": "Obtenir des données pour la dernière révision des titres <kbd>API</kbd> et <kbd>Main Page</kbd>, y compris le contenu.",
+       "apihelp-query+revisions-example-last5": "Obtenir les 5 dernières révisions de <kbd>Main Page</kbd>.",
+       "apihelp-query+revisions-example-first5": "Obtenir les 5 premières révisions de <kbd>Main Page</kbd>.",
+       "apihelp-query+revisions-example-first5-after": "Obtenir les 5 premières révisions de <kbd>Main Page</kbd> faites après le 01/05/2006.",
+       "apihelp-query+revisions-example-first5-not-localhost": "Obtenir les 5 premières révisions de <kbd>Main Page</kbd> qui n’ont pas été faites par l’utilisateur anonyme <kbd>127.0.0.1</kbd>.",
+       "apihelp-query+revisions-example-first5-user": "Obtenir les 5 premières révisions de <kbd>Main Page</kbd> qui ont été faites par l’utilisateur <kbd>MediaWiki default</kbd>.",
        "apihelp-query+revisions+base-param-prop": "Quelles propriétés obtenir pour chaque révision :",
        "apihelp-query+revisions+base-paramvalue-prop-ids": "L’ID de la révision.",
-       "apihelp-query+revisions+base-paramvalue-prop-flags": "Marques de la révision (mineure).",
+       "apihelp-query+revisions+base-paramvalue-prop-flags": "Attributs de la révision (mineure).",
        "apihelp-query+revisions+base-paramvalue-prop-timestamp": "L’horodatage de la révision.",
        "apihelp-query+revisions+base-paramvalue-prop-user": "L’utilisateur qui a fait la révision.",
        "apihelp-query+revisions+base-paramvalue-prop-userid": "L’ID de l’utilisateur créateur de la révision.",
        "apihelp-query+revisions+base-paramvalue-prop-size": "Longueur (en octets) de la révision.",
        "apihelp-query+revisions+base-paramvalue-prop-slotsize": "Longueur (en octets) de chaque emplacement de révision.",
-       "apihelp-query+revisions+base-paramvalue-prop-sha1": "Hachage SHA-1 (base 16) de la révision.",
+       "apihelp-query+revisions+base-paramvalue-prop-sha1": "SHA-1 (base 16) de la révision.",
        "apihelp-query+revisions+base-paramvalue-prop-slotsha1": "SHA-1 (base 16) de chaque emplacement de révision.",
        "apihelp-query+revisions+base-paramvalue-prop-contentmodel": "ID du modèle de contenu de chaque emplacement de révision.",
        "apihelp-query+revisions+base-paramvalue-prop-comment": "Commentaire de l’utilisateur sur la révision.",
        "apihelp-query+revisions+base-paramvalue-prop-roles": "Lister les rôles d’emplacement de contenu qui existent dans la révision.",
        "apihelp-query+revisions+base-paramvalue-prop-parsetree": "Utiliser  <kbd>[[Special:ApiHelp/expandtemplates|action=expandtemplates]]</kbd> ou <kbd>[[Special:ApiHelp/parse|action=parse]]</kbd> à la place. L’arbre d’analyse XML du contenu de la révision (nécessite le modèle de contenu <code>$1</code>).",
        "apihelp-query+revisions+base-param-slots": "Pour quels emplacements de révision renvoyer des données, quand les propriétés relatives aux emplacements sont incluses dans <var>$1props</var>. Si omis, les données de l’emplacement <kbd>main</kbd> seront renvoyées dans un format rétro-compatible.",
-       "apihelp-query+revisions+base-param-limit": "Limiter le nombre de révisions retournées.",
+       "apihelp-query+revisions+base-param-limit": "Limiter le nombre de révisions renvoyées.",
        "apihelp-query+revisions+base-param-expandtemplates": "Utiliser <kbd>[[Special:ApiHelp/expandtemplates|action=expandtemplates]]</kbd> à la place. Développer les modèles dans le contenu de la révision (nécessite $1prop=content).",
        "apihelp-query+revisions+base-param-generatexml": "Utiliser <kbd>[[Special:ApiHelp/expandtemplates|action=expandtemplates]]</kbd> ou <kbd>[[Special:ApiHelp/parse|action=parse]]</kbd> à la place. Générer l’arbre d’analyse XML pour le contenu de la révision (nécessite $1prop=content).",
        "apihelp-query+revisions+base-param-parse": "Utiliser <kbd>[[Special:ApiHelp/parse|action=parse]]</kbd> à la place. Analyser le contenu de la révision (nécessite $1prop=content). Pour des raisons de performance, si cette option est utilisée, $1limit est forcé à 1.",
        "apihelp-query+userinfo-paramvalue-prop-registrationdate": "Ajoute la date d’inscription de l’utilisateur.",
        "apihelp-query+userinfo-paramvalue-prop-unreadcount": "Ajoute le compteur de pages non lues de la liste de suivi de l’utilisateur (au maximum $1 ; renvoie <samp>$2</samp> s’il y en a plus).",
        "apihelp-query+userinfo-paramvalue-prop-centralids": "Ajoute les IDs centraux et l’état d’attachement de l’utilisateur.",
+       "apihelp-query+userinfo-paramvalue-prop-latestcontrib": "Ajoute la date de la dernière contribution de l'utilisateur.",
        "apihelp-query+userinfo-param-attachedwiki": "Avec <kbd>$1prop=centralids</kbd>, indiquer si l’utilisateur est attaché au wiki identifié par cet ID.",
        "apihelp-query+userinfo-example-simple": "Obtenir des informations sur l’utilisateur actuel.",
        "apihelp-query+userinfo-example-data": "Obtenir des informations supplémentaires sur l’utilisateur actuel.",
        "apihelp-unblock-param-tags": "Modifier les balises à appliquer à l’entrée dans le journal de blocage.",
        "apihelp-unblock-example-id": "Lever le blocage d’ID #<kbd>105</kbd>.",
        "apihelp-unblock-example-user": "Débloquer l’utilisateur <kbd>Bob</kbd> avec le motif <kbd>Désolé Bob</kbd>.",
-       "apihelp-undelete-summary": "Restituer les versions d'une page supprimée.",
+       "apihelp-undelete-summary": "Restaurer les versions d’une page supprimée.",
        "apihelp-undelete-extended-description": "Une liste des révisions supprimées (avec les horodatages) peut être récupérée via [[Special:ApiHelp/query+deletedrevisions|prop=deletedrevisions]], et une liste d’IDs de fichiers supprimés peut être récupérée via [[Special:ApiHelp/query+filearchive|list=filearchive]].",
        "apihelp-undelete-param-title": "Titre de la page à restaurer.",
        "apihelp-undelete-param-reason": "Motif de restauration.",
        "api-pageset-param-redirects-generator": "Résoudre automatiquement les redirections dans <var>$1titles</var>, <var>$1pageids</var> et <var>$1revids</var>, et dans les pages renvoyées par <var>$1generator</var>.",
        "api-pageset-param-redirects-nogenerator": "Résoudre automatiquement les redirections dans <var>$1titles</var>, <var>$1pageids</var> et <var>$1revids</var>.",
        "api-pageset-param-converttitles": "Convertir les titres dans d’autres variantes si nécessaire. Fonctionne uniquement si la langue de contenu du wiki prend en charge la conversion en variantes. Les langues qui prennent en charge la conversion en variantes incluent $1.",
-       "api-help-title": "API aide de MediaWiki",
+       "api-help-title": "Aide de l'API MediaWiki",
        "api-help-lead": "Ceci est une page d’aide de l’API de MediaWiki générée automatiquement.\n\nDocumentation et exemples : https://www.mediawiki.org/wiki/API",
        "api-help-main-header": "Module principal",
        "api-help-undocumented-module": "Aucune documentation pour le module $1.",
        "api-help-license-noname": "Licence : [[$1|Voir le lien]]",
        "api-help-license-unknown": "Licence : <span class=\"apihelp-unknown\">inconnue</span>",
        "api-help-parameters": "{{PLURAL:$1|Paramètre|Paramètres}} :",
-       "api-help-param-deprecated": "Désuet.",
+       "api-help-param-deprecated": "Obsolète.",
        "api-help-param-required": "Ce paramètre est obligatoire.",
        "api-help-param-templated": "Ceci est un [[Special:ApiHelp/main#main/templatedparams|paramètre de modèle]]. En faisant une requête, $2.",
        "api-help-param-templated-var-first": "<var>&#x7B;$1&#x7D;</var> dans le nom du paramètre doit être remplacé par des valeurs de <var>$2</var>",
        "api-help-param-list": "{{PLURAL:$1|1=Une des valeurs suivantes|2=Valeurs (séparées par <kbd>{{!}}</kbd> ou [[Special:ApiHelp/main#main/datatypes|autre]])}} : $2",
        "api-help-param-list-can-be-empty": "{{PLURAL:$1|0=Doit être vide|Peut être vide, ou $2}}",
        "api-help-param-limit": "Pas plus de $1 autorisé.",
-       "api-help-param-limit2": "Pas plus de $1 autorisé ($2 pour les robots).",
+       "api-help-param-limit2": "La valeur maximale autorisée est $1 ($2 pour les robots).",
        "api-help-param-integer-min": "{{PLURAL:$1|1=La valeur ne doit pas être inférieure|2=Les valeurs ne doivent pas être inférieures}} à $2.",
        "api-help-param-integer-max": "{{PLURAL:$1|1=La valeur ne doit pas être supérieure|2=Les valeurs ne doivent pas être supérieures}} à $3.",
        "api-help-param-integer-minmax": "{{PLURAL:$1|1=La valeur doit|2=Les valeurs doivent}} être entre $2 et $3.",
        "apiwarn-validationfailed-cannotset": "ne peut pas être initialisé par ce module.",
        "apiwarn-validationfailed-keytoolong": "clé trop longue (au plus $1 octets).",
        "apiwarn-validationfailed": "Erreur de validation pour <kbd>$1</kbd>: $2",
-       "apiwarn-wgDebugAPI": "<strong>Avertissement de sécurité</strong>: <var>$wgDebugAPI</var> est activé.",
+       "apiwarn-wgdebugapi": "<strong>Avertissement de sécurité</strong>: <var>$wgDebugAPI</var> est activé.",
        "api-feed-error-title": "Erreur ($1)",
        "api-usage-docref": "Voir $1 concernant l'utilisation de l'API.",
        "api-usage-mailinglist-ref": "S’abonner à la liste de diffusion mediawiki-api-announce sur &lt;https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce&gt; pour les signalisations d’obsolescence de l’API ou de modifications en rupture.",
index 43e6e6d..cb4cd81 100644 (file)
        "apihelp-login-param-password": "Contrasinal",
        "apihelp-login-param-domain": "Dominio (opcional).",
        "apihelp-login-param-token": "Identificador de conexión obtido na primeira petición.",
-       "apihelp-login-example-gettoken": "Recuperar un identificador de conexión.",
        "apihelp-login-example-login": "Identificarse",
        "apihelp-logout-summary": "Terminar e limpar datos de sesión.",
        "apihelp-logout-example-logout": "Cerrar a sesión do usuario actual",
        "apihelp-query+allfileusages-paramvalue-prop-title": "Engade o nome do ficheiro.",
        "apihelp-query+allfileusages-param-limit": "Número total de obxectos a devolver.",
        "apihelp-query+allfileusages-param-dir": "Dirección na cal listar.",
-       "apihelp-query+allfileusages-example-B": "Lista títulos de ficheiro, incluíndo os   eliminados, cos IDs de páxina dos que proveñen, comezando en <kbd>B</kbd>.",
+       "apihelp-query+allfileusages-example-b": "Lista títulos de ficheiro, incluíndo os   eliminados, cos IDs de páxina dos que proveñen, comezando en <kbd>B</kbd>.",
        "apihelp-query+allfileusages-example-unique": "Listar títulos únicos de ficheiros.",
        "apihelp-query+allfileusages-example-unique-generator": "Obter todos os títulos de ficheiro, marcando os que faltan.",
        "apihelp-query+allfileusages-example-generator": "Obtén as páxinas que conteñen os ficheiros.",
        "apihelp-query+allimages-param-filterbots": "Como filtrar ficheiros subidos por bots. Só pode usarse con $1sort=timestamp. Non pode usarse xunto con $1user.",
        "apihelp-query+allimages-param-mime": "Que tipos MIME  buscar, por exemplo <kbd>imaxe/jpeg</kbd>.",
        "apihelp-query+allimages-param-limit": "Cantas imaxes mostar en total.",
-       "apihelp-query+allimages-example-B": "Amosar unha lista de ficheiros que comezan por <kbd>B</kbd>.",
+       "apihelp-query+allimages-example-b": "Amosar unha lista de ficheiros que comezan por <kbd>B</kbd>.",
        "apihelp-query+allimages-example-recent": "Amosar unha lista de ficheiros subidos recentemente, similares a [[Special:NewFiles]].",
        "apihelp-query+allimages-example-mimetypes": "Amosar unha lista de ficheiros con tipo MIME <kbd>image/png</kbd> ou <kbd>image/gif</kbd>",
        "apihelp-query+allimages-example-generator": "Mostar información sobre catro ficheiros que comecen pola letra <kbd>T</kbd>.",
        "apihelp-query+alllinks-param-namespace": "Espazo de nomes a enumerar.",
        "apihelp-query+alllinks-param-limit": "Número total de obxectos a devolver.",
        "apihelp-query+alllinks-param-dir": "Dirección na cal listar.",
-       "apihelp-query+alllinks-example-B": "Lista os títulos ligados, incluíndo os eliminados, cos ID das páxinas das que proveñen, comezando en <kbd>B</kbd>.",
+       "apihelp-query+alllinks-example-b": "Lista os títulos ligados, incluíndo os eliminados, cos ID das páxinas das que proveñen, comezando en <kbd>B</kbd>.",
        "apihelp-query+alllinks-example-unique": "Listar títulos ligados únicos",
        "apihelp-query+alllinks-example-unique-generator": "Obtén tódolos títulos ligados, marcando  os eliminados.",
        "apihelp-query+alllinks-example-generator": "Obtén as páxinas que conteñen as ligazóns.",
        "apihelp-query+allpages-param-dir": "Dirección na cal listar.",
        "apihelp-query+allpages-param-filterlanglinks": "Filtro baseado en se unha páxina ten ligazóns de lingua. Decátese de que isto pode non considerar as ligazóns de lingua engadidas polas extensións.",
        "apihelp-query+allpages-param-prexpiry": "Que finalización de protección pola que filtrar a páxina:\n;indefinida: Só obter páxinas coa finalización de protección indefinida.\n;definite: Só obter páxinas cunha finalización de protección definida.\n;all: Obter páxinas con calquera finalización de protección.",
-       "apihelp-query+allpages-example-B": "Amosar unha lista de páxinas que comezan pola letra <kbd>B</kbd>.",
+       "apihelp-query+allpages-example-b": "Amosar unha lista de páxinas que comezan pola letra <kbd>B</kbd>.",
        "apihelp-query+allpages-example-generator": "Amosar información sobre 4 páxinas que comecen pola letra <kbd>T</kbd>.",
        "apihelp-query+allpages-example-generator-revisions": "Motrar o contido das dúas primeiras páxinas que non sexan redirección que comecen por <kbd>Re</kbd>.",
        "apihelp-query+allredirects-summary": "Lista tódalas redireccións a un espazo de nomes.",
        "apihelp-query+allredirects-param-namespace": "Espazo de nomes a enumerar.",
        "apihelp-query+allredirects-param-limit": "Número total de obxectos a devolver.",
        "apihelp-query+allredirects-param-dir": "Dirección na cal listar.",
-       "apihelp-query+allredirects-example-B": "Lista as páxinas obxectivo, incluíndo as eliminadas, cos ID das páxinas das que proveñen, comezando en <kbd>B</kbd>.",
+       "apihelp-query+allredirects-example-b": "Lista as páxinas obxectivo, incluíndo as eliminadas, cos ID das páxinas das que proveñen, comezando en <kbd>B</kbd>.",
        "apihelp-query+allredirects-example-unique": "Lista páxinas obxectivo únicas.",
        "apihelp-query+allredirects-example-unique-generator": "Obtén tódalas páxinas obxectivo, marcando as eliminadas.",
        "apihelp-query+allredirects-example-generator": "Obtén as páxinas que conteñen as redireccións.",
        "apihelp-query+alltransclusions-param-namespace": "Nome de espazos a numerar.",
        "apihelp-query+alltransclusions-param-limit": "Número total de obxectos a devolver.",
        "apihelp-query+alltransclusions-param-dir": "Dirección na cal listar.",
-       "apihelp-query+alltransclusions-example-B": "Lista os títulos transcluídos, incluíndo os eliminados, cos ID das páxinas das que proveñen, comezando en <kbd>B</kbd>.",
+       "apihelp-query+alltransclusions-example-b": "Lista os títulos transcluídos, incluíndo os eliminados, cos ID das páxinas das que proveñen, comezando en <kbd>B</kbd>.",
        "apihelp-query+alltransclusions-example-unique": "Lista os títulos transcluídos únicos.",
        "apihelp-query+alltransclusions-example-unique-generator": "Obtén tódolos títulos transcluídos, marcando  os eliminados.",
        "apihelp-query+alltransclusions-example-generator": "Obtén as páxinas que conteñen as transclusións.",
        "apihelp-query+allusers-param-witheditsonly": "Só listar usuarios que teñan feito edicións.",
        "apihelp-query+allusers-param-activeusers": "Só listar usuarios activos {{PLURAL:$1|no último día|nos $1 últimos días}}.",
        "apihelp-query+allusers-param-attachedwiki": "Con <kbd>$1prop=centralids</kbd>, \ntamén indica se o usuario está acoplado á wiki identificada por este identificador.",
-       "apihelp-query+allusers-example-Y": "Listar usuarios que comecen por <kbd>Y</kbd>.",
+       "apihelp-query+allusers-example-y": "Listar usuarios que comecen por <kbd>Y</kbd>.",
        "apihelp-query+authmanagerinfo-summary": "Recuperar información sobre o estado de autenticación actual.",
        "apihelp-query+authmanagerinfo-param-securitysensitiveoperation": "Comprobar se o estado de autenticación actual do usuario é abondo para a operación especificada como sensible dende o punto de vista da seguridade.",
        "apihelp-query+authmanagerinfo-param-requestsfor": "Recuperar a información sobre as peticións de autenticación necesarias para a acción de autenticación especificada.",
        "apiwarn-validationfailed-cannotset": "non pode ser establecido por este módulo.",
        "apiwarn-validationfailed-keytoolong": "clave demasiado longa (non pode ter máis de $1 bytes).",
        "apiwarn-validationfailed": "Erro de validación de <kbd>$1</kbd>: $2",
-       "apiwarn-wgDebugAPI": "<strong>Aviso de seguridade</strong>: <var>$wgDebugAPI</var> está habilitado.",
+       "apiwarn-wgdebugapi": "<strong>Aviso de seguridade</strong>: <var>$wgDebugAPI</var> está habilitado.",
        "api-feed-error-title": "Erro ($1)",
        "api-usage-docref": "Consulte $1 para ver o uso da API.",
        "api-usage-mailinglist-ref": "Subscribirse á lista de correo mediawiki-api-announce en &lt;https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce&gt;  para obter avisos de obsolescencia da API ou de modificacións importantes.",
index 04efe36..80f74b0 100644 (file)
        "apihelp-edit-param-text": "תוכן הדף.",
        "apihelp-edit-param-summary": "תקציר עריכה. גם כותרת פסקה כש־$1section=new ו־$1sectiontitle אינו מוגדר.",
        "apihelp-edit-param-tags": "אילו תגי שינוי להחיל על הגרסה.",
-       "apihelp-edit-param-minor": "ער×\99×\9b×\94 משנית.",
-       "apihelp-edit-param-notminor": "ש×\99× ×\95×\99 ×\9c×\90 ×\9eשנ×\99.",
+       "apihelp-edit-param-minor": "ס×\99×\9e×\95×\9f ×\94ער×\99×\9b×\94 ×\91ת×\95ר משנית.",
+       "apihelp-edit-param-notminor": "×\9c×\90 ×\9cס×\9e×\9f ×\90ת ×\94ער×\99×\9b×\94 ×\94×\96×\90ת ×\91ת×\95ר ×\9eשנ×\99ת ×\90פ×\99×\9c×\95 ×\9bש×\9e×\95פע×\9cת ×\94×\94×¢×\93פ×\94 \"{{int:tog-minordefault}}\".",
        "apihelp-edit-param-bot": "סימון עריכה זו כעריכת בוט.",
        "apihelp-edit-param-basetimestamp": "חותם־זמן של גרסת הבסיס, משמש לזיהוי התנגשויות עריכה. אפשר לקבל אותו באמצעות [[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]].",
        "apihelp-edit-param-starttimestamp": "חותם־הזמן של תחילת תהליך העריכה, משמש לזיהוי התנגשויות. אפשר לקבל ערך מתאים באמצעות <var>[[Special:ApiHelp/main|curtimestamp]]</var> בעת תחילת תהליך העריכה (למשל בזמן טעינת תוכן הדף לעריכה).",
        "apihelp-login-param-password": "ססמה.",
        "apihelp-login-param-domain": "שם מתחם (רשות).",
        "apihelp-login-param-token": "אסימון כניסה התקבל בבקשה הראשונה.",
-       "apihelp-login-example-gettoken": "קבלת אסימון כניסה.",
        "apihelp-login-example-login": "כניסה.",
        "apihelp-logout-summary": "יציאה וניקוי של נתוני הפעילות.",
        "apihelp-logout-example-logout": "הוצאת המשתמש הנוכחי.",
        "apihelp-parse-paramvalue-prop-revid": "הוספת מזהה הגרסה של הדף המפוענח.",
        "apihelp-parse-paramvalue-prop-displaytitle": "הוספת הכותרת של קוד הוויקי המפוענח.",
        "apihelp-parse-paramvalue-prop-headitems": "נותן פריטים לשים ב־<code>&lt;head&gt;</code> של הדף.",
-       "apihelp-parse-paramvalue-prop-headhtml": "נותן את ה־<code>&lt;head&gt;</code> המפוענח של הדף.",
+       "apihelp-parse-paramvalue-prop-headhtml": "נותן doctype מפוענח, תג <code>&lt;html&gt;</code> פותח, רכיב <code>&lt;head&gt;</code>, ותג <code>&lt;body&gt;</code> פותח של הדף.",
        "apihelp-parse-paramvalue-prop-modules": "מתן יחידות ResourceLoader שמשמשות בדף. כדי לטעון, יש להשתמש ב<code dir=\"ltr\">mw.loader.using()</code>. יש לבקש את <kbd>jsconfigvars</kbd> או את <kbd>encodedjsconfigvars</kbd> יחד עם <kbd>modules</kbd>.",
        "apihelp-parse-paramvalue-prop-jsconfigvars": "נותן משתני הגדרות של JavaScript שייחודיים לדף הזה. כדי להחיל, יש להשתמש ב<code dir=\"ltr\">mw.config.set()</code>.",
        "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "נותן משתני הגדרות של JavaScript שייחודיים לדף הזה בתור מחרוזת JSON.",
        "apihelp-query+allfileusages-paramvalue-prop-title": "הוספת שם הקובץ.",
        "apihelp-query+allfileusages-param-limit": "כמה פריטים להחזיר בסך הכול.",
        "apihelp-query+allfileusages-param-dir": "באיזה כיוון לרשום.",
-       "apihelp-query+allfileusages-example-B": "רשימת שמות קבצים, כולל חסרים, עם מזהי הדפים שהם מופיעים בהם, החל מ־<kbd>B</kbd>.",
+       "apihelp-query+allfileusages-example-b": "רשימת שמות קבצים, כולל חסרים, עם מזהי הדפים שהם מופיעים בהם, החל מ־<kbd>B</kbd>.",
        "apihelp-query+allfileusages-example-unique": "רשימת שמות קבצים ייחודיים.",
        "apihelp-query+allfileusages-example-unique-generator": "קבלת כל שמות הקבצים, כולל חסרים.",
        "apihelp-query+allfileusages-example-generator": "קבלת דפים שמכילים את הקבצים.",
        "apihelp-query+allimages-param-filterbots": "איך לסנן קבצים שמעלים בוטים. יכול לשמש רק עם $1sort=timestamp. לא יכול לשמש יחד עם $1user.",
        "apihelp-query+allimages-param-mime": "אילו סוגי MIME לחפש, למשל <kbd>image/jpeg</kbd>.",
        "apihelp-query+allimages-param-limit": "כמה תמונות להחזיר בסך הכול.",
-       "apihelp-query+allimages-example-B": "הצגת רשימה של קבצים שמתחילים באות <kbd>B</kbd>.",
+       "apihelp-query+allimages-example-b": "הצגת רשימה של קבצים שמתחילים באות <kbd>B</kbd>.",
        "apihelp-query+allimages-example-recent": "הצגת רשימת קבצים שהועלו לאחרונה, דומה ל־[[Special:NewFiles]].",
        "apihelp-query+allimages-example-mimetypes": "להציג רשימה של קבצות שסוג ה־MIME שלהם הוא <kbd>image/png</kbd> או <kbd>image/gif</kbd>.",
        "apihelp-query+allimages-example-generator": "הצגת מידע על 4 קבצים המתחילים באות <kbd>T</kbd>.",
        "apihelp-query+alllinks-param-namespace": "איזה מרחב שם למנות.",
        "apihelp-query+alllinks-param-limit": "כמה פריטים להחזיר בסך הכול.",
        "apihelp-query+alllinks-param-dir": "באיזה כיוון לרשום.",
-       "apihelp-query+alllinks-example-B": "רשימת כותרות מקושרות, כולל חסרות, עם מזהי הדפים שהן מופיעות בהם, החל מ־<kbd>B</kbd>.",
+       "apihelp-query+alllinks-example-b": "רשימת כותרות מקושרות, כולל חסרות, עם מזהי הדפים שהן מופיעות בהם, החל מ־<kbd>B</kbd>.",
        "apihelp-query+alllinks-example-unique": "רשימת כותרות מקושרים ייחודיות.",
        "apihelp-query+alllinks-example-unique-generator": "קבלת כל הכותרות המקושרות, וסימון החסרות.",
        "apihelp-query+alllinks-example-generator": "קבלת דפים שמכילים את הקישורים.",
        "apihelp-query+allpages-param-dir": "באיזה כיוון לרשום.",
        "apihelp-query+allpages-param-filterlanglinks": "סינון על סמך קיום קישורים לשוניים בדף. יש לשים לב לכך שזה אולי לא יתייחס לקישורים לשוניים שנוספו על־ידי הרחבות.",
        "apihelp-query+allpages-param-prexpiry": "לפי איזו תפוגת הגנה לסנן את הדף הזה:\n;indefinite:לקבל רק דפים מוגנית לצמיתות.\n;definite:לקבל רק דפים עם תפוגת הגנה מוגדרת.\n;all:לקבל דפים עם תפוגת הגנה כלשהי.",
-       "apihelp-query+allpages-example-B": "להציג רשימה של דפים במתחילים באות <kbd>B</kbd>.",
+       "apihelp-query+allpages-example-b": "להציג רשימה של דפים במתחילים באות <kbd>B</kbd>.",
        "apihelp-query+allpages-example-generator": "להציג מידע על 4 דפים שמתחילים באות <kbd>T</kbd>.",
        "apihelp-query+allpages-example-generator-revisions": "להציג את תוכן של 2 הדפים הראשונים שמתחילים ב־<kbd>Re</kbd> ושאינם דפי הפניה.",
        "apihelp-query+allredirects-summary": "רשימה של כל ההפניות למרחב שם.",
        "apihelp-query+allredirects-param-namespace": "איזה מרחב שם למנות.",
        "apihelp-query+allredirects-param-limit": "כמה פריטים להחזיר בסך הכול.",
        "apihelp-query+allredirects-param-dir": "באיזה כיוון לרשום.",
-       "apihelp-query+allredirects-example-B": "רשימת דפי יעד, כולל חסרים, עם מזהי הדפים שהם מופיעים בהם, החל מ־<kbd>B</kbd>.",
+       "apihelp-query+allredirects-example-b": "רשימת דפי יעד, כולל חסרים, עם מזהי הדפים שהם מופיעים בהם, החל מ־<kbd>B</kbd>.",
        "apihelp-query+allredirects-example-unique": "רשימת דפי יעד ייחודיים.",
        "apihelp-query+allredirects-example-unique-generator": "קבלת על דפי היעד, תוך כדי סימון החסרים.",
        "apihelp-query+allredirects-example-generator": "קבלת דפים שמכילים את ההפניות.",
        "apihelp-query+alltransclusions-param-namespace": "איזה מרחב שם למנות.",
        "apihelp-query+alltransclusions-param-limit": "כמה פריטים להחזיר בסך הכול.",
        "apihelp-query+alltransclusions-param-dir": "באיזה כיוון לרשום.",
-       "apihelp-query+alltransclusions-example-B": "רשימת כותרות מוכללות, כולל חסרות, עם מזהי הדפים שהן מופיעות בהם, החל מ־<kbd>B</kbd>.",
+       "apihelp-query+alltransclusions-example-b": "רשימת כותרות מוכללות, כולל חסרות, עם מזהי הדפים שהן מופיעות בהם, החל מ־<kbd>B</kbd>.",
        "apihelp-query+alltransclusions-example-unique": "רשימת כותרת מוכללות ייחודיות.",
        "apihelp-query+alltransclusions-example-unique-generator": "קבלת כל כל הכותרות המוכללות, תוך כדי סימון החסרות.",
        "apihelp-query+alltransclusions-example-generator": "קבלת דפים שמכילים את ההכללות.",
        "apihelp-query+allusers-param-witheditsonly": "לרשום רק משתמשים שעשו עריכות.",
        "apihelp-query+allusers-param-activeusers": "לרשום רק משתמשים שהיו פעילים {{PLURAL:$1|ביום האחרון|ביומיים האחרונים|ב־$1 הימים האחרונים}}.",
        "apihelp-query+allusers-param-attachedwiki": "עם <kbd>$1prop=centralids</kbd>, לציין גם האם המשתמש משויך לוויקי עם המזהה הזה.",
-       "apihelp-query+allusers-example-Y": "לרשום משתמשים שמתחילים ב־<kbd>Y</kbd>.",
+       "apihelp-query+allusers-example-y": "לרשום משתמשים שמתחילים ב־<kbd>Y</kbd>.",
        "apihelp-query+authmanagerinfo-summary": "אחזור מידע אודות מצב האימות הנוכחי.",
        "apihelp-query+authmanagerinfo-param-securitysensitiveoperation": "בדיקה האם מצב האימות הנוכחי של המשתמש מספיק בשביל הפעולה הרגישה מבחינת אבטחה שצוינה.",
        "apihelp-query+authmanagerinfo-param-requestsfor": "אחזור מידע על בקשות האימות הדרושות לפעולת האימות המבוקשת.",
        "apihelp-query+filerepoinfo-paramvalue-prop-displayname": "שם אתר הוויקי של המאגר (בפורמט שמתאים לקריאה על־ידי אדם).",
        "apihelp-query+filerepoinfo-paramvalue-prop-favicon": "כתובת הצלמית של אתר הוויקי של המאגר, מתוך ההגדרה <var dir=\"ltr\">[[mw:Special:MyLanguage/Manual:$wgFavicon|$wgFavicon]]</var>.",
        "apihelp-query+filerepoinfo-paramvalue-prop-fetchDescription": "האם דפי תיאור של קבצים מאוחזרים מהמאגר הזה בעת צפייה בדפי תיאור של קבצים מקומיים.",
-       "apihelp-query+filerepoinfo-paramvalue-prop-initialCapital": "×\94×\90×\9d ×©×\9e×\95ת ×©×\9c ×§×\91צ×\99×\9d ×\9eת×\97×\99×\9c×\99×\9d ×\91×\90×\95ת ×\92×\93×\95×\9c×\94.",
+       "apihelp-query+filerepoinfo-paramvalue-prop-initialCapital": "×\94×\90×\9d ×©×\9e×\95ת ×©×\9c ×§×\91צ×\99×\9d ×\9eת×\97×\99×\9c×\99×\9d ×\91×\90×\95ת ×¨×\99ש×\99ת.",
        "apihelp-query+filerepoinfo-paramvalue-prop-local": "האם המאגר הזה הוא המאגר המקומי או לא.",
        "apihelp-query+filerepoinfo-paramvalue-prop-name": "מפתח המאגר, שנמצא בשימוש למשל בערכים המוחזרים של <var dir=\"ltr\">[[mw:Special:MyLanguage/Manual:$wgForeignFileRepos|$wgForeignFileRepos]]</var> ושל [[Special:ApiHelp/query+imageinfo|imageinfo]].",
        "apihelp-query+filerepoinfo-paramvalue-prop-rootUrl": "נתיב כתובת הבסיס עבור נתיבים של תמונות.",
        "apihelp-query+userinfo-paramvalue-prop-registrationdate": "הוספת תאריך הרישום של המשתמש.",
        "apihelp-query+userinfo-paramvalue-prop-unreadcount": "הוספת מניין הדפים שלא נקראו ברשימת המעקב של המשתמש (לכל היותר $1; מחזיר <samp>$2</samp> אם יש יותר).",
        "apihelp-query+userinfo-paramvalue-prop-centralids": "הוספת המזהה המרכזי ומצב השיוך למשתמש.",
+       "apihelp-query+userinfo-paramvalue-prop-latestcontrib": "הוספת התאריך של התרומה האחרונה של המשתמש.",
        "apihelp-query+userinfo-param-attachedwiki": "עם <kbd>$1prop=centralids</kbd>, לציין האם המשתמש משויך לוויקי עם המזהה הזה.",
        "apihelp-query+userinfo-example-simple": "קבלת מידע על המשתמש הנוכחי.",
        "apihelp-query+userinfo-example-data": "קבלת מידע נוסף על המשתמש הנוכחי.",
        "apiwarn-validationfailed-cannotset": "לא יכולה להיות מוגדרת על־ידי המודול הזה.",
        "apiwarn-validationfailed-keytoolong": "המפתח ארוך מדי (מותר לכתוב לא יותר מ־$1 בתים).",
        "apiwarn-validationfailed": "שגיאה בבדיקת תקינות עבור <kbd>$1</kbd>: $2",
-       "apiwarn-wgDebugAPI": "<strong>אזהרת אבטחה</strong>: <var dir=\"ltr\">$wgDebugAPI</var> מופעל.",
+       "apiwarn-wgdebugapi": "<strong>אזהרת אבטחה</strong>: <var dir=\"ltr\">$wgDebugAPI</var> מופעל.",
        "api-feed-error-title": "שגיאה ($1)",
        "api-usage-docref": "ר' $1 לשימוש ב־API.",
        "api-usage-mailinglist-ref": "עשו מינוי לרשימת התפוצה mediawiki-api-announce בכתובת &lt;https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce&gt; בשביל הודעות על התיישנות API ושינויים שוברים.",
index 59d7b28..530b7dd 100644 (file)
        "apihelp-login-param-password": "Jelszó.",
        "apihelp-login-param-domain": "Tartomány (opcionális)",
        "apihelp-login-param-token": "Az első kérésben megszerzett bejelentkezési token.",
-       "apihelp-login-example-gettoken": "Egy bejelentkezés token lekérése.",
        "apihelp-login-example-login": "Bejelentkezés.",
        "apihelp-logout-summary": "Kijelentkezés és munkamenetadatok törlése.",
        "apihelp-logout-example-logout": "Aktuális felhasználó kijelentkeztetése.",
        "apihelp-query+allfileusages-paramvalue-prop-title": "A fájl neve.",
        "apihelp-query+allfileusages-param-limit": "A visszaadandó elemek maximális száma.",
        "apihelp-query+allfileusages-param-dir": "A listázás iránya.",
-       "apihelp-query+allfileusages-example-B": "Fájlnevek listázása, a hiányzókat is beleértve, a forráslapok lapazonosítójával, <kbd>B</kbd>-től kezdve.",
+       "apihelp-query+allfileusages-example-b": "Fájlnevek listázása, a hiányzókat is beleértve, a forráslapok lapazonosítójával, <kbd>B</kbd>-től kezdve.",
        "apihelp-query+allfileusages-example-unique": "Különböző fájlnevek listázása.",
        "apihelp-query+allfileusages-example-unique-generator": "Az összes fájlnév lekérése, hiányzók megjelölése.",
        "apihelp-query+allfileusages-example-generator": "A fájlokat használó lapok lekérése.",
        "apihelp-query+allimages-param-filterbots": "Botok által feltöltött fájlok szűrése. Csak az <kbd>$1sort=timestamp</kbd> paraméterrel együtt használható. Nem használható együtt az <var>$1user</var> paraméterrel.",
        "apihelp-query+allimages-param-mime": "Szűrés MIME-típus alapján, pl. <kbd>image/jpeg</kbd>.",
        "apihelp-query+allimages-param-limit": "A visszaadandó képek száma.",
-       "apihelp-query+allimages-example-B": "Fájlok listázása <kbd>B</kbd>-től kezdve.",
+       "apihelp-query+allimages-example-b": "Fájlok listázása <kbd>B</kbd>-től kezdve.",
        "apihelp-query+allimages-example-recent": "A legutóbb feltöltött fájlok listázása, hasonló a [[Special:NewFiles]] laphoz.",
        "apihelp-query+allimages-example-mimetypes": "<kbd>image/png</kbd> vagy <kbd>image/gif</kbd> MIME-típusú fájlok listázása",
        "apihelp-query+allimages-example-generator": "Információk 4 fájlról <kbd>T</kbd>-től kezdve.",
        "apihelp-query+alllinks-param-namespace": "A listázandó névtér.",
        "apihelp-query+alllinks-param-limit": "A visszaadandó elemek maximális száma.",
        "apihelp-query+alllinks-param-dir": "A listázás iránya.",
-       "apihelp-query+alllinks-example-B": "Hivatkozott lapok listázása, a hiányzókat is beleértve, a forráslapok lapazonosítójával, <kbd>B</kbd>-től kezdve.",
+       "apihelp-query+alllinks-example-b": "Hivatkozott lapok listázása, a hiányzókat is beleértve, a forráslapok lapazonosítójával, <kbd>B</kbd>-től kezdve.",
        "apihelp-query+alllinks-example-unique": "Különböző hivatkozott lapok listázása.",
        "apihelp-query+alllinks-example-unique-generator": "Az összes hivatkozott lap lekérése, hiányzók megjelölése.",
        "apihelp-query+alllinks-example-generator": "A hivatkozásokat tartalmazó lapok lekérése.",
        "apihelp-query+allpages-param-dir": "A listázás iránya.",
        "apihelp-query+allpages-param-filterlanglinks": "Szűrés az alapján, hogy vannak-e nyelvközi hivatkozások a lapon. Nem biztos, hogy figyelembe veszi a kiterjesztések által hozzáadott nyelvközi hivatkozásokat.",
        "apihelp-query+allpages-param-prexpiry": "Szűrés a védelem lejárata alapján:\n;indefinite: Csak meghatározatlan idejű védelemmel ellátott lapok.\n;definite: Csak meghatározott idejű (konkrét lejáratú) védelemmel ellátott lapok.\n;all: Bármilyen lejáratú védelemmel ellátott lapok.",
-       "apihelp-query+allpages-example-B": "Lapok listázása <kbd>B</kbd>-től kezdve.",
+       "apihelp-query+allpages-example-b": "Lapok listázása <kbd>B</kbd>-től kezdve.",
        "apihelp-query+allpages-example-generator": "Információk 4 lapról <kbd>T</kbd>-től kezdve.",
        "apihelp-query+allpages-example-generator-revisions": "Az első két nem átirányító lap tartalmának megjelenítése <kbd>Re</kbd>-től kezdve.",
        "apihelp-query+allredirects-summary": "Egy adott névtérbe mutató összes átirányítás listázása.",
        "apihelp-query+allredirects-param-namespace": "A listázandó névtér.",
        "apihelp-query+allredirects-param-limit": "A visszaadandó elemek maximális száma.",
        "apihelp-query+allredirects-param-dir": "A listázás iránya.",
-       "apihelp-query+allredirects-example-B": "Céllapok listázása, a hiányzókat is beleértve, a forráslapok lapazonosítójával, <kbd>B</kbd>-től kezdve.",
+       "apihelp-query+allredirects-example-b": "Céllapok listázása, a hiányzókat is beleértve, a forráslapok lapazonosítójával, <kbd>B</kbd>-től kezdve.",
        "apihelp-query+allredirects-example-unique": "Különböző céllapok listázása.",
        "apihelp-query+allredirects-example-unique-generator": "Az összes céllap lekérése, hiányzók megjelölése.",
        "apihelp-query+allredirects-example-generator": "Az átirányításokat tartalmazó lapok lekérése.",
        "apihelp-query+alltransclusions-param-namespace": "A listázandó névtér.",
        "apihelp-query+alltransclusions-param-limit": "A visszaadandó elemek maximális száma.",
        "apihelp-query+alltransclusions-param-dir": "A listázás iránya.",
-       "apihelp-query+alltransclusions-example-B": "Beillesztett lapok listázása, a hiányzókat is beleértve, a forráslapok lapazonosítójával, <kbd>B</kbd>-től kezdve.",
+       "apihelp-query+alltransclusions-example-b": "Beillesztett lapok listázása, a hiányzókat is beleértve, a forráslapok lapazonosítójával, <kbd>B</kbd>-től kezdve.",
        "apihelp-query+alltransclusions-example-unique": "Különböző beillesztett címek listázása.",
        "apihelp-query+alltransclusions-example-unique-generator": "Az összes beillesztett lap lekérése, hiányzók megjelölése.",
        "apihelp-query+alltransclusions-example-generator": "A beillesztéseket tartalmazó lapok lekérése.",
        "apihelp-query+allusers-param-witheditsonly": "Csak szerkesztéssel rendelkező felhasználók listázása.",
        "apihelp-query+allusers-param-activeusers": "Csak az elmúlt $1 napban aktív felhasználók listázása.",
        "apihelp-query+allusers-param-attachedwiki": "Az <kbd>$1prop=centralids</kbd> paraméter mellett annak jelzése, hogy a felhasználó össze van-e kapcsolva a megadott wikivel.",
-       "apihelp-query+allusers-example-Y": "A felhasználók listázása <kbd>Y</kbd>-tól kezdve.",
+       "apihelp-query+allusers-example-y": "A felhasználók listázása <kbd>Y</kbd>-tól kezdve.",
        "apihelp-query+authmanagerinfo-summary": "Információk lekérése az aktuális azonosítási státuszról.",
        "apihelp-query+authmanagerinfo-param-securitysensitiveoperation": "Annak ellenőrzése, hogy a felhasználó jelenlegi azonosítási státusza megfelelő-e a megadott biztonságkritikus művelethez.",
        "apihelp-query+authmanagerinfo-param-requestsfor": "Információk lekérése a megadott azonosítási művelethez szükséges azonosítási kérésekről.",
index 721cd0b..d82dd84 100644 (file)
@@ -82,8 +82,8 @@
        "apihelp-edit-param-text": "Contenuto della pagina.",
        "apihelp-edit-param-summary": "Oggetto della modifica. Anche titolo della sezione se $1sezione=new e $1sectiontitle non è impostato.",
        "apihelp-edit-param-tags": "Cambia i tag da applicare alla revisione.",
-       "apihelp-edit-param-minor": "Modifica minore.",
-       "apihelp-edit-param-notminor": "Modifica non minore.",
+       "apihelp-edit-param-minor": "Contrassegna questa modifica come minore.",
+       "apihelp-edit-param-notminor": "Non contrassegnare questa modifica come minore anche se la preferenza \"{{int:tog-minordefault}}\" è impostata.",
        "apihelp-edit-param-bot": "Contrassegna questa modifica come eseguita da un bot.",
        "apihelp-edit-param-createonly": "Non modificare la pagina se già esiste.",
        "apihelp-edit-param-nocreate": "Genera un errore se la pagina non esiste.",
        "apihelp-login-param-name": "Nome utente.",
        "apihelp-login-param-password": "Password.",
        "apihelp-login-param-domain": "Dominio (opzionale).",
-       "apihelp-login-example-gettoken": "Recupera un token di login.",
        "apihelp-login-example-login": "Entra.",
        "apihelp-logout-summary": "Esci e cancella i dati della sessione.",
        "apihelp-logout-example-logout": "Disconnetti l'utente attuale.",
        "apihelp-query+allimages-param-start": "Il timestamp da cui iniziare l'elenco. Può essere utilizzato solo con $1sort=timestamp.",
        "apihelp-query+allimages-param-end": "Il timestamp al quale interrompere l'elenco. Può essere utilizzato solo con $1sort=timestamp.",
        "apihelp-query+allimages-param-limit": "Quante immagini in totale restituire.",
-       "apihelp-query+allimages-example-B": "Mostra un elenco di file a partire dalla lettera <kbd>B</kbd>.",
+       "apihelp-query+allimages-example-b": "Mostra un elenco di file a partire dalla lettera <kbd>B</kbd>.",
        "apihelp-query+alllinks-summary": "Elenca tutti i collegamenti che puntano ad un namespace indicato.",
        "apihelp-query+alllinks-param-from": "Il titolo del collegamento da cui iniziare l'elenco.",
        "apihelp-query+alllinks-param-to": "Il titolo del collegamento al quale interrompere l'elenco.",
index f824f8d..70fa9da 100644 (file)
@@ -23,7 +23,7 @@
        "apihelp-main-param-smaxage": "<code>s-maxage</code> HTTP キャッシュ コントロール ヘッダー に、この秒数を設定します。エラーがキャッシュされることはありません。",
        "apihelp-main-param-maxage": "<code>max-age</code> HTTP キャッシュ コントロール ヘッダー に、この秒数を設定します。エラーがキャッシュされることはありません。",
        "apihelp-main-param-assert": "<kbd>user</kbd> を設定した場合は利用者がログイン済みかどうかを、<kbd>bot</kbd> を指定した場合はボット権限があるかどうかを、それぞれ検証します。",
-       "apihelp-main-param-assertuser": "現在のユーザーが指定されたユーザーであることを確認します。",
+       "apihelp-main-param-assertuser": "現在の利用者が指定された利用者であることを確認します。",
        "apihelp-main-param-requestid": "任意の値を指定でき、その値が結果に含められます。リクエストを識別するために使用できます。",
        "apihelp-main-param-servedby": "リクエストを処理したホスト名を結果に含めます。",
        "apihelp-main-param-curtimestamp": "現在のタイムスタンプを結果に含めます。",
        "apihelp-import-extended-description": "<var>xml</var> パラメーターでファイルを送信する場合、ファイルのアップロードとしてHTTP POSTされなければならない (例えば、multipart/form-dataを使用する) 点に注意してください。",
        "apihelp-import-param-summary": "記録されるページ取り込みの要約。",
        "apihelp-import-param-xml": "XMLファイルをアップロード",
-       "apihelp-import-param-assignknownusers": "指定されたユーザーがこのウィキに存在する場合そのユーザーに編集を割り当てる",
+       "apihelp-import-param-assignknownusers": "指定された利用者がこのウィキに存在する場合その利用者に編集を割り当てる。",
        "apihelp-import-param-interwikisource": "ウィキ間の取り込みの場合: 取り込み元のウィキ。",
        "apihelp-import-param-interwikipage": "ウィキ間の取り込みの場合: 取り込むページ。",
        "apihelp-import-param-fullhistory": "ウィキ間の取り込みの場合: 現在の版のみではなく完全な履歴を取り込む。",
        "apihelp-login-param-password": "パスワード。",
        "apihelp-login-param-domain": "ドメイン (省略可能)",
        "apihelp-login-param-token": "最初のリクエストで取得したログイントークンです。",
-       "apihelp-login-example-gettoken": "ログイントークンを取得する。",
        "apihelp-login-example-login": "ログイン",
        "apihelp-logout-summary": "ログアウトしてセッションデータを消去します。",
        "apihelp-logout-example-logout": "現在の利用者をログアウトする。",
        "apihelp-query+allimages-param-filterbots": "ボットによりアップロードされたファイルを絞り込む方法。$1sort=timestamp を指定した場合のみ使用できます。$1user とは同時に使用できません。",
        "apihelp-query+allimages-param-mime": "検索対象のMIMEタイプ、たとえば <kbd>image/jpeg</kbd>。",
        "apihelp-query+allimages-param-limit": "返す画像の総数。",
-       "apihelp-query+allimages-example-B": "<kbd>B</kbd> で始まるファイルの一覧を表示する。",
+       "apihelp-query+allimages-example-b": "<kbd>B</kbd> で始まるファイルの一覧を表示する。",
        "apihelp-query+allimages-example-recent": "[[Special:NewFiles]] のように、最近アップロードされたファイルの一覧を表示する。",
        "apihelp-query+allimages-example-mimetypes": "MIMEタイプが <kbd>image/png</kbd> または <kbd>image/gif</kbd> であるファイルの一覧を表示する",
        "apihelp-query+allimages-example-generator": "<kbd>T</kbd> で始まる4つのファイルに関する情報を表示する。",
        "apihelp-query+alllinks-param-namespace": "列挙する名前空間。",
        "apihelp-query+alllinks-param-limit": "返す項目の総数。",
        "apihelp-query+alllinks-param-dir": "昇順・降順の別。",
-       "apihelp-query+alllinks-example-B": "<kbd>B</kbd> で始まるリンクされたページ (存在しないページも含む)を、リンク元のページIDとともに表示する。",
+       "apihelp-query+alllinks-example-b": "<kbd>B</kbd> で始まるリンクされたページ (存在しないページも含む)を、リンク元のページIDとともに表示する。",
        "apihelp-query+alllinks-example-unique": "ユニークなリンクのタイトルを一覧。",
        "apihelp-query+alllinks-example-unique-generator": "リンクされているページを、存在しないものに印をつけて、すべて取得する。",
        "apihelp-query+alllinks-example-generator": "リンクを含むページを取得します。",
        "apihelp-query+allpages-param-prlevel": "保護レベルで絞り込む ($1type= パラメーターと同時に使用しなければなりません)。",
        "apihelp-query+allpages-param-limit": "返すページの総数。",
        "apihelp-query+allpages-param-dir": "昇順・降順の別。",
-       "apihelp-query+allpages-example-B": "<kbd>B</kbd> で始まるページの一覧を表示する。",
+       "apihelp-query+allpages-example-b": "<kbd>B</kbd> で始まるページの一覧を表示する。",
        "apihelp-query+allpages-example-generator": "<kbd>T</kbd> で始まる4つのページに関する情報を表示する。",
        "apihelp-query+allpages-example-generator-revisions": "<kbd>Re</kbd> で始まる最初の非リダイレクトの2ページの内容を表示する。",
        "apihelp-query+allredirects-summary": "ある名前空間へのすべての転送を一覧表示する。",
        "apihelp-query+allredirects-param-namespace": "列挙する名前空間。",
        "apihelp-query+allredirects-param-limit": "返す項目の総数。",
        "apihelp-query+allredirects-param-dir": "昇順・降順の別。",
-       "apihelp-query+allredirects-example-B": "<kbd>B</kbd> で始まる転送先ページ (存在しないページも含む)を、転送元のページIDとともに表示する。",
+       "apihelp-query+allredirects-example-b": "<kbd>B</kbd> で始まる転送先ページ (存在しないページも含む)を、転送元のページIDとともに表示する。",
        "apihelp-query+allredirects-example-unique": "一意のターゲットページを一覧表示します。",
        "apihelp-query+allredirects-example-unique-generator": "存在しないものに印をつけて、すべて取得する。",
        "apihelp-query+allredirects-example-generator": "リダイレクトを含むページを取得します。",
        "apihelp-query+alltransclusions-param-namespace": "列挙する名前空間。",
        "apihelp-query+alltransclusions-param-limit": "返す項目の総数。",
        "apihelp-query+alltransclusions-param-dir": "昇順・降順の別。",
-       "apihelp-query+alltransclusions-example-B": "参照読み込みされているページ (存在しないページも含む) を、参照元のページIDとともに、<kbd>B</kbd> で始まるものから一覧表示する。",
+       "apihelp-query+alltransclusions-example-b": "参照読み込みされているページ (存在しないページも含む) を、参照元のページIDとともに、<kbd>B</kbd> で始まるものから一覧表示する。",
        "apihelp-query+alltransclusions-example-unique-generator": "参照読み込みされたページを、存在しないものに印をつけて、すべて取得する。",
        "apihelp-query+alltransclusions-example-generator": "参照読み込みを含んでいるページを取得する。",
        "apihelp-query+allusers-summary": "すべての登録利用者を一覧表示します。",
        "apihelp-query+allusers-param-limit": "返す利用者名の総数。",
        "apihelp-query+allusers-param-witheditsonly": "編集履歴のある利用者のみ一覧表示する。",
        "apihelp-query+allusers-param-activeusers": "最近 $1 {{PLURAL:$1|日間}}のアクティブな利用者のみを一覧表示する。",
-       "apihelp-query+allusers-example-Y": "<kbd>Y</kbd> で始まる利用者を一覧表示する。",
+       "apihelp-query+allusers-example-y": "<kbd>Y</kbd> で始まる利用者を一覧表示する。",
        "apihelp-query+backlinks-summary": "与えられたページにリンクしているすべてのページを検索します。",
        "apihelp-query+backlinks-param-title": "検索するページ名。<var>$1pageid</var> とは同時に使用できません。",
        "apihelp-query+backlinks-param-pageid": "検索するページID。<var>$1title</var>とは同時に使用できません。",
        "apihelp-query+embeddedin-param-filterredir": "転送ページを絞り込む方法。",
        "apihelp-query+embeddedin-param-limit": "返すページの総数。",
        "apihelp-query+embeddedin-example-simple": "<kbd>Template:Stub</kbd> を参照読み込みしているページを表示する。",
-       "apihelp-query+embeddedin-example-generator": "<kbd>Template:Stub</kbd> をトランスクルードしているページに関する情報を取得する。",
+       "apihelp-query+embeddedin-example-generator": "<kbd>Template:Stub</kbd> を参照読み込みしているページに関する情報を取得する。",
        "apihelp-query+extlinks-summary": "与えられたページにあるすべての外部URL (インターウィキを除く) を返します。",
        "apihelp-query+extlinks-param-limit": "返すリンクの数。",
        "apihelp-query+extlinks-param-protocol": "URLのプロトコル。このパラメータが空であり、かつ<var>$1query</var> が設定されている場合, protocol は <kbd>http</kbd> となります。すべての外部リンクを一覧表示するためにはこのパラメータと <var>$1query</var> の両方を空にしてください。",
        "apihelp-query+transcludedin-param-namespace": "この名前空間に含まれるページのみを一覧表示します。",
        "apihelp-query+transcludedin-param-limit": "返す数。",
        "apihelp-query+transcludedin-example-simple": "<kbd>Main Page</kbd> をトランスクルードしているページの一覧を取得する。",
-       "apihelp-query+transcludedin-example-generator": "<kbd>Main Page</kbd> をトランスクルードしているページに関する情報を取得する。",
+       "apihelp-query+transcludedin-example-generator": "<kbd>Main Page</kbd> を参照読み込みしているページに関する情報を取得する。",
        "apihelp-query+usercontribs-summary": "利用者によるすべての編集を取得します。",
        "apihelp-query+usercontribs-param-limit": "返す投稿記録の最大数。",
        "apihelp-query+usercontribs-param-user": "投稿記録を取得する利用者。<var>$1userids</var> または <var>$1userprefix</var> とは同時に使用できません。",
        "apierror-botsnotsupported": "この API インターフェースはボットをサポートしていません。",
        "apierror-emptypage": "内容がないページの新規作成は許可されていません。",
        "apierror-filedoesnotexist": "ファイルが存在しません。",
-       "apierror-invaliduser": "無効なユーザー名「$1」。",
+       "apierror-invaliduser": "無効な利用者名「$1」。",
        "apierror-missingparam": "パラメーター <var>$1</var> を設定してください。",
        "apierror-mustbeloggedin": "$1にログインしている必要があります。",
        "apierror-noimageredirect": "画像のリダイレクトを作成する権限がありません。",
        "apierror-nosuchpageid": "ID $1のページはありません。",
+       "apierror-pagelang-disabled": "このウィキではページの言語は変更できません。",
        "apierror-permissiondenied": "$1に必要な権限がありません。",
        "apierror-permissiondenied-generic": "アクセスが拒否されました。",
        "apierror-readonly": "ウィキは現在読み取り専用モードです。",
        "apiwarn-notfile": "「$1」はファイルではありません。",
        "apiwarn-validationfailed-cannotset": "このモジュールでは設定できません。",
        "apiwarn-validationfailed-keytoolong": "キーが長すぎます($1バイト以上は許可されません)。",
-       "apiwarn-wgDebugAPI": "<strong>セキュリティ警告</strong>:<var>$wgDebugAPI</var>が有効です。",
+       "apiwarn-wgdebugapi": "<strong>セキュリティ警告</strong>:<var>$wgDebugAPI</var>が有効です。",
        "api-feed-error-title": "エラー ($1)",
        "api-usage-docref": "APIの使用については$1を参照してください。",
        "api-exception-trace": "$2の$1($3)\n$4",
index 9497d8d..04ee838 100644 (file)
        "apihelp-edit-param-text": "문서 내용.",
        "apihelp-edit-param-summary": "편집 요약. 또한 $1section=new 및 $1sectiontitle이 설정되어 있지 않을 때 문단 제목.",
        "apihelp-edit-param-tags": "이 판에 적용할 태그를 변경합니다.",
-       "apihelp-edit-param-minor": "ì\82¬ì\86\8cí\95\9c í\8e¸ì§\91.",
+       "apihelp-edit-param-minor": "ì\9d´ í\8e¸ì§\91ì\9d\84 ì\82¬ì\86\8cí\95\9c í\8e¸ì§\91ì\9c¼ë¡\9c í\91\9cì\8b\9cí\95©ë\8b\88ë\8b¤.",
        "apihelp-edit-param-notminor": "사소하지 않은 편집.",
        "apihelp-edit-param-bot": "이 편집을 봇 편집으로 표시.",
        "apihelp-edit-param-basetimestamp": "기본 판의 타임스탬프이며, 편집 충돌을 발견하기 위해 사용됩니다. [[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]]를 통해 가져올 수 있습니다.",
        "apihelp-login-param-password": "비밀번호.",
        "apihelp-login-param-domain": "도메인 (선택).",
        "apihelp-login-param-token": "처음 요청에서 로그인 토큰을 취득했습니다.",
-       "apihelp-login-example-gettoken": "로그인 토큰을 검색합니다.",
        "apihelp-login-example-login": "로그인.",
        "apihelp-logout-summary": "로그아웃하고 세션 데이터를 지웁니다.",
        "apihelp-logout-example-logout": "현재 사용자를 로그아웃합니다.",
        "apihelp-query+allusers-paramvalue-prop-blockinfo": "현재 차단된 사용자의 정보를 추가함.",
        "apihelp-query+allusers-paramvalue-prop-editcount": "사용자의 편집 수를 추가합니다.",
        "apihelp-query+allusers-param-witheditsonly": "편집을 한 사용자만 나열합니다.",
-       "apihelp-query+allusers-example-Y": "<kbd>Y</kbd>로 시작하는 사용자를 나열합니다.",
+       "apihelp-query+allusers-example-y": "<kbd>Y</kbd>로 시작하는 사용자를 나열합니다.",
        "apihelp-query+authmanagerinfo-summary": "현재의 인증 상태에 대한 정보를 검색합니다.",
        "apihelp-query+backlinks-summary": "제시된 문서에 연결된 모든 문서를 찾습니다.",
        "apihelp-query+backlinks-param-namespace": "열거할 이름공간.",
index 669295c..d99f1b5 100644 (file)
        "apihelp-query+allfileusages-paramvalue-prop-title": "Deiht dä Dattei ehr Övverschreff derbei.",
        "apihelp-query+allfileusages-param-limit": "Wi vill sulle överhoup aanjezeisch wähde?",
        "apihelp-query+allfileusages-param-dir": "En wälsche Reijefollsch?",
-       "apihelp-query+allfileusages-example-B": "Donn Övverschreffte vun Datteije aanzeije, och vun Datteije, di (noch) nit doh sin, zesame met dä Kännonge vun dä Sigge, woh se vun sin, aanjevange vun <kbd>B</kbd>.",
+       "apihelp-query+allfileusages-example-b": "Donn Övverschreffte vun Datteije aanzeije, och vun Datteije, di (noch) nit doh sin, zesame met dä Kännonge vun dä Sigge, woh se vun sin, aanjevange vun <kbd>B</kbd>.",
        "apihelp-query+allfileusages-example-unique": "Donn ongerscheidlejje Övverschreffte vun Datteije opleßte.",
        "apihelp-query+allfileusages-example-unique-generator": "Hollt alle Övverschreffte vun Datteije, un makehr di (noch) nit doh sin.",
        "apihelp-query+allfileusages-example-generator": "Holl Sigge, woh Datteieje dren vorkumme.",
        "apihelp-query+allimages-param-filterbots": "Wi mer blohß de Datteije ußjitt, di vun Bots huh jelahde wohde sin. Kam_mer blohß met „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1sort=timestamp</code>“ bruche. Kam_mer nit met „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1user</code>“ zersamme bruche.",
        "apihelp-query+allimages-param-mime": "Wat för ene <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Multi-Purpose Internet Mail Extensions\">MIME</i>-Zoot ze Söhke, för e Beijschpell „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">image/jpeg</kbd>“.",
        "apihelp-query+allimages-param-limit": "Wi vell Bellder ennsjesamp ußjävve.",
-       "apihelp-query+allimages-example-B": "Zeisch en Leß met Sigge un bejenn mem Bohchschtabe <kbd>B</kbd>.",
+       "apihelp-query+allimages-example-b": "Zeisch en Leß met Sigge un bejenn mem Bohchschtabe <kbd>B</kbd>.",
        "apihelp-query+allimages-example-recent": "Zeijsch en Leß met de köözlesch huhjelahde Datteije, ähnlesch wi en [[Special:NewFiles]].",
        "apihelp-query+allimages-example-mimetypes": "Zeijsch en Leß met dä <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Multi-Purpose Internet Mail Extensions\">MIME</i>-Zoote „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">image/png</kbd>“ udder „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">image/gif</kbd>“.",
        "apihelp-query+allimages-example-generator": "Zeisch Aanjahbe övver veer Bellder un bejenn mem Bohchschtabe <kbd>T</kbd>.",
        "apihelp-query+alllinks-param-namespace": "Dat Appachtemang zom opzälle.",
        "apihelp-query+alllinks-param-limit": "Wi vill sulle överhoup aanjezeisch wähde?",
        "apihelp-query+alllinks-param-dir": "En wälsche Reijefollsch?",
-       "apihelp-query+alllinks-example-B": "Donn Övverschreffte aanzeije, woh Lengks drop jonnn, och di (noch) nit doh sin, zesame met dä Kännonge vun dä Sigge, woh se vun sin, aanjevange vun <kbd>B</kbd>.",
+       "apihelp-query+alllinks-example-b": "Donn Övverschreffte aanzeije, woh Lengks drop jonnn, och di (noch) nit doh sin, zesame met dä Kännonge vun dä Sigge, woh se vun sin, aanjevange vun <kbd>B</kbd>.",
        "apihelp-query+alllinks-example-unique": "Leß ongerscheidlejje verlengk Övverschreffte.",
        "apihelp-query+alllinks-example-unique-generator": "Hollt alle Övverschreffte, woh Lengks drop jonnn un makehr di (noch) nit doh sin.",
        "apihelp-query+alllinks-example-generator": "Holl Sigge, di Lengks änthallde.",
        "apihelp-query+allpages-param-limit": "Wi vill Sigge zem aanzeihje?",
        "apihelp-query+allpages-param-dir": "En wälsche Reijefollsch?",
        "apihelp-query+allpages-param-filterlanglinks": "Blohß Sigge met Schprohchelengks opleßte. Opjepaß: Dat künnt Schprohchelengks övverjonn, di vun Zohsazprojramme beijschtührt wohde sin.",
-       "apihelp-query+allpages-example-B": "Zeisch en Leß met Sigge un bejenn mem Bohchschtabe <kbd>B</kbd>.",
+       "apihelp-query+allpages-example-b": "Zeisch en Leß met Sigge un bejenn mem Bohchschtabe <kbd>B</kbd>.",
        "apihelp-query+allpages-example-generator": "Zeisch Aanjahbe övver veer Bellder un bejenn mem Bohchschtabe <kbd>T</kbd>.",
        "apihelp-query+allpages-example-generator-revisions": "Zeisch der Enhalld vu de eetsde zwai Sigg un bejenn bei <kbd>Re</kbd>.",
        "apihelp-query+allredirects-summary": "Alle Ömleidonge op e beschtemmp Appachtemang opleßte.",
        "apihelp-query+allredirects-param-namespace": "Dat Appachtemang zom opzälle.",
        "apihelp-query+allredirects-param-limit": "Wi vill sulle överhoup aanjezeisch wääde?",
        "apihelp-query+allredirects-param-dir": "En wälsche Reijefollsch?",
-       "apihelp-query+allredirects-example-B": "Zeisch Zihlsigge, och di et (noch) nit jitt, met dä Kännonge, wo se her sin, un bejenn mem Bohchschtabe <kbd>B</kbd>.",
+       "apihelp-query+allredirects-example-b": "Zeisch Zihlsigge, och di et (noch) nit jitt, met dä Kännonge, wo se her sin, un bejenn mem Bohchschtabe <kbd>B</kbd>.",
        "apihelp-query+allredirects-example-unique": "Ongerscheidlijje Sigge opleste.",
        "apihelp-query+allredirects-example-unique-generator": "Hollt alle Zihlsigge un makkehr di (noch) nit doh sin.",
        "apihelp-query+allredirects-example-generator": "Holl de Sigge met de Ömleidonge.",
        "apihelp-query+alltransclusions-param-namespace": "Dat Appachtemang zom opzälle.",
        "apihelp-query+alltransclusions-param-limit": "Wi vill sulle överhoup aanjezeisch wähde?",
        "apihelp-query+alltransclusions-param-dir": "En wälsche Reijefollsch?",
-       "apihelp-query+alltransclusions-example-B": "Donn Övverschreffte aanzeije, och vun Sigge, di (noch) nit doh sin, zesame met dä Kännonge vun dä Sigge, woh se vun sin, aanjevange vun <kbd>B</kbd>.",
+       "apihelp-query+alltransclusions-example-b": "Donn Övverschreffte aanzeije, och vun Sigge, di (noch) nit doh sin, zesame met dä Kännonge vun dä Sigge, woh se vun sin, aanjevange vun <kbd>B</kbd>.",
        "apihelp-query+alltransclusions-example-unique": "Donn de Övverschreffte vun ennjeföhschte Sigge opleßte, ävver jehde blohß eijmohl.",
        "apihelp-query+alltransclusions-example-unique-generator": "Hollt alle Övverschreffte vun ennjeföhschte Sigge, un makehr di (noch) nit doh sin.",
        "apihelp-query+alltransclusions-example-generator": "Holl Sigge, di Ennföhjonge änthallde.",
        "apihelp-query+allusers-param-limit": "Wi vill Nahme Metmaacher sulle mer krijje?",
        "apihelp-query+allusers-param-witheditsonly": "Blohß Metmahcher, di och ens jät verändert han.",
        "apihelp-query+allusers-param-activeusers": "Donn blohß Metmaacher opleßte, di  {{PLURAL:$1|der läzde Daach|en de läzde $1 Dääsch|keine läzde Daach}} aktihf wohre.",
-       "apihelp-query+allusers-example-Y": "Monn metmaacher opleßte, woh de Nahme vun met <kbd>Y</kbd> aanfange.",
+       "apihelp-query+allusers-example-y": "Monn metmaacher opleßte, woh de Nahme vun met <kbd>Y</kbd> aanfange.",
        "apihelp-query+backlinks-summary": "Fengk alle Sigge, di op de aanjejovve Sigg lengke.",
        "apihelp-query+backlinks-param-title": "De Övverschreff för noh ze Söhke. Kam_mer nit zesamme met „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1pageid</var>“ bruche.",
        "apihelp-query+backlinks-param-pageid": "De Känong vun dä Sigg zom Söhke. Kam_mer nit zesamme met „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1title</var>“ bruche.",
index 615f71e..cfca2ee 100644 (file)
@@ -28,8 +28,8 @@
        "apihelp-edit-summary": "Säiten uleeën an änneren.",
        "apihelp-edit-param-sectiontitle": "Den Titel fir en neien Abschnitt.",
        "apihelp-edit-param-text": "Säiteninhalt.",
-       "apihelp-edit-param-minor": "Kleng Ännerung.",
-       "apihelp-edit-param-notminor": "Keng kleng Ännerung",
+       "apihelp-edit-param-minor": "Dës Ännerung als kleng Ännerung markéieren.",
+       "apihelp-edit-param-notminor": "Dës Ännerung net als keng kleng Ännerung markéieren esouguer wann d'Benotzerastellung \"{{int:tog-minordefault}}\" agestallt ass.",
        "apihelp-edit-param-bot": "Dës Ännerung als eng Bot-Ännerung markéieren.",
        "apihelp-edit-param-createonly": "D'Säit net ännere wann et se scho gëtt.",
        "apihelp-edit-param-watch": "D'Säit op dem aktuelle Benotzer seng Iwwerwaachungslëscht dobäisetzen.",
index f78c25c..907be26 100644 (file)
        "apihelp-query+allfileusages-example-generator": "Gauti puslapius, kuriuose yra failai.",
        "apihelp-query+allimages-param-sort": "Pagal ką rūšiuoti.",
        "apihelp-query+allimages-param-limit": "Kiek iš viso gražinti paveikslėlių.",
-       "apihelp-query+allimages-example-B": "Rodyti failų sąrašą, pradedant raide <kbd>B</kbd>.",
+       "apihelp-query+allimages-example-b": "Rodyti failų sąrašą, pradedant raide <kbd>B</kbd>.",
        "apihelp-query+allimages-example-recent": "Rodyti neseniai įkeltų failų sąrašą, panašu į [[Special:NewFiles]].",
        "apihelp-query+allimages-example-mimetypes": "Rodyti sąrašą failų su MIME tipu <kbd>image/png</kbd> arba <kbd>image/gif</kbd>",
        "apihelp-query+allimages-example-generator": "Rodyti informaciją apie 4 failus, pradedant raide <kbd>T</kbd>.",
        "apihelp-query+allusers-param-limit": "Kiek viso gražinti vartotojų vardų.",
        "apihelp-query+allusers-param-witheditsonly": "Nurodyti tik vartotojus, kurie atliko keitimus.",
        "apihelp-query+allusers-param-activeusers": "Nurodyti tik vartotojus, kurie buvo aktyvus per {{PLURAL:$1|paskutinę dieną|paskutines $1 dienas}}.",
-       "apihelp-query+allusers-example-Y": "Nurodyti vartotojus, pradedant nuo <kbd>Y</kbd>.",
+       "apihelp-query+allusers-example-y": "Nurodyti vartotojus, pradedant nuo <kbd>Y</kbd>.",
        "apihelp-query+backlinks-summary": "Rasti visus puslapius, kurie nukreipia į pateiktą puslapį.",
        "apihelp-query+backlinks-example-simple": "Rodyti nuorodas <kbd>Pagrindinis puslapis</kbd>.",
        "apihelp-query+blocks-summary": "Nurodyti visus užblokuotus vartotojus ir IP adresus.",
index 4bfea35..912f026 100644 (file)
        "apihelp-login-param-password": "Лозинка.",
        "apihelp-login-param-domain": "Домен (незадолжително).",
        "apihelp-login-param-token": "Најавна шифра добиена со првото барање.",
-       "apihelp-login-example-gettoken": "Набави најавна шифра.",
        "apihelp-login-example-login": "Најава",
        "apihelp-logout-summary": "Одјави се и исчисти ги податоците на седницата.",
        "apihelp-logout-example-logout": "Одјави го тековниот корисник",
        "apihelp-query+alldeletedrevisions-param-to": "Запри го исписот на овој наслов.",
        "apihelp-query+alldeletedrevisions-example-user": "Список на последните 50 избришани придонеси на корисникот <kbd>Example</kbd>.",
        "apihelp-query+alldeletedrevisions-example-ns-main": "Список на последните 50 избришани преработки во главниот именски простор.",
-       "apihelp-query+allimages-example-B": "Прикажи список на податотеки што почнуваат со буквата <kbd>B</kbd>.",
+       "apihelp-query+allimages-example-b": "Прикажи список на податотеки што почнуваат со буквата <kbd>B</kbd>.",
        "apihelp-query+allimages-example-recent": "Прикажи список на неодамна подигнати податотеки сличен на [[Special:NewFiles]]",
        "apihelp-query+allimages-example-generator": "Прикажи информации за околу 4 податотеки што почнуваат со буквата <kbd>T</kbd>.",
        "apihelp-query+alllinks-summary": "Наброј ги сите врски што водат кон даден именски простор.",
        "apihelp-query+alllinks-param-namespace": "Именскиот простор што се набројува.",
        "apihelp-query+alllinks-param-limit": "Колку вкупно ставки да се дадат.",
        "apihelp-query+alllinks-param-dir": "Насока на исписот.",
-       "apihelp-query+alllinks-example-B": "Списока на наслови со врски, вклучувајќи ги отсутните, со назнаки на нивните страници, почнувајќи од <kbd>Б</kbd>.",
+       "apihelp-query+alllinks-example-b": "Списока на наслови со врски, вклучувајќи ги отсутните, со назнаки на нивните страници, почнувајќи од <kbd>Б</kbd>.",
        "apihelp-query+alllinks-example-unique": "Испиши единствени наслови со врски",
        "apihelp-query+alllinks-example-unique-generator": "Ги дава сите наслови со врски, означувајќи ги отсутните",
        "apihelp-query+alllinks-example-generator": "Дава страници што ги содржат врските",
index 7ac0575..670e3e1 100644 (file)
        "apihelp-login-param-name": "Brukernavn.",
        "apihelp-login-param-password": "Passord.",
        "apihelp-login-param-domain": "Domene (valgfritt).",
-       "apihelp-login-example-gettoken": "Henter innloggingstegn.",
        "apihelp-login-example-login": "Logg inn.",
        "apihelp-logout-summary": "Logg ut og fjern sesjonsdata.",
        "apihelp-logout-example-logout": "Logg ut den aktuelle brukeren.",
        "apihelp-query+allimages-param-filterbots": "Hvordan opplastinger av roboter skal filtreres. Kan kun brukes med $1sort=timestamp. Kan ikke brukes sammen med $1user.",
        "apihelp-query+allimages-param-mime": "Hvilke MIME-typer det skal søkes etter, f.eks. <kbd>image/jpeg</kbd>.",
        "apihelp-query+allimages-param-limit": "Hvor mange bilder som skal returneres totalt.",
-       "apihelp-query+allimages-example-B": "Viser en liste over filer som begynner med bokstaven <kbd>B</kbd>.",
+       "apihelp-query+allimages-example-b": "Viser en liste over filer som begynner med bokstaven <kbd>B</kbd>.",
        "apihelp-query+allimages-example-recent": "Viser en liste over nylig opplastede filer på samme måte som [[Special:NewFiles]].",
        "apihelp-query+allimages-example-mimetypes": "Viser en liste over filer med MIME-typen <kbd>image/png</kbd> eller <kbd>image/gif</kbd>",
        "apihelp-query+allimages-example-generator": "Viser informasjon om 4 filer fra og med bokstaven <kbd>T</kbd>.",
        "apihelp-query+allredirects-paramvalue-prop-interwiki": "Legger til interwikiprefikset fra omdirigeringen, om det er et (kan ikke brukes med <var>$1unique</var>).",
        "apihelp-query+allredirects-param-limit": "Hvor mange elementer som skal returneres totalt.",
        "apihelp-query+allredirects-param-dir": "Retningen det skal listes opp i.",
-       "apihelp-query+allredirects-example-B": "List opp målsider, inkludert de som mangler, med side-ID-ene de kommer fra, begynner på <kbd>B</kbd>.",
+       "apihelp-query+allredirects-example-b": "List opp målsider, inkludert de som mangler, med side-ID-ene de kommer fra, begynner på <kbd>B</kbd>.",
        "apihelp-query+allredirects-example-unique": "List opp unike målsider.",
        "apihelp-query+allredirects-example-unique-generator": "Henter alle målsider, markerer de som mangler.",
        "apihelp-query+allredirects-example-generator": "Henter sider som inneholder omdirigeringene.",
        "apihelp-query+allusers-param-witheditsonly": "List bare opp brukere som har gjort redigeringer.",
        "apihelp-query+allusers-param-activeusers": "List bare opp brukere som har vært aktiv {{PLURAL:$1|den siste dagene|de siste $1 dagene}}.",
        "apihelp-query+allusers-param-attachedwiki": "Med <kbd>$1prop</kbd>, indiker også hvorvidt brukeren er tilkoblet med wikien som identifiseres av denne ID-en.",
-       "apihelp-query+allusers-example-Y": "List opp brukere fra og med <kbd>Y</kbd>.",
+       "apihelp-query+allusers-example-y": "List opp brukere fra og med <kbd>Y</kbd>.",
        "apihelp-query+authmanagerinfo-summary": "Hent informasjon om den gjeldende autentiseringsstatusen.",
        "apihelp-query+backlinks-summary": "Finn alle sider som lenker til den gitte siden.",
        "apihelp-query+backlinks-param-title": "Tittel det skal søkes etter. Kan ikke brukes sammen med <var>$1pageid</var>.",
index 84eef72..968920b 100644 (file)
@@ -17,7 +17,8 @@
                        "Hex",
                        "Mainframe98",
                        "Southparkfan",
-                       "Elroy"
+                       "Elroy",
+                       "Rots61"
                ]
        },
        "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|Documentatie]]\n* [[mw:Special:MyLanguage/API:FAQ|FAQ]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api E-maillijst]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API-aankondigingen]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Bugs & verzoeken]\n</div>\n<strong>Status:</strong> De MediaWiki API is een stabiele interface die actief ondersteund en verbeterd wordt. Hoewel we het proberen te voorkomen, is het mogelijk dat er soms wijzigingen worden aangebracht die bepaalde API-verzoek kunnen verhinderen; abonneer u op de [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ e-maillijst mediawiki-api-announce] voor meldingen over wijzigingen.\n\n<strong>Foutieve verzoeken:</strong> als de API foutieve verzoeken ontvangt, wordt er geantwoord met een HTTP-header met de sleutel \"MediaWiki-API-Error\" en daarna worden de waarde van de header en de foutcode op dezelfde waarde ingesteld. Zie [[mw:Special:MyLanguage/API:Errors_and_warnings|API: Foutmeldingen en waarschuwingen]] voor meer informatie.\n\n<p class=\"mw-apisandbox-link\"><strong>Testen:</strong> u kunt [[Special:ApiSandbox|eenvoudig API-verzoeken testen]].</p>",
@@ -87,7 +88,7 @@
        "apihelp-edit-param-sectiontitle": "De naam van een nieuwe sectie.",
        "apihelp-edit-param-text": "Pagina-inhoud.",
        "apihelp-edit-param-tags": "De labels voor de revisie wijzigen.",
-       "apihelp-edit-param-minor": "Kleine bewerking.",
+       "apihelp-edit-param-minor": "Mankeer deze bewerking als een kleine bewerking.",
        "apihelp-edit-param-notminor": "Niet-kleine bewerking.",
        "apihelp-edit-param-bot": "Deze bewerking markeren als een botbewerking.",
        "apihelp-edit-param-createonly": "De pagina niet bewerken als die al bestaat.",
        "apihelp-query+allusers-param-limit": "Het totaal aantal aan gebruikersnamen dat getoont moet worden.",
        "apihelp-query+allusers-param-witheditsonly": "Toon alleen gebruikers die bewerkingen hebben gemaakt.",
        "apihelp-query+allusers-param-activeusers": "Toon alleen gebruikers die actief zijn geweest in de laatste {{PLURAL:$1|dag|$1 dagen}}.",
-       "apihelp-query+allusers-example-Y": "Toon gebruikers vanaf <kbd>Y</kbd>.",
+       "apihelp-query+allusers-example-y": "Toon gebruikers vanaf <kbd>Y</kbd>.",
        "apihelp-query+authmanagerinfo-summary": "Haal informatie op over de huidige authentificatiestatus.",
        "apihelp-query+backlinks-summary": "Vind alle pagina's die verwijzen naar de gegeven pagina.",
        "apihelp-query+backlinks-param-title": "Te onderzoeken titel. Kan niet in combinatie met <var>$1pageid</var> gebruikt worden.",
index 2d4fc69..f068ec0 100644 (file)
@@ -16,7 +16,8 @@
                        "Woytecr",
                        "InternerowyGołąb",
                        "CiaPan",
-                       "Vlad5250"
+                       "Vlad5250",
+                       "Railfail536"
                ]
        },
        "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]].",
@@ -81,7 +82,7 @@
        "apihelp-edit-param-text": "Zawartość strony.",
        "apihelp-edit-param-summary": "Opis edycji. Także tytuł sekcji gdy użyto $1section=new, a nie ustawiono $1sectiontitle.",
        "apihelp-edit-param-tags": "Znaczniki zmian do zastosowania w tej edycji.",
-       "apihelp-edit-param-minor": "Drobna zmiana.",
+       "apihelp-edit-param-minor": "Oznacz tą zmianę jako drobną zmianę.",
        "apihelp-edit-param-notminor": "Nie oznaczaj tej zmiany jako drobną.",
        "apihelp-edit-param-bot": "Oznacz tę edycję jako edycję bota.",
        "apihelp-edit-param-basetimestamp": "Czas wersji, która jest edytowana. Służy do wykrywania konfliktów edycji. Można pobrać poprzez [[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]].",
        "apihelp-login-param-password": "Hasło.",
        "apihelp-login-param-domain": "Domena (opcjonalnie).",
        "apihelp-login-param-token": "Token logowania zdobyty w pierwszym zapytaniu.",
-       "apihelp-login-example-gettoken": "Zdobądź token logowania.",
        "apihelp-login-example-login": "Zaloguj się",
        "apihelp-logout-summary": "Wyloguj i wyczyść dane sesji.",
        "apihelp-logout-example-logout": "Wyloguj obecnego użytkownika.",
        "apihelp-query+allimages-param-sort": "Sortowanie według właściwości.",
        "apihelp-query+allimages-param-minsize": "Ogranicz do obrazków, mających co najmniej taką liczbę bajtów.",
        "apihelp-query+allimages-param-maxsize": "Ogranicz do obrazków, mających co najwyżej taką liczbę bajtów.",
-       "apihelp-query+allimages-example-B": "Pokaz listę plików rozpoczynających się na literę <kbd>B</kbd>.",
+       "apihelp-query+allimages-example-b": "Pokaz listę plików rozpoczynających się na literę <kbd>B</kbd>.",
        "apihelp-query+allimages-example-recent": "Pokaż listę ostatnio przesłanych plików, podobnie do [[Special:NewFiles]].",
        "apihelp-query+allimages-example-mimetypes": "Pokaż listę plików z typem MIME <kbd>image/png</kbd> lub <kbd>image/gif</kbd>",
        "apihelp-query+allimages-example-generator": "Pokaż informacje o 4 plikach rozpoczynających się na literę <kbd>T</kbd>.",
        "apihelp-query+allpages-param-maxsize": "Ogranicz do stron, mających co najwyżej taką liczbę bajtów.",
        "apihelp-query+allpages-param-prtype": "Ogranicz tylko do zabezpieczonych stron.",
        "apihelp-query+allpages-param-limit": "Liczba stron do zwrócenia.",
-       "apihelp-query+allpages-example-B": "Pokaż listę stron rozpoczynających się na literę <kbd>B</kbd>.",
+       "apihelp-query+allpages-example-b": "Pokaż listę stron rozpoczynających się na literę <kbd>B</kbd>.",
        "apihelp-query+allpages-example-generator": "Pokaż informacje o 4 stronach rozpoczynających się na literę <kbd>T</kbd>.",
        "apihelp-query+allpages-example-generator-revisions": "Pokaż zawartość pierwszych dwóch nieprzekierowujących stron, zaczynających się na <kbd>Re</kbd>.",
        "apihelp-query+allredirects-summary": "Lista wszystkich przekierowań do przestrzeni nazw.",
        "apihelp-query+allusers-param-limit": "Łączna liczba nazw użytkowników do zwrócenia.",
        "apihelp-query+allusers-param-witheditsonly": "Tylko użytkownicy, którzy edytowali.",
        "apihelp-query+allusers-param-activeusers": "Wyświetl tylko użytkowników, aktywnych w ciągu {{PLURAL:$1|ostatniego dnia|ostatnich $1 dni}}.",
-       "apihelp-query+allusers-example-Y": "Wyświetl użytkowników zaczynających się na <kbd>Y</kbd>.",
+       "apihelp-query+allusers-example-y": "Wyświetl użytkowników zaczynających się na <kbd>Y</kbd>.",
        "apihelp-query+backlinks-summary": "Znajdź wszystkie strony, które linkują do danej strony.",
        "apihelp-query+backlinks-param-title": "Tytuł strony do wyszukania. Nie może być użyty równocześnie z <var>$1pageid</var>.",
        "apihelp-query+backlinks-param-namespace": "Przestrzeń nazw, z której wymieniać.",
        "apiwarn-tokennotallowed": "Działanie „$1” jest niedozwolone dla bieżącego użytkownika.",
        "apiwarn-validationfailed-keytoolong": "klucz zbyt długi (dozwolone nie więcej niż $1 bajtów).",
        "apiwarn-validationfailed": "Błąd walidacji dla <kbd>$1</kbd>: $2",
-       "apiwarn-wgDebugAPI": "<strong>Ostrzeżenie o zabezpieczeniach</strong>: włączone jest <var>$wgDebugAPI</var>.",
+       "apiwarn-wgdebugapi": "<strong>Ostrzeżenie o zabezpieczeniach</strong>: włączone jest <var>$wgDebugAPI</var>.",
        "api-feed-error-title": "Błąd ($1)",
        "api-exception-trace": "$1 w $2($3)\n$4",
        "api-credits-header": "Twórcy",
index 4b0f603..e44a577 100644 (file)
        "apihelp-edit-param-text": "Conteúdo da página.",
        "apihelp-edit-param-summary": "Edit o resumo. Também o título da seção quando $1section=new e $1sectiontitle não está definido.",
        "apihelp-edit-param-tags": "Alterar as tags para aplicar à revisão.",
-       "apihelp-edit-param-minor": "Edição menor.",
-       "apihelp-edit-param-notminor": "Edição não-menor.",
+       "apihelp-edit-param-minor": "Marque esta edição como uma edição menor.",
+       "apihelp-edit-param-notminor": "Não marque esta edição como uma edição menor, mesmo se a preferência do usuário \"{{int:tog-minordefault}}\" é definida.",
        "apihelp-edit-param-bot": "Marcar esta edição como uma edição de bot.",
        "apihelp-edit-param-basetimestamp": "Timestamp da revisão base, usada para detectar conflitos de edição. Pode ser obtido através de [[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]].",
        "apihelp-edit-param-starttimestamp": "Timestamp quando o processo de edição começou, usado para detectar conflitos de edição. Um valor apropriado pode ser obtido usando <var>[[Special:ApiHelp/main|curtimestamp]]</var> ao iniciar o processo de edição (por exemplo, ao carregar o conteúdo da página a editar).",
        "apihelp-login-param-password": "Senha.",
        "apihelp-login-param-domain": "Domínio (opcional).",
        "apihelp-login-param-token": "Token de login obtido no primeiro pedido.",
-       "apihelp-login-example-gettoken": "Recupere um token de login.",
        "apihelp-login-example-login": "Entrar.",
        "apihelp-logout-summary": "Faça o logout e limpe os dados da sessão.",
        "apihelp-logout-example-logout": "Finaliza a sessão do usuário atual.",
        "apihelp-parse-paramvalue-prop-revid": "Adiciona o ID da revisão da página analisada.",
        "apihelp-parse-paramvalue-prop-displaytitle": "Adiciona o título do texto wiki analisado.",
        "apihelp-parse-paramvalue-prop-headitems": "Fornece itens para colocar no <code>&lt;head&gt;</code> da página.",
-       "apihelp-parse-paramvalue-prop-headhtml": "Fornece <code>&lt;head&gt;</code> analisado da página.",
+       "apihelp-parse-paramvalue-prop-headhtml": "Fornece o tipo analisado do documento, abrindo <code>&lt;html&gt;</code>, o elemento <code>&lt;head&gt;</code> e o <code>&lt;body&gt;</code> da página.",
        "apihelp-parse-paramvalue-prop-modules": "Fornece os módulos do ResourceLoader usados na página. Para carregar, use <code>mw.loader.using()</code>. Contudo, <kbd>jsconfigvars</kbd> ou <kbd>encodedjsconfigvars</kbd> deve ser solicitado conjuntamente com <kbd>modules</kbd>.",
        "apihelp-parse-paramvalue-prop-jsconfigvars": "Fornece as variáveis de configuração JavaScript específicas da página. Para aplicar, use <code>mw.config.set()</code>.",
        "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "Fornece as variáveis de configuração JavaScript específicas da página como uma string JSON.",
        "apihelp-query+allfileusages-paramvalue-prop-title": "Adiciona o título do arquivo.",
        "apihelp-query+allfileusages-param-limit": "Quantos itens retornar.",
        "apihelp-query+allfileusages-param-dir": "A direção na qual listar.",
-       "apihelp-query+allfileusages-example-B": "Listar títulos de arquivos, incluindo os que faltam, com IDs de página de que são, começando em <kbd>B</kbd>.",
+       "apihelp-query+allfileusages-example-b": "Listar títulos de arquivos, incluindo os que faltam, com IDs de página de que são, começando em <kbd>B</kbd>.",
        "apihelp-query+allfileusages-example-unique": "Listar títulos únicos de arquivos.",
        "apihelp-query+allfileusages-example-unique-generator": "Obtém todos os títulos de arquivo, marcando os que faltam.",
        "apihelp-query+allfileusages-example-generator": "Obter as páginas contendo os arquivos.",
        "apihelp-query+allimages-param-filterbots": "Como filtrar arquivos enviados por bots. Só pode ser usado com $1sort=timestamp. Não pode ser usado em conjunto com $1user.",
        "apihelp-query+allimages-param-mime": "Quais tipos MIME pesquisar, por exemplo: <kbd>image/jpeg</kbd>.",
        "apihelp-query+allimages-param-limit": "Quantas imagens retornar.",
-       "apihelp-query+allimages-example-B": "Mostra uma lista de arquivos começando com a letra <kbd>B</kbd>.",
+       "apihelp-query+allimages-example-b": "Mostra uma lista de arquivos começando com a letra <kbd>B</kbd>.",
        "apihelp-query+allimages-example-recent": "Mostra uma lista de arquivos recentemente enviados, semelhante a [[Special:NewFiles]].",
        "apihelp-query+allimages-example-mimetypes": "Mostra uma lista de arquivos com o tipo MIME <kbd>image/png</kbd> ou <kbd>image/gif</kbd>",
        "apihelp-query+allimages-example-generator": "Mostra informações sobre 4 arquivos começando com a letra <kbd>T</kbd>.",
        "apihelp-query+alllinks-param-namespace": "O espaço nominal a se enumerar.",
        "apihelp-query+alllinks-param-limit": "Quantos itens retornar.",
        "apihelp-query+alllinks-param-dir": "A direção na qual listar.",
-       "apihelp-query+alllinks-example-B": "Listar títulos vinculados, incluindo os que faltam, com IDs de página de que são, começando em <kbd>B</kbd>.",
+       "apihelp-query+alllinks-example-b": "Listar títulos vinculados, incluindo os que faltam, com IDs de página de que são, começando em <kbd>B</kbd>.",
        "apihelp-query+alllinks-example-unique": "Lista de títulos vinculados exclusivos.",
        "apihelp-query+alllinks-example-unique-generator": "Obtém todos os títulos vinculados, marcando as que faltam.",
        "apihelp-query+alllinks-example-generator": "Obter páginas contendo os links.",
        "apihelp-query+allpages-param-dir": "A direção na qual listar.",
        "apihelp-query+allpages-param-filterlanglinks": "Filtrar com base em se uma página tem lingulinks. Observe que isso pode não considerar os langlinks adicionados por extensões.",
        "apihelp-query+allpages-param-prexpiry": "Qual proteção expira para filtrar a página em:\n;indefinite: Obtém apenas páginas com expiração de proteção indefinida.\n;definite: Obtém apenas páginas com uma expiração de proteção definida (específica).\n;all: Obtém páginas com qualquer validade de proteção.",
-       "apihelp-query+allpages-example-B": "Mostrar uma lista de páginas a partir da letra <kbd>B</kbd>.",
+       "apihelp-query+allpages-example-b": "Mostrar uma lista de páginas a partir da letra <kbd>B</kbd>.",
        "apihelp-query+allpages-example-generator": "Mostre informações sobre 4 páginas começando na letra <kbd>T</kbd>.",
        "apihelp-query+allpages-example-generator-revisions": "Mostre o conteúdo das primeiras 2 páginas não redirecionadas que começam em <kbd>Re</kbd>.",
        "apihelp-query+allredirects-summary": "Lista todos os redirecionamentos para um espaço nominal.",
        "apihelp-query+allredirects-param-namespace": "O espaço nominal a se enumerar.",
        "apihelp-query+allredirects-param-limit": "Quantos itens retornar.",
        "apihelp-query+allredirects-param-dir": "A direção na qual listar.",
-       "apihelp-query+allredirects-example-B": "Lista de páginas de destino, incluindo as que faltam, com IDs de página de que são, começando em <kbd>B</kbd>.",
+       "apihelp-query+allredirects-example-b": "Lista de páginas de destino, incluindo as que faltam, com IDs de página de que são, começando em <kbd>B</kbd>.",
        "apihelp-query+allredirects-example-unique": "Listar páginas de destino únicas.",
        "apihelp-query+allredirects-example-unique-generator": "Obtém todas as páginas alvo, marcando as que faltam.",
        "apihelp-query+allredirects-example-generator": "Obtém páginas contendo os redirecionamentos.",
        "apihelp-query+alltransclusions-param-namespace": "O espaço nominal a se enumerar.",
        "apihelp-query+alltransclusions-param-limit": "Quantos itens retornar.",
        "apihelp-query+alltransclusions-param-dir": "A direção na qual listar.",
-       "apihelp-query+alltransclusions-example-B": "Lista de títulos transcluídos, incluindo os que faltam, com IDs de página de onde são, começando em <kbd>B</kbd>.",
+       "apihelp-query+alltransclusions-example-b": "Lista de títulos transcluídos, incluindo os que faltam, com IDs de página de onde são, começando em <kbd>B</kbd>.",
        "apihelp-query+alltransclusions-example-unique": "Listar títulos translúcidos exclusivos.",
        "apihelp-query+alltransclusions-example-unique-generator": "Obtém todas as páginas transcluídas, marcando as que faltam.",
        "apihelp-query+alltransclusions-example-generator": "Obtém páginas contendo as transclusões.",
        "apihelp-query+allusers-param-witheditsonly": "Apenas lista os usuários que fizeram edições.",
        "apihelp-query+allusers-param-activeusers": "Apenas lista os usuários ativos no último $1 {{PLURAL:$1|dia|dias}}.",
        "apihelp-query+allusers-param-attachedwiki": "Com <kbd>$1prop=centralids</kbd>, também indica se o usuário está conectado com a wiki identificado por este ID.",
-       "apihelp-query+allusers-example-Y": "Listar usuários começando em <kbd>Y</kbd>.",
+       "apihelp-query+allusers-example-y": "Listar usuários começando em <kbd>Y</kbd>.",
        "apihelp-query+authmanagerinfo-summary": "Recupere informações sobre o status de autenticação atual.",
        "apihelp-query+authmanagerinfo-param-securitysensitiveoperation": "Teste se o status de autenticação atual do usuário é suficiente para a operação específica de segurança especificada.",
        "apihelp-query+authmanagerinfo-param-requestsfor": "Obtenha informações sobre os pedidos de autenticação necessários para a ação de autenticação especificada.",
        "apihelp-query+userinfo-paramvalue-prop-registrationdate": "Adiciona a data de registro do usuário.",
        "apihelp-query+userinfo-paramvalue-prop-unreadcount": "Adiciona a contagem de páginas não lidas na lista de páginas vigiadas do usuário (máximo $1; retorna <samp>$2</samp> se mais).",
        "apihelp-query+userinfo-paramvalue-prop-centralids": "Adiciona os IDs centrais e o status do anexo do usuário.",
+       "apihelp-query+userinfo-paramvalue-prop-latestcontrib": "Adiciona a data da última contribuição do usuário.",
        "apihelp-query+userinfo-param-attachedwiki": "Com <kbd>$1prop=centralids</kbd>, indique se o usuário está conectado com a wiki identificada por este ID.",
        "apihelp-query+userinfo-example-simple": "Ober informações sobre o usuário atual.",
        "apihelp-query+userinfo-example-data": "Obter informações adicionais sobre o usuário atual.",
        "apiwarn-validationfailed-cannotset": "não pode ser configurado por este módulo.",
        "apiwarn-validationfailed-keytoolong": "chave muito longa (não é permitido mais de $1 bytes).",
        "apiwarn-validationfailed": "Erro de validação para <kbd>$1</kbd>: $2",
-       "apiwarn-wgDebugAPI": "<strong>Aviso de Segurança</strong>: <var>$wgDebugAPI</var> está ativado.",
+       "apiwarn-wgdebugapi": "<strong>Aviso de Segurança</strong>: <var>$wgDebugAPI</var> está ativado.",
        "api-feed-error-title": "Erro ($1)",
        "api-usage-docref": "Veja $1 para uso da API.",
        "api-usage-mailinglist-ref": "Inscreva-se na lista de discussão mediawiki-api-announce em &lt;https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce&gt; Para aviso de depreciações de API e alterações.",
index fc38b40..8eb0d0f 100644 (file)
        "apihelp-edit-param-text": "Conteúdo da página.",
        "apihelp-edit-param-summary": "Resumo da edição. Também é o título da secção quando $1section=new e $1sectiontitle não está definido.",
        "apihelp-edit-param-tags": "Etiquetas de modificação a aplicar à revisão.",
-       "apihelp-edit-param-minor": "Edição menor.",
-       "apihelp-edit-param-notminor": "Edição não menor.",
+       "apihelp-edit-param-minor": "Marcar esta edição como menor.",
+       "apihelp-edit-param-notminor": "Não marcar esta edição como uma edição menor, mesmo se a preferência \"{{int:tog-minordefault}}\" do utilizador estiver definida.",
        "apihelp-edit-param-bot": "Marcar esta edição como edição de robô.",
        "apihelp-edit-param-basetimestamp": "Data e hora da revisão de base, usada para detetar conflitos de edição. Pode ser obtida usando [[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]].",
        "apihelp-edit-param-starttimestamp": "Data e hora de início do processo de edição, usada para detetar conflitos de edição. Pode-se obter um valor apropriado usando <var>[[Special:ApiHelp/main|curtimestamp]]</var> ao iniciar o processo de edição (por exemplo, ao carregar o conteúdo da página para edição).",
        "apihelp-login-param-password": "Palavra-passe.",
        "apihelp-login-param-domain": "Domínio (opcional).",
        "apihelp-login-param-token": "Chave de início de sessão obtida no primeiro pedido.",
-       "apihelp-login-example-gettoken": "Obter uma chave de início de sessão.",
        "apihelp-login-example-login": "Entrar.",
        "apihelp-logout-summary": "Terminar a sessão e limpar os dados da sessão.",
        "apihelp-logout-example-logout": "Terminar a sessão do utilizador atual.",
        "apihelp-parse-paramvalue-prop-revid": "Adiciona o identificador de revisão da página analisada.",
        "apihelp-parse-paramvalue-prop-displaytitle": "Adiciona o título do texto wiki analisado.",
        "apihelp-parse-paramvalue-prop-headitems": "Fornece os elementos a colocar no <code>&lt;head&gt;</code> da página.",
-       "apihelp-parse-paramvalue-prop-headhtml": "Fornece o <code>&lt;head&gt;</code> analisado da página.",
+       "apihelp-parse-paramvalue-prop-headhtml": "Fornece o tipo analisado do documento, abrindo <code>&lt;html&gt;</code>, o elemento <code>&lt;head&gt;</code> e o <code>&lt;body&gt;</code> da página.",
        "apihelp-parse-paramvalue-prop-modules": "Fornece os módulos ResourceLoader usados na página. Para carregá-los, usar <code>mw.loader.using()</code>. Uma das variáveis <kbd>jsconfigvars</kbd> ou <kbd>encodedjsconfigvars</kbd> tem de ser pedida em conjunto com <kbd>modules</kbd>.",
        "apihelp-parse-paramvalue-prop-jsconfigvars": "Fornece as variáveis de configuração JavaScript específicas da página. Para aplicá-las, usar <code>mw.config.set()</code>.",
        "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "Fornece as variáveis de configuração JavaScript específicas da página, no formato de uma ''string'' JSON.",
        "apihelp-query+allfileusages-paramvalue-prop-title": "Adiciona o título do ficheiro.",
        "apihelp-query+allfileusages-param-limit": "O número total de elementos a serem devolvidos.",
        "apihelp-query+allfileusages-param-dir": "A direção de listagem.",
-       "apihelp-query+allfileusages-example-B": "Listar os títulos de ficheiros, incluindo aqueles em falta, com os identificadores das páginas de onde provêm, começando no <kbd>B</kbd>.",
+       "apihelp-query+allfileusages-example-b": "Listar os títulos de ficheiros, incluindo aqueles em falta, com os identificadores das páginas de onde provêm, começando no <kbd>B</kbd>.",
        "apihelp-query+allfileusages-example-unique": "Listar os títulos de ficheiro únicos.",
        "apihelp-query+allfileusages-example-unique-generator": "Obtém todos os títulos de ficheiros, marcando aqueles em falta.",
        "apihelp-query+allfileusages-example-generator": "Obtém as páginas que contêm os ficheiros.",
        "apihelp-query+allimages-param-filterbots": "Como filtrar os ficheiros carregados por robôs. Só pode ser usado com $1sort=timestamp. Não pode ser usado em conjunto com $1user.",
        "apihelp-query+allimages-param-mime": "Tipos MIME a procurar; por exemplo, <kbd>image/jpeg</kbd>.",
        "apihelp-query+allimages-param-limit": "O número total de imagens a serem devolvidas.",
-       "apihelp-query+allimages-example-B": "Mostrar uma lista dos ficheiros que começam com a letra <kbd>B</kbd>.",
+       "apihelp-query+allimages-example-b": "Mostrar uma lista dos ficheiros que começam com a letra <kbd>B</kbd>.",
        "apihelp-query+allimages-example-recent": "Mostrar uma lista dos ficheiros carregados recentemente, semelhante a [[Special:NewFiles]].",
        "apihelp-query+allimages-example-mimetypes": "Mostrar uma lista dos ficheiros com os tipos MIME <kbd>image/png</kbd> ou <kbd>image/gif</kbd>.",
        "apihelp-query+allimages-example-generator": "Mostrar informação sobre 4 ficheiros, começando pela letra <kbd>T</kbd>.",
        "apihelp-query+alllinks-param-namespace": "O espaço nominal a ser enumerado.",
        "apihelp-query+alllinks-param-limit": "O número total de entradas a serem devolvidas.",
        "apihelp-query+alllinks-param-dir": "A direção de listagem.",
-       "apihelp-query+alllinks-example-B": "Listar os títulos para os quais existem ligações, incluindo títulos em falta, com os identificadores das páginas que contêm as respetivas ligações, começando pela letra <kbd>B</kbd>.",
+       "apihelp-query+alllinks-example-b": "Listar os títulos para os quais existem ligações, incluindo títulos em falta, com os identificadores das páginas que contêm as respetivas ligações, começando pela letra <kbd>B</kbd>.",
        "apihelp-query+alllinks-example-unique": "Listar os títulos únicos para os quais existem hiperligações.",
        "apihelp-query+alllinks-example-unique-generator": "Obtém todos os títulos para os quais existem hiperligações, marcando aqueles em falta.",
        "apihelp-query+alllinks-example-generator": "Obtém as páginas que contêm as hiperligações.",
        "apihelp-query+allpages-param-dir": "A direção de listagem.",
        "apihelp-query+allpages-param-filterlanglinks": "Filtrar dependo de uma página conter hiperligações interlínguas. Note que isto pode não ter em consideração hiperligações interlínguas adicionadas por extensões.",
        "apihelp-query+allpages-param-prexpiry": "O tipo de expiração pelo qual as páginas serão filtradas:\n;indefinite:Obter só páginas com um período de expiração indefinido.\n;definite:Obter só páginas com um período de expiração definido (específico).\n;all:Obter páginas com qualquer período de expiração.",
-       "apihelp-query+allpages-example-B": "Mostrar uma lista de páginas, começando na letra <kbd>B</kbd>.",
+       "apihelp-query+allpages-example-b": "Mostrar uma lista de páginas, começando na letra <kbd>B</kbd>.",
        "apihelp-query+allpages-example-generator": "Mostrar informação sobre 4 páginas, começando na letra <kbd>T</kbd>.",
        "apihelp-query+allpages-example-generator-revisions": "Mostrar o conteúdo das primeiras 2 páginas que não sejam redirecionamentos, começando na página <kbd>Re</kbd>.",
        "apihelp-query+allredirects-summary": "Listar todos os redirecionamentos para um espaço nominal.",
        "apihelp-query+allredirects-param-namespace": "O espaço nominal a ser enumerado.",
        "apihelp-query+allredirects-param-limit": "O número total de elementos a serem devolvidos.",
        "apihelp-query+allredirects-param-dir": "A direção de listagem.",
-       "apihelp-query+allredirects-example-B": "Listar as páginas de destino, incluindo aquelas em falta, com os identificadores da página de origem, começando na <kbd>B</kbd>.",
+       "apihelp-query+allredirects-example-b": "Listar as páginas de destino, incluindo aquelas em falta, com os identificadores da página de origem, começando na <kbd>B</kbd>.",
        "apihelp-query+allredirects-example-unique": "Listar as páginas de destino únicas.",
        "apihelp-query+allredirects-example-unique-generator": "Obtém todas as páginas de destino, marcando aquelas em falta.",
        "apihelp-query+allredirects-example-generator": "Obtém as páginas que contêm os redirecionamentos.",
        "apihelp-query+alltransclusions-param-namespace": "O espaço nominal a enumerar.",
        "apihelp-query+alltransclusions-param-limit": "O número total de elementos a serem devolvidos.",
        "apihelp-query+alltransclusions-param-dir": "A direção de listagem.",
-       "apihelp-query+alltransclusions-example-B": "Listar os títulos transcluídos, incluindo aqueles em falta, com os identificadores das páginas de origem, começando no <kbd>B</kbd>.",
+       "apihelp-query+alltransclusions-example-b": "Listar os títulos transcluídos, incluindo aqueles em falta, com os identificadores das páginas de origem, começando no <kbd>B</kbd>.",
        "apihelp-query+alltransclusions-example-unique": "Listar os títulos transcluídos únicos.",
        "apihelp-query+alltransclusions-example-unique-generator": "Obtém todos os títulos transcluídos, marcando aqueles em falta.",
        "apihelp-query+alltransclusions-example-generator": "Obtém as páginas que contêm as transclusões.",
        "apihelp-query+allusers-param-witheditsonly": "Listar só os utilizadores que realizaram edições.",
        "apihelp-query+allusers-param-activeusers": "Listar só os utilizadores ativos {{PLURAL:$1|no último dia|nos últimos $1 dias}}.",
        "apihelp-query+allusers-param-attachedwiki": "Com <kbd>$1prop=centralids</kbd>, indicar também se o utilizador tem ligação com a wiki designada por este identificador.",
-       "apihelp-query+allusers-example-Y": "Listar utilizadores, começando pelo <kbd>Y</kbd>.",
+       "apihelp-query+allusers-example-y": "Listar utilizadores, começando pelo <kbd>Y</kbd>.",
        "apihelp-query+authmanagerinfo-summary": "Obter informação sobre o atual estado de autenticação.",
        "apihelp-query+authmanagerinfo-param-securitysensitiveoperation": "Testar se o estado atual de autenticação do utilizador é suficiente para a operação especificada, que exige condições seguras.",
        "apihelp-query+authmanagerinfo-param-requestsfor": "Obter informação sobre os pedidos de autenticação que são necessários para a operação de autenticação especificada.",
        "apihelp-query+deletedrevs-param-tag": "Listar só as revisões marcadas com esta etiqueta.",
        "apihelp-query+deletedrevs-param-user": "Listar só as revisões deste utilizador.",
        "apihelp-query+deletedrevs-param-excludeuser": "Não listar edições deste utilizador.",
-       "apihelp-query+deletedrevs-param-namespace": "Listar só as páginas neste domínio.",
+       "apihelp-query+deletedrevs-param-namespace": "Listar só as páginas deste espaço nominal/domínio.",
        "apihelp-query+deletedrevs-param-limit": "O número máximo de revisões a serem listadas.",
        "apihelp-query+deletedrevs-param-prop": "As propriedades a serem obtidas:\n;revid:Adiciona o identificador da revisão eliminada.\n;parentid:Adiciona o identificador da revisão anterior da página.\n;user:Adiciona o utilizador que fez a revisão.\n;userid:Adiciona o identificador do utilizador que fez a revisão.\n;comment:Adiciona o comentário da revisão.\n;parsedcomment:Adiciona o comentário da revisão após passagem pelo analisador sintático.\n;minor:Etiqueta a revisão como uma revisão menor.\n;len:Adiciona o comprimento (em bytes) da revisão.\n;sha1:Adiciona o SHA-1 da revisão (na base 16).\n;content:Adiciona o conteúdo da revisão.\n;token:<span class=\"apihelp-deprecated\">Obsoleto.</span> Fornece a chave da edição.\n;tags:Etiquetas da revisão.",
        "apihelp-query+deletedrevs-example-mode1": "Listar só as últimas revisões eliminadas das páginas <kbd>Main Page</kbd> e <kbd>Talk:Main Page</kbd>, com o conteúdo (modo 1).",
        "apihelp-query+userinfo-paramvalue-prop-registrationdate": "Adiciona a data de registo do utilizador.",
        "apihelp-query+userinfo-paramvalue-prop-unreadcount": "Adiciona a contagem de páginas não lidas da lista de páginas vigiadas do utilizador (máximo $1; devolve <samp>$2</samp> se forem mais).",
        "apihelp-query+userinfo-paramvalue-prop-centralids": "Adiciona os identificadores centrais e o estado de ligação central (''attachment'') do utilizador.",
+       "apihelp-query+userinfo-paramvalue-prop-latestcontrib": "Adiciona a data da última contribuição do utilizador.",
        "apihelp-query+userinfo-param-attachedwiki": "Com <kbd>$1prop=centralids</kbd>, indicar se o utilizador tem ligação com a wiki designada por este identificador.",
        "apihelp-query+userinfo-example-simple": "Obter informações sobre o utilizador atual.",
        "apihelp-query+userinfo-example-data": "Obter informações adicionais sobre o utilizador atual.",
        "apiwarn-validationfailed-cannotset": "não pode ser definido por este módulo.",
        "apiwarn-validationfailed-keytoolong": "chave demasiado longa (não pode ter mais de $1 bytes).",
        "apiwarn-validationfailed": "Erro de validação de <kbd>$1</kbd>: $2",
-       "apiwarn-wgDebugAPI": "<strong>Aviso de segurança</strong>: <var>$wgDebugAPI</var> está ativado.",
+       "apiwarn-wgdebugapi": "<strong>Aviso de segurança</strong>: <var>$wgDebugAPI</var> está ativado.",
        "api-feed-error-title": "Erro ($1)",
        "api-usage-docref": "Consulte $1 para a utilização da API.",
        "api-usage-mailinglist-ref": "Subscreva a lista de distribuição mediawiki-api-announce em &lt;https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce&gt; para receber anúncios de descontinuação e de alterações disruptivas da API.",
index 9abcfe2..d1dcfe9 100644 (file)
@@ -13,7 +13,8 @@
                        "Siebrand",
                        "Purodha",
                        "Tacsipacsi",
-                       "D41D8CD98F"
+                       "D41D8CD98F",
+                       "Zoranzoki21"
                ]
        },
        "apihelp-main-summary": "{{doc-apihelp-summary|main}}",
        "apihelp-login-param-password": "{{doc-apihelp-param|login|password}}\n{{Identical|Password}}",
        "apihelp-login-param-domain": "{{doc-apihelp-param|login|domain}}",
        "apihelp-login-param-token": "{{doc-apihelp-param|login|token}}",
-       "apihelp-login-example-gettoken": "{{doc-apihelp-example|login}}",
        "apihelp-login-example-login": "{{doc-apihelp-example|login}}\n{{Identical|Log in}}",
        "apihelp-logout-summary": "{{doc-apihelp-summary|logout}}",
        "apihelp-logout-example-logout": "{{doc-apihelp-example|logout}}",
        "apihelp-query+allfileusages-paramvalue-prop-title": "{{doc-apihelp-paramvalue|query+allfileusages|prop|title}}",
        "apihelp-query+allfileusages-param-limit": "{{doc-apihelp-param|query+allfileusages|limit}}",
        "apihelp-query+allfileusages-param-dir": "{{doc-apihelp-param|query+allfileusages|dir}}",
-       "apihelp-query+allfileusages-example-B": "{{doc-apihelp-example|query+allfileusages}}",
+       "apihelp-query+allfileusages-example-b": "{{doc-apihelp-example|query+allfileusages}}",
        "apihelp-query+allfileusages-example-unique": "{{doc-apihelp-example|query+allfileusages}}",
        "apihelp-query+allfileusages-example-unique-generator": "{{doc-apihelp-example|query+allfileusages}}",
        "apihelp-query+allfileusages-example-generator": "{{doc-apihelp-example|query+allfileusages}}",
        "apihelp-query+allimages-param-filterbots": "{{doc-apihelp-param|query+allimages|filterbots}}",
        "apihelp-query+allimages-param-mime": "{{doc-apihelp-param|query+allimages|mime}}",
        "apihelp-query+allimages-param-limit": "{{doc-apihelp-param|query+allimages|limit}}",
-       "apihelp-query+allimages-example-B": "{{doc-apihelp-example|query+allimages}}",
+       "apihelp-query+allimages-example-b": "{{doc-apihelp-example|query+allimages}}",
        "apihelp-query+allimages-example-recent": "{{doc-apihelp-example|query+allimages}}",
        "apihelp-query+allimages-example-mimetypes": "{{doc-apihelp-example|query+allimages}}",
        "apihelp-query+allimages-example-generator": "{{doc-apihelp-example|query+allimages}}",
        "apihelp-query+alllinks-param-namespace": "{{doc-apihelp-param|query+alllinks|namespace}}",
        "apihelp-query+alllinks-param-limit": "{{doc-apihelp-param|query+alllinks|limit}}",
        "apihelp-query+alllinks-param-dir": "{{doc-apihelp-param|query+alllinks|dir}}",
-       "apihelp-query+alllinks-example-B": "{{doc-apihelp-example|query+alllinks}}",
+       "apihelp-query+alllinks-example-b": "{{doc-apihelp-example|query+alllinks}}",
        "apihelp-query+alllinks-example-unique": "{{doc-apihelp-example|query+alllinks}}",
        "apihelp-query+alllinks-example-unique-generator": "{{doc-apihelp-example|query+alllinks}}",
        "apihelp-query+alllinks-example-generator": "{{doc-apihelp-example|query+alllinks}}",
        "apihelp-query+allpages-param-dir": "{{doc-apihelp-param|query+allpages|dir}}",
        "apihelp-query+allpages-param-filterlanglinks": "{{doc-apihelp-param|query+allpages|filterlanglinks}}",
        "apihelp-query+allpages-param-prexpiry": "{{doc-apihelp-param|query+allpages|prexpiry}}",
-       "apihelp-query+allpages-example-B": "{{doc-apihelp-example|query+allpages}}",
+       "apihelp-query+allpages-example-b": "{{doc-apihelp-example|query+allpages}}",
        "apihelp-query+allpages-example-generator": "{{doc-apihelp-example|query+allpages}}",
        "apihelp-query+allpages-example-generator-revisions": "{{doc-apihelp-example|query+allpages}}",
        "apihelp-query+allredirects-summary": "{{doc-apihelp-summary|query+allredirects}}",
        "apihelp-query+allredirects-param-namespace": "{{doc-apihelp-param|query+allredirects|namespace}}",
        "apihelp-query+allredirects-param-limit": "{{doc-apihelp-param|query+allredirects|limit}}",
        "apihelp-query+allredirects-param-dir": "{{doc-apihelp-param|query+allredirects|dir}}",
-       "apihelp-query+allredirects-example-B": "{{doc-apihelp-example|query+allredirects}}",
+       "apihelp-query+allredirects-example-b": "{{doc-apihelp-example|query+allredirects}}",
        "apihelp-query+allredirects-example-unique": "{{doc-apihelp-example|query+allredirects}}",
        "apihelp-query+allredirects-example-unique-generator": "{{doc-apihelp-example|query+allredirects}}",
        "apihelp-query+allredirects-example-generator": "{{doc-apihelp-example|query+allredirects}}",
        "apihelp-query+alltransclusions-param-namespace": "{{doc-apihelp-param|query+alltransclusions|namespace}}",
        "apihelp-query+alltransclusions-param-limit": "{{doc-apihelp-param|query+alltransclusions|limit}}",
        "apihelp-query+alltransclusions-param-dir": "{{doc-apihelp-param|query+alltransclusions|dir}}",
-       "apihelp-query+alltransclusions-example-B": "{{doc-apihelp-example|query+alltransclusions}}",
+       "apihelp-query+alltransclusions-example-b": "{{doc-apihelp-example|query+alltransclusions}}",
        "apihelp-query+alltransclusions-example-unique": "{{doc-apihelp-example|query+alltransclusions}}",
        "apihelp-query+alltransclusions-example-unique-generator": "{{doc-apihelp-example|query+alltransclusions}}",
        "apihelp-query+alltransclusions-example-generator": "{{doc-apihelp-example|query+alltransclusions}}",
        "apihelp-query+allusers-param-witheditsonly": "{{doc-apihelp-param|query+allusers|witheditsonly}}",
        "apihelp-query+allusers-param-activeusers": "{{doc-apihelp-param|query+allusers|activeusers|params=* $1 - Value of [[mw:Manual:$wgActiveUserDays]]|paramstart=2}}",
        "apihelp-query+allusers-param-attachedwiki": "{{doc-apihelp-param|query+allusers|attachedwiki}}",
-       "apihelp-query+allusers-example-Y": "{{doc-apihelp-example|query+allusers}}",
+       "apihelp-query+allusers-example-y": "{{doc-apihelp-example|query+allusers}}",
        "apihelp-query+authmanagerinfo-summary": "{{doc-apihelp-summary|query+authmanagerinfo}}",
        "apihelp-query+authmanagerinfo-param-securitysensitiveoperation": "{{doc-apihelp-param|query+authmanagerinfo|securitysensitiveoperation}}",
        "apihelp-query+authmanagerinfo-param-requestsfor": "{{doc-apihelp-param|query+authmanagerinfo|requestsfor}}",
        "apihelp-query+userinfo-paramvalue-prop-registrationdate": "{{doc-apihelp-paramvalue|query+userinfo|prop|registrationdate}}",
        "apihelp-query+userinfo-paramvalue-prop-unreadcount": "{{doc-apihelp-paramvalue|query+userinfo|prop|unreadcount|params=* $1 - Maximum value for the \"unreadcount\" property.\n* $2 - Return value when there are more unread pages.|paramstart=3}}",
        "apihelp-query+userinfo-paramvalue-prop-centralids": "{{doc-apihelp-paramvalue|query+userinfo|prop|centralids}}",
+       "apihelp-query+userinfo-paramvalue-prop-latestcontrib": "{{doc-apihelp-paramvalue|query+userinfo|prop|latestcontrib}}",
        "apihelp-query+userinfo-param-attachedwiki": "{{doc-apihelp-param|query+userinfo|attachedwiki}}",
        "apihelp-query+userinfo-example-simple": "{{doc-apihelp-example|query+userinfo}}",
        "apihelp-query+userinfo-example-data": "{{doc-apihelp-example|query+userinfo}}",
        "apierror-unknownaction": "{{doc-apierror}}\n\nParameters:\n* $1 - Action provided.",
        "apierror-unknownerror-editpage": "{{doc-apierror}}\n\nParameters:\n* $1 - Error code (an integer).",
        "apierror-unknownerror-nocode": "{{doc-apierror}}",
-       "apierror-unknownerror": "{{doc-apierror}}\n\nParameters:\n* $1 - Error code (possibly a message key) not handled by ApiBase::parseMsg().",
+       "apierror-unknownerror": "{{doc-apierror}}\n\nParameters:\n* $1 - Error code (possibly a message key) not handled by an error handler.",
        "apierror-unknownformat": "{{doc-apierror}}\n\nParameters:\n* $1 - Format provided.",
        "apierror-unrecognizedparams": "{{doc-apierror}}\n\nParameters:\n* $1 - List of parameters.\n* $2 - Number of parameters.",
        "apierror-unrecognizedvalue": "{{doc-apierror}}\n\nParameters:\n* $1 - Parameter name.\n* $2 - Parameter value.",
        "apiwarn-validationfailed-cannotset": "{{doc-apierror}}\n\nUsed with {{msg-mw|apiwarn-validationfailed}}.",
        "apiwarn-validationfailed-keytoolong": "{{doc-apierror}}\n\nUsed with {{msg-mw|apiwarn-validationfailed}}.\n\nParameters:\n* $1 - Maximum allowed key length in bytes.",
        "apiwarn-validationfailed": "{{doc-apierror}}\n\nParameters:\n* $1 - User preference name.\n* $2 - Failure message, such as {{msg-mw|apiwarn-validationfailed-badpref}}. Probably already ends with punctuation",
-       "apiwarn-wgDebugAPI": "{{doc-apierror}}",
+       "apiwarn-wgdebugapi": "{{doc-apierror}}",
        "api-feed-error-title": "Used as a feed item title when an error occurs in <kbd>action=feedwatchlist</kbd>.\n\nParameters:\n* $1 - API error code\n{{Identical|Error}}",
        "api-usage-docref": "\n\nParameters:\n* $1 - URL of the API auto-generated documentation.",
        "api-usage-mailinglist-ref": "{{doc-apierror}} Also used in the error response.",
index 1b30d00..599cbb8 100644 (file)
@@ -35,7 +35,9 @@
                        "Movses",
                        "Stjn",
                        "Edward Chernenko",
-                       "Vlad5250"
+                       "Vlad5250",
+                       "Diralik",
+                       "DmitTrix"
                ]
        },
        "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|Документация]]\n* [[mw:Special:MyLanguage/API:FAQ|ЧаВО]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Почтовая рассылка]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Новости API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Ошибки и запросы]\n</div>\n<strong>Статус:</strong> MediaWiki API — зрелый и стабильный интерфейс, активно поддерживаемый и улучшаемый. Мы стараемся избегать ломающих изменений, однако изредка они могут быть необходимы. Подпишитесь на [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ почтовую рассылку mediawiki-api-announce], чтобы быть в курсе обновлений.\n\n<strong>Ошибочные запросы:</strong> Если API получает запрос с ошибкой, вернётся заголовок HTTP с ключом «MediaWiki-API-Error», после чего значение заголовка и код ошибки будут отправлены обратно и установлены в то же значение. Более подробную информацию см. [[mw:Special:MyLanguage/API:Errors_and_warnings|API: Ошибки и предупреждения]].\n\n<p class=\"mw-apisandbox-link\"><strong>Тестирование:</strong> для удобства тестирования API-запросов, см. [[Special:ApiSandbox]].</p>",
@@ -69,6 +71,9 @@
        "apihelp-block-param-reblock": "Если участник уже заблокирован, перезаписать существующую блокировку.",
        "apihelp-block-param-watchuser": "Следить за страницей участника и соответствующей страницей обсуждения, принадлежащей участнику или IP-адресу.",
        "apihelp-block-param-tags": "Изменить метки записи в журнале блокировок.",
+       "apihelp-block-param-partial": "Блокировать пользователю доступ только к определённым страницам или пространствам имён, а не ко всему сайту.",
+       "apihelp-block-param-pagerestrictions": "Список заголовков страниц, редактирование которых заблокировано для этого участника. Действителен, только если <var>partial</var> установлен в true.",
+       "apihelp-block-param-namespacerestrictions": "Список пространств имён, редактирование в которых заблокировано для этого участника. Действителен, только если <var>partial</var> установлен в true.",
        "apihelp-block-example-ip-simple": "Заблокировать IP-адрес <kbd>192.0.2.5</kbd> на три дня по причине <kbd>First strike</kbd>.",
        "apihelp-block-example-user-complex": "Бессрочно заблокировать участника <kbd>Vandal</kbd> по причине <kbd>Vandalism</kbd> и предотвратить создание новых аккаунтов и отправку электронной почты.",
        "apihelp-changeauthenticationdata-summary": "Смена параметров аутентификации для текущего участника.",
@@ -88,7 +93,7 @@
        "apihelp-compare-param-fromtitle": "Заголовок первой сравниваемой страницы.",
        "apihelp-compare-param-fromid": "Идентификатор первой сравниваемой страницы.",
        "apihelp-compare-param-fromrev": "Первая сравниваемая версия.",
-       "apihelp-compare-param-frompst": "Выполнить преобразование перед записью правки (PST) над <var>fromtext</var>.",
+       "apihelp-compare-param-frompst": "Выполнить преобразование перед записью правки (PST) над <var>fromtext-&#x7B;slot}</var>.",
        "apihelp-compare-param-fromtext": "Используйте этот текст вместо содержимого версии, заданной <var>fromtitle</var>, <var>fromid</var> или <var>fromrev</var>.",
        "apihelp-compare-param-fromcontentmodel": "Модель содержимого <var>fromtext</var>. Если не задана, будет угадана по другим параметрам.",
        "apihelp-compare-param-fromcontentformat": "Формат сериализации содержимого <var>fromtext</var>.",
        "apihelp-edit-param-text": "Содержимое страницы.",
        "apihelp-edit-param-summary": "Описание изменений. Также является заголовком раздела, когда используется $1section=new, а $1sectiontitle не задано.",
        "apihelp-edit-param-tags": "Изменить метки записи в истории изменений.",
-       "apihelp-edit-param-minor": "Ð\9cалаÑ\8f Ð¿Ñ\80авка.",
-       "apihelp-edit-param-notminor": "Ð\9dе Ð¼Ð°Ð»Ð°Ñ\8f Ð¿Ñ\80авка.",
+       "apihelp-edit-param-minor": "Ð\9fомеÑ\82иÑ\82Ñ\8c Ñ\8dÑ\82Ñ\83 Ð¿Ñ\80авкÑ\83 ÐºÐ°Ðº Ð¼Ð°Ð»Ð¾Ðµ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ðµ.",
+       "apihelp-edit-param-notminor": "Ð\9dе Ð¿Ð¾Ð¼ÐµÑ\87аÑ\82Ñ\8c Ñ\8dÑ\82Ñ\83 Ð¿Ñ\80авкÑ\83 ÐºÐ°Ðº Ð¼Ð°Ð»Ð¾Ðµ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ðµ Ð´Ð°Ð¶Ðµ ÐµÑ\81Ñ\82Ñ\8c Ñ\83Ñ\81Ñ\82ановлена Ð¿Ð¾Ð»Ñ\8cзоваÑ\82елÑ\8cÑ\81каÑ\8f Ð½Ð°Ñ\81Ñ\82Ñ\80ойка Â«{{int:tog-minordefault}}».",
        "apihelp-edit-param-bot": "Пометить правку как сделанную ботом.",
        "apihelp-edit-param-basetimestamp": "Метка времени редактируемой версии, используется для обнаружения конфликтов редактирования. Может быть получена посредством [[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]].",
        "apihelp-edit-param-starttimestamp": "Метка времени начала редактирования, используется для обнаружения конфликтов редактирования. Необходимое значение может быть получено с помощью <var>[[Special:ApiHelp/main|curtimestamp]]</var> в начале редактирования (то есть, после загрузки содержимого редактируемой страницы).",
        "apihelp-login-param-password": "Пароль.",
        "apihelp-login-param-domain": "Домен (необязательно).",
        "apihelp-login-param-token": "Токен входа, полученный при первом запросе.",
-       "apihelp-login-example-gettoken": "Получить токен входа.",
        "apihelp-login-example-login": "Войти.",
        "apihelp-logout-summary": "Выйти и очистить данные сессии.",
        "apihelp-logout-example-logout": "Выйти из текущей учётной записи.",
        "apihelp-purge-param-forcelinkupdate": "Обновить таблицы ссылок.",
        "apihelp-purge-param-forcerecursivelinkupdate": "Обновить таблицу ссылок для данной страницы, а также всех страниц, использующих данную как шаблон.",
        "apihelp-purge-example-simple": "Очистить кэш для страниц <kbd>Main Page</kbd> и <kbd>API</kbd>.",
-       "apihelp-purge-example-generator": "Очистить кэш первых 10 страниц в основном пространстве имен.",
+       "apihelp-purge-example-generator": "Очистить кэш первых 10 страниц в основном пространстве имён.",
        "apihelp-query-summary": "Запросить данные с и о MediaWiki.",
        "apihelp-query-extended-description": "Все модификации данных сначала должны запросить соответствующий токен для предотвращения злоупотреблений с вредоносных сайтов.",
        "apihelp-query-param-prop": "Какие использовать свойства для запрашиваемых страниц.",
        "apihelp-query+allfileusages-paramvalue-prop-title": "Добавляет название файла.",
        "apihelp-query+allfileusages-param-limit": "Сколько элементов вернуть.",
        "apihelp-query+allfileusages-param-dir": "Порядок перечисления.",
-       "apihelp-query+allfileusages-example-B": "Список названий файлов, включая несуществующих, с идентификаторами использующих их страниц, начиная с <kbd>B</kbd>.",
+       "apihelp-query+allfileusages-example-b": "Список названий файлов, включая несуществующих, с идентификаторами использующих их страниц, начиная с <kbd>B</kbd>.",
        "apihelp-query+allfileusages-example-unique": "Список уникальных названий файлов.",
        "apihelp-query+allfileusages-example-unique-generator": "Список всех названий файлов с отметкой несуществующих.",
        "apihelp-query+allfileusages-example-generator": "Список страниц, содержащих файлы.",
        "apihelp-query+allimages-param-filterbots": "Как отфильтровывать файлы, загруженные ботами. Может быть использовано только одновременно с $1sort=timestamp и не может одновременно с $1user.",
        "apihelp-query+allimages-param-mime": "Какие типы MIME искать, например, <kbd>image/jpeg</kbd>.",
        "apihelp-query+allimages-param-limit": "Сколько изображений вернуть.",
-       "apihelp-query+allimages-example-B": "Показать список файлов, начиная с буквы <kbd>B</kbd>.",
+       "apihelp-query+allimages-example-b": "Показать список файлов, начиная с буквы <kbd>B</kbd>.",
        "apihelp-query+allimages-example-recent": "Показать список недавно загруженных файлов, аналогично [[Special:NewFiles]].",
        "apihelp-query+allimages-example-mimetypes": "Показать список файлов с MIME-типом <kbd>image/png</kbd> или <kbd>image/gif</kbd>.",
        "apihelp-query+allimages-example-generator": "Показать информацию о 4 файлах, начиная с буквы <kbd>T</kbd>.",
        "apihelp-query+alllinks-param-namespace": "Пространство имён для перечисления.",
        "apihelp-query+alllinks-param-limit": "Сколько элементов вернуть.",
        "apihelp-query+alllinks-param-dir": "Порядок перечисления.",
-       "apihelp-query+alllinks-example-B": "Список заголовков ссылаемых страниц, включая несуществующих, с идентификаторами страниц, ссылающихся на них, начиная с <kbd>B</kbd>.",
+       "apihelp-query+alllinks-example-b": "Список заголовков ссылаемых страниц, включая несуществующих, с идентификаторами страниц, ссылающихся на них, начиная с <kbd>B</kbd>.",
        "apihelp-query+alllinks-example-unique": "Список уникальных названий ссылаемых страниц.",
        "apihelp-query+alllinks-example-unique-generator": "Список всех ссылаемых страниц с отметкой несуществующих.",
        "apihelp-query+alllinks-example-generator": "Список страниц, содержащих ссылки.",
        "apihelp-query+allpages-param-dir": "Порядок перечисления.",
        "apihelp-query+allpages-param-filterlanglinks": "Отфильтровывать страницы, основываясь на наличие на странице языковых ссылок. Обратите внимание: языковые ссылки, добавленные расширениями, могут не учитываться.",
        "apihelp-query+allpages-param-prexpiry": "Отфильтровывать страницы, основываясь на длительности защиты:\n;indefinite: Получить только страницы с неограниченной защитой.\n;definite: Получить только страницы с заданной длительностью защиты.\n;all: Получить страницы с любой длительностью защиты.",
-       "apihelp-query+allpages-example-B": "Показать список страниц, начиная с буквы <kbd>B</kbd>.",
+       "apihelp-query+allpages-example-b": "Показать список страниц, начиная с буквы <kbd>B</kbd>.",
        "apihelp-query+allpages-example-generator": "Получить информацию о четырёх страницах, начиная с буквы <kbd>T</kbd>.",
        "apihelp-query+allpages-example-generator-revisions": "Показать содержимое первых двух страниц, не являющихся перенаправлениями, начиная с <kbd>Re</kbd>.",
        "apihelp-query+allredirects-summary": "Перечисление всех перенаправлений на заданное пространство имён.",
        "apihelp-query+allredirects-param-namespace": "Пространство имён для перечисления.",
        "apihelp-query+allredirects-param-limit": "Сколько элементов вернуть.",
        "apihelp-query+allredirects-param-dir": "Порядок перечисления.",
-       "apihelp-query+allredirects-example-B": "Список целевых страниц, в включая несуществующих, с идентификаторами перенаправлений, начиная с буквы <kbd>B</kbd>.",
+       "apihelp-query+allredirects-example-b": "Список целевых страниц, в включая несуществующих, с идентификаторами перенаправлений, начиная с буквы <kbd>B</kbd>.",
        "apihelp-query+allredirects-example-unique": "Список уникальных целевых страниц.",
        "apihelp-query+allredirects-example-unique-generator": "Список всех целевых страниц с отметкой несуществующих.",
        "apihelp-query+allredirects-example-generator": "Список страниц, содержащих перенаправления.",
        "apihelp-query+alltransclusions-param-namespace": "Пространство имён для перечисления.",
        "apihelp-query+alltransclusions-param-limit": "Сколько элементов вернуть.",
        "apihelp-query+alltransclusions-param-dir": "Порядок перечисления.",
-       "apihelp-query+alltransclusions-example-B": "Списки заголовков включаемых страниц, в том числе несуществующих, с идентификаторами включающих их страниц, начиная с буквы <kbd>B</kbd>.",
+       "apihelp-query+alltransclusions-example-b": "Списки заголовков включаемых страниц, в том числе несуществующих, с идентификаторами включающих их страниц, начиная с буквы <kbd>B</kbd>.",
        "apihelp-query+alltransclusions-example-unique": "Список уникальных включаемых названий.",
        "apihelp-query+alltransclusions-example-unique-generator": "Список всех включаемых страниц с отметкой несуществующих.",
        "apihelp-query+alltransclusions-example-generator": "Список страниц, содержащих включения.",
        "apihelp-query+allusers-param-witheditsonly": "Перечислять только участников, совершавших правки.",
        "apihelp-query+allusers-param-activeusers": "Перечислять только участников, которые были активны в последние $1 {{PLURAL:$1|день|дня|дней}}.",
        "apihelp-query+allusers-param-attachedwiki": "С <kbd>$1prop=centralids</kbd>, также отображает, прикреплён ли к вики участник с этим идентификатором.",
-       "apihelp-query+allusers-example-Y": "Список участников, начиная с <kbd>Y</kbd>.",
+       "apihelp-query+allusers-example-y": "Список участников, начиная с <kbd>Y</kbd>.",
        "apihelp-query+authmanagerinfo-summary": "Получение информации о текущем статусе аутентификации.",
        "apihelp-query+authmanagerinfo-param-securitysensitiveoperation": "Проверить, достаточен ли текущий статус для осуществления чувствительных к безопасности операций.",
        "apihelp-query+authmanagerinfo-param-requestsfor": "Получить информацию о аутентификационных запросах, необходимых для указанного действия аутентификации.",
        "apihelp-query+protectedtitles-paramvalue-prop-parsedcomment": "Добавляет распарсенное описание защиты.",
        "apihelp-query+protectedtitles-paramvalue-prop-expiry": "Добавляет метку времени снятия защиты.",
        "apihelp-query+protectedtitles-paramvalue-prop-level": "Добавляет уровень защиты.",
-       "apihelp-query+protectedtitles-example-simple": "Список защищенных заголовков",
+       "apihelp-query+protectedtitles-example-simple": "Список защищённых заголовков",
        "apihelp-query+protectedtitles-example-generator": "Поиск ссылок на защищённые заголовки в основном пространстве имён.",
        "apihelp-query+querypage-summary": "Получение списка, предоставляемого служебной страницей, основанной на QueryPage.",
        "apihelp-query+querypage-param-page": "Название служебной страницы. Обратите внимание: чувствительно к регистру.",
        "api-help-permissions-granted-to": "{{PLURAL:$1|Гарантируется}}: $2",
        "api-help-right-apihighlimits": "Использовать высокие лимиты в запросах API (медленные запросы: $1, быстрые запросы: $2). Лимиты для медленных запросов также применимы к параметрам со множеством значений.",
        "api-help-open-in-apisandbox": "<small>[открыть в песочнице]</small>",
-       "api-help-authmanager-general-usage": "СÑ\82андаÑ\80Ñ\82наÑ\8f Ð¿Ñ\80оÑ\86едÑ\83Ñ\80а Ð¸Ñ\81полÑ\8cзованиÑ\8f Ñ\8dÑ\82ого Ð¼Ð¾Ð´Ñ\83лÑ\8f Ñ\82акова:\n# Ð\97апÑ\80оÑ\81 Ð¿Ð¾Ð»ÐµÐ¹, Ð´Ð¾Ñ\81Ñ\82Ñ\83пнÑ\8bÑ\85 Ð¸Ð· <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> Ñ\81 <kbd>amirequestsfor=$4</kbd>, Ð¸ Ñ\82окена <kbd>$5</kbd> Ð¸Ð· <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.\n# Ð\9fÑ\80едоÑ\81Ñ\82авление Ð¿Ð¾Ð»ÐµÐ¹ Ð¿Ð¾Ð»Ñ\8cзоваÑ\82елÑ\8e Ð¸ Ð¿Ð¾Ð»Ñ\83Ñ\87ение ÐµÐ³Ð¾ Ð´Ð°Ð½Ð½Ñ\8bÑ\85.\n# Ð\97апÑ\80оÑ\81 Ðº Ñ\8dÑ\82омÑ\83 Ð¼Ð¾Ð´Ñ\83лÑ\8e, Ñ\81одеÑ\80жаÑ\89ий <var>$1returnurl</var> Ð¸Ð»Ð¸ Ð°Ð½Ð°Ð»Ð¾Ð³Ð¸Ñ\87ное Ð¿Ð¾Ð»Ðµ.\n# Ð\9fÑ\80овеÑ\80ка Ð¿Ð¾Ð»Ñ\8f <samp>status</samp> Ð¾Ñ\82веÑ\82а.\n#* Ð\95Ñ\81ли Ð²Ñ\8b Ð¿Ð¾Ð»Ñ\83Ñ\87или <samp>PASS</samp> Ð¸Ð»Ð¸ <samp>FAIL</samp>, Ð²Ñ\8b Ð·Ð°ÐºÐ¾Ð½Ñ\87или. Ð\9eпеÑ\80аÑ\86иÑ\8f Ð»Ð¸Ð±Ð¾ Ð·Ð°Ð²ÐµÑ\80Ñ\88илаÑ\81Ñ\8c Ñ\83Ñ\81пеÑ\85ом, Ð»Ð¸Ð±Ð¾ Ð½ÐµÑ\82.\n#* Ð\95Ñ\81ли Ð²Ñ\8b Ð¿Ð¾Ð»Ñ\83Ñ\87или <samp>UI</samp>, Ð¿Ñ\80едоÑ\81Ñ\82авÑ\8cÑ\82е Ð½Ð¾Ð²Ñ\8bе Ð¿Ð¾Ð»Ñ\8f Ð¿Ð¾Ð»Ñ\8cззоваÑ\82елÑ\8e Ð¸ Ð¿Ð¾Ð»Ñ\83Ñ\87иÑ\82е Ð½Ð¾Ð²Ñ\8bе Ð´Ð°Ð½Ð½Ñ\8bе. Ð\97аÑ\82ем Ñ\81овеÑ\80Ñ\88иÑ\82е Ð½Ð¾Ð²Ñ\8bй Ð·Ð°Ð¿Ñ\80оÑ\81 Ñ\81 Ð¿Ð°Ñ\80амеÑ\82Ñ\80ом <var>$1continue</var> Ð¸ Ð½Ð¾Ð²Ñ\8bми Ð¿Ð¾Ð»Ñ\8fми, Ð¿Ð¾Ñ\81ле Ñ\87его Ð¿Ð¾Ð²Ñ\82оÑ\80иÑ\82е Ð¿Ñ\83нкÑ\82 4.\n#* Ð\95Ñ\81ли Ð²Ñ\8b Ð¿Ð¾Ð»Ñ\83Ñ\87или <samp>REDIRECT</samp>, Ð¾Ñ\82пÑ\80авÑ\8cÑ\82е Ð¿Ð¾Ð»Ñ\8cзоваÑ\82елÑ\8f Ð½Ð° <samp>redirecttarget</samp> Ð¸ Ð¿Ð¾Ð´Ð¾Ð¶Ð´Ð¸Ñ\82е Ð²Ð¾Ð·Ð²Ñ\80аÑ\89ениÑ\8f Ð½Ð° <var>$1returnurl</var>. Ð\97аÑ\82ем Ñ\81овеÑ\80Ñ\88иÑ\82е Ð·Ð°Ð¿Ñ\80оÑ\81 Ðº Ñ\8dÑ\82омÑ\83 Ð¼Ð¾Ð´Ñ\83лÑ\8e Ñ\81 Ð¿Ð°Ñ\80амеÑ\82Ñ\80ом <var>$1continue</var> Ð¸ Ð²Ñ\81еми Ð¿Ð¾Ð»Ñ\8fми, Ñ\81одеÑ\80жаÑ\89имиÑ\81Ñ\8f Ð² Ð²Ð¾Ð·Ð²Ñ\80аÑ\89Ñ\91нной Ñ\81Ñ\81Ñ\8bлке, Ð¸ Ð¿Ð¾Ð²Ñ\82оÑ\80иÑ\82е Ð¿Ñ\83нкÑ\82 4.\n#* Ð\95Ñ\81ли Ð²Ñ\8b Ð¿Ð¾Ð»Ñ\83Ñ\87или <samp>RESTART</samp>, Ñ\8dÑ\82о Ð¾Ð·Ð½Ð°Ñ\87аеÑ\82, Ñ\87Ñ\82о Ð°Ñ\83Ñ\82енÑ\82иÑ\84икаÑ\86иÑ\8f Ñ\80абоÑ\82аеÑ\82, Ð½Ð¾ Ð¼Ñ\8b Ð½Ðµ Ð¿Ñ\80ивÑ\8fзали Ð¿Ð¾Ð»Ñ\8cзоваÑ\82елÑ\8cÑ\81кий Ð°ÐºÐºÐ°Ñ\83нÑ\82. Ð\92Ñ\8b Ð¼Ð¾Ð¶ÐµÑ\82е Ñ\80аÑ\81Ñ\81маÑ\82Ñ\80иваÑ\82Ñ\8c Ñ\8dÑ\82о ÐºÐ°Ðº <samp>UI</samp> Ð¸Ð»Ð¸ <samp>FAIL</samp>.",
+       "api-help-authmanager-general-usage": "Стандартная процедура использования этого модуля такова:\n# Запрос полей, доступных из <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> с <kbd>amirequestsfor=$4</kbd>, и токена <kbd>$5</kbd> из <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.\n# Предоставление полей пользователю и получение его данных.\n# Запрос к этому модулю, содержащий <var>$1returnurl</var> или аналогичное поле.\n# Проверка поля <samp>status</samp> ответа.\n#* Если вы получили <samp>PASS</samp> или <samp>FAIL</samp>, вы закончили. Операция либо завершилась успехом, либо нет.\n#* Если вы получили <samp>UI</samp>, предоставьте новые поля пользователю и получите новые данные. Затем совершите новый запрос с параметром <var>$1continue</var> и новыми полями, после чего повторите пункт 4.\n#* Если вы получили <samp>REDIRECT</samp>, отправьте пользователя на <samp>redirecttarget</samp> и подождите возвращения на <var>$1returnurl</var>. Затем совершите запрос к этому модулю с параметром <var>$1continue</var> и всеми полями, содержащимися в возвращённой ссылке, и повторите пункт 4.\n#* Если вы получили <samp>RESTART</samp>, это означает, что аутентификация работает, но мы не привязали пользовательский аккаунт. Вы можете рассматривать это как <samp>UI</samp> или <samp>FAIL</samp>.",
        "api-help-authmanagerhelper-requests": "Использовать только эти аутентификационные запросы, с <samp>id</samp>, возвращённом из <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> с <kbd>amirequestsfor=$1</kbd>, или из предыдущего ответа этого модуля.",
        "api-help-authmanagerhelper-request": "Использовать этот аутентификационный запрос, с <samp>id</samp>, возвращённом из <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> с <kbd>amirequestsfor=$1</kbd>.",
        "api-help-authmanagerhelper-messageformat": "Формат, используемый для возвращаемых сообщений.",
        "apierror-maxchars": "Параметр <var>$1</var> не может быть длиннее $2 {{PLURAL:$2|символа|символов}}",
        "apierror-maxlag-generic": "Ожидание сервера базы данных: $1 {{PLURAL:$1|секунда|секунды|секунд}} задержки.",
        "apierror-maxlag": "Ожидание $2: $1 {{PLURAL:$1|секунда|секунды|секунд}} задержки.",
-       "apierror-mimesearchdisabled": "Поиск по MIME отключен в жадном режиме.",
+       "apierror-mimesearchdisabled": "Поиск по MIME отключён в жадном режиме.",
        "apierror-missingcontent-pageid": "Отсутствует содержимое страницы с идентификатором $1.",
        "apierror-missingcontent-revid": "Отсутствует содержимое версии с идентификатором $1.",
        "apierror-missingparam-at-least-one-of": "{{PLURAL:$2|Параметр|Как минимум один из параметров}} $1 обязателен.",
        "apierror-permissiondenied-generic": "Доступ запрещён.",
        "apierror-permissiondenied-patrolflag": "Вам нужно право <code>patrol</code> или <code>patrolmarks</code> для запроса статуса патрулирования.",
        "apierror-permissiondenied-unblock": "У вас нет прав снимать блокировку с участников.",
-       "apierror-prefixsearchdisabled": "Поиск по префиксу отключен в жадном режиме.",
+       "apierror-prefixsearchdisabled": "Поиск по префиксу отключён в жадном режиме.",
        "apierror-promised-nonwrite-api": "Заголовок HTTP <code>Promise-Non-Write-API-Action</code> не может быть передан в записывающие модули API.",
        "apierror-protect-invalidaction": "Недопустимый тип защиты «$1».",
        "apierror-protect-invalidlevel": "Недопустимый уровень защиты «$1».",
        "apiwarn-compare-nocontentmodel": "Модель содержимого не может быть определена, предполагается $1.",
        "apiwarn-deprecation-deletedrevs": "<kbd>list=deletedrevs</kbd> устарел. Пожалуйста, вместо него используйте <kbd>prop=deletedrevisions</kbd> или <kbd>list=alldeletedrevisions</kbd>.",
        "apiwarn-deprecation-httpsexpected": "Использован HTTP, где ожидался HTTPS.",
-       "apiwarn-deprecation-login-botpw": "Вход в основной аккаунт через <kbd>action=login</kbd> устарел и может быть отключен без предупреждения. Для продолжения авторизации с <kbd>action=login</kbd>, см.\n[[Special:BotPasswords]]. Для безопасного продолжения использования входа в основной аккаунт, см. <kbd>action=clientlogin</kbd>.",
-       "apiwarn-deprecation-login-nobotpw": "Вход в основной аккаунт через <kbd>action=login</kbd> не поддерживается и может быть отключен без предупреждения. Для безопасной авторизации, см. <kbd>action=clientlogin</kbd>.",
+       "apiwarn-deprecation-login-botpw": "Вход в основной аккаунт через <kbd>action=login</kbd> устарел и может быть отключён без предупреждения. Для продолжения авторизации с <kbd>action=login</kbd>, см.\n[[Special:BotPasswords]]. Для безопасного продолжения использования входа в основной аккаунт, см. <kbd>action=clientlogin</kbd>.",
+       "apiwarn-deprecation-login-nobotpw": "Вход в основной аккаунт через <kbd>action=login</kbd> не поддерживается и может быть отключён без предупреждения. Для безопасной авторизации, см. <kbd>action=clientlogin</kbd>.",
        "apiwarn-deprecation-login-token": "Запрос токена через <kbd>action=login</kbd> устарел. Используйте <kbd>action=query&meta=tokens&type=login</kbd>.",
        "apiwarn-deprecation-parameter": "Параметр <var>$1</var> не поддерживается.",
        "apiwarn-deprecation-parse-headitems": "<kbd>prop=headitems</kbd> устарело с MediaWiki 1.28. Используйте <kbd>prop=headhtml</kbd> при создании новых HTML документов или <kbd>prop=modules|jsconfigvars</kbd> при обновлении документов на стороне клиента.",
        "apiwarn-validationfailed-cannotset": "не может быть задано этим модулем.",
        "apiwarn-validationfailed-keytoolong": "ключ слишком длинен (разрешено не более $1 {{PLURAL:$1|байт|байта|байт}}).",
        "apiwarn-validationfailed": "Ошибка проверки для <kbd>$1</kbd>: $2",
-       "apiwarn-wgDebugAPI": "<strong>Предупреждение безопасности</strong>: активирован <var>$wgDebugAPI</var>.",
+       "apiwarn-wgdebugapi": "<strong>Предупреждение безопасности</strong>: активирован <var>$wgDebugAPI</var>.",
        "api-feed-error-title": "Ошибка ($1)",
        "api-usage-docref": "См. $1 для использования API.",
        "api-usage-mailinglist-ref": "Подпишитесь на электронную рассылку MediaWiki API на &lt;https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce&gt;, чтобы получать информацию о неподдерживаемых функциях и ломающих изменениях.",
index df94ce2..75c41fc 100644 (file)
@@ -94,8 +94,8 @@
        "apihelp-edit-param-text": "Sidans innehåll.",
        "apihelp-edit-param-summary": "Redigeringssammanfattning. Även avsnittets rubrik när $1section=new och $1sectiontitle inte anges.",
        "apihelp-edit-param-tags": "Ändra taggar till att gälla för revideringen.",
-       "apihelp-edit-param-minor": "Mindre redigering.",
-       "apihelp-edit-param-notminor": "Icke-mindre redigering.",
+       "apihelp-edit-param-minor": "Markera denna redigering som en mindre redigering.",
+       "apihelp-edit-param-notminor": "Markera inte denna redigering som en mindre redigering även om användarinställningen \"{{int:tog-minordefault}}\" är inställd.",
        "apihelp-edit-param-bot": "Markera denna redigering som en robotredigering.",
        "apihelp-edit-param-basetimestamp": "Tidsstämpel för grundversionen, används för att upptäcka redigeringskonflikter. Kan erhållas genom [[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]].",
        "apihelp-edit-param-starttimestamp": "Tidsstämpel för när redigeringsprocessen började, används för att upptäcka redigeringskonflikter. Ett lämpligt värde kan erhållas via  <var>[[Special:ApiHelp/main|curtimestamp]]</var> när redigeringsprocessen startas (t.ex. när sidans innehåll laddas för redigering).",
        "apihelp-login-param-password": "Lösenord.",
        "apihelp-login-param-domain": "Domän (valfritt).",
        "apihelp-login-param-token": "Login nyckel erhållen i första begäran.",
-       "apihelp-login-example-gettoken": "Hämta en login nyckel.",
        "apihelp-login-example-login": "Logga in",
        "apihelp-logout-summary": "Logga ut och rensa sessionsdata.",
        "apihelp-logout-example-logout": "Logga ut den aktuella användaren",
        "apihelp-query+allimages-param-filterbots": "Hur man filtrerar filer uppladdade av bots. Kan enbart användas med $1sort=timestamp. Kan inte användas tillsammans med $1user.",
        "apihelp-query+allimages-param-mime": "Vilka MIME-typer du vill söka efter, t.ex. <kbd>image/jpeg</kbd>.",
        "apihelp-query+allimages-param-limit": "Hur många bilder att returnera totalt.",
-       "apihelp-query+allimages-example-B": "Visa en lista över filer som börjar på bokstaven <kbd>B</kbd>.",
+       "apihelp-query+allimages-example-b": "Visa en lista över filer som börjar på bokstaven <kbd>B</kbd>.",
        "apihelp-query+allimages-example-recent": "Visa en lista över nyligen överförda filer, ungefär som [[Special:Nya_filer]].",
        "apihelp-query+allimages-example-mimetypes": "Visa en lista över filer med MIME-typen <kbd>image/png</kbd> eller <kbd>image/gif</kbd>",
        "apihelp-query+allimages-example-generator": "Visa info om 4 filer som börjar med bokstaven <kbd>T</kbd>.",
        "apihelp-query+alllinks-param-prefix": "Sök alla länkade titlar som börjar med detta värde.",
        "apihelp-query+alllinks-param-limit": "Hur många saker att returnera totalt.",
        "apihelp-query+alllinks-param-dir": "Riktningen att lista mot.",
-       "apihelp-query+alllinks-example-B": "Lista länkade titlar, inkluderade saknade, med dem sid-IDs dem är från, med början vid <kbd>B</kbd>.",
+       "apihelp-query+alllinks-example-b": "Lista länkade titlar, inkluderade saknade, med dem sid-IDs dem är från, med början vid <kbd>B</kbd>.",
        "apihelp-query+alllinks-example-unique": "Lista unika länkade titlar.",
        "apihelp-query+alllinks-example-unique-generator": "Hämtar alla länkade titlar, markera de saknade.",
        "apihelp-query+alllinks-example-generator": "Hämtar sidor som innehåller länkarna.",
        "apihelp-query+allpages-param-prtype": "Begränsa till endast skyddade sidor.",
        "apihelp-query+allpages-param-limit": "Hur många sidor att returnera totalt.",
        "apihelp-query+allpages-param-dir": "Riktningen att lista mot.",
-       "apihelp-query+allpages-example-B": "Visa en lista över sidor som börjar på bokstaven <kbd>B</kbd>.",
+       "apihelp-query+allpages-example-b": "Visa en lista över sidor som börjar på bokstaven <kbd>B</kbd>.",
        "apihelp-query+allpages-example-generator": "Visa information om fyra sidor som börjar på bokstaven <kbd>T</kbd>.",
        "apihelp-query+allredirects-summary": "Lista alla omdirigeringar till en namnrymd.",
        "apihelp-query+allredirects-param-dir": "Riktningen att lista mot.",
        "apihelp-query+allusers-param-limit": "Hur många användarnamn att returnera totalt.",
        "apihelp-query+allusers-param-witheditsonly": "Lista bara användare som har gjort redigeringar.",
        "apihelp-query+allusers-param-activeusers": "Lista bara användare aktiva i dem sista $1{{PLURAL:$1|dagen|dagarna}}.",
-       "apihelp-query+allusers-example-Y": "Lista användare som börjar på <kbd>Y</kbd>.",
+       "apihelp-query+allusers-example-y": "Lista användare som börjar på <kbd>Y</kbd>.",
        "apihelp-query+authmanagerinfo-summary": "Hämta information om aktuell autentiseringsstatus.",
        "apihelp-query+backlinks-summary": "Hitta alla sidor som länkar till den givna sidan.",
        "apihelp-query+backlinks-param-dir": "Riktningen att lista mot.",
        "apihelp-query+usercontribs-summary": "Hämta alla redigeringar av en användare.",
        "apihelp-query+userinfo-summary": "Få information om den aktuella användaren.",
        "apihelp-query+userinfo-paramvalue-prop-preferencestoken": "Hämta en nyckel för att ändra aktuell användares inställningar.",
+       "apihelp-query+userinfo-paramvalue-prop-latestcontrib": "Lägg till datumet för användarens senaste bidrag.",
        "apihelp-query+userinfo-example-simple": "Få information om den aktuella användaren.",
        "apihelp-query+userinfo-example-data": "Få ytterligare information om den aktuella användaren.",
        "apihelp-query+users-summary": "Hämta information om en lista över användare.",
index 7bad7c0..3ca00ee 100644 (file)
        "apihelp-edit-param-text": "Вміст сторінки.",
        "apihelp-edit-param-summary": "Опис редагування. Також заголовок розділу, коли $1section=new і коли $1sectiontitle не вказано.",
        "apihelp-edit-param-tags": "Змінити теги для версії.",
-       "apihelp-edit-param-minor": "Ð\9dезнаÑ\87не Ñ\80едагÑ\83ваннÑ\8f.",
-       "apihelp-edit-param-notminor": "Не «незначне» редагування.",
+       "apihelp-edit-param-minor": "Ð\9fознаÑ\87иÑ\82и Ñ\86е Ñ\80едагÑ\83ваннÑ\8f Ñ\8fк Ð½ÐµÐ·Ð½Ð°Ñ\87не.",
+       "apihelp-edit-param-notminor": "Не позначати це редагування як незначне, навіть якщо стоїть налаштування користувача «{{int:tog-minordefault}}».",
        "apihelp-edit-param-bot": "Позначити редагування як зроблене ботом.",
        "apihelp-edit-param-basetimestamp": "Мітка часу для основної версії, використовується для виявлення конфлікту редагувань. Може бути отримана через [[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]].",
        "apihelp-edit-param-starttimestamp": "Мітка часу, з якого почався процес редагування, використовується для виявлення конфліктів редагувань. Відповідне значення можна отримати з допомогою <var>[[Special:ApiHelp/main|curtimestamp]]</var> на початку процесу редагування (напр., коли завантажується вміст сторінки для редагування).",
        "apihelp-login-param-password": "Пароль.",
        "apihelp-login-param-domain": "Домен (необов'язково).",
        "apihelp-login-param-token": "Токен входу в систему, отриманий у першому запиті.",
-       "apihelp-login-example-gettoken": "Отримати токен входу в систему.",
        "apihelp-login-example-login": "Увійти в систему.",
        "apihelp-logout-summary": "Вийти й очистити дані сесії.",
        "apihelp-logout-example-logout": "Вийти з поточного облікового запису.",
        "apihelp-parse-paramvalue-prop-revid": "Додає ідентифікатор версії аналізованої сторінки.",
        "apihelp-parse-paramvalue-prop-displaytitle": "Додає заголовок аналізованого вікітексту.",
        "apihelp-parse-paramvalue-prop-headitems": "Дає елементи для вставки в <code>&lt;head&gt;</code> сторінки.",
-       "apihelp-parse-paramvalue-prop-headhtml": "Дає проаналізований <code>&lt;head&gt;</code> сторінки.",
+       "apihelp-parse-paramvalue-prop-headhtml": "Дає проаналізований тип документа, початковий <code>&lt;html&gt;</code>, елемент <code>&lt;head&gt;</code> та початковий <code>&lt;body&gt;</code> сторінки.",
        "apihelp-parse-paramvalue-prop-modules": "Дає модулі ResourceLoader, використані на сторінці. Щоб завантажити, використовуйте <code>mw.loader.using()</code>. Чи <kbd>jsconfigvars</kbd>, чи <kbd>encodedjsconfigvars</kbd> має бути запитано разом з <kbd>modules</kbd>.",
        "apihelp-parse-paramvalue-prop-jsconfigvars": "Дає змінні конфігурації JavaScript, притаманні для сторінки. Щоб застосувати, використайте <code>mw.config.set()</code>.",
        "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "Дає змінні конфігурації JavaScript, притаманні для сторінки, як рядок JSON.",
        "apihelp-query+allfileusages-paramvalue-prop-title": "Додає назву файлу.",
        "apihelp-query+allfileusages-param-limit": "Скільки всього елементів виводити.",
        "apihelp-query+allfileusages-param-dir": "Напрямок, у якому перелічити.",
-       "apihelp-query+allfileusages-example-B": "Перерахувати назви файлів, включно з відсутніми, з ідентифікаторами сторінок, на яких вони використані, починаючи з <kbd>B</kbd>.",
+       "apihelp-query+allfileusages-example-b": "Перерахувати назви файлів, включно з відсутніми, з ідентифікаторами сторінок, на яких вони використані, починаючи з <kbd>B</kbd>.",
        "apihelp-query+allfileusages-example-unique": "Перерахувати унікальні назви файлів.",
        "apihelp-query+allfileusages-example-unique-generator": "Отримує всі назви файлів, позначаючи відсутні.",
        "apihelp-query+allfileusages-example-generator": "Отримує сторінки, на яких є файли.",
        "apihelp-query+allimages-param-filterbots": "Як фільтрувати файли, завантажені ботами. Можна використати лише з $1sort=timestamp. Не можна використати разом з $1user.",
        "apihelp-query+allimages-param-mime": "Які MIME-типи шукати, напр., <kbd>image/jpeg</kbd>.",
        "apihelp-query+allimages-param-limit": "Скільки всього зображень видати.",
-       "apihelp-query+allimages-example-B": "Показати список файлів, які починаються на літеру <kbd>B</kbd>.",
+       "apihelp-query+allimages-example-b": "Показати список файлів, які починаються на літеру <kbd>B</kbd>.",
        "apihelp-query+allimages-example-recent": "Показати список нещодавно завантажених файлів, подібно до [[Special:NewFiles]].",
        "apihelp-query+allimages-example-mimetypes": "Показати список файлів з MIME-типом <kbd>image/png</kbd> або <kbd>image/gif</kbd>",
        "apihelp-query+allimages-example-generator": "Показати інформацію про 4 файли, що починаються на літеру <kbd>T</kbd>.",
        "apihelp-query+alllinks-param-namespace": "Простір назв для переліку.",
        "apihelp-query+alllinks-param-limit": "Скільки всього елементів виводити.",
        "apihelp-query+alllinks-param-dir": "Напрямок, у якому перелічити.",
-       "apihelp-query+alllinks-example-B": "Перерахувати пов'язані назви, включно з відсутніми, з ідентифікаторами сторінок, на яких вони використані, починаючи з <kbd>B</kbd>.",
+       "apihelp-query+alllinks-example-b": "Перерахувати пов'язані назви, включно з відсутніми, з ідентифікаторами сторінок, на яких вони використані, починаючи з <kbd>B</kbd>.",
        "apihelp-query+alllinks-example-unique": "Перерахувати унікальні назви з посиланнями.",
        "apihelp-query+alllinks-example-unique-generator": "Отримує всі назви з посиланнями, позначаючи відсутні.",
        "apihelp-query+alllinks-example-generator": "Отримує сторінки, на яких є посилання.",
        "apihelp-query+allpages-param-dir": "Напрямок, у якому перелічити.",
        "apihelp-query+allpages-param-filterlanglinks": "Фільтрувати залежно від наявності у сторінки мовних посилань. Зауважте, що це може не врахувати мовні посилання, додані розширеннями.",
        "apihelp-query+allpages-param-prexpiry": "За якою тривалістю захисту фільтрувати сторінку:\n;indefinite:Отримати лише сторінки з нескінченним захистом.\n;definite:Отримати лише сторінки з визначеним терміном захисту.\n;all:Отримати сторінки з будь-яким терміном захисту.",
-       "apihelp-query+allpages-example-B": "Показати список сторінок, які починаються на літеру <kbd>B</kbd>.",
+       "apihelp-query+allpages-example-b": "Показати список сторінок, які починаються на літеру <kbd>B</kbd>.",
        "apihelp-query+allpages-example-generator": "Показати інформацію про 4 сторінки, що починаються на літеру <kbd>T</kbd>.",
        "apihelp-query+allpages-example-generator-revisions": "Показати вміст перших двох сторінок, що не є перенаправленнями і починаються на <kbd>Re</kbd>.",
        "apihelp-query+allredirects-summary": "Перерахувати усі перенаправлення на простір назв.",
        "apihelp-query+allredirects-param-namespace": "Простір назв для переліку.",
        "apihelp-query+allredirects-param-limit": "Скільки всього елементів виводити.",
        "apihelp-query+allredirects-param-dir": "Напрямок, у якому перелічити.",
-       "apihelp-query+allredirects-example-B": "Перерахувати цільові сторінки, включно з відсутніми, з ідентифікаторами сторінок, на яких вони використані, починаючи з <kbd>B</kbd>.",
+       "apihelp-query+allredirects-example-b": "Перерахувати цільові сторінки, включно з відсутніми, з ідентифікаторами сторінок, на яких вони використані, починаючи з <kbd>B</kbd>.",
        "apihelp-query+allredirects-example-unique": "Перерахувати унікальні цільові сторінки.",
        "apihelp-query+allredirects-example-unique-generator": "Отримує всі цільові сторінки, позначаючи відсутні.",
        "apihelp-query+allredirects-example-generator": "Отримує сторінки, які містять перенаправлення.",
        "apihelp-query+alltransclusions-param-namespace": "Простір назв для переліку.",
        "apihelp-query+alltransclusions-param-limit": "Скільки всього елементів виводити.",
        "apihelp-query+alltransclusions-param-dir": "Напрямок, у якому перелічити.",
-       "apihelp-query+alltransclusions-example-B": "Перерахувати включені назви, включно з відсутніми, з ідентифікаторами сторінок, на яких вони використані, починаючи з <kbd>B</kbd>.",
+       "apihelp-query+alltransclusions-example-b": "Перерахувати включені назви, включно з відсутніми, з ідентифікаторами сторінок, на яких вони використані, починаючи з <kbd>B</kbd>.",
        "apihelp-query+alltransclusions-example-unique": "Перерахувати унікальні включені назв.",
        "apihelp-query+alltransclusions-example-unique-generator": "Отримує всі включені назви, позначаючи відсутні.",
        "apihelp-query+alltransclusions-example-generator": "Отримує сторінки, на яких є включення.",
        "apihelp-query+allusers-param-witheditsonly": "Перерахувати лише користувачів, що зробили редагування.",
        "apihelp-query+allusers-param-activeusers": "Перерахувати лише користувачів, що були активні $1 {{PLURAL:$1|останній день|останні дні|останніх днів}}.",
        "apihelp-query+allusers-param-attachedwiki": "Із <kbd>$1prop=centralids</kbd>, також вказати, чи користувач має приєднану вікі, визначену цим ідентифікатором.",
-       "apihelp-query+allusers-example-Y": "Перерахувати користувачів, починаючи з <kbd>Y</kbd>.",
+       "apihelp-query+allusers-example-y": "Перерахувати користувачів, починаючи з <kbd>Y</kbd>.",
        "apihelp-query+authmanagerinfo-summary": "Отримати інформацію про поточний стан автентифікації.",
        "apihelp-query+authmanagerinfo-param-securitysensitiveoperation": "Перевірити, чи поточний стан автентифікації користувача є достатнім для даної конфіденційної операції.",
        "apihelp-query+authmanagerinfo-param-requestsfor": "Отримати інформацію про запити автентифікації, потрібні для даної дії автентифікації.",
        "apiwarn-validationfailed-cannotset": "не може бути встановлено цим модулем.",
        "apiwarn-validationfailed-keytoolong": "ключ надто довгий (дозволено не більш як $1 байтів).",
        "apiwarn-validationfailed": "Помилка перевірки для <kbd>$1</kbd>: $2",
-       "apiwarn-wgDebugAPI": "<strong>Попередження щодо безпеки</strong>: увімкнено <var>$wgDebugAPI</var>.",
+       "apiwarn-wgdebugapi": "<strong>Попередження щодо безпеки</strong>: увімкнено <var>$wgDebugAPI</var>.",
        "api-feed-error-title": "Помилка ($1)",
        "api-usage-docref": "Див. $1 щодо використання API.",
        "api-usage-mailinglist-ref": "Щоб взнавати про заплановані і остаточні критичні зміни API, підпишіться на розсилку mediawiki-api-announce тут: &lt;https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce&gt;.",
index 78f92f1..b174993 100644 (file)
@@ -26,7 +26,8 @@
                        "NeverBehave",
                        "Wbxshiori",
                        "Wxyveronica",
-                       "WhitePhosphorus"
+                       "WhitePhosphorus",
+                       "科劳"
                ]
        },
        "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|文档]]\n* [[mw:Special:MyLanguage/API:FAQ|常见问题]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api 邮件列表]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API公告]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R 程序错误与功能请求]\n</div>\n<strong>状态信息:</strong>MediaWiki API是一个成熟稳定的,不断受到支持和改进的界面。尽管我们尽力避免,但偶尔也需要作出重大更新;请订阅[https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ mediawiki-api-announce 邮件列表]以便获得更新通知。\n\n<strong>错误请求:</strong>当API收到错误请求时,HTTP header将会返回一个包含\"MediaWiki-API-Error\"的值,随后header的值与error code将会送回并设置为相同的值。详细信息请参阅[[mw:Special:MyLanguage/API:Errors_and_warnings|API:错误与警告]]。\n\n<p class=\"mw-apisandbox-link\"><strong>测试中:</strong>测试API请求的易用性,请参见[[Special:ApiSandbox]]。</p>",
        "apihelp-edit-param-text": "页面内容。",
        "apihelp-edit-param-summary": "编辑摘要。当$1section=new且未设置$1sectiontitle时,还包括小节标题。",
        "apihelp-edit-param-tags": "应用到此修订的更改标签。",
-       "apihelp-edit-param-minor": "å°\8fç¼\96è¾\91ã\80\82",
+       "apihelp-edit-param-minor": "å°\86此次ç¼\96è¾\91æ \87记为å°\8fç¼\96è¾\91",
        "apihelp-edit-param-notminor": "不是小编辑。",
        "apihelp-edit-param-bot": "标记此编辑为机器人编辑。",
        "apihelp-edit-param-basetimestamp": "基础修订的时间戳,用于检测编辑冲突。可以通过[[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]]得到。",
        "apihelp-login-param-password": "密码。",
        "apihelp-login-param-domain": "域名(可选)。",
        "apihelp-login-param-token": "在首个请求中获得的登录令牌。",
-       "apihelp-login-example-gettoken": "检索登录令牌。",
        "apihelp-login-example-login": "登录。",
        "apihelp-logout-summary": "退出并清除会话数据。",
        "apihelp-logout-example-logout": "退出当前用户。",
        "apihelp-query+allfileusages-paramvalue-prop-title": "添加文件的标题。",
        "apihelp-query+allfileusages-param-limit": "要返回的总计项目。",
        "apihelp-query+allfileusages-param-dir": "罗列所采用的方向。",
-       "apihelp-query+allfileusages-example-B": "列举文件标题,包含丢失的文件、它们来自的页面ID,以<kbd>B</kbd>开头。",
+       "apihelp-query+allfileusages-example-b": "列举文件标题,包含丢失的文件、它们来自的页面ID,以<kbd>B</kbd>开头。",
        "apihelp-query+allfileusages-example-unique": "列出唯一文件标题。",
        "apihelp-query+allfileusages-example-unique-generator": "获取所有文件标题,并标记出缺失者。",
        "apihelp-query+allfileusages-example-generator": "获取包含这些文件的页面。",
        "apihelp-query+allimages-param-filterbots": "如何过滤由机器人上传的文件。只能与$1sort=timestamp一起使用。不能与$1user一起使用。",
        "apihelp-query+allimages-param-mime": "要搜索的MIME类型,例如<kbd>image/jpeg</kbd>。",
        "apihelp-query+allimages-param-limit": "共计要返回多少图像。",
-       "apihelp-query+allimages-example-B": "显示以字母<kbd>B</kbd>开始的文件列表。",
+       "apihelp-query+allimages-example-b": "显示以字母<kbd>B</kbd>开始的文件列表。",
        "apihelp-query+allimages-example-recent": "显示一个最近上传文件的列表,类似[[Special:NewFiles]]。",
        "apihelp-query+allimages-example-mimetypes": "显示带MIME类型<kbd>image/png</kbd>或<kbd>image/gif</kbd>的文件列表",
        "apihelp-query+allimages-example-generator": "显示有关4个以<kbd>T</kbd>开头的文件的信息。",
        "apihelp-query+alllinks-param-namespace": "要列举的名字空间。",
        "apihelp-query+alllinks-param-limit": "总共要返回多少个项目。",
        "apihelp-query+alllinks-param-dir": "列出方向。",
-       "apihelp-query+alllinks-example-B": "列出链接的标题,包括丢失的,带它们来自的页面ID,以<kbd>B</kbd>开头。",
+       "apihelp-query+alllinks-example-b": "列出链接的标题,包括丢失的,带它们来自的页面ID,以<kbd>B</kbd>开头。",
        "apihelp-query+alllinks-example-unique": "列出唯一的链接标题。",
        "apihelp-query+alllinks-example-unique-generator": "获取所有已链接的标题,标记缺少的。",
        "apihelp-query+alllinks-example-generator": "获取包含这些链接的页面。",
        "apihelp-query+allpages-param-dir": "罗列所采用的方向。",
        "apihelp-query+allpages-param-filterlanglinks": "过滤基于页面是否有语言链接。注意这可能不考虑由扩展添加的语言链接。",
        "apihelp-query+allpages-param-prexpiry": "要在页面上过滤的保护期限:\n;indefinite:只获取带无限期保护的页面。\n;definite:只获取带指定保护期限的页面。\n;all:获取任意保护期限的页面。",
-       "apihelp-query+allpages-example-B": "显示以字母<kbd>B</kbd>开头的页面的列表。",
+       "apihelp-query+allpages-example-b": "显示以字母<kbd>B</kbd>开头的页面的列表。",
        "apihelp-query+allpages-example-generator": "显示有关4个以字母<kbd>T</kbd>开头的页面的信息。",
        "apihelp-query+allpages-example-generator-revisions": "显示前2个以<kbd>Re</kbd>开头的非重定向页面的内容。",
        "apihelp-query+allredirects-summary": "列出至一个名字空间的重定向。",
        "apihelp-query+allredirects-param-namespace": "要列举的名字空间。",
        "apihelp-query+allredirects-param-limit": "返回的总计项目数。",
        "apihelp-query+allredirects-param-dir": "罗列所采用的方向。",
-       "apihelp-query+allredirects-example-B": "列举目标页面,包含丢失的页面、它们来自的页面ID,以<kbd>B</kbd>开头。",
+       "apihelp-query+allredirects-example-b": "列举目标页面,包含丢失的页面、它们来自的页面ID,以<kbd>B</kbd>开头。",
        "apihelp-query+allredirects-example-unique": "列出孤立目标页面。",
        "apihelp-query+allredirects-example-unique-generator": "获取所有目标页面,标记丢失的。",
        "apihelp-query+allredirects-example-generator": "获取包含重定向的页面。",
        "apihelp-query+alltransclusions-param-namespace": "要列举的名字空间。",
        "apihelp-query+alltransclusions-param-limit": "要返回的总计项目。",
        "apihelp-query+alltransclusions-param-dir": "罗列所采用的方向。",
-       "apihelp-query+alltransclusions-example-B": "列出嵌入的标题,包括丢失的,带有来自的页面ID,从<kbd>B</kbd>开始。",
+       "apihelp-query+alltransclusions-example-b": "列出嵌入的标题,包括丢失的,带有来自的页面ID,从<kbd>B</kbd>开始。",
        "apihelp-query+alltransclusions-example-unique": "列出孤立嵌入标题",
        "apihelp-query+alltransclusions-example-unique-generator": "获取所有嵌入的标题,并标记缺失的。",
        "apihelp-query+alltransclusions-example-generator": "获得包含嵌入内容的页面。",
        "apihelp-query+allusers-param-witheditsonly": "只列出有编辑的用户。",
        "apihelp-query+allusers-param-activeusers": "只列出最近$1{{PLURAL:$1|天}}内活跃的用户。",
        "apihelp-query+allusers-param-attachedwiki": "与<kbd>$1prop=centralids</kbd>一起使用,也表明用户是否附加于此ID定义的wiki。",
-       "apihelp-query+allusers-example-Y": "列出以<kbd>Y</kbd>开头的用户。",
+       "apihelp-query+allusers-example-y": "列出以<kbd>Y</kbd>开头的用户。",
        "apihelp-query+authmanagerinfo-summary": "检索有关当前身份验证状态的信息。",
        "apihelp-query+authmanagerinfo-param-securitysensitiveoperation": "测试用户当前的身份验证状态是否足够用于指定的安全敏感操作。",
        "apihelp-query+authmanagerinfo-param-requestsfor": "取得指定身份验证操作所需的有关身份验证请求的信息。",
        "apihelp-query+categorymembers-paramvalue-prop-sortkeyprefix": "添加用于分类中排序的关键字前缀(关键字的人类可读部分)。",
        "apihelp-query+categorymembers-paramvalue-prop-type": "添加页面被分类的类型(<samp>page</samp>、<samp>subcat</samp>或<samp>file</samp>)。",
        "apihelp-query+categorymembers-paramvalue-prop-timestamp": "添加页面被包括时的时间戳。",
-       "apihelp-query+categorymembers-param-namespace": "仅包含这些名字空间的页面。注意<kbd>$1type=subcat</kbd>或<kbd>$1type=file</kbd>可能被使用,而不是<kbd>$1namespace=14</kbd>或<kbd>6</kbd>。",
+       "apihelp-query+categorymembers-param-namespace": "仅包含这些名字空间的页面。注意可使用<kbd>$1type=subcat</kbd>或<kbd>$1type=file</kbd>替代<kbd>$1namespace=14</kbd>或<kbd>6</kbd>。",
        "apihelp-query+categorymembers-param-type": "包含的分类成员类型。当<kbd>$1sort=timestamp</kbd>被设置时会忽略。",
        "apihelp-query+categorymembers-param-limit": "返回页面的最大数量。",
        "apihelp-query+categorymembers-param-sort": "要作为排序方式的属性。",
        "apiwarn-validationfailed-cannotset": "不能通过此模块设置。",
        "apiwarn-validationfailed-keytoolong": "关键词太长(不允许超过$1字节)。",
        "apiwarn-validationfailed": "<kbd>$1</kbd>的合法性错误:$2",
-       "apiwarn-wgDebugAPI": "<strong>安全警告</strong>:<var>$wgDebugAPI</var>已启用。",
+       "apiwarn-wgdebugapi": "<strong>安全警告</strong>:<var>$wgDebugAPI</var>已启用。",
        "api-feed-error-title": "错误($1)",
        "api-usage-docref": "参见$1以获取API用法。",
        "api-usage-mailinglist-ref": "在&lt;https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce&gt;订阅mediawiki-api-announce列表以获取API弃用和重大更新的通知。",
index 776c59a..a1d7cb9 100644 (file)
@@ -24,8 +24,8 @@
        "apihelp-main-param-action": "要執行的動作。",
        "apihelp-main-param-format": "輸出的格式。",
        "apihelp-main-param-maxlag": "最大延遲可在當 MediaWiki 安裝於資料庫複寫叢集時使用。為了保存引起更多站台複寫延遲的操作,此參數可讓客戶端等待至複寫延遲小於指定值為止。在過渡延遲的情況下,錯誤碼 <samp>maxlag</samp> 會帶有著像是 <samp>Waiting for $host: $lag seconds lagged</samp> 的訊息內容回傳。<br />請查看[[mw:Special:MyLanguage/Manual:Maxlag_parameter|手冊:Maxlag 參數]]來獲取更多資訊。",
-       "apihelp-main-param-smaxage": "將HTTP緩存控制頭欄位設為<code>s-maxage</code>秒。錯誤不會做緩存。",
-       "apihelp-main-param-maxage": "將HTTP緩存控制頭欄位設為<code>max-age</code>秒。錯誤不會做緩存。",
+       "apihelp-main-param-smaxage": "將HTTP暫存控制頭欄位設為<code>s-maxage</code>秒。錯誤不會做暫存。",
+       "apihelp-main-param-maxage": "將HTTP暫存控制頭欄位設為<code>max-age</code>秒。錯誤不會做暫存。",
        "apihelp-main-param-assert": "若設為<kbd>user</kbd>,會確認使用者是否已登入;若設為<kbd>bot</kbd>,會確認是否擁有機械人權限。",
        "apihelp-main-param-assertuser": "確認目前使用者就是指定的使用者。",
        "apihelp-main-param-requestid": "在此處提供的任何值都將包括在響應之中。可用於區分請求。",
@@ -55,7 +55,7 @@
        "apihelp-block-param-pagerestrictions": "封鎖使用者做出編輯的標題清單。僅在 <var>partial</var> 被設定為 true 時套用。",
        "apihelp-block-param-namespacerestrictions": "封鎖使用者做出編輯的命名空間 ID 清單。僅在 <var>partial</var> 被設定為 true 時套用。",
        "apihelp-block-example-ip-simple": "封鎖 IP 位址 <kbd>192.0.2.5</kbd> 三天,原因為 <kbd>First strike</kbd>。",
-       "apihelp-block-example-user-complex": "永久封鎖 IP 位址 <kbd>Vandal</kbd>,原因為 <kbd>Vandalism</kbd>。",
+       "apihelp-block-example-user-complex": "永久封鎖用戶 <kbd>Vandal</kbd>,原因為 <kbd>Vandalism</kbd>,並防止建立新帳號及發送電子郵件。",
        "apihelp-changeauthenticationdata-summary": "為目前使用者變更身分核對資料。",
        "apihelp-changeauthenticationdata-example-password": "嘗試更改目前使用者的密碼至 <kbd>ExamplePassword</kbd>。",
        "apihelp-checktoken-summary": "檢查來自 <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd> 的權杖有效性。",
        "apihelp-edit-param-text": "頁面內容。",
        "apihelp-edit-param-summary": "編輯摘要。 當未設定 $1section=new 與 $1sectiontitle 時也會當做章節標題。",
        "apihelp-edit-param-tags": "更改套用到修訂的標籤。",
-       "apihelp-edit-param-minor": "小編輯。",
-       "apihelp-edit-param-notminor": "非小編輯。",
+       "apihelp-edit-param-minor": "標記此編輯為小編輯。",
+       "apihelp-edit-param-notminor": "不要標記此編輯為小編輯,即使有設定到「{{int:tog-minordefault}}」使用者偏好設定。",
        "apihelp-edit-param-bot": "標記此編輯為機器人編輯。",
        "apihelp-edit-param-basetimestamp": "基於修訂的時間戳記,用來檢測編輯衝突。也许可以取得[[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]]認可。",
        "apihelp-edit-param-starttimestamp": "當編輯程序開始的時間戳記,用於偵測編輯衝突。當編輯程序開始時(例如:當載入要編輯的頁面內容),使用 <var>[[Special:ApiHelp/main|curtimestamp]]</var> 可以取得一個適當值。",
        "apihelp-login-param-password": "密碼。",
        "apihelp-login-param-domain": "網域名稱(可有可無)。",
        "apihelp-login-param-token": "在首次請求獲得的登入權杖。",
-       "apihelp-login-example-gettoken": "檢索登入權杖。",
        "apihelp-login-example-login": "登入",
        "apihelp-logout-summary": "登出並清除 session 資料。",
        "apihelp-logout-example-logout": "登出當前使用者",
        "apihelp-parse-paramvalue-prop-revid": "添加已解析頁面的修訂 ID。",
        "apihelp-parse-paramvalue-prop-displaytitle": "添加已解析 wiki 文字的標題。",
        "apihelp-parse-paramvalue-prop-headitems": "提供放置頁面裡的 <code>&lt;head&gt;</code> 之項目。",
-       "apihelp-parse-paramvalue-prop-headhtml": "取得頁面已解析的 <code>&lt;head&gt;</code>。",
+       "apihelp-parse-paramvalue-prop-headhtml": "給予頁面已解析的 doctype、開啟的 <code>&lt;html&gt;</code>、<code>&lt;head&gt;</code> 元素、以及開啟的 <code>&lt;body&gt;</code>。",
        "apihelp-parse-paramvalue-prop-modules": "在頁面提供使用的 ResourceLoader 模組。要載入請使用 <code>mw.loader.using()</code>。<kbd>jsconfigvars</kbd> 或 <kbd>encodedjsconfigvars</kbd> 其一必須與 <kbd>modules</kbd> 一同被請求。",
        "apihelp-parse-paramvalue-prop-jsconfigvars": "針對頁面提供指定的 JavaScript 設置變數。若要套用,請使用 <code>mw.config.set()</code>。",
        "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "指定頁面的 JavaScript 設置變量為 JSON 字串。",
        "apihelp-patrol-example-rcid": "巡查一次近期變更。",
        "apihelp-patrol-example-revid": "巡查一個修訂。",
        "apihelp-protect-summary": "變更頁面的保護層級。",
-       "apihelp-protect-param-title": "要(解除)保護頁面的標題。 不能與 $1pageid 一起使用。",
-       "apihelp-protect-param-pageid": "要(解除)保護頁面的 ID。 不能與 $1title 一起使用。",
-       "apihelp-protect-param-protections": "保護層級清單,格式為 <kbd>action=level</kbd> (例如 <kbd>edit=sysop</kbd>)。<kbd>all</kbd> 層級代表所有人都可以進行行動,亦即無限制。\n\n<strong>注意:</strong>未列入清單項目的限制皆會移除。",
+       "apihelp-protect-param-title": "要(解除)保護頁面的標題。 不能與 $1pageid 一起使用。",
+       "apihelp-protect-param-pageid": "要(解除)保護頁面的 ID。 不能與 $1title 一起使用。",
+       "apihelp-protect-param-protections": "保護層級清單,格式為 <kbd>action=level</kbd>(例如 <kbd>edit=sysop</kbd>)。<kbd>all</kbd> 層級代表所有人都可以進行行動,亦即無限制。\n\n<strong>注意:</strong>未列入清單項目的限制皆會移除。",
        "apihelp-protect-param-expiry": "期限時間戳記,若只設定一個時間戳記,該時間戳記將會套用至所有的保護層級。 使用 <kbd>infinite</kbd>、<kbd>indefinite</kbd>、<kbd>infinity</kbd> 或 <kbd>never</kbd> 來設定保護層級期限為永遠。",
-       "apihelp-protect-param-reason": "(解除)保護的原因。",
+       "apihelp-protect-param-reason": "(解除)保護的原因。",
        "apihelp-protect-param-tags": "修改標籤以套用於保護日誌裡的項目。",
        "apihelp-protect-param-cascade": "啟用連鎖保護(也就是保護包含於此頁面的頁面)。如果所有提供的保護等級不支援連鎖,就將其忽略。",
        "apihelp-protect-param-watch": "如果被設定,就將被(解除)保護的頁面加至目前使用者的監視列表。",
        "apihelp-query+allfileusages-paramvalue-prop-title": "添加檔案標題。",
        "apihelp-query+allfileusages-param-limit": "要回傳的項目總數。",
        "apihelp-query+allfileusages-param-dir": "列出時所採用的方向。",
-       "apihelp-query+allfileusages-example-B": "列出檔案標題,包含頁面 ID 以 <kbd>B</kbd> 為起始的遺失項目。",
+       "apihelp-query+allfileusages-example-b": "列出檔案標題,包含頁面 ID 以 <kbd>B</kbd> 為起始的遺失項目。",
        "apihelp-query+allfileusages-example-unique": "列出唯一的檔案標題。",
        "apihelp-query+allfileusages-example-unique-generator": "取得所有檔案標題,標記為遺失。",
        "apihelp-query+allfileusages-example-generator": "取得包含檔案的頁面。",
        "apihelp-query+allimages-param-filterbots": "如何篩選由機器人上傳的檔案。僅能與 $1sort=timestamp 一起使用,且不可與 $1user 一起使用。",
        "apihelp-query+allimages-param-mime": "所要搜尋的 MIME 類型,例如:<kbd>image/jpeg</kbd>。",
        "apihelp-query+allimages-param-limit": "要回傳的圖片總數。",
-       "apihelp-query+allimages-example-B": "搜尋以字母 <kbd>B</kbd> 為開頭的所有檔案清單。",
+       "apihelp-query+allimages-example-b": "搜尋以字母 <kbd>B</kbd> 為開頭的所有檔案清單。",
        "apihelp-query+allimages-example-recent": "顯示近期已上傳檔案的清單,類似於 [[Special:NewFiles]]。",
        "apihelp-query+allimages-example-mimetypes": "顯示帶有 MIME 類型為 <kbd>image/png</kbd> 或 <kbd>image/gif</kbd> 的檔案清單",
        "apihelp-query+allimages-example-generator": "顯示 4 個以 <kbd>T</kbd> 為開頭的檔案之資訊。",
        "apihelp-query+alllinks-param-namespace": "要列舉的命名空間。",
        "apihelp-query+alllinks-param-limit": "要回傳的項目總數。",
        "apihelp-query+alllinks-param-dir": "列出時所採用的方向。",
-       "apihelp-query+alllinks-example-B": "列出連結標題,包含頁面 ID 以 <kbd>B</kbd> 為起始的遺失項目。",
+       "apihelp-query+alllinks-example-b": "列出連結標題,包含頁面 ID 以 <kbd>B</kbd> 為起始的遺失項目。",
        "apihelp-query+alllinks-example-unique": "列出唯一的連結標題。",
        "apihelp-query+alllinks-example-unique-generator": "取得所有已連結標題,標記為遺失。",
        "apihelp-query+alllinks-example-generator": "取得包含連結的頁面。",
        "apihelp-query+allpages-param-dir": "列出時所採用的方向。",
        "apihelp-query+allpages-param-filterlanglinks": "篩選基於頁面是否有語言連結。請注意這可能不會考慮由擴充所添加的語言連結。",
        "apihelp-query+allpages-param-prexpiry": "篩選頁面的保護期限:\n;indefinite:只取得無限期保護的頁面。\n;definite:只取得帶有特定保護期限的頁面。\n;all:取得任何保護期限的頁面。",
-       "apihelp-query+allpages-example-B": "顯示以字母 <kbd>B</kbd> 為開頭的所有頁面清單。",
+       "apihelp-query+allpages-example-b": "顯示以字母 <kbd>B</kbd> 為開頭的所有頁面清單。",
        "apihelp-query+allpages-example-generator": "顯示 4 個以 <kbd>T</kbd> 為開頭的頁面之資訊。",
        "apihelp-query+allpages-example-generator-revisions": "顯示前 2 個以 <kbd>Re</kbd> 為開頭的非重新導向頁面內容。",
        "apihelp-query+allredirects-summary": "列出至命名空間的所有重新導向。",
        "apihelp-query+allredirects-param-namespace": "要列舉的命名空間。",
        "apihelp-query+allredirects-param-limit": "要回傳的項目總數。",
        "apihelp-query+allredirects-param-dir": "列出時所採用的方向。",
-       "apihelp-query+allredirects-example-B": "列出目標頁面,包含頁面 ID 以 <kbd>B</kbd> 為起始的遺失項目。",
+       "apihelp-query+allredirects-example-b": "列出目標頁面,包含頁面 ID 以 <kbd>B</kbd> 為起始的遺失項目。",
        "apihelp-query+allredirects-example-unique": "列出唯一目標頁面。",
        "apihelp-query+allredirects-example-unique-generator": "取得所有目標頁面,標記為遺失。",
        "apihelp-query+allredirects-example-generator": "取得包含重新導向的頁面。",
        "apihelp-query+alltransclusions-param-namespace": "要列舉的命名空間。",
        "apihelp-query+alltransclusions-param-limit": "要回傳的項目總數。",
        "apihelp-query+alltransclusions-param-dir": "列出時所採用的方向。",
-       "apihelp-query+alltransclusions-example-B": "列出嵌入標題,包含頁面 ID 以 <kbd>B</kbd> 為起始的遺失項目。",
+       "apihelp-query+alltransclusions-example-b": "列出嵌入標題,包含頁面 ID 以 <kbd>B</kbd> 為起始的遺失項目。",
        "apihelp-query+alltransclusions-example-unique": "列出獨一嵌入標題。",
        "apihelp-query+alltransclusions-example-unique-generator": "取得所有嵌入標題,標記為遺失。",
        "apihelp-query+alltransclusions-example-generator": "取得包含嵌入的頁面。",
        "apihelp-query+allusers-param-witheditsonly": "僅列出有做過編輯的使用者。",
        "apihelp-query+allusers-param-activeusers": "僅列出在最近 $1 {{PLURAL:$1|天|天}}裡活躍的使用者。",
        "apihelp-query+allusers-param-attachedwiki": "與 <kbd>$1prop=centralids</kbd> 使用,另外表明使用者是否附加於由此 ID 所識別出的 wiki。",
-       "apihelp-query+allusers-example-Y": "列出以<kbd>Y</kbd>開頭的使用者。",
+       "apihelp-query+allusers-example-y": "列出以<kbd>Y</kbd>開頭的使用者。",
        "apihelp-query+authmanagerinfo-summary": "取得目前身分核對狀態的資訊。",
        "apihelp-query+authmanagerinfo-param-securitysensitiveoperation": "測試使用者的目前驗證狀態是否足夠於指定的安全敏感操作。",
        "apihelp-query+authmanagerinfo-param-requestsfor": "索取關於指定驗證操作所需的驗證請求方面資訊。",
        "apihelp-query+userinfo-paramvalue-prop-registrationdate": "添加使用者的註冊日期。",
        "apihelp-query+userinfo-paramvalue-prop-unreadcount": "添加未讀頁面數目在使用者的監視清單(最多 $1,若有更多則回傳 <samp>$2</samp>)。",
        "apihelp-query+userinfo-paramvalue-prop-centralids": "替使用者添加中心 ID 與附加狀態。",
+       "apihelp-query+userinfo-paramvalue-prop-latestcontrib": "添加使用者最新貢獻的日期。",
        "apihelp-query+userinfo-param-attachedwiki": "以 <kbd>$1prop=centralids</kbd> 來表明使用者是否附加於由此 ID 所識別出的 wiki。",
        "apihelp-query+userinfo-example-simple": "取得目前使用者的資訊。",
        "apihelp-query+userinfo-example-data": "取得目前使用者的額外資訊。",
        "apihelp-format-example-generic": "以 $1 格式傳回查詢結果。",
        "apihelp-format-param-wrappedhtml": "回傳作為 JSON 物件的美觀列印 HTML 內容以及關聯 ResourceLoader 模組。",
        "apihelp-json-summary": "使用 JSON 格式輸出資料。",
-       "apihelp-json-param-callback": "若有指定,將輸出包在指定的函式調用。出於安全考量,會限制所有使用者特定資料。",
+       "apihelp-json-param-callback": "若有指定,將輸出包在指定的函式呼叫。出於安全考量,會限制所有使用者特定資料。",
        "apihelp-json-param-utf8": "若有指定的話,將多數(並非全部)非 ASCII 字元編碼成 UTF-8,而不是以十六進位轉義序列來取代掉。預設是當 <var>formatversion</var> 不是 <kbd>1</kbd> 時。",
-       "apihelp-json-param-ascii": "è\8b¥æ\9c\89æ\8c\87å®\9aï¼\8c編碼æ\89\80æ\9c\89使ç\94¨å\8d\81å\85­é\80²ä½\8dè½\89義åº\8få\88\97ç\9a\84é\9d\9e ASCII。預設當 <var>formatversion</var> 為 <kbd>1</kbd> 時。",
-       "apihelp-json-param-formatversion": "輸出格式:\n;1:向下兼容格式(XML 風格布林,用於內容節點的 <samp>*</samp> 鍵、其它)。\n;2:現代格式。\n;latest:使用最新格式(目前為 <kbd>2</kbd>)可能會不帶警告作更改。",
+       "apihelp-json-param-ascii": "è\8b¥æ\9c\89æ\8c\87å®\9aï¼\8c編碼æ\89\80æ\9c\89使ç\94¨å\8d\81å\85­é\80²ä½\8dè·³è\84«åº\8få\88\97ç\9a\84é\9d\9e ASCII å­\97碼。預設當 <var>formatversion</var> 為 <kbd>1</kbd> 時。",
+       "apihelp-json-param-formatversion": "輸出格式:\n;1:向下相容格式(XML 式布林值,用於內容節點的 <samp>*</samp> 鍵、其它)。\n;2:現代格式。\n;latest:使用最新格式(目前為 <kbd>2</kbd>)可能會不帶警告作更改。",
        "apihelp-jsonfm-summary": "使用 JSON 格式輸出資料 (使用 HTML 格式顯示)。",
        "apihelp-none-summary": "不輸出。",
        "apihelp-php-summary": "使用序列化 PHP 格式輸出資料。",
        "api-help-param-integer-minmax": "{{PLURAL:$1|1=數值|2=數值}}必須在 $2 與 $3 之間。",
        "api-help-param-upload": "必須使用 multipart/form-data 以檔案上傳的方式傳送。",
        "api-help-param-multi-separate": "將幾個值以 <kbd>|</kbd> 或 [[Special:ApiHelp/main#main/datatypes|alternative]] 分隔。",
-       "api-help-param-multi-max": "上限值為 {{PLURAL:$1|$1}} (機器人為 {{PLURAL:$2|$2}})。",
+       "api-help-param-multi-max": "上限值為 {{PLURAL:$1|$1}}(機器人為 {{PLURAL:$2|$2}})。",
        "api-help-param-multi-max-simple": "值的最大數量為 {{PLURAL:$1|$1}}。",
        "api-help-param-multi-all": "要指定所有值,請使用<kbd>$1</kbd>。",
        "api-help-param-default": "預設值:$1",
        "api-help-param-default-empty": "預設值:<span class=\"apihelp-empty\">(空)</span>",
-       "api-help-param-token": "自 [[Special:ApiHelp/query+tokens|action=query&meta=tokens]] 接收的 \"$1\" 權杖。",
+       "api-help-param-token": "自 [[Special:ApiHelp/query+tokens|action=query&meta=tokens]] 接收的「$1」權杖。",
        "api-help-param-token-webui": "為顧及相容性,web UI 中使用的權杖(Token)也是可接受的。",
        "api-help-param-disabled-in-miser-mode": "因[[mw:Special:MyLanguage/Manual:$wgMiserMode|miser模式]]而被停用。",
        "api-help-param-limited-in-miser-mode": "<strong>注意:</strong>出於 [[mw:Special:MyLanguage/Manual:$wgMiserMode|miser 模式]]緣故,使用這個可能會導致在繼續之前,傳回少於 <var>$1limit</var> 筆的結果,極端情況下則可能不會傳回任何结果。",
        "api-help-examples": "{{PLURAL:$1|範例}}:",
        "api-help-permissions": "{{PLURAL:$1|權限}}:",
        "api-help-permissions-granted-to": "{{PLURAL:$1|已授權給}}: $2",
-       "api-help-right-apihighlimits": "在 API 查詢使用較高的限制(慢查詢:$1;快查詢:$2)。慢查詢的限制也適用於多值參數。",
+       "api-help-right-apihighlimits": "在 API 查詢使用較高的限制(慢速查詢:$1;快速查詢:$2)。慢速查詢的限制也適用於多值參數。",
        "api-help-open-in-apisandbox": "<small>[在沙盒中開啟]</small>",
-       "api-help-authmanager-general-usage": "使用此模組的一般程式是:\n# 通過 <kbd>amirequestsfor=$4</kbd> 取得來自 <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> 的可用欄位,和來自 <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd> 的<kbd>$5</kbd>權杖。\n# 向用戶顯示欄位,並獲得其提交的內容。\n# 提交(POST)至此模組,提供 <var>$1returnurl</var> 及任何相關欄位。\n# 在回應中檢查 <samp>status</samp>。\n#* 如果您收到了 <samp>PASS</samp>(成功)或<samp>FAIL</samp>(失敗),則認為操作結束。成功與否如上句所示。\n#* 如果您收到了 <samp>UI</samp>,向用戶顯示新欄位,並再次獲取其提交的內容。然後再次使用 <var>$1continue</var>,向本模組提交相關欄位,並重復第四步。\n#* 如果您收到了 <samp>REDIRECT</samp>,將使用者指向<samp>redirecttarget</samp> 中的目標,等待其返回<var>$1returnurl</var>。然後再次使用 <var>$1continue</var>,向本模組提交返回 URL 中提供的一切欄位,並重復第四步。\n#* 如果您收到了 <samp>RESTART</samp>,這意味著身份驗證正常運作,但我們沒有連結的使用者帳戶。您可以將此視為 <samp>UI</samp>或<samp>FAIL</samp>。",
+       "api-help-authmanager-general-usage": "使用此模組的一般步驟是:\n# 透過 <kbd>amirequestsfor=$4</kbd> 取得來自 <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> 的可用欄位,和來自 <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd> 的<kbd>$5</kbd>權杖。\n# 向使用者顯示欄位,並獲得其提交的內容。\n# 提交(POST)至此模組,提供 <var>$1returnurl</var> 及任何相關欄位。\n# 在回應中檢查 <samp>status</samp>。\n#* 如果您收到了 <samp>PASS</samp>(成功)或<samp>FAIL</samp>(失敗),則認為操作結束。成功與否如上句所示。\n#* 如果您收到了 <samp>UI</samp>,向使用者顯示新欄位,並再次獲取其提交的內容。然後再次使用 <var>$1continue</var>,向本模組提交相關欄位,並重復第四步。\n#* 如果您收到了 <samp>REDIRECT</samp>,將使用者指向<samp>redirecttarget</samp> 中的目標,等待其返回<var>$1returnurl</var>。然後再次使用 <var>$1continue</var>,向本模組提交返回 URL 中提供的一切欄位,並重復第四步。\n#* 如果您收到了 <samp>RESTART</samp>,表示身份驗證正常運作,但我們沒有連結的使用者帳戶。您可以將此視為 <samp>UI</samp>或<samp>FAIL</samp>。",
        "api-help-authmanagerhelper-requests": "只使用這些身份驗證請求,透過自<kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd>回傳的<samp>id</samp>與<kbd>amirequestsfor=$1</kbd>,或來自此模組之前的回應。",
        "api-help-authmanagerhelper-request": "使用此身份驗證請求,透過自<kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd>回傳的<samp>id</samp>與<kbd>amirequestsfor=$1</kbd>。",
        "api-help-authmanagerhelper-messageformat": "用於回傳訊息的格式。",
        "apiwarn-validationfailed-cannotset": "不能透過此模組設定。",
        "apiwarn-validationfailed-keytoolong": "鍵太長(不允許超過 $1 位元組)。",
        "apiwarn-validationfailed": "<kbd>$1</kbd>驗證錯誤:$2",
-       "apiwarn-wgDebugAPI": "<strong>安全警告</strong>:<var>$wgDebugAPI</var> 已啟用。",
+       "apiwarn-wgdebugapi": "<strong>安全警告</strong>:<var>$wgDebugAPI</var> 已啟用。",
        "api-feed-error-title": "錯誤($1)",
        "api-usage-docref": "查看 $1 來了解 API 的使用。",
        "api-usage-mailinglist-ref": "在 &lt;https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce&gt; 的 mediawiki-api-announce 郵件清單做出訂閱,來取得 API 棄用與重大修訂的通知。",
index 946decf..5915d35 100644 (file)
@@ -1006,7 +1006,7 @@ class AuthManager implements LoggerAwareInterface {
                if ( $block ) {
                        $errorParams = [
                                $block->getTarget(),
-                               $block->mReason ?: wfMessage( 'blockednoreason' )->text(),
+                               $block->getReason() ?: wfMessage( 'blockednoreason' )->text(),
                                $block->getByName()
                        ];
 
@@ -1021,7 +1021,10 @@ class AuthManager implements LoggerAwareInterface {
                }
 
                $ip = $this->getRequest()->getIP();
-               if ( $creator->isDnsBlacklisted( $ip, true /* check $wgProxyWhitelist */ ) ) {
+               if (
+                       MediaWikiServices::getInstance()->getBlockManager()
+                               ->isDnsBlacklisted( $ip, true /* check $wgProxyWhitelist */ )
+               ) {
                        return Status::newFatal( 'sorbs_create_account_reason' );
                }
 
@@ -1423,7 +1426,7 @@ class AuthManager implements LoggerAwareInterface {
                                        // @codeCoverageIgnoreEnd
                                }
                                $this->setDefaultUserOptions( $user, $creator->isAnon() );
-                               \Hooks::run( 'LocalUserCreated', [ $user, false ] );
+                               \Hooks::runWithoutAbort( 'LocalUserCreated', [ $user, false ] );
                                $user->saveSettings();
                                $state['userid'] = $user->getId();
 
@@ -2101,10 +2104,8 @@ class AuthManager implements LoggerAwareInterface {
                                $id = $req->getUniqueId();
 
                                // If a required request if from a Primary, mark it as "primary-required" instead
-                               if ( $isPrimary ) {
-                                       if ( $req->required ) {
-                                               $req->required = AuthenticationRequest::PRIMARY_REQUIRED;
-                                       }
+                               if ( $isPrimary && $req->required ) {
+                                       $req->required = AuthenticationRequest::PRIMARY_REQUIRED;
                                }
 
                                if (
index 7fc362a..4744c4d 100644 (file)
@@ -370,6 +370,7 @@ abstract class AuthenticationRequest {
         * @return AuthenticationRequest
         */
        public static function __set_state( $data ) {
+               // @phan-suppress-next-line PhanTypeInstantiateAbstract
                $ret = new static();
                foreach ( $data as $k => $v ) {
                        $ret->$k = $v;
index 7488fba..3e26097 100644 (file)
@@ -59,9 +59,11 @@ class CheckBlocksSecondaryAuthenticationProvider extends AbstractSecondaryAuthen
        }
 
        public function beginSecondaryAuthentication( $user, array $reqs ) {
+               // @TODO Partial blocks should not prevent the user from logging in.
+               //       see: https://phabricator.wikimedia.org/T208895
                if ( !$this->blockDisablesLogin ) {
                        return AuthenticationResponse::newAbstain();
-               } elseif ( $user->isBlocked() ) {
+               } elseif ( $user->getBlock() ) {
                        return AuthenticationResponse::newFail(
                                new \Message( 'login-userblocked', [ $user->getName() ] )
                        );
@@ -77,8 +79,8 @@ class CheckBlocksSecondaryAuthenticationProvider extends AbstractSecondaryAuthen
        public function testUserForCreation( $user, $autocreate, array $options = [] ) {
                $block = $user->isBlockedFromCreateAccount();
                if ( $block ) {
-                       if ( $block->mReason ) {
-                               $reason = $block->mReason;
+                       if ( $block->getReason() ) {
+                               $reason = $block->getReason();
                        } else {
                                $msg = \Message::newFromKey( 'blockednoreason' );
                                if ( !\RequestContext::getMain()->getUser()->isSafeToLoad() ) {
diff --git a/includes/auth/LegacyHookPreAuthenticationProvider.php b/includes/auth/LegacyHookPreAuthenticationProvider.php
deleted file mode 100644 (file)
index 5f55ec5..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Auth
- */
-
-namespace MediaWiki\Auth;
-
-/**
- * A pre-authentication provider to call some legacy hooks.
- * @ingroup Auth
- * @since 1.27
- * @deprecated since 1.27
- */
-class LegacyHookPreAuthenticationProvider extends AbstractPreAuthenticationProvider {
-       public function __construct() {
-               wfDeprecated( self::class, '1.27' );
-       }
-}
index 047a811..b646380 100644 (file)
@@ -303,18 +303,16 @@ class LocalPasswordPrimaryAuthenticationProvider
                }
 
                $req = AuthenticationRequest::getRequestByClass( $reqs, PasswordAuthenticationRequest::class );
-               if ( $req ) {
-                       if ( $req->username !== null && $req->password !== null ) {
-                               // Nothing we can do besides claim it, because the user isn't in
-                               // the DB yet
-                               if ( $req->username !== $user->getName() ) {
-                                       $req = clone $req;
-                                       $req->username = $user->getName();
-                               }
-                               $ret = AuthenticationResponse::newPass( $req->username );
-                               $ret->createRequest = $req;
-                               return $ret;
+               if ( $req && $req->username !== null && $req->password !== null ) {
+                       // Nothing we can do besides claim it, because the user isn't in
+                       // the DB yet
+                       if ( $req->username !== $user->getName() ) {
+                               $req = clone $req;
+                               $req->username = $user->getName();
                        }
+                       $ret = AuthenticationResponse::newPass( $req->username );
+                       $ret->createRequest = $req;
+                       return $ret;
                }
                return AuthenticationResponse::newAbstain();
        }
index 045f791..e129538 100644 (file)
@@ -356,23 +356,21 @@ class TemporaryPasswordPrimaryAuthenticationProvider
                $req = AuthenticationRequest::getRequestByClass(
                        $reqs, TemporaryPasswordAuthenticationRequest::class
                );
-               if ( $req ) {
-                       if ( $req->username !== null && $req->password !== null ) {
-                               // Nothing we can do yet, because the user isn't in the DB yet
-                               if ( $req->username !== $user->getName() ) {
-                                       $req = clone $req;
-                                       $req->username = $user->getName();
-                               }
-
-                               if ( $req->mailpassword ) {
-                                       // prevent EmailNotificationSecondaryAuthenticationProvider from sending another mail
-                                       $this->manager->setAuthenticationSessionData( 'no-email', true );
-                               }
+               if ( $req && $req->username !== null && $req->password !== null ) {
+                       // Nothing we can do yet, because the user isn't in the DB yet
+                       if ( $req->username !== $user->getName() ) {
+                               $req = clone $req;
+                               $req->username = $user->getName();
+                       }
 
-                               $ret = AuthenticationResponse::newPass( $req->username );
-                               $ret->createRequest = $req;
-                               return $ret;
+                       if ( $req->mailpassword ) {
+                               // prevent EmailNotificationSecondaryAuthenticationProvider from sending another mail
+                               $this->manager->setAuthenticationSessionData( 'no-email', true );
                        }
+
+                       $ret = AuthenticationResponse::newPass( $req->username );
+                       $ret->createRequest = $req;
+                       return $ret;
                }
                return AuthenticationResponse::newAbstain();
        }
diff --git a/includes/block/AbstractBlock.php b/includes/block/AbstractBlock.php
new file mode 100644 (file)
index 0000000..a931d7a
--- /dev/null
@@ -0,0 +1,674 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+namespace MediaWiki\Block;
+
+use IContextSource;
+use InvalidArgumentException;
+use IP;
+use RequestContext;
+use Title;
+use User;
+
+/**
+ * @since 1.34 Factored out from Block.
+ */
+abstract class AbstractBlock {
+       /** @var string */
+       public $mReason;
+
+       /** @var string */
+       public $mTimestamp;
+
+       /** @var string */
+       public $mExpiry = '';
+
+       /** @var bool */
+       protected $mBlockEmail = false;
+
+       /** @var bool */
+       protected $allowUsertalk = false;
+
+       /** @var bool */
+       protected $blockCreateAccount = false;
+
+       /** @var bool */
+       public $mHideName = false;
+
+       /** @var User|string */
+       protected $target;
+
+       /**
+        * @var int Block::TYPE_ constant. After the block has been loaded
+        * from the database, this can only be USER, IP or RANGE.
+        */
+       protected $type;
+
+       /** @var User */
+       protected $blocker;
+
+       /** @var bool */
+       protected $isSitewide = true;
+
+       # TYPE constants
+       const TYPE_USER = 1;
+       const TYPE_IP = 2;
+       const TYPE_RANGE = 3;
+       const TYPE_AUTO = 4;
+       const TYPE_ID = 5;
+
+       /**
+        * Create a new block with specified parameters on a user, IP or IP range.
+        *
+        * @param array $options Parameters of the block:
+        *     address string|User  Target user name, User object, IP address or IP range
+        *     by int               User ID of the blocker
+        *     reason string        Reason of the block
+        *     timestamp string     The time at which the block comes into effect
+        *     byText string        Username of the blocker (for foreign users)
+        */
+       function __construct( $options = [] ) {
+               $defaults = [
+                       'address'         => '',
+                       'by'              => null,
+                       'reason'          => '',
+                       'timestamp'       => '',
+                       'byText'          => '',
+               ];
+
+               $options += $defaults;
+
+               $this->setTarget( $options['address'] );
+
+               if ( $options['by'] ) {
+                       # Local user
+                       $this->setBlocker( User::newFromId( $options['by'] ) );
+               } else {
+                       # Foreign user
+                       $this->setBlocker( $options['byText'] );
+               }
+
+               $this->setReason( $options['reason'] );
+               $this->setTimestamp( wfTimestamp( TS_MW, $options['timestamp'] ) );
+       }
+
+       /**
+        * Get the user id of the blocking sysop
+        *
+        * @return int (0 for foreign users)
+        */
+       public function getBy() {
+               return $this->getBlocker()->getId();
+       }
+
+       /**
+        * Get the username of the blocking sysop
+        *
+        * @return string
+        */
+       public function getByName() {
+               return $this->getBlocker()->getName();
+       }
+
+       /**
+        * Get the block ID
+        * @return int|null
+        */
+       public function getId() {
+               return null;
+       }
+
+       /**
+        * Get the reason given for creating the block
+        *
+        * @since 1.33
+        * @return string
+        */
+       public function getReason() {
+               return $this->mReason;
+       }
+
+       /**
+        * Set the reason for creating the block
+        *
+        * @since 1.33
+        * @param string $reason
+        */
+       public function setReason( $reason ) {
+               $this->mReason = $reason;
+       }
+
+       /**
+        * Get whether the block hides the target's username
+        *
+        * @since 1.33
+        * @return bool The block hides the username
+        */
+       public function getHideName() {
+               return $this->mHideName;
+       }
+
+       /**
+        * Set whether ths block hides the target's username
+        *
+        * @since 1.33
+        * @param bool $hideName The block hides the username
+        */
+       public function setHideName( $hideName ) {
+               $this->mHideName = $hideName;
+       }
+
+       /**
+        * Indicates that the block is a sitewide block. This means the user is
+        * prohibited from editing any page on the site (other than their own talk
+        * page).
+        *
+        * @since 1.33
+        * @param null|bool $x
+        * @return bool
+        */
+       public function isSitewide( $x = null ) {
+               return wfSetVar( $this->isSitewide, $x );
+       }
+
+       /**
+        * Get or set the flag indicating whether this block blocks the target from
+        * creating an account. (Note that the flag may be overridden depending on
+        * global configs.)
+        *
+        * @since 1.33
+        * @param null|bool $x Value to set (if null, just get the property value)
+        * @return bool Value of the property
+        */
+       public function isCreateAccountBlocked( $x = null ) {
+               return wfSetVar( $this->blockCreateAccount, $x );
+       }
+
+       /**
+        * Get or set the flag indicating whether this block blocks the target from
+        * sending emails. (Note that the flag may be overridden depending on
+        * global configs.)
+        *
+        * @since 1.33
+        * @param null|bool $x Value to set (if null, just get the property value)
+        * @return bool Value of the property
+        */
+       public function isEmailBlocked( $x = null ) {
+               return wfSetVar( $this->mBlockEmail, $x );
+       }
+
+       /**
+        * Get or set the flag indicating whether this block blocks the target from
+        * editing their own user talk page. (Note that the flag may be overridden
+        * depending on global configs.)
+        *
+        * @since 1.33
+        * @param null|bool $x Value to set (if null, just get the property value)
+        * @return bool Value of the property
+        */
+       public function isUsertalkEditAllowed( $x = null ) {
+               return wfSetVar( $this->allowUsertalk, $x );
+       }
+
+       /**
+        * Determine whether the Block prevents a given right. A right
+        * may be blacklisted or whitelisted, or determined from a
+        * property on the Block object. For certain rights, the property
+        * may be overridden according to global configs.
+        *
+        * @since 1.33
+        * @param string $right Right to check
+        * @return bool|null null if unrecognized right or unset property
+        */
+       public function appliesToRight( $right ) {
+               $config = RequestContext::getMain()->getConfig();
+               $blockDisablesLogin = $config->get( 'BlockDisablesLogin' );
+
+               $res = null;
+               switch ( $right ) {
+                       case 'edit':
+                               // TODO: fix this case to return proper value
+                               $res = true;
+                               break;
+                       case 'createaccount':
+                               $res = $this->isCreateAccountBlocked();
+                               break;
+                       case 'sendemail':
+                               $res = $this->isEmailBlocked();
+                               break;
+                       case 'upload':
+                               // Until T6995 is completed
+                               $res = $this->isSitewide();
+                               break;
+                       case 'read':
+                               $res = false;
+                               break;
+                       case 'purge':
+                               $res = false;
+                               break;
+               }
+               if ( !$res && $blockDisablesLogin ) {
+                       // If a block would disable login, then it should
+                       // prevent any right that all users cannot do
+                       $anon = new User;
+                       $res = $anon->isAllowed( $right ) ? $res : true;
+               }
+
+               return $res;
+       }
+
+       /**
+        * Get/set whether the Block prevents a given action
+        *
+        * @deprecated since 1.33, use appliesToRight to determine block
+        *  behaviour, and specific methods to get/set properties
+        * @param string $action Action to check
+        * @param bool|null $x Value for set, or null to just get value
+        * @return bool|null Null for unrecognized rights.
+        */
+       public function prevents( $action, $x = null ) {
+               $config = RequestContext::getMain()->getConfig();
+               $blockDisablesLogin = $config->get( 'BlockDisablesLogin' );
+               $blockAllowsUTEdit = $config->get( 'BlockAllowsUTEdit' );
+
+               $res = null;
+               switch ( $action ) {
+                       case 'edit':
+                               # For now... <evil laugh>
+                               $res = true;
+                               break;
+                       case 'createaccount':
+                               $res = wfSetVar( $this->blockCreateAccount, $x );
+                               break;
+                       case 'sendemail':
+                               $res = wfSetVar( $this->mBlockEmail, $x );
+                               break;
+                       case 'upload':
+                               // Until T6995 is completed
+                               $res = $this->isSitewide();
+                               break;
+                       case 'editownusertalk':
+                               // NOTE: this check is not reliable on partial blocks
+                               // since partially blocked users are always allowed to edit
+                               // their own talk page unless a restriction exists on the
+                               // page or User_talk: namespace
+                               wfSetVar( $this->allowUsertalk, $x === null ? null : !$x );
+                               $res = !$this->isUsertalkEditAllowed();
+
+                               // edit own user talk can be disabled by config
+                               if ( !$blockAllowsUTEdit ) {
+                                       $res = true;
+                               }
+                               break;
+                       case 'read':
+                               $res = false;
+                               break;
+                       case 'purge':
+                               $res = false;
+                               break;
+               }
+               if ( !$res && $blockDisablesLogin ) {
+                       // If a block would disable login, then it should
+                       // prevent any action that all users cannot do
+                       $anon = new User;
+                       $res = $anon->isAllowed( $action ) ? $res : true;
+               }
+
+               return $res;
+       }
+
+       /**
+        * From an existing Block, get the target and the type of target.
+        * Note that, except for null, it is always safe to treat the target
+        * as a string; for User objects this will return User::__toString()
+        * which in turn gives User::getName().
+        *
+        * @param string|int|User|null $target
+        * @return array [ User|String|null, Block::TYPE_ constant|null ]
+        */
+       public static function parseTarget( $target ) {
+               # We may have been through this before
+               if ( $target instanceof User ) {
+                       if ( IP::isValid( $target->getName() ) ) {
+                               return [ $target, self::TYPE_IP ];
+                       } else {
+                               return [ $target, self::TYPE_USER ];
+                       }
+               } elseif ( $target === null ) {
+                       return [ null, null ];
+               }
+
+               $target = trim( $target );
+
+               if ( IP::isValid( $target ) ) {
+                       # We can still create a User if it's an IP address, but we need to turn
+                       # off validation checking (which would exclude IP addresses)
+                       return [
+                               User::newFromName( IP::sanitizeIP( $target ), false ),
+                               self::TYPE_IP
+                       ];
+
+               } elseif ( IP::isValidRange( $target ) ) {
+                       # Can't create a User from an IP range
+                       return [ IP::sanitizeRange( $target ), self::TYPE_RANGE ];
+               }
+
+               # Consider the possibility that this is not a username at all
+               # but actually an old subpage (T31797)
+               if ( strpos( $target, '/' ) !== false ) {
+                       # An old subpage, drill down to the user behind it
+                       $target = explode( '/', $target )[0];
+               }
+
+               $userObj = User::newFromName( $target );
+               if ( $userObj instanceof User ) {
+                       # Note that since numbers are valid usernames, a $target of "12345" will be
+                       # considered a User.  If you want to pass a block ID, prepend a hash "#12345",
+                       # since hash characters are not valid in usernames or titles generally.
+                       return [ $userObj, self::TYPE_USER ];
+
+               } elseif ( preg_match( '/^#\d+$/', $target ) ) {
+                       # Autoblock reference in the form "#12345"
+                       return [ substr( $target, 1 ), self::TYPE_AUTO ];
+
+               } else {
+                       return [ null, null ];
+               }
+       }
+
+       /**
+        * Get the type of target for this particular block.
+        * @return int Block::TYPE_ constant, will never be TYPE_ID
+        */
+       public function getType() {
+               return $this->type;
+       }
+
+       /**
+        * Get the target and target type for this particular Block.  Note that for autoblocks,
+        * this returns the unredacted name; frontend functions need to call $block->getRedactedName()
+        * in this situation.
+        * @return array [ User|String, Block::TYPE_ constant ]
+        * @todo FIXME: This should be an integral part of the Block member variables
+        */
+       public function getTargetAndType() {
+               return [ $this->getTarget(), $this->getType() ];
+       }
+
+       /**
+        * Get the target for this particular Block.  Note that for autoblocks,
+        * this returns the unredacted name; frontend functions need to call $block->getRedactedName()
+        * in this situation.
+        * @return User|string
+        */
+       public function getTarget() {
+               return $this->target;
+       }
+
+       /**
+        * Get the block expiry time
+        *
+        * @since 1.19
+        * @return string
+        */
+       public function getExpiry() {
+               return $this->mExpiry;
+       }
+
+       /**
+        * Set the block expiry time
+        *
+        * @since 1.33
+        * @param string $expiry
+        */
+       public function setExpiry( $expiry ) {
+               $this->mExpiry = $expiry;
+       }
+
+       /**
+        * Get the timestamp indicating when the block was created
+        *
+        * @since 1.33
+        * @return string
+        */
+       public function getTimestamp() {
+               return $this->mTimestamp;
+       }
+
+       /**
+        * Set the timestamp indicating when the block was created
+        *
+        * @since 1.33
+        * @param string $timestamp
+        */
+       public function setTimestamp( $timestamp ) {
+               $this->mTimestamp = $timestamp;
+       }
+
+       /**
+        * Set the target for this block, and update $this->type accordingly
+        * @param mixed $target
+        */
+       public function setTarget( $target ) {
+               list( $this->target, $this->type ) = static::parseTarget( $target );
+       }
+
+       /**
+        * Get the user who implemented this block
+        * @return User User object. May name a foreign user.
+        */
+       public function getBlocker() {
+               return $this->blocker;
+       }
+
+       /**
+        * Set the user who implemented (or will implement) this block
+        * @param User|string $user Local User object or username string
+        */
+       public function setBlocker( $user ) {
+               if ( is_string( $user ) ) {
+                       $user = User::newFromName( $user, false );
+               }
+
+               if ( $user->isAnon() && User::isUsableName( $user->getName() ) ) {
+                       throw new InvalidArgumentException(
+                               'Blocker must be a local user or a name that cannot be a local user'
+                       );
+               }
+
+               $this->blocker = $user;
+       }
+
+       /**
+        * Get the key and parameters for the corresponding error message.
+        *
+        * @since 1.22
+        * @param IContextSource $context
+        * @return array
+        */
+       abstract public function getPermissionsError( IContextSource $context );
+
+       /**
+        * Get block information used in different block error messages
+        *
+        * @since 1.33
+        * @param IContextSource $context
+        * @return array
+        */
+       public function getBlockErrorParams( IContextSource $context ) {
+               $blocker = $this->getBlocker();
+               if ( $blocker instanceof User ) { // local user
+                       $blockerUserpage = $blocker->getUserPage();
+                       $link = "[[{$blockerUserpage->getPrefixedText()}|{$blockerUserpage->getText()}]]";
+               } else { // foreign user
+                       $link = $blocker;
+               }
+
+               $reason = $this->getReason();
+               if ( $reason == '' ) {
+                       $reason = $context->msg( 'blockednoreason' )->text();
+               }
+
+               /* $ip returns who *is* being blocked, $intended contains who was meant to be blocked.
+                * This could be a username, an IP range, or a single IP. */
+               $intended = $this->getTarget();
+               $lang = $context->getLanguage();
+
+               return [
+                       $link,
+                       $reason,
+                       $context->getRequest()->getIP(),
+                       $this->getByName(),
+                       // TODO: SystemBlock replaces this with the system block type. Clean up
+                       // error params so that this is not necessary.
+                       $this->getId(),
+                       $lang->formatExpiry( $this->getExpiry() ),
+                       (string)$intended,
+                       $lang->userTimeAndDate( $this->getTimestamp(), $context->getUser() ),
+               ];
+       }
+
+       /**
+        * Determine whether the block allows the user to edit their own
+        * user talk page. This is done separately from Block::appliesToRight
+        * because there is no right for editing one's own user talk page
+        * and because the user's talk page needs to be passed into the
+        * Block object, which is unaware of the user.
+        *
+        * The ipb_allow_usertalk flag (which corresponds to the property
+        * allowUsertalk) is used on sitewide blocks and partial blocks
+        * that contain a namespace restriction on the user talk namespace,
+        * but do not contain a page restriction on the user's talk page.
+        * For all other (i.e. most) partial blocks, the flag is ignored,
+        * and the user can always edit their user talk page unless there
+        * is a page restriction on their user talk page, in which case
+        * they can never edit it. (Ideally the flag would be stored as
+        * null in these cases, but the database field isn't nullable.)
+        *
+        * This method does not validate that the passed in talk page belongs to the
+        * block target since the target (an IP) might not be the same as the user's
+        * talk page (if they are logged in).
+        *
+        * @since 1.33
+        * @param Title|null $usertalk The user's user talk page. If null,
+        *  and if the target is a User, the target's userpage is used
+        * @return bool The user can edit their talk page
+        */
+       public function appliesToUsertalk( Title $usertalk = null ) {
+               if ( !$usertalk ) {
+                       if ( $this->target instanceof User ) {
+                               $usertalk = $this->target->getTalkPage();
+                       } else {
+                               throw new InvalidArgumentException(
+                                       '$usertalk must be provided if block target is not a user/IP'
+                               );
+                       }
+               }
+
+               if ( $usertalk->getNamespace() !== NS_USER_TALK ) {
+                       throw new InvalidArgumentException(
+                               '$usertalk must be a user talk page'
+                       );
+               }
+
+               if ( !$this->isSitewide() ) {
+                       if ( $this->appliesToPage( $usertalk->getArticleID() ) ) {
+                               return true;
+                       }
+                       if ( !$this->appliesToNamespace( NS_USER_TALK ) ) {
+                               return false;
+                       }
+               }
+
+               // This is a type of block which uses the ipb_allow_usertalk
+               // flag. The flag can still be overridden by global configs.
+               $config = RequestContext::getMain()->getConfig();
+               if ( !$config->get( 'BlockAllowsUTEdit' ) ) {
+                       return true;
+               }
+               return !$this->isUsertalkEditAllowed();
+       }
+
+       /**
+        * Checks if a block applies to a particular title
+        *
+        * This check does not consider whether `$this->isUsertalkEditAllowed`
+        * returns false, as the identity of the user making the hypothetical edit
+        * isn't known here (particularly in the case of IP hardblocks, range
+        * blocks, and auto-blocks).
+        *
+        * @param Title $title
+        * @return bool
+        */
+       public function appliesToTitle( Title $title ) {
+               return $this->isSitewide();
+       }
+
+       /**
+        * Checks if a block applies to a particular namespace
+        *
+        * @since 1.33
+        *
+        * @param int $ns
+        * @return bool
+        */
+       public function appliesToNamespace( $ns ) {
+               return $this->isSitewide();
+       }
+
+       /**
+        * Checks if a block applies to a particular page
+        *
+        * This check does not consider whether `$this->isUsertalkEditAllowed`
+        * returns false, as the identity of the user making the hypothetical edit
+        * isn't known here (particularly in the case of IP hardblocks, range
+        * blocks, and auto-blocks).
+        *
+        * @since 1.33
+        *
+        * @param int $pageId
+        * @return bool
+        */
+       public function appliesToPage( $pageId ) {
+               return $this->isSitewide();
+       }
+
+       /**
+        * Check if the block should be tracked with a cookie.
+        *
+        * @since 1.33
+        * @param bool $isAnon The user is logged out
+        * @return bool The block should be tracked with a cookie
+        */
+       public function shouldTrackWithCookie( $isAnon ) {
+               return false;
+       }
+
+       /**
+        * Check if the block prevents a user from resetting their password
+        *
+        * @since 1.33
+        * @return bool The block blocks password reset
+        */
+       public function appliesToPasswordReset() {
+               return $this->isCreateAccountBlocked();
+       }
+
+}
diff --git a/includes/block/BlockManager.php b/includes/block/BlockManager.php
new file mode 100644 (file)
index 0000000..7b665ae
--- /dev/null
@@ -0,0 +1,373 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+namespace MediaWiki\Block;
+
+use Block;
+use IP;
+use MediaWiki\User\UserIdentity;
+use User;
+use WebRequest;
+use Wikimedia\IPSet;
+
+/**
+ * A service class for checking blocks.
+ * To obtain an instance, use MediaWikiServices::getInstance()->getBlockManager().
+ *
+ * @since 1.34 Refactored from User and Block.
+ */
+class BlockManager {
+       // TODO: This should be UserIdentity instead of User
+       /** @var User */
+       private $currentUser;
+
+       /** @var WebRequest */
+       private $currentRequest;
+
+       /** @var bool */
+       private $applyIpBlocksToXff;
+
+       /** @var bool */
+       private $cookieSetOnAutoblock;
+
+       /** @var bool */
+       private $cookieSetOnIpBlock;
+
+       /** @var array */
+       private $dnsBlacklistUrls;
+
+       /** @var bool */
+       private $enableDnsBlacklist;
+
+       /** @var array */
+       private $proxyList;
+
+       /** @var array */
+       private $proxyWhitelist;
+
+       /** @var array */
+       private $softBlockRanges;
+
+       /**
+        * @param User $currentUser
+        * @param WebRequest $currentRequest
+        * @param bool $applyIpBlocksToXff
+        * @param bool $cookieSetOnAutoblock
+        * @param bool $cookieSetOnIpBlock
+        * @param array $dnsBlacklistUrls
+        * @param bool $enableDnsBlacklist
+        * @param array $proxyList
+        * @param array $proxyWhitelist
+        * @param array $softBlockRanges
+        */
+       public function __construct(
+               $currentUser,
+               $currentRequest,
+               $applyIpBlocksToXff,
+               $cookieSetOnAutoblock,
+               $cookieSetOnIpBlock,
+               $dnsBlacklistUrls,
+               $enableDnsBlacklist,
+               $proxyList,
+               $proxyWhitelist,
+               $softBlockRanges
+       ) {
+               $this->currentUser = $currentUser;
+               $this->currentRequest = $currentRequest;
+               $this->applyIpBlocksToXff = $applyIpBlocksToXff;
+               $this->cookieSetOnAutoblock = $cookieSetOnAutoblock;
+               $this->cookieSetOnIpBlock = $cookieSetOnIpBlock;
+               $this->dnsBlacklistUrls = $dnsBlacklistUrls;
+               $this->enableDnsBlacklist = $enableDnsBlacklist;
+               $this->proxyList = $proxyList;
+               $this->proxyWhitelist = $proxyWhitelist;
+               $this->softBlockRanges = $softBlockRanges;
+       }
+
+       /**
+        * Get the blocks that apply to a user and return the most relevant one.
+        *
+        * TODO: $user should be UserIdentity instead of User
+        *
+        * @internal This should only be called by User::getBlockedStatus
+        * @param User $user
+        * @param bool $fromReplica Whether to check the replica DB first.
+        *  To improve performance, non-critical checks are done against replica DBs.
+        *  Check when actually saving should be done against master.
+        * @return AbstractBlock|null The most relevant block, or null if there is no block.
+        */
+       public function getUserBlock( User $user, $fromReplica ) {
+               $isAnon = $user->getId() === 0;
+
+               // TODO: If $user is the current user, we should use the current request. Otherwise,
+               // we should not look for XFF or cookie blocks.
+               $request = $user->getRequest();
+
+               # We only need to worry about passing the IP address to the Block generator if the
+               # user is not immune to autoblocks/hardblocks, and they are the current user so we
+               # know which IP address they're actually coming from
+               $ip = null;
+               $sessionUser = $this->currentUser;
+               // the session user is set up towards the end of Setup.php. Until then,
+               // assume it's a logged-out user.
+               $globalUserName = $sessionUser->isSafeToLoad()
+                       ? $sessionUser->getName()
+                       : IP::sanitizeIP( $this->currentRequest->getIP() );
+               if ( $user->getName() === $globalUserName && !$user->isAllowed( 'ipblock-exempt' ) ) {
+                       $ip = $this->currentRequest->getIP();
+               }
+
+               // User/IP blocking
+               // TODO: remove dependency on Block
+               $block = Block::newFromTarget( $user, $ip, !$fromReplica );
+
+               // Cookie blocking
+               if ( !$block instanceof AbstractBlock ) {
+                       $block = $this->getBlockFromCookieValue( $user, $request );
+               }
+
+               // Proxy blocking
+               if ( !$block instanceof AbstractBlock
+                       && $ip !== null
+                       && !in_array( $ip, $this->proxyWhitelist )
+               ) {
+                       // Local list
+                       if ( $this->isLocallyBlockedProxy( $ip ) ) {
+                               $block = new SystemBlock( [
+                                       'byText' => wfMessage( 'proxyblocker' )->text(),
+                                       'reason' => wfMessage( 'proxyblockreason' )->plain(),
+                                       'address' => $ip,
+                                       'systemBlock' => 'proxy',
+                               ] );
+                       } elseif ( $isAnon && $this->isDnsBlacklisted( $ip ) ) {
+                               $block = new SystemBlock( [
+                                       'byText' => wfMessage( 'sorbs' )->text(),
+                                       'reason' => wfMessage( 'sorbsreason' )->plain(),
+                                       'address' => $ip,
+                                       'systemBlock' => 'dnsbl',
+                               ] );
+                       }
+               }
+
+               // (T25343) Apply IP blocks to the contents of XFF headers, if enabled
+               if ( !$block instanceof AbstractBlock
+                       && $this->applyIpBlocksToXff
+                       && $ip !== null
+                       && !in_array( $ip, $this->proxyWhitelist )
+               ) {
+                       $xff = $request->getHeader( 'X-Forwarded-For' );
+                       $xff = array_map( 'trim', explode( ',', $xff ) );
+                       $xff = array_diff( $xff, [ $ip ] );
+                       // TODO: remove dependency on Block
+                       $xffblocks = Block::getBlocksForIPList( $xff, $isAnon, !$fromReplica );
+                       // TODO: remove dependency on Block
+                       $block = Block::chooseBlock( $xffblocks, $xff );
+                       if ( $block instanceof AbstractBlock ) {
+                               # Mangle the reason to alert the user that the block
+                               # originated from matching the X-Forwarded-For header.
+                               $block->setReason( wfMessage( 'xffblockreason', $block->getReason() )->plain() );
+                       }
+               }
+
+               if ( !$block instanceof AbstractBlock
+                       && $ip !== null
+                       && $isAnon
+                       && IP::isInRanges( $ip, $this->softBlockRanges )
+               ) {
+                       $block = new SystemBlock( [
+                               'address' => $ip,
+                               'byText' => 'MediaWiki default',
+                               'reason' => wfMessage( 'softblockrangesreason', $ip )->plain(),
+                               'anonOnly' => true,
+                               'systemBlock' => 'wgSoftBlockRanges',
+                       ] );
+               }
+
+               return $block;
+       }
+
+       /**
+        * Try to load a Block from an ID given in a cookie value.
+        *
+        * @param UserIdentity $user
+        * @param WebRequest $request
+        * @return Block|bool The Block object, or false if none could be loaded.
+        */
+       private function getBlockFromCookieValue(
+               UserIdentity $user,
+               WebRequest $request
+       ) {
+               $blockCookieVal = $request->getCookie( 'BlockID' );
+               $response = $request->response();
+
+               // Make sure there's something to check. The cookie value must start with a number.
+               if ( strlen( $blockCookieVal ) < 1 || !is_numeric( substr( $blockCookieVal, 0, 1 ) ) ) {
+                       return false;
+               }
+               // Load the Block from the ID in the cookie.
+               // TODO: remove dependency on Block
+               $blockCookieId = Block::getIdFromCookieValue( $blockCookieVal );
+               if ( $blockCookieId !== null ) {
+                       // An ID was found in the cookie.
+                       // TODO: remove dependency on Block
+                       $tmpBlock = Block::newFromID( $blockCookieId );
+                       if ( $tmpBlock instanceof Block ) {
+                               switch ( $tmpBlock->getType() ) {
+                                       case Block::TYPE_USER:
+                                               $blockIsValid = !$tmpBlock->isExpired() && $tmpBlock->isAutoblocking();
+                                               $useBlockCookie = ( $this->cookieSetOnAutoblock === true );
+                                               break;
+                                       case Block::TYPE_IP:
+                                       case Block::TYPE_RANGE:
+                                               // If block is type IP or IP range, load only if user is not logged in (T152462)
+                                               $blockIsValid = !$tmpBlock->isExpired() && $user->getId() === 0;
+                                               $useBlockCookie = ( $this->cookieSetOnIpBlock === true );
+                                               break;
+                                       default:
+                                               $blockIsValid = false;
+                                               $useBlockCookie = false;
+                               }
+
+                               if ( $blockIsValid && $useBlockCookie ) {
+                                       // Use the block.
+                                       return $tmpBlock;
+                               }
+
+                               // If the block is not valid, remove the cookie.
+                               // TODO: remove dependency on Block
+                               Block::clearCookie( $response );
+                       } else {
+                               // If the block doesn't exist, remove the cookie.
+                               // TODO: remove dependency on Block
+                               Block::clearCookie( $response );
+                       }
+               }
+               return false;
+       }
+
+       /**
+        * Check if an IP address is in the local proxy list
+        *
+        * @param string $ip
+        * @return bool
+        */
+       private function isLocallyBlockedProxy( $ip ) {
+               if ( !$this->proxyList ) {
+                       return false;
+               }
+
+               if ( !is_array( $this->proxyList ) ) {
+                       // Load values from the specified file
+                       $this->proxyList = array_map( 'trim', file( $this->proxyList ) );
+               }
+
+               $resultProxyList = [];
+               $deprecatedIPEntries = [];
+
+               // backward compatibility: move all ip addresses in keys to values
+               foreach ( $this->proxyList as $key => $value ) {
+                       $keyIsIP = IP::isIPAddress( $key );
+                       $valueIsIP = IP::isIPAddress( $value );
+                       if ( $keyIsIP && !$valueIsIP ) {
+                               $deprecatedIPEntries[] = $key;
+                               $resultProxyList[] = $key;
+                       } elseif ( $keyIsIP && $valueIsIP ) {
+                               $deprecatedIPEntries[] = $key;
+                               $resultProxyList[] = $key;
+                               $resultProxyList[] = $value;
+                       } else {
+                               $resultProxyList[] = $value;
+                       }
+               }
+
+               if ( $deprecatedIPEntries ) {
+                       wfDeprecated(
+                               'IP addresses in the keys of $wgProxyList (found the following IP addresses in keys: ' .
+                               implode( ', ', $deprecatedIPEntries ) . ', please move them to values)', '1.30' );
+               }
+
+               $proxyListIPSet = new IPSet( $resultProxyList );
+               return $proxyListIPSet->match( $ip );
+       }
+
+       /**
+        * Whether the given IP is in a DNS blacklist.
+        *
+        * @param string $ip IP to check
+        * @param bool $checkWhitelist Whether to check the whitelist first
+        * @return bool True if blacklisted.
+        */
+       public function isDnsBlacklisted( $ip, $checkWhitelist = false ) {
+               if ( !$this->enableDnsBlacklist ||
+                       ( $checkWhitelist && in_array( $ip, $this->proxyWhitelist ) )
+               ) {
+                       return false;
+               }
+
+               return $this->inDnsBlacklist( $ip, $this->dnsBlacklistUrls );
+       }
+
+       /**
+        * Whether the given IP is in a given DNS blacklist.
+        *
+        * @param string $ip IP to check
+        * @param array $bases Array of Strings: URL of the DNS blacklist
+        * @return bool True if blacklisted.
+        */
+       private function inDnsBlacklist( $ip, array $bases ) {
+               $found = false;
+               // @todo FIXME: IPv6 ???  (https://bugs.php.net/bug.php?id=33170)
+               if ( IP::isIPv4( $ip ) ) {
+                       // Reverse IP, T23255
+                       $ipReversed = implode( '.', array_reverse( explode( '.', $ip ) ) );
+
+                       foreach ( $bases as $base ) {
+                               // Make hostname
+                               // If we have an access key, use that too (ProjectHoneypot, etc.)
+                               $basename = $base;
+                               if ( is_array( $base ) ) {
+                                       if ( count( $base ) >= 2 ) {
+                                               // Access key is 1, base URL is 0
+                                               $host = "{$base[1]}.$ipReversed.{$base[0]}";
+                                       } else {
+                                               $host = "$ipReversed.{$base[0]}";
+                                       }
+                                       $basename = $base[0];
+                               } else {
+                                       $host = "$ipReversed.$base";
+                               }
+
+                               // Send query
+                               $ipList = gethostbynamel( $host );
+
+                               if ( $ipList ) {
+                                       wfDebugLog( 'dnsblacklist', "Hostname $host is {$ipList[0]}, it's a proxy says $basename!" );
+                                       $found = true;
+                                       break;
+                               }
+
+                               wfDebugLog( 'dnsblacklist', "Requested $host, not found in $basename." );
+                       }
+               }
+
+               return $found;
+       }
+
+}
diff --git a/includes/block/BlockRestriction.php b/includes/block/BlockRestriction.php
deleted file mode 100644 (file)
index 72f6eaa..0000000
+++ /dev/null
@@ -1,433 +0,0 @@
-<?php
-/**
- * Block restriction interface.
- *
- * 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
- */
-
-namespace MediaWiki\Block;
-
-use MediaWiki\Block\Restriction\NamespaceRestriction;
-use MediaWiki\Block\Restriction\PageRestriction;
-use MediaWiki\Block\Restriction\Restriction;
-use Wikimedia\Rdbms\IResultWrapper;
-use Wikimedia\Rdbms\IDatabase;
-
-class BlockRestriction {
-
-       /**
-        * Map of all of the restriction types.
-        */
-       private static $types = [
-               PageRestriction::TYPE_ID => PageRestriction::class,
-               NamespaceRestriction::TYPE_ID => NamespaceRestriction::class,
-       ];
-
-       /**
-        * Retrieves the restrictions from the database by block id.
-        *
-        * @since 1.33
-        * @param int|array $blockId
-        * @param IDatabase|null $db
-        * @return Restriction[]
-        */
-       public static function loadByBlockId( $blockId, IDatabase $db = null ) {
-               if ( $blockId === null || $blockId === [] ) {
-                       return [];
-               }
-
-               $db = $db ?: wfGetDb( DB_REPLICA );
-
-               $result = $db->select(
-                       [ 'ipblocks_restrictions', 'page' ],
-                       [ 'ir_ipb_id', 'ir_type', 'ir_value', 'page_namespace', 'page_title' ],
-                       [ 'ir_ipb_id' => $blockId ],
-                       __METHOD__,
-                       [],
-                       [ 'page' => [ 'LEFT JOIN', [ 'ir_type' => PageRestriction::TYPE_ID, 'ir_value=page_id' ] ] ]
-               );
-
-               return self::resultToRestrictions( $result );
-       }
-
-       /**
-        * Inserts the restrictions into the database.
-        *
-        * @since 1.33
-        * @param Restriction[] $restrictions
-        * @return bool
-        */
-       public static function insert( array $restrictions ) {
-               if ( empty( $restrictions ) ) {
-                       return false;
-               }
-
-               $rows = [];
-               foreach ( $restrictions as $restriction ) {
-                       if ( !$restriction instanceof Restriction ) {
-                               continue;
-                       }
-                       $rows[] = $restriction->toRow();
-               }
-
-               if ( empty( $rows ) ) {
-                       return false;
-               }
-
-               $dbw = wfGetDB( DB_MASTER );
-
-               return $dbw->insert(
-                       'ipblocks_restrictions',
-                       $rows,
-                       __METHOD__,
-                       [ 'IGNORE' ]
-               );
-       }
-
-       /**
-        * Updates the list of restrictions. This method does not allow removing all
-        * of the restrictions. To do that, use ::deleteByBlockId().
-        *
-        * @since 1.33
-        * @param Restriction[] $restrictions
-        * @return bool
-        */
-       public static function update( array $restrictions ) {
-               $dbw = wfGetDB( DB_MASTER );
-
-               $dbw->startAtomic( __METHOD__ );
-
-               // Organize the restrictions by blockid.
-               $restrictionList = self::restrictionsByBlockId( $restrictions );
-
-               // Load the existing restrictions and organize by block id. Any block ids
-               // that were passed into this function will be used to load all of the
-               // existing restrictions. This list might be the same, or may be completely
-               // different.
-               $existingList = [];
-               $blockIds = array_keys( $restrictionList );
-               if ( !empty( $blockIds ) ) {
-                       $result = $dbw->select(
-                               [ 'ipblocks_restrictions' ],
-                               [ 'ir_ipb_id', 'ir_type', 'ir_value' ],
-                               [ 'ir_ipb_id' => $blockIds ],
-                               __METHOD__,
-                               [ 'FOR UPDATE' ]
-                       );
-
-                       $existingList = self::restrictionsByBlockId(
-                               self::resultToRestrictions( $result )
-                       );
-               }
-
-               $result = true;
-               // Perform the actions on a per block-id basis.
-               foreach ( $restrictionList as $blockId => $blockRestrictions ) {
-                       // Insert all of the restrictions first, ignoring ones that already exist.
-                       $success = self::insert( $blockRestrictions );
-
-                       // Update the result. The first false is the result, otherwise, true.
-                       $result = $success && $result;
-
-                       $restrictionsToRemove = self::restrictionsToRemove(
-                               $existingList[$blockId] ?? [],
-                               $restrictions
-                       );
-
-                       if ( empty( $restrictionsToRemove ) ) {
-                               continue;
-                       }
-
-                       $success = self::delete( $restrictionsToRemove );
-
-                       // Update the result. The first false is the result, otherwise, true.
-                       $result = $success && $result;
-               }
-
-               $dbw->endAtomic( __METHOD__ );
-
-               return $result;
-       }
-
-       /**
-        * Updates the list of restrictions by parent id.
-        *
-        * @since 1.33
-        * @param int $parentBlockId
-        * @param Restriction[] $restrictions
-        * @return bool
-        */
-       public static function updateByParentBlockId( $parentBlockId, array $restrictions ) {
-               // If removing all of the restrictions, then just delete them all.
-               if ( empty( $restrictions ) ) {
-                       return self::deleteByParentBlockId( $parentBlockId );
-               }
-
-               $parentBlockId = (int)$parentBlockId;
-
-               $db = wfGetDb( DB_MASTER );
-
-               $db->startAtomic( __METHOD__ );
-
-               $blockIds = $db->selectFieldValues(
-                       'ipblocks',
-                       'ipb_id',
-                       [ 'ipb_parent_block_id' => $parentBlockId ],
-                       __METHOD__,
-                       [ 'FOR UPDATE' ]
-               );
-
-               $result = true;
-               foreach ( $blockIds as $id ) {
-                       $success = self::update( self::setBlockId( $id, $restrictions ) );
-                       // Update the result. The first false is the result, otherwise, true.
-                       $result = $success && $result;
-               }
-
-               $db->endAtomic( __METHOD__ );
-
-               return $result;
-       }
-
-       /**
-        * Delete the restrictions.
-        *
-        * @since 1.33
-        * @param Restriction[]|null $restrictions
-        * @throws MWException
-        * @return bool
-        */
-       public static function delete( array $restrictions ) {
-               $dbw = wfGetDB( DB_MASTER );
-               $result = true;
-               foreach ( $restrictions as $restriction ) {
-                       if ( !$restriction instanceof Restriction ) {
-                               continue;
-                       }
-
-                       $success = $dbw->delete(
-                               'ipblocks_restrictions',
-                               // The restriction row is made up of a compound primary key. Therefore,
-                               // the row and the delete conditions are the same.
-                               $restriction->toRow(),
-                               __METHOD__
-                       );
-                       // Update the result. The first false is the result, otherwise, true.
-                       $result = $success && $result;
-               }
-
-               return $result;
-       }
-
-       /**
-        * Delete the restrictions by Block ID.
-        *
-        * @since 1.33
-        * @param int|array $blockId
-        * @throws MWException
-        * @return bool
-        */
-       public static function deleteByBlockId( $blockId ) {
-               $dbw = wfGetDB( DB_MASTER );
-               return $dbw->delete(
-                       'ipblocks_restrictions',
-                       [ 'ir_ipb_id' => $blockId ],
-                       __METHOD__
-               );
-       }
-
-       /**
-        * Delete the restrictions by Parent Block ID.
-        *
-        * @since 1.33
-        * @param int|array $parentBlockId
-        * @throws MWException
-        * @return bool
-        */
-       public static function deleteByParentBlockId( $parentBlockId ) {
-               $dbw = wfGetDB( DB_MASTER );
-               return $dbw->deleteJoin(
-                       'ipblocks_restrictions',
-                       'ipblocks',
-                       'ir_ipb_id',
-                       'ipb_id',
-                       [ 'ipb_parent_block_id' => $parentBlockId ],
-                       __METHOD__
-               );
-       }
-
-       /**
-        * Checks if two arrays of Restrictions are effectively equal. This is a loose
-        * equality check as the restrictions do not have to contain the same block
-        * ids.
-        *
-        * @since 1.33
-        * @param Restriction[] $a
-        * @param Restriction[] $b
-        * @return bool
-        */
-       public static function equals( array $a, array $b ) {
-               $filter = function ( $restriction ) {
-                       return $restriction instanceof Restriction;
-               };
-
-               // Ensure that every item in the array is a Restriction. This prevents a
-               // fatal error from calling Restriction::getHash if something in the array
-               // is not a restriction.
-               $a = array_filter( $a, $filter );
-               $b = array_filter( $b, $filter );
-
-               $aCount = count( $a );
-               $bCount = count( $b );
-
-               // If the count is different, then they are obviously a different set.
-               if ( $aCount !== $bCount ) {
-                       return false;
-               }
-
-               // If both sets contain no items, then they are the same set.
-               if ( $aCount === 0 && $bCount === 0 ) {
-                       return true;
-               }
-
-               $hasher = function ( $r ) {
-                       return $r->getHash();
-               };
-
-               $aHashes = array_map( $hasher, $a );
-               $bHashes = array_map( $hasher, $b );
-
-               sort( $aHashes );
-               sort( $bHashes );
-
-               return $aHashes === $bHashes;
-       }
-
-       /**
-        * Set the blockId on a set of restrictions and return a new set.
-        *
-        * @since 1.33
-        * @param int $blockId
-        * @param Restriction[] $restrictions
-        * @return Restriction[]
-        */
-       public static function setBlockId( $blockId, array $restrictions ) {
-               $blockRestrictions = [];
-
-               foreach ( $restrictions as $restriction ) {
-                       if ( !$restriction instanceof Restriction ) {
-                               continue;
-                       }
-
-                       // Clone the restriction so any references to the current restriction are
-                       // not suddenly changed to a different blockId.
-                       $restriction = clone $restriction;
-                       $restriction->setBlockId( $blockId );
-
-                       $blockRestrictions[] = $restriction;
-               }
-
-               return $blockRestrictions;
-       }
-
-       /**
-        * Get the restrictions that should be removed, which are existing
-        * restrictions that are not in the new list of restrictions.
-        *
-        * @param Restriction[] $existing
-        * @param Restriction[] $new
-        * @return array
-        */
-       private static function restrictionsToRemove( array $existing, array $new ) {
-               return array_filter( $existing, function ( $e ) use ( $new ) {
-                       foreach ( $new as $restriction ) {
-                               if ( !$restriction instanceof Restriction ) {
-                                       continue;
-                               }
-
-                               if ( $restriction->equals( $e ) ) {
-                                       return false;
-                               }
-                       }
-
-                       return true;
-               } );
-       }
-
-       /**
-        * Converts an array of restrictions to an associative array of restrictions
-        * where the keys are the block ids.
-        *
-        * @param Restriction[] $restrictions
-        * @return array
-        */
-       private static function restrictionsByBlockId( array $restrictions ) {
-               $blockRestrictions = [];
-
-               foreach ( $restrictions as $restriction ) {
-                       // Ensure that all of the items in the array are restrictions.
-                       if ( !$restriction instanceof Restriction ) {
-                               continue;
-                       }
-
-                       if ( !isset( $blockRestrictions[$restriction->getBlockId()] ) ) {
-                               $blockRestrictions[$restriction->getBlockId()] = [];
-                       }
-
-                       $blockRestrictions[$restriction->getBlockId()][] = $restriction;
-               }
-
-               return $blockRestrictions;
-       }
-
-       /**
-        * Convert an Result Wrapper to an array of restrictions.
-        *
-        * @param IResultWrapper $result
-        * @return Restriction[]
-        */
-       private static function resultToRestrictions( IResultWrapper $result ) {
-               $restrictions = [];
-               foreach ( $result as $row ) {
-                       $restriction = self::rowToRestriction( $row );
-
-                       if ( !$restriction ) {
-                               continue;
-                       }
-
-                       $restrictions[] = $restriction;
-               }
-
-               return $restrictions;
-       }
-
-       /**
-        * Convert a result row from the database into a restriction object.
-        *
-        * @param \stdClass $row
-        * @return Restriction|null
-        */
-       private static function rowToRestriction( \stdClass $row ) {
-               if ( array_key_exists( (int)$row->ir_type, self::$types ) ) {
-                       $class = self::$types[ (int)$row->ir_type ];
-                       return call_user_func( [ $class, 'newFromRow' ], $row );
-               }
-
-               return null;
-       }
-}
diff --git a/includes/block/BlockRestrictionStore.php b/includes/block/BlockRestrictionStore.php
new file mode 100644 (file)
index 0000000..d242c87
--- /dev/null
@@ -0,0 +1,449 @@
+<?php
+/**
+ * Block restriction interface.
+ *
+ * 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
+ */
+
+namespace MediaWiki\Block;
+
+use MediaWiki\Block\Restriction\NamespaceRestriction;
+use MediaWiki\Block\Restriction\PageRestriction;
+use MediaWiki\Block\Restriction\Restriction;
+use MWException;
+use Wikimedia\Rdbms\IResultWrapper;
+use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\ILoadBalancer;
+
+class BlockRestrictionStore {
+
+       /**
+        * Map of all of the restriction types.
+        */
+       private $types = [
+               PageRestriction::TYPE_ID => PageRestriction::class,
+               NamespaceRestriction::TYPE_ID => NamespaceRestriction::class,
+       ];
+
+       /**
+        * @var ILoadBalancer
+        */
+       private $loadBalancer;
+
+       /*
+        * @param LoadBalancer $loadBalancer load balancer for acquiring database connections
+        */
+       public function __construct( ILoadBalancer $loadBalancer ) {
+               $this->loadBalancer = $loadBalancer;
+       }
+
+       /**
+        * Retrieves the restrictions from the database by block id.
+        *
+        * @since 1.33
+        * @param int|array $blockId
+        * @param IDatabase|null $db
+        * @return Restriction[]
+        */
+       public function loadByBlockId( $blockId, IDatabase $db = null ) {
+               if ( $blockId === null || $blockId === [] ) {
+                       return [];
+               }
+
+               $db = $db ?: $this->loadBalancer->getConnection( DB_REPLICA );
+
+               $result = $db->select(
+                       [ 'ipblocks_restrictions', 'page' ],
+                       [ 'ir_ipb_id', 'ir_type', 'ir_value', 'page_namespace', 'page_title' ],
+                       [ 'ir_ipb_id' => $blockId ],
+                       __METHOD__,
+                       [],
+                       [ 'page' => [ 'LEFT JOIN', [ 'ir_type' => PageRestriction::TYPE_ID, 'ir_value=page_id' ] ] ]
+               );
+
+               return $this->resultToRestrictions( $result );
+       }
+
+       /**
+        * Inserts the restrictions into the database.
+        *
+        * @since 1.33
+        * @param Restriction[] $restrictions
+        * @return bool
+        */
+       public function insert( array $restrictions ) {
+               if ( !$restrictions ) {
+                       return false;
+               }
+
+               $rows = [];
+               foreach ( $restrictions as $restriction ) {
+                       if ( !$restriction instanceof Restriction ) {
+                               continue;
+                       }
+                       $rows[] = $restriction->toRow();
+               }
+
+               if ( !$rows ) {
+                       return false;
+               }
+
+               $dbw = $this->loadBalancer->getConnection( DB_MASTER );
+
+               $dbw->insert(
+                       'ipblocks_restrictions',
+                       $rows,
+                       __METHOD__,
+                       [ 'IGNORE' ]
+               );
+
+               return true;
+       }
+
+       /**
+        * Updates the list of restrictions. This method does not allow removing all
+        * of the restrictions. To do that, use ::deleteByBlockId().
+        *
+        * @since 1.33
+        * @param Restriction[] $restrictions
+        * @return bool
+        */
+       public function update( array $restrictions ) {
+               $dbw = $this->loadBalancer->getConnection( DB_MASTER );
+
+               $dbw->startAtomic( __METHOD__ );
+
+               // Organize the restrictions by blockid.
+               $restrictionList = $this->restrictionsByBlockId( $restrictions );
+
+               // Load the existing restrictions and organize by block id. Any block ids
+               // that were passed into this function will be used to load all of the
+               // existing restrictions. This list might be the same, or may be completely
+               // different.
+               $existingList = [];
+               $blockIds = array_keys( $restrictionList );
+               if ( !empty( $blockIds ) ) {
+                       $result = $dbw->select(
+                               [ 'ipblocks_restrictions' ],
+                               [ 'ir_ipb_id', 'ir_type', 'ir_value' ],
+                               [ 'ir_ipb_id' => $blockIds ],
+                               __METHOD__,
+                               [ 'FOR UPDATE' ]
+                       );
+
+                       $existingList = $this->restrictionsByBlockId(
+                               $this->resultToRestrictions( $result )
+                       );
+               }
+
+               $result = true;
+               // Perform the actions on a per block-id basis.
+               foreach ( $restrictionList as $blockId => $blockRestrictions ) {
+                       // Insert all of the restrictions first, ignoring ones that already exist.
+                       $success = $this->insert( $blockRestrictions );
+
+                       // Update the result. The first false is the result, otherwise, true.
+                       $result = $success && $result;
+
+                       $restrictionsToRemove = $this->restrictionsToRemove(
+                               $existingList[$blockId] ?? [],
+                               $restrictions
+                       );
+
+                       if ( empty( $restrictionsToRemove ) ) {
+                               continue;
+                       }
+
+                       $success = $this->delete( $restrictionsToRemove );
+
+                       // Update the result. The first false is the result, otherwise, true.
+                       $result = $success && $result;
+               }
+
+               $dbw->endAtomic( __METHOD__ );
+
+               return $result;
+       }
+
+       /**
+        * Updates the list of restrictions by parent id.
+        *
+        * @since 1.33
+        * @param int $parentBlockId
+        * @param Restriction[] $restrictions
+        * @return bool
+        */
+       public function updateByParentBlockId( $parentBlockId, array $restrictions ) {
+               // If removing all of the restrictions, then just delete them all.
+               if ( empty( $restrictions ) ) {
+                       return $this->deleteByParentBlockId( $parentBlockId );
+               }
+
+               $parentBlockId = (int)$parentBlockId;
+
+               $db = $this->loadBalancer->getConnection( DB_MASTER );
+
+               $db->startAtomic( __METHOD__ );
+
+               $blockIds = $db->selectFieldValues(
+                       'ipblocks',
+                       'ipb_id',
+                       [ 'ipb_parent_block_id' => $parentBlockId ],
+                       __METHOD__,
+                       [ 'FOR UPDATE' ]
+               );
+
+               $result = true;
+               foreach ( $blockIds as $id ) {
+                       $success = $this->update( $this->setBlockId( $id, $restrictions ) );
+                       // Update the result. The first false is the result, otherwise, true.
+                       $result = $success && $result;
+               }
+
+               $db->endAtomic( __METHOD__ );
+
+               return $result;
+       }
+
+       /**
+        * Delete the restrictions.
+        *
+        * @since 1.33
+        * @param Restriction[]|null $restrictions
+        * @throws MWException
+        * @return bool
+        */
+       public function delete( array $restrictions ) {
+               $dbw = $this->loadBalancer->getConnection( DB_MASTER );
+               $result = true;
+               foreach ( $restrictions as $restriction ) {
+                       if ( !$restriction instanceof Restriction ) {
+                               continue;
+                       }
+
+                       $success = $dbw->delete(
+                               'ipblocks_restrictions',
+                               // The restriction row is made up of a compound primary key. Therefore,
+                               // the row and the delete conditions are the same.
+                               $restriction->toRow(),
+                               __METHOD__
+                       );
+                       // Update the result. The first false is the result, otherwise, true.
+                       $result = $success && $result;
+               }
+
+               return $result;
+       }
+
+       /**
+        * Delete the restrictions by Block ID.
+        *
+        * @since 1.33
+        * @param int|array $blockId
+        * @throws MWException
+        * @return bool
+        */
+       public function deleteByBlockId( $blockId ) {
+               $dbw = $this->loadBalancer->getConnection( DB_MASTER );
+               return $dbw->delete(
+                       'ipblocks_restrictions',
+                       [ 'ir_ipb_id' => $blockId ],
+                       __METHOD__
+               );
+       }
+
+       /**
+        * Delete the restrictions by Parent Block ID.
+        *
+        * @since 1.33
+        * @param int|array $parentBlockId
+        * @throws MWException
+        * @return bool
+        */
+       public function deleteByParentBlockId( $parentBlockId ) {
+               $dbw = $this->loadBalancer->getConnection( DB_MASTER );
+               return $dbw->deleteJoin(
+                       'ipblocks_restrictions',
+                       'ipblocks',
+                       'ir_ipb_id',
+                       'ipb_id',
+                       [ 'ipb_parent_block_id' => $parentBlockId ],
+                       __METHOD__
+               );
+       }
+
+       /**
+        * Checks if two arrays of Restrictions are effectively equal. This is a loose
+        * equality check as the restrictions do not have to contain the same block
+        * ids.
+        *
+        * @since 1.33
+        * @param Restriction[] $a
+        * @param Restriction[] $b
+        * @return bool
+        */
+       public function equals( array $a, array $b ) {
+               $filter = function ( $restriction ) {
+                       return $restriction instanceof Restriction;
+               };
+
+               // Ensure that every item in the array is a Restriction. This prevents a
+               // fatal error from calling Restriction::getHash if something in the array
+               // is not a restriction.
+               $a = array_filter( $a, $filter );
+               $b = array_filter( $b, $filter );
+
+               $aCount = count( $a );
+               $bCount = count( $b );
+
+               // If the count is different, then they are obviously a different set.
+               if ( $aCount !== $bCount ) {
+                       return false;
+               }
+
+               // If both sets contain no items, then they are the same set.
+               if ( $aCount === 0 && $bCount === 0 ) {
+                       return true;
+               }
+
+               $hasher = function ( $r ) {
+                       return $r->getHash();
+               };
+
+               $aHashes = array_map( $hasher, $a );
+               $bHashes = array_map( $hasher, $b );
+
+               sort( $aHashes );
+               sort( $bHashes );
+
+               return $aHashes === $bHashes;
+       }
+
+       /**
+        * Set the blockId on a set of restrictions and return a new set.
+        *
+        * @since 1.33
+        * @param int $blockId
+        * @param Restriction[] $restrictions
+        * @return Restriction[]
+        */
+       public function setBlockId( $blockId, array $restrictions ) {
+               $blockRestrictions = [];
+
+               foreach ( $restrictions as $restriction ) {
+                       if ( !$restriction instanceof Restriction ) {
+                               continue;
+                       }
+
+                       // Clone the restriction so any references to the current restriction are
+                       // not suddenly changed to a different blockId.
+                       $restriction = clone $restriction;
+                       $restriction->setBlockId( $blockId );
+
+                       $blockRestrictions[] = $restriction;
+               }
+
+               return $blockRestrictions;
+       }
+
+       /**
+        * Get the restrictions that should be removed, which are existing
+        * restrictions that are not in the new list of restrictions.
+        *
+        * @param Restriction[] $existing
+        * @param Restriction[] $new
+        * @return array
+        */
+       private function restrictionsToRemove( array $existing, array $new ) {
+               return array_filter( $existing, function ( $e ) use ( $new ) {
+                       foreach ( $new as $restriction ) {
+                               if ( !$restriction instanceof Restriction ) {
+                                       continue;
+                               }
+
+                               if ( $restriction->equals( $e ) ) {
+                                       return false;
+                               }
+                       }
+
+                       return true;
+               } );
+       }
+
+       /**
+        * Converts an array of restrictions to an associative array of restrictions
+        * where the keys are the block ids.
+        *
+        * @param Restriction[] $restrictions
+        * @return array
+        */
+       private function restrictionsByBlockId( array $restrictions ) {
+               $blockRestrictions = [];
+
+               foreach ( $restrictions as $restriction ) {
+                       // Ensure that all of the items in the array are restrictions.
+                       if ( !$restriction instanceof Restriction ) {
+                               continue;
+                       }
+
+                       if ( !isset( $blockRestrictions[$restriction->getBlockId()] ) ) {
+                               $blockRestrictions[$restriction->getBlockId()] = [];
+                       }
+
+                       $blockRestrictions[$restriction->getBlockId()][] = $restriction;
+               }
+
+               return $blockRestrictions;
+       }
+
+       /**
+        * Convert an Result Wrapper to an array of restrictions.
+        *
+        * @param IResultWrapper $result
+        * @return Restriction[]
+        */
+       private function resultToRestrictions( IResultWrapper $result ) {
+               $restrictions = [];
+               foreach ( $result as $row ) {
+                       $restriction = $this->rowToRestriction( $row );
+
+                       if ( !$restriction ) {
+                               continue;
+                       }
+
+                       $restrictions[] = $restriction;
+               }
+
+               return $restrictions;
+       }
+
+       /**
+        * Convert a result row from the database into a restriction object.
+        *
+        * @param \stdClass $row
+        * @return Restriction|null
+        */
+       private function rowToRestriction( \stdClass $row ) {
+               if ( array_key_exists( (int)$row->ir_type, $this->types ) ) {
+                       $class = $this->types[ (int)$row->ir_type ];
+                       return call_user_func( [ $class, 'newFromRow' ], $row );
+               }
+
+               return null;
+       }
+}
index 20678ad..a010e83 100644 (file)
@@ -25,12 +25,14 @@ namespace MediaWiki\Block\Restriction;
 abstract class AbstractRestriction implements Restriction {
 
        /**
-        * @var string
+        * String constant identifying the type of restriction. Expected to be overriden in subclasses
+        * with a non-empty string value.
         */
        const TYPE = '';
 
        /**
-        * @var int
+        * Numeric type identifier. Expected to be overriden in subclasses with a non-zero integer
+        * number. Must not exceed 127 to fit into a TINYINT database field.
         */
        const TYPE_ID = 0;
 
@@ -97,6 +99,7 @@ abstract class AbstractRestriction implements Restriction {
         * @inheritDoc
         */
        public static function newFromRow( \stdClass $row ) {
+               // @phan-suppress-next-line PhanTypeInstantiateAbstract
                return new static( $row->ir_ipb_id, $row->ir_value );
        }
 
index fdf223a..d717fe7 100644 (file)
@@ -61,7 +61,7 @@ interface Restriction {
         * Gets the id of the type of restriction. This id is used in the database.
         *
         * @since 1.33
-        * @return string
+        * @return int
         */
        public static function getTypeId();
 
diff --git a/includes/block/SystemBlock.php b/includes/block/SystemBlock.php
new file mode 100644 (file)
index 0000000..2a8c663
--- /dev/null
@@ -0,0 +1,107 @@
+<?php
+/**
+ * Class for temporary blocks created on enforcement.
+ *
+ * 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
+ */
+
+namespace MediaWiki\Block;
+
+use IContextSource;
+
+/**
+ * System blocks are temporary blocks that are created on enforcement (e.g.
+ * from IP blacklists) and are not saved to the database. The target of a
+ * system block is an IP address. System blocks do not give rise to
+ * autoblocks and are not tracked with cookies.
+ *
+ * @since 1.34
+ */
+class SystemBlock extends AbstractBlock {
+       /** @var string|null */
+       private $systemBlockType;
+
+       /**
+        * Create a new block with specified parameters on a user, IP or IP range.
+        *
+        * @param array $options Parameters of the block:
+        *     systemBlock string   Indicate that this block is automatically
+        *                          created by MediaWiki rather than being stored
+        *                          in the database. Value is a string to return
+        *                          from self::getSystemBlockType().
+        */
+       function __construct( $options = [] ) {
+               parent::__construct( $options );
+
+               $defaults = [
+                       'systemBlock' => null,
+               ];
+
+               $options += $defaults;
+
+               $this->systemBlockType = $options['systemBlock'];
+       }
+
+       /**
+        * Get the system block type, if any. A SystemBlock can have the following types:
+        * - 'proxy': the IP is blacklisted in $wgProxyList
+        * - 'dnsbl': the IP is associated with a blacklisted domain in $wgDnsBlacklistUrls
+        * - 'wgSoftBlockRanges': the IP is covered by $wgSoftBlockRanges
+        * - 'global-block': for backwards compatability with the UserIsBlockedGlobally hook
+        *
+        * @since 1.29
+        * @return string|null
+        */
+       public function getSystemBlockType() {
+               return $this->systemBlockType;
+       }
+
+       /**
+        * @inheritDoc
+        */
+       public function getPermissionsError( IContextSource $context ) {
+               $params = $this->getBlockErrorParams( $context );
+               // TODO: Clean up error messages params so we don't have to do this
+               $params[ 4 ] = $this->getSystemBlockType();
+
+               $msg = 'systemblockedtext';
+
+               array_unshift( $params, $msg );
+
+               return $params;
+       }
+
+       /**
+        * @inheritDoc
+        */
+       public function appliesToPasswordReset() {
+               switch ( $this->getSystemBlockType() ) {
+                       case null:
+                       case 'global-block':
+                               return $this->isCreateAccountBlocked();
+                       case 'proxy':
+                               return true;
+                       case 'dnsbl':
+                       case 'wgSoftBlockRanges':
+                               return false;
+                       default:
+                               return true;
+               }
+       }
+
+}
index d7669eb..d798ddb 100644 (file)
@@ -221,13 +221,11 @@ class CacheHelper implements ICacheHelper {
                                } else {
                                        $value = array_shift( $this->cachedChunks );
                                }
+                       } elseif ( array_key_exists( $key, $this->cachedChunks ) ) {
+                               $value = $this->cachedChunks[$key];
+                               unset( $this->cachedChunks[$key] );
                        } else {
-                               if ( array_key_exists( $key, $this->cachedChunks ) ) {
-                                       $value = $this->cachedChunks[$key];
-                                       unset( $this->cachedChunks[$key] );
-                               } else {
-                                       wfWarn( "There is no item with key '$key' in this->cachedChunks in " . __METHOD__ );
-                               }
+                               wfWarn( "There is no item with key '$key' in this->cachedChunks in " . __METHOD__ );
                        }
                } else {
                        if ( !is_array( $args ) ) {
@@ -290,7 +288,9 @@ class CacheHelper implements ICacheHelper {
                        throw new MWException( 'No cache key set, so cannot obtain or save the CacheHelper values.' );
                }
 
-               return wfMemcKey( ...array_values( $this->cacheKey ) );
+               return ObjectCache::getLocalClusterInstance()->makeKey(
+                       ...array_values( $this->cacheKey )
+               );
        }
 
        /**
index 7228814..eedc3c6 100644 (file)
@@ -34,6 +34,13 @@ class GenderCache {
        protected $misses = 0;
        protected $missLimit = 1000;
 
+       /** @var NamespaceInfo */
+       private $nsInfo;
+
+       public function __construct( NamespaceInfo $nsInfo = null ) {
+               $this->nsInfo = $nsInfo ?? MediaWikiServices::getInstance()->getNamespaceInfo();
+       }
+
        /**
         * @deprecated in 1.28 see MediaWikiServices::getInstance()->getGenderCache()
         * @return GenderCache
@@ -97,7 +104,7 @@ class GenderCache {
        public function doLinkBatch( $data, $caller = '' ) {
                $users = [];
                foreach ( $data as $ns => $pagenames ) {
-                       if ( !MWNamespace::hasGenderDistinction( $ns ) ) {
+                       if ( !$this->nsInfo->hasGenderDistinction( $ns ) ) {
                                continue;
                        }
                        foreach ( array_keys( $pagenames ) as $username ) {
@@ -122,7 +129,7 @@ class GenderCache {
                        if ( !$titleObj ) {
                                continue;
                        }
-                       if ( !MWNamespace::hasGenderDistinction( $titleObj->getNamespace() ) ) {
+                       if ( !$this->nsInfo->hasGenderDistinction( $titleObj->getNamespace() ) ) {
                                continue;
                        }
                        $users[] = $titleObj->getText();
index 3a89066..a0d61b2 100644 (file)
@@ -128,10 +128,8 @@ class HTMLFileCache extends FileCacheBase {
                        return false;
                }
 
-               if ( $mode === self::MODE_NORMAL ) {
-                       if ( $user->getNewtalk() ) {
-                               return false;
-                       }
+               if ( ( $mode === self::MODE_NORMAL ) && $user->getNewtalk() ) {
+                       return false;
                }
 
                // Allow extensions to disable caching
@@ -211,18 +209,14 @@ class HTMLFileCache extends FileCacheBase {
                }
 
                // gzip output to buffer as needed and set headers...
-               if ( $this->useGzip() ) {
-                       // @todo Ugly wfClientAcceptsGzip() function - use context!
-                       if ( wfClientAcceptsGzip() ) {
-                               header( 'Content-Encoding: gzip' );
+               // @todo Ugly wfClientAcceptsGzip() function - use context!
+               if ( $this->useGzip() && wfClientAcceptsGzip() ) {
+                       header( 'Content-Encoding: gzip' );
 
-                               return $compressed;
-                       } else {
-                               return $text;
-                       }
-               } else {
-                       return $text;
+                       return $compressed;
                }
+
+               return $text;
        }
 
        /**
index c13f95e..1bcf948 100644 (file)
@@ -45,17 +45,29 @@ class LinkCache {
        /** @var TitleFormatter */
        private $titleFormatter;
 
+       /** @var NamespaceInfo */
+       private $nsInfo;
+
        /**
         * How many Titles to store. There are two caches, so the amount actually
         * stored in memory can be up to twice this.
         */
        const MAX_SIZE = 10000;
 
-       public function __construct( TitleFormatter $titleFormatter, WANObjectCache $cache ) {
+       public function __construct(
+               TitleFormatter $titleFormatter,
+               WANObjectCache $cache,
+               NamespaceInfo $nsInfo = null
+       ) {
+               if ( !$nsInfo ) {
+                       wfDeprecated( __METHOD__ . ' with no NamespaceInfo argument', '1.34' );
+                       $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
+               }
                $this->goodLinks = new MapCacheLRU( self::MAX_SIZE );
                $this->badLinks = new MapCacheLRU( self::MAX_SIZE );
                $this->wanCache = $cache;
                $this->titleFormatter = $titleFormatter;
+               $this->nsInfo = $nsInfo;
        }
 
        /**
@@ -231,9 +243,7 @@ class LinkCache {
         */
        public function addLinkObj( LinkTarget $nt ) {
                $key = $this->titleFormatter->getPrefixedDBkey( $nt );
-               if ( $this->isBadLink( $key ) || $nt->isExternal()
-                       || $nt->inNamespace( NS_SPECIAL )
-               ) {
+               if ( $this->isBadLink( $key ) || $nt->isExternal() || $nt->getNamespace() < 0 ) {
                        return 0;
                }
                $id = $this->getGoodLinkID( $key );
@@ -300,11 +310,11 @@ class LinkCache {
                        return true;
                }
                // Focus on transcluded pages more than the main content
-               if ( MWNamespace::isContent( $ns ) ) {
+               if ( $this->nsInfo->isContent( $ns ) ) {
                        return false;
                }
                // Non-talk extension namespaces (e.g. NS_MODULE)
-               return ( $ns >= 100 && MWNamespace::isSubject( $ns ) );
+               return ( $ns >= 100 && $this->nsInfo->isSubject( $ns ) );
        }
 
        private function fetchPageRow( IDatabase $db, LinkTarget $nt ) {
diff --git a/includes/cache/MessageBlobStore.php b/includes/cache/MessageBlobStore.php
deleted file mode 100644 (file)
index ceb51f2..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-<?php
-/**
- * Message blobs storage used by ResourceLoader.
- *
- * 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
- * @author Roan Kattouw
- * @author Trevor Parscal
- * @author Timo Tijhof
- */
-
-use MediaWiki\MediaWikiServices;
-use Psr\Log\LoggerAwareInterface;
-use Psr\Log\LoggerInterface;
-use Psr\Log\NullLogger;
-use Wikimedia\Rdbms\Database;
-
-/**
- * This class generates message blobs for use by ResourceLoader modules.
- *
- * A message blob is a JSON object containing the interface messages for a certain module in
- * a certain language.
- */
-class MessageBlobStore implements LoggerAwareInterface {
-
-       /* @var ResourceLoader */
-       private $resourceloader;
-
-       /**
-        * @var LoggerInterface
-        */
-       protected $logger;
-
-       /**
-        * @var WANObjectCache
-        */
-       protected $wanCache;
-
-       /**
-        * @param ResourceLoader $rl
-        * @param LoggerInterface|null $logger
-        */
-       public function __construct( ResourceLoader $rl, LoggerInterface $logger = null ) {
-               $this->resourceloader = $rl;
-               $this->logger = $logger ?: new NullLogger();
-               $this->wanCache = MediaWikiServices::getInstance()->getMainWANObjectCache();
-       }
-
-       /**
-        * @since 1.27
-        * @param LoggerInterface $logger
-        */
-       public function setLogger( LoggerInterface $logger ) {
-               $this->logger = $logger;
-       }
-
-       /**
-        * Get the message blob for a module
-        *
-        * @since 1.27
-        * @param ResourceLoaderModule $module
-        * @param string $lang Language code
-        * @return string JSON
-        */
-       public function getBlob( ResourceLoaderModule $module, $lang ) {
-               $blobs = $this->getBlobs( [ $module->getName() => $module ], $lang );
-               return $blobs[$module->getName()];
-       }
-
-       /**
-        * Get the message blobs for a set of modules
-        *
-        * @since 1.27
-        * @param ResourceLoaderModule[] $modules Array of module objects keyed by name
-        * @param string $lang Language code
-        * @return array An array mapping module names to message blobs
-        */
-       public function getBlobs( array $modules, $lang ) {
-               // Each cache key for a message blob by module name and language code also has a generic
-               // check key without language code. This is used to invalidate any and all language subkeys
-               // that exist for a module from the updateMessage() method.
-               $cache = $this->wanCache;
-               $checkKeys = [
-                       // Global check key, see clear()
-                       $cache->makeKey( __CLASS__ )
-               ];
-               $cacheKeys = [];
-               foreach ( $modules as $name => $module ) {
-                       $cacheKey = $this->makeCacheKey( $module, $lang );
-                       $cacheKeys[$name] = $cacheKey;
-                       // Per-module check key, see updateMessage()
-                       $checkKeys[$cacheKey][] = $cache->makeKey( __CLASS__, $name );
-               }
-               $curTTLs = [];
-               $result = $cache->getMulti( array_values( $cacheKeys ), $curTTLs, $checkKeys );
-
-               $blobs = [];
-               foreach ( $modules as $name => $module ) {
-                       $key = $cacheKeys[$name];
-                       if ( !isset( $result[$key] ) || $curTTLs[$key] === null || $curTTLs[$key] < 0 ) {
-                               $blobs[$name] = $this->recacheMessageBlob( $key, $module, $lang );
-                       } else {
-                               // Use unexpired cache
-                               $blobs[$name] = $result[$key];
-                       }
-               }
-               return $blobs;
-       }
-
-       /**
-        * @deprecated since 1.27 Use getBlobs() instead
-        * @return array
-        */
-       public function get( ResourceLoader $resourceLoader, $modules, $lang ) {
-               return $this->getBlobs( $modules, $lang );
-       }
-
-       /**
-        * @since 1.27
-        * @param ResourceLoaderModule $module
-        * @param string $lang
-        * @return string Cache key
-        */
-       private function makeCacheKey( ResourceLoaderModule $module, $lang ) {
-               $messages = array_values( array_unique( $module->getMessages() ) );
-               sort( $messages );
-               return $this->wanCache->makeKey( __CLASS__, $module->getName(), $lang,
-                       md5( json_encode( $messages ) )
-               );
-       }
-
-       /**
-        * @since 1.27
-        * @param string $cacheKey
-        * @param ResourceLoaderModule $module
-        * @param string $lang
-        * @return string JSON blob
-        */
-       protected function recacheMessageBlob( $cacheKey, ResourceLoaderModule $module, $lang ) {
-               $blob = $this->generateMessageBlob( $module, $lang );
-               $cache = $this->wanCache;
-               $cache->set( $cacheKey, $blob,
-                       // Add part of a day to TTL to avoid all modules expiring at once
-                       $cache::TTL_WEEK + mt_rand( 0, $cache::TTL_DAY ),
-                       Database::getCacheSetOptions( wfGetDB( DB_REPLICA ) )
-               );
-               return $blob;
-       }
-
-       /**
-        * Invalidate cache keys for modules using this message key.
-        * Called by MessageCache when a message has changed.
-        *
-        * @param string $key Message key
-        */
-       public function updateMessage( $key ) {
-               $moduleNames = $this->getResourceLoader()->getModulesByMessage( $key );
-               foreach ( $moduleNames as $moduleName ) {
-                       // Uses a holdoff to account for database replica DB lag (for MessageCache)
-                       $this->wanCache->touchCheckKey( $this->wanCache->makeKey( __CLASS__, $moduleName ) );
-               }
-       }
-
-       /**
-        * Invalidate cache keys for all known modules.
-        * Called by LocalisationCache after cache is regenerated.
-        */
-       public function clear() {
-               $cache = $this->wanCache;
-               // Disable holdoff because this invalidates all modules and also not needed since
-               // LocalisationCache is stored outside the database and doesn't have lag.
-               $cache->touchCheckKey( $cache->makeKey( __CLASS__ ), $cache::HOLDOFF_NONE );
-       }
-
-       /**
-        * @since 1.27
-        * @return ResourceLoader
-        */
-       protected function getResourceLoader() {
-               return $this->resourceloader;
-       }
-
-       /**
-        * @since 1.27
-        * @param string $key Message key
-        * @param string $lang Language code
-        * @return string
-        */
-       protected function fetchMessage( $key, $lang ) {
-               $message = wfMessage( $key )->inLanguage( $lang );
-               $value = $message->plain();
-               if ( !$message->exists() ) {
-                       $this->logger->warning( 'Failed to find {messageKey} ({lang})', [
-                               'messageKey' => $key,
-                               'lang' => $lang,
-                       ] );
-               }
-               return $value;
-       }
-
-       /**
-        * Generate the message blob for a given module in a given language.
-        *
-        * @param ResourceLoaderModule $module
-        * @param string $lang Language code
-        * @return string JSON blob
-        */
-       private function generateMessageBlob( ResourceLoaderModule $module, $lang ) {
-               $messages = [];
-               foreach ( $module->getMessages() as $key ) {
-                       $messages[$key] = $this->fetchMessage( $key, $lang );
-               }
-
-               $json = FormatJson::encode( (object)$messages );
-               // @codeCoverageIgnoreStart
-               if ( $json === false ) {
-                       $this->logger->warning( 'Failed to encode message blob for {module} ({lang})', [
-                               'module' => $module->getName(),
-                               'lang' => $lang,
-                       ] );
-                       $json = '{}';
-               }
-               // codeCoverageIgnoreEnd
-               return $json;
-       }
-}
index e78dfa1..328cc2f 100644 (file)
@@ -540,7 +540,10 @@ class MessageCache {
                $res = $dbr->select(
                        $revQuery['tables'],
                        $revQuery['fields'],
-                       array_merge( $conds, [ 'page_len <= ' . intval( $wgMaxMsgCacheEntrySize ) ] ),
+                       array_merge( $conds, [
+                               'page_len <= ' . intval( $wgMaxMsgCacheEntrySize ),
+                               'page_latest = rev_id' // get the latest revision only
+                       ] ),
                        __METHOD__ . "($code)-small",
                        [],
                        $revQuery['joins']
@@ -715,8 +718,7 @@ class MessageCache {
                $this->wanCache->touchCheckKey( $this->getCheckKey( $code ) );
 
                // Purge the messages in the message blob store and fire any hook handlers
-               $resourceloader = RequestContext::getMain()->getOutput()->getResourceLoader();
-               $blobStore = $resourceloader->getMessageBlobStore();
+               $blobStore = MediaWikiServices::getInstance()->getResourceLoader()->getMessageBlobStore();
                foreach ( $replacements as list( $title, $msg ) ) {
                        $blobStore->updateMessage( $this->contLang->lcfirst( $msg ) );
                        Hooks::run( 'MessageCacheReplace', [ $title, $newTextByTitle[$title] ] );
@@ -1200,18 +1202,18 @@ class MessageCache {
         * @return Parser
         */
        public function getParser() {
-               global $wgParser, $wgParserConf;
-
-               if ( !$this->mParser && isset( $wgParser ) ) {
+               global $wgParserConf;
+               if ( !$this->mParser ) {
+                       $parser = MediaWikiServices::getInstance()->getParser();
                        # Do some initialisation so that we don't have to do it twice
-                       $wgParser->firstCallInit();
+                       $parser->firstCallInit();
                        # Clone it and store it
                        $class = $wgParserConf['class'];
                        if ( $class == ParserDiffTest::class ) {
                                # Uncloneable
                                $this->mParser = new $class( $wgParserConf );
                        } else {
-                               $this->mParser = clone $wgParser;
+                               $this->mParser = clone $parser;
                        }
                }
 
index 8d199e2..a8f542f 100644 (file)
@@ -75,22 +75,22 @@ class FileDependency extends CacheDependency {
                        if ( $this->timestamp === false ) {
                                # Still nonexistent
                                return false;
-                       } else {
-                               # Deleted
-                               wfDebug( "Dependency triggered: {$this->filename} deleted.\n" );
-
-                               return true;
                        }
-               } else {
-                       if ( $lastmod > $this->timestamp ) {
-                               # Modified or created
-                               wfDebug( "Dependency triggered: {$this->filename} changed.\n" );
 
-                               return true;
-                       } else {
-                               # Not modified
-                               return false;
-                       }
+                       # Deleted
+                       wfDebug( "Dependency triggered: {$this->filename} deleted.\n" );
+
+                       return true;
                }
+
+               if ( $lastmod > $this->timestamp ) {
+                       # Modified or created
+                       wfDebug( "Dependency triggered: {$this->filename} changed.\n" );
+
+                       return true;
+               }
+
+               # Not modified
+               return false;
        }
 }
index 246a3dd..aad9439 100644 (file)
@@ -22,9 +22,7 @@ use Cdb\Reader;
 use Cdb\Writer;
 
 /**
- * LCStore implementation which stores data as a collection of CDB files in the
- * directory given by $wgCacheDirectory. If $wgCacheDirectory is not set, this
- * will throw an exception.
+ * LCStore implementation which stores data as a collection of CDB files.
  *
  * Profiling indicates that on Linux, this implementation outperforms MySQL if
  * the directory is on a local filesystem and there is ample kernel cache
@@ -44,13 +42,11 @@ class LCStoreCDB implements LCStore {
        /** @var string Current language code */
        private $currentLang;
 
-       /** @var bool|string Cache directory. False if not set */
+       /** @var string Cache directory */
        private $directory;
 
        function __construct( $conf = [] ) {
-               global $wgCacheDirectory;
-
-               $this->directory = $conf['directory'] ?? $wgCacheDirectory;
+               $this->directory = $conf['directory'];
        }
 
        public function get( $code, $key ) {
@@ -86,11 +82,9 @@ class LCStoreCDB implements LCStore {
        }
 
        public function startWrite( $code ) {
-               if ( !file_exists( $this->directory ) ) {
-                       if ( !wfMkdirParents( $this->directory, null, __METHOD__ ) ) {
-                               throw new MWException( "Unable to create the localisation store " .
-                                       "directory \"{$this->directory}\"" );
-                       }
+               if ( !file_exists( $this->directory ) && !wfMkdirParents( $this->directory, null, __METHOD__ ) ) {
+                       throw new MWException( "Unable to create the localisation store " .
+                               "directory \"{$this->directory}\"" );
                }
 
                // Close reader to stop permission errors on write
index 75c8465..5911656 100644 (file)
@@ -39,17 +39,13 @@ class LCStoreStaticArray implements LCStore {
        private $directory;
 
        public function __construct( $conf = [] ) {
-               global $wgCacheDirectory;
-
-               $this->directory = $conf['directory'] ?? $wgCacheDirectory;
+               $this->directory = $conf['directory'];
        }
 
        public function startWrite( $code ) {
-               if ( !file_exists( $this->directory ) ) {
-                       if ( !wfMkdirParents( $this->directory, null, __METHOD__ ) ) {
-                               throw new MWException( "Unable to create the localisation store " .
-                                       "directory \"{$this->directory}\"" );
-                       }
+               if ( !file_exists( $this->directory ) && !wfMkdirParents( $this->directory, null, __METHOD__ ) ) {
+                       throw new MWException( "Unable to create the localisation store " .
+                               "directory \"{$this->directory}\"" );
                }
 
                $this->currentLang = $code;
@@ -101,8 +97,7 @@ class LCStoreStaticArray implements LCStore {
                        return $encoded;
                }
 
-               $type = $encoded[0];
-               $data = $encoded[1];
+               list( $type, $data ) = $encoded;
 
                switch ( $type ) {
                        case 'a':
index 1d00d19..788eec3 100644 (file)
@@ -192,7 +192,11 @@ class LocalisationCache {
                global $wgCacheDirectory;
 
                $this->conf = $conf;
-               $storeConf = [];
+
+               $directory = !empty( $conf['storeDirectory'] ) ? $conf['storeDirectory'] : $wgCacheDirectory;
+               $storeArg = [];
+               $storeArg['directory'] = $directory;
+
                if ( !empty( $conf['storeClass'] ) ) {
                        $storeClass = $conf['storeClass'];
                } else {
@@ -203,20 +207,17 @@ class LocalisationCache {
                                        break;
                                case 'db':
                                        $storeClass = LCStoreDB::class;
-                                       $storeConf['server'] = $conf['storeServer'] ?? [];
+                                       $storeArg['server'] = $conf['storeServer'] ?? [];
                                        break;
                                case 'array':
                                        $storeClass = LCStoreStaticArray::class;
                                        break;
                                case 'detect':
-                                       if ( !empty( $conf['storeDirectory'] ) ) {
-                                               $storeClass = LCStoreCDB::class;
-                                       } elseif ( $wgCacheDirectory ) {
-                                               $storeConf['directory'] = $wgCacheDirectory;
+                                       if ( $directory ) {
                                                $storeClass = LCStoreCDB::class;
                                        } else {
                                                $storeClass = LCStoreDB::class;
-                                               $storeConf['server'] = $conf['storeServer'] ?? [];
+                                               $storeArg['server'] = $conf['storeServer'] ?? [];
                                        }
                                        break;
                                default:
@@ -227,11 +228,8 @@ class LocalisationCache {
                }
 
                wfDebugLog( 'caches', static::class . ": using store $storeClass" );
-               if ( !empty( $conf['storeDirectory'] ) ) {
-                       $storeConf['directory'] = $conf['storeDirectory'];
-               }
 
-               $this->store = new $storeClass( $storeConf );
+               $this->store = new $storeClass( $storeArg );
                foreach ( [ 'manualRecache', 'forceRecache' ] as $var ) {
                        if ( isset( $conf[$var] ) ) {
                                $this->$var = $conf[$var];
@@ -536,7 +534,6 @@ class LocalisationCache {
                        }
                } elseif ( $_fileType == 'aliases' ) {
                        if ( isset( $aliases ) ) {
-                               /** @suppress PhanUndeclaredVariable */
                                $data['aliases'] = $aliases;
                        }
                } else {
@@ -1034,9 +1031,7 @@ class LocalisationCache {
                # HACK: If using a null (i.e. disabled) storage backend, we
                # can't write to the MessageBlobStore either
                if ( $purgeBlobs && !$this->store instanceof LCStoreNull ) {
-                       $blobStore = new MessageBlobStore(
-                               MediaWikiServices::getInstance()->getResourceLoader()
-                       );
+                       $blobStore = MediaWikiServices::getInstance()->getResourceLoader()->getMessageBlobStore();
                        $blobStore->clear();
                }
        }
diff --git a/includes/changes/AtomFeed.php b/includes/changes/AtomFeed.php
new file mode 100644 (file)
index 0000000..a4ce0c1
--- /dev/null
@@ -0,0 +1,111 @@
+<?php
+/**
+ * Copyright © 2004 Brion Vibber <brion@pobox.com>
+ * https://www.mediawiki.org/
+ *
+ * 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
+ */
+
+/**
+ * Generate an Atom feed.
+ *
+ * @ingroup Feed
+ */
+class AtomFeed extends ChannelFeed {
+       /**
+        * Format a date given timestamp, if one is given.
+        *
+        * @param string|int|null $timestamp
+        * @return string|null
+        */
+       function formatTime( $timestamp ) {
+               if ( $timestamp ) {
+                       // need to use RFC 822 time format at least for rss2.0
+                       return gmdate( 'Y-m-d\TH:i:s', wfTimestamp( TS_UNIX, $timestamp ) );
+               }
+       }
+
+       /**
+        * Outputs a basic header for Atom 1.0 feeds.
+        */
+       function outHeader() {
+               global $wgVersion;
+               $this->outXmlHeader();
+               // Manually escaping rather than letting Mustache do it because Mustache
+               // uses htmlentities, which does not work with XML
+               $templateParams = [
+                       'language' => $this->xmlEncode( $this->getLanguage() ),
+                       'feedID' => $this->getFeedId(),
+                       'title' => $this->getTitle(),
+                       'url' => $this->xmlEncode( wfExpandUrl( $this->getUrlUnescaped(), PROTO_CURRENT ) ),
+                       'selfUrl' => $this->getSelfUrl(),
+                       'timestamp' => $this->xmlEncode( $this->formatTime( wfTimestampNow() ) ),
+                       'description' => $this->getDescription(),
+                       'version' => $this->xmlEncode( $wgVersion ),
+               ];
+               print $this->templateParser->processTemplate( 'AtomHeader', $templateParams );
+       }
+
+       /**
+        * Atom 1.0 requires a unique, opaque IRI as a unique identifier
+        * for every feed we create. For now just use the URL, but who
+        * can tell if that's right? If we put options on the feed, do we
+        * have to change the id? Maybe? Maybe not.
+        *
+        * @return string
+        */
+       private function getFeedId() {
+               return $this->getSelfUrl();
+       }
+
+       /**
+        * Atom 1.0 requests a self-reference to the feed.
+        * @return string
+        */
+       private function getSelfUrl() {
+               global $wgRequest;
+               return htmlspecialchars( $wgRequest->getFullRequestURL() );
+       }
+
+       /**
+        * Output a given item.
+        * @param FeedItem $item
+        */
+       function outItem( $item ) {
+               global $wgMimeType;
+               // Manually escaping rather than letting Mustache do it because Mustache
+               // uses htmlentities, which does not work with XML
+               $templateParams = [
+                       "uniqueID" => $item->getUniqueID(),
+                       "title" => $item->getTitle(),
+                       "mimeType" => $this->xmlEncode( $wgMimeType ),
+                       "url" => $this->xmlEncode( wfExpandUrl( $item->getUrlUnescaped(), PROTO_CURRENT ) ),
+                       "date" => $this->xmlEncode( $this->formatTime( $item->getDate() ) ),
+                       "description" => $item->getDescription(),
+                       "author" => $item->getAuthor()
+               ];
+               print $this->templateParser->processTemplate( 'AtomItem', $templateParams );
+       }
+
+       /**
+        * Outputs the footer for Atom 1.0 feed (basically '\</feed\>').
+        */
+       function outFooter() {
+               print "</feed>";
+       }
+}
index 50c6826..bb9114a 100644 (file)
  * @file
  */
 
-use Wikimedia\Rdbms\ResultWrapper;
 use MediaWiki\MediaWikiServices;
 
 /**
- * Feed to Special:RecentChanges and Special:RecentChangesLiked
+ * Feed to Special:RecentChanges and Special:RecentChangesLinked.
  *
  * @ingroup Feed
  */
 class ChangesFeed {
-       public $format, $type, $titleMsg, $descMsg;
+       private $format;
 
        /**
         * @param string $format Feed's format (either 'rss' or 'atom')
-        * @param string $type Type of feed (for cache keys)
         */
-       public function __construct( $format, $type ) {
+       public function __construct( $format ) {
                $this->format = $format;
-               $this->type = $type;
        }
 
        /**
@@ -65,119 +62,6 @@ class ChangesFeed {
                        $feedTitle, htmlspecialchars( $description ), $url );
        }
 
-       /**
-        * Generates feed's content
-        *
-        * @param ChannelFeed $feed ChannelFeed subclass object (generally the one returned
-        *   by getFeedObject())
-        * @param ResultWrapper $rows ResultWrapper object with rows in recentchanges table
-        * @param int $lastmod Timestamp of the last item in the recentchanges table (only
-        *   used for the cache key)
-        * @param FormOptions $opts As in SpecialRecentChanges::getDefaultOptions()
-        * @return null|bool True or null
-        */
-       public function execute( $feed, $rows, $lastmod, $opts ) {
-               global $wgLang, $wgRenderHashAppend;
-
-               if ( !FeedUtils::checkFeedOutput( $this->format ) ) {
-                       return null;
-               }
-
-               $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
-               $optionsHash = md5( serialize( $opts->getAllValues() ) ) . $wgRenderHashAppend;
-               $timekey = $cache->makeKey(
-                       $this->type, $this->format, $wgLang->getCode(), $optionsHash, 'timestamp' );
-               $key = $cache->makeKey( $this->type, $this->format, $wgLang->getCode(), $optionsHash );
-
-               FeedUtils::checkPurge( $timekey, $key );
-
-               /**
-                * Bumping around loading up diffs can be pretty slow, so where
-                * possible we want to cache the feed output so the next visitor
-                * gets it quick too.
-                */
-               $cachedFeed = $this->loadFromCache( $lastmod, $timekey, $key );
-               if ( is_string( $cachedFeed ) ) {
-                       wfDebug( "RC: Outputting cached feed\n" );
-                       $feed->httpHeaders();
-                       echo $cachedFeed;
-               } else {
-                       wfDebug( "RC: rendering new feed and caching it\n" );
-                       ob_start();
-                       self::generateFeed( $rows, $feed );
-                       $cachedFeed = ob_get_contents();
-                       ob_end_flush();
-                       $this->saveToCache( $cachedFeed, $timekey, $key );
-               }
-               return true;
-       }
-
-       /**
-        * Save to feed result to cache
-        *
-        * @param string $feed Feed's content
-        * @param string $timekey Memcached key of the last modification
-        * @param string $key Memcached key of the content
-        */
-       public function saveToCache( $feed, $timekey, $key ) {
-               $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
-               $cache->set( $key, $feed, $cache::TTL_DAY );
-               $cache->set( $timekey, wfTimestamp( TS_MW ), $cache::TTL_DAY );
-       }
-
-       /**
-        * Try to load the feed result from cache
-        *
-        * @param int $lastmod Timestamp of the last item in the recentchanges table
-        * @param string $timekey Memcached key of the last modification
-        * @param string $key Memcached key of the content
-        * @return string|bool Feed's content on cache hit or false on cache miss
-        */
-       public function loadFromCache( $lastmod, $timekey, $key ) {
-               global $wgFeedCacheTimeout, $wgOut;
-
-               $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
-               $feedLastmod = $cache->get( $timekey );
-
-               if ( ( $wgFeedCacheTimeout > 0 ) && $feedLastmod ) {
-                       /**
-                        * If the cached feed was rendered very recently, we may
-                        * go ahead and use it even if there have been edits made
-                        * since it was rendered. This keeps a swarm of requests
-                        * from being too bad on a super-frequently edited wiki.
-                        */
-
-                       $feedAge = time() - wfTimestamp( TS_UNIX, $feedLastmod );
-                       $feedLastmodUnix = wfTimestamp( TS_UNIX, $feedLastmod );
-                       $lastmodUnix = wfTimestamp( TS_UNIX, $lastmod );
-
-                       if ( $feedAge < $wgFeedCacheTimeout || $feedLastmodUnix > $lastmodUnix ) {
-                               wfDebug( "RC: loading feed from cache ($key; $feedLastmod; $lastmod)...\n" );
-                               if ( $feedLastmodUnix < $lastmodUnix ) {
-                                       $wgOut->setLastModified( $feedLastmod ); // T23916
-                               }
-                               return $cache->get( $key );
-                       } else {
-                               wfDebug( "RC: cached feed timestamp check failed ($feedLastmod; $lastmod)\n" );
-                       }
-               }
-               return false;
-       }
-
-       /**
-        * Generate the feed items given a row from the database, printing the feed.
-        * @param object $rows IDatabase resource with recentchanges rows
-        * @param ChannelFeed &$feed
-        */
-       public static function generateFeed( $rows, &$feed ) {
-               $items = self::buildItems( $rows );
-               $feed->outHeader();
-               foreach ( $items as $item ) {
-                       $feed->outItem( $item );
-               }
-               $feed->outFooter();
-       }
-
        /**
         * Generate the feed items given a row from the database.
         * @param object $rows IDatabase resource with recentchanges rows
@@ -206,9 +90,10 @@ class ChangesFeed {
                        }
                }
 
+               $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
                foreach ( $sorted as $obj ) {
                        $title = Title::makeTitle( $obj->rc_namespace, $obj->rc_title );
-                       $talkpage = MWNamespace::hasTalkNamespace( $obj->rc_namespace )
+                       $talkpage = $nsInfo->hasTalkNamespace( $obj->rc_namespace )
                                ? $title->getTalkPage()->getFullURL()
                                : '';
 
index bf275b3..85035bc 100644 (file)
@@ -192,7 +192,7 @@ class ChangesList extends ContextSource {
         * @param RecentChange|RCCacheEntry $rc
         * @param string|bool $watched Optionally timestamp for adding watched class
         *
-        * @return array of classes
+        * @return string[] List of CSS class names
         */
        protected function getHTMLClasses( $rc, $watched ) {
                $classes = [ self::CSS_CLASS_PREFIX . 'line' ];
@@ -395,6 +395,36 @@ class ChangesList extends ContextSource {
                return $out;
        }
 
+       /**
+        * Render the date and time of a revision in the current user language
+        * based on whether the user is able to view this information or not.
+        * @param Revision $rev
+        * @param User $user
+        * @param Language $lang
+        * @param Title|null $title (optional) where Title does not match
+        *   the Title associated with the Revision
+        * @internal For usage by Pager classes only (e.g. HistoryPager and ContribsPager).
+        * @return string HTML
+        */
+       public static function revDateLink( Revision $rev, User $user, Language $lang, $title = null ) {
+               $ts = $rev->getTimestamp();
+               $date = $lang->userTimeAndDate( $ts, $user );
+               if ( $rev->userCan( Revision::DELETED_TEXT, $user ) ) {
+                       $link = MediaWikiServices::getInstance()->getLinkRenderer()->makeKnownLink(
+                               $title ?? $rev->getTitle(),
+                               $date,
+                               [ 'class' => 'mw-changeslist-date' ],
+                               [ 'oldid' => $rev->getId() ]
+                       );
+               } else {
+                       $link = htmlspecialchars( $date );
+               }
+               if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
+                       $link = "<span class=\"history-deleted mw-changeslist-date\">$link</span>";
+               }
+               return $link;
+       }
+
        /**
         * @param string &$s HTML to update
         * @param mixed $rc_timestamp
@@ -517,6 +547,7 @@ class ChangesList extends ContextSource {
         * and a separator
         *
         * @param RecentChange $rc
+        * @deprecated use revDateLink instead.
         * @return string HTML fragment
         */
        public function getTimestamp( $rc ) {
@@ -586,7 +617,13 @@ class ChangesList extends ContextSource {
                        return ' <span class="history-deleted">' .
                                $this->msg( 'rev-deleted-comment' )->escaped() . '</span>';
                } else {
-                       return Linker::commentBlock( $rc->mAttribs['rc_comment'], $rc->getTitle() );
+                       return Linker::commentBlock( $rc->mAttribs['rc_comment'], $rc->getTitle(),
+                               // Whether section links should refer to local page (using default false)
+                               false,
+                               // wikid to generate links for (using default null) */
+                               null,
+                               // whether parentheses should be rendered as part of the message
+                               false );
                }
        }
 
@@ -603,7 +640,7 @@ class ChangesList extends ContextSource {
                return $this->watchMsgCache->getWithSetCallback(
                        "watching-users-msg:$count",
                        function () use ( $count ) {
-                               return $this->msg( 'number_of_watching_users_RCview' )
+                               return $this->msg( 'number-of-watching-users-for-recent-changes' )
                                        ->numParams( $count )->escaped();
                        }
                );
diff --git a/includes/changes/ChannelFeed.php b/includes/changes/ChannelFeed.php
new file mode 100644 (file)
index 0000000..a1b832e
--- /dev/null
@@ -0,0 +1,129 @@
+<?php
+/**
+ * Copyright © 2004 Brion Vibber <brion@pobox.com>
+ * https://www.mediawiki.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * Class to support the outputting of syndication feeds in Atom and RSS format.
+ *
+ * @ingroup Feed
+ */
+abstract class ChannelFeed extends FeedItem {
+
+       /** @var TemplateParser */
+       protected $templateParser;
+
+       /**
+        * @param string|Title $title Feed's title
+        * @param string $description
+        * @param string $url URL uniquely designating the feed.
+        * @param string $date Feed's date
+        * @param string $author Author's user name
+        * @param string $comments
+        */
+       function __construct( $title, $description, $url, $date = '', $author = '', $comments = '' ) {
+               parent::__construct( $title, $description, $url, $date, $author, $comments );
+               $this->templateParser = new TemplateParser();
+       }
+
+       /**
+        * Generate Header of the feed
+        * @par Example:
+        * @code
+        * print "<feed>";
+        * @endcode
+        */
+       abstract public function outHeader();
+
+       /**
+        * Generate an item
+        * @par Example:
+        * @code
+        * print "<item>...</item>";
+        * @endcode
+        * @param FeedItem $item
+        */
+       abstract public function outItem( $item );
+
+       /**
+        * Generate Footer of the feed
+        * @par Example:
+        * @code
+        * print "</feed>";
+        * @endcode
+        */
+       abstract public function outFooter();
+
+       /**
+        * Setup and send HTTP headers. Don't send any content;
+        * content might end up being cached and re-sent with
+        * these same headers later.
+        *
+        * This should be called from the outHeader() method,
+        * but can also be called separately.
+        */
+       public function httpHeaders() {
+               global $wgOut, $wgVaryOnXFP;
+
+               # We take over from $wgOut, excepting its cache header info
+               $wgOut->disable();
+               $mimetype = $this->contentType();
+               header( "Content-type: $mimetype; charset=UTF-8" );
+
+               // Set a sane filename
+               $exts = MediaWiki\MediaWikiServices::getInstance()->getMimeAnalyzer()
+                       ->getExtensionsForType( $mimetype );
+               $ext = $exts ? strtok( $exts, ' ' ) : 'xml';
+               header( "Content-Disposition: inline; filename=\"feed.{$ext}\"" );
+
+               if ( $wgVaryOnXFP ) {
+                       $wgOut->addVaryHeader( 'X-Forwarded-Proto' );
+               }
+               $wgOut->sendCacheControl();
+       }
+
+       /**
+        * Return an internet media type to be sent in the headers.
+        *
+        * @return string
+        */
+       private function contentType() {
+               global $wgRequest;
+
+               $ctype = $wgRequest->getVal( 'ctype', 'application/xml' );
+               $allowedctypes = [
+                       'application/xml',
+                       'text/xml',
+                       'application/rss+xml',
+                       'application/atom+xml'
+               ];
+
+               return ( in_array( $ctype, $allowedctypes ) ? $ctype : 'application/xml' );
+       }
+
+       /**
+        * Output the initial XML headers.
+        */
+       protected function outXmlHeader() {
+               $this->httpHeaders();
+               echo '<?xml version="1.0"?>' . "\n";
+       }
+}
index 3e98f65..8f32ba2 100644 (file)
@@ -184,9 +184,7 @@ class EnhancedChangesList extends ChangesList {
                        $tableClasses[] = Sanitizer::escapeClass( 'mw-changeslist-ns'
                                . $block[0]->mAttribs['rc_namespace'] . '-' . $block[0]->mAttribs['rc_title'] );
                }
-               if ( $block[0]->watched
-                       && $block[0]->mAttribs['rc_timestamp'] >= $block[0]->watched
-               ) {
+               if ( $block[0]->watched ) {
                        $tableClasses[] = 'mw-changeslist-line-watched';
                } else {
                        $tableClasses[] = 'mw-changeslist-line-not-watched';
@@ -219,7 +217,7 @@ class EnhancedChangesList extends ChangesList {
                foreach ( $block as $rcObj ) {
                        // If all log actions to this page were hidden, then don't
                        // give the name of the affected page for this block!
-                       if ( !$this->isDeleted( $rcObj, LogPage::DELETED_ACTION ) ) {
+                       if ( !static::isDeleted( $rcObj, LogPage::DELETED_ACTION ) ) {
                                $namehidden = false;
                        }
                        $u = $rcObj->userlink;
@@ -260,7 +258,8 @@ class EnhancedChangesList extends ChangesList {
                } elseif ( $allLogs ) {
                        $articleLink = $this->maybeWatchedLink( $block[0]->link, $block[0]->watched );
                } else {
-                       $articleLink = $this->getArticleLink( $block[0], $block[0]->unpatrolled, $block[0]->watched );
+                       $articleLink = $this->getArticleLink(
+                               $block[0], $block[0]->unpatrolled, $block[0]->watched );
                }
 
                $queryParams['curid'] = $curId;
@@ -386,14 +385,12 @@ class EnhancedChangesList extends ChangesList {
                $lineParams = [ 'targetTitle' => $rcObj->getTitle() ];
 
                $classes = [ 'mw-enhanced-rc' ];
-               if ( $rcObj->watched
-                       && $rcObj->mAttribs['rc_timestamp'] >= $rcObj->watched
-               ) {
+               if ( $rcObj->watched ) {
                        $classes[] = 'mw-enhanced-watched';
                }
                $classes = array_merge( $classes, $this->getHTMLClasses( $rcObj, $rcObj->watched ) );
 
-               $separator = ' <span class="mw-changeslist-separator">. .</span> ';
+               $separator = ' <span class="mw-changeslist-separator"></span> ';
 
                $data['recentChangesFlags'] = [
                        'newpage' => $type == RC_NEW,
@@ -421,7 +418,7 @@ class EnhancedChangesList extends ChangesList {
                                [],
                                $params
                        );
-                       if ( $this->isDeleted( $rcObj, Revision::DELETED_TEXT ) ) {
+                       if ( static::isDeleted( $rcObj, Revision::DELETED_TEXT ) ) {
                                $link = '<span class="history-deleted">' . $link . '</span> ';
                        }
                }
@@ -503,7 +500,7 @@ class EnhancedChangesList extends ChangesList {
        /**
         * Generates amount of changes (linking to diff ) & link to history.
         *
-        * @param array $block
+        * @param RCCacheEntry[] $block
         * @param array $queryParams
         * @param bool $allLogs
         * @param bool $isnew
@@ -529,7 +526,7 @@ class EnhancedChangesList extends ChangesList {
                /** @var RCCacheEntry $rcObj */
                foreach ( $block as $rcObj ) {
                        // Same logic as below inside main foreach
-                       if ( $rcObj->watched && $rcObj->mAttribs['rc_timestamp'] >= $rcObj->watched ) {
+                       if ( $rcObj->watched ) {
                                $sinceLast++;
                                $unvisitedOldid = $rcObj->mAttribs['rc_last_oldid'];
                        }
@@ -552,32 +549,42 @@ class EnhancedChangesList extends ChangesList {
                $block0 = $block[0];
                $last = $block[count( $block ) - 1];
                if ( !$allLogs ) {
-                       if ( !ChangesList::userCan( $rcObj, Revision::DELETED_TEXT, $this->getUser() ) ||
+                       if (
                                $isnew ||
-                               $rcObj->mAttribs['rc_type'] == RC_CATEGORIZE
+                               $rcObj->mAttribs['rc_type'] == RC_CATEGORIZE ||
+                               !ChangesList::userCan( $rcObj, Revision::DELETED_TEXT, $this->getUser() )
                        ) {
-                               $links['total-changes'] = $nchanges[$n];
+                               $links['total-changes'] = Html::rawElement( 'span', [], $nchanges[$n] );
                        } else {
-                               $links['total-changes'] = $this->linkRenderer->makeKnownLink(
-                                       $block0->getTitle(),
-                                       new HtmlArmor( $nchanges[$n] ),
-                                       [ 'class' => 'mw-changeslist-groupdiff' ],
-                                       $queryParams + [
-                                               'diff' => $currentRevision,
-                                               'oldid' => $last->mAttribs['rc_last_oldid'],
-                                       ]
+                               $links['total-changes'] = Html::rawElement( 'span', [],
+                                       $this->linkRenderer->makeKnownLink(
+                                               $block0->getTitle(),
+                                               new HtmlArmor( $nchanges[$n] ),
+                                               [ 'class' => 'mw-changeslist-groupdiff' ],
+                                               $queryParams + [
+                                                       'diff' => $currentRevision,
+                                                       'oldid' => $last->mAttribs['rc_last_oldid'],
+                                               ]
+                                       )
+                               );
+                       }
+
+                       if (
+                               $rcObj->mAttribs['rc_type'] != RC_CATEGORIZE &&
+                               $sinceLast > 0 &&
+                               $sinceLast < $n
+                       ) {
+                               $links['total-changes-since-last'] = Html::rawElement( 'span', [],
+                                       $this->linkRenderer->makeKnownLink(
+                                               $block0->getTitle(),
+                                               new HtmlArmor( $sinceLastVisitMsg[$sinceLast] ),
+                                               [ 'class' => 'mw-changeslist-groupdiff' ],
+                                               $queryParams + [
+                                                       'diff' => $currentRevision,
+                                                       'oldid' => $unvisitedOldid,
+                                               ]
+                                       )
                                );
-                               if ( $sinceLast > 0 && $sinceLast < $n ) {
-                                       $links['total-changes-since-last'] = $this->linkRenderer->makeKnownLink(
-                                                       $block0->getTitle(),
-                                                       new HtmlArmor( $sinceLastVisitMsg[$sinceLast] ),
-                                                       [ 'class' => 'mw-changeslist-groupdiff' ],
-                                                       $queryParams + [
-                                                               'diff' => $currentRevision,
-                                                               'oldid' => $unvisitedOldid,
-                                                       ]
-                                               );
-                               }
                        }
                }
 
@@ -585,17 +592,19 @@ class EnhancedChangesList extends ChangesList {
                if ( $allLogs || $rcObj->mAttribs['rc_type'] == RC_CATEGORIZE ) {
                        // don't show history link for logs
                } elseif ( $namehidden || !$block0->getTitle()->exists() ) {
-                       $links['history'] = $this->message['enhancedrc-history'];
+                       $links['history'] = Html::rawElement( 'span', [], $this->message['enhancedrc-history'] );
                } else {
                        $params = $queryParams;
                        $params['action'] = 'history';
 
-                       $links['history'] = $this->linkRenderer->makeKnownLink(
+                       $links['history'] = Html::rawElement( 'span', [],
+                               $this->linkRenderer->makeKnownLink(
                                        $block0->getTitle(),
                                        new HtmlArmor( $this->message['enhancedrc-history'] ),
                                        [ 'class' => 'mw-changeslist-history' ],
                                        $params
-                               );
+                               )
+                       );
                }
 
                # Allow others to alter, remove or add to these links
@@ -606,8 +615,8 @@ class EnhancedChangesList extends ChangesList {
                        return '';
                }
 
-               $logtext = implode( $this->message['pipe-separator'], $links );
-               $logtext = $this->msg( 'parentheses' )->rawParams( $logtext )->escaped();
+               $logtext = Html::rawElement( 'span', [ 'class' => 'mw-changeslist-links' ],
+                       implode( ' ', $links ) );
                return ' ' . $logtext;
        }
 
@@ -653,10 +662,9 @@ class EnhancedChangesList extends ChangesList {
                        $logPage = new LogPage( $logType );
                        $logTitle = SpecialPage::getTitleFor( 'Log', $logType );
                        $logName = $logPage->getName()->text();
-                       $data['logLink'] = $this->msg( 'parentheses' )
-                               ->rawParams(
-                                       $this->linkRenderer->makeKnownLink( $logTitle, $logName )
-                               )->escaped();
+                       $data['logLink'] = Html::rawElement( 'span', [ 'class' => 'mw-changeslist-links' ],
+                               $this->linkRenderer->makeKnownLink( $logTitle, $logName )
+                       );
                } else {
                        $data['articleLink'] = $this->getArticleLink( $rcObj, $rcObj->unpatrolled, $rcObj->watched );
                }
@@ -664,16 +672,16 @@ class EnhancedChangesList extends ChangesList {
                # Diff and hist links
                if ( $type != RC_LOG && $type != RC_CATEGORIZE ) {
                        $query['action'] = 'history';
-                       $data['historyLink'] = $this->getDiffHistLinks( $rcObj, $query );
+                       $data['historyLink'] = $this->getDiffHistLinks( $rcObj, $query, false );
                }
-               $data['separatorAfterLinks'] = ' <span class="mw-changeslist-separator">. .</span> ';
+               $data['separatorAfterLinks'] = ' <span class="mw-changeslist-separator"></span> ';
 
                # Character diff
                if ( $this->getConfig()->get( 'RCShowChangedSize' ) ) {
                        $cd = $this->formatCharacterDifference( $rcObj );
                        if ( $cd !== '' ) {
                                $data['characterDiff'] = $cd;
-                               $data['separatorAftercharacterDiff'] = ' <span class="mw-changeslist-separator">. .</span> ';
+                               $data['separatorAftercharacterDiff'] = ' <span class="mw-changeslist-separator"></span> ';
                        }
                }
 
@@ -686,7 +694,7 @@ class EnhancedChangesList extends ChangesList {
                        $data['userTalkLink'] = $rcObj->usertalklink;
                        $data['comment'] = $this->insertComment( $rcObj );
                        if ( $type == RC_CATEGORIZE ) {
-                               $data['historyLink'] = $this->getDiffHistLinks( $rcObj, $query );
+                               $data['historyLink'] = $this->getDiffHistLinks( $rcObj, $query, false );
                        }
                        $data['rollback'] = $this->getRollback( $rcObj );
                }
@@ -744,7 +752,11 @@ class EnhancedChangesList extends ChangesList {
                ] );
 
                // everything else: makes it easier for extensions to add or remove data
-               $line .= implode( '', $data );
+               foreach ( $data as $key => $dataItem ) {
+                       $line .= Html::rawElement( 'span', [
+                               'class' => 'mw-changeslist-line-inner-' . $key,
+                       ], $dataItem );
+               }
 
                $line .= "</td></tr></table>\n";
 
@@ -759,9 +771,10 @@ class EnhancedChangesList extends ChangesList {
         *
         * @param RCCacheEntry $rc
         * @param array $query array of key/value pairs to append as a query string
+        * @param bool $useParentheses (optional) Wrap comments in parentheses where needed
         * @return string HTML
         */
-       public function getDiffHistLinks( RCCacheEntry $rc, array $query ) {
+       public function getDiffHistLinks( RCCacheEntry $rc, array $query, $useParentheses = true ) {
                $pageTitle = $rc->getTitle();
                if ( $rc->getAttribute( 'rc_type' ) == RC_CATEGORIZE ) {
                        // For categorizations we must swap the category title with the page title!
@@ -773,15 +786,23 @@ class EnhancedChangesList extends ChangesList {
                        }
                }
 
-               $retVal = ' ' . $this->msg( 'parentheses' )
-                               ->rawParams( $rc->difflink . $this->message['pipe-separator']
-                                       . $this->linkRenderer->makeKnownLink(
-                                               $pageTitle,
-                                               new HtmlArmor( $this->message['hist'] ),
-                                               [ 'class' => 'mw-changeslist-history' ],
-                                               $query
-                                       ) )->escaped();
-               return $retVal;
+               $histLink = $this->linkRenderer->makeKnownLink(
+                       $pageTitle,
+                       new HtmlArmor( $this->message['hist'] ),
+                       [ 'class' => 'mw-changeslist-history' ],
+                       $query
+               );
+               if ( $useParentheses ) {
+                       $retVal = $this->msg( 'parentheses' )
+                       ->rawParams( $rc->difflink . $this->message['pipe-separator']
+                               . $histLink )->escaped();
+               } else {
+                       $retVal = Html::rawElement( 'span', [ 'class' => 'mw-changeslist-links' ],
+                               Html::rawElement( 'span', [], $rc->difflink ) .
+                               Html::rawElement( 'span', [], $histLink )
+                       );
+               }
+               return ' ' . $retVal;
        }
 
        /**
diff --git a/includes/changes/FeedItem.php b/includes/changes/FeedItem.php
new file mode 100644 (file)
index 0000000..a6a2615
--- /dev/null
@@ -0,0 +1,222 @@
+<?php
+/**
+ * Copyright © 2004 Brion Vibber <brion@pobox.com>
+ * https://www.mediawiki.org/
+ *
+ * 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
+ */
+
+/**
+ * @defgroup Feed Feed
+ */
+
+/**
+ * A base class for outputting syndication feeds (e.g. RSS and other formats).
+ *
+ * @ingroup Feed
+ */
+class FeedItem {
+       /** @var Title */
+       public $title;
+
+       public $description;
+
+       public $url;
+
+       public $date;
+
+       public $author;
+
+       public $uniqueId;
+
+       public $comments;
+
+       public $rssIsPermalink = false;
+
+       /**
+        * @param string|Title $title Item's title
+        * @param string $description
+        * @param string $url URL uniquely designating the item.
+        * @param string $date Item's date
+        * @param string $author Author's user name
+        * @param string $comments
+        */
+       function __construct( $title, $description, $url, $date = '', $author = '', $comments = '' ) {
+               $this->title = $title;
+               $this->description = $description;
+               $this->url = $url;
+               $this->uniqueId = $url;
+               $this->date = $date;
+               $this->author = $author;
+               $this->comments = $comments;
+       }
+
+       /**
+        * Encode $string so that it can be safely embedded in a XML document
+        *
+        * @param string $string String to encode
+        * @return string
+        */
+       public function xmlEncode( $string ) {
+               $string = str_replace( "\r\n", "\n", $string );
+               $string = preg_replace( '/[\x00-\x08\x0b\x0c\x0e-\x1f]/', '', $string );
+               return htmlspecialchars( $string );
+       }
+
+       /**
+        * Get the unique id of this item; already xml-encoded
+        * @return string
+        */
+       public function getUniqueID() {
+               $id = $this->getUniqueIdUnescaped();
+               if ( $id ) {
+                       return $this->xmlEncode( $id );
+               }
+       }
+
+       /**
+        * Get the unique id of this item, without any escaping
+        * @return string
+        */
+       public function getUniqueIdUnescaped() {
+               if ( $this->uniqueId ) {
+                       return wfExpandUrl( $this->uniqueId, PROTO_CURRENT );
+               }
+       }
+
+       /**
+        * Set the unique id of an item
+        *
+        * @param string $uniqueId Unique id for the item
+        * @param bool $rssIsPermalink Set to true if the guid (unique id) is a permalink (RSS feeds only)
+        */
+       public function setUniqueId( $uniqueId, $rssIsPermalink = false ) {
+               $this->uniqueId = $uniqueId;
+               $this->rssIsPermalink = $rssIsPermalink;
+       }
+
+       /**
+        * Get the title of this item; already xml-encoded
+        *
+        * @return string
+        */
+       public function getTitle() {
+               return $this->xmlEncode( $this->title );
+       }
+
+       /**
+        * Get the URL of this item; already xml-encoded
+        *
+        * @return string
+        */
+       public function getUrl() {
+               return $this->xmlEncode( $this->url );
+       }
+
+       /** Get the URL of this item without any escaping
+        *
+        * @return string
+        */
+       public function getUrlUnescaped() {
+               return $this->url;
+       }
+
+       /**
+        * Get the description of this item; already xml-encoded
+        *
+        * @return string
+        */
+       public function getDescription() {
+               return $this->xmlEncode( $this->description );
+       }
+
+       /**
+        * Get the description of this item without any escaping
+        *
+        * @return string
+        */
+       public function getDescriptionUnescaped() {
+               return $this->description;
+       }
+
+       /**
+        * Get the language of this item
+        *
+        * @return string
+        */
+       public function getLanguage() {
+               global $wgLanguageCode;
+               return LanguageCode::bcp47( $wgLanguageCode );
+       }
+
+       /**
+        * Get the date of this item
+        *
+        * @return string
+        */
+       public function getDate() {
+               return $this->date;
+       }
+
+       /**
+        * Get the author of this item; already xml-encoded
+        *
+        * @return string
+        */
+       public function getAuthor() {
+               return $this->xmlEncode( $this->author );
+       }
+
+       /**
+        * Get the author of this item without any escaping
+        *
+        * @return string
+        */
+       public function getAuthorUnescaped() {
+               return $this->author;
+       }
+
+       /**
+        * Get the comment of this item; already xml-encoded
+        *
+        * @return string
+        */
+       public function getComments() {
+               return $this->xmlEncode( $this->comments );
+       }
+
+       /**
+        * Get the comment of this item without any escaping
+        *
+        * @return string
+        */
+       public function getCommentsUnescaped() {
+               return $this->comments;
+       }
+
+       /**
+        * Quickie hack... strip out wikilinks to more legible form from the comment.
+        *
+        * @param string $text Wikitext
+        * @return string
+        */
+       public static function stripComment( $text ) {
+               return preg_replace( '/\[\[([^]]*\|)?([^]]+)\]\]/', '\2', $text );
+       }
+       /**#@-*/
+}
index 9f85aa1..6d9236a 100644 (file)
  */
 
 class RCCacheEntry extends RecentChange {
+       /** @var string|null */
        public $curlink;
+       /** @var string|null */
        public $difflink;
+       /** @var string|null */
        public $lastlink;
+       /** @var string|null */
        public $link;
+       /** @var string|null */
        public $timestamp;
+       /** @var bool|null */
        public $unpatrolled;
+       /** @var string|null */
        public $userlink;
+       /** @var string|null */
        public $usertalklink;
+       /** @var bool|null */
        public $watched;
-       public $mAttribs;
-       public $mExtra;
 
        /**
         * @param RecentChange $rc
index e8c3a99..2d60ca2 100644 (file)
@@ -82,7 +82,15 @@ class RCCacheEntryFactory {
                if ( !ChangesList::isDeleted( $cacheEntry, Revision::DELETED_USER ) ) {
                        $cacheEntry->usertalklink = Linker::userToolLinks(
                                $cacheEntry->mAttribs['rc_user'],
-                               $cacheEntry->mAttribs['rc_user_text']
+                               $cacheEntry->mAttribs['rc_user_text'],
+                               // Should the contributions link be red if the user has no edits (using default)
+                               false,
+                               // Customisation flags (using default 0)
+                               0,
+                               // User edit count (using default )
+                               null,
+                               // do not wrap the message in parentheses
+                               false
                        );
                }
 
diff --git a/includes/changes/RSSFeed.php b/includes/changes/RSSFeed.php
new file mode 100644 (file)
index 0000000..3b34500
--- /dev/null
@@ -0,0 +1,93 @@
+<?php
+/**
+ * Copyright © 2004 Brion Vibber <brion@pobox.com>
+ * https://www.mediawiki.org/
+ *
+ * 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
+ */
+
+/**
+ * Generate an RSS feed.
+ *
+ * @ingroup Feed
+ */
+class RSSFeed extends ChannelFeed {
+
+       /**
+        * Format a date given a timestamp. If a timestamp is not given, nothing is returned
+        *
+        * @param int|null $ts Timestamp
+        * @return string|null Date string
+        */
+       function formatTime( $ts ) {
+               if ( $ts ) {
+                       return gmdate( 'D, d M Y H:i:s \G\M\T', wfTimestamp( TS_UNIX, $ts ) );
+               }
+       }
+
+       /**
+        * Output an RSS 2.0 header
+        */
+       function outHeader() {
+               global $wgVersion;
+
+               $this->outXmlHeader();
+               // Manually escaping rather than letting Mustache do it because Mustache
+               // uses htmlentities, which does not work with XML
+               $templateParams = [
+                       'title' => $this->getTitle(),
+                       'url' => $this->xmlEncode( wfExpandUrl( $this->getUrlUnescaped(), PROTO_CURRENT ) ),
+                       'description' => $this->getDescription(),
+                       'language' => $this->xmlEncode( $this->getLanguage() ),
+                       'version' => $this->xmlEncode( $wgVersion ),
+                       'timestamp' => $this->xmlEncode( $this->formatTime( wfTimestampNow() ) )
+               ];
+               print $this->templateParser->processTemplate( 'RSSHeader', $templateParams );
+       }
+
+       /**
+        * Output an RSS 2.0 item
+        * @param FeedItem $item Item to be output
+        */
+       function outItem( $item ) {
+               // Manually escaping rather than letting Mustache do it because Mustache
+               // uses htmlentities, which does not work with XML
+               $templateParams = [
+                       "title" => $item->getTitle(),
+                       "url" => $this->xmlEncode( wfExpandUrl( $item->getUrlUnescaped(), PROTO_CURRENT ) ),
+                       "permalink" => $item->rssIsPermalink,
+                       "uniqueID" => $item->getUniqueID(),
+                       "description" => $item->getDescription(),
+                       "date" => $this->xmlEncode( $this->formatTime( $item->getDate() ) ),
+                       "author" => $item->getAuthor()
+               ];
+               $comments = $item->getCommentsUnescaped();
+               if ( $comments ) {
+                       $commentsEscaped = $this->xmlEncode( wfExpandUrl( $comments, PROTO_CURRENT ) );
+                       $templateParams["comments"] = $commentsEscaped;
+               }
+               print $this->templateParser->processTemplate( 'RSSItem', $templateParams );
+       }
+
+       /**
+        * Output an RSS 2.0 footer
+        */
+       function outFooter() {
+               print "</channel></rss>";
+       }
+}
index 2d37eac..eed159d 100644 (file)
@@ -590,6 +590,13 @@ class RecentChange implements Taggable {
        public function doMarkPatrolled( User $user, $auto = false, $tags = null ) {
                global $wgUseRCPatrol, $wgUseNPPatrol, $wgUseFilePatrol;
 
+               // Fix up $tags so that the MarkPatrolled hook below always gets an array
+               if ( $tags === null ) {
+                       $tags = [];
+               } elseif ( is_string( $tags ) ) {
+                       $tags = [ $tags ];
+               }
+
                $errors = [];
                // If recentchanges patrol is disabled, only new pages or new file versions
                // can be patrolled, provided the appropriate config variable is set
@@ -602,7 +609,7 @@ class RecentChange implements Taggable {
                $right = $auto ? 'autopatrol' : 'patrol';
                $errors = array_merge( $errors, $this->getTitle()->getUserPermissionsErrors( $right, $user ) );
                if ( !Hooks::run( 'MarkPatrolled',
-                                       [ $this->getAttribute( 'rc_id' ), &$user, false, $auto ] )
+                                       [ $this->getAttribute( 'rc_id' ), &$user, false, $auto, &$tags ] )
                ) {
                        $errors[] = [ 'hookaborted' ];
                }
index 00eed14..9146429 100644 (file)
@@ -482,7 +482,9 @@ class ChangeTags {
                if ( !is_null( $user ) ) {
                        if ( !$user->isAllowed( 'applychangetags' ) ) {
                                return Status::newFatal( 'tags-apply-no-permission' );
-                       } elseif ( $user->isBlocked() ) {
+                       } elseif ( $user->getBlock() ) {
+                               // @TODO Ensure that the block does not apply to the `applychangetags`
+                               //       right.
                                return Status::newFatal( 'tags-apply-blocked', $user->getName() );
                        }
                }
@@ -555,7 +557,9 @@ class ChangeTags {
                if ( !is_null( $user ) ) {
                        if ( !$user->isAllowed( 'changetags' ) ) {
                                return Status::newFatal( 'tags-update-no-permission' );
-                       } elseif ( $user->isBlocked() ) {
+                       } elseif ( $user->getBlock() ) {
+                               // @TODO Ensure that the block does not apply to the `changetags`
+                               //       right.
                                return Status::newFatal( 'tags-update-blocked', $user->getName() );
                        }
                }
@@ -604,7 +608,7 @@ class ChangeTags {
         * @param int|null $rc_id The rc_id of the change to add the tags to
         * @param int|null $rev_id The rev_id of the change to add the tags to
         * @param int|null $log_id The log_id of the change to add the tags to
-        * @param string $params Params to put in the ct_params field of table
+        * @param string|null $params Params to put in the ct_params field of table
         * 'change_tag' when adding tags
         * @param string $reason Comment for the log
         * @param User $user Who to give credit for the action
@@ -766,7 +770,7 @@ class ChangeTags {
                                        // Return nothing.
                                        $conds[] = '0';
                                        break;
-                               };
+                               }
                        }
 
                        if ( $filterTagIds !== [] ) {
@@ -973,7 +977,9 @@ class ChangeTags {
                if ( !is_null( $user ) ) {
                        if ( !$user->isAllowed( 'managechangetags' ) ) {
                                return Status::newFatal( 'tags-manage-no-permission' );
-                       } elseif ( $user->isBlocked() ) {
+                       } elseif ( $user->getBlock() ) {
+                               // @TODO Ensure that the block does not apply to the `managechangetags`
+                               //       right.
                                return Status::newFatal( 'tags-manage-blocked', $user->getName() );
                        }
                }
@@ -1045,7 +1051,9 @@ class ChangeTags {
                if ( !is_null( $user ) ) {
                        if ( !$user->isAllowed( 'managechangetags' ) ) {
                                return Status::newFatal( 'tags-manage-no-permission' );
-                       } elseif ( $user->isBlocked() ) {
+                       } elseif ( $user->getBlock() ) {
+                               // @TODO Ensure that the block does not apply to the `managechangetags`
+                               //       right.
                                return Status::newFatal( 'tags-manage-blocked', $user->getName() );
                        }
                }
@@ -1142,7 +1150,9 @@ class ChangeTags {
                if ( !is_null( $user ) ) {
                        if ( !$user->isAllowed( 'managechangetags' ) ) {
                                return Status::newFatal( 'tags-manage-no-permission' );
-                       } elseif ( $user->isBlocked() ) {
+                       } elseif ( $user->getBlock() ) {
+                               // @TODO Ensure that the block does not apply to the `managechangetags`
+                               //       right.
                                return Status::newFatal( 'tags-manage-blocked', $user->getName() );
                        }
                }
@@ -1258,7 +1268,9 @@ class ChangeTags {
                if ( !is_null( $user ) ) {
                        if ( !$user->isAllowed( 'deletechangetags' ) ) {
                                return Status::newFatal( 'tags-delete-no-permission' );
-                       } elseif ( $user->isBlocked() ) {
+                       } elseif ( $user->getBlock() ) {
+                               // @TODO Ensure that the block does not apply to the `deletechangetags`
+                               //       right.
                                return Status::newFatal( 'tags-manage-blocked', $user->getName() );
                        }
                }
@@ -1458,15 +1470,6 @@ class ChangeTags {
                MediaWikiServices::getInstance()->getChangeTagDefStore()->reloadMap();
        }
 
-       /**
-        * Invalidates the tag statistics cache only.
-        * @since 1.25
-        * @deprecated since 1.33 the cache this purges no longer exists
-        */
-       public static function purgeTagUsageCache() {
-               wfDeprecated( __METHOD__, '1.33' );
-       }
-
        /**
         * Returns a map of any tags used on the wiki to number of edits
         * tagged with them, ordered descending by the hitcount.
index 7e1f1d1..bf455af 100644 (file)
@@ -66,7 +66,7 @@ class ChangeTagsLogList extends ChangeTagsList {
         *
         * @param array $tagsToAdd
         * @param array $tagsToRemove
-        * @param array $params
+        * @param string|null $params
         * @param string $reason
         * @param User $user
         * @return Status
index 49d9d1c..75f51ef 100644 (file)
@@ -68,9 +68,8 @@ class SquidPurgeClient {
 
        /**
         * @param string $server
-        * @param array $options
         */
-       public function __construct( $server, $options = [] ) {
+       public function __construct( $server ) {
                $parts = explode( ':', $server, 2 );
                $this->host = $parts[0];
                $this->port = $parts[1] ?? 80;
index ab3c6fb..312c2d4 100644 (file)
@@ -76,7 +76,7 @@ abstract class Collation {
                                $collationObject = null;
                                Hooks::run( 'Collation::factory', [ $collationName, &$collationObject ] );
 
-                               if ( $collationObject instanceof Collation ) {
+                               if ( $collationObject instanceof self ) {
                                        return $collationObject;
                                }
 
index d45b2ce..7774a60 100644 (file)
@@ -365,16 +365,14 @@ class IcuCollation extends Collation {
                        foreach ( $digits as $digit ) {
                                $letters[] = $this->digitTransformLanguage->formatNum( $digit, true );
                        }
+               } elseif ( $this->locale === 'root' ) {
+                       $letters = require "$IP/includes/collation/data/first-letters-root.php";
                } else {
-                       if ( $this->locale === 'root' ) {
-                               $letters = require "$IP/includes/collation/data/first-letters-root.php";
-                       } else {
-                               // FIXME: Is this still used?
-                               $letters = wfGetPrecompiledData( "first-letters-{$this->locale}.ser" );
-                               if ( $letters === false ) {
-                                       throw new MWException( "MediaWiki does not support ICU locale " .
-                                               "\"{$this->locale}\"" );
-                               }
+                       // FIXME: Is this still used?
+                       $letters = wfGetPrecompiledData( "first-letters-{$this->locale}.ser" );
+                       if ( $letters === false ) {
+                               throw new MWException( "MediaWiki does not support ICU locale " .
+                                       "\"{$this->locale}\"" );
                        }
                }
 
@@ -528,23 +526,6 @@ class IcuCollation extends Collation {
                return false;
        }
 
-       /**
-        * Return the version of ICU library used by PHP's intl extension,
-        * or false when the extension is not installed of the version
-        * can't be determined.
-        *
-        * The constant INTL_ICU_VERSION this function refers to isn't really
-        * documented, but see https://bugs.php.net/bug.php?id=54561.
-        *
-        * @since 1.21
-        * @deprecated since 1.32, use INTL_ICU_VERSION directly
-        * @return string
-        */
-       static function getICUVersion() {
-               wfDeprecated( __METHOD__, '1.32' );
-               return INTL_ICU_VERSION;
-       }
-
        /**
         * Return the version of Unicode appropriate for the version of ICU library
         * currently in use, or false when it can't be determined.
diff --git a/includes/compat/ObjectFactory.php b/includes/compat/ObjectFactory.php
deleted file mode 100644 (file)
index 7646238..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-/**
- * Construct objects from configuration instructions.
- *
- * @deprecated since 1.31, use \Wikimedia\ObjectFactory instead
- */
-class ObjectFactory extends \Wikimedia\ObjectFactory {
-}
diff --git a/includes/compat/XMPReader.php b/includes/compat/XMPReader.php
deleted file mode 100644 (file)
index 5854842..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-/**
- * Back-compat for pre-librarized XMP classes
- *
- * 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.
- */
-
-use Wikimedia\XMPReader\Info;
-use Wikimedia\XMPReader\Reader;
-use Wikimedia\XMPReader\Validate;
-
-/**
- * @deprecated since 1.32
- */
-class XMPInfo extends Info {
-}
-
-/**
- * @deprecated since 1.32
- */
-class XMPReader extends Reader {
-}
-
-/**
- * @deprecated since 1.32
- */
-class XMPValidate extends Validate {
-}
index 52bc0cd..5071fdc 100644 (file)
@@ -55,7 +55,7 @@ class ComposerVersionNormalizer {
                        $version = substr( $version, 0, $dashPosition );
                }
 
-               $version = implode( '.', array_pad( explode( '.', $version ), 4, '0' ) );
+               $version = implode( '.', array_pad( explode( '.', $version, 4 ), 4, '0' ) );
 
                if ( $dashPosition !== false ) {
                        $version .= $suffix;
index 96dc51c..d48eb0e 100644 (file)
@@ -71,10 +71,8 @@ class ConfigRepository implements SalvageableService {
                if ( !$this->has( $name, true ) ) {
                        throw new \ConfigException( 'The configuration option ' . $name . ' does not exist.' );
                }
-               if ( isset( $this->configItems['public'][$name] ) ) {
-                       return $this->configItems['public'][$name];
-               }
-               return $this->configItems['private'][$name];
+
+               return $this->configItems['public'][$name] ?? $this->configItems['private'][$name];
        }
 
        /**
@@ -191,19 +189,12 @@ class ConfigRepository implements SalvageableService {
        public function salvage( SalvageableService $other ) {
                Assert::parameterType( self::class, $other, '$other' );
 
-               /** @var ConfigRepository $other */
-               $otherCurrentObj = $other->current();
                foreach ( $other->configItems['public'] as $name => $otherConfig ) {
                        if ( isset( $this->configItems['public'][$name] ) ) {
                                continue;
                        }
 
                        $this->add( $name, $otherConfig );
-
-                       // recover the pointer of the other config repository
-                       if ( $otherCurrentObj === $otherConfig ) {
-                               end( $this->configItems['public'] );
-                       }
                }
                foreach ( $other->configItems['private'] as $name => $otherConfig ) {
                        if ( isset( $this->configItems['private'][$name] ) ) {
@@ -211,11 +202,6 @@ class ConfigRepository implements SalvageableService {
                        }
 
                        $this->add( $name, $otherConfig );
-
-                       // recover the pointer of the other config repository
-                       if ( $otherCurrentObj === $otherConfig ) {
-                               end( $this->configItems['private'] );
-                       }
                }
 
                // disable $other
diff --git a/includes/config/ServiceOptions.php b/includes/config/ServiceOptions.php
new file mode 100644 (file)
index 0000000..0f3743f
--- /dev/null
@@ -0,0 +1,87 @@
+<?php
+
+namespace MediaWiki\Config;
+
+use Config;
+use InvalidArgumentException;
+use Wikimedia\Assert\Assert;
+
+/**
+ * A class for passing options to services. It can be constructed from a Config, and in practice
+ * most options will be taken from site configuration, but they don't have to be. The options passed
+ * are copied and will not reflect subsequent updates to site configuration (assuming they're not
+ * objects).
+ *
+ * Services that take this type as a parameter to their constructor should specify a list of the
+ * keys they expect to receive in an array. The convention is to make it a public static variable
+ * called $constructorOptions. (When we drop HHVM support -- see T192166 -- it should become a
+ * const.) In the constructor, they should call assertRequiredOptions() to make sure that they
+ * weren't passed too few or too many options. This way it's clear what each class depends on, and
+ * that it's getting passed the correct set of options. (This means there are no optional options.
+ * This makes sense for services, since they shouldn't be constructed by outside code.)
+ *
+ * @since 1.34
+ */
+class ServiceOptions {
+       private $options = [];
+
+       /**
+        * @param string[] $keys Which keys to extract from $sources
+        * @param Config|array ...$sources Each source is either a Config object or an array. If the
+        *  same key is present in two sources, the first one takes precedence. Keys that are not in
+        *  $keys are ignored.
+        * @throws InvalidArgumentException if one of $keys is not found in any of $sources
+        */
+       public function __construct( array $keys, ...$sources ) {
+               foreach ( $keys as $key ) {
+                       foreach ( $sources as $source ) {
+                               if ( $source instanceof Config ) {
+                                       if ( $source->has( $key ) ) {
+                                               $this->options[$key] = $source->get( $key );
+                                               continue 2;
+                                       }
+                               } else {
+                                       if ( array_key_exists( $key, $source ) ) {
+                                               $this->options[$key] = $source[$key];
+                                               continue 2;
+                                       }
+                               }
+                       }
+                       throw new InvalidArgumentException( "Key \"$key\" not found in input sources" );
+               }
+       }
+
+       /**
+        * Assert that the list of options provided in this instance exactly match $expectedKeys,
+        * without regard for order.
+        *
+        * @param string[] $expectedKeys
+        */
+       public function assertRequiredOptions( array $expectedKeys ) {
+               $actualKeys = array_keys( $this->options );
+               $extraKeys = array_diff( $actualKeys, $expectedKeys );
+               $missingKeys = array_diff( $expectedKeys, $actualKeys );
+               Assert::precondition( !$extraKeys && !$missingKeys,
+                       (
+                       $extraKeys
+                               ? 'Unsupported options passed: ' . implode( ', ', $extraKeys ) . '!'
+                               : ''
+                       ) . ( $extraKeys && $missingKeys ? ' ' : '' ) . (
+                       $missingKeys
+                               ? 'Required options missing: ' . implode( ', ', $missingKeys ) . '!'
+                               : ''
+                       )
+               );
+       }
+
+       /**
+        * @param string $key
+        * @return mixed
+        */
+       public function get( $key ) {
+               if ( !array_key_exists( $key, $this->options ) ) {
+                       throw new InvalidArgumentException( "Unrecognized option \"$key\"" );
+               }
+               return $this->options[$key];
+       }
+}
index decbb0c..65a7b7d 100644 (file)
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * Base class for content handling.
  *
@@ -645,9 +646,6 @@ abstract class ContentHandler {
                $slotDiffRenderer->setStatsdDataFactory( $statsdDataFactory );
                // XXX using the page language would be better, but it's unclear how that should be injected
                $slotDiffRenderer->setLanguage( $contentLanguage );
-               $slotDiffRenderer->setWikiDiff2MovedParagraphDetectionCutoff(
-                       $context->getConfig()->get( 'WikiDiff2MovedParagraphDetectionCutoff' )
-               );
 
                $engine = DifferenceEngine::getEngine();
                if ( $engine === false ) {
@@ -690,6 +688,10 @@ abstract class ContentHandler {
                        $pageLang = Language::factory( $lang );
                }
 
+               // Simplify hook handlers by only passing objects of one type, in case nothing
+               // else has unstubbed the StubUserLang object by now.
+               StubObject::unstub( $wgLang );
+
                Hooks::run( 'PageContentLanguage', [ $title, &$pageLang, $wgLang ] );
 
                return wfGetLangObj( $pageLang );
index d32fa88..87c5ff2 100644 (file)
@@ -25,6 +25,8 @@
  * @author Daniel Kinzler
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * Content object for CSS pages.
  *
@@ -58,11 +60,11 @@ class CssContent extends TextContent {
         * @see TextContent::preSaveTransform
         */
        public function preSaveTransform( Title $title, User $user, ParserOptions $popts ) {
-               global $wgParser;
                // @todo Make pre-save transformation optional for script pages
 
                $text = $this->getText();
-               $pst = $wgParser->preSaveTransform( $text, $title, $user, $popts );
+               $pst = MediaWikiServices::getInstance()->getParser()
+                       ->preSaveTransform( $text, $title, $user, $popts );
 
                return new static( $pst );
        }
index e637798..4804758 100644 (file)
@@ -25,6 +25,8 @@
  * @author Daniel Kinzler
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * Content for JavaScript pages.
  *
@@ -56,12 +58,12 @@ class JavaScriptContent extends TextContent {
         * @return JavaScriptContent
         */
        public function preSaveTransform( Title $title, User $user, ParserOptions $popts ) {
-               global $wgParser;
                // @todo Make pre-save transformation optional for script pages
                // See T34858
 
                $text = $this->getText();
-               $pst = $wgParser->preSaveTransform( $text, $title, $user, $popts );
+               $pst = MediaWikiServices::getInstance()->getParser()
+                       ->preSaveTransform( $text, $title, $user, $popts );
 
                return new static( $pst );
        }
index 2cd1fb3..a1f199d 100644 (file)
@@ -220,7 +220,7 @@ class JsonContent extends TextContent {
                        return Html::rawElement( 'td', [], $this->arrayTable( $val ) );
                }
 
-               return Html::element( 'td', [ 'class' => 'value' ], $this->primitiveValue( $val ) );
+               return Html::element( 'td', [ 'class' => 'mw-json-value' ], $this->primitiveValue( $val ) );
        }
 
        /**
index 750b958..71dd35c 100644 (file)
@@ -253,11 +253,12 @@ class TextContent extends AbstractContent {
        protected function fillParserOutput( Title $title, $revId,
                ParserOptions $options, $generateHtml, ParserOutput &$output
        ) {
-               global $wgParser, $wgTextModelsToParse;
+               global $wgTextModelsToParse;
 
                if ( in_array( $this->getModel(), $wgTextModelsToParse ) ) {
                        // parse just to get links etc into the database, HTML is replaced below.
-                       $output = $wgParser->parse( $this->getText(), $title, $options, true, true, $revId );
+                       $output = MediaWikiServices::getInstance()->getParser()
+                               ->parse( $this->getText(), $title, $options, true, true, $revId );
                }
 
                if ( $generateHtml ) {
index 0e03e72..2f3a6f6 100644 (file)
@@ -154,7 +154,7 @@ class WikiTextStructure {
                        'enableSectionEditTokens' => false,
                        'allowTOC' => false,
                ] );
-               if ( strlen( $text ) == 0 ) {
+               if ( $text === '' ) {
                        $this->allText = "";
                        // empty text - nothing to seek here
                        return;
index 3e2313c..455eb0d 100644 (file)
@@ -59,10 +59,9 @@ class WikitextContent extends TextContent {
         * @see Content::getSection()
         */
        public function getSection( $sectionId ) {
-               global $wgParser;
-
                $text = $this->getText();
-               $sect = $wgParser->getSection( $text, $sectionId, false );
+               $sect = MediaWikiServices::getInstance()->getParser()
+                       ->getSection( $text, $sectionId, false );
 
                if ( $sect === false ) {
                        return false;
@@ -109,9 +108,8 @@ class WikitextContent extends TextContent {
                        }
                } else {
                        # Replacing an existing section; roll out the big guns
-                       global $wgParser;
-
-                       $text = $wgParser->replaceSection( $oldtext, $sectionId, $text );
+                       $text = MediaWikiServices::getInstance()->getParser()
+                               ->replaceSection( $oldtext, $sectionId, $text );
                }
 
                $newContent = new static( $text );
@@ -147,10 +145,10 @@ class WikitextContent extends TextContent {
         * @return Content
         */
        public function preSaveTransform( Title $title, User $user, ParserOptions $popts ) {
-               global $wgParser;
-
                $text = $this->getText();
-               $pst = $wgParser->preSaveTransform( $text, $title, $user, $popts );
+
+               $parser = MediaWikiServices::getInstance()->getParser();
+               $pst = $parser->preSaveTransform( $text, $title, $user, $popts );
 
                if ( $text === $pst ) {
                        return $this;
@@ -158,7 +156,7 @@ class WikitextContent extends TextContent {
 
                $ret = new static( $pst );
 
-               if ( $wgParser->getOutput()->getFlag( 'user-signature' ) ) {
+               if ( $parser->getOutput()->getFlag( 'user-signature' ) ) {
                        $ret->hadSignature = true;
                }
 
@@ -176,10 +174,9 @@ class WikitextContent extends TextContent {
         * @return Content
         */
        public function preloadTransform( Title $title, ParserOptions $popts, $params = [] ) {
-               global $wgParser;
-
                $text = $this->getText();
-               $plt = $wgParser->getPreloadText( $text, $title, $popts, $params );
+               $plt = MediaWikiServices::getInstance()->getParser()
+                       ->getPreloadText( $text, $title, $popts, $params );
 
                return new static( $plt );
        }
@@ -329,7 +326,7 @@ class WikitextContent extends TextContent {
 
        /**
         * Returns a ParserOutput object resulting from parsing the content's text
-        * using $wgParser.
+        * using the global Parser service.
         *
         * @param Title $title
         * @param int $revId Revision to pass to the parser (default: null)
@@ -341,8 +338,6 @@ class WikitextContent extends TextContent {
        protected function fillParserOutput( Title $title, $revId,
                        ParserOptions $options, $generateHtml, ParserOutput &$output
        ) {
-               global $wgParser;
-
                $stackTrace = ( new RuntimeException() )->getTraceAsString();
                if ( $this->previousParseStackTrace ) {
                        // NOTE: there may be legitimate changes to re-parse the same WikiText content,
@@ -366,7 +361,8 @@ class WikitextContent extends TextContent {
                $this->previousParseStackTrace = $stackTrace;
 
                list( $redir, $text ) = $this->getRedirectTargetAndText();
-               $output = $wgParser->parse( $text, $title, $options, true, true, $revId );
+               $output = MediaWikiServices::getInstance()->getParser()
+                       ->parse( $text, $title, $options, true, true, $revId );
 
                // Add redirect indicator at the top
                if ( $redir ) {
index 9817c3f..d32617e 100644 (file)
@@ -91,11 +91,7 @@ class DerivativeContext extends ContextSource implements MutableContext {
         * @return Config
         */
        public function getConfig() {
-               if ( !is_null( $this->config ) ) {
-                       return $this->config;
-               } else {
-                       return $this->getContext()->getConfig();
-               }
+               return $this->config ?: $this->getContext()->getConfig();
        }
 
        /**
@@ -111,11 +107,7 @@ class DerivativeContext extends ContextSource implements MutableContext {
         * @return Timing
         */
        public function getTiming() {
-               if ( !is_null( $this->timing ) ) {
-                       return $this->timing;
-               } else {
-                       return $this->getContext()->getTiming();
-               }
+               return $this->timing ?: $this->getContext()->getTiming();
        }
 
        /**
@@ -129,11 +121,7 @@ class DerivativeContext extends ContextSource implements MutableContext {
         * @return WebRequest
         */
        public function getRequest() {
-               if ( !is_null( $this->request ) ) {
-                       return $this->request;
-               } else {
-                       return $this->getContext()->getRequest();
-               }
+               return $this->request ?: $this->getContext()->getRequest();
        }
 
        /**
@@ -147,11 +135,7 @@ class DerivativeContext extends ContextSource implements MutableContext {
         * @return Title|null
         */
        public function getTitle() {
-               if ( !is_null( $this->title ) ) {
-                       return $this->title;
-               } else {
-                       return $this->getContext()->getTitle();
-               }
+               return $this->title ?: $this->getContext()->getTitle();
        }
 
        /**
@@ -165,11 +149,13 @@ class DerivativeContext extends ContextSource implements MutableContext {
        public function canUseWikiPage() {
                if ( $this->wikipage !== null ) {
                        return true;
-               } elseif ( $this->title !== null ) {
+               }
+
+               if ( $this->title !== null ) {
                        return $this->title->canExist();
-               } else {
-                       return $this->getContext()->canUseWikiPage();
                }
+
+               return $this->getContext()->canUseWikiPage();
        }
 
        /**
@@ -190,11 +176,7 @@ class DerivativeContext extends ContextSource implements MutableContext {
         * @return WikiPage
         */
        public function getWikiPage() {
-               if ( !is_null( $this->wikipage ) ) {
-                       return $this->wikipage;
-               } else {
-                       return $this->getContext()->getWikiPage();
-               }
+               return $this->wikipage ?: $this->getContext()->getWikiPage();
        }
 
        /**
@@ -208,11 +190,7 @@ class DerivativeContext extends ContextSource implements MutableContext {
         * @return OutputPage
         */
        public function getOutput() {
-               if ( !is_null( $this->output ) ) {
-                       return $this->output;
-               } else {
-                       return $this->getContext()->getOutput();
-               }
+               return $this->output ?: $this->getContext()->getOutput();
        }
 
        /**
@@ -226,11 +204,7 @@ class DerivativeContext extends ContextSource implements MutableContext {
         * @return User
         */
        public function getUser() {
-               if ( !is_null( $this->user ) ) {
-                       return $this->user;
-               } else {
-                       return $this->getContext()->getUser();
-               }
+               return $this->user ?: $this->getContext()->getUser();
        }
 
        /**
@@ -255,11 +229,7 @@ class DerivativeContext extends ContextSource implements MutableContext {
         * @since 1.19
         */
        public function getLanguage() {
-               if ( !is_null( $this->lang ) ) {
-                       return $this->lang;
-               } else {
-                       return $this->getContext()->getLanguage();
-               }
+               return $this->lang ?: $this->getContext()->getLanguage();
        }
 
        /**
@@ -274,11 +244,7 @@ class DerivativeContext extends ContextSource implements MutableContext {
         * @return Skin
         */
        public function getSkin() {
-               if ( !is_null( $this->skin ) ) {
-                       return $this->skin;
-               } else {
-                       return $this->getContext()->getSkin();
-               }
+               return $this->skin ?: $this->getContext()->getSkin();
        }
 
        /**
index 2cbe67c..aada514 100644 (file)
@@ -345,12 +345,8 @@ class RequestContext implements IContextSource, MutableContext {
                                        $obj = Language::factory( $code );
                                        $this->lang = $obj;
                                }
-
-                               unset( $this->recursion );
-                       }
-                       catch ( Exception $ex ) {
+                       } finally {
                                unset( $this->recursion );
-                               throw $ex;
                        }
                }
 
@@ -372,7 +368,7 @@ class RequestContext implements IContextSource, MutableContext {
                if ( $this->skin === null ) {
                        $skin = null;
                        Hooks::run( 'RequestContextCreateSkin', [ $this, &$skin ] );
-                       $factory = SkinFactory::getDefaultInstance();
+                       $factory = MediaWikiServices::getInstance()->getSkinFactory();
 
                        // If the hook worked try to set a skin from it
                        if ( $skin instanceof Skin ) {
index 8900962..e099b38 100644 (file)
@@ -2,7 +2,7 @@
 
 use MediaWiki\MediaWikiServices;
 use Wikimedia\Rdbms\IDatabase;
-use Wikimedia\Rdbms\LoadBalancer;
+use Wikimedia\Rdbms\ILoadBalancer;
 
 /**
  * Base class for objects that allow access to other wiki's databases using
@@ -88,7 +88,7 @@ abstract class DBAccessBase implements IDBAccessObject {
         *
         * @since 1.21
         *
-        * @return LoadBalancer The database load balancer object
+        * @return ILoadBalancer The database load balancer object
         */
        public function getLoadBalancer() {
                $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
index d427724..cdf0f79 100644 (file)
@@ -25,16 +25,16 @@ use Wikimedia\Rdbms\IMaintainableDatabase;
 
 class CloneDatabase {
        /** @var string Table prefix for cloning */
-       private $newTablePrefix = '';
+       private $newTablePrefix;
 
        /** @var string Current table prefix */
-       private $oldTablePrefix = '';
+       private $oldTablePrefix;
 
        /** @var array List of tables to be cloned */
-       private $tablesToClone = [];
+       private $tablesToClone;
 
        /** @var bool Should we DROP tables containing the new names? */
-       private $dropCurrentTables = true;
+       private $dropCurrentTables;
 
        /** @var bool Whether to use temporary tables or not */
        private $useTemporaryTables = true;
@@ -128,7 +128,7 @@ class CloneDatabase {
        }
 
        /**
-        * Change the table prefix on all open DB connections/
+        * Change the table prefix on all open DB connections
         *
         * @param string $prefix
         * @return void
index a051d83..f4753d6 100644 (file)
@@ -21,7 +21,7 @@
  * @ingroup Database
  */
 
-use MediaWiki\MediaWikiServices;
+use Wikimedia\Timestamp\ConvertibleTimestamp;
 use Wikimedia\Rdbms\Database;
 use Wikimedia\Rdbms\DatabaseDomain;
 use Wikimedia\Rdbms\Blob;
@@ -52,15 +52,18 @@ class DatabaseOracle extends Database {
        /** @var array */
        private $mFieldInfoCache = [];
 
-       function __construct( array $p ) {
-               global $wgDBprefix;
+       /** @var string[] Map of (reserved table name => alternate table name) */
+       private $keywordTableMap = [];
 
-               if ( $p['tablePrefix'] == 'get from global' ) {
-                       $p['tablePrefix'] = $wgDBprefix;
-               }
-               $p['tablePrefix'] = strtoupper( $p['tablePrefix'] );
-               parent::__construct( $p );
-               Hooks::run( 'DatabaseOraclePostInit', [ $this ] );
+       /**
+        * @see Database::__construct()
+        * @param array $params Additional parameters include:
+        *   - keywordTableMap : Map of reserved table names to alternative table names to use
+        */
+       function __construct( array $params ) {
+               $this->keywordTableMap = $params['keywordTableMap'] ?? [];
+               $params['tablePrefix'] = strtoupper( $params['tablePrefix'] );
+               parent::__construct( $params );
        }
 
        function __destruct() {
@@ -84,8 +87,6 @@ class DatabaseOracle extends Database {
        }
 
        protected function open( $server, $user, $password, $dbName, $schema, $tablePrefix ) {
-               global $wgDBOracleDRCP;
-
                if ( !function_exists( 'oci_connect' ) ) {
                        throw new DBConnectionError(
                                $this,
@@ -112,11 +113,7 @@ class DatabaseOracle extends Database {
                        return null;
                }
 
-               if ( $wgDBOracleDRCP ) {
-                       $this->setFlag( DBO_PERSISTENT );
-               }
-
-               $session_mode = $this->flags & DBO_SYSDBA ? OCI_SYSDBA : OCI_DEFAULT;
+               $session_mode = ( $this->flags & DBO_SYSDBA ) ? OCI_SYSDBA : OCI_DEFAULT;
 
                Wikimedia\suppressWarnings();
                if ( $this->flags & DBO_PERSISTENT ) {
@@ -189,9 +186,8 @@ class DatabaseOracle extends Database {
         * @return bool|mixed|ORAResult
         */
        protected function doQuery( $sql ) {
-               wfDebug( "SQL: [$sql]\n" );
-               if ( !StringUtils::isUtf8( $sql ) ) {
-                       throw new InvalidArgumentException( "SQL encoding is invalid\n$sql" );
+               if ( !mb_check_encoding( (string)$sql, 'UTF-8' ) ) {
+                       throw new DBUnexpectedError( $this, "SQL encoding is invalid\n$sql" );
                }
 
                // handle some oracle specifics
@@ -425,7 +421,11 @@ class DatabaseOracle extends Database {
                }
 
                if ( $val === null ) {
-                       if ( $col_info != false && $col_info->isNullable() == 0 && $col_info->defaultValue() != null ) {
+                       if (
+                               $col_info != false &&
+                               $col_info->isNullable() == 0 &&
+                               $col_info->defaultValue() != null
+                       ) {
                                $bind .= 'DEFAULT';
                        } else {
                                $bind .= 'NULL';
@@ -470,7 +470,7 @@ class DatabaseOracle extends Database {
                $this->mLastResult = $stmt = oci_parse( $this->conn, $sql );
                if ( $stmt === false ) {
                        $e = oci_error( $this->conn );
-                       $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ );
+                       $this->reportQueryError( $e['message'], $e['code'], $sql, $fname );
 
                        return false;
                }
@@ -486,15 +486,17 @@ class DatabaseOracle extends Database {
                                }
 
                                // backward compatibility
-                               if ( preg_match( '/^timestamp.*/i', $col_type ) == 1 && strtolower( $val ) == 'infinity' ) {
+                               if (
+                                       preg_match( '/^timestamp.*/i', $col_type ) == 1 &&
+                                       strtolower( $val ) == 'infinity'
+                               ) {
                                        $val = $this->getInfinity();
                                }
 
-                               $val = MediaWikiServices::getInstance()->getContentLanguage()->
-                                       checkTitleEncoding( $val );
+                               $val = $this->getVerifiedUTF8( $val );
                                if ( oci_bind_by_name( $stmt, ":$col", $val, -1, SQLT_CHR ) === false ) {
                                        $e = oci_error( $stmt );
-                                       $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ );
+                                       $this->reportQueryError( $e['message'], $e['code'], $sql, $fname );
 
                                        return false;
                                }
@@ -503,7 +505,10 @@ class DatabaseOracle extends Database {
                                $lob[$col] = oci_new_descriptor( $this->conn, OCI_D_LOB );
                                if ( $lob[$col] === false ) {
                                        $e = oci_error( $stmt );
-                                       throw new DBUnexpectedError( $this, "Cannot create LOB descriptor: " . $e['message'] );
+                                       throw new DBUnexpectedError(
+                                               $this,
+                                               "Cannot create LOB descriptor: " . $e['message']
+                                       );
                                }
 
                                if ( is_object( $val ) ) {
@@ -525,7 +530,7 @@ class DatabaseOracle extends Database {
                if ( oci_execute( $stmt, $this->execFlags() ) === false ) {
                        $e = oci_error( $stmt );
                        if ( !$this->ignoreDupValOnIndex || $e['code'] != '1' ) {
-                               $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ );
+                               $this->reportQueryError( $e['message'], $e['code'], $sql, $fname );
 
                                return false;
                        } else {
@@ -559,7 +564,8 @@ class DatabaseOracle extends Database {
                if ( $sequenceData !== false &&
                        !isset( $varMap[$sequenceData['column']] )
                ) {
-                       $varMap[$sequenceData['column']] = 'GET_SEQUENCE_VALUE(\'' . $sequenceData['sequence'] . '\')';
+                       $varMap[$sequenceData['column']] =
+                               'GET_SEQUENCE_VALUE(\'' . $sequenceData['sequence'] . '\')';
                }
 
                // count-alias subselect fields to avoid abigious definition errors
@@ -578,7 +584,8 @@ class DatabaseOracle extends Database {
                        $selectJoinConds
                );
 
-               $sql = "INSERT INTO $destTable (" . implode( ',', array_keys( $varMap ) ) . ') ' . $selectSql;
+               $sql = "INSERT INTO $destTable (" .
+                       implode( ',', array_keys( $varMap ) ) . ') ' . $selectSql;
 
                if ( in_array( 'IGNORE', $insertOptions ) ) {
                        $this->ignoreDupValOnIndex = true;
@@ -617,24 +624,21 @@ class DatabaseOracle extends Database {
                return parent::upsert( $table, $rows, $uniqueIndexes, $set, $fname );
        }
 
-       function tableName( $name, $format = 'quoted' ) {
-               /*
-               Replace reserved words with better ones
-               Using uppercase because that's the only way Oracle can handle
-               quoted tablenames
-               */
-               switch ( $name ) {
-                       case 'user':
-                               $name = 'MWUSER';
-                               break;
-                       case 'text':
-                               $name = 'PAGECONTENT';
-                               break;
-               }
+       public function tableName( $name, $format = 'quoted' ) {
+               // Replace reserved words with better ones
+               $name = $this->remappedTableName( $name );
 
                return strtoupper( parent::tableName( $name, $format ) );
        }
 
+       /**
+        * @param string $name
+        * @return string Value of $name or remapped name if $name is a reserved keyword
+        */
+       public function remappedTableName( $name ) {
+               return $this->keywordTableMap[$name] ?? $name;
+       }
+
        function tableNameInternal( $name ) {
                $name = $this->tableName( $name );
 
@@ -645,23 +649,31 @@ class DatabaseOracle extends Database {
         * Return sequence_name if table has a sequence
         *
         * @param string $table
-        * @return bool
+        * @return string[]|bool
         */
        private function getSequenceData( $table ) {
                if ( $this->sequenceData == null ) {
-                       $result = $this->doQuery( "SELECT lower(asq.sequence_name),
-                               lower(atc.table_name),
-                               lower(atc.column_name)
-                       FROM all_sequences asq, all_tab_columns atc
-                       WHERE decode(
-                                       atc.table_name,
-                                       '{$this->tablePrefix}MWUSER',
-                                       '{$this->tablePrefix}USER',
-                                       atc.table_name
-                               ) || '_' ||
-                               atc.column_name || '_SEQ' = '{$this->tablePrefix}' || asq.sequence_name
-                               AND asq.sequence_owner = upper('{$this->getDBname()}')
-                               AND atc.owner = upper('{$this->getDBname()}')" );
+                       $dbname = $this->currentDomain->getDatabase();
+                       $prefix = $this->currentDomain->getTablePrefix();
+                       // See https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions040.htm
+                       $decodeArgs = [ 'atc.table_name' ]; // the switch
+                       foreach ( $this->keywordTableMap as $reserved => $alternative ) {
+                               $search = strtoupper( $prefix . $alternative ); // case
+                               $replace = strtoupper( $prefix . $reserved ); // result
+                               $decodeArgs[] = $this->addQuotes( $search );
+                               $decodeArgs[] = $this->addQuotes( $replace );
+                       }
+                       $decodeArgs[] = [ 'atc.table_name' ]; // default
+                       $decodeArgs = implode( ', ', $decodeArgs );
+
+                       $result = $this->doQuery(
+                               "SELECT lower(asq.sequence_name), lower(atc.table_name), lower(atc.column_name)
+                               FROM all_sequences asq, all_tab_columns atc
+                               WHERE decode({$decodeArgs}) || '_' ||
+                               atc.column_name || '_SEQ' = '{$prefix}' || asq.sequence_name
+                               AND asq.sequence_owner = upper('{$dbname}')
+                               AND atc.owner = upper('{$dbname}')"
+                       );
 
                        while ( ( $row = $result->fetchRow() ) !== false ) {
                                $this->sequenceData[$row[1]] = [
@@ -700,14 +712,6 @@ class DatabaseOracle extends Database {
                return new Blob( $b );
        }
 
-       function decodeBlob( $b ) {
-               if ( $b instanceof Blob ) {
-                       $b = $b->fetch();
-               }
-
-               return $b;
-       }
-
        function unionQueries( $sqls, $all ) {
                $glue = ' UNION ALL ';
 
@@ -723,13 +727,14 @@ class DatabaseOracle extends Database {
                $fname = __METHOD__
        ) {
                $temporary = $temporary ? 'TRUE' : 'FALSE';
+               $tablePrefix = $this->currentDomain->getTablePrefix();
 
                $newName = strtoupper( $newName );
                $oldName = strtoupper( $oldName );
 
-               $tabName = substr( $newName, strlen( $this->tablePrefix ) );
+               $tabName = substr( $newName, strlen( $tablePrefix ) );
                $oldPrefix = substr( $oldName, 0, strlen( $oldName ) - strlen( $tabName ) );
-               $newPrefix = strtoupper( $this->tablePrefix );
+               $newPrefix = strtoupper( $tablePrefix );
 
                return $this->doQuery( "BEGIN DUPLICATE_TABLE( '$tabName', " .
                        "'$oldPrefix', '$newPrefix', $temporary ); END;" );
@@ -769,8 +774,10 @@ class DatabaseOracle extends Database {
                return $this->doQuery( "DROP TABLE $tableName CASCADE CONSTRAINTS PURGE" );
        }
 
-       function timestamp( $ts = 0 ) {
-               return wfTimestamp( TS_ORACLE, $ts );
+       public function timestamp( $ts = 0 ) {
+               $t = new ConvertibleTimestamp( $ts );
+               // Let errors bubble up to avoid putting garbage in the DB
+               return $t->getTimestamp( TS_ORACLE );
        }
 
        /**
@@ -925,7 +932,10 @@ class DatabaseOracle extends Database {
         */
        function fieldInfo( $table, $field ) {
                if ( is_array( $table ) ) {
-                       throw new DBUnexpectedError( $this, 'DatabaseOracle::fieldInfo called with table array!' );
+                       throw new DBUnexpectedError(
+                               $this,
+                               'DatabaseOracle::fieldInfo called with table array!'
+                       );
                }
 
                return $this->fieldInfoMulti( $table, $field );
@@ -969,7 +979,7 @@ class DatabaseOracle extends Database {
                // Defines must comply with ^define\s*([^\s=]*)\s*=\s?'\{\$([^\}]*)\}';
                while ( !feof( $fp ) ) {
                        if ( $lineCallback ) {
-                               call_user_func( $lineCallback );
+                               $lineCallback();
                        }
                        $line = trim( fgets( $fp, 1024 ) );
                        $sl = strlen( $line ) - 1;
@@ -1015,7 +1025,7 @@ class DatabaseOracle extends Database {
 
                                        $cmd = $this->replaceVars( $cmd );
                                        if ( $inputCallback ) {
-                                               call_user_func( $inputCallback, $cmd );
+                                               $inputCallback( $cmd );
                                        }
                                        $res = $this->doQuery( $cmd );
                                        if ( $resultCallback ) {
@@ -1074,12 +1084,7 @@ class DatabaseOracle extends Database {
        }
 
        function addQuotes( $s ) {
-               $contLang = MediaWikiServices::getInstance()->getContentLanguage();
-               if ( isset( $contLang->mLoaded ) && $contLang->mLoaded ) {
-                       $s = $contLang->checkTitleEncoding( $s );
-               }
-
-               return "'" . $this->strencode( $s ) . "'";
+               return "'" . $this->strencode( $this->getVerifiedUTF8( $s ) ) . "'";
        }
 
        public function addIdentifierQuotes( $s ) {
@@ -1103,11 +1108,9 @@ class DatabaseOracle extends Database {
                $col_type = $col_info != false ? $col_info->type() : 'CONSTANT';
                if ( $col_type == 'CLOB' ) {
                        $col = 'TO_CHAR(' . $col . ')';
-                       $val =
-                               MediaWikiServices::getInstance()->getContentLanguage()->checkTitleEncoding( $val );
+                       $val = $this->getVerifiedUTF8( $val );
                } elseif ( $col_type == 'VARCHAR2' ) {
-                       $val =
-                               MediaWikiServices::getInstance()->getContentLanguage()->checkTitleEncoding( $val );
+                       $val = $this->getVerifiedUTF8( $val );
                }
        }
 
@@ -1273,12 +1276,14 @@ class DatabaseOracle extends Database {
                                        $val = $val->getData();
                                }
 
-                               if ( preg_match( '/^timestamp.*/i', $col_type ) == 1 && strtolower( $val ) == 'infinity' ) {
+                               if (
+                                       preg_match( '/^timestamp.*/i', $col_type ) == 1 &&
+                                       strtolower( $val ) == 'infinity'
+                               ) {
                                        $val = '31-12-2030 12:00:00.000000';
                                }
 
-                               $val = MediaWikiServices::getInstance()->getContentLanguage()->
-                                       checkTitleEncoding( $val );
+                               $val = $this->getVerifiedUTF8( $val );
                                if ( oci_bind_by_name( $stmt, ":$col", $val ) === false ) {
                                        $e = oci_error( $stmt );
                                        $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ );
@@ -1290,7 +1295,10 @@ class DatabaseOracle extends Database {
                                $lob[$col] = oci_new_descriptor( $this->conn, OCI_D_LOB );
                                if ( $lob[$col] === false ) {
                                        $e = oci_error( $stmt );
-                                       throw new DBUnexpectedError( $this, "Cannot create LOB descriptor: " . $e['message'] );
+                                       throw new DBUnexpectedError(
+                                               $this,
+                                               "Cannot create LOB descriptor: " . $e['message']
+                                       );
                                }
 
                                if ( is_object( $val ) ) {
@@ -1350,10 +1358,6 @@ class DatabaseOracle extends Database {
                return 'BITOR(' . $fieldLeft . ', ' . $fieldRight . ')';
        }
 
-       function getServer() {
-               return $this->server;
-       }
-
        public function buildGroupConcatField(
                $delim, $table, $field, $conds = '', $join_conds = []
        ) {
@@ -1383,4 +1387,16 @@ class DatabaseOracle extends Database {
        public function getInfinity() {
                return '31-12-2030 12:00:00.000000';
        }
+
+       /**
+        * @param string $s
+        * @return string
+        */
+       private function getVerifiedUTF8( $s ) {
+               if ( mb_check_encoding( (string)$s, 'UTF-8' ) ) {
+                       return $s; // valid
+               }
+
+               throw new DBUnexpectedError( $this, "Non BLOB/CLOB field must be UTF-8." );
+       }
 }
index cb1a69d..5b62984 100644 (file)
@@ -21,8 +21,8 @@
  * @ingroup Database
  */
 
+use MediaWiki\Config\ServiceOptions;
 use MediaWiki\Logger\LoggerFactory;
-use MediaWiki\MediaWikiServices;
 use Wikimedia\Rdbms\LBFactory;
 use Wikimedia\Rdbms\DatabaseDomain;
 
@@ -35,24 +35,61 @@ abstract class MWLBFactory {
        /** @var array Cache of already-logged deprecation messages */
        private static $loggedDeprecations = [];
 
+       /**
+        * TODO Make this a const when HHVM support is dropped (T192166)
+        *
+        * @var array
+        * @since 1.34
+        */
+       public static $applyDefaultConfigOptions = [
+               'DBcompress',
+               'DBDefaultGroup',
+               'DBmwschema',
+               'DBname',
+               'DBpassword',
+               'DBport',
+               'DBprefix',
+               'DBserver',
+               'DBservers',
+               'DBssl',
+               'DBtype',
+               'DBuser',
+               'DBWindowsAuthentication',
+               'DebugDumpSql',
+               'DebugLogFile',
+               'ExternalServers',
+               'SQLiteDataDir',
+               'SQLMode',
+       ];
+
        /**
         * @param array $lbConf Config for LBFactory::__construct()
-        * @param Config $mainConfig Main config object from MediaWikiServices
+        * @param ServiceOptions $options
         * @param ConfiguredReadOnlyMode $readOnlyMode
+        * @param BagOStuff $srvCace
+        * @param BagOStuff $mainStash
+        * @param WANObjectCache $wanCache
         * @return array
         */
-       public static function applyDefaultConfig( array $lbConf, Config $mainConfig,
-               ConfiguredReadOnlyMode $readOnlyMode
+       public static function applyDefaultConfig(
+               array $lbConf,
+               ServiceOptions $options,
+               ConfiguredReadOnlyMode $readOnlyMode,
+               BagOStuff $srvCace,
+               BagOStuff $mainStash,
+               WANObjectCache $wanCache
        ) {
+               $options->assertRequiredOptions( self::$applyDefaultConfigOptions );
+
                global $wgCommandLineMode;
 
-               static $typesWithSchema = [ 'postgres', 'msssql' ];
+               $typesWithSchema = self::getDbTypesWithSchemas();
 
                $lbConf += [
                        'localDomain' => new DatabaseDomain(
-                               $mainConfig->get( 'DBname' ),
-                               $mainConfig->get( 'DBmwschema' ),
-                               $mainConfig->get( 'DBprefix' )
+                               $options->get( 'DBname' ),
+                               $options->get( 'DBmwschema' ),
+                               $options->get( 'DBprefix' )
                        ),
                        'profiler' => function ( $section ) {
                                return Profiler::instance()->scopedProfileIn( $section );
@@ -67,102 +104,140 @@ abstract class MWLBFactory {
                        'cliMode' => $wgCommandLineMode,
                        'hostname' => wfHostname(),
                        'readOnlyReason' => $readOnlyMode->getReason(),
-                       'defaultGroup' => $mainConfig->get( 'DBDefaultGroup' ),
+                       'defaultGroup' => $options->get( 'DBDefaultGroup' ),
                ];
 
+               $serversCheck = [];
                // When making changes here, remember to also specify MediaWiki-specific options
                // for Database classes in the relevant Installer subclass.
                // Such as MysqlInstaller::openConnection and PostgresInstaller::openConnectionWithParams.
                if ( $lbConf['class'] === Wikimedia\Rdbms\LBFactorySimple::class ) {
                        if ( isset( $lbConf['servers'] ) ) {
-                               // Server array is already explicitly configured; leave alone
-                       } elseif ( is_array( $mainConfig->get( 'DBservers' ) ) ) {
-                               foreach ( $mainConfig->get( 'DBservers' ) as $i => $server ) {
-                                       if ( $server['type'] === 'sqlite' ) {
-                                               $server += [ 'dbDirectory' => $mainConfig->get( 'SQLiteDataDir' ) ];
-                                       } elseif ( $server['type'] === 'postgres' ) {
-                                               $server += [
-                                                       'port' => $mainConfig->get( 'DBport' ),
-                                                       // Work around the reserved word usage in MediaWiki schema
-                                                       'keywordTableMap' => [ 'user' => 'mwuser', 'text' => 'pagecontent' ]
-                                               ];
-                                       } elseif ( $server['type'] === 'mssql' ) {
-                                               $server += [
-                                                       'port' => $mainConfig->get( 'DBport' ),
-                                                       'useWindowsAuth' => $mainConfig->get( 'DBWindowsAuthentication' )
-                                               ];
-                                       }
-
-                                       if ( in_array( $server['type'], $typesWithSchema, true ) ) {
-                                               $server += [ 'schema' => $mainConfig->get( 'DBmwschema' ) ];
-                                       }
-
-                                       $server += [
-                                               'tablePrefix' => $mainConfig->get( 'DBprefix' ),
-                                               'flags' => DBO_DEFAULT,
-                                               'sqlMode' => $mainConfig->get( 'SQLMode' ),
-                                               'utf8Mode' => $mainConfig->get( 'DBmysql5' )
-                                       ];
-
-                                       $lbConf['servers'][$i] = $server;
+                               // Server array is already explicitly configured
+                       } elseif ( is_array( $options->get( 'DBservers' ) ) ) {
+                               $lbConf['servers'] = [];
+                               foreach ( $options->get( 'DBservers' ) as $i => $server ) {
+                                       $lbConf['servers'][$i] = self::initServerInfo( $server, $options );
                                }
                        } else {
-                               $flags = DBO_DEFAULT;
-                               $flags |= $mainConfig->get( 'DebugDumpSql' ) ? DBO_DEBUG : 0;
-                               $flags |= $mainConfig->get( 'DBssl' ) ? DBO_SSL : 0;
-                               $flags |= $mainConfig->get( 'DBcompress' ) ? DBO_COMPRESS : 0;
-                               $server = [
-                                       'host' => $mainConfig->get( 'DBserver' ),
-                                       'user' => $mainConfig->get( 'DBuser' ),
-                                       'password' => $mainConfig->get( 'DBpassword' ),
-                                       'dbname' => $mainConfig->get( 'DBname' ),
-                                       'tablePrefix' => $mainConfig->get( 'DBprefix' ),
-                                       'type' => $mainConfig->get( 'DBtype' ),
-                                       'load' => 1,
-                                       'flags' => $flags,
-                                       'sqlMode' => $mainConfig->get( 'SQLMode' ),
-                                       'utf8Mode' => $mainConfig->get( 'DBmysql5' )
-                               ];
-                               if ( in_array( $server['type'], $typesWithSchema, true ) ) {
-                                       $server += [ 'schema' => $mainConfig->get( 'DBmwschema' ) ];
-                               }
-                               if ( $server['type'] === 'sqlite' ) {
-                                       $server[ 'dbDirectory'] = $mainConfig->get( 'SQLiteDataDir' );
-                               } elseif ( $server['type'] === 'postgres' ) {
-                                       $server['port'] = $mainConfig->get( 'DBport' );
-                                       // Work around the reserved word usage in MediaWiki schema
-                                       $server['keywordTableMap'] = [ 'user' => 'mwuser', 'text' => 'pagecontent' ];
-                               } elseif ( $server['type'] === 'mssql' ) {
-                                       $server['port'] = $mainConfig->get( 'DBport' );
-                                       $server['useWindowsAuth'] = $mainConfig->get( 'DBWindowsAuthentication' );
-                               }
+                               $server = self::initServerInfo(
+                                       [
+                                               'host' => $options->get( 'DBserver' ),
+                                               'user' => $options->get( 'DBuser' ),
+                                               'password' => $options->get( 'DBpassword' ),
+                                               'dbname' => $options->get( 'DBname' ),
+                                               'type' => $options->get( 'DBtype' ),
+                                               'load' => 1
+                                       ],
+                                       $options
+                               );
+
+                               $server['flags'] |= $options->get( 'DBssl' ) ? DBO_SSL : 0;
+                               $server['flags'] |= $options->get( 'DBcompress' ) ? DBO_COMPRESS : 0;
+
                                $lbConf['servers'] = [ $server ];
                        }
                        if ( !isset( $lbConf['externalClusters'] ) ) {
-                               $lbConf['externalClusters'] = $mainConfig->get( 'ExternalServers' );
+                               $lbConf['externalClusters'] = $options->get( 'ExternalServers' );
                        }
+
+                       $serversCheck = $lbConf['servers'];
                } elseif ( $lbConf['class'] === Wikimedia\Rdbms\LBFactoryMulti::class ) {
                        if ( isset( $lbConf['serverTemplate'] ) ) {
                                if ( in_array( $lbConf['serverTemplate']['type'], $typesWithSchema, true ) ) {
-                                       $lbConf['serverTemplate']['schema'] = $mainConfig->get( 'DBmwschema' );
+                                       $lbConf['serverTemplate']['schema'] = $options->get( 'DBmwschema' );
                                }
-                               $lbConf['serverTemplate']['sqlMode'] = $mainConfig->get( 'SQLMode' );
-                               $lbConf['serverTemplate']['utf8Mode'] = $mainConfig->get( 'DBmysql5' );
+                               $lbConf['serverTemplate']['sqlMode'] = $options->get( 'SQLMode' );
                        }
+                       $serversCheck = [ $lbConf['serverTemplate'] ] ?? [];
                }
 
-               $services = MediaWikiServices::getInstance();
+               self::assertValidServerConfigs( $serversCheck, $options->get( 'DBname' ),
+                       $options->get( 'DBprefix' ) );
+
+               $lbConf = self::injectObjectCaches( $lbConf, $srvCace, $mainStash, $wanCache );
+
+               return $lbConf;
+       }
+
+       /**
+        * @return array
+        */
+       private static function getDbTypesWithSchemas() {
+               return [ 'postgres', 'msssql' ];
+       }
+
+       /**
+        * @param array $server
+        * @param ServiceOptions $options
+        * @return array
+        */
+       private static function initServerInfo( array $server, ServiceOptions $options ) {
+               if ( $server['type'] === 'sqlite' ) {
+                       $httpMethod = $_SERVER['REQUEST_METHOD'] ?? null;
+                       // T93097: hint for how file-based databases (e.g. sqlite) should go about locking.
+                       // See https://www.sqlite.org/lang_transaction.html
+                       // See https://www.sqlite.org/lockingv3.html#shared_lock
+                       $isHttpRead = in_array( $httpMethod, [ 'GET', 'HEAD', 'OPTIONS', 'TRACE' ] );
+                       $server += [
+                               'dbDirectory' => $options->get( 'SQLiteDataDir' ),
+                               'trxMode' => $isHttpRead ? 'DEFERRED' : 'IMMEDIATE'
+                       ];
+               } elseif ( $server['type'] === 'postgres' ) {
+                       $server += [
+                               'port' => $options->get( 'DBport' ),
+                               // Work around the reserved word usage in MediaWiki schema
+                               'keywordTableMap' => [ 'user' => 'mwuser', 'text' => 'pagecontent' ]
+                       ];
+               } elseif ( $server['type'] === 'oracle' ) {
+                       $server += [
+                               // Work around the reserved word usage in MediaWiki schema
+                               'keywordTableMap' => [ 'user' => 'mwuser', 'text' => 'pagecontent' ]
+                       ];
+               } elseif ( $server['type'] === 'mssql' ) {
+                       $server += [
+                               'port' => $options->get( 'DBport' ),
+                               'useWindowsAuth' => $options->get( 'DBWindowsAuthentication' )
+                       ];
+               }
+
+               if ( in_array( $server['type'], self::getDbTypesWithSchemas(), true ) ) {
+                       $server += [ 'schema' => $options->get( 'DBmwschema' ) ];
+               }
+
+               $flags = DBO_DEFAULT;
+               $flags |= $options->get( 'DebugDumpSql' ) ? DBO_DEBUG : 0;
+               $flags |= $options->get( 'DebugLogFile' ) ? DBO_DEBUG : 0;
+               if ( $server['type'] === 'oracle' ) {
+                       $flags |= $options->get( 'DBOracleDRCP' ) ? DBO_PERSISTENT : 0;
+               }
+
+               $server += [
+                       'tablePrefix' => $options->get( 'DBprefix' ),
+                       'flags' => $flags,
+                       'sqlMode' => $options->get( 'SQLMode' ),
+               ];
+
+               return $server;
+       }
 
+       /**
+        * @param array $lbConf
+        * @param BagOStuff $sCache
+        * @param BagOStuff $mStash
+        * @param WANObjectCache $wCache
+        * @return array
+        */
+       private static function injectObjectCaches(
+               array $lbConf, BagOStuff $sCache, BagOStuff $mStash, WANObjectCache $wCache
+       ) {
                // Use APC/memcached style caching, but avoids loops with CACHE_DB (T141804)
-               $sCache = $services->getLocalServerObjectCache();
                if ( $sCache->getQoS( $sCache::ATTR_EMULATION ) > $sCache::QOS_EMULATION_SQL ) {
                        $lbConf['srvCache'] = $sCache;
                }
-               $mStash = $services->getMainObjectStash();
                if ( $mStash->getQoS( $mStash::ATTR_EMULATION ) > $mStash::QOS_EMULATION_SQL ) {
                        $lbConf['memStash'] = $mStash;
                }
-               $wCache = $services->getMainWANObjectCache();
                if ( $wCache->getQoS( $wCache::ATTR_EMULATION ) > $wCache::QOS_EMULATION_SQL ) {
                        $lbConf['wanCache'] = $wCache;
                }
@@ -170,6 +245,82 @@ abstract class MWLBFactory {
                return $lbConf;
        }
 
+       /**
+        * @param array $servers
+        * @param string $lbDB Local domain database name
+        * @param string $lbTP Local domain prefix
+        */
+       private static function assertValidServerConfigs( array $servers, $ldDB, $ldTP ) {
+               foreach ( $servers as $server ) {
+                       $type = $server['type'] ?? null;
+                       $srvDB = $server['dbname'] ?? null; // server DB
+                       $srvTP = $server['tablePrefix'] ?? ''; // server table prefix
+
+                       if ( $type === 'mysql' ) {
+                               // A DB name is not needed to connect to mysql; 'dbname' is useless.
+                               // This field only defines the DB to use for unspecified DB domains.
+                               if ( $srvDB !== null && $srvDB !== $ldDB ) {
+                                       self::reportMismatchedDBs( $srvDB, $ldDB );
+                               }
+                       } elseif ( $type === 'postgres' ) {
+                               if ( $srvTP !== '' ) {
+                                       self::reportIfPrefixSet( $srvTP, $type );
+                               }
+                       }
+
+                       if ( $srvTP !== '' && $srvTP !== $ldTP ) {
+                               self::reportMismatchedPrefixes( $srvTP, $ldTP );
+                       }
+               }
+       }
+
+       /**
+        * @param string $prefix Table prefix
+        * @param string $dbType Database type
+        */
+       private static function reportIfPrefixSet( $prefix, $dbType ) {
+               $e = new UnexpectedValueException(
+                       "\$wgDBprefix is set to '$prefix' but the database type is '$dbType'. " .
+                       "MediaWiki does not support using a table prefix with this RDBMS type."
+               );
+               MWExceptionRenderer::output( $e, MWExceptionRenderer::AS_PRETTY );
+               exit;
+       }
+
+       /**
+        * @param string $srvDB Server config database
+        * @param string $ldDB Local DB domain database
+        */
+       private static function reportMismatchedDBs( $srvDB, $ldDB ) {
+               $e = new UnexpectedValueException(
+                       "\$wgDBservers has dbname='$srvDB' but \$wgDBname='$ldDB'. " .
+                       "Set \$wgDBname to the database used by this wiki project. " .
+                       "There is rarely a need to set 'dbname' in \$wgDBservers. " .
+                       "Cross-wiki database access, use of WikiMap::getCurrentWikiDbDomain(), " .
+                       "use of Database::getDomainId(), and other features are not reliable when " .
+                       "\$wgDBservers does not match the local wiki database/prefix."
+               );
+               MWExceptionRenderer::output( $e, MWExceptionRenderer::AS_PRETTY );
+               exit;
+       }
+
+       /**
+        * @param string $srvTP Server config table prefix
+        * @param string $ldTP Local DB domain database
+        */
+       private static function reportMismatchedPrefixes( $srvTP, $ldTP ) {
+               $e = new UnexpectedValueException(
+                       "\$wgDBservers has tablePrefix='$srvTP' but \$wgDBprefix='$ldTP'. " .
+                       "Set \$wgDBprefix to the table prefix used by this wiki project. " .
+                       "There is rarely a need to set 'tablePrefix' in \$wgDBservers. " .
+                       "Cross-wiki database access, use of WikiMap::getCurrentWikiDbDomain(), " .
+                       "use of Database::getDomainId(), and other features are not reliable when " .
+                       "\$wgDBservers does not match the local wiki database/prefix."
+               );
+               MWExceptionRenderer::output( $e, MWExceptionRenderer::AS_PRETTY );
+               exit;
+       }
+
        /**
         * Returns the LBFactory class to use and the load balancer configuration.
         *
@@ -211,8 +362,17 @@ abstract class MWLBFactory {
                return $class;
        }
 
-       public static function setSchemaAliases( LBFactory $lbFactory, Config $config ) {
-               if ( $config->get( 'DBtype' ) === 'mysql' ) {
+       /**
+        * @param LBFactory $lbFactory
+        * @param string $dbType 'mysql', 'sqlite', etc.
+        */
+       public static function setSchemaAliases( LBFactory $lbFactory, $dbType ) {
+               if ( $dbType instanceof Config ) {
+                       // Before 1.34 this took a whole Config just to get $dbType
+                       wfDeprecated( __METHOD__ . ' with Config argument', '1.34' );
+                       $dbType = $dbType->get( 'DBtype' );
+               }
+               if ( $dbType === 'mysql' ) {
                        /**
                         * When SQLite indexes were introduced in r45764, it was noted that
                         * SQLite requires index names to be unique within the whole database,
index cd78005..0e1ee6b 100644 (file)
@@ -50,7 +50,7 @@ trait DeprecationHelper {
         * the name of the class defining the property, <component> is the MediaWiki component
         * (extension, skin etc.) for use in the deprecation warning) or null if it is MediaWiki.
         * E.g. [ 'mNewRev' => [ '1.32', 'DifferenceEngine', null ]
-        * @var string[]
+        * @var string[][]
         */
        protected $deprecatedPublicProperties = [];
 
@@ -68,7 +68,7 @@ trait DeprecationHelper {
        protected function deprecatePublicProperty(
                $property, $version, $class = null, $component = null
        ) {
-               $this->deprecatedPublicProperties[$property] = [ $version, $class ?: get_class(), $component ];
+               $this->deprecatedPublicProperties[$property] = [ $version, $class ?: __CLASS__, $component ];
        }
 
        public function __get( $name ) {
@@ -79,8 +79,9 @@ trait DeprecationHelper {
                        return $this->$name;
                }
 
-               $qualifiedName = get_class() . '::$' . $name;
-               if ( $this->deprecationHelperGetPropertyOwner( $name ) ) {
+               $ownerClass = $this->deprecationHelperGetPropertyOwner( $name );
+               $qualifiedName = ( $ownerClass ?: get_class( $this ) ) . '::$' . $name;
+               if ( $ownerClass ) {
                        // Someone tried to access a normal non-public property. Try to behave like PHP would.
                        trigger_error( "Cannot access non-public property $qualifiedName", E_USER_ERROR );
                } else {
@@ -99,8 +100,9 @@ trait DeprecationHelper {
                        return;
                }
 
-               $qualifiedName = get_class() . '::$' . $name;
-               if ( $this->deprecationHelperGetPropertyOwner( $name ) ) {
+               $ownerClass = $this->deprecationHelperGetPropertyOwner( $name );
+               $qualifiedName = ( $ownerClass ?: get_class( $this ) ) . '::$' . $name;
+               if ( $ownerClass ) {
                        // Someone tried to access a normal non-public property. Try to behave like PHP would.
                        trigger_error( "Cannot access non-public property $qualifiedName", E_USER_ERROR );
                } else {
@@ -113,22 +115,12 @@ trait DeprecationHelper {
         * Like property_exists but also check for non-visible private properties and returns which
         * class in the inheritance chain declared the property.
         * @param string $property
-        * @return string|bool Best guess for the class in which the property is defined.
+        * @return string|bool Best guess for the class in which the property is defined. False if
+        *   the object does not have such a property.
         */
        private function deprecationHelperGetPropertyOwner( $property ) {
-               // Easy branch: check for protected property / private property of the current class.
-               if ( property_exists( $this, $property ) ) {
-                       // The class name is not necessarily correct here but getting the correct class
-                       // name would be expensive, this will work most of the time and getting it
-                       // wrong is not a big deal.
-                       return __CLASS__;
-               }
-               // property_exists() returns false when the property does exist but is private (and not
-               // defined by the current class, for some value of "current" that differs slightly
-               // between engines).
-               // Since PHP triggers an error on public access of non-public properties but happily
-               // allows public access to undefined properties, we need to detect this case as well.
-               // Reflection is slow so use array cast hack to check for that:
+               // Returning false is a non-error path and should avoid slow checks like reflection.
+               // Use array cast hack instead.
                $obfuscatedProps = array_keys( (array)$this );
                $obfuscatedPropTail = "\0$property";
                foreach ( $obfuscatedProps as $obfuscatedProp ) {
@@ -136,8 +128,9 @@ trait DeprecationHelper {
                        if ( strpos( $obfuscatedProp, $obfuscatedPropTail, 1 ) !== false ) {
                                $classname = substr( $obfuscatedProp, 1, -strlen( $obfuscatedPropTail ) );
                                if ( $classname === '*' ) {
-                                       // sanity; this shouldn't be possible as protected properties were handled earlier
-                                       $classname = __CLASS__;
+                                       // protected property; we didn't get the name, but we are on an error path
+                                       // now so it's fine to use reflection
+                                       return ( new ReflectionProperty( $this, $property ) )->getDeclaringClass()->getName();
                                }
                                return $classname;
                        }
index ff653ab..d67696a 100644 (file)
@@ -22,6 +22,7 @@ namespace MediaWiki\Logger;
 
 use MediaWiki\Logger\Monolog\BufferHandler;
 use Monolog\Logger;
+use Monolog\Handler\StreamHandler;
 use Wikimedia\ObjectFactory;
 
 /**
@@ -147,6 +148,17 @@ class MonologSpi implements Spi {
                                $this->config[$key] = $value;
                        }
                }
+               if ( !isset( $this->config['loggers']['@default'] ) ) {
+                       $this->config['loggers']['@default'] = [
+                               'handlers' => [ '@default' ],
+                       ];
+                       if ( !isset( $this->config['handlers']['@default'] ) ) {
+                               $this->config['handlers']['@default'] = [
+                                       'class' => StreamHandler::class,
+                                       'args' => [ 'php://stderr', Logger::ERROR ],
+                               ];
+                       }
+               }
                $this->reset();
        }
 
diff --git a/includes/debug/logger/monolog/MwlogHandler.php b/includes/debug/logger/monolog/MwlogHandler.php
new file mode 100644 (file)
index 0000000..e61aada
--- /dev/null
@@ -0,0 +1,102 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+namespace MediaWiki\Logger\Monolog;
+
+use Monolog\Handler\SyslogUdpHandler;
+use Monolog\Logger;
+
+/**
+ * Log handler that will append the record's channel to a fixed 'application
+ * prefix' given at construction time.
+ *
+ * The use case for this handler is to deprecate udp2log with a localhost
+ * syslog endpoint. The application name is then used to reconstruct the
+ * message's channel.
+ *
+ * @since 1.32
+ * @copyright © 2019 Wikimedia Foundation and contributors
+ */
+class MwlogHandler extends SyslogUdpHandler {
+
+       /**
+        * @var string $appprefix
+        */
+       private $appprefix;
+
+       /**
+        * @var string $hostname
+        */
+       private $hostname;
+
+       /**
+        * @param string $appprefix Application prefix to use, channel will be appended.
+        * @param string $host Syslog host
+        * @param int $port Syslog port
+        * @param int $facility Syslog message facility
+        * @param int $level The minimum logging level at which this handler
+        *   will be triggered
+        * @param bool $bubble Whether the messages that are handled can bubble up
+        *   the stack or not
+        */
+       public function __construct(
+               $appprefix,
+               $host,
+               $port = 514,
+               $facility = LOG_USER,
+               $level = Logger::DEBUG,
+               $bubble = true
+       ) {
+               parent::__construct( $host, $port, $facility, $level, $bubble );
+               $this->appprefix = $appprefix;
+               $this->hostname = php_uname( 'n' );
+       }
+
+       protected function syslogHeader( $severity, $app ) {
+               $pri = $severity + $this->facility;
+
+               // Goofy date format courtesy of RFC 3164 :(
+               // RFC 3164 actually specifies that the day of month should be space
+               // padded rather than unpadded but this seems to work with rsyslog and
+               // Logstash.
+               $timestamp = date( 'M j H:i:s' );
+
+               return "<{$pri}>{$timestamp} {$this->hostname} {$app}: ";
+       }
+
+       private function splitMessageIntoLines( $message ): array {
+               if ( is_array( $message ) ) {
+                       $message = implode( "\n", $message );
+               }
+
+               return preg_split( '/$\R?^/m', (string)$message, -1, PREG_SPLIT_NO_EMPTY );
+       }
+
+       protected function write( array $record ) {
+               $lines = $this->splitMessageIntoLines( $record['formatted'] );
+               $header = $this->syslogHeader(
+                       $this->logLevels[$record['level']],
+                       $this->appprefix . $record['channel'] );
+
+               foreach ( $lines as $line ) {
+                       $this->socket->write( $line, $header );
+               }
+       }
+}
index 8b62989..69f09e3 100644 (file)
@@ -15,18 +15,22 @@ class AtomicSectionUpdate implements DeferrableUpdate, DeferrableCallback {
        private $callback;
 
        /**
-        * @param IDatabase $dbw
+        * @param IDatabase $dbw DB handle; update aborts if a transaction now this rolls back
         * @param string $fname Caller name (usually __METHOD__)
         * @param callable $callback
+        * @param IDatabase[] $conns Abort if a transaction now on one of these rolls back [optional]
         * @see IDatabase::doAtomicSection()
         */
-       public function __construct( IDatabase $dbw, $fname, callable $callback ) {
+       public function __construct( IDatabase $dbw, $fname, callable $callback, array $conns = [] ) {
                $this->dbw = $dbw;
                $this->fname = $fname;
                $this->callback = $callback;
-
-               if ( $this->dbw->trxLevel() ) {
-                       $this->dbw->onTransactionResolution( [ $this, 'cancelOnRollback' ], $fname );
+               // Register DB connections for which uncommitted changes are related to this update
+               $conns[] = $dbw;
+               foreach ( $conns as $conn ) {
+                       if ( $conn->trxLevel() ) {
+                               $conn->onTransactionResolution( [ $this, 'cancelOnRollback' ], $fname );
+                       }
                }
        }
 
@@ -36,6 +40,10 @@ class AtomicSectionUpdate implements DeferrableUpdate, DeferrableCallback {
                }
        }
 
+       /**
+        * @private This method is public so that it works with onTransactionResolution()
+        * @param int $trigger
+        */
        public function cancelOnRollback( $trigger ) {
                if ( $trigger === IDatabase::TRIGGER_ROLLBACK ) {
                        $this->callback = null;
index 8507157..ddfd987 100644 (file)
@@ -15,17 +15,21 @@ class AutoCommitUpdate implements DeferrableUpdate, DeferrableCallback {
        private $callback;
 
        /**
-        * @param IDatabase $dbw
+        * @param IDatabase $dbw DB handle; update aborts if a transaction now this rolls back
         * @param string $fname Caller name (usually __METHOD__)
         * @param callable $callback Callback that takes (IDatabase, method name string)
+        * @param IDatabase[] $conns Abort if a transaction now on one of these rolls back [optional]
         */
-       public function __construct( IDatabase $dbw, $fname, callable $callback ) {
+       public function __construct( IDatabase $dbw, $fname, callable $callback, array $conns = [] ) {
                $this->dbw = $dbw;
                $this->fname = $fname;
                $this->callback = $callback;
-
-               if ( $this->dbw->trxLevel() ) {
-                       $this->dbw->onTransactionResolution( [ $this, 'cancelOnRollback' ], $fname );
+               // Register DB connections for which uncommitted changes are related to this update
+               $conns[] = $dbw;
+               foreach ( $conns as $conn ) {
+                       if ( $conn->trxLevel() ) {
+                               $conn->onTransactionResolution( [ $this, 'cancelOnRollback' ], $fname );
+                       }
                }
        }
 
@@ -50,6 +54,10 @@ class AutoCommitUpdate implements DeferrableUpdate, DeferrableCallback {
                }
        }
 
+       /**
+        * @private This method is public so that it works with onTransactionResolution()
+        * @param int $trigger
+        */
        public function cancelOnRollback( $trigger ) {
                if ( $trigger === IDatabase::TRIGGER_ROLLBACK ) {
                        $this->callback = null;
index 6f961e8..2d07f75 100644 (file)
@@ -71,13 +71,10 @@ class CdnCacheUpdate implements DeferrableUpdate, MergeableUpdate {
                self::purge( $this->urls );
 
                if ( $wgCdnReboundPurgeDelay > 0 ) {
-                       JobQueueGroup::singleton()->lazyPush( new CdnPurgeJob(
-                               Title::makeTitle( NS_SPECIAL, 'Badtitle/' . __CLASS__ ),
-                               [
-                                       'urls' => $this->urls,
-                                       'jobReleaseTimestamp' => time() + $wgCdnReboundPurgeDelay
-                               ]
-                       ) );
+                       JobQueueGroup::singleton()->lazyPush( new CdnPurgeJob( [
+                               'urls' => $this->urls,
+                               'jobReleaseTimestamp' => time() + $wgCdnReboundPurgeDelay
+                       ] ) );
                }
        }
 
index 67b5490..3b7de9d 100644 (file)
@@ -263,7 +263,8 @@ class DeferredUpdates {
                        if ( $mode === 'enqueue' && $update instanceof EnqueueableDataUpdate ) {
                                // Run only the job enqueue logic to complete the update later
                                $spec = $update->getAsJobSpecification();
-                               JobQueueGroup::singleton( $spec['wiki'] )->push( $spec['job'] );
+                               $domain = $spec['domain'] ?? $spec['wiki'];
+                               JobQueueGroup::singleton( $domain )->push( $spec['job'] );
                        } elseif ( $update instanceof TransactionRoundDefiningUpdate ) {
                                $update->doUpdate();
                        } else {
@@ -335,7 +336,8 @@ class DeferredUpdates {
                foreach ( $updates as $update ) {
                        if ( $update instanceof EnqueueableDataUpdate ) {
                                $spec = $update->getAsJobSpecification();
-                               JobQueueGroup::singleton( $spec['wiki'] )->push( $spec['job'] );
+                               $domain = $spec['domain'] ?? $spec['wiki'];
+                               JobQueueGroup::singleton( $domain )->push( $spec['job'] );
                        } else {
                                $remaining[] = $update;
                        }
index ffeb740..3a77f54 100644 (file)
@@ -9,7 +9,7 @@
  */
 interface EnqueueableDataUpdate {
        /**
-        * @return array (wiki => wiki ID, job => IJobSpecification)
+        * @return array (domain => DB domain ID, job => IJobSpecification)
         */
        public function getAsJobSpecification();
 }
index 0743dbe..8bc9dfa 100644 (file)
  */
 use MediaWiki\MediaWikiServices;
 use Wikimedia\ScopedCallback;
-use Wikimedia\Rdbms\IDatabase;
 
 /**
  * Update object handling the cleanup of links tables after a page was deleted.
  */
-class LinksDeletionUpdate extends DataUpdate implements EnqueueableDataUpdate {
+class LinksDeletionUpdate extends LinksUpdate implements EnqueueableDataUpdate {
        /** @var WikiPage */
        protected $page;
-       /** @var int */
-       protected $pageId;
        /** @var string */
        protected $timestamp;
 
-       /** @var IDatabase */
-       private $db;
-
        /**
         * @param WikiPage $page Page we are updating
         * @param int|null $pageId ID of the page we are updating [optional]
@@ -44,117 +38,50 @@ class LinksDeletionUpdate extends DataUpdate implements EnqueueableDataUpdate {
         * @throws MWException
         */
        function __construct( WikiPage $page, $pageId = null, $timestamp = null ) {
-               parent::__construct();
-
                $this->page = $page;
                if ( $pageId ) {
-                       $this->pageId = $pageId; // page ID at time of deletion
+                       $this->mId = $pageId; // page ID at time of deletion
                } elseif ( $page->exists() ) {
-                       $this->pageId = $page->getId();
+                       $this->mId = $page->getId();
                } else {
                        throw new InvalidArgumentException( "Page ID not known. Page doesn't exist?" );
                }
 
                $this->timestamp = $timestamp ?: wfTimestampNow();
+
+               $fakePO = new ParserOutput();
+               $fakePO->setCacheTime( $timestamp );
+               parent::__construct( $page->getTitle(), $fakePO, false );
        }
 
-       public function doUpdate() {
+       protected function doIncrementalUpdate() {
                $services = MediaWikiServices::getInstance();
                $config = $services->getMainConfig();
                $lbFactory = $services->getDBLoadBalancerFactory();
                $batchSize = $config->get( 'UpdateRowsPerQuery' );
 
-               // Page may already be deleted, so don't just getId()
-               $id = $this->pageId;
-
-               if ( $this->ticket ) {
-                       // Make sure all links update threads see the changes of each other.
-                       // This handles the case when updates have to batched into several COMMITs.
-                       $scopedLock = LinksUpdate::acquirePageLock( $this->getDB(), $id );
-                       if ( !$scopedLock ) {
-                               throw new RuntimeException( "Could not acquire lock for page ID '{$id}'." );
-                       }
-               }
+               $id = $this->mId;
+               $title = $this->mTitle;
 
-               $title = $this->page->getTitle();
                $dbw = $this->getDB(); // convenience
 
-               // Delete restrictions for it
-               $dbw->delete( 'page_restrictions', [ 'pr_page' => $id ], __METHOD__ );
+               parent::doIncrementalUpdate();
 
-               // Fix category table counts
-               $cats = $dbw->selectFieldValues(
-                       'categorylinks',
-                       'cl_to',
-                       [ 'cl_from' => $id ],
-                       __METHOD__
-               );
-               $catBatches = array_chunk( $cats, $batchSize );
-               foreach ( $catBatches as $catBatch ) {
-                       $this->page->updateCategoryCounts( [], $catBatch, $id );
-                       if ( count( $catBatches ) > 1 ) {
-                               // Only sacrifice atomicity if necessary due to size
-                               $lbFactory->commitAndWaitForReplication(
-                                       __METHOD__, $this->ticket, [ 'domain' => $dbw->getDomainID() ]
-                               );
-                       }
-               }
-
-               // Refresh counts on categories that should be empty now
+               // Typically, a category is empty when deleted, so check that we don't leave
+               // spurious row in the category table.
                if ( $title->getNamespace() === NS_CATEGORY ) {
                        // T166757: do the update after the main job DB commit
                        DeferredUpdates::addCallableUpdate( function () use ( $title ) {
                                $cat = Category::newFromName( $title->getDBkey() );
-                               $cat->refreshCountsIfEmpty();
+                               $cat->refreshCountsIfSmall();
                        } );
                }
 
-               $this->batchDeleteByPK(
-                       'pagelinks',
-                       [ 'pl_from' => $id ],
-                       [ 'pl_from', 'pl_namespace', 'pl_title' ],
-                       $batchSize
-               );
-               $this->batchDeleteByPK(
-                       'imagelinks',
-                       [ 'il_from' => $id ],
-                       [ 'il_from', 'il_to' ],
-                       $batchSize
-               );
-               $this->batchDeleteByPK(
-                       'categorylinks',
-                       [ 'cl_from' => $id ],
-                       [ 'cl_from', 'cl_to' ],
-                       $batchSize
-               );
-               $this->batchDeleteByPK(
-                       'templatelinks',
-                       [ 'tl_from' => $id ],
-                       [ 'tl_from', 'tl_namespace', 'tl_title' ],
-                       $batchSize
-               );
-               $this->batchDeleteByPK(
-                       'externallinks',
-                       [ 'el_from' => $id ],
-                       [ 'el_id' ],
-                       $batchSize
-               );
-               $this->batchDeleteByPK(
-                       'langlinks',
-                       [ 'll_from' => $id ],
-                       [ 'll_from', 'll_lang' ],
-                       $batchSize
-               );
-               $this->batchDeleteByPK(
-                       'iwlinks',
-                       [ 'iwl_from' => $id ],
-                       [ 'iwl_from', 'iwl_prefix', 'iwl_title' ],
-                       $batchSize
-               );
+               // Delete restrictions for the deleted page
+               $dbw->delete( 'page_restrictions', [ 'pr_page' => $id ], __METHOD__ );
 
-               // Delete any redirect entry or page props entries
+               // Delete any redirect entry
                $dbw->delete( 'redirect', [ 'rd_from' => $id ], __METHOD__ );
-               $dbw->delete( 'page_props', [ 'pp_page' => $id ], __METHOD__ );
 
                // Find recentchanges entries to clean up...
                $rcIdsForTitle = $dbw->selectFieldValues(
@@ -191,46 +118,14 @@ class LinksDeletionUpdate extends DataUpdate implements EnqueueableDataUpdate {
                ScopedCallback::consume( $scopedLock );
        }
 
-       private function batchDeleteByPK( $table, array $conds, array $pk, $bSize ) {
-               $services = MediaWikiServices::getInstance();
-               $lbFactory = $services->getDBLoadBalancerFactory();
-               $dbw = $this->getDB(); // convenience
-
-               $res = $dbw->select( $table, $pk, $conds, __METHOD__ );
-
-               $pkDeleteConds = [];
-               foreach ( $res as $row ) {
-                       $pkDeleteConds[] = $dbw->makeList( (array)$row, LIST_AND );
-                       if ( count( $pkDeleteConds ) >= $bSize ) {
-                               $dbw->delete( $table, $dbw->makeList( $pkDeleteConds, LIST_OR ), __METHOD__ );
-                               $lbFactory->commitAndWaitForReplication(
-                                       __METHOD__, $this->ticket, [ 'domain' => $dbw->getDomainID() ]
-                               );
-                               $pkDeleteConds = [];
-                       }
-               }
-
-               if ( $pkDeleteConds ) {
-                       $dbw->delete( $table, $dbw->makeList( $pkDeleteConds, LIST_OR ), __METHOD__ );
-               }
-       }
-
-       protected function getDB() {
-               if ( !$this->db ) {
-                       $this->db = wfGetDB( DB_MASTER );
-               }
-
-               return $this->db;
-       }
-
        public function getAsJobSpecification() {
                return [
-                       'wiki' => WikiMap::getWikiIdFromDbDomain( $this->getDB()->getDomainID() ),
-                       'job'  => new JobSpecification(
+                       'domain' => $this->getDB()->getDomainID(),
+                       'job' => new JobSpecification(
                                'deleteLinks',
-                               [ 'pageId' => $this->pageId, 'timestamp' => $this->timestamp ],
+                               [ 'pageId' => $this->mId, 'timestamp' => $this->timestamp ],
                                [ 'removeDuplicates' => true ],
-                               $this->page->getTitle()
+                               $this->mTitle
                        )
                ];
        }
index 7a31e26..9d3309b 100644 (file)
@@ -122,7 +122,11 @@ class LinksUpdate extends DataUpdate implements EnqueueableDataUpdate {
                parent::__construct();
 
                $this->mTitle = $title;
-               $this->mId = $title->getArticleID( Title::GAID_FOR_UPDATE );
+
+               if ( !$this->mId ) {
+                       // NOTE: subclasses may initialize mId before calling this constructor!
+                       $this->mId = $title->getArticleID( Title::GAID_FOR_UPDATE );
+               }
 
                if ( !$this->mId ) {
                        throw new InvalidArgumentException(
@@ -611,7 +615,8 @@ class LinksUpdate extends DataUpdate implements EnqueueableDataUpdate {
                        $nt = Title::makeTitleSafe( NS_CATEGORY, $name );
                        $contLang->findVariantLink( $name, $nt, true );
 
-                       $type = MWNamespace::getCategoryLinkType( $this->mTitle->getNamespace() );
+                       $type = MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               getCategoryLinkType( $this->mTitle->getNamespace() );
 
                        # Treat custom sortkeys as a prefix, so that if multiple
                        # things are forced to sort as '*' or something, they'll
@@ -1180,7 +1185,7 @@ class LinksUpdate extends DataUpdate implements EnqueueableDataUpdate {
        /**
         * @return IDatabase
         */
-       private function getDB() {
+       protected function getDB() {
                if ( !$this->db ) {
                        $this->db = wfGetDB( DB_MASTER );
                }
@@ -1205,7 +1210,7 @@ class LinksUpdate extends DataUpdate implements EnqueueableDataUpdate {
                }
 
                return [
-                       'wiki' => WikiMap::getWikiIdFromDbDomain( $this->getDB()->getDomainID() ),
+                       'domain' => $this->getDB()->getDomainID(),
                        'job'  => new JobSpecification(
                                'refreshLinksPrioritized',
                                [
index 9803b7a..efca406 100644 (file)
@@ -35,6 +35,10 @@ class MWCallableUpdate implements DeferrableUpdate, DeferrableCallback {
                }
        }
 
+       /**
+        * @private This method is public so that it works with onTransactionResolution()
+        * @param int $trigger
+        */
        public function cancelOnRollback( $trigger ) {
                if ( $trigger === IDatabase::TRIGGER_ROLLBACK ) {
                        $this->callback = null;
diff --git a/includes/diff/DairikiDiff.php b/includes/diff/DairikiDiff.php
deleted file mode 100644 (file)
index 063f826..0000000
+++ /dev/null
@@ -1,334 +0,0 @@
-<?php
-/**
- * A PHP diff engine for phpwiki. (Taken from phpwiki-1.3.3)
- *
- * Copyright © 2000, 2001 Geoffrey T. Dairiki <dairiki@dairiki.org>
- * You may copy this code freely under the conditions of the GPL.
- *
- * 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 DifferenceEngine
- * @defgroup DifferenceEngine DifferenceEngine
- */
-
-/**
- * The base class for all other DiffOp classes.
- *
- * The classes that extend DiffOp are: DiffOpCopy, DiffOpDelete, DiffOpAdd and
- * DiffOpChange. FakeDiffOp also extends DiffOp, but it is not located in this file.
- *
- * @private
- * @ingroup DifferenceEngine
- */
-abstract class DiffOp {
-
-       /**
-        * @var string
-        */
-       public $type;
-
-       /**
-        * @var string[]
-        */
-       public $orig;
-
-       /**
-        * @var string[]
-        */
-       public $closing;
-
-       /**
-        * @return string
-        */
-       public function getType() {
-               return $this->type;
-       }
-
-       /**
-        * @return string[]
-        */
-       public function getOrig() {
-               return $this->orig;
-       }
-
-       /**
-        * @param int|null $i
-        * @return string[]|string|null
-        */
-       public function getClosing( $i = null ) {
-               if ( $i === null ) {
-                       return $this->closing;
-               }
-               if ( array_key_exists( $i, $this->closing ) ) {
-                       return $this->closing[$i];
-               }
-               return null;
-       }
-
-       abstract public function reverse();
-
-       /**
-        * @return int
-        */
-       public function norig() {
-               return $this->orig ? count( $this->orig ) : 0;
-       }
-
-       /**
-        * @return int
-        */
-       public function nclosing() {
-               return $this->closing ? count( $this->closing ) : 0;
-       }
-}
-
-/**
- * Extends DiffOp. Used to mark strings that have been
- * copied from one string array to the other.
- *
- * @private
- * @ingroup DifferenceEngine
- */
-class DiffOpCopy extends DiffOp {
-       public $type = 'copy';
-
-       public function __construct( $orig, $closing = false ) {
-               if ( !is_array( $closing ) ) {
-                       $closing = $orig;
-               }
-               $this->orig = $orig;
-               $this->closing = $closing;
-       }
-
-       /**
-        * @return DiffOpCopy
-        */
-       public function reverse() {
-               return new DiffOpCopy( $this->closing, $this->orig );
-       }
-}
-
-/**
- * Extends DiffOp. Used to mark strings that have been
- * deleted from the first string array.
- *
- * @private
- * @ingroup DifferenceEngine
- */
-class DiffOpDelete extends DiffOp {
-       public $type = 'delete';
-
-       public function __construct( $lines ) {
-               $this->orig = $lines;
-               $this->closing = false;
-       }
-
-       /**
-        * @return DiffOpAdd
-        */
-       public function reverse() {
-               return new DiffOpAdd( $this->orig );
-       }
-}
-
-/**
- * Extends DiffOp. Used to mark strings that have been
- * added from the first string array.
- *
- * @private
- * @ingroup DifferenceEngine
- */
-class DiffOpAdd extends DiffOp {
-       public $type = 'add';
-
-       public function __construct( $lines ) {
-               $this->closing = $lines;
-               $this->orig = false;
-       }
-
-       /**
-        * @return DiffOpDelete
-        */
-       public function reverse() {
-               return new DiffOpDelete( $this->closing );
-       }
-}
-
-/**
- * Extends DiffOp. Used to mark strings that have been
- * changed from the first string array (both added and subtracted).
- *
- * @private
- * @ingroup DifferenceEngine
- */
-class DiffOpChange extends DiffOp {
-       public $type = 'change';
-
-       public function __construct( $orig, $closing ) {
-               $this->orig = $orig;
-               $this->closing = $closing;
-       }
-
-       /**
-        * @return DiffOpChange
-        */
-       public function reverse() {
-               return new DiffOpChange( $this->closing, $this->orig );
-       }
-}
-
-/**
- * Class representing a 'diff' between two sequences of strings.
- * @todo document
- * @private
- * @ingroup DifferenceEngine
- */
-class Diff {
-
-       /**
-        * @var DiffOp[]
-        */
-       public $edits;
-
-       /**
-        * @var int If this diff complexity is exceeded, a ComplexityException is thrown
-        *          0 means no limit.
-        */
-       protected $bailoutComplexity = 0;
-
-       /**
-        * Computes diff between sequences of strings.
-        *
-        * @param string[] $from_lines An array of strings.
-        *   Typically these are lines from a file.
-        * @param string[] $to_lines An array of strings.
-        * @throws \MediaWiki\Diff\ComplexityException
-        */
-       public function __construct( $from_lines, $to_lines ) {
-               $eng = new DiffEngine;
-               $eng->setBailoutComplexity( $this->bailoutComplexity );
-               $this->edits = $eng->diff( $from_lines, $to_lines );
-       }
-
-       /**
-        * @return DiffOp[]
-        */
-       public function getEdits() {
-               return $this->edits;
-       }
-
-       /**
-        * Compute reversed Diff.
-        *
-        * SYNOPSIS:
-        *
-        *    $diff = new Diff($lines1, $lines2);
-        *    $rev = $diff->reverse();
-        *
-        * @return Object A Diff object representing the inverse of the
-        *   original diff.
-        */
-       public function reverse() {
-               $rev = $this;
-               $rev->edits = [];
-               /** @var DiffOp $edit */
-               foreach ( $this->edits as $edit ) {
-                       $rev->edits[] = $edit->reverse();
-               }
-
-               return $rev;
-       }
-
-       /**
-        * Check for empty diff.
-        *
-        * @return bool True if two sequences were identical.
-        */
-       public function isEmpty() {
-               foreach ( $this->edits as $edit ) {
-                       if ( $edit->type != 'copy' ) {
-                               return false;
-                       }
-               }
-
-               return true;
-       }
-
-       /**
-        * Compute the length of the Longest Common Subsequence (LCS).
-        *
-        * This is mostly for diagnostic purposed.
-        *
-        * @return int The length of the LCS.
-        */
-       public function lcs() {
-               $lcs = 0;
-               foreach ( $this->edits as $edit ) {
-                       if ( $edit->type == 'copy' ) {
-                               $lcs += count( $edit->orig );
-                       }
-               }
-
-               return $lcs;
-       }
-
-       /**
-        * Get the original set of lines.
-        *
-        * This reconstructs the $from_lines parameter passed to the
-        * constructor.
-        *
-        * @return string[] The original sequence of strings.
-        */
-       public function orig() {
-               $lines = [];
-
-               foreach ( $this->edits as $edit ) {
-                       if ( $edit->orig ) {
-                               array_splice( $lines, count( $lines ), 0, $edit->orig );
-                       }
-               }
-
-               return $lines;
-       }
-
-       /**
-        * Get the closing set of lines.
-        *
-        * This reconstructs the $to_lines parameter passed to the
-        * constructor.
-        *
-        * @return string[] The sequence of strings.
-        */
-       public function closing() {
-               $lines = [];
-
-               foreach ( $this->edits as $edit ) {
-                       if ( $edit->closing ) {
-                               array_splice( $lines, count( $lines ), 0, $edit->closing );
-                       }
-               }
-
-               return $lines;
-       }
-}
-
-/**
- * @deprecated Alias for WordAccumulator, to be soon removed
- */
-class HWLDFWordAccumulator extends MediaWiki\Diff\WordAccumulator {
-}
diff --git a/includes/diff/Diff.php b/includes/diff/Diff.php
new file mode 100644 (file)
index 0000000..2dab88b
--- /dev/null
@@ -0,0 +1,160 @@
+<?php
+/**
+ * A PHP diff engine for phpwiki. (Taken from phpwiki-1.3.3)
+ *
+ * Copyright © 2000, 2001 Geoffrey T. Dairiki <dairiki@dairiki.org>
+ * You may copy this code freely under the conditions of the GPL.
+ *
+ * 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 DifferenceEngine
+ */
+
+/**
+ * Class representing a 'diff' between two sequences of strings.
+ * @private
+ * @ingroup DifferenceEngine
+ */
+class Diff {
+
+       /**
+        * @var DiffOp[]
+        */
+       public $edits;
+
+       /**
+        * @var int If this diff complexity is exceeded, a ComplexityException is thrown
+        *          0 means no limit.
+        */
+       protected $bailoutComplexity = 0;
+
+       /**
+        * Computes diff between sequences of strings.
+        *
+        * @param string[] $from_lines An array of strings.
+        *   Typically these are lines from a file.
+        * @param string[] $to_lines An array of strings.
+        * @throws \MediaWiki\Diff\ComplexityException
+        */
+       public function __construct( $from_lines, $to_lines ) {
+               $eng = new DiffEngine;
+               $eng->setBailoutComplexity( $this->bailoutComplexity );
+               $this->edits = $eng->diff( $from_lines, $to_lines );
+       }
+
+       /**
+        * @return DiffOp[]
+        */
+       public function getEdits() {
+               return $this->edits;
+       }
+
+       /**
+        * Compute reversed Diff.
+        *
+        * SYNOPSIS:
+        *
+        *    $diff = new Diff($lines1, $lines2);
+        *    $rev = $diff->reverse();
+        *
+        * @return Object A Diff object representing the inverse of the
+        *   original diff.
+        */
+       public function reverse() {
+               $rev = $this;
+               $rev->edits = [];
+               /** @var DiffOp $edit */
+               foreach ( $this->edits as $edit ) {
+                       $rev->edits[] = $edit->reverse();
+               }
+
+               return $rev;
+       }
+
+       /**
+        * Check for empty diff.
+        *
+        * @return bool True if two sequences were identical.
+        */
+       public function isEmpty() {
+               foreach ( $this->edits as $edit ) {
+                       if ( $edit->type != 'copy' ) {
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+
+       /**
+        * Compute the length of the Longest Common Subsequence (LCS).
+        *
+        * This is mostly for diagnostic purposed.
+        *
+        * @return int The length of the LCS.
+        */
+       public function lcs() {
+               $lcs = 0;
+               foreach ( $this->edits as $edit ) {
+                       if ( $edit->type == 'copy' ) {
+                               $lcs += count( $edit->orig );
+                       }
+               }
+
+               return $lcs;
+       }
+
+       /**
+        * Get the original set of lines.
+        *
+        * This reconstructs the $from_lines parameter passed to the
+        * constructor.
+        *
+        * @return string[] The original sequence of strings.
+        */
+       public function orig() {
+               $lines = [];
+
+               foreach ( $this->edits as $edit ) {
+                       if ( $edit->orig ) {
+                               array_splice( $lines, count( $lines ), 0, $edit->orig );
+                       }
+               }
+
+               return $lines;
+       }
+
+       /**
+        * Get the closing set of lines.
+        *
+        * This reconstructs the $to_lines parameter passed to the
+        * constructor.
+        *
+        * @return string[] The sequence of strings.
+        */
+       public function closing() {
+               $lines = [];
+
+               foreach ( $this->edits as $edit ) {
+                       if ( $edit->closing ) {
+                               array_splice( $lines, count( $lines ), 0, $edit->closing );
+                       }
+               }
+
+               return $lines;
+       }
+}
index edf8444..ce507d7 100644 (file)
@@ -456,9 +456,7 @@ class DiffEngine {
 
                // need to store these so we don't lose them when they're
                // overwritten by the recursion
-               $len = $snake[2];
-               $startx = $snake[0];
-               $starty = $snake[1];
+               list( $startx, $starty, $len ) = $snake;
 
                // the middle snake is part of the LCS, store it
                for ( $i = 0; $i < $len; ++$i ) {
@@ -508,13 +506,13 @@ class DiffEngine {
 
                // value_to_add_forward: a 0 or 1 that we add to the start
                // offset to make it odd/even
-               if ( ( $M & 1 ) == 1 ) {
+               if ( $M & 1 ) {
                        $value_to_add_forward = 1;
                } else {
                        $value_to_add_forward = 0;
                }
 
-               if ( ( $N & 1 ) == 1 ) {
+               if ( $N & 1 ) {
                        $value_to_add_backward = 1;
                } else {
                        $value_to_add_backward = 0;
@@ -532,7 +530,7 @@ class DiffEngine {
                $V1[$limit_min_1] = $N;
                $limit = min( $this->maxDifferences, ceil( ( $N + $M ) / 2 ) );
 
-               if ( ( $delta & 1 ) == 1 ) {
+               if ( $delta & 1 ) {
                        for ( $d = 0; $d <= $limit; ++$d ) {
                                $start_diag = max( $value_to_add_forward + $start_forward, -$d );
                                $end_diag = min( $end_forward, $d );
diff --git a/includes/diff/DiffOp.php b/includes/diff/DiffOp.php
new file mode 100644 (file)
index 0000000..2a1f3e1
--- /dev/null
@@ -0,0 +1,97 @@
+<?php
+/**
+ * A PHP diff engine for phpwiki. (Taken from phpwiki-1.3.3)
+ *
+ * Copyright © 2000, 2001 Geoffrey T. Dairiki <dairiki@dairiki.org>
+ * You may copy this code freely under the conditions of the GPL.
+ *
+ * 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 DifferenceEngine
+ * @defgroup DifferenceEngine DifferenceEngine
+ */
+
+/**
+ * The base class for all other DiffOp classes.
+ *
+ * The classes that extend DiffOp are: DiffOpCopy, DiffOpDelete, DiffOpAdd and
+ * DiffOpChange. FakeDiffOp also extends DiffOp, but it is not located in this file.
+ *
+ * @private
+ * @ingroup DifferenceEngine
+ */
+abstract class DiffOp {
+
+       /**
+        * @var string
+        */
+       public $type;
+
+       /**
+        * @var string[]
+        */
+       public $orig;
+
+       /**
+        * @var string[]
+        */
+       public $closing;
+
+       /**
+        * @return string
+        */
+       public function getType() {
+               return $this->type;
+       }
+
+       /**
+        * @return string[]
+        */
+       public function getOrig() {
+               return $this->orig;
+       }
+
+       /**
+        * @param int|null $i
+        * @return string[]|string|null
+        */
+       public function getClosing( $i = null ) {
+               if ( $i === null ) {
+                       return $this->closing;
+               }
+               if ( array_key_exists( $i, $this->closing ) ) {
+                       return $this->closing[$i];
+               }
+               return null;
+       }
+
+       abstract public function reverse();
+
+       /**
+        * @return int
+        */
+       public function norig() {
+               return $this->orig ? count( $this->orig ) : 0;
+       }
+
+       /**
+        * @return int
+        */
+       public function nclosing() {
+               return $this->closing ? count( $this->closing ) : 0;
+       }
+}
diff --git a/includes/diff/DiffOpAdd.php b/includes/diff/DiffOpAdd.php
new file mode 100644 (file)
index 0000000..3f95e8d
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * A PHP diff engine for phpwiki. (Taken from phpwiki-1.3.3)
+ *
+ * Copyright © 2000, 2001 Geoffrey T. Dairiki <dairiki@dairiki.org>
+ * You may copy this code freely under the conditions of the GPL.
+ *
+ * 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 DifferenceEngine
+ */
+
+/**
+ * Extends DiffOp. Used to mark strings that have been
+ * added from the first string array.
+ *
+ * @private
+ * @ingroup DifferenceEngine
+ */
+class DiffOpAdd extends DiffOp {
+       public $type = 'add';
+
+       public function __construct( $lines ) {
+               $this->closing = $lines;
+               $this->orig = false;
+       }
+
+       /**
+        * @return DiffOpDelete
+        */
+       public function reverse() {
+               return new DiffOpDelete( $this->closing );
+       }
+}
diff --git a/includes/diff/DiffOpChange.php b/includes/diff/DiffOpChange.php
new file mode 100644 (file)
index 0000000..bde9287
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * A PHP diff engine for phpwiki. (Taken from phpwiki-1.3.3)
+ *
+ * Copyright © 2000, 2001 Geoffrey T. Dairiki <dairiki@dairiki.org>
+ * You may copy this code freely under the conditions of the GPL.
+ *
+ * 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 DifferenceEngine
+ */
+
+/**
+ * Extends DiffOp. Used to mark strings that have been
+ * changed from the first string array (both added and subtracted).
+ *
+ * @private
+ * @ingroup DifferenceEngine
+ */
+class DiffOpChange extends DiffOp {
+       public $type = 'change';
+
+       public function __construct( $orig, $closing ) {
+               $this->orig = $orig;
+               $this->closing = $closing;
+       }
+
+       /**
+        * @return DiffOpChange
+        */
+       public function reverse() {
+               return new DiffOpChange( $this->closing, $this->orig );
+       }
+}
diff --git a/includes/diff/DiffOpCopy.php b/includes/diff/DiffOpCopy.php
new file mode 100644 (file)
index 0000000..904ee58
--- /dev/null
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * A PHP diff engine for phpwiki. (Taken from phpwiki-1.3.3)
+ *
+ * Copyright © 2000, 2001 Geoffrey T. Dairiki <dairiki@dairiki.org>
+ * You may copy this code freely under the conditions of the GPL.
+ *
+ * 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 DifferenceEngine
+ */
+
+/**
+ * Extends DiffOp. Used to mark strings that have been
+ * copied from one string array to the other.
+ *
+ * @private
+ * @ingroup DifferenceEngine
+ */
+class DiffOpCopy extends DiffOp {
+       public $type = 'copy';
+
+       public function __construct( $orig, $closing = false ) {
+               if ( !is_array( $closing ) ) {
+                       $closing = $orig;
+               }
+               $this->orig = $orig;
+               $this->closing = $closing;
+       }
+
+       /**
+        * @return DiffOpCopy
+        */
+       public function reverse() {
+               return new DiffOpCopy( $this->closing, $this->orig );
+       }
+}
diff --git a/includes/diff/DiffOpDelete.php b/includes/diff/DiffOpDelete.php
new file mode 100644 (file)
index 0000000..22b65ab
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * A PHP diff engine for phpwiki. (Taken from phpwiki-1.3.3)
+ *
+ * Copyright © 2000, 2001 Geoffrey T. Dairiki <dairiki@dairiki.org>
+ * You may copy this code freely under the conditions of the GPL.
+ *
+ * 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 DifferenceEngine
+ */
+
+/**
+ * Extends DiffOp. Used to mark strings that have been
+ * deleted from the first string array.
+ *
+ * @private
+ * @ingroup DifferenceEngine
+ */
+class DiffOpDelete extends DiffOp {
+       public $type = 'delete';
+
+       public function __construct( $lines ) {
+               $this->orig = $lines;
+               $this->closing = false;
+       }
+
+       /**
+        * @return DiffOpAdd
+        */
+       public function reverse() {
+               return new DiffOpAdd( $this->orig );
+       }
+}
index e39334f..f7658fc 100644 (file)
@@ -250,7 +250,7 @@ class DifferenceEngine extends ContextSource {
 
                        $slotContents = $this->getSlotContents();
                        $this->slotDiffRenderers = array_map( function ( $contents ) {
-                               /** @var $content Content */
+                               /** @var Content $content */
                                $content = $contents['new'] ?: $contents['old'];
                                return $content->getContentHandler()->getSlotDiffRenderer( $this->getContext() );
                        }, $slotContents );
@@ -1172,7 +1172,6 @@ class DifferenceEngine extends ContextSource {
 
                if ( $engine === 'wikidiff2' ) {
                        $params[] = phpversion( 'wikidiff2' );
-                       $params[] = $this->getConfig()->get( 'WikiDiff2MovedParagraphDetectionCutoff' );
                }
 
                if ( !$this->isSlotDiffRenderer ) {
@@ -1733,16 +1732,16 @@ class DifferenceEngine extends ContextSource {
         * by the request context); if oldid is 0, then compare the revision in newid to the
         * immediately previous one.
         *
-        * If oldid is false, leave the corresponding revision object set
-        * to false. This can happen with 'diff=prev' pointing to a non-existent revision,
-        * and is also used directly by the API.
+        * If oldid is false, leave the corresponding revision object set to false. This can
+        * happen with 'diff=prev' pointing to a non-existent revision, and is also used directly
+        * by the API.
         *
         * @return bool Whether both revisions were loaded successfully. Setting mOldRev
         *   to false counts as successful loading.
         */
        public function loadRevisionData() {
                if ( $this->mRevisionsLoaded ) {
-                       return $this->isContentOverridden || $this->mNewRev && !is_null( $this->mOldRev );
+                       return $this->isContentOverridden || ( $this->mOldRev !== null && $this->mNewRev !== null );
                }
 
                // Whether it succeeds or fails, we don't want to try again
index e2cdd82..510465b 100644 (file)
@@ -51,14 +51,6 @@ class TextSlotDiffRenderer extends SlotDiffRenderer {
        /** @var Language|null The language this content is in. */
        private $language;
 
-       /**
-        * Number of paragraph moves the algorithm should attempt to detect.
-        * Only used with the wikidiff2 engine.
-        * @var int
-        * @see $wgWikiDiff2MovedParagraphDetectionCutoff
-        */
-       private $wikiDiff2MovedParagraphDetectionCutoff = 0;
-
        /** @var string One of the ENGINE_* constants. */
        private $engine = self::ENGINE_PHP;
 
@@ -72,7 +64,7 @@ class TextSlotDiffRenderer extends SlotDiffRenderer {
         * @return string
         */
        public static function diff( $oldText, $newText ) {
-               /** @var $slotDiffRenderer TextSlotDiffRenderer */
+               /** @var TextSlotDiffRenderer $slotDiffRenderer */
                $slotDiffRenderer = ContentHandler::getForModelID( CONTENT_MODEL_TEXT )
                        ->getSlotDiffRenderer( RequestContext::getMain() );
                return $slotDiffRenderer->getTextDiff( $oldText, $newText );
@@ -86,15 +78,6 @@ class TextSlotDiffRenderer extends SlotDiffRenderer {
                $this->language = $language;
        }
 
-       /**
-        * @param int $cutoff
-        * @see $wgWikiDiff2MovedParagraphDetectionCutoff
-        */
-       public function setWikiDiff2MovedParagraphDetectionCutoff( $cutoff ) {
-               Assert::parameterType( 'integer', $cutoff, '$cutoff' );
-               $this->wikiDiff2MovedParagraphDetectionCutoff = $cutoff;
-       }
-
        /**
         * Set which diff engine to use.
         * @param string $type One of the ENGINE_* constants.
@@ -205,7 +188,7 @@ class TextSlotDiffRenderer extends SlotDiffRenderer {
                                        $oldText,
                                        $newText,
                                        2,
-                                       $this->wikiDiff2MovedParagraphDetectionCutoff
+                                       0
                                );
                        } else {
                                // Don't pass the 4th parameter introduced in version 1.5.0 and removed in version 1.8.0
@@ -214,12 +197,6 @@ class TextSlotDiffRenderer extends SlotDiffRenderer {
                                        $newText,
                                        2
                                );
-
-                               // Log a warning in case the configuration value is set to not silently ignore it
-                               if ( $this->wikiDiff2MovedParagraphDetectionCutoff > 0 ) {
-                                       wfLogWarning( '$wgWikiDiff2MovedParagraphDetectionCutoff is set but has no
-                                               effect since the used version of WikiDiff2 does not support it.' );
-                               }
                        }
 
                        return $text;
index 7007316..88eae36 100644 (file)
@@ -22,6 +22,7 @@ namespace MediaWiki\Edit;
 
 use Content;
 use ParserOptions;
+use RuntimeException;
 use ParserOutput;
 
 /**
@@ -32,7 +33,6 @@ use ParserOutput;
  * @since 1.30
  */
 class PreparedEdit {
-
        /**
         * Time this prepared edit was made
         *
@@ -73,7 +73,7 @@ class PreparedEdit {
         *
         * @var ParserOutput|null
         */
-       public $output;
+       private $canonicalOutput;
 
        /**
         * Content that is being saved (before PST)
@@ -89,4 +89,36 @@ class PreparedEdit {
         */
        public $oldContent;
 
+       /**
+        * Lazy-loading callback to get canonical ParserOutput object
+        *
+        * @var callable
+        */
+       public $parserOutputCallback;
+
+       /**
+        * @return ParserOutput Canonical parser output
+        */
+       public function getOutput() {
+               if ( !$this->canonicalOutput ) {
+                       $this->canonicalOutput = call_user_func( $this->parserOutputCallback );
+               }
+
+               return $this->canonicalOutput;
+       }
+
+       /**
+        * Fetch the ParserOutput via a lazy-loaded callback (for backwards compatibility).
+        *
+        * @deprecated since 1.33
+        * @param string $name
+        * @return mixed
+        */
+       function __get( $name ) {
+               if ( $name === 'output' ) {
+                       return $this->getOutput();
+               }
+
+               throw new RuntimeException( "Undefined field $name." );
+       }
 }
index f7d0945..b5b74fb 100644 (file)
@@ -166,7 +166,6 @@ class TextConflictHelper {
         * HTML to build the textbox1 on edit conflicts
         *
         * @param array $customAttribs
-        * @return string HTML
         */
        public function getEditConflictMainTextBox( array $customAttribs = [] ) {
                $builder = new TextboxBuilder();
@@ -246,7 +245,7 @@ class TextConflictHelper {
         * @param string $text
         * @return Content
         */
-       public function toEditContent( $text ) {
+       private function toEditContent( $text ) {
                return ContentHandler::makeContent(
                        $text,
                        $this->title,
index 354cc61..103b3e5 100644 (file)
@@ -24,7 +24,7 @@
 
 namespace MediaWiki\EditPage;
 
-use MWNamespace;
+use MediaWiki\MediaWikiServices;
 use Sanitizer;
 use Title;
 use User;
@@ -75,7 +75,8 @@ class TextboxBuilder {
        public function getTextboxProtectionCSSClasses( Title $title ) {
                $classes = []; // Textarea CSS
                if ( $title->isProtected( 'edit' ) &&
-                       MWNamespace::getRestrictionLevels( $title->getNamespace() ) !== [ '' ]
+                       MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       getRestrictionLevels( $title->getNamespace() ) !== [ '' ]
                ) {
                        # Is the title semi-protected?
                        if ( $title->isSemiProtected() ) {
index 502cee8..c16d9f7 100644 (file)
@@ -69,23 +69,22 @@ class MWException extends Exception {
         * @param string $key Message name
         * @param string $fallback Default message if the message cache can't be
         *                  called by the exception
-        * The function also has other parameters that are arguments for the message
+        * @param mixed ...$params To pass to wfMessage()
         * @return string Message with arguments replaced
         */
-       public function msg( $key, $fallback /*[, params...] */ ) {
+       public function msg( $key, $fallback, ...$params ) {
                global $wgSitename;
-               $args = array_slice( func_get_args(), 2 );
 
                // FIXME: Keep logic in sync with MWExceptionRenderer::msg.
                $res = false;
                if ( $this->useMessageCache() ) {
                        try {
-                               $res = wfMessage( $key, $args )->text();
+                               $res = wfMessage( $key, $params )->text();
                        } catch ( Exception $e ) {
                        }
                }
                if ( $res === false ) {
-                       $res = wfMsgReplaceArgs( $fallback, $args );
+                       $res = wfMsgReplaceArgs( $fallback, $params );
                        // If an exception happens inside message rendering,
                        // {{SITENAME}} sometimes won't be replaced.
                        $res = strtr( $res, [
@@ -253,6 +252,7 @@ class MWException extends Exception {
                        header( $header );
                }
        }
+
        private static function statusHeader( $code ) {
                if ( !headers_sent() ) {
                        HttpStatus::header( $code );
index 6e3fa79..b4e483b 100644 (file)
@@ -74,9 +74,32 @@ class MWExceptionHandler {
         * Install handlers with PHP.
         */
        public static function installHandler() {
+               // This catches:
+               // * Exception objects that were explicitly thrown but not
+               //   caught anywhere in the application. This is rare given those
+               //   would normally be caught at a high-level like MediaWiki::run (index.php),
+               //   api.php, or ResourceLoader::respond (load.php). These high-level
+               //   catch clauses would then call MWExceptionHandler::logException
+               //   or MWExceptionHandler::handleException.
+               //   If they are not caught, then they are handled here.
+               // * Error objects (on PHP 7+), for issues that would historically
+               //   cause fatal errors but may now be caught as Throwable (not Exception).
+               //   Same as previous case, but more common to bubble to here instead of
+               //   caught locally because they tend to not be safe to recover from.
+               //   (e.g. argument TypeErorr, devision by zero, etc.)
                set_exception_handler( 'MWExceptionHandler::handleUncaughtException' );
+
+               // This catches:
+               // * Non-fatal errors (e.g. PHP Notice, PHP Warning, PHP Error) that do not
+               //   interrupt execution in any way. We log these in the background and then
+               //   continue execution.
+               // * Fatal errors (on HHVM in PHP5 mode) where PHP 7 would throw Throwable.
                set_error_handler( 'MWExceptionHandler::handleError' );
 
+               // This catches:
+               // * Fatal error for which no Throwable is thrown (PHP 7), and no Error emitted (HHVM).
+               //   This includes Out-Of-Memory and Timeout fatals.
+               //
                // Reserve 16k of memory so we can report OOM fatals
                self::$reservedMemory = str_repeat( ' ', 16384 );
                register_shutdown_function( 'MWExceptionHandler::handleFatalError' );
index ca590d8..c52a867 100644 (file)
@@ -71,14 +71,12 @@ class MWExceptionRenderer {
                                                self::getShowBacktraceError( $e );
                                }
                                $message .= "\n";
+                       } elseif ( $wgShowExceptionDetails ) {
+                               $message = MWExceptionHandler::getLogMessage( $e ) .
+                                       "\nBacktrace:\n" .
+                                       MWExceptionHandler::getRedactedTraceAsString( $e ) . "\n";
                        } else {
-                               if ( $wgShowExceptionDetails ) {
-                                       $message = MWExceptionHandler::getLogMessage( $e ) .
-                                               "\nBacktrace:\n" .
-                                               MWExceptionHandler::getRedactedTraceAsString( $e ) . "\n";
-                               } else {
-                                       $message = MWExceptionHandler::getPublicLogMessage( $e );
-                               }
+                               $message = MWExceptionHandler::getPublicLogMessage( $e );
                        }
                        echo nl2br( htmlspecialchars( $message ) ) . "\n";
                }
@@ -193,18 +191,17 @@ class MWExceptionRenderer {
         * @param string $key Message name
         * @param string $fallback Default message if the message cache can't be
         *                  called by the exception
-        * The function also has other parameters that are arguments for the message
+        * @param mixed ...$params To pass to wfMessage()
         * @return string Message with arguments replaced
         */
-       private static function msg( $key, $fallback /*[, params...] */ ) {
+       private static function msg( $key, $fallback, ...$params ) {
                global $wgSitename;
-               $args = array_slice( func_get_args(), 2 );
 
                // FIXME: Keep logic in sync with MWException::msg.
                try {
-                       $res = wfMessage( $key, $args )->text();
+                       $res = wfMessage( $key, $params )->text();
                } catch ( Exception $e ) {
-                       $res = wfMsgReplaceArgs( $fallback, $args );
+                       $res = wfMsgReplaceArgs( $fallback, $params );
                        // If an exception happens inside message rendering,
                        // {{SITENAME}} sometimes won't be replaced.
                        $res = strtr( $res, [
index 9d19f8b..9746c2b 100644 (file)
@@ -18,6 +18,8 @@
  * @file
  */
 
+use MediaWiki\Block\AbstractBlock;
+
 /**
  * Show an error when the user tries to do something whilst blocked.
  *
@@ -25,7 +27,7 @@
  * @ingroup Exception
  */
 class UserBlockedError extends ErrorPageError {
-       public function __construct( Block $block ) {
+       public function __construct( AbstractBlock $block ) {
                // @todo FIXME: Implement a more proper way to get context here.
                $params = $block->getPermissionsError( RequestContext::getMain() );
                parent::__construct( 'blockedtitle', array_shift( $params ), $params );
index 31c945c..a50150e 100644 (file)
@@ -23,6 +23,8 @@
  * @file
  */
 
+use MediaWiki\Shell\Shell;
+
 /**
  * @ingroup Dump
  */
@@ -49,8 +51,8 @@ class Dump7ZipOutput extends DumpPipeOutput {
         */
        function setup7zCommand( $file ) {
                $command = "7za a -bd -si -mx=";
-               $command .= wfEscapeShellArg( $this->compressionLevel ) . ' ';
-               $command .= wfEscapeShellArg( $file );
+               $command .= Shell::escape( $this->compressionLevel ) . ' ';
+               $command .= Shell::escape( $file );
                // Suppress annoying useless crap from p7zip
                // Unfortunately this could suppress real error messages too
                $command .= ' >' . wfGetNull() . ' 2>&1';
diff --git a/includes/export/DumpLBZip2Output.php b/includes/export/DumpLBZip2Output.php
new file mode 100644 (file)
index 0000000..b923995
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+/**
+ * Sends dump output via the lbzip2 compressor.
+ *
+ * Copyright © 2003, 2005, 2006 Brion Vibber <brion@pobox.com>
+ * Copyright © 2019 Wikimedia Foundation Inc.
+ * https://www.mediawiki.org/
+ *
+ * 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 Dump
+ * @since 1.33
+ */
+class DumpLBZip2Output extends DumpPipeOutput {
+       /**
+        * @param string $file
+        */
+       function __construct( $file ) {
+               # use only one core
+               parent::__construct( "lbzip2 -n 1", $file );
+       }
+}
index c201c76..6b2a22a 100644 (file)
@@ -23,6 +23,8 @@
  * @file
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * @ingroup Dump
  */
@@ -32,6 +34,7 @@ class DumpNotalkFilter extends DumpFilter {
         * @return bool
         */
        protected function pass( $page ) {
-               return !MWNamespace::isTalk( $page->page_namespace );
+               return !MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       isTalk( $page->page_namespace );
        }
 }
index 26010da..a353c44 100644 (file)
@@ -25,6 +25,8 @@
  * @file
  */
 
+use MediaWiki\Shell\Shell;
+
 /**
  * @ingroup Dump
  */
@@ -38,7 +40,7 @@ class DumpPipeOutput extends DumpFileOutput {
         */
        function __construct( $command, $file = null ) {
                if ( !is_null( $file ) ) {
-                       $command .= " > " . wfEscapeShellArg( $file );
+                       $command .= " > " . Shell::escape( $file );
                }
 
                $this->startCommand( $command );
@@ -94,7 +96,7 @@ class DumpPipeOutput extends DumpFileOutput {
                        $this->renameOrException( $newname );
                        if ( $open ) {
                                $command = $this->command;
-                               $command .= " > " . wfEscapeShellArg( $this->filename );
+                               $command .= " > " . Shell::escape( $this->filename );
                                $this->startCommand( $command );
                        }
                }
index fbcf832..ca63dfe 100644 (file)
@@ -63,12 +63,16 @@ class WikiExporter {
        /** @var DumpOutput */
        public $sink;
 
+       /** @var XmlDumpWriter */
+       private $writer;
+
        /**
-        * Returns the export schema version.
+        * Returns the default export schema version, as defined by $wgXmlDumpSchemaVersion.
         * @return string
         */
        public static function schemaVersion() {
-               return "0.10";
+               global $wgXmlDumpSchemaVersion;
+               return $wgXmlDumpSchemaVersion;
        }
 
        /**
@@ -79,13 +83,27 @@ class WikiExporter {
         *   - limit: maximum number of rows to return
         *   - dir: "asc" or "desc" timestamp order
         * @param int $text One of WikiExporter::TEXT or WikiExporter::STUB
+        * @param null|array $limitNamespaces Comma-separated list of namespace numbers
+        *   to limit results
         */
-       function __construct( $db, $history = self::CURRENT, $text = self::TEXT ) {
+       function __construct( $db, $history = self::CURRENT, $text = self::TEXT,
+                       $limitNamespaces = null
+       ) {
                $this->db = $db;
                $this->history = $history;
-               $this->writer = new XmlDumpWriter();
+               $this->writer = new XmlDumpWriter( $text, self::schemaVersion() );
                $this->sink = new DumpOutput();
                $this->text = $text;
+               $this->limitNamespaces = $limitNamespaces;
+       }
+
+       /**
+        * @param string $schemaVersion which schema version the generated XML should comply to.
+        * One of the values from self::$supportedSchemas, using the XML_DUMP_SCHEMA_VERSION_XX
+        * constants.
+        */
+       public function setSchemaVersion( $schemaVersion ) {
+               $this->writer = new XmlDumpWriter( $this->text, $schemaVersion );
        }
 
        /**
@@ -455,9 +473,14 @@ class WikiExporter {
         */
        protected function outputPageStreamBatch( $results, $lastRow ) {
                foreach ( $results as $row ) {
+                       if ( $this->limitNamespaces &&
+                               !in_array( $row->page_namespace, $this->limitNamespaces ) ) {
+                               $lastRow = $row;
+                               continue;
+                       }
                        if ( $lastRow === null ||
-                               $lastRow->page_namespace != $row->page_namespace ||
-                               $lastRow->page_title != $row->page_title ) {
+                               $lastRow->page_namespace !== $row->page_namespace ||
+                               $lastRow->page_title !== $row->page_title ) {
                                if ( $lastRow !== null ) {
                                        $output = '';
                                        if ( $this->dumpUploads ) {
index fbc4b0d..39153cf 100644 (file)
@@ -30,6 +30,13 @@ use MediaWiki\Storage\SqlBlobStore;
  * @ingroup Dump
  */
 class XmlDumpWriter {
+       /**
+        * @var string[] the schema versions supported for output
+        * @final
+        */
+       public static $supportedSchemas = [
+               XML_DUMP_SCHEMA_VERSION_10,
+       ];
 
        /**
         * Title of the currently processed page
@@ -134,6 +141,7 @@ class XmlDumpWriter {
         */
        function namespaces() {
                $spaces = "<namespaces>\n";
+               $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
                foreach (
                        MediaWikiServices::getInstance()->getContentLanguage()->getFormattedNamespaces()
                        as $ns => $title
@@ -142,7 +150,8 @@ class XmlDumpWriter {
                                Xml::element( 'namespace',
                                        [
                                                'key' => $ns,
-                                               'case' => MWNamespace::isCapitalized( $ns ) ? 'first-letter' : 'case-sensitive',
+                                               'case' => $nsInfo->isCapitalized( $ns )
+                                                       ? 'first-letter' : 'case-sensitive',
                                        ], $title ) . "\n";
                }
                $spaces .= "    </namespaces>";
@@ -200,6 +209,12 @@ class XmlDumpWriter {
         * @return string
         */
        function closePage() {
+               if ( $this->currentTitle !== null ) {
+                       $linkCache = MediaWikiServices::getInstance()->getLinkCache();
+                       // In rare cases, link cache has the same key for some pages which
+                       // might be read as part of the same batch. T220424 and T220316
+                       $linkCache->clearLink( $this->currentTitle );
+               }
                return "  </page>\n";
        }
 
@@ -279,7 +294,17 @@ class XmlDumpWriter {
                } elseif ( isset( $row->old_text ) ) {
                        // Raw text from the database may have invalid chars
                        $text = strval( Revision::getRevisionText( $row ) );
-                       $text = $content_handler->exportTransform( $text, $content_format );
+                       try {
+                               $text = $content_handler->exportTransform( $text, $content_format );
+                       }
+                       catch ( Exception $ex ) {
+                               if ( $ex instanceof MWException || $ex instanceof RuntimeException ) {
+                                       // leave text as is; that's the way it goes
+                                       wfLogWarning( 'exportTransform failed on text for revid ' . $row->rev_id . "\n" );
+                               } else {
+                                       throw $ex;
+                               }
+                       }
                        $out .= "      " . Xml::elementClean( 'text',
                                [ 'xml:space' => 'preserve', 'bytes' => intval( $row->rev_len ) ],
                                strval( $text ) ) . "\n";
@@ -287,21 +312,33 @@ class XmlDumpWriter {
                        // TODO: make this fully MCR aware, see T174031
                        $rev = $this->getRevisionStore()->newRevisionFromRow( $row, 0, $this->currentTitle );
                        $slot = $rev->getSlot( 'main' );
-                       $content = $slot->getContent();
-
-                       if ( $content instanceof TextContent ) {
-                               // HACK: For text based models, bypass the serialization step.
-                               // This allows extensions (like Flow)that use incompatible combinations
-                               // of serialization format and content model.
-                               $text = $content->getNativeData();
-                       } else {
-                               $text = $content->serialize( $content_format );
+                       try {
+                               $content = $slot->getContent();
+
+                               if ( $content instanceof TextContent ) {
+                                       // HACK: For text based models, bypass the serialization step.
+                                       // This allows extensions (like Flow)that use incompatible combinations
+                                       // of serialization format and content model.
+                                       $text = $content->getNativeData();
+                               } else {
+                                       $text = $content->serialize( $content_format );
+                               }
+                               $text = $content_handler->exportTransform( $text, $content_format );
+                               $out .= "      " . Xml::elementClean( 'text',
+                                       [ 'xml:space' => 'preserve', 'bytes' => intval( $slot->getSize() ) ],
+                                       strval( $text ) ) . "\n";
+                       }
+                       catch ( Exception $ex ) {
+                               if ( $ex instanceof MWException || $ex instanceof RuntimeException ) {
+                                       // there's no provsion in the schema for an attribute that will let
+                                       // the user know this element was unavailable due to error; an empty
+                                       // tag is the best we can do
+                                       $out .= "      " . Xml::element( 'text' ) . "\n";
+                                       wfLogWarning( 'failed to load content for revid ' . $row->rev_id . "\n" );
+                               } else {
+                                       throw $ex;
+                               }
                        }
-
-                       $text = $content_handler->exportTransform( $text, $content_format );
-                       $out .= "      " . Xml::elementClean( 'text',
-                               [ 'xml:space' => 'preserve', 'bytes' => intval( $slot->getSize() ) ],
-                               strval( $text ) ) . "\n";
                } elseif ( isset( $row->rev_text_id ) ) {
                        // Stub output for pre-MCR schema
                        // TODO: MCR: rev_text_id only exists in the pre-MCR schema. Remove this when
index de7d1a4..9cf8e15 100644 (file)
@@ -197,7 +197,7 @@ class ExternalStore {
                                        $msg = 'read only';
                                } else {
                                        $url = $store->store( $path, $data );
-                                       if ( strlen( $url ) ) {
+                                       if ( $url !== false ) {
                                                return $url; // a store accepted the write; done!
                                        }
                                        $msg = 'operation failed';
index 75f7ccd..4164505 100644 (file)
@@ -166,7 +166,7 @@ class ExternalStoreDB extends ExternalStoreMedium {
         * @return string|bool Database domain ID or false
         */
        private function getDomainId( array $server ) {
-               if ( isset( $this->params['wiki'] ) ) {
+               if ( isset( $this->params['wiki'] ) && $this->params['wiki'] !== false ) {
                        return $this->params['wiki']; // explicit domain
                }
 
index 879686f..a723557 100644 (file)
@@ -20,6 +20,8 @@
  * @file
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * Example class for HTTP accessible external objects.
  * Only supports reading, not storing.
@@ -28,7 +30,8 @@
  */
 class ExternalStoreHttp extends ExternalStoreMedium {
        public function fetchFromURL( $url ) {
-               return Http::get( $url, [], __METHOD__ );
+               return MediaWikiServices::getInstance()->getHttpRequestFactory()->
+                       get( $url, [], __METHOD__ );
        }
 
        public function store( $location, $data ) {
index a091608..a5860e2 100644 (file)
@@ -178,9 +178,15 @@ class FileBackendGroup {
 
                $config = $this->backends[$name]['config'];
                $config['class'] = $class;
-               $config += [ // set defaults
+               if ( isset( $config['domainId'] ) ) {
+                       $domain = $config['domainId'];
+               } else {
                        // @FIXME: this does not include the domain for b/c but it ideally should
-                       'wikiId' => wfWikiID(), // e.g. "my_wiki-en_"
+                       $domain = $config['wikiId'] ?? wfWikiID();
+               }
+               // Set default parameter values
+               $config += [
+                       'domainId' => $domain, // e.g. "my_wiki-en_"
                        'mimeCallback' => [ $this, 'guessMimeInternal' ],
                        'obResetFunc' => 'wfResetOutputBuffers',
                        'streamMimeFunc' => [ StreamFile::class, 'contentTypeFromPath' ],
@@ -194,7 +200,7 @@ class FileBackendGroup {
                        }
                ];
                $config['lockManager'] =
-                       LockManagerGroup::singleton( $config['wikiId'] )->get( $config['lockManager'] );
+                       LockManagerGroup::singleton( $domain )->get( $config['lockManager'] );
                $config['fileJournal'] = isset( $config['fileJournal'] )
                        ? FileJournal::factory( $config['fileJournal'], $name )
                        : FileJournal::factory( [ 'class' => NullFileJournal::class ], $name );
index 3dc9f18..17cf8f0 100644 (file)
@@ -32,19 +32,19 @@ use Wikimedia\Rdbms\DBError;
 class DBFileJournal extends FileJournal {
        /** @var IDatabase */
        protected $dbw;
-
-       protected $wiki = false; // string; wiki DB name
+       /** @var string */
+       protected $domain;
 
        /**
         * Construct a new instance from configuration.
         *
         * @param array $config Includes:
-        *     'wiki' : wiki name to use for LoadBalancer
+        *   domain: database domain ID of the wiki
         */
        protected function __construct( array $config ) {
                parent::__construct( $config );
 
-               $this->wiki = $config['wiki'];
+               $this->domain = $config['domain'] ?? $config['wiki']; // b/c
        }
 
        /**
@@ -184,7 +184,7 @@ class DBFileJournal extends FileJournal {
                if ( !$this->dbw ) {
                        // Get a separate connection in autocommit mode
                        $lb = MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->newMainLB();
-                       $this->dbw = $lb->getConnection( DB_MASTER, [], $this->wiki );
+                       $this->dbw = $lb->getConnection( DB_MASTER, [], $this->domain );
                        $this->dbw->clearFlag( DBO_TRX );
                }
 
index aa955d0..43f6010 100644 (file)
@@ -129,6 +129,7 @@ class LockManagerGroup {
                        }
                        $config['logger'] = LoggerFactory::getInstance( 'LockManager' );
 
+                       // @phan-suppress-next-line PhanTypeInstantiateAbstract
                        $this->managers[$name]['instance'] = new $class( $config );
                }
 
index b445487..962cfd9 100644 (file)
@@ -54,7 +54,7 @@ class FileBackendDBRepoWrapper extends FileBackend {
                /** @var FileBackend $backend */
                $backend = $config['backend'];
                $config['name'] = $backend->getName();
-               $config['wikiId'] = $backend->getWikiId();
+               $config['domainId'] = $backend->getDomainId();
                parent::__construct( $config );
                $this->backend = $config['backend'];
                $this->repoName = $config['repoName'];
index 3225625..3e11a48 100644 (file)
@@ -176,7 +176,8 @@ class FileRepo {
                }
 
                // Optional settings that have a default
-               $this->initialCapital = $info['initialCapital'] ?? MWNamespace::isCapitalized( NS_FILE );
+               $this->initialCapital = $info['initialCapital'] ??
+                       MediaWikiServices::getInstance()->getNamespaceInfo()->isCapitalized( NS_FILE );
                $this->url = $info['url'] ?? false; // a subclass may set the URL (e.g. ForeignAPIRepo)
                if ( isset( $info['thumbUrl'] ) ) {
                        $this->thumbUrl = $info['thumbUrl'];
@@ -645,7 +646,10 @@ class FileRepo {
         * @return string
         */
        public function getNameFromTitle( Title $title ) {
-               if ( $this->initialCapital != MWNamespace::isCapitalized( NS_FILE ) ) {
+               if (
+                       $this->initialCapital !=
+                       MediaWikiServices::getInstance()->getNamespaceInfo()->isCapitalized( NS_FILE )
+               ) {
                        $name = $title->getUserCaseDBKey();
                        if ( $this->initialCapital ) {
                                $name = MediaWikiServices::getInstance()->getContentLanguage()->ucfirst( $name );
@@ -1630,18 +1634,6 @@ class FileRepo {
                return $status;
        }
 
-       /**
-        * Attempt to stream a file with the given virtual URL/storage path
-        *
-        * @deprecated since 1.26, use streamFileWithStatus
-        * @param string $virtualUrl
-        * @param array $headers Additional HTTP headers to send on success
-        * @return bool Success
-        */
-       public function streamFile( $virtualUrl, $headers = [] ) {
-               return $this->streamFileWithStatus( $virtualUrl, $headers )->isOK();
-       }
-
        /**
         * Call a callback function for every public regular file in the repository.
         * This only acts on the current version of files, not any old versions.
diff --git a/includes/filerepo/FileRepoStatus.php b/includes/filerepo/FileRepoStatus.php
deleted file mode 100644 (file)
index 538e9bc..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-/**
- * Generic operation result for FileRepo-related operations.
- *
- * 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 FileRepo
- */
-
-/**
- * Generic operation result class for FileRepo-related operations
- * @ingroup FileRepo
- * @deprecated since 1.25
- */
-class FileRepoStatus extends Status {
-}
index 9e4b6df..2c6f296 100644 (file)
@@ -348,14 +348,11 @@ class ForeignAPIRepo extends FileRepo {
                if ( !$knownThumbUrls ) {
                        /* No knownThumbUrls for this file */
                        $knownThumbUrls = [];
-               } else {
-                       if ( isset( $knownThumbUrls[$sizekey] ) ) {
-                               wfDebug( __METHOD__ . ': Got thumburl from local cache: ' .
-                                       "{$knownThumbUrls[$sizekey]} \n" );
+               } elseif ( isset( $knownThumbUrls[$sizekey] ) ) {
+                       wfDebug( __METHOD__ . ': Got thumburl from local cache: ' .
+                               "{$knownThumbUrls[$sizekey]} \n" );
 
-                               return $knownThumbUrls[$sizekey];
-                       }
-                       /* This size is not yet known */
+                       return $knownThumbUrls[$sizekey];
                }
 
                $metadata = null;
@@ -505,8 +502,9 @@ class ForeignAPIRepo extends FileRepo {
        }
 
        /**
-        * Like a Http:get request, but with custom User-Agent.
-        * @see Http::get
+        * Like a HttpRequestFactory::get request, but with custom User-Agent.
+        * @see HttpRequestFactory::get
+        * @todo Can this use HttpRequestFactory::get() but just pass the 'userAgent' option?
         * @param string $url
         * @param string $timeout
         * @param array $options
index b6c70ab..8047835 100644 (file)
@@ -35,6 +35,9 @@ class RepoGroup {
        /** @var FileRepo[] */
        protected $foreignRepos;
 
+       /** @var WANObjectCache */
+       protected $wanCache;
+
        /** @var bool */
        protected $reposInitialised = false;
 
@@ -47,66 +50,60 @@ class RepoGroup {
        /** @var ProcessCacheLRU */
        protected $cache;
 
-       /** @var RepoGroup */
-       protected static $instance;
-
        /** Maximum number of cache items */
        const MAX_CACHE_SIZE = 500;
 
        /**
-        * Get a RepoGroup instance. At present only one instance of RepoGroup is
-        * needed in a MediaWiki invocation, this may change in the future.
+        * @deprecated since 1.34, use MediaWikiServices::getRepoGroup
         * @return RepoGroup
         */
        static function singleton() {
-               if ( self::$instance ) {
-                       return self::$instance;
-               }
-               global $wgLocalFileRepo, $wgForeignFileRepos;
-               /** @var array $wgLocalFileRepo */
-               self::$instance = new RepoGroup( $wgLocalFileRepo, $wgForeignFileRepos );
-
-               return self::$instance;
+               return MediaWikiServices::getInstance()->getRepoGroup();
        }
 
        /**
-        * Destroy the singleton instance, so that a new one will be created next
-        * time singleton() is called.
+        * @deprecated since 1.34, use MediaWikiTestCase::overrideMwServices() or similar. This will
+        * cause bugs if you don't reset all other services that depend on this one at the same time.
         */
        static function destroySingleton() {
-               self::$instance = null;
+               MediaWikiServices::getInstance()->resetServiceForTesting( 'RepoGroup' );
        }
 
        /**
-        * Set the singleton instance to a given object
-        * Used by extensions which hook into the Repo chain.
-        * It's not enough to just create a superclass ... you have
-        * to get people to call into it even though all they know is RepoGroup::singleton()
-        *
+        * @deprecated since 1.34, use MediaWikiTestCase::setService, this can mess up state of other
+        *   tests
         * @param RepoGroup $instance
         */
        static function setSingleton( $instance ) {
-               self::$instance = $instance;
+               $services = MediaWikiServices::getInstance();
+               $services->disableService( 'RepoGroup' );
+               $services->redefineService( 'RepoGroup',
+                       function () use ( $instance ) {
+                               return $instance;
+                       }
+               );
        }
 
        /**
-        * Construct a group of file repositories.
+        * Construct a group of file repositories. Do not call this -- use
+        * MediaWikiServices::getRepoGroup.
         *
         * @param array $localInfo Associative array for local repo's info
         * @param array $foreignInfo Array of repository info arrays.
         *   Each info array is an associative array with the 'class' member
         *   giving the class name. The entire array is passed to the repository
         *   constructor as the first parameter.
+        * @param WANObjectCache $wanCache
         */
-       function __construct( $localInfo, $foreignInfo ) {
+       function __construct( $localInfo, $foreignInfo, $wanCache ) {
                $this->localInfo = $localInfo;
                $this->foreignInfo = $foreignInfo;
                $this->cache = new MapCacheLRU( self::MAX_CACHE_SIZE );
+               $this->wanCache = $wanCache;
        }
 
        /**
         * Search repositories for an image.
-        * You can also use wfFindFile() to do this.
         *
         * @param Title|string $title Title object or string
         * @param array $options Associative array of options:
@@ -419,8 +416,7 @@ class RepoGroup {
        protected function newRepo( $info ) {
                $class = $info['class'];
 
-               $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
-               $info['wanCache'] = $cache;
+               $info['wanCache'] = $this->wanCache;
 
                return new $class( $info );
        }
index c3b5199..92be7d4 100644 (file)
@@ -29,6 +29,7 @@ use MediaWiki\MediaWikiServices;
  * @ingroup FileAbstraction
  */
 
+// @phan-file-suppress PhanTypeMissingReturn false positives
 /**
  * Implements some public methods and some protected utility functions which
  * are required by multiple child classes. Contains stub functionality for
@@ -633,20 +634,15 @@ abstract class File implements IDBAccessObject {
                        // one would not expect it to be animated
                        // so true.
                        return true;
-               } else {
-                       if ( $this->allowInlineDisplay()
-                               && $handler->isAnimatedImage( $this )
-                               && !$handler->canAnimateThumbnail( $this )
-                       ) {
-                               // Image is animated, but thumbnail isn't.
-                               // This is unexpected to the user.
-                               return false;
-                       } else {
-                               // Image is not animated, so one would
-                               // not expect thumb to be
-                               return true;
-                       }
                }
+
+               return !$this->allowInlineDisplay()
+                       // Image is not animated, so one would
+                       // not expect thumb to be
+                       || !$handler->isAnimatedImage( $this )
+                       // Image is animated, but thumbnail isn't.
+                       // This is unexpected to the user.
+                       || $handler->canAnimateThumbnail( $this );
        }
 
        /**
@@ -2074,7 +2070,8 @@ abstract class File implements IDBAccessObject {
                                $this->repo->descriptionCacheExpiry ?: $cache::TTL_UNCACHEABLE,
                                function ( $oldValue, &$ttl, array &$setOpts ) use ( $renderUrl, $fname ) {
                                        wfDebug( "Fetching shared description from $renderUrl\n" );
-                                       $res = Http::get( $renderUrl, [], $fname );
+                                       $res = MediaWikiServices::getInstance()->getHttpRequestFactory()->
+                                               get( $renderUrl, [], $fname );
                                        if ( !$res ) {
                                                $ttl = WANObjectCache::TTL_UNCACHEABLE;
                                        }
index c49810c..ab8ef2f 100644 (file)
@@ -154,7 +154,7 @@ class ForeignAPIFile extends File {
 
        /**
         * @param int $page
-        * @return int|number
+        * @return int
         */
        public function getWidth( $page = 1 ) {
                return isset( $this->mInfo['width'] ) ? intval( $this->mInfo['width'] ) : 0;
@@ -184,11 +184,7 @@ class ForeignAPIFile extends File {
         *   null on error
         */
        public function getExtendedMetadata() {
-               if ( isset( $this->mInfo['extmetadata'] ) ) {
-                       return $this->mInfo['extmetadata'];
-               }
-
-               return null;
+               return $this->mInfo['extmetadata'] ?? null;
        }
 
        /**
index 1869967..e083a4e 100644 (file)
@@ -24,6 +24,7 @@
 use MediaWiki\MediaWikiServices;
 use Wikimedia\Rdbms\DBUnexpectedError;
 
+// @phan-file-suppress PhanTypeMissingReturn false positives
 /**
  * Foreign file with an accessible MediaWiki database
  *
@@ -164,7 +165,8 @@ class ForeignDBFile extends LocalFile {
                        $this->repo->descriptionCacheExpiry ?: $cache::TTL_UNCACHEABLE,
                        function ( $oldValue, &$ttl, array &$setOpts ) use ( $renderUrl, $fname ) {
                                wfDebug( "Fetching shared description from $renderUrl\n" );
-                               $res = Http::get( $renderUrl, [], $fname );
+                               $res = MediaWikiServices::getInstance()->getHttpRequestFactory()->
+                                       get( $renderUrl, [], $fname );
                                if ( !$res ) {
                                        $ttl = WANObjectCache::TTL_UNCACHEABLE;
                                }
index a3d1624..86b8bbb 100644 (file)
@@ -634,7 +634,6 @@ class LocalFile extends File {
                }
 
                $this->fileExists = true;
-               $this->maybeUpgradeRow();
        }
 
        /**
@@ -659,7 +658,7 @@ class LocalFile extends File {
        /**
         * Upgrade a row if it needs it
         */
-       function maybeUpgradeRow() {
+       protected function maybeUpgradeRow() {
                global $wgUpdateCompatibleMetadata;
 
                if ( wfReadOnly() || $this->upgrading ) {
@@ -797,11 +796,14 @@ class LocalFile extends File {
        /** isVisible inherited */
 
        /**
+        * Checks if this file exists in its parent repo, as referenced by its
+        * virtual URL.
+        *
         * @return bool
         */
        function isMissing() {
                if ( $this->missing === null ) {
-                       list( $fileExists ) = $this->repo->fileExists( $this->getVirtualUrl() );
+                       $fileExists = $this->repo->fileExists( $this->getVirtualUrl() );
                        $this->missing = !$fileExists;
                }
 
@@ -1028,6 +1030,7 @@ class LocalFile extends File {
         */
        function purgeCache( $options = [] ) {
                // Refresh metadata cache
+               $this->maybeUpgradeRow();
                $this->purgeMetadataCache();
 
                // Delete thumbnails
@@ -1838,8 +1841,13 @@ class LocalFile extends File {
 
                $this->lock();
 
-               $archiveName = wfTimestamp( TS_MW ) . '!' . $this->getName();
-               $archiveRel = $this->getArchiveRel( $archiveName );
+               if ( $this->isOld() ) {
+                       $archiveRel = $dstRel;
+                       $archiveName = basename( $archiveRel );
+               } else {
+                       $archiveName = wfTimestamp( TS_MW ) . '!' . $this->getName();
+                       $archiveRel = $this->getArchiveRel( $archiveName );
+               }
 
                if ( $repo->hasSha1Storage() ) {
                        $sha1 = FileRepo::isVirtualUrl( $srcPath )
@@ -2287,1148 +2295,4 @@ class LocalFile extends File {
        function __destruct() {
                $this->unlock();
        }
-} // LocalFile class
-
-# ------------------------------------------------------------------------------
-
-/**
- * Helper class for file deletion
- * @ingroup FileAbstraction
- */
-class LocalFileDeleteBatch {
-       /** @var LocalFile */
-       private $file;
-
-       /** @var string */
-       private $reason;
-
-       /** @var array */
-       private $srcRels = [];
-
-       /** @var array */
-       private $archiveUrls = [];
-
-       /** @var array Items to be processed in the deletion batch */
-       private $deletionBatch;
-
-       /** @var bool Whether to suppress all suppressable fields when deleting */
-       private $suppress;
-
-       /** @var Status */
-       private $status;
-
-       /** @var User */
-       private $user;
-
-       /**
-        * @param File $file
-        * @param string $reason
-        * @param bool $suppress
-        * @param User|null $user
-        */
-       function __construct( File $file, $reason = '', $suppress = false, $user = null ) {
-               $this->file = $file;
-               $this->reason = $reason;
-               $this->suppress = $suppress;
-               if ( $user ) {
-                       $this->user = $user;
-               } else {
-                       global $wgUser;
-                       $this->user = $wgUser;
-               }
-               $this->status = $file->repo->newGood();
-       }
-
-       public function addCurrent() {
-               $this->srcRels['.'] = $this->file->getRel();
-       }
-
-       /**
-        * @param string $oldName
-        */
-       public function addOld( $oldName ) {
-               $this->srcRels[$oldName] = $this->file->getArchiveRel( $oldName );
-               $this->archiveUrls[] = $this->file->getArchiveUrl( $oldName );
-       }
-
-       /**
-        * Add the old versions of the image to the batch
-        * @return string[] List of archive names from old versions
-        */
-       public function addOlds() {
-               $archiveNames = [];
-
-               $dbw = $this->file->repo->getMasterDB();
-               $result = $dbw->select( 'oldimage',
-                       [ 'oi_archive_name' ],
-                       [ 'oi_name' => $this->file->getName() ],
-                       __METHOD__
-               );
-
-               foreach ( $result as $row ) {
-                       $this->addOld( $row->oi_archive_name );
-                       $archiveNames[] = $row->oi_archive_name;
-               }
-
-               return $archiveNames;
-       }
-
-       /**
-        * @return array
-        */
-       protected function getOldRels() {
-               if ( !isset( $this->srcRels['.'] ) ) {
-                       $oldRels =& $this->srcRels;
-                       $deleteCurrent = false;
-               } else {
-                       $oldRels = $this->srcRels;
-                       unset( $oldRels['.'] );
-                       $deleteCurrent = true;
-               }
-
-               return [ $oldRels, $deleteCurrent ];
-       }
-
-       /**
-        * @return array
-        */
-       protected function getHashes() {
-               $hashes = [];
-               list( $oldRels, $deleteCurrent ) = $this->getOldRels();
-
-               if ( $deleteCurrent ) {
-                       $hashes['.'] = $this->file->getSha1();
-               }
-
-               if ( count( $oldRels ) ) {
-                       $dbw = $this->file->repo->getMasterDB();
-                       $res = $dbw->select(
-                               'oldimage',
-                               [ 'oi_archive_name', 'oi_sha1' ],
-                               [ 'oi_archive_name' => array_keys( $oldRels ),
-                                       'oi_name' => $this->file->getName() ], // performance
-                               __METHOD__
-                       );
-
-                       foreach ( $res as $row ) {
-                               if ( rtrim( $row->oi_sha1, "\0" ) === '' ) {
-                                       // Get the hash from the file
-                                       $oldUrl = $this->file->getArchiveVirtualUrl( $row->oi_archive_name );
-                                       $props = $this->file->repo->getFileProps( $oldUrl );
-
-                                       if ( $props['fileExists'] ) {
-                                               // Upgrade the oldimage row
-                                               $dbw->update( 'oldimage',
-                                                       [ 'oi_sha1' => $props['sha1'] ],
-                                                       [ 'oi_name' => $this->file->getName(), 'oi_archive_name' => $row->oi_archive_name ],
-                                                       __METHOD__ );
-                                               $hashes[$row->oi_archive_name] = $props['sha1'];
-                                       } else {
-                                               $hashes[$row->oi_archive_name] = false;
-                                       }
-                               } else {
-                                       $hashes[$row->oi_archive_name] = $row->oi_sha1;
-                               }
-                       }
-               }
-
-               $missing = array_diff_key( $this->srcRels, $hashes );
-
-               foreach ( $missing as $name => $rel ) {
-                       $this->status->error( 'filedelete-old-unregistered', $name );
-               }
-
-               foreach ( $hashes as $name => $hash ) {
-                       if ( !$hash ) {
-                               $this->status->error( 'filedelete-missing', $this->srcRels[$name] );
-                               unset( $hashes[$name] );
-                       }
-               }
-
-               return $hashes;
-       }
-
-       protected function doDBInserts() {
-               global $wgActorTableSchemaMigrationStage;
-
-               $now = time();
-               $dbw = $this->file->repo->getMasterDB();
-
-               $commentStore = MediaWikiServices::getInstance()->getCommentStore();
-               $actorMigration = ActorMigration::newMigration();
-
-               $encTimestamp = $dbw->addQuotes( $dbw->timestamp( $now ) );
-               $encUserId = $dbw->addQuotes( $this->user->getId() );
-               $encGroup = $dbw->addQuotes( 'deleted' );
-               $ext = $this->file->getExtension();
-               $dotExt = $ext === '' ? '' : ".$ext";
-               $encExt = $dbw->addQuotes( $dotExt );
-               list( $oldRels, $deleteCurrent ) = $this->getOldRels();
-
-               // Bitfields to further suppress the content
-               if ( $this->suppress ) {
-                       $bitfield = Revision::SUPPRESSED_ALL;
-               } else {
-                       $bitfield = 'oi_deleted';
-               }
-
-               if ( $deleteCurrent ) {
-                       $tables = [ 'image' ];
-                       $fields = [
-                               'fa_storage_group' => $encGroup,
-                               'fa_storage_key' => $dbw->conditional(
-                                       [ 'img_sha1' => '' ],
-                                       $dbw->addQuotes( '' ),
-                                       $dbw->buildConcat( [ "img_sha1", $encExt ] )
-                               ),
-                               'fa_deleted_user' => $encUserId,
-                               'fa_deleted_timestamp' => $encTimestamp,
-                               'fa_deleted' => $this->suppress ? $bitfield : 0,
-                               'fa_name' => 'img_name',
-                               'fa_archive_name' => 'NULL',
-                               'fa_size' => 'img_size',
-                               'fa_width' => 'img_width',
-                               'fa_height' => 'img_height',
-                               'fa_metadata' => 'img_metadata',
-                               'fa_bits' => 'img_bits',
-                               'fa_media_type' => 'img_media_type',
-                               'fa_major_mime' => 'img_major_mime',
-                               'fa_minor_mime' => 'img_minor_mime',
-                               'fa_description_id' => 'img_description_id',
-                               'fa_timestamp' => 'img_timestamp',
-                               'fa_sha1' => 'img_sha1'
-                       ];
-                       $joins = [];
-
-                       $fields += array_map(
-                               [ $dbw, 'addQuotes' ],
-                               $commentStore->insert( $dbw, 'fa_deleted_reason', $this->reason )
-                       );
-
-                       if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) {
-                               $fields['fa_user'] = 'img_user';
-                               $fields['fa_user_text'] = 'img_user_text';
-                       }
-                       if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) {
-                               $fields['fa_actor'] = 'img_actor';
-                       }
-
-                       if (
-                               ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_BOTH ) === SCHEMA_COMPAT_WRITE_BOTH
-                       ) {
-                               // Upgrade any rows that are still old-style. Otherwise an upgrade
-                               // might be missed if a deletion happens while the migration script
-                               // is running.
-                               $res = $dbw->select(
-                                       [ 'image' ],
-                                       [ 'img_name', 'img_user', 'img_user_text' ],
-                                       [ 'img_name' => $this->file->getName(), 'img_actor' => 0 ],
-                                       __METHOD__
-                               );
-                               foreach ( $res as $row ) {
-                                       $actorId = User::newFromAnyId( $row->img_user, $row->img_user_text, null )->getActorId( $dbw );
-                                       $dbw->update(
-                                               'image',
-                                               [ 'img_actor' => $actorId ],
-                                               [ 'img_name' => $row->img_name, 'img_actor' => 0 ],
-                                               __METHOD__
-                                       );
-                               }
-                       }
-
-                       $dbw->insertSelect( 'filearchive', $tables, $fields,
-                               [ 'img_name' => $this->file->getName() ], __METHOD__, [], [], $joins );
-               }
-
-               if ( count( $oldRels ) ) {
-                       $fileQuery = OldLocalFile::getQueryInfo();
-                       $res = $dbw->select(
-                               $fileQuery['tables'],
-                               $fileQuery['fields'],
-                               [
-                                       'oi_name' => $this->file->getName(),
-                                       'oi_archive_name' => array_keys( $oldRels )
-                               ],
-                               __METHOD__,
-                               [ 'FOR UPDATE' ],
-                               $fileQuery['joins']
-                       );
-                       $rowsInsert = [];
-                       if ( $res->numRows() ) {
-                               $reason = $commentStore->createComment( $dbw, $this->reason );
-                               foreach ( $res as $row ) {
-                                       $comment = $commentStore->getComment( 'oi_description', $row );
-                                       $user = User::newFromAnyId( $row->oi_user, $row->oi_user_text, $row->oi_actor );
-                                       $rowsInsert[] = [
-                                               // Deletion-specific fields
-                                               'fa_storage_group' => 'deleted',
-                                               'fa_storage_key' => ( $row->oi_sha1 === '' )
-                                               ? ''
-                                               : "{$row->oi_sha1}{$dotExt}",
-                                               'fa_deleted_user' => $this->user->getId(),
-                                               'fa_deleted_timestamp' => $dbw->timestamp( $now ),
-                                               // Counterpart fields
-                                               'fa_deleted' => $this->suppress ? $bitfield : $row->oi_deleted,
-                                               'fa_name' => $row->oi_name,
-                                               'fa_archive_name' => $row->oi_archive_name,
-                                               'fa_size' => $row->oi_size,
-                                               'fa_width' => $row->oi_width,
-                                               'fa_height' => $row->oi_height,
-                                               'fa_metadata' => $row->oi_metadata,
-                                               'fa_bits' => $row->oi_bits,
-                                               'fa_media_type' => $row->oi_media_type,
-                                               'fa_major_mime' => $row->oi_major_mime,
-                                               'fa_minor_mime' => $row->oi_minor_mime,
-                                               'fa_timestamp' => $row->oi_timestamp,
-                                               'fa_sha1' => $row->oi_sha1
-                                       ] + $commentStore->insert( $dbw, 'fa_deleted_reason', $reason )
-                                       + $commentStore->insert( $dbw, 'fa_description', $comment )
-                                       + $actorMigration->getInsertValues( $dbw, 'fa_user', $user );
-                               }
-                       }
-
-                       $dbw->insert( 'filearchive', $rowsInsert, __METHOD__ );
-               }
-       }
-
-       function doDBDeletes() {
-               $dbw = $this->file->repo->getMasterDB();
-               list( $oldRels, $deleteCurrent ) = $this->getOldRels();
-
-               if ( count( $oldRels ) ) {
-                       $dbw->delete( 'oldimage',
-                               [
-                                       'oi_name' => $this->file->getName(),
-                                       'oi_archive_name' => array_keys( $oldRels )
-                               ], __METHOD__ );
-               }
-
-               if ( $deleteCurrent ) {
-                       $dbw->delete( 'image', [ 'img_name' => $this->file->getName() ], __METHOD__ );
-               }
-       }
-
-       /**
-        * Run the transaction
-        * @return Status
-        */
-       public function execute() {
-               $repo = $this->file->getRepo();
-               $this->file->lock();
-
-               // Prepare deletion batch
-               $hashes = $this->getHashes();
-               $this->deletionBatch = [];
-               $ext = $this->file->getExtension();
-               $dotExt = $ext === '' ? '' : ".$ext";
-
-               foreach ( $this->srcRels as $name => $srcRel ) {
-                       // Skip files that have no hash (e.g. missing DB record, or sha1 field and file source)
-                       if ( isset( $hashes[$name] ) ) {
-                               $hash = $hashes[$name];
-                               $key = $hash . $dotExt;
-                               $dstRel = $repo->getDeletedHashPath( $key ) . $key;
-                               $this->deletionBatch[$name] = [ $srcRel, $dstRel ];
-                       }
-               }
-
-               if ( !$repo->hasSha1Storage() ) {
-                       // Removes non-existent file from the batch, so we don't get errors.
-                       // This also handles files in the 'deleted' zone deleted via revision deletion.
-                       $checkStatus = $this->removeNonexistentFiles( $this->deletionBatch );
-                       if ( !$checkStatus->isGood() ) {
-                               $this->status->merge( $checkStatus );
-                               return $this->status;
-                       }
-                       $this->deletionBatch = $checkStatus->value;
-
-                       // Execute the file deletion batch
-                       $status = $this->file->repo->deleteBatch( $this->deletionBatch );
-                       if ( !$status->isGood() ) {
-                               $this->status->merge( $status );
-                       }
-               }
-
-               if ( !$this->status->isOK() ) {
-                       // Critical file deletion error; abort
-                       $this->file->unlock();
-
-                       return $this->status;
-               }
-
-               // Copy the image/oldimage rows to filearchive
-               $this->doDBInserts();
-               // Delete image/oldimage rows
-               $this->doDBDeletes();
-
-               // Commit and return
-               $this->file->unlock();
-
-               return $this->status;
-       }
-
-       /**
-        * Removes non-existent files from a deletion batch.
-        * @param array $batch
-        * @return Status
-        */
-       protected function removeNonexistentFiles( $batch ) {
-               $files = $newBatch = [];
-
-               foreach ( $batch as $batchItem ) {
-                       list( $src, ) = $batchItem;
-                       $files[$src] = $this->file->repo->getVirtualUrl( 'public' ) . '/' . rawurlencode( $src );
-               }
-
-               $result = $this->file->repo->fileExistsBatch( $files );
-               if ( in_array( null, $result, true ) ) {
-                       return Status::newFatal( 'backend-fail-internal',
-                               $this->file->repo->getBackend()->getName() );
-               }
-
-               foreach ( $batch as $batchItem ) {
-                       if ( $result[$batchItem[0]] ) {
-                               $newBatch[] = $batchItem;
-                       }
-               }
-
-               return Status::newGood( $newBatch );
-       }
-}
-
-# ------------------------------------------------------------------------------
-
-/**
- * Helper class for file undeletion
- * @ingroup FileAbstraction
- */
-class LocalFileRestoreBatch {
-       /** @var LocalFile */
-       private $file;
-
-       /** @var string[] List of file IDs to restore */
-       private $cleanupBatch;
-
-       /** @var string[] List of file IDs to restore */
-       private $ids;
-
-       /** @var bool Add all revisions of the file */
-       private $all;
-
-       /** @var bool Whether to remove all settings for suppressed fields */
-       private $unsuppress = false;
-
-       /**
-        * @param File $file
-        * @param bool $unsuppress
-        */
-       function __construct( File $file, $unsuppress = false ) {
-               $this->file = $file;
-               $this->cleanupBatch = [];
-               $this->ids = [];
-               $this->unsuppress = $unsuppress;
-       }
-
-       /**
-        * Add a file by ID
-        * @param int $fa_id
-        */
-       public function addId( $fa_id ) {
-               $this->ids[] = $fa_id;
-       }
-
-       /**
-        * Add a whole lot of files by ID
-        * @param int[] $ids
-        */
-       public function addIds( $ids ) {
-               $this->ids = array_merge( $this->ids, $ids );
-       }
-
-       /**
-        * Add all revisions of the file
-        */
-       public function addAll() {
-               $this->all = true;
-       }
-
-       /**
-        * Run the transaction, except the cleanup batch.
-        * The cleanup batch should be run in a separate transaction, because it locks different
-        * rows and there's no need to keep the image row locked while it's acquiring those locks
-        * The caller may have its own transaction open.
-        * So we save the batch and let the caller call cleanup()
-        * @return Status
-        */
-       public function execute() {
-               /** @var Language */
-               global $wgLang;
-
-               $repo = $this->file->getRepo();
-               if ( !$this->all && !$this->ids ) {
-                       // Do nothing
-                       return $repo->newGood();
-               }
-
-               $lockOwnsTrx = $this->file->lock();
-
-               $dbw = $this->file->repo->getMasterDB();
-
-               $commentStore = MediaWikiServices::getInstance()->getCommentStore();
-               $actorMigration = ActorMigration::newMigration();
-
-               $status = $this->file->repo->newGood();
-
-               $exists = (bool)$dbw->selectField( 'image', '1',
-                       [ 'img_name' => $this->file->getName() ],
-                       __METHOD__,
-                       // The lock() should already prevents changes, but this still may need
-                       // to bypass any transaction snapshot. However, if lock() started the
-                       // trx (which it probably did) then snapshot is post-lock and up-to-date.
-                       $lockOwnsTrx ? [] : [ 'LOCK IN SHARE MODE' ]
-               );
-
-               // Fetch all or selected archived revisions for the file,
-               // sorted from the most recent to the oldest.
-               $conditions = [ 'fa_name' => $this->file->getName() ];
-
-               if ( !$this->all ) {
-                       $conditions['fa_id'] = $this->ids;
-               }
-
-               $arFileQuery = ArchivedFile::getQueryInfo();
-               $result = $dbw->select(
-                       $arFileQuery['tables'],
-                       $arFileQuery['fields'],
-                       $conditions,
-                       __METHOD__,
-                       [ 'ORDER BY' => 'fa_timestamp DESC' ],
-                       $arFileQuery['joins']
-               );
-
-               $idsPresent = [];
-               $storeBatch = [];
-               $insertBatch = [];
-               $insertCurrent = false;
-               $deleteIds = [];
-               $first = true;
-               $archiveNames = [];
-
-               foreach ( $result as $row ) {
-                       $idsPresent[] = $row->fa_id;
-
-                       if ( $row->fa_name != $this->file->getName() ) {
-                               $status->error( 'undelete-filename-mismatch', $wgLang->timeanddate( $row->fa_timestamp ) );
-                               $status->failCount++;
-                               continue;
-                       }
-
-                       if ( $row->fa_storage_key == '' ) {
-                               // Revision was missing pre-deletion
-                               $status->error( 'undelete-bad-store-key', $wgLang->timeanddate( $row->fa_timestamp ) );
-                               $status->failCount++;
-                               continue;
-                       }
-
-                       $deletedRel = $repo->getDeletedHashPath( $row->fa_storage_key ) .
-                               $row->fa_storage_key;
-                       $deletedUrl = $repo->getVirtualUrl() . '/deleted/' . $deletedRel;
-
-                       if ( isset( $row->fa_sha1 ) ) {
-                               $sha1 = $row->fa_sha1;
-                       } else {
-                               // old row, populate from key
-                               $sha1 = LocalRepo::getHashFromKey( $row->fa_storage_key );
-                       }
-
-                       # Fix leading zero
-                       if ( strlen( $sha1 ) == 32 && $sha1[0] == '0' ) {
-                               $sha1 = substr( $sha1, 1 );
-                       }
-
-                       if ( is_null( $row->fa_major_mime ) || $row->fa_major_mime == 'unknown'
-                               || is_null( $row->fa_minor_mime ) || $row->fa_minor_mime == 'unknown'
-                               || is_null( $row->fa_media_type ) || $row->fa_media_type == 'UNKNOWN'
-                               || is_null( $row->fa_metadata )
-                       ) {
-                               // Refresh our metadata
-                               // Required for a new current revision; nice for older ones too. :)
-                               $props = RepoGroup::singleton()->getFileProps( $deletedUrl );
-                       } else {
-                               $props = [
-                                       'minor_mime' => $row->fa_minor_mime,
-                                       'major_mime' => $row->fa_major_mime,
-                                       'media_type' => $row->fa_media_type,
-                                       'metadata' => $row->fa_metadata
-                               ];
-                       }
-
-                       $comment = $commentStore->getComment( 'fa_description', $row );
-                       $user = User::newFromAnyId( $row->fa_user, $row->fa_user_text, $row->fa_actor );
-                       if ( $first && !$exists ) {
-                               // This revision will be published as the new current version
-                               $destRel = $this->file->getRel();
-                               $commentFields = $commentStore->insert( $dbw, 'img_description', $comment );
-                               $actorFields = $actorMigration->getInsertValues( $dbw, 'img_user', $user );
-                               $insertCurrent = [
-                                       'img_name' => $row->fa_name,
-                                       'img_size' => $row->fa_size,
-                                       'img_width' => $row->fa_width,
-                                       'img_height' => $row->fa_height,
-                                       'img_metadata' => $props['metadata'],
-                                       'img_bits' => $row->fa_bits,
-                                       'img_media_type' => $props['media_type'],
-                                       'img_major_mime' => $props['major_mime'],
-                                       'img_minor_mime' => $props['minor_mime'],
-                                       'img_timestamp' => $row->fa_timestamp,
-                                       'img_sha1' => $sha1
-                               ] + $commentFields + $actorFields;
-
-                               // The live (current) version cannot be hidden!
-                               if ( !$this->unsuppress && $row->fa_deleted ) {
-                                       $status->fatal( 'undeleterevdel' );
-                                       $this->file->unlock();
-                                       return $status;
-                               }
-                       } else {
-                               $archiveName = $row->fa_archive_name;
-
-                               if ( $archiveName == '' ) {
-                                       // This was originally a current version; we
-                                       // have to devise a new archive name for it.
-                                       // Format is <timestamp of archiving>!<name>
-                                       $timestamp = wfTimestamp( TS_UNIX, $row->fa_deleted_timestamp );
-
-                                       do {
-                                               $archiveName = wfTimestamp( TS_MW, $timestamp ) . '!' . $row->fa_name;
-                                               $timestamp++;
-                                       } while ( isset( $archiveNames[$archiveName] ) );
-                               }
-
-                               $archiveNames[$archiveName] = true;
-                               $destRel = $this->file->getArchiveRel( $archiveName );
-                               $insertBatch[] = [
-                                       'oi_name' => $row->fa_name,
-                                       'oi_archive_name' => $archiveName,
-                                       'oi_size' => $row->fa_size,
-                                       'oi_width' => $row->fa_width,
-                                       'oi_height' => $row->fa_height,
-                                       'oi_bits' => $row->fa_bits,
-                                       'oi_timestamp' => $row->fa_timestamp,
-                                       'oi_metadata' => $props['metadata'],
-                                       'oi_media_type' => $props['media_type'],
-                                       'oi_major_mime' => $props['major_mime'],
-                                       'oi_minor_mime' => $props['minor_mime'],
-                                       'oi_deleted' => $this->unsuppress ? 0 : $row->fa_deleted,
-                                       'oi_sha1' => $sha1
-                               ] + $commentStore->insert( $dbw, 'oi_description', $comment )
-                               + $actorMigration->getInsertValues( $dbw, 'oi_user', $user );
-                       }
-
-                       $deleteIds[] = $row->fa_id;
-
-                       if ( !$this->unsuppress && $row->fa_deleted & File::DELETED_FILE ) {
-                               // private files can stay where they are
-                               $status->successCount++;
-                       } else {
-                               $storeBatch[] = [ $deletedUrl, 'public', $destRel ];
-                               $this->cleanupBatch[] = $row->fa_storage_key;
-                       }
-
-                       $first = false;
-               }
-
-               unset( $result );
-
-               // Add a warning to the status object for missing IDs
-               $missingIds = array_diff( $this->ids, $idsPresent );
-
-               foreach ( $missingIds as $id ) {
-                       $status->error( 'undelete-missing-filearchive', $id );
-               }
-
-               if ( !$repo->hasSha1Storage() ) {
-                       // Remove missing files from batch, so we don't get errors when undeleting them
-                       $checkStatus = $this->removeNonexistentFiles( $storeBatch );
-                       if ( !$checkStatus->isGood() ) {
-                               $status->merge( $checkStatus );
-                               return $status;
-                       }
-                       $storeBatch = $checkStatus->value;
-
-                       // Run the store batch
-                       // Use the OVERWRITE_SAME flag to smooth over a common error
-                       $storeStatus = $this->file->repo->storeBatch( $storeBatch, FileRepo::OVERWRITE_SAME );
-                       $status->merge( $storeStatus );
-
-                       if ( !$status->isGood() ) {
-                               // Even if some files could be copied, fail entirely as that is the
-                               // easiest thing to do without data loss
-                               $this->cleanupFailedBatch( $storeStatus, $storeBatch );
-                               $status->setOK( false );
-                               $this->file->unlock();
-
-                               return $status;
-                       }
-               }
-
-               // Run the DB updates
-               // Because we have locked the image row, key conflicts should be rare.
-               // If they do occur, we can roll back the transaction at this time with
-               // no data loss, but leaving unregistered files scattered throughout the
-               // public zone.
-               // This is not ideal, which is why it's important to lock the image row.
-               if ( $insertCurrent ) {
-                       $dbw->insert( 'image', $insertCurrent, __METHOD__ );
-               }
-
-               if ( $insertBatch ) {
-                       $dbw->insert( 'oldimage', $insertBatch, __METHOD__ );
-               }
-
-               if ( $deleteIds ) {
-                       $dbw->delete( 'filearchive',
-                               [ 'fa_id' => $deleteIds ],
-                               __METHOD__ );
-               }
-
-               // If store batch is empty (all files are missing), deletion is to be considered successful
-               if ( $status->successCount > 0 || !$storeBatch || $repo->hasSha1Storage() ) {
-                       if ( !$exists ) {
-                               wfDebug( __METHOD__ . " restored {$status->successCount} items, creating a new current\n" );
-
-                               DeferredUpdates::addUpdate( SiteStatsUpdate::factory( [ 'images' => 1 ] ) );
-
-                               $this->file->purgeEverything();
-                       } else {
-                               wfDebug( __METHOD__ . " restored {$status->successCount} as archived versions\n" );
-                               $this->file->purgeDescription();
-                       }
-               }
-
-               $this->file->unlock();
-
-               return $status;
-       }
-
-       /**
-        * Removes non-existent files from a store batch.
-        * @param array $triplets
-        * @return Status
-        */
-       protected function removeNonexistentFiles( $triplets ) {
-               $files = $filteredTriplets = [];
-               foreach ( $triplets as $file ) {
-                       $files[$file[0]] = $file[0];
-               }
-
-               $result = $this->file->repo->fileExistsBatch( $files );
-               if ( in_array( null, $result, true ) ) {
-                       return Status::newFatal( 'backend-fail-internal',
-                               $this->file->repo->getBackend()->getName() );
-               }
-
-               foreach ( $triplets as $file ) {
-                       if ( $result[$file[0]] ) {
-                               $filteredTriplets[] = $file;
-                       }
-               }
-
-               return Status::newGood( $filteredTriplets );
-       }
-
-       /**
-        * Removes non-existent files from a cleanup batch.
-        * @param string[] $batch
-        * @return string[]
-        */
-       protected function removeNonexistentFromCleanup( $batch ) {
-               $files = $newBatch = [];
-               $repo = $this->file->repo;
-
-               foreach ( $batch as $file ) {
-                       $files[$file] = $repo->getVirtualUrl( 'deleted' ) . '/' .
-                               rawurlencode( $repo->getDeletedHashPath( $file ) . $file );
-               }
-
-               $result = $repo->fileExistsBatch( $files );
-
-               foreach ( $batch as $file ) {
-                       if ( $result[$file] ) {
-                               $newBatch[] = $file;
-                       }
-               }
-
-               return $newBatch;
-       }
-
-       /**
-        * Delete unused files in the deleted zone.
-        * This should be called from outside the transaction in which execute() was called.
-        * @return Status
-        */
-       public function cleanup() {
-               if ( !$this->cleanupBatch ) {
-                       return $this->file->repo->newGood();
-               }
-
-               $this->cleanupBatch = $this->removeNonexistentFromCleanup( $this->cleanupBatch );
-
-               $status = $this->file->repo->cleanupDeletedBatch( $this->cleanupBatch );
-
-               return $status;
-       }
-
-       /**
-        * Cleanup a failed batch. The batch was only partially successful, so
-        * rollback by removing all items that were successfully copied.
-        *
-        * @param Status $storeStatus
-        * @param array[] $storeBatch
-        */
-       protected function cleanupFailedBatch( $storeStatus, $storeBatch ) {
-               $cleanupBatch = [];
-
-               foreach ( $storeStatus->success as $i => $success ) {
-                       // Check if this item of the batch was successfully copied
-                       if ( $success ) {
-                               // Item was successfully copied and needs to be removed again
-                               // Extract ($dstZone, $dstRel) from the batch
-                               $cleanupBatch[] = [ $storeBatch[$i][1], $storeBatch[$i][2] ];
-                       }
-               }
-               $this->file->repo->cleanupBatch( $cleanupBatch );
-       }
-}
-
-# ------------------------------------------------------------------------------
-
-/**
- * Helper class for file movement
- * @ingroup FileAbstraction
- */
-class LocalFileMoveBatch {
-       /** @var LocalFile */
-       protected $file;
-
-       /** @var Title */
-       protected $target;
-
-       protected $cur;
-
-       protected $olds;
-
-       protected $oldCount;
-
-       protected $archive;
-
-       /** @var IDatabase */
-       protected $db;
-
-       /**
-        * @param File $file
-        * @param Title $target
-        */
-       function __construct( File $file, Title $target ) {
-               $this->file = $file;
-               $this->target = $target;
-               $this->oldHash = $this->file->repo->getHashPath( $this->file->getName() );
-               $this->newHash = $this->file->repo->getHashPath( $this->target->getDBkey() );
-               $this->oldName = $this->file->getName();
-               $this->newName = $this->file->repo->getNameFromTitle( $this->target );
-               $this->oldRel = $this->oldHash . $this->oldName;
-               $this->newRel = $this->newHash . $this->newName;
-               $this->db = $file->getRepo()->getMasterDB();
-       }
-
-       /**
-        * Add the current image to the batch
-        */
-       public function addCurrent() {
-               $this->cur = [ $this->oldRel, $this->newRel ];
-       }
-
-       /**
-        * Add the old versions of the image to the batch
-        * @return string[] List of archive names from old versions
-        */
-       public function addOlds() {
-               $archiveBase = 'archive';
-               $this->olds = [];
-               $this->oldCount = 0;
-               $archiveNames = [];
-
-               $result = $this->db->select( 'oldimage',
-                       [ 'oi_archive_name', 'oi_deleted' ],
-                       [ 'oi_name' => $this->oldName ],
-                       __METHOD__,
-                       [ 'LOCK IN SHARE MODE' ] // ignore snapshot
-               );
-
-               foreach ( $result as $row ) {
-                       $archiveNames[] = $row->oi_archive_name;
-                       $oldName = $row->oi_archive_name;
-                       $bits = explode( '!', $oldName, 2 );
-
-                       if ( count( $bits ) != 2 ) {
-                               wfDebug( "Old file name missing !: '$oldName' \n" );
-                               continue;
-                       }
-
-                       list( $timestamp, $filename ) = $bits;
-
-                       if ( $this->oldName != $filename ) {
-                               wfDebug( "Old file name doesn't match: '$oldName' \n" );
-                               continue;
-                       }
-
-                       $this->oldCount++;
-
-                       // Do we want to add those to oldCount?
-                       if ( $row->oi_deleted & File::DELETED_FILE ) {
-                               continue;
-                       }
-
-                       $this->olds[] = [
-                               "{$archiveBase}/{$this->oldHash}{$oldName}",
-                               "{$archiveBase}/{$this->newHash}{$timestamp}!{$this->newName}"
-                       ];
-               }
-
-               return $archiveNames;
-       }
-
-       /**
-        * Perform the move.
-        * @return Status
-        */
-       public function execute() {
-               $repo = $this->file->repo;
-               $status = $repo->newGood();
-               $destFile = wfLocalFile( $this->target );
-
-               $this->file->lock();
-               $destFile->lock(); // quickly fail if destination is not available
-
-               $triplets = $this->getMoveTriplets();
-               $checkStatus = $this->removeNonexistentFiles( $triplets );
-               if ( !$checkStatus->isGood() ) {
-                       $destFile->unlock();
-                       $this->file->unlock();
-                       $status->merge( $checkStatus ); // couldn't talk to file backend
-                       return $status;
-               }
-               $triplets = $checkStatus->value;
-
-               // Verify the file versions metadata in the DB.
-               $statusDb = $this->verifyDBUpdates();
-               if ( !$statusDb->isGood() ) {
-                       $destFile->unlock();
-                       $this->file->unlock();
-                       $statusDb->setOK( false );
-
-                       return $statusDb;
-               }
-
-               if ( !$repo->hasSha1Storage() ) {
-                       // Copy the files into their new location.
-                       // If a prior process fataled copying or cleaning up files we tolerate any
-                       // of the existing files if they are identical to the ones being stored.
-                       $statusMove = $repo->storeBatch( $triplets, FileRepo::OVERWRITE_SAME );
-                       wfDebugLog( 'imagemove', "Moved files for {$this->file->getName()}: " .
-                               "{$statusMove->successCount} successes, {$statusMove->failCount} failures" );
-                       if ( !$statusMove->isGood() ) {
-                               // Delete any files copied over (while the destination is still locked)
-                               $this->cleanupTarget( $triplets );
-                               $destFile->unlock();
-                               $this->file->unlock();
-                               wfDebugLog( 'imagemove', "Error in moving files: "
-                                       . $statusMove->getWikiText( false, false, 'en' ) );
-                               $statusMove->setOK( false );
-
-                               return $statusMove;
-                       }
-                       $status->merge( $statusMove );
-               }
-
-               // Rename the file versions metadata in the DB.
-               $this->doDBUpdates();
-
-               wfDebugLog( 'imagemove', "Renamed {$this->file->getName()} in database: " .
-                       "{$statusDb->successCount} successes, {$statusDb->failCount} failures" );
-
-               $destFile->unlock();
-               $this->file->unlock();
-
-               // Everything went ok, remove the source files
-               $this->cleanupSource( $triplets );
-
-               $status->merge( $statusDb );
-
-               return $status;
-       }
-
-       /**
-        * Verify the database updates and return a new Status indicating how
-        * many rows would be updated.
-        *
-        * @return Status
-        */
-       protected function verifyDBUpdates() {
-               $repo = $this->file->repo;
-               $status = $repo->newGood();
-               $dbw = $this->db;
-
-               $hasCurrent = $dbw->lockForUpdate(
-                       'image',
-                       [ 'img_name' => $this->oldName ],
-                       __METHOD__
-               );
-               $oldRowCount = $dbw->lockForUpdate(
-                       'oldimage',
-                       [ 'oi_name' => $this->oldName ],
-                       __METHOD__
-               );
-
-               if ( $hasCurrent ) {
-                       $status->successCount++;
-               } else {
-                       $status->failCount++;
-               }
-               $status->successCount += $oldRowCount;
-               // T36934: oldCount is based on files that actually exist.
-               // There may be more DB rows than such files, in which case $affected
-               // can be greater than $total. We use max() to avoid negatives here.
-               $status->failCount += max( 0, $this->oldCount - $oldRowCount );
-               if ( $status->failCount ) {
-                       $status->error( 'imageinvalidfilename' );
-               }
-
-               return $status;
-       }
-
-       /**
-        * Do the database updates and return a new Status indicating how
-        * many rows where updated.
-        */
-       protected function doDBUpdates() {
-               $dbw = $this->db;
-
-               // Update current image
-               $dbw->update(
-                       'image',
-                       [ 'img_name' => $this->newName ],
-                       [ 'img_name' => $this->oldName ],
-                       __METHOD__
-               );
-
-               // Update old images
-               $dbw->update(
-                       'oldimage',
-                       [
-                               'oi_name' => $this->newName,
-                               'oi_archive_name = ' . $dbw->strreplace( 'oi_archive_name',
-                                       $dbw->addQuotes( $this->oldName ), $dbw->addQuotes( $this->newName ) ),
-                       ],
-                       [ 'oi_name' => $this->oldName ],
-                       __METHOD__
-               );
-       }
-
-       /**
-        * Generate triplets for FileRepo::storeBatch().
-        * @return array[]
-        */
-       protected function getMoveTriplets() {
-               $moves = array_merge( [ $this->cur ], $this->olds );
-               $triplets = []; // The format is: (srcUrl, destZone, destUrl)
-
-               foreach ( $moves as $move ) {
-                       // $move: (oldRelativePath, newRelativePath)
-                       $srcUrl = $this->file->repo->getVirtualUrl() . '/public/' . rawurlencode( $move[0] );
-                       $triplets[] = [ $srcUrl, 'public', $move[1] ];
-                       wfDebugLog(
-                               'imagemove',
-                               "Generated move triplet for {$this->file->getName()}: {$srcUrl} :: public :: {$move[1]}"
-                       );
-               }
-
-               return $triplets;
-       }
-
-       /**
-        * Removes non-existent files from move batch.
-        * @param array $triplets
-        * @return Status
-        */
-       protected function removeNonexistentFiles( $triplets ) {
-               $files = [];
-
-               foreach ( $triplets as $file ) {
-                       $files[$file[0]] = $file[0];
-               }
-
-               $result = $this->file->repo->fileExistsBatch( $files );
-               if ( in_array( null, $result, true ) ) {
-                       return Status::newFatal( 'backend-fail-internal',
-                               $this->file->repo->getBackend()->getName() );
-               }
-
-               $filteredTriplets = [];
-               foreach ( $triplets as $file ) {
-                       if ( $result[$file[0]] ) {
-                               $filteredTriplets[] = $file;
-                       } else {
-                               wfDebugLog( 'imagemove', "File {$file[0]} does not exist" );
-                       }
-               }
-
-               return Status::newGood( $filteredTriplets );
-       }
-
-       /**
-        * Cleanup a partially moved array of triplets by deleting the target
-        * files. Called if something went wrong half way.
-        * @param array[] $triplets
-        */
-       protected function cleanupTarget( $triplets ) {
-               // Create dest pairs from the triplets
-               $pairs = [];
-               foreach ( $triplets as $triplet ) {
-                       // $triplet: (old source virtual URL, dst zone, dest rel)
-                       $pairs[] = [ $triplet[1], $triplet[2] ];
-               }
-
-               $this->file->repo->cleanupBatch( $pairs );
-       }
-
-       /**
-        * Cleanup a fully moved array of triplets by deleting the source files.
-        * Called at the end of the move process if everything else went ok.
-        * @param array[] $triplets
-        */
-       protected function cleanupSource( $triplets ) {
-               // Create source file names from the triplets
-               $files = [];
-               foreach ( $triplets as $triplet ) {
-                       $files[] = $triplet[0];
-               }
-
-               $this->file->repo->cleanupBatch( $files );
-       }
-}
-
-class LocalFileLockError extends ErrorPageError {
-       public function __construct( Status $status ) {
-               parent::__construct(
-                       'actionfailed',
-                       $status->getMessage()
-               );
-       }
-
-       public function report() {
-               global $wgOut;
-               $wgOut->setStatusCode( 429 );
-               parent::report();
-       }
 }
diff --git a/includes/filerepo/file/LocalFileDeleteBatch.php b/includes/filerepo/file/LocalFileDeleteBatch.php
new file mode 100644 (file)
index 0000000..d447945
--- /dev/null
@@ -0,0 +1,425 @@
+<?php
+/**
+ * Local file in the wiki's own database.
+ *
+ * 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 FileAbstraction
+ */
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * Helper class for file deletion
+ * @ingroup FileAbstraction
+ */
+class LocalFileDeleteBatch {
+       /** @var LocalFile */
+       private $file;
+
+       /** @var string */
+       private $reason;
+
+       /** @var array */
+       private $srcRels = [];
+
+       /** @var array */
+       private $archiveUrls = [];
+
+       /** @var array Items to be processed in the deletion batch */
+       private $deletionBatch;
+
+       /** @var bool Whether to suppress all suppressable fields when deleting */
+       private $suppress;
+
+       /** @var Status */
+       private $status;
+
+       /** @var User */
+       private $user;
+
+       /**
+        * @param File $file
+        * @param string $reason
+        * @param bool $suppress
+        * @param User|null $user
+        */
+       function __construct( File $file, $reason = '', $suppress = false, $user = null ) {
+               $this->file = $file;
+               $this->reason = $reason;
+               $this->suppress = $suppress;
+               global $wgUser;
+               $this->user = $user ?: $wgUser;
+               $this->status = $file->repo->newGood();
+       }
+
+       public function addCurrent() {
+               $this->srcRels['.'] = $this->file->getRel();
+       }
+
+       /**
+        * @param string $oldName
+        */
+       public function addOld( $oldName ) {
+               $this->srcRels[$oldName] = $this->file->getArchiveRel( $oldName );
+               $this->archiveUrls[] = $this->file->getArchiveUrl( $oldName );
+       }
+
+       /**
+        * Add the old versions of the image to the batch
+        * @return string[] List of archive names from old versions
+        */
+       public function addOlds() {
+               $archiveNames = [];
+
+               $dbw = $this->file->repo->getMasterDB();
+               $result = $dbw->select( 'oldimage',
+                       [ 'oi_archive_name' ],
+                       [ 'oi_name' => $this->file->getName() ],
+                       __METHOD__
+               );
+
+               foreach ( $result as $row ) {
+                       $this->addOld( $row->oi_archive_name );
+                       $archiveNames[] = $row->oi_archive_name;
+               }
+
+               return $archiveNames;
+       }
+
+       /**
+        * @return array
+        */
+       protected function getOldRels() {
+               if ( !isset( $this->srcRels['.'] ) ) {
+                       $oldRels =& $this->srcRels;
+                       $deleteCurrent = false;
+               } else {
+                       $oldRels = $this->srcRels;
+                       unset( $oldRels['.'] );
+                       $deleteCurrent = true;
+               }
+
+               return [ $oldRels, $deleteCurrent ];
+       }
+
+       /**
+        * @return array
+        */
+       protected function getHashes() {
+               $hashes = [];
+               list( $oldRels, $deleteCurrent ) = $this->getOldRels();
+
+               if ( $deleteCurrent ) {
+                       $hashes['.'] = $this->file->getSha1();
+               }
+
+               if ( count( $oldRels ) ) {
+                       $dbw = $this->file->repo->getMasterDB();
+                       $res = $dbw->select(
+                               'oldimage',
+                               [ 'oi_archive_name', 'oi_sha1' ],
+                               [ 'oi_archive_name' => array_keys( $oldRels ),
+                                       'oi_name' => $this->file->getName() ], // performance
+                               __METHOD__
+                       );
+
+                       foreach ( $res as $row ) {
+                               if ( rtrim( $row->oi_sha1, "\0" ) === '' ) {
+                                       // Get the hash from the file
+                                       $oldUrl = $this->file->getArchiveVirtualUrl( $row->oi_archive_name );
+                                       $props = $this->file->repo->getFileProps( $oldUrl );
+
+                                       if ( $props['fileExists'] ) {
+                                               // Upgrade the oldimage row
+                                               $dbw->update( 'oldimage',
+                                                       [ 'oi_sha1' => $props['sha1'] ],
+                                                       [ 'oi_name' => $this->file->getName(), 'oi_archive_name' => $row->oi_archive_name ],
+                                                       __METHOD__ );
+                                               $hashes[$row->oi_archive_name] = $props['sha1'];
+                                       } else {
+                                               $hashes[$row->oi_archive_name] = false;
+                                       }
+                               } else {
+                                       $hashes[$row->oi_archive_name] = $row->oi_sha1;
+                               }
+                       }
+               }
+
+               $missing = array_diff_key( $this->srcRels, $hashes );
+
+               foreach ( $missing as $name => $rel ) {
+                       $this->status->error( 'filedelete-old-unregistered', $name );
+               }
+
+               foreach ( $hashes as $name => $hash ) {
+                       if ( !$hash ) {
+                               $this->status->error( 'filedelete-missing', $this->srcRels[$name] );
+                               unset( $hashes[$name] );
+                       }
+               }
+
+               return $hashes;
+       }
+
+       protected function doDBInserts() {
+               global $wgActorTableSchemaMigrationStage;
+
+               $now = time();
+               $dbw = $this->file->repo->getMasterDB();
+
+               $commentStore = MediaWikiServices::getInstance()->getCommentStore();
+               $actorMigration = ActorMigration::newMigration();
+
+               $encTimestamp = $dbw->addQuotes( $dbw->timestamp( $now ) );
+               $encUserId = $dbw->addQuotes( $this->user->getId() );
+               $encGroup = $dbw->addQuotes( 'deleted' );
+               $ext = $this->file->getExtension();
+               $dotExt = $ext === '' ? '' : ".$ext";
+               $encExt = $dbw->addQuotes( $dotExt );
+               list( $oldRels, $deleteCurrent ) = $this->getOldRels();
+
+               // Bitfields to further suppress the content
+               if ( $this->suppress ) {
+                       $bitfield = Revision::SUPPRESSED_ALL;
+               } else {
+                       $bitfield = 'oi_deleted';
+               }
+
+               if ( $deleteCurrent ) {
+                       $tables = [ 'image' ];
+                       $fields = [
+                               'fa_storage_group' => $encGroup,
+                               'fa_storage_key' => $dbw->conditional(
+                                       [ 'img_sha1' => '' ],
+                                       $dbw->addQuotes( '' ),
+                                       $dbw->buildConcat( [ "img_sha1", $encExt ] )
+                               ),
+                               'fa_deleted_user' => $encUserId,
+                               'fa_deleted_timestamp' => $encTimestamp,
+                               'fa_deleted' => $this->suppress ? $bitfield : 0,
+                               'fa_name' => 'img_name',
+                               'fa_archive_name' => 'NULL',
+                               'fa_size' => 'img_size',
+                               'fa_width' => 'img_width',
+                               'fa_height' => 'img_height',
+                               'fa_metadata' => 'img_metadata',
+                               'fa_bits' => 'img_bits',
+                               'fa_media_type' => 'img_media_type',
+                               'fa_major_mime' => 'img_major_mime',
+                               'fa_minor_mime' => 'img_minor_mime',
+                               'fa_description_id' => 'img_description_id',
+                               'fa_timestamp' => 'img_timestamp',
+                               'fa_sha1' => 'img_sha1'
+                       ];
+                       $joins = [];
+
+                       $fields += array_map(
+                               [ $dbw, 'addQuotes' ],
+                               $commentStore->insert( $dbw, 'fa_deleted_reason', $this->reason )
+                       );
+
+                       if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) {
+                               $fields['fa_user'] = 'img_user';
+                               $fields['fa_user_text'] = 'img_user_text';
+                       }
+                       if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) {
+                               $fields['fa_actor'] = 'img_actor';
+                       }
+
+                       if (
+                               ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_BOTH ) === SCHEMA_COMPAT_WRITE_BOTH
+                       ) {
+                               // Upgrade any rows that are still old-style. Otherwise an upgrade
+                               // might be missed if a deletion happens while the migration script
+                               // is running.
+                               $res = $dbw->select(
+                                       [ 'image' ],
+                                       [ 'img_name', 'img_user', 'img_user_text' ],
+                                       [ 'img_name' => $this->file->getName(), 'img_actor' => 0 ],
+                                       __METHOD__
+                               );
+                               foreach ( $res as $row ) {
+                                       $actorId = User::newFromAnyId( $row->img_user, $row->img_user_text, null )->getActorId( $dbw );
+                                       $dbw->update(
+                                               'image',
+                                               [ 'img_actor' => $actorId ],
+                                               [ 'img_name' => $row->img_name, 'img_actor' => 0 ],
+                                               __METHOD__
+                                       );
+                               }
+                       }
+
+                       $dbw->insertSelect( 'filearchive', $tables, $fields,
+                               [ 'img_name' => $this->file->getName() ], __METHOD__, [], [], $joins );
+               }
+
+               if ( count( $oldRels ) ) {
+                       $fileQuery = OldLocalFile::getQueryInfo();
+                       $res = $dbw->select(
+                               $fileQuery['tables'],
+                               $fileQuery['fields'],
+                               [
+                                       'oi_name' => $this->file->getName(),
+                                       'oi_archive_name' => array_keys( $oldRels )
+                               ],
+                               __METHOD__,
+                               [ 'FOR UPDATE' ],
+                               $fileQuery['joins']
+                       );
+                       $rowsInsert = [];
+                       if ( $res->numRows() ) {
+                               $reason = $commentStore->createComment( $dbw, $this->reason );
+                               foreach ( $res as $row ) {
+                                       $comment = $commentStore->getComment( 'oi_description', $row );
+                                       $user = User::newFromAnyId( $row->oi_user, $row->oi_user_text, $row->oi_actor );
+                                       $rowsInsert[] = [
+                                               // Deletion-specific fields
+                                               'fa_storage_group' => 'deleted',
+                                               'fa_storage_key' => ( $row->oi_sha1 === '' )
+                                               ? ''
+                                               : "{$row->oi_sha1}{$dotExt}",
+                                               'fa_deleted_user' => $this->user->getId(),
+                                               'fa_deleted_timestamp' => $dbw->timestamp( $now ),
+                                               // Counterpart fields
+                                               'fa_deleted' => $this->suppress ? $bitfield : $row->oi_deleted,
+                                               'fa_name' => $row->oi_name,
+                                               'fa_archive_name' => $row->oi_archive_name,
+                                               'fa_size' => $row->oi_size,
+                                               'fa_width' => $row->oi_width,
+                                               'fa_height' => $row->oi_height,
+                                               'fa_metadata' => $row->oi_metadata,
+                                               'fa_bits' => $row->oi_bits,
+                                               'fa_media_type' => $row->oi_media_type,
+                                               'fa_major_mime' => $row->oi_major_mime,
+                                               'fa_minor_mime' => $row->oi_minor_mime,
+                                               'fa_timestamp' => $row->oi_timestamp,
+                                               'fa_sha1' => $row->oi_sha1
+                                       ] + $commentStore->insert( $dbw, 'fa_deleted_reason', $reason )
+                                       + $commentStore->insert( $dbw, 'fa_description', $comment )
+                                       + $actorMigration->getInsertValues( $dbw, 'fa_user', $user );
+                               }
+                       }
+
+                       $dbw->insert( 'filearchive', $rowsInsert, __METHOD__ );
+               }
+       }
+
+       function doDBDeletes() {
+               $dbw = $this->file->repo->getMasterDB();
+               list( $oldRels, $deleteCurrent ) = $this->getOldRels();
+
+               if ( count( $oldRels ) ) {
+                       $dbw->delete( 'oldimage',
+                               [
+                                       'oi_name' => $this->file->getName(),
+                                       'oi_archive_name' => array_keys( $oldRels )
+                               ], __METHOD__ );
+               }
+
+               if ( $deleteCurrent ) {
+                       $dbw->delete( 'image', [ 'img_name' => $this->file->getName() ], __METHOD__ );
+               }
+       }
+
+       /**
+        * Run the transaction
+        * @return Status
+        */
+       public function execute() {
+               $repo = $this->file->getRepo();
+               $this->file->lock();
+
+               // Prepare deletion batch
+               $hashes = $this->getHashes();
+               $this->deletionBatch = [];
+               $ext = $this->file->getExtension();
+               $dotExt = $ext === '' ? '' : ".$ext";
+
+               foreach ( $this->srcRels as $name => $srcRel ) {
+                       // Skip files that have no hash (e.g. missing DB record, or sha1 field and file source)
+                       if ( isset( $hashes[$name] ) ) {
+                               $hash = $hashes[$name];
+                               $key = $hash . $dotExt;
+                               $dstRel = $repo->getDeletedHashPath( $key ) . $key;
+                               $this->deletionBatch[$name] = [ $srcRel, $dstRel ];
+                       }
+               }
+
+               if ( !$repo->hasSha1Storage() ) {
+                       // Removes non-existent file from the batch, so we don't get errors.
+                       // This also handles files in the 'deleted' zone deleted via revision deletion.
+                       $checkStatus = $this->removeNonexistentFiles( $this->deletionBatch );
+                       if ( !$checkStatus->isGood() ) {
+                               $this->status->merge( $checkStatus );
+                               return $this->status;
+                       }
+                       $this->deletionBatch = $checkStatus->value;
+
+                       // Execute the file deletion batch
+                       $status = $this->file->repo->deleteBatch( $this->deletionBatch );
+                       if ( !$status->isGood() ) {
+                               $this->status->merge( $status );
+                       }
+               }
+
+               if ( !$this->status->isOK() ) {
+                       // Critical file deletion error; abort
+                       $this->file->unlock();
+
+                       return $this->status;
+               }
+
+               // Copy the image/oldimage rows to filearchive
+               $this->doDBInserts();
+               // Delete image/oldimage rows
+               $this->doDBDeletes();
+
+               // Commit and return
+               $this->file->unlock();
+
+               return $this->status;
+       }
+
+       /**
+        * Removes non-existent files from a deletion batch.
+        * @param array $batch
+        * @return Status
+        */
+       protected function removeNonexistentFiles( $batch ) {
+               $files = $newBatch = [];
+
+               foreach ( $batch as $batchItem ) {
+                       list( $src, ) = $batchItem;
+                       $files[$src] = $this->file->repo->getVirtualUrl( 'public' ) . '/' . rawurlencode( $src );
+               }
+
+               $result = $this->file->repo->fileExistsBatch( $files );
+               if ( in_array( null, $result, true ) ) {
+                       return Status::newFatal( 'backend-fail-internal',
+                               $this->file->repo->getBackend()->getName() );
+               }
+
+               foreach ( $batch as $batchItem ) {
+                       if ( $result[$batchItem[0]] ) {
+                               $newBatch[] = $batchItem;
+                       }
+               }
+
+               return Status::newGood( $newBatch );
+       }
+}
diff --git a/includes/filerepo/file/LocalFileLockError.php b/includes/filerepo/file/LocalFileLockError.php
new file mode 100644 (file)
index 0000000..7cfc8c2
--- /dev/null
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Local file in the wiki's own database.
+ *
+ * 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 FileAbstraction
+ */
+
+class LocalFileLockError extends ErrorPageError {
+       public function __construct( Status $status ) {
+               parent::__construct(
+                       'actionfailed',
+                       $status->getMessage()
+               );
+       }
+
+       public function report() {
+               global $wgOut;
+               $wgOut->setStatusCode( 429 );
+               parent::report();
+       }
+}
diff --git a/includes/filerepo/file/LocalFileMoveBatch.php b/includes/filerepo/file/LocalFileMoveBatch.php
new file mode 100644 (file)
index 0000000..5594004
--- /dev/null
@@ -0,0 +1,339 @@
+<?php
+/**
+ * Local file in the wiki's own database.
+ *
+ * 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 FileAbstraction
+ */
+
+use Wikimedia\Rdbms\IDatabase;
+
+/**
+ * Helper class for file movement
+ * @ingroup FileAbstraction
+ */
+class LocalFileMoveBatch {
+       /** @var LocalFile */
+       protected $file;
+
+       /** @var Title */
+       protected $target;
+
+       protected $cur;
+
+       protected $olds;
+
+       protected $oldCount;
+
+       protected $archive;
+
+       /** @var IDatabase */
+       protected $db;
+
+       /**
+        * @param File $file
+        * @param Title $target
+        */
+       function __construct( File $file, Title $target ) {
+               $this->file = $file;
+               $this->target = $target;
+               $this->oldHash = $this->file->repo->getHashPath( $this->file->getName() );
+               $this->newHash = $this->file->repo->getHashPath( $this->target->getDBkey() );
+               $this->oldName = $this->file->getName();
+               $this->newName = $this->file->repo->getNameFromTitle( $this->target );
+               $this->oldRel = $this->oldHash . $this->oldName;
+               $this->newRel = $this->newHash . $this->newName;
+               $this->db = $file->getRepo()->getMasterDB();
+       }
+
+       /**
+        * Add the current image to the batch
+        */
+       public function addCurrent() {
+               $this->cur = [ $this->oldRel, $this->newRel ];
+       }
+
+       /**
+        * Add the old versions of the image to the batch
+        * @return string[] List of archive names from old versions
+        */
+       public function addOlds() {
+               $archiveBase = 'archive';
+               $this->olds = [];
+               $this->oldCount = 0;
+               $archiveNames = [];
+
+               $result = $this->db->select( 'oldimage',
+                       [ 'oi_archive_name', 'oi_deleted' ],
+                       [ 'oi_name' => $this->oldName ],
+                       __METHOD__,
+                       [ 'LOCK IN SHARE MODE' ] // ignore snapshot
+               );
+
+               foreach ( $result as $row ) {
+                       $archiveNames[] = $row->oi_archive_name;
+                       $oldName = $row->oi_archive_name;
+                       $bits = explode( '!', $oldName, 2 );
+
+                       if ( count( $bits ) != 2 ) {
+                               wfDebug( "Old file name missing !: '$oldName' \n" );
+                               continue;
+                       }
+
+                       list( $timestamp, $filename ) = $bits;
+
+                       if ( $this->oldName != $filename ) {
+                               wfDebug( "Old file name doesn't match: '$oldName' \n" );
+                               continue;
+                       }
+
+                       $this->oldCount++;
+
+                       // Do we want to add those to oldCount?
+                       if ( $row->oi_deleted & File::DELETED_FILE ) {
+                               continue;
+                       }
+
+                       $this->olds[] = [
+                               "{$archiveBase}/{$this->oldHash}{$oldName}",
+                               "{$archiveBase}/{$this->newHash}{$timestamp}!{$this->newName}"
+                       ];
+               }
+
+               return $archiveNames;
+       }
+
+       /**
+        * Perform the move.
+        * @return Status
+        */
+       public function execute() {
+               $repo = $this->file->repo;
+               $status = $repo->newGood();
+               $destFile = wfLocalFile( $this->target );
+
+               $this->file->lock();
+               $destFile->lock(); // quickly fail if destination is not available
+
+               $triplets = $this->getMoveTriplets();
+               $checkStatus = $this->removeNonexistentFiles( $triplets );
+               if ( !$checkStatus->isGood() ) {
+                       $destFile->unlock();
+                       $this->file->unlock();
+                       $status->merge( $checkStatus ); // couldn't talk to file backend
+                       return $status;
+               }
+               $triplets = $checkStatus->value;
+
+               // Verify the file versions metadata in the DB.
+               $statusDb = $this->verifyDBUpdates();
+               if ( !$statusDb->isGood() ) {
+                       $destFile->unlock();
+                       $this->file->unlock();
+                       $statusDb->setOK( false );
+
+                       return $statusDb;
+               }
+
+               if ( !$repo->hasSha1Storage() ) {
+                       // Copy the files into their new location.
+                       // If a prior process fataled copying or cleaning up files we tolerate any
+                       // of the existing files if they are identical to the ones being stored.
+                       $statusMove = $repo->storeBatch( $triplets, FileRepo::OVERWRITE_SAME );
+                       wfDebugLog( 'imagemove', "Moved files for {$this->file->getName()}: " .
+                               "{$statusMove->successCount} successes, {$statusMove->failCount} failures" );
+                       if ( !$statusMove->isGood() ) {
+                               // Delete any files copied over (while the destination is still locked)
+                               $this->cleanupTarget( $triplets );
+                               $destFile->unlock();
+                               $this->file->unlock();
+                               wfDebugLog( 'imagemove', "Error in moving files: "
+                                       . $statusMove->getWikiText( false, false, 'en' ) );
+                               $statusMove->setOK( false );
+
+                               return $statusMove;
+                       }
+                       $status->merge( $statusMove );
+               }
+
+               // Rename the file versions metadata in the DB.
+               $this->doDBUpdates();
+
+               wfDebugLog( 'imagemove', "Renamed {$this->file->getName()} in database: " .
+                       "{$statusDb->successCount} successes, {$statusDb->failCount} failures" );
+
+               $destFile->unlock();
+               $this->file->unlock();
+
+               // Everything went ok, remove the source files
+               $this->cleanupSource( $triplets );
+
+               $status->merge( $statusDb );
+
+               return $status;
+       }
+
+       /**
+        * Verify the database updates and return a new Status indicating how
+        * many rows would be updated.
+        *
+        * @return Status
+        */
+       protected function verifyDBUpdates() {
+               $repo = $this->file->repo;
+               $status = $repo->newGood();
+               $dbw = $this->db;
+
+               $hasCurrent = $dbw->lockForUpdate(
+                       'image',
+                       [ 'img_name' => $this->oldName ],
+                       __METHOD__
+               );
+               $oldRowCount = $dbw->lockForUpdate(
+                       'oldimage',
+                       [ 'oi_name' => $this->oldName ],
+                       __METHOD__
+               );
+
+               if ( $hasCurrent ) {
+                       $status->successCount++;
+               } else {
+                       $status->failCount++;
+               }
+               $status->successCount += $oldRowCount;
+               // T36934: oldCount is based on files that actually exist.
+               // There may be more DB rows than such files, in which case $affected
+               // can be greater than $total. We use max() to avoid negatives here.
+               $status->failCount += max( 0, $this->oldCount - $oldRowCount );
+               if ( $status->failCount ) {
+                       $status->error( 'imageinvalidfilename' );
+               }
+
+               return $status;
+       }
+
+       /**
+        * Do the database updates and return a new Status indicating how
+        * many rows where updated.
+        */
+       protected function doDBUpdates() {
+               $dbw = $this->db;
+
+               // Update current image
+               $dbw->update(
+                       'image',
+                       [ 'img_name' => $this->newName ],
+                       [ 'img_name' => $this->oldName ],
+                       __METHOD__
+               );
+
+               // Update old images
+               $dbw->update(
+                       'oldimage',
+                       [
+                               'oi_name' => $this->newName,
+                               'oi_archive_name = ' . $dbw->strreplace( 'oi_archive_name',
+                                       $dbw->addQuotes( $this->oldName ), $dbw->addQuotes( $this->newName ) ),
+                       ],
+                       [ 'oi_name' => $this->oldName ],
+                       __METHOD__
+               );
+       }
+
+       /**
+        * Generate triplets for FileRepo::storeBatch().
+        * @return array[]
+        */
+       protected function getMoveTriplets() {
+               $moves = array_merge( [ $this->cur ], $this->olds );
+               $triplets = []; // The format is: (srcUrl, destZone, destUrl)
+
+               foreach ( $moves as $move ) {
+                       // $move: (oldRelativePath, newRelativePath)
+                       $srcUrl = $this->file->repo->getVirtualUrl() . '/public/' . rawurlencode( $move[0] );
+                       $triplets[] = [ $srcUrl, 'public', $move[1] ];
+                       wfDebugLog(
+                               'imagemove',
+                               "Generated move triplet for {$this->file->getName()}: {$srcUrl} :: public :: {$move[1]}"
+                       );
+               }
+
+               return $triplets;
+       }
+
+       /**
+        * Removes non-existent files from move batch.
+        * @param array $triplets
+        * @return Status
+        */
+       protected function removeNonexistentFiles( $triplets ) {
+               $files = [];
+
+               foreach ( $triplets as $file ) {
+                       $files[$file[0]] = $file[0];
+               }
+
+               $result = $this->file->repo->fileExistsBatch( $files );
+               if ( in_array( null, $result, true ) ) {
+                       return Status::newFatal( 'backend-fail-internal',
+                               $this->file->repo->getBackend()->getName() );
+               }
+
+               $filteredTriplets = [];
+               foreach ( $triplets as $file ) {
+                       if ( $result[$file[0]] ) {
+                               $filteredTriplets[] = $file;
+                       } else {
+                               wfDebugLog( 'imagemove', "File {$file[0]} does not exist" );
+                       }
+               }
+
+               return Status::newGood( $filteredTriplets );
+       }
+
+       /**
+        * Cleanup a partially moved array of triplets by deleting the target
+        * files. Called if something went wrong half way.
+        * @param array[] $triplets
+        */
+       protected function cleanupTarget( $triplets ) {
+               // Create dest pairs from the triplets
+               $pairs = [];
+               foreach ( $triplets as $triplet ) {
+                       // $triplet: (old source virtual URL, dst zone, dest rel)
+                       $pairs[] = [ $triplet[1], $triplet[2] ];
+               }
+
+               $this->file->repo->cleanupBatch( $pairs );
+       }
+
+       /**
+        * Cleanup a fully moved array of triplets by deleting the source files.
+        * Called at the end of the move process if everything else went ok.
+        * @param array[] $triplets
+        */
+       protected function cleanupSource( $triplets ) {
+               // Create source file names from the triplets
+               $files = [];
+               foreach ( $triplets as $triplet ) {
+                       $files[] = $triplet[0];
+               }
+
+               $this->file->repo->cleanupBatch( $files );
+       }
+}
diff --git a/includes/filerepo/file/LocalFileRestoreBatch.php b/includes/filerepo/file/LocalFileRestoreBatch.php
new file mode 100644 (file)
index 0000000..8dedbec
--- /dev/null
@@ -0,0 +1,427 @@
+<?php
+/**
+ * Local file in the wiki's own database.
+ *
+ * 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 FileAbstraction
+ */
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * Helper class for file undeletion
+ * @ingroup FileAbstraction
+ */
+class LocalFileRestoreBatch {
+       /** @var LocalFile */
+       private $file;
+
+       /** @var string[] List of file IDs to restore */
+       private $cleanupBatch;
+
+       /** @var string[] List of file IDs to restore */
+       private $ids;
+
+       /** @var bool Add all revisions of the file */
+       private $all;
+
+       /** @var bool Whether to remove all settings for suppressed fields */
+       private $unsuppress = false;
+
+       /**
+        * @param File $file
+        * @param bool $unsuppress
+        */
+       function __construct( File $file, $unsuppress = false ) {
+               $this->file = $file;
+               $this->cleanupBatch = [];
+               $this->ids = [];
+               $this->unsuppress = $unsuppress;
+       }
+
+       /**
+        * Add a file by ID
+        * @param int $fa_id
+        */
+       public function addId( $fa_id ) {
+               $this->ids[] = $fa_id;
+       }
+
+       /**
+        * Add a whole lot of files by ID
+        * @param int[] $ids
+        */
+       public function addIds( $ids ) {
+               $this->ids = array_merge( $this->ids, $ids );
+       }
+
+       /**
+        * Add all revisions of the file
+        */
+       public function addAll() {
+               $this->all = true;
+       }
+
+       /**
+        * Run the transaction, except the cleanup batch.
+        * The cleanup batch should be run in a separate transaction, because it locks different
+        * rows and there's no need to keep the image row locked while it's acquiring those locks
+        * The caller may have its own transaction open.
+        * So we save the batch and let the caller call cleanup()
+        * @return Status
+        */
+       public function execute() {
+               /** @var Language */
+               global $wgLang;
+
+               $repo = $this->file->getRepo();
+               if ( !$this->all && !$this->ids ) {
+                       // Do nothing
+                       return $repo->newGood();
+               }
+
+               $lockOwnsTrx = $this->file->lock();
+
+               $dbw = $this->file->repo->getMasterDB();
+
+               $commentStore = MediaWikiServices::getInstance()->getCommentStore();
+               $actorMigration = ActorMigration::newMigration();
+
+               $status = $this->file->repo->newGood();
+
+               $exists = (bool)$dbw->selectField( 'image', '1',
+                       [ 'img_name' => $this->file->getName() ],
+                       __METHOD__,
+                       // The lock() should already prevents changes, but this still may need
+                       // to bypass any transaction snapshot. However, if lock() started the
+                       // trx (which it probably did) then snapshot is post-lock and up-to-date.
+                       $lockOwnsTrx ? [] : [ 'LOCK IN SHARE MODE' ]
+               );
+
+               // Fetch all or selected archived revisions for the file,
+               // sorted from the most recent to the oldest.
+               $conditions = [ 'fa_name' => $this->file->getName() ];
+
+               if ( !$this->all ) {
+                       $conditions['fa_id'] = $this->ids;
+               }
+
+               $arFileQuery = ArchivedFile::getQueryInfo();
+               $result = $dbw->select(
+                       $arFileQuery['tables'],
+                       $arFileQuery['fields'],
+                       $conditions,
+                       __METHOD__,
+                       [ 'ORDER BY' => 'fa_timestamp DESC' ],
+                       $arFileQuery['joins']
+               );
+
+               $idsPresent = [];
+               $storeBatch = [];
+               $insertBatch = [];
+               $insertCurrent = false;
+               $deleteIds = [];
+               $first = true;
+               $archiveNames = [];
+
+               foreach ( $result as $row ) {
+                       $idsPresent[] = $row->fa_id;
+
+                       if ( $row->fa_name != $this->file->getName() ) {
+                               $status->error( 'undelete-filename-mismatch', $wgLang->timeanddate( $row->fa_timestamp ) );
+                               $status->failCount++;
+                               continue;
+                       }
+
+                       if ( $row->fa_storage_key == '' ) {
+                               // Revision was missing pre-deletion
+                               $status->error( 'undelete-bad-store-key', $wgLang->timeanddate( $row->fa_timestamp ) );
+                               $status->failCount++;
+                               continue;
+                       }
+
+                       $deletedRel = $repo->getDeletedHashPath( $row->fa_storage_key ) .
+                               $row->fa_storage_key;
+                       $deletedUrl = $repo->getVirtualUrl() . '/deleted/' . $deletedRel;
+
+                       if ( isset( $row->fa_sha1 ) ) {
+                               $sha1 = $row->fa_sha1;
+                       } else {
+                               // old row, populate from key
+                               $sha1 = LocalRepo::getHashFromKey( $row->fa_storage_key );
+                       }
+
+                       # Fix leading zero
+                       if ( strlen( $sha1 ) == 32 && $sha1[0] == '0' ) {
+                               $sha1 = substr( $sha1, 1 );
+                       }
+
+                       if ( is_null( $row->fa_major_mime ) || $row->fa_major_mime == 'unknown'
+                               || is_null( $row->fa_minor_mime ) || $row->fa_minor_mime == 'unknown'
+                               || is_null( $row->fa_media_type ) || $row->fa_media_type == 'UNKNOWN'
+                               || is_null( $row->fa_metadata )
+                       ) {
+                               // Refresh our metadata
+                               // Required for a new current revision; nice for older ones too. :)
+                               $props = RepoGroup::singleton()->getFileProps( $deletedUrl );
+                       } else {
+                               $props = [
+                                       'minor_mime' => $row->fa_minor_mime,
+                                       'major_mime' => $row->fa_major_mime,
+                                       'media_type' => $row->fa_media_type,
+                                       'metadata' => $row->fa_metadata
+                               ];
+                       }
+
+                       $comment = $commentStore->getComment( 'fa_description', $row );
+                       $user = User::newFromAnyId( $row->fa_user, $row->fa_user_text, $row->fa_actor );
+                       if ( $first && !$exists ) {
+                               // This revision will be published as the new current version
+                               $destRel = $this->file->getRel();
+                               $commentFields = $commentStore->insert( $dbw, 'img_description', $comment );
+                               $actorFields = $actorMigration->getInsertValues( $dbw, 'img_user', $user );
+                               $insertCurrent = [
+                                       'img_name' => $row->fa_name,
+                                       'img_size' => $row->fa_size,
+                                       'img_width' => $row->fa_width,
+                                       'img_height' => $row->fa_height,
+                                       'img_metadata' => $props['metadata'],
+                                       'img_bits' => $row->fa_bits,
+                                       'img_media_type' => $props['media_type'],
+                                       'img_major_mime' => $props['major_mime'],
+                                       'img_minor_mime' => $props['minor_mime'],
+                                       'img_timestamp' => $row->fa_timestamp,
+                                       'img_sha1' => $sha1
+                               ] + $commentFields + $actorFields;
+
+                               // The live (current) version cannot be hidden!
+                               if ( !$this->unsuppress && $row->fa_deleted ) {
+                                       $status->fatal( 'undeleterevdel' );
+                                       $this->file->unlock();
+                                       return $status;
+                               }
+                       } else {
+                               $archiveName = $row->fa_archive_name;
+
+                               if ( $archiveName == '' ) {
+                                       // This was originally a current version; we
+                                       // have to devise a new archive name for it.
+                                       // Format is <timestamp of archiving>!<name>
+                                       $timestamp = wfTimestamp( TS_UNIX, $row->fa_deleted_timestamp );
+
+                                       do {
+                                               $archiveName = wfTimestamp( TS_MW, $timestamp ) . '!' . $row->fa_name;
+                                               $timestamp++;
+                                       } while ( isset( $archiveNames[$archiveName] ) );
+                               }
+
+                               $archiveNames[$archiveName] = true;
+                               $destRel = $this->file->getArchiveRel( $archiveName );
+                               $insertBatch[] = [
+                                       'oi_name' => $row->fa_name,
+                                       'oi_archive_name' => $archiveName,
+                                       'oi_size' => $row->fa_size,
+                                       'oi_width' => $row->fa_width,
+                                       'oi_height' => $row->fa_height,
+                                       'oi_bits' => $row->fa_bits,
+                                       'oi_timestamp' => $row->fa_timestamp,
+                                       'oi_metadata' => $props['metadata'],
+                                       'oi_media_type' => $props['media_type'],
+                                       'oi_major_mime' => $props['major_mime'],
+                                       'oi_minor_mime' => $props['minor_mime'],
+                                       'oi_deleted' => $this->unsuppress ? 0 : $row->fa_deleted,
+                                       'oi_sha1' => $sha1
+                               ] + $commentStore->insert( $dbw, 'oi_description', $comment )
+                               + $actorMigration->getInsertValues( $dbw, 'oi_user', $user );
+                       }
+
+                       $deleteIds[] = $row->fa_id;
+
+                       if ( !$this->unsuppress && $row->fa_deleted & File::DELETED_FILE ) {
+                               // private files can stay where they are
+                               $status->successCount++;
+                       } else {
+                               $storeBatch[] = [ $deletedUrl, 'public', $destRel ];
+                               $this->cleanupBatch[] = $row->fa_storage_key;
+                       }
+
+                       $first = false;
+               }
+
+               unset( $result );
+
+               // Add a warning to the status object for missing IDs
+               $missingIds = array_diff( $this->ids, $idsPresent );
+
+               foreach ( $missingIds as $id ) {
+                       $status->error( 'undelete-missing-filearchive', $id );
+               }
+
+               if ( !$repo->hasSha1Storage() ) {
+                       // Remove missing files from batch, so we don't get errors when undeleting them
+                       $checkStatus = $this->removeNonexistentFiles( $storeBatch );
+                       if ( !$checkStatus->isGood() ) {
+                               $status->merge( $checkStatus );
+                               return $status;
+                       }
+                       $storeBatch = $checkStatus->value;
+
+                       // Run the store batch
+                       // Use the OVERWRITE_SAME flag to smooth over a common error
+                       $storeStatus = $this->file->repo->storeBatch( $storeBatch, FileRepo::OVERWRITE_SAME );
+                       $status->merge( $storeStatus );
+
+                       if ( !$status->isGood() ) {
+                               // Even if some files could be copied, fail entirely as that is the
+                               // easiest thing to do without data loss
+                               $this->cleanupFailedBatch( $storeStatus, $storeBatch );
+                               $status->setOK( false );
+                               $this->file->unlock();
+
+                               return $status;
+                       }
+               }
+
+               // Run the DB updates
+               // Because we have locked the image row, key conflicts should be rare.
+               // If they do occur, we can roll back the transaction at this time with
+               // no data loss, but leaving unregistered files scattered throughout the
+               // public zone.
+               // This is not ideal, which is why it's important to lock the image row.
+               if ( $insertCurrent ) {
+                       $dbw->insert( 'image', $insertCurrent, __METHOD__ );
+               }
+
+               if ( $insertBatch ) {
+                       $dbw->insert( 'oldimage', $insertBatch, __METHOD__ );
+               }
+
+               if ( $deleteIds ) {
+                       $dbw->delete( 'filearchive',
+                               [ 'fa_id' => $deleteIds ],
+                               __METHOD__ );
+               }
+
+               // If store batch is empty (all files are missing), deletion is to be considered successful
+               if ( $status->successCount > 0 || !$storeBatch || $repo->hasSha1Storage() ) {
+                       if ( !$exists ) {
+                               wfDebug( __METHOD__ . " restored {$status->successCount} items, creating a new current\n" );
+
+                               DeferredUpdates::addUpdate( SiteStatsUpdate::factory( [ 'images' => 1 ] ) );
+
+                               $this->file->purgeEverything();
+                       } else {
+                               wfDebug( __METHOD__ . " restored {$status->successCount} as archived versions\n" );
+                               $this->file->purgeDescription();
+                       }
+               }
+
+               $this->file->unlock();
+
+               return $status;
+       }
+
+       /**
+        * Removes non-existent files from a store batch.
+        * @param array $triplets
+        * @return Status
+        */
+       protected function removeNonexistentFiles( $triplets ) {
+               $files = $filteredTriplets = [];
+               foreach ( $triplets as $file ) {
+                       $files[$file[0]] = $file[0];
+               }
+
+               $result = $this->file->repo->fileExistsBatch( $files );
+               if ( in_array( null, $result, true ) ) {
+                       return Status::newFatal( 'backend-fail-internal',
+                               $this->file->repo->getBackend()->getName() );
+               }
+
+               foreach ( $triplets as $file ) {
+                       if ( $result[$file[0]] ) {
+                               $filteredTriplets[] = $file;
+                       }
+               }
+
+               return Status::newGood( $filteredTriplets );
+       }
+
+       /**
+        * Removes non-existent files from a cleanup batch.
+        * @param string[] $batch
+        * @return string[]
+        */
+       protected function removeNonexistentFromCleanup( $batch ) {
+               $files = $newBatch = [];
+               $repo = $this->file->repo;
+
+               foreach ( $batch as $file ) {
+                       $files[$file] = $repo->getVirtualUrl( 'deleted' ) . '/' .
+                               rawurlencode( $repo->getDeletedHashPath( $file ) . $file );
+               }
+
+               $result = $repo->fileExistsBatch( $files );
+
+               foreach ( $batch as $file ) {
+                       if ( $result[$file] ) {
+                               $newBatch[] = $file;
+                       }
+               }
+
+               return $newBatch;
+       }
+
+       /**
+        * Delete unused files in the deleted zone.
+        * This should be called from outside the transaction in which execute() was called.
+        * @return Status
+        */
+       public function cleanup() {
+               if ( !$this->cleanupBatch ) {
+                       return $this->file->repo->newGood();
+               }
+
+               $this->cleanupBatch = $this->removeNonexistentFromCleanup( $this->cleanupBatch );
+
+               $status = $this->file->repo->cleanupDeletedBatch( $this->cleanupBatch );
+
+               return $status;
+       }
+
+       /**
+        * Cleanup a failed batch. The batch was only partially successful, so
+        * rollback by removing all items that were successfully copied.
+        *
+        * @param Status $storeStatus
+        * @param array[] $storeBatch
+        */
+       protected function cleanupFailedBatch( $storeStatus, $storeBatch ) {
+               $cleanupBatch = [];
+
+               foreach ( $storeStatus->success as $i => $success ) {
+                       // Check if this item of the batch was successfully copied
+                       if ( $success ) {
+                               // Item was successfully copied and needs to be removed again
+                               // Extract ($dstZone, $dstRel) from the batch
+                               $cleanupBatch[] = [ $storeBatch[$i][1], $storeBatch[$i][2] ];
+                       }
+               }
+               $this->file->repo->cleanupBatch( $cleanupBatch );
+       }
+}
index 23ff304..3cdbfc2 100644 (file)
@@ -418,10 +418,10 @@ class OldLocalFile extends LocalFile {
                $dstRel = $this->getArchiveRel( $archiveName );
                $status = $this->publishTo( $srcPath, $dstRel );
 
-               if ( $status->isGood() ) {
-                       if ( !$this->recordOldUpload( $srcPath, $archiveName, $timestamp, $comment, $user ) ) {
-                               $status->fatal( 'filenotfound', $srcPath );
-                       }
+               if ( $status->isGood() &&
+                       !$this->recordOldUpload( $srcPath, $archiveName, $timestamp, $comment, $user )
+               ) {
+                       $status->fatal( 'filenotfound', $srcPath );
                }
 
                $this->unlock();
diff --git a/includes/gallery/PackedHoverImageGallery.php b/includes/gallery/PackedHoverImageGallery.php
new file mode 100644 (file)
index 0000000..2e1ef7d
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * Same as Packed except different CSS is applied to make the
+ * caption only show up on hover. If a touch screen is detected,
+ * falls back to PackedHoverGallery. Degrades gracefully for
+ * screen readers.
+ */
+class PackedHoverImageGallery extends PackedOverlayImageGallery {
+}
index 0a5a457..4c72f87 100644 (file)
@@ -53,12 +53,3 @@ class PackedOverlayImageGallery extends PackedImageGallery {
                        . "\n\t\t\t</div></div>";
        }
 }
-
-/**
- * Same as Packed except different CSS is applied to make the
- * caption only show up on hover. If a touch screen is detected,
- * falls back to PackedHoverGallery. Degrades gracefully for
- * screen readers.
- */
-class PackedHoverImageGallery extends PackedOverlayImageGallery {
-}
index 5ede631..4d5222c 100644 (file)
@@ -72,11 +72,9 @@ class TraditionalImageGallery extends ImageGalleryBase {
                $lang = $this->getRenderLang();
                # Output each image...
                foreach ( $this->mImages as $pair ) {
+                       // "text" means "caption" here
                        /** @var Title $nt */
-                       $nt = $pair[0];
-                       $text = $pair[1]; # "text" means "caption" here
-                       $alt = $pair[2];
-                       $link = $pair[3];
+                       list( $nt, $text, $alt, $link ) = $pair;
 
                        $descQuery = false;
                        if ( $nt->getNamespace() === NS_FILE ) {
@@ -171,7 +169,8 @@ class TraditionalImageGallery extends ImageGalleryBase {
 
                        // @todo Code is incomplete.
                        // $linkTarget = Title::newFromText( MediaWikiServices::getInstance()->
-                       // getContentLanguage()->getNsText( MWNamespace::getUser() ) . ":{$ut}" );
+                       // getContentLanguage()->getNsText( MediaWikiServices::getInstance()->
+                       // getNamespaceInfo()->getUser() ) . ":{$ut}" );
                        // $ul = Linker::link( $linkTarget, $ut );
 
                        $meta = [];
diff --git a/includes/historyblob/ConcatenatedGzipHistoryBlob.php b/includes/historyblob/ConcatenatedGzipHistoryBlob.php
new file mode 100644 (file)
index 0000000..f6ca2f5
--- /dev/null
@@ -0,0 +1,146 @@
+<?php
+/**
+ * Efficient concatenated text storage.
+ *
+ * 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
+ */
+
+/**
+ * Concatenated gzip (CGZ) storage
+ * Improves compression ratio by concatenating like objects before gzipping
+ */
+class ConcatenatedGzipHistoryBlob implements HistoryBlob {
+       public $mVersion = 0, $mCompressed = false, $mItems = [], $mDefaultHash = '';
+       public $mSize = 0;
+       public $mMaxSize = 10000000;
+       public $mMaxCount = 100;
+
+       public function __construct() {
+               if ( !function_exists( 'gzdeflate' ) ) {
+                       throw new MWException( "Need zlib support to read or write this "
+                               . "kind of history object (ConcatenatedGzipHistoryBlob)\n" );
+               }
+       }
+
+       /**
+        * @param string $text
+        * @return string
+        */
+       public function addItem( $text ) {
+               $this->uncompress();
+               $hash = md5( $text );
+               if ( !isset( $this->mItems[$hash] ) ) {
+                       $this->mItems[$hash] = $text;
+                       $this->mSize += strlen( $text );
+               }
+               return $hash;
+       }
+
+       /**
+        * @param string $hash
+        * @return array|bool
+        */
+       public function getItem( $hash ) {
+               $this->uncompress();
+               if ( array_key_exists( $hash, $this->mItems ) ) {
+                       return $this->mItems[$hash];
+               } else {
+                       return false;
+               }
+       }
+
+       /**
+        * @param string $text
+        * @return void
+        */
+       public function setText( $text ) {
+               $this->uncompress();
+               $this->mDefaultHash = $this->addItem( $text );
+       }
+
+       /**
+        * @return array|bool
+        */
+       public function getText() {
+               $this->uncompress();
+               return $this->getItem( $this->mDefaultHash );
+       }
+
+       /**
+        * Remove an item
+        *
+        * @param string $hash
+        */
+       public function removeItem( $hash ) {
+               $this->mSize -= strlen( $this->mItems[$hash] );
+               unset( $this->mItems[$hash] );
+       }
+
+       /**
+        * Compress the bulk data in the object
+        */
+       public function compress() {
+               if ( !$this->mCompressed ) {
+                       $this->mItems = gzdeflate( serialize( $this->mItems ) );
+                       $this->mCompressed = true;
+               }
+       }
+
+       /**
+        * Uncompress bulk data
+        */
+       public function uncompress() {
+               if ( $this->mCompressed ) {
+                       $this->mItems = unserialize( gzinflate( $this->mItems ) );
+                       $this->mCompressed = false;
+               }
+       }
+
+       /**
+        * @return array
+        */
+       function __sleep() {
+               $this->compress();
+               return [ 'mVersion', 'mCompressed', 'mItems', 'mDefaultHash' ];
+       }
+
+       function __wakeup() {
+               $this->uncompress();
+       }
+
+       /**
+        * Helper function for compression jobs
+        * Returns true until the object is "full" and ready to be committed
+        *
+        * @return bool
+        */
+       public function isHappy() {
+               return $this->mSize < $this->mMaxSize
+                       && count( $this->mItems ) < $this->mMaxCount;
+       }
+}
+
+// phpcs:ignore Generic.CodeAnalysis.UnconditionalIfStatement.Found
+if ( false ) {
+       // Blobs generated by MediaWiki < 1.5 on PHP 4 were serialized with the
+       // class name coerced to lowercase. We can improve efficiency by adding
+       // autoload entries for the lowercase variants of these classes (T166759).
+       // The code below is never executed, but it is picked up by the AutoloadGenerator
+       // parser, which scans for class_alias() calls.
+       class_alias( ConcatenatedGzipHistoryBlob::class, 'concatenatedgziphistoryblob' );
+}
diff --git a/includes/historyblob/DiffHistoryBlob.php b/includes/historyblob/DiffHistoryBlob.php
new file mode 100644 (file)
index 0000000..8d92fe5
--- /dev/null
@@ -0,0 +1,377 @@
+<?php
+/**
+ * Efficient concatenated text storage.
+ *
+ * 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
+ */
+
+/**
+ * Diff-based history compression
+ * Requires xdiff 1.5+ and zlib
+ */
+class DiffHistoryBlob implements HistoryBlob {
+       /** @var array Uncompressed item cache */
+       public $mItems = [];
+
+       /** @var int Total uncompressed size */
+       public $mSize = 0;
+
+       /**
+        * @var array Array of diffs. If a diff D from A to B is notated D = B - A,
+        * and Z is an empty string:
+        *
+        *              { item[map[i]] - item[map[i-1]]   where i > 0
+        *    diff[i] = {
+        *              { item[map[i]] - Z                where i = 0
+        */
+       public $mDiffs;
+
+       /** @var array The diff map, see above */
+       public $mDiffMap;
+
+       /** @var int The key for getText()
+        */
+       public $mDefaultKey;
+
+       /** @var string Compressed storage */
+       public $mCompressed;
+
+       /** @var bool True if the object is locked against further writes */
+       public $mFrozen = false;
+
+       /**
+        * @var int The maximum uncompressed size before the object becomes sad
+        * Should be less than max_allowed_packet
+        */
+       public $mMaxSize = 10000000;
+
+       /** @var int The maximum number of text items before the object becomes sad */
+       public $mMaxCount = 100;
+
+       /** Constants from xdiff.h */
+       const XDL_BDOP_INS = 1;
+       const XDL_BDOP_CPY = 2;
+       const XDL_BDOP_INSB = 3;
+
+       function __construct() {
+               if ( !function_exists( 'gzdeflate' ) ) {
+                       throw new MWException( "Need zlib support to read or write DiffHistoryBlob\n" );
+               }
+       }
+
+       /**
+        * @throws MWException
+        * @param string $text
+        * @return int
+        */
+       function addItem( $text ) {
+               if ( $this->mFrozen ) {
+                       throw new MWException( __METHOD__ . ": Cannot add more items after sleep/wakeup" );
+               }
+
+               $this->mItems[] = $text;
+               $this->mSize += strlen( $text );
+               $this->mDiffs = null; // later
+               return count( $this->mItems ) - 1;
+       }
+
+       /**
+        * @param string $key
+        * @return string
+        */
+       function getItem( $key ) {
+               return $this->mItems[$key];
+       }
+
+       /**
+        * @param string $text
+        */
+       function setText( $text ) {
+               $this->mDefaultKey = $this->addItem( $text );
+       }
+
+       /**
+        * @return string
+        */
+       function getText() {
+               return $this->getItem( $this->mDefaultKey );
+       }
+
+       /**
+        * @throws MWException
+        */
+       function compress() {
+               if ( !function_exists( 'xdiff_string_rabdiff' ) ) {
+                       throw new MWException( "Need xdiff 1.5+ support to write DiffHistoryBlob\n" );
+               }
+               if ( isset( $this->mDiffs ) ) {
+                       // Already compressed
+                       return;
+               }
+               if ( $this->mItems === [] ) {
+                       return;
+               }
+
+               // Create two diff sequences: one for main text and one for small text
+               $sequences = [
+                       'small' => [
+                               'tail' => '',
+                               'diffs' => [],
+                               'map' => [],
+                       ],
+                       'main' => [
+                               'tail' => '',
+                               'diffs' => [],
+                               'map' => [],
+                       ],
+               ];
+               $smallFactor = 0.5;
+
+               $mItemsCount = count( $this->mItems );
+               for ( $i = 0; $i < $mItemsCount; $i++ ) {
+                       $text = $this->mItems[$i];
+                       if ( $i == 0 ) {
+                               $seqName = 'main';
+                       } else {
+                               $mainTail = $sequences['main']['tail'];
+                               if ( strlen( $text ) < strlen( $mainTail ) * $smallFactor ) {
+                                       $seqName = 'small';
+                               } else {
+                                       $seqName = 'main';
+                               }
+                       }
+                       $seq =& $sequences[$seqName];
+                       $tail = $seq['tail'];
+                       $diff = $this->diff( $tail, $text );
+                       $seq['diffs'][] = $diff;
+                       $seq['map'][] = $i;
+                       $seq['tail'] = $text;
+               }
+               unset( $seq ); // unlink dangerous alias
+
+               // Knit the sequences together
+               $tail = '';
+               $this->mDiffs = [];
+               $this->mDiffMap = [];
+               foreach ( $sequences as $seq ) {
+                       if ( $seq['diffs'] === [] ) {
+                               continue;
+                       }
+                       if ( $tail === '' ) {
+                               $this->mDiffs[] = $seq['diffs'][0];
+                       } else {
+                               $head = $this->patch( '', $seq['diffs'][0] );
+                               $this->mDiffs[] = $this->diff( $tail, $head );
+                       }
+                       $this->mDiffMap[] = $seq['map'][0];
+                       $diffsCount = count( $seq['diffs'] );
+                       for ( $i = 1; $i < $diffsCount; $i++ ) {
+                               $this->mDiffs[] = $seq['diffs'][$i];
+                               $this->mDiffMap[] = $seq['map'][$i];
+                       }
+                       $tail = $seq['tail'];
+               }
+       }
+
+       /**
+        * @param string $t1
+        * @param string $t2
+        * @return string
+        */
+       function diff( $t1, $t2 ) {
+               # Need to do a null concatenation with warnings off, due to bugs in the current version of xdiff
+               # "String is not zero-terminated"
+               Wikimedia\suppressWarnings();
+               $diff = xdiff_string_rabdiff( $t1, $t2 ) . '';
+               Wikimedia\restoreWarnings();
+               return $diff;
+       }
+
+       /**
+        * @param string $base
+        * @param string $diff
+        * @return bool|string
+        */
+       function patch( $base, $diff ) {
+               if ( function_exists( 'xdiff_string_bpatch' ) ) {
+                       Wikimedia\suppressWarnings();
+                       $text = xdiff_string_bpatch( $base, $diff ) . '';
+                       Wikimedia\restoreWarnings();
+                       return $text;
+               }
+
+               # Pure PHP implementation
+
+               $header = unpack( 'Vofp/Vcsize', substr( $diff, 0, 8 ) );
+
+               # Check the checksum if hash extension is available
+               $ofp = $this->xdiffAdler32( $base );
+               if ( $ofp !== false && $ofp !== substr( $diff, 0, 4 ) ) {
+                       wfDebug( __METHOD__ . ": incorrect base checksum\n" );
+                       return false;
+               }
+               if ( $header['csize'] != strlen( $base ) ) {
+                       wfDebug( __METHOD__ . ": incorrect base length\n" );
+                       return false;
+               }
+
+               $p = 8;
+               $out = '';
+               while ( $p < strlen( $diff ) ) {
+                       $x = unpack( 'Cop', substr( $diff, $p, 1 ) );
+                       $op = $x['op'];
+                       ++$p;
+                       switch ( $op ) {
+                               case self::XDL_BDOP_INS:
+                                       $x = unpack( 'Csize', substr( $diff, $p, 1 ) );
+                                       $p++;
+                                       $out .= substr( $diff, $p, $x['size'] );
+                                       $p += $x['size'];
+                                       break;
+                               case self::XDL_BDOP_INSB:
+                                       $x = unpack( 'Vcsize', substr( $diff, $p, 4 ) );
+                                       $p += 4;
+                                       $out .= substr( $diff, $p, $x['csize'] );
+                                       $p += $x['csize'];
+                                       break;
+                               case self::XDL_BDOP_CPY:
+                                       $x = unpack( 'Voff/Vcsize', substr( $diff, $p, 8 ) );
+                                       $p += 8;
+                                       $out .= substr( $base, $x['off'], $x['csize'] );
+                                       break;
+                               default:
+                                       wfDebug( __METHOD__ . ": invalid op\n" );
+                                       return false;
+                       }
+               }
+               return $out;
+       }
+
+       /**
+        * Compute a binary "Adler-32" checksum as defined by LibXDiff, i.e. with
+        * the bytes backwards and initialised with 0 instead of 1. See T36428.
+        *
+        * @param string $s
+        * @return string|bool False if the hash extension is not available
+        */
+       function xdiffAdler32( $s ) {
+               if ( !function_exists( 'hash' ) ) {
+                       return false;
+               }
+
+               static $init;
+               if ( $init === null ) {
+                       $init = str_repeat( "\xf0", 205 ) . "\xee" . str_repeat( "\xf0", 67 ) . "\x02";
+               }
+
+               // The real Adler-32 checksum of $init is zero, so it initialises the
+               // state to zero, as it is at the start of LibXDiff's checksum
+               // algorithm. Appending the subject string then simulates LibXDiff.
+               return strrev( hash( 'adler32', $init . $s, true ) );
+       }
+
+       function uncompress() {
+               if ( !$this->mDiffs ) {
+                       return;
+               }
+               $tail = '';
+               $mDiffsCount = count( $this->mDiffs );
+               for ( $diffKey = 0; $diffKey < $mDiffsCount; $diffKey++ ) {
+                       $textKey = $this->mDiffMap[$diffKey];
+                       $text = $this->patch( $tail, $this->mDiffs[$diffKey] );
+                       $this->mItems[$textKey] = $text;
+                       $tail = $text;
+               }
+       }
+
+       /**
+        * @return array
+        */
+       function __sleep() {
+               $this->compress();
+               if ( $this->mItems === [] ) {
+                       $info = false;
+               } else {
+                       // Take forward differences to improve the compression ratio for sequences
+                       $map = '';
+                       $prev = 0;
+                       foreach ( $this->mDiffMap as $i ) {
+                               if ( $map !== '' ) {
+                                       $map .= ',';
+                               }
+                               $map .= $i - $prev;
+                               $prev = $i;
+                       }
+                       $info = [
+                               'diffs' => $this->mDiffs,
+                               'map' => $map
+                       ];
+               }
+               if ( isset( $this->mDefaultKey ) ) {
+                       $info['default'] = $this->mDefaultKey;
+               }
+               $this->mCompressed = gzdeflate( serialize( $info ) );
+               return [ 'mCompressed' ];
+       }
+
+       function __wakeup() {
+               // addItem() doesn't work if mItems is partially filled from mDiffs
+               $this->mFrozen = true;
+               $info = unserialize( gzinflate( $this->mCompressed ) );
+               unset( $this->mCompressed );
+
+               if ( !$info ) {
+                       // Empty object
+                       return;
+               }
+
+               if ( isset( $info['default'] ) ) {
+                       $this->mDefaultKey = $info['default'];
+               }
+               $this->mDiffs = $info['diffs'];
+               if ( isset( $info['base'] ) ) {
+                       // Old format
+                       $this->mDiffMap = range( 0, count( $this->mDiffs ) - 1 );
+                       array_unshift( $this->mDiffs,
+                               pack( 'VVCV', 0, 0, self::XDL_BDOP_INSB, strlen( $info['base'] ) ) .
+                               $info['base'] );
+               } else {
+                       // New format
+                       $map = explode( ',', $info['map'] );
+                       $cur = 0;
+                       $this->mDiffMap = [];
+                       foreach ( $map as $i ) {
+                               $cur += $i;
+                               $this->mDiffMap[] = $cur;
+                       }
+               }
+               $this->uncompress();
+       }
+
+       /**
+        * Helper function for compression jobs
+        * Returns true until the object is "full" and ready to be committed
+        *
+        * @return bool
+        */
+       function isHappy() {
+               return $this->mSize < $this->mMaxSize
+                       && count( $this->mItems ) < $this->mMaxCount;
+       }
+
+}
diff --git a/includes/historyblob/HistoryBlob.php b/includes/historyblob/HistoryBlob.php
new file mode 100644 (file)
index 0000000..36c7c8f
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+/**
+ * Efficient concatenated text storage.
+ *
+ * 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
+ */
+
+/**
+ * Base class for general text storage via the "object" flag in old_flags, or
+ * two-part external storage URLs. Used for represent efficient concatenated
+ * storage, and migration-related pointer objects.
+ */
+interface HistoryBlob {
+       /**
+        * Adds an item of text, returns a stub object which points to the item.
+        * You must call setLocation() on the stub object before storing it to the
+        * database
+        *
+        * @param string $text
+        *
+        * @return string The key for getItem()
+        */
+       function addItem( $text );
+
+       /**
+        * Get item by key, or false if the key is not present
+        *
+        * @param string $key
+        *
+        * @return string|bool
+        */
+       function getItem( $key );
+
+       /**
+        * Set the "default text"
+        * This concept is an odd property of the current DB schema, whereby each text item has a revision
+        * associated with it. The default text is the text of the associated revision. There may, however,
+        * be other revisions in the same object.
+        *
+        * Default text is not required for two-part external storage URLs.
+        *
+        * @param string $text
+        */
+       function setText( $text );
+
+       /**
+        * Get default text. This is called from Revision::getRevisionText()
+        *
+        * @return string
+        */
+       function getText();
+}
diff --git a/includes/historyblob/HistoryBlobCurStub.php b/includes/historyblob/HistoryBlobCurStub.php
new file mode 100644 (file)
index 0000000..8858c8d
--- /dev/null
@@ -0,0 +1,73 @@
+<?php
+/**
+ * Efficient concatenated text storage.
+ *
+ * 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
+ */
+
+/**
+ * To speed up conversion from 1.4 to 1.5 schema, text rows can refer to the
+ * leftover cur table as the backend. This avoids expensively copying hundreds
+ * of megabytes of data during the conversion downtime.
+ *
+ * Serialized HistoryBlobCurStub objects will be inserted into the text table
+ * on conversion if $wgLegacySchemaConversion is set to true.
+ */
+class HistoryBlobCurStub {
+       /** @var int */
+       public $mCurId;
+
+       /**
+        * @param int $curid The cur_id pointed to
+        */
+       function __construct( $curid = 0 ) {
+               $this->mCurId = $curid;
+       }
+
+       /**
+        * Sets the location (cur_id) of the main object to which this object
+        * points
+        *
+        * @param int $id
+        */
+       function setLocation( $id ) {
+               $this->mCurId = $id;
+       }
+
+       /**
+        * @return string|bool
+        */
+       function getText() {
+               $dbr = wfGetDB( DB_REPLICA );
+               $row = $dbr->selectRow( 'cur', [ 'cur_text' ], [ 'cur_id' => $this->mCurId ] );
+               if ( !$row ) {
+                       return false;
+               }
+               return $row->cur_text;
+       }
+}
+
+// phpcs:ignore Generic.CodeAnalysis.UnconditionalIfStatement.Found
+if ( false ) {
+       // Blobs generated by MediaWiki < 1.5 on PHP 4 were serialized with the
+       // class name coerced to lowercase. We can improve efficiency by adding
+       // autoload entries for the lowercase variants of these classes (T166759).
+       // The code below is never executed, but it is picked up by the AutoloadGenerator
+       // parser, which scans for class_alias() calls.
+       class_alias( HistoryBlobCurStub::class, 'historyblobcurstub' );
+}
diff --git a/includes/historyblob/HistoryBlobStub.php b/includes/historyblob/HistoryBlobStub.php
new file mode 100644 (file)
index 0000000..4995d3b
--- /dev/null
@@ -0,0 +1,150 @@
+<?php
+/**
+ * Efficient concatenated text storage.
+ *
+ * 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
+ */
+
+/**
+ * Pointer object for an item within a CGZ blob stored in the text table.
+ */
+class HistoryBlobStub {
+       /**
+        * @var array One-step cache variable to hold base blobs; operations that
+        * pull multiple revisions may often pull multiple times from the same
+        * blob. By keeping the last-used one open, we avoid redundant
+        * unserialization and decompression overhead.
+        */
+       protected static $blobCache = [];
+
+       /** @var int */
+       public $mOldId;
+
+       /** @var string */
+       public $mHash;
+
+       /** @var string */
+       public $mRef;
+
+       /**
+        * @param string $hash The content hash of the text
+        * @param int $oldid The old_id for the CGZ object
+        */
+       function __construct( $hash = '', $oldid = 0 ) {
+               $this->mHash = $hash;
+       }
+
+       /**
+        * Sets the location (old_id) of the main object to which this object
+        * points
+        * @param int $id
+        */
+       function setLocation( $id ) {
+               $this->mOldId = $id;
+       }
+
+       /**
+        * Sets the location (old_id) of the referring object
+        * @param string $id
+        */
+       function setReferrer( $id ) {
+               $this->mRef = $id;
+       }
+
+       /**
+        * Gets the location of the referring object
+        * @return string
+        */
+       function getReferrer() {
+               return $this->mRef;
+       }
+
+       /**
+        * @return string|false
+        */
+       function getText() {
+               if ( isset( self::$blobCache[$this->mOldId] ) ) {
+                       $obj = self::$blobCache[$this->mOldId];
+               } else {
+                       $dbr = wfGetDB( DB_REPLICA );
+                       $row = $dbr->selectRow(
+                               'text',
+                               [ 'old_flags', 'old_text' ],
+                               [ 'old_id' => $this->mOldId ]
+                       );
+
+                       if ( !$row ) {
+                               return false;
+                       }
+
+                       $flags = explode( ',', $row->old_flags );
+                       if ( in_array( 'external', $flags ) ) {
+                               $url = $row->old_text;
+                               $parts = explode( '://', $url, 2 );
+                               if ( !isset( $parts[1] ) || $parts[1] == '' ) {
+                                       return false;
+                               }
+                               $row->old_text = ExternalStore::fetchFromURL( $url );
+
+                       }
+
+                       if ( !in_array( 'object', $flags ) ) {
+                               return false;
+                       }
+
+                       if ( in_array( 'gzip', $flags ) ) {
+                               // This shouldn't happen, but a bug in the compress script
+                               // may at times gzip-compress a HistoryBlob object row.
+                               $obj = unserialize( gzinflate( $row->old_text ) );
+                       } else {
+                               $obj = unserialize( $row->old_text );
+                       }
+
+                       if ( !is_object( $obj ) ) {
+                               // Correct for old double-serialization bug.
+                               $obj = unserialize( $obj );
+                       }
+
+                       // Save this item for reference; if pulling many
+                       // items in a row we'll likely use it again.
+                       $obj->uncompress();
+                       self::$blobCache = [ $this->mOldId => $obj ];
+               }
+
+               return $obj->getItem( $this->mHash );
+       }
+
+       /**
+        * Get the content hash
+        *
+        * @return string
+        */
+       function getHash() {
+               return $this->mHash;
+       }
+}
+
+// phpcs:ignore Generic.CodeAnalysis.UnconditionalIfStatement.Found
+if ( false ) {
+       // Blobs generated by MediaWiki < 1.5 on PHP 4 were serialized with the
+       // class name coerced to lowercase. We can improve efficiency by adding
+       // autoload entries for the lowercase variants of these classes (T166759).
+       // The code below is never executed, but it is picked up by the AutoloadGenerator
+       // parser, which scans for class_alias() calls.
+       class_alias( HistoryBlobStub::class, 'historyblobstub' );
+}
index 82cbb40..f5be83f 100644 (file)
@@ -221,6 +221,20 @@ class HTMLForm extends ContextSource {
         */
        protected $mAction = false;
 
+       /**
+        * Whether the form can be collapsed
+        * @since 1.34
+        * @var bool
+        */
+       protected $mCollapsible = false;
+
+       /**
+        * Whether the form is collapsed by default
+        * @since 1.34
+        * @var bool
+        */
+       protected $mCollapsed = false;
+
        /**
         * Form attribute autocomplete. A typical value is "off". null does not set the attribute
         * @since 1.27
@@ -233,6 +247,7 @@ class HTMLForm extends ContextSource {
        protected $mButtons = [];
 
        protected $mWrapperLegend = false;
+       protected $mWrapperAttributes = [];
 
        /**
         * Salt for the edit token.
@@ -526,7 +541,6 @@ class HTMLForm extends ContextSource {
        public function tryAuthorizedSubmit() {
                $result = false;
 
-               $identOkay = false;
                if ( $this->mFormIdentifier === null ) {
                        $identOkay = true;
                } else {
@@ -605,7 +619,7 @@ class HTMLForm extends ContextSource {
                $valid = true;
                $hoistedErrors = Status::newGood();
                if ( $this->mValidationErrorMessage ) {
-                       foreach ( (array)$this->mValidationErrorMessage as $error ) {
+                       foreach ( $this->mValidationErrorMessage as $error ) {
                                $hoistedErrors->fatal( ...$error );
                        }
                } else {
@@ -700,8 +714,8 @@ class HTMLForm extends ContextSource {
        /**
         * Set a message to display on a validation error.
         *
-        * @param string|array $msg String or Array of valid inputs to wfMessage()
-        *     (so each entry can be either a String or Array)
+        * @param array $msg Array of valid inputs to wfMessage()
+        *     (so each entry must itself be an array of arguments)
         *
         * @return HTMLForm $this for chaining calls (since 1.20)
         */
@@ -1047,6 +1061,19 @@ class HTMLForm extends ContextSource {
                return '' . $this->mPre . $html . $this->mPost;
        }
 
+       /**
+        * Set whether the HTML form can be collapsed.
+        *
+        * @since 1.34
+        * @param bool $collapsedByDefault (optional) whether the form is collapsed by default
+        * @return HTMLForm $this for chaining calls
+        */
+       public function setCollapsibleOptions( $collapsedByDefault = false ) {
+               $this->mCollapsible = true;
+               $this->mCollapsed = $collapsedByDefault;
+               return $this;
+       }
+
        /**
         * Get HTML attributes for the `<form>` tag.
         * @return array
@@ -1089,7 +1116,7 @@ class HTMLForm extends ContextSource {
                # Include a <fieldset> wrapper for style, if requested.
                if ( $this->mWrapperLegend !== false ) {
                        $legend = is_string( $this->mWrapperLegend ) ? $this->mWrapperLegend : false;
-                       $html = Xml::fieldset( $legend, $html );
+                       $html = Xml::fieldset( $legend, $html, $this->mWrapperAttributes );
                }
 
                return Html::rawElement(
@@ -1260,7 +1287,7 @@ class HTMLForm extends ContextSource {
         * @return string
         */
        public function getErrors( $errors ) {
-               wfDeprecated( __METHOD__ );
+               wfDeprecated( __METHOD__, '1.28' );
                return $this->getErrorsOrWarnings( $errors, 'error' );
        }
 
@@ -1346,21 +1373,6 @@ class HTMLForm extends ContextSource {
                return $this;
        }
 
-       /**
-        * Identify that the submit button in the form has a progressive action
-        * @since 1.25
-        * @deprecated since 1.32, No need to call. Submit button already
-        * has a progressive action form.
-        *
-        * @return HTMLForm $this for chaining calls (since 1.28)
-        */
-       public function setSubmitProgressive() {
-               wfDeprecated( __METHOD__, '1.32' );
-               $this->mSubmitFlags = [ 'progressive', 'primary' ];
-
-               return $this;
-       }
-
        /**
         * Set the text for the submit button to a message
         * @since 1.19
@@ -1534,6 +1546,19 @@ class HTMLForm extends ContextSource {
                return $this;
        }
 
+       /**
+        * For internal use only. Use is discouraged, and should only be used where
+        * support for gadgets/user scripts is warranted.
+        * @param array $attributes
+        * @internal
+        * @return HTMLForm $this for chaining calls
+        */
+       public function setWrapperAttributes( $attributes ) {
+               $this->mWrapperAttributes = $attributes;
+
+               return $this;
+       }
+
        /**
         * Prompt the whole form to be wrapped in a "<fieldset>", with
         * this message as its "<legend>" element.
diff --git a/includes/htmlform/HTMLFormActionFieldLayout.php b/includes/htmlform/HTMLFormActionFieldLayout.php
new file mode 100644 (file)
index 0000000..2c08224
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+
+class HTMLFormActionFieldLayout extends OOUI\ActionFieldLayout {
+       use HTMLFormElement;
+
+       public function __construct( $fieldWidget, $buttonWidget = false, array $config = [] ) {
+               parent::__construct( $fieldWidget, $buttonWidget, $config );
+
+               // Traits
+               $this->initializeHTMLFormElement( $config );
+       }
+
+       protected function getJavaScriptClassName() {
+               return 'mw.htmlform.ActionFieldLayout';
+       }
+}
index fbef265..b77c17e 100644 (file)
@@ -33,33 +33,3 @@ trait HTMLFormElement {
                } );
        }
 }
-
-class HTMLFormFieldLayout extends OOUI\FieldLayout {
-       use HTMLFormElement;
-
-       public function __construct( $fieldWidget, array $config = [] ) {
-               parent::__construct( $fieldWidget, $config );
-
-               // Traits
-               $this->initializeHTMLFormElement( $config );
-       }
-
-       protected function getJavaScriptClassName() {
-               return 'mw.htmlform.FieldLayout';
-       }
-}
-
-class HTMLFormActionFieldLayout extends OOUI\ActionFieldLayout {
-       use HTMLFormElement;
-
-       public function __construct( $fieldWidget, $buttonWidget = false, array $config = [] ) {
-               parent::__construct( $fieldWidget, $buttonWidget, $config );
-
-               // Traits
-               $this->initializeHTMLFormElement( $config );
-       }
-
-       protected function getJavaScriptClassName() {
-               return 'mw.htmlform.ActionFieldLayout';
-       }
-}
index 818474d..16dc465 100644 (file)
@@ -586,7 +586,7 @@ abstract class HTMLFormField {
                        // It might look weird, but it'll work OK.
                        return $this->getFieldLayoutOOUI(
                                new OOUI\Widget( [ 'content' => new OOUI\HtmlSnippet( $this->getDiv( $value ) ) ] ),
-                               [ 'infusable' => false, 'align' => 'top' ]
+                               [ 'align' => 'top' ]
                        );
                }
 
diff --git a/includes/htmlform/HTMLFormFieldLayout.php b/includes/htmlform/HTMLFormFieldLayout.php
new file mode 100644 (file)
index 0000000..ce93db2
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+
+class HTMLFormFieldLayout extends OOUI\FieldLayout {
+       use HTMLFormElement;
+
+       public function __construct( $fieldWidget, array $config = [] ) {
+               parent::__construct( $fieldWidget, $config );
+
+               // Traits
+               $this->initializeHTMLFormElement( $config );
+       }
+
+       protected function getJavaScriptClassName() {
+               return 'mw.htmlform.FieldLayout';
+       }
+}
index 49cbdee..baafa5e 100644 (file)
@@ -145,19 +145,21 @@ class OOUIHTMLForm extends HTMLForm {
                        [ 'class' => 'mw-htmlform-submit-buttons' ], "\n$buttons" ) . "\n";
        }
 
+       /**
+        * @inheritDoc
+        * @return OOUI\PanelLayout
+        */
        protected function wrapFieldSetSection( $legend, $section, $attributes, $isRoot ) {
                // to get a user visible effect, wrap the fieldset into a framed panel layout
                $layout = new OOUI\PanelLayout( [
                        'expanded' => false,
                        'padded' => true,
                        'framed' => true,
-                       'infusable' => false,
                ] );
 
                $layout->appendContent(
                        new OOUI\FieldsetLayout( [
                                'label' => $legend,
-                               'infusable' => false,
                                'items' => [
                                        new OOUI\Widget( [
                                                'content' => new OOUI\HtmlSnippet( $section )
@@ -279,20 +281,30 @@ class OOUIHTMLForm extends HTMLForm {
 
        public function wrapForm( $html ) {
                if ( is_string( $this->mWrapperLegend ) ) {
+                       $classes = $this->mCollapsible ? [ 'mw-collapsible' ] : [];
+                       if ( $this->mCollapsed ) {
+                               $classes[] = 'mw-collapsed';
+                       }
                        $content = new OOUI\FieldsetLayout( [
                                'label' => $this->mWrapperLegend,
+                               'classes' => $classes,
+                               'group' => new OOUI\StackLayout( [
+                                       'expanded' => false,
+                                       'classes' => [ 'mw-collapsible-content' ],
+                               ] ),
                                'items' => [
                                        new OOUI\Widget( [
                                                'content' => new OOUI\HtmlSnippet( $html )
                                        ] ),
                                ],
-                       ] );
+                       ] + OOUI\Element::configFromHtmlAttributes( $this->mWrapperAttributes ) );
                } else {
                        $content = new OOUI\HtmlSnippet( $html );
                }
 
+               $classes = [ 'mw-htmlform', 'mw-htmlform-ooui' ];
                $form = new OOUI\FormLayout( $this->getFormAttributes() + [
-                       'classes' => [ 'mw-htmlform', 'mw-htmlform-ooui' ],
+                       'classes' => $classes,
                        'content' => $content,
                ] );
 
index aad9f6e..0a1024c 100644 (file)
@@ -119,7 +119,7 @@ class HTMLCheckField extends HTMLFormField {
                // Fetch the value in either one of the two following case:
                // - we have a valid submit attempt (form was just submitted)
                // - we have a value (an URL manually built by the user, or GET form with no wpFormIdentifier)
-               if ( $this->isSubmitAttempt( $request ) || $request->getVal( $this->mName ) !== null ) {
+               if ( $this->isSubmitAttempt( $request ) || $request->getCheck( $this->mName ) ) {
                        return $invert
                                ? !$request->getBool( $this->mName )
                                : $request->getBool( $this->mName );
index 7b59a1d..d1f3c44 100644 (file)
@@ -171,11 +171,20 @@ class HTMLDateTimeField extends HTMLTextField {
                        }
                }
 
-               return new MediaWiki\Widget\DateTimeInputWidget( $params );
+               if ( $this->mType === 'date' ) {
+                       $this->mParent->getOutput()->addModuleStyles( 'mediawiki.widgets.DateInputWidget.styles' );
+                       return new MediaWiki\Widget\DateInputWidget( $params );
+               } else {
+                       return new MediaWiki\Widget\DateTimeInputWidget( $params );
+               }
        }
 
        protected function getOOUIModules() {
-               return [ 'mediawiki.widgets.datetime' ];
+               if ( $this->mType === 'date' ) {
+                       return [ 'mediawiki.widgets.DateInputWidget' ];
+               } else {
+                       return [ 'mediawiki.widgets.datetime' ];
+               }
        }
 
        protected function shouldInfuseOOUI() {
index 03e479b..be8f7d8 100644 (file)
@@ -59,6 +59,7 @@ class HTMLFormFieldWithButton extends HTMLFormField {
                        'type' => $this->mButtonType,
                        'label' => $this->mButtonValue,
                        'flags' => $this->mButtonFlags,
+                       'id' => $this->mButtonId ?: null,
                ] + OOUI\Element::configFromHtmlAttributes(
                        $this->getAttributes( [ 'disabled', 'tabindex' ] )
                ) );
index 5ad1a4d..5eab605 100644 (file)
@@ -38,13 +38,15 @@ class HTMLNamespacesMultiselectField extends HTMLSelectNamespace {
                // $value is a string, because HTMLForm fields store their values as strings
                $namespaces = explode( "\n", $value );
 
-               if ( isset( $this->mParams['max'] ) ) {
-                       if ( count( $namespaces ) > $this->mParams['max'] ) {
-                               return $this->msg( 'htmlform-int-toohigh', $this->mParams['max'] );
-                       }
+               if ( isset( $this->mParams['max'] ) && ( count( $namespaces ) > $this->mParams['max'] ) ) {
+                       return $this->msg( 'htmlform-int-toohigh', $this->mParams['max'] );
                }
 
                foreach ( $namespaces as $namespace ) {
+                       if ( $namespace < 0 ) {
+                               return $this->msg( 'htmlform-select-badoption' );
+                       }
+
                        $result = parent::validate( $namespace, $alldata );
                        if ( $result !== true ) {
                                return $result;
index 4e64e9d..f137bf1 100644 (file)
@@ -144,7 +144,7 @@ class HTMLSelectAndOtherField extends HTMLSelectField {
        /**
         * @param WebRequest $request
         *
-        * @return array("<overall message>","<select value>","<text field value>")
+        * @return array ["<overall message>","<select value>","<text field value>"]
         */
        public function loadDataFromRequest( $request ) {
                if ( $request->getCheck( $this->mName ) ) {
index 60c63d6..56589b0 100644 (file)
@@ -131,6 +131,9 @@ class HTMLTextField extends HTMLFormField {
                                case 'url':
                                        $type = $this->mParams['type'];
                                        break;
+                               case 'textwithbutton':
+                                       $type = $this->mParams['inputtype'] ?? 'text';
+                                       break;
                        }
                }
 
index 1cfbd5f..bd1d2d3 100644 (file)
@@ -53,10 +53,8 @@ class HTMLTitlesMultiselectField extends HTMLTitleTextField {
                // $value is a string, because HTMLForm fields store their values as strings
                $titlesArray = explode( "\n", $value );
 
-               if ( isset( $this->mParams['max'] ) ) {
-                       if ( count( $titlesArray ) > $this->mParams['max'] ) {
-                               return $this->msg( 'htmlform-int-toohigh', $this->mParams['max'] );
-                       }
+               if ( isset( $this->mParams['max'] ) && ( count( $titlesArray ) > $this->mParams['max'] ) ) {
+                       return $this->msg( 'htmlform-int-toohigh', $this->mParams['max'] );
                }
 
                foreach ( $titlesArray as $title ) {
index d672314..5b3bc25 100644 (file)
@@ -65,7 +65,7 @@ class HTMLUserTextField extends HTMLTextField {
        protected function isValidIPRange( $value ) {
                $cidrIPRanges = $this->mParams['iprangelimits'];
 
-               if ( !IP::isValidBlock( $value ) ) {
+               if ( !IP::isValidRange( $value ) ) {
                        return false;
                }
 
index 8ef9cc2..5130e36 100644 (file)
@@ -27,6 +27,18 @@ class CurlHttpRequest extends MWHttpRequest {
        protected $curlOptions = [];
        protected $headerText = "";
 
+       /**
+        * @throws RuntimeException
+        */
+       public function __construct() {
+               if ( !function_exists( 'curl_init' ) ) {
+                       throw new RuntimeException(
+                               __METHOD__ . ': curl (https://www.php.net/curl) is not installed' );
+               }
+
+               parent::__construct( ...func_get_args() );
+       }
+
        /**
         * @param resource $fh
         * @param string $content
index e6b2892..3af7f56 100644 (file)
@@ -45,7 +45,7 @@ class GuzzleHttpRequest extends MWHttpRequest {
 
        /**
         * @param string $url Url to use. If protocol-relative, will be expanded to an http:// URL
-        * @param array $options (optional) extra params to pass (see Http::request())
+        * @param array $options (optional) extra params to pass (see HttpRequestFactory::create())
         * @param string $caller The method making this request, for profiling
         * @param Profiler|null $profiler An instance of the profiler for profiling, or null
         * @throws Exception
index f0972dc..9596169 100644 (file)
  */
 
 use MediaWiki\Logger\LoggerFactory;
+use MediaWiki\MediaWikiServices;
 
 /**
  * Various HTTP related functions
+ * @deprecated since 1.34
  * @ingroup HTTP
  */
 class Http {
-       public static $httpEngine = false;
+       /** @deprecated since 1.34, just use the default engine */
+       public static $httpEngine = null;
 
        /**
         * Perform an HTTP request
         *
+        * @deprecated since 1.34, use HttpRequestFactory::request()
+        *
         * @param string $method HTTP method. Usually GET/POST
         * @param string $url Full URL to act on. If protocol-relative, will be expanded to an http:// URL
-        * @param array $options Options to pass to MWHttpRequest object.
-        *      Possible keys for the array:
-        *    - timeout             Timeout length in seconds
-        *    - connectTimeout      Timeout for connection, in seconds (curl only)
-        *    - postData            An array of key-value pairs or a url-encoded form data
-        *    - proxy               The proxy to use.
-        *                          Otherwise it will use $wgHTTPProxy (if set)
-        *                          Otherwise it will use the environment variable "http_proxy" (if set)
-        *    - noProxy             Don't use any proxy at all. Takes precedence over proxy value(s).
-        *    - sslVerifyHost       Verify hostname against certificate
-        *    - sslVerifyCert       Verify SSL certificate
-        *    - caInfo              Provide CA information
-        *    - maxRedirects        Maximum number of redirects to follow (defaults to 5)
-        *    - followRedirects     Whether to follow redirects (defaults to false).
-        *                          Note: this should only be used when the target URL is trusted,
-        *                          to avoid attacks on intranet services accessible by HTTP.
-        *    - userAgent           A user agent, if you want to override the default
-        *                          MediaWiki/$wgVersion
-        *    - logger              A \Psr\Logger\LoggerInterface instance for debug logging
-        *    - username            Username for HTTP Basic Authentication
-        *    - password            Password for HTTP Basic Authentication
-        *    - originalRequest     Information about the original request (as a WebRequest object or
-        *                          an associative array with 'ip' and 'userAgent').
+        * @param array $options Options to pass to MWHttpRequest object. See HttpRequestFactory::create
+        *  docs
         * @param string $caller The method making this request, for profiling
         * @return string|bool (bool)false on failure or a string on success
         */
        public static function request( $method, $url, array $options = [], $caller = __METHOD__ ) {
-               $logger = LoggerFactory::getInstance( 'http' );
-               $logger->debug( "$method: $url" );
-
-               $options['method'] = strtoupper( $method );
-
-               if ( !isset( $options['timeout'] ) ) {
-                       $options['timeout'] = 'default';
-               }
-               if ( !isset( $options['connectTimeout'] ) ) {
-                       $options['connectTimeout'] = 'default';
-               }
-
-               $req = MWHttpRequest::factory( $url, $options, $caller );
-               $status = $req->execute();
-
-               if ( $status->isOK() ) {
-                       return $req->getContent();
-               } else {
-                       $errors = $status->getErrorsByType( 'error' );
-                       $logger->warning( Status::wrap( $status )->getWikiText( false, false, 'en' ),
-                               [ 'error' => $errors, 'caller' => $caller, 'content' => $req->getContent() ] );
-                       return false;
-               }
+               $ret = MediaWikiServices::getInstance()->getHttpRequestFactory()->request(
+                       $method, $url, $options, $caller );
+               return is_string( $ret ) ? $ret : false;
        }
 
        /**
         * Simple wrapper for Http::request( 'GET' )
-        * @see Http::request()
+        *
+        * @deprecated since 1.34, use HttpRequestFactory::get()
+        *
         * @since 1.25 Second parameter $timeout removed. Second parameter
         * is now $options which can be given a 'timeout'
         *
@@ -111,7 +77,8 @@ class Http {
 
        /**
         * Simple wrapper for Http::request( 'POST' )
-        * @see Http::request()
+        *
+        * @deprecated since 1.34, use HttpRequestFactory::post()
         *
         * @param string $url
         * @param array $options
@@ -124,11 +91,12 @@ class Http {
 
        /**
         * A standard user-agent we can use for external requests.
+        *
+        * @deprecated since 1.34, use HttpRequestFactory::getUserAgent()
         * @return string
         */
        public static function userAgent() {
-               global $wgVersion;
-               return "MediaWiki/$wgVersion";
+               return MediaWikiServices::getInstance()->getHttpRequestFactory()->getUserAgent();
        }
 
        /**
@@ -143,37 +111,37 @@ class Http {
         *
         * @todo FIXME this is wildly inaccurate and fails to actually check most stuff
         *
+        * @deprecated since 1.34, use MWHttpRequest::isValidURI
         * @param string $uri URI to check for validity
         * @return bool
         */
        public static function isValidURI( $uri ) {
-               return (bool)preg_match(
-                       '/^https?:\/\/[^\/\s]\S*$/D',
-                       $uri
-               );
+               return MWHttpRequest::isValidURI( $uri );
        }
 
        /**
         * Gets the relevant proxy from $wgHTTPProxy
         *
-        * @return mixed The proxy address or an empty string if not set.
+        * @deprecated since 1.34, use $wgHTTPProxy directly
+        * @return string The proxy address or an empty string if not set.
         */
        public static function getProxy() {
-               global $wgHTTPProxy;
+               wfDeprecated( __METHOD__, '1.34' );
 
-               if ( $wgHTTPProxy ) {
-                       return $wgHTTPProxy;
-               }
-
-               return "";
+               global $wgHTTPProxy;
+               return (string)$wgHTTPProxy;
        }
 
        /**
         * Get a configured MultiHttpClient
+        *
+        * @deprecated since 1.34, construct it directly
         * @param array $options
         * @return MultiHttpClient
         */
        public static function createMultiClient( array $options = [] ) {
+               wfDeprecated( __METHOD__, '1.34' );
+
                global $wgHTTPConnectTimeout, $wgHTTPTimeout, $wgHTTPProxy;
 
                return new MultiHttpClient( $options + [
index a3a14d0..8e5567b 100644 (file)
 namespace MediaWiki\Http;
 
 use CurlHttpRequest;
-use DomainException;
+use GuzzleHttpRequest;
 use Http;
 use MediaWiki\Logger\LoggerFactory;
 use MWHttpRequest;
 use PhpHttpRequest;
 use Profiler;
-use GuzzleHttpRequest;
+use RuntimeException;
+use Status;
 
 /**
  * Factory creating MWHttpRequest objects.
  */
 class HttpRequestFactory {
-
        /**
         * Generate a new MWHttpRequest object
         * @param string $url Url to use
-        * @param array $options (optional) extra params to pass (see Http::request())
+        * @param array $options Possible keys for the array:
+        *    - timeout             Timeout length in seconds
+        *    - connectTimeout      Timeout for connection, in seconds (curl only)
+        *    - postData            An array of key-value pairs or a url-encoded form data
+        *    - proxy               The proxy to use.
+        *                          Otherwise it will use $wgHTTPProxy (if set)
+        *                          Otherwise it will use the environment variable "http_proxy" (if set)
+        *    - noProxy             Don't use any proxy at all. Takes precedence over proxy value(s).
+        *    - sslVerifyHost       Verify hostname against certificate
+        *    - sslVerifyCert       Verify SSL certificate
+        *    - caInfo              Provide CA information
+        *    - maxRedirects        Maximum number of redirects to follow (defaults to 5)
+        *    - followRedirects     Whether to follow redirects (defaults to false).
+        *                          Note: this should only be used when the target URL is trusted,
+        *                          to avoid attacks on intranet services accessible by HTTP.
+        *    - userAgent           A user agent, if you want to override the default
+        *                          MediaWiki/$wgVersion
+        *    - logger              A \Psr\Logger\LoggerInterface instance for debug logging
+        *    - username            Username for HTTP Basic Authentication
+        *    - password            Password for HTTP Basic Authentication
+        *    - originalRequest     Information about the original request (as a WebRequest object or
+        *                          an associative array with 'ip' and 'userAgent').
         * @param string $caller The method making this request, for profiling
-        * @throws DomainException
+        * @throws RuntimeException
         * @return MWHttpRequest
         * @see MWHttpRequest::__construct
         */
        public function create( $url, array $options = [], $caller = __METHOD__ ) {
                if ( !Http::$httpEngine ) {
                        Http::$httpEngine = 'guzzle';
-               } elseif ( Http::$httpEngine == 'curl' && !function_exists( 'curl_init' ) ) {
-                       throw new DomainException( __METHOD__ . ': curl (https://secure.php.net/curl) is not ' .
-                          'installed, but Http::$httpEngine is set to "curl"' );
                }
 
                if ( !isset( $options['logger'] ) ) {
@@ -60,16 +78,9 @@ class HttpRequestFactory {
                        case 'curl':
                                return new CurlHttpRequest( $url, $options, $caller, Profiler::instance() );
                        case 'php':
-                               if ( !wfIniGetBool( 'allow_url_fopen' ) ) {
-                                       throw new DomainException( __METHOD__ . ': allow_url_fopen ' .
-                                          'needs to be enabled for pure PHP http requests to ' .
-                                          'work. If possible, curl should be used instead. See ' .
-                                          'https://secure.php.net/curl.'
-                                       );
-                               }
                                return new PhpHttpRequest( $url, $options, $caller, Profiler::instance() );
                        default:
-                               throw new DomainException( __METHOD__ . ': The setting of Http::$httpEngine is not valid.' );
+                               throw new RuntimeException( __METHOD__ . ': The requested engine is not valid.' );
                }
        }
 
@@ -82,4 +93,75 @@ class HttpRequestFactory {
                return function_exists( 'curl_init' ) || wfIniGetBool( 'allow_url_fopen' );
        }
 
+       /**
+        * Perform an HTTP request
+        *
+        * @since 1.34
+        * @param string $method HTTP method. Usually GET/POST
+        * @param string $url Full URL to act on. If protocol-relative, will be expanded to an http://
+        *  URL
+        * @param array $options See HttpRequestFactory::create
+        * @param string $caller The method making this request, for profiling
+        * @return string|null null on failure or a string on success
+        */
+       public function request( $method, $url, array $options = [], $caller = __METHOD__ ) {
+               $logger = LoggerFactory::getInstance( 'http' );
+               $logger->debug( "$method: $url" );
+
+               $options['method'] = strtoupper( $method );
+
+               if ( !isset( $options['timeout'] ) ) {
+                       $options['timeout'] = 'default';
+               }
+               if ( !isset( $options['connectTimeout'] ) ) {
+                       $options['connectTimeout'] = 'default';
+               }
+
+               $req = $this->create( $url, $options, $caller );
+               $status = $req->execute();
+
+               if ( $status->isOK() ) {
+                       return $req->getContent();
+               } else {
+                       $errors = $status->getErrorsByType( 'error' );
+                       $logger->warning( Status::wrap( $status )->getWikiText( false, false, 'en' ),
+                               [ 'error' => $errors, 'caller' => $caller, 'content' => $req->getContent() ] );
+                       return null;
+               }
+       }
+
+       /**
+        * Simple wrapper for request( 'GET' ), parameters have same meaning as for request()
+        *
+        * @since 1.34
+        * @param string $url
+        * @param array $options
+        * @param string $caller
+        * @return string|null
+        */
+       public function get( $url, array $options = [], $caller = __METHOD__ ) {
+               return $this->request( 'GET', $url, $options, $caller );
+       }
+
+       /**
+        * Simple wrapper for request( 'POST' ), parameters have same meaning as for request()
+        *
+        * @since 1.34
+        * @param string $url
+        * @param array $options
+        * @param string $caller
+        * @return string|null
+        */
+       public function post( $url, array $options = [], $caller = __METHOD__ ) {
+               return $this->request( 'POST', $url, $options, $caller );
+       }
+
+       /**
+        * @return string
+        */
+       public function getUserAgent() {
+               global $wgVersion;
+
+               return "MediaWiki/$wgVersion";
+       }
 }
index b4ac9a7..41ea1dc 100644 (file)
@@ -85,7 +85,7 @@ abstract class MWHttpRequest implements LoggerAwareInterface {
 
        /**
         * @param string $url Url to use. If protocol-relative, will be expanded to an http:// URL
-        * @param array $options (optional) extra params to pass (see Http::request())
+        * @param array $options (optional) extra params to pass (see HttpRequestFactory::create())
         * @param string $caller The method making this request, for profiling
         * @param Profiler|null $profiler An instance of the profiler for profiling, or null
         * @throws Exception
@@ -172,9 +172,9 @@ abstract class MWHttpRequest implements LoggerAwareInterface {
 
        /**
         * Generate a new request object
-        * Deprecated: @see HttpRequestFactory::create
+        * @deprecated since 1.34, use HttpRequestFactory instead
         * @param string $url Url to use
-        * @param array|null $options (optional) extra params to pass (see Http::request())
+        * @param array|null $options (optional) extra params to pass (see HttpRequestFactory::create())
         * @param string $caller The method making this request, for profiling
         * @throws DomainException
         * @return MWHttpRequest
@@ -224,7 +224,8 @@ abstract class MWHttpRequest implements LoggerAwareInterface {
                if ( self::isLocalURL( $this->url ) || $this->noProxy ) {
                        $this->proxy = '';
                } else {
-                       $this->proxy = Http::getProxy();
+                       global $wgHTTPProxy;
+                       $this->proxy = (string)$wgHTTPProxy;
                }
        }
 
@@ -662,4 +663,27 @@ abstract class MWHttpRequest implements LoggerAwareInterface {
                $this->reqHeaders['X-Forwarded-For'] = $originalRequest['ip'];
                $this->reqHeaders['X-Original-User-Agent'] = $originalRequest['userAgent'];
        }
+
+       /**
+        * Check that the given URI is a valid one.
+        *
+        * This hardcodes a small set of protocols only, because we want to
+        * deterministically reject protocols not supported by all HTTP-transport
+        * methods.
+        *
+        * "file://" specifically must not be allowed, for security reasons
+        * (see <https://www.mediawiki.org/wiki/Special:Code/MediaWiki/r67684>).
+        *
+        * @todo FIXME this is wildly inaccurate and fails to actually check most stuff
+        *
+        * @since 1.34
+        * @param string $uri URI to check for validity
+        * @return bool
+        */
+       public static function isValidURI( $uri ) {
+               return (bool)preg_match(
+                       '/^https?:\/\/[^\/\s]\S*$/D',
+                       $uri
+               );
+       }
 }
index 30ab181..c987c62 100644 (file)
@@ -22,6 +22,17 @@ class PhpHttpRequest extends MWHttpRequest {
 
        private $fopenErrors = [];
 
+       public function __construct() {
+               if ( !wfIniGetBool( 'allow_url_fopen' ) ) {
+                       throw new RuntimeException( __METHOD__ . ': allow_url_fopen needs to be enabled for ' .
+                               'pure PHP http requests to work. If possible, curl should be used instead. See ' .
+                               'https://www.php.net/curl.'
+                       );
+               }
+
+               parent::__construct( ...func_get_args() );
+       }
+
        /**
         * @param string $url
         * @return string
@@ -217,7 +228,7 @@ class PhpHttpRequest extends MWHttpRequest {
                                        break;
                                }
 
-                               if ( strlen( $buf ) ) {
+                               if ( $buf !== '' ) {
                                        call_user_func( $this->callback, $fh, $buf );
                                }
                        }
index ebac200..e6936cb 100644 (file)
@@ -112,7 +112,7 @@ class ImportStreamSource implements ImportSource {
                # quicker and sorts out user-agent problems which might
                # otherwise prevent importing from large sites, such
                # as the Wikimedia cluster, etc.
-               $data = Http::request(
+               $data = MediaWikiServices::getInstance()->getHttpRequestFactory()->request(
                        $method,
                        $url,
                        [
index 4b378c1..f1ac42c 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 
+use MediaWiki\MediaWikiServices;
 use Psr\Log\LoggerInterface;
 
 /**
@@ -159,7 +160,8 @@ class ImportableUploadRevisionImporter implements UploadRevisionImporter {
 
                // @todo FIXME!
                $src = $wikiRevision->getSrc();
-               $data = Http::get( $src, [], __METHOD__ );
+               $data = MediaWikiServices::getInstance()->getHttpRequestFactory()->
+                       get( $src, [], __METHOD__ );
                if ( !$data ) {
                        $this->logger->debug( "IMPORT: couldn't fetch source $src\n" );
                        fclose( $f );
index ccacbe4..7ac895c 100644 (file)
@@ -32,7 +32,7 @@ class UploadSourceAdapter {
        /** @var array */
        public static $sourceRegistrations = [];
 
-       /** @var string */
+       /** @var ImportSource */
        private $mSource;
 
        /** @var string */
index 4d72102..8f58344 100644 (file)
@@ -120,10 +120,7 @@ class WikiImporter {
                wfDebug( "IMPORT: $data\n" );
        }
 
-       public function notice( $msg /*, $param, ...*/ ) {
-               $params = func_get_args();
-               array_shift( $params );
-
+       public function notice( $msg, ...$params ) {
                if ( is_callable( $this->mNoticeCallback ) ) {
                        call_user_func( $this->mNoticeCallback, $msg, $params );
                } else { # No ImportReporter -> CLI
@@ -260,7 +257,7 @@ class WikiImporter {
                        return true;
                } elseif (
                        $namespace >= 0 &&
-                       MWNamespace::exists( intval( $namespace ) )
+                       MediaWikiServices::getInstance()->getNamespaceInfo()->exists( intval( $namespace ) )
                ) {
                        $namespace = intval( $namespace );
                        $this->setImportTitleFactory( new NamespaceImportTitleFactory( $namespace ) );
@@ -286,18 +283,19 @@ class WikiImporter {
 
                        if ( !$title || $title->isExternal() ) {
                                $status->fatal( 'import-rootpage-invalid' );
+                       } elseif (
+                               !MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               hasSubpages( $title->getNamespace() )
+                       ) {
+                               $displayNSText = $title->getNamespace() == NS_MAIN
+                                       ? wfMessage( 'blanknamespace' )->text()
+                                       : MediaWikiServices::getInstance()->getContentLanguage()->
+                                               getNsText( $title->getNamespace() );
+                               $status->fatal( 'import-rootpage-nosubpage', $displayNSText );
                        } else {
-                               if ( !MWNamespace::hasSubpages( $title->getNamespace() ) ) {
-                                       $displayNSText = $title->getNamespace() == NS_MAIN
-                                               ? wfMessage( 'blanknamespace' )->text()
-                                               : MediaWikiServices::getInstance()->getContentLanguage()->
-                                                       getNsText( $title->getNamespace() );
-                                       $status->fatal( 'import-rootpage-nosubpage', $displayNSText );
-                               } else {
-                                       // set namespace to 'all', so the namespace check in processTitle() can pass
-                                       $this->setTargetNamespace( null );
-                                       $this->setImportTitleFactory( new SubpageImportTitleFactory( $title ) );
-                               }
+                               // set namespace to 'all', so the namespace check in processTitle() can pass
+                               $this->setTargetNamespace( null );
+                               $this->setImportTitleFactory( new SubpageImportTitleFactory( $title ) );
                        }
                }
                return $status;
@@ -432,8 +430,7 @@ class WikiImporter {
                        }
                }
 
-               $args = func_get_args();
-               return Hooks::run( 'AfterImportPage', $args );
+               return Hooks::run( 'AfterImportPage', func_get_args() );
        }
 
        /**
@@ -488,8 +485,7 @@ class WikiImporter {
        private function pageOutCallback( $title, $foreignTitle, $revCount,
                        $sucCount, $pageInfo ) {
                if ( isset( $this->mPageOutCallback ) ) {
-                       $args = func_get_args();
-                       call_user_func_array( $this->mPageOutCallback, $args );
+                       call_user_func_array( $this->mPageOutCallback, func_get_args() );
                }
        }
 
@@ -893,6 +889,7 @@ class WikiImporter {
                                ) . " exceeds the maximum allowable size ($wgMaxArticleSize KB)" );
                }
 
+               // FIXME: process schema version 11!
                $revision = new WikiRevision( $this->config );
 
                if ( isset( $revisionInfo['id'] ) ) {
index 96b43d6..c006874 100644 (file)
@@ -54,14 +54,6 @@ class WikiRevision implements ImportableUploadRevision, ImportableOldRevision {
         */
        public $timestamp = "20010115000000";
 
-       /**
-        * @since 1.2
-        * @var int
-        * @deprecated in 1.29. Unused.
-        * @note Introduced in 436a028086fb3f01c4605c5ad2964d56f9306aca, unused there, unused now.
-        */
-       public $user = 0;
-
        /**
         * @since 1.2
         * @var string
index 7267ddd..c008333 100644 (file)
@@ -200,24 +200,23 @@ class CliInstaller extends Installer {
                $this->showMessage( 'config-install-step-done' );
        }
 
-       public function showMessage( $msg /*, ... */ ) {
-               echo $this->getMessageText( func_get_args() ) . "\n";
+       public function showMessage( $msg, ...$params ) {
+               echo $this->getMessageText( $msg, $params ) . "\n";
                flush();
        }
 
-       public function showError( $msg /*, ... */ ) {
-               echo "***{$this->getMessageText( func_get_args() )}***\n";
+       public function showError( $msg, ...$params ) {
+               echo "***{$this->getMessageText( $msg, $params )}***\n";
                flush();
        }
 
        /**
+        * @param string $msg
         * @param array $params
         *
         * @return string
         */
-       protected function getMessageText( $params ) {
-               $msg = array_shift( $params );
-
+       protected function getMessageText( $msg, $params ) {
                $text = wfMessage( $msg, $params )->parse();
 
                $text = preg_replace( '/<a href="(.*?)".*?>(.*?)<\/a>/', '$2 &lt;$1&gt;', $text );
index 6315de4..a219452 100644 (file)
@@ -37,8 +37,6 @@ abstract class DatabaseInstaller {
        /**
         * The Installer object.
         *
-        * @todo Naming this parent is confusing, 'installer' would be clearer.
-        *
         * @var WebInstaller
         */
        public $parent;
index 7a92807..b32be39 100644 (file)
@@ -20,8 +20,8 @@
  * @file
  * @ingroup Deployment
  */
-use Wikimedia\Rdbms\Database;
 use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\IMaintainableDatabase;
 use MediaWiki\MediaWikiServices;
 
 require_once __DIR__ . '/../../maintenance/Maintenance.php';
@@ -59,7 +59,7 @@ abstract class DatabaseUpdater {
        /**
         * Handle to the database subclass
         *
-        * @var Database
+        * @var IMaintainableDatabase
         */
        protected $db;
 
@@ -110,11 +110,15 @@ abstract class DatabaseUpdater {
        protected $holdContentHandlerUseDB = true;
 
        /**
-        * @param Database &$db To perform updates on
+        * @param IMaintainableDatabase &$db To perform updates on
         * @param bool $shared Whether to perform updates on shared tables
         * @param Maintenance|null $maintenance Maintenance object which created us
         */
-       protected function __construct( Database &$db, $shared, Maintenance $maintenance = null ) {
+       protected function __construct(
+               IMaintainableDatabase &$db,
+               $shared,
+               Maintenance $maintenance = null
+       ) {
                $this->db = $db;
                $this->db->setFlag( DBO_DDLMODE ); // For Oracle's handling of schema files
                $this->shared = $shared;
@@ -177,14 +181,18 @@ abstract class DatabaseUpdater {
        }
 
        /**
-        * @param Database $db
+        * @param IMaintainableDatabase $db
         * @param bool $shared
         * @param Maintenance|null $maintenance
         *
         * @throws MWException
         * @return DatabaseUpdater
         */
-       public static function newForDB( Database $db, $shared = false, Maintenance $maintenance = null ) {
+       public static function newForDB(
+               IMaintainableDatabase $db,
+               $shared = false,
+               Maintenance $maintenance = null
+       ) {
                $type = $db->getType();
                if ( in_array( $type, Installer::getDBTypes() ) ) {
                        $class = ucfirst( $type ) . 'Updater';
@@ -198,7 +206,7 @@ abstract class DatabaseUpdater {
        /**
         * Get a database connection to run updates
         *
-        * @return Database
+        * @return IMaintainableDatabase
         */
        public function getDB() {
                return $this->db;
@@ -410,9 +418,7 @@ abstract class DatabaseUpdater {
                $this->updatesSkipped = [];
 
                foreach ( $updates as $funcList ) {
-                       $func = $funcList[0];
-                       $args = $funcList[1];
-                       $origParams = $funcList[2];
+                       list( $func, $args, $origParams ) = $funcList;
                        $func( ...$args );
                        flush();
                        $this->updatesSkipped[] = $origParams;
@@ -1221,7 +1227,7 @@ abstract class DatabaseUpdater {
         */
        protected function rebuildLocalisationCache() {
                /**
-                * @var $cl RebuildLocalisationCache
+                * @var RebuildLocalisationCache $cl
                 */
                $cl = $this->maintenance->runChild(
                        RebuildLocalisationCache::class, 'rebuildLocalisationCache.php'
index 0bc0a83..26f9bf0 100644 (file)
@@ -336,14 +336,16 @@ abstract class Installer {
         * The messages will be in wikitext format, which will be converted to an
         * output format such as HTML or text before being sent to the user.
         * @param string $msg
+        * @param mixed ...$params
         */
-       abstract public function showMessage( $msg /*, ... */ );
+       abstract public function showMessage( $msg, ...$params );
 
        /**
         * Same as showMessage(), but for displaying errors
         * @param string $msg
+        * @param mixed ...$params
         */
-       abstract public function showError( $msg /*, ... */ );
+       abstract public function showError( $msg, ...$params );
 
        /**
         * Show a message to the installing user by using a Status object
@@ -492,7 +494,7 @@ abstract class Installer {
 
                $good = true;
                // Must go here because an old version of PCRE can prevent other checks from completing
-               list( $pcreVersion ) = explode( ' ', PCRE_VERSION, 2 );
+               $pcreVersion = explode( ' ', PCRE_VERSION, 2 )[0];
                if ( version_compare( $pcreVersion, self::MINIMUM_PCRE_VERSION, '<' ) ) {
                        $this->showError( 'config-pcre-old', self::MINIMUM_PCRE_VERSION, $pcreVersion );
                        $good = false;
@@ -694,6 +696,7 @@ abstract class Installer {
                                'enableSectionEditLinks' => false,
                                'unwrap' => true,
                        ] );
+                       $html = Parser::stripOuterParagraph( $html );
                } catch ( Wikimedia\Services\ServiceDisabledException $e ) {
                        $html = '<!--DB access attempted during parse-->  ' . htmlspecialchars( $text );
                }
@@ -1201,9 +1204,11 @@ abstract class Installer {
                                }
 
                                try {
-                                       $text = Http::get( $url . $file, [ 'timeout' => 3 ], __METHOD__ );
+                                       $text = MediaWikiServices::getInstance()->getHttpRequestFactory()->
+                                               get( $url . $file, [ 'timeout' => 3 ], __METHOD__ );
                                } catch ( Exception $e ) {
-                                       // Http::get throws with allow_url_fopen = false and no curl extension.
+                                       // HttpRequestFactory::get can throw with allow_url_fopen = false and no curl
+                                       // extension.
                                        $text = null;
                                }
                                unlink( $dir . $file );
@@ -1501,7 +1506,7 @@ abstract class Installer {
                $data = $registry->readFromQueue( $queue );
                $wgAutoloadClasses += $data['autoload'];
 
-               /** @suppress PhanUndeclaredVariable $wgHooks is set by DefaultSettings */
+               // @phan-suppress-next-line PhanUndeclaredVariable $wgHooks is set by DefaultSettings
                $hooksWeWant = $wgHooks['LoadExtensionSchemaUpdates'] ?? [];
 
                if ( isset( $data['globals']['wgHooks']['LoadExtensionSchemaUpdates'] ) ) {
@@ -1607,9 +1612,7 @@ abstract class Installer {
                }
                if ( $status->isOk() ) {
                        $this->showMessage(
-                               'config-install-success',
-                               $this->getVar( 'wgServer' ),
-                               $this->getVar( 'wgScriptPath' )
+                               'config-install-db-success'
                        );
                        $this->setVar( '_InstallDone', true );
                }
index e462220..6d62c43 100644 (file)
@@ -187,7 +187,7 @@ class MssqlInstaller extends DatabaseInstaller {
                        return $status;
                }
                /**
-                * @var $conn Database
+                * @var Database $conn
                 */
                $conn = $status->value;
 
@@ -241,7 +241,7 @@ class MssqlInstaller extends DatabaseInstaller {
                        return;
                }
                /**
-                * @var $conn Database
+                * @var Database $conn
                 */
                $conn = $status->value;
                $conn->selectDB( $this->getVar( 'wgDBname' ) );
index 75f3894..b8dc5ff 100644 (file)
@@ -166,6 +166,7 @@ class MssqlUpdater extends DatabaseUpdater {
                parent::applyPatch( $path, $isFullPath, $msg );
                $this->db->scrollableCursor( $prevScroll );
                $this->db->prepareStatements( $prevPrep );
+               return true;
        }
 
        /**
index e9a2d03..74924d0 100644 (file)
@@ -128,7 +128,7 @@ class MysqlInstaller extends DatabaseInstaller {
                        return $status;
                }
                /**
-                * @var $conn Database
+                * @var Database $conn
                 */
                $conn = $status->value;
 
@@ -167,7 +167,7 @@ class MysqlInstaller extends DatabaseInstaller {
                        return;
                }
                /**
-                * @var $conn Database
+                * @var Database $conn
                 */
                $conn = $status->value;
                $conn->selectDB( $this->getVar( 'wgDBname' ) );
@@ -232,7 +232,7 @@ class MysqlInstaller extends DatabaseInstaller {
                $status = $this->getConnection();
 
                /**
-                * @var $conn Database
+                * @var Database $conn
                 */
                $conn = $status->value;
 
index 2e3fdba..c33d3dd 100644 (file)
@@ -375,6 +375,7 @@ class MysqlUpdater extends DatabaseUpdater {
                        [ 'dropTable', 'valid_tag' ],
                        [ 'dropTable', 'tag_summary' ],
                        [ 'dropField', 'protected_titles', 'pt_reason', 'patch-drop-comment-fields.sql' ],
+                       [ 'modifyTable', 'job', 'patch-job-params-mediumblob.sql' ],
                ];
        }
 
diff --git a/includes/installer/PhpBugTests.php b/includes/installer/PhpBugTests.php
deleted file mode 100644 (file)
index 4e1e365..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-<?php
-/**
- * Classes for self-contained tests for known bugs in PHP.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-/**
- * @defgroup PHPBugTests PHP known bugs tests
- */
-/**
- * Test for PHP+libxml2 bug which breaks XML input subtly with certain versions.
- * Known fixed with PHP 5.2.9 + libxml2-2.7.3
- * @see https://bugs.php.net/bug.php?id=45996
- * @ingroup PHPBugTests
- */
-class PhpXmlBugTester {
-       private $parsedData = '';
-       public $ok = false;
-
-       public function __construct() {
-               $charData = '<b>c</b>';
-               $xml = '<a>' . htmlspecialchars( $charData ) . '</a>';
-
-               $parser = xml_parser_create();
-               xml_set_character_data_handler( $parser, [ $this, 'chardata' ] );
-               $parsedOk = xml_parse( $parser, $xml, true );
-               $this->ok = $parsedOk && ( $this->parsedData == $charData );
-       }
-
-       public function chardata( $parser, $data ) {
-               $this->parsedData .= $data;
-       }
-}
diff --git a/includes/installer/PhpXmlBugTester.php b/includes/installer/PhpXmlBugTester.php
new file mode 100644 (file)
index 0000000..4e1e365
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Classes for self-contained tests for known bugs in PHP.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * @defgroup PHPBugTests PHP known bugs tests
+ */
+/**
+ * Test for PHP+libxml2 bug which breaks XML input subtly with certain versions.
+ * Known fixed with PHP 5.2.9 + libxml2-2.7.3
+ * @see https://bugs.php.net/bug.php?id=45996
+ * @ingroup PHPBugTests
+ */
+class PhpXmlBugTester {
+       private $parsedData = '';
+       public $ok = false;
+
+       public function __construct() {
+               $charData = '<b>c</b>';
+               $xml = '<a>' . htmlspecialchars( $charData ) . '</a>';
+
+               $parser = xml_parser_create();
+               xml_set_character_data_handler( $parser, [ $this, 'chardata' ] );
+               $parsedOk = xml_parse( $parser, $xml, true );
+               $this->ok = $parsedOk && ( $this->parsedData == $charData );
+       }
+
+       public function chardata( $parser, $data ) {
+               $this->parsedData .= $data;
+       }
+}
index 16b47e2..21b6f39 100644 (file)
@@ -119,13 +119,13 @@ class PostgresInstaller extends DatabaseInstaller {
                        return $status;
                }
                /**
-                * @var $conn Database
+                * @var Database $conn
                 */
                $conn = $status->value;
 
                // Check version
                $version = $conn->getServerVersion();
-               $status = static::meetsMinimumRequirement( $conn->getServerVersion() );
+               $status = static::meetsMinimumRequirement( $version );
                if ( !$status->isOK() ) {
                        return $status;
                }
@@ -190,7 +190,7 @@ class PostgresInstaller extends DatabaseInstaller {
 
                if ( $status->isOK() ) {
                        /**
-                        * @var $conn Database
+                        * @var Database $conn
                         */
                        $conn = $status->value;
                        $conn->clearFlag( DBO_TRX );
@@ -242,7 +242,7 @@ class PostgresInstaller extends DatabaseInstaller {
                                $status = $this->openPgConnection( 'create-schema' );
                                if ( $status->isOK() ) {
                                        /**
-                                        * @var $conn Database
+                                        * @var Database $conn
                                         */
                                        $conn = $status->value;
                                        $safeRole = $conn->addIdentifierQuotes( $this->getVar( 'wgDBuser' ) );
@@ -296,7 +296,7 @@ class PostgresInstaller extends DatabaseInstaller {
                        return false;
                }
                /**
-                * @var $conn Database
+                * @var Database $conn
                 */
                $conn = $status->value;
                $superuser = $this->getVar( '_InstallUser' );
@@ -443,11 +443,11 @@ class PostgresInstaller extends DatabaseInstaller {
                        }
                        // Recursively search each member of the group to see if the target
                        // is a member of it, up to the given maximum depth.
-                       if ( $maxDepth > 0 ) {
-                               if ( $this->isRoleMember( $conn, $targetMember, $row->member, $maxDepth - 1 ) ) {
-                                       // Found member of member
-                                       return true;
-                               }
+                       if ( $maxDepth > 0 &&
+                               $this->isRoleMember( $conn, $targetMember, $row->member, $maxDepth - 1 )
+                       ) {
+                               // Found member of member
+                               return true;
                        }
                }
 
@@ -645,7 +645,7 @@ class PostgresInstaller extends DatabaseInstaller {
                        return $status;
                }
                /**
-                * @var $conn Database
+                * @var Database $conn
                 */
                $conn = $status->value;
 
index 75877a1..008240a 100644 (file)
@@ -839,7 +839,7 @@ END;
                if ( !$this->db->tableExists( $table, __METHOD__ ) ) {
                        $this->output( "...skipping: '$table' table doesn't exist yet.\n" );
 
-                       return;
+                       return true;
                }
 
                // Second requirement: the new index must be missing
@@ -853,17 +853,18 @@ END;
                                        "            $old should be manually removed if not needed anymore.\n" );
                        }
 
-                       return;
+                       return true;
                }
 
                // Third requirement: the old index must exist
                if ( !$this->db->indexExists( $table, $old, __METHOD__ ) ) {
                        $this->output( "...skipping: index $old doesn't exist.\n" );
 
-                       return;
+                       return true;
                }
 
                $this->db->query( "ALTER INDEX $old RENAME TO $new" );
+               return true;
        }
 
        protected function dropPgField( $table, $field ) {
@@ -1007,13 +1008,11 @@ END;
        public function addPgExtIndex( $table, $index, $type ) {
                if ( $this->db->indexExists( $table, $index ) ) {
                        $this->output( "...index '$index' on table '$table' already exists\n" );
+               } elseif ( preg_match( '/^\(/', $type ) ) {
+                       $this->output( "Creating index '$index' on table '$table'\n" );
+                       $this->db->query( "CREATE INDEX $index ON $table $type" );
                } else {
-                       if ( preg_match( '/^\(/', $type ) ) {
-                               $this->output( "Creating index '$index' on table '$table'\n" );
-                               $this->db->query( "CREATE INDEX $index ON $table $type" );
-                       } else {
-                               $this->applyPatch( $type, true, "Creating index '$index' on table '$table'" );
-                       }
+                       $this->applyPatch( $type, true, "Creating index '$index' on table '$table'" );
                }
        }
 
index a8abba9..7d2898c 100644 (file)
@@ -231,6 +231,7 @@ class SqliteInstaller extends DatabaseInstaller {
                $status->merge( $this->makeStubDBFile( $dir, $db ) );
                $status->merge( $this->makeStubDBFile( $dir, "wikicache" ) );
                $status->merge( $this->makeStubDBFile( $dir, "{$db}_l10n_cache" ) );
+               $status->merge( $this->makeStubDBFile( $dir, "{$db}_jobqueue" ) );
                if ( !$status->isOK() ) {
                        return $status;
                }
@@ -283,6 +284,39 @@ EOT;
                        return Status::newFatal( 'config-sqlite-connection-error', $e->getMessage() );
                }
 
+               # Create the job queue DB
+               try {
+                       $conn = Database::factory(
+                               'sqlite', [ 'dbname' => "{$db}_jobqueue", 'dbDirectory' => $dir ] );
+                       # @todo: don't duplicate job definition, though it's very static
+                       $sql =
+<<<EOT
+       CREATE TABLE job (
+               job_id INTEGER  NOT NULL PRIMARY KEY AUTOINCREMENT,
+               job_cmd BLOB NOT NULL default '',
+               job_namespace INTEGER NOT NULL,
+               job_title TEXT  NOT NULL,
+               job_timestamp BLOB NULL default NULL,
+               job_params BLOB NOT NULL,
+               job_random integer  NOT NULL default 0,
+               job_attempts integer  NOT NULL default 0,
+               job_token BLOB NOT NULL default '',
+               job_token_timestamp BLOB NULL default NULL,
+               job_sha1 BLOB NOT NULL default ''
+       );
+       CREATE INDEX job_sha1 ON job (job_sha1);
+       CREATE INDEX job_cmd_token ON job (job_cmd,job_token,job_random);
+       CREATE INDEX job_cmd_token_id ON job (job_cmd,job_token,job_id);
+       CREATE INDEX job_cmd ON job (job_cmd, job_namespace, job_title, job_params);
+       CREATE INDEX job_timestamp ON job (job_timestamp);
+EOT;
+                       $conn->query( $sql );
+                       $conn->query( "PRAGMA journal_mode=WAL" ); // this is permanent
+                       $conn->close();
+               } catch ( DBConnectionError $e ) {
+                       return Status::newFatal( 'config-sqlite-connection-error', $e->getMessage() );
+               }
+
                # Open the main DB
                return $this->getConnection();
        }
@@ -298,10 +332,8 @@ EOT;
                        if ( !is_writable( $file ) ) {
                                return Status::newFatal( 'config-sqlite-readonly', $file );
                        }
-               } else {
-                       if ( file_put_contents( $file, '' ) === false ) {
-                               return Status::newFatal( 'config-sqlite-cant-create-db', $file );
-                       }
+               } elseif ( file_put_contents( $file, '' ) === false ) {
+                       return Status::newFatal( 'config-sqlite-cant-create-db', $file );
                }
 
                return Status::newGood();
@@ -340,7 +372,9 @@ EOT;
         */
        public function getLocalSettings() {
                $dir = LocalSettingsGenerator::escapePhpString( $this->getVar( 'wgSQLiteDataDir' ) );
-
+               // These tables have frequent writes and are thus split off from the main one.
+               // Since the code using these tables only uses transactions for writes then set
+               // them to using BEGIN IMMEDIATE. This avoids frequent lock errors on first write.
                return "# SQLite-specific settings
 \$wgSQLiteDataDir = \"{$dir}\";
 \$wgObjectCaches[CACHE_DB] = [
@@ -350,7 +384,9 @@ EOT;
                'type' => 'sqlite',
                'dbname' => 'wikicache',
                'tablePrefix' => '',
+               'variables' => [ 'synchronous' => 'NORMAL' ],
                'dbDirectory' => \$wgSQLiteDataDir,
+               'trxMode' => 'IMMEDIATE',
                'flags' => 0
        ]
 ];
@@ -358,8 +394,22 @@ EOT;
        'type' => 'sqlite',
        'dbname' => \"{\$wgDBname}_l10n_cache\",
        'tablePrefix' => '',
+       'variables' => [ 'synchronous' => 'NORMAL' ],
        'dbDirectory' => \$wgSQLiteDataDir,
+       'trxMode' => 'IMMEDIATE',
        'flags' => 0
+];
+\$wgJobTypeConf['default'] = [
+       'class' => 'JobQueueDB',
+       'claimTTL' => 3600,
+       'server' => [
+               'type' => 'sqlite',
+               'dbname' => \"{\$wgDBname}_jobqueue\",
+               'tablePrefix' => '',
+               'dbDirectory' => \$wgSQLiteDataDir,
+               'trxMode' => 'IMMEDIATE',
+               'flags' => 0
+       ]
 ];";
        }
 }
index e1070c6..0a6be86 100644 (file)
@@ -374,13 +374,14 @@ class WebInstaller extends Installer {
         * Show an error message in a box. Parameters are like wfMessage(), or
         * alternatively, pass a Message object in.
         * @param string|Message $msg
+        * @param mixed ...$params
         */
-       public function showError( $msg /*...*/ ) {
+       public function showError( $msg, ...$params ) {
                if ( !( $msg instanceof Message ) ) {
-                       $args = func_get_args();
-                       array_shift( $args );
-                       $args = array_map( 'htmlspecialchars', $args );
-                       $msg = wfMessage( $msg, $args );
+                       $msg = wfMessage(
+                               $msg,
+                               array_map( 'htmlspecialchars', $params )
+                       );
                }
                $text = $msg->useDatabase( false )->plain();
                $this->output->addHTML( $this->getErrorBox( $text ) );
@@ -675,9 +676,7 @@ class WebInstaller extends Installer {
         * @param string $msg
         * @return string
         */
-       public function getHelpBox( $msg /*, ... */ ) {
-               $args = func_get_args();
-               array_shift( $args );
+       public function getHelpBox( $msg, ...$args ) {
                $args = array_map( 'htmlspecialchars', $args );
                $text = wfMessage( $msg, $args )->useDatabase( false )->plain();
                $html = $this->parse( $text, true );
@@ -693,10 +692,10 @@ class WebInstaller extends Installer {
        /**
         * Output a help box.
         * @param string $msg Key for wfMessage()
+        * @param mixed ...$params
         */
-       public function showHelpBox( $msg /*, ... */ ) {
-               $args = func_get_args();
-               $html = $this->getHelpBox( ...$args );
+       public function showHelpBox( $msg, ...$params ) {
+               $html = $this->getHelpBox( $msg, ...$params );
                $this->output->addHTML( $html );
        }
 
@@ -705,12 +704,11 @@ class WebInstaller extends Installer {
         * Output looks like a list.
         *
         * @param string $msg
+        * @param mixed ...$params
         */
-       public function showMessage( $msg /*, ... */ ) {
-               $args = func_get_args();
-               array_shift( $args );
+       public function showMessage( $msg, ...$params ) {
                $html = '<div class="config-message">' .
-                       $this->parse( wfMessage( $msg, $args )->useDatabase( false )->plain() ) .
+                       $this->parse( wfMessage( $msg, $params )->useDatabase( false )->plain() ) .
                        "</div>\n";
                $this->output->addHTML( $html );
        }
@@ -1072,12 +1070,10 @@ class WebInstaller extends Installer {
                        if ( $value === null ) {
                                // Checkbox?
                                $this->setVar( $name, false );
+                       } elseif ( stripos( $name, 'password' ) !== false ) {
+                               $this->setPassword( $name, $value );
                        } else {
-                               if ( stripos( $name, 'password' ) !== false ) {
-                                       $this->setPassword( $name, $value );
-                               } else {
-                                       $this->setVar( $name, $value );
-                               }
+                               $this->setVar( $name, $value );
                        }
                }
 
index 456058e..9f80489 100644 (file)
@@ -59,6 +59,7 @@ class WebInstallerComplete extends WebInstallerPage {
 
                $this->parent->restoreLinkPopups();
                $this->endForm( false, false );
+               return '';
        }
 
 }
index f79d272..5241b3c 100644 (file)
@@ -32,6 +32,7 @@ abstract class WebInstallerDocument extends WebInstallerPage {
                $this->parent->output->addWikiTextAsInterface( $text );
                $this->startForm();
                $this->endForm( false );
+               return '';
        }
 
        /**
index 8314fd2..1222ac2 100644 (file)
@@ -28,10 +28,8 @@ class WebInstallerName extends WebInstallerPage {
         */
        public function execute() {
                $r = $this->parent->request;
-               if ( $r->wasPosted() ) {
-                       if ( $this->submit() ) {
-                               return 'continue';
-                       }
+               if ( $r->wasPosted() && $this->submit() ) {
+                       return 'continue';
                }
 
                $this->startForm();
index 4794712..bc25179 100644 (file)
@@ -31,10 +31,8 @@ class WebInstallerOptions extends WebInstallerPage {
                        $this->submitSkins();
                        return 'skip';
                }
-               if ( $this->parent->request->wasPosted() ) {
-                       if ( $this->submit() ) {
-                               return 'continue';
-                       }
+               if ( $this->parent->request->wasPosted() && $this->submit() ) {
+                       return 'continue';
                }
 
                $emailwrapperStyle = $this->getVar( 'wgEnableEmail' ) ? '' : 'display: none';
index a4f031c..28e8784 100644 (file)
@@ -25,10 +25,8 @@ class WebInstallerWelcome extends WebInstallerPage {
         * @return string
         */
        public function execute() {
-               if ( $this->parent->request->wasPosted() ) {
-                       if ( $this->getVar( '_Environment' ) ) {
-                               return 'continue';
-                       }
+               if ( $this->parent->request->wasPosted() && $this->getVar( '_Environment' ) ) {
+                       return 'continue';
                }
                $this->parent->output->addWikiTextAsInterface( wfMessage( 'config-welcome' )->plain() );
                $status = $this->parent->doEnvironmentChecks();
index 73a2525..d04b0f2 100644 (file)
        "config-pcre-no-utf8": "<strong>فادح:</strong> يبدو أن وحدة PCRE في PHP يتم تجميعها بدون دعم PCRE_UTF8، \nيتطلب ميدياويكي دعم UTF-8 ليعمل بشكل صحيح.",
        "config-memory-raised": "<code>memory_limit</code> في PHP $1 ومرتفعة إلى $2.",
        "config-memory-bad": "<strong>تحذير:</strong> في PHP <code>memory_limit</code> $1،\nهذا على الارجح منخفض جدا;\nقد يفشل التثبيت!",
-       "config-apc": "تثبيت [https://secure.php.net/apc APC]",
-       "config-apcu": "[https://secure.php.net/apcu APCu] مثبت",
+       "config-apc": "تثبيت [https://www.php.net/apc APC]",
+       "config-apcu": "[https://www.php.net/apcu APCu] مثبت",
        "config-wincache": "تثبيت [https://www.iis.net/downloads/microsoft/wincache-extension WinCache]",
-       "config-no-cache-apcu": "<strong>تحذير:</strong> تعذر العثور على [https://secure.php.net/apcu APCu] أو [https://www.iis.net/downloads/microsoft/wincache-extension WinCache];\nكائن التخزين المؤقت غير ممكّّن.",
+       "config-no-cache-apcu": "<strong>تحذير:</strong> تعذر العثور على [https://www.php.net/apcu APCu] أو [https://www.iis.net/downloads/microsoft/wincache-extension WinCache];\nكائن التخزين المؤقت غير ممكّّن.",
        "config-mod-security": "<strong>تحذير:</strong> تم تمكين خادم الويب الخاص بك [https://modsecurity.org/ mod_security]/mod_security2، العديد من التكوينات الشائعة له سوف تتسبب في مشاكل لميدياويكي والبرامج الأخرى التي تسمح للمستخدمين بنشر محتوى عشوائي; \nإذا كان ذلك ممكنا، يجب تعطيل هذا، أو يمكنك الرجوع إلى [https://modsecurity.org/documentation/ توثيق mod_security] أو الاتصال بدعم مضيفك إذا واجهتك أخطاء عشوائية.",
        "config-diff3-bad": "أداة جنو diff3 لمقارنة النصوص غير موجودة. يمكنك تجاهل هذا الآن، لكن ربما تصادف تضاربات تحريرية أكثر من المعتاد.",
        "config-git": "العثور على برنامج التحكم في إصدار جت <code>$1</code>.",
        "config-type-oracle": "أوراكل",
        "config-type-mssql": "خادم SQL لميكروسوفت",
        "config-support-info": "ميدياويكي يدعم نظم قواعد البيانات التالية: $1 إذا كنت لا ترى نظام قاعدة البيانات الذي تحاول استخدامه مدرجًا أدناه، اتبع الإرشادات المرتبطة فوق لتمكين الدعم.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] هو الهدف الأساسي لميدياويكي وأفضل دعم له، يعمل ميدياويكي أيضا مع [{{int:version-db-mariadb-url}} MariaDB] و[{{int:version-db-percona-url}} Percona Server]، وهما متوافقان مع MySQL، ([https://secure.php.net/manual/en/mysqli.installation.php كيفية تجميع PHP مع دعم MySQL])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] هو نظام قاعدة بيانات مفتوح المصدر مشهور كبديل لـMySQL ([https://secure.php.net/manual/en/pgsql.installation.php كيفية تجميع PHP مع دعم PostgreSQL])",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] هو نظام قاعدة بيانات خفيف مدعوم بشكل جيد. ([https://secure.php.net/manual/en/pdo.installation.php كيفية ترجمة PHP باستخدام دعم SQLite]، يستخدم PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] هي قاعدة بيانات مؤسسة تجارية. ([https://secure.php.net/manual/en/oci8.installation.php كيفية تجميع PHP مع دعم OCI8])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] هي قاعدة بيانات مؤسسة تجارية لويندوز. ([https://secure.php.net/manual/en/sqlsrv.installation.php كيفية تجميع PHP مع دعم SQLSRV])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] هو الهدف الأساسي لميدياويكي وأفضل دعم له، يعمل ميدياويكي أيضا مع [{{int:version-db-mariadb-url}} MariaDB] و[{{int:version-db-percona-url}} Percona Server]، وهما متوافقان مع MySQL، ([https://www.php.net/manual/en/mysqli.installation.php كيفية تجميع PHP مع دعم MySQL])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] هو نظام قاعدة بيانات مفتوح المصدر مشهور كبديل لـMySQL ([https://www.php.net/manual/en/pgsql.installation.php كيفية تجميع PHP مع دعم PostgreSQL])",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] هو نظام قاعدة بيانات خفيف مدعوم بشكل جيد. ([https://www.php.net/manual/en/pdo.installation.php كيفية ترجمة PHP باستخدام دعم SQLite]، يستخدم PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] هي قاعدة بيانات مؤسسة تجارية. ([https://www.php.net/manual/en/oci8.installation.php كيفية تجميع PHP مع دعم OCI8])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] هي قاعدة بيانات مؤسسة تجارية لويندوز. ([https://www.php.net/manual/en/sqlsrv.installation.php كيفية تجميع PHP مع دعم SQLSRV])",
        "config-header-mysql": "إعدادات MariaDB/MySQL",
        "config-header-postgres": "إعدادات PostgreSQL",
        "config-header-sqlite": "إعدادات SQLite",
        "config-license-help": "يضع العديد من الويكيات العامة جميع المساهمات تحت [https://freedomdefined.org/Definition خصة حرة]، \nوهذا يساعد على خلق شعور بالملكية المجتمعية ويشجع على المساهمة طويلة الأجل، \nليس من الضروري عموما استخدام ويكي خاص أو شركة. \n\nإذا كنت تريد أن تكون قادرا على استخدام النص من ويكيبيديا، وتريد أن تكون ويكيبيديا قادرة على قبول النص الذي تم نسخه من الويكي الخاص بك، فيجب عليك اختيار <strong>{{int:config-license-cc-by-sa}}</strong>. \n\nاستخدمت ويكيبيديا في السابق رخصة جنو للوثائق الحرة، \nGFDL هو ترخيص صالح، ولكن من الصعب فهمه، \nمن الصعب أيضا إعادة استخدام المحتوى المرخص بموجب GFDL.",
        "config-email-settings": "إعدادات البريد الإلكتروني",
        "config-enable-email": "تمكين البريد الإلكتروني الصادرة",
-       "config-enable-email-help": "إذا كنت تريد إرسال بريد إلكتروني إلى العمل، [Config-dbsupport-oracle/manual/en/mail.configuration.php إعدات بريد PHP's] تحتاج لأن يتم تكوينها بشكل صحيح. إذا كنت لا تريد أيا من ميزات البريد الإلكتروني، يمكنك تعطيلها هنا.",
+       "config-enable-email-help": "إذا كنت تريد إرسال بريد إلكتروني إلى العمل، [https://www.php.net/manual/en/mail.configuration.php إعدات بريد PHP] تحتاج لأن يتم تكوينها بشكل صحيح. إذا كنت لا تريد أيا من ميزات البريد الإلكتروني، يمكنك تعطيلها هنا.",
        "config-email-user": "تفعيل البريد الإلكتروني من المستخدم إلى مستخدم آخر",
        "config-email-user-help": "يتيح لكل المستخدمين إرسال رسائل بريد إلكتروني إلى بعضهم البعض إذا فعَّلوا هذا الخيار في تفضيلاتهم.",
        "config-email-usertalk": "فعل إخطارات صفحات نقاش المستخدمين",
        "config-install-done": "<strong>مبروك!</strong>\nلقد قمت بتثبيت ميدياوكي.\n\nقام المثبت بتوليد ملف <code>LocalSettings.php</code>.\nيحتوي هذا الملف على كل تضبيطاتك.\n\nسيتطلب تشغيل الويكي منك تنزيل هذا الملف ووضعه في مجلد التثبيت الخاص بالويكي (نفس المجلد المحتوي على <code>index.php</code>). سيبدأ التنزيل تلقائيا.\n\nلو لم يُعرض عليك التنزيل أو قمت أنت بالغائه، يمكنك تنزيله بالضغط على الوصلة أدناه:\n\n$3\n\n<strong>تنبيه:</strong> لو لم تقم بهذا الآن، لن يكن ملف الضبط متاحا لك لاحقا إذا غادرت التثبيت بدون تنزيله.\n\nعندما تنتهي من وضع الملف بمكانه، يمكنك <strong>[$2 دخول الويكي]</strong>.",
        "config-install-done-path": "<strong>مبروك!</strong>\nلقد قمت بتثبيت ميدياوكي.\n\nقام المثبت بتوليد ملف <code>LocalSettings.php</code>.\nيحتوي هذا الملف على كل تضبيطاتك.\n\nسيتطلب تشغيل الويكي منك تنزيل هذا الملف ووضعه في <code>$4</code> (نفس المجلد المحتوي على index.php). سيبدأ التنزيل تلقائيا.\n\nلو لم يُعرض عليك التنزيل أو قمت أنت بالغائه، يمكنك تنزيله بالضغط على الوصلة أدناه:\n\n$3\n\n<strong>تنبيه:</strong> لو لم تقم بهذا الآن، لن يكن ملف الضبط متاحا لك لاحقا إذا غادرت التثبيت بدون تنزيله.\n\nعندما تنتهي من وضع الملف بمكانه، يمكنك <code>[$2 دخول الويكي]</strong>.",
        "config-install-success": "لقد تم تثبيت ميدياويكي بنجاح; يمكنك الآن \nزيارة <$1$2> لعرض الويكي الخاص بك; \nإذا كانت لديك أسئلة، فاطلع على قائمة الأسئلة الشائعة: \n<https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ>> أو استخدم أحد \nمنتديات الدعم المرتبطة بهذه الصفحة.",
+       "config-install-db-success": "تم إعداد قاعدة البيانات بنجاح",
        "config-download-localsettings": "تنزيل <code>LocalSettings.php</code>",
        "config-help": "مساعدة",
        "config-help-tooltip": "اضغط للتوسيع",
index 73929dd..512f032 100644 (file)
@@ -7,47 +7,47 @@
                        "Crucifunked"
                ]
        },
-       "config-desc": "L'instalador pa MediaWiki",
+       "config-desc": "L'instalador de MediaWiki",
        "config-title": "Instalación de MediaWiki $1",
        "config-information": "Información",
-       "config-localsettings-upgrade": "Detectose un ficheru <code>LocalSettings.php</code>.\nP'anovar esta instalación, escriba'l valor de\n<code>$wgUpgradeKey</code> nel cuadru d'abaxo.\nAlcontraralu en <code>LocalSettings.php</code>.",
-       "config-localsettings-cli-upgrade": "Deteutose un ficheru <code>LocalSettings.php</code>.\nP'anovar esta instalación, execute <code>update.php</code>",
+       "config-localsettings-upgrade": "Deteutóse un ficheru <code>LocalSettings.php</code>.\nP'anovar esta instalación, introduz el valor de <code>$wgUpgradeKey</code> na caxa d'embaxo.\nVas alcontralu en <code>LocalSettings.php</code>.",
+       "config-localsettings-cli-upgrade": "Deteutóse un ficheru <code>LocalSettings.php</code>.\nP'anovar esta instalación, executa <code>update.php</code>",
        "config-localsettings-key": "Clave d'anovamientu:",
        "config-localsettings-badkey": "La clave d'anovamientu que disti ye incorreuta.",
-       "config-upgrade-key-missing": "Deteutose una instalación esistente de MediaWiki.\nP'anovar esta instalación, ponga la llinia siguiente al final del ficheru <code>LocalSettings.php</code>:\n\n$1",
+       "config-upgrade-key-missing": "Deteutóse una instalación esistente de MediaWiki.\nP'anovar esta instalación, pon la llinia de darréu no baxero del ficheru <code>LocalSettings.php</code>:\n\n$1",
        "config-localsettings-incomplete": "Paez que'l ficheru <code>LocalSettings.php</code> esistente ta incompletu.\nLa variable $1 nun ta definida.\nCamude'l ficheru <code>LocalSettings.php</code> pa qu'esta variable quede definida y calque \"{{int:Config-continue}}\".",
        "config-localsettings-connection-error": "Alcontróse un error al conectar cola base de datos usando la configuración especificada en <code>LocalSettings.php</code>. Corrixa esta configuración y vuelva a intentalo.\n\n$1",
-       "config-session-error": "Error al aniciar sesión: $1",
+       "config-session-error": "Fallu al aniciar sesión: $1",
        "config-session-expired": "Paez que caducaron los sos datos de sesión.\nLes sesiones tan configuraes pa tener una duración de $1.\nPue incrementar esto configurando <code>session.gc_maxlifetime</code> en php.ini.\nReanicie'l procesu d'instalación.",
        "config-no-session": "¡Perdiéronse los sos datos de sesión!\nCompruebe php.ini y asegúrese de qu'en <code>session.save_path</code> ta definíu un direutoriu correutu.",
        "config-your-language": "La so llingua:",
-       "config-your-language-help": "Seleicione la llingua a emplegar nel procesu d'instalación.",
+       "config-your-language-help": "Esbilla la llingua a usar nel procesu d'instalación.",
        "config-wiki-language": "Llingua de la wiki:",
        "config-wiki-language-help": "Seleicione la llingua que s'usará preferentemente na wiki.",
        "config-back": "← Atrás",
        "config-continue": "Siguir →",
        "config-page-language": "Llingua",
-       "config-page-welcome": "¡Bienveníu a MediaWiki!",
+       "config-page-welcome": "¡Afáyate en MediaWiki!",
        "config-page-dbconnect": "Conectar cola base de datos",
        "config-page-upgrade": "Anovar instalación esistente",
        "config-page-dbsettings": "Configuración de la base de datos",
        "config-page-name": "Nome",
        "config-page-options": "Opciones",
        "config-page-install": "Instalar",
-       "config-page-complete": "¡Completo!",
+       "config-page-complete": "¡Completóse!",
        "config-page-restart": "Reaniciar la instalación",
        "config-page-readme": "Llei-me",
        "config-page-releasenotes": "Notes de la versión",
        "config-page-copying": "Copiar",
        "config-page-upgradedoc": "Anovando",
        "config-page-existingwiki": "Wiki esistente",
-       "config-help-restart": "¿Quier llimpiar tolos datos guardaos qu'escribió y reaniciar el procesu d'instalación?",
+       "config-help-restart": "¿Quies llimpiar tolos datos guardaos qu'introduxesti y reaniciar el procesu d'instalación?",
        "config-restart": "Sí, reanicialu",
        "config-welcome": "=== Comprobaciones del entornu ===\nAgora van facese unes comprobaciones básiques para ver si l'entornu ye afayadizu pa la instalación de MediaWiki.\nAlcuérdese d'incluir esta información si necesita encontu pa completar la instalación.",
        "config-copyright": "=== Drechos d'autor y condiciones d'usu ===\n\n$1\n\nEsti programa ye software llibre; puedes redistribuilu y/o camudalu baxo les condiciones de la llicencia pública xeneral GNU tal como la publica la Free Software Foundation; versión 2 o (como prefieras) cualquier versión posterior.\n\nEsti programa distribúese cola esperanza de que pueda ser útil, pero <strong>ensin garantía denguna</strong>; nin siquiera la garantía implícita de <strong>comercialidá</strong> o \n<strong>adautación a un fin determináu</strong>.\nVer la Llicencia pública xeneral GNU pa más detalles.\n\nHabríes de tener recibío <doclink href=Copying>una copia de la llicencia pública xeneral GNU</doclink> xunto con esti programa; sinón, escribi a la Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA, o [https://www.gnu.org/copyleft/gpl.html lléila en llinia].",
        "config-sidebar": "* [https://www.mediawiki.org/wiki/MediaWiki/gl Páxina principal de MediaWiki]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Guía del usuariu]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents Guía del alministrador]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ Entrugues frecuentes]\n----\n* <doclink href=Readme>Lléame</doclink>\n* <doclink href=ReleaseNotes>Notes de llanzamientu</doclink>\n* <doclink href=Copying>Copia</doclink>\n* <doclink href=UpgradeDoc>Anovamientu</doclink>",
-       "config-env-good": "Comprobóse l'entornu.\nPue instalar MediaWiki.",
-       "config-env-bad": "Comprobóse l'entornu.\nNun pue instalar MediaWiki.",
+       "config-env-good": "Comprobóse l'entornu.\nPues instalar MediaWiki.",
+       "config-env-bad": "Comprobóse l'entornu.\nNun pues instalar MediaWiki.",
        "config-env-php": "PHP $1 ta instaláu.",
        "config-env-hhvm": "HHVM $1 ta instaláu.",
        "config-unicode-using-intl": "Usando la [https://pecl.php.net/intl estensión intl PECL] pa la normalización Unicode.",
        "config-pcre-no-utf8": "<strong>Erru fatal:</strong> Paez que'l módulu PCRE de PHP foi compiláu ensin el soporte PCRE_UTF8.\nMediaWiki requier compatibilidá con UTF_8 pa furrular correutamente.",
        "config-memory-raised": "El parámetru <code>memory_limit</code> de PHP ye $1. Auméntase a $2.",
        "config-memory-bad": "<strong>Alvertencia:</strong>: el parámetru <code>memory_limit</code> de PHP ye $1.\nProbablemente sía demasiáu baxu.\n¡La instalación puede fallar!",
-       "config-apc": "[https://secure.php.net/apc APC] ta instaláu",
-       "config-apcu": "[https://secure.php.net/apcu APCu] ta instaláu",
+       "config-apc": "[https://www.php.net/apc APC] ta instaláu",
+       "config-apcu": "[https://www.php.net/apcu APCu] ta instaláu",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] ta instaláu",
-       "config-no-cache-apcu": "<strong>Atención:</strong> Nun pudo alcontrase [https://secure.php.net/apcu APCu] o [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nLa caché d'oxetos nun ta activada.",
+       "config-no-cache-apcu": "<strong>Atención:</strong> Nun pudo alcontrase [https://www.php.net/apcu APCu] o [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nLa caché d'oxetos nun ta activada.",
        "config-mod-security": "<strong>Alvertencia:</strong> El to servidor web tien activáu [https://modsecurity.org/mod_security]/mod_security2 .Munches de les sos configuraciones comunes pueden causar problemes a MediaWiki o otru software que dexe a los usuarios publicar conteníu arbitrario. De ser posible, tendríes de desactivalo. Si non, consulta la  [https://modsecurity.org/documentation/ mod_security documentation] o contacta col alministrador del to servidor si atopes erros aleatorios.",
-       "config-diff3-bad": "Nun s'alcontró GNU diff3.",
+       "config-diff3-bad": "Nun s'alcontró la utilidá de comparanza de testos GNU diff3. Pues inorar esto pel momentu pero podríes tener problemes d'edición davezu.",
        "config-git": "Alcontróse'l software de control de versiones Git: <code>$1</code>.",
-       "config-git-bad": "Nun s'alcontró el software de control de versiones Git.",
+       "config-git-bad": "Nun s'alcontró el software de control de versiones Git. Pues inorar esto pel momentu. Decátate que Special:Version nun va amosase nos hashes de los unvios.",
        "config-imagemagick": "ImageMagick atopáu: <code>$1</code>.\nLa miniaturización d'imaxes habilitaráse si habilites les cargues.",
        "config-gd": "Atopóse una biblioteca de gráficos GD integrada.\nLa miniaturización d'imaxes habilitaráse si habilites les xubíes.",
        "config-no-scaling": "Nun s'atopó la biblioteca GD o ImageMagik.\nVa desactivase la miniaturización d'imaxes.",
        "config-using-32bit": "<strong>Atención:</strong> paez que'l sistema funciona con enteros de 32 bits. Esto ta [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:32-bit desaconseyáu].",
        "config-db-type": "Tipu de base de datos:",
        "config-db-host": "Servidor de la base de datos:",
-       "config-db-host-help": "Si'l to servidor de base de datos ta n'otru servidor, escribe'l nome del equipu o la so dirección IP equí.\n\nSi tas utilizando alojamiento web compartíu, el to provisor tendría de date'l nome correctu del servidor na so documentación.\n\nSi vas instalar nun servidor Windows y a utilizar MySQL, l'usu de \"localhost\" como nome del servidor puede nun #funcionar. Si ye asina, intenta poner \"127.0.0.1\" como dirección IP local.\n\nSi utilices PostgreSQL, dexa esti campu vacío pa conectase al traviés d'un socket de Unix.",
+       "config-db-host-help": "Si'l sirvidor de bases de datos ta nun sirvidor diferente, introduz equí la IP o'l nome del agospiu.\n\nSi tas usando un agospiu web compartíu, el so fornidor debió especificar el nome del agospiu na so documentación.\n\nSi tas usando MySQL, usar «localhost» pue nun funcionar pal nome del sirvidor. Si non, prueba «120.0.0.1» pa la direición IP llocal.\n\nSi tas usando PostgreSQL, dexa esti campu baleru pa coneutate per una ralura d'Unix.",
        "config-db-host-oracle": "TNS de la base de datos:",
        "config-db-host-oracle-help": "Escribe un [http://download.oracle.com/docs/cd/B28359_01/network.111/b28317/tnsnames.htm nome de conexón local] válidu; un archivu tnsnames.ora ten de ser visible pa esta instalación.<br />Si tas utilizando biblioteques de veceru 10g o más recién tamién puedes utilizar el métodu de asignación de nomes [http://download.oracle.com/docs/cd/Y11882_01/network.112/y10836/naming.htm Easy Connect].",
        "config-db-wiki-settings": "Identifica esta wiki",
-       "config-db-name": "Nome de base de datos:",
+       "config-db-name": "Nome de la base de datos (ensin guiones):",
        "config-db-name-help": "Escueye un nome qu'identifique la to wiki. Nun tien de contener espacios. \nSi tas utilizando agospiamientu web compartíu, el to provisor va date un nome específicu de base de datos por que lu utilices, o bien va dexate crear bases de datos al traviés d'un panel de control.",
        "config-db-name-oracle": "Esquema de la base de datos:",
        "config-db-account-oracle-warn": "Hai tres escenarios compatibles pa la instalación de Oracle como motor de base de datos:\n\nSi desees crear una cuenta de base de datos como parte del procesu d'instalación, por favor apurre una cuenta con rol SYSDBA como cuenta de base de datos pa la instalación y especifica les credenciales que quies tener pal accesu a la web a la cuenta; d'otra miente, puedes crear manualmente la cuenta d'accesu a la web y suministrar namái esa cuenta (si tien los permisos necesarios pa crear los oxetos d'esquema) o dar dos cuentes distintos, una con privilexos de creación y otra con accesu acutáu a la web\n\nLa secuencia de comandos (script) pa crear una cuenta colos privilexos necesarios puede atopase nel direutoriu \"maintenance/oracle/\" d'esta instalación. Ten en cuenta qu'utilizar una cuenta acutada va desactivar toles capacidaes de caltenimientu cola cuenta predeterminada.",
        "config-db-account-lock": "Usar el mesmu nome d'usuariu y contraseña demientres la operación normal",
        "config-db-wiki-account": "Cuenta d'usuariu pa operar normalmente",
        "config-db-wiki-help": "Escribe'l nome d'usuariu y la contraseña que se van utilizar p'aportar a la base de datos mientres la operación normal de la wiki.\nSi esta cuenta nun esiste y la cuenta d'instalación tien permisos bastante, va crease esta cuenta d'usuariu colos mínimos permisos necesarios pa operar normalmente la wiki.",
-       "config-db-prefix": "Prefixu de tables de la base de datos:",
+       "config-db-prefix": "Prefixu de tables de la base de datos (ensin guiones):",
        "config-db-prefix-help": "Si precises compartir una base de datos ente múltiples wikis, o ente MediaWiki y otra aplicación web, puedes optar por amestar un prefixu a tolos nomes de tabla pa evitar conflictos.\nNun utilices espacios.\n\nDe normal déxase esti campu vacío.",
        "config-mysql-old": "Precísase MySQL $1 o posterior. Tienes $2.",
        "config-db-port": "Puertu de la base de datos:",
-       "config-db-schema": "Esquema pa MediaWiki:",
+       "config-db-schema": "Esquema pa MediaWiki (ensin guiones):",
        "config-db-schema-help": "Esti esquema de vezu va tar bien.\nCamúdalos solo si sabes que lo precises.",
        "config-pg-test-error": "Nun puede coneutase cola base de datos <strong>$1</strong>: $2",
        "config-sqlite-dir": "Direutoriu de datos SQLite:",
        "config-oracle-def-ts": "Espaciu de tables predetermináu:",
        "config-oracle-temp-ts": "Espaciu de tables temporal:",
        "config-type-mysql": "MariaDB, MySQL o compatible",
+       "config-type-postgres": "PostgreSQL",
+       "config-type-sqlite": "SQLite",
+       "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki ye compatible colos siguientes sistemes de bases de datos:\n\n$1\n\nSi nun atopes na llista el sistema de base de datos que tas intentando utilizar, sigue les instrucciones enllazaes enriba p'activar la compatibilidá.",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] ye un sistema comercial de base de datos empresariales pa Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php Cómo compilar PHP con compatibilidá pa SQLSRV])",
-       "config-header-mysql": "Configuración de MariaDB/MySQL",
-       "config-header-postgres": "Configuración de PostgreSQL",
-       "config-header-sqlite": "Configuración de SQLite",
-       "config-header-oracle": "Configuración d'Oracle",
-       "config-header-mssql": "Configuración de Microsoft SQL Server",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] ye un sistema comercial de base de datos empresariales pa Windows. ([https://www.php.net/manual/en/sqlsrv.installation.php Cómo compilar PHP con compatibilidá pa SQLSRV])",
+       "config-header-mysql": "Axustes de MariaDB/MySQL",
+       "config-header-postgres": "Axustes de PostgreSQL",
+       "config-header-sqlite": "Axustes de SQLite",
+       "config-header-oracle": "Axustes d'Oracle",
+       "config-header-mssql": "Axustes de Microsoft SQL Server",
        "config-invalid-db-type": "Triba non válida de base de datos.",
-       "config-missing-db-name": "Tienes d'introducir un valor pa «{{int:config-db-name}}».",
-       "config-missing-db-host": "Tienes d'escribir un valor pa «{{int:config-db-host}}».",
-       "config-missing-db-server-oracle": "Tienes d'escribir un valor pa «{{int:config-db-host-oracle}}».",
+       "config-missing-db-name": "Has introducir un valor pa «{{int:config-db-name}}».",
+       "config-missing-db-host": "Has introducir un valor pa «{{int:config-db-host}}».",
+       "config-missing-db-server-oracle": "Has introducir un valor pa «{{int:config-db-host-oracle}}».",
        "config-invalid-db-server-oracle": "TNS inválidu pa la base de datos «$1».\nUsa una cadena «TNS Name» o «Easy Connect» ([http://docs.oracle.com/cd/E11882_01/network.112/e10836/naming.htm Métodos de nomenclatura d'Oracle]).",
        "config-invalid-db-name": "Nome inválidu de la base de datos «$1».\nUsa sólo lletres ASCII (a-z, A-Z), númberos (0-9), guiones baxos (_) y guiones (-).",
        "config-invalid-db-prefix": "Prefixu inválidu pa la base de datos «$1».\nUsa sólo lletres ASCII (a-z, A-Z), númberos (0-9), guiones baxos (_) y guiones (-).",
-       "config-connection-error": "$1.\n\nComprueba'l sirvidor, el nome d'usuariu y la contraseña, y tenta nuevamente.",
+       "config-connection-error": "$1.\n\nComprueba'l sirvidor, el nome d'usuariu y la contraseña, y tenta nuevamente.Si uses \"localhost\" como sirvidor de base de datos, tenta usando \"127.0.0.1\" nel so llugar (o viceversa).",
        "config-invalid-schema": "Esquema inválidu «$1» pa MediaWiki.\nUsa sólo lletres ASCII (a-z, A-Z), númberos (0-9) y guiones baxos (_).",
-       "config-db-sys-create-oracle": "L'instalador sólo almite l'emplegu d'una cuenta SYSDBA pa crear una cuenta nueva.",
+       "config-db-sys-create-oracle": "L'instalador namái sofita l'usu d'una cuenta SYSDBA pa la creación d'otra cuenta nueva.",
        "config-db-sys-user-exists-oracle": "La cuenta d'usuariu «$1» yá esiste. ¡SYSDBA sólo puede utilizase pa crear una nueva cuenta!",
        "config-postgres-old": "Ríquese PostgreSQL $1 o posterior. Tienes la versión $2.",
        "config-mssql-old": "Ríquese Microsoft SQL Server $1 o posterior. Tienes la versión $2.",
        "config-db-web-create": "Crear la cuenta si nun esiste yá",
        "config-db-web-no-create-privs": "La cuenta qu'especificasti pa la instalación nun tien permisos abondo pa crear una cuenta.\nLa cuenta qu'especifiques equí yá tien d'esistir.",
        "config-mysql-engine": "Motor d'almacenamientu:",
-       "config-mysql-innodb": "InnoDB (recomendao)",
+       "config-mysql-innodb": "InnoDB (aconséyase)",
        "config-mysql-myisam": "MyISAM",
        "config-mssql-auth": "Triba d'autenticación:",
        "config-mssql-sqlauth": "Autenticación de SQL Server",
        "config-admin-password-confirm": "Repiti la contraseña:",
        "config-admin-help": "Escribe equí'l nome d'usuariu que desees, como por casu \"Nel Bloggs\".\nEsti ye'l nome que vas usar pa entrar na wiki.",
        "config-admin-name-blank": "Escribe'l nome d'usuariu d'un alministrador.",
+       "config-admin-password-mismatch": "Les dos contraseñes qu'introduxesti nun concasen.",
        "config-optional-skip": "Yá toi aburríu, namái instala la wiki.",
        "config-profile-wiki": "Wiki públicu",
        "config-profile-no-anon": "Ríquese crear una cuenta",
        "config-license-cc-choose": "Escoyer una llicencia Creative Commons  personalizada",
        "config-email-settings": "Configuración de corréu electrónicu",
        "config-enable-email": "Activar el corréu electrónicu de salida",
-       "config-enable-email-help": "Si quies que'l corréu electrónicu funcione, les [https://secure.php.net/manual/en/mail.configuration.php preferencies de corréu de PHP] tienen de tar configuraes correutamente.\nSi nun quies les funciones de corréu electrónicu, puedes desactivales equí.",
+       "config-enable-email-help": "Si quies que'l corréu electrónicu funcione, les [https://www.php.net/manual/en/mail.configuration.php preferencies de corréu de PHP] tienen de tar configuraes correutamente.\nSi nun quies les funciones de corréu electrónicu, puedes desactivales equí.",
        "config-email-user": "Activar el corréu electrónicu ente usuarios",
        "config-logo": "URL del logo:",
        "config-instantcommons": "Activar Instant Commons",
+       "config-advanced-settings": "Configuración avanzada",
        "config-extensions": "Estensiones",
-       "config-skins": "Apariencies",
+       "config-skins": "Estilos",
        "config-skins-help": "Deteutáronse les apariencies de la llista anterior nel direutoriu <code>./skins</code>. Tienes d'activar siquier una, y escoyer la predeterminada.",
        "config-skins-use-as-default": "Utilizar esta apariencia como predeterminada",
        "config-skins-missing": "Nun s'atopó nenguna apariencia; MediaWiki utilizará una apariencia de respaldu hasta qu'instales delles apariencies afayadices.",
-       "config-skins-must-enable-some": "Tienes d'escoyer polo meno una apariencia p'activar.",
+       "config-skins-must-enable-some": "Has escoyer polo menos un estilu p'activar.",
        "config-skins-must-enable-default": "L'apariencia escoyida como predeterminada tien de tar activada.",
        "config-install-step-done": "fecho",
        "config-install-step-failed": "falló",
        "config-install-interwiki": "Enllenando la tabla d'interwiki predeterminada",
        "config-install-interwiki-list": "Nun pudo lleese'l ficheru <code>interwiki.list</code>.",
        "config-download-localsettings": "Descargar <code>LocalSettings.php</code>",
-       "config-help": "Ayuda",
+       "config-help": "ayuda",
        "config-nofile": "Nun pudo atopase'l ficheru \"$1\". ¿Desaniciose?",
        "config-skins-screenshots": "$1 (imaxes de pantalla: $2)",
+       "config-skins-screenshot": "$1 ($2)",
+       "config-extensions-requires": "$1 (rique $2)",
        "config-screenshot": "imaxe de pantalla",
        "mainpagetext": "<strong>Instalóse MediaWiki.</strong>",
        "mainpagedocfooter": "Consulta la [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Guía del usuariu] pa saber cómo usar el software wiki.\n\n== Primeros pasos ==\n\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Llista de les opciones de configuración]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ EMF de MediaWiki]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Llista de corréu de llanzamientos de MediaWiki]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Llocaliza MediaWiki na to llingua]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Depriende como combatir la puxarra na to wiki]"
index bfe2ca4..e0d2bc9 100644 (file)
@@ -67,9 +67,9 @@
        "config-pcre-no-utf8": "'''Фаталь хата'''. PHP өсөн PCRE модуле  PCRE_UTF8 менән яраҡлыштырылмаған.\nMediaWiki дөрөҫ эшләһен өсөн UTF-8 талап ителә.",
        "config-memory-raised": "Хәтер сикләнгән PHP  (<code>memory_limit</code>)  $1  $2 тиклем арттырылған.",
        "config-memory-bad": "'''Иғтибар:''' PHP күләме <code>memory_limit</code> $1 тәшкил итә.\nБәлки, был саманан тыш аҙҙыр. \nҠуйылыштың уңышһыҙлыҡҡа осрауы бар!",
-       "config-apc": "[https://secure.php.net/apc APC] урынлаштырылды",
+       "config-apc": "[https://www.php.net/apc APC] урынлаштырылды",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] урынлыштырылды",
-       "config-no-cache-apcu": "'''Иғтибар:'''  [https://secure.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] табылманы йәки [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nОбъекттарҙы кэшлау һүндереләсәк..",
+       "config-no-cache-apcu": "'''Иғтибар:'''  [https://www.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] табылманы йәки [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nОбъекттарҙы кэшлау һүндереләсәк..",
        "config-mod-security": "<strong>Иғтибар</strong>: һеҙҙең веб-серверығыҙҙа [https://modsecurity.org/ mod_security]/mod_security2 ҡабыҙылған. Уның күп кенә стандарт көйләүҙәре MediaWiki йәки бүтән ПО ҡулланыусыларға серверға ирекле контент ебәрегрә мөмкинлек буйынса проблемалар тыуҙырыуы мөмкин.\nКөтөлмәгән хаталарға тап булһағыҙ, ошонда [https://modsecurity.org/documentation/ документации mod_security]йәки үҙегеҙҙең хостинг-провайдерығыҙға мөрәжәғәт итегеҙ.",
        "config-diff3-bad": "GNU diff3 табылманы.",
        "config-git": "Git өлгөләрҙе контролләү системаһы табылды: <code>$1</code>.",
        "config-type-mysql": "MySQL (йәки тура килгән)",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki -ла түбәндәге СУБД бар:\n\n$1\n\nӘгәр мәғлүмәт һаҡлау системаһын исемлектә күрмәһәгеҙ, рөхсәт алыу өсөн өҫтәге һылтанмалағы инструкция буйынса эш итегеҙ.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] — MediaWiki-ҙың иҫ яҡшы эшләгән төп мәғлүмәттәр базаһы.  MediaWiki шулай уҡ MySQL-тап килгән [{{int:version-db-mariadb-url}} MariaDB] һәм [{{int:version-db-percona-url}} Percona Server] менән эшләй. ([https://secure.php.net/manual/ru/mysql.installation.php MySQL-ярҙамында PHP туплау инструкцияһы])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] —  СУБД-ның популяр открыткаһы, MySQL өсөн альтернатива.\nТөҙәтелмәгән хаталар булыуы мөмкин, эш схемаһында ҡулланыу тәҡдим ителмәй. ([https://secure.php.net/manual/en/pgsql.installation.php  PostgreSQL рөхсәт ителгән РНР йыйыу инструкцияһы]).",
+       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] — MediaWiki-ҙың иҫ яҡшы эшләгән төп мәғлүмәттәр базаһы.  MediaWiki шулай уҡ MySQL-тап килгән [{{int:version-db-mariadb-url}} MariaDB] һәм [{{int:version-db-percona-url}} Percona Server] менән эшләй. ([https://www.php.net/manual/ru/mysql.installation.php MySQL-ярҙамында PHP туплау инструкцияһы])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] —  СУБД-ның популяр открыткаһы, MySQL өсөн альтернатива.\nТөҙәтелмәгән хаталар булыуы мөмкин, эш схемаһында ҡулланыу тәҡдим ителмәй. ([https://www.php.net/manual/en/pgsql.installation.php  PostgreSQL рөхсәт ителгән РНР йыйыу инструкцияһы]).",
        "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] — яҡшы һәм еңел мәғлүмәт базаһы системаһы. ([http://www.php.net/manual/ru/pdo.installation.php  собрать PHP  SQLite]  PDO менән эшләй торған инструкция)",
        "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] — предприятие масштабындаға коммерция базыһы. ([http://www.php.net/manual/ru/oci8.installation.php OCI8 ярҙамындағы РНР нисек йыйырға])",
-       "config-dbsupport-mssql": "* [{{int:version-db-oracle-url}} Oracle] — предприятие масштабындаға Windows өсөн коммерция базыһы. ([https://secure.php.net/manual/en/sqlsrv.installation.php OCI8 ярҙамындағы РНР нисек йыйырға])",
+       "config-dbsupport-mssql": "* [{{int:version-db-oracle-url}} Oracle] — предприятие масштабындаға Windows өсөн коммерция базыһы. ([https://www.php.net/manual/en/sqlsrv.installation.php OCI8 ярҙамындағы РНР нисек йыйырға])",
        "config-header-mysql": "MySQL көйләү",
        "config-header-postgres": "PostgreSQL көйләү",
        "config-header-sqlite": "SQLite көйләү",
index 0e83199..65743df 100644 (file)
        "config-pcre-no-utf8": "'''Фатальная памылка''': модуль PCRE для PHP скампіляваны без падтрымкі PCRE_UTF8.\nMediaWiki патрабуе падтрымкі UTF-8 для слушнай працы.",
        "config-memory-raised": "Абмежаваньне на даступную для PHP памяць <code>memory_limit</code> было падвышанае з $1 да $2.",
        "config-memory-bad": "'''Папярэджаньне:''' памер PHP <code>memory_limit</code> складае $1.\nВерагодна, гэта вельмі мала.\nУсталяваньне можа быць няўдалым!",
-       "config-apc": "[https://secure.php.net/apc APC] усталяваны",
-       "config-apcu": "[https://secure.php.net/apcu APCu] ўсталяваны",
+       "config-apc": "[https://www.php.net/apc APC] усталяваны",
+       "config-apcu": "[https://www.php.net/apcu APCu] ўсталяваны",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] усталяваны",
-       "config-no-cache-apcu": "<strong>Папярэджаньне:</strong> ня знойдзеныя [https://secure.php.net/apcu APCu] ці [https://www.iis.net/downloads/microsoft/wincache-extension WinCache]. Кэшаваньне аб’ектаў адключанае.",
+       "config-no-cache-apcu": "<strong>Папярэджаньне:</strong> ня знойдзеныя [https://www.php.net/apcu APCu] ці [https://www.iis.net/downloads/microsoft/wincache-extension WinCache]. Кэшаваньне аб’ектаў адключанае.",
        "config-mod-security": "'''Папярэджаньне''': на Вашым ўэб-сэрверы ўключаны [https://modsecurity.org/ mod_security]. У выпадку няслушнай наладцы, ён можа стаць прычынай праблемаў для MediaWiki ці іншага праграмнага забесьпячэньня, якое дазваляе ўдзельнікам дасылаць на сэрвэр любы зьмест.\nГлядзіце [https://modsecurity.org/documentation/ дакумэнтацыю mod_security] ці зьвярніцеся ў падтрымку Вашага хосту, калі ў Вас узьнікаюць выпадковыя праблемы.",
        "config-diff3-bad": "Праграма параўнаньня тэксту GNU diff3 ня знойдзеная. Вы можаце праігнараваць гэта, але можаце сутыкнуцца з канфліктамі рэдагаваньня больш часта.",
        "config-git": "Знойдзеная сыстэма канстролю вэрсіяў Git: <code>$1</code>",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki падтрымлівае наступныя сыстэмы базаў зьвестак:\n\n$1\n\nКалі Вы ня бачыце сыстэму базаў зьвестак, якую Вы спрабуеце выкарыстоўваць ў сьпісе ніжэй, перайдзіце па спасылцы інструкцыі, якая знаходзіцца ніжэй, каб уключыць падтрымку.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] зьяўляецца галоўнай мэтай MediaWiki і падтрымліваецца найлепш. MediaWiki таксама працуе з [{{int:version-db-mysql-url}} MySQL] і [{{int:version-db-percona-url}} Percona Server], якія сумяшчальныя з MariaDB. ([https://secure.php.net/manual/en/mysqli.installation.php Як скампіляваць PHP з падтрымкай MySQL])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] — папулярная сыстэма базы зьвестак з адкрытым кодам, якая зьяўляецца альтэрнатывай MySQL. ([https://secure.php.net/manual/en/pgsql.installation.php Як кампіляваць PHP з падтрымкай PostgreSQL])",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] — невялікая сыстэма базы зьвестак, якая мае вельмі добрую падтрымку. ([https://secure.php.net/manual/en/pdo.installation.php Як кампіляваць PHP з падтрымкай SQLite], выкарыстоўвае PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] зьяўляецца камэрцыйнай прафэсійнай базай зьвестак. ([https://secure.php.net/manual/en/oci8.installation.php Як скампіляваць PHP з падтрымкай OCI8])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] — камэрцыйная база зьвестак для Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php Як скампіляваць PHP з падтрымкай SQLSRV])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] зьяўляецца галоўнай мэтай MediaWiki і падтрымліваецца найлепш. MediaWiki таксама працуе з [{{int:version-db-mysql-url}} MySQL] і [{{int:version-db-percona-url}} Percona Server], якія сумяшчальныя з MariaDB. ([https://www.php.net/manual/en/mysqli.installation.php Як скампіляваць PHP з падтрымкай MySQL])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] — папулярная сыстэма базы зьвестак з адкрытым кодам, якая зьяўляецца альтэрнатывай MySQL. ([https://www.php.net/manual/en/pgsql.installation.php Як кампіляваць PHP з падтрымкай PostgreSQL])",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] — невялікая сыстэма базы зьвестак, якая мае вельмі добрую падтрымку. ([https://www.php.net/manual/en/pdo.installation.php Як кампіляваць PHP з падтрымкай SQLite], выкарыстоўвае PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] зьяўляецца камэрцыйнай прафэсійнай базай зьвестак. ([https://www.php.net/manual/en/oci8.installation.php Як скампіляваць PHP з падтрымкай OCI8])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] — камэрцыйная база зьвестак для Windows. ([https://www.php.net/manual/en/sqlsrv.installation.php Як скампіляваць PHP з падтрымкай SQLSRV])",
        "config-header-mysql": "Налады MariaDB/MySQL",
        "config-header-postgres": "Налады PostgreSQL",
        "config-header-sqlite": "Налады SQLite",
        "config-license-help": "Шматлікія адкрытыя вікі публікуюць увесь унёсак у праект на ўмовах [https://freedomdefined.org/Definition вольнай ліцэнзіі].\nГэта дазваляе ствараць эфэкт супольнай уласнасьці і садзейнічае доўгатэрміноваму ўнёску.\nДля прыватных і карпаратыўных вікі гэта не зьяўляецца неабходнасьцю.\n\nКалі Вы жадаеце выкарыстоўваць тэкст зь Вікіпэдыі, і жадаеце, каб Вікіпэдыя магла прымаць тэксты, скапіяваныя з Вашай вікі, Вам неабходна выбраць ліцэнзію <strong>{{int:config-license-cc-by-sa}}</strong>.\n\nРаней Вікіпэдыя выкарыстоўвала ліцэнзію GNU Free Documentation.\nЯна ўсё яшчэ дзейнічае, але яна ўтрымлівае некаторыя моманты, якія ўскладняюць паўторнае выкарыстаньне і інтэрпрэтацыю матэрыялаў.",
        "config-email-settings": "Налады электроннай пошты",
        "config-enable-email": "Дазволіць выходзячыя электронныя лісты",
-       "config-enable-email-help": "Калі вы жадаеце, каб працавала электронная пошта, неабходна сканфігураваць PHP [https://secure.php.net/manual/en/mail.configuration.php адпаведным чынам].\nКалі вы не жадаеце выкарыстоўваць магчымасьці электроннай пошты, вы можаце іх адключыць тут.",
+       "config-enable-email-help": "Калі вы жадаеце, каб працавала электронная пошта, неабходна сканфігураваць PHP [https://www.php.net/manual/en/mail.configuration.php адпаведным чынам].\nКалі вы не жадаеце выкарыстоўваць магчымасьці электроннай пошты, вы можаце іх адключыць тут.",
        "config-email-user": "Дазволіць электронную пошту для сувязі паміж удзельнікамі",
        "config-email-user-help": "Дазволіць усім удзельнікам дасылаць адзін аднаму электронныя лісты, калі ўключаная адпаведная магчымасьць ў іх наладах.",
        "config-email-usertalk": "Уключыць абвяшчэньні пра паведамленьні на старонцы абмеркаваньня",
        "config-install-done": "<strong>Віншуем!</strong>\nВы ўсталявалі MediaWiki.\n\nПраграма ўсталяваньня стварыла файл <code>LocalSettings.php</code>.\nЁн утрымлівае ўсе Вашыя налады.\n\nВам неабходна загрузіць яго і захаваць у карэнную дырэкторыю Вашай вікі (у тую ж самую дырэкторыю, дзе знаходзіцца index.php). Загрузка павінна пачацца аўтаматычна.\n\nКалі загрузка не пачалася, ці Вы яе адмянілі, Вы можаце перазапусьціць яе націснуўшы на спасылку ніжэй:\n\n$3\n\n<strong>Заўвага</strong>: калі Вы гэтага ня зробіце зараз, то створаны файл ня будзе даступны Вам потым, калі Вы выйдзеце з праграмы ўсталяваньня безь яго загрузкі.\n\nКалі Вы гэта зробіце, Вы можаце <strong>[$2 ўвайсьці ў Вашую вікі]</strong>.",
        "config-install-done-path": "<strong>Віншуем!</strong>\nВы ўсталявалі MediaWiki.\n\nПраграма ўсталёўкі стварыла файл <code>LocalSettings.php</code>. Ён утрымлівае ўсе вашыя налады.\n\nВам трэба спампаваць яго і пакласьці ў <code>$4</code>. Спампоўка павінна пачацца аўтаматычна.\n\nКалі спампоўка не пачалася або вы адмянілі яе, вы можаце пачаць яе наноў, калі націсьніце на наступную спасылку:\n\n$3\n\n<strong>Заўвага:</strong> Калі вы ня зробіце гэта зараз, то створаны файл ня будзе даступны вам па выхадзе з праграмы безь яго спампоўкі.\n\nКалі вы зробіце гэта, вы можаце <strong>[$2 ўвайсьці ў вашую вікі]</strong>.",
        "config-install-success": "MediaWiki была пасьпяхова ўсталяваная. Цяпер вы можаце наведаць <$1$2>, каб пабачыць вашую вікі. Калі вы маеце пытаньні, сьпярша паглядзіце сьпіс адказаў на частыя пытаньні: <https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ> ці скарыстайцеся адным з форумаў падтрымкі, пазначаных на гэтай старонцы.",
+       "config-install-db-success": "База зьвестак была пасьпяхова наладжаная",
        "config-download-localsettings": "Загрузіць <code>LocalSettings.php</code>",
        "config-help": "дапамога",
        "config-help-tooltip": "націсьніце, каб разгарнуць",
index 4e9ae3b..8074a14 100644 (file)
        "config-pcre-no-utf8": "<strong>Фатално:</strong> Модулът PCRE на PHP изглежда е компилиран без поддръжка на PCRE_UTF8.\nЗа да функционира правилно, МедияУики изисква поддръжка на UTF-8.",
        "config-memory-raised": "<code>memory_limit</code> на PHP е $1, увеличаване до $2.",
        "config-memory-bad": "<strong>Внимание:</strong> <code>memory_limit</code> на PHP е $1.\nСтойността вероятно е твърде ниска.\nВъзможно е инсталацията да се провали!",
-       "config-apc": "[https://secure.php.net/apc APC] е инсталиран",
-       "config-apcu": "[https://secure.php.net/apcu APCu] е инсталиран",
+       "config-apc": "[https://www.php.net/apc APC] е инсталиран",
+       "config-apcu": "[https://www.php.net/apcu APCu] е инсталиран",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] е инсталиран",
-       "config-no-cache-apcu": "<strong>Внимание:</strong> [https://secure.php.net/apcu APCu] и [https://www.iis.net/downloads/microsoft/wincache-extension WinCache] не могат да бъдат открити.\nКеширането на обекти не е активирано.",
+       "config-no-cache-apcu": "<strong>Внимание:</strong> [https://www.php.net/apcu APCu] и [https://www.iis.net/downloads/microsoft/wincache-extension WinCache] не могат да бъдат открити.\nКеширането на обекти не е активирано.",
        "config-mod-security": "<strong>Предупреждение:</strong> [https://modsecurity.org/ mod_security]/mod_security2 е включено на вашия уеб сървър. Много от обичайните му конфигурации пораждат проблеми с МедияУики и друг софтуер, който позволява публикуване на произволно съдържание.\nАко е възможно, моля изключете го. В противен случай се обърнете към [https://modsecurity.org/documentation/ документацията на mod_security] или се свържете с поддръжката на хостинга си, ако се сблъскате със случайни грешки.",
        "config-diff3-bad": "Инструментът за сравняване на текст GNU diff3 не беше намерен. Можете да игнорирате това за сега, но конфликтите при редактиране може да бъдат по-чести.",
        "config-git": "Налична е системата за контрол на версиите Git: <code>$1</code>.",
-       "config-git-bad": "Не е намерен софтуер за контрол на версиите Git.",
+       "config-git-bad": "Не е намерен софтуер за контрол на версиите Git. Може да игнорирате това. Забележете, че Специални:Версия няма да покаже хешове на къмит.",
        "config-imagemagick": "Открит е ImageMagick: <code>$1</code>.\nПреоразмеряването на картинки ще бъде включено ако качването на файлове бъде разрешено.",
        "config-gd": "Открита е вградена графичната библиотека GD.\nАко качването на файлове бъде включено, ще бъде включена възможността за преоразмеряване на картинки.",
        "config-no-scaling": "Не са открити библиотеките GD или ImageMagick.\nПреоразмеряването на картинки ще бъде изключено.",
@@ -85,7 +85,7 @@
        "config-using-32bit": "<strong>Внимание:</strong> изглежда, че системата Ви работи с 32-битови числа. Това [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:32-bit не се препоръчва].",
        "config-db-type": "Тип на базата от данни:",
        "config-db-host": "Сървър на базата от данни:",
-       "config-db-host-help": "Ако базата от данни е на друг сървър, в кутията се въвежда името на хоста или IP адреса.\n\nАко се използва споделен уеб хостинг, доставчикът на услугата би трябвало да е предоставил в документацията си коректния хост.\n\nАко инсталацията протича на Windows-сървър и се използва MySQL, използването на \"localhost\" може да е неприемливо. В такива случаи се използва \"127.0.0.1\" за локален IP адрес.\n\nПри използване на PostgreSQL, това поле се оставя празно, за свързване чрез Unix socket.",
+       "config-db-host-help": "Ако базата от данни е на друг сървър, в кутията се въвежда името на хоста или IP адреса.\n\nАко се използва споделен уеб хостинг, доставчикът на услугата би трябвало да е предоставил в документацията си коректния хост.\n\nАко се използва MySQL, използването на „localhost“ може да е неприемливо. В такива случаи се използва „127.0.0.1“ за локален IP адрес.\n\nПри използване на PostgreSQL, това поле се оставя празно, за свързване чрез Unix socket.",
        "config-db-host-oracle": "TNS на базата от данни:",
        "config-db-host-oracle-help": "Въведете валидно [http://download.oracle.com/docs/cd/B28359_01/network.111/b28317/tnsnames.htm Local Connect Name]. Файлът tnsnames.ora трябва да бъде видим за инсталацията.<br />Ако използвате клиентска библиотека версия 10g или по-нова можете да използвате метода [http://download.oracle.com/docs/cd/E11882_01/network.112/e10836/naming.htm Easy Connect].",
        "config-db-wiki-settings": "Идентифициране на това уики",
        "config-type-mysql": "MariaDB, MySQL (или съвместима)",
        "config-type-mssql": "Microsoft SQL сървър",
        "config-support-info": "МедияУики поддържа следните системи за бази от данни:\n\n$1\n\nАко не виждате желаната за използване система в списъка по-долу, следвайте инструкциите за активиране на поддръжка по-горе.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] е най-важна за МедияУики и се поддържа най-добре. МедияУики работи също така с [{{int:version-db-mysql-url}} MySQL] и [{{int:version-db-percona-url}} Percona Server], които са съвместими с MariaDB.\n([https://secure.php.net/manual/en/mysqli.installation.php Как се компилира PHP с поддръжка на MySQL])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] е популярна система за управление на бази от данни, алтернатива на MySQL. ([https://secure.php.net/manual/bg/pgsql.installation.php Как се компилира PHP с поддръжка на PostgreSQL])",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] е олекотена система за бази от данни, която е много добре поддържана. ([https://secure.php.net/manual/en/pdo.installation.php Как се компилира PHP с поддръжка на SQLite], използва PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] е комерсиална корпоративна база от данни. ([https://secure.php.net/manual/en/oci8.installation.php Как се компилира PHP с поддръжка на OCI8])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] е комерсиална корпоративна база от данни за Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php Как да се компилира PHP с поддръжка на SQLSRV])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] е най-важна за МедияУики и се поддържа най-добре. МедияУики работи също така с [{{int:version-db-mysql-url}} MySQL] и [{{int:version-db-percona-url}} Percona Server], които са съвместими с MariaDB.\n([https://www.php.net/manual/en/mysqli.installation.php Как се компилира PHP с поддръжка на MySQL])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] е популярна система за управление на бази от данни, алтернатива на MySQL. ([https://www.php.net/manual/bg/pgsql.installation.php Как се компилира PHP с поддръжка на PostgreSQL])",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] е олекотена система за бази от данни, която е много добре поддържана. ([https://www.php.net/manual/en/pdo.installation.php Как се компилира PHP с поддръжка на SQLite], използва PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] е комерсиална корпоративна база от данни. ([https://www.php.net/manual/en/oci8.installation.php Как се компилира PHP с поддръжка на OCI8])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] е комерсиална корпоративна база от данни за Windows. ([https://www.php.net/manual/en/sqlsrv.installation.php Как да се компилира PHP с поддръжка на SQLSRV])",
        "config-header-mysql": "Настройки на MariaDB/MySQL",
        "config-header-postgres": "Настройки за PostgreSQL",
        "config-header-sqlite": "Настройки за SQLite",
        "config-invalid-db-server-oracle": "Невалиден TNS на базата от данни „$1“.\nИзползвайте „TNS Name“ или „Easy Connect“ ([http://docs.oracle.com/cd/E11882_01/network.112/e10836/naming.htm Методи за именуване на Oracle])",
        "config-invalid-db-name": "Невалидно име на базата от данни „$1“.\nИзползват се само ASCII букви (a-z, A-Z), цифри (0-9), долни черти (_) и тирета (-).",
        "config-invalid-db-prefix": "Невалидна представка за базата от данни „$1“.\nПозволени са само ASCII букви (a-z, A-Z), цифри (0-9), долни черти (_) и тирета (-).",
-       "config-connection-error": "$1.\n\nНеобходимо е да се проверят хостът, потребителското име и паролата, след което да се опита отново.",
+       "config-connection-error": "$1.\n\nНеобходимо е да се проверят хостът, потребителското име и паролата, след което да се опита отново. Ако използвате „localhost“ като хост на базата от данни, опитайте с „127.0.0.1“ вместо него (и обратно).",
        "config-invalid-schema": "Невалидна схема за МедияУики „$1“.\nДопустими са само ASCII букви (a-z, A-Z), цифри (0-9) и долни черти (_).",
        "config-db-sys-create-oracle": "Инсталаторът поддържа само сметка SYSDBA за създаване на нова сметка.",
        "config-db-sys-user-exists-oracle": "Потребителската сметка „$1“ вече съществува. SYSDBA може да се използва само за създаване на нова сметка!",
        "config-license-help": "Много публични уикита поставят всички приноси под [https://freedomdefined.org/Definition/Bg свободен лиценз].\nТова помага за създаването на усещане за общност и насърчава дългосрочните приноси. \nТова не е необходимо като цяло за частно или корпоративно уики.\n\nАко искате да използвате текстове от Уикипедия, и искате Уикипедия да може да приема текстове, копирани от вашето уики, трябва да изберете лиценз <strong>{{int:config-license-cc-by-sa}}</strong>.\n\nЛицензът за свободна документация на GNU е старият лиценз на съдържанието на Уикипедия.\nТой все още е валиден лиценз, но някои негови условия са трудни за разбиране и правят по-сложни повторното използване и интерпретацията.",
        "config-email-settings": "Настройки за е-поща",
        "config-enable-email": "Разрешаване на изходящи е-писма",
-       "config-enable-email-help": "За да работят възможностите за използване на е-поща, необходимо е [https://secure.php.net/manual/en/mail.configuration.ph настройките за поща на PHP] да бъдат конфигурирани правилно.\nАко няма да се използват услугите за е-поща в уикито, те могат да бъдат изключени тук.",
+       "config-enable-email-help": "За да работят възможностите за използване на е-поща, необходимо е [https://www.php.net/manual/en/mail.configuration.ph настройките за поща на PHP] да бъдат конфигурирани правилно.\nАко няма да се използват услугите за е-поща в уикито, те могат да бъдат изключени тук.",
        "config-email-user": "Позволяване на потребителите да си изпращат е-писма през уикито",
        "config-email-user-help": "Позволяване на потребителите да си изпращат е-писма ако са разрешили това в настройките си.",
        "config-email-usertalk": "Оповестяване при промяна на потребителската беседа",
index 9df3c8b..2392f73 100644 (file)
@@ -45,8 +45,8 @@
        "config-env-php": "পিএইচপি $1 ইন্সটল করা হয়েছে।",
        "config-env-hhvm": "HHVM $1 ইনস্টল করা হয়েছে।",
        "config-memory-raised": "পিএইচপির <code>memory_limit</code> হচ্ছে $1, বৃদ্ধি পেয়ে $2 হয়েছে।",
-       "config-apc": "[https://secure.php.net/apc এপিসি] ইনস্টল করা হয়েছে",
-       "config-apcu": "[https://secure.php.net/apcu এপিসিu] ইনস্টল করা হয়েছে",
+       "config-apc": "[https://www.php.net/apc এপিসি] ইনস্টল করা হয়েছে",
+       "config-apcu": "[https://www.php.net/apcu এপিসিu] ইনস্টল করা হয়েছে",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] ইনস্টল করা হয়েছে",
        "config-diff3-bad": "GNU diff3 লেখা তুলনা করার কার্যকারিতা পাওয়া যায়নি। আপনি এখন এটিকে উপেক্ষা করতে পারেন, তবে এতে আপনি আরো ঘন ঘন সম্পাদনা সংঘাতের মধ্যে পড়তে পারেন।",
        "config-git": "Git সংস্করণের নিয়ন্ত্রণ সফটওয়্যার পাওয়া গেছে: <code>$1</code>।",
@@ -72,7 +72,7 @@
        "config-oracle-temp-ts": "সাময়কি টেবিলস্পেস:",
        "config-type-mysql": "MariaDB, MySQL, বা উপযুক্তগুলি",
        "config-type-mssql": "মাইক্রোসফট SQL সার্ভার",
-       "config-dbsupport-postgres": "* MySQL-এর বিকল্প হিসেবে [{{int:version-db-postgres-url}} PostgreSQL] হচ্ছে একটি জনপ্রিয় মুক্ত উৎসের ডাটাবেস ব্যবস্থা। ([https://secure.php.net/manual/en/pgsql.installation.php PostgreSQL সমর্থনসহ কিভাবে PHP সঙ্কলন করবেন])",
+       "config-dbsupport-postgres": "* MySQL-এর বিকল্প হিসেবে [{{int:version-db-postgres-url}} PostgreSQL] হচ্ছে একটি জনপ্রিয় মুক্ত উৎসের ডাটাবেস ব্যবস্থা। ([https://www.php.net/manual/en/pgsql.installation.php PostgreSQL সমর্থনসহ কিভাবে PHP সঙ্কলন করবেন])",
        "config-header-mysql": "MariaDB/MySQL সেটিং",
        "config-header-postgres": "PostgreSQL সেটিংস",
        "config-header-sqlite": "SQLite সেটিংস",
index 876ed53..91f9bdb 100644 (file)
        "config-pcre-no-utf8": "'''Fazi groñs ''': evit doare eo bet kempunet modulenn PCRE PHP hep ar skor PCRE_UTF8.\nEzhomm en deus MediaWiki eus UTF-8 evit mont plaen en-dro.",
        "config-memory-raised": "<code>memory_limit</code> ar PHP zo $1, kemmet e $2.",
        "config-memory-bad": "'''Diwallit :''' Da $1 emañ arventenn <code>memory_limit</code> PHP.\nRe izel eo moarvat.\nMarteze e c'hwito ar staliadenn !",
-       "config-apc": "Staliet eo [https://secure.php.net/apc APC]",
-       "config-apcu": "Staliet eo [https://secure.php.net/apcu APCu]",
+       "config-apc": "Staliet eo [https://www.php.net/apc APC]",
+       "config-apcu": "Staliet eo [https://www.php.net/apcu APCu]",
        "config-wincache": "Staliet eo [https://www.iis.net/downloads/microsoft/wincache-extension WinCache]",
-       "config-no-cache-apcu": "<strong>Taolit pled :</strong> N'eus ket bet gallet kavout [https://secure.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] pe [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nN'eo ket gweredekaet ar c'hrubuilhañ traezoù.",
+       "config-no-cache-apcu": "<strong>Taolit pled :</strong> N'eus ket bet gallet kavout [https://www.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] pe [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nN'eo ket gweredekaet ar c'hrubuilhañ traezoù.",
        "config-mod-security": "<strong>Taolit pled :</strong> Gweredekaet eo [https://modsecurity.org/ mod_security]/mod_security2 gant ho servijer web. Ma n'eo ket kfluniet mat e c'hall tegas trubuilhoù da MediaWiki ha meziantoù all a aotre implijerien da ouzhpennañ danvez evel ma karont.\nE kement ha m'eo posupl e tlefe bezañ diweredekaet. A-hend-all, sellit ouzh [https://modsecurity.org/documentation/ mod_security an teuliadur] pe kit e darempred gant skoazell ho herberc'hier m'en em gavit gant fazioù dargouezhek.",
        "config-diff3-bad": "N'eo ket bet kavet GNU diff3.",
        "config-git": "Kavet eo bet ar meziant kontrolliñ adstummoù Git : <code>$1</code>.",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "Skoret eo ar reizhiadoù diaz titouroù da-heul gant MediaWiki :\n\n$1\n\nMa ne welit ket amañ dindan ar reizhiad diaz titouroù a fell deoc'h ober ganti, heuilhit an titouroù a-us (s.o. al liammoù) evit gweredekaat ar skorañ.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] eo an dibab kentañ evit MediaWiki hag an hini skoret ar gwellañ. Mont a ra MediaWiki en-dro gant [{{int:version-db-mariadb-url}} MariaDB] ha [{{int:version-db-percona-url}} Percona Server] ivez, kenglotus o-daou gant MySQL. ([https://secure.php.net/manual/en/mysqli.installation.php Penaos kempunañ PHP gant skor MySQL])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] zo anezhi ur reizhiad diaz roadennoù frank a wirioù brudet-mat a c'haller ober gantañ e plas MySQL. ([https://secure.php.net/manual/en/pgsql.installation.php Penaos kempunañ PHP gant skor PostgreSQL])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] eo an dibab kentañ evit MediaWiki hag an hini skoret ar gwellañ. Mont a ra MediaWiki en-dro gant [{{int:version-db-mariadb-url}} MariaDB] ha [{{int:version-db-percona-url}} Percona Server] ivez, kenglotus o-daou gant MySQL. ([https://www.php.net/manual/en/mysqli.installation.php Penaos kempunañ PHP gant skor MySQL])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] zo anezhi ur reizhiad diaz roadennoù frank a wirioù brudet-mat a c'haller ober gantañ e plas MySQL. ([https://www.php.net/manual/en/pgsql.installation.php Penaos kempunañ PHP gant skor PostgreSQL])",
        "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] zo anezhi ur reizhiad diaz roadennoù skañv skoret eus ar c'hentañ. ([http://www.php.net/manual/en/pdo.installation.php Penaos kempunañ PHP gant skor SQLite], implijout a ra PDO)",
        "config-dbsupport-oracle": "* Un embregerezh kenwerzhel diaz roadennoù eo [{{int:version-db-oracle-url}} Oracle]. ([http://www.php.net/manual/en/oci8.installation.php Penaos kempunañ PHP gant skor OCI8])",
-       "config-dbsupport-mssql": "* Un embregerezh kenwerzhel diaz roadennoù evit Windows eo [{{int:version-db-mssql-url}} Microsoft SQL Server]. ([https://secure.php.net/manual/en/sqlsrv.installation.php Penaos kempunañ PHP gant skor SQLSRV])",
+       "config-dbsupport-mssql": "* Un embregerezh kenwerzhel diaz roadennoù evit Windows eo [{{int:version-db-mssql-url}} Microsoft SQL Server]. ([https://www.php.net/manual/en/sqlsrv.installation.php Penaos kempunañ PHP gant skor SQLSRV])",
        "config-header-mysql": "Arventennoù MySQL",
        "config-header-postgres": "Arventennoù PostgreSQL",
        "config-header-sqlite": "Arventennoù SQLite",
index 58931b8..e6118f8 100644 (file)
@@ -50,8 +50,8 @@
        "config-no-db": "Ne mogu pronaći pogodan upravljački program za bazu podataka! Morate ga instalirati za PHP-bazu.\n{{PLURAL:$2|Podržana je sljedeća vrsta|Podržane su sljedeće vrste}} baze podataka: $1.\n\nAko se sami kompajlirali PHP, omogućite klijent baze podataka u postavkama koristeći, naprimjer, <code>./configure --with-mysqli</code>.\nAko ste instalirali PHP iz paketa za Debian ili Ubuntu, onda također morate instalirati, naprimjer, paket <code>php-mysql</code>.",
        "config-memory-raised": "<code>memory_limit</code> za PHP iznosi $1, povišen na $2.",
        "config-memory-bad": "<strong>Upozorenje:</strong> <code>memory_limit</code> za PHP iznosi $1.\nOvo je vjerovatno premalo.\nInstalacija možda neće uspjeti!",
-       "config-apc": "[https://secure.php.net/apc APC] je instaliran",
-       "config-apcu": "[https://secure.php.net/apcu APCu] je instaliran",
+       "config-apc": "[https://www.php.net/apc APC] je instaliran",
+       "config-apcu": "[https://www.php.net/apcu APCu] je instaliran",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] je instaliran",
        "config-diff3-bad": "GNU diff3 nije pronađen.",
        "config-git": "Pronađen je Git program za kontrolu verzija: <code>$1</code>.",
index c856203..c9abc94 100644 (file)
@@ -66,8 +66,8 @@
        "config-pcre-old": "<strong>Error fatal:</strong> Cal el PCRE $1 o superior.\nEl binari PHP que utilitzeu està enllaçat amb el PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Més informació].",
        "config-memory-raised": "El <code>memory_limit</code> del PHP és $1 i s'ha aixecat a $2.",
        "config-memory-bad": "<strong>Avís:</strong> El <code>memory_limit</code> del PHP és $1.\nAixò és probablement massa baix.\nLa instal·lació pot fallar!",
-       "config-apc": "L'[https://secure.php.net/apc APC] està instal·lat",
-       "config-apcu": "L'[https://secure.php.net/apcu APCu] està instal·lat",
+       "config-apc": "L'[https://www.php.net/apc APC] està instal·lat",
+       "config-apcu": "L'[https://www.php.net/apcu APCu] està instal·lat",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] està instal·lat",
        "config-diff3-bad": "No s'ha trobat el GNU diff3. Podeu ignorar-ho per ara, però us podeu trobar amb conflictes d'edició més habitualment.",
        "config-git": "S'ha trobat el programari de control de versions Git: <code>$1</code>.",
        "config-license-cc-choose": "Selecció d'una llicència personalitzada de Creative Commons",
        "config-email-settings": "Paràmetres del correu electrònic",
        "config-enable-email": "Habilita el correu sortint",
-       "config-enable-email-help": "Si voleu que el correu electrònic funcioni, cal configurar [https://secure.php.net/manual/en/mail.configuration.php PHP's els paràmetres de correu] correctament.\nSi no voleu cap funcionalitat de correu, podeu inhabilitar-ho.",
+       "config-enable-email-help": "Si voleu que el correu electrònic funcioni, cal configurar [https://www.php.net/manual/en/mail.configuration.php PHP's els paràmetres de correu] correctament.\nSi no voleu cap funcionalitat de correu, podeu inhabilitar-ho.",
        "config-email-user": "Habilita el correu electrònic usuari-a-usuari",
        "config-email-user-help": "Permet que tots els usuaris puguin enviar-se correu si ho han habilitat a les preferències.",
        "config-email-usertalk": "Habilita la notificació a la pàgina de discussió de l'usuari",
        "config-install-done": "<strong>Enhorabona!</strong>\nHeu instal·lat MediaWiki.\n\nL'instal·lador a generat un fitxer <code>LocalSettings.php</code>.\nConté tota la configuració.\n\nCaldrà que el baixeu i el poseu al directori base on heu instal·lat al wiki (el mateix directori on es troba index.php). La baixada hauria d'haver començat automàticament.\n\nSi la baixada no comença, o si l'heu cancel·lat, podeu reiniciar-la fent clic a l'enllaç de sota:\n\n$3\n\n<strong>Nota:</strong> Si no ho feu ara, no podreu accedir a aquest fitxer de configuració més endavant si no l'heu baixat abans.\n\nUna vegada tot això fet, podeu <strong>[$2 entrar al vostre wiki]</strong>.",
        "config-install-done-path": "<strong>Enhorabona!</strong>\nHeu instal·lat MediaWiki.\n\nL'instal·lador a generat un fitxer <code>LocalSettings.php</code>.\nConté tota la configuració.\n\nCaldrà que el baixeu i el poseu a <code>$4</code>. La baixada hauria d'haver començat automàticament.\n\nSi la baixada no comença, o si l'heu cancel·lat, podeu reiniciar-la fent clic a l'enllaç de sota:\n\n$3\n\n<strong>Nota:</strong> Si no ho feu ara, no podreu accedir a aquest fitxer de configuració més endavant si no l'heu baixat abans.\n\nUna vegada tot això fet, podeu <strong>[$2 entrar al vostre wiki]</strong>.",
        "config-install-success": "El MediaWiki s'ha instal·lat amb èxit. Podeu visitar <$1$2> per veure el vostre wiki.\nSi teniu preguntes, reviseu la llista de preguntes més freqüents:\n<https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ> o utilitzeu un dels fòrums d'assistència enllaçats a la pàgina.",
+       "config-install-db-success": "La base de dades s'ha configurat amb èxit",
        "config-download-localsettings": "Baixa <code>LocalSettings.php</code>",
        "config-help": "ajuda",
        "config-help-tooltip": "feu clic per ampliar",
index 33bce2f..1b814a2 100644 (file)
@@ -31,7 +31,7 @@
        "config-page-existingwiki": "ویکی پێشوو",
        "config-restart": "بەڵێ، دەستی پێ بکەرەوە",
        "config-env-php": "PHP $1 دامەزراوە.",
-       "config-apc": "[https://secure.php.net/apc APC] دامەزراوە",
+       "config-apc": "[https://www.php.net/apc APC] دامەزراوە",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] دامەزراوە",
        "config-db-type": "جۆری داتابەیس:",
        "config-db-host": "خانەخوێی داتابەیس:",
index 76408c2..944ecbe 100644 (file)
@@ -11,7 +11,8 @@
                        "LordMsz",
                        "Seb35",
                        "Ilimanaq29",
-                       "Dvorapa"
+                       "Dvorapa",
+                       "Patriccck"
                ]
        },
        "config-desc": "Instalační program pro MediaWiki",
        "config-pcre-no-utf8": "<strong>Kritická chyba:</strong> PHP modul PCRE byl zřejmě přeložen bez podpory PCRE_UTF8.\nMediaWiki vyžaduje ke správné funkci podporu UTF-8.",
        "config-memory-raised": "<code>memory_limit</code> v PHP byl nastaven na $1, zvýšen na $2.",
        "config-memory-bad": "<strong>Upozornění:</strong> <code>memory_limit</code> je v PHP nastaven na $1.\nTo je pravděpodobně příliš málo.\nInstalace může selhat!",
-       "config-apc": "Je nainstalováno [https://secure.php.net/apc APC]",
-       "config-apcu": "Je nainstalováno [https://secure.php.net/apcu APCu]",
+       "config-apc": "Je nainstalováno [https://www.php.net/apc APC]",
+       "config-apcu": "Je nainstalováno [https://www.php.net/apcu APCu]",
        "config-wincache": "Je nainstalováno [https://www.iis.net/downloads/microsoft/wincache-extension WinCache]",
-       "config-no-cache-apcu": "<strong>Upozornění:</strong> Nebylo nalezeno [https://secure.php.net/apcu APCu], \nani [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nCachování objektů není povoleno.",
+       "config-no-cache-apcu": "<strong>Upozornění:</strong> Nebylo nalezeno [https://www.php.net/apcu APCu], \nani [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nCachování objektů není povoleno.",
        "config-mod-security": "<strong>Upozornění:</strong> váš webový server má zapnuto [https://modsecurity.org/ mod_security]/mod_security2. Mnoho běžných konfigurací bude způsobovat potíže MediaWiki a dalším programům, které umožňují ukládat libovolný obsah.\nPokud je to možné, mělo by se to vypnout. Jinak se v případě, že narazíte na náhodné chyby, podívejte do [https://modsecurity.org/documentation/ dokumentace mod_security] nebo kontaktujte technickou podporu vašeho poskytovatele.",
        "config-diff3-bad": "Nebyl nalezen nástroj pro porovnávání textu GNU diff3. Můžete to zatím ignorovat, ale je možné, že budete častěji narážet na editační konflikty.",
        "config-git": "Nalezen software pro správu verzí Git: <code>$1</code>.",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki podporuje následující databázové systémy:\n\n$1\n\nPokud v nabídce níže nevidíte databázový systém, který chcete použít, musíte pro zapnutí podpory následovat instrukce odkázané výše.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] je pro MediaWiki hlavní platformou a je podporováno nejlépe. MediaWiki pracuje také s [{{int:version-db-mysql-url}} MySQL] a [{{int:version-db-percona-url}} Percona Server], které jsou s MariaDB kompatibilní. ([https://secure.php.net/manual/en/mysqli.installation.php Jak zkompilovat PHP s podporou MySQL])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] je populární otevřený databázový systém používaný jako alternativa k MySQL. ([https://secure.php.net/manual/en/pgsql.installation.php Jak přeložit PHP s podporou PostgreSQL])",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] je velmi dobře podporovaný odlehčený databázový systém. ([https://secure.php.net/manual/en/pdo.installation.php Jak přeložit PHP s podporou SQLite], používá PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] je komerční podniková databáze. ([https://secure.php.net/manual/en/oci8.installation.php Jak přeložit PHP s podporou OCI8])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] je komerční podniková databáze pro Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php Jak přeložit PHP s podporou SQLSRV])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] je pro MediaWiki hlavní platformou a je podporováno nejlépe. MediaWiki pracuje také s [{{int:version-db-mysql-url}} MySQL] a [{{int:version-db-percona-url}} Percona Server], které jsou s MariaDB kompatibilní. ([https://www.php.net/manual/en/mysqli.installation.php Jak zkompilovat PHP s podporou MySQL])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] je populární otevřený databázový systém používaný jako alternativa k MySQL. ([https://www.php.net/manual/en/pgsql.installation.php Jak přeložit PHP s podporou PostgreSQL])",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] je velmi dobře podporovaný odlehčený databázový systém. ([https://www.php.net/manual/en/pdo.installation.php Jak přeložit PHP s podporou SQLite], používá PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] je komerční podniková databáze. ([https://www.php.net/manual/en/oci8.installation.php Jak přeložit PHP s podporou OCI8])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] je komerční podniková databáze pro Windows. ([https://www.php.net/manual/en/sqlsrv.installation.php Jak přeložit PHP s podporou SQLSRV])",
        "config-header-mysql": "Nastavení MariaDB/MySQL",
        "config-header-postgres": "Nastavení PostgreSQL",
        "config-header-sqlite": "Nastavení SQLite",
        "config-missing-db-name": "Musíte zadat hodnotu pro „{{int:config-db-name}}“.",
        "config-missing-db-host": "Musíte zadat hodnotu pro „{{int:config-db-host}}“.",
        "config-missing-db-server-oracle": "Musíte zadat hodnotu pro „{{int:config-db-host-oracle}}“.",
-       "config-invalid-db-server-oracle": "Chybné databázové TNS „$1“.\nPoužívejte buď „TNS Name“ nebo „Easy Connect“ (vizte [http://docs.oracle.com/cd/E11882_01/network.112/e10836/naming.htm Oracle Naming Methods]).",
+       "config-invalid-db-server-oracle": "Chybné databázové TNS „$1“.\nPoužívejte buď „TNS Name“ nebo „Easy Connect“ (viz [http://docs.oracle.com/cd/E11882_01/network.112/e10836/naming.htm Oracle Naming Methods]).",
        "config-invalid-db-name": "Chybné jméno databáze „$1“.\nPoužívejte pouze ASCII písmena (a-z, A-Z), čísla (0-9), podtržítko (_) a spojovník (-).",
        "config-invalid-db-prefix": "Chybný databázový prefix „$1“.\nPoužívejte pouze ASCII písmena (a-z, A-Z), čísla (0-9), podtržítko (_) a spojovník (-).",
        "config-connection-error": "$1.\n\nZkontrolujte server, uživatelské jméno a heslo a zkuste to znovu. Pokud jako adresu databázového serveru používáte „localhost“, zkuste použít „127.0.0.1“ (a naopak).",
        "config-profile-no-anon": "Vyžadována registrace uživatelů",
        "config-profile-fishbowl": "Editace jen pro vybrané",
        "config-profile-private": "Soukromá wiki",
-       "config-profile-help": "Wiki fungují nejlépe, když je necháte editovat co největším možným počtem lidí.\nV MediaWiki můžete snadno kontrolovat poslední změny a vracet zpět libovolnou škodu způsobenou hloupými nebo zlými uživateli.\n\nMnoho lidí však zjistilo, že je MediaWiki užitečné v širokém spektru rolí a někdy není snadné všechny přesvědčit o výhodách wikizvyklostí.\nTakže si můžete vybrat.\n\nModel '''{{int:config-profile-wiki}}''' dovoluje editovat všem, aniž by se museli přihlašovat.\nNa wiki, kde je '''{{int:config-profile-no-anon}}''', se lépe řídí zodpovědnost, ale může to odradit náhodné přispěvatele.\n\nProfil '''{{int:config-profile-fishbowl}}''' umožňuje schváleným uživatelům editovat, ale veřejnost si může stránky prohlížet včetně jejich historie.\n'''{{int:config-profile-private}}''' dovoluje stránky prohlížet jen schváleným uživatelům, kteří je i mohou editovat.\n\nPo instalaci je možná komplexní konfigurace uživatelských práv; vizte [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:User_rights odpovídající stránku příručky].",
+       "config-profile-help": "Wiki fungují nejlépe, když je necháte editovat co největším možným počtem lidí.\nV MediaWiki můžete snadno kontrolovat poslední změny a vracet zpět libovolnou škodu způsobenou hloupými nebo zlými uživateli.\n\nMnoho lidí však zjistilo, že je MediaWiki užitečné v širokém spektru rolí a někdy není snadné všechny přesvědčit o výhodách wikizvyklostí.\nTakže si můžete vybrat.\n\nModel '''{{int:config-profile-wiki}}''' dovoluje editovat všem, aniž by se museli přihlašovat.\nNa wiki, kde je '''{{int:config-profile-no-anon}}''', se lépe řídí zodpovědnost, ale může to odradit náhodné přispěvatele.\n\nProfil '''{{int:config-profile-fishbowl}}''' umožňuje schváleným uživatelům editovat, ale veřejnost si může stránky prohlížet včetně jejich historie.\n'''{{int:config-profile-private}}''' dovoluje stránky prohlížet jen schváleným uživatelům, kteří je i mohou editovat.\n\nPo instalaci je možná komplexní konfigurace uživatelských práv; viz [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:User_rights odpovídající stránku příručky].",
        "config-license": "Autorská práva a licence:",
        "config-license-none": "Bez patičky s licencí",
        "config-license-cc-by-sa": "Creative Commons Uveďte autora-Zachovejte licenci",
        "config-license-help": "Mnoho veřejných wiki všechny příspěvky zveřejňuje pod některou [https://freedomdefined.org/Definition/Cs svobodnou licencí].\nTo pomáhá vytvořit duch komunitního vlastnictví a povzbuzuje dlouhodobé přispívání.\nTo obecně není potřeba u soukromé nebo firemní wiki.\n\nPokud chcete být schopni používat text z Wikipedie a chcete, aby Wikipedie byla schopna přijímat text okopírovaný z vaší wiki, měli byste zvolit <strong>{{int:config-license-cc-by-sa}}</strong>.\n\nDříve Wikipedie používala GNU Free Documentation License.\nGFDL je platná licence, ale složité jí porozumět.\nTaké je komplikované používat obsah licencovaný pod GFDL.",
        "config-email-settings": "Nastavení e-mailu",
        "config-enable-email": "Zapnout odchozí e-mail",
-       "config-enable-email-help": "Pokud chcete, aby e-mail fungoval, je potřeba správně nakonfigurovat [https://secure.php.net/manual/en/mail.configuration.php e-mailová nastavení PHP].\nPokud nechcete žádné e-mailové funkce, můžete je zde vypnout.",
+       "config-enable-email-help": "Pokud chcete, aby e-mail fungoval, je potřeba správně nakonfigurovat [https://www.php.net/manual/en/mail.configuration.php e-mailová nastavení PHP].\nPokud nechcete žádné e-mailové funkce, můžete je zde vypnout.",
        "config-email-user": "Umožnit vzájemné e-maily mezi uživateli",
        "config-email-user-help": "Umožní všem uživatelům posílat si navzájem e-maily, pokud si to zapnout v uživatelském nastavení.",
        "config-email-usertalk": "Umožnit notifikace k uživatelským diskusím",
        "config-install-done": "<strong>Gratulujeme!</strong>\nNainstalovali jste MediaWiki.\n\nInstalátor vytvořil soubor <code>LocalSettings.php</code>.\nTen obsahuje veškerou vaši konfiguraci.\n\nBudete si ho muset stáhnout a uložit do základního adresáře vaší instalace wiki (do stejného adresáře jako soubor index.php). Stažení souboru se mělo spustit automaticky.\n\nPokud se vám stažení nenabídlo nebo jste ho zrušili, můžete ho spustit znovu kliknutím na následující odkaz:\n\n$3\n\n<strong>Poznámka</strong>: Pokud to neuděláte hned, tento vygenerovaný konfigurační soubor nebude později dostupný, pokud instalaci opustíte, aniž byste si ho stáhli.\n\nAž to dokončíte, můžete <strong>[$2 vstoupit do své wiki]</strong>.",
        "config-install-done-path": "<strong>Gratulujeme!</strong>\nNainstalovali jste MediaWiki.\n\nInstalátor vytvořil soubor <code>LocalSettings.php</code>.\nTen obsahuje veškerou vaši konfiguraci.\n\nBudete si ho muset stáhnout a uložit do <code>$4</code>. Stažení souboru se mělo spustit automaticky.\n\nPokud se vám stažení nenabídlo nebo jste ho zrušili, můžete ho spustit znovu kliknutím na následující odkaz:\n\n$3\n\n<strong>Poznámka:</strong> Pokud to neuděláte hned, tento vygenerovaný konfigurační soubor nebude později dostupný, pokud instalaci opustíte, aniž byste si ho stáhli.\n\nAž to dokončíte, můžete <strong>[$2 vstoupit do své wiki]</strong>.",
        "config-install-success": "MediaWiki byla úspěšně nainstalována. Nyní můžete navštívit <$1$2>, abyste si prohlédli svou novou wiki.\nPokud máte dotazy, podívejte se do našeho seznamu často kladených otázek:\n<https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ> nebo použijte jedno\nz tam odkazovaných diskusních fór.",
+       "config-install-db-success": "Databáze byla úspěšně nastavena",
        "config-download-localsettings": "Stáhnout <code>LocalSettings.php</code>",
        "config-help": "nápověda",
        "config-help-tooltip": "rozbalíte kliknutím",
index 6c8e9b8..f7df024 100644 (file)
@@ -35,7 +35,7 @@
        "config-env-hhvm": "HHVM $1 je wjinastalowóné",
        "config-memory-raised": "Paraméter PHP <code>memory_limit</code> $1 òstôł zwikszony do $2.",
        "config-apc": "[Http://www.php.net/apc APC] je wjinstalowóny",
-       "config-apcu": "[https://secure.php.net/apcu APCu] je wjinstalowóny",
+       "config-apcu": "[https://www.php.net/apcu APCu] je wjinstalowóny",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] je wjinstalowóny",
        "config-diff3-bad": "Felënk GNU diff3.",
        "config-mysql-innodb": "InnoDB",
index 943b8fc..946955e 100644 (file)
@@ -46,8 +46,8 @@
        "config-restart": "Ja, genstart den",
        "config-env-php": "PHP $1 er installeret.",
        "config-env-hhvm": "HHVM $1 er installeret.",
-       "config-apc": "[https://secure.php.net/apc APC] er installeret",
-       "config-apcu": "[https://secure.php.net/apcu APCu] er installeret",
+       "config-apc": "[https://www.php.net/apc APC] er installeret",
+       "config-apcu": "[https://www.php.net/apcu APCu] er installeret",
        "config-db-type": "Databasetype:",
        "config-db-host": "Databasevært:",
        "config-db-name": "Databasenavn (ingen bindestreg):",
index 2a6aa23..5fcc4c9 100644 (file)
        "config-pcre-no-utf8": "'''Fataler Fehler:''' Das PHP-Modul PCRE scheint ohne PCRE_UTF8-Unterstützung kompiliert worden zu sein.\nMediaWiki benötigt die UTF-8-Unterstützung, um fehlerfrei lauffähig zu sein.",
        "config-memory-raised": "Der PHP-Parameter <code>memory_limit</code> betrug $1 und wurde auf $2 erhöht.",
        "config-memory-bad": "'''Warnung:''' Der PHP-Parameter <code>memory_limit</code> beträgt $1.\nDieser Wert ist wahrscheinlich zu niedrig.\nDer Installationsvorgang könnte eventuell scheitern!",
-       "config-apc": "[https://secure.php.net/apc APC] ist installiert",
-       "config-apcu": "[https://secure.php.net/apcu APCu] ist installiert",
+       "config-apc": "[https://www.php.net/apc APC] ist installiert",
+       "config-apcu": "[https://www.php.net/apcu APCu] ist installiert",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] ist installiert",
-       "config-no-cache-apcu": "<strong>Warnung:</strong> [https://secure.php.net/apcu APCu] oder [https://www.iis.net/downloads/microsoft/wincache-extension WinCache] konnten nicht gefunden werden.\nDer Objektcache ist nicht aktiviert.",
+       "config-no-cache-apcu": "<strong>Warnung:</strong> [https://www.php.net/apcu APCu] oder [https://www.iis.net/downloads/microsoft/wincache-extension WinCache] konnten nicht gefunden werden.\nDer Objektcache ist nicht aktiviert.",
        "config-mod-security": "'''Warnung:''' Auf dem Webserver wurde [https://modsecurity.org/ ModSecurity] aktiviert. Sofern falsch konfiguriert, kann dies zu Problemen mit MediaWiki sowie anderer Software auf dem Server führen und es Benutzern ermöglichen, beliebige Inhalte im Wiki einzustellen.\nFür weitere Informationen empfehlen wir die [https://modsecurity.org/documentation/ Dokumentation zu ModSecurity] oder den Kontakt zum Hoster, sofern Fehler auftreten.",
        "config-diff3-bad": "Das Textvergleichswerkzeug GNU diff3 wurde nicht gefunden. Du kannst diese Meldung vorerst ignorieren, jedoch kann es vermehrt zu Bearbeitungskonflikten kommen.",
        "config-git": "Die Versionsverwaltungssoftware „Git“ wurde gefunden: <code>$1</code>.",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki unterstützt die folgenden Datenbanksysteme:\n\n$1\n\nSofern unterhalb nicht das Datenbanksystem angezeigt wird, das verwendet werden soll, muss dieses noch verfügbar gemacht werden. Oben ist zu jedem unterstützten Datenbanksystem ein Link zur entsprechenden Anleitung vorhanden.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] ist das von MediaWiki primär unterstützte Datenbanksystem. MediaWiki funktioniert auch mit [{{int:version-db-mysql-url}} MySQL] und [{{int:version-db-percona-url}} Percona Server], die MariaDB-kompatibel sind. ([https://secure.php.net/manual/en/mysqli.installation.php Anleitung zur Kompilierung von PHP mit MySQL-Unterstützung])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] ist ein beliebtes Open-Source-Datenbanksystem und eine Alternative zu MySQL. ([https://secure.php.net/manual/en/pgsql.installation.php Anleitung zur Kompilierung von PHP mit PostgreSQL-Unterstützung])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] ist das von MediaWiki primär unterstützte Datenbanksystem. MediaWiki funktioniert auch mit [{{int:version-db-mysql-url}} MySQL] und [{{int:version-db-percona-url}} Percona Server], die MariaDB-kompatibel sind. ([https://www.php.net/manual/en/mysqli.installation.php Anleitung zur Kompilierung von PHP mit MySQL-Unterstützung])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] ist ein beliebtes Open-Source-Datenbanksystem und eine Alternative zu MySQL. ([https://www.php.net/manual/en/pgsql.installation.php Anleitung zur Kompilierung von PHP mit PostgreSQL-Unterstützung])",
        "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] ist ein verschlanktes Datenbanksystem, das auch gut unterstützt wird ([https://www.php.net/manual/de/pdo.installation.php Anleitung zur Kompilierung von PHP mit SQLite-Unterstützung], verwendet PHP Data Objects (PDO))",
        "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] ist eine kommerzielle Unternehmensdatenbank ([https://www.php.net/manual/en/oci8.installation.php Anleitung zur Kompilierung von PHP mit OCI8-Unterstützung])",
        "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] ist eine gewerbliche Unternehmensdatenbank für Windows. ([https://www.php.net/manual/de/sqlsrv.installation.php Anleitung zur Kompilierung von PHP mit SQLSRV-Unterstützung])",
        "config-license-help": "Viele öffentliche Wikis publizieren alle Beiträge unter einer [https://freedomdefined.org/Definition/De freien Lizenz.]\nDies trägt dazu bei, ein Gefühl von Gemeinschaft zu schaffen, und ermutigt zu längerfristiger Mitarbeit.\nHingegen ist im Allgemeinen eine freie Lizenz auf geschlossenen Wikis nicht notwendig.\n\nSofern man Texte aus der Wikipedia verwenden möchte und umgekehrt, sollte die Lizenz {{int:config-license-cc-by-sa}} gewählt werden.\n\nDie Wikipedia nutzte vormals die GNU-Lizenz für freie Dokumentation (GFDL).\nDie GFDL ist eine gültige Lizenz, die allerdings schwer zu verstehen ist.\nEs ist zudem schwierig, gemäß dieser Lizenz lizenzierte Inhalte wiederzuverwenden.",
        "config-email-settings": "E-Mail-Einstellungen",
        "config-enable-email": "Ausgehende E-Mails ermöglichen",
-       "config-enable-email-help": "Sofern die E-Mail-Funktionen genutzt werden sollen, müssen die entsprechenden [https://secure.php.net/manual/en/mail.configuration.php PHP-E-Mail-Einstellungen] richtig konfiguriert werden.\nFür den Fall, dass die E-Mail-Funktionen nicht benötigt werden, können sie hier deaktiviert werden.",
+       "config-enable-email-help": "Sofern die E-Mail-Funktionen genutzt werden sollen, müssen die entsprechenden [https://www.php.net/manual/en/mail.configuration.php PHP-E-Mail-Einstellungen] richtig konfiguriert werden.\nFür den Fall, dass die E-Mail-Funktionen nicht benötigt werden, können sie hier deaktiviert werden.",
        "config-email-user": "E-Mail-Versand von Benutzer zu Benutzer aktivieren",
        "config-email-user-help": "Allen Benutzern ermöglichen, sich gegenseitig E-Mails zu schicken, sofern sie es in ihren Einstellungen aktiviert haben.",
        "config-email-usertalk": "Benachrichtigungen zu Änderungen an Benutzerdiskussionsseiten ermöglichen",
        "config-install-done": "'''Herzlichen Glückwunsch!'''\nMediaWiki wurde erfolgreich installiert.\n\nDas Installationsprogramm hat die Datei <code>LocalSettings.php</code> erzeugt.\nSie enthält alle vorgenommenen Konfigurationseinstellungen.\n\nDiese Datei muss nun heruntergeladen und anschließend in das Stammverzeichnis der MediaWiki-Installation hochgeladen werden. Dies ist dasselbe Verzeichnis, in dem sich auch die Datei <code>index.php</code> befindet. Das Herunterladen sollte inzwischen automatisch gestartet worden sein.\n\nSofern dies nicht der Fall war, oder das Herunterladen unterbrochen wurde, kann der Vorgang durch einen Klick auf den folgenden Link erneut gestartet werden:\n\n$3\n\n'''Hinweis:''' Die Konfigurationsdatei sollte jetzt unbedingt heruntergeladen werden. Sie wird nach Beenden des Installationsprogramms, nicht mehr zur Verfügung stehen.\n\nSobald alles erledigt wurde, kann auf das '''[$2 Wiki zugegriffen werden]'''. Wir wünschen viel Spaß und Erfolg mit dem Wiki.",
        "config-install-done-path": "<strong>Herzlichen Glückwunsch!</strong>\nDu hast MediaWiki installiert.\n\nDas Installationsprogramm hat eine Datei „<code>LocalSettings.php</code>“ erzeugt.\nSie enthält deine gesamte Konfiguration.\n\nDu musst sie herunterladen und unter <code>$4</code> ablegen. Der Download sollte automatisch gestartet sein.\n\nFalls der Download nicht angeboten wird oder du ihn abgebrochen hast, kannst du ihn durch Anklicken des folgenden Links neu starten:\n\n$3\n\n<strong>Hinweis:</strong> Falls du dies jetzt nicht tust, wird die erzeugte Konfigurationsdatei später nicht verfügbar sein, wenn du die Installation ohne Herunterladen verlässt.\n\nBei Fertigstellung kannst du <strong>[$2 dein Wiki aufrufen]</strong>.",
        "config-install-success": "MediaWiki wurde erfolgreich installiert. Du kannst jetzt\n<$1$2> aufrufen, um dein Wiki anzusehen.\nFalls du Fragen hast, lies unsere Liste der häufig gestellten Fragen:\n<https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ> oder benutze eines der\nSupport-Foren, die auf dieser Seite verlinkt sind.",
+       "config-install-db-success": "Die Datenbank wurde erfolgreich aufgesetzt",
        "config-download-localsettings": "<code>LocalSettings.php</code> herunterladen",
        "config-help": "Hilfe",
        "config-help-tooltip": "Zum Expandieren klicken",
index 4a98d5d..21c7249 100644 (file)
@@ -71,7 +71,7 @@
        "config-admin-name": "Nameyê şımayê karberi:",
        "config-admin-password": "Parola:",
        "config-admin-password-confirm": "Fına parola:",
-       "config-admin-email": "Adresa e-postey:",
+       "config-admin-email": "Adresa e-posteyi:",
        "config-profile-wiki": "Wiki Ak",
        "config-profile-private": "Bexse wiki",
        "config-license": "Heqa telifi û lisans:",
index 55b7799..b7a4e06 100644 (file)
@@ -25,9 +25,9 @@
        "config-upgrade-key-missing": "Έχει εντοπιστεί μια υπάρχουσα εγκατάσταση του MediaWiki.\nΓια να αναβαθμίσετε αυτήν την εγκατάσταση, παρακαλούμε να βάλετε την ακόλουθη γραμμή στο κάτω μέρος του <code>LocalSettings.php</code> σας:\n\n$1",
        "config-localsettings-incomplete": "Το υπάρχον <code>LocalSettings.php</code> φαίνεται να είναι ελλιπές.\nΤο $1 μεταβλητή δεν έχει οριστεί.\nΠαρακαλούμε να αλλάξετε  το <code>LocalSettings.php</code> έτσι ώστε αυτή η μεταβλητή έχει οριστεί, και κάντε κλικ στο \"{{int:Config-continue}}\".",
        "config-localsettings-connection-error": "Ένα σφάλμα παρουσιάστηκε κατά τη σύνδεση με τη βάση δεδομένων και με τη χρήση των ρυθμίσεων που ορίστηκαν στο <code>LocalSettings.php</code>. Παρακαλούμε διορθώστε αυτές τις ρυθμίσεις και δοκιμάστε ξανά.\n\n$1",
-       "config-session-error": "ΣÏ\86άλμα ÎºÎ±Ï\84ά Ï\84ην ÎµÎºÎºÎ¯Î½Î·Ï\83η Ï\83Ï\85νεδÏ\81ίας: $1",
-       "config-session-expired": "Τα Î´ÎµÎ´Î¿Î¼Î­Î½Î± Ï\83Ï\85νÏ\8cδοÏ\85 Ï\86αίνεÏ\84αι Î½Î± Î­Ï\87οÏ\85ν Î»Î®Î¾ÎµÎ¹.\nΣÏ\85νεδÏ\81ίεÏ\82 Î­Ï\87οÏ\85ν Ï\81Ï\85θμιÏ\83Ï\84εί Î³Î¹Î± Î¼Î¹Î± Î´Î¹Î¬Ï\81κεια Î¶Ï\89ήÏ\82 $1.\nÎ\9cÏ\80οÏ\81είÏ\84ε Î½Î± Î±Ï\85ξήÏ\83εÏ\84ε Î±Ï\85Ï\84Ï\8c Î²Î¬Î¶Î¿Î½Ï\84αÏ\82  <code>session.gc_maxlifetime</code> στο php.ini.\nΚάντε επανεκκίνηση της διαδικασίας εγκατάστασης.",
-       "config-no-session": "Î\97 Ï\83Ï\85νεδÏ\81ία Î´ÎµÎ´Î¿Î¼Î­Î½Ï\89ν Ï\83αÏ\82 Î­Ï\87ει Ï\87αθεί!Î\95λέγξÏ\84ε Ï\84ο Î±Ï\81Ï\87είο php.ini ÎºÎ±Î¹ Î²ÎµÎ²Î±Î¹Ï\89θείÏ\84ε Ï\8cÏ\84ι Ï\84ο <code>session.save_path</code> Î­Ï\87ει Î¼Ï\80ει στον κατάλληλο κατάλογο.",
+       "config-session-error": "ΣÏ\86άλμα ÎºÎ±Ï\84ά Ï\84ην ÎµÎºÎºÎ¯Î½Î·Ï\83η Ï\84ηÏ\82 Ï\80εÏ\81ιÏ\8cδοÏ\85 Ï\83Ï\8dνδεÏ\83ης: $1",
+       "config-session-expired": "Τα Î´ÎµÎ´Î¿Î¼Î­Î½Î± Ï\84ηÏ\82 Ï\80εÏ\81ιÏ\8cδοÏ\85 Ï\83Ï\8dνδεÏ\83ηÏ\82 Ï\86αίνεÏ\84αι Î½Î± Î­Ï\87οÏ\85ν Î»Î®Î¾ÎµÎ¹.\nÎ\9fι Ï\80εÏ\81ίοδοι Ï\83Ï\8dνδεÏ\83ηÏ\82 ÎµÎ¯Î½Î±Î¹ Ï\81Ï\85θμιÏ\83μένεÏ\82 Î³Î¹Î± Î´Î¹Î¬Ï\81κεια Î¶Ï\89ήÏ\82 $1.\nÎ\9cÏ\80οÏ\81είÏ\84ε Î½Î± Ï\84ην Î±Ï\85ξήÏ\83εÏ\84ε Î¸Î­Ï\84ονÏ\84αÏ\82 Ï\84ο <code>session.gc_maxlifetime</code> στο php.ini.\nΚάντε επανεκκίνηση της διαδικασίας εγκατάστασης.",
+       "config-no-session": "Τα Î´ÎµÎ´Î¿Î¼Î­Î½Î± Ï\84ηÏ\82 Ï\80εÏ\81ιÏ\8cδοÏ\85 Ï\83Ï\8dνδεÏ\83ήÏ\82 Ï\83αÏ\82 Î­Ï\87οÏ\85ν Ï\87αθεί!\nÎ\95λέγξÏ\84ε Ï\84ο php.ini Ï\83αÏ\82 ÎºÎ±Î¹ Î²ÎµÎ²Î±Î¹Ï\89θείÏ\84ε Ï\8cÏ\84ι Ï\84ο <code>session.save_path</code> Î­Ï\87ει Î¿Ï\81ιÏ\83Ï\84εί στον κατάλληλο κατάλογο.",
        "config-your-language": "Η γλώσσα σας:",
        "config-your-language-help": "Επιλέξτε μία γλώσσα για τη διαδικασία της εγκατάστασης.",
        "config-wiki-language": "Γλώσσα του wiki:",
        "config-pcre-no-utf8": "<strong>Κρίσιμο:</strong> Το PCRE module της PHP  φαίνεται να έχει μεταγλωττιστεί χωρίς υποστήριξη  PCRE_UTF8.\nΓια τη σωστή λειτουργία του MediaWiki απαιτείται υποστήριξη UTF-8.",
        "config-memory-raised": "Το  <code>memory_limit</code> της PHP είναι  $1 και αυξήθηκε σε  $2.",
        "config-memory-bad": "<strong>Προειδοποίηση:</strong> το <code>memory_limit</code> της PHP είναι $1.\nΑυτή η τιμή είναι πιθανώς πολύ χαμηλή.\n\nΗ εγκατάσταση ενδέχεται να αποτύχει!",
-       "config-apc": "Το [https://secure.php.net/apc APC] είναι εγκατεστημένο",
-       "config-apcu": "Το [https://secure.php.net/apcu APCu] είναι εγκατεστημένο",
+       "config-apc": "Το [https://www.php.net/apc APC] είναι εγκατεστημένο",
+       "config-apcu": "Το [https://www.php.net/apcu APCu] είναι εγκατεστημένο",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension Το WinCache] είναι εγκατεστημένο",
-       "config-no-cache-apcu": "<strong>Προειδοποίηση:</strong> Αποτυχία εύρεσης του [https://secure.php.net/apcu APCu] ή του [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nΗ αρχειοθέτηση αντικειμένων δεν έχει ενεργοποιηθεί.",
+       "config-no-cache-apcu": "<strong>Προειδοποίηση:</strong> Αποτυχία εύρεσης του [https://www.php.net/apcu APCu] ή του [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nΗ αρχειοθέτηση αντικειμένων δεν έχει ενεργοποιηθεί.",
        "config-diff3-bad": "Το GNU diff3 δεν βρέθηκε.",
        "config-git": "Βρέθηκε το λογισμικό ελέγχου εκδόσεων Git: <code>$1</code>.",
        "config-git-bad": "Το λογισμικό ελέγχου εκδόσεων Git δεν βρέθηκε.",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "To MediaWiki υποστηρίζει τα ακόλουθα συστήματα βάσεων δεδομένων:\n\n$1\n\nΑν δεν εμφανίζεται παρακάτω το σύστημα βάσης δεδομένων που θέλετε να χρησιμοποιήσετε, τότε ακολουθήστε τις οδηγίες στον παραπάνω σύνδεσμο για να ενεργοποιήσετε την υποστήριξη.",
-       "config-dbsupport-mysql": "* Η [{{int:version-db-mysql-url}} MySQL] είναι ο πρωταρχικός στόχος για το MediaWiki και υποστηρίζεται καλύτερα. Το MediaWiki συνεργάζεται επίσης με τη [{{int:version-db-mariadb-url}} MariaDB] και το [{{int:version-db-percona-url}} διακομιστή Percona], που είναι όλα συμβατά με MySQL. ([https://secure.php.net/manual/en/mysqli.installation.php Πώς να μεταγλωττίσετε την PHP με υποστήριξη MySQL])",
-       "config-dbsupport-postgres": "* Η [{{int:version-db-postgres-url}} PostgreSQL] είναι δημοφιλές σύστημα βάσης δεδομένων ανοικτού κώδικα ως εναλλακτική της MySQL. ([https://secure.php.net/manual/en/pgsql.installation.php Πώς να μεταγλωττίσετε την PHP με υποστήριξη PostgreSQL])",
+       "config-dbsupport-mysql": "* Η [{{int:version-db-mysql-url}} MySQL] είναι ο πρωταρχικός στόχος για το MediaWiki και υποστηρίζεται καλύτερα. Το MediaWiki συνεργάζεται επίσης με τη [{{int:version-db-mariadb-url}} MariaDB] και το [{{int:version-db-percona-url}} διακομιστή Percona], που είναι όλα συμβατά με MySQL. ([https://www.php.net/manual/en/mysqli.installation.php Πώς να μεταγλωττίσετε την PHP με υποστήριξη MySQL])",
+       "config-dbsupport-postgres": "* Η [{{int:version-db-postgres-url}} PostgreSQL] είναι δημοφιλές σύστημα βάσης δεδομένων ανοικτού κώδικα ως εναλλακτική της MySQL. ([https://www.php.net/manual/en/pgsql.installation.php Πώς να μεταγλωττίσετε την PHP με υποστήριξη PostgreSQL])",
        "config-dbsupport-sqlite": "* Η [{{int:version-db-sqlite-url}} SQLite] είναι ένα ελαφρύ σύστημα βάσης δεδομένων που υποστηρίζεται πολύ καλά. ([http://www.php.net/manual/en/pdo.installation.php Πώς να μεταγλωττίσετε την PHP με υποστήριξη SQLite], χρησιμοποιεί PDO)",
        "config-dbsupport-oracle": "* Η [{{int:version-db-oracle-url}} Oracle] είναι εμπορική βάση δεδομένων για επιχειρήσεις. ([http://www.php.net/manual/en/oci8.installation.php Πώς να μεταγλωττίσετε την PHP με υποστήριξη OCI8])",
-       "config-dbsupport-mssql": "* Ο [{{int:version-db-mssql-url}} Microsoft SQL Server] είναι εμπορική βάση δεδομένων για επιχειρήσεις που λειτουργεί σε Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php Πώς να μεταγλωττίσετε την PHP με υποστήριξη SQLSRV])",
+       "config-dbsupport-mssql": "* Ο [{{int:version-db-mssql-url}} Microsoft SQL Server] είναι εμπορική βάση δεδομένων για επιχειρήσεις που λειτουργεί σε Windows. ([https://www.php.net/manual/en/sqlsrv.installation.php Πώς να μεταγλωττίσετε την PHP με υποστήριξη SQLSRV])",
        "config-header-mysql": "Ρυθμίσεις MySQL",
        "config-header-postgres": "Ρυθμίσεις PostgreSQL",
        "config-header-sqlite": "Ρυθμίσεις SQLite",
        "config-project-namespace-help": "Ακολουθώντας το παράδειγμα της Βικιπαίδειας, πολλά wiki διατηρούν τις σελίδες πολιτικής τους χωριστά από τις σελίδες περιεχομένου τους, σε έναν '''ονοματοχώρο έργου'''.\nΌλοι οι τίτλοι σελίδων σε αυτόν τον ονοματοχώρο ξεκινούν με συγκεκριμένο πρόθεμα, το οποίο μπορείτε να ορίσετε εδώ.\nΣυνήθως, αυτό το πρόθεμα παράγεται από το όνομα του wiki, αλλά δεν μπορεί να περιέχει χαρακτήρες στίξης όπως «#» ή «:».",
        "config-admin-box": "Λογαριασμός διαχειριστή",
        "config-admin-name": "Το όνομα χρήστη σας:",
-       "config-admin-password": "Î\9aÏ\89δικÏ\8cÏ\82 Ï\80Ï\81Ï\8cÏ\83βαÏ\83ηÏ\82:",
+       "config-admin-password": "ΣÏ\85νθημαÏ\84ικÏ\8c:",
        "config-admin-password-confirm": "Επανάληψη κωδικού πρόσβασης:",
        "config-admin-help": "Εισαγάγετε το προτιμώμενο όνομα χρήστη εδώ, για παράδειγμα «Γιάννης Ιστολόγιος». \nΑυτό είναι το όνομα που θα χρησιμοποιείτε για να συνδέεστε στο wiki.",
        "config-admin-name-blank": "Εισαγάγετε όνομα χρήστη διαχειριστή.",
index c248468..4852380 100644 (file)
        "config-pcre-no-utf8": "<strong>Fatal:</strong> PHP's PCRE module seems to be compiled without PCRE_UTF8 support.\nMediaWiki requires UTF-8 support to function correctly.",
        "config-memory-raised": "PHP's <code>memory_limit</code> is $1, raised to $2.",
        "config-memory-bad": "<strong>Warning:</strong> PHP's <code>memory_limit</code> is $1.\nThis is probably too low.\nThe installation may fail!",
-       "config-apc": "[https://secure.php.net/apc APC] is installed",
-       "config-apcu": "[https://secure.php.net/apcu APCu] is installed",
+       "config-apc": "[https://www.php.net/apc APC] is installed",
+       "config-apcu": "[https://www.php.net/apcu APCu] is installed",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] is installed",
-       "config-no-cache-apcu": "<strong>Warning:</strong> Could not find [https://secure.php.net/apcu APCu] or [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nObject caching is not enabled.",
+       "config-no-cache-apcu": "<strong>Warning:</strong> Could not find [https://www.php.net/apcu APCu] or [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nObject caching is not enabled.",
        "config-mod-security": "<strong>Warning:</strong> Your web server has [https://modsecurity.org/ mod_security]/mod_security2 enabled. Many common configurations of this will cause problems for MediaWiki and other software that allows users to post arbitrary content.\nIf possible, this should be disabled. Otherwise, refer to [https://modsecurity.org/documentation/ mod_security documentation] or contact your host's support if you encounter random errors.",
 
        "config-diff3-bad": "GNU diff3 text comparison utility not found. You can ignore this for now, but might run into edit conflicts more frequently.",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki supports the following database systems:\n\n$1\n\nIf you do not see the database system you are trying to use listed below, then follow the instructions linked above to enable support.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] is the primary target for MediaWiki and is best supported. MediaWiki also works with [{{int:version-db-mysql-url}} MySQL] and [{{int:version-db-percona-url}} Percona Server], which are MariaDB compatible. ([https://secure.php.net/manual/en/mysqli.installation.php How to compile PHP with MySQL support])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] is a popular open source database system as an alternative to MySQL. ([https://secure.php.net/manual/en/pgsql.installation.php How to compile PHP with PostgreSQL support])",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] is a lightweight database system that is very well supported. ([https://secure.php.net/manual/en/pdo.installation.php How to compile PHP with SQLite support], uses PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] is a commercial enterprise database. ([https://secure.php.net/manual/en/oci8.installation.php How to compile PHP with OCI8 support])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] is a commercial enterprise database for Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php How to compile PHP with SQLSRV support])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] is the primary target for MediaWiki and is best supported. MediaWiki also works with [{{int:version-db-mysql-url}} MySQL] and [{{int:version-db-percona-url}} Percona Server], which are MariaDB compatible. ([https://www.php.net/manual/en/mysqli.installation.php How to compile PHP with MySQL support])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] is a popular open source database system as an alternative to MySQL. ([https://www.php.net/manual/en/pgsql.installation.php How to compile PHP with PostgreSQL support])",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] is a lightweight database system that is very well supported. ([https://www.php.net/manual/en/pdo.installation.php How to compile PHP with SQLite support], uses PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] is a commercial enterprise database. ([https://www.php.net/manual/en/oci8.installation.php How to compile PHP with OCI8 support])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] is a commercial enterprise database for Windows. ([https://www.php.net/manual/en/sqlsrv.installation.php How to compile PHP with SQLSRV support])",
        "config-header-mysql": "MariaDB/MySQL settings",
        "config-header-postgres": "PostgreSQL settings",
        "config-header-sqlite": "SQLite settings",
        "config-license-help": "Many public wikis put all contributions under a [https://freedomdefined.org/Definition free license].\nThis helps to create a sense of community ownership and encourages long-term contribution.\nIt is not generally necessary for a private or corporate wiki.\n\nIf you want to be able to use text from Wikipedia, and you want Wikipedia to be able to accept text copied from your wiki, you should choose <strong>{{int:config-license-cc-by-sa}}</strong>.\n\nWikipedia previously used the GNU Free Documentation License.\nThe GFDL is a valid license, but it is difficult to understand.\nIt is also difficult to reuse content licensed under the GFDL.",
        "config-email-settings": "Email settings",
        "config-enable-email": "Enable outbound email",
-       "config-enable-email-help": "If you want email to work, [https://secure.php.net/manual/en/mail.configuration.php PHP's mail settings] need to be configured correctly.\nIf you do not want any email features, you can disable them here.",
+       "config-enable-email-help": "If you want email to work, [https://www.php.net/manual/en/mail.configuration.php PHP's mail settings] need to be configured correctly.\nIf you do not want any email features, you can disable them here.",
        "config-email-user": "Enable user-to-user email",
        "config-email-user-help": "Allow all users to send each other email if they have enabled it in their preferences.",
        "config-email-usertalk": "Enable user talk page notification",
        "config-install-done": "<strong>Congratulations!</strong>\nYou have installed MediaWiki.\n\nThe installer has generated a <code>LocalSettings.php</code> file.\nIt contains all your configuration.\n\nYou will need to download it and put it in the base of your wiki installation (the same directory as index.php). The download should have started automatically.\n\nIf the download was not offered, or if you cancelled it, you can restart the download by clicking the link below:\n\n$3\n\n<strong>Note:</strong> If you do not do this now, this generated configuration file will not be available to you later if you exit the installation without downloading it.\n\nWhen that has been done, you can <strong>[$2 enter your wiki]</strong>.",
        "config-install-done-path": "<strong>Congratulations!</strong>\nYou have installed MediaWiki.\n\nThe installer has generated a <code>LocalSettings.php</code> file.\nIt contains all your configuration.\n\nYou will need to download it and put it at <code>$4</code>. The download should have started automatically.\n\nIf the download was not offered, or if you cancelled it, you can restart the download by clicking the link below:\n\n$3\n\n<strong>Note:</strong> If you do not do this now, this generated configuration file will not be available to you later if you exit the installation without downloading it.\n\nWhen that has been done, you can <strong>[$2 enter your wiki]</strong>.",
        "config-install-success": "MediaWiki has been successfully installed. You can now visit <$1$2> to view your wiki.\nIf you have questions, check out our frequently asked questions list:\n<https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ> or use one of the\nsupport forums linked on that page.",
+       "config-install-db-success": "Database was successfully set up",
        "config-download-localsettings": "Download <code>LocalSettings.php</code>",
        "config-help": "help",
        "config-help-tooltip": "click to expand",
index 924bc2b..364209c 100644 (file)
@@ -41,8 +41,8 @@
        "config-env-bad": "La medio estas kontrolita.\nNe eblas instali MediaWiki.",
        "config-env-php": "PHP $1 estas instalita.",
        "config-env-hhvm": "HHVM $1 estas instalita.",
-       "config-apc": "[https://secure.php.net/apc APC] estas instalita",
-       "config-apcu": "[https://secure.php.net/apcu APCu] estas instalita",
+       "config-apc": "[https://www.php.net/apc APC] estas instalita",
+       "config-apcu": "[https://www.php.net/apcu APCu] estas instalita",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] estas instalita",
        "config-diff3-bad": "GNU diff3 ne estis trovita.",
        "config-db-type": "Tipo de datumbazo:",
index 8048a26..6b8ceb2 100644 (file)
        "config-pcre-no-utf8": "'''Error fatal ''': Parece que el módulo PCRE de PHP fue compilado sin el soporte PCRE_UTF8.\nMediaWiki requiere compatibilidad con UTF-8 para funcionar correctamente.",
        "config-memory-raised": "El parámetro <code>memory_limit</code> de PHP es $1. Se aumenta a $2.",
        "config-memory-bad": "<strong>Advertencia:</strong> el parámetro <code>memory_limit</code> de PHP es $1.\nProbablemente sea demasiado bajo.\n¡La instalación puede fallar!",
-       "config-apc": "[https://secure.php.net/apc APC] está instalado",
-       "config-apcu": "[https://secure.php.net/apcu APCu] está instalado",
+       "config-apc": "[https://www.php.net/apc APC] está instalado",
+       "config-apcu": "[https://www.php.net/apcu APCu] está instalado",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] está instalado",
-       "config-no-cache-apcu": "<strong>Atención:</strong> no se pudo encontrar [https://secure.php.net/apcu APCu] o [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nEl almacenamiento en antememoria de objetos no está activado.",
+       "config-no-cache-apcu": "<strong>Atención:</strong> no se pudo encontrar [https://www.php.net/apcu APCu] o [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nEl almacenamiento en caché de objetos no está activado.",
        "config-mod-security": "<strong>Advertencia:</strong> tu servidor web tiene activado [https://modsecurity.org/ mod_security]/mod_security2. Muchas de sus configuraciones comunes pueden causar problemas a MediaWiki u otro software que permita a los usuarios publicar contenido arbitrario. De ser posible, deberías desactivarlo. Si no, consulta la [https://modsecurity.org/documentation/ documentación de mod_security] o contacta con el administrador de tu servidor si encuentras errores aleatorios.",
        "config-diff3-bad": "GNU diff3 no se encuentra.",
        "config-git": "Se encontró el software de control de versiones Git: <code>$1</code>.",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki es compatible con los siguientes sistemas de bases de datos:\n\n$1\n\nSi no encuentras en el listado el sistema de base de datos que estás intentando utilizar, sigue las instrucciones enlazadas arriba para activar la compatibilidad.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] es la base de datos mayoritaria para MediaWiki y la que goza de mayor compatibilidad. MediaWiki también funciona con [{{int:version-db-myslql-url}} MySQL] y [{{int:version-db-percona-url}} Percona Server], que son compatibles con MariaDB. ([https://secure.php.net/manual/es/mysql.installation.php Cómo compilar PHP con compatibilidad MySQL])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] es un sistema de base de datos popular de código abierto, alternativa a MySQL. ([https://secure.php.net/manual/es/pgsql.installation.php Cómo compilar PHP con compatibilidad PostgreSQL]).",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] es un sistema de base de datos ligero con gran compatibilidad con MediaWiki. ([https://secure.php.net/manual/en/pdo.installation.php Cómo compilar PHP con compatibilidad SQLite], usando PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] es una base de datos comercial a nivel empresarial. ([https://secure.php.net/manual/en/oci8.installation.php Cómo compilar PHP con compatibilidad con OCI8])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] es un sistema comercial de base de datos empresariales para Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php Cómo compilar PHP con compatibilidad con SQLSRV])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] es la base de datos mayoritaria para MediaWiki y la que goza de mayor compatibilidad. MediaWiki también funciona con [{{int:version-db-myslql-url}} MySQL] y [{{int:version-db-percona-url}} Percona Server], que son compatibles con MariaDB. ([https://www.php.net/manual/es/mysql.installation.php Cómo compilar PHP con compatibilidad MySQL])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] es un sistema de base de datos popular de código abierto, alternativa a MySQL. ([https://www.php.net/manual/es/pgsql.installation.php Cómo compilar PHP con compatibilidad PostgreSQL]).",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] es un sistema de base de datos ligero con gran compatibilidad con MediaWiki. ([https://www.php.net/manual/en/pdo.installation.php Cómo compilar PHP con compatibilidad SQLite], usando PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] es una base de datos comercial a nivel empresarial. ([https://www.php.net/manual/en/oci8.installation.php Cómo compilar PHP con compatibilidad con OCI8])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] es un sistema comercial de base de datos empresariales para Windows. ([https://www.php.net/manual/en/sqlsrv.installation.php Cómo compilar PHP con compatibilidad con SQLSRV])",
        "config-header-mysql": "Configuración de MariaDB/MySQL",
        "config-header-postgres": "Configuración de PostgreSQL",
        "config-header-sqlite": "Configuración de SQLite",
        "config-license-help": "Muchos wikis públicos ponen todas las contribuciones bajo una [https://freedomdefined.org/Definition licencia libre].\nEsto ayuda a crear un sentido de propiedad comunitaria y alienta la contribución a largo plazo.\nEsto no es generalmente necesario para un wiki privado o corporativo.\n\nSi deseas poder utilizar texto de Wikipedia, y deseas que Wikipedia pueda aceptar el texto copiado de tu wiki, debes elegir <strong>{{int:config-license-cc-by-sa}}</strong>.\n\nWikipedia utilizaba anteriormente la licencia de documentación libre de GNU (GFDL).\nLa GFDL es una licencia válida, pero es difícil de entender.\nTambién es difícil reutilizar el contenido licenciado bajo la GFDL.",
        "config-email-settings": "Configuración de correo electrónico",
        "config-enable-email": "Activar el envío de correos electrónicos",
-       "config-enable-email-help": "Si quieres que el correo electrónico funcione, la [https://secure.php.net/manual/en/mail.configuration.php configuración PHP de correo electrónico] debe ser la correcta.\nSi no quieres ninguna funcionalidad de correo electrónico, puedes desactivarlas aquí.",
+       "config-enable-email-help": "Si quieres que el correo electrónico funcione, la [https://www.php.net/manual/en/mail.configuration.php configuración PHP de correo electrónico] debe ser la correcta.\nSi no quieres ninguna funcionalidad de correo electrónico, puedes desactivarlas aquí.",
        "config-email-user": "Activar correo electrónico entre usuarios",
        "config-email-user-help": "Permitir que todos los usuarios intercambien correos electrónicos si lo han activado en sus preferencias.",
        "config-email-usertalk": "Activar notificaciones de páginas de discusión de usuarios",
        "config-cc-again": "Elegir otra vez...",
        "config-cc-not-chosen": "Elige la licencia Creative Commons que desees y haz clic en \"proceed\".",
        "config-advanced-settings": "Configuración avanzada",
-       "config-cache-options": "Configuración de la antememoria de objetos:",
+       "config-cache-options": "Configuración de la caché de objetos:",
        "config-cache-help": "El almacenamiento en caché de objetos se utiliza para mejorar la velocidad de MediaWiki mediante el almacenamiento en caché los datos usados más frecuentemente.\nA los sitios medianos y grandes se les recomienda que permitirlo. También es beneficioso para los sitios pequeños.",
        "config-cache-none": "Sin almacenamiento en caché (no se pierde ninguna funcionalidad, pero la velocidad puede resentirse en sitios grandes)",
-       "config-cache-accel": "Almacenamiento en antememoria de objetos PHP (APC, APCu o WinCache)",
+       "config-cache-accel": "Almacenamiento en caché de objetos PHP (APC, APCu o WinCache)",
        "config-cache-memcached": "Utilizar Memcached (necesita ser instalado y configurado aparte)",
        "config-memcached-servers": "Servidores Memcached:",
        "config-memcached-help": "Lista de direcciones IP que serán usadas por Memcached.\nDeben especificarse una por cada línea y especificar el puerto a utilizar. Por ejemplo:\n127.0.0.1:11211\n192.168.1.25:1234",
        "config-install-done": "<strong>¡Felicidades!</strong>\nHas instalado MediaWiki.\n\nEl instalador ha generado un archivo <code>LocalSettings.php</code>.\nEste contiene toda su configuración.\n\nDeberás descargarlo y ponerlo en la base de la instalación de wiki (el mismo directorio que index.php). La descarga debería haber comenzado automáticamente.\n\nSi no comenzó la descarga, o si se ha cancelado, puedes reiniciar la descarga haciendo clic en el siguiente enlace:\n\n$3\n\n<strong>Nota</strong>: si no haces esto ahora, este archivo de configuración generado no estará disponible más tarde si sales de la instalación sin descargarlo.\n\nCuando lo hayas hecho, podrás <strong>[$2 entrar en tu wiki]</strong>.",
        "config-install-done-path": "<strong>¡Felicidades!</strong>\nHas instalado MediaWiki.\n\nEl instalador ha generado un archivo <code>LocalSettings.php</code>.\nEste contiene toda su configuración.\n\nDeberás descargarlo y ponerlo en <code>$4</code>. La descarga debería haber comenzado automáticamente.\n\nSi no comenzó la descarga, o si se ha cancelado, puedes reiniciar la descarga haciendo clic en el siguiente enlace:\n\n$3\n\n<strong>Nota</strong>: si no haces esto ahora, este archivo de configuración generado no estará disponible más tarde si sales de la instalación sin descargarlo.\n\nCuando lo hayas hecho, podrás <strong>[$2 entrar en tu wiki]</strong>.",
        "config-install-success": "Se instaló MediaWiki correctamente. Ahora puedes visitar\n<$1$2> para ver el wiki.\nSi tienes dudas, echa un vistazo a la lista de preguntas frecuentes:\n<https://www.mediawiki.org/wiki/Manual:FAQ>, o bien, utiliza uno de\nlos foros de asistencia que se enumeran en esa página.",
+       "config-install-db-success": "Se configuró la base de datos correctamente",
        "config-download-localsettings": "Descargar <code>LocalSettings.php</code>",
        "config-help": "ayuda",
        "config-help-tooltip": "pulsa para ampliar",
index d681fe3..61a1d2f 100644 (file)
        "config-pcre-no-utf8": "<strong>Fatal:</strong> PHREko PCRE modulua PCRE_UTF8 ko laguntza gabe bildu da.\nMediaWiki-k UTF-8 euskarria behar du behar bezala funtziona dezan.",
        "config-memory-raised": "PHP-ko <code>memory_limit</code> $1 da, $2-ra igota.",
        "config-memory-bad": "<strong>Warning:</strong> PHPko <code>memory_limit</code> $1 da.\nZiurrenik hau oso baxua da.\nInstalazioa huts egin dezake!",
-       "config-apc": "[https://secure.php.net/apc APC] instalatuta dago",
-       "config-apcu": "[https://secure.php.net/apcu APCu] instalatuta dago",
+       "config-apc": "[https://www.php.net/apc APC] instalatuta dago",
+       "config-apcu": "[https://www.php.net/apcu APCu] instalatuta dago",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] instalatuta dago",
-       "config-no-cache-apcu": "<strong>Warning:</strong> Ezin izan da [https://secure.php.net/apcu APCu] edo [https://www.iis.net/downloads/microsoft/wincache-extension WinCache] aurkitu.\nObjektu katxea ez dago aktibatuta.",
+       "config-no-cache-apcu": "<strong>Warning:</strong> Ezin izan da [https://www.php.net/apcu APCu] edo [https://www.iis.net/downloads/microsoft/wincache-extension WinCache] aurkitu.\nObjektu katxea ez dago aktibatuta.",
        "config-mod-security": "<strong>Warning:</strong> Zure web zerbitzariak [https://modsecurity.org/mod_security] / mod_security2 aktibatu du. Honen konfigurazio komun asko sortu ahal dituzte arazoak MediaWikin  eta beste software batzuetan, hautazko edukia argitaratzeko aukera ematen dutenei erabiltzaileei.\nAhal izanez gero, desgaitu egin beharko litzateke. Bestela, kontsultatu [https://modsecurity.org/documentation/ mod_security documentation] edo jarri harremanetan zure ostalariarekin ausazko akatsak aurkitzen badituzu.",
        "config-diff3-bad": "GNU diff3 ez da aurkitu.",
        "config-git": "Git bertsio-kontrol software aurkitu da: <code>$1</code>",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki-k onartzen du hurrengo datu-base sistemak:\n\n$1\n\nListan ez baduzu ikusten erabili nahi duzun sistema, jarraitu goiko argibideak aktibatzeko.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] MediaWikiren lehenengoko helburua da eta primeran babesturik dago. MediaWikik ere [{{int:version-db-mariadb-url}} MariaDB]-rekin egiten du lan baita [{{int:version-db-percona-url}} Percona Server]-kin, MySQL-rekin balio dutenak. ([https://secure.php.net/manual/en/mysqli.installation.php How to compile PHP with MySQL support])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] iturburu irekiko datu basea sistema famatua da MySQL-rako alternatiba bezala. ([https://secure.php.net/manual/en/pgsql.installation.php How to compile PHP with PostgreSQL support])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] MediaWikiren lehenengoko helburua da eta primeran babesturik dago. MediaWikik ere [{{int:version-db-mariadb-url}} MariaDB]-rekin egiten du lan baita [{{int:version-db-percona-url}} Percona Server]-kin, MySQL-rekin balio dutenak. ([https://www.php.net/manual/en/mysqli.installation.php How to compile PHP with MySQL support])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] iturburu irekiko datu basea sistema famatua da MySQL-rako alternatiba bezala. ([https://www.php.net/manual/en/pgsql.installation.php How to compile PHP with PostgreSQL support])",
        "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] oso ondo onartzen duen datu-basearen sistema arina da.\n ([http://www.php.net/manual/en/pdo.installation.php How to compile PHP with SQLite support], uses PDO)",
        "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] enpresa komertzial baten datu-basea da. ([http://www.php.net/manual/en/oci8.installation.php How to compile PHP with OCI8 support])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] Windows-entzako enpresa komertzial baten datu-basea da.  ([https://secure.php.net/manual/en/sqlsrv.installation.php How to compile PHP with SQLSRV support])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] Windows-entzako enpresa komertzial baten datu-basea da.  ([https://www.php.net/manual/en/sqlsrv.installation.php How to compile PHP with SQLSRV support])",
        "config-header-mysql": "MySQL hobespenak",
        "config-header-postgres": "PostgreSQL hobespenak",
        "config-header-sqlite": "SQLite hobespenak",
index 3102bfb..b17b093 100644 (file)
                        "درفش کاویانی",
                        "Hamisun",
                        "Alifakoor",
-                       "Seb35"
+                       "Seb35",
+                       "Ahmad252",
+                       "FarsiNevis"
                ]
        },
-       "config-desc": "نصب کنندهٔ مدیاویکی",
+       "config-desc": "نصبکنندهٔ مدیاویکی",
        "config-title": "نصب مدیاویکی $1",
        "config-information": "اطلاعات",
        "config-localsettings-upgrade": "یک پرونده <code>LocalSettings.php</code> شناسایی شده‌است.\nبرای ارتقاء این نصب لطفاً مقدار <code>$wgUpgradeKey</code> در جعبه زیر وارد کنید.\nشما می‌توانید آن را در <code>LocalSettings.php</code> پیدا کنید.",
        "config-pcre-no-utf8": "<strong>مخرب:</strong> به‌ نظر می‌رسد پودمان پی‌سی‌آراییِ پی‌اچ‌پی بدون پشتیبانی پی‌سی‌آرایی_یو‌تی‌اف۸ تهیه شده‌است.\nمدیاویکی برای درست عمل کردن نیازمند پشتیبانی یوتی‌اف-۸ است.",
        "config-memory-raised": "PHP's <code>memory_limit</code>, نسخهٔ $1 است، به نسخهٔ $2 ارتقاء داده شده‌است.",
        "config-memory-bad": "'''هشدار:''' PHP's <code>memory_limit</code> نسخهٔ $1 است.\nاین ممکن است خیلی پایین باشد.\nممکن است نصب با مشکل رو‌به‌رو شود.",
-       "config-apc": "[https://secure.php.net/apc APC] نصب شده‌است.",
-       "config-apcu": "[https://secure.php.net/apcu APCu] نصب شده‌است",
+       "config-apc": "[https://www.php.net/apc APC] نصب شده‌است.",
+       "config-apcu": "[https://www.php.net/apcu APCu] نصب شده‌است",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] نصب شده‌است.",
-       "config-no-cache-apcu": "<strong>هشدار:</strong> پیوند [https://secure.php.net/apcu APCu] یا [https://www.iis.net/downloads/microsoft/wincache-extension WinCache] یافت نشد. ذخیره شی فعال نیست.",
+       "config-no-cache-apcu": "<strong>هشدار:</strong> پیوند [https://www.php.net/apcu APCu] یا [https://www.iis.net/downloads/microsoft/wincache-extension WinCache] یافت نشد. ذخیره شی فعال نیست.",
        "config-mod-security": "'''هشدار:''' وب سرور شما [https://modsecurity.org/ mod_security] فعال است.اگر اشتباه پیکربندی شده‌‌ باشد،می تواند باعث ایجاد مشکلاتی برای مدیاویکی یا دیگر نرم‌افزاری شود که به کاربران اجازه می‌دهد پیام دلخواه ارسال کنند.\nبه [https://modsecurity.org/documentation/ mod_security documentation] مراجعه کنید یا اگر با خطاهای اتفاقی مواجه شدید با پشتیبانی میزبان خود در تماس باشید.",
-       "config-diff3-bad": "جÛ\8câ\80\8cاÙ\86â\80\8cÛ\8cÙ\88 Ø¯Û\8cÙ\81Û³ Ù¾Û\8cدا Ù\86Ø´د.",
+       "config-diff3-bad": "ابزار Ù\85Ù\82اÛ\8cسÙ\87 Ù\85تÙ\86 ØªÙ\81اÙ\88ت۳ Ú¯Ù\86Ù\88 Ù¾Û\8cدا Ù\86شد. Ù\85Û\8câ\80\8cتÙ\88اÙ\86Û\8cد Ù\81عÙ\84اÙ\8b Ø§Û\8cÙ\86 Ù¾Û\8cاÙ\85 Ø±Ø§ Ù\86ادÛ\8cدÙ\87 Ø¨Ú¯Û\8cرÛ\8cدØ\8c Ø§Ù\85ا Ù\85Ù\85Ú©Ù\86 Ø§Ø³Øª Ø¨Ù\87 Ø¯Ù\81عات Ø¨Û\8cشترÛ\8c Ø¯Ú\86ار ØªØ¹Ø§Ø±Ø¶ Ù\88Û\8cراÛ\8cØ´Û\8c Ø´Ù\88Û\8cد.",
        "config-git": "کنترل نسخهٔ نرم‌افزار گیت پیدا شد: <code>$1</code>.",
-       "config-git-bad": "کنترل نسخهٔ نرم‌افزار گیت پیدا نشد.",
+       "config-git-bad": "کنترل نسخهٔ نرم‌افزار گیت پیدا نشد. فعلاً می‌توانید این پیام را نادیده بگیرید. در نظر داشته باشید که ویژه:نسخه، توابع درهم‌سازی‌شده را نمایش نخواهد داد.",
        "config-imagemagick": "ایمیج‌مجیک پیدا شد: <code>$1</code>.\nاگر ارسال‌ها را فعال کنید،تصویر کوچک فعال خواهد‌شد.",
        "config-gd": "گرافیک‌های جی‌دی ساخته‌‌ شده در کتابخانه پیدا شد.\nاگر ارسال‌ها را فعال کنید تصویر کوچک فعال خواهد‌شد.",
        "config-no-scaling": "کتابخانهٔ جی‌دی یا ایمیج‌مجیک نتوانست پیدا شود.\nتصویر کوچک غیر‌فعال خواهد‌شد.",
        "config-using-32bit": "<strong>هشدار:</strong> سیستم شما به‌نظر می‌آید با اعداد صحیح ۳۲ بیت اجرا شده باشد. [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:32-bit توصیه نمی‌شود].",
        "config-db-type": "نوع پایگاه اطلاعات:",
        "config-db-host": "میزبان پایگاه اطلاعات:",
-       "config-db-host-help": "اگر سرور پایگاه اطلاعاتی شما در سرور دیگری است، نام گروه و آدرس آی‌پی را اینجا وارد کنید.\nاگر از گروه شبکهٔ اشتراک گذاری استفاده می‌کنید، تهیه‌کنندهٔ گروه‌تان باید نام گروه صحیح در اسنادومدارک را به شما بدهد.\nاگر در حال نصب یک سرور ویندوز هستید و از مای‌اس‌کیو‌ال استفاده می‌کنید، ممکن است استفاده از \"گروه داخلی\" برای نام سرور کار نکند.اگر کار نکرد، \"۱۲۷.۰.۰.۱\" را برای آدرس آی‌پی داخلی امتحان کنید.\nاگر از پستگِرِاس‌کیوال استفاده می‌کنید،برای اتصال از طریق یک سوکت یونیکس این زمینه را خالی رها کنید.",
+       "config-db-host-help": "اگر سرور پایگاه اطلاعاتی شما در سرور دیگری است، نام گروه و آدرس آی‌پی را اینجا وارد کنید.\nاگر از میزبان شبکهٔ به اشتراک گذاشته‌شده استفاده می‌کنید، تهیه‌کنندهٔ خدمات میزبانی شما باید نام میزبان صحیح در اسناد و مدارک را به شما بدهد.\nاگر از مای‌اس‌کیو‌ال استفاده می‌کنید، ممکن است استفاده از «میزبان‌محلی» برای نام سرور کار نکند.اگر کار نکرد، «۱۲۷.۰.۰.۱» را برای آدرس آی‌پی محلی امتحان کنید.\nاگر از پستگرس‌کیوال استفاده می‌کنید، برای اتصال از طریق یک سوکت یونیکس این قسمت را خالی رها کنید.",
        "config-db-host-oracle": "پایگاه اطلاعاتی تی‌ان‌اس:",
        "config-db-host-oracle-help": "یک [http://download.oracle.com/docs/cd/B28359_01/network.111/b28317/tnsnames.htm Local Connect Name] معتبر وارد کنید؛ پوشهٔ tnsnames.ora باید برای این نصب نمایان باشد.<br /> اگر از کتابخانه‌های پردازشگر ۱۰جی یا جدیدتر استفاده می‌کنید،همچنین می‌توانید از روش نامبردهٔ [http://download.oracle.com/docs/cd/E11882_01/network.112/e10836/naming.htm Easy Connect] استفاده کنید.",
        "config-db-wiki-settings": "این ویکی را شناسایی کنید.",
-       "config-db-name": "Ù\86اÙ\85 Ù¾Ø§Û\8cگاÙ\87 Ø§Ø·Ù\84اعاتÛ\8c:",
+       "config-db-name": "Ù\86اÙ\85 Ù¾Ø§Û\8cگاÙ\87 Ø¯Ø§Ø¯Ù\87 (بدÙ\88Ù\86 Ø®Ø· Ù¾Û\8cÙ\88Ù\86د):",
        "config-db-name-help": "نامی را انتخاب کنید که ویکی شما را شناسایی کند.\nنباید شامل فاصله باشد.\nاگر از گروه شبکهٔ اشتراک‌گذاری استفاده می‌کنید، تهیه‌کنندهٔ گروهتان یا باید به شما نام یک پایگاه اطلاعاتی مشخص برای استفاده بدهد یا برای ایجاد پایگاه‌های اطلاعاتی از طریق یک کنترل پنل به شما اجازه بدهد.",
        "config-db-name-oracle": "طرح کلی پایگاه اطلاعاتی:",
        "config-db-account-oracle-warn": "برای نصب برنامهٔ اوراکل به عنوان پایگاه اطلاعاتی در بخش گذشته،سه سناریو پشتیبانی شده است:\nاگر مایل به ایجاد حساب پایگاه اطلاعاتی به عنوان بخشی از روند نصب هستید، لطفاً یک حساب با نقش اس‌وای‌اس‌دی‌بی‌ای به عنوان حساب پایگاه اطلاعاتی برای نصب تهیه کنید و اعتبارنامه‌های مطلوبی را برای حساب دردسترس شبکه تعیین کنید، به عبارتی دیگر یا می‌توانید حساب دردسترس شبکه را به طور دستی ایجاد کنید و تنها آن حساب را تهیه کنید (اگر مستلزم مجوزهایی برای ایجاد موضوعات طرح کلی باشد) یا دو حساب دیگر تهیه کنید،یکی با ایجاد مزایا و یک حساب محدود برای دسترسی شبکه.\nمتنی برای ایجاد یک حساب با مزایای لازم بنویسید که می‌تواند در فهرست\"نگهداری/برنامهٔ اوراکل\" این نصب یافت شود. به یاد داشته باشید که استفاده از یک حساب محدود،همهٔ قابلیت‌های نگهداری با حساب پیش‌فرض را غیرفعال خواهد کرد.",
        "config-db-account-lock": "در طی عملیات عادی از نام کاربری و رمز عبور یکسان استفاده کنید",
        "config-db-wiki-account": "حساب کاربری برای عملیات عادی",
        "config-db-wiki-help": "نام کاربری و رمز عبوری را وارد کنید که برای اتصال به پایگاه اطلاعاتی در طی عملیات عادی ویکی استفاده خواهید‌کرد.\nاگر حساب وجود ندارد، و نصب حساب مزایای کافی را داراست، این حساب کاربر با حداقل مزایای مورد نیاز برای عمل کردن ویکی به‌وجود خواهد‌آمد.",
-       "config-db-prefix": "جدÙ\88Ù\84 Ù¾Û\8cØ´Ù\88Ù\86د Ù¾Ø§Û\8cگاÙ\87 Ø§Ø·Ù\84اعاتÛ\8c",
+       "config-db-prefix": "جدÙ\88Ù\84 Ù¾Û\8cØ´Ù\88Ù\86د Ù¾Ø§Û\8cگاÙ\87 Ø¯Ø§Ø¯Ù\87 (بدÙ\88Ù\86 Ø®Ø· Ù¾Û\8cÙ\88Ù\86د):",
        "config-db-prefix-help": "اگر نیاز دارید یک اطلاعات پایگاهی را بین چندین ویکی یا بین مدیاویکی و برنامهٔ کاربردی وب دیگری به اشتراک بگذارید،مجاز به انتخاب برای اضافه کردن یک پیشوند به همهٔ  نام‌های جدول برای جلوگیری از اختلاف‌ها هستید.\nاز فاصله‌ها استفاده نکنید.\nاغلب این زمینه خالی مانده‌است.",
        "config-mysql-old": "مای‌اس‌کیو‌ال نسخهٔ $1 و یا بالاتر نیاز است، شما نسخهٔ $2 را دارید.",
        "config-db-port": "درگاه پایگاه‌داده:",
-       "config-db-schema": "طرح کلی برای مدیاویکی:",
+       "config-db-schema": "طرح کلی برای مدیاویکی (بدون خط پیوند):",
        "config-db-schema-help": "طرح کلی اغلب بی‌نقص خواهد بود.\nاگر می‌دانید نیاز دارید که تغییرش دهید،آن را تغییر دهید.",
        "config-pg-test-error": "نمی‌توان به پایگاه اطلاعاتی '''$1''' وصل شد: $2",
        "config-sqlite-dir": "فهرست اطلاعات اس‌کیو‌لایت:",
        "config-type-mysql": "MariaDB، مای‌اس‌کیو‌ال (یا سازگار)",
        "config-type-mssql": "سرور مایکروسافت اس‌کیو‌ال",
        "config-support-info": "مدیاویکی سامانه‌های پایگاه اطلاعاتی زیر را حمایت می‌کند:\n$1\nاگر متوجه سامانه پایگاه اطلاعاتی که سعی دارید از فهرست زیر استفاده کنید، نمی‌شوید، بنابراین دستورالعمل‌های مرتبط در بالا را برای فعال کردن پشتیبانی دنبال کنید.",
-       "config-dbsupport-mysql": "*[{{int:version-db-mariadb-url}} MariaDB] مهم‌ترین هدف برای مدیاویکی است و بهترین پشتیبانی. مدیاویکی همچنین کار می‌کند با [{{int:version-db-mysql-url}} MariaDB] و [{{int:version-db-percona-url}} Percona Server] که با MariaDB سازگار هستند.([https://secure.php.net/manual/en/mysqli.installation.php چگونه php را با MariaDB کامپایل کنیم])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} پستگرس‌کیوال] یک سامانه پایگاه اطلاعات متن‌باز پر‌طرفدار است که جایگزینی برای مای‌اس‌کیوال است. ([https://secure.php.net/manual/en/pgsql.installation.php راهنمای تنظیم کردن پی‌اچ‌پی به همراه پستگرس‌کیوال])",
-       "config-dbsupport-sqlite": "*[{{int:version-db-sqlite-url}} اس‌کیولایت] یک سامانه پایگاه اطلاعاتی کم حجمی است که بسیار خوب پشتیبانی شده‌است.\n([https://secure.php.net/manual/en/pdo.installation.php چگونگی کامپایل پی‌اچ‌پی با اس‌کیولایت]، از PDO استفاده می‌کند)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] یک پایگاه اطلاعاتی کار تبلیغاتی است.\n([https://secure.php.net/manual/en/oci8.installation.php How to compile PHP with OCI8 support])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] یک پایگاه اطلاعاتی موسسهٔ تبلیغاتی برای وینذوز است. ([https://secure.php.net/manual/en/sqlsrv.installation.php How to compile PHP with SQLSRV support])",
+       "config-dbsupport-mysql": "*[{{int:version-db-mariadb-url}} MariaDB] مهم‌ترین هدف برای مدیاویکی است و بهترین پشتیبانی. مدیاویکی همچنین کار می‌کند با [{{int:version-db-mysql-url}} MariaDB] و [{{int:version-db-percona-url}} Percona Server] که با MariaDB سازگار هستند.([https://www.php.net/manual/en/mysqli.installation.php چگونه php را با MariaDB کامپایل کنیم])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} پستگرس‌کیوال] یک سامانه پایگاه اطلاعات متن‌باز پر‌طرفدار است که جایگزینی برای مای‌اس‌کیوال است. ([https://www.php.net/manual/en/pgsql.installation.php راهنمای تنظیم کردن پی‌اچ‌پی به همراه پستگرس‌کیوال])",
+       "config-dbsupport-sqlite": "*[{{int:version-db-sqlite-url}} اس‌کیولایت] یک سامانه پایگاه اطلاعاتی کم حجمی است که بسیار خوب پشتیبانی شده‌است.\n([https://www.php.net/manual/en/pdo.installation.php چگونگی کامپایل پی‌اچ‌پی با اس‌کیولایت]، از PDO استفاده می‌کند)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] یک پایگاه اطلاعاتی کار تبلیغاتی است.\n([https://www.php.net/manual/en/oci8.installation.php How to compile PHP with OCI8 support])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] یک پایگاه اطلاعاتی موسسهٔ تبلیغاتی برای وینذوز است. ([https://www.php.net/manual/en/sqlsrv.installation.php How to compile PHP with SQLSRV support])",
        "config-header-mysql": "تنظیمات MariaDB/مای‌اس‌کیو‌ال",
        "config-header-postgres": "تنظیمات پست‌گر‌اس‌کیو‌ال",
        "config-header-sqlite": "تنظیمات اس‌کیو‌لایت",
        "config-invalid-db-server-oracle": "تی‌ان‌اس پایگاه اطلاعاتی $1 نامعتبر.\nیا از \"نام تی‌ان‌اس\" یا یک سلسله \"ارتباط آسان\" ([http://docs.oracle.com/cd/E11882_01/network.112/e10836/naming.htm Oracle Naming Methods]) استفاده کنید.",
        "config-invalid-db-name": "نام پایگاه اطلاعاتی نامعتبر \"$1\".\nفقط حروف اِی‌اس‌سی‌آی‌آی بزرگ (اِی-زدکوچک،اِی-زد بزرگ)،اعداد (۰-۹)،آندرلاین (_) و خط تیره کوتاه (-) استفاده کنید.",
        "config-invalid-db-prefix": "پیشوند پایگاه اطلاعاتی نامعتبر \"$1\".\nفقط حروف اِی‌اس‌سی‌آی‌آی بزرگ (اِی-زدکوچک،اِی-زد بزرگ)،اعداد (۰-۹)،آندرلاین (_) و خط تیره کوتاه (-) استفاده کنید.",
-       "config-connection-error": "$1.\n\nمیزبان، نام کاربری و گذرواژه را بررسی کنید و دوباره امتحان کنید.",
+       "config-connection-error": "$1.\n\nمیزبان، نام کاربری و گذرواژه را بررسی کرده و دوباره امتحان کنید. اگر از «میزبان محلی» به عنوان میزبان پایگاه داده استفاده می‌کنید، استفاده از «۱۲۷.۰.۰.۱» را امتحان کنید (یا برعکس).",
        "config-invalid-schema": "طرح‌کلی برای مدیاویکی نامعتبر \"$1\".\nفقط حروف اِی‌اس‌سی‌آی‌آی بزرگ (اِی-زدکوچک،اِی-زد بزرگ)،اعداد (۰-۹)،آندرلاین (_) و خط تیره کوتاه (-) استفاده کنید.",
        "config-db-sys-create-oracle": "نصب‌کننده تنها از استفادهٔ یک حساب اس‌وای‌اس‌دی‌بی‌اِی برای ایجاد یک حساب جدید حمایت می‌کند.",
        "config-db-sys-user-exists-oracle": "حساب کاربری \"$1\" در‌حال‌حاضر وجود دارد.تنها اس‌وای‌اس‌دی‌بی‌اِی می‌تواند برای ایجاد یک حساب جدید استفاده شود!",
        "config-sqlite-cant-create-db": "پوشه‌ٔ پایگاه اطلا‌عاتی <code>$1</code>نتوانست ایجاد شود.",
        "config-sqlite-fts3-downgrade": "پی‌اچ‌پی، پشتیبانی اف‌تی‌اس۳ کار نمی‌کند، کاهش جدول‌ها",
        "config-can-upgrade": "جدول‌های مدیاویکی در این پایگاه اطلاعاتی وجود دارند.\nبرای ارتقاء دادن آنها به مدیاویکی $1، '''ادامه''' را کلیک کنید.",
+       "config-upgrade-error": "در به‌روزرسانی جدول‌های مدیاویکی در پایگاه داده شما خطایی پیش آمد.\n\nبرای اطلاعات بیشتر به سیاهۀ بالا نگاه کنید. برای تلاش دوباره، روی <strong>ادامه</strong> کلیک کنید.",
        "config-upgrade-done": "تکمیل ارتقاء.\nاکنون شما می‌توانید [$1 start using your wiki].\nاگر می‌خواهید پوشهٔ <code>LocalSettings.php</code> را احیا کنید،دکمهٔ زیر را کلیک کنید.\nاین ''' توصیه نمی‌شود ''' مگر اینکه با ویکی خود مشکل داشته باشید.",
        "config-upgrade-done-no-regenerate": "ارتقاء کامل شد.\nاکنون شما می‌توانید [$1 start using your wiki].",
        "config-regenerate": "بازسازی LocalSettings.php ←",
        "config-license-help": "بسیاری از وبگاه‌ها ویرایش‌های ها را با  [https://freedomdefined.org/Definition اجازه‌نامهٔ آزاد] منتشر می‌کنند.\nاین کار به داشتن حس مالکیت جمعی کمک می‌کند و ویرایش‌های طولانی مدت را اشاعه می‌دهد.\nاین برای ویکی‌های خصوصی یا سازمانی الزامی نیست.\n\nاگر شما می‌خواهید از متون ویکی‌پدیا استفاده کنید، یا اینکه به ویکی‌پدیا اجازه دهید از متون شما استفاده کند باید متون خود را با <strong>{{int:config-license-cc-by-sa}}</strong> منتشر کنید.\n\nویکی‌پدیا در گذشته از اجازه‌نامهٔ داده‌های آزاد گنو استفاده می‌کرد.\nاین اجازه‌نامه مورد قبول است، ولی فهم آن آسان نیست.\nهمچنین استفادهٔ دوباره از متون تحت اجازه‌نامهٔ داده‌های آزاد گنو به سختی انجام می‌گیرد.",
        "config-email-settings": "تنظیمات ایمیل",
        "config-enable-email": "فعال‌سازی ایمیل خروجی",
-       "config-enable-email-help": "اگر می‌خواهید ارسال ایمیل کار کند، [https://secure.php.net/manual/en/mail.configuration.php PHP's mail settings] نیازمند پیکربندی صحیح است.\nاگر هیچ قابلیت ایمیلی نمی‌خواهید، می‌توانید آنها را اینجا غیر‌فعال کنید.",
+       "config-enable-email-help": "اگر می‌خواهید ارسال ایمیل کار کند، [https://www.php.net/manual/en/mail.configuration.php PHP's mail settings] نیازمند پیکربندی صحیح است.\nاگر هیچ قابلیت ایمیلی نمی‌خواهید، می‌توانید آنها را اینجا غیر‌فعال کنید.",
        "config-email-user": "فعال کردن ایمیل کاربر به کاربر",
        "config-email-user-help": "به همهٔ کاربرانی که ارسال ایمیل را در ترجیحات خود فعال کرده‌اند، اجازه داده خواهد شد که به یکدیگر ایمیل ارسال کنند.",
        "config-email-usertalk": "فعال کردن اطلاع‌رسانی صفحهٔ بحث کاربر",
        "config-install-mainpage-failed": "قادر به درج صفحهٔ اصلی نمی‌باشد:$1",
        "config-install-done": "'''تبریک!'''\nبا موفقیت مدیاویکی را نصب کردید.\nبرنامه نصب‌کننده پرونده <code>LocalSettings.php</code> را درست کرد.\nکه شامل تمام تنظیمات می‌باشد.\n\nشما نیاز به دریافت آن دارید و آن را در پایهٔ نصب ویکی قرار دهید (همان پوشهٔ index.php). دریافت باید به صورت خودکار شروع شده‌باشد.\n\nاگر دریافت شروع نشد یا اگر آن را لغو کردید با کلیک روی پیوند زیر می‌توانید آن را دریافت کنید:\n\n$3\n\n'''توجه داشته باشید:''' اگر این را الآن انجام ندهید، این پرونده تولیدشده در صورتی که نصب را بدون دریافت آن تمام کردید بعداً در اختیار شما قرار نخواهد گرفت.\n\nوقتی انجام شد شما می‌توانید '''[$2 وارد ویکی شوید]'''.",
        "config-install-done-path": "<strong>تبریک!</strong>\nمدیاویکی با موفقیت نصب گردید.\nبرنامه نصب‌کننده یک پرونده <code>LocalSettings.php</code> ایجاد کرده است که شامل تمام تنظیمات می‌باشد.\n\nلازم است شما آن را دریافت کرده و در <code>$4</code> قرار دهید. اِن دریافت می باِست به صورت خودکار شروع شده‌باشد.\n\nاگر دریافت شروع نشده بود و یا آن را لغو کرده اید با کلیک روی پیوند زیر می‌توانید آن را دریافت کنید:\n\n$3\n\n<strong>توجه:</strong> اگر این کار را هم اکنون انجام ندهید و بدون دریافت آن از برنامه نصب خارج شويد، این پرونده تنظیمات تولیدشده در آینده در اختیار شما قرار نخواهد داشت.\n\nوقتی که آن کار را انجام داديد، می‌توانید <strong>[$2 وارد ويکی خودتان شويد]</strong>.",
-       "config-install-success": "مدیاویکی به صورت موفقیت‌آمیز نصب شد. شما می‌توانید\nاز <$1$2> برای دیدن ویکی‌تان بازدید کنید.\nاگر پرسشی داشتید، فهرست سوال‌های متداول ما را مطالعه کنید:\n<https://www.mediawiki.org/wiki/Manual:FAQ> یا از یکی از انجمن‌های پشیبانی ما که در آن صفحه فهرست شده‌اند استفاده کنید.",
+       "config-install-success": "نصب مدیاویکی موفق بود. شما می‌توانید برای دیدن ویکی‌تان از <$1$2> بازدید کنید.\nاگر پرسشی داشتید، فهرست پرسش‌های متداول ما را مطالعه کنید:\n<https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ> یا از یکی از انجمن‌های پشیبانی که در آن صفحه فهرست شده‌اند استفاده کنید.",
+       "config-install-db-success": "دادگان با موفقیت نصب شد",
        "config-download-localsettings": "دریافت <code>LocalSettings.php</code>",
        "config-help": "راهنما",
        "config-help-tooltip": "برای گسترش کلیک کنید",
        "config-nofile": "پروندهٔ «$1» یافت نشد. آیا حذف شده‌است؟",
-       "config-extension-link": "آیا می‌دانستید که ویکی شما [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions extensions] را پشتیبانی می‌کند؟\nشما می‌توانید [https://www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category extensions by category]",
+       "config-extension-link": "آیا می‌دانستید که ویکی شما از [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions extensions] پشتیبانی می‌کند؟\nمی‌توانید [https://www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category extensions by category] را مرور کنید.",
        "config-skins-screenshots": "$1 (تصاویر: $2)",
        "config-extensions-requires": "$1 (نیازمند $2)",
        "config-screenshot": "تصویر",
+       "config-extension-not-found": "پرونده ثبت افزونه «$1» پیدا نشد.",
+       "config-extension-dependency": "خطای وابسته در حین نصب افزونه «$1» رخ داد: $2",
        "mainpagetext": "'''مدیاویکی با موفقیت نصب شد.'''",
        "mainpagedocfooter": "از [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents راهنمای کاربری]\nبرای اطلاعات بیشتر در مورد به‌کارگیری نرم‌افزار ویکی استفاده کنید.\n\n== آغاز به کار ==\n\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings فهرست تنظیمات پیکربندی]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ پرسش‌های متداول مدیاویکی]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce فهرست ایمیلی نسخه‌های مدیاویکی]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources محلی‌سازی مدیاویکی به زبان شما]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam یادگیری روش‌های مقابله با هرزنگاری در ویکی]"
 }
index a134db8..fbc80f8 100644 (file)
        "config-outdated-sqlite": "<strong>Varoitus:</strong> sinulla on käytössä SQLite $1, joke on vanhempi kuin vähintään vaadittava versio $2. SQLite ei ole saatavilla.",
        "config-no-fts3": "<strong>Varoitus:</strong> SQLite on koostettu ilman [//sqlite.org/fts3.html FTS3-moduulia], hakuominaisuudet eivät ole käytössä tässä taustajärjestelmässä.",
        "config-pcre-old": "<strong>Tärkeää:</strong> PCRE $1 tai uudempi versio tarvitaan.\nPHP-binäärisi on linkitetty versiolla PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Lisätietoja].",
+       "config-pcre-no-utf8": "<strong>Vakava virhe:</strong> PHP:n PCRE-moduuli näyttää olevan koottu ilman PCRE_UTF8 tukea.\nMediaWiki edellyttää UTF-8 tukea toimiakseen oikein.",
        "config-memory-raised": "PHP:n <code>memory_limit</code> on $1, nostetaan arvoon $2.",
        "config-memory-bad": "'''Varoitus:''' PHP:n <code>memory_limit</code> on $1.\nTämä on luultavasti liian alhainen.\nAsennus saattaa epäonnistua!",
-       "config-apc": "[https://secure.php.net/apc APC] on asennettu",
-       "config-apcu": "[https://secure.php.net/apcu APCu] on asennettu",
+       "config-apc": "[https://www.php.net/apc APC] on asennettu",
+       "config-apcu": "[https://www.php.net/apcu APCu] on asennettu",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] on asennettu",
        "config-diff3-bad": "GNU diff3:a ei löytynyt.",
        "config-git": "Löydetty Git-versionhallintaohjelmisto: <code>$1</code>",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki tukee seuraavia tietokantajärjestelmiä:\n\n$1\n\nJos et näe tietokantajärjestelmää, jota yrität käyttää, listattuna alhaalla, seuraa yläpuolella olevia ohjeita tuen aktivoimiseksi.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] on MediaWikin ensisijainen kohde ja se on myös parhaiten tuettu. MediaWiki voi myös käyttää [{{int:version-db-mysql-url}} MySQL]- sekä [{{int:version-db-percona-url}} Percona Server]-järjestelmiä, jotka ovat MariaDB-yhteensopivia. ([https://secure.php.net/manual/en/mysqli.installation.php Miten käännetään PHP MySQL-tuella])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] on suosittu avoimen lähdekoodin tietokantajärjestelmä vaihtoehtona MySQL:lle. ([https://secure.php.net/manual/en/pgsql.installation.php Kuinka käännetään PHP PostgreSQL-tuella])",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] on kevyt tietokantajärjestelmä, jota tuetaan hyvin. ([https://secure.php.net/manual/en/pdo.installation.php Miten käännetään PHP SQLite-tuella], käyttää PDO:ta)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] on kaupallinen yritystietokanta. ([https://secure.php.net/manual/en/oci8.installation.php Kuinka käännetään PHP OCI8-tuella])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] on kaupallinen yritystietokanta Windowsille. ([https://secure.php.net/manual/en/sqlsrv.installation.php Miten käännetään PHP SQLSRV-tuella])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] on MediaWikin ensisijainen kohde ja se on myös parhaiten tuettu. MediaWiki voi myös käyttää [{{int:version-db-mysql-url}} MySQL]- sekä [{{int:version-db-percona-url}} Percona Server]-järjestelmiä, jotka ovat MariaDB-yhteensopivia. ([https://www.php.net/manual/en/mysqli.installation.php Miten käännetään PHP MySQL-tuella])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] on suosittu avoimen lähdekoodin tietokantajärjestelmä vaihtoehtona MySQL:lle. ([https://www.php.net/manual/en/pgsql.installation.php Kuinka käännetään PHP PostgreSQL-tuella])",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] on kevyt tietokantajärjestelmä, jota tuetaan hyvin. ([https://www.php.net/manual/en/pdo.installation.php Miten käännetään PHP SQLite-tuella], käyttää PDO:ta)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] on kaupallinen yritystietokanta. ([https://www.php.net/manual/en/oci8.installation.php Kuinka käännetään PHP OCI8-tuella])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] on kaupallinen yritystietokanta Windowsille. ([https://www.php.net/manual/en/sqlsrv.installation.php Miten käännetään PHP SQLSRV-tuella])",
        "config-header-mysql": "MariaDB/MySQL-asetukset",
        "config-header-postgres": "PostgreSQL-asetukset",
        "config-header-sqlite": "SQLite-asetukset",
        "config-license-help": "Monet julkiset wikit käyttävät muokkauksiin [https://freedomdefined.org/Definition vapaata lisenssiä].\nTämä auttaa luomaan yhteisöllisen omistajuuden tunteen ja kannustaa pitkäkestoiseen muokkaamiseen.\nSe ei ole yleensä tarpeen yksityiselle tai yrityksen wikille.\n\nJos haluat pystyä käyttämään tekstiä Wikipediasta, ja haluat Wikipedian pystyvän hyväksymään wikistäsi kopioitua tekstiä, sinun tulisi valita <strong>{{int:config-license-cc-by-sa}}</strong>.\n\nWikipedia käytti aiemmin GNU Free Documentation Licenseä.\nGFDL on kelvollinen lisenssi, mutta vaikea ymmärtää.\nOn myös vaikeaa käyttää uudelleen GFDL-lisensöityä sisältöä.",
        "config-email-settings": "Sähköpostiasetukset",
        "config-enable-email": "Ota käyttöön sähköpostien lähetys",
-       "config-enable-email-help": "Jotta sähköposti toimii, [https://secure.php.net/manual/en/mail.configuration.php PHP:n sähköpostiasetukset] täytyy asettaa oikein.\nJos et halua käyttää sähköpostiominaisuuksia, ne voi kytkeä pois päältä tästä.",
+       "config-enable-email-help": "Jotta sähköposti toimii, [https://www.php.net/manual/en/mail.configuration.php PHP:n sähköpostiasetukset] täytyy asettaa oikein.\nJos et halua käyttää sähköpostiominaisuuksia, ne voi kytkeä pois päältä tästä.",
        "config-email-user": "Ota käyttöön käyttäjältä käyttäjälle sähköpostit",
        "config-email-user-help": "Salli käyttäjien lähettää sähköpostia toisilleen jos he ovat ottaneet käyttöön toiminnon asetuksissaan.",
        "config-email-usertalk": "Ota käyttöön käyttäjien keskustelusivusta ilmoittaminen",
        "config-install-done": "<strong>Onnittelut!</strong>\nOlet asentanut MediaWikin.\n\nAsennusohjelma on luonut <code>LocalSettings.php</code> -tiedoston.\nSiinä on kaikki MediaWikin asetukset.\n\nLataa tiedosto ja laita se MediaWikin asennushakemistoon (sama kuin missä on index.php). Lataamisen olisi pitänyt alkaa automaattisesti.\n\nMikäli latausta ei tarjottu tai keskeytit latauksen, käynnistä se uudestaan tästä linkistä:\n\n$3\n\n<strong>Huom:</strong> Mikäli et nyt lataa tiedostoa, luotu tiedosto ei ole saatavissa myöhemmin, jos poistut asennuksesta lataamatta sitä.\n\nKun olet laittanut tiedoston oikeaan paikkaan, voit <strong>[$2 mennä wikiisi]</strong>.",
        "config-install-done-path": "<strong>Onnittelut!</strong>\nOlet asentanut MediaWikin.\n\nAsennusohjelma on luonut <code>LocalSettings.php</code> -tiedoston.\nSiinä on kaikki MediaWikin asetukset.\n\nLataa tiedosto ja laita se sijaintiin <code>$4</code>. Lataamisen olisi pitänyt alkaa automaattisesti.\n\nMikäli latausta ei tarjottu tai keskeytit latauksen, käynnistä se uudestaan tästä linkistä:\n\n$3\n\n<strong>Huom:</strong> Mikäli et nyt lataa tiedostoa, luotu tiedosto ei ole saatavissa myöhemmin, jos poistut asennuksesta lataamatta sitä.\n\nKun olet laittanut tiedoston oikeaan paikkaan, voit <strong>[$2 mennä wikiisi]</strong>.",
        "config-install-success": "MediaWiki on asennettu onnistuneesti. Voit nyt vierailla <$1$2> katsellaksesi wikiäsi. Jos sinulla on kysyttävää, tutustu usein kysyttyjen kysymysten luetteloon: <https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ> tai käytä jotakin sivulla linkitettyä tukifoorumia.",
+       "config-install-db-success": "Tietokanta asennettiin onnistuneesti",
        "config-download-localsettings": "Lataa <code>LocalSettings.php</code>",
        "config-help": "ohje",
        "config-help-tooltip": "Klikkaa laajentaaksesi",
index 79a1ebb..07b61cc 100644 (file)
        "config-pcre-no-utf8": "<strong>Erreur fatale :</strong> le module PCRE de PHP semble être compilé sans la prise en charge de PCRE_UTF8.\nMediaWiki a besoin de la gestion d’UTF-8 pour fonctionner correctement.",
        "config-memory-raised": "Le paramètre <code>memory_limit</code> de PHP était à $1, porté à $2.",
        "config-memory-bad": "<strong>Attention :</strong> Le paramètre <code>memory_limit</code> de PHP est à $1.\nCette valeur est probablement trop faible.\nIl est possible que l’installation échoue !",
-       "config-apc": "[https://secure.php.net/apc APC] est installé",
-       "config-apcu": "[https://secure.php.net/apcu APCu] est installé",
+       "config-apc": "[https://www.php.net/apc APC] est installé",
+       "config-apcu": "[https://www.php.net/apcu APCu] est installé",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] est installé",
-       "config-no-cache-apcu": "<strong>Attention :</strong> impossible de trouver [https://secure.php.net/apcu APCu] ou [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nLa mise en cache d’objets n’est pas activée.",
-       "config-mod-security": "<strong>Attention :</strong> votre serveur web a [https://modsecurity.org/ mod_security] activé. S’il est mal configuré, cela peut poser des problèmes à MediaWiki ou à d’autres applications qui permettent aux utilisateurs de publier un contenu quelconque. Si possible, ceci devrait être désactivé. Sinon, reportez-vous à [https://modsecurity.org/documentation/ la documentation de mod_security] ou contactez l’assistance de votre hébergeur si vous rencontrez des erreurs aléatoires.",
+       "config-no-cache-apcu": "<strong>Attention :</strong> impossible de trouver [https://www.php.net/apcu APCu] ou [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nLa mise en cache des objets n’est pas activée.",
+       "config-mod-security": "<strong>Attention :</strong> votre serveur web a activé [https://modsecurity.org/ mod_security]/mod_security2 . Dans plusieurs configurations communes cela pose des problèmes à MediaWiki ou à d’autres applications qui permettent aux utilisateurs de publier un contenu quelconque. \nSi possible, ceci devrait être désactivé. Sinon, reportez-vous à [https://modsecurity.org/documentation/ la documentation de mod_security] ou contactez l’assistance de votre hébergeur si vous rencontrez des erreurs aléatoires.",
        "config-diff3-bad": "L’utilitaire de comparaison de texte GNU diff3 est introuvable. Vous pouvez l’ignorer pour le moment, mais cela peut provoquer des conflits de modification plus souvent.",
        "config-git": "Logiciel de contrôle de version Git trouvé : <code>$1</code>.",
        "config-git-bad": "Logiciel de contrôle de version Git non trouvé. Vous pouvez l’ignorer pour le moment. Notez que Special:Version n’affichera pas les hachages de validation.",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki prend en charge ces systèmes de bases de données :\n\n$1\n\nSi vous ne voyez pas le système de base de données que vous essayez d’utiliser ci-dessous, alors suivez les instructions ci-dessus (voir liens) pour activer la prise en charge.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] est le premier choix pour MediaWiki et est le mieux pris en charge. MediaWiki fonctionne aussi avec [{{int:version-db-mysql-url}} MySQL] et [{{int:version-db-percona-url}} Percona Server], qui sont compatibles avec MariaDB. ([https://secure.php.net/manual/en/mysqli.installation.php Comment compiler PHP avec la prise en charge de MySQL])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] est un système de base de données populaire en ''source ouverte'' qui peut être une alternative à MySQL ([https://secure.php.net/manual/en/pgsql.installation.php Comment compiler PHP avec la prise en charge de PostgreSQL]).",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] est un système de base de données léger bien pris en charge ([https://secure.php.net/manual/en/pdo.installation.php Comment compiler PHP avec la prise en charge de SQLite], en utilisant PDO).",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] est un système commercial de gestion de base de données d’entreprise. ([https://secure.php.net/manual/en/oci8.installation.php Comment compiler PHP avec la prise en charge d’OCI8])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] est une base de données commerciale d’entreprise pour Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php Comment compiler PHP avec la prise en charge de SQLSRV])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] est le premier choix pour MediaWiki et est le mieux pris en charge. MediaWiki fonctionne aussi avec [{{int:version-db-mysql-url}} MySQL] et [{{int:version-db-percona-url}} Percona Server], qui sont compatibles avec MariaDB. ([https://www.php.net/manual/en/mysqli.installation.php Comment compiler PHP avec la prise en charge de MySQL])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] est un système de base de données populaire en ''source ouverte'' qui peut être une alternative à MySQL ([https://www.php.net/manual/en/pgsql.installation.php Comment compiler PHP avec la prise en charge de PostgreSQL]).",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] est un système de base de données léger bien pris en charge ([https://www.php.net/manual/en/pdo.installation.php Comment compiler PHP avec la prise en charge de SQLite], en utilisant PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] est un système commercial de gestion de base de données d’entreprise. ([https://www.php.net/manual/en/oci8.installation.php Comment compiler PHP avec la prise en charge d’OCI8])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] est une base de données commerciale d’entreprise pour Windows. ([https://www.php.net/manual/en/sqlsrv.installation.php Comment compiler PHP avec la prise en charge de SQLSRV])",
        "config-header-mysql": "Paramètres de MariaDB/MySQL",
        "config-header-postgres": "Paramètres de PostgreSQL",
        "config-header-sqlite": "Paramètres de SQLite",
        "config-license-help": "Beaucoup de wikis publics mettent l’ensemble des contributions sous une [https://freedomdefined.org/Definition/Fr licence libre].\nCela contribue à créer un sentiment d’appartenance à une communauté et encourage les contributions sur le long terme.\nCe n’est généralement pas nécessaire pour un wiki privé ou d’entreprise.\n\nSi vous souhaitez utiliser des textes de Wikipédia, et souhaitez que Wikipédia puisse réutiliser des textes copiés depuis votre wiki, vous devriez choisir <strong>{{int:config-license-cc-by-sa}}</strong>.\n\nWikipédia utilisait auparavant la Licence de Documentation Libre GNU (GFDL).\nC’est une licence valide, mais difficile à comprendre. \nIl est aussi difficile de réutiliser du contenu sous la licence GFDL.",
        "config-email-settings": "Paramètres de courriel",
        "config-enable-email": "Activer les courriels sortants",
-       "config-enable-email-help": "Si vous souhaitez utiliser le courriel, vous devez avoir les [https://secure.php.net/manual/en/mail.configuration.php paramètres courriel de PHP] configurés correctement (texte en anglais).\nSi vous ne voulez pas du service de courriel, vous pouvez le désactiver ici.",
+       "config-enable-email-help": "Si vous souhaitez utiliser le courriel, vous devez avoir configuré correctement les [https://www.php.net/manual/en/mail.configuration.php paramètres courriel de PHP] (texte en anglais).\nSi vous ne voulez pas du service de courriel, vous pouvez le désactiver ici.",
        "config-email-user": "Activer les courriers électroniques d'utilisateur à utilisateur",
        "config-email-user-help": "Permet à tous les utilisateurs d'envoyer des courriels à d'autres utilisateurs si cela est activé dans leurs préférences.",
        "config-email-usertalk": "Activer la notification des pages de discussion des utilisateurs",
        "config-install-done": "<strong>Félicitations!</strong>\nVous avez installé MediaWiki.\n\nLe programme d'installation a généré un fichier <code>LocalSettings.php</code>. Il contient tous les paramètres de votre configuration.\n\nVous devrez le télécharger et le mettre à la racine de votre installation wiki (dans le même répertoire que index.php). Le téléchargement devrait démarrer automatiquement.\n\nSi le téléchargement n'a pas été proposé, ou que vous l'avez annulé, vous pouvez redémarrer le téléchargement en cliquant ce lien :\n\n$3\n\n<strong>Note :</strong> Si vous ne le faites pas maintenant, ce fichier de configuration généré ne sera pas disponible plus tard si vous quittez l'installation sans le télécharger.\n\nLorsque c'est fait, vous pouvez <strong>[$2 accéder à votre wiki]</strong> .",
        "config-install-done-path": "<strong>Félicitations !</strong>\nVous avez installé MédiaWiki.\n\nL’installeur a généré un fichier <code>LocalSettings.php</code>.\nIl contient toute votre configuration.\n\nVous devez le télécharger et le mettre dans <code>$4</code>. Le téléchargement devrait avoir démarré automatiquement.\n\nSi le téléchargement n’a pas été proposé ou si vous l’avez annulé, vous pouvez le redémarrer en cliquant sur le lien ci-dessous :\n\n$3\n\n<strong>Note :</strong> Si vous ne le faites pas maintenant, ce fichier de configuration généré ne sera plus disponible ultérieurement si vous quittez l’installation sans le télécharger.\n\nUne fois ceci fait, vous pouvez <strong>[$2 entrer dans votre wiki]</strong>.",
        "config-install-success": "MédiaWiki a été installé correctement. Vous pouvez maintenant visiter <$1$2> pour voir votre wiki.\nSi vous avez des questions, consultez notre foire aux questions :\n<https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ> ou utilisez un des\nforums de support liés sur cette page.",
+       "config-install-db-success": "La base de données a été bien installée",
        "config-download-localsettings": "Télécharger <code>LocalSettings.php</code>",
        "config-help": "aide",
        "config-help-tooltip": "cliquer pour agrandir",
index fa84d5f..033692a 100644 (file)
@@ -30,7 +30,7 @@
        "config-page-existingwiki": "Vouiqui ègzistent",
        "config-env-php": "PHP $1 est enstalâ.",
        "config-memory-raised": "Lo paramètre <code>memory_limit</code> de PHP ére a $1, portâ a $2.",
-       "config-apc": "[https://secure.php.net/apc APC] est enstalâ",
+       "config-apc": "[https://www.php.net/apc APC] est enstalâ",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] est enstalâ",
        "config-diff3-bad": "GNU diff3 entrovâblo.",
        "config-db-type": "Tipo de bâsa de balyês :",
index c5d34f3..86c0c57 100644 (file)
        "config-pcre-no-utf8": "<strong>Erro fatal:</strong> Semella que o módulo PCRE do PHP foi compilado sen o soporte PCRE_UTF8.\nMediaWiki necesita soporte UTF-8 para funcionar correctamente.",
        "config-memory-raised": "O parámetro <code>memory_limit</code> do PHP é $1. Aumentado a $2.",
        "config-memory-bad": "<strong>Atención:<strong> O parámetro <code>memory_limit</code> do PHP é $1.\nProbablemente é un valor baixo de máis.\nA instalación pode fallar!",
-       "config-apc": "[https://secure.php.net/apc APC] está instalado",
-       "config-apcu": "[https://secure.php.net/apcu APCu] está instalado",
+       "config-apc": "[https://www.php.net/apc APC] está instalado",
+       "config-apcu": "[https://www.php.net/apcu APCu] está instalado",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] está instalado",
-       "config-no-cache-apcu": "<strong>Advertencia:</strong> Non se puido atopar [https://secure.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] ou [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nA caché de obxectos non está activada.",
+       "config-no-cache-apcu": "<strong>Advertencia:</strong> Non se puido atopar [https://www.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] ou [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nA caché de obxectos non está activada.",
        "config-mod-security": "<strong>Atención:</strong> O seu servidor web ten o [https://modsecurity.org/ mod_security] activado. Se estivese mal configurado, pode causar problemas a MediaWiki ou calquera outro software que permita aos usuarios publicar contidos arbitrarios.\nOlle a [https://modsecurity.org/documentation/ documentación do mod_security] ou póñase en contacto co soporte do seu servidor se atopa erros aleatorios.",
        "config-diff3-bad": "GNU diff3 non se atopou.",
        "config-git": "Atopouse o software de control da versión de Git: <code>$1</code>.",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki soporta os seguintes sistemas de bases de datos:\n\n$1\n\nSe non ve listado a continuación o sistema de base de datos que intenta usar, siga as instrucións ligadas enriba para activar o soporte.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] é o obxectivo principal para MediaWiki e é o que mellor soportado está. MediaWiki tamén funciona con [{{int:version-db-mysql-url}} MySQL] e [{{int:version-db-percona-url}} Percona Server], que son compatibles con MariaDB. ([https://secure.php.net/manual/en/mysqli.installation.php Como compilar PHP con compatibilidade MySQL])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] é un sistema de base de datos popular e de código aberto como alternativa a MySQL. ([https://secure.php.net/manual/en/pgsql.installation.php Como compilar PHP con compatibilidade PostgreSQL])",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] é un sistema de base de datos lixeiro moi ben soportado. ([https://secure.php.net/manual/en/pdo.installation.php Como compilar o PHP con soporte SQLite], emprega PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] é un sistema comercial de xestión de base de datos a nivel empresarial. ([https://secure.php.net/manual/en/oci8.installation.php Como compilar PHP con soporte OCI8])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] é un sistema comercial de xestión de base de datos de nivel empresarial para Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php Como compilar o PHP con compatibilidade SQLSRV])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] é o obxectivo principal para MediaWiki e é o que mellor soportado está. MediaWiki tamén funciona con [{{int:version-db-mysql-url}} MySQL] e [{{int:version-db-percona-url}} Percona Server], que son compatibles con MariaDB. ([https://www.php.net/manual/en/mysqli.installation.php Como compilar PHP con compatibilidade MySQL])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] é un sistema de base de datos popular e de código aberto como alternativa a MySQL. ([https://www.php.net/manual/en/pgsql.installation.php Como compilar PHP con compatibilidade PostgreSQL])",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] é un sistema de base de datos lixeiro moi ben soportado. ([https://www.php.net/manual/en/pdo.installation.php Como compilar o PHP con soporte SQLite], emprega PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] é un sistema comercial de xestión de base de datos a nivel empresarial. ([https://www.php.net/manual/en/oci8.installation.php Como compilar PHP con soporte OCI8])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] é un sistema comercial de xestión de base de datos de nivel empresarial para Windows. ([https://www.php.net/manual/en/sqlsrv.installation.php Como compilar o PHP con compatibilidade SQLSRV])",
        "config-header-mysql": "Configuración MariaDB/MySQL",
        "config-header-postgres": "Configuración do PostgreSQL",
        "config-header-sqlite": "Configuración do SQLite",
        "config-license-help": "Moitos wikis públicos liberan todas as súas contribucións baixo unha [https://freedomdefined.org/Definition/Gl licenza libre].\nIsto axuda a crear un sentido de propiedade comunitaria e anima a seguir contribuíndo durante moito tempo.\nXeralmente, non é necesario nos wikis privados ou de empresas.\n\nSe quere poder empregar textos da Wikipedia, así como que a Wikipedia poida aceptar textos copiados do seu wiki, escolla a licenza <strong>{{int:config-license-cc-by-sa}}</strong>.\n\nA licenza de documentación libre de GNU era a licenza anterior da Wikipedia.\nMalia aínda ser unha licenza válida, é difícil de entender.\nTamén é difícil reusar contidos baixo esta licenza.",
        "config-email-settings": "Configuración do correo electrónico",
        "config-enable-email": "Activar os correos electrónicos de saída",
-       "config-enable-email-help": "Se quere que o correo electrónico funcione, cómpre configurar os [https://secure.php.net/manual/en/mail.configuration.php parámetros PHP de correo] correctamente.\nSe non quere ningunha característica de correo electrónico, pode desactivalas aquí.",
+       "config-enable-email-help": "Se quere que o correo electrónico funcione, cómpre configurar os [https://www.php.net/manual/en/mail.configuration.php parámetros PHP de correo] correctamente.\nSe non quere ningunha característica de correo electrónico, pode desactivalas aquí.",
        "config-email-user": "Activar o intercambio de correos electrónicos entre usuarios",
        "config-email-user-help": "Permitir que todos os usuarios intercambien correos electrónicos, se o teñen activado nas súas preferencias.",
        "config-email-usertalk": "Activar a notificación da páxina de conversa de usuario",
index 48dfbe3..337a179 100644 (file)
@@ -49,7 +49,7 @@
        "config-pcre-no-utf8": "'''Fatale Fähler: S PHP-Modul PCRE isch schyns ohni PCRE_UTF8-Unterstitzig kompiliert wore.'''\nMediaWiki brucht d UTF-8-Unterstitzi zum fählerfrej lauffähig syy.",
        "config-memory-raised": "Dr PHP-Parameter <code>memory_limit</code> lyt bi $1 un isch uf $2 uffegsetzt wore.",
        "config-memory-bad": "'''Warnig:''' Dr PHP-Parameter <code>memory_limit</code> lyt bi $1.\nDää Wärt isch wahrschyns z nider.\nDr Inschtallationsvorgang chennt wäge däm fählschlaa!",
-       "config-apc": "[https://secure.php.net/apc APC] isch inschtalliert",
+       "config-apc": "[https://www.php.net/apc APC] isch inschtalliert",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] isch inschtalliert",
        "config-diff3-bad": "GNU diff3 isch nit gfunde wore.",
        "config-imagemagick": "ImageMagick isch gfunde wore: <code>$1</code>.\nMiniaturaasichte vu Bilder sin megli, sobald s Uffelade vu Dateie aktiviert isch.",
index 756c87c..08e56e0 100644 (file)
        "config-pcre-no-utf8": "<strong>שגיאה סופנית</strong>: נראה שמודול PCRE של PHP מהודר ללא תמיכה ב־PCRE_UTF8.\nמדיה־ויקי דורשת תמיכה ב־UTF-8 לפעילות נכונה.",
        "config-memory-raised": "ערך האפשרות <code>memory_limit</code> של PHP הוא $1, הועלה ל־$2.",
        "config-memory-bad": "'''אזהרה:''' ערך האפשרות <code>memory_limit</code> של PHP הוא $1.\nזה כנראה נמוך מדי.\nההתקנה עשויה להיכשל!",
-       "config-apc": "[https://secure.php.net/apc APC] מותקן",
-       "config-apcu": "[https://secure.php.net/apcu APCu] מותקן",
+       "config-apc": "[https://www.php.net/apc APC] מותקן",
+       "config-apcu": "[https://www.php.net/apcu APCu] מותקן",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] מותקן",
-       "config-no-cache-apcu": "<strong>אזהרה:</strong> לא נמצא [https://secure.php.net/apcu APCu]‏ או [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nמטמון עצמים לא מופעל.",
+       "config-no-cache-apcu": "<strong>אזהרה:</strong> לא נמצא [https://www.php.net/apcu APCu]‏ או [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nמטמון עצמים לא מופעל.",
        "config-mod-security": "'''אזהרה''': בשרת הווב שלך מופעל [https://modsecurity.org/ mod_security]. אם הוא לא מוגדר טוב, זה יכול לגרום לבעיות במדיה־ויקי ובתכנה אחרת שמאפשרת למשתמשים לשלוח תוכן שרירותי.\nיש לקרוא את [https://modsecurity.org/documentation/ התיעוד של mod_security] או ליצור קשר עם אנשי התמיכה של שירותי האירוח שלכם אם מופיעות לך שגיאות אקראיות.",
        "config-diff3-bad": "GNU diff3 לא נמצא.",
        "config-git": "נמצאה Git, תכנת בקרת התצורה: <code dir=\"ltr\">$1</code>.",
        "config-type-mysql": "MariaDB‏, MySQL, או תואם",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "מדיה־ויקי תומכת במערכות מסדי הנתונים הבאות:\n\n$1\n\nאם אינך רואה את מסד הנתונים שלך ברשימה, יש לעקוב אחר ההוראות המקושרות לעיל כדי להפעיל את התמיכה.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] הוא היעד העיקרי עבור מדיה־ויקי ולו התמיכה הטובה ביותר. מדיה־ויקי עובדת גם עם [{{int:version-db-mysql-url}} MySQL] ועם [{{int:version-db-percona-url}} Percona Server], שתואמים ל־MariaDB. (ר׳ [https://secure.php.net/manual/en/mysql.installation.php how to compile PHP with MySQL support])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] הוא מסד נתונים נפוץ בקוד פתוח והוא נפוץ בתור חלופה ל־MySQL. (ר׳ [https://secure.php.net/manual/en/pgsql.installation.php how to compile PHP with PostgreSQL support]).",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] הוא מסד נתונים קליל עם תמיכה טובה מאוד. (ר׳ [https://secure.php.net/manual/en/pdo.installation.php How to compile PHP with SQLite support], משתמש ב־PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] הוא מסד נתונים עסקי מסחרי. (ר׳ [https://secure.php.net/manual/en/oci8.installation.php How to compile PHP with OCI8 support])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] הוא מסד נתונים עסקי מסחרי לחלונות. ([https://secure.php.net/manual/en/sqlsrv.installation.php How to compile PHP with SQLSRV support])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] הוא היעד העיקרי עבור מדיה־ויקי ולו התמיכה הטובה ביותר. מדיה־ויקי עובדת גם עם [{{int:version-db-mysql-url}} MySQL] ועם [{{int:version-db-percona-url}} Percona Server], שתואמים ל־MariaDB. (ר׳ [https://www.php.net/manual/en/mysql.installation.php how to compile PHP with MySQL support])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] הוא מסד נתונים נפוץ בקוד פתוח והוא נפוץ בתור חלופה ל־MySQL. (ר׳ [https://www.php.net/manual/en/pgsql.installation.php how to compile PHP with PostgreSQL support]).",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] הוא מסד נתונים קליל עם תמיכה טובה מאוד. (ר׳ [https://www.php.net/manual/en/pdo.installation.php How to compile PHP with SQLite support], משתמש ב־PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] הוא מסד נתונים עסקי מסחרי. (ר׳ [https://www.php.net/manual/en/oci8.installation.php How to compile PHP with OCI8 support])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] הוא מסד נתונים עסקי מסחרי לחלונות. ([https://www.php.net/manual/en/sqlsrv.installation.php How to compile PHP with SQLSRV support])",
        "config-header-mysql": "הגדרות MariaDB/MySQL",
        "config-header-postgres": "הגדרות PostgreSQL",
        "config-header-sqlite": "הגדרות SQLite",
        "config-license-help": "אתרי ויקי ציבוריים רבים מפרסמים את כל התרומות [https://freedomdefined.org/Definition ברישיון חופשי].\nזה עוזר ליצור תחושה של בעלות קהילתית ומעודד תרומה לאורך זמן.\nזה בדרך כלל לא נחוץ לאתר ויקי פרטי או אתר של חברה מסחרית.\n\nאם האפשרות להשתמש בטקסט מוויקיפדיה והאפשרות שוויקיפדיה תוכל תקבל עותקים של טקסטים מהוויקי שלך חשובות לך, כדאי לבחור ב<strong>{{int:config-license-cc-by-sa}}</strong>.\n\nויקיפדיה השתמשה בעבר ברישיון החופשי למסמכים של גנו (GNU FDL או GFDL).\nהוא עדיין רישיון תקין, אבל קשה להבנה.\nכמו־כן, קשה לעשות שימוש חוזר ביצירות שפורסמו לפי GFDL.",
        "config-email-settings": "הגדרות דוא״ל",
        "config-enable-email": "להפעיל דוא״ל יוצא",
-       "config-enable-email-help": "אם אתם רוצים שדוא״ל יעבוד, [https://secure.php.net/manual/en/mail.configuration.php אפשרויות הדוא״ל של PHP] צריכות להיות מוגדרות נכון.\nאם אינכם רוצים להפעיל שום אפשרויות דוא״ל, כבו אותן כאן ועכשיו.",
+       "config-enable-email-help": "אם אתם רוצים שדוא״ל יעבוד, [https://www.php.net/manual/en/mail.configuration.php אפשרויות הדוא״ל של PHP] צריכות להיות מוגדרות נכון.\nאם אינכם רוצים להפעיל שום אפשרויות דוא״ל, כבו אותן כאן ועכשיו.",
        "config-email-user": "להפעיל שליחת דוא״ל ממשתמש למשתמש",
        "config-email-user-help": "לאפשר לכל המשתמשים לשלוח אחד לשני דוא״ל אם הם הפעילו את זה בהעדפות שלהם.",
        "config-email-usertalk": "להפעיל הודעות על דף שיחת משתמש",
index ca3d1df..90b11a9 100644 (file)
@@ -47,8 +47,8 @@
        "config-env-php": "PHP $1 स्थापित किया गया है।",
        "config-env-hhvm": "एचएचवीएम $1 स्थापित किया गया है।",
        "config-memory-raised": "पीएचपी की <code>memory_limit</code> सीमा $1 है, जो $2 तक बढ़ गई है।",
-       "config-apc": "[https://secure.php.net/apc एपीसी] स्थापित है।",
-       "config-apcu": "[https://secure.php.net/apcu एपीसीयू] स्थापित है।",
+       "config-apc": "[https://www.php.net/apc एपीसी] स्थापित है।",
+       "config-apcu": "[https://www.php.net/apcu एपीसीयू] स्थापित है।",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension विनकैश] स्थापित है।",
        "config-using-32bit": "<विशेष>चेतावनी:</विशेष> आपका सिस्टम 32-बिट पूर्णांक के साथ चल रहा है यह [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:32-bit विवेचित नहीं है]।",
        "config-db-type": "डेटाबेस प्रकार:",
index b358c4d..75a76b1 100644 (file)
@@ -57,7 +57,7 @@
        "config-pcre-no-utf8": "'''Fataler Fehler:''' Das PHP-Modul PCRE scheint ohne PCRE_UTF8-Unterstützung kompiliert worre sin.\nMediaWiki benöticht die UTF-8-Unnerstützung, um fehlerfrei looffähich zu sin.",
        "config-memory-raised": "Der PHP-Parameter <code>memory_limit</code> betruch $1 und woard uff $2 erhöcht.",
        "config-memory-bad": "'''Warnung:''' Der PHP-Parameter <code>memory_limit</code> beträcht $1.\nDer Weart ist wahrscheinlich zu niedrich.\nDer Installationsvoargang könnt doher scheitre!",
-       "config-apc": "[https://secure.php.net/apc APC] ist installiert",
+       "config-apc": "[https://www.php.net/apc APC] ist installiert",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] ist installiert",
        "config-mod-security": "'''Warnung:''' Uff dem Webserver woard [https://modsecurity.org/ ModSecurity] aktiviert. Sofern falsch konfiguriert, kann das zu Probleme mit MediaWiki sowie annrer Software uff dem Server führe und es Benutzer ermöchliche beliebiche Inhalte im Wiki Renzustelle.\nFür weitre Informatione empfehle mir die [https://modsecurity.org/documentation/ Dokumentation zu ModSecurity] orrer den Kontakt zum Hoster, sofern Fehler ufftrete.",
        "config-diff3-bad": "GNU diff3 woard net gefund.",
        "config-type-mysql": "MySQL (orrer kompatible Datebanksysteme)",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki unnerstützt die follichenne Datebanksysteme:\n\n$1\n\nSoweit net das Datebanksystem oongezeicht weard, das verwennt werre soll, gebt das uwe en Link zu der Oonleitung mit Informatione, wie das aktiviert sin kann.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] ist das von MediaWiki primär unterstützte Datebanksystem. MediaWiki funktioniert ooch mit [{{int:version-db-mariadb-url}} MariaDB] und [{{int:version-db-percona-url}} Percona Server], die MySQL-kompatibel sind. ([https://secure.php.net/manual/en/mysqli.installation.php Oonleitung zur Kompilierung von PHP mit MySQL-Unnerstützung] [englisch Sproch])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] ist en beliebtes Open-Source-Datebanksystem und ein Alternativ zu MySQL. Es gibt awer enche klenre Implementierungsfehler, so dass von der Nutzung in ener Produktivumgebung abgerat weard. ([https://secure.php.net/manual/en/pgsql.installation.php Oonnleitung zur Kompilierung von PHP mit PostgreSQL-Unterstützung])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] ist das von MediaWiki primär unterstützte Datebanksystem. MediaWiki funktioniert ooch mit [{{int:version-db-mariadb-url}} MariaDB] und [{{int:version-db-percona-url}} Percona Server], die MySQL-kompatibel sind. ([https://www.php.net/manual/en/mysqli.installation.php Oonleitung zur Kompilierung von PHP mit MySQL-Unnerstützung] [englisch Sproch])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] ist en beliebtes Open-Source-Datebanksystem und ein Alternativ zu MySQL. Es gibt awer enche klenre Implementierungsfehler, so dass von der Nutzung in ener Produktivumgebung abgerat weard. ([https://www.php.net/manual/en/pgsql.installation.php Oonnleitung zur Kompilierung von PHP mit PostgreSQL-Unterstützung])",
        "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] ist en verschlanktes Datebanksystem, das ooch gut unnerstützt weard ([http://www.php.net/manual/de/pdo.installation.php Oonleitung zur Kompilierung von PHP mit SQLite-Unterstützung], verwennt PHP Data Objects (PDO))",
        "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] ist en kommerzielle Unnernehmensdatebank ([http://www.php.net/manual/en/oci8.installation.php Oonleitung zur Kompilierung von PHP mit OCI8-Unnerstützung (en)])",
        "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] ist en gewerbliche Unnernehmensdatebank für Windows. ([Config-dbsupport-oracle/manual/de/sqlsrv.installation.php Oonleitung zur Kompilierung von PHP mithilfe SQLSRV-Unnerstützung])",
index 10c6159..f2b2a7f 100644 (file)
@@ -53,7 +53,7 @@
        "config-pcre-no-utf8": "'''Ćežki zmylk''': Zda so, zo PCRE-modul za PHP ma so bjez PCRE_UTF8-podpěry kompilować.\nMediaWiki trjeba UTF-8-podpěru, zo by korektnje fungował.",
        "config-memory-raised": "PHP-parameter <code>memory_limit</code> je $1, je so na hódnotu $2 zwyšił.",
        "config-memory-bad": "'''Warnowanje:''' PHP-parameter <code>memory_limit</code> ma hódnotu $1,\nTo je najskerje přeniske.\nInstalacija móhła so njeporadźić!",
-       "config-apc": "[https://secure.php.net/apc APC] je instalowany",
+       "config-apc": "[https://www.php.net/apc APC] je instalowany",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] je instalowany",
        "config-diff3-bad": "GNU diff3 njenamakany.",
        "config-no-uri": "'''Zmylk:''' Aktualny URI njeda so postajić.\nInstalacija bu přetorhnjena.",
@@ -87,8 +87,8 @@
        "config-type-postgres": "PostgreSQL",
        "config-type-sqlite": "SQLite",
        "config-type-oracle": "Oracle",
-       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] je primarny cil za MediaWiki a podpěruje so najlěpje. MediaWiki funguje tež z [{{int:version-db-mariadb-url}} MariaDB] a [{{int:version-db-percona-url}} Percona Server], kotrejž stej kompatibelnej z MySQL. ([https://secure.php.net/manual/en/mysqli.installation.php Nawod ke kompilowanju  PHP z  MySQL-podpěru])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] je popularny system datoweje banki zjawneho žórła jako alternatiwa k MySQL. Móhło hišće někotre zmylki eksistować, a njeporuča so jón w produktiwnej wokolinje wužiwać. ([https://secure.php.net/manual/en/pgsql.installation.php Nawod za kompilowanje PHP z podpěru PostgreSQL])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] je primarny cil za MediaWiki a podpěruje so najlěpje. MediaWiki funguje tež z [{{int:version-db-mariadb-url}} MariaDB] a [{{int:version-db-percona-url}} Percona Server], kotrejž stej kompatibelnej z MySQL. ([https://www.php.net/manual/en/mysqli.installation.php Nawod ke kompilowanju  PHP z  MySQL-podpěru])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] je popularny system datoweje banki zjawneho žórła jako alternatiwa k MySQL. Móhło hišće někotre zmylki eksistować, a njeporuča so jón w produktiwnej wokolinje wužiwać. ([https://www.php.net/manual/en/pgsql.installation.php Nawod za kompilowanje PHP z podpěru PostgreSQL])",
        "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] je komercielna předewzaćelska datowa banka. ([http://www.php.net/manual/en/oci8.installation.php Nawod za kompilowanje PHP z OCI8-podpěru])",
        "config-header-mysql": "Nastajenja MySQL",
        "config-header-postgres": "Nastajenja PostgreSQL",
index 25c6cae..a2a4e3b 100644 (file)
        "config-pcre-no-utf8": "<strong>Kritikus hiba:</strong> Úgy tűnik, hogy a PHP PRCE modulja PRCE_UTF8 támogatás nélkül lett fordítva.\nA MediaWikinek UTF-8-támogatásra van szüksége a helyes működéshez.",
        "config-memory-raised": "A PHP <code>memory_limit</code> beállításának értéke: $1. Meg lett növelve a következő értékre: $2.",
        "config-memory-bad": "<strong>Figyelmeztetés:</strong> A PHP <code>memory_limit</code> beállításának értéke $1.\nEz az érték valószínűleg túl kevés, a telepítés sikertelen lehet.",
-       "config-apc": "Az [https://secure.php.net/apc APC] telepítve van",
-       "config-apcu": "Az [https://secure.php.net/apcu APCu] telepítve van",
+       "config-apc": "Az [https://www.php.net/apc APC] telepítve van",
+       "config-apcu": "Az [https://www.php.net/apcu APCu] telepítve van",
        "config-wincache": "A [https://www.iis.net/downloads/microsoft/wincache-extension WinCache] telepítve van",
-       "config-no-cache-apcu": "<strong>Figyelmeztetés:</strong> nem találhatók a következők: [https://secure.php.net/apcu APCu] vagy [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nAz objektum gyorsítótárazása nincs engedélyezve.",
+       "config-no-cache-apcu": "<strong>Figyelmeztetés:</strong> nem találhatók a következők: [https://www.php.net/apcu APCu] vagy [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nAz objektum gyorsítótárazása nincs engedélyezve.",
        "config-diff3-bad": "GNU diff3 nem található.",
        "config-git": "Megtaláltam a Git verziókezelő szoftvert: <code>$1</code>.",
        "config-git-bad": "A Git verziókezelő rendszer nem található.",
        "config-type-mysql": "MySQL (vagy kompatibilis)",
        "config-type-mssql": "Microsoft SQL Szerver",
        "config-support-info": "A MediaWiki a következő adatbázisrendszereket támogatja:\n\n$1\n\nHa az alábbi listán nem találod azt a rendszert, melyet használni szeretnél, a fenti linken található instrukciókat követve engedélyezheted a támogatását.",
-       "config-dbsupport-mysql": "* A [{{int:version-db-mysql-url}} MySQL] a MediaWiki elsődleges célpontja, így a legjobban támogatott. A MediaWiki elfut [{{int:version-db-mariadb-url}} MariaDB-n] és [{{int:version-db-percona-url}} Percona Serveren] is, mivel ezek MySQL-kompatibilisek. ([https://secure.php.net/manual/en/mysql.installation.php Hogyan fordítható a PHP MySQL-támogatással])",
-       "config-dbsupport-postgres": "* A [{{int:version-db-postgres-url}} PostgreSQL] népszerű, nyílt forráskódú adatbázisrendszer, a MySQL alternatívája. ([https://secure.php.net/manual/en/pgsql.installation.php Hogyan fordítható a PHP PostgreSQL-támogatással])",
+       "config-dbsupport-mysql": "* A [{{int:version-db-mysql-url}} MySQL] a MediaWiki elsődleges célpontja, így a legjobban támogatott. A MediaWiki elfut [{{int:version-db-mariadb-url}} MariaDB-n] és [{{int:version-db-percona-url}} Percona Serveren] is, mivel ezek MySQL-kompatibilisek. ([https://www.php.net/manual/en/mysql.installation.php Hogyan fordítható a PHP MySQL-támogatással])",
+       "config-dbsupport-postgres": "* A [{{int:version-db-postgres-url}} PostgreSQL] népszerű, nyílt forráskódú adatbázisrendszer, a MySQL alternatívája. ([https://www.php.net/manual/en/pgsql.installation.php Hogyan fordítható a PHP PostgreSQL-támogatással])",
        "config-dbsupport-sqlite": "* Az [{{int:version-db-sqlite-url}} SQLite] egy könnyű, nagyon jól támogatott adatbázisrendszer. ([http://www.php.net/manual/en/pdo.installation.php Hogyan fordítható a PHP SQLite-támogatással], PDO-t használ)",
        "config-dbsupport-oracle": "* Az [{{int:version-db-oracle-url}} Oracle] kereskedelmi, vállalati adatbázisrendszer. ([http://www.php.net/manual/en/oci8.installation.php Hogyan fordítható a PHP OCI8-támogatással])",
-       "config-dbsupport-mssql": "* A [{{int:version-db-mssql-url}} Microsoft SQL Server] kereskedelmi, vállalati adatbázisrendszer. ([https://secure.php.net/manual/en/sqlsrv.installation.php Hogyan fordítható a PHP SQLSRV-támogatással])",
+       "config-dbsupport-mssql": "* A [{{int:version-db-mssql-url}} Microsoft SQL Server] kereskedelmi, vállalati adatbázisrendszer. ([https://www.php.net/manual/en/sqlsrv.installation.php Hogyan fordítható a PHP SQLSRV-támogatással])",
        "config-header-mysql": "MySQL-beállítások",
        "config-header-postgres": "PostgreSQL-beállítások",
        "config-header-sqlite": "SQLite-beállítások",
index 01dc661..8bf48d8 100644 (file)
        "config-pcre-no-utf8": "'''Fatal''': Le modulo PCRE de PHP pare haber essite compilate sin supporto de PCRE_UTF8.\nMediaWiki require supporto de UTF-8 pro functionar correctemente.",
        "config-memory-raised": "Le <code>memory_limit</code> de PHP es $1, elevate a $2.",
        "config-memory-bad": "'''Aviso:''' Le <code>memory_limit</code> de PHP es $1.\nIsto es probabilemente troppo basse.\nLe installation pote faller!",
-       "config-apc": "[https://secure.php.net/apc APC] es installate",
-       "config-apcu": "[https://secure.php.net/apcu APCu] es installate",
+       "config-apc": "[https://www.php.net/apc APC] es installate",
+       "config-apcu": "[https://www.php.net/apcu APCu] es installate",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] es installate",
-       "config-no-cache-apcu": "<strong>Attention:</strong> Impossibile trovar [https://secure.php.net/apcu APCu] o [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nLe cache de objectos non es activate.",
+       "config-no-cache-apcu": "<strong>Attention:</strong> Impossibile trovar [https://www.php.net/apcu APCu] o [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nLe cache de objectos non es activate.",
        "config-mod-security": "<strong>Attention</strong>: [https://modsecurity.org/ mod_security]/mod_security2 es active in tu servitor web. Multe configurationes commun de isto causa problemas pro MediaWiki o altere software que permitte al usatores de publicar contento arbitrari. Si possibile, isto deberea esser disactivate.\nAlteremente, consulta le [https://modsecurity.org/documentation/ documentation de mod_security] o contacta le servicio de adjuta de tu servitor si tu incontra estranie errores.",
        "config-diff3-bad": "Le utilitate de comparation de texto GNU diff3 non ha essite trovate. Es possibile ignorar isto pro le momento, ma tu poterea incontrar conflictos de modification plus frequentemente.",
        "config-git": "Systema de controlo de version Git trovate: <code>$1</code>",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki supporta le sequente systemas de base de datos:\n\n$1\n\nSi tu non vide hic infra le systema de base de datos que tu tenta usar, alora seque le instructiones ligate hic supra pro activar le supporto.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] es le systema primari pro MediaWiki e le melio supportate. MediaWiki functiona anque con [{{int:version-db-mysql-url}} MySQL] e con [{{int:version-db-percona-url}} Percona Server], le quales es compatibile con MariaDB. ([https://secure.php.net/manual/en/mysqli.installation.php Como compilar PHP con supporto de MySQL])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] es un systema de base de datos popular e open source, alternativa a MySQL. ([https://secure.php.net/manual/en/pgsql.installation.php Como compilar PHP con supporto de PostgreSQL])",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] es un systema de base de datos legier que es multo ben supportate. ([https://secure.php.net/manual/en/pdo.installation.php Como compilar PHP con supporto de SQLite], usa PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] es un banca de datos commercial pro interprisas. ([https://secure.php.net/manual/en/oci8.installation.php Como compilar PHP con supporto de OCI8])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] es un base de datos de interprisa commercial pro Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php Como compilar PHP con supporto de SQLSRV])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] es le systema primari pro MediaWiki e le melio supportate. MediaWiki functiona anque con [{{int:version-db-mysql-url}} MySQL] e con [{{int:version-db-percona-url}} Percona Server], le quales es compatibile con MariaDB. ([https://www.php.net/manual/en/mysqli.installation.php Como compilar PHP con supporto de MySQL])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] es un systema de base de datos popular e open source, alternativa a MySQL. ([https://www.php.net/manual/en/pgsql.installation.php Como compilar PHP con supporto de PostgreSQL])",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] es un systema de base de datos legier que es multo ben supportate. ([https://www.php.net/manual/en/pdo.installation.php Como compilar PHP con supporto de SQLite], usa PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] es un banca de datos commercial pro interprisas. ([https://www.php.net/manual/en/oci8.installation.php Como compilar PHP con supporto de OCI8])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] es un base de datos de interprisa commercial pro Windows. ([https://www.php.net/manual/en/sqlsrv.installation.php Como compilar PHP con supporto de SQLSRV])",
        "config-header-mysql": "Configuration de MariaDB/MySQL",
        "config-header-postgres": "Configuration de PostgreSQL",
        "config-header-sqlite": "Configuration de SQLite",
        "config-sqlite-cant-create-db": "Non poteva crear le file de base de datos <code>$1</code>.",
        "config-sqlite-fts3-downgrade": "PHP non ha supporto pro FTS3. Le tabellas es retrogradate.",
        "config-can-upgrade": "Il ha tabellas MediaWiki in iste base de datos.\nPro actualisar los a MediaWiki $1, clicca super '''Continuar'''.",
+       "config-upgrade-error": "Un error ha occurrite durante le actualisation del tabellas MediaWiki in tu base de datos.\n\nPro plus information, examina le registro supra. Pro tentar lo de novo, clicca sur <strong>Continuar</strong>.",
        "config-upgrade-done": "Actualisation complete.\n\nTu pote ora [$1 comenciar a usar tu wiki].\n\nSi tu vole regenerar tu file <code>LocalSettings.php</code>, clicca super le button hic infra.\nIsto '''non es recommendate''' si tu non ha problemas con tu wiki.",
        "config-upgrade-done-no-regenerate": "Actualisation complete.\n\nTu pote ora [$1 comenciar a usar tu wiki].",
        "config-regenerate": "Regenerar LocalSettings.php →",
        "config-license-help": "Multe wikis public pone tote le contributiones sub un [https://freedomdefined.org/Definition/Ia?uselang=ia licentia libere].\nIsto adjuta a crear un senso de proprietate communitari e incoragia le contribution in longe termino.\nIsto non es generalmente necessari pro un wiki private o de interprisa.\n\nSi tu vole poter usar texto de Wikipedia, e si tu vole que Wikipedia pote acceptar texto copiate de tu wiki, tu debe seliger <strong>{{int:config-license-cc-by-sa}}</strong>.\n\nWikipedia usava anteriormente le Licentia GNU pro Documentation Libere (GFDL).\nIste es un licentia valide, ma es difficile a comprender.\nIl es anque difficile reusar le contento licentiate sub GFDL.",
        "config-email-settings": "Configuration de e-mail",
        "config-enable-email": "Activar le e-mail sortiente",
-       "config-enable-email-help": "Si tu vole que e-mail functiona, [Config-dbsupport-oracle/manual/en/mail.configuration.php le optiones de e-mail de PHP] debe esser configurate correctemente.\nSi tu non vole functiones de e-mail, tu pote disactivar los hic.",
+       "config-enable-email-help": "Si tu vole que e-mail functiona, [https://www.php.net/manual/en/mail.configuration.php le optiones de e-mail de PHP] debe esser configurate correctemente.\nSi tu non vole functiones de e-mail, tu pote disactivar los hic.",
        "config-email-user": "Activar le e-mail de usator a usator",
        "config-email-user-help": "Permitter a tote le usatores de inviar e-mail inter se, si illes lo ha activate in lor preferentias.",
        "config-email-usertalk": "Activar notification de cambios in paginas de discussion de usatores",
        "config-install-done": "<strong>Felicitationes!</strong>\nTu ha installate MediaWiki.\n\nLe installator ha generate un file <code>LocalSettings.php</code>.\nIste contine tote le configuration.\n\nEs necessari discargar lo e poner lo in le base del installation wiki (le mesme directorio que index.php).\nLe discargamento debe haber comenciate automaticamente.\n\nSi le discargamento non ha comenciate, o si illo esseva cancellate, recomencia le discargamento con un clic sur le ligamine sequente:\n\n$3\n\n<strong>Nota:</strong> Si tu non discarga iste file de configuration ora, illo non essera disponibile plus tarde.\n\nPost facer isto, tu pote <strong>[$2 entrar in tu wiki]</strong>.",
        "config-install-done-path": "<strong>Felicitationes!</strong>\nTu ha installate MediaWiki.\n\nLe installator ha generate un file <code>LocalSettings.php</code>.\nIste contine tote le configuration.\n\nEs necessari discargar lo e poner lo in <code>$4</code>.\nLe discargamento debe haber comenciate automaticamente.\n\nSi le discargamento non ha comenciate, o si illo esseva cancellate, recomencia le discargamento con un clic sur le ligamine sequente:\n\n$3\n\n<strong>Nota:</strong> Si tu non discarga iste file de configuration ora, illo non essera disponibile plus tarde.\n\nPost facer isto, tu pote <strong>[$2 entrar in tu wiki]</strong>.",
        "config-install-success": "MediaWiki ha essite installate con successo. Tu pote ora\nvisitar <$1$2> pro vider tu wiki.\nSi tu ha questiones, consulta nostre lista de questiones frequentemente ponite:\n<https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ> o usa un del\nforos de supporto indicate sur ille pagina.",
+       "config-install-db-success": "Le installation del base de datos ha succedite",
        "config-download-localsettings": "Discargar <code>LocalSettings.php</code>",
        "config-help": "adjuta",
        "config-help-tooltip": "clicca pro displicar",
        "config-skins-screenshots": "$1 (capturas de schermo: $2)",
        "config-extensions-requires": "$1 (require $2)",
        "config-screenshot": "captura de schermo",
+       "config-extension-not-found": "Impossibile trovar le file de registration pro le extension \"$1\"",
+       "config-extension-dependency": "Un error de dependentia se ha producite durante le installation del extension \"$1\": $2",
        "mainpagetext": "<strong>MediaWiki ha essite installate.</strong>",
        "mainpagedocfooter": "Consulta le [https://meta.wikimedia.org/wiki/Help:Contents Guida del usator] pro information sur le uso del software wiki.\n\n== Pro initiar ==\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Lista de configurationes]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ FAQ a proposito de MediaWiki]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Lista de diffusion pro annuncios de nove versiones de MediaWiki]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Traducer MediaWiki in tu lingua]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Como combatter le spam in tu wiki]"
 }
index 7d8ce34..0071634 100644 (file)
        "config-pcre-no-utf8": "'''Fatal''': Modul PCRE PHP tampaknya dikompilasi tanpa dukungan PCRE_UTF8.\nMediaWiki memerlukan dukungan UTF-8 untuk berfungsi dengan benar.",
        "config-memory-raised": "<code>memory_limit</code> PHP adalah $1, dinaikkan ke $2.",
        "config-memory-bad": "'''Peringatan:''' <code>memory_limit</code> PHP adalah $1.\nIni terlalu rendah.\nInstalasi terancam gagal!",
-       "config-apc": "[https://secure.php.net/apc APC] telah dipasang",
-       "config-apcu": "[https://secure.php.net/apcu APCu] telah dipasang",
+       "config-apc": "[https://www.php.net/apc APC] telah dipasang",
+       "config-apcu": "[https://www.php.net/apcu APCu] telah dipasang",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] telah diinstal",
-       "config-no-cache-apcu": "<strong>Peringatan:</strong> Tidak dapat menemukan [https://secure.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] atau [https://www.iis.net/downloads/microsoft/wincache-extension WinCache]. Singgahan obyek tidak diaktifkan.",
+       "config-no-cache-apcu": "<strong>Peringatan:</strong> Tidak dapat menemukan [https://www.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] atau [https://www.iis.net/downloads/microsoft/wincache-extension WinCache]. Singgahan obyek tidak diaktifkan.",
        "config-mod-security": "<strong>Peringatan:</strong> Server web Anda memiliki [https://modsecurity.org/ mod_security] yang diaktifkan. Jika salah dalam mengkonfigurasi, ini dapat menyebabkan masalah untuk MediaWiki atau perangkat lunak lain yang memungkinkan pengguna untuk mengirim sembarang konten.\nLihat [https://modsecurity.org/documentation/ dokumentasi mod_security] atau hubungi layanan host Anda jika Anda mengalami kesalahan acak.",
        "config-diff3-bad": "GNU diff3 tidak ditemukan.",
        "config-git": "Menemukan perangkat lunak kontrol versi Git: <code>$1</code>.",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki mendukung sistem basis data berikut:\n\n$1\n\nJika Anda tidak melihat sistem basis data yang Anda gunakan tercantum di bawah ini, ikuti petunjuk terkait di atas untuk mengaktifkan dukungan.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] adalah target utama MediaWiki dan memiliki dukungan terbaik. MediaWiki juga berjalan dengan [{{int:version-db-mariadb-url}} MariaDB] dan [{{int:version-db-percona-url}} Server Percona], yang kompatibel dengan MySQL. ([https://secure.php.net/manual/en/mysql.installation.php Cara mengompilasi PHP dengan dukungan MySQL])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] adalah sistem basis data sumber terbuka populer sebagai alternatif MySQL.([https://secure.php.net/manual/en/pgsql.installation.php Bagaimana mengompilasikan PHP dengan dukungan PostgreSQL])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] adalah target utama MediaWiki dan memiliki dukungan terbaik. MediaWiki juga berjalan dengan [{{int:version-db-mariadb-url}} MariaDB] dan [{{int:version-db-percona-url}} Server Percona], yang kompatibel dengan MySQL. ([https://www.php.net/manual/en/mysql.installation.php Cara mengompilasi PHP dengan dukungan MySQL])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] adalah sistem basis data sumber terbuka populer sebagai alternatif MySQL.([https://www.php.net/manual/en/pgsql.installation.php Bagaimana mengompilasikan PHP dengan dukungan PostgreSQL])",
        "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] adalah sistem basis data yang ringan yang sangat baik dukungannya. ([http://www.php.net/manual/en/pdo.installation.php cara mengompilasi PHP dengan dukungan SQLite], menggunakan PDO)",
        "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] adalah basis data komersial untuk perusahaan. ([http://www.php.net/manual/en/oci8.installation.php cara mengompilasi PHP dengan dukungan OCI8])",
-       "config-dbsupport-mssql": "[{{int:version-db-mssql-url}} Microsoft SQL Server] adalah database perusahaan komersial untuk Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php Bagaimana cara mengkompilasi PHP dengan dukungan SQLSRV])",
+       "config-dbsupport-mssql": "[{{int:version-db-mssql-url}} Microsoft SQL Server] adalah database perusahaan komersial untuk Windows. ([https://www.php.net/manual/en/sqlsrv.installation.php Bagaimana cara mengkompilasi PHP dengan dukungan SQLSRV])",
        "config-header-mysql": "Pengaturan MariaDB/MySQL",
        "config-header-postgres": "Pengaturan PostgreSQL",
        "config-header-sqlite": "Pengaturan SQLite",
index 530fd0e..4e9781b 100644 (file)
@@ -38,8 +38,8 @@
        "config-env-bad": "Omno verifikesis.\nVu NE POVAS intalar MediaWiki.",
        "config-env-php": "PHP $1 instalesis.",
        "config-env-hhvm": "HHVM $1 instalesis.",
-       "config-apc": "[https://secure.php.net/apc APC] instalesis",
-       "config-apcu": "[https://secure.php.net/apcu APCu] instalesis",
+       "config-apc": "[https://www.php.net/apc APC] instalesis",
+       "config-apcu": "[https://www.php.net/apcu APCu] instalesis",
        "config-profile-private": "Privata wiki",
        "config-license": "Autoroyuro e permiso:",
        "config-license-cc-0": "Creative Commons Zero (Publika domeno)",
index 707fc24..3af2fc0 100644 (file)
@@ -34,7 +34,7 @@
        "config-copyright": "=== Höfundarréttur og skilmálar ===\n\n$1\n\nÞetta er frjáls hugbúnaður; þú mátt dreifa honum og/eða breyta samkvæmt skilmálum í almenna GNU GPL notkunarleyfinu eins og það er gefið út af Frjálsu hugbúnaðarstofnuninni; annaðhvort útgáfu 2 af GPL-leyfinu, eða (ef þér sýnist svo) einhverri nýrri útgáfu leyfisins.\n\nHugbúnaði þessum er dreift í þeirri von að hann geti verið gagnlegur, en <strong>ÁN ALLRAR ÁBYRGÐAR</strong>; einnig án þeirrar ábyrgðar sem gefin er í skyn með <strong>SELJANLEIKA</strong> eða <strong>EIGINLEIKUM TIL TILTEKINNA NOTA</strong>. Sjá almenna GNU GPL notkunarleyfið fyrir nánari upplýsingar.\n\nÞað ætti að hafa fylgt afrit af almenna <doclink href=Copying>GNU GPL notkunarleyfinu</doclink> með forritinu; ef ekki skrifið þá Fjálsu hugbúnarstofnuninni: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA, eða [https://www.gnu.org/copyleft/gpl.html lestu það á netinu].",
        "config-env-php": "PHP $1 er uppsett.",
        "config-env-hhvm": "HHVM $1 er uppsett.",
-       "config-apc": "[https://secure.php.net/apc APC] er uppsett",
+       "config-apc": "[https://www.php.net/apc APC] er uppsett",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] er uppsett",
        "config-diff3-bad": "GNU diff3 textasamanburðartólið fannst ekki. Þú getur hunsað þetta núna, en þú gætir lent oftar í breytingaárekstrum.",
        "config-using-server": "Nota \"<nowiki>$1</nowiki>\" sem heiti á þjóni.",
index 5be6e03..cc34a31 100644 (file)
        "config-pcre-no-utf8": "'''Errore''': Il modulo PCRE di PHP sembra essere stato compilato senza il supporto PCRE_UTF8, ma MediaWiki lo richiede per funzionare correttamente.",
        "config-memory-raised": "Il valore <code>memory_limit</code> di PHP è $1, aumentato a $2.",
        "config-memory-bad": "''Attenzione:''' Il valore di <code>memory_limit</code> di PHP è $1.\nProbabilmente è troppo basso.\nL'installazione potrebbe non riuscire!",
-       "config-apc": "[https://secure.php.net/apc APC] è installato",
-       "config-apcu": "[https://secure.php.net/apcu APCu] è installato",
+       "config-apc": "[https://www.php.net/apc APC] è installato",
+       "config-apcu": "[https://www.php.net/apcu APCu] è installato",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] è installato",
-       "config-no-cache-apcu": "'''Attenzione:''' [https://secure.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] o [https://www.iis.net/downloads/microsoft/wincache-extension WinCache] non sono stati trovati.\nLa caching degli oggetti non è attivata.",
+       "config-no-cache-apcu": "'''Attenzione:''' [https://www.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] o [https://www.iis.net/downloads/microsoft/wincache-extension WinCache] non sono stati trovati.\nLa caching degli oggetti non è attivata.",
        "config-mod-security": "<strong>Attenzione:</strong> Il tuo server web ha il [https://modsecurity.org/ mod_security] abilitato. Se non correttamente configurato, può creare problemi a MediaWiki o ad altro software che permette agli utenti di pubblicare contenuto.\nFai riferimento alla [https://modsecurity.org/documentation/ documentazione sul mod_security] o contatta il supporto tecnico del tuo provider di hosting se si verificano errori.",
        "config-diff3-bad": "Utilità di confronto del testo GNU diff3 non trovata. È possibile ignorare per ora, ma potresti incorrere in conflitti di modifica più frequentemente.",
        "config-git": "Trovato software di controllo della versione Git: <code>$1</code>.",
        "config-type-mysql": "MariaDB, MySQL o compatibile",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki supporta i seguenti sistemi di database:\n\n$1\n\nSe fra quelli elencati qui sotto non vedi il sistema di database che vorresti utilizzare, seguire le istruzioni linkate sopra per abilitare il supporto.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] è la configurazione preferibile per MediaWiki ed è quella meglio supportata. MediaWiki funziona anche con [{{int:version-db-mysql-url}} MySQL] e [{{int:version-db-percona-url}} Percona Server], che sono compatibili con MariaDB.([https://secure.php.net/manual/en/mysqli.installation.php Come compilare PHP con supporto MySQL])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] è un popolare sistema di database open source come alternativa a MySQL. ([https://secure.php.net/manual/en/pgsql.installation.php Come compilare PHP con supporto PostgreSQL])",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite]  è un sistema di database leggero, che è supportato molto bene. ([https://secure.php.net/manual/en/pdo.installation.php Come compilare PHP con supporto SQLite], utilizza PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] è un database di un'impresa commerciale. ([https://secure.php.net/manual/en/oci8.installation.php Come compilare PHP con supporto OCI8])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] è un database di un'impresa commerciale per Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php Come compilare PHP con supporto SQLSRV])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] è la configurazione preferibile per MediaWiki ed è quella meglio supportata. MediaWiki funziona anche con [{{int:version-db-mysql-url}} MySQL] e [{{int:version-db-percona-url}} Percona Server], che sono compatibili con MariaDB.([https://www.php.net/manual/en/mysqli.installation.php Come compilare PHP con supporto MySQL])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] è un popolare sistema di database open source come alternativa a MySQL. ([https://www.php.net/manual/en/pgsql.installation.php Come compilare PHP con supporto PostgreSQL])",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite]  è un sistema di database leggero, che è supportato molto bene. ([https://www.php.net/manual/en/pdo.installation.php Come compilare PHP con supporto SQLite], utilizza PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] è un database di un'impresa commerciale. ([https://www.php.net/manual/en/oci8.installation.php Come compilare PHP con supporto OCI8])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] è un database di un'impresa commerciale per Windows. ([https://www.php.net/manual/en/sqlsrv.installation.php Come compilare PHP con supporto SQLSRV])",
        "config-header-mysql": "Impostazioni MySQL",
        "config-header-postgres": "Impostazioni PostgreSQL",
        "config-header-sqlite": "Impostazioni SQLite",
        "config-sqlite-cant-create-db": "Impossibile creare il file di database <code>$1</code> .",
        "config-sqlite-fts3-downgrade": "Il PHP è mancante del supporto FTS3, declassamento tabelle in corso",
        "config-can-upgrade": "Ci sono tabelle di MediaWiki in questo database.\nPer aggiornarle a MediaWiki $1, fai clic su '''continua'''.",
+       "config-upgrade-error": "Si è verificato un errore durante l'aggiornamento delle tabelle MediaWiki nel tuo database.\n\nPer ulteriori informazioni guarda nel registro qui sopra, per riprovare clicca su <strong>Continua</strong>.",
        "config-upgrade-done": "Aggiornamento completo.\n\nPuoi [$1 iniziare ad usare il tuo wiki].\n\nSe vuoi rigenerare il tuo file <code>LocalSettings.php</code>, clicca sul pulsante sotto. Questa operazione '''non è raccomandata''', a meno che non hai problemi con il tuo wiki.",
        "config-upgrade-done-no-regenerate": "Aggiornamento completo.\n\nPuoi [$1 iniziare ad usare il tuo wiki].",
        "config-regenerate": "Rigenera LocalSettings.php →",
        "config-license-help": "Molti wiki pubblici rilasciano i loro contributi con una [https://freedomdefined.org/Definition licenza libera]. Questo aiuta a creare un senso di proprietà condivisa nella comunità e incoraggia a contribuire a lungo termine. Non è generalmente necessario per un wiki privato o aziendale.\n\nSe vuoi usare testi da Wikipedia, o desideri che Wikipedia possa essere in grado di accettare testi copiati dal tuo wiki, dovresti scegliere <strong>{{int:config-license-cc-by-sa}}</strong>.\n\nIn precedenza Wikipedia ha utilizzato la GNU Free Documentation License. La GFDL è una licenza valida, ma è di difficile comprensione e complica il riutilizzo dei contenuti.",
        "config-email-settings": "Impostazioni email",
        "config-enable-email": "Abilita la posta elettronica in uscita",
-       "config-enable-email-help": "Se vuoi che funzionino le email, le [https://secure.php.net/manual/en/mail.configuration.php impostazioni della posta] devono essere configurate correttamente.\nSe non si desidera alcuna funzionalità di posta elettronica, puoi disabilitarla qui.",
+       "config-enable-email-help": "Se vuoi che funzionino le email, le [https://www.php.net/manual/en/mail.configuration.php impostazioni della posta] devono essere configurate correttamente.\nSe non si desidera alcuna funzionalità di posta elettronica, puoi disabilitarla qui.",
        "config-email-user": "Abilita invio email fra utenti",
        "config-email-user-help": "Consente a tutti gli utenti di inviarsi a vicenda email, se lo hanno abilitato nelle loro preferenze.",
        "config-email-usertalk": "Abilita le notifiche per le pagine di discussione utente",
        "config-install-mainpage-failed": "Impossibile inserire la pagina principale: $1",
        "config-install-done": "<strong>Complimenti!</strong>\nHai installato MediaWiki.\n\nIl programma di installazione ha generato un file <code>LocalSettings.php</code> che contiene tutte le impostazioni.\n\nDevi scaricarlo ed inserirlo nella directory base del tuo wiki (la stessa dove è presente index.php). Il download dovrebbe partire automaticamente.\n\nSe il download non si avvia, o se è stato annullato, puoi riavviarlo cliccando sul collegamento di seguito:\n\n$3\n\n<strong>Nota:</strong> se esci ora dall'installazione senza scaricare il file di configurazione che è stato generato, questo poi non sarà più disponibile in seguito.\n\nQuando hai fatto, puoi <strong>[$2 entrare nel tuo wiki]</strong>.",
        "config-install-done-path": "<strong>Complimenti!</strong>\nHai installato MediaWiki.\n\nIl programma di installazione ha generato un file <code>LocalSettings.php</code> che contiene tutte le impostazioni.\n\nDevi scaricarlo ed inserirlo in <code>$4</code>. Il download dovrebbe partire automaticamente.\n\nSe il download non si avvia, o se è stato annullato, puoi riavviarlo cliccando sul collegamento seguente:\n\n$3\n\n<strong>Nota:</strong> se esci ora dall'installazione senza scaricare il file di configurazione che è stato generato, questo poi non sarà più disponibile in seguito.\n\nQuando hai fatto, puoi <strong>[$2 entrare nel tuo wiki]</strong>.",
+       "config-install-success": "MediaWiki è stato installato corretamente. Ora puoi visitare <$1$2> per vedere il tuo wiki.\nSe hai domande, controlla la nostra lista di domande frequenti:\n<https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ> o usa usa uno dei forum di supporto riepilogati su quella pagina.",
+       "config-install-db-success": "Il database è stato configurato correttamente",
        "config-download-localsettings": "Scarica <code>LocalSettings.php</code>",
        "config-help": "aiuto",
        "config-help-tooltip": "fai clic per espandere",
index 70462a1..f8318f0 100644 (file)
        "config-pcre-no-utf8": "<strong>致命的エラー:</strong> PHP の PCRE が PCRE_UTF8 対応なしでコンパイルされているようです。\nMediaWiki を正しく動作させるには、UTF-8 対応が必要です。",
        "config-memory-raised": "PHPの<code>memory_limit</code>は$1で、$2に引き上げられました。",
        "config-memory-bad": "<strong>警告:</strong> PHPの<code>memory_limit</code>に$1に設定されています。\nこの値はおそらく小さすぎます。\nインストールが失敗するおそれがあります!",
-       "config-apc": "[https://secure.php.net/apc APC] がインストール済み",
-       "config-apcu": "[https://secure.php.net/apcu APCu] がインストール済み",
+       "config-apc": "[https://www.php.net/apc APC] がインストール済み",
+       "config-apcu": "[https://www.php.net/apcu APCu] がインストール済み",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] がインストール済み",
-       "config-no-cache-apcu": "<strong>警告:</strong> [https://secure.php.net/apcu APCu]、 [https://www.iis.net/downloads/microsoft/wincache-extension WinCache] のいずれも見つかりませんでした。\nオブジェクトのキャッシュは有効化されません。",
+       "config-no-cache-apcu": "<strong>警告:</strong> [https://www.php.net/apcu APCu]、 [https://www.iis.net/downloads/microsoft/wincache-extension WinCache] のいずれも見つかりませんでした。\nオブジェクトのキャッシュは有効化されません。",
        "config-mod-security": "<strong>警告:</strong> あなたのウェブサーバーでは [https://modsecurity.org/ mod_security] が有効になっています。正しく構成されていない場合は、MediaWiki や利用者にコンテンツの投稿を許可するその他のソフトウェアに問題が発生する場合があります。\n[https://modsecurity.org/documentation/ mod_security の説明文書]を確認するか、ランダムなエラーが発生した場合はあなたのホストのサポートにお問い合わせください。",
        "config-diff3-bad": "GNU diff3 が見つかりません。",
        "config-git": "バージョン管理ソフトウェア Git が見つかりました: <code>$1</code>",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "マイクロソフト SQL Server",
        "config-support-info": "MediaWiki は以下のデータベース システムに対応しています:\n\n$1\n\n使用しようとしているデータベース システムが下記の一覧にない場合は、上記リンク先の手順に従ってインストールしてください。",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB]はMediaWikiの主要な対象であり、最もよくサポートされています。MediaWikiはMariaDBと互換性のある[{{int:version-db-mysql-url}} MySQL]、[{{int:version-db-percona-url}} Percona Server]でも動きます。 ([https://secure.php.net/manual/ja/mysqli.installation.php PHPをMySQLサポート付きでコンパイルする方法])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] は、MySQLの代替として人気がある公開のデータベースシステムです。([https://secure.php.net/manual/en/pgsql.installation.php PHPをPostgreSQLサポート付きでコンパイルする方法])",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite]は、良くサポートされている、軽量データベースシステムです。([https://secure.php.net/manual/ja/pdo.installation.php SQLiteに対応したPHPをコンパイルする方法]、PDOを使用)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle]は商業企業のデータベースです。([https://secure.php.net/manual/en/oci8.installation.php OCI8サポートなPHPをコンパイルする方法])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server]は商業企業のWindows用データベースです。([https://secure.php.net/manual/en/sqlsrv.installation.php SQLSRVサポートなPHPをコンパイルする方法])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB]はMediaWikiの主要な対象であり、最もよくサポートされています。MediaWikiはMariaDBと互換性のある[{{int:version-db-mysql-url}} MySQL]、[{{int:version-db-percona-url}} Percona Server]でも動きます。 ([https://www.php.net/manual/ja/mysqli.installation.php PHPをMySQLサポート付きでコンパイルする方法])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] は、MySQLの代替として人気がある公開のデータベースシステムです。([https://www.php.net/manual/en/pgsql.installation.php PHPをPostgreSQLサポート付きでコンパイルする方法])",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite]は、良くサポートされている、軽量データベースシステムです。([https://www.php.net/manual/ja/pdo.installation.php SQLiteに対応したPHPをコンパイルする方法]、PDOを使用)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle]は商業企業のデータベースです。([https://www.php.net/manual/en/oci8.installation.php OCI8サポートなPHPをコンパイルする方法])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server]は商業企業のWindows用データベースです。([https://www.php.net/manual/en/sqlsrv.installation.php SQLSRVサポートなPHPをコンパイルする方法])",
        "config-header-mysql": "MariaDB/MySQL の設定",
        "config-header-postgres": "PostgreSQL の設定",
        "config-header-sqlite": "SQLite の設定",
        "config-enable-email-help": "メールを使用したい場合は、[Config-dbsupport-oracle/manual/en/mail.configuration.php PHP のメール設定]が正しく設定されている必要があります。\nメールの機能を使用しない場合は、ここで無効にすることができます。",
        "config-email-user": "利用者間のメールを有効にする",
        "config-email-user-help": "設定で有効になっている場合、すべてのユーザーがお互いにメールのやりとりを行うことを許可する。",
-       "config-email-usertalk": "ユーザーのトークページでの通知を有効にする",
-       "config-email-usertalk-help": "設定で有効にしている場合は、ユーザーのトークページの変更の通知を受けることをユーザーに許可する。",
+       "config-email-usertalk": "利用者のトークページでの通知を有効にする",
+       "config-email-usertalk-help": "設定で有効にしている場合は、利用者のトークページの変更の通知を受けることを利用者に許可する。",
        "config-email-watchlist": "ウォッチリストの通知を有効にする",
        "config-email-watchlist-help": "利用者が設定で有効にしている場合、閲覧されたページに関する通知を受け取ることを許可する。",
        "config-email-auth": "メールの認証を有効にする",
index 90967d1..856fa6f 100644 (file)
@@ -27,7 +27,7 @@
        "config-sidebar": "* [https://www.mediawiki.org მედიავიკის ვებ-გვერდი]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents/ka მომხმარებლების დახმარება]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents/ka ადმინისტრატორების დახმარება]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ/ka FAQ]\n----\n* <doclink href=Readme>წამიკითხე</doclink>\n* <doclink href=ReleaseNotes>ინფორმაცია გამოშვებაზე</doclink>\n* <doclink href=Copying>ლიცენზია</doclink>\n* <doclink href=UpgradeDoc>განახლება</doclink>",
        "config-env-php": "PHP $1 დაინსტალირებულია",
        "config-env-hhvm": "HHVM $1 დაინსტალირებულია.",
-       "config-apc": "[https://secure.php.net/apc APC] დაყენდა",
+       "config-apc": "[https://www.php.net/apc APC] დაყენდა",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] დაყენდა",
        "config-diff3-bad": "GNU diff3 ვერ მოიძებნა.",
        "config-db-type": "მონაცემთა ბაზის ტიპი:",
index c91f0a9..dca5ef8 100644 (file)
        "config-pcre-no-utf8": "<strong>치명:</strong> PHP의 PCRE 모듈은 RCRE_UTF8 지원 없이 컴파일된 것 같습니다.\n미디어위키가 올바르게 작동하려면 UTF-8을 지원해야 합니다.",
        "config-memory-raised": "PHP의 <code>memory_limit</code>는 $1이며 $2(으)로 늘렸습니다.",
        "config-memory-bad": "<strong>경고:</strong> PHP의 <code>memory_limit</code>는 $1입니다.\n아마도 너무 낮은 것 같습니다.\n설치가 실패할 수 있습니다!",
-       "config-apc": "[https://secure.php.net/apc APC]가 설치되었습니다",
-       "config-apcu": "[https://secure.php.net/apcu APCu]가 설치되었습니다",
+       "config-apc": "[https://www.php.net/apc APC]가 설치되었습니다",
+       "config-apcu": "[https://www.php.net/apcu APCu]가 설치되었습니다",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache]가 설치되었습니다",
-       "config-no-cache-apcu": "<strong>경고:</strong> [https://secure.php.net/apcu APCu] 또는 [https://www.iis.net/downloads/microsoft/wincache-extension WinCache]를 찾을 수 없습니다.",
+       "config-no-cache-apcu": "<strong>경고:</strong> [https://www.php.net/apcu APCu] 또는 [https://www.iis.net/downloads/microsoft/wincache-extension WinCache]를 찾을 수 없습니다. 오브젝트 캐시를 사용할 수 없습니다.",
        "config-mod-security": "<strong>경고:</strong> 웹 서버에 [https://modsecurity.org/ mod_security]가 허용되었습니다. 잘못 설정된 경우 미디어위키나 사용자가 임의의 내용을 게시할 수 있는 다른 소프트웨어에 대한 문제를 일으킬 수 있습니다.\n[https://modsecurity.org/documentation/ mod_security] 문서를 참고하거나 임의의 오류가 발생할 경우 호스트의 지원 요청에 문의하십시오.",
        "config-diff3-bad": "GNU diff3를 찾을 수 없습니다.",
        "config-git": "Git 버전 관리 소프트웨어를 찾았습니다: <code>$1</code>.",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL 서버",
        "config-support-info": "미디어위키는 다음의 데이터베이스 시스템을 지원합니다:\n\n$1\n\n데이터베이스 시스템이 표시되지 않을 때 아래에 나열된 다음 지원을 활성화하려면 위의 링크된 지시에 따라 설치해볼 수 있습니다.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB]는 미디어위키의 기본 대상이며 가장 잘 지원됩니다. 미디어위키는 또한 MariaDB와 호환되는 [{{int:version-db-mysql-url}} MySQL]과 [{{int:version-db-percona-url}} Percona 서버]에서도 작동합니다. ([https://secure.php.net/manual/en/mysql.installation.php MySQL 지원으로 PHP를 컴파일하는 방법])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL]은 MySQL의 대안으로서 인기 있는 오픈 소스 데이터베이스 시스템입니다. ([https://secure.php.net/manual/en/pgsql.installation.php PostgreSQL 지원으로 PHP를 컴파일하는 방법])",
-       "config-dbsupport-sqlite": "*  [{{int:version-db-sqlite-url}} SQLite]는 매우 잘 지원되고 가벼운 데이터베이스 시스템입니다. ([https://secure.php.net/manual/en/pdo.installation.php SQLite 지원으로 PHP를 컴파일하는 방법], PDO 사용)",
-       "config-dbsupport-oracle": "*  [{{int:version-db-oracle-url}} Oracle]은 상용 기업 데이터베이스입니다. ([https://secure.php.net/manual/en/oci8.installation.php OCI8 지원으로 PHP를 컴파일하는 방법])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL 서버]는 Windows용 상용 기업 데이터베이스입니다. ([https://secure.php.net/manual/en/sqlsrv.installation.php SQLSRV 지원으로 PHP를 컴파일하는 방법])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB]는 미디어위키의 기본 대상이며 가장 잘 지원됩니다. 미디어위키는 또한 MariaDB와 호환되는 [{{int:version-db-mysql-url}} MySQL]과 [{{int:version-db-percona-url}} Percona 서버]에서도 작동합니다. ([https://www.php.net/manual/en/mysql.installation.php MySQL 지원으로 PHP를 컴파일하는 방법])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL]은 MySQL의 대안으로서 인기 있는 오픈 소스 데이터베이스 시스템입니다. ([https://www.php.net/manual/en/pgsql.installation.php PostgreSQL 지원으로 PHP를 컴파일하는 방법])",
+       "config-dbsupport-sqlite": "*  [{{int:version-db-sqlite-url}} SQLite]는 매우 잘 지원되고 가벼운 데이터베이스 시스템입니다. ([https://www.php.net/manual/en/pdo.installation.php SQLite 지원으로 PHP를 컴파일하는 방법], PDO 사용)",
+       "config-dbsupport-oracle": "*  [{{int:version-db-oracle-url}} Oracle]은 상용 기업 데이터베이스입니다. ([https://www.php.net/manual/en/oci8.installation.php OCI8 지원으로 PHP를 컴파일하는 방법])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL 서버]는 Windows용 상용 기업 데이터베이스입니다. ([https://www.php.net/manual/en/sqlsrv.installation.php SQLSRV 지원으로 PHP를 컴파일하는 방법])",
        "config-header-mysql": "MariaDB/MySQL 설정",
        "config-header-postgres": "PostgreSQL 설정",
        "config-header-sqlite": "SQLite 설정",
        "config-install-done": "<strong>축하합니다!</strong>\n미디어위키를 설치했습니다.\n\n설치 관리자가 <code>LocalSettings.php</code> 파일을 만들었습니다.\n여기에 모든 설정이 포함되어 있습니다.\n\n파일을 다운로드하여 위키 설치의 거점에 넣어야 합니다. (index.php와 같은 디렉터리) 다운로드가 자동으로 시작됩니다.\n\n다운로드가 제공되지 않을 경우나 그것을 취소한 경우에는 아래의 링크를 클릭하여 다운로드를 다시 시작할 수 있습니다:\n\n$3\n\n<strong>참고:</strong> 이 생성한 설정 파일을 다운로드하지 않고 설치를 끝내면 이 파일은 나중에 사용할 수 없습니다.\n\n완료되었으면 <strong>[$2 위키에 들어갈 수 있습니다]</strong>.",
        "config-install-done-path": "<strong>축하합니다!</strong>\n미디어위키가 설치되었습니다.\n\n설치 관리자가 <code>LocalSettings.php</code> 파일을 생성했습니다.\n이 파일에 모든 설정이 포함되어 있습니다.\n\n이 파일을 다운로드하여 <code>$4</code> 위치에 넣으세요. 다운로드가 자동으로 시작되었을 것입니다.\n\n다운로드가 시작되지 않았거나 취소했다면, 아래 링크를 클릭하여 다운로드를 재시작할 수 있습니다.\n\n$3\n\n<strong>알림:</strong> 지금 다운로드하지 않는다면, 이후에는 이 설정 파일을 다운로드할 수 없습니다.\n\n모든 작업이 완료되었다면, <strong>[$2 위키에 들어갈 수 있습니다]</strong>.",
        "config-install-success": "미디어위키가 성공적으로 설치되었습니다. 이제 <$1$2>에 방문하여 위키를 볼 수 있습니다.\n질문이 있으시다면 자주 묻는 질문 목록을 살펴보십시오:\n<https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ> 아니면\n해당 문서에 연결된 지원 포럼 중 한곳을 이용하십시오.",
+       "config-install-db-success": "데이터베이스가 성공적으로 구축되었습니다",
        "config-download-localsettings": "<code>LocalSettings.php</code> 다운로드",
        "config-help": "도움말",
        "config-help-tooltip": "확장하려면 클릭",
index 5ac7ec6..50cf468 100644 (file)
@@ -60,9 +60,9 @@
        "config-pcre-no-utf8": "'''Dä:''' Et PHP-Modul <i lang=\"en\">PCRE</i> schingk ohne de <i lang=\"en\">PCRE_UTF8</i>-Aandeile övversaz ze sin.\nMediaWiki bruch dä UTF-8-Krohm ävver, öm ohne Fähler loufe ze künne.",
        "config-memory-raised": "Der jrühzte zohjelasse Shpeisherbedarf vum PHP, et <code lang=\"en\">memory_limit</code>, shtund op $1 un es op $2 erop jesaz woode.",
        "config-memory-bad": "'''Opjepaß:''' Dem PHP singe Parameeter <code lang=\"en\">memory_limit</code> es $1.\nDat es wall ze winnisch.\nEt Enreeschte kunnt doh draan kappott jon!",
-       "config-apc": "Dä <code lang=\"en\">[https://secure.php.net/apc APC]</code> es ennjeresht.",
+       "config-apc": "Dä <code lang=\"en\">[https://www.php.net/apc APC]</code> es ennjeresht.",
        "config-wincache": "Dä <code lang=\"en\">[https://www.iis.net/downloads/microsoft/wincache-extension WinCache]</code> es ennjeresht.",
-       "config-no-cache-apcu": "'''Opjepaß:''' Mer kunnte dä <code lang=\"en\" xml:lang=\"en\" dir=\"rtl\">[https://secure.php.net/apcu APCu]</code>, dä <code lang=\"en\" xml:lang=\"en\" dir=\"rtl\">[http://xcache.lighttpd.net/ XCache]</code> udder dä <code lang=\"en\" xml:lang=\"en\" dir=\"rtl\">[https://www.iis.net/downloads/microsoft/wincache-extension WinCache]</code> nit fenge.\nEt <i lang=\"en\" xml:lang=\"en\" dir=\"rtl\">object caching</i> es nit müjjelesch un es ußjeschalldt.",
+       "config-no-cache-apcu": "'''Opjepaß:''' Mer kunnte dä <code lang=\"en\" xml:lang=\"en\" dir=\"rtl\">[https://www.php.net/apcu APCu]</code>, dä <code lang=\"en\" xml:lang=\"en\" dir=\"rtl\">[http://xcache.lighttpd.net/ XCache]</code> udder dä <code lang=\"en\" xml:lang=\"en\" dir=\"rtl\">[https://www.iis.net/downloads/microsoft/wincache-extension WinCache]</code> nit fenge.\nEt <i lang=\"en\" xml:lang=\"en\" dir=\"rtl\">object caching</i> es nit müjjelesch un es ußjeschalldt.",
        "config-mod-security": "<strong>Opjepaß</strong>: Dinge Wäbßööver hät <code  lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[https://modsecurity.org/ mod_security]</code> enjeschalldt. Jenohch schtandattmähßejje Enschtällonge heh em Wikki künne Problehme met MehdijaWikki un och met ander Projramme aanschtivvelle, di zohlohße, dat vun ußerhallef öhndsene Krohm op dä Webßööver jebraat wähde künnt.\nWann müjjelesch sullt mer dat affschallde. Söns beloor Der di Sigg <code  lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[https://modsecurity.org/documentation/ mod_security documentation]</code> udder donn met dä Fachlück för Dinge Webßööver kalle, wann zohfälleje un koomijje Fähler bemärke deihß.",
        "config-diff3-bad": "Mer han <i lang=\"en\">GNU</i> <code lang=\"en\">diff3</code> nit jefonge.",
        "config-git": "Mer han de Väsjohn <code>$1</code> vun däm Väsjohnsverwalldongsprojamm <i lang=\"en\">Git</i> jefonge.",
        "config-type-oracle": "<i lang=\"en\">Oracle</i>",
        "config-type-mssql": "Dä <i lang=\"en\" xml:lang=\"en\">SQL</i>-ẞööver vun <i lang=\"en\" xml:lang=\"en\">Microsoft</i>",
        "config-support-info": "MediaWiki kann met heh dä Daatebangk_Süßteeme zosamme jonn:\n\n$1\n\nWann dat Daatebangk_Süßteem, wat De nämme wells, onge nit dobei es, dann donn desch aan di Aanleidonge hallde, di bovve verlengk sen, öm et op Dingem ẞööver singem Süßteem müjjelesh ze maache, se aan et Loufe ze krijje.",
-       "config-dbsupport-mysql": "* <i lang=\"en\" xml:lang=\"en\">[{{int:version-db-mysql-url}} MySQL]</i> es dat vum MediaWiki et eets un et bäß ongerschtöz Daatebangksüßtehm. Et leuf ävver och met <i lang=\"en\" xml:lang=\"en\">[{{int:version-db-mariadb-url}} MariaDB]</i> un <i lang=\"en\" xml:lang=\"en\">[{{int:version-db-percona-url}} Percona Server]</i>. Di sin kumpatihbel mem <i lang=\"en\" xml:lang=\"en\">MySQL</i>. ([https://secure.php.net/manual/de/mysql.installation.php Aanleidung för et Övversäze un Enreeschte von <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"PHP Hypertext Preprocessor\">PHP</i> met <i lang=\"en\">MySQL</i> dobei, op Deutsch])",
-       "config-dbsupport-postgres": "* <i lang=\"en\">[{{int:version-db-postgres-url}} PostgreSQL]</i> es e bikannt Daatebangksüßtehm met offe Quälltäxde, un ed es och en Wahl nävve <i lang=\"en\">MySQL</i>. Et sinn_er ävver paa klein Fählersche bekannt, um mer künne et em Momang för et reschtijje Werke nit ämfähle. ([https://secure.php.net/manual/de/pgsql.installation.php Aanleidung för et Övversäze un Enreeschte von PHP met <i lang=\"en\">PostgreSQL</i> dobei, op Deutsch])",
+       "config-dbsupport-mysql": "* <i lang=\"en\" xml:lang=\"en\">[{{int:version-db-mysql-url}} MySQL]</i> es dat vum MediaWiki et eets un et bäß ongerschtöz Daatebangksüßtehm. Et leuf ävver och met <i lang=\"en\" xml:lang=\"en\">[{{int:version-db-mariadb-url}} MariaDB]</i> un <i lang=\"en\" xml:lang=\"en\">[{{int:version-db-percona-url}} Percona Server]</i>. Di sin kumpatihbel mem <i lang=\"en\" xml:lang=\"en\">MySQL</i>. ([https://www.php.net/manual/de/mysql.installation.php Aanleidung för et Övversäze un Enreeschte von <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"PHP Hypertext Preprocessor\">PHP</i> met <i lang=\"en\">MySQL</i> dobei, op Deutsch])",
+       "config-dbsupport-postgres": "* <i lang=\"en\">[{{int:version-db-postgres-url}} PostgreSQL]</i> es e bikannt Daatebangksüßtehm met offe Quälltäxde, un ed es och en Wahl nävve <i lang=\"en\">MySQL</i>. Et sinn_er ävver paa klein Fählersche bekannt, um mer künne et em Momang för et reschtijje Werke nit ämfähle. ([https://www.php.net/manual/de/pgsql.installation.php Aanleidung för et Övversäze un Enreeschte von PHP met <i lang=\"en\">PostgreSQL</i> dobei, op Deutsch])",
        "config-dbsupport-sqlite": "* <i lang=\"en\">[{{int:version-db-sqlite-url}} SQLite]</i> es e eijfach Daatebangksüßtehm, wat joot en Schoß jehallde weed. ([http://www.php.net/manual/de/pdo.installation.php Aanleidong för et Övversäze un Enreeschte von PHP met <i lang=\"en\">SQLite</i> dobei, op Deutsch])",
        "config-dbsupport-oracle": "* <i lang=\"en\">[{{int:version-db-oracle-url}} Oracle]</i> es e jeschäfflesch Daatebangksüßtehm för Ferme. ([http://www.php.net/manual/de/oci8.installation.php Aanleidong för et Övversäze un Enreeschte von PHP met <i lang=\"en\" xml:lang=\"en\">OCI8</i> dobei, op Deutsch])",
-       "config-dbsupport-mssql": "* Dä <i lang=\"en\" xml:lang=\"en\">[{{int:version-db-mssql-url}} Microsoft SQL Server]</i> es e jeschäfflesch Dahtebangksüßtehm för Rääschner met <i lang=\"en\" xml:lang=\"en\">Windows</i>. ([https://secure.php.net/manual/en/sqlsrv.installation.php Aanleidong för et Övversäze un Enreeschte von <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"PHP Hypertext Preprocessor\">PHP</i> met <i lang=\"en\" xml:lang=\"en\">SQLSRV </i> dobei, op Deutsch])",
+       "config-dbsupport-mssql": "* Dä <i lang=\"en\" xml:lang=\"en\">[{{int:version-db-mssql-url}} Microsoft SQL Server]</i> es e jeschäfflesch Dahtebangksüßtehm för Rääschner met <i lang=\"en\" xml:lang=\"en\">Windows</i>. ([https://www.php.net/manual/en/sqlsrv.installation.php Aanleidong för et Övversäze un Enreeschte von <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"PHP Hypertext Preprocessor\">PHP</i> met <i lang=\"en\" xml:lang=\"en\">SQLSRV </i> dobei, op Deutsch])",
        "config-header-mysql": "De Enshtällunge för de <i lang=\"en\">MySQL</i> Daatebangk",
        "config-header-postgres": "De Enshtällunge för de <i lang=\"en\">PostgreSQL</i> Daatebangk",
        "config-header-sqlite": "De Enshtällunge för de <i lang=\"en\">SQLite</i> Daatebangk",
index a6d5fda..11b662e 100644 (file)
@@ -26,7 +26,7 @@
        "config-page-upgradedoc": "Bilindkirin",
        "config-page-existingwiki": "Wîkiya heye",
        "config-restart": "Erê, jinûve bide destpêkirin",
-       "config-apc": "[https://secure.php.net/apc APC] hate avakirin",
+       "config-apc": "[https://www.php.net/apc APC] hate avakirin",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] hate avakirin",
        "config-diff3-bad": "GNU diff3 nehate dîtin.",
        "config-db-type": "Cureya danegehê:",
index 9c550df..bbe1a1d 100644 (file)
@@ -49,8 +49,8 @@
        "config-no-db": "Et konnt kee passenden Datebank-Driver fonnt ginn! Dir musst een Datebank-Driver fir PHP installéieren.\n{{PLURAL:$2|Dësn Datebank-Typ gëtt|Dës Datebank-Type ginn}} ënnerstëtzt: $1.\n\nWann Dir PHP selwer compiléiert hutt, da rekonfiguréiert en mat dem ageschalten Datebank-Client, zum Beispill an deem Dir <code>./configure --with-mysqli</code> benotzt.\nWann Dir PHP vun engem Debian oder Ubuntu Package aus installéiert hutt, da musst Dir och den php5-mysql Modul installéieren.",
        "config-outdated-sqlite": "'''Warnung:''' SQLite $1 ass installéiert. Allerdengs brauch MediaWiki SQLite $2 oder méi nei. SQLite ass dofir net disponibel.",
        "config-memory-bad": "'''Opgepasst:''' De Parameter <code>memory_limit</code> vu PHP ass $1.\nDat ass wahrscheinlech ze niddreg.\nD'Installatioun kéint net funktionéieren.",
-       "config-apc": "[https://secure.php.net/apc APC] ass installéiert",
-       "config-apcu": "[https://secure.php.net/apcu APCu] ass installéiert.",
+       "config-apc": "[https://www.php.net/apc APC] ass installéiert",
+       "config-apcu": "[https://www.php.net/apcu APCu] ass installéiert.",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] ass installéiert",
        "config-diff3-bad": "GNU diff3 gouf net fonnt.",
        "config-git": "D'Software Git fir d'Kontroll vu Versioune gouf fonnt: <code>$1</code>.",
@@ -84,9 +84,9 @@
        "config-type-sqlite": "SQLite",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] ass e beléiften Open-Source-Datebanksystem an eng Alternativ zu MySQL. ([https://secure.php.net/manual/en/pgsql.installation.php Uleedung fir d'Kompilatoun vu PHP mat PostgreSQL-Ënnerstëtzung])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] ass e beléiften Open-Source-Datebanksystem an eng Alternativ zu MySQL. ([https://www.php.net/manual/en/pgsql.installation.php Uleedung fir d'Kompilatoun vu PHP mat PostgreSQL-Ënnerstëtzung])",
        "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] ass eng kommerziell Datebank-Software. ([http://www.php.net/manual/en/oci8.installation.php How to compile PHP mat OCI8 Ënnerstëtzung])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] ass eng kommerziell Datebank-Software fir Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php Wéi PHP mat SQLSRV Ënnerstëtzung kompiléieren])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] ass eng kommerziell Datebank-Software fir Windows. ([https://www.php.net/manual/en/sqlsrv.installation.php Wéi PHP mat SQLSRV Ënnerstëtzung kompiléieren])",
        "config-header-mysql": "MariaDB/MySQL-Astellungen",
        "config-header-postgres": "PostgreSQL-Astellungen",
        "config-header-sqlite": "SQLite-Astellungen",
index 0f004c1..b686444 100644 (file)
        "config-pcre-no-utf8": "'''Fatale''': o modulo PCRE de PHP pâ ch'o segge stæto compilou sença o supporto PCRE_UTF8. A MediaWiki a-o richiede pe fonçionâ corettamente.",
        "config-memory-raised": "O valô <code>memory_limit</code> de PHP o l'è $1, aomentou a $2.",
        "config-memory-bad": "''Atençion:''' O valô de <code>memory_limit</code> do PHP o l'è $1.\nFoscia o l'è troppo basso.\nL'installaçion a porriæ fallî!",
-       "config-apc": "[https://secure.php.net/apc APC] o l'è installou",
-       "config-apcu": "[https://secure.php.net/apc APC] o l'è installou",
+       "config-apc": "[https://www.php.net/apc APC] o l'è installou",
+       "config-apcu": "[https://www.php.net/apc APC] o l'è installou",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] o l'è installou",
-       "config-no-cache-apcu": "'''Atençion:''' [https://secure.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] ò [https://www.iis.net/downloads/microsoft/wincache-extension WinCache] no son stæti trovæ.\nA caching di ogetti a no l'è attivâ.",
+       "config-no-cache-apcu": "'''Atençion:''' [https://www.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] ò [https://www.iis.net/downloads/microsoft/wincache-extension WinCache] no son stæti trovæ.\nA caching di ogetti a no l'è attivâ.",
        "config-mod-security": "<strong>Atençion:</strong> O to serviou web o g'ha o [https://modsecurity.org/ mod_security] abilitou. Gh'è tante configuaçioin che crean di problemi a-a MediaWiki ò a atro software ch'o permette a-i utenti de pubbricâ quâ-se-segge contegnuo. Se poscibbile o doviæ ese disabilitou.\nFanni rifeimento a-a [https://modsecurity.org/documentation/ documentaçion insce-o mod_security] ò contatta o supporto tecnico do to provider de hosting se se veifica di erroî.",
        "config-diff3-bad": "GNU diff3 non trovou.",
        "config-git": "Trovou software de controllo da verscion Git: <code>$1</code>.",
        "config-type-mysql": "MariaDB, MySQL ò compatibbile",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki o supporta i seguenti scistemi de database:\n\n$1\n\nSe fra quelli elencæ chì de sotta no ti veddi o scistema de database che ti voriesci doeuviâ, segui e instruçioin inganciæ de d'ato pe abilitâ o supporto.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] a l'è a primma scelta pe MediaWiki e a l'è quella megio suportâ. MediaWiki a fonçion-a ascì con [{{int:version-db-mariadb-url}} MariaDB] e [{{int:version-db-percona-url}} Percona Server], che son compatibbili con MySQL.([https://secure.php.net/manual/en/mysqli.installation.php Comme compilâ PHP con suporto MySQL])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] o l'è un popolare scistema de database open source comme alternativa a MySQL. ([https://secure.php.net/manual/en/pgsql.installation.php Comme compilâ PHP con suporto PostgreSQL])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] a l'è a primma scelta pe MediaWiki e a l'è quella megio suportâ. MediaWiki a fonçion-a ascì con [{{int:version-db-mariadb-url}} MariaDB] e [{{int:version-db-percona-url}} Percona Server], che son compatibbili con MySQL.([https://www.php.net/manual/en/mysqli.installation.php Comme compilâ PHP con suporto MySQL])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] o l'è un popolare scistema de database open source comme alternativa a MySQL. ([https://www.php.net/manual/en/pgsql.installation.php Comme compilâ PHP con suporto PostgreSQL])",
        "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] o l'è un scistema de database leggio, ch'o l'è suportou molto ben. ([http://www.php.net/manual/en/pdo.installation.php Comme compilâ PHP con suporto SQLite], o l'utilizza PDO)",
        "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] o l'è un database de un'impreiza comerciâ. ([http://www.php.net/manual/en/oci8.installation.php Comme compilâ PHP con suporto OCI8])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] o l'è un database de un'impreiza commerciâ per Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php Comme compilâ PHP con supporto SQLSRV])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] o l'è un database de un'impreiza commerciâ per Windows. ([https://www.php.net/manual/en/sqlsrv.installation.php Comme compilâ PHP con supporto SQLSRV])",
        "config-header-mysql": "Impostaçioin MySQL",
        "config-header-postgres": "Impostaçioin PostgreSQL",
        "config-header-sqlite": "Impostaçioin SQLite",
index fe1888d..fcb39df 100644 (file)
        "config-env-hhvm": "HHVM $1 yra įdiegtas.",
        "config-outdated-sqlite": "<strong>Įspėjimas:</strong> jūs turite SQLite $1, kuri yra mažesnė nei minimali reikalinga versija $2. SQLite nebus prieinama.",
        "config-memory-raised": "PHP <code>memory_limit</code> yra $1, padidintas iki $2.",
-       "config-apc": "[https://secure.php.net/apc APC] yra įdiegtas",
-       "config-apcu": "[https://secure.php.net/apcu APCu] yra įdiegtas",
+       "config-apc": "[https://www.php.net/apc APC] yra įdiegtas",
+       "config-apcu": "[https://www.php.net/apcu APCu] yra įdiegtas",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] yra įdiegtas",
-       "config-no-cache-apcu": "<strong>Įspėjimas:</strong> Nepavyko rasti [https://secure.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] ar [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nObjekto spartinimas neįjungtas.",
+       "config-no-cache-apcu": "<strong>Įspėjimas:</strong> Nepavyko rasti [https://www.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] ar [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nObjekto spartinimas neįjungtas.",
        "config-diff3-bad": "GNU diff3 nerastas.",
        "config-git": "Rasta Git versijų kontrolės sistema: <code>$1</code>.",
        "config-imagemagick": "Rastas „ImageMagick“: <code>$1</code>.\nPaveikslėlių miniatiūrizavimas bus įjungtas, jeigu įgalinsite vaizdų įkėlimą.",
index baa6e49..e744495 100644 (file)
@@ -27,7 +27,7 @@
        "config-restart": "Jā, restartēt",
        "config-env-php": "PHP $1 ir uzstādīts.",
        "config-env-hhvm": "HHVM $1 ir uzstādīts.",
-       "config-apcu": "[https://secure.php.net/apcu APCu] ir uzstādīts",
+       "config-apcu": "[https://www.php.net/apcu APCu] ir uzstādīts",
        "config-diff3-bad": "GNU diff3 nav atrasts.",
        "config-db-host-oracle": "Datubāzes TNS:",
        "config-db-name": "Datubāzes nosaukums:",
index 66d3982..450fa8b 100644 (file)
        "config-pcre-no-utf8": "<strong>Кобно</strong>: PCRE-модулот на PHP е срочен без поддршка за PCRE_UTF8.\nМедијаВики бара поддршка за UTF-8 за да може да работи правилно.",
        "config-memory-raised": "<code>memory_limit</code> за PHP изнесува $1, зголемен на $2.",
        "config-memory-bad": "<strong>Предупредување:</strong> <code>memory_limit</code> за PHP изнесува $1.\nОва е веројатно премалку.\nВоспоставката може да не успее!",
-       "config-apc": "[https://secure.php.net/apc APC] е воспоставен",
-       "config-apcu": "[https://secure.php.net/apcu APCu] е воспоставен",
+       "config-apc": "[https://www.php.net/apc APC] е воспоставен",
+       "config-apcu": "[https://www.php.net/apcu APCu] е воспоставен",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] е воспоставен",
-       "config-no-cache-apcu": "<strong>Предупредување:</strong> Не можев да го најдам [https://secure.php.net/apcu APCu] или [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].",
+       "config-no-cache-apcu": "<strong>Предупредување:</strong> Не можев да го најдам [https://www.php.net/apcu APCu] или [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].",
        "config-mod-security": "'''Предупредување''': на вашиот опслужувач има овозможено [https://modsecurity.org/ mod_security]. Ако не е поставено како што треба, ова може да предизвика проблеми кај МедијаВики и други програми што им овозможуваат на корисниците да објавуваат произволни содржини.\nПогледнете ја [https://modsecurity.org/documentation/ mod_security документацијата] или обратете се кај домаќинот ако наидете на случајни грешки.",
        "config-diff3-bad": "Не го пронајдов споредникот за текст ГНУ разл3 (GNU diff3). Засега ова можете да го занемарите, но затоа пак спротиставеностите во уредувањата може да зачестат.",
        "config-git": "Го пронајдов Git програмот за контрола на верзии: <code>$1</code>.",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "МедијаВики ги поддржува следниве системи на бази на податоци:\n\n$1\n\nАко системот што сакате да го користите не е наведен подолу, тогаш проследете ја горенаведената врска со инструкции за да овозможите поддршка за тој систем.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] е главната цел на МедијаВики и најдобро е поддржан. МедијаВики работи и со  [{{int:version-db-mysql-url}} MySQL] и [{{int:version-db-percona-url}} Percona], кои се складни со MariaDB. ([https://secure.php.net/manual/en/mysqli.installation.php Како да срочите PHP со поддршка за MySQL])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] е популарен систем на бази на податоци со отворен код кој претставува алтернатива на MySQL ([https://secure.php.net/manual/en/pgsql.installation.php како да составите PHP со поддршка за PostgreSQL]). ([https://secure.php.net/manual/en/pgsql.installation.php Како да срочите PHP со поддршка за PostgreSQL])",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] е лесен систем за бази на податоци кој е многу добро поддржан. ([https://secure.php.net/manual/en/pdo.installation.php Како да составите PHP со поддршка за SQLite], користи PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] е база на податоци на комерцијално претпријатие. ([https://secure.php.net/manual/en/oci8.installation.php Како да составите PHP со поддршка за OCI8])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server]  е база на податоци на комерцијално претпријатиe за Windows ([https://secure.php.net/manual/en/sqlsrv.installation.php How to compile PHP with SQLSRV поддршка])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] е главната цел на МедијаВики и најдобро е поддржан. МедијаВики работи и со  [{{int:version-db-mysql-url}} MySQL] и [{{int:version-db-percona-url}} Percona], кои се складни со MariaDB. ([https://www.php.net/manual/en/mysqli.installation.php Како да срочите PHP со поддршка за MySQL])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] е популарен систем на бази на податоци со отворен код кој претставува алтернатива на MySQL ([https://www.php.net/manual/en/pgsql.installation.php како да составите PHP со поддршка за PostgreSQL]). ([https://www.php.net/manual/en/pgsql.installation.php Како да срочите PHP со поддршка за PostgreSQL])",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] е лесен систем за бази на податоци кој е многу добро поддржан. ([https://www.php.net/manual/en/pdo.installation.php Како да составите PHP со поддршка за SQLite], користи PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] е база на податоци на комерцијално претпријатие. ([https://www.php.net/manual/en/oci8.installation.php Како да составите PHP со поддршка за OCI8])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server]  е база на податоци на комерцијално претпријатиe за Windows ([https://www.php.net/manual/en/sqlsrv.installation.php How to compile PHP with SQLSRV поддршка])",
        "config-header-mysql": "Нагодувања на MariaDB/MySQL",
        "config-header-postgres": "Нагодувања на PostgreSQL",
        "config-header-sqlite": "Нагодувања на SQLite",
        "config-install-done": "<strong>Честитаме!</strong>\nУспешно го воспоставивте МедијаВики.\n\nВоспоставувачот создаде податотека <code>LocalSettings.php</code>.\nТаму се содржат сите ваши нагодувања.\n\nЌе треба да ја преземете и да ја ставите во основата на воспоставката (истата папка во која се наоѓа index.php). Преземањето треба да е започнато автоматски.\n\nАко не ви е понудено преземање, или пак ако сте го откажале, можете да го почнете одново стискајќи на следнава врска:\n\n$3\n\n<strong>Напомена</strong>: Ако ова не го направите сега, податотеката со поставки повеќе нема да биде на достапна.\n\nОткога ќе завршите со тоа, можете да <strong>[$2 влезете на вашето вики]</strong>.",
        "config-install-done-path": "<strong>Честитаме!</strong>\nГо воспоставивте МедијаВики.\n\nВоспоставувачот создаде податотека <code>LocalSettings.php</code>.\nТаму се содржат сите ваши нагодувања.\n\nЌе треба да ја преземете и да ја ставите во <code>$4</code>. Преземањето треба да е започнато автоматски.\n\nАко не ви е понудено преземање, или пак ако сте го откажале, можете да го почнете одново стискајќи на следнава врска:\n\n$3\n\n<strong>Напомена</strong>: Ако ова не го направите сега, создадената податотека со поставки повеќе нема да биде на достапна, освен ако не ја преземете пред да излезете.\n\nОткога ќе завршите со тоа, можете да <strong>[$2 влезете на вашето вики]</strong>.",
        "config-install-success": "МедијаВики е успешно воспоставен. Сега можете да појдете на <$1$2> за да го погледате вашето вики.\nАко имате било какви прашања, погледајте го списокот на често поставувани прашања:\n<https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ> или појдете на еден од форумите за поддршка наведени на таа страница.",
+       "config-install-db-success": "Базата е успешно поставена",
        "config-download-localsettings": "Преземи го <code>LocalSettings.php</code>",
        "config-help": "помош",
        "config-help-tooltip": "стиснете да расклопите",
index c00382d..67d9f54 100644 (file)
@@ -52,7 +52,7 @@
        "config-outdated-sqlite": "<strong>इशारा:</strong> आपणापाशी SQLite $1 आहे, जी किमान आवश्यक आवृत्ती $2 पेक्षा, निम्न आहे. SQLite अनुपलब्ध राहील.",
        "config-memory-raised": "पीएचपीची <code>memory_limit</code> ही $1 आहे, त्यास $2 ला वाढविली.",
        "config-memory-bad": "पीएचपीची <code>memory_limit</code> ही $1 आहे.\nही बरीच खालच्या स्तरावरची आहे.\nउभारणी अयशस्वी होऊ शकते!",
-       "config-apc": "[https://secure.php.net/apc APC] उभारली आहे",
+       "config-apc": "[https://www.php.net/apc APC] उभारली आहे",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] उभारली आहे",
        "config-diff3-bad": "GNU diff3 सापडली नाही.",
        "config-git-bad": "गीट आवृत्ती नियमन संचेतन सापडली नाही.",
index 334d3a0..0318f64 100644 (file)
@@ -58,7 +58,7 @@
        "config-no-fts3": "<strong>Amaran:</strong> SQLite disusun tanpa [//sqlite.org/fts3.html modil FTS3], maka ciri-ciri pencarian tidak akan disediakan pada backend ini.",
        "config-pcre-old": "<strong>Amaran keras:</strong> PCRE $1 ke atas diperlukan.\nBinari PHP anda berpaut dengan PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Keterangan lanjut].",
        "config-memory-bad": "<strong>Amaran:</strong> <code>memory_limit</code> (Had memori) PHP ialah $1.\nIni mungkin terlalu rendah.\nPemasangan mungkin akan gagal!",
-       "config-apc": "[https://secure.php.net/apc APC] dipasang",
+       "config-apc": "[https://www.php.net/apc APC] dipasang",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] dipasang",
        "config-mod-security": "<strong>Amaran:</strong> Pelayan web anda dihidupkan [https://modsecurity.org/ mod_security]/mod_security2. Kebanyakan konfigurasinya yang umum boleh menimbulkan kesulitan untuk MediaWiki dan perisian-perisian lain yang membolehkan pengguna untuk mengeposkan kandungan yang sewenang-wenang.\nJika boleh, ciri-ciri ini harus dimatikan. Jika tidak, rujuki [https://modsecurity.org/documentation/ dokumentasi mod_security] atau hubungi bantuan hos anda jika anda menghadapi ralat sembarangan.",
        "config-diff3-bad": "GNU diff3 tidak dijumpai.",
index c64a2cd..5662f0a 100644 (file)
@@ -31,8 +31,8 @@
        "config-env-hhvm": "اچ‌اچ‌وی‌ام $1 نصب بیه.",
        "config-unicode-using-intl": "عادی یونیکد وسه [https://pecl.php.net/intl افزونهٔ intl برای PECL] جه استفاده هاکن.",
        "config-memory-raised": "PHP's <code>memory_limit</code>, نسخهٔ $1 هسته، ونه نسخهٔ $2 ره بَیری آپگریت هاکنی.",
-       "config-apc": "[https://secure.php.net/apc APC] نصب بیه.",
-       "config-apcu": "[https://secure.php.net/apcu APCu] نصب بیه.",
+       "config-apc": "[https://www.php.net/apc APC] نصب بیه.",
+       "config-apcu": "[https://www.php.net/apcu APCu] نصب بیه.",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] نصب بیه.",
        "config-diff3-bad": "GNU diff3 پیدا نیه.",
        "config-mssql-auth": "نوع تأیید:",
index 8183ed7..d4dc4b6 100644 (file)
        "config-pcre-no-utf8": "<strong>Fatale:</strong> 'E module PCRE d' 'o PHP pare ca se so' compilate senza PCRE_UTF8 supporto.\nA MediaWiki serve nu supporto UTF-8 pe' putè funziunà apposto.",
        "config-memory-raised": "'O valore 'e PHP <code>memory_limit</code> è $1, aumentato a $2.",
        "config-memory-bad": "<strong>Attenziò:</strong> 'o valore 'e PHP <code>memory_limit</code> è $1.\nProbabbilmente troppo basso.\n'A installazione se putesse scassà!",
-       "config-apc": "[https://secure.php.net/apc APC] è installato",
-       "config-apcu": "[https://secure.php.net/apcu APCu] è installato",
+       "config-apc": "[https://www.php.net/apc APC] è installato",
+       "config-apcu": "[https://www.php.net/apcu APCu] è installato",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] è installato",
-       "config-no-cache-apcu": "<strong>Attenziò:</strong> [https://secure.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] o [https://www.iis.net/downloads/microsoft/wincache-extension WinCache] nun so' state truvate.\n'A funziona caching 'e ll'oggette non è apicciata.",
+       "config-no-cache-apcu": "<strong>Attenziò:</strong> [https://www.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] o [https://www.iis.net/downloads/microsoft/wincache-extension WinCache] nun so' state truvate.\n'A funziona caching 'e ll'oggette non è apicciata.",
        "config-mod-security": "<strong>Attenziò:</strong> 'O servitore web vuosto téne [https://modsecurity.org/ mod_security]/mod_security2 appicciato. Ce stanno tante mpustaziune commune ca 'o facessero causà prubbleme a MediaWiki e ll'ati software ca permettessero ll'utente 'e pubbrecà cuntenute.\nSi putite, stutate sta funziona. Sinò, riferite 'a [https://modsecurity.org/documentation/ documentaziona ncopp' 'o mod_security] o cuntattate 'o host vuosto pe' ve dà supporto quanno se scummogliasse cocch'errore.",
        "config-diff3-bad": "GNU diff3 nun truvato.",
        "config-git": "Truvato software 'e cuntrollo d' 'a verziona Git: <code>$1</code>.",
        "config-type-mysql": "MariaDB, MySQL o compatibbele",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki supporta 'e sisteme 'e database ccà abbascio:\n\n$1\n\nSi nfra chiste ccà nun vedite 'o sistema 'e database ca vulite ausà, allora avite liegge 'e instruziune ccà ncoppa pe' ne dà supporto.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] è 'a configurazione cchiù mmeglio p' 'o MediaWiki e è chilla meglio suppurtata. MediaWiki può faticà pure cu' [{{int:version-db-mariadb-url}} MariaDB] e [{{int:version-db-percona-url}} Percona Server], ca fossero MariaDB cumpatibbele. ([https://secure.php.net/manual/en/mysqli.installation.php Comme s'adda fà pe' cumpilà PHP cu suppuorto MySQL])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] è nu sistema canusciuto 'e database open source ca fosse n'alternativa a MySQL.\n([https://secure.php.net/manual/en/pgsql.installation.php Comme s'avess'a cumpilà PHP cu suppuorto PostgreSQL])",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite]  è nu sistema 'e database leggero, ca fosse assaje buono suppurtato.\n([https://secure.php.net/manual/en/pdo.installation.php Comme cumpilà PHP cu suppuorto SQLite], aùsa PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] è nu database 'e na fraveca commerciale. ([https://secure.php.net/manual/en/oci8.installation.php Comme cumpilà PHP cu suppuorto OCI8])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] è nu database 'e na fraveca commerciale p' 'o Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php Comme cumpilà PHP cu suppuorto SQLSRV])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] è 'a configurazione cchiù mmeglio p' 'o MediaWiki e è chilla meglio suppurtata. MediaWiki può faticà pure cu' [{{int:version-db-mariadb-url}} MariaDB] e [{{int:version-db-percona-url}} Percona Server], ca fossero MariaDB cumpatibbele. ([https://www.php.net/manual/en/mysqli.installation.php Comme s'adda fà pe' cumpilà PHP cu suppuorto MySQL])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] è nu sistema canusciuto 'e database open source ca fosse n'alternativa a MySQL.\n([https://www.php.net/manual/en/pgsql.installation.php Comme s'avess'a cumpilà PHP cu suppuorto PostgreSQL])",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite]  è nu sistema 'e database leggero, ca fosse assaje buono suppurtato.\n([https://www.php.net/manual/en/pdo.installation.php Comme cumpilà PHP cu suppuorto SQLite], aùsa PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] è nu database 'e na fraveca commerciale. ([https://www.php.net/manual/en/oci8.installation.php Comme cumpilà PHP cu suppuorto OCI8])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] è nu database 'e na fraveca commerciale p' 'o Windows. ([https://www.php.net/manual/en/sqlsrv.installation.php Comme cumpilà PHP cu suppuorto SQLSRV])",
        "config-header-mysql": "Mpustaziune MariaDB/MySQL",
        "config-header-postgres": "Mpustaziune PostgreSQL",
        "config-header-sqlite": "Mpustaziune SQLite",
index fef5391..8dec566 100644 (file)
        "config-pcre-no-utf8": "'''Fatal''': PHPs PCRE modul ser ut til å være kompilert uten PCRE_UTF8-støtte.\nMediaWiki krever UTF-8-støtte for å fungere riktig.",
        "config-memory-raised": "PHPs <code>memory_limit</code> er $1, økt til $2.",
        "config-memory-bad": "'''Advarsel:''' PHPs <code>memory_limit</code> er $1.\nDette er sannsynligvis for lavt.\nInstallasjonen kan mislykkes!",
-       "config-apc": "[https://secure.php.net/apc APC] er installert",
-       "config-apcu": "[https://secure.php.net/apcu APCu] er installert",
+       "config-apc": "[https://www.php.net/apc APC] er installert",
+       "config-apcu": "[https://www.php.net/apcu APCu] er installert",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] er installert",
-       "config-no-cache-apcu": "<strong>Advarsel:</strong> Kunne ikke finne [https://secure.php.net/apcu APCu] eller [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nObjekthurtiglagring er ikke aktivert.",
+       "config-no-cache-apcu": "<strong>Advarsel:</strong> Kunne ikke finne [https://www.php.net/apcu APCu] eller [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nObjekthurtiglagring er ikke aktivert.",
        "config-mod-security": "'''Advarsel''': Din web-tjener har [https://modsecurity.org/ mod_security] påslått. Hvis denne er feilinnstilt, kan det gi problemer for MediaWiki eller annen programvare som tillater brukere å poste vilkårlig innhold.\nSjekk [https://modsecurity.org/documentation/ mod_security-dokumentasjonen] eller ta kontakt med din nettleverandør hvis du opplever tilfeldige feil.",
        "config-diff3-bad": "GNU diff3 ikke funnet.",
        "config-git": "Har funnet Git version control software: <code>$1</code>.",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQLServer",
        "config-support-info": "MediaWiki støtter følgende databasesystem:\n\n$1\n\nHvis du ikke ser databasesystemet du prøver å bruke i listen nedenfor, følg instruksjonene det er lenket til over for å aktivere støtte.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] er den foretrukne databasetypen for MediaWiki og har best støtte.  MediaWiki fungerer også med [{{int:version-db-mysql-url}} MySQL] og [{{int:version-db-percona-url}} Percona Server], som begge er MariaDB-kompatible. ([https://secure.php.net/manual/en/mysqli.installation.php Hvordan kompilere PHP med MySQL-støtte])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] er et populært åpen kildekode-databasesystem og et alternativ til MySQL.  ([https://secure.php.net/manual/en/pgsql.installation.php Hvordan kompilere PHP med PostgreSQL-støtte])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] er den foretrukne databasetypen for MediaWiki og har best støtte.  MediaWiki fungerer også med [{{int:version-db-mysql-url}} MySQL] og [{{int:version-db-percona-url}} Percona Server], som begge er MariaDB-kompatible. ([https://www.php.net/manual/en/mysqli.installation.php Hvordan kompilere PHP med MySQL-støtte])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] er et populært åpen kildekode-databasesystem og et alternativ til MySQL.  ([https://www.php.net/manual/en/pgsql.installation.php Hvordan kompilere PHP med PostgreSQL-støtte])",
        "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] er et lettvekts-databasesystem som har veldig god støtte. ([http://www.php.net/manual/en/pdo.installation.php Hvordan kompilere PHP med SQLite-støtte], bruker PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] er en kommersiell database for bedrifter. ([https://secure.php.net/manual/en/oci8.installation.php Hvordan kompilere PHP med OCI8-støtte])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] er et kommersielt databasesystem under Windows for bedrifter. ([https://secure.php.net/manual/en/sqlsrv.installation.php Hvordan kompilere PHP med SQLSRV-støtte])",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] er en kommersiell database for bedrifter. ([https://www.php.net/manual/en/oci8.installation.php Hvordan kompilere PHP med OCI8-støtte])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] er et kommersielt databasesystem under Windows for bedrifter. ([https://www.php.net/manual/en/sqlsrv.installation.php Hvordan kompilere PHP med SQLSRV-støtte])",
        "config-header-mysql": "MariadB/MySQL-innstillinger",
        "config-header-postgres": "PostgreSQL-innstillinger",
        "config-header-sqlite": "SQLite-innstillinger",
        "config-license-help": "Mange åpne wikier legger alle bidrag under en [https://freedomdefined.org/Definition gratislisens].\nDette gir en følelse av felleseie og stimulerer til langvarige bidrag.\nDette er normalt unødvendig for en privat eller virksomhetsbegrenset wiki.\n\nHvis du ønsker å kunne bruke tekst fra Wikipedia, og at Wikipedia skal kunne ta i mot tekst kopiert fra din wiki, bør du velge <strong>{{int:config-license-cc-by-sa}}</strong>.\n\nWikipedia brukte tidligere GNU Free Documentation License.\nGFDL er en grei lisens, med vanskelig å forstå.\nDet er også vanskelig å gjenbruke innhold lisensiert under GFDL.",
        "config-email-settings": "E-postinnstillinger",
        "config-enable-email": "Aktiver utgående e-post",
-       "config-enable-email-help": "Hvis du vil at e-post skal virke, må [https://secure.php.net/manual/en/mail.configuration.php PHPs epostinnstillinger] konfigureres riktig.\nHvis du ikke ønsker noen epostfunksjoner, kan du deaktivere dem her.",
+       "config-enable-email-help": "Hvis du vil at e-post skal virke, må [https://www.php.net/manual/en/mail.configuration.php PHPs epostinnstillinger] konfigureres riktig.\nHvis du ikke ønsker noen epostfunksjoner, kan du deaktivere dem her.",
        "config-email-user": "Aktiver e-post mellom brukere",
        "config-email-user-help": "Tillat alle brukere å sende hverandre e-post hvis de har aktivert det i deres innstillinger.",
        "config-email-usertalk": "Aktiver brukerdiskusjonssidevarsler",
index 54f743d..a12445c 100644 (file)
        "config-pcre-no-utf8": "<strong>Onherstelbare fout:</strong> de module PRCE van PHP lijkt te zijn gecompileerd zonder ondersteuning voor PCRE_UTF8.\nMediaWiki heeft ondersteuning voor UTF-8 nodig om correct te kunnen werken.",
        "config-memory-raised": "PHP's <code>memory_limit</code> is $1 en is verhoogd tot $2.",
        "config-memory-bad": "'''Waarschuwing:''' PHP's <code>memory_limit</code> is $1.\nDit is waarschijnlijk te laag.\nDe installatie kan mislukken!",
-       "config-apc": "[https://secure.php.net/apc APC] is op dit moment geïnstalleerd",
-       "config-apcu": "[https://secure.php.net/apcu APCu] is geïnstalleerd",
+       "config-apc": "[https://www.php.net/apc APC] is op dit moment geïnstalleerd",
+       "config-apcu": "[https://www.php.net/apcu APCu] is geïnstalleerd",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] is op dit moment geïnstalleerd",
-       "config-no-cache-apcu": "<strong>Waarschuwing:</strong> [https://secure.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] of [https://www.iis.net/downloads/microsoft/wincache-extension WinCache] is niet aangetroffen.\nHet cachen van objecten is niet ingeschakeld.",
+       "config-no-cache-apcu": "<strong>Waarschuwing:</strong> [https://www.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] of [https://www.iis.net/downloads/microsoft/wincache-extension WinCache] is niet aangetroffen.\nHet cachen van objecten is niet ingeschakeld.",
        "config-mod-security": "<strong>Waarschuwing:</strong> Uw webserver heeft de module [https://modsecurity.org/ mod_security]/mod_security2 ingeschakeld. Veel standaard instellingen hiervan zorgen voor problemen in combinatie met MediaWiki en andere software die gebruikers in staat stelt willekeurige inhoud te posten.\nIndien mogelijk, zou deze moeten worden uitgeschakeld. Lees anders de [https://modsecurity.org/documentation/ documentatie over mod_security] of neem contact op met de helpdesk van uw provider als u tegen problemen aanloopt.",
        "config-diff3-bad": "GNU diff3 niet aangetroffen. U kunt dit voorlopig negeren, maar bewerkingsconflicten kunnen vaker voorkomen.",
        "config-git": "Versiecontrolesoftware git is aangetroffen: <code>$1</code>",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki ondersteunt de volgende databasesystemen:\n\n$1\n\nAls u het databasesysteem dat u wilt gebruiken niet in de lijst terugvindt, volg dan de handleiding waarnaar hierboven wordt verwezen om ondersteuning toe te voegen.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] is de primaire database voor MediaWiki en wordt het best ondersteund. MediaWiki werkt ook met [{{int:version-db-mysql-url}} MySQL] en [{{int:version-db-percona-url}} Percona Server], die MariaDB-compatibel zijn ([https://secure.php.net/manual/en/mysqli.installation.php hoe PHP te compileren met MySQL-ondersteuning]).",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] is een populair open source databasesysteem als alternatief voor MySQL.([https://secure.php.net/manual/en/pgsql.installation.php Hoe u PHP kunt compileren met ondersteuning voor PostgreSQL])",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] is een zeer goed ondersteund lichtgewicht databasesysteem ([https://secure.php.net/manual/en/pdo.installation.php hoe PHP gecompileerd moet zijn met ondersteuning voor SQLite]; gebruikt PDO).",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] is een commerciële database voor grote bedrijven ([https://secure.php.net/manual/en/oci8.installation.php PHP compileren met ondersteuning voor OCI8]).",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] is een commerciële enterprisedatabase voor Windows ([https://secure.php.net/manual/en/sqlsrv.installation.php PHP compileren met ondersteuning voor SQLSRV]).",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] is de primaire database voor MediaWiki en wordt het best ondersteund. MediaWiki werkt ook met [{{int:version-db-mysql-url}} MySQL] en [{{int:version-db-percona-url}} Percona Server], die MariaDB-compatibel zijn ([https://www.php.net/manual/en/mysqli.installation.php hoe PHP te compileren met MySQL-ondersteuning]).",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] is een populair open source databasesysteem als alternatief voor MySQL.([https://www.php.net/manual/en/pgsql.installation.php Hoe u PHP kunt compileren met ondersteuning voor PostgreSQL])",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] is een zeer goed ondersteund lichtgewicht databasesysteem ([https://www.php.net/manual/en/pdo.installation.php hoe PHP gecompileerd moet zijn met ondersteuning voor SQLite]; gebruikt PDO).",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] is een commerciële database voor grote bedrijven ([https://www.php.net/manual/en/oci8.installation.php PHP compileren met ondersteuning voor OCI8]).",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] is een commerciële enterprisedatabase voor Windows ([https://www.php.net/manual/en/sqlsrv.installation.php PHP compileren met ondersteuning voor SQLSRV]).",
        "config-header-mysql": "MariaDB/MySQL-instellingen",
        "config-header-postgres": "PostgreSQL-instellingen",
        "config-header-sqlite": "SQLite-instellingen",
        "config-license-help": "In veel openbare wiki's zijn alle bijdragen beschikbaar onder een [https://freedomdefined.org/Definition vrije licentie].\nDit helpt bij het creëren van een gevoel van gemeenschappelijk eigendom en stimuleert bijdragen op lange termijn.\nDit is over het algemeen niet nodig is voor een particuliere of zakelijke wiki.\n\nAls u teksten uit Wikipedia wilt kunnen gebruiken en u wilt het mogelijk maken teksten uit uw wiki naar Wikipedia te kopiëren, kies dan de licentie <strong>{{int:config-license-cc-by-sa}}</strong>.\n\nDe GNU Free Documentation License is de oude licentie voor inhoud uit Wikipedia.\nDit is nog steeds een geldige licentie, maar deze licentie is lastig te begrijpen.\nHet is ook lastig inhoud te hergebruiken onder de GFDL.",
        "config-email-settings": "E-mailinstellingen",
        "config-enable-email": "Uitgaande e-mail inschakelen",
-       "config-enable-email-help": "Als u wilt dat e-mailen mogelijk is, dan moeten de [https://secure.php.net/manual/en/mail.configuration.php e-mailinstellingen van PHP] correct zijn.\nAls u niet wilt dat e-mailen mogelijk is, dan kunt u de instellingen hier uitschakelen.",
+       "config-enable-email-help": "Als u wilt dat e-mailen mogelijk is, dan moeten de [https://www.php.net/manual/en/mail.configuration.php e-mailinstellingen van PHP] correct zijn.\nAls u niet wilt dat e-mailen mogelijk is, dan kunt u de instellingen hier uitschakelen.",
        "config-email-user": "E-mail tussen gebruikers inschakelen",
        "config-email-user-help": "Gebruikers toestaan e-mail aan elkaar te verzenden als dit in de voorkeuren is ingesteld.",
        "config-email-usertalk": "Gebruikersoverlegmeldingen inschakelen",
        "config-install-done": "<strong>Gefeliciteerd!</strong>\nU hebt MediaWiki geïnstalleerd.\n\nHet installatieprogramma heeft het bestand <code>LocalSettings.php</code> aangemaakt.\nDit bevat al uw instellingen.\n\nU moet het bestand downloaden en in de hoofdmap van uw wiki-installatie plaatsen, in dezelfde map als index.php.\nDe download zou automatisch moeten zijn gestart.\n\nAls de download niet is gestart of als u de download hebt geannuleerd, dan kunt u de download opnieuw starten door op de onderstaande koppeling te klikken:\n\n$3\n\n<strong>Let op:</strong> als u dit niet nu doet, dan is het bestand als u later de installatieprocedure afsluit zonder het bestand te downloaden niet meer beschikbaar.\n\nNa het plaatsen van het bestand met instellingen kunt u <strong>[$2 uw wiki gebruiken]</strong>.",
        "config-install-done-path": "<strong>Gefeliciteerd!</strong>\nU hebt MediaWiki geïnstalleerd.\n\nHet installatieprogramma heeft het bestand <code>LocalSettings.php</code> aangemaakt.\nDit bevat al uw instellingen.\n\nU moet het bestand downloaden en in <code>$4</code> plaatsen. De download zou automatisch moeten zijn gestart.\n\nAls de download niet is gestart of als u de download hebt geannuleerd, dan kunt u de download opnieuw starten door op de onderstaande koppeling te klikken:\n\n$3\n\n<strong>Let op:</strong> Als u dit niet nu doet, dan is het bestand als u later de installatieprocedure afsluit zonder het bestand te downloaden niet meer beschikbaar.\n\nNa het plaatsen van het bestand met instellingen kunt u <strong>[$2 uw wiki gebruiken]</strong>.",
        "config-install-success": "MediaWiki is geïnstalleerd. U kunt nu\n<$1$2> bezoeken om uw wiki te bekijken.\nAls u vragen hebt, bekijk dan onze lijst met veelgestelde vragen:\n<https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ>, of gebruik een van de hulpforums vermeld op die pagina.",
+       "config-install-db-success": "Het installeren van de database is geslaagd",
        "config-download-localsettings": "<code>LocalSettings.php</code> downloaden",
        "config-help": "hulp",
        "config-help-tooltip": "klik om uit te vouwen",
index e88aec2..7a99bb8 100644 (file)
@@ -42,7 +42,7 @@
        "config-env-hhvm": "HHVM $1 es installat.",
        "config-unicode-using-intl": "Utilizacion de [https://pecl.php.net/intl l'extension PECL intl] per la normalizacion Unicode.",
        "config-memory-raised": "Lo paramètre <code>memory_limit</code> de PHP èra a $1, portat a $2.",
-       "config-apc": "[https://secure.php.net/apc APC] es installat",
+       "config-apc": "[https://www.php.net/apc APC] es installat",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] es installat",
        "config-diff3-bad": "GNU diff3 pas trobat.",
        "config-git": "Logicial de contraròtle de version Git trobat : <code>$1</code>.",
index dd24138..6a518c7 100644 (file)
@@ -2,7 +2,8 @@
        "@metadata": {
                "authors": [
                        "Mashoi7",
-                       "Ilja.mos"
+                       "Ilja.mos",
+                       "Pyscowicz"
                ]
        },
        "config-your-language": "Sinun kieli:",
@@ -28,7 +29,7 @@
        "config-db-username": "Tiedokannan käyttäinimi:",
        "config-db-password": "Tiedokannan salasana:",
        "config-type-mssql": "Microsoft SQL Server",
-       "config-header-mysql": "MySQL-azetukset",
+       "config-header-mysql": "MariaDB/MySQL-azetukset",
        "config-header-postgres": "PostgreSQL-azetukset",
        "config-header-sqlite": "SQLite-azetukset",
        "config-header-oracle": "Oracle-azetukset",
index 0efcc11..41da9dc 100644 (file)
        "config-pcre-no-utf8": "'''Błąd krytyczny''' – wydaje się, że moduł PCRE w PHP został skompilowany bez wsparcia dla UTF‐8.\nMediaWiki wymaga wsparcia dla UTF‐8 do prawidłowego działania.",
        "config-memory-raised": "PHP <code>memory_limit</code> było ustawione na $1, zostanie zwiększone do $2.",
        "config-memory-bad": "'''Uwaga:''' PHP <code>memory_limit</code> jest ustawione na $1.\nTo jest prawdopodobnie zbyt mało.\nInstalacja może się nie udać!",
-       "config-apc": "[https://secure.php.net/apc APC] jest zainstalowany",
-       "config-apcu": "[https://secure.php.net/apcu APCu] jest zainstalowany",
+       "config-apc": "[https://www.php.net/apc APC] jest zainstalowany",
+       "config-apcu": "[https://www.php.net/apcu APCu] jest zainstalowany",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] jest zainstalowany",
-       "config-no-cache-apcu": "<strong>Ostrzeżenie:</strong> Nie można było znaleźć [https://secure.php.net/apcu APCu] ani [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nPamięć podręczna obiektów nie została włączona.",
+       "config-no-cache-apcu": "<strong>Ostrzeżenie:</strong> Nie można było znaleźć [https://www.php.net/apcu APCu] ani [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nPamięć podręczna obiektów nie została włączona.",
        "config-mod-security": "''' Ostrzeżenie ''': Serwer sieci web ma włączone [https://modsecurity.org/ mod_security]. Jeśli jest niepoprawnie skonfigurowane, może być przyczyną problemów MediaWiki lub innego oprogramowania, które pozwala użytkownikom na wysyłanie dowolnej zawartości.\nSprawdź w [https://modsecurity.org/documentation/ dokumentacji mod_security] lub skontaktuj się z obsługa hosta, jeśli wystąpią losowe błędy.",
        "config-diff3-bad": "Nie znaleziono funkcjonalności porównywania tekstu GNU diff3. Możesz zignorować ten komunikat, jednak konflikty edycji będą wówczas częstsze.",
        "config-git": "Znaleziono oprogramowanie kontroli wersji Git: <code>$1</code>.",
        "config-type-mysql": "MariaDB, MySQL lub kompatybilna",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki może współpracować z następującymi systemami baz danych:\n\n$1\n\nPoniżej wyświetlone są systemy baz danych gotowe do użycia. Jeżeli poniżej brakuje bazy danych, z której chcesz skorzystać, oznacza to, że brakuje odpowiedniego oprogramowania lub zostało ono niepoprawnie skonfigurowane. Powyżej znajdziesz odnośniki do dokumentacji, która pomoże w konfiguracji odpowiednich komponentów.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] jest bazą danych, na której rozwijane jest oprogramowanie MediaWiki. MediaWiki działa również z [{{int:version-db-mysql-url}} MySQL] i [{{int:version-db-percona-url}} Percona Server], które są zgodne z MariaDB. ([https://secure.php.net/manual/en/mysqli.installation.php Zobacz, jak skompilować PHP ze wsparciem dla MySQL])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] jest popularnym, otawrtym systemem baz danych, często stosowanym jako alternatywa dla MySQL. ([https://secure.php.net/manual/en/pgsql.installation.php Zobacz, jak skompilować PHP z obsługą PostgreSQL])",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] jest niewielkim systemem bazy danych, z którym MediaWiki bardzo dobrze współpracuje. ([https://secure.php.net/manual/pl/pdo.installation.php Zobacz, jak skompilować PHP ze wsparciem dla SQLite], korzystając z PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] jest komercyjną profesjonalną bazą danych. ([https://secure.php.net/manual/pl/oci8.installation.php Jak skompilować PHP ze wsparciem dla OCI8])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] jest komercyjną profesjonalną bazą danych. ([https://secure.php.net/manual/pl/sqlsrv.installation.php Jak skompilować PHP ze wsparciem dla SQLSRV])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] jest bazą danych, na której rozwijane jest oprogramowanie MediaWiki. MediaWiki działa również z [{{int:version-db-mysql-url}} MySQL] i [{{int:version-db-percona-url}} Percona Server], które są zgodne z MariaDB. ([https://www.php.net/manual/en/mysqli.installation.php Zobacz, jak skompilować PHP ze wsparciem dla MySQL])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] jest popularnym, otawrtym systemem baz danych, często stosowanym jako alternatywa dla MySQL. ([https://www.php.net/manual/en/pgsql.installation.php Zobacz, jak skompilować PHP z obsługą PostgreSQL])",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] jest niewielkim systemem bazy danych, z którym MediaWiki bardzo dobrze współpracuje. ([https://www.php.net/manual/pl/pdo.installation.php Zobacz, jak skompilować PHP ze wsparciem dla SQLite], korzystając z PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] jest komercyjną profesjonalną bazą danych. ([https://www.php.net/manual/pl/oci8.installation.php Jak skompilować PHP ze wsparciem dla OCI8])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] jest komercyjną profesjonalną bazą danych. ([https://www.php.net/manual/pl/sqlsrv.installation.php Jak skompilować PHP ze wsparciem dla SQLSRV])",
        "config-header-mysql": "Ustawienia MariaDB/MySQL",
        "config-header-postgres": "Ustawienia PostgreSQL",
        "config-header-sqlite": "Ustawienia SQLite",
        "config-license-help": "Wiele publicznych wiki umieszcza wszystkie dopisane treści na [https://freedomdefined.org/Definition wolnej licencji].\nPomaga to tworzyć poczucie wspólnoty i zachęca do długoterminowego wkładu.\nNie jest to zazwyczaj konieczne w prywatnych lub firmowych wiki.\n\nJeśli chcesz móc użyć tekstu z Wikipedii i chcesz Wikipedia mogła zaakceptować tekst skopiowany z twojej wiki, należy wybrać <strong>{{int:config-license-cc-by-sa}}</strong>.\n\nWikipedia używała poprzednio GNU Free Documentation License.\nGFDL jest poprawną licencję, ale trudno ją zrozumieć.\nTrudno także ponowne użyć zawartości na licencji GFDL.",
        "config-email-settings": "Ustawienia e-maili",
        "config-enable-email": "Włącz wychodzące wiadomości e–mail",
-       "config-enable-email-help": "Jeśli chcesz, aby działał e-mail, [https://secure.php.net/manual/pl/mail.configuration.php Ustawienia poczty PHP] muszą być poprawnie wprowadzone.\nJeśli nie chcesz jakichś funkcji poczty e-mail, można je wyłączyć tutaj.",
+       "config-enable-email-help": "Jeśli chcesz, aby działał e-mail, [https://www.php.net/manual/pl/mail.configuration.php Ustawienia poczty PHP] muszą być poprawnie wprowadzone.\nJeśli nie chcesz jakichś funkcji poczty e-mail, można je wyłączyć tutaj.",
        "config-email-user": "Włącz możliwość przesyłania e‐maili pomiędzy użytkownikami",
        "config-email-user-help": "Zezwalaj użytkownikom na wysyłanie wzajemnie e‐maili, jeśli będą mieć włączoną tę funkcję w swoich preferencjach.",
        "config-email-usertalk": "Włącz powiadamianie o zmianach na stronie dyskusji użytkownika",
        "config-install-done": "<strong>'''Gratulacje!</strong>\nUdało Ci się zainstalować MediaWiki.\n\nInstalator wygenerował plik konfiguracyjny <code>LocalSettings.php</code>.\n\nMusisz go pobrać i umieścić w katalogu głównym Twojej instalacji wiki (tym samym katalogu co index.php). Pobieranie powinno zacząć się automatycznie.\n\nJeżeli pobieranie nie zostało zaproponowane lub jeśli użytkownik je anulował, można ponownie uruchomić pobranie klikając poniższe łącze:\n\n$3\n\n<strong>Uwaga</strong>: Jeśli nie zrobisz tego teraz, wygenerowany plik konfiguracyjny nie będzie już dostępny po zakończeniu instalacji.\n\nPo załadowaniu pliku konfiguracyjnego możesz <strong>[$2 wejść na wiki]</strong>.",
        "config-install-done-path": "<strong>Gratulacje!</strong>\nZainstalowałeś właśnie MediaWiki.\n\nInstalator wygenerował plik <code>LocalSettings.php</code>.\nZawiera całą Twoją konfigurację.\n\nMusisz go pobrać i umieścić w <code>$4</code>. Pobieranie powinno rozpocząć się automatycznie.\n\nJeżeli nie pojawiła się informacja o pobieraniu lub jeżeli ja anulowałeś, kliknij poniższy link:\n\n$3\n\n<strong>Uwaga:</strong> Jeżeli nie zrobisz tego teraz, wygenerowany plik konfiguracyjny nie będzie potem dostępny, jeżeli wyjdziesz z instalacji bez jego pobrania.\n\nGdy to będzie zrobione, możesz <strong>[$2 wejść na swoją wiki]</strong>.",
        "config-install-success": "MediaWiki została pomyślnie zainstalowana. Możesz teraz\nodwiedzić <$1$2>, aby zobaczyć swoją wiki.\nJeśli masz pytania, sprawdź naszą listę najczęściej zadawanych pytań:\n<https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ> lub użyj jednej z\nform wsparcia odsyłanej z tej strony.",
+       "config-install-db-success": "Baza danych została pomyślnie utworzona",
        "config-download-localsettings": "Pobierz <code>LocalSettings.php</code>",
        "config-help": "pomoc",
        "config-help-tooltip": "kliknij, aby rozwinąć",
index 131e06f..130d507 100644 (file)
@@ -7,7 +7,8 @@
                        "아라",
                        "Amire80",
                        "Macofe",
-                       "Seb35"
+                       "Seb35",
+                       "MaxSem"
                ]
        },
        "config-desc": "L'instalador për mediaWiki",
@@ -62,7 +63,7 @@
        "config-pcre-no-utf8": "'''Fatal''': ël mòdul PCRE ëd PHP a smija esse compilà sensa l'apògg PCRE_UTF8.\nMediaWiki a ciama l'apògg d'UTF8 për marcé për da bin.",
        "config-memory-raised": "<code>memory_limit</code> ëd PHP a l'é $1, aussà a $2.",
        "config-memory-bad": "'''Avis:''' <code>memory_limit</code> ëd PHP a l'é $1.\nSossì a l'é probabilment tròp bass.\nL'instalassion a peul falì!",
-       "config-apc": "[https://secure.php.net/apc APC] a l'é instalà",
+       "config-apc": "[https://www.php.net/apc APC] a l'é instalà",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache]  a l'é instalà",
        "config-mod-security": "'''Avis''': Sò servent për l'aragnà a l'ha [https://modsecurity.org/ mod_security] abilità. Se mal configurà, a peul causé dij problema për MediaWiki o d'àutri programa ch'a përmëtto a j'utent dë spedì un contnù qualsëssìa.\nCh'a fasa arferiment a la [https://modsecurity.org/documentation/ mod_security documentassion] o ch'a contata l'echip ëd sò servissi s'a-j rivo dj'eror casuaj.",
        "config-diff3-bad": "GNU diff3 pa trovà.",
@@ -76,7 +77,7 @@
        "config-uploads-not-safe": "'''Avis:''' Sò dossié stàndard për carié <code>$1</code> a l'é vulneràbil a l'esecussion ëd qualsëssìa senari.\nBele che MediaWiki a contròla j'aspet ëd sicurëssa ëd tùit j'archivi carià, a l'é motobin arcomandà ëd [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security#Upload_security saré ës përtus ëd sicurëssa] prima d'abilité ij cariament.",
        "config-no-cli-uploads-check": "'''Avis:''' Toa cartela predefinìa për j-amportassion (<code>$1</code>) a l'é nen controlà a propòsit ëd la vulnerabilità\nd'esecussion ëd senari arbitrari durant l'istalassion CLI.",
        "config-brokenlibxml": "Sò sistema a l'ha na combinassion ëd version PHP e libxml2 che a l'ha dij bigat e a peul provoché la corussion ëd dat ëstërmà an MediaWiki e d'àutre aplicassion për l'aragnà.\nCh'a agiorna a PHP 5.2.9 o pi neuv e libxml2 2.7.3 o pi neuv ([https://bugs.php.net/bug.php?id=45996 bigat archivià con PHP]).\nAnstalassion abortìa.",
-       "config-suhosin-max-value-length": "Suhosin a l'é instalà e a lìmita la longheur dël paràmetr GET a $1 byte. Ël component ResourceLoader ëd MediaWiki a travajerà an rispetand ës lìmit, ma sòn a degraderà le prestassion. Se possìbil, a dovrìa amposté suhosin.get.max_value_lenght a 1024 o pi àut an <code>php.ini</code>, e amposté <code>$wgResourceLoaderMaxQueryLength</code> al midem valor an LocalSettings.php .",
+       "config-suhosin-max-value-length": "Suhosin a l'é instalà e a lìmita la <code>longheur</code> dël paràmetr GET a $1 byte. Ël component ResourceLoader ëd MediaWiki a travajerà an rispetand ës lìmit, ma sòn a degraderà le prestassion. Se possìbil, a dovrìa amposté <code>suhosin.get.max_value_length</code> a 1024 o pi àut an <code>php.ini</code>, e amposté <code>$wgResourceLoaderMaxQueryLength</code> al midem valor an <code>LocalSettings.php</code>.",
        "config-db-type": "Sòrt ëd base ëd dàit:",
        "config-db-host": "Ospitant ëd la base ëd dàit:",
        "config-db-host-help": "Se sò servent ëd base ëd dàit a l'é su un servent diferent, ch'a anserissa ambelessì ël nòm dl'ospitant o l'adrëssa IP.\n\nS'a deuvra n'ospitalità partagià, sò fornidor d'ospitalità a dovrìa deje ël nòm dl'ospitant giust ant soa documentassion.\n\nSe a anstala su un servent Windows e a deuvra MySQL, dovré «localhost» a podrìa funsioné nen com nòm dël servent. S'a marcia nen, ch'a preuva «127.0.0.1» com adrëssa IP local.\n\nS'a deuvra PostgresSQL, ch'a lassa sto camp bianch për coleghesse a travers un socket UNIX.",
        "config-oracle-def-ts": "Spassi dla tàula dë stàndard:",
        "config-oracle-temp-ts": "Spassi dla tàula temporani:",
        "config-support-info": "MediaWiki a manten ij sistema ëd base ëd dàit sì-dapress:\n\n$1\n\nS'a vëd pa listà sì-sota ël sistema ëd base ëd dàit ch'a preuva a dovré, antlora va andaré a j'istrussion dl'anliura sì-dzora për abilité ël manteniment.",
-       "config-dbsupport-mysql": "* $1 e l'é l'obietiv primari për MediaWiki e a l'é mej mantnù ([https://secure.php.net/manual/en/mysql.installation.php com compilé PHP con ël manteniment MySQL])",
-       "config-dbsupport-postgres": "* $1 e l'é un sistema ëd base ëd dàit popolar a sorgiss duverta com alternativa a MySQL ([https://secure.php.net/manual/en/pgsql.installation.php com compilé PHP con ël manteniment ëd PostgreSQL]). A peulo ess-ie chèich cit bigat, e a l'é nen arcomandà ëd dovrelo an n'ambient ëd produssion.",
+       "config-dbsupport-mysql": "* $1 e l'é l'obietiv primari për MediaWiki e a l'é mej mantnù ([https://www.php.net/manual/en/mysql.installation.php com compilé PHP con ël manteniment MySQL])",
+       "config-dbsupport-postgres": "* $1 e l'é un sistema ëd base ëd dàit popolar a sorgiss duverta com alternativa a MySQL ([https://www.php.net/manual/en/pgsql.installation.php com compilé PHP con ël manteniment ëd PostgreSQL]). A peulo ess-ie chèich cit bigat, e a l'é nen arcomandà ëd dovrelo an n'ambient ëd produssion.",
        "config-dbsupport-sqlite": "* $1 e l'é un sistema ëd base ëd dàit leger che a l'é motobin bin mantnù ([http://www.php.net/manual/en/pdo.installation.php com compilé PHP con ël manteniment ëd SQLite], a deuvra PDO)",
        "config-dbsupport-oracle": "* $1 a l'é na base ëd dàit comersial për j'amprèise. ([http://www.php.net/manual/en/oci8.installation.php Com compilé PHP con ël manteniment OCI8])",
        "config-header-mysql": "Ampostassion MySQL",
index 840c449..632813c 100644 (file)
@@ -30,7 +30,7 @@
        "config-restart": "هو، سر له نوي يې پيل کړه",
        "config-env-php": "د $1 PHP نصب شو.",
        "config-env-hhvm": "HHVM $1 نصب شو.",
-       "config-apc": "[https://secure.php.net/apc APC] نصب شو",
+       "config-apc": "[https://www.php.net/apc APC] نصب شو",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] نصب شو",
        "config-diff3-bad": "جي ان يو ډيف3 و نه موندل شو.",
        "config-using-server": "د پالنگر نوم \"<nowiki>$1</nowiki>\" کارېږي.",
index 8c53ed1..2bae20f 100644 (file)
        "config-pcre-no-utf8": "<strong>Erro fatal:</strong> O módulo PCRE do PHP parece ser compilado sem suporte a PCRE_UTF8.\nO MediaWiki requer suporte a UTF-8 para funcionar corretamente.",
        "config-memory-raised": "A configuração <code>memory_limit</code> do PHP era $1; foi aumentada para $2.",
        "config-memory-bad": "<strong>Aviso:</strong> A configuração <code>memory_limit</code> do PHP é $1.\nIsso provavelmente é muito baixo.\nA instalação pode falhar!",
-       "config-apc": "[https://secure.php.net/apc APC] está instalado",
-       "config-apcu": "[https://secure.php.net/apcu APCu] está instalado",
+       "config-apc": "[https://www.php.net/apc APC] está instalado",
+       "config-apcu": "[https://www.php.net/apcu APCu] está instalado",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] está instalado",
-       "config-no-cache-apcu": "<strong>Aviso:</strong> Não foram encontrados o [https://secure.php.net/apcu APCu], ou o [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nA cache de objetos não está ativa.",
+       "config-no-cache-apcu": "<strong>Aviso:</strong> Não foram encontrados o [https://www.php.net/manual/pt_BR/book.apcu.php APCu], ou o [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nA cache de objetos não está ativa.",
        "config-mod-security": "<strong>Aviso:</strong> Seu servidor web tem [https://modsecurity.org/ mod_security2] habilitado. Muitas configurações comuns de módulo podem causar problemas para o MediaWiki ou outro software que permite aos usuários postar conteúdo arbitrário.\nSe possível, ele dever ser desativad. Consulte a [https://modsecurity.org/documentation/ documentação do mod_security] ou entre em contato com o suporte do seu host se você encontrar erros aleatórios.",
        "config-diff3-bad": "Utilitário de comparação de texto do GNU diff3 não encontrado. Você pode ignorar isso por enquanto, mas pode se deparar com conflitos de edição com mais frequência.",
        "config-git": "Foi encontrado o software de controle de versão Git: <code>$1</code>.",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "O MediaWiki suporta os sistemas de banco de dados a seguir:\n\n$1\n\nSe você não vê o sistema de banco de dados que você está tentando usar listados abaixo, siga as instruções relacionadas acima, para ativar o suporte.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] é a base de dados preferida para o MediaWiki e a melhor suportada. O MediaWiki também trabalha com [{{int:version-db-mysql-url}} MySQL] e [{{int:version-db-percona-url}} Percona Server], que são compatíveis com MariaDB. ([https://secure.php.net/manual/pt_BR/mysqli.installation.php Como compilar PHP com suporte para MySQL].)",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] é um popular sistema de banco de dados de código aberto como uma alternativa para o MySQL. ([https://secure.php.net/manual/en/pgsql.installation.php Como compilar o PHP com suporte PostgreSQL])",
-       "config-dbsupport-sqlite": "* O [{{int:version-db-sqlite-url}} SQLite] é uma plataforma de base de dados ligeira muito bem suportada. ([https://secure.php.net/manual/en/pdo.installation.php Como compilar PHP com suporte para SQLite], usa PDO.)",
-       "config-dbsupport-oracle": "* A [{{int:version-db-oracle-url}} Oracle] é uma base de dados comercial para empresas. ([https://secure.php.net/manual/en/oci8.installation.php Como compilar PHP com suporte para OCI8].)",
-       "config-dbsupport-mssql": "* O [{{int:version-db-mssql-url}} Microsoft SQL Server] é uma base de dados comercial do Windows para empresas. ([https://secure.php.net/manual/en/sqlsrv.installation.php Como compilar PHP com suporte para SQLSRV].)",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] é a base de dados preferida para o MediaWiki e a melhor suportada. O MediaWiki também trabalha com [{{int:version-db-mysql-url}} MySQL] e [{{int:version-db-percona-url}} Percona Server], que são compatíveis com MariaDB. ([https://www.php.net/manual/pt_BR/mysqli.installation.php Como compilar PHP com suporte para MySQL].)",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] é um popular sistema de banco de dados de código aberto como uma alternativa para o MySQL. ([https://www.php.net/manual/en/pgsql.installation.php Como compilar o PHP com suporte PostgreSQL])",
+       "config-dbsupport-sqlite": "* O [{{int:version-db-sqlite-url}} SQLite] é uma plataforma de base de dados ligeira muito bem suportada. ([https://www.php.net/manual/en/pdo.installation.php Como compilar PHP com suporte para SQLite], usa PDO.)",
+       "config-dbsupport-oracle": "* A [{{int:version-db-oracle-url}} Oracle] é uma base de dados comercial para empresas. ([https://www.php.net/manual/pt_BR/oci8.installation.php Como compilar PHP com suporte para OCI8].)",
+       "config-dbsupport-mssql": "* O [{{int:version-db-mssql-url}} Microsoft SQL Server] é uma base de dados comercial do Windows para empresas. ([https://www.php.net/manual/en/sqlsrv.installation.php Como compilar PHP com suporte para SQLSRV].)",
        "config-header-mysql": "Definições MariaDB/MySQL",
        "config-header-postgres": "Configurações PostgreSQL",
        "config-header-sqlite": "Configurações SQLite",
        "config-license-help": "Muitas wikis públicas colocam todas as contribuições sob uma [https://freedomdefined.org/Definition licença livre].\nIsso ajuda a criar um senso de propriedade da comunidade e incentiva a contribuição de longo prazo.\nGeralmente não é necessário para uma empresa privada ou wiki corporativa.\nSe você quiser poder usar o texto da Wikipédia e quiser que a Wikipédia possa aceitar o texto copiado da sua wiki, você deve escolher <strong>{{int:config-license-cc-by-sa}}</strong>.\n\nA Wikipédia usou anteriormente a Licença de Documentação Livre GNU.\n A GFDL é uma licença válida, mas é difícil de entender.\nTambém é difícil reutilizar conteúdo licenciado sob o GFDL.",
        "config-email-settings": "Configurações de e-mail",
        "config-enable-email": "Ativar envio de e-mail",
-       "config-enable-email-help": "Se você quer que o e-mail funcione, estas [Config-dbsupport-oracle/manual/en/mail.configuration.php configurações de e-mail PHP] precisam ser configuradas corretamente.\nSe você não quiser usar nenhuma das funcionalidades, você pode desabilitá-las aqui.",
+       "config-enable-email-help": "Se você quer que o e-mail funcione, estas [https://www.php.net/manual/pt_BR/mail.configuration.php configurações de e-mail PHP] precisam ser configuradas corretamente.\nSe você não quiser usar nenhuma das funcionalidades, você pode desabilitá-las aqui.",
        "config-email-user": "Ativar e-mails entre usuários",
        "config-email-user-help": "Permitir que todos os usuários enviem e-mail entre si se eles tiverem habilitado este recurso em suas preferências.",
        "config-email-usertalk": "Ativar notificação de alterações em páginas de discussão de usuário",
        "config-install-done": "<strong>Parabéns!</strong>\nVocê instalou o MediaWiki.\n\nO instalador gerou um arquivo <code>LocalSettings.php</code>.\nEste arquivo contém todas as suas configurações.\n\nVocê precisa fazer o download desse arquivo e colocá-lo na raiz da sua instalação (o mesmo diretório onde está o arquivo index.php). O download deve iniciar automaticamente.\n\nSe o download não foi iniciado ou se ele foi cancelado, você pode recomeçá-lo clicando no link abaixo:\n\n$3\n\n<strong>Nota:</strong> Se você não fizer isso agora, o arquivo de configuração que foi gerado não estará mais disponível se você sair da instalação sem fazer o download.\n\nQuando isso tiver sido feito, você pode <strong>[$2 entrar na sua wiki]</strong>.",
        "config-install-done-path": "<strong>Parabéns!</strong>\nVocê instalou o MediaWiki.\n\nO instalador gerou um arquivo <code>LocalSettings.php</code>.\nEste arquivo contém todas as suas configurações.\n\nVocê precisa fazer o download desse arquivo e colocá-lo em <code>$4</code>. O download deve iniciar automaticamente.\n\nSe o download não foi iniciado ou se ele foi cancelado, você pode recomeçá-lo clicando no link abaixo:\n\n$3\n\n<strong>Nota:</strong> Se você não fizer isso agora, o arquivo de configuração que foi gerado não estará mais disponível se você sair da instalação sem fazer o download.\n\nQuando isso tiver sido feito, você pode <strong>[$2 entrar na sua wiki]</strong>.",
        "config-install-success": "O MediaWiki foi instalado. Já pode visitar <$1$2> para ver a sua wiki.\nSe tiver dúvidas, veja a nossa lista de perguntas frequentes,\n<https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ>, ou utilize um dos fóruns de suporte indicados nessa página.",
+       "config-install-db-success": "Banco de dados foi configurado com sucesso",
        "config-download-localsettings": "Baixar <code>LocalSettings.php</code>",
        "config-help": "ajuda",
        "config-help-tooltip": "clique para expandir",
index f9fc84f..8768afc 100644 (file)
        "config-pcre-no-utf8": "'''Erro fatal''': O módulo PCRE do PHP parece ter sido compilado sem suporte PCRE_UTF8.\nO MediaWiki necessita do suporte UTF-8 para funcionar corretamente.",
        "config-memory-raised": "A configuração <code>memory_limit</code> do PHP era $1; foi aumentada para $2.",
        "config-memory-bad": "<strong>Aviso:</strong> A configuração <code>memory_limit</code> do PHP é $1.\nIsto é provavelmente demasiado baixo.\nA instalação poderá falhar!",
-       "config-apc": "[https://secure.php.net/apc APC] instalada",
-       "config-apcu": "[https://secure.php.net/apcu APCu] instalado",
+       "config-apc": "[https://www.php.net/apc APC] instalada",
+       "config-apcu": "[https://www.php.net/apcu APCu] instalado",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] instalada",
-       "config-no-cache-apcu": "<strong>Aviso:</strong> Não foi encontrado o [https://secure.php.net/apcu APCu] nem o [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nA cache de objetos não está ativa.",
+       "config-no-cache-apcu": "<strong>Aviso:</strong> Não foi encontrado o [https://www.php.net/apcu APCu] nem o [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nA cache de objetos não está ativa.",
        "config-mod-security": "<strong>Aviso:</strong> O seu servidor de Internet tem o [https://modsecurity.org/ mod_security]/mod_security2 ativado. Muitas das suas configurações normais podem causar problemas ao MediaWiki e a outros programas, permitindo que os utilizadores publiquem conteúdos arbitrários.\nSe possível, isto deve ser desativado. Se não, consulte a [https://modsecurity.org/documentation/ mod_security documentação] ou peça apoio ao fornecedor do alojamento do seu servidor se encontrar erros aleatórios.",
        "config-diff3-bad": "O utilitário de comparação de texto GNU diff3 não foi encontrado. Pode ignorar esta situação por agora, mas poderá encontrar conflitos entre edições mais frequentemente.",
        "config-git": "Foi encontrado o software de controlo de versões Git: <code>$1</code>.",
@@ -99,7 +99,7 @@
        "config-using-32bit": "<strong>Aviso:</strong> o seu sistema parece estar a funcionar com inteiros de 32 bits. Isto  [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:32-bit não é recomendado].",
        "config-db-type": "Tipo da base de dados:",
        "config-db-host": "Servidor da base de dados:",
-       "config-db-host-help": "Se seu servidor de base de dados estiver num servidor separado, introduza aqui o nome do host ou o endereço de IP.\n\nSe estiver a usar um web hosting partilhado, o provedor de hosting deve fornecer-lhe o nome de host correto em sua documentação.\n\nSe estiver a usar MySQL, usar «localhost» pode não funcionar como nome de servidor. Se não funcionar, tente usar «127.0.0.1» para endereço de IP local.\n\nSe estiver a usar PostgreSQL, deixe este campo em branco para conexão através de um socket Unix.",
+       "config-db-host-help": "Se a base de dados estiver num servidor separado, introduza aqui o nome ou o endereço IP desse servidor.\n\nSe estiver a usar um servidor partilhado, o fornecedor do alojamento deve fornecer o nome do servidor na documentação.\n\nSe estiver a usar MySQL, usar como nome do servidor \"localhost\" poderá não funcionar. Se não funcionar, tente usar \"127.0.0.1\" como endereço IP local.\n\nSe estiver a usar PostgreSQL, deixe este campo em branco para fazer a ligação através de um socket Unix.",
        "config-db-host-oracle": "TNS (Transparent Network Substrate) da base de dados:",
        "config-db-host-oracle-help": "Introduza um [http://download.oracle.com/docs/cd/B28359_01/network.111/b28317/tnsnames.htm Nome Local de Ligação] válido; tem de estar visível para esta instalação um ficheiro tnsnames.ora.<br />Se está a usar bibliotecas cliente versão 10g ou posterior, também pode usar o método [http://download.oracle.com/docs/cd/E11882_01/network.112/e10836/naming.htm Ligação Fácil] de atribuição do nome.",
        "config-db-wiki-settings": "Identifique esta wiki",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "O MediaWiki suporta as seguintes plataformas de base de dados:\n\n$1\n\nSe a plataforma que pretende usar não está listada abaixo, siga as instruções nas hiperligações acima para ativar o suporte.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] é a base de dados preferida para o MediaWiki e a melhor suportada. O MediaWiki também trabalha com [{{int:version-db-mysql-url}} MySQL] e [{{int:version-db-percona-url}} Percona Server], que são compatíveis com MariaDB. ([https://secure.php.net/manual/pt_BR/mysqli.installation.php Como compilar PHP com suporte para MySQL].)",
-       "config-dbsupport-postgres": "* O [{{int:version-db-postgres-url}} PostgreSQL] é uma plataforma popular de base de dados de código aberto, alternativa ao MySQL. ([https://secure.php.net/manual/en/pgsql.installation.php Como compilar PHP com suporte para PostgreSQL].)",
-       "config-dbsupport-sqlite": "* O [{{int:version-db-sqlite-url}} SQLite] é uma plataforma de base de dados ligeira muito bem suportada. ([https://secure.php.net/manual/en/pdo.installation.php Como compilar PHP com suporte para SQLite], usa PDO.)",
-       "config-dbsupport-oracle": "* A [{{int:version-db-oracle-url}} Oracle] é uma base de dados comercial para empresas. ([https://secure.php.net/manual/en/oci8.installation.php Como compilar PHP com suporte para OCI8].)",
-       "config-dbsupport-mssql": "* O [{{int:version-db-mssql-url}} Microsoft SQL Server] é uma base de dados comercial do Windows para empresas. ([https://secure.php.net/manual/en/sqlsrv.installation.php Como compilar PHP com suporte para SQLSRV].)",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] é a base de dados preferida para o MediaWiki e a melhor suportada. O MediaWiki também trabalha com [{{int:version-db-mysql-url}} MySQL] e [{{int:version-db-percona-url}} Percona Server], que são compatíveis com MariaDB. ([https://www.php.net/manual/pt_BR/mysqli.installation.php Como compilar PHP com suporte para MySQL].)",
+       "config-dbsupport-postgres": "* O [{{int:version-db-postgres-url}} PostgreSQL] é uma plataforma popular de base de dados de código aberto, alternativa ao MySQL. ([https://www.php.net/manual/en/pgsql.installation.php Como compilar PHP com suporte para PostgreSQL].)",
+       "config-dbsupport-sqlite": "* O [{{int:version-db-sqlite-url}} SQLite] é uma plataforma de base de dados ligeira muito bem suportada. ([https://www.php.net/manual/en/pdo.installation.php Como compilar PHP com suporte para SQLite], usa PDO.)",
+       "config-dbsupport-oracle": "* A [{{int:version-db-oracle-url}} Oracle] é uma base de dados comercial para empresas. ([https://www.php.net/manual/en/oci8.installation.php Como compilar PHP com suporte para OCI8].)",
+       "config-dbsupport-mssql": "* O [{{int:version-db-mssql-url}} Microsoft SQL Server] é uma base de dados comercial do Windows para empresas. ([https://www.php.net/manual/en/sqlsrv.installation.php Como compilar PHP com suporte para SQLSRV].)",
        "config-header-mysql": "Definições MariaDB/MySQL",
        "config-header-postgres": "Definições PostgreSQL",
        "config-header-sqlite": "Definições SQLite",
        "config-invalid-db-server-oracle": "O TNS da base de dados, \"$1\", é inválido.\nUse \"TNS Name\" ou o método \"Easy Connect\" ([http://docs.oracle.com/cd/E11882_01/network.112/e10836/naming.htm Métodos de Configuração da Conectividade em Oracle])",
        "config-invalid-db-name": "O nome da base de dados, \"$1\",  é inválido.\nUse só letras (a-z, A-Z), algarismos (0-9), sublinhados (_) e hífens (-) dos caracteres ASCII.",
        "config-invalid-db-prefix": "O prefixo da base de dados, \"$1\",  é inválido.\nUse só letras (a-z, A-Z), algarismos (0-9), sublinhados (_) e hífens (-) dos caracteres ASCII.",
-       "config-connection-error": "$1.\n\nVerifique o host, o nome de utilizador e a password e tente novamente. Se usar «localhost» como o host da base de dados, tente usar «127.0.0.1» antes (ou vice versa).",
+       "config-connection-error": "$1.\n\nVerifique o servidor, o nome do utilizador e a palavra-passe e tente novamente. Se estiver a usar \"localhost\" como servidor da base de dados, tente antes usar \"127.0.0.1\" (ou vice-versa).",
        "config-invalid-schema": "O esquema ''(schema)'' do MediaWiki, \"$1\", é inválido.\nUse só letras (a-z, A-Z), algarismos (0-9) e sublinhados (_) dos caracteres ASCII.",
        "config-db-sys-create-oracle": "O instalador só permite criar uma conta nova usando uma conta SYSDBA.",
        "config-db-sys-user-exists-oracle": "A conta \"$1\" já existe. A conta SYSDBA só pode criar uma conta nova!",
        "config-license-help": "Muitas wikis de acesso público licenciam todas as colaborações com uma [https://freedomdefined.org/Definition licença livre].\nIsto ajuda a criar um sentido de propriedade da comunidade e encoraja as colaborações a longo prazo.\nTal não é geralmente necessário nas wikis privadas ou corporativas.\n\nSe pretende que seja possível usar textos da Wikipédia na sua wiki e que seja possível a Wikipédia aceitar textos copiados da sua wiki, deve escolher a licença <strong>{{int:config-license-cc-by-sa}}</strong>..\n\nA licença anterior da Wikipédia era a licença GNU Free Documentation License.\nA GFDL é uma licença válida, mas de difícil compreensão.\nTambém é difícil reutilizar conteúdos licenciados com a GFDL.",
        "config-email-settings": "Definições do correio eletrónico",
        "config-enable-email": "Ativar mensagens eletrónicas de saída",
-       "config-enable-email-help": "Se quer que o correio eletrónico funcione, as [https://secure.php.net/manual/en/mail.configuration.php definições de correio eletrónico do PHP] têm de estar configuradas corretamente.\nSe não pretende viabilizar qualquer funcionalidade de correio eletrónico, pode desativá-lo aqui.",
+       "config-enable-email-help": "Se quer que o correio eletrónico funcione, as [https://www.php.net/manual/en/mail.configuration.php definições de correio eletrónico do PHP] têm de estar configuradas corretamente.\nSe não pretende viabilizar qualquer funcionalidade de correio eletrónico, pode desativá-lo aqui.",
        "config-email-user": "Ativar mensagens eletrónicas entre utilizadores",
        "config-email-user-help": "Permitir que todos os utilizadores troquem entre si mensagens de correio eletrónico, se tiverem ativado esta funcionalidade nas suas preferências.",
        "config-email-usertalk": "Ativar notificações de alterações à página de discussão dos utilizadores",
        "config-install-done": "<strong>Parabéns!</strong>\nTerminou a instalação do MediaWiki.\n\nO instalador gerou um ficheiro <code>LocalSettings.php</code>.\nEste ficheiro contém todas as configurações.\n\nPrecisa de descarregar o ficheiro e colocá-lo no diretório de raiz da sua instalação (o mesmo diretório onde está o ficheiro index.php). Este descarregamento deverá ter sido iniciado automaticamente.\n\nSe o descarregamento não foi iniciado, ou se o cancelou, pode recomeçá-lo clicando na hiperligação abaixo:\n\n$3\n\n<strong>Nota</strong>: Se não o descarregar agora, o ficheiro que foi gerado deixará de estar disponível quando sair do processo de instalação.\n\nDepois de terminar o passo anterior, pode <strong>[$2 entrar na wiki]</strong>.",
        "config-install-done-path": "<strong>Parabéns!</strong>\nTerminou a instalação do MediaWiki.\n\nO instalador gerou um ficheiro <code>LocalSettings.php</code>.\nEste ficheiro contém todas as configurações.\n\nPrecisa de descarregar o ficheiro e colocá-lo no diretório <code>$4</code>. Este descarregamento deverá ter sido iniciado automaticamente.\n\nSe o descarregamento não foi iniciado, ou se o cancelou, pode recomeçá-lo clicando a hiperligação abaixo:\n\n$3\n\n<strong>Nota</strong>: Se não fizer o descarregamento agora, o ficheiro que foi gerado deixará de estar disponível quando sair do processo de instalação.\n\nDepois de terminar o passo anterior, pode <strong>[$2 entrar na wiki]</strong>.",
        "config-install-success": "O MediaWiki foi instalado. Já pode visitar <$1$2> para ver a sua wiki.\nSe tiver dúvidas, veja a nossa lista de perguntas frequentes,\n<https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ>, ou utilize um dos fóruns de suporte indicados nessa página.",
+       "config-install-db-success": "A base de dados foi configurada",
        "config-download-localsettings": "Descarregar <code>LocalSettings.php</code>",
        "config-help": "ajuda",
        "config-help-tooltip": "clique para expandir",
index bf19769..91f07c3 100644 (file)
        "config-install-mainpage-failed": "Used as error message. Parameters:\n* $1 - detailed error message",
        "config-install-done": "Parameters:\n* $1 is the URL to LocalSettings download\n* $2 is a link to the wiki.\n* $3 is a download link with attached download icon. The config-download-localsettings message will be used as the link text.",
        "config-install-done-path": "Parameters:\n* $1 is the URL to LocalSettings download\n* $2 is a link to the wiki.\n* $3 is a download link with attached download icon. The config-download-localsettings message will be used as the link text.\n* $4 is the filesystem location of where the LocalSettings.php file should be saved to.",
-       "config-install-success": "Gives user information that installation was successful. Parameters:\n* $1 - server name\n* $2 - script path",
+       "config-install-success": "Gives user information that installation was successful. Only shown in command line installer. Parameters:\n* $1 - server name\n* $2 - script path",
+       "config-install-db-success": "Shown after DB is set up. In web installer this is step prior to downloading LocalSettings.php",
        "config-download-localsettings": "The link text used in the download link in config-install-done.",
        "config-help": "This is used in help boxes.\n{{Identical|Help}}",
        "config-help-tooltip": "Tooltip for the 'help' links ({{msg-mw|config-help}}), to make it clear they'll expand in place rather than open a new page",
index f6c63e0..66eca85 100644 (file)
@@ -9,7 +9,8 @@
                        "Strainu",
                        "Fitoschido",
                        "WebSourceContentRO",
-                       "MSClaudiu"
+                       "MSClaudiu",
+                       "Andrei Stroe"
                ]
        },
        "config-desc": "Programul de instalare pentru MediaWiki",
        "config-pcre-no-utf8": "<strong>Fatal:</strong> Modul PCRE al PHP pare să fie compilat fără suport PCRE_UTF8.\nMediaWiki necesită ca suportul UTF-8 să funcționeze corect.",
        "config-memory-raised": "PHP<code>memory_limit</code> este $1, mărit cu $2.",
        "config-memory-bad": "<strong>Atenție:</strong> PHP<code>memory_limit</code> este $1.\nAcesta este probabil mai jos.\nAceastă instalare eșuează!",
-       "config-apc": "[https://secure.php.net/apc APC] este instalat",
-       "config-apcu": "[https://secure.php.net/apcu APCu] este instalat",
+       "config-apc": "[https://www.php.net/apc APC] este instalat",
+       "config-apcu": "[https://www.php.net/apcu APCu] este instalat",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] este instalat",
-       "config-no-cache-apcu": "<strong>Atenție:</strong> Nu am putut găsi [https://secure.php.net/apcu APCu] sau [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nObiect cache nu este activat.",
+       "config-no-cache-apcu": "<strong>Atenție:</strong> Nu am putut găsi [https://www.php.net/apcu APCu] sau [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nObiect cache nu este activat.",
        "config-mod-security": "<strong>Avertisment:</strong> Serverul dvs. web are activat [https://modsecurity.org/ mod_security] / mod_security2. Multe configurații comune vor provoca probleme pentru MediaWiki și alte programe software care permit utilizatorilor să posteze conținuturi arbitrare.\nDacă este posibil, aceasta ar trebui dezactivată. În caz contrar, consultați documentația [https://modsecurity.org/documentation/ mod_security] sau contactați asistența gazdei dvs. dacă întâmpinați erori aleatorii.",
        "config-diff3-bad": "Utilitarul de comparare a textului GNU diff3 nu a fost găsit. Puteți ignora acest lucru pentru moment, dar ar putea apărea mai frecvent conflicte de editare.",
        "config-git": "Am găsit versiunea software de control Git:<code>$1</code>.",
@@ -79,7 +80,7 @@
        "config-db-host": "Gazdă bază de date:",
        "config-db-host-oracle": "Baza de date TNS:",
        "config-db-wiki-settings": "Identificați acest wiki",
-       "config-db-name": "Numele bazei de date:",
+       "config-db-name": "Numele bazei de date (fără cratime):",
        "config-db-name-oracle": "Schema bazei de date:",
        "config-db-install-account": "Contul de utilizator pentru instalare",
        "config-db-username": "Nume de utilizator pentru baza de date:",
        "config-db-install-help": "Introduceți numele de utilizator și parola care vor fi utilizate pentru conexiunea la baza de date în timpul procesului de instalare.",
        "config-db-account-lock": "Folosește același nume de utilizator și parolă în timpul funcționării normale",
        "config-db-wiki-account": "Contul de utilizator pentru funcționarea normală",
-       "config-db-prefix": "Prefixul tabelelor din baza de date:",
+       "config-db-prefix": "Prefixul tabelelor din baza de date (fără cratime):",
        "config-db-port": "Portul bazei de date:",
-       "config-db-schema": "Schema pentru MediaWiki:",
+       "config-db-schema": "Schema pentru MediaWiki (fără cratime):",
        "config-sqlite-dir": "Director de date SQLite:",
        "config-oracle-def-ts": "Spațiu de stocare („tablespace”) implicit:",
        "config-oracle-temp-ts": "Spațiu de stocare („tablespace”) temporar:",
        "config-type-mysql": "MariaDB, MySQL sau compatibil",
        "config-type-mssql": "Microsoft SQL Server",
-       "config-header-mysql": "Setările MySQL",
+       "config-header-mysql": "Setările MariaDB/MySQL",
        "config-header-postgres": "Setări PostgreSQL",
        "config-header-sqlite": "Setări SQLite",
        "config-header-oracle": "Setări Oracle",
        "config-missing-db-name": "Trebuie să introduceți o valoare pentru „{{int:config-db-name}}”.",
        "config-missing-db-host": "Trebuie să introduceți o valoare pentru „{{int:config-db-host}}”.",
        "config-missing-db-server-oracle": "Trebuie să introduceți o valoare pentru „{{int:config-db-host-oracle}}”.",
-       "config-connection-error": "$1.\n\nVerificați gazda, numele de utilizator și parola și reîncercați.",
+       "config-connection-error": "$1.\n\nVerificați hostul, numele de utilizator și parola și reîncercați. Dacă folosiți „localhost” drept host al bazei de date, încercați mai bine „127.0.0.1” (sau invers).",
        "config-upgrade-done-no-regenerate": "Actualizare completă.\n\nAcum puteți [$1 începe să vă folosiți wikiul].",
        "config-regenerate": "Regenerare LocalSettings.php →",
        "config-unknown-collation": "AVERTISMENT: Baza de date folosește o colaționare nerecunoscută.",
        "config-db-web-account": "Contul bazei de date pentru accesul web.",
        "config-db-web-create": "Creați contul dacă nu există deja",
        "config-mysql-engine": "Motor de stocare:",
-       "config-mysql-innodb": "InnoDB",
+       "config-mysql-innodb": "InnoDB (recomandat)",
        "config-mysql-myisam": "MyISAM",
        "config-mssql-auth": "Tip de autentificare:",
        "config-site-name": "Numele wikiului:",
        "config-download-localsettings": "Descarcă <code>LocalSettings.php</code>",
        "config-help": "ajutor",
        "config-help-tooltip": "clic pentru a extinde",
-       "mainpagetext": "'''Programul Wiki a fost instalat cu succes.'''",
-       "mainpagedocfooter": "Consultați [https://meta.wikimedia.org/wiki/Help:Contents Ghidul utilizatorului (en)] pentru informații despre utilizarea software-ului wiki.\n\n== Primii pași ==\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Lista parametrilor configurabili (en)]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ Întrebări frecvente despre MediaWiki (en)]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Lista de discuții a MediaWiki (en)]"
+       "mainpagetext": "<strong>Programul Wiki a fost instalat.</strong>",
+       "mainpagedocfooter": "Consultați [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Ghidul utilizatorului] pentru informații despre utilizarea software-ului wiki.\n\n== Primii pași ==\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Lista de setări de configurare]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ Întrebări frecvente despre MediaWiki]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Lista de e-mail pentru release-urile MediaWiki]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Localizați MediaWiki în limba dumneavoastră]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Învățați cum să combateți spamul pe wikiul dumneavoastră]"
 }
index de6d731..8297dd8 100644 (file)
@@ -27,7 +27,8 @@
                        "Facenapalm",
                        "Movses",
                        "Vlad5250",
-                       "Athena Atterdag"
+                       "Athena Atterdag",
+                       "Diralik"
                ]
        },
        "config-desc": "Инсталлятор MediaWiki",
        "config-pcre-no-utf8": "'''Фатальная ошибка'''. Модуль PCRE для PHP, похоже, собран без поддержки PCRE_UTF8.\nMediaWiki требует поддержки UTF-8 для корректной работы.",
        "config-memory-raised": "Ограничение на доступную PHP память (<code>memory_limit</code>) поднято с $1 до $2.",
        "config-memory-bad": "'''Внимание:''' размер PHP <code>memory_limit</code> составляет $1.\nВероятно, этого слишком мало.\nУстановка может потерпеть неудачу!",
-       "config-apc": "[https://secure.php.net/apc APC] установлен",
-       "config-apcu": "[https://secure.php.net/apcu APCu] установлен",
+       "config-apc": "[https://www.php.net/apc APC] установлен",
+       "config-apcu": "[https://www.php.net/apcu APCu] установлен",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] установлен",
-       "config-no-cache-apcu": "<strong>Внимание:</strong> Не найдены [https://secure.php.net/apcu APCu] или [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nКэширование объектов будет отключено.",
+       "config-no-cache-apcu": "<strong>Внимание:</strong> Не найдены [https://www.php.net/apcu APCu] или [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nКэширование объектов будет отключено.",
        "config-mod-security": "<strong>Внимание</strong>: На вашем веб-сервере включён [https://modsecurity.org/ mod_security]/mod_security2. Многие его стандартные настройки могут вызывать проблемы для MediaWiki или другого ПО, позволяющего пользователям отправлять на сервер произвольный контент.\nПо возможности он должен быть отключён. Обратитесь к [https://modsecurity.org/documentation/ документации mod_security] или в службу поддержки вашего хостинг-провайдера, если вы сталкиваетесь со случайными ошибками.",
        "config-diff3-bad": "Утилита для сравнения GNU diff3 не найдена. Вы можете пока это проигнорировать, но, скорее всего, вы будете видеть эту ошибку вновь и вновь при конфликтах редактирования.",
        "config-git": "Найдена система контроля версий Git: <code>$1</code>.",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki поддерживает следующие СУБД:\n\n$1\n\nЕсли вы не видите своей системы хранения данных в этом списке, следуйте инструкциям, на которые есть ссылка выше, чтобы получить поддержку.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] — основная база данных для MediaWiki, которая поддерживается лучше всего. MediaWiki также работает с [{{int:version-db-mariadb-url}} MariaDB] и [{{int:version-db-percona-url}} Percona Server], которые являются MariaDB-совместимыми. (См.[https://secure.php.net/manual/ru/mysql.installation.php Как собрать PHP с поддержкой MySQL])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] — популярная СУБД с открытым исходным кодом, альтернатива MySQL. ([https://secure.php.net/manual/ru/pgsql.installation.php Как собрать PHP с поддержкой PostgreSQL]).",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] — это легковесная система баз данных, имеющая очень хорошую поддержку. ([https://secure.php.net/manual/ru/pdo.installation.php Как собрать PHP с поддержкой SQLite], работающей посредством PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] — это коммерческая корпоративная база данных. ([https://secure.php.net/manual/ru/oci8.installation.php Как собрать PHP с поддержкой OCI8])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] — это коммерческая корпоративная база данных для Windows. ([https://secure.php.net/manual/ru/sqlsrv.installation.php Как собрать PHP с поддержкой SQLSRV])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] — основная база данных для MediaWiki, которая поддерживается лучше всего. MediaWiki также работает с [{{int:version-db-mariadb-url}} MariaDB] и [{{int:version-db-percona-url}} Percona Server], которые являются MariaDB-совместимыми. (См.[https://www.php.net/manual/ru/mysql.installation.php Как собрать PHP с поддержкой MySQL])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] — популярная СУБД с открытым исходным кодом, альтернатива MySQL. ([https://www.php.net/manual/ru/pgsql.installation.php Как собрать PHP с поддержкой PostgreSQL]).",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] — это легковесная система баз данных, имеющая очень хорошую поддержку. ([https://www.php.net/manual/ru/pdo.installation.php Как собрать PHP с поддержкой SQLite], работающей посредством PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] — это коммерческая корпоративная база данных. ([https://www.php.net/manual/ru/oci8.installation.php Как собрать PHP с поддержкой OCI8])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] — это коммерческая корпоративная база данных для Windows. ([https://www.php.net/manual/ru/sqlsrv.installation.php Как собрать PHP с поддержкой SQLSRV])",
        "config-header-mysql": "Настройки MariaDB/MySQL",
        "config-header-postgres": "Настройки PostgreSQL",
        "config-header-sqlite": "Настройки SQLite",
        "config-license-help": "Многие общедоступные вики разрешают использовать свои материалы на условиях [https://freedomdefined.org/Definition/Ru свободных лицензий].\nЭто помогает созданию чувства общности, стимулирует долгосрочное участие.\nНо в этом нет необходимости для частных или корпоративных вики.\n\nЕсли вы хотите использовать тексты из Википедии или хотите, что в Википедию можно было копировать тексты из вашей вики, вам следует выбрать <strong>{{int:config-license-cc-by-sa}}</strong>.\n\nВикипедия ранее использовала лицензию GNU Free Documentation License.\nGFDL может быть использована, но она сложна для понимания и осложняет повторное использование материалов.",
        "config-email-settings": "Настройки электронной почты",
        "config-enable-email": "Включить исходящие e-mail",
-       "config-enable-email-help": "Если вы хотите, чтобы электронная почта работала, необходимо правильно настроить [https://secure.php.net/manual/ru/mail.configuration.php работу почты в PHP].\nЕсли вы не хотите использовать возможности электронной почты, вы можете её здесь отключить.",
+       "config-enable-email-help": "Если вы хотите, чтобы электронная почта работала, необходимо правильно настроить [https://www.php.net/manual/ru/mail.configuration.php работу почты в PHP].\nЕсли вы не хотите использовать возможности электронной почты, вы можете её здесь отключить.",
        "config-email-user": "Включить электронную почту от участника к участнику",
        "config-email-user-help": "Разрешить всем пользователям отправлять друг другу электронные письма, если выставлена соответствующая настройка в профиле.",
        "config-email-usertalk": "Включить уведомления пользователей о сообщениях на их странице обсуждения",
        "config-cc-not-chosen": "Выберите, какую лицензию Creative Commons Вы хотите использовать, и нажмите кнопку \"proceed\".",
        "config-advanced-settings": "Дополнительные настройки",
        "config-cache-options": "Параметры кэширования объектов:",
-       "config-cache-help": "Кэширование объектов используется для повышения скорости MediaWiki путем кэширования часто используемых данных.\nДля средних и больших сайтов кеширование настоятельно рекомендуется включать, а для небольших сайтов кеширование может показать преимущество.",
+       "config-cache-help": "Кэширование объектов используется для повышения скорости MediaWiki путём кэширования часто используемых данных.\nДля средних и больших сайтов кеширование настоятельно рекомендуется включать, а для небольших сайтов кеширование может показать преимущество.",
        "config-cache-none": "Без кэширования (никакой функционал не теряется, но крупные вики-сайты могут работать медленнее)",
        "config-cache-accel": "Кэширование PHP-объектов (APC, APCu или WinCache)",
        "config-cache-memcached": "Использовать Memcached (требует дополнительной настройки)",
        "config-install-done": "<strong>Поздравляем!</strong>\nВы установили MediaWiki.\n\nВо время установки был создан файл <code>LocalSettings.php</code>.\nОн содержит все ваши настройки.\n\nВам необходимо скачать его и положить в корневую директорию вашей вики (ту же директорию, где находится файл index.php). Его загрузка должна начаться автоматически.\n\nЕсли автоматическая загрузка не началась или вы её отменили, вы можете скачать по ссылке ниже:\n\n$3\n\n<strong>Примечание</strong>: Если вы не сделаете этого сейчас, то сгенерированный файл конфигурации не будет доступен вам в дальнейшем, если вы выйдете из установки, не скачивая его.\n\nПо окончании действий, описанных выше, вы сможете <strong>[$2 войти в вашу вики]</strong>.",
        "config-install-done-path": "<strong>Поздравляем!</strong>\nВы установили MediaWiki.\n\nВо время установки был создан файл <code>LocalSettings.php</code>.\nОн содержит все ваши настройки.\n\nВам необходимо скачать его и положить в <code>$4</code>. Его загрузка должна начаться автоматически.\n\nЕсли автоматическая загрузка не началась или вы её отменили, вы можете скачать по ссылке ниже:\n\n$3\n\n<strong>Примечание</strong>: Если вы не сделаете этого сейчас, то сгенерированный файл конфигурации не будет доступен вам в дальнейшем, если вы выйдете из установки, не скачивая его.\n\nПо окончании действий, описанных выше, вы сможете <strong>[$2 войти в вашу вики]</strong>.",
        "config-install-success": "MediaWiki успешно установлена. Сейчас вы можете перейти на <$1 $2>, чтобы просмотреть свою вики.\nЕсли у вас есть вопросы, ознакомьтесь с нашим часто задаваемыми вопросами:\n<https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ> или используйте один из форумов поддержки, указанный на этой странице.",
+       "config-install-db-success": "База данных была успешно настроена",
        "config-download-localsettings": "Загрузить <code>LocalSettings.php</code>",
        "config-help": "справка",
        "config-help-tooltip": "нажмите, чтобы развернуть",
-       "config-nofile": "Файл \"$1\" не удается найти. Он был удален?",
+       "config-nofile": "Файл \"$1\" не удаётся найти. Он был удалён?",
        "config-extension-link": "Знаете ли вы, что ваш вики-проект поддерживает [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions расширения]?\n\nВы можете просмотреть [https://www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category расширения по категориям]",
        "config-skins-screenshots": "$1 (скриншоты: $2)",
        "config-extensions-requires": "$1 (требуется $2)",
index 68d40d5..a8bada1 100644 (file)
@@ -61,9 +61,9 @@
        "config-pcre-no-utf8": "<strong>Fatal:</strong> PHP's PCRE module seems tae be compiled wioot PCRE_UTF8 support.\nMediaWiki requires UTF-8 support tae function correctly.",
        "config-memory-raised": "PHP's <code>memerie_limit</code> is $1, raised til $2.",
        "config-memory-bad": "<strong>Warnishment:</strong> PHP's <code>memerie_limit</code> is $1.\nThis is proably ower low.\nThe installation micht fail!",
-       "config-apc": "[https://secure.php.net/apc APC] is installed.",
+       "config-apc": "[https://www.php.net/apc APC] is installed.",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] is instawed.",
-       "config-no-cache-apcu": "<strong>Wairnin:</strong> Could nae find [https://secure.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] or [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nObject cachin isna enabled.",
+       "config-no-cache-apcu": "<strong>Wairnin:</strong> Could nae find [https://www.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] or [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nObject cachin isna enabled.",
        "config-mod-security": "<strong>Warnishment:</strong> Yer wab server haes [https://modsecurity.org/ mod_security] enabled. Gif misconfeegured, it can cause problems fer MediaWiki or ither saffware that allous uisers tae post arbitrie content.\nRefer til [https://modsecurity.org/documentation/ mod_security documentation] or contact yer host's support gif ye encounter random mistaks.",
        "config-diff3-bad": "GNU diff3 naw foond.",
        "config-git": "Foond the Git version control saffware: <code>$1</code>.",
        "config-type-mysql": "MaSQL (or compâtible)",
        "config-type-mssql": "Micræsaff SQL Server",
        "config-support-info": "MediaWiki supports the follaein database systems:\n\n$1\n\nGif ye dinna see the database system ye'r tryin tae uise listed ablow, than follae the instructions linked abuin tae enable support.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] is the primarie tairget fer MediaWiki n is best supported. MediaWiki warks forby wi [{{int:version-db-mariadb-url}} MariaDB] n [{{int:version-db-percona-url}} Percona Server], thir ar MySQL compatible. ([https://secure.php.net/manual/en/mysqli.installation.php Hou tae compile PHP wi MySQL support])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] is ae popular apen soorce database system aes aen alternative til MySQL. Thaur micht be some wee bugs still hingin roond, n it's na recommendit fer uiss in ae production environment. ([https://secure.php.net/manual/en/pgsql.installation.php Hou tae compile PHP wi PostgreSQL support])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] is the primarie tairget fer MediaWiki n is best supported. MediaWiki warks forby wi [{{int:version-db-mariadb-url}} MariaDB] n [{{int:version-db-percona-url}} Percona Server], thir ar MySQL compatible. ([https://www.php.net/manual/en/mysqli.installation.php Hou tae compile PHP wi MySQL support])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] is ae popular apen soorce database system aes aen alternative til MySQL. Thaur micht be some wee bugs still hingin roond, n it's na recommendit fer uiss in ae production environment. ([https://www.php.net/manual/en/pgsql.installation.php Hou tae compile PHP wi PostgreSQL support])",
        "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] is ae lichtweicht database system that is ver weel supportit. ([http://www.php.net/manual/en/pdo.installation.php Hou tae compile PHP wi SQLite support], uises PDO)",
        "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] is ae commercial enterprise database. ([http://www.php.net/manual/en/oci8.installation.php Hou tae compile PHP wi OCI8 support])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] is ae commercial enterprise database fer Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php Hou tae compile PHP wi SQLSRV support])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] is ae commercial enterprise database fer Windows. ([https://www.php.net/manual/en/sqlsrv.installation.php Hou tae compile PHP wi SQLSRV support])",
        "config-header-mysql": "MaSQL settins",
        "config-header-postgres": "PostgreSQL settins",
        "config-header-sqlite": "SQLite settins",
index c359130..e884770 100644 (file)
        "config-pcre-no-utf8": "<strong>Kobno</strong>: PCRE modul PHP-a je hitan bez podrške za PCRE_UTF8.\nMediaWiki zahtijeva podršku za UTF-8 kako bi ispravno funkcionirao.",
        "config-memory-raised": "<code>memory_limit</code> za PHP iznosi $1, povišen na $2.",
        "config-memory-bad": "<strong>Upozorenje:</strong> <code>memory_limit</code> za PHP iznosi $1.\nOvo je vjerovatno premalo.\nUspostava možda neće uspjeti!",
-       "config-apc": "[https://secure.php.net/apc APC] je uspostavljen",
-       "config-apcu": "[https://secure.php.net/apcu APCu] je uspostavljen",
+       "config-apc": "[https://www.php.net/apc APC] je uspostavljen",
+       "config-apcu": "[https://www.php.net/apcu APCu] je uspostavljen",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] je uspostavljen",
-       "config-no-cache-apcu": "<strong>Upozorenje:</strong> Nisam mogao naći [https://secure.php.net/apcu APCu] ili [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].",
+       "config-no-cache-apcu": "<strong>Upozorenje:</strong> Nisam mogao naći [https://www.php.net/apcu APCu] ili [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].",
        "config-mod-security": "'''Upozorenje''': na vašem poslužitelju ima omogućeno [https://modsecurity.org/ mod_security]. Ako nije postavljeno kako treba, to može uzrokovati probleme s programom MediaWikija i drugim programima koji korisnicima omogućuju objavljivanje proizvoljnog sadržaja.\nPogledajte [https://modsecurity.org/documentation/ mod_security dokumentaciju] ili kontaktirajte domaćin ako naiđete na slučajne greške.",
        "config-diff3-bad": "Nisam pronašao usporednik za tekst GNU razl3 (GNU diff3). Za sada ovo možete zanemariti, ali kontradikcije u uređivanju mogu postati češće.",
        "config-git": "Pronašao sam Git program za kontrolu verzija: <code>$1</code>.",
        "config-type-mysql": "MariaDB, MySQL ili kompatibilan",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki podržava sljedeće sustave baza podataka:\n\n$1\n\nAko sustav koji želite koristiti nije naveden u nastavku, slijedite vezu gore navedenih uputa kako biste omogućili podršku za taj sustav.",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] je glavna meta MediaWikija i najbolje je podržan. MediaWiki također radi sa [{{int:version-db-mysql-url}} MySQL-om] i [{{int:version-db-percona-url}} Percona], koji su skladni sa MariaDB-om. ([https://www.php.net/manual/en/mysqli.installation.php Kako kompajlirati PHP sa podrškom MySQL-a])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] je popularan sistem baza podataka otvorenog koda koji predstavlja alternativu MySQL-u. ([https://www.php.net/manual/en/pgsql.installation.php Kako kompajlirati PHP sa podrškom PostgreSQL-a])",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] je lagan sistem baze podataka koji je veoma dobro podržan. ([https://www.php.net/manual/en/pdo.installation.php Kako kompajlirati PHP sa podrškom SQLite-a], koristi PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] je baza podataka komercijalnih preduzeća. ([https://www.php.net/manual/en/oci8.installation.php Kako kompajlirati PHP sa podrškom OCI8-a])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] je baza podataka komercijalnih preduzeća za Windows. ([https://www.php.net/manual/en/sqlsrv.installation.php Kako kompajlirati PHP sa podrškom SQLSRV-a])",
+       "config-header-mysql": "Podešavanja MariaDB/MySQL-a",
+       "config-header-postgres": "Podešavanja PostgreSQL-a",
+       "config-header-sqlite": "Podešavanja SQLite-a",
+       "config-header-oracle": "Podešavanja Oracle-a",
+       "config-header-mssql": "Podešavanja za Microsoft SQL Server",
+       "config-invalid-db-type": "Nevažeći tip baze",
+       "config-missing-db-name": "Morate unijeti vrijednost za \"{{int:config-db-name}}\".",
+       "config-missing-db-host": "Morate unijeti vrijednost za \"{{int:config-db-host}}\".",
+       "config-missing-db-server-oracle": "Morate unijeti vrijednost za \"{{int:config-db-host-oracle}}\".",
+       "config-invalid-db-server-oracle": "Nevažeći TNS „$1”.\nKoristite ili „TNS Name” ili nisku „Easy Connect”.\n([http://docs.oracle.com/cd/E11882_01/network.112/e10836/naming.htm Oracle metodi imenovanja]).",
+       "config-invalid-db-name": "Ime baze podataka „$1” nije važeće.\nKoristite samo ASCII-slova (a-z, A-Z), brojeve (0-9) i podvlake (_).",
+       "config-invalid-db-prefix": "Prefiks baze podataka „$1” nije važeći.\nKoristite samo ASCII-slova (a-z, A-Z), brojeve (0-9), podvlake (_) i crtice (-).",
+       "config-connection-error": "$1.\n\nProvjerite host, korisničko ime i lozinku i pokušajte ponovno. Ako kao host baze podataka koristite \"localhost\", zamijenite ga \"127.0.0.1\" (ili obrnuto).",
+       "config-invalid-schema": "Šema za MediaWiki „$1” nije važeća.\nKoristite samo ASCII slova (a-z, A-Z), brojeve (0-9) i podvlake (_).",
+       "config-db-sys-create-oracle": "Uspostavljač podržava samo upotrebu SYSDBA-računa za pravljenje novih računa.",
+       "config-db-sys-user-exists-oracle": "Korisnički račun \"$1\" već postoji. SYSDBA samo služi za stvaranje novog računa!",
+       "config-postgres-old": "Zahtijeva se PostgreSQL $1 ili noviji. Vi imate $2.",
+       "config-mssql-old": "Zahtijeva se Microsoft SQL Server $1 ili novija verzija. Vi imate $2.",
+       "config-sqlite-name-help": "Odaberite ime koje će predstavljati vaš wiki.\nNe koristite razmake i crte.\nOvo će se koristiti za ime datoteke SQLite-podataka.",
+       "config-sqlite-parent-unwritable-group": "Nije moguće izraditi direktorijum <code><nowiki>$1</nowiki></code> \njer mrežni poslužitelj ne može pisati u matični direktorijum <code><nowiki>$2</nowiki></code>.\n\nIdentificiran je korisnik pod kojim radi vaš mrežni poslužitelj.\nDa biste nastavili, namjestite da može zapisivati u direktorijum <code><nowiki>$3</nowiki></code>.\nNa Unix/Linux sistemu učinite sljedeće:\n\n<pre>cd $2\nmkdir $3\nchgrp $4 $3\nchmod g+w $3</pre>",
+       "config-sqlite-parent-unwritable-nogroup": "Nije moguće izraditi direktorijum <code><nowiki>$1</nowiki></code> \njer mrežni poslužitelj ne može pisati u matični direktorijum <code><nowiki>$2</nowiki></code>.\n\nUspostavljač nije mogao odrediti korisnika pod kojim radi vaš mrežni poslužitelj.\nDa biste nastavili, postavite toga (i druge!) da biste se globalno zapisivati u direktorijum <code><nowiki>$3</nowiki></code>.\nNa Unix/Linux sistemu učinite sljedeće:\n\n<pre>cd $2\nmkdir $3\nchmod a+w $3</pre>",
+       "config-sqlite-mkdir-error": "Greška pri pravljenju podatkovnog direktorijuma \"$1\".\nProvjerite gdje se nalazi i pokušajte ponovo.",
+       "config-sqlite-dir-unwritable": "Nije moguće upisati u direktorijum \"$1\".\nU dopuštenjima za nju, omogućite mrežnom poslužitelju da upisuje u njemu i pokušajte ponovo.",
+       "config-sqlite-connection-error": "$1.\n\nProverite podatkovni direktorijum i ime baze podataka, i pokušajte ponovo.",
+       "config-sqlite-readonly": "Datoteka <code>$1</code> je nezapisiva.",
+       "config-sqlite-cant-create-db": "Nisam mogao stvoriti datoteku <code>$1</code> za bazu podataka.",
+       "config-sqlite-fts3-downgrade": "PHP-u nedostaje FTS3 podrška — poništavam nadogradnju tabela",
+       "config-can-upgrade": "U ovoj bazi podataka ima tabele MediaWikija.\nDa biste ih nadogradili na MediaWiki $1, kliknite na <strong>Nastavi</strong>.",
+       "config-upgrade-error": "Došlo je do greške pri obnovi MediaWiki tabela u bazi podataka.\n\nZa više informacija, pogledajte evidenciju iznad. Da biste pokušali ponovo, kliknite na <strong>Nastavi</strong>.",
+       "config-upgrade-done": "Nadogradnja završena.\n\nSada možete [$1 početi koristiti Vaš wiki].\n\nAko želite prestvoriti Vašu datoteku <code>LocalSettings.php</code>, tada kliknite na dugme ispod.\nOvo <strong>nije preporučeno</strong> osim u slučaju problema s wikijem.",
+       "config-upgrade-done-no-regenerate": "Nadogradnja završena.\n\nSad možete [$1 početi da koristite wiki].",
+       "config-regenerate": "Prestvori LocalSettings.php →",
+       "config-show-table-status": "Upit <code>SHOW TABLE STATUS</code> nije uspeo!",
+       "config-unknown-collation": "<strong>Upozorenje:</strong> Baza podataka koristi neprepoznatu uputnu poredbu.",
+       "config-db-web-account": "Račun baze podataka za mrežni pristup",
+       "config-db-web-help": "Odaberite korisničko ime i lozinku koje će koristiti mrežni poslužitelj za povezivanje s poslužiteljem baze podataka tijekom redovitog rada s wikijem.",
+       "config-db-web-account-same": "Koristi isti račun iz uspostave",
+       "config-db-web-create": "Napravi račun ako već ne postoji",
+       "config-db-web-no-create-privs": "Račun koji ste naveli za uspostavu nema dovoljne privilegije za da stvori račun.\nOvdje morate navesti postojeći račun.",
+       "config-mysql-engine": "Skladišni pogon:",
+       "config-mysql-innodb": "InnoDB (preporučeno)",
+       "config-mysql-myisam": "MyISAM",
+       "config-mysql-myisam-dep": "<strong>Upozorenje:</strong> Odabrali ste MyISAM kao skladišni pogon za MySQL. Ali ne preporučuje se za MediaWiki jer:\n* jedva podržava istovremenost iz zaključavanja tabela\n* vjerojatnije je da će ih druge biljke pokvariti\n* kodna baza MediaWikija ne može uvijek ispravno raditi s MyISAM-om\n\nAko vaša uspostava MySQL-a podržava InnoDB, tada seriozno preporučujemo da je koristite umjesto MyISAM.\nAko vaša uspostava MySQL-a ne podržava InnoDB, vjerojatno je vrijeme za nadogradnju.",
+       "config-mysql-only-myisam-dep": "<strong>Upozorenje:</strong> MyISAM je jedini dostupan skladišni pogon za MySQL na ovom stroju, a ovo se ne preporučuje za uporabu s MediaWiki, jer:\n* skoro ne podržava istovremeno izvršavanje zadataka zbog zaključavanja tablica\n* više osjetljiv na kvarenje od drugih pogona \n* kodna baza MediaWIkija ne radi uvijek ispravno s MyISAM-om\nVaša MySQL uspostava ne podržava InnoDB. Možda je vrijeme da ga nadogradimo.",
        "config-admin-password": "Lozinka:",
        "mainpagetext": "<strong>MediaWiki je uspješno instaliran.</strong>",
        "mainpagedocfooter": "Za informacije o korištenju wiki softvera konzultirajte [https://meta.wikimedia.org/wiki/Help:Contents Vodič za korisnike].\n\n== Uvod u rad ==\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Lista konfiguracije postavki]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki FAQ]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Lista primatelja izdanja MediaWikija]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Lokalizirajte MediaWiki za svoj jezik]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Saznajte kako se boriti protiv spama na svojem wikiju]"
index 97288bb..5471fdb 100644 (file)
@@ -52,7 +52,7 @@
        "config-env-hhvm": "HHVM $1 je nameščen.",
        "config-unicode-using-intl": "Uporaba [https://pecl.php.net/intl razširitve PECL intl] za normalizacijo unikoda.",
        "config-memory-raised": "PHP-jev <code>memory_limit</code> je $1, dvignjen na $2.",
-       "config-apc": "[https://secure.php.net/apc APC] je nameščen",
+       "config-apc": "[https://www.php.net/apc APC] je nameščen",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] je nameščen",
        "config-diff3-bad": "Pripomočka za primerjavo besedila GNU diff3 nismo našli. To lahko zaenkrat prezrete, ampak morda boste pogosteje naleteli na spore pri urejanju.",
        "config-using-server": "Uporabljam ime strežnika \"<nowiki>$1</nowiki>\".",
index 6cac5a6..3ba7928 100644 (file)
        "config-pcre-no-utf8": "<strong>Неотклоњива грешка:</strong> Изгледа да је PCRE модул PHP-а  компајлиран без PCRE_UTF8 подршке.\nMediaWiki захтева UTF-8 подршку за исправно функционисање.",
        "config-memory-raised": "Вредност параметра <code>memory_limit</code> PHP-а износи $1, подигнута на $2.",
        "config-memory-bad": "<strong>Упозорење:</strong> Вредност параметра <code>memory_limit</code> PHP-а износи $1.\nОво је вероватно прениско.\nИнсталација можда неће успети!",
-       "config-apc": "[https://secure.php.net/apc APC] је инсталиран",
-       "config-apcu": "[https://secure.php.net/apcu APCu] је инсталиран",
+       "config-apc": "[https://www.php.net/apc APC] је инсталиран",
+       "config-apcu": "[https://www.php.net/apcu APCu] је инсталиран",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] је инсталиран",
-       "config-no-cache-apcu": "<strong>Упозорење:</strong> Није могуће пронаћи [https://secure.php.net/apcu APCu] или [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nКеширање објеката није омогућено.",
+       "config-no-cache-apcu": "<strong>Упозорење:</strong> Није могуће пронаћи [https://www.php.net/apcu APCu] или [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nКеширање објеката није омогућено.",
        "config-diff3-bad": "GNU diff3 није пронађен.",
        "config-git": "Пронађен је Git софтвер за контролу верзија: <code>$1</code>",
        "config-git-bad": "Није пронађен Git софтвер за контролу верзија.",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki подржава следеће системе база података:\n\n$1\n\nАко не видите систем који покушавате да користите на листи испод, онда пратите повезана упутства изнад како бисте омогућили подршку.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] је примарна мета за MediaWiki и најбоље је подржана. MediaWiki такође ради са [{{int:version-db-mysql-url}} MySQL-ом] и [{{int:version-db-percona-url}} Percona Server-ом], који су компатибилни са MariaDB-ом. ([https://secure.php.net/manual/en/mysqli.installation.php Како компајлирати PHP са подршком MySQL-а])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] је популаран систем база података отвореног кода кaо алтернатива MySQL-у. ([https://secure.php.net/manual/en/pgsql.installation.php Како компајлирати PHP са подршком PostgreSQL-а])",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] је лаган систем базе података који је веома добро подржан. ([https://secure.php.net/manual/en/pdo.installation.php Како компајлирати PHP са подршком SQLite-а], користи PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] је база података комерцијалних предузећа. ([https://secure.php.net/manual/en/oci8.installation.php Како компајлирати PHP са подршком OCI8-а])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] је база података комерцијалних предузећа за Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php Како компајлирати PHP са подршком SQLSRV-а])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] је примарна мета за Медијавики и најбоље је подржана. Медијавики ради и са [{{int:version-db-mysql-url}} MySQL-ом] и [{{int:version-db-percona-url}} Percona Server-ом], који су компатибилни са MariaDB-ом. ([https://www.php.net/manual/en/mysqli.installation.php Како компајлирати PHP са подршком MySQL-а])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] је популаран систем база података отвореног кода кaо алтернатива MySQL-у. ([https://www.php.net/manual/en/pgsql.installation.php Како компајлирати PHP са подршком PostgreSQL-а])",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] је лаган систем базе података који је веома добро подржан. ([https://www.php.net/manual/en/pdo.installation.php Како компајлирати PHP са подршком SQLite-а], користи PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] је база података комерцијалних предузећа. ([https://www.php.net/manual/en/oci8.installation.php Како компајлирати PHP са подршком OCI8-а])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] је база података комерцијалних предузећа за Windows. ([https://www.php.net/manual/en/sqlsrv.installation.php Како компајлирати PHP са подршком SQLSRV-а])",
        "config-header-mysql": "Подешавања MariaDB/MySQL-а",
        "config-header-postgres": "Подешавања PostgreSQL-а",
        "config-header-sqlite": "Подешавања SQLite-а",
index 3415608..0b31bca 100644 (file)
        "config-pcre-no-utf8": "<strong>Neotklonjiva greška:</strong> Izgleda da je PCRE modul PHP-a  kompajliran bez PCRE_UTF8 podrške.\nMediaWiki zahteva UTF-8 podršku za ispravno funkcionisanje.",
        "config-memory-raised": "Vrednost parametra <code>memory_limit</code> PHP-a iznosi $1, podignuta na $2.",
        "config-memory-bad": "<strong>Upozorenje:</strong> Vrednost parametra <code>memory_limit</code> PHP-a iznosi $1.\nOvo je verovatno prenisko.\nInstalacija možda neće uspeti!",
-       "config-apc": "[https://secure.php.net/apc APC] je instaliran",
-       "config-apcu": "[https://secure.php.net/apcu APCu] je instaliran",
+       "config-apc": "[https://www.php.net/apc APC] je instaliran",
+       "config-apcu": "[https://www.php.net/apcu APCu] je instaliran",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] je instaliran",
-       "config-no-cache-apcu": "<strong>Upozorenje:</strong> Nije moguće pronaći [https://secure.php.net/apcu APCu] ili [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nKeširanje objekata nije omogućeno.",
+       "config-no-cache-apcu": "<strong>Upozorenje:</strong> Nije moguće pronaći [https://www.php.net/apcu APCu] ili [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nKeširanje objekata nije omogućeno.",
        "config-diff3-bad": "GNU diff3 nije pronađen.",
        "config-git": "Pronađen je Git softver za kontrolu verzija: <code>$1</code>",
        "config-git-bad": "Nije pronađen Git softver za kontrolu verzija.",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki podržava sledeće sisteme baza podataka:\n\n$1\n\nAko ne vidite sistem koji pokušavate da koristite na listi ispod, onda pratite povezana uputstva iznad kako biste omogućili podršku.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] je primarna meta za MediaWiki i najbolje je podržana. MediaWiki takođe radi sa [{{int:version-db-mysql-url}} MySQL-om] i [{{int:version-db-percona-url}} Percona Server-om], koji su kompatibilni sa MariaDB-om. ([https://secure.php.net/manual/en/mysqli.installation.php Kako kompajlirati PHP sa podrškom MySQL-a])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] je popularan sistem baza podataka otvorenog koda kao alternativa MySQL-u. ([https://secure.php.net/manual/en/pgsql.installation.php Kako kompajlirati PHP sa podrškom PostgreSQL-a])",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] je lagan sistem baze podataka koji je veoma dobro podržan. ([https://secure.php.net/manual/en/pdo.installation.php Kako kompajlirati PHP sa podrškom SQLite-a], koristi PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] je baza podataka komercijalnih preduzeća. ([https://secure.php.net/manual/en/oci8.installation.php Kako kompajlirati PHP sa podrškom OCI8-a])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] je baza podataka komercijalnih preduzeća za Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php Kako kompajlirati PHP sa podrškom SQLSRV-a])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] je primarna meta za MediaWiki i najbolje je podržana. MediaWiki takođe radi sa [{{int:version-db-mysql-url}} MySQL-om] i [{{int:version-db-percona-url}} Percona Server-om], koji su kompatibilni sa MariaDB-om. ([https://www.php.net/manual/en/mysqli.installation.php Kako kompajlirati PHP sa podrškom MySQL-a])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] je popularan sistem baza podataka otvorenog koda kao alternativa MySQL-u. ([https://www.php.net/manual/en/pgsql.installation.php Kako kompajlirati PHP sa podrškom PostgreSQL-a])",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] je lagan sistem baze podataka koji je veoma dobro podržan. ([https://www.php.net/manual/en/pdo.installation.php Kako kompajlirati PHP sa podrškom SQLite-a], koristi PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] je baza podataka komercijalnih preduzeća. ([https://www.php.net/manual/en/oci8.installation.php Kako kompajlirati PHP sa podrškom OCI8-a])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] je baza podataka komercijalnih preduzeća za Windows. ([https://www.php.net/manual/en/sqlsrv.installation.php Kako kompajlirati PHP sa podrškom SQLSRV-a])",
        "config-header-mysql": "Podešavanja MariaDB/MySQL-a",
        "config-header-postgres": "Podešavanja PostgreSQL-a",
        "config-header-sqlite": "Podešavanja SQLite-a",
index a313371..e2cb99e 100644 (file)
        "config-pcre-no-utf8": "'''Kritiskt:''' PHP:s PCRE-modul verkar vara kompilerat utan PCRE_UTF8-stöd.\nMediaWiki kräver stöd för UTF-8 för att fungera korrekt.",
        "config-memory-raised": "PHPs <code>memory_limit</code> är $1, ökad till $2.",
        "config-memory-bad": "''' Varning:''' PHP:s <code>memory_limit</code> är $1.\nDetta är förmodligen för lågt.\nInstallationen kan misslyckas!",
-       "config-apc": "[https://secure.php.net/apc APC] är installerat",
-       "config-apcu": "[https://secure.php.net/apcu APCu] är installerat",
+       "config-apc": "[https://www.php.net/apc APC] är installerat",
+       "config-apcu": "[https://www.php.net/apcu APCu] är installerat",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] är installerat",
-       "config-no-cache-apcu": "<strong>Varning:</strong> Kunde inte hitta [https://secure.php.net/apcu APCu] eller [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nCachelagring av objekt är inte aktiverat.",
+       "config-no-cache-apcu": "<strong>Varning:</strong> Kunde inte hitta [https://www.php.net/apcu APCu] eller [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nCachelagring av objekt är inte aktiverat.",
        "config-mod-security": "'''Varning:''' Din webbserver har [https://modsecurity.org/ mod_security] aktiverat. Om felaktigt konfigurerat kan den skapa problem för MediaWiki eller annan programvara som tillåter användaren att posta godtyckligt innehåll.\nTitta på [https://modsecurity.org/documentation/ mod_security-dokumentationen] eller kontakta din värd om du påträffar slumpmässiga fel.",
        "config-diff3-bad": "Inget verktyg för att jämföra GNU diff3-text hittades. Du kan ignorera detta för tillfället, men då kan du stöta på redigeringskonflikter mer frekvent.",
        "config-git": "Hittade Git-mjukvara för versionskontroll: <code>$1</code>.",
@@ -87,7 +87,7 @@
        "config-using-32bit": "<strong>Varning:</strong> ditt system verkar vara en 32-bitarsversion. Detta [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:32-bit rekommenderas inte].",
        "config-db-type": "Databastyp:",
        "config-db-host": "Databasvärd:",
-       "config-db-host-help": "Om din databasserver är på en annan server, ange då värdnamnet eller IP-adressen här.\n\nOm du använder ett delat webbhotell, bör din leverantör ge dig rätt värdnamn i deras dokumentation.\n\nOm du installerar på en Windowsserver och använder MySQL, kanske \"localhost\" inte fungerar för servernamnet. Om det inte gör det försök med \"127.0.0.1\" som den lokala IP-adressen.\n\nOm du använder PostgreSQL, lämna detta fält blankt för att ansluta via en Unix-socket.",
+       "config-db-host-help": "Om din databasserver är på en annan server, ange då värdnamnet eller IP-adressen här.\n\nOm du använder ett delat webbhotell, bör din leverantör ge dig rätt värdnamn i deras dokumentation.\n\nOm du använder MySQL, kanske \"localhost\" inte fungerar för servernamnet. Om det inte gör det försök med \"127.0.0.1\" som den lokala IP-adressen.\n\nOm du använder PostgreSQL, lämna detta fält blankt för att ansluta via en Unix-socket.",
        "config-db-host-oracle": "Databas TNS:",
        "config-db-host-oracle-help": "Ange ett giltigt [http://download.oracle.com/docs/cd/B28359_01/network.111/b28317/tnsnames.htm Local Connect Name]; en tnsnames.ora-fil måste vara synlig för denna installation.<br />Om du använder klientbibliotek 10g eller nyare kan du också använda [http://download.oracle.com/docs/cd/E11882_01/network.112/e10836/naming.htm Easy Connect] namngivningsmetoden.",
        "config-db-wiki-settings": "Identifiera denna wiki",
        "config-type-mysql": "MariaDB, MySQL eller kompatibelt",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki stöder följande databassystem:\n\n$1\n\nOm du inte ser det databassystem som du försöker använda nedanstående, följ då instruktionerna länkade ovan för aktivera stöd för det.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] är det primära målet för MediaWiki och stöds bäst. MediaWiki fungerar även med [{{int:version-db-mysql-url}} MySQL] och [{{int:version-db-percona-url}} Percona Server], som är kompatibla med MariaDB. ([https://secure.php.net/manual/en/mysqli.installation.php Hur man kompilerar PHP med stöd för MySQL])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] är ett populärt databassystem med öppen källkod som ett alternativ till MySQL. ([https://secure.php.net/manual/en/pgsql.installation.php Hur man kompilerar PHP med PostgreSQL-stöd])",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] är en lättviktsdatabassystem med väldigt bra stöd. ([https://secure.php.net/manual/en/pdo.installation.php Hur man kompilerar PHP med SQLite stöd], använder PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] är en kommersiellt databas för företag. ([https://secure.php.net/manual/en/oci8.installation.php Hur man kompilerar PHP med OCI8 stöd])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] är en kommersiellt databas för företag för Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php Hur man kompilerar PHP med SQLSRV stöd])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] är det primära målet för MediaWiki och stöds bäst. MediaWiki fungerar även med [{{int:version-db-mysql-url}} MySQL] och [{{int:version-db-percona-url}} Percona Server], som är kompatibla med MariaDB. ([https://www.php.net/manual/en/mysqli.installation.php Hur man kompilerar PHP med stöd för MySQL])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] är ett populärt databassystem med öppen källkod som ett alternativ till MySQL. ([https://www.php.net/manual/en/pgsql.installation.php Hur man kompilerar PHP med PostgreSQL-stöd])",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] är en lättviktsdatabassystem med väldigt bra stöd. ([https://www.php.net/manual/en/pdo.installation.php Hur man kompilerar PHP med SQLite stöd], använder PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] är en kommersiellt databas för företag. ([https://www.php.net/manual/en/oci8.installation.php Hur man kompilerar PHP med OCI8 stöd])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] är en kommersiellt databas för företag för Windows. ([https://www.php.net/manual/en/sqlsrv.installation.php Hur man kompilerar PHP med SQLSRV stöd])",
        "config-header-mysql": "MariaDB/MySQL-inställningar",
        "config-header-postgres": "PostgreSQL-inställningar",
        "config-header-sqlite": "SQLite-inställningar",
        "config-invalid-db-server-oracle": "Ogiltig databas-TNS \"$1\".\nAnvända antingen \"TNS Name\" eller en \"Easy Connect\"-sträng ([http://docs.oracle.com/cd/E11882_01/network.112/e10836/naming.htm Oracles namngivningsmetoder]).",
        "config-invalid-db-name": "\"$1\" är ett ogiltigt databasnamn.\nAnvänd bara ASCII-bokstäver (a-z, A-Z), siffror (0-9), understreck (_) och bindestreck (-).",
        "config-invalid-db-prefix": "\"$1\" är ett ogiltigt databasprefix.\nAnvänd bara ASCII-bokstäver (a-z, A-Z), siffror (0-9), understreck (_) och bindestreck (-).",
-       "config-connection-error": "$1.\n\nKontrollera värd, användarnamn och lösenord och försök igen.",
+       "config-connection-error": "$1.\n\nKontrollera värd, användarnamn och lösenord och försök igen. Om du använder \"localhost\" som databasvärden, försök använda \"127.0.0.1\" istället (eller tvärtom).",
        "config-invalid-schema": "\"$1\" är ett ogiltigt schema för MediaWiki.\nAnvänd bara ASCII-bokstäver (a-z, A-Z), siffror (0-9), understreck (_) och bindestreck (-).",
        "config-db-sys-create-oracle": "Installationsprogrammet stöder endast användningen av ett SYSDBA-konto för att skapa ett nytt konto.",
        "config-db-sys-user-exists-oracle": "Användarkontot \"$1\" finns redan. SYSDBA kan endast användas för att skapa ett nytt konto!",
        "config-install-done": "<strong>Grattis!</strong>\nDu har installerat MediaWiki.\n\nInstallationsprogrammet har genererat filen <code>LocalSettings.php</code>.\nDet innehåller alla dina konfigurationer.\n\nDu kommer att behöva ladda ner den och placera den i roten för din wiki-installation (samma katalog som index.php). Nedladdningen borde ha startats automatiskt.\n\nOm ingen nedladdning erbjöds, eller om du har avbrutit det kan du starta om nedladdningen genom att klicka på länken nedan:\n\n$3\n\n<strong>OBS</strong>: Om du inte gör detta nu, kommer denna genererade konfigurationsfil inte vara tillgänglig för dig senare om du avslutar installationen utan att ladda ned den.\n\nNär det är klart, kan du <strong>[$2 gå in på din wiki]</strong>",
        "config-install-done-path": "<strong>Grattis!</strong>\nDu har installerat MediaWiki.\n\nInstallationsprogrammet har genererat filen <code>LocalSettings.php</code>.\nDet innehåller alla dina konfigurationer.\n\nDu kommer att behöva ladda ner den och placera den i <code>$4</code>. Nedladdningen borde ha startats automatiskt.\n\nOm ingen nedladdning erbjöds, eller om du har avbrutit det kan du starta om nedladdningen genom att klicka på länken nedan:\n\n$3\n\n<strong>OBS</strong>: Om du inte gör detta nu, kommer denna genererade konfigurationsfil inte vara tillgänglig för dig senare om du avslutar installationen utan att ladda ned den.\n\nNär det är klart, kan du <strong>[$2 gå in på din wiki]</strong>",
        "config-install-success": "MediaWiki har installerats. Du kan nu besöka <$1$2> för att se din wiki.\nOm du undrar någonting, kolla in vår lista över vanliga ställda frågor:\n<https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ> eller använda något supportforum som länkas på sidan.",
+       "config-install-db-success": "Databasen har konfigurerats",
        "config-download-localsettings": "Ladda ner <code>LocalSettings.php</code>",
        "config-help": "hjälp",
        "config-help-tooltip": "klicka för att expandera",
index dd4bd0c..1460fec 100644 (file)
@@ -14,7 +14,7 @@
        "config-localsettings-cli-upgrade": "ఓ <code>LocalSettings.php</code> ఫైలు కనబడింది.\nఈ స్థాపనను ఉన్నతీకరించడానికి, దాని బదులు <code>update.php</code> ను రన్ చెయ్యండి.",
        "config-localsettings-key": "ఉన్నతీకరణ కీ:",
        "config-localsettings-badkey": "మీరిచ్చిన కీ తప్పు.",
-       "config-upgrade-key-missing": "MediaWiki యొక్క ఒక స్థాపన కనబడింది.\nదాన్ని ఉన్నతీకరించడానికి, కింది లైనును <code>LocalSettings.php</code> లో అట్టడుగున ఉంచండి:\n\n$1",
+       "config-upgrade-key-missing": "ఇప్పటికే ఉన్న MediaWiki స్థాపన కనబడింది.\nదాన్ని నవీకరించడానికి, కింది లైనును <code>LocalSettings.php</code> లో అట్టడుగున ఉంచండి:\n\n$1",
        "config-localsettings-incomplete": "ఇప్పటి <code>LocalSettings.php</code> అసంపూర్తిగా ఉన్నట్లుగా కనబడుతోంది.\n$1 చరరాశిని సెట్ చెయ్యలేదు.\nఈ చరరాశిని సెట్ చేస్తూ <code>LocalSettings.php</code> ను మార్చి, \"{{int:Config-continue}}\" ను నొక్కండి.",
        "config-localsettings-connection-error": "<code>LocalSettings.php</code> లో ఇచ్చిన సెట్టింగులను వాడుతూ డేటాబేసుకు కనెక్టు కాబోతే, లోపం తలెత్తింది. ఈ సెట్టింగులను సరిచేసి మళ్ళీ ప్రయత్నించండి.\n\n$1",
        "config-session-error": "సెషన్ను ప్రారంభించబోతే లోపం జరిగింది: $1",
@@ -53,7 +53,7 @@
        "config-outdated-sqlite": "<strong>హెచ్చరిక:</strong> మీ వద్ద SQLite $1 ఉంది. అదికావలసిన వెర్షను $2 కంటే దిగువది. SQLite అందుబాటులో ఉండదు.",
        "config-memory-raised": "PHP యొక్క <code>memory_limit</code> $1, దాన్ని $2 కి పెంచాం.",
        "config-memory-bad": "<strong>హెచ్చరిక:</strong> PHP యొక్క <code>memory_limit</code> $1.\nబహుశా ఇది మరీ తక్కువ.\nస్థాపన విఫలం కావచ్చు!",
-       "config-apc": "[https://secure.php.net/apc APC] స్థాపించబడింది",
+       "config-apc": "[https://www.php.net/apc APC] స్థాపించబడింది",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] స్థాపించబడింది",
        "config-diff3-bad": "GNU diff3 కనబడలేదు.",
        "config-no-uri": "<strong>లోపం:</strong> ప్రస్తుత URI ఏమిటో నిర్ధారించలేకపోయాం.\nస్థాపన ఆగిపోయింది.",
@@ -89,7 +89,7 @@
        "config-type-mysql": "MySQL (లేదా సరిపోయేది)",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki కింది డేటాబేసు వ్యవస్థలకు అనుకూలిస్తుంది:\n\n$1\n\nమీరు వాడదలచిన డేటాబేసు వ్యవస్ కింది జాబితాలో లేకపోతే, పైన లింకు ద్వారా ఇచ్చిన సూచనలను పాటించి, అనుకూలతలను సాధించండి.",
-       "config-dbsupport-postgres": "* MySQL కు ప్రత్యామ్నాయంగా [{{int:version-db-postgres-url}} PostgreSQL] ప్రజామోదం పొందిన ఓపెన్‍సోర్సు డేటాబేసు వ్యవస్థ. దానిలో చిన్న చితకా లోపాలుండే అవకాశం ఉంది. అందుచేత దాన్ని ఉత్పాదక రంగంలో వాడవచ్చని చెప్పలేం.  ([https://secure.php.net/manual/en/pgsql.installation.php How to compile PHP with PostgreSQL support])",
+       "config-dbsupport-postgres": "* MySQL కు ప్రత్యామ్నాయంగా [{{int:version-db-postgres-url}} PostgreSQL] ప్రజామోదం పొందిన ఓపెన్‍సోర్సు డేటాబేసు వ్యవస్థ. దానిలో చిన్న చితకా లోపాలుండే అవకాశం ఉంది. అందుచేత దాన్ని ఉత్పాదక రంగంలో వాడవచ్చని చెప్పలేం.  ([https://www.php.net/manual/en/pgsql.installation.php How to compile PHP with PostgreSQL support])",
        "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] ఓ తేలికైన డేటాబేసు వ్యవస్థ. దానికి చక్కటి అనుకూలతలున్నాయి. ([http://www.php.net/manual/en/pdo.installation.php How to compile PHP with SQLite support], uses PDO)",
        "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] ఒక వాణిజ్యపరంగా సంస్థాగతంగా వాడదగ్గ డేటాబేసు. ([http://www.php.net/manual/en/oci8.installation.php How to compile PHP with OCI8 support])",
        "config-header-mysql": "MySQL అమరికలు",
        "config-mssql-auth": "ఆథెంటికేషన్ రకం:",
        "config-mssql-sqlauth": "SQL Server ఆథెంటికేషన్",
        "config-mssql-windowsauth": "విండోస్ ఆథెంటికేషన్",
-       "config-site-name": "విà°\95à±\80 à°¯à±\8aà°\95à±\8dà°\95 à°ªà±\87à°°à±\81:",
+       "config-site-name": "వికీ పేరు:",
        "config-site-name-help": "ఇది బ్రౌజరు టిటిలుబారు లోను, అనేక ఇతర చోట్లా కనిపిస్తుంది.",
        "config-site-name-blank": "ఓ సైటు పేరును ఇవ్వండి.",
        "config-project-namespace": "ప్రాజెక్టు పేరుబరి:",
index 115f4e6..a4e2ac0 100644 (file)
        "config-pcre-no-utf8": "<strong>ข้อผิดพลาดร้ายแรง:</strong> โมดูล PCRE ของ PHP ดูเหมือนจะถูกคอมไพล์โดยไม่มีการรองรับ PCRE_UTF8\nMediaWiki ต้องการการรองรับ UTF-8 เพื่อให้ทำงานได้อย่างถูกต้อง",
        "config-memory-raised": "<code>memory_limit</code> ของ PHP คือ $1 ได้เพิ่มเป็น $2",
        "config-memory-bad": "<strong>คำเตือน:</strong> <code>memory_limit</code> ของ PHP คือ $1.\nเป็นไปได้ว่ามันอาจต่ำเกินไป\nการติดตั้งอาจล้มเหลวได้!",
-       "config-apc": "มี [https://secure.php.net/apc APC] ติดตั้งอยู่",
-       "config-apcu": "มี [https://secure.php.net/apcu APCu] ติดตั้งอยู่",
+       "config-apc": "มี [https://www.php.net/apc APC] ติดตั้งอยู่",
+       "config-apcu": "มี [https://www.php.net/apcu APCu] ติดตั้งอยู่",
        "config-wincache": "มี [https://www.iis.net/downloads/microsoft/wincache-extension WinCache] ติดตั้งอยู่",
-       "config-no-cache-apcu": "<strong>คำเตือน:</strong> ไม่พบ [https://secure.php.net/apcu APCu] [http://xcache.lighttpd.net/ XCache] หรือ [https://www.iis.net/downloads/microsoft/wincache-extension WinCache]\nการแคชวัตถุไม่ได้ถูกเปิดใช้งาน",
+       "config-no-cache-apcu": "<strong>คำเตือน:</strong> ไม่พบ [https://www.php.net/apcu APCu] [http://xcache.lighttpd.net/ XCache] หรือ [https://www.iis.net/downloads/microsoft/wincache-extension WinCache]\nการแคชวัตถุไม่ได้ถูกเปิดใช้งาน",
        "config-mod-security": "<strong>คำเตือน:</strong> เว็บเซิร์ฟเวอร์ของคุณมี [https://modsecurity.org/ mod_security]/mod_security2 เปิดใช้งานอยู่ การตั้งค่าทั่วไปหลายอย่างของสิ่งนี้จะก่อให้เกิดปัญหาสำหรับ MediaWiki และซอฟต์แวร์อื่นที่อนุญาตให้ผู้ใช้สามารถโพสต์เนื้อหาได้ตามที่ผู้ใช้\nหากเป็นไปได้ ควรปิดใช้งานคุณลักษณะนี้ หรือมิฉะนั้นก็ อ้างไปยัง[https://modsecurity.org/documentation/ เอกสารกำกับการใช้งาน mod_security] หรือติดต่อการสนับสนุนจากโฮสต์ของคุณ ถ้าคุณพบข้อผิดพลาดโดยสุ่ม",
        "config-diff3-bad": "ไม่พบโปรแกรมเปรียบเทียบข้อความ GNU diff3 คุณสามารถละเว้นสิ่งนี้ได้ในตอนนี้ แต่อาจพบข้อขัดแย้งในการแก้ไขบ่อยครั้งกว่า",
        "config-git": "พบซอฟต์แวร์ควบคุมรุ่น Git: <code>$1</code>",
        "config-type-mysql": "MySQL (หรือที่เข้ากันได้)",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki สนับสนุนระบบฐานข้อมูลต่อไปนี้:\n\n$1\n\nถ้าคุณไม่พบระบบฐานข้อมูลที่คุณกำลังพยายามใช้ในรายการด้านล่างนี้ ให้ทำตามคำแนะนำที่เชื่อมโยงด้านบนเพื่อเปิดใช้งานการสนับสนุน",
-       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] คือเป้าหมายหลักสำหรับ MediaWiki และได้รับการสนับสนุนดีที่สุด MediaWiki ยังคงสามารถใช้ได้ร่วมกับ [{{int:version-db-mariadb-url}} MariaDB] และ [{{int:version-db-percona-url}} Percona Server] ซึ่งเข้ากันได้กับ MySQL ([https://secure.php.net/manual/en/mysqli.installation.php วิธีการคอมไพล์ PHP ด้วยการสนับสนุน MySQL])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] คือระบบฐานข้อมูลแบบโอเพนซอร์สที่ได้รับความนิยมสูงที่สามารถใช้แทน MySQL ได้ ([https://secure.php.net/manual/en/pgsql.installation.php วิธีการคอมไพล์ PHP ด้วยการสนับสนุน PostgreSQL])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] คือเป้าหมายหลักสำหรับ MediaWiki และได้รับการสนับสนุนดีที่สุด MediaWiki ยังคงสามารถใช้ได้ร่วมกับ [{{int:version-db-mariadb-url}} MariaDB] และ [{{int:version-db-percona-url}} Percona Server] ซึ่งเข้ากันได้กับ MySQL ([https://www.php.net/manual/en/mysqli.installation.php วิธีการคอมไพล์ PHP ด้วยการสนับสนุน MySQL])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] คือระบบฐานข้อมูลแบบโอเพนซอร์สที่ได้รับความนิยมสูงที่สามารถใช้แทน MySQL ได้ ([https://www.php.net/manual/en/pgsql.installation.php วิธีการคอมไพล์ PHP ด้วยการสนับสนุน PostgreSQL])",
        "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] คือระบบฐานข้อมูลขนาดเล็กที่ได้รับการสนับสนุนดีมาก ([http://www.php.net/manual/en/pdo.installation.php วิธีการคอมไพล์ PHP ด้วยการสนับสนุน SQLite], ใช้ PDO)",
        "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] คือฐานข้อมูลสำหรับองค์กรพาณิชย์ ([http://www.php.net/manual/en/oci8.installation.php วิธีการคอมไพล์ PHP ด้วยการสนับสนุน OCI8])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] คือฐานข้อมูลสำหรับองค์กรพาณิชย์สำหรับ Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php วิธีการคอมไพล์ PHP ด้วยการสนับสนุน SQLSRV])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] คือฐานข้อมูลสำหรับองค์กรพาณิชย์สำหรับ Windows. ([https://www.php.net/manual/en/sqlsrv.installation.php วิธีการคอมไพล์ PHP ด้วยการสนับสนุน SQLSRV])",
        "config-header-mysql": "การตั้งค่า MySQL",
        "config-header-postgres": "การตั้งค่า PostgreSQL",
        "config-header-sqlite": "การตั้งค่า SQLite",
index 3614333..fe53fa1 100644 (file)
@@ -63,7 +63,7 @@
        "config-pcre-no-utf8": "'''Malubha''': Tila tinipon ang modyul na PCRE ng PHP na wala ang suporta ng PCRE_UTF8.\nNangangailangan ang MediaWiki ng suporta ng UTF-8 upang maging tama ang pag-andar.",
        "config-memory-raised": "Ang <code>hangganan_ng_alaala</code> ng PHP ay $1, itinaas sa $2.",
        "config-memory-bad": "'''Babala:''' Ang <code>hangganan_ng_alaala</code> ng PHP ay $1.\nIto ay maaaring napakababa.\nMaaaring mabigo ang pagluluklok!",
-       "config-apc": "Ininstala na ang [https://secure.php.net/apc APC]",
+       "config-apc": "Ininstala na ang [https://www.php.net/apc APC]",
        "config-wincache": "Ininstala na ang [https://www.iis.net/downloads/microsoft/wincache-extension WinCache]",
        "config-mod-security": "'''Babala''': Ang tagapaghain mo ng sangkasaputan ay pinagana na mayroong [https://modsecurity.org/ mod_security]. Kung mali ang kaayusan, makapagdurulot ito ng mga suliranin para sa MediaWiki o ibang mga sopwer na nagpapahintulot sa mga tagagamit na magpaskil ng hindi makatwirang nilalaman.\nSumangguni sa [https://modsecurity.org/documentation/ mod_security kasulatan] o makipag-ugnayan sa suporta ng iyong tagapagpasinaya kapag nakatagpo ng alin mang mga kamalian.",
        "config-diff3-bad": "Hindi natagpuan ang GNU diff3.",
        "config-type-sqlite": "SQLite",
        "config-type-oracle": "Oracle",
        "config-support-info": "Sinusuportahan ng MediaWiki ang sumusunod na mga sistema ng kalipunan ng dato:\n\n$1\n\nKung hindi mo makita ang sistema ng kalipunan ng dato na sinusubukan mong gamitin na nakatala sa ibaba, kung gayon ay sundi ang mga tagubilin na nakakawing sa itaas upang mapagana ang suporta,",
-       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] ang pangunahing puntirya para sa MediaWiki at ang pinaka sinusuportahan. Gumagana rin ang MediaWiki [{{int:version-db-mariadb-url}} MariaDB] at sa [{{int:version-db-percona-url}} Percona Server], na tugma sa MySQL.  ([https://secure.php.net/manual/en/mysql.installation.php Paano magtipon ng PHP na mayroong suporta ng MySQL])",
-       "config-dbsupport-postgres": "* Ang [{{int:version-db-postgres-url}} PostgreSQL] ay isang bantog na sistema ng kalipunan ng dato na bukas ang pinagmulan na panghalili sa MySQL. ([https://secure.php.net/manual/en/pgsql.installation.php Paano magtipon ng PHP na mayroong suporta ng PostgreSQL]).",
+       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] ang pangunahing puntirya para sa MediaWiki at ang pinaka sinusuportahan. Gumagana rin ang MediaWiki [{{int:version-db-mariadb-url}} MariaDB] at sa [{{int:version-db-percona-url}} Percona Server], na tugma sa MySQL.  ([https://www.php.net/manual/en/mysql.installation.php Paano magtipon ng PHP na mayroong suporta ng MySQL])",
+       "config-dbsupport-postgres": "* Ang [{{int:version-db-postgres-url}} PostgreSQL] ay isang bantog na sistema ng kalipunan ng dato na bukas ang pinagmulan na panghalili sa MySQL. ([https://www.php.net/manual/en/pgsql.installation.php Paano magtipon ng PHP na mayroong suporta ng PostgreSQL]).",
        "config-dbsupport-sqlite": "* Ang [{{int:version-db-sqlite-url}} SQLite] ay isang magaan ang timbang na sistema ng kalipunan ng dato na sinusuportahan nang napaka mainam. ([http://www.php.net/manual/en/pdo.installation.php Paano magtipon ng PHP na mayroong suporta ng SQLite], gumagamit ng PDO)",
        "config-dbsupport-oracle": "* Ang [{{int:version-db-oracle-url}} Oracle] ay isang kalipunan ng dato ng kasigasigang pangkalakal. ([http://www.php.net/manual/en/oci8.installation.php Paano magtipunan ng PHP na mayroong suporta ng OCI8])",
        "config-header-mysql": "Mga katakdaan ng MariaDB/MySQL",
index c8732e2..feb682a 100644 (file)
        "config-pcre-no-utf8": "<strong>Önemli hata:</strong> PHP'nin PCRE modülü PCRE_UTF8 desteği olmadan derlenmiş gözüküyor.\nMediaWiki'nin doğru çalışabilmesi için UTF-8 desteği gereklidir.",
        "config-memory-raised": "PHP'nin <code>memory_limit</code> (hafıza sınırı) değeri $1, $2'ye yükseltildi.",
        "config-memory-bad": "<strong>Uyarı:</strong> PHP'nin <code>memory_limit</code> (hafıza sınırı) değeri $1.\nBu büyük ihtimalle çok düşük.\nKurulum başarısız olabilir!",
-       "config-apc": "[https://secure.php.net/apc APC] kuruldu",
-       "config-apcu": "[https://secure.php.net/apcu APCu] kuruldu",
+       "config-apc": "[https://www.php.net/apc APC] kuruldu",
+       "config-apcu": "[https://www.php.net/apcu APCu] kuruldu",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] kuruldu",
-       "config-no-cache-apcu": "<strong>Uyarı:</strong> [https://secure.php.net/apcu APCu] ya da [https://www.iis.net/downloads/microsoft/wincache-extension WinCache] kurulumu bulunamadı.\nNesne önbellekleme etkin değil.",
+       "config-no-cache-apcu": "<strong>Uyarı:</strong> [https://www.php.net/apcu APCu] ya da [https://www.iis.net/downloads/microsoft/wincache-extension WinCache] kurulumu bulunamadı.\nNesne önbellekleme etkin değil.",
        "config-mod-security": "<strong>'''Uyarı:'''</strong> Web sunucunuz [https://modsecurity.org/mod_security2 mod_security] etkin. Bunun birçok yaygın yapılandırması bulunur ve eğer yanlış yapılandırılmış ise, bu MediaWiki ve kullanıcılara isteğe bağlı içerik göndermesine izin veren diğer yazılımlar için sorun oluşturabilir.\nMümkünse bu devre dışı bırakılmalıdır. Aksi takdirde rastgele hatalar alırsanız [https://modsecurity.org/documentation/ mod_security belgelemesine] bakın ya da sunucunuzun desteğine başvurun.",
        "config-diff3-bad": "GNU diff3 bulunamadı.",
        "config-git": "Sürüm kontrol yazılımı Git bulundu: <code>$1</code>.",
index 5565354..bc222a5 100644 (file)
@@ -29,7 +29,7 @@
        "config-restart": "Әйе, яңадан башларга",
        "config-env-php": "PHP $1 куелды.",
        "config-env-hhvm": "HHVM $1 куелды.",
-       "config-apc": "[https://secure.php.net/apc APC] куелды",
+       "config-apc": "[https://www.php.net/apc APC] куелды",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] куелды",
        "config-diff3-bad": "GNU diff3 табылмады.",
        "config-git": "Git юрамалар идарә итү системасы табылды: <code>$1</code>.",
index d9e5cd7..5a88deb 100644 (file)
@@ -14,7 +14,8 @@
                        "Piramidion",
                        "Macofe",
                        "Movses",
-                       "Vlad5250"
+                       "Vlad5250",
+                       "Gzhegozh"
                ]
        },
        "config-desc": "Інсталятор MediaWiki",
        "config-pcre-no-utf8": "'''Помилка''': PCRE-модуть PHP, вочевидь, було зібрано без підтримки PCRE_UTF8.\nMediaWiki вимагає підтримку UTF-8 для коректної роботи.",
        "config-memory-raised": "Обмеження пам'яті PHP (<code>memory_limit</code>) $1, піднято до $2.",
        "config-memory-bad": "'''Увага:''' Розмір пам'яті PHP (<code>memory_limit</code>) становить $1.\nІмовірно, це замало.\nВстановлення може не вдатись!",
-       "config-apc": "[https://secure.php.net/apc APC] встановлено",
-       "config-apcu": "[https://secure.php.net/apcu APCu] встановлено",
+       "config-apc": "[https://www.php.net/apc APC] встановлено",
+       "config-apcu": "[https://www.php.net/apcu APCu] встановлено",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] встановлено",
-       "config-no-cache-apcu": "<strong>Увага:</strong> Не вдалося знайти [https://secure.php.net/apcu APCu] чи [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nКешування об'єктів не ввімкнено.",
+       "config-no-cache-apcu": "<strong>Увага:</strong> Не вдалося знайти [https://www.php.net/apcu APCu] чи [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nКешування об'єктів не ввімкнено.",
        "config-mod-security": "'''Увага''': на Вашому веб-сервері увімкнено [https://modsecurity.org/ mod_security]. У разі неправильних налаштувать, він може викликати проблеми MediaWiki або іншого ПЗ, яке дозволяє користувачам надсилати довільний вміст.\nЗверніться до [https://modsecurity.org/documentation/ документації mod_security] або підтримки Вашого хостера, якщо під час роботи виникають незрозумілі помилки.",
        "config-diff3-bad": "УтилітуGNU diff3, призначену для порівняння текстів, не знайдено. Можете поки що це проігнорувати, але згодом, ймовірно, будете частіше натрапляти на конфлікти редагувань.",
        "config-git": "Знайшов програму управління версіями Git: <code>$1</code>.",
        "config-type-mysql": "\nMariaDB, MySQL (або сумісні)",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki підтримує такі системи баз даних:\n\n$1\n\nЯкщо Ви не бачите серед перерахованих систему баз даних, яку використовуєте, виконайте вказівки, вказані вище, щоб увімкнути підтримку.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] є основною ціллю для MediaWiki і найкраще підтримується.  MediaWiki також працює з [{{int:version-db-mysql-url}} MySQL] та [{{int:version-db-percona-url}} Percona Server], які сумісні з MariaDB.  ([https://secure.php.net/manual/en/mysqli.installation.php Як зібрати PHP з підтримкою MySQL])",
-       "config-dbsupport-postgres": "*  [{{int:version-db-postgres-url}} PostgreSQL] — популярна відкрита СУБД, альтернатива MySQL. ([https://secure.php.net/manual/en/pgsql.installation.php як зібрати PHP з допомогою PostgreSQL]).",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] є основною ціллю для MediaWiki і найкраще підтримується.  MediaWiki також працює з [{{int:version-db-mysql-url}} MySQL] та [{{int:version-db-percona-url}} Percona Server], які сумісні з MariaDB.  ([https://www.php.net/manual/en/mysqli.installation.php Як зібрати PHP з підтримкою MySQL])",
+       "config-dbsupport-postgres": "*  [{{int:version-db-postgres-url}} PostgreSQL] — популярна відкрита СУБД, альтернатива MySQL. ([https://www.php.net/manual/en/pgsql.installation.php як зібрати PHP з допомогою PostgreSQL]).",
        "config-dbsupport-sqlite": "*  [{{int:version-db-sqlite-url}} SQLite] — легка система баз даних, яка дуже добре підтримується. ([http://www.php.net/manual/en/pdo.installation.php Як зібрати PHP з допомогою SQLite], що використовує PDO)",
        "config-dbsupport-oracle": "*  [{{int:version-db-oracle-url}} Oracle] — комерційна база даних масштабу підприємства. ([http://www.php.net/manual/en/oci8.installation.php Як зібрати PHP з підтримкою OCI8])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] — це комерційна база даних для Windows масштабу підприємства. ([https://secure.php.net/manual/en/sqlsrv.installation.php Як зібрати PHP з підтримкою SQLSRV])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] — це комерційна база даних для Windows масштабу підприємства. ([https://www.php.net/manual/en/sqlsrv.installation.php Як зібрати PHP з підтримкою SQLSRV])",
        "config-header-mysql": "Налаштування MariaDB/MySQL",
        "config-header-postgres": "Налаштування PostgreSQL",
        "config-header-sqlite": "Налаштування SQLite",
        "config-install-begin": "Натискаючи \"{{int:config-continue}}\", Ви розпочинаєте встановлення MediaWiki.\nЯкщо Ви все ще хочете внести зміни, натисніть \"{{int:config-back}}\".",
        "config-install-step-done": "виконано",
        "config-install-step-failed": "не вдалося",
-       "config-install-extensions": "У Ñ\82омÑ\83 Ñ\87иÑ\81лÑ\96 розширення",
+       "config-install-extensions": "Ð\97окÑ\80ема розширення",
        "config-install-database": "Налаштування бази даних",
        "config-install-schema": "Створення схеми",
        "config-install-pg-schema-not-exist": "Схеми PostgreSQL не існує.",
        "config-install-done": "<strong>Вітаємо!</strong>\nВи успішно встановили MediaWiki.\n\nІнсталятор згенерував файл <code>LocalSettings.php</code>, який містить усі Ваші налаштування.\n\nВам необхідно завантажити його і помістити у кореневу папку Вашої вікі (туди ж, де index.php). Завантаження мало початись автоматично.\n\nЯкщо завантаження не почалось або Ви його скасували, можете заново його почати, натиснувши на посилання внизу:\n\n$3\n\n<strong>Примітка</strong>: Якщо Ви не зробите цього зараз, цей файл не буде доступним пізніше, коли Ви вийдете з встановлення, не скачавши його.\n\nПісля виконання дій, описаних вище, Ви зможете <strong>[$2 увійти у свою вікі]</strong>.",
        "config-install-done-path": "<strong>Вітаємо!</strong>\nВи встановили Медіавікі.\n\nІнсталятор створив файл <code>LocalSettings.php</code>.\nУ ньому містяться всі Ваші налаштування.\n\nВам потрібно завантажити його й помістити в <code>$4</code>. Завантаження повинно було автоматично розпочатись.\n\nЯкщо завантаження не було запропоновано, або Ви його скасували, Ви можете перезапустити завантаження натиснувши на посилання нижче:\n\n$3\n\n<strong>Зверніть увагу:</strong> Якщо Ви не зробите це зараз, цей згенерований файл налаштувань не буде доступним для Вас пізніше якщо Ви вийдете зі встановлення не завантаживши його.\n\nКоли це було зроблено Ви можете <strong>[$2 зайти до своєї вікі]</strong>.",
        "config-install-success": "Mediawiki успішно встановлено. Зараз Ви можете перейти до <$1$2>, щоб переглянути свою вікі. Якщо у Вас є питання, ознайомтеся з нашим FAQ: <https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ> або використовуйте один з форумів підтримки, які вказано на цій сторінці.",
+       "config-install-db-success": "База даних була успішно сформована",
        "config-download-localsettings": "Завантажити <code>LocalSettings.php</code>",
        "config-help": "допомога",
        "config-help-tooltip": "натисніть, щоб розгорнути",
index 4ee268d..890f996 100644 (file)
        "config-pcre-no-utf8": "<strong>Lỗi chí tử:</strong> Mô đun PCRE của PHP dường như được biên dịch mà không có hỗ trợ PCRE_UTF8.\nMediaWiki yêu cầu phải có hỗ trợ UTF-8 để hoạt động chính xác.",
        "config-memory-raised": "<code>memory_limit</code> của PHP là $1, tăng lên $2.",
        "config-memory-bad": "<strong>Cảnh báo:</strong> <code>memory_limit</code> của PHP là $1.\nGiá trị này có lẽ quá thấp.\nCài đặt có thể bị thất bại!",
-       "config-apc": "[https://secure.php.net/apc APC] đã được cài đặt",
-       "config-apcu": "[https://secure.php.net/apcu APCu] đã được cài đặt",
+       "config-apc": "[https://www.php.net/apc APC] đã được cài đặt",
+       "config-apcu": "[https://www.php.net/apcu APCu] đã được cài đặt",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] đã được cài đặt",
-       "config-no-cache-apcu": "<strong>Cảnh báo:</strong> Không tìm thấy [https://secure.php.net/apcu APCu] hoặc [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nVùng nhớ đệm đối tượng không được kích hoạt.",
+       "config-no-cache-apcu": "<strong>Cảnh báo:</strong> Không tìm thấy [https://www.php.net/apcu APCu] hoặc [https://www.iis.net/downloads/microsoft/wincache-extension WinCache].\nVùng nhớ đệm đối tượng không được kích hoạt.",
        "config-mod-security": "<strong>Cảnh báo:</strong> [https://modsecurity.org/ mod_security]/mod_security2 đã được kích hoạt trên máy chủ Web của bạn. Nhiều cấu hình phổ biến của phần mềm này sẽ gây vấn đề cho MediaWiki và những phần mềm khác cho phép người dùng đăng các nội dung tùy tiện.\nNếu có thể, bạn nên vô hiệu nó. Còn không, tra cứu [https://modsecurity.org/documentation/ tài liệu mod_security] hoặc liên hệ với nhà cung cấp hỗ trợ cho máy chủ nếu bạn gặp những lỗi ngẫu nhiên nào đó.",
        "config-diff3-bad": "Không tìm thấy GNU diff3.",
        "config-git": "Đã tìm thấy phần mềm điều khiển phiên bản Git: <code>$1</code>.",
        "config-type-mysql": "MariaDB, MySQL, hoặc tương hợp",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki hỗ trợ các hệ thống cơ sở dữ liệu sau đây:\n\n$1\n\nNếu bạn không thấy hệ thống cơ sở dữ liệu mà bạn đang muốn sử dụng được liệt kê dưới đây, thì hãy theo chỉ dẫn được liên kết ở trên để kích hoạt tính năng hỗ trợ.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] là mục tiêu chính cho MediaWiki và được hỗ trợ tốt nhất. MediaWiki cũng làm việc với [{{int:version-db-mysql-url}} MySQL] và [{{int:version-db-percona-url}} Percona Server], là những cơ sở dữ liệu tương thích với MariaDB. ([https://secure.php.net/manual/en/mysqli.installation.php Làm thế nào để biên dịch PHP với sự hỗ trợ của MySQL])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] là một hệ thống cơ sở dữ liệu mã nguồn mở phổ biến như là một thay thế cho MySQL. ([https://secure.php.net/manual/en/pgsql.installation.php Làm thế nào để biên dịch PHP với sự hỗ trợ của PostgreSQL])",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] là một hệ thống cơ sở dữ liệu dung lượng nhẹ được hỗ trợ rất tốt. ([https://secure.php.net/manual/en/pdo.installation.php Làm thế nào để biên dịch PHP với sự hỗ trợ của SQLite], sử dụng PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] là một cơ sở dữ liệu doanh nghiệp thương mại. ([https://secure.php.net/manual/en/oci8.installation.php Làm thế nào để biên dịch PHP với sự hỗ trợ của OCI8])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] là một cơ sở dữ liệu doanh nghiệp thương mại cho Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php Làm thế nào để biên dịch PHP với sự hỗ trợ của SQLSRV])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] là mục tiêu chính cho MediaWiki và được hỗ trợ tốt nhất. MediaWiki cũng làm việc với [{{int:version-db-mysql-url}} MySQL] và [{{int:version-db-percona-url}} Percona Server], là những cơ sở dữ liệu tương thích với MariaDB. ([https://www.php.net/manual/en/mysqli.installation.php Làm thế nào để biên dịch PHP với sự hỗ trợ của MySQL])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] là một hệ thống cơ sở dữ liệu mã nguồn mở phổ biến như là một thay thế cho MySQL. ([https://www.php.net/manual/en/pgsql.installation.php Làm thế nào để biên dịch PHP với sự hỗ trợ của PostgreSQL])",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] là một hệ thống cơ sở dữ liệu dung lượng nhẹ được hỗ trợ rất tốt. ([https://www.php.net/manual/en/pdo.installation.php Làm thế nào để biên dịch PHP với sự hỗ trợ của SQLite], sử dụng PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] là một cơ sở dữ liệu doanh nghiệp thương mại. ([https://www.php.net/manual/en/oci8.installation.php Làm thế nào để biên dịch PHP với sự hỗ trợ của OCI8])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] là một cơ sở dữ liệu doanh nghiệp thương mại cho Windows. ([https://www.php.net/manual/en/sqlsrv.installation.php Làm thế nào để biên dịch PHP với sự hỗ trợ của SQLSRV])",
        "config-header-mysql": "Thiết lập MariaDB/MySQL",
        "config-header-postgres": "Thiết lập PostgreSQL",
        "config-header-sqlite": "Thiết lập SQLite",
        "config-license-help": "Nhiều wiki công khai phát hành tất cả các đóng góp theo một [https://freedomdefined.org/Definition/Vi?uselang=vi giấy phép tự do].\nĐiều này giúp tạo nên thái độ cộng đồng sở hữu và ủng hộ sự đóng góp lâu dài.\nNói chung, một wiki riêng tư hoặc của công ty không nhất thiết phải sử dụng một giấy phép tự do.\n\nNếu bạn muốn được phép sử dụng văn bản từ Wikipedia và muốn Wikipedia nhận được những văn bản được sao chép từ wiki của bạn, bạn nên chọn <strong>{{int:config-license-cc-by-sa}}</strong>.\n\nWikipedia từng sử dụng Giấy phép Tài liệu Tự do GNU.\nGFDL là một giấy phép hợp lệ nhưng khó hiểu trên thực tế.\nNội dung được phát hành theo GFDL cũng khó tái sử dụng.",
        "config-email-settings": "Thiết lập thư điện tử",
        "config-enable-email": "Cho phép gửi thư điện tử đi",
-       "config-enable-email-help": "Nếu bạn muốn khả năng gửi thư điện tử, [https://secure.php.net/manual/en/mail.configuration.php thiết lập mail của PHP] cần phải được cấu hình đúng.\nNếu bạn không muốn sử dụng bất kỳ tính năng thư điện tử nào, bạn có thể vô hiệu chúng ở đây.",
+       "config-enable-email-help": "Nếu bạn muốn khả năng gửi thư điện tử, [https://www.php.net/manual/en/mail.configuration.php thiết lập mail của PHP] cần phải được cấu hình đúng.\nNếu bạn không muốn sử dụng bất kỳ tính năng thư điện tử nào, bạn có thể vô hiệu chúng ở đây.",
        "config-email-user": "Cho phép người dùng gửi thư điện tử cho người dùng khác",
        "config-email-user-help": "Cho phép tất cả người dùng gửi thư điện tử cho nhau, nếu họ đã kích hoạt nó trong cài đặt tùy chọn của họ.",
        "config-email-usertalk": "Gửi thư thông báo về tin nhắn mới",
index 2496153..8877f2d 100644 (file)
@@ -39,7 +39,7 @@
        "config-env-bad": "מ'האט קאנטראלירט די סביבה.\nאיר קענט נישט אינסטאלירן מעדיעוויקי.",
        "config-env-php": "PHP $1 איז אינצטאלירט.",
        "config-env-hhvm": "HHVM $1 איז אינסטאלירט.",
-       "config-apc": "[https://secure.php.net/apc APC] איז אינסטאַלירט",
+       "config-apc": "[https://www.php.net/apc APC] איז אינסטאַלירט",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] איז אינסטאַלירט",
        "config-diff3-bad": "GNU diff3 נישט געטראפן.",
        "config-using-server": "באניצן סארווער־נאמען \"<nowiki>$1</nowiki>\".",
index 4f4a6a6..6035c61 100644 (file)
        "config-pcre-no-utf8": "<strong>致命错误:</strong>PHP的PCRE模块在编译时可能没有包含PCRE_UTF8支持。\nMediaWiki需要UTF-8支持才能正常工作。",
        "config-memory-raised": "PHP的内存使用上限<code>memory_limit</code>为$1,自动提升到$2。",
        "config-memory-bad": "<strong>警告:</strong>PHP的内存使用上限<code>memory_limit</code>为$1。\n该设定可能过低,并导致安装失败!",
-       "config-apc": "[https://secure.php.net/apc APC]已安装",
-       "config-apcu": "已安装[https://secure.php.net/apcu APCu]",
+       "config-apc": "[https://www.php.net/apc APC]已安装",
+       "config-apcu": "已安装[https://www.php.net/apcu APCu]",
        "config-wincache": "已安装[https://www.iis.net/downloads/microsoft/wincache-extension WinCache]",
-       "config-no-cache-apcu": "<strong>警告:</strong>找不到[https://secure.php.net/apcu APCu]或[https://www.iis.net/downloads/microsoft/wincache-extension WinCache]。对象缓存未启用。",
+       "config-no-cache-apcu": "<strong>警告:</strong>找不到[https://www.php.net/apcu APCu]或[https://www.iis.net/downloads/microsoft/wincache-extension WinCache]。对象缓存未启用。",
        "config-mod-security": "<strong>警告:</strong>您的web服务器已启用[https://modsecurity.org/ mod_security]/mod_security2。它的很多常见配置可能导致MediaWiki及其他软件允许用户发布任意内容的问题。如果可能,这应当被禁用。否则,当您遭遇随机错误时,请参考[https://modsecurity.org/documentation/ mod_security 文档]或联络您的主机支持。",
        "config-diff3-bad": "找不到GNU diff3文字对比工具程序,您可以暂时忽略它,但可能会更频繁遇到编辑冲突。",
        "config-git": "发现Git版本控制软件:<code>$1</code>",
        "config-type-mysql": "MariaDB、MySQL或兼容程序",
        "config-type-mssql": "微软SQL服务器",
        "config-support-info": "MediaWiki支持以下数据库系统:\n\n$1\n\n如果您在下面列出的数据库系统中没有找到您希望使用的系统,请根据上方链向的指引启用支持。",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB]是用于MediaWiki的主要数据库,对它的支持最为完备。MediaWiki也可以在[{{int:version-db-mysql-url}} MySQL]和[{{int:version-db-percona-url}} Percona Server]下工作,它们与MariaDB兼容。([https://secure.php.net/manual/en/mysqli.installation.php 如何将对MySQL的支持编译进PHP中])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL]是一种流行的开源数据库系统,可作为MySQL的替代。([https://secure.php.net/manual/en/pgsql.installation.php 如何将对PostgreSQL的支持编译进PHP中])",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite]是一种轻量级的数据库系统,能被良好地支持。([https://secure.php.net/manual/en/pdo.installation.php 如何将对SQLite的支持编译进PHP中],须使用PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle]是一种商用企业级的数据库。([https://secure.php.net/manual/en/oci8.installation.php 如何将对OCI8的支持编译进PHP中])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server]是一个适用于Windows的商业性企业数据库。([https://secure.php.net/manual/en/sqlsrv.installation.php 如何编译带有SQLSRV支持的PHP])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB]是用于MediaWiki的主要数据库,对它的支持最为完备。MediaWiki也可以在[{{int:version-db-mysql-url}} MySQL]和[{{int:version-db-percona-url}} Percona Server]下工作,它们与MariaDB兼容。([https://www.php.net/manual/en/mysqli.installation.php 如何将对MySQL的支持编译进PHP中])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL]是一种流行的开源数据库系统,可作为MySQL的替代。([https://www.php.net/manual/en/pgsql.installation.php 如何将对PostgreSQL的支持编译进PHP中])",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite]是一种轻量级的数据库系统,能被良好地支持。([https://www.php.net/manual/en/pdo.installation.php 如何将对SQLite的支持编译进PHP中],须使用PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle]是一种商用企业级的数据库。([https://www.php.net/manual/en/oci8.installation.php 如何将对OCI8的支持编译进PHP中])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server]是一个适用于Windows的商业性企业数据库。([https://www.php.net/manual/en/sqlsrv.installation.php 如何编译带有SQLSRV支持的PHP])",
        "config-header-mysql": "MariaDB/MySQL设置",
        "config-header-postgres": "PostgreSQL设置",
        "config-header-sqlite": "SQLite设置",
        "config-license-help": "许多公共wiki将所有用户贡献置于[https://freedomdefined.org/Definition 自由许可证]之下。这有助于构建社区的主人翁意识,并鼓励长期贡献。对于非公共wiki或公司wiki,这并非必要条件。\n\n如果您希望使用来自维基百科的内容,并希望维基百科能接受复制自您的wiki的内容,您应当选择<strong>{{int:config-license-cc-by-sa}}</strong>。\n\nGNU自由文档许可证是维基百科曾经使用过的许可证,并迄今有效。然而,该许可证难以理解,并会增加重用内容的难度。",
        "config-email-settings": "电子邮件设置",
        "config-enable-email": "启用出站电子邮件",
-       "config-enable-email-help": "如果您希望使用电子邮件功能,请正确配置[https://secure.php.net/manual/en/mail.configuration.php PHP的邮件设定]。如果您不需要任何电子邮件功能,请在此处禁用它。",
+       "config-enable-email-help": "如果您希望使用电子邮件功能,请正确配置[https://www.php.net/manual/en/mail.configuration.php PHP的邮件设定]。如果您不需要任何电子邮件功能,请在此处禁用它。",
        "config-email-user": "启用用户到用户的电子邮件",
        "config-email-user-help": "允许所有用户互发邮件,假若他们启用了该功能。",
        "config-email-usertalk": "启用用户讨论页面通知",
index 52c78c8..7a30492 100644 (file)
        "config-pcre-no-utf8": "<strong>嚴重:</strong> PHP 的 PCRE 模組在編譯時未包含 PCRE_UTF8 支援。\nMediaWiki 需要支援 UTF-8 才可正常運作。",
        "config-memory-raised": "PHP 的記憶體使用上限 <code>memory_limit</code> 目前為 $1,自動提高到 $2。",
        "config-memory-bad": "<strong>警告:</strong>PHP 的記憶體使用上限 <code>memory_limit</code> 為 $1。\n該設定值可能過低。\n這可能導致後續的安裝失敗!",
-       "config-apc": "[https://secure.php.net/apc APC] 已安裝",
-       "config-apcu": "已安裝[https://secure.php.net/apcu APCu]",
+       "config-apc": "[https://www.php.net/apc APC] 已安裝",
+       "config-apcu": "已安裝[https://www.php.net/apcu APCu]",
        "config-wincache": "[https://www.iis.net/downloads/microsoft/wincache-extension WinCache] 已安裝",
-       "config-no-cache-apcu": "<strong>警告:</strong>找不到[https://secure.php.net/apcu APCu]或[https://www.iis.net/downloads/microsoft/wincache-extension WinCache]。未開啟物件快取。",
+       "config-no-cache-apcu": "<strong>警告:</strong>找不到[https://www.php.net/apcu APCu]或[https://www.iis.net/downloads/microsoft/wincache-extension WinCache]。未開啟物件快取。",
        "config-mod-security": "<strong>警告:</strong>您的網頁伺服器已開啟 [https://modsecurity.org/ mod_security] 模組,如果設定不恰當會導致使用者可在 MediaWiki 或其他應用程式發佈任意的內容。\n若您遇到任何問題,請參考 [https://modsecurity.org/documentation/ mod_security 文件] 或聯繫您的伺服器技術支援人員。",
        "config-diff3-bad": "找不到 GNU diff3 文字比對工具程式,而您現在可忽略它,但可能會更頻繁地遇到編輯衝突。",
        "config-git": "找到 Git 版本控制軟體:<code>$1</code>。",
        "config-type-mysql": "MariaDB、MySQL、或與其相容的套件",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki 支援以下資料庫系統:\n\n$1\n\n如果您下方沒有看到您要使用的資料庫系統,請根據上方連結指示開啟資料庫的支援。",
-       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] 是 MediaWiki 主要支援的資料庫系統。MediaWiki 也同時可運作與於 [{{int:version-db-mysql-url}} MySQL] 和 [{{int:version-db-percona-url}} Percona 伺服器],上述這些與 MariaDB 相容的資料庫系統。([https://secure.php.net/manual/en/mysqli.installation.php 如何編譯支援 MySQL 的 PHP])",
-       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] 是一套受歡迎的開源資料庫系統,可用來替代 MySQL。([https://secure.php.net/manual/en/pgsql.installation.php 如何編譯支援 PostgreSQL 的 PHP])。",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] 是一套輕量級的資料庫系統,MediaWiki 可在此資料庫系統上良好的運作。([https://secure.php.net/manual/en/pdo.installation.php 如何編譯支援 SQLite 的 PHP],須透過 PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] 是一套商用企業級的資料庫。([https://secure.php.net/manual/en/oci8.installation.php 如何編譯支援 OCI8 的 PHP])",
-       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] 是一套 Windows 專用的商用企業級的資料庫。 ([https://secure.php.net/manual/en/sqlsrv.installation.php 如何編譯支援 SQLSRV 的 PHP])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] 是 MediaWiki 主要支援的資料庫系統。MediaWiki 也同時可運作與於 [{{int:version-db-mysql-url}} MySQL] 和 [{{int:version-db-percona-url}} Percona 伺服器],上述這些與 MariaDB 相容的資料庫系統。([https://www.php.net/manual/en/mysqli.installation.php 如何編譯支援 MySQL 的 PHP])",
+       "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] 是一套受歡迎的開源資料庫系統,可用來替代 MySQL。([https://www.php.net/manual/en/pgsql.installation.php 如何編譯支援 PostgreSQL 的 PHP])。",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] 是一套輕量級的資料庫系統,MediaWiki 可在此資料庫系統上良好的運作。([https://www.php.net/manual/en/pdo.installation.php 如何編譯支援 SQLite 的 PHP],須透過 PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] 是一套商用企業級的資料庫。([https://www.php.net/manual/en/oci8.installation.php 如何編譯支援 OCI8 的 PHP])",
+       "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] 是一套 Windows 專用的商用企業級的資料庫。 ([https://www.php.net/manual/en/sqlsrv.installation.php 如何編譯支援 SQLSRV 的 PHP])",
        "config-header-mysql": "MariaDB/MySQL 設定",
        "config-header-postgres": "PostgreSQL 設定",
        "config-header-sqlite": "SQLite 設定",
        "config-license-help": "許多開放式 Wiki 會以 [https://freedomdefined.org/Definition 自由授權條款] 的方式釋放出編者的所有貢獻,這有助於構建社群的所有權,並且能鼓勵長期貢獻。對於封閉式的 Wiki 或公司 Wiki 則是非必要的。\n\n如果您希望使用來自維基百科(Wikipedia)的內容,並希望維基百科能接受您的 Wiki 內容,請應選擇 <strong>{{int:config-license-cc-by-sa}}</strong> 授權條款。\n\n維基百科(Wikipedia)先前是使用 GNU 自由文件授權條款,\n但該授權條款的內容較難理解,因此較難再利用在該條款底下的內容。",
        "config-email-settings": "E-mail 設定",
        "config-enable-email": "開啟外寄電子郵件",
-       "config-enable-email-help": "如果您要使用電子郵件功能,請正確設定 [https://secure.php.net/manual/en/mail.configuration.php PHP 的郵件設定]。\n如果您不需要使用電子郵件功能,請在此處關閉。",
+       "config-enable-email-help": "如果您要使用電子郵件功能,請正確設定 [https://www.php.net/manual/en/mail.configuration.php PHP 的郵件設定]。\n如果您不需要使用電子郵件功能,請在此處關閉。",
        "config-email-user": "開啟使用者對使用者間的電子郵件互通",
        "config-email-user-help": "若使用者在個人偏好設定開啟了此功能,則可允許使用者間相互傳送郵件。",
        "config-email-usertalk": "開啟使用者討論頁面通知",
        "config-install-done": "<strong>恭喜!</strong>\n您已經成功安裝MediaWiki。\n\n安裝程式已自動產生<code>LocalSettings.php</code>檔案,\n該檔案中包含了您所有的設定項目。\n\n您需要下載該檔案,並將其放置在您的Wiki的根目錄(index.php所在的目錄)中,下載應已自動開始。\n\n若瀏覽器沒有提示您下載,或者您取消了下載,您可以點選下方連結重新下載:\n\n$3\n\n<strong>注意:</strong>如果您現在不下載此檔案,稍後結束安裝程式之後將無法再下載設定檔。\n\n當您完成本步驟後,您可以<strong>[$2 進入您的Wiki]</strong>。",
        "config-install-done-path": "<strong>恭喜!</strong>\n您已經成功安裝MediaWiki。\n\n安裝程式已自動產生<code>LocalSettings.php</code>檔案,\n該檔案中包含了您所有的設定項目。\n\n您需要下載該檔案,並將其放置在<code>$4</code>中,下載應已自動開始。\n\n若瀏覽器沒有提示您下載,或者您取消了下載,您可以點選下方連結重新下載:\n\n$3\n\n<strong>注意:</strong>如果您現在不下載此檔案,稍後結束安裝程式之後將無法再下載設定檔。\n\n當您完成本步驟後,您可以<strong>[$2 進入您的Wiki]</strong>。",
        "config-install-success": "MediaWiki 已安裝成功。您現在可以在 <$1$2> 上檢視您的 wiki。若您有任何問題,請閱讀常見問題清單:<https://www.mediawiki.org/wiki/Manual:FAQ/zh>,或是利用在頁面上所連結的支援論壇之一。",
+       "config-install-db-success": "資料庫設定成功",
        "config-download-localsettings": "下載 <code>LocalSettings.php</code>",
        "config-help": "說明",
        "config-help-tooltip": "點選以展開",
index 832883b..30826d4 100644 (file)
@@ -36,7 +36,7 @@ class Interwiki {
        protected $mAPI;
 
        /** @var string The name of the database (for a connection to be established
-        *    with LBFactory::getMainLB( 'wikiid' ))
+        *    with LBFactory::getMainLB( 'domainId' ))
         */
        protected $mWikiID;
 
diff --git a/includes/jobqueue/GenericParameterJob.php b/includes/jobqueue/GenericParameterJob.php
new file mode 100644 (file)
index 0000000..f7da42b
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Interface for generic jobs only uses the parameters field.
+ *
+ * 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
+ */
+
+/**
+ * Interface for generic jobs only uses the parameters field and are JSON serializable
+ *
+ * @ingroup JobQueue
+ * @since 1.33
+ */
+interface GenericParameterJob extends IJobSpecification {
+       /**
+        * @param array $params JSON-serializable map of parameters
+        */
+       public function __construct( array $params );
+}
index 8bc1bc3..2b3caa2 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * Job queue task description base code.
+ * Job queue task description interface
  *
  * 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
  */
 
 /**
- * Job queue task description interface
+ * Interface for serializable objects that describe a job queue task
+ *
+ * A job specification can be inserted into a queue via JobQueue::push().
+ * The specification parameters should be JSON serializable (e.g. no PHP classes).
+ * Whatever queue the job specification is pushed into is assumed to have job runners
+ * that will eventually pop the job specification from the queue, construct a RunnableJob
+ * instance from the specification, and then execute that instance via RunnableJob::run().
  *
  * @ingroup JobQueue
  * @since 1.23
  */
 interface IJobSpecification {
        /**
-        * @return string Job type
+        * @return string Job type that defines what sort of changes this job makes
         */
        public function getType();
 
        /**
-        * @return array
+        * @return array Parameters that specify sources, targets, and options for execution
         */
        public function getParams();
 
@@ -76,9 +82,4 @@ interface IJobSpecification {
         * @return bool Whether this is job is a root job
         */
        public function isRootJob();
-
-       /**
-        * @return Title Descriptive title (this can simply be informative)
-        */
-       public function getTitle();
 }
index d624acf..d2f1dbc 100644 (file)
@@ -27,7 +27,7 @@
  *
  * @ingroup JobQueue
  */
-abstract class Job implements IJobSpecification {
+abstract class Job implements RunnableJob {
        /** @var string */
        public $command;
 
@@ -41,7 +41,7 @@ abstract class Job implements IJobSpecification {
        protected $title;
 
        /** @var bool Expensive jobs may set this to true */
-       protected $removeDuplicates;
+       protected $removeDuplicates = false;
 
        /** @var string Text for error that occurred last */
        protected $error;
@@ -55,40 +55,55 @@ abstract class Job implements IJobSpecification {
        /** @var int Job must not be wrapped in the usual explicit LBFactory transaction round */
        const JOB_NO_EXPLICIT_TRX_ROUND = 1;
 
-       /**
-        * Run the job
-        * @return bool Success
-        */
-       abstract public function run();
-
        /**
         * Create the appropriate object to handle a specific job
         *
         * @param string $command Job command
-        * @param Title $title Associated title
-        * @param array $params Job parameters
+        * @param array|Title $params Job parameters
         * @throws InvalidArgumentException
         * @return Job
         */
-       public static function factory( $command, Title $title, $params = [] ) {
+       public static function factory( $command, $params = [] ) {
                global $wgJobClasses;
 
+               if ( $params instanceof Title ) {
+                       // Backwards compatibility for old signature ($command, $title, $params)
+                       $title = $params;
+                       $params = func_num_args() >= 3 ? func_get_arg( 2 ) : [];
+               } elseif ( isset( $params['namespace'] ) && isset( $params['title'] ) ) {
+                       // Handle job classes that take title as constructor parameter.
+                       // If a newer classes like GenericParameterJob uses these parameters,
+                       // then this happens in Job::__construct instead.
+                       $title = Title::makeTitle( $params['namespace'], $params['title'] );
+               } else {
+                       // Default title for job classes not implementing GenericParameterJob.
+                       // This must be a valid title because it not directly passed to
+                       // our Job constructor, but rather it's subclasses which may expect
+                       // to be able to use it.
+                       $title = Title::makeTitle( NS_SPECIAL, 'Blankpage' );
+               }
+
                if ( isset( $wgJobClasses[$command] ) ) {
                        $handler = $wgJobClasses[$command];
 
                        if ( is_callable( $handler ) ) {
                                $job = call_user_func( $handler, $title, $params );
                        } elseif ( class_exists( $handler ) ) {
-                               $job = new $handler( $title, $params );
+                               if ( is_subclass_of( $handler, GenericParameterJob::class ) ) {
+                                       $job = new $handler( $params );
+                               } else {
+                                       $job = new $handler( $title, $params );
+                               }
                        } else {
                                $job = null;
                        }
 
                        if ( $job instanceof Job ) {
                                $job->command = $command;
+
                                return $job;
                        } else {
-                               throw new InvalidArgumentException( "Cannot instantiate job '$command': bad spec!" );
+                               throw new InvalidArgumentException( "Could instantiate job '$command': bad spec!" );
                        }
                }
 
@@ -97,19 +112,43 @@ abstract class Job implements IJobSpecification {
 
        /**
         * @param string $command
-        * @param Title $title
-        * @param array|bool $params Can not be === true
+        * @param array|Title|null $params
         */
-       public function __construct( $command, $title, $params = false ) {
-               $this->command = $command;
-               $this->title = $title;
-               $this->params = is_array( $params ) ? $params : []; // sanity
+       public function __construct( $command, $params = null ) {
+               if ( $params instanceof Title ) {
+                       // Backwards compatibility for old signature ($command, $title, $params)
+                       $title = $params;
+                       $params = func_num_args() >= 3 ? func_get_arg( 2 ) : [];
+               } else {
+                       // Newer jobs may choose to not have a top-level title (e.g. GenericParameterJob)
+                       $title = null;
+               }
+
+               if ( !is_array( $params ) ) {
+                       throw new InvalidArgumentException( '$params must be an array' );
+               }
 
-               // expensive jobs may set this to true
-               $this->removeDuplicates = false;
+               if (
+                       $title &&
+                       !isset( $params['namespace'] ) &&
+                       !isset( $params['title'] )
+               ) {
+                       // When constructing this class for submitting to the queue,
+                       // normalise the $title arg of old job classes as part of $params.
+                       $params['namespace'] = $title->getNamespace();
+                       $params['title'] = $title->getDBKey();
+               }
 
-               if ( !isset( $this->params['requestId'] ) ) {
-                       $this->params['requestId'] = WebRequest::getRequestId();
+               $this->command = $command;
+               $this->params = $params + [ 'requestId' => WebRequest::getRequestId() ];
+
+               if ( $this->title === null ) {
+                       // Set this field for access via getTitle().
+                       $this->title = ( isset( $params['namespace'] ) && isset( $params['title'] ) )
+                               ? Title::makeTitle( $params['namespace'], $params['title'] )
+                               // GenericParameterJob classes without namespace/title params
+                               // should not use getTitle(). Set an invalid title as placeholder.
+                               : Title::makeTitle( NS_SPECIAL, '' );
                }
        }
 
@@ -119,7 +158,7 @@ abstract class Job implements IJobSpecification {
         * @since 1.31
         */
        public function hasExecutionFlag( $flag ) {
-               return ( $this->executionFlags && $flag ) === $flag;
+               return ( $this->executionFlags & $flag ) === $flag;
        }
 
        /**
@@ -132,7 +171,7 @@ abstract class Job implements IJobSpecification {
        /**
         * @return Title
         */
-       public function getTitle() {
+       final public function getTitle() {
                return $this->title;
        }
 
@@ -143,6 +182,36 @@ abstract class Job implements IJobSpecification {
                return $this->params;
        }
 
+       /**
+        * @param string|null $field Metadata field or null to get all the metadata
+        * @return mixed|null Value; null if missing
+        * @since 1.33
+        */
+       public function getMetadata( $field = null ) {
+               if ( $field === null ) {
+                       return $this->metadata;
+               }
+
+               return $this->metadata[$field] ?? null;
+       }
+
+       /**
+        * @param string $field Key name to set the value for
+        * @param mixed $value The value to set the field for
+        * @return mixed|null The prior field value; null if missing
+        * @since 1.33
+        */
+       public function setMetadata( $field, $value ) {
+               $old = $this->getMetadata( $field );
+               if ( $value === null ) {
+                       unset( $this->metadata[$field] );
+               } else {
+                       $this->metadata[$field] = $value;
+               }
+
+               return $old;
+       }
+
        /**
         * @return int|null UNIX timestamp to delay running this job until, otherwise null
         * @since 1.22
@@ -225,8 +294,6 @@ abstract class Job implements IJobSpecification {
        public function getDeduplicationInfo() {
                $info = [
                        'type' => $this->getType(),
-                       'namespace' => $this->getTitle()->getNamespace(),
-                       'title' => $this->getTitle()->getDBkey(),
                        'params' => $this->getParams()
                ];
                if ( is_array( $info['params'] ) ) {
index 660352a..f5ed7b9 100644 (file)
@@ -20,7 +20,7 @@
  * @file
  * @defgroup JobQueue JobQueue
  */
-use MediaWiki\MediaWikiServices;
+use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface;
 
 /**
  * Class to handle enqueueing and running of background jobs
@@ -29,7 +29,7 @@ use MediaWiki\MediaWikiServices;
  * @since 1.21
  */
 abstract class JobQueue {
-       /** @var string Wiki ID */
+       /** @var string DB domain ID */
        protected $domain;
        /** @var string Job type */
        protected $type;
@@ -41,11 +41,11 @@ abstract class JobQueue {
        protected $maxTries;
        /** @var string|bool Read only rationale (or false if r/w) */
        protected $readOnlyReason;
+       /** @var StatsdDataFactoryInterface */
+       protected $stats;
 
        /** @var BagOStuff */
        protected $dupCache;
-       /** @var JobQueueAggregator */
-       protected $aggr;
 
        const QOS_ATOMIC = 1; // integer; "all-or-nothing" job insertions
 
@@ -53,7 +53,7 @@ abstract class JobQueue {
 
        /**
         * @param array $params
-        * @throws MWException
+        * @throws JobQueueError
         */
        protected function __construct( array $params ) {
                $this->domain = $params['domain'] ?? $params['wiki']; // b/c
@@ -66,18 +66,18 @@ abstract class JobQueue {
                        $this->order = $this->optimalOrder();
                }
                if ( !in_array( $this->order, $this->supportedOrders() ) ) {
-                       throw new MWException( __CLASS__ . " does not support '{$this->order}' order." );
+                       throw new JobQueueError( __CLASS__ . " does not support '{$this->order}' order." );
                }
-               $this->dupCache = wfGetCache( CACHE_ANYTHING );
-               $this->aggr = $params['aggregator'] ?? new JobQueueAggregatorNull( [] );
                $this->readOnlyReason = $params['readOnlyReason'] ?? false;
+               $this->stats = $params['stats'] ?? new NullStatsdDataFactory();
+               $this->dupCache = $params['stash'] ?? new EmptyBagOStuff();
        }
 
        /**
         * Get a job queue object of the specified type.
         * $params includes:
         *   - class      : What job class to use (determines job type)
-        *   - wiki       : wiki ID of the wiki the jobs are for (defaults to current wiki)
+        *   - domain     : Database domain ID of the wiki the jobs are for (defaults to current wiki)
         *   - type       : The name of the job types this queue handles
         *   - order      : Order that pop() selects jobs, one of "fifo", "timestamp" or "random".
         *                  If "fifo" is used, the queue will effectively be FIFO. Note that job
@@ -94,28 +94,30 @@ abstract class JobQueue {
         *                  of jobs simply means re-inserting them into the queue. Jobs can be
         *                  attempted up to three times before being discarded.
         *   - readOnlyReason : Set this to a string to make the queue read-only.
+        *   - stash      : A BagOStuff instance that can be used for root job deduplication
+        *   - stats      : A StatsdDataFactoryInterface [optional]
         *
         * Queue classes should throw an exception if they do not support the options given.
         *
         * @param array $params
         * @return JobQueue
-        * @throws MWException
+        * @throws JobQueueError
         */
        final public static function factory( array $params ) {
                $class = $params['class'];
                if ( !class_exists( $class ) ) {
-                       throw new MWException( "Invalid job queue class '$class'." );
+                       throw new JobQueueError( "Invalid job queue class '$class'." );
                }
                $obj = new $class( $params );
                if ( !( $obj instanceof self ) ) {
-                       throw new MWException( "Class '$class' is not a " . __CLASS__ . " class." );
+                       throw new JobQueueError( "Class '$class' is not a " . __CLASS__ . " class." );
                }
 
                return $obj;
        }
 
        /**
-        * @return string Wiki ID
+        * @return string Database domain ID
         */
        final public function getDomain() {
                return $this->domain;
@@ -126,7 +128,7 @@ abstract class JobQueue {
         * @deprecated 1.33
         */
        final public function getWiki() {
-               return $this->domain;
+               return WikiMap::getWikiIdFromDbDomain( $this->domain );
        }
 
        /**
@@ -318,7 +320,7 @@ abstract class JobQueue {
         * @param IJobSpecification[] $jobs
         * @param int $flags Bitfield (supports JobQueue::QOS_ATOMIC)
         * @return void
-        * @throws MWException
+        * @throws JobQueueError
         */
        final public function batchPush( array $jobs, $flags = 0 ) {
                $this->assertNotReadOnly();
@@ -329,16 +331,15 @@ abstract class JobQueue {
 
                foreach ( $jobs as $job ) {
                        if ( $job->getType() !== $this->type ) {
-                               throw new MWException(
+                               throw new JobQueueError(
                                        "Got '{$job->getType()}' job; expected a '{$this->type}' job." );
                        } elseif ( $job->getReleaseTimestamp() && !$this->supportsDelayedJobs() ) {
-                               throw new MWException(
+                               throw new JobQueueError(
                                        "Got delayed '{$job->getType()}' job; delays are not supported." );
                        }
                }
 
                $this->doBatchPush( $jobs, $flags );
-               $this->aggr->notifyQueueNonEmpty( $this->domain, $this->type );
 
                foreach ( $jobs as $job ) {
                        if ( $job->isRootJob() ) {
@@ -359,31 +360,18 @@ abstract class JobQueue {
         * This requires $wgJobClasses to be set for the given job type.
         * Outside callers should use JobQueueGroup::pop() instead of this function.
         *
-        * @throws MWException
-        * @return Job|bool Returns false if there are no jobs
+        * @throws JobQueueError
+        * @return RunnableJob|bool Returns false if there are no jobs
         */
        final public function pop() {
-               global $wgJobClasses;
-
                $this->assertNotReadOnly();
-               if ( !WikiMap::isCurrentWikiDbDomain( $this->domain ) ) {
-                       throw new MWException(
-                               "Cannot pop '{$this->type}' job off foreign '{$this->domain}' wiki queue." );
-               } elseif ( !isset( $wgJobClasses[$this->type] ) ) {
-                       // Do not pop jobs if there is no class for the queue type
-                       throw new MWException( "Unrecognized job type '{$this->type}'." );
-               }
 
                $job = $this->doPop();
 
-               if ( !$job ) {
-                       $this->aggr->notifyQueueEmpty( $this->domain, $this->type );
-               }
-
                // Flag this job as an old duplicate based on its "root" job...
                try {
                        if ( $job && $this->isRootJobOldDuplicate( $job ) ) {
-                               self::incrStats( 'dupe_pops', $this->type );
+                               $this->incrStats( 'dupe_pops', $this->type );
                                $job = DuplicateJob::newFromJob( $job ); // convert to a no-op
                        }
                } catch ( Exception $e ) {
@@ -395,7 +383,7 @@ abstract class JobQueue {
 
        /**
         * @see JobQueue::pop()
-        * @return Job|bool
+        * @return RunnableJob|bool
         */
        abstract protected function doPop();
 
@@ -405,14 +393,14 @@ abstract class JobQueue {
         * This does nothing for certain queue classes or if "claimTTL" is not set.
         * Outside callers should use JobQueueGroup::ack() instead of this function.
         *
-        * @param Job $job
+        * @param RunnableJob $job
         * @return void
-        * @throws MWException
+        * @throws JobQueueError
         */
-       final public function ack( Job $job ) {
+       final public function ack( RunnableJob $job ) {
                $this->assertNotReadOnly();
                if ( $job->getType() !== $this->type ) {
-                       throw new MWException( "Got '{$job->getType()}' job; expected '{$this->type}'." );
+                       throw new JobQueueError( "Got '{$job->getType()}' job; expected '{$this->type}'." );
                }
 
                $this->doAck( $job );
@@ -420,9 +408,9 @@ abstract class JobQueue {
 
        /**
         * @see JobQueue::ack()
-        * @param Job $job
+        * @param RunnableJob $job
         */
-       abstract protected function doAck( Job $job );
+       abstract protected function doAck( RunnableJob $job );
 
        /**
         * Register the "root job" of a given job into the queue for de-duplication.
@@ -452,13 +440,13 @@ abstract class JobQueue {
         * This does nothing for certain queue classes.
         *
         * @param IJobSpecification $job
-        * @throws MWException
+        * @throws JobQueueError
         * @return bool
         */
        final public function deduplicateRootJob( IJobSpecification $job ) {
                $this->assertNotReadOnly();
                if ( $job->getType() !== $this->type ) {
-                       throw new MWException( "Got '{$job->getType()}' job; expected '{$this->type}'." );
+                       throw new JobQueueError( "Got '{$job->getType()}' job; expected '{$this->type}'." );
                }
 
                return $this->doDeduplicateRootJob( $job );
@@ -467,12 +455,12 @@ abstract class JobQueue {
        /**
         * @see JobQueue::deduplicateRootJob()
         * @param IJobSpecification $job
-        * @throws MWException
+        * @throws JobQueueError
         * @return bool
         */
        protected function doDeduplicateRootJob( IJobSpecification $job ) {
                if ( !$job->hasRootJobParams() ) {
-                       throw new MWException( "Cannot register root job; missing parameters." );
+                       throw new JobQueueError( "Cannot register root job; missing parameters." );
                }
                $params = $job->getRootJobParams();
 
@@ -488,19 +476,19 @@ abstract class JobQueue {
                }
 
                // Update the timestamp of the last root job started at the location...
-               return $this->dupCache->set( $key, $params['rootJobTimestamp'], JobQueueDB::ROOTJOB_TTL );
+               return $this->dupCache->set( $key, $params['rootJobTimestamp'], self::ROOTJOB_TTL );
        }
 
        /**
         * Check if the "root" job of a given job has been superseded by a newer one
         *
-        * @param Job $job
-        * @throws MWException
+        * @param IJobSpecification $job
+        * @throws JobQueueError
         * @return bool
         */
-       final protected function isRootJobOldDuplicate( Job $job ) {
+       final protected function isRootJobOldDuplicate( IJobSpecification $job ) {
                if ( $job->getType() !== $this->type ) {
-                       throw new MWException( "Got '{$job->getType()}' job; expected '{$this->type}'." );
+                       throw new JobQueueError( "Got '{$job->getType()}' job; expected '{$this->type}'." );
                }
                $isDuplicate = $this->doIsRootJobOldDuplicate( $job );
 
@@ -509,10 +497,10 @@ abstract class JobQueue {
 
        /**
         * @see JobQueue::isRootJobOldDuplicate()
-        * @param Job $job
+        * @param IJobSpecification $job
         * @return bool
         */
-       protected function doIsRootJobOldDuplicate( Job $job ) {
+       protected function doIsRootJobOldDuplicate( IJobSpecification $job ) {
                if ( !$job->hasRootJobParams() ) {
                        return false; // job has no de-deplication info
                }
@@ -555,10 +543,10 @@ abstract class JobQueue {
 
        /**
         * @see JobQueue::delete()
-        * @throws MWException
+        * @throws JobQueueError
         */
        protected function doDelete() {
-               throw new MWException( "This method is not implemented." );
+               throw new JobQueueError( "This method is not implemented." );
        }
 
        /**
@@ -659,7 +647,7 @@ abstract class JobQueue {
         *
         * @param array $types List of queues types
         * @return array|null (list of non-empty queue types) or null if unsupported
-        * @throws MWException
+        * @throws JobQueueError
         * @since 1.22
         */
        final public function getSiblingQueuesWithJobs( array $types ) {
@@ -682,7 +670,7 @@ abstract class JobQueue {
         *
         * @param array $types List of queues types
         * @return array|null (job type => whether queue is empty) or null if unsupported
-        * @throws MWException
+        * @throws JobQueueError
         * @since 1.22
         */
        final public function getSiblingQueueSizes( array $types ) {
@@ -698,6 +686,16 @@ abstract class JobQueue {
                return null; // not supported
        }
 
+       /**
+        * @param string $command
+        * @param array $params
+        * @return Job
+        */
+       protected function factoryJob( $command, $params ) {
+               // @TODO: dependency inject this as a callback
+               return Job::factory( $command, $params );
+       }
+
        /**
         * @throws JobQueueReadOnlyError
         */
@@ -715,12 +713,8 @@ abstract class JobQueue {
         * @param int $delta
         * @since 1.22
         */
-       public static function incrStats( $key, $type, $delta = 1 ) {
-               static $stats;
-               if ( !$stats ) {
-                       $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
-               }
-               $stats->updateCount( "jobqueue.{$key}.all", $delta );
-               $stats->updateCount( "jobqueue.{$key}.{$type}", $delta );
+       protected function incrStats( $key, $type, $delta = 1 ) {
+               $this->stats->updateCount( "jobqueue.{$key}.all", $delta );
+               $this->stats->updateCount( "jobqueue.{$key}.{$type}", $delta );
        }
 }
index 495be73..7c78f40 100644 (file)
@@ -55,6 +55,7 @@ class JobQueueDB extends JobQueue {
         *               If not specified, the primary DB cluster for the wiki will be used.
         *               This can be overridden with a custom cluster so that DB handles will
         *               be retrieved via LBFactory::getExternalLB() and getConnection().
+        *   - wanCache : An instance of WANObjectCache to use for caching.
         * @param array $params
         */
        protected function __construct( array $params ) {
@@ -66,7 +67,7 @@ class JobQueueDB extends JobQueue {
                        $this->cluster = $params['cluster'];
                }
 
-               $this->cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
+               $this->cache = $params['wanCache'] ?? WANObjectCache::newEmpty();
        }
 
        protected function supportedOrders() {
@@ -83,12 +84,14 @@ class JobQueueDB extends JobQueue {
         */
        protected function doIsEmpty() {
                $dbr = $this->getReplicaDB();
+               /** @noinspection PhpUnusedLocalVariableInspection */
+               $scope = $this->getScopedNoTrxFlag( $dbr );
                try {
                        $found = $dbr->selectField( // unclaimed job
                                'job', '1', [ 'job_cmd' => $this->type, 'job_token' => '' ], __METHOD__
                        );
                } catch ( DBError $e ) {
-                       $this->throwDBException( $e );
+                       throw $this->getDBException( $e );
                }
 
                return !$found;
@@ -106,14 +109,16 @@ class JobQueueDB extends JobQueue {
                        return $size;
                }
 
+               $dbr = $this->getReplicaDB();
+               /** @noinspection PhpUnusedLocalVariableInspection */
+               $scope = $this->getScopedNoTrxFlag( $dbr );
                try {
-                       $dbr = $this->getReplicaDB();
                        $size = (int)$dbr->selectField( 'job', 'COUNT(*)',
                                [ 'job_cmd' => $this->type, 'job_token' => '' ],
                                __METHOD__
                        );
                } catch ( DBError $e ) {
-                       $this->throwDBException( $e );
+                       throw $this->getDBException( $e );
                }
                $this->cache->set( $key, $size, self::CACHE_TTL_SHORT );
 
@@ -137,13 +142,15 @@ class JobQueueDB extends JobQueue {
                }
 
                $dbr = $this->getReplicaDB();
+               /** @noinspection PhpUnusedLocalVariableInspection */
+               $scope = $this->getScopedNoTrxFlag( $dbr );
                try {
                        $count = (int)$dbr->selectField( 'job', 'COUNT(*)',
                                [ 'job_cmd' => $this->type, "job_token != {$dbr->addQuotes( '' )}" ],
                                __METHOD__
                        );
                } catch ( DBError $e ) {
-                       $this->throwDBException( $e );
+                       throw $this->getDBException( $e );
                }
                $this->cache->set( $key, $count, self::CACHE_TTL_SHORT );
 
@@ -168,6 +175,8 @@ class JobQueueDB extends JobQueue {
                }
 
                $dbr = $this->getReplicaDB();
+               /** @noinspection PhpUnusedLocalVariableInspection */
+               $scope = $this->getScopedNoTrxFlag( $dbr );
                try {
                        $count = (int)$dbr->selectField( 'job', 'COUNT(*)',
                                [
@@ -178,7 +187,7 @@ class JobQueueDB extends JobQueue {
                                __METHOD__
                        );
                } catch ( DBError $e ) {
-                       $this->throwDBException( $e );
+                       throw $this->getDBException( $e );
                }
 
                $this->cache->set( $key, $count, self::CACHE_TTL_SHORT );
@@ -195,6 +204,8 @@ class JobQueueDB extends JobQueue {
         */
        protected function doBatchPush( array $jobs, $flags ) {
                $dbw = $this->getMasterDB();
+               /** @noinspection PhpUnusedLocalVariableInspection */
+               $scope = $this->getScopedNoTrxFlag( $dbw );
                // In general, there will be two cases here:
                // a) sqlite; DB connection is probably a regular round-aware handle.
                // If the connection is busy with a transaction, then defer the job writes
@@ -265,12 +276,12 @@ class JobQueueDB extends JobQueue {
                        foreach ( array_chunk( $rows, 50 ) as $rowBatch ) {
                                $dbw->insert( 'job', $rowBatch, $method );
                        }
-                       JobQueue::incrStats( 'inserts', $this->type, count( $rows ) );
-                       JobQueue::incrStats( 'dupe_inserts', $this->type,
+                       $this->incrStats( 'inserts', $this->type, count( $rows ) );
+                       $this->incrStats( 'dupe_inserts', $this->type,
                                count( $rowSet ) + count( $rowList ) - count( $rows )
                        );
                } catch ( DBError $e ) {
-                       $this->throwDBException( $e );
+                       throw $this->getDBException( $e );
                }
                if ( $flags & self::QOS_ATOMIC ) {
                        $dbw->endAtomic( $method );
@@ -279,19 +290,16 @@ class JobQueueDB extends JobQueue {
 
        /**
         * @see JobQueue::doPop()
-        * @return Job|bool
+        * @return RunnableJob|bool
         */
        protected function doPop() {
                $dbw = $this->getMasterDB();
-               try {
-                       $autoTrx = $dbw->getFlag( DBO_TRX ); // get current setting
-                       $dbw->clearFlag( DBO_TRX ); // make each query its own transaction
-                       $scopedReset = new ScopedCallback( function () use ( $dbw, $autoTrx ) {
-                               $dbw->setFlag( $autoTrx ? DBO_TRX : 0 ); // restore old setting
-                       } );
+               /** @noinspection PhpUnusedLocalVariableInspection */
+               $scope = $this->getScopedNoTrxFlag( $dbw );
 
+               $job = false; // job popped off
+               try {
                        $uuid = wfRandomString( 32 ); // pop attempt
-                       $job = false; // job popped off
                        do { // retry when our row is invalid or deleted as a duplicate
                                // Try to reserve a row in the DB...
                                if ( in_array( $this->order, [ 'fifo', 'timestamp' ] ) ) {
@@ -305,13 +313,10 @@ class JobQueueDB extends JobQueue {
                                if ( !$row ) {
                                        break; // nothing to do
                                }
-                               JobQueue::incrStats( 'pops', $this->type );
+                               $this->incrStats( 'pops', $this->type );
+
                                // Get the job object from the row...
-                               $title = Title::makeTitle( $row->job_namespace, $row->job_title );
-                               $job = Job::factory( $row->job_cmd, $title,
-                                       self::extractBlob( $row->job_params ) );
-                               $job->metadata['id'] = $row->job_id;
-                               $job->metadata['timestamp'] = $row->job_timestamp;
+                               $job = $this->jobFromRow( $row );
                                break; // done
                        } while ( true );
 
@@ -321,7 +326,7 @@ class JobQueueDB extends JobQueue {
                                $this->recycleAndDeleteStaleJobs();
                        }
                } catch ( DBError $e ) {
-                       $this->throwDBException( $e );
+                       throw $this->getDBException( $e );
                }
 
                return $job;
@@ -337,10 +342,11 @@ class JobQueueDB extends JobQueue {
         */
        protected function claimRandom( $uuid, $rand, $gte ) {
                $dbw = $this->getMasterDB();
+               /** @noinspection PhpUnusedLocalVariableInspection */
+               $scope = $this->getScopedNoTrxFlag( $dbw );
                // Check cache to see if the queue has <= OFFSET items
                $tinyQueue = $this->cache->get( $this->getCacheKey( 'small' ) );
 
-               $row = false; // the row acquired
                $invertedDirection = false; // whether one job_random direction was already scanned
                // This uses a replication safe method for acquiring jobs. One could use UPDATE+LIMIT
                // instead, but that either uses ORDER BY (in which case it deadlocks in MySQL) or is
@@ -414,6 +420,8 @@ class JobQueueDB extends JobQueue {
         */
        protected function claimOldest( $uuid ) {
                $dbw = $this->getMasterDB();
+               /** @noinspection PhpUnusedLocalVariableInspection */
+               $scope = $this->getScopedNoTrxFlag( $dbw );
 
                $row = false; // the row acquired
                do {
@@ -469,29 +477,29 @@ class JobQueueDB extends JobQueue {
 
        /**
         * @see JobQueue::doAck()
-        * @param Job $job
+        * @param RunnableJob $job
         * @throws MWException
         */
-       protected function doAck( Job $job ) {
-               if ( !isset( $job->metadata['id'] ) ) {
+       protected function doAck( RunnableJob $job ) {
+               $id = $job->getMetadata( 'id' );
+               if ( $id === null ) {
                        throw new MWException( "Job of type '{$job->getType()}' has no ID." );
                }
 
                $dbw = $this->getMasterDB();
+               /** @noinspection PhpUnusedLocalVariableInspection */
+               $scope = $this->getScopedNoTrxFlag( $dbw );
                try {
-                       $autoTrx = $dbw->getFlag( DBO_TRX ); // get current setting
-                       $dbw->clearFlag( DBO_TRX ); // make each query its own transaction
-                       $scopedReset = new ScopedCallback( function () use ( $dbw, $autoTrx ) {
-                               $dbw->setFlag( $autoTrx ? DBO_TRX : 0 ); // restore old setting
-                       } );
-
                        // Delete a row with a single DELETE without holding row locks over RTTs...
-                       $dbw->delete( 'job',
-                               [ 'job_cmd' => $this->type, 'job_id' => $job->metadata['id'] ], __METHOD__ );
+                       $dbw->delete(
+                               'job',
+                               [ 'job_cmd' => $this->type, 'job_id' => $id ],
+                               __METHOD__
+                       );
 
-                       JobQueue::incrStats( 'acks', $this->type );
+                       $this->incrStats( 'acks', $this->type );
                } catch ( DBError $e ) {
-                       $this->throwDBException( $e );
+                       throw $this->getDBException( $e );
                }
        }
 
@@ -515,6 +523,9 @@ class JobQueueDB extends JobQueue {
                // maintained. Having only the de-duplication registration succeed would cause
                // jobs to become no-ops without any actual jobs that made them redundant.
                $dbw = $this->getMasterDB();
+               /** @noinspection PhpUnusedLocalVariableInspection */
+               $scope = $this->getScopedNoTrxFlag( $dbw );
+
                $cache = $this->dupCache;
                $dbw->onTransactionCommitOrIdle(
                        function () use ( $cache, $params, $key ) {
@@ -538,10 +549,12 @@ class JobQueueDB extends JobQueue {
         */
        protected function doDelete() {
                $dbw = $this->getMasterDB();
+               /** @noinspection PhpUnusedLocalVariableInspection */
+               $scope = $this->getScopedNoTrxFlag( $dbw );
                try {
                        $dbw->delete( 'job', [ 'job_cmd' => $this->type ] );
                } catch ( DBError $e ) {
-                       $this->throwDBException( $e );
+                       throw $this->getDBException( $e );
                }
 
                return true;
@@ -594,23 +607,17 @@ class JobQueueDB extends JobQueue {
         */
        protected function getJobIterator( array $conds ) {
                $dbr = $this->getReplicaDB();
+               /** @noinspection PhpUnusedLocalVariableInspection */
+               $scope = $this->getScopedNoTrxFlag( $dbr );
                try {
                        return new MappedIterator(
                                $dbr->select( 'job', self::selectFields(), $conds ),
                                function ( $row ) {
-                                       $job = Job::factory(
-                                               $row->job_cmd,
-                                               Title::makeTitle( $row->job_namespace, $row->job_title ),
-                                               strlen( $row->job_params ) ? unserialize( $row->job_params ) : []
-                                       );
-                                       $job->metadata['id'] = $row->job_id;
-                                       $job->metadata['timestamp'] = $row->job_timestamp;
-
-                                       return $job;
+                                       return $this->jobFromRow( $row );
                                }
                        );
                } catch ( DBError $e ) {
-                       $this->throwDBException( $e );
+                       throw $this->getDBException( $e );
                }
        }
 
@@ -626,6 +633,8 @@ class JobQueueDB extends JobQueue {
 
        protected function doGetSiblingQueuesWithJobs( array $types ) {
                $dbr = $this->getReplicaDB();
+               /** @noinspection PhpUnusedLocalVariableInspection */
+               $scope = $this->getScopedNoTrxFlag( $dbr );
                // @note: this does not check whether the jobs are claimed or not.
                // This is useful so JobQueueGroup::pop() also sees queues that only
                // have stale jobs. This lets recycleAndDeleteStaleJobs() re-enqueue
@@ -643,6 +652,9 @@ class JobQueueDB extends JobQueue {
 
        protected function doGetSiblingQueueSizes( array $types ) {
                $dbr = $this->getReplicaDB();
+               /** @noinspection PhpUnusedLocalVariableInspection */
+               $scope = $this->getScopedNoTrxFlag( $dbr );
+
                $res = $dbr->select( 'job', [ 'job_cmd', 'COUNT(*) AS count' ],
                        [ 'job_cmd' => $types ], __METHOD__, [ 'GROUP BY' => 'job_cmd' ] );
 
@@ -663,6 +675,8 @@ class JobQueueDB extends JobQueue {
                $now = time();
                $count = 0; // affected rows
                $dbw = $this->getMasterDB();
+               /** @noinspection PhpUnusedLocalVariableInspection */
+               $scope = $this->getScopedNoTrxFlag( $dbw );
 
                try {
                        if ( !$dbw->lock( "jobqueue-recycle-{$this->type}", __METHOD__, 1 ) ) {
@@ -702,8 +716,7 @@ class JobQueueDB extends JobQueue {
                                        );
                                        $affected = $dbw->affectedRows();
                                        $count += $affected;
-                                       JobQueue::incrStats( 'recycles', $this->type, $affected );
-                                       $this->aggr->notifyQueueNonEmpty( $this->domain, $this->type );
+                                       $this->incrStats( 'recycles', $this->type, $affected );
                                }
                        }
 
@@ -729,12 +742,12 @@ class JobQueueDB extends JobQueue {
                                $dbw->delete( 'job', [ 'job_id' => $ids ], __METHOD__ );
                                $affected = $dbw->affectedRows();
                                $count += $affected;
-                               JobQueue::incrStats( 'abandons', $this->type, $affected );
+                               $this->incrStats( 'abandons', $this->type, $affected );
                        }
 
                        $dbw->unlock( "jobqueue-recycle-{$this->type}", __METHOD__ );
                } catch ( DBError $e ) {
-                       $this->throwDBException( $e );
+                       throw $this->getDBException( $e );
                }
 
                return $count;
@@ -749,8 +762,8 @@ class JobQueueDB extends JobQueue {
                return [
                        // Fields that describe the nature of the job
                        'job_cmd' => $job->getType(),
-                       'job_namespace' => $job->getTitle()->getNamespace(),
-                       'job_title' => $job->getTitle()->getDBkey(),
+                       'job_namespace' => $job->getParams()['namespace'] ?? NS_SPECIAL,
+                       'job_title' => $job->getParams()['title'] ?? '',
                        'job_params' => self::makeBlob( $job->getParams() ),
                        // Additional job metadata
                        'job_timestamp' => $db->timestamp(),
@@ -821,6 +834,21 @@ class JobQueueDB extends JobQueue {
                }
        }
 
+       /**
+        * @param IDatabase $db
+        * @return ScopedCallback
+        */
+       private function getScopedNoTrxFlag( IDatabase $db ) {
+               $autoTrx = $db->getFlag( DBO_TRX ); // get current setting
+               $db->clearFlag( DBO_TRX ); // make each query its own transaction
+
+               return new ScopedCallback( function () use ( $db, $autoTrx ) {
+                       if ( $autoTrx ) {
+                               $db->setFlag( DBO_TRX ); // restore old setting
+                       }
+               } );
+       }
+
        /**
         * @param string $property
         * @return string
@@ -850,23 +878,30 @@ class JobQueueDB extends JobQueue {
        }
 
        /**
-        * @param string $blob
-        * @return bool|mixed
+        * @param stdClass $row
+        * @return RunnableJob|null
         */
-       protected static function extractBlob( $blob ) {
-               if ( (string)$blob !== '' ) {
-                       return unserialize( $blob );
-               } else {
-                       return false;
+       protected function jobFromRow( $row ) {
+               $params = ( (string)$row->job_params !== '' ) ? unserialize( $row->job_params ) : [];
+               if ( !is_array( $params ) ) { // this shouldn't happen
+                       throw new UnexpectedValueException(
+                               "Could not unserialize job with ID '{$row->job_id}'." );
                }
+
+               $params += [ 'namespace' => $row->job_namespace, 'title' => $row->job_title ];
+               $job = $this->factoryJob( $row->job_cmd, $params );
+               $job->setMetadata( 'id', $row->job_id );
+               $job->setMetadata( 'timestamp', $row->job_timestamp );
+
+               return $job;
        }
 
        /**
         * @param DBError $e
-        * @throws JobQueueError
+        * @return JobQueueError
         */
-       protected function throwDBException( DBError $e ) {
-               throw new JobQueueError( get_class( $e ) . ": " . $e->getMessage() );
+       protected function getDBException( DBError $e ) {
+               return new JobQueueError( get_class( $e ) . ": " . $e->getMessage() );
        }
 
        /**
index 2025bf7..8b5a62e 100644 (file)
@@ -199,7 +199,7 @@ class JobQueueFederated extends JobQueue {
         * @param HashRing &$partitionRing
         * @param int $flags
         * @throws JobQueueError
-        * @return array List of Job object that could not be inserted
+        * @return IJobSpecification[] List of Job object that could not be inserted
         */
        protected function tryJobInsertions( array $jobs, HashRing &$partitionRing, $flags ) {
                $jobsLeft = [];
@@ -287,7 +287,7 @@ class JobQueueFederated extends JobQueue {
                                $job = false;
                        }
                        if ( $job ) {
-                               $job->metadata['QueuePartition'] = $partition;
+                               $job->setMetadata( 'QueuePartition', $partition );
 
                                return $job;
                        } else {
@@ -299,15 +299,16 @@ class JobQueueFederated extends JobQueue {
                return false;
        }
 
-       protected function doAck( Job $job ) {
-               if ( !isset( $job->metadata['QueuePartition'] ) ) {
+       protected function doAck( RunnableJob $job ) {
+               $partition = $job->getMetadata( 'QueuePartition' );
+               if ( $partition === null ) {
                        throw new MWException( "The given job has no defined partition name." );
                }
 
-               $this->partitionQueues[$job->metadata['QueuePartition']]->ack( $job );
+               $this->partitionQueues[$partition]->ack( $job );
        }
 
-       protected function doIsRootJobOldDuplicate( Job $job ) {
+       protected function doIsRootJobOldDuplicate( IJobSpecification $job ) {
                $signature = $job->getRootJobParams()['rootJobSignature'];
                $partition = $this->partitionRing->getLiveLocation( $signature );
                try {
index 328f298..7a0d4ea 100644 (file)
@@ -114,11 +114,15 @@ class JobQueueGroup {
                } else {
                        $conf = $conf + $wgJobTypeConf['default'];
                }
-               $conf['aggregator'] = JobQueueAggregator::singleton();
                if ( !isset( $conf['readOnlyReason'] ) ) {
                        $conf['readOnlyReason'] = $this->readOnlyReason;
                }
 
+               $services = MediaWikiServices::getInstance();
+               $conf['stats'] = $services->getStatsdDataFactory();
+               $conf['wanCache'] = $services->getMainWANObjectCache();
+               $conf['stash'] = $services->getMainObjectStash();
+
                return JobQueue::factory( $conf );
        }
 
@@ -183,10 +187,6 @@ class JobQueueGroup {
        /**
         * Buffer jobs for insertion via push() or call it now if in CLI mode
         *
-        * Note that pushLazyJobs() is registered as a deferred update just before
-        * DeferredUpdates::doUpdates() in MediaWiki and JobRunner classes in order
-        * to be executed as the very last deferred update (T100085, T154425).
-        *
         * @param IJobSpecification|IJobSpecification[] $jobs A single Job or a list of Jobs
         * @return void
         * @since 1.26
@@ -210,17 +210,6 @@ class JobQueueGroup {
                DeferredUpdates::addUpdate( new JobQueueEnqueueUpdate( $this->domain, $jobs ) );
        }
 
-       /**
-        * Push all jobs buffered via lazyPush() into their respective queues
-        *
-        * @return void
-        * @since 1.26
-        * @deprecated Since 1.33 Not needed anymore
-        */
-       public static function pushLazyJobs() {
-               wfDeprecated( __METHOD__, '1.33' );
-       }
-
        /**
         * Pop a job off one of the job queues
         *
@@ -230,11 +219,21 @@ class JobQueueGroup {
         * @param int|string $qtype JobQueueGroup::TYPE_* constant or job type string
         * @param int $flags Bitfield of JobQueueGroup::USE_* constants
         * @param array $blacklist List of job types to ignore
-        * @return Job|bool Returns false on failure
+        * @return RunnableJob|bool Returns false on failure
         */
        public function pop( $qtype = self::TYPE_DEFAULT, $flags = 0, array $blacklist = [] ) {
+               global $wgJobClasses;
+
                $job = false;
 
+               if ( !WikiMap::isCurrentWikiDbDomain( $this->domain ) ) {
+                       throw new JobQueueError(
+                               "Cannot pop '{$qtype}' job off foreign '{$this->domain}' wiki queue." );
+               } elseif ( is_string( $qtype ) && !isset( $wgJobClasses[$qtype] ) ) {
+                       // Do not pop jobs if there is no class for the queue type
+                       throw new JobQueueError( "Unrecognized job type '$qtype'." );
+               }
+
                if ( is_string( $qtype ) ) { // specific job type
                        if ( !in_array( $qtype, $blacklist ) ) {
                                $job = $this->get( $qtype )->pop();
@@ -353,12 +352,14 @@ class JobQueueGroup {
        /**
         * Get the list of job types that have non-empty queues
         *
-        * @return array List of job types that have non-empty queues
+        * @return string[] List of job types that have non-empty queues
         */
        public function getQueuesWithJobs() {
                $types = [];
                foreach ( $this->getCoalescedQueues() as $info ) {
-                       $nonEmpty = $info['queue']->getSiblingQueuesWithJobs( $this->getQueueTypes() );
+                       /** @var JobQueue $queue */
+                       $queue = $info['queue'];
+                       $nonEmpty = $queue->getSiblingQueuesWithJobs( $this->getQueueTypes() );
                        if ( is_array( $nonEmpty ) ) { // batching features supported
                                $types = array_merge( $types, $nonEmpty );
                        } else { // we have to go through the queues in the bucket one-by-one
@@ -376,12 +377,14 @@ class JobQueueGroup {
        /**
         * Get the size of the queus for a list of job types
         *
-        * @return array Map of (job type => size)
+        * @return int[] Map of (job type => size)
         */
        public function getQueueSizes() {
                $sizeMap = [];
                foreach ( $this->getCoalescedQueues() as $info ) {
-                       $sizes = $info['queue']->getSiblingQueueSizes( $this->getQueueTypes() );
+                       /** @var JobQueue $queue */
+                       $queue = $info['queue'];
+                       $sizes = $queue->getSiblingQueueSizes( $this->getQueueTypes() );
                        if ( is_array( $sizes ) ) { // batching features supported
                                $sizeMap = $sizeMap + $sizes;
                        } else { // we have to go through the queues in the bucket one-by-one
@@ -395,7 +398,7 @@ class JobQueueGroup {
        }
 
        /**
-        * @return array
+        * @return JobQueue[]
         */
        protected function getCoalescedQueues() {
                global $wgJobTypeConf;
@@ -404,7 +407,7 @@ class JobQueueGroup {
                        $this->coalescedQueues = [];
                        foreach ( $wgJobTypeConf as $type => $conf ) {
                                $queue = JobQueue::factory(
-                                       [ 'wiki' => $this->domain, 'type' => 'null' ] + $conf );
+                                       [ 'domain' => $this->domain, 'type' => 'null' ] + $conf );
                                $loc = $queue->getCoalesceLocationInternal();
                                if ( !isset( $this->coalescedQueues[$loc] ) ) {
                                        $this->coalescedQueues[$loc]['queue'] = $queue;
index 9b1fbdf..cb20a76 100644 (file)
@@ -32,6 +32,12 @@ class JobQueueMemory extends JobQueue {
        /** @var array[] */
        protected static $data = [];
 
+       public function __construct( array $params ) {
+               parent::__construct( $params );
+
+               $this->dupCache = new HashBagOStuff();
+       }
+
        /**
         * @see JobQueue::doBatchPush
         *
@@ -43,10 +49,7 @@ class JobQueueMemory extends JobQueue {
 
                foreach ( $jobs as $job ) {
                        if ( $job->ignoreDuplicates() ) {
-                               $sha1 = Wikimedia\base_convert(
-                                       sha1( serialize( $job->getDeduplicationInfo() ) ),
-                                       16, 36, 31
-                               );
+                               $sha1 = sha1( serialize( $job->getDeduplicationInfo() ) );
                                if ( !isset( $unclaimed[$sha1] ) ) {
                                        $unclaimed[$sha1] = $job;
                                }
@@ -108,7 +111,7 @@ class JobQueueMemory extends JobQueue {
        /**
         * @see JobQueue::doPop
         *
-        * @return Job|bool
+        * @return RunnableJob|bool
         */
        protected function doPop() {
                if ( $this->doGetSize() == 0 ) {
@@ -132,7 +135,7 @@ class JobQueueMemory extends JobQueue {
                $job = $this->jobFromSpecInternal( $spec );
 
                end( $claimed );
-               $job->metadata['claimId'] = key( $claimed );
+               $job->setMetadata( 'claimId', key( $claimed ) );
 
                return $job;
        }
@@ -140,15 +143,15 @@ class JobQueueMemory extends JobQueue {
        /**
         * @see JobQueue::doAck
         *
-        * @param Job $job
+        * @param RunnableJob $job
         */
-       protected function doAck( Job $job ) {
+       protected function doAck( RunnableJob $job ) {
                if ( $this->getAcquiredCount() == 0 ) {
                        return;
                }
 
                $claimed =& $this->getQueueData( 'claimed' );
-               unset( $claimed[$job->metadata['claimId']] );
+               unset( $claimed[$job->getMetadata( 'claimId' )] );
        }
 
        /**
@@ -203,11 +206,10 @@ class JobQueueMemory extends JobQueue {
 
        /**
         * @param IJobSpecification $spec
-        *
-        * @return Job
+        * @return RunnableJob
         */
        public function jobFromSpecInternal( IJobSpecification $spec ) {
-               return Job::factory( $spec->getType(), $spec->getTitle(), $spec->getParams() );
+               return $this->factoryJob( $spec->getType(), $spec->getParams() );
        }
 
        /**
index 5e7a115..2140043 100644 (file)
@@ -225,9 +225,9 @@ class JobQueueRedis extends JobQueue {
                                        $failed += count( $itemBatch );
                                }
                        }
-                       JobQueue::incrStats( 'inserts', $this->type, count( $items ) );
-                       JobQueue::incrStats( 'inserts_actual', $this->type, $pushed );
-                       JobQueue::incrStats( 'dupe_inserts', $this->type,
+                       $this->incrStats( 'inserts', $this->type, count( $items ) );
+                       $this->incrStats( 'inserts_actual', $this->type, $pushed );
+                       $this->incrStats( 'dupe_inserts', $this->type,
                                count( $items ) - $failed - $pushed );
                        if ( $failed > 0 ) {
                                $err = "Could not insert {$failed} {$this->type} job(s).";
@@ -307,7 +307,7 @@ LUA;
 
        /**
         * @see JobQueue::doPop()
-        * @return Job|bool
+        * @return RunnableJob|bool
         * @throws JobQueueError
         */
        protected function doPop() {
@@ -321,7 +321,7 @@ LUA;
                                        break; // no jobs; nothing to do
                                }
 
-                               JobQueue::incrStats( 'pops', $this->type );
+                               $this->incrStats( 'pops', $this->type );
                                $item = $this->unserialize( $blob );
                                if ( $item === false ) {
                                        wfDebugLog( 'JobQueueRedis', "Could not unserialize {$this->type} job." );
@@ -379,17 +379,17 @@ LUA;
 
        /**
         * @see JobQueue::doAck()
-        * @param Job $job
-        * @return Job|bool
+        * @param RunnableJob $job
+        * @return RunnableJob|bool
         * @throws UnexpectedValueException
         * @throws JobQueueError
         */
-       protected function doAck( Job $job ) {
-               if ( !isset( $job->metadata['uuid'] ) ) {
+       protected function doAck( RunnableJob $job ) {
+               $uuid = $job->getMetadata( 'uuid' );
+               if ( $uuid === null ) {
                        throw new UnexpectedValueException( "Job of type '{$job->getType()}' has no UUID." );
                }
 
-               $uuid = $job->metadata['uuid'];
                $conn = $this->getConnection();
                try {
                        static $script =
@@ -424,7 +424,7 @@ LUA;
                                return false;
                        }
 
-                       JobQueue::incrStats( 'acks', $this->type );
+                       $this->incrStats( 'acks', $this->type );
                } catch ( RedisException $e ) {
                        $this->throwRedisException( $conn, $e );
                }
@@ -463,11 +463,11 @@ LUA;
 
        /**
         * @see JobQueue::doIsRootJobOldDuplicate()
-        * @param Job $job
+        * @param IJobSpecification $job
         * @return bool
         * @throws JobQueueError
         */
-       protected function doIsRootJobOldDuplicate( Job $job ) {
+       protected function doIsRootJobOldDuplicate( IJobSpecification $job ) {
                if ( !$job->hasRootJobParams() ) {
                        return false; // job has no de-deplication info
                }
@@ -627,7 +627,7 @@ LUA;
         *
         * @param string $uid
         * @param RedisConnRef $conn
-        * @return Job|bool Returns false if the job does not exist
+        * @return RunnableJob|bool Returns false if the job does not exist
         * @throws JobQueueError
         * @throws UnexpectedValueException
         */
@@ -639,14 +639,17 @@ LUA;
                        }
                        $item = $this->unserialize( $data );
                        if ( !is_array( $item ) ) { // this shouldn't happen
-                               throw new UnexpectedValueException( "Could not find job with ID '$uid'." );
+                               throw new UnexpectedValueException( "Could not unserialize job with ID '$uid'." );
                        }
-                       $title = Title::makeTitle( $item['namespace'], $item['title'] );
-                       $job = Job::factory( $item['type'], $title, $item['params'] );
-                       $job->metadata['uuid'] = $item['uuid'];
-                       $job->metadata['timestamp'] = $item['timestamp'];
+
+                       $params = $item['params'];
+                       $params += [ 'namespace' => $item['namespace'], 'title' => $item['title'] ];
+                       $job = $this->factoryJob( $item['type'], $params );
+                       $job->setMetadata( 'uuid', $item['uuid'] );
+                       $job->setMetadata( 'timestamp', $item['timestamp'] );
                        // Add in attempt count for debugging at showJobs.php
-                       $job->metadata['attempts'] = $conn->hGet( $this->getQueueKey( 'h-attempts' ), $uid );
+                       $job->setMetadata( 'attempts',
+                               $conn->hGet( $this->getQueueKey( 'h-attempts' ), $uid ) );
 
                        return $job;
                } catch ( RedisException $e ) {
@@ -683,8 +686,8 @@ LUA;
                return [
                        // Fields that describe the nature of the job
                        'type' => $job->getType(),
-                       'namespace' => $job->getTitle()->getNamespace(),
-                       'title' => $job->getTitle()->getDBkey(),
+                       'namespace' => $job->getParams()['namespace'] ?? NS_SPECIAL,
+                       'title' => $job->getParams()['title'] ?? '',
                        'params' => $job->getParams(),
                        // Some jobs cannot run until a "release timestamp"
                        'rtimestamp' => $job->getReleaseTimestamp() ?: 0,
@@ -699,13 +702,15 @@ LUA;
 
        /**
         * @param array $fields
-        * @return Job|bool
+        * @return RunnableJob|bool
         */
        protected function getJobFromFields( array $fields ) {
-               $title = Title::makeTitle( $fields['namespace'], $fields['title'] );
-               $job = Job::factory( $fields['type'], $title, $fields['params'] );
-               $job->metadata['uuid'] = $fields['uuid'];
-               $job->metadata['timestamp'] = $fields['timestamp'];
+               $params = $fields['params'];
+               $params += [ 'namespace' => $fields['namespace'], 'title' => $fields['title'] ];
+
+               $job = $this->factoryJob( $fields['type'], $params );
+               $job->setMetadata( 'uuid', $fields['uuid'] );
+               $job->setMetadata( 'timestamp', $fields['timestamp'] );
 
                return $job;
        }
index 4abbc6d..80a46d0 100644 (file)
@@ -28,8 +28,7 @@
  * $job = new JobSpecification(
  *             'null',
  *             array( 'lives' => 1, 'usleep' => 100, 'pi' => 3.141569 ),
- *             array( 'removeDuplicates' => 1 ),
- *             Title::makeTitle( NS_SPECIAL, 'nullity' )
+ *             array( 'removeDuplicates' => 1 )
  * );
  * JobQueueGroup::singleton()->push( $job )
  * @endcode
@@ -63,8 +62,19 @@ class JobSpecification implements IJobSpecification {
                $this->validateParams( $opts );
 
                $this->type = $type;
+               if ( $title instanceof Title ) {
+                       // Make sure JobQueue classes can pull the title from parameters alone
+                       if ( $title->getDBkey() !== '' ) {
+                               $params += [
+                                       'namespace' => $title->getNamespace(),
+                                       'title' => $title->getDBkey()
+                               ];
+                       }
+               } else {
+                       $title = Title::makeTitle( NS_SPECIAL, '' );
+               }
                $this->params = $params;
-               $this->title = $title ?: Title::makeTitle( NS_SPECIAL, 'Badtitle/' . static::class );
+               $this->title = $title;
                $this->opts = $opts;
        }
 
diff --git a/includes/jobqueue/RunnableJob.php b/includes/jobqueue/RunnableJob.php
new file mode 100644 (file)
index 0000000..e477b12
--- /dev/null
@@ -0,0 +1,54 @@
+<?php
+/**
+ * Job queue task instance that can be executed via a run() method
+ *
+ * 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
+ */
+
+/**
+ * Job that has a run() method and metadata accessors for JobQueue::pop() and JobQueue::ack()
+ *
+ * Instances are not only enqueueable via JobQueue::push(), but they can also be executed by
+ * by calling their run() method. When constructing a job to be enqueued via JobQueue::push(),
+ * it will not be possible to construct a RunnableJob instance if the class for that job is not
+ * loaded by the application for the local DB domain. In that case, the general-purpose
+ * JobSpecification class can be used instead.
+ *
+ * @ingroup JobQueue
+ * @since 1.33
+ */
+interface RunnableJob extends IJobSpecification {
+       /**
+        * Run the job
+        * @return bool Success
+        */
+       public function run();
+
+       /**
+        * @param string|null $field Metadata field or null to get all the metadata
+        * @return mixed|null Value; null if missing
+        */
+       public function getMetadata( $field = null );
+
+       /**
+        * @param string $field Key name to set the value for
+        * @param mixed $value The value to set the field for
+        * @return mixed|null The prior field value; null if missing
+        */
+       public function setMetadata( $field, $value );
+}
diff --git a/includes/jobqueue/aggregator/JobQueueAggregator.php b/includes/jobqueue/aggregator/JobQueueAggregator.php
deleted file mode 100644 (file)
index b44fc45..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-<?php
-/**
- * Job queue aggregator code.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-/**
- * Class to handle tracking information about all queues
- *
- * @ingroup JobQueue
- * @since 1.21
- */
-abstract class JobQueueAggregator {
-       /** @var JobQueueAggregator */
-       protected static $instance = null;
-
-       /**
-        * @param array $params
-        */
-       public function __construct( array $params ) {
-       }
-
-       /**
-        * @throws MWException
-        * @return JobQueueAggregator
-        */
-       final public static function singleton() {
-               global $wgJobQueueAggregator;
-
-               if ( !isset( self::$instance ) ) {
-                       $class = $wgJobQueueAggregator['class'];
-                       $obj = new $class( $wgJobQueueAggregator );
-                       if ( !( $obj instanceof JobQueueAggregator ) ) {
-                               throw new MWException( "Class '$class' is not a JobQueueAggregator class." );
-                       }
-                       self::$instance = $obj;
-               }
-
-               return self::$instance;
-       }
-
-       /**
-        * Destroy the singleton instance
-        *
-        * @return void
-        */
-       final public static function destroySingleton() {
-               self::$instance = null;
-       }
-
-       /**
-        * Mark a queue as being empty
-        *
-        * @param string $wiki
-        * @param string $type
-        * @return bool Success
-        */
-       final public function notifyQueueEmpty( $wiki, $type ) {
-               $ok = $this->doNotifyQueueEmpty( $wiki, $type );
-
-               return $ok;
-       }
-
-       /**
-        * @see JobQueueAggregator::notifyQueueEmpty()
-        * @param string $wiki
-        * @param string $type
-        * @return bool
-        */
-       abstract protected function doNotifyQueueEmpty( $wiki, $type );
-
-       /**
-        * Mark a queue as being non-empty
-        *
-        * @param string $wiki
-        * @param string $type
-        * @return bool Success
-        */
-       final public function notifyQueueNonEmpty( $wiki, $type ) {
-               $ok = $this->doNotifyQueueNonEmpty( $wiki, $type );
-
-               return $ok;
-       }
-
-       /**
-        * @see JobQueueAggregator::notifyQueueNonEmpty()
-        * @param string $wiki
-        * @param string $type
-        * @return bool
-        */
-       abstract protected function doNotifyQueueNonEmpty( $wiki, $type );
-
-       /**
-        * Get the list of all of the queues with jobs
-        *
-        * @return array (job type => (list of wiki IDs))
-        */
-       final public function getAllReadyWikiQueues() {
-               $res = $this->doGetAllReadyWikiQueues();
-
-               return $res;
-       }
-
-       /**
-        * @see JobQueueAggregator::getAllReadyWikiQueues()
-        */
-       abstract protected function doGetAllReadyWikiQueues();
-
-       /**
-        * Purge all of the aggregator information
-        *
-        * @return bool Success
-        */
-       final public function purge() {
-               $res = $this->doPurge();
-
-               return $res;
-       }
-
-       /**
-        * @see JobQueueAggregator::purge()
-        */
-       abstract protected function doPurge();
-
-       /**
-        * Get all databases that have a pending job.
-        * This poll all the queues and is this expensive.
-        *
-        * @return array (job type => (list of wiki IDs))
-        */
-       protected function findPendingWikiQueues() {
-               global $wgLocalDatabases;
-
-               $pendingDBs = []; // (job type => (db list))
-               foreach ( $wgLocalDatabases as $wikiId ) {
-                       foreach ( JobQueueGroup::singleton( $wikiId )->getQueuesWithJobs() as $type ) {
-                               $pendingDBs[$type][] = $wikiId;
-                       }
-               }
-
-               return $pendingDBs;
-       }
-}
diff --git a/includes/jobqueue/aggregator/JobQueueAggregatorNull.php b/includes/jobqueue/aggregator/JobQueueAggregatorNull.php
deleted file mode 100644 (file)
index c44d70e..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-<?php
-/**
- * Job queue aggregator code.
- *
- * 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 JobQueue
- */
-class JobQueueAggregatorNull extends JobQueueAggregator {
-       protected function doNotifyQueueEmpty( $wiki, $type ) {
-               return true;
-       }
-
-       protected function doNotifyQueueNonEmpty( $wiki, $type ) {
-               return true;
-       }
-
-       protected function doGetAllReadyWikiQueues() {
-               return [];
-       }
-
-       protected function doPurge() {
-               return true;
-       }
-}
diff --git a/includes/jobqueue/aggregator/JobQueueAggregatorRedis.php b/includes/jobqueue/aggregator/JobQueueAggregatorRedis.php
deleted file mode 100644 (file)
index 7d0e1e6..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-<?php
-/**
- * Job queue aggregator code that uses PhpRedis.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-use Psr\Log\LoggerInterface;
-
-/**
- * Class to handle tracking information about all queues using PhpRedis
- *
- * The mediawiki/services/jobrunner background service must be set up and running.
- *
- * @ingroup JobQueue
- * @ingroup Redis
- * @since 1.21
- */
-class JobQueueAggregatorRedis extends JobQueueAggregator {
-       /** @var RedisConnectionPool */
-       protected $redisPool;
-       /** @var LoggerInterface */
-       protected $logger;
-       /** @var array List of Redis server addresses */
-       protected $servers;
-
-       /**
-        * @param array $params Possible keys:
-        *   - redisConfig  : An array of parameters to RedisConnectionPool::__construct().
-        *   - redisServers : Array of server entries, the first being the primary and the
-        *                    others being fallback servers. Each entry is either a hostname/port
-        *                    combination or the absolute path of a UNIX socket.
-        *                    If a hostname is specified but no port, the standard port number
-        *                    6379 will be used. Required.
-        */
-       public function __construct( array $params ) {
-               parent::__construct( $params );
-               $this->servers = $params['redisServers'] ?? [ $params['redisServer'] ]; // b/c
-               $params['redisConfig']['serializer'] = 'none';
-               $this->redisPool = RedisConnectionPool::singleton( $params['redisConfig'] );
-               $this->logger = \MediaWiki\Logger\LoggerFactory::getInstance( 'redis' );
-       }
-
-       protected function doNotifyQueueEmpty( $wiki, $type ) {
-               return true; // managed by the service
-       }
-
-       protected function doNotifyQueueNonEmpty( $wiki, $type ) {
-               return true; // managed by the service
-       }
-
-       protected function doGetAllReadyWikiQueues() {
-               $conn = $this->getConnection();
-               if ( !$conn ) {
-                       return [];
-               }
-               try {
-                       $map = $conn->hGetAll( $this->getReadyQueueKey() );
-
-                       if ( is_array( $map ) && isset( $map['_epoch'] ) ) {
-                               unset( $map['_epoch'] ); // ignore
-                               $pendingDBs = []; // (type => list of wikis)
-                               foreach ( $map as $key => $time ) {
-                                       list( $type, $wiki ) = $this->decodeQueueName( $key );
-                                       $pendingDBs[$type][] = $wiki;
-                               }
-                       } else {
-                               throw new UnexpectedValueException(
-                                       "No queue listing found; make sure redisJobChronService is running."
-                               );
-                       }
-
-                       return $pendingDBs;
-               } catch ( RedisException $e ) {
-                       $this->redisPool->handleError( $conn, $e );
-
-                       return [];
-               }
-       }
-
-       protected function doPurge() {
-               return true; // fully and only refreshed by the service
-       }
-
-       /**
-        * Get a connection to the server that handles all sub-queues for this queue
-        *
-        * @return RedisConnRef|bool Returns false on failure
-        * @throws MWException
-        */
-       protected function getConnection() {
-               $conn = false;
-               foreach ( $this->servers as $server ) {
-                       $conn = $this->redisPool->getConnection( $server, $this->logger );
-                       if ( $conn ) {
-                               break;
-                       }
-               }
-
-               return $conn;
-       }
-
-       /**
-        * @return string
-        */
-       private function getReadyQueueKey() {
-               return "jobqueue:aggregator:h-ready-queues:v2"; // global
-       }
-
-       /**
-        * @param string $name
-        * @return string[]
-        */
-       private function decodeQueueName( $name ) {
-               list( $type, $wiki ) = explode( '/', $name, 2 );
-
-               return [ rawurldecode( $type ), rawurldecode( $wiki ) ];
-       }
-}
index 8cc14e5..4de72a9 100644 (file)
@@ -19,6 +19,8 @@
  * @ingroup JobQueue
  */
 
+use MediaWiki\Linker\LinkTarget;
+
 /**
  * Job for updating user activity like "last viewed" timestamps
  *
@@ -32,7 +34,9 @@
  * @since 1.26
  */
 class ActivityUpdateJob extends Job {
-       function __construct( Title $title, array $params ) {
+       function __construct( LinkTarget $title, array $params ) {
+               $title = Title::newFromLinkTarget( $title );
+
                parent::__construct( 'activityUpdateJob', $title, $params );
 
                static $required = [ 'type', 'userid', 'notifTime', 'curTime' ];
@@ -55,9 +59,7 @@ class ActivityUpdateJob extends Job {
        }
 
        protected function updateWatchlistNotification() {
-               $casTimestamp = ( $this->params['notifTime'] !== null )
-                       ? $this->params['notifTime']
-                       : $this->params['curTime'];
+               $casTimestamp = $this->params['notifTime'] ?? $this->params['curTime'];
 
                $dbw = wfGetDB( DB_MASTER );
                $dbw->update( 'watchlist',
index 356eeba..d8cbf75 100644 (file)
  * @ingroup JobQueue
  * @since 1.27
  */
-class CdnPurgeJob extends Job {
-       /**
-        * @param Title $title
-        * @param array $params Job parameters (urls)
-        */
-       function __construct( Title $title, array $params ) {
-               parent::__construct( 'cdnPurge', $title, $params );
+class CdnPurgeJob extends Job implements GenericParameterJob {
+       function __construct( array $params ) {
+               parent::__construct( 'cdnPurge', $params );
                $this->removeDuplicates = false; // delay semantics are critical
        }
 
index 77adfa1..0cb1a52 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 
 use MediaWiki\MediaWikiServices;
+use MediaWiki\User\UserIdentity;
 
 /**
  * Job to clear a users watchlist in batches.
@@ -10,37 +11,28 @@ use MediaWiki\MediaWikiServices;
  * @ingroup JobQueue
  * @since 1.31
  */
-class ClearUserWatchlistJob extends Job {
-
-       /**
-        * @param User $user User to clear the watchlist for.
-        * @param int $maxWatchlistId The maximum wl_id at the time the job was first created.
-        *
-        * @return ClearUserWatchlistJob
-        */
-       public static function newForUser( User $user, $maxWatchlistId ) {
-               return new self(
-                       null,
-                       [ 'userId' => $user->getId(), 'maxWatchlistId' => $maxWatchlistId ]
-               );
-       }
-
+class ClearUserWatchlistJob extends Job implements GenericParameterJob {
        /**
-        * @param Title|null $title Not used by this job.
         * @param array $params
         *  - userId,         The ID for the user whose watchlist is being cleared.
         *  - maxWatchlistId, The maximum wl_id at the time the job was first created,
         */
-       public function __construct( Title $title = null, array $params ) {
-               parent::__construct(
-                       'clearUserWatchlist',
-                       SpecialPage::getTitleFor( 'EditWatchlist', 'clear' ),
-                       $params
-               );
+       public function __construct( array $params ) {
+               parent::__construct( 'clearUserWatchlist', $params );
 
                $this->removeDuplicates = true;
        }
 
+       /**
+        * @param UserIdentity $user User to clear the watchlist for.
+        * @param int $maxWatchlistId The maximum wl_id at the time the job was first created.
+        *
+        * @return ClearUserWatchlistJob
+        */
+       public static function newForUser( UserIdentity $user, $maxWatchlistId ) {
+               return new self( [ 'userId' => $user->getId(), 'maxWatchlistId' => $maxWatchlistId ] );
+       }
+
        public function run() {
                global $wgUpdateRowsPerQuery;
                $userId = $this->params['userId'];
@@ -101,7 +93,7 @@ class ClearUserWatchlistJob extends Job {
                if ( count( $watchlistIds ) === (int)$batchSize ) {
                        // Until we get less results than the limit, recursively push
                        // the same job again.
-                       JobQueueGroup::singleton()->push( new self( $this->getTitle(), $this->getParams() ) );
+                       JobQueueGroup::singleton()->push( new self( $this->getParams() ) );
                }
 
                return true;
index 94c1351..f53174a 100644 (file)
 use MediaWiki\MediaWikiServices;
 
 /**
- * Job for clearing all of the "last viewed" timestamps for a user's watchlist
+ * Job for clearing all of the "last viewed" timestamps for a user's watchlist, or setting them all
+ * to the same value.
  *
  * Job parameters include:
  *   - userId: affected user ID [required]
  *   - casTime: UNIX timestamp of the event that triggered this job [required]
+ *   - timestamp: value to set all of the "last viewed" timestamps to [optional, defaults to null]
  *
  * @ingroup JobQueue
  * @since 1.31
  */
-class ClearWatchlistNotificationsJob extends Job {
-       function __construct( Title $title, array $params ) {
-               parent::__construct( 'clearWatchlistNotifications', $title, $params );
+class ClearWatchlistNotificationsJob extends Job implements GenericParameterJob {
+       function __construct( array $params ) {
+               parent::__construct( 'clearWatchlistNotifications', $params );
 
                static $required = [ 'userId', 'casTime' ];
                $missing = implode( ', ', array_diff( $required, array_keys( $this->params ) ) );
                if ( $missing != '' ) {
-                       throw new InvalidArgumentException( "Missing paramter(s) $missing" );
+                       throw new InvalidArgumentException( "Missing parameter(s) $missing" );
                }
 
                $this->removeDuplicates = true;
@@ -51,29 +53,49 @@ class ClearWatchlistNotificationsJob extends Job {
 
                $dbw = $lbFactory->getMainLB()->getConnection( DB_MASTER );
                $ticket = $lbFactory->getEmptyTransactionTicket( __METHOD__ );
+               $timestamp = $this->params['timestamp'] ?? null;
+               if ( $timestamp === null ) {
+                       $timestampCond = 'wl_notificationtimestamp IS NOT NULL';
+               } else {
+                       $timestamp = $dbw->timestamp( $timestamp );
+                       $timestampCond = 'wl_notificationtimestamp != ' . $dbw->addQuotes( $timestamp ) .
+                               ' OR wl_notificationtimestamp IS NULL';
+               }
+               // New notifications since the reset should not be cleared
+               $casTimeCond = 'wl_notificationtimestamp < ' .
+                       $dbw->addQuotes( $dbw->timestamp( $this->params['casTime'] ) ) .
+                       ' OR wl_notificationtimestamp IS NULL';
 
-               $asOfTimes = array_unique( $dbw->selectFieldValues(
-                       'watchlist',
-                       'wl_notificationtimestamp',
-                       [ 'wl_user' => $this->params['userId'], 'wl_notificationtimestamp IS NOT NULL' ],
-                       __METHOD__,
-                       [ 'ORDER BY' => 'wl_notificationtimestamp DESC' ]
-               ) );
-
-               foreach ( array_chunk( $asOfTimes, $rowsPerQuery ) as $asOfTimeBatch ) {
-                       $dbw->update(
+               $firstBatch = true;
+               do {
+                       $idsToUpdate = $dbw->selectFieldValues(
                                'watchlist',
-                               [ 'wl_notificationtimestamp' => null ],
+                               'wl_id',
                                [
                                        'wl_user' => $this->params['userId'],
-                                       'wl_notificationtimestamp' => $asOfTimeBatch,
-                                       // New notifications since the reset should not be cleared
-                                       'wl_notificationtimestamp < ' .
-                                               $dbw->addQuotes( $dbw->timestamp( $this->params['casTime'] ) )
+                                       $timestampCond,
+                                       $casTimeCond,
                                ],
-                               __METHOD__
+                               __METHOD__,
+                               [ 'LIMIT' => $rowsPerQuery ]
                        );
-                       $lbFactory->commitAndWaitForReplication( __METHOD__, $ticket );
-               }
+                       if ( $idsToUpdate ) {
+                               $dbw->update(
+                                       'watchlist',
+                                       [ 'wl_notificationtimestamp' => $timestamp ],
+                                       [
+                                               'wl_id' => $idsToUpdate,
+                                               // For paranoia, enforce the CAS time condition here too
+                                               $casTimeCond
+                                       ],
+                                       __METHOD__
+                               );
+                               if ( !$firstBatch ) {
+                                       $lbFactory->commitAndWaitForReplication( __METHOD__, $ticket );
+                               }
+                               $firstBatch = false;
+                       }
+               } while ( $idsToUpdate );
+               return true;
        }
 }
index 9b5cef4..b0ce6a5 100644 (file)
@@ -3,16 +3,13 @@
 /**
  * Class DeletePageJob
  */
-class DeletePageJob extends Job {
-       public function __construct( $title, $params ) {
-               parent::__construct( 'deletePage', $title, $params );
+class DeletePageJob extends Job implements GenericParameterJob {
+       public function __construct( array $params ) {
+               parent::__construct( 'deletePage', $params );
+
+               $this->title = Title::makeTitle( $params['namespace'], $params['title'] );
        }
 
-       /**
-        * Execute the job
-        *
-        * @return bool
-        */
        public function run() {
                // Failure to load the page is not job failure.
                // A parallel deletion operation may have already completed the page deletion.
index 1bcbd30..2c2cf89 100644 (file)
@@ -29,10 +29,6 @@ use MediaWiki\MediaWikiServices;
  * @ingroup JobQueue
  */
 class DoubleRedirectJob extends Job {
-       /** @var string Reason for the change, 'maintenance' or 'move'. Suffix fo
-        *    message key 'double-redirect-fixed-'.
-        */
-       private $reason;
 
        /** @var Title The title which has changed, redirects pointing to this
         *    title are fixed
@@ -44,11 +40,15 @@ class DoubleRedirectJob extends Job {
 
        /**
         * @param Title $title
-        * @param array $params
+        * @param array $params Expected to contain these elements:
+        * - 'redirTitle' => string The title that changed and should be fixed.
+        * - 'reason' => string Reason for the change, can be "move" or "maintenance". Used as a suffix
+        *   for the message keys "double-redirect-fixed-move" and
+        *   "double-redirect-fixed-maintenance".
+        * ]
         */
        function __construct( Title $title, array $params ) {
                parent::__construct( 'fixDoubleRedirect', $title, $params );
-               $this->reason = $params['reason'];
                $this->redirTitle = Title::newFromText( $params['redirTitle'] );
        }
 
@@ -166,7 +166,7 @@ class DoubleRedirectJob extends Job {
                $article = WikiPage::factory( $this->title );
 
                // Messages: double-redirect-fixed-move, double-redirect-fixed-maintenance
-               $reason = wfMessage( 'double-redirect-fixed-' . $this->reason,
+               $reason = wfMessage( 'double-redirect-fixed-' . $this->params['reason'],
                        $this->redirTitle->getPrefixedText(), $newTitle->getPrefixedText()
                )->inContentLanguage()->text();
                $flags = EDIT_UPDATE | EDIT_SUPPRESS_RC | EDIT_INTERNAL;
index c005a29..4231e15 100644 (file)
  *
  * @ingroup JobQueue
  */
-final class DuplicateJob extends Job {
+final class DuplicateJob extends Job implements GenericParameterJob {
        /**
         * Callers should use DuplicateJob::newFromJob() instead
         *
-        * @param Title $title
         * @param array $params Job parameters
         */
-       function __construct( Title $title, array $params ) {
-               parent::__construct( 'duplicate', $title, $params );
+       function __construct( array $params ) {
+               parent::__construct( 'duplicate', $params );
        }
 
        /**
         * Get a duplicate no-op version of a job
         *
-        * @param Job $job
+        * @param RunnableJob $job
         * @return Job
         */
-       public static function newFromJob( Job $job ) {
-               $djob = new self( $job->getTitle(), $job->getParams() );
+       public static function newFromJob( RunnableJob $job ) {
+               $djob = new self( $job->getParams() );
                $djob->command = $job->getType();
                $djob->params = is_array( $djob->params ) ? $djob->params : [];
                $djob->params = [ 'isDuplicate' => true ] + $djob->params;
-               $djob->metadata = $job->metadata;
+               $djob->metadata = $job->getMetadata();
 
                return $djob;
        }
index ea7a8d7..f9735d5 100644 (file)
  * @ingroup JobQueue
  * @since 1.25
  */
-final class EnqueueJob extends Job {
+final class EnqueueJob extends Job implements GenericParameterJob {
        /**
         * Callers should use the factory methods instead
         *
-        * @param Title $title
         * @param array $params Job parameters
         */
-       function __construct( Title $title, array $params ) {
-               parent::__construct( 'enqueue', $title, $params );
+       public function __construct( array $params ) {
+               parent::__construct( 'enqueue', $params );
        }
 
        /**
@@ -50,22 +49,24 @@ final class EnqueueJob extends Job {
        public static function newFromLocalJobs( $jobs ) {
                $jobs = is_array( $jobs ) ? $jobs : [ $jobs ];
 
-               return self::newFromJobsByWiki( [ wfWikiID() => $jobs ] );
+               return self::newFromJobsByDomain( [
+                       WikiMap::getCurrentWikiDbDomain()->getId() => $jobs
+               ] );
        }
 
        /**
-        * @param array $jobsByWiki Map of (wiki => JobSpecification list)
+        * @param array $jobsByDomain Map of (wiki => JobSpecification list)
         * @return EnqueueJob
         */
-       public static function newFromJobsByWiki( array $jobsByWiki ) {
+       public static function newFromJobsByDomain( array $jobsByDomain ) {
                $deduplicate = true;
 
-               $jobMapsByWiki = [];
-               foreach ( $jobsByWiki as $wiki => $jobs ) {
-                       $jobMapsByWiki[$wiki] = [];
+               $jobMapsByDomain = [];
+               foreach ( $jobsByDomain as $domain => $jobs ) {
+                       $jobMapsByDomain[$domain] = [];
                        foreach ( $jobs as $job ) {
                                if ( $job instanceof JobSpecification ) {
-                                       $jobMapsByWiki[$wiki][] = $job->toSerializableArray();
+                                       $jobMapsByDomain[$domain][] = $job->toSerializableArray();
                                } else {
                                        throw new InvalidArgumentException( "Jobs must be of type JobSpecification." );
                                }
@@ -73,10 +74,7 @@ final class EnqueueJob extends Job {
                        }
                }
 
-               $eJob = new self(
-                       Title::makeTitle( NS_SPECIAL, 'Badtitle/' . __CLASS__ ),
-                       [ 'jobsByWiki' => $jobMapsByWiki ]
-               );
+               $eJob = new self( [ 'jobsByDomain' => $jobMapsByDomain ] );
                // If *all* jobs to be pushed are to be de-duplicated (a common case), then
                // de-duplicate this whole job itself to avoid build up in high traffic cases
                $eJob->removeDuplicates = $deduplicate;
@@ -84,13 +82,24 @@ final class EnqueueJob extends Job {
                return $eJob;
        }
 
+       /**
+        * @param array $jobsByWiki
+        * @return EnqueueJob
+        * @deprecated Since 1.33; use newFromJobsByDomain()
+        */
+       public static function newFromJobsByWiki( array $jobsByWiki ) {
+               return self::newFromJobsByDomain( $jobsByWiki );
+       }
+
        public function run() {
-               foreach ( $this->params['jobsByWiki'] as $wiki => $jobMaps ) {
+               $jobsByDomain = $this->params['jobsByDomain'] ?? $this->params['jobsByWiki']; // b/c
+
+               foreach ( $jobsByDomain as $domain => $jobMaps ) {
                        $jobSpecs = [];
                        foreach ( $jobMaps as $jobMap ) {
                                $jobSpecs[] = JobSpecification::newFromArray( $jobMap );
                        }
-                       JobQueueGroup::singleton( $wiki )->push( $jobSpecs );
+                       JobQueueGroup::singleton( $domain )->push( $jobSpecs );
                }
 
                return true;
index 80826fe..01afe6f 100644 (file)
@@ -31,7 +31,7 @@
  * @code
  * $ php maintenance/eval.php
  * > $queue = JobQueueGroup::singleton();
- * > $job = new NullJob( Title::newMainPage(), [ 'lives' => 10 ] );
+ * > $job = new NullJob( [ 'lives' => 10 ] );
  * > $queue->push( $job );
  * @endcode
  * You can then confirm the job has been enqueued by using the showJobs.php
  *
  * @ingroup JobQueue
  */
-class NullJob extends Job {
+class NullJob extends Job implements GenericParameterJob {
        /**
-        * @param Title $title
         * @param array $params Job parameters (lives, usleep)
         */
-       function __construct( Title $title, array $params ) {
-               parent::__construct( 'null', $title, $params );
+       function __construct( array $params ) {
+               parent::__construct( 'null', $params );
                if ( !isset( $this->params['lives'] ) ) {
                        $this->params['lives'] = 1;
                }
@@ -67,7 +66,7 @@ class NullJob extends Job {
                if ( $this->params['lives'] > 1 ) {
                        $params = $this->params;
                        $params['lives']--;
-                       $job = new self( $this->title, $params );
+                       $job = new self( $params );
                        JobQueueGroup::singleton()->push( $job );
                }
 
index 7f9b2a3..b1c805b 100644 (file)
@@ -54,6 +54,8 @@ class RefreshLinksJob extends Job {
                        !( isset( $params['pages'] ) && count( $params['pages'] ) != 1 )
                );
                $this->params += [ 'causeAction' => 'unknown', 'causeAgent' => 'unknown' ];
+               // This will control transaction rounds in order to run DataUpdates
+               $this->executionFlags |= self::JOB_NO_EXPLICIT_TRX_ROUND;
        }
 
        /**
@@ -145,6 +147,8 @@ class RefreshLinksJob extends Job {
                $renderer = $services->getRevisionRenderer();
                $ticket = $lbFactory->getEmptyTransactionTicket( __METHOD__ );
 
+               $lbFactory->beginMasterChanges( __METHOD__ );
+
                $page = WikiPage::factory( $title );
                $page->loadPageData( WikiPage::READ_LATEST );
 
@@ -153,6 +157,7 @@ class RefreshLinksJob extends Job {
                /** @noinspection PhpUnusedLocalVariableInspection */
                $scopedLock = LinksUpdate::acquirePageLock( $dbw, $page->getId(), 'job' );
                if ( $scopedLock === null ) {
+                       $lbFactory->commitMasterChanges( __METHOD__ );
                        // Another job is already updating the page, likely for an older revision (T170596).
                        $this->setLastError( 'LinksUpdate already running for this page, try again later.' );
                        return false;
@@ -175,10 +180,12 @@ class RefreshLinksJob extends Job {
                }
 
                if ( !$revision ) {
+                       $lbFactory->commitMasterChanges( __METHOD__ );
                        $stats->increment( 'refreshlinks.rev_not_found' );
                        $this->setLastError( "Revision not found for {$title->getPrefixedDBkey()}" );
                        return false; // just deleted?
                } elseif ( $revision->getId() != $latest || $revision->getPageId() !== $page->getId() ) {
+                       $lbFactory->commitMasterChanges( __METHOD__ );
                        // Do not clobber over newer updates with older ones. If all jobs where FIFO and
                        // serialized, it would be OK to update links based on older revisions since it
                        // would eventually get to the latest. Since that is not the case (by design),
@@ -208,6 +215,7 @@ class RefreshLinksJob extends Job {
                        }
 
                        if ( $page->getLinksTimestamp() > $skewedTimestamp ) {
+                               $lbFactory->commitMasterChanges( __METHOD__ );
                                // Something already updated the backlinks since this job was made
                                $stats->increment( 'refreshlinks.update_skipped' );
                                return true;
@@ -284,6 +292,9 @@ class RefreshLinksJob extends Job {
                                $options['triggeringUser'] = User::newFromName( $userInfo['userName'], false );
                        }
                }
+
+               $lbFactory->commitMasterChanges( __METHOD__ );
+
                $page->doSecondaryDataUpdates( $options );
 
                InfoAction::invalidateCache( $title );
index 63575eb..eb8b1a2 100644 (file)
@@ -93,7 +93,7 @@ class ThumbnailRenderJob extends Job {
                if ( $wgUploadThumbnailRenderHttpCustomDomain ) {
                        $parsedUrl = wfParseUrl( $thumbUrl );
 
-                       if ( !$parsedUrl || !isset( $parsedUrl['path'] ) || !strlen( $parsedUrl['path'] ) ) {
+                       if ( !isset( $parsedUrl['path'] ) || $parsedUrl['path'] === '' ) {
                                $this->setLastError( __METHOD__ . ": invalid thumb URL: $thumbUrl" );
                                return false;
                        }
index 0945e58..ac8f94a 100644 (file)
@@ -21,9 +21,9 @@
  * @ingroup JobQueue
  */
 
-class UserGroupExpiryJob extends Job {
-       public function __construct( $params = false ) {
-               parent::__construct( 'userGroupExpiry', Title::newMainPage(), $params );
+class UserGroupExpiryJob extends Job implements GenericParameterJob {
+       public function __construct( array $params = [] ) {
+               parent::__construct( 'userGroupExpiry', $params );
                $this->removeDuplicates = true;
        }
 
diff --git a/includes/jobqueue/jobs/UserOptionsUpdateJob.php b/includes/jobqueue/jobs/UserOptionsUpdateJob.php
new file mode 100644 (file)
index 0000000..0e8b19f
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+/**
+ * Job that updates a user's preferences.
+ *
+ * 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 3 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 JobQueue
+ */
+
+/**
+ * Job that updates a user's preferences
+ *
+ * The following job parameters are required:
+ *   - userId: the user ID
+ *   - options: a map of (option => value)
+ *
+ * @since 1.33
+ */
+class UserOptionsUpdateJob extends Job implements GenericParameterJob {
+       public function __construct( array $params ) {
+               parent::__construct( 'userOptionsUpdate', $params );
+               $this->removeDuplicates = true;
+       }
+
+       public function run() {
+               if ( !$this->params['options'] ) {
+                       return true; // nothing to do
+               }
+
+               $user = User::newFromId( $this->params['userId'] );
+               $user->load( $user::READ_EXCLUSIVE );
+               if ( !$user->getId() ) {
+                       return true;
+               }
+
+               foreach ( $this->params['options'] as $name => $value ) {
+                       $user->setOption( $name, $value );
+               }
+
+               $user->saveSettings();
+
+               return true;
+       }
+}
index e238887..ccc76bb 100644 (file)
@@ -151,13 +151,11 @@ class ArrayUtils {
         * @since 1.23
         *
         * @param array $array1 The array to compare from
-        * @param array $array2,... More arrays to compare against
+        * @param array ...$arrays More arrays to compare against
         * @return array An array containing all the values from array1
         *               that are not present in any of the other arrays.
         */
-       public static function arrayDiffAssocRecursive( $array1 ) {
-               $arrays = func_get_args();
-               array_shift( $arrays );
+       public static function arrayDiffAssocRecursive( $array1, ...$arrays ) {
                $ret = [];
 
                foreach ( $array1 as $key => $value ) {
index 3129c5b..7a90082 100644 (file)
@@ -407,14 +407,14 @@ class CSSMin {
                        // FIXME: Simplify now we only support PHP 7.0.0+
                        // Note: PCRE doesn't support multiple capture groups with the same name by default.
                        // - PCRE 6.7 introduced the "J" modifier (PCRE_INFO_JCHANGED for PCRE_DUPNAMES).
-                       //   https://secure.php.net/manual/en/reference.pcre.pattern.modifiers.php
+                       //   https://www.php.net/manual/en/reference.pcre.pattern.modifiers.php
                        //   However this isn't useful since it just ignores all but the first one.
                        //   Also, while the modifier was introduced in PCRE 6.7 (PHP 5.2+) it was
                        //   not exposed to public preg_* functions until PHP 5.6.0.
                        // - PCRE 8.36 fixed this to work as expected (e.g. merge conceptually to
                        //   only return the one matched in the part that actually matched).
                        //   However MediaWiki supports 5.5.9, which has PCRE 8.32
-                       //   Per https://secure.php.net/manual/en/pcre.installation.php:
+                       //   Per https://www.php.net/manual/en/pcre.installation.php:
                        //   - PCRE 8.32 (PHP 5.5.0)
                        //   - PCRE 8.34 (PHP 5.5.10, PHP 5.6.0)
                        //   - PCRE 8.37 (PHP 5.5.26, PHP 5.6.9, PHP 7.0.0)
diff --git a/includes/libs/CryptRand.php b/includes/libs/CryptRand.php
deleted file mode 100644 (file)
index da0cae2..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-<?php
-/**
- * A cryptographic random generator class used for generating secret keys
- *
- * This is based in part on Drupal code as well as what we used in our own code
- * prior to introduction of this class.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @author Daniel Friesen
- * @file
- */
-
-/**
- * @deprecated since 1.32, use random_bytes()/random_int()
- */
-class CryptRand {
-       /**
-        * @deprecated since 1.32, unused
-        */
-       const MIN_ITERATIONS = 1000;
-
-       /**
-        * @deprecated since 1.32, unused
-        */
-       const MSEC_PER_BYTE = 0.5;
-
-       /**
-        * Initialize an initial random state based off of whatever we can find
-        *
-        * @deprecated since 1.32, unused and does nothing
-        *
-        * @return string
-        */
-       protected function initialRandomState() {
-               wfDeprecated( __METHOD__, '1.32' );
-               return '';
-       }
-
-       /**
-        * Randomly hash data while mixing in clock drift data for randomness
-        *
-        * @deprecated since 1.32, unused and does nothing
-        *
-        * @param string $data The data to randomly hash.
-        * @return string The hashed bytes
-        * @author Tim Starling
-        */
-       protected function driftHash( $data ) {
-               wfDeprecated( __METHOD__, '1.32' );
-               return '';
-       }
-
-       /**
-        * Return a rolling random state initially build using data from unstable sources
-        *
-        * @deprecated since 1.32, unused and does nothing
-        *
-        * @return string A new weak random state
-        */
-       protected function randomState() {
-               wfDeprecated( __METHOD__, '1.32' );
-               return '';
-       }
-
-       /**
-        * Return a boolean indicating whether or not the source used for cryptographic
-        * random bytes generation in the previously run generate* call
-        * was cryptographically strong.
-        *
-        * @deprecated since 1.32, always returns true
-        *
-        * @return bool Always true
-        */
-       public function wasStrong() {
-               wfDeprecated( __METHOD__, '1.32' );
-               return true;
-       }
-
-       /**
-        * Generate a run of cryptographically random data and return
-        * it in raw binary form.
-        * You can use CryptRand::wasStrong() if you wish to know if the source used
-        * was cryptographically strong.
-        *
-        * @param int $bytes The number of bytes of random data to generate
-        * @return string Raw binary random data
-        */
-       public function generate( $bytes ) {
-               wfDeprecated( __METHOD__, '1.32' );
-               $bytes = floor( $bytes );
-               return random_bytes( $bytes );
-       }
-
-       /**
-        * Generate a run of cryptographically random data and return
-        * it in hexadecimal string format.
-        *
-        * @param int $chars The number of hex chars of random data to generate
-        * @return string Hexadecimal random data
-        */
-       public function generateHex( $chars ) {
-               wfDeprecated( __METHOD__, '1.32' );
-               return MWCryptRand::generateHex( $chars );
-       }
-}
index 9470413..7de60b1 100644 (file)
@@ -36,12 +36,11 @@ class DeferredStringifier {
 
        /**
         * @param callable $callback Callback that gets called by __toString
-        * @param mixed $param,... Parameters to the callback
+        * @param mixed ...$params Parameters to the callback
         */
-       public function __construct( $callback /*...*/ ) {
-               $this->params = func_get_args();
-               array_shift( $this->params );
+       public function __construct( $callback, ...$params ) {
                $this->callback = $callback;
+               $this->params = $params;
        }
 
        /**
index 8efcd15..e9f0258 100644 (file)
@@ -115,19 +115,6 @@ class IP {
                        || preg_match( '/^' . RE_IPV6_ADD . '$/', $ip ) );
        }
 
-       /**
-        * Validate an IP range (valid address with a valid CIDR prefix).
-        * SIIT IPv4-translated addresses are rejected.
-        * @note canonicalize() tries to convert translated addresses to IPv4.
-        *
-        * @deprecated since 1.30. Use the equivalent IP::isValidRange().
-        * @param string $ipRange
-        * @return bool True if it is valid
-        */
-       public static function isValidBlock( $ipRange ) {
-               return self::isValidRange( $ipRange );
-       }
-
        /**
         * Validate an IP range (valid address with a valid CIDR prefix).
         * SIIT IPv4-translated addresses are rejected.
@@ -467,7 +454,7 @@ class IP {
         * to an integer network and a number of bits
         *
         * @param string $range IP with CIDR prefix
-        * @return array(int or string, int)
+        * @return array [int or string, int]
         */
        public static function parseCIDR( $range ) {
                if ( self::isIPv6( $range ) ) {
@@ -557,7 +544,7 @@ class IP {
         *
         * @param string $range
         *
-        * @return array(string, int)
+        * @return array [string, int]
         */
        private static function parseCIDR6( $range ) {
                # Explode into <expanded IP,range>
@@ -598,7 +585,7 @@ class IP {
         *
         * @param string $range
         *
-        * @return array(string, string)
+        * @return array [string, string]
         */
        private static function parseRange6( $range ) {
                # Expand any IPv6 IP
index be7e93d..84b7b3e 100644 (file)
@@ -31,6 +31,7 @@
  *
  * @since 1.23
  * @file
+ * @deprecated since 1.34, no longer used
  */
 class MWMessagePack {
        /** @var bool|null Whether current system is bigendian. **/
@@ -43,11 +44,14 @@ class MWMessagePack {
         * (both indexed and associative) types. Object serialization is not
         * supported.
         *
+        * @deprecated since 1.34, no longer used
+        *
         * @param mixed $value
         * @return string
         * @throws InvalidArgumentException if $value is an unsupported type or too long a string
         */
        public static function pack( $value ) {
+               wfDeprecated( __METHOD__, '1.34' );
                if ( self::$bigendian === null ) {
                        self::$bigendian = pack( 'S', 1 ) === pack( 'n', 1 );
                }
index e9d1fc1..5e7485c 100644 (file)
@@ -135,11 +135,11 @@ class MemoizedCallable {
         *
         * Like MemoizedCallable::invokeArgs(), but variadic.
         *
-        * @param mixed $params,... Parameters for memoized function or method.
+        * @param mixed ...$params Parameters for memoized function or method.
         * @return mixed The memoized callable's return value.
         */
-       public function invoke() {
-               return $this->invokeArgs( func_get_args() );
+       public function invoke( ...$params ) {
+               return $this->invokeArgs( $params );
        }
 
        /**
index 536177e..a6135ae 100644 (file)
@@ -237,11 +237,9 @@ class MultiHttpClient implements LoggerAwareInterface {
                                        }
                                } while ( $mrc == CURLM_CALL_MULTI_PERFORM );
                                // Wait (if possible) for available work...
-                               if ( $active > 0 && $mrc == CURLM_OK ) {
-                                       if ( curl_multi_select( $chm, $selectTimeout ) == -1 ) {
-                                               // PHP bug 63411; https://curl.haxx.se/libcurl/c/curl_multi_fdset.html
-                                               usleep( 5000 ); // 5ms
-                                       }
+                               if ( $active > 0 && $mrc == CURLM_OK && curl_multi_select( $chm, $selectTimeout ) == -1 ) {
+                                       // PHP bug 63411; https://curl.haxx.se/libcurl/c/curl_multi_fdset.html
+                                       usleep( 5000 ); // 5ms
                                }
                        } while ( $active > 0 && $mrc == CURLM_OK );
                }
index f3c1f01..593e617 100644 (file)
@@ -1,4 +1,24 @@
 <?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup FileBackend
+ */
+
 /**
  * File system based backend.
  *
@@ -101,7 +121,7 @@ class FSFileBackend extends FileBackendStore {
        public function getFeatures() {
                if ( $this->isWindows && version_compare( PHP_VERSION, '7.1', 'lt' ) ) {
                        // PHP before 7.1 used 8-bit code page for filesystem paths on Windows;
-                       // See https://secure.php.net/manual/en/migration71.windows-support.php
+                       // See https://www.php.net/manual/en/migration71.windows-support.php
                        return 0;
                } else {
                        return FileBackend::ATTR_UNICODE_PATHS;
@@ -802,189 +822,3 @@ class FSFileBackend extends FileBackendStore {
                return true; // suppress from PHP handler
        }
 }
-
-/**
- * @see FileBackendStoreOpHandle
- */
-class FSFileOpHandle extends FileBackendStoreOpHandle {
-       public $cmd; // string; shell command
-       public $chmodPath; // string; file to chmod
-
-       /**
-        * @param FSFileBackend $backend
-        * @param array $params
-        * @param callable $call
-        * @param string $cmd
-        * @param int|null $chmodPath
-        */
-       public function __construct(
-               FSFileBackend $backend, array $params, $call, $cmd, $chmodPath = null
-       ) {
-               $this->backend = $backend;
-               $this->params = $params;
-               $this->call = $call;
-               $this->cmd = $cmd;
-               $this->chmodPath = $chmodPath;
-       }
-}
-
-/**
- * Wrapper around RecursiveDirectoryIterator/DirectoryIterator that
- * catches exception or does any custom behavoir that we may want.
- * Do not use this class from places outside FSFileBackend.
- *
- * @ingroup FileBackend
- */
-abstract class FSFileBackendList implements Iterator {
-       /** @var Iterator */
-       protected $iter;
-
-       /** @var int */
-       protected $suffixStart;
-
-       /** @var int */
-       protected $pos = 0;
-
-       /** @var array */
-       protected $params = [];
-
-       /**
-        * @param string $dir File system directory
-        * @param array $params
-        */
-       public function __construct( $dir, array $params ) {
-               $path = realpath( $dir ); // normalize
-               if ( $path === false ) {
-                       $path = $dir;
-               }
-               $this->suffixStart = strlen( $path ) + 1; // size of "path/to/dir/"
-               $this->params = $params;
-
-               try {
-                       $this->iter = $this->initIterator( $path );
-               } catch ( UnexpectedValueException $e ) {
-                       $this->iter = null; // bad permissions? deleted?
-               }
-       }
-
-       /**
-        * Return an appropriate iterator object to wrap
-        *
-        * @param string $dir File system directory
-        * @return Iterator
-        */
-       protected function initIterator( $dir ) {
-               if ( !empty( $this->params['topOnly'] ) ) { // non-recursive
-                       # Get an iterator that will get direct sub-nodes
-                       return new DirectoryIterator( $dir );
-               } else { // recursive
-                       # Get an iterator that will return leaf nodes (non-directories)
-                       # RecursiveDirectoryIterator extends FilesystemIterator.
-                       # FilesystemIterator::SKIP_DOTS default is inconsistent in PHP 5.3.x.
-                       $flags = FilesystemIterator::CURRENT_AS_SELF | FilesystemIterator::SKIP_DOTS;
-
-                       return new RecursiveIteratorIterator(
-                               new RecursiveDirectoryIterator( $dir, $flags ),
-                               RecursiveIteratorIterator::CHILD_FIRST // include dirs
-                       );
-               }
-       }
-
-       /**
-        * @see Iterator::key()
-        * @return int
-        */
-       public function key() {
-               return $this->pos;
-       }
-
-       /**
-        * @see Iterator::current()
-        * @return string|bool String or false
-        */
-       public function current() {
-               return $this->getRelPath( $this->iter->current()->getPathname() );
-       }
-
-       /**
-        * @see Iterator::next()
-        * @throws FileBackendError
-        */
-       public function next() {
-               try {
-                       $this->iter->next();
-                       $this->filterViaNext();
-               } catch ( UnexpectedValueException $e ) { // bad permissions? deleted?
-                       throw new FileBackendError( "File iterator gave UnexpectedValueException." );
-               }
-               ++$this->pos;
-       }
-
-       /**
-        * @see Iterator::rewind()
-        * @throws FileBackendError
-        */
-       public function rewind() {
-               $this->pos = 0;
-               try {
-                       $this->iter->rewind();
-                       $this->filterViaNext();
-               } catch ( UnexpectedValueException $e ) { // bad permissions? deleted?
-                       throw new FileBackendError( "File iterator gave UnexpectedValueException." );
-               }
-       }
-
-       /**
-        * @see Iterator::valid()
-        * @return bool
-        */
-       public function valid() {
-               return $this->iter && $this->iter->valid();
-       }
-
-       /**
-        * Filter out items by advancing to the next ones
-        */
-       protected function filterViaNext() {
-       }
-
-       /**
-        * Return only the relative path and normalize slashes to FileBackend-style.
-        * Uses the "real path" since the suffix is based upon that.
-        *
-        * @param string $dir
-        * @return string
-        */
-       protected function getRelPath( $dir ) {
-               $path = realpath( $dir );
-               if ( $path === false ) {
-                       $path = $dir;
-               }
-
-               return strtr( substr( $path, $this->suffixStart ), '\\', '/' );
-       }
-}
-
-class FSFileBackendDirList extends FSFileBackendList {
-       protected function filterViaNext() {
-               while ( $this->iter->valid() ) {
-                       if ( $this->iter->current()->isDot() || !$this->iter->current()->isDir() ) {
-                               $this->iter->next(); // skip non-directories and dot files
-                       } else {
-                               break;
-                       }
-               }
-       }
-}
-
-class FSFileBackendFileList extends FSFileBackendList {
-       protected function filterViaNext() {
-               while ( $this->iter->valid() ) {
-                       if ( !$this->iter->current()->isFile() ) {
-                               $this->iter->next(); // skip non-files and dot files
-                       } else {
-                               break;
-                       }
-               }
-       }
-}
index 19373ea..53a0ca0 100644 (file)
@@ -162,9 +162,8 @@ abstract class FileBackend implements LoggerAwareInterface {
         */
        public function __construct( array $config ) {
                $this->name = $config['name'];
-               $this->domainId = isset( $config['domainId'] )
-                       ? $config['domainId'] // e.g. "my_wiki-en_"
-                       : $config['wikiId']; // b/c alias
+               $this->domainId = $config['domainId'] // e.g. "my_wiki-en_"
+                       ?? $config['wikiId']; // b/c alias
                if ( !preg_match( '!^[a-zA-Z0-9-_]{1,255}$!', $this->name ) ) {
                        throw new InvalidArgumentException( "Backend name '{$this->name}' is invalid." );
                } elseif ( !is_string( $this->domainId ) ) {
@@ -1576,11 +1575,10 @@ abstract class FileBackend implements LoggerAwareInterface {
         *   - StatusValue::newGood() if this method is called without parameters
         *   - StatusValue::newFatal() with all parameters to this method if passed in
         *
-        * @param string $args,...
+        * @param string ...$args
         * @return StatusValue
         */
-       final protected function newStatus() {
-               $args = func_get_args();
+       final protected function newStatus( ...$args ) {
                if ( count( $args ) ) {
                        $sv = StatusValue::newFatal( ...$args );
                } else {
diff --git a/includes/libs/filebackend/FileBackendError.php b/includes/libs/filebackend/FileBackendError.php
deleted file mode 100644 (file)
index e233535..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<?php
-/**
- * File backend exception for checked exceptions (e.g. I/O errors)
- *
- * @ingroup FileBackend
- * @since 1.22
- */
-class FileBackendError extends Exception {
-}
index 655a710..f92d5fa 100644 (file)
@@ -87,9 +87,6 @@ class FileBackendMultiWrite extends FileBackend {
         *                      This will apply such updates post-send for web requests. Note that
         *                      any checks from "syncChecks" are still synchronous.
         *
-        * Bogus warning
-        * @suppress PhanAccessMethodProtected
-        *
         * @param array $config
         * @throws FileBackendError
         */
@@ -260,11 +257,11 @@ class FileBackendMultiWrite extends FileBackend {
                                                $status->fatal( 'backend-fail-synced', $path );
                                                continue;
                                        }
-                                       if ( $this->syncChecks & self::CHECK_SIZE ) {
-                                               if ( $cStat['size'] != $mStat['size'] ) { // wrong size
-                                                       $status->fatal( 'backend-fail-synced', $path );
-                                                       continue;
-                                               }
+                                       if ( ( $this->syncChecks & self::CHECK_SIZE )
+                                               && $cStat['size'] != $mStat['size']
+                                       ) { // wrong size
+                                               $status->fatal( 'backend-fail-synced', $path );
+                                               continue;
                                        }
                                        if ( $this->syncChecks & self::CHECK_TIME ) {
                                                $mTs = wfTimestamp( TS_UNIX, $mStat['mtime'] );
@@ -274,16 +271,12 @@ class FileBackendMultiWrite extends FileBackend {
                                                        continue;
                                                }
                                        }
-                                       if ( $this->syncChecks & self::CHECK_SHA1 ) {
-                                               if ( $cBackend->getFileSha1Base36( $cParams ) !== $mSha1 ) { // wrong SHA1
-                                                       $status->fatal( 'backend-fail-synced', $path );
-                                                       continue;
-                                               }
-                                       }
-                               } else { // file is not in master
-                                       if ( $cStat ) { // file should not exist
+                                       if ( ( $this->syncChecks & self::CHECK_SHA1 ) && $cBackend->getFileSha1Base36( $cParams ) !== $mSha1 ) { // wrong SHA1
                                                $status->fatal( 'backend-fail-synced', $path );
+                                               continue;
                                        }
+                               } elseif ( $cStat ) { // file is not in master; file should not exist
+                                       $status->fatal( 'backend-fail-synced', $path );
                                }
                        }
                }
index 97da557..3663637 100644 (file)
@@ -1866,133 +1866,3 @@ abstract class FileBackendStore extends FileBackend {
                return $mime ?: 'unknown/unknown';
        }
 }
-
-/**
- * FileBackendStore helper class for performing asynchronous file operations.
- *
- * For example, calling FileBackendStore::createInternal() with the "async"
- * param flag may result in a StatusValue that contains this object as a value.
- * This class is largely backend-specific and is mostly just "magic" to be
- * passed to FileBackendStore::executeOpHandlesInternal().
- */
-abstract class FileBackendStoreOpHandle {
-       /** @var array */
-       public $params = []; // params to caller functions
-       /** @var FileBackendStore */
-       public $backend;
-       /** @var array */
-       public $resourcesToClose = [];
-
-       public $call; // string; name that identifies the function called
-
-       /**
-        * Close all open file handles
-        */
-       public function closeResources() {
-               array_map( 'fclose', $this->resourcesToClose );
-       }
-}
-
-/**
- * FileBackendStore helper function to handle listings that span container shards.
- * Do not use this class from places outside of FileBackendStore.
- *
- * @ingroup FileBackend
- */
-abstract class FileBackendStoreShardListIterator extends FilterIterator {
-       /** @var FileBackendStore */
-       protected $backend;
-
-       /** @var array */
-       protected $params;
-
-       /** @var string Full container name */
-       protected $container;
-
-       /** @var string Resolved relative path */
-       protected $directory;
-
-       /** @var array */
-       protected $multiShardPaths = []; // (rel path => 1)
-
-       /**
-        * @param FileBackendStore $backend
-        * @param string $container Full storage container name
-        * @param string $dir Storage directory relative to container
-        * @param array $suffixes List of container shard suffixes
-        * @param array $params
-        */
-       public function __construct(
-               FileBackendStore $backend, $container, $dir, array $suffixes, array $params
-       ) {
-               $this->backend = $backend;
-               $this->container = $container;
-               $this->directory = $dir;
-               $this->params = $params;
-
-               $iter = new AppendIterator();
-               foreach ( $suffixes as $suffix ) {
-                       $iter->append( $this->listFromShard( $this->container . $suffix ) );
-               }
-
-               parent::__construct( $iter );
-       }
-
-       public function accept() {
-               $rel = $this->getInnerIterator()->current(); // path relative to given directory
-               $path = $this->params['dir'] . "/{$rel}"; // full storage path
-               if ( $this->backend->isSingleShardPathInternal( $path ) ) {
-                       return true; // path is only on one shard; no issue with duplicates
-               } elseif ( isset( $this->multiShardPaths[$rel] ) ) {
-                       // Don't keep listing paths that are on multiple shards
-                       return false;
-               } else {
-                       $this->multiShardPaths[$rel] = 1;
-
-                       return true;
-               }
-       }
-
-       public function rewind() {
-               parent::rewind();
-               $this->multiShardPaths = [];
-       }
-
-       /**
-        * Get the list for a given container shard
-        *
-        * @param string $container Resolved container name
-        * @return Iterator
-        */
-       abstract protected function listFromShard( $container );
-}
-
-/**
- * Iterator for listing directories
- */
-class FileBackendStoreShardDirIterator extends FileBackendStoreShardListIterator {
-       protected function listFromShard( $container ) {
-               $list = $this->backend->getDirectoryListInternal(
-                       $container, $this->directory, $this->params );
-               if ( $list === null ) {
-                       return new ArrayIterator( [] );
-               } else {
-                       return is_array( $list ) ? new ArrayIterator( $list ) : $list;
-               }
-       }
-}
-
-/**
- * Iterator for listing regular files
- */
-class FileBackendStoreShardFileIterator extends FileBackendStoreShardListIterator {
-       protected function listFromShard( $container ) {
-               $list = $this->backend->getFileListInternal(
-                       $container, $this->directory, $this->params );
-               if ( $list === null ) {
-                       return new ArrayIterator( [] );
-               } else {
-                       return is_array( $list ) ? new ArrayIterator( $list ) : $list;
-               }
-       }
-}
index 61b4d69..2587812 100644 (file)
@@ -1707,9 +1707,7 @@ class SwiftFileBackend extends FileBackendStore {
                                if ( $rcode >= 200 && $rcode <= 299 ) { // OK
                                        $this->authCreds = [
                                                'auth_token' => $rhdrs['x-auth-token'],
-                                               'storage_url' => ( $this->swiftStorageUrl !== null )
-                                                       ? $this->swiftStorageUrl
-                                                       : $rhdrs['x-storage-url']
+                                               'storage_url' => $this->swiftStorageUrl ?? $rhdrs['x-storage-url']
                                        ];
 
                                        $this->srvCache->set( $cacheKey, $this->authCreds, ceil( $this->authTTL / 2 ) );
@@ -1803,180 +1801,3 @@ class SwiftFileBackend extends FileBackendStore {
                $this->logger->error( $msg, $msgParams );
        }
 }
-
-/**
- * @see FileBackendStoreOpHandle
- */
-class SwiftFileOpHandle extends FileBackendStoreOpHandle {
-       /** @var array List of Requests for MultiHttpClient */
-       public $httpOp;
-       /** @var Closure */
-       public $callback;
-
-       /**
-        * @param SwiftFileBackend $backend
-        * @param Closure $callback Function that takes (HTTP request array, status)
-        * @param array $httpOp MultiHttpClient op
-        */
-       public function __construct( SwiftFileBackend $backend, Closure $callback, array $httpOp ) {
-               $this->backend = $backend;
-               $this->callback = $callback;
-               $this->httpOp = $httpOp;
-       }
-}
-
-/**
- * SwiftFileBackend helper class to page through listings.
- * Swift also has a listing limit of 10,000 objects for sanity.
- * Do not use this class from places outside SwiftFileBackend.
- *
- * @ingroup FileBackend
- */
-abstract class SwiftFileBackendList implements Iterator {
-       /** @var array List of path or (path,stat array) entries */
-       protected $bufferIter = [];
-
-       /** @var string List items *after* this path */
-       protected $bufferAfter = null;
-
-       /** @var int */
-       protected $pos = 0;
-
-       /** @var array */
-       protected $params = [];
-
-       /** @var SwiftFileBackend */
-       protected $backend;
-
-       /** @var string Container name */
-       protected $container;
-
-       /** @var string Storage directory */
-       protected $dir;
-
-       /** @var int */
-       protected $suffixStart;
-
-       const PAGE_SIZE = 9000; // file listing buffer size
-
-       /**
-        * @param SwiftFileBackend $backend
-        * @param string $fullCont Resolved container name
-        * @param string $dir Resolved directory relative to container
-        * @param array $params
-        */
-       public function __construct( SwiftFileBackend $backend, $fullCont, $dir, array $params ) {
-               $this->backend = $backend;
-               $this->container = $fullCont;
-               $this->dir = $dir;
-               if ( substr( $this->dir, -1 ) === '/' ) {
-                       $this->dir = substr( $this->dir, 0, -1 ); // remove trailing slash
-               }
-               if ( $this->dir == '' ) { // whole container
-                       $this->suffixStart = 0;
-               } else { // dir within container
-                       $this->suffixStart = strlen( $this->dir ) + 1; // size of "path/to/dir/"
-               }
-               $this->params = $params;
-       }
-
-       /**
-        * @see Iterator::key()
-        * @return int
-        */
-       public function key() {
-               return $this->pos;
-       }
-
-       /**
-        * @see Iterator::next()
-        */
-       public function next() {
-               // Advance to the next file in the page
-               next( $this->bufferIter );
-               ++$this->pos;
-               // Check if there are no files left in this page and
-               // advance to the next page if this page was not empty.
-               if ( !$this->valid() && count( $this->bufferIter ) ) {
-                       $this->bufferIter = $this->pageFromList(
-                               $this->container, $this->dir, $this->bufferAfter, self::PAGE_SIZE, $this->params
-                       ); // updates $this->bufferAfter
-               }
-       }
-
-       /**
-        * @see Iterator::rewind()
-        */
-       public function rewind() {
-               $this->pos = 0;
-               $this->bufferAfter = null;
-               $this->bufferIter = $this->pageFromList(
-                       $this->container, $this->dir, $this->bufferAfter, self::PAGE_SIZE, $this->params
-               ); // updates $this->bufferAfter
-       }
-
-       /**
-        * @see Iterator::valid()
-        * @return bool
-        */
-       public function valid() {
-               if ( $this->bufferIter === null ) {
-                       return false; // some failure?
-               } else {
-                       return ( current( $this->bufferIter ) !== false ); // no paths can have this value
-               }
-       }
-
-       /**
-        * Get the given list portion (page)
-        *
-        * @param string $container Resolved container name
-        * @param string $dir Resolved path relative to container
-        * @param string &$after
-        * @param int $limit
-        * @param array $params
-        * @return Traversable|array
-        */
-       abstract protected function pageFromList( $container, $dir, &$after, $limit, array $params );
-}
-
-/**
- * Iterator for listing directories
- */
-class SwiftFileBackendDirList extends SwiftFileBackendList {
-       /**
-        * @see Iterator::current()
-        * @return string|bool String (relative path) or false
-        */
-       public function current() {
-               return substr( current( $this->bufferIter ), $this->suffixStart, -1 );
-       }
-
-       protected function pageFromList( $container, $dir, &$after, $limit, array $params ) {
-               return $this->backend->getDirListPageInternal( $container, $dir, $after, $limit, $params );
-       }
-}
-
-/**
- * Iterator for listing regular files
- */
-class SwiftFileBackendFileList extends SwiftFileBackendList {
-       /**
-        * @see Iterator::current()
-        * @return string|bool String (relative path) or false
-        */
-       public function current() {
-               list( $path, $stat ) = current( $this->bufferIter );
-               $relPath = substr( $path, $this->suffixStart );
-               if ( is_array( $stat ) ) {
-                       $storageDir = rtrim( $this->params['dir'], '/' );
-                       $this->backend->loadListingStatInternal( "$storageDir/$relPath", $stat );
-               }
-
-               return $relPath;
-       }
-
-       protected function pageFromList( $container, $dir, &$after, $limit, array $params ) {
-               return $this->backend->getFileListPageInternal( $container, $dir, $after, $limit, $params );
-       }
-}
diff --git a/includes/libs/filebackend/exception/FileBackendError.php b/includes/libs/filebackend/exception/FileBackendError.php
new file mode 100644 (file)
index 0000000..e233535
--- /dev/null
@@ -0,0 +1,9 @@
+<?php
+/**
+ * File backend exception for checked exceptions (e.g. I/O errors)
+ *
+ * @ingroup FileBackend
+ * @since 1.22
+ */
+class FileBackendError extends Exception {
+}
diff --git a/includes/libs/filebackend/fileiteration/FSFileBackendDirList.php b/includes/libs/filebackend/fileiteration/FSFileBackendDirList.php
new file mode 100644 (file)
index 0000000..0545d9f
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup FileBackend
+ */
+
+class FSFileBackendDirList extends FSFileBackendList {
+       protected function filterViaNext() {
+               while ( $this->iter->valid() ) {
+                       if ( $this->iter->current()->isDot() || !$this->iter->current()->isDir() ) {
+                               $this->iter->next(); // skip non-directories and dot files
+                       } else {
+                               break;
+                       }
+               }
+       }
+}
diff --git a/includes/libs/filebackend/fileiteration/FSFileBackendFileList.php b/includes/libs/filebackend/fileiteration/FSFileBackendFileList.php
new file mode 100644 (file)
index 0000000..980e999
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup FileBackend
+ */
+
+class FSFileBackendFileList extends FSFileBackendList {
+       protected function filterViaNext() {
+               while ( $this->iter->valid() ) {
+                       if ( !$this->iter->current()->isFile() ) {
+                               $this->iter->next(); // skip non-files and dot files
+                       } else {
+                               break;
+                       }
+               }
+       }
+}
diff --git a/includes/libs/filebackend/fileiteration/FSFileBackendList.php b/includes/libs/filebackend/fileiteration/FSFileBackendList.php
new file mode 100644 (file)
index 0000000..9194efe
--- /dev/null
@@ -0,0 +1,157 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup FileBackend
+ */
+
+/**
+ * Wrapper around RecursiveDirectoryIterator/DirectoryIterator that
+ * catches exception or does any custom behavoir that we may want.
+ * Do not use this class from places outside FSFileBackend.
+ *
+ * @ingroup FileBackend
+ */
+abstract class FSFileBackendList implements Iterator {
+       /** @var Iterator */
+       protected $iter;
+
+       /** @var int */
+       protected $suffixStart;
+
+       /** @var int */
+       protected $pos = 0;
+
+       /** @var array */
+       protected $params = [];
+
+       /**
+        * @param string $dir File system directory
+        * @param array $params
+        */
+       public function __construct( $dir, array $params ) {
+               $path = realpath( $dir ); // normalize
+               if ( $path === false ) {
+                       $path = $dir;
+               }
+               $this->suffixStart = strlen( $path ) + 1; // size of "path/to/dir/"
+               $this->params = $params;
+
+               try {
+                       $this->iter = $this->initIterator( $path );
+               } catch ( UnexpectedValueException $e ) {
+                       $this->iter = null; // bad permissions? deleted?
+               }
+       }
+
+       /**
+        * Return an appropriate iterator object to wrap
+        *
+        * @param string $dir File system directory
+        * @return Iterator
+        */
+       protected function initIterator( $dir ) {
+               if ( !empty( $this->params['topOnly'] ) ) { // non-recursive
+                       # Get an iterator that will get direct sub-nodes
+                       return new DirectoryIterator( $dir );
+               } else { // recursive
+                       # Get an iterator that will return leaf nodes (non-directories)
+                       # RecursiveDirectoryIterator extends FilesystemIterator.
+                       # FilesystemIterator::SKIP_DOTS default is inconsistent in PHP 5.3.x.
+                       $flags = FilesystemIterator::CURRENT_AS_SELF | FilesystemIterator::SKIP_DOTS;
+
+                       return new RecursiveIteratorIterator(
+                               new RecursiveDirectoryIterator( $dir, $flags ),
+                               RecursiveIteratorIterator::CHILD_FIRST // include dirs
+                       );
+               }
+       }
+
+       /**
+        * @see Iterator::key()
+        * @return int
+        */
+       public function key() {
+               return $this->pos;
+       }
+
+       /**
+        * @see Iterator::current()
+        * @return string|bool String or false
+        */
+       public function current() {
+               return $this->getRelPath( $this->iter->current()->getPathname() );
+       }
+
+       /**
+        * @see Iterator::next()
+        * @throws FileBackendError
+        */
+       public function next() {
+               try {
+                       $this->iter->next();
+                       $this->filterViaNext();
+               } catch ( UnexpectedValueException $e ) { // bad permissions? deleted?
+                       throw new FileBackendError( "File iterator gave UnexpectedValueException." );
+               }
+               ++$this->pos;
+       }
+
+       /**
+        * @see Iterator::rewind()
+        * @throws FileBackendError
+        */
+       public function rewind() {
+               $this->pos = 0;
+               try {
+                       $this->iter->rewind();
+                       $this->filterViaNext();
+               } catch ( UnexpectedValueException $e ) { // bad permissions? deleted?
+                       throw new FileBackendError( "File iterator gave UnexpectedValueException." );
+               }
+       }
+
+       /**
+        * @see Iterator::valid()
+        * @return bool
+        */
+       public function valid() {
+               return $this->iter && $this->iter->valid();
+       }
+
+       /**
+        * Filter out items by advancing to the next ones
+        */
+       protected function filterViaNext() {
+       }
+
+       /**
+        * Return only the relative path and normalize slashes to FileBackend-style.
+        * Uses the "real path" since the suffix is based upon that.
+        *
+        * @param string $dir
+        * @return string
+        */
+       protected function getRelPath( $dir ) {
+               $path = realpath( $dir );
+               if ( $path === false ) {
+                       $path = $dir;
+               }
+
+               return strtr( substr( $path, $this->suffixStart ), '\\', '/' );
+       }
+}
diff --git a/includes/libs/filebackend/fileiteration/FileBackendStoreShardDirIterator.php b/includes/libs/filebackend/fileiteration/FileBackendStoreShardDirIterator.php
new file mode 100644 (file)
index 0000000..cd8ebff
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup FileBackend
+ */
+
+/**
+ * Iterator for listing directories
+ */
+class FileBackendStoreShardDirIterator extends FileBackendStoreShardListIterator {
+       protected function listFromShard( $container ) {
+               $list = $this->backend->getDirectoryListInternal(
+                       $container, $this->directory, $this->params );
+               if ( $list === null ) {
+                       return new ArrayIterator( [] );
+               } else {
+                       return is_array( $list ) ? new ArrayIterator( $list ) : $list;
+               }
+       }
+}
diff --git a/includes/libs/filebackend/fileiteration/FileBackendStoreShardFileIterator.php b/includes/libs/filebackend/fileiteration/FileBackendStoreShardFileIterator.php
new file mode 100644 (file)
index 0000000..d65a5d7
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup FileBackend
+ */
+
+/**
+ * Iterator for listing regular files
+ */
+class FileBackendStoreShardFileIterator extends FileBackendStoreShardListIterator {
+       protected function listFromShard( $container ) {
+               $list = $this->backend->getFileListInternal(
+                       $container, $this->directory, $this->params );
+               if ( $list === null ) {
+                       return new ArrayIterator( [] );
+               } else {
+                       return is_array( $list ) ? new ArrayIterator( $list ) : $list;
+               }
+       }
+}
diff --git a/includes/libs/filebackend/fileiteration/FileBackendStoreShardListIterator.php b/includes/libs/filebackend/fileiteration/FileBackendStoreShardListIterator.php
new file mode 100644 (file)
index 0000000..5f6b762
--- /dev/null
@@ -0,0 +1,94 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup FileBackend
+ */
+
+/**
+ * FileBackendStore helper function to handle listings that span container shards.
+ * Do not use this class from places outside of FileBackendStore.
+ *
+ * @ingroup FileBackend
+ */
+abstract class FileBackendStoreShardListIterator extends FilterIterator {
+       /** @var FileBackendStore */
+       protected $backend;
+
+       /** @var array */
+       protected $params;
+
+       /** @var string Full container name */
+       protected $container;
+
+       /** @var string Resolved relative path */
+       protected $directory;
+
+       /** @var array */
+       protected $multiShardPaths = []; // (rel path => 1)
+
+       /**
+        * @param FileBackendStore $backend
+        * @param string $container Full storage container name
+        * @param string $dir Storage directory relative to container
+        * @param array $suffixes List of container shard suffixes
+        * @param array $params
+        */
+       public function __construct(
+               FileBackendStore $backend, $container, $dir, array $suffixes, array $params
+       ) {
+               $this->backend = $backend;
+               $this->container = $container;
+               $this->directory = $dir;
+               $this->params = $params;
+
+               $iter = new AppendIterator();
+               foreach ( $suffixes as $suffix ) {
+                       $iter->append( $this->listFromShard( $this->container . $suffix ) );
+               }
+
+               parent::__construct( $iter );
+       }
+
+       public function accept() {
+               $rel = $this->getInnerIterator()->current(); // path relative to given directory
+               $path = $this->params['dir'] . "/{$rel}"; // full storage path
+               if ( $this->backend->isSingleShardPathInternal( $path ) ) {
+                       return true; // path is only on one shard; no issue with duplicates
+               } elseif ( isset( $this->multiShardPaths[$rel] ) ) {
+                       // Don't keep listing paths that are on multiple shards
+                       return false;
+               } else {
+                       $this->multiShardPaths[$rel] = 1;
+
+                       return true;
+               }
+       }
+
+       public function rewind() {
+               parent::rewind();
+               $this->multiShardPaths = [];
+       }
+
+       /**
+        * Get the list for a given container shard
+        *
+        * @param string $container Resolved container name
+        * @return Iterator
+        */
+       abstract protected function listFromShard( $container );
+}
diff --git a/includes/libs/filebackend/fileiteration/SwiftFileBackendDirList.php b/includes/libs/filebackend/fileiteration/SwiftFileBackendDirList.php
new file mode 100644 (file)
index 0000000..b0b784d
--- /dev/null
@@ -0,0 +1,40 @@
+<?php
+/**
+ * OpenStack Swift based file backend.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup FileBackend
+ * @author Russ Nelson
+ */
+
+/**
+ * Iterator for listing directories
+ */
+class SwiftFileBackendDirList extends SwiftFileBackendList {
+       /**
+        * @see Iterator::current()
+        * @return string|bool String (relative path) or false
+        */
+       public function current() {
+               return substr( current( $this->bufferIter ), $this->suffixStart, -1 );
+       }
+
+       protected function pageFromList( $container, $dir, &$after, $limit, array $params ) {
+               return $this->backend->getDirListPageInternal( $container, $dir, $after, $limit, $params );
+       }
+}
diff --git a/includes/libs/filebackend/fileiteration/SwiftFileBackendFileList.php b/includes/libs/filebackend/fileiteration/SwiftFileBackendFileList.php
new file mode 100644 (file)
index 0000000..045b8f8
--- /dev/null
@@ -0,0 +1,47 @@
+<?php
+/**
+ * OpenStack Swift based file backend.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup FileBackend
+ * @author Russ Nelson
+ */
+
+/**
+ * Iterator for listing regular files
+ */
+class SwiftFileBackendFileList extends SwiftFileBackendList {
+       /**
+        * @see Iterator::current()
+        * @return string|bool String (relative path) or false
+        */
+       public function current() {
+               list( $path, $stat ) = current( $this->bufferIter );
+               $relPath = substr( $path, $this->suffixStart );
+               if ( is_array( $stat ) ) {
+                       $storageDir = rtrim( $this->params['dir'], '/' );
+                       $this->backend->loadListingStatInternal( "$storageDir/$relPath", $stat );
+               }
+
+               return $relPath;
+       }
+
+       protected function pageFromList( $container, $dir, &$after, $limit, array $params ) {
+               return $this->backend->getFileListPageInternal( $container, $dir, $after, $limit, $params );
+       }
+}
diff --git a/includes/libs/filebackend/fileiteration/SwiftFileBackendList.php b/includes/libs/filebackend/fileiteration/SwiftFileBackendList.php
new file mode 100644 (file)
index 0000000..bcde8d9
--- /dev/null
@@ -0,0 +1,138 @@
+<?php
+/**
+ * OpenStack Swift based file backend.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup FileBackend
+ * @author Russ Nelson
+ */
+
+/**
+ * SwiftFileBackend helper class to page through listings.
+ * Swift also has a listing limit of 10,000 objects for sanity.
+ * Do not use this class from places outside SwiftFileBackend.
+ *
+ * @ingroup FileBackend
+ */
+abstract class SwiftFileBackendList implements Iterator {
+       /** @var array List of path or (path,stat array) entries */
+       protected $bufferIter = [];
+
+       /** @var string List items *after* this path */
+       protected $bufferAfter = null;
+
+       /** @var int */
+       protected $pos = 0;
+
+       /** @var array */
+       protected $params = [];
+
+       /** @var SwiftFileBackend */
+       protected $backend;
+
+       /** @var string Container name */
+       protected $container;
+
+       /** @var string Storage directory */
+       protected $dir;
+
+       /** @var int */
+       protected $suffixStart;
+
+       const PAGE_SIZE = 9000; // file listing buffer size
+
+       /**
+        * @param SwiftFileBackend $backend
+        * @param string $fullCont Resolved container name
+        * @param string $dir Resolved directory relative to container
+        * @param array $params
+        */
+       public function __construct( SwiftFileBackend $backend, $fullCont, $dir, array $params ) {
+               $this->backend = $backend;
+               $this->container = $fullCont;
+               $this->dir = $dir;
+               if ( substr( $this->dir, -1 ) === '/' ) {
+                       $this->dir = substr( $this->dir, 0, -1 ); // remove trailing slash
+               }
+               if ( $this->dir == '' ) { // whole container
+                       $this->suffixStart = 0;
+               } else { // dir within container
+                       $this->suffixStart = strlen( $this->dir ) + 1; // size of "path/to/dir/"
+               }
+               $this->params = $params;
+       }
+
+       /**
+        * @see Iterator::key()
+        * @return int
+        */
+       public function key() {
+               return $this->pos;
+       }
+
+       /**
+        * @see Iterator::next()
+        */
+       public function next() {
+               // Advance to the next file in the page
+               next( $this->bufferIter );
+               ++$this->pos;
+               // Check if there are no files left in this page and
+               // advance to the next page if this page was not empty.
+               if ( !$this->valid() && count( $this->bufferIter ) ) {
+                       $this->bufferIter = $this->pageFromList(
+                               $this->container, $this->dir, $this->bufferAfter, self::PAGE_SIZE, $this->params
+                       ); // updates $this->bufferAfter
+               }
+       }
+
+       /**
+        * @see Iterator::rewind()
+        */
+       public function rewind() {
+               $this->pos = 0;
+               $this->bufferAfter = null;
+               $this->bufferIter = $this->pageFromList(
+                       $this->container, $this->dir, $this->bufferAfter, self::PAGE_SIZE, $this->params
+               ); // updates $this->bufferAfter
+       }
+
+       /**
+        * @see Iterator::valid()
+        * @return bool
+        */
+       public function valid() {
+               if ( $this->bufferIter === null ) {
+                       return false; // some failure?
+               } else {
+                       return ( current( $this->bufferIter ) !== false ); // no paths can have this value
+               }
+       }
+
+       /**
+        * Get the given list portion (page)
+        *
+        * @param string $container Resolved container name
+        * @param string $dir Resolved path relative to container
+        * @param string &$after
+        * @param int $limit
+        * @param array $params
+        * @return Traversable|array
+        */
+       abstract protected function pageFromList( $container, $dir, &$after, $limit, array $params );
+}
diff --git a/includes/libs/filebackend/fileophandle/FSFileOpHandle.php b/includes/libs/filebackend/fileophandle/FSFileOpHandle.php
new file mode 100644 (file)
index 0000000..2d65c43
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup FileBackend
+ */
+
+/**
+ * @see FileBackendStoreOpHandle
+ */
+class FSFileOpHandle extends FileBackendStoreOpHandle {
+       public $cmd; // string; shell command
+       public $chmodPath; // string; file to chmod
+
+       /**
+        * @param FSFileBackend $backend
+        * @param array $params
+        * @param callable $call
+        * @param string $cmd
+        * @param int|null $chmodPath
+        */
+       public function __construct(
+               FSFileBackend $backend, array $params, $call, $cmd, $chmodPath = null
+       ) {
+               $this->backend = $backend;
+               $this->params = $params;
+               $this->call = $call;
+               $this->cmd = $cmd;
+               $this->chmodPath = $chmodPath;
+       }
+}
diff --git a/includes/libs/filebackend/fileophandle/FileBackendStoreOpHandle.php b/includes/libs/filebackend/fileophandle/FileBackendStoreOpHandle.php
new file mode 100644 (file)
index 0000000..c366a0f
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup FileBackend
+ */
+
+/**
+ * FileBackendStore helper class for performing asynchronous file operations.
+ *
+ * For example, calling FileBackendStore::createInternal() with the "async"
+ * param flag may result in a StatusValue that contains this object as a value.
+ * This class is largely backend-specific and is mostly just "magic" to be
+ * passed to FileBackendStore::executeOpHandlesInternal().
+ */
+abstract class FileBackendStoreOpHandle {
+       /** @var array */
+       public $params = []; // params to caller functions
+       /** @var FileBackendStore */
+       public $backend;
+       /** @var array */
+       public $resourcesToClose = [];
+
+       public $call; // string; name that identifies the function called
+
+       /**
+        * Close all open file handles
+        */
+       public function closeResources() {
+               array_map( 'fclose', $this->resourcesToClose );
+       }
+}
diff --git a/includes/libs/filebackend/fileophandle/SwiftFileOpHandle.php b/includes/libs/filebackend/fileophandle/SwiftFileOpHandle.php
new file mode 100644 (file)
index 0000000..1119867
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+/**
+ * OpenStack Swift based file backend.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup FileBackend
+ * @author Russ Nelson
+ */
+
+/**
+ * @see FileBackendStoreOpHandle
+ */
+class SwiftFileOpHandle extends FileBackendStoreOpHandle {
+       /** @var array List of Requests for MultiHttpClient */
+       public $httpOp;
+       /** @var Closure */
+       public $callback;
+
+       /**
+        * @param SwiftFileBackend $backend
+        * @param Closure $callback Function that takes (HTTP request array, status)
+        * @param array $httpOp MultiHttpClient op
+        */
+       public function __construct( SwiftFileBackend $backend, Closure $callback, array $httpOp ) {
+               $this->backend = $backend;
+               $this->callback = $callback;
+               $this->httpOp = $httpOp;
+       }
+}
index 321424f..b993626 100644 (file)
@@ -178,7 +178,7 @@ class TempFSFile extends FSFile {
         * This method should only be called internally
         */
        public static function purgeAllOnShutdown() {
-               foreach ( self::$pathsCollect as $path ) {
+               foreach ( self::$pathsCollect as $path => $unused ) {
                        Wikimedia\suppressWarnings();
                        unlink( $path );
                        Wikimedia\restoreWarnings();
index 3134e50..0eab860 100644 (file)
@@ -1700,7 +1700,7 @@ class JSNode
        public $funDecls = array();
        public $varDecls = array();
 
-       public function __construct($t, $type=0)
+       public function __construct($t, $type=0, ...$nodes)
        {
                if ($token = $t->currentToken())
                {
@@ -1716,11 +1716,9 @@ class JSNode
                        $this->lineno = $t->lineno;
                }
 
-               if (($numargs = func_num_args()) > 2)
+               foreach($nodes as $node)
                {
-                       $args = func_get_args();
-                       for ($i = 2; $i < $numargs; $i++)
-                               $this->addNode($args[$i]);
+                       $this->addNode($node);
                }
        }
 
index e08da61..a326df2 100644 (file)
@@ -806,7 +806,7 @@ EOT;
                if ( $eocdrPos !== false ) {
                        $this->logger->info( __METHOD__ . ": ZIP signature present in $file\n" );
                        // Check if it really is a ZIP file, make sure the EOCDR is at the end (T40432)
-                       $commentLength = unpack( "n", $tail, $eocdrPos + 20 )[0];
+                       $commentLength = unpack( "n", substr( $tail, $eocdrPos + 20 ) )[0];
                        if ( $eocdrPos + 22 + $commentLength !== strlen( $tail ) ) {
                                $this->logger->info( __METHOD__ . ": ZIP EOCDR not at end. Not a ZIP file." );
                        } else {
index 993eea9..0b52391 100644 (file)
@@ -72,7 +72,7 @@ class XmlTypeCheck {
         * Additional parsing options
         */
        private $parserOptions = [
-               'processing_instruction_handler' => '',
+               'processing_instruction_handler' => null,
                'external_dtd_handler' => '',
                'dtd_handler' => '',
                'require_safe_dtd' => true
@@ -406,10 +406,10 @@ class XmlTypeCheck {
                        $callbackReturn = false;
                }
 
-               if ( $checkIfSafe && isset( $parsedDTD['internal'] ) ) {
-                       if ( !$this->checkDTDIsSafe( $parsedDTD['internal'] ) ) {
-                               $this->wellFormed = false;
-                       }
+               if ( $checkIfSafe && isset( $parsedDTD['internal'] ) &&
+                       !$this->checkDTDIsSafe( $parsedDTD['internal'] )
+               ) {
+                       $this->wellFormed = false;
                }
        }
 
index 847a1eb..9a5a433 100644 (file)
 /**
  * This is a wrapper for APC's shared memory functions
  *
+ * Use PHP serialization to avoid bugs and easily create CAS tokens.
+ * APCu has a memory corruption bug when the serializer is set to 'default'.
+ * See T120267, and upstream bug reports:
+ *  - https://github.com/krakjoe/apcu/issues/38
+ *  - https://github.com/krakjoe/apcu/issues/35
+ *  - https://github.com/krakjoe/apcu/issues/111
+ *
  * @ingroup Cache
  */
 class APCBagOStuff extends BagOStuff {
-
-       /**
-        * @var bool If true, trust the APC implementation to serialize and
-        * deserialize objects correctly. If false, (de-)serialize in PHP.
-        */
-       protected $nativeSerialize;
-
        /**
         * @var string String to append to each APC key. This may be changed
         *  whenever the handling of values is changed, to prevent existing code
         *  from encountering older values which it cannot handle.
         */
-       const KEY_SUFFIX = ':2';
+       const KEY_SUFFIX = ':3';
 
-       /**
-        * Available parameters are:
-        *   - nativeSerialize:     If true, pass objects to apc_store(), and trust it
-        *                          to serialize them correctly. If false, serialize
-        *                          all values in PHP.
-        *
-        * @param array $params
-        */
-       public function __construct( array $params = [] ) {
-               parent::__construct( $params );
+       protected function doGet( $key, $flags = 0, &$casToken = null ) {
+               $casToken = null;
 
-               if ( isset( $params['nativeSerialize'] ) ) {
-                       $this->nativeSerialize = $params['nativeSerialize'];
-               } elseif ( extension_loaded( 'apcu' ) && ini_get( 'apc.serializer' ) === 'default' ) {
-                       // APCu has a memory corruption bug when the serializer is set to 'default'.
-                       // See T120267, and upstream bug reports:
-                       //  - https://github.com/krakjoe/apcu/issues/38
-                       //  - https://github.com/krakjoe/apcu/issues/35
-                       //  - https://github.com/krakjoe/apcu/issues/111
-                       $this->logger->warning(
-                               'The APCu extension is loaded and the apc.serializer INI setting ' .
-                               'is set to "default". This can cause memory corruption! ' .
-                               'You should change apc.serializer to "php" instead. ' .
-                               'See <https://github.com/krakjoe/apcu/issues/38>.'
-                       );
-                       $this->nativeSerialize = false;
-               } else {
-                       $this->nativeSerialize = true;
+               $blob = apc_fetch( $key . self::KEY_SUFFIX );
+               $value = $this->unserialize( $blob );
+               if ( $value !== false ) {
+                       $casToken = $blob; // don't bother hashing this
                }
-       }
-
-       protected function doGet( $key, $flags = 0 ) {
-               return $this->getUnserialize(
-                       apc_fetch( $key . self::KEY_SUFFIX )
-               );
-       }
 
-       protected function getUnserialize( $value ) {
-               if ( is_string( $value ) && !$this->nativeSerialize ) {
-                       $value = $this->isInteger( $value )
-                               ? intval( $value )
-                               : unserialize( $value );
-               }
                return $value;
        }
 
        public function set( $key, $value, $exptime = 0, $flags = 0 ) {
                apc_store(
                        $key . self::KEY_SUFFIX,
-                       $this->setSerialize( $value ),
+                       $this->serialize( $value ),
                        $exptime
                );
 
@@ -100,18 +66,11 @@ class APCBagOStuff extends BagOStuff {
        public function add( $key, $value, $exptime = 0, $flags = 0 ) {
                return apc_add(
                        $key . self::KEY_SUFFIX,
-                       $this->setSerialize( $value ),
+                       $this->serialize( $value ),
                        $exptime
                );
        }
 
-       protected function setSerialize( $value ) {
-               if ( !$this->nativeSerialize && !$this->isInteger( $value ) ) {
-                       $value = serialize( $value );
-               }
-               return $value;
-       }
-
        public function delete( $key, $flags = 0 ) {
                apc_delete( $key . self::KEY_SUFFIX );
 
@@ -125,4 +84,12 @@ class APCBagOStuff extends BagOStuff {
        public function decr( $key, $value = 1 ) {
                return apc_dec( $key . self::KEY_SUFFIX, $value );
        }
+
+       protected function serialize( $value ) {
+               return $this->isInteger( $value ) ? (int)$value : serialize( $value );
+       }
+
+       protected function unserialize( $value ) {
+               return $this->isInteger( $value ) ? (int)$value : unserialize( $value );
+       }
 }
index d5f1edc..eba0af5 100644 (file)
 /**
  * This is a wrapper for APCU's shared memory functions
  *
+ * Use PHP serialization to avoid bugs and easily create CAS tokens.
+ * APCu has a memory corruption bug when the serializer is set to 'default'.
+ * See T120267, and upstream bug reports:
+ *  - https://github.com/krakjoe/apcu/issues/38
+ *  - https://github.com/krakjoe/apcu/issues/35
+ *  - https://github.com/krakjoe/apcu/issues/111
+ *
  * @ingroup Cache
  */
-class APCUBagOStuff extends APCBagOStuff {
+class APCUBagOStuff extends BagOStuff {
+       /** @var bool Whether to trust the APC implementation to serialization */
+       private $nativeSerialize;
+
        /**
-        * Available parameters are:
-        *   - nativeSerialize:     If true, pass objects to apcu_store(), and trust it
-        *                          to serialize them correctly. If false, serialize
-        *                          all values in PHP.
-        *
-        * @param array $params
+        * @var string String to append to each APC key. This may be changed
+        *  whenever the handling of values is changed, to prevent existing code
+        *  from encountering older values which it cannot handle.
         */
+       const KEY_SUFFIX = ':4';
+
        public function __construct( array $params = [] ) {
                parent::__construct( $params );
+               // The extension serialize is still buggy, unlike "php" and "igbinary"
+               $this->nativeSerialize = ( ini_get( 'apc.serializer' ) !== 'default' );
        }
 
-       protected function doGet( $key, $flags = 0 ) {
-               return $this->getUnserialize(
-                       apcu_fetch( $key . self::KEY_SUFFIX )
-               );
+       protected function doGet( $key, $flags = 0, &$casToken = null ) {
+               $casToken = null;
+
+               $blob = apcu_fetch( $key . self::KEY_SUFFIX );
+               $value = $this->unserialize( $blob );
+               if ( $value !== false ) {
+                       $casToken = $blob; // don't bother hashing this
+               }
+
+               return $value;
        }
 
        public function set( $key, $value, $exptime = 0, $flags = 0 ) {
-               apcu_store(
+               return apcu_store(
                        $key . self::KEY_SUFFIX,
-                       $this->setSerialize( $value ),
+                       $this->serialize( $value ),
                        $exptime
                );
-
-               return true;
        }
 
        public function add( $key, $value, $exptime = 0, $flags = 0 ) {
                return apcu_add(
                        $key . self::KEY_SUFFIX,
-                       $this->setSerialize( $value ),
+                       $this->serialize( $value ),
                        $exptime
                );
        }
@@ -70,11 +85,7 @@ class APCUBagOStuff extends APCBagOStuff {
        }
 
        public function incr( $key, $value = 1 ) {
-               /**
-                * @todo When we only support php 7 or higher remove this hack
-                *
-                * https://github.com/krakjoe/apcu/issues/166
-                */
+               // https://github.com/krakjoe/apcu/issues/166
                if ( apcu_exists( $key . self::KEY_SUFFIX ) ) {
                        return apcu_inc( $key . self::KEY_SUFFIX, $value );
                } else {
@@ -83,15 +94,27 @@ class APCUBagOStuff extends APCBagOStuff {
        }
 
        public function decr( $key, $value = 1 ) {
-               /**
-                * @todo When we only support php 7 or higher remove this hack
-                *
-                * https://github.com/krakjoe/apcu/issues/166
-                */
+               // https://github.com/krakjoe/apcu/issues/166
                if ( apcu_exists( $key . self::KEY_SUFFIX ) ) {
                        return apcu_dec( $key . self::KEY_SUFFIX, $value );
                } else {
                        return false;
                }
        }
+
+       protected function serialize( $value ) {
+               if ( $this->nativeSerialize ) {
+                       return $value;
+               }
+
+               return $this->isInteger( $value ) ? (int)$value : serialize( $value );
+       }
+
+       protected function unserialize( $value ) {
+               if ( $this->nativeSerialize ) {
+                       return $value;
+               }
+
+               return $this->isInteger( $value ) ? (int)$value : unserialize( $value );
+       }
 }
index 27c6167..0dd7b57 100644 (file)
@@ -139,7 +139,7 @@ abstract class BagOStuff implements IExpiringStore, LoggerAwareInterface {
        /**
         * Get an item with the given key, regenerating and setting it if not found
         *
-        * If the callback returns false, then nothing is stored.
+        * Nothing is stored nor deleted if the callback returns false
         *
         * @param string $key
         * @param int $ttl Time-to-live (seconds)
@@ -175,13 +175,9 @@ abstract class BagOStuff implements IExpiringStore, LoggerAwareInterface {
         *
         * @param string $key
         * @param int $flags Bitfield of BagOStuff::READ_* constants [optional]
-        * @param int|null $oldFlags [unused]
-        * @return mixed Returns false on failure and if the item does not exist
+        * @return mixed Returns false on failure or if the item does not exist
         */
-       public function get( $key, $flags = 0, $oldFlags = null ) {
-               // B/C for ( $key, &$casToken = null, $flags = 0 )
-               $flags = is_int( $oldFlags ) ? $oldFlags : $flags;
-
+       public function get( $key, $flags = 0 ) {
                $this->trackDuplicateKeys( $key );
 
                return $this->doGet( $key, $flags );
@@ -223,22 +219,10 @@ abstract class BagOStuff implements IExpiringStore, LoggerAwareInterface {
        /**
         * @param string $key
         * @param int $flags Bitfield of BagOStuff::READ_* constants [optional]
-        * @return mixed Returns false on failure and if the item does not exist
-        */
-       abstract protected function doGet( $key, $flags = 0 );
-
-       /**
-        * @note This method is only needed if merge() uses mergeViaCas()
-        *
-        * @param string $key
-        * @param mixed &$casToken
-        * @param int $flags Bitfield of BagOStuff::READ_* constants [optional]
-        * @return mixed Returns false on failure and if the item does not exist
-        * @throws Exception
+        * @param mixed|null &$casToken Token to use for check-and-set comparisons
+        * @return mixed Returns false on failure or if the item does not exist
         */
-       protected function getWithToken( $key, &$casToken, $flags = 0 ) {
-               throw new Exception( __METHOD__ . ' not implemented.' );
-       }
+       abstract protected function doGet( $key, $flags = 0, &$casToken = null );
 
        /**
         * Set an item
@@ -260,6 +244,17 @@ abstract class BagOStuff implements IExpiringStore, LoggerAwareInterface {
         */
        abstract public function delete( $key, $flags = 0 );
 
+       /**
+        * Insert an item if it does not already exist
+        *
+        * @param string $key
+        * @param mixed $value
+        * @param int $exptime
+        * @param int $flags Bitfield of BagOStuff::WRITE_* constants (since 1.33)
+        * @return bool Success
+        */
+       abstract public function add( $key, $value, $exptime = 0, $flags = 0 );
+
        /**
         * Merge changes into the existing cache value (possibly creating a new one)
         *
@@ -267,7 +262,7 @@ abstract class BagOStuff implements IExpiringStore, LoggerAwareInterface {
         * (which will be false if not present), and takes the arguments:
         * (this BagOStuff, cache key, current value, TTL).
         * The TTL parameter is reference set to $exptime. It can be overriden in the callback.
-        * If the callback returns false, then the current value will be unchanged (including TTL).
+        * Nothing is stored nor deleted if the callback returns false.
         *
         * @param string $key
         * @param callable $callback Callback method to be executed
@@ -278,7 +273,7 @@ abstract class BagOStuff implements IExpiringStore, LoggerAwareInterface {
         * @throws InvalidArgumentException
         */
        public function merge( $key, callable $callback, $exptime = 0, $attempts = 10, $flags = 0 ) {
-               return $this->mergeViaLock( $key, $callback, $exptime, $attempts, $flags );
+               return $this->mergeViaCas( $key, $callback, $exptime, $attempts, $flags );
        }
 
        /**
@@ -293,13 +288,10 @@ abstract class BagOStuff implements IExpiringStore, LoggerAwareInterface {
         */
        protected function mergeViaCas( $key, $callback, $exptime = 0, $attempts = 10, $flags = 0 ) {
                do {
-                       $this->clearLastError();
-                       $reportDupes = $this->reportDupes;
-                       $this->reportDupes = false;
                        $casToken = null; // passed by reference
-                       $currentValue = $this->getWithToken( $key, $casToken, self::READ_LATEST );
-                       $this->reportDupes = $reportDupes;
-
+                       // Get the old value and CAS token from cache
+                       $this->clearLastError();
+                       $currentValue = $this->doGet( $key, self::READ_LATEST, $casToken );
                        if ( $this->getLastError() ) {
                                $this->logger->warning(
                                        __METHOD__ . ' failed due to I/O error on get() for {key}.',
@@ -311,11 +303,13 @@ abstract class BagOStuff implements IExpiringStore, LoggerAwareInterface {
 
                        // Derive the new value from the old value
                        $value = call_user_func( $callback, $this, $key, $currentValue, $exptime );
+                       $hadNoCurrentValue = ( $currentValue === false );
+                       unset( $currentValue ); // free RAM in case the value is large
 
                        $this->clearLastError();
                        if ( $value === false ) {
                                $success = true; // do nothing
-                       } elseif ( $currentValue === false ) {
+                       } elseif ( $hadNoCurrentValue ) {
                                // Try to create the key, failing if it gets created in the meantime
                                $success = $this->add( $key, $value, $exptime, $flags );
                        } else {
@@ -352,7 +346,7 @@ abstract class BagOStuff implements IExpiringStore, LoggerAwareInterface {
                }
 
                $curCasToken = null; // passed by reference
-               $this->getWithToken( $key, $curCasToken, self::READ_LATEST );
+               $this->doGet( $key, self::READ_LATEST, $curCasToken );
                if ( $casToken === $curCasToken ) {
                        $success = $this->set( $key, $value, $exptime, $flags );
                } else {
@@ -370,70 +364,32 @@ abstract class BagOStuff implements IExpiringStore, LoggerAwareInterface {
        }
 
        /**
-        * @see BagOStuff::merge()
+        * Change the expiration on a key if it exists
         *
-        * @param string $key
-        * @param callable $callback Callback method to be executed
-        * @param int $exptime Either an interval in seconds or a unix timestamp for expiry
-        * @param int $attempts The amount of times to attempt a merge in case of failure
-        * @param int $flags Bitfield of BagOStuff::WRITE_* constants
-        * @return bool Success
-        */
-       protected function mergeViaLock( $key, $callback, $exptime = 0, $attempts = 10, $flags = 0 ) {
-               if ( $attempts <= 1 ) {
-                       $timeout = 0; // clearly intended to be "non-blocking"
-               } else {
-                       $timeout = 3;
-               }
-
-               if ( !$this->lock( $key, $timeout ) ) {
-                       return false;
-               }
-
-               $this->clearLastError();
-               $reportDupes = $this->reportDupes;
-               $this->reportDupes = false;
-               $currentValue = $this->get( $key, self::READ_LATEST );
-               $this->reportDupes = $reportDupes;
-
-               if ( $this->getLastError() ) {
-                       $this->logger->warning(
-                               __METHOD__ . ' failed due to I/O error on get() for {key}.',
-                               [ 'key' => $key ]
-                       );
-
-                       $success = false;
-               } else {
-                       // Derive the new value from the old value
-                       $value = call_user_func( $callback, $this, $key, $currentValue, $exptime );
-                       if ( $value === false ) {
-                               $success = true; // do nothing
-                       } else {
-                               $success = $this->set( $key, $value, $exptime, $flags ); // set the new value
-                       }
-               }
-
-               if ( !$this->unlock( $key ) ) {
-                       // this should never happen
-                       trigger_error( "Could not release lock for key '$key'." );
-               }
-
-               return $success;
-       }
-
-       /**
-        * Reset the TTL on a key if it exists
+        * If an expiry in the past is given then the key will immediately be expired
         *
         * @param string $key
-        * @param int $expiry
+        * @param int $expiry TTL or UNIX timestamp
         * @param int $flags Bitfield of BagOStuff::WRITE_* constants (since 1.33)
-        * @return bool Success Returns false if there is no key
+        * @return bool Success Returns false on failure or if the item does not exist
         * @since 1.28
         */
        public function changeTTL( $key, $expiry = 0, $flags = 0 ) {
-               $value = $this->get( $key );
+               $found = false;
+
+               $ok = $this->merge(
+                       $key,
+                       function ( $cache, $ttl, $currentValue ) use ( &$found ) {
+                               $found = ( $currentValue !== false );
 
-               return ( $value === false ) ? false : $this->set( $key, $value, $expiry, $flags );
+                               return $currentValue; // nothing is written if this is false
+                       },
+                       $expiry,
+                       1, // 1 attempt
+                       $flags
+               );
+
+               return ( $ok && $found );
        }
 
        /**
@@ -623,16 +579,6 @@ abstract class BagOStuff implements IExpiringStore, LoggerAwareInterface {
                return $res;
        }
 
-       /**
-        * Insertion
-        * @param string $key
-        * @param mixed $value
-        * @param int $exptime
-        * @param int $flags Bitfield of BagOStuff::WRITE_* constants (since 1.33)
-        * @return bool Success
-        */
-       abstract public function add( $key, $value, $exptime = 0, $flags = 0 );
-
        /**
         * Increase stored value of $key by $value while preserving its TTL
         * @param string $key Key to increase
@@ -739,13 +685,21 @@ abstract class BagOStuff implements IExpiringStore, LoggerAwareInterface {
                }
        }
 
+       /**
+        * @param int $exptime
+        * @return bool
+        */
+       protected function expiryIsRelative( $exptime ) {
+               return ( $exptime != 0 && $exptime < ( 10 * self::TTL_YEAR ) );
+       }
+
        /**
         * Convert an optionally relative time to an absolute time
         * @param int $exptime
         * @return int
         */
-       protected function convertExpiry( $exptime ) {
-               if ( $exptime != 0 && $exptime < ( 10 * self::TTL_YEAR ) ) {
+       protected function convertToExpiry( $exptime ) {
+               if ( $this->expiryIsRelative( $exptime ) ) {
                        return (int)$this->getCurrentTime() + $exptime;
                } else {
                        return $exptime;
index 95dda71..8892f73 100644 (file)
@@ -32,6 +32,7 @@
  *   up going to the HashBagOStuff used for the in-memory cache).
  *
  * @ingroup Cache
+ * @TODO: Make this class use composition instead of calling super
  */
 class CachedBagOStuff extends HashBagOStuff {
        /** @var BagOStuff */
@@ -50,10 +51,10 @@ class CachedBagOStuff extends HashBagOStuff {
                $this->attrMap = $backend->attrMap;
        }
 
-       protected function doGet( $key, $flags = 0 ) {
-               $ret = parent::doGet( $key, $flags );
+       public function get( $key, $flags = 0 ) {
+               $ret = parent::get( $key, $flags );
                if ( $ret === false && !$this->hasKey( $key ) ) {
-                       $ret = $this->backend->doGet( $key, $flags );
+                       $ret = $this->backend->get( $key, $flags );
                        $this->set( $key, $ret, 0, self::WRITE_CACHE_ONLY );
                }
                return $ret;
index e0f4364..ffe3a4c 100644 (file)
@@ -27,7 +27,9 @@
  * @ingroup Cache
  */
 class EmptyBagOStuff extends BagOStuff {
-       protected function doGet( $key, $flags = 0 ) {
+       protected function doGet( $key, $flags = 0, &$casToken = null ) {
+               $casToken = null;
+
                return false;
        }
 
index 4793ce0..d24f408 100644 (file)
@@ -34,8 +34,15 @@ class HashBagOStuff extends BagOStuff {
        /** @var int Max entries allowed */
        protected $maxCacheKeys;
 
+       /** @var string CAS token prefix for this instance */
+       private $token;
+
+       /** @var int CAS token counter */
+       private static $casCounter = 0;
+
        const KEY_VAL = 0;
        const KEY_EXP = 1;
+       const KEY_CAS = 2;
 
        /**
         * @param array $params Additional parameters include:
@@ -44,40 +51,17 @@ class HashBagOStuff extends BagOStuff {
        function __construct( $params = [] ) {
                parent::__construct( $params );
 
+               $this->token = microtime( true ) . ':' . mt_rand();
                $this->maxCacheKeys = $params['maxKeys'] ?? INF;
                if ( $this->maxCacheKeys <= 0 ) {
                        throw new InvalidArgumentException( '$maxKeys parameter must be above zero' );
                }
        }
 
-       protected function expire( $key ) {
-               $et = $this->bag[$key][self::KEY_EXP];
-               if ( $et == self::TTL_INDEFINITE || $et > $this->getCurrentTime() ) {
-                       return false;
-               }
-
-               $this->delete( $key );
-
-               return true;
-       }
-
-       /**
-        * Does this bag have a non-null value for the given key?
-        *
-        * @param string $key
-        * @return bool
-        * @since 1.27
-        */
-       protected function hasKey( $key ) {
-               return isset( $this->bag[$key] );
-       }
-
-       protected function doGet( $key, $flags = 0 ) {
-               if ( !$this->hasKey( $key ) ) {
-                       return false;
-               }
+       protected function doGet( $key, $flags = 0, &$casToken = null ) {
+               $casToken = null;
 
-               if ( $this->expire( $key ) ) {
+               if ( !$this->hasKey( $key ) || $this->expire( $key ) ) {
                        return false;
                }
 
@@ -86,6 +70,8 @@ class HashBagOStuff extends BagOStuff {
                unset( $this->bag[$key] );
                $this->bag[$key] = $temp;
 
+               $casToken = $this->bag[$key][self::KEY_CAS];
+
                return $this->bag[$key][self::KEY_VAL];
        }
 
@@ -94,7 +80,8 @@ class HashBagOStuff extends BagOStuff {
                unset( $this->bag[$key] );
                $this->bag[$key] = [
                        self::KEY_VAL => $value,
-                       self::KEY_EXP => $this->convertExpiry( $exptime )
+                       self::KEY_EXP => $this->convertToExpiry( $exptime ),
+                       self::KEY_CAS => $this->token . ':' . ++self::$casCounter
                ];
 
                if ( count( $this->bag ) > $this->maxCacheKeys ) {
@@ -132,7 +119,36 @@ class HashBagOStuff extends BagOStuff {
                return false;
        }
 
+       /**
+        * Clear all values in cache
+        */
        public function clear() {
                $this->bag = [];
        }
+
+       /**
+        * @param string $key
+        * @return bool
+        */
+       protected function expire( $key ) {
+               $et = $this->bag[$key][self::KEY_EXP];
+               if ( $et == self::TTL_INDEFINITE || $et > $this->getCurrentTime() ) {
+                       return false;
+               }
+
+               $this->delete( $key );
+
+               return true;
+       }
+
+       /**
+        * Does this bag have a non-null value for the given key?
+        *
+        * @param string $key
+        * @return bool
+        * @since 1.27
+        */
+       protected function hasKey( $key ) {
+               return isset( $this->bag[$key] );
+       }
 }
index c1edff7..61a4c61 100644 (file)
@@ -21,7 +21,7 @@
  */
 
 /**
- * Generic base class for storage interfaces.
+ * Generic interface for lightweight expiring object stores.
  *
  * Provides convenient TTL constants.
  *
@@ -44,16 +44,19 @@ interface IExpiringStore {
 
        const TTL_INDEFINITE = 0;
 
-       // Attribute and QoS constants; higher QOS values with the same prefix rank higher...
-       // Medium attributes constants related to emulation or media type
+       // Emulation/fallback medium attribute (e.g. SQLBagOStuff)
        const ATTR_EMULATION = 1;
+       // Quality of service constants for ATTR_EMULATION (higher means faster)
        const QOS_EMULATION_SQL = 1;
-       // Medium attributes constants related to replica consistency
-       const ATTR_SYNCWRITES = 2; // SYNC_WRITES flag support
+
+       // Replica synchronization/consistency attribute of medium when SYNC_WRITES is used
+       const ATTR_SYNCWRITES = 2;
+       // Quality of service constants for ATTR_SYNCWRITES (higher means more consistent)
        const QOS_SYNCWRITES_NONE = 1; // replication only supports eventual consistency or less
        const QOS_SYNCWRITES_BE = 2; // best effort synchronous with limited retries
        const QOS_SYNCWRITES_QC = 3; // write quorum applied directly to state machines where R+W > N
        const QOS_SYNCWRITES_SS = 4; // strict-serializable, nodes refuse reads if possible stale
+
        // Generic "unknown" value that is useful for comparisons (e.g. always good enough)
        const QOS_UNKNOWN = INF;
 
index 5453862..3d6bd16 100644 (file)
@@ -50,13 +50,7 @@ class MemcachedBagOStuff extends BagOStuff {
                ];
        }
 
-       protected function doGet( $key, $flags = 0 ) {
-               $casToken = null;
-
-               return $this->getWithToken( $key, $casToken, $flags );
-       }
-
-       protected function getWithToken( $key, &$casToken, $flags = 0 ) {
+       protected function doGet( $key, $flags = 0, &$casToken = null ) {
                return $this->client->get( $this->validateKeyEncoding( $key ), $casToken );
        }
 
@@ -91,10 +85,6 @@ class MemcachedBagOStuff extends BagOStuff {
                return ( $n !== false && $n !== null ) ? $n : false;
        }
 
-       public function merge( $key, callable $callback, $exptime = 0, $attempts = 10, $flags = 0 ) {
-               return $this->mergeViaCas( $key, $callback, $exptime, $attempts );
-       }
-
        public function changeTTL( $key, $exptime = 0, $flags = 0 ) {
                return $this->client->touch( $this->validateKeyEncoding( $key ),
                        $this->fixExpiry( $exptime ) );
@@ -185,12 +175,4 @@ class MemcachedBagOStuff extends BagOStuff {
                }
                return (int)$expiry;
        }
-
-       /**
-        * Send a debug message to the log
-        * @param string $text
-        */
-       protected function debugLog( $text ) {
-               $this->logger->debug( $text );
-       }
 }
index 1cc07b7..937ca55 100644 (file)
@@ -255,8 +255,6 @@ class MemcachedClient {
         * Memcache initializer
         *
         * @param array $args Associative array of settings
-        *
-        * @return mixed
         */
        public function __construct( $args ) {
                $this->set_servers( $args['servers'] ?? array() );
index 62a57b6..db94503 100644 (file)
@@ -138,8 +138,11 @@ class MemcachedPeclBagOStuff extends MemcachedBagOStuff {
                return $params;
        }
 
-       protected function getWithToken( $key, &$casToken, $flags = 0 ) {
-               $this->debugLog( "get($key)" );
+       /**
+        * @suppress PhanTypeNonVarPassByRef
+        */
+       protected function doGet( $key, $flags = 0, &$casToken = null ) {
+               $this->debug( "get($key)" );
                if ( defined( Memcached::class . '::GET_EXTENDED' ) ) { // v3.0.0
                        $flags = Memcached::GET_EXTENDED;
                        $res = $this->client->get( $this->validateKeyEncoding( $key ), null, $flags );
@@ -158,7 +161,7 @@ class MemcachedPeclBagOStuff extends MemcachedBagOStuff {
        }
 
        public function set( $key, $value, $exptime = 0, $flags = 0 ) {
-               $this->debugLog( "set($key)" );
+               $this->debug( "set($key)" );
                $result = parent::set( $key, $value, $exptime, $flags = 0 );
                if ( $result === false && $this->client->getResultCode() === Memcached::RES_NOTSTORED ) {
                        // "Not stored" is always used as the mcrouter response with AllAsyncRoute
@@ -168,12 +171,12 @@ class MemcachedPeclBagOStuff extends MemcachedBagOStuff {
        }
 
        protected function cas( $casToken, $key, $value, $exptime = 0, $flags = 0 ) {
-               $this->debugLog( "cas($key)" );
+               $this->debug( "cas($key)" );
                return $this->checkResult( $key, parent::cas( $casToken, $key, $value, $exptime, $flags ) );
        }
 
        public function delete( $key, $flags = 0 ) {
-               $this->debugLog( "delete($key)" );
+               $this->debug( "delete($key)" );
                $result = parent::delete( $key );
                if ( $result === false && $this->client->getResultCode() === Memcached::RES_NOTFOUND ) {
                        // "Not found" is counted as success in our interface
@@ -183,18 +186,18 @@ class MemcachedPeclBagOStuff extends MemcachedBagOStuff {
        }
 
        public function add( $key, $value, $exptime = 0, $flags = 0 ) {
-               $this->debugLog( "add($key)" );
+               $this->debug( "add($key)" );
                return $this->checkResult( $key, parent::add( $key, $value, $exptime ) );
        }
 
        public function incr( $key, $value = 1 ) {
-               $this->debugLog( "incr($key)" );
+               $this->debug( "incr($key)" );
                $result = $this->client->increment( $key, $value );
                return $this->checkResult( $key, $result );
        }
 
        public function decr( $key, $value = 1 ) {
-               $this->debugLog( "decr($key)" );
+               $this->debug( "decr($key)" );
                $result = $this->client->decrement( $key, $value );
                return $this->checkResult( $key, $result );
        }
@@ -220,7 +223,7 @@ class MemcachedPeclBagOStuff extends MemcachedBagOStuff {
                        case Memcached::RES_DATA_EXISTS:
                        case Memcached::RES_NOTSTORED:
                        case Memcached::RES_NOTFOUND:
-                               $this->debugLog( "result: " . $this->client->getResultMessage() );
+                               $this->debug( "result: " . $this->client->getResultMessage() );
                                break;
                        default:
                                $msg = $this->client->getResultMessage();
@@ -240,7 +243,7 @@ class MemcachedPeclBagOStuff extends MemcachedBagOStuff {
        }
 
        public function getMulti( array $keys, $flags = 0 ) {
-               $this->debugLog( 'getMulti(' . implode( ', ', $keys ) . ')' );
+               $this->debug( 'getMulti(' . implode( ', ', $keys ) . ')' );
                foreach ( $keys as $key ) {
                        $this->validateKeyEncoding( $key );
                }
@@ -249,7 +252,7 @@ class MemcachedPeclBagOStuff extends MemcachedBagOStuff {
        }
 
        public function setMulti( array $data, $exptime = 0, $flags = 0 ) {
-               $this->debugLog( 'setMulti(' . implode( ', ', array_keys( $data ) ) . ')' );
+               $this->debug( 'setMulti(' . implode( ', ', array_keys( $data ) ) . ')' );
                foreach ( array_keys( $data ) as $key ) {
                        $this->validateKeyEncoding( $key );
                }
@@ -258,7 +261,7 @@ class MemcachedPeclBagOStuff extends MemcachedBagOStuff {
        }
 
        public function changeTTL( $key, $expiry = 0, $flags = 0 ) {
-               $this->debugLog( "touch($key)" );
+               $this->debug( "touch($key)" );
                $result = $this->client->touch( $key, $expiry );
                return $this->checkResult( $key, $result );
        }
index 5cf9de4..1ed91ea 100644 (file)
@@ -27,6 +27,9 @@ use Wikimedia\ObjectFactory;
  * are implemented by reading from the caches in the order they are given in
  * the configuration until a cache gives a positive result.
  *
+ * Note that cache key construction will use the first cache backend in the list,
+ * so make sure that the other backends can handle such keys (e.g. via encoding).
+ *
  * @ingroup Cache
  */
 class MultiWriteBagOStuff extends BagOStuff {
@@ -100,11 +103,11 @@ class MultiWriteBagOStuff extends BagOStuff {
                }
        }
 
-       protected function doGet( $key, $flags = 0 ) {
+       public function get( $key, $flags = 0 ) {
                if ( ( $flags & self::READ_LATEST ) == self::READ_LATEST ) {
                        // If the latest write was a delete(), we do NOT want to fallback
                        // to the other tiers and possibly see the old value. Also, this
-                       // is used by mergeViaLock(), which only needs to hit the primary.
+                       // is used by merge(), which only needs to hit the primary.
                        return $this->caches[0]->get( $key, $flags );
                }
 
@@ -124,7 +127,10 @@ class MultiWriteBagOStuff extends BagOStuff {
                ) {
                        // Backfill the value to the higher (and often faster/smaller) cache tiers
                        $this->doWrite(
-                               $missIndexes, $this->asyncWrites, 'set', $key, $value, self::UPGRADE_TTL
+                               $missIndexes,
+                               $this->asyncWrites,
+                               'set',
+                               [ $key, $value, self::UPGRADE_TTL ]
                        );
                }
 
@@ -132,59 +138,62 @@ class MultiWriteBagOStuff extends BagOStuff {
        }
 
        public function set( $key, $value, $exptime = 0, $flags = 0 ) {
-               $asyncWrites = ( ( $flags & self::WRITE_SYNC ) == self::WRITE_SYNC )
-                       ? false
-                       : $this->asyncWrites;
-
-               return $this->doWrite( $this->cacheIndexes, $asyncWrites, 'set', $key, $value, $exptime );
+               return $this->doWrite(
+                       $this->cacheIndexes,
+                       $this->usesAsyncWritesGivenFlags( $flags ),
+                       __FUNCTION__,
+                       func_get_args()
+               );
        }
 
        public function delete( $key, $flags = 0 ) {
-               return $this->doWrite( $this->cacheIndexes, $this->asyncWrites, 'delete', $key );
+               return $this->doWrite(
+                       $this->cacheIndexes,
+                       $this->usesAsyncWritesGivenFlags( $flags ),
+                       __FUNCTION__,
+                       func_get_args()
+               );
        }
 
        public function add( $key, $value, $exptime = 0, $flags = 0 ) {
                // Try the write to the top-tier cache
-               $ok = $this->doWrite( [ 0 ], $this->asyncWrites, 'add', $key, $value, $exptime );
+               $ok = $this->doWrite(
+                       [ 0 ],
+                       $this->usesAsyncWritesGivenFlags( $flags ),
+                       __FUNCTION__,
+                       func_get_args()
+               );
+
                if ( $ok ) {
                        // Relay the add() using set() if it succeeded. This is meant to handle certain
                        // migration scenarios where the same store might get written to twice for certain
                        // keys. In that case, it does not make sense to return false due to "self-conflicts".
                        return $this->doWrite(
                                array_slice( $this->cacheIndexes, 1 ),
-                               $this->asyncWrites,
+                               $this->usesAsyncWritesGivenFlags( $flags ),
                                'set',
-                               $key,
-                               $value,
-                               $exptime
+                               [ $key, $value, $exptime, $flags ]
                        );
                }
 
                return false;
        }
 
-       public function incr( $key, $value = 1 ) {
-               return $this->doWrite( $this->cacheIndexes, $this->asyncWrites, 'incr', $key, $value );
-       }
-
-       public function decr( $key, $value = 1 ) {
-               return $this->doWrite( $this->cacheIndexes, $this->asyncWrites, 'decr', $key, $value );
-       }
-
        public function merge( $key, callable $callback, $exptime = 0, $attempts = 10, $flags = 0 ) {
-               $asyncWrites = ( ( $flags & self::WRITE_SYNC ) == self::WRITE_SYNC )
-                       ? false
-                       : $this->asyncWrites;
+               return $this->doWrite(
+                       $this->cacheIndexes,
+                       $this->usesAsyncWritesGivenFlags( $flags ),
+                       __FUNCTION__,
+                       func_get_args()
+               );
+       }
 
+       public function changeTTL( $key, $exptime = 0, $flags = 0 ) {
                return $this->doWrite(
                        $this->cacheIndexes,
-                       $asyncWrites,
-                       'merge',
-                       $key,
-                       $callback,
-                       $exptime,
-                       $attempts,
-                       $flags
+                       $this->usesAsyncWritesGivenFlags( $flags ),
+                       __FUNCTION__,
+                       func_get_args()
                );
        }
 
@@ -198,6 +207,83 @@ class MultiWriteBagOStuff extends BagOStuff {
                return $this->caches[0]->unlock( $key );
        }
 
+       /**
+        * Delete objects expiring before a certain date.
+        *
+        * Succeed if any of the child caches succeed.
+        * @param string $date
+        * @param bool|callable $progressCallback
+        * @return bool
+        */
+       public function deleteObjectsExpiringBefore( $date, $progressCallback = false ) {
+               $ret = false;
+               foreach ( $this->caches as $cache ) {
+                       if ( $cache->deleteObjectsExpiringBefore( $date, $progressCallback ) ) {
+                               $ret = true;
+                       }
+               }
+
+               return $ret;
+       }
+
+       public function getMulti( array $keys, $flags = 0 ) {
+               // Just iterate over each key in order to handle all the backfill logic
+               $res = [];
+               foreach ( $keys as $key ) {
+                       $val = $this->get( $key, $flags );
+                       if ( $val !== false ) {
+                               $res[$key] = $val;
+                       }
+               }
+
+               return $res;
+       }
+
+       public function setMulti( array $data, $exptime = 0, $flags = 0 ) {
+               return $this->doWrite(
+                       $this->cacheIndexes,
+                       $this->usesAsyncWritesGivenFlags( $flags ),
+                       __FUNCTION__,
+                       func_get_args()
+               );
+       }
+
+       public function deleteMulti( array $data, $flags = 0 ) {
+               return $this->doWrite(
+                       $this->cacheIndexes,
+                       $this->usesAsyncWritesGivenFlags( $flags ),
+                       __FUNCTION__,
+                       func_get_args()
+               );
+       }
+
+       public function incr( $key, $value = 1 ) {
+               return $this->doWrite(
+                       $this->cacheIndexes,
+                       $this->asyncWrites,
+                       __FUNCTION__,
+                       func_get_args()
+               );
+       }
+
+       public function decr( $key, $value = 1 ) {
+               return $this->doWrite(
+                       $this->cacheIndexes,
+                       $this->asyncWrites,
+                       __FUNCTION__,
+                       func_get_args()
+               );
+       }
+
+       public function incrWithInit( $key, $ttl, $value = 1, $init = 1 ) {
+               return $this->doWrite(
+                       $this->cacheIndexes,
+                       $this->asyncWrites,
+                       __FUNCTION__,
+                       func_get_args()
+               );
+       }
+
        public function getLastError() {
                return $this->caches[0]->getLastError();
        }
@@ -211,13 +297,12 @@ class MultiWriteBagOStuff extends BagOStuff {
         *
         * @param int[] $indexes List of backing cache indexes
         * @param bool $asyncWrites
-        * @param string $method
-        * @param mixed $args,...
+        * @param string $method Method name of backing caches
+        * @param array[] $args Arguments to the method of backing caches
         * @return bool
         */
-       protected function doWrite( $indexes, $asyncWrites, $method /*, ... */ ) {
+       protected function doWrite( $indexes, $asyncWrites, $method, array $args ) {
                $ret = true;
-               $args = array_slice( func_get_args(), 3 );
 
                if ( array_diff( $indexes, [ 0 ] ) && $asyncWrites && $method !== 'merge' ) {
                        // Deep-clone $args to prevent misbehavior when something writes an
@@ -249,22 +334,11 @@ class MultiWriteBagOStuff extends BagOStuff {
        }
 
        /**
-        * Delete objects expiring before a certain date.
-        *
-        * Succeed if any of the child caches succeed.
-        * @param string $date
-        * @param bool|callable $progressCallback
+        * @param int $flags
         * @return bool
         */
-       public function deleteObjectsExpiringBefore( $date, $progressCallback = false ) {
-               $ret = false;
-               foreach ( $this->caches as $cache ) {
-                       if ( $cache->deleteObjectsExpiringBefore( $date, $progressCallback ) ) {
-                               $ret = true;
-                       }
-               }
-
-               return $ret;
+       protected function usesAsyncWritesGivenFlags( $flags ) {
+               return ( ( $flags & self::WRITE_SYNC ) == self::WRITE_SYNC ) ? false : $this->asyncWrites;
        }
 
        public function makeKeyInternal( $keyspace, $args ) {
@@ -278,4 +352,8 @@ class MultiWriteBagOStuff extends BagOStuff {
        public function makeGlobalKey( $class, $component = null ) {
                return $this->caches[0]->makeGlobalKey( ...func_get_args() );
        }
+
+       protected function doGet( $key, $flags = 0, &$casToken = null ) {
+               throw new LogicException( __METHOD__ . ': proxy class does not need this method.' );
+       }
 }
index c127ec6..a10d1a4 100644 (file)
@@ -7,26 +7,42 @@ use Psr\Log\LoggerInterface;
  *
  * Uses URL of the form "baseURL/{KEY}" to store, fetch, and delete values.
  *
- * E.g., when base URL is `/v1/sessions/`, then the store would do:
+ * E.g., when base URL is `/sessions/v1`, then the store would do:
  *
- * `PUT /v1/sessions/12345758`
+ * `PUT /sessions/v1/12345758`
  *
  * and fetch would do:
  *
- * `GET /v1/sessions/12345758`
+ * `GET /sessions/v1/12345758`
  *
  * delete would do:
  *
- * `DELETE /v1/sessions/12345758`
+ * `DELETE /sessions/v1/12345758`
  *
- * Configure with:
+ * Minimal generic configuration:
  *
  * @code
  * $wgObjectCaches['sessions'] = array(
  *     'class' => 'RESTBagOStuff',
- *     'url' => 'http://localhost:7231/wikimedia.org/v1/sessions/'
+ *     'url' => 'http://localhost:7231/wikimedia.org/somepath/'
  * );
  * @endcode
+ *
+ * Configuration for Kask (session storage):
+ * @code
+ * $wgObjectCaches['sessions'] = array(
+ *     'class' => 'RESTBagOStuff',
+ *     'url' => 'https://kaskhost:1234/sessions/v1/',
+ *     'httpParams' => [
+ *             'readHeaders' => [],
+ *             'writeHeaders' => [ 'content-type' => 'application/octet-stream' ],
+ *             'deleteHeaders' => [],
+ *             'writeMethod' => 'POST',
+ *     ],
+ *     'extendedErrorBodyFields' => [ 'type', 'title', 'detail', 'instance' ]
+ * );
+ * $wgSessionCacheType = 'sessions';
+ * @endcode
  */
 class RESTBagOStuff extends BagOStuff {
        /**
@@ -52,10 +68,21 @@ class RESTBagOStuff extends BagOStuff {
         */
        private $url;
 
+       /**
+        * @var array http parameters: readHeaders, writeHeaders, deleteHeaders, writeMethod
+        */
+       private $httpParams;
+
+       /**
+        * @var array additional body fields to log on error, if possible
+        */
+       private $extendedErrorBodyFields;
+
        public function __construct( $params ) {
                if ( empty( $params['url'] ) ) {
                        throw new InvalidArgumentException( 'URL parameter is required' );
                }
+
                if ( empty( $params['client'] ) ) {
                        // Pass through some params to the HTTP client.
                        $clientParams = [
@@ -71,10 +98,19 @@ class RESTBagOStuff extends BagOStuff {
                } else {
                        $this->client = $params['client'];
                }
+
+               $this->httpParams['writeMethod'] = $params['httpParams']['writeMethod'] ?? 'PUT';
+               $this->httpParams['readHeaders'] = $params['httpParams']['readHeaders'] ?? [];
+               $this->httpParams['writeHeaders'] = $params['httpParams']['writeHeaders'] ?? [];
+               $this->httpParams['deleteHeaders'] = $params['httpParams']['deleteHeaders'] ?? [];
+               $this->extendedErrorBodyFields = $params['extendedErrorBodyFields'] ?? [];
+
                // The parent constructor calls setLogger() which sets the logger in $this->client
                parent::__construct( $params );
+
                // Make sure URL ends with /
                $this->url = rtrim( $params['url'], '/' ) . '/';
+
                // Default config, R+W > N; no locks on reads though; writes go straight to state-machine
                $this->attrMap[self::ATTR_SYNCWRITES] = self::QOS_SYNCWRITES_QC;
        }
@@ -84,59 +120,47 @@ class RESTBagOStuff extends BagOStuff {
                $this->client->setLogger( $logger );
        }
 
-       /**
-        * @param string $key
-        * @param int $flags Bitfield of BagOStuff::READ_* constants [optional]
-        * @return mixed Returns false on failure and if the item does not exist
-        */
-       protected function doGet( $key, $flags = 0 ) {
+       protected function doGet( $key, $flags = 0, &$casToken = null ) {
+               $casToken = null;
+
                $req = [
                        'method' => 'GET',
                        'url' => $this->url . rawurlencode( $key ),
+                       'headers' => $this->httpParams['readHeaders'],
                ];
 
                list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $this->client->run( $req );
                if ( $rcode === 200 ) {
                        if ( is_string( $rbody ) ) {
-                               return unserialize( $rbody );
+                               $value = $this->decodeBody( $rbody );
+                               /// @FIXME: use some kind of hash or UUID header as CAS token
+                               $casToken = ( $value !== false ) ? $rbody : null;
+
+                               return $value;
                        }
                        return false;
                }
                if ( $rcode === 0 || ( $rcode >= 400 && $rcode != 404 ) ) {
-                       return $this->handleError( "Failed to fetch $key", $rcode, $rerr );
+                       return $this->handleError( "Failed to fetch $key", $rcode, $rerr, $rhdrs, $rbody );
                }
                return false;
        }
 
-       /**
-        * Handle storage error
-        * @param string $msg Error message
-        * @param int $rcode Error code from client
-        * @param string $rerr Error message from client
-        * @return false
-        */
-       protected function handleError( $msg, $rcode, $rerr ) {
-               $this->logger->error( "$msg : ({code}) {error}", [
-                       'code' => $rcode,
-                       'error' => $rerr
-               ] );
-               $this->setLastError( $rcode === 0 ? self::ERR_UNREACHABLE : self::ERR_UNEXPECTED );
-               return false;
-       }
-
        public function set( $key, $value, $exptime = 0, $flags = 0 ) {
                // @TODO: respect WRITE_SYNC (e.g. EACH_QUORUM)
                // @TODO: respect $exptime
                $req = [
-                       'method' => 'PUT',
+                       'method' => $this->httpParams['writeMethod'],
                        'url' => $this->url . rawurlencode( $key ),
-                       'body' => serialize( $value )
+                       'body' => $this->encodeBody( $value ),
+                       'headers' => $this->httpParams['writeHeaders'],
                ];
+
                list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $this->client->run( $req );
                if ( $rcode === 200 || $rcode === 201 || $rcode === 204 ) {
                        return true;
                }
-               return $this->handleError( "Failed to store $key", $rcode, $rerr );
+               return $this->handleError( "Failed to store $key", $rcode, $rerr, $rhdrs, $rbody );
        }
 
        public function add( $key, $value, $exptime = 0, $flags = 0 ) {
@@ -153,12 +177,14 @@ class RESTBagOStuff extends BagOStuff {
                $req = [
                        'method' => 'DELETE',
                        'url' => $this->url . rawurlencode( $key ),
+                       'headers' => $this->httpParams['deleteHeaders'],
                ];
+
                list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $this->client->run( $req );
                if ( in_array( $rcode, [ 200, 204, 205, 404, 410 ] ) ) {
                        return true;
                }
-               return $this->handleError( "Failed to delete $key", $rcode, $rerr );
+               return $this->handleError( "Failed to delete $key", $rcode, $rerr, $rhdrs, $rbody );
        }
 
        public function incr( $key, $value = 1 ) {
@@ -172,4 +198,67 @@ class RESTBagOStuff extends BagOStuff {
 
                return false;
        }
+
+       /**
+        * Processes the response body.
+        *
+        * @param string $body request body to process
+        * @return mixed|bool the processed body, or false on error
+        */
+       private function decodeBody( $body ) {
+               $value = json_decode( $body, true );
+               return ( json_last_error() === JSON_ERROR_NONE ) ? $value : false;
+       }
+
+       /**
+        * Prepares the request body (the "value" portion of our key/value store) for transmission.
+        *
+        * @param string $body request body to prepare
+        * @return string the prepared body, or an empty string on error
+        * @throws LogicException
+        */
+       private function encodeBody( $body ) {
+               $value = json_encode( $body );
+               if ( $value === false ) {
+                       throw new InvalidArgumentException( __METHOD__ . ": body could not be encoded." );
+               }
+               return $value;
+       }
+
+       /**
+        * Handle storage error
+        * @param string $msg Error message
+        * @param int $rcode Error code from client
+        * @param string $rerr Error message from client
+        * @param array $rhdrs Response headers
+        * @param string $rbody Error body from client (if any)
+        * @return false
+        */
+       protected function handleError( $msg, $rcode, $rerr, $rhdrs, $rbody ) {
+               $message = "$msg : ({code}) {error}";
+               $context = [
+                       'code' => $rcode,
+                       'error' => $rerr
+               ];
+
+               if ( $this->extendedErrorBodyFields !== [] ) {
+                       $body = $this->decodeBody( $rbody );
+                       if ( $body ) {
+                               $extraFields = '';
+                               foreach ( $this->extendedErrorBodyFields as $field ) {
+                                       if ( isset( $body[$field] ) ) {
+                                               $extraFields .= " : ({$field}) {$body[$field]}";
+                                       }
+                               }
+                               if ( $extraFields !== '' ) {
+                                       $message .= " {extra_fields}";
+                                       $context['extra_fields'] = $extraFields;
+                               }
+                       }
+               }
+
+               $this->logger->error( $message, $context );
+               $this->setLastError( $rcode === 0 ? self::ERR_UNREACHABLE : self::ERR_UNEXPECTED );
+               return false;
+       }
 }
index f64fe7e..2c74d45 100644 (file)
@@ -86,13 +86,9 @@ class RedisBagOStuff extends BagOStuff {
                $this->attrMap[self::ATTR_SYNCWRITES] = self::QOS_SYNCWRITES_NONE;
        }
 
-       protected function doGet( $key, $flags = 0 ) {
+       protected function doGet( $key, $flags = 0, &$casToken = null ) {
                $casToken = null;
 
-               return $this->getWithToken( $key, $casToken, $flags );
-       }
-
-       protected function getWithToken( $key, &$casToken, $flags = 0 ) {
                list( $server, $conn ) = $this->getConnection( $key );
                if ( !$conn ) {
                        return false;
@@ -297,10 +293,6 @@ class RedisBagOStuff extends BagOStuff {
                return $result;
        }
 
-       public function merge( $key, callable $callback, $exptime = 0, $attempts = 10, $flags = 0 ) {
-               return $this->mergeViaCas( $key, $callback, $exptime, $attempts );
-       }
-
        /**
         * Non-atomic implementation of incr().
         *
@@ -333,21 +325,29 @@ class RedisBagOStuff extends BagOStuff {
                return $result;
        }
 
-       public function changeTTL( $key, $expiry = 0, $flags = 0 ) {
+       public function changeTTL( $key, $exptime = 0, $flags = 0 ) {
                list( $server, $conn ) = $this->getConnection( $key );
                if ( !$conn ) {
                        return false;
                }
 
-               $expiry = $this->convertToRelative( $expiry );
+               $relative = $this->expiryIsRelative( $exptime );
                try {
-                       $result = $conn->expire( $key, $expiry );
+                       if ( $exptime == 0 ) {
+                               $result = $conn->persist( $key );
+                               $this->logRequest( 'persist', $key, $server, $result );
+                       } elseif ( $relative ) {
+                               $result = $conn->expire( $key, $this->convertToRelative( $exptime ) );
+                               $this->logRequest( 'expire', $key, $server, $result );
+                       } else {
+                               $result = $conn->expireAt( $key, $this->convertToExpiry( $exptime ) );
+                               $this->logRequest( 'expireAt', $key, $server, $result );
+                       }
                } catch ( RedisException $e ) {
                        $result = false;
                        $this->handleException( $conn, $e );
                }
 
-               $this->logRequest( 'expire', $key, $server, $result );
                return $result;
        }
 
index 14e2fef..70f9096 100644 (file)
@@ -74,44 +74,30 @@ class ReplicatedBagOStuff extends BagOStuff {
                $this->readStore->setDebug( $debug );
        }
 
-       protected function doGet( $key, $flags = 0 ) {
+       public function get( $key, $flags = 0 ) {
                return ( $flags & self::READ_LATEST )
                        ? $this->writeStore->get( $key, $flags )
                        : $this->readStore->get( $key, $flags );
        }
 
-       public function getMulti( array $keys, $flags = 0 ) {
-               return ( $flags & self::READ_LATEST )
-                       ? $this->writeStore->getMulti( $keys, $flags )
-                       : $this->readStore->getMulti( $keys, $flags );
-       }
-
        public function set( $key, $value, $exptime = 0, $flags = 0 ) {
                return $this->writeStore->set( $key, $value, $exptime, $flags );
        }
 
-       public function setMulti( array $keys, $exptime = 0, $flags = 0 ) {
-               return $this->writeStore->setMulti( $keys, $exptime, $flags );
-       }
-
        public function delete( $key, $flags = 0 ) {
                return $this->writeStore->delete( $key, $flags );
        }
 
-       public function deleteMulti( array $keys, $flags = 0 ) {
-               return $this->writeStore->deleteMulti( $keys, $flags );
-       }
-
        public function add( $key, $value, $exptime = 0, $flags = 0 ) {
                return $this->writeStore->add( $key, $value, $exptime, $flags );
        }
 
-       public function incr( $key, $value = 1 ) {
-               return $this->writeStore->incr( $key, $value );
+       public function merge( $key, callable $callback, $exptime = 0, $attempts = 10, $flags = 0 ) {
+               return $this->writeStore->merge( $key, $callback, $exptime, $attempts, $flags );
        }
 
-       public function decr( $key, $value = 1 ) {
-               return $this->writeStore->decr( $key, $value );
+       public function changeTTL( $key, $exptime = 0, $flags = 0 ) {
+               return $this->writeStore->changeTTL( $key, $exptime, $flags );
        }
 
        public function lock( $key, $timeout = 6, $expiry = 6, $rclass = '' ) {
@@ -122,8 +108,34 @@ class ReplicatedBagOStuff extends BagOStuff {
                return $this->writeStore->unlock( $key );
        }
 
-       public function merge( $key, callable $callback, $exptime = 0, $attempts = 10, $flags = 0 ) {
-               return $this->writeStore->merge( $key, $callback, $exptime, $attempts, $flags );
+       public function deleteObjectsExpiringBefore( $date, $progressCallback = false ) {
+               return $this->writeStore->deleteObjectsExpiringBefore( $date, $progressCallback );
+       }
+
+       public function getMulti( array $keys, $flags = 0 ) {
+               return ( ( $flags & self::READ_LATEST ) == self::READ_LATEST )
+                       ? $this->writeStore->getMulti( $keys, $flags )
+                       : $this->readStore->getMulti( $keys, $flags );
+       }
+
+       public function setMulti( array $data, $exptime = 0, $flags = 0 ) {
+               return $this->writeStore->setMulti( $data, $exptime, $flags );
+       }
+
+       public function deleteMulti( array $keys, $flags = 0 ) {
+               return $this->writeStore->deleteMulti( $keys, $flags );
+       }
+
+       public function incr( $key, $value = 1 ) {
+               return $this->writeStore->incr( $key, $value );
+       }
+
+       public function decr( $key, $value = 1 ) {
+               return $this->writeStore->decr( $key, $value );
+       }
+
+       public function incrWithInit( $key, $ttl, $value = 1, $init = 1 ) {
+               return $this->writeStore->incrWithInit( $key, $ttl, $value, $init );
        }
 
        public function getLastError() {
@@ -148,4 +160,8 @@ class ReplicatedBagOStuff extends BagOStuff {
        public function makeGlobalKey( $class, $component = null ) {
                return $this->writeStore->makeGlobalKey( ...func_get_args() );
        }
+
+       protected function doGet( $key, $flags = 0, &$casToken = null ) {
+               throw new LogicException( __METHOD__ . ': proxy class does not need this method.' );
+       }
 }
index 9fbad39..dac3421 100644 (file)
@@ -194,8 +194,8 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
        /** Tiny positive float to use when using "minTime" to assert an inequality */
        const TINY_POSTIVE = 0.000001;
 
-       /** Seconds of delay after get() where set() storms are a consideration with 'lockTSE' */
-       const SET_DELAY_HIGH_SEC = 0.1;
+       /** Milliseconds of delay after get() where set() storms are a consideration with 'lockTSE' */
+       const SET_DELAY_HIGH_MS = 50;
        /** Min millisecond set() backoff for keys in hold-off (far less than INTERIM_KEY_TTL) */
        const RECENT_SET_LOW_MS = 50;
        /** Max millisecond set() backoff for keys in hold-off (far less than INTERIM_KEY_TTL) */
@@ -320,7 +320,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
         *   - tombAsOf: UNIX timestamp of the tombstone or null if the key is not tombstoned
         *   - lastCKPurge: UNIX timestamp of the highest check key or null if none provided
         *
-        * Othwerwise, $info will transform into the cached value timestamp.
+        * Otherwise, $info will transform into the cached value timestamp.
         *
         * @param string $key Cache key made from makeKey() or makeGlobalKey()
         * @param mixed|null &$curTTL Approximate TTL left on the key if present/tombstoned [returned]
@@ -521,31 +521,34 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
         * @param int $ttl Seconds to live. Special values are:
         *   - WANObjectCache::TTL_INDEFINITE: Cache forever (default)
         * @param array $opts Options map:
-        *   - lag : Seconds of replica DB lag. Typically, this is either the replica DB lag
+        *   - lag: seconds of replica DB lag. Typically, this is either the replica DB lag
         *      before the data was read or, if applicable, the replica DB lag before
         *      the snapshot-isolated transaction the data was read from started.
         *      Use false to indicate that replication is not running.
         *      Default: 0 seconds
-        *   - since : UNIX timestamp of the data in $value. Typically, this is either
+        *   - since: UNIX timestamp of the data in $value. Typically, this is either
         *      the current time the data was read or (if applicable) the time when
         *      the snapshot-isolated transaction the data was read from started.
         *      Default: 0 seconds
-        *   - pending : Whether this data is possibly from an uncommitted write transaction.
+        *   - pending: whether this data is possibly from an uncommitted write transaction.
         *      Generally, other threads should not see values from the future and
         *      they certainly should not see ones that ended up getting rolled back.
         *      Default: false
-        *   - lockTSE : if excessive replication/snapshot lag is detected, then store the value
+        *   - lockTSE: if excessive replication/snapshot lag is detected, then store the value
         *      with this TTL and flag it as stale. This is only useful if the reads for this key
         *      use getWithSetCallback() with "lockTSE" set. Note that if "staleTTL" is set
         *      then it will still add on to this TTL in the excessive lag scenario.
         *      Default: WANObjectCache::TSE_NONE
-        *   - staleTTL : Seconds to keep the key around if it is stale. The get()/getMulti()
+        *   - staleTTL: seconds to keep the key around if it is stale. The get()/getMulti()
         *      methods return such stale values with a $curTTL of 0, and getWithSetCallback()
         *      will call the regeneration callback in such cases, passing in the old value
         *      and its as-of time to the callback. This is useful if adaptiveTTL() is used
         *      on the old value's as-of time when it is verified as still being correct.
         *      Default: WANObjectCache::STALE_TTL_NONE.
+        *   - creating: optimize for the case where the key does not already exist.
+        *      Default: false
         * @note Options added in 1.28: staleTTL
+        * @note Options added in 1.33: creating
         * @return bool Success
         */
        final public function set( $key, $value, $ttl = self::TTL_INDEFINITE, array $opts = [] ) {
@@ -553,6 +556,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
                $lockTSE = $opts['lockTSE'] ?? self::TSE_NONE;
                $staleTTL = $opts['staleTTL'] ?? self::STALE_TTL_NONE;
                $age = isset( $opts['since'] ) ? max( 0, $now - $opts['since'] ) : 0;
+               $creating = $opts['creating'] ?? false;
                $lag = $opts['lag'] ?? 0;
 
                // Do not cache potentially uncommitted data as it might get rolled back
@@ -597,35 +601,42 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
                                        [ 'cachekey' => $key, 'lag' => $lag, 'age' => $age ]
                                );
                        // Case C: medium length request with medium replication lag
+                       } elseif ( $lockTSE >= 0 ) {
+                               // Store value as *almost* stale to avoid cache and mutex stampedes
+                               $logicalTTL = self::TTL_SECOND;
+                               $this->logger->info(
+                                       'Lowered set() TTL for {cachekey} due to high read lag.',
+                                       [ 'cachekey' => $key, 'lag' => $lag, 'age' => $age ]
+                               );
                        } else {
-                               if ( $lockTSE >= 0 ) {
-                                       // Store value as *almost* stale to avoid cache and mutex stampedes
-                                       $logicalTTL = self::TTL_SECOND;
-                                       $this->logger->info(
-                                               'Lowered set() TTL for {cachekey} due to high read lag.',
-                                               [ 'cachekey' => $key, 'lag' => $lag, 'age' => $age ]
-                                       );
-                               } else {
-                                       $this->logger->info(
-                                               'Rejected set() for {cachekey} due to high read lag.',
-                                               [ 'cachekey' => $key, 'lag' => $lag, 'age' => $age ]
-                                       );
+                               $this->logger->info(
+                                       'Rejected set() for {cachekey} due to high read lag.',
+                                       [ 'cachekey' => $key, 'lag' => $lag, 'age' => $age ]
+                               );
 
-                                       return true; // no-op the write for being unsafe
-                               }
+                               return true; // no-op the write for being unsafe
                        }
                }
 
                // Wrap that value with time/TTL/version metadata
                $wrapped = $this->wrap( $value, $logicalTTL ?: $ttl, $now );
+               $storeTTL = $ttl + $staleTTL;
 
-               $func = function ( $cache, $key, $cWrapped ) use ( $wrapped ) {
-                       return ( is_string( $cWrapped ) )
-                               ? false // key is tombstoned; do nothing
-                               : $wrapped;
-               };
+               if ( $creating ) {
+                       $ok = $this->cache->add( self::VALUE_KEY_PREFIX . $key, $wrapped, $storeTTL );
+               } else {
+                       $ok = $this->cache->merge(
+                               self::VALUE_KEY_PREFIX . $key,
+                               function ( $cache, $key, $cWrapped ) use ( $wrapped ) {
+                                       // A string value means that it is a tombstone; do nothing in that case
+                                       return ( is_string( $cWrapped ) ) ? false : $wrapped;
+                               },
+                               $storeTTL,
+                               1 // 1 attempt
+                       );
+               }
 
-               return $this->cache->merge( self::VALUE_KEY_PREFIX . $key, $func, $ttl + $staleTTL, 1 );
+               return $ok;
        }
 
        /**
@@ -1124,7 +1135,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
         *      stampede is worth avoiding. Note that if the key falls out of cache then concurrent
         *      threads will all run the callback on cache miss until the value is saved in cache.
         *      The only stampede protection in that case is from duplicate cache sets when the
-        *      callback takes longer than WANObjectCache::SET_DELAY_HIGH_SEC seconds; consider
+        *      callback takes longer than WANObjectCache::SET_DELAY_HIGH_MS milliseconds; consider
         *      using "busyValue" if such stampedes are a problem. Note that the higher "lockTSE" is
         *      set, the higher the worst-case staleness of returned values can be. Also note that
         *      this option does not by itself handle the case of the key simply expiring on account
@@ -1150,10 +1161,17 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
         *      It is generally preferable to use a class constant when setting this value.
         *      This has no effect unless pcTTL is used.
         *      Default: WANObjectCache::PC_PRIMARY.
-        *   - version: Integer version number. This allows for callers to make breaking changes to
-        *      how values are stored while maintaining compatability and correct cache purges. New
-        *      versions are stored alongside older versions concurrently. Avoid storing class objects
-        *      however, as this reduces compatibility (due to serialization).
+        *   - version: Integer version number. This lets callers make breaking changes to the format
+        *      of cached values without causing problems for sites that use non-instantaneous code
+        *      deployments. Old and new code will recognize incompatible versions and purges from
+        *      both old and new code will been seen by each other. When this method encounters an
+        *      incompatibly versioned value at the provided key, a "variant key" will be used for
+        *      reading from and saving to cache. The variant key is specific to the key and version
+        *      number provided to this method. If the variant key value is older than that of the
+        *      provided key, or the provided key is non-existant, then the variant key will be seen
+        *      as non-existant. Therefore, delete() calls invalidate the provided key's variant keys.
+        *      The "checkKeys" and "touchedCallback" options still apply to variant keys as usual.
+        *      Avoid storing class objects, as this reduces compatibility (due to serialization).
         *      Default: null.
         *   - minAsOf: Reject values if they were generated before this UNIX timestamp.
         *      This is useful if the source of a key is suspected of having possibly changed
@@ -1411,6 +1429,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
                                }
                        } elseif ( !$useMutex || $hasLock ) {
                                if ( $this->checkAndSetCooloff( $key, $kClass, $ago, $lockTSE, $hasLock ) ) {
+                                       $setOpts['creating'] = ( $curValue === false );
                                        // Save the value unless a lock-winning thread is already expected to do that
                                        $setOpts['lockTSE'] = $lockTSE;
                                        $setOpts['staleTTL'] = $staleTTL;
@@ -1457,7 +1476,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
                // consistent hashing).
                if ( $lockTSE < 0 || $hasLock ) {
                        return true; // either not a priori hot or thread has the lock
-               } elseif ( $elapsed <= self::SET_DELAY_HIGH_SEC ) {
+               } elseif ( $elapsed <= self::SET_DELAY_HIGH_MS * 1e3 ) {
                        return true; // not enough time for threads to pile up
                }
 
@@ -2306,7 +2325,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
         * @return string A collection name to describe this class of key
         */
        protected function determineKeyClassForStats( $key ) {
-               $parts = explode( ':', $key );
+               $parts = explode( ':', $key, 3 );
 
                return $parts[1] ?? $parts[0]; // sanity
        }
index cae0280..8c419b2 100644 (file)
  * @ingroup Cache
  */
 class WinCacheBagOStuff extends BagOStuff {
-       protected function doGet( $key, $flags = 0 ) {
-               $val = wincache_ucache_get( $key );
-               if ( is_string( $val ) ) {
-                       $val = unserialize( $val );
+       protected function doGet( $key, $flags = 0, &$casToken = null ) {
+               $casToken = null;
+
+               $blob = wincache_ucache_get( $key );
+               if ( !is_string( $blob ) ) {
+                       return false;
+               }
+
+               $value = unserialize( $blob );
+               if ( $value !== false ) {
+                       $casToken = (string)$blob; // don't bother hashing this
                }
 
-               return $val;
+               return $value;
+       }
+
+       protected function cas( $casToken, $key, $value, $exptime = 0, $flags = 0 ) {
+               if ( !wincache_lock( $key ) ) { // optimize with FIFO lock
+                       return false;
+               }
+
+               $curCasToken = null; // passed by reference
+               $this->doGet( $key, self::READ_LATEST, $curCasToken );
+               if ( $casToken === $curCasToken ) {
+                       $success = $this->set( $key, $value, $exptime, $flags );
+               } else {
+                       $this->logger->info(
+                               __METHOD__ . ' failed due to race condition for {key}.',
+                               [ 'key' => $key ]
+                       );
+
+                       $success = false; // mismatched or failed
+               }
+
+               wincache_unlock( $key );
+
+               return $success;
        }
 
        public function set( $key, $value, $expire = 0, $flags = 0 ) {
                $result = wincache_ucache_set( $key, serialize( $value ), $expire );
 
+               // false positive, wincache_ucache_set returns an empty array
+               // in some circumstances.
+               // @phan-suppress-next-line PhanTypeComparisonToArray
                return ( $result === [] || $result === true );
        }
 
        public function add( $key, $value, $exptime = 0, $flags = 0 ) {
                $result = wincache_ucache_add( $key, serialize( $value ), $exptime );
 
+               // false positive, wincache_ucache_add returns an empty array
+               // in some circumstances.
+               // @phan-suppress-next-line PhanTypeComparisonToArray
                return ( $result === [] || $result === true );
        }
 
@@ -55,17 +91,6 @@ class WinCacheBagOStuff extends BagOStuff {
                return true;
        }
 
-       public function merge( $key, callable $callback, $exptime = 0, $attempts = 10, $flags = 0 ) {
-               if ( wincache_lock( $key ) ) { // optimize with FIFO lock
-                       $ok = $this->mergeViaLock( $key, $callback, $exptime, $attempts, $flags );
-                       wincache_unlock( $key );
-               } else {
-                       $ok = false;
-               }
-
-               return $ok;
-       }
-
        /**
         * Construct a cache key.
         *
@@ -109,18 +134,20 @@ class WinCacheBagOStuff extends BagOStuff {
         * @return int|bool New value or false on failure
         */
        public function incr( $key, $value = 1 ) {
-               if ( !$this->lock( $key ) ) {
+               if ( !wincache_lock( $key ) ) { // optimize with FIFO lock
                        return false;
                }
-               $n = $this->get( $key );
-               if ( $this->isInteger( $n ) ) { // key exists?
-                       $n += intval( $value );
+
+               $n = $this->doGet( $key );
+               if ( $this->isInteger( $n ) ) {
+                       $n = max( $n + (int)$value, 0 );
                        $oldTTL = wincache_ucache_info( false, $key )["ucache_entries"][1]["ttl_seconds"];
-                       $this->set( $key, max( 0, $n ), $oldTTL );
+                       $this->set( $key, $n, $oldTTL );
                } else {
                        $n = false;
                }
-               $this->unlock( $key );
+
+               wincache_unlock( $key );
 
                return $n;
        }
index 3e71e36..fa454c8 100644 (file)
@@ -72,14 +72,20 @@ class ChronologyProtector implements LoggerAwareInterface {
 
        /**
         * @param BagOStuff $store
-        * @param array[] $client Map of (ip: <IP>, agent: <user-agent> [, clientId: <hash>] )
-        * @param int|null $posIndex Write counter index [optional]
+        * @param array $client Map of (ip: <IP>, agent: <user-agent> [, clientId: <hash>] )
+        * @param int|null $posIndex Write counter index
+        * @param string $secret Secret string for HMAC hashing [optional]
         * @since 1.27
         */
-       public function __construct( BagOStuff $store, array $client, $posIndex = null ) {
+       public function __construct( BagOStuff $store, array $client, $posIndex, $secret = '' ) {
                $this->store = $store;
-               $this->clientId = $client['clientId'] ??
-                       md5( $client['ip'] . "\n" . $client['agent'] );
+               if ( isset( $client['clientId'] ) ) {
+                       $this->clientId = $client['clientId'];
+               } else {
+                       $this->clientId = strlen( $secret )
+                               ? hash_hmac( 'md5', $client['ip'] . "\n" . $client['agent'], $secret )
+                               : md5( $client['ip'] . "\n" . $client['agent'] );
+               }
                $this->key = $store->makeGlobalKey( __CLASS__, $this->clientId, 'v2' );
                $this->waitForPosIndex = $posIndex;
 
index e4dad01..c89820d 100644 (file)
@@ -218,7 +218,7 @@ class TransactionProfiler implements LoggerAwareInterface {
         *
         * This assumes that all queries are synchronous (non-overlapping)
         *
-        * @param string $query Function name or generalized SQL
+        * @param string|GeneralizedSql $query Function name or generalized SQL
         * @param float $sTime Starting UNIX wall time
         * @param bool $isWrite Whether this is a write query
         * @param int $n Number of affected/read rows
@@ -229,11 +229,11 @@ class TransactionProfiler implements LoggerAwareInterface {
 
                if ( $isWrite && $n > $this->expect['maxAffected'] ) {
                        $this->logger->warning(
-                               "Query affected $n row(s):\n" . $query . "\n" .
+                               "Query affected $n row(s):\n" . self::queryString( $query ) . "\n" .
                                ( new RuntimeException() )->getTraceAsString() );
                } elseif ( !$isWrite && $n > $this->expect['readQueryRows'] ) {
                        $this->logger->warning(
-                               "Query returned $n row(s):\n" . $query . "\n" .
+                               "Query returned $n row(s):\n" . self::queryString( $query ) . "\n" .
                                ( new RuntimeException() )->getTraceAsString() );
                }
 
@@ -341,7 +341,8 @@ class TransactionProfiler implements LoggerAwareInterface {
                        $trace = '';
                        foreach ( $this->dbTrxMethodTimes[$name] as $i => $info ) {
                                list( $query, $sTime, $end ) = $info;
-                               $trace .= sprintf( "%d\t%.6f\t%s\n", $i, ( $end - $sTime ), $query );
+                               $trace .= sprintf(
+                                       "%d\t%.6f\t%s\n", $i, ( $end - $sTime ), self::queryString( $query ) );
                        }
                        $this->logger->warning( "Sub-optimal transaction on DB(s) [{dbs}]: \n{trace}", [
                                'dbs' => implode( ', ', array_keys( $this->dbTrxHoldingLocks[$name]['conns'] ) ),
@@ -354,7 +355,7 @@ class TransactionProfiler implements LoggerAwareInterface {
 
        /**
         * @param string $expect
-        * @param string $query
+        * @param string|GeneralizedSql $query
         * @param string|float|int $actual
         */
        protected function reportExpectationViolated( $expect, $query, $actual ) {
@@ -370,8 +371,16 @@ class TransactionProfiler implements LoggerAwareInterface {
                                'max' => $this->expect[$expect],
                                'by' => $this->expectBy[$expect],
                                'actual' => $actual,
-                               'query' => $query
+                               'query' => self::queryString( $query )
                        ]
                );
        }
+
+       /**
+        * @param GeneralizedSql|string $query
+        * @return string
+        */
+       private static function queryString( $query ) {
+               return $query instanceof GeneralizedSql ? $query->stringify() : $query;
+       }
 }
diff --git a/includes/libs/rdbms/database/AtomicSectionIdentifier.php b/includes/libs/rdbms/database/AtomicSectionIdentifier.php
deleted file mode 100644 (file)
index c6e3d44..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Database
- */
-namespace Wikimedia\Rdbms;
-
-/**
- * Class used for token representing identifiers for atomic sections from IDatabase instances
- */
-class AtomicSectionIdentifier {
-}
index 4fdac81..b216892 100644 (file)
@@ -8,7 +8,6 @@ use InvalidArgumentException;
  * Helper class to handle automatically marking connections as reusable (via RAII pattern)
  * as well handling deferring the actual network connection until the handle is used
  *
- * @note: proxy methods are defined explicitly to avoid interface errors
  * @ingroup Database
  * @since 1.22
  */
@@ -19,6 +18,8 @@ class DBConnRef implements IDatabase {
        private $conn;
        /** @var array|null N-tuple of (server index, group, DatabaseDomain|string) */
        private $params;
+       /** @var int One of DB_MASTER/DB_REPLICA */
+       private $role;
 
        const FLD_INDEX = 0;
        const FLD_GROUP = 1;
@@ -27,10 +28,13 @@ class DBConnRef implements IDatabase {
 
        /**
         * @param ILoadBalancer $lb Connection manager for $conn
-        * @param Database|array $conn Database handle or (server index, query groups, domain, flags)
+        * @param Database|array $conn Database or (server index, query groups, domain, flags)
+        * @param int $role The type of connection asked for; one of DB_MASTER/DB_REPLICA
+        * @internal This method should not be called outside of LoadBalancer
         */
-       public function __construct( ILoadBalancer $lb, $conn ) {
+       public function __construct( ILoadBalancer $lb, $conn, $role ) {
                $this->lb = $lb;
+               $this->role = $role;
                if ( $conn instanceof Database ) {
                        $this->conn = $conn; // live handle
                } elseif ( is_array( $conn ) && count( $conn ) >= 4 && $conn[self::FLD_DOMAIN] !== false ) {
@@ -42,13 +46,21 @@ class DBConnRef implements IDatabase {
 
        function __call( $name, array $arguments ) {
                if ( $this->conn === null ) {
-                       list( $db, $groups, $wiki, $flags ) = $this->params;
-                       $this->conn = $this->lb->getConnection( $db, $groups, $wiki, $flags );
+                       list( $index, $groups, $wiki, $flags ) = $this->params;
+                       $this->conn = $this->lb->getConnection( $index, $groups, $wiki, $flags );
                }
 
                return $this->conn->$name( ...$arguments );
        }
 
+       /**
+        * @return int DB_MASTER when this *requires* the master DB, otherwise DB_REPLICA
+        * @since 1.33
+        */
+       public function getReferenceRole() {
+               return $this->role;
+       }
+
        public function getServerInfo() {
                return $this->__call( __FUNCTION__, func_get_args() );
        }
@@ -74,11 +86,29 @@ class DBConnRef implements IDatabase {
        }
 
        public function tablePrefix( $prefix = null ) {
-               return $this->__call( __FUNCTION__, func_get_args() );
+               if ( $this->conn === null && $prefix === null ) {
+                       $domain = DatabaseDomain::newFromId( $this->params[self::FLD_DOMAIN] );
+                       // Avoid triggering a database connection
+                       return $domain->getTablePrefix();
+               } elseif ( $this->conn !== null && $prefix === null ) {
+                       // This will just return the prefix
+                       return $this->__call( __FUNCTION__, func_get_args() );
+               }
+               // Disallow things that might confuse the LoadBalancer tracking
+               throw new DBUnexpectedError( $this, "Database selection is disallowed to enable reuse." );
        }
 
        public function dbSchema( $schema = null ) {
-               return $this->__call( __FUNCTION__, func_get_args() );
+               if ( $this->conn === null && $schema === null ) {
+                       $domain = DatabaseDomain::newFromId( $this->params[self::FLD_DOMAIN] );
+                       // Avoid triggering a database connection
+                       return $domain->getSchema();
+               } elseif ( $this->conn !== null && $schema === null ) {
+                       // This will just return the schema
+                       return $this->__call( __FUNCTION__, func_get_args() );
+               }
+               // Disallow things that might confuse the LoadBalancer tracking
+               throw new DBUnexpectedError( $this, "Database selection is disallowed to enable reuse." );
        }
 
        public function getLBInfo( $name = null ) {
@@ -86,11 +116,13 @@ class DBConnRef implements IDatabase {
        }
 
        public function setLBInfo( $name, $value = null ) {
-               return $this->__call( __FUNCTION__, func_get_args() );
+               // Disallow things that might confuse the LoadBalancer tracking
+               throw new DBUnexpectedError( $this, "Changing LB info is disallowed to enable reuse." );
        }
 
        public function setLazyMasterHandle( IDatabase $conn ) {
-               return $this->__call( __FUNCTION__, func_get_args() );
+               // Disallow things that might confuse the LoadBalancer tracking
+               throw new DBUnexpectedError( $this, "Database injection is disallowed to enable reuse." );
        }
 
        public function implicitGroupby() {
@@ -179,6 +211,19 @@ class DBConnRef implements IDatabase {
        }
 
        public function getType() {
+               if ( $this->conn === null ) {
+                       // Avoid triggering a database connection
+                       if ( $this->params[self::FLD_INDEX] === ILoadBalancer::DB_MASTER ) {
+                               $index = $this->lb->getWriterIndex();
+                       } else {
+                               $index = $this->params[self::FLD_INDEX];
+                       }
+                       if ( $index >= 0 ) {
+                               // In theory, if $index is DB_REPLICA, the type could vary
+                               return $this->lb->getServerType( $index );
+                       }
+               }
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
@@ -231,11 +276,15 @@ class DBConnRef implements IDatabase {
        }
 
        public function close() {
-               return $this->__call( __FUNCTION__, func_get_args() );
+               throw new DBUnexpectedError( $this->conn, 'Cannot close shared connection.' );
        }
 
-       public function query( $sql, $fname = __METHOD__, $tempIgnore = false ) {
-               return $this->__call( __FUNCTION__, func_get_args() );
+       public function query( $sql, $fname = __METHOD__, $flags = 0 ) {
+               if ( $this->role !== ILoadBalancer::DB_MASTER ) {
+                       $flags |= IDatabase::QUERY_REPLICA_ROLE;
+               }
+
+               return $this->__call( __FUNCTION__, [ $sql, $fname, $flags ] );
        }
 
        public function freeResult( $res ) {
@@ -268,6 +317,10 @@ class DBConnRef implements IDatabase {
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
+       public function limitResult( $sql, $limit, $offset = false ) {
+               return $this->__call( __FUNCTION__, func_get_args() );
+       }
+
        public function selectRow(
                $table, $vars, $conds, $fname = __METHOD__,
                $options = [], $join_conds = []
@@ -290,6 +343,8 @@ class DBConnRef implements IDatabase {
        public function lockForUpdate(
                $table, $conds = '', $fname = __METHOD__, $options = [], $join_conds = []
        ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
@@ -306,10 +361,14 @@ class DBConnRef implements IDatabase {
        }
 
        public function insert( $table, $a, $fname = __METHOD__, $options = [] ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function update( $table, $values, $conds, $fname = __METHOD__, $options = [] ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
@@ -381,6 +440,12 @@ class DBConnRef implements IDatabase {
        }
 
        public function getDBname() {
+               if ( $this->conn === null ) {
+                       $domain = DatabaseDomain::newFromId( $this->params[self::FLD_DOMAIN] );
+                       // Avoid triggering a database connection
+                       return $domain->getDatabase();
+               }
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
@@ -409,26 +474,36 @@ class DBConnRef implements IDatabase {
        }
 
        public function nextSequenceValue( $seqName ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function replace( $table, $uniqueIndexes, $rows, $fname = __METHOD__ ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function upsert(
                $table, array $rows, $uniqueIndexes, array $set, $fname = __METHOD__
        ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function deleteJoin(
                $delTable, $joinTable, $delVar, $joinVar, $conds, $fname = __METHOD__
        ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function delete( $table, $conds, $fname = __METHOD__ ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
@@ -436,6 +511,8 @@ class DBConnRef implements IDatabase {
                $destTable, $srcTable, $varMap, $conds,
                $fname = __METHOD__, $insertOptions = [], $selectOptions = [], $selectJoinConds = []
        ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
@@ -503,18 +580,21 @@ class DBConnRef implements IDatabase {
        }
 
        public function onTransactionResolution( callable $callback, $fname = __METHOD__ ) {
+               // DB_REPLICA role: caller might want to refresh cache after a REPEATABLE-READ snapshot
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function onTransactionCommitOrIdle( callable $callback, $fname = __METHOD__ ) {
+               // DB_REPLICA role: caller might want to refresh cache after a REPEATABLE-READ snapshot
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function onTransactionIdle( callable $callback, $fname = __METHOD__ ) {
-               return $this->__call( __FUNCTION__, func_get_args() );
+               return $this->onTransactionCommitOrIdle( $callback, $fname );
        }
 
        public function onTransactionPreCommitOrIdle( callable $callback, $fname = __METHOD__ ) {
+               // DB_REPLICA role: caller might want to refresh cache after a cache mutex is released
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
@@ -525,20 +605,24 @@ class DBConnRef implements IDatabase {
        public function startAtomic(
                $fname = __METHOD__, $cancelable = IDatabase::ATOMIC_NOT_CANCELABLE
        ) {
+               // Don't call assertRoleAllowsWrites(); caller might want a REPEATABLE-READ snapshot
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function endAtomic( $fname = __METHOD__ ) {
+               // Don't call assertRoleAllowsWrites(); caller might want a REPEATABLE-READ snapshot
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function cancelAtomic( $fname = __METHOD__, AtomicSectionIdentifier $sectionId = null ) {
+               // Don't call assertRoleAllowsWrites(); caller might want a REPEATABLE-READ snapshot
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function doAtomicSection(
                $fname, callable $callback, $cancelable = self::ATOMIC_NOT_CANCELABLE
        ) {
+               // Don't call assertRoleAllowsWrites(); caller might want a REPEATABLE-READ snapshot
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
@@ -601,18 +685,26 @@ class DBConnRef implements IDatabase {
        }
 
        public function lockIsFree( $lockName, $method ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function lock( $lockName, $method, $timeout = 5 ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function unlock( $lockName, $method ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function getScopedLockAndFlush( $lockKey, $fname, $timeout ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
@@ -648,6 +740,26 @@ class DBConnRef implements IDatabase {
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
+       /**
+        * Error out if the role is not DB_MASTER
+        *
+        * Note that the underlying connection may or may not itself be read-only.
+        * It could even be to a writable master (both server-side and to the application).
+        * This error is meant for the case when a DB_REPLICA handle was requested but a
+        * a write was attempted on that handle regardless.
+        *
+        * In configurations where the master DB has some generic read load or is the only server,
+        * DB_MASTER/DB_REPLICA will sometimes (or always) use the same connection to the master DB.
+        * This does not effect the role of DBConnRef instances.
+        * @throws DBReadOnlyRoleError
+        */
+       protected function assertRoleAllowsWrites() {
+               // DB_MASTER is "prima facie" writable
+               if ( $this->role !== ILoadBalancer::DB_MASTER ) {
+                       throw new DBReadOnlyRoleError( $this->conn, "Cannot write with role DB_REPLICA" );
+               }
+       }
+
        /**
         * Clean up the connection when out of scope
         */
index 9ce3086..de9ea55 100644 (file)
@@ -61,20 +61,23 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        const SLOW_WRITE_SEC = 0.500;
        const SMALL_WRITE_ROWS = 100;
 
-       /** @var string Whether lock granularity is on the level of the entire database */
+       /** @var string Lock granularity is on the level of the entire database */
        const ATTR_DB_LEVEL_LOCKING = 'db-level-locking';
+       /** @var string The SCHEMA keyword refers to a grouping of tables in a database */
+       const ATTR_SCHEMAS_AS_TABLE_GROUPS = 'supports-schemas';
 
        /** @var int New Database instance will not be connected yet when returned */
        const NEW_UNCONNECTED = 0;
        /** @var int New Database instance will already be connected when returned */
        const NEW_CONNECTED = 1;
 
-       /** @var string SQL query */
-       protected $lastQuery = '';
+       /** @var string The last SQL query attempted */
+       private $lastQuery = '';
        /** @var float|bool UNIX timestamp of last write query */
-       protected $lastWriteTime = false;
+       private $lastWriteTime = false;
        /** @var string|bool */
-       protected $phpError = false;
+       private $lastPhpError = false;
+
        /** @var string Server that this instance is currently connected to */
        protected $server;
        /** @var string User that this instance is currently connected under the name of */
@@ -102,7 +105,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        /** @var callable Deprecation logging callback */
        protected $deprecationLogger;
 
-       /** @var resource|null Database connection */
+       /** @var object|resource|null Database connection */
        protected $conn = null;
        /** @var bool */
        protected $opened = false;
@@ -280,6 +283,11 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        /** @var int No transaction is active */
        const STATUS_TRX_NONE = 3;
 
+       /** @var int Writes to this temporary table do not affect lastDoneWrites() */
+       const TEMP_NORMAL = 1;
+       /** @var int Writes to this temporary table effect lastDoneWrites() */
+       const TEMP_PSEUDO_PERMANENT = 2;
+
        /**
         * @note exceptions for missing libraries/drivers should be thrown in initConnection()
         * @param array $params Parameters passed from Database::factory()
@@ -475,12 +483,15 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        /**
         * @param string $dbType A possible DB type (sqlite, mysql, postgres,...)
         * @param string|null $driver Optional name of a specific DB client driver
-        * @return array Map of (Database::ATTRIBUTE_* constant => value) for all such constants
+        * @return array Map of (Database::ATTR_* constant => value) for all such constants
         * @throws InvalidArgumentException
         * @since 1.31
         */
        final public static function attributesFromType( $dbType, $driver = null ) {
-               static $defaults = [ self::ATTR_DB_LEVEL_LOCKING => false ];
+               static $defaults = [
+                       self::ATTR_DB_LEVEL_LOCKING => false,
+                       self::ATTR_SCHEMAS_AS_TABLE_GROUPS => false
+               ];
 
                $class = self::getClass( $dbType, $driver );
 
@@ -514,20 +525,18 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                        $possibleDrivers = $builtinTypes[$dbType];
                        if ( is_string( $possibleDrivers ) ) {
                                $class = $possibleDrivers;
+                       } elseif ( (string)$driver !== '' ) {
+                               if ( !isset( $possibleDrivers[$driver] ) ) {
+                                       throw new InvalidArgumentException( __METHOD__ .
+                                               " type '$dbType' does not support driver '{$driver}'" );
+                               }
+
+                               $class = $possibleDrivers[$driver];
                        } else {
-                               if ( (string)$driver !== '' ) {
-                                       if ( !isset( $possibleDrivers[$driver] ) ) {
-                                               throw new InvalidArgumentException( __METHOD__ .
-                                                       " type '$dbType' does not support driver '{$driver}'" );
-                                       } else {
-                                               $class = $possibleDrivers[$driver];
-                                       }
-                               } else {
-                                       foreach ( $possibleDrivers as $posDriver => $possibleClass ) {
-                                               if ( extension_loaded( $posDriver ) ) {
-                                                       $class = $possibleClass;
-                                                       break;
-                                               }
+                               foreach ( $possibleDrivers as $posDriver => $possibleClass ) {
+                                       if ( extension_loaded( $posDriver ) ) {
+                                               $class = $possibleClass;
+                                               break;
                                        }
                                }
                        }
@@ -544,7 +553,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        }
 
        /**
-        * @return array Map of (Database::ATTRIBUTE_* constant => value
+        * @return array Map of (Database::ATTR_* constant => value
         * @since 1.31
         */
        protected static function getAttributes() {
@@ -607,6 +616,10 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        }
 
        public function dbSchema( $schema = null ) {
+               if ( strlen( $schema ) && $this->getDBname() === null ) {
+                       throw new DBUnexpectedError( $this, "Cannot set schema to '$schema'; no database set." );
+               }
+
                $old = $this->currentDomain->getSchema();
                if ( $schema !== null ) {
                        $this->currentDomain = new DatabaseDomain(
@@ -630,13 +643,13 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        public function getLBInfo( $name = null ) {
                if ( is_null( $name ) ) {
                        return $this->lbInfo;
-               } else {
-                       if ( array_key_exists( $name, $this->lbInfo ) ) {
-                               return $this->lbInfo[$name];
-                       } else {
-                               return null;
-                       }
                }
+
+               if ( array_key_exists( $name, $this->lbInfo ) ) {
+                       return $this->lbInfo[$name];
+               }
+
+               return null;
        }
 
        public function setLBInfo( $name, $value = null ) {
@@ -862,7 +875,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
         * Set a custom error handler for logging errors during database connection
         */
        protected function installErrorHandler() {
-               $this->phpError = false;
+               $this->lastPhpError = false;
                $this->htmlErrors = ini_set( 'html_errors', '0' );
                set_error_handler( [ $this, 'connectionErrorLogger' ] );
        }
@@ -885,8 +898,8 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
         * @return string|bool Last PHP error for this DB (typically connection errors)
         */
        protected function getLastPHPError() {
-               if ( $this->phpError ) {
-                       $error = preg_replace( '!\[<a.*</a>\]!', '', $this->phpError );
+               if ( $this->lastPhpError ) {
+                       $error = preg_replace( '!\[<a.*</a>\]!', '', $this->lastPhpError );
                        $error = preg_replace( '!^.*?:\s?(.*)$!', '$1', $error );
 
                        return $error;
@@ -903,7 +916,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
         * @param string $errstr
         */
        public function connectionErrorLogger( $errno, $errstr ) {
-               $this->phpError = $errstr;
+               $this->lastPhpError = $errstr;
        }
 
        /**
@@ -1020,7 +1033,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
         */
        protected function assertIsWritableMaster() {
                if ( $this->getLBInfo( 'replica' ) === true ) {
-                       throw new DBUnexpectedError(
+                       throw new DBReadOnlyRoleError(
                                $this,
                                'Write operations are not allowed on replica database connections.'
                        );
@@ -1135,57 +1148,70 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
 
        /**
         * @param string $sql A SQL query
-        * @return bool Whether $sql is SQL for TEMPORARY table operation
+        * @param bool $pseudoPermanent Treat any table from CREATE TEMPORARY as pseudo-permanent
+        * @return int|null A self::TEMP_* constant for temp table operations or null otherwise
         */
-       protected function registerTempTableOperation( $sql ) {
+       protected function registerTempTableWrite( $sql, $pseudoPermanent ) {
+               static $qt = '[`"\']?(\w+)[`"\']?'; // quoted table
+
                if ( preg_match(
-                       '/^CREATE\s+TEMPORARY\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?[`"\']?(\w+)[`"\']?/i',
+                       '/^CREATE\s+TEMPORARY\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?' . $qt . '/i',
                        $sql,
                        $matches
                ) ) {
-                       $this->sessionTempTables[$matches[1]] = 1;
+                       $type = $pseudoPermanent ? self::TEMP_PSEUDO_PERMANENT : self::TEMP_NORMAL;
+                       $this->sessionTempTables[$matches[1]] = $type;
 
-                       return true;
+                       return $type;
                } elseif ( preg_match(
-                       '/^DROP\s+(?:TEMPORARY\s+)?TABLE\s+(?:IF\s+EXISTS\s+)?[`"\']?(\w+)[`"\']?/i',
+                       '/^DROP\s+(?:TEMPORARY\s+)?TABLE\s+(?:IF\s+EXISTS\s+)?' . $qt . '/i',
                        $sql,
                        $matches
                ) ) {
-                       $isTemp = isset( $this->sessionTempTables[$matches[1]] );
+                       $type = $this->sessionTempTables[$matches[1]] ?? null;
                        unset( $this->sessionTempTables[$matches[1]] );
 
-                       return $isTemp;
+                       return $type;
                } elseif ( preg_match(
-                       '/^TRUNCATE\s+(?:TEMPORARY\s+)?TABLE\s+(?:IF\s+EXISTS\s+)?[`"\']?(\w+)[`"\']?/i',
+                       '/^TRUNCATE\s+(?:TEMPORARY\s+)?TABLE\s+(?:IF\s+EXISTS\s+)?' . $qt . '/i',
                        $sql,
                        $matches
                ) ) {
-                       return isset( $this->sessionTempTables[$matches[1]] );
+                       return $this->sessionTempTables[$matches[1]] ?? null;
                } elseif ( preg_match(
-                       '/^(?:INSERT\s+(?:\w+\s+)?INTO|UPDATE|DELETE\s+FROM)\s+[`"\']?(\w+)[`"\']?/i',
+                       '/^(?:(?:INSERT|REPLACE)\s+(?:\w+\s+)?INTO|UPDATE|DELETE\s+FROM)\s+' . $qt . '/i',
                        $sql,
                        $matches
                ) ) {
-                       return isset( $this->sessionTempTables[$matches[1]] );
+                       return $this->sessionTempTables[$matches[1]] ?? null;
                }
 
-               return false;
+               return null;
        }
 
-       public function query( $sql, $fname = __METHOD__, $tempIgnore = false ) {
+       public function query( $sql, $fname = __METHOD__, $flags = 0 ) {
                $this->assertTransactionStatus( $sql, $fname );
                $this->assertHasConnectionHandle();
 
+               $flags = (int)$flags; // b/c; this field used to be a bool
+               $ignoreErrors = $this->hasFlags( $flags, self::QUERY_SILENCE_ERRORS );
+
                $priorTransaction = $this->trxLevel;
                $priorWritesPending = $this->writesOrCallbacksPending();
-               $this->lastQuery = $sql;
 
                if ( $this->isWriteQuery( $sql ) ) {
                        # In theory, non-persistent writes are allowed in read-only mode, but due to things
                        # like https://bugs.mysql.com/bug.php?id=33669 that might not work anyway...
                        $this->assertIsWritableMaster();
-                       # Avoid treating temporary table operations as meaningful "writes"
-                       $isEffectiveWrite = !$this->registerTempTableOperation( $sql );
+                       # Do not treat temporary table writes as "meaningful writes" that need committing.
+                       # Profile them as reads. Integration tests can override this behavior via $flags.
+                       $pseudoPermanent = $this->hasFlags( $flags, self::QUERY_PSEUDO_PERMANENT );
+                       $tableType = $this->registerTempTableWrite( $sql, $pseudoPermanent );
+                       $isEffectiveWrite = ( $tableType !== self::TEMP_NORMAL );
+                       # DBConnRef uses QUERY_REPLICA_ROLE to enforce the replica role for raw SQL queries
+                       if ( $isEffectiveWrite && $this->hasFlags( $flags, self::QUERY_REPLICA_ROLE ) ) {
+                               throw new DBReadOnlyRoleError( $this, "Cannot write; target role is DB_REPLICA" );
+                       }
                } else {
                        $isEffectiveWrite = false;
                }
@@ -1240,12 +1266,12 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                                        $this->trxStatus = self::STATUS_TRX_ERROR;
                                        $this->trxStatusCause =
                                                $this->getQueryExceptionAndLog( $lastError, $lastErrno, $sql, $fname );
-                                       $tempIgnore = false; // cannot recover
+                                       $ignoreErrors = false; // cannot recover
                                        $this->trxStatusIgnoredCause = null;
                                }
                        }
 
-                       $this->reportQueryError( $lastError, $lastErrno, $sql, $fname, $tempIgnore );
+                       $this->reportQueryError( $lastError, $lastErrno, $sql, $fname, $ignoreErrors );
                }
 
                return $this->resultObject( $ret );
@@ -1264,7 +1290,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        private function attemptQuery( $sql, $commentedSql, $isEffectiveWrite, $fname ) {
                $this->beginIfImplied( $sql, $fname );
 
-               # Keep track of whether the transaction has write queries pending
+               // Keep track of whether the transaction has write queries pending
                if ( $isEffectiveWrite ) {
                        $this->lastWriteTime = microtime( true );
                        if ( $this->trxLevel && !$this->trxDoneWrites ) {
@@ -1274,25 +1300,15 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                        }
                }
 
-               if ( $this->getFlag( self::DBO_DEBUG ) ) {
-                       $this->queryLogger->debug( "{$this->getDomainID()} {$commentedSql}" );
-               }
-
-               $isMaster = !is_null( $this->getLBInfo( 'master' ) );
-               # generalizeSQL() will probably cut down the query to reasonable
-               # logging size most of the time. The substr is really just a sanity check.
-               if ( $isMaster ) {
-                       $queryProf = 'query-m: ' . substr( self::generalizeSQL( $sql ), 0, 255 );
-               } else {
-                       $queryProf = 'query: ' . substr( self::generalizeSQL( $sql ), 0, 255 );
-               }
-
-               # Include query transaction state
-               $queryProf .= $this->trxShortId ? " [TRX#{$this->trxShortId}]" : "";
+               $prefix = !is_null( $this->getLBInfo( 'master' ) ) ? 'query-m: ' : 'query: ';
+               $generalizedSql = new GeneralizedSql( $sql, $this->trxShortId, $prefix );
 
                $startTime = microtime( true );
-               $ps = $this->profiler ? ( $this->profiler )( $queryProf ) : null;
+               $ps = $this->profiler
+                       ? ( $this->profiler )( $generalizedSql->stringify() )
+                       : null;
                $this->affectedRowCount = null;
+               $this->lastQuery = $sql;
                $ret = $this->doQuery( $commentedSql );
                $this->affectedRowCount = $this->affectedRows();
                unset( $ps ); // profile out (if set)
@@ -1311,16 +1327,24 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                }
 
                $this->trxProfiler->recordQueryCompletion(
-                       $queryProf,
+                       $generalizedSql,
                        $startTime,
                        $isEffectiveWrite,
                        $isEffectiveWrite ? $this->affectedRows() : $this->numRows( $ret )
                );
-               $this->queryLogger->debug( $sql, [
-                       'method' => $fname,
-                       'master' => $isMaster,
-                       'runtime' => $queryRuntime,
-               ] );
+
+               // Avoid the overhead of logging calls unless debug mode is enabled
+               if ( $this->getFlag( self::DBO_DEBUG ) ) {
+                       $this->queryLogger->debug(
+                               "{method} [{runtime}s]: $sql",
+                               [
+                                       'method' => $fname,
+                                       'db_host' => $this->getServer(),
+                                       'domain' => $this->getDomainID(),
+                                       'runtime' => round( $queryRuntime, 3 )
+                               ]
+                       );
+               }
 
                return $ret;
        }
@@ -1514,17 +1538,17 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
 
        /**
         * Report a query error. Log the error, and if neither the object ignore
-        * flag nor the $tempIgnore flag is set, throw a DBQueryError.
+        * flag nor the $ignoreErrors flag is set, throw a DBQueryError.
         *
         * @param string $error
         * @param int $errno
         * @param string $sql
         * @param string $fname
-        * @param bool $tempIgnore
+        * @param bool $ignore
         * @throws DBQueryError
         */
-       public function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false ) {
-               if ( $tempIgnore ) {
+       public function reportQueryError( $error, $errno, $sql, $fname, $ignore = false ) {
+               if ( $ignore ) {
                        $this->queryLogger->debug( "SQL ERROR (ignored): $error\n" );
                } else {
                        $exception = $this->getQueryExceptionAndLog( $error, $errno, $sql, $fname );
@@ -1554,9 +1578,10 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                        ] )
                );
                $this->queryLogger->debug( "SQL ERROR: " . $error . "\n" );
-               $wasQueryTimeout = $this->wasQueryTimeout( $error, $errno );
-               if ( $wasQueryTimeout ) {
+               if ( $this->wasQueryTimeout( $error, $errno ) ) {
                        $e = new DBQueryTimeoutError( $this, $error, $errno, $sql, $fname );
+               } elseif ( $this->wasConnectionError( $errno ) ) {
+                       $e = new DBQueryDisconnectedError( $this, $error, $errno, $sql, $fname );
                } else {
                        $e = new DBQueryError( $this, $error, $errno, $sql, $fname );
                }
@@ -1581,17 +1606,16 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                $options['LIMIT'] = 1;
 
                $res = $this->select( $table, $var, $cond, $fname, $options, $join_conds );
-               if ( $res === false || !$this->numRows( $res ) ) {
-                       return false;
+               if ( $res === false ) {
+                       throw new DBUnexpectedError( $this, "Got false from select()" );
                }
 
                $row = $this->fetchRow( $res );
-
-               if ( $row !== false ) {
-                       return reset( $row );
-               } else {
+               if ( $row === false ) {
                        return false;
                }
+
+               return reset( $row );
        }
 
        public function selectFieldValues(
@@ -1609,7 +1633,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
 
                $res = $this->select( $table, [ 'value' => $var ], $cond, $fname, $options, $join_conds );
                if ( $res === false ) {
-                       return false;
+                       throw new DBUnexpectedError( $this, "Got false from select()" );
                }
 
                $values = [];
@@ -1846,19 +1870,17 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        ) {
                $options = (array)$options;
                $options['LIMIT'] = 1;
-               $res = $this->select( $table, $vars, $conds, $fname, $options, $join_conds );
 
+               $res = $this->select( $table, $vars, $conds, $fname, $options, $join_conds );
                if ( $res === false ) {
-                       return false;
+                       throw new DBUnexpectedError( $this, "Got false from select()" );
                }
 
                if ( !$this->numRows( $res ) ) {
                        return false;
                }
 
-               $obj = $this->fetchObject( $res );
-
-               return $obj;
+               return $this->fetchObject( $res );
        }
 
        public function estimateRowCount(
@@ -2010,36 +2032,6 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                return $this->selectRowCount( $table, '*', $conds, $fname, $options, $join_conds );
        }
 
-       /**
-        * Removes most variables from an SQL query and replaces them with X or N for numbers.
-        * It's only slightly flawed. Don't use for anything important.
-        *
-        * @param string $sql A SQL Query
-        *
-        * @return string
-        */
-       protected static function generalizeSQL( $sql ) {
-               # This does the same as the regexp below would do, but in such a way
-               # as to avoid crashing php on some large strings.
-               # $sql = preg_replace( "/'([^\\\\']|\\\\.)*'|\"([^\\\\\"]|\\\\.)*\"/", "'X'", $sql );
-
-               $sql = str_replace( "\\\\", '', $sql );
-               $sql = str_replace( "\\'", '', $sql );
-               $sql = str_replace( "\\\"", '', $sql );
-               $sql = preg_replace( "/'.*'/s", "'X'", $sql );
-               $sql = preg_replace( '/".*"/s', "'X'", $sql );
-
-               # All newlines, tabs, etc replaced by single space
-               $sql = preg_replace( '/\s+/', ' ', $sql );
-
-               # All numbers => N,
-               # except the ones surrounded by characters, e.g. l10n
-               $sql = preg_replace( '/-?\d+(,-?\d+)+/s', 'N,...,N', $sql );
-               $sql = preg_replace( '/(?<![a-zA-Z])-?\d+(?![a-zA-Z])/s', 'N', $sql );
-
-               return $sql;
-       }
-
        public function fieldExists( $table, $field, $fname = __METHOD__ ) {
                $info = $this->fieldInfo( $table, $field );
 
@@ -2532,7 +2524,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                        throw new InvalidArgumentException( "Table must be a string or Subquery." );
                }
 
-               if ( !strlen( $alias ) || $alias === $table ) {
+               if ( $alias === false || $alias === $table ) {
                        if ( $table instanceof Subquery ) {
                                throw new InvalidArgumentException( "Subquery table missing alias." );
                        }
@@ -2687,8 +2679,8 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                }
 
                // We can't separate explicit JOIN clauses with ',', use ' ' for those
-               $implicitJoins = $ret ? implode( ',', $ret ) : "";
-               $explicitJoins = $retJOIN ? implode( ' ', $retJOIN ) : "";
+               $implicitJoins = implode( ',', $ret );
+               $explicitJoins = implode( ' ', $retJOIN );
 
                // Compile our final table clause
                return implode( ' ', [ $implicitJoins, $explicitJoins ] );
@@ -3165,34 +3157,16 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                $this->query( $sql, $fname );
        }
 
-       /**
-        * Construct a LIMIT query with optional offset. This is used for query
-        * pages. The SQL should be adjusted so that only the first $limit rows
-        * are returned. If $offset is provided as well, then the first $offset
-        * rows should be discarded, and the next $limit rows should be returned.
-        * If the result of the query is not ordered, then the rows to be returned
-        * are theoretically arbitrary.
-        *
-        * $sql is expected to be a SELECT, if that makes a difference.
-        *
-        * The version provided by default works in MySQL and SQLite. It will very
-        * likely need to be overridden for most other DBMSes.
-        *
-        * @param string $sql SQL query we will append the limit too
-        * @param int $limit The SQL limit
-        * @param int|bool $offset The SQL offset (default false)
-        * @throws DBUnexpectedError
-        * @return string
-        */
        public function limitResult( $sql, $limit, $offset = false ) {
                if ( !is_numeric( $limit ) ) {
                        throw new DBUnexpectedError( $this,
                                "Invalid non-numeric limit passed to limitResult()\n" );
                }
-
+               // This version works in MySQL and SQLite. It will very likely need to be
+               // overridden for most other RDBMS subclasses.
                return "$sql LIMIT "
-               . ( ( is_numeric( $offset ) && $offset != 0 ) ? "{$offset}," : "" )
-               . "{$limit} ";
+                       . ( ( is_numeric( $offset ) && $offset != 0 ) ? "{$offset}," : "" )
+                       . "{$limit} ";
        }
 
        public function unionSupportsOrderAndLimit() {
@@ -3558,6 +3532,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                                list( $phpCallback ) = $callback;
                                $this->clearFlag( self::DBO_TRX ); // make each query its own transaction
                                try {
+                                       // @phan-suppress-next-line PhanParamTooManyCallable
                                        call_user_func( $phpCallback, $trigger, $this );
                                } catch ( Exception $ex ) {
                                        call_user_func( $this->errorLogger, $ex );
@@ -3951,17 +3926,15 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                                        "$fname: Flushing an explicit transaction, getting out of sync."
                                );
                        }
-               } else {
-                       if ( !$this->trxLevel ) {
-                               $this->queryLogger->error(
-                                       "$fname: No transaction to commit, something got out of sync." );
-                               return; // nothing to do
-                       } elseif ( $this->trxAutomatic ) {
-                               throw new DBUnexpectedError(
-                                       $this,
-                                       "$fname: Expected mass commit of all peer transactions (DBO_TRX set)."
-                               );
-                       }
+               } elseif ( !$this->trxLevel ) {
+                       $this->queryLogger->error(
+                               "$fname: No transaction to commit, something got out of sync." );
+                       return; // nothing to do
+               } elseif ( $this->trxAutomatic ) {
+                       throw new DBUnexpectedError(
+                               $this,
+                               "$fname: Expected mass commit of all peer transactions (DBO_TRX set)."
+                       );
                }
 
                $this->assertHasConnectionHandle();
@@ -4006,13 +3979,14 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        final public function rollback( $fname = __METHOD__, $flush = '' ) {
                $trxActive = $this->trxLevel;
 
-               if ( $flush !== self::FLUSHING_INTERNAL && $flush !== self::FLUSHING_ALL_PEERS ) {
-                       if ( $this->getFlag( self::DBO_TRX ) ) {
-                               throw new DBUnexpectedError(
-                                       $this,
-                                       "$fname: Expected mass rollback of all peer transactions (DBO_TRX set)."
-                               );
-                       }
+               if ( $flush !== self::FLUSHING_INTERNAL
+                       && $flush !== self::FLUSHING_ALL_PEERS
+                       && $this->getFlag( self::DBO_TRX )
+               ) {
+                       throw new DBUnexpectedError(
+                               $this,
+                               "$fname: Expected mass rollback of all peer transactions (DBO_TRX set)."
+                       );
                }
 
                if ( $trxActive ) {
@@ -4684,6 +4658,15 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                $this->indexAliases = $aliases;
        }
 
+       /**
+        * @param int $field
+        * @param int $flags
+        * @return bool
+        */
+       protected function hasFlags( $field, $flags ) {
+               return ( ( $field & $flags ) === $flags );
+       }
+
        /**
         * Get the underlying binding connection handle
         *
diff --git a/includes/libs/rdbms/database/DatabaseDomain.php b/includes/libs/rdbms/database/DatabaseDomain.php
deleted file mode 100644 (file)
index 7559b06..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-<?php
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Database
- */
-namespace Wikimedia\Rdbms;
-
-use InvalidArgumentException;
-
-/**
- * Class to handle database/prefix specification for IDatabase domains
- */
-class DatabaseDomain {
-       /** @var string|null */
-       private $database;
-       /** @var string|null */
-       private $schema;
-       /** @var string */
-       private $prefix;
-
-       /** @var string Cache of convertToString() */
-       private $equivalentString;
-
-       /**
-        * @param string|null $database Database name
-        * @param string|null $schema Schema name
-        * @param string $prefix Table prefix
-        */
-       public function __construct( $database, $schema, $prefix ) {
-               if ( $database !== null && ( !is_string( $database ) || !strlen( $database ) ) ) {
-                       throw new InvalidArgumentException( "Database must be null or a non-empty string." );
-               }
-               $this->database = $database;
-               if ( $schema !== null && ( !is_string( $schema ) || !strlen( $schema ) ) ) {
-                       throw new InvalidArgumentException( "Schema must be null or a non-empty string." );
-               }
-               $this->schema = $schema;
-               if ( !is_string( $prefix ) ) {
-                       throw new InvalidArgumentException( "Prefix must be a string." );
-               }
-               $this->prefix = $prefix;
-       }
-
-       /**
-        * @param DatabaseDomain|string $domain Result of DatabaseDomain::toString()
-        * @return DatabaseDomain
-        */
-       public static function newFromId( $domain ) {
-               if ( $domain instanceof self ) {
-                       return $domain;
-               }
-
-               $parts = array_map( [ __CLASS__, 'decode' ], explode( '-', $domain ) );
-
-               $schema = null;
-               $prefix = '';
-
-               if ( count( $parts ) == 1 ) {
-                       $database = $parts[0];
-               } elseif ( count( $parts ) == 2 ) {
-                       list( $database, $prefix ) = $parts;
-               } elseif ( count( $parts ) == 3 ) {
-                       list( $database, $schema, $prefix ) = $parts;
-               } else {
-                       throw new InvalidArgumentException( "Domain '$domain' has too few or too many parts." );
-               }
-
-               if ( $database === '' ) {
-                       $database = null;
-               }
-
-               if ( $schema === '' ) {
-                       $schema = null;
-               }
-
-               return new self( $database, $schema, $prefix );
-       }
-
-       /**
-        * @return DatabaseDomain
-        */
-       public static function newUnspecified() {
-               return new self( null, null, '' );
-       }
-
-       /**
-        * @param DatabaseDomain|string $other
-        * @return bool Whether the domain instances are the same by value
-        */
-       public function equals( $other ) {
-               if ( $other instanceof self ) {
-                       return (
-                               $this->database === $other->database &&
-                               $this->schema === $other->schema &&
-                               $this->prefix === $other->prefix
-                       );
-               }
-
-               return ( $this->getId() === $other );
-       }
-
-       /**
-        * Check whether the domain $other meets the specifications of this domain
-        *
-        * If this instance has a null database specifier, then $other can have any database
-        * specified, including the null, and likewise if the schema specifier is null. This
-        * is not transitive like equals() since a domain that explicitly wants a certain
-        * database or schema cannot be satisfied by one of another (nor null). If the prefix
-        * is empty and the DB and schema are both null, then the entire domain is considered
-        * unspecified, and any prefix of $other is considered compatible.
-        *
-        * @param DatabaseDomain|string $other
-        * @return bool
-        * @since 1.32
-        */
-       public function isCompatible( $other ) {
-               if ( $this->isUnspecified() ) {
-                       return true; // even the prefix doesn't matter
-               }
-
-               $other = ( $other instanceof self ) ? $other : self::newFromId( $other );
-
-               return (
-                       ( $this->database === $other->database || $this->database === null ) &&
-                       ( $this->schema === $other->schema || $this->schema === null ) &&
-                       $this->prefix === $other->prefix
-               );
-       }
-
-       /**
-        * @return bool
-        * @since 1.32
-        */
-       public function isUnspecified() {
-               return (
-                       $this->database === null && $this->schema === null && $this->prefix === ''
-               );
-       }
-
-       /**
-        * @return string|null Database name
-        */
-       public function getDatabase() {
-               return $this->database;
-       }
-
-       /**
-        * @return string|null Database schema
-        */
-       public function getSchema() {
-               return $this->schema;
-       }
-
-       /**
-        * @return string Table prefix
-        */
-       public function getTablePrefix() {
-               return $this->prefix;
-       }
-
-       /**
-        * @return string
-        */
-       public function getId() {
-               if ( $this->equivalentString === null ) {
-                       $this->equivalentString = $this->convertToString();
-               }
-
-               return $this->equivalentString;
-       }
-
-       /**
-        * @return string
-        */
-       private function convertToString() {
-               $parts = [ $this->database ];
-               if ( $this->schema !== null ) {
-                       $parts[] = $this->schema;
-               }
-               if ( $this->prefix != '' || $this->schema !== null ) {
-                       // If there is a schema, then we need the prefix to disambiguate.
-                       // For engines like Postgres that use schemas, this awkwardness is hopefully
-                       // avoided since it is easy to have one DB per server (to avoid having many users)
-                       // and use schema/prefix to have wiki farms. For example, a domain schemes could be
-                       // wiki-<project>-<language>, e.g. "wiki-fitness-es"/"wiki-sports-fr"/"wiki-news-en".
-                       $parts[] = $this->prefix;
-               }
-
-               return implode( '-', array_map( [ __CLASS__, 'encode' ], $parts ) );
-       }
-
-       private static function encode( $decoded ) {
-               $encoded = '';
-
-               $length = strlen( $decoded );
-               for ( $i = 0; $i < $length; ++$i ) {
-                       $char = $decoded[$i];
-                       if ( $char === '-' ) {
-                               $encoded .= '?h';
-                       } elseif ( $char === '?' ) {
-                               $encoded .= '??';
-                       } else {
-                               $encoded .= $char;
-                       }
-               }
-
-               return $encoded;
-       }
-
-       private static function decode( $encoded ) {
-               $decoded = '';
-
-               $length = strlen( $encoded );
-               for ( $i = 0; $i < $length; ++$i ) {
-                       $char = $encoded[$i];
-                       if ( $char === '?' ) {
-                               $nextChar = $encoded[$i + 1] ?? null;
-                               if ( $nextChar === 'h' ) {
-                                       $decoded .= '-';
-                                       ++$i;
-                               } elseif ( $nextChar === '?' ) {
-                                       $decoded .= '?';
-                                       ++$i;
-                               } else {
-                                       $decoded .= $char;
-                               }
-                       } else {
-                               $decoded .= $char;
-                       }
-               }
-
-               return $decoded;
-       }
-
-       /**
-        * @return string
-        */
-       function __toString() {
-               return $this->getId();
-       }
-}
index ad5cf98..6d266ae 100644 (file)
@@ -702,12 +702,6 @@ class DatabaseMssql extends Database {
                                }
                                if ( is_null( $value ) ) {
                                        $sql .= 'null';
-                               } elseif ( is_array( $value ) || is_object( $value ) ) {
-                                       if ( is_object( $value ) && $value instanceof Blob ) {
-                                               $sql .= $this->addQuotes( $value );
-                                       } else {
-                                               $sql .= $this->addQuotes( serialize( $value ) );
-                                       }
                                } else {
                                        $sql .= $this->addQuotes( $value );
                                }
@@ -1328,8 +1322,9 @@ class DatabaseMssql extends Database {
 
        /**
         * @param string $name
-        * @param string $format
-        * @return string
+        * @param string $format One of "quoted" (default), "raw", or "split".
+        * @return string|array When the requested $format is "split", a list of database, schema, and
+        *  table name is returned. Database and schema can be `false`.
         */
        function tableName( $name, $format = 'quoted' ) {
                # Replace reserved words with better ones
@@ -1344,18 +1339,17 @@ class DatabaseMssql extends Database {
        /**
         * call this instead of tableName() in the updater when renaming tables
         * @param string $name
-        * @param string $format One of quoted, raw, or split
-        * @return string
+        * @param string $format One of "quoted" (default), "raw", or "split".
+        * @return string|array When the requested $format is "split", a list of database, schema, and
+        *  table name is returned. Database and schema can be `false`.
+        * @private
         */
        function realTableName( $name, $format = 'quoted' ) {
                $table = parent::tableName( $name, $format );
                if ( $format == 'split' ) {
                        // Used internally, we want the schema split off from the table name and returned
                        // as a list with 3 elements (database, schema, table)
-                       $table = explode( '.', $table );
-                       while ( count( $table ) < 3 ) {
-                               array_unshift( $table, false );
-                       }
+                       return array_pad( explode( '.', $table, 3 ), -3, false );
                }
                return $table;
        }
@@ -1412,6 +1406,9 @@ class DatabaseMssql extends Database {
                return "CAST( $field AS NVARCHAR )";
        }
 
+       public static function getAttributes() {
+               return [ self::ATTR_SCHEMAS_AS_TABLE_GROUPS => true ];
+       }
 }
 
 /**
index 1a406cf..36c947f 100644 (file)
@@ -106,7 +106,7 @@ abstract class DatabaseMysqlBase extends Database {
                                $this->$var = $params[$var];
                        }
                }
-               $this->sqlMode = $params['sqlMode'] ?? '';
+               $this->sqlMode = $params['sqlMode'] ?? null;
                $this->utf8Mode = !empty( $params['utf8Mode'] );
                $this->insertSelectIsSafe = isset( $params['insertSelectIsSafe'] )
                        ? (bool)$params['insertSelectIsSafe'] : null;
@@ -225,6 +225,39 @@ abstract class DatabaseMysqlBase extends Database {
                }
        }
 
+       protected function doSelectDomain( DatabaseDomain $domain ) {
+               if ( $domain->getSchema() !== null ) {
+                       throw new DBExpectedError( $this, __CLASS__ . ": domain schemas are not supported." );
+               }
+
+               $database = $domain->getDatabase();
+               // A null database means "don't care" so leave it as is and update the table prefix
+               if ( $database === null ) {
+                       $this->currentDomain = new DatabaseDomain(
+                               $this->currentDomain->getDatabase(),
+                               null,
+                               $domain->getTablePrefix()
+                       );
+
+                       return true;
+               }
+
+               if ( $database !== $this->getDBname() ) {
+                       $sql = 'USE ' . $this->addIdentifierQuotes( $database );
+                       $ret = $this->doQuery( $sql );
+                       if ( $ret === false ) {
+                               $error = $this->lastError();
+                               $errno = $this->lastErrno();
+                               $this->reportQueryError( $error, $errno, $sql, __METHOD__ );
+                       }
+               }
+
+               // Update that domain fields on success (no exception thrown)
+               $this->currentDomain = $domain;
+
+               return true;
+       }
+
        /**
         * Open a connection to a MySQL server
         *
@@ -486,7 +519,9 @@ abstract class DatabaseMysqlBase extends Database {
        abstract protected function mysqlError( $conn = null );
 
        protected function wasQueryTimeout( $error, $errno ) {
-               return $errno == 2062;
+               // https://dev.mysql.com/doc/refman/8.0/en/client-error-reference.html
+               // https://phabricator.wikimedia.org/T170638
+               return in_array( $errno, [ 2062, 3024 ] );
        }
 
        public function replace( $table, $uniqueIndexes, $rows, $fname = __METHOD__ ) {
@@ -1407,7 +1442,7 @@ abstract class DatabaseMysqlBase extends Database {
                }
 
                // See https://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html
-               return in_array( $errno, [ 1022, 1216, 1217, 1137, 1146, 1051, 1054 ], true );
+               return in_array( $errno, [ 1022, 1062, 1216, 1217, 1137, 1146, 1051, 1054 ], true );
        }
 
        /**
@@ -1425,7 +1460,7 @@ abstract class DatabaseMysqlBase extends Database {
                $oldName = $this->addIdentifierQuotes( $oldName );
                $query = "CREATE $tmp TABLE $newName (LIKE $oldName)";
 
-               return $this->query( $query, $fname );
+               return $this->query( $query, $fname, $this::QUERY_PSEUDO_PERMANENT );
        }
 
        /**
index 1c4ed56..1a5cdab 100644 (file)
@@ -78,9 +78,7 @@ class DatabaseMysqli extends DatabaseMysqlBase {
                } elseif ( substr_count( $realServer, ':' ) == 1 ) {
                        // If we have a colon and something that's not a port number
                        // inside the hostname, assume it's the socket location
-                       $hostAndSocket = explode( ':', $realServer, 2 );
-                       $realServer = $hostAndSocket[0];
-                       $socket = $hostAndSocket[1];
+                       list( $realServer, $socket ) = explode( ':', $realServer, 2 );
                }
 
                $mysqli = mysqli_init();
@@ -180,25 +178,6 @@ class DatabaseMysqli extends DatabaseMysqlBase {
                return $conn->affected_rows;
        }
 
-       function doSelectDomain( DatabaseDomain $domain ) {
-               if ( $domain->getSchema() !== null ) {
-                       throw new DBExpectedError( $this, __CLASS__ . ": domain schemas are not supported." );
-               }
-
-               $database = $domain->getDatabase();
-               if ( $database !== $this->getDBname() ) {
-                       $conn = $this->getBindingHandle();
-                       if ( !$conn->select_db( $database ) ) {
-                               throw new DBExpectedError( $this, "Could not select database '$database'." );
-                       }
-               }
-
-               // Update that domain fields on success (no exception thrown)
-               $this->currentDomain = $domain;
-
-               return true;
-       }
-
        /**
         * @param mysqli_result $res
         * @return bool
index 8aec1ac..d8be62f 100644 (file)
@@ -116,7 +116,7 @@ class DatabasePostgres extends Database {
                        $connectVars['port'] = (int)$this->port;
                }
                if ( $this->flags & self::DBO_SSL ) {
-                       $connectVars['sslmode'] = 1;
+                       $connectVars['sslmode'] = 'require';
                }
 
                $this->connectString = $this->makeConnectionString( $connectVars );
@@ -819,8 +819,12 @@ __INDEXATTR__;
 
                $temporary = $temporary ? 'TEMPORARY' : '';
 
-               $ret = $this->query( "CREATE $temporary TABLE $newNameE " .
-                       "(LIKE $oldNameE INCLUDING DEFAULTS INCLUDING INDEXES)", $fname );
+               $ret = $this->query(
+                       "CREATE $temporary TABLE $newNameE " .
+                               "(LIKE $oldNameE INCLUDING DEFAULTS INCLUDING INDEXES)",
+                       $fname,
+                       $this::QUERY_PSEUDO_PERMANENT
+               );
                if ( !$ret ) {
                        return $ret;
                }
@@ -842,7 +846,10 @@ __INDEXATTR__;
                        $fieldE = $this->addIdentifierQuotes( $field );
                        $newSeqE = $this->addIdentifierQuotes( $newSeq );
                        $newSeqQ = $this->addQuotes( $newSeq );
-                       $this->query( "CREATE $temporary SEQUENCE $newSeqE OWNED BY $newNameE.$fieldE", $fname );
+                       $this->query(
+                               "CREATE $temporary SEQUENCE $newSeqE OWNED BY $newNameE.$fieldE",
+                               $fname
+                       );
                        $this->query(
                                "ALTER TABLE $newNameE ALTER COLUMN $fieldE SET DEFAULT nextval({$newSeqQ}::regclass)",
                                $fname
@@ -915,7 +922,7 @@ __INDEXATTR__;
 
        /**
         * Posted by cc[plus]php[at]c2se[dot]com on 25-Mar-2009 09:12
-        * to https://secure.php.net/manual/en/ref.pgsql.php
+        * to https://www.php.net/manual/en/ref.pgsql.php
         *
         * Parsing a postgres array can be a tricky problem, he's my
         * take on this, it handles multi-dimensional arrays plus
@@ -1346,10 +1353,6 @@ SQL;
                return [ $startOpts, $useIndex, $preLimitTail, $postLimitTail, $ignoreIndex ];
        }
 
-       public function getServer() {
-               return $this->server;
-       }
-
        public function buildConcat( $stringList ) {
                return implode( ' || ', $stringList );
        }
@@ -1462,6 +1465,10 @@ SQL;
                return $row ? ( strtolower( $row->default_transaction_read_only ) === 'on' ) : false;
        }
 
+       public static function getAttributes() {
+               return [ self::ATTR_SCHEMAS_AS_TABLE_GROUPS => true ];
+       }
+
        /**
         * @param string $lockName
         * @return string Integer
index 7049df5..c9942a5 100644 (file)
@@ -216,6 +216,11 @@ class DatabaseSqlite extends Database {
                        # Enforce LIKE to be case sensitive, just like MySQL
                        $this->query( 'PRAGMA case_sensitive_like = 1' );
 
+                       $sync = $this->sessionVars['synchronous'] ?? null;
+                       if ( in_array( $sync, [ 'EXTRA', 'FULL', 'NORMAL' ], true ) ) {
+                               $this->query( "PRAGMA synchronous = $sync" );
+                       }
+
                        return $this->conn;
                }
 
@@ -254,7 +259,7 @@ class DatabaseSqlite extends Database {
         * Check if the searchindext table is FTS enabled.
         * @return bool False if not enabled.
         */
-       function checkForEnabledSearch() {
+       public function checkForEnabledSearch() {
                if ( self::$fulltextEnabled === null ) {
                        self::$fulltextEnabled = false;
                        $table = $this->tableName( 'searchindex' );
@@ -1013,7 +1018,7 @@ class DatabaseSqlite extends Database {
                        }
                }
 
-               $res = $this->query( $sql, $fname );
+               $res = $this->query( $sql, $fname, self::QUERY_PSEUDO_PERMANENT );
 
                // Take over indexes
                $indexList = $this->query( 'PRAGMA INDEX_LIST(' . $this->addQuotes( $oldName ) . ')' );
index 6f58cc6..aeefacd 100644 (file)
@@ -106,6 +106,21 @@ interface IDatabase {
        /** @var int Enable compression in connection protocol */
        const DBO_COMPRESS = 512;
 
+       /** @var int Ignore query errors and return false when they happen */
+       const QUERY_SILENCE_ERRORS = 1; // b/c for 1.32 query() argument; note that (int)true = 1
+       /**
+        * @var int Treat the TEMPORARY table from the given CREATE query as if it is
+        *   permanent as far as write tracking is concerned. This is useful for testing.
+        */
+       const QUERY_PSEUDO_PERMANENT = 2;
+       /** @var int Enforce that a query does not make effective writes */
+       const QUERY_REPLICA_ROLE = 4;
+
+       /** @var bool Parameter to unionQueries() for UNION ALL */
+       const UNION_ALL = true;
+       /** @var bool Parameter to unionQueries() for UNION DISTINCT */
+       const UNION_DISTINCT = false;
+
        /**
         * A string describing the current software version, and possibly
         * other details in a user-friendly way. Will be listed on Special:Version, etc.
@@ -232,8 +247,8 @@ interface IDatabase {
        public function implicitOrderby();
 
        /**
-        * Return the last query that went through IDatabase::query()
-        * @return string
+        * Return the last query that sent on account of IDatabase::query()
+        * @return string SQL text or empty string if there was no such query
         */
        public function lastQuery();
 
@@ -416,7 +431,7 @@ interface IDatabase {
 
        /**
         * Get the number of fields in a result object
-        * @see https://secure.php.net/mysql_num_fields
+        * @see https://www.php.net/mysql_num_fields
         *
         * @param mixed $res A SQL result
         * @return int
@@ -425,7 +440,7 @@ interface IDatabase {
 
        /**
         * Get a field name in a result object
-        * @see https://secure.php.net/mysql_field_name
+        * @see https://www.php.net/mysql_field_name
         *
         * @param mixed $res A SQL result
         * @param int $n
@@ -446,7 +461,7 @@ interface IDatabase {
 
        /**
         * Change the position of the cursor in a result object
-        * @see https://secure.php.net/mysql_data_seek
+        * @see https://www.php.net/mysql_data_seek
         *
         * @param mixed $res A SQL result
         * @param int $row
@@ -455,7 +470,7 @@ interface IDatabase {
 
        /**
         * Get the last error number
-        * @see https://secure.php.net/mysql_errno
+        * @see https://www.php.net/mysql_errno
         *
         * @return int
         */
@@ -463,7 +478,7 @@ interface IDatabase {
 
        /**
         * Get a description of the last error
-        * @see https://secure.php.net/mysql_error
+        * @see https://www.php.net/mysql_error
         *
         * @return string
         */
@@ -471,7 +486,7 @@ interface IDatabase {
 
        /**
         * Get the number of rows affected by the last write query
-        * @see https://secure.php.net/mysql_affected_rows
+        * @see https://www.php.net/mysql_affected_rows
         *
         * @return int
         */
@@ -527,13 +542,13 @@ interface IDatabase {
         * @param string $sql SQL query
         * @param string $fname Name of the calling function, for profiling/SHOW PROCESSLIST
         *     comment (you can use __METHOD__ or add some extra info)
-        * @param bool $tempIgnore Whether to avoid throwing an exception on errors...
-        *     maybe best to catch the exception instead?
+        * @param int $flags Bitfield of IDatabase::QUERY_* constants. Note that suppression
+        *     of errors is best handled by try/catch rather than using one of these flags.
         * @return bool|IResultWrapper True for a successful write query, IResultWrapper object
-        *     for a successful read query, or false on failure if $tempIgnore set
+        *     for a successful read query, or false on failure if QUERY_SILENCE_ERRORS is set.
         * @throws DBError
         */
-       public function query( $sql, $fname = __METHOD__, $tempIgnore = false );
+       public function query( $sql, $fname = __METHOD__, $flags = 0 );
 
        /**
         * Free a result object returned by query() or select(). It's usually not
@@ -698,7 +713,8 @@ interface IDatabase {
         *     is applied to a result set after OFFSET.
         *
         *   - FOR UPDATE: Boolean: lock the returned rows so that they can't be
-        *     changed until the next COMMIT.
+        *     changed until the next COMMIT. Cannot be used with aggregate functions
+        *     (COUNT, MAX, etc., but also DISTINCT).
         *
         *   - DISTINCT: Boolean: return only unique result rows.
         *
@@ -998,6 +1014,7 @@ interface IDatabase {
         * @param string $valuename
         *
         * @return string
+        * @deprecated Since 1.33
         */
        public function aggregateValue( $valuedata, $valuename = 'value' );
 
@@ -1096,6 +1113,25 @@ interface IDatabase {
                $options = [], $join_conds = []
        );
 
+       /**
+        * Construct a LIMIT query with optional offset. This is used for query
+        * pages. The SQL should be adjusted so that only the first $limit rows
+        * are returned. If $offset is provided as well, then the first $offset
+        * rows should be discarded, and the next $limit rows should be returned.
+        * If the result of the query is not ordered, then the rows to be returned
+        * are theoretically arbitrary.
+        *
+        * $sql is expected to be a SELECT, if that makes a difference.
+        *
+        * @param string $sql SQL query we will append the limit too
+        * @param int $limit The SQL limit
+        * @param int|bool $offset The SQL offset (default false)
+        * @throws DBUnexpectedError
+        * @return string
+        * @since 1.34
+        */
+       public function limitResult( $sql, $limit, $offset = false );
+
        /**
         * Returns true if DBs are assumed to be on potentially different servers
         *
@@ -1376,7 +1412,7 @@ interface IDatabase {
         * This is used for providing overload point for other DB abstractions
         * not compatible with the MySQL syntax.
         * @param array $sqls SQL statements to combine
-        * @param bool $all Use UNION ALL
+        * @param bool $all Either IDatabase::UNION_ALL or IDatabase::UNION_DISTINCT
         * @return string SQL fragment
         */
        public function unionQueries( $sqls, $all );
@@ -1541,7 +1577,6 @@ interface IDatabase {
         *
         * @param callable $callback
         * @param string $fname Caller name
-        * @return mixed
         * @since 1.28
         */
        public function onTransactionResolution( callable $callback, $fname = __METHOD__ );
@@ -1585,7 +1620,6 @@ interface IDatabase {
         *
         * @param callable $callback
         * @param string $fname
-        * @return mixed
         * @since 1.20
         * @deprecated Since 1.32
         */
@@ -1631,7 +1665,6 @@ interface IDatabase {
         *
         * @param string $name Callback name
         * @param callable|null $callback Use null to unset a listener
-        * @return mixed
         * @since 1.28
         */
        public function setTransactionListener( $name, callable $callback = null );
@@ -2159,7 +2192,6 @@ interface IDatabase {
         * the aliases can be removed, and then the old X-named indexes dropped.
         *
         * @param string[] $aliases
-        * @return mixed
         * @since 1.31
         */
        public function setIndexAliases( array $aliases );
index 8a2c795..10a0897 100644 (file)
@@ -30,6 +30,8 @@ class MaintainableDBConnRef extends DBConnRef implements IMaintainableDatabase {
                $fname = false,
                callable $inputCallback = null
        ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
@@ -40,14 +42,20 @@ class MaintainableDBConnRef extends DBConnRef implements IMaintainableDatabase {
                $fname = __METHOD__,
                callable $inputCallback = null
        ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function dropTable( $tableName, $fName = __METHOD__ ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function deadlockLoop() {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
@@ -66,6 +74,8 @@ class MaintainableDBConnRef extends DBConnRef implements IMaintainableDatabase {
        public function duplicateTableStructure(
                $oldName, $newName, $temporary = false, $fname = __METHOD__
        ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
@@ -74,10 +84,14 @@ class MaintainableDBConnRef extends DBConnRef implements IMaintainableDatabase {
        }
 
        public function lockTables( array $read, array $write, $method ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
        public function unlockTables( $method ) {
+               $this->assertRoleAllowsWrites();
+
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
diff --git a/includes/libs/rdbms/database/domain/DatabaseDomain.php b/includes/libs/rdbms/database/domain/DatabaseDomain.php
new file mode 100644 (file)
index 0000000..5dd4b49
--- /dev/null
@@ -0,0 +1,260 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Database
+ */
+namespace Wikimedia\Rdbms;
+
+use InvalidArgumentException;
+
+/**
+ * Class to handle database/prefix specification for IDatabase domains
+ */
+class DatabaseDomain {
+       /** @var string|null */
+       private $database;
+       /** @var string|null */
+       private $schema;
+       /** @var string */
+       private $prefix;
+
+       /** @var string Cache of convertToString() */
+       private $equivalentString;
+
+       /**
+        * @param string|null $database Database name
+        * @param string|null $schema Schema name
+        * @param string $prefix Table prefix
+        */
+       public function __construct( $database, $schema, $prefix ) {
+               if ( $database !== null && ( !is_string( $database ) || $database === '' ) ) {
+                       throw new InvalidArgumentException( 'Database must be null or a non-empty string.' );
+               }
+               $this->database = $database;
+               if ( $schema !== null && ( !is_string( $schema ) || $schema === '' ) ) {
+                       throw new InvalidArgumentException( 'Schema must be null or a non-empty string.' );
+               } elseif ( $database === null && $schema !== null ) {
+                       throw new InvalidArgumentException( 'Schema must be null if database is null.' );
+               }
+               $this->schema = $schema;
+               if ( !is_string( $prefix ) ) {
+                       throw new InvalidArgumentException( 'Prefix must be a string.' );
+               } elseif ( $prefix !== '' && substr( $prefix, -1, 1 ) !== '_' ) {
+                       throw new InvalidArgumentException( 'A non-empty prefix must end with "_".' );
+               }
+               $this->prefix = $prefix;
+       }
+
+       /**
+        * @param DatabaseDomain|string $domain Result of DatabaseDomain::toString()
+        * @return DatabaseDomain
+        */
+       public static function newFromId( $domain ) {
+               if ( $domain instanceof self ) {
+                       return $domain;
+               }
+
+               $parts = array_map( [ __CLASS__, 'decode' ], explode( '-', $domain ) );
+
+               $schema = null;
+               $prefix = '';
+
+               if ( count( $parts ) == 1 ) {
+                       $database = $parts[0];
+               } elseif ( count( $parts ) == 2 ) {
+                       list( $database, $prefix ) = $parts;
+               } elseif ( count( $parts ) == 3 ) {
+                       list( $database, $schema, $prefix ) = $parts;
+               } else {
+                       throw new InvalidArgumentException( "Domain '$domain' has too few or too many parts." );
+               }
+
+               if ( $database === '' ) {
+                       $database = null;
+               }
+
+               if ( $schema === '' ) {
+                       $schema = null;
+               }
+
+               return new self( $database, $schema, $prefix );
+       }
+
+       /**
+        * @return DatabaseDomain
+        */
+       public static function newUnspecified() {
+               return new self( null, null, '' );
+       }
+
+       /**
+        * @param DatabaseDomain|string $other
+        * @return bool Whether the domain instances are the same by value
+        */
+       public function equals( $other ) {
+               if ( $other instanceof self ) {
+                       return (
+                               $this->database === $other->database &&
+                               $this->schema === $other->schema &&
+                               $this->prefix === $other->prefix
+                       );
+               }
+
+               return ( $this->getId() === $other );
+       }
+
+       /**
+        * Check whether the domain $other meets the specifications of this domain
+        *
+        * If this instance has a null database specifier, then $other can have any database
+        * specifier, including null. This is likewise true if the schema specifier is null.
+        * This is not transitive like equals() since a domain that explicitly wants a certain
+        * database or schema cannot be satisfied by one of another (nor null). If the prefix
+        * is empty and the DB and schema are both null, then the entire domain is considered
+        * unspecified, and any prefix of $other is considered compatible.
+        *
+        * @param DatabaseDomain|string $other
+        * @return bool
+        * @since 1.32
+        */
+       public function isCompatible( $other ) {
+               if ( $this->isUnspecified() ) {
+                       return true; // even the prefix doesn't matter
+               }
+
+               $other = self::newFromId( $other );
+
+               return (
+                       ( $this->database === $other->database || $this->database === null ) &&
+                       ( $this->schema === $other->schema || $this->schema === null ) &&
+                       $this->prefix === $other->prefix
+               );
+       }
+
+       /**
+        * @return bool
+        * @since 1.32
+        */
+       public function isUnspecified() {
+               return (
+                       $this->database === null && $this->schema === null && $this->prefix === ''
+               );
+       }
+
+       /**
+        * @return string|null Database name
+        */
+       public function getDatabase() {
+               return $this->database;
+       }
+
+       /**
+        * @return string|null Database schema
+        */
+       public function getSchema() {
+               return $this->schema;
+       }
+
+       /**
+        * @return string Table prefix
+        */
+       public function getTablePrefix() {
+               return $this->prefix;
+       }
+
+       /**
+        * @return string
+        */
+       public function getId() {
+               if ( $this->equivalentString === null ) {
+                       $this->equivalentString = $this->convertToString();
+               }
+
+               return $this->equivalentString;
+       }
+
+       /**
+        * @return string
+        */
+       private function convertToString() {
+               $parts = [ (string)$this->database ];
+               if ( $this->schema !== null ) {
+                       $parts[] = $this->schema;
+               }
+               if ( $this->prefix != '' || $this->schema !== null ) {
+                       // If there is a schema, then we need the prefix to disambiguate.
+                       // For engines like Postgres that use schemas, this awkwardness is hopefully
+                       // avoided since it is easy to have one DB per server (to avoid having many users)
+                       // and use schema/prefix to have wiki farms. For example, a domain schemes could be
+                       // wiki-<project>-<language>, e.g. "wiki-fitness-es"/"wiki-sports-fr"/"wiki-news-en".
+                       $parts[] = $this->prefix;
+               }
+
+               return implode( '-', array_map( [ __CLASS__, 'encode' ], $parts ) );
+       }
+
+       private static function encode( $decoded ) {
+               $encoded = '';
+
+               $length = strlen( $decoded );
+               for ( $i = 0; $i < $length; ++$i ) {
+                       $char = $decoded[$i];
+                       if ( $char === '-' ) {
+                               $encoded .= '?h';
+                       } elseif ( $char === '?' ) {
+                               $encoded .= '??';
+                       } else {
+                               $encoded .= $char;
+                       }
+               }
+
+               return $encoded;
+       }
+
+       private static function decode( $encoded ) {
+               $decoded = '';
+
+               $length = strlen( $encoded );
+               for ( $i = 0; $i < $length; ++$i ) {
+                       $char = $encoded[$i];
+                       if ( $char === '?' ) {
+                               $nextChar = $encoded[$i + 1] ?? null;
+                               if ( $nextChar === 'h' ) {
+                                       $decoded .= '-';
+                                       ++$i;
+                               } elseif ( $nextChar === '?' ) {
+                                       $decoded .= '?';
+                                       ++$i;
+                               } else {
+                                       $decoded .= $char;
+                               }
+                       } else {
+                               $decoded .= $char;
+                       }
+               }
+
+               return $decoded;
+       }
+
+       /**
+        * @return string
+        */
+       function __toString() {
+               return $this->getId();
+       }
+}
index 1355e22..a9befc2 100644 (file)
@@ -69,7 +69,6 @@ class ResultWrapper implements IResultWrapper {
 
        public function free() {
                if ( $this->db ) {
-                       $this->db->freeResult( $this );
                        $this->db = null;
                }
                $this->result = null;
diff --git a/includes/libs/rdbms/database/utils/AtomicSectionIdentifier.php b/includes/libs/rdbms/database/utils/AtomicSectionIdentifier.php
new file mode 100644 (file)
index 0000000..c6e3d44
--- /dev/null
@@ -0,0 +1,27 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Database
+ */
+namespace Wikimedia\Rdbms;
+
+/**
+ * Class used for token representing identifiers for atomic sections from IDatabase instances
+ */
+class AtomicSectionIdentifier {
+}
diff --git a/includes/libs/rdbms/database/utils/GeneralizedSql.php b/includes/libs/rdbms/database/utils/GeneralizedSql.php
new file mode 100644 (file)
index 0000000..db5c639
--- /dev/null
@@ -0,0 +1,95 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Profiler
+ */
+
+namespace Wikimedia\Rdbms;
+
+/**
+ * Lazy-loaded wrapper for simplification and scrubbing of SQL queries for profiling
+ *
+ * @since 1.34
+ */
+class GeneralizedSql {
+       /** @var string */
+       private $rawSql;
+       /** @var string */
+       private $trxId;
+       /** @var string */
+       private $prefix;
+
+       /** @var string|null */
+       private $genericSql;
+
+       /**
+        * @param string $rawSql
+        * @param string $trxId
+        * @param string $prefix
+        */
+       public function __construct( $rawSql, $trxId, $prefix ) {
+               $this->rawSql = $rawSql;
+               $this->trxId = $trxId;
+               $this->prefix = $prefix;
+       }
+
+       /**
+        * Removes most variables from an SQL query and replaces them with X or N for numbers.
+        * It's only slightly flawed. Don't use for anything important.
+        *
+        * @param string $sql A SQL Query
+        *
+        * @return string
+        */
+       private static function generalizeSQL( $sql ) {
+               # This does the same as the regexp below would do, but in such a way
+               # as to avoid crashing php on some large strings.
+               # $sql = preg_replace( "/'([^\\\\']|\\\\.)*'|\"([^\\\\\"]|\\\\.)*\"/", "'X'", $sql );
+
+               $sql = str_replace( "\\\\", '', $sql );
+               $sql = str_replace( "\\'", '', $sql );
+               $sql = str_replace( "\\\"", '', $sql );
+               $sql = preg_replace( "/'.*'/s", "'X'", $sql );
+               $sql = preg_replace( '/".*"/s', "'X'", $sql );
+
+               # All newlines, tabs, etc replaced by single space
+               $sql = preg_replace( '/\s+/', ' ', $sql );
+
+               # All numbers => N,
+               # except the ones surrounded by characters, e.g. l10n
+               $sql = preg_replace( '/-?\d+(,-?\d+)+/s', 'N,...,N', $sql );
+               $sql = preg_replace( '/(?<![a-zA-Z])-?\d+(?![a-zA-Z])/s', 'N', $sql );
+
+               return $sql;
+       }
+
+       /**
+        * @return string
+        */
+       public function stringify() {
+               if ( $this->genericSql !== null ) {
+                       return $this->genericSql;
+               }
+
+               $this->genericSql = $this->prefix .
+                       substr( self::generalizeSQL( $this->rawSql ), 0, 255 ) .
+                       ( $this->trxId ? " [TRX#{$this->trxId}]" : "" );
+
+               return $this->genericSql;
+       }
+}
diff --git a/includes/libs/rdbms/database/utils/SavepointPostgres.php b/includes/libs/rdbms/database/utils/SavepointPostgres.php
deleted file mode 100644 (file)
index edbcdfe..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-<?php
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Database
- */
-
-namespace Wikimedia\Rdbms;
-
-use Psr\Log\LoggerInterface;
-
-/**
- * Manage savepoints within a transaction
- * @ingroup Database
- * @since 1.19
- * @deprecated since 1.31, use IDatabase::startAtomic() and such instead.
- */
-class SavepointPostgres {
-       /** @var DatabasePostgres Establish a savepoint within a transaction */
-       protected $dbw;
-       /** @var LoggerInterface */
-       protected $logger;
-       /** @var int */
-       protected $id;
-       /** @var bool */
-       protected $didbegin;
-
-       /**
-        * @param DatabasePostgres $dbw
-        * @param int $id
-        * @param LoggerInterface $logger
-        */
-       public function __construct( DatabasePostgres $dbw, $id, LoggerInterface $logger ) {
-               $this->dbw = $dbw;
-               $this->logger = $logger;
-               $this->id = $id;
-               $this->didbegin = false;
-               /* If we are not in a transaction, we need to be for savepoint trickery */
-               if ( !$dbw->trxLevel() ) {
-                       $dbw->begin( __CLASS__, DatabasePostgres::TRANSACTION_INTERNAL );
-                       $this->didbegin = true;
-               }
-       }
-
-       public function __destruct() {
-               if ( $this->didbegin ) {
-                       $this->dbw->rollback();
-                       $this->didbegin = false;
-               }
-       }
-
-       public function commit() {
-               if ( $this->didbegin ) {
-                       $this->dbw->commit( __CLASS__, DatabasePostgres::FLUSHING_INTERNAL );
-                       $this->didbegin = false;
-               }
-       }
-
-       protected function query( $keyword, $msg_ok, $msg_failed ) {
-               if ( $this->dbw->doQuery( $keyword . " " . $this->id ) !== false ) {
-                       $this->logger->debug( sprintf( $msg_ok, $this->id ) );
-               } else {
-                       $this->logger->debug( sprintf( $msg_failed, $this->id ) );
-               }
-       }
-
-       public function savepoint() {
-               $this->query( "SAVEPOINT",
-                       "Transaction state: savepoint \"%s\" established.\n",
-                       "Transaction state: establishment of savepoint \"%s\" FAILED.\n"
-               );
-       }
-
-       public function release() {
-               $this->query( "RELEASE",
-                       "Transaction state: savepoint \"%s\" released.\n",
-                       "Transaction state: release of savepoint \"%s\" FAILED.\n"
-               );
-       }
-
-       public function rollback() {
-               $this->query( "ROLLBACK TO",
-                       "Transaction state: savepoint \"%s\" rolled back.\n",
-                       "Transaction state: rollback of savepoint \"%s\" FAILED.\n"
-               );
-       }
-
-       public function __toString() {
-               return (string)$this->id;
-       }
-}
index 8e68aba..1819a9a 100644 (file)
@@ -6,15 +6,13 @@ class MssqlBlob extends Blob {
        /** @noinspection PhpMissingParentConstructorInspection */
 
        /**
-        * @param string $data
+        * @param Blob|string $data
         */
        public function __construct( $data ) {
                if ( $data instanceof MssqlBlob ) {
-                       return $data;
+                       $this->data = $data->data;
                } elseif ( $data instanceof Blob ) {
                        $this->data = $data->fetch();
-               } elseif ( is_array( $data ) && is_object( $data ) ) {
-                       $this->data = serialize( $data );
                } else {
                        $this->data = $data;
                }
diff --git a/includes/libs/rdbms/exception/DBQueryDisconnectedError.php b/includes/libs/rdbms/exception/DBQueryDisconnectedError.php
new file mode 100644 (file)
index 0000000..a142b4a
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Database
+ */
+
+namespace Wikimedia\Rdbms;
+
+/**
+ * @ingroup Database
+ * @since 1.34
+ */
+class DBQueryDisconnectedError extends DBQueryError {
+
+}
index b1353b7..9b664fc 100644 (file)
@@ -45,7 +45,7 @@ class DBQueryError extends DBExpectedError {
        public function __construct( IDatabase $db, $error, $errno, $sql, $fname, $message = null ) {
                if ( $message === null ) {
                        if ( $db instanceof Database && $db->wasConnectionError( $errno ) ) {
-                               $message = "A connection error occurred. \n" .
+                               $message = "A connection error occurred during a query. \n" .
                                         "Query: $sql\n" .
                                         "Function: $fname\n" .
                                         "Error: $errno $error\n";
diff --git a/includes/libs/rdbms/exception/DBReadOnlyRoleError.php b/includes/libs/rdbms/exception/DBReadOnlyRoleError.php
new file mode 100644 (file)
index 0000000..4d565ba
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Database
+ */
+
+namespace Wikimedia\Rdbms;
+
+/**
+ * Exception class for attempted DB write access to a DBConnRef with the DB_REPLICA role
+ *
+ * @ingroup Database
+ */
+class DBReadOnlyRoleError extends DBUnexpectedError {
+}
index 98c06ad..c5dbfc5 100644 (file)
@@ -57,6 +57,7 @@ interface ILBFactory {
         *  - perfLogger: PSR-3 logger instance. [optional]
         *  - errorLogger: Callback that takes an Exception and logs it. [optional]
         *  - deprecationLogger: Callback to log a deprecation warning. [optional]
+        *  - secret: Secret string to use for HMAC hashing [optional]
         * @throws InvalidArgumentException
         */
        public function __construct( array $conf );
@@ -356,6 +357,14 @@ interface ILBFactory {
         */
        public function appendShutdownCPIndexAsQuery( $url, $index );
 
+       /**
+        * Get the client ID of the ChronologyProtector instance
+        *
+        * @return string Client ID
+        * @since 1.34
+        */
+       public function getChronologyProtectorClientId();
+
        /**
         * @param array $info Map of fields, including:
         *   - IPAddress : IP address
@@ -390,7 +399,6 @@ interface ILBFactory {
         * the aliases can be removed, and then the old X-named indexes dropped.
         *
         * @param string[] $aliases
-        * @return mixed
         * @since 1.31
         */
        public function setIndexAliases( array $aliases );
index 9ec1ce1..bf10053 100644 (file)
@@ -24,6 +24,7 @@
 namespace Wikimedia\Rdbms;
 
 use Psr\Log\LoggerInterface;
+use Psr\Log\NullLogger;
 use Wikimedia\ScopedCallback;
 use BagOStuff;
 use EmptyBagOStuff;
@@ -74,6 +75,8 @@ abstract class LBFactory implements ILBFactory {
        private $cliMode;
        /** @var string Agent name for query profiling */
        private $agent;
+       /** @var string Secret string for HMAC hashing */
+       private $secret;
 
        /** @var array[] $aliases Map of (table => (dbname, schema, prefix) map) */
        private $tableAliases = [];
@@ -123,7 +126,7 @@ abstract class LBFactory implements ILBFactory {
                $this->wanCache = $conf['wanCache'] ?? WANObjectCache::newEmpty();
 
                foreach ( self::$loggerFields as $key ) {
-                       $this->$key = $conf[$key] ?? new \Psr\Log\NullLogger();
+                       $this->$key = $conf[$key] ?? new NullLogger();
                }
                $this->errorLogger = $conf['errorLogger'] ?? function ( Exception $e ) {
                        trigger_error( get_class( $e ) . ': ' . $e->getMessage(), E_USER_WARNING );
@@ -148,6 +151,7 @@ abstract class LBFactory implements ILBFactory {
                $this->hostname = $conf['hostname'] ?? gethostname();
                $this->agent = $conf['agent'] ?? '';
                $this->defaultGroup = $conf['defaultGroup'] ?? null;
+               $this->secret = $conf['secret'] ?? '';
 
                $this->ticket = mt_rand();
        }
@@ -399,7 +403,7 @@ abstract class LBFactory implements ILBFactory {
                                $lbs[] = $lb;
                        } );
                        if ( !$lbs ) {
-                               return; // nothing actually used
+                               return true; // nothing actually used
                        }
                }
 
@@ -463,7 +467,7 @@ abstract class LBFactory implements ILBFactory {
                        $this->perfLogger->error( __METHOD__ . ": $fname does not have outer scope.\n" .
                                ( new RuntimeException() )->getTraceAsString() );
 
-                       return;
+                       return false;
                }
 
                // The transaction owner and any caller with the empty transaction ticket can commit
@@ -482,6 +486,7 @@ abstract class LBFactory implements ILBFactory {
                if ( $fnameEffective !== $fname ) {
                        $this->beginMasterChanges( $fnameEffective );
                }
+
                return $waitSucceeded;
        }
 
@@ -508,7 +513,8 @@ abstract class LBFactory implements ILBFactory {
                                'agent' => $this->requestInfo['UserAgent'],
                                'clientId' => $this->requestInfo['ChronologyClientId']
                        ],
-                       $this->requestInfo['ChronologyPositionIndex']
+                       $this->requestInfo['ChronologyPositionIndex'],
+                       $this->secret
                );
                $this->chronProt->setLogger( $this->replLogger );
 
@@ -634,7 +640,7 @@ abstract class LBFactory implements ILBFactory {
        public function setLocalDomainPrefix( $prefix ) {
                $this->localDomain = new DatabaseDomain(
                        $this->localDomain->getDatabase(),
-                       null,
+                       $this->localDomain->getSchema(),
                        $prefix
                );
 
@@ -654,7 +660,7 @@ abstract class LBFactory implements ILBFactory {
        }
 
        public function closeAll() {
-               $this->forEachLBCallMethod( 'closeAll', [] );
+               $this->forEachLBCallMethod( 'closeAll' );
        }
 
        public function setAgentName( $agent ) {
@@ -674,6 +680,10 @@ abstract class LBFactory implements ILBFactory {
                return strpos( $url, '?' ) === false ? "$url?cpPosIndex=$index" : "$url&cpPosIndex=$index";
        }
 
+       public function getChronologyProtectorClientId() {
+               return $this->getChronologyProtector()->getClientId();
+       }
+
        /**
         * @param int $index Write index
         * @param int $time UNIX timestamp; can be used to detect stale cookies (T190082)
index 189ceee..aec99f4 100644 (file)
@@ -89,9 +89,6 @@ class LBFactoryMulti extends LBFactory {
         */
        private $readOnlyBySection = [];
 
-       /** @var array Load balancer factory configuration */
-       private $conf;
-
        /** @var LoadBalancer[] */
        private $mainLBs = [];
 
@@ -166,7 +163,6 @@ class LBFactoryMulti extends LBFactory {
        public function __construct( array $conf ) {
                parent::__construct( $conf );
 
-               $this->conf = $conf;
                $required = [ 'sectionsByDB', 'sectionLoads', 'serverTemplate' ];
                $optional = [ 'groupLoadsBySection', 'groupLoadsByDB', 'hostsByName',
                        'externalLoads', 'externalTemplateOverrides', 'templateOverridesByServer',
index b20bf04..52d8370 100644 (file)
@@ -291,13 +291,13 @@ interface ILoadBalancer {
         *
         * @see ILoadBalancer::getConnection() for parameter information
         *
-        * @param int $db Server index or DB_MASTER/DB_REPLICA
+        * @param int $i Server index or DB_MASTER/DB_REPLICA
         * @param array|string|bool $groups Query group(s), or false for the generic reader
         * @param string|bool $domain Domain ID, or false for the current domain
         * @param int $flags Bitfield of CONN_* class constants (e.g. CONN_TRX_AUTOCOMMIT)
         * @return MaintainableDBConnRef
         */
-       public function getMaintenanceConnectionRef( $db, $groups = [], $domain = false, $flags = 0 );
+       public function getMaintenanceConnectionRef( $i, $groups = [], $domain = false, $flags = 0 );
 
        /**
         * Open a connection to the server given by the specified index
@@ -680,7 +680,6 @@ interface ILoadBalancer {
         * the aliases can be removed, and then the old X-named indexes dropped.
         *
         * @param string[] $aliases
-        * @return mixed
         * @since 1.31
         */
        public function setIndexAliases( array $aliases );
index 9e4b15f..da5382a 100644 (file)
@@ -487,10 +487,8 @@ class LoadBalancer implements ILoadBalancer {
                        $this->waitForPos = $pos;
                        // If a generic reader connection was already established, then wait now
                        $i = $this->readIndex;
-                       if ( $i > 0 ) {
-                               if ( !$this->doWait( $i ) ) {
-                                       $this->laggedReplicaMode = true;
-                               }
+                       if ( ( $i > 0 ) && !$this->doWait( $i ) ) {
+                               $this->laggedReplicaMode = true;
                        }
                } finally {
                        // Restore the older position if it was higher since this is used for lag-protection
@@ -566,15 +564,24 @@ class LoadBalancer implements ILoadBalancer {
        }
 
        public function getAnyOpenConnection( $i, $flags = 0 ) {
+               $i = ( $i === self::DB_MASTER ) ? $this->getWriterIndex() : $i;
                $autocommit = ( ( $flags & self::CONN_TRX_AUTOCOMMIT ) == self::CONN_TRX_AUTOCOMMIT );
+
                foreach ( $this->conns as $connsByServer ) {
-                       if ( !isset( $connsByServer[$i] ) ) {
-                               continue;
+                       if ( $i === self::DB_REPLICA ) {
+                               $indexes = array_keys( $connsByServer );
+                       } else {
+                               $indexes = isset( $connsByServer[$i] ) ? [ $i ] : [];
                        }
 
-                       foreach ( $connsByServer[$i] as $conn ) {
-                               if ( !$autocommit || $conn->getLBInfo( 'autoCommitOnly' ) ) {
-                                       return $conn;
+                       foreach ( $indexes as $index ) {
+                               foreach ( $connsByServer[$index] as $conn ) {
+                                       if ( !$conn->isOpen() ) {
+                                               continue; // some sort of error occured?
+                                       }
+                                       if ( !$autocommit || $conn->getLBInfo( 'autoCommitOnly' ) ) {
+                                               return $conn;
+                                       }
                                }
                        }
                }
@@ -827,23 +834,36 @@ class LoadBalancer implements ILoadBalancer {
                }
        }
 
-       public function getConnectionRef( $db, $groups = [], $domain = false, $flags = 0 ) {
+       public function getConnectionRef( $i, $groups = [], $domain = false, $flags = 0 ) {
                $domain = $this->resolveDomainID( $domain );
+               $role = $this->getRoleFromIndex( $i );
 
-               return new DBConnRef( $this, $this->getConnection( $db, $groups, $domain, $flags ) );
+               return new DBConnRef( $this, $this->getConnection( $i, $groups, $domain, $flags ), $role );
        }
 
-       public function getLazyConnectionRef( $db, $groups = [], $domain = false, $flags = 0 ) {
+       public function getLazyConnectionRef( $i, $groups = [], $domain = false, $flags = 0 ) {
                $domain = $this->resolveDomainID( $domain );
+               $role = $this->getRoleFromIndex( $i );
 
-               return new DBConnRef( $this, [ $db, $groups, $domain, $flags ] );
+               return new DBConnRef( $this, [ $i, $groups, $domain, $flags ], $role );
        }
 
-       public function getMaintenanceConnectionRef( $db, $groups = [], $domain = false, $flags = 0 ) {
+       public function getMaintenanceConnectionRef( $i, $groups = [], $domain = false, $flags = 0 ) {
                $domain = $this->resolveDomainID( $domain );
+               $role = $this->getRoleFromIndex( $i );
 
                return new MaintainableDBConnRef(
-                       $this, $this->getConnection( $db, $groups, $domain, $flags ) );
+                       $this, $this->getConnection( $i, $groups, $domain, $flags ), $role );
+       }
+
+       /**
+        * @param int $i Server index or DB_MASTER/DB_REPLICA
+        * @return int One of DB_MASTER/DB_REPLICA
+        */
+       private function getRoleFromIndex( $i ) {
+               return ( $i === self::DB_MASTER || $i === $this->getWriterIndex() )
+                       ? self::DB_MASTER
+                       : self::DB_REPLICA;
        }
 
        public function openConnection( $i, $domain = false, $flags = 0 ) {
@@ -1018,7 +1038,7 @@ class LoadBalancer implements ILoadBalancer {
                                }
                                unset( $this->conns[$connFreeKey][$i][$oldDomain] );
                                // Note that if $domain is an empty string, getDomainID() might not match it
-                               $this->conns[$connInUseKey][$i][$conn->getDomainId()] = $conn;
+                               $this->conns[$connInUseKey][$i][$conn->getDomainID()] = $conn;
                                $this->connLogger->debug( __METHOD__ .
                                        ": reusing free connection from $oldDomain for $domain" );
                                break;
index aa60242..9a8086f 100644 (file)
@@ -245,13 +245,11 @@ class RedisConnectionPool implements LoggerAwareInterface {
 
                                return false;
                        }
-                       if ( $this->password !== null ) {
-                               if ( !$conn->auth( $this->password ) ) {
-                                       $logger->error(
-                                               'Authentication error connecting to "{redis_server}"',
-                                               [ 'redis_server' => $server ]
-                                       );
-                               }
+                       if ( ( $this->password !== null ) && !$conn->auth( $this->password ) ) {
+                               $logger->error(
+                                       'Authentication error connecting to "{redis_server}"',
+                                       [ 'redis_server' => $server ]
+                               );
                        }
                } catch ( RedisException $e ) {
                        $this->downServers[$server] = time() + self::SERVER_DOWN_TTL;
@@ -364,15 +362,13 @@ class RedisConnectionPool implements LoggerAwareInterface {
         * @return bool Success
         */
        public function reauthenticateConnection( $server, Redis $conn ) {
-               if ( $this->password !== null ) {
-                       if ( !$conn->auth( $this->password ) ) {
-                               $this->logger->error(
-                                       'Authentication error connecting to "{redis_server}"',
-                                       [ 'redis_server' => $server ]
-                               );
+               if ( $this->password !== null && !$conn->auth( $this->password ) ) {
+                       $this->logger->error(
+                               'Authentication error connecting to "{redis_server}"',
+                               [ 'redis_server' => $server ]
+                       );
 
-                               return false;
-                       }
+                       return false;
                }
 
                return true;
index 59e5c4b..25d1d6a 100644 (file)
@@ -399,7 +399,7 @@ class ServiceContainer implements DestructibleService {
         * @throws ContainerDisabledException if this container has already been destroyed.
         * @throws ServiceDisabledException if the requested service has been disabled.
         *
-        * @return object The service instance
+        * @return mixed The service instance
         */
        public function getService( $name ) {
                if ( $this->destroyed ) {
index 61efba0..c90cea9 100644 (file)
@@ -43,28 +43,19 @@ class PageDataRequestHandler {
         */
        public function canHandleRequest( $subPage, WebRequest $request ) {
                if ( $subPage === '' || $subPage === null ) {
-                       if ( $request->getText( 'target', '' ) === '' ) {
-                               return false;
-                       } else {
-                               return true;
-                       }
+                       return $request->getText( 'target' ) !== '';
                }
 
                $parts = explode( '/', $subPage, 2 );
-               if ( $parts !== 2 ) {
-                       $slot = $parts[0];
-                       if ( $slot === 'main' || $slot === '' ) {
-                               return true;
-                       }
-               }
-
-               return false;
+               $slot = $parts[0];
+               $title = $parts[1] ?? '';
+               return ( $slot === 'main' || $slot === '' ) && $title !== '';
        }
 
        /**
         * Main method for handling requests.
         *
-        * @param string $subPage
+        * @param string|null $subPage
         * @param WebRequest $request The request parameters. Known parameters are:
         *        - title: the page title
         *        - format: the format
@@ -86,11 +77,11 @@ class PageDataRequestHandler {
 
                $revision = 0;
 
-               $parts = explode( '/', $subPage, 2 );
                if ( $subPage !== '' ) {
-                       $title = $parts[1];
+                       $parts = explode( '/', $subPage, 2 );
+                       $title = $parts[1] ?? '';
                } else {
-                       $title = $request->getText( 'target', '' );
+                       $title = $request->getText( 'target' );
                }
 
                $revision = $request->getInt( 'oldid', $revision );
@@ -145,7 +136,7 @@ class PageDataRequestHandler {
                }
 
                $negotiator = new HttpAcceptNegotiator( $mimeTypes );
-               $format = $negotiator->getBestSupportedKey( $accept, null );
+               $format = $negotiator->getBestSupportedKey( $accept );
 
                if ( $format === null ) {
                        $format = isset( $accept['text/html'] ) ? 'text/html' : null;
index d096b00..707c382 100644 (file)
@@ -27,7 +27,7 @@ use HtmlArmor;
 use LinkCache;
 use Linker;
 use MediaWiki\MediaWikiServices;
-use MWNamespace;
+use NamespaceInfo;
 use Sanitizer;
 use Title;
 use TitleFormatter;
@@ -69,6 +69,11 @@ class LinkRenderer {
         */
        private $linkCache;
 
+       /**
+        * @var NamespaceInfo
+        */
+       private $nsInfo;
+
        /**
         * Whether to run the legacy Linker hooks
         *
@@ -79,10 +84,14 @@ class LinkRenderer {
        /**
         * @param TitleFormatter $titleFormatter
         * @param LinkCache $linkCache
+        * @param NamespaceInfo $nsInfo
         */
-       public function __construct( TitleFormatter $titleFormatter, LinkCache $linkCache ) {
+       public function __construct(
+               TitleFormatter $titleFormatter, LinkCache $linkCache, NamespaceInfo $nsInfo
+       ) {
                $this->titleFormatter = $titleFormatter;
                $this->linkCache = $linkCache;
+               $this->nsInfo = $nsInfo;
        }
 
        /**
@@ -293,7 +302,7 @@ class LinkRenderer {
                return $this->makePreloadedLink(
                        $target,
                        $text,
-                       $classes ? implode( ' ', $classes ) : '',
+                       implode( ' ', $classes ),
                        $extraAttribs,
                        $query
                );
@@ -468,8 +477,9 @@ class LinkRenderer {
                if ( $this->linkCache->getGoodLinkFieldObj( $target, 'redirect' ) ) {
                        # Page is a redirect
                        return 'mw-redirect';
-               } elseif ( $this->stubThreshold > 0 && MWNamespace::isContent( $target->getNamespace() )
-                       && $this->linkCache->getGoodLinkFieldObj( $target, 'length' ) < $this->stubThreshold
+               } elseif (
+                       $this->stubThreshold > 0 && $this->nsInfo->isContent( $target->getNamespace() ) &&
+                       $this->linkCache->getGoodLinkFieldObj( $target, 'length' ) < $this->stubThreshold
                ) {
                        # Page is a stub
                        return 'stub';
index 240ea09..eeb28b5 100644 (file)
@@ -21,6 +21,7 @@
 namespace MediaWiki\Linker;
 
 use LinkCache;
+use NamespaceInfo;
 use TitleFormatter;
 use User;
 
@@ -40,20 +41,29 @@ class LinkRendererFactory {
         */
        private $linkCache;
 
+       /**
+        * @var NamespaceInfo
+        */
+       private $nsInfo;
+
        /**
         * @param TitleFormatter $titleFormatter
         * @param LinkCache $linkCache
+        * @param NamespaceInfo $nsInfo
         */
-       public function __construct( TitleFormatter $titleFormatter, LinkCache $linkCache ) {
+       public function __construct(
+               TitleFormatter $titleFormatter, LinkCache $linkCache, NamespaceInfo $nsInfo
+       ) {
                $this->titleFormatter = $titleFormatter;
                $this->linkCache = $linkCache;
+               $this->nsInfo = $nsInfo;
        }
 
        /**
         * @return LinkRenderer
         */
        public function create() {
-               return new LinkRenderer( $this->titleFormatter, $this->linkCache );
+               return new LinkRenderer( $this->titleFormatter, $this->linkCache, $this->nsInfo );
        }
 
        /**
diff --git a/includes/logging/DatabaseLogEntry.php b/includes/logging/DatabaseLogEntry.php
new file mode 100644 (file)
index 0000000..db0f599
--- /dev/null
@@ -0,0 +1,231 @@
+<?php
+/**
+ * Contains a class for dealing with database log entries
+ *
+ * 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
+ * @author Niklas Laxström
+ * @license GPL-2.0-or-later
+ * @since 1.19
+ */
+
+use Wikimedia\Rdbms\IDatabase;
+
+/**
+ * A value class to process existing log entries. In other words, this class caches a log
+ * entry from the database and provides an immutable object-oriented representation of it.
+ *
+ * @since 1.19
+ */
+class DatabaseLogEntry extends LogEntryBase {
+
+       /**
+        * Returns array of information that is needed for querying
+        * log entries. Array contains the following keys:
+        * tables, fields, conds, options and join_conds
+        *
+        * @return array
+        */
+       public static function getSelectQueryData() {
+               $commentQuery = CommentStore::getStore()->getJoin( 'log_comment' );
+               $actorQuery = ActorMigration::newMigration()->getJoin( 'log_user' );
+
+               $tables = array_merge(
+                       [ 'logging' ], $commentQuery['tables'], $actorQuery['tables'], [ 'user' ]
+               );
+               $fields = [
+                       'log_id', 'log_type', 'log_action', 'log_timestamp',
+                       'log_namespace', 'log_title', // unused log_page
+                       'log_params', 'log_deleted',
+                       'user_id', 'user_name', 'user_editcount',
+               ] + $commentQuery['fields'] + $actorQuery['fields'];
+
+               $joins = [
+                       // IPs don't have an entry in user table
+                       'user' => [ 'LEFT JOIN', 'user_id=' . $actorQuery['fields']['log_user'] ],
+               ] + $commentQuery['joins'] + $actorQuery['joins'];
+
+               return [
+                       'tables' => $tables,
+                       'fields' => $fields,
+                       'conds' => [],
+                       'options' => [],
+                       'join_conds' => $joins,
+               ];
+       }
+
+       /**
+        * Constructs new LogEntry from database result row.
+        * Supports rows from both logging and recentchanges table.
+        *
+        * @param stdClass|array $row
+        * @return DatabaseLogEntry
+        */
+       public static function newFromRow( $row ) {
+               $row = (object)$row;
+               if ( isset( $row->rc_logid ) ) {
+                       return new RCDatabaseLogEntry( $row );
+               } else {
+                       return new self( $row );
+               }
+       }
+
+       /**
+        * Loads a LogEntry with the given id from database
+        *
+        * @param int $id
+        * @param IDatabase $db
+        * @return DatabaseLogEntry|null
+        */
+       public static function newFromId( $id, IDatabase $db ) {
+               $queryInfo = self::getSelectQueryData();
+               $queryInfo['conds'] += [ 'log_id' => $id ];
+               $row = $db->selectRow(
+                       $queryInfo['tables'],
+                       $queryInfo['fields'],
+                       $queryInfo['conds'],
+                       __METHOD__,
+                       $queryInfo['options'],
+                       $queryInfo['join_conds']
+               );
+               if ( !$row ) {
+                       return null;
+               }
+               return self::newFromRow( $row );
+       }
+
+       /** @var stdClass Database result row. */
+       protected $row;
+
+       /** @var User */
+       protected $performer;
+
+       /** @var array Parameters for log entry */
+       protected $params;
+
+       /** @var int A rev id associated to the log entry */
+       protected $revId = null;
+
+       /** @var bool Whether the parameters for this log entry are stored in new or old format. */
+       protected $legacy;
+
+       protected function __construct( $row ) {
+               $this->row = $row;
+       }
+
+       /**
+        * Returns the unique database id.
+        *
+        * @return int
+        */
+       public function getId() {
+               return (int)$this->row->log_id;
+       }
+
+       /**
+        * Returns whatever is stored in the database field.
+        *
+        * @return string
+        */
+       protected function getRawParameters() {
+               return $this->row->log_params;
+       }
+
+       public function isLegacy() {
+               // This extracts the property
+               $this->getParameters();
+               return $this->legacy;
+       }
+
+       public function getType() {
+               return $this->row->log_type;
+       }
+
+       public function getSubtype() {
+               return $this->row->log_action;
+       }
+
+       public function getParameters() {
+               if ( !isset( $this->params ) ) {
+                       $blob = $this->getRawParameters();
+                       Wikimedia\suppressWarnings();
+                       $params = LogEntryBase::extractParams( $blob );
+                       Wikimedia\restoreWarnings();
+                       if ( $params !== false ) {
+                               $this->params = $params;
+                               $this->legacy = false;
+                       } else {
+                               $this->params = LogPage::extractParams( $blob );
+                               $this->legacy = true;
+                       }
+
+                       if ( isset( $this->params['associated_rev_id'] ) ) {
+                               $this->revId = $this->params['associated_rev_id'];
+                               unset( $this->params['associated_rev_id'] );
+                       }
+               }
+
+               return $this->params;
+       }
+
+       public function getAssociatedRevId() {
+               // This extracts the property
+               $this->getParameters();
+               return $this->revId;
+       }
+
+       public function getPerformer() {
+               if ( !$this->performer ) {
+                       $actorId = isset( $this->row->log_actor ) ? (int)$this->row->log_actor : 0;
+                       $userId = (int)$this->row->log_user;
+                       if ( $userId !== 0 || $actorId !== 0 ) {
+                               // logged-in users
+                               if ( isset( $this->row->user_name ) ) {
+                                       $this->performer = User::newFromRow( $this->row );
+                               } elseif ( $actorId !== 0 ) {
+                                       $this->performer = User::newFromActorId( $actorId );
+                               } else {
+                                       $this->performer = User::newFromId( $userId );
+                               }
+                       } else {
+                               // IP users
+                               $userText = $this->row->log_user_text;
+                               $this->performer = User::newFromName( $userText, false );
+                       }
+               }
+
+               return $this->performer;
+       }
+
+       public function getTarget() {
+               $namespace = $this->row->log_namespace;
+               $page = $this->row->log_title;
+               return Title::makeTitle( $namespace, $page );
+       }
+
+       public function getTimestamp() {
+               return wfTimestamp( TS_MW, $this->row->log_timestamp );
+       }
+
+       public function getComment() {
+               return CommentStore::getStore()->getComment( 'log_comment', $this->row )->text;
+       }
+
+       public function getDeleted() {
+               return $this->row->log_deleted;
+       }
+}
diff --git a/includes/logging/LegacyLogFormatter.php b/includes/logging/LegacyLogFormatter.php
new file mode 100644 (file)
index 0000000..61104db
--- /dev/null
@@ -0,0 +1,127 @@
+<?php
+/**
+ * Contains a class for formatting log legacy entries
+ *
+ * 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
+ * @author Niklas Laxström
+ * @license GPL-2.0-or-later
+ * @since 1.19
+ */
+
+/**
+ * This class formats all log entries for log types
+ * which have not been converted to the new system.
+ * This is not about old log entries which store
+ * parameters in a different format - the new
+ * LogFormatter classes have code to support formatting
+ * those too.
+ * @since 1.19
+ */
+class LegacyLogFormatter extends LogFormatter {
+       /**
+        * Backward compatibility for extension changing the comment from
+        * the LogLine hook. This will be set by the first call on getComment(),
+        * then it might be modified by the hook when calling getActionLinks(),
+        * so that the modified value will be returned when calling getComment()
+        * a second time.
+        *
+        * @var string|null
+        */
+       private $comment = null;
+
+       /**
+        * Cache for the result of getActionLinks() so that it does not need to
+        * run multiple times depending on the order that getComment() and
+        * getActionLinks() are called.
+        *
+        * @var string|null
+        */
+       private $revert = null;
+
+       public function getComment() {
+               if ( $this->comment === null ) {
+                       $this->comment = parent::getComment();
+               }
+
+               // Make sure we execute the LogLine hook so that we immediately return
+               // the correct value.
+               if ( $this->revert === null ) {
+                       $this->getActionLinks();
+               }
+
+               return $this->comment;
+       }
+
+       /**
+        * @return string
+        * @return-taint onlysafefor_html
+        */
+       protected function getActionMessage() {
+               $entry = $this->entry;
+               $action = LogPage::actionText(
+                       $entry->getType(),
+                       $entry->getSubtype(),
+                       $entry->getTarget(),
+                       $this->plaintext ? null : $this->context->getSkin(),
+                       (array)$entry->getParameters(),
+                       !$this->plaintext // whether to filter [[]] links
+               );
+
+               $performer = $this->getPerformerElement();
+               if ( !$this->irctext ) {
+                       $sep = $this->msg( 'word-separator' );
+                       $sep = $this->plaintext ? $sep->text() : $sep->escaped();
+                       $action = $performer . $sep . $action;
+               }
+
+               return $action;
+       }
+
+       public function getActionLinks() {
+               if ( $this->revert !== null ) {
+                       return $this->revert;
+               }
+
+               if ( $this->entry->isDeleted( LogPage::DELETED_ACTION ) ) {
+                       $this->revert = '';
+                       return $this->revert;
+               }
+
+               $title = $this->entry->getTarget();
+               $type = $this->entry->getType();
+               $subtype = $this->entry->getSubtype();
+
+               // Do nothing. The implementation is handled by the hook modifiying the
+               // passed-by-ref parameters. This also changes the default value so that
+               // getComment() and getActionLinks() do not call them indefinitely.
+               $this->revert = '';
+
+               // This is to populate the $comment member of this instance so that it
+               // can be modified when calling the hook just below.
+               if ( $this->comment === null ) {
+                       $this->getComment();
+               }
+
+               $params = $this->entry->getParameters();
+
+               Hooks::run( 'LogLine', [ $type, $subtype, $title, $params,
+                       &$this->comment, &$this->revert, $this->entry->getTimestamp() ] );
+
+               return $this->revert;
+       }
+}
index 33dd69b..17f72bd 100644 (file)
@@ -1,11 +1,6 @@
 <?php
 /**
- * Contain classes for dealing with individual log entries
- *
- * This is how I see the log system history:
- * - appending to plain wiki pages
- * - formatting log entries based on database fields
- * - user is now part of the action message
+ * Contains a class for dealing with individual log entries
  *
  * 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
  * @since 1.19
  */
 
-use MediaWiki\ChangeTags\Taggable;
-use MediaWiki\Linker\LinkTarget;
-use MediaWiki\User\UserIdentity;
-use Wikimedia\Rdbms\IDatabase;
-use Wikimedia\Assert\Assert;
-
 /**
  * Interface for log entries. Every log entry has these methods.
  *
@@ -100,7 +89,7 @@ interface LogEntry {
        /**
         * Get the access restriction.
         *
-        * @return string
+        * @return int
         */
        public function getDeleted();
 
@@ -110,789 +99,3 @@ interface LogEntry {
         */
        public function isDeleted( $field );
 }
-
-/**
- * Extends the LogEntryInterface with some basic functionality
- *
- * @since 1.19
- */
-abstract class LogEntryBase implements LogEntry {
-
-       public function getFullType() {
-               return $this->getType() . '/' . $this->getSubtype();
-       }
-
-       public function isDeleted( $field ) {
-               return ( $this->getDeleted() & $field ) === $field;
-       }
-
-       /**
-        * Whether the parameters for this log are stored in new or
-        * old format.
-        *
-        * @return bool
-        */
-       public function isLegacy() {
-               return false;
-       }
-
-       /**
-        * Create a blob from a parameter array
-        *
-        * @since 1.26
-        * @param array $params
-        * @return string
-        */
-       public static function makeParamBlob( $params ) {
-               return serialize( (array)$params );
-       }
-
-       /**
-        * Extract a parameter array from a blob
-        *
-        * @since 1.26
-        * @param string $blob
-        * @return array
-        */
-       public static function extractParams( $blob ) {
-               return unserialize( $blob );
-       }
-}
-
-/**
- * A value class to process existing log entries. In other words, this class caches a log
- * entry from the database and provides an immutable object-oriented representation of it.
- *
- * @since 1.19
- */
-class DatabaseLogEntry extends LogEntryBase {
-
-       /**
-        * Returns array of information that is needed for querying
-        * log entries. Array contains the following keys:
-        * tables, fields, conds, options and join_conds
-        *
-        * @return array
-        */
-       public static function getSelectQueryData() {
-               $commentQuery = CommentStore::getStore()->getJoin( 'log_comment' );
-               $actorQuery = ActorMigration::newMigration()->getJoin( 'log_user' );
-
-               $tables = array_merge(
-                       [ 'logging' ], $commentQuery['tables'], $actorQuery['tables'], [ 'user' ]
-               );
-               $fields = [
-                       'log_id', 'log_type', 'log_action', 'log_timestamp',
-                       'log_namespace', 'log_title', // unused log_page
-                       'log_params', 'log_deleted',
-                       'user_id', 'user_name', 'user_editcount',
-               ] + $commentQuery['fields'] + $actorQuery['fields'];
-
-               $joins = [
-                       // IPs don't have an entry in user table
-                       'user' => [ 'LEFT JOIN', 'user_id=' . $actorQuery['fields']['log_user'] ],
-               ] + $commentQuery['joins'] + $actorQuery['joins'];
-
-               return [
-                       'tables' => $tables,
-                       'fields' => $fields,
-                       'conds' => [],
-                       'options' => [],
-                       'join_conds' => $joins,
-               ];
-       }
-
-       /**
-        * Constructs new LogEntry from database result row.
-        * Supports rows from both logging and recentchanges table.
-        *
-        * @param stdClass|array $row
-        * @return DatabaseLogEntry
-        */
-       public static function newFromRow( $row ) {
-               $row = (object)$row;
-               if ( isset( $row->rc_logid ) ) {
-                       return new RCDatabaseLogEntry( $row );
-               } else {
-                       return new self( $row );
-               }
-       }
-
-       /**
-        * Loads a LogEntry with the given id from database
-        *
-        * @param int $id
-        * @param IDatabase $db
-        * @return DatabaseLogEntry|null
-        */
-       public static function newFromId( $id, IDatabase $db ) {
-               $queryInfo = self::getSelectQueryData();
-               $queryInfo['conds'] += [ 'log_id' => $id ];
-               $row = $db->selectRow(
-                       $queryInfo['tables'],
-                       $queryInfo['fields'],
-                       $queryInfo['conds'],
-                       __METHOD__,
-                       $queryInfo['options'],
-                       $queryInfo['join_conds']
-               );
-               if ( !$row ) {
-                       return null;
-               }
-               return self::newFromRow( $row );
-       }
-
-       /** @var stdClass Database result row. */
-       protected $row;
-
-       /** @var User */
-       protected $performer;
-
-       /** @var array Parameters for log entry */
-       protected $params;
-
-       /** @var int A rev id associated to the log entry */
-       protected $revId = null;
-
-       /** @var bool Whether the parameters for this log entry are stored in new or old format. */
-       protected $legacy;
-
-       protected function __construct( $row ) {
-               $this->row = $row;
-       }
-
-       /**
-        * Returns the unique database id.
-        *
-        * @return int
-        */
-       public function getId() {
-               return (int)$this->row->log_id;
-       }
-
-       /**
-        * Returns whatever is stored in the database field.
-        *
-        * @return string
-        */
-       protected function getRawParameters() {
-               return $this->row->log_params;
-       }
-
-       public function isLegacy() {
-               // This extracts the property
-               $this->getParameters();
-               return $this->legacy;
-       }
-
-       public function getType() {
-               return $this->row->log_type;
-       }
-
-       public function getSubtype() {
-               return $this->row->log_action;
-       }
-
-       public function getParameters() {
-               if ( !isset( $this->params ) ) {
-                       $blob = $this->getRawParameters();
-                       Wikimedia\suppressWarnings();
-                       $params = LogEntryBase::extractParams( $blob );
-                       Wikimedia\restoreWarnings();
-                       if ( $params !== false ) {
-                               $this->params = $params;
-                               $this->legacy = false;
-                       } else {
-                               $this->params = LogPage::extractParams( $blob );
-                               $this->legacy = true;
-                       }
-
-                       if ( isset( $this->params['associated_rev_id'] ) ) {
-                               $this->revId = $this->params['associated_rev_id'];
-                               unset( $this->params['associated_rev_id'] );
-                       }
-               }
-
-               return $this->params;
-       }
-
-       public function getAssociatedRevId() {
-               // This extracts the property
-               $this->getParameters();
-               return $this->revId;
-       }
-
-       public function getPerformer() {
-               if ( !$this->performer ) {
-                       $actorId = isset( $this->row->log_actor ) ? (int)$this->row->log_actor : 0;
-                       $userId = (int)$this->row->log_user;
-                       if ( $userId !== 0 || $actorId !== 0 ) {
-                               // logged-in users
-                               if ( isset( $this->row->user_name ) ) {
-                                       $this->performer = User::newFromRow( $this->row );
-                               } elseif ( $actorId !== 0 ) {
-                                       $this->performer = User::newFromActorId( $actorId );
-                               } else {
-                                       $this->performer = User::newFromId( $userId );
-                               }
-                       } else {
-                               // IP users
-                               $userText = $this->row->log_user_text;
-                               $this->performer = User::newFromName( $userText, false );
-                       }
-               }
-
-               return $this->performer;
-       }
-
-       public function getTarget() {
-               $namespace = $this->row->log_namespace;
-               $page = $this->row->log_title;
-               $title = Title::makeTitle( $namespace, $page );
-
-               return $title;
-       }
-
-       public function getTimestamp() {
-               return wfTimestamp( TS_MW, $this->row->log_timestamp );
-       }
-
-       public function getComment() {
-               return CommentStore::getStore()->getComment( 'log_comment', $this->row )->text;
-       }
-
-       public function getDeleted() {
-               return $this->row->log_deleted;
-       }
-}
-
-/**
- * A subclass of DatabaseLogEntry for objects constructed from entries in the
- * recentchanges table (rather than the logging table).
- */
-class RCDatabaseLogEntry extends DatabaseLogEntry {
-
-       public function getId() {
-               return $this->row->rc_logid;
-       }
-
-       protected function getRawParameters() {
-               return $this->row->rc_params;
-       }
-
-       public function getAssociatedRevId() {
-               return $this->row->rc_this_oldid;
-       }
-
-       public function getType() {
-               return $this->row->rc_log_type;
-       }
-
-       public function getSubtype() {
-               return $this->row->rc_log_action;
-       }
-
-       public function getPerformer() {
-               if ( !$this->performer ) {
-                       $actorId = isset( $this->row->rc_actor ) ? (int)$this->row->rc_actor : 0;
-                       $userId = (int)$this->row->rc_user;
-                       if ( $actorId !== 0 ) {
-                               $this->performer = User::newFromActorId( $actorId );
-                       } elseif ( $userId !== 0 ) {
-                               $this->performer = User::newFromId( $userId );
-                       } else {
-                               $userText = $this->row->rc_user_text;
-                               // Might be an IP, don't validate the username
-                               $this->performer = User::newFromName( $userText, false );
-                       }
-               }
-
-               return $this->performer;
-       }
-
-       public function getTarget() {
-               $namespace = $this->row->rc_namespace;
-               $page = $this->row->rc_title;
-               $title = Title::makeTitle( $namespace, $page );
-
-               return $title;
-       }
-
-       public function getTimestamp() {
-               return wfTimestamp( TS_MW, $this->row->rc_timestamp );
-       }
-
-       public function getComment() {
-               return CommentStore::getStore()
-                       // Legacy because the row may have used RecentChange::selectFields()
-                       ->getCommentLegacy( wfGetDB( DB_REPLICA ), 'rc_comment', $this->row )->text;
-       }
-
-       public function getDeleted() {
-               return $this->row->rc_deleted;
-       }
-}
-
-/**
- * Class for creating new log entries and inserting them into the database.
- *
- * @since 1.19
- */
-class ManualLogEntry extends LogEntryBase implements Taggable {
-       /** @var string Type of log entry */
-       protected $type;
-
-       /** @var string Sub type of log entry */
-       protected $subtype;
-
-       /** @var array Parameters for log entry */
-       protected $parameters = [];
-
-       /** @var array */
-       protected $relations = [];
-
-       /** @var User Performer of the action for the log entry */
-       protected $performer;
-
-       /** @var Title Target title for the log entry */
-       protected $target;
-
-       /** @var string Timestamp of creation of the log entry */
-       protected $timestamp;
-
-       /** @var string Comment for the log entry */
-       protected $comment = '';
-
-       /** @var int A rev id associated to the log entry */
-       protected $revId = 0;
-
-       /** @var string[] Change tags add to the log entry */
-       protected $tags = [];
-
-       /** @var int Deletion state of the log entry */
-       protected $deleted;
-
-       /** @var int ID of the log entry */
-       protected $id;
-
-       /** @var bool Can this log entry be patrolled? */
-       protected $isPatrollable = false;
-
-       /** @var bool Whether this is a legacy log entry */
-       protected $legacy = false;
-
-       /**
-        * @since 1.19
-        * @param string $type
-        * @param string $subtype
-        */
-       public function __construct( $type, $subtype ) {
-               $this->type = $type;
-               $this->subtype = $subtype;
-       }
-
-       /**
-        * Set extra log parameters.
-        *
-        * You can pass params to the log action message by prefixing the keys with
-        * a number and optional type, using colons to separate the fields. The
-        * numbering should start with number 4, the first three parameters are
-        * hardcoded for every message.
-        *
-        * If you want to store stuff that should not be available in messages, don't
-        * prefix the array key with a number and don't use the colons.
-        *
-        * Example:
-        *   $entry->setParameters(
-        *     '4::color' => 'blue',
-        *     '5:number:count' => 3000,
-        *     'animal' => 'dog'
-        *   );
-        *
-        * @since 1.19
-        * @param array $parameters Associative array
-        */
-       public function setParameters( $parameters ) {
-               $this->parameters = $parameters;
-       }
-
-       /**
-        * Declare arbitrary tag/value relations to this log entry.
-        * These can be used to filter log entries later on.
-        *
-        * @param array $relations Map of (tag => (list of values|value))
-        * @since 1.22
-        */
-       public function setRelations( array $relations ) {
-               $this->relations = $relations;
-       }
-
-       /**
-        * Set the user that performed the action being logged.
-        *
-        * @since 1.19
-        * @param UserIdentity $performer
-        */
-       public function setPerformer( UserIdentity $performer ) {
-               $this->performer = User::newFromIdentity( $performer );
-       }
-
-       /**
-        * Set the title of the object changed.
-        *
-        * @since 1.19
-        * @param LinkTarget $target
-        */
-       public function setTarget( LinkTarget $target ) {
-               $this->target = Title::newFromLinkTarget( $target );
-       }
-
-       /**
-        * Set the timestamp of when the logged action took place.
-        *
-        * @since 1.19
-        * @param string $timestamp
-        */
-       public function setTimestamp( $timestamp ) {
-               $this->timestamp = $timestamp;
-       }
-
-       /**
-        * Set a comment associated with the action being logged.
-        *
-        * @since 1.19
-        * @param string $comment
-        */
-       public function setComment( $comment ) {
-               $this->comment = $comment;
-       }
-
-       /**
-        * Set an associated revision id.
-        *
-        * For example, the ID of the revision that was inserted to mark a page move
-        * or protection, file upload, etc.
-        *
-        * @since 1.27
-        * @param int $revId
-        */
-       public function setAssociatedRevId( $revId ) {
-               $this->revId = $revId;
-       }
-
-       /**
-        * Set change tags for the log entry.
-        *
-        * Passing `null` means the same as empty array,
-        * for compatibility with WikiPage::doUpdateRestrictions().
-        *
-        * @since 1.27
-        * @param string|string[]|null $tags
-        * @deprecated since 1.33 Please use addTags() instead
-        */
-       public function setTags( $tags ) {
-               if ( $this->tags ) {
-                       wfDebug( 'Overwriting existing ManualLogEntry tags' );
-               }
-               $this->tags = [];
-               if ( $tags !== null ) {
-                       $this->addTags( $tags );
-               }
-       }
-
-       /**
-        * Add change tags for the log entry
-        *
-        * @since 1.33
-        * @param string|string[] $tags Tags to apply
-        */
-       public function addTags( $tags ) {
-               if ( is_string( $tags ) ) {
-                       $tags = [ $tags ];
-               }
-               Assert::parameterElementType( 'string', $tags, 'tags' );
-               $this->tags = array_unique( array_merge( $this->tags, $tags ) );
-       }
-
-       /**
-        * Set whether this log entry should be made patrollable
-        * This shouldn't depend on config, only on whether there is full support
-        * in the software for patrolling this log entry.
-        * False by default
-        *
-        * @since 1.27
-        * @param bool $patrollable
-        */
-       public function setIsPatrollable( $patrollable ) {
-               $this->isPatrollable = (bool)$patrollable;
-       }
-
-       /**
-        * Set the 'legacy' flag
-        *
-        * @since 1.25
-        * @param bool $legacy
-        */
-       public function setLegacy( $legacy ) {
-               $this->legacy = $legacy;
-       }
-
-       /**
-        * Set the 'deleted' flag.
-        *
-        * @since 1.19
-        * @param int $deleted One of LogPage::DELETED_* bitfield constants
-        */
-       public function setDeleted( $deleted ) {
-               $this->deleted = $deleted;
-       }
-
-       /**
-        * Insert the entry into the `logging` table.
-        *
-        * @param IDatabase|null $dbw
-        * @return int ID of the log entry
-        * @throws MWException
-        */
-       public function insert( IDatabase $dbw = null ) {
-               global $wgActorTableSchemaMigrationStage;
-
-               $dbw = $dbw ?: wfGetDB( DB_MASTER );
-
-               if ( $this->timestamp === null ) {
-                       $this->timestamp = wfTimestampNow();
-               }
-
-               // Trim spaces on user supplied text
-               $comment = trim( $this->getComment() );
-
-               $params = $this->getParameters();
-               $relations = $this->relations;
-
-               // Ensure actor relations are set
-               if ( ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) &&
-                       empty( $relations['target_author_actor'] )
-               ) {
-                       $actorIds = [];
-                       if ( !empty( $relations['target_author_id'] ) ) {
-                               foreach ( $relations['target_author_id'] as $id ) {
-                                       $actorIds[] = User::newFromId( $id )->getActorId( $dbw );
-                               }
-                       }
-                       if ( !empty( $relations['target_author_ip'] ) ) {
-                               foreach ( $relations['target_author_ip'] as $ip ) {
-                                       $actorIds[] = User::newFromName( $ip, false )->getActorId( $dbw );
-                               }
-                       }
-                       if ( $actorIds ) {
-                               $relations['target_author_actor'] = $actorIds;
-                               $params['authorActors'] = $actorIds;
-                       }
-               }
-               if ( !( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) ) {
-                       unset( $relations['target_author_id'], $relations['target_author_ip'] );
-                       unset( $params['authorIds'], $params['authorIPs'] );
-               }
-
-               // Additional fields for which there's no space in the database table schema
-               $revId = $this->getAssociatedRevId();
-               if ( $revId ) {
-                       $params['associated_rev_id'] = $revId;
-                       $relations['associated_rev_id'] = $revId;
-               }
-
-               $data = [
-                       'log_type' => $this->getType(),
-                       'log_action' => $this->getSubtype(),
-                       'log_timestamp' => $dbw->timestamp( $this->getTimestamp() ),
-                       'log_namespace' => $this->getTarget()->getNamespace(),
-                       'log_title' => $this->getTarget()->getDBkey(),
-                       'log_page' => $this->getTarget()->getArticleID(),
-                       'log_params' => LogEntryBase::makeParamBlob( $params ),
-               ];
-               if ( isset( $this->deleted ) ) {
-                       $data['log_deleted'] = $this->deleted;
-               }
-               $data += CommentStore::getStore()->insert( $dbw, 'log_comment', $comment );
-               $data += ActorMigration::newMigration()
-                       ->getInsertValues( $dbw, 'log_user', $this->getPerformer() );
-
-               $dbw->insert( 'logging', $data, __METHOD__ );
-               $this->id = $dbw->insertId();
-
-               $rows = [];
-               foreach ( $relations as $tag => $values ) {
-                       if ( !strlen( $tag ) ) {
-                               throw new MWException( "Got empty log search tag." );
-                       }
-
-                       if ( !is_array( $values ) ) {
-                               $values = [ $values ];
-                       }
-
-                       foreach ( $values as $value ) {
-                               $rows[] = [
-                                       'ls_field' => $tag,
-                                       'ls_value' => $value,
-                                       'ls_log_id' => $this->id
-                               ];
-                       }
-               }
-               if ( count( $rows ) ) {
-                       $dbw->insert( 'log_search', $rows, __METHOD__, 'IGNORE' );
-               }
-
-               return $this->id;
-       }
-
-       /**
-        * Get a RecentChanges object for the log entry
-        *
-        * @param int $newId
-        * @return RecentChange
-        * @since 1.23
-        */
-       public function getRecentChange( $newId = 0 ) {
-               $formatter = LogFormatter::newFromEntry( $this );
-               $context = RequestContext::newExtraneousContext( $this->getTarget() );
-               $formatter->setContext( $context );
-
-               $logpage = SpecialPage::getTitleFor( 'Log', $this->getType() );
-               $user = $this->getPerformer();
-               $ip = "";
-               if ( $user->isAnon() ) {
-                       // "MediaWiki default" and friends may have
-                       // no IP address in their name
-                       if ( IP::isIPAddress( $user->getName() ) ) {
-                               $ip = $user->getName();
-                       }
-               }
-
-               return RecentChange::newLogEntry(
-                       $this->getTimestamp(),
-                       $logpage,
-                       $user,
-                       $formatter->getPlainActionText(),
-                       $ip,
-                       $this->getType(),
-                       $this->getSubtype(),
-                       $this->getTarget(),
-                       $this->getComment(),
-                       LogEntryBase::makeParamBlob( $this->getParameters() ),
-                       $newId,
-                       $formatter->getIRCActionComment(), // Used for IRC feeds
-                       $this->getAssociatedRevId(), // Used for e.g. moves and uploads
-                       $this->getIsPatrollable()
-               );
-       }
-
-       /**
-        * Publish the log entry.
-        *
-        * @param int $newId Id of the log entry.
-        * @param string $to One of: rcandudp (default), rc, udp
-        */
-       public function publish( $newId, $to = 'rcandudp' ) {
-               DeferredUpdates::addCallableUpdate(
-                       function () use ( $newId, $to ) {
-                               $log = new LogPage( $this->getType() );
-                               if ( !$log->isRestricted() ) {
-                                       Hooks::runWithoutAbort( 'ManualLogEntryBeforePublish', [ $this ] );
-                                       $rc = $this->getRecentChange( $newId );
-
-                                       if ( $to === 'rc' || $to === 'rcandudp' ) {
-                                               // save RC, passing tags so they are applied there
-                                               $rc->addTags( $this->getTags() );
-                                               $rc->save( $rc::SEND_NONE );
-                                       } else {
-                                               $tags = $this->getTags();
-                                               if ( $tags ) {
-                                                       $revId = $this->getAssociatedRevId(); // Use null if $revId is 0
-                                                       ChangeTags::addTags( $tags, null, $revId > 0 ? $revId : null, $newId );
-                                               }
-                                       }
-
-                                       if ( $to === 'udp' || $to === 'rcandudp' ) {
-                                               $rc->notifyRCFeeds();
-                                       }
-                               }
-                       },
-                       DeferredUpdates::POSTSEND,
-                       wfGetDB( DB_MASTER )
-               );
-       }
-
-       public function getType() {
-               return $this->type;
-       }
-
-       public function getSubtype() {
-               return $this->subtype;
-       }
-
-       public function getParameters() {
-               return $this->parameters;
-       }
-
-       /**
-        * @return User
-        */
-       public function getPerformer() {
-               return $this->performer;
-       }
-
-       /**
-        * @return Title
-        */
-       public function getTarget() {
-               return $this->target;
-       }
-
-       public function getTimestamp() {
-               $ts = $this->timestamp ?? wfTimestampNow();
-
-               return wfTimestamp( TS_MW, $ts );
-       }
-
-       public function getComment() {
-               return $this->comment;
-       }
-
-       /**
-        * @since 1.27
-        * @return int
-        */
-       public function getAssociatedRevId() {
-               return $this->revId;
-       }
-
-       /**
-        * @since 1.27
-        * @return string[]
-        */
-       public function getTags() {
-               return $this->tags;
-       }
-
-       /**
-        * Whether this log entry is patrollable
-        *
-        * @since 1.27
-        * @return bool
-        */
-       public function getIsPatrollable() {
-               return $this->isPatrollable;
-       }
-
-       /**
-        * @since 1.25
-        * @return bool
-        */
-       public function isLegacy() {
-               return $this->legacy;
-       }
-
-       public function getDeleted() {
-               return (int)$this->deleted;
-       }
-}
diff --git a/includes/logging/LogEntryBase.php b/includes/logging/LogEntryBase.php
new file mode 100644 (file)
index 0000000..170fc29
--- /dev/null
@@ -0,0 +1,72 @@
+<?php
+/**
+ * Contains a class for dealing with individual log entries
+ *
+ * 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
+ * @author Niklas Laxström
+ * @license GPL-2.0-or-later
+ * @since 1.19
+ */
+
+/**
+ * Extends the LogEntry Interface with some basic functionality
+ *
+ * @since 1.19
+ */
+abstract class LogEntryBase implements LogEntry {
+
+       public function getFullType() {
+               return $this->getType() . '/' . $this->getSubtype();
+       }
+
+       public function isDeleted( $field ) {
+               return ( $this->getDeleted() & $field ) === $field;
+       }
+
+       /**
+        * Whether the parameters for this log are stored in new or
+        * old format.
+        *
+        * @return bool
+        */
+       public function isLegacy() {
+               return false;
+       }
+
+       /**
+        * Create a blob from a parameter array
+        *
+        * @since 1.26
+        * @param array $params
+        * @return string
+        */
+       public static function makeParamBlob( $params ) {
+               return serialize( (array)$params );
+       }
+
+       /**
+        * Extract a parameter array from a blob
+        *
+        * @since 1.26
+        * @param string $blob
+        * @return array
+        */
+       public static function extractParams( $blob ) {
+               return unserialize( $blob );
+       }
+}
index c66aa59..3fd52af 100644 (file)
@@ -692,6 +692,8 @@ class LogEventsList extends ContextSource {
                        $s .= $loglist->beginLogEventsList() .
                                $logBody .
                                $loglist->endLogEventsList();
+                       // add styles for change tags
+                       $context->getOutput()->addModuleStyles( 'mediawiki.interface.helpers.styles' );
                } elseif ( $showIfEmpty ) {
                        $s = Html::rawElement( 'div', [ 'class' => 'mw-warning-logempty' ],
                                $context->msg( 'logempty' )->parse() );
index 6d45ed5..3e942ae 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * Contains classes for formatting log entries
+ * Contains a class for formatting log entries
  *
  * 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
@@ -762,7 +762,9 @@ class LogFormatter {
                                        $user->getName(),
                                        true, // redContribsWhenNoEdits
                                        $toolFlags,
-                                       $user->getEditCount()
+                                       $user->getEditCount(),
+                                       // do not render parenthesises in the HTML markup (CSS will provide)
+                                       false
                                );
                        }
                }
@@ -815,6 +817,11 @@ class LogFormatter {
                foreach ( $this->getParametersForApi() as $key => $value ) {
                        $vals = explode( ':', $key, 3 );
                        if ( count( $vals ) !== 3 ) {
+                               if ( $value instanceof __PHP_Incomplete_Class ) {
+                                       wfLogWarning( 'Log entry of type ' . $this->entry->getFullType() .
+                                               ' contains unrecoverable extra parameters.' );
+                                       continue;
+                               }
                                $logParams[$key] = $value;
                                continue;
                        }
@@ -903,106 +910,3 @@ class LogFormatter {
                return [ $name => $value ];
        }
 }
-
-/**
- * This class formats all log entries for log types
- * which have not been converted to the new system.
- * This is not about old log entries which store
- * parameters in a different format - the new
- * LogFormatter classes have code to support formatting
- * those too.
- * @since 1.19
- */
-class LegacyLogFormatter extends LogFormatter {
-       /**
-        * Backward compatibility for extension changing the comment from
-        * the LogLine hook. This will be set by the first call on getComment(),
-        * then it might be modified by the hook when calling getActionLinks(),
-        * so that the modified value will be returned when calling getComment()
-        * a second time.
-        *
-        * @var string|null
-        */
-       private $comment = null;
-
-       /**
-        * Cache for the result of getActionLinks() so that it does not need to
-        * run multiple times depending on the order that getComment() and
-        * getActionLinks() are called.
-        *
-        * @var string|null
-        */
-       private $revert = null;
-
-       public function getComment() {
-               if ( $this->comment === null ) {
-                       $this->comment = parent::getComment();
-               }
-
-               // Make sure we execute the LogLine hook so that we immediately return
-               // the correct value.
-               if ( $this->revert === null ) {
-                       $this->getActionLinks();
-               }
-
-               return $this->comment;
-       }
-
-       /**
-        * @return string
-        * @return-taint onlysafefor_html
-        */
-       protected function getActionMessage() {
-               $entry = $this->entry;
-               $action = LogPage::actionText(
-                       $entry->getType(),
-                       $entry->getSubtype(),
-                       $entry->getTarget(),
-                       $this->plaintext ? null : $this->context->getSkin(),
-                       (array)$entry->getParameters(),
-                       !$this->plaintext // whether to filter [[]] links
-               );
-
-               $performer = $this->getPerformerElement();
-               if ( !$this->irctext ) {
-                       $sep = $this->msg( 'word-separator' );
-                       $sep = $this->plaintext ? $sep->text() : $sep->escaped();
-                       $action = $performer . $sep . $action;
-               }
-
-               return $action;
-       }
-
-       public function getActionLinks() {
-               if ( $this->revert !== null ) {
-                       return $this->revert;
-               }
-
-               if ( $this->entry->isDeleted( LogPage::DELETED_ACTION ) ) {
-                       $this->revert = '';
-                       return $this->revert;
-               }
-
-               $title = $this->entry->getTarget();
-               $type = $this->entry->getType();
-               $subtype = $this->entry->getSubtype();
-
-               // Do nothing. The implementation is handled by the hook modifiying the
-               // passed-by-ref parameters. This also changes the default value so that
-               // getComment() and getActionLinks() do not call them indefinitely.
-               $this->revert = '';
-
-               // This is to populate the $comment member of this instance so that it
-               // can be modified when calling the hook just below.
-               if ( $this->comment === null ) {
-                       $this->getComment();
-               }
-
-               $params = $this->entry->getParameters();
-
-               Hooks::run( 'LogLine', [ $type, $subtype, $title, $params,
-                       &$this->comment, &$this->revert, $this->entry->getTimestamp() ] );
-
-               return $this->revert;
-       }
-}
index 45d6e1f..1fc56bb 100644 (file)
@@ -104,7 +104,11 @@ class LogPage {
                        'log_page' => $this->target->getArticleID(),
                        'log_params' => $this->params
                ];
-               $data += CommentStore::getStore()->insert( $dbw, 'log_comment', $this->comment );
+               $data += MediaWikiServices::getInstance()->getCommentStore()->insert(
+                       $dbw,
+                       'log_comment',
+                       $this->comment
+               );
                $data += ActorMigration::newMigration()->getInsertValues( $dbw, 'log_user', $this->doer );
                $dbw->insert( 'logging', $data, __METHOD__ );
                $newId = $dbw->insertId();
index 801c474..4ecc368 100644 (file)
@@ -335,6 +335,14 @@ class LogPager extends ReverseChronologicalPager {
                # Don't show duplicate rows when using log_search
                $joins['log_search'] = [ 'JOIN', 'ls_log_id=log_id' ];
 
+               // T221458: MySQL/MariaDB (10.1.37) can sometimes irrationally decide that querying `actor` before
+               // `logging` and filesorting is somehow better than querying $limit+1 rows from `logging`.
+               // Tell it not to reorder the query. But not when tag filtering or log_search was used, as it
+               // seems as likely to be harmed as helped in that case.
+               if ( !$this->mTagFilter && !array_key_exists( 'ls_field', $this->mConds ) ) {
+                       $options[] = 'STRAIGHT_JOIN';
+               }
+
                $info = [
                        'tables' => $tables,
                        'fields' => $fields,
diff --git a/includes/logging/ManualLogEntry.php b/includes/logging/ManualLogEntry.php
new file mode 100644 (file)
index 0000000..90c0a72
--- /dev/null
@@ -0,0 +1,515 @@
+<?php
+/**
+ * Contains a class for dealing with manual log entries
+ *
+ * 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
+ * @author Niklas Laxström
+ * @license GPL-2.0-or-later
+ * @since 1.19
+ */
+
+use MediaWiki\ChangeTags\Taggable;
+use MediaWiki\Linker\LinkTarget;
+use MediaWiki\User\UserIdentity;
+use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Assert\Assert;
+
+/**
+ * Class for creating new log entries and inserting them into the database.
+ *
+ * @since 1.19
+ */
+class ManualLogEntry extends LogEntryBase implements Taggable {
+       /** @var string Type of log entry */
+       protected $type;
+
+       /** @var string Sub type of log entry */
+       protected $subtype;
+
+       /** @var array Parameters for log entry */
+       protected $parameters = [];
+
+       /** @var array */
+       protected $relations = [];
+
+       /** @var User Performer of the action for the log entry */
+       protected $performer;
+
+       /** @var Title Target title for the log entry */
+       protected $target;
+
+       /** @var string Timestamp of creation of the log entry */
+       protected $timestamp;
+
+       /** @var string Comment for the log entry */
+       protected $comment = '';
+
+       /** @var int A rev id associated to the log entry */
+       protected $revId = 0;
+
+       /** @var string[] Change tags add to the log entry */
+       protected $tags = [];
+
+       /** @var int Deletion state of the log entry */
+       protected $deleted;
+
+       /** @var int ID of the log entry */
+       protected $id;
+
+       /** @var bool Can this log entry be patrolled? */
+       protected $isPatrollable = false;
+
+       /** @var bool Whether this is a legacy log entry */
+       protected $legacy = false;
+
+       /**
+        * @since 1.19
+        * @param string $type
+        * @param string $subtype
+        */
+       public function __construct( $type, $subtype ) {
+               $this->type = $type;
+               $this->subtype = $subtype;
+       }
+
+       /**
+        * Set extra log parameters.
+        *
+        * You can pass params to the log action message by prefixing the keys with
+        * a number and optional type, using colons to separate the fields. The
+        * numbering should start with number 4, the first three parameters are
+        * hardcoded for every message.
+        *
+        * If you want to store stuff that should not be available in messages, don't
+        * prefix the array key with a number and don't use the colons.
+        *
+        * Example:
+        *   $entry->setParameters(
+        *     '4::color' => 'blue',
+        *     '5:number:count' => 3000,
+        *     'animal' => 'dog'
+        *   );
+        *
+        * @since 1.19
+        * @param array $parameters Associative array
+        */
+       public function setParameters( $parameters ) {
+               $this->parameters = $parameters;
+       }
+
+       /**
+        * Declare arbitrary tag/value relations to this log entry.
+        * These can be used to filter log entries later on.
+        *
+        * @param array $relations Map of (tag => (list of values|value))
+        * @since 1.22
+        */
+       public function setRelations( array $relations ) {
+               $this->relations = $relations;
+       }
+
+       /**
+        * Set the user that performed the action being logged.
+        *
+        * @since 1.19
+        * @param UserIdentity $performer
+        */
+       public function setPerformer( UserIdentity $performer ) {
+               $this->performer = User::newFromIdentity( $performer );
+       }
+
+       /**
+        * Set the title of the object changed.
+        *
+        * @since 1.19
+        * @param LinkTarget $target
+        */
+       public function setTarget( LinkTarget $target ) {
+               $this->target = Title::newFromLinkTarget( $target );
+       }
+
+       /**
+        * Set the timestamp of when the logged action took place.
+        *
+        * @since 1.19
+        * @param string $timestamp
+        */
+       public function setTimestamp( $timestamp ) {
+               $this->timestamp = $timestamp;
+       }
+
+       /**
+        * Set a comment associated with the action being logged.
+        *
+        * @since 1.19
+        * @param string $comment
+        */
+       public function setComment( $comment ) {
+               $this->comment = $comment;
+       }
+
+       /**
+        * Set an associated revision id.
+        *
+        * For example, the ID of the revision that was inserted to mark a page move
+        * or protection, file upload, etc.
+        *
+        * @since 1.27
+        * @param int $revId
+        */
+       public function setAssociatedRevId( $revId ) {
+               $this->revId = $revId;
+       }
+
+       /**
+        * Set change tags for the log entry.
+        *
+        * Passing `null` means the same as empty array,
+        * for compatibility with WikiPage::doUpdateRestrictions().
+        *
+        * @since 1.27
+        * @param string|string[]|null $tags
+        * @deprecated since 1.33 Please use addTags() instead
+        */
+       public function setTags( $tags ) {
+               if ( $this->tags ) {
+                       wfDebug( 'Overwriting existing ManualLogEntry tags' );
+               }
+               $this->tags = [];
+               if ( $tags !== null ) {
+                       $this->addTags( $tags );
+               }
+       }
+
+       /**
+        * Add change tags for the log entry
+        *
+        * @since 1.33
+        * @param string|string[] $tags Tags to apply
+        */
+       public function addTags( $tags ) {
+               if ( is_string( $tags ) ) {
+                       $tags = [ $tags ];
+               }
+               Assert::parameterElementType( 'string', $tags, 'tags' );
+               $this->tags = array_unique( array_merge( $this->tags, $tags ) );
+       }
+
+       /**
+        * Set whether this log entry should be made patrollable
+        * This shouldn't depend on config, only on whether there is full support
+        * in the software for patrolling this log entry.
+        * False by default
+        *
+        * @since 1.27
+        * @param bool $patrollable
+        */
+       public function setIsPatrollable( $patrollable ) {
+               $this->isPatrollable = (bool)$patrollable;
+       }
+
+       /**
+        * Set the 'legacy' flag
+        *
+        * @since 1.25
+        * @param bool $legacy
+        */
+       public function setLegacy( $legacy ) {
+               $this->legacy = $legacy;
+       }
+
+       /**
+        * Set the 'deleted' flag.
+        *
+        * @since 1.19
+        * @param int $deleted One of LogPage::DELETED_* bitfield constants
+        */
+       public function setDeleted( $deleted ) {
+               $this->deleted = $deleted;
+       }
+
+       /**
+        * Insert the entry into the `logging` table.
+        *
+        * @param IDatabase|null $dbw
+        * @return int ID of the log entry
+        * @throws MWException
+        */
+       public function insert( IDatabase $dbw = null ) {
+               global $wgActorTableSchemaMigrationStage;
+
+               $dbw = $dbw ?: wfGetDB( DB_MASTER );
+
+               if ( $this->timestamp === null ) {
+                       $this->timestamp = wfTimestampNow();
+               }
+
+               // Trim spaces on user supplied text
+               $comment = trim( $this->getComment() );
+
+               $params = $this->getParameters();
+               $relations = $this->relations;
+
+               // Ensure actor relations are set
+               if ( ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) &&
+                       empty( $relations['target_author_actor'] )
+               ) {
+                       $actorIds = [];
+                       if ( !empty( $relations['target_author_id'] ) ) {
+                               foreach ( $relations['target_author_id'] as $id ) {
+                                       $actorIds[] = User::newFromId( $id )->getActorId( $dbw );
+                               }
+                       }
+                       if ( !empty( $relations['target_author_ip'] ) ) {
+                               foreach ( $relations['target_author_ip'] as $ip ) {
+                                       $actorIds[] = User::newFromName( $ip, false )->getActorId( $dbw );
+                               }
+                       }
+                       if ( $actorIds ) {
+                               $relations['target_author_actor'] = $actorIds;
+                               $params['authorActors'] = $actorIds;
+                       }
+               }
+               if ( !( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) ) {
+                       unset( $relations['target_author_id'], $relations['target_author_ip'] );
+                       unset( $params['authorIds'], $params['authorIPs'] );
+               }
+
+               // Additional fields for which there's no space in the database table schema
+               $revId = $this->getAssociatedRevId();
+               if ( $revId ) {
+                       $params['associated_rev_id'] = $revId;
+                       $relations['associated_rev_id'] = $revId;
+               }
+
+               $data = [
+                       'log_type' => $this->getType(),
+                       'log_action' => $this->getSubtype(),
+                       'log_timestamp' => $dbw->timestamp( $this->getTimestamp() ),
+                       'log_namespace' => $this->getTarget()->getNamespace(),
+                       'log_title' => $this->getTarget()->getDBkey(),
+                       'log_page' => $this->getTarget()->getArticleID(),
+                       'log_params' => LogEntryBase::makeParamBlob( $params ),
+               ];
+               if ( isset( $this->deleted ) ) {
+                       $data['log_deleted'] = $this->deleted;
+               }
+               $data += CommentStore::getStore()->insert( $dbw, 'log_comment', $comment );
+               $data += ActorMigration::newMigration()
+                       ->getInsertValues( $dbw, 'log_user', $this->getPerformer() );
+
+               $dbw->insert( 'logging', $data, __METHOD__ );
+               $this->id = $dbw->insertId();
+
+               $rows = [];
+               foreach ( $relations as $tag => $values ) {
+                       if ( !strlen( $tag ) ) {
+                               throw new MWException( "Got empty log search tag." );
+                       }
+
+                       if ( !is_array( $values ) ) {
+                               $values = [ $values ];
+                       }
+
+                       foreach ( $values as $value ) {
+                               $rows[] = [
+                                       'ls_field' => $tag,
+                                       'ls_value' => $value,
+                                       'ls_log_id' => $this->id
+                               ];
+                       }
+               }
+               if ( count( $rows ) ) {
+                       $dbw->insert( 'log_search', $rows, __METHOD__, 'IGNORE' );
+               }
+
+               return $this->id;
+       }
+
+       /**
+        * Get a RecentChanges object for the log entry
+        *
+        * @param int $newId
+        * @return RecentChange
+        * @since 1.23
+        */
+       public function getRecentChange( $newId = 0 ) {
+               $formatter = LogFormatter::newFromEntry( $this );
+               $context = RequestContext::newExtraneousContext( $this->getTarget() );
+               $formatter->setContext( $context );
+
+               $logpage = SpecialPage::getTitleFor( 'Log', $this->getType() );
+               $user = $this->getPerformer();
+               $ip = "";
+               if ( $user->isAnon() ) {
+                       // "MediaWiki default" and friends may have
+                       // no IP address in their name
+                       if ( IP::isIPAddress( $user->getName() ) ) {
+                               $ip = $user->getName();
+                       }
+               }
+
+               return RecentChange::newLogEntry(
+                       $this->getTimestamp(),
+                       $logpage,
+                       $user,
+                       $formatter->getPlainActionText(),
+                       $ip,
+                       $this->getType(),
+                       $this->getSubtype(),
+                       $this->getTarget(),
+                       $this->getComment(),
+                       LogEntryBase::makeParamBlob( $this->getParameters() ),
+                       $newId,
+                       $formatter->getIRCActionComment(), // Used for IRC feeds
+                       $this->getAssociatedRevId(), // Used for e.g. moves and uploads
+                       $this->getIsPatrollable()
+               );
+       }
+
+       /**
+        * Publish the log entry.
+        *
+        * @param int $newId Id of the log entry.
+        * @param string $to One of: rcandudp (default), rc, udp
+        */
+       public function publish( $newId, $to = 'rcandudp' ) {
+               $canAddTags = true;
+               // FIXME: this code should be removed once all callers properly call publish()
+               if ( $to === 'udp' && !$newId && !$this->getAssociatedRevId() ) {
+                       \MediaWiki\Logger\LoggerFactory::getInstance( 'logging' )->warning(
+                               'newId and/or revId must be set when calling ManualLogEntry::publish()',
+                               [
+                                       'newId' => $newId,
+                                       'to' => $to,
+                                       'revId' => $this->getAssociatedRevId(),
+                                       // pass a new exception to register the stack trace
+                                       'exception' => new RuntimeException()
+                               ]
+                       );
+                       $canAddTags = false;
+               }
+
+               DeferredUpdates::addCallableUpdate(
+                       function () use ( $newId, $to, $canAddTags ) {
+                               $log = new LogPage( $this->getType() );
+                               if ( !$log->isRestricted() ) {
+                                       Hooks::runWithoutAbort( 'ManualLogEntryBeforePublish', [ $this ] );
+                                       $rc = $this->getRecentChange( $newId );
+
+                                       if ( $to === 'rc' || $to === 'rcandudp' ) {
+                                               // save RC, passing tags so they are applied there
+                                               $rc->addTags( $this->getTags() );
+                                               $rc->save( $rc::SEND_NONE );
+                                       } else {
+                                               $tags = $this->getTags();
+                                               if ( $tags && $canAddTags ) {
+                                                       $revId = $this->getAssociatedRevId();
+                                                       ChangeTags::addTags(
+                                                               $tags,
+                                                               null,
+                                                               $revId > 0 ? $revId : null,
+                                                               $newId > 0 ? $newId : null
+                                                       );
+                                               }
+                                       }
+
+                                       if ( $to === 'udp' || $to === 'rcandudp' ) {
+                                               $rc->notifyRCFeeds();
+                                       }
+                               }
+                       },
+                       DeferredUpdates::POSTSEND,
+                       wfGetDB( DB_MASTER )
+               );
+       }
+
+       public function getType() {
+               return $this->type;
+       }
+
+       public function getSubtype() {
+               return $this->subtype;
+       }
+
+       public function getParameters() {
+               return $this->parameters;
+       }
+
+       /**
+        * @return User
+        */
+       public function getPerformer() {
+               return $this->performer;
+       }
+
+       /**
+        * @return Title
+        */
+       public function getTarget() {
+               return $this->target;
+       }
+
+       public function getTimestamp() {
+               $ts = $this->timestamp ?? wfTimestampNow();
+
+               return wfTimestamp( TS_MW, $ts );
+       }
+
+       public function getComment() {
+               return $this->comment;
+       }
+
+       /**
+        * @since 1.27
+        * @return int
+        */
+       public function getAssociatedRevId() {
+               return $this->revId;
+       }
+
+       /**
+        * @since 1.27
+        * @return string[]
+        */
+       public function getTags() {
+               return $this->tags;
+       }
+
+       /**
+        * Whether this log entry is patrollable
+        *
+        * @since 1.27
+        * @return bool
+        */
+       public function getIsPatrollable() {
+               return $this->isPatrollable;
+       }
+
+       /**
+        * @since 1.25
+        * @return bool
+        */
+       public function isLegacy() {
+               return $this->legacy;
+       }
+
+       public function getDeleted() {
+               return (int)$this->deleted;
+       }
+}
diff --git a/includes/logging/RCDatabaseLogEntry.php b/includes/logging/RCDatabaseLogEntry.php
new file mode 100644 (file)
index 0000000..4dc4037
--- /dev/null
@@ -0,0 +1,89 @@
+<?php
+/**
+ * Contains a class for dealing with recent changes database log entries
+ *
+ * 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
+ * @author Niklas Laxström
+ * @license GPL-2.0-or-later
+ * @since 1.19
+ */
+
+/**
+ * A subclass of DatabaseLogEntry for objects constructed from entries in the
+ * recentchanges table (rather than the logging table).
+ */
+class RCDatabaseLogEntry extends DatabaseLogEntry {
+
+       public function getId() {
+               return $this->row->rc_logid;
+       }
+
+       protected function getRawParameters() {
+               return $this->row->rc_params;
+       }
+
+       public function getAssociatedRevId() {
+               return $this->row->rc_this_oldid;
+       }
+
+       public function getType() {
+               return $this->row->rc_log_type;
+       }
+
+       public function getSubtype() {
+               return $this->row->rc_log_action;
+       }
+
+       public function getPerformer() {
+               if ( !$this->performer ) {
+                       $actorId = isset( $this->row->rc_actor ) ? (int)$this->row->rc_actor : 0;
+                       $userId = (int)$this->row->rc_user;
+                       if ( $actorId !== 0 ) {
+                               $this->performer = User::newFromActorId( $actorId );
+                       } elseif ( $userId !== 0 ) {
+                               $this->performer = User::newFromId( $userId );
+                       } else {
+                               $userText = $this->row->rc_user_text;
+                               // Might be an IP, don't validate the username
+                               $this->performer = User::newFromName( $userText, false );
+                       }
+               }
+
+               return $this->performer;
+       }
+
+       public function getTarget() {
+               $namespace = $this->row->rc_namespace;
+               $page = $this->row->rc_title;
+               return Title::makeTitle( $namespace, $page );
+       }
+
+       public function getTimestamp() {
+               return wfTimestamp( TS_MW, $this->row->rc_timestamp );
+       }
+
+       public function getComment() {
+               return CommentStore::getStore()
+                       // Legacy because the row may have used RecentChange::selectFields()
+                       ->getCommentLegacy( wfGetDB( DB_REPLICA ), 'rc_comment', $this->row )->text;
+       }
+
+       public function getDeleted() {
+               return $this->row->rc_deleted;
+       }
+}
index 4d1b855..0b77651 100644 (file)
@@ -224,11 +224,12 @@ class EmailNotification {
                                                && $watchingUser->isEmailConfirmed()
                                                && $watchingUser->getId() != $userTalkId
                                                && !in_array( $watchingUser->getName(), $wgUsersNotifiedOnAllChanges )
-                                               && !( $wgBlockDisablesLogin && $watchingUser->isBlocked() )
+                                               // @TODO Partial blocks should not prevent the user from logging in.
+                                               //       see: https://phabricator.wikimedia.org/T208895
+                                               && !( $wgBlockDisablesLogin && $watchingUser->getBlock() )
+                                               && Hooks::run( 'SendWatchlistEmailNotification', [ $watchingUser, $title, $this ] )
                                        ) {
-                                               if ( Hooks::run( 'SendWatchlistEmailNotification', [ $watchingUser, $title, $this ] ) ) {
-                                                       $this->compose( $watchingUser, self::WATCHLIST );
-                                               }
+                                               $this->compose( $watchingUser, self::WATCHLIST );
                                        }
                                }
                        }
@@ -263,7 +264,9 @@ class EmailNotification {
                                wfDebug( __METHOD__ . ": user talk page edited, but user does not exist\n" );
                        } elseif ( $targetUser->getId() == $editor->getId() ) {
                                wfDebug( __METHOD__ . ": user edited their own talk page, no notification sent\n" );
-                       } elseif ( $wgBlockDisablesLogin && $targetUser->isBlocked() ) {
+                       } elseif ( $wgBlockDisablesLogin && $targetUser->getBlock() ) {
+                               // @TODO Partial blocks should not prevent the user from logging in.
+                               //       see: https://phabricator.wikimedia.org/T208895
                                wfDebug( __METHOD__ . ": talk page owner is blocked and cannot login, no notification sent\n" );
                        } elseif ( $targetUser->getOption( 'enotifusertalkpages' )
                                && ( !$minorEdit || $targetUser->getOption( 'enotifminoredits' ) )
@@ -328,8 +331,9 @@ class EmailNotification {
 
                $keys['$PAGETITLE'] = $this->title->getPrefixedText();
                $keys['$PAGETITLE_URL'] = $this->title->getCanonicalURL();
-               $keys['$PAGEMINOREDIT'] = "\n" . ( $this->minorEdit ?
-                       wfMessage( 'enotif_minoredit' )->inContentLanguage()->text() : '' );
+               $keys['$PAGEMINOREDIT'] = $this->minorEdit ?
+                       "\n\n" . wfMessage( 'enotif_minoredit' )->inContentLanguage()->text() :
+                       '';
                $keys['$UNWATCHURL'] = $this->title->getCanonicalURL( 'action=unwatch' );
 
                if ( $this->editor->isAnon() ) {
index b8b706d..e07b166 100644 (file)
@@ -21,6 +21,8 @@
  * @ingroup Media
  */
 
+use MediaWiki\Shell\Shell;
+
 /**
  * Generic handler for bitmap images
  *
@@ -108,7 +110,7 @@ class BitmapHandler extends TransformationalImageHandler {
         * Get ImageMagick subsampling factors for the target JPEG pixel format.
         *
         * @param string $pixelFormat one of 'yuv444', 'yuv422', 'yuv420'
-        * @return array of string keys
+        * @return string[] List of sampling factors
         */
        protected function imageMagickSubsampling( $pixelFormat ) {
                switch ( $pixelFormat ) {
@@ -228,7 +230,7 @@ class BitmapHandler extends TransformationalImageHandler {
                $rotation = isset( $params['disableRotation'] ) ? 0 : $this->getRotation( $image );
                list( $width, $height ) = $this->extractPreRotationDimensions( $params, $rotation );
 
-               $cmd = wfEscapeShellArg( ...array_merge(
+               $cmd = Shell::escape( ...array_merge(
                        [ $wgImageMagickConvertCommand ],
                        $quality,
                        // Specify white background color, will be used for transparent images
@@ -338,10 +340,8 @@ class BitmapHandler extends TransformationalImageHandler {
                        }
                        $im->setImageDepth( 8 );
 
-                       if ( $rotation ) {
-                               if ( !$im->rotateImage( new ImagickPixel( 'white' ), 360 - $rotation ) ) {
-                                       return $this->getMediaTransformError( $params, "Error rotating $rotation degrees" );
-                               }
+                       if ( $rotation && !$im->rotateImage( new ImagickPixel( 'white' ), 360 - $rotation ) ) {
+                               return $this->getMediaTransformError( $params, "Error rotating $rotation degrees" );
                        }
 
                        if ( $this->isAnimatedImage( $image ) ) {
@@ -375,12 +375,12 @@ class BitmapHandler extends TransformationalImageHandler {
                global $wgCustomConvertCommand;
 
                # Variables: %s %d %w %h
-               $src = wfEscapeShellArg( $params['srcPath'] );
-               $dst = wfEscapeShellArg( $params['dstPath'] );
+               $src = Shell::escape( $params['srcPath'] );
+               $dst = Shell::escape( $params['dstPath'] );
                $cmd = $wgCustomConvertCommand;
                $cmd = str_replace( '%s', $src, str_replace( '%d', $dst, $cmd ) ); # Filenames
-               $cmd = str_replace( '%h', wfEscapeShellArg( $params['physicalHeight'] ),
-                       str_replace( '%w', wfEscapeShellArg( $params['physicalWidth'] ), $cmd ) ); # Size
+               $cmd = str_replace( '%h', Shell::escape( $params['physicalHeight'] ),
+                       str_replace( '%w', Shell::escape( $params['physicalWidth'] ), $cmd ) ); # Size
                wfDebug( __METHOD__ . ": Running custom convert command $cmd\n" );
                $retval = 0;
                $err = wfShellExecWithStderr( $cmd, $retval );
@@ -571,10 +571,10 @@ class BitmapHandler extends TransformationalImageHandler {
                $scaler = $this->getScalerType( null, false );
                switch ( $scaler ) {
                        case 'im':
-                               $cmd = wfEscapeShellArg( $wgImageMagickConvertCommand ) . " " .
-                                       wfEscapeShellArg( $this->escapeMagickInput( $params['srcPath'], $scene ) ) .
-                                       " -rotate " . wfEscapeShellArg( "-$rotation" ) . " " .
-                                       wfEscapeShellArg( $this->escapeMagickOutput( $params['dstPath'] ) );
+                               $cmd = Shell::escape( $wgImageMagickConvertCommand ) . " " .
+                                       Shell::escape( $this->escapeMagickInput( $params['srcPath'], $scene ) ) .
+                                       " -rotate " . Shell::escape( "-$rotation" ) . " " .
+                                       Shell::escape( $this->escapeMagickOutput( $params['dstPath'] ) );
                                wfDebug( __METHOD__ . ": running ImageMagick: $cmd\n" );
                                $retval = 0;
                                $err = wfShellExecWithStderr( $cmd, $retval );
index 81c63db..9617692 100644 (file)
@@ -132,13 +132,13 @@ class BitmapMetadataHandler {
                                        // Do some special casing for multilingual values.
                                        // Don't discard translations if also as a simple value.
                                        foreach ( $this->metadata[$type] as $itemName => $item ) {
-                                               if ( is_array( $item ) && isset( $item['_type'] ) && $item['_type'] === 'lang' ) {
-                                                       if ( isset( $temp[$itemName] ) && !is_array( $temp[$itemName] ) ) {
-                                                               $default = $temp[$itemName];
-                                                               $temp[$itemName] = $item;
-                                                               $temp[$itemName]['x-default'] = $default;
-                                                               unset( $this->metadata[$type][$itemName] );
-                                                       }
+                                               if ( is_array( $item ) && isset( $item['_type'] ) && $item['_type'] === 'lang' &&
+                                                       isset( $temp[$itemName] ) && !is_array( $temp[$itemName] )
+                                               ) {
+                                                       $default = $temp[$itemName];
+                                                       $temp[$itemName] = $item;
+                                                       $temp[$itemName]['x-default'] = $default;
+                                                       unset( $this->metadata[$type][$itemName] );
                                                }
                                        }
 
index a0e7f2c..3b904e8 100644 (file)
@@ -21,6 +21,7 @@
  * @ingroup Media
  */
 use MediaWiki\MediaWikiServices;
+use MediaWiki\Shell\Shell;
 
 /**
  * Handler for DjVu images
@@ -204,7 +205,7 @@ class DjVuHandler extends ImageHandler {
 
                # Use a subshell (brackets) to aggregate stderr from both pipeline commands
                # before redirecting it to the overall stdout. This works in both Linux and Windows XP.
-               $cmd = '(' . wfEscapeShellArg(
+               $cmd = '(' . Shell::escape(
                        $wgDjvuRenderer,
                        "-format=ppm",
                        "-page={$page}",
@@ -213,7 +214,7 @@ class DjVuHandler extends ImageHandler {
                if ( $wgDjvuPostProcessor ) {
                        $cmd .= " | {$wgDjvuPostProcessor}";
                }
-               $cmd .= ' > ' . wfEscapeShellArg( $dstPath ) . ') 2>&1';
+               $cmd .= ' > ' . Shell::escape( $dstPath ) . ') 2>&1';
                wfDebug( __METHOD__ . ": $cmd\n" );
                $retval = '';
                $err = wfShellExec( $cmd, $retval );
index d059cd8..13a39ed 100644 (file)
@@ -24,6 +24,8 @@
  * @ingroup Media
  */
 
+use MediaWiki\Shell\Shell;
+
 /**
  * Support for detecting/validating DjVu image files and getting
  * some basic file metadata (resolution etc)
@@ -34,8 +36,9 @@
  * @ingroup Media
  */
 class DjVuImage {
+
        /**
-        * @const DJVUTXT_MEMORY_LIMIT Memory limit for the DjVu description software
+        * Memory limit for the DjVu description software
         */
        const DJVUTXT_MEMORY_LIMIT = 300000;
 
@@ -108,7 +111,7 @@ class DjVuImage {
                                $this->dumpForm( $file, $chunkLength, $indent + 1 );
                        } else {
                                fseek( $file, $chunkLength, SEEK_CUR );
-                               if ( $chunkLength & 1 == 1 ) {
+                               if ( $chunkLength & 1 ) {
                                        // Padding byte between chunks
                                        fseek( $file, 1, SEEK_CUR );
                                }
@@ -166,7 +169,7 @@ class DjVuImage {
        private function skipChunk( $file, $chunkLength ) {
                fseek( $file, $chunkLength, SEEK_CUR );
 
-               if ( $chunkLength & 0x01 == 1 && !feof( $file ) ) {
+               if ( ( $chunkLength & 1 ) && !feof( $file ) ) {
                        // padding byte
                        fseek( $file, 1, SEEK_CUR );
                }
@@ -253,19 +256,19 @@ class DjVuImage {
                if ( isset( $wgDjvuDump ) ) {
                        # djvudump is faster as of version 3.5
                        # https://sourceforge.net/p/djvu/bugs/71/
-                       $cmd = wfEscapeShellArg( $wgDjvuDump ) . ' ' . wfEscapeShellArg( $this->mFilename );
+                       $cmd = Shell::escape( $wgDjvuDump ) . ' ' . Shell::escape( $this->mFilename );
                        $dump = wfShellExec( $cmd );
                        $xml = $this->convertDumpToXML( $dump );
                } elseif ( isset( $wgDjvuToXML ) ) {
-                       $cmd = wfEscapeShellArg( $wgDjvuToXML ) . ' --without-anno --without-text ' .
-                               wfEscapeShellArg( $this->mFilename );
+                       $cmd = Shell::escape( $wgDjvuToXML ) . ' --without-anno --without-text ' .
+                               Shell::escape( $this->mFilename );
                        $xml = wfShellExec( $cmd );
                } else {
                        $xml = null;
                }
                # Text layer
                if ( isset( $wgDjvuTxt ) ) {
-                       $cmd = wfEscapeShellArg( $wgDjvuTxt ) . ' --detail=page ' . wfEscapeShellArg( $this->mFilename );
+                       $cmd = Shell::escape( $wgDjvuTxt ) . ' --detail=page ' . Shell::escape( $this->mFilename );
                        wfDebug( __METHOD__ . ": $cmd\n" );
                        $retval = '';
                        $txt = wfShellExec( $cmd, $retval, [], [ 'memory' => self::DJVUTXT_MEMORY_LIMIT ] );
index 0fde386..6dfa8d3 100644 (file)
@@ -548,6 +548,7 @@ class Exif {
        /**#@+
         * @return array
         */
+
        /**
         * Get $this->mRawExifData
         * @return array
index 345b3cb..333c610 100644 (file)
@@ -1181,7 +1181,7 @@ class FormatMetadata extends ContextSource {
                $langName = Language::fetchLanguageName( $lowLang );
                if ( $langName === '' ) {
                        // try just the base language name. (aka en-US -> en ).
-                       list( $langPrefix ) = explode( '-', $lowLang, 2 );
+                       $langPrefix = explode( '-', $lowLang, 2 )[0];
                        $langName = Language::fetchLanguageName( $langPrefix );
                        if ( $langName === '' ) {
                                // give up.
index 556e83c..9ef37fb 100644 (file)
@@ -86,8 +86,11 @@ class GIFHandler extends BitmapHandler {
                $ser = $image->getMetadata();
                if ( $ser ) {
                        $metadata = unserialize( $ser );
-
-                       return $image->getWidth() * $image->getHeight() * $metadata['frameCount'];
+                       if ( isset( $metadata['frameCount'] ) && $metadata['frameCount'] > 0 ) {
+                               return $image->getWidth() * $image->getHeight() * $metadata['frameCount'];
+                       } else {
+                               return $image->getWidth() * $image->getHeight();
+                       }
                } else {
                        return $image->getWidth() * $image->getHeight();
                }
@@ -101,7 +104,7 @@ class GIFHandler extends BitmapHandler {
                $ser = $image->getMetadata();
                if ( $ser ) {
                        $metadata = unserialize( $ser );
-                       if ( $metadata['frameCount'] > 1 ) {
+                       if ( isset( $metadata['frameCount'] ) && $metadata['frameCount'] > 1 ) {
                                return true;
                        }
                }
index 4bcb53d..4aca5b3 100644 (file)
@@ -21,6 +21,8 @@
  * @ingroup Media
  */
 
+use MediaWiki\Shell\Shell;
+
 /**
  * JPEG specific handler.
  * Inherits most stuff from BitmapHandler, just here to do the metadata handler differently.
@@ -140,17 +142,23 @@ class JpegHandler extends ExifBitmapHandler {
                $rotation = ( $params['rotation'] + $this->getRotation( $file ) ) % 360;
 
                if ( $wgJpegTran && is_executable( $wgJpegTran ) ) {
-                       $cmd = wfEscapeShellArg( $wgJpegTran ) .
-                               " -rotate " . wfEscapeShellArg( $rotation ) .
-                               " -outfile " . wfEscapeShellArg( $params['dstPath'] ) .
-                               " " . wfEscapeShellArg( $params['srcPath'] );
-                       wfDebug( __METHOD__ . ": running jpgtran: $cmd\n" );
-                       $retval = 0;
-                       $err = wfShellExecWithStderr( $cmd, $retval );
-                       if ( $retval !== 0 ) {
-                               $this->logErrorForExternalProcess( $retval, $err, $cmd );
-
-                               return new MediaTransformError( 'thumbnail_error', 0, 0, $err );
+                       $command = Shell::command( $wgJpegTran,
+                               '-rotate',
+                               $rotation,
+                               '-outfile',
+                               $params['dstPath'],
+                               $params['srcPath']
+                       );
+                       $result = $command
+                               ->includeStderr()
+                               ->execute();
+                       if ( $result->getExitCode() !== 0 ) {
+                               $this->logErrorForExternalProcess( $result->getExitCode(),
+                                       $result->getStdout(),
+                                       $command
+                               );
+
+                               return new MediaTransformError( 'thumbnail_error', 0, 0, $result->getStdout() );
                        }
 
                        return false;
@@ -240,20 +248,21 @@ class JpegHandler extends ExifBitmapHandler {
                        return false;
                }
 
-               $cmd = wfEscapeShellArg( $wgExiftool,
+               $result = Shell::command(
+                       $wgExiftool,
                        '-EXIF:ColorSpace',
                        '-ICC_Profile:ProfileDescription',
                        '-S',
                        '-T',
                        $filepath
-               );
-
-               $output = wfShellExecWithStderr( $cmd, $retval );
+               )
+                       ->includeStderr()
+                       ->execute();
 
                // Explode EXIF data into an array with [0 => Color Space, 1 => Device Model Desc]
-               $data = explode( "\t", trim( $output ) );
+               $data = explode( "\t", trim( $result->getStdout() ) );
 
-               if ( $retval !== 0 ) {
+               if ( $result->getExitCode() !== 0 ) {
                        return false;
                }
 
@@ -271,16 +280,20 @@ class JpegHandler extends ExifBitmapHandler {
                        return false;
                }
 
-               $cmd = wfEscapeShellArg( $wgExiftool,
+               $command = Shell::command( $wgExiftool,
                        '-overwrite_original',
                        '-icc_profile<=' . $profileFilepath,
                        $filepath
                );
-
-               $output = wfShellExecWithStderr( $cmd, $retval );
-
-               if ( $retval !== 0 ) {
-                       $this->logErrorForExternalProcess( $retval, $output, $cmd );
+               $result = $command
+                       ->includeStderr()
+                       ->execute();
+
+               if ( $result->getExitCode() !== 0 ) {
+                       $this->logErrorForExternalProcess( $result->getExitCode(),
+                               $result->getStdout(),
+                               $command
+                       );
 
                        return false;
                }
index a54da7d..1a96c1d 100644 (file)
@@ -104,7 +104,7 @@ abstract class MediaHandler {
         *   Warning, FSFile::getPropsFromPath might pass an FSFile instead of File (!)
         * @param string $path The filename
         * @return array|bool Follow the format of PHP getimagesize() internal function.
-        *   See https://secure.php.net/getimagesize. MediaWiki will only ever use the
+        *   See https://www.php.net/getimagesize. MediaWiki will only ever use the
         *   first two array keys (the width and height), and the 'bits' associative
         *   key. All other array keys are ignored. Returning a 'bits' key is optional
         *   as not all formats have a notion of "bitdepth". Returns false on failure.
index 543dc80..82e8d1f 100644 (file)
@@ -66,11 +66,7 @@ class MediaHandlerFactory {
        }
 
        protected function getHandlerClass( $type ) {
-               if ( isset( $this->registry[$type] ) ) {
-                       return $this->registry[$type];
-               } else {
-                       return false;
-               }
+               return $this->registry[$type] ?? false;
        }
 
        /**
diff --git a/includes/media/MediaTransformError.php b/includes/media/MediaTransformError.php
new file mode 100644 (file)
index 0000000..fb1b015
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+/**
+ * Base class for the output of file transformation methods.
+ *
+ * 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 Media
+ */
+
+/**
+ * Basic media transform error class
+ *
+ * @ingroup Media
+ */
+class MediaTransformError extends MediaTransformOutput {
+       /** @var Message */
+       private $msg;
+
+       function __construct( $msg, $width, $height, ...$args ) {
+               $this->msg = wfMessage( $msg )->params( $args );
+               $this->width = intval( $width );
+               $this->height = intval( $height );
+               $this->url = false;
+               $this->path = false;
+       }
+
+       function toHtml( $options = [] ) {
+               return "<div class=\"MediaTransformError\" style=\"" .
+                       "width: {$this->width}px; height: {$this->height}px; display:inline-block;\">" .
+                       $this->getHtmlMsg() .
+                       "</div>";
+       }
+
+       function toText() {
+               return $this->msg->text();
+       }
+
+       function getHtmlMsg() {
+               return $this->msg->escaped();
+       }
+
+       function getMsg() {
+               return $this->msg;
+       }
+
+       function isError() {
+               return true;
+       }
+
+       function getHttpStatusCode() {
+               return 500;
+       }
+}
index 87b4be7..463a794 100644 (file)
@@ -202,7 +202,8 @@ abstract class MediaTransformOutput {
                        return Status::newFatal( 'backend-fail-stream', '<no path>' );
                } elseif ( FileBackend::isStoragePath( $this->path ) ) {
                        $be = $this->file->getRepo()->getBackend();
-                       return $be->streamFile( [ 'src' => $this->path, 'headers' => $headers ] );
+                       return Status::wrap(
+                               $be->streamFile( [ 'src' => $this->path, 'headers' => $headers ] ) );
                } else { // FS-file
                        $success = StreamFile::stream( $this->getLocalCopyPath(), $headers );
                        return $success ? Status::newGood() : Status::newFatal( 'backend-fail-stream', $this->path );
@@ -268,270 +269,3 @@ abstract class MediaTransformOutput {
                return $attribs;
        }
 }
-
-/**
- * Media transform output for images
- *
- * @ingroup Media
- */
-class ThumbnailImage extends MediaTransformOutput {
-       private static $firstNonIconImageRendered = false;
-
-       /**
-        * Get a thumbnail object from a file and parameters.
-        * If $path is set to null, the output file is treated as a source copy.
-        * If $path is set to false, no output file will be created.
-        * $parameters should include, as a minimum, (file) 'width' and 'height'.
-        * It may also include a 'page' parameter for multipage files.
-        *
-        * @param File $file
-        * @param string $url URL path to the thumb
-        * @param string|bool $path Filesystem path to the thumb
-        * @param array $parameters Associative array of parameters
-        */
-       function __construct( $file, $url, $path = false, $parameters = [] ) {
-               # Previous parameters:
-               #   $file, $url, $width, $height, $path = false, $page = false
-
-               $defaults = [
-                       'page' => false,
-                       'lang' => false
-               ];
-
-               if ( is_array( $parameters ) ) {
-                       $actualParams = $parameters + $defaults;
-               } else {
-                       # Using old format, should convert. Later a warning could be added here.
-                       $numArgs = func_num_args();
-                       $actualParams = [
-                               'width' => $path,
-                               'height' => $parameters,
-                               'page' => ( $numArgs > 5 ) ? func_get_arg( 5 ) : false
-                       ] + $defaults;
-                       $path = ( $numArgs > 4 ) ? func_get_arg( 4 ) : false;
-               }
-
-               $this->file = $file;
-               $this->url = $url;
-               $this->path = $path;
-
-               # These should be integers when they get here.
-               # If not, there's a bug somewhere.  But let's at
-               # least produce valid HTML code regardless.
-               $this->width = round( $actualParams['width'] );
-               $this->height = round( $actualParams['height'] );
-
-               $this->page = $actualParams['page'];
-               $this->lang = $actualParams['lang'];
-       }
-
-       /**
-        * Return HTML <img ... /> tag for the thumbnail, will include
-        * width and height attributes and a blank alt text (as required).
-        *
-        * @param array $options Associative array of options. Boolean options
-        *     should be indicated with a value of true for true, and false or
-        *     absent for false.
-        *
-        *     alt          HTML alt attribute
-        *     title        HTML title attribute
-        *     desc-link    Boolean, show a description link
-        *     file-link    Boolean, show a file download link
-        *     valign       vertical-align property, if the output is an inline element
-        *     img-class    Class applied to the \<img\> tag, if there is such a tag
-        *     desc-query   String, description link query params
-        *     override-width     Override width attribute. Should generally not set
-        *     override-height    Override height attribute. Should generally not set
-        *     no-dimensions      Boolean, skip width and height attributes (useful if
-        *                        set in CSS)
-        *     custom-url-link    Custom URL to link to
-        *     custom-title-link  Custom Title object to link to
-        *     custom target-link Value of the target attribute, for custom-target-link
-        *     parser-extlink-*   Attributes added by parser for external links:
-        *          parser-extlink-rel: add rel="nofollow"
-        *          parser-extlink-target: link target, but overridden by custom-target-link
-        *
-        * For images, desc-link and file-link are implemented as a click-through. For
-        * sounds and videos, they may be displayed in other ways.
-        *
-        * @throws MWException
-        * @return string
-        */
-       function toHtml( $options = [] ) {
-               global $wgPriorityHints;
-
-               if ( count( func_get_args() ) == 2 ) {
-                       throw new MWException( __METHOD__ . ' called in the old style' );
-               }
-
-               $alt = $options['alt'] ?? '';
-
-               $query = $options['desc-query'] ?? '';
-
-               $attribs = [
-                       'alt' => $alt,
-                       'src' => $this->url,
-                       'decoding' => 'async',
-               ];
-
-               if ( $wgPriorityHints
-                       && !self::$firstNonIconImageRendered
-                       && $this->width * $this->height > 100 * 100 ) {
-                       self::$firstNonIconImageRendered = true;
-
-                       $attribs['importance'] = 'high';
-               }
-
-               if ( !empty( $options['custom-url-link'] ) ) {
-                       $linkAttribs = [ 'href' => $options['custom-url-link'] ];
-                       if ( !empty( $options['title'] ) ) {
-                               $linkAttribs['title'] = $options['title'];
-                       }
-                       if ( !empty( $options['custom-target-link'] ) ) {
-                               $linkAttribs['target'] = $options['custom-target-link'];
-                       } elseif ( !empty( $options['parser-extlink-target'] ) ) {
-                               $linkAttribs['target'] = $options['parser-extlink-target'];
-                       }
-                       if ( !empty( $options['parser-extlink-rel'] ) ) {
-                               $linkAttribs['rel'] = $options['parser-extlink-rel'];
-                       }
-               } elseif ( !empty( $options['custom-title-link'] ) ) {
-                       /** @var Title $title */
-                       $title = $options['custom-title-link'];
-                       $linkAttribs = [
-                               'href' => $title->getLinkURL(),
-                               'title' => empty( $options['title'] ) ? $title->getFullText() : $options['title']
-                       ];
-               } elseif ( !empty( $options['desc-link'] ) ) {
-                       $linkAttribs = $this->getDescLinkAttribs(
-                               empty( $options['title'] ) ? null : $options['title'],
-                               $query
-                       );
-               } elseif ( !empty( $options['file-link'] ) ) {
-                       $linkAttribs = [ 'href' => $this->file->getUrl() ];
-               } else {
-                       $linkAttribs = false;
-                       if ( !empty( $options['title'] ) ) {
-                               $attribs['title'] = $options['title'];
-                       }
-               }
-
-               if ( empty( $options['no-dimensions'] ) ) {
-                       $attribs['width'] = $this->width;
-                       $attribs['height'] = $this->height;
-               }
-               if ( !empty( $options['valign'] ) ) {
-                       $attribs['style'] = "vertical-align: {$options['valign']}";
-               }
-               if ( !empty( $options['img-class'] ) ) {
-                       $attribs['class'] = $options['img-class'];
-               }
-               if ( isset( $options['override-height'] ) ) {
-                       $attribs['height'] = $options['override-height'];
-               }
-               if ( isset( $options['override-width'] ) ) {
-                       $attribs['width'] = $options['override-width'];
-               }
-
-               // Additional densities for responsive images, if specified.
-               // If any of these urls is the same as src url, it'll be excluded.
-               $responsiveUrls = array_diff( $this->responsiveUrls, [ $this->url ] );
-               if ( !empty( $responsiveUrls ) ) {
-                       $attribs['srcset'] = Html::srcSet( $responsiveUrls );
-               }
-
-               Hooks::run( 'ThumbnailBeforeProduceHTML', [ $this, &$attribs, &$linkAttribs ] );
-
-               return $this->linkWrap( $linkAttribs, Xml::element( 'img', $attribs ) );
-       }
-}
-
-/**
- * Basic media transform error class
- *
- * @ingroup Media
- */
-class MediaTransformError extends MediaTransformOutput {
-       /** @var Message */
-       private $msg;
-
-       function __construct( $msg, $width, $height /*, ... */ ) {
-               $args = array_slice( func_get_args(), 3 );
-               $this->msg = wfMessage( $msg )->params( $args );
-               $this->width = intval( $width );
-               $this->height = intval( $height );
-               $this->url = false;
-               $this->path = false;
-       }
-
-       function toHtml( $options = [] ) {
-               return "<div class=\"MediaTransformError\" style=\"" .
-                       "width: {$this->width}px; height: {$this->height}px; display:inline-block;\">" .
-                       $this->getHtmlMsg() .
-                       "</div>";
-       }
-
-       function toText() {
-               return $this->msg->text();
-       }
-
-       function getHtmlMsg() {
-               return $this->msg->escaped();
-       }
-
-       function getMsg() {
-               return $this->msg;
-       }
-
-       function isError() {
-               return true;
-       }
-
-       function getHttpStatusCode() {
-               return 500;
-       }
-}
-
-/**
- * Shortcut class for parameter validation errors
- *
- * @ingroup Media
- */
-class TransformParameterError extends MediaTransformError {
-       function __construct( $params ) {
-               parent::__construct( 'thumbnail_error',
-                       max( $params['width'] ?? 0, 120 ),
-                       max( $params['height'] ?? 0, 120 ),
-                       wfMessage( 'thumbnail_invalid_params' )
-               );
-       }
-
-       function getHttpStatusCode() {
-               return 400;
-       }
-}
-
-/**
- * Shortcut class for parameter file size errors
- *
- * @ingroup Media
- * @since 1.25
- */
-class TransformTooBigImageAreaError extends MediaTransformError {
-       function __construct( $params, $maxImageArea ) {
-               $msg = wfMessage( 'thumbnail_toobigimagearea' );
-               $msg->params(
-                       $msg->getLanguage()->formatComputingNumbers( $maxImageArea, 1000, "size-$1pixel" )
-               );
-
-               parent::__construct( 'thumbnail_error',
-                       max( $params['width'] ?? 0, 120 ),
-                       max( $params['height'] ?? 0, 120 ),
-                       $msg
-               );
-       }
-
-       function getHttpStatusCode() {
-               return 400;
-       }
-}
index bc5eb09..ac332b7 100644 (file)
@@ -35,361 +35,3 @@ class SVGMetadataExtractor {
                return $svg->getMetadata();
        }
 }
-
-/**
- * @ingroup Media
- */
-class SVGReader {
-       const DEFAULT_WIDTH = 512;
-       const DEFAULT_HEIGHT = 512;
-       const NS_SVG = 'http://www.w3.org/2000/svg';
-       const LANG_PREFIX_MATCH = 1;
-       const LANG_FULL_MATCH = 2;
-
-       /** @var null|XMLReader */
-       private $reader = null;
-
-       /** @var bool */
-       private $mDebug = false;
-
-       /** @var array */
-       private $metadata = [];
-       private $languages = [];
-       private $languagePrefixes = [];
-
-       /**
-        * Creates an SVGReader drawing from the source provided
-        * @param string $source URI from which to read
-        * @throws MWException|Exception
-        */
-       function __construct( $source ) {
-               global $wgSVGMetadataCutoff;
-               $this->reader = new XMLReader();
-
-               // Don't use $file->getSize() since file object passed to SVGHandler::getMetadata is bogus.
-               $size = filesize( $source );
-               if ( $size === false ) {
-                       throw new MWException( "Error getting filesize of SVG." );
-               }
-
-               if ( $size > $wgSVGMetadataCutoff ) {
-                       $this->debug( "SVG is $size bytes, which is bigger than $wgSVGMetadataCutoff. Truncating." );
-                       $contents = file_get_contents( $source, false, null, 0, $wgSVGMetadataCutoff );
-                       if ( $contents === false ) {
-                               throw new MWException( 'Error reading SVG file.' );
-                       }
-                       $this->reader->XML( $contents, null, LIBXML_NOERROR | LIBXML_NOWARNING );
-               } else {
-                       $this->reader->open( $source, null, LIBXML_NOERROR | LIBXML_NOWARNING );
-               }
-
-               // Expand entities, since Adobe Illustrator uses them for xmlns
-               // attributes (T33719). Note that libxml2 has some protection
-               // against large recursive entity expansions so this is not as
-               // insecure as it might appear to be. However, it is still extremely
-               // insecure. It's necessary to wrap any read() calls with
-               // libxml_disable_entity_loader() to avoid arbitrary local file
-               // inclusion, or even arbitrary code execution if the expect
-               // extension is installed (T48859).
-               $oldDisable = libxml_disable_entity_loader( true );
-               $this->reader->setParserProperty( XMLReader::SUBST_ENTITIES, true );
-
-               $this->metadata['width'] = self::DEFAULT_WIDTH;
-               $this->metadata['height'] = self::DEFAULT_HEIGHT;
-
-               // The size in the units specified by the SVG file
-               // (for the metadata box)
-               // Per the SVG spec, if unspecified, default to '100%'
-               $this->metadata['originalWidth'] = '100%';
-               $this->metadata['originalHeight'] = '100%';
-
-               // Because we cut off the end of the svg making an invalid one. Complicated
-               // try catch thing to make sure warnings get restored. Seems like there should
-               // be a better way.
-               Wikimedia\suppressWarnings();
-               try {
-                       $this->read();
-               } catch ( Exception $e ) {
-                       // Note, if this happens, the width/height will be taken to be 0x0.
-                       // Should we consider it the default 512x512 instead?
-                       Wikimedia\restoreWarnings();
-                       libxml_disable_entity_loader( $oldDisable );
-                       throw $e;
-               }
-               Wikimedia\restoreWarnings();
-               libxml_disable_entity_loader( $oldDisable );
-       }
-
-       /**
-        * @return array Array with the known metadata
-        */
-       public function getMetadata() {
-               return $this->metadata;
-       }
-
-       /**
-        * Read the SVG
-        * @throws MWException
-        * @return bool
-        */
-       protected function read() {
-               $keepReading = $this->reader->read();
-
-               /* Skip until first element */
-               while ( $keepReading && $this->reader->nodeType != XMLReader::ELEMENT ) {
-                       $keepReading = $this->reader->read();
-               }
-
-               if ( $this->reader->localName != 'svg' || $this->reader->namespaceURI != self::NS_SVG ) {
-                       throw new MWException( "Expected <svg> tag, got " .
-                               $this->reader->localName . " in NS " . $this->reader->namespaceURI );
-               }
-               $this->debug( "<svg> tag is correct." );
-               $this->handleSVGAttribs();
-
-               $exitDepth = $this->reader->depth;
-               $keepReading = $this->reader->read();
-               while ( $keepReading ) {
-                       $tag = $this->reader->localName;
-                       $type = $this->reader->nodeType;
-                       $isSVG = ( $this->reader->namespaceURI == self::NS_SVG );
-
-                       $this->debug( "$tag" );
-
-                       if ( $isSVG && $tag == 'svg' && $type == XMLReader::END_ELEMENT
-                               && $this->reader->depth <= $exitDepth
-                       ) {
-                               break;
-                       } elseif ( $isSVG && $tag == 'title' ) {
-                               $this->readField( $tag, 'title' );
-                       } elseif ( $isSVG && $tag == 'desc' ) {
-                               $this->readField( $tag, 'description' );
-                       } elseif ( $isSVG && $tag == 'metadata' && $type == XMLReader::ELEMENT ) {
-                               $this->readXml( 'metadata' );
-                       } elseif ( $isSVG && $tag == 'script' ) {
-                               // We normally do not allow scripted svgs.
-                               // However its possible to configure MW to let them
-                               // in, and such files should be considered animated.
-                               $this->metadata['animated'] = true;
-                       } elseif ( $tag !== '#text' ) {
-                               $this->debug( "Unhandled top-level XML tag $tag" );
-
-                               // Recurse into children of current tag, looking for animation and languages.
-                               $this->animateFilterAndLang( $tag );
-                       }
-
-                       // Goto next element, which is sibling of current (Skip children).
-                       $keepReading = $this->reader->next();
-               }
-
-               $this->reader->close();
-
-               $this->metadata['translations'] = $this->languages + $this->languagePrefixes;
-
-               return true;
-       }
-
-       /**
-        * Read a textelement from an element
-        *
-        * @param string $name Name of the element that we are reading from
-        * @param string $metafield Field that we will fill with the result
-        */
-       private function readField( $name, $metafield = null ) {
-               $this->debug( "Read field $metafield" );
-               if ( !$metafield || $this->reader->nodeType != XMLReader::ELEMENT ) {
-                       return;
-               }
-               $keepReading = $this->reader->read();
-               while ( $keepReading ) {
-                       if ( $this->reader->localName == $name
-                               && $this->reader->namespaceURI == self::NS_SVG
-                               && $this->reader->nodeType == XMLReader::END_ELEMENT
-                       ) {
-                               break;
-                       } elseif ( $this->reader->nodeType == XMLReader::TEXT ) {
-                               $this->metadata[$metafield] = trim( $this->reader->value );
-                       }
-                       $keepReading = $this->reader->read();
-               }
-       }
-
-       /**
-        * Read an XML snippet from an element
-        *
-        * @param string $metafield Field that we will fill with the result
-        * @throws MWException
-        */
-       private function readXml( $metafield = null ) {
-               $this->debug( "Read top level metadata" );
-               if ( !$metafield || $this->reader->nodeType != XMLReader::ELEMENT ) {
-                       return;
-               }
-               // @todo Find and store type of xml snippet. metadata['metadataType'] = "rdf"
-               $this->metadata[$metafield] = trim( $this->reader->readInnerXml() );
-
-               $this->reader->next();
-       }
-
-       /**
-        * Filter all children, looking for animated elements.
-        * Also get a list of languages that can be targeted.
-        *
-        * @param string $name Name of the element that we are reading from
-        */
-       private function animateFilterAndLang( $name ) {
-               $this->debug( "animate filter for tag $name" );
-               if ( $this->reader->nodeType != XMLReader::ELEMENT ) {
-                       return;
-               }
-               if ( $this->reader->isEmptyElement ) {
-                       return;
-               }
-               $exitDepth = $this->reader->depth;
-               $keepReading = $this->reader->read();
-               while ( $keepReading ) {
-                       if ( $this->reader->localName == $name && $this->reader->depth <= $exitDepth
-                               && $this->reader->nodeType == XMLReader::END_ELEMENT
-                       ) {
-                               break;
-                       } elseif ( $this->reader->namespaceURI == self::NS_SVG
-                               && $this->reader->nodeType == XMLReader::ELEMENT
-                       ) {
-                               $sysLang = $this->reader->getAttribute( 'systemLanguage' );
-                               if ( !is_null( $sysLang ) && $sysLang !== '' ) {
-                                       // See https://www.w3.org/TR/SVG/struct.html#SystemLanguageAttribute
-                                       $langList = explode( ',', $sysLang );
-                                       foreach ( $langList as $langItem ) {
-                                               $langItem = trim( $langItem );
-                                               if ( Language::isWellFormedLanguageTag( $langItem ) ) {
-                                                       $this->languages[$langItem] = self::LANG_FULL_MATCH;
-                                               }
-                                               // Note, the standard says that any prefix should work,
-                                               // here we do only the initial prefix, since that will catch
-                                               // 99% of cases, and we are going to compare against fallbacks.
-                                               // This differs mildly from how the spec says languages should be
-                                               // handled, however it matches better how the MediaWiki language
-                                               // preference is generally handled.
-                                               $dash = strpos( $langItem, '-' );
-                                               // Intentionally checking both !false and > 0 at the same time.
-                                               if ( $dash ) {
-                                                       $itemPrefix = substr( $langItem, 0, $dash );
-                                                       if ( Language::isWellFormedLanguageTag( $itemPrefix ) ) {
-                                                               $this->languagePrefixes[$itemPrefix] = self::LANG_PREFIX_MATCH;
-                                                       }
-                                               }
-                                       }
-                               }
-                               switch ( $this->reader->localName ) {
-                                       case 'script':
-                                               // Normally we disallow files with
-                                               // <script>, but its possible
-                                               // to configure MW to disable
-                                               // such checks.
-                                       case 'animate':
-                                       case 'set':
-                                       case 'animateMotion':
-                                       case 'animateColor':
-                                       case 'animateTransform':
-                                               $this->debug( "HOUSTON WE HAVE ANIMATION" );
-                                               $this->metadata['animated'] = true;
-                                               break;
-                               }
-                       }
-                       $keepReading = $this->reader->read();
-               }
-       }
-
-       private function debug( $data ) {
-               if ( $this->mDebug ) {
-                       wfDebug( "SVGReader: $data\n" );
-               }
-       }
-
-       /**
-        * Parse the attributes of an SVG element
-        *
-        * The parser has to be in the start element of "<svg>"
-        */
-       private function handleSVGAttribs() {
-               $defaultWidth = self::DEFAULT_WIDTH;
-               $defaultHeight = self::DEFAULT_HEIGHT;
-               $aspect = 1.0;
-               $width = null;
-               $height = null;
-
-               if ( $this->reader->getAttribute( 'viewBox' ) ) {
-                       // min-x min-y width height
-                       $viewBox = preg_split( '/\s*[\s,]\s*/', trim( $this->reader->getAttribute( 'viewBox' ) ) );
-                       if ( count( $viewBox ) == 4 ) {
-                               $viewWidth = $this->scaleSVGUnit( $viewBox[2] );
-                               $viewHeight = $this->scaleSVGUnit( $viewBox[3] );
-                               if ( $viewWidth > 0 && $viewHeight > 0 ) {
-                                       $aspect = $viewWidth / $viewHeight;
-                                       $defaultHeight = $defaultWidth / $aspect;
-                               }
-                       }
-               }
-               if ( $this->reader->getAttribute( 'width' ) ) {
-                       $width = $this->scaleSVGUnit( $this->reader->getAttribute( 'width' ), $defaultWidth );
-                       $this->metadata['originalWidth'] = $this->reader->getAttribute( 'width' );
-               }
-               if ( $this->reader->getAttribute( 'height' ) ) {
-                       $height = $this->scaleSVGUnit( $this->reader->getAttribute( 'height' ), $defaultHeight );
-                       $this->metadata['originalHeight'] = $this->reader->getAttribute( 'height' );
-               }
-
-               if ( !isset( $width ) && !isset( $height ) ) {
-                       $width = $defaultWidth;
-                       $height = $width / $aspect;
-               } elseif ( isset( $width ) && !isset( $height ) ) {
-                       $height = $width / $aspect;
-               } elseif ( isset( $height ) && !isset( $width ) ) {
-                       $width = $height * $aspect;
-               }
-
-               if ( $width > 0 && $height > 0 ) {
-                       $this->metadata['width'] = intval( round( $width ) );
-                       $this->metadata['height'] = intval( round( $height ) );
-               }
-       }
-
-       /**
-        * Return a rounded pixel equivalent for a labeled CSS/SVG length.
-        * https://www.w3.org/TR/SVG11/coords.html#Units
-        *
-        * @param string $length CSS/SVG length.
-        * @param float|int $viewportSize Optional scale for percentage units...
-        * @return float Length in pixels
-        */
-       static function scaleSVGUnit( $length, $viewportSize = 512 ) {
-               static $unitLength = [
-                       'px' => 1.0,
-                       'pt' => 1.25,
-                       'pc' => 15.0,
-                       'mm' => 3.543307,
-                       'cm' => 35.43307,
-                       'in' => 90.0,
-                       'em' => 16.0, // fake it?
-                       'ex' => 12.0, // fake it?
-                       '' => 1.0, // "User units" pixels by default
-               ];
-               $matches = [];
-               if ( preg_match(
-                       '/^\s*([-+]?\d*(?:\.\d+|\d+)(?:[Ee][-+]?\d+)?)\s*(em|ex|px|pt|pc|cm|mm|in|%|)\s*$/',
-                       $length,
-                       $matches
-               ) ) {
-                       $length = floatval( $matches[1] );
-                       $unit = $matches[2];
-                       if ( $unit == '%' ) {
-                               return $length * 0.01 * $viewportSize;
-                       } else {
-                               return $length * $unitLength[$unit];
-                       }
-               } else {
-                       // Assume pixels
-                       return floatval( $length );
-               }
-       }
-}
diff --git a/includes/media/SVGReader.php b/includes/media/SVGReader.php
new file mode 100644 (file)
index 0000000..480aec5
--- /dev/null
@@ -0,0 +1,384 @@
+<?php
+/**
+ * Extraction of SVG image metadata.
+ *
+ * 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 Media
+ * @author "Derk-Jan Hartman <hartman _at_ videolan d0t org>"
+ * @author Brion Vibber
+ * @copyright Copyright © 2010-2010 Brion Vibber, Derk-Jan Hartman
+ * @license GPL-2.0-or-later
+ */
+
+/**
+ * @ingroup Media
+ */
+class SVGReader {
+       const DEFAULT_WIDTH = 512;
+       const DEFAULT_HEIGHT = 512;
+       const NS_SVG = 'http://www.w3.org/2000/svg';
+       const LANG_PREFIX_MATCH = 1;
+       const LANG_FULL_MATCH = 2;
+
+       /** @var null|XMLReader */
+       private $reader = null;
+
+       /** @var bool */
+       private $mDebug = false;
+
+       /** @var array */
+       private $metadata = [];
+       private $languages = [];
+       private $languagePrefixes = [];
+
+       /**
+        * Creates an SVGReader drawing from the source provided
+        * @param string $source URI from which to read
+        * @throws MWException|Exception
+        */
+       function __construct( $source ) {
+               global $wgSVGMetadataCutoff;
+               $this->reader = new XMLReader();
+
+               // Don't use $file->getSize() since file object passed to SVGHandler::getMetadata is bogus.
+               $size = filesize( $source );
+               if ( $size === false ) {
+                       throw new MWException( "Error getting filesize of SVG." );
+               }
+
+               if ( $size > $wgSVGMetadataCutoff ) {
+                       $this->debug( "SVG is $size bytes, which is bigger than $wgSVGMetadataCutoff. Truncating." );
+                       $contents = file_get_contents( $source, false, null, 0, $wgSVGMetadataCutoff );
+                       if ( $contents === false ) {
+                               throw new MWException( 'Error reading SVG file.' );
+                       }
+                       $this->reader->XML( $contents, null, LIBXML_NOERROR | LIBXML_NOWARNING );
+               } else {
+                       $this->reader->open( $source, null, LIBXML_NOERROR | LIBXML_NOWARNING );
+               }
+
+               // Expand entities, since Adobe Illustrator uses them for xmlns
+               // attributes (T33719). Note that libxml2 has some protection
+               // against large recursive entity expansions so this is not as
+               // insecure as it might appear to be. However, it is still extremely
+               // insecure. It's necessary to wrap any read() calls with
+               // libxml_disable_entity_loader() to avoid arbitrary local file
+               // inclusion, or even arbitrary code execution if the expect
+               // extension is installed (T48859).
+               $oldDisable = libxml_disable_entity_loader( true );
+               $this->reader->setParserProperty( XMLReader::SUBST_ENTITIES, true );
+
+               $this->metadata['width'] = self::DEFAULT_WIDTH;
+               $this->metadata['height'] = self::DEFAULT_HEIGHT;
+
+               // The size in the units specified by the SVG file
+               // (for the metadata box)
+               // Per the SVG spec, if unspecified, default to '100%'
+               $this->metadata['originalWidth'] = '100%';
+               $this->metadata['originalHeight'] = '100%';
+
+               // Because we cut off the end of the svg making an invalid one. Complicated
+               // try catch thing to make sure warnings get restored. Seems like there should
+               // be a better way.
+               Wikimedia\suppressWarnings();
+               try {
+                       $this->read();
+               } catch ( Exception $e ) {
+                       // Note, if this happens, the width/height will be taken to be 0x0.
+                       // Should we consider it the default 512x512 instead?
+                       Wikimedia\restoreWarnings();
+                       libxml_disable_entity_loader( $oldDisable );
+                       throw $e;
+               }
+               Wikimedia\restoreWarnings();
+               libxml_disable_entity_loader( $oldDisable );
+       }
+
+       /**
+        * @return array Array with the known metadata
+        */
+       public function getMetadata() {
+               return $this->metadata;
+       }
+
+       /**
+        * Read the SVG
+        * @throws MWException
+        * @return bool
+        */
+       protected function read() {
+               $keepReading = $this->reader->read();
+
+               /* Skip until first element */
+               while ( $keepReading && $this->reader->nodeType != XMLReader::ELEMENT ) {
+                       $keepReading = $this->reader->read();
+               }
+
+               if ( $this->reader->localName != 'svg' || $this->reader->namespaceURI != self::NS_SVG ) {
+                       throw new MWException( "Expected <svg> tag, got " .
+                               $this->reader->localName . " in NS " . $this->reader->namespaceURI );
+               }
+               $this->debug( "<svg> tag is correct." );
+               $this->handleSVGAttribs();
+
+               $exitDepth = $this->reader->depth;
+               $keepReading = $this->reader->read();
+               while ( $keepReading ) {
+                       $tag = $this->reader->localName;
+                       $type = $this->reader->nodeType;
+                       $isSVG = ( $this->reader->namespaceURI == self::NS_SVG );
+
+                       $this->debug( "$tag" );
+
+                       if ( $isSVG && $tag == 'svg' && $type == XMLReader::END_ELEMENT
+                               && $this->reader->depth <= $exitDepth
+                       ) {
+                               break;
+                       } elseif ( $isSVG && $tag == 'title' ) {
+                               $this->readField( $tag, 'title' );
+                       } elseif ( $isSVG && $tag == 'desc' ) {
+                               $this->readField( $tag, 'description' );
+                       } elseif ( $isSVG && $tag == 'metadata' && $type == XMLReader::ELEMENT ) {
+                               $this->readXml( 'metadata' );
+                       } elseif ( $isSVG && $tag == 'script' ) {
+                               // We normally do not allow scripted svgs.
+                               // However its possible to configure MW to let them
+                               // in, and such files should be considered animated.
+                               $this->metadata['animated'] = true;
+                       } elseif ( $tag !== '#text' ) {
+                               $this->debug( "Unhandled top-level XML tag $tag" );
+
+                               // Recurse into children of current tag, looking for animation and languages.
+                               $this->animateFilterAndLang( $tag );
+                       }
+
+                       // Goto next element, which is sibling of current (Skip children).
+                       $keepReading = $this->reader->next();
+               }
+
+               $this->reader->close();
+
+               $this->metadata['translations'] = $this->languages + $this->languagePrefixes;
+
+               return true;
+       }
+
+       /**
+        * Read a textelement from an element
+        *
+        * @param string $name Name of the element that we are reading from
+        * @param string $metafield Field that we will fill with the result
+        */
+       private function readField( $name, $metafield = null ) {
+               $this->debug( "Read field $metafield" );
+               if ( !$metafield || $this->reader->nodeType != XMLReader::ELEMENT ) {
+                       return;
+               }
+               $keepReading = $this->reader->read();
+               while ( $keepReading ) {
+                       if ( $this->reader->localName == $name
+                               && $this->reader->namespaceURI == self::NS_SVG
+                               && $this->reader->nodeType == XMLReader::END_ELEMENT
+                       ) {
+                               break;
+                       } elseif ( $this->reader->nodeType == XMLReader::TEXT ) {
+                               $this->metadata[$metafield] = trim( $this->reader->value );
+                       }
+                       $keepReading = $this->reader->read();
+               }
+       }
+
+       /**
+        * Read an XML snippet from an element
+        *
+        * @param string $metafield Field that we will fill with the result
+        * @throws MWException
+        */
+       private function readXml( $metafield = null ) {
+               $this->debug( "Read top level metadata" );
+               if ( !$metafield || $this->reader->nodeType != XMLReader::ELEMENT ) {
+                       return;
+               }
+               // @todo Find and store type of xml snippet. metadata['metadataType'] = "rdf"
+               $this->metadata[$metafield] = trim( $this->reader->readInnerXml() );
+
+               $this->reader->next();
+       }
+
+       /**
+        * Filter all children, looking for animated elements.
+        * Also get a list of languages that can be targeted.
+        *
+        * @param string $name Name of the element that we are reading from
+        */
+       private function animateFilterAndLang( $name ) {
+               $this->debug( "animate filter for tag $name" );
+               if ( $this->reader->nodeType != XMLReader::ELEMENT ) {
+                       return;
+               }
+               if ( $this->reader->isEmptyElement ) {
+                       return;
+               }
+               $exitDepth = $this->reader->depth;
+               $keepReading = $this->reader->read();
+               while ( $keepReading ) {
+                       if ( $this->reader->localName == $name && $this->reader->depth <= $exitDepth
+                               && $this->reader->nodeType == XMLReader::END_ELEMENT
+                       ) {
+                               break;
+                       } elseif ( $this->reader->namespaceURI == self::NS_SVG
+                               && $this->reader->nodeType == XMLReader::ELEMENT
+                       ) {
+                               $sysLang = $this->reader->getAttribute( 'systemLanguage' );
+                               if ( !is_null( $sysLang ) && $sysLang !== '' ) {
+                                       // See https://www.w3.org/TR/SVG/struct.html#SystemLanguageAttribute
+                                       $langList = explode( ',', $sysLang );
+                                       foreach ( $langList as $langItem ) {
+                                               $langItem = trim( $langItem );
+                                               if ( Language::isWellFormedLanguageTag( $langItem ) ) {
+                                                       $this->languages[$langItem] = self::LANG_FULL_MATCH;
+                                               }
+                                               // Note, the standard says that any prefix should work,
+                                               // here we do only the initial prefix, since that will catch
+                                               // 99% of cases, and we are going to compare against fallbacks.
+                                               // This differs mildly from how the spec says languages should be
+                                               // handled, however it matches better how the MediaWiki language
+                                               // preference is generally handled.
+                                               $dash = strpos( $langItem, '-' );
+                                               // Intentionally checking both !false and > 0 at the same time.
+                                               if ( $dash ) {
+                                                       $itemPrefix = substr( $langItem, 0, $dash );
+                                                       if ( Language::isWellFormedLanguageTag( $itemPrefix ) ) {
+                                                               $this->languagePrefixes[$itemPrefix] = self::LANG_PREFIX_MATCH;
+                                                       }
+                                               }
+                                       }
+                               }
+                               switch ( $this->reader->localName ) {
+                                       case 'script':
+                                               // Normally we disallow files with
+                                               // <script>, but its possible
+                                               // to configure MW to disable
+                                               // such checks.
+                                       case 'animate':
+                                       case 'set':
+                                       case 'animateMotion':
+                                       case 'animateColor':
+                                       case 'animateTransform':
+                                               $this->debug( "HOUSTON WE HAVE ANIMATION" );
+                                               $this->metadata['animated'] = true;
+                                               break;
+                               }
+                       }
+                       $keepReading = $this->reader->read();
+               }
+       }
+
+       private function debug( $data ) {
+               if ( $this->mDebug ) {
+                       wfDebug( "SVGReader: $data\n" );
+               }
+       }
+
+       /**
+        * Parse the attributes of an SVG element
+        *
+        * The parser has to be in the start element of "<svg>"
+        */
+       private function handleSVGAttribs() {
+               $defaultWidth = self::DEFAULT_WIDTH;
+               $defaultHeight = self::DEFAULT_HEIGHT;
+               $aspect = 1.0;
+               $width = null;
+               $height = null;
+
+               if ( $this->reader->getAttribute( 'viewBox' ) ) {
+                       // min-x min-y width height
+                       $viewBox = preg_split( '/\s*[\s,]\s*/', trim( $this->reader->getAttribute( 'viewBox' ) ) );
+                       if ( count( $viewBox ) == 4 ) {
+                               $viewWidth = $this->scaleSVGUnit( $viewBox[2] );
+                               $viewHeight = $this->scaleSVGUnit( $viewBox[3] );
+                               if ( $viewWidth > 0 && $viewHeight > 0 ) {
+                                       $aspect = $viewWidth / $viewHeight;
+                                       $defaultHeight = $defaultWidth / $aspect;
+                               }
+                       }
+               }
+               if ( $this->reader->getAttribute( 'width' ) ) {
+                       $width = $this->scaleSVGUnit( $this->reader->getAttribute( 'width' ), $defaultWidth );
+                       $this->metadata['originalWidth'] = $this->reader->getAttribute( 'width' );
+               }
+               if ( $this->reader->getAttribute( 'height' ) ) {
+                       $height = $this->scaleSVGUnit( $this->reader->getAttribute( 'height' ), $defaultHeight );
+                       $this->metadata['originalHeight'] = $this->reader->getAttribute( 'height' );
+               }
+
+               if ( !isset( $width ) && !isset( $height ) ) {
+                       $width = $defaultWidth;
+                       $height = $width / $aspect;
+               } elseif ( isset( $width ) && !isset( $height ) ) {
+                       $height = $width / $aspect;
+               } elseif ( isset( $height ) && !isset( $width ) ) {
+                       $width = $height * $aspect;
+               }
+
+               if ( $width > 0 && $height > 0 ) {
+                       $this->metadata['width'] = intval( round( $width ) );
+                       $this->metadata['height'] = intval( round( $height ) );
+               }
+       }
+
+       /**
+        * Return a rounded pixel equivalent for a labeled CSS/SVG length.
+        * https://www.w3.org/TR/SVG11/coords.html#Units
+        *
+        * @param string $length CSS/SVG length.
+        * @param float|int $viewportSize Optional scale for percentage units...
+        * @return float Length in pixels
+        */
+       static function scaleSVGUnit( $length, $viewportSize = 512 ) {
+               static $unitLength = [
+                       'px' => 1.0,
+                       'pt' => 1.25,
+                       'pc' => 15.0,
+                       'mm' => 3.543307,
+                       'cm' => 35.43307,
+                       'in' => 90.0,
+                       'em' => 16.0, // fake it?
+                       'ex' => 12.0, // fake it?
+                       '' => 1.0, // "User units" pixels by default
+               ];
+               $matches = [];
+               if ( preg_match(
+                       '/^\s*([-+]?\d*(?:\.\d+|\d+)(?:[Ee][-+]?\d+)?)\s*(em|ex|px|pt|pc|cm|mm|in|%|)\s*$/',
+                       $length,
+                       $matches
+               ) ) {
+                       $length = floatval( $matches[1] );
+                       $unit = $matches[2];
+                       if ( $unit == '%' ) {
+                               return $length * 0.01 * $viewportSize;
+                       } else {
+                               return $length * $unitLength[$unit];
+                       }
+               } else {
+                       // Assume pixels
+                       return floatval( $length );
+               }
+       }
+}
index b7745df..bdda674 100644 (file)
@@ -20,6 +20,8 @@
  * @file
  * @ingroup Media
  */
+
+use MediaWiki\Shell\Shell;
 use Wikimedia\ScopedCallback;
 
 /**
@@ -199,20 +201,16 @@ class SvgHandler extends ImageHandler {
                                $params['physicalWidth'] = $wgSVGMaxSize;
                                $params['physicalHeight'] = File::scaleHeight( $srcWidth, $srcHeight, $wgSVGMaxSize );
                        }
-               } else {
-                       if ( $params['physicalHeight'] > $wgSVGMaxSize ) {
-                               $srcWidth = $image->getWidth( $params['page'] );
-                               $srcHeight = $image->getHeight( $params['page'] );
-                               $params['physicalWidth'] = File::scaleHeight( $srcHeight, $srcWidth, $wgSVGMaxSize );
-                               $params['physicalHeight'] = $wgSVGMaxSize;
-                       }
+               } elseif ( $params['physicalHeight'] > $wgSVGMaxSize ) {
+                       $srcWidth = $image->getWidth( $params['page'] );
+                       $srcHeight = $image->getHeight( $params['page'] );
+                       $params['physicalWidth'] = File::scaleHeight( $srcHeight, $srcWidth, $wgSVGMaxSize );
+                       $params['physicalHeight'] = $wgSVGMaxSize;
                }
                // To prevent the proliferation of thumbnails in languages not present in SVGs, unless
                // explicitly forced by user.
-               if ( isset( $params['targetlang'] ) ) {
-                       if ( !$image->getMatchedLanguage( $params['targetlang'] ) ) {
-                               unset( $params['targetlang'] );
-                       }
+               if ( isset( $params['targetlang'] ) && !$image->getMatchedLanguage( $params['targetlang'] ) ) {
+                       unset( $params['targetlang'] );
                }
 
                return $params;
@@ -339,11 +337,11 @@ class SvgHandler extends ImageHandler {
                                // External command
                                $cmd = str_replace(
                                        [ '$path/', '$width', '$height', '$input', '$output' ],
-                                       [ $wgSVGConverterPath ? wfEscapeShellArg( "$wgSVGConverterPath/" ) : "",
+                                       [ $wgSVGConverterPath ? Shell::escape( "$wgSVGConverterPath/" ) : "",
                                                intval( $width ),
                                                intval( $height ),
-                                               wfEscapeShellArg( $srcPath ),
-                                               wfEscapeShellArg( $dstPath ) ],
+                                               Shell::escape( $srcPath ),
+                                               Shell::escape( $dstPath ) ],
                                        $wgSVGConverters[$wgSVGConverter]
                                );
 
diff --git a/includes/media/ThumbnailImage.php b/includes/media/ThumbnailImage.php
new file mode 100644 (file)
index 0000000..7ee6dcb
--- /dev/null
@@ -0,0 +1,214 @@
+<?php
+/**
+ * Base class for the output of file transformation methods.
+ *
+ * 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 Media
+ */
+
+/**
+ * Media transform output for images
+ *
+ * @ingroup Media
+ */
+class ThumbnailImage extends MediaTransformOutput {
+       private static $firstNonIconImageRendered = false;
+
+       /**
+        * Get a thumbnail object from a file and parameters.
+        * If $path is set to null, the output file is treated as a source copy.
+        * If $path is set to false, no output file will be created.
+        * $parameters should include, as a minimum, (file) 'width' and 'height'.
+        * It may also include a 'page' parameter for multipage files.
+        *
+        * @param File $file
+        * @param string $url URL path to the thumb
+        * @param string|bool $path Filesystem path to the thumb
+        * @param array $parameters Associative array of parameters
+        */
+       function __construct( $file, $url, $path = false, $parameters = [] ) {
+               # Previous parameters:
+               #   $file, $url, $width, $height, $path = false, $page = false
+
+               $defaults = [
+                       'page' => false,
+                       'lang' => false
+               ];
+
+               if ( is_array( $parameters ) ) {
+                       $actualParams = $parameters + $defaults;
+               } else {
+                       # Using old format, should convert. Later a warning could be added here.
+                       $numArgs = func_num_args();
+                       $actualParams = [
+                               'width' => $path,
+                               'height' => $parameters,
+                               'page' => ( $numArgs > 5 ) ? func_get_arg( 5 ) : false
+                       ] + $defaults;
+                       $path = ( $numArgs > 4 ) ? func_get_arg( 4 ) : false;
+               }
+
+               $this->file = $file;
+               $this->url = $url;
+               $this->path = $path;
+
+               # These should be integers when they get here.
+               # If not, there's a bug somewhere.  But let's at
+               # least produce valid HTML code regardless.
+               $this->width = round( $actualParams['width'] );
+               $this->height = round( $actualParams['height'] );
+
+               $this->page = $actualParams['page'];
+               $this->lang = $actualParams['lang'];
+       }
+
+       /**
+        * Return HTML <img ... /> tag for the thumbnail, will include
+        * width and height attributes and a blank alt text (as required).
+        *
+        * @param array $options Associative array of options. Boolean options
+        *     should be indicated with a value of true for true, and false or
+        *     absent for false.
+        *
+        *     alt          HTML alt attribute
+        *     title        HTML title attribute
+        *     desc-link    Boolean, show a description link
+        *     file-link    Boolean, show a file download link
+        *     valign       vertical-align property, if the output is an inline element
+        *     img-class    Class applied to the \<img\> tag, if there is such a tag
+        *     desc-query   String, description link query params
+        *     override-width     Override width attribute. Should generally not set
+        *     override-height    Override height attribute. Should generally not set
+        *     no-dimensions      Boolean, skip width and height attributes (useful if
+        *                        set in CSS)
+        *     custom-url-link    Custom URL to link to
+        *     custom-title-link  Custom Title object to link to
+        *     custom target-link Value of the target attribute, for custom-target-link
+        *     parser-extlink-*   Attributes added by parser for external links:
+        *          parser-extlink-rel: add rel="nofollow"
+        *          parser-extlink-target: link target, but overridden by custom-target-link
+        *
+        * For images, desc-link and file-link are implemented as a click-through. For
+        * sounds and videos, they may be displayed in other ways.
+        *
+        * @throws MWException
+        * @return string
+        */
+       function toHtml( $options = [] ) {
+               global $wgPriorityHints, $wgPriorityHintsRatio, $wgElementTiming;
+
+               if ( func_num_args() == 2 ) {
+                       throw new MWException( __METHOD__ . ' called in the old style' );
+               }
+
+               $alt = $options['alt'] ?? '';
+
+               $query = $options['desc-query'] ?? '';
+
+               $attribs = [
+                       'alt' => $alt,
+                       'src' => $this->url,
+                       'decoding' => 'async',
+               ];
+
+               $elementTimingName = 'thumbnail';
+
+               if ( $wgPriorityHints
+                       && !self::$firstNonIconImageRendered
+                       && $this->width * $this->height > 100 * 100 ) {
+                       self::$firstNonIconImageRendered = true;
+
+                       // Generate a random number between 0.01 and 1.0, included
+                       $random = rand( 1, 100 ) / 100.0;
+
+                       if ( $random <= $wgPriorityHintsRatio ) {
+                               $attribs['importance'] = 'high';
+                               $elementTimingName = 'thumbnail-high';
+                       } else {
+                               // This lets us track that the thumbnail *would* have gotten high priority but didn't.
+                               $elementTimingName = 'thumbnail-top';
+                       }
+               }
+
+               if ( $wgElementTiming ) {
+                       $attribs['elementtiming'] = $elementTimingName;
+               }
+
+               if ( !empty( $options['custom-url-link'] ) ) {
+                       $linkAttribs = [ 'href' => $options['custom-url-link'] ];
+                       if ( !empty( $options['title'] ) ) {
+                               $linkAttribs['title'] = $options['title'];
+                       }
+                       if ( !empty( $options['custom-target-link'] ) ) {
+                               $linkAttribs['target'] = $options['custom-target-link'];
+                       } elseif ( !empty( $options['parser-extlink-target'] ) ) {
+                               $linkAttribs['target'] = $options['parser-extlink-target'];
+                       }
+                       if ( !empty( $options['parser-extlink-rel'] ) ) {
+                               $linkAttribs['rel'] = $options['parser-extlink-rel'];
+                       }
+               } elseif ( !empty( $options['custom-title-link'] ) ) {
+                       /** @var Title $title */
+                       $title = $options['custom-title-link'];
+                       $linkAttribs = [
+                               'href' => $title->getLinkURL(),
+                               'title' => empty( $options['title'] ) ? $title->getFullText() : $options['title']
+                       ];
+               } elseif ( !empty( $options['desc-link'] ) ) {
+                       $linkAttribs = $this->getDescLinkAttribs(
+                               empty( $options['title'] ) ? null : $options['title'],
+                               $query
+                       );
+               } elseif ( !empty( $options['file-link'] ) ) {
+                       $linkAttribs = [ 'href' => $this->file->getUrl() ];
+               } else {
+                       $linkAttribs = false;
+                       if ( !empty( $options['title'] ) ) {
+                               $attribs['title'] = $options['title'];
+                       }
+               }
+
+               if ( empty( $options['no-dimensions'] ) ) {
+                       $attribs['width'] = $this->width;
+                       $attribs['height'] = $this->height;
+               }
+               if ( !empty( $options['valign'] ) ) {
+                       $attribs['style'] = "vertical-align: {$options['valign']}";
+               }
+               if ( !empty( $options['img-class'] ) ) {
+                       $attribs['class'] = $options['img-class'];
+               }
+               if ( isset( $options['override-height'] ) ) {
+                       $attribs['height'] = $options['override-height'];
+               }
+               if ( isset( $options['override-width'] ) ) {
+                       $attribs['width'] = $options['override-width'];
+               }
+
+               // Additional densities for responsive images, if specified.
+               // If any of these urls is the same as src url, it'll be excluded.
+               $responsiveUrls = array_diff( $this->responsiveUrls, [ $this->url ] );
+               if ( !empty( $responsiveUrls ) ) {
+                       $attribs['srcset'] = Html::srcSet( $responsiveUrls );
+               }
+
+               Hooks::run( 'ThumbnailBeforeProduceHTML', [ $this, &$attribs, &$linkAttribs ] );
+
+               return $this->linkWrap( $linkAttribs, Xml::element( 'img', $attribs ) );
+       }
+}
diff --git a/includes/media/TransformParameterError.php b/includes/media/TransformParameterError.php
new file mode 100644 (file)
index 0000000..0f26239
--- /dev/null
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Base class for the output of file transformation methods.
+ *
+ * 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 Media
+ */
+
+/**
+ * Shortcut class for parameter validation errors
+ *
+ * @ingroup Media
+ */
+class TransformParameterError extends MediaTransformError {
+       function __construct( $params ) {
+               parent::__construct( 'thumbnail_error',
+                       max( $params['width'] ?? 0, 120 ),
+                       max( $params['height'] ?? 0, 120 ),
+                       wfMessage( 'thumbnail_invalid_params' )
+               );
+       }
+
+       function getHttpStatusCode() {
+               return 400;
+       }
+}
diff --git a/includes/media/TransformTooBigImageAreaError.php b/includes/media/TransformTooBigImageAreaError.php
new file mode 100644 (file)
index 0000000..0a58ef3
--- /dev/null
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Base class for the output of file transformation methods.
+ *
+ * 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 Media
+ */
+
+/**
+ * Shortcut class for parameter file size errors
+ *
+ * @ingroup Media
+ * @since 1.25
+ */
+class TransformTooBigImageAreaError extends MediaTransformError {
+       function __construct( $params, $maxImageArea ) {
+               $msg = wfMessage( 'thumbnail_toobigimagearea' );
+               $msg->params(
+                       $msg->getLanguage()->formatComputingNumbers( $maxImageArea, 1000, "size-$1pixel" )
+               );
+
+               parent::__construct( 'thumbnail_error',
+                       max( $params['width'] ?? 0, 120 ),
+                       max( $params['height'] ?? 0, 120 ),
+                       $msg
+               );
+       }
+
+       function getHttpStatusCode() {
+               return 400;
+       }
+}
index 38dc390..dbeca0b 100644 (file)
@@ -26,6 +26,7 @@
  * @ingroup Media
  */
 use MediaWiki\MediaWikiServices;
+use MediaWiki\Shell\Shell;
 
 /**
  * Handler for images that need to be transformed
@@ -517,7 +518,7 @@ abstract class TransformationalImageHandler extends ImageHandler {
                        function () use ( $method ) {
                                global $wgImageMagickConvertCommand;
 
-                               $cmd = wfEscapeShellArg( $wgImageMagickConvertCommand ) . ' -version';
+                               $cmd = Shell::escape( $wgImageMagickConvertCommand ) . ' -version';
                                wfDebug( $method . ": Running convert -version\n" );
                                $retval = '';
                                $return = wfShellExecWithStderr( $cmd, $retval );
index 33f33bd..e47cc37 100644 (file)
@@ -67,7 +67,7 @@ class XCFHandler extends BitmapHandler {
                }
 
                # Forge a return array containing metadata information just like getimagesize()
-               # See PHP documentation at: https://secure.php.net/getimagesize
+               # See PHP documentation at: https://www.php.net/getimagesize
                return [
                        0 => $header['width'],
                        1 => $header['height'],
index dc8b146..bc87c70 100644 (file)
@@ -238,7 +238,6 @@ class ObjectCache {
                global $wgMainCacheType, $wgMessageCacheType, $wgParserCacheType;
                $candidates = [ $wgMainCacheType, $wgMessageCacheType, $wgParserCacheType ];
                foreach ( $candidates as $candidate ) {
-                       $cache = false;
                        if ( $candidate !== CACHE_NONE && $candidate !== CACHE_ANYTHING ) {
                                $cache = self::getInstance( $candidate );
                                // CACHE_ACCEL might default to nothing if no APCu
@@ -327,14 +326,6 @@ class ObjectCache {
                global $wgCommandLineMode;
 
                $services = MediaWikiServices::getInstance();
-
-               $erGroup = $services->getEventRelayerGroup();
-               if ( isset( $params['channels'] ) ) {
-                       foreach ( $params['channels'] as $action => $channel ) {
-                               $params['relayers'][$action] = $erGroup->getRelayer( $channel );
-                               $params['channels'][$action] = $channel;
-                       }
-               }
                $params['cache'] = self::newFromParams( $params['store'] );
                $params['logger'] = LoggerFactory::getInstance( $params['loggroup'] ?? 'objectcache' );
                if ( !$wgCommandLineMode ) {
index b2d61a8..088f94e 100644 (file)
@@ -234,22 +234,34 @@ class SqlBagOStuff extends BagOStuff {
                }
        }
 
-       protected function doGet( $key, $flags = 0 ) {
+       protected function doGet( $key, $flags = 0, &$casToken = null ) {
                $casToken = null;
 
-               return $this->getWithToken( $key, $casToken, $flags );
-       }
+               $blobs = $this->fetchBlobMulti( [ $key ] );
+               if ( array_key_exists( $key, $blobs ) ) {
+                       $blob = $blobs[$key];
+                       $value = $this->unserialize( $blob );
+
+                       $casToken = ( $value !== false ) ? $blob : null;
 
-       protected function getWithToken( $key, &$casToken, $flags = 0 ) {
-               $values = $this->getMulti( [ $key ] );
-               if ( array_key_exists( $key, $values ) ) {
-                       $casToken = $values[$key];
-                       return $values[$key];
+                       return $value;
                }
+
                return false;
        }
 
        public function getMulti( array $keys, $flags = 0 ) {
+               $values = [];
+
+               $blobs = $this->fetchBlobMulti( $keys );
+               foreach ( $blobs as $key => $blob ) {
+                       $values[$key] = $this->unserialize( $blob );
+               }
+
+               return $values;
+       }
+
+       public function fetchBlobMulti( array $keys, $flags = 0 ) {
                $values = []; // array of (key => value)
 
                $keysByTable = [];
@@ -298,7 +310,7 @@ class SqlBagOStuff extends BagOStuff {
                                        if ( $this->isExpired( $db, $row->exptime ) ) { // MISS
                                                $this->debug( "get: key has expired" );
                                        } else { // HIT
-                                               $values[$key] = $this->unserialize( $db->decodeBlob( $row->value ) );
+                                               $values[$key] = $db->decodeBlob( $row->value );
                                        }
                                } catch ( DBQueryError $e ) {
                                        $this->handleWriteError( $e, $db, $row->serverIndex );
@@ -344,7 +356,7 @@ class SqlBagOStuff extends BagOStuff {
                        if ( $exptime == 0 ) {
                                $encExpiry = $this->getMaxDateTime( $db );
                        } else {
-                               $exptime = $this->convertExpiry( $exptime );
+                               $exptime = $this->convertToExpiry( $exptime );
                                $encExpiry = $db->timestamp( $exptime );
                        }
                        foreach ( $serverKeys as $tableName => $tableKeys ) {
@@ -406,7 +418,7 @@ class SqlBagOStuff extends BagOStuff {
                        if ( $exptime == 0 ) {
                                $encExpiry = $this->getMaxDateTime( $db );
                        } else {
-                               $exptime = $this->convertExpiry( $exptime );
+                               $exptime = $this->convertToExpiry( $exptime );
                                $encExpiry = $db->timestamp( $exptime );
                        }
                        // (T26425) use a replace if the db supports it instead of
@@ -420,7 +432,7 @@ class SqlBagOStuff extends BagOStuff {
                                ],
                                [
                                        'keyname' => $key,
-                                       'value' => $db->encodeBlob( $this->serialize( $casToken ) )
+                                       'value' => $db->encodeBlob( $casToken )
                                ],
                                __METHOD__
                        );
@@ -519,7 +531,7 @@ class SqlBagOStuff extends BagOStuff {
                        }
                } catch ( DBError $e ) {
                        $this->handleWriteError( $e, $db, $serverIndex );
-                       return null;
+                       return false;
                }
 
                return $newValue;
@@ -534,20 +546,33 @@ class SqlBagOStuff extends BagOStuff {
                return $ok;
        }
 
-       public function changeTTL( $key, $expiry = 0, $flags = 0 ) {
+       public function changeTTL( $key, $exptime = 0, $flags = 0 ) {
                list( $serverIndex, $tableName ) = $this->getTableByKey( $key );
                $db = null;
                $silenceScope = $this->silenceTransactionProfiler();
                try {
                        $db = $this->getDB( $serverIndex );
+                       if ( $exptime == 0 ) {
+                               $timestamp = $this->getMaxDateTime( $db );
+                       } else {
+                               $timestamp = $db->timestamp( $this->convertToExpiry( $exptime ) );
+                       }
                        $db->update(
                                $tableName,
-                               [ 'exptime' => $db->timestamp( $this->convertExpiry( $expiry ) ) ],
+                               [ 'exptime' => $timestamp ],
                                [ 'keyname' => $key, 'exptime > ' . $db->addQuotes( $db->timestamp( time() ) ) ],
                                __METHOD__
                        );
                        if ( $db->affectedRows() == 0 ) {
-                               return false;
+                               $exists = (bool)$db->selectField(
+                                       $tableName,
+                                       1,
+                                       [ 'keyname' => $key, 'exptime' => $timestamp ],
+                                       __METHOD__,
+                                       [ 'FOR UPDATE' ]
+                               );
+
+                               return $exists;
                        }
                } catch ( DBError $e ) {
                        $this->handleWriteError( $e, $db, $serverIndex );
index d71cdcb..b20c83e 100644 (file)
@@ -1131,13 +1131,11 @@ class Article implements Page {
         * [[MediaWiki:Talkpagetext]]. For Article::view().
         */
        public function showNamespaceHeader() {
-               if ( $this->getTitle()->isTalkPage() ) {
-                       if ( !wfMessage( 'talkpageheader' )->isDisabled() ) {
-                               $this->getContext()->getOutput()->wrapWikiMsg(
-                                       "<div class=\"mw-talkpageheader\">\n$1\n</div>",
-                                       [ 'talkpageheader' ]
-                               );
-                       }
+               if ( $this->getTitle()->isTalkPage() && !wfMessage( 'talkpageheader' )->isDisabled() ) {
+                       $this->getContext()->getOutput()->wrapWikiMsg(
+                               "<div class=\"mw-talkpageheader\">\n$1\n</div>",
+                               [ 'talkpageheader' ]
+                       );
                }
        }
 
@@ -1354,6 +1352,8 @@ class Article implements Page {
 
                $title = $this->getTitle();
 
+               $services = MediaWikiServices::getInstance();
+
                # Show info in user (talk) namespace. Does the user exist? Is he blocked?
                if ( $title->getNamespace() == NS_USER
                        || $title->getNamespace() == NS_USER_TALK
@@ -1376,7 +1376,8 @@ class Article implements Page {
                                LogEventsList::showLogExtract(
                                        $outputPage,
                                        'block',
-                                       MWNamespace::getCanonicalName( NS_USER ) . ':' . $block->getTarget(),
+                                       $services->getNamespaceInfo()->getCanonicalName( NS_USER ) . ':' .
+                                               $block->getTarget(),
                                        '',
                                        [
                                                'lim' => 1,
@@ -1398,7 +1399,7 @@ class Article implements Page {
                # Show delete and move logs if there were any such events.
                # The logging query can DOS the site when bots/crawlers cause 404 floods,
                # so be careful showing this. 404 pages must be cheap as they are hard to cache.
-               $cache = MediaWikiServices::getInstance()->getMainObjectStash();
+               $cache = $services->getMainObjectStash();
                $key = $cache->makeKey( 'page-recent-delete', md5( $title->getPrefixedText() ) );
                $loggedIn = $this->getContext()->getUser()->isLoggedIn();
                $sessionExists = $this->getContext()->getRequest()->getSession()->isPersistent();
@@ -2733,7 +2734,7 @@ class Article implements Page {
         * @see WikiPage::setTimestamp
         */
        public function setTimestamp( $ts ) {
-               return $this->mPage->setTimestamp( $ts );
+               $this->mPage->setTimestamp( $ts );
        }
 
        /**
index 66804bc..86c59ad 100644 (file)
@@ -321,9 +321,7 @@ class ImagePage extends Article {
                $dirmark = $lang->getDirMarkEntity();
                $request = $this->getContext()->getRequest();
 
-               $max = $this->getImageLimitsFromOption( $user, 'imagesize' );
-               $maxWidth = $max[0];
-               $maxHeight = $max[1];
+               list( $maxWidth, $maxHeight ) = $this->getImageLimitsFromOption( $user, 'imagesize' );
 
                if ( $this->displayImg->exists() ) {
                        # image
@@ -963,7 +961,7 @@ EOT
                $out->addHTML( "<ul class='mw-imagepage-duplicates'>\n" );
 
                /**
-                * @var $file File
+                * @var File $file
                 */
                foreach ( $dupes as $file ) {
                        $fromSrc = '';
@@ -1029,7 +1027,7 @@ EOT
         *
         * @param User $user
         * @param string $optionName Name of a option to check, typically imagesize or thumbsize
-        * @return array
+        * @return int[]
         * @since 1.21
         */
        public function getImageLimitsFromOption( $user, $optionName ) {
@@ -1224,7 +1222,7 @@ EOT
         * @return TitleArray|Title[]
         */
        public function getForeignCategories() {
-               $this->mPage->getForeignCategories();
+               return $this->mPage->getForeignCategories();
        }
 
 }
index e843cf3..a314f3a 100644 (file)
@@ -21,7 +21,6 @@
 use MediaWiki\MediaWikiServices;
 use MediaWiki\Revision\RevisionRecord;
 use MediaWiki\Revision\RevisionStore;
-use MediaWiki\Storage\SqlBlobStore;
 use Wikimedia\Assert\Assert;
 use Wikimedia\Rdbms\IResultWrapper;
 use Wikimedia\Rdbms\IDatabase;
@@ -69,23 +68,6 @@ class PageArchive {
                return true;
        }
 
-       /**
-        * List all deleted pages recorded in the archive table. Returns result
-        * wrapper with (ar_namespace, ar_title, count) fields, ordered by page
-        * namespace/title.
-        *
-        * @deprecated since 1.32.
-        *
-        * @return IResultWrapper
-        */
-       public static function listAllPages() {
-               wfDeprecated( __METHOD__, '1.32' );
-
-               $dbr = wfGetDB( DB_REPLICA );
-
-               return self::listPages( $dbr, '' );
-       }
-
        /**
         * List deleted pages recorded in the archive matching the
         * given term, using search engine archive.
@@ -370,59 +352,6 @@ class PageArchive {
                return $rec;
        }
 
-       /**
-        * Get the text from an archive row containing ar_text_id.
-        *
-        * @deprecated since 1.32. In the MCR schema, ar_text_id no longer exists.
-        * Calling code should switch to getArchiveRevision().
-        *
-        * @todo remove in 1.33
-        *
-        * @param object $row Database row
-        * @return string
-        */
-       public function getTextFromRow( $row ) {
-               wfDeprecated( __METHOD__, '1.32' );
-
-               if ( empty( $row->ar_text_id ) ) {
-                       throw new InvalidArgumentException( '$row->ar_text_id must be set and not empty!' );
-               }
-
-               $address = SqlBlobStore::makeAddressFromTextId( $row->ar_text_id );
-               $blobStore = MediaWikiServices::getInstance()->getBlobStore();
-
-               return $blobStore->getBlob( $address );
-       }
-
-       /**
-        * Fetch (and decompress if necessary) the stored text of the most
-        * recently edited deleted revision of the page.
-        *
-        * If there are no archived revisions for the page, returns NULL.
-        *
-        * @note this bypasses any audience checks.
-        *
-        * @deprecated since 1.32. For compatibility with the MCR schema,
-        * calling code should switch to getLastRevisionId() and getArchiveRevision().
-        *
-        * @todo remove in 1.33
-        *
-        * @return string|null
-        */
-       public function getLastRevisionText() {
-               wfDeprecated( __METHOD__, '1.32' );
-
-               $revId = $this->getLastRevisionId();
-
-               if ( $revId ) {
-                       $rev = $this->getArchivedRevision( $revId );
-                       $content = $rev->getContent( RevisionRecord::RAW );
-                       return $content->serialize();
-               }
-
-               return null;
-       }
-
        /**
         * Returns the ID of the latest deleted revision.
         *
index 4b0e503..863a3f3 100644 (file)
@@ -1962,9 +1962,7 @@ class WikiPage implements Page, IDBAccessObject {
         * @deprecated since 1.32, use getDerivedDataUpdater instead.
         *
         * @param Content $content
-        * @param Revision|RevisionRecord|int|null $revision Revision object.
-        *        For backwards compatibility, a revision ID is also accepted,
-        *        but this is deprecated.
+        * @param Revision|RevisionRecord|null $revision Revision object.
         *        Used with vary-revision or vary-revision-id.
         * @param User|null $user
         * @param string|null $serialFormat IGNORED
@@ -1987,19 +1985,13 @@ class WikiPage implements Page, IDBAccessObject {
                        $user = $wgUser;
                }
 
-               if ( !is_object( $revision ) ) {
-                       $revid = $revision;
-                       // This code path is deprecated, and nothing is known to
-                       // use it, so performance here shouldn't be a worry.
-                       if ( $revid !== null ) {
-                               wfDeprecated( __METHOD__ . ' with $revision = revision ID', '1.25' );
-                               $store = $this->getRevisionStore();
-                               $revision = $store->getRevisionById( $revid, Revision::READ_LATEST );
-                       } else {
-                               $revision = null;
+               if ( $revision !== null ) {
+                       if ( $revision instanceof Revision ) {
+                               $revision = $revision->getRevisionRecord();
+                       } elseif ( !( $revision instanceof RevisionRecord ) ) {
+                               throw new InvalidArgumentException(
+                                       __METHOD__ . ': invalid $revision argument type ' . gettype( $revision ) );
                        }
-               } elseif ( $revision instanceof Revision ) {
-                       $revision = $revision->getRevisionRecord();
                }
 
                $slots = RevisionSlotsUpdate::newFromContent( [ SlotRecord::MAIN => $content ] );
@@ -2736,6 +2728,8 @@ class WikiPage implements Page, IDBAccessObject {
                        $dbw->endAtomic( __METHOD__ );
 
                        $jobParams = [
+                               'namespace' => $this->getTitle()->getNamespace(),
+                               'title' => $this->getTitle()->getDBkey(),
                                'wikiPageId' => $id,
                                'requestId' => $webRequestId ?? WebRequest::getRequestId(),
                                'reason' => $reason,
@@ -2745,7 +2739,7 @@ class WikiPage implements Page, IDBAccessObject {
                                'logsubtype' => $logsubtype,
                        ];
 
-                       $job = new DeletePageJob( $this->getTitle(), $jobParams );
+                       $job = new DeletePageJob( $jobParams );
                        JobQueueGroup::singleton()->push( $job );
 
                        $status->warning( 'delete-scheduled',
@@ -2997,7 +2991,7 @@ class WikiPage implements Page, IDBAccessObject {
         * @param Content|null $content Page content to be used when determining
         *   the required updates. This may be needed because $this->getContent()
         *   may already return null when the page proper was deleted.
-        * @param RevisionRecord|Revision|null $revision The current page revision at the time of
+        * @param Revision|null $revision The current page revision at the time of
         *   deletion, used when determining the required updates. This may be needed because
         *   $this->getRevision() may already return null when the page proper was deleted.
         * @param User|null $user The user that caused the deletion
@@ -3325,7 +3319,7 @@ class WikiPage implements Page, IDBAccessObject {
                        return [ [ 'alreadyrolled',
                                        htmlspecialchars( $this->mTitle->getPrefixedText() ),
                                        htmlspecialchars( $fromP ),
-                                       htmlspecialchars( $targetEditorForPublic ? $targetEditorForPublic->getName() : '' )
+                                       htmlspecialchars( $currentEditorForPublic ? $currentEditorForPublic->getName() : '' )
                        ] ];
                }
 
@@ -3602,7 +3596,8 @@ class WikiPage implements Page, IDBAccessObject {
         */
        public function updateCategoryCounts( array $added, array $deleted, $id = 0 ) {
                $id = $id ?: $this->getId();
-               $type = MWNamespace::getCategoryLinkType( $this->getTitle()->getNamespace() );
+               $type = MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       getCategoryLinkType( $this->getTitle()->getNamespace() );
 
                $addFields = [ 'cat_pages = cat_pages + 1' ];
                $removeFields = [ 'cat_pages = cat_pages - 1' ];
index edec490..9cfbfbf 100644 (file)
@@ -31,5 +31,6 @@
  */
 interface Pager {
        function getNavigationBar();
+
        function getBody();
 }
index b2bcc8c..50c7e23 100644 (file)
@@ -199,8 +199,11 @@ class BlockLevelPass {
                $pendingPTag = false;
                $inBlockquote = false;
 
-               $lineCount = count( $textLines );
-               foreach ( $textLines as $i => $inputLine ) {
+               for ( $textLines->rewind(); $textLines->valid(); ) {
+                       $inputLine = $textLines->current();
+                       $textLines->next();
+                       $notLastLine = $textLines->valid();
+
                        # Fix up $lineStart
                        if ( !$this->lineStart ) {
                                $output .= $inputLine;
@@ -377,23 +380,19 @@ class BlockLevelPass {
                                                                $output .= $pendingPTag . '<br />';
                                                                $pendingPTag = false;
                                                                $this->lastParagraph = 'p';
-                                                       } else {
-                                                               if ( $this->lastParagraph !== 'p' ) {
-                                                                       $output .= $this->closeParagraph();
-                                                                       $pendingPTag = '<p>';
-                                                               } else {
-                                                                       $pendingPTag = '</p><p>';
-                                                               }
-                                                       }
-                                               } else {
-                                                       if ( $pendingPTag ) {
-                                                               $output .= $pendingPTag;
-                                                               $pendingPTag = false;
-                                                               $this->lastParagraph = 'p';
                                                        } elseif ( $this->lastParagraph !== 'p' ) {
-                                                               $output .= $this->closeParagraph() . '<p>';
-                                                               $this->lastParagraph = 'p';
+                                                               $output .= $this->closeParagraph();
+                                                               $pendingPTag = '<p>';
+                                                       } else {
+                                                               $pendingPTag = '</p><p>';
                                                        }
+                                               } elseif ( $pendingPTag ) {
+                                                       $output .= $pendingPTag;
+                                                       $pendingPTag = false;
+                                                       $this->lastParagraph = 'p';
+                                               } elseif ( $this->lastParagraph !== 'p' ) {
+                                                       $output .= $this->closeParagraph() . '<p>';
+                                                       $this->lastParagraph = 'p';
                                                }
                                        }
                                }
@@ -407,7 +406,7 @@ class BlockLevelPass {
                                        $output .= $t;
                                        // Add a newline if there's an open paragraph
                                        // or we've yet to reach the last line.
-                                       if ( $i < $lineCount - 1 || $this->hasOpenParagraph() ) {
+                                       if ( $notLastLine || $this->hasOpenParagraph() ) {
                                                $output .= "\n";
                                        }
                                } else {
index d1d1a9c..0c745c9 100644 (file)
@@ -90,13 +90,13 @@ class CoreParserFunctions {
 
        /**
         * @param Parser $parser
-        * @param string $part1
+        * @param string $part1 Message key
+        * @param mixed ...$params To pass to wfMessage()
         * @return array
         */
-       public static function intFunction( $parser, $part1 = '' /*, ... */ ) {
+       public static function intFunction( $parser, $part1 = '', ...$params ) {
                if ( strval( $part1 ) !== '' ) {
-                       $args = array_slice( func_get_args(), 2 );
-                       $message = wfMessage( $part1, $args )
+                       $message = wfMessage( $part1, $params )
                                ->inLanguage( $parser->getOptions()->getUserLangObj() );
                        return [ $message->plain(), 'noparse' => false ];
                } else {
@@ -113,7 +113,7 @@ class CoreParserFunctions {
         */
        public static function formatDate( $parser, $date, $defaultPref = null ) {
                $lang = $parser->getFunctionLang();
-               $df = DateFormatter::getInstance( $lang );
+               $df = MediaWikiServices::getInstance()->getDateFormatterFactory()->get( $lang );
 
                $date = trim( $date );
 
@@ -313,11 +313,10 @@ class CoreParserFunctions {
        /**
         * @param Parser $parser
         * @param string $username
+        * @param string ...$forms What to output for each gender
         * @return string
         */
-       public static function gender( $parser, $username ) {
-               $forms = array_slice( func_get_args(), 2 );
-
+       public static function gender( $parser, $username, ...$forms ) {
                // Some shortcuts to avoid loading user data unnecessarily
                if ( count( $forms ) === 0 ) {
                        return '';
@@ -351,10 +350,10 @@ class CoreParserFunctions {
        /**
         * @param Parser $parser
         * @param string $text
+        * @param string ...$forms What to output for each number (singular, dual, plural, etc.)
         * @return string
         */
-       public static function plural( $parser, $text = '' ) {
-               $forms = array_slice( func_get_args(), 2 );
+       public static function plural( $parser, $text = '', ...$forms ) {
                $text = $parser->getFunctionLang()->parseFormattedNumber( $text );
                settype( $text, ctype_digit( $text ) ? 'int' : 'float' );
                return $parser->getFunctionLang()->convertPlural( $text, $forms );
@@ -515,6 +514,7 @@ class CoreParserFunctions {
        public static function numberofusers( $parser, $raw = null ) {
                return self::formatRaw( SiteStats::users(), $raw, $parser->getFunctionLang() );
        }
+
        public static function numberofactiveusers( $parser, $raw = null ) {
                return self::formatRaw( SiteStats::activeUsers(), $raw, $parser->getFunctionLang() );
        }
@@ -546,6 +546,7 @@ class CoreParserFunctions {
                        $parser->getFunctionLang()
                );
        }
+
        public static function numberingroup( $parser, $name = '', $raw = null ) {
                return self::formatRaw(
                        SiteStats::numberingroup( strtolower( $name ) ),
@@ -570,6 +571,7 @@ class CoreParserFunctions {
                }
                return str_replace( '_', ' ', $t->getNsText() );
        }
+
        public static function namespacee( $parser, $title = null ) {
                $t = Title::newFromText( $title );
                if ( is_null( $t ) ) {
@@ -577,6 +579,7 @@ class CoreParserFunctions {
                }
                return wfUrlencode( $t->getNsText() );
        }
+
        public static function namespacenumber( $parser, $title = null ) {
                $t = Title::newFromText( $title );
                if ( is_null( $t ) ) {
@@ -584,6 +587,7 @@ class CoreParserFunctions {
                }
                return $t->getNamespace();
        }
+
        public static function talkspace( $parser, $title = null ) {
                $t = Title::newFromText( $title );
                if ( is_null( $t ) || !$t->canHaveTalkPage() ) {
@@ -591,6 +595,7 @@ class CoreParserFunctions {
                }
                return str_replace( '_', ' ', $t->getTalkNsText() );
        }
+
        public static function talkspacee( $parser, $title = null ) {
                $t = Title::newFromText( $title );
                if ( is_null( $t ) || !$t->canHaveTalkPage() ) {
@@ -598,6 +603,7 @@ class CoreParserFunctions {
                }
                return wfUrlencode( $t->getTalkNsText() );
        }
+
        public static function subjectspace( $parser, $title = null ) {
                $t = Title::newFromText( $title );
                if ( is_null( $t ) ) {
@@ -605,6 +611,7 @@ class CoreParserFunctions {
                }
                return str_replace( '_', ' ', $t->getSubjectNsText() );
        }
+
        public static function subjectspacee( $parser, $title = null ) {
                $t = Title::newFromText( $title );
                if ( is_null( $t ) ) {
@@ -627,6 +634,7 @@ class CoreParserFunctions {
                }
                return wfEscapeWikiText( $t->getText() );
        }
+
        public static function pagenamee( $parser, $title = null ) {
                $t = Title::newFromText( $title );
                if ( is_null( $t ) ) {
@@ -634,6 +642,7 @@ class CoreParserFunctions {
                }
                return wfEscapeWikiText( $t->getPartialURL() );
        }
+
        public static function fullpagename( $parser, $title = null ) {
                $t = Title::newFromText( $title );
                if ( is_null( $t ) || !$t->canHaveTalkPage() ) {
@@ -641,6 +650,7 @@ class CoreParserFunctions {
                }
                return wfEscapeWikiText( $t->getPrefixedText() );
        }
+
        public static function fullpagenamee( $parser, $title = null ) {
                $t = Title::newFromText( $title );
                if ( is_null( $t ) || !$t->canHaveTalkPage() ) {
@@ -648,6 +658,7 @@ class CoreParserFunctions {
                }
                return wfEscapeWikiText( $t->getPrefixedURL() );
        }
+
        public static function subpagename( $parser, $title = null ) {
                $t = Title::newFromText( $title );
                if ( is_null( $t ) ) {
@@ -655,6 +666,7 @@ class CoreParserFunctions {
                }
                return wfEscapeWikiText( $t->getSubpageText() );
        }
+
        public static function subpagenamee( $parser, $title = null ) {
                $t = Title::newFromText( $title );
                if ( is_null( $t ) ) {
@@ -662,6 +674,7 @@ class CoreParserFunctions {
                }
                return wfEscapeWikiText( $t->getSubpageUrlForm() );
        }
+
        public static function rootpagename( $parser, $title = null ) {
                $t = Title::newFromText( $title );
                if ( is_null( $t ) ) {
@@ -669,6 +682,7 @@ class CoreParserFunctions {
                }
                return wfEscapeWikiText( $t->getRootText() );
        }
+
        public static function rootpagenamee( $parser, $title = null ) {
                $t = Title::newFromText( $title );
                if ( is_null( $t ) ) {
@@ -676,6 +690,7 @@ class CoreParserFunctions {
                }
                return wfEscapeWikiText( wfUrlencode( str_replace( ' ', '_', $t->getRootText() ) ) );
        }
+
        public static function basepagename( $parser, $title = null ) {
                $t = Title::newFromText( $title );
                if ( is_null( $t ) ) {
@@ -683,6 +698,7 @@ class CoreParserFunctions {
                }
                return wfEscapeWikiText( $t->getBaseText() );
        }
+
        public static function basepagenamee( $parser, $title = null ) {
                $t = Title::newFromText( $title );
                if ( is_null( $t ) ) {
@@ -690,6 +706,7 @@ class CoreParserFunctions {
                }
                return wfEscapeWikiText( wfUrlencode( str_replace( ' ', '_', $t->getBaseText() ) ) );
        }
+
        public static function talkpagename( $parser, $title = null ) {
                $t = Title::newFromText( $title );
                if ( is_null( $t ) || !$t->canHaveTalkPage() ) {
@@ -697,6 +714,7 @@ class CoreParserFunctions {
                }
                return wfEscapeWikiText( $t->getTalkPage()->getPrefixedText() );
        }
+
        public static function talkpagenamee( $parser, $title = null ) {
                $t = Title::newFromText( $title );
                if ( is_null( $t ) || !$t->canHaveTalkPage() ) {
@@ -704,6 +722,7 @@ class CoreParserFunctions {
                }
                return wfEscapeWikiText( $t->getTalkPage()->getPrefixedURL() );
        }
+
        public static function subjectpagename( $parser, $title = null ) {
                $t = Title::newFromText( $title );
                if ( is_null( $t ) ) {
@@ -711,6 +730,7 @@ class CoreParserFunctions {
                }
                return wfEscapeWikiText( $t->getSubjectPage()->getPrefixedText() );
        }
+
        public static function subjectpagenamee( $parser, $title = null ) {
                $t = Title::newFromText( $title );
                if ( is_null( $t ) ) {
index fb79442..b0c41d9 100644 (file)
 use MediaWiki\MediaWikiServices;
 
 /**
- * Date formatter, recognises dates in plain text and formats them according to user preferences.
- * @todo preferences, OutputPage
+ * Date formatter. Recognises dates and formats them according to a specified preference.
+ *
+ * This class was originally introduced to detect and transform dates in free text. It is now
+ * only used by the {{#dateformat}} parser function. This is a very rudimentary date formatter;
+ * Language::sprintfDate() has many more features and is the correct choice for most new code.
+ * The main advantage of this date formatter is that it is able to format incomplete dates with an
+ * unspecified year.
+ *
  * @ingroup Parser
  */
 class DateFormatter {
-       private $mSource, $mTarget;
-       private $monthNames = '';
-
+       /** @var string[] Date format regexes indexed the class constants */
        private $regexes;
-       private $rules, $xMonths, $preferences;
 
-       private $lang, $mLinked;
+       /**
+        * @var int[][] Array of special rules. The first key is the preference ID
+        * (one of the class constants), the second key is the detected source
+        * format, and the value is the ID of the target format that will be used
+        * in that case.
+        */
+       private $rules = [];
 
-       /** @var string[] */
-       private $keys;
+       /**
+        * @var int[] Month numbers by lowercase name
+        */
+       private $xMonths = [];
 
-       /** @var string[] */
-       private $targets;
+       /**
+        * @var string[] Month names by number
+        */
+       private $monthNames = [];
 
+       /**
+        * @var int[] A map of descriptive preference text to internal format ID
+        */
+       private $preferenceIDs;
+
+       /** @var string[] Format strings similar to those used by date(), indexed by ID */
+       private $targetFormats;
+
+       /** Used as a preference ID for rules that apply regardless of preference */
        const ALL = -1;
+
+       /** No preference: the date may be left in the same format as the input */
        const NONE = 0;
+
+       /** e.g. January 15, 2001 */
        const MDY = 1;
+
+       /** e.g. 15 January 2001 */
        const DMY = 2;
+
+       /** e.g. 2001 January 15 */
        const YMD = 3;
-       const ISO1 = 4;
+
+       /** e.g. 2001-01-15 */
+       const ISO = 4;
+
+       /** The highest ID that is a valid user preference */
        const LASTPREF = 4;
-       const ISO2 = 5;
-       const YDM = 6;
-       const DM = 7;
-       const MD = 8;
-       const LAST = 8;
+
+       /** e.g. 2001, 15 January */
+       const YDM = 5;
+
+       /** e.g. 15 January */
+       const DM = 6;
+
+       /** e.g. January 15 */
+       const MD = 7;
+
+       /** The highest ID that is a valid target format */
+       const LAST = 7;
 
        /**
         * @param Language $lang In which language to format the date
         */
        public function __construct( Language $lang ) {
-               $this->lang = $lang;
-
-               $this->monthNames = $this->getMonthRegex();
+               $monthRegexParts = [];
                for ( $i = 1; $i <= 12; $i++ ) {
-                       $this->xMonths[$this->lang->lc( $this->lang->getMonthName( $i ) )] = $i;
-                       $this->xMonths[$this->lang->lc( $this->lang->getMonthAbbreviation( $i ) )] = $i;
+                       $monthName = $lang->getMonthName( $i );
+                       $monthAbbrev = $lang->getMonthAbbreviation( $i );
+                       $this->monthNames[$i] = $monthName;
+                       $monthRegexParts[] = preg_quote( $monthName, '/' );
+                       $monthRegexParts[] = preg_quote( $monthAbbrev, '/' );
+                       $this->xMonths[mb_strtolower( $monthName )] = $i;
+                       $this->xMonths[mb_strtolower( $monthAbbrev )] = $i;
                }
 
-               $this->regexTrail = '(?![a-z])/iu';
-
-               # Partial regular expressions
-               $this->prxDM = '\[\[(\d{1,2})[ _](' . $this->monthNames . ')\]\]';
-               $this->prxMD = '\[\[(' . $this->monthNames . ')[ _](\d{1,2})\]\]';
-               $this->prxY = '\[\[(\d{1,4}([ _]BC|))\]\]';
-               $this->prxISO1 = '\[\[(-?\d{4})]]-\[\[(\d{2})-(\d{2})\]\]';
-               $this->prxISO2 = '\[\[(-?\d{4})-(\d{2})-(\d{2})\]\]';
-
-               # Real regular expressions
-               $this->regexes[self::DMY] = "/{$this->prxDM}(?: *, *| +){$this->prxY}{$this->regexTrail}";
-               $this->regexes[self::YDM] = "/{$this->prxY}(?: *, *| +){$this->prxDM}{$this->regexTrail}";
-               $this->regexes[self::MDY] = "/{$this->prxMD}(?: *, *| +){$this->prxY}{$this->regexTrail}";
-               $this->regexes[self::YMD] = "/{$this->prxY}(?: *, *| +){$this->prxMD}{$this->regexTrail}";
-               $this->regexes[self::DM] = "/{$this->prxDM}{$this->regexTrail}";
-               $this->regexes[self::MD] = "/{$this->prxMD}{$this->regexTrail}";
-               $this->regexes[self::ISO1] = "/{$this->prxISO1}{$this->regexTrail}";
-               $this->regexes[self::ISO2] = "/{$this->prxISO2}{$this->regexTrail}";
-
-               # Extraction keys
-               # See the comments in replace() for the meaning of the letters
-               $this->keys[self::DMY] = 'jFY';
-               $this->keys[self::YDM] = 'Y jF';
-               $this->keys[self::MDY] = 'FjY';
-               $this->keys[self::YMD] = 'Y Fj';
-               $this->keys[self::DM] = 'jF';
-               $this->keys[self::MD] = 'Fj';
-               $this->keys[self::ISO1] = 'ymd'; # y means ISO year
-               $this->keys[self::ISO2] = 'ymd';
-
-               # Target date formats
-               $this->targets[self::DMY] = '[[F j|j F]] [[Y]]';
-               $this->targets[self::YDM] = '[[Y]], [[F j|j F]]';
-               $this->targets[self::MDY] = '[[F j]], [[Y]]';
-               $this->targets[self::YMD] = '[[Y]] [[F j]]';
-               $this->targets[self::DM] = '[[F j|j F]]';
-               $this->targets[self::MD] = '[[F j]]';
-               $this->targets[self::ISO1] = '[[Y|y]]-[[F j|m-d]]';
-               $this->targets[self::ISO2] = '[[y-m-d]]';
-
-               # Rules
-               #            pref       source      target
+               // Partial regular expressions
+               $monthNames = implode( '|', $monthRegexParts );
+               $dm = "(?<day>\d{1,2})[ _](?<monthName>{$monthNames})";
+               $md = "(?<monthName>{$monthNames})[ _](?<day>\d{1,2})";
+               $y = '(?<year>\d{1,4}([ _]BC|))';
+               $iso = '(?<isoYear>-?\d{4})-(?<isoMonth>\d{2})-(?<isoDay>\d{2})';
+
+               $this->regexes = [
+                       self::DMY => "/^{$dm}(?: *, *| +){$y}$/iu",
+                       self::YDM => "/^{$y}(?: *, *| +){$dm}$/iu",
+                       self::MDY => "/^{$md}(?: *, *| +){$y}$/iu",
+                       self::YMD => "/^{$y}(?: *, *| +){$md}$/iu",
+                       self::DM => "/^{$dm}$/iu",
+                       self::MD => "/^{$md}$/iu",
+                       self::ISO => "/^{$iso}$/iu",
+               ];
+
+               // Target date formats
+               $this->targetFormats = [
+                       self::DMY => 'j F Y',
+                       self::YDM => 'Y, j F',
+                       self::MDY => 'F j, Y',
+                       self::YMD => 'Y F j',
+                       self::DM => 'j F',
+                       self::MD => 'F j',
+                       self::ISO => 'y-m-d',
+               ];
+
+               // Rules
+               //           pref       source      target
                $this->rules[self::DMY][self::MD] = self::DM;
                $this->rules[self::ALL][self::MD] = self::MD;
                $this->rules[self::MDY][self::DM] = self::MD;
                $this->rules[self::ALL][self::DM] = self::DM;
-               $this->rules[self::NONE][self::ISO2] = self::ISO1;
+               $this->rules[self::NONE][self::ISO] = self::ISO;
 
-               $this->preferences = [
+               $this->preferenceIDs = [
                        'default' => self::NONE,
                        'dmy' => self::DMY,
                        'mdy' => self::MDY,
                        'ymd' => self::YMD,
-                       'ISO 8601' => self::ISO1,
+                       'ISO 8601' => self::ISO,
                ];
        }
 
        /**
         * Get a DateFormatter object
         *
+        * @deprecated since 1.33 use MediaWikiServices::getDateFormatterFactory()
+        *
         * @param Language|null $lang In which language to format the date
         *     Defaults to the site content language
         * @return DateFormatter
         */
        public static function getInstance( Language $lang = null ) {
-               global $wgMainCacheType;
-
                $lang = $lang ?? MediaWikiServices::getInstance()->getContentLanguage();
-               $cache = ObjectCache::getLocalServerInstance( $wgMainCacheType );
-
-               static $dateFormatter = false;
-               if ( !$dateFormatter ) {
-                       $dateFormatter = $cache->getWithSetCallback(
-                               $cache->makeKey( 'dateformatter', $lang->getCode() ),
-                               $cache::TTL_HOUR,
-                               function () use ( $lang ) {
-                                       return new DateFormatter( $lang );
-                               }
-                       );
-               }
-
-               return $dateFormatter;
+               return MediaWikiServices::getInstance()->getDateFormatterFactory()->get( $lang );
        }
 
        /**
-        * @param string $preference User preference
+        * @param string $preference User preference, must be one of "default",
+        *   "dmy", "mdy", "ymd" or "ISO 8601".
         * @param string $text Text to reformat
-        * @param array $options Array can contain 'linked' and/or 'match-whole'
+        * @param array $options Ignored. Since 1.33, 'match-whole' is implied, and
+        *  'linked' has been removed.
         *
         * @return string
         */
-       public function reformat( $preference, $text, $options = [ 'linked' ] ) {
-               $linked = in_array( 'linked', $options );
-               $match_whole = in_array( 'match-whole', $options );
-
-               if ( isset( $this->preferences[$preference] ) ) {
-                       $preference = $this->preferences[$preference];
+       public function reformat( $preference, $text, $options = [] ) {
+               if ( isset( $this->preferenceIDs[$preference] ) ) {
+                       $preference = $this->preferenceIDs[$preference];
                } else {
                        $preference = self::NONE;
                }
-               for ( $i = 1; $i <= self::LAST; $i++ ) {
-                       $this->mSource = $i;
-                       if ( isset( $this->rules[$preference][$i] ) ) {
+               for ( $source = 1; $source <= self::LAST; $source++ ) {
+                       if ( isset( $this->rules[$preference][$source] ) ) {
                                # Specific rules
-                               $this->mTarget = $this->rules[$preference][$i];
-                       } elseif ( isset( $this->rules[self::ALL][$i] ) ) {
+                               $target = $this->rules[$preference][$source];
+                       } elseif ( isset( $this->rules[self::ALL][$source] ) ) {
                                # General rules
-                               $this->mTarget = $this->rules[self::ALL][$i];
+                               $target = $this->rules[self::ALL][$source];
                        } elseif ( $preference ) {
                                # User preference
-                               $this->mTarget = $preference;
+                               $target = $preference;
                        } else {
                                # Default
-                               $this->mTarget = $i;
-                       }
-                       $regex = $this->regexes[$i];
-
-                       // Horrible hack
-                       if ( !$linked ) {
-                               $regex = str_replace( [ '\[\[', '\]\]' ], '', $regex );
-                       }
-
-                       if ( $match_whole ) {
-                               // Let's hope this works
-                               $regex = preg_replace( '!^/!', '/^', $regex );
-                               $regex = str_replace( $this->regexTrail,
-                                       '$' . $this->regexTrail, $regex );
-                       }
-
-                       // Another horrible hack
-                       $this->mLinked = $linked;
-                       $text = preg_replace_callback( $regex, [ $this, 'replace' ], $text );
-                       unset( $this->mLinked );
-               }
-               return $text;
-       }
-
-       /**
-        * Regexp replacement callback
-        *
-        * @param array $matches
-        * @return string
-        */
-       private function replace( $matches ) {
-               # Extract information from $matches
-               $linked = $this->mLinked ?? true;
-
-               $bits = [];
-               $key = $this->keys[$this->mSource];
-               $keyLength = strlen( $key );
-               for ( $p = 0; $p < $keyLength; $p++ ) {
-                       if ( $key[$p] != ' ' ) {
-                               $bits[$key[$p]] = $matches[$p + 1];
+                               $target = $source;
                        }
-               }
-
-               return $this->formatDate( $bits, $matches[0], $linked );
-       }
+                       $regex = $this->regexes[$source];
 
-       /**
-        * @param array $bits
-        * @param string $orig Original input string, to be returned
-        *  on formatting failure.
-        * @param bool $link
-        * @return string
-        */
-       private function formatDate( $bits, $orig, $link = true ) {
-               $format = $this->targets[$this->mTarget];
-
-               if ( !$link ) {
-                       // strip piped links
-                       $format = preg_replace( '/\[\[[^|]+\|([^\]]+)\]\]/', '$1', $format );
-                       // strip remaining links
-                       $format = str_replace( [ '[[', ']]' ], '', $format );
-               }
-
-               # Construct new date
-               $text = '';
-               $fail = false;
-
-               // Pre-generate y/Y stuff because we need the year for the <span> title.
-               if ( !isset( $bits['y'] ) && isset( $bits['Y'] ) ) {
-                       $bits['y'] = $this->makeIsoYear( $bits['Y'] );
-               }
-               if ( !isset( $bits['Y'] ) && isset( $bits['y'] ) ) {
-                       $bits['Y'] = $this->makeNormalYear( $bits['y'] );
-               }
-
-               if ( !isset( $bits['m'] ) ) {
-                       $m = $this->makeIsoMonth( $bits['F'] );
-                       if ( !$m || $m == '00' ) {
-                               $fail = true;
-                       } else {
-                               $bits['m'] = $m;
-                       }
-               }
+                       $text = preg_replace_callback( $regex,
+                               function ( $match ) use ( $target ) {
+                                       $format = $this->targetFormats[$target];
 
-               if ( !isset( $bits['d'] ) ) {
-                       $bits['d'] = sprintf( '%02d', $bits['j'] );
-               }
+                                       $text = '';
 
-               $formatLength = strlen( $format );
-               for ( $p = 0; $p < $formatLength; $p++ ) {
-                       $char = $format[$p];
-                       switch ( $char ) {
-                               case 'd': # ISO day of month
-                                       $text .= $bits['d'];
-                                       break;
-                               case 'm': # ISO month
-                                       $text .= $bits['m'];
-                                       break;
-                               case 'y': # ISO year
-                                       $text .= $bits['y'];
-                                       break;
-                               case 'j': # ordinary day of month
-                                       if ( !isset( $bits['j'] ) ) {
-                                               $text .= intval( $bits['d'] );
-                                       } else {
-                                               $text .= $bits['j'];
+                                       // Pre-generate y/Y stuff because we need the year for the <span> title.
+                                       if ( !isset( $match['isoYear'] ) && isset( $match['year'] ) ) {
+                                               $match['isoYear'] = $this->makeIsoYear( $match['year'] );
+                                       }
+                                       if ( !isset( $match['year'] ) && isset( $match['isoYear'] ) ) {
+                                               $match['year'] = $this->makeNormalYear( $match['isoYear'] );
                                        }
-                                       break;
-                               case 'F': # long month
-                                       if ( !isset( $bits['F'] ) ) {
-                                               $m = intval( $bits['m'] );
-                                               if ( $m > 12 || $m < 1 ) {
-                                                       $fail = true;
+
+                                       if ( !isset( $match['isoMonth'] ) ) {
+                                               $m = $this->makeIsoMonth( $match['monthName'] );
+                                               if ( $m === false ) {
+                                                       // Fail
+                                                       return $match[0];
                                                } else {
-                                                       $text .= $this->lang->getMonthName( $m );
+                                                       $match['isoMonth'] = $m;
                                                }
-                                       } else {
-                                               $text .= ucfirst( $bits['F'] );
                                        }
-                                       break;
-                               case 'Y': # ordinary (optional BC) year
-                                       $text .= $bits['Y'];
-                                       break;
-                               default:
-                                       $text .= $char;
-                       }
-               }
-               if ( $fail ) {
-                       // This occurs when parsing a date with day or month outside the bounds
-                       // of possibilities.
-                       $text = $orig;
-               }
 
-               $isoBits = [];
-               if ( isset( $bits['y'] ) ) {
-                       $isoBits[] = $bits['y'];
-               }
-               $isoBits[] = $bits['m'];
-               $isoBits[] = $bits['d'];
-               $isoDate = implode( '-', $isoBits );
+                                       if ( !isset( $match['isoDay'] ) ) {
+                                               $match['isoDay'] = sprintf( '%02d', $match['day'] );
+                                       }
 
-               // Output is not strictly HTML (it's wikitext), but <span> is whitelisted.
-               $text = Html::rawElement( 'span',
-                                       [ 'class' => 'mw-formatted-date', 'title' => $isoDate ], $text );
+                                       $formatLength = strlen( $format );
+                                       for ( $p = 0; $p < $formatLength; $p++ ) {
+                                               $char = $format[$p];
+                                               switch ( $char ) {
+                                                       case 'd': // ISO day of month
+                                                               $text .= $match['isoDay'];
+                                                               break;
+                                                       case 'm': // ISO month
+                                                               $text .= $match['isoMonth'];
+                                                               break;
+                                                       case 'y': // ISO year
+                                                               $text .= $match['isoYear'];
+                                                               break;
+                                                       case 'j': // ordinary day of month
+                                                               if ( !isset( $match['day'] ) ) {
+                                                                       $text .= intval( $match['isoDay'] );
+                                                               } else {
+                                                                       $text .= $match['day'];
+                                                               }
+                                                               break;
+                                                       case 'F': // long month
+                                                               $m = intval( $match['isoMonth'] );
+                                                               if ( $m > 12 || $m < 1 ) {
+                                                                       // Fail
+                                                                       return $match[0];
+                                                               } else {
+                                                                       $text .= $this->monthNames[$m];
+                                                               }
+                                                               break;
+                                                       case 'Y': // ordinary (optional BC) year
+                                                               $text .= $match['year'];
+                                                               break;
+                                                       default:
+                                                               $text .= $char;
+                                               }
+                                       }
 
-               return $text;
-       }
+                                       $isoBits = [];
+                                       if ( isset( $match['isoYear'] ) ) {
+                                               $isoBits[] = $match['isoYear'];
+                                       }
+                                       $isoBits[] = $match['isoMonth'];
+                                       $isoBits[] = $match['isoDay'];
+                                       $isoDate = implode( '-', $isoBits );
 
-       /**
-        * Return a regex that can be used to find month names in string
-        * @return string regex to find the months with
-        */
-       private function getMonthRegex() {
-               $names = [];
-               for ( $i = 1; $i <= 12; $i++ ) {
-                       $names[] = $this->lang->getMonthName( $i );
-                       $names[] = $this->lang->getMonthAbbreviation( $i );
+                                       // Output is not strictly HTML (it's wikitext), but <span> is whitelisted.
+                                       $text = Html::rawElement( 'span',
+                                               [ 'class' => 'mw-formatted-date', 'title' => $isoDate ], $text );
+
+                                       return $text;
+                               }, $text
+                       );
                }
-               return implode( '|', $names );
+               return $text;
        }
 
        /**
         * Makes an ISO month, e.g. 02, from a month name
         * @param string $monthName Month name
-        * @return string ISO month name
+        * @return string|false ISO month name, or false if the input was invalid
         */
        private function makeIsoMonth( $monthName ) {
-               $n = $this->xMonths[$this->lang->lc( $monthName )];
-               return sprintf( '%02d', $n );
+               $isoMonth = $this->xMonths[mb_strtolower( $monthName )] ?? false;
+               if ( $isoMonth === false ) {
+                       return false;
+               }
+               return sprintf( '%02d', $isoMonth );
        }
 
        /**
@@ -358,12 +305,11 @@ class DateFormatter {
         * @return string ISO year name
         */
        private function makeIsoYear( $year ) {
-               # Assumes the year is in a nice format, as enforced by the regex
+               // Assumes the year is in a nice format, as enforced by the regex
                if ( substr( $year, -2 ) == 'BC' ) {
                        $num = intval( substr( $year, 0, -3 ) ) - 1;
-                       # PHP bug note: sprintf( "%04d", -1 ) fails poorly
+                       // PHP bug note: sprintf( "%04d", -1 ) fails poorly
                        $text = sprintf( '-%04d', $num );
-
                } else {
                        $text = sprintf( '%04d', $year );
                }
@@ -371,7 +317,7 @@ class DateFormatter {
        }
 
        /**
-        * Make a year one from an ISO year, for instance: '400 BC' from '-0399'.
+        * Make a year from an ISO year, for instance: '400 BC' from '-0399'.
         * @param string $iso ISO year
         * @return int|string int representing year number in case of AD dates, or string containing
         *   year number and 'BC' at the end otherwise.
diff --git a/includes/parser/DateFormatterFactory.php b/includes/parser/DateFormatterFactory.php
new file mode 100644 (file)
index 0000000..d18ecf4
--- /dev/null
@@ -0,0 +1,18 @@
+<?php
+
+class DateFormatterFactory {
+       /** @var DateFormatter[] */
+       private $instances;
+
+       /**
+        * @param Language $lang
+        * @return DateFormatter
+        */
+       public function get( Language $lang ) {
+               $code = $lang->getCode();
+               if ( !isset( $this->instances[$code] ) ) {
+                       $this->instances[$code] = new DateFormatter( $lang );
+               }
+               return $this->instances[$code];
+       }
+}
index 078c819..6416449 100644 (file)
@@ -632,8 +632,7 @@ class LinkHolderArray {
         * @private
         */
        public function replaceTextCallback( $matches ) {
-               $type = $matches[1];
-               $key = $matches[2];
+               list( , $type, $key ) = $matches;
                if ( $type == 'LINK' ) {
                        list( $ns, $index ) = explode( ':', $key, 2 );
                        if ( isset( $this->internals[$ns][$index]['text'] ) ) {
diff --git a/includes/parser/PPCustomFrame_DOM.php b/includes/parser/PPCustomFrame_DOM.php
new file mode 100644 (file)
index 0000000..70663a0
--- /dev/null
@@ -0,0 +1,70 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Parser
+ */
+
+/**
+ * Expansion frame with custom arguments
+ * @ingroup Parser
+ */
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
+class PPCustomFrame_DOM extends PPFrame_DOM {
+
+       public $args;
+
+       public function __construct( $preprocessor, $args ) {
+               parent::__construct( $preprocessor );
+               $this->args = $args;
+       }
+
+       public function __toString() {
+               $s = 'cstmframe{';
+               $first = true;
+               foreach ( $this->args as $name => $value ) {
+                       if ( $first ) {
+                               $first = false;
+                       } else {
+                               $s .= ', ';
+                       }
+                       $s .= "\"$name\":\"" .
+                               str_replace( '"', '\\"', $value->__toString() ) . '"';
+               }
+               $s .= '}';
+               return $s;
+       }
+
+       /**
+        * @return bool
+        */
+       public function isEmpty() {
+               return !count( $this->args );
+       }
+
+       /**
+        * @param int|string $index
+        * @return string|bool
+        */
+       public function getArgument( $index ) {
+               return $this->args[$index] ?? false;
+       }
+
+       public function getArguments() {
+               return $this->args;
+       }
+}
diff --git a/includes/parser/PPCustomFrame_Hash.php b/includes/parser/PPCustomFrame_Hash.php
new file mode 100644 (file)
index 0000000..a92b104
--- /dev/null
@@ -0,0 +1,70 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Parser
+ */
+
+/**
+ * Expansion frame with custom arguments
+ * @ingroup Parser
+ */
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
+class PPCustomFrame_Hash extends PPFrame_Hash {
+
+       public $args;
+
+       public function __construct( $preprocessor, $args ) {
+               parent::__construct( $preprocessor );
+               $this->args = $args;
+       }
+
+       public function __toString() {
+               $s = 'cstmframe{';
+               $first = true;
+               foreach ( $this->args as $name => $value ) {
+                       if ( $first ) {
+                               $first = false;
+                       } else {
+                               $s .= ', ';
+                       }
+                       $s .= "\"$name\":\"" .
+                               str_replace( '"', '\\"', $value->__toString() ) . '"';
+               }
+               $s .= '}';
+               return $s;
+       }
+
+       /**
+        * @return bool
+        */
+       public function isEmpty() {
+               return !count( $this->args );
+       }
+
+       /**
+        * @param int|string $index
+        * @return string|bool
+        */
+       public function getArgument( $index ) {
+               return $this->args[$index] ?? false;
+       }
+
+       public function getArguments() {
+               return $this->args;
+       }
+}
diff --git a/includes/parser/PPDPart.php b/includes/parser/PPDPart.php
new file mode 100644 (file)
index 0000000..1873730
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Parser
+ */
+
+/**
+ * @ingroup Parser
+ */
+class PPDPart {
+       /**
+        * @var string Output accumulator string
+        */
+       public $out;
+
+       // Optional member variables:
+       //   eqpos        Position of equals sign in output accumulator
+       //   commentEnd   Past-the-end input pointer for the last comment encountered
+       //   visualEnd    Past-the-end input pointer for the end of the accumulator minus comments
+
+       public function __construct( $out = '' ) {
+               $this->out = $out;
+       }
+}
diff --git a/includes/parser/PPDPart_Hash.php b/includes/parser/PPDPart_Hash.php
new file mode 100644 (file)
index 0000000..7507f06
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Parser
+ */
+
+/**
+ * @ingroup Parser
+ */
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
+class PPDPart_Hash extends PPDPart {
+
+       public function __construct( $out = '' ) {
+               if ( $out !== '' ) {
+                       $accum = [ $out ];
+               } else {
+                       $accum = [];
+               }
+               parent::__construct( $accum );
+       }
+}
diff --git a/includes/parser/PPDStack.php b/includes/parser/PPDStack.php
new file mode 100644 (file)
index 0000000..4108bd7
--- /dev/null
@@ -0,0 +1,113 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Parser
+ */
+
+/**
+ * Stack class to help Preprocessor::preprocessToObj()
+ * @ingroup Parser
+ */
+class PPDStack {
+       public $stack, $rootAccum;
+
+       /**
+        * @var PPDStack
+        */
+       public $top;
+       public $out;
+       public $elementClass = PPDStackElement::class;
+
+       public static $false = false;
+
+       public function __construct() {
+               $this->stack = [];
+               $this->top = false;
+               $this->rootAccum = '';
+               $this->accum =& $this->rootAccum;
+       }
+
+       /**
+        * @return int
+        */
+       public function count() {
+               return count( $this->stack );
+       }
+
+       public function &getAccum() {
+               return $this->accum;
+       }
+
+       /**
+        * @return bool|PPDPart
+        */
+       public function getCurrentPart() {
+               if ( $this->top === false ) {
+                       return false;
+               } else {
+                       return $this->top->getCurrentPart();
+               }
+       }
+
+       public function push( $data ) {
+               if ( $data instanceof $this->elementClass ) {
+                       $this->stack[] = $data;
+               } else {
+                       $class = $this->elementClass;
+                       $this->stack[] = new $class( $data );
+               }
+               $this->top = $this->stack[count( $this->stack ) - 1];
+               $this->accum =& $this->top->getAccum();
+       }
+
+       public function pop() {
+               if ( $this->stack === [] ) {
+                       throw new MWException( __METHOD__ . ': no elements remaining' );
+               }
+               $temp = array_pop( $this->stack );
+
+               if ( count( $this->stack ) ) {
+                       $this->top = $this->stack[count( $this->stack ) - 1];
+                       $this->accum =& $this->top->getAccum();
+               } else {
+                       $this->top = self::$false;
+                       $this->accum =& $this->rootAccum;
+               }
+               return $temp;
+       }
+
+       public function addPart( $s = '' ) {
+               $this->top->addPart( $s );
+               $this->accum =& $this->top->getAccum();
+       }
+
+       /**
+        * @return array
+        */
+       public function getFlags() {
+               if ( $this->stack === [] ) {
+                       return [
+                               'findEquals' => false,
+                               'findPipe' => false,
+                               'inHeading' => false,
+                       ];
+               } else {
+                       return $this->top->getFlags();
+               }
+       }
+}
diff --git a/includes/parser/PPDStackElement.php b/includes/parser/PPDStackElement.php
new file mode 100644 (file)
index 0000000..116244d
--- /dev/null
@@ -0,0 +1,129 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Parser
+ */
+
+/**
+ * @ingroup Parser
+ */
+class PPDStackElement {
+       /**
+        * @var string Opening character (\n for heading)
+        */
+       public $open;
+
+       /**
+        * @var string Matching closing character
+        */
+       public $close;
+
+       /**
+        * @var string Saved prefix that may affect later processing,
+        *  e.g. to differentiate `-{{{{` and `{{{{` after later seeing `}}}`.
+        */
+       public $savedPrefix = '';
+
+       /**
+        * @var int Number of opening characters found (number of "=" for heading)
+        */
+       public $count;
+
+       /**
+        * @var PPDPart[] Array of PPDPart objects describing pipe-separated parts.
+        */
+       public $parts;
+
+       /**
+        * @var bool True if the open char appeared at the start of the input line.
+        *  Not set for headings.
+        */
+       public $lineStart;
+
+       public $partClass = PPDPart::class;
+
+       public function __construct( $data = [] ) {
+               $class = $this->partClass;
+               $this->parts = [ new $class ];
+
+               foreach ( $data as $name => $value ) {
+                       $this->$name = $value;
+               }
+       }
+
+       public function &getAccum() {
+               return $this->parts[count( $this->parts ) - 1]->out;
+       }
+
+       public function addPart( $s = '' ) {
+               $class = $this->partClass;
+               $this->parts[] = new $class( $s );
+       }
+
+       /**
+        * @return PPDPart
+        */
+       public function getCurrentPart() {
+               return $this->parts[count( $this->parts ) - 1];
+       }
+
+       /**
+        * @return array
+        */
+       public function getFlags() {
+               $partCount = count( $this->parts );
+               $findPipe = $this->open != "\n" && $this->open != '[';
+               return [
+                       'findPipe' => $findPipe,
+                       'findEquals' => $findPipe && $partCount > 1 && !isset( $this->parts[$partCount - 1]->eqpos ),
+                       'inHeading' => $this->open == "\n",
+               ];
+       }
+
+       /**
+        * Get the output string that would result if the close is not found.
+        *
+        * @param bool|int $openingCount
+        * @return string
+        */
+       public function breakSyntax( $openingCount = false ) {
+               if ( $this->open == "\n" ) {
+                       $s = $this->savedPrefix . $this->parts[0]->out;
+               } else {
+                       if ( $openingCount === false ) {
+                               $openingCount = $this->count;
+                       }
+                       $s = substr( $this->open, 0, -1 );
+                       $s .= str_repeat(
+                               substr( $this->open, -1 ),
+                               $openingCount - strlen( $s )
+                       );
+                       $s = $this->savedPrefix . $s;
+                       $first = true;
+                       foreach ( $this->parts as $part ) {
+                               if ( $first ) {
+                                       $first = false;
+                               } else {
+                                       $s .= '|';
+                               }
+                               $s .= $part->out;
+                       }
+               }
+               return $s;
+       }
+}
diff --git a/includes/parser/PPDStackElement_Hash.php b/includes/parser/PPDStackElement_Hash.php
new file mode 100644 (file)
index 0000000..26351b2
--- /dev/null
@@ -0,0 +1,73 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Parser
+ */
+
+/**
+ * @ingroup Parser
+ */
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
+class PPDStackElement_Hash extends PPDStackElement {
+
+       public function __construct( $data = [] ) {
+               $this->partClass = PPDPart_Hash::class;
+               parent::__construct( $data );
+       }
+
+       /**
+        * Get the accumulator that would result if the close is not found.
+        *
+        * @param int|bool $openingCount
+        * @return array
+        */
+       public function breakSyntax( $openingCount = false ) {
+               if ( $this->open == "\n" ) {
+                       $accum = array_merge( [ $this->savedPrefix ], $this->parts[0]->out );
+               } else {
+                       if ( $openingCount === false ) {
+                               $openingCount = $this->count;
+                       }
+                       $s = substr( $this->open, 0, -1 );
+                       $s .= str_repeat(
+                               substr( $this->open, -1 ),
+                               $openingCount - strlen( $s )
+                       );
+                       $accum = [ $this->savedPrefix . $s ];
+                       $lastIndex = 0;
+                       $first = true;
+                       foreach ( $this->parts as $part ) {
+                               if ( $first ) {
+                                       $first = false;
+                               } elseif ( is_string( $accum[$lastIndex] ) ) {
+                                       $accum[$lastIndex] .= '|';
+                               } else {
+                                       $accum[++$lastIndex] = '|';
+                               }
+                               foreach ( $part->out as $node ) {
+                                       if ( is_string( $node ) && is_string( $accum[$lastIndex] ) ) {
+                                               $accum[$lastIndex] .= $node;
+                                       } else {
+                                               $accum[++$lastIndex] = $node;
+                                       }
+                               }
+                       }
+               }
+               return $accum;
+       }
+}
diff --git a/includes/parser/PPDStack_Hash.php b/includes/parser/PPDStack_Hash.php
new file mode 100644 (file)
index 0000000..1e50b1c
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Parser
+ */
+
+/**
+ * Stack class to help Preprocessor::preprocessToObj()
+ * @ingroup Parser
+ */
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
+class PPDStack_Hash extends PPDStack {
+
+       public function __construct() {
+               $this->elementClass = PPDStackElement_Hash::class;
+               parent::__construct();
+               $this->rootAccum = [];
+       }
+}
diff --git a/includes/parser/PPFrame.php b/includes/parser/PPFrame.php
new file mode 100644 (file)
index 0000000..79c7c3b
--- /dev/null
@@ -0,0 +1,204 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Parser
+ */
+
+/**
+ * @ingroup Parser
+ */
+interface PPFrame {
+       const NO_ARGS = 1;
+       const NO_TEMPLATES = 2;
+       const STRIP_COMMENTS = 4;
+       const NO_IGNORE = 8;
+       const RECOVER_COMMENTS = 16;
+       const NO_TAGS = 32;
+
+       const RECOVER_ORIG = self::NO_ARGS | self::NO_TEMPLATES | self::NO_IGNORE |
+               self::RECOVER_COMMENTS | self::NO_TAGS;
+
+       /** This constant exists when $indexOffset is supported in newChild() */
+       const SUPPORTS_INDEX_OFFSET = 1;
+
+       /**
+        * Create a child frame
+        *
+        * @param array|bool $args
+        * @param bool|Title $title
+        * @param int $indexOffset A number subtracted from the index attributes of the arguments
+        *
+        * @return PPFrame
+        */
+       public function newChild( $args = false, $title = false, $indexOffset = 0 );
+
+       /**
+        * Expand a document tree node, caching the result on its parent with the given key
+        * @param string|int $key
+        * @param string|PPNode $root
+        * @param int $flags
+        * @return string
+        */
+       public function cachedExpand( $key, $root, $flags = 0 );
+
+       /**
+        * Expand a document tree node
+        * @param string|PPNode $root
+        * @param int $flags
+        * @return string
+        */
+       public function expand( $root, $flags = 0 );
+
+       /**
+        * Implode with flags for expand()
+        * @param string $sep
+        * @param int $flags
+        * @param string|PPNode $args,...
+        * @return string
+        */
+       public function implodeWithFlags( $sep, $flags /*, ... */ );
+
+       /**
+        * Implode with no flags specified
+        * @param string $sep
+        * @param string|PPNode $args,...
+        * @return string
+        */
+       public function implode( $sep /*, ... */ );
+
+       /**
+        * Makes an object that, when expand()ed, will be the same as one obtained
+        * with implode()
+        * @param string $sep
+        * @param string|PPNode $args,...
+        * @return PPNode
+        */
+       public function virtualImplode( $sep /*, ... */ );
+
+       /**
+        * Virtual implode with brackets
+        * @param string $start
+        * @param string $sep
+        * @param string $end
+        * @param string|PPNode $args,...
+        * @return PPNode
+        */
+       public function virtualBracketedImplode( $start, $sep, $end /*, ... */ );
+
+       /**
+        * Returns true if there are no arguments in this frame
+        *
+        * @return bool
+        */
+       public function isEmpty();
+
+       /**
+        * Returns all arguments of this frame
+        * @return array
+        */
+       public function getArguments();
+
+       /**
+        * Returns all numbered arguments of this frame
+        * @return array
+        */
+       public function getNumberedArguments();
+
+       /**
+        * Returns all named arguments of this frame
+        * @return array
+        */
+       public function getNamedArguments();
+
+       /**
+        * Get an argument to this frame by name
+        * @param int|string $name
+        * @return string|bool
+        */
+       public function getArgument( $name );
+
+       /**
+        * Returns true if the infinite loop check is OK, false if a loop is detected
+        *
+        * @param Title $title
+        * @return bool
+        */
+       public function loopCheck( $title );
+
+       /**
+        * Return true if the frame is a template frame
+        * @return bool
+        */
+       public function isTemplate();
+
+       /**
+        * Set the "volatile" flag.
+        *
+        * Note that this is somewhat of a "hack" in order to make extensions
+        * with side effects (such as Cite) work with the PHP parser. New
+        * extensions should be written in a way that they do not need this
+        * function, because other parsers (such as Parsoid) are not guaranteed
+        * to respect it, and it may be removed in the future.
+        *
+        * @param bool $flag
+        */
+       public function setVolatile( $flag = true );
+
+       /**
+        * Get the "volatile" flag.
+        *
+        * Callers should avoid caching the result of an expansion if it has the
+        * volatile flag set.
+        *
+        * @see self::setVolatile()
+        * @return bool
+        */
+       public function isVolatile();
+
+       /**
+        * Get the TTL of the frame's output.
+        *
+        * This is the maximum amount of time, in seconds, that this frame's
+        * output should be cached for. A value of null indicates that no
+        * maximum has been specified.
+        *
+        * Note that this TTL only applies to caching frames as parts of pages.
+        * It is not relevant to caching the entire rendered output of a page.
+        *
+        * @return int|null
+        */
+       public function getTTL();
+
+       /**
+        * Set the TTL of the output of this frame and all of its ancestors.
+        * Has no effect if the new TTL is greater than the one already set.
+        * Note that it is the caller's responsibility to change the cache
+        * expiry of the page as a whole, if such behavior is desired.
+        *
+        * @see self::getTTL()
+        * @param int $ttl
+        */
+       public function setTTL( $ttl );
+
+       /**
+        * Get a title of frame
+        *
+        * @return Title
+        */
+       public function getTitle();
+}
diff --git a/includes/parser/PPFrame_DOM.php b/includes/parser/PPFrame_DOM.php
new file mode 100644 (file)
index 0000000..a7fea00
--- /dev/null
@@ -0,0 +1,631 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Parser
+ */
+
+/**
+ * An expansion frame, used as a context to expand the result of preprocessToObj()
+ * @ingroup Parser
+ */
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
+class PPFrame_DOM implements PPFrame {
+
+       /**
+        * @var Preprocessor
+        */
+       public $preprocessor;
+
+       /**
+        * @var Parser
+        */
+       public $parser;
+
+       /**
+        * @var Title
+        */
+       public $title;
+       public $titleCache;
+
+       /**
+        * Hashtable listing templates which are disallowed for expansion in this frame,
+        * having been encountered previously in parent frames.
+        */
+       public $loopCheckHash;
+
+       /**
+        * Recursion depth of this frame, top = 0
+        * Note that this is NOT the same as expansion depth in expand()
+        */
+       public $depth;
+
+       private $volatile = false;
+       private $ttl = null;
+
+       /**
+        * @var array
+        */
+       protected $childExpansionCache;
+
+       /**
+        * Construct a new preprocessor frame.
+        * @param Preprocessor $preprocessor The parent preprocessor
+        */
+       public function __construct( $preprocessor ) {
+               $this->preprocessor = $preprocessor;
+               $this->parser = $preprocessor->parser;
+               $this->title = $this->parser->mTitle;
+               $this->titleCache = [ $this->title ? $this->title->getPrefixedDBkey() : false ];
+               $this->loopCheckHash = [];
+               $this->depth = 0;
+               $this->childExpansionCache = [];
+       }
+
+       /**
+        * Create a new child frame
+        * $args is optionally a multi-root PPNode or array containing the template arguments
+        *
+        * @param bool|array $args
+        * @param Title|bool $title
+        * @param int $indexOffset
+        * @return PPTemplateFrame_DOM
+        */
+       public function newChild( $args = false, $title = false, $indexOffset = 0 ) {
+               $namedArgs = [];
+               $numberedArgs = [];
+               if ( $title === false ) {
+                       $title = $this->title;
+               }
+               if ( $args !== false ) {
+                       $xpath = false;
+                       if ( $args instanceof PPNode ) {
+                               $args = $args->node;
+                       }
+                       foreach ( $args as $arg ) {
+                               if ( $arg instanceof PPNode ) {
+                                       $arg = $arg->node;
+                               }
+                               if ( !$xpath || $xpath->document !== $arg->ownerDocument ) {
+                                       $xpath = new DOMXPath( $arg->ownerDocument );
+                               }
+
+                               $nameNodes = $xpath->query( 'name', $arg );
+                               $value = $xpath->query( 'value', $arg );
+                               if ( $nameNodes->item( 0 )->hasAttributes() ) {
+                                       // Numbered parameter
+                                       $index = $nameNodes->item( 0 )->attributes->getNamedItem( 'index' )->textContent;
+                                       $index = $index - $indexOffset;
+                                       if ( isset( $namedArgs[$index] ) || isset( $numberedArgs[$index] ) ) {
+                                               $this->parser->getOutput()->addWarning( wfMessage( 'duplicate-args-warning',
+                                                       wfEscapeWikiText( $this->title ),
+                                                       wfEscapeWikiText( $title ),
+                                                       wfEscapeWikiText( $index ) )->text() );
+                                               $this->parser->addTrackingCategory( 'duplicate-args-category' );
+                                       }
+                                       $numberedArgs[$index] = $value->item( 0 );
+                                       unset( $namedArgs[$index] );
+                               } else {
+                                       // Named parameter
+                                       $name = trim( $this->expand( $nameNodes->item( 0 ), PPFrame::STRIP_COMMENTS ) );
+                                       if ( isset( $namedArgs[$name] ) || isset( $numberedArgs[$name] ) ) {
+                                               $this->parser->getOutput()->addWarning( wfMessage( 'duplicate-args-warning',
+                                                       wfEscapeWikiText( $this->title ),
+                                                       wfEscapeWikiText( $title ),
+                                                       wfEscapeWikiText( $name ) )->text() );
+                                               $this->parser->addTrackingCategory( 'duplicate-args-category' );
+                                       }
+                                       $namedArgs[$name] = $value->item( 0 );
+                                       unset( $numberedArgs[$name] );
+                               }
+                       }
+               }
+               return new PPTemplateFrame_DOM( $this->preprocessor, $this, $numberedArgs, $namedArgs, $title );
+       }
+
+       /**
+        * @throws MWException
+        * @param string|int $key
+        * @param string|PPNode_DOM|DOMDocument $root
+        * @param int $flags
+        * @return string
+        */
+       public function cachedExpand( $key, $root, $flags = 0 ) {
+               // we don't have a parent, so we don't have a cache
+               return $this->expand( $root, $flags );
+       }
+
+       /**
+        * @throws MWException
+        * @param string|PPNode_DOM|DOMDocument $root
+        * @param int $flags
+        * @return string
+        */
+       public function expand( $root, $flags = 0 ) {
+               static $expansionDepth = 0;
+               if ( is_string( $root ) ) {
+                       return $root;
+               }
+
+               if ( ++$this->parser->mPPNodeCount > $this->parser->mOptions->getMaxPPNodeCount() ) {
+                       $this->parser->limitationWarn( 'node-count-exceeded',
+                               $this->parser->mPPNodeCount,
+                               $this->parser->mOptions->getMaxPPNodeCount()
+                       );
+                       return '<span class="error">Node-count limit exceeded</span>';
+               }
+
+               if ( $expansionDepth > $this->parser->mOptions->getMaxPPExpandDepth() ) {
+                       $this->parser->limitationWarn( 'expansion-depth-exceeded',
+                               $expansionDepth,
+                               $this->parser->mOptions->getMaxPPExpandDepth()
+                       );
+                       return '<span class="error">Expansion depth limit exceeded</span>';
+               }
+               ++$expansionDepth;
+               if ( $expansionDepth > $this->parser->mHighestExpansionDepth ) {
+                       $this->parser->mHighestExpansionDepth = $expansionDepth;
+               }
+
+               if ( $root instanceof PPNode_DOM ) {
+                       $root = $root->node;
+               }
+               if ( $root instanceof DOMDocument ) {
+                       $root = $root->documentElement;
+               }
+
+               $outStack = [ '', '' ];
+               $iteratorStack = [ false, $root ];
+               $indexStack = [ 0, 0 ];
+
+               while ( count( $iteratorStack ) > 1 ) {
+                       $level = count( $outStack ) - 1;
+                       $iteratorNode =& $iteratorStack[$level];
+                       $out =& $outStack[$level];
+                       $index =& $indexStack[$level];
+
+                       if ( $iteratorNode instanceof PPNode_DOM ) {
+                               $iteratorNode = $iteratorNode->node;
+                       }
+
+                       if ( is_array( $iteratorNode ) ) {
+                               if ( $index >= count( $iteratorNode ) ) {
+                                       // All done with this iterator
+                                       $iteratorStack[$level] = false;
+                                       $contextNode = false;
+                               } else {
+                                       $contextNode = $iteratorNode[$index];
+                                       $index++;
+                               }
+                       } elseif ( $iteratorNode instanceof DOMNodeList ) {
+                               if ( $index >= $iteratorNode->length ) {
+                                       // All done with this iterator
+                                       $iteratorStack[$level] = false;
+                                       $contextNode = false;
+                               } else {
+                                       $contextNode = $iteratorNode->item( $index );
+                                       $index++;
+                               }
+                       } else {
+                               // Copy to $contextNode and then delete from iterator stack,
+                               // because this is not an iterator but we do have to execute it once
+                               $contextNode = $iteratorStack[$level];
+                               $iteratorStack[$level] = false;
+                       }
+
+                       if ( $contextNode instanceof PPNode_DOM ) {
+                               $contextNode = $contextNode->node;
+                       }
+
+                       $newIterator = false;
+
+                       if ( $contextNode === false ) {
+                               // nothing to do
+                       } elseif ( is_string( $contextNode ) ) {
+                               $out .= $contextNode;
+                       } elseif ( is_array( $contextNode ) || $contextNode instanceof DOMNodeList ) {
+                               $newIterator = $contextNode;
+                       } elseif ( $contextNode instanceof DOMNode ) {
+                               if ( $contextNode->nodeType == XML_TEXT_NODE ) {
+                                       $out .= $contextNode->nodeValue;
+                               } elseif ( $contextNode->nodeName == 'template' ) {
+                                       # Double-brace expansion
+                                       $xpath = new DOMXPath( $contextNode->ownerDocument );
+                                       $titles = $xpath->query( 'title', $contextNode );
+                                       $title = $titles->item( 0 );
+                                       $parts = $xpath->query( 'part', $contextNode );
+                                       if ( $flags & PPFrame::NO_TEMPLATES ) {
+                                               $newIterator = $this->virtualBracketedImplode( '{{', '|', '}}', $title, $parts );
+                                       } else {
+                                               $lineStart = $contextNode->getAttribute( 'lineStart' );
+                                               $params = [
+                                                       'title' => new PPNode_DOM( $title ),
+                                                       'parts' => new PPNode_DOM( $parts ),
+                                                       'lineStart' => $lineStart ];
+                                               $ret = $this->parser->braceSubstitution( $params, $this );
+                                               if ( isset( $ret['object'] ) ) {
+                                                       $newIterator = $ret['object'];
+                                               } else {
+                                                       $out .= $ret['text'];
+                                               }
+                                       }
+                               } elseif ( $contextNode->nodeName == 'tplarg' ) {
+                                       # Triple-brace expansion
+                                       $xpath = new DOMXPath( $contextNode->ownerDocument );
+                                       $titles = $xpath->query( 'title', $contextNode );
+                                       $title = $titles->item( 0 );
+                                       $parts = $xpath->query( 'part', $contextNode );
+                                       if ( $flags & PPFrame::NO_ARGS ) {
+                                               $newIterator = $this->virtualBracketedImplode( '{{{', '|', '}}}', $title, $parts );
+                                       } else {
+                                               $params = [
+                                                       'title' => new PPNode_DOM( $title ),
+                                                       'parts' => new PPNode_DOM( $parts ) ];
+                                               $ret = $this->parser->argSubstitution( $params, $this );
+                                               if ( isset( $ret['object'] ) ) {
+                                                       $newIterator = $ret['object'];
+                                               } else {
+                                                       $out .= $ret['text'];
+                                               }
+                                       }
+                               } elseif ( $contextNode->nodeName == 'comment' ) {
+                                       # HTML-style comment
+                                       # Remove it in HTML, pre+remove and STRIP_COMMENTS modes
+                                       # Not in RECOVER_COMMENTS mode (msgnw) though.
+                                       if ( ( $this->parser->ot['html']
+                                               || ( $this->parser->ot['pre'] && $this->parser->mOptions->getRemoveComments() )
+                                               || ( $flags & PPFrame::STRIP_COMMENTS )
+                                               ) && !( $flags & PPFrame::RECOVER_COMMENTS )
+                                       ) {
+                                               $out .= '';
+                                       } elseif ( $this->parser->ot['wiki'] && !( $flags & PPFrame::RECOVER_COMMENTS ) ) {
+                                               # Add a strip marker in PST mode so that pstPass2() can
+                                               # run some old-fashioned regexes on the result.
+                                               # Not in RECOVER_COMMENTS mode (extractSections) though.
+                                               $out .= $this->parser->insertStripItem( $contextNode->textContent );
+                                       } else {
+                                               # Recover the literal comment in RECOVER_COMMENTS and pre+no-remove
+                                               $out .= $contextNode->textContent;
+                                       }
+                               } elseif ( $contextNode->nodeName == 'ignore' ) {
+                                       # Output suppression used by <includeonly> etc.
+                                       # OT_WIKI will only respect <ignore> in substed templates.
+                                       # The other output types respect it unless NO_IGNORE is set.
+                                       # extractSections() sets NO_IGNORE and so never respects it.
+                                       if ( ( !isset( $this->parent ) && $this->parser->ot['wiki'] )
+                                               || ( $flags & PPFrame::NO_IGNORE )
+                                       ) {
+                                               $out .= $contextNode->textContent;
+                                       } else {
+                                               $out .= '';
+                                       }
+                               } elseif ( $contextNode->nodeName == 'ext' ) {
+                                       # Extension tag
+                                       $xpath = new DOMXPath( $contextNode->ownerDocument );
+                                       $names = $xpath->query( 'name', $contextNode );
+                                       $attrs = $xpath->query( 'attr', $contextNode );
+                                       $inners = $xpath->query( 'inner', $contextNode );
+                                       $closes = $xpath->query( 'close', $contextNode );
+                                       if ( $flags & PPFrame::NO_TAGS ) {
+                                               $s = '<' . $this->expand( $names->item( 0 ), $flags );
+                                               if ( $attrs->length > 0 ) {
+                                                       $s .= $this->expand( $attrs->item( 0 ), $flags );
+                                               }
+                                               if ( $inners->length > 0 ) {
+                                                       $s .= '>' . $this->expand( $inners->item( 0 ), $flags );
+                                                       if ( $closes->length > 0 ) {
+                                                               $s .= $this->expand( $closes->item( 0 ), $flags );
+                                                       }
+                                               } else {
+                                                       $s .= '/>';
+                                               }
+                                               $out .= $s;
+                                       } else {
+                                               $params = [
+                                                       'name' => new PPNode_DOM( $names->item( 0 ) ),
+                                                       'attr' => $attrs->length > 0 ? new PPNode_DOM( $attrs->item( 0 ) ) : null,
+                                                       'inner' => $inners->length > 0 ? new PPNode_DOM( $inners->item( 0 ) ) : null,
+                                                       'close' => $closes->length > 0 ? new PPNode_DOM( $closes->item( 0 ) ) : null,
+                                               ];
+                                               $out .= $this->parser->extensionSubstitution( $params, $this );
+                                       }
+                               } elseif ( $contextNode->nodeName == 'h' ) {
+                                       # Heading
+                                       $s = $this->expand( $contextNode->childNodes, $flags );
+
+                                       # Insert a heading marker only for <h> children of <root>
+                                       # This is to stop extractSections from going over multiple tree levels
+                                       if ( $contextNode->parentNode->nodeName == 'root' && $this->parser->ot['html'] ) {
+                                               # Insert heading index marker
+                                               $headingIndex = $contextNode->getAttribute( 'i' );
+                                               $titleText = $this->title->getPrefixedDBkey();
+                                               $this->parser->mHeadings[] = [ $titleText, $headingIndex ];
+                                               $serial = count( $this->parser->mHeadings ) - 1;
+                                               $marker = Parser::MARKER_PREFIX . "-h-$serial-" . Parser::MARKER_SUFFIX;
+                                               $count = $contextNode->getAttribute( 'level' );
+                                               $s = substr( $s, 0, $count ) . $marker . substr( $s, $count );
+                                               $this->parser->mStripState->addGeneral( $marker, '' );
+                                       }
+                                       $out .= $s;
+                               } else {
+                                       # Generic recursive expansion
+                                       $newIterator = $contextNode->childNodes;
+                               }
+                       } else {
+                               throw new MWException( __METHOD__ . ': Invalid parameter type' );
+                       }
+
+                       if ( $newIterator !== false ) {
+                               if ( $newIterator instanceof PPNode_DOM ) {
+                                       $newIterator = $newIterator->node;
+                               }
+                               $outStack[] = '';
+                               $iteratorStack[] = $newIterator;
+                               $indexStack[] = 0;
+                       } elseif ( $iteratorStack[$level] === false ) {
+                               // Return accumulated value to parent
+                               // With tail recursion
+                               while ( $iteratorStack[$level] === false && $level > 0 ) {
+                                       $outStack[$level - 1] .= $out;
+                                       array_pop( $outStack );
+                                       array_pop( $iteratorStack );
+                                       array_pop( $indexStack );
+                                       $level--;
+                               }
+                       }
+               }
+               --$expansionDepth;
+               return $outStack[0];
+       }
+
+       /**
+        * @param string $sep
+        * @param int $flags
+        * @param string|PPNode_DOM|DOMDocument ...$args
+        * @return string
+        */
+       public function implodeWithFlags( $sep, $flags, ...$args ) {
+               $first = true;
+               $s = '';
+               foreach ( $args as $root ) {
+                       if ( $root instanceof PPNode_DOM ) {
+                               $root = $root->node;
+                       }
+                       if ( !is_array( $root ) && !( $root instanceof DOMNodeList ) ) {
+                               $root = [ $root ];
+                       }
+                       foreach ( $root as $node ) {
+                               if ( $first ) {
+                                       $first = false;
+                               } else {
+                                       $s .= $sep;
+                               }
+                               $s .= $this->expand( $node, $flags );
+                       }
+               }
+               return $s;
+       }
+
+       /**
+        * Implode with no flags specified
+        * This previously called implodeWithFlags but has now been inlined to reduce stack depth
+        *
+        * @param string $sep
+        * @param string|PPNode_DOM|DOMDocument ...$args
+        * @return string
+        */
+       public function implode( $sep, ...$args ) {
+               $first = true;
+               $s = '';
+               foreach ( $args as $root ) {
+                       if ( $root instanceof PPNode_DOM ) {
+                               $root = $root->node;
+                       }
+                       if ( !is_array( $root ) && !( $root instanceof DOMNodeList ) ) {
+                               $root = [ $root ];
+                       }
+                       foreach ( $root as $node ) {
+                               if ( $first ) {
+                                       $first = false;
+                               } else {
+                                       $s .= $sep;
+                               }
+                               $s .= $this->expand( $node );
+                       }
+               }
+               return $s;
+       }
+
+       /**
+        * Makes an object that, when expand()ed, will be the same as one obtained
+        * with implode()
+        *
+        * @param string $sep
+        * @param string|PPNode_DOM|DOMDocument ...$args
+        * @return array
+        */
+       public function virtualImplode( $sep, ...$args ) {
+               $out = [];
+               $first = true;
+
+               foreach ( $args as $root ) {
+                       if ( $root instanceof PPNode_DOM ) {
+                               $root = $root->node;
+                       }
+                       if ( !is_array( $root ) && !( $root instanceof DOMNodeList ) ) {
+                               $root = [ $root ];
+                       }
+                       foreach ( $root as $node ) {
+                               if ( $first ) {
+                                       $first = false;
+                               } else {
+                                       $out[] = $sep;
+                               }
+                               $out[] = $node;
+                       }
+               }
+               return $out;
+       }
+
+       /**
+        * Virtual implode with brackets
+        * @param string $start
+        * @param string $sep
+        * @param string $end
+        * @param string|PPNode_DOM|DOMDocument ...$args
+        * @return array
+        */
+       public function virtualBracketedImplode( $start, $sep, $end, ...$args ) {
+               $out = [ $start ];
+               $first = true;
+
+               foreach ( $args as $root ) {
+                       if ( $root instanceof PPNode_DOM ) {
+                               $root = $root->node;
+                       }
+                       if ( !is_array( $root ) && !( $root instanceof DOMNodeList ) ) {
+                               $root = [ $root ];
+                       }
+                       foreach ( $root as $node ) {
+                               if ( $first ) {
+                                       $first = false;
+                               } else {
+                                       $out[] = $sep;
+                               }
+                               $out[] = $node;
+                       }
+               }
+               $out[] = $end;
+               return $out;
+       }
+
+       public function __toString() {
+               return 'frame{}';
+       }
+
+       public function getPDBK( $level = false ) {
+               if ( $level === false ) {
+                       return $this->title->getPrefixedDBkey();
+               } else {
+                       return $this->titleCache[$level] ?? false;
+               }
+       }
+
+       /**
+        * @return array
+        */
+       public function getArguments() {
+               return [];
+       }
+
+       /**
+        * @return array
+        */
+       public function getNumberedArguments() {
+               return [];
+       }
+
+       /**
+        * @return array
+        */
+       public function getNamedArguments() {
+               return [];
+       }
+
+       /**
+        * Returns true if there are no arguments in this frame
+        *
+        * @return bool
+        */
+       public function isEmpty() {
+               return true;
+       }
+
+       /**
+        * @param int|string $name
+        * @return bool Always false in this implementation.
+        */
+       public function getArgument( $name ) {
+               return false;
+       }
+
+       /**
+        * Returns true if the infinite loop check is OK, false if a loop is detected
+        *
+        * @param Title $title
+        * @return bool
+        */
+       public function loopCheck( $title ) {
+               return !isset( $this->loopCheckHash[$title->getPrefixedDBkey()] );
+       }
+
+       /**
+        * Return true if the frame is a template frame
+        *
+        * @return bool
+        */
+       public function isTemplate() {
+               return false;
+       }
+
+       /**
+        * Get a title of frame
+        *
+        * @return Title
+        */
+       public function getTitle() {
+               return $this->title;
+       }
+
+       /**
+        * Set the volatile flag
+        *
+        * @param bool $flag
+        */
+       public function setVolatile( $flag = true ) {
+               $this->volatile = $flag;
+       }
+
+       /**
+        * Get the volatile flag
+        *
+        * @return bool
+        */
+       public function isVolatile() {
+               return $this->volatile;
+       }
+
+       /**
+        * Set the TTL
+        *
+        * @param int $ttl
+        */
+       public function setTTL( $ttl ) {
+               if ( $ttl !== null && ( $this->ttl === null || $ttl < $this->ttl ) ) {
+                       $this->ttl = $ttl;
+               }
+       }
+
+       /**
+        * Get the TTL
+        *
+        * @return int|null
+        */
+       public function getTTL() {
+               return $this->ttl;
+       }
+}
diff --git a/includes/parser/PPFrame_Hash.php b/includes/parser/PPFrame_Hash.php
new file mode 100644 (file)
index 0000000..845ec73
--- /dev/null
@@ -0,0 +1,613 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Parser
+ */
+
+/**
+ * An expansion frame, used as a context to expand the result of preprocessToObj()
+ * @ingroup Parser
+ */
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
+class PPFrame_Hash implements PPFrame {
+
+       /**
+        * @var Parser
+        */
+       public $parser;
+
+       /**
+        * @var Preprocessor
+        */
+       public $preprocessor;
+
+       /**
+        * @var Title
+        */
+       public $title;
+       public $titleCache;
+
+       /**
+        * Hashtable listing templates which are disallowed for expansion in this frame,
+        * having been encountered previously in parent frames.
+        */
+       public $loopCheckHash;
+
+       /**
+        * Recursion depth of this frame, top = 0
+        * Note that this is NOT the same as expansion depth in expand()
+        */
+       public $depth;
+
+       private $volatile = false;
+       private $ttl = null;
+
+       /**
+        * @var array
+        */
+       protected $childExpansionCache;
+
+       /**
+        * Construct a new preprocessor frame.
+        * @param Preprocessor $preprocessor The parent preprocessor
+        */
+       public function __construct( $preprocessor ) {
+               $this->preprocessor = $preprocessor;
+               $this->parser = $preprocessor->parser;
+               $this->title = $this->parser->mTitle;
+               $this->titleCache = [ $this->title ? $this->title->getPrefixedDBkey() : false ];
+               $this->loopCheckHash = [];
+               $this->depth = 0;
+               $this->childExpansionCache = [];
+       }
+
+       /**
+        * Create a new child frame
+        * $args is optionally a multi-root PPNode or array containing the template arguments
+        *
+        * @param array|bool|PPNode_Hash_Array $args
+        * @param Title|bool $title
+        * @param int $indexOffset
+        * @throws MWException
+        * @return PPTemplateFrame_Hash
+        */
+       public function newChild( $args = false, $title = false, $indexOffset = 0 ) {
+               $namedArgs = [];
+               $numberedArgs = [];
+               if ( $title === false ) {
+                       $title = $this->title;
+               }
+               if ( $args !== false ) {
+                       if ( $args instanceof PPNode_Hash_Array ) {
+                               $args = $args->value;
+                       } elseif ( !is_array( $args ) ) {
+                               throw new MWException( __METHOD__ . ': $args must be array or PPNode_Hash_Array' );
+                       }
+                       foreach ( $args as $arg ) {
+                               $bits = $arg->splitArg();
+                               if ( $bits['index'] !== '' ) {
+                                       // Numbered parameter
+                                       $index = $bits['index'] - $indexOffset;
+                                       if ( isset( $namedArgs[$index] ) || isset( $numberedArgs[$index] ) ) {
+                                               $this->parser->getOutput()->addWarning( wfMessage( 'duplicate-args-warning',
+                                                       wfEscapeWikiText( $this->title ),
+                                                       wfEscapeWikiText( $title ),
+                                                       wfEscapeWikiText( $index ) )->text() );
+                                               $this->parser->addTrackingCategory( 'duplicate-args-category' );
+                                       }
+                                       $numberedArgs[$index] = $bits['value'];
+                                       unset( $namedArgs[$index] );
+                               } else {
+                                       // Named parameter
+                                       $name = trim( $this->expand( $bits['name'], PPFrame::STRIP_COMMENTS ) );
+                                       if ( isset( $namedArgs[$name] ) || isset( $numberedArgs[$name] ) ) {
+                                               $this->parser->getOutput()->addWarning( wfMessage( 'duplicate-args-warning',
+                                                       wfEscapeWikiText( $this->title ),
+                                                       wfEscapeWikiText( $title ),
+                                                       wfEscapeWikiText( $name ) )->text() );
+                                               $this->parser->addTrackingCategory( 'duplicate-args-category' );
+                                       }
+                                       $namedArgs[$name] = $bits['value'];
+                                       unset( $numberedArgs[$name] );
+                               }
+                       }
+               }
+               return new PPTemplateFrame_Hash( $this->preprocessor, $this, $numberedArgs, $namedArgs, $title );
+       }
+
+       /**
+        * @throws MWException
+        * @param string|int $key
+        * @param string|PPNode $root
+        * @param int $flags
+        * @return string
+        */
+       public function cachedExpand( $key, $root, $flags = 0 ) {
+               // we don't have a parent, so we don't have a cache
+               return $this->expand( $root, $flags );
+       }
+
+       /**
+        * @throws MWException
+        * @param string|PPNode $root
+        * @param int $flags
+        * @return string
+        */
+       public function expand( $root, $flags = 0 ) {
+               static $expansionDepth = 0;
+               if ( is_string( $root ) ) {
+                       return $root;
+               }
+
+               if ( ++$this->parser->mPPNodeCount > $this->parser->mOptions->getMaxPPNodeCount() ) {
+                       $this->parser->limitationWarn( 'node-count-exceeded',
+                                       $this->parser->mPPNodeCount,
+                                       $this->parser->mOptions->getMaxPPNodeCount()
+                       );
+                       return '<span class="error">Node-count limit exceeded</span>';
+               }
+               if ( $expansionDepth > $this->parser->mOptions->getMaxPPExpandDepth() ) {
+                       $this->parser->limitationWarn( 'expansion-depth-exceeded',
+                                       $expansionDepth,
+                                       $this->parser->mOptions->getMaxPPExpandDepth()
+                       );
+                       return '<span class="error">Expansion depth limit exceeded</span>';
+               }
+               ++$expansionDepth;
+               if ( $expansionDepth > $this->parser->mHighestExpansionDepth ) {
+                       $this->parser->mHighestExpansionDepth = $expansionDepth;
+               }
+
+               $outStack = [ '', '' ];
+               $iteratorStack = [ false, $root ];
+               $indexStack = [ 0, 0 ];
+
+               while ( count( $iteratorStack ) > 1 ) {
+                       $level = count( $outStack ) - 1;
+                       $iteratorNode =& $iteratorStack[$level];
+                       $out =& $outStack[$level];
+                       $index =& $indexStack[$level];
+
+                       if ( is_array( $iteratorNode ) ) {
+                               if ( $index >= count( $iteratorNode ) ) {
+                                       // All done with this iterator
+                                       $iteratorStack[$level] = false;
+                                       $contextNode = false;
+                               } else {
+                                       $contextNode = $iteratorNode[$index];
+                                       $index++;
+                               }
+                       } elseif ( $iteratorNode instanceof PPNode_Hash_Array ) {
+                               if ( $index >= $iteratorNode->getLength() ) {
+                                       // All done with this iterator
+                                       $iteratorStack[$level] = false;
+                                       $contextNode = false;
+                               } else {
+                                       $contextNode = $iteratorNode->item( $index );
+                                       $index++;
+                               }
+                       } else {
+                               // Copy to $contextNode and then delete from iterator stack,
+                               // because this is not an iterator but we do have to execute it once
+                               $contextNode = $iteratorStack[$level];
+                               $iteratorStack[$level] = false;
+                       }
+
+                       $newIterator = false;
+                       $contextName = false;
+                       $contextChildren = false;
+
+                       if ( $contextNode === false ) {
+                               // nothing to do
+                       } elseif ( is_string( $contextNode ) ) {
+                               $out .= $contextNode;
+                       } elseif ( $contextNode instanceof PPNode_Hash_Array ) {
+                               $newIterator = $contextNode;
+                       } elseif ( $contextNode instanceof PPNode_Hash_Attr ) {
+                               // No output
+                       } elseif ( $contextNode instanceof PPNode_Hash_Text ) {
+                               $out .= $contextNode->value;
+                       } elseif ( $contextNode instanceof PPNode_Hash_Tree ) {
+                               $contextName = $contextNode->name;
+                               $contextChildren = $contextNode->getRawChildren();
+                       } elseif ( is_array( $contextNode ) ) {
+                               // Node descriptor array
+                               if ( count( $contextNode ) !== 2 ) {
+                                       throw new MWException( __METHOD__ .
+                                               ': found an array where a node descriptor should be' );
+                               }
+                               list( $contextName, $contextChildren ) = $contextNode;
+                       } else {
+                               throw new MWException( __METHOD__ . ': Invalid parameter type' );
+                       }
+
+                       // Handle node descriptor array or tree object
+                       if ( $contextName === false ) {
+                               // Not a node, already handled above
+                       } elseif ( $contextName[0] === '@' ) {
+                               // Attribute: no output
+                       } elseif ( $contextName === 'template' ) {
+                               # Double-brace expansion
+                               $bits = PPNode_Hash_Tree::splitRawTemplate( $contextChildren );
+                               if ( $flags & PPFrame::NO_TEMPLATES ) {
+                                       $newIterator = $this->virtualBracketedImplode(
+                                               '{{', '|', '}}',
+                                               $bits['title'],
+                                               $bits['parts']
+                                       );
+                               } else {
+                                       $ret = $this->parser->braceSubstitution( $bits, $this );
+                                       if ( isset( $ret['object'] ) ) {
+                                               $newIterator = $ret['object'];
+                                       } else {
+                                               $out .= $ret['text'];
+                                       }
+                               }
+                       } elseif ( $contextName === 'tplarg' ) {
+                               # Triple-brace expansion
+                               $bits = PPNode_Hash_Tree::splitRawTemplate( $contextChildren );
+                               if ( $flags & PPFrame::NO_ARGS ) {
+                                       $newIterator = $this->virtualBracketedImplode(
+                                               '{{{', '|', '}}}',
+                                               $bits['title'],
+                                               $bits['parts']
+                                       );
+                               } else {
+                                       $ret = $this->parser->argSubstitution( $bits, $this );
+                                       if ( isset( $ret['object'] ) ) {
+                                               $newIterator = $ret['object'];
+                                       } else {
+                                               $out .= $ret['text'];
+                                       }
+                               }
+                       } elseif ( $contextName === 'comment' ) {
+                               # HTML-style comment
+                               # Remove it in HTML, pre+remove and STRIP_COMMENTS modes
+                               # Not in RECOVER_COMMENTS mode (msgnw) though.
+                               if ( ( $this->parser->ot['html']
+                                       || ( $this->parser->ot['pre'] && $this->parser->mOptions->getRemoveComments() )
+                                       || ( $flags & PPFrame::STRIP_COMMENTS )
+                                       ) && !( $flags & PPFrame::RECOVER_COMMENTS )
+                               ) {
+                                       $out .= '';
+                               } elseif ( $this->parser->ot['wiki'] && !( $flags & PPFrame::RECOVER_COMMENTS ) ) {
+                                       # Add a strip marker in PST mode so that pstPass2() can
+                                       # run some old-fashioned regexes on the result.
+                                       # Not in RECOVER_COMMENTS mode (extractSections) though.
+                                       $out .= $this->parser->insertStripItem( $contextChildren[0] );
+                               } else {
+                                       # Recover the literal comment in RECOVER_COMMENTS and pre+no-remove
+                                       $out .= $contextChildren[0];
+                               }
+                       } elseif ( $contextName === 'ignore' ) {
+                               # Output suppression used by <includeonly> etc.
+                               # OT_WIKI will only respect <ignore> in substed templates.
+                               # The other output types respect it unless NO_IGNORE is set.
+                               # extractSections() sets NO_IGNORE and so never respects it.
+                               if ( ( !isset( $this->parent ) && $this->parser->ot['wiki'] )
+                                       || ( $flags & PPFrame::NO_IGNORE )
+                               ) {
+                                       $out .= $contextChildren[0];
+                               } else {
+                                       // $out .= '';
+                               }
+                       } elseif ( $contextName === 'ext' ) {
+                               # Extension tag
+                               $bits = PPNode_Hash_Tree::splitRawExt( $contextChildren ) +
+                                       [ 'attr' => null, 'inner' => null, 'close' => null ];
+                               if ( $flags & PPFrame::NO_TAGS ) {
+                                       $s = '<' . $bits['name']->getFirstChild()->value;
+                                       if ( $bits['attr'] ) {
+                                               $s .= $bits['attr']->getFirstChild()->value;
+                                       }
+                                       if ( $bits['inner'] ) {
+                                               $s .= '>' . $bits['inner']->getFirstChild()->value;
+                                               if ( $bits['close'] ) {
+                                                       $s .= $bits['close']->getFirstChild()->value;
+                                               }
+                                       } else {
+                                               $s .= '/>';
+                                       }
+                                       $out .= $s;
+                               } else {
+                                       $out .= $this->parser->extensionSubstitution( $bits, $this );
+                               }
+                       } elseif ( $contextName === 'h' ) {
+                               # Heading
+                               if ( $this->parser->ot['html'] ) {
+                                       # Expand immediately and insert heading index marker
+                                       $s = $this->expand( $contextChildren, $flags );
+                                       $bits = PPNode_Hash_Tree::splitRawHeading( $contextChildren );
+                                       $titleText = $this->title->getPrefixedDBkey();
+                                       $this->parser->mHeadings[] = [ $titleText, $bits['i'] ];
+                                       $serial = count( $this->parser->mHeadings ) - 1;
+                                       $marker = Parser::MARKER_PREFIX . "-h-$serial-" . Parser::MARKER_SUFFIX;
+                                       $s = substr( $s, 0, $bits['level'] ) . $marker . substr( $s, $bits['level'] );
+                                       $this->parser->mStripState->addGeneral( $marker, '' );
+                                       $out .= $s;
+                               } else {
+                                       # Expand in virtual stack
+                                       $newIterator = $contextChildren;
+                               }
+                       } else {
+                               # Generic recursive expansion
+                               $newIterator = $contextChildren;
+                       }
+
+                       if ( $newIterator !== false ) {
+                               $outStack[] = '';
+                               $iteratorStack[] = $newIterator;
+                               $indexStack[] = 0;
+                       } elseif ( $iteratorStack[$level] === false ) {
+                               // Return accumulated value to parent
+                               // With tail recursion
+                               while ( $iteratorStack[$level] === false && $level > 0 ) {
+                                       $outStack[$level - 1] .= $out;
+                                       array_pop( $outStack );
+                                       array_pop( $iteratorStack );
+                                       array_pop( $indexStack );
+                                       $level--;
+                               }
+                       }
+               }
+               --$expansionDepth;
+               return $outStack[0];
+       }
+
+       /**
+        * @param string $sep
+        * @param int $flags
+        * @param string|PPNode ...$args
+        * @return string
+        */
+       public function implodeWithFlags( $sep, $flags, ...$args ) {
+               $first = true;
+               $s = '';
+               foreach ( $args as $root ) {
+                       if ( $root instanceof PPNode_Hash_Array ) {
+                               $root = $root->value;
+                       }
+                       if ( !is_array( $root ) ) {
+                               $root = [ $root ];
+                       }
+                       foreach ( $root as $node ) {
+                               if ( $first ) {
+                                       $first = false;
+                               } else {
+                                       $s .= $sep;
+                               }
+                               $s .= $this->expand( $node, $flags );
+                       }
+               }
+               return $s;
+       }
+
+       /**
+        * Implode with no flags specified
+        * This previously called implodeWithFlags but has now been inlined to reduce stack depth
+        * @param string $sep
+        * @param string|PPNode ...$args
+        * @return string
+        */
+       public function implode( $sep, ...$args ) {
+               $first = true;
+               $s = '';
+               foreach ( $args as $root ) {
+                       if ( $root instanceof PPNode_Hash_Array ) {
+                               $root = $root->value;
+                       }
+                       if ( !is_array( $root ) ) {
+                               $root = [ $root ];
+                       }
+                       foreach ( $root as $node ) {
+                               if ( $first ) {
+                                       $first = false;
+                               } else {
+                                       $s .= $sep;
+                               }
+                               $s .= $this->expand( $node );
+                       }
+               }
+               return $s;
+       }
+
+       /**
+        * Makes an object that, when expand()ed, will be the same as one obtained
+        * with implode()
+        *
+        * @param string $sep
+        * @param string|PPNode ...$args
+        * @return PPNode_Hash_Array
+        */
+       public function virtualImplode( $sep, ...$args ) {
+               $out = [];
+               $first = true;
+
+               foreach ( $args as $root ) {
+                       if ( $root instanceof PPNode_Hash_Array ) {
+                               $root = $root->value;
+                       }
+                       if ( !is_array( $root ) ) {
+                               $root = [ $root ];
+                       }
+                       foreach ( $root as $node ) {
+                               if ( $first ) {
+                                       $first = false;
+                               } else {
+                                       $out[] = $sep;
+                               }
+                               $out[] = $node;
+                       }
+               }
+               return new PPNode_Hash_Array( $out );
+       }
+
+       /**
+        * Virtual implode with brackets
+        *
+        * @param string $start
+        * @param string $sep
+        * @param string $end
+        * @param string|PPNode ...$args
+        * @return PPNode_Hash_Array
+        */
+       public function virtualBracketedImplode( $start, $sep, $end, ...$args ) {
+               $out = [ $start ];
+               $first = true;
+
+               foreach ( $args as $root ) {
+                       if ( $root instanceof PPNode_Hash_Array ) {
+                               $root = $root->value;
+                       }
+                       if ( !is_array( $root ) ) {
+                               $root = [ $root ];
+                       }
+                       foreach ( $root as $node ) {
+                               if ( $first ) {
+                                       $first = false;
+                               } else {
+                                       $out[] = $sep;
+                               }
+                               $out[] = $node;
+                       }
+               }
+               $out[] = $end;
+               return new PPNode_Hash_Array( $out );
+       }
+
+       public function __toString() {
+               return 'frame{}';
+       }
+
+       /**
+        * @param bool $level
+        * @return array|bool|string
+        */
+       public function getPDBK( $level = false ) {
+               if ( $level === false ) {
+                       return $this->title->getPrefixedDBkey();
+               } else {
+                       return $this->titleCache[$level] ?? false;
+               }
+       }
+
+       /**
+        * @return array
+        */
+       public function getArguments() {
+               return [];
+       }
+
+       /**
+        * @return array
+        */
+       public function getNumberedArguments() {
+               return [];
+       }
+
+       /**
+        * @return array
+        */
+       public function getNamedArguments() {
+               return [];
+       }
+
+       /**
+        * Returns true if there are no arguments in this frame
+        *
+        * @return bool
+        */
+       public function isEmpty() {
+               return true;
+       }
+
+       /**
+        * @param int|string $name
+        * @return bool Always false in this implementation.
+        */
+       public function getArgument( $name ) {
+               return false;
+       }
+
+       /**
+        * Returns true if the infinite loop check is OK, false if a loop is detected
+        *
+        * @param Title $title
+        *
+        * @return bool
+        */
+       public function loopCheck( $title ) {
+               return !isset( $this->loopCheckHash[$title->getPrefixedDBkey()] );
+       }
+
+       /**
+        * Return true if the frame is a template frame
+        *
+        * @return bool
+        */
+       public function isTemplate() {
+               return false;
+       }
+
+       /**
+        * Get a title of frame
+        *
+        * @return Title
+        */
+       public function getTitle() {
+               return $this->title;
+       }
+
+       /**
+        * Set the volatile flag
+        *
+        * @param bool $flag
+        */
+       public function setVolatile( $flag = true ) {
+               $this->volatile = $flag;
+       }
+
+       /**
+        * Get the volatile flag
+        *
+        * @return bool
+        */
+       public function isVolatile() {
+               return $this->volatile;
+       }
+
+       /**
+        * Set the TTL
+        *
+        * @param int $ttl
+        */
+       public function setTTL( $ttl ) {
+               if ( $ttl !== null && ( $this->ttl === null || $ttl < $this->ttl ) ) {
+                       $this->ttl = $ttl;
+               }
+       }
+
+       /**
+        * Get the TTL
+        *
+        * @return int|null
+        */
+       public function getTTL() {
+               return $this->ttl;
+       }
+}
diff --git a/includes/parser/PPNode.php b/includes/parser/PPNode.php
new file mode 100644 (file)
index 0000000..2b6cf7c
--- /dev/null
@@ -0,0 +1,112 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Parser
+ */
+
+/**
+ * There are three types of nodes:
+ *     * Tree nodes, which have a name and contain other nodes as children
+ *     * Array nodes, which also contain other nodes but aren't considered part of a tree
+ *     * Leaf nodes, which contain the actual data
+ *
+ * This interface provides access to the tree structure and to the contents of array nodes,
+ * but it does not provide access to the internal structure of leaf nodes. Access to leaf
+ * data is provided via two means:
+ *     * PPFrame::expand(), which provides expanded text
+ *     * The PPNode::split*() functions, which provide metadata about certain types of tree node
+ * @ingroup Parser
+ */
+interface PPNode {
+       /**
+        * Get an array-type node containing the children of this node.
+        * Returns false if this is not a tree node.
+        * @return PPNode
+        */
+       public function getChildren();
+
+       /**
+        * Get the first child of a tree node. False if there isn't one.
+        *
+        * @return PPNode
+        */
+       public function getFirstChild();
+
+       /**
+        * Get the next sibling of any node. False if there isn't one
+        * @return PPNode
+        */
+       public function getNextSibling();
+
+       /**
+        * Get all children of this tree node which have a given name.
+        * Returns an array-type node, or false if this is not a tree node.
+        * @param string $type
+        * @return bool|PPNode
+        */
+       public function getChildrenOfType( $type );
+
+       /**
+        * Returns the length of the array, or false if this is not an array-type node
+        */
+       public function getLength();
+
+       /**
+        * Returns an item of an array-type node
+        * @param int $i
+        * @return bool|PPNode
+        */
+       public function item( $i );
+
+       /**
+        * Get the name of this node. The following names are defined here:
+        *
+        *    h             A heading node.
+        *    template      A double-brace node.
+        *    tplarg        A triple-brace node.
+        *    title         The first argument to a template or tplarg node.
+        *    part          Subsequent arguments to a template or tplarg node.
+        *    #nodelist     An array-type node
+        *
+        * The subclass may define various other names for tree and leaf nodes.
+        * @return string
+        */
+       public function getName();
+
+       /**
+        * Split a "<part>" node into an associative array containing:
+        *    name          PPNode name
+        *    index         String index
+        *    value         PPNode value
+        * @return array
+        */
+       public function splitArg();
+
+       /**
+        * Split an "<ext>" node into an associative array containing name, attr, inner and close
+        * All values in the resulting array are PPNodes. Inner and close are optional.
+        * @return array
+        */
+       public function splitExt();
+
+       /**
+        * Split an "<h>" node
+        * @return array
+        */
+       public function splitHeading();
+}
diff --git a/includes/parser/PPNode_DOM.php b/includes/parser/PPNode_DOM.php
new file mode 100644 (file)
index 0000000..8a435ba
--- /dev/null
@@ -0,0 +1,188 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Parser
+ */
+
+/**
+ * @ingroup Parser
+ */
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
+class PPNode_DOM implements PPNode {
+
+       /**
+        * @var DOMElement
+        */
+       public $node;
+       public $xpath;
+
+       public function __construct( $node, $xpath = false ) {
+               $this->node = $node;
+       }
+
+       /**
+        * @return DOMXPath
+        */
+       public function getXPath() {
+               if ( $this->xpath === null ) {
+                       $this->xpath = new DOMXPath( $this->node->ownerDocument );
+               }
+               return $this->xpath;
+       }
+
+       public function __toString() {
+               if ( $this->node instanceof DOMNodeList ) {
+                       $s = '';
+                       foreach ( $this->node as $node ) {
+                               $s .= $node->ownerDocument->saveXML( $node );
+                       }
+               } else {
+                       $s = $this->node->ownerDocument->saveXML( $this->node );
+               }
+               return $s;
+       }
+
+       /**
+        * @return bool|PPNode_DOM
+        */
+       public function getChildren() {
+               return $this->node->childNodes ? new self( $this->node->childNodes ) : false;
+       }
+
+       /**
+        * @return bool|PPNode_DOM
+        */
+       public function getFirstChild() {
+               return $this->node->firstChild ? new self( $this->node->firstChild ) : false;
+       }
+
+       /**
+        * @return bool|PPNode_DOM
+        */
+       public function getNextSibling() {
+               return $this->node->nextSibling ? new self( $this->node->nextSibling ) : false;
+       }
+
+       /**
+        * @param string $type
+        *
+        * @return bool|PPNode_DOM
+        */
+       public function getChildrenOfType( $type ) {
+               return new self( $this->getXPath()->query( $type, $this->node ) );
+       }
+
+       /**
+        * @return int
+        */
+       public function getLength() {
+               if ( $this->node instanceof DOMNodeList ) {
+                       return $this->node->length;
+               } else {
+                       return false;
+               }
+       }
+
+       /**
+        * @param int $i
+        * @return bool|PPNode_DOM
+        */
+       public function item( $i ) {
+               $item = $this->node->item( $i );
+               return $item ? new self( $item ) : false;
+       }
+
+       /**
+        * @return string
+        */
+       public function getName() {
+               if ( $this->node instanceof DOMNodeList ) {
+                       return '#nodelist';
+               } else {
+                       return $this->node->nodeName;
+               }
+       }
+
+       /**
+        * Split a "<part>" node into an associative array containing:
+        *  - name          PPNode name
+        *  - index         String index
+        *  - value         PPNode value
+        *
+        * @throws MWException
+        * @return array
+        */
+       public function splitArg() {
+               $xpath = $this->getXPath();
+               $names = $xpath->query( 'name', $this->node );
+               $values = $xpath->query( 'value', $this->node );
+               if ( !$names->length || !$values->length ) {
+                       throw new MWException( 'Invalid brace node passed to ' . __METHOD__ );
+               }
+               $name = $names->item( 0 );
+               $index = $name->getAttribute( 'index' );
+               return [
+                       'name' => new self( $name ),
+                       'index' => $index,
+                       'value' => new self( $values->item( 0 ) ) ];
+       }
+
+       /**
+        * Split an "<ext>" node into an associative array containing name, attr, inner and close
+        * All values in the resulting array are PPNodes. Inner and close are optional.
+        *
+        * @throws MWException
+        * @return array
+        */
+       public function splitExt() {
+               $xpath = $this->getXPath();
+               $names = $xpath->query( 'name', $this->node );
+               $attrs = $xpath->query( 'attr', $this->node );
+               $inners = $xpath->query( 'inner', $this->node );
+               $closes = $xpath->query( 'close', $this->node );
+               if ( !$names->length || !$attrs->length ) {
+                       throw new MWException( 'Invalid ext node passed to ' . __METHOD__ );
+               }
+               $parts = [
+                       'name' => new self( $names->item( 0 ) ),
+                       'attr' => new self( $attrs->item( 0 ) ) ];
+               if ( $inners->length ) {
+                       $parts['inner'] = new self( $inners->item( 0 ) );
+               }
+               if ( $closes->length ) {
+                       $parts['close'] = new self( $closes->item( 0 ) );
+               }
+               return $parts;
+       }
+
+       /**
+        * Split a "<h>" node
+        * @throws MWException
+        * @return array
+        */
+       public function splitHeading() {
+               if ( $this->getName() !== 'h' ) {
+                       throw new MWException( 'Invalid h node passed to ' . __METHOD__ );
+               }
+               return [
+                       'i' => $this->node->getAttribute( 'i' ),
+                       'level' => $this->node->getAttribute( 'level' ),
+                       'contents' => $this->getChildren()
+               ];
+       }
+}
diff --git a/includes/parser/PPNode_Hash_Array.php b/includes/parser/PPNode_Hash_Array.php
new file mode 100644 (file)
index 0000000..3892616
--- /dev/null
@@ -0,0 +1,77 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Parser
+ */
+
+/**
+ * @ingroup Parser
+ */
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
+class PPNode_Hash_Array implements PPNode {
+
+       public $value;
+
+       public function __construct( $value ) {
+               $this->value = $value;
+       }
+
+       public function __toString() {
+               return var_export( $this, true );
+       }
+
+       public function getLength() {
+               return count( $this->value );
+       }
+
+       public function item( $i ) {
+               return $this->value[$i];
+       }
+
+       public function getName() {
+               return '#nodelist';
+       }
+
+       public function getNextSibling() {
+               return false;
+       }
+
+       public function getChildren() {
+               return false;
+       }
+
+       public function getFirstChild() {
+               return false;
+       }
+
+       public function getChildrenOfType( $name ) {
+               return false;
+       }
+
+       public function splitArg() {
+               throw new MWException( __METHOD__ . ': not supported' );
+       }
+
+       public function splitExt() {
+               throw new MWException( __METHOD__ . ': not supported' );
+       }
+
+       public function splitHeading() {
+               throw new MWException( __METHOD__ . ': not supported' );
+       }
+}
diff --git a/includes/parser/PPNode_Hash_Attr.php b/includes/parser/PPNode_Hash_Attr.php
new file mode 100644 (file)
index 0000000..91ba69d
--- /dev/null
@@ -0,0 +1,92 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Parser
+ */
+
+/**
+ * @ingroup Parser
+ */
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
+class PPNode_Hash_Attr implements PPNode {
+
+       public $name, $value;
+       private $store, $index;
+
+       /**
+        * Construct an object using the data from $store[$index]. The rest of the
+        * store array can be accessed via getNextSibling().
+        *
+        * @param array $store
+        * @param int $index
+        */
+       public function __construct( array $store, $index ) {
+               $descriptor = $store[$index];
+               if ( $descriptor[PPNode_Hash_Tree::NAME][0] !== '@' ) {
+                       throw new MWException( __METHOD__ . ': invalid name in attribute descriptor' );
+               }
+               $this->name = substr( $descriptor[PPNode_Hash_Tree::NAME], 1 );
+               $this->value = $descriptor[PPNode_Hash_Tree::CHILDREN][0];
+               $this->store = $store;
+               $this->index = $index;
+       }
+
+       public function __toString() {
+               return "<@{$this->name}>" . htmlspecialchars( $this->value ) . "</@{$this->name}>";
+       }
+
+       public function getName() {
+               return $this->name;
+       }
+
+       public function getNextSibling() {
+               return PPNode_Hash_Tree::factory( $this->store, $this->index + 1 );
+       }
+
+       public function getChildren() {
+               return false;
+       }
+
+       public function getFirstChild() {
+               return false;
+       }
+
+       public function getChildrenOfType( $name ) {
+               return false;
+       }
+
+       public function getLength() {
+               return false;
+       }
+
+       public function item( $i ) {
+               return false;
+       }
+
+       public function splitArg() {
+               throw new MWException( __METHOD__ . ': not supported' );
+       }
+
+       public function splitExt() {
+               throw new MWException( __METHOD__ . ': not supported' );
+       }
+
+       public function splitHeading() {
+               throw new MWException( __METHOD__ . ': not supported' );
+       }
+}
diff --git a/includes/parser/PPNode_Hash_Text.php b/includes/parser/PPNode_Hash_Text.php
new file mode 100644 (file)
index 0000000..182982f
--- /dev/null
@@ -0,0 +1,90 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Parser
+ */
+
+/**
+ * @ingroup Parser
+ */
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
+class PPNode_Hash_Text implements PPNode {
+
+       public $value;
+       private $store, $index;
+
+       /**
+        * Construct an object using the data from $store[$index]. The rest of the
+        * store array can be accessed via getNextSibling().
+        *
+        * @param array $store
+        * @param int $index
+        */
+       public function __construct( array $store, $index ) {
+               $this->value = $store[$index];
+               if ( !is_scalar( $this->value ) ) {
+                       throw new MWException( __CLASS__ . ' given object instead of string' );
+               }
+               $this->store = $store;
+               $this->index = $index;
+       }
+
+       public function __toString() {
+               return htmlspecialchars( $this->value );
+       }
+
+       public function getNextSibling() {
+               return PPNode_Hash_Tree::factory( $this->store, $this->index + 1 );
+       }
+
+       public function getChildren() {
+               return false;
+       }
+
+       public function getFirstChild() {
+               return false;
+       }
+
+       public function getChildrenOfType( $name ) {
+               return false;
+       }
+
+       public function getLength() {
+               return false;
+       }
+
+       public function item( $i ) {
+               return false;
+       }
+
+       public function getName() {
+               return '#text';
+       }
+
+       public function splitArg() {
+               throw new MWException( __METHOD__ . ': not supported' );
+       }
+
+       public function splitExt() {
+               throw new MWException( __METHOD__ . ': not supported' );
+       }
+
+       public function splitHeading() {
+               throw new MWException( __METHOD__ . ': not supported' );
+       }
+}
diff --git a/includes/parser/PPNode_Hash_Tree.php b/includes/parser/PPNode_Hash_Tree.php
new file mode 100644 (file)
index 0000000..e6cabf8
--- /dev/null
@@ -0,0 +1,369 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Parser
+ */
+
+/**
+ * @ingroup Parser
+ */
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
+class PPNode_Hash_Tree implements PPNode {
+
+       public $name;
+
+       /**
+        * The store array for children of this node. It is "raw" in the sense that
+        * nodes are two-element arrays ("descriptors") rather than PPNode_Hash_*
+        * objects.
+        */
+       private $rawChildren;
+
+       /**
+        * The store array for the siblings of this node, including this node itself.
+        */
+       private $store;
+
+       /**
+        * The index into $this->store which contains the descriptor of this node.
+        */
+       private $index;
+
+       /**
+        * The offset of the name within descriptors, used in some places for
+        * readability.
+        */
+       const NAME = 0;
+
+       /**
+        * The offset of the child list within descriptors, used in some places for
+        * readability.
+        */
+       const CHILDREN = 1;
+
+       /**
+        * Construct an object using the data from $store[$index]. The rest of the
+        * store array can be accessed via getNextSibling().
+        *
+        * @param array $store
+        * @param int $index
+        */
+       public function __construct( array $store, $index ) {
+               $this->store = $store;
+               $this->index = $index;
+               list( $this->name, $this->rawChildren ) = $this->store[$index];
+       }
+
+       /**
+        * Construct an appropriate PPNode_Hash_* object with a class that depends
+        * on what is at the relevant store index.
+        *
+        * @param array $store
+        * @param int $index
+        * @return PPNode_Hash_Tree|PPNode_Hash_Attr|PPNode_Hash_Text|false
+        * @throws MWException
+        */
+       public static function factory( array $store, $index ) {
+               if ( !isset( $store[$index] ) ) {
+                       return false;
+               }
+
+               $descriptor = $store[$index];
+               if ( is_string( $descriptor ) ) {
+                       $class = PPNode_Hash_Text::class;
+               } elseif ( is_array( $descriptor ) ) {
+                       if ( $descriptor[self::NAME][0] === '@' ) {
+                               $class = PPNode_Hash_Attr::class;
+                       } else {
+                               $class = self::class;
+                       }
+               } else {
+                       throw new MWException( __METHOD__ . ': invalid node descriptor' );
+               }
+               return new $class( $store, $index );
+       }
+
+       /**
+        * Convert a node to XML, for debugging
+        * @return string
+        */
+       public function __toString() {
+               $inner = '';
+               $attribs = '';
+               for ( $node = $this->getFirstChild(); $node; $node = $node->getNextSibling() ) {
+                       if ( $node instanceof PPNode_Hash_Attr ) {
+                               $attribs .= ' ' . $node->name . '="' . htmlspecialchars( $node->value ) . '"';
+                       } else {
+                               $inner .= $node->__toString();
+                       }
+               }
+               if ( $inner === '' ) {
+                       return "<{$this->name}$attribs/>";
+               } else {
+                       return "<{$this->name}$attribs>$inner</{$this->name}>";
+               }
+       }
+
+       /**
+        * @return PPNode_Hash_Array
+        */
+       public function getChildren() {
+               $children = [];
+               foreach ( $this->rawChildren as $i => $child ) {
+                       $children[] = self::factory( $this->rawChildren, $i );
+               }
+               return new PPNode_Hash_Array( $children );
+       }
+
+       /**
+        * Get the first child, or false if there is none. Note that this will
+        * return a temporary proxy object: different instances will be returned
+        * if this is called more than once on the same node.
+        *
+        * @return PPNode_Hash_Tree|PPNode_Hash_Attr|PPNode_Hash_Text|bool
+        */
+       public function getFirstChild() {
+               if ( !isset( $this->rawChildren[0] ) ) {
+                       return false;
+               } else {
+                       return self::factory( $this->rawChildren, 0 );
+               }
+       }
+
+       /**
+        * Get the next sibling, or false if there is none. Note that this will
+        * return a temporary proxy object: different instances will be returned
+        * if this is called more than once on the same node.
+        *
+        * @return PPNode_Hash_Tree|PPNode_Hash_Attr|PPNode_Hash_Text|bool
+        */
+       public function getNextSibling() {
+               return self::factory( $this->store, $this->index + 1 );
+       }
+
+       /**
+        * Get an array of the children with a given node name
+        *
+        * @param string $name
+        * @return PPNode_Hash_Array
+        */
+       public function getChildrenOfType( $name ) {
+               $children = [];
+               foreach ( $this->rawChildren as $i => $child ) {
+                       if ( is_array( $child ) && $child[self::NAME] === $name ) {
+                               $children[] = self::factory( $this->rawChildren, $i );
+                       }
+               }
+               return new PPNode_Hash_Array( $children );
+       }
+
+       /**
+        * Get the raw child array. For internal use.
+        * @return array
+        */
+       public function getRawChildren() {
+               return $this->rawChildren;
+       }
+
+       /**
+        * @return bool
+        */
+       public function getLength() {
+               return false;
+       }
+
+       /**
+        * @param int $i
+        * @return bool
+        */
+       public function item( $i ) {
+               return false;
+       }
+
+       /**
+        * @return string
+        */
+       public function getName() {
+               return $this->name;
+       }
+
+       /**
+        * Split a "<part>" node into an associative array containing:
+        *  - name          PPNode name
+        *  - index         String index
+        *  - value         PPNode value
+        *
+        * @throws MWException
+        * @return array
+        */
+       public function splitArg() {
+               return self::splitRawArg( $this->rawChildren );
+       }
+
+       /**
+        * Like splitArg() but for a raw child array. For internal use only.
+        * @param array $children
+        * @return array
+        */
+       public static function splitRawArg( array $children ) {
+               $bits = [];
+               foreach ( $children as $i => $child ) {
+                       if ( !is_array( $child ) ) {
+                               continue;
+                       }
+                       if ( $child[self::NAME] === 'name' ) {
+                               $bits['name'] = new self( $children, $i );
+                               if ( isset( $child[self::CHILDREN][0][self::NAME] )
+                                       && $child[self::CHILDREN][0][self::NAME] === '@index'
+                               ) {
+                                       $bits['index'] = $child[self::CHILDREN][0][self::CHILDREN][0];
+                               }
+                       } elseif ( $child[self::NAME] === 'value' ) {
+                               $bits['value'] = new self( $children, $i );
+                       }
+               }
+
+               if ( !isset( $bits['name'] ) ) {
+                       throw new MWException( 'Invalid brace node passed to ' . __METHOD__ );
+               }
+               if ( !isset( $bits['index'] ) ) {
+                       $bits['index'] = '';
+               }
+               return $bits;
+       }
+
+       /**
+        * Split an "<ext>" node into an associative array containing name, attr, inner and close
+        * All values in the resulting array are PPNodes. Inner and close are optional.
+        *
+        * @throws MWException
+        * @return array
+        */
+       public function splitExt() {
+               return self::splitRawExt( $this->rawChildren );
+       }
+
+       /**
+        * Like splitExt() but for a raw child array. For internal use only.
+        * @param array $children
+        * @return array
+        */
+       public static function splitRawExt( array $children ) {
+               $bits = [];
+               foreach ( $children as $i => $child ) {
+                       if ( !is_array( $child ) ) {
+                               continue;
+                       }
+                       switch ( $child[self::NAME] ) {
+                               case 'name':
+                                       $bits['name'] = new self( $children, $i );
+                                       break;
+                               case 'attr':
+                                       $bits['attr'] = new self( $children, $i );
+                                       break;
+                               case 'inner':
+                                       $bits['inner'] = new self( $children, $i );
+                                       break;
+                               case 'close':
+                                       $bits['close'] = new self( $children, $i );
+                                       break;
+                       }
+               }
+               if ( !isset( $bits['name'] ) ) {
+                       throw new MWException( 'Invalid ext node passed to ' . __METHOD__ );
+               }
+               return $bits;
+       }
+
+       /**
+        * Split an "<h>" node
+        *
+        * @throws MWException
+        * @return array
+        */
+       public function splitHeading() {
+               if ( $this->name !== 'h' ) {
+                       throw new MWException( 'Invalid h node passed to ' . __METHOD__ );
+               }
+               return self::splitRawHeading( $this->rawChildren );
+       }
+
+       /**
+        * Like splitHeading() but for a raw child array. For internal use only.
+        * @param array $children
+        * @return array
+        */
+       public static function splitRawHeading( array $children ) {
+               $bits = [];
+               foreach ( $children as $i => $child ) {
+                       if ( !is_array( $child ) ) {
+                               continue;
+                       }
+                       if ( $child[self::NAME] === '@i' ) {
+                               $bits['i'] = $child[self::CHILDREN][0];
+                       } elseif ( $child[self::NAME] === '@level' ) {
+                               $bits['level'] = $child[self::CHILDREN][0];
+                       }
+               }
+               if ( !isset( $bits['i'] ) ) {
+                       throw new MWException( 'Invalid h node passed to ' . __METHOD__ );
+               }
+               return $bits;
+       }
+
+       /**
+        * Split a "<template>" or "<tplarg>" node
+        *
+        * @throws MWException
+        * @return array
+        */
+       public function splitTemplate() {
+               return self::splitRawTemplate( $this->rawChildren );
+       }
+
+       /**
+        * Like splitTemplate() but for a raw child array. For internal use only.
+        * @param array $children
+        * @return array
+        */
+       public static function splitRawTemplate( array $children ) {
+               $parts = [];
+               $bits = [ 'lineStart' => '' ];
+               foreach ( $children as $i => $child ) {
+                       if ( !is_array( $child ) ) {
+                               continue;
+                       }
+                       switch ( $child[self::NAME] ) {
+                               case 'title':
+                                       $bits['title'] = new self( $children, $i );
+                                       break;
+                               case 'part':
+                                       $parts[] = new self( $children, $i );
+                                       break;
+                               case '@lineStart':
+                                       $bits['lineStart'] = '1';
+                                       break;
+                       }
+               }
+               if ( !isset( $bits['title'] ) ) {
+                       throw new MWException( 'Invalid node passed to ' . __METHOD__ );
+               }
+               $bits['parts'] = new PPNode_Hash_Array( $parts );
+               return $bits;
+       }
+}
diff --git a/includes/parser/PPTemplateFrame_DOM.php b/includes/parser/PPTemplateFrame_DOM.php
new file mode 100644 (file)
index 0000000..52cb9cb
--- /dev/null
@@ -0,0 +1,198 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Parser
+ */
+
+/**
+ * Expansion frame with template arguments
+ * @ingroup Parser
+ */
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
+class PPTemplateFrame_DOM extends PPFrame_DOM {
+
+       public $numberedArgs, $namedArgs;
+
+       /**
+        * @var PPFrame_DOM
+        */
+       public $parent;
+       public $numberedExpansionCache, $namedExpansionCache;
+
+       /**
+        * @param Preprocessor $preprocessor
+        * @param bool|PPFrame_DOM $parent
+        * @param array $numberedArgs
+        * @param array $namedArgs
+        * @param bool|Title $title
+        */
+       public function __construct( $preprocessor, $parent = false, $numberedArgs = [],
+               $namedArgs = [], $title = false
+       ) {
+               parent::__construct( $preprocessor );
+
+               $this->parent = $parent;
+               $this->numberedArgs = $numberedArgs;
+               $this->namedArgs = $namedArgs;
+               $this->title = $title;
+               $pdbk = $title ? $title->getPrefixedDBkey() : false;
+               $this->titleCache = $parent->titleCache;
+               $this->titleCache[] = $pdbk;
+               $this->loopCheckHash = /*clone*/ $parent->loopCheckHash;
+               if ( $pdbk !== false ) {
+                       $this->loopCheckHash[$pdbk] = true;
+               }
+               $this->depth = $parent->depth + 1;
+               $this->numberedExpansionCache = $this->namedExpansionCache = [];
+       }
+
+       public function __toString() {
+               $s = 'tplframe{';
+               $first = true;
+               $args = $this->numberedArgs + $this->namedArgs;
+               foreach ( $args as $name => $value ) {
+                       if ( $first ) {
+                               $first = false;
+                       } else {
+                               $s .= ', ';
+                       }
+                       $s .= "\"$name\":\"" .
+                               str_replace( '"', '\\"', $value->ownerDocument->saveXML( $value ) ) . '"';
+               }
+               $s .= '}';
+               return $s;
+       }
+
+       /**
+        * @throws MWException
+        * @param string|int $key
+        * @param string|PPNode_DOM|DOMDocument $root
+        * @param int $flags
+        * @return string
+        */
+       public function cachedExpand( $key, $root, $flags = 0 ) {
+               if ( isset( $this->parent->childExpansionCache[$key] ) ) {
+                       return $this->parent->childExpansionCache[$key];
+               }
+               $retval = $this->expand( $root, $flags );
+               if ( !$this->isVolatile() ) {
+                       $this->parent->childExpansionCache[$key] = $retval;
+               }
+               return $retval;
+       }
+
+       /**
+        * Returns true if there are no arguments in this frame
+        *
+        * @return bool
+        */
+       public function isEmpty() {
+               return !count( $this->numberedArgs ) && !count( $this->namedArgs );
+       }
+
+       public function getArguments() {
+               $arguments = [];
+               foreach ( array_merge(
+                               array_keys( $this->numberedArgs ),
+                               array_keys( $this->namedArgs ) ) as $key ) {
+                       $arguments[$key] = $this->getArgument( $key );
+               }
+               return $arguments;
+       }
+
+       public function getNumberedArguments() {
+               $arguments = [];
+               foreach ( array_keys( $this->numberedArgs ) as $key ) {
+                       $arguments[$key] = $this->getArgument( $key );
+               }
+               return $arguments;
+       }
+
+       public function getNamedArguments() {
+               $arguments = [];
+               foreach ( array_keys( $this->namedArgs ) as $key ) {
+                       $arguments[$key] = $this->getArgument( $key );
+               }
+               return $arguments;
+       }
+
+       /**
+        * @param int $index
+        * @return string|bool
+        */
+       public function getNumberedArgument( $index ) {
+               if ( !isset( $this->numberedArgs[$index] ) ) {
+                       return false;
+               }
+               if ( !isset( $this->numberedExpansionCache[$index] ) ) {
+                       # No trimming for unnamed arguments
+                       $this->numberedExpansionCache[$index] = $this->parent->expand(
+                               $this->numberedArgs[$index],
+                               PPFrame::STRIP_COMMENTS
+                       );
+               }
+               return $this->numberedExpansionCache[$index];
+       }
+
+       /**
+        * @param string $name
+        * @return string|bool
+        */
+       public function getNamedArgument( $name ) {
+               if ( !isset( $this->namedArgs[$name] ) ) {
+                       return false;
+               }
+               if ( !isset( $this->namedExpansionCache[$name] ) ) {
+                       # Trim named arguments post-expand, for backwards compatibility
+                       $this->namedExpansionCache[$name] = trim(
+                               $this->parent->expand( $this->namedArgs[$name], PPFrame::STRIP_COMMENTS ) );
+               }
+               return $this->namedExpansionCache[$name];
+       }
+
+       /**
+        * @param int|string $name
+        * @return string|bool
+        */
+       public function getArgument( $name ) {
+               $text = $this->getNumberedArgument( $name );
+               if ( $text === false ) {
+                       $text = $this->getNamedArgument( $name );
+               }
+               return $text;
+       }
+
+       /**
+        * Return true if the frame is a template frame
+        *
+        * @return bool
+        */
+       public function isTemplate() {
+               return true;
+       }
+
+       public function setVolatile( $flag = true ) {
+               parent::setVolatile( $flag );
+               $this->parent->setVolatile( $flag );
+       }
+
+       public function setTTL( $ttl ) {
+               parent::setTTL( $ttl );
+               $this->parent->setTTL( $ttl );
+       }
+}
diff --git a/includes/parser/PPTemplateFrame_Hash.php b/includes/parser/PPTemplateFrame_Hash.php
new file mode 100644 (file)
index 0000000..df740cf
--- /dev/null
@@ -0,0 +1,202 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Parser
+ */
+
+/**
+ * Expansion frame with template arguments
+ * @ingroup Parser
+ */
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
+class PPTemplateFrame_Hash extends PPFrame_Hash {
+
+       public $numberedArgs, $namedArgs, $parent;
+       public $numberedExpansionCache, $namedExpansionCache;
+
+       /**
+        * @param Preprocessor $preprocessor
+        * @param bool|PPFrame $parent
+        * @param array $numberedArgs
+        * @param array $namedArgs
+        * @param bool|Title $title
+        */
+       public function __construct( $preprocessor, $parent = false, $numberedArgs = [],
+               $namedArgs = [], $title = false
+       ) {
+               parent::__construct( $preprocessor );
+
+               $this->parent = $parent;
+               $this->numberedArgs = $numberedArgs;
+               $this->namedArgs = $namedArgs;
+               $this->title = $title;
+               $pdbk = $title ? $title->getPrefixedDBkey() : false;
+               $this->titleCache = $parent->titleCache;
+               $this->titleCache[] = $pdbk;
+               $this->loopCheckHash = /*clone*/ $parent->loopCheckHash;
+               if ( $pdbk !== false ) {
+                       $this->loopCheckHash[$pdbk] = true;
+               }
+               $this->depth = $parent->depth + 1;
+               $this->numberedExpansionCache = $this->namedExpansionCache = [];
+       }
+
+       public function __toString() {
+               $s = 'tplframe{';
+               $first = true;
+               $args = $this->numberedArgs + $this->namedArgs;
+               foreach ( $args as $name => $value ) {
+                       if ( $first ) {
+                               $first = false;
+                       } else {
+                               $s .= ', ';
+                       }
+                       $s .= "\"$name\":\"" .
+                               str_replace( '"', '\\"', $value->__toString() ) . '"';
+               }
+               $s .= '}';
+               return $s;
+       }
+
+       /**
+        * @throws MWException
+        * @param string|int $key
+        * @param string|PPNode $root
+        * @param int $flags
+        * @return string
+        */
+       public function cachedExpand( $key, $root, $flags = 0 ) {
+               if ( isset( $this->parent->childExpansionCache[$key] ) ) {
+                       return $this->parent->childExpansionCache[$key];
+               }
+               $retval = $this->expand( $root, $flags );
+               if ( !$this->isVolatile() ) {
+                       $this->parent->childExpansionCache[$key] = $retval;
+               }
+               return $retval;
+       }
+
+       /**
+        * Returns true if there are no arguments in this frame
+        *
+        * @return bool
+        */
+       public function isEmpty() {
+               return !count( $this->numberedArgs ) && !count( $this->namedArgs );
+       }
+
+       /**
+        * @return array
+        */
+       public function getArguments() {
+               $arguments = [];
+               foreach ( array_merge(
+                               array_keys( $this->numberedArgs ),
+                               array_keys( $this->namedArgs ) ) as $key ) {
+                       $arguments[$key] = $this->getArgument( $key );
+               }
+               return $arguments;
+       }
+
+       /**
+        * @return array
+        */
+       public function getNumberedArguments() {
+               $arguments = [];
+               foreach ( array_keys( $this->numberedArgs ) as $key ) {
+                       $arguments[$key] = $this->getArgument( $key );
+               }
+               return $arguments;
+       }
+
+       /**
+        * @return array
+        */
+       public function getNamedArguments() {
+               $arguments = [];
+               foreach ( array_keys( $this->namedArgs ) as $key ) {
+                       $arguments[$key] = $this->getArgument( $key );
+               }
+               return $arguments;
+       }
+
+       /**
+        * @param int $index
+        * @return string|bool
+        */
+       public function getNumberedArgument( $index ) {
+               if ( !isset( $this->numberedArgs[$index] ) ) {
+                       return false;
+               }
+               if ( !isset( $this->numberedExpansionCache[$index] ) ) {
+                       # No trimming for unnamed arguments
+                       $this->numberedExpansionCache[$index] = $this->parent->expand(
+                               $this->numberedArgs[$index],
+                               PPFrame::STRIP_COMMENTS
+                       );
+               }
+               return $this->numberedExpansionCache[$index];
+       }
+
+       /**
+        * @param string $name
+        * @return string|bool
+        */
+       public function getNamedArgument( $name ) {
+               if ( !isset( $this->namedArgs[$name] ) ) {
+                       return false;
+               }
+               if ( !isset( $this->namedExpansionCache[$name] ) ) {
+                       # Trim named arguments post-expand, for backwards compatibility
+                       $this->namedExpansionCache[$name] = trim(
+                               $this->parent->expand( $this->namedArgs[$name], PPFrame::STRIP_COMMENTS ) );
+               }
+               return $this->namedExpansionCache[$name];
+       }
+
+       /**
+        * @param int|string $name
+        * @return string|bool
+        */
+       public function getArgument( $name ) {
+               $text = $this->getNumberedArgument( $name );
+               if ( $text === false ) {
+                       $text = $this->getNamedArgument( $name );
+               }
+               return $text;
+       }
+
+       /**
+        * Return true if the frame is a template frame
+        *
+        * @return bool
+        */
+       public function isTemplate() {
+               return true;
+       }
+
+       public function setVolatile( $flag = true ) {
+               parent::setVolatile( $flag );
+               $this->parent->setVolatile( $flag );
+       }
+
+       public function setTTL( $ttl ) {
+               parent::setTTL( $ttl );
+               $this->parent->setTTL( $ttl );
+       }
+}
index 546152f..27c34a6 100644 (file)
  * @file
  * @ingroup Parser
  */
+use MediaWiki\Config\ServiceOptions;
 use MediaWiki\Linker\LinkRenderer;
+use MediaWiki\Linker\LinkRendererFactory;
+use MediaWiki\Linker\LinkTarget;
 use MediaWiki\MediaWikiServices;
 use MediaWiki\Special\SpecialPageFactory;
 use Wikimedia\ScopedCallback;
@@ -167,8 +170,15 @@ class Parser {
         * @var MagicWordArray
         */
        public $mSubstWords;
+
+       /**
+        * @deprecated since 1.34, there should be no need to use this
+        * @var array
+        */
+       public $mConf;
+
        # Initialised in constructor
-       public $mConf, $mExtLinkBracketedRegex, $mUrlProtocols;
+       public $mExtLinkBracketedRegex, $mUrlProtocols;
 
        # Initialized in getPreprocessor()
        /** @var Preprocessor */
@@ -226,12 +236,6 @@ class Parser {
        public $mRevIdForTs;   # The revision ID which was used to fetch the timestamp
        public $mInputSize = false; # For {{PAGESIZE}} on current page.
 
-       /**
-        * @var string Deprecated accessor for the strip marker prefix.
-        * @deprecated since 1.26; use Parser::MARKER_PREFIX instead.
-        */
-       public $mUniqPrefix = self::MARKER_PREFIX;
-
        /**
         * @var array Array with the language name of each language link (i.e. the
         * interwiki prefix) in the key, value arbitrary. Used to avoid sending
@@ -273,45 +277,100 @@ class Parser {
        /** @var SpecialPageFactory */
        private $specialPageFactory;
 
-       /** @var Config */
-       private $siteConfig;
+       /**
+        * This is called $svcOptions instead of $options like elsewhere to avoid confusion with
+        * $mOptions, which is public and widely used, and also with the local variable $options used
+        * for ParserOptions throughout this file.
+        *
+        * @var ServiceOptions
+        */
+       private $svcOptions;
+
+       /** @var LinkRendererFactory */
+       private $linkRendererFactory;
+
+       /** @var NamespaceInfo */
+       private $nsInfo;
+
+       /**
+        * TODO Make this a const when HHVM support is dropped (T192166)
+        *
+        * @var array
+        * @since 1.33
+        */
+       public static $constructorOptions = [
+               // See $wgParserConf documentation
+               'class',
+               'preprocessorClass',
+               // See documentation for the corresponding config options
+               'ArticlePath',
+               'EnableScaryTranscluding',
+               'ExtraInterlanguageLinkPrefixes',
+               'FragmentMode',
+               'LanguageCode',
+               'MaxSigChars',
+               'MaxTocLevel',
+               'MiserMode',
+               'ScriptPath',
+               'Server',
+               'ServerName',
+               'ShowHostnames',
+               'Sitename',
+               'StylePath',
+               'TranscludeCacheExpiry',
+       ];
 
        /**
-        * @param array $parserConf See $wgParserConf documentation
+        * Constructing parsers directly is deprecated! Use a ParserFactory.
+        *
+        * @param ServiceOptions|null $svcOptions
         * @param MagicWordFactory|null $magicWordFactory
         * @param Language|null $contLang Content language
         * @param ParserFactory|null $factory
         * @param string|null $urlProtocols As returned from wfUrlProtocols()
         * @param SpecialPageFactory|null $spFactory
-        * @param Config|null $siteConfig
+        * @param LinkRendererFactory|null $linkRendererFactory
+        * @param NamespaceInfo|null $nsInfo
         */
        public function __construct(
-               array $parserConf = [], MagicWordFactory $magicWordFactory = null,
+               $svcOptions = null, MagicWordFactory $magicWordFactory = null,
                Language $contLang = null, ParserFactory $factory = null, $urlProtocols = null,
-               SpecialPageFactory $spFactory = null, Config $siteConfig = null
+               SpecialPageFactory $spFactory = null, $linkRendererFactory = null, $nsInfo = null
        ) {
-               $this->mConf = $parserConf;
+               $services = MediaWikiServices::getInstance();
+               if ( !$svcOptions || is_array( $svcOptions ) ) {
+                       // Pre-1.34 calling convention is the first parameter is just ParserConf, the seventh is
+                       // Config, and the eighth is LinkRendererFactory.
+                       $this->mConf = (array)$svcOptions;
+                       if ( empty( $this->mConf['class'] ) ) {
+                               $this->mConf['class'] = self::class;
+                       }
+                       if ( empty( $this->mConf['preprocessorClass'] ) ) {
+                               $this->mConf['preprocessorClass'] = self::getDefaultPreprocessorClass();
+                       }
+                       $this->svcOptions = new ServiceOptions( self::$constructorOptions,
+                               $this->mConf,
+                               func_num_args() > 6 ? func_get_arg( 6 ) : $services->getMainConfig()
+                       );
+                       $linkRendererFactory = func_num_args() > 7 ? func_get_arg( 7 ) : null;
+                       $nsInfo = func_num_args() > 8 ? func_get_arg( 8 ) : null;
+               } else {
+                       // New calling convention
+                       $svcOptions->assertRequiredOptions( self::$constructorOptions );
+                       // $this->mConf is public, so we'll keep those two options there as well for
+                       // compatibility until it's removed
+                       $this->mConf = [
+                               'class' => $svcOptions->get( 'class' ),
+                               'preprocessorClass' => $svcOptions->get( 'preprocessorClass' ),
+                       ];
+                       $this->svcOptions = $svcOptions;
+               }
+
                $this->mUrlProtocols = $urlProtocols ?? wfUrlProtocols();
                $this->mExtLinkBracketedRegex = '/\[(((?i)' . $this->mUrlProtocols . ')' .
                        self::EXT_LINK_ADDR .
                        self::EXT_LINK_URL_CLASS . '*)\p{Zs}*([^\]\\x00-\\x08\\x0a-\\x1F\\x{FFFD}]*?)\]/Su';
-               if ( isset( $parserConf['preprocessorClass'] ) ) {
-                       $this->mPreprocessorClass = $parserConf['preprocessorClass'];
-               } elseif ( wfIsHHVM() ) {
-                       # Under HHVM Preprocessor_Hash is much faster than Preprocessor_DOM
-                       $this->mPreprocessorClass = Preprocessor_Hash::class;
-               } elseif ( extension_loaded( 'domxml' ) ) {
-                       # PECL extension that conflicts with the core DOM extension (T15770)
-                       wfDebug( "Warning: you have the obsolete domxml extension for PHP. Please remove it!\n" );
-                       $this->mPreprocessorClass = Preprocessor_Hash::class;
-               } elseif ( extension_loaded( 'dom' ) ) {
-                       $this->mPreprocessorClass = Preprocessor_DOM::class;
-               } else {
-                       $this->mPreprocessorClass = Preprocessor_Hash::class;
-               }
-               wfDebug( __CLASS__ . ": using preprocessor: {$this->mPreprocessorClass}\n" );
 
-               $services = MediaWikiServices::getInstance();
                $this->magicWordFactory = $magicWordFactory ??
                        $services->getMagicWordFactory();
 
@@ -319,7 +378,8 @@ class Parser {
 
                $this->factory = $factory ?? $services->getParserFactory();
                $this->specialPageFactory = $spFactory ?? $services->getSpecialPageFactory();
-               $this->siteConfig = $siteConfig ?? MediaWikiServices::getInstance()->getMainConfig();
+               $this->linkRendererFactory = $linkRendererFactory ?? $services->getLinkRendererFactory();
+               $this->nsInfo = $nsInfo ?? $services->getNamespaceInfo();
        }
 
        /**
@@ -357,6 +417,28 @@ class Parser {
                Hooks::run( 'ParserCloned', [ $this ] );
        }
 
+       /**
+        * Which class should we use for the preprocessor if not otherwise specified?
+        *
+        * @since 1.34
+        * @return string
+        */
+       public static function getDefaultPreprocessorClass() {
+               if ( wfIsHHVM() ) {
+                       # Under HHVM Preprocessor_Hash is much faster than Preprocessor_DOM
+                       return Preprocessor_Hash::class;
+               }
+               if ( extension_loaded( 'domxml' ) ) {
+                       # PECL extension that conflicts with the core DOM extension (T15770)
+                       wfDebug( "Warning: you have the obsolete domxml extension for PHP. Please remove it!\n" );
+                       return Preprocessor_Hash::class;
+               }
+               if ( extension_loaded( 'dom' ) ) {
+                       return Preprocessor_DOM::class;
+               }
+               return Preprocessor_Hash::class;
+       }
+
        /**
         * Do various kinds of initialisation on the first call of the parser
         */
@@ -588,7 +670,7 @@ class Parser {
                Hooks::run( 'ParserLimitReportPrepare', [ $this, $this->mOutput ] );
 
                $limitReport = "NewPP limit report\n";
-               if ( $this->siteConfig->get( 'ShowHostnames' ) ) {
+               if ( $this->svcOptions->get( 'ShowHostnames' ) ) {
                        $limitReport .= 'Parsed by ' . wfHostname() . "\n";
                }
                $limitReport .= 'Cached time: ' . $this->mOutput->getCacheTime() . "\n";
@@ -639,7 +721,7 @@ class Parser {
                $this->mOutput->setLimitReportData( 'limitreport-timingprofile', $profileReport );
 
                // Add other cache related metadata
-               if ( $this->siteConfig->get( 'ShowHostnames' ) ) {
+               if ( $this->svcOptions->get( 'ShowHostnames' ) ) {
                        $this->mOutput->setLimitReportData( 'cachereport-origin', wfHostname() );
                }
                $this->mOutput->setLimitReportData( 'cachereport-timestamp',
@@ -960,7 +1042,7 @@ class Parser {
         */
        public function getPreprocessor() {
                if ( !isset( $this->mPreprocessor ) ) {
-                       $class = $this->mPreprocessorClass;
+                       $class = $this->svcOptions->get( 'preprocessorClass' );
                        $this->mPreprocessor = new $class( $this );
                }
                return $this->mPreprocessor;
@@ -973,9 +1055,9 @@ class Parser {
         * @return LinkRenderer
         */
        public function getLinkRenderer() {
+               // XXX We make the LinkRenderer with current options and then cache it forever
                if ( !$this->mLinkRenderer ) {
-                       $this->mLinkRenderer = MediaWikiServices::getInstance()
-                               ->getLinkRendererFactory()->create();
+                       $this->mLinkRenderer = $this->linkRendererFactory->create();
                        $this->mLinkRenderer->setStubThreshold(
                                $this->getOptions()->getStubThreshold()
                        );
@@ -1045,10 +1127,7 @@ class Parser {
                                $inside = $p[5];
                        } else {
                                # tag
-                               $element = $p[1];
-                               $attributes = $p[2];
-                               $close = $p[3];
-                               $inside = $p[4];
+                               list( , $element, $attributes, $close, $inside ) = $p;
                        }
 
                        $marker = self::MARKER_PREFIX . "-$element-" . sprintf( '%08X', $n++ ) . self::MARKER_SUFFIX;
@@ -1072,8 +1151,7 @@ class Parser {
                                        $tail = '';
                                        $text = '';
                                } else {
-                                       $tail = $q[1];
-                                       $text = $q[2];
+                                       list( , $tail, $text ) = $q;
                                }
                        }
 
@@ -1425,13 +1503,12 @@ class Parser {
                 */
                if ( !( $this->mOptions->getDisableContentConversion()
                        || isset( $this->mDoubleUnderscores['nocontentconvert'] ) )
+                       && !$this->mOptions->getInterfaceMessage()
                ) {
-                       if ( !$this->mOptions->getInterfaceMessage() ) {
-                               # The position of the convert() call should not be changed. it
-                               # assumes that the links are all replaced and the only thing left
-                               # is the <nowiki> mark.
-                               $text = $this->getTargetLanguage()->convert( $text );
-                       }
+                       # The position of the convert() call should not be changed. it
+                       # assumes that the links are all replaced and the only thing left
+                       # is the <nowiki> mark.
+                       $text = $this->getTargetLanguage()->convert( $text );
                }
 
                $text = $this->mStripState->unstripNoWiki( $text );
@@ -1771,10 +1848,8 @@ class Parser {
                                                // if $firstsingleletterword is set, we don't
                                                // look at the other options, so we can bail early.
                                                break;
-                                       } else {
-                                               if ( $firstmultiletterword == -1 ) {
-                                                       $firstmultiletterword = $i;
-                                               }
+                                       } elseif ( $firstmultiletterword == -1 ) {
+                                               $firstmultiletterword = $i;
                                        }
                                }
                        }
@@ -1973,7 +2048,7 @@ class Parser {
         * @since 1.21
         * @param string|bool $url Optional URL, to extract the domain from for rel =>
         *   nofollow if appropriate
-        * @param Title|null $title Optional Title, for wgNoFollowNsExceptions lookups
+        * @param LinkTarget|null $title Optional LinkTarget, for wgNoFollowNsExceptions lookups
         * @return string|null Rel attribute for $url
         */
        public static function getExternalLinkRel( $url = false, $title = null ) {
@@ -2240,8 +2315,7 @@ class Parser {
 
                        if ( $useLinkPrefixExtension ) {
                                if ( preg_match( $e2, $s, $m ) ) {
-                                       $prefix = $m[2];
-                                       $s = $m[1];
+                                       list( , $s, $prefix ) = $m;
                                } else {
                                        $prefix = '';
                                }
@@ -2385,7 +2459,7 @@ class Parser {
                                if (
                                        $iw && $this->mOptions->getInterwikiMagic() && $nottalk && (
                                                Language::fetchLanguageName( $iw, null, 'mw' ) ||
-                                               in_array( $iw, $this->siteConfig->get( 'ExtraInterlanguageLinkPrefixes' ) )
+                                               in_array( $iw, $this->svcOptions->get( 'ExtraInterlanguageLinkPrefixes' ) )
                                        )
                                ) {
                                        # T26502: filter duplicates
@@ -2528,7 +2602,7 @@ class Parser {
         */
        public function areSubpagesAllowed() {
                # Some namespaces don't allow subpages
-               return MWNamespace::hasSubpages( $this->mTitle->getNamespace() );
+               return $this->nsInfo->hasSubpages( $this->mTitle->getNamespace() );
        }
 
        /**
@@ -2583,10 +2657,11 @@ class Parser {
                 * Some of these require message or data lookups and can be
                 * expensive to check many times.
                 */
-               if ( Hooks::run( 'ParserGetVariableValueVarCache', [ &$parser, &$this->mVarCache ] ) ) {
-                       if ( isset( $this->mVarCache[$index] ) ) {
-                               return $this->mVarCache[$index];
-                       }
+               if (
+                       Hooks::run( 'ParserGetVariableValueVarCache', [ &$parser, &$this->mVarCache ] ) &&
+                       isset( $this->mVarCache[$index] )
+               ) {
+                       return $this->mVarCache[$index];
                }
 
                $ts = wfTimestamp( TS_UNIX, $this->mOptions->getTimestamp() );
@@ -2715,23 +2790,35 @@ class Parser {
                                $value = $pageid ?: null;
                                break;
                        case 'revisionid':
-                               # Let the edit saving system know we should parse the page
-                               # *after* a revision ID has been assigned.
-                               $this->mOutput->setFlag( 'vary-revision-id' );
-                               wfDebug( __METHOD__ . ": {{REVISIONID}} used, setting vary-revision-id...\n" );
-                               $value = $this->mRevisionId;
-
-                               if ( !$value ) {
-                                       $rev = $this->getRevisionObject();
-                                       if ( $rev ) {
-                                               $value = $rev->getId();
+                               if (
+                                       $this->svcOptions->get( 'MiserMode' ) &&
+                                       !$this->mOptions->getInterfaceMessage() &&
+                                       // @TODO: disallow this word on all namespaces
+                                       $this->nsInfo->isContent( $this->mTitle->getNamespace() )
+                               ) {
+                                       // Use a stub result instead of the actual revision ID in order to avoid
+                                       // double parses on page save but still allow preview detection (T137900)
+                                       if ( $this->getRevisionId() || $this->mOptions->getSpeculativeRevId() ) {
+                                               $value = '-';
+                                       } else {
+                                               $this->mOutput->setFlag( 'vary-revision-exists' );
+                                               $value = '';
                                        }
-                               }
-
-                               if ( !$value ) {
-                                       $value = $this->mOptions->getSpeculativeRevId();
-                                       if ( $value ) {
-                                               $this->mOutput->setSpeculativeRevIdUsed( $value );
+                               } else {
+                                       # Inform the edit saving system that getting the canonical output after
+                                       # revision insertion requires another parse using the actual revision ID
+                                       $this->mOutput->setFlag( 'vary-revision-id' );
+                                       wfDebug( __METHOD__ . ": {{REVISIONID}} used, setting vary-revision-id...\n" );
+                                       $value = $this->getRevisionId();
+                                       if ( $value === 0 ) {
+                                               $rev = $this->getRevisionObject();
+                                               $value = $rev ? $rev->getId() : $value;
+                                       }
+                                       if ( !$value ) {
+                                               $value = $this->mOptions->getSpeculativeRevId();
+                                               if ( $value ) {
+                                                       $this->mOutput->setSpeculativeRevIdUsed( $value );
+                                               }
                                        }
                                }
                                break;
@@ -2868,21 +2955,21 @@ class Parser {
                                $value = SpecialVersion::getVersion();
                                break;
                        case 'articlepath':
-                               return $this->siteConfig->get( 'ArticlePath' );
+                               return $this->svcOptions->get( 'ArticlePath' );
                        case 'sitename':
-                               return $this->siteConfig->get( 'Sitename' );
+                               return $this->svcOptions->get( 'Sitename' );
                        case 'server':
-                               return $this->siteConfig->get( 'Server' );
+                               return $this->svcOptions->get( 'Server' );
                        case 'servername':
-                               return $this->siteConfig->get( 'ServerName' );
+                               return $this->svcOptions->get( 'ServerName' );
                        case 'scriptpath':
-                               return $this->siteConfig->get( 'ScriptPath' );
+                               return $this->svcOptions->get( 'ScriptPath' );
                        case 'stylepath':
-                               return $this->siteConfig->get( 'StylePath' );
+                               return $this->svcOptions->get( 'StylePath' );
                        case 'directionmark':
                                return $pageLang->getDirMark();
                        case 'contentlanguage':
-                               return $this->siteConfig->get( 'LanguageCode' );
+                               return $this->svcOptions->get( 'LanguageCode' );
                        case 'pagelanguage':
                                $value = $pageLang->getCode();
                                break;
@@ -3326,7 +3413,7 @@ class Parser {
                                                        );
                                                }
                                        }
-                               } elseif ( MWNamespace::isNonincludable( $title->getNamespace() ) ) {
+                               } elseif ( $this->nsInfo->isNonincludable( $title->getNamespace() ) ) {
                                        $found = false; # access denied
                                        wfDebug( __METHOD__ . ": template inclusion denied for " .
                                                $title->getPrefixedDBkey() . "\n" );
@@ -3824,7 +3911,7 @@ class Parser {
         * @return string
         */
        public function interwikiTransclude( $title, $action ) {
-               if ( !$this->siteConfig->get( 'EnableScaryTranscluding' ) ) {
+               if ( !$this->svcOptions->get( 'EnableScaryTranscluding' ) ) {
                        return wfMessage( 'scarytranscludedisabled' )->inContentLanguage()->text();
                }
 
@@ -3844,7 +3931,7 @@ class Parser {
                                ( $wikiId !== false ) ? $wikiId : 'external',
                                sha1( $url )
                        ),
-                       $this->siteConfig->get( 'TranscludeCacheExpiry' ),
+                       $this->svcOptions->get( 'TranscludeCacheExpiry' ),
                        function ( $oldValue, &$ttl ) use ( $url, $fname, $cache ) {
                                $req = MWHttpRequest::factory( $url, [], $fname );
 
@@ -4216,7 +4303,7 @@ class Parser {
 
                $headlines = $numMatches !== false ? $matches[3] : [];
 
-               $maxTocLevel = $this->siteConfig->get( 'MaxTocLevel' );
+               $maxTocLevel = $this->svcOptions->get( 'MaxTocLevel' );
                foreach ( $headlines as $headline ) {
                        $isTemplate = false;
                        $titleText = false;
@@ -4648,7 +4735,7 @@ class Parser {
         * If you have pre-fetched the nickname or the fancySig option, you can
         * specify them here to save a database query.
         * Do not reuse this parser instance after calling getUserSig(),
-        * as it may have changed if it's the $wgParser.
+        * as it may have changed.
         *
         * @param User &$user
         * @param string|bool $nickname Nickname to use or false to use user's default nickname
@@ -4670,7 +4757,7 @@ class Parser {
 
                $nickname = $nickname == null ? $username : $nickname;
 
-               if ( mb_strlen( $nickname ) > $this->siteConfig->get( 'MaxSigChars' ) ) {
+               if ( mb_strlen( $nickname ) > $this->svcOptions->get( 'MaxSigChars' ) ) {
                        $nickname = $username;
                        wfDebug( __METHOD__ . ": $username has overlong signature.\n" );
                } elseif ( $fancySig !== false ) {
@@ -5360,10 +5447,8 @@ class Parser {
                                                                        if ( $paramName === 'no-link' ) {
                                                                                $value = true;
                                                                        }
-                                                                       if ( $paramName === 'link-url' ) {
-                                                                               if ( $this->mOptions->getExternalLinkTarget() ) {
-                                                                                       $params[$type]['link-target'] = $this->mOptions->getExternalLinkTarget();
-                                                                               }
+                                                                       if ( ( $paramName === 'link-url' ) && $this->mOptions->getExternalLinkTarget() ) {
+                                                                               $params[$type]['link-target'] = $this->mOptions->getExternalLinkTarget();
                                                                        }
                                                                }
                                                                break;
@@ -5704,15 +5789,15 @@ class Parser {
                        if ( $sectionIndex == 0 ) {
                                if ( $mode === 'get' ) {
                                        return '';
-                               } else {
-                                       return $newText;
                                }
+
+                               return $newText;
                        } else {
                                if ( $mode === 'get' ) {
                                        return $newText;
-                               } else {
-                                       return $text;
                                }
+
+                               return $text;
                        }
                }
 
@@ -5828,6 +5913,11 @@ class Parser {
        /**
         * Get the ID of the revision we are parsing
         *
+        * The return value will be either:
+        *   - a) Positive, indicating a specific revision ID (current or old)
+        *   - b) Zero, meaning the revision ID specified by getCurrentRevisionCallback()
+        *   - c) Null, meaning the parse is for preview mode and there is no revision
+        *
         * @return int|null
         */
        public function getRevisionId() {
@@ -5988,7 +6078,7 @@ class Parser {
        }
 
        private function makeLegacyAnchor( $sectionName ) {
-               $fragmentMode = $this->siteConfig->get( 'FragmentMode' );
+               $fragmentMode = $this->svcOptions->get( 'FragmentMode' );
                if ( isset( $fragmentMode[1] ) && $fragmentMode[1] === 'legacy' ) {
                        // ForAttribute() and ForLink() are the same for legacy encoding
                        $id = Sanitizer::escapeIdForAttribute( $sectionName, Sanitizer::ID_FALLBACK );
@@ -6327,10 +6417,8 @@ class Parser {
         */
        public static function stripOuterParagraph( $html ) {
                $m = [];
-               if ( preg_match( '/^<p>(.*)\n?<\/p>\n?$/sU', $html, $m ) ) {
-                       if ( strpos( $m[1], '</p>' ) === false ) {
-                               $html = $m[1];
-                       }
+               if ( preg_match( '/^<p>(.*)\n?<\/p>\n?$/sU', $html, $m ) && strpos( $m[1], '</p>' ) === false ) {
+                       $html = $m[1];
                }
 
                return $html;
@@ -6339,9 +6427,9 @@ class Parser {
        /**
         * Return this parser if it is not doing anything, otherwise
         * get a fresh parser. You can use this method by doing
-        * $myParser = $wgParser->getFreshParser(), or more simply
-        * $wgParser->getFreshParser()->parse( ... );
-        * if you're unsure if $wgParser is safe to use.
+        * $newParser = $oldParser->getFreshParser(), or more simply
+        * $oldParser->getFreshParser()->parse( ... );
+        * if you're unsure if $oldParser is safe to use.
         *
         * @since 1.24
         * @return Parser A parser object that is not parsing anything
index 8e8cd98..2585872 100644 (file)
@@ -57,6 +57,7 @@ class ParserCache {
         * @var string
         */
        private $cacheEpoch;
+
        /**
         * Get an instance of this object
         *
index eb05ace..0446d9c 100644 (file)
  * @ingroup Parser
  */
 
+use MediaWiki\Config\ServiceOptions;
+use MediaWiki\Linker\LinkRendererFactory;
+use MediaWiki\MediaWikiServices;
 use MediaWiki\Special\SpecialPageFactory;
 
 /**
  * @since 1.32
  */
 class ParserFactory {
-       /** @var array */
-       private $parserConf;
+       /** @var ServiceOptions */
+       private $svcOptions;
 
        /** @var MagicWordFactory */
        private $magicWordFactory;
@@ -40,28 +43,70 @@ class ParserFactory {
        /** @var SpecialPageFactory */
        private $specialPageFactory;
 
-       /** @var Config */
-       private $siteConfig;
+       /** @var LinkRendererFactory */
+       private $linkRendererFactory;
+
+       /** @var NamespaceInfo */
+       private $nsInfo;
 
        /**
-        * @param array $parserConf See $wgParserConf documentation
+        * Old parameter list, which we support for backwards compatibility, were:
+        *   array $parserConf See $wgParserConf documentation
+        *   MagicWordFactory $magicWordFactory
+        *   Language $contLang Content language
+        *   string $urlProtocols As returned from wfUrlProtocols()
+        *   SpecialPageFactory $spFactory
+        *   Config $siteConfig
+        *   LinkRendererFactory $linkRendererFactory
+        *   NamespaceInfo|null $nsInfo
+        *
+        * Some type declarations were intentionally omitted so that the backwards compatibility code
+        * would work. When backwards compatibility is no longer required, we should remove it, and
+        * and add the omitted type declarations.
+        *
+        * @param ServiceOptions|array $svcOptions
         * @param MagicWordFactory $magicWordFactory
         * @param Language $contLang Content language
         * @param string $urlProtocols As returned from wfUrlProtocols()
         * @param SpecialPageFactory $spFactory
-        * @param Config $siteConfig
+        * @param LinkRendererFactory $linkRendererFactory
+        * @param NamespaceInfo|LinkRendererFactory|null $nsInfo
         * @since 1.32
         */
        public function __construct(
-               array $parserConf, MagicWordFactory $magicWordFactory, Language $contLang, $urlProtocols,
-               SpecialPageFactory $spFactory, Config $siteConfig
+               $svcOptions, MagicWordFactory $magicWordFactory, Language $contLang,
+               $urlProtocols, SpecialPageFactory $spFactory, $linkRendererFactory,
+               $nsInfo = null
        ) {
-               $this->parserConf = $parserConf;
+               // @todo Do we need to retain compat for constructing this class directly?
+               if ( !$nsInfo ) {
+                       wfDeprecated( __METHOD__ . ' with no NamespaceInfo argument', '1.34' );
+                       $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
+               }
+               if ( $linkRendererFactory instanceof Config ) {
+                       // Old calling convention had an array in the format of $wgParserConf as the first
+                       // parameter, and a Config as the sixth, with LinkRendererFactory as the seventh.
+                       wfDeprecated( __METHOD__ . ' with Config parameter', '1.34' );
+                       $svcOptions = new ServiceOptions( Parser::$constructorOptions,
+                               $svcOptions,
+                               [ 'class' => Parser::class,
+                                       'preprocessorClass' => Parser::getDefaultPreprocessorClass() ],
+                               func_get_arg( 5 )
+                       );
+                       $linkRendererFactory = func_get_arg( 6 );
+                       $nsInfo = func_num_args() > 7 ? func_get_arg( 7 ) : null;
+               }
+               $svcOptions->assertRequiredOptions( Parser::$constructorOptions );
+
+               wfDebug( __CLASS__ . ": using preprocessor: {$svcOptions->get( 'preprocessorClass' )}\n" );
+
+               $this->svcOptions = $svcOptions;
                $this->magicWordFactory = $magicWordFactory;
                $this->contLang = $contLang;
                $this->urlProtocols = $urlProtocols;
                $this->specialPageFactory = $spFactory;
-               $this->siteConfig = $siteConfig;
+               $this->linkRendererFactory = $linkRendererFactory;
+               $this->nsInfo = $nsInfo;
        }
 
        /**
@@ -69,7 +114,8 @@ class ParserFactory {
         * @since 1.32
         */
        public function create() : Parser {
-               return new Parser( $this->parserConf, $this->magicWordFactory, $this->contLang, $this,
-                       $this->urlProtocols, $this->specialPageFactory, $this->siteConfig );
+               return new Parser( $this->svcOptions, $this->magicWordFactory, $this->contLang, $this,
+                       $this->urlProtocols, $this->specialPageFactory, $this->linkRendererFactory,
+                       $this->nsInfo );
        }
 }
index bdca848..66b1612 100644 (file)
@@ -123,7 +123,7 @@ class ParserOptions {
         */
 
        /**
-        * Fetch an option, generically
+        * Fetch an option and track that is was accessed
         * @since 1.30
         * @param string $name Option name
         * @return mixed
@@ -133,15 +133,22 @@ class ParserOptions {
                        throw new InvalidArgumentException( "Unknown parser option $name" );
                }
 
-               if ( isset( self::$lazyOptions[$name] ) && $this->options[$name] === null ) {
-                       $this->options[$name] = call_user_func( self::$lazyOptions[$name], $this, $name );
-               }
+               $this->lazyLoadOption( $name );
                if ( !empty( self::$inCacheKey[$name] ) ) {
                        $this->optionUsed( $name );
                }
                return $this->options[$name];
        }
 
+       /**
+        * @param string $name Lazy load option without tracking usage
+        */
+       private function lazyLoadOption( $name ) {
+               if ( isset( self::$lazyOptions[$name] ) && $this->options[$name] === null ) {
+                       $this->options[$name] = call_user_func( self::$lazyOptions[$name], $this, $name );
+               }
+       }
+
        /**
         * Set an option, generically
         * @since 1.30
@@ -1197,22 +1204,16 @@ class ParserOptions {
         * @since 1.25
         */
        public function matches( ParserOptions $other ) {
-               // Populate lazy options
-               foreach ( self::$lazyOptions as $name => $callback ) {
-                       if ( $this->options[$name] === null ) {
-                               $this->options[$name] = call_user_func( $callback, $this, $name );
-                       }
-                       if ( $other->options[$name] === null ) {
-                               $other->options[$name] = call_user_func( $callback, $other, $name );
-                       }
-               }
-
                // Compare most options
                $options = array_keys( $this->options );
                $options = array_diff( $options, [
                        'enableLimitReport', // only affects HTML comments
                ] );
                foreach ( $options as $option ) {
+                       // Resolve any lazy options
+                       $this->lazyLoadOption( $option );
+                       $other->lazyLoadOption( $option );
+
                        $o1 = $this->optionToString( $this->options[$option] );
                        $o2 = $this->optionToString( $other->options[$option] );
                        if ( $o1 !== $o2 ) {
@@ -1238,6 +1239,27 @@ class ParserOptions {
                return true;
        }
 
+       /**
+        * @param ParserOptions $other
+        * @return bool Whether the cache key relevant options match those of $other
+        * @since 1.33
+        */
+       public function matchesForCacheKey( ParserOptions $other ) {
+               foreach ( self::allCacheVaryingOptions() as $option ) {
+                       // Populate any lazy options
+                       $this->lazyLoadOption( $option );
+                       $other->lazyLoadOption( $option );
+
+                       $o1 = $this->optionToString( $this->options[$option] );
+                       $o2 = $this->optionToString( $other->options[$option] );
+                       if ( $o1 !== $o2 ) {
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+
        /**
         * Registers a callback for tracking which ParserOptions which are used.
         * This is a private API with the parser.
@@ -1314,10 +1336,9 @@ class ParserOptions {
                $inCacheKey = self::allCacheVaryingOptions();
 
                // Resolve any lazy options
-               foreach ( array_intersect( $forOptions, $inCacheKey, array_keys( self::$lazyOptions ) ) as $k ) {
-                       if ( $this->options[$k] === null ) {
-                               $this->options[$k] = call_user_func( self::$lazyOptions[$k], $this, $k );
-                       }
+               $lazyOpts = array_intersect( $forOptions, $inCacheKey, array_keys( self::$lazyOptions ) );
+               foreach ( $lazyOpts as $k ) {
+                       $this->lazyLoadOption( $k );
                }
 
                $options = $this->options;
index f2aaeed..ef22a1f 100644 (file)
@@ -42,7 +42,7 @@ class ParserOutput extends CacheTime {
        public $mLanguageLinks;
 
        /**
-        * @var array $mCategoriesMap of category names to sort keys
+        * @var array $mCategories Map of category names to sort keys
         */
        public $mCategories;
 
@@ -471,14 +471,6 @@ class ParserOutput extends CacheTime {
                return $this->mSections;
        }
 
-       /**
-        * @deprecated since 1.31 Use getText() options.
-        */
-       public function getEditSectionTokens() {
-               wfDeprecated( __METHOD__, '1.31' );
-               return true;
-       }
-
        public function &getLinks() {
                return $this->mLinks;
        }
@@ -506,6 +498,7 @@ class ParserOutput extends CacheTime {
        public function setNoGallery( $value ) {
                $this->mNoGallery = (bool)$value;
        }
+
        public function getNoGallery() {
                return $this->mNoGallery;
        }
@@ -518,11 +511,6 @@ class ParserOutput extends CacheTime {
                return $this->mModules;
        }
 
-       public function getModuleScripts() {
-               wfDeprecated( __METHOD__, '1.33' );
-               return [];
-       }
-
        public function getModuleStyles() {
                return $this->mModuleStyles;
        }
@@ -566,14 +554,6 @@ class ParserOutput extends CacheTime {
                return $this->mLimitReportJSData;
        }
 
-       /**
-        * @deprecated since 1.31 Use getText() options.
-        */
-       public function getTOCEnabled() {
-               wfDeprecated( __METHOD__, '1.31' );
-               return true;
-       }
-
        public function getEnableOOUI() {
                return $this->mEnableOOUI;
        }
@@ -598,14 +578,6 @@ class ParserOutput extends CacheTime {
                return wfSetVar( $this->mSections, $toc );
        }
 
-       /**
-        * @deprecated since 1.31 Use getText() options.
-        */
-       public function setEditSectionTokens( $t ) {
-               wfDeprecated( __METHOD__, '1.31' );
-               return true;
-       }
-
        public function setIndexPolicy( $policy ) {
                return wfSetVar( $this->mIndexPolicy, $policy );
        }
@@ -618,14 +590,6 @@ class ParserOutput extends CacheTime {
                return wfSetVar( $this->mTimestamp, $timestamp );
        }
 
-       /**
-        * @deprecated since 1.31 Use getText() options.
-        */
-       public function setTOCEnabled( $flag ) {
-               wfDeprecated( __METHOD__, '1.31' );
-               return true;
-       }
-
        public function addCategory( $c, $sort ) {
                $this->mCategories[$c] = $sort;
        }
@@ -665,12 +629,15 @@ class ParserOutput extends CacheTime {
        public function setNewSection( $value ) {
                $this->mNewSection = (bool)$value;
        }
+
        public function hideNewSection( $value ) {
                $this->mHideNewSection = (bool)$value;
        }
+
        public function getHideNewSection() {
                return (bool)$this->mHideNewSection;
        }
+
        public function getNewSection() {
                return (bool)$this->mNewSection;
        }
index b6084d8..b321078 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 use MediaWiki\Logger\LoggerFactory;
+use MediaWiki\MediaWikiServices;
 
 /**
  * @ingroup Parser
@@ -73,10 +74,12 @@ abstract class Preprocessor {
                        return;
                }
 
-               $cache = ObjectCache::getLocalClusterInstance();
+               $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
                $key = $cache->makeKey(
                        defined( 'static::CACHE_PREFIX' ) ? static::CACHE_PREFIX : static::class,
-                       md5( $text ), $flags );
+                       md5( $text ),
+                       $flags
+               );
                $value = sprintf( "%08d", static::CACHE_VERSION ) . $tree;
 
                $cache->set( $key, $value, 86400 );
@@ -102,11 +105,13 @@ abstract class Preprocessor {
                        return false;
                }
 
-               $cache = ObjectCache::getLocalClusterInstance();
+               $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
 
                $key = $cache->makeKey(
                        defined( 'static::CACHE_PREFIX' ) ? static::CACHE_PREFIX : static::class,
-                       md5( $text ), $flags );
+                       md5( $text ),
+                       $flags
+               );
 
                $value = $cache->get( $key );
                if ( !$value ) {
@@ -159,279 +164,3 @@ abstract class Preprocessor {
         */
        abstract public function preprocessToObj( $text, $flags = 0 );
 }
-
-/**
- * @ingroup Parser
- */
-interface PPFrame {
-       const NO_ARGS = 1;
-       const NO_TEMPLATES = 2;
-       const STRIP_COMMENTS = 4;
-       const NO_IGNORE = 8;
-       const RECOVER_COMMENTS = 16;
-       const NO_TAGS = 32;
-
-       const RECOVER_ORIG = self::NO_ARGS | self::NO_TEMPLATES | self::NO_IGNORE |
-               self::RECOVER_COMMENTS | self::NO_TAGS;
-
-       /** This constant exists when $indexOffset is supported in newChild() */
-       const SUPPORTS_INDEX_OFFSET = 1;
-
-       /**
-        * Create a child frame
-        *
-        * @param array|bool $args
-        * @param bool|Title $title
-        * @param int $indexOffset A number subtracted from the index attributes of the arguments
-        *
-        * @return PPFrame
-        */
-       public function newChild( $args = false, $title = false, $indexOffset = 0 );
-
-       /**
-        * Expand a document tree node, caching the result on its parent with the given key
-        * @param string|int $key
-        * @param string|PPNode $root
-        * @param int $flags
-        * @return string
-        */
-       public function cachedExpand( $key, $root, $flags = 0 );
-
-       /**
-        * Expand a document tree node
-        * @param string|PPNode $root
-        * @param int $flags
-        * @return string
-        */
-       public function expand( $root, $flags = 0 );
-
-       /**
-        * Implode with flags for expand()
-        * @param string $sep
-        * @param int $flags
-        * @param string|PPNode $args,...
-        * @return string
-        */
-       public function implodeWithFlags( $sep, $flags /*, ... */ );
-
-       /**
-        * Implode with no flags specified
-        * @param string $sep
-        * @param string|PPNode $args,...
-        * @return string
-        */
-       public function implode( $sep /*, ... */ );
-
-       /**
-        * Makes an object that, when expand()ed, will be the same as one obtained
-        * with implode()
-        * @param string $sep
-        * @param string|PPNode $args,...
-        * @return PPNode
-        */
-       public function virtualImplode( $sep /*, ... */ );
-
-       /**
-        * Virtual implode with brackets
-        * @param string $start
-        * @param string $sep
-        * @param string $end
-        * @param string|PPNode $args,...
-        * @return PPNode
-        */
-       public function virtualBracketedImplode( $start, $sep, $end /*, ... */ );
-
-       /**
-        * Returns true if there are no arguments in this frame
-        *
-        * @return bool
-        */
-       public function isEmpty();
-
-       /**
-        * Returns all arguments of this frame
-        * @return array
-        */
-       public function getArguments();
-
-       /**
-        * Returns all numbered arguments of this frame
-        * @return array
-        */
-       public function getNumberedArguments();
-
-       /**
-        * Returns all named arguments of this frame
-        * @return array
-        */
-       public function getNamedArguments();
-
-       /**
-        * Get an argument to this frame by name
-        * @param int|string $name
-        * @return string|bool
-        */
-       public function getArgument( $name );
-
-       /**
-        * Returns true if the infinite loop check is OK, false if a loop is detected
-        *
-        * @param Title $title
-        * @return bool
-        */
-       public function loopCheck( $title );
-
-       /**
-        * Return true if the frame is a template frame
-        * @return bool
-        */
-       public function isTemplate();
-
-       /**
-        * Set the "volatile" flag.
-        *
-        * Note that this is somewhat of a "hack" in order to make extensions
-        * with side effects (such as Cite) work with the PHP parser. New
-        * extensions should be written in a way that they do not need this
-        * function, because other parsers (such as Parsoid) are not guaranteed
-        * to respect it, and it may be removed in the future.
-        *
-        * @param bool $flag
-        */
-       public function setVolatile( $flag = true );
-
-       /**
-        * Get the "volatile" flag.
-        *
-        * Callers should avoid caching the result of an expansion if it has the
-        * volatile flag set.
-        *
-        * @see self::setVolatile()
-        * @return bool
-        */
-       public function isVolatile();
-
-       /**
-        * Get the TTL of the frame's output.
-        *
-        * This is the maximum amount of time, in seconds, that this frame's
-        * output should be cached for. A value of null indicates that no
-        * maximum has been specified.
-        *
-        * Note that this TTL only applies to caching frames as parts of pages.
-        * It is not relevant to caching the entire rendered output of a page.
-        *
-        * @return int|null
-        */
-       public function getTTL();
-
-       /**
-        * Set the TTL of the output of this frame and all of its ancestors.
-        * Has no effect if the new TTL is greater than the one already set.
-        * Note that it is the caller's responsibility to change the cache
-        * expiry of the page as a whole, if such behavior is desired.
-        *
-        * @see self::getTTL()
-        * @param int $ttl
-        */
-       public function setTTL( $ttl );
-
-       /**
-        * Get a title of frame
-        *
-        * @return Title
-        */
-       public function getTitle();
-}
-
-/**
- * There are three types of nodes:
- *     * Tree nodes, which have a name and contain other nodes as children
- *     * Array nodes, which also contain other nodes but aren't considered part of a tree
- *     * Leaf nodes, which contain the actual data
- *
- * This interface provides access to the tree structure and to the contents of array nodes,
- * but it does not provide access to the internal structure of leaf nodes. Access to leaf
- * data is provided via two means:
- *     * PPFrame::expand(), which provides expanded text
- *     * The PPNode::split*() functions, which provide metadata about certain types of tree node
- * @ingroup Parser
- */
-interface PPNode {
-       /**
-        * Get an array-type node containing the children of this node.
-        * Returns false if this is not a tree node.
-        * @return PPNode
-        */
-       public function getChildren();
-
-       /**
-        * Get the first child of a tree node. False if there isn't one.
-        *
-        * @return PPNode
-        */
-       public function getFirstChild();
-
-       /**
-        * Get the next sibling of any node. False if there isn't one
-        * @return PPNode
-        */
-       public function getNextSibling();
-
-       /**
-        * Get all children of this tree node which have a given name.
-        * Returns an array-type node, or false if this is not a tree node.
-        * @param string $type
-        * @return bool|PPNode
-        */
-       public function getChildrenOfType( $type );
-
-       /**
-        * Returns the length of the array, or false if this is not an array-type node
-        */
-       public function getLength();
-
-       /**
-        * Returns an item of an array-type node
-        * @param int $i
-        * @return bool|PPNode
-        */
-       public function item( $i );
-
-       /**
-        * Get the name of this node. The following names are defined here:
-        *
-        *    h             A heading node.
-        *    template      A double-brace node.
-        *    tplarg        A triple-brace node.
-        *    title         The first argument to a template or tplarg node.
-        *    part          Subsequent arguments to a template or tplarg node.
-        *    #nodelist     An array-type node
-        *
-        * The subclass may define various other names for tree and leaf nodes.
-        * @return string
-        */
-       public function getName();
-
-       /**
-        * Split a "<part>" node into an associative array containing:
-        *    name          PPNode name
-        *    index         String index
-        *    value         PPNode value
-        * @return array
-        */
-       public function splitArg();
-
-       /**
-        * Split an "<ext>" node into an associative array containing name, attr, inner and close
-        * All values in the resulting array are PPNodes. Inner and close are optional.
-        * @return array
-        */
-       public function splitExt();
-
-       /**
-        * Split an "<h>" node
-        * @return array
-        */
-       public function splitHeading();
-}
index 3bcd012..0f0496b 100644 (file)
@@ -823,1231 +823,3 @@ class Preprocessor_DOM extends Preprocessor {
                return $xml;
        }
 }
-
-/**
- * Stack class to help Preprocessor::preprocessToObj()
- * @ingroup Parser
- */
-class PPDStack {
-       public $stack, $rootAccum;
-
-       /**
-        * @var PPDStack
-        */
-       public $top;
-       public $out;
-       public $elementClass = PPDStackElement::class;
-
-       public static $false = false;
-
-       public function __construct() {
-               $this->stack = [];
-               $this->top = false;
-               $this->rootAccum = '';
-               $this->accum =& $this->rootAccum;
-       }
-
-       /**
-        * @return int
-        */
-       public function count() {
-               return count( $this->stack );
-       }
-
-       public function &getAccum() {
-               return $this->accum;
-       }
-
-       public function getCurrentPart() {
-               if ( $this->top === false ) {
-                       return false;
-               } else {
-                       return $this->top->getCurrentPart();
-               }
-       }
-
-       public function push( $data ) {
-               if ( $data instanceof $this->elementClass ) {
-                       $this->stack[] = $data;
-               } else {
-                       $class = $this->elementClass;
-                       $this->stack[] = new $class( $data );
-               }
-               $this->top = $this->stack[count( $this->stack ) - 1];
-               $this->accum =& $this->top->getAccum();
-       }
-
-       public function pop() {
-               if ( $this->stack === [] ) {
-                       throw new MWException( __METHOD__ . ': no elements remaining' );
-               }
-               $temp = array_pop( $this->stack );
-
-               if ( count( $this->stack ) ) {
-                       $this->top = $this->stack[count( $this->stack ) - 1];
-                       $this->accum =& $this->top->getAccum();
-               } else {
-                       $this->top = self::$false;
-                       $this->accum =& $this->rootAccum;
-               }
-               return $temp;
-       }
-
-       public function addPart( $s = '' ) {
-               $this->top->addPart( $s );
-               $this->accum =& $this->top->getAccum();
-       }
-
-       /**
-        * @return array
-        */
-       public function getFlags() {
-               if ( $this->stack === [] ) {
-                       return [
-                               'findEquals' => false,
-                               'findPipe' => false,
-                               'inHeading' => false,
-                       ];
-               } else {
-                       return $this->top->getFlags();
-               }
-       }
-}
-
-/**
- * @ingroup Parser
- */
-class PPDStackElement {
-       /**
-        * @var string Opening character (\n for heading)
-        */
-       public $open;
-
-       /**
-        * @var string Matching closing character
-        */
-       public $close;
-
-       /**
-        * @var string Saved prefix that may affect later processing,
-        *  e.g. to differentiate `-{{{{` and `{{{{` after later seeing `}}}`.
-        */
-       public $savedPrefix = '';
-
-       /**
-        * @var int Number of opening characters found (number of "=" for heading)
-        */
-       public $count;
-
-       /**
-        * @var PPDPart[] Array of PPDPart objects describing pipe-separated parts.
-        */
-       public $parts;
-
-       /**
-        * @var bool True if the open char appeared at the start of the input line.
-        *  Not set for headings.
-        */
-       public $lineStart;
-
-       public $partClass = PPDPart::class;
-
-       public function __construct( $data = [] ) {
-               $class = $this->partClass;
-               $this->parts = [ new $class ];
-
-               foreach ( $data as $name => $value ) {
-                       $this->$name = $value;
-               }
-       }
-
-       public function &getAccum() {
-               return $this->parts[count( $this->parts ) - 1]->out;
-       }
-
-       public function addPart( $s = '' ) {
-               $class = $this->partClass;
-               $this->parts[] = new $class( $s );
-       }
-
-       public function getCurrentPart() {
-               return $this->parts[count( $this->parts ) - 1];
-       }
-
-       /**
-        * @return array
-        */
-       public function getFlags() {
-               $partCount = count( $this->parts );
-               $findPipe = $this->open != "\n" && $this->open != '[';
-               return [
-                       'findPipe' => $findPipe,
-                       'findEquals' => $findPipe && $partCount > 1 && !isset( $this->parts[$partCount - 1]->eqpos ),
-                       'inHeading' => $this->open == "\n",
-               ];
-       }
-
-       /**
-        * Get the output string that would result if the close is not found.
-        *
-        * @param bool|int $openingCount
-        * @return string
-        */
-       public function breakSyntax( $openingCount = false ) {
-               if ( $this->open == "\n" ) {
-                       $s = $this->savedPrefix . $this->parts[0]->out;
-               } else {
-                       if ( $openingCount === false ) {
-                               $openingCount = $this->count;
-                       }
-                       $s = substr( $this->open, 0, -1 );
-                       $s .= str_repeat(
-                               substr( $this->open, -1 ),
-                               $openingCount - strlen( $s )
-                       );
-                       $s = $this->savedPrefix . $s;
-                       $first = true;
-                       foreach ( $this->parts as $part ) {
-                               if ( $first ) {
-                                       $first = false;
-                               } else {
-                                       $s .= '|';
-                               }
-                               $s .= $part->out;
-                       }
-               }
-               return $s;
-       }
-}
-
-/**
- * @ingroup Parser
- */
-class PPDPart {
-       /**
-        * @var string Output accumulator string
-        */
-       public $out;
-
-       // Optional member variables:
-       //   eqpos        Position of equals sign in output accumulator
-       //   commentEnd   Past-the-end input pointer for the last comment encountered
-       //   visualEnd    Past-the-end input pointer for the end of the accumulator minus comments
-
-       public function __construct( $out = '' ) {
-               $this->out = $out;
-       }
-}
-
-/**
- * An expansion frame, used as a context to expand the result of preprocessToObj()
- * @ingroup Parser
- */
-// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
-class PPFrame_DOM implements PPFrame {
-
-       /**
-        * @var Preprocessor
-        */
-       public $preprocessor;
-
-       /**
-        * @var Parser
-        */
-       public $parser;
-
-       /**
-        * @var Title
-        */
-       public $title;
-       public $titleCache;
-
-       /**
-        * Hashtable listing templates which are disallowed for expansion in this frame,
-        * having been encountered previously in parent frames.
-        */
-       public $loopCheckHash;
-
-       /**
-        * Recursion depth of this frame, top = 0
-        * Note that this is NOT the same as expansion depth in expand()
-        */
-       public $depth;
-
-       private $volatile = false;
-       private $ttl = null;
-
-       /**
-        * @var array
-        */
-       protected $childExpansionCache;
-
-       /**
-        * Construct a new preprocessor frame.
-        * @param Preprocessor $preprocessor The parent preprocessor
-        */
-       public function __construct( $preprocessor ) {
-               $this->preprocessor = $preprocessor;
-               $this->parser = $preprocessor->parser;
-               $this->title = $this->parser->mTitle;
-               $this->titleCache = [ $this->title ? $this->title->getPrefixedDBkey() : false ];
-               $this->loopCheckHash = [];
-               $this->depth = 0;
-               $this->childExpansionCache = [];
-       }
-
-       /**
-        * Create a new child frame
-        * $args is optionally a multi-root PPNode or array containing the template arguments
-        *
-        * @param bool|array $args
-        * @param Title|bool $title
-        * @param int $indexOffset
-        * @return PPTemplateFrame_DOM
-        */
-       public function newChild( $args = false, $title = false, $indexOffset = 0 ) {
-               $namedArgs = [];
-               $numberedArgs = [];
-               if ( $title === false ) {
-                       $title = $this->title;
-               }
-               if ( $args !== false ) {
-                       $xpath = false;
-                       if ( $args instanceof PPNode ) {
-                               $args = $args->node;
-                       }
-                       foreach ( $args as $arg ) {
-                               if ( $arg instanceof PPNode ) {
-                                       $arg = $arg->node;
-                               }
-                               if ( !$xpath || $xpath->document !== $arg->ownerDocument ) {
-                                       $xpath = new DOMXPath( $arg->ownerDocument );
-                               }
-
-                               $nameNodes = $xpath->query( 'name', $arg );
-                               $value = $xpath->query( 'value', $arg );
-                               if ( $nameNodes->item( 0 )->hasAttributes() ) {
-                                       // Numbered parameter
-                                       $index = $nameNodes->item( 0 )->attributes->getNamedItem( 'index' )->textContent;
-                                       $index = $index - $indexOffset;
-                                       if ( isset( $namedArgs[$index] ) || isset( $numberedArgs[$index] ) ) {
-                                               $this->parser->getOutput()->addWarning( wfMessage( 'duplicate-args-warning',
-                                                       wfEscapeWikiText( $this->title ),
-                                                       wfEscapeWikiText( $title ),
-                                                       wfEscapeWikiText( $index ) )->text() );
-                                               $this->parser->addTrackingCategory( 'duplicate-args-category' );
-                                       }
-                                       $numberedArgs[$index] = $value->item( 0 );
-                                       unset( $namedArgs[$index] );
-                               } else {
-                                       // Named parameter
-                                       $name = trim( $this->expand( $nameNodes->item( 0 ), PPFrame::STRIP_COMMENTS ) );
-                                       if ( isset( $namedArgs[$name] ) || isset( $numberedArgs[$name] ) ) {
-                                               $this->parser->getOutput()->addWarning( wfMessage( 'duplicate-args-warning',
-                                                       wfEscapeWikiText( $this->title ),
-                                                       wfEscapeWikiText( $title ),
-                                                       wfEscapeWikiText( $name ) )->text() );
-                                               $this->parser->addTrackingCategory( 'duplicate-args-category' );
-                                       }
-                                       $namedArgs[$name] = $value->item( 0 );
-                                       unset( $numberedArgs[$name] );
-                               }
-                       }
-               }
-               return new PPTemplateFrame_DOM( $this->preprocessor, $this, $numberedArgs, $namedArgs, $title );
-       }
-
-       /**
-        * @throws MWException
-        * @param string|int $key
-        * @param string|PPNode_DOM|DOMDocument $root
-        * @param int $flags
-        * @return string
-        */
-       public function cachedExpand( $key, $root, $flags = 0 ) {
-               // we don't have a parent, so we don't have a cache
-               return $this->expand( $root, $flags );
-       }
-
-       /**
-        * @throws MWException
-        * @param string|PPNode_DOM|DOMDocument $root
-        * @param int $flags
-        * @return string
-        */
-       public function expand( $root, $flags = 0 ) {
-               static $expansionDepth = 0;
-               if ( is_string( $root ) ) {
-                       return $root;
-               }
-
-               if ( ++$this->parser->mPPNodeCount > $this->parser->mOptions->getMaxPPNodeCount() ) {
-                       $this->parser->limitationWarn( 'node-count-exceeded',
-                               $this->parser->mPPNodeCount,
-                               $this->parser->mOptions->getMaxPPNodeCount()
-                       );
-                       return '<span class="error">Node-count limit exceeded</span>';
-               }
-
-               if ( $expansionDepth > $this->parser->mOptions->getMaxPPExpandDepth() ) {
-                       $this->parser->limitationWarn( 'expansion-depth-exceeded',
-                               $expansionDepth,
-                               $this->parser->mOptions->getMaxPPExpandDepth()
-                       );
-                       return '<span class="error">Expansion depth limit exceeded</span>';
-               }
-               ++$expansionDepth;
-               if ( $expansionDepth > $this->parser->mHighestExpansionDepth ) {
-                       $this->parser->mHighestExpansionDepth = $expansionDepth;
-               }
-
-               if ( $root instanceof PPNode_DOM ) {
-                       $root = $root->node;
-               }
-               if ( $root instanceof DOMDocument ) {
-                       $root = $root->documentElement;
-               }
-
-               $outStack = [ '', '' ];
-               $iteratorStack = [ false, $root ];
-               $indexStack = [ 0, 0 ];
-
-               while ( count( $iteratorStack ) > 1 ) {
-                       $level = count( $outStack ) - 1;
-                       $iteratorNode =& $iteratorStack[$level];
-                       $out =& $outStack[$level];
-                       $index =& $indexStack[$level];
-
-                       if ( $iteratorNode instanceof PPNode_DOM ) {
-                               $iteratorNode = $iteratorNode->node;
-                       }
-
-                       if ( is_array( $iteratorNode ) ) {
-                               if ( $index >= count( $iteratorNode ) ) {
-                                       // All done with this iterator
-                                       $iteratorStack[$level] = false;
-                                       $contextNode = false;
-                               } else {
-                                       $contextNode = $iteratorNode[$index];
-                                       $index++;
-                               }
-                       } elseif ( $iteratorNode instanceof DOMNodeList ) {
-                               if ( $index >= $iteratorNode->length ) {
-                                       // All done with this iterator
-                                       $iteratorStack[$level] = false;
-                                       $contextNode = false;
-                               } else {
-                                       $contextNode = $iteratorNode->item( $index );
-                                       $index++;
-                               }
-                       } else {
-                               // Copy to $contextNode and then delete from iterator stack,
-                               // because this is not an iterator but we do have to execute it once
-                               $contextNode = $iteratorStack[$level];
-                               $iteratorStack[$level] = false;
-                       }
-
-                       if ( $contextNode instanceof PPNode_DOM ) {
-                               $contextNode = $contextNode->node;
-                       }
-
-                       $newIterator = false;
-
-                       if ( $contextNode === false ) {
-                               // nothing to do
-                       } elseif ( is_string( $contextNode ) ) {
-                               $out .= $contextNode;
-                       } elseif ( is_array( $contextNode ) || $contextNode instanceof DOMNodeList ) {
-                               $newIterator = $contextNode;
-                       } elseif ( $contextNode instanceof DOMNode ) {
-                               if ( $contextNode->nodeType == XML_TEXT_NODE ) {
-                                       $out .= $contextNode->nodeValue;
-                               } elseif ( $contextNode->nodeName == 'template' ) {
-                                       # Double-brace expansion
-                                       $xpath = new DOMXPath( $contextNode->ownerDocument );
-                                       $titles = $xpath->query( 'title', $contextNode );
-                                       $title = $titles->item( 0 );
-                                       $parts = $xpath->query( 'part', $contextNode );
-                                       if ( $flags & PPFrame::NO_TEMPLATES ) {
-                                               $newIterator = $this->virtualBracketedImplode( '{{', '|', '}}', $title, $parts );
-                                       } else {
-                                               $lineStart = $contextNode->getAttribute( 'lineStart' );
-                                               $params = [
-                                                       'title' => new PPNode_DOM( $title ),
-                                                       'parts' => new PPNode_DOM( $parts ),
-                                                       'lineStart' => $lineStart ];
-                                               $ret = $this->parser->braceSubstitution( $params, $this );
-                                               if ( isset( $ret['object'] ) ) {
-                                                       $newIterator = $ret['object'];
-                                               } else {
-                                                       $out .= $ret['text'];
-                                               }
-                                       }
-                               } elseif ( $contextNode->nodeName == 'tplarg' ) {
-                                       # Triple-brace expansion
-                                       $xpath = new DOMXPath( $contextNode->ownerDocument );
-                                       $titles = $xpath->query( 'title', $contextNode );
-                                       $title = $titles->item( 0 );
-                                       $parts = $xpath->query( 'part', $contextNode );
-                                       if ( $flags & PPFrame::NO_ARGS ) {
-                                               $newIterator = $this->virtualBracketedImplode( '{{{', '|', '}}}', $title, $parts );
-                                       } else {
-                                               $params = [
-                                                       'title' => new PPNode_DOM( $title ),
-                                                       'parts' => new PPNode_DOM( $parts ) ];
-                                               $ret = $this->parser->argSubstitution( $params, $this );
-                                               if ( isset( $ret['object'] ) ) {
-                                                       $newIterator = $ret['object'];
-                                               } else {
-                                                       $out .= $ret['text'];
-                                               }
-                                       }
-                               } elseif ( $contextNode->nodeName == 'comment' ) {
-                                       # HTML-style comment
-                                       # Remove it in HTML, pre+remove and STRIP_COMMENTS modes
-                                       # Not in RECOVER_COMMENTS mode (msgnw) though.
-                                       if ( ( $this->parser->ot['html']
-                                               || ( $this->parser->ot['pre'] && $this->parser->mOptions->getRemoveComments() )
-                                               || ( $flags & PPFrame::STRIP_COMMENTS )
-                                               ) && !( $flags & PPFrame::RECOVER_COMMENTS )
-                                       ) {
-                                               $out .= '';
-                                       } elseif ( $this->parser->ot['wiki'] && !( $flags & PPFrame::RECOVER_COMMENTS ) ) {
-                                               # Add a strip marker in PST mode so that pstPass2() can
-                                               # run some old-fashioned regexes on the result.
-                                               # Not in RECOVER_COMMENTS mode (extractSections) though.
-                                               $out .= $this->parser->insertStripItem( $contextNode->textContent );
-                                       } else {
-                                               # Recover the literal comment in RECOVER_COMMENTS and pre+no-remove
-                                               $out .= $contextNode->textContent;
-                                       }
-                               } elseif ( $contextNode->nodeName == 'ignore' ) {
-                                       # Output suppression used by <includeonly> etc.
-                                       # OT_WIKI will only respect <ignore> in substed templates.
-                                       # The other output types respect it unless NO_IGNORE is set.
-                                       # extractSections() sets NO_IGNORE and so never respects it.
-                                       if ( ( !isset( $this->parent ) && $this->parser->ot['wiki'] )
-                                               || ( $flags & PPFrame::NO_IGNORE )
-                                       ) {
-                                               $out .= $contextNode->textContent;
-                                       } else {
-                                               $out .= '';
-                                       }
-                               } elseif ( $contextNode->nodeName == 'ext' ) {
-                                       # Extension tag
-                                       $xpath = new DOMXPath( $contextNode->ownerDocument );
-                                       $names = $xpath->query( 'name', $contextNode );
-                                       $attrs = $xpath->query( 'attr', $contextNode );
-                                       $inners = $xpath->query( 'inner', $contextNode );
-                                       $closes = $xpath->query( 'close', $contextNode );
-                                       if ( $flags & PPFrame::NO_TAGS ) {
-                                               $s = '<' . $this->expand( $names->item( 0 ), $flags );
-                                               if ( $attrs->length > 0 ) {
-                                                       $s .= $this->expand( $attrs->item( 0 ), $flags );
-                                               }
-                                               if ( $inners->length > 0 ) {
-                                                       $s .= '>' . $this->expand( $inners->item( 0 ), $flags );
-                                                       if ( $closes->length > 0 ) {
-                                                               $s .= $this->expand( $closes->item( 0 ), $flags );
-                                                       }
-                                               } else {
-                                                       $s .= '/>';
-                                               }
-                                               $out .= $s;
-                                       } else {
-                                               $params = [
-                                                       'name' => new PPNode_DOM( $names->item( 0 ) ),
-                                                       'attr' => $attrs->length > 0 ? new PPNode_DOM( $attrs->item( 0 ) ) : null,
-                                                       'inner' => $inners->length > 0 ? new PPNode_DOM( $inners->item( 0 ) ) : null,
-                                                       'close' => $closes->length > 0 ? new PPNode_DOM( $closes->item( 0 ) ) : null,
-                                               ];
-                                               $out .= $this->parser->extensionSubstitution( $params, $this );
-                                       }
-                               } elseif ( $contextNode->nodeName == 'h' ) {
-                                       # Heading
-                                       $s = $this->expand( $contextNode->childNodes, $flags );
-
-                                       # Insert a heading marker only for <h> children of <root>
-                                       # This is to stop extractSections from going over multiple tree levels
-                                       if ( $contextNode->parentNode->nodeName == 'root' && $this->parser->ot['html'] ) {
-                                               # Insert heading index marker
-                                               $headingIndex = $contextNode->getAttribute( 'i' );
-                                               $titleText = $this->title->getPrefixedDBkey();
-                                               $this->parser->mHeadings[] = [ $titleText, $headingIndex ];
-                                               $serial = count( $this->parser->mHeadings ) - 1;
-                                               $marker = Parser::MARKER_PREFIX . "-h-$serial-" . Parser::MARKER_SUFFIX;
-                                               $count = $contextNode->getAttribute( 'level' );
-                                               $s = substr( $s, 0, $count ) . $marker . substr( $s, $count );
-                                               $this->parser->mStripState->addGeneral( $marker, '' );
-                                       }
-                                       $out .= $s;
-                               } else {
-                                       # Generic recursive expansion
-                                       $newIterator = $contextNode->childNodes;
-                               }
-                       } else {
-                               throw new MWException( __METHOD__ . ': Invalid parameter type' );
-                       }
-
-                       if ( $newIterator !== false ) {
-                               if ( $newIterator instanceof PPNode_DOM ) {
-                                       $newIterator = $newIterator->node;
-                               }
-                               $outStack[] = '';
-                               $iteratorStack[] = $newIterator;
-                               $indexStack[] = 0;
-                       } elseif ( $iteratorStack[$level] === false ) {
-                               // Return accumulated value to parent
-                               // With tail recursion
-                               while ( $iteratorStack[$level] === false && $level > 0 ) {
-                                       $outStack[$level - 1] .= $out;
-                                       array_pop( $outStack );
-                                       array_pop( $iteratorStack );
-                                       array_pop( $indexStack );
-                                       $level--;
-                               }
-                       }
-               }
-               --$expansionDepth;
-               return $outStack[0];
-       }
-
-       /**
-        * @param string $sep
-        * @param int $flags
-        * @param string|PPNode_DOM|DOMDocument $args,...
-        * @return string
-        */
-       public function implodeWithFlags( $sep, $flags /*, ... */ ) {
-               $args = array_slice( func_get_args(), 2 );
-
-               $first = true;
-               $s = '';
-               foreach ( $args as $root ) {
-                       if ( $root instanceof PPNode_DOM ) {
-                               $root = $root->node;
-                       }
-                       if ( !is_array( $root ) && !( $root instanceof DOMNodeList ) ) {
-                               $root = [ $root ];
-                       }
-                       foreach ( $root as $node ) {
-                               if ( $first ) {
-                                       $first = false;
-                               } else {
-                                       $s .= $sep;
-                               }
-                               $s .= $this->expand( $node, $flags );
-                       }
-               }
-               return $s;
-       }
-
-       /**
-        * Implode with no flags specified
-        * This previously called implodeWithFlags but has now been inlined to reduce stack depth
-        *
-        * @param string $sep
-        * @param string|PPNode_DOM|DOMDocument $args,...
-        * @return string
-        */
-       public function implode( $sep /*, ... */ ) {
-               $args = array_slice( func_get_args(), 1 );
-
-               $first = true;
-               $s = '';
-               foreach ( $args as $root ) {
-                       if ( $root instanceof PPNode_DOM ) {
-                               $root = $root->node;
-                       }
-                       if ( !is_array( $root ) && !( $root instanceof DOMNodeList ) ) {
-                               $root = [ $root ];
-                       }
-                       foreach ( $root as $node ) {
-                               if ( $first ) {
-                                       $first = false;
-                               } else {
-                                       $s .= $sep;
-                               }
-                               $s .= $this->expand( $node );
-                       }
-               }
-               return $s;
-       }
-
-       /**
-        * Makes an object that, when expand()ed, will be the same as one obtained
-        * with implode()
-        *
-        * @param string $sep
-        * @param string|PPNode_DOM|DOMDocument $args,...
-        * @return array
-        */
-       public function virtualImplode( $sep /*, ... */ ) {
-               $args = array_slice( func_get_args(), 1 );
-               $out = [];
-               $first = true;
-
-               foreach ( $args as $root ) {
-                       if ( $root instanceof PPNode_DOM ) {
-                               $root = $root->node;
-                       }
-                       if ( !is_array( $root ) && !( $root instanceof DOMNodeList ) ) {
-                               $root = [ $root ];
-                       }
-                       foreach ( $root as $node ) {
-                               if ( $first ) {
-                                       $first = false;
-                               } else {
-                                       $out[] = $sep;
-                               }
-                               $out[] = $node;
-                       }
-               }
-               return $out;
-       }
-
-       /**
-        * Virtual implode with brackets
-        * @param string $start
-        * @param string $sep
-        * @param string $end
-        * @param string|PPNode_DOM|DOMDocument $args,...
-        * @return array
-        */
-       public function virtualBracketedImplode( $start, $sep, $end /*, ... */ ) {
-               $args = array_slice( func_get_args(), 3 );
-               $out = [ $start ];
-               $first = true;
-
-               foreach ( $args as $root ) {
-                       if ( $root instanceof PPNode_DOM ) {
-                               $root = $root->node;
-                       }
-                       if ( !is_array( $root ) && !( $root instanceof DOMNodeList ) ) {
-                               $root = [ $root ];
-                       }
-                       foreach ( $root as $node ) {
-                               if ( $first ) {
-                                       $first = false;
-                               } else {
-                                       $out[] = $sep;
-                               }
-                               $out[] = $node;
-                       }
-               }
-               $out[] = $end;
-               return $out;
-       }
-
-       public function __toString() {
-               return 'frame{}';
-       }
-
-       public function getPDBK( $level = false ) {
-               if ( $level === false ) {
-                       return $this->title->getPrefixedDBkey();
-               } else {
-                       return $this->titleCache[$level] ?? false;
-               }
-       }
-
-       /**
-        * @return array
-        */
-       public function getArguments() {
-               return [];
-       }
-
-       /**
-        * @return array
-        */
-       public function getNumberedArguments() {
-               return [];
-       }
-
-       /**
-        * @return array
-        */
-       public function getNamedArguments() {
-               return [];
-       }
-
-       /**
-        * Returns true if there are no arguments in this frame
-        *
-        * @return bool
-        */
-       public function isEmpty() {
-               return true;
-       }
-
-       /**
-        * @param int|string $name
-        * @return bool Always false in this implementation.
-        */
-       public function getArgument( $name ) {
-               return false;
-       }
-
-       /**
-        * Returns true if the infinite loop check is OK, false if a loop is detected
-        *
-        * @param Title $title
-        * @return bool
-        */
-       public function loopCheck( $title ) {
-               return !isset( $this->loopCheckHash[$title->getPrefixedDBkey()] );
-       }
-
-       /**
-        * Return true if the frame is a template frame
-        *
-        * @return bool
-        */
-       public function isTemplate() {
-               return false;
-       }
-
-       /**
-        * Get a title of frame
-        *
-        * @return Title
-        */
-       public function getTitle() {
-               return $this->title;
-       }
-
-       /**
-        * Set the volatile flag
-        *
-        * @param bool $flag
-        */
-       public function setVolatile( $flag = true ) {
-               $this->volatile = $flag;
-       }
-
-       /**
-        * Get the volatile flag
-        *
-        * @return bool
-        */
-       public function isVolatile() {
-               return $this->volatile;
-       }
-
-       /**
-        * Set the TTL
-        *
-        * @param int $ttl
-        */
-       public function setTTL( $ttl ) {
-               if ( $ttl !== null && ( $this->ttl === null || $ttl < $this->ttl ) ) {
-                       $this->ttl = $ttl;
-               }
-       }
-
-       /**
-        * Get the TTL
-        *
-        * @return int|null
-        */
-       public function getTTL() {
-               return $this->ttl;
-       }
-}
-
-/**
- * Expansion frame with template arguments
- * @ingroup Parser
- */
-// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
-class PPTemplateFrame_DOM extends PPFrame_DOM {
-
-       public $numberedArgs, $namedArgs;
-
-       /**
-        * @var PPFrame_DOM
-        */
-       public $parent;
-       public $numberedExpansionCache, $namedExpansionCache;
-
-       /**
-        * @param Preprocessor $preprocessor
-        * @param bool|PPFrame_DOM $parent
-        * @param array $numberedArgs
-        * @param array $namedArgs
-        * @param bool|Title $title
-        */
-       public function __construct( $preprocessor, $parent = false, $numberedArgs = [],
-               $namedArgs = [], $title = false
-       ) {
-               parent::__construct( $preprocessor );
-
-               $this->parent = $parent;
-               $this->numberedArgs = $numberedArgs;
-               $this->namedArgs = $namedArgs;
-               $this->title = $title;
-               $pdbk = $title ? $title->getPrefixedDBkey() : false;
-               $this->titleCache = $parent->titleCache;
-               $this->titleCache[] = $pdbk;
-               $this->loopCheckHash = /*clone*/ $parent->loopCheckHash;
-               if ( $pdbk !== false ) {
-                       $this->loopCheckHash[$pdbk] = true;
-               }
-               $this->depth = $parent->depth + 1;
-               $this->numberedExpansionCache = $this->namedExpansionCache = [];
-       }
-
-       public function __toString() {
-               $s = 'tplframe{';
-               $first = true;
-               $args = $this->numberedArgs + $this->namedArgs;
-               foreach ( $args as $name => $value ) {
-                       if ( $first ) {
-                               $first = false;
-                       } else {
-                               $s .= ', ';
-                       }
-                       $s .= "\"$name\":\"" .
-                               str_replace( '"', '\\"', $value->ownerDocument->saveXML( $value ) ) . '"';
-               }
-               $s .= '}';
-               return $s;
-       }
-
-       /**
-        * @throws MWException
-        * @param string|int $key
-        * @param string|PPNode_DOM|DOMDocument $root
-        * @param int $flags
-        * @return string
-        */
-       public function cachedExpand( $key, $root, $flags = 0 ) {
-               if ( isset( $this->parent->childExpansionCache[$key] ) ) {
-                       return $this->parent->childExpansionCache[$key];
-               }
-               $retval = $this->expand( $root, $flags );
-               if ( !$this->isVolatile() ) {
-                       $this->parent->childExpansionCache[$key] = $retval;
-               }
-               return $retval;
-       }
-
-       /**
-        * Returns true if there are no arguments in this frame
-        *
-        * @return bool
-        */
-       public function isEmpty() {
-               return !count( $this->numberedArgs ) && !count( $this->namedArgs );
-       }
-
-       public function getArguments() {
-               $arguments = [];
-               foreach ( array_merge(
-                               array_keys( $this->numberedArgs ),
-                               array_keys( $this->namedArgs ) ) as $key ) {
-                       $arguments[$key] = $this->getArgument( $key );
-               }
-               return $arguments;
-       }
-
-       public function getNumberedArguments() {
-               $arguments = [];
-               foreach ( array_keys( $this->numberedArgs ) as $key ) {
-                       $arguments[$key] = $this->getArgument( $key );
-               }
-               return $arguments;
-       }
-
-       public function getNamedArguments() {
-               $arguments = [];
-               foreach ( array_keys( $this->namedArgs ) as $key ) {
-                       $arguments[$key] = $this->getArgument( $key );
-               }
-               return $arguments;
-       }
-
-       /**
-        * @param int $index
-        * @return string|bool
-        */
-       public function getNumberedArgument( $index ) {
-               if ( !isset( $this->numberedArgs[$index] ) ) {
-                       return false;
-               }
-               if ( !isset( $this->numberedExpansionCache[$index] ) ) {
-                       # No trimming for unnamed arguments
-                       $this->numberedExpansionCache[$index] = $this->parent->expand(
-                               $this->numberedArgs[$index],
-                               PPFrame::STRIP_COMMENTS
-                       );
-               }
-               return $this->numberedExpansionCache[$index];
-       }
-
-       /**
-        * @param string $name
-        * @return string|bool
-        */
-       public function getNamedArgument( $name ) {
-               if ( !isset( $this->namedArgs[$name] ) ) {
-                       return false;
-               }
-               if ( !isset( $this->namedExpansionCache[$name] ) ) {
-                       # Trim named arguments post-expand, for backwards compatibility
-                       $this->namedExpansionCache[$name] = trim(
-                               $this->parent->expand( $this->namedArgs[$name], PPFrame::STRIP_COMMENTS ) );
-               }
-               return $this->namedExpansionCache[$name];
-       }
-
-       /**
-        * @param int|string $name
-        * @return string|bool
-        */
-       public function getArgument( $name ) {
-               $text = $this->getNumberedArgument( $name );
-               if ( $text === false ) {
-                       $text = $this->getNamedArgument( $name );
-               }
-               return $text;
-       }
-
-       /**
-        * Return true if the frame is a template frame
-        *
-        * @return bool
-        */
-       public function isTemplate() {
-               return true;
-       }
-
-       public function setVolatile( $flag = true ) {
-               parent::setVolatile( $flag );
-               $this->parent->setVolatile( $flag );
-       }
-
-       public function setTTL( $ttl ) {
-               parent::setTTL( $ttl );
-               $this->parent->setTTL( $ttl );
-       }
-}
-
-/**
- * Expansion frame with custom arguments
- * @ingroup Parser
- */
-// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
-class PPCustomFrame_DOM extends PPFrame_DOM {
-
-       public $args;
-
-       public function __construct( $preprocessor, $args ) {
-               parent::__construct( $preprocessor );
-               $this->args = $args;
-       }
-
-       public function __toString() {
-               $s = 'cstmframe{';
-               $first = true;
-               foreach ( $this->args as $name => $value ) {
-                       if ( $first ) {
-                               $first = false;
-                       } else {
-                               $s .= ', ';
-                       }
-                       $s .= "\"$name\":\"" .
-                               str_replace( '"', '\\"', $value->__toString() ) . '"';
-               }
-               $s .= '}';
-               return $s;
-       }
-
-       /**
-        * @return bool
-        */
-       public function isEmpty() {
-               return !count( $this->args );
-       }
-
-       /**
-        * @param int|string $index
-        * @return string|bool
-        */
-       public function getArgument( $index ) {
-               return $this->args[$index] ?? false;
-       }
-
-       public function getArguments() {
-               return $this->args;
-       }
-}
-
-/**
- * @ingroup Parser
- */
-// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
-class PPNode_DOM implements PPNode {
-
-       /**
-        * @var DOMElement
-        */
-       public $node;
-       public $xpath;
-
-       public function __construct( $node, $xpath = false ) {
-               $this->node = $node;
-       }
-
-       /**
-        * @return DOMXPath
-        */
-       public function getXPath() {
-               if ( $this->xpath === null ) {
-                       $this->xpath = new DOMXPath( $this->node->ownerDocument );
-               }
-               return $this->xpath;
-       }
-
-       public function __toString() {
-               if ( $this->node instanceof DOMNodeList ) {
-                       $s = '';
-                       foreach ( $this->node as $node ) {
-                               $s .= $node->ownerDocument->saveXML( $node );
-                       }
-               } else {
-                       $s = $this->node->ownerDocument->saveXML( $this->node );
-               }
-               return $s;
-       }
-
-       /**
-        * @return bool|PPNode_DOM
-        */
-       public function getChildren() {
-               return $this->node->childNodes ? new self( $this->node->childNodes ) : false;
-       }
-
-       /**
-        * @return bool|PPNode_DOM
-        */
-       public function getFirstChild() {
-               return $this->node->firstChild ? new self( $this->node->firstChild ) : false;
-       }
-
-       /**
-        * @return bool|PPNode_DOM
-        */
-       public function getNextSibling() {
-               return $this->node->nextSibling ? new self( $this->node->nextSibling ) : false;
-       }
-
-       /**
-        * @param string $type
-        *
-        * @return bool|PPNode_DOM
-        */
-       public function getChildrenOfType( $type ) {
-               return new self( $this->getXPath()->query( $type, $this->node ) );
-       }
-
-       /**
-        * @return int
-        */
-       public function getLength() {
-               if ( $this->node instanceof DOMNodeList ) {
-                       return $this->node->length;
-               } else {
-                       return false;
-               }
-       }
-
-       /**
-        * @param int $i
-        * @return bool|PPNode_DOM
-        */
-       public function item( $i ) {
-               $item = $this->node->item( $i );
-               return $item ? new self( $item ) : false;
-       }
-
-       /**
-        * @return string
-        */
-       public function getName() {
-               if ( $this->node instanceof DOMNodeList ) {
-                       return '#nodelist';
-               } else {
-                       return $this->node->nodeName;
-               }
-       }
-
-       /**
-        * Split a "<part>" node into an associative array containing:
-        *  - name          PPNode name
-        *  - index         String index
-        *  - value         PPNode value
-        *
-        * @throws MWException
-        * @return array
-        */
-       public function splitArg() {
-               $xpath = $this->getXPath();
-               $names = $xpath->query( 'name', $this->node );
-               $values = $xpath->query( 'value', $this->node );
-               if ( !$names->length || !$values->length ) {
-                       throw new MWException( 'Invalid brace node passed to ' . __METHOD__ );
-               }
-               $name = $names->item( 0 );
-               $index = $name->getAttribute( 'index' );
-               return [
-                       'name' => new self( $name ),
-                       'index' => $index,
-                       'value' => new self( $values->item( 0 ) ) ];
-       }
-
-       /**
-        * Split an "<ext>" node into an associative array containing name, attr, inner and close
-        * All values in the resulting array are PPNodes. Inner and close are optional.
-        *
-        * @throws MWException
-        * @return array
-        */
-       public function splitExt() {
-               $xpath = $this->getXPath();
-               $names = $xpath->query( 'name', $this->node );
-               $attrs = $xpath->query( 'attr', $this->node );
-               $inners = $xpath->query( 'inner', $this->node );
-               $closes = $xpath->query( 'close', $this->node );
-               if ( !$names->length || !$attrs->length ) {
-                       throw new MWException( 'Invalid ext node passed to ' . __METHOD__ );
-               }
-               $parts = [
-                       'name' => new self( $names->item( 0 ) ),
-                       'attr' => new self( $attrs->item( 0 ) ) ];
-               if ( $inners->length ) {
-                       $parts['inner'] = new self( $inners->item( 0 ) );
-               }
-               if ( $closes->length ) {
-                       $parts['close'] = new self( $closes->item( 0 ) );
-               }
-               return $parts;
-       }
-
-       /**
-        * Split a "<h>" node
-        * @throws MWException
-        * @return array
-        */
-       public function splitHeading() {
-               if ( $this->getName() !== 'h' ) {
-                       throw new MWException( 'Invalid h node passed to ' . __METHOD__ );
-               }
-               return [
-                       'i' => $this->node->getAttribute( 'i' ),
-                       'level' => $this->node->getAttribute( 'level' ),
-                       'contents' => $this->getChildren()
-               ];
-       }
-}
index eb869e2..66f081f 100644 (file)
@@ -795,1463 +795,3 @@ class Preprocessor_Hash extends Preprocessor {
                }
        }
 }
-
-/**
- * Stack class to help Preprocessor::preprocessToObj()
- * @ingroup Parser
- */
-// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
-class PPDStack_Hash extends PPDStack {
-
-       public function __construct() {
-               $this->elementClass = PPDStackElement_Hash::class;
-               parent::__construct();
-               $this->rootAccum = [];
-       }
-}
-
-/**
- * @ingroup Parser
- */
-// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
-class PPDStackElement_Hash extends PPDStackElement {
-
-       public function __construct( $data = [] ) {
-               $this->partClass = PPDPart_Hash::class;
-               parent::__construct( $data );
-       }
-
-       /**
-        * Get the accumulator that would result if the close is not found.
-        *
-        * @param int|bool $openingCount
-        * @return array
-        */
-       public function breakSyntax( $openingCount = false ) {
-               if ( $this->open == "\n" ) {
-                       $accum = array_merge( [ $this->savedPrefix ], $this->parts[0]->out );
-               } else {
-                       if ( $openingCount === false ) {
-                               $openingCount = $this->count;
-                       }
-                       $s = substr( $this->open, 0, -1 );
-                       $s .= str_repeat(
-                               substr( $this->open, -1 ),
-                               $openingCount - strlen( $s )
-                       );
-                       $accum = [ $this->savedPrefix . $s ];
-                       $lastIndex = 0;
-                       $first = true;
-                       foreach ( $this->parts as $part ) {
-                               if ( $first ) {
-                                       $first = false;
-                               } elseif ( is_string( $accum[$lastIndex] ) ) {
-                                       $accum[$lastIndex] .= '|';
-                               } else {
-                                       $accum[++$lastIndex] = '|';
-                               }
-                               foreach ( $part->out as $node ) {
-                                       if ( is_string( $node ) && is_string( $accum[$lastIndex] ) ) {
-                                               $accum[$lastIndex] .= $node;
-                                       } else {
-                                               $accum[++$lastIndex] = $node;
-                                       }
-                               }
-                       }
-               }
-               return $accum;
-       }
-}
-
-/**
- * @ingroup Parser
- */
-// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
-class PPDPart_Hash extends PPDPart {
-
-       public function __construct( $out = '' ) {
-               if ( $out !== '' ) {
-                       $accum = [ $out ];
-               } else {
-                       $accum = [];
-               }
-               parent::__construct( $accum );
-       }
-}
-
-/**
- * An expansion frame, used as a context to expand the result of preprocessToObj()
- * @ingroup Parser
- */
-// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
-class PPFrame_Hash implements PPFrame {
-
-       /**
-        * @var Parser
-        */
-       public $parser;
-
-       /**
-        * @var Preprocessor
-        */
-       public $preprocessor;
-
-       /**
-        * @var Title
-        */
-       public $title;
-       public $titleCache;
-
-       /**
-        * Hashtable listing templates which are disallowed for expansion in this frame,
-        * having been encountered previously in parent frames.
-        */
-       public $loopCheckHash;
-
-       /**
-        * Recursion depth of this frame, top = 0
-        * Note that this is NOT the same as expansion depth in expand()
-        */
-       public $depth;
-
-       private $volatile = false;
-       private $ttl = null;
-
-       /**
-        * @var array
-        */
-       protected $childExpansionCache;
-
-       /**
-        * Construct a new preprocessor frame.
-        * @param Preprocessor $preprocessor The parent preprocessor
-        */
-       public function __construct( $preprocessor ) {
-               $this->preprocessor = $preprocessor;
-               $this->parser = $preprocessor->parser;
-               $this->title = $this->parser->mTitle;
-               $this->titleCache = [ $this->title ? $this->title->getPrefixedDBkey() : false ];
-               $this->loopCheckHash = [];
-               $this->depth = 0;
-               $this->childExpansionCache = [];
-       }
-
-       /**
-        * Create a new child frame
-        * $args is optionally a multi-root PPNode or array containing the template arguments
-        *
-        * @param array|bool|PPNode_Hash_Array $args
-        * @param Title|bool $title
-        * @param int $indexOffset
-        * @throws MWException
-        * @return PPTemplateFrame_Hash
-        */
-       public function newChild( $args = false, $title = false, $indexOffset = 0 ) {
-               $namedArgs = [];
-               $numberedArgs = [];
-               if ( $title === false ) {
-                       $title = $this->title;
-               }
-               if ( $args !== false ) {
-                       if ( $args instanceof PPNode_Hash_Array ) {
-                               $args = $args->value;
-                       } elseif ( !is_array( $args ) ) {
-                               throw new MWException( __METHOD__ . ': $args must be array or PPNode_Hash_Array' );
-                       }
-                       foreach ( $args as $arg ) {
-                               $bits = $arg->splitArg();
-                               if ( $bits['index'] !== '' ) {
-                                       // Numbered parameter
-                                       $index = $bits['index'] - $indexOffset;
-                                       if ( isset( $namedArgs[$index] ) || isset( $numberedArgs[$index] ) ) {
-                                               $this->parser->getOutput()->addWarning( wfMessage( 'duplicate-args-warning',
-                                                       wfEscapeWikiText( $this->title ),
-                                                       wfEscapeWikiText( $title ),
-                                                       wfEscapeWikiText( $index ) )->text() );
-                                               $this->parser->addTrackingCategory( 'duplicate-args-category' );
-                                       }
-                                       $numberedArgs[$index] = $bits['value'];
-                                       unset( $namedArgs[$index] );
-                               } else {
-                                       // Named parameter
-                                       $name = trim( $this->expand( $bits['name'], PPFrame::STRIP_COMMENTS ) );
-                                       if ( isset( $namedArgs[$name] ) || isset( $numberedArgs[$name] ) ) {
-                                               $this->parser->getOutput()->addWarning( wfMessage( 'duplicate-args-warning',
-                                                       wfEscapeWikiText( $this->title ),
-                                                       wfEscapeWikiText( $title ),
-                                                       wfEscapeWikiText( $name ) )->text() );
-                                               $this->parser->addTrackingCategory( 'duplicate-args-category' );
-                                       }
-                                       $namedArgs[$name] = $bits['value'];
-                                       unset( $numberedArgs[$name] );
-                               }
-                       }
-               }
-               return new PPTemplateFrame_Hash( $this->preprocessor, $this, $numberedArgs, $namedArgs, $title );
-       }
-
-       /**
-        * @throws MWException
-        * @param string|int $key
-        * @param string|PPNode $root
-        * @param int $flags
-        * @return string
-        */
-       public function cachedExpand( $key, $root, $flags = 0 ) {
-               // we don't have a parent, so we don't have a cache
-               return $this->expand( $root, $flags );
-       }
-
-       /**
-        * @throws MWException
-        * @param string|PPNode $root
-        * @param int $flags
-        * @return string
-        */
-       public function expand( $root, $flags = 0 ) {
-               static $expansionDepth = 0;
-               if ( is_string( $root ) ) {
-                       return $root;
-               }
-
-               if ( ++$this->parser->mPPNodeCount > $this->parser->mOptions->getMaxPPNodeCount() ) {
-                       $this->parser->limitationWarn( 'node-count-exceeded',
-                                       $this->parser->mPPNodeCount,
-                                       $this->parser->mOptions->getMaxPPNodeCount()
-                       );
-                       return '<span class="error">Node-count limit exceeded</span>';
-               }
-               if ( $expansionDepth > $this->parser->mOptions->getMaxPPExpandDepth() ) {
-                       $this->parser->limitationWarn( 'expansion-depth-exceeded',
-                                       $expansionDepth,
-                                       $this->parser->mOptions->getMaxPPExpandDepth()
-                       );
-                       return '<span class="error">Expansion depth limit exceeded</span>';
-               }
-               ++$expansionDepth;
-               if ( $expansionDepth > $this->parser->mHighestExpansionDepth ) {
-                       $this->parser->mHighestExpansionDepth = $expansionDepth;
-               }
-
-               $outStack = [ '', '' ];
-               $iteratorStack = [ false, $root ];
-               $indexStack = [ 0, 0 ];
-
-               while ( count( $iteratorStack ) > 1 ) {
-                       $level = count( $outStack ) - 1;
-                       $iteratorNode =& $iteratorStack[$level];
-                       $out =& $outStack[$level];
-                       $index =& $indexStack[$level];
-
-                       if ( is_array( $iteratorNode ) ) {
-                               if ( $index >= count( $iteratorNode ) ) {
-                                       // All done with this iterator
-                                       $iteratorStack[$level] = false;
-                                       $contextNode = false;
-                               } else {
-                                       $contextNode = $iteratorNode[$index];
-                                       $index++;
-                               }
-                       } elseif ( $iteratorNode instanceof PPNode_Hash_Array ) {
-                               if ( $index >= $iteratorNode->getLength() ) {
-                                       // All done with this iterator
-                                       $iteratorStack[$level] = false;
-                                       $contextNode = false;
-                               } else {
-                                       $contextNode = $iteratorNode->item( $index );
-                                       $index++;
-                               }
-                       } else {
-                               // Copy to $contextNode and then delete from iterator stack,
-                               // because this is not an iterator but we do have to execute it once
-                               $contextNode = $iteratorStack[$level];
-                               $iteratorStack[$level] = false;
-                       }
-
-                       $newIterator = false;
-                       $contextName = false;
-                       $contextChildren = false;
-
-                       if ( $contextNode === false ) {
-                               // nothing to do
-                       } elseif ( is_string( $contextNode ) ) {
-                               $out .= $contextNode;
-                       } elseif ( $contextNode instanceof PPNode_Hash_Array ) {
-                               $newIterator = $contextNode;
-                       } elseif ( $contextNode instanceof PPNode_Hash_Attr ) {
-                               // No output
-                       } elseif ( $contextNode instanceof PPNode_Hash_Text ) {
-                               $out .= $contextNode->value;
-                       } elseif ( $contextNode instanceof PPNode_Hash_Tree ) {
-                               $contextName = $contextNode->name;
-                               $contextChildren = $contextNode->getRawChildren();
-                       } elseif ( is_array( $contextNode ) ) {
-                               // Node descriptor array
-                               if ( count( $contextNode ) !== 2 ) {
-                                       throw new MWException( __METHOD__ .
-                                               ': found an array where a node descriptor should be' );
-                               }
-                               list( $contextName, $contextChildren ) = $contextNode;
-                       } else {
-                               throw new MWException( __METHOD__ . ': Invalid parameter type' );
-                       }
-
-                       // Handle node descriptor array or tree object
-                       if ( $contextName === false ) {
-                               // Not a node, already handled above
-                       } elseif ( $contextName[0] === '@' ) {
-                               // Attribute: no output
-                       } elseif ( $contextName === 'template' ) {
-                               # Double-brace expansion
-                               $bits = PPNode_Hash_Tree::splitRawTemplate( $contextChildren );
-                               if ( $flags & PPFrame::NO_TEMPLATES ) {
-                                       $newIterator = $this->virtualBracketedImplode(
-                                               '{{', '|', '}}',
-                                               $bits['title'],
-                                               $bits['parts']
-                                       );
-                               } else {
-                                       $ret = $this->parser->braceSubstitution( $bits, $this );
-                                       if ( isset( $ret['object'] ) ) {
-                                               $newIterator = $ret['object'];
-                                       } else {
-                                               $out .= $ret['text'];
-                                       }
-                               }
-                       } elseif ( $contextName === 'tplarg' ) {
-                               # Triple-brace expansion
-                               $bits = PPNode_Hash_Tree::splitRawTemplate( $contextChildren );
-                               if ( $flags & PPFrame::NO_ARGS ) {
-                                       $newIterator = $this->virtualBracketedImplode(
-                                               '{{{', '|', '}}}',
-                                               $bits['title'],
-                                               $bits['parts']
-                                       );
-                               } else {
-                                       $ret = $this->parser->argSubstitution( $bits, $this );
-                                       if ( isset( $ret['object'] ) ) {
-                                               $newIterator = $ret['object'];
-                                       } else {
-                                               $out .= $ret['text'];
-                                       }
-                               }
-                       } elseif ( $contextName === 'comment' ) {
-                               # HTML-style comment
-                               # Remove it in HTML, pre+remove and STRIP_COMMENTS modes
-                               # Not in RECOVER_COMMENTS mode (msgnw) though.
-                               if ( ( $this->parser->ot['html']
-                                       || ( $this->parser->ot['pre'] && $this->parser->mOptions->getRemoveComments() )
-                                       || ( $flags & PPFrame::STRIP_COMMENTS )
-                                       ) && !( $flags & PPFrame::RECOVER_COMMENTS )
-                               ) {
-                                       $out .= '';
-                               } elseif ( $this->parser->ot['wiki'] && !( $flags & PPFrame::RECOVER_COMMENTS ) ) {
-                                       # Add a strip marker in PST mode so that pstPass2() can
-                                       # run some old-fashioned regexes on the result.
-                                       # Not in RECOVER_COMMENTS mode (extractSections) though.
-                                       $out .= $this->parser->insertStripItem( $contextChildren[0] );
-                               } else {
-                                       # Recover the literal comment in RECOVER_COMMENTS and pre+no-remove
-                                       $out .= $contextChildren[0];
-                               }
-                       } elseif ( $contextName === 'ignore' ) {
-                               # Output suppression used by <includeonly> etc.
-                               # OT_WIKI will only respect <ignore> in substed templates.
-                               # The other output types respect it unless NO_IGNORE is set.
-                               # extractSections() sets NO_IGNORE and so never respects it.
-                               if ( ( !isset( $this->parent ) && $this->parser->ot['wiki'] )
-                                       || ( $flags & PPFrame::NO_IGNORE )
-                               ) {
-                                       $out .= $contextChildren[0];
-                               } else {
-                                       // $out .= '';
-                               }
-                       } elseif ( $contextName === 'ext' ) {
-                               # Extension tag
-                               $bits = PPNode_Hash_Tree::splitRawExt( $contextChildren ) +
-                                       [ 'attr' => null, 'inner' => null, 'close' => null ];
-                               if ( $flags & PPFrame::NO_TAGS ) {
-                                       $s = '<' . $bits['name']->getFirstChild()->value;
-                                       if ( $bits['attr'] ) {
-                                               $s .= $bits['attr']->getFirstChild()->value;
-                                       }
-                                       if ( $bits['inner'] ) {
-                                               $s .= '>' . $bits['inner']->getFirstChild()->value;
-                                               if ( $bits['close'] ) {
-                                                       $s .= $bits['close']->getFirstChild()->value;
-                                               }
-                                       } else {
-                                               $s .= '/>';
-                                       }
-                                       $out .= $s;
-                               } else {
-                                       $out .= $this->parser->extensionSubstitution( $bits, $this );
-                               }
-                       } elseif ( $contextName === 'h' ) {
-                               # Heading
-                               if ( $this->parser->ot['html'] ) {
-                                       # Expand immediately and insert heading index marker
-                                       $s = $this->expand( $contextChildren, $flags );
-                                       $bits = PPNode_Hash_Tree::splitRawHeading( $contextChildren );
-                                       $titleText = $this->title->getPrefixedDBkey();
-                                       $this->parser->mHeadings[] = [ $titleText, $bits['i'] ];
-                                       $serial = count( $this->parser->mHeadings ) - 1;
-                                       $marker = Parser::MARKER_PREFIX . "-h-$serial-" . Parser::MARKER_SUFFIX;
-                                       $s = substr( $s, 0, $bits['level'] ) . $marker . substr( $s, $bits['level'] );
-                                       $this->parser->mStripState->addGeneral( $marker, '' );
-                                       $out .= $s;
-                               } else {
-                                       # Expand in virtual stack
-                                       $newIterator = $contextChildren;
-                               }
-                       } else {
-                               # Generic recursive expansion
-                               $newIterator = $contextChildren;
-                       }
-
-                       if ( $newIterator !== false ) {
-                               $outStack[] = '';
-                               $iteratorStack[] = $newIterator;
-                               $indexStack[] = 0;
-                       } elseif ( $iteratorStack[$level] === false ) {
-                               // Return accumulated value to parent
-                               // With tail recursion
-                               while ( $iteratorStack[$level] === false && $level > 0 ) {
-                                       $outStack[$level - 1] .= $out;
-                                       array_pop( $outStack );
-                                       array_pop( $iteratorStack );
-                                       array_pop( $indexStack );
-                                       $level--;
-                               }
-                       }
-               }
-               --$expansionDepth;
-               return $outStack[0];
-       }
-
-       /**
-        * @param string $sep
-        * @param int $flags
-        * @param string|PPNode $args,...
-        * @return string
-        */
-       public function implodeWithFlags( $sep, $flags /*, ... */ ) {
-               $args = array_slice( func_get_args(), 2 );
-
-               $first = true;
-               $s = '';
-               foreach ( $args as $root ) {
-                       if ( $root instanceof PPNode_Hash_Array ) {
-                               $root = $root->value;
-                       }
-                       if ( !is_array( $root ) ) {
-                               $root = [ $root ];
-                       }
-                       foreach ( $root as $node ) {
-                               if ( $first ) {
-                                       $first = false;
-                               } else {
-                                       $s .= $sep;
-                               }
-                               $s .= $this->expand( $node, $flags );
-                       }
-               }
-               return $s;
-       }
-
-       /**
-        * Implode with no flags specified
-        * This previously called implodeWithFlags but has now been inlined to reduce stack depth
-        * @param string $sep
-        * @param string|PPNode $args,...
-        * @return string
-        */
-       public function implode( $sep /*, ... */ ) {
-               $args = array_slice( func_get_args(), 1 );
-
-               $first = true;
-               $s = '';
-               foreach ( $args as $root ) {
-                       if ( $root instanceof PPNode_Hash_Array ) {
-                               $root = $root->value;
-                       }
-                       if ( !is_array( $root ) ) {
-                               $root = [ $root ];
-                       }
-                       foreach ( $root as $node ) {
-                               if ( $first ) {
-                                       $first = false;
-                               } else {
-                                       $s .= $sep;
-                               }
-                               $s .= $this->expand( $node );
-                       }
-               }
-               return $s;
-       }
-
-       /**
-        * Makes an object that, when expand()ed, will be the same as one obtained
-        * with implode()
-        *
-        * @param string $sep
-        * @param string|PPNode $args,...
-        * @return PPNode_Hash_Array
-        */
-       public function virtualImplode( $sep /*, ... */ ) {
-               $args = array_slice( func_get_args(), 1 );
-               $out = [];
-               $first = true;
-
-               foreach ( $args as $root ) {
-                       if ( $root instanceof PPNode_Hash_Array ) {
-                               $root = $root->value;
-                       }
-                       if ( !is_array( $root ) ) {
-                               $root = [ $root ];
-                       }
-                       foreach ( $root as $node ) {
-                               if ( $first ) {
-                                       $first = false;
-                               } else {
-                                       $out[] = $sep;
-                               }
-                               $out[] = $node;
-                       }
-               }
-               return new PPNode_Hash_Array( $out );
-       }
-
-       /**
-        * Virtual implode with brackets
-        *
-        * @param string $start
-        * @param string $sep
-        * @param string $end
-        * @param string|PPNode $args,...
-        * @return PPNode_Hash_Array
-        */
-       public function virtualBracketedImplode( $start, $sep, $end /*, ... */ ) {
-               $args = array_slice( func_get_args(), 3 );
-               $out = [ $start ];
-               $first = true;
-
-               foreach ( $args as $root ) {
-                       if ( $root instanceof PPNode_Hash_Array ) {
-                               $root = $root->value;
-                       }
-                       if ( !is_array( $root ) ) {
-                               $root = [ $root ];
-                       }
-                       foreach ( $root as $node ) {
-                               if ( $first ) {
-                                       $first = false;
-                               } else {
-                                       $out[] = $sep;
-                               }
-                               $out[] = $node;
-                       }
-               }
-               $out[] = $end;
-               return new PPNode_Hash_Array( $out );
-       }
-
-       public function __toString() {
-               return 'frame{}';
-       }
-
-       /**
-        * @param bool $level
-        * @return array|bool|string
-        */
-       public function getPDBK( $level = false ) {
-               if ( $level === false ) {
-                       return $this->title->getPrefixedDBkey();
-               } else {
-                       return $this->titleCache[$level] ?? false;
-               }
-       }
-
-       /**
-        * @return array
-        */
-       public function getArguments() {
-               return [];
-       }
-
-       /**
-        * @return array
-        */
-       public function getNumberedArguments() {
-               return [];
-       }
-
-       /**
-        * @return array
-        */
-       public function getNamedArguments() {
-               return [];
-       }
-
-       /**
-        * Returns true if there are no arguments in this frame
-        *
-        * @return bool
-        */
-       public function isEmpty() {
-               return true;
-       }
-
-       /**
-        * @param int|string $name
-        * @return bool Always false in this implementation.
-        */
-       public function getArgument( $name ) {
-               return false;
-       }
-
-       /**
-        * Returns true if the infinite loop check is OK, false if a loop is detected
-        *
-        * @param Title $title
-        *
-        * @return bool
-        */
-       public function loopCheck( $title ) {
-               return !isset( $this->loopCheckHash[$title->getPrefixedDBkey()] );
-       }
-
-       /**
-        * Return true if the frame is a template frame
-        *
-        * @return bool
-        */
-       public function isTemplate() {
-               return false;
-       }
-
-       /**
-        * Get a title of frame
-        *
-        * @return Title
-        */
-       public function getTitle() {
-               return $this->title;
-       }
-
-       /**
-        * Set the volatile flag
-        *
-        * @param bool $flag
-        */
-       public function setVolatile( $flag = true ) {
-               $this->volatile = $flag;
-       }
-
-       /**
-        * Get the volatile flag
-        *
-        * @return bool
-        */
-       public function isVolatile() {
-               return $this->volatile;
-       }
-
-       /**
-        * Set the TTL
-        *
-        * @param int $ttl
-        */
-       public function setTTL( $ttl ) {
-               if ( $ttl !== null && ( $this->ttl === null || $ttl < $this->ttl ) ) {
-                       $this->ttl = $ttl;
-               }
-       }
-
-       /**
-        * Get the TTL
-        *
-        * @return int|null
-        */
-       public function getTTL() {
-               return $this->ttl;
-       }
-}
-
-/**
- * Expansion frame with template arguments
- * @ingroup Parser
- */
-// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
-class PPTemplateFrame_Hash extends PPFrame_Hash {
-
-       public $numberedArgs, $namedArgs, $parent;
-       public $numberedExpansionCache, $namedExpansionCache;
-
-       /**
-        * @param Preprocessor $preprocessor
-        * @param bool|PPFrame $parent
-        * @param array $numberedArgs
-        * @param array $namedArgs
-        * @param bool|Title $title
-        */
-       public function __construct( $preprocessor, $parent = false, $numberedArgs = [],
-               $namedArgs = [], $title = false
-       ) {
-               parent::__construct( $preprocessor );
-
-               $this->parent = $parent;
-               $this->numberedArgs = $numberedArgs;
-               $this->namedArgs = $namedArgs;
-               $this->title = $title;
-               $pdbk = $title ? $title->getPrefixedDBkey() : false;
-               $this->titleCache = $parent->titleCache;
-               $this->titleCache[] = $pdbk;
-               $this->loopCheckHash = /*clone*/ $parent->loopCheckHash;
-               if ( $pdbk !== false ) {
-                       $this->loopCheckHash[$pdbk] = true;
-               }
-               $this->depth = $parent->depth + 1;
-               $this->numberedExpansionCache = $this->namedExpansionCache = [];
-       }
-
-       public function __toString() {
-               $s = 'tplframe{';
-               $first = true;
-               $args = $this->numberedArgs + $this->namedArgs;
-               foreach ( $args as $name => $value ) {
-                       if ( $first ) {
-                               $first = false;
-                       } else {
-                               $s .= ', ';
-                       }
-                       $s .= "\"$name\":\"" .
-                               str_replace( '"', '\\"', $value->__toString() ) . '"';
-               }
-               $s .= '}';
-               return $s;
-       }
-
-       /**
-        * @throws MWException
-        * @param string|int $key
-        * @param string|PPNode $root
-        * @param int $flags
-        * @return string
-        */
-       public function cachedExpand( $key, $root, $flags = 0 ) {
-               if ( isset( $this->parent->childExpansionCache[$key] ) ) {
-                       return $this->parent->childExpansionCache[$key];
-               }
-               $retval = $this->expand( $root, $flags );
-               if ( !$this->isVolatile() ) {
-                       $this->parent->childExpansionCache[$key] = $retval;
-               }
-               return $retval;
-       }
-
-       /**
-        * Returns true if there are no arguments in this frame
-        *
-        * @return bool
-        */
-       public function isEmpty() {
-               return !count( $this->numberedArgs ) && !count( $this->namedArgs );
-       }
-
-       /**
-        * @return array
-        */
-       public function getArguments() {
-               $arguments = [];
-               foreach ( array_merge(
-                               array_keys( $this->numberedArgs ),
-                               array_keys( $this->namedArgs ) ) as $key ) {
-                       $arguments[$key] = $this->getArgument( $key );
-               }
-               return $arguments;
-       }
-
-       /**
-        * @return array
-        */
-       public function getNumberedArguments() {
-               $arguments = [];
-               foreach ( array_keys( $this->numberedArgs ) as $key ) {
-                       $arguments[$key] = $this->getArgument( $key );
-               }
-               return $arguments;
-       }
-
-       /**
-        * @return array
-        */
-       public function getNamedArguments() {
-               $arguments = [];
-               foreach ( array_keys( $this->namedArgs ) as $key ) {
-                       $arguments[$key] = $this->getArgument( $key );
-               }
-               return $arguments;
-       }
-
-       /**
-        * @param int $index
-        * @return string|bool
-        */
-       public function getNumberedArgument( $index ) {
-               if ( !isset( $this->numberedArgs[$index] ) ) {
-                       return false;
-               }
-               if ( !isset( $this->numberedExpansionCache[$index] ) ) {
-                       # No trimming for unnamed arguments
-                       $this->numberedExpansionCache[$index] = $this->parent->expand(
-                               $this->numberedArgs[$index],
-                               PPFrame::STRIP_COMMENTS
-                       );
-               }
-               return $this->numberedExpansionCache[$index];
-       }
-
-       /**
-        * @param string $name
-        * @return string|bool
-        */
-       public function getNamedArgument( $name ) {
-               if ( !isset( $this->namedArgs[$name] ) ) {
-                       return false;
-               }
-               if ( !isset( $this->namedExpansionCache[$name] ) ) {
-                       # Trim named arguments post-expand, for backwards compatibility
-                       $this->namedExpansionCache[$name] = trim(
-                               $this->parent->expand( $this->namedArgs[$name], PPFrame::STRIP_COMMENTS ) );
-               }
-               return $this->namedExpansionCache[$name];
-       }
-
-       /**
-        * @param int|string $name
-        * @return string|bool
-        */
-       public function getArgument( $name ) {
-               $text = $this->getNumberedArgument( $name );
-               if ( $text === false ) {
-                       $text = $this->getNamedArgument( $name );
-               }
-               return $text;
-       }
-
-       /**
-        * Return true if the frame is a template frame
-        *
-        * @return bool
-        */
-       public function isTemplate() {
-               return true;
-       }
-
-       public function setVolatile( $flag = true ) {
-               parent::setVolatile( $flag );
-               $this->parent->setVolatile( $flag );
-       }
-
-       public function setTTL( $ttl ) {
-               parent::setTTL( $ttl );
-               $this->parent->setTTL( $ttl );
-       }
-}
-
-/**
- * Expansion frame with custom arguments
- * @ingroup Parser
- */
-// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
-class PPCustomFrame_Hash extends PPFrame_Hash {
-
-       public $args;
-
-       public function __construct( $preprocessor, $args ) {
-               parent::__construct( $preprocessor );
-               $this->args = $args;
-       }
-
-       public function __toString() {
-               $s = 'cstmframe{';
-               $first = true;
-               foreach ( $this->args as $name => $value ) {
-                       if ( $first ) {
-                               $first = false;
-                       } else {
-                               $s .= ', ';
-                       }
-                       $s .= "\"$name\":\"" .
-                               str_replace( '"', '\\"', $value->__toString() ) . '"';
-               }
-               $s .= '}';
-               return $s;
-       }
-
-       /**
-        * @return bool
-        */
-       public function isEmpty() {
-               return !count( $this->args );
-       }
-
-       /**
-        * @param int|string $index
-        * @return string|bool
-        */
-       public function getArgument( $index ) {
-               return $this->args[$index] ?? false;
-       }
-
-       public function getArguments() {
-               return $this->args;
-       }
-}
-
-/**
- * @ingroup Parser
- */
-// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
-class PPNode_Hash_Tree implements PPNode {
-
-       public $name;
-
-       /**
-        * The store array for children of this node. It is "raw" in the sense that
-        * nodes are two-element arrays ("descriptors") rather than PPNode_Hash_*
-        * objects.
-        */
-       private $rawChildren;
-
-       /**
-        * The store array for the siblings of this node, including this node itself.
-        */
-       private $store;
-
-       /**
-        * The index into $this->store which contains the descriptor of this node.
-        */
-       private $index;
-
-       /**
-        * The offset of the name within descriptors, used in some places for
-        * readability.
-        */
-       const NAME = 0;
-
-       /**
-        * The offset of the child list within descriptors, used in some places for
-        * readability.
-        */
-       const CHILDREN = 1;
-
-       /**
-        * Construct an object using the data from $store[$index]. The rest of the
-        * store array can be accessed via getNextSibling().
-        *
-        * @param array $store
-        * @param int $index
-        */
-       public function __construct( array $store, $index ) {
-               $this->store = $store;
-               $this->index = $index;
-               list( $this->name, $this->rawChildren ) = $this->store[$index];
-       }
-
-       /**
-        * Construct an appropriate PPNode_Hash_* object with a class that depends
-        * on what is at the relevant store index.
-        *
-        * @param array $store
-        * @param int $index
-        * @return PPNode_Hash_Tree|PPNode_Hash_Attr|PPNode_Hash_Text
-        */
-       public static function factory( array $store, $index ) {
-               if ( !isset( $store[$index] ) ) {
-                       return false;
-               }
-
-               $descriptor = $store[$index];
-               if ( is_string( $descriptor ) ) {
-                       $class = PPNode_Hash_Text::class;
-               } elseif ( is_array( $descriptor ) ) {
-                       if ( $descriptor[self::NAME][0] === '@' ) {
-                               $class = PPNode_Hash_Attr::class;
-                       } else {
-                               $class = self::class;
-                       }
-               } else {
-                       throw new MWException( __METHOD__ . ': invalid node descriptor' );
-               }
-               return new $class( $store, $index );
-       }
-
-       /**
-        * Convert a node to XML, for debugging
-        */
-       public function __toString() {
-               $inner = '';
-               $attribs = '';
-               for ( $node = $this->getFirstChild(); $node; $node = $node->getNextSibling() ) {
-                       if ( $node instanceof PPNode_Hash_Attr ) {
-                               $attribs .= ' ' . $node->name . '="' . htmlspecialchars( $node->value ) . '"';
-                       } else {
-                               $inner .= $node->__toString();
-                       }
-               }
-               if ( $inner === '' ) {
-                       return "<{$this->name}$attribs/>";
-               } else {
-                       return "<{$this->name}$attribs>$inner</{$this->name}>";
-               }
-       }
-
-       /**
-        * @return PPNode_Hash_Array
-        */
-       public function getChildren() {
-               $children = [];
-               foreach ( $this->rawChildren as $i => $child ) {
-                       $children[] = self::factory( $this->rawChildren, $i );
-               }
-               return new PPNode_Hash_Array( $children );
-       }
-
-       /**
-        * Get the first child, or false if there is none. Note that this will
-        * return a temporary proxy object: different instances will be returned
-        * if this is called more than once on the same node.
-        *
-        * @return PPNode_Hash_Tree|PPNode_Hash_Attr|PPNode_Hash_Text|bool
-        */
-       public function getFirstChild() {
-               if ( !isset( $this->rawChildren[0] ) ) {
-                       return false;
-               } else {
-                       return self::factory( $this->rawChildren, 0 );
-               }
-       }
-
-       /**
-        * Get the next sibling, or false if there is none. Note that this will
-        * return a temporary proxy object: different instances will be returned
-        * if this is called more than once on the same node.
-        *
-        * @return PPNode_Hash_Tree|PPNode_Hash_Attr|PPNode_Hash_Text|bool
-        */
-       public function getNextSibling() {
-               return self::factory( $this->store, $this->index + 1 );
-       }
-
-       /**
-        * Get an array of the children with a given node name
-        *
-        * @param string $name
-        * @return PPNode_Hash_Array
-        */
-       public function getChildrenOfType( $name ) {
-               $children = [];
-               foreach ( $this->rawChildren as $i => $child ) {
-                       if ( is_array( $child ) && $child[self::NAME] === $name ) {
-                               $children[] = self::factory( $this->rawChildren, $i );
-                       }
-               }
-               return new PPNode_Hash_Array( $children );
-       }
-
-       /**
-        * Get the raw child array. For internal use.
-        * @return array
-        */
-       public function getRawChildren() {
-               return $this->rawChildren;
-       }
-
-       /**
-        * @return bool
-        */
-       public function getLength() {
-               return false;
-       }
-
-       /**
-        * @param int $i
-        * @return bool
-        */
-       public function item( $i ) {
-               return false;
-       }
-
-       /**
-        * @return string
-        */
-       public function getName() {
-               return $this->name;
-       }
-
-       /**
-        * Split a "<part>" node into an associative array containing:
-        *  - name          PPNode name
-        *  - index         String index
-        *  - value         PPNode value
-        *
-        * @throws MWException
-        * @return array
-        */
-       public function splitArg() {
-               return self::splitRawArg( $this->rawChildren );
-       }
-
-       /**
-        * Like splitArg() but for a raw child array. For internal use only.
-        * @param array $children
-        * @return array
-        */
-       public static function splitRawArg( array $children ) {
-               $bits = [];
-               foreach ( $children as $i => $child ) {
-                       if ( !is_array( $child ) ) {
-                               continue;
-                       }
-                       if ( $child[self::NAME] === 'name' ) {
-                               $bits['name'] = new self( $children, $i );
-                               if ( isset( $child[self::CHILDREN][0][self::NAME] )
-                                       && $child[self::CHILDREN][0][self::NAME] === '@index'
-                               ) {
-                                       $bits['index'] = $child[self::CHILDREN][0][self::CHILDREN][0];
-                               }
-                       } elseif ( $child[self::NAME] === 'value' ) {
-                               $bits['value'] = new self( $children, $i );
-                       }
-               }
-
-               if ( !isset( $bits['name'] ) ) {
-                       throw new MWException( 'Invalid brace node passed to ' . __METHOD__ );
-               }
-               if ( !isset( $bits['index'] ) ) {
-                       $bits['index'] = '';
-               }
-               return $bits;
-       }
-
-       /**
-        * Split an "<ext>" node into an associative array containing name, attr, inner and close
-        * All values in the resulting array are PPNodes. Inner and close are optional.
-        *
-        * @throws MWException
-        * @return array
-        */
-       public function splitExt() {
-               return self::splitRawExt( $this->rawChildren );
-       }
-
-       /**
-        * Like splitExt() but for a raw child array. For internal use only.
-        * @param array $children
-        * @return array
-        */
-       public static function splitRawExt( array $children ) {
-               $bits = [];
-               foreach ( $children as $i => $child ) {
-                       if ( !is_array( $child ) ) {
-                               continue;
-                       }
-                       switch ( $child[self::NAME] ) {
-                               case 'name':
-                                       $bits['name'] = new self( $children, $i );
-                                       break;
-                               case 'attr':
-                                       $bits['attr'] = new self( $children, $i );
-                                       break;
-                               case 'inner':
-                                       $bits['inner'] = new self( $children, $i );
-                                       break;
-                               case 'close':
-                                       $bits['close'] = new self( $children, $i );
-                                       break;
-                       }
-               }
-               if ( !isset( $bits['name'] ) ) {
-                       throw new MWException( 'Invalid ext node passed to ' . __METHOD__ );
-               }
-               return $bits;
-       }
-
-       /**
-        * Split an "<h>" node
-        *
-        * @throws MWException
-        * @return array
-        */
-       public function splitHeading() {
-               if ( $this->name !== 'h' ) {
-                       throw new MWException( 'Invalid h node passed to ' . __METHOD__ );
-               }
-               return self::splitRawHeading( $this->rawChildren );
-       }
-
-       /**
-        * Like splitHeading() but for a raw child array. For internal use only.
-        * @param array $children
-        * @return array
-        */
-       public static function splitRawHeading( array $children ) {
-               $bits = [];
-               foreach ( $children as $i => $child ) {
-                       if ( !is_array( $child ) ) {
-                               continue;
-                       }
-                       if ( $child[self::NAME] === '@i' ) {
-                               $bits['i'] = $child[self::CHILDREN][0];
-                       } elseif ( $child[self::NAME] === '@level' ) {
-                               $bits['level'] = $child[self::CHILDREN][0];
-                       }
-               }
-               if ( !isset( $bits['i'] ) ) {
-                       throw new MWException( 'Invalid h node passed to ' . __METHOD__ );
-               }
-               return $bits;
-       }
-
-       /**
-        * Split a "<template>" or "<tplarg>" node
-        *
-        * @throws MWException
-        * @return array
-        */
-       public function splitTemplate() {
-               return self::splitRawTemplate( $this->rawChildren );
-       }
-
-       /**
-        * Like splitTemplate() but for a raw child array. For internal use only.
-        * @param array $children
-        * @return array
-        */
-       public static function splitRawTemplate( array $children ) {
-               $parts = [];
-               $bits = [ 'lineStart' => '' ];
-               foreach ( $children as $i => $child ) {
-                       if ( !is_array( $child ) ) {
-                               continue;
-                       }
-                       switch ( $child[self::NAME] ) {
-                               case 'title':
-                                       $bits['title'] = new self( $children, $i );
-                                       break;
-                               case 'part':
-                                       $parts[] = new self( $children, $i );
-                                       break;
-                               case '@lineStart':
-                                       $bits['lineStart'] = '1';
-                                       break;
-                       }
-               }
-               if ( !isset( $bits['title'] ) ) {
-                       throw new MWException( 'Invalid node passed to ' . __METHOD__ );
-               }
-               $bits['parts'] = new PPNode_Hash_Array( $parts );
-               return $bits;
-       }
-}
-
-/**
- * @ingroup Parser
- */
-// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
-class PPNode_Hash_Text implements PPNode {
-
-       public $value;
-       private $store, $index;
-
-       /**
-        * Construct an object using the data from $store[$index]. The rest of the
-        * store array can be accessed via getNextSibling().
-        *
-        * @param array $store
-        * @param int $index
-        */
-       public function __construct( array $store, $index ) {
-               $this->value = $store[$index];
-               if ( !is_scalar( $this->value ) ) {
-                       throw new MWException( __CLASS__ . ' given object instead of string' );
-               }
-               $this->store = $store;
-               $this->index = $index;
-       }
-
-       public function __toString() {
-               return htmlspecialchars( $this->value );
-       }
-
-       public function getNextSibling() {
-               return PPNode_Hash_Tree::factory( $this->store, $this->index + 1 );
-       }
-
-       public function getChildren() {
-               return false;
-       }
-
-       public function getFirstChild() {
-               return false;
-       }
-
-       public function getChildrenOfType( $name ) {
-               return false;
-       }
-
-       public function getLength() {
-               return false;
-       }
-
-       public function item( $i ) {
-               return false;
-       }
-
-       public function getName() {
-               return '#text';
-       }
-
-       public function splitArg() {
-               throw new MWException( __METHOD__ . ': not supported' );
-       }
-
-       public function splitExt() {
-               throw new MWException( __METHOD__ . ': not supported' );
-       }
-
-       public function splitHeading() {
-               throw new MWException( __METHOD__ . ': not supported' );
-       }
-}
-
-/**
- * @ingroup Parser
- */
-// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
-class PPNode_Hash_Array implements PPNode {
-
-       public $value;
-
-       public function __construct( $value ) {
-               $this->value = $value;
-       }
-
-       public function __toString() {
-               return var_export( $this, true );
-       }
-
-       public function getLength() {
-               return count( $this->value );
-       }
-
-       public function item( $i ) {
-               return $this->value[$i];
-       }
-
-       public function getName() {
-               return '#nodelist';
-       }
-
-       public function getNextSibling() {
-               return false;
-       }
-
-       public function getChildren() {
-               return false;
-       }
-
-       public function getFirstChild() {
-               return false;
-       }
-
-       public function getChildrenOfType( $name ) {
-               return false;
-       }
-
-       public function splitArg() {
-               throw new MWException( __METHOD__ . ': not supported' );
-       }
-
-       public function splitExt() {
-               throw new MWException( __METHOD__ . ': not supported' );
-       }
-
-       public function splitHeading() {
-               throw new MWException( __METHOD__ . ': not supported' );
-       }
-}
-
-/**
- * @ingroup Parser
- */
-// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
-class PPNode_Hash_Attr implements PPNode {
-
-       public $name, $value;
-       private $store, $index;
-
-       /**
-        * Construct an object using the data from $store[$index]. The rest of the
-        * store array can be accessed via getNextSibling().
-        *
-        * @param array $store
-        * @param int $index
-        */
-       public function __construct( array $store, $index ) {
-               $descriptor = $store[$index];
-               if ( $descriptor[PPNode_Hash_Tree::NAME][0] !== '@' ) {
-                       throw new MWException( __METHOD__ . ': invalid name in attribute descriptor' );
-               }
-               $this->name = substr( $descriptor[PPNode_Hash_Tree::NAME], 1 );
-               $this->value = $descriptor[PPNode_Hash_Tree::CHILDREN][0];
-               $this->store = $store;
-               $this->index = $index;
-       }
-
-       public function __toString() {
-               return "<@{$this->name}>" . htmlspecialchars( $this->value ) . "</@{$this->name}>";
-       }
-
-       public function getName() {
-               return $this->name;
-       }
-
-       public function getNextSibling() {
-               return PPNode_Hash_Tree::factory( $this->store, $this->index + 1 );
-       }
-
-       public function getChildren() {
-               return false;
-       }
-
-       public function getFirstChild() {
-               return false;
-       }
-
-       public function getChildrenOfType( $name ) {
-               return false;
-       }
-
-       public function getLength() {
-               return false;
-       }
-
-       public function item( $i ) {
-               return false;
-       }
-
-       public function splitArg() {
-               throw new MWException( __METHOD__ . ': not supported' );
-       }
-
-       public function splitExt() {
-               throw new MWException( __METHOD__ . ': not supported' );
-       }
-
-       public function splitHeading() {
-               throw new MWException( __METHOD__ . ': not supported' );
-       }
-}
index 2d75c86..cb85627 100644 (file)
@@ -9,6 +9,7 @@ use RemexHtml\Tokenizer\Tokenizer;
  */
 class RemexStripTagHandler implements TokenHandler {
        private $text = '';
+
        public function getResult() {
                return $this->text;
        }
@@ -16,15 +17,19 @@ class RemexStripTagHandler implements TokenHandler {
        function startDocument( Tokenizer $t, $fns, $fn ) {
                // Do nothing.
        }
+
        function endDocument( $pos ) {
                // Do nothing.
        }
+
        function error( $text, $pos ) {
                // Do nothing.
        }
+
        function characters( $text, $start, $length, $sourceStart, $sourceLength ) {
                $this->text .= substr( $text, $start, $length );
        }
+
        function startTag( $name, Attributes $attrs, $selfClose, $sourceStart, $sourceLength ) {
                // Inject whitespace for typical block-level tags to
                // prevent merging unrelated<br>words.
@@ -32,6 +37,7 @@ class RemexStripTagHandler implements TokenHandler {
                        $this->text .= ' ';
                }
        }
+
        function endTag( $name, $sourceStart, $sourceLength ) {
                // Inject whitespace for typical block-level tags to
                // prevent merging unrelated<br>words.
@@ -39,9 +45,11 @@ class RemexStripTagHandler implements TokenHandler {
                        $this->text .= ' ';
                }
        }
+
        function doctype( $name, $public, $system, $quirks, $sourceStart, $sourceLength ) {
                // Do nothing.
        }
+
        function comment( $text, $sourceStart, $sourceLength ) {
                // Do nothing.
        }
index 0aa58c1..abf0714 100644 (file)
@@ -578,10 +578,8 @@ class Sanitizer {
                                                                        $badtag = true;
                                                                }
                                                        }
-                                               } else {
-                                                       if ( $t == 'table' ) {
-                                                               $tagstack = array_pop( $tablestack );
-                                                       }
+                                               } elseif ( $t == 'table' ) {
+                                                       $tagstack = array_pop( $tablestack );
                                                }
                                                $newparams = '';
                                        } else {
@@ -1920,7 +1918,8 @@ class Sanitizer {
                        # such as <math> when it is rasterized, or if $wgAllowImageTag is
                        # true
                        'img'        => array_merge( $common, [ 'alt', 'src', 'width', 'height', 'srcset' ] ),
-
+                       # Attributes for A/V tags added in T163583 / T133673
+                       'audio'      => array_merge( $common, [ 'controls', 'preload', 'width', 'height' ] ),
                        'video'      => array_merge( $common, [ 'poster', 'controls', 'preload', 'width', 'height' ] ),
                        'source'     => array_merge( $common, [ 'type', 'src' ] ),
                        'track'      => array_merge( $common, [ 'type', 'src', 'srclang', 'kind', 'label' ] ),
@@ -1958,6 +1957,7 @@ class Sanitizer {
 
                        // HTML 5 section 4.5
                        'figure'     => $common,
+                       'figure-inline' => $common, # T118520
                        'figcaption' => $common,
 
                        # HTML 5 section 4.6
index 9138c33..c03da3b 100644 (file)
@@ -81,6 +81,8 @@ class Argon2Password extends Password {
         * @inheritDoc
         */
        public function equals( $other ) {
+               wfDeprecated( __METHOD__, '1.33' );
+
                if ( is_string( $other ) ) {
                        return $this->verify( $other );
                }
index 978118f..105937c 100644 (file)
@@ -38,6 +38,8 @@ class InvalidPassword extends Password {
        }
 
        public function equals( $other ) {
+               wfDeprecated( __METHOD__, '1.33' );
+
                return false;
        }
 
index 4caff8e..342995a 100644 (file)
@@ -155,11 +155,14 @@ abstract class Password {
         * custom comparison, but it is not recommended unless necessary.
         *
         * @deprecated since 1.33, use verify()
+        * @codeCoverageIgnore
         *
         * @param Password|string $other The other password
         * @return bool True if equal, false otherwise
         */
        public function equals( $other ) {
+               wfDeprecated( __METHOD__, '1.33' );
+
                if ( is_string( $other ) ) {
                        return $this->verify( $other );
                }
index ba0b4cb..060faec 100644 (file)
@@ -39,7 +39,7 @@
  * that start with "nowait:". However, only 0 timeouts (non-blocking requests)
  * can be used with "nowait:" keys.
  *
- * By default PoolCounter_Stub is used, which provides no locking. You
+ * By default PoolCounterNull is used, which provides no locking. You
  * can get a useful one in the PoolCounter extension.
  */
 abstract class PoolCounter {
@@ -111,7 +111,7 @@ abstract class PoolCounter {
        public static function factory( $type, $key ) {
                global $wgPoolCounterConf;
                if ( !isset( $wgPoolCounterConf[$type] ) ) {
-                       return new PoolCounter_Stub;
+                       return new PoolCounterNull;
                }
                $conf = $wgPoolCounterConf[$type];
                $class = $conf['class'];
@@ -208,23 +208,3 @@ abstract class PoolCounter {
                return $type . ':' . ( hexdec( substr( sha1( $key ), 0, 4 ) ) % $slots );
        }
 }
-
-// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
-class PoolCounter_Stub extends PoolCounter {
-
-       public function __construct() {
-               /* No parameters needed */
-       }
-
-       public function acquireForMe() {
-               return Status::newGood( PoolCounter::LOCKED );
-       }
-
-       public function acquireForAnyone() {
-               return Status::newGood( PoolCounter::LOCKED );
-       }
-
-       public function release() {
-               return Status::newGood( PoolCounter::RELEASED );
-       }
-}
diff --git a/includes/poolcounter/PoolCounterNull.php b/includes/poolcounter/PoolCounterNull.php
new file mode 100644 (file)
index 0000000..95a5057
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+/**
+ * Provides of semaphore semantics for restricting the number
+ * of workers that may be concurrently performing the same task.
+ *
+ * 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
+ */
+
+/**
+ * A default PoolCounter, which provides no locking.
+ */
+class PoolCounterNull extends PoolCounter {
+
+       public function __construct() {
+               /* No parameters needed */
+       }
+
+       public function acquireForMe() {
+               return Status::newGood( PoolCounter::LOCKED );
+       }
+
+       public function acquireForAnyone() {
+               return Status::newGood( PoolCounter::LOCKED );
+       }
+
+       public function release() {
+               return Status::newGood( PoolCounter::RELEASED );
+       }
+}
index 2c9fbc8..0abe1a5 100644 (file)
@@ -114,7 +114,9 @@ class PoolWorkArticleView extends PoolCounterWork {
                $this->revision = $revision;
                $this->audience = $audience;
                $this->cacheKey = $this->parserCache->getKey( $page, $parserOptions );
-               $keyPrefix = $this->cacheKey ?: wfMemcKey( 'articleview', 'missingcachekey' );
+               $keyPrefix = $this->cacheKey ?: ObjectCache::getLocalClusterInstance()->makeKey(
+                       'articleview', 'missingcachekey'
+               );
 
                parent::__construct( 'ArticleView', $keyPrefix . ':revid:' . $revid );
        }
index 3651882..b18088f 100644 (file)
@@ -34,16 +34,17 @@ use LanguageCode;
 use LanguageConverter;
 use MediaWiki\Auth\AuthManager;
 use MediaWiki\Auth\PasswordAuthenticationRequest;
+use MediaWiki\Config\ServiceOptions;
 use MediaWiki\Linker\LinkRenderer;
 use MediaWiki\MediaWikiServices;
 use MessageLocalizer;
 use MWException;
-use MWNamespace;
 use MWTimestamp;
+use NamespaceInfo;
 use OutputPage;
 use Parser;
 use ParserOptions;
-use PreferencesFormLegacy;
+use PreferencesFormOOUI;
 use Psr\Log\LoggerAwareTrait;
 use Psr\Log\NullLogger;
 use Skin;
@@ -61,8 +62,8 @@ use Xml;
 class DefaultPreferencesFactory implements PreferencesFactory {
        use LoggerAwareTrait;
 
-       /** @var Config */
-       protected $config;
+       /** @var ServiceOptions */
+       protected $options;
 
        /** @var Language The wiki's content language. */
        protected $contLang;
@@ -73,22 +74,74 @@ class DefaultPreferencesFactory implements PreferencesFactory {
        /** @var LinkRenderer */
        protected $linkRenderer;
 
+       /** @var NamespaceInfo */
+       protected $nsInfo;
+
        /**
-        * @param Config $config
+        * TODO Make this a const when we drop HHVM support (T192166)
+        *
+        * @var array
+        * @since 1.34
+        */
+       public static $constructorOptions = [
+               'AllowUserCss',
+               'AllowUserCssPrefs',
+               'AllowUserJs',
+               'DefaultSkin',
+               'DisableLangConversion',
+               'EmailAuthentication',
+               'EmailConfirmToEdit',
+               'EnableEmail',
+               'EnableUserEmail',
+               'EnableUserEmailBlacklist',
+               'EnotifMinorEdits',
+               'EnotifRevealEditorAddress',
+               'EnotifUserTalk',
+               'EnotifWatchlist',
+               'HiddenPrefs',
+               'ImageLimits',
+               'LanguageCode',
+               'LocalTZoffset',
+               'MaxSigChars',
+               'RCMaxAge',
+               'RCShowWatchingUsers',
+               'RCWatchCategoryMembership',
+               'SecureLogin',
+               'ThumbLimits',
+       ];
+
+       /**
+        * Do not call this directly.  Get it from MediaWikiServices.
+        *
+        * @param array|Config $options Config accepted for backwards compatibility
         * @param Language $contLang
         * @param AuthManager $authManager
         * @param LinkRenderer $linkRenderer
+        * @param NamespaceInfo|null $nsInfo
         */
        public function __construct(
-               Config $config,
+               $options,
                Language $contLang,
                AuthManager $authManager,
-               LinkRenderer $linkRenderer
+               LinkRenderer $linkRenderer,
+               NamespaceInfo $nsInfo = null
        ) {
-               $this->config = $config;
+               if ( $options instanceof Config ) {
+                       wfDeprecated( __METHOD__ . ' with Config parameter', '1.34' );
+                       $options = new ServiceOptions( self::$constructorOptions, $options );
+               }
+
+               $options->assertRequiredOptions( self::$constructorOptions );
+
+               if ( !$nsInfo ) {
+                       wfDeprecated( __METHOD__ . ' with no NamespaceInfo argument', '1.34' );
+                       $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
+               }
+               $this->options = $options;
                $this->contLang = $contLang;
                $this->authManager = $authManager;
                $this->linkRenderer = $linkRenderer;
+               $this->nsInfo = $nsInfo;
                $this->logger = new NullLogger();
        }
 
@@ -121,7 +174,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                $this->skinPreferences( $user, $context, $preferences );
                $this->datetimePreferences( $user, $context, $preferences );
                $this->filesPreferences( $context, $preferences );
-               $this->renderingPreferences( $context, $preferences );
+               $this->renderingPreferences( $user, $context, $preferences );
                $this->editingPreferences( $user, $context, $preferences );
                $this->rcPreferences( $user, $context, $preferences );
                $this->watchlistPreferences( $user, $context, $preferences );
@@ -146,7 +199,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                User $user, IContextSource $context, &$defaultPreferences
        ) {
                # # Remove preferences that wikis don't want to use
-               foreach ( $this->config->get( 'HiddenPrefs' ) as $pref ) {
+               foreach ( $this->options->get( 'HiddenPrefs' ) as $pref ) {
                        if ( isset( $defaultPreferences[$pref] ) ) {
                                unset( $defaultPreferences[$pref] );
                        }
@@ -364,7 +417,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                        ];
                }
                // Only show prefershttps if secure login is turned on
-               if ( $this->config->get( 'SecureLogin' ) && $canIPUseHTTPS ) {
+               if ( $this->options->get( 'SecureLogin' ) && $canIPUseHTTPS ) {
                        $defaultPreferences['prefershttps'] = [
                                'type' => 'toggle',
                                'label-message' => 'tog-prefershttps',
@@ -374,7 +427,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                }
 
                $languages = Language::fetchLanguageNames( null, 'mwfile' );
-               $languageCode = $this->config->get( 'LanguageCode' );
+               $languageCode = $this->options->get( 'LanguageCode' );
                if ( !array_key_exists( $languageCode, $languages ) ) {
                        $languages[$languageCode] = $languageCode;
                        // Sort the array again
@@ -408,7 +461,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                ];
 
                // see if there are multiple language variants to choose from
-               if ( !$this->config->get( 'DisableLangConversion' ) ) {
+               if ( !$this->options->get( 'DisableLangConversion' ) ) {
                        foreach ( LanguageConverter::$languagesWithVariants as $langCode ) {
                                if ( $langCode == $this->contLang->getCode() ) {
                                        if ( !$this->contLang->hasVariants() ) {
@@ -474,7 +527,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                ];
                $defaultPreferences['nickname'] = [
                        'type' => $this->authManager->allowsPropertyChange( 'nickname' ) ? 'text' : 'info',
-                       'maxlength' => $this->config->get( 'MaxSigChars' ),
+                       'maxlength' => $this->options->get( 'MaxSigChars' ),
                        'label-message' => 'yournick',
                        'validation-callback' => function ( $signature, $alldata, HTMLForm $form ) {
                                return $this->validateSignature( $signature, $alldata, $form );
@@ -494,13 +547,13 @@ class DefaultPreferencesFactory implements PreferencesFactory {
 
                # # Email stuff
 
-               if ( $this->config->get( 'EnableEmail' ) ) {
+               if ( $this->options->get( 'EnableEmail' ) ) {
                        if ( $canViewPrivateInfo ) {
-                               $helpMessages[] = $this->config->get( 'EmailConfirmToEdit' )
+                               $helpMessages[] = $this->options->get( 'EmailConfirmToEdit' )
                                                ? 'prefs-help-email-required'
                                                : 'prefs-help-email';
 
-                               if ( $this->config->get( 'EnableUserEmail' ) ) {
+                               if ( $this->options->get( 'EnableUserEmail' ) ) {
                                        // additional messages when users can send email to each other
                                        $helpMessages[] = 'prefs-help-email-others';
                                }
@@ -531,7 +584,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
 
                        $disableEmailPrefs = false;
 
-                       if ( $this->config->get( 'EmailAuthentication' ) ) {
+                       if ( $this->options->get( 'EmailAuthentication' ) ) {
                                $emailauthenticationclass = 'mw-email-not-authenticated';
                                if ( $user->getEmail() ) {
                                        if ( $user->getEmailAuthenticationTimestamp() ) {
@@ -575,7 +628,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                                }
                        }
 
-                       if ( $this->config->get( 'EnableUserEmail' ) && $user->isAllowed( 'sendemail' ) ) {
+                       if ( $this->options->get( 'EnableUserEmail' ) && $user->isAllowed( 'sendemail' ) ) {
                                $defaultPreferences['disablemail'] = [
                                        'id' => 'wpAllowEmail',
                                        'type' => 'toggle',
@@ -600,7 +653,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                                        'disabled' => $disableEmailPrefs,
                                ];
 
-                               if ( $this->config->get( 'EnableUserEmailBlacklist' ) ) {
+                               if ( $this->options->get( 'EnableUserEmailBlacklist' ) ) {
                                        $defaultPreferences['email-blacklist'] = [
                                                'type' => 'usersmultiselect',
                                                'label-message' => 'email-blacklist-label',
@@ -611,7 +664,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                                }
                        }
 
-                       if ( $this->config->get( 'EnotifWatchlist' ) ) {
+                       if ( $this->options->get( 'EnotifWatchlist' ) ) {
                                $defaultPreferences['enotifwatchlistpages'] = [
                                        'type' => 'toggle',
                                        'section' => 'personal/email',
@@ -619,7 +672,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                                        'disabled' => $disableEmailPrefs,
                                ];
                        }
-                       if ( $this->config->get( 'EnotifUserTalk' ) ) {
+                       if ( $this->options->get( 'EnotifUserTalk' ) ) {
                                $defaultPreferences['enotifusertalkpages'] = [
                                        'type' => 'toggle',
                                        'section' => 'personal/email',
@@ -627,8 +680,9 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                                        'disabled' => $disableEmailPrefs,
                                ];
                        }
-                       if ( $this->config->get( 'EnotifUserTalk' ) || $this->config->get( 'EnotifWatchlist' ) ) {
-                               if ( $this->config->get( 'EnotifMinorEdits' ) ) {
+                       if ( $this->options->get( 'EnotifUserTalk' ) ||
+                       $this->options->get( 'EnotifWatchlist' ) ) {
+                               if ( $this->options->get( 'EnotifMinorEdits' ) ) {
                                        $defaultPreferences['enotifminoredits'] = [
                                                'type' => 'toggle',
                                                'section' => 'personal/email',
@@ -637,7 +691,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                                        ];
                                }
 
-                               if ( $this->config->get( 'EnotifRevealEditorAddress' ) ) {
+                               if ( $this->options->get( 'EnotifRevealEditorAddress' ) ) {
                                        $defaultPreferences['enotifrevealaddr'] = [
                                                'type' => 'toggle',
                                                'section' => 'personal/email',
@@ -668,8 +722,8 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                        ];
                }
 
-               $allowUserCss = $this->config->get( 'AllowUserCss' );
-               $allowUserJs = $this->config->get( 'AllowUserJs' );
+               $allowUserCss = $this->options->get( 'AllowUserCss' );
+               $allowUserJs = $this->options->get( 'AllowUserJs' );
                # Create links to user CSS/JS pages for all skins
                # This code is basically copied from generateSkinOptions().  It'd
                # be nice to somehow merge this back in there to avoid redundancy.
@@ -800,10 +854,12 @@ class DefaultPreferencesFactory implements PreferencesFactory {
        }
 
        /**
+        * @param User $user
         * @param MessageLocalizer $l10n
         * @param array &$defaultPreferences
         */
        protected function renderingPreferences(
+               User $user,
                MessageLocalizer $l10n,
                &$defaultPreferences
        ) {
@@ -820,7 +876,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                ];
 
                # # Page Rendering ##############################
-               if ( $this->config->get( 'AllowUserCssPrefs' ) ) {
+               if ( $this->options->get( 'AllowUserCssPrefs' ) ) {
                        $defaultPreferences['underline'] = [
                                'type' => 'select',
                                'options' => [
@@ -861,6 +917,14 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                        'section' => 'rendering/advancedrendering',
                        'label-message' => 'tog-numberheadings',
                ];
+
+               if ( $user->isAllowed( 'rollback' ) ) {
+                       $defaultPreferences['showrollbackconfirmation'] = [
+                               'type' => 'toggle',
+                               'section' => 'rendering/advancedrendering',
+                               'label-message' => 'tog-showrollbackconfirmation',
+                       ];
+               }
        }
 
        /**
@@ -881,7 +945,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                        'label-message' => 'tog-editondblclick',
                ];
 
-               if ( $this->config->get( 'AllowUserCssPrefs' ) ) {
+               if ( $this->options->get( 'AllowUserCssPrefs' ) ) {
                        $defaultPreferences['editfont'] = [
                                'type' => 'select',
                                'section' => 'editing/editor',
@@ -936,7 +1000,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
         * @param array &$defaultPreferences
         */
        protected function rcPreferences( User $user, MessageLocalizer $l10n, &$defaultPreferences ) {
-               $rcMaxAge = $this->config->get( 'RCMaxAge' );
+               $rcMaxAge = $this->options->get( 'RCMaxAge' );
                # # RecentChanges #####################################
                $defaultPreferences['rcdays'] = [
                        'type' => 'float',
@@ -989,7 +1053,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                        'type' => 'api',
                ];
 
-               if ( $this->config->get( 'RCWatchCategoryMembership' ) ) {
+               if ( $this->options->get( 'RCWatchCategoryMembership' ) ) {
                        $defaultPreferences['hidecategorization'] = [
                                'type' => 'toggle',
                                'label-message' => 'tog-hidecategorization',
@@ -1013,7 +1077,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                        ];
                }
 
-               if ( $this->config->get( 'RCShowWatchingUsers' ) ) {
+               if ( $this->options->get( 'RCShowWatchingUsers' ) ) {
                        $defaultPreferences['shownumberswatching'] = [
                                'type' => 'toggle',
                                'section' => 'rc/advancedrc',
@@ -1037,12 +1101,11 @@ class DefaultPreferencesFactory implements PreferencesFactory {
        protected function watchlistPreferences(
                User $user, IContextSource $context, &$defaultPreferences
        ) {
-               $watchlistdaysMax = ceil( $this->config->get( 'RCMaxAge' ) / ( 3600 * 24 ) );
+               $watchlistdaysMax = ceil( $this->options->get( 'RCMaxAge' ) / ( 3600 * 24 ) );
 
                # # Watchlist #####################################
                if ( $user->isAllowed( 'editmywatchlist' ) ) {
                        $editWatchlistLinks = '';
-                       $editWatchlistLinksOld = [];
                        $editWatchlistModes = [
                                'edit' => [ 'subpage' => false, 'flags' => [] ],
                                'raw' => [ 'subpage' => 'raw', 'flags' => [] ],
@@ -1118,10 +1181,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                        'label-message' => 'tog-watchlisthideliu',
                ];
 
-               if ( !\SpecialWatchlist::checkStructuredFilterUiEnabled(
-                       $this->config,
-                       $user
-               ) ) {
+               if ( !\SpecialWatchlist::checkStructuredFilterUiEnabled( $user ) ) {
                        $defaultPreferences['watchlistreloadautomatically'] = [
                                'type' => 'toggle',
                                'section' => 'watchlist/advancedwatchlist',
@@ -1135,7 +1195,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                        'label-message' => 'tog-watchlistunwatchlinks',
                ];
 
-               if ( $this->config->get( 'RCWatchCategoryMembership' ) ) {
+               if ( $this->options->get( 'RCWatchCategoryMembership' ) ) {
                        $defaultPreferences['watchlisthidecategorization'] = [
                                'type' => 'toggle',
                                'section' => 'watchlist/changeswatchlist',
@@ -1214,7 +1274,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
         * @param array &$defaultPreferences
         */
        protected function searchPreferences( &$defaultPreferences ) {
-               foreach ( MWNamespace::getValidNamespaces() as $n ) {
+               foreach ( $this->nsInfo->getValidNamespaces() as $n ) {
                        $defaultPreferences['searchNs' . $n] = [
                                'type' => 'api',
                        ];
@@ -1234,6 +1294,23 @@ class DefaultPreferencesFactory implements PreferencesFactory {
 
                # Only show skins that aren't disabled in $wgSkipSkins
                $validSkinNames = Skin::getAllowedSkins();
+               $allInstalledSkins = Skin::getSkinNames();
+
+               // Display the installed skin the user has specifically requested via useskin=….
+               $useSkin = $context->getRequest()->getRawVal( 'useskin' );
+               if ( isset( $allInstalledSkins[$useSkin] )
+                       && $context->msg( "skinname-$useSkin" )->exists()
+               ) {
+                       $validSkinNames[$useSkin] = $useSkin;
+               }
+
+               // Display the skin if the user has set it as a preference already before it was hidden.
+               $currentUserSkin = $user->getOption( 'skin' );
+               if ( isset( $allInstalledSkins[$currentUserSkin] )
+                       && $context->msg( "skinname-$useSkin" )->exists()
+               ) {
+                       $validSkinNames[$currentUserSkin] = $currentUserSkin;
+               }
 
                foreach ( $validSkinNames as $skinkey => &$skinname ) {
                        $msg = $context->msg( "skinname-{$skinkey}" );
@@ -1242,9 +1319,9 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                        }
                }
 
-               $defaultSkin = $this->config->get( 'DefaultSkin' );
-               $allowUserCss = $this->config->get( 'AllowUserCss' );
-               $allowUserJs = $this->config->get( 'AllowUserJs' );
+               $defaultSkin = $this->options->get( 'DefaultSkin' );
+               $allowUserCss = $this->options->get( 'AllowUserCss' );
+               $allowUserJs = $this->options->get( 'AllowUserJs' );
 
                # Sort by the internal name, so that the ordering is the same for each display language,
                # especially if some skin names are translated to use a different alphabet and some are not.
@@ -1343,7 +1420,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                $ret = [];
                $pixels = $l10n->msg( 'unit-pixel' )->text();
 
-               foreach ( $this->config->get( 'ImageLimits' ) as $index => $limits ) {
+               foreach ( $this->options->get( 'ImageLimits' ) as $index => $limits ) {
                        // Note: A left-to-right marker (U+200E) is inserted, see T144386
                        $display = "{$limits[0]}\u{200E}×{$limits[1]}$pixels";
                        $ret[$display] = $index;
@@ -1360,7 +1437,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                $ret = [];
                $pixels = $l10n->msg( 'unit-pixel' )->text();
 
-               foreach ( $this->config->get( 'ThumbLimits' ) as $index => $size ) {
+               foreach ( $this->options->get( 'ThumbLimits' ) as $index => $size ) {
                        $display = $size . $pixels;
                        $ret[$display] = $index;
                }
@@ -1375,7 +1452,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
         * @return bool|string
         */
        protected function validateSignature( $signature, $alldata, HTMLForm $form ) {
-               $maxSigChars = $this->config->get( 'MaxSigChars' );
+               $maxSigChars = $this->options->get( 'MaxSigChars' );
                if ( mb_strlen( $signature ) > $maxSigChars ) {
                        return Xml::element( 'span', [ 'class' => 'error' ],
                                $form->msg( 'badsiglength' )->numParams( $maxSigChars )->text() );
@@ -1421,7 +1498,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
        public function getForm(
                User $user,
                IContextSource $context,
-               $formClass = PreferencesFormLegacy::class,
+               $formClass = PreferencesFormOOUI::class,
                array $remove = []
        ) {
                // We use ButtonWidgets in some of the getPreferences() functions
@@ -1441,10 +1518,18 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                }
 
                /**
-                * @var $htmlForm HTMLForm
+                * @var HTMLForm $htmlForm
                 */
                $htmlForm = new $formClass( $formDescriptor, $context, 'prefs' );
 
+               // This allows users to opt-in to hidden skins. While this should be discouraged and is not
+               // discoverable, this allows users to still use hidden skins while preventing new users from
+               // adopting unsupported skins. If no useskin=… parameter was provided, it will not show up
+               // in the resulting URL.
+               $htmlForm->setAction( $context->getTitle()->getLocalURL( [
+                       'useskin' => $context->getRequest()->getRawVal( 'useskin' )
+               ] ) );
+
                $htmlForm->setModifiedUser( $user );
                $htmlForm->setId( 'mw-prefs-form' );
                $htmlForm->setAutocomplete( 'off' );
@@ -1468,7 +1553,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
        protected function getTimezoneOptions( IContextSource $context ) {
                $opt = [];
 
-               $localTZoffset = $this->config->get( 'LocalTZoffset' );
+               $localTZoffset = $this->options->get( 'LocalTZoffset' );
                $timeZoneList = $this->getTimeZoneList( $context->getLanguage() );
 
                $timestamp = MWTimestamp::getLocalInstance();
@@ -1516,7 +1601,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
        protected function saveFormData( $formData, HTMLForm $form, array $formDescriptor ) {
                /** @var \User $user */
                $user = $form->getModifiedUser();
-               $hiddenPrefs = $this->config->get( 'HiddenPrefs' );
+               $hiddenPrefs = $this->options->get( 'HiddenPrefs' );
                $result = true;
 
                if ( !$user->isAllowedAny( 'editmyprivateinfo', 'editmyoptions' ) ) {
index 478edce..6602a0a 100644 (file)
@@ -22,13 +22,14 @@ namespace MediaWiki\Preferences;
 
 use HTMLForm;
 use IContextSource;
+use PreferencesFormOOUI;
 use User;
 
 /**
  * A PreferencesFactory is a MediaWiki service that provides the definitions of preferences for a
  * given user. These definitions are in the form of an HTMLForm descriptor.
  *
- * PreferencesFormLegacy (a subclass of HTMLForm) is used to generate the Preferences form, and
+ * PreferencesFormOOUI (a subclass of HTMLForm) is used to generate the Preferences form, and
  * handles generic submission, CSRF protection, layout and other logic in a reusable manner.
  *
  * In order to generate the form, the HTMLForm object needs an array structure detailing the
@@ -62,7 +63,7 @@ interface PreferencesFactory {
        public function getForm(
                User $user,
                IContextSource $contextSource,
-               $formClass = \PreferencesFormLegacy::class,
+               $formClass = PreferencesFormOOUI::class,
                array $remove = []
        );
 
index 1017e44..fe46798 100644 (file)
@@ -32,9 +32,11 @@ class ProfilerStub extends Profiler {
        }
 
        public function getFunctionStats() {
+               return [];
        }
 
        public function getOutput() {
+               return '';
        }
 
        public function close() {
diff --git a/includes/profiler/SectionProfileCallback.php b/includes/profiler/SectionProfileCallback.php
new file mode 100644 (file)
index 0000000..4c25c50
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Profiler
+ */
+use Wikimedia\ScopedCallback;
+
+/**
+ * Subclass ScopedCallback to avoid call_user_func_array(), which is slow.
+ *
+ * @internal For use by SectionProfiler
+ * @since 1.25
+ */
+class SectionProfileCallback extends ScopedCallback {
+       /** @var SectionProfiler */
+       protected $profiler;
+       /** @var string */
+       protected $section;
+
+       /**
+        * @param SectionProfiler $profiler
+        * @param string $section
+        */
+       public function __construct( SectionProfiler $profiler, $section ) {
+               parent::__construct( null );
+               $this->profiler = $profiler;
+               $this->section = $section;
+       }
+
+       function __destruct() {
+               $this->profiler->profileOutInternal( $this->section );
+       }
+}
index b00401d..c27ab4f 100644 (file)
@@ -496,29 +496,3 @@ class SectionProfiler {
                }
        }
 }
-
-/**
- * Subclass ScopedCallback to avoid call_user_func_array(), which is slow
- *
- * This class should not be used outside of SectionProfiler
- */
-class SectionProfileCallback extends ScopedCallback {
-       /** @var SectionProfiler */
-       protected $profiler;
-       /** @var string */
-       protected $section;
-
-       /**
-        * @param SectionProfiler $profiler
-        * @param string $section
-        */
-       public function __construct( SectionProfiler $profiler, $section ) {
-               parent::__construct( null );
-               $this->profiler = $profiler;
-               $this->section = $section;
-       }
-
-       function __destruct() {
-               $this->profiler->profileOutInternal( $this->section );
-       }
-}
index afe900d..d0b7ae3 100644 (file)
@@ -53,6 +53,7 @@ abstract class FormattedRCFeed extends RCFeed {
        public function notify( RecentChange $rc, $actionComment = null ) {
                $params = $this->params;
                /** @var RCFeedFormatter $formatter */
+               // @phan-suppress-next-line PhanTypeExpectedObjectOrClassName
                $formatter = is_object( $params['formatter'] ) ? $params['formatter'] : new $params['formatter'];
 
                $line = $formatter->getLine( $params, $rc, $actionComment );
index 158ee59..ff85c90 100644 (file)
@@ -19,6 +19,8 @@
  * @file
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * Generates a colourful notification intended for humans on IRC.
  *
@@ -93,8 +95,9 @@ class IRCColourfulRCFeedFormatter implements RCFeedFormatter {
                        ) );
                        $flag = $attribs['rc_log_action'];
                } else {
+                       $store = MediaWikiServices::getInstance()->getCommentStore();
                        $comment = self::cleanupForIRC(
-                               CommentStore::getStore()->getComment( 'rc_comment', $attribs )->text
+                               $store->getComment( 'rc_comment', $attribs )->text
                        );
                        $flag = '';
                        if ( !$attribs['rc_patrolled']
index 8a3aa0c..c954df1 100644 (file)
@@ -37,7 +37,7 @@
  *
  * @since 1.22
  */
-class RedisPubSubFeedEngine extends RCFeedEngine {
+class RedisPubSubFeedEngine extends FormattedRCFeed {
 
        /**
         * @see FormattedRCFeed::send
@@ -68,8 +68,8 @@ class RedisPubSubFeedEngine extends RCFeedEngine {
                if ( $conn !== false ) {
                        $conn->publish( $channel, $line );
                        return true;
-               } else {
-                       return false;
                }
+
+               return false;
        }
 }
index f76d771..d142c48 100644 (file)
@@ -24,7 +24,7 @@
  */
 class UDPRCFeedEngine extends RCFeedEngine {
        /**
-        * @see RCFeedEngine::send
+        * @see FormattedRCFeed::send
         * @param array $feed
         * @param string $line
         * @return bool
@@ -32,5 +32,6 @@ class UDPRCFeedEngine extends RCFeedEngine {
        public function send( array $feed, $line ) {
                $transport = UDPTransport::newFromString( $feed['uri'] );
                $transport->emit( $line );
+               return true;
        }
 }
index c27cd2c..5329572 100644 (file)
@@ -58,6 +58,11 @@ class ExtensionDependencyError extends Exception {
         */
        public $missingPhpExtensions = [];
 
+       /**
+        * @var string[]
+        */
+       public $missingAbilities = [];
+
        /**
         * @param array $errors Each error has a 'msg' and 'type' key at minimum
         */
@@ -75,6 +80,9 @@ class ExtensionDependencyError extends Exception {
                                case 'missing-phpExtension':
                                        $this->missingPhpExtensions[] = $info['missing'];
                                        break;
+                               case 'missing-ability':
+                                       $this->missingAbilities[] = $info['missing'];
+                                       break;
                                case 'missing-skins':
                                        $this->missingSkins[] = $info['missing'];
                                        break;
index 9d6c1a5..ba5df52 100644 (file)
@@ -60,12 +60,16 @@ class ExtensionJsonValidator {
                                'The JsonSchema library cannot be found, please install it through composer.'
                        );
                        return false;
-               } elseif ( !class_exists( SpdxLicenses::class ) ) {
+               }
+
+               if ( !class_exists( SpdxLicenses::class ) ) {
                        call_user_func( $this->missingDepCallback,
                                'The spdx-licenses library cannot be found, please install it through composer.'
                        );
                        return false;
-               } elseif ( !class_exists( JsonParser::class ) ) {
+               }
+
+               if ( !class_exists( JsonParser::class ) ) {
                        call_user_func( $this->missingDepCallback,
                                'The JSON lint library cannot be found, please install it through composer.'
                        );
@@ -104,7 +108,9 @@ class ExtensionJsonValidator {
                        throw new ExtensionJsonValidationError(
                                "$path is using a non-supported schema version"
                        );
-               } elseif ( $version > ExtensionRegistry::MANIFEST_VERSION ) {
+               }
+
+               if ( $version > ExtensionRegistry::MANIFEST_VERSION ) {
                        throw new ExtensionJsonValidationError(
                                "$path is using a non-supported schema version"
                        );
@@ -140,15 +146,15 @@ class ExtensionJsonValidator {
                if ( $validator->isValid() && !$extraErrors ) {
                        // All good.
                        return true;
-               } else {
-                       $out = "$path did not pass validation.\n";
-                       foreach ( $validator->getErrors() as $error ) {
-                               $out .= "[{$error['property']}] {$error['message']}\n";
-                       }
-                       if ( $extraErrors ) {
-                               $out .= implode( "\n", $extraErrors ) . "\n";
-                       }
-                       throw new ExtensionJsonValidationError( $out );
                }
+
+               $out = "$path did not pass validation.\n";
+               foreach ( $validator->getErrors() as $error ) {
+                       $out .= "[{$error['property']}] {$error['message']}\n";
+               }
+               if ( $extraErrors ) {
+                       $out .= implode( "\n", $extraErrors ) . "\n";
+               }
+               throw new ExtensionJsonValidationError( $out );
        }
 }
index 1d3fd86..b474ddc 100644 (file)
@@ -189,7 +189,6 @@ class ExtensionProcessor implements Processor {
         * @param string $path
         * @param array $info
         * @param int $version manifest_version for info
-        * @return array
         */
        public function extractInfo( $path, array $info, $version ) {
                $dir = dirname( $path );
index e3df499..fb89731 100644 (file)
@@ -2,6 +2,8 @@
 
 use Composer\Semver\Semver;
 use Wikimedia\ScopedCallback;
+use MediaWiki\Shell\Shell;
+use MediaWiki\ShellDisabledError;
 
 /**
  * ExtensionRegistry class
@@ -144,7 +146,8 @@ class ExtensionRegistry {
                // A few more things to vary the cache on
                $versions = [
                        'registration' => self::CACHE_VERSION,
-                       'mediawiki' => $wgVersion
+                       'mediawiki' => $wgVersion,
+                       'abilities' => $this->getAbilities(),
                ];
 
                // We use a try/catch because we don't want to fail here
@@ -207,6 +210,38 @@ class ExtensionRegistry {
                $this->finished = true;
        }
 
+       /**
+        * Get the list of abilities and their values
+        * @return bool[]
+        */
+       private function getAbilities() {
+               return [
+                       'shell' => !Shell::isDisabled(),
+               ];
+       }
+
+       /**
+        * Queries information about the software environment and constructs an appropiate version checker
+        *
+        * @return VersionChecker
+        */
+       private function buildVersionChecker() {
+               global $wgVersion;
+               // array to optionally specify more verbose error messages for
+               // missing abilities
+               $abilityErrors = [
+                       'shell' => ( new ShellDisabledError() )->getMessage(),
+               ];
+
+               return new VersionChecker(
+                       $wgVersion,
+                       PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION,
+                       get_loaded_extensions(),
+                       $this->getAbilities(),
+                       $abilityErrors
+               );
+       }
+
        /**
         * Process a queue of extensions and return their extracted data
         *
@@ -216,16 +251,11 @@ class ExtensionRegistry {
         * @throws ExtensionDependencyError
         */
        public function readFromQueue( array $queue ) {
-               global $wgVersion;
                $autoloadClasses = [];
                $autoloadNamespaces = [];
                $autoloaderPaths = [];
                $processor = new ExtensionProcessor();
-               $versionChecker = new VersionChecker(
-                       $wgVersion,
-                       PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION,
-                       get_loaded_extensions()
-               );
+               $versionChecker = $this->buildVersionChecker();
                $extDependencies = [];
                $incompatible = [];
                $warnings = false;
@@ -383,10 +413,12 @@ class ExtensionRegistry {
         *
         * If some extensions are already queued, this will load
         * those as well.
-        *
+        * TODO: Remove in MediaWiki 1.35
+        * @deprecated since 1.34, use ExtensionRegistry->queue() instead
         * @param string $path Absolute path to the JSON file
         */
        public function load( $path ) {
+               wfDeprecated( __METHOD__, '1.34' );
                $this->loadFromQueue(); // First clear the queue
                $this->queue( $path );
                $this->loadFromQueue();
index 636d3b3..68ba413 100644 (file)
@@ -17,7 +17,6 @@ interface Processor {
         * @param string $path Absolute path of JSON file
         * @param array $info
         * @param int $version manifest_version for info
-        * @return array "credits" information to store
         */
        public function extractInfo( $path, array $info, $version );
 
index 586729d..a5d1fa1 100644 (file)
@@ -45,6 +45,16 @@ class VersionChecker {
         */
        private $phpExtensions = [];
 
+       /**
+        * @var bool[] List of provided abilities
+        */
+       private $abilities = [];
+
+       /**
+        * @var string[] List of provided ability errors
+        */
+       private $abilityErrors = [];
+
        /**
         * @var array Loaded extensions
         */
@@ -59,12 +69,19 @@ class VersionChecker {
         * @param string $coreVersion Current version of core
         * @param string $phpVersion Current PHP version
         * @param string[] $phpExtensions List of installed PHP extensions
+        * @param bool[] $abilities List of provided abilities
+        * @param string[] $abilityErrors Error messages for the abilities
         */
-       public function __construct( $coreVersion, $phpVersion, array $phpExtensions ) {
+       public function __construct(
+               $coreVersion, $phpVersion, array $phpExtensions,
+               array $abilities = [], array $abilityErrors = []
+       ) {
                $this->versionParser = new VersionParser();
                $this->setCoreVersion( $coreVersion );
                $this->setPhpVersion( $phpVersion );
                $this->phpExtensions = $phpExtensions;
+               $this->abilities = $abilities;
+               $this->abilityErrors = $abilityErrors;
        }
 
        /**
@@ -121,7 +138,8 @@ class VersionChecker {
         *         'MediaWiki' => '>= 1.25.0',
         *         'platform': {
         *           'php': '>= 7.0.0',
-        *           'ext-foo': '*'
+        *           'ext-foo': '*',
+        *           'ability-bar': true
         *         },
         *         'extensions' => {
         *           'FooBaz' => '>= 1.25.0'
@@ -193,6 +211,37 @@ class VersionChecker {
                                                                                'missing' => $phpExtension,
                                                                        ];
                                                                }
+                                                       } elseif ( substr( $dependency, 0, 8 ) === 'ability-' ) {
+                                                               // Other abilities the environment might provide.
+                                                               $ability = substr( $dependency, 8 );
+                                                               if ( !isset( $this->abilities[$ability] ) ) {
+                                                                       throw new UnexpectedValueException( 'Dependency type '
+                                                                       . $dependency . ' unknown in ' . $extension );
+                                                               }
+                                                               if ( !is_bool( $constraint ) ) {
+                                                                       throw new UnexpectedValueException( 'Only booleans are '
+                                                                               . 'allowed to to indicate the presence of abilities '
+                                                                               . 'in ' . $extension );
+                                                               }
+
+                                                               if ( $constraint === true &&
+                                                                       $this->abilities[$ability] !== true
+                                                               ) {
+                                                                       // add custom error message for missing ability if specified
+                                                                       $customMessage = '';
+                                                                       if ( isset( $this->abilityErrors[$ability] ) ) {
+                                                                               $customMessage = ': ' . $this->abilityErrors[$ability];
+                                                                       }
+
+                                                                       $errors[] = [
+                                                                               'msg' =>
+                                                                                       "{$extension} requires \"{$ability}\" ability"
+                                                                                       . $customMessage
+                                                                               ,
+                                                                               'type' => 'missing-ability',
+                                                                               'missing' => $ability,
+                                                                       ];
+                                                               }
                                                        } else {
                                                                // add other platform dependencies here
                                                                throw new UnexpectedValueException( 'Dependency type ' . $dependency .
diff --git a/includes/resourceloader/MessageBlobStore.php b/includes/resourceloader/MessageBlobStore.php
new file mode 100644 (file)
index 0000000..635e433
--- /dev/null
@@ -0,0 +1,237 @@
+<?php
+/**
+ * Message blobs storage used by ResourceLoader.
+ *
+ * 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
+ * @author Roan Kattouw
+ * @author Trevor Parscal
+ * @author Timo Tijhof
+ */
+
+use MediaWiki\MediaWikiServices;
+use Psr\Log\LoggerAwareInterface;
+use Psr\Log\LoggerInterface;
+use Psr\Log\NullLogger;
+use Wikimedia\Rdbms\Database;
+
+/**
+ * This class generates message blobs for use by ResourceLoader modules.
+ *
+ * A message blob is a JSON object containing the interface messages for a certain module in
+ * a certain language.
+ */
+class MessageBlobStore implements LoggerAwareInterface {
+
+       /* @var ResourceLoader */
+       private $resourceloader;
+
+       /**
+        * @var LoggerInterface
+        */
+       protected $logger;
+
+       /**
+        * @var WANObjectCache
+        */
+       protected $wanCache;
+
+       /**
+        * @param ResourceLoader $rl
+        * @param LoggerInterface|null $logger
+        */
+       public function __construct( ResourceLoader $rl, LoggerInterface $logger = null ) {
+               $this->resourceloader = $rl;
+               $this->logger = $logger ?: new NullLogger();
+               $this->wanCache = MediaWikiServices::getInstance()->getMainWANObjectCache();
+       }
+
+       /**
+        * @since 1.27
+        * @param LoggerInterface $logger
+        */
+       public function setLogger( LoggerInterface $logger ) {
+               $this->logger = $logger;
+       }
+
+       /**
+        * Get the message blob for a module
+        *
+        * @since 1.27
+        * @param ResourceLoaderModule $module
+        * @param string $lang Language code
+        * @return string JSON
+        */
+       public function getBlob( ResourceLoaderModule $module, $lang ) {
+               $blobs = $this->getBlobs( [ $module->getName() => $module ], $lang );
+               return $blobs[$module->getName()];
+       }
+
+       /**
+        * Get the message blobs for a set of modules
+        *
+        * @since 1.27
+        * @param ResourceLoaderModule[] $modules Array of module objects keyed by name
+        * @param string $lang Language code
+        * @return array An array mapping module names to message blobs
+        */
+       public function getBlobs( array $modules, $lang ) {
+               // Each cache key for a message blob by module name and language code also has a generic
+               // check key without language code. This is used to invalidate any and all language subkeys
+               // that exist for a module from the updateMessage() method.
+               $cache = $this->wanCache;
+               $checkKeys = [
+                       // Global check key, see clear()
+                       $cache->makeKey( __CLASS__ )
+               ];
+               $cacheKeys = [];
+               foreach ( $modules as $name => $module ) {
+                       $cacheKey = $this->makeCacheKey( $module, $lang );
+                       $cacheKeys[$name] = $cacheKey;
+                       // Per-module check key, see updateMessage()
+                       $checkKeys[$cacheKey][] = $cache->makeKey( __CLASS__, $name );
+               }
+               $curTTLs = [];
+               $result = $cache->getMulti( array_values( $cacheKeys ), $curTTLs, $checkKeys );
+
+               $blobs = [];
+               foreach ( $modules as $name => $module ) {
+                       $key = $cacheKeys[$name];
+                       if ( !isset( $result[$key] ) || $curTTLs[$key] === null || $curTTLs[$key] < 0 ) {
+                               $blobs[$name] = $this->recacheMessageBlob( $key, $module, $lang );
+                       } else {
+                               // Use unexpired cache
+                               $blobs[$name] = $result[$key];
+                       }
+               }
+               return $blobs;
+       }
+
+       /**
+        * @since 1.27
+        * @param ResourceLoaderModule $module
+        * @param string $lang
+        * @return string Cache key
+        */
+       private function makeCacheKey( ResourceLoaderModule $module, $lang ) {
+               $messages = array_values( array_unique( $module->getMessages() ) );
+               sort( $messages );
+               return $this->wanCache->makeKey( __CLASS__, $module->getName(), $lang,
+                       md5( json_encode( $messages ) )
+               );
+       }
+
+       /**
+        * @since 1.27
+        * @param string $cacheKey
+        * @param ResourceLoaderModule $module
+        * @param string $lang
+        * @return string JSON blob
+        */
+       protected function recacheMessageBlob( $cacheKey, ResourceLoaderModule $module, $lang ) {
+               $blob = $this->generateMessageBlob( $module, $lang );
+               $cache = $this->wanCache;
+               $cache->set( $cacheKey, $blob,
+                       // Add part of a day to TTL to avoid all modules expiring at once
+                       $cache::TTL_WEEK + mt_rand( 0, $cache::TTL_DAY ),
+                       Database::getCacheSetOptions( wfGetDB( DB_REPLICA ) )
+               );
+               return $blob;
+       }
+
+       /**
+        * Invalidate cache keys for modules using this message key.
+        * Called by MessageCache when a message has changed.
+        *
+        * @param string $key Message key
+        */
+       public function updateMessage( $key ) {
+               $moduleNames = $this->getResourceLoader()->getModulesByMessage( $key );
+               foreach ( $moduleNames as $moduleName ) {
+                       // Uses a holdoff to account for database replica DB lag (for MessageCache)
+                       $this->wanCache->touchCheckKey( $this->wanCache->makeKey( __CLASS__, $moduleName ) );
+               }
+       }
+
+       /**
+        * Invalidate cache keys for all known modules.
+        * Called by LocalisationCache after cache is regenerated.
+        */
+       public function clear() {
+               $cache = $this->wanCache;
+               // Disable holdoff because this invalidates all modules and also not needed since
+               // LocalisationCache is stored outside the database and doesn't have lag.
+               $cache->touchCheckKey( $cache->makeKey( __CLASS__ ), $cache::HOLDOFF_NONE );
+       }
+
+       /**
+        * @since 1.27
+        * @return ResourceLoader
+        */
+       protected function getResourceLoader() {
+               return $this->resourceloader;
+       }
+
+       /**
+        * @since 1.27
+        * @param string $key Message key
+        * @param string $lang Language code
+        * @return string|null
+        */
+       protected function fetchMessage( $key, $lang ) {
+               $message = wfMessage( $key )->inLanguage( $lang );
+               if ( !$message->exists() ) {
+                       $this->logger->warning( 'Failed to find {messageKey} ({lang})', [
+                               'messageKey' => $key,
+                               'lang' => $lang,
+                       ] );
+                       $value = null;
+               } else {
+                       $value = $message->plain();
+               }
+               return $value;
+       }
+
+       /**
+        * Generate the message blob for a given module in a given language.
+        *
+        * @param ResourceLoaderModule $module
+        * @param string $lang Language code
+        * @return string JSON blob
+        */
+       private function generateMessageBlob( ResourceLoaderModule $module, $lang ) {
+               $messages = [];
+               foreach ( $module->getMessages() as $key ) {
+                       $value = $this->fetchMessage( $key, $lang );
+                       if ( $value !== null ) {
+                               $messages[$key] = $value;
+                       }
+               }
+
+               $json = FormatJson::encode( (object)$messages );
+               // @codeCoverageIgnoreStart
+               if ( $json === false ) {
+                       $this->logger->warning( 'Failed to encode message blob for {module} ({lang})', [
+                               'module' => $module->getName(),
+                               'lang' => $lang,
+                       ] );
+                       $json = '{}';
+               }
+               // codeCoverageIgnoreEnd
+               return $json;
+       }
+}
index 5712692..418f532 100644 (file)
@@ -240,8 +240,6 @@ class ResourceLoader implements LoggerAwareInterface {
         * @param LoggerInterface|null $logger [optional]
         */
        public function __construct( Config $config = null, LoggerInterface $logger = null ) {
-               global $IP;
-
                $this->logger = $logger ?: new NullLogger();
 
                if ( !$config ) {
@@ -254,21 +252,8 @@ class ResourceLoader implements LoggerAwareInterface {
                // Add 'local' source first
                $this->addSource( 'local', $config->get( 'LoadScript' ) );
 
-               // Add other sources
-               $this->addSource( $config->get( 'ResourceLoaderSources' ) );
-
-               // Register core modules
-               $this->register( include "$IP/resources/Resources.php" );
-               // Register extension modules
-               $this->register( $config->get( 'ResourceModules' ) );
-
-               // Avoid PHP 7.1 warning from passing $this by reference
-               $rl = $this;
-               Hooks::run( 'ResourceLoaderRegisterModules', [ &$rl ] );
-
-               if ( $config->get( 'EnableJavaScriptTest' ) === true ) {
-                       $this->registerTestModules();
-               }
+               // Special module that always exists
+               $this->register( 'startup', [ 'class' => ResourceLoaderStartUpModule::class ] );
 
                $this->setMessageBlobStore( new MessageBlobStore( $this, $this->logger ) );
        }
@@ -322,8 +307,6 @@ class ResourceLoader implements LoggerAwareInterface {
         * @throws MWException If a duplicate module registration is attempted
         * @throws MWException If a module name contains illegal characters (pipes or commas)
         * @throws MWException If something other than a ResourceLoaderModule is being registered
-        * @return bool False if there were any errors, in which case one or more modules were
-        *   not registered
         */
        public function register( $name, $info = null ) {
                $moduleSkinStyles = $this->config->get( 'ResourceModuleSkinStyles' );
@@ -400,6 +383,9 @@ class ResourceLoader implements LoggerAwareInterface {
                }
        }
 
+       /**
+        * @internal For use by ServiceWiring only
+        */
        public function registerTestModules() {
                global $IP;
 
@@ -1125,6 +1111,10 @@ MESSAGE;
 
                                if ( !$context->getDebug() ) {
                                        $strContent = self::filter( $filter, $strContent );
+                               } else {
+                                       // In debug mode, separate each response by a new line.
+                                       // For example, between 'mw.loader.implement();' statements.
+                                       $strContent = $this->ensureNewline( $strContent );
                                }
 
                                if ( $context->getOnly() === 'scripts' ) {
@@ -1163,11 +1153,9 @@ MESSAGE;
                                // Use a linebreak between module script and state script (T162719)
                                $out = $this->ensureNewline( $out ) . $stateScript;
                        }
-               } else {
-                       if ( $states ) {
-                               $this->errors[] = 'Problematic modules: '
-                                       . self::encodeJsonForScript( $states );
-                       }
+               } elseif ( $states ) {
+                       $this->errors[] = 'Problematic modules: '
+                               . self::encodeJsonForScript( $states );
                }
 
                return $out;
@@ -1180,7 +1168,7 @@ MESSAGE;
         */
        private function ensureNewline( $str ) {
                $end = substr( $str, -1 );
-               if ( $end === false || $end === "\n" ) {
+               if ( $end === false || $end === '' || $end === "\n" ) {
                        return $str;
                }
                return $str . "\n";
@@ -1452,7 +1440,7 @@ MESSAGE;
                        }
                }
 
-               array_walk( $modules, [ 'self', 'trimArray' ] );
+               array_walk( $modules, [ self::class, 'trimArray' ] );
 
                return Xml::encodeJsCall(
                        'mw.loader.register',
@@ -1494,7 +1482,7 @@ MESSAGE;
         */
        public static function makeLoaderConditionalScript( $script ) {
                // Adds a function to lazy-created RLQ
-               return '(window.RLQ=window.RLQ||[]).push(function(){' .
+               return '(RLQ=window.RLQ||[]).push(function(){' .
                        trim( $script ) . '});';
        }
 
@@ -1508,7 +1496,7 @@ MESSAGE;
         */
        public static function makeInlineCodeWithModule( $modules, $script ) {
                // Adds an array to lazy-created RLQ
-               return '(window.RLQ=window.RLQ||[]).push(['
+               return '(RLQ=window.RLQ||[]).push(['
                        . self::encodeJsonForScript( $modules ) . ','
                        . 'function(){' . trim( $script ) . '}'
                        . ']);';
@@ -1539,7 +1527,7 @@ MESSAGE;
 
                return new WrappedString(
                        Html::inlineScript( $js, $nonce ),
-                       "<script$escNonce>(window.RLQ=window.RLQ||[]).push(function(){",
+                       "<script$escNonce>(RLQ=window.RLQ||[]).push(function(){",
                        '});</script>'
                );
        }
@@ -1575,7 +1563,7 @@ MESSAGE;
         * For example, `[ 'foo.bar', 'foo.baz', 'bar.baz', 'bar.quux' ]`
         * becomes `'foo.bar,baz|bar.baz,quux'`.
         *
-        * This process is reversed by ResourceLoaderContext::expandModuleNames().
+        * This process is reversed by ResourceLoader::expandModuleNames().
         * See also mw.loader#buildModulesString() which is a port of this, used
         * on the client-side.
         *
@@ -1599,6 +1587,44 @@ MESSAGE;
                return implode( '|', $arr );
        }
 
+       /**
+        * Expand a string of the form `jquery.foo,bar|jquery.ui.baz,quux` to
+        * an array of module names like `[ 'jquery.foo', 'jquery.bar',
+        * 'jquery.ui.baz', 'jquery.ui.quux' ]`.
+        *
+        * This process is reversed by ResourceLoader::makePackedModulesString().
+        *
+        * @since 1.33
+        * @param string $modules Packed module name list
+        * @return array Array of module names
+        */
+       public static function expandModuleNames( $modules ) {
+               $retval = [];
+               $exploded = explode( '|', $modules );
+               foreach ( $exploded as $group ) {
+                       if ( strpos( $group, ',' ) === false ) {
+                               // This is not a set of modules in foo.bar,baz notation
+                               // but a single module
+                               $retval[] = $group;
+                       } else {
+                               // This is a set of modules in foo.bar,baz notation
+                               $pos = strrpos( $group, '.' );
+                               if ( $pos === false ) {
+                                       // Prefixless modules, i.e. without dots
+                                       $retval = array_merge( $retval, explode( ',', $group ) );
+                               } else {
+                                       // We have a prefix and a bunch of suffixes
+                                       $prefix = substr( $group, 0, $pos ); // 'foo'
+                                       $suffixes = explode( ',', substr( $group, $pos + 1 ) ); // [ 'bar', 'baz' ]
+                                       foreach ( $suffixes as $suffix ) {
+                                               $retval[] = "$prefix.$suffix";
+                                       }
+                               }
+                       }
+               }
+               return $retval;
+       }
+
        /**
         * Determine whether debug mode was requested
         * Order of priority is 1) request param, 2) cookie, 3) $wg setting
index 2b3db22..6061fb5 100644 (file)
@@ -22,7 +22,7 @@ use Wikimedia\WrappedString;
 use Wikimedia\WrappedStringList;
 
 /**
- * Bootstrap a ResourceLoader client on an HTML page.
+ * Load and configure a ResourceLoader client on an HTML page.
  *
  * @since 1.28
  */
@@ -233,27 +233,43 @@ class ResourceLoaderClientHtml {
                $chunks = [];
 
                // Change "client-nojs" class to client-js. This allows easy toggling of UI components.
-               // This happens synchronously on every page view to avoid flashes of wrong content.
+               // This must happen synchronously on every page view to avoid flashes of wrong content.
                // See also #getDocumentAttributes() and /resources/src/startup.js.
-               $chunks[] = Html::inlineScript(
-                       'document.documentElement.className = document.documentElement.className'
-                       . '.replace( /(^|\s)client-nojs(\s|$)/, "$1client-js$2" );',
-                       $nonce
-               );
+               $script = <<<JAVASCRIPT
+document.documentElement.className = document.documentElement.className
+       .replace( /(^|\s)client-nojs(\s|$)/, "$1client-js$2" );
+JAVASCRIPT;
 
-               // Inline RLQ: Set page variables
+               // Inline script: Declare mw.config variables for this page.
                if ( $this->config ) {
-                       $chunks[] = ResourceLoader::makeInlineScript(
-                               ResourceLoader::makeConfigSetScript( $this->config ),
-                               $nonce
-                       );
+                       $confJson = ResourceLoader::encodeJsonForScript( $this->config );
+                       $script .= <<<JAVASCRIPT
+RLCONF = {$confJson};
+JAVASCRIPT;
                }
 
-               // Inline RLQ: Initial module states
+               // Inline script: Declare initial module states for this page.
                $states = array_merge( $this->exemptStates, $data['states'] );
                if ( $states ) {
-                       $chunks[] = ResourceLoader::makeInlineScript(
-                               ResourceLoader::makeLoaderStateScript( $states ),
+                       $stateJson = ResourceLoader::encodeJsonForScript( $states );
+                       $script .= <<<JAVASCRIPT
+RLSTATE = {$stateJson};
+JAVASCRIPT;
+               }
+
+               // Inline script: Declare general modules to load on this page.
+               if ( $data['general'] ) {
+                       $pageModulesJson = ResourceLoader::encodeJsonForScript( $data['general'] );
+                       $script .= <<<JAVASCRIPT
+RLPAGEMODULES = {$pageModulesJson};
+JAVASCRIPT;
+               }
+
+               if ( $this->context->getDebug() ) {
+                       $chunks[] = Html::inlineScript( $script, $nonce );
+               } else {
+                       $chunks[] = Html::inlineScript(
+                               ResourceLoader::filter( 'minify-js', $script, [ 'cache' => false ] ),
                                $nonce
                        );
                }
@@ -267,17 +283,6 @@ class ResourceLoaderClientHtml {
                        );
                }
 
-               // Inline RLQ: Load general modules
-               if ( $data['general'] ) {
-                       $chunks[] = ResourceLoader::makeInlineScript(
-                               'RLPAGEMODULES='
-                                       . ResourceLoader::encodeJsonForScript( $data['general'] )
-                                       . ';'
-                                       . 'mw.loader.load(RLPAGEMODULES);',
-                               $nonce
-                       );
-               }
-
                // External stylesheets (only=styles)
                if ( $data['styles'] ) {
                        $chunks[] = $this->getLoad(
@@ -450,19 +455,17 @@ class ResourceLoaderClientHtml {
                                                // Decide whether to use 'style' or 'script' element
                                                if ( $only === ResourceLoaderModule::TYPE_STYLES ) {
                                                        $chunk = Html::linkedStyle( $url );
+                                               } elseif ( $context->getRaw() || $isRaw ) {
+                                                       $chunk = Html::element( 'script', [
+                                                               // In SpecialJavaScriptTest, QUnit must load synchronous
+                                                               'async' => !isset( $extraQuery['sync'] ),
+                                                               'src' => $url
+                                                       ] );
                                                } else {
-                                                       if ( $context->getRaw() || $isRaw ) {
-                                                               $chunk = Html::element( 'script', [
-                                                                       // In SpecialJavaScriptTest, QUnit must load synchronous
-                                                                       'async' => !isset( $extraQuery['sync'] ),
-                                                                       'src' => $url
-                                                               ] );
-                                                       } else {
-                                                               $chunk = ResourceLoader::makeInlineScript(
-                                                                       Xml::encodeJsCall( 'mw.loader.load', [ $url ] ),
-                                                                       $nonce
-                                                               );
-                                                       }
+                                                       $chunk = ResourceLoader::makeInlineScript(
+                                                               Xml::encodeJsCall( 'mw.loader.load', [ $url ] ),
+                                                               $nonce
+                                                       );
                                                }
 
                                                if ( $group == 'noscript' ) {
index a625970..58152ea 100644 (file)
@@ -63,12 +63,12 @@ class ResourceLoaderContext implements MessageLocalizer {
                $this->request = $request;
                $this->logger = $resourceLoader->getLogger();
 
-               // Future developers: Use WebRequest::getRawVal() instead getVal().
+               // Future developers: Use WebRequest::getRawVal() instead of getVal().
                // The getVal() method performs slow Language+UTF logic. (f303bb9360)
 
                // List of modules
                $modules = $request->getRawVal( 'modules' );
-               $this->modules = $modules ? self::expandModuleNames( $modules ) : [];
+               $this->modules = $modules ? ResourceLoader::expandModuleNames( $modules ) : [];
 
                // Various parameters
                $this->user = $request->getRawVal( 'user' );
@@ -84,47 +84,25 @@ class ResourceLoaderContext implements MessageLocalizer {
 
                $this->skin = $request->getRawVal( 'skin' );
                $skinnames = Skin::getSkinNames();
-               // If no skin is specified, or we don't recognize the skin, use the default skin
                if ( !$this->skin || !isset( $skinnames[$this->skin] ) ) {
-                       $this->skin = $this->getConfig()->get( 'DefaultSkin' );
+                       // The 'skin' parameter is required. (Not yet enforced.)
+                       // For requests without a known skin specified,
+                       // use MediaWiki's 'fallback' skin for skin-specific decisions.
+                       $this->skin = 'fallback';
                }
        }
 
        /**
-        * Expand a string of the form `jquery.foo,bar|jquery.ui.baz,quux` to
-        * an array of module names like `[ 'jquery.foo', 'jquery.bar',
-        * 'jquery.ui.baz', 'jquery.ui.quux' ]`.
-        *
-        * This process is reversed by ResourceLoader::makePackedModulesString().
+        * Reverse the process done by ResourceLoader::makePackedModulesString().
         *
+        * @deprecated since 1.33 Use ResourceLoader::expandModuleNames instead.
         * @param string $modules Packed module name list
         * @return array Array of module names
+        * @codeCoverageIgnore
         */
        public static function expandModuleNames( $modules ) {
-               $retval = [];
-               $exploded = explode( '|', $modules );
-               foreach ( $exploded as $group ) {
-                       if ( strpos( $group, ',' ) === false ) {
-                               // This is not a set of modules in foo.bar,baz notation
-                               // but a single module
-                               $retval[] = $group;
-                       } else {
-                               // This is a set of modules in foo.bar,baz notation
-                               $pos = strrpos( $group, '.' );
-                               if ( $pos === false ) {
-                                       // Prefixless modules, i.e. without dots
-                                       $retval = array_merge( $retval, explode( ',', $group ) );
-                               } else {
-                                       // We have a prefix and a bunch of suffixes
-                                       $prefix = substr( $group, 0, $pos ); // 'foo'
-                                       $suffixes = explode( ',', substr( $group, $pos + 1 ) ); // [ 'bar', 'baz' ]
-                                       foreach ( $suffixes as $suffix ) {
-                                               $retval[] = "$prefix.$suffix";
-                                       }
-                               }
-                       }
-               }
-               return $retval;
+               wfDeprecated( __METHOD__, '1.33' );
+               return ResourceLoader::expandModuleNames( $modules );
        }
 
        /**
@@ -132,7 +110,6 @@ class ResourceLoaderContext implements MessageLocalizer {
         * things that don't "really" need a context.
         *
         * Use cases:
-        * - Creating html5shiv script tag in OutputPage.
         * - Unit tests (deprecated, create empty instance directly or use RLTestCase).
         *
         * @return ResourceLoaderContext
@@ -195,7 +172,9 @@ class ResourceLoaderContext implements MessageLocalizer {
                        $lang = $this->getRequest()->getRawVal( 'lang', '' );
                        // Stricter version of RequestContext::sanitizeLangCode()
                        if ( !Language::isValidBuiltInCode( $lang ) ) {
-                               $lang = $this->getConfig()->get( 'LanguageCode' );
+                               // The 'lang' parameter is required. (Not yet enforced.)
+                               // If omitted, localise with the dummy language code.
+                               $lang = 'qqx';
                        }
                        $this->language = $lang;
                }
index 9be5de3..031541b 100644 (file)
@@ -385,7 +385,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
                if ( $this->packageFiles !== null ) {
                        $packageFiles = $this->getPackageFiles( $context );
                        if ( $deprecationScript ) {
-                               $mainFile =& $packageFiles['files'][ $packageFiles['main'] ];
+                               $mainFile =& $packageFiles['files'][$packageFiles['main']];
                                $mainFile['content'] = $deprecationScript . $mainFile['content'];
                        }
                        return $packageFiles;
index 8cd5b19..2e2da70 100644 (file)
@@ -20,6 +20,8 @@
  * @file
  */
 
+use MediaWiki\Shell\Shell;
+
 /**
  * Class encapsulating an image used in a ResourceLoaderImageModule.
  *
@@ -38,6 +40,21 @@ class ResourceLoaderImage {
                'jpg' => 'image/jpg',
        ];
 
+       /** @var string */
+       private $name;
+       /** @var string */
+       private $module;
+       /** @var string|array */
+       private $descriptor;
+       /** @var string */
+       private $basePath;
+       /** @var array */
+       private $variants;
+       /** @var string|null */
+       private $defaultColor;
+       /** @var string */
+       private $extension;
+
        /**
         * @param string $name Image name
         * @param string $module Module name
@@ -73,7 +90,7 @@ class ResourceLoaderImage {
                }
                // Remove 'deprecated' key
                if ( is_array( $this->descriptor ) ) {
-                       unset( $this->descriptor[ 'deprecated' ] );
+                       unset( $this->descriptor['deprecated'] );
                }
 
                // Ensure that all files have common extension.
@@ -373,7 +390,7 @@ class ResourceLoaderImage {
                if ( strpos( $wgSVGConverter, 'rsvg' ) === 0 ) {
                        $command = 'rsvg-convert';
                        if ( $wgSVGConverterPath ) {
-                               $command = wfEscapeShellArg( "$wgSVGConverterPath/" ) . $command;
+                               $command = Shell::escape( "$wgSVGConverterPath/" ) . $command;
                        }
 
                        $process = proc_open(
index d06e8ac..9b50d80 100644 (file)
@@ -220,7 +220,7 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
 
        /**
         * Get CSS selector templates used by this module.
-        * @return string
+        * @return string[]
         */
        public function getSelectors() {
                $this->loadFromDefinition();
@@ -428,7 +428,7 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
                        'selectorWithVariant',
                ] as $member ) {
                        $options[$member] = $this->{$member};
-               };
+               }
 
                $summary[] = [
                        'options' => $options,
index aca5c73..53ed133 100644 (file)
@@ -182,7 +182,7 @@ abstract class ResourceLoaderModule implements LoggerAwareInterface {
        /**
         * Takes named templates by the module and returns an array mapping.
         *
-        * @return array of templates mapping template alias to content
+        * @return string[] Array of templates mapping template alias to content
         */
        public function getTemplates() {
                // Stub, override expected.
index e97e074..7d39a58 100644 (file)
@@ -28,15 +28,15 @@ class ResourceLoaderOOUIFileModule extends ResourceLoaderFileModule {
        use ResourceLoaderOOUIModule;
 
        public function __construct( $options = [] ) {
-               if ( isset( $options[ 'themeScripts' ] ) ) {
-                       $skinScripts = $this->getSkinSpecific( $options[ 'themeScripts' ], 'scripts' );
+               if ( isset( $options['themeScripts'] ) ) {
+                       $skinScripts = $this->getSkinSpecific( $options['themeScripts'], 'scripts' );
                        if ( !isset( $options['skinScripts'] ) ) {
                                $options['skinScripts'] = [];
                        }
                        $this->extendSkinSpecific( $options['skinScripts'], $skinScripts );
                }
-               if ( isset( $options[ 'themeStyles' ] ) ) {
-                       $skinStyles = $this->getSkinSpecific( $options[ 'themeStyles' ], 'styles' );
+               if ( isset( $options['themeStyles'] ) ) {
+                       $skinStyles = $this->getSkinSpecific( $options['themeStyles'], 'styles' );
                        if ( !isset( $options['skinStyles'] ) ) {
                                $options['skinStyles'] = [];
                        }
index 0a4e94e..0395127 100644 (file)
@@ -104,7 +104,7 @@ trait ResourceLoaderOOUIModule {
         */
        protected function getThemePath( $theme, $kind, $module ) {
                $paths = self::getThemePaths();
-               $path = $paths[ $theme ][ $kind ];
+               $path = $paths[$theme][$kind];
                $path = str_replace( '{module}', $module, $path );
                return $path;
        }
index e0fbeee..2dd6c17 100644 (file)
@@ -91,7 +91,6 @@ class ResourceLoaderSkinModule extends ResourceLoaderFileModule {
        private function getLogoPreloadlinks() {
                $logo = $this->getLogoData( $this->getConfig() );
 
-               $tags = [];
                $logosPerDppx = [];
                $logos = [];
 
@@ -99,14 +98,14 @@ class ResourceLoaderSkinModule extends ResourceLoaderFileModule {
 
                if ( !is_array( $logo ) ) {
                        // No media queries required if we only have one variant
-                       $preloadLinks[ $logo ] = [ 'as' => 'image' ];
+                       $preloadLinks[$logo] = [ 'as' => 'image' ];
                        return $preloadLinks;
                }
 
                if ( isset( $logo['svg'] ) ) {
                        // No media queries required if we only have a 1x and svg variant
                        // because all preload-capable browsers support SVGs
-                       $preloadLinks [ $logo['svg'] ] = [ 'as' => 'image' ];
+                       $preloadLinks[$logo['svg']] = [ 'as' => 'image' ];
                        return $preloadLinks;
                }
 
@@ -125,7 +124,10 @@ class ResourceLoaderSkinModule extends ResourceLoaderFileModule {
                } );
 
                foreach ( $logosPerDppx as $dppx => $src ) {
-                       $logos[] = [ 'dppx' => $dppx, 'src' => $src ];
+                       $logos[] = [
+                               'dppx' => $dppx,
+                               'src' => $src
+                       ];
                }
 
                $logosCount = count( $logos );
@@ -139,21 +141,24 @@ class ResourceLoaderSkinModule extends ResourceLoaderFileModule {
                                // Smallest dppx
                                // min-resolution is ">=" (larger than or equal to)
                                // "not min-resolution" is essentially "<"
-                               $media_query = 'not all and (min-resolution: ' . $logos[ 1 ]['dppx'] . 'dppx)';
+                               $media_query = 'not all and (min-resolution: ' . $logos[1]['dppx'] . 'dppx)';
                        } elseif ( $i !== $logosCount - 1 ) {
                                // In between
                                // Media query expressions can only apply "not" to the entire expression
                                // (e.g. can't express ">= 1.5 and not >= 2).
                                // Workaround: Use <= 1.9999 in place of < 2.
-                               $upper_bound = floatval( $logos[ $i + 1 ]['dppx'] ) - 0.000001;
-                               $media_query = '(min-resolution: ' . $logos[ $i ]['dppx'] .
+                               $upper_bound = floatval( $logos[$i + 1]['dppx'] ) - 0.000001;
+                               $media_query = '(min-resolution: ' . $logos[$i]['dppx'] .
                                        'dppx) and (max-resolution: ' . $upper_bound . 'dppx)';
                        } else {
                                // Largest dppx
-                               $media_query = '(min-resolution: ' . $logos[ $i ]['dppx'] . 'dppx)';
+                               $media_query = '(min-resolution: ' . $logos[$i]['dppx'] . 'dppx)';
                        }
 
-                       $preloadLinks[ $logos[$i]['src'] ] = [ 'as' => 'image', 'media' => $media_query ];
+                       $preloadLinks[$logos[$i]['src']] = [
+                               'as' => 'image',
+                               'media' => $media_query
+                       ];
                }
 
                return $preloadLinks;
index acc2503..c834db1 100644 (file)
@@ -49,16 +49,6 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
        private function getConfigSettings( $context ) {
                $conf = $this->getConfig();
 
-               // We can't use Title::newMainPage() if 'mainpage' is in
-               // $wgForceUIMsgAsContentMsg because that will try to use the session
-               // user's language and we have no session user. This does the
-               // equivalent but falling back to our ResourceLoaderContext language
-               // instead.
-               $mainPage = Title::newFromText( $context->msg( 'mainpage' )->inContentLanguage()->text() );
-               if ( !$mainPage ) {
-                       $mainPage = Title::newFromText( 'Main Page' );
-               }
-
                /**
                 * Namespace related preparation
                 * - wgNamespaceIds: Key-value pairs of all localized, canonical and aliases for namespaces.
@@ -67,9 +57,10 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                $contLang = MediaWikiServices::getInstance()->getContentLanguage();
                $namespaceIds = $contLang->getNamespaceIds();
                $caseSensitiveNamespaces = [];
-               foreach ( MWNamespace::getCanonicalNamespaces() as $index => $name ) {
+               $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
+               foreach ( $nsInfo->getCanonicalNamespaces() as $index => $name ) {
                        $namespaceIds[$contLang->lc( $name )] = $index;
-                       if ( !MWNamespace::isCapitalized( $index ) ) {
+                       if ( !$nsInfo->isCapitalized( $index ) ) {
                                $caseSensitiveNamespaces[] = $index;
                        }
                }
@@ -100,10 +91,9 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                        'wgVersion' => $conf->get( 'Version' ),
                        'wgEnableAPI' => true, // Deprecated since MW 1.32
                        'wgEnableWriteAPI' => true, // Deprecated since MW 1.32
-                       'wgMainPageTitle' => $mainPage->getPrefixedText(),
                        'wgFormattedNamespaces' => $contLang->getFormattedNamespaces(),
                        'wgNamespaceIds' => $namespaceIds,
-                       'wgContentNamespaces' => MWNamespace::getContentNamespaces(),
+                       'wgContentNamespaces' => $nsInfo->getContentNamespaces(),
                        'wgSiteName' => $conf->get( 'Sitename' ),
                        'wgDBname' => $conf->get( 'DBname' ),
                        'wgExtraSignatureNamespaces' => $conf->get( 'ExtraSignatureNamespaces' ),
@@ -331,29 +321,6 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                return true;
        }
 
-       /**
-        * Internal modules used by ResourceLoader that cannot be depended on.
-        *
-        * These module(s) should have isRaw() return true, and are not
-        * legal dependencies (enforced by structure/ResourcesTest).
-        *
-        * @deprecated since 1.32 No longer used.
-        * @return array
-        */
-       public static function getStartupModules() {
-               wfDeprecated( __METHOD__, '1.32' );
-               return [];
-       }
-
-       /**
-        * @deprecated since 1.32 No longer used.
-        * @return array
-        */
-       public static function getLegacyModules() {
-               wfDeprecated( __METHOD__, '1.32' );
-               return [];
-       }
-
        /**
         * @private For internal use by SpecialJavaScriptTest
         * @since 1.32
index a91537f..4c11fce 100644 (file)
@@ -82,7 +82,7 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule {
         *  getPages.
         */
        public function __construct( array $options = null ) {
-               if ( is_null( $options ) ) {
+               if ( $options === null ) {
                        return;
                }
 
@@ -144,15 +144,18 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule {
        }
 
        /**
-        * Get the Database object used in getTitleInfo().
+        * Get the Database handle used for computing the module version.
         *
-        * Defaults to the local replica DB. Subclasses may want to override this to return a foreign
-        * database object, or null if getTitleInfo() shouldn't access the database.
+        * Subclasses may override this to return a foreign database, which would
+        * allow them to register a module on wiki A that fetches wiki pages from
+        * wiki B.
         *
-        * NOTE: This ONLY works for getTitleInfo() and isKnownEmpty(), NOT FOR ANYTHING ELSE.
-        * In particular, it doesn't work for getContent() or getScript() etc.
+        * The way this works is that the local module is a placeholder that can
+        * only computer a module version hash. The 'source' of the module must
+        * be set to the foreign wiki directly. Methods getScript() and getContent()
+        * will not use this handle and are not valid on the local wiki.
         *
-        * @return IDatabase|null
+        * @return IDatabase
         */
        protected function getDB() {
                return wfGetDB( DB_REPLICA );
@@ -379,10 +382,6 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule {
         */
        protected function getTitleInfo( ResourceLoaderContext $context ) {
                $dbr = $this->getDB();
-               if ( !$dbr ) {
-                       // We're dealing with a subclass that doesn't have a DB
-                       return [];
-               }
 
                $pageNames = array_keys( $this->getPages( $context ) );
                sort( $pageNames );
@@ -433,7 +432,7 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule {
                                // Avoid including ids or timestamps of revision/page tables so
                                // that versions are not wasted
                                $title = new TitleValue( (int)$row->page_namespace, $row->page_title );
-                               $titleInfo[ self::makeTitleKey( $title ) ] = [
+                               $titleInfo[self::makeTitleKey( $title )] = [
                                        'page_len' => $row->page_len,
                                        'page_latest' => $row->page_latest,
                                        'page_touched' => $row->page_touched,
@@ -462,8 +461,8 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule {
                        $module = $rl->getModule( $name );
                        if ( $module instanceof self ) {
                                $mDB = $module->getDB();
-                               // Subclasses may disable getDB and implement getTitleInfo differently
-                               if ( $mDB && $mDB->getDomainID() === $db->getDomainID() ) {
+                               // Subclasses may implement getDB differently
+                               if ( $mDB->getDomainID() === $db->getDomainID() ) {
                                        $wikiModules[] = $module;
                                        $allPages += $module->getPages( $context );
                                }
index 7ddf587..221359d 100644 (file)
@@ -224,8 +224,21 @@ abstract class RevDelList extends RevisionListBase {
                                        } elseif ( IP::isIPAddress( $item->getAuthorName() ) ) {
                                                $authorIPs[] = $item->getAuthorName();
                                        }
-                               }
-                               if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) {
+                                       if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) {
+                                               $actorId = $item->getAuthorActor();
+                                               // During migration, the actor field might be empty. If so, populate
+                                               // it here.
+                                               if ( !$actorId ) {
+                                                       if ( $item->getAuthorId() > 0 ) {
+                                                               $user = User::newFromId( $item->getAuthorId() );
+                                                       } else {
+                                                               $user = User::newFromName( $item->getAuthorName(), false );
+                                                       }
+                                                       $actorId = $user->getActorId( $dbw );
+                                               }
+                                               $authorActors[] = $actorId;
+                                       }
+                               } elseif ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) {
                                        $authorActors[] = $item->getAuthorActor();
                                }
 
diff --git a/includes/revisionlist/RevisionItem.php b/includes/revisionlist/RevisionItem.php
new file mode 100644 (file)
index 0000000..faf8d82
--- /dev/null
@@ -0,0 +1,135 @@
+<?php
+/**
+ * Holders of revision list for a single page
+ *
+ * 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
+ */
+
+/**
+ * Item class for a live revision table row
+ */
+class RevisionItem extends RevisionItemBase {
+       /** @var Revision */
+       protected $revision;
+
+       /** @var RequestContext */
+       protected $context;
+
+       public function __construct( $list, $row ) {
+               parent::__construct( $list, $row );
+               $this->revision = new Revision( $row );
+               $this->context = $list->getContext();
+       }
+
+       public function getIdField() {
+               return 'rev_id';
+       }
+
+       public function getTimestampField() {
+               return 'rev_timestamp';
+       }
+
+       public function getAuthorIdField() {
+               return 'rev_user';
+       }
+
+       public function getAuthorNameField() {
+               return 'rev_user_text';
+       }
+
+       public function canView() {
+               return $this->revision->userCan( Revision::DELETED_RESTRICTED, $this->context->getUser() );
+       }
+
+       public function canViewContent() {
+               return $this->revision->userCan( Revision::DELETED_TEXT, $this->context->getUser() );
+       }
+
+       public function isDeleted() {
+               return $this->revision->isDeleted( Revision::DELETED_TEXT );
+       }
+
+       /**
+        * Get the HTML link to the revision text.
+        * @todo Essentially a copy of RevDelRevisionItem::getRevisionLink. That class
+        * should inherit from this one, and implement an appropriate interface instead
+        * of extending RevDelItem
+        * @return string
+        */
+       protected function getRevisionLink() {
+               $date = $this->list->getLanguage()->userTimeAndDate(
+                       $this->revision->getTimestamp(), $this->list->getUser() );
+
+               if ( $this->isDeleted() && !$this->canViewContent() ) {
+                       return htmlspecialchars( $date );
+               }
+               $linkRenderer = $this->getLinkRenderer();
+               return $linkRenderer->makeKnownLink(
+                       $this->list->title,
+                       $date,
+                       [],
+                       [
+                               'oldid' => $this->revision->getId(),
+                               'unhide' => 1
+                       ]
+               );
+       }
+
+       /**
+        * Get the HTML link to the diff.
+        * @todo Essentially a copy of RevDelRevisionItem::getDiffLink. That class
+        * should inherit from this one, and implement an appropriate interface instead
+        * of extending RevDelItem
+        * @return string
+        */
+       protected function getDiffLink() {
+               if ( $this->isDeleted() && !$this->canViewContent() ) {
+                       return $this->context->msg( 'diff' )->escaped();
+               } else {
+                       $linkRenderer = $this->getLinkRenderer();
+                       return $linkRenderer->makeKnownLink(
+                                       $this->list->title,
+                                       $this->list->msg( 'diff' )->text(),
+                                       [],
+                                       [
+                                               'diff' => $this->revision->getId(),
+                                               'oldid' => 'prev',
+                                               'unhide' => 1
+                                       ]
+                               );
+               }
+       }
+
+       /**
+        * @todo Essentially a copy of RevDelRevisionItem::getHTML. That class
+        * should inherit from this one, and implement an appropriate interface instead
+        * of extending RevDelItem
+        * @return string
+        */
+       public function getHTML() {
+               $difflink = $this->context->msg( 'parentheses' )
+                       ->rawParams( $this->getDiffLink() )->escaped();
+               $revlink = $this->getRevisionLink();
+               $userlink = Linker::revUserLink( $this->revision );
+               $comment = Linker::revComment( $this->revision );
+               if ( $this->isDeleted() ) {
+                       $revlink = "<span class=\"history-deleted\">$revlink</span>";
+               }
+               return "<li>$difflink $revlink $userlink $comment</li>";
+       }
+}
diff --git a/includes/revisionlist/RevisionItemBase.php b/includes/revisionlist/RevisionItemBase.php
new file mode 100644 (file)
index 0000000..dcb2f39
--- /dev/null
@@ -0,0 +1,177 @@
+<?php
+/**
+ * Holders of revision list for a single page
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * Abstract base class for revision items
+ */
+abstract class RevisionItemBase {
+       /** @var RevisionListBase The parent */
+       protected $list;
+
+       /** The database result row */
+       protected $row;
+
+       /**
+        * @param RevisionListBase $list
+        * @param object $row DB result row
+        */
+       public function __construct( $list, $row ) {
+               $this->list = $list;
+               $this->row = $row;
+       }
+
+       /**
+        * Get the DB field name associated with the ID list.
+        * Override this function.
+        * @return null
+        */
+       public function getIdField() {
+               return null;
+       }
+
+       /**
+        * Get the DB field name storing timestamps.
+        * Override this function.
+        * @return bool
+        */
+       public function getTimestampField() {
+               return false;
+       }
+
+       /**
+        * Get the DB field name storing user ids.
+        * Override this function.
+        * @return bool
+        */
+       public function getAuthorIdField() {
+               return false;
+       }
+
+       /**
+        * Get the DB field name storing user names.
+        * Override this function.
+        * @return bool
+        */
+       public function getAuthorNameField() {
+               return false;
+       }
+
+       /**
+        * Get the DB field name storing actor ids.
+        * Override this function.
+        * @since 1.31
+        * @return bool
+        */
+       public function getAuthorActorField() {
+               return false;
+       }
+
+       /**
+        * Get the ID, as it would appear in the ids URL parameter
+        * @return int
+        */
+       public function getId() {
+               $field = $this->getIdField();
+               return $this->row->$field;
+       }
+
+       /**
+        * Get the date, formatted in user's language
+        * @return string
+        */
+       public function formatDate() {
+               return $this->list->getLanguage()->userDate( $this->getTimestamp(),
+                       $this->list->getUser() );
+       }
+
+       /**
+        * Get the time, formatted in user's language
+        * @return string
+        */
+       public function formatTime() {
+               return $this->list->getLanguage()->userTime( $this->getTimestamp(),
+                       $this->list->getUser() );
+       }
+
+       /**
+        * Get the timestamp in MW 14-char form
+        * @return mixed
+        */
+       public function getTimestamp() {
+               $field = $this->getTimestampField();
+               return wfTimestamp( TS_MW, $this->row->$field );
+       }
+
+       /**
+        * Get the author user ID
+        * @return int
+        */
+       public function getAuthorId() {
+               $field = $this->getAuthorIdField();
+               return intval( $this->row->$field );
+       }
+
+       /**
+        * Get the author user name
+        * @return string
+        */
+       public function getAuthorName() {
+               $field = $this->getAuthorNameField();
+               return strval( $this->row->$field );
+       }
+
+       /**
+        * Get the author actor ID
+        * @since 1.31
+        * @return string
+        */
+       public function getAuthorActor() {
+               $field = $this->getAuthorActorField();
+               return strval( $this->row->$field );
+       }
+
+       /**
+        * Returns true if the current user can view the item
+        */
+       abstract public function canView();
+
+       /**
+        * Returns true if the current user can view the item text/file
+        */
+       abstract public function canViewContent();
+
+       /**
+        * Get the HTML of the list item. Should be include "<li></li>" tags.
+        * This is used to show the list in HTML form, by the special page.
+        */
+       abstract public function getHTML();
+
+       /**
+        * Returns an instance of LinkRenderer
+        * @return \MediaWiki\Linker\LinkRenderer
+        */
+       protected function getLinkRenderer() {
+               return MediaWikiServices::getInstance()->getLinkRenderer();
+       }
+}
diff --git a/includes/revisionlist/RevisionList.php b/includes/revisionlist/RevisionList.php
new file mode 100644 (file)
index 0000000..e7fab9b
--- /dev/null
@@ -0,0 +1,53 @@
+<?php
+/**
+ * Holders of revision list for a single page
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+use Wikimedia\Rdbms\IDatabase;
+
+class RevisionList extends RevisionListBase {
+       public function getType() {
+               return 'revision';
+       }
+
+       /**
+        * @param IDatabase $db
+        * @return mixed
+        */
+       public function doQuery( $db ) {
+               $conds = [ 'rev_page' => $this->title->getArticleID() ];
+               if ( $this->ids !== null ) {
+                       $conds['rev_id'] = array_map( 'intval', $this->ids );
+               }
+               $revQuery = Revision::getQueryInfo( [ 'page', 'user' ] );
+               return $db->select(
+                       $revQuery['tables'],
+                       $revQuery['fields'],
+                       $conds,
+                       __METHOD__,
+                       [ 'ORDER BY' => 'rev_id DESC' ],
+                       $revQuery['joins']
+               );
+       }
+
+       public function newItem( $row ) {
+               return new RevisionItem( $this, $row );
+       }
+}
diff --git a/includes/revisionlist/RevisionListBase.php b/includes/revisionlist/RevisionListBase.php
new file mode 100644 (file)
index 0000000..fb379c9
--- /dev/null
@@ -0,0 +1,148 @@
+<?php
+/**
+ * Holders of revision list for a single page
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+use Wikimedia\Rdbms\ResultWrapper;
+use Wikimedia\Rdbms\IDatabase;
+
+/**
+ * List for revision table items for a single page
+ */
+abstract class RevisionListBase extends ContextSource implements Iterator {
+       /** @var Title */
+       public $title;
+
+       /** @var array */
+       protected $ids;
+
+       /** @var ResultWrapper|bool */
+       protected $res;
+
+       /** @var bool|Revision */
+       protected $current;
+
+       /**
+        * Construct a revision list for a given title
+        * @param IContextSource $context
+        * @param Title $title
+        */
+       function __construct( IContextSource $context, Title $title ) {
+               $this->setContext( $context );
+               $this->title = $title;
+       }
+
+       /**
+        * Select items only where the ID is any of the specified values
+        * @param array $ids
+        */
+       function filterByIds( array $ids ) {
+               $this->ids = $ids;
+       }
+
+       /**
+        * Get the internal type name of this list. Equal to the table name.
+        * Override this function.
+        * @return null
+        */
+       public function getType() {
+               return null;
+       }
+
+       /**
+        * Initialise the current iteration pointer
+        */
+       protected function initCurrent() {
+               $row = $this->res->current();
+               if ( $row ) {
+                       $this->current = $this->newItem( $row );
+               } else {
+                       $this->current = false;
+               }
+       }
+
+       /**
+        * Start iteration. This must be called before current() or next().
+        * @return Revision First list item
+        */
+       public function reset() {
+               if ( !$this->res ) {
+                       $this->res = $this->doQuery( wfGetDB( DB_REPLICA ) );
+               } else {
+                       $this->res->rewind();
+               }
+               $this->initCurrent();
+               return $this->current;
+       }
+
+       public function rewind() {
+               $this->reset();
+       }
+
+       /**
+        * Get the current list item, or false if we are at the end
+        * @return Revision
+        */
+       public function current() {
+               return $this->current;
+       }
+
+       /**
+        * Move the iteration pointer to the next list item, and return it.
+        * @return Revision
+        */
+       public function next() {
+               $this->res->next();
+               $this->initCurrent();
+               return $this->current;
+       }
+
+       public function key() {
+               return $this->res ? $this->res->key() : 0;
+       }
+
+       public function valid() {
+               return $this->res ? $this->res->valid() : false;
+       }
+
+       /**
+        * Get the number of items in the list.
+        * @return int
+        */
+       public function length() {
+               if ( !$this->res ) {
+                       return 0;
+               } else {
+                       return $this->res->numRows();
+               }
+       }
+
+       /**
+        * Do the DB query to iterate through the objects.
+        * @param IDatabase $db DB object to use for the query
+        */
+       abstract public function doQuery( $db );
+
+       /**
+        * Create an item object from a DB result row
+        * @param object $row
+        */
+       abstract public function newItem( $row );
+}
index ff1e8cb..22f5998 100644 (file)
@@ -22,6 +22,7 @@ class NullIndexField implements SearchIndexField {
         * @return $this
         */
        public function setFlag( $flag, $unset = false ) {
+               return $this;
        }
 
        /**
diff --git a/includes/search/PrefixSearch.php b/includes/search/PrefixSearch.php
new file mode 100644 (file)
index 0000000..3b7a0a9
--- /dev/null
@@ -0,0 +1,328 @@
+<?php
+/**
+ * Prefix search of page names.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * Handles searching prefixes of titles and finding any page
+ * names that match. Used largely by the OpenSearch implementation.
+ * @deprecated Since 1.27, Use SearchEngine::defaultPrefixSearch or SearchEngine::completionSearch
+ *
+ * @ingroup Search
+ */
+abstract class PrefixSearch {
+       /**
+        * Do a prefix search of titles and return a list of matching page names.
+        * @deprecated Since 1.23, use TitlePrefixSearch or StringPrefixSearch classes
+        *
+        * @param string $search
+        * @param int $limit
+        * @param array $namespaces Used if query is not explicitly prefixed
+        * @param int $offset How many results to offset from the beginning
+        * @return array Array of strings
+        */
+       public static function titleSearch( $search, $limit, $namespaces = [], $offset = 0 ) {
+               wfDeprecated( __METHOD__, '1.23' );
+               $prefixSearch = new StringPrefixSearch;
+               return $prefixSearch->search( $search, $limit, $namespaces, $offset );
+       }
+
+       /**
+        * Do a prefix search of titles and return a list of matching page names.
+        *
+        * @param string $search
+        * @param int $limit
+        * @param array $namespaces Used if query is not explicitly prefixed
+        * @param int $offset How many results to offset from the beginning
+        * @return array Array of strings or Title objects
+        */
+       public function search( $search, $limit, $namespaces = [], $offset = 0 ) {
+               $search = trim( $search );
+               if ( $search == '' ) {
+                       return []; // Return empty result
+               }
+
+               $hasNamespace = SearchEngine::parseNamespacePrefixes( $search, false, true );
+               if ( $hasNamespace !== false ) {
+                       list( $search, $namespaces ) = $hasNamespace;
+               }
+
+               return $this->searchBackend( $namespaces, $search, $limit, $offset );
+       }
+
+       /**
+        * Do a prefix search for all possible variants of the prefix
+        * @param string $search
+        * @param int $limit
+        * @param array $namespaces
+        * @param int $offset How many results to offset from the beginning
+        *
+        * @return array
+        */
+       public function searchWithVariants( $search, $limit, array $namespaces, $offset = 0 ) {
+               $searches = $this->search( $search, $limit, $namespaces, $offset );
+
+               // if the content language has variants, try to retrieve fallback results
+               $fallbackLimit = $limit - count( $searches );
+               if ( $fallbackLimit > 0 ) {
+                       $fallbackSearches = MediaWikiServices::getInstance()->getContentLanguage()->
+                               autoConvertToAllVariants( $search );
+                       $fallbackSearches = array_diff( array_unique( $fallbackSearches ), [ $search ] );
+
+                       foreach ( $fallbackSearches as $fbs ) {
+                               $fallbackSearchResult = $this->search( $fbs, $fallbackLimit, $namespaces );
+                               $searches = array_merge( $searches, $fallbackSearchResult );
+                               $fallbackLimit -= count( $fallbackSearchResult );
+
+                               if ( $fallbackLimit == 0 ) {
+                                       break;
+                               }
+                       }
+               }
+               return $searches;
+       }
+
+       /**
+        * When implemented in a descendant class, receives an array of Title objects and returns
+        * either an unmodified array or an array of strings corresponding to titles passed to it.
+        *
+        * @param array $titles
+        * @return array
+        */
+       abstract protected function titles( array $titles );
+
+       /**
+        * When implemented in a descendant class, receives an array of titles as strings and returns
+        * either an unmodified array or an array of Title objects corresponding to strings received.
+        *
+        * @param array $strings
+        *
+        * @return array
+        */
+       abstract protected function strings( array $strings );
+
+       /**
+        * Do a prefix search of titles and return a list of matching page names.
+        * @param array $namespaces
+        * @param string $search
+        * @param int $limit
+        * @param int $offset How many results to offset from the beginning
+        * @return array Array of strings
+        */
+       protected function searchBackend( $namespaces, $search, $limit, $offset ) {
+               if ( count( $namespaces ) == 1 ) {
+                       $ns = $namespaces[0];
+                       if ( $ns == NS_MEDIA ) {
+                               $namespaces = [ NS_FILE ];
+                       } elseif ( $ns == NS_SPECIAL ) {
+                               return $this->titles( $this->specialSearch( $search, $limit, $offset ) );
+                       }
+               }
+               $srchres = [];
+               if ( Hooks::run(
+                       'PrefixSearchBackend',
+                       [ $namespaces, $search, $limit, &$srchres, $offset ]
+               ) ) {
+                       return $this->titles( $this->defaultSearchBackend( $namespaces, $search, $limit, $offset ) );
+               }
+               return $this->strings(
+                       $this->handleResultFromHook( $srchres, $namespaces, $search, $limit, $offset ) );
+       }
+
+       private function handleResultFromHook( $srchres, $namespaces, $search, $limit, $offset ) {
+               if ( $offset === 0 ) {
+                       // Only perform exact db match if offset === 0
+                       // This is still far from perfect but at least we avoid returning the
+                       // same title afain and again when the user is scrolling with a query
+                       // that matches a title in the db.
+                       $rescorer = new SearchExactMatchRescorer();
+                       $srchres = $rescorer->rescore( $search, $namespaces, $srchres, $limit );
+               }
+               return $srchres;
+       }
+
+       /**
+        * Prefix search special-case for Special: namespace.
+        *
+        * @param string $search Term
+        * @param int $limit Max number of items to return
+        * @param int $offset Number of items to offset
+        * @return array
+        */
+       protected function specialSearch( $search, $limit, $offset ) {
+               $searchParts = explode( '/', $search, 2 );
+               $searchKey = $searchParts[0];
+               $subpageSearch = $searchParts[1] ?? null;
+
+               // Handle subpage search separately.
+               $spFactory = MediaWikiServices::getInstance()->getSpecialPageFactory();
+               if ( $subpageSearch !== null ) {
+                       // Try matching the full search string as a page name
+                       $specialTitle = Title::makeTitleSafe( NS_SPECIAL, $searchKey );
+                       if ( !$specialTitle ) {
+                               return [];
+                       }
+                       $special = $spFactory->getPage( $specialTitle->getText() );
+                       if ( $special ) {
+                               $subpages = $special->prefixSearchSubpages( $subpageSearch, $limit, $offset );
+                               return array_map( function ( $sub ) use ( $specialTitle ) {
+                                       return $specialTitle->getSubpage( $sub );
+                               }, $subpages );
+                       } else {
+                               return [];
+                       }
+               }
+
+               # normalize searchKey, so aliases with spaces can be found - T27675
+               $contLang = MediaWikiServices::getInstance()->getContentLanguage();
+               $searchKey = str_replace( ' ', '_', $searchKey );
+               $searchKey = $contLang->caseFold( $searchKey );
+
+               // Unlike SpecialPage itself, we want the canonical forms of both
+               // canonical and alias title forms...
+               $keys = [];
+               foreach ( $spFactory->getNames() as $page ) {
+                       $keys[$contLang->caseFold( $page )] = [ 'page' => $page, 'rank' => 0 ];
+               }
+
+               foreach ( $contLang->getSpecialPageAliases() as $page => $aliases ) {
+                       if ( !in_array( $page, $spFactory->getNames() ) ) {# T22885
+                               continue;
+                       }
+
+                       foreach ( $aliases as $key => $alias ) {
+                               $keys[$contLang->caseFold( $alias )] = [ 'page' => $alias, 'rank' => $key ];
+                       }
+               }
+               ksort( $keys );
+
+               $matches = [];
+               foreach ( $keys as $pageKey => $page ) {
+                       if ( $searchKey === '' || strpos( $pageKey, $searchKey ) === 0 ) {
+                               // T29671: Don't use SpecialPage::getTitleFor() here because it
+                               // localizes its input leading to searches for e.g. Special:All
+                               // returning Spezial:MediaWiki-Systemnachrichten and returning
+                               // Spezial:Alle_Seiten twice when $wgLanguageCode == 'de'
+                               $matches[$page['rank']][] = Title::makeTitleSafe( NS_SPECIAL, $page['page'] );
+
+                               if ( isset( $matches[0] ) && count( $matches[0] ) >= $limit + $offset ) {
+                                       // We have enough items in primary rank, no use to continue
+                                       break;
+                               }
+                       }
+
+               }
+
+               // Ensure keys are in order
+               ksort( $matches );
+               // Flatten the array
+               $matches = array_reduce( $matches, 'array_merge', [] );
+
+               return array_slice( $matches, $offset, $limit );
+       }
+
+       /**
+        * Unless overridden by PrefixSearchBackend hook...
+        * This is case-sensitive (First character may
+        * be automatically capitalized by Title::secureAndSpit()
+        * later on depending on $wgCapitalLinks)
+        *
+        * @param array|null $namespaces Namespaces to search in
+        * @param string $search Term
+        * @param int $limit Max number of items to return
+        * @param int $offset Number of items to skip
+        * @return Title[] Array of Title objects
+        */
+       public function defaultSearchBackend( $namespaces, $search, $limit, $offset ) {
+               // Backwards compatability with old code. Default to NS_MAIN if no namespaces provided.
+               if ( $namespaces === null ) {
+                       $namespaces = [];
+               }
+               if ( !$namespaces ) {
+                       $namespaces[] = NS_MAIN;
+               }
+
+               // Construct suitable prefix for each namespace. They differ in cases where
+               // some namespaces always capitalize and some don't.
+               $prefixes = [];
+               foreach ( $namespaces as $namespace ) {
+                       // For now, if special is included, ignore the other namespaces
+                       if ( $namespace == NS_SPECIAL ) {
+                               return $this->specialSearch( $search, $limit, $offset );
+                       }
+
+                       $title = Title::makeTitleSafe( $namespace, $search );
+                       // Why does the prefix default to empty?
+                       $prefix = $title ? $title->getDBkey() : '';
+                       $prefixes[$prefix][] = $namespace;
+               }
+
+               $dbr = wfGetDB( DB_REPLICA );
+               // Often there is only one prefix that applies to all requested namespaces,
+               // but sometimes there are two if some namespaces do not always capitalize.
+               $conds = [];
+               foreach ( $prefixes as $prefix => $namespaces ) {
+                       $condition = [
+                               'page_namespace' => $namespaces,
+                               'page_title' . $dbr->buildLike( $prefix, $dbr->anyString() ),
+                       ];
+                       $conds[] = $dbr->makeList( $condition, LIST_AND );
+               }
+
+               $table = 'page';
+               $fields = [ 'page_id', 'page_namespace', 'page_title' ];
+               $conds = $dbr->makeList( $conds, LIST_OR );
+               $options = [
+                       'LIMIT' => $limit,
+                       'ORDER BY' => [ 'page_title', 'page_namespace' ],
+                       'OFFSET' => $offset
+               ];
+
+               $res = $dbr->select( $table, $fields, $conds, __METHOD__, $options );
+
+               return iterator_to_array( TitleArray::newFromResult( $res ) );
+       }
+
+       /**
+        * Validate an array of numerical namespace indexes
+        *
+        * @param array $namespaces
+        * @return array (default: contains only NS_MAIN)
+        */
+       protected function validateNamespaces( $namespaces ) {
+               // We will look at each given namespace against content language namespaces
+               $validNamespaces = MediaWikiServices::getInstance()->getContentLanguage()->getNamespaces();
+               if ( is_array( $namespaces ) && count( $namespaces ) > 0 ) {
+                       $valid = [];
+                       foreach ( $namespaces as $ns ) {
+                               if ( is_numeric( $ns ) && array_key_exists( $ns, $validNamespaces ) ) {
+                                       $valid[] = $ns;
+                               }
+                       }
+                       if ( count( $valid ) > 0 ) {
+                               return $valid;
+                       }
+               }
+
+               return [ NS_MAIN ];
+       }
+}
index 54bfd28..230cded 100644 (file)
@@ -38,11 +38,7 @@ abstract class SearchDatabase extends SearchEngine {
         * @param IDatabase|null $db The database to search from
         */
        public function __construct( IDatabase $db = null ) {
-               if ( $db ) {
-                       $this->db = $db;
-               } else {
-                       $this->db = wfGetDB( DB_REPLICA );
-               }
+               $this->db = $db ?: wfGetDB( DB_REPLICA );
        }
 
        /**
index 0b29dd7..9771e88 100644 (file)
@@ -56,16 +56,16 @@ abstract class SearchEngine {
        /** @var array Feature values */
        protected $features = [];
 
-       /** @const string profile type for completionSearch */
+       /** Profile type for completionSearch */
        const COMPLETION_PROFILE_TYPE = 'completionSearchProfile';
 
-       /** @const string profile type for query independent ranking features */
+       /** Profile type for query independent ranking features */
        const FT_QUERY_INDEP_PROFILE_TYPE = 'fulltextQueryIndepProfile';
 
-       /** @const int flag for legalSearchChars: includes all chars allowed in a search query */
+       /** Integer flag for legalSearchChars: includes all chars allowed in a search query */
        const CHARS_ALL = 1;
 
-       /** @const int flag for legalSearchChars: includes all chars allowed in a search term */
+       /** Integer flag for legalSearchChars: includes all chars allowed in a search term */
        const CHARS_NO_SYNTAX = 2;
 
        /**
@@ -235,19 +235,6 @@ abstract class SearchEngine {
                return MediaWikiServices::getInstance()->getContentLanguage()->segmentByWord( $string );
        }
 
-       /**
-        * Transform search term in cases when parts of the query came as different
-        * GET params (when supported), e.g. for prefix queries:
-        * search=test&prefix=Main_Page/Archive -> test prefix:Main Page/Archive
-        * @param string $term
-        * @return string
-        * @deprecated since 1.32 this should now be handled internally by the
-        * search engine
-        */
-       public function transformSearchTerm( $term ) {
-               return $term;
-       }
-
        /**
         * Get service class to finding near matches.
         * @param Config $config Configuration to use for the matcher.
@@ -268,25 +255,13 @@ abstract class SearchEngine {
                return $services->newSearchEngine()->getNearMatcher( $config );
        }
 
-       /**
-        * If an exact title match can be found, or a very slightly close match,
-        * return the title. If no match, returns NULL.
-        * @deprecated since 1.27; Use SearchEngine::getNearMatcher()
-        * @param string $searchterm
-        * @return Title
-        */
-       public static function getNearMatch( $searchterm ) {
-               return static::defaultNearMatcher()->getNearMatch( $searchterm );
-       }
-
        /**
         * Get chars legal for search
-        * NOTE: usage as static is deprecated and preserved only as BC measure
         * @param int $type type of search chars (see self::CHARS_ALL
         * and self::CHARS_NO_SYNTAX). Defaults to CHARS_ALL
         * @return string
         */
-       public static function legalSearchChars( $type = self::CHARS_ALL ) {
+       public function legalSearchChars( $type = self::CHARS_ALL ) {
                return "A-Za-z_'.0-9\\x80-\\xFF\\-";
        }
 
@@ -311,7 +286,7 @@ abstract class SearchEngine {
        function setNamespaces( $namespaces ) {
                if ( $namespaces ) {
                        // Filter namespaces to only keep valid ones
-                       $validNs = $this->searchableNamespaces();
+                       $validNs = MediaWikiServices::getInstance()->getSearchEngineConfig()->searchableNamespaces();
                        $namespaces = array_filter( $namespaces, function ( $ns ) use( $validNs ) {
                                return $ns < 0 || isset( $validNs[$ns] );
                        } );
@@ -730,67 +705,6 @@ abstract class SearchEngine {
                return $backend->defaultSearchBackend( $this->namespaces, $search, $this->limit, $this->offset );
        }
 
-       /**
-        * Make a list of searchable namespaces and their canonical names.
-        * @deprecated since 1.27; use SearchEngineConfig::searchableNamespaces()
-        * @return array
-        */
-       public static function searchableNamespaces() {
-               return MediaWikiServices::getInstance()->getSearchEngineConfig()->searchableNamespaces();
-       }
-
-       /**
-        * Extract default namespaces to search from the given user's
-        * settings, returning a list of index numbers.
-        * @deprecated since 1.27; use SearchEngineConfig::userNamespaces()
-        * @param user $user
-        * @return array
-        */
-       public static function userNamespaces( $user ) {
-               return MediaWikiServices::getInstance()->getSearchEngineConfig()->userNamespaces( $user );
-       }
-
-       /**
-        * An array of namespaces indexes to be searched by default
-        * @deprecated since 1.27; use SearchEngineConfig::defaultNamespaces()
-        * @return array
-        */
-       public static function defaultNamespaces() {
-               return MediaWikiServices::getInstance()->getSearchEngineConfig()->defaultNamespaces();
-       }
-
-       /**
-        * Get a list of namespace names useful for showing in tooltips
-        * and preferences
-        * @deprecated since 1.27; use SearchEngineConfig::namespacesAsText()
-        * @param array $namespaces
-        * @return array
-        */
-       public static function namespacesAsText( $namespaces ) {
-               return MediaWikiServices::getInstance()->getSearchEngineConfig()->namespacesAsText( $namespaces );
-       }
-
-       /**
-        * Load up the appropriate search engine class for the currently
-        * active database backend, and return a configured instance.
-        * @deprecated since 1.27; Use SearchEngineFactory::create
-        * @param string $type Type of search backend, if not the default
-        * @return SearchEngine
-        */
-       public static function create( $type = null ) {
-               return MediaWikiServices::getInstance()->getSearchEngineFactory()->create( $type );
-       }
-
-       /**
-        * Return the search engines we support. If only $wgSearchType
-        * is set, it'll be an array of just that one item.
-        * @deprecated since 1.27; use SearchEngineConfig::getSearchTypes()
-        * @return array
-        */
-       public static function getSearchTypes() {
-               return MediaWikiServices::getInstance()->getSearchEngineConfig()->getSearchTypes();
-       }
-
        /**
         * Get a list of supported profiles.
         * Some search engine implementations may expose specific profiles to fine-tune
@@ -814,7 +728,7 @@ abstract class SearchEngine {
         * Create a search field definition.
         * Specific search engines should override this method to create search fields.
         * @param string $name
-        * @param int $type One of the types in SearchIndexField::INDEX_TYPE_*
+        * @param string $type One of the types in SearchIndexField::INDEX_TYPE_*
         * @return SearchIndexField
         * @since 1.28
         */
@@ -894,13 +808,3 @@ abstract class SearchEngine {
                }
        }
 }
-
-/**
- * Dummy class to be used when non-supported Database engine is present.
- * @todo FIXME: Dummy class should probably try something at least mildly useful,
- * such as a LIKE search through titles.
- * @ingroup Search
- */
-class SearchEngineDummy extends SearchEngine {
-       // no-op
-}
diff --git a/includes/search/SearchEngineDummy.php b/includes/search/SearchEngineDummy.php
new file mode 100644 (file)
index 0000000..b3db28b
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Dummy search engine
+ *
+ * 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 Search
+ */
+
+/**
+ * Dummy class to be used when non-supported Database engine is present.
+ * @todo FIXME: Dummy class should probably try something at least mildly useful,
+ * such as a LIKE search through titles.
+ * @ingroup Search
+ */
+class SearchEngineDummy extends SearchEngine {
+       // no-op
+}
index daeb5f5..7bc4ba5 100644 (file)
@@ -15,17 +15,17 @@ interface SearchIndexField {
         * https://wikimediafoundation.org/2018/08/07/anatomy-search-token-affection/
         * https://wikimediafoundation.org/2018/09/13/anatomy-search-variation-under-nature/
         */
-       const INDEX_TYPE_TEXT = 0;
+       const INDEX_TYPE_TEXT = 'text';
        /**
         * KEYWORD fields are indexed without any processing, so are appropriate
         * for e.g. URLs.  The content will often consist of a single token.
         */
-       const INDEX_TYPE_KEYWORD = 1;
-       const INDEX_TYPE_INTEGER = 2;
-       const INDEX_TYPE_NUMBER = 3;
-       const INDEX_TYPE_DATETIME = 4;
-       const INDEX_TYPE_NESTED = 5;
-       const INDEX_TYPE_BOOL = 6;
+       const INDEX_TYPE_KEYWORD = 'keyword';
+       const INDEX_TYPE_INTEGER = 'integer';
+       const INDEX_TYPE_NUMBER = 'number';
+       const INDEX_TYPE_DATETIME = 'datetime';
+       const INDEX_TYPE_NESTED = 'nested';
+       const INDEX_TYPE_BOOL = 'bool';
 
        /**
         * SHORT_TEXT is meant to be used with short text made of mostly ascii
@@ -33,7 +33,7 @@ interface SearchIndexField {
         * is used and aggressive splitting to increase recall.
         * E.g suited for mime/type
         */
-       const INDEX_TYPE_SHORT_TEXT = 7;
+       const INDEX_TYPE_SHORT_TEXT = 'short_text';
 
        /**
         * Generic field flags.
index a11dff9..d0d2b89 100644 (file)
@@ -20,7 +20,7 @@ abstract class SearchIndexFieldDefinition implements SearchIndexField {
        /**
         * Type of the field, one of the constants above
         *
-        * @var int
+        * @var string
         */
        protected $type;
 
@@ -44,7 +44,7 @@ abstract class SearchIndexFieldDefinition implements SearchIndexField {
 
        /**
         * @param string $name Field name
-        * @param int $type Index type
+        * @param string $type Index type
         */
        public function __construct( $name, $type ) {
                $this->name = $name;
index 9f10697..cae3426 100644 (file)
@@ -149,7 +149,7 @@ class SearchMySQL extends SearchDatabase {
                return $regex;
        }
 
-       public static function legalSearchChars( $type = self::CHARS_ALL ) {
+       public function legalSearchChars( $type = self::CHARS_ALL ) {
                $searchChars = parent::legalSearchChars( $type );
                if ( $type === self::CHARS_ALL ) {
                        // " for phrase, * for wildcard
index 0a64493..9ee3e17 100644 (file)
@@ -165,7 +165,7 @@ class SearchNearMatcher {
                # Quoted term? Try without the quotes...
                $matches = [];
                if ( preg_match( '/^"([^"]+)"$/', $searchterm, $matches ) ) {
-                       return self::getNearMatch( $matches[1] );
+                       return $this->getNearMatch( $matches[1] );
                }
 
                return null;
index 0cbb41c..6b2b403 100644 (file)
@@ -267,7 +267,7 @@ class SearchOracle extends SearchDatabase {
                        [] );
        }
 
-       public static function legalSearchChars( $type = self::CHARS_ALL ) {
+       public function legalSearchChars( $type = self::CHARS_ALL ) {
                $searchChars = parent::legalSearchChars( $type );
                if ( $type === self::CHARS_ALL ) {
                        $searchChars = "\"" . $searchChars;
index 6d5f117..74ee552 100644 (file)
@@ -23,6 +23,8 @@
  * @file
  * @ingroup Search
  */
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Revision\SlotRecord;
 
 /**
  * Search engine hook base class for Postgres
@@ -137,10 +139,16 @@ class SearchPostgres extends SearchDatabase {
                $top = $res->fetchRow()[0];
 
                $this->searchTerms = [];
+               $slotRoleStore = MediaWikiServices::getInstance()->getSlotRoleStore();
                if ( $top === "" ) { # # e.g. if only stopwords are used XXX return something better
                        $query = "SELECT page_id, page_namespace, page_title, 0 AS score " .
-                               "FROM page p, revision r, pagecontent c WHERE p.page_latest = r.rev_id " .
-                               "AND r.rev_text_id = c.old_id AND 1=0";
+                               "FROM page p, revision r, slots s, content c, pagecontent pc " .
+                               "WHERE p.page_latest = r.rev_id " .
+                               "AND s.slot_revision_id = r.rev_id " .
+                               "AND s.slot_role_id = " . $slotRoleStore->getId( SlotRecord::MAIN ) . " " .
+                               "AND c.content_id = s.slot_content_id " .
+                               "AND pc.old_id = substring( c.content_address from '^tt:([0-9]+)$' )::int " .
+                               "AND 1=0";
                } else {
                        $m = [];
                        if ( preg_match_all( "/'([^']+)'/", $top, $m, PREG_SET_ORDER ) ) {
@@ -151,10 +159,14 @@ class SearchPostgres extends SearchDatabase {
 
                        $query = "SELECT page_id, page_namespace, page_title, " .
                                "ts_rank($fulltext, to_tsquery($searchstring), 5) AS score " .
-                               "FROM page p, revision r, pagecontent c WHERE p.page_latest = r.rev_id " .
-                               "AND r.rev_text_id = c.old_id AND $fulltext @@ to_tsquery($searchstring)";
+                               "FROM page p, revision r, slots s, content c, pagecontent pc " .
+                               "WHERE p.page_latest = r.rev_id " .
+                               "AND s.slot_revision_id = r.rev_id " .
+                               "AND s.slot_role_id = " . $slotRoleStore->getId( SlotRecord::MAIN ) . " " .
+                               "AND c.content_id = s.slot_content_id " .
+                               "AND pc.old_id = substring( c.content_address from '^tt:([0-9]+)$' )::int " .
+                               "AND $fulltext @@ to_tsquery($searchstring)";
                }
-
                # # Namespaces - defaults to 0
                if ( !is_null( $this->namespaces ) ) { // null -> search all
                        if ( count( $this->namespaces ) < 1 ) {
@@ -178,9 +190,17 @@ class SearchPostgres extends SearchDatabase {
 
        function update( $pageid, $title, $text ) {
                # # We don't want to index older revisions
-               $sql = "UPDATE pagecontent SET textvector = NULL WHERE textvector IS NOT NULL and old_id IN " .
-                               "(SELECT DISTINCT rev_text_id FROM revision WHERE rev_page = " . intval( $pageid ) .
-                               " ORDER BY rev_text_id DESC OFFSET 1)";
+               $slotRoleStore = MediaWikiServices::getInstance()->getSlotRoleStore();
+               $sql = "UPDATE pagecontent SET textvector = NULL " .
+                       "WHERE textvector IS NOT NULL " .
+                       "AND old_id IN " .
+                       "(SELECT DISTINCT substring( c.content_address from '^tt:([0-9]+)$' )::int AS old_rev_text_id " .
+                       " FROM content c, slots s, revision r " .
+                       " WHERE r.rev_page = $pageid " .
+                       " AND s.slot_revision_id = r.rev_id " .
+                       " AND s.slot_role_id = " . $slotRoleStore->getId( SlotRecord::MAIN ) . " " .
+                       " AND c.content_id = s.slot_content_id " .
+                       " ORDER BY old_rev_text_id DESC OFFSET 1)";
                $this->db->query( $sql );
                return true;
        }
index bd19a84..f85c58f 100644 (file)
@@ -285,7 +285,7 @@ class SearchResult {
                if ( $extensionData instanceof Closure ) {
                        $this->extensionData = $extensionData;
                } elseif ( is_array( $extensionData ) ) {
-                       wfDeprecated( __METHOD__ . ' with array argument', 1.32 );
+                       wfDeprecated( __METHOD__ . ' with array argument', '1.32' );
                        $this->extensionData = function () use ( $extensionData ) {
                                return $extensionData;
                        };
index 2f1a5c2..3d3b446 100644 (file)
  * @ingroup Search
  */
 class SearchResultSet implements Countable, IteratorAggregate {
+
        /**
-        * Types of interwiki results
-        */
-       /**
-        * Results that are displayed only together with existing main wiki results
-        * @var int
+        * Identifier for interwiki results that are displayed only together with existing main wiki
+        * results.
         */
        const SECONDARY_RESULTS = 0;
+
        /**
-        * Results that can displayed even if no existing main wiki results exist
-        * @var int
+        * Identifier for interwiki results that can be displayed even if no existing main wiki results
+        * exist.
         */
        const INLINE_RESULTS = 1;
 
@@ -85,7 +84,7 @@ class SearchResultSet implements Countable, IteratorAggregate {
                        // This class will eventually be abstract. SearchEngine implementations
                        // already have to extend this class anyways to provide the actual
                        // search results.
-                       wfDeprecated( __METHOD__, 1.32 );
+                       wfDeprecated( __METHOD__, '1.32' );
                }
                $this->containedSyntax = $containedSyntax;
                $this->hasMoreResults = $hasMoreResults;
index f653796..c304797 100644 (file)
@@ -142,7 +142,7 @@ class SearchSqlite extends SearchDatabase {
                return $regex;
        }
 
-       public static function legalSearchChars( $type = self::CHARS_ALL ) {
+       public function legalSearchChars( $type = self::CHARS_ALL ) {
                $searchChars = parent::legalSearchChars( $type );
                if ( $type === self::CHARS_ALL ) {
                        // " for phrase, * for wildcard
diff --git a/includes/search/StringPrefixSearch.php b/includes/search/StringPrefixSearch.php
new file mode 100644 (file)
index 0000000..517518e
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+/**
+ * Prefix search of page names.
+ *
+ * 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
+ */
+
+/**
+ * Performs prefix search, returning strings
+ * @deprecated Since 1.27, Use SearchEngine::prefixSearchSubpages or SearchEngine::completionSearch
+ * @ingroup Search
+ */
+class StringPrefixSearch extends PrefixSearch {
+
+       protected function titles( array $titles ) {
+               return array_map( function ( Title $t ) {
+                       return $t->getPrefixedText();
+               }, $titles );
+       }
+
+       protected function strings( array $strings ) {
+               return $strings;
+       }
+}
diff --git a/includes/search/TitlePrefixSearch.php b/includes/search/TitlePrefixSearch.php
new file mode 100644 (file)
index 0000000..a548dbf
--- /dev/null
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Prefix search of page names.
+ *
+ * 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
+ */
+
+/**
+ * Performs prefix search, returning Title objects
+ * @deprecated Since 1.27, Use SearchEngine::defaultPrefixSearch or SearchEngine::completionSearch
+ * @ingroup Search
+ */
+class TitlePrefixSearch extends PrefixSearch {
+
+       protected function titles( array $titles ) {
+               return $titles;
+       }
+
+       protected function strings( array $strings ) {
+               $titles = array_map( 'Title::newFromText', $strings );
+               $lb = new LinkBatch( $titles );
+               $lb->setCaller( __METHOD__ );
+               $lb->execute();
+               return $titles;
+       }
+}
index 3dc8299..328958c 100644 (file)
@@ -537,7 +537,7 @@ final class Session implements \Countable, \Iterator, \ArrayAccess {
                // Extension::OATHAuth.
 
                // Unseal and check
-               $pieces = explode( '.', $encrypted );
+               $pieces = explode( '.', $encrypted, 4 );
                if ( count( $pieces ) !== 3 ) {
                        $ex = new \Exception( 'Invalid sealed-secret format' );
                        $this->logger->warning( $ex->getMessage(), [ 'exception' => $ex ] );
index 7956e9f..0ea13e2 100644 (file)
@@ -270,6 +270,8 @@ final class SessionBackend {
                        // Delete the data for the old session ID now
                        $this->store->delete( $this->store->makeKey( 'MWSession', $oldId ) );
                }
+
+               return $this->id;
        }
 
        /**
index 1f015b5..def3bc3 100644 (file)
@@ -141,9 +141,9 @@ abstract class SessionProvider implements SessionProviderInterface, LoggerAwareI
         * unless only max-priority makes sense.
         *
         * @warning This will be called early in the MediaWiki setup process,
-        *  before $wgUser, $wgLang, $wgOut, $wgParser, $wgTitle, and corresponding
-        *  pieces of the main RequestContext are set up! If you try to use these,
-        *  things *will* break.
+        *  before $wgUser, $wgLang, $wgOut, $wgTitle, the global parser, and
+        *  corresponding pieces of the main RequestContext are set up! If you try
+        *  to use these, things *will* break.
         * @note The SessionProvider must not attempt to auto-create users.
         *  MediaWiki will do this later (when it's safe) if the chosen session has
         *  a user with a valid name but no ID.
@@ -374,7 +374,7 @@ abstract class SessionProvider implements SessionProviderInterface, LoggerAwareI
        public function preventSessionsForUser( $username ) {
                if ( !$this->canChangeUser() ) {
                        throw new \BadMethodCallException(
-                               __METHOD__ . ' must be implmented when canChangeUser() is false'
+                               __METHOD__ . ' must be implemented when canChangeUser() is false'
                        );
                }
        }
@@ -469,7 +469,7 @@ abstract class SessionProvider implements SessionProviderInterface, LoggerAwareI
         * @note If self::__toString() is overridden, this will likely need to be
         *  overridden as well.
         * @warning This will be called early during MediaWiki startup. Do not
-        *  use $wgUser, $wgLang, $wgOut, $wgParser, or their equivalents via
+        *  use $wgUser, $wgLang, $wgOut, the global Parser, or their equivalents via
         *  RequestContext from this method!
         * @return \Message
         */
index 1936d00..20b9445 100644 (file)
@@ -26,6 +26,7 @@ use MediaWiki\ShellDisabledError;
 use Profiler;
 use Psr\Log\LoggerAwareTrait;
 use Psr\Log\NullLogger;
+use Wikimedia\AtEase\AtEase;
 
 /**
  * Class used for executing shell commands
@@ -111,11 +112,10 @@ class Command {
         * Adds parameters to the command. All parameters are sanitized via Shell::escape().
         * Null values are ignored.
         *
-        * @param string|string[] $args,...
+        * @param string|string[] ...$args
         * @return $this
         */
-       public function params( /* ... */ ) {
-               $args = func_get_args();
+       public function params( ...$args ): Command {
                if ( count( $args ) === 1 && is_array( reset( $args ) ) ) {
                        // If only one argument has been passed, and that argument is an array,
                        // treat it as a list of arguments
@@ -130,11 +130,10 @@ class Command {
         * Adds unsafe parameters to the command. These parameters are NOT sanitized in any way.
         * Null values are ignored.
         *
-        * @param string|string[] $args,...
+        * @param string|string[] ...$args
         * @return $this
         */
-       public function unsafeParams( /* ... */ ) {
-               $args = func_get_args();
+       public function unsafeParams( ...$args ): Command {
                if ( count( $args ) === 1 && is_array( reset( $args ) ) ) {
                        // If only one argument has been passed, and that argument is an array,
                        // treat it as a list of arguments
@@ -157,7 +156,7 @@ class Command {
         *   filesize (for ulimit -f), memory, time, walltime.
         * @return $this
         */
-       public function limits( array $limits ) {
+       public function limits( array $limits ): Command {
                if ( !isset( $limits['walltime'] ) && isset( $limits['time'] ) ) {
                        // Emulate the behavior of old wfShellExec() where walltime fell back on time
                        // if the latter was overridden and the former wasn't
@@ -174,7 +173,7 @@ class Command {
         * @param string[] $env array of variable name => value
         * @return $this
         */
-       public function environment( array $env ) {
+       public function environment( array $env ): Command {
                $this->env = $env;
 
                return $this;
@@ -186,7 +185,7 @@ class Command {
         * @param string $method
         * @return $this
         */
-       public function profileMethod( $method ) {
+       public function profileMethod( $method ): Command {
                $this->method = $method;
 
                return $this;
@@ -198,7 +197,7 @@ class Command {
         * @param string|null $inputString
         * @return $this
         */
-       public function input( $inputString ) {
+       public function input( $inputString ): Command {
                $this->inputString = is_null( $inputString ) ? null : (string)$inputString;
 
                return $this;
@@ -211,7 +210,7 @@ class Command {
         * @param bool $yesno
         * @return $this
         */
-       public function includeStderr( $yesno = true ) {
+       public function includeStderr( $yesno = true ): Command {
                $this->doIncludeStderr = $yesno;
 
                return $this;
@@ -223,7 +222,7 @@ class Command {
         * @param bool $yesno
         * @return $this
         */
-       public function logStderr( $yesno = true ) {
+       public function logStderr( $yesno = true ): Command {
                $this->doLogStderr = $yesno;
 
                return $this;
@@ -235,7 +234,7 @@ class Command {
         * @param string|false $cgroup Absolute file path to the cgroup, or false to not use a cgroup
         * @return $this
         */
-       public function cgroup( $cgroup ) {
+       public function cgroup( $cgroup ): Command {
                $this->cgroup = $cgroup;
 
                return $this;
@@ -248,7 +247,7 @@ class Command {
         * @param int $restrictions
         * @return $this
         */
-       public function restrict( $restrictions ) {
+       public function restrict( $restrictions ): Command {
                $this->restrictions |= $restrictions;
 
                return $this;
@@ -275,7 +274,7 @@ class Command {
         *
         * @return $this
         */
-       public function whitelistPaths( array $paths ) {
+       public function whitelistPaths( array $paths ): Command {
                // Default implementation is a no-op
                return $this;
        }
@@ -429,13 +428,13 @@ class Command {
                        }
 
                        // clear get_last_error without actually raising an error
-                       // from https://secure.php.net/manual/en/function.error-get-last.php#113518
+                       // from https://www.php.net/manual/en/function.error-get-last.php#113518
                        // TODO replace with clear_last_error when requirements are bumped to PHP7
                        set_error_handler( function () {
                        }, 0 );
-                       \Wikimedia\suppressWarnings();
+                       AtEase::suppressWarnings();
                        trigger_error( '' );
-                       \Wikimedia\restoreWarnings();
+                       AtEase::restoreWarnings();
                        restore_error_handler();
 
                        $readPipes = array_filter( $pipes, function ( $fd ) use ( $desc ) {
index b4b9b92..d3e00b1 100644 (file)
@@ -97,7 +97,7 @@ class CommandFactory {
         *
         * @return Command
         */
-       public function create() {
+       public function create(): Command {
                if ( $this->restrictionMethod === 'firejail' ) {
                        $command = new FirejailCommand( $this->findFirejail() );
                        $command->restrict( Shell::RESTRICT_DEFAULT );
index 7aed05f..6bf94cd 100644 (file)
@@ -51,7 +51,7 @@ class FirejailCommand extends Command {
        /**
         * @inheritDoc
         */
-       public function whitelistPaths( array $paths ) {
+       public function whitelistPaths( array $paths ): Command {
                $this->whitelistedPaths = array_merge( $this->whitelistedPaths, $paths );
                return $this;
        }
index 467e4ef..19fa1da 100644 (file)
@@ -116,7 +116,7 @@ class Shell {
         *   Example:   [ 'convert', '-font', 'font name' ] would produce "'convert' '-font' 'font name'"
         * @return Command
         */
-       public static function command( ...$commands ) {
+       public static function command( ...$commands ): Command {
                if ( count( $commands ) === 1 && is_array( reset( $commands ) ) ) {
                        // If only one argument has been passed, and that argument is an array,
                        // treat it as a list of arguments
@@ -232,7 +232,7 @@ class Shell {
         *     'wrapper': Path to a PHP wrapper to handle the maintenance script
         * @return Command
         */
-       public static function makeScriptCommand( $script, $parameters, $options = [] ) {
+       public static function makeScriptCommand( $script, $parameters, $options = [] ): Command {
                global $wgPhpCli;
                // Give site config file a chance to run the script in a wrapper.
                // The caller may likely want to call wfBasename() on $script.
index 02247bd..6d108e8 100644 (file)
@@ -43,18 +43,6 @@ abstract class BaseTemplate extends QuickTemplate {
                echo $this->getMsg( $str )->escaped();
        }
 
-       /**
-        * @param string $str
-        * @warning You should never use this method. I18n messages should be escaped
-        * @deprecated 1.32 Use ->msg() or ->getMsg() instead.
-        * @suppress SecurityCheck-XSS
-        * @return-taint exec_html
-        */
-       function msgHtml( $str ) {
-               wfDeprecated( __METHOD__, '1.32' );
-               echo $this->getMsg( $str )->text();
-       }
-
        /**
         * @deprecated since 1.33 Use ->msg() or ->getMsg() instead.
         */
@@ -264,28 +252,26 @@ abstract class BaseTemplate extends QuickTemplate {
                                        $boxes[$boxName]['content'] = $content;
                                }
                        }
-               } else {
-                       if ( $hookContents ) {
-                               $boxes['TOOLBOXEND'] = [
-                                       'id' => 'p-toolboxend',
-                                       'header' => $boxes['TOOLBOX']['header'],
-                                       'generated' => false,
-                                       'content' => "<ul>{$hookContents}</ul>",
-                               ];
-                               // HACK: Make sure that TOOLBOXEND is sorted next to TOOLBOX
-                               $boxes2 = [];
-                               foreach ( $boxes as $key => $box ) {
-                                       if ( $key === 'TOOLBOXEND' ) {
-                                               continue;
-                                       }
-                                       $boxes2[$key] = $box;
-                                       if ( $key === 'TOOLBOX' ) {
-                                               $boxes2['TOOLBOXEND'] = $boxes['TOOLBOXEND'];
-                                       }
+               } elseif ( $hookContents ) {
+                       $boxes['TOOLBOXEND'] = [
+                               'id' => 'p-toolboxend',
+                               'header' => $boxes['TOOLBOX']['header'],
+                               'generated' => false,
+                               'content' => "<ul>{$hookContents}</ul>",
+                       ];
+                       // HACK: Make sure that TOOLBOXEND is sorted next to TOOLBOX
+                       $boxes2 = [];
+                       foreach ( $boxes as $key => $box ) {
+                               if ( $key === 'TOOLBOXEND' ) {
+                                       continue;
+                               }
+                               $boxes2[$key] = $box;
+                               if ( $key === 'TOOLBOX' ) {
+                                       $boxes2['TOOLBOXEND'] = $boxes['TOOLBOXEND'];
                                }
-                               $boxes = $boxes2;
-                               // END hack
                        }
+                       $boxes = $boxes2;
+                       // END hack
                }
 
                return $boxes;
index 5044301..6bcf1c3 100644 (file)
@@ -125,19 +125,6 @@ abstract class QuickTemplate {
                echo htmlspecialchars( wfMessage( $msgKey )->text() );
        }
 
-       /**
-        * @private
-        * @param string $msgKey
-        * @warning You should never use this method. I18n messages should be escaped
-        * @deprecated 1.32 Use ->msg() instead.
-        * @suppress SecurityCheck-XSS
-        * @return-taint exec_html
-        */
-       function msgHtml( $msgKey ) {
-               wfDeprecated( __METHOD__, '1.32' );
-               echo wfMessage( $msgKey )->text();
-       }
-
        /**
         * An ugly, ugly hack.
         * @deprecated since 1.33 Use ->msg() instead.
index 6ab2468..f45596f 100644 (file)
@@ -55,7 +55,8 @@ abstract class Skin extends ContextSource {
         * @return array Associative array of strings
         */
        static function getSkinNames() {
-               return SkinFactory::getDefaultInstance()->getSkinNames();
+               $skinFactory = MediaWikiServices::getInstance()->getSkinFactory();
+               return $skinFactory->getSkinNames();
        }
 
        /**
@@ -175,7 +176,6 @@ abstract class Skin extends ContextSource {
         */
        public function getDefaultModules() {
                $out = $this->getOutput();
-               $config = $this->getConfig();
                $user = $this->getUser();
 
                // Modules declared in the $modules literal are loaded
@@ -519,6 +519,7 @@ abstract class Skin extends ContextSource {
        function getCategoryLinks() {
                $out = $this->getOutput();
                $allCats = $out->getCategoryLinks();
+               $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
 
                if ( $allCats === [] ) {
                        return '';
@@ -533,10 +534,10 @@ abstract class Skin extends ContextSource {
                if ( !empty( $allCats['normal'] ) ) {
                        $t = $embed . implode( $pop . $embed, $allCats['normal'] ) . $pop;
 
-                       $msg = $this->msg( 'pagecategories' )->numParams( count( $allCats['normal'] ) )->escaped();
+                       $msg = $this->msg( 'pagecategories' )->numParams( count( $allCats['normal'] ) );
                        $linkPage = $this->msg( 'pagecategorieslink' )->inContentLanguage()->text();
                        $title = Title::newFromText( $linkPage );
-                       $link = $title ? Linker::link( $title, $msg ) : $msg;
+                       $link = $title ? $linkRenderer->makeLink( $title, $msg->text() ) : $msg->escaped();
                        $s .= '<div id="mw-normal-catlinks" class="mw-normal-catlinks">' .
                                $link . $colon . '<ul>' . $t . '</ul></div>';
                }
@@ -584,6 +585,7 @@ abstract class Skin extends ContextSource {
         */
        function drawCategoryBrowser( $tree ) {
                $return = '';
+               $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
 
                foreach ( $tree as $element => $parent ) {
                        if ( empty( $parent ) ) {
@@ -596,7 +598,7 @@ abstract class Skin extends ContextSource {
 
                        # add our current element to the list
                        $eltitle = Title::newFromText( $element );
-                       $return .= Linker::link( $eltitle, htmlspecialchars( $eltitle->getText() ) );
+                       $return .= $linkRenderer->makeLink( $eltitle, $eltitle->getText() );
                }
 
                return $return;
@@ -718,6 +720,7 @@ abstract class Skin extends ContextSource {
        function getUndeleteLink() {
                $action = $this->getRequest()->getVal( 'action', 'view' );
                $title = $this->getTitle();
+               $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
 
                if ( ( !$title->exists() || $action == 'history' ) &&
                        $title->quickUserCan( 'deletedhistory', $this->getUser() )
@@ -732,9 +735,9 @@ abstract class Skin extends ContextSource {
                                }
 
                                return $this->msg( $msg )->rawParams(
-                                       Linker::linkKnown(
+                                       $linkRenderer->makeKnownLink(
                                                SpecialPage::getTitleFor( 'Undelete', $this->getTitle()->getPrefixedDBkey() ),
-                                               $this->msg( 'restorelink' )->numParams( $n )->escaped() )
+                                               $this->msg( 'restorelink' )->numParams( $n )->text() )
                                        )->escaped();
                        }
                }
@@ -747,6 +750,7 @@ abstract class Skin extends ContextSource {
         * @return string
         */
        function subPageSubtitle( $out = null ) {
+               $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
                if ( $out === null ) {
                        $out = $this->getOutput();
                }
@@ -757,7 +761,10 @@ abstract class Skin extends ContextSource {
                        return $subpages;
                }
 
-               if ( $out->isArticle() && MWNamespace::hasSubpages( $title->getNamespace() ) ) {
+               if (
+                       $out->isArticle() && MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               hasSubpages( $title->getNamespace() )
+               ) {
                        $ptext = $title->getPrefixedText();
                        if ( strpos( $ptext, '/' ) !== false ) {
                                $links = explode( '/', $ptext );
@@ -773,9 +780,8 @@ abstract class Skin extends ContextSource {
                                        $linkObj = Title::newFromText( $growinglink );
 
                                        if ( is_object( $linkObj ) && $linkObj->isKnown() ) {
-                                               $getlink = Linker::linkKnown(
-                                                       $linkObj,
-                                                       htmlspecialchars( $display )
+                                               $getlink = $linkRenderer->makeKnownLink(
+                                                       $linkObj, $display
                                                );
 
                                                $c++;
@@ -819,6 +825,7 @@ abstract class Skin extends ContextSource {
         * @return string
         */
        function getCopyright( $type = 'detect' ) {
+               $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
                if ( $type == 'detect' ) {
                        if ( !$this->isRevisionCurrent()
                                && !$this->msg( 'history_copyright' )->inContentLanguage()->isDisabled()
@@ -839,7 +846,9 @@ abstract class Skin extends ContextSource {
 
                if ( $config->get( 'RightsPage' ) ) {
                        $title = Title::newFromText( $config->get( 'RightsPage' ) );
-                       $link = Linker::linkKnown( $title, $config->get( 'RightsText' ) );
+                       $link = $linkRenderer->makeKnownLink(
+                               $title, new HtmlArmor( $config->get( 'RightsText' ) )
+                       );
                } elseif ( $config->get( 'RightsUrl' ) ) {
                        $link = Linker::makeExternalLink( $config->get( 'RightsUrl' ), $config->get( 'RightsText' ) );
                } elseif ( $config->get( 'RightsText' ) ) {
@@ -905,7 +914,7 @@ abstract class Skin extends ContextSource {
                $url2 = htmlspecialchars(
                        "$resourceBasePath/resources/assets/poweredby_mediawiki_176x62.png"
                );
-               $text = '<a href="//www.mediawiki.org/"><img src="' . $url1
+               $text = '<a href="https://www.mediawiki.org/"><img src="' . $url1
                        . '" srcset="' . $url1_5 . ' 1.5x, ' . $url2 . ' 2x" '
                        . 'height="31" width="88" alt="Powered by MediaWiki" /></a>';
                Hooks::run( 'SkinGetPoweredBy', [ &$text, $this ] );
@@ -995,9 +1004,10 @@ abstract class Skin extends ContextSource {
         * @return string
         */
        function mainPageLink() {
-               $s = Linker::linkKnown(
+               $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
+               $s = $linkRenderer->makeKnownLink(
                        Title::newMainPage(),
-                       $this->msg( 'mainpage' )->escaped()
+                       $this->msg( 'mainpage' )->text()
                );
 
                return $s;
@@ -1011,13 +1021,14 @@ abstract class Skin extends ContextSource {
         */
        public function footerLink( $desc, $page ) {
                $title = $this->footerLinkTitle( $desc, $page );
+               $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
                if ( !$title ) {
                        return '';
                }
 
-               return Linker::linkKnown(
+               return $linkRenderer->makeKnownLink(
                        $title,
-                       $this->msg( $desc )->escaped()
+                       $this->msg( $desc )->text()
                );
        }
 
@@ -1437,6 +1448,7 @@ abstract class Skin extends ContextSource {
                $user = $this->getUser();
                $newtalks = $user->getNewMessageLinks();
                $out = $this->getOutput();
+               $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
 
                // Allow extensions to disable or modify the new messages alert
                if ( !Hooks::run( 'GetNewMessagesAlert', [ &$newMessagesAlert, $newtalks, $user, $out ] ) ) {
@@ -1467,16 +1479,16 @@ abstract class Skin extends ContextSource {
                        // 999 signifies "more than one revision". We don't know how many, and even if we did,
                        // the number of revisions or authors is not necessarily the same as the number of
                        // "messages".
-                       $newMessagesLink = Linker::linkKnown(
+                       $newMessagesLink = $linkRenderer->makeKnownLink(
                                $uTalkTitle,
-                               $this->msg( 'newmessageslinkplural' )->params( $plural )->escaped(),
+                               $this->msg( 'newmessageslinkplural' )->params( $plural )->text(),
                                [],
                                $uTalkTitle->isRedirect() ? [ 'redirect' => 'no' ] : []
                        );
 
-                       $newMessagesDiffLink = Linker::linkKnown(
+                       $newMessagesDiffLink = $linkRenderer->makeKnownLink(
                                $uTalkTitle,
-                               $this->msg( 'newmessagesdifflinkplural' )->params( $plural )->escaped(),
+                               $this->msg( 'newmessagesdifflinkplural' )->params( $plural )->text(),
                                [],
                                $lastSeenRev !== null
                                        ? [ 'oldid' => $lastSeenRev->getId(), 'diff' => 'cur' ]
@@ -1526,7 +1538,6 @@ abstract class Skin extends ContextSource {
         *   should fall back to the next notice in its sequence
         */
        private function getCachedNotice( $name ) {
-               $needParse = false;
                $config = $this->getConfig();
 
                if ( $name === 'default' ) {
@@ -1623,11 +1634,10 @@ abstract class Skin extends ContextSource {
 
                $links = [
                        'editsection' => [
-                               'text' => $this->msg( 'editsection' )->inLanguage( $lang )->escaped(),
+                               'text' => $this->msg( 'editsection' )->inLanguage( $lang )->text(),
                                'targetTitle' => $nt,
                                'attribs' => $attribs,
-                               'query' => [ 'action' => 'edit', 'section' => $section ],
-                               'options' => [ 'noclasses', 'known' ]
+                               'query' => [ 'action' => 'edit', 'section' => $section ]
                        ]
                ];
 
@@ -1635,14 +1645,14 @@ abstract class Skin extends ContextSource {
 
                $result = '<span class="mw-editsection"><span class="mw-editsection-bracket">[</span>';
 
+               $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
                $linksHtml = [];
                foreach ( $links as $k => $linkDetails ) {
-                       $linksHtml[] = Linker::link(
+                       $linksHtml[] = $linkRenderer->makeKnownLink(
                                $linkDetails['targetTitle'],
                                $linkDetails['text'],
                                $linkDetails['attribs'],
-                               $linkDetails['query'],
-                               $linkDetails['options']
+                               $linkDetails['query']
                        );
                }
 
index c29c996..ef45d15 100644 (file)
@@ -171,6 +171,9 @@ class SkinTemplate extends Skin {
                return $languageLinks;
        }
 
+       /**
+        * @return QuickTemplate
+        */
        protected function setupTemplateForOutput() {
                $request = $this->getRequest();
                $user = $this->getUser();
@@ -386,14 +389,15 @@ class SkinTemplate extends Skin {
                $tpl->set( 'credits', false );
                $tpl->set( 'numberofwatchingusers', false );
                if ( $title->exists() ) {
-                       if ( $out->isArticle() ) {
-                               if ( $this->isRevisionCurrent() ) {
-                                       if ( $wgMaxCredits != 0 ) {
-                                               $tpl->set( 'credits', Action::factory( 'credits', $this->getWikiPage(),
-                                                       $this->getContext() )->getCredits( $wgMaxCredits, $wgShowCreditsIfMax ) );
-                                       } else {
-                                               $tpl->set( 'lastmod', $this->lastModified() );
-                                       }
+                       if ( $out->isArticle() && $this->isRevisionCurrent() ) {
+                               if ( $wgMaxCredits != 0 ) {
+                                       /** @var CreditsAction $action */
+                                       $action = Action::factory(
+                                               'credits', $this->getWikiPage(), $this->getContext() );
+                                       $tpl->set( 'credits',
+                                               $action->getCredits( $wgMaxCredits, $wgShowCreditsIfMax ) );
+                               } else {
+                                       $tpl->set( 'lastmod', $this->lastModified() );
                                }
                        }
                        if ( $out->showsCopyright() ) {
@@ -526,7 +530,9 @@ class SkinTemplate extends Skin {
                $html = '';
 
                if ( $personalTools === null ) {
-                       $personalTools = $tpl->getPersonalTools();
+                       $personalTools = ( $tpl instanceof BaseTemplate )
+                               ? $tpl->getPersonalTools()
+                               : [];
                }
 
                foreach ( $personalTools as $key => $item ) {
@@ -547,7 +553,7 @@ class SkinTemplate extends Skin {
                $tpl = $this->setupTemplateForOutput();
                $tpl->set( 'personal_urls', $this->buildPersonalUrls() );
 
-               return $tpl->getPersonalTools();
+               return ( $tpl instanceof BaseTemplate ) ? $tpl->getPersonalTools() : [];
        }
 
        /**
@@ -611,16 +617,18 @@ class SkinTemplate extends Skin {
                        $page = Title::newFromText( $request->getVal( 'title', '' ) );
                }
                $page = $request->getVal( 'returnto', $page );
-               $a = [];
+               $returnto = [];
                if ( strval( $page ) !== '' ) {
-                       $a['returnto'] = $page;
+                       $returnto['returnto'] = $page;
                        $query = $request->getVal( 'returntoquery', $this->thisquery );
+                       $paramsArray = wfCgiToArray( $query );
+                       unset( $paramsArray['logoutToken'] );
+                       $query = wfArrayToCgi( $paramsArray );
                        if ( $query != '' ) {
-                               $a['returntoquery'] = $query;
+                               $returnto['returntoquery'] = $query;
                        }
                }
 
-               $returnto = wfArrayToCgi( $a );
                if ( $this->loggedin ) {
                        $personal_urls['userpage'] = [
                                'text' => $this->username,
@@ -685,9 +693,10 @@ class SkinTemplate extends Skin {
                                $personal_urls['logout'] = [
                                        'text' => $this->msg( 'pt-userlogout' )->text(),
                                        'href' => self::makeSpecialUrl( 'Userlogout',
-                                               // userlogout link must always contain an & character, otherwise we might not be able
+                                               // Note: userlogout link must always contain an & character, otherwise we might not be able
                                                // to detect a buggy precaching proxy (T19790)
-                                               $title->isSpecial( 'Preferences' ) ? 'noreturnto' : $returnto ),
+                                               ( $title->isSpecial( 'Preferences' ) ? [] : $returnto )
+                                               + [ 'logoutToken' => $this->getUser()->getEditToken( 'logoutToken', $this->getRequest() ) ] ),
                                        'active' => false
                                ];
                        }
@@ -781,7 +790,8 @@ class SkinTemplate extends Skin {
                        }
                }
 
-               $linkClass = MediaWikiServices::getInstance()->getLinkRenderer()->getLinkClasses( $title );
+               $services = MediaWikiServices::getInstance();
+               $linkClass = $services->getLinkRenderer()->getLinkClasses( $title );
 
                // wfMessageFallback will nicely accept $message as an array of fallbacks
                // or just a single key
@@ -793,8 +803,9 @@ class SkinTemplate extends Skin {
                if ( $msg->exists() ) {
                        $text = $msg->text();
                } else {
-                       $text = MediaWikiServices::getInstance()->getContentLanguage()->getConverter()->
-                               convertNamespace( MWNamespace::getSubject( $title->getNamespace() ) );
+                       $text = $services->getContentLanguage()->getConverter()->
+                               convertNamespace( $services->getNamespaceInfo()->
+                                       getSubject( $title->getNamespace() ) );
                }
 
                // Avoid PHP 7.1 warning of passing $this by reference
@@ -1077,7 +1088,8 @@ class SkinTemplate extends Skin {
                                }
 
                                if ( $title->quickUserCan( 'protect', $user ) && $title->getRestrictionTypes() &&
-                                       MWNamespace::getRestrictionLevels( $title->getNamespace(), $user ) !== [ '' ]
+                                       MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                               getRestrictionLevels( $title->getNamespace(), $user ) !== [ '' ]
                                ) {
                                        $mode = $title->isProtected() ? 'unprotect' : 'protect';
                                        $content_navigation['actions'][$mode] = [
index 0e0a26a..101570f 100644 (file)
@@ -710,7 +710,6 @@ abstract class AuthManagerSpecialPage extends SpecialPage {
         * are shown closer to the bottom; weight defaults to 0. Negative weight is allowed.)
         * Keep order if weights are equal.
         * @param array &$formDescriptor
-        * @return array
         */
        protected static function sortFormDescriptorFields( array &$formDescriptor ) {
                $i = 0;
index a8271ac..a9debb3 100644 (file)
  * @file
  * @ingroup SpecialPage
  */
+
 use MediaWiki\Logger\LoggerFactory;
+use MediaWiki\MediaWikiServices;
 use Wikimedia\Rdbms\DBQueryTimeoutError;
 use Wikimedia\Rdbms\IResultWrapper;
 use Wikimedia\Rdbms\FakeResultWrapper;
 use Wikimedia\Rdbms\IDatabase;
-use MediaWiki\MediaWikiServices;
 
 /**
  * Special page which uses a ChangesList to show query results.
@@ -158,7 +159,7 @@ abstract class ChangesListSpecialPage extends SpecialPage {
 
                        [
                                'name' => 'userExpLevel',
-                               'title' => 'rcfilters-filtergroup-userExpLevel',
+                               'title' => 'rcfilters-filtergroup-user-experience-level',
                                'class' => ChangesListStringOptionsFilterGroup::class,
                                'isFullCoverage' => true,
                                'filters' => [
@@ -353,7 +354,7 @@ abstract class ChangesListSpecialPage extends SpecialPage {
 
                        [
                                'name' => 'lastRevision',
-                               'title' => 'rcfilters-filtergroup-lastRevision',
+                               'title' => 'rcfilters-filtergroup-lastrevision',
                                'class' => ChangesListBooleanFilterGroup::class,
                                'priority' => -7,
                                'filters' => [
@@ -616,9 +617,7 @@ abstract class ChangesListSpecialPage extends SpecialPage {
        }
 
        /**
-        * Main execution point
-        *
-        * @param string $subpage
+        * @param string|null $subpage
         */
        public function execute( $subpage ) {
                $this->rcSubpage = $subpage;
@@ -1054,6 +1053,7 @@ abstract class ChangesListSpecialPage extends SpecialPage {
         *
         * There is light processing to simplify core maintenance.
         * @param array $definition
+        * @phan-param array<int,array{class:string}> $definition
         */
        protected function registerFiltersFromDefinitions( array $definition ) {
                $autoFillPriority = -1;
@@ -1190,6 +1190,7 @@ abstract class ChangesListSpecialPage extends SpecialPage {
        // to include data on filters that use the unstructured UI.  messageKeys is a
        // special top-level value, with the value being an array of the message keys to
        // send to the client.
+
        /**
         * Gets structured filter information needed by JS
         *
@@ -1452,7 +1453,8 @@ abstract class ChangesListSpecialPage extends SpecialPage {
                        if ( $opts[ 'associated' ] ) {
                                $associatedNamespaces = array_map(
                                        function ( $ns ) {
-                                               return MWNamespace::getAssociated( $ns );
+                                               return MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                                       getAssociated( $ns );
                                        },
                                        $namespaces
                                );
@@ -1848,21 +1850,21 @@ abstract class ChangesListSpecialPage extends SpecialPage {
                        return true;
                }
 
-               return static::checkStructuredFilterUiEnabled(
-                       $this->getConfig(),
-                       $this->getUser()
-               );
+               return static::checkStructuredFilterUiEnabled( $this->getUser() );
        }
 
        /**
         * Static method to check whether StructuredFilter UI is enabled for the given user
         *
         * @since 1.31
-        * @param Config $config
         * @param User $user
         * @return bool
         */
-       public static function checkStructuredFilterUiEnabled( Config $config, User $user ) {
+       public static function checkStructuredFilterUiEnabled( $user ) {
+               if ( $user instanceof Config ) {
+                       wfDeprecated( __METHOD__ . ' with Config argument', '1.34' );
+                       $user = func_get_arg( 1 );
+               }
                return !$user->getOption( 'rcenhancedfilters-disable' );
        }
 
index d1c6aea..939460f 100644 (file)
@@ -31,7 +31,7 @@
 abstract class FormSpecialPage extends SpecialPage {
        /**
         * The sub-page of the special page.
-        * @var string
+        * @var string|null
         */
        protected $par = null;
 
@@ -166,7 +166,7 @@ abstract class FormSpecialPage extends SpecialPage {
        /**
         * Basic SpecialPage workflow: get a form, send it to the user; get some data back,
         *
-        * @param string $par Subpage string if one was specified
+        * @param string|null $par Subpage string if one was specified
         */
        public function execute( $par ) {
                $this->setParameter( $par );
@@ -188,7 +188,7 @@ abstract class FormSpecialPage extends SpecialPage {
 
        /**
         * Maybe do something interesting with the subpage parameter
-        * @param string $par
+        * @param string|null $par
         */
        protected function setParameter( $par ) {
                $this->par = $par;
index 8df6493..722251d 100644 (file)
@@ -68,6 +68,7 @@ abstract class ImageQueryPage extends QueryPage {
 
        // Gotta override this since it's abstract
        function formatResult( $skin, $result ) {
+               return false;
        }
 
        /**
index 579ca19..700672f 100644 (file)
@@ -46,13 +46,18 @@ abstract class QueryPage extends SpecialPage {
         * The number of rows returned by the query. Reading this variable
         * only makes sense in functions that are run after the query has been
         * done, such as preprocessResults() and formatRow().
+        *
+        * @var int
         */
        protected $numRows;
 
+       /**
+        * @var string|null
+        */
        protected $cachedTimestamp = null;
 
        /**
-        * Whether to show prev/next links
+        * @var bool Whether to show prev/next links
         */
        protected $shownavigation = true;
 
@@ -62,7 +67,8 @@ abstract class QueryPage extends SpecialPage {
         *
         * DO NOT CHANGE THIS LIST without testing that
         * maintenance/updateSpecialPages.php still works.
-        * @return array
+        *
+        * @return string[][]
         */
        public static function getPages() {
                static $qp = null;
@@ -166,7 +172,7 @@ abstract class QueryPage extends SpecialPage {
         * Subclasses return an array of fields to order by here. Don't append
         * DESC to the field names, that'll be done automatically if
         * sortDescending() returns true.
-        * @return array
+        * @return string[]
         * @since 1.18
         */
        function getOrderFields() {
@@ -279,21 +285,6 @@ abstract class QueryPage extends SpecialPage {
                return [];
        }
 
-       /**
-        * Some special pages (for example SpecialListusers used to) might not return the
-        * current object formatted, but return the previous one instead.
-        * Setting this to return true will ensure formatResult() is called
-        * one more time to make sure that the very last result is formatted
-        * as well.
-        *
-        * @deprecated since 1.27
-        *
-        * @return bool
-        */
-       function tryLastResult() {
-               return false;
-       }
-
        /**
         * Clear the cache and save new results
         *
@@ -500,6 +491,9 @@ abstract class QueryPage extends SpecialPage {
                return [ 'value' ];
        }
 
+       /**
+        * @return string
+        */
        public function getCachedTimestamp() {
                if ( is_null( $this->cachedTimestamp ) ) {
                        $dbr = wfGetDB( DB_REPLICA );
@@ -569,7 +563,7 @@ abstract class QueryPage extends SpecialPage {
        /**
         * This is the actual workhorse. It does everything needed to make a
         * real, honest-to-gosh query page.
-        * @param string $par
+        * @param string|null $par
         */
        public function execute( $par ) {
                $user = $this->getUser();
@@ -649,8 +643,8 @@ abstract class QueryPage extends SpecialPage {
                                $miserMaxResults = $this->getConfig()->get( 'MiserMode' )
                                        && ( $this->offset + $this->limit >= $this->getMaxResults() );
                                $atEnd = ( $this->numRows <= $this->limit ) || $miserMaxResults;
-                               $paging = $this->getLanguage()->viewPrevNext( $this->getPageTitle( $par ), $this->offset,
-                                       $this->limit, $this->linkParameters(), $atEnd );
+                               $paging = $this->buildPrevNextNavigation( $this->offset,
+                                       $this->limit, $this->linkParameters(), $atEnd, $par );
                                $out->addHTML( '<p>' . $paging . '</p>' );
                        } else {
                                # No results to show, so don't bother with "showing X of Y" etc.
@@ -708,17 +702,6 @@ abstract class QueryPage extends SpecialPage {
                                }
                        }
 
-                       # Flush the final result
-                       if ( $this->tryLastResult() ) {
-                               $row = null;
-                               $line = $this->formatResult( $skin, $row );
-                               if ( $line ) {
-                                       $html[] = $this->listoutput
-                                               ? $line
-                                               : "<li>{$line}</li>\n";
-                               }
-                       }
-
                        if ( !$this->listoutput ) {
                                $html[] = $this->closeList();
                        }
@@ -754,98 +737,6 @@ abstract class QueryPage extends SpecialPage {
        function preprocessResults( $db, $res ) {
        }
 
-       /**
-        * Similar to above, but packaging in a syndicated feed instead of a web page
-        * @param string $class
-        * @param int $limit
-        * @return bool
-        */
-       function doFeed( $class = '', $limit = 50 ) {
-               if ( !$this->getConfig()->get( 'Feed' ) ) {
-                       $this->getOutput()->addWikiMsg( 'feed-unavailable' );
-                       return false;
-               }
-
-               $limit = min( $limit, $this->getConfig()->get( 'FeedLimit' ) );
-
-               $feedClasses = $this->getConfig()->get( 'FeedClasses' );
-               if ( isset( $feedClasses[$class] ) ) {
-                       /** @var RSSFeed|AtomFeed $feed */
-                       $feed = new $feedClasses[$class](
-                               $this->feedTitle(),
-                               $this->feedDesc(),
-                               $this->feedUrl() );
-                       $feed->outHeader();
-
-                       $res = $this->reallyDoQuery( $limit, 0 );
-                       foreach ( $res as $obj ) {
-                               $item = $this->feedResult( $obj );
-                               if ( $item ) {
-                                       $feed->outItem( $item );
-                               }
-                       }
-
-                       $feed->outFooter();
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-
-       /**
-        * Override for custom handling. If the titles/links are ok, just do
-        * feedItemDesc()
-        * @param object $row
-        * @return FeedItem|null
-        */
-       function feedResult( $row ) {
-               if ( !isset( $row->title ) ) {
-                       return null;
-               }
-               $title = Title::makeTitle( intval( $row->namespace ), $row->title );
-               if ( $title ) {
-                       $date = $row->timestamp ?? '';
-                       $comments = '';
-                       if ( $title ) {
-                               $talkpage = $title->getTalkPage();
-                               $comments = $talkpage->getFullURL();
-                       }
-
-                       return new FeedItem(
-                               $title->getPrefixedText(),
-                               $this->feedItemDesc( $row ),
-                               $title->getFullURL(),
-                               $date,
-                               $this->feedItemAuthor( $row ),
-                               $comments );
-               } else {
-                       return null;
-               }
-       }
-
-       function feedItemDesc( $row ) {
-               return isset( $row->comment ) ? htmlspecialchars( $row->comment ) : '';
-       }
-
-       function feedItemAuthor( $row ) {
-               return $row->user_text ?? '';
-       }
-
-       function feedTitle() {
-               $desc = $this->getDescription();
-               $code = $this->getConfig()->get( 'LanguageCode' );
-               $sitename = $this->getConfig()->get( 'Sitename' );
-               return "$sitename - $desc [$code]";
-       }
-
-       function feedDesc() {
-               return $this->msg( 'tagline' )->text();
-       }
-
-       function feedUrl() {
-               return $this->getPageTitle()->getFullURL();
-       }
-
        /**
         * Creates a new LinkBatch object, adds all pages from the passed ResultWrapper (MUST include
         * title and optional the namespace field) and executes the batch. This operation will pre-cache
index 01a88f4..c28b89e 100644 (file)
@@ -35,23 +35,19 @@ abstract class RedirectSpecialPage extends UnlistedSpecialPage {
 
        /**
         * @param string|null $subpage
-        * @return Title|bool
         */
        public function execute( $subpage ) {
                $redirect = $this->getRedirect( $subpage );
-               $query = $this->getRedirectQuery();
-               // Redirect to a page title with possible query parameters
+               $query = $this->getRedirectQuery( $subpage );
+
                if ( $redirect instanceof Title ) {
+                       // Redirect to a page title with possible query parameters
                        $url = $redirect->getFullUrlForRedirect( $query );
                        $this->getOutput()->redirect( $url );
-
-                       return $redirect;
                } elseif ( $redirect === true ) {
                        // Redirect to index.php with query parameters
                        $url = wfAppendQuery( wfScript( 'index' ), $query );
                        $this->getOutput()->redirect( $url );
-
-                       return $redirect;
                } else {
                        $this->showNoRedirectPage();
                }
@@ -70,9 +66,10 @@ abstract class RedirectSpecialPage extends UnlistedSpecialPage {
         * Return part of the request string for a special redirect page
         * This allows passing, e.g. action=history to Special:Mypage, etc.
         *
+        * @param string|null $subpage
         * @return array|bool
         */
-       public function getRedirectQuery() {
+       public function getRedirectQuery( $subpage ) {
                $params = [];
                $request = $this->getRequest();
 
index a9bbb8a..670a0b8 100644 (file)
@@ -162,6 +162,7 @@ class SpecialPage implements MessageLocalizer {
        }
 
        // @todo FIXME: Decide which syntax to use for this, and stick to it
+
        /**
         * Whether this special page is listed in Special:SpecialPages
         * @since 1.3 (r3583)
@@ -920,4 +921,70 @@ class SpecialPage implements MessageLocalizer {
        public function setLinkRenderer( LinkRenderer $linkRenderer ) {
                $this->linkRenderer = $linkRenderer;
        }
+
+       /**
+        * Generate (prev x| next x) (20|50|100...) type links for paging
+        *
+        * @param int $offset
+        * @param int $limit
+        * @param array $query Optional URL query parameter string
+        * @param bool $atend Optional param for specified if this is the last page
+        * @param string|bool $subpage Optional param for specifying subpage
+        * @return string
+        */
+       protected function buildPrevNextNavigation( $offset, $limit,
+               array $query = [], $atend = false, $subpage = false
+       ) {
+               $lang = $this->getLanguage();
+
+               # Make 'previous' link
+               $prev = $this->msg( 'prevn' )->numParams( $limit )->text();
+               if ( $offset > 0 ) {
+                       $plink = $this->numLink( max( $offset - $limit, 0 ), $limit, $query,
+                               $prev, 'prevn-title', 'mw-prevlink', $subpage );
+               } else {
+                       $plink = htmlspecialchars( $prev );
+               }
+
+               # Make 'next' link
+               $next = $this->msg( 'nextn' )->numParams( $limit )->text();
+               if ( $atend ) {
+                       $nlink = htmlspecialchars( $next );
+               } else {
+                       $nlink = $this->numLink( $offset + $limit, $limit,
+                               $query, $next, 'nextn-title', 'mw-nextlink', $subpage );
+               }
+
+               # Make links to set number of items per page
+               $numLinks = [];
+               foreach ( [ 20, 50, 100, 250, 500 ] as $num ) {
+                       $numLinks[] = $this->numLink( $offset, $num, $query,
+                               $lang->formatNum( $num ), 'shown-title', 'mw-numlink', $subpage );
+               }
+
+               return $this->msg( 'viewprevnext' )->rawParams( $plink, $nlink, $lang->pipeList( $numLinks ) )->
+                       escaped();
+       }
+
+       /**
+        * Helper function for buildPrevNextNavigation() that generates links
+        *
+        * @param int $offset
+        * @param int $limit
+        * @param array $query Extra query parameters
+        * @param string $link Text to use for the link; will be escaped
+        * @param string $tooltipMsg Name of the message to use as tooltip
+        * @param string $class Value of the "class" attribute of the link
+        * @param string|bool $subpage Optional param for specifying subpage
+        * @return string HTML fragment
+        */
+       private function numLink( $offset, $limit, array $query, $link,
+               $tooltipMsg, $class, $subpage = false
+       ) {
+               $query = [ 'limit' => $limit, 'offset' => $offset ] + $query;
+               $tooltip = $this->msg( $tooltipMsg )->numParams( $limit )->text();
+               $href = $this->getPageTitle( $subpage )->getLocalURL( $query );
+               return Html::element( 'a', [ 'href' => $href,
+                       'title' => $tooltip, 'class' => $class ], $link );
+       }
 }
index 58212dd..1053bda 100644 (file)
 
 namespace MediaWiki\Special;
 
-use Config;
 use Hooks;
 use IContextSource;
 use Language;
+use MediaWiki\Config\ServiceOptions;
 use MediaWiki\Linker\LinkRenderer;
 use Profiler;
 use RequestContext;
@@ -214,18 +214,35 @@ class SpecialPageFactory {
        /** @var array */
        private $aliases;
 
-       /** @var Config */
-       private $config;
+       /** @var ServiceOptions */
+       private $options;
 
        /** @var Language */
        private $contLang;
 
        /**
-        * @param Config $config
+        * TODO Make this a const when HHVM support is dropped (T192166)
+        *
+        * @var array
+        * @since 1.33
+        * */
+       public static $constructorOptions = [
+               'ContentHandlerUseDB',
+               'DisableInternalSearch',
+               'EmailAuthentication',
+               'EnableEmail',
+               'EnableJavaScriptTest',
+               'PageLanguageUseDB',
+               'SpecialPages',
+       ];
+
+       /**
+        * @param ServiceOptions $options
         * @param Language $contLang
         */
-       public function __construct( Config $config, Language $contLang ) {
-               $this->config = $config;
+       public function __construct( ServiceOptions $options, Language $contLang ) {
+               $options->assertRequiredOptions( self::$constructorOptions );
+               $this->options = $options;
                $this->contLang = $contLang;
        }
 
@@ -248,32 +265,32 @@ class SpecialPageFactory {
                if ( !is_array( $this->list ) ) {
                        $this->list = self::$coreList;
 
-                       if ( !$this->config->get( 'DisableInternalSearch' ) ) {
+                       if ( !$this->options->get( 'DisableInternalSearch' ) ) {
                                $this->list['Search'] = \SpecialSearch::class;
                        }
 
-                       if ( $this->config->get( 'EmailAuthentication' ) ) {
+                       if ( $this->options->get( 'EmailAuthentication' ) ) {
                                $this->list['Confirmemail'] = \EmailConfirmation::class;
                                $this->list['Invalidateemail'] = \EmailInvalidation::class;
                        }
 
-                       if ( $this->config->get( 'EnableEmail' ) ) {
+                       if ( $this->options->get( 'EnableEmail' ) ) {
                                $this->list['ChangeEmail'] = \SpecialChangeEmail::class;
                        }
 
-                       if ( $this->config->get( 'EnableJavaScriptTest' ) ) {
+                       if ( $this->options->get( 'EnableJavaScriptTest' ) ) {
                                $this->list['JavaScriptTest'] = \SpecialJavaScriptTest::class;
                        }
 
-                       if ( $this->config->get( 'PageLanguageUseDB' ) ) {
+                       if ( $this->options->get( 'PageLanguageUseDB' ) ) {
                                $this->list['PageLanguage'] = \SpecialPageLanguage::class;
                        }
-                       if ( $this->config->get( 'ContentHandlerUseDB' ) ) {
+                       if ( $this->options->get( 'ContentHandlerUseDB' ) ) {
                                $this->list['ChangeContentModel'] = \SpecialChangeContentModel::class;
                        }
 
                        // Add extension special pages
-                       $this->list = array_merge( $this->list, $this->config->get( 'SpecialPages' ) );
+                       $this->list = array_merge( $this->list, $this->options->get( 'SpecialPages' ) );
 
                        // This hook can be used to disable unwanted core special pages
                        // or conditionally register special pages.
diff --git a/includes/specials/SpecialActiveUsers.php b/includes/specials/SpecialActiveUsers.php
new file mode 100644 (file)
index 0000000..7995e3e
--- /dev/null
@@ -0,0 +1,173 @@
+<?php
+/**
+ * Implements Special:Activeusers
+ *
+ * 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
+ */
+
+/**
+ * Implements Special:Activeusers
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialActiveUsers extends SpecialPage {
+
+       public function __construct() {
+               parent::__construct( 'Activeusers' );
+       }
+
+       /**
+        * @param string|null $par Parameter passed to the page or null
+        */
+       public function execute( $par ) {
+               $out = $this->getOutput();
+
+               $this->setHeaders();
+               $this->outputHeader();
+
+               $opts = new FormOptions();
+
+               $opts->add( 'username', '' );
+               $opts->add( 'groups', [] );
+               $opts->add( 'excludegroups', [] );
+               // Backwards-compatibility with old URLs
+               $opts->add( 'hidebots', false, FormOptions::BOOL );
+               $opts->add( 'hidesysops', false, FormOptions::BOOL );
+
+               $opts->fetchValuesFromRequest( $this->getRequest() );
+
+               if ( $par !== null ) {
+                       $opts->setValue( 'username', $par );
+               }
+
+               $pager = new ActiveUsersPager( $this->getContext(), $opts );
+               $usersBody = $pager->getBody();
+
+               $this->buildForm();
+
+               if ( $usersBody ) {
+                       $out->addHTML(
+                               $pager->getNavigationBar() .
+                               Html::rawElement( 'ul', [], $usersBody ) .
+                               $pager->getNavigationBar()
+                       );
+                       $out->addModuleStyles( 'mediawiki.interface.helpers.styles' );
+               } else {
+                       $out->addWikiMsg( 'activeusers-noresult' );
+               }
+       }
+
+       /**
+        * Generate and output the form
+        */
+       protected function buildForm() {
+               $groups = User::getAllGroups();
+
+               $options = [];
+               foreach ( $groups as $group ) {
+                       $msg = htmlspecialchars( UserGroupMembership::getGroupName( $group ) );
+                       $options[$msg] = $group;
+               }
+               asort( $options );
+
+               // Backwards-compatibility with old URLs
+               $req = $this->getRequest();
+               $excludeDefault = [];
+               if ( $req->getCheck( 'hidebots' ) ) {
+                       $excludeDefault[] = 'bot';
+               }
+               if ( $req->getCheck( 'hidesysops' ) ) {
+                       $excludeDefault[] = 'sysop';
+               }
+
+               $formDescriptor = [
+                       'username' => [
+                               'type' => 'user',
+                               'name' => 'username',
+                               'label-message' => 'activeusers-from',
+                       ],
+                       'groups' => [
+                               'type' => 'multiselect',
+                               'dropdown' => true,
+                               'flatlist' => true,
+                               'name' => 'groups',
+                               'label-message' => 'activeusers-groups',
+                               'options' => $options,
+                       ],
+                       'excludegroups' => [
+                               'type' => 'multiselect',
+                               'dropdown' => true,
+                               'flatlist' => true,
+                               'name' => 'excludegroups',
+                               'label-message' => 'activeusers-excludegroups',
+                               'options' => $options,
+                               'default' => $excludeDefault,
+                       ],
+               ];
+
+               HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() )
+                       // For the 'multiselect' field values to be preserved on submit
+                       ->setFormIdentifier( 'specialactiveusers' )
+                       ->setIntro( $this->getIntroText() )
+                       ->setWrapperLegendMsg( 'activeusers' )
+                       ->setSubmitTextMsg( 'activeusers-submit' )
+                       // prevent setting subpage and 'username' parameter at the same time
+                       ->setAction( $this->getPageTitle()->getLocalURL() )
+                       ->setMethod( 'get' )
+                       ->prepareForm()
+                       ->displayForm( false );
+       }
+
+       /**
+        * Return introductory message.
+        * @return string
+        */
+       protected function getIntroText() {
+               $days = $this->getConfig()->get( 'ActiveUserDays' );
+
+               $intro = $this->msg( 'activeusers-intro' )->numParams( $days )->parse();
+
+               // Mention the level of cache staleness...
+               $dbr = wfGetDB( DB_REPLICA, 'recentchanges' );
+               $rcMax = $dbr->selectField( 'recentchanges', 'MAX(rc_timestamp)', '', __METHOD__ );
+               if ( $rcMax ) {
+                       $cTime = $dbr->selectField( 'querycache_info',
+                               'qci_timestamp',
+                               [ 'qci_type' => 'activeusers' ],
+                               __METHOD__
+                       );
+                       if ( $cTime ) {
+                               $secondsOld = wfTimestamp( TS_UNIX, $rcMax ) - wfTimestamp( TS_UNIX, $cTime );
+                       } else {
+                               $rcMin = $dbr->selectField( 'recentchanges', 'MIN(rc_timestamp)' );
+                               $secondsOld = time() - wfTimestamp( TS_UNIX, $rcMin );
+                       }
+                       if ( $secondsOld > 0 ) {
+                               $intro .= $this->msg( 'cachedspecial-viewing-cached-ttl' )
+                                       ->durationParams( $secondsOld )->parseAsBlock();
+                       }
+               }
+
+               return $intro;
+       }
+
+       protected function getGroupName() {
+               return 'users';
+       }
+}
diff --git a/includes/specials/SpecialActiveusers.php b/includes/specials/SpecialActiveusers.php
deleted file mode 100644 (file)
index 0c709af..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-<?php
-/**
- * Implements Special:Activeusers
- *
- * 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
- */
-
-/**
- * Implements Special:Activeusers
- *
- * @ingroup SpecialPage
- */
-class SpecialActiveUsers extends SpecialPage {
-
-       public function __construct() {
-               parent::__construct( 'Activeusers' );
-       }
-
-       /**
-        * Show the special page
-        *
-        * @param string $par Parameter passed to the page or null
-        */
-       public function execute( $par ) {
-               $out = $this->getOutput();
-
-               $this->setHeaders();
-               $this->outputHeader();
-
-               $opts = new FormOptions();
-
-               $opts->add( 'username', '' );
-               $opts->add( 'groups', [] );
-               $opts->add( 'excludegroups', [] );
-               // Backwards-compatibility with old URLs
-               $opts->add( 'hidebots', false, FormOptions::BOOL );
-               $opts->add( 'hidesysops', false, FormOptions::BOOL );
-
-               $opts->fetchValuesFromRequest( $this->getRequest() );
-
-               if ( $par !== null ) {
-                       $opts->setValue( 'username', $par );
-               }
-
-               $pager = new ActiveUsersPager( $this->getContext(), $opts );
-               $usersBody = $pager->getBody();
-
-               $this->buildForm();
-
-               if ( $usersBody ) {
-                       $out->addHTML(
-                               $pager->getNavigationBar() .
-                               Html::rawElement( 'ul', [], $usersBody ) .
-                               $pager->getNavigationBar()
-                       );
-               } else {
-                       $out->addWikiMsg( 'activeusers-noresult' );
-               }
-       }
-
-       /**
-        * Generate and output the form
-        */
-       protected function buildForm() {
-               $groups = User::getAllGroups();
-
-               $options = [];
-               foreach ( $groups as $group ) {
-                       $msg = htmlspecialchars( UserGroupMembership::getGroupName( $group ) );
-                       $options[$msg] = $group;
-               }
-               asort( $options );
-
-               // Backwards-compatibility with old URLs
-               $req = $this->getRequest();
-               $excludeDefault = [];
-               if ( $req->getCheck( 'hidebots' ) ) {
-                       $excludeDefault[] = 'bot';
-               }
-               if ( $req->getCheck( 'hidesysops' ) ) {
-                       $excludeDefault[] = 'sysop';
-               }
-
-               $formDescriptor = [
-                       'username' => [
-                               'type' => 'user',
-                               'name' => 'username',
-                               'label-message' => 'activeusers-from',
-                       ],
-                       'groups' => [
-                               'type' => 'multiselect',
-                               'dropdown' => true,
-                               'flatlist' => true,
-                               'name' => 'groups',
-                               'label-message' => 'activeusers-groups',
-                               'options' => $options,
-                       ],
-                       'excludegroups' => [
-                               'type' => 'multiselect',
-                               'dropdown' => true,
-                               'flatlist' => true,
-                               'name' => 'excludegroups',
-                               'label-message' => 'activeusers-excludegroups',
-                               'options' => $options,
-                               'default' => $excludeDefault,
-                       ],
-               ];
-
-               HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() )
-                       // For the 'multiselect' field values to be preserved on submit
-                       ->setFormIdentifier( 'specialactiveusers' )
-                       ->setIntro( $this->getIntroText() )
-                       ->setWrapperLegendMsg( 'activeusers' )
-                       ->setSubmitTextMsg( 'activeusers-submit' )
-                       // prevent setting subpage and 'username' parameter at the same time
-                       ->setAction( $this->getPageTitle()->getLocalURL() )
-                       ->setMethod( 'get' )
-                       ->prepareForm()
-                       ->displayForm( false );
-       }
-
-       /**
-        * Return introductory message.
-        * @return string
-        */
-       protected function getIntroText() {
-               $days = $this->getConfig()->get( 'ActiveUserDays' );
-
-               $intro = $this->msg( 'activeusers-intro' )->numParams( $days )->parse();
-
-               // Mention the level of cache staleness...
-               $dbr = wfGetDB( DB_REPLICA, 'recentchanges' );
-               $rcMax = $dbr->selectField( 'recentchanges', 'MAX(rc_timestamp)', '', __METHOD__ );
-               if ( $rcMax ) {
-                       $cTime = $dbr->selectField( 'querycache_info',
-                               'qci_timestamp',
-                               [ 'qci_type' => 'activeusers' ],
-                               __METHOD__
-                       );
-                       if ( $cTime ) {
-                               $secondsOld = wfTimestamp( TS_UNIX, $rcMax ) - wfTimestamp( TS_UNIX, $cTime );
-                       } else {
-                               $rcMin = $dbr->selectField( 'recentchanges', 'MIN(rc_timestamp)' );
-                               $secondsOld = time() - wfTimestamp( TS_UNIX, $rcMin );
-                       }
-                       if ( $secondsOld > 0 ) {
-                               $intro .= $this->msg( 'cachedspecial-viewing-cached-ttl' )
-                                       ->durationParams( $secondsOld )->parseAsBlock();
-                       }
-               }
-
-               return $intro;
-       }
-
-       protected function getGroupName() {
-               return 'users';
-       }
-}
index 2482d74..f6b8b90 100644 (file)
@@ -35,9 +35,7 @@ class SpecialAllMessages extends SpecialPage {
        }
 
        /**
-        * Show the special page
-        *
-        * @param string $par Parameter passed to the page or null
+        * @param string|null $par Parameter passed to the page or null
         */
        public function execute( $par ) {
                $out = $this->getOutput();
@@ -45,7 +43,7 @@ class SpecialAllMessages extends SpecialPage {
                $this->setHeaders();
 
                if ( !$this->getConfig()->get( 'UseDatabaseMessages' ) ) {
-                       $out->addWikiMsg( 'allmessagesnotsupportedDB' );
+                       $out->addWikiMsg( 'allmessages-not-supported-database' );
 
                        return;
                }
@@ -79,10 +77,10 @@ class SpecialAllMessages extends SpecialPage {
                                'type' => 'radio',
                                'name' => 'filter',
                                'label-message' => 'allmessages-filter',
-                               'options' => [
-                                       $this->msg( 'allmessages-filter-unmodified' )->text() => 'unmodified',
-                                       $this->msg( 'allmessages-filter-all' )->text() => 'all',
-                                       $this->msg( 'allmessages-filter-modified' )->text() => 'modified',
+                               'options-messages' => [
+                                       'allmessages-filter-unmodified' => 'unmodified',
+                                       'allmessages-filter-all' => 'all',
+                                       'allmessages-filter-modified' => 'modified',
                                ],
                                'default' => 'all',
                                'flatlist' => true,
index cea6d37..a32393e 100644 (file)
@@ -45,7 +45,8 @@ class AncientPagesPage extends QueryPage {
        public function getQueryInfo() {
                $tables = [ 'page', 'revision' ];
                $conds = [
-                       'page_namespace' => MWNamespace::getContentNamespaces(),
+                       'page_namespace' =>
+                               MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces(),
                        'page_is_redirect' => 0
                ];
                $joinConds = [
index cab5a2e..34c3371 100644 (file)
@@ -34,9 +34,7 @@ class SpecialAutoblockList extends SpecialPage {
        }
 
        /**
-        * Main execution point
-        *
-        * @param string $par Title fragment
+        * @param string|null $par Title fragment
         */
        public function execute( $par ) {
                $this->setHeaders();
index 7330e77..b79a482 100644 (file)
@@ -21,9 +21,9 @@
  * @ingroup SpecialPage
  */
 
-use MediaWiki\Block\BlockRestriction;
 use MediaWiki\Block\Restriction\PageRestriction;
 use MediaWiki\Block\Restriction\NamespaceRestriction;
+use MediaWiki\MediaWikiServices;
 
 /**
  * A special page that allows users with 'block' right to block users from
@@ -141,7 +141,9 @@ class SpecialBlock extends FormSpecialPage {
         * @return array
         */
        protected function getFormFields() {
-               global $wgBlockAllowsUTEdit;
+               $conf = $this->getConfig();
+               $enablePartialBlocks = $conf->get( 'EnablePartialBlocks' );
+               $blockAllowsUTEdit = $conf->get( 'BlockAllowsUTEdit' );
 
                $this->getOutput()->enableOOUI();
 
@@ -149,9 +151,6 @@ class SpecialBlock extends FormSpecialPage {
 
                $suggestedDurations = self::getSuggestedDurations();
 
-               $conf = $this->getConfig();
-               $enablePartialBlocks = $conf->get( 'EnablePartialBlocks' );
-
                $a = [];
 
                $a['Target'] = [
@@ -232,7 +231,7 @@ class SpecialBlock extends FormSpecialPage {
                        ];
                }
 
-               if ( $wgBlockAllowsUTEdit ) {
+               if ( $blockAllowsUTEdit ) {
                        $a['DisableUTEdit'] = [
                                'type' => 'check',
                                'label-message' => 'ipb-disableusertalk',
@@ -338,9 +337,11 @@ class SpecialBlock extends FormSpecialPage {
 
                $block = Block::newFromTarget( $this->target );
 
-               if ( $block instanceof Block && !$block->mAuto # The block exists and isn't an autoblock
-                       && ( $this->type != Block::TYPE_RANGE # The block isn't a rangeblock
-                               || $block->getTarget() == $this->target ) # or if it is, the range is what we're about to block
+               // Populate fields if there is a block that is not an autoblock; if it is a range
+               // block, only populate the fields if the range is the same as $this->target
+               if ( $block instanceof Block && $block->getType() !== Block::TYPE_AUTO
+                       && ( $this->type != Block::TYPE_RANGE
+                               || $block->getTarget() == $this->target )
                ) {
                        $fields['HardBlock']['default'] = $block->isHardblock();
                        $fields['CreateAccount']['default'] = $block->isCreateAccountBlocked();
@@ -351,7 +352,7 @@ class SpecialBlock extends FormSpecialPage {
                        }
 
                        if ( isset( $fields['HideUser'] ) ) {
-                               $fields['HideUser']['default'] = $block->mHideName;
+                               $fields['HideUser']['default'] = $block->getHideName();
                        }
 
                        if ( isset( $fields['DisableUTEdit'] ) ) {
@@ -360,8 +361,8 @@ class SpecialBlock extends FormSpecialPage {
 
                        // If the username was hidden (ipb_deleted == 1), don't show the reason
                        // unless this user also has rights to hideuser: T37839
-                       if ( !$block->mHideName || $this->getUser()->isAllowed( 'hideuser' ) ) {
-                               $fields['Reason']['default'] = $block->mReason;
+                       if ( !$block->getHideName() || $this->getUser()->isAllowed( 'hideuser' ) ) {
+                               $fields['Reason']['default'] = $block->getReason();
                        } else {
                                $fields['Reason']['default'] = '';
                        }
@@ -377,16 +378,22 @@ class SpecialBlock extends FormSpecialPage {
                                $fields['Confirm']['default'] = 1;
                        }
 
-                       if ( $block->mExpiry == 'infinity' ) {
+                       if ( $block->getExpiry() == 'infinity' ) {
                                $fields['Expiry']['default'] = 'infinite';
                        } else {
-                               $fields['Expiry']['default'] = wfTimestamp( TS_RFC2822, $block->mExpiry );
+                               $fields['Expiry']['default'] = wfTimestamp( TS_RFC2822, $block->getExpiry() );
                        }
 
                        $this->alreadyBlocked = true;
                        $this->preErrors[] = [ 'ipb-needreblock', wfEscapeWikiText( (string)$block->getTarget() ) ];
                }
 
+               if ( $this->alreadyBlocked || $this->getRequest()->wasPosted()
+                       || $this->getRequest()->getCheck( 'wpCreateAccount' )
+               ) {
+                       $this->getOutput()->addJsConfigVars( 'wgCreateAccountDirty', true );
+               }
+
                # We always need confirmation to do HideUser
                if ( $this->requestedHideUser ) {
                        $fields['Confirm']['type'] = 'check';
@@ -612,6 +619,7 @@ class SpecialBlock extends FormSpecialPage {
         *     the HTMLForm
         * @param WebRequest|null $request Optionally try and get data from a request too
         * @return array [ User|string|null, Block::TYPE_ constant|null ]
+        * @phan-return array{0:User|string|null,1:int|null}
         */
        public static function getTargetAndType( $par, WebRequest $request = null ) {
                $i = 0;
@@ -855,14 +863,14 @@ class SpecialBlock extends FormSpecialPage {
                $block = new Block();
                $block->setTarget( $target );
                $block->setBlocker( $performer );
-               $block->mReason = $data['Reason'][0];
-               $block->mExpiry = $expiryTime;
+               $block->setReason( $data['Reason'][0] );
+               $block->setExpiry( $expiryTime );
                $block->isCreateAccountBlocked( $data['CreateAccount'] );
                $block->isUsertalkEditAllowed( !$wgBlockAllowsUTEdit || !$data['DisableUTEdit'] );
                $block->isEmailBlocked( $data['DisableEmail'] );
                $block->isHardblock( $data['HardBlock'] );
                $block->isAutoblocking( $data['AutoBlock'] );
-               $block->mHideName = $data['HideUser'];
+               $block->setHideName( $data['HideUser'] );
 
                if ( $isPartialBlock ) {
                        $block->isSitewide( false );
@@ -921,19 +929,19 @@ class SpecialBlock extends FormSpecialPage {
                                }
                                # If the name was hidden and the blocking user cannot hide
                                # names, then don't allow any block changes...
-                               if ( $currentBlock->mHideName && !$performer->isAllowed( 'hideuser' ) ) {
+                               if ( $currentBlock->getHideName() && !$performer->isAllowed( 'hideuser' ) ) {
                                        return [ 'cant-see-hidden-user' ];
                                }
 
                                $priorBlock = clone $currentBlock;
                                $currentBlock->isHardblock( $block->isHardblock() );
                                $currentBlock->isCreateAccountBlocked( $block->isCreateAccountBlocked() );
-                               $currentBlock->mExpiry = $block->mExpiry;
+                               $currentBlock->setExpiry( $block->getExpiry() );
                                $currentBlock->isAutoblocking( $block->isAutoblocking() );
-                               $currentBlock->mHideName = $block->mHideName;
+                               $currentBlock->setHideName( $block->getHideName() );
                                $currentBlock->isEmailBlocked( $block->isEmailBlocked() );
                                $currentBlock->isUsertalkEditAllowed( $block->isUsertalkEditAllowed() );
-                               $currentBlock->mReason = $block->mReason;
+                               $currentBlock->setReason( $block->getReason() );
 
                                if ( $enablePartialBlocks ) {
                                        // Maintain the sitewide status. If partial blocks is not enabled,
@@ -941,8 +949,9 @@ class SpecialBlock extends FormSpecialPage {
                                        $currentBlock->isSitewide( $block->isSitewide() );
 
                                        // Set the block id of the restrictions.
+                                       $blockRestrictionStore = MediaWikiServices::getInstance()->getBlockRestrictionStore();
                                        $currentBlock->setRestrictions(
-                                               BlockRestriction::setBlockId( $currentBlock->getId(), $restrictions )
+                                               $blockRestrictionStore->setBlockId( $currentBlock->getId(), $restrictions )
                                        );
                                }
 
@@ -952,12 +961,12 @@ class SpecialBlock extends FormSpecialPage {
                                $logaction = 'reblock';
 
                                # Unset _deleted fields if requested
-                               if ( $currentBlock->mHideName && !$data['HideUser'] ) {
+                               if ( $currentBlock->getHideName() && !$data['HideUser'] ) {
                                        RevisionDeleteUser::unsuppressUserName( $target, $userId );
                                }
 
                                # If hiding/unhiding a name, this should go in the private logs
-                               if ( (bool)$currentBlock->mHideName ) {
+                               if ( (bool)$currentBlock->getHideName() ) {
                                        $data['HideUser'] = true;
                                }
 
@@ -1067,7 +1076,7 @@ class SpecialBlock extends FormSpecialPage {
         *
         * @todo strtotime() only accepts English strings. This means the expiry input
         *       can only be specified in English.
-        * @see https://secure.php.net/manual/en/function.strtotime.php
+        * @see https://www.php.net/manual/en/function.strtotime.php
         *
         * @param string $expiry Whatever was typed into the form
         * @return string|bool Timestamp or 'infinity' or false on error.
@@ -1117,9 +1126,11 @@ class SpecialBlock extends FormSpecialPage {
                } elseif ( is_string( $target ) ) {
                        $target = User::newFromName( $target );
                }
-               if ( $performer->isBlocked() ) {
+               if ( $performer->getBlock() ) {
                        if ( $target instanceof User && $target->getId() == $performer->getId() ) {
                                # User is trying to unblock themselves
+                               // @TODO Ensure that the block does not apply to the `unblockself`
+                               //       right.
                                if ( $performer->isAllowed( 'unblockself' ) ) {
                                        return true;
                                        # User blocked themselves and is now trying to reverse it
index 186e5ad..4e541c9 100644 (file)
@@ -31,27 +31,28 @@ class SpecialBlockList extends SpecialPage {
 
        protected $options;
 
+       protected $blockType;
+
        function __construct() {
                parent::__construct( 'BlockList' );
        }
 
        /**
-        * Main execution point
-        *
-        * @param string $par Title fragment
+        * @param string|null $par Title fragment
         */
        public function execute( $par ) {
                $this->setHeaders();
                $this->outputHeader();
                $out = $this->getOutput();
                $out->setPageTitle( $this->msg( 'ipblocklist' ) );
-               $out->addModuleStyles( [ 'mediawiki.special' ] );
+               $out->addModuleStyles( [ 'mediawiki.special', 'mediawiki.special.blocklist' ] );
 
                $request = $this->getRequest();
                $par = $request->getVal( 'ip', $par );
                $this->target = trim( $request->getVal( 'wpTarget', $par ) );
 
                $this->options = $request->getArray( 'wpOptions', [] );
+               $this->blockType = $request->getVal( 'blockType' );
 
                $action = $request->getText( 'action' );
 
@@ -85,14 +86,33 @@ class SpecialBlockList extends SpecialPage {
                                ],
                                'flatlist' => true,
                        ],
-                       'Limit' => [
-                               'type' => 'limitselect',
-                               'label-message' => 'table_pager_limit_label',
-                               'options' => $pager->getLimitSelectList(),
-                               'name' => 'limit',
-                               'default' => $pager->getLimit(),
-                       ],
                ];
+
+               if ( $this->getConfig()->get( 'EnablePartialBlocks' ) ) {
+                       $fields['BlockType'] = [
+                               'type' => 'select',
+                               'label-message' => 'blocklist-type',
+                               'options' => [
+                                       $this->msg( 'blocklist-type-opt-all' )->escaped() => '',
+                                       $this->msg( 'blocklist-type-opt-sitewide' )->escaped() => 'sitewide',
+                                       $this->msg( 'blocklist-type-opt-partial' )->escaped() => 'partial',
+                               ],
+                               'name' => 'blockType',
+                               'cssclass' => 'mw-field-block-type',
+                       ];
+               }
+
+               $fields['Limit'] = [
+                       'type' => 'limitselect',
+                       'label-message' => 'table_pager_limit_label',
+                       'options' => $pager->getLimitSelectList(),
+                       'name' => 'limit',
+                       'default' => $pager->getLimit(),
+                       'cssclass' => $this->getConfig()->get( 'EnablePartialBlocks' ) ?
+                               'mw-field-limit mw-has-field-block-type' :
+                               'mw-field-limit',
+               ];
+
                $context = new DerivativeContext( $this->getContext() );
                $context->setTitle( $this->getPageTitle() ); // Remove subpage
                $form = HTMLForm::factory( 'ooui', $fields, $context );
@@ -161,6 +181,12 @@ class SpecialBlockList extends SpecialPage {
                        $conds[] = "ipb_range_end = ipb_range_start";
                }
 
+               if ( $this->blockType === 'sitewide' ) {
+                       $conds[] = 'ipb_sitewide = 1';
+               } elseif ( $this->blockType === 'partial' ) {
+                       $conds[] = 'ipb_sitewide = 0';
+               }
+
                return new BlockListPager( $this, $conds );
        }
 
diff --git a/includes/specials/SpecialBookSources.php b/includes/specials/SpecialBookSources.php
new file mode 100644 (file)
index 0000000..ea9ddaf
--- /dev/null
@@ -0,0 +1,212 @@
+<?php
+/**
+ * Implements Special:Booksources
+ *
+ * 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 outputs information on sourcing a book with a particular ISBN
+ * The parser creates links to this page when dealing with ISBNs in wikitext
+ *
+ * @author Rob Church <robchur@gmail.com>
+ * @ingroup SpecialPage
+ */
+class SpecialBookSources extends SpecialPage {
+       public function __construct() {
+               parent::__construct( 'Booksources' );
+       }
+
+       /**
+        * @param string|null $isbn ISBN passed as a subpage parameter
+        */
+       public function execute( $isbn ) {
+               $out = $this->getOutput();
+
+               $this->setHeaders();
+               $this->outputHeader();
+
+               // User provided ISBN
+               $isbn = $isbn ?: $this->getRequest()->getText( 'isbn' );
+               $isbn = trim( $isbn );
+
+               $this->buildForm( $isbn );
+
+               if ( $isbn !== '' ) {
+                       if ( !self::isValidISBN( $isbn ) ) {
+                               $out->wrapWikiMsg(
+                                       "<div class=\"error\">\n$1\n</div>",
+                                       'booksources-invalid-isbn'
+                               );
+                       }
+
+                       $this->showList( $isbn );
+               }
+       }
+
+       /**
+        * Return whether a given ISBN (10 or 13) is valid.
+        *
+        * @param string $isbn ISBN passed for check
+        * @return bool
+        */
+       public static function isValidISBN( $isbn ) {
+               $isbn = self::cleanIsbn( $isbn );
+               $sum = 0;
+               if ( strlen( $isbn ) == 13 ) {
+                       for ( $i = 0; $i < 12; $i++ ) {
+                               if ( $isbn[$i] === 'X' ) {
+                                       return false;
+                               } elseif ( $i % 2 == 0 ) {
+                                       $sum += $isbn[$i];
+                               } else {
+                                       $sum += 3 * $isbn[$i];
+                               }
+                       }
+
+                       $check = ( 10 - ( $sum % 10 ) ) % 10;
+                       if ( (string)$check === $isbn[12] ) {
+                               return true;
+                       }
+               } elseif ( strlen( $isbn ) == 10 ) {
+                       for ( $i = 0; $i < 9; $i++ ) {
+                               if ( $isbn[$i] === 'X' ) {
+                                       return false;
+                               }
+                               $sum += $isbn[$i] * ( $i + 1 );
+                       }
+
+                       $check = $sum % 11;
+                       if ( $check == 10 ) {
+                               $check = "X";
+                       }
+                       if ( (string)$check === $isbn[9] ) {
+                               return true;
+                       }
+               }
+
+               return false;
+       }
+
+       /**
+        * Trim ISBN and remove characters which aren't required
+        *
+        * @param string $isbn Unclean ISBN
+        * @return string
+        */
+       private static function cleanIsbn( $isbn ) {
+               return trim( preg_replace( '![^0-9X]!', '', $isbn ) );
+       }
+
+       /**
+        * Generate a form to allow users to enter an ISBN
+        *
+        * @param string $isbn
+        */
+       private function buildForm( $isbn ) {
+               $formDescriptor = [
+                       'isbn' => [
+                               'type' => 'text',
+                               'name' => 'isbn',
+                               'label-message' => 'booksources-isbn',
+                               'default' => $isbn,
+                               'autofocus' => true,
+                               'required' => true,
+                       ],
+               ];
+
+               $context = new DerivativeContext( $this->getContext() );
+               $context->setTitle( $this->getPageTitle() );
+               HTMLForm::factory( 'ooui', $formDescriptor, $context )
+                       ->setWrapperLegendMsg( 'booksources-search-legend' )
+                       ->setSubmitTextMsg( 'booksources-search' )
+                       ->setMethod( 'get' )
+                       ->prepareForm()
+                       ->displayForm( false );
+       }
+
+       /**
+        * Determine where to get the list of book sources from,
+        * format and output them
+        *
+        * @param string $isbn
+        * @throws MWException
+        * @return bool
+        */
+       private function showList( $isbn ) {
+               $out = $this->getOutput();
+
+               $isbn = self::cleanIsbn( $isbn );
+               # Hook to allow extensions to insert additional HTML,
+               # e.g. for API-interacting plugins and so on
+               Hooks::run( 'BookInformation', [ $isbn, $out ] );
+
+               # Check for a local page such as Project:Book_sources and use that if available
+               $page = $this->msg( 'booksources' )->inContentLanguage()->text();
+               $title = Title::makeTitleSafe( NS_PROJECT, $page ); # Show list in content language
+               if ( is_object( $title ) && $title->exists() ) {
+                       $rev = Revision::newFromTitle( $title, false, Revision::READ_NORMAL );
+                       $content = $rev->getContent();
+
+                       if ( $content instanceof TextContent ) {
+                               // XXX: in the future, this could be stored as structured data, defining a list of book sources
+
+                               $text = $content->getText();
+                               $out->addWikiTextAsInterface( str_replace( 'MAGICNUMBER', $isbn, $text ) );
+
+                               return true;
+                       } else {
+                               throw new MWException( "Unexpected content type for book sources: " . $content->getModel() );
+                       }
+               }
+
+               # Fall back to the defaults given in the language file
+               $out->addWikiMsg( 'booksources-text' );
+               $out->addHTML( '<ul>' );
+               $items = MediaWikiServices::getInstance()->getContentLanguage()->getBookstoreList();
+               foreach ( $items as $label => $url ) {
+                       $out->addHTML( $this->makeListItem( $isbn, $label, $url ) );
+               }
+               $out->addHTML( '</ul>' );
+
+               return true;
+       }
+
+       /**
+        * Format a book source list item
+        *
+        * @param string $isbn
+        * @param string $label Book source label
+        * @param string $url Book source URL
+        * @return string
+        */
+       private function makeListItem( $isbn, $label, $url ) {
+               $url = str_replace( '$1', $isbn, $url );
+
+               return Html::rawElement( 'li', [],
+                       Html::element( 'a', [ 'href' => $url, 'class' => 'external' ], $label )
+               );
+       }
+
+       protected function getGroupName() {
+               return 'wiki';
+       }
+}
diff --git a/includes/specials/SpecialBooksources.php b/includes/specials/SpecialBooksources.php
deleted file mode 100644 (file)
index 2fe38ed..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-<?php
-/**
- * Implements Special:Booksources
- *
- * 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 outputs information on sourcing a book with a particular ISBN
- * The parser creates links to this page when dealing with ISBNs in wikitext
- *
- * @author Rob Church <robchur@gmail.com>
- * @ingroup SpecialPage
- */
-class SpecialBookSources extends SpecialPage {
-       public function __construct() {
-               parent::__construct( 'Booksources' );
-       }
-
-       /**
-        * Show the special page
-        *
-        * @param string $isbn ISBN passed as a subpage parameter
-        */
-       public function execute( $isbn ) {
-               $out = $this->getOutput();
-
-               $this->setHeaders();
-               $this->outputHeader();
-
-               // User provided ISBN
-               $isbn = $isbn ?: $this->getRequest()->getText( 'isbn' );
-               $isbn = trim( $isbn );
-
-               $this->buildForm( $isbn );
-
-               if ( $isbn !== '' ) {
-                       if ( !self::isValidISBN( $isbn ) ) {
-                               $out->wrapWikiMsg(
-                                       "<div class=\"error\">\n$1\n</div>",
-                                       'booksources-invalid-isbn'
-                               );
-                       }
-
-                       $this->showList( $isbn );
-               }
-       }
-
-       /**
-        * Return whether a given ISBN (10 or 13) is valid.
-        *
-        * @param string $isbn ISBN passed for check
-        * @return bool
-        */
-       public static function isValidISBN( $isbn ) {
-               $isbn = self::cleanIsbn( $isbn );
-               $sum = 0;
-               if ( strlen( $isbn ) == 13 ) {
-                       for ( $i = 0; $i < 12; $i++ ) {
-                               if ( $isbn[$i] === 'X' ) {
-                                       return false;
-                               } elseif ( $i % 2 == 0 ) {
-                                       $sum += $isbn[$i];
-                               } else {
-                                       $sum += 3 * $isbn[$i];
-                               }
-                       }
-
-                       $check = ( 10 - ( $sum % 10 ) ) % 10;
-                       if ( (string)$check === $isbn[12] ) {
-                               return true;
-                       }
-               } elseif ( strlen( $isbn ) == 10 ) {
-                       for ( $i = 0; $i < 9; $i++ ) {
-                               if ( $isbn[$i] === 'X' ) {
-                                       return false;
-                               }
-                               $sum += $isbn[$i] * ( $i + 1 );
-                       }
-
-                       $check = $sum % 11;
-                       if ( $check == 10 ) {
-                               $check = "X";
-                       }
-                       if ( (string)$check === $isbn[9] ) {
-                               return true;
-                       }
-               }
-
-               return false;
-       }
-
-       /**
-        * Trim ISBN and remove characters which aren't required
-        *
-        * @param string $isbn Unclean ISBN
-        * @return string
-        */
-       private static function cleanIsbn( $isbn ) {
-               return trim( preg_replace( '![^0-9X]!', '', $isbn ) );
-       }
-
-       /**
-        * Generate a form to allow users to enter an ISBN
-        *
-        * @param string $isbn
-        */
-       private function buildForm( $isbn ) {
-               $formDescriptor = [
-                       'isbn' => [
-                               'type' => 'text',
-                               'name' => 'isbn',
-                               'label-message' => 'booksources-isbn',
-                               'default' => $isbn,
-                               'autofocus' => true,
-                               'required' => true,
-                       ],
-               ];
-
-               $context = new DerivativeContext( $this->getContext() );
-               $context->setTitle( $this->getPageTitle() );
-               HTMLForm::factory( 'ooui', $formDescriptor, $context )
-                       ->setWrapperLegendMsg( 'booksources-search-legend' )
-                       ->setSubmitTextMsg( 'booksources-search' )
-                       ->setMethod( 'get' )
-                       ->prepareForm()
-                       ->displayForm( false );
-       }
-
-       /**
-        * Determine where to get the list of book sources from,
-        * format and output them
-        *
-        * @param string $isbn
-        * @throws MWException
-        * @return bool
-        */
-       private function showList( $isbn ) {
-               $out = $this->getOutput();
-
-               $isbn = self::cleanIsbn( $isbn );
-               # Hook to allow extensions to insert additional HTML,
-               # e.g. for API-interacting plugins and so on
-               Hooks::run( 'BookInformation', [ $isbn, $out ] );
-
-               # Check for a local page such as Project:Book_sources and use that if available
-               $page = $this->msg( 'booksources' )->inContentLanguage()->text();
-               $title = Title::makeTitleSafe( NS_PROJECT, $page ); # Show list in content language
-               if ( is_object( $title ) && $title->exists() ) {
-                       $rev = Revision::newFromTitle( $title, false, Revision::READ_NORMAL );
-                       $content = $rev->getContent();
-
-                       if ( $content instanceof TextContent ) {
-                               // XXX: in the future, this could be stored as structured data, defining a list of book sources
-
-                               $text = $content->getText();
-                               $out->addWikiTextAsInterface( str_replace( 'MAGICNUMBER', $isbn, $text ) );
-
-                               return true;
-                       } else {
-                               throw new MWException( "Unexpected content type for book sources: " . $content->getModel() );
-                       }
-               }
-
-               # Fall back to the defaults given in the language file
-               $out->addWikiMsg( 'booksources-text' );
-               $out->addHTML( '<ul>' );
-               $items = MediaWikiServices::getInstance()->getContentLanguage()->getBookstoreList();
-               foreach ( $items as $label => $url ) {
-                       $out->addHTML( $this->makeListItem( $isbn, $label, $url ) );
-               }
-               $out->addHTML( '</ul>' );
-
-               return true;
-       }
-
-       /**
-        * Format a book source list item
-        *
-        * @param string $isbn
-        * @param string $label Book source label
-        * @param string $url Book source URL
-        * @return string
-        */
-       private function makeListItem( $isbn, $label, $url ) {
-               $url = str_replace( '$1', $isbn, $url );
-
-               return Html::rawElement( 'li', [],
-                       Html::element( 'a', [ 'href' => $url, 'class' => 'external' ], $label )
-               );
-       }
-
-       protected function getGroupName() {
-               return 'wiki';
-       }
-}
index d6fb10f..36928ca 100644 (file)
@@ -43,8 +43,7 @@ class SpecialComparePages extends SpecialPage {
        /**
         * Show a form for filtering namespace and username
         *
-        * @param string $par
-        * @return string
+        * @param string|null $par
         */
        public function execute( $par ) {
                $this->setHeaders();
index c0303b2..ce08392 100644 (file)
@@ -21,6 +21,7 @@
  * @ingroup SpecialPage
  */
 
+use MediaWiki\MediaWikiServices;
 use MediaWiki\Widget\DateInputWidget;
 
 /**
@@ -244,9 +245,9 @@ class SpecialContributions extends IncludableSpecialPage {
 
                                $output = $pager->getBody();
                                if ( !$this->including() ) {
-                                       $output = '<p>' . $pager->getNavigationBar() . '</p>' .
+                                       $output = $pager->getNavigationBar() .
                                                $output .
-                                               '<p>' . $pager->getNavigationBar() . '</p>';
+                                               $pager->getNavigationBar();
                                }
                                $out->addHTML( $output );
                        }
@@ -267,14 +268,10 @@ class SpecialContributions extends IncludableSpecialPage {
                                $message = 'sp-contributions-footer';
                        }
 
-                       if ( $message ) {
-                               if ( !$this->including() ) {
-                                       if ( !$this->msg( $message, $target )->isDisabled() ) {
-                                               $out->wrapWikiMsg(
-                                                       "<div class='mw-contributions-footer'>\n$1\n</div>",
-                                                       [ $message, $target ] );
-                                       }
-                               }
+                       if ( $message && !$this->including() && !$this->msg( $message, $target )->isDisabled() ) {
+                               $out->wrapWikiMsg(
+                                       "<div class='mw-contributions-footer'>\n$1\n</div>",
+                                       [ $message, $target ] );
                        }
                }
        }
@@ -313,7 +310,11 @@ class SpecialContributions extends IncludableSpecialPage {
                $links = '';
                if ( $talk ) {
                        $tools = self::getUserLinks( $this, $userObj );
-                       $links = $this->getLanguage()->pipeList( $tools );
+                       $links = Html::openElement( 'span', [ 'class' => 'mw-changeslist-links' ] );
+                       foreach ( $tools as $tool ) {
+                               $links .= Html::rawElement( 'span', [], $tool ) . ' ';
+                       }
+                       $links = trim( $links ) . Html::closeElement( 'span' );
 
                        // Show a note if the user is blocked and display the last block log entry.
                        // Do not expose the autoblocks, since that may lead to a leak of accounts' IPs,
@@ -328,7 +329,8 @@ class SpecialContributions extends IncludableSpecialPage {
 
                                if ( !is_null( $block ) && $block->getType() != Block::TYPE_AUTO ) {
                                        if ( $block->getType() == Block::TYPE_RANGE ) {
-                                               $nt = MWNamespace::getCanonicalName( NS_USER ) . ':' . $block->getTarget();
+                                               $nt = MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                                       getCanonicalName( NS_USER ) . ':' . $block->getTarget();
                                        }
 
                                        $out = $this->getOutput(); // showLogExtract() wants first parameter by reference
@@ -353,7 +355,10 @@ class SpecialContributions extends IncludableSpecialPage {
                        }
                }
 
-               return $this->msg( 'contribsub2' )->rawParams( $user, $links )->params( $userObj->getName() );
+               return Html::rawElement( 'div', [ 'class' => 'mw-contributions-user-tools' ],
+                       $this->msg( 'contributions-subtitle' )->rawParams( $user )->params( $userObj->getName() )
+                       . ' ' . $links
+               );
        }
 
        /**
@@ -369,70 +374,74 @@ class SpecialContributions extends IncludableSpecialPage {
                $username = $target->getName();
                $userpage = $target->getUserPage();
                $talkpage = $target->getTalkPage();
+               $isIP = IP::isValid( $username );
+               $isRange = IP::isValidRange( $username );
 
                $linkRenderer = $sp->getLinkRenderer();
 
                # No talk pages for IP ranges.
-               if ( !IP::isValidRange( $username ) ) {
+               if ( !$isRange ) {
                        $tools['user-talk'] = $linkRenderer->makeLink(
                                $talkpage,
                                $sp->msg( 'sp-contributions-talk' )->text()
                        );
                }
 
-               if ( ( $id !== null ) || ( $id === null && IP::isIPAddress( $username ) ) ) {
-                       if ( $sp->getUser()->isAllowed( 'block' ) ) { # Block / Change block / Unblock links
-                               if ( $target->isBlocked() && $target->getBlock()->getType() != Block::TYPE_AUTO ) {
-                                       $tools['block'] = $linkRenderer->makeKnownLink( # Change block link
-                                               SpecialPage::getTitleFor( 'Block', $username ),
-                                               $sp->msg( 'change-blocklink' )->text()
-                                       );
-                                       $tools['unblock'] = $linkRenderer->makeKnownLink( # Unblock link
-                                               SpecialPage::getTitleFor( 'Unblock', $username ),
-                                               $sp->msg( 'unblocklink' )->text()
-                                       );
-                               } else { # User is not blocked
-                                       $tools['block'] = $linkRenderer->makeKnownLink( # Block link
-                                               SpecialPage::getTitleFor( 'Block', $username ),
-                                               $sp->msg( 'blocklink' )->text()
-                                       );
-                               }
+               if ( $sp->getUser()->isAllowed( 'block' ) ) { # Block / Change block / Unblock links
+                       if ( $target->getBlock() && $target->getBlock()->getType() != Block::TYPE_AUTO ) {
+                               $tools['block'] = $linkRenderer->makeKnownLink( # Change block link
+                                       SpecialPage::getTitleFor( 'Block', $username ),
+                                       $sp->msg( 'change-blocklink' )->text()
+                               );
+                               $tools['unblock'] = $linkRenderer->makeKnownLink( # Unblock link
+                                       SpecialPage::getTitleFor( 'Unblock', $username ),
+                                       $sp->msg( 'unblocklink' )->text()
+                               );
+                       } else { # User is not blocked
+                               $tools['block'] = $linkRenderer->makeKnownLink( # Block link
+                                       SpecialPage::getTitleFor( 'Block', $username ),
+                                       $sp->msg( 'blocklink' )->text()
+                               );
                        }
+               }
+
+               # Block log link
+               $tools['log-block'] = $linkRenderer->makeKnownLink(
+                       SpecialPage::getTitleFor( 'Log', 'block' ),
+                       $sp->msg( 'sp-contributions-blocklog' )->text(),
+                       [],
+                       [ 'page' => $userpage->getPrefixedText() ]
+               );
 
-                       # Block log link
-                       $tools['log-block'] = $linkRenderer->makeKnownLink(
-                               SpecialPage::getTitleFor( 'Log', 'block' ),
-                               $sp->msg( 'sp-contributions-blocklog' )->text(),
+               # Suppression log link (T61120)
+               if ( $sp->getUser()->isAllowed( 'suppressionlog' ) ) {
+                       $tools['log-suppression'] = $linkRenderer->makeKnownLink(
+                               SpecialPage::getTitleFor( 'Log', 'suppress' ),
+                               $sp->msg( 'sp-contributions-suppresslog', $username )->text(),
                                [],
-                               [ 'page' => $userpage->getPrefixedText() ]
+                               [ 'offender' => $username ]
                        );
-
-                       # Suppression log link (T61120)
-                       if ( $sp->getUser()->isAllowed( 'suppressionlog' ) ) {
-                               $tools['log-suppression'] = $linkRenderer->makeKnownLink(
-                                       SpecialPage::getTitleFor( 'Log', 'suppress' ),
-                                       $sp->msg( 'sp-contributions-suppresslog', $username )->text(),
-                                       [],
-                                       [ 'offender' => $username ]
-                               );
-                       }
                }
 
                # Don't show some links for IP ranges
-               if ( !IP::isValidRange( $username ) ) {
-                       # Uploads
-                       $tools['uploads'] = $linkRenderer->makeKnownLink(
-                               SpecialPage::getTitleFor( 'Listfiles', $username ),
-                               $sp->msg( 'sp-contributions-uploads' )->text()
-                       );
+               if ( !$isRange ) {
+                       # Uploads: hide if IPs cannot upload (T220674)
+                       if ( !$isIP || $target->isAllowed( 'upload' ) ) {
+                               $tools['uploads'] = $linkRenderer->makeKnownLink(
+                                       SpecialPage::getTitleFor( 'Listfiles', $username ),
+                                       $sp->msg( 'sp-contributions-uploads' )->text()
+                               );
+                       }
 
                        # Other logs link
+                       # Todo: T146628
                        $tools['logs'] = $linkRenderer->makeKnownLink(
                                SpecialPage::getTitleFor( 'Log', $username ),
                                $sp->msg( 'sp-contributions-logs' )->text()
                        );
 
                        # Add link to deleted user contributions for priviledged users
+                       # Todo: T183457
                        if ( $sp->getUser()->isAllowed( 'deletedhistory' ) ) {
                                $tools['deletedcontribs'] = $linkRenderer->makeKnownLink(
                                        SpecialPage::getTitleFor( 'DeletedContributions', $username ),
index f13f231..2a967c5 100644 (file)
@@ -21,6 +21,8 @@
  * @ingroup SpecialPage
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * A special page that list pages that contain no link to other pages
  *
@@ -66,7 +68,8 @@ class DeadendPagesPage extends PageQueryPage {
                        ],
                        'conds' => [
                                'pl_from IS NULL',
-                               'page_namespace' => MWNamespace::getContentNamespaces(),
+                               'page_namespace' => MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                       getContentNamespaces(),
                                'page_is_redirect' => 0
                        ],
                        'join_conds' => [
@@ -81,7 +84,9 @@ class DeadendPagesPage extends PageQueryPage {
        function getOrderFields() {
                // For some crazy reason ordering by a constant
                // causes a filesort
-               if ( count( MWNamespace::getContentNamespaces() ) > 1 ) {
+               if ( count( MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       getContentNamespaces() ) > 1
+               ) {
                        return [ 'page_namespace', 'page_title' ];
                } else {
                        return [ 'page_title' ];
index d405be7..73b438c 100644 (file)
@@ -21,6 +21,8 @@
  * @ingroup SpecialPage
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * Implements Special:DeletedContributions to display archived revisions
  * @ingroup SpecialPage
@@ -44,8 +46,6 @@ class DeletedContributionsPage extends SpecialPage {
                $this->outputHeader();
                $this->checkPermissions();
 
-               $user = $this->getUser();
-
                $out = $this->getOutput();
                $out->setPageTitle( $this->msg( 'deletedcontributions-title' ) );
 
@@ -162,7 +162,8 @@ class DeletedContributionsPage extends SpecialPage {
                        $block = Block::newFromTarget( $userObj, $userObj );
                        if ( !is_null( $block ) && $block->getType() != Block::TYPE_AUTO ) {
                                if ( $block->getType() == Block::TYPE_RANGE ) {
-                                       $nt = MWNamespace::getCanonicalName( NS_USER ) . ':' . $block->getTarget();
+                                       $nt = MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                               getCanonicalName( NS_USER ) . ':' . $block->getTarget();
                                }
 
                                // LogEventsList::showLogExtract() wants the first parameter by ref
index 6807ed3..ed398de 100644 (file)
@@ -68,8 +68,10 @@ class SpecialEditTags extends UnlistedSpecialPage {
                $request = $this->getRequest();
 
                // Check blocks
-               if ( $user->isBlocked() ) {
-                       throw new UserBlockedError( $user->getBlock() );
+               // @TODO Use PermissionManager::isBlockedFrom() instead.
+               $block = $user->getBlock();
+               if ( $block ) {
+                       throw new UserBlockedError( $block );
                }
 
                $this->setHeaders();
@@ -209,8 +211,6 @@ class SpecialEditTags extends UnlistedSpecialPage {
         * the user to modify the tags applied to those items.
         */
        protected function showForm() {
-               $userAllowed = true;
-
                $out = $this->getOutput();
                // Messages: tags-edit-revision-selected, tags-edit-logentry-selected
                $out->wrapWikiMsg( "<strong>$1</strong>", [
index b05c81a..480e81a 100644 (file)
@@ -380,8 +380,9 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
         */
        protected function getWatchlistInfo() {
                $titles = [];
+               $services = MediaWikiServices::getInstance();
 
-               $watchedItems = MediaWikiServices::getInstance()->getWatchedItemStore()
+               $watchedItems = $services->getWatchedItemStore()
                        ->getWatchedItemsForUser( $this->getUser(), [ 'sort' => WatchedItemStore::SORT_ASC ] );
 
                $lb = new LinkBatch();
@@ -390,7 +391,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
                        $namespace = $watchedItem->getLinkTarget()->getNamespace();
                        $dbKey = $watchedItem->getLinkTarget()->getDBkey();
                        $lb->add( $namespace, $dbKey );
-                       if ( !MWNamespace::isTalk( $namespace ) ) {
+                       if ( !$services->getNamespaceInfo()->isTalk( $namespace ) ) {
                                $titles[$namespace][$dbKey] = 1;
                        }
                }
@@ -511,6 +512,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
         */
        private function getExpandedTargets( array $targets ) {
                $expandedTargets = [];
+               $services = MediaWikiServices::getInstance();
                foreach ( $targets as $target ) {
                        if ( !$target instanceof LinkTarget ) {
                                try {
@@ -523,8 +525,10 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
 
                        $ns = $target->getNamespace();
                        $dbKey = $target->getDBkey();
-                       $expandedTargets[] = new TitleValue( MWNamespace::getSubject( $ns ), $dbKey );
-                       $expandedTargets[] = new TitleValue( MWNamespace::getTalk( $ns ), $dbKey );
+                       $expandedTargets[] =
+                               new TitleValue( $services->getNamespaceInfo()->getSubject( $ns ), $dbKey );
+                       $expandedTargets[] =
+                               new TitleValue( $services->getNamespaceInfo()->getTalk( $ns ), $dbKey );
                }
                return $expandedTargets;
        }
diff --git a/includes/specials/SpecialEmailUser.php b/includes/specials/SpecialEmailUser.php
new file mode 100644 (file)
index 0000000..5f80215
--- /dev/null
@@ -0,0 +1,533 @@
+<?php
+/**
+ * Implements Special:Emailuser
+ *
+ * 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 MediaWiki\Preferences\MultiUsernameFilter;
+
+/**
+ * A special page that allows users to send e-mails to other users
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialEmailUser extends UnlistedSpecialPage {
+       protected $mTarget;
+
+       /**
+        * @var User|string $mTargetObj
+        */
+       protected $mTargetObj;
+
+       public function __construct() {
+               parent::__construct( 'Emailuser' );
+       }
+
+       public function doesWrites() {
+               return true;
+       }
+
+       public function getDescription() {
+               $target = self::getTarget( $this->mTarget, $this->getUser() );
+               if ( !$target instanceof User ) {
+                       return $this->msg( 'emailuser-title-notarget' )->text();
+               }
+
+               return $this->msg( 'emailuser-title-target', $target->getName() )->text();
+       }
+
+       protected function getFormFields() {
+               $linkRenderer = $this->getLinkRenderer();
+               return [
+                       'From' => [
+                               'type' => 'info',
+                               'raw' => 1,
+                               'default' => $linkRenderer->makeLink(
+                                       $this->getUser()->getUserPage(),
+                                       $this->getUser()->getName()
+                               ),
+                               'label-message' => 'emailfrom',
+                               'id' => 'mw-emailuser-sender',
+                       ],
+                       'To' => [
+                               'type' => 'info',
+                               'raw' => 1,
+                               'default' => $linkRenderer->makeLink(
+                                       $this->mTargetObj->getUserPage(),
+                                       $this->mTargetObj->getName()
+                               ),
+                               'label-message' => 'emailto',
+                               'id' => 'mw-emailuser-recipient',
+                       ],
+                       'Target' => [
+                               'type' => 'hidden',
+                               'default' => $this->mTargetObj->getName(),
+                       ],
+                       'Subject' => [
+                               'type' => 'text',
+                               'default' => $this->msg( 'defemailsubject',
+                                       $this->getUser()->getName() )->inContentLanguage()->text(),
+                               'label-message' => 'emailsubject',
+                               'maxlength' => 200,
+                               'size' => 60,
+                               'required' => true,
+                       ],
+                       'Text' => [
+                               'type' => 'textarea',
+                               'rows' => 20,
+                               'label-message' => 'emailmessage',
+                               'required' => true,
+                       ],
+                       'CCMe' => [
+                               'type' => 'check',
+                               'label-message' => 'emailccme',
+                               'default' => $this->getUser()->getBoolOption( 'ccmeonemails' ),
+                       ],
+               ];
+       }
+
+       public function execute( $par ) {
+               $out = $this->getOutput();
+               $request = $this->getRequest();
+               $out->addModuleStyles( 'mediawiki.special' );
+
+               $this->mTarget = $par ?? $request->getVal( 'wpTarget', $request->getVal( 'target', '' ) );
+
+               // Make sure, that HTMLForm uses the correct target.
+               $request->setVal( 'wpTarget', $this->mTarget );
+
+               // This needs to be below assignment of $this->mTarget because
+               // getDescription() needs it to determine the correct page title.
+               $this->setHeaders();
+               $this->outputHeader();
+
+               // error out if sending user cannot do this
+               $error = self::getPermissionsError(
+                       $this->getUser(),
+                       $this->getRequest()->getVal( 'wpEditToken' ),
+                       $this->getConfig()
+               );
+
+               switch ( $error ) {
+                       case null:
+                               # Wahey!
+                               break;
+                       case 'badaccess':
+                               throw new PermissionsError( 'sendemail' );
+                       case 'blockedemailuser':
+                               throw $this->getBlockedEmailError();
+                       case 'actionthrottledtext':
+                               throw new ThrottledError;
+                       case 'mailnologin':
+                       case 'usermaildisabled':
+                               throw new ErrorPageError( $error, "{$error}text" );
+                       default:
+                               # It's a hook error
+                               list( $title, $msg, $params ) = $error;
+                               throw new ErrorPageError( $title, $msg, $params );
+               }
+
+               // Make sure, that a submitted form isn't submitted to a subpage (which could be
+               // a non-existing username)
+               $context = new DerivativeContext( $this->getContext() );
+               $context->setTitle( $this->getPageTitle() ); // Remove subpage
+               $this->setContext( $context );
+
+               // A little hack: HTMLForm will check $this->mTarget only, if the form was posted, not
+               // if the user opens Special:EmailUser/Florian (e.g.). So check, if the user did that
+               // and show the "Send email to user" form directly, if so. Show the "enter username"
+               // form, otherwise.
+               $this->mTargetObj = self::getTarget( $this->mTarget, $this->getUser() );
+               if ( !$this->mTargetObj instanceof User ) {
+                       $this->userForm( $this->mTarget );
+               } else {
+                       $this->sendEmailForm();
+               }
+       }
+
+       /**
+        * Validate target User
+        *
+        * @param string $target Target user name
+        * @param User|null $sender User sending the email
+        * @return User|string User object on success or a string on error
+        */
+       public static function getTarget( $target, User $sender = null ) {
+               if ( $sender === null ) {
+                       wfDeprecated( __METHOD__ . ' without specifying the sending user', '1.30' );
+               }
+
+               if ( $target == '' ) {
+                       wfDebug( "Target is empty.\n" );
+
+                       return 'notarget';
+               }
+
+               $nu = User::newFromName( $target );
+               $error = self::validateTarget( $nu, $sender );
+
+               return $error ?: $nu;
+       }
+
+       /**
+        * Validate target User
+        *
+        * @param User $target Target user
+        * @param User|null $sender User sending the email
+        * @return string Error message or empty string if valid.
+        * @since 1.30
+        */
+       public static function validateTarget( $target, User $sender = null ) {
+               if ( $sender === null ) {
+                       wfDeprecated( __METHOD__ . ' without specifying the sending user', '1.30' );
+               }
+
+               if ( !$target instanceof User || !$target->getId() ) {
+                       wfDebug( "Target is invalid user.\n" );
+
+                       return 'notarget';
+               }
+
+               if ( !$target->isEmailConfirmed() ) {
+                       wfDebug( "User has no valid email.\n" );
+
+                       return 'noemail';
+               }
+
+               if ( !$target->canReceiveEmail() ) {
+                       wfDebug( "User does not allow user emails.\n" );
+
+                       return 'nowikiemail';
+               }
+
+               if ( $sender !== null && !$target->getOption( 'email-allow-new-users' ) &&
+                       $sender->isNewbie()
+               ) {
+                       wfDebug( "User does not allow user emails from new users.\n" );
+
+                       return 'nowikiemail';
+               }
+
+               if ( $sender !== null ) {
+                       $blacklist = $target->getOption( 'email-blacklist', '' );
+                       if ( $blacklist ) {
+                               $blacklist = MultiUsernameFilter::splitIds( $blacklist );
+                               $lookup = CentralIdLookup::factory();
+                               $senderId = $lookup->centralIdFromLocalUser( $sender );
+                               if ( $senderId !== 0 && in_array( $senderId, $blacklist ) ) {
+                                       wfDebug( "User does not allow user emails from this user.\n" );
+
+                                       return 'nowikiemail';
+                               }
+                       }
+               }
+
+               return '';
+       }
+
+       /**
+        * Check whether a user is allowed to send email
+        *
+        * @param User $user
+        * @param string $editToken Edit token
+        * @param Config|null $config optional for backwards compatibility
+        * @return null|string|array Null on success, string on error, or array on
+        *  hook error
+        */
+       public static function getPermissionsError( $user, $editToken, Config $config = null ) {
+               if ( $config === null ) {
+                       wfDebug( __METHOD__ . ' called without a Config instance passed to it' );
+                       $config = MediaWikiServices::getInstance()->getMainConfig();
+               }
+               if ( !$config->get( 'EnableEmail' ) || !$config->get( 'EnableUserEmail' ) ) {
+                       return 'usermaildisabled';
+               }
+
+               // Run this before $user->isAllowed, to show appropriate message to anons (T160309)
+               if ( !$user->isEmailConfirmed() ) {
+                       return 'mailnologin';
+               }
+
+               if ( !$user->isAllowed( 'sendemail' ) ) {
+                       return 'badaccess';
+               }
+
+               if ( $user->isBlockedFromEmailuser() ) {
+                       wfDebug( "User is blocked from sending e-mail.\n" );
+
+                       return "blockedemailuser";
+               }
+
+               // Check the ping limiter without incrementing it - we'll check it
+               // again later and increment it on a successful send
+               if ( $user->pingLimiter( 'emailuser', 0 ) ) {
+                       wfDebug( "Ping limiter triggered.\n" );
+
+                       return 'actionthrottledtext';
+               }
+
+               $hookErr = false;
+
+               Hooks::run( 'UserCanSendEmail', [ &$user, &$hookErr ] );
+               Hooks::run( 'EmailUserPermissionsErrors', [ $user, $editToken, &$hookErr ] );
+
+               if ( $hookErr ) {
+                       return $hookErr;
+               }
+
+               return null;
+       }
+
+       /**
+        * Form to ask for target user name.
+        *
+        * @param string $name User name submitted.
+        */
+       protected function userForm( $name ) {
+               $htmlForm = HTMLForm::factory( 'ooui', [
+                       'Target' => [
+                               'type' => 'user',
+                               'exists' => true,
+                               'label' => $this->msg( 'emailusername' )->text(),
+                               'id' => 'emailusertarget',
+                               'autofocus' => true,
+                               'value' => $name,
+                       ]
+               ], $this->getContext() );
+
+               $htmlForm
+                       ->setMethod( 'post' )
+                       ->setSubmitCallback( [ $this, 'sendEmailForm' ] )
+                       ->setFormIdentifier( 'userForm' )
+                       ->setId( 'askusername' )
+                       ->setWrapperLegendMsg( 'emailtarget' )
+                       ->setSubmitTextMsg( 'emailusernamesubmit' )
+                       ->show();
+       }
+
+       public function sendEmailForm() {
+               $out = $this->getOutput();
+
+               $ret = $this->mTargetObj;
+               if ( !$ret instanceof User ) {
+                       if ( $this->mTarget != '' ) {
+                               // Messages used here: notargettext, noemailtext, nowikiemailtext
+                               $ret = ( $ret == 'notarget' ) ? 'emailnotarget' : ( $ret . 'text' );
+                               return Status::newFatal( $ret );
+                       }
+                       return false;
+               }
+
+               $htmlForm = HTMLForm::factory( 'ooui', $this->getFormFields(), $this->getContext() );
+               // By now we are supposed to be sure that $this->mTarget is a user name
+               $htmlForm
+                       ->addPreText( $this->msg( 'emailpagetext', $this->mTarget )->parse() )
+                       ->setSubmitTextMsg( 'emailsend' )
+                       ->setSubmitCallback( [ __CLASS__, 'submit' ] )
+                       ->setFormIdentifier( 'sendEmailForm' )
+                       ->setWrapperLegendMsg( 'email-legend' )
+                       ->loadData();
+
+               if ( !Hooks::run( 'EmailUserForm', [ &$htmlForm ] ) ) {
+                       return false;
+               }
+
+               $result = $htmlForm->show();
+
+               if ( $result === true || ( $result instanceof Status && $result->isGood() ) ) {
+                       $out->setPageTitle( $this->msg( 'emailsent' ) );
+                       $out->addWikiMsg( 'emailsenttext', $this->mTarget );
+                       $out->returnToMain( false, $ret->getUserPage() );
+               }
+               return true;
+       }
+
+       /**
+        * Really send a mail. Permissions should have been checked using
+        * getPermissionsError(). It is probably also a good
+        * idea to check the edit token and ping limiter in advance.
+        *
+        * @param array $data
+        * @param IContextSource $context
+        * @return Status|bool
+        */
+       public static function submit( array $data, IContextSource $context ) {
+               $config = $context->getConfig();
+
+               $target = self::getTarget( $data['Target'], $context->getUser() );
+               if ( !$target instanceof User ) {
+                       // Messages used here: notargettext, noemailtext, nowikiemailtext
+                       return Status::newFatal( $target . 'text' );
+               }
+
+               $to = MailAddress::newFromUser( $target );
+               $from = MailAddress::newFromUser( $context->getUser() );
+               $subject = $data['Subject'];
+               $text = $data['Text'];
+
+               // Add a standard footer and trim up trailing newlines
+               $text = rtrim( $text ) . "\n\n-- \n";
+               $text .= $context->msg( 'emailuserfooter',
+                       $from->name, $to->name )->inContentLanguage()->text();
+
+               // Check and increment the rate limits
+               if ( $context->getUser()->pingLimiter( 'emailuser' ) ) {
+                       throw new ThrottledError();
+               }
+
+               $error = false;
+               if ( !Hooks::run( 'EmailUser', [ &$to, &$from, &$subject, &$text, &$error ] ) ) {
+                       if ( $error instanceof Status ) {
+                               return $error;
+                       } elseif ( $error === false || $error === '' || $error === [] ) {
+                               // Possibly to tell HTMLForm to pretend there was no submission?
+                               return false;
+                       } elseif ( $error === true ) {
+                               // Hook sent the mail itself and indicates success?
+                               return Status::newGood();
+                       } elseif ( is_array( $error ) ) {
+                               $status = Status::newGood();
+                               foreach ( $error as $e ) {
+                                       $status->fatal( $e );
+                               }
+                               return $status;
+                       } elseif ( $error instanceof MessageSpecifier ) {
+                               return Status::newFatal( $error );
+                       } else {
+                               // Ugh. Either a raw HTML string, or something that's supposed
+                               // to be treated like one.
+                               $type = is_object( $error ) ? get_class( $error ) : gettype( $error );
+                               wfDeprecated( "EmailUser hook returning a $type as \$error", '1.29' );
+                               return Status::newFatal( new ApiRawMessage(
+                                       [ '$1', Message::rawParam( (string)$error ) ], 'hookaborted'
+                               ) );
+                       }
+               }
+
+               if ( $config->get( 'UserEmailUseReplyTo' ) ) {
+                       /**
+                        * Put the generic wiki autogenerated address in the From:
+                        * header and reserve the user for Reply-To.
+                        *
+                        * This is a bit ugly, but will serve to differentiate
+                        * wiki-borne mails from direct mails and protects against
+                        * SPF and bounce problems with some mailers (see below).
+                        */
+                       $mailFrom = new MailAddress( $config->get( 'PasswordSender' ),
+                               $context->msg( 'emailsender' )->inContentLanguage()->text() );
+                       $replyTo = $from;
+               } else {
+                       /**
+                        * Put the sending user's e-mail address in the From: header.
+                        *
+                        * This is clean-looking and convenient, but has issues.
+                        * One is that it doesn't as clearly differentiate the wiki mail
+                        * from "directly" sent mails.
+                        *
+                        * Another is that some mailers (like sSMTP) will use the From
+                        * address as the envelope sender as well. For open sites this
+                        * can cause mails to be flunked for SPF violations (since the
+                        * wiki server isn't an authorized sender for various users'
+                        * domains) as well as creating a privacy issue as bounces
+                        * containing the recipient's e-mail address may get sent to
+                        * the sending user.
+                        */
+                       $mailFrom = $from;
+                       $replyTo = null;
+               }
+
+               $status = UserMailer::send( $to, $mailFrom, $subject, $text, [
+                       'replyTo' => $replyTo,
+               ] );
+
+               if ( !$status->isGood() ) {
+                       return $status;
+               } else {
+                       // if the user requested a copy of this mail, do this now,
+                       // unless they are emailing themselves, in which case one
+                       // copy of the message is sufficient.
+                       if ( $data['CCMe'] && $to != $from ) {
+                               $ccTo = $from;
+                               $ccFrom = $from;
+                               $ccSubject = $context->msg( 'emailccsubject' )->plaintextParams(
+                                       $target->getName(), $subject )->text();
+                               $ccText = $text;
+
+                               Hooks::run( 'EmailUserCC', [ &$ccTo, &$ccFrom, &$ccSubject, &$ccText ] );
+
+                               if ( $config->get( 'UserEmailUseReplyTo' ) ) {
+                                       $mailFrom = new MailAddress(
+                                               $config->get( 'PasswordSender' ),
+                                               $context->msg( 'emailsender' )->inContentLanguage()->text()
+                                       );
+                                       $replyTo = $ccFrom;
+                               } else {
+                                       $mailFrom = $ccFrom;
+                                       $replyTo = null;
+                               }
+
+                               $ccStatus = UserMailer::send(
+                                       $ccTo, $mailFrom, $ccSubject, $ccText, [
+                                               'replyTo' => $replyTo,
+                               ] );
+                               $status->merge( $ccStatus );
+                       }
+
+                       Hooks::run( 'EmailUserComplete', [ $to, $from, $subject, $text ] );
+
+                       return $status;
+               }
+       }
+
+       /**
+        * Return an array of subpages beginning with $search that this special page will accept.
+        *
+        * @param string $search Prefix to search for
+        * @param int $limit Maximum number of results to return (usually 10)
+        * @param int $offset Number of results to skip (usually 0)
+        * @return string[] Matching subpages
+        */
+       public function prefixSearchSubpages( $search, $limit, $offset ) {
+               $user = User::newFromName( $search );
+               if ( !$user ) {
+                       // No prefix suggestion for invalid user
+                       return [];
+               }
+               // Autocomplete subpage as user list - public to allow caching
+               return UserNamePrefixSearch::search( 'public', $search, $limit, $offset );
+       }
+
+       protected function getGroupName() {
+               return 'users';
+       }
+
+       /**
+        * Builds an error message based on the block params
+        *
+        * @return ErrorPageError
+        */
+       private function getBlockedEmailError() {
+               $block = $this->getUser()->mBlock;
+               $params = $block->getBlockErrorParams( $this->getContext() );
+
+               $msg = $block->isSitewide() ? 'blockedtext' : 'blocked-email-user';
+               return new ErrorPageError( 'blockedtitle', $msg, $params );
+       }
+}
diff --git a/includes/specials/SpecialEmailuser.php b/includes/specials/SpecialEmailuser.php
deleted file mode 100644 (file)
index 887f905..0000000
+++ /dev/null
@@ -1,533 +0,0 @@
-<?php
-/**
- * Implements Special:Emailuser
- *
- * 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 MediaWiki\Preferences\MultiUsernameFilter;
-
-/**
- * A special page that allows users to send e-mails to other users
- *
- * @ingroup SpecialPage
- */
-class SpecialEmailUser extends UnlistedSpecialPage {
-       protected $mTarget;
-
-       /**
-        * @var User|string $mTargetObj
-        */
-       protected $mTargetObj;
-
-       public function __construct() {
-               parent::__construct( 'Emailuser' );
-       }
-
-       public function doesWrites() {
-               return true;
-       }
-
-       public function getDescription() {
-               $target = self::getTarget( $this->mTarget, $this->getUser() );
-               if ( !$target instanceof User ) {
-                       return $this->msg( 'emailuser-title-notarget' )->text();
-               }
-
-               return $this->msg( 'emailuser-title-target', $target->getName() )->text();
-       }
-
-       protected function getFormFields() {
-               $linkRenderer = $this->getLinkRenderer();
-               return [
-                       'From' => [
-                               'type' => 'info',
-                               'raw' => 1,
-                               'default' => $linkRenderer->makeLink(
-                                       $this->getUser()->getUserPage(),
-                                       $this->getUser()->getName()
-                               ),
-                               'label-message' => 'emailfrom',
-                               'id' => 'mw-emailuser-sender',
-                       ],
-                       'To' => [
-                               'type' => 'info',
-                               'raw' => 1,
-                               'default' => $linkRenderer->makeLink(
-                                       $this->mTargetObj->getUserPage(),
-                                       $this->mTargetObj->getName()
-                               ),
-                               'label-message' => 'emailto',
-                               'id' => 'mw-emailuser-recipient',
-                       ],
-                       'Target' => [
-                               'type' => 'hidden',
-                               'default' => $this->mTargetObj->getName(),
-                       ],
-                       'Subject' => [
-                               'type' => 'text',
-                               'default' => $this->msg( 'defemailsubject',
-                                       $this->getUser()->getName() )->inContentLanguage()->text(),
-                               'label-message' => 'emailsubject',
-                               'maxlength' => 200,
-                               'size' => 60,
-                               'required' => true,
-                       ],
-                       'Text' => [
-                               'type' => 'textarea',
-                               'rows' => 20,
-                               'label-message' => 'emailmessage',
-                               'required' => true,
-                       ],
-                       'CCMe' => [
-                               'type' => 'check',
-                               'label-message' => 'emailccme',
-                               'default' => $this->getUser()->getBoolOption( 'ccmeonemails' ),
-                       ],
-               ];
-       }
-
-       public function execute( $par ) {
-               $out = $this->getOutput();
-               $request = $this->getRequest();
-               $out->addModuleStyles( 'mediawiki.special' );
-
-               $this->mTarget = $par ?? $request->getVal( 'wpTarget', $request->getVal( 'target', '' ) );
-
-               // Make sure, that HTMLForm uses the correct target.
-               $request->setVal( 'wpTarget', $this->mTarget );
-
-               // This needs to be below assignment of $this->mTarget because
-               // getDescription() needs it to determine the correct page title.
-               $this->setHeaders();
-               $this->outputHeader();
-
-               // error out if sending user cannot do this
-               $error = self::getPermissionsError(
-                       $this->getUser(),
-                       $this->getRequest()->getVal( 'wpEditToken' ),
-                       $this->getConfig()
-               );
-
-               switch ( $error ) {
-                       case null:
-                               # Wahey!
-                               break;
-                       case 'badaccess':
-                               throw new PermissionsError( 'sendemail' );
-                       case 'blockedemailuser':
-                               throw $this->getBlockedEmailError();
-                       case 'actionthrottledtext':
-                               throw new ThrottledError;
-                       case 'mailnologin':
-                       case 'usermaildisabled':
-                               throw new ErrorPageError( $error, "{$error}text" );
-                       default:
-                               # It's a hook error
-                               list( $title, $msg, $params ) = $error;
-                               throw new ErrorPageError( $title, $msg, $params );
-               }
-
-               // Make sure, that a submitted form isn't submitted to a subpage (which could be
-               // a non-existing username)
-               $context = new DerivativeContext( $this->getContext() );
-               $context->setTitle( $this->getPageTitle() ); // Remove subpage
-               $this->setContext( $context );
-
-               // A little hack: HTMLForm will check $this->mTarget only, if the form was posted, not
-               // if the user opens Special:EmailUser/Florian (e.g.). So check, if the user did that
-               // and show the "Send email to user" form directly, if so. Show the "enter username"
-               // form, otherwise.
-               $this->mTargetObj = self::getTarget( $this->mTarget, $this->getUser() );
-               if ( !$this->mTargetObj instanceof User ) {
-                       $this->userForm( $this->mTarget );
-               } else {
-                       $this->sendEmailForm();
-               }
-       }
-
-       /**
-        * Validate target User
-        *
-        * @param string $target Target user name
-        * @param User|null $sender User sending the email
-        * @return User|string User object on success or a string on error
-        */
-       public static function getTarget( $target, User $sender = null ) {
-               if ( $sender === null ) {
-                       wfDeprecated( __METHOD__ . ' without specifying the sending user', '1.30' );
-               }
-
-               if ( $target == '' ) {
-                       wfDebug( "Target is empty.\n" );
-
-                       return 'notarget';
-               }
-
-               $nu = User::newFromName( $target );
-               $error = self::validateTarget( $nu, $sender );
-
-               return $error ?: $nu;
-       }
-
-       /**
-        * Validate target User
-        *
-        * @param User $target Target user
-        * @param User|null $sender User sending the email
-        * @return string Error message or empty string if valid.
-        * @since 1.30
-        */
-       public static function validateTarget( $target, User $sender = null ) {
-               if ( $sender === null ) {
-                       wfDeprecated( __METHOD__ . ' without specifying the sending user', '1.30' );
-               }
-
-               if ( !$target instanceof User || !$target->getId() ) {
-                       wfDebug( "Target is invalid user.\n" );
-
-                       return 'notarget';
-               }
-
-               if ( !$target->isEmailConfirmed() ) {
-                       wfDebug( "User has no valid email.\n" );
-
-                       return 'noemail';
-               }
-
-               if ( !$target->canReceiveEmail() ) {
-                       wfDebug( "User does not allow user emails.\n" );
-
-                       return 'nowikiemail';
-               }
-
-               if ( $sender !== null && !$target->getOption( 'email-allow-new-users' ) &&
-                       $sender->isNewbie()
-               ) {
-                       wfDebug( "User does not allow user emails from new users.\n" );
-
-                       return 'nowikiemail';
-               }
-
-               if ( $sender !== null ) {
-                       $blacklist = $target->getOption( 'email-blacklist', '' );
-                       if ( $blacklist ) {
-                               $blacklist = MultiUsernameFilter::splitIds( $blacklist );
-                               $lookup = CentralIdLookup::factory();
-                               $senderId = $lookup->centralIdFromLocalUser( $sender );
-                               if ( $senderId !== 0 && in_array( $senderId, $blacklist ) ) {
-                                       wfDebug( "User does not allow user emails from this user.\n" );
-
-                                       return 'nowikiemail';
-                               }
-                       }
-               }
-
-               return '';
-       }
-
-       /**
-        * Check whether a user is allowed to send email
-        *
-        * @param User $user
-        * @param string $editToken Edit token
-        * @param Config|null $config optional for backwards compatibility
-        * @return string|null Null on success or string on error
-        */
-       public static function getPermissionsError( $user, $editToken, Config $config = null ) {
-               if ( $config === null ) {
-                       wfDebug( __METHOD__ . ' called without a Config instance passed to it' );
-                       $config = MediaWikiServices::getInstance()->getMainConfig();
-               }
-               if ( !$config->get( 'EnableEmail' ) || !$config->get( 'EnableUserEmail' ) ) {
-                       return 'usermaildisabled';
-               }
-
-               // Run this before $user->isAllowed, to show appropriate message to anons (T160309)
-               if ( !$user->isEmailConfirmed() ) {
-                       return 'mailnologin';
-               }
-
-               if ( !$user->isAllowed( 'sendemail' ) ) {
-                       return 'badaccess';
-               }
-
-               if ( $user->isBlockedFromEmailuser() ) {
-                       wfDebug( "User is blocked from sending e-mail.\n" );
-
-                       return "blockedemailuser";
-               }
-
-               // Check the ping limiter without incrementing it - we'll check it
-               // again later and increment it on a successful send
-               if ( $user->pingLimiter( 'emailuser', 0 ) ) {
-                       wfDebug( "Ping limiter triggered.\n" );
-
-                       return 'actionthrottledtext';
-               }
-
-               $hookErr = false;
-
-               Hooks::run( 'UserCanSendEmail', [ &$user, &$hookErr ] );
-               Hooks::run( 'EmailUserPermissionsErrors', [ $user, $editToken, &$hookErr ] );
-
-               if ( $hookErr ) {
-                       return $hookErr;
-               }
-
-               return null;
-       }
-
-       /**
-        * Form to ask for target user name.
-        *
-        * @param string $name User name submitted.
-        * @return string Form asking for user name.
-        */
-       protected function userForm( $name ) {
-               $htmlForm = HTMLForm::factory( 'ooui', [
-                       'Target' => [
-                               'type' => 'user',
-                               'exists' => true,
-                               'label' => $this->msg( 'emailusername' )->text(),
-                               'id' => 'emailusertarget',
-                               'autofocus' => true,
-                               'value' => $name,
-                       ]
-               ], $this->getContext() );
-
-               $htmlForm
-                       ->setMethod( 'post' )
-                       ->setSubmitCallback( [ $this, 'sendEmailForm' ] )
-                       ->setFormIdentifier( 'userForm' )
-                       ->setId( 'askusername' )
-                       ->setWrapperLegendMsg( 'emailtarget' )
-                       ->setSubmitTextMsg( 'emailusernamesubmit' )
-                       ->show();
-       }
-
-       public function sendEmailForm() {
-               $out = $this->getOutput();
-
-               $ret = $this->mTargetObj;
-               if ( !$ret instanceof User ) {
-                       if ( $this->mTarget != '' ) {
-                               // Messages used here: notargettext, noemailtext, nowikiemailtext
-                               $ret = ( $ret == 'notarget' ) ? 'emailnotarget' : ( $ret . 'text' );
-                               return Status::newFatal( $ret );
-                       }
-                       return false;
-               }
-
-               $htmlForm = HTMLForm::factory( 'ooui', $this->getFormFields(), $this->getContext() );
-               // By now we are supposed to be sure that $this->mTarget is a user name
-               $htmlForm
-                       ->addPreText( $this->msg( 'emailpagetext', $this->mTarget )->parse() )
-                       ->setSubmitTextMsg( 'emailsend' )
-                       ->setSubmitCallback( [ __CLASS__, 'submit' ] )
-                       ->setFormIdentifier( 'sendEmailForm' )
-                       ->setWrapperLegendMsg( 'email-legend' )
-                       ->loadData();
-
-               if ( !Hooks::run( 'EmailUserForm', [ &$htmlForm ] ) ) {
-                       return false;
-               }
-
-               $result = $htmlForm->show();
-
-               if ( $result === true || ( $result instanceof Status && $result->isGood() ) ) {
-                       $out->setPageTitle( $this->msg( 'emailsent' ) );
-                       $out->addWikiMsg( 'emailsenttext', $this->mTarget );
-                       $out->returnToMain( false, $ret->getUserPage() );
-               }
-               return true;
-       }
-
-       /**
-        * Really send a mail. Permissions should have been checked using
-        * getPermissionsError(). It is probably also a good
-        * idea to check the edit token and ping limiter in advance.
-        *
-        * @param array $data
-        * @param IContextSource $context
-        * @return Status|bool
-        */
-       public static function submit( array $data, IContextSource $context ) {
-               $config = $context->getConfig();
-
-               $target = self::getTarget( $data['Target'], $context->getUser() );
-               if ( !$target instanceof User ) {
-                       // Messages used here: notargettext, noemailtext, nowikiemailtext
-                       return Status::newFatal( $target . 'text' );
-               }
-
-               $to = MailAddress::newFromUser( $target );
-               $from = MailAddress::newFromUser( $context->getUser() );
-               $subject = $data['Subject'];
-               $text = $data['Text'];
-
-               // Add a standard footer and trim up trailing newlines
-               $text = rtrim( $text ) . "\n\n-- \n";
-               $text .= $context->msg( 'emailuserfooter',
-                       $from->name, $to->name )->inContentLanguage()->text();
-
-               // Check and increment the rate limits
-               if ( $context->getUser()->pingLimiter( 'emailuser' ) ) {
-                       throw new ThrottledError();
-               }
-
-               $error = false;
-               if ( !Hooks::run( 'EmailUser', [ &$to, &$from, &$subject, &$text, &$error ] ) ) {
-                       if ( $error instanceof Status ) {
-                               return $error;
-                       } elseif ( $error === false || $error === '' || $error === [] ) {
-                               // Possibly to tell HTMLForm to pretend there was no submission?
-                               return false;
-                       } elseif ( $error === true ) {
-                               // Hook sent the mail itself and indicates success?
-                               return Status::newGood();
-                       } elseif ( is_array( $error ) ) {
-                               $status = Status::newGood();
-                               foreach ( $error as $e ) {
-                                       $status->fatal( $e );
-                               }
-                               return $status;
-                       } elseif ( $error instanceof MessageSpecifier ) {
-                               return Status::newFatal( $error );
-                       } else {
-                               // Ugh. Either a raw HTML string, or something that's supposed
-                               // to be treated like one.
-                               $type = is_object( $error ) ? get_class( $error ) : gettype( $error );
-                               wfDeprecated( "EmailUser hook returning a $type as \$error", '1.29' );
-                               return Status::newFatal( new ApiRawMessage(
-                                       [ '$1', Message::rawParam( (string)$error ) ], 'hookaborted'
-                               ) );
-                       }
-               }
-
-               if ( $config->get( 'UserEmailUseReplyTo' ) ) {
-                       /**
-                        * Put the generic wiki autogenerated address in the From:
-                        * header and reserve the user for Reply-To.
-                        *
-                        * This is a bit ugly, but will serve to differentiate
-                        * wiki-borne mails from direct mails and protects against
-                        * SPF and bounce problems with some mailers (see below).
-                        */
-                       $mailFrom = new MailAddress( $config->get( 'PasswordSender' ),
-                               $context->msg( 'emailsender' )->inContentLanguage()->text() );
-                       $replyTo = $from;
-               } else {
-                       /**
-                        * Put the sending user's e-mail address in the From: header.
-                        *
-                        * This is clean-looking and convenient, but has issues.
-                        * One is that it doesn't as clearly differentiate the wiki mail
-                        * from "directly" sent mails.
-                        *
-                        * Another is that some mailers (like sSMTP) will use the From
-                        * address as the envelope sender as well. For open sites this
-                        * can cause mails to be flunked for SPF violations (since the
-                        * wiki server isn't an authorized sender for various users'
-                        * domains) as well as creating a privacy issue as bounces
-                        * containing the recipient's e-mail address may get sent to
-                        * the sending user.
-                        */
-                       $mailFrom = $from;
-                       $replyTo = null;
-               }
-
-               $status = UserMailer::send( $to, $mailFrom, $subject, $text, [
-                       'replyTo' => $replyTo,
-               ] );
-
-               if ( !$status->isGood() ) {
-                       return $status;
-               } else {
-                       // if the user requested a copy of this mail, do this now,
-                       // unless they are emailing themselves, in which case one
-                       // copy of the message is sufficient.
-                       if ( $data['CCMe'] && $to != $from ) {
-                               $ccTo = $from;
-                               $ccFrom = $from;
-                               $ccSubject = $context->msg( 'emailccsubject' )->plaintextParams(
-                                       $target->getName(), $subject )->text();
-                               $ccText = $text;
-
-                               Hooks::run( 'EmailUserCC', [ &$ccTo, &$ccFrom, &$ccSubject, &$ccText ] );
-
-                               if ( $config->get( 'UserEmailUseReplyTo' ) ) {
-                                       $mailFrom = new MailAddress(
-                                               $config->get( 'PasswordSender' ),
-                                               $context->msg( 'emailsender' )->inContentLanguage()->text()
-                                       );
-                                       $replyTo = $ccFrom;
-                               } else {
-                                       $mailFrom = $ccFrom;
-                                       $replyTo = null;
-                               }
-
-                               $ccStatus = UserMailer::send(
-                                       $ccTo, $mailFrom, $ccSubject, $ccText, [
-                                               'replyTo' => $replyTo,
-                               ] );
-                               $status->merge( $ccStatus );
-                       }
-
-                       Hooks::run( 'EmailUserComplete', [ $to, $from, $subject, $text ] );
-
-                       return $status;
-               }
-       }
-
-       /**
-        * Return an array of subpages beginning with $search that this special page will accept.
-        *
-        * @param string $search Prefix to search for
-        * @param int $limit Maximum number of results to return (usually 10)
-        * @param int $offset Number of results to skip (usually 0)
-        * @return string[] Matching subpages
-        */
-       public function prefixSearchSubpages( $search, $limit, $offset ) {
-               $user = User::newFromName( $search );
-               if ( !$user ) {
-                       // No prefix suggestion for invalid user
-                       return [];
-               }
-               // Autocomplete subpage as user list - public to allow caching
-               return UserNamePrefixSearch::search( 'public', $search, $limit, $offset );
-       }
-
-       protected function getGroupName() {
-               return 'users';
-       }
-
-       /**
-        * Builds an error message based on the block params
-        *
-        * @return ErrorPageError
-        */
-       private function getBlockedEmailError() {
-               $block = $this->getUser()->mBlock;
-               $params = $block->getBlockErrorParams( $this->getContext() );
-
-               $msg = $block->isSitewide() ? 'blockedtext' : 'blocked-email-user';
-               return new ErrorPageError( 'blockedtitle', $msg, $params );
-       }
-}
index 619665b..ceba987 100644 (file)
@@ -21,6 +21,8 @@
  * @ingroup SpecialPage
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * A special page that expands submitted templates, parser functions,
  * and variables, allowing easier debugging of these.
@@ -53,8 +55,6 @@ class SpecialExpandTemplates extends SpecialPage {
         * @param string|null $subpage
         */
        function execute( $subpage ) {
-               global $wgParser;
-
                $this->setHeaders();
                $this->addHelpLink( 'Help:ExpandTemplates' );
 
@@ -77,9 +77,10 @@ class SpecialExpandTemplates extends SpecialPage {
                        $options->setTidy( true );
                        $options->setMaxIncludeSize( self::MAX_INCLUDE_SIZE );
 
+                       $parser = MediaWikiServices::getInstance()->getParser();
                        if ( $this->generateXML ) {
-                               $wgParser->startExternalParse( $title, $options, Parser::OT_PREPROCESS );
-                               $dom = $wgParser->preprocessToDom( $input );
+                               $parser->startExternalParse( $title, $options, Parser::OT_PREPROCESS );
+                               $dom = $parser->preprocessToDom( $input );
 
                                if ( method_exists( $dom, 'saveXML' ) ) {
                                        $xml = $dom->saveXML();
@@ -88,7 +89,7 @@ class SpecialExpandTemplates extends SpecialPage {
                                }
                        }
 
-                       $output = $wgParser->preprocess( $input, $title, $options );
+                       $output = $parser->preprocess( $input, $title, $options );
                } else {
                        $this->removeComments = $request->getBool( 'wpRemoveComments', true );
                        $this->removeNowiki = $request->getBool( 'wpRemoveNowiki', false );
@@ -154,7 +155,6 @@ class SpecialExpandTemplates extends SpecialPage {
         *
         * @param string $title Value for context title field
         * @param string $input Value for input textbox
-        * @return string
         */
        private function makeForm( $title, $input ) {
                $fields = [
@@ -247,11 +247,9 @@ class SpecialExpandTemplates extends SpecialPage {
         * @return ParserOutput
         */
        private function generateHtml( Title $title, $text ) {
-               global $wgParser;
-
                $popts = ParserOptions::newFromContext( $this->getContext() );
                $popts->setTargetLanguage( $title->getPageLanguage() );
-               return $wgParser->parse( $text, $title, $popts );
+               return MediaWikiServices::getInstance()->getParser()->parse( $text, $title, $popts );
        }
 
        /**
index 84454e2..c47d87b 100644 (file)
@@ -52,7 +52,8 @@ class FewestrevisionsPage extends QueryPage {
                                'redirect' => 'page_is_redirect'
                        ],
                        'conds' => [
-                               'page_namespace' => MWNamespace::getContentNamespaces(),
+                               'page_namespace' => MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                       getContentNamespaces(),
                                'page_id = rev_page' ],
                        'options' => [
                                'GROUP BY' => [ 'page_namespace', 'page_title', 'page_is_redirect' ]
index a985bcc..c3aec83 100644 (file)
@@ -24,6 +24,8 @@
  * @ingroup SpecialPage
  */
 
+use MediaWiki\Permissions\PermissionManager;
+
 /**
  * MediaWiki page data importer
  *
@@ -83,11 +85,11 @@ class SpecialImport extends SpecialPage {
                # getUserPermissionsErrors() might actually be used for, hence the 'ns-specialprotected'
                $errors = wfMergeErrorArrays(
                        $this->getPageTitle()->getUserPermissionsErrors(
-                               'import', $user, true,
+                               'import', $user, PermissionManager::RIGOR_FULL,
                                [ 'ns-specialprotected', 'badaccess-group0', 'badaccess-groups' ]
                        ),
                        $this->getPageTitle()->getUserPermissionsErrors(
-                               'importupload', $user, true,
+                               'importupload', $user, PermissionManager::RIGOR_FULL,
                                [ 'ns-specialprotected', 'badaccess-group0', 'badaccess-groups' ]
                        )
                );
@@ -320,7 +322,7 @@ class SpecialImport extends SpecialPage {
                $action = $this->getPageTitle()->getLocalURL( [ 'action' => 'submit' ] );
                $user = $this->getUser();
                $out = $this->getOutput();
-               $this->addHelpLink( '//meta.wikimedia.org/wiki/Special:MyLanguage/Help:Import', true );
+               $this->addHelpLink( 'https://meta.wikimedia.org/wiki/Special:MyLanguage/Help:Import', true );
 
                if ( $user->isAllowed( 'importupload' ) ) {
                        $mappingSelection = $this->getMappingFormPart( 'upload' );
@@ -391,10 +393,8 @@ class SpecialImport extends SpecialPage {
                                        Xml::closeElement( 'form' ) .
                                        Xml::closeElement( 'fieldset' )
                        );
-               } else {
-                       if ( empty( $this->importSources ) ) {
-                               $out->addWikiMsg( 'importnosources' );
-                       }
+               } elseif ( empty( $this->importSources ) ) {
+                       $out->addWikiMsg( 'importnosources' );
                }
 
                if ( $user->isAllowed( 'import' ) && !empty( $this->importSources ) ) {
diff --git a/includes/specials/SpecialListFiles.php b/includes/specials/SpecialListFiles.php
new file mode 100644 (file)
index 0000000..e6e1048
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+/**
+ * Implements Special:Listfiles
+ *
+ * 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
+ */
+
+class SpecialListFiles extends IncludableSpecialPage {
+       public function __construct() {
+               parent::__construct( 'Listfiles' );
+       }
+
+       public function execute( $par ) {
+               $this->setHeaders();
+               $this->outputHeader();
+
+               if ( $this->including() ) {
+                       $userName = $par;
+                       $search = '';
+                       $showAll = false;
+               } else {
+                       $userName = $this->getRequest()->getText( 'user', $par );
+                       $search = $this->getRequest()->getText( 'ilsearch', '' );
+                       $showAll = $this->getRequest()->getBool( 'ilshowall', false );
+               }
+
+               $pager = new ImageListPager(
+                       $this->getContext(),
+                       $userName,
+                       $search,
+                       $this->including(),
+                       $showAll
+               );
+
+               $out = $this->getOutput();
+               if ( $this->including() ) {
+                       $out->addParserOutputContent( $pager->getBodyOutput() );
+               } else {
+                       $user = $pager->getRelevantUser();
+                       $this->getSkin()->setRelevantUser( $user );
+                       $pager->getForm();
+                       $out->addParserOutputContent( $pager->getFullOutput() );
+               }
+       }
+
+       /**
+        * Return an array of subpages beginning with $search that this special page will accept.
+        *
+        * @param string $search Prefix to search for
+        * @param int $limit Maximum number of results to return (usually 10)
+        * @param int $offset Number of results to skip (usually 0)
+        * @return string[] Matching subpages
+        */
+       public function prefixSearchSubpages( $search, $limit, $offset ) {
+               $user = User::newFromName( $search );
+               if ( !$user ) {
+                       // No prefix suggestion for invalid user
+                       return [];
+               }
+               // Autocomplete subpage as user list - public to allow caching
+               return UserNamePrefixSearch::search( 'public', $search, $limit, $offset );
+       }
+
+       protected function getGroupName() {
+               return 'media';
+       }
+}
diff --git a/includes/specials/SpecialListGrants.php b/includes/specials/SpecialListGrants.php
new file mode 100644 (file)
index 0000000..ba16baf
--- /dev/null
@@ -0,0 +1,91 @@
+<?php
+/**
+ * Implements Special:Listgrants
+ *
+ * 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
+ */
+
+/**
+ * This special page lists all defined rights grants and the associated rights.
+ * See also @ref $wgGrantPermissions and @ref $wgGrantPermissionGroups.
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialListGrants extends SpecialPage {
+       function __construct() {
+               parent::__construct( 'Listgrants' );
+       }
+
+       /**
+        * Show the special page
+        * @param string|null $par
+        */
+       public function execute( $par ) {
+               $this->setHeaders();
+               $this->outputHeader();
+
+               $out = $this->getOutput();
+               $out->addModuleStyles( 'mediawiki.special' );
+
+               $out->addHTML(
+                       \Html::openElement( 'table',
+                               [ 'class' => 'wikitable mw-listgrouprights-table' ] ) .
+                               '<tr>' .
+                               \Html::element( 'th', null, $this->msg( 'listgrants-grant' )->text() ) .
+                               \Html::element( 'th', null, $this->msg( 'listgrants-rights' )->text() ) .
+                               '</tr>'
+               );
+
+               foreach ( $this->getConfig()->get( 'GrantPermissions' ) as $grant => $rights ) {
+                       $descs = [];
+                       $rights = array_filter( $rights ); // remove ones with 'false'
+                       foreach ( $rights as $permission => $granted ) {
+                               $descs[] = $this->msg(
+                                       'listgrouprights-right-display',
+                                       \User::getRightDescription( $permission ),
+                                       '<span class="mw-listgrants-right-name">' . $permission . '</span>'
+                               )->parse();
+                       }
+                       if ( $descs === [] ) {
+                               $grantCellHtml = '';
+                       } else {
+                               sort( $descs );
+                               $grantCellHtml = '<ul><li>' . implode( "</li>\n<li>", $descs ) . '</li></ul>';
+                       }
+
+                       $id = Sanitizer::escapeIdForAttribute( $grant );
+                       $out->addHTML( \Html::rawElement( 'tr', [ 'id' => $id ],
+                               "<td>" .
+                               $this->msg(
+                                       "listgrants-grant-display",
+                                       \User::getGrantName( $grant ),
+                                       "<span class='mw-listgrants-grant-name'>" . $id . "</span>"
+                               )->parse() .
+                               "</td>" .
+                               "<td>" . $grantCellHtml . "</td>"
+                       ) );
+               }
+
+               $out->addHTML( \Html::closeElement( 'table' ) );
+       }
+
+       protected function getGroupName() {
+               return 'users';
+       }
+}
diff --git a/includes/specials/SpecialListGroupRights.php b/includes/specials/SpecialListGroupRights.php
new file mode 100644 (file)
index 0000000..ae4b090
--- /dev/null
@@ -0,0 +1,295 @@
+<?php
+/**
+ * Implements Special:Listgrouprights
+ *
+ * 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;
+
+/**
+ * This special page lists all defined user groups and the associated rights.
+ * See also @ref $wgGroupPermissions.
+ *
+ * @ingroup SpecialPage
+ * @author Petr Kadlec <mormegil@centrum.cz>
+ */
+class SpecialListGroupRights extends SpecialPage {
+       public function __construct() {
+               parent::__construct( 'Listgrouprights' );
+       }
+
+       /**
+        * Show the special page
+        * @param string|null $par
+        */
+       public function execute( $par ) {
+               $this->setHeaders();
+               $this->outputHeader();
+
+               $out = $this->getOutput();
+               $out->addModuleStyles( 'mediawiki.special' );
+
+               $out->wrapWikiMsg( "<div class=\"mw-listgrouprights-key\">\n$1\n</div>", 'listgrouprights-key' );
+
+               $out->addHTML(
+                       Xml::openElement( 'table', [ 'class' => 'wikitable mw-listgrouprights-table' ] ) .
+                               '<tr>' .
+                               Xml::element( 'th', null, $this->msg( 'listgrouprights-group' )->text() ) .
+                               Xml::element( 'th', null, $this->msg( 'listgrouprights-rights' )->text() ) .
+                               '</tr>'
+               );
+
+               $config = $this->getConfig();
+               $groupPermissions = $config->get( 'GroupPermissions' );
+               $revokePermissions = $config->get( 'RevokePermissions' );
+               $addGroups = $config->get( 'AddGroups' );
+               $removeGroups = $config->get( 'RemoveGroups' );
+               $groupsAddToSelf = $config->get( 'GroupsAddToSelf' );
+               $groupsRemoveFromSelf = $config->get( 'GroupsRemoveFromSelf' );
+               $allGroups = array_unique( array_merge(
+                       array_keys( $groupPermissions ),
+                       array_keys( $revokePermissions ),
+                       array_keys( $addGroups ),
+                       array_keys( $removeGroups ),
+                       array_keys( $groupsAddToSelf ),
+                       array_keys( $groupsRemoveFromSelf )
+               ) );
+               asort( $allGroups );
+
+               $linkRenderer = $this->getLinkRenderer();
+
+               foreach ( $allGroups as $group ) {
+                       $permissions = $groupPermissions[$group] ?? [];
+                       $groupname = ( $group == '*' ) // Replace * with a more descriptive groupname
+                               ? 'all'
+                               : $group;
+
+                       $groupnameLocalized = UserGroupMembership::getGroupName( $groupname );
+
+                       $grouppageLocalizedTitle = UserGroupMembership::getGroupPage( $groupname )
+                               ?: Title::newFromText( MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               getCanonicalName( NS_PROJECT ) . ':' . $groupname );
+
+                       if ( $group == '*' || !$grouppageLocalizedTitle ) {
+                               // Do not make a link for the generic * group or group with invalid group page
+                               $grouppage = htmlspecialchars( $groupnameLocalized );
+                       } else {
+                               $grouppage = $linkRenderer->makeLink(
+                                       $grouppageLocalizedTitle,
+                                       $groupnameLocalized
+                               );
+                       }
+
+                       if ( $group === 'user' ) {
+                               // Link to Special:listusers for implicit group 'user'
+                               $grouplink = '<br />' . $linkRenderer->makeKnownLink(
+                                       SpecialPage::getTitleFor( 'Listusers' ),
+                                       $this->msg( 'listgrouprights-members' )->text()
+                               );
+                       } elseif ( !in_array( $group, $config->get( 'ImplicitGroups' ) ) ) {
+                               $grouplink = '<br />' . $linkRenderer->makeKnownLink(
+                                       SpecialPage::getTitleFor( 'Listusers' ),
+                                       $this->msg( 'listgrouprights-members' )->text(),
+                                       [],
+                                       [ 'group' => $group ]
+                               );
+                       } else {
+                               // No link to Special:listusers for other implicit groups as they are unlistable
+                               $grouplink = '';
+                       }
+
+                       $revoke = $revokePermissions[$group] ?? [];
+                       $addgroups = $addGroups[$group] ?? [];
+                       $removegroups = $removeGroups[$group] ?? [];
+                       $addgroupsSelf = $groupsAddToSelf[$group] ?? [];
+                       $removegroupsSelf = $groupsRemoveFromSelf[$group] ?? [];
+
+                       $id = $group == '*' ? false : Sanitizer::escapeIdForAttribute( $group );
+                       $out->addHTML( Html::rawElement( 'tr', [ 'id' => $id ], "
+                               <td>$grouppage$grouplink</td>
+                                       <td>" .
+                                       $this->formatPermissions( $permissions, $revoke, $addgroups, $removegroups,
+                                               $addgroupsSelf, $removegroupsSelf ) .
+                                       '</td>
+                               '
+                       ) );
+               }
+               $out->addHTML( Xml::closeElement( 'table' ) );
+               $this->outputNamespaceProtectionInfo();
+       }
+
+       private function outputNamespaceProtectionInfo() {
+               $out = $this->getOutput();
+               $namespaceProtection = $this->getConfig()->get( 'NamespaceProtection' );
+
+               if ( count( $namespaceProtection ) == 0 ) {
+                       return;
+               }
+
+               $header = $this->msg( 'listgrouprights-namespaceprotection-header' )->text();
+               $out->addHTML(
+                       Html::rawElement( 'h2', [], Html::element( 'span', [
+                               'class' => 'mw-headline',
+                               'id' => substr( Parser::guessSectionNameFromStrippedText( $header ), 1 )
+                       ], $header ) ) .
+                       Xml::openElement( 'table', [ 'class' => 'wikitable' ] ) .
+                       Html::element(
+                               'th',
+                               [],
+                               $this->msg( 'listgrouprights-namespaceprotection-namespace' )->text()
+                       ) .
+                       Html::element(
+                               'th',
+                               [],
+                               $this->msg( 'listgrouprights-namespaceprotection-restrictedto' )->text()
+                       )
+               );
+               $linkRenderer = $this->getLinkRenderer();
+               ksort( $namespaceProtection );
+               $validNamespaces =
+                       MediaWikiServices::getInstance()->getNamespaceInfo()->getValidNamespaces();
+               $contLang = MediaWikiServices::getInstance()->getContentLanguage();
+               foreach ( $namespaceProtection as $namespace => $rights ) {
+                       if ( !in_array( $namespace, $validNamespaces ) ) {
+                               continue;
+                       }
+
+                       if ( $namespace == NS_MAIN ) {
+                               $namespaceText = $this->msg( 'blanknamespace' )->text();
+                       } else {
+                               $namespaceText = $contLang->convertNamespace( $namespace );
+                       }
+
+                       $out->addHTML(
+                               Xml::openElement( 'tr' ) .
+                               Html::rawElement(
+                                       'td',
+                                       [],
+                                       $linkRenderer->makeLink(
+                                               SpecialPage::getTitleFor( 'Allpages' ),
+                                               $namespaceText,
+                                               [],
+                                               [ 'namespace' => $namespace ]
+                                       )
+                               ) .
+                               Xml::openElement( 'td' ) . Xml::openElement( 'ul' )
+                       );
+
+                       if ( !is_array( $rights ) ) {
+                               $rights = [ $rights ];
+                       }
+
+                       foreach ( $rights as $right ) {
+                               $out->addHTML(
+                                       Html::rawElement( 'li', [], $this->msg(
+                                               'listgrouprights-right-display',
+                                               User::getRightDescription( $right ),
+                                               Html::element(
+                                                       'span',
+                                                       [ 'class' => 'mw-listgrouprights-right-name' ],
+                                                       $right
+                                               )
+                                       )->parse() )
+                               );
+                       }
+
+                       $out->addHTML(
+                               Xml::closeElement( 'ul' ) .
+                               Xml::closeElement( 'td' ) .
+                               Xml::closeElement( 'tr' )
+                       );
+               }
+               $out->addHTML( Xml::closeElement( 'table' ) );
+       }
+
+       /**
+        * Create a user-readable list of permissions from the given array.
+        *
+        * @param array $permissions Array of permission => bool (from $wgGroupPermissions items)
+        * @param array $revoke Array of permission => bool (from $wgRevokePermissions items)
+        * @param array $add Array of groups this group is allowed to add or true
+        * @param array $remove Array of groups this group is allowed to remove or true
+        * @param array $addSelf Array of groups this group is allowed to add to self or true
+        * @param array $removeSelf Array of group this group is allowed to remove from self or true
+        * @return string HTML list of all granted permissions
+        */
+       private function formatPermissions( $permissions, $revoke, $add, $remove, $addSelf, $removeSelf ) {
+               $r = [];
+               foreach ( $permissions as $permission => $granted ) {
+                       // show as granted only if it isn't revoked to prevent duplicate display of permissions
+                       if ( $granted && ( !isset( $revoke[$permission] ) || !$revoke[$permission] ) ) {
+                               $r[] = $this->msg( 'listgrouprights-right-display',
+                                       User::getRightDescription( $permission ),
+                                       '<span class="mw-listgrouprights-right-name">' . $permission . '</span>'
+                               )->parse();
+                       }
+               }
+               foreach ( $revoke as $permission => $revoked ) {
+                       if ( $revoked ) {
+                               $r[] = $this->msg( 'listgrouprights-right-revoked',
+                                       User::getRightDescription( $permission ),
+                                       '<span class="mw-listgrouprights-right-name">' . $permission . '</span>'
+                               )->parse();
+                       }
+               }
+
+               sort( $r );
+
+               $lang = $this->getLanguage();
+               $allGroups = User::getAllGroups();
+
+               $changeGroups = [
+                       'addgroup' => $add,
+                       'removegroup' => $remove,
+                       'addgroup-self' => $addSelf,
+                       'removegroup-self' => $removeSelf
+               ];
+
+               foreach ( $changeGroups as $messageKey => $changeGroup ) {
+                       if ( $changeGroup === true ) {
+                               // For grep: listgrouprights-addgroup-all, listgrouprights-removegroup-all,
+                               // listgrouprights-addgroup-self-all, listgrouprights-removegroup-self-all
+                               $r[] = $this->msg( 'listgrouprights-' . $messageKey . '-all' )->escaped();
+                       } elseif ( is_array( $changeGroup ) ) {
+                               $changeGroup = array_intersect( array_values( array_unique( $changeGroup ) ), $allGroups );
+                               if ( count( $changeGroup ) ) {
+                                       $groupLinks = [];
+                                       foreach ( $changeGroup as $group ) {
+                                               $groupLinks[] = UserGroupMembership::getLink( $group, $this->getContext(), 'wiki' );
+                                       }
+                                       // For grep: listgrouprights-addgroup, listgrouprights-removegroup,
+                                       // listgrouprights-addgroup-self, listgrouprights-removegroup-self
+                                       $r[] = $this->msg( 'listgrouprights-' . $messageKey,
+                                               $lang->listToText( $groupLinks ), count( $changeGroup ) )->parse();
+                               }
+                       }
+               }
+
+               if ( empty( $r ) ) {
+                       return '';
+               } else {
+                       return '<ul><li>' . implode( "</li>\n<li>", $r ) . '</li></ul>';
+               }
+       }
+
+       protected function getGroupName() {
+               return 'users';
+       }
+}
diff --git a/includes/specials/SpecialListUsers.php b/includes/specials/SpecialListUsers.php
new file mode 100644 (file)
index 0000000..f8aac32
--- /dev/null
@@ -0,0 +1,79 @@
+<?php
+/**
+ * Implements Special:Listusers
+ *
+ * Copyright © 2004 Brion Vibber, lcrocker, Tim Starling,
+ * Domas Mituzas, Antoine Musso, Jens Frank, Zhengzhu,
+ * 2006 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
+ */
+
+/**
+ * @ingroup SpecialPage
+ */
+class SpecialListUsers extends IncludableSpecialPage {
+
+       public function __construct() {
+               parent::__construct( 'Listusers' );
+       }
+
+       /**
+        * @param string|null $par (optional) A group to list users from
+        */
+       public function execute( $par ) {
+               $this->setHeaders();
+               $this->outputHeader();
+
+               $up = new UsersPager( $this->getContext(), $par, $this->including() );
+
+               # getBody() first to check, if empty
+               $usersbody = $up->getBody();
+
+               $s = '';
+               if ( !$this->including() ) {
+                       $s = $up->getPageHeader();
+               }
+
+               if ( $usersbody ) {
+                       $s .= $up->getNavigationBar();
+                       $s .= Html::rawElement( 'ul', [], $usersbody );
+                       $s .= $up->getNavigationBar();
+               } else {
+                       $s .= $this->msg( 'listusers-noresult' )->parseAsBlock();
+               }
+
+               $out = $this->getOutput();
+               $out->addHTML( $s );
+               $out->addModuleStyles( 'mediawiki.interface.helpers.styles' );
+       }
+
+       /**
+        * Return an array of subpages that this special page will accept.
+        *
+        * @return string[] subpages
+        */
+       public function getSubpagesForPrefixSearch() {
+               return User::getAllGroups();
+       }
+
+       protected function getGroupName() {
+               return 'users';
+       }
+}
diff --git a/includes/specials/SpecialListfiles.php b/includes/specials/SpecialListfiles.php
deleted file mode 100644 (file)
index e6e1048..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-<?php
-/**
- * Implements Special:Listfiles
- *
- * 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
- */
-
-class SpecialListFiles extends IncludableSpecialPage {
-       public function __construct() {
-               parent::__construct( 'Listfiles' );
-       }
-
-       public function execute( $par ) {
-               $this->setHeaders();
-               $this->outputHeader();
-
-               if ( $this->including() ) {
-                       $userName = $par;
-                       $search = '';
-                       $showAll = false;
-               } else {
-                       $userName = $this->getRequest()->getText( 'user', $par );
-                       $search = $this->getRequest()->getText( 'ilsearch', '' );
-                       $showAll = $this->getRequest()->getBool( 'ilshowall', false );
-               }
-
-               $pager = new ImageListPager(
-                       $this->getContext(),
-                       $userName,
-                       $search,
-                       $this->including(),
-                       $showAll
-               );
-
-               $out = $this->getOutput();
-               if ( $this->including() ) {
-                       $out->addParserOutputContent( $pager->getBodyOutput() );
-               } else {
-                       $user = $pager->getRelevantUser();
-                       $this->getSkin()->setRelevantUser( $user );
-                       $pager->getForm();
-                       $out->addParserOutputContent( $pager->getFullOutput() );
-               }
-       }
-
-       /**
-        * Return an array of subpages beginning with $search that this special page will accept.
-        *
-        * @param string $search Prefix to search for
-        * @param int $limit Maximum number of results to return (usually 10)
-        * @param int $offset Number of results to skip (usually 0)
-        * @return string[] Matching subpages
-        */
-       public function prefixSearchSubpages( $search, $limit, $offset ) {
-               $user = User::newFromName( $search );
-               if ( !$user ) {
-                       // No prefix suggestion for invalid user
-                       return [];
-               }
-               // Autocomplete subpage as user list - public to allow caching
-               return UserNamePrefixSearch::search( 'public', $search, $limit, $offset );
-       }
-
-       protected function getGroupName() {
-               return 'media';
-       }
-}
diff --git a/includes/specials/SpecialListgrants.php b/includes/specials/SpecialListgrants.php
deleted file mode 100644 (file)
index ba16baf..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-<?php
-/**
- * Implements Special:Listgrants
- *
- * 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
- */
-
-/**
- * This special page lists all defined rights grants and the associated rights.
- * See also @ref $wgGrantPermissions and @ref $wgGrantPermissionGroups.
- *
- * @ingroup SpecialPage
- */
-class SpecialListGrants extends SpecialPage {
-       function __construct() {
-               parent::__construct( 'Listgrants' );
-       }
-
-       /**
-        * Show the special page
-        * @param string|null $par
-        */
-       public function execute( $par ) {
-               $this->setHeaders();
-               $this->outputHeader();
-
-               $out = $this->getOutput();
-               $out->addModuleStyles( 'mediawiki.special' );
-
-               $out->addHTML(
-                       \Html::openElement( 'table',
-                               [ 'class' => 'wikitable mw-listgrouprights-table' ] ) .
-                               '<tr>' .
-                               \Html::element( 'th', null, $this->msg( 'listgrants-grant' )->text() ) .
-                               \Html::element( 'th', null, $this->msg( 'listgrants-rights' )->text() ) .
-                               '</tr>'
-               );
-
-               foreach ( $this->getConfig()->get( 'GrantPermissions' ) as $grant => $rights ) {
-                       $descs = [];
-                       $rights = array_filter( $rights ); // remove ones with 'false'
-                       foreach ( $rights as $permission => $granted ) {
-                               $descs[] = $this->msg(
-                                       'listgrouprights-right-display',
-                                       \User::getRightDescription( $permission ),
-                                       '<span class="mw-listgrants-right-name">' . $permission . '</span>'
-                               )->parse();
-                       }
-                       if ( $descs === [] ) {
-                               $grantCellHtml = '';
-                       } else {
-                               sort( $descs );
-                               $grantCellHtml = '<ul><li>' . implode( "</li>\n<li>", $descs ) . '</li></ul>';
-                       }
-
-                       $id = Sanitizer::escapeIdForAttribute( $grant );
-                       $out->addHTML( \Html::rawElement( 'tr', [ 'id' => $id ],
-                               "<td>" .
-                               $this->msg(
-                                       "listgrants-grant-display",
-                                       \User::getGrantName( $grant ),
-                                       "<span class='mw-listgrants-grant-name'>" . $id . "</span>"
-                               )->parse() .
-                               "</td>" .
-                               "<td>" . $grantCellHtml . "</td>"
-                       ) );
-               }
-
-               $out->addHTML( \Html::closeElement( 'table' ) );
-       }
-
-       protected function getGroupName() {
-               return 'users';
-       }
-}
diff --git a/includes/specials/SpecialListgrouprights.php b/includes/specials/SpecialListgrouprights.php
deleted file mode 100644 (file)
index 1d10791..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-<?php
-/**
- * Implements Special:Listgrouprights
- *
- * 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;
-
-/**
- * This special page lists all defined user groups and the associated rights.
- * See also @ref $wgGroupPermissions.
- *
- * @ingroup SpecialPage
- * @author Petr Kadlec <mormegil@centrum.cz>
- */
-class SpecialListGroupRights extends SpecialPage {
-       public function __construct() {
-               parent::__construct( 'Listgrouprights' );
-       }
-
-       /**
-        * Show the special page
-        * @param string|null $par
-        */
-       public function execute( $par ) {
-               $this->setHeaders();
-               $this->outputHeader();
-
-               $out = $this->getOutput();
-               $out->addModuleStyles( 'mediawiki.special' );
-
-               $out->wrapWikiMsg( "<div class=\"mw-listgrouprights-key\">\n$1\n</div>", 'listgrouprights-key' );
-
-               $out->addHTML(
-                       Xml::openElement( 'table', [ 'class' => 'wikitable mw-listgrouprights-table' ] ) .
-                               '<tr>' .
-                               Xml::element( 'th', null, $this->msg( 'listgrouprights-group' )->text() ) .
-                               Xml::element( 'th', null, $this->msg( 'listgrouprights-rights' )->text() ) .
-                               '</tr>'
-               );
-
-               $config = $this->getConfig();
-               $groupPermissions = $config->get( 'GroupPermissions' );
-               $revokePermissions = $config->get( 'RevokePermissions' );
-               $addGroups = $config->get( 'AddGroups' );
-               $removeGroups = $config->get( 'RemoveGroups' );
-               $groupsAddToSelf = $config->get( 'GroupsAddToSelf' );
-               $groupsRemoveFromSelf = $config->get( 'GroupsRemoveFromSelf' );
-               $allGroups = array_unique( array_merge(
-                       array_keys( $groupPermissions ),
-                       array_keys( $revokePermissions ),
-                       array_keys( $addGroups ),
-                       array_keys( $removeGroups ),
-                       array_keys( $groupsAddToSelf ),
-                       array_keys( $groupsRemoveFromSelf )
-               ) );
-               asort( $allGroups );
-
-               $linkRenderer = $this->getLinkRenderer();
-
-               foreach ( $allGroups as $group ) {
-                       $permissions = $groupPermissions[$group] ?? [];
-                       $groupname = ( $group == '*' ) // Replace * with a more descriptive groupname
-                               ? 'all'
-                               : $group;
-
-                       $groupnameLocalized = UserGroupMembership::getGroupName( $groupname );
-
-                       $grouppageLocalizedTitle = UserGroupMembership::getGroupPage( $groupname )
-                               ?: Title::newFromText( MWNamespace::getCanonicalName( NS_PROJECT ) . ':' . $groupname );
-
-                       if ( $group == '*' || !$grouppageLocalizedTitle ) {
-                               // Do not make a link for the generic * group or group with invalid group page
-                               $grouppage = htmlspecialchars( $groupnameLocalized );
-                       } else {
-                               $grouppage = $linkRenderer->makeLink(
-                                       $grouppageLocalizedTitle,
-                                       $groupnameLocalized
-                               );
-                       }
-
-                       if ( $group === 'user' ) {
-                               // Link to Special:listusers for implicit group 'user'
-                               $grouplink = '<br />' . $linkRenderer->makeKnownLink(
-                                       SpecialPage::getTitleFor( 'Listusers' ),
-                                       $this->msg( 'listgrouprights-members' )->text()
-                               );
-                       } elseif ( !in_array( $group, $config->get( 'ImplicitGroups' ) ) ) {
-                               $grouplink = '<br />' . $linkRenderer->makeKnownLink(
-                                       SpecialPage::getTitleFor( 'Listusers' ),
-                                       $this->msg( 'listgrouprights-members' )->text(),
-                                       [],
-                                       [ 'group' => $group ]
-                               );
-                       } else {
-                               // No link to Special:listusers for other implicit groups as they are unlistable
-                               $grouplink = '';
-                       }
-
-                       $revoke = $revokePermissions[$group] ?? [];
-                       $addgroups = $addGroups[$group] ?? [];
-                       $removegroups = $removeGroups[$group] ?? [];
-                       $addgroupsSelf = $groupsAddToSelf[$group] ?? [];
-                       $removegroupsSelf = $groupsRemoveFromSelf[$group] ?? [];
-
-                       $id = $group == '*' ? false : Sanitizer::escapeIdForAttribute( $group );
-                       $out->addHTML( Html::rawElement( 'tr', [ 'id' => $id ], "
-                               <td>$grouppage$grouplink</td>
-                                       <td>" .
-                                       $this->formatPermissions( $permissions, $revoke, $addgroups, $removegroups,
-                                               $addgroupsSelf, $removegroupsSelf ) .
-                                       '</td>
-                               '
-                       ) );
-               }
-               $out->addHTML( Xml::closeElement( 'table' ) );
-               $this->outputNamespaceProtectionInfo();
-       }
-
-       private function outputNamespaceProtectionInfo() {
-               $out = $this->getOutput();
-               $namespaceProtection = $this->getConfig()->get( 'NamespaceProtection' );
-
-               if ( count( $namespaceProtection ) == 0 ) {
-                       return;
-               }
-
-               $header = $this->msg( 'listgrouprights-namespaceprotection-header' )->text();
-               $out->addHTML(
-                       Html::rawElement( 'h2', [], Html::element( 'span', [
-                               'class' => 'mw-headline',
-                               'id' => substr( Parser::guessSectionNameFromStrippedText( $header ), 1 )
-                       ], $header ) ) .
-                       Xml::openElement( 'table', [ 'class' => 'wikitable' ] ) .
-                       Html::element(
-                               'th',
-                               [],
-                               $this->msg( 'listgrouprights-namespaceprotection-namespace' )->text()
-                       ) .
-                       Html::element(
-                               'th',
-                               [],
-                               $this->msg( 'listgrouprights-namespaceprotection-restrictedto' )->text()
-                       )
-               );
-               $linkRenderer = $this->getLinkRenderer();
-               ksort( $namespaceProtection );
-               $validNamespaces = MWNamespace::getValidNamespaces();
-               $contLang = MediaWikiServices::getInstance()->getContentLanguage();
-               foreach ( $namespaceProtection as $namespace => $rights ) {
-                       if ( !in_array( $namespace, $validNamespaces ) ) {
-                               continue;
-                       }
-
-                       if ( $namespace == NS_MAIN ) {
-                               $namespaceText = $this->msg( 'blanknamespace' )->text();
-                       } else {
-                               $namespaceText = $contLang->convertNamespace( $namespace );
-                       }
-
-                       $out->addHTML(
-                               Xml::openElement( 'tr' ) .
-                               Html::rawElement(
-                                       'td',
-                                       [],
-                                       $linkRenderer->makeLink(
-                                               SpecialPage::getTitleFor( 'Allpages' ),
-                                               $namespaceText,
-                                               [],
-                                               [ 'namespace' => $namespace ]
-                                       )
-                               ) .
-                               Xml::openElement( 'td' ) . Xml::openElement( 'ul' )
-                       );
-
-                       if ( !is_array( $rights ) ) {
-                               $rights = [ $rights ];
-                       }
-
-                       foreach ( $rights as $right ) {
-                               $out->addHTML(
-                                       Html::rawElement( 'li', [], $this->msg(
-                                               'listgrouprights-right-display',
-                                               User::getRightDescription( $right ),
-                                               Html::element(
-                                                       'span',
-                                                       [ 'class' => 'mw-listgrouprights-right-name' ],
-                                                       $right
-                                               )
-                                       )->parse() )
-                               );
-                       }
-
-                       $out->addHTML(
-                               Xml::closeElement( 'ul' ) .
-                               Xml::closeElement( 'td' ) .
-                               Xml::closeElement( 'tr' )
-                       );
-               }
-               $out->addHTML( Xml::closeElement( 'table' ) );
-       }
-
-       /**
-        * Create a user-readable list of permissions from the given array.
-        *
-        * @param array $permissions Array of permission => bool (from $wgGroupPermissions items)
-        * @param array $revoke Array of permission => bool (from $wgRevokePermissions items)
-        * @param array $add Array of groups this group is allowed to add or true
-        * @param array $remove Array of groups this group is allowed to remove or true
-        * @param array $addSelf Array of groups this group is allowed to add to self or true
-        * @param array $removeSelf Array of group this group is allowed to remove from self or true
-        * @return string HTML list of all granted permissions
-        */
-       private function formatPermissions( $permissions, $revoke, $add, $remove, $addSelf, $removeSelf ) {
-               $r = [];
-               foreach ( $permissions as $permission => $granted ) {
-                       // show as granted only if it isn't revoked to prevent duplicate display of permissions
-                       if ( $granted && ( !isset( $revoke[$permission] ) || !$revoke[$permission] ) ) {
-                               $r[] = $this->msg( 'listgrouprights-right-display',
-                                       User::getRightDescription( $permission ),
-                                       '<span class="mw-listgrouprights-right-name">' . $permission . '</span>'
-                               )->parse();
-                       }
-               }
-               foreach ( $revoke as $permission => $revoked ) {
-                       if ( $revoked ) {
-                               $r[] = $this->msg( 'listgrouprights-right-revoked',
-                                       User::getRightDescription( $permission ),
-                                       '<span class="mw-listgrouprights-right-name">' . $permission . '</span>'
-                               )->parse();
-                       }
-               }
-
-               sort( $r );
-
-               $lang = $this->getLanguage();
-               $allGroups = User::getAllGroups();
-
-               $changeGroups = [
-                       'addgroup' => $add,
-                       'removegroup' => $remove,
-                       'addgroup-self' => $addSelf,
-                       'removegroup-self' => $removeSelf
-               ];
-
-               foreach ( $changeGroups as $messageKey => $changeGroup ) {
-                       if ( $changeGroup === true ) {
-                               // For grep: listgrouprights-addgroup-all, listgrouprights-removegroup-all,
-                               // listgrouprights-addgroup-self-all, listgrouprights-removegroup-self-all
-                               $r[] = $this->msg( 'listgrouprights-' . $messageKey . '-all' )->escaped();
-                       } elseif ( is_array( $changeGroup ) ) {
-                               $changeGroup = array_intersect( array_values( array_unique( $changeGroup ) ), $allGroups );
-                               if ( count( $changeGroup ) ) {
-                                       $groupLinks = [];
-                                       foreach ( $changeGroup as $group ) {
-                                               $groupLinks[] = UserGroupMembership::getLink( $group, $this->getContext(), 'wiki' );
-                                       }
-                                       // For grep: listgrouprights-addgroup, listgrouprights-removegroup,
-                                       // listgrouprights-addgroup-self, listgrouprights-removegroup-self
-                                       $r[] = $this->msg( 'listgrouprights-' . $messageKey,
-                                               $lang->listToText( $groupLinks ), count( $changeGroup ) )->parse();
-                               }
-                       }
-               }
-
-               if ( empty( $r ) ) {
-                       return '';
-               } else {
-                       return '<ul><li>' . implode( "</li>\n<li>", $r ) . '</li></ul>';
-               }
-       }
-
-       protected function getGroupName() {
-               return 'users';
-       }
-}
diff --git a/includes/specials/SpecialListusers.php b/includes/specials/SpecialListusers.php
deleted file mode 100644 (file)
index 2c35815..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-<?php
-/**
- * Implements Special:Listusers
- *
- * Copyright © 2004 Brion Vibber, lcrocker, Tim Starling,
- * Domas Mituzas, Antoine Musso, Jens Frank, Zhengzhu,
- * 2006 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
- */
-
-/**
- * @ingroup SpecialPage
- */
-class SpecialListUsers extends IncludableSpecialPage {
-
-       public function __construct() {
-               parent::__construct( 'Listusers' );
-       }
-
-       /**
-        * Show the special page
-        *
-        * @param string $par (optional) A group to list users from
-        */
-       public function execute( $par ) {
-               $this->setHeaders();
-               $this->outputHeader();
-
-               $up = new UsersPager( $this->getContext(), $par, $this->including() );
-
-               # getBody() first to check, if empty
-               $usersbody = $up->getBody();
-
-               $s = '';
-               if ( !$this->including() ) {
-                       $s = $up->getPageHeader();
-               }
-
-               if ( $usersbody ) {
-                       $s .= $up->getNavigationBar();
-                       $s .= Html::rawElement( 'ul', [], $usersbody );
-                       $s .= $up->getNavigationBar();
-               } else {
-                       $s .= $this->msg( 'listusers-noresult' )->parseAsBlock();
-               }
-
-               $this->getOutput()->addHTML( $s );
-       }
-
-       /**
-        * Return an array of subpages that this special page will accept.
-        *
-        * @return string[] subpages
-        */
-       public function getSubpagesForPrefixSearch() {
-               return User::getAllGroups();
-       }
-
-       protected function getGroupName() {
-               return 'users';
-       }
-}
index 21c166c..2f0c2ce 100644 (file)
@@ -185,7 +185,7 @@ class SpecialLog extends SpecialPage {
         */
        private function parseParams( FormOptions $opts, $par ) {
                # Get parameters
-               $par = $par !== null ? $par : '';
+               $par = $par ?? '';
                $parms = explode( '/', $par );
                $symsForAll = [ '*', 'all' ];
                if ( $parms[0] != '' &&
index ff76a4b..ca3f4da 100644 (file)
@@ -21,6 +21,8 @@
  * @ingroup SpecialPage
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * A special page looking for articles with no article linking to them,
  * thus being lonely.
@@ -52,7 +54,8 @@ class LonelyPagesPage extends PageQueryPage {
                $tables = [ 'page', 'pagelinks', 'templatelinks' ];
                $conds = [
                        'pl_namespace IS NULL',
-                       'page_namespace' => MWNamespace::getContentNamespaces(),
+                       'page_namespace' => MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               getContentNamespaces(),
                        'page_is_redirect' => 0,
                        'tl_namespace IS NULL'
                ];
@@ -89,7 +92,9 @@ class LonelyPagesPage extends PageQueryPage {
        function getOrderFields() {
                // For some crazy reason ordering by a constant
                // causes a filesort in MySQL 5
-               if ( count( MWNamespace::getContentNamespaces() ) > 1 ) {
+               if ( count( MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       getContentNamespaces() ) > 1
+               ) {
                        return [ 'page_namespace', 'page_title' ];
                } else {
                        return [ 'page_title' ];
index 2599b16..e8e5ea0 100644 (file)
@@ -132,6 +132,7 @@ class MIMEsearchPage extends QueryPage {
                        ->setMethod( 'get' )
                        ->prepareForm()
                        ->displayForm( false );
+               return '';
        }
 
        protected function getSuggestionsForTypes() {
index 123c174..0dd9437 100644 (file)
@@ -24,6 +24,7 @@
  * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
  */
 
+use MediaWiki\MediaWikiServices;
 use Wikimedia\Rdbms\IResultWrapper;
 use Wikimedia\Rdbms\IDatabase;
 
@@ -53,7 +54,8 @@ class MostcategoriesPage extends QueryPage {
                                'title' => 'page_title',
                                'value' => 'COUNT(*)'
                        ],
-                       'conds' => [ 'page_namespace' => MWNamespace::getContentNamespaces() ],
+                       'conds' => [ 'page_namespace' =>
+                               MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces() ],
                        'options' => [
                                'HAVING' => 'COUNT(*) > 1',
                                'GROUP BY' => [ 'page_namespace', 'page_title' ]
index c963838..0fcf842 100644 (file)
@@ -21,6 +21,7 @@
  * @ingroup SpecialPage
  */
 
+use MediaWiki\MediaWikiServices;
 use Wikimedia\Rdbms\IResultWrapper;
 use Wikimedia\Rdbms\IDatabase;
 
@@ -52,7 +53,8 @@ class MostinterwikisPage extends QueryPage {
                                'title' => 'page_title',
                                'value' => 'COUNT(*)'
                        ], 'conds' => [
-                               'page_namespace' => MWNamespace::getContentNamespaces()
+                               'page_namespace' =>
+                                       MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces()
                        ], 'options' => [
                                'HAVING' => 'COUNT(*) > 1',
                                'GROUP BY' => [
index 8b5562f..b561e5b 100644 (file)
@@ -21,6 +21,8 @@
  * @ingroup SpecialPage
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * A special page that allows users to change page titles
  *
@@ -297,7 +299,7 @@ class MovePageForm extends UnlistedSpecialPage {
 
                $immovableNamespaces = [];
                foreach ( array_keys( $this->getLanguage()->getNamespaces() ) as $nsId ) {
-                       if ( !MWNamespace::isMovable( $nsId ) ) {
+                       if ( !MediaWikiServices::getInstance()->getNamespaceInfo()->isMovable( $nsId ) ) {
                                $immovableNamespaces[] = $nsId;
                        }
                }
@@ -591,21 +593,12 @@ class MovePageForm extends UnlistedSpecialPage {
 
                # Do the actual move.
                $mp = new MovePage( $ot, $nt );
-               $valid = $mp->isValidMove();
-               if ( !$valid->isOK() ) {
-                       $this->showForm( $valid->getErrorsArray() );
-                       return;
-               }
 
-               $permStatus = $mp->checkPermissions( $user, $this->reason );
-               if ( !$permStatus->isOK() ) {
-                       $this->showForm( $permStatus->getErrorsArray(), true );
-                       return;
-               }
+               $userPermitted = $mp->checkPermissions( $user, $this->reason )->isOK();
 
-               $status = $mp->move( $user, $this->reason, $createRedirect );
+               $status = $mp->moveIfAllowed( $user, $this->reason, $createRedirect );
                if ( !$status->isOK() ) {
-                       $this->showForm( $status->getErrorsArray() );
+                       $this->showForm( $status->getErrorsArray(), !$userPermitted );
                        return;
                }
 
@@ -673,11 +666,12 @@ class MovePageForm extends UnlistedSpecialPage {
                 */
 
                // @todo FIXME: Use Title::moveSubpages() here
+               $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
                $dbr = wfGetDB( DB_MASTER );
                if ( $this->moveSubpages && (
-                       MWNamespace::hasSubpages( $nt->getNamespace() ) || (
+                       $nsInfo->hasSubpages( $nt->getNamespace() ) || (
                                $this->moveTalk
-                                       && MWNamespace::hasSubpages( $nt->getTalkPage()->getNamespace() )
+                                       && $nsInfo->hasSubpages( $nt->getTalkPage()->getNamespace() )
                        )
                ) ) {
                        $conds = [
@@ -685,11 +679,11 @@ class MovePageForm extends UnlistedSpecialPage {
                                        . ' OR page_title = ' . $dbr->addQuotes( $ot->getDBkey() )
                        ];
                        $conds['page_namespace'] = [];
-                       if ( MWNamespace::hasSubpages( $nt->getNamespace() ) ) {
+                       if ( $nsInfo->hasSubpages( $nt->getNamespace() ) ) {
                                $conds['page_namespace'][] = $ot->getNamespace();
                        }
                        if ( $this->moveTalk &&
-                               MWNamespace::hasSubpages( $nt->getTalkPage()->getNamespace() )
+                               $nsInfo->hasSubpages( $nt->getTalkPage()->getNamespace() )
                        ) {
                                $conds['page_namespace'][] = $ot->getTalkPage()->getNamespace();
                        }
@@ -808,7 +802,8 @@ class MovePageForm extends UnlistedSpecialPage {
         * @param Title $title Page being moved.
         */
        function showSubpages( $title ) {
-               $nsHasSubpages = MWNamespace::hasSubpages( $title->getNamespace() );
+               $nsHasSubpages = MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       hasSubpages( $title->getNamespace() );
                $subpages = $title->getSubpages();
                $count = $subpages instanceof TitleArray ? $subpages->count() : 0;
 
index 1f81cf0..1b8ba85 100644 (file)
@@ -39,6 +39,9 @@ class SpecialNewpages extends IncludableSpecialPage {
                parent::__construct( 'Newpages' );
        }
 
+       /**
+        * @param string|null $par
+        */
        protected function setup( $par ) {
                $opts = new FormOptions();
                $this->opts = $opts; // bind
@@ -70,6 +73,9 @@ class SpecialNewpages extends IncludableSpecialPage {
                $opts->validateIntBounds( 'limit', 0, 5000 );
        }
 
+       /**
+        * @param string $par
+        */
        protected function parseParams( $par ) {
                $bits = preg_split( '/\s*,\s*/', trim( $par ) );
                foreach ( $bits as $bit ) {
@@ -115,7 +121,7 @@ class SpecialNewpages extends IncludableSpecialPage {
        /**
         * Show a form for filtering namespace and username
         *
-        * @param string $par
+        * @param string|null $par
         */
        public function execute( $par ) {
                $out = $this->getOutput();
index 52db060..7e41305 100644 (file)
@@ -44,6 +44,7 @@ class SpecialPageLanguage extends FormSpecialPage {
 
        protected function preText() {
                $this->getOutput()->addModules( 'mediawiki.special.pageLanguage' );
+               return parent::preText();
        }
 
        protected function getFormFields() {
index d09deab..9bd855a 100644 (file)
@@ -21,6 +21,8 @@
  * @ingroup SpecialPage
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * This special page lists the defined password policies for user groups.
  * See also @ref $wgPasswordPolicy.
@@ -84,7 +86,8 @@ class SpecialPasswordPolicies extends SpecialPage {
                        $groupnameLocalized = UserGroupMembership::getGroupName( $group );
 
                        $grouppageLocalizedTitle = UserGroupMembership::getGroupPage( $group )
-                               ?: Title::newFromText( MWNamespace::getCanonicalName( NS_PROJECT ) . ':' . $group );
+                               ?: Title::newFromText( MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                       getCanonicalName( NS_PROJECT ) . ':' . $group );
 
                        $grouppage = $linkRenderer->makeLink(
                                $grouppageLocalizedTitle,
index cc7ed55..0bc9147 100644 (file)
@@ -106,7 +106,7 @@ class SpecialPreferences extends SpecialPage {
         * Get the preferences form to use.
         * @param User $user The user.
         * @param IContextSource $context The context.
-        * @return PreferencesFormLegacy|HTMLForm
+        * @return PreferencesFormOOUI|HTMLForm
         */
        protected function getFormObject( $user, IContextSource $context ) {
                $preferencesFactory = MediaWikiServices::getInstance()->getPreferencesFactory();
index 7e5a73f..c4ea005 100644 (file)
@@ -35,7 +35,8 @@ class RandomPage extends SpecialPage {
        protected $extra = []; // Extra SQL statements
 
        public function __construct( $name = 'Randompage' ) {
-               $this->namespaces = MWNamespace::getContentNamespaces();
+               $this->namespaces = MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       getContentNamespaces();
                parent::__construct( $name );
        }
 
diff --git a/includes/specials/SpecialRecentChanges.php b/includes/specials/SpecialRecentChanges.php
new file mode 100644 (file)
index 0000000..6949c61
--- /dev/null
@@ -0,0 +1,947 @@
+<?php
+/**
+ * Implements Special:Recentchanges
+ *
+ * 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\FakeResultWrapper;
+
+/**
+ * A special page that lists last changes made to the wiki
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialRecentChanges extends ChangesListSpecialPage {
+
+       protected static $savedQueriesPreferenceName = 'rcfilters-saved-queries';
+       protected static $daysPreferenceName = 'rcdays'; // Use general RecentChanges preference
+       protected static $limitPreferenceName = 'rcfilters-limit'; // Use RCFilters-specific preference
+       protected static $collapsedPreferenceName = 'rcfilters-rc-collapsed';
+
+       private $watchlistFilterGroupDefinition;
+
+       public function __construct( $name = 'Recentchanges', $restriction = '' ) {
+               parent::__construct( $name, $restriction );
+
+               $this->watchlistFilterGroupDefinition = [
+                       'name' => 'watchlist',
+                       'title' => 'rcfilters-filtergroup-watchlist',
+                       'class' => ChangesListStringOptionsFilterGroup::class,
+                       'priority' => -9,
+                       'isFullCoverage' => true,
+                       'filters' => [
+                               [
+                                       'name' => 'watched',
+                                       'label' => 'rcfilters-filter-watchlist-watched-label',
+                                       'description' => 'rcfilters-filter-watchlist-watched-description',
+                                       'cssClassSuffix' => 'watched',
+                                       'isRowApplicableCallable' => function ( $ctx, $rc ) {
+                                               return $rc->getAttribute( 'wl_user' );
+                                       }
+                               ],
+                               [
+                                       'name' => 'watchednew',
+                                       'label' => 'rcfilters-filter-watchlist-watchednew-label',
+                                       'description' => 'rcfilters-filter-watchlist-watchednew-description',
+                                       'cssClassSuffix' => 'watchednew',
+                                       'isRowApplicableCallable' => function ( $ctx, $rc ) {
+                                               return $rc->getAttribute( 'wl_user' ) &&
+                                                       $rc->getAttribute( 'rc_timestamp' ) &&
+                                                       $rc->getAttribute( 'wl_notificationtimestamp' ) &&
+                                                       $rc->getAttribute( 'rc_timestamp' ) >= $rc->getAttribute( 'wl_notificationtimestamp' );
+                                       },
+                               ],
+                               [
+                                       'name' => 'notwatched',
+                                       'label' => 'rcfilters-filter-watchlist-notwatched-label',
+                                       'description' => 'rcfilters-filter-watchlist-notwatched-description',
+                                       'cssClassSuffix' => 'notwatched',
+                                       'isRowApplicableCallable' => function ( $ctx, $rc ) {
+                                               return $rc->getAttribute( 'wl_user' ) === null;
+                                       },
+                               ]
+                       ],
+                       'default' => ChangesListStringOptionsFilterGroup::NONE,
+                       'queryCallable' => function ( $specialPageClassName, $context, $dbr,
+                               &$tables, &$fields, &$conds, &$query_options, &$join_conds, $selectedValues ) {
+                               sort( $selectedValues );
+                               $notwatchedCond = 'wl_user IS NULL';
+                               $watchedCond = 'wl_user IS NOT NULL';
+                               $newCond = 'rc_timestamp >= wl_notificationtimestamp';
+
+                               if ( $selectedValues === [ 'notwatched' ] ) {
+                                       $conds[] = $notwatchedCond;
+                                       return;
+                               }
+
+                               if ( $selectedValues === [ 'watched' ] ) {
+                                       $conds[] = $watchedCond;
+                                       return;
+                               }
+
+                               if ( $selectedValues === [ 'watchednew' ] ) {
+                                       $conds[] = $dbr->makeList( [
+                                               $watchedCond,
+                                               $newCond
+                                       ], LIST_AND );
+                                       return;
+                               }
+
+                               if ( $selectedValues === [ 'notwatched', 'watched' ] ) {
+                                       // no filters
+                                       return;
+                               }
+
+                               if ( $selectedValues === [ 'notwatched', 'watchednew' ] ) {
+                                       $conds[] = $dbr->makeList( [
+                                               $notwatchedCond,
+                                               $dbr->makeList( [
+                                                       $watchedCond,
+                                                       $newCond
+                                               ], LIST_AND )
+                                       ], LIST_OR );
+                                       return;
+                               }
+
+                               if ( $selectedValues === [ 'watched', 'watchednew' ] ) {
+                                       $conds[] = $watchedCond;
+                                       return;
+                               }
+
+                               if ( $selectedValues === [ 'notwatched', 'watched', 'watchednew' ] ) {
+                                       // no filters
+                                       return;
+                               }
+                       }
+               ];
+       }
+
+       /**
+        * @param string|null $subpage
+        */
+       public function execute( $subpage ) {
+               // Backwards-compatibility: redirect to new feed URLs
+               $feedFormat = $this->getRequest()->getVal( 'feed' );
+               if ( !$this->including() && $feedFormat ) {
+                       $query = $this->getFeedQuery();
+                       $query['feedformat'] = $feedFormat === 'atom' ? 'atom' : 'rss';
+                       $this->getOutput()->redirect( wfAppendQuery( wfScript( 'api' ), $query ) );
+
+                       return;
+               }
+
+               // 10 seconds server-side caching max
+               $out = $this->getOutput();
+               $out->setCdnMaxage( 10 );
+               // Check if the client has a cached version
+               $lastmod = $this->checkLastModified();
+               if ( $lastmod === false ) {
+                       return;
+               }
+
+               $this->addHelpLink(
+                       'https://meta.wikimedia.org/wiki/Special:MyLanguage/Help:Recent_changes',
+                       true
+               );
+               parent::execute( $subpage );
+       }
+
+       /**
+        * @inheritDoc
+        */
+       protected function transformFilterDefinition( array $filterDefinition ) {
+               if ( isset( $filterDefinition['showHideSuffix'] ) ) {
+                       $filterDefinition['showHide'] = 'rc' . $filterDefinition['showHideSuffix'];
+               }
+
+               return $filterDefinition;
+       }
+
+       /**
+        * @inheritDoc
+        */
+       protected function registerFilters() {
+               parent::registerFilters();
+
+               if (
+                       !$this->including() &&
+                       $this->getUser()->isLoggedIn() &&
+                       $this->getUser()->isAllowed( 'viewmywatchlist' )
+               ) {
+                       $this->registerFiltersFromDefinitions( [ $this->watchlistFilterGroupDefinition ] );
+                       $watchlistGroup = $this->getFilterGroup( 'watchlist' );
+                       $watchlistGroup->getFilter( 'watched' )->setAsSupersetOf(
+                               $watchlistGroup->getFilter( 'watchednew' )
+                       );
+               }
+
+               $user = $this->getUser();
+
+               $significance = $this->getFilterGroup( 'significance' );
+               $hideMinor = $significance->getFilter( 'hideminor' );
+               $hideMinor->setDefault( $user->getBoolOption( 'hideminor' ) );
+
+               $automated = $this->getFilterGroup( 'automated' );
+               $hideBots = $automated->getFilter( 'hidebots' );
+               $hideBots->setDefault( true );
+
+               $reviewStatus = $this->getFilterGroup( 'reviewStatus' );
+               if ( $reviewStatus !== null ) {
+                       // Conditional on feature being available and rights
+                       if ( $user->getBoolOption( 'hidepatrolled' ) ) {
+                               $reviewStatus->setDefault( 'unpatrolled' );
+                               $legacyReviewStatus = $this->getFilterGroup( 'legacyReviewStatus' );
+                               $legacyHidePatrolled = $legacyReviewStatus->getFilter( 'hidepatrolled' );
+                               $legacyHidePatrolled->setDefault( true );
+                       }
+               }
+
+               $changeType = $this->getFilterGroup( 'changeType' );
+               $hideCategorization = $changeType->getFilter( 'hidecategorization' );
+               if ( $hideCategorization !== null ) {
+                       // Conditional on feature being available
+                       $hideCategorization->setDefault( $user->getBoolOption( 'hidecategorization' ) );
+               }
+       }
+
+       /**
+        * Process $par and put options found in $opts. Used when including the page.
+        *
+        * @param string $par
+        * @param FormOptions $opts
+        */
+       public function parseParameters( $par, FormOptions $opts ) {
+               parent::parseParameters( $par, $opts );
+
+               $bits = preg_split( '/\s*,\s*/', trim( $par ) );
+               foreach ( $bits as $bit ) {
+                       if ( is_numeric( $bit ) ) {
+                               $opts['limit'] = $bit;
+                       }
+
+                       $m = [];
+                       if ( preg_match( '/^limit=(\d+)$/', $bit, $m ) ) {
+                               $opts['limit'] = $m[1];
+                       }
+                       if ( preg_match( '/^days=(\d+(?:\.\d+)?)$/', $bit, $m ) ) {
+                               $opts['days'] = $m[1];
+                       }
+                       if ( preg_match( '/^namespace=(.*)$/', $bit, $m ) ) {
+                               $opts['namespace'] = $m[1];
+                       }
+                       if ( preg_match( '/^tagfilter=(.*)$/', $bit, $m ) ) {
+                               $opts['tagfilter'] = $m[1];
+                       }
+               }
+       }
+
+       /**
+        * @inheritDoc
+        */
+       protected function doMainQuery( $tables, $fields, $conds, $query_options,
+               $join_conds, FormOptions $opts
+       ) {
+               $dbr = $this->getDB();
+               $user = $this->getUser();
+
+               $rcQuery = RecentChange::getQueryInfo();
+               $tables = array_merge( $tables, $rcQuery['tables'] );
+               $fields = array_merge( $rcQuery['fields'], $fields );
+               $join_conds = array_merge( $join_conds, $rcQuery['joins'] );
+
+               // JOIN on watchlist for users
+               if ( $user->isLoggedIn() && $user->isAllowed( 'viewmywatchlist' ) ) {
+                       $tables[] = 'watchlist';
+                       $fields[] = 'wl_user';
+                       $fields[] = 'wl_notificationtimestamp';
+                       $join_conds['watchlist'] = [ 'LEFT JOIN', [
+                               'wl_user' => $user->getId(),
+                               'wl_title=rc_title',
+                               'wl_namespace=rc_namespace'
+                       ] ];
+               }
+
+               // JOIN on page, used for 'last revision' filter highlight
+               $tables[] = 'page';
+               $fields[] = 'page_latest';
+               $join_conds['page'] = [ 'LEFT JOIN', 'rc_cur_id=page_id' ];
+
+               $tagFilter = $opts['tagfilter'] ? explode( '|', $opts['tagfilter'] ) : [];
+               ChangeTags::modifyDisplayQuery(
+                       $tables,
+                       $fields,
+                       $conds,
+                       $join_conds,
+                       $query_options,
+                       $tagFilter
+               );
+
+               if ( !$this->runMainQueryHook( $tables, $fields, $conds, $query_options, $join_conds,
+                       $opts )
+               ) {
+                       return false;
+               }
+
+               if ( $this->areFiltersInConflict() ) {
+                       return false;
+               }
+
+               $orderByAndLimit = [
+                       'ORDER BY' => 'rc_timestamp DESC',
+                       'LIMIT' => $opts['limit']
+               ];
+               if ( in_array( 'DISTINCT', $query_options ) ) {
+                       // ChangeTags::modifyDisplayQuery() adds DISTINCT when filtering on multiple tags.
+                       // In order to prevent DISTINCT from causing query performance problems,
+                       // we have to GROUP BY the primary key. This in turn requires us to add
+                       // the primary key to the end of the ORDER BY, and the old ORDER BY to the
+                       // start of the GROUP BY
+                       $orderByAndLimit['ORDER BY'] = 'rc_timestamp DESC, rc_id DESC';
+                       $orderByAndLimit['GROUP BY'] = 'rc_timestamp, rc_id';
+               }
+               // array_merge() is used intentionally here so that hooks can, should
+               // they so desire, override the ORDER BY / LIMIT condition(s); prior to
+               // MediaWiki 1.26 this used to use the plus operator instead, which meant
+               // that extensions weren't able to change these conditions
+               $query_options = array_merge( $orderByAndLimit, $query_options );
+               $rows = $dbr->select(
+                       $tables,
+                       $fields,
+                       // rc_new is not an ENUM, but adding a redundant rc_new IN (0,1) gives mysql enough
+                       // knowledge to use an index merge if it wants (it may use some other index though).
+                       $conds + [ 'rc_new' => [ 0, 1 ] ],
+                       __METHOD__,
+                       $query_options,
+                       $join_conds
+               );
+
+               return $rows;
+       }
+
+       protected function getDB() {
+               return wfGetDB( DB_REPLICA, 'recentchanges' );
+       }
+
+       public function outputFeedLinks() {
+               $this->addFeedLinks( $this->getFeedQuery() );
+       }
+
+       /**
+        * Get URL query parameters for action=feedrecentchanges API feed of current recent changes view.
+        *
+        * @return array
+        */
+       protected function getFeedQuery() {
+               $query = array_filter( $this->getOptions()->getAllValues(), function ( $value ) {
+                       // API handles empty parameters in a different way
+                       return $value !== '';
+               } );
+               $query['action'] = 'feedrecentchanges';
+               $feedLimit = $this->getConfig()->get( 'FeedLimit' );
+               if ( $query['limit'] > $feedLimit ) {
+                       $query['limit'] = $feedLimit;
+               }
+
+               return $query;
+       }
+
+       /**
+        * Build and output the actual changes list.
+        *
+        * @param IResultWrapper $rows Database rows
+        * @param FormOptions $opts
+        */
+       public function outputChangesList( $rows, $opts ) {
+               $limit = $opts['limit'];
+
+               $showWatcherCount = $this->getConfig()->get( 'RCShowWatchingUsers' )
+                       && $this->getUser()->getOption( 'shownumberswatching' );
+               $watcherCache = [];
+
+               $counter = 1;
+               $list = ChangesList::newFromContext( $this->getContext(), $this->filterGroups );
+               $list->initChangesListRows( $rows );
+
+               $userShowHiddenCats = $this->getUser()->getBoolOption( 'showhiddencats' );
+               $rclistOutput = $list->beginRecentChangesList();
+               if ( $this->isStructuredFilterUiEnabled() ) {
+                       $rclistOutput .= $this->makeLegend();
+               }
+
+               foreach ( $rows as $obj ) {
+                       if ( $limit == 0 ) {
+                               break;
+                       }
+                       $rc = RecentChange::newFromRow( $obj );
+
+                       # Skip CatWatch entries for hidden cats based on user preference
+                       if (
+                               $rc->getAttribute( 'rc_type' ) == RC_CATEGORIZE &&
+                               !$userShowHiddenCats &&
+                               $rc->getParam( 'hidden-cat' )
+                       ) {
+                               continue;
+                       }
+
+                       $rc->counter = $counter++;
+                       # Check if the page has been updated since the last visit
+                       if ( $this->getConfig()->get( 'ShowUpdatedMarker' )
+                               && !empty( $obj->wl_notificationtimestamp )
+                       ) {
+                               $rc->notificationtimestamp = ( $obj->rc_timestamp >= $obj->wl_notificationtimestamp );
+                       } else {
+                               $rc->notificationtimestamp = false; // Default
+                       }
+                       # Check the number of users watching the page
+                       $rc->numberofWatchingusers = 0; // Default
+                       if ( $showWatcherCount && $obj->rc_namespace >= 0 ) {
+                               if ( !isset( $watcherCache[$obj->rc_namespace][$obj->rc_title] ) ) {
+                                       $watcherCache[$obj->rc_namespace][$obj->rc_title] =
+                                               MediaWikiServices::getInstance()->getWatchedItemStore()->countWatchers(
+                                                       new TitleValue( (int)$obj->rc_namespace, $obj->rc_title )
+                                               );
+                               }
+                               $rc->numberofWatchingusers = $watcherCache[$obj->rc_namespace][$obj->rc_title];
+                       }
+
+                       $changeLine = $list->recentChangesLine( $rc, !empty( $obj->wl_user ), $counter );
+                       if ( $changeLine !== false ) {
+                               $rclistOutput .= $changeLine;
+                               --$limit;
+                       }
+               }
+               $rclistOutput .= $list->endRecentChangesList();
+
+               if ( $rows->numRows() === 0 ) {
+                       $this->outputNoResults();
+                       if ( !$this->including() ) {
+                               $this->getOutput()->setStatusCode( 404 );
+                       }
+               } else {
+                       $this->getOutput()->addHTML( $rclistOutput );
+               }
+       }
+
+       /**
+        * Set the text to be displayed above the changes
+        *
+        * @param FormOptions $opts
+        * @param int $numRows Number of rows in the result to show after this header
+        */
+       public function doHeader( $opts, $numRows ) {
+               $this->setTopText( $opts );
+
+               $defaults = $opts->getAllValues();
+               $nondefaults = $opts->getChangedValues();
+
+               $panel = [];
+               if ( !$this->isStructuredFilterUiEnabled() ) {
+                       $panel[] = $this->makeLegend();
+               }
+               $panel[] = $this->optionsPanel( $defaults, $nondefaults, $numRows );
+               $panel[] = '<hr />';
+
+               $extraOpts = $this->getExtraOptions( $opts );
+               $extraOptsCount = count( $extraOpts );
+               $count = 0;
+               $submit = ' ' . Xml::submitButton( $this->msg( 'recentchanges-submit' )->text() );
+
+               $out = Xml::openElement( 'table', [ 'class' => 'mw-recentchanges-table' ] );
+               foreach ( $extraOpts as $name => $optionRow ) {
+                       # Add submit button to the last row only
+                       ++$count;
+                       $addSubmit = ( $count === $extraOptsCount ) ? $submit : '';
+
+                       $out .= Xml::openElement( 'tr', [ 'class' => $name . 'Form' ] );
+                       if ( is_array( $optionRow ) ) {
+                               $out .= Xml::tags(
+                                       'td',
+                                       [ 'class' => 'mw-label mw-' . $name . '-label' ],
+                                       $optionRow[0]
+                               );
+                               $out .= Xml::tags(
+                                       'td',
+                                       [ 'class' => 'mw-input' ],
+                                       $optionRow[1] . $addSubmit
+                               );
+                       } else {
+                               $out .= Xml::tags(
+                                       'td',
+                                       [ 'class' => 'mw-input', 'colspan' => 2 ],
+                                       $optionRow . $addSubmit
+                               );
+                       }
+                       $out .= Xml::closeElement( 'tr' );
+               }
+               $out .= Xml::closeElement( 'table' );
+
+               $unconsumed = $opts->getUnconsumedValues();
+               foreach ( $unconsumed as $key => $value ) {
+                       $out .= Html::hidden( $key, $value );
+               }
+
+               $t = $this->getPageTitle();
+               $out .= Html::hidden( 'title', $t->getPrefixedText() );
+               $form = Xml::tags( 'form', [ 'action' => wfScript() ], $out );
+               $panel[] = $form;
+               $panelString = implode( "\n", $panel );
+
+               $rcoptions = Xml::fieldset(
+                       $this->msg( 'recentchanges-legend' )->text(),
+                       $panelString,
+                       [ 'class' => 'rcoptions cloptions' ]
+               );
+
+               // Insert a placeholder for RCFilters
+               if ( $this->isStructuredFilterUiEnabled() ) {
+                       $rcfilterContainer = Html::element(
+                               'div',
+                               // TODO: Remove deprecated rcfilters-container class
+                               [ 'class' => 'rcfilters-container mw-rcfilters-container' ]
+                       );
+
+                       $loadingContainer = Html::rawElement(
+                               'div',
+                               [ 'class' => 'mw-rcfilters-spinner' ],
+                               Html::element(
+                                       'div',
+                                       [ 'class' => 'mw-rcfilters-spinner-bounce' ]
+                               )
+                       );
+
+                       // Wrap both with rcfilters-head
+                       $this->getOutput()->addHTML(
+                               Html::rawElement(
+                                       'div',
+                                       // TODO: Remove deprecated rcfilters-head class
+                                       [ 'class' => 'rcfilters-head mw-rcfilters-head' ],
+                                       $rcfilterContainer . $rcoptions
+                               )
+                       );
+
+                       // Add spinner
+                       $this->getOutput()->addHTML( $loadingContainer );
+               } else {
+                       $this->getOutput()->addHTML( $rcoptions );
+               }
+
+               $this->setBottomText( $opts );
+       }
+
+       /**
+        * Send the text to be displayed above the options
+        *
+        * @param FormOptions $opts Unused
+        */
+       function setTopText( FormOptions $opts ) {
+               $message = $this->msg( 'recentchangestext' )->inContentLanguage();
+               if ( !$message->isDisabled() ) {
+                       $contLang = MediaWikiServices::getInstance()->getContentLanguage();
+                       // Parse the message in this weird ugly way to preserve the ability to include interlanguage
+                       // links in it (T172461). In the future when T66969 is resolved, perhaps we can just use
+                       // $message->parse() instead. This code is copied from Message::parseText().
+                       $parserOutput = MessageCache::singleton()->parse(
+                               $message->plain(),
+                               $this->getPageTitle(),
+                               /*linestart*/true,
+                               // Message class sets the interface flag to false when parsing in a language different than
+                               // user language, and this is wiki content language
+                               /*interface*/false,
+                               $contLang
+                       );
+                       $content = $parserOutput->getText( [
+                               'enableSectionEditLinks' => false,
+                       ] );
+                       // Add only metadata here (including the language links), text is added below
+                       $this->getOutput()->addParserOutputMetadata( $parserOutput );
+
+                       $langAttributes = [
+                               'lang' => $contLang->getHtmlCode(),
+                               'dir' => $contLang->getDir(),
+                       ];
+
+                       $topLinksAttributes = [ 'class' => 'mw-recentchanges-toplinks' ];
+
+                       if ( $this->isStructuredFilterUiEnabled() ) {
+                               // Check whether the widget is already collapsed or expanded
+                               $collapsedState = $this->getRequest()->getCookie( 'rcfilters-toplinks-collapsed-state' );
+                               // Note that an empty/unset cookie means collapsed, so check for !== 'expanded'
+                               $topLinksAttributes[ 'class' ] .= $collapsedState !== 'expanded' ?
+                                       ' mw-recentchanges-toplinks-collapsed' : '';
+
+                               $this->getOutput()->enableOOUI();
+                               $contentTitle = new OOUI\ButtonWidget( [
+                                       'classes' => [ 'mw-recentchanges-toplinks-title' ],
+                                       'label' => new OOUI\HtmlSnippet( $this->msg( 'rcfilters-other-review-tools' )->parse() ),
+                                       'framed' => false,
+                                       'indicator' => $collapsedState !== 'expanded' ? 'down' : 'up',
+                                       'flags' => [ 'progressive' ],
+                               ] );
+
+                               $contentWrapper = Html::rawElement( 'div',
+                                       array_merge(
+                                               [ 'class' => 'mw-recentchanges-toplinks-content mw-collapsible-content' ],
+                                               $langAttributes
+                                       ),
+                                       $content
+                               );
+                               $content = $contentTitle . $contentWrapper;
+                       } else {
+                               // Language direction should be on the top div only
+                               // if the title is not there. If it is there, it's
+                               // interface direction, and the language/dir attributes
+                               // should be on the content itself
+                               $topLinksAttributes = array_merge( $topLinksAttributes, $langAttributes );
+                       }
+
+                       $this->getOutput()->addHTML(
+                               Html::rawElement( 'div', $topLinksAttributes, $content )
+                       );
+               }
+       }
+
+       /**
+        * Get options to be displayed in a form
+        *
+        * @param FormOptions $opts
+        * @return array
+        */
+       function getExtraOptions( $opts ) {
+               $opts->consumeValues( [
+                       'namespace', 'invert', 'associated', 'tagfilter'
+               ] );
+
+               $extraOpts = [];
+               $extraOpts['namespace'] = $this->namespaceFilterForm( $opts );
+
+               $tagFilter = ChangeTags::buildTagFilterSelector(
+                       $opts['tagfilter'], false, $this->getContext() );
+               if ( count( $tagFilter ) ) {
+                       $extraOpts['tagfilter'] = $tagFilter;
+               }
+
+               // Don't fire the hook for subclasses. (Or should we?)
+               if ( $this->getName() === 'Recentchanges' ) {
+                       Hooks::run( 'SpecialRecentChangesPanel', [ &$extraOpts, $opts ] );
+               }
+
+               return $extraOpts;
+       }
+
+       /**
+        * Add page-specific modules.
+        */
+       protected function addModules() {
+               parent::addModules();
+               $out = $this->getOutput();
+               $out->addModules( 'mediawiki.special.recentchanges' );
+       }
+
+       /**
+        * Get last modified date, for client caching
+        * Don't use this if we are using the patrol feature, patrol changes don't
+        * update the timestamp
+        *
+        * @return string|bool
+        */
+       public function checkLastModified() {
+               $dbr = $this->getDB();
+               $lastmod = $dbr->selectField( 'recentchanges', 'MAX(rc_timestamp)', '', __METHOD__ );
+
+               return $lastmod;
+       }
+
+       /**
+        * Creates the choose namespace selection
+        *
+        * @param FormOptions $opts
+        * @return string[]
+        */
+       protected function namespaceFilterForm( FormOptions $opts ) {
+               $nsSelect = Html::namespaceSelector(
+                       [ 'selected' => $opts['namespace'], 'all' => '', 'in-user-lang' => true ],
+                       [ 'name' => 'namespace', 'id' => 'namespace' ]
+               );
+               $nsLabel = Xml::label( $this->msg( 'namespace' )->text(), 'namespace' );
+               $attribs = [ 'class' => [ 'mw-input-with-label' ] ];
+               // Hide the checkboxes when the namespace filter is set to 'all'.
+               if ( $opts['namespace'] === '' ) {
+                       $attribs['class'][] = 'mw-input-hidden';
+               }
+               $invert = Html::rawElement( 'span', $attribs, Xml::checkLabel(
+                       $this->msg( 'invert' )->text(), 'invert', 'nsinvert',
+                       $opts['invert'],
+                       [ 'title' => $this->msg( 'tooltip-invert' )->text() ]
+               ) );
+               $associated = Html::rawElement( 'span', $attribs, Xml::checkLabel(
+                       $this->msg( 'namespace_association' )->text(), 'associated', 'nsassociated',
+                       $opts['associated'],
+                       [ 'title' => $this->msg( 'tooltip-namespace_association' )->text() ]
+               ) );
+
+               return [ $nsLabel, "$nsSelect $invert $associated" ];
+       }
+
+       /**
+        * Filter $rows by categories set in $opts
+        *
+        * @deprecated since 1.31
+        *
+        * @param IResultWrapper &$rows Database rows
+        * @param FormOptions $opts
+        */
+       function filterByCategories( &$rows, FormOptions $opts ) {
+               wfDeprecated( __METHOD__, '1.31' );
+
+               $categories = array_map( 'trim', explode( '|', $opts['categories'] ) );
+
+               if ( $categories === [] ) {
+                       return;
+               }
+
+               # Filter categories
+               $cats = [];
+               foreach ( $categories as $cat ) {
+                       $cat = trim( $cat );
+                       if ( $cat == '' ) {
+                               continue;
+                       }
+                       $cats[] = $cat;
+               }
+
+               # Filter articles
+               $articles = [];
+               $a2r = [];
+               $rowsarr = [];
+               foreach ( $rows as $k => $r ) {
+                       $nt = Title::makeTitle( $r->rc_namespace, $r->rc_title );
+                       $id = $nt->getArticleID();
+                       if ( $id == 0 ) {
+                               continue; # Page might have been deleted...
+                       }
+                       if ( !in_array( $id, $articles ) ) {
+                               $articles[] = $id;
+                       }
+                       if ( !isset( $a2r[$id] ) ) {
+                               $a2r[$id] = [];
+                       }
+                       $a2r[$id][] = $k;
+                       $rowsarr[$k] = $r;
+               }
+
+               # Shortcut?
+               if ( $articles === [] || $cats === [] ) {
+                       return;
+               }
+
+               # Look up
+               $catFind = new CategoryFinder;
+               $catFind->seed( $articles, $cats, $opts['categories_any'] ? 'OR' : 'AND' );
+               $match = $catFind->run();
+
+               # Filter
+               $newrows = [];
+               foreach ( $match as $id ) {
+                       foreach ( $a2r[$id] as $rev ) {
+                               $k = $rev;
+                               $newrows[$k] = $rowsarr[$k];
+                       }
+               }
+               $rows = new FakeResultWrapper( array_values( $newrows ) );
+       }
+
+       /**
+        * Makes change an option link which carries all the other options
+        *
+        * @param string $title
+        * @param array $override Options to override
+        * @param array $options Current options
+        * @param bool $active Whether to show the link in bold
+        * @return string
+        */
+       function makeOptionsLink( $title, $override, $options, $active = false ) {
+               $params = $this->convertParamsForLink( $override + $options );
+
+               if ( $active ) {
+                       $title = new HtmlArmor( '<strong>' . htmlspecialchars( $title ) . '</strong>' );
+               }
+
+               return $this->getLinkRenderer()->makeKnownLink( $this->getPageTitle(), $title, [
+                       'data-params' => json_encode( $override ),
+                       'data-keys' => implode( ',', array_keys( $override ) ),
+               ], $params );
+       }
+
+       /**
+        * Creates the options panel.
+        *
+        * @param array $defaults
+        * @param array $nondefaults
+        * @param int $numRows Number of rows in the result to show after this header
+        * @return string
+        */
+       function optionsPanel( $defaults, $nondefaults, $numRows ) {
+               $options = $nondefaults + $defaults;
+
+               $note = '';
+               $msg = $this->msg( 'rclegend' );
+               if ( !$msg->isDisabled() ) {
+                       $note .= Html::rawElement(
+                               'div',
+                               [ 'class' => 'mw-rclegend' ],
+                               $msg->parse()
+                       );
+               }
+
+               $lang = $this->getLanguage();
+               $user = $this->getUser();
+               $config = $this->getConfig();
+               if ( $options['from'] ) {
+                       $resetLink = $this->makeOptionsLink( $this->msg( 'rclistfromreset' ),
+                               [ 'from' => '' ], $nondefaults );
+
+                       $noteFromMsg = $this->msg( 'rcnotefrom' )
+                               ->numParams( $options['limit'] )
+                               ->params(
+                                       $lang->userTimeAndDate( $options['from'], $user ),
+                                       $lang->userDate( $options['from'], $user ),
+                                       $lang->userTime( $options['from'], $user )
+                               )
+                               ->numParams( $numRows );
+                       $note .= Html::rawElement(
+                                       'span',
+                                       [ 'class' => 'rcnotefrom' ],
+                                       $noteFromMsg->parse()
+                               ) .
+                               ' ' .
+                               Html::rawElement(
+                                       'span',
+                                       [ 'class' => 'rcoptions-listfromreset' ],
+                                       $this->msg( 'parentheses' )->rawParams( $resetLink )->parse()
+                               ) .
+                               '<br />';
+               }
+
+               # Sort data for display and make sure it's unique after we've added user data.
+               $linkLimits = $config->get( 'RCLinkLimits' );
+               $linkLimits[] = $options['limit'];
+               sort( $linkLimits );
+               $linkLimits = array_unique( $linkLimits );
+
+               $linkDays = $config->get( 'RCLinkDays' );
+               $linkDays[] = $options['days'];
+               sort( $linkDays );
+               $linkDays = array_unique( $linkDays );
+
+               // limit links
+               $cl = [];
+               foreach ( $linkLimits as $value ) {
+                       $cl[] = $this->makeOptionsLink( $lang->formatNum( $value ),
+                               [ 'limit' => $value ], $nondefaults, $value == $options['limit'] );
+               }
+               $cl = $lang->pipeList( $cl );
+
+               // day links, reset 'from' to none
+               $dl = [];
+               foreach ( $linkDays as $value ) {
+                       $dl[] = $this->makeOptionsLink( $lang->formatNum( $value ),
+                               [ 'days' => $value, 'from' => '' ], $nondefaults, $value == $options['days'] );
+               }
+               $dl = $lang->pipeList( $dl );
+
+               $showhide = [ 'show', 'hide' ];
+
+               $links = [];
+
+               foreach ( $this->getLegacyShowHideFilters() as $key => $filter ) {
+                       $msg = $filter->getShowHide();
+                       $linkMessage = $this->msg( $msg . '-' . $showhide[1 - $options[$key]] );
+                       // Extensions can define additional filters, but don't need to define the corresponding
+                       // messages. If they don't exist, just fall back to 'show' and 'hide'.
+                       if ( !$linkMessage->exists() ) {
+                               $linkMessage = $this->msg( $showhide[1 - $options[$key]] );
+                       }
+
+                       $link = $this->makeOptionsLink( $linkMessage->text(),
+                               [ $key => 1 - $options[$key] ], $nondefaults );
+
+                       $attribs = [
+                               'class' => "$msg rcshowhideoption clshowhideoption",
+                               'data-filter-name' => $filter->getName(),
+                       ];
+
+                       if ( $filter->isFeatureAvailableOnStructuredUi( $this ) ) {
+                               $attribs['data-feature-in-structured-ui'] = true;
+                       }
+
+                       $links[] = Html::rawElement(
+                               'span',
+                               $attribs,
+                               $this->msg( $msg )->rawParams( $link )->parse()
+                       );
+               }
+
+               // show from this onward link
+               $timestamp = wfTimestampNow();
+               $now = $lang->userTimeAndDate( $timestamp, $user );
+               $timenow = $lang->userTime( $timestamp, $user );
+               $datenow = $lang->userDate( $timestamp, $user );
+               $pipedLinks = '<span class="rcshowhide">' . $lang->pipeList( $links ) . '</span>';
+
+               $rclinks = Html::rawElement(
+                       'span',
+                       [ 'class' => 'rclinks' ],
+                       $this->msg( 'rclinks' )->rawParams( $cl, $dl, '' )->parse()
+               );
+
+               $rclistfrom = Html::rawElement(
+                       'span',
+                       [ 'class' => 'rclistfrom' ],
+                       $this->makeOptionsLink(
+                               $this->msg( 'rclistfrom' )->plaintextParams( $now, $timenow, $datenow )->parse(),
+                               [ 'from' => $timestamp, 'fromFormatted' => $now ],
+                               $nondefaults
+                       )
+               );
+
+               return "{$note}$rclinks<br />$pipedLinks<br />$rclistfrom";
+       }
+
+       public function isIncludable() {
+               return true;
+       }
+
+       protected function getCacheTTL() {
+               return 60 * 5;
+       }
+
+       public function getDefaultLimit() {
+               $systemPrefValue = $this->getUser()->getIntOption( 'rclimit' );
+               // Prefer the RCFilters-specific preference if RCFilters is enabled
+               if ( $this->isStructuredFilterUiEnabled() ) {
+                       return $this->getUser()->getIntOption( static::$limitPreferenceName, $systemPrefValue );
+               }
+
+               // Otherwise, use the system rclimit preference value
+               return $systemPrefValue;
+       }
+}
diff --git a/includes/specials/SpecialRecentChangesLinked.php b/includes/specials/SpecialRecentChangesLinked.php
new file mode 100644 (file)
index 0000000..8865654
--- /dev/null
@@ -0,0 +1,319 @@
+<?php
+/**
+ * Implements Special:Recentchangeslinked
+ *
+ * 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
+ */
+
+/**
+ * This is to display changes made to all articles linked in an article.
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialRecentChangesLinked extends SpecialRecentChanges {
+       /** @var bool|Title */
+       protected $rclTargetTitle;
+
+       function __construct() {
+               parent::__construct( 'Recentchangeslinked' );
+       }
+
+       public function getDefaultOptions() {
+               $opts = parent::getDefaultOptions();
+               $opts->add( 'target', '' );
+               $opts->add( 'showlinkedto', false );
+
+               return $opts;
+       }
+
+       public function parseParameters( $par, FormOptions $opts ) {
+               $opts['target'] = $par;
+       }
+
+       /**
+        * @inheritDoc
+        */
+       protected function doMainQuery( $tables, $select, $conds, $query_options,
+               $join_conds, FormOptions $opts
+       ) {
+               $target = $opts['target'];
+               $showlinkedto = $opts['showlinkedto'];
+               $limit = $opts['limit'];
+
+               if ( $target === '' ) {
+                       return false;
+               }
+               $outputPage = $this->getOutput();
+               $title = Title::newFromText( $target );
+               if ( !$title || $title->isExternal() ) {
+                       $outputPage->addHTML(
+                               Html::errorBox( $this->msg( 'allpagesbadtitle' )->parse() )
+                       );
+                       return false;
+               }
+
+               $outputPage->setPageTitle( $this->msg( 'recentchangeslinked-title', $title->getPrefixedText() ) );
+
+               /*
+                * Ordinary links are in the pagelinks table, while transclusions are
+                * in the templatelinks table, categorizations in categorylinks and
+                * image use in imagelinks.  We need to somehow combine all these.
+                * Special:Whatlinkshere does this by firing multiple queries and
+                * merging the results, but the code we inherit from our parent class
+                * expects only one result set so we use UNION instead.
+                */
+
+               $dbr = wfGetDB( DB_REPLICA, 'recentchangeslinked' );
+               $id = $title->getArticleID();
+               $ns = $title->getNamespace();
+               $dbkey = $title->getDBkey();
+
+               $rcQuery = RecentChange::getQueryInfo();
+               $tables = array_merge( $tables, $rcQuery['tables'] );
+               $select = array_merge( $rcQuery['fields'], $select );
+               $join_conds = array_merge( $join_conds, $rcQuery['joins'] );
+
+               // left join with watchlist table to highlight watched rows
+               $uid = $this->getUser()->getId();
+               if ( $uid && $this->getUser()->isAllowed( 'viewmywatchlist' ) ) {
+                       $tables[] = 'watchlist';
+                       $select[] = 'wl_user';
+                       $join_conds['watchlist'] = [ 'LEFT JOIN', [
+                               'wl_user' => $uid,
+                               'wl_title=rc_title',
+                               'wl_namespace=rc_namespace'
+                       ] ];
+               }
+
+               // JOIN on page, used for 'last revision' filter highlight
+               $tables[] = 'page';
+               $join_conds['page'] = [ 'LEFT JOIN', 'rc_cur_id=page_id' ];
+               $select[] = 'page_latest';
+
+               $tagFilter = $opts['tagfilter'] ? explode( '|', $opts['tagfilter'] ) : [];
+               ChangeTags::modifyDisplayQuery(
+                       $tables,
+                       $select,
+                       $conds,
+                       $join_conds,
+                       $query_options,
+                       $tagFilter
+               );
+
+               if ( $dbr->unionSupportsOrderAndLimit() ) {
+                       if ( count( $tagFilter ) > 1 ) {
+                               // ChangeTags::modifyDisplayQuery() will have added DISTINCT.
+                               // To prevent this from causing query performance problems, we need to add
+                               // a GROUP BY, and add rc_id to the ORDER BY.
+                               $order = [
+                                       'GROUP BY' => 'rc_timestamp, rc_id',
+                                       'ORDER BY' => 'rc_timestamp DESC, rc_id DESC'
+                               ];
+                       } else {
+                               $order = [ 'ORDER BY' => 'rc_timestamp DESC' ];
+                       }
+               } else {
+                       $order = [];
+               }
+
+               if ( !$this->runMainQueryHook( $tables, $select, $conds, $query_options, $join_conds,
+                       $opts )
+               ) {
+                       return false;
+               }
+
+               if ( $ns == NS_CATEGORY && !$showlinkedto ) {
+                       // special handling for categories
+                       // XXX: should try to make this less kludgy
+                       $link_tables = [ 'categorylinks' ];
+                       $showlinkedto = true;
+               } else {
+                       // for now, always join on these tables; really should be configurable as in whatlinkshere
+                       $link_tables = [ 'pagelinks', 'templatelinks' ];
+                       // imagelinks only contains links to pages in NS_FILE
+                       if ( $ns == NS_FILE || !$showlinkedto ) {
+                               $link_tables[] = 'imagelinks';
+                       }
+               }
+
+               if ( $id == 0 && !$showlinkedto ) {
+                       return false; // nonexistent pages can't link to any pages
+               }
+
+               // field name prefixes for all the various tables we might want to join with
+               $prefix = [
+                       'pagelinks' => 'pl',
+                       'templatelinks' => 'tl',
+                       'categorylinks' => 'cl',
+                       'imagelinks' => 'il'
+               ];
+
+               $subsql = []; // SELECT statements to combine with UNION
+
+               foreach ( $link_tables as $link_table ) {
+                       $pfx = $prefix[$link_table];
+
+                       // imagelinks and categorylinks tables have no xx_namespace field,
+                       // and have xx_to instead of xx_title
+                       if ( $link_table == 'imagelinks' ) {
+                               $link_ns = NS_FILE;
+                       } elseif ( $link_table == 'categorylinks' ) {
+                               $link_ns = NS_CATEGORY;
+                       } else {
+                               $link_ns = 0;
+                       }
+
+                       if ( $showlinkedto ) {
+                               // find changes to pages linking to this page
+                               if ( $link_ns ) {
+                                       if ( $ns != $link_ns ) {
+                                               continue;
+                                       } // should never happen, but check anyway
+                                       $subconds = [ "{$pfx}_to" => $dbkey ];
+                               } else {
+                                       $subconds = [ "{$pfx}_namespace" => $ns, "{$pfx}_title" => $dbkey ];
+                               }
+                               $subjoin = "rc_cur_id = {$pfx}_from";
+                       } else {
+                               // find changes to pages linked from this page
+                               $subconds = [ "{$pfx}_from" => $id ];
+                               if ( $link_table == 'imagelinks' || $link_table == 'categorylinks' ) {
+                                       $subconds["rc_namespace"] = $link_ns;
+                                       $subjoin = "rc_title = {$pfx}_to";
+                               } else {
+                                       $subjoin = [ "rc_namespace = {$pfx}_namespace", "rc_title = {$pfx}_title" ];
+                               }
+                       }
+
+                       $query = $dbr->selectSQLText(
+                               array_merge( $tables, [ $link_table ] ),
+                               $select,
+                               $conds + $subconds,
+                               __METHOD__,
+                               $order + $query_options,
+                               $join_conds + [ $link_table => [ 'JOIN', $subjoin ] ]
+                       );
+
+                       if ( $dbr->unionSupportsOrderAndLimit() ) {
+                               $query = $dbr->limitResult( $query, $limit );
+                       }
+
+                       $subsql[] = $query;
+               }
+
+               if ( count( $subsql ) == 0 ) {
+                       return false; // should never happen
+               }
+               if ( count( $subsql ) == 1 && $dbr->unionSupportsOrderAndLimit() ) {
+                       $sql = $subsql[0];
+               } else {
+                       // need to resort and relimit after union
+                       $sql = $dbr->unionQueries( $subsql, $dbr::UNION_DISTINCT ) .
+                               ' ORDER BY rc_timestamp DESC';
+                       $sql = $dbr->limitResult( $sql, $limit, false );
+               }
+
+               $res = $dbr->query( $sql, __METHOD__ );
+
+               if ( $res->numRows() == 0 ) {
+                       $this->mResultEmpty = true;
+               }
+
+               return $res;
+       }
+
+       function setTopText( FormOptions $opts ) {
+               $target = $this->getTargetTitle();
+               if ( $target ) {
+                       $this->getOutput()->addBacklinkSubtitle( $target );
+                       $this->getSkin()->setRelevantTitle( $target );
+               }
+       }
+
+       /**
+        * Get options to be displayed in a form
+        *
+        * @param FormOptions $opts
+        * @return array
+        */
+       function getExtraOptions( $opts ) {
+               $extraOpts = parent::getExtraOptions( $opts );
+
+               $opts->consumeValues( [ 'showlinkedto', 'target' ] );
+
+               $extraOpts['target'] = [ $this->msg( 'recentchangeslinked-page' )->escaped(),
+                       Xml::input( 'target', 40, str_replace( '_', ' ', $opts['target'] ) ) .
+                       Xml::check( 'showlinkedto', $opts['showlinkedto'], [ 'id' => 'showlinkedto' ] ) . ' ' .
+                       Xml::label( $this->msg( 'recentchangeslinked-to' )->text(), 'showlinkedto' ) ];
+
+               $this->addHelpLink( 'Help:Related changes' );
+               return $extraOpts;
+       }
+
+       /**
+        * @return Title
+        */
+       function getTargetTitle() {
+               if ( $this->rclTargetTitle === null ) {
+                       $opts = $this->getOptions();
+                       if ( isset( $opts['target'] ) && $opts['target'] !== '' ) {
+                               $this->rclTargetTitle = Title::newFromText( $opts['target'] );
+                       } else {
+                               $this->rclTargetTitle = false;
+                       }
+               }
+
+               return $this->rclTargetTitle;
+       }
+
+       /**
+        * Return an array of subpages beginning with $search that this special page will accept.
+        *
+        * @param string $search Prefix to search for
+        * @param int $limit Maximum number of results to return (usually 10)
+        * @param int $offset Number of results to skip (usually 0)
+        * @return string[] Matching subpages
+        */
+       public function prefixSearchSubpages( $search, $limit, $offset ) {
+               return $this->prefixSearchString( $search, $limit, $offset );
+       }
+
+       protected function outputNoResults() {
+               $targetTitle = $this->getTargetTitle();
+               if ( $targetTitle === false ) {
+                       $this->getOutput()->addHTML(
+                               Html::rawElement(
+                                       'div',
+                                       [ 'class' => 'mw-changeslist-empty mw-changeslist-notargetpage' ],
+                                       $this->msg( 'recentchanges-notargetpage' )->parse()
+                               )
+                       );
+               } elseif ( !$targetTitle || $targetTitle->isExternal() ) {
+                       $this->getOutput()->addHTML(
+                               Html::rawElement(
+                                       'div',
+                                       [ 'class' => 'mw-changeslist-empty mw-changeslist-invalidtargetpage' ],
+                                       $this->msg( 'allpagesbadtitle' )->parse()
+                               )
+                       );
+               } else {
+                       parent::outputNoResults();
+               }
+       }
+}
diff --git a/includes/specials/SpecialRecentchanges.php b/includes/specials/SpecialRecentchanges.php
deleted file mode 100644 (file)
index 46b5520..0000000
+++ /dev/null
@@ -1,947 +0,0 @@
-<?php
-/**
- * Implements Special:Recentchanges
- *
- * 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\FakeResultWrapper;
-
-/**
- * A special page that lists last changes made to the wiki
- *
- * @ingroup SpecialPage
- */
-class SpecialRecentChanges extends ChangesListSpecialPage {
-
-       protected static $savedQueriesPreferenceName = 'rcfilters-saved-queries';
-       protected static $daysPreferenceName = 'rcdays'; // Use general RecentChanges preference
-       protected static $limitPreferenceName = 'rcfilters-limit'; // Use RCFilters-specific preference
-       protected static $collapsedPreferenceName = 'rcfilters-rc-collapsed';
-
-       private $watchlistFilterGroupDefinition;
-
-       public function __construct( $name = 'Recentchanges', $restriction = '' ) {
-               parent::__construct( $name, $restriction );
-
-               $this->watchlistFilterGroupDefinition = [
-                       'name' => 'watchlist',
-                       'title' => 'rcfilters-filtergroup-watchlist',
-                       'class' => ChangesListStringOptionsFilterGroup::class,
-                       'priority' => -9,
-                       'isFullCoverage' => true,
-                       'filters' => [
-                               [
-                                       'name' => 'watched',
-                                       'label' => 'rcfilters-filter-watchlist-watched-label',
-                                       'description' => 'rcfilters-filter-watchlist-watched-description',
-                                       'cssClassSuffix' => 'watched',
-                                       'isRowApplicableCallable' => function ( $ctx, $rc ) {
-                                               return $rc->getAttribute( 'wl_user' );
-                                       }
-                               ],
-                               [
-                                       'name' => 'watchednew',
-                                       'label' => 'rcfilters-filter-watchlist-watchednew-label',
-                                       'description' => 'rcfilters-filter-watchlist-watchednew-description',
-                                       'cssClassSuffix' => 'watchednew',
-                                       'isRowApplicableCallable' => function ( $ctx, $rc ) {
-                                               return $rc->getAttribute( 'wl_user' ) &&
-                                                       $rc->getAttribute( 'rc_timestamp' ) &&
-                                                       $rc->getAttribute( 'wl_notificationtimestamp' ) &&
-                                                       $rc->getAttribute( 'rc_timestamp' ) >= $rc->getAttribute( 'wl_notificationtimestamp' );
-                                       },
-                               ],
-                               [
-                                       'name' => 'notwatched',
-                                       'label' => 'rcfilters-filter-watchlist-notwatched-label',
-                                       'description' => 'rcfilters-filter-watchlist-notwatched-description',
-                                       'cssClassSuffix' => 'notwatched',
-                                       'isRowApplicableCallable' => function ( $ctx, $rc ) {
-                                               return $rc->getAttribute( 'wl_user' ) === null;
-                                       },
-                               ]
-                       ],
-                       'default' => ChangesListStringOptionsFilterGroup::NONE,
-                       'queryCallable' => function ( $specialPageClassName, $context, $dbr,
-                               &$tables, &$fields, &$conds, &$query_options, &$join_conds, $selectedValues ) {
-                               sort( $selectedValues );
-                               $notwatchedCond = 'wl_user IS NULL';
-                               $watchedCond = 'wl_user IS NOT NULL';
-                               $newCond = 'rc_timestamp >= wl_notificationtimestamp';
-
-                               if ( $selectedValues === [ 'notwatched' ] ) {
-                                       $conds[] = $notwatchedCond;
-                                       return;
-                               }
-
-                               if ( $selectedValues === [ 'watched' ] ) {
-                                       $conds[] = $watchedCond;
-                                       return;
-                               }
-
-                               if ( $selectedValues === [ 'watchednew' ] ) {
-                                       $conds[] = $dbr->makeList( [
-                                               $watchedCond,
-                                               $newCond
-                                       ], LIST_AND );
-                                       return;
-                               }
-
-                               if ( $selectedValues === [ 'notwatched', 'watched' ] ) {
-                                       // no filters
-                                       return;
-                               }
-
-                               if ( $selectedValues === [ 'notwatched', 'watchednew' ] ) {
-                                       $conds[] = $dbr->makeList( [
-                                               $notwatchedCond,
-                                               $dbr->makeList( [
-                                                       $watchedCond,
-                                                       $newCond
-                                               ], LIST_AND )
-                                       ], LIST_OR );
-                                       return;
-                               }
-
-                               if ( $selectedValues === [ 'watched', 'watchednew' ] ) {
-                                       $conds[] = $watchedCond;
-                                       return;
-                               }
-
-                               if ( $selectedValues === [ 'notwatched', 'watched', 'watchednew' ] ) {
-                                       // no filters
-                                       return;
-                               }
-                       }
-               ];
-       }
-
-       /**
-        * Main execution point
-        *
-        * @param string $subpage
-        */
-       public function execute( $subpage ) {
-               // Backwards-compatibility: redirect to new feed URLs
-               $feedFormat = $this->getRequest()->getVal( 'feed' );
-               if ( !$this->including() && $feedFormat ) {
-                       $query = $this->getFeedQuery();
-                       $query['feedformat'] = $feedFormat === 'atom' ? 'atom' : 'rss';
-                       $this->getOutput()->redirect( wfAppendQuery( wfScript( 'api' ), $query ) );
-
-                       return;
-               }
-
-               // 10 seconds server-side caching max
-               $out = $this->getOutput();
-               $out->setCdnMaxage( 10 );
-               // Check if the client has a cached version
-               $lastmod = $this->checkLastModified();
-               if ( $lastmod === false ) {
-                       return;
-               }
-
-               $this->addHelpLink(
-                       '//meta.wikimedia.org/wiki/Special:MyLanguage/Help:Recent_changes',
-                       true
-               );
-               parent::execute( $subpage );
-       }
-
-       /**
-        * @inheritDoc
-        */
-       protected function transformFilterDefinition( array $filterDefinition ) {
-               if ( isset( $filterDefinition['showHideSuffix'] ) ) {
-                       $filterDefinition['showHide'] = 'rc' . $filterDefinition['showHideSuffix'];
-               }
-
-               return $filterDefinition;
-       }
-
-       /**
-        * @inheritDoc
-        */
-       protected function registerFilters() {
-               parent::registerFilters();
-
-               if (
-                       !$this->including() &&
-                       $this->getUser()->isLoggedIn() &&
-                       $this->getUser()->isAllowed( 'viewmywatchlist' )
-               ) {
-                       $this->registerFiltersFromDefinitions( [ $this->watchlistFilterGroupDefinition ] );
-                       $watchlistGroup = $this->getFilterGroup( 'watchlist' );
-                       $watchlistGroup->getFilter( 'watched' )->setAsSupersetOf(
-                               $watchlistGroup->getFilter( 'watchednew' )
-                       );
-               }
-
-               $user = $this->getUser();
-
-               $significance = $this->getFilterGroup( 'significance' );
-               $hideMinor = $significance->getFilter( 'hideminor' );
-               $hideMinor->setDefault( $user->getBoolOption( 'hideminor' ) );
-
-               $automated = $this->getFilterGroup( 'automated' );
-               $hideBots = $automated->getFilter( 'hidebots' );
-               $hideBots->setDefault( true );
-
-               $reviewStatus = $this->getFilterGroup( 'reviewStatus' );
-               if ( $reviewStatus !== null ) {
-                       // Conditional on feature being available and rights
-                       if ( $user->getBoolOption( 'hidepatrolled' ) ) {
-                               $reviewStatus->setDefault( 'unpatrolled' );
-                               $legacyReviewStatus = $this->getFilterGroup( 'legacyReviewStatus' );
-                               $legacyHidePatrolled = $legacyReviewStatus->getFilter( 'hidepatrolled' );
-                               $legacyHidePatrolled->setDefault( true );
-                       }
-               }
-
-               $changeType = $this->getFilterGroup( 'changeType' );
-               $hideCategorization = $changeType->getFilter( 'hidecategorization' );
-               if ( $hideCategorization !== null ) {
-                       // Conditional on feature being available
-                       $hideCategorization->setDefault( $user->getBoolOption( 'hidecategorization' ) );
-               }
-       }
-
-       /**
-        * Process $par and put options found in $opts. Used when including the page.
-        *
-        * @param string $par
-        * @param FormOptions $opts
-        */
-       public function parseParameters( $par, FormOptions $opts ) {
-               parent::parseParameters( $par, $opts );
-
-               $bits = preg_split( '/\s*,\s*/', trim( $par ) );
-               foreach ( $bits as $bit ) {
-                       if ( is_numeric( $bit ) ) {
-                               $opts['limit'] = $bit;
-                       }
-
-                       $m = [];
-                       if ( preg_match( '/^limit=(\d+)$/', $bit, $m ) ) {
-                               $opts['limit'] = $m[1];
-                       }
-                       if ( preg_match( '/^days=(\d+(?:\.\d+)?)$/', $bit, $m ) ) {
-                               $opts['days'] = $m[1];
-                       }
-                       if ( preg_match( '/^namespace=(.*)$/', $bit, $m ) ) {
-                               $opts['namespace'] = $m[1];
-                       }
-                       if ( preg_match( '/^tagfilter=(.*)$/', $bit, $m ) ) {
-                               $opts['tagfilter'] = $m[1];
-                       }
-               }
-       }
-
-       /**
-        * @inheritDoc
-        */
-       protected function doMainQuery( $tables, $fields, $conds, $query_options,
-               $join_conds, FormOptions $opts
-       ) {
-               $dbr = $this->getDB();
-               $user = $this->getUser();
-
-               $rcQuery = RecentChange::getQueryInfo();
-               $tables = array_merge( $tables, $rcQuery['tables'] );
-               $fields = array_merge( $rcQuery['fields'], $fields );
-               $join_conds = array_merge( $join_conds, $rcQuery['joins'] );
-
-               // JOIN on watchlist for users
-               if ( $user->isLoggedIn() && $user->isAllowed( 'viewmywatchlist' ) ) {
-                       $tables[] = 'watchlist';
-                       $fields[] = 'wl_user';
-                       $fields[] = 'wl_notificationtimestamp';
-                       $join_conds['watchlist'] = [ 'LEFT JOIN', [
-                               'wl_user' => $user->getId(),
-                               'wl_title=rc_title',
-                               'wl_namespace=rc_namespace'
-                       ] ];
-               }
-
-               // JOIN on page, used for 'last revision' filter highlight
-               $tables[] = 'page';
-               $fields[] = 'page_latest';
-               $join_conds['page'] = [ 'LEFT JOIN', 'rc_cur_id=page_id' ];
-
-               $tagFilter = $opts['tagfilter'] ? explode( '|', $opts['tagfilter'] ) : [];
-               ChangeTags::modifyDisplayQuery(
-                       $tables,
-                       $fields,
-                       $conds,
-                       $join_conds,
-                       $query_options,
-                       $tagFilter
-               );
-
-               if ( !$this->runMainQueryHook( $tables, $fields, $conds, $query_options, $join_conds,
-                       $opts )
-               ) {
-                       return false;
-               }
-
-               if ( $this->areFiltersInConflict() ) {
-                       return false;
-               }
-
-               $orderByAndLimit = [
-                       'ORDER BY' => 'rc_timestamp DESC',
-                       'LIMIT' => $opts['limit']
-               ];
-               if ( in_array( 'DISTINCT', $query_options ) ) {
-                       // ChangeTags::modifyDisplayQuery() adds DISTINCT when filtering on multiple tags.
-                       // In order to prevent DISTINCT from causing query performance problems,
-                       // we have to GROUP BY the primary key. This in turn requires us to add
-                       // the primary key to the end of the ORDER BY, and the old ORDER BY to the
-                       // start of the GROUP BY
-                       $orderByAndLimit['ORDER BY'] = 'rc_timestamp DESC, rc_id DESC';
-                       $orderByAndLimit['GROUP BY'] = 'rc_timestamp, rc_id';
-               }
-               // array_merge() is used intentionally here so that hooks can, should
-               // they so desire, override the ORDER BY / LIMIT condition(s); prior to
-               // MediaWiki 1.26 this used to use the plus operator instead, which meant
-               // that extensions weren't able to change these conditions
-               $query_options = array_merge( $orderByAndLimit, $query_options );
-               $rows = $dbr->select(
-                       $tables,
-                       $fields,
-                       // rc_new is not an ENUM, but adding a redundant rc_new IN (0,1) gives mysql enough
-                       // knowledge to use an index merge if it wants (it may use some other index though).
-                       $conds + [ 'rc_new' => [ 0, 1 ] ],
-                       __METHOD__,
-                       $query_options,
-                       $join_conds
-               );
-
-               return $rows;
-       }
-
-       protected function getDB() {
-               return wfGetDB( DB_REPLICA, 'recentchanges' );
-       }
-
-       public function outputFeedLinks() {
-               $this->addFeedLinks( $this->getFeedQuery() );
-       }
-
-       /**
-        * Get URL query parameters for action=feedrecentchanges API feed of current recent changes view.
-        *
-        * @return array
-        */
-       protected function getFeedQuery() {
-               $query = array_filter( $this->getOptions()->getAllValues(), function ( $value ) {
-                       // API handles empty parameters in a different way
-                       return $value !== '';
-               } );
-               $query['action'] = 'feedrecentchanges';
-               $feedLimit = $this->getConfig()->get( 'FeedLimit' );
-               if ( $query['limit'] > $feedLimit ) {
-                       $query['limit'] = $feedLimit;
-               }
-
-               return $query;
-       }
-
-       /**
-        * Build and output the actual changes list.
-        *
-        * @param IResultWrapper $rows Database rows
-        * @param FormOptions $opts
-        */
-       public function outputChangesList( $rows, $opts ) {
-               $limit = $opts['limit'];
-
-               $showWatcherCount = $this->getConfig()->get( 'RCShowWatchingUsers' )
-                       && $this->getUser()->getOption( 'shownumberswatching' );
-               $watcherCache = [];
-
-               $counter = 1;
-               $list = ChangesList::newFromContext( $this->getContext(), $this->filterGroups );
-               $list->initChangesListRows( $rows );
-
-               $userShowHiddenCats = $this->getUser()->getBoolOption( 'showhiddencats' );
-               $rclistOutput = $list->beginRecentChangesList();
-               if ( $this->isStructuredFilterUiEnabled() ) {
-                       $rclistOutput .= $this->makeLegend();
-               }
-
-               foreach ( $rows as $obj ) {
-                       if ( $limit == 0 ) {
-                               break;
-                       }
-                       $rc = RecentChange::newFromRow( $obj );
-
-                       # Skip CatWatch entries for hidden cats based on user preference
-                       if (
-                               $rc->getAttribute( 'rc_type' ) == RC_CATEGORIZE &&
-                               !$userShowHiddenCats &&
-                               $rc->getParam( 'hidden-cat' )
-                       ) {
-                               continue;
-                       }
-
-                       $rc->counter = $counter++;
-                       # Check if the page has been updated since the last visit
-                       if ( $this->getConfig()->get( 'ShowUpdatedMarker' )
-                               && !empty( $obj->wl_notificationtimestamp )
-                       ) {
-                               $rc->notificationtimestamp = ( $obj->rc_timestamp >= $obj->wl_notificationtimestamp );
-                       } else {
-                               $rc->notificationtimestamp = false; // Default
-                       }
-                       # Check the number of users watching the page
-                       $rc->numberofWatchingusers = 0; // Default
-                       if ( $showWatcherCount && $obj->rc_namespace >= 0 ) {
-                               if ( !isset( $watcherCache[$obj->rc_namespace][$obj->rc_title] ) ) {
-                                       $watcherCache[$obj->rc_namespace][$obj->rc_title] =
-                                               MediaWikiServices::getInstance()->getWatchedItemStore()->countWatchers(
-                                                       new TitleValue( (int)$obj->rc_namespace, $obj->rc_title )
-                                               );
-                               }
-                               $rc->numberofWatchingusers = $watcherCache[$obj->rc_namespace][$obj->rc_title];
-                       }
-
-                       $changeLine = $list->recentChangesLine( $rc, !empty( $obj->wl_user ), $counter );
-                       if ( $changeLine !== false ) {
-                               $rclistOutput .= $changeLine;
-                               --$limit;
-                       }
-               }
-               $rclistOutput .= $list->endRecentChangesList();
-
-               if ( $rows->numRows() === 0 ) {
-                       $this->outputNoResults();
-                       if ( !$this->including() ) {
-                               $this->getOutput()->setStatusCode( 404 );
-                       }
-               } else {
-                       $this->getOutput()->addHTML( $rclistOutput );
-               }
-       }
-
-       /**
-        * Set the text to be displayed above the changes
-        *
-        * @param FormOptions $opts
-        * @param int $numRows Number of rows in the result to show after this header
-        */
-       public function doHeader( $opts, $numRows ) {
-               $this->setTopText( $opts );
-
-               $defaults = $opts->getAllValues();
-               $nondefaults = $opts->getChangedValues();
-
-               $panel = [];
-               if ( !$this->isStructuredFilterUiEnabled() ) {
-                       $panel[] = $this->makeLegend();
-               }
-               $panel[] = $this->optionsPanel( $defaults, $nondefaults, $numRows );
-               $panel[] = '<hr />';
-
-               $extraOpts = $this->getExtraOptions( $opts );
-               $extraOptsCount = count( $extraOpts );
-               $count = 0;
-               $submit = ' ' . Xml::submitButton( $this->msg( 'recentchanges-submit' )->text() );
-
-               $out = Xml::openElement( 'table', [ 'class' => 'mw-recentchanges-table' ] );
-               foreach ( $extraOpts as $name => $optionRow ) {
-                       # Add submit button to the last row only
-                       ++$count;
-                       $addSubmit = ( $count === $extraOptsCount ) ? $submit : '';
-
-                       $out .= Xml::openElement( 'tr', [ 'class' => $name . 'Form' ] );
-                       if ( is_array( $optionRow ) ) {
-                               $out .= Xml::tags(
-                                       'td',
-                                       [ 'class' => 'mw-label mw-' . $name . '-label' ],
-                                       $optionRow[0]
-                               );
-                               $out .= Xml::tags(
-                                       'td',
-                                       [ 'class' => 'mw-input' ],
-                                       $optionRow[1] . $addSubmit
-                               );
-                       } else {
-                               $out .= Xml::tags(
-                                       'td',
-                                       [ 'class' => 'mw-input', 'colspan' => 2 ],
-                                       $optionRow . $addSubmit
-                               );
-                       }
-                       $out .= Xml::closeElement( 'tr' );
-               }
-               $out .= Xml::closeElement( 'table' );
-
-               $unconsumed = $opts->getUnconsumedValues();
-               foreach ( $unconsumed as $key => $value ) {
-                       $out .= Html::hidden( $key, $value );
-               }
-
-               $t = $this->getPageTitle();
-               $out .= Html::hidden( 'title', $t->getPrefixedText() );
-               $form = Xml::tags( 'form', [ 'action' => wfScript() ], $out );
-               $panel[] = $form;
-               $panelString = implode( "\n", $panel );
-
-               $rcoptions = Xml::fieldset(
-                       $this->msg( 'recentchanges-legend' )->text(),
-                       $panelString,
-                       [ 'class' => 'rcoptions cloptions' ]
-               );
-
-               // Insert a placeholder for RCFilters
-               if ( $this->isStructuredFilterUiEnabled() ) {
-                       $rcfilterContainer = Html::element(
-                               'div',
-                               [ 'class' => 'rcfilters-container' ]
-                       );
-
-                       $loadingContainer = Html::rawElement(
-                               'div',
-                               [ 'class' => 'rcfilters-spinner' ],
-                               Html::element(
-                                       'div',
-                                       [ 'class' => 'rcfilters-spinner-bounce' ]
-                               )
-                       );
-
-                       // Wrap both with rcfilters-head
-                       $this->getOutput()->addHTML(
-                               Html::rawElement(
-                                       'div',
-                                       [ 'class' => 'rcfilters-head' ],
-                                       $rcfilterContainer . $rcoptions
-                               )
-                       );
-
-                       // Add spinner
-                       $this->getOutput()->addHTML( $loadingContainer );
-               } else {
-                       $this->getOutput()->addHTML( $rcoptions );
-               }
-
-               $this->setBottomText( $opts );
-       }
-
-       /**
-        * Send the text to be displayed above the options
-        *
-        * @param FormOptions $opts Unused
-        */
-       function setTopText( FormOptions $opts ) {
-               $message = $this->msg( 'recentchangestext' )->inContentLanguage();
-               if ( !$message->isDisabled() ) {
-                       $contLang = MediaWikiServices::getInstance()->getContentLanguage();
-                       // Parse the message in this weird ugly way to preserve the ability to include interlanguage
-                       // links in it (T172461). In the future when T66969 is resolved, perhaps we can just use
-                       // $message->parse() instead. This code is copied from Message::parseText().
-                       $parserOutput = MessageCache::singleton()->parse(
-                               $message->plain(),
-                               $this->getPageTitle(),
-                               /*linestart*/true,
-                               // Message class sets the interface flag to false when parsing in a language different than
-                               // user language, and this is wiki content language
-                               /*interface*/false,
-                               $contLang
-                       );
-                       $content = $parserOutput->getText( [
-                               'enableSectionEditLinks' => false,
-                       ] );
-                       // Add only metadata here (including the language links), text is added below
-                       $this->getOutput()->addParserOutputMetadata( $parserOutput );
-
-                       $langAttributes = [
-                               'lang' => $contLang->getHtmlCode(),
-                               'dir' => $contLang->getDir(),
-                       ];
-
-                       $topLinksAttributes = [ 'class' => 'mw-recentchanges-toplinks' ];
-
-                       if ( $this->isStructuredFilterUiEnabled() ) {
-                               // Check whether the widget is already collapsed or expanded
-                               $collapsedState = $this->getRequest()->getCookie( 'rcfilters-toplinks-collapsed-state' );
-                               // Note that an empty/unset cookie means collapsed, so check for !== 'expanded'
-                               $topLinksAttributes[ 'class' ] .= $collapsedState !== 'expanded' ?
-                                       ' mw-recentchanges-toplinks-collapsed' : '';
-
-                               $this->getOutput()->enableOOUI();
-                               $contentTitle = new OOUI\ButtonWidget( [
-                                       'classes' => [ 'mw-recentchanges-toplinks-title' ],
-                                       'label' => new OOUI\HtmlSnippet( $this->msg( 'rcfilters-other-review-tools' )->parse() ),
-                                       'framed' => false,
-                                       'indicator' => $collapsedState !== 'expanded' ? 'down' : 'up',
-                                       'flags' => [ 'progressive' ],
-                               ] );
-
-                               $contentWrapper = Html::rawElement( 'div',
-                                       array_merge(
-                                               [ 'class' => 'mw-recentchanges-toplinks-content mw-collapsible-content' ],
-                                               $langAttributes
-                                       ),
-                                       $content
-                               );
-                               $content = $contentTitle . $contentWrapper;
-                       } else {
-                               // Language direction should be on the top div only
-                               // if the title is not there. If it is there, it's
-                               // interface direction, and the language/dir attributes
-                               // should be on the content itself
-                               $topLinksAttributes = array_merge( $topLinksAttributes, $langAttributes );
-                       }
-
-                       $this->getOutput()->addHTML(
-                               Html::rawElement( 'div', $topLinksAttributes, $content )
-                       );
-               }
-       }
-
-       /**
-        * Get options to be displayed in a form
-        *
-        * @param FormOptions $opts
-        * @return array
-        */
-       function getExtraOptions( $opts ) {
-               $opts->consumeValues( [
-                       'namespace', 'invert', 'associated', 'tagfilter'
-               ] );
-
-               $extraOpts = [];
-               $extraOpts['namespace'] = $this->namespaceFilterForm( $opts );
-
-               $tagFilter = ChangeTags::buildTagFilterSelector(
-                       $opts['tagfilter'], false, $this->getContext() );
-               if ( count( $tagFilter ) ) {
-                       $extraOpts['tagfilter'] = $tagFilter;
-               }
-
-               // Don't fire the hook for subclasses. (Or should we?)
-               if ( $this->getName() === 'Recentchanges' ) {
-                       Hooks::run( 'SpecialRecentChangesPanel', [ &$extraOpts, $opts ] );
-               }
-
-               return $extraOpts;
-       }
-
-       /**
-        * Add page-specific modules.
-        */
-       protected function addModules() {
-               parent::addModules();
-               $out = $this->getOutput();
-               $out->addModules( 'mediawiki.special.recentchanges' );
-       }
-
-       /**
-        * Get last modified date, for client caching
-        * Don't use this if we are using the patrol feature, patrol changes don't
-        * update the timestamp
-        *
-        * @return string|bool
-        */
-       public function checkLastModified() {
-               $dbr = $this->getDB();
-               $lastmod = $dbr->selectField( 'recentchanges', 'MAX(rc_timestamp)', '', __METHOD__ );
-
-               return $lastmod;
-       }
-
-       /**
-        * Creates the choose namespace selection
-        *
-        * @param FormOptions $opts
-        * @return string[]
-        */
-       protected function namespaceFilterForm( FormOptions $opts ) {
-               $nsSelect = Html::namespaceSelector(
-                       [ 'selected' => $opts['namespace'], 'all' => '', 'in-user-lang' => true ],
-                       [ 'name' => 'namespace', 'id' => 'namespace' ]
-               );
-               $nsLabel = Xml::label( $this->msg( 'namespace' )->text(), 'namespace' );
-               $attribs = [ 'class' => [ 'mw-input-with-label' ] ];
-               // Hide the checkboxes when the namespace filter is set to 'all'.
-               if ( $opts['namespace'] === '' ) {
-                       $attribs['class'][] = 'mw-input-hidden';
-               }
-               $invert = Html::rawElement( 'span', $attribs, Xml::checkLabel(
-                       $this->msg( 'invert' )->text(), 'invert', 'nsinvert',
-                       $opts['invert'],
-                       [ 'title' => $this->msg( 'tooltip-invert' )->text() ]
-               ) );
-               $associated = Html::rawElement( 'span', $attribs, Xml::checkLabel(
-                       $this->msg( 'namespace_association' )->text(), 'associated', 'nsassociated',
-                       $opts['associated'],
-                       [ 'title' => $this->msg( 'tooltip-namespace_association' )->text() ]
-               ) );
-
-               return [ $nsLabel, "$nsSelect $invert $associated" ];
-       }
-
-       /**
-        * Filter $rows by categories set in $opts
-        *
-        * @deprecated since 1.31
-        *
-        * @param IResultWrapper &$rows Database rows
-        * @param FormOptions $opts
-        */
-       function filterByCategories( &$rows, FormOptions $opts ) {
-               wfDeprecated( __METHOD__, '1.31' );
-
-               $categories = array_map( 'trim', explode( '|', $opts['categories'] ) );
-
-               if ( $categories === [] ) {
-                       return;
-               }
-
-               # Filter categories
-               $cats = [];
-               foreach ( $categories as $cat ) {
-                       $cat = trim( $cat );
-                       if ( $cat == '' ) {
-                               continue;
-                       }
-                       $cats[] = $cat;
-               }
-
-               # Filter articles
-               $articles = [];
-               $a2r = [];
-               $rowsarr = [];
-               foreach ( $rows as $k => $r ) {
-                       $nt = Title::makeTitle( $r->rc_namespace, $r->rc_title );
-                       $id = $nt->getArticleID();
-                       if ( $id == 0 ) {
-                               continue; # Page might have been deleted...
-                       }
-                       if ( !in_array( $id, $articles ) ) {
-                               $articles[] = $id;
-                       }
-                       if ( !isset( $a2r[$id] ) ) {
-                               $a2r[$id] = [];
-                       }
-                       $a2r[$id][] = $k;
-                       $rowsarr[$k] = $r;
-               }
-
-               # Shortcut?
-               if ( $articles === [] || $cats === [] ) {
-                       return;
-               }
-
-               # Look up
-               $catFind = new CategoryFinder;
-               $catFind->seed( $articles, $cats, $opts['categories_any'] ? 'OR' : 'AND' );
-               $match = $catFind->run();
-
-               # Filter
-               $newrows = [];
-               foreach ( $match as $id ) {
-                       foreach ( $a2r[$id] as $rev ) {
-                               $k = $rev;
-                               $newrows[$k] = $rowsarr[$k];
-                       }
-               }
-               $rows = new FakeResultWrapper( array_values( $newrows ) );
-       }
-
-       /**
-        * Makes change an option link which carries all the other options
-        *
-        * @param string $title
-        * @param array $override Options to override
-        * @param array $options Current options
-        * @param bool $active Whether to show the link in bold
-        * @return string
-        */
-       function makeOptionsLink( $title, $override, $options, $active = false ) {
-               $params = $this->convertParamsForLink( $override + $options );
-
-               if ( $active ) {
-                       $title = new HtmlArmor( '<strong>' . htmlspecialchars( $title ) . '</strong>' );
-               }
-
-               return $this->getLinkRenderer()->makeKnownLink( $this->getPageTitle(), $title, [
-                       'data-params' => json_encode( $override ),
-                       'data-keys' => implode( ',', array_keys( $override ) ),
-               ], $params );
-       }
-
-       /**
-        * Creates the options panel.
-        *
-        * @param array $defaults
-        * @param array $nondefaults
-        * @param int $numRows Number of rows in the result to show after this header
-        * @return string
-        */
-       function optionsPanel( $defaults, $nondefaults, $numRows ) {
-               $options = $nondefaults + $defaults;
-
-               $note = '';
-               $msg = $this->msg( 'rclegend' );
-               if ( !$msg->isDisabled() ) {
-                       $note .= Html::rawElement(
-                               'div',
-                               [ 'class' => 'mw-rclegend' ],
-                               $msg->parse()
-                       );
-               }
-
-               $lang = $this->getLanguage();
-               $user = $this->getUser();
-               $config = $this->getConfig();
-               if ( $options['from'] ) {
-                       $resetLink = $this->makeOptionsLink( $this->msg( 'rclistfromreset' ),
-                               [ 'from' => '' ], $nondefaults );
-
-                       $noteFromMsg = $this->msg( 'rcnotefrom' )
-                               ->numParams( $options['limit'] )
-                               ->params(
-                                       $lang->userTimeAndDate( $options['from'], $user ),
-                                       $lang->userDate( $options['from'], $user ),
-                                       $lang->userTime( $options['from'], $user )
-                               )
-                               ->numParams( $numRows );
-                       $note .= Html::rawElement(
-                                       'span',
-                                       [ 'class' => 'rcnotefrom' ],
-                                       $noteFromMsg->parse()
-                               ) .
-                               ' ' .
-                               Html::rawElement(
-                                       'span',
-                                       [ 'class' => 'rcoptions-listfromreset' ],
-                                       $this->msg( 'parentheses' )->rawParams( $resetLink )->parse()
-                               ) .
-                               '<br />';
-               }
-
-               # Sort data for display and make sure it's unique after we've added user data.
-               $linkLimits = $config->get( 'RCLinkLimits' );
-               $linkLimits[] = $options['limit'];
-               sort( $linkLimits );
-               $linkLimits = array_unique( $linkLimits );
-
-               $linkDays = $config->get( 'RCLinkDays' );
-               $linkDays[] = $options['days'];
-               sort( $linkDays );
-               $linkDays = array_unique( $linkDays );
-
-               // limit links
-               $cl = [];
-               foreach ( $linkLimits as $value ) {
-                       $cl[] = $this->makeOptionsLink( $lang->formatNum( $value ),
-                               [ 'limit' => $value ], $nondefaults, $value == $options['limit'] );
-               }
-               $cl = $lang->pipeList( $cl );
-
-               // day links, reset 'from' to none
-               $dl = [];
-               foreach ( $linkDays as $value ) {
-                       $dl[] = $this->makeOptionsLink( $lang->formatNum( $value ),
-                               [ 'days' => $value, 'from' => '' ], $nondefaults, $value == $options['days'] );
-               }
-               $dl = $lang->pipeList( $dl );
-
-               $showhide = [ 'show', 'hide' ];
-
-               $links = [];
-
-               foreach ( $this->getLegacyShowHideFilters() as $key => $filter ) {
-                       $msg = $filter->getShowHide();
-                       $linkMessage = $this->msg( $msg . '-' . $showhide[1 - $options[$key]] );
-                       // Extensions can define additional filters, but don't need to define the corresponding
-                       // messages. If they don't exist, just fall back to 'show' and 'hide'.
-                       if ( !$linkMessage->exists() ) {
-                               $linkMessage = $this->msg( $showhide[1 - $options[$key]] );
-                       }
-
-                       $link = $this->makeOptionsLink( $linkMessage->text(),
-                               [ $key => 1 - $options[$key] ], $nondefaults );
-
-                       $attribs = [
-                               'class' => "$msg rcshowhideoption clshowhideoption",
-                               'data-filter-name' => $filter->getName(),
-                       ];
-
-                       if ( $filter->isFeatureAvailableOnStructuredUi( $this ) ) {
-                               $attribs['data-feature-in-structured-ui'] = true;
-                       }
-
-                       $links[] = Html::rawElement(
-                               'span',
-                               $attribs,
-                               $this->msg( $msg )->rawParams( $link )->parse()
-                       );
-               }
-
-               // show from this onward link
-               $timestamp = wfTimestampNow();
-               $now = $lang->userTimeAndDate( $timestamp, $user );
-               $timenow = $lang->userTime( $timestamp, $user );
-               $datenow = $lang->userDate( $timestamp, $user );
-               $pipedLinks = '<span class="rcshowhide">' . $lang->pipeList( $links ) . '</span>';
-
-               $rclinks = Html::rawElement(
-                       'span',
-                       [ 'class' => 'rclinks' ],
-                       $this->msg( 'rclinks' )->rawParams( $cl, $dl, '' )->parse()
-               );
-
-               $rclistfrom = Html::rawElement(
-                       'span',
-                       [ 'class' => 'rclistfrom' ],
-                       $this->makeOptionsLink(
-                               $this->msg( 'rclistfrom' )->plaintextParams( $now, $timenow, $datenow )->parse(),
-                               [ 'from' => $timestamp ],
-                               $nondefaults
-                       )
-               );
-
-               return "{$note}$rclinks<br />$pipedLinks<br />$rclistfrom";
-       }
-
-       public function isIncludable() {
-               return true;
-       }
-
-       protected function getCacheTTL() {
-               return 60 * 5;
-       }
-
-       public function getDefaultLimit() {
-               $systemPrefValue = $this->getUser()->getIntOption( 'rclimit' );
-               // Prefer the RCFilters-specific preference if RCFilters is enabled
-               if ( $this->isStructuredFilterUiEnabled() ) {
-                       return $this->getUser()->getIntOption( static::$limitPreferenceName, $systemPrefValue );
-               }
-
-               // Otherwise, use the system rclimit preference value
-               return $systemPrefValue;
-       }
-}
diff --git a/includes/specials/SpecialRecentchangeslinked.php b/includes/specials/SpecialRecentchangeslinked.php
deleted file mode 100644 (file)
index 62c867b..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-<?php
-/**
- * Implements Special:Recentchangeslinked
- *
- * 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
- */
-
-/**
- * This is to display changes made to all articles linked in an article.
- *
- * @ingroup SpecialPage
- */
-class SpecialRecentChangesLinked extends SpecialRecentChanges {
-       /** @var bool|Title */
-       protected $rclTargetTitle;
-
-       function __construct() {
-               parent::__construct( 'Recentchangeslinked' );
-       }
-
-       public function getDefaultOptions() {
-               $opts = parent::getDefaultOptions();
-               $opts->add( 'target', '' );
-               $opts->add( 'showlinkedto', false );
-
-               return $opts;
-       }
-
-       public function parseParameters( $par, FormOptions $opts ) {
-               $opts['target'] = $par;
-       }
-
-       /**
-        * @inheritDoc
-        */
-       protected function doMainQuery( $tables, $select, $conds, $query_options,
-               $join_conds, FormOptions $opts
-       ) {
-               $target = $opts['target'];
-               $showlinkedto = $opts['showlinkedto'];
-               $limit = $opts['limit'];
-
-               if ( $target === '' ) {
-                       return false;
-               }
-               $outputPage = $this->getOutput();
-               $title = Title::newFromText( $target );
-               if ( !$title || $title->isExternal() ) {
-                       $outputPage->addHTML(
-                               Html::errorBox( $this->msg( 'allpagesbadtitle' )->parse() )
-                       );
-                       return false;
-               }
-
-               $outputPage->setPageTitle( $this->msg( 'recentchangeslinked-title', $title->getPrefixedText() ) );
-
-               /*
-                * Ordinary links are in the pagelinks table, while transclusions are
-                * in the templatelinks table, categorizations in categorylinks and
-                * image use in imagelinks.  We need to somehow combine all these.
-                * Special:Whatlinkshere does this by firing multiple queries and
-                * merging the results, but the code we inherit from our parent class
-                * expects only one result set so we use UNION instead.
-                */
-
-               $dbr = wfGetDB( DB_REPLICA, 'recentchangeslinked' );
-               $id = $title->getArticleID();
-               $ns = $title->getNamespace();
-               $dbkey = $title->getDBkey();
-
-               $rcQuery = RecentChange::getQueryInfo();
-               $tables = array_merge( $tables, $rcQuery['tables'] );
-               $select = array_merge( $rcQuery['fields'], $select );
-               $join_conds = array_merge( $join_conds, $rcQuery['joins'] );
-
-               // left join with watchlist table to highlight watched rows
-               $uid = $this->getUser()->getId();
-               if ( $uid && $this->getUser()->isAllowed( 'viewmywatchlist' ) ) {
-                       $tables[] = 'watchlist';
-                       $select[] = 'wl_user';
-                       $join_conds['watchlist'] = [ 'LEFT JOIN', [
-                               'wl_user' => $uid,
-                               'wl_title=rc_title',
-                               'wl_namespace=rc_namespace'
-                       ] ];
-               }
-
-               // JOIN on page, used for 'last revision' filter highlight
-               $tables[] = 'page';
-               $join_conds['page'] = [ 'LEFT JOIN', 'rc_cur_id=page_id' ];
-               $select[] = 'page_latest';
-
-               $tagFilter = $opts['tagfilter'] ? explode( '|', $opts['tagfilter'] ) : [];
-               ChangeTags::modifyDisplayQuery(
-                       $tables,
-                       $select,
-                       $conds,
-                       $join_conds,
-                       $query_options,
-                       $tagFilter
-               );
-
-               if ( $dbr->unionSupportsOrderAndLimit() ) {
-                       if ( count( $tagFilter ) > 1 ) {
-                               // ChangeTags::modifyDisplayQuery() will have added DISTINCT.
-                               // To prevent this from causing query performance problems, we need to add
-                               // a GROUP BY, and add rc_id to the ORDER BY.
-                               $order = [
-                                       'GROUP BY' => 'rc_timestamp, rc_id',
-                                       'ORDER BY' => 'rc_timestamp DESC, rc_id DESC'
-                               ];
-                       } else {
-                               $order = [ 'ORDER BY' => 'rc_timestamp DESC' ];
-                       }
-               } else {
-                       $order = [];
-               }
-
-               if ( !$this->runMainQueryHook( $tables, $select, $conds, $query_options, $join_conds,
-                       $opts )
-               ) {
-                       return false;
-               }
-
-               if ( $ns == NS_CATEGORY && !$showlinkedto ) {
-                       // special handling for categories
-                       // XXX: should try to make this less kludgy
-                       $link_tables = [ 'categorylinks' ];
-                       $showlinkedto = true;
-               } else {
-                       // for now, always join on these tables; really should be configurable as in whatlinkshere
-                       $link_tables = [ 'pagelinks', 'templatelinks' ];
-                       // imagelinks only contains links to pages in NS_FILE
-                       if ( $ns == NS_FILE || !$showlinkedto ) {
-                               $link_tables[] = 'imagelinks';
-                       }
-               }
-
-               if ( $id == 0 && !$showlinkedto ) {
-                       return false; // nonexistent pages can't link to any pages
-               }
-
-               // field name prefixes for all the various tables we might want to join with
-               $prefix = [
-                       'pagelinks' => 'pl',
-                       'templatelinks' => 'tl',
-                       'categorylinks' => 'cl',
-                       'imagelinks' => 'il'
-               ];
-
-               $subsql = []; // SELECT statements to combine with UNION
-
-               foreach ( $link_tables as $link_table ) {
-                       $pfx = $prefix[$link_table];
-
-                       // imagelinks and categorylinks tables have no xx_namespace field,
-                       // and have xx_to instead of xx_title
-                       if ( $link_table == 'imagelinks' ) {
-                               $link_ns = NS_FILE;
-                       } elseif ( $link_table == 'categorylinks' ) {
-                               $link_ns = NS_CATEGORY;
-                       } else {
-                               $link_ns = 0;
-                       }
-
-                       if ( $showlinkedto ) {
-                               // find changes to pages linking to this page
-                               if ( $link_ns ) {
-                                       if ( $ns != $link_ns ) {
-                                               continue;
-                                       } // should never happen, but check anyway
-                                       $subconds = [ "{$pfx}_to" => $dbkey ];
-                               } else {
-                                       $subconds = [ "{$pfx}_namespace" => $ns, "{$pfx}_title" => $dbkey ];
-                               }
-                               $subjoin = "rc_cur_id = {$pfx}_from";
-                       } else {
-                               // find changes to pages linked from this page
-                               $subconds = [ "{$pfx}_from" => $id ];
-                               if ( $link_table == 'imagelinks' || $link_table == 'categorylinks' ) {
-                                       $subconds["rc_namespace"] = $link_ns;
-                                       $subjoin = "rc_title = {$pfx}_to";
-                               } else {
-                                       $subjoin = [ "rc_namespace = {$pfx}_namespace", "rc_title = {$pfx}_title" ];
-                               }
-                       }
-
-                       $query = $dbr->selectSQLText(
-                               array_merge( $tables, [ $link_table ] ),
-                               $select,
-                               $conds + $subconds,
-                               __METHOD__,
-                               $order + $query_options,
-                               $join_conds + [ $link_table => [ 'JOIN', $subjoin ] ]
-                       );
-
-                       if ( $dbr->unionSupportsOrderAndLimit() ) {
-                               $query = $dbr->limitResult( $query, $limit );
-                       }
-
-                       $subsql[] = $query;
-               }
-
-               if ( count( $subsql ) == 0 ) {
-                       return false; // should never happen
-               }
-               if ( count( $subsql ) == 1 && $dbr->unionSupportsOrderAndLimit() ) {
-                       $sql = $subsql[0];
-               } else {
-                       // need to resort and relimit after union
-                       $sql = $dbr->unionQueries( $subsql, false ) . ' ORDER BY rc_timestamp DESC';
-                       $sql = $dbr->limitResult( $sql, $limit, false );
-               }
-
-               $res = $dbr->query( $sql, __METHOD__ );
-
-               if ( $res->numRows() == 0 ) {
-                       $this->mResultEmpty = true;
-               }
-
-               return $res;
-       }
-
-       function setTopText( FormOptions $opts ) {
-               $target = $this->getTargetTitle();
-               if ( $target ) {
-                       $this->getOutput()->addBacklinkSubtitle( $target );
-                       $this->getSkin()->setRelevantTitle( $target );
-               }
-       }
-
-       /**
-        * Get options to be displayed in a form
-        *
-        * @param FormOptions $opts
-        * @return array
-        */
-       function getExtraOptions( $opts ) {
-               $extraOpts = parent::getExtraOptions( $opts );
-
-               $opts->consumeValues( [ 'showlinkedto', 'target' ] );
-
-               $extraOpts['target'] = [ $this->msg( 'recentchangeslinked-page' )->escaped(),
-                       Xml::input( 'target', 40, str_replace( '_', ' ', $opts['target'] ) ) .
-                       Xml::check( 'showlinkedto', $opts['showlinkedto'], [ 'id' => 'showlinkedto' ] ) . ' ' .
-                       Xml::label( $this->msg( 'recentchangeslinked-to' )->text(), 'showlinkedto' ) ];
-
-               $this->addHelpLink( 'Help:Related changes' );
-               return $extraOpts;
-       }
-
-       /**
-        * @return Title
-        */
-       function getTargetTitle() {
-               if ( $this->rclTargetTitle === null ) {
-                       $opts = $this->getOptions();
-                       if ( isset( $opts['target'] ) && $opts['target'] !== '' ) {
-                               $this->rclTargetTitle = Title::newFromText( $opts['target'] );
-                       } else {
-                               $this->rclTargetTitle = false;
-                       }
-               }
-
-               return $this->rclTargetTitle;
-       }
-
-       /**
-        * Return an array of subpages beginning with $search that this special page will accept.
-        *
-        * @param string $search Prefix to search for
-        * @param int $limit Maximum number of results to return (usually 10)
-        * @param int $offset Number of results to skip (usually 0)
-        * @return string[] Matching subpages
-        */
-       public function prefixSearchSubpages( $search, $limit, $offset ) {
-               return $this->prefixSearchString( $search, $limit, $offset );
-       }
-
-       protected function outputNoResults() {
-               $targetTitle = $this->getTargetTitle();
-               if ( $targetTitle === false ) {
-                       $this->getOutput()->addHTML(
-                               Html::rawElement(
-                                       'div',
-                                       [ 'class' => 'mw-changeslist-empty mw-changeslist-notargetpage' ],
-                                       $this->msg( 'recentchanges-notargetpage' )->parse()
-                               )
-                       );
-               } elseif ( !$targetTitle || $targetTitle->isExternal() ) {
-                       $this->getOutput()->addHTML(
-                               Html::rawElement(
-                                       'div',
-                                       [ 'class' => 'mw-changeslist-empty mw-changeslist-invalidtargetpage' ],
-                                       $this->msg( 'allpagesbadtitle' )->parse()
-                               )
-                       );
-               } else {
-                       parent::outputNoResults();
-               }
-       }
-}
index c4e4635..49f1b3c 100644 (file)
@@ -61,8 +61,8 @@ class SpecialRedirect extends FormSpecialPage {
        function setParameter( $subpage ) {
                // parse $subpage to pull out the parts
                $parts = explode( '/', $subpage, 2 );
-               $this->mType = count( $parts ) > 0 ? $parts[0] : null;
-               $this->mValue = count( $parts ) > 1 ? $parts[1] : null;
+               $this->mType = $parts[0];
+               $this->mValue = $parts[1] ?? null;
        }
 
        /**
diff --git a/includes/specials/SpecialRevisionDelete.php b/includes/specials/SpecialRevisionDelete.php
new file mode 100644 (file)
index 0000000..682bceb
--- /dev/null
@@ -0,0 +1,687 @@
+<?php
+/**
+ * Implements Special:Revisiondelete
+ *
+ * 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 allowing users with the appropriate permissions to view
+ * and hide revisions. Log items can also be hidden.
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialRevisionDelete extends UnlistedSpecialPage {
+       /** @var bool Was the DB modified in this request */
+       protected $wasSaved = false;
+
+       /** @var bool True if the submit button was clicked, and the form was posted */
+       private $submitClicked;
+
+       /** @var array Target ID list */
+       private $ids;
+
+       /** @var string Archive name, for reviewing deleted files */
+       private $archiveName;
+
+       /** @var string Edit token for securing image views against XSS */
+       private $token;
+
+       /** @var Title Title object for target parameter */
+       private $targetObj;
+
+       /** @var string Deletion type, may be revision, archive, oldimage, filearchive, logging. */
+       private $typeName;
+
+       /** @var array Array of checkbox specs (message, name, deletion bits) */
+       private $checks;
+
+       /** @var array UI Labels about the current type */
+       private $typeLabels;
+
+       /** @var RevDelList RevDelList object, storing the list of items to be deleted/undeleted */
+       private $revDelList;
+
+       /** @var bool Whether user is allowed to perform the action */
+       private $mIsAllowed;
+
+       /** @var string */
+       private $otherReason;
+
+       /**
+        * UI labels for each type.
+        */
+       private static $UILabels = [
+               'revision' => [
+                       'check-label' => 'revdelete-hide-text',
+                       'success' => 'revdelete-success',
+                       'failure' => 'revdelete-failure',
+                       'text' => 'revdelete-text-text',
+                       'selected' => 'revdelete-selected-text',
+               ],
+               'archive' => [
+                       'check-label' => 'revdelete-hide-text',
+                       'success' => 'revdelete-success',
+                       'failure' => 'revdelete-failure',
+                       'text' => 'revdelete-text-text',
+                       'selected' => 'revdelete-selected-text',
+               ],
+               'oldimage' => [
+                       'check-label' => 'revdelete-hide-image',
+                       'success' => 'revdelete-success',
+                       'failure' => 'revdelete-failure',
+                       'text' => 'revdelete-text-file',
+                       'selected' => 'revdelete-selected-file',
+               ],
+               'filearchive' => [
+                       'check-label' => 'revdelete-hide-image',
+                       'success' => 'revdelete-success',
+                       'failure' => 'revdelete-failure',
+                       'text' => 'revdelete-text-file',
+                       'selected' => 'revdelete-selected-file',
+               ],
+               'logging' => [
+                       'check-label' => 'revdelete-hide-name',
+                       'success' => 'logdelete-success',
+                       'failure' => 'logdelete-failure',
+                       'text' => 'logdelete-text',
+                       'selected' => 'logdelete-selected',
+               ],
+       ];
+
+       public function __construct() {
+               parent::__construct( 'Revisiondelete', 'deleterevision' );
+       }
+
+       public function doesWrites() {
+               return true;
+       }
+
+       public function execute( $par ) {
+               $this->useTransactionalTimeLimit();
+
+               $this->checkPermissions();
+               $this->checkReadOnly();
+
+               $output = $this->getOutput();
+               $user = $this->getUser();
+
+               // Check blocks
+               // @TODO Use PermissionManager::isBlockedFrom() instead.
+               $block = $user->getBlock();
+               if ( $block ) {
+                       throw new UserBlockedError( $block );
+               }
+
+               $this->setHeaders();
+               $this->outputHeader();
+               $request = $this->getRequest();
+               $this->submitClicked = $request->wasPosted() && $request->getBool( 'wpSubmit' );
+               # Handle our many different possible input types.
+               $ids = $request->getVal( 'ids' );
+               if ( !is_null( $ids ) ) {
+                       # Allow CSV, for backwards compatibility, or a single ID for show/hide links
+                       $this->ids = explode( ',', $ids );
+               } else {
+                       # Array input
+                       $this->ids = array_keys( $request->getArray( 'ids', [] ) );
+               }
+               // $this->ids = array_map( 'intval', $this->ids );
+               $this->ids = array_unique( array_filter( $this->ids ) );
+
+               $this->typeName = $request->getVal( 'type' );
+               $this->targetObj = Title::newFromText( $request->getText( 'target' ) );
+
+               # For reviewing deleted files...
+               $this->archiveName = $request->getVal( 'file' );
+               $this->token = $request->getVal( 'token' );
+               if ( $this->archiveName && $this->targetObj ) {
+                       $this->tryShowFile( $this->archiveName );
+
+                       return;
+               }
+
+               $this->typeName = RevisionDeleter::getCanonicalTypeName( $this->typeName );
+
+               # No targets?
+               if ( !$this->typeName || count( $this->ids ) == 0 ) {
+                       throw new ErrorPageError( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
+               }
+
+               # Allow the list type to adjust the passed target
+               $this->targetObj = RevisionDeleter::suggestTarget(
+                       $this->typeName,
+                       $this->targetObj,
+                       $this->ids
+               );
+
+               # We need a target page!
+               if ( $this->targetObj === null ) {
+                       $output->addWikiMsg( 'undelete-header' );
+
+                       return;
+               }
+
+               $this->typeLabels = self::$UILabels[$this->typeName];
+               $list = $this->getList();
+               $list->reset();
+               $this->mIsAllowed = $user->isAllowed( RevisionDeleter::getRestriction( $this->typeName ) );
+               $canViewSuppressedOnly = $this->getUser()->isAllowed( 'viewsuppressed' ) &&
+                       !$this->getUser()->isAllowed( 'suppressrevision' );
+               $pageIsSuppressed = $list->areAnySuppressed();
+               $this->mIsAllowed = $this->mIsAllowed && !( $canViewSuppressedOnly && $pageIsSuppressed );
+
+               $this->otherReason = $request->getVal( 'wpReason' );
+               # Give a link to the logs/hist for this page
+               $this->showConvenienceLinks();
+
+               # Initialise checkboxes
+               $this->checks = [
+                       # Messages: revdelete-hide-text, revdelete-hide-image, revdelete-hide-name
+                       [ $this->typeLabels['check-label'], 'wpHidePrimary',
+                               RevisionDeleter::getRevdelConstant( $this->typeName )
+                       ],
+                       [ 'revdelete-hide-comment', 'wpHideComment', Revision::DELETED_COMMENT ],
+                       [ 'revdelete-hide-user', 'wpHideUser', Revision::DELETED_USER ]
+               ];
+               if ( $user->isAllowed( 'suppressrevision' ) ) {
+                       $this->checks[] = [ 'revdelete-hide-restricted',
+                               'wpHideRestricted', Revision::DELETED_RESTRICTED ];
+               }
+
+               # Either submit or create our form
+               if ( $this->mIsAllowed && $this->submitClicked ) {
+                       $this->submit();
+               } else {
+                       $this->showForm();
+               }
+
+               if ( $user->isAllowed( 'deletedhistory' ) ) {
+                       $qc = $this->getLogQueryCond();
+                       # Show relevant lines from the deletion log
+                       $deleteLogPage = new LogPage( 'delete' );
+                       $output->addHTML( "<h2>" . $deleteLogPage->getName()->escaped() . "</h2>\n" );
+                       LogEventsList::showLogExtract(
+                               $output,
+                               'delete',
+                               $this->targetObj,
+                               '', /* user */
+                               [ 'lim' => 25, 'conds' => $qc, 'useMaster' => $this->wasSaved ]
+                       );
+               }
+               # Show relevant lines from the suppression log
+               if ( $user->isAllowed( 'suppressionlog' ) ) {
+                       $suppressLogPage = new LogPage( 'suppress' );
+                       $output->addHTML( "<h2>" . $suppressLogPage->getName()->escaped() . "</h2>\n" );
+                       LogEventsList::showLogExtract(
+                               $output,
+                               'suppress',
+                               $this->targetObj,
+                               '',
+                               [ 'lim' => 25, 'conds' => $qc, 'useMaster' => $this->wasSaved ]
+                       );
+               }
+       }
+
+       /**
+        * Show some useful links in the subtitle
+        */
+       protected function showConvenienceLinks() {
+               $linkRenderer = $this->getLinkRenderer();
+               # Give a link to the logs/hist for this page
+               if ( $this->targetObj ) {
+                       // Also set header tabs to be for the target.
+                       $this->getSkin()->setRelevantTitle( $this->targetObj );
+
+                       $links = [];
+                       $links[] = $linkRenderer->makeKnownLink(
+                               SpecialPage::getTitleFor( 'Log' ),
+                               $this->msg( 'viewpagelogs' )->text(),
+                               [],
+                               [ 'page' => $this->targetObj->getPrefixedText() ]
+                       );
+                       if ( !$this->targetObj->isSpecialPage() ) {
+                               # Give a link to the page history
+                               $links[] = $linkRenderer->makeKnownLink(
+                                       $this->targetObj,
+                                       $this->msg( 'pagehist' )->text(),
+                                       [],
+                                       [ 'action' => 'history' ]
+                               );
+                               # Link to deleted edits
+                               if ( $this->getUser()->isAllowed( 'undelete' ) ) {
+                                       $undelete = SpecialPage::getTitleFor( 'Undelete' );
+                                       $links[] = $linkRenderer->makeKnownLink(
+                                               $undelete,
+                                               $this->msg( 'deletedhist' )->text(),
+                                               [],
+                                               [ 'target' => $this->targetObj->getPrefixedDBkey() ]
+                                       );
+                               }
+                       }
+                       # Logs themselves don't have histories or archived revisions
+                       $this->getOutput()->addSubtitle( $this->getLanguage()->pipeList( $links ) );
+               }
+       }
+
+       /**
+        * Get the condition used for fetching log snippets
+        * @return array
+        */
+       protected function getLogQueryCond() {
+               $conds = [];
+               // Revision delete logs for these item
+               $conds['log_type'] = [ 'delete', 'suppress' ];
+               $conds['log_action'] = $this->getList()->getLogAction();
+               $conds['ls_field'] = RevisionDeleter::getRelationType( $this->typeName );
+               $conds['ls_value'] = $this->ids;
+
+               return $conds;
+       }
+
+       /**
+        * Show a deleted file version requested by the visitor.
+        * @todo Mostly copied from Special:Undelete. Refactor.
+        * @param string $archiveName
+        * @throws MWException
+        * @throws PermissionsError
+        */
+       protected function tryShowFile( $archiveName ) {
+               $repo = RepoGroup::singleton()->getLocalRepo();
+               $oimage = $repo->newFromArchiveName( $this->targetObj, $archiveName );
+               $oimage->load();
+               // Check if user is allowed to see this file
+               if ( !$oimage->exists() ) {
+                       $this->getOutput()->addWikiMsg( 'revdelete-no-file' );
+
+                       return;
+               }
+               $user = $this->getUser();
+               if ( !$oimage->userCan( File::DELETED_FILE, $user ) ) {
+                       if ( $oimage->isDeleted( File::DELETED_RESTRICTED ) ) {
+                               throw new PermissionsError( 'suppressrevision' );
+                       } else {
+                               throw new PermissionsError( 'deletedtext' );
+                       }
+               }
+               if ( !$user->matchEditToken( $this->token, $archiveName ) ) {
+                       $lang = $this->getLanguage();
+                       $this->getOutput()->addWikiMsg( 'revdelete-show-file-confirm',
+                               $this->targetObj->getText(),
+                               $lang->userDate( $oimage->getTimestamp(), $user ),
+                               $lang->userTime( $oimage->getTimestamp(), $user ) );
+                       $this->getOutput()->addHTML(
+                               Xml::openElement( 'form', [
+                                       'method' => 'POST',
+                                       'action' => $this->getPageTitle()->getLocalURL( [
+                                                       'target' => $this->targetObj->getPrefixedDBkey(),
+                                                       'file' => $archiveName,
+                                                       'token' => $user->getEditToken( $archiveName ),
+                                               ] )
+                                       ]
+                               ) .
+                               Xml::submitButton( $this->msg( 'revdelete-show-file-submit' )->text() ) .
+                               '</form>'
+                       );
+
+                       return;
+               }
+               $this->getOutput()->disable();
+               # We mustn't allow the output to be CDN cached, otherwise
+               # if an admin previews a deleted image, and it's cached, then
+               # a user without appropriate permissions can toddle off and
+               # nab the image, and CDN will serve it
+               $this->getRequest()->response()->header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' );
+               $this->getRequest()->response()->header(
+                       'Cache-Control: no-cache, no-store, max-age=0, must-revalidate'
+               );
+               $this->getRequest()->response()->header( 'Pragma: no-cache' );
+
+               $key = $oimage->getStorageKey();
+               $path = $repo->getZonePath( 'deleted' ) . '/' . $repo->getDeletedHashPath( $key ) . $key;
+               $repo->streamFileWithStatus( $path );
+       }
+
+       /**
+        * Get the list object for this request
+        * @return RevDelList
+        */
+       protected function getList() {
+               if ( is_null( $this->revDelList ) ) {
+                       $this->revDelList = RevisionDeleter::createList(
+                               $this->typeName, $this->getContext(), $this->targetObj, $this->ids
+                       );
+               }
+
+               return $this->revDelList;
+       }
+
+       /**
+        * Show a list of items that we will operate on, and show a form with checkboxes
+        * which will allow the user to choose new visibility settings.
+        */
+       protected function showForm() {
+               $userAllowed = true;
+
+               // Messages: revdelete-selected-text, revdelete-selected-file, logdelete-selected
+               $out = $this->getOutput();
+               $out->wrapWikiMsg( "<strong>$1</strong>", [ $this->typeLabels['selected'],
+                       $this->getLanguage()->formatNum( count( $this->ids ) ), $this->targetObj->getPrefixedText() ] );
+
+               $this->addHelpLink( 'Help:RevisionDelete' );
+               $out->addHTML( "<ul>" );
+
+               $numRevisions = 0;
+               // Live revisions...
+               $list = $this->getList();
+               for ( $list->reset(); $list->current(); $list->next() ) {
+                       $item = $list->current();
+
+                       if ( !$item->canView() ) {
+                               if ( !$this->submitClicked ) {
+                                       throw new PermissionsError( 'suppressrevision' );
+                               }
+                               $userAllowed = false;
+                       }
+
+                       $numRevisions++;
+                       $out->addHTML( $item->getHTML() );
+               }
+
+               if ( !$numRevisions ) {
+                       throw new ErrorPageError( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
+               }
+
+               $out->addHTML( "</ul>" );
+               // Explanation text
+               $this->addUsageText();
+
+               // Normal sysops can always see what they did, but can't always change it
+               if ( !$userAllowed ) {
+                       return;
+               }
+
+               // Show form if the user can submit
+               if ( $this->mIsAllowed ) {
+                       $out->addModules( [ 'mediawiki.special.revisionDelete' ] );
+                       $out->addModuleStyles( [ 'mediawiki.special',
+                               'mediawiki.interface.helpers.styles' ] );
+
+                       $form = Xml::openElement( 'form', [ 'method' => 'post',
+                                       'action' => $this->getPageTitle()->getLocalURL( [ 'action' => 'submit' ] ),
+                                       'id' => 'mw-revdel-form-revisions' ] ) .
+                               Xml::fieldset( $this->msg( 'revdelete-legend' )->text() ) .
+                               $this->buildCheckBoxes() .
+                               Xml::openElement( 'table' ) .
+                               "<tr>\n" .
+                                       '<td class="mw-label">' .
+                                               Xml::label( $this->msg( 'revdelete-log' )->text(), 'wpRevDeleteReasonList' ) .
+                                       '</td>' .
+                                       '<td class="mw-input">' .
+                                               Xml::listDropDown( 'wpRevDeleteReasonList',
+                                                       $this->msg( 'revdelete-reason-dropdown' )->inContentLanguage()->text(),
+                                                       $this->msg( 'revdelete-reasonotherlist' )->inContentLanguage()->text(),
+                                                       $this->getRequest()->getText( 'wpRevDeleteReasonList', 'other' ), 'wpReasonDropDown'
+                                               ) .
+                                       '</td>' .
+                               "</tr><tr>\n" .
+                                       '<td class="mw-label">' .
+                                               Xml::label( $this->msg( 'revdelete-otherreason' )->text(), 'wpReason' ) .
+                                       '</td>' .
+                                       '<td class="mw-input">' .
+                                               Xml::input( 'wpReason', 60, $this->otherReason, [
+                                                       'id' => 'wpReason',
+                                                       // HTML maxlength uses "UTF-16 code units", which means that characters outside BMP
+                                                       // (e.g. emojis) count for two each. This limit is overridden in JS to instead count
+                                                       // Unicode codepoints.
+                                                       // "- 155" is to leave room for the 'wpRevDeleteReasonList' value.
+                                                       'maxlength' => CommentStore::COMMENT_CHARACTER_LIMIT - 155,
+                                               ] ) .
+                                       '</td>' .
+                               "</tr><tr>\n" .
+                                       '<td></td>' .
+                                       '<td class="mw-submit">' .
+                                               Xml::submitButton( $this->msg( 'revdelete-submit', $numRevisions )->text(),
+                                                       [ 'name' => 'wpSubmit' ] ) .
+                                       '</td>' .
+                               "</tr>\n" .
+                               Xml::closeElement( 'table' ) .
+                               Html::hidden( 'wpEditToken', $this->getUser()->getEditToken() ) .
+                               Html::hidden( 'target', $this->targetObj->getPrefixedText() ) .
+                               Html::hidden( 'type', $this->typeName ) .
+                               Html::hidden( 'ids', implode( ',', $this->ids ) ) .
+                               Xml::closeElement( 'fieldset' ) . "\n" .
+                               Xml::closeElement( 'form' ) . "\n";
+                       // Show link to edit the dropdown reasons
+                       if ( $this->getUser()->isAllowed( 'editinterface' ) ) {
+                               $link = $this->getLinkRenderer()->makeKnownLink(
+                                       $this->msg( 'revdelete-reason-dropdown' )->inContentLanguage()->getTitle(),
+                                       $this->msg( 'revdelete-edit-reasonlist' )->text(),
+                                       [],
+                                       [ 'action' => 'edit' ]
+                               );
+                               $form .= Xml::tags( 'p', [ 'class' => 'mw-revdel-editreasons' ], $link ) . "\n";
+                       }
+               } else {
+                       $form = '';
+               }
+               $out->addHTML( $form );
+       }
+
+       /**
+        * Show some introductory text
+        * @todo FIXME: Wikimedia-specific policy text
+        */
+       protected function addUsageText() {
+               // Messages: revdelete-text-text, revdelete-text-file, logdelete-text
+               $this->getOutput()->wrapWikiMsg(
+                       "<strong>$1</strong>\n$2", $this->typeLabels['text'],
+                       'revdelete-text-others'
+               );
+
+               if ( $this->getUser()->isAllowed( 'suppressrevision' ) ) {
+                       $this->getOutput()->addWikiMsg( 'revdelete-suppress-text' );
+               }
+
+               if ( $this->mIsAllowed ) {
+                       $this->getOutput()->addWikiMsg( 'revdelete-confirm' );
+               }
+       }
+
+       /**
+        * @return string HTML
+        */
+       protected function buildCheckBoxes() {
+               $html = '<table>';
+               // If there is just one item, use checkboxes
+               $list = $this->getList();
+               if ( $list->length() == 1 ) {
+                       $list->reset();
+                       $bitfield = $list->current()->getBits(); // existing field
+
+                       if ( $this->submitClicked ) {
+                               $bitfield = RevisionDeleter::extractBitfield( $this->extractBitParams(), $bitfield );
+                       }
+
+                       foreach ( $this->checks as $item ) {
+                               // Messages: revdelete-hide-text, revdelete-hide-image, revdelete-hide-name,
+                               // revdelete-hide-comment, revdelete-hide-user, revdelete-hide-restricted
+                               list( $message, $name, $field ) = $item;
+                               $innerHTML = Xml::checkLabel(
+                                       $this->msg( $message )->text(),
+                                       $name,
+                                       $name,
+                                       $bitfield & $field
+                               );
+
+                               if ( $field == Revision::DELETED_RESTRICTED ) {
+                                       $innerHTML = "<b>$innerHTML</b>";
+                               }
+
+                               $line = Xml::tags( 'td', [ 'class' => 'mw-input' ], $innerHTML );
+                               $html .= "<tr>$line</tr>\n";
+                       }
+               } else {
+                       // Otherwise, use tri-state radios
+                       $html .= '<tr>';
+                       $html .= '<th class="mw-revdel-checkbox">'
+                               . $this->msg( 'revdelete-radio-same' )->escaped() . '</th>';
+                       $html .= '<th class="mw-revdel-checkbox">'
+                               . $this->msg( 'revdelete-radio-unset' )->escaped() . '</th>';
+                       $html .= '<th class="mw-revdel-checkbox">'
+                               . $this->msg( 'revdelete-radio-set' )->escaped() . '</th>';
+                       $html .= "<th></th></tr>\n";
+                       foreach ( $this->checks as $item ) {
+                               // Messages: revdelete-hide-text, revdelete-hide-image, revdelete-hide-name,
+                               // revdelete-hide-comment, revdelete-hide-user, revdelete-hide-restricted
+                               list( $message, $name, $field ) = $item;
+                               // If there are several items, use third state by default...
+                               if ( $this->submitClicked ) {
+                                       $selected = $this->getRequest()->getInt( $name, 0 /* unchecked */ );
+                               } else {
+                                       $selected = -1; // use existing field
+                               }
+                               $line = '<td class="mw-revdel-checkbox">' . Xml::radio( $name, -1, $selected == -1 ) . '</td>';
+                               $line .= '<td class="mw-revdel-checkbox">' . Xml::radio( $name, 0, $selected == 0 ) . '</td>';
+                               $line .= '<td class="mw-revdel-checkbox">' . Xml::radio( $name, 1, $selected == 1 ) . '</td>';
+                               $label = $this->msg( $message )->escaped();
+                               if ( $field == Revision::DELETED_RESTRICTED ) {
+                                       $label = "<b>$label</b>";
+                               }
+                               $line .= "<td>$label</td>";
+                               $html .= "<tr>$line</tr>\n";
+                       }
+               }
+
+               $html .= '</table>';
+
+               return $html;
+       }
+
+       /**
+        * UI entry point for form submission.
+        * @throws PermissionsError
+        * @return bool
+        */
+       protected function submit() {
+               # Check edit token on submission
+               $token = $this->getRequest()->getVal( 'wpEditToken' );
+               if ( $this->submitClicked && !$this->getUser()->matchEditToken( $token ) ) {
+                       $this->getOutput()->addWikiMsg( 'sessionfailure' );
+
+                       return false;
+               }
+               $bitParams = $this->extractBitParams();
+               // from dropdown
+               $listReason = $this->getRequest()->getText( 'wpRevDeleteReasonList', 'other' );
+               $comment = $listReason;
+               if ( $comment === 'other' ) {
+                       $comment = $this->otherReason;
+               } elseif ( $this->otherReason !== '' ) {
+                       // Entry from drop down menu + additional comment
+                       $comment .= $this->msg( 'colon-separator' )->inContentLanguage()->text()
+                               . $this->otherReason;
+               }
+               # Can the user set this field?
+               if ( $bitParams[Revision::DELETED_RESTRICTED] == 1
+                       && !$this->getUser()->isAllowed( 'suppressrevision' )
+               ) {
+                       throw new PermissionsError( 'suppressrevision' );
+               }
+               # If the save went through, go to success message...
+               $status = $this->save( $bitParams, $comment );
+               if ( $status->isGood() ) {
+                       $this->success();
+
+                       return true;
+               } else {
+                       # ...otherwise, bounce back to form...
+                       $this->failure( $status );
+               }
+
+               return false;
+       }
+
+       /**
+        * Report that the submit operation succeeded
+        */
+       protected function success() {
+               // Messages: revdelete-success, logdelete-success
+               $this->getOutput()->setPageTitle( $this->msg( 'actioncomplete' ) );
+               $this->getOutput()->wrapWikiMsg(
+                       "<div class=\"successbox\">\n$1\n</div>",
+                       $this->typeLabels['success']
+               );
+               $this->wasSaved = true;
+               $this->revDelList->reloadFromMaster();
+               $this->showForm();
+       }
+
+       /**
+        * Report that the submit operation failed
+        * @param Status $status
+        */
+       protected function failure( $status ) {
+               // Messages: revdelete-failure, logdelete-failure
+               $this->getOutput()->setPageTitle( $this->msg( 'actionfailed' ) );
+               $this->getOutput()->wrapWikiTextAsInterface(
+                       'errorbox',
+                       $status->getWikiText( $this->typeLabels['failure'] )
+               );
+               $this->showForm();
+       }
+
+       /**
+        * Put together an array that contains -1, 0, or the *_deleted const for each bit
+        *
+        * @return array
+        */
+       protected function extractBitParams() {
+               $bitfield = [];
+               foreach ( $this->checks as $item ) {
+                       list( /* message */, $name, $field ) = $item;
+                       $val = $this->getRequest()->getInt( $name, 0 /* unchecked */ );
+                       if ( $val < -1 || $val > 1 ) {
+                               $val = -1; // -1 for existing value
+                       }
+                       $bitfield[$field] = $val;
+               }
+               if ( !isset( $bitfield[Revision::DELETED_RESTRICTED] ) ) {
+                       $bitfield[Revision::DELETED_RESTRICTED] = 0;
+               }
+
+               return $bitfield;
+       }
+
+       /**
+        * Do the write operations. Simple wrapper for RevDel*List::setVisibility().
+        * @param array $bitPars ExtractBitParams() bitfield array
+        * @param string $reason
+        * @return Status
+        */
+       protected function save( array $bitPars, $reason ) {
+               return $this->getList()->setVisibility(
+                       [ 'value' => $bitPars, 'comment' => $reason ]
+               );
+       }
+
+       protected function getGroupName() {
+               return 'pagetools';
+       }
+}
diff --git a/includes/specials/SpecialRevisiondelete.php b/includes/specials/SpecialRevisiondelete.php
deleted file mode 100644 (file)
index f0bac45..0000000
+++ /dev/null
@@ -1,685 +0,0 @@
-<?php
-/**
- * Implements Special:Revisiondelete
- *
- * 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 allowing users with the appropriate permissions to view
- * and hide revisions. Log items can also be hidden.
- *
- * @ingroup SpecialPage
- */
-class SpecialRevisionDelete extends UnlistedSpecialPage {
-       /** @var bool Was the DB modified in this request */
-       protected $wasSaved = false;
-
-       /** @var bool True if the submit button was clicked, and the form was posted */
-       private $submitClicked;
-
-       /** @var array Target ID list */
-       private $ids;
-
-       /** @var string Archive name, for reviewing deleted files */
-       private $archiveName;
-
-       /** @var string Edit token for securing image views against XSS */
-       private $token;
-
-       /** @var Title Title object for target parameter */
-       private $targetObj;
-
-       /** @var string Deletion type, may be revision, archive, oldimage, filearchive, logging. */
-       private $typeName;
-
-       /** @var array Array of checkbox specs (message, name, deletion bits) */
-       private $checks;
-
-       /** @var array UI Labels about the current type */
-       private $typeLabels;
-
-       /** @var RevDelList RevDelList object, storing the list of items to be deleted/undeleted */
-       private $revDelList;
-
-       /** @var bool Whether user is allowed to perform the action */
-       private $mIsAllowed;
-
-       /** @var string */
-       private $otherReason;
-
-       /**
-        * UI labels for each type.
-        */
-       private static $UILabels = [
-               'revision' => [
-                       'check-label' => 'revdelete-hide-text',
-                       'success' => 'revdelete-success',
-                       'failure' => 'revdelete-failure',
-                       'text' => 'revdelete-text-text',
-                       'selected' => 'revdelete-selected-text',
-               ],
-               'archive' => [
-                       'check-label' => 'revdelete-hide-text',
-                       'success' => 'revdelete-success',
-                       'failure' => 'revdelete-failure',
-                       'text' => 'revdelete-text-text',
-                       'selected' => 'revdelete-selected-text',
-               ],
-               'oldimage' => [
-                       'check-label' => 'revdelete-hide-image',
-                       'success' => 'revdelete-success',
-                       'failure' => 'revdelete-failure',
-                       'text' => 'revdelete-text-file',
-                       'selected' => 'revdelete-selected-file',
-               ],
-               'filearchive' => [
-                       'check-label' => 'revdelete-hide-image',
-                       'success' => 'revdelete-success',
-                       'failure' => 'revdelete-failure',
-                       'text' => 'revdelete-text-file',
-                       'selected' => 'revdelete-selected-file',
-               ],
-               'logging' => [
-                       'check-label' => 'revdelete-hide-name',
-                       'success' => 'logdelete-success',
-                       'failure' => 'logdelete-failure',
-                       'text' => 'logdelete-text',
-                       'selected' => 'logdelete-selected',
-               ],
-       ];
-
-       public function __construct() {
-               parent::__construct( 'Revisiondelete', 'deleterevision' );
-       }
-
-       public function doesWrites() {
-               return true;
-       }
-
-       public function execute( $par ) {
-               $this->useTransactionalTimeLimit();
-
-               $this->checkPermissions();
-               $this->checkReadOnly();
-
-               $output = $this->getOutput();
-               $user = $this->getUser();
-
-               // Check blocks
-               if ( $user->isBlocked() ) {
-                       throw new UserBlockedError( $user->getBlock() );
-               }
-
-               $this->setHeaders();
-               $this->outputHeader();
-               $request = $this->getRequest();
-               $this->submitClicked = $request->wasPosted() && $request->getBool( 'wpSubmit' );
-               # Handle our many different possible input types.
-               $ids = $request->getVal( 'ids' );
-               if ( !is_null( $ids ) ) {
-                       # Allow CSV, for backwards compatibility, or a single ID for show/hide links
-                       $this->ids = explode( ',', $ids );
-               } else {
-                       # Array input
-                       $this->ids = array_keys( $request->getArray( 'ids', [] ) );
-               }
-               // $this->ids = array_map( 'intval', $this->ids );
-               $this->ids = array_unique( array_filter( $this->ids ) );
-
-               $this->typeName = $request->getVal( 'type' );
-               $this->targetObj = Title::newFromText( $request->getText( 'target' ) );
-
-               # For reviewing deleted files...
-               $this->archiveName = $request->getVal( 'file' );
-               $this->token = $request->getVal( 'token' );
-               if ( $this->archiveName && $this->targetObj ) {
-                       $this->tryShowFile( $this->archiveName );
-
-                       return;
-               }
-
-               $this->typeName = RevisionDeleter::getCanonicalTypeName( $this->typeName );
-
-               # No targets?
-               if ( !$this->typeName || count( $this->ids ) == 0 ) {
-                       throw new ErrorPageError( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
-               }
-
-               # Allow the list type to adjust the passed target
-               $this->targetObj = RevisionDeleter::suggestTarget(
-                       $this->typeName,
-                       $this->targetObj,
-                       $this->ids
-               );
-
-               # We need a target page!
-               if ( $this->targetObj === null ) {
-                       $output->addWikiMsg( 'undelete-header' );
-
-                       return;
-               }
-
-               $this->typeLabels = self::$UILabels[$this->typeName];
-               $list = $this->getList();
-               $list->reset();
-               $this->mIsAllowed = $user->isAllowed( RevisionDeleter::getRestriction( $this->typeName ) );
-               $canViewSuppressedOnly = $this->getUser()->isAllowed( 'viewsuppressed' ) &&
-                       !$this->getUser()->isAllowed( 'suppressrevision' );
-               $pageIsSuppressed = $list->areAnySuppressed();
-               $this->mIsAllowed = $this->mIsAllowed && !( $canViewSuppressedOnly && $pageIsSuppressed );
-
-               $this->otherReason = $request->getVal( 'wpReason' );
-               # Give a link to the logs/hist for this page
-               $this->showConvenienceLinks();
-
-               # Initialise checkboxes
-               $this->checks = [
-                       # Messages: revdelete-hide-text, revdelete-hide-image, revdelete-hide-name
-                       [ $this->typeLabels['check-label'], 'wpHidePrimary',
-                               RevisionDeleter::getRevdelConstant( $this->typeName )
-                       ],
-                       [ 'revdelete-hide-comment', 'wpHideComment', Revision::DELETED_COMMENT ],
-                       [ 'revdelete-hide-user', 'wpHideUser', Revision::DELETED_USER ]
-               ];
-               if ( $user->isAllowed( 'suppressrevision' ) ) {
-                       $this->checks[] = [ 'revdelete-hide-restricted',
-                               'wpHideRestricted', Revision::DELETED_RESTRICTED ];
-               }
-
-               # Either submit or create our form
-               if ( $this->mIsAllowed && $this->submitClicked ) {
-                       $this->submit();
-               } else {
-                       $this->showForm();
-               }
-
-               if ( $user->isAllowed( 'deletedhistory' ) ) {
-                       $qc = $this->getLogQueryCond();
-                       # Show relevant lines from the deletion log
-                       $deleteLogPage = new LogPage( 'delete' );
-                       $output->addHTML( "<h2>" . $deleteLogPage->getName()->escaped() . "</h2>\n" );
-                       LogEventsList::showLogExtract(
-                               $output,
-                               'delete',
-                               $this->targetObj,
-                               '', /* user */
-                               [ 'lim' => 25, 'conds' => $qc, 'useMaster' => $this->wasSaved ]
-                       );
-               }
-               # Show relevant lines from the suppression log
-               if ( $user->isAllowed( 'suppressionlog' ) ) {
-                       $suppressLogPage = new LogPage( 'suppress' );
-                       $output->addHTML( "<h2>" . $suppressLogPage->getName()->escaped() . "</h2>\n" );
-                       LogEventsList::showLogExtract(
-                               $output,
-                               'suppress',
-                               $this->targetObj,
-                               '',
-                               [ 'lim' => 25, 'conds' => $qc, 'useMaster' => $this->wasSaved ]
-                       );
-               }
-       }
-
-       /**
-        * Show some useful links in the subtitle
-        */
-       protected function showConvenienceLinks() {
-               $linkRenderer = $this->getLinkRenderer();
-               # Give a link to the logs/hist for this page
-               if ( $this->targetObj ) {
-                       // Also set header tabs to be for the target.
-                       $this->getSkin()->setRelevantTitle( $this->targetObj );
-
-                       $links = [];
-                       $links[] = $linkRenderer->makeKnownLink(
-                               SpecialPage::getTitleFor( 'Log' ),
-                               $this->msg( 'viewpagelogs' )->text(),
-                               [],
-                               [ 'page' => $this->targetObj->getPrefixedText() ]
-                       );
-                       if ( !$this->targetObj->isSpecialPage() ) {
-                               # Give a link to the page history
-                               $links[] = $linkRenderer->makeKnownLink(
-                                       $this->targetObj,
-                                       $this->msg( 'pagehist' )->text(),
-                                       [],
-                                       [ 'action' => 'history' ]
-                               );
-                               # Link to deleted edits
-                               if ( $this->getUser()->isAllowed( 'undelete' ) ) {
-                                       $undelete = SpecialPage::getTitleFor( 'Undelete' );
-                                       $links[] = $linkRenderer->makeKnownLink(
-                                               $undelete,
-                                               $this->msg( 'deletedhist' )->text(),
-                                               [],
-                                               [ 'target' => $this->targetObj->getPrefixedDBkey() ]
-                                       );
-                               }
-                       }
-                       # Logs themselves don't have histories or archived revisions
-                       $this->getOutput()->addSubtitle( $this->getLanguage()->pipeList( $links ) );
-               }
-       }
-
-       /**
-        * Get the condition used for fetching log snippets
-        * @return array
-        */
-       protected function getLogQueryCond() {
-               $conds = [];
-               // Revision delete logs for these item
-               $conds['log_type'] = [ 'delete', 'suppress' ];
-               $conds['log_action'] = $this->getList()->getLogAction();
-               $conds['ls_field'] = RevisionDeleter::getRelationType( $this->typeName );
-               $conds['ls_value'] = $this->ids;
-
-               return $conds;
-       }
-
-       /**
-        * Show a deleted file version requested by the visitor.
-        * @todo Mostly copied from Special:Undelete. Refactor.
-        * @param string $archiveName
-        * @throws MWException
-        * @throws PermissionsError
-        */
-       protected function tryShowFile( $archiveName ) {
-               $repo = RepoGroup::singleton()->getLocalRepo();
-               $oimage = $repo->newFromArchiveName( $this->targetObj, $archiveName );
-               $oimage->load();
-               // Check if user is allowed to see this file
-               if ( !$oimage->exists() ) {
-                       $this->getOutput()->addWikiMsg( 'revdelete-no-file' );
-
-                       return;
-               }
-               $user = $this->getUser();
-               if ( !$oimage->userCan( File::DELETED_FILE, $user ) ) {
-                       if ( $oimage->isDeleted( File::DELETED_RESTRICTED ) ) {
-                               throw new PermissionsError( 'suppressrevision' );
-                       } else {
-                               throw new PermissionsError( 'deletedtext' );
-                       }
-               }
-               if ( !$user->matchEditToken( $this->token, $archiveName ) ) {
-                       $lang = $this->getLanguage();
-                       $this->getOutput()->addWikiMsg( 'revdelete-show-file-confirm',
-                               $this->targetObj->getText(),
-                               $lang->userDate( $oimage->getTimestamp(), $user ),
-                               $lang->userTime( $oimage->getTimestamp(), $user ) );
-                       $this->getOutput()->addHTML(
-                               Xml::openElement( 'form', [
-                                       'method' => 'POST',
-                                       'action' => $this->getPageTitle()->getLocalURL( [
-                                                       'target' => $this->targetObj->getPrefixedDBkey(),
-                                                       'file' => $archiveName,
-                                                       'token' => $user->getEditToken( $archiveName ),
-                                               ] )
-                                       ]
-                               ) .
-                               Xml::submitButton( $this->msg( 'revdelete-show-file-submit' )->text() ) .
-                               '</form>'
-                       );
-
-                       return;
-               }
-               $this->getOutput()->disable();
-               # We mustn't allow the output to be CDN cached, otherwise
-               # if an admin previews a deleted image, and it's cached, then
-               # a user without appropriate permissions can toddle off and
-               # nab the image, and CDN will serve it
-               $this->getRequest()->response()->header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' );
-               $this->getRequest()->response()->header(
-                       'Cache-Control: no-cache, no-store, max-age=0, must-revalidate'
-               );
-               $this->getRequest()->response()->header( 'Pragma: no-cache' );
-
-               $key = $oimage->getStorageKey();
-               $path = $repo->getZonePath( 'deleted' ) . '/' . $repo->getDeletedHashPath( $key ) . $key;
-               $repo->streamFile( $path );
-       }
-
-       /**
-        * Get the list object for this request
-        * @return RevDelList
-        */
-       protected function getList() {
-               if ( is_null( $this->revDelList ) ) {
-                       $this->revDelList = RevisionDeleter::createList(
-                               $this->typeName, $this->getContext(), $this->targetObj, $this->ids
-                       );
-               }
-
-               return $this->revDelList;
-       }
-
-       /**
-        * Show a list of items that we will operate on, and show a form with checkboxes
-        * which will allow the user to choose new visibility settings.
-        */
-       protected function showForm() {
-               $userAllowed = true;
-
-               // Messages: revdelete-selected-text, revdelete-selected-file, logdelete-selected
-               $out = $this->getOutput();
-               $out->wrapWikiMsg( "<strong>$1</strong>", [ $this->typeLabels['selected'],
-                       $this->getLanguage()->formatNum( count( $this->ids ) ), $this->targetObj->getPrefixedText() ] );
-
-               $this->addHelpLink( 'Help:RevisionDelete' );
-               $out->addHTML( "<ul>" );
-
-               $numRevisions = 0;
-               // Live revisions...
-               $list = $this->getList();
-               for ( $list->reset(); $list->current(); $list->next() ) {
-                       $item = $list->current();
-
-                       if ( !$item->canView() ) {
-                               if ( !$this->submitClicked ) {
-                                       throw new PermissionsError( 'suppressrevision' );
-                               }
-                               $userAllowed = false;
-                       }
-
-                       $numRevisions++;
-                       $out->addHTML( $item->getHTML() );
-               }
-
-               if ( !$numRevisions ) {
-                       throw new ErrorPageError( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
-               }
-
-               $out->addHTML( "</ul>" );
-               // Explanation text
-               $this->addUsageText();
-
-               // Normal sysops can always see what they did, but can't always change it
-               if ( !$userAllowed ) {
-                       return;
-               }
-
-               // Show form if the user can submit
-               if ( $this->mIsAllowed ) {
-                       $out->addModules( [ 'mediawiki.special.revisionDelete' ] );
-                       $out->addModuleStyles( [ 'mediawiki.special',
-                               'mediawiki.interface.helpers.styles' ] );
-
-                       $form = Xml::openElement( 'form', [ 'method' => 'post',
-                                       'action' => $this->getPageTitle()->getLocalURL( [ 'action' => 'submit' ] ),
-                                       'id' => 'mw-revdel-form-revisions' ] ) .
-                               Xml::fieldset( $this->msg( 'revdelete-legend' )->text() ) .
-                               $this->buildCheckBoxes() .
-                               Xml::openElement( 'table' ) .
-                               "<tr>\n" .
-                                       '<td class="mw-label">' .
-                                               Xml::label( $this->msg( 'revdelete-log' )->text(), 'wpRevDeleteReasonList' ) .
-                                       '</td>' .
-                                       '<td class="mw-input">' .
-                                               Xml::listDropDown( 'wpRevDeleteReasonList',
-                                                       $this->msg( 'revdelete-reason-dropdown' )->inContentLanguage()->text(),
-                                                       $this->msg( 'revdelete-reasonotherlist' )->inContentLanguage()->text(),
-                                                       $this->getRequest()->getText( 'wpRevDeleteReasonList', 'other' ), 'wpReasonDropDown'
-                                               ) .
-                                       '</td>' .
-                               "</tr><tr>\n" .
-                                       '<td class="mw-label">' .
-                                               Xml::label( $this->msg( 'revdelete-otherreason' )->text(), 'wpReason' ) .
-                                       '</td>' .
-                                       '<td class="mw-input">' .
-                                               Xml::input( 'wpReason', 60, $this->otherReason, [
-                                                       'id' => 'wpReason',
-                                                       // HTML maxlength uses "UTF-16 code units", which means that characters outside BMP
-                                                       // (e.g. emojis) count for two each. This limit is overridden in JS to instead count
-                                                       // Unicode codepoints.
-                                                       // "- 155" is to leave room for the 'wpRevDeleteReasonList' value.
-                                                       'maxlength' => CommentStore::COMMENT_CHARACTER_LIMIT - 155,
-                                               ] ) .
-                                       '</td>' .
-                               "</tr><tr>\n" .
-                                       '<td></td>' .
-                                       '<td class="mw-submit">' .
-                                               Xml::submitButton( $this->msg( 'revdelete-submit', $numRevisions )->text(),
-                                                       [ 'name' => 'wpSubmit' ] ) .
-                                       '</td>' .
-                               "</tr>\n" .
-                               Xml::closeElement( 'table' ) .
-                               Html::hidden( 'wpEditToken', $this->getUser()->getEditToken() ) .
-                               Html::hidden( 'target', $this->targetObj->getPrefixedText() ) .
-                               Html::hidden( 'type', $this->typeName ) .
-                               Html::hidden( 'ids', implode( ',', $this->ids ) ) .
-                               Xml::closeElement( 'fieldset' ) . "\n" .
-                               Xml::closeElement( 'form' ) . "\n";
-                       // Show link to edit the dropdown reasons
-                       if ( $this->getUser()->isAllowed( 'editinterface' ) ) {
-                               $link = $this->getLinkRenderer()->makeKnownLink(
-                                       $this->msg( 'revdelete-reason-dropdown' )->inContentLanguage()->getTitle(),
-                                       $this->msg( 'revdelete-edit-reasonlist' )->text(),
-                                       [],
-                                       [ 'action' => 'edit' ]
-                               );
-                               $form .= Xml::tags( 'p', [ 'class' => 'mw-revdel-editreasons' ], $link ) . "\n";
-                       }
-               } else {
-                       $form = '';
-               }
-               $out->addHTML( $form );
-       }
-
-       /**
-        * Show some introductory text
-        * @todo FIXME: Wikimedia-specific policy text
-        */
-       protected function addUsageText() {
-               // Messages: revdelete-text-text, revdelete-text-file, logdelete-text
-               $this->getOutput()->wrapWikiMsg(
-                       "<strong>$1</strong>\n$2", $this->typeLabels['text'],
-                       'revdelete-text-others'
-               );
-
-               if ( $this->getUser()->isAllowed( 'suppressrevision' ) ) {
-                       $this->getOutput()->addWikiMsg( 'revdelete-suppress-text' );
-               }
-
-               if ( $this->mIsAllowed ) {
-                       $this->getOutput()->addWikiMsg( 'revdelete-confirm' );
-               }
-       }
-
-       /**
-        * @return string HTML
-        */
-       protected function buildCheckBoxes() {
-               $html = '<table>';
-               // If there is just one item, use checkboxes
-               $list = $this->getList();
-               if ( $list->length() == 1 ) {
-                       $list->reset();
-                       $bitfield = $list->current()->getBits(); // existing field
-
-                       if ( $this->submitClicked ) {
-                               $bitfield = RevisionDeleter::extractBitfield( $this->extractBitParams(), $bitfield );
-                       }
-
-                       foreach ( $this->checks as $item ) {
-                               // Messages: revdelete-hide-text, revdelete-hide-image, revdelete-hide-name,
-                               // revdelete-hide-comment, revdelete-hide-user, revdelete-hide-restricted
-                               list( $message, $name, $field ) = $item;
-                               $innerHTML = Xml::checkLabel(
-                                       $this->msg( $message )->text(),
-                                       $name,
-                                       $name,
-                                       $bitfield & $field
-                               );
-
-                               if ( $field == Revision::DELETED_RESTRICTED ) {
-                                       $innerHTML = "<b>$innerHTML</b>";
-                               }
-
-                               $line = Xml::tags( 'td', [ 'class' => 'mw-input' ], $innerHTML );
-                               $html .= "<tr>$line</tr>\n";
-                       }
-               } else {
-                       // Otherwise, use tri-state radios
-                       $html .= '<tr>';
-                       $html .= '<th class="mw-revdel-checkbox">'
-                               . $this->msg( 'revdelete-radio-same' )->escaped() . '</th>';
-                       $html .= '<th class="mw-revdel-checkbox">'
-                               . $this->msg( 'revdelete-radio-unset' )->escaped() . '</th>';
-                       $html .= '<th class="mw-revdel-checkbox">'
-                               . $this->msg( 'revdelete-radio-set' )->escaped() . '</th>';
-                       $html .= "<th></th></tr>\n";
-                       foreach ( $this->checks as $item ) {
-                               // Messages: revdelete-hide-text, revdelete-hide-image, revdelete-hide-name,
-                               // revdelete-hide-comment, revdelete-hide-user, revdelete-hide-restricted
-                               list( $message, $name, $field ) = $item;
-                               // If there are several items, use third state by default...
-                               if ( $this->submitClicked ) {
-                                       $selected = $this->getRequest()->getInt( $name, 0 /* unchecked */ );
-                               } else {
-                                       $selected = -1; // use existing field
-                               }
-                               $line = '<td class="mw-revdel-checkbox">' . Xml::radio( $name, -1, $selected == -1 ) . '</td>';
-                               $line .= '<td class="mw-revdel-checkbox">' . Xml::radio( $name, 0, $selected == 0 ) . '</td>';
-                               $line .= '<td class="mw-revdel-checkbox">' . Xml::radio( $name, 1, $selected == 1 ) . '</td>';
-                               $label = $this->msg( $message )->escaped();
-                               if ( $field == Revision::DELETED_RESTRICTED ) {
-                                       $label = "<b>$label</b>";
-                               }
-                               $line .= "<td>$label</td>";
-                               $html .= "<tr>$line</tr>\n";
-                       }
-               }
-
-               $html .= '</table>';
-
-               return $html;
-       }
-
-       /**
-        * UI entry point for form submission.
-        * @throws PermissionsError
-        * @return bool
-        */
-       protected function submit() {
-               # Check edit token on submission
-               $token = $this->getRequest()->getVal( 'wpEditToken' );
-               if ( $this->submitClicked && !$this->getUser()->matchEditToken( $token ) ) {
-                       $this->getOutput()->addWikiMsg( 'sessionfailure' );
-
-                       return false;
-               }
-               $bitParams = $this->extractBitParams();
-               // from dropdown
-               $listReason = $this->getRequest()->getText( 'wpRevDeleteReasonList', 'other' );
-               $comment = $listReason;
-               if ( $comment === 'other' ) {
-                       $comment = $this->otherReason;
-               } elseif ( $this->otherReason !== '' ) {
-                       // Entry from drop down menu + additional comment
-                       $comment .= $this->msg( 'colon-separator' )->inContentLanguage()->text()
-                               . $this->otherReason;
-               }
-               # Can the user set this field?
-               if ( $bitParams[Revision::DELETED_RESTRICTED] == 1
-                       && !$this->getUser()->isAllowed( 'suppressrevision' )
-               ) {
-                       throw new PermissionsError( 'suppressrevision' );
-               }
-               # If the save went through, go to success message...
-               $status = $this->save( $bitParams, $comment );
-               if ( $status->isGood() ) {
-                       $this->success();
-
-                       return true;
-               } else {
-                       # ...otherwise, bounce back to form...
-                       $this->failure( $status );
-               }
-
-               return false;
-       }
-
-       /**
-        * Report that the submit operation succeeded
-        */
-       protected function success() {
-               // Messages: revdelete-success, logdelete-success
-               $this->getOutput()->setPageTitle( $this->msg( 'actioncomplete' ) );
-               $this->getOutput()->wrapWikiMsg(
-                       "<div class=\"successbox\">\n$1\n</div>",
-                       $this->typeLabels['success']
-               );
-               $this->wasSaved = true;
-               $this->revDelList->reloadFromMaster();
-               $this->showForm();
-       }
-
-       /**
-        * Report that the submit operation failed
-        * @param Status $status
-        */
-       protected function failure( $status ) {
-               // Messages: revdelete-failure, logdelete-failure
-               $this->getOutput()->setPageTitle( $this->msg( 'actionfailed' ) );
-               $this->getOutput()->wrapWikiTextAsInterface(
-                       'errorbox',
-                       $status->getWikiText( $this->typeLabels['failure'] )
-               );
-               $this->showForm();
-       }
-
-       /**
-        * Put together an array that contains -1, 0, or the *_deleted const for each bit
-        *
-        * @return array
-        */
-       protected function extractBitParams() {
-               $bitfield = [];
-               foreach ( $this->checks as $item ) {
-                       list( /* message */, $name, $field ) = $item;
-                       $val = $this->getRequest()->getInt( $name, 0 /* unchecked */ );
-                       if ( $val < -1 || $val > 1 ) {
-                               $val = -1; // -1 for existing value
-                       }
-                       $bitfield[$field] = $val;
-               }
-               if ( !isset( $bitfield[Revision::DELETED_RESTRICTED] ) ) {
-                       $bitfield[Revision::DELETED_RESTRICTED] = 0;
-               }
-
-               return $bitfield;
-       }
-
-       /**
-        * Do the write operations. Simple wrapper for RevDel*List::setVisibility().
-        * @param array $bitPars ExtractBitParams() bitfield array
-        * @param string $reason
-        * @return Status
-        */
-       protected function save( array $bitPars, $reason ) {
-               return $this->getList()->setVisibility(
-                       [ 'value' => $bitPars, 'comment' => $reason ]
-               );
-       }
-
-       protected function getGroupName() {
-               return 'pagetools';
-       }
-}
index e6d0632..4adc247 100644 (file)
@@ -102,7 +102,7 @@ class SpecialSearch extends SpecialPage {
        /**
         * Entry point
         *
-        * @param string $par
+        * @param string|null $par
         */
        public function execute( $par ) {
                $request = $this->getRequest();
@@ -115,7 +115,7 @@ class SpecialSearch extends SpecialPage {
                // parameter, but also as part of the primary url. This can have PII implications
                // in releasing page view data. As such issue a 301 redirect to the correct
                // URL.
-               if ( strlen( $par ) && !strlen( $term ) ) {
+               if ( $par !== null && $par !== '' && $term === '' ) {
                        $query = $request->getValues();
                        unset( $query['title'] );
                        // Strip underscores from title parameter; most of the time we'll want
@@ -129,7 +129,7 @@ class SpecialSearch extends SpecialPage {
                $this->load();
                // TODO: This performs database actions on GET request, which is going to
                // be a problem for our multi-datacenter work.
-               if ( !is_null( $request->getVal( 'nsRemember' ) ) ) {
+               if ( $request->getCheck( 'nsRemember' ) ) {
                        $this->saveNamespaces();
                        // Remove the token from the URL to prevent the user from inadvertently
                        // exposing it (e.g. by pasting it into a public wiki page) or undoing
@@ -141,10 +141,7 @@ class SpecialSearch extends SpecialPage {
                }
 
                $this->searchEngineType = $request->getVal( 'srbackend' );
-               if (
-                       !$request->getVal( 'fulltext' ) &&
-                       $request->getVal( 'offset' ) === null
-               ) {
+               if ( !$request->getVal( 'fulltext' ) && !$request->getCheck( 'offset' ) ) {
                        $url = $this->goResult( $term );
                        if ( $url !== null ) {
                                // successful 'go'
@@ -246,14 +243,12 @@ class SpecialSearch extends SpecialPage {
                        $this->namespaces = $nslist;
                } elseif ( $profile === 'advanced' ) {
                        $this->namespaces = $nslist;
+               } elseif ( isset( $profiles[$profile]['namespaces'] ) ) {
+                       $this->namespaces = $profiles[$profile]['namespaces'];
                } else {
-                       if ( isset( $profiles[$profile]['namespaces'] ) ) {
-                               $this->namespaces = $profiles[$profile]['namespaces'];
-                       } else {
-                               // Unknown profile requested
-                               $profile = 'default';
-                               $this->namespaces = $profiles['default']['namespaces'];
-                       }
+                       // Unknown profile requested
+                       $profile = 'default';
+                       $this->namespaces = $profiles['default']['namespaces'];
                }
 
                $this->fulltext = $request->getVal( 'fulltext' );
@@ -335,13 +330,6 @@ class SpecialSearch extends SpecialPage {
                $showSuggestion = $title === null || !$title->isKnown();
                $search->setShowSuggestion( $showSuggestion );
 
-               $rewritten = $search->transformSearchTerm( $term );
-               if ( $rewritten !== $term ) {
-                       $term = $rewritten;
-                       wfDeprecated( 'SearchEngine::transformSearchTerm() (overridden by ' .
-                               get_class( $search ) . ')', '1.32' );
-               }
-
                $rewritten = $search->replacePrefixes( $term );
                if ( $rewritten !== $term ) {
                        wfDeprecated( 'SearchEngine::replacePrefixes() (overridden by ' .
@@ -474,8 +462,7 @@ class SpecialSearch extends SpecialPage {
                                $offset = $this->offset;
                        }
 
-                       $prevnext = $this->getLanguage()->viewPrevNext(
-                               $this->getPageTitle(),
+                       $prevnext = $this->buildPrevNextNavigation(
                                $offset,
                                $this->limit,
                                $this->powerSearchOptions() + [ 'search' => $term ],
@@ -660,7 +647,9 @@ class SpecialSearch extends SpecialPage {
                ) {
                        // Reset namespace preferences: namespaces are not searched
                        // when they're not mentioned in the URL parameters.
-                       foreach ( MWNamespace::getValidNamespaces() as $n ) {
+                       foreach ( MediaWikiServices::getInstance()->getNamespaceInfo()->getValidNamespaces()
+                               as $n
+                       ) {
                                $user->setOption( 'searchNs' . $n, false );
                        }
                        // The request parameters include all the namespaces to be searched.
index d90f72c..94da25d 100644 (file)
@@ -21,6 +21,7 @@
  * @ingroup SpecialPage
  */
 
+use MediaWiki\MediaWikiServices;
 use Wikimedia\Rdbms\IResultWrapper;
 use Wikimedia\Rdbms\IDatabase;
 
@@ -45,7 +46,10 @@ class ShortPagesPage extends QueryPage {
                $blacklist = $config->get( 'ShortPagesNamespaceBlacklist' );
                $tables = [ 'page' ];
                $conds = [
-                       'page_namespace' => array_diff( MWNamespace::getContentNamespaces(), $blacklist ),
+                       'page_namespace' => array_diff(
+                               MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces(),
+                               $blacklist
+                       ),
                        'page_is_redirect' => 0
                ];
                $joinConds = [];
index d5e14d2..eff8889 100644 (file)
@@ -21,6 +21,8 @@
  * @ingroup SpecialPage
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * Special page lists various statistics, including the contents of
  * `site_stats`, plus page view details if enabled
@@ -207,8 +209,8 @@ class SpecialStatistics extends SpecialPage {
                        }
                        $msg = $this->msg( 'grouppage-' . $groupname )->inContentLanguage();
                        if ( $msg->isBlank() ) {
-                               $grouppageLocalized = MWNamespace::getCanonicalName( NS_PROJECT ) .
-                                       ':' . $groupname;
+                               $grouppageLocalized = MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                       getCanonicalName( NS_PROJECT ) . ':' . $groupname;
                        } else {
                                $grouppageLocalized = $msg->text();
                        }
index 632415c..a04fe4e 100644 (file)
@@ -205,7 +205,7 @@ class SpecialUnblock extends SpecialPage {
 
                # If the name was hidden and the blocking user cannot hide
                # names, then don't allow any block removals...
-               if ( !$performer->isAllowed( 'hideuser' ) && $block->mHideName ) {
+               if ( !$performer->isAllowed( 'hideuser' ) && $block->getHideName() ) {
                        return [ 'unblock-hideuser' ];
                }
 
@@ -222,7 +222,7 @@ class SpecialUnblock extends SpecialPage {
                Hooks::run( 'UnblockUserComplete', [ $block, $performer ] );
 
                # Unset _deleted fields as needed
-               if ( $block->mHideName ) {
+               if ( $block->getHideName() ) {
                        # Something is deeply FUBAR if this is not a User object, but who knows?
                        $id = $block->getTarget() instanceof User
                                ? $block->getTarget()->getId()
index 30b33cc..9efa803 100644 (file)
@@ -21,6 +21,8 @@
  * @ingroup SpecialPage
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * A special page looking for page without any category.
  *
@@ -60,7 +62,8 @@ class UncategorizedPagesPage extends PageQueryPage {
                                'cl_from IS NULL',
                                'page_namespace' => $this->requestedNamespace !== false
                                                ? $this->requestedNamespace
-                                               : MWNamespace::getContentNamespaces(),
+                                               : MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                                       getContentNamespaces(),
                                'page_is_redirect' => 0
                        ],
                        'join_conds' => [
@@ -72,7 +75,10 @@ class UncategorizedPagesPage extends PageQueryPage {
        function getOrderFields() {
                // For some crazy reason ordering by a constant
                // causes a filesort
-               if ( $this->requestedNamespace === false && count( MWNamespace::getContentNamespaces() ) > 1 ) {
+               if ( $this->requestedNamespace === false &&
+                       count( MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               getContentNamespaces() ) > 1
+               ) {
                        return [ 'page_namespace', 'page_title' ];
                }
 
index 529c331..456face 100644 (file)
@@ -95,7 +95,8 @@ class SpecialUndelete extends SpecialPage {
                $this->mUnsuppress = $request->getVal( 'wpUnsuppress' ) && $user->isAllowed( 'suppressrevision' );
                $this->mToken = $request->getVal( 'token' );
 
-               if ( $this->isAllowed( 'undelete' ) && !$user->isBlocked() ) {
+               $block = $user->getBlock();
+               if ( $this->isAllowed( 'undelete' ) && !( $block && $block->isSitewide() ) ) {
                        $this->mAllowed = true; // user can restore
                        $this->mCanView = true; // user can view content
                } elseif ( $this->isAllowed( 'deletedtext' ) ) {
@@ -456,7 +457,7 @@ class SpecialUndelete extends SpecialPage {
                        Message::rawParam( $link ), $time,
                        Message::rawParam( $userLink ), $d, $t
                );
-               $out->addHtml( '</div>' );
+               $out->addHTML( '</div>' );
 
                if ( !Hooks::run( 'UndeleteShowRevision', [ $this->mTargetObj, $rev ] ) ) {
                        return;
@@ -503,7 +504,6 @@ class SpecialUndelete extends SpecialPage {
                        ] );
                } else {
                        $sourceView = '';
-                       $previewButton = '';
                }
 
                $buttonFields[] = new OOUI\ButtonInputWidget( [
@@ -549,7 +549,6 @@ class SpecialUndelete extends SpecialPage {
         *
         * @param Revision $previousRev
         * @param Revision $currentRev
-        * @return string HTML
         */
        function showDiff( $previousRev, $currentRev ) {
                $diffContext = clone $this->getContext();
@@ -688,7 +687,7 @@ class SpecialUndelete extends SpecialPage {
 
                $repo = RepoGroup::singleton()->getLocalRepo();
                $path = $repo->getZonePath( 'deleted' ) . '/' . $repo->getDeletedHashPath( $key ) . $key;
-               $repo->streamFile( $path );
+               $repo->streamFileWithStatus( $path );
        }
 
        protected function showHistory() {
index dbb1481..dcc35fc 100644 (file)
@@ -146,8 +146,7 @@ class SpecialUpload extends SpecialPage {
        }
 
        /**
-        * Special page entry point
-        * @param string $par
+        * @param string|null $par
         * @throws ErrorPageError
         * @throws Exception
         * @throws FatalError
@@ -192,11 +191,9 @@ class SpecialUpload extends SpecialPage {
                $this->loadRequest();
 
                # Unsave the temporary file in case this was a cancelled upload
-               if ( $this->mCancelUpload ) {
-                       if ( !$this->unsaveUploadedFile() ) {
-                               # Something went wrong, so unsaveUploadedFile showed a warning
-                               return;
-                       }
+               if ( $this->mCancelUpload && !$this->unsaveUploadedFile() ) {
+                       # Something went wrong, so unsaveUploadedFile showed a warning
+                       return;
                }
 
                # Process upload or show a form
index 4d0c20c..c278bab 100644 (file)
@@ -60,7 +60,7 @@ class SpecialUploadStash extends UnlistedSpecialPage {
        /**
         * Execute page -- can output a file directly or show a listing of them.
         *
-        * @param string $subPage Subpage, e.g. in
+        * @param string|null $subPage Subpage, e.g. in
         *   https://example.com/wiki/Special:UploadStash/foo.jpg, the "foo.jpg" part
         * @return bool Success
         */
@@ -261,6 +261,15 @@ class SpecialUploadStash extends UnlistedSpecialPage {
                $scalerThumbUrl = $scalerBaseUrl . '/' . $file->getUrlRel() .
                        '/' . rawurlencode( $scalerThumbName );
 
+               // If a thumb proxy is set up for the repo, we favor that, as that will
+               // keep the request internal
+               $thumbProxyUrl = $file->getRepo()->getThumbProxyUrl();
+
+               if ( strlen( $thumbProxyUrl ) ) {
+                       $scalerThumbUrl = $thumbProxyUrl . 'temp/' . $file->getUrlRel() .
+                       '/' . rawurlencode( $scalerThumbName );
+               }
+
                // make an http request based on wgUploadStashScalerBaseUrl to lazy-create
                // a thumbnail
                $httpOptions = [
@@ -268,6 +277,14 @@ class SpecialUploadStash extends UnlistedSpecialPage {
                        'timeout' => 5 // T90599 attempt to time out cleanly
                ];
                $req = MWHttpRequest::factory( $scalerThumbUrl, $httpOptions, __METHOD__ );
+
+               $secret = $file->getRepo()->getThumbProxySecret();
+
+               // Pass a secret key shared with the proxied service if any
+               if ( strlen( $secret ) ) {
+                       $req->setHeader( 'X-Swift-Secret', $secret );
+               }
+
                $status = $req->execute();
                if ( !$status->isOK() ) {
                        $errors = $status->getErrorsArray();
@@ -305,10 +322,10 @@ class SpecialUploadStash extends UnlistedSpecialPage {
                        );
                }
 
-               return $file->getRepo()->streamFile( $file->getPath(),
+               return $file->getRepo()->streamFileWithStatus( $file->getPath(),
                        [ 'Content-Transfer-Encoding: binary',
                                'Expires: Sun, 17-Jan-2038 19:14:07 GMT' ]
-               );
+               )->isOK();
        }
 
        /**
index a9b732e..568327d 100644 (file)
@@ -48,6 +48,28 @@ class SpecialUserLogout extends UnlistedSpecialPage {
                $this->setHeaders();
                $this->outputHeader();
 
+               $out = $this->getOutput();
+               $user = $this->getUser();
+               $request = $this->getRequest();
+
+               $logoutToken = $request->getVal( 'logoutToken' );
+               $urlParams = [
+                       'logoutToken' => $user->getEditToken( 'logoutToken', $request )
+               ] + $request->getValues();
+               unset( $urlParams['title'] );
+               $continueLink = $this->getFullTitle()->getFullUrl( $urlParams );
+
+               if ( $logoutToken === null ) {
+                       $this->getOutput()->addWikiMsg( 'userlogout-continue', $continueLink );
+                       return;
+               }
+               if ( !$this->getUser()->matchEditToken(
+                       $logoutToken, 'logoutToken', $this->getRequest(), 24 * 60 * 60
+               ) ) {
+                       $this->getOutput()->addWikiMsg( 'userlogout-sessionerror', $continueLink );
+                       return;
+               }
+
                // Make sure it's possible to log out
                $session = MediaWiki\Session\SessionManager::getGlobalSession();
                if ( !$session->canSetUser() ) {
index 540754f..8655b1c 100644 (file)
@@ -61,15 +61,23 @@ class UserrightsPage extends SpecialPage {
                $isself = $this->getUser()->equals( $targetUser );
 
                $available = $this->changeableGroups();
-               if ( $targetUser->getId() == 0 ) {
+               if ( $targetUser->getId() === 0 ) {
                        return false;
                }
 
-               return !empty( $available['add'] )
-                       || !empty( $available['remove'] )
-                       || ( ( $isself || !$checkIfSelf ) &&
-                               ( !empty( $available['add-self'] )
-                                       || !empty( $available['remove-self'] ) ) );
+               if ( $available['add'] || $available['remove'] ) {
+                       // can change some rights for any user
+                       return true;
+               }
+
+               if ( ( $available['add-self'] || $available['remove-self'] )
+                       && ( $isself || !$checkIfSelf )
+               ) {
+                       // can change some rights for self
+                       return true;
+               }
+
+               return false;
        }
 
        /**
@@ -152,8 +160,13 @@ class UserrightsPage extends SpecialPage {
                        * (e.g. they don't have the userrights permission), then don't
                        * allow them to change any user rights.
                        */
-                       if ( $user->isBlocked() && !$user->isAllowed( 'userrights' ) ) {
-                               throw new UserBlockedError( $user->getBlock() );
+                       if ( !$user->isAllowed( 'userrights' ) ) {
+                               // @TODO Should the user be blocked from changing user rights if they
+                               //       are partially blocked?
+                               $block = $user->getBlock();
+                               if ( $block ) {
+                                       throw new UserBlockedError( $user->getBlock() );
+                               }
                        }
 
                        $this->checkReadOnly();
index 2ad0def..0c4959a 100644 (file)
@@ -23,6 +23,8 @@
  * @ingroup SpecialPage
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * Give information about the version of MediaWiki, PHP, the DB and extensions
  *
@@ -47,7 +49,9 @@ class SpecialVersion extends SpecialPage {
         * @param string|null $par
         */
        public function execute( $par ) {
-               global $IP, $wgExtensionCredits;
+               global $IP;
+               $config = $this->getConfig();
+               $extensionCredits = $config->get( 'ExtensionCredits' );
 
                $this->setHeaders();
                $this->outputHeader();
@@ -60,7 +64,7 @@ class SpecialVersion extends SpecialPage {
                if ( isset( $parts[1] ) ) {
                        $extName = str_replace( '_', ' ', $parts[1] );
                        // Find it!
-                       foreach ( $wgExtensionCredits as $group => $extensions ) {
+                       foreach ( $extensionCredits as $group => $extensions ) {
                                foreach ( $extensions as $ext ) {
                                        if ( isset( $ext['name'] ) && ( $ext['name'] === $extName ) ) {
                                                $extNode = &$ext;
@@ -206,6 +210,7 @@ class SpecialVersion extends SpecialPage {
                        'Victor Vasiliev', 'Rotem Liss', 'Platonides', 'Antoine Musso',
                        'Timo Tijhof', 'Daniel Kinzler', 'Jeroen De Dauw', 'Brad Jorsch',
                        'Bartosz Dziewoński', 'Ed Sanders', 'Moriel Schottlender',
+                       'Kunal Mehta', 'James D. Forrester', 'Brian Wolff', 'Adam Shorland',
                        $othersLink, $translatorsLink
                ];
 
@@ -405,12 +410,13 @@ class SpecialVersion extends SpecialPage {
         * @return string Wikitext
         */
        public function getExtensionCredits() {
-               global $wgExtensionCredits;
+               $config = $this->getConfig();
+               $extensionCredits = $config->get( 'ExtensionCredits' );
 
                if (
-                       count( $wgExtensionCredits ) === 0 ||
+                       count( $extensionCredits ) === 0 ||
                        // Skins are displayed separately, see getSkinCredits()
-                       ( count( $wgExtensionCredits ) === 1 && isset( $wgExtensionCredits['skin'] ) )
+                       ( count( $extensionCredits ) === 1 && isset( $extensionCredits['skin'] ) )
                ) {
                        return '';
                }
@@ -425,14 +431,14 @@ class SpecialVersion extends SpecialPage {
                        Xml::openElement( 'table', [ 'class' => 'wikitable plainlinks', 'id' => 'sv-ext' ] );
 
                // Make sure the 'other' type is set to an array.
-               if ( !array_key_exists( 'other', $wgExtensionCredits ) ) {
-                       $wgExtensionCredits['other'] = [];
+               if ( !array_key_exists( 'other', $extensionCredits ) ) {
+                       $extensionCredits['other'] = [];
                }
 
                // Find all extensions that do not have a valid type and give them the type 'other'.
-               foreach ( $wgExtensionCredits as $type => $extensions ) {
+               foreach ( $extensionCredits as $type => $extensions ) {
                        if ( !array_key_exists( $type, $extensionTypes ) ) {
-                               $wgExtensionCredits['other'] = array_merge( $wgExtensionCredits['other'], $extensions );
+                               $extensionCredits['other'] = array_merge( $extensionCredits['other'], $extensions );
                        }
                }
 
@@ -554,9 +560,7 @@ class SpecialVersion extends SpecialPage {
         * @return string HTML output
         */
        protected function getParserTags() {
-               global $wgParser;
-
-               $tags = $wgParser->getTags();
+               $tags = MediaWikiServices::getInstance()->getParser()->getTags();
 
                if ( count( $tags ) ) {
                        $out = Html::rawElement(
@@ -598,9 +602,7 @@ class SpecialVersion extends SpecialPage {
         * @return string HTML output
         */
        protected function getParserFunctionHooks() {
-               global $wgParser;
-
-               $fhooks = $wgParser->getFunctionHooks();
+               $fhooks = MediaWikiServices::getInstance()->getParser()->getFunctionHooks();
                if ( count( $fhooks ) ) {
                        $out = Html::rawElement(
                                'h2',
@@ -634,16 +636,17 @@ class SpecialVersion extends SpecialPage {
         * @return string
         */
        protected function getExtensionCategory( $type, $message ) {
-               global $wgExtensionCredits;
+               $config = $this->getConfig();
+               $extensionCredits = $config->get( 'ExtensionCredits' );
 
                $out = '';
 
-               if ( array_key_exists( $type, $wgExtensionCredits ) && count( $wgExtensionCredits[$type] ) > 0 ) {
+               if ( array_key_exists( $type, $extensionCredits ) && count( $extensionCredits[$type] ) > 0 ) {
                        $out .= $this->openExtType( $message, 'credits-' . $type );
 
-                       usort( $wgExtensionCredits[$type], [ $this, 'compare' ] );
+                       usort( $extensionCredits[$type], [ $this, 'compare' ] );
 
-                       foreach ( $wgExtensionCredits[$type] as $extension ) {
+                       foreach ( $extensionCredits[$type] as $extension ) {
                                $out .= $this->getCreditsForExtension( $type, $extension );
                        }
                }
@@ -703,7 +706,7 @@ class SpecialVersion extends SpecialPage {
                                [ 'class' => 'mw-version-ext-name' ]
                        );
                } else {
-                       $extensionNameLink = $extensionName;
+                       $extensionNameLink = htmlspecialchars( $extensionName );
                }
 
                // ... and the version information
@@ -883,9 +886,9 @@ class SpecialVersion extends SpecialPage {
                        $ret[] = Html::closeElement( 'table' );
 
                        return implode( "\n", $ret );
-               } else {
-                       return '';
                }
+
+               return '';
        }
 
        private function openExtType( $text = null, $name = null ) {
@@ -1133,10 +1136,11 @@ class SpecialVersion extends SpecialPage {
         * @return string Wikitext
         */
        public function getEntryPointInfo() {
-               global $wgArticlePath, $wgScriptPath;
-               $scriptPath = $wgScriptPath ?: "/";
+               $config = $this->getConfig();
+               $scriptPath = $config->get( 'ScriptPath' ) ?: '/';
+
                $entryPoints = [
-                       'version-entrypoints-articlepath' => $wgArticlePath,
+                       'version-entrypoints-articlepath' => $config->get( 'ArticlePath' ),
                        'version-entrypoints-scriptpath' => $scriptPath,
                        'version-entrypoints-index-php' => wfScript( 'index' ),
                        'version-entrypoints-api-php' => wfScript( 'api' ),
index 6defc9d..2443470 100644 (file)
@@ -110,7 +110,14 @@ class SpecialWatchlist extends ChangesListSpecialPage {
                }
        }
 
-       public static function checkStructuredFilterUiEnabled( Config $config, User $user ) {
+       /**
+        * @see ChangesListSpecialPage::checkStructuredFilterUiEnabled
+        */
+       public static function checkStructuredFilterUiEnabled( $user ) {
+               if ( $user instanceof Config ) {
+                       wfDeprecated( __METHOD__ . ' with Config argument', '1.34' );
+                       $user = func_get_arg( 1 );
+               }
                return !$user->getOption( 'wlenhancedfilters-disable' );
        }
 
@@ -192,13 +199,7 @@ class SpecialWatchlist extends ChangesListSpecialPage {
                                        'description' => 'rcfilters-filter-watchlistactivity-unseen-description',
                                        'cssClassSuffix' => 'watchedunseen',
                                        'isRowApplicableCallable' => function ( $ctx, RecentChange $rc ) {
-                                               $changeTs = $rc->getAttribute( 'rc_timestamp' );
-                                               $lastVisitTs = $this->watchStore->getLatestNotificationTimestamp(
-                                                       $rc->getAttribute( 'wl_notificationtimestamp' ),
-                                                       $rc->getPerformer(),
-                                                       $rc->getTitle()
-                                               );
-                                               return $lastVisitTs !== null && $changeTs >= $lastVisitTs;
+                                               return !$this->isChangeEffectivelySeen( $rc );
                                        },
                                ],
                                [
@@ -206,16 +207,23 @@ class SpecialWatchlist extends ChangesListSpecialPage {
                                        'label' => 'rcfilters-filter-watchlistactivity-seen-label',
                                        'description' => 'rcfilters-filter-watchlistactivity-seen-description',
                                        'cssClassSuffix' => 'watchedseen',
-                                       'isRowApplicableCallable' => function ( $ctx, $rc ) {
-                                               $changeTs = $rc->getAttribute( 'rc_timestamp' );
-                                               $lastVisitTs = $rc->getAttribute( 'wl_notificationtimestamp' );
-                                               return $lastVisitTs === null || $changeTs < $lastVisitTs;
+                                       'isRowApplicableCallable' => function ( $ctx, RecentChange $rc ) {
+                                               return $this->isChangeEffectivelySeen( $rc );
                                        }
                                ],
                        ],
                        'default' => ChangesListStringOptionsFilterGroup::NONE,
-                       'queryCallable' => function ( $specialPageClassName, $context, $dbr,
-                                       &$tables, &$fields, &$conds, &$query_options, &$join_conds, $selectedValues ) {
+                       'queryCallable' => function (
+                               $specialPageClassName,
+                               $context,
+                               IDatabase $dbr,
+                               &$tables,
+                               &$fields,
+                               &$conds,
+                               &$query_options,
+                               &$join_conds,
+                               $selectedValues
+                       ) {
                                if ( $selectedValues === [ 'seen' ] ) {
                                        $conds[] = $dbr->makeList( [
                                                'wl_notificationtimestamp IS NULL',
@@ -534,9 +542,9 @@ class SpecialWatchlist extends ChangesListSpecialPage {
                        $rc->counter = $counter++;
 
                        if ( $this->getConfig()->get( 'ShowUpdatedMarker' ) ) {
-                               $updated = $obj->wl_notificationtimestamp;
+                               $unseen = !$this->isChangeEffectivelySeen( $rc );
                        } else {
-                               $updated = false;
+                               $unseen = false;
                        }
 
                        if ( isset( $watchedItemStore ) ) {
@@ -546,7 +554,10 @@ class SpecialWatchlist extends ChangesListSpecialPage {
                                $rc->numberofWatchingusers = 0;
                        }
 
-                       $changeLine = $list->recentChangesLine( $rc, $updated, $counter );
+                       // XXX: this treats pages with no unseen changes as "not on the watchlist" since
+                       // everything is on the watchlist and it is an easy way to make pages with unseen
+                       // changes appear bold. @TODO: clean this up.
+                       $changeLine = $list->recentChangesLine( $rc, $unseen, $counter );
                        if ( $changeLine !== false ) {
                                $s .= $changeLine;
                        }
@@ -598,11 +609,12 @@ class SpecialWatchlist extends ChangesListSpecialPage {
 
                $lang = $this->getLanguage();
                $timestamp = wfTimestampNow();
+               $now = $lang->userTimeAndDate( $timestamp, $user );
                $wlInfo = Html::rawElement(
                        'span',
                        [
                                'class' => 'wlinfo',
-                               'data-params' => json_encode( [ 'from' => $timestamp ] ),
+                               'data-params' => json_encode( [ 'from' => $timestamp, 'fromFormatted' => $now ] ),
                        ],
                        $this->msg( 'wlnote' )->numParams( $numRows, round( $opts['days'] * 24 ) )->params(
                                $lang->userDate( $timestamp, $user ), $lang->userTime( $timestamp, $user )
@@ -699,15 +711,16 @@ class SpecialWatchlist extends ChangesListSpecialPage {
                if ( $this->isStructuredFilterUiEnabled() ) {
                        $rcfilterContainer = Html::element(
                                'div',
-                               [ 'class' => 'rcfilters-container' ]
+                               // TODO: Remove deprecated rcfilters-container class
+                               [ 'class' => 'rcfilters-container mw-rcfilters-container' ]
                        );
 
                        $loadingContainer = Html::rawElement(
                                'div',
-                               [ 'class' => 'rcfilters-spinner' ],
+                               [ 'class' => 'mw-rcfilters-spinner' ],
                                Html::element(
                                        'div',
-                                       [ 'class' => 'rcfilters-spinner-bounce' ]
+                                       [ 'class' => 'mw-rcfilters-spinner-bounce' ]
                                )
                        );
 
@@ -715,7 +728,8 @@ class SpecialWatchlist extends ChangesListSpecialPage {
                        $this->getOutput()->addHTML(
                                Html::rawElement(
                                        'div',
-                                       [ 'class' => 'rcfilters-head' ],
+                                       // TODO: Remove deprecated rcfilters-head class
+                                       [ 'class' => 'rcfilters-head mw-rcfilters-head' ],
                                        $rcfilterContainer . $form
                                )
                        );
@@ -848,4 +862,26 @@ class SpecialWatchlist extends ChangesListSpecialPage {
                $count = $store->countWatchedItems( $this->getUser() );
                return floor( $count / 2 );
        }
+
+       /**
+        * @param RecentChange $rc
+        * @return bool User viewed the revision or a newer one
+        */
+       protected function isChangeEffectivelySeen( RecentChange $rc ) {
+               $firstUnseen = $this->getLatestNotificationTimestamp( $rc );
+
+               return ( $firstUnseen === null || $firstUnseen > $rc->getAttribute( 'rc_timestamp' ) );
+       }
+
+       /**
+        * @param RecentChange $rc
+        * @return string|null TS_MW timestamp of first unseen revision or null if there isn't one
+        */
+       private function getLatestNotificationTimestamp( RecentChange $rc ) {
+               return $this->watchStore->getLatestNotificationTimestamp(
+                       $rc->getAttribute( 'wl_notificationtimestamp' ),
+                       $this->getUser(),
+                       $rc->getTitle()
+               );
+       }
 }
diff --git a/includes/specials/SpecialWhatLinksHere.php b/includes/specials/SpecialWhatLinksHere.php
new file mode 100644 (file)
index 0000000..18c10bf
--- /dev/null
@@ -0,0 +1,591 @@
+<?php
+/**
+ * Implements Special:Whatlinkshere
+ *
+ * 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
+ * @todo Use some variant of Pager or something; the pagination here is lousy.
+ */
+
+use Wikimedia\Rdbms\IDatabase;
+
+/**
+ * Implements Special:Whatlinkshere
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialWhatLinksHere extends IncludableSpecialPage {
+       /** @var FormOptions */
+       protected $opts;
+
+       protected $selfTitle;
+
+       /** @var Title */
+       protected $target;
+
+       protected $limits = [ 20, 50, 100, 250, 500 ];
+
+       public function __construct() {
+               parent::__construct( 'Whatlinkshere' );
+       }
+
+       function execute( $par ) {
+               $out = $this->getOutput();
+
+               $this->setHeaders();
+               $this->outputHeader();
+               $this->addHelpLink( 'Help:What links here' );
+
+               $opts = new FormOptions();
+
+               $opts->add( 'target', '' );
+               $opts->add( 'namespace', '', FormOptions::INTNULL );
+               $opts->add( 'limit', $this->getConfig()->get( 'QueryPageDefaultLimit' ) );
+               $opts->add( 'from', 0 );
+               $opts->add( 'back', 0 );
+               $opts->add( 'hideredirs', false );
+               $opts->add( 'hidetrans', false );
+               $opts->add( 'hidelinks', false );
+               $opts->add( 'hideimages', false );
+               $opts->add( 'invert', false );
+
+               $opts->fetchValuesFromRequest( $this->getRequest() );
+               $opts->validateIntBounds( 'limit', 0, 5000 );
+
+               // Give precedence to subpage syntax
+               if ( $par !== null ) {
+                       $opts->setValue( 'target', $par );
+               }
+
+               // Bind to member variable
+               $this->opts = $opts;
+
+               $this->target = Title::newFromText( $opts->getValue( 'target' ) );
+               if ( !$this->target ) {
+                       if ( !$this->including() ) {
+                               $out->addHTML( $this->whatlinkshereForm() );
+                       }
+
+                       return;
+               }
+
+               $this->getSkin()->setRelevantTitle( $this->target );
+
+               $this->selfTitle = $this->getPageTitle( $this->target->getPrefixedDBkey() );
+
+               $out->setPageTitle( $this->msg( 'whatlinkshere-title', $this->target->getPrefixedText() ) );
+               $out->addBacklinkSubtitle( $this->target );
+               $this->showIndirectLinks(
+                       0,
+                       $this->target,
+                       $opts->getValue( 'limit' ),
+                       $opts->getValue( 'from' ),
+                       $opts->getValue( 'back' )
+               );
+       }
+
+       /**
+        * @param int $level Recursion level
+        * @param Title $target Target title
+        * @param int $limit Number of entries to display
+        * @param int $from Display from this article ID (default: 0)
+        * @param int $back Display from this article ID at backwards scrolling (default: 0)
+        */
+       function showIndirectLinks( $level, $target, $limit, $from = 0, $back = 0 ) {
+               $out = $this->getOutput();
+               $dbr = wfGetDB( DB_REPLICA );
+
+               $hidelinks = $this->opts->getValue( 'hidelinks' );
+               $hideredirs = $this->opts->getValue( 'hideredirs' );
+               $hidetrans = $this->opts->getValue( 'hidetrans' );
+               $hideimages = $target->getNamespace() != NS_FILE || $this->opts->getValue( 'hideimages' );
+
+               $fetchlinks = ( !$hidelinks || !$hideredirs );
+
+               // Build query conds in concert for all three tables...
+               $conds['pagelinks'] = [
+                       'pl_namespace' => $target->getNamespace(),
+                       'pl_title' => $target->getDBkey(),
+               ];
+               $conds['templatelinks'] = [
+                       'tl_namespace' => $target->getNamespace(),
+                       'tl_title' => $target->getDBkey(),
+               ];
+               $conds['imagelinks'] = [
+                       'il_to' => $target->getDBkey(),
+               ];
+
+               $namespace = $this->opts->getValue( 'namespace' );
+               $invert = $this->opts->getValue( 'invert' );
+               $nsComparison = ( $invert ? '!= ' : '= ' ) . $dbr->addQuotes( $namespace );
+               if ( is_int( $namespace ) ) {
+                       $conds['pagelinks'][] = "pl_from_namespace $nsComparison";
+                       $conds['templatelinks'][] = "tl_from_namespace $nsComparison";
+                       $conds['imagelinks'][] = "il_from_namespace $nsComparison";
+               }
+
+               if ( $from ) {
+                       $conds['templatelinks'][] = "tl_from >= $from";
+                       $conds['pagelinks'][] = "pl_from >= $from";
+                       $conds['imagelinks'][] = "il_from >= $from";
+               }
+
+               if ( $hideredirs ) {
+                       $conds['pagelinks']['rd_from'] = null;
+               } elseif ( $hidelinks ) {
+                       $conds['pagelinks'][] = 'rd_from is NOT NULL';
+               }
+
+               $queryFunc = function ( IDatabase $dbr, $table, $fromCol ) use (
+                       $conds, $target, $limit
+               ) {
+                       // Read an extra row as an at-end check
+                       $queryLimit = $limit + 1;
+                       $on = [
+                               "rd_from = $fromCol",
+                               'rd_title' => $target->getDBkey(),
+                               'rd_interwiki = ' . $dbr->addQuotes( '' ) . ' OR rd_interwiki IS NULL'
+                       ];
+                       $on['rd_namespace'] = $target->getNamespace();
+                       // Inner LIMIT is 2X in case of stale backlinks with wrong namespaces
+                       $subQuery = $dbr->buildSelectSubquery(
+                               [ $table, 'redirect', 'page' ],
+                               [ $fromCol, 'rd_from' ],
+                               $conds[$table],
+                               __CLASS__ . '::showIndirectLinks',
+                               // Force JOIN order per T106682 to avoid large filesorts
+                               [ 'ORDER BY' => $fromCol, 'LIMIT' => 2 * $queryLimit, 'STRAIGHT_JOIN' ],
+                               [
+                                       'page' => [ 'JOIN', "$fromCol = page_id" ],
+                                       'redirect' => [ 'LEFT JOIN', $on ]
+                               ]
+                       );
+                       return $dbr->select(
+                               [ 'page', 'temp_backlink_range' => $subQuery ],
+                               [ 'page_id', 'page_namespace', 'page_title', 'rd_from', 'page_is_redirect' ],
+                               [],
+                               __CLASS__ . '::showIndirectLinks',
+                               [ 'ORDER BY' => 'page_id', 'LIMIT' => $queryLimit ],
+                               [ 'page' => [ 'JOIN', "$fromCol = page_id" ] ]
+                       );
+               };
+
+               if ( $fetchlinks ) {
+                       $plRes = $queryFunc( $dbr, 'pagelinks', 'pl_from' );
+               }
+
+               if ( !$hidetrans ) {
+                       $tlRes = $queryFunc( $dbr, 'templatelinks', 'tl_from' );
+               }
+
+               if ( !$hideimages ) {
+                       $ilRes = $queryFunc( $dbr, 'imagelinks', 'il_from' );
+               }
+
+               if ( ( !$fetchlinks || !$plRes->numRows() )
+                       && ( $hidetrans || !$tlRes->numRows() )
+                       && ( $hideimages || !$ilRes->numRows() )
+               ) {
+                       if ( $level == 0 && !$this->including() ) {
+                               $out->addHTML( $this->whatlinkshereForm() );
+
+                               // Show filters only if there are links
+                               if ( $hidelinks || $hidetrans || $hideredirs || $hideimages ) {
+                                       $out->addHTML( $this->getFilterPanel() );
+                               }
+                               $msgKey = is_int( $namespace ) ? 'nolinkshere-ns' : 'nolinkshere';
+                               $link = $this->getLinkRenderer()->makeLink(
+                                       $this->target,
+                                       null,
+                                       [],
+                                       $this->target->isRedirect() ? [ 'redirect' => 'no' ] : []
+                               );
+
+                               $errMsg = $this->msg( $msgKey )
+                                       ->params( $this->target->getPrefixedText() )
+                                       ->rawParams( $link )
+                                       ->parseAsBlock();
+                               $out->addHTML( $errMsg );
+                               $out->setStatusCode( 404 );
+                       }
+
+                       return;
+               }
+
+               // Read the rows into an array and remove duplicates
+               // templatelinks comes second so that the templatelinks row overwrites the
+               // pagelinks row, so we get (inclusion) rather than nothing
+               if ( $fetchlinks ) {
+                       foreach ( $plRes as $row ) {
+                               $row->is_template = 0;
+                               $row->is_image = 0;
+                               $rows[$row->page_id] = $row;
+                       }
+               }
+               if ( !$hidetrans ) {
+                       foreach ( $tlRes as $row ) {
+                               $row->is_template = 1;
+                               $row->is_image = 0;
+                               $rows[$row->page_id] = $row;
+                       }
+               }
+               if ( !$hideimages ) {
+                       foreach ( $ilRes as $row ) {
+                               $row->is_template = 0;
+                               $row->is_image = 1;
+                               $rows[$row->page_id] = $row;
+                       }
+               }
+
+               // Sort by key and then change the keys to 0-based indices
+               ksort( $rows );
+               $rows = array_values( $rows );
+
+               $numRows = count( $rows );
+
+               // Work out the start and end IDs, for prev/next links
+               if ( $numRows > $limit ) {
+                       // More rows available after these ones
+                       // Get the ID from the last row in the result set
+                       $nextId = $rows[$limit]->page_id;
+                       // Remove undisplayed rows
+                       $rows = array_slice( $rows, 0, $limit );
+               } else {
+                       // No more rows after
+                       $nextId = false;
+               }
+               $prevId = $from;
+
+               // use LinkBatch to make sure, that all required data (associated with Titles)
+               // is loaded in one query
+               $lb = new LinkBatch();
+               foreach ( $rows as $row ) {
+                       $lb->add( $row->page_namespace, $row->page_title );
+               }
+               $lb->execute();
+
+               if ( $level == 0 && !$this->including() ) {
+                       $out->addHTML( $this->whatlinkshereForm() );
+                       $out->addHTML( $this->getFilterPanel() );
+
+                       $link = $this->getLinkRenderer()->makeLink(
+                               $this->target,
+                               null,
+                               [],
+                               $this->target->isRedirect() ? [ 'redirect' => 'no' ] : []
+                       );
+
+                       $msg = $this->msg( 'linkshere' )
+                               ->params( $this->target->getPrefixedText() )
+                               ->rawParams( $link )
+                               ->parseAsBlock();
+                       $out->addHTML( $msg );
+
+                       $prevnext = $this->getPrevNext( $prevId, $nextId );
+                       $out->addHTML( $prevnext );
+               }
+               $out->addHTML( $this->listStart( $level ) );
+               foreach ( $rows as $row ) {
+                       $nt = Title::makeTitle( $row->page_namespace, $row->page_title );
+
+                       if ( $row->rd_from && $level < 2 ) {
+                               $out->addHTML( $this->listItem( $row, $nt, $target, true ) );
+                               $this->showIndirectLinks(
+                                       $level + 1,
+                                       $nt,
+                                       $this->getConfig()->get( 'MaxRedirectLinksRetrieved' )
+                               );
+                               $out->addHTML( Xml::closeElement( 'li' ) );
+                       } else {
+                               $out->addHTML( $this->listItem( $row, $nt, $target ) );
+                       }
+               }
+
+               $out->addHTML( $this->listEnd() );
+
+               if ( $level == 0 && !$this->including() ) {
+                       $out->addHTML( $prevnext );
+               }
+       }
+
+       protected function listStart( $level ) {
+               return Xml::openElement( 'ul', ( $level ? [] : [ 'id' => 'mw-whatlinkshere-list' ] ) );
+       }
+
+       protected function listItem( $row, $nt, $target, $notClose = false ) {
+               $dirmark = $this->getLanguage()->getDirMark();
+
+               # local message cache
+               static $msgcache = null;
+               if ( $msgcache === null ) {
+                       static $msgs = [ 'isredirect', 'istemplate', 'semicolon-separator',
+                               'whatlinkshere-links', 'isimage', 'editlink' ];
+                       $msgcache = [];
+                       foreach ( $msgs as $msg ) {
+                               $msgcache[$msg] = $this->msg( $msg )->escaped();
+                       }
+               }
+
+               if ( $row->rd_from ) {
+                       $query = [ 'redirect' => 'no' ];
+               } else {
+                       $query = [];
+               }
+
+               $link = $this->getLinkRenderer()->makeKnownLink(
+                       $nt,
+                       null,
+                       $row->page_is_redirect ? [ 'class' => 'mw-redirect' ] : [],
+                       $query
+               );
+
+               // Display properties (redirect or template)
+               $propsText = '';
+               $props = [];
+               if ( $row->rd_from ) {
+                       $props[] = $msgcache['isredirect'];
+               }
+               if ( $row->is_template ) {
+                       $props[] = $msgcache['istemplate'];
+               }
+               if ( $row->is_image ) {
+                       $props[] = $msgcache['isimage'];
+               }
+
+               Hooks::run( 'WhatLinksHereProps', [ $row, $nt, $target, &$props ] );
+
+               if ( count( $props ) ) {
+                       $propsText = $this->msg( 'parentheses' )
+                               ->rawParams( implode( $msgcache['semicolon-separator'], $props ) )->escaped();
+               }
+
+               # Space for utilities links, with a what-links-here link provided
+               $wlhLink = $this->wlhLink( $nt, $msgcache['whatlinkshere-links'], $msgcache['editlink'] );
+               $wlh = Xml::wrapClass(
+                       $this->msg( 'parentheses' )->rawParams( $wlhLink )->escaped(),
+                       'mw-whatlinkshere-tools'
+               );
+
+               return $notClose ?
+                       Xml::openElement( 'li' ) . "$link $propsText $dirmark $wlh\n" :
+                       Xml::tags( 'li', null, "$link $propsText $dirmark $wlh" ) . "\n";
+       }
+
+       protected function listEnd() {
+               return Xml::closeElement( 'ul' );
+       }
+
+       protected function wlhLink( Title $target, $text, $editText ) {
+               static $title = null;
+               if ( $title === null ) {
+                       $title = $this->getPageTitle();
+               }
+
+               $linkRenderer = $this->getLinkRenderer();
+
+               if ( $text !== null ) {
+                       $text = new HtmlArmor( $text );
+               }
+
+               // always show a "<- Links" link
+               $links = [
+                       'links' => $linkRenderer->makeKnownLink(
+                               $title,
+                               $text,
+                               [],
+                               [ 'target' => $target->getPrefixedText() ]
+                       ),
+               ];
+
+               // if the page is editable, add an edit link
+               if (
+                       // check user permissions
+                       $this->getUser()->isAllowed( 'edit' ) &&
+                       // check, if the content model is editable through action=edit
+                       ContentHandler::getForTitle( $target )->supportsDirectEditing()
+               ) {
+                       if ( $editText !== null ) {
+                               $editText = new HtmlArmor( $editText );
+                       }
+
+                       $links['edit'] = $linkRenderer->makeKnownLink(
+                               $target,
+                               $editText,
+                               [],
+                               [ 'action' => 'edit' ]
+                       );
+               }
+
+               // build the links html
+               return $this->getLanguage()->pipeList( $links );
+       }
+
+       function makeSelfLink( $text, $query ) {
+               if ( $text !== null ) {
+                       $text = new HtmlArmor( $text );
+               }
+
+               return $this->getLinkRenderer()->makeKnownLink(
+                       $this->selfTitle,
+                       $text,
+                       [],
+                       $query
+               );
+       }
+
+       function getPrevNext( $prevId, $nextId ) {
+               $currentLimit = $this->opts->getValue( 'limit' );
+               $prev = $this->msg( 'whatlinkshere-prev' )->numParams( $currentLimit )->escaped();
+               $next = $this->msg( 'whatlinkshere-next' )->numParams( $currentLimit )->escaped();
+
+               $changed = $this->opts->getChangedValues();
+               unset( $changed['target'] ); // Already in the request title
+
+               if ( $prevId != 0 ) {
+                       $overrides = [ 'from' => $this->opts->getValue( 'back' ) ];
+                       $prev = $this->makeSelfLink( $prev, array_merge( $changed, $overrides ) );
+               }
+               if ( $nextId != 0 ) {
+                       $overrides = [ 'from' => $nextId, 'back' => $prevId ];
+                       $next = $this->makeSelfLink( $next, array_merge( $changed, $overrides ) );
+               }
+
+               $limitLinks = [];
+               $lang = $this->getLanguage();
+               foreach ( $this->limits as $limit ) {
+                       $prettyLimit = htmlspecialchars( $lang->formatNum( $limit ) );
+                       $overrides = [ 'limit' => $limit ];
+                       $limitLinks[] = $this->makeSelfLink( $prettyLimit, array_merge( $changed, $overrides ) );
+               }
+
+               $nums = $lang->pipeList( $limitLinks );
+
+               return $this->msg( 'viewprevnext' )->rawParams( $prev, $next, $nums )->escaped();
+       }
+
+       function whatlinkshereForm() {
+               // We get nicer value from the title object
+               $this->opts->consumeValue( 'target' );
+               // Reset these for new requests
+               $this->opts->consumeValues( [ 'back', 'from' ] );
+
+               $target = $this->target ? $this->target->getPrefixedText() : '';
+               $namespace = $this->opts->consumeValue( 'namespace' );
+               $nsinvert = $this->opts->consumeValue( 'invert' );
+
+               # Build up the form
+               $f = Xml::openElement( 'form', [ 'action' => wfScript() ] );
+
+               # Values that should not be forgotten
+               $f .= Html::hidden( 'title', $this->getPageTitle()->getPrefixedText() );
+               foreach ( $this->opts->getUnconsumedValues() as $name => $value ) {
+                       $f .= Html::hidden( $name, $value );
+               }
+
+               $f .= Xml::fieldset( $this->msg( 'whatlinkshere' )->text() );
+
+               # Target input (.mw-searchInput enables suggestions)
+               $f .= Xml::inputLabel( $this->msg( 'whatlinkshere-page' )->text(), 'target',
+                       'mw-whatlinkshere-target', 40, $target, [ 'class' => 'mw-searchInput' ] );
+
+               $f .= ' ';
+
+               # Namespace selector
+               $f .= Html::namespaceSelector(
+                       [
+                               'selected' => $namespace,
+                               'all' => '',
+                               'label' => $this->msg( 'namespace' )->text(),
+                               'in-user-lang' => true,
+                       ], [
+                               'name' => 'namespace',
+                               'id' => 'namespace',
+                               'class' => 'namespaceselector',
+                       ]
+               );
+
+               $f .= "\u{00A0}" .
+                       Xml::checkLabel(
+                               $this->msg( 'invert' )->text(),
+                               'invert',
+                               'nsinvert',
+                               $nsinvert,
+                               [ 'title' => $this->msg( 'tooltip-whatlinkshere-invert' )->text() ]
+                       );
+
+               $f .= ' ';
+
+               # Submit
+               $f .= Xml::submitButton( $this->msg( 'whatlinkshere-submit' )->text() );
+
+               # Close
+               $f .= Xml::closeElement( 'fieldset' ) . Xml::closeElement( 'form' ) . "\n";
+
+               return $f;
+       }
+
+       /**
+        * Create filter panel
+        *
+        * @return string HTML fieldset and filter panel with the show/hide links
+        */
+       function getFilterPanel() {
+               $show = $this->msg( 'show' )->escaped();
+               $hide = $this->msg( 'hide' )->escaped();
+
+               $changed = $this->opts->getChangedValues();
+               unset( $changed['target'] ); // Already in the request title
+
+               $links = [];
+               $types = [ 'hidetrans', 'hidelinks', 'hideredirs' ];
+               if ( $this->target->getNamespace() == NS_FILE ) {
+                       $types[] = 'hideimages';
+               }
+
+               // Combined message keys: 'whatlinkshere-hideredirs', 'whatlinkshere-hidetrans',
+               // 'whatlinkshere-hidelinks', 'whatlinkshere-hideimages'
+               // To be sure they will be found by grep
+               foreach ( $types as $type ) {
+                       $chosen = $this->opts->getValue( $type );
+                       $msg = $chosen ? $show : $hide;
+                       $overrides = [ $type => !$chosen ];
+                       $links[] = $this->msg( "whatlinkshere-{$type}" )->rawParams(
+                               $this->makeSelfLink( $msg, array_merge( $changed, $overrides ) ) )->escaped();
+               }
+
+               return Xml::fieldset(
+                       $this->msg( 'whatlinkshere-filters' )->text(),
+                       $this->getLanguage()->pipeList( $links )
+               );
+       }
+
+       /**
+        * Return an array of subpages beginning with $search that this special page will accept.
+        *
+        * @param string $search Prefix to search for
+        * @param int $limit Maximum number of results to return (usually 10)
+        * @param int $offset Number of results to skip (usually 0)
+        * @return string[] Matching subpages
+        */
+       public function prefixSearchSubpages( $search, $limit, $offset ) {
+               return $this->prefixSearchString( $search, $limit, $offset );
+       }
+
+       protected function getGroupName() {
+               return 'pagetools';
+       }
+}
diff --git a/includes/specials/SpecialWhatlinkshere.php b/includes/specials/SpecialWhatlinkshere.php
deleted file mode 100644 (file)
index b48e858..0000000
+++ /dev/null
@@ -1,597 +0,0 @@
-<?php
-/**
- * Implements Special:Whatlinkshere
- *
- * 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
- * @todo Use some variant of Pager or something; the pagination here is lousy.
- */
-
-use Wikimedia\Rdbms\IDatabase;
-
-/**
- * Implements Special:Whatlinkshere
- *
- * @ingroup SpecialPage
- */
-class SpecialWhatLinksHere extends IncludableSpecialPage {
-       /** @var FormOptions */
-       protected $opts;
-
-       protected $selfTitle;
-
-       /** @var Title */
-       protected $target;
-
-       protected $limits = [ 20, 50, 100, 250, 500 ];
-
-       public function __construct() {
-               parent::__construct( 'Whatlinkshere' );
-       }
-
-       function execute( $par ) {
-               $out = $this->getOutput();
-
-               $this->setHeaders();
-               $this->outputHeader();
-               $this->addHelpLink( 'Help:What links here' );
-
-               $opts = new FormOptions();
-
-               $opts->add( 'target', '' );
-               $opts->add( 'namespace', '', FormOptions::INTNULL );
-               $opts->add( 'limit', $this->getConfig()->get( 'QueryPageDefaultLimit' ) );
-               $opts->add( 'from', 0 );
-               $opts->add( 'back', 0 );
-               $opts->add( 'hideredirs', false );
-               $opts->add( 'hidetrans', false );
-               $opts->add( 'hidelinks', false );
-               $opts->add( 'hideimages', false );
-               $opts->add( 'invert', false );
-
-               $opts->fetchValuesFromRequest( $this->getRequest() );
-               $opts->validateIntBounds( 'limit', 0, 5000 );
-
-               // Give precedence to subpage syntax
-               if ( $par !== null ) {
-                       $opts->setValue( 'target', $par );
-               }
-
-               // Bind to member variable
-               $this->opts = $opts;
-
-               $this->target = Title::newFromText( $opts->getValue( 'target' ) );
-               if ( !$this->target ) {
-                       if ( !$this->including() ) {
-                               $out->addHTML( $this->whatlinkshereForm() );
-                       }
-
-                       return;
-               }
-
-               $this->getSkin()->setRelevantTitle( $this->target );
-
-               $this->selfTitle = $this->getPageTitle( $this->target->getPrefixedDBkey() );
-
-               $out->setPageTitle( $this->msg( 'whatlinkshere-title', $this->target->getPrefixedText() ) );
-               $out->addBacklinkSubtitle( $this->target );
-               $this->showIndirectLinks(
-                       0,
-                       $this->target,
-                       $opts->getValue( 'limit' ),
-                       $opts->getValue( 'from' ),
-                       $opts->getValue( 'back' )
-               );
-       }
-
-       /**
-        * @param int $level Recursion level
-        * @param Title $target Target title
-        * @param int $limit Number of entries to display
-        * @param int $from Display from this article ID (default: 0)
-        * @param int $back Display from this article ID at backwards scrolling (default: 0)
-        */
-       function showIndirectLinks( $level, $target, $limit, $from = 0, $back = 0 ) {
-               $out = $this->getOutput();
-               $dbr = wfGetDB( DB_REPLICA );
-
-               $hidelinks = $this->opts->getValue( 'hidelinks' );
-               $hideredirs = $this->opts->getValue( 'hideredirs' );
-               $hidetrans = $this->opts->getValue( 'hidetrans' );
-               $hideimages = $target->getNamespace() != NS_FILE || $this->opts->getValue( 'hideimages' );
-
-               $fetchlinks = ( !$hidelinks || !$hideredirs );
-
-               // Build query conds in concert for all three tables...
-               $conds['pagelinks'] = [
-                       'pl_namespace' => $target->getNamespace(),
-                       'pl_title' => $target->getDBkey(),
-               ];
-               $conds['templatelinks'] = [
-                       'tl_namespace' => $target->getNamespace(),
-                       'tl_title' => $target->getDBkey(),
-               ];
-               $conds['imagelinks'] = [
-                       'il_to' => $target->getDBkey(),
-               ];
-
-               $namespace = $this->opts->getValue( 'namespace' );
-               $invert = $this->opts->getValue( 'invert' );
-               $nsComparison = ( $invert ? '!= ' : '= ' ) . $dbr->addQuotes( $namespace );
-               if ( is_int( $namespace ) ) {
-                       $conds['pagelinks'][] = "pl_from_namespace $nsComparison";
-                       $conds['templatelinks'][] = "tl_from_namespace $nsComparison";
-                       $conds['imagelinks'][] = "il_from_namespace $nsComparison";
-               }
-
-               if ( $from ) {
-                       $conds['templatelinks'][] = "tl_from >= $from";
-                       $conds['pagelinks'][] = "pl_from >= $from";
-                       $conds['imagelinks'][] = "il_from >= $from";
-               }
-
-               if ( $hideredirs ) {
-                       $conds['pagelinks']['rd_from'] = null;
-               } elseif ( $hidelinks ) {
-                       $conds['pagelinks'][] = 'rd_from is NOT NULL';
-               }
-
-               $queryFunc = function ( IDatabase $dbr, $table, $fromCol ) use (
-                       $conds, $target, $limit
-               ) {
-                       // Read an extra row as an at-end check
-                       $queryLimit = $limit + 1;
-                       $on = [
-                               "rd_from = $fromCol",
-                               'rd_title' => $target->getDBkey(),
-                               'rd_interwiki = ' . $dbr->addQuotes( '' ) . ' OR rd_interwiki IS NULL'
-                       ];
-                       $on['rd_namespace'] = $target->getNamespace();
-                       // Inner LIMIT is 2X in case of stale backlinks with wrong namespaces
-                       $subQuery = $dbr->buildSelectSubquery(
-                               [ $table, 'redirect', 'page' ],
-                               [ $fromCol, 'rd_from' ],
-                               $conds[$table],
-                               __CLASS__ . '::showIndirectLinks',
-                               // Force JOIN order per T106682 to avoid large filesorts
-                               [ 'ORDER BY' => $fromCol, 'LIMIT' => 2 * $queryLimit, 'STRAIGHT_JOIN' ],
-                               [
-                                       'page' => [ 'JOIN', "$fromCol = page_id" ],
-                                       'redirect' => [ 'LEFT JOIN', $on ]
-                               ]
-                       );
-                       return $dbr->select(
-                               [ 'page', 'temp_backlink_range' => $subQuery ],
-                               [ 'page_id', 'page_namespace', 'page_title', 'rd_from', 'page_is_redirect' ],
-                               [],
-                               __CLASS__ . '::showIndirectLinks',
-                               [ 'ORDER BY' => 'page_id', 'LIMIT' => $queryLimit ],
-                               [ 'page' => [ 'JOIN', "$fromCol = page_id" ] ]
-                       );
-               };
-
-               if ( $fetchlinks ) {
-                       $plRes = $queryFunc( $dbr, 'pagelinks', 'pl_from' );
-               }
-
-               if ( !$hidetrans ) {
-                       $tlRes = $queryFunc( $dbr, 'templatelinks', 'tl_from' );
-               }
-
-               if ( !$hideimages ) {
-                       $ilRes = $queryFunc( $dbr, 'imagelinks', 'il_from' );
-               }
-
-               if ( ( !$fetchlinks || !$plRes->numRows() )
-                       && ( $hidetrans || !$tlRes->numRows() )
-                       && ( $hideimages || !$ilRes->numRows() )
-               ) {
-                       if ( $level == 0 ) {
-                               if ( !$this->including() ) {
-                                       $out->addHTML( $this->whatlinkshereForm() );
-
-                                       // Show filters only if there are links
-                                       if ( $hidelinks || $hidetrans || $hideredirs || $hideimages ) {
-                                               $out->addHTML( $this->getFilterPanel() );
-                                       }
-                                       $msgKey = is_int( $namespace ) ? 'nolinkshere-ns' : 'nolinkshere';
-                                       $link = $this->getLinkRenderer()->makeLink(
-                                               $this->target,
-                                               null,
-                                               [],
-                                               $this->target->isRedirect() ? [ 'redirect' => 'no' ] : []
-                                       );
-
-                                       $errMsg = $this->msg( $msgKey )
-                                               ->params( $this->target->getPrefixedText() )
-                                               ->rawParams( $link )
-                                               ->parseAsBlock();
-                                       $out->addHTML( $errMsg );
-                                       $out->setStatusCode( 404 );
-                               }
-                       }
-
-                       return;
-               }
-
-               // Read the rows into an array and remove duplicates
-               // templatelinks comes second so that the templatelinks row overwrites the
-               // pagelinks row, so we get (inclusion) rather than nothing
-               if ( $fetchlinks ) {
-                       foreach ( $plRes as $row ) {
-                               $row->is_template = 0;
-                               $row->is_image = 0;
-                               $rows[$row->page_id] = $row;
-                       }
-               }
-               if ( !$hidetrans ) {
-                       foreach ( $tlRes as $row ) {
-                               $row->is_template = 1;
-                               $row->is_image = 0;
-                               $rows[$row->page_id] = $row;
-                       }
-               }
-               if ( !$hideimages ) {
-                       foreach ( $ilRes as $row ) {
-                               $row->is_template = 0;
-                               $row->is_image = 1;
-                               $rows[$row->page_id] = $row;
-                       }
-               }
-
-               // Sort by key and then change the keys to 0-based indices
-               ksort( $rows );
-               $rows = array_values( $rows );
-
-               $numRows = count( $rows );
-
-               // Work out the start and end IDs, for prev/next links
-               if ( $numRows > $limit ) {
-                       // More rows available after these ones
-                       // Get the ID from the last row in the result set
-                       $nextId = $rows[$limit]->page_id;
-                       // Remove undisplayed rows
-                       $rows = array_slice( $rows, 0, $limit );
-               } else {
-                       // No more rows after
-                       $nextId = false;
-               }
-               $prevId = $from;
-
-               // use LinkBatch to make sure, that all required data (associated with Titles)
-               // is loaded in one query
-               $lb = new LinkBatch();
-               foreach ( $rows as $row ) {
-                       $lb->add( $row->page_namespace, $row->page_title );
-               }
-               $lb->execute();
-
-               if ( $level == 0 ) {
-                       if ( !$this->including() ) {
-                               $out->addHTML( $this->whatlinkshereForm() );
-                               $out->addHTML( $this->getFilterPanel() );
-
-                               $link = $this->getLinkRenderer()->makeLink(
-                                       $this->target,
-                                       null,
-                                       [],
-                                       $this->target->isRedirect() ? [ 'redirect' => 'no' ] : []
-                               );
-
-                               $msg = $this->msg( 'linkshere' )
-                                       ->params( $this->target->getPrefixedText() )
-                                       ->rawParams( $link )
-                                       ->parseAsBlock();
-                               $out->addHTML( $msg );
-
-                               $prevnext = $this->getPrevNext( $prevId, $nextId );
-                               $out->addHTML( $prevnext );
-                       }
-               }
-               $out->addHTML( $this->listStart( $level ) );
-               foreach ( $rows as $row ) {
-                       $nt = Title::makeTitle( $row->page_namespace, $row->page_title );
-
-                       if ( $row->rd_from && $level < 2 ) {
-                               $out->addHTML( $this->listItem( $row, $nt, $target, true ) );
-                               $this->showIndirectLinks(
-                                       $level + 1,
-                                       $nt,
-                                       $this->getConfig()->get( 'MaxRedirectLinksRetrieved' )
-                               );
-                               $out->addHTML( Xml::closeElement( 'li' ) );
-                       } else {
-                               $out->addHTML( $this->listItem( $row, $nt, $target ) );
-                       }
-               }
-
-               $out->addHTML( $this->listEnd() );
-
-               if ( $level == 0 ) {
-                       if ( !$this->including() ) {
-                               $out->addHTML( $prevnext );
-                       }
-               }
-       }
-
-       protected function listStart( $level ) {
-               return Xml::openElement( 'ul', ( $level ? [] : [ 'id' => 'mw-whatlinkshere-list' ] ) );
-       }
-
-       protected function listItem( $row, $nt, $target, $notClose = false ) {
-               $dirmark = $this->getLanguage()->getDirMark();
-
-               # local message cache
-               static $msgcache = null;
-               if ( $msgcache === null ) {
-                       static $msgs = [ 'isredirect', 'istemplate', 'semicolon-separator',
-                               'whatlinkshere-links', 'isimage', 'editlink' ];
-                       $msgcache = [];
-                       foreach ( $msgs as $msg ) {
-                               $msgcache[$msg] = $this->msg( $msg )->escaped();
-                       }
-               }
-
-               if ( $row->rd_from ) {
-                       $query = [ 'redirect' => 'no' ];
-               } else {
-                       $query = [];
-               }
-
-               $link = $this->getLinkRenderer()->makeKnownLink(
-                       $nt,
-                       null,
-                       $row->page_is_redirect ? [ 'class' => 'mw-redirect' ] : [],
-                       $query
-               );
-
-               // Display properties (redirect or template)
-               $propsText = '';
-               $props = [];
-               if ( $row->rd_from ) {
-                       $props[] = $msgcache['isredirect'];
-               }
-               if ( $row->is_template ) {
-                       $props[] = $msgcache['istemplate'];
-               }
-               if ( $row->is_image ) {
-                       $props[] = $msgcache['isimage'];
-               }
-
-               Hooks::run( 'WhatLinksHereProps', [ $row, $nt, $target, &$props ] );
-
-               if ( count( $props ) ) {
-                       $propsText = $this->msg( 'parentheses' )
-                               ->rawParams( implode( $msgcache['semicolon-separator'], $props ) )->escaped();
-               }
-
-               # Space for utilities links, with a what-links-here link provided
-               $wlhLink = $this->wlhLink( $nt, $msgcache['whatlinkshere-links'], $msgcache['editlink'] );
-               $wlh = Xml::wrapClass(
-                       $this->msg( 'parentheses' )->rawParams( $wlhLink )->escaped(),
-                       'mw-whatlinkshere-tools'
-               );
-
-               return $notClose ?
-                       Xml::openElement( 'li' ) . "$link $propsText $dirmark $wlh\n" :
-                       Xml::tags( 'li', null, "$link $propsText $dirmark $wlh" ) . "\n";
-       }
-
-       protected function listEnd() {
-               return Xml::closeElement( 'ul' );
-       }
-
-       protected function wlhLink( Title $target, $text, $editText ) {
-               static $title = null;
-               if ( $title === null ) {
-                       $title = $this->getPageTitle();
-               }
-
-               $linkRenderer = $this->getLinkRenderer();
-
-               if ( $text !== null ) {
-                       $text = new HtmlArmor( $text );
-               }
-
-               // always show a "<- Links" link
-               $links = [
-                       'links' => $linkRenderer->makeKnownLink(
-                               $title,
-                               $text,
-                               [],
-                               [ 'target' => $target->getPrefixedText() ]
-                       ),
-               ];
-
-               // if the page is editable, add an edit link
-               if (
-                       // check user permissions
-                       $this->getUser()->isAllowed( 'edit' ) &&
-                       // check, if the content model is editable through action=edit
-                       ContentHandler::getForTitle( $target )->supportsDirectEditing()
-               ) {
-                       if ( $editText !== null ) {
-                               $editText = new HtmlArmor( $editText );
-                       }
-
-                       $links['edit'] = $linkRenderer->makeKnownLink(
-                               $target,
-                               $editText,
-                               [],
-                               [ 'action' => 'edit' ]
-                       );
-               }
-
-               // build the links html
-               return $this->getLanguage()->pipeList( $links );
-       }
-
-       function makeSelfLink( $text, $query ) {
-               if ( $text !== null ) {
-                       $text = new HtmlArmor( $text );
-               }
-
-               return $this->getLinkRenderer()->makeKnownLink(
-                       $this->selfTitle,
-                       $text,
-                       [],
-                       $query
-               );
-       }
-
-       function getPrevNext( $prevId, $nextId ) {
-               $currentLimit = $this->opts->getValue( 'limit' );
-               $prev = $this->msg( 'whatlinkshere-prev' )->numParams( $currentLimit )->escaped();
-               $next = $this->msg( 'whatlinkshere-next' )->numParams( $currentLimit )->escaped();
-
-               $changed = $this->opts->getChangedValues();
-               unset( $changed['target'] ); // Already in the request title
-
-               if ( $prevId != 0 ) {
-                       $overrides = [ 'from' => $this->opts->getValue( 'back' ) ];
-                       $prev = $this->makeSelfLink( $prev, array_merge( $changed, $overrides ) );
-               }
-               if ( $nextId != 0 ) {
-                       $overrides = [ 'from' => $nextId, 'back' => $prevId ];
-                       $next = $this->makeSelfLink( $next, array_merge( $changed, $overrides ) );
-               }
-
-               $limitLinks = [];
-               $lang = $this->getLanguage();
-               foreach ( $this->limits as $limit ) {
-                       $prettyLimit = htmlspecialchars( $lang->formatNum( $limit ) );
-                       $overrides = [ 'limit' => $limit ];
-                       $limitLinks[] = $this->makeSelfLink( $prettyLimit, array_merge( $changed, $overrides ) );
-               }
-
-               $nums = $lang->pipeList( $limitLinks );
-
-               return $this->msg( 'viewprevnext' )->rawParams( $prev, $next, $nums )->escaped();
-       }
-
-       function whatlinkshereForm() {
-               // We get nicer value from the title object
-               $this->opts->consumeValue( 'target' );
-               // Reset these for new requests
-               $this->opts->consumeValues( [ 'back', 'from' ] );
-
-               $target = $this->target ? $this->target->getPrefixedText() : '';
-               $namespace = $this->opts->consumeValue( 'namespace' );
-               $nsinvert = $this->opts->consumeValue( 'invert' );
-
-               # Build up the form
-               $f = Xml::openElement( 'form', [ 'action' => wfScript() ] );
-
-               # Values that should not be forgotten
-               $f .= Html::hidden( 'title', $this->getPageTitle()->getPrefixedText() );
-               foreach ( $this->opts->getUnconsumedValues() as $name => $value ) {
-                       $f .= Html::hidden( $name, $value );
-               }
-
-               $f .= Xml::fieldset( $this->msg( 'whatlinkshere' )->text() );
-
-               # Target input (.mw-searchInput enables suggestions)
-               $f .= Xml::inputLabel( $this->msg( 'whatlinkshere-page' )->text(), 'target',
-                       'mw-whatlinkshere-target', 40, $target, [ 'class' => 'mw-searchInput' ] );
-
-               $f .= ' ';
-
-               # Namespace selector
-               $f .= Html::namespaceSelector(
-                       [
-                               'selected' => $namespace,
-                               'all' => '',
-                               'label' => $this->msg( 'namespace' )->text(),
-                               'in-user-lang' => true,
-                       ], [
-                               'name' => 'namespace',
-                               'id' => 'namespace',
-                               'class' => 'namespaceselector',
-                       ]
-               );
-
-               $f .= "\u{00A0}" .
-                       Xml::checkLabel(
-                               $this->msg( 'invert' )->text(),
-                               'invert',
-                               'nsinvert',
-                               $nsinvert,
-                               [ 'title' => $this->msg( 'tooltip-whatlinkshere-invert' )->text() ]
-                       );
-
-               $f .= ' ';
-
-               # Submit
-               $f .= Xml::submitButton( $this->msg( 'whatlinkshere-submit' )->text() );
-
-               # Close
-               $f .= Xml::closeElement( 'fieldset' ) . Xml::closeElement( 'form' ) . "\n";
-
-               return $f;
-       }
-
-       /**
-        * Create filter panel
-        *
-        * @return string HTML fieldset and filter panel with the show/hide links
-        */
-       function getFilterPanel() {
-               $show = $this->msg( 'show' )->escaped();
-               $hide = $this->msg( 'hide' )->escaped();
-
-               $changed = $this->opts->getChangedValues();
-               unset( $changed['target'] ); // Already in the request title
-
-               $links = [];
-               $types = [ 'hidetrans', 'hidelinks', 'hideredirs' ];
-               if ( $this->target->getNamespace() == NS_FILE ) {
-                       $types[] = 'hideimages';
-               }
-
-               // Combined message keys: 'whatlinkshere-hideredirs', 'whatlinkshere-hidetrans',
-               // 'whatlinkshere-hidelinks', 'whatlinkshere-hideimages'
-               // To be sure they will be found by grep
-               foreach ( $types as $type ) {
-                       $chosen = $this->opts->getValue( $type );
-                       $msg = $chosen ? $show : $hide;
-                       $overrides = [ $type => !$chosen ];
-                       $links[] = $this->msg( "whatlinkshere-{$type}" )->rawParams(
-                               $this->makeSelfLink( $msg, array_merge( $changed, $overrides ) ) )->escaped();
-               }
-
-               return Xml::fieldset(
-                       $this->msg( 'whatlinkshere-filters' )->text(),
-                       $this->getLanguage()->pipeList( $links )
-               );
-       }
-
-       /**
-        * Return an array of subpages beginning with $search that this special page will accept.
-        *
-        * @param string $search Prefix to search for
-        * @param int $limit Maximum number of results to return (usually 10)
-        * @param int $offset Number of results to skip (usually 0)
-        * @return string[] Matching subpages
-        */
-       public function prefixSearchSubpages( $search, $limit, $offset ) {
-               return $this->prefixSearchString( $search, $limit, $offset );
-       }
-
-       protected function getGroupName() {
-               return 'pagetools';
-       }
-}
index a1e5156..548e921 100644 (file)
@@ -22,6 +22,8 @@
  * @author Rob Church <robchur@gmail.com>
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * Special page lists pages without language links
  *
@@ -91,7 +93,8 @@ class WithoutInterwikiPage extends PageQueryPage {
                        ],
                        'conds' => [
                                'll_title IS NULL',
-                               'page_namespace' => MWNamespace::getContentNamespaces(),
+                               'page_namespace' => MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                       getContentNamespaces(),
                                'page_is_redirect' => 0
                        ],
                        'join_conds' => [ 'langlinks' => [ 'LEFT JOIN', 'll_from = page_id' ] ]
diff --git a/includes/specials/forms/PreferencesFormLegacy.php b/includes/specials/forms/PreferencesFormLegacy.php
deleted file mode 100644 (file)
index 951e5ce..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-/**
- * Form to edit user preferences.
- *
- * @since 1.32
- */
-class PreferencesFormLegacy extends PreferencesFormOOUI {
-       // No-op
-}
-
-/**
- * Retain the old class name for backwards compatibility.
- *
- * @deprecated since 1.32
- */
-class_alias( PreferencesFormLegacy::class, 'PreferencesForm' );
index 81abf1c..9b86812 100644 (file)
@@ -117,45 +117,12 @@ class PreferencesFormOOUI extends OOUIHTMLForm {
        }
 
        protected function wrapFieldSetSection( $legend, $section, $attributes, $isRoot ) {
-               // to get a user visible effect, wrap the fieldset into a framed panel layout
-               if ( $isRoot ) {
-                       // Mimic TabPanelLayout
-                       $wrapper = new OOUI\PanelLayout( [
-                               'expanded' => false,
-                               'scrollable' => true,
-                               // Framed and padded for no-JS, frame hidden with CSS
-                               'framed' => true,
-                               'infusable' => false,
-                               'classes' => [ 'oo-ui-stackLayout oo-ui-indexLayout-stackLayout' ]
-                       ] );
-                       $layout = new OOUI\PanelLayout( [
-                               'expanded' => false,
-                               'scrollable' => true,
-                               'infusable' => false,
-                               'classes' => [ 'oo-ui-tabPanelLayout' ]
-                       ] );
-                       $wrapper->appendContent( $layout );
-               } else {
-                       $wrapper = $layout = new OOUI\PanelLayout( [
-                               'expanded' => false,
-                               'padded' => true,
-                               'framed' => true,
-                               'infusable' => false,
-                       ] );
-               }
+               $layout = parent::wrapFieldSetSection( $legend, $section, $attributes, $isRoot );
+
+               $layout->addClasses( [ 'mw-prefs-fieldset-wrapper' ] );
+               $layout->removeClasses( [ 'oo-ui-panelLayout-framed' ] );
 
-               $layout->appendContent(
-                       new OOUI\FieldsetLayout( [
-                               'label' => $legend,
-                               'infusable' => false,
-                               'items' => [
-                                       new OOUI\Widget( [
-                                               'content' => new OOUI\HtmlSnippet( $section )
-                                       ] ),
-                               ],
-                       ] + $attributes )
-               );
-               return $wrapper;
+               return $layout;
        }
 
        /**
@@ -163,61 +130,55 @@ class PreferencesFormOOUI extends OOUIHTMLForm {
         * @return string
         */
        function getBody() {
-               // Construct fake tabs to avoid FOUC. The structure mimics OOUI's tabPanelLayout.
-               // TODO: Consider creating an infusable TabPanelLayout in OOUI-PHP.
-               $fakeTabs = [];
-               foreach ( $this->getPreferenceSections() as $i => $key ) {
-                       $fakeTabs[] =
-                               Html::rawElement(
-                                       'div',
-                                       [
-                                               'class' =>
-                                                       'oo-ui-widget oo-ui-widget-enabled oo-ui-optionWidget ' .
-                                                       'oo-ui-tabOptionWidget oo-ui-labelElement' .
-                                                       ( $i === 0 ? ' oo-ui-optionWidget-selected' : '' )
+               $tabPanels = [];
+               foreach ( $this->mFieldTree as $key => $val ) {
+                       if ( !is_array( $val ) ) {
+                               wfDebug( __METHOD__ . " encountered a field not attached to a section: '$key'" );
+                               continue;
+                       }
+                       $label = $this->getLegend( $key );
+                       $content =
+                               $this->getHeaderText( $key ) .
+                               $this->displaySection(
+                                       $this->mFieldTree[$key],
+                                       "",
+                                       "mw-prefsection-$key-"
+                               ) .
+                               $this->getFooterText( $key );
+
+                       $tabPanels[] = new OOUI\TabPanelLayout( [
+                               'classes' => [ 'mw-htmlform-autoinfuse-lazy' ],
+                               'name' => 'mw-prefsection-' . $key,
+                               'label' => $label,
+                               'content' => new OOUI\FieldsetLayout( [
+                                       'classes' => [ 'mw-prefs-section-fieldset' ],
+                                       'id' => "mw-prefsection-$key",
+                                       'label' => $label,
+                                       'items' => [
+                                               new OOUI\Widget( [
+                                                       'content' => new OOUI\HtmlSnippet( $content )
+                                               ] ),
                                        ],
-                                       Html::element(
-                                               'a',
-                                               [
-                                                       'class' => 'oo-ui-labelElement-label',
-                                                       // Make this a usable link instead of a span so the tabs
-                                                       // can be used before JS runs
-                                                       'href' => '#mw-prefsection-' . $key
-                                               ],
-                                               $this->getLegend( $key )
-                                       )
-                               );
+                               ] ),
+                               'expanded' => false,
+                               'framed' => true,
+                       ] );
                }
-               $fakeTabsHtml = Html::rawElement(
-                       'div',
-                       [ 'class' => 'oo-ui-layout oo-ui-panelLayout oo-ui-indexLayout-tabPanel' ],
-                       Html::rawElement(
-                               'div',
-                               [ 'class' => 'oo-ui-widget oo-ui-widget-enabled oo-ui-selectWidget ' .
-                                       'oo-ui-selectWidget-depressed oo-ui-tabSelectWidget' ],
-                               implode( $fakeTabs )
-                       )
-               );
-
-               return Html::rawElement(
-                       'div',
-                       [ 'class' => 'oo-ui-layout oo-ui-panelLayout oo-ui-panelLayout-framed mw-prefs-faketabs' ],
-                       Html::rawElement(
-                               'div',
-                               [ 'class' => 'oo-ui-layout oo-ui-menuLayout oo-ui-menuLayout-static ' .
-                                       'oo-ui-menuLayout-top oo-ui-menuLayout-showMenu oo-ui-indexLayout' ],
-                               Html::rawElement(
-                                       'div',
-                                       [ 'class' => 'oo-ui-menuLayout-menu' ],
-                                       $fakeTabsHtml
-                               ) .
-                               Html::rawElement(
-                                       'div',
-                                       [ 'class' => 'oo-ui-menuLayout-content mw-htmlform-autoinfuse-lazy' ],
-                                       $this->displaySection( $this->mFieldTree, '', 'mw-prefsection-' )
-                               )
-                       )
-               );
+
+               $indexLayout = new OOUI\IndexLayout( [
+                       'infusable' => true,
+                       'expanded' => false,
+                       'autoFocus' => false,
+                       'classes' => [ 'mw-prefs-tabs' ],
+               ] );
+               $indexLayout->addTabPanels( $tabPanels );
+
+               return new OOUI\PanelLayout( [
+                       'framed' => true,
+                       'expanded' => false,
+                       'classes' => [ 'mw-prefs-tabs-wrapper' ],
+                       'content' => $indexLayout
+               ] );
        }
 
        /**
@@ -234,7 +195,7 @@ class PreferencesFormOOUI extends OOUIHTMLForm {
 
        /**
         * Get the keys of each top level preference section.
-        * @return array of section keys
+        * @return string[] List of section keys
         */
        function getPreferenceSections() {
                return array_keys( array_filter( $this->mFieldTree, 'is_array' ) );
index da4398a..be28417 100644 (file)
@@ -393,7 +393,7 @@ class UploadForm extends HTMLForm {
         */
        public function show() {
                $this->addUploadJS();
-               parent::show();
+               return parent::show();
        }
 
        /**
@@ -415,7 +415,8 @@ class UploadForm extends HTMLForm {
                        'wgCheckFileExtensions' => $config->get( 'CheckFileExtensions' ),
                        'wgStrictFileExtensions' => $config->get( 'StrictFileExtensions' ),
                        'wgFileExtensions' => array_values( array_unique( $config->get( 'FileExtensions' ) ) ),
-                       'wgCapitalizeUploads' => MWNamespace::isCapitalized( NS_FILE ),
+                       'wgCapitalizeUploads' => MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               isCapitalized( NS_FILE ),
                        'wgMaxUploadSize' => $this->mMaxUploadSize,
                        'wgFileCanRotate' => SpecialUpload::rotationEnabled(),
                ];
index c79e87c..8063804 100644 (file)
@@ -69,10 +69,10 @@ class ImportReporter extends ContextSource {
                );
        }
 
-       function reportLogItem( /* ... */ ) {
+       function reportLogItem( ...$args ) {
                $this->mLogItemCount++;
                if ( is_callable( $this->mOriginalLogCallback ) ) {
-                       call_user_func_array( $this->mOriginalLogCallback, func_get_args() );
+                       call_user_func_array( $this->mOriginalLogCallback, $args );
                }
        }
 
@@ -86,8 +86,7 @@ class ImportReporter extends ContextSource {
         */
        public function reportPage( $title, $foreignTitle, $revisionCount,
                        $successCount, $pageInfo ) {
-               $args = func_get_args();
-               call_user_func_array( $this->mOriginalPageOutCallback, $args );
+               call_user_func_array( $this->mOriginalPageOutCallback, func_get_args() );
 
                if ( $title === null ) {
                        # Invalid or non-importable title; a notice is already displayed
index 5dbdba0..368c6d1 100644 (file)
@@ -225,12 +225,22 @@ class ActiveUsersPager extends UsersPager {
                $userName = $row->user_name;
 
                $ulinks = Linker::userLink( $row->user_id, $userName );
-               $ulinks .= Linker::userToolLinks( $row->user_id, $userName );
+               $ulinks .= Linker::userToolLinks(
+                       $row->user_id,
+                       $userName,
+                       // Should the contributions link be red if the user has no edits (using default)
+                       false,
+                       // Customisation flags (using default 0)
+                       0,
+                       // User edit count (using default)
+                       null,
+                       // do not wrap the message in parentheses (CSS will provide these)
+                       false
+               );
 
                $lang = $this->getLanguage();
 
                $list = [];
-               $user = User::newFromId( $row->user_id );
 
                $ugms = self::getGroupMemberships( intval( $row->user_id ), $this->userGroupCache );
                foreach ( $ugms as $ugm ) {
index 2fc946e..a2dbb72 100644 (file)
@@ -22,7 +22,6 @@
 /**
  * @ingroup Pager
  */
-use MediaWiki\Block\BlockRestriction;
 use MediaWiki\Block\Restriction\Restriction;
 use MediaWiki\Block\Restriction\PageRestriction;
 use MediaWiki\Block\Restriction\NamespaceRestriction;
@@ -161,7 +160,7 @@ class BlockListPager extends TablePager {
                                        $formatted .= '<br />' . $this->msg(
                                                'ipb-blocklist-duration-left',
                                                $language->formatDuration(
-                                                       $timestamp->getTimestamp() - time(),
+                                                       $timestamp->getTimestamp() - MWTimestamp::time(),
                                                        // reasonable output
                                                        [
                                                                'minutes',
@@ -191,10 +190,8 @@ class BlockListPager extends TablePager {
                        case 'ipb_params':
                                $properties = [];
 
-                               if ( $this->getConfig()->get( 'EnablePartialBlocks' ) ) {
-                                       if ( $row->ipb_sitewide ) {
-                                               $properties[] = htmlspecialchars( $msg['blocklist-editing-sitewide'] );
-                                       }
+                               if ( $this->getConfig()->get( 'EnablePartialBlocks' ) && $row->ipb_sitewide ) {
+                                       $properties[] = htmlspecialchars( $msg['blocklist-editing-sitewide'] );
                                }
 
                                if ( !$row->ipb_sitewide && $this->restrictions ) {
@@ -252,6 +249,7 @@ class BlockListPager extends TablePager {
         */
        private function getRestrictionListHTML( stdClass $row ) {
                $items = [];
+               $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
 
                foreach ( $this->restrictions as $restriction ) {
                        if ( $restriction->getBlockId() !== (int)$row->ipb_id ) {
@@ -261,23 +259,23 @@ class BlockListPager extends TablePager {
                        switch ( $restriction->getType() ) {
                                case PageRestriction::TYPE:
                                        if ( $restriction->getTitle() ) {
-                                               $items[$restriction->getType()][] = HTML::rawElement(
+                                               $items[$restriction->getType()][] = Html::rawElement(
                                                        'li',
                                                        [],
-                                                       Linker::link( $restriction->getTitle() )
+                                                       $linkRenderer->makeLink( $restriction->getTitle() )
                                                );
                                        }
                                        break;
                                case NamespaceRestriction::TYPE:
                                        $text = $restriction->getValue() === NS_MAIN
-                                               ? $this->msg( 'blanknamespace' )
+                                               ? $this->msg( 'blanknamespace' )->text()
                                                : $this->getLanguage()->getFormattedNsText(
                                                        $restriction->getValue()
                                                );
-                                       $items[$restriction->getType()][] = HTML::rawElement(
+                                       $items[$restriction->getType()][] = Html::rawElement(
                                                'li',
                                                [],
-                                               Linker::link(
+                                               $linkRenderer->makeLink(
                                                        SpecialPage::getTitleValueFor( 'Allpages' ),
                                                        $text,
                                                        [],
@@ -421,7 +419,8 @@ class BlockListPager extends TablePager {
                if ( $partialBlocks ) {
                        // Mutations to the $row object are not persisted. The restrictions will
                        // need be stored in a separate store.
-                       $this->restrictions = BlockRestriction::loadByBlockId( $partialBlocks );
+                       $blockRestrictionStore = MediaWikiServices::getInstance()->getBlockRestrictionStore();
+                       $this->restrictions = $blockRestrictionStore->loadByBlockId( $partialBlocks );
                }
 
                $lb->execute();
index 382ba2f..d82ba53 100644 (file)
@@ -103,6 +103,21 @@ class ContribsPager extends RangeChronologicalPager {
        private $templateParser;
 
        public function __construct( IContextSource $context, array $options ) {
+               // Set ->target and ->contribs before calling parent::__construct() so
+               // parent can call $this->getIndexField() and get the right result. Set
+               // the rest too just to keep things simple.
+               $this->target = $options['target'] ?? '';
+               $this->contribs = $options['contribs'] ?? 'users';
+               $this->namespace = $options['namespace'] ?? '';
+               $this->tagFilter = $options['tagfilter'] ?? false;
+               $this->nsInvert = $options['nsInvert'] ?? false;
+               $this->associated = $options['associated'] ?? false;
+
+               $this->deletedOnly = !empty( $options['deletedOnly'] );
+               $this->topOnly = !empty( $options['topOnly'] );
+               $this->newOnly = !empty( $options['newOnly'] );
+               $this->hideMinor = !empty( $options['hideMinor'] );
+
                parent::__construct( $context );
 
                $msgs = [
@@ -116,18 +131,6 @@ class ContribsPager extends RangeChronologicalPager {
                        $this->messages[$msg] = $this->msg( $msg )->escaped();
                }
 
-               $this->target = $options['target'] ?? '';
-               $this->contribs = $options['contribs'] ?? 'users';
-               $this->namespace = $options['namespace'] ?? '';
-               $this->tagFilter = $options['tagfilter'] ?? false;
-               $this->nsInvert = $options['nsInvert'] ?? false;
-               $this->associated = $options['associated'] ?? false;
-
-               $this->deletedOnly = !empty( $options['deletedOnly'] );
-               $this->topOnly = !empty( $options['topOnly'] );
-               $this->newOnly = !empty( $options['newOnly'] );
-               $this->hideMinor = !empty( $options['hideMinor'] );
-
                // Date filtering: use timestamp if available
                $startTimestamp = '';
                $endTimestamp = '';
@@ -154,6 +157,19 @@ class ContribsPager extends RangeChronologicalPager {
                return $query;
        }
 
+       /**
+        * Wrap the navigation bar in a p element with identifying class.
+        * In future we may want to change the `p` tag to a `div` and upstream
+        * this to the parent class.
+        *
+        * @return string HTML
+        */
+       function getNavigationBar() {
+               return Html::rawElement( 'p', [ 'class' => 'mw-pager-navigation-bar' ],
+                       parent::getNavigationBar()
+               );
+       }
+
        /**
         * This method basically executes the exact same code as the parent class, though with
         * a hook added, to allow extensions to add additional queries.
@@ -222,6 +238,35 @@ class ContribsPager extends RangeChronologicalPager {
                return new FakeResultWrapper( $result );
        }
 
+       /**
+        * Return the table targeted for ordering and continuation
+        *
+        * See T200259 and T221380.
+        *
+        * @warning Keep this in sync with self::getQueryInfo()!
+        *
+        * @return string
+        */
+       private function getTargetTable() {
+               if ( $this->contribs == 'newbie' ) {
+                       return 'revision';
+               }
+
+               $user = User::newFromName( $this->target, false );
+               $ipRangeConds = $user->isAnon() ? $this->getIpRangeConds( $this->mDb, $this->target ) : null;
+               if ( $ipRangeConds ) {
+                       return 'ip_changes';
+               } else {
+                       $conds = ActorMigration::newMigration()->getWhere( $this->mDb, 'rev_user', $user );
+                       if ( isset( $conds['orconds']['actor'] ) ) {
+                               // @todo: This will need changing when revision_actor_temp goes away
+                               return 'revision_actor_temp';
+                       }
+               }
+
+               return 'revision';
+       }
+
        function getQueryInfo() {
                $revQuery = Revision::getQueryInfo( [ 'page', 'user' ] );
                $queryInfo = [
@@ -232,6 +277,8 @@ class ContribsPager extends RangeChronologicalPager {
                        'join_conds' => $revQuery['joins'],
                ];
 
+               // WARNING: Keep this in sync with getTargetTable()!
+
                if ( $this->contribs == 'newbie' ) {
                        $max = $this->mDb->selectField( 'user', 'max(user_id)', '', __METHOD__ );
                        $queryInfo['conds'][] = $revQuery['fields']['rev_user'] . ' >' . (int)( $max - $max / 100 );
@@ -260,22 +307,6 @@ class ContribsPager extends RangeChronologicalPager {
                        $ipRangeConds = $user->isAnon() ? $this->getIpRangeConds( $this->mDb, $this->target ) : null;
                        if ( $ipRangeConds ) {
                                $queryInfo['tables'][] = 'ip_changes';
-                               /**
-                                * These aliases make `ORDER BY rev_timestamp, rev_id` from {@see getIndexField} and
-                                * {@see getExtraSortFields} use the replicated `ipc_rev_timestamp` and `ipc_rev_id`
-                                * columns from the `ip_changes` table, for more efficient queries.
-                                * @see https://phabricator.wikimedia.org/T200259#4832318
-                                */
-                               $queryInfo['fields'] = array_merge(
-                                       [
-                                               'rev_timestamp' => 'ipc_rev_timestamp',
-                                               'rev_id' => 'ipc_rev_id',
-                                       ],
-                                       array_diff( $queryInfo['fields'], [
-                                               'rev_timestamp',
-                                               'rev_id',
-                                       ] )
-                               );
                                $queryInfo['join_conds']['ip_changes'] = [
                                        'LEFT JOIN', [ 'ipc_rev_id = rev_id' ]
                                ];
@@ -286,14 +317,8 @@ class ContribsPager extends RangeChronologicalPager {
                                $queryInfo['conds'][] = $conds['conds'];
                                // Force the appropriate index to avoid bad query plans (T189026)
                                if ( isset( $conds['orconds']['actor'] ) ) {
-                                       // @todo: This will need changing when revision_comment_temp goes away
+                                       // @todo: This will need changing when revision_actor_temp goes away
                                        $queryInfo['options']['USE INDEX']['temp_rev_user'] = 'actor_timestamp';
-                                       // Alias 'rev_timestamp' => 'revactor_timestamp' so "ORDER BY rev_timestamp" is interpreted to
-                                       // use revactor_timestamp instead.
-                                       $queryInfo['fields'] = array_merge(
-                                               array_diff( $queryInfo['fields'], [ 'rev_timestamp' ] ),
-                                               [ 'rev_timestamp' => 'revactor_timestamp' ]
-                                       );
                                } else {
                                        $queryInfo['options']['USE INDEX']['revision'] =
                                                isset( $conds['orconds']['userid'] ) ? 'user_timestamp' : 'usertext_timestamp';
@@ -328,10 +353,10 @@ class ContribsPager extends RangeChronologicalPager {
                                ' != ' . Revision::SUPPRESSED_USER;
                }
 
-               // For IPv6, we use ipc_rev_timestamp on ip_changes as the index field,
-               // which will be referenced when parsing the results of a query.
-               if ( self::isQueryableRange( $this->target ) ) {
-                       $queryInfo['fields'][] = 'ipc_rev_timestamp';
+               // $this->getIndexField() must be in the result rows, as reallyDoQuery() tries to access it.
+               $indexField = $this->getIndexField();
+               if ( $indexField !== 'rev_timestamp' ) {
+                       $queryInfo['fields'][] = $indexField;
                }
 
                ChangeTags::modifyDisplayQuery(
@@ -361,7 +386,7 @@ class ContribsPager extends RangeChronologicalPager {
                        }
 
                        $associatedNS = $this->mDb->addQuotes(
-                               MWNamespace::getAssociated( $this->namespace )
+                               MediaWikiServices::getInstance()->getNamespaceInfo()->getAssociated( $this->namespace )
                        );
 
                        return [
@@ -417,8 +442,24 @@ class ContribsPager extends RangeChronologicalPager {
         * @return string
         */
        public function getIndexField() {
-               // Note this is run via parent::__construct() *before* $this->target is set!
-               return 'rev_timestamp';
+               // The returned column is used for sorting and continuation, so we need to
+               // make sure to use the right denormalized column depending on which table is
+               // being targeted by the query to avoid bad query plans.
+               // See T200259, T204669, T220991, and T221380.
+               $target = $this->getTargetTable();
+               switch ( $target ) {
+                       case 'revision':
+                               return 'rev_timestamp';
+                       case 'ip_changes':
+                               return 'ipc_rev_timestamp';
+                       case 'revision_actor_temp':
+                               return 'revactor_timestamp';
+                       default:
+                               wfWarn(
+                                       __METHOD__ . ": Unknown value '$target' from " . static::class . '::getTargetTable()', 0
+                               );
+                               return 'rev_timestamp';
+               }
        }
 
        /**
@@ -460,8 +501,24 @@ class ContribsPager extends RangeChronologicalPager {
         * @return string[]
         */
        protected function getExtraSortFields() {
-               // Note this is run via parent::__construct() *before* $this->target is set!
-               return [ 'rev_id' ];
+               // The returned columns are used for sorting, so we need to make sure
+               // to use the right denormalized column depending on which table is
+               // being targeted by the query to avoid bad query plans.
+               // See T200259, T204669, T220991, and T221380.
+               $target = $this->getTargetTable();
+               switch ( $target ) {
+                       case 'revision':
+                               return [ 'rev_id' ];
+                       case 'ip_changes':
+                               return [ 'ipc_rev_id' ];
+                       case 'revision_actor_temp':
+                               return [ 'revactor_rev' ];
+                       default:
+                               wfWarn(
+                                       __METHOD__ . ": Unknown value '$target' from " . static::class . '::getTargetTable()', 0
+                               );
+                               return [ 'rev_id' ];
+               }
        }
 
        protected function doBatchLookups() {
@@ -633,20 +690,7 @@ class ContribsPager extends RangeChronologicalPager {
 
                        $lang = $this->getLanguage();
                        $comment = $lang->getDirMark() . Linker::revComment( $rev, false, true, false );
-                       $date = $lang->userTimeAndDate( $row->rev_timestamp, $user );
-                       if ( $rev->userCan( Revision::DELETED_TEXT, $user ) ) {
-                               $d = $linkRenderer->makeKnownLink(
-                                       $page,
-                                       $date,
-                                       [ 'class' => 'mw-changeslist-date' ],
-                                       [ 'oldid' => intval( $row->rev_id ) ]
-                               );
-                       } else {
-                               $d = htmlspecialchars( $date );
-                       }
-                       if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
-                               $d = '<span class="history-deleted">' . $d . '</span>';
-                       }
+                       $d = ChangesList::revDateLink( $rev, $user, $lang, $page );
 
                        # Show user names for /newbies as there may be different users.
                        # Note that only unprivileged users have rows with hidden user names excluded.
index 56b799b..11a8532 100644 (file)
@@ -50,7 +50,7 @@ class DeletedContribsPager extends IndexPager {
        public $namespace = '';
 
        /**
-        * @var \Wikimedia\Rdbms\Database
+        * @var IDatabase
         */
        public $mDb;
 
index 486b0ec..ea55568 100644 (file)
@@ -269,10 +269,8 @@ class ImageListPager extends TablePager {
                                }
                        }
                        $fields['top'] = $dbr->addQuotes( 'no' );
-               } else {
-                       if ( $this->mShowAll ) {
-                               $fields['top'] = $dbr->addQuotes( 'yes' );
-                       }
+               } elseif ( $this->mShowAll ) {
+                       $fields['top'] = $dbr->addQuotes( 'yes' );
                }
                $fields['thumb'] = $prefix . '_name';
 
@@ -382,14 +380,12 @@ class ImageListPager extends TablePager {
                                        $resultArray[] = $topRes2;
                                        $topRes2 = $res2->next();
                                }
+                       } elseif ( !$ascending ) {
+                               $resultArray[] = $topRes2;
+                               $topRes2 = $res2->next();
                        } else {
-                               if ( !$ascending ) {
-                                       $resultArray[] = $topRes2;
-                                       $topRes2 = $res2->next();
-                               } else {
-                                       $resultArray[] = $topRes1;
-                                       $topRes1 = $res1->next();
-                               }
+                               $resultArray[] = $topRes1;
+                               $topRes1 = $res1->next();
                        }
                }
 
index d05ebf8..88dff6e 100644 (file)
@@ -204,5 +204,6 @@ class NewFilesPager extends RangeChronologicalPager {
                        . htmlspecialchars( $time )
                        . "</i><br />\n"
                );
+               return '';
        }
 }
index bc4202e..5583842 100644 (file)
@@ -49,7 +49,7 @@ class ProtectedPagesPager extends TablePager {
                LinkRenderer $linkRenderer
        ) {
                $this->mConds = $conds;
-               $this->type = ( $type ) ? $type : 'edit';
+               $this->type = $type ?: 'edit';
                $this->level = $level;
                $this->namespace = $namespace;
                $this->sizetype = $sizetype;
index 8dd6e23..57b575b 100644 (file)
@@ -49,7 +49,7 @@ class UsersPager extends AlphabeticPager {
                }
 
                $request = $this->getRequest();
-               $par = ( $par !== null ) ? $par : '';
+               $par = $par ?? '';
                $parms = explode( '/', $par );
                $symsForAll = [ '*', 'user' ];
 
@@ -178,7 +178,9 @@ class UsersPager extends AlphabeticPager {
                $ulinks .= Linker::userToolLinksRedContribs(
                        $row->user_id,
                        $userName,
-                       (int)$row->edits
+                       (int)$row->edits,
+                       // don't render parentheses in HTML markup (CSS will provide)
+                       false
                );
 
                $lang = $this->getLanguage();
@@ -275,7 +277,7 @@ class UsersPager extends AlphabeticPager {
         * @return string
         */
        function getPageHeader() {
-               list( $self ) = explode( '/', $this->getTitle()->getPrefixedDBkey() );
+               $self = explode( '/', $this->getTitle()->getPrefixedDBkey(), 2 )[0];
 
                $groupOptions = [ $this->msg( 'group-all' )->text() => '' ];
                foreach ( $this->getAllGroups() as $group => $groupText ) {
index 6d9d6b0..f20afdb 100644 (file)
                                <div class="mw-rcfilters-ui-highlights-color-c5" data-color="c5"></div>
                        </div>
                </td>
-               <td><span class="mw-collapsible-toggle mw-collapsible-arrow mw-enhancedchanges-arrow mw-enhancedchanges-arrow-space mw-collapsible-toggle-collapsed"></span></td>
+               <td>{{!
+                       }}<span class="mw-collapsible-toggle mw-collapsible-arrow mw-enhancedchanges-arrow mw-enhancedchanges-arrow-space mw-collapsible-toggle-collapsed"></span>{{!
+               }}</td>
                <td class="mw-changeslist-line-prefix">{{{ prefix }}}</td>
                <td class="mw-enhanced-rc" colspan="2">{{{ collectedRcFlags }}}&#160;{{ timestamp }}&#160;</td>
-               <td class="mw-changeslist-line-inner">
-                       {{# rev-deleted-event }}<span class="history-deleted">{{{ . }}}</span>{{/ rev-deleted-event }}
-                       {{{ articleLink }}}{{{ languageDirMark }}}{{{ logText }}}
-                       <span class="mw-changeslist-separator">. .</span>
-                       {{# charDifference }}{{{ . }}} <span class="mw-changeslist-separator">. .</span>{{/ charDifference }}
-                       <span class="changedby">{{{ users }}}</span>
-                       {{ numberofWatchingusers }}
-               </td>
+               <td class="mw-changeslist-line-inner">{{!
+                       }}{{# rev-deleted-event }}<span class="history-deleted">{{{ . }}}</span>{{/ rev-deleted-event }}{{!
+                       }}{{{ articleLink }}}{{{ languageDirMark }}}{{{ logText }}}{{!
+                       }}<span class="mw-changeslist-separator"></span>{{!
+                       }}{{# charDifference }}{{{ . }}} <span class="mw-changeslist-separator"></span>{{/ charDifference }}{{!
+                       }}<span class="changedby">{{{ users }}}</span>{{!
+                       }}{{ numberofWatchingusers }}{{!
+               }}</td>
        </tr>
        {{# lines }}
        <tr class="mw-rcfilters-ui-highlights-enhanced-nested {{# classes }}{{ . }} {{/ classes }}"{{{ attribs }}}>
                                <div class="mw-rcfilters-ui-highlights-color-c5" data-color="c5"></div>
                        </div>
                </td>
-               <td class="mw-enhanced-rc-nested" data-target-page="{{ targetTitle }}">
-                       {{# timestampLink }}
-                       <span class="mw-enhanced-rc-time">{{{ . }}}</span>
-                       {{/ timestampLink }}
-                       {{# data }}{{{ . }}}{{/ data }}
-               </td>
+               <td class="mw-enhanced-rc-nested" data-target-page="{{ targetTitle }}">{{!
+                       }}{{# timestampLink }}{{!
+                       }}<span class="mw-enhanced-rc-time">{{{ . }}}</span>{{!
+                       }}{{/ timestampLink }}{{!
+                       }}{{# data }}{{{ . }}}{{/ data }}{{!
+               }}</td>
        </tr>
        {{/ lines }}
 </table>
index 4e93382..abc98ba 100644 (file)
@@ -40,10 +40,10 @@ class RemexCompatFormatter extends HtmlFormatter {
 
                $name = $node->name;
                $attrs = $node->attrs;
-               if ( isset( self::$markedEmptyElements[$name] ) && $attrs->count() === 0 ) {
-                       if ( strspn( $contents, "\t\n\f\r " ) === strlen( $contents ) ) {
-                               return "<{$name} class=\"mw-empty-elt\">$contents</{$name}>";
-                       }
+               if ( isset( self::$markedEmptyElements[$name] ) && $attrs->count() === 0
+                       && strspn( $contents, "\t\n\f\r " ) === strlen( $contents )
+               ) {
+                       return "<{$name} class=\"mw-empty-elt\">$contents</{$name}>";
                }
 
                $s = "<$name";
index df9bb96..0cc9905 100644 (file)
@@ -287,7 +287,6 @@ class RemexCompatMunger implements TreeHandler {
                        $newParent = $this->serializer->getParentNode( $parent );
                        $parent = $newParent;
                        $parentData = $parent->snData;
-                       $pElement = $parentData->childPElement;
                        $parentData->childPElement = null;
                        $newRef = $refElement->userData;
                } elseif ( $under && $parentData->isSplittable
index e06bfb5..5021a1c 100644 (file)
@@ -56,20 +56,35 @@ class MediaWikiTitleCodec implements TitleFormatter, TitleParser {
         */
        protected $interwikiLookup;
 
+       /**
+        * @var NamespaceInfo
+        */
+       protected $nsInfo;
+
        /**
         * @param Language $language The language object to use for localizing namespace names.
         * @param GenderCache $genderCache The gender cache for generating gendered namespace names
         * @param string[]|string $localInterwikis
         * @param InterwikiLookup|null $interwikiLookup
+        * @param NamespaceInfo|null $nsInfo
         */
        public function __construct( Language $language, GenderCache $genderCache,
-               $localInterwikis = [], $interwikiLookup = null
+               $localInterwikis = [], InterwikiLookup $interwikiLookup = null,
+               NamespaceInfo $nsInfo = null
        ) {
+               if ( !$interwikiLookup ) {
+                       wfDeprecated( __METHOD__ . ' with no InterwikiLookup argument', '1.34' );
+                       $interwikiLookup = MediaWikiServices::getInstance()->getInterwikiLookup();
+               }
+               if ( !$nsInfo ) {
+                       wfDeprecated( __METHOD__ . ' with no NamespaceInfo argument', '1.34' );
+                       $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
+               }
                $this->language = $language;
                $this->genderCache = $genderCache;
                $this->localInterwikis = (array)$localInterwikis;
-               $this->interwikiLookup = $interwikiLookup ?:
-                       MediaWikiServices::getInstance()->getInterwikiLookup();
+               $this->interwikiLookup = $interwikiLookup;
+               $this->nsInfo = $nsInfo;
        }
 
        /**
@@ -83,7 +98,7 @@ class MediaWikiTitleCodec implements TitleFormatter, TitleParser {
         */
        public function getNamespaceName( $namespace, $text ) {
                if ( $this->language->needsGenderDistinction() &&
-                       MWNamespace::hasGenderDistinction( $namespace )
+                       $this->nsInfo->hasGenderDistinction( $namespace )
                ) {
                        // NOTE: we are assuming here that the title text is a user name!
                        $gender = $this->genderCache->getGenderOf( $text, __METHOD__ );
@@ -139,8 +154,7 @@ class MediaWikiTitleCodec implements TitleFormatter, TitleParser {
        }
 
        /**
-        * Parses the given text and constructs a TitleValue. Normalization
-        * is applied according to the rules appropriate for the form specified by $form.
+        * Parses the given text and constructs a TitleValue.
         *
         * @param string $text The text to parse
         * @param int $defaultNamespace Namespace to assume per default (usually NS_MAIN)
@@ -149,13 +163,17 @@ class MediaWikiTitleCodec implements TitleFormatter, TitleParser {
         * @return TitleValue
         */
        public function parseTitle( $text, $defaultNamespace = NS_MAIN ) {
+               // Convert things like &eacute; &#257; or &#x3017; into normalized (T16952) text
+               $filteredText = Sanitizer::decodeCharReferencesAndNormalize( $text );
+
                // NOTE: this is an ugly cludge that allows this class to share the
                // code for parsing with the old Title class. The parser code should
                // be refactored to avoid this.
-               $parts = $this->splitTitleString( $text, $defaultNamespace );
+               $parts = $this->splitTitleString( $filteredText, $defaultNamespace );
 
-               // Relative fragment links are not supported by TitleValue
-               if ( $parts['dbkey'] === '' ) {
+               // Fragment-only is okay, but only with no namespace
+               if ( $parts['dbkey'] === '' &&
+               ( $parts['fragment'] === '' || $parts['namespace'] !== NS_MAIN ) ) {
                        throw new MalformedTitleException( 'title-invalid-empty', $text );
                }
 
@@ -265,7 +283,7 @@ class MediaWikiTitleCodec implements TitleFormatter, TitleParser {
                # Strip Unicode bidi override characters.
                # Sometimes they slip into cut-n-pasted page titles, where the
                # override chars get included in list displays.
-               $dbkey = preg_replace( '/\xE2\x80[\x8E\x8F\xAA-\xAE]/S', '', $dbkey );
+               $dbkey = preg_replace( '/[\x{200E}\x{200F}\x{202A}-\x{202E}]+/u', '', $dbkey );
 
                # Clean up whitespace
                # Note: use of the /u option on preg_replace here will cause
@@ -421,10 +439,8 @@ class MediaWikiTitleCodec implements TitleFormatter, TitleParser {
 
                # Can't make a link to a namespace alone... "empty" local links can only be
                # self-links with a fragment identifier.
-               if ( $dbkey == '' && $parts['interwiki'] === '' ) {
-                       if ( $parts['namespace'] != NS_MAIN ) {
-                               throw new MalformedTitleException( 'title-invalid-empty', $text );
-                       }
+               if ( $dbkey == '' && $parts['interwiki'] === '' && $parts['namespace'] != NS_MAIN ) {
+                       throw new MalformedTitleException( 'title-invalid-empty', $text );
                }
 
                // Allow IPv6 usernames to start with '::' by canonicalizing IPv6 titles.
index 4da9395..1a6ba72 100644 (file)
@@ -46,7 +46,10 @@ class NaiveImportTitleFactory implements ImportTitleFactory {
 
                        // For built-in namespaces (0 <= ID < 100), we try to find a local NS with
                        // the same namespace ID
-                       if ( $foreignNs < 100 && MWNamespace::exists( $foreignNs ) ) {
+                       if (
+                               $foreignNs < 100 &&
+                               MediaWikiServices::getInstance()->getNamespaceInfo()->exists( $foreignNs )
+                       ) {
                                return Title::makeTitleSafe( $foreignNs, $foreignTitle->getText() );
                        }
                }
index 7c756aa..7a44d0a 100644 (file)
@@ -18,6 +18,8 @@
  * @file
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * A class to convert page titles on a foreign wiki (ForeignTitle objects) into
  * page titles on the local wiki (Title objects), placing all pages in a fixed
@@ -31,7 +33,7 @@ class NamespaceImportTitleFactory implements ImportTitleFactory {
         * @param int $ns The namespace to use for all pages
         */
        public function __construct( $ns ) {
-               if ( !MWNamespace::exists( $ns ) ) {
+               if ( !MediaWikiServices::getInstance()->getNamespaceInfo()->exists( $ns ) ) {
                        throw new MWException( "Namespace $ns doesn't exist on this wiki" );
                }
                $this->ns = $ns;
diff --git a/includes/title/NamespaceInfo.php b/includes/title/NamespaceInfo.php
new file mode 100644 (file)
index 0000000..cdb8f25
--- /dev/null
@@ -0,0 +1,598 @@
+<?php
+/**
+ * Provide things related to namespaces.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+use MediaWiki\Config\ServiceOptions;
+use MediaWiki\Linker\LinkTarget;
+
+/**
+ * This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of
+ * them based on index.  The textual names of the namespaces are handled by Language.php.
+ *
+ * @since 1.34
+ */
+class NamespaceInfo {
+
+       /**
+        * These namespaces should always be first-letter capitalized, now and
+        * forevermore. Historically, they could've probably been lowercased too,
+        * but some things are just too ingrained now. :)
+        */
+       private $alwaysCapitalizedNamespaces = [ NS_SPECIAL, NS_USER, NS_MEDIAWIKI ];
+
+       /** @var string[]|null Canonical namespaces cache */
+       private $canonicalNamespaces = null;
+
+       /** @var array|false Canonical namespaces index cache */
+       private $namespaceIndexes = false;
+
+       /** @var int[]|null Valid namespaces cache */
+       private $validNamespaces = null;
+
+       /** @var ServiceOptions */
+       private $options;
+
+       /**
+        * TODO Make this const when HHVM support is dropped (T192166)
+        *
+        * @since 1.34
+        * @var array
+        */
+       public static $constructorOptions = [
+               'AllowImageMoving',
+               'CanonicalNamespaceNames',
+               'CapitalLinkOverrides',
+               'CapitalLinks',
+               'ContentNamespaces',
+               'ExtraNamespaces',
+               'ExtraSignatureNamespaces',
+               'NamespaceContentModels',
+               'NamespaceProtection',
+               'NamespacesWithSubpages',
+               'NonincludableNamespaces',
+               'RestrictionLevels',
+       ];
+
+       /**
+        * @param ServiceOptions $options
+        */
+       public function __construct( ServiceOptions $options ) {
+               $options->assertRequiredOptions( self::$constructorOptions );
+               $this->options = $options;
+       }
+
+       /**
+        * Throw an exception when trying to get the subject or talk page
+        * for a given namespace where it does not make sense.
+        * Special namespaces are defined in includes/Defines.php and have
+        * a value below 0 (ex: NS_SPECIAL = -1 , NS_MEDIA = -2)
+        *
+        * @param int $index
+        * @param string $method
+        *
+        * @throws MWException
+        * @return bool
+        */
+       private function isMethodValidFor( $index, $method ) {
+               if ( $index < NS_MAIN ) {
+                       throw new MWException( "$method does not make any sense for given namespace $index" );
+               }
+               return true;
+       }
+
+       /**
+        * Can pages in the given namespace be moved?
+        *
+        * @param int $index Namespace index
+        * @return bool
+        */
+       public function isMovable( $index ) {
+               $result = $index >= NS_MAIN &&
+                       ( $index != NS_FILE || $this->options->get( 'AllowImageMoving' ) );
+
+               /**
+                * @since 1.20
+                */
+               Hooks::run( 'NamespaceIsMovable', [ $index, &$result ] );
+
+               return $result;
+       }
+
+       /**
+        * Is the given namespace is a subject (non-talk) namespace?
+        *
+        * @param int $index Namespace index
+        * @return bool
+        */
+       public function isSubject( $index ) {
+               return !$this->isTalk( $index );
+       }
+
+       /**
+        * Is the given namespace a talk namespace?
+        *
+        * @param int $index Namespace index
+        * @return bool
+        */
+       public function isTalk( $index ) {
+               return $index > NS_MAIN
+                       && $index % 2;
+       }
+
+       /**
+        * Get the talk namespace index for a given namespace
+        *
+        * @param int $index Namespace index
+        * @return int
+        */
+       public function getTalk( $index ) {
+               $this->isMethodValidFor( $index, __METHOD__ );
+               return $this->isTalk( $index )
+                       ? $index
+                       : $index + 1;
+       }
+
+       /**
+        * @param LinkTarget $target
+        * @return LinkTarget Talk page for $target
+        * @throws MWException if $target's namespace doesn't have talk pages (e.g., NS_SPECIAL)
+        */
+       public function getTalkPage( LinkTarget $target ) : LinkTarget {
+               if ( $this->isTalk( $target->getNamespace() ) ) {
+                       return $target;
+               }
+               return new TitleValue( $this->getTalk( $target->getNamespace() ), $target->getDbKey() );
+       }
+
+       /**
+        * Get the subject namespace index for a given namespace
+        * Special namespaces (NS_MEDIA, NS_SPECIAL) are always the subject.
+        *
+        * @param int $index Namespace index
+        * @return int
+        */
+       public function getSubject( $index ) {
+               # Handle special namespaces
+               if ( $index < NS_MAIN ) {
+                       return $index;
+               }
+
+               return $this->isTalk( $index )
+                       ? $index - 1
+                       : $index;
+       }
+
+       /**
+        * @param LinkTarget $target
+        * @return LinkTarget Subject page for $target
+        */
+       public function getSubjectPage( LinkTarget $target ) : LinkTarget {
+               if ( $this->isSubject( $target->getNamespace() ) ) {
+                       return $target;
+               }
+               return new TitleValue( $this->getSubject( $target->getNamespace() ), $target->getDbKey() );
+       }
+
+       /**
+        * Get the associated namespace.
+        * For talk namespaces, returns the subject (non-talk) namespace
+        * For subject (non-talk) namespaces, returns the talk namespace
+        *
+        * @param int $index Namespace index
+        * @return int
+        * @throws MWException if called on a namespace that has no talk pages (e.g., NS_SPECIAL)
+        */
+       public function getAssociated( $index ) {
+               $this->isMethodValidFor( $index, __METHOD__ );
+
+               if ( $this->isSubject( $index ) ) {
+                       return $this->getTalk( $index );
+               }
+               return $this->getSubject( $index );
+       }
+
+       /**
+        * @param LinkTarget $target
+        * @return LinkTarget Talk page for $target if it's a subject page, subject page if it's a talk
+        *   page
+        * @throws MWException if $target's namespace doesn't have talk pages (e.g., NS_SPECIAL)
+        */
+       public function getAssociatedPage( LinkTarget $target ) : LinkTarget {
+               return new TitleValue(
+                       $this->getAssociated( $target->getNamespace() ), $target->getDbKey() );
+       }
+
+       /**
+        * Returns whether the specified namespace exists
+        *
+        * @param int $index
+        *
+        * @return bool
+        */
+       public function exists( $index ) {
+               $nslist = $this->getCanonicalNamespaces();
+               return isset( $nslist[$index] );
+       }
+
+       /**
+        * Returns whether the specified namespaces are the same namespace
+        *
+        * @note It's possible that in the future we may start using something
+        * other than just namespace indexes. Under that circumstance making use
+        * of this function rather than directly doing comparison will make
+        * sure that code will not potentially break.
+        *
+        * @param int $ns1 The first namespace index
+        * @param int $ns2 The second namespace index
+        *
+        * @return bool
+        */
+       public function equals( $ns1, $ns2 ) {
+               return $ns1 == $ns2;
+       }
+
+       /**
+        * Returns whether the specified namespaces share the same subject.
+        * eg: NS_USER and NS_USER wil return true, as well
+        *     NS_USER and NS_USER_TALK will return true.
+        *
+        * @param int $ns1 The first namespace index
+        * @param int $ns2 The second namespace index
+        *
+        * @return bool
+        */
+       public function subjectEquals( $ns1, $ns2 ) {
+               return $this->getSubject( $ns1 ) == $this->getSubject( $ns2 );
+       }
+
+       /**
+        * Returns array of all defined namespaces with their canonical
+        * (English) names.
+        *
+        * @return array
+        */
+       public function getCanonicalNamespaces() {
+               if ( $this->canonicalNamespaces === null ) {
+                       $this->canonicalNamespaces =
+                               [ NS_MAIN => '' ] + $this->options->get( 'CanonicalNamespaceNames' );
+                       $this->canonicalNamespaces +=
+                               ExtensionRegistry::getInstance()->getAttribute( 'ExtensionNamespaces' );
+                       if ( is_array( $this->options->get( 'ExtraNamespaces' ) ) ) {
+                               $this->canonicalNamespaces += $this->options->get( 'ExtraNamespaces' );
+                       }
+                       Hooks::run( 'CanonicalNamespaces', [ &$this->canonicalNamespaces ] );
+               }
+               return $this->canonicalNamespaces;
+       }
+
+       /**
+        * Returns the canonical (English) name for a given index
+        *
+        * @param int $index Namespace index
+        * @return string|bool If no canonical definition.
+        */
+       public function getCanonicalName( $index ) {
+               $nslist = $this->getCanonicalNamespaces();
+               return $nslist[$index] ?? false;
+       }
+
+       /**
+        * Returns the index for a given canonical name, or NULL
+        * The input *must* be converted to lower case first
+        *
+        * @param string $name Namespace name
+        * @return int|null
+        */
+       public function getCanonicalIndex( $name ) {
+               if ( $this->namespaceIndexes === false ) {
+                       $this->namespaceIndexes = [];
+                       foreach ( $this->getCanonicalNamespaces() as $i => $text ) {
+                               $this->namespaceIndexes[strtolower( $text )] = $i;
+                       }
+               }
+               if ( array_key_exists( $name, $this->namespaceIndexes ) ) {
+                       return $this->namespaceIndexes[$name];
+               } else {
+                       return null;
+               }
+       }
+
+       /**
+        * Returns an array of the namespaces (by integer id) that exist on the wiki. Used primarily by
+        * the API in help documentation. The array is sorted numerically and omits negative namespaces.
+        * @return array
+        */
+       public function getValidNamespaces() {
+               if ( is_null( $this->validNamespaces ) ) {
+                       foreach ( array_keys( $this->getCanonicalNamespaces() ) as $ns ) {
+                               if ( $ns >= 0 ) {
+                                       $this->validNamespaces[] = $ns;
+                               }
+                       }
+                       // T109137: sort numerically
+                       sort( $this->validNamespaces, SORT_NUMERIC );
+               }
+
+               return $this->validNamespaces;
+       }
+
+       /*
+
+       /**
+        * Does this namespace ever have a talk namespace?
+        *
+        * @param int $index Namespace ID
+        * @return bool True if this namespace either is or has a corresponding talk namespace.
+        */
+       public function hasTalkNamespace( $index ) {
+               return $index >= NS_MAIN;
+       }
+
+       /**
+        * Does this namespace contain content, for the purposes of calculating
+        * statistics, etc?
+        *
+        * @param int $index Index to check
+        * @return bool
+        */
+       public function isContent( $index ) {
+               return $index == NS_MAIN || in_array( $index, $this->options->get( 'ContentNamespaces' ) );
+       }
+
+       /**
+        * Might pages in this namespace require the use of the Signature button on
+        * the edit toolbar?
+        *
+        * @param int $index Index to check
+        * @return bool
+        */
+       public function wantSignatures( $index ) {
+               return $this->isTalk( $index ) ||
+                       in_array( $index, $this->options->get( 'ExtraSignatureNamespaces' ) );
+       }
+
+       /**
+        * Can pages in a namespace be watched?
+        *
+        * @param int $index
+        * @return bool
+        */
+       public function isWatchable( $index ) {
+               return $index >= NS_MAIN;
+       }
+
+       /**
+        * Does the namespace allow subpages?
+        *
+        * @param int $index Index to check
+        * @return bool
+        */
+       public function hasSubpages( $index ) {
+               return !empty( $this->options->get( 'NamespacesWithSubpages' )[$index] );
+       }
+
+       /**
+        * Get a list of all namespace indices which are considered to contain content
+        * @return array Array of namespace indices
+        */
+       public function getContentNamespaces() {
+               $contentNamespaces = $this->options->get( 'ContentNamespaces' );
+               if ( !is_array( $contentNamespaces ) || $contentNamespaces === [] ) {
+                       return [ NS_MAIN ];
+               } elseif ( !in_array( NS_MAIN, $contentNamespaces ) ) {
+                       // always force NS_MAIN to be part of array (to match the algorithm used by isContent)
+                       return array_merge( [ NS_MAIN ], $contentNamespaces );
+               } else {
+                       return $contentNamespaces;
+               }
+       }
+
+       /**
+        * List all namespace indices which are considered subject, aka not a talk
+        * or special namespace. See also NamespaceInfo::isSubject
+        *
+        * @return array Array of namespace indices
+        */
+       public function getSubjectNamespaces() {
+               return array_filter(
+                       $this->getValidNamespaces(),
+                       [ $this, 'isSubject' ]
+               );
+       }
+
+       /**
+        * List all namespace indices which are considered talks, aka not a subject
+        * or special namespace. See also NamespaceInfo::isTalk
+        *
+        * @return array Array of namespace indices
+        */
+       public function getTalkNamespaces() {
+               return array_filter(
+                       $this->getValidNamespaces(),
+                       [ $this, 'isTalk' ]
+               );
+       }
+
+       /**
+        * Is the namespace first-letter capitalized?
+        *
+        * @param int $index Index to check
+        * @return bool
+        */
+       public function isCapitalized( $index ) {
+               // Turn NS_MEDIA into NS_FILE
+               $index = $index === NS_MEDIA ? NS_FILE : $index;
+
+               // Make sure to get the subject of our namespace
+               $index = $this->getSubject( $index );
+
+               // Some namespaces are special and should always be upper case
+               if ( in_array( $index, $this->alwaysCapitalizedNamespaces ) ) {
+                       return true;
+               }
+               $overrides = $this->options->get( 'CapitalLinkOverrides' );
+               if ( isset( $overrides[$index] ) ) {
+                       // CapitalLinkOverrides is explicitly set
+                       return $overrides[$index];
+               }
+               // Default to the global setting
+               return $this->options->get( 'CapitalLinks' );
+       }
+
+       /**
+        * Does the namespace (potentially) have different aliases for different
+        * genders. Not all languages make a distinction here.
+        *
+        * @param int $index Index to check
+        * @return bool
+        */
+       public function hasGenderDistinction( $index ) {
+               return $index == NS_USER || $index == NS_USER_TALK;
+       }
+
+       /**
+        * It is not possible to use pages from this namespace as template?
+        *
+        * @param int $index Index to check
+        * @return bool
+        */
+       public function isNonincludable( $index ) {
+               $namespaces = $this->options->get( 'NonincludableNamespaces' );
+               return $namespaces && in_array( $index, $namespaces );
+       }
+
+       /**
+        * Get the default content model for a namespace
+        * This does not mean that all pages in that namespace have the model
+        *
+        * @note To determine the default model for a new page's main slot, or any slot in general,
+        * use SlotRoleHandler::getDefaultModel() together with SlotRoleRegistry::getRoleHandler().
+        *
+        * @param int $index Index to check
+        * @return null|string Default model name for the given namespace, if set
+        */
+       public function getNamespaceContentModel( $index ) {
+               return $this->options->get( 'NamespaceContentModels' )[$index] ?? null;
+       }
+
+       /**
+        * Determine which restriction levels it makes sense to use in a namespace,
+        * optionally filtered by a user's rights.
+        *
+        * @todo Move this to PermissionManager and remove the dependency here on permissions-related
+        * config settings.
+        *
+        * @param int $index Index to check
+        * @param User|null $user User to check
+        * @return array
+        */
+       public function getRestrictionLevels( $index, User $user = null ) {
+               if ( !isset( $this->options->get( 'NamespaceProtection' )[$index] ) ) {
+                       // All levels are valid if there's no namespace restriction.
+                       // But still filter by user, if necessary
+                       $levels = $this->options->get( 'RestrictionLevels' );
+                       if ( $user ) {
+                               $levels = array_values( array_filter( $levels, function ( $level ) use ( $user ) {
+                                       $right = $level;
+                                       if ( $right == 'sysop' ) {
+                                               $right = 'editprotected'; // BC
+                                       }
+                                       if ( $right == 'autoconfirmed' ) {
+                                               $right = 'editsemiprotected'; // BC
+                                       }
+                                       return ( $right == '' || $user->isAllowed( $right ) );
+                               } ) );
+                       }
+                       return $levels;
+               }
+
+               // $wgNamespaceProtection can require one or more rights to edit the namespace, which
+               // may be satisfied by membership in multiple groups each giving a subset of those rights.
+               // A restriction level is redundant if, for any one of the namespace rights, all groups
+               // giving that right also give the restriction level's right. Or, conversely, a
+               // restriction level is not redundant if, for every namespace right, there's at least one
+               // group giving that right without the restriction level's right.
+               //
+               // First, for each right, get a list of groups with that right.
+               $namespaceRightGroups = [];
+               foreach ( (array)$this->options->get( 'NamespaceProtection' )[$index] as $right ) {
+                       if ( $right == 'sysop' ) {
+                               $right = 'editprotected'; // BC
+                       }
+                       if ( $right == 'autoconfirmed' ) {
+                               $right = 'editsemiprotected'; // BC
+                       }
+                       if ( $right != '' ) {
+                               $namespaceRightGroups[$right] = User::getGroupsWithPermission( $right );
+                       }
+               }
+
+               // Now, go through the protection levels one by one.
+               $usableLevels = [ '' ];
+               foreach ( $this->options->get( 'RestrictionLevels' ) as $level ) {
+                       $right = $level;
+                       if ( $right == 'sysop' ) {
+                               $right = 'editprotected'; // BC
+                       }
+                       if ( $right == 'autoconfirmed' ) {
+                               $right = 'editsemiprotected'; // BC
+                       }
+
+                       if ( $right != '' &&
+                               !isset( $namespaceRightGroups[$right] ) &&
+                               ( !$user || $user->isAllowed( $right ) )
+                       ) {
+                               // Do any of the namespace rights imply the restriction right? (see explanation above)
+                               foreach ( $namespaceRightGroups as $groups ) {
+                                       if ( !array_diff( $groups, User::getGroupsWithPermission( $right ) ) ) {
+                                               // Yes, this one does.
+                                               continue 2;
+                                       }
+                               }
+                               // No, keep the restriction level
+                               $usableLevels[] = $level;
+                       }
+               }
+
+               return $usableLevels;
+       }
+
+       /**
+        * Returns the link type to be used for categories.
+        *
+        * This determines which section of a category page titles
+        * in the namespace will appear within.
+        *
+        * @param int $index Namespace index
+        * @return string One of 'subcat', 'file', 'page'
+        */
+       public function getCategoryLinkType( $index ) {
+               $this->isMethodValidFor( $index, __METHOD__ );
+
+               if ( $index == NS_CATEGORY ) {
+                       return 'subcat';
+               } elseif ( $index == NS_FILE ) {
+                       return 'file';
+               } else {
+                       return 'page';
+               }
+       }
+}
index 4244350..415196a 100644 (file)
@@ -18,6 +18,8 @@
  * @file
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * A class to convert page titles on a foreign wiki (ForeignTitle objects) into
  * page titles on the local wiki (Title objects), placing all pages as subpages
@@ -32,7 +34,10 @@ class SubpageImportTitleFactory implements ImportTitleFactory {
         * created
         */
        public function __construct( Title $rootPage ) {
-               if ( !MWNamespace::hasSubpages( $rootPage->getNamespace() ) ) {
+               if (
+                       !MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               hasSubpages( $rootPage->getNamespace() )
+               ) {
                        throw new MWException( "The root page you specified, $rootPage, is in a " .
                                "namespace where subpages are not allowed" );
                }
index ddffed6..8569735 100644 (file)
@@ -32,8 +32,7 @@
  */
 interface TitleParser {
        /**
-        * Parses the given text and constructs a TitleValue. Normalization
-        * is applied according to the rules appropriate for the form specified by $form.
+        * Parses the given text and constructs a TitleValue.
         *
         * @note this only parses local page links, interwiki-prefixes etc. are not considered!
         *
index 698bc4f..722e5ef 100644 (file)
@@ -103,7 +103,8 @@ class TitleValue implements LinkTarget {
                // Sanity check, no full validation or normalization applied here!
                Assert::parameter( !preg_match( '/^_|[ \r\n\t]|_$/', $dbkey ), '$dbkey',
                        "invalid DB key '$dbkey'" );
-               Assert::parameter( $dbkey !== '', '$dbkey', 'should not be empty' );
+               Assert::parameter( $dbkey !== '' || ( $fragment !== '' && $namespace === NS_MAIN ),
+                       '$dbkey', 'should not be empty unless namespace is main and fragment is non-empty' );
 
                $this->namespace = $namespace;
                $this->dbkey = $dbkey;
index c42584c..2bbe7c3 100644 (file)
@@ -21,6 +21,7 @@
  * @ingroup Upload
  */
 use MediaWiki\MediaWikiServices;
+use MediaWiki\Shell\Shell;
 
 /**
  * @defgroup Upload Upload related
@@ -947,8 +948,8 @@ abstract class UploadBase {
                 */
                list( $partname, $ext ) = $this->splitExtensions( $this->mFilteredName );
 
-               if ( count( $ext ) ) {
-                       $this->mFinalExtension = trim( $ext[count( $ext ) - 1] );
+               if ( $ext !== [] ) {
+                       $this->mFinalExtension = trim( end( $ext ) );
                } else {
                        $this->mFinalExtension = '';
 
@@ -1078,10 +1079,8 @@ abstract class UploadBase {
                $props = $this->mFileProps;
                $error = null;
                Hooks::run( 'UploadStashFile', [ $this, $user, $props, &$error ] );
-               if ( $error ) {
-                       if ( !is_array( $error ) ) {
-                               $error = [ $error ];
-                       }
+               if ( $error && !is_array( $error ) ) {
+                       $error = [ $error ];
                }
                return $error;
        }
@@ -1865,10 +1864,10 @@ abstract class UploadBase {
 
                if ( strpos( $command, "%f" ) === false ) {
                        # simple pattern: append file to scan
-                       $command .= " " . wfEscapeShellArg( $file );
+                       $command .= " " . Shell::escape( $file );
                } else {
                        # complex pattern: replace "%f" with file to scan
-                       $command = str_replace( "%f", wfEscapeShellArg( $file ), $command );
+                       $command = str_replace( "%f", Shell::escape( $file ), $command );
                }
 
                wfDebug( __METHOD__ . ": running virus scan: $command \n" );
@@ -1916,10 +1915,8 @@ abstract class UploadBase {
                                $output = true; # if there's no output, return true
                        } elseif ( $msgPattern ) {
                                $groups = [];
-                               if ( preg_match( $msgPattern, $output, $groups ) ) {
-                                       if ( $groups[1] ) {
-                                               $output = $groups[1];
-                                       }
+                               if ( preg_match( $msgPattern, $output, $groups ) && $groups[1] ) {
+                                       $output = $groups[1];
                                }
                        }
 
index aa31a5b..d39975d 100644 (file)
@@ -89,12 +89,8 @@ class UploadStash {
 
                // if a user was passed, use it. otherwise, attempt to use the global.
                // this keeps FileRepo from breaking when it creates an UploadStash object
-               if ( $user ) {
-                       $this->user = $user;
-               } else {
-                       global $wgUser;
-                       $this->user = $wgUser;
-               }
+               global $wgUser;
+               $this->user = $user ?: $wgUser;
 
                if ( is_object( $this->user ) ) {
                        $this->userId = $this->user->getId();
@@ -162,12 +158,10 @@ class UploadStash {
                        );
                }
 
-               if ( !$noAuth ) {
-                       if ( $this->fileMetadata[$key]['us_user'] != $this->userId ) {
-                               throw new UploadStashWrongOwnerException(
-                                       wfMessage( 'uploadstash-wrong-owner', $key )
-                               );
-                       }
+               if ( !$noAuth && $this->fileMetadata[$key]['us_user'] != $this->userId ) {
+                       throw new UploadStashWrongOwnerException(
+                               wfMessage( 'uploadstash-wrong-owner', $key )
+                       );
                }
 
                return $this->files[$key];
@@ -574,195 +568,3 @@ class UploadStash {
                return true;
        }
 }
-
-/**
- * @ingroup Upload
- */
-class UploadStashFile extends UnregisteredLocalFile {
-       private $fileKey;
-       private $urlName;
-       protected $url;
-
-       /**
-        * A LocalFile wrapper around a file that has been temporarily stashed,
-        * so we can do things like create thumbnails for it. Arguably
-        * UnregisteredLocalFile should be handling its own file repo but that
-        * class is a bit retarded currently.
-        *
-        * @param FileRepo $repo Repository where we should find the path
-        * @param string $path Path to file
-        * @param string $key Key to store the path and any stashed data under
-        * @throws UploadStashBadPathException
-        * @throws UploadStashFileNotFoundException
-        */
-       public function __construct( $repo, $path, $key ) {
-               $this->fileKey = $key;
-
-               // resolve mwrepo:// urls
-               if ( FileRepo::isVirtualUrl( $path ) ) {
-                       $path = $repo->resolveVirtualUrl( $path );
-               } else {
-                       // check if path appears to be sane, no parent traversals,
-                       // and is in this repo's temp zone.
-                       $repoTempPath = $repo->getZonePath( 'temp' );
-                       if ( ( !$repo->validateFilename( $path ) ) ||
-                               ( strpos( $path, $repoTempPath ) !== 0 )
-                       ) {
-                               wfDebug( "UploadStash: tried to construct an UploadStashFile "
-                                       . "from a file that should already exist at '$path', but path is not valid\n" );
-                               throw new UploadStashBadPathException(
-                                       wfMessage( 'uploadstash-bad-path-invalid' )
-                               );
-                       }
-
-                       // check if path exists! and is a plain file.
-                       if ( !$repo->fileExists( $path ) ) {
-                               wfDebug( "UploadStash: tried to construct an UploadStashFile from "
-                                       . "a file that should already exist at '$path', but path is not found\n" );
-                               throw new UploadStashFileNotFoundException(
-                                       wfMessage( 'uploadstash-file-not-found-not-exists' )
-                               );
-                       }
-               }
-
-               parent::__construct( false, $repo, $path, false );
-
-               $this->name = basename( $this->path );
-       }
-
-       /**
-        * A method needed by the file transforming and scaling routines in File.php
-        * We do not necessarily care about doing the description at this point
-        * However, we also can't return the empty string, as the rest of MediaWiki
-        * demands this (and calls to imagemagick convert require it to be there)
-        *
-        * @return string Dummy value
-        */
-       public function getDescriptionUrl() {
-               return $this->getUrl();
-       }
-
-       /**
-        * Get the path for the thumbnail (actually any transformation of this file)
-        * The actual argument is the result of thumbName although we seem to have
-        * buggy code elsewhere that expects a boolean 'suffix'
-        *
-        * @param string $thumbName Name of thumbnail (e.g. "120px-123456.jpg" ),
-        *   or false to just get the path
-        * @return string Path thumbnail should take on filesystem, or containing
-        *   directory if thumbname is false
-        */
-       public function getThumbPath( $thumbName = false ) {
-               $path = dirname( $this->path );
-               if ( $thumbName !== false ) {
-                       $path .= "/$thumbName";
-               }
-
-               return $path;
-       }
-
-       /**
-        * Return the file/url base name of a thumbnail with the specified parameters.
-        * We override this because we want to use the pretty url name instead of the
-        * ugly file name.
-        *
-        * @param array $params Handler-specific parameters
-        * @param int $flags Bitfield that supports THUMB_* constants
-        * @return string|null Base name for URL, like '120px-12345.jpg', or null if there is no handler
-        */
-       function thumbName( $params, $flags = 0 ) {
-               return $this->generateThumbName( $this->getUrlName(), $params );
-       }
-
-       /**
-        * Helper function -- given a 'subpage', return the local URL,
-        * e.g. /wiki/Special:UploadStash/subpage
-        * @param string $subPage
-        * @return string Local URL for this subpage in the Special:UploadStash space.
-        */
-       private function getSpecialUrl( $subPage ) {
-               return SpecialPage::getTitleFor( 'UploadStash', $subPage )->getLocalURL();
-       }
-
-       /**
-        * Get a URL to access the thumbnail
-        * This is required because the model of how files work requires that
-        * the thumbnail urls be predictable. However, in our model the URL is
-        * not based on the filename (that's hidden in the db)
-        *
-        * @param string $thumbName Basename of thumbnail file -- however, we don't
-        *   want to use the file exactly
-        * @return string URL to access thumbnail, or URL with partial path
-        */
-       public function getThumbUrl( $thumbName = false ) {
-               wfDebug( __METHOD__ . " getting for $thumbName \n" );
-
-               return $this->getSpecialUrl( 'thumb/' . $this->getUrlName() . '/' . $thumbName );
-       }
-
-       /**
-        * The basename for the URL, which we want to not be related to the filename.
-        * Will also be used as the lookup key for a thumbnail file.
-        *
-        * @return string Base url name, like '120px-123456.jpg'
-        */
-       public function getUrlName() {
-               if ( !$this->urlName ) {
-                       $this->urlName = $this->fileKey;
-               }
-
-               return $this->urlName;
-       }
-
-       /**
-        * Return the URL of the file, if for some reason we wanted to download it
-        * We tend not to do this for the original file, but we do want thumb icons
-        *
-        * @return string Url
-        */
-       public function getUrl() {
-               if ( !isset( $this->url ) ) {
-                       $this->url = $this->getSpecialUrl( 'file/' . $this->getUrlName() );
-               }
-
-               return $this->url;
-       }
-
-       /**
-        * Parent classes use this method, for no obvious reason, to return the path
-        * (relative to wiki root, I assume). But with this class, the URL is
-        * unrelated to the path.
-        *
-        * @return string Url
-        */
-       public function getFullUrl() {
-               return $this->getUrl();
-       }
-
-       /**
-        * Getter for file key (the unique id by which this file's location &
-        * metadata is stored in the db)
-        *
-        * @return string File key
-        */
-       public function getFileKey() {
-               return $this->fileKey;
-       }
-
-       /**
-        * Remove the associated temporary file
-        * @return status Success
-        */
-       public function remove() {
-               if ( !$this->repo->fileExists( $this->path ) ) {
-                       // Maybe the file's already been removed? This could totally happen in UploadBase.
-                       return true;
-               }
-
-               return $this->repo->freeTemp( $this->path );
-       }
-
-       public function exists() {
-               return $this->repo->fileExists( $this->path );
-       }
-}
diff --git a/includes/upload/UploadStashFile.php b/includes/upload/UploadStashFile.php
new file mode 100644 (file)
index 0000000..53edba5
--- /dev/null
@@ -0,0 +1,211 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * @ingroup Upload
+ */
+class UploadStashFile extends UnregisteredLocalFile {
+       private $fileKey;
+       private $urlName;
+       protected $url;
+
+       /**
+        * A LocalFile wrapper around a file that has been temporarily stashed,
+        * so we can do things like create thumbnails for it. Arguably
+        * UnregisteredLocalFile should be handling its own file repo but that
+        * class is a bit retarded currently.
+        *
+        * @param FileRepo $repo Repository where we should find the path
+        * @param string $path Path to file
+        * @param string $key Key to store the path and any stashed data under
+        * @throws UploadStashBadPathException
+        * @throws UploadStashFileNotFoundException
+        */
+       public function __construct( $repo, $path, $key ) {
+               $this->fileKey = $key;
+
+               // resolve mwrepo:// urls
+               if ( FileRepo::isVirtualUrl( $path ) ) {
+                       $path = $repo->resolveVirtualUrl( $path );
+               } else {
+                       // check if path appears to be sane, no parent traversals,
+                       // and is in this repo's temp zone.
+                       $repoTempPath = $repo->getZonePath( 'temp' );
+                       if ( ( !$repo->validateFilename( $path ) ) ||
+                               ( strpos( $path, $repoTempPath ) !== 0 )
+                       ) {
+                               wfDebug( "UploadStash: tried to construct an UploadStashFile "
+                                       . "from a file that should already exist at '$path', but path is not valid\n" );
+                               throw new UploadStashBadPathException(
+                                       wfMessage( 'uploadstash-bad-path-invalid' )
+                               );
+                       }
+
+                       // check if path exists! and is a plain file.
+                       if ( !$repo->fileExists( $path ) ) {
+                               wfDebug( "UploadStash: tried to construct an UploadStashFile from "
+                                       . "a file that should already exist at '$path', but path is not found\n" );
+                               throw new UploadStashFileNotFoundException(
+                                       wfMessage( 'uploadstash-file-not-found-not-exists' )
+                               );
+                       }
+               }
+
+               parent::__construct( false, $repo, $path, false );
+
+               $this->name = basename( $this->path );
+       }
+
+       /**
+        * A method needed by the file transforming and scaling routines in File.php
+        * We do not necessarily care about doing the description at this point
+        * However, we also can't return the empty string, as the rest of MediaWiki
+        * demands this (and calls to imagemagick convert require it to be there)
+        *
+        * @return string Dummy value
+        */
+       public function getDescriptionUrl() {
+               return $this->getUrl();
+       }
+
+       /**
+        * Get the path for the thumbnail (actually any transformation of this file)
+        * The actual argument is the result of thumbName although we seem to have
+        * buggy code elsewhere that expects a boolean 'suffix'
+        *
+        * @param string $thumbName Name of thumbnail (e.g. "120px-123456.jpg" ),
+        *   or false to just get the path
+        * @return string Path thumbnail should take on filesystem, or containing
+        *   directory if thumbname is false
+        */
+       public function getThumbPath( $thumbName = false ) {
+               $path = dirname( $this->path );
+               if ( $thumbName !== false ) {
+                       $path .= "/$thumbName";
+               }
+
+               return $path;
+       }
+
+       /**
+        * Return the file/url base name of a thumbnail with the specified parameters.
+        * We override this because we want to use the pretty url name instead of the
+        * ugly file name.
+        *
+        * @param array $params Handler-specific parameters
+        * @param int $flags Bitfield that supports THUMB_* constants
+        * @return string|null Base name for URL, like '120px-12345.jpg', or null if there is no handler
+        */
+       function thumbName( $params, $flags = 0 ) {
+               return $this->generateThumbName( $this->getUrlName(), $params );
+       }
+
+       /**
+        * Helper function -- given a 'subpage', return the local URL,
+        * e.g. /wiki/Special:UploadStash/subpage
+        * @param string $subPage
+        * @return string Local URL for this subpage in the Special:UploadStash space.
+        */
+       private function getSpecialUrl( $subPage ) {
+               return SpecialPage::getTitleFor( 'UploadStash', $subPage )->getLocalURL();
+       }
+
+       /**
+        * Get a URL to access the thumbnail
+        * This is required because the model of how files work requires that
+        * the thumbnail urls be predictable. However, in our model the URL is
+        * not based on the filename (that's hidden in the db)
+        *
+        * @param string $thumbName Basename of thumbnail file -- however, we don't
+        *   want to use the file exactly
+        * @return string URL to access thumbnail, or URL with partial path
+        */
+       public function getThumbUrl( $thumbName = false ) {
+               wfDebug( __METHOD__ . " getting for $thumbName \n" );
+
+               return $this->getSpecialUrl( 'thumb/' . $this->getUrlName() . '/' . $thumbName );
+       }
+
+       /**
+        * The basename for the URL, which we want to not be related to the filename.
+        * Will also be used as the lookup key for a thumbnail file.
+        *
+        * @return string Base url name, like '120px-123456.jpg'
+        */
+       public function getUrlName() {
+               if ( !$this->urlName ) {
+                       $this->urlName = $this->fileKey;
+               }
+
+               return $this->urlName;
+       }
+
+       /**
+        * Return the URL of the file, if for some reason we wanted to download it
+        * We tend not to do this for the original file, but we do want thumb icons
+        *
+        * @return string Url
+        */
+       public function getUrl() {
+               if ( !isset( $this->url ) ) {
+                       $this->url = $this->getSpecialUrl( 'file/' . $this->getUrlName() );
+               }
+
+               return $this->url;
+       }
+
+       /**
+        * Parent classes use this method, for no obvious reason, to return the path
+        * (relative to wiki root, I assume). But with this class, the URL is
+        * unrelated to the path.
+        *
+        * @return string Url
+        */
+       public function getFullUrl() {
+               return $this->getUrl();
+       }
+
+       /**
+        * Getter for file key (the unique id by which this file's location &
+        * metadata is stored in the db)
+        *
+        * @return string File key
+        */
+       public function getFileKey() {
+               return $this->fileKey;
+       }
+
+       /**
+        * Remove the associated temporary file
+        * @return bool Success
+        */
+       public function remove() {
+               if ( !$this->repo->fileExists( $this->path ) ) {
+                       // Maybe the file's already been removed? This could totally happen in UploadBase.
+                       return true;
+               }
+
+               return $this->repo->freeTemp( $this->path );
+       }
+
+       public function exists() {
+               return $this->repo->fileExists( $this->path );
+       }
+}
index cee8c03..d7733ab 100644 (file)
@@ -23,6 +23,7 @@
 
 class UploadChunkVerificationException extends MWException {
        public $msg;
+
        public function __construct( array $res ) {
                $this->msg = wfMessage( ...$res );
                parent::__construct( wfMessage( ...$res )
index 66674dc..41facc7 100644 (file)
@@ -64,9 +64,11 @@ class ExternalUserNames {
                if ( $pos !== false ) {
                        $iw = explode( ':', substr( $userName, 0, $pos ) );
                        $firstIw = array_shift( $iw );
-                       $interwikiLookup = MediaWikiServices::getInstance()->getInterwikiLookup();
+                       $services = MediaWikiServices::getInstance();
+                       $interwikiLookup = $services->getInterwikiLookup();
                        if ( $interwikiLookup->isValidInterwiki( $firstIw ) ) {
-                               $title = MWNamespace::getCanonicalName( NS_USER ) . ':' . substr( $userName, $pos + 1 );
+                               $title = $services->getNamespaceInfo()->getCanonicalName( NS_USER ) .
+                                       ':' . substr( $userName, $pos + 1 );
                                if ( $iw ) {
                                        $title = implode( ':', $iw ) . ':' . $title;
                                }
index ef104cc..aada319 100644 (file)
@@ -81,9 +81,7 @@ class PasswordReset implements LoggerAwareInterface {
                        $resetRoutes = $this->config->get( 'PasswordResetRoutes' );
                        $status = StatusValue::newGood();
 
-                       if ( !is_array( $resetRoutes ) ||
-                                !in_array( true, array_values( $resetRoutes ), true )
-                       ) {
+                       if ( !is_array( $resetRoutes ) || !in_array( true, $resetRoutes, true ) ) {
                                // Maybe password resets are disabled, or there are no allowable routes
                                $status = StatusValue::newFatal( 'passwordreset-disabled' );
                        } elseif (
@@ -265,23 +263,7 @@ class PasswordReset implements LoggerAwareInterface {
                if ( !$block ) {
                        return false;
                }
-               $type = $block->getSystemBlockType();
-               if ( in_array( $type, [ null, 'global-block' ], true ) ) {
-                       // Normal block. Maybe it was meant for someone else and the user just needs to log in;
-                       // or maybe it was issued specifically to prevent some IP from messing with password
-                       // reset? Go out on a limb and use the registration allowed flag to decide.
-                       return $block->isCreateAccountBlocked();
-               } elseif ( $type === 'proxy' ) {
-                       // we disallow actions through proxy even if the user is logged in
-                       // so it makes sense to disallow password resets as well
-                       return true;
-               } elseif ( in_array( $type, [ 'dnsbl', 'wgSoftBlockRanges' ], true ) ) {
-                       // these are just meant to force login so let's not prevent that
-                       return false;
-               } else {
-                       // some extension - we'll have to guess
-                       return true;
-               }
+               return $block->appliesToPasswordReset();
        }
 
        /**
index 786f288..18d62f5 100644 (file)
@@ -20,6 +20,8 @@
  * @file
  */
 
+use MediaWiki\Block\AbstractBlock;
+use MediaWiki\Block\SystemBlock;
 use MediaWiki\MediaWikiServices;
 use MediaWiki\Session\SessionManager;
 use MediaWiki\Session\Token;
@@ -28,6 +30,7 @@ use MediaWiki\Auth\AuthenticationResponse;
 use MediaWiki\Auth\AuthenticationRequest;
 use MediaWiki\User\UserIdentity;
 use MediaWiki\Logger\LoggerFactory;
+use Wikimedia\Assert\Assert;
 use Wikimedia\IPSet;
 use Wikimedia\ScopedCallback;
 use Wikimedia\Rdbms\Database;
@@ -45,18 +48,20 @@ use Wikimedia\Rdbms\IDatabase;
  * of the database.
  */
 class User implements IDBAccessObject, UserIdentity {
+
        /**
-        * @const int Number of characters in user_token field.
+        * Number of characters required for the user_token field.
         */
        const TOKEN_LENGTH = 32;
 
        /**
-        * @const string An invalid value for user_token
+        * An invalid string value for the user_token field.
         */
        const INVALID_TOKEN = '*** INVALID ***';
 
        /**
-        * @const int Serialized record version.
+        * Version number to tag cached versions of serialized User objects. Should be increased when
+        * {@link $mCacheVars} or one of it's members changes.
         */
        const VERSION = 13;
 
@@ -275,7 +280,7 @@ class User implements IDBAccessObject, UserIdentity {
        protected $mImplicitGroups;
        /** @var array */
        protected $mFormerGroups;
-       /** @var Block */
+       /** @var AbstractBlock */
        protected $mGlobalBlock;
        /** @var bool */
        protected $mLocked;
@@ -287,13 +292,13 @@ class User implements IDBAccessObject, UserIdentity {
        /** @var WebRequest */
        private $mRequest;
 
-       /** @var Block */
+       /** @var AbstractBlock */
        public $mBlock;
 
        /** @var bool */
        protected $mAllowUsertalk;
 
-       /** @var Block */
+       /** @var AbstractBlock */
        private $mBlockedFromCreateAccount = false;
 
        /** @var int User::READ_* constant bitfield used to load data */
@@ -670,11 +675,20 @@ class User implements IDBAccessObject, UserIdentity {
         * @param int|null $userId User ID, if known
         * @param string|null $userName User name, if known
         * @param int|null $actorId Actor ID, if known
+        * @param bool|string $wikiId remote wiki to which the User/Actor ID applies, or false if none
         * @return User
         */
-       public static function newFromAnyId( $userId, $userName, $actorId ) {
+       public static function newFromAnyId( $userId, $userName, $actorId, $wikiId = false ) {
                global $wgActorTableSchemaMigrationStage;
 
+               // Stop-gap solution for the problem described in T222212.
+               // Force the User ID and Actor ID to zero for users loaded from the database
+               // of another wiki, to prevent subtle data corruption and confusing failure modes.
+               if ( $wikiId !== false ) {
+                       $userId = 0;
+                       $actorId = 0;
+               }
+
                $user = new User;
                $user->mFrom = 'defaults';
 
@@ -911,7 +925,7 @@ class User implements IDBAccessObject, UserIdentity {
                }
 
                if ( !( $flags & self::READ_LATEST ) && array_key_exists( $name, self::$idCacheByName ) ) {
-                       return self::$idCacheByName[$name];
+                       return is_null( self::$idCacheByName[$name] ) ? null : (int)self::$idCacheByName[$name];
                }
 
                list( $index, $options ) = DBAccessObjectUtils::getDBOptions( $flags );
@@ -1148,35 +1162,6 @@ class User implements IDBAccessObject, UserIdentity {
                return $this->checkPasswordValidity( $password )->isGood();
        }
 
-       /**
-        * Given unvalidated password input, return error message on failure.
-        *
-        * @param string $password Desired password
-        * @return bool|string|array True on success, string or array of error message on failure
-        * @deprecated since 1.33, use checkPasswordValidity
-        */
-       public function getPasswordValidity( $password ) {
-               wfDeprecated( __METHOD__, '1.33' );
-
-               $result = $this->checkPasswordValidity( $password );
-               if ( $result->isGood() ) {
-                       return true;
-               }
-
-               $messages = [];
-               foreach ( $result->getErrorsByType( 'error' ) as $error ) {
-                       $messages[] = $error['message'];
-               }
-               foreach ( $result->getErrorsByType( 'warning' ) as $warning ) {
-                       $messages[] = $warning['message'];
-               }
-               if ( count( $messages ) === 1 ) {
-                       return $messages[0];
-               }
-
-               return $messages;
-       }
-
        /**
         * Check if this is a valid password for this user
         *
@@ -1287,17 +1272,6 @@ class User implements IDBAccessObject, UserIdentity {
                return $name;
        }
 
-       /**
-        * Return a random password.
-        *
-        * @deprecated since 1.27, use PasswordFactory::generateRandomPasswordString()
-        * @return string New random password
-        */
-       public static function randomPassword() {
-               global $wgMinimalPasswordLength;
-               return PasswordFactory::generateRandomPasswordString( $wgMinimalPasswordLength );
-       }
-
        /**
         * Set cached properties to default.
         *
@@ -1380,7 +1354,7 @@ class User implements IDBAccessObject, UserIdentity {
                $user = $session->getUser();
                if ( $user->isLoggedIn() ) {
                        $this->loadFromUserObject( $user );
-                       if ( $user->isBlocked() ) {
+                       if ( $user->getBlock() ) {
                                // If this user is autoblocked, set a cookie to track the Block. This has to be done on
                                // every session load, because an autoblocked editor might not edit again from the same
                                // IP address after being blocked.
@@ -1403,24 +1377,11 @@ class User implements IDBAccessObject, UserIdentity {
         */
        public function trackBlockWithCookie() {
                $block = $this->getBlock();
-               if ( $block && $this->getRequest()->getCookie( 'BlockID' ) === null ) {
-                       $config = RequestContext::getMain()->getConfig();
-                       $shouldSetCookie = false;
 
-                       if ( $this->isAnon() && $config->get( 'CookieSetOnIpBlock' ) ) {
-                               // If user is logged-out, set a cookie to track the Block
-                               $shouldSetCookie = in_array( $block->getType(), [
-                                       Block::TYPE_IP, Block::TYPE_RANGE
-                               ] );
-                               if ( $shouldSetCookie ) {
-                                       $block->setCookie( $this->getRequest()->response() );
-                               }
-                       } elseif ( $this->isLoggedIn() && $config->get( 'CookieSetOnAutoblock' ) ) {
-                               $shouldSetCookie = $block->getType() === Block::TYPE_USER && $block->isAutoblocking();
-                               if ( $shouldSetCookie ) {
-                                       $block->setCookie( $this->getRequest()->response() );
-                               }
-                       }
+               if ( $block && $this->getRequest()->getCookie( 'BlockID' ) === null
+                       && $block->shouldTrackWithCookie( $this->isAnon() )
+               ) {
+                       $block->setCookie( $this->getRequest()->response() );
                }
        }
 
@@ -1683,11 +1644,11 @@ class User implements IDBAccessObject, UserIdentity {
         * protected against race conditions using a compare-and-set (CAS) mechanism
         * based on comparing $this->mTouched with the user_touched field.
         *
-        * @param Database $db
+        * @param IDatabase $db
         * @param array $conditions WHERE conditions for use with Database::update
         * @return array WHERE conditions for use with Database::update
         */
-       protected function makeUpdateConditions( Database $db, array $conditions ) {
+       protected function makeUpdateConditions( IDatabase $db, array $conditions ) {
                if ( $this->mTouched ) {
                        // CAS check: only update if the row wasn't changed sicne it was loaded.
                        $conditions['user_touched'] = $db->timestamp( $this->mTouched );
@@ -1727,7 +1688,7 @@ class User implements IDBAccessObject, UserIdentity {
 
                if ( $success ) {
                        $this->mTouched = $newTouched;
-                       $this->clearSharedCache();
+                       $this->clearSharedCache( 'changed' );
                } else {
                        // Clears on failure too since that is desired if the cache is stale
                        $this->clearSharedCache( 'refresh' );
@@ -1762,6 +1723,23 @@ class User implements IDBAccessObject, UserIdentity {
                }
        }
 
+       /** @var array|null */
+       private static $defOpt = null;
+       /** @var string|null */
+       private static $defOptLang = null;
+
+       /**
+        * Reset the process cache of default user options. This is only necessary
+        * if the wiki configuration has changed since defaults were calculated,
+        * and as such should only be performed inside the testing suite that
+        * regularly changes wiki configuration.
+        */
+       public static function resetGetDefaultOptionsForTestsOnly() {
+               Assert::invariant( defined( 'MW_PHPUNIT_TEST' ), 'Unit tests only' );
+               self::$defOpt = null;
+               self::$defOptLang = null;
+       }
+
        /**
         * Combine the language default options with any site-specific options
         * and add the default language variants.
@@ -1771,26 +1749,23 @@ class User implements IDBAccessObject, UserIdentity {
        public static function getDefaultOptions() {
                global $wgNamespacesToBeSearchedDefault, $wgDefaultUserOptions, $wgDefaultSkin;
 
-               static $defOpt = null;
-               static $defOptLang = null;
-
                $contLang = MediaWikiServices::getInstance()->getContentLanguage();
-               if ( $defOpt !== null && $defOptLang === $contLang->getCode() ) {
+               if ( self::$defOpt !== null && self::$defOptLang === $contLang->getCode() ) {
                        // The content language does not change (and should not change) mid-request, but the
                        // unit tests change it anyway, and expect this method to return values relevant to the
                        // current content language.
-                       return $defOpt;
+                       return self::$defOpt;
                }
 
-               $defOpt = $wgDefaultUserOptions;
+               self::$defOpt = $wgDefaultUserOptions;
                // Default language setting
-               $defOptLang = $contLang->getCode();
-               $defOpt['language'] = $defOptLang;
+               self::$defOptLang = $contLang->getCode();
+               self::$defOpt['language'] = self::$defOptLang;
                foreach ( LanguageConverter::$languagesWithVariants as $langCode ) {
                        if ( $langCode === $contLang->getCode() ) {
-                               $defOpt['variant'] = $langCode;
+                               self::$defOpt['variant'] = $langCode;
                        } else {
-                               $defOpt["variant-$langCode"] = $langCode;
+                               self::$defOpt["variant-$langCode"] = $langCode;
                        }
                }
 
@@ -1798,13 +1773,13 @@ class User implements IDBAccessObject, UserIdentity {
                // since extensions may change the set of searchable namespaces depending
                // on user groups/permissions.
                foreach ( $wgNamespacesToBeSearchedDefault as $nsnum => $val ) {
-                       $defOpt['searchNs' . $nsnum] = (bool)$val;
+                       self::$defOpt['searchNs' . $nsnum] = (bool)$val;
                }
-               $defOpt['skin'] = Skin::normalizeKey( $wgDefaultSkin );
+               self::$defOpt['skin'] = Skin::normalizeKey( $wgDefaultSkin );
 
-               Hooks::run( 'UserGetDefaultOptions', [ &$defOpt ] );
+               Hooks::run( 'UserGetDefaultOptions', [ &self::$defOpt ] );
 
-               return $defOpt;
+               return self::$defOpt;
        }
 
        /**
@@ -1820,13 +1795,14 @@ class User implements IDBAccessObject, UserIdentity {
 
        /**
         * Get blocking information
-        * @param bool $bFromReplica Whether to check the replica DB first.
+        *
+        * TODO: Move this into the BlockManager, along with block-related properties.
+        *
+        * @param bool $fromReplica Whether to check the replica DB first.
         *   To improve performance, non-critical checks are done against replica DBs.
         *   Check when actually saving should be done against master.
         */
-       private function getBlockedStatus( $bFromReplica = true ) {
-               global $wgProxyWhitelist, $wgApplyIpBlocksToXff, $wgSoftBlockRanges;
-
+       private function getBlockedStatus( $fromReplica = true ) {
                if ( $this->mBlockedby != -1 ) {
                        return;
                }
@@ -1840,88 +1816,17 @@ class User implements IDBAccessObject, UserIdentity {
                // overwriting mBlockedby, surely?
                $this->load();
 
-               # We only need to worry about passing the IP address to the Block generator if the
-               # user is not immune to autoblocks/hardblocks, and they are the current user so we
-               # know which IP address they're actually coming from
-               $ip = null;
-               if ( !$this->isAllowed( 'ipblock-exempt' ) ) {
-                       $sessionUser = RequestContext::getMain()->getUser();
-                       // the session user is set up towards the end of Setup.php. Until then,
-                       // assume it's a logged-out user.
-                       $globalUserName = $sessionUser->isSafeToLoad()
-                               ? $sessionUser->getName()
-                               : IP::sanitizeIP( $sessionUser->getRequest()->getIP() );
-                       if ( $this->getName() === $globalUserName ) {
-                               $ip = $this->getRequest()->getIP();
-                       }
-               }
-
-               // User/IP blocking
-               $block = Block::newFromTarget( $this, $ip, !$bFromReplica );
-
-               // Cookie blocking
-               if ( !$block instanceof Block ) {
-                       $block = $this->getBlockFromCookieValue( $this->getRequest()->getCookie( 'BlockID' ) );
-               }
-
-               // Proxy blocking
-               if ( !$block instanceof Block && $ip !== null && !in_array( $ip, $wgProxyWhitelist ) ) {
-                       // Local list
-                       if ( self::isLocallyBlockedProxy( $ip ) ) {
-                               $block = new Block( [
-                                       'byText' => wfMessage( 'proxyblocker' )->text(),
-                                       'reason' => wfMessage( 'proxyblockreason' )->plain(),
-                                       'address' => $ip,
-                                       'systemBlock' => 'proxy',
-                               ] );
-                       } elseif ( $this->isAnon() && $this->isDnsBlacklisted( $ip ) ) {
-                               $block = new Block( [
-                                       'byText' => wfMessage( 'sorbs' )->text(),
-                                       'reason' => wfMessage( 'sorbsreason' )->plain(),
-                                       'address' => $ip,
-                                       'systemBlock' => 'dnsbl',
-                               ] );
-                       }
-               }
-
-               // (T25343) Apply IP blocks to the contents of XFF headers, if enabled
-               if ( !$block instanceof Block
-                       && $wgApplyIpBlocksToXff
-                       && $ip !== null
-                       && !in_array( $ip, $wgProxyWhitelist )
-               ) {
-                       $xff = $this->getRequest()->getHeader( 'X-Forwarded-For' );
-                       $xff = array_map( 'trim', explode( ',', $xff ) );
-                       $xff = array_diff( $xff, [ $ip ] );
-                       $xffblocks = Block::getBlocksForIPList( $xff, $this->isAnon(), !$bFromReplica );
-                       $block = Block::chooseBlock( $xffblocks, $xff );
-                       if ( $block instanceof Block ) {
-                               # Mangle the reason to alert the user that the block
-                               # originated from matching the X-Forwarded-For header.
-                               $block->mReason = wfMessage( 'xffblockreason', $block->mReason )->plain();
-                       }
-               }
-
-               if ( !$block instanceof Block
-                       && $ip !== null
-                       && $this->isAnon()
-                       && IP::isInRanges( $ip, $wgSoftBlockRanges )
-               ) {
-                       $block = new Block( [
-                               'address' => $ip,
-                               'byText' => 'MediaWiki default',
-                               'reason' => wfMessage( 'softblockrangesreason', $ip )->plain(),
-                               'anonOnly' => true,
-                               'systemBlock' => 'wgSoftBlockRanges',
-                       ] );
-               }
+               $block = MediaWikiServices::getInstance()->getBlockManager()->getUserBlock(
+                       $this,
+                       $fromReplica
+               );
 
-               if ( $block instanceof Block ) {
+               if ( $block instanceof AbstractBlock ) {
                        wfDebug( __METHOD__ . ": Found block.\n" );
                        $this->mBlock = $block;
                        $this->mBlockedby = $block->getByName();
-                       $this->mBlockreason = $block->mReason;
-                       $this->mHideName = $block->mHideName;
+                       $this->mBlockreason = $block->getReason();
+                       $this->mHideName = $block->getHideName();
                        $this->mAllowUsertalk = $block->isUsertalkEditAllowed();
                } else {
                        $this->mBlock = null;
@@ -1937,82 +1842,30 @@ class User implements IDBAccessObject, UserIdentity {
                Hooks::run( 'GetBlockedStatus', [ &$thisUser ] );
        }
 
-       /**
-        * Try to load a Block from an ID given in a cookie value.
-        * @param string|null $blockCookieVal The cookie value to check.
-        * @return Block|bool The Block object, or false if none could be loaded.
-        */
-       protected function getBlockFromCookieValue( $blockCookieVal ) {
-               // Make sure there's something to check. The cookie value must start with a number.
-               if ( strlen( $blockCookieVal ) < 1 || !is_numeric( substr( $blockCookieVal, 0, 1 ) ) ) {
-                       return false;
-               }
-               // Load the Block from the ID in the cookie.
-               $blockCookieId = Block::getIdFromCookieValue( $blockCookieVal );
-               if ( $blockCookieId !== null ) {
-                       // An ID was found in the cookie.
-                       $tmpBlock = Block::newFromID( $blockCookieId );
-                       if ( $tmpBlock instanceof Block ) {
-                               $config = RequestContext::getMain()->getConfig();
-
-                               switch ( $tmpBlock->getType() ) {
-                                       case Block::TYPE_USER:
-                                               $blockIsValid = !$tmpBlock->isExpired() && $tmpBlock->isAutoblocking();
-                                               $useBlockCookie = ( $config->get( 'CookieSetOnAutoblock' ) === true );
-                                               break;
-                                       case Block::TYPE_IP:
-                                       case Block::TYPE_RANGE:
-                                               // If block is type IP or IP range, load only if user is not logged in (T152462)
-                                               $blockIsValid = !$tmpBlock->isExpired() && !$this->isLoggedIn();
-                                               $useBlockCookie = ( $config->get( 'CookieSetOnIpBlock' ) === true );
-                                               break;
-                                       default:
-                                               $blockIsValid = false;
-                                               $useBlockCookie = false;
-                               }
-
-                               if ( $blockIsValid && $useBlockCookie ) {
-                                       // Use the block.
-                                       return $tmpBlock;
-                               }
-
-                               // If the block is not valid, remove the cookie.
-                               Block::clearCookie( $this->getRequest()->response() );
-                       } else {
-                               // If the block doesn't exist, remove the cookie.
-                               Block::clearCookie( $this->getRequest()->response() );
-                       }
-               }
-               return false;
-       }
-
        /**
         * Whether the given IP is in a DNS blacklist.
         *
+        * @deprecated since 1.34 Use BlockManager::isDnsBlacklisted.
         * @param string $ip IP to check
         * @param bool $checkWhitelist Whether to check the whitelist first
         * @return bool True if blacklisted.
         */
        public function isDnsBlacklisted( $ip, $checkWhitelist = false ) {
-               global $wgEnableDnsBlacklist, $wgDnsBlacklistUrls, $wgProxyWhitelist;
-
-               if ( !$wgEnableDnsBlacklist ||
-                       ( $checkWhitelist && in_array( $ip, $wgProxyWhitelist ) )
-               ) {
-                       return false;
-               }
-
-               return $this->inDnsBlacklist( $ip, $wgDnsBlacklistUrls );
+               return MediaWikiServices::getInstance()->getBlockManager()
+                       ->isDnsBlacklisted( $ip, $checkWhitelist );
        }
 
        /**
         * Whether the given IP is in a given DNS blacklist.
         *
+        * @deprecated since 1.34 Check via BlockManager::isDnsBlacklisted instead.
         * @param string $ip IP to check
         * @param string|array $bases Array of Strings: URL of the DNS blacklist
         * @return bool True if blacklisted.
         */
        public function inDnsBlacklist( $ip, $bases ) {
+               wfDeprecated( __METHOD__, '1.34' );
+
                $found = false;
                // @todo FIXME: IPv6 ???  (https://bugs.php.net/bug.php?id=33170)
                if ( IP::isIPv4( $ip ) ) {
@@ -2054,11 +1907,13 @@ class User implements IDBAccessObject, UserIdentity {
        /**
         * Check if an IP address is in the local proxy list
         *
+        * @deprecated since 1.34 Use BlockManager::getUserBlock instead.
         * @param string $ip
-        *
         * @return bool
         */
        public static function isLocallyBlockedProxy( $ip ) {
+               wfDeprecated( __METHOD__, '1.34' );
+
                global $wgProxyList;
 
                if ( !$wgProxyList ) {
@@ -2205,6 +2060,9 @@ class User implements IDBAccessObject, UserIdentity {
 
                // Set the user limit key
                if ( $userLimit !== false ) {
+                       // phan is confused because &can-bypass's value is a bool, so it assumes
+                       // that $userLimit is also a bool here.
+                       // @phan-suppress-next-line PhanTypeInvalidExpressionArrayDestructuring
                        list( $max, $period ) = $userLimit;
                        wfDebug( __METHOD__ . ": effective user limit: $max in {$period}s\n" );
                        $keys[$cache->makeKey( 'limiter', $action, 'user', $id )] = $userLimit;
@@ -2236,6 +2094,9 @@ class User implements IDBAccessObject, UserIdentity {
 
                $triggered = false;
                foreach ( $keys as $key => $limit ) {
+                       // phan is confused because &can-bypass's value is a bool, so it assumes
+                       // that $userLimit is also a bool here.
+                       // @phan-suppress-next-line PhanTypeInvalidExpressionArrayDestructuring
                        list( $max, $period ) = $limit;
                        $summary = "(limit $max in {$period}s)";
                        $count = $cache->get( $key );
@@ -2265,24 +2126,28 @@ class User implements IDBAccessObject, UserIdentity {
        /**
         * Check if user is blocked
         *
-        * @param bool $bFromReplica Whether to check the replica DB instead of
+        * @deprecated since 1.34, use User::getBlock() or
+        *             PermissionManager::isBlockedFrom() or
+        *             PermissionManager::userCan() instead.
+        *
+        * @param bool $fromReplica Whether to check the replica DB instead of
         *   the master. Hacked from false due to horrible probs on site.
         * @return bool True if blocked, false otherwise
         */
-       public function isBlocked( $bFromReplica = true ) {
-               return $this->getBlock( $bFromReplica ) instanceof Block &&
+       public function isBlocked( $fromReplica = true ) {
+               return $this->getBlock( $fromReplica ) instanceof AbstractBlock &&
                        $this->getBlock()->appliesToRight( 'edit' );
        }
 
        /**
         * Get the block affecting the user, or null if the user is not blocked
         *
-        * @param bool $bFromReplica Whether to check the replica DB instead of the master
-        * @return Block|null
+        * @param bool $fromReplica Whether to check the replica DB instead of the master
+        * @return AbstractBlock|null
         */
-       public function getBlock( $bFromReplica = true ) {
-               $this->getBlockedStatus( $bFromReplica );
-               return $this->mBlock instanceof Block ? $this->mBlock : null;
+       public function getBlock( $fromReplica = true ) {
+               $this->getBlockedStatus( $fromReplica );
+               return $this->mBlock instanceof AbstractBlock ? $this->mBlock : null;
        }
 
        /**
@@ -2291,29 +2156,15 @@ class User implements IDBAccessObject, UserIdentity {
         * @param Title $title Title to check
         * @param bool $fromReplica Whether to check the replica DB instead of the master
         * @return bool
+        * @throws MWException
+        *
+        * @deprecated since 1.33,
+        * use MediaWikiServices::getInstance()->getPermissionManager()->isBlockedFrom(..)
+        *
         */
        public function isBlockedFrom( $title, $fromReplica = false ) {
-               $blocked = $this->isHidden();
-
-               if ( !$blocked ) {
-                       $block = $this->getBlock( $fromReplica );
-                       if ( $block ) {
-                               // Special handling for a user's own talk page. The block is not aware
-                               // of the user, so this must be done here.
-                               if ( $title->equals( $this->getTalkPage() ) ) {
-                                       $blocked = $block->appliesToUsertalk( $title );
-                               } else {
-                                       $blocked = $block->appliesToTitle( $title );
-                               }
-                       }
-               }
-
-               // only for the purpose of the hook. We really don't need this here.
-               $allowUsertalk = $this->mAllowUsertalk;
-
-               Hooks::run( 'UserIsBlockedFrom', [ $this, $title, &$blocked, &$allowUsertalk ] );
-
-               return $blocked;
+               return MediaWikiServices::getInstance()->getPermissionManager()
+                       ->isBlockedFrom( $this, $title, $fromReplica );
        }
 
        /**
@@ -2352,7 +2203,7 @@ class User implements IDBAccessObject, UserIdentity {
         * @return bool True if blocked, false otherwise
         */
        public function isBlockedGlobally( $ip = '' ) {
-               return $this->getGlobalBlock( $ip ) instanceof Block;
+               return $this->getGlobalBlock( $ip ) instanceof AbstractBlock;
        }
 
        /**
@@ -2361,7 +2212,7 @@ class User implements IDBAccessObject, UserIdentity {
         * This is intended for quick UI checks.
         *
         * @param string $ip IP address, uses current client if none given
-        * @return Block|null Block object if blocked, null otherwise
+        * @return AbstractBlock|null Block object if blocked, null otherwise
         * @throws FatalError
         * @throws MWException
         */
@@ -2383,7 +2234,7 @@ class User implements IDBAccessObject, UserIdentity {
 
                if ( $blocked && $block === null ) {
                        // back-compat: UserIsBlockedGlobally didn't have $block param first
-                       $block = new Block( [
+                       $block = new SystemBlock( [
                                'address' => $ip,
                                'systemBlock' => 'global-block'
                        ] );
@@ -2779,29 +2630,26 @@ class User implements IDBAccessObject, UserIdentity {
         *
         * Called implicitly from invalidateCache() and saveSettings().
         *
-        * @param string $mode Use 'refresh' to clear now; otherwise before DB commit
+        * @param string $mode Use 'refresh' to clear now or 'changed' to clear before DB commit
         */
-       public function clearSharedCache( $mode = 'changed' ) {
+       public function clearSharedCache( $mode = 'refresh' ) {
                if ( !$this->getId() ) {
                        return;
                }
 
+               $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
                $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
                $key = $this->getCacheKey( $cache );
+
                if ( $mode === 'refresh' ) {
-                       $cache->delete( $key, 1 );
+                       $cache->delete( $key, 1 ); // low tombstone/"hold-off" TTL
                } else {
-                       $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
-                       if ( $lb->hasOrMadeRecentMasterChanges() ) {
-                               $lb->getConnection( DB_MASTER )->onTransactionPreCommitOrIdle(
-                                       function () use ( $cache, $key ) {
-                                               $cache->delete( $key );
-                                       },
-                                       __METHOD__
-                               );
-                       } else {
-                               $cache->delete( $key );
-                       }
+                       $lb->getConnection( DB_MASTER )->onTransactionPreCommitOrIdle(
+                               function () use ( $cache, $key ) {
+                                       $cache->delete( $key );
+                               },
+                               __METHOD__
+                       );
                }
        }
 
@@ -2812,7 +2660,7 @@ class User implements IDBAccessObject, UserIdentity {
         */
        public function invalidateCache() {
                $this->touch();
-               $this->clearSharedCache();
+               $this->clearSharedCache( 'changed' );
        }
 
        /**
@@ -3580,10 +3428,12 @@ class User implements IDBAccessObject, UserIdentity {
                        // $user->isAllowed(). It is also checked in Title::checkUserBlock()
                        // to give a better error message in the common case.
                        $config = RequestContext::getMain()->getConfig();
+                       // @TODO Partial blocks should not prevent the user from logging in.
+                       //       see: https://phabricator.wikimedia.org/T208895
                        if (
                                $this->isLoggedIn() &&
                                $config->get( 'BlockDisablesLogin' ) &&
-                               $this->isBlocked()
+                               $this->getBlock()
                        ) {
                                $anon = new User;
                                $this->mRights = array_intersect( $this->mRights, $anon->getRights() );
@@ -3797,12 +3647,25 @@ class User implements IDBAccessObject, UserIdentity {
                return true;
        }
 
+       /**
+        * Alias of isLoggedIn() with a name that describes its actual functionality. UserIdentity has
+        * only this new name and not the old isLoggedIn() variant.
+        *
+        * @return bool True if user is registered on this wiki, i.e., has a user ID. False if user is
+        *   anonymous or has no local account (which can happen when importing). This is equivalent to
+        *   getId() != 0 and is provided for code readability.
+        * @since 1.34
+        */
+       public function isRegistered() {
+               return $this->getId() != 0;
+       }
+
        /**
         * Get whether the user is logged in
         * @return bool
         */
        public function isLoggedIn() {
-               return $this->getId() != 0;
+               return $this->isRegistered();
        }
 
        /**
@@ -3810,7 +3673,7 @@ class User implements IDBAccessObject, UserIdentity {
         * @return bool
         */
        public function isAnon() {
-               return !$this->isLoggedIn();
+               return !$this->isRegistered();
        }
 
        /**
@@ -4217,7 +4080,7 @@ class User implements IDBAccessObject, UserIdentity {
                $newTouched = $this->newTouchedTimestamp();
 
                $dbw = wfGetDB( DB_MASTER );
-               $dbw->doAtomicSection( __METHOD__, function ( $dbw, $fname ) use ( $newTouched ) {
+               $dbw->doAtomicSection( __METHOD__, function ( IDatabase $dbw, $fname ) use ( $newTouched ) {
                        global $wgActorTableSchemaMigrationStage;
 
                        $dbw->update( 'user',
@@ -4263,7 +4126,7 @@ class User implements IDBAccessObject, UserIdentity {
                $this->saveOptions();
 
                Hooks::run( 'UserSaveSettings', [ $this ] );
-               $this->clearSharedCache();
+               $this->clearSharedCache( 'changed' );
                $this->getUserPage()->purgeSquid();
        }
 
@@ -4343,7 +4206,7 @@ class User implements IDBAccessObject, UserIdentity {
                        $fields["user_$name"] = $value;
                }
 
-               return $dbw->doAtomicSection( __METHOD__, function ( $dbw, $fname ) use ( $fields ) {
+               return $dbw->doAtomicSection( __METHOD__, function ( IDatabase $dbw, $fname ) use ( $fields ) {
                        $dbw->insert( 'user', $fields, $fname, [ 'IGNORE' ] );
                        if ( $dbw->affectedRows() ) {
                                $newUser = self::newFromId( $dbw->insertId() );
@@ -4397,7 +4260,7 @@ class User implements IDBAccessObject, UserIdentity {
                $this->mTouched = $this->newTouchedTimestamp();
 
                $dbw = wfGetDB( DB_MASTER );
-               $status = $dbw->doAtomicSection( __METHOD__, function ( $dbw, $fname ) {
+               $status = $dbw->doAtomicSection( __METHOD__, function ( IDatabase $dbw, $fname ) {
                        $noPass = PasswordFactory::newInvalidPassword()->toString();
                        $dbw->insert( 'user',
                                [
@@ -4424,10 +4287,8 @@ class User implements IDBAccessObject, UserIdentity {
                                        [ 'LOCK IN SHARE MODE' ]
                                );
                                $loaded = false;
-                               if ( $this->mId ) {
-                                       if ( $this->loadFromDatabase( self::READ_LOCKING ) ) {
-                                               $loaded = true;
-                                       }
+                               if ( $this->mId && $this->loadFromDatabase( self::READ_LOCKING ) ) {
+                                       $loaded = true;
                                }
                                if ( !$loaded ) {
                                        throw new MWException( $fname . ": hit a key conflict attempting " .
@@ -4475,7 +4336,7 @@ class User implements IDBAccessObject, UserIdentity {
         * @return bool A block was spread
         */
        public function spreadAnyEditBlock() {
-               if ( $this->isLoggedIn() && $this->isBlocked() ) {
+               if ( $this->isLoggedIn() && $this->getBlock() ) {
                        return $this->spreadBlock();
                }
 
@@ -4504,7 +4365,7 @@ class User implements IDBAccessObject, UserIdentity {
 
        /**
         * Get whether the user is explicitly blocked from account creation.
-        * @return bool|Block
+        * @return bool|AbstractBlock
         */
        public function isBlockedFromCreateAccount() {
                $this->getBlockedStatus();
@@ -4518,7 +4379,7 @@ class User implements IDBAccessObject, UserIdentity {
                if ( $this->mBlockedFromCreateAccount === false && !$this->isAllowed( 'ipblock-exempt' ) ) {
                        $this->mBlockedFromCreateAccount = Block::newFromTarget( null, $this->getRequest()->getIP() );
                }
-               return $this->mBlockedFromCreateAccount instanceof Block
+               return $this->mBlockedFromCreateAccount instanceof AbstractBlock
                        && $this->mBlockedFromCreateAccount->appliesToRight( 'createaccount' )
                        ? $this->mBlockedFromCreateAccount
                        : false;
@@ -5177,68 +5038,6 @@ class User implements IDBAccessObject, UserIdentity {
                return $wgImplicitGroups;
        }
 
-       /**
-        * Get the title of a page describing a particular group
-        * @deprecated since 1.29 Use UserGroupMembership::getGroupPage instead
-        *
-        * @param string $group Internal group name
-        * @return Title|bool Title of the page if it exists, false otherwise
-        */
-       public static function getGroupPage( $group ) {
-               wfDeprecated( __METHOD__, '1.29' );
-               return UserGroupMembership::getGroupPage( $group );
-       }
-
-       /**
-        * Create a link to the group in HTML, if available;
-        * else return the group name.
-        * @deprecated since 1.29 Use UserGroupMembership::getLink instead, or
-        * make the link yourself if you need custom text
-        *
-        * @param string $group Internal name of the group
-        * @param string $text The text of the link
-        * @return string HTML link to the group
-        */
-       public static function makeGroupLinkHTML( $group, $text = '' ) {
-               wfDeprecated( __METHOD__, '1.29' );
-
-               if ( $text == '' ) {
-                       $text = UserGroupMembership::getGroupName( $group );
-               }
-               $title = UserGroupMembership::getGroupPage( $group );
-               if ( $title ) {
-                       return MediaWikiServices::getInstance()
-                               ->getLinkRenderer()->makeLink( $title, $text );
-               }
-
-               return htmlspecialchars( $text );
-       }
-
-       /**
-        * Create a link to the group in Wikitext, if available;
-        * else return the group name.
-        * @deprecated since 1.29 Use UserGroupMembership::getLink instead, or
-        * make the link yourself if you need custom text
-        *
-        * @param string $group Internal name of the group
-        * @param string $text The text of the link
-        * @return string Wikilink to the group
-        */
-       public static function makeGroupLinkWiki( $group, $text = '' ) {
-               wfDeprecated( __METHOD__, '1.29' );
-
-               if ( $text == '' ) {
-                       $text = UserGroupMembership::getGroupName( $group );
-               }
-               $title = UserGroupMembership::getGroupPage( $group );
-               if ( $title ) {
-                       $page = $title->getFullText();
-                       return "[[$page|$text]]";
-               }
-
-               return $text;
-       }
-
        /**
         * Returns an array of the groups that a particular group can add/remove.
         *
@@ -5743,4 +5542,14 @@ class User implements IDBAccessObject, UserIdentity {
                // XXX it's not clear whether central ID providers are supposed to obey this
                return $this->getName() === $user->getName();
        }
+
+       /**
+        * Checks if usertalk is allowed
+        *
+        * @return bool
+        */
+       public function isAllowUsertalk() {
+               return $this->mAllowUsertalk;
+       }
+
 }
index acd6970..e06df9f 100644 (file)
@@ -395,12 +395,13 @@ class UserGroupMembership {
 
                // link to the group description page, if it exists
                $linkTitle = self::getGroupPage( $group );
+               $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
                if ( $linkTitle ) {
                        if ( $format === 'wiki' ) {
                                $linkPage = $linkTitle->getFullText();
                                $groupLink = "[[$linkPage|$groupName]]";
                        } else {
-                               $groupLink = Linker::link( $linkTitle, htmlspecialchars( $groupName ) );
+                               $groupLink = $linkRenderer->makeLink( $linkTitle, $groupName );
                        }
                } else {
                        $groupLink = htmlspecialchars( $groupName );
index ac9bbec..64c61fe 100644 (file)
@@ -62,4 +62,12 @@ interface UserIdentity {
         */
        public function equals( UserIdentity $user );
 
+       /**
+        * @since 1.34
+        *
+        * @return bool True if user is registered on this wiki, i.e., has a user ID. False if user is
+        *   anonymous or has no local account (which can happen when importing). This must be
+        *   equivalent to getId() != 0 and is provided for code readability.
+        */
+       public function isRegistered();
 }
index d1fd19d..800ac76 100644 (file)
@@ -93,4 +93,14 @@ class UserIdentityValue implements UserIdentity {
                return $this->getName() === $user->getName();
        }
 
+       /**
+        * @since 1.34
+        *
+        * @return bool True if user is registered on this wiki, i.e., has a user ID. False if user is
+        *   anonymous or has no local account (which can happen when importing). This is equivalent to
+        *   getId() != 0 and is provided for code readability.
+        */
+       public function isRegistered() {
+               return $this->getId() != 0;
+       }
 }
index 2fc7bc0..260f66c 100644 (file)
@@ -1,4 +1,22 @@
 <?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
 
 /**
  * Accepts a list of files and directories to search for
@@ -368,190 +386,3 @@ EOD;
                }
        }
 }
-
-/**
- * Reads PHP code and returns the FQCN of every class defined within it.
- */
-class ClassCollector {
-
-       /**
-        * @var string Current namespace
-        */
-       protected $namespace = '';
-
-       /**
-        * @var array List of FQCN detected in this pass
-        */
-       protected $classes;
-
-       /**
-        * @var array Token from token_get_all() that started an expect sequence
-        */
-       protected $startToken;
-
-       /**
-        * @var array List of tokens that are members of the current expect sequence
-        */
-       protected $tokens;
-
-       /**
-        * @var array Class alias with target/name fields
-        */
-       protected $alias;
-
-       /**
-        * @param string $code PHP code (including <?php) to detect class names from
-        * @return array List of FQCN detected within the tokens
-        */
-       public function getClasses( $code ) {
-               $this->namespace = '';
-               $this->classes = [];
-               $this->startToken = null;
-               $this->alias = null;
-               $this->tokens = [];
-
-               foreach ( token_get_all( $code ) as $token ) {
-                       if ( $this->startToken === null ) {
-                               $this->tryBeginExpect( $token );
-                       } else {
-                               $this->tryEndExpect( $token );
-                       }
-               }
-
-               return $this->classes;
-       }
-
-       /**
-        * Determine if $token begins the next expect sequence.
-        *
-        * @param array $token
-        */
-       protected function tryBeginExpect( $token ) {
-               if ( is_string( $token ) ) {
-                       return;
-               }
-               // Note: When changing class name discovery logic,
-               // AutoLoaderStructureTest.php may also need to be updated.
-               switch ( $token[0] ) {
-                       case T_NAMESPACE:
-                       case T_CLASS:
-                       case T_INTERFACE:
-                       case T_TRAIT:
-                       case T_DOUBLE_COLON:
-                       case T_NEW:
-                               $this->startToken = $token;
-                               break;
-                       case T_STRING:
-                               if ( $token[1] === 'class_alias' ) {
-                                       $this->startToken = $token;
-                                       $this->alias = [];
-                               }
-               }
-       }
-
-       /**
-        * Accepts the next token in an expect sequence
-        *
-        * @param array $token
-        */
-       protected function tryEndExpect( $token ) {
-               switch ( $this->startToken[0] ) {
-                       case T_DOUBLE_COLON:
-                               // Skip over T_CLASS after T_DOUBLE_COLON because this is something like
-                               // "self::static" which accesses the class name. It doens't define a new class.
-                               $this->startToken = null;
-                               break;
-                       case T_NEW:
-                               // Skip over T_CLASS after T_NEW because this is a PHP 7 anonymous class.
-                               if ( !is_array( $token ) || $token[0] !== T_WHITESPACE ) {
-                                       $this->startToken = null;
-                               }
-                               break;
-                       case T_NAMESPACE:
-                               if ( $token === ';' || $token === '{' ) {
-                                       $this->namespace = $this->implodeTokens() . '\\';
-                               } else {
-                                       $this->tokens[] = $token;
-                               }
-                               break;
-
-                       case T_STRING:
-                               if ( $this->alias !== null ) {
-                                       // Flow 1 - Two string literals:
-                                       // - T_STRING  class_alias
-                                       // - '('
-                                       // - T_CONSTANT_ENCAPSED_STRING 'TargetClass'
-                                       // - ','
-                                       // - T_WHITESPACE
-                                       // - T_CONSTANT_ENCAPSED_STRING 'AliasName'
-                                       // - ')'
-                                       // Flow 2 - Use of ::class syntax for first parameter
-                                       // - T_STRING  class_alias
-                                       // - '('
-                                       // - T_STRING TargetClass
-                                       // - T_DOUBLE_COLON ::
-                                       // - T_CLASS class
-                                       // - ','
-                                       // - T_WHITESPACE
-                                       // - T_CONSTANT_ENCAPSED_STRING 'AliasName'
-                                       // - ')'
-                                       if ( $token === '(' ) {
-                                               // Start of a function call to class_alias()
-                                               $this->alias = [ 'target' => false, 'name' => false ];
-                                       } elseif ( $token === ',' ) {
-                                               // Record that we're past the first parameter
-                                               if ( $this->alias['target'] === false ) {
-                                                       $this->alias['target'] = true;
-                                               }
-                                       } elseif ( is_array( $token ) && $token[0] === T_CONSTANT_ENCAPSED_STRING ) {
-                                               if ( $this->alias['target'] === true ) {
-                                                       // We already saw a first argument, this must be the second.
-                                                       // Strip quotes from the string literal.
-                                                       $this->alias['name'] = substr( $token[1], 1, -1 );
-                                               }
-                                       } elseif ( $token === ')' ) {
-                                               // End of function call
-                                               $this->classes[] = $this->alias['name'];
-                                               $this->alias = null;
-                                               $this->startToken = null;
-                                       } elseif ( !is_array( $token ) || (
-                                               $token[0] !== T_STRING &&
-                                               $token[0] !== T_DOUBLE_COLON &&
-                                               $token[0] !== T_CLASS &&
-                                               $token[0] !== T_WHITESPACE
-                                       ) ) {
-                                               // Ignore this call to class_alias() - compat/Timestamp.php
-                                               $this->alias = null;
-                                               $this->startToken = null;
-                                       }
-                               }
-                               break;
-
-                       case T_CLASS:
-                       case T_INTERFACE:
-                       case T_TRAIT:
-                               $this->tokens[] = $token;
-                               if ( is_array( $token ) && $token[0] === T_STRING ) {
-                                       $this->classes[] = $this->namespace . $this->implodeTokens();
-                               }
-               }
-       }
-
-       /**
-        * Returns the string representation of the tokens within the
-        * current expect sequence and resets the sequence.
-        *
-        * @return string
-        */
-       protected function implodeTokens() {
-               $content = [];
-               foreach ( $this->tokens as $token ) {
-                       $content[] = is_string( $token ) ? $token : $token[1];
-               }
-
-               $this->tokens = [];
-               $this->startToken = null;
-
-               return trim( implode( '', $content ), " \n\t" );
-       }
-}
index f42b5a0..f2bc615 100644 (file)
@@ -77,7 +77,7 @@ class BatchRowUpdate {
                $this->reader = $reader;
                $this->writer = $writer;
                $this->generator = $generator;
-               $this->output = function () {
+               $this->output = function ( $text ) {
                }; // nop
        }
 
diff --git a/includes/utils/ClassCollector.php b/includes/utils/ClassCollector.php
new file mode 100644 (file)
index 0000000..c987354
--- /dev/null
@@ -0,0 +1,206 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * Reads PHP code and returns the FQCN of every class defined within it.
+ */
+class ClassCollector {
+
+       /**
+        * @var string Current namespace
+        */
+       protected $namespace = '';
+
+       /**
+        * @var array List of FQCN detected in this pass
+        */
+       protected $classes;
+
+       /**
+        * @var array Token from token_get_all() that started an expect sequence
+        */
+       protected $startToken;
+
+       /**
+        * @var array List of tokens that are members of the current expect sequence
+        */
+       protected $tokens;
+
+       /**
+        * @var array Class alias with target/name fields
+        */
+       protected $alias;
+
+       /**
+        * @param string $code PHP code (including <?php) to detect class names from
+        * @return array List of FQCN detected within the tokens
+        */
+       public function getClasses( $code ) {
+               $this->namespace = '';
+               $this->classes = [];
+               $this->startToken = null;
+               $this->alias = null;
+               $this->tokens = [];
+
+               foreach ( token_get_all( $code ) as $token ) {
+                       if ( $this->startToken === null ) {
+                               $this->tryBeginExpect( $token );
+                       } else {
+                               $this->tryEndExpect( $token );
+                       }
+               }
+
+               return $this->classes;
+       }
+
+       /**
+        * Determine if $token begins the next expect sequence.
+        *
+        * @param array $token
+        */
+       protected function tryBeginExpect( $token ) {
+               if ( is_string( $token ) ) {
+                       return;
+               }
+               // Note: When changing class name discovery logic,
+               // AutoLoaderStructureTest.php may also need to be updated.
+               switch ( $token[0] ) {
+                       case T_NAMESPACE:
+                       case T_CLASS:
+                       case T_INTERFACE:
+                       case T_TRAIT:
+                       case T_DOUBLE_COLON:
+                       case T_NEW:
+                               $this->startToken = $token;
+                               break;
+                       case T_STRING:
+                               if ( $token[1] === 'class_alias' ) {
+                                       $this->startToken = $token;
+                                       $this->alias = [];
+                               }
+               }
+       }
+
+       /**
+        * Accepts the next token in an expect sequence
+        *
+        * @param array $token
+        */
+       protected function tryEndExpect( $token ) {
+               switch ( $this->startToken[0] ) {
+                       case T_DOUBLE_COLON:
+                               // Skip over T_CLASS after T_DOUBLE_COLON because this is something like
+                               // "self::static" which accesses the class name. It doens't define a new class.
+                               $this->startToken = null;
+                               break;
+                       case T_NEW:
+                               // Skip over T_CLASS after T_NEW because this is a PHP 7 anonymous class.
+                               if ( !is_array( $token ) || $token[0] !== T_WHITESPACE ) {
+                                       $this->startToken = null;
+                               }
+                               break;
+                       case T_NAMESPACE:
+                               if ( $token === ';' || $token === '{' ) {
+                                       $this->namespace = $this->implodeTokens() . '\\';
+                               } else {
+                                       $this->tokens[] = $token;
+                               }
+                               break;
+
+                       case T_STRING:
+                               if ( $this->alias !== null ) {
+                                       // Flow 1 - Two string literals:
+                                       // - T_STRING  class_alias
+                                       // - '('
+                                       // - T_CONSTANT_ENCAPSED_STRING 'TargetClass'
+                                       // - ','
+                                       // - T_WHITESPACE
+                                       // - T_CONSTANT_ENCAPSED_STRING 'AliasName'
+                                       // - ')'
+                                       // Flow 2 - Use of ::class syntax for first parameter
+                                       // - T_STRING  class_alias
+                                       // - '('
+                                       // - T_STRING TargetClass
+                                       // - T_DOUBLE_COLON ::
+                                       // - T_CLASS class
+                                       // - ','
+                                       // - T_WHITESPACE
+                                       // - T_CONSTANT_ENCAPSED_STRING 'AliasName'
+                                       // - ')'
+                                       if ( $token === '(' ) {
+                                               // Start of a function call to class_alias()
+                                               $this->alias = [ 'target' => false, 'name' => false ];
+                                       } elseif ( $token === ',' ) {
+                                               // Record that we're past the first parameter
+                                               if ( $this->alias['target'] === false ) {
+                                                       $this->alias['target'] = true;
+                                               }
+                                       } elseif ( is_array( $token ) && $token[0] === T_CONSTANT_ENCAPSED_STRING ) {
+                                               if ( $this->alias['target'] === true ) {
+                                                       // We already saw a first argument, this must be the second.
+                                                       // Strip quotes from the string literal.
+                                                       $this->alias['name'] = substr( $token[1], 1, -1 );
+                                               }
+                                       } elseif ( $token === ')' ) {
+                                               // End of function call
+                                               $this->classes[] = $this->alias['name'];
+                                               $this->alias = null;
+                                               $this->startToken = null;
+                                       } elseif ( !is_array( $token ) || (
+                                                       $token[0] !== T_STRING &&
+                                                       $token[0] !== T_DOUBLE_COLON &&
+                                                       $token[0] !== T_CLASS &&
+                                                       $token[0] !== T_WHITESPACE
+                                               ) ) {
+                                               // Ignore this call to class_alias() - compat/Timestamp.php
+                                               $this->alias = null;
+                                               $this->startToken = null;
+                                       }
+                               }
+                               break;
+
+                       case T_CLASS:
+                       case T_INTERFACE:
+                       case T_TRAIT:
+                               $this->tokens[] = $token;
+                               if ( is_array( $token ) && $token[0] === T_STRING ) {
+                                       $this->classes[] = $this->namespace . $this->implodeTokens();
+                               }
+               }
+       }
+
+       /**
+        * Returns the string representation of the tokens within the
+        * current expect sequence and resets the sequence.
+        *
+        * @return string
+        */
+       protected function implodeTokens() {
+               $content = [];
+               foreach ( $this->tokens as $token ) {
+                       $content[] = is_string( $token ) ? $token : $token[1];
+               }
+
+               $this->tokens = [];
+               $this->startToken = null;
+
+               return trim( implode( '', $content ), " \n\t" );
+       }
+}
index ec8bf5c..673586d 100644 (file)
  * @file
  */
 
-use MediaWiki\MediaWikiServices;
-
 class MWCryptRand {
-       /**
-        * @deprecated since 1.32
-        * @return CryptRand
-        */
-       protected static function singleton() {
-               wfDeprecated( __METHOD__, '1.32' );
-               return MediaWikiServices::getInstance()->getCryptRand();
-       }
-
-       /**
-        * Return a boolean indicating whether or not the source used for cryptographic
-        * random bytes generation in the previously run generate* call
-        * was cryptographically strong.
-        *
-        * @deprecated since 1.32, always returns true
-        *
-        * @return bool Always true
-        */
-       public static function wasStrong() {
-               wfDeprecated( __METHOD__, '1.32' );
-               return true;
-       }
-
-       /**
-        * Generate a run of cryptographically random data and return
-        * it in raw binary form.
-        *
-        * @deprecated since 1.32, use random_bytes()
-        *
-        * @param int $bytes The number of bytes of random data to generate
-        * @return string Raw binary random data
-        */
-       public static function generate( $bytes ) {
-               wfDeprecated( __METHOD__, '1.32' );
-               return random_bytes( floor( $bytes ) );
-       }
 
        /**
         * Generate a run of cryptographically random data and return
index 15c0cf9..fea5404 100644 (file)
@@ -137,8 +137,7 @@ class UIDGenerator {
                        $time = $info['time'];
                        $counter = $info['offsetCounter'];
                } else {
-                       $time = $info[0];
-                       $counter = $info[1];
+                       list( $time, $counter ) = $info;
                }
                // Take the 46 LSBs of "milliseconds since epoch"
                $id_bin = $this->millisecondsSinceEpochBinary( $time );
@@ -192,9 +191,7 @@ class UIDGenerator {
                        $counter = $info['offsetCounter'];
                        $clkSeq = $info['clkSeq'];
                } else {
-                       $time = $info[0];
-                       $counter = $info[1];
-                       $clkSeq = $info[2];
+                       list( $time, $counter, $clkSeq ) = $info;
                }
                // Take the 46 LSBs of "milliseconds since epoch"
                $id_bin = $this->millisecondsSinceEpochBinary( $time );
@@ -577,7 +574,7 @@ class UIDGenerator {
                $start = microtime( true );
                do {
                        $ct = time();
-                       // https://secure.php.net/manual/en/language.operators.comparison.php
+                       // https://www.php.net/manual/en/language.operators.comparison.php
                        if ( $ct >= $time ) {
                                // current time is higher than or equal to than $time
                                return $ct;
index 39d7a5d..72f6086 100644 (file)
@@ -18,7 +18,9 @@
  * @file
  * @ingroup Watchlist
  */
+
 use MediaWiki\Linker\LinkTarget;
+use MediaWiki\User\UserIdentity;
 use Wikimedia\Rdbms\DBReadOnlyError;
 
 /**
@@ -32,9 +34,6 @@ class NoWriteWatchedItemStore implements WatchedItemStoreInterface {
         */
        private $actualStore;
 
-       /**
-        * @var string
-        */
        const DB_READONLY_ERROR = 'The watchlist is currently readonly.';
 
        /**
@@ -45,7 +44,7 @@ class NoWriteWatchedItemStore implements WatchedItemStoreInterface {
                $this->actualStore = $actualStore;
        }
 
-       public function countWatchedItems( User $user ) {
+       public function countWatchedItems( UserIdentity $user ) {
                return $this->actualStore->countWatchedItems( $user );
        }
 
@@ -71,27 +70,27 @@ class NoWriteWatchedItemStore implements WatchedItemStoreInterface {
                );
        }
 
-       public function getWatchedItem( User $user, LinkTarget $target ) {
+       public function getWatchedItem( UserIdentity $user, LinkTarget $target ) {
                return $this->actualStore->getWatchedItem( $user, $target );
        }
 
-       public function loadWatchedItem( User $user, LinkTarget $target ) {
+       public function loadWatchedItem( UserIdentity $user, LinkTarget $target ) {
                return $this->actualStore->loadWatchedItem( $user, $target );
        }
 
-       public function getWatchedItemsForUser( User $user, array $options = [] ) {
+       public function getWatchedItemsForUser( UserIdentity $user, array $options = [] ) {
                return $this->actualStore->getWatchedItemsForUser( $user, $options );
        }
 
-       public function isWatched( User $user, LinkTarget $target ) {
+       public function isWatched( UserIdentity $user, LinkTarget $target ) {
                return $this->actualStore->isWatched( $user, $target );
        }
 
-       public function getNotificationTimestampsBatch( User $user, array $targets ) {
+       public function getNotificationTimestampsBatch( UserIdentity $user, array $targets ) {
                return $this->actualStore->getNotificationTimestampsBatch( $user, $targets );
        }
 
-       public function countUnreadNotifications( User $user, $unreadLimit = null ) {
+       public function countUnreadNotifications( UserIdentity $user, $unreadLimit = null ) {
                return $this->actualStore->countUnreadNotifications( $user, $unreadLimit );
        }
 
@@ -103,56 +102,60 @@ class NoWriteWatchedItemStore implements WatchedItemStoreInterface {
                throw new DBReadOnlyError( null, self::DB_READONLY_ERROR );
        }
 
-       public function addWatch( User $user, LinkTarget $target ) {
+       public function addWatch( UserIdentity $user, LinkTarget $target ) {
                throw new DBReadOnlyError( null, self::DB_READONLY_ERROR );
        }
 
-       public function addWatchBatchForUser( User $user, array $targets ) {
+       public function addWatchBatchForUser( UserIdentity $user, array $targets ) {
                throw new DBReadOnlyError( null, self::DB_READONLY_ERROR );
        }
 
-       public function removeWatch( User $user, LinkTarget $target ) {
+       public function removeWatch( UserIdentity $user, LinkTarget $target ) {
                throw new DBReadOnlyError( null, self::DB_READONLY_ERROR );
        }
 
        public function setNotificationTimestampsForUser(
-               User $user,
+               UserIdentity $user,
                $timestamp,
                array $targets = []
        ) {
                throw new DBReadOnlyError( null, self::DB_READONLY_ERROR );
        }
 
-       public function updateNotificationTimestamp( User $editor, LinkTarget $target, $timestamp ) {
+       public function updateNotificationTimestamp(
+               UserIdentity $editor, LinkTarget $target, $timestamp
+       ) {
                throw new DBReadOnlyError( null, self::DB_READONLY_ERROR );
        }
 
-       public function resetAllNotificationTimestampsForUser( User $user ) {
+       public function resetAllNotificationTimestampsForUser( UserIdentity $user ) {
                throw new DBReadOnlyError( null, self::DB_READONLY_ERROR );
        }
 
        public function resetNotificationTimestamp(
-               User $user,
-               Title $title,
+               UserIdentity $user,
+               LinkTarget $title,
                $force = '',
                $oldid = 0
        ) {
                throw new DBReadOnlyError( null, self::DB_READONLY_ERROR );
        }
 
-       public function clearUserWatchedItems( User $user ) {
+       public function clearUserWatchedItems( UserIdentity $user ) {
                throw new DBReadOnlyError( null, self::DB_READONLY_ERROR );
        }
 
-       public function clearUserWatchedItemsUsingJobQueue( User $user ) {
+       public function clearUserWatchedItemsUsingJobQueue( UserIdentity $user ) {
                throw new DBReadOnlyError( null, self::DB_READONLY_ERROR );
        }
 
-       public function removeWatchBatchForUser( User $user, array $titles ) {
+       public function removeWatchBatchForUser( UserIdentity $user, array $titles ) {
                throw new DBReadOnlyError( null, self::DB_READONLY_ERROR );
        }
 
-       public function getLatestNotificationTimestamp( $timestamp, User $user, LinkTarget $target ) {
+       public function getLatestNotificationTimestamp(
+               $timestamp, UserIdentity $user, LinkTarget $target
+       ) {
                return wfTimestampOrNull( TS_MW, $timestamp );
        }
 }
index 43a9c4e..4bf7f0c 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 use MediaWiki\Linker\LinkTarget;
+use MediaWiki\User\UserIdentity;
 
 /**
  * Representation of a pair of user and title for watchlist entries.
@@ -36,7 +37,7 @@ class WatchedItem {
        private $linkTarget;
 
        /**
-        * @var User
+        * @var UserIdentity
         */
        private $user;
 
@@ -46,12 +47,12 @@ class WatchedItem {
        private $notificationTimestamp;
 
        /**
-        * @param User $user
+        * @param UserIdentity $user
         * @param LinkTarget $linkTarget
         * @param null|string $notificationTimestamp the value of the wl_notificationtimestamp field
         */
        public function __construct(
-               User $user,
+               UserIdentity $user,
                LinkTarget $linkTarget,
                $notificationTimestamp
        ) {
@@ -61,9 +62,17 @@ class WatchedItem {
        }
 
        /**
+        * @deprecated since 1.34, use getUserIdentity()
         * @return User
         */
        public function getUser() {
+               return User::newFromIdentity( $this->user );
+       }
+
+       /**
+        * @return UserIdentity
+        */
+       public function getUserIdentity() {
                return $this->user;
        }
 
index 3ebc94a..b134bfe 100644 (file)
@@ -1,8 +1,9 @@
 <?php
 
-use Wikimedia\Rdbms\IDatabase;
 use MediaWiki\Linker\LinkTarget;
+use MediaWiki\User\UserIdentity;
 use Wikimedia\Assert\Assert;
+use Wikimedia\Rdbms\IDatabase;
 use Wikimedia\Rdbms\LoadBalancer;
 
 /**
@@ -121,8 +122,8 @@ class WatchedItemQueryService {
         *        'end'                 => string (format accepted by wfTimestamp) requires 'dir' option,
         *                                 timestamp to end enumerating
         *        'watchlistOwner'      => User user whose watchlist items should be listed if different
-        *                                 than the one specified with $user param,
-        *                                 requires 'watchlistOwnerToken' option
+        *                                 than the one specified with $user param, requires
+        *                                 'watchlistOwnerToken' option
         *        'watchlistOwnerToken' => string a watchlist token used to access another user's
         *                                 watchlist, used with 'watchlistOwnerToken' option
         *        'limit'               => int maximum numbers of items to return
@@ -131,7 +132,7 @@ class WatchedItemQueryService {
         *                                 id fields ('rc_cur_id', 'rc_this_oldid', 'rc_last_oldid')
         *                                 if false (default)
         * @param array|null &$startFrom Continuation value: [ string $rcTimestamp, int $rcId ]
-        * @return array of pairs ( WatchedItem $watchedItem, string[] $recentChangeInfo ),
+        * @return array[] Array of pairs ( WatchedItem $watchedItem, string[] $recentChangeInfo ),
         *         where $recentChangeInfo contains the following keys:
         *         - 'rc_id',
         *         - 'rc_namespace',
@@ -256,7 +257,7 @@ class WatchedItemQueryService {
        /**
         * For simple listing of user's watchlist items, see WatchedItemStore::getWatchedItemsForUser
         *
-        * @param User $user
+        * @param UserIdentity $user
         * @param array $options Allowed keys:
         *        'sort'         => string optional sorting by namespace ID and title
         *                          one of the self::SORT_* constants
@@ -272,8 +273,8 @@ class WatchedItemQueryService {
         *                          specified using the form option
         * @return WatchedItem[]
         */
-       public function getWatchedItemsForUser( User $user, array $options = [] ) {
-               if ( $user->isAnon() ) {
+       public function getWatchedItemsForUser( UserIdentity $user, array $options = [] ) {
+               if ( !$user->isRegistered() ) {
                        // TODO: should this just return an empty array or rather complain loud at this point
                        // as e.g. ApiBase::getWatchlistUser does?
                        return [];
@@ -445,11 +446,9 @@ class WatchedItemQueryService {
 
                $conds = array_merge( $conds, $this->getStartEndConds( $db, $options ) );
 
-               if ( !isset( $options['start'] ) && !isset( $options['end'] ) ) {
-                       if ( $db->getType() === 'mysql' ) {
-                               // This is an index optimization for mysql
-                               $conds[] = 'rc_timestamp > ' . $db->addQuotes( '' );
-                       }
+               if ( !isset( $options['start'] ) && !isset( $options['end'] ) && $db->getType() === 'mysql' ) {
+                       // This is an index optimization for mysql
+                       $conds[] = 'rc_timestamp > ' . $db->addQuotes( '' );
                }
 
                $conds = array_merge( $conds, $this->getUserRelatedConds( $db, $user, $options ) );
@@ -462,11 +461,12 @@ class WatchedItemQueryService {
                return $conds;
        }
 
-       private function getWatchlistOwnerId( User $user, array $options ) {
+       private function getWatchlistOwnerId( UserIdentity $user, array $options ) {
                if ( array_key_exists( 'watchlistOwner', $options ) ) {
                        /** @var User $watchlistOwner */
                        $watchlistOwner = $options['watchlistOwner'];
-                       $ownersToken = $watchlistOwner->getOption( 'watchlisttoken' );
+                       $ownersToken =
+                               $watchlistOwner->getOption( 'watchlisttoken' );
                        $token = $options['watchlistOwnerToken'];
                        if ( $ownersToken == '' || !hash_equals( $ownersToken, $token ) ) {
                                throw ApiUsageException::newWithMessage( null, 'apierror-bad-watchlist-token', 'bad_wltoken' );
@@ -615,7 +615,9 @@ class WatchedItemQueryService {
                );
        }
 
-       private function getWatchedItemsForUserQueryConds( IDatabase $db, User $user, array $options ) {
+       private function getWatchedItemsForUserQueryConds(
+               IDatabase $db, UserIdentity $user, array $options
+       ) {
                $conds = [ 'wl_user' => $user->getId() ];
                if ( $options['namespaceIds'] ) {
                        $conds['wl_namespace'] = array_map( 'intval', $options['namespaceIds'] );
index a0e64c5..00770ea 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 
+use MediaWiki\User\UserIdentity;
 use Wikimedia\Rdbms\IResultWrapper;
 use Wikimedia\Rdbms\IDatabase;
 
@@ -21,7 +22,7 @@ interface WatchedItemQueryServiceExtension {
         *
         * @warning Any joins added *must* join on a unique key of the target table
         *  unless you really know what you're doing.
-        * @param User $user
+        * @param UserIdentity $user
         * @param array $options Options from
         *  WatchedItemQueryService::getWatchedItemsWithRecentChangeInfo()
         * @param IDatabase $db Database connection being used for the query
@@ -31,15 +32,16 @@ interface WatchedItemQueryServiceExtension {
         * @param array &$dbOptions Options for Database::select()
         * @param array &$joinConds Join conditions for Database::select()
         */
-       public function modifyWatchedItemsWithRCInfoQuery( User $user, array $options, IDatabase $db,
-               array &$tables, array &$fields, array &$conds, array &$dbOptions, array &$joinConds
+       public function modifyWatchedItemsWithRCInfoQuery( UserIdentity $user, array $options,
+               IDatabase $db, array &$tables, array &$fields, array &$conds, array &$dbOptions,
+               array &$joinConds
        );
 
        /**
         * Modify the results from WatchedItemQueryService::getWatchedItemsWithRecentChangeInfo()
         * before they're returned.
         *
-        * @param User $user
+        * @param UserIdentity $user
         * @param array $options Options from
         *  WatchedItemQueryService::getWatchedItemsWithRecentChangeInfo()
         * @param IDatabase $db Database connection being used for the query
@@ -50,7 +52,7 @@ interface WatchedItemQueryServiceExtension {
         *  [ $recentChangeInfo['rc_timestamp'], $recentChangeInfo['rc_id'] ] from the first item
         *  removed.
         */
-       public function modifyWatchedItemsWithRCInfo( User $user, array $options, IDatabase $db,
+       public function modifyWatchedItemsWithRCInfo( UserIdentity $user, array $options, IDatabase $db,
                array &$items, $res, &$startFrom
        );
 
index e092859..ec25002 100644 (file)
@@ -1,12 +1,14 @@
 <?php
 
-use Wikimedia\Rdbms\IDatabase;
 use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface;
 use MediaWiki\Linker\LinkTarget;
+use MediaWiki\Revision\RevisionLookup;
+use MediaWiki\User\UserIdentity;
 use Wikimedia\Assert\Assert;
-use Wikimedia\ScopedCallback;
+use Wikimedia\Rdbms\IDatabase;
 use Wikimedia\Rdbms\ILBFactory;
 use Wikimedia\Rdbms\LoadBalancer;
+use Wikimedia\ScopedCallback;
 
 /**
  * Storage layer class for WatchedItems.
@@ -67,14 +69,19 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
        private $deferredUpdatesAddCallableUpdateCallback;
 
        /**
-        * @var callable|null
+        * @var int
         */
-       private $revisionGetTimestampFromIdCallback;
+       private $updateRowsPerQuery;
 
        /**
-        * @var int
+        * @var NamespaceInfo
         */
-       private $updateRowsPerQuery;
+       private $nsInfo;
+
+       /**
+        * @var RevisionLookup
+        */
+       private $revisionLookup;
 
        /**
         * @var StatsdDataFactoryInterface
@@ -88,6 +95,8 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
         * @param HashBagOStuff $cache
         * @param ReadOnlyMode $readOnlyMode
         * @param int $updateRowsPerQuery
+        * @param NamespaceInfo $nsInfo
+        * @param RevisionLookup $revisionLookup
         */
        public function __construct(
                ILBFactory $lbFactory,
@@ -95,7 +104,9 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
                BagOStuff $stash,
                HashBagOStuff $cache,
                ReadOnlyMode $readOnlyMode,
-               $updateRowsPerQuery
+               $updateRowsPerQuery,
+               NamespaceInfo $nsInfo,
+               RevisionLookup $revisionLookup
        ) {
                $this->lbFactory = $lbFactory;
                $this->loadBalancer = $lbFactory->getMainLB();
@@ -106,9 +117,9 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
                $this->stats = new NullStatsdDataFactory();
                $this->deferredUpdatesAddCallableUpdateCallback =
                        [ DeferredUpdates::class, 'addCallableUpdate' ];
-               $this->revisionGetTimestampFromIdCallback =
-                       [ Revision::class, 'getTimestampFromId' ];
                $this->updateRowsPerQuery = $updateRowsPerQuery;
+               $this->nsInfo = $nsInfo;
+               $this->revisionLookup = $revisionLookup;
 
                $this->latestUpdateCache = new HashBagOStuff( [ 'maxKeys' => 3 ] );
        }
@@ -144,30 +155,7 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
                } );
        }
 
-       /**
-        * Overrides the Revision::getTimestampFromId callback
-        * This is intended for use while testing and will fail if MW_PHPUNIT_TEST is not defined.
-        *
-        * @param callable $callback
-        * @see Revision::getTimestampFromId for callback signiture
-        *
-        * @return ScopedCallback to reset the overridden value
-        * @throws MWException
-        */
-       public function overrideRevisionGetTimestampFromIdCallback( callable $callback ) {
-               if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
-                       throw new MWException(
-                               'Cannot override Revision::getTimestampFromId callback in operation.'
-                       );
-               }
-               $previousValue = $this->revisionGetTimestampFromIdCallback;
-               $this->revisionGetTimestampFromIdCallback = $callback;
-               return new ScopedCallback( function () use ( $previousValue ) {
-                       $this->revisionGetTimestampFromIdCallback = $previousValue;
-               } );
-       }
-
-       private function getCacheKey( User $user, LinkTarget $target ) {
+       private function getCacheKey( UserIdentity $user, LinkTarget $target ) {
                return $this->cache->makeKey(
                        (string)$target->getNamespace(),
                        $target->getDBkey(),
@@ -176,7 +164,7 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
        }
 
        private function cache( WatchedItem $item ) {
-               $user = $item->getUser();
+               $user = $item->getUserIdentity();
                $target = $item->getLinkTarget();
                $key = $this->getCacheKey( $user, $target );
                $this->cache->set( $key, $item );
@@ -184,7 +172,7 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
                $this->stats->increment( 'WatchedItemStore.cache' );
        }
 
-       private function uncache( User $user, LinkTarget $target ) {
+       private function uncache( UserIdentity $user, LinkTarget $target ) {
                $this->cache->delete( $this->getCacheKey( $user, $target ) );
                unset( $this->cacheIndex[$target->getNamespace()][$target->getDBkey()][$user->getId()] );
                $this->stats->increment( 'WatchedItemStore.uncache' );
@@ -201,7 +189,7 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
                }
        }
 
-       private function uncacheUser( User $user ) {
+       private function uncacheUser( UserIdentity $user ) {
                $this->stats->increment( 'WatchedItemStore.uncacheUser' );
                foreach ( $this->cacheIndex as $ns => $dbKeyArray ) {
                        foreach ( $dbKeyArray as $dbKey => $userArray ) {
@@ -211,15 +199,19 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
                                }
                        }
                }
+
+               $pageSeenKey = $this->getPageSeenTimestampsKey( $user );
+               $this->latestUpdateCache->delete( $pageSeenKey );
+               $this->stash->delete( $pageSeenKey );
        }
 
        /**
-        * @param User $user
+        * @param UserIdentity $user
         * @param LinkTarget $target
         *
         * @return WatchedItem|false
         */
-       private function getCached( User $user, LinkTarget $target ) {
+       private function getCached( UserIdentity $user, LinkTarget $target ) {
                return $this->cache->get( $this->getCacheKey( $user, $target ) );
        }
 
@@ -227,12 +219,12 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
         * Return an array of conditions to select or update the appropriate database
         * row.
         *
-        * @param User $user
+        * @param UserIdentity $user
         * @param LinkTarget $target
         *
         * @return array
         */
-       private function dbCond( User $user, LinkTarget $target ) {
+       private function dbCond( UserIdentity $user, LinkTarget $target ) {
                return [
                        'wl_user' => $user->getId(),
                        'wl_namespace' => $target->getNamespace(),
@@ -256,11 +248,11 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
         *
         * @since 1.30
         *
-        * @param User $user
+        * @param UserIdentity $user
         *
         * @return bool true on success, false when too many items are watched
         */
-       public function clearUserWatchedItems( User $user ) {
+       public function clearUserWatchedItems( UserIdentity $user ) {
                if ( $this->countWatchedItems( $user ) > $this->updateRowsPerQuery ) {
                        return false;
                }
@@ -276,7 +268,7 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
                return true;
        }
 
-       private function uncacheAllItemsForUser( User $user ) {
+       private function uncacheAllItemsForUser( UserIdentity $user ) {
                $userId = $user->getId();
                foreach ( $this->cacheIndex as $ns => $dbKeyIndex ) {
                        foreach ( $dbKeyIndex as $dbKey => $userIndex ) {
@@ -305,9 +297,9 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
         *
         * @since 1.31
         *
-        * @param User $user
+        * @param UserIdentity $user
         */
-       public function clearUserWatchedItemsUsingJobQueue( User $user ) {
+       public function clearUserWatchedItemsUsingJobQueue( UserIdentity $user ) {
                $job = ClearUserWatchlistJob::newForUser( $user, $this->getMaxId() );
                $this->queueGroup->push( $job );
        }
@@ -328,10 +320,10 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
 
        /**
         * @since 1.31
-        * @param User $user
+        * @param UserIdentity $user
         * @return int
         */
-       public function countWatchedItems( User $user ) {
+       public function countWatchedItems( UserIdentity $user ) {
                $dbr = $this->getConnectionRef( DB_REPLICA );
                $return = (int)$dbr->selectField(
                        'watchlist',
@@ -390,16 +382,16 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
        }
 
        /**
-        * @param User $user
+        * @param UserIdentity $user
         * @param TitleValue[] $titles
         * @return bool
         * @throws MWException
         */
-       public function removeWatchBatchForUser( User $user, array $titles ) {
+       public function removeWatchBatchForUser( UserIdentity $user, array $titles ) {
                if ( $this->readOnlyMode->isReadOnly() ) {
                        return false;
                }
-               if ( $user->isAnon() ) {
+               if ( !$user->isRegistered() ) {
                        return false;
                }
                if ( !$titles ) {
@@ -559,12 +551,12 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
 
        /**
         * @since 1.27
-        * @param User $user
+        * @param UserIdentity $user
         * @param LinkTarget $target
         * @return bool
         */
-       public function getWatchedItem( User $user, LinkTarget $target ) {
-               if ( $user->isAnon() ) {
+       public function getWatchedItem( UserIdentity $user, LinkTarget $target ) {
+               if ( !$user->isRegistered() ) {
                        return false;
                }
 
@@ -579,13 +571,13 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
 
        /**
         * @since 1.27
-        * @param User $user
+        * @param UserIdentity $user
         * @param LinkTarget $target
         * @return WatchedItem|bool
         */
-       public function loadWatchedItem( User $user, LinkTarget $target ) {
-               // Only loggedin user can have a watchlist
-               if ( $user->isAnon() ) {
+       public function loadWatchedItem( UserIdentity $user, LinkTarget $target ) {
+               // Only registered user can have a watchlist
+               if ( !$user->isRegistered() ) {
                        return false;
                }
 
@@ -614,11 +606,11 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
 
        /**
         * @since 1.27
-        * @param User $user
+        * @param UserIdentity $user
         * @param array $options
         * @return WatchedItem[]
         */
-       public function getWatchedItemsForUser( User $user, array $options = [] ) {
+       public function getWatchedItemsForUser( UserIdentity $user, array $options = [] ) {
                $options += [ 'forWrite' => false ];
 
                $dbOptions = [];
@@ -660,27 +652,27 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
 
        /**
         * @since 1.27
-        * @param User $user
+        * @param UserIdentity $user
         * @param LinkTarget $target
         * @return bool
         */
-       public function isWatched( User $user, LinkTarget $target ) {
+       public function isWatched( UserIdentity $user, LinkTarget $target ) {
                return (bool)$this->getWatchedItem( $user, $target );
        }
 
        /**
         * @since 1.27
-        * @param User $user
+        * @param UserIdentity $user
         * @param LinkTarget[] $targets
         * @return array
         */
-       public function getNotificationTimestampsBatch( User $user, array $targets ) {
+       public function getNotificationTimestampsBatch( UserIdentity $user, array $targets ) {
                $timestamps = [];
                foreach ( $targets as $target ) {
                        $timestamps[$target->getNamespace()][$target->getDBkey()] = false;
                }
 
-               if ( $user->isAnon() ) {
+               if ( !$user->isRegistered() ) {
                        return $timestamps;
                }
 
@@ -724,27 +716,27 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
 
        /**
         * @since 1.27
-        * @param User $user
+        * @param UserIdentity $user
         * @param LinkTarget $target
         * @throws MWException
         */
-       public function addWatch( User $user, LinkTarget $target ) {
+       public function addWatch( UserIdentity $user, LinkTarget $target ) {
                $this->addWatchBatchForUser( $user, [ $target ] );
        }
 
        /**
         * @since 1.27
-        * @param User $user
+        * @param UserIdentity $user
         * @param LinkTarget[] $targets
         * @return bool
         * @throws MWException
         */
-       public function addWatchBatchForUser( User $user, array $targets ) {
+       public function addWatchBatchForUser( UserIdentity $user, array $targets ) {
                if ( $this->readOnlyMode->isReadOnly() ) {
                        return false;
                }
-               // Only logged-in user can have a watchlist
-               if ( $user->isAnon() ) {
+               // Only registered user can have a watchlist
+               if ( !$user->isRegistered() ) {
                        return false;
                }
 
@@ -795,53 +787,85 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
 
        /**
         * @since 1.27
-        * @param User $user
+        * @param UserIdentity $user
         * @param LinkTarget $target
         * @return bool
         * @throws MWException
         */
-       public function removeWatch( User $user, LinkTarget $target ) {
+       public function removeWatch( UserIdentity $user, LinkTarget $target ) {
                return $this->removeWatchBatchForUser( $user, [ $target ] );
        }
 
        /**
+        * Set the "last viewed" timestamps for certain titles on a user's watchlist.
+        *
+        * If the $targets parameter is omitted or set to [], this method simply wraps
+        * resetAllNotificationTimestampsForUser(), and in that case you should instead call that method
+        * directly; support for omitting $targets is for backwards compatibility.
+        *
+        * If $targets is omitted or set to [], timestamps will be updated for every title on the user's
+        * watchlist, and this will be done through a DeferredUpdate. If $targets is a non-empty array,
+        * only the specified titles will be updated, and this will be done immediately (not deferred).
+        *
         * @since 1.27
-        * @param User $user
-        * @param string|int $timestamp
-        * @param LinkTarget[] $targets
+        * @param UserIdentity $user
+        * @param string|int $timestamp Value to set the "last viewed" timestamp to (null to clear)
+        * @param LinkTarget[] $targets Titles to set the timestamp for; [] means the entire watchlist
         * @return bool
         */
-       public function setNotificationTimestampsForUser( User $user, $timestamp, array $targets = [] ) {
-               // Only loggedin user can have a watchlist
-               if ( $user->isAnon() ) {
+       public function setNotificationTimestampsForUser(
+               UserIdentity $user, $timestamp, array $targets = []
+       ) {
+               // Only registered user can have a watchlist
+               if ( !$user->isRegistered() || $this->readOnlyMode->isReadOnly() ) {
                        return false;
                }
 
-               $dbw = $this->getConnectionRef( DB_MASTER );
-
-               $conds = [ 'wl_user' => $user->getId() ];
-               if ( $targets ) {
-                       $batch = new LinkBatch( $targets );
-                       $conds[] = $batch->constructSet( 'wl', $dbw );
+               if ( !$targets ) {
+                       // Backwards compatibility
+                       $this->resetAllNotificationTimestampsForUser( $user, $timestamp );
+                       return true;
                }
 
+               $rows = $this->getTitleDbKeysGroupedByNamespace( $targets );
+
+               $dbw = $this->getConnectionRef( DB_MASTER );
                if ( $timestamp !== null ) {
                        $timestamp = $dbw->timestamp( $timestamp );
                }
+               $ticket = $this->lbFactory->getEmptyTransactionTicket( __METHOD__ );
+               $affectedSinceWait = 0;
 
-               $dbw->update(
-                       'watchlist',
-                       [ 'wl_notificationtimestamp' => $timestamp ],
-                       $conds,
-                       __METHOD__
-               );
+               // Batch update items per namespace
+               foreach ( $rows as $namespace => $namespaceTitles ) {
+                       $rowBatches = array_chunk( $namespaceTitles, $this->updateRowsPerQuery );
+                       foreach ( $rowBatches as $toUpdate ) {
+                               $dbw->update(
+                                       'watchlist',
+                                       [ 'wl_notificationtimestamp' => $timestamp ],
+                                       [
+                                               'wl_user' => $user->getId(),
+                                               'wl_namespace' => $namespace,
+                                               'wl_title' => $toUpdate
+                                       ]
+                               );
+                               $affectedSinceWait += $dbw->affectedRows();
+                               // Wait for replication every time we've touched updateRowsPerQuery rows
+                               if ( $affectedSinceWait >= $this->updateRowsPerQuery ) {
+                                       $this->lbFactory->commitAndWaitForReplication( __METHOD__, $ticket );
+                                       $affectedSinceWait = 0;
+                               }
+                       }
+               }
 
                $this->uncacheUser( $user );
 
                return true;
        }
 
-       public function getLatestNotificationTimestamp( $timestamp, User $user, LinkTarget $target ) {
+       public function getLatestNotificationTimestamp(
+               $timestamp, UserIdentity $user, LinkTarget $target
+       ) {
                $timestamp = wfTimestampOrNull( TS_MW, $timestamp );
                if ( $timestamp === null ) {
                        return null; // no notification
@@ -859,17 +883,22 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
                return $timestamp;
        }
 
-       public function resetAllNotificationTimestampsForUser( User $user ) {
-               // Only loggedin user can have a watchlist
-               if ( $user->isAnon() ) {
+       /**
+        * Schedule a DeferredUpdate that sets all of the "last viewed" timestamps for a given user
+        * to the same value.
+        * @param UserIdentity $user
+        * @param string|int|null $timestamp Value to set all timestamps to, null to clear them
+        */
+       public function resetAllNotificationTimestampsForUser( UserIdentity $user, $timestamp = null ) {
+               // Only registered user can have a watchlist
+               if ( !$user->isRegistered() ) {
                        return;
                }
 
                // If the page is watched by the user (or may be watched), update the timestamp
-               $job = new ClearWatchlistNotificationsJob(
-                       $user->getUserPage(),
-                       [ 'userId'  => $user->getId(), 'casTime' => time() ]
-               );
+               $job = new ClearWatchlistNotificationsJob( [
+                       'userId'  => $user->getId(), 'timestamp' => $timestamp, 'casTime' => time()
+               ] );
 
                // Try to run this post-send
                // Calls DeferredUpdates::addCallableUpdate in normal operation
@@ -883,12 +912,14 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
 
        /**
         * @since 1.27
-        * @param User $editor
+        * @param UserIdentity $editor
         * @param LinkTarget $target
         * @param string|int $timestamp
         * @return int[]
         */
-       public function updateNotificationTimestamp( User $editor, LinkTarget $target, $timestamp ) {
+       public function updateNotificationTimestamp(
+               UserIdentity $editor, LinkTarget $target, $timestamp
+       ) {
                $dbw = $this->getConnectionRef( DB_MASTER );
                $uids = $dbw->selectFieldValues(
                        'watchlist',
@@ -940,23 +971,36 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
 
        /**
         * @since 1.27
-        * @param User $user
-        * @param Title $title
+        * @param UserIdentity $user
+        * @param LinkTarget $title
         * @param string $force
         * @param int $oldid
         * @return bool
         */
-       public function resetNotificationTimestamp( User $user, Title $title, $force = '', $oldid = 0 ) {
+       public function resetNotificationTimestamp(
+               UserIdentity $user, LinkTarget $title, $force = '', $oldid = 0
+       ) {
                $time = time();
 
-               // Only loggedin user can have a watchlist
-               if ( $this->readOnlyMode->isReadOnly() || $user->isAnon() ) {
+               // Only registered user can have a watchlist
+               if ( $this->readOnlyMode->isReadOnly() || !$user->isRegistered() ) {
                        return false;
                }
 
-               if ( !Hooks::run( 'BeforeResetNotificationTimestamp', [ &$user, &$title, $force, &$oldid ] ) ) {
+               // Hook expects User and Title, not UserIdentity and LinkTarget
+               $userObj = User::newFromId( $user->getId() );
+               $titleObj = Title::castFromLinkTarget( $title );
+               if ( !Hooks::run( 'BeforeResetNotificationTimestamp',
+                       [ &$userObj, &$titleObj, $force, &$oldid ] )
+               ) {
                        return false;
                }
+               if ( !$userObj->equals( $user ) ) {
+                       $user = $userObj;
+               }
+               if ( !$titleObj->equals( $title ) ) {
+                       $title = $titleObj;
+               }
 
                $item = null;
                if ( $force != 'force' ) {
@@ -967,11 +1011,19 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
                }
 
                // Get the timestamp (TS_MW) of this revision to track the latest one seen
-               $seenTime = call_user_func(
-                       $this->revisionGetTimestampFromIdCallback,
-                       $title,
-                       $oldid ?: $title->getLatestRevID()
-               );
+               $id = $oldid;
+               $seenTime = null;
+               if ( !$id ) {
+                       $latestRev = $this->revisionLookup->getRevisionByTitle( $title );
+                       if ( $latestRev ) {
+                               $id = $latestRev->getId();
+                               // Save a DB query
+                               $seenTime = $latestRev->getTimestamp();
+                       }
+               }
+               if ( $seenTime === null ) {
+                       $seenTime = $this->revisionLookup->getTimestampFromId( $id );
+               }
 
                // Mark the item as read immediately in lightweight storage
                $this->stash->merge(
@@ -1016,10 +1068,10 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
        }
 
        /**
-        * @param User $user
+        * @param UserIdentity $user
         * @return MapCacheLRU|null The map contains prefixed title keys and TS_MW values
         */
-       private function getPageSeenTimestamps( User $user ) {
+       private function getPageSeenTimestamps( UserIdentity $user ) {
                $key = $this->getPageSeenTimestampsKey( $user );
 
                return $this->latestUpdateCache->getWithSetCallback(
@@ -1032,10 +1084,10 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
        }
 
        /**
-        * @param User $user
+        * @param UserIdentity $user
         * @return string
         */
-       private function getPageSeenTimestampsKey( User $user ) {
+       private function getPageSeenTimestampsKey( UserIdentity $user ) {
                return $this->stash->makeGlobalKey(
                        'watchlist-recent-updates',
                        $this->lbFactory->getLocalDomainID(),
@@ -1051,13 +1103,25 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
                return "{$target->getNamespace()}:{$target->getDBkey()}";
        }
 
-       private function getNotificationTimestamp( User $user, Title $title, $item, $force, $oldid ) {
+       /**
+        * @param UserIdentity $user
+        * @param LinkTarget $title
+        * @param WatchedItem $item
+        * @param bool $force
+        * @param int|bool $oldid The ID of the last revision that the user viewed
+        * @return bool|string|null
+        */
+       private function getNotificationTimestamp(
+               UserIdentity $user, LinkTarget $title, $item, $force, $oldid
+       ) {
                if ( !$oldid ) {
                        // No oldid given, assuming latest revision; clear the timestamp.
                        return null;
                }
 
-               if ( !$title->getNextRevisionID( $oldid ) ) {
+               $oldRev = $this->revisionLookup->getRevisionById( $oldid );
+               $nextRev = $this->revisionLookup->getNextRevision( $oldRev, $title );
+               if ( !$nextRev ) {
                        // Oldid given and is the latest revision for this title; clear the timestamp.
                        return null;
                }
@@ -1073,12 +1137,9 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
 
                // Oldid given and isn't the latest; update the timestamp.
                // This will result in no further notification emails being sent!
-               // Calls Revision::getTimestampFromId in normal operation
-               $notificationTimestamp = call_user_func(
-                       $this->revisionGetTimestampFromIdCallback,
-                       $title,
-                       $oldid
-               );
+               $notificationTimestamp = $this->revisionLookup->getTimestampFromId( $oldid );
+               // @FIXME: this should use getTimestamp() for consistency with updates on new edits
+               // $notificationTimestamp = $nextRev->getTimestamp(); // first unseen revision timestamp
 
                // We need to go one second to the future because of various strict comparisons
                // throughout the codebase
@@ -1100,11 +1161,11 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
 
        /**
         * @since 1.27
-        * @param User $user
+        * @param UserIdentity $user
         * @param int|null $unreadLimit
         * @return int|bool
         */
-       public function countUnreadNotifications( User $user, $unreadLimit = null ) {
+       public function countUnreadNotifications( UserIdentity $user, $unreadLimit = null ) {
                $dbr = $this->getConnectionRef( DB_REPLICA );
 
                $queryOptions = [];
@@ -1137,11 +1198,15 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
         * @param LinkTarget $newTarget
         */
        public function duplicateAllAssociatedEntries( LinkTarget $oldTarget, LinkTarget $newTarget ) {
-               $oldTarget = Title::newFromLinkTarget( $oldTarget );
-               $newTarget = Title::newFromLinkTarget( $newTarget );
-
-               $this->duplicateEntry( $oldTarget->getSubjectPage(), $newTarget->getSubjectPage() );
-               $this->duplicateEntry( $oldTarget->getTalkPage(), $newTarget->getTalkPage() );
+               // Duplicate first the subject page, then the talk page
+               $this->duplicateEntry(
+                       $this->nsInfo->getSubjectPage( $oldTarget ),
+                       $this->nsInfo->getSubjectPage( $newTarget )
+               );
+               $this->duplicateEntry(
+                       $this->nsInfo->getTalkPage( $oldTarget ),
+                       $this->nsInfo->getTalkPage( $newTarget )
+               );
        }
 
        /**
@@ -1191,7 +1256,7 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
        }
 
        /**
-        * @param TitleValue[] $titles
+        * @param LinkTarget[] $titles
         * @return array
         */
        private function getTitleDbKeysGroupedByNamespace( array $titles ) {
@@ -1204,10 +1269,10 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
        }
 
        /**
-        * @param User $user
-        * @param Title[] $titles
+        * @param UserIdentity $user
+        * @param LinkTarget[] $titles
         */
-       private function uncacheTitlesForUser( User $user, array $titles ) {
+       private function uncacheTitlesForUser( UserIdentity $user, array $titles ) {
                foreach ( $titles as $title ) {
                        $this->uncache( $user, $title );
                }
index 349d98a..1cf3288 100644 (file)
@@ -18,7 +18,9 @@
  * @file
  * @ingroup Watchlist
  */
+
 use MediaWiki\Linker\LinkTarget;
+use MediaWiki\User\UserIdentity;
 use Wikimedia\Rdbms\DBUnexpectedError;
 
 /**
@@ -43,11 +45,11 @@ interface WatchedItemStoreInterface {
         *
         * @since 1.31
         *
-        * @param User $user
+        * @param UserIdentity $user
         *
         * @return int
         */
-       public function countWatchedItems( User $user );
+       public function countWatchedItems( UserIdentity $user );
 
        /**
         * @since 1.31
@@ -115,29 +117,29 @@ interface WatchedItemStoreInterface {
         *
         * @since 1.31
         *
-        * @param User $user
+        * @param UserIdentity $user
         * @param LinkTarget $target
         *
         * @return WatchedItem|false
         */
-       public function getWatchedItem( User $user, LinkTarget $target );
+       public function getWatchedItem( UserIdentity $user, LinkTarget $target );
 
        /**
         * Loads an item from the db
         *
         * @since 1.31
         *
-        * @param User $user
+        * @param UserIdentity $user
         * @param LinkTarget $target
         *
         * @return WatchedItem|false
         */
-       public function loadWatchedItem( User $user, LinkTarget $target );
+       public function loadWatchedItem( UserIdentity $user, LinkTarget $target );
 
        /**
         * @since 1.31
         *
-        * @param User $user
+        * @param UserIdentity $user
         * @param array $options Allowed keys:
         *        'forWrite' => bool defaults to false
         *        'sort' => string optional sorting by namespace ID and title
@@ -145,24 +147,24 @@ interface WatchedItemStoreInterface {
         *
         * @return WatchedItem[]
         */
-       public function getWatchedItemsForUser( User $user, array $options = [] );
+       public function getWatchedItemsForUser( UserIdentity $user, array $options = [] );
 
        /**
         * Must be called separately for Subject & Talk namespaces
         *
         * @since 1.31
         *
-        * @param User $user
+        * @param UserIdentity $user
         * @param LinkTarget $target
         *
         * @return bool
         */
-       public function isWatched( User $user, LinkTarget $target );
+       public function isWatched( UserIdentity $user, LinkTarget $target );
 
        /**
         * @since 1.31
         *
-        * @param User $user
+        * @param UserIdentity $user
         * @param LinkTarget[] $targets
         *
         * @return array multi-dimensional like $return[$namespaceId][$titleString] = $timestamp,
@@ -170,54 +172,54 @@ interface WatchedItemStoreInterface {
         *         - string|null value of wl_notificationtimestamp,
         *         - false if $target is not watched by $user.
         */
-       public function getNotificationTimestampsBatch( User $user, array $targets );
+       public function getNotificationTimestampsBatch( UserIdentity $user, array $targets );
 
        /**
         * Must be called separately for Subject & Talk namespaces
         *
         * @since 1.31
         *
-        * @param User $user
+        * @param UserIdentity $user
         * @param LinkTarget $target
         */
-       public function addWatch( User $user, LinkTarget $target );
+       public function addWatch( UserIdentity $user, LinkTarget $target );
 
        /**
         * @since 1.31
         *
-        * @param User $user
+        * @param UserIdentity $user
         * @param LinkTarget[] $targets
         *
         * @return bool success
         */
-       public function addWatchBatchForUser( User $user, array $targets );
+       public function addWatchBatchForUser( UserIdentity $user, array $targets );
 
        /**
-        * Removes an entry for the User watching the LinkTarget
+        * Removes an entry for the UserIdentity watching the LinkTarget
         * Must be called separately for Subject & Talk namespaces
         *
         * @since 1.31
         *
-        * @param User $user
+        * @param UserIdentity $user
         * @param LinkTarget $target
         *
         * @return bool success
         * @throws DBUnexpectedError
         * @throws MWException
         */
-       public function removeWatch( User $user, LinkTarget $target );
+       public function removeWatch( UserIdentity $user, LinkTarget $target );
 
        /**
         * @since 1.31
         *
-        * @param User $user The user to set the timestamps for
+        * @param UserIdentity $user The user to set the timestamps for
         * @param string|null $timestamp Set the update timestamp to this value
         * @param LinkTarget[] $targets List of targets to update. Default to all targets
         *
         * @return bool success
         */
        public function setNotificationTimestampsForUser(
-               User $user,
+               UserIdentity $user,
                $timestamp,
                array $targets = []
        );
@@ -227,29 +229,30 @@ interface WatchedItemStoreInterface {
         *
         * @since 1.31
         *
-        * @param User $user The user to reset the timestamps for
+        * @param UserIdentity $user The user to reset the timestamps for
         */
-       public function resetAllNotificationTimestampsForUser( User $user );
+       public function resetAllNotificationTimestampsForUser( UserIdentity $user );
 
        /**
         * @since 1.31
         *
-        * @param User $editor The editor that triggered the update. Their notification
+        * @param UserIdentity $editor The editor that triggered the update. Their notification
         *  timestamp will not be updated(they have already seen it)
         * @param LinkTarget $target The target to update timestamps for
-        * @param string $timestamp Set the update timestamp to this value
+        * @param string $timestamp Set the update (first unseen revision) timestamp to this value
         *
         * @return int[] Array of user IDs the timestamp has been updated for
         */
-       public function updateNotificationTimestamp( User $editor, LinkTarget $target, $timestamp );
+       public function updateNotificationTimestamp(
+               UserIdentity $editor, LinkTarget $target, $timestamp );
 
        /**
         * Reset the notification timestamp of this entry
         *
         * @since 1.31
         *
-        * @param User $user
-        * @param Title $title
+        * @param UserIdentity $user
+        * @param LinkTarget $title
         * @param string $force Whether to force the write query to be executed even if the
         *    page is not watched or the notification timestamp is already NULL.
         *    'force' in order to force
@@ -258,18 +261,19 @@ interface WatchedItemStoreInterface {
         *
         * @return bool success Whether a job was enqueued
         */
-       public function resetNotificationTimestamp( User $user, Title $title, $force = '', $oldid = 0 );
+       public function resetNotificationTimestamp(
+               UserIdentity $user, LinkTarget $title, $force = '', $oldid = 0 );
 
        /**
         * @since 1.31
         *
-        * @param User $user
+        * @param UserIdentity $user
         * @param int|null $unreadLimit
         *
         * @return int|bool The number of unread notifications
         *                  true if greater than or equal to $unreadLimit
         */
-       public function countUnreadNotifications( User $user, $unreadLimit = null );
+       public function countUnreadNotifications( UserIdentity $user, $unreadLimit = null );
 
        /**
         * Check if the given title already is watched by the user, and if so
@@ -303,28 +307,28 @@ interface WatchedItemStoreInterface {
         *
         * @since 1.31
         *
-        * @param User $user
+        * @param UserIdentity $user
         */
-       public function clearUserWatchedItems( User $user );
+       public function clearUserWatchedItems( UserIdentity $user );
 
        /**
         * Queues a job that will clear the users watchlist using the Job Queue.
         *
         * @since 1.31
         *
-        * @param User $user
+        * @param UserIdentity $user
         */
-       public function clearUserWatchedItemsUsingJobQueue( User $user );
+       public function clearUserWatchedItemsUsingJobQueue( UserIdentity $user );
 
        /**
         * @since 1.32
         *
-        * @param User $user
+        * @param UserIdentity $user
         * @param LinkTarget[] $targets
         *
         * @return bool success
         */
-       public function removeWatchBatchForUser( User $user, array $targets );
+       public function removeWatchBatchForUser( UserIdentity $user, array $targets );
 
        /**
         * Convert $timestamp to TS_MW or return null if the page was visited since then by $user
@@ -335,9 +339,10 @@ interface WatchedItemStoreInterface {
         * Usage of this method should be limited to WatchedItem* classes
         *
         * @param string|null $timestamp Value of wl_notificationtimestamp from the DB
-        * @param User $user
+        * @param UserIdentity $user
         * @param LinkTarget $target
-        * @return string TS_MW timestamp or null
+        * @return string|null TS_MW timestamp of first unseen revision or null if there isn't one
         */
-       public function getLatestNotificationTimestamp( $timestamp, User $user, LinkTarget $target );
+       public function getLatestNotificationTimestamp(
+               $timestamp, UserIdentity $user, LinkTarget $target );
 }
index be6e676..02f369a 100644 (file)
@@ -30,8 +30,6 @@ class ExpiryInputWidget extends Widget {
         * @param array $options Configuration options
         */
        public function __construct( Widget $relativeInput, array $options = [] ) {
-               $config = \RequestContext::getMain()->getConfig();
-
                parent::__construct( $options );
 
                $this->required = $options['required'] ?? false;
index 6fed794..d4ffed2 100644 (file)
@@ -10,7 +10,6 @@ namespace MediaWiki\Widget;
  */
 class SearchInputWidget extends TitleInputWidget {
 
-       protected $pushPending = false;
        protected $performSearchOnClick = true;
        protected $validateTitle = false;
        protected $highlightFirst = false;
@@ -18,8 +17,6 @@ class SearchInputWidget extends TitleInputWidget {
 
        /**
         * @param array $config Configuration options
-        *   - int|null $config['pushPending'] Whether the input should be visually marked as
-        *     "pending", while requesting suggestions (default: false)
         *   - bool|null $config['performSearchOnClick'] If true, the script will start a search
         *     whenever a user hits a suggestion. If false, the text of the suggestion is inserted into
         *     the text field only (default: true)
@@ -35,10 +32,6 @@ class SearchInputWidget extends TitleInputWidget {
                parent::__construct( $config );
 
                // Properties, which are ignored in PHP and just shipped back to JS
-               if ( isset( $config['pushPending'] ) ) {
-                       $this->pushPending = $config['pushPending'];
-               }
-
                if ( isset( $config['performSearchOnClick'] ) ) {
                        $this->performSearchOnClick = $config['performSearchOnClick'];
                }
@@ -61,7 +54,6 @@ class SearchInputWidget extends TitleInputWidget {
        }
 
        public function getConfig( &$config ) {
-               $config['pushPending'] = $this->pushPending;
                $config['performSearchOnClick'] = $this->performSearchOnClick;
                if ( $this->dataLocation ) {
                        $config['dataLocation'] = $this->dataLocation;
index c0efd24..48c624c 100644 (file)
@@ -16,17 +16,17 @@ use OOUI;
  * the results are from.
  */
 class InterwikiSearchResultSetWidget implements SearchResultSetWidget {
-       /** @var SpecialSearch */
+       /** @var SpecialSearch $specialSearch */
        protected $specialSearch;
-       /** @var SearchResultWidget */
+       /** @var SearchResultWidget $resultWidget */
        protected $resultWidget;
-       /** @var string[]|null */
+       /** @var string[]|null $customCaptions */
        protected $customCaptions;
-       /** @var LinkRenderer */
+       /** @var LinkRenderer $linkRenderer */
        protected $linkRenderer;
-       /** @var InterwikiLookup */
+       /** @var InterwikiLookup $iwLookup */
        protected $iwLookup;
-       /** @var $output */
+       /** @var \OutputPage $output */
        protected $output;
        /** @var bool $showMultimedia */
        protected $showMultimedia;
index 4eead5e..095c30a 100644 (file)
@@ -30,7 +30,6 @@ class InterwikiSearchResultWidget implements SearchResultWidget {
         */
        public function render( SearchResult $result, $terms, $position ) {
                $title = $result->getTitle();
-               $iwPrefix = $result->getTitle()->getInterwiki();
                $titleSnippet = $result->getTitleSnippet();
                $snippet = $result->getTextSnippet( $terms );
 
index 5106c17..7c28b5e 100644 (file)
@@ -6,7 +6,6 @@ use Hooks;
 use Html;
 use MediaWiki\MediaWikiServices;
 use MediaWiki\Widget\SearchInputWidget;
-use MWNamespace;
 use SearchEngineConfig;
 use SpecialSearch;
 use Xml;
@@ -51,12 +50,15 @@ class SearchFormWidget {
                $offset,
                $isPowerSearch
        ) {
+               $user = $this->specialSearch->getUser();
+
                return '<div class="mw-search-form-wrapper">' .
                        Xml::openElement(
                                'form',
                                [
                                        'id' => $isPowerSearch ? 'powersearch' : 'search',
-                                       'method' => 'get',
+                                       // T151903: default to POST in case JS is disabled
+                                       'method' => ( $isPowerSearch && $user->isLoggedIn() ) ? 'post' : 'get',
                                        'action' => wfScript(),
                                ]
                        ) .
@@ -240,7 +242,8 @@ class SearchFormWidget {
                $activeNamespaces = $this->specialSearch->getNamespaces();
                $langConverter = $this->specialSearch->getLanguage();
                foreach ( $this->searchConfig->searchableNamespaces() as $namespace => $name ) {
-                       $subject = MWNamespace::getSubject( $namespace );
+                       $subject = MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               getSubject( $namespace );
                        if ( !isset( $rows[$subject] ) ) {
                                $rows[$subject] = "";
                        }
index 3362788..fad38e3 100644 (file)
@@ -7,7 +7,7 @@
        "--builtin-classes": true,
        "--processes": "0",
        "--warnings-exit-nonzero": true,
-       "--external": "Blob,File,HTMLDocument,HTMLElement,HTMLIframeElement,HTMLInputElement,KeyboardEvent,MouseEvent,Node,Window,XMLDocument",
+       "--external": "Blob,File,FileList,HTMLDocument,HTMLElement,HTMLIframeElement,HTMLInputElement,KeyboardEvent,MouseEvent,Node,Window,XMLDocument",
        "--output": "docs/js",
        "--exclude": [
                "resources/src/jquery.tablesorter",
index aaaf2a2..2262fa7 100644 (file)
@@ -27,6 +27,7 @@
  */
 
 use CLDRPluralRuleParser\Evaluator;
+use MediaWiki\MediaWikiServices;
 use Wikimedia\Assert\Assert;
 
 /**
@@ -506,7 +507,8 @@ class Language {
                if ( is_null( $this->namespaceNames ) ) {
                        global $wgMetaNamespace, $wgMetaNamespaceTalk, $wgExtraNamespaces;
 
-                       $validNamespaces = MWNamespace::getCanonicalNamespaces();
+                       $validNamespaces = MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               getCanonicalNamespaces();
 
                        $this->namespaceNames = $wgExtraNamespaces +
                                self::$dataCache->getItem( $this->mCode, 'namespaceNames' );
@@ -744,7 +746,8 @@ class Language {
         */
        public function getNsIndex( $text ) {
                $lctext = $this->lc( $text );
-               $ns = MWNamespace::getCanonicalIndex( $lctext );
+               $ns = MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       getCanonicalIndex( $lctext );
                if ( $ns !== null ) {
                        return $ns;
                }
@@ -1977,7 +1980,11 @@ class Language {
                                        $gy_offset = '元';
                                }
                                $gy_offset = '昭和' . $gy_offset;
-                       } else {
+                       } elseif (
+                               ( ( $gy == 1989 ) && ( $gm == 1 ) && ( $gd >= 8 ) ) ||
+                               ( ( $gy > 1989 ) && ( $gy < 2019 ) ) ||
+                               ( ( $gy == 2019 ) && ( $gm < 5 ) )
+                       ) {
                                # Heisei period
                                $gy_gannen = $gy - 1989 + 1;
                                $gy_offset = $gy_gannen;
@@ -1985,6 +1992,14 @@ class Language {
                                        $gy_offset = '元';
                                }
                                $gy_offset = '平成' . $gy_offset;
+                       } else {
+                               # Reiwa period
+                               $gy_gannen = $gy - 2019 + 1;
+                               $gy_offset = $gy_gannen;
+                               if ( $gy_gannen == 1 ) {
+                                       $gy_offset = '元';
+                               }
+                               $gy_offset = '令和' . $gy_offset;
                        }
                } else {
                        $gy_offset = $gy;
@@ -2713,7 +2728,7 @@ class Language {
        public function uc( $str, $first = false ) {
                if ( $first ) {
                        if ( $this->isMultibyte( $str ) ) {
-                               return mb_strtoupper( mb_substr( $str, 0, 1 ) ) . mb_substr( $str, 1 );
+                               return $this->mbUpperChar( mb_substr( $str, 0, 1 ) ) . mb_substr( $str, 1 );
                        } else {
                                return ucfirst( $str );
                        }
@@ -2722,6 +2737,28 @@ class Language {
                }
        }
 
+       /**
+        * Convert character to uppercase, allowing overrides of the default mb_upper
+        * behaviour, which is buggy in many ways. Having a conversion table can be
+        * useful during transitions between PHP versions where unicode changes happen.
+        * This can make some resources unreachable on-wiki, see discussion at T219279.
+        * Providing such a conversion table can allow to manage the transition period.
+        *
+        * @since 1.34
+        *
+        * @param string $char
+        *
+        * @return string
+        */
+       protected function mbUpperChar( $char ) {
+               global $wgOverrideUcfirstCharacters;
+               if ( array_key_exists( $char, $wgOverrideUcfirstCharacters ) ) {
+                       return $wgOverrideUcfirstCharacters[$char];
+               } else {
+                       return mb_strtoupper( $char );
+               }
+       }
+
        /**
         * @param string $str
         * @return mixed|string
@@ -2838,11 +2875,14 @@ class Language {
        }
 
        /**
+        * TODO: $s is not always a string per T218883
         * @param string $s
         * @return string
         */
        function checkTitleEncoding( $s ) {
-               Assert::parameterType( 'string', $s, '$s' );
+               if ( is_array( $s ) ) {
+                       throw new MWException( 'Given array to checkTitleEncoding.' );
+               }
                if ( StringUtils::isUtf8( $s ) ) {
                        return $s;
                }
@@ -2851,7 +2891,7 @@ class Language {
        }
 
        /**
-        * @return array
+        * @return string
         */
        function fallback8bitEncoding() {
                return self::$dataCache->getItem( $this->mCode, 'fallback8bitEncoding' );
@@ -2993,34 +3033,6 @@ class Language {
                }
        }
 
-       /**
-        * @deprecated No-op since 1.28
-        */
-       function initEncoding() {
-               wfDeprecated( __METHOD__, '1.28' );
-               // No-op.
-       }
-
-       /**
-        * @param string $s
-        * @return string
-        * @deprecated No-op since 1.28
-        */
-       function recodeForEdit( $s ) {
-               wfDeprecated( __METHOD__, '1.28' );
-               return $s;
-       }
-
-       /**
-        * @param string $s
-        * @return string
-        * @deprecated No-op since 1.28
-        */
-       function recodeInput( $s ) {
-               wfDeprecated( __METHOD__, '1.28' );
-               return $s;
-       }
-
        /**
         * Convert a UTF-8 string to normal form C. In Malayalam and Arabic, this
         * also cleans up certain backwards-compatible sequences, converting them
@@ -3512,8 +3524,8 @@ class Language {
         * Truncate a string to a specified number of characters, appending an optional
         * string (e.g. for ellipsis).
         *
-        * This provides multibyte version of truncate() method of this class, suitable for truncation
-        * based on number of characters, instead of number of bytes.
+        * This provides multibyte version of truncateForDatabase() method of this class,
+        * suitable for truncation based on number of characters, instead of number of bytes.
         *
         * If $length is negative, the string will be truncated from the beginning.
         *
@@ -3553,12 +3565,8 @@ class Language {
         * @return string
         */
        private function truncateInternal(
-               $string, $length, $ellipsis, $adjustLength, $measureLength, $getSubstring
+               $string, $length, $ellipsis, $adjustLength, callable $measureLength, callable $getSubstring
        ) {
-               if ( !is_callable( $measureLength ) || !is_callable( $getSubstring ) ) {
-                       throw new InvalidArgumentException( 'Invalid callback provided' );
-               }
-
                # Check if there is no need to truncate
                if ( $measureLength( $string ) <= abs( $length ) ) {
                        return $string; // no need to truncate
@@ -3698,6 +3706,7 @@ class Language {
                                        }
                                } elseif ( $dispLen > $length && $dispLen > strlen( $ellipsis ) ) {
                                        # String in fact does need truncation, the truncation point was OK.
+                                       // @phan-suppress-next-line PhanTypeInvalidExpressionArrayDestructuring
                                        list( $ret, $openTags ) = $maybeState; // reload state
                                        $ret = $this->removeBadCharLast( $ret ); // multi-byte char fix
                                        $ret .= $ellipsis; // add ellipsis
@@ -4020,15 +4029,12 @@ class Language {
         * Checks that convertPlural was given an array and pads it to requested
         * amount of forms by copying the last one.
         *
-        * @param array $forms Array of forms given to convertPlural
+        * @param array $forms
         * @param int $count How many forms should there be at least
-        * @return array Padded array of forms or an exception if not an array
+        * @return array Padded array of forms
         */
        protected function preConvertPlural( /* Array */ $forms, $count ) {
-               while ( count( $forms ) < $count ) {
-                       $forms[] = $forms[count( $forms ) - 1];
-               }
-               return $forms;
+               return array_pad( $forms, $count, end( $forms ) );
        }
 
        /**
@@ -4406,18 +4412,6 @@ class Language {
                return $this->mHtmlCode;
        }
 
-       /**
-        * @param string $code
-        * @deprecated since 1.32, use Language::factory to create a new object instead.
-        */
-       public function setCode( $code ) {
-               wfDeprecated( __METHOD__, '1.32' );
-               $this->mCode = $code;
-               // Ensure we don't leave incorrect cached data lying around
-               $this->mHtmlCode = null;
-               $this->mParentLanguage = false;
-       }
-
        /**
         * Get the language code from a file name. Inverse of getFileName()
         * @param string $filename $prefix . $languageCode . $suffix
@@ -4664,6 +4658,7 @@ class Language {
         *
         * @param int|float $seconds
         * @param array $format An optional argument that formats the returned string in different ways:
+        *   If $format['avoid'] === 'avoidhours': don't show hours, just show days
         *   If $format['avoid'] === 'avoidseconds': don't show seconds if $seconds >= 1 hour,
         *   If $format['avoid'] === 'avoidminutes': don't show seconds/minutes if $seconds > 48 hours,
         *   If $format['noabbrevs'] is true: use 'seconds' and friends instead of 'seconds-abbrev'
@@ -4722,12 +4717,19 @@ class Language {
                        $s = $hoursMsg->params( $this->formatNum( $hours ) )->text();
                        $s .= ' ';
                        $s .= $minutesMsg->params( $this->formatNum( $minutes ) )->text();
-                       if ( !in_array( $format['avoid'], [ 'avoidseconds', 'avoidminutes' ] ) ) {
+                       if ( !in_array( $format['avoid'], [ 'avoidseconds', 'avoidminutes', 'avoidhours' ] ) ) {
                                $s .= ' ' . $secondsMsg->params( $this->formatNum( $secondsPart ) )->text();
                        }
                } else {
                        $days = floor( $seconds / 86400 );
-                       if ( $format['avoid'] === 'avoidminutes' ) {
+                       if ( $format['avoid'] === 'avoidhours' ) {
+                               $hours = round( ( $seconds - $days * 86400 ) / 3600 );
+                               if ( $hours == 24 ) {
+                                       $hours = 0;
+                                       $days++;
+                               }
+                               $s = $daysMsg->params( $this->formatNum( $days ) )->text();
+                       } elseif ( $format['avoid'] === 'avoidminutes' ) {
                                $hours = round( ( $seconds - $days * 86400 ) / 3600 );
                                if ( $hours == 24 ) {
                                        $hours = 0;
@@ -4854,6 +4856,8 @@ class Language {
         * @param array $query Optional URL query parameter string
         * @param bool $atend Optional param for specified if this is the last page
         * @return string
+        * @deprecated since 1.33, use SpecialPage::viewPrevNext()
+        *  instead.
         */
        public function viewPrevNext( Title $title, $offset, $limit,
                array $query = [], $atend = false
index 8aa7c87..c5ff9d6 100644 (file)
@@ -60,7 +60,13 @@ class LanguageConverter {
        public $mVariantFallbacks;
        public $mVariantNames;
        public $mTablesLoaded = false;
+
+       /**
+        * @var ReplacementArray[]
+        * @phan-var array<string,ReplacementArray>
+        */
        public $mTables;
+
        // 'bidirectional' 'unidirectional' 'disable' for each variant
        public $mManualLevel;
 
index d695be1..a89dbc2 100644 (file)
@@ -63,9 +63,7 @@ class LanguageKk_cyrl extends Language {
                $secondPerson = [ "з" ]; // 1st plural, 2nd formal
                $thirdPerson = [ "ы", "і" ]; // 3rd
 
-               $lastLetter = $this->lastLetter( $word, $allVowels );
-               $wordEnding =& $lastLetter[0];
-               $wordLastVowel =& $lastLetter[1];
+               list( $wordEnding, $wordLastVowel ) = $this->lastLetter( $word, $allVowels );
 
                // Now convert the word
                switch ( $case ) {
@@ -297,9 +295,7 @@ class LanguageKk_cyrl extends Language {
                $secondPerson = [ "z" ]; // 1st plural, 2nd formal
                $thirdPerson = [ "ı", "i" ]; // 3rd
 
-               $lastLetter = $this->lastLetter( $word, $allVowels );
-               $wordEnding =& $lastLetter[0];
-               $wordLastVowel =& $lastLetter[1];
+               list( $wordEnding, $wordLastVowel ) = $this->lastLetter( $word, $allVowels );
 
                // Now convert the word
                switch ( $case ) {
@@ -531,9 +527,7 @@ class LanguageKk_cyrl extends Language {
                $secondPerson = [ "ز" ]; // 1st plural, 2nd formal
                $thirdPerson = [ "ى", "ٸ" ]; // 3rd
 
-               $lastLetter = $this->lastLetter( $word, $allVowels );
-               $wordEnding = $lastLetter[0];
-               $wordLastVowel = $lastLetter[1];
+               list( $wordEnding, $wordLastVowel ) = $this->lastLetter( $word, $allVowels );
 
                // Now convert the word
                switch ( $case ) {
@@ -737,7 +731,7 @@ class LanguageKk_cyrl extends Language {
 
        /**
         * @param string $word
-        * @param array $allVowels
+        * @param string[] $allVowels
         * @return array
         */
        function lastLetter( $word, $allVowels ) {
index 868b746..d7d5eec 100644 (file)
@@ -203,7 +203,7 @@ class Names {
                'hu' => 'magyar', # Hungarian
                'hu-formal' => "magyar (formal)\u{200E}", # Hungarian formal address
                'hy' => 'հայերեն', # Armenian, T202611
-               'hyw' => 'արեւմտահայերէն', # Western Armenian, T201276
+               'hyw' => 'Արեւմտահայերէն', # Western Armenian, T201276, T219975
                'hz' => 'Otsiherero', # Herero
                'ia' => 'interlingua', # Interlingua (IALA)
                'id' => 'Bahasa Indonesia', # Indonesian
@@ -223,7 +223,7 @@ class Names {
                'jam' => 'Patois', # Jamaican Creole English
                'jbo' => 'la .lojban.', # Lojban
                'jut' => 'jysk', # Jutish / Jutlandic
-               'jv' => 'Basa Jawa', # Javanese
+               'jv' => 'Jawa', # Javanese
                'ka' => 'ქართული', # Georgian
                'kaa' => 'Qaraqalpaqsha', # Karakalpak
                'kab' => 'Taqbaylit', # Kabyle
@@ -327,6 +327,7 @@ class Names {
                'nn' => 'norsk nynorsk', # Norwegian (Nynorsk)
                'no' => 'norsk', # Norwegian macro language (falls back to nb).
                'nov' => 'Novial', # Novial
+               'nqo' => 'ߒߞߏ', # N'Ko
                'nrm' => 'Nouormand', # Norman (invalid code; 'nrf' in ISO 639 since 2014)
                'nso' => 'Sesotho sa Leboa', # Northern Sotho
                'nv' => 'Diné bizaad', # Navajo
@@ -360,7 +361,7 @@ class Names {
                'rgn' => 'Rumagnôl', # Romagnol
                'rif' => 'Tarifit', # Tarifit
                'rm' => 'rumantsch', # Raeto-Romance
-               'rmy' => 'Romani', # Vlax Romany
+               'rmy' => 'romani čhib', # Vlax Romany
                'rn' => 'Kirundi', # Rundi/Kirundi/Urundi
                'ro' => 'română', # Romanian
                'roa-rup' => 'armãneashti', # Aromanian (deprecated code, 'rup' exists in ISO 639-3)
index 0240f85..e05b7a7 100644 (file)
@@ -2681,6 +2681,7 @@ public static $zh2Hant = [
 '𡭜' => '𡮉',
 '𡭬' => '𡮣',
 '𡶴' => '嵼',
+'𢀖' => '巠',
 '𢋈' => '㢝',
 '𢘝' => '𢣚',
 '𢘞' => '𢣭',
@@ -3703,7 +3704,6 @@ public static $zh2Hant = [
 '于小彤' => '于小彤',
 '于小惠' => '于小惠',
 '于少保' => '于少保',
-'于山' => '于山',
 '于山国' => '于山國',
 '于山國' => '于山國',
 '于帅' => '于帥',
@@ -3769,7 +3769,6 @@ public static $zh2Hant = [
 '于洪区' => '于洪區',
 '于洪區' => '于洪區',
 '于浩威' => '于浩威',
-'于海' => '于海',
 '于湘兰' => '于湘蘭',
 '于湘蘭' => '于湘蘭',
 '于汉超' => '于漢超',
@@ -3833,8 +3832,6 @@ public static $zh2Hant = [
 '于韦斯屈莱' => '于韋斯屈萊',
 '于風政' => '于風政',
 '于风政' => '于風政',
-'于飛' => '于飛',
-'于飞' => '于飛',
 '于余曲折' => '于餘曲折',
 '于鬯' => '于鬯',
 '于魁智' => '于魁智',
@@ -4267,7 +4264,6 @@ public static $zh2Hant = [
 '刮胡' => '刮鬍',
 '到山里' => '到山裡',
 '制冷机' => '制冷機',
-'制签' => '制籤',
 '制钟' => '制鐘',
 '刻半钟' => '刻半鐘',
 '刻多钟' => '刻多鐘',
@@ -4322,7 +4318,6 @@ public static $zh2Hant = [
 '勾心斗角' => '勾心鬥角',
 '勾魂荡魄' => '勾魂蕩魄',
 '包干' => '包幹',
-'包括' => '包括',
 '包准' => '包準',
 '包谷' => '包穀',
 '包扎' => '包紮',
@@ -4880,7 +4875,6 @@ public static $zh2Hant = [
 '好斗膽' => '好斗膽',
 '好斗蓬' => '好斗蓬',
 '好困' => '好睏',
-'好签' => '好籤',
 '好丑' => '好醜',
 '好斗' => '好鬥',
 '如果干' => '如果幹',
@@ -5656,7 +5650,7 @@ public static $zh2Hant = [
 '抑制' => '抑制',
 '抑郁' => '抑鬱',
 '抓奸' => '抓姦',
-'抓斗' => '抓',
+'抓斗' => '抓',
 '抗御' => '抗禦',
 '折子戏' => '折子戲',
 '折子戲' => '折子戲',
@@ -5828,9 +5822,9 @@ public static $zh2Hant = [
 '采种' => '採種',
 '采空区' => '採空區',
 '采空采穗' => '採空採穗',
-'采納' => '採納',
 '采纳' => '採納',
 '采给' => '採給',
+'采编' => '採編',
 '采花' => '採花',
 '采芹人' => '採芹人',
 '采茶' => '採茶',
@@ -5867,7 +5861,6 @@ public static $zh2Hant = [
 '提心吊胆' => '提心弔膽',
 '提摩太后书' => '提摩太後書',
 '提高后' => '提高後',
-'换签' => '換籤',
 '换只' => '換隻',
 '握发' => '握髮',
 '揩干' => '揩乾',
@@ -5996,13 +5989,6 @@ public static $zh2Hant = [
 '方便面' => '方便麵',
 '方向' => '方向',
 '方法里' => '方法裡',
-'于山东' => '於山東',
-'于山西' => '於山西',
-'于海上' => '於海上',
-'于海平面' => '於海平面',
-'于海拔' => '於海拔',
-'于海洋' => '於海洋',
-'于海边' => '於海邊',
 '于震中' => '於震中',
 '于震前' => '於震前',
 '于震后' => '於震後',
@@ -6071,7 +6057,9 @@ public static $zh2Hant = [
 '晒谷' => '曬穀',
 '曰云' => '曰云',
 '更仆难数' => '更僕難數',
-'更签' => '更籤',
+'更钟情' => '更鍾情',
+'更钟意' => '更鍾意',
+'更钟爱' => '更鍾愛',
 '更钟' => '更鐘',
 '书签' => '書籤',
 '书面' => '書面',
@@ -6135,6 +6123,7 @@ public static $zh2Hant = [
 '本庄' => '本庄',
 '本征' => '本徵',
 '本出戏' => '本齣戲',
+'术忽' => '朮忽',
 '术虎高' => '朮虎高',
 '术赤' => '朮赤',
 '朱庆余' => '朱慶餘',
@@ -6786,7 +6775,6 @@ public static $zh2Hant = [
 '田里' => '田裡',
 '田里穗' => '田里穗',
 '由余' => '由余',
-'由于' => '由於',
 '甲胄' => '甲冑',
 '甲后路' => '甲后路',
 '男仆' => '男僕',
@@ -6903,8 +6891,6 @@ public static $zh2Hant = [
 '盼复' => '盼覆',
 '看法里' => '看法裡',
 '看准' => '看準',
-'看表面' => '看表面',
-'看表' => '看錶',
 '看钟' => '看鐘',
 '真凶' => '真兇',
 '真个' => '真箇',
@@ -7164,7 +7150,6 @@ public static $zh2Hant = [
 '米团' => '米糰',
 '米余' => '米餘',
 '米面' => '米麵',
-'粉签子' => '粉籤子',
 '粗制' => '粗製',
 '精制伏' => '精制伏',
 '精制住' => '精制住',
@@ -8391,6 +8376,7 @@ public static $zh2Hant = [
 '鄉愿' => '鄉愿',
 '郑凯云' => '鄭凱云',
 '鄭凱云' => '鄭凱云',
+'郑苹如' => '鄭蘋如',
 '配制饲料' => '配制飼料',
 '配图里' => '配圖裡',
 '配制' => '配製',
@@ -8875,8 +8861,6 @@ public static $zh2Hant = [
 '风范' => '風範',
 '风里' => '風裡',
 '风起云涌' => '風起雲湧',
-'風采' => '風采',
-'风采' => '風采',
 '风刮' => '風颳',
 '台风' => '颱風',
 '台风后' => '颱風後',
@@ -9306,6 +9290,8 @@ public static $zh2Hant = [
 '鳥栖' => '鳥栖',
 '鳥栖市' => '鳥栖市',
 '鸟栖市' => '鳥栖市',
+'凤凰于飞' => '鳳凰于飛',
+'鳳凰于飛' => '鳳凰于飛',
 '凤梨干' => '鳳梨乾',
 '鸣钟' => '鳴鐘',
 '鸿范' => '鴻範',
@@ -10083,6 +10069,7 @@ public static $zh2Hans = [
 '巖' => '岩',
 '巗' => '岩',
 '巘' => '𪩘',
+'巠' => '𢀖',
 '巰' => '巯',
 '巵' => '卮',
 '帀' => '匝',
@@ -13981,6 +13968,7 @@ public static $zh2Hans = [
 '近角聪信' => '近角聪信',
 '造麴' => '造曲',
 '遺著' => '遗著',
+'鄭蘋如' => '郑苹如',
 '郭子乾' => '郭子乾',
 '酒麴' => '酒曲',
 '醉瀋' => '醉渖',
@@ -14299,7 +14287,6 @@ public static $zh2TW = [
 '机床' => '工具機',
 '機床' => '工具機',
 '珍寶客機' => '巨無霸客機',
-'发达国家' => '已開發國家',
 '巴塞罗那' => '巴塞隆納',
 '巴塞隆拿' => '巴塞隆納',
 '巴士拉' => '巴斯拉',
@@ -14402,6 +14389,7 @@ public static $zh2TW = [
 '旱烟' => '旱菸',
 '旱煙' => '旱菸',
 '普利策' => '普利茲',
+'普利策奖' => '普立茲獎',
 '芯片' => '晶片',
 '智能卡' => '智慧卡',
 '智能手机' => '智慧型手機',
@@ -14456,7 +14444,7 @@ public static $zh2TW = [
 '毛里裘斯' => '模里西斯',
 '樸茨茅夫' => '樸茨茅斯',
 '機械人' => '機器人',
-'率' => '機率',
+'率' => '機率',
 '電單車' => '機車',
 '枱' => '檯',
 '字段' => '欄位',
@@ -14498,7 +14486,8 @@ public static $zh2TW = [
 '熏肉' => '燻肉',
 '熏黑' => '燻黑',
 '版权信息' => '版權資訊',
-'疯牛症' => '狂牛症',
+'疯牛病' => '狂牛症',
+'瘋牛症' => '狂牛症',
 '鐵托' => '狄托',
 '铁托' => '狄托',
 '塞拉利昂' => '獅子山',
@@ -14550,6 +14539,7 @@ public static $zh2TW = [
 '私煙' => '私菸',
 '程序员' => '程式設計師',
 '编程语言' => '程式語言',
+'空中客车' => '空中巴士',
 '空气质量' => '空氣品質',
 '空氣質素' => '空氣品質',
 '突尼斯' => '突尼西亞',
@@ -14938,6 +14928,7 @@ public static $zh2HK = [
 '網際網路' => '互聯網',
 '井里' => '井裏',
 '亮著' => '亮着',
+'亮著《' => '亮著《',
 '亮著作' => '亮著作',
 '亮著名' => '亮著名',
 '亮著書' => '亮著書',
@@ -15235,6 +15226,7 @@ public static $zh2HK = [
 '保障著述' => '保障著述',
 '保障著錄' => '保障著錄',
 '信著' => '信着',
+'信著《' => '信著《',
 '信著作' => '信著作',
 '信著名' => '信著名',
 '信著書' => '信著書',
@@ -15305,6 +15297,7 @@ public static $zh2HK = [
 '凶殺' => '兇殺',
 '先占' => '先佔',
 '光著' => '光着',
+'光著《' => '光著《',
 '光著作' => '光著作',
 '光著名' => '光著名',
 '光著書' => '光著書',
@@ -15406,6 +15399,7 @@ public static $zh2HK = [
 '喀拉蚩' => '卡拉奇',
 '卡斯楚' => '卡斯特羅',
 '印著' => '印着',
+'印著《' => '印著《',
 '印著作' => '印著作',
 '印著名' => '印著名',
 '印著書' => '印著書',
@@ -15629,6 +15623,7 @@ public static $zh2HK = [
 '夢有五不占' => '夢有五不占',
 '梦有五不占' => '夢有五不占',
 '夢著' => '夢着',
+'夢著《' => '夢著《',
 '夢著作' => '夢著作',
 '夢著名' => '夢著名',
 '夢著書' => '夢著書',
@@ -15684,6 +15679,7 @@ public static $zh2HK = [
 '安地卡' => '安提瓜',
 '安地卡及巴布達' => '安提瓜和巴布達',
 '定著' => '定着',
+'定著《' => '定著《',
 '定著作' => '定著作',
 '定著名' => '定著名',
 '定著書' => '定著書',
@@ -15739,6 +15735,7 @@ public static $zh2HK = [
 '局里' => '局裏',
 '屋里' => '屋裏',
 '展著' => '展着',
+'展著《' => '展著《',
 '展著作' => '展著作',
 '展著名' => '展著名',
 '展著書' => '展著書',
@@ -15850,6 +15847,7 @@ public static $zh2HK = [
 '德勒斯登' => '德累斯頓',
 '澈底' => '徹底',
 '心著' => '心着',
+'心著《' => '心著《',
 '心著作' => '心著作',
 '心著名' => '心著名',
 '心著書' => '心著書',
@@ -15942,6 +15940,7 @@ public static $zh2HK = [
 '應著述' => '應著述',
 '應著錄' => '應著錄',
 '懷著' => '懷着',
+'懷著《' => '懷著《',
 '懷著作' => '懷著作',
 '懷著名' => '懷著名',
 '懷著書' => '懷著書',
@@ -16281,6 +16280,7 @@ public static $zh2HK = [
 '晃著者' => '晃著者',
 '晃著述' => '晃著述',
 '晃著錄' => '晃著錄',
+'普利策奖' => '普立茲獎',
 '晶元' => '晶片',
 '芯片' => '晶片',
 '智慧型' => '智能',
@@ -16395,6 +16395,7 @@ public static $zh2HK = [
 '榴莲' => '榴槤',
 '榴蓮' => '榴槤',
 '樂著' => '樂着',
+'樂著《' => '樂著《',
 '樂著作' => '樂著作',
 '樂著名' => '樂著名',
 '樂著書' => '樂著書',
@@ -16736,6 +16737,7 @@ public static $zh2HK = [
 '疑著述' => '疑著述',
 '疑著錄' => '疑著錄',
 '狂牛症' => '瘋牛症',
+'疯牛病' => '瘋牛症',
 '丹帕沙' => '登巴薩',
 '发布' => '發佈',
 '發布' => '發佈',
@@ -16747,6 +16749,7 @@ public static $zh2HK = [
 '發著者' => '發著者',
 '白里透红' => '白裏透紅',
 '戈登·布朗' => '白高敦',
+'百慕大' => '百慕達',
 '百科里' => '百科裏',
 '的图里' => '的圖裏',
 '的山里' => '的山裏',
@@ -16893,6 +16896,7 @@ public static $zh2HK = [
 '穩占' => '穩佔',
 '穫著' => '穫着',
 '空中布雷' => '空中佈雷',
+'空中客车' => '空中巴士',
 '空投布雷' => '空投佈雷',
 '空气质量' => '空氣質素',
 '空氣品質' => '空氣質素',
@@ -17902,14 +17906,6 @@ public static $zh2HK = [
 '牛轧' => '鳥結',
 '鳩占' => '鳩佔',
 '鸠占' => '鳩佔',
-'麗著' => '麗着',
-'麗著作' => '麗著作',
-'麗著名' => '麗著名',
-'麗著書' => '麗著書',
-'麗著稱' => '麗著稱',
-'麗著者' => '麗著者',
-'麗著述' => '麗著述',
-'麗著錄' => '麗著錄',
 '麼著' => '麼着',
 '芮氏0' => '黎克特制0',
 '里氏0' => '黎克特制0',
@@ -17962,7 +17958,10 @@ public static $zh2CN = [
 '16進位制' => '16进位制',
 '16進位' => '16进制',
 'IP位址' => 'IP地址',
+'乙個' => '一个',
+'乙份' => '一份',
 '一份子' => '一分子',
+'乙隻' => '一只',
 '全球資訊網' => '万维网',
 '三十六著' => '三十六着',
 '三極體' => '三极管',
@@ -18026,17 +18025,10 @@ public static $zh2CN = [
 '為著者' => '为著者',
 '為著述' => '为著述',
 '主機板' => '主板',
-'麗著' => '丽着',
-'麗著書' => '丽著书',
-'麗著作' => '丽著作',
-'麗著名' => '丽著名',
-'麗著錄' => '丽著录',
-'麗著稱' => '丽著称',
-'麗著者' => '丽著者',
-'麗著述' => '丽著述',
 '麼著' => '么着',
 '烏龍麵' => '乌冬面',
 '樂著' => '乐着',
+'樂著《' => '乐著《',
 '樂著書' => '乐著书',
 '樂著作' => '乐著作',
 '樂著名' => '乐著名',
@@ -18078,6 +18070,7 @@ public static $zh2CN = [
 '雅穆索戈' => '亚穆苏克罗',
 '交帳' => '交账',
 '亮著' => '亮着',
+'亮著《' => '亮著《',
 '亮著書' => '亮著书',
 '亮著作' => '亮著作',
 '亮著名' => '亮著名',
@@ -18108,6 +18101,8 @@ public static $zh2CN = [
 '代表著者' => '代表著者',
 '代表著述' => '代表著述',
 '乙太網' => '以太网',
+'份外卖' => '份外卖',
+'份外,' => '份外,',
 '伊莉莎白' => '伊丽莎白',
 '伊利諾' => '伊利诺伊',
 '伊利諾伊' => '伊利诺伊',
@@ -18181,6 +18176,7 @@ public static $zh2CN = [
 '資訊時代' => '信息时代',
 '資訊理論' => '信息论',
 '信著' => '信着',
+'信著《' => '信著《',
 '信著書' => '信著书',
 '信著作' => '信著作',
 '信著名' => '信著名',
@@ -18228,6 +18224,7 @@ public static $zh2CN = [
 '偷著述' => '偷著述',
 '傅利葉' => '傅里叶',
 '光著' => '光着',
+'光著《' => '光著《',
 '光著書' => '光著书',
 '光著作' => '光著作',
 '光著名' => '光著名',
@@ -18303,6 +18300,7 @@ public static $zh2CN = [
 '涼著述' => '凉著述',
 '湊合著' => '凑合着',
 '幾內亞比索' => '几内亚比绍',
+'機率' => '几率',
 '憑著' => '凭着',
 '憑著作' => '凭著作',
 '憑著名' => '凭著名',
@@ -18395,6 +18393,7 @@ public static $zh2CN = [
 '羅浮宮' => '卢浮宫',
 '羅亞爾' => '卢瓦尔',
 '印著' => '印着',
+'印著《' => '印著《',
 '印著書' => '印著书',
 '印著作' => '印著作',
 '印著名' => '印著名',
@@ -18423,7 +18422,6 @@ public static $zh2CN = [
 '發著名' => '发著名',
 '發著稱' => '发著称',
 '發著者' => '发著者',
-'已開發國家' => '发达国家',
 '受著' => '受着',
 '受著書' => '受著书',
 '受著作' => '受著作',
@@ -18697,6 +18695,7 @@ public static $zh2CN = [
 '安地卡及巴布達' => '安提瓜和巴布达',
 '巨集' => '宏',
 '定著' => '定着',
+'定著《' => '定著《',
 '定著書' => '定著书',
 '定著作' => '定著作',
 '定著名' => '定著名',
@@ -18732,6 +18731,7 @@ public static $zh2CN = [
 '區域網' => '局域网',
 '區域網路' => '局域网络',
 '展著' => '展着',
+'展著《' => '展著《',
 '展著書' => '展著书',
 '展著作' => '展著作',
 '展著名' => '展著名',
@@ -18855,6 +18855,7 @@ public static $zh2CN = [
 '德勒斯登' => '德累斯顿',
 '德希達' => '德里达',
 '心著' => '心着',
+'心著《' => '心著《',
 '心著書' => '心著书',
 '心著作' => '心著作',
 '心著名' => '心著名',
@@ -18881,6 +18882,7 @@ public static $zh2CN = [
 '忙著述' => '忙著述',
 '忠貞著' => '忠贞着',
 '懷著' => '怀着',
+'懷著《' => '怀著《',
 '懷著書' => '怀著书',
 '懷著作' => '怀著作',
 '懷著名' => '怀著名',
@@ -19271,6 +19273,7 @@ public static $zh2CN = [
 '晃著者' => '晃著者',
 '晃著述' => '晃著述',
 '普利茲' => '普利策',
+'普立茲獎' => '普利策奖',
 '蒲美蓬' => '普密蓬',
 '蒲朗克' => '普朗克',
 '電晶體' => '晶体管',
@@ -19372,6 +19375,7 @@ public static $zh2CN = [
 '森巴舞' => '桑巴舞',
 '梅赫西迪' => '梅赛德斯',
 '夢著' => '梦着',
+'夢著《' => '梦著《',
 '夢著書' => '梦著书',
 '夢著作' => '梦著作',
 '夢著名' => '梦著名',
@@ -19631,6 +19635,7 @@ public static $zh2CN = [
 '疑著者' => '疑著者',
 '疑著述' => '疑著述',
 '狂牛症' => '疯牛病',
+'瘋牛症' => '疯牛病',
 '徵狀' => '症状',
 '丹帕沙' => '登巴萨',
 '百慕達' => '百慕大',
@@ -19825,6 +19830,7 @@ public static $zh2CN = [
 '磁碟' => '磁盘',
 '磁軌' => '磁道',
 '福馬林' => '福尔马林',
+'富比士' => '福布斯',
 '福著' => '福着',
 '福著書' => '福著书',
 '福著作' => '福著作',
index 0fe2f4b..fb41de2 100644 (file)
@@ -3,7 +3,8 @@
                "authors": [
                        "Anok kutai jang",
                        "Bonaditya",
-                       "Matěj Suchánek"
+                       "Matěj Suchánek",
+                       "Mnam23"
                ]
        },
        "tog-oldsig": "Ale pung tanda tangan yang su ada:",
index 946b3ed..f052ccf 100644 (file)
@@ -29,6 +29,8 @@
        "tog-watchdefault": "Tamah laman nyang lôn peusaneut u dapeuta keunalon",
        "tog-watchmoves": "Tamah laman nyang lôn peupinah u dapeuta keunalon",
        "tog-watchdeletion": "Tamah laman nyang lôn sampôh u dapeuta keunalon",
+       "tog-watchuploads": "Tamah beureukah nyang lôn pasoe lam dapeuta kalön lôn",
+       "tog-watchrollback": "Tamah laman yang asoe lön peuriwang lam dapeuta kalön lôn",
        "tog-minordefault": "Bôh tanda mandum neuandam sibagoe neuandam bacut ngön baku",
        "tog-previewontop": "Peuleumah hasé yôh goh plôk peusaneut",
        "tog-previewonfirst": "Peuleumah hasé bak neuandam phôn",
        "october-date": "$1 Buleuen Siplôh",
        "november-date": "$1 Buleuen Siblaih",
        "december-date": "$1 Buleuen Duwa Blaih",
+       "period-am": "AM",
+       "period-pm": "PM",
        "pagecategories": "{{PLURAL:$1|Kawan}}",
        "category_header": "Seunurat lam kawan \"$1\"",
        "subcategories": "Aneuk kawan",
        "returnto": "Gisa u $1.",
        "tagline": "Nibak {{SITENAME}}",
        "help": "Beunantu",
+       "help-mediawiki": "Beunantu bhah MediaWiki",
        "search": "Mita",
        "searchbutton": "Mita",
        "go": "Jak u",
        "minoreditletter": "b",
        "newpageletter": "B",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 kalön {{PLURAL:$1|ureuëng ngui}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|bita}} lheueh neuubah",
        "newsectionsummary": "/* $1 */ bideung barô",
        "rc-enhanced-expand": "Peuleumah rincian",
index 0c06ebf..70e707b 100644 (file)
        "rev-deleted-event": "(فعل السجل تمت إزالته)",
        "rev-deleted-user-contribs": "[اسم المستخدم أو عنوان الأيبي تمت إزالته - التعديل مخفي من المساهمات]",
        "rev-deleted-text-permission": "'''حُذِفت''' مراجعة هذه الصفحة.\nيمكنك العثور على التفاصيل في [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سجل الحذف].",
-       "rev-deleted-text-unhide": "'''حُذِفت''' مراجعة الصفحة هذه.\nيمكن العثور على تفاصيل في [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سجل الحذف].\nمازال بإمكانك [$1 رؤية هذه المراجعة] إذا أردت المتابعة.",
+       "rev-deleted-text-unhide": "<strong>حُذِفت</strong> مراجعة الصفحة هذه.\nيمكن العثور على التفاصيل في [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سجل الحذف].\nمازال بإمكانك [$1 رؤية هذه المراجعة] إذا أردت المتابعة.",
        "rev-suppressed-text-unhide": "'''أُخفيت''' مراجعة الصفحة هذه.\nيمكنك العثور على التفاصيل في [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} سجل الإخفاء].\nبإمكانك [$1 رؤية هذه المراجعة] إذا أردت المتابعة.",
        "rev-deleted-text-view": "'''حُذِفت''' مراجعة هذه الصفحة.\nيمكنك رؤيتها؛ ويمكنك العثور على التفاصيل في [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سجل الحذف].",
        "rev-suppressed-text-view": "'''أُخفيت''' مراجعة الصفحة هذه.\nيمكنك رؤيتها؛ ويمكنك العثور على التفاصيل في  [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} سجل الإخفاء].",
        "revdelete-suppress": "أخف البيانات عن مديري النظام والبقية",
        "revdelete-unsuppress": "إزالة الضوابط من المراجعات المسترجعة",
        "revdelete-log": "السبب:",
-       "revdelete-submit": "طبق على {{PLURAL:$1||المراجعة المختارة|المراجعتين المختارتين|المراجعات المختارة}}",
+       "revdelete-submit": "تطبÙ\8aق على {{PLURAL:$1||المراجعة المختارة|المراجعتين المختارتين|المراجعات المختارة}}",
        "revdelete-success": "'''تم تحديث رؤية المراجعات بنجاح.'''",
        "revdelete-failure": "'''تعذر تحديث رؤية المراجعة:'''\n$1",
        "logdelete-success": "'''تم ضبط رؤية السجلات بنجاح.'''",
index 92a9e67..35eaba4 100644 (file)
        "rcfilters-filter-editsbyself-description": "U eie bydraes.",
        "rcfilters-filter-editsbyother-label": "Wysigings deur ander",
        "rcfilters-filter-editsbyother-description": "Alle wysigings behalwe u eie.",
-       "rcfilters-filtergroup-userExpLevel": "Registrasie en ervaring",
+       "rcfilters-filtergroup-user-experience-level": "Registrasie en ervaring",
        "rcfilters-filter-user-experience-level-registered-label": "Geregistreer",
        "rcfilters-filter-user-experience-level-registered-description": "Aangemelde redigeerders.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Ongeregistreer",
        "rcfilters-filter-categorization-description": "Wys kategorisering van bladsye.",
        "rcfilters-filter-logactions-label": "Geregistreerde aksies",
        "rcfilters-filter-logactions-description": "Administratiewe aksies, nuwe rekeninge, bladsyverwyderings, oplaaie…",
-       "rcfilters-filtergroup-lastRevision": "Nuutste weergawes",
+       "rcfilters-filtergroup-lastrevision": "Nuutste weergawes",
        "rcfilters-filter-lastrevision-label": "Nuutste weergawe",
        "rcfilters-filter-lastrevision-description": "Slegs die mees onlangse wysigings aan die bladsy.",
        "rcfilters-filter-previousrevision-label": "Nie die nuutste weergawe nie",
        "minoreditletter": "k",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|gebruiker|gebruikers}} hou die bladsy dop]",
        "rc-change-size-new": "$1 {{PLURAL:$1|greep|grepe}} na die wysiging",
        "newsectionsummary": "/* $1 */ nuwe afdeling",
        "rc-enhanced-expand": "Wys details",
        "img-auth-nopathinfo": "PATH_INFO word vermis.\nU bediener is nie ingestel om hierdie inligting deur te stuur nie.\nMiskien gebruik dit CGI, waartydens img_auth nie ondersteun word nie.\nSien https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization vir meer inligting.",
        "img-auth-notindir": "Die aangevraagde pad is nie die ingestelde oplaaigids nie.",
        "img-auth-badtitle": "Dit was nie moontlik om 'n geldige bladsynaam van \"$1\" te maak nie.",
-       "img-auth-nologinnWL": "U is nie aangeteken en \"$1\" is nie op die witlys nie.",
        "img-auth-nofile": "Lêer \"$1\" bestaan nie.",
        "img-auth-isdir": "U probeer om toegang na gids \"$1\" te kry.\nSlegs toegang tot lêers word toegelaat.",
        "img-auth-streaming": "Besig met die stoom van \"$1\".",
        "allmessagesdefault": "Verstekteks",
        "allmessagescurrent": "Huidige teks",
        "allmessagestext": "Hier is 'n lys boodskappe wat in die ''MediaWiki''-naamruimte teenwoordig is.\nGaan na [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki-lokalisasie] en [https://translatewiki.net translatewiki.net] as u wil help om MediaWiki te vertaal.",
-       "allmessagesnotsupportedDB": "Daar is geen ondersteuning vir '''{{ns:special}}:Allmessages''' omdat '''$wgUseDatabaseMessages''' uitgeskakel is.",
+       "allmessages-not-supported-database": "Daar is geen ondersteuning vir '''{{ns:special}}:Allmessages''' omdat '''$wgUseDatabaseMessages''' uitgeskakel is.",
        "allmessages-filter-legend": "Filter",
        "allmessages-filter": "Filtreer op staat van verandering:",
        "allmessages-filter-unmodified": "Onveranderd",
index ce46414..ca8d946 100644 (file)
        "rcfilters-hideminor-conflicts-typeofchange-global": "\"mikilulay mikawaway-kalumyiti\" a sakacucek nu misapili’ sasula’cus tu cacay saca yadah sumad nikalahizaan sakacucek nu misapili’,zayhan izaw hatizaay sumad nikalahizaan la’cus patuzu’ay tu \"mikilulay\". sasula’cusay a sakacucek nu misapili’ sacuzu’ tu i pabaw nu pisaungay a subal nu sakacucek nu misapili’.",
        "rcfilters-hideminor-conflicts-typeofchange": "izaw ku zumaay misumad nikalahizaan la’cus matuzu’ay mala \"mikilulay\", sisa tina sakacucek nu misapili’ atu isasa’ay a sumad nikalahizaan sakacucek nu misapili’ sasula’cus: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "tina misumad nikalahizaan sakacucek nu misapili’ atu \"mikilulay mikawaway-kalumyiti\" sakacucek nu misapili’sasula’cus, uzuma misumad nikalahizaan la’cus matuzu’ay ku \"mikilulay\"",
-       "rcfilters-filtergroup-lastRevision": "sabaluhay masumad",
+       "rcfilters-filtergroup-lastrevision": "sabaluhay masumad",
        "rcnotefrom": "isasa’ay a {{PLURAL:$5|ku}}nay <strong>$3 $4</strong> a sumad  (sayadah paazih <strong>$1</strong>).",
        "rclistfrom": "paazih nay $3 $2 baluhayay a sumad katukuh ayza",
        "rcshowhideminor": "$1 mikilulay mikawaway-kalumyiti",
        "minoreditletter": "adidi’",
        "newpageletter": "baluhay",
        "boteditletter": "kikay a tademaw",
-       "number_of_watching_users_pageview": "[$1 imahini miazihay a {{PLURAL:$1|misaungayay}}]",
        "rc-change-size-new": "masumadtu sa u $1 {{PLURAL:$1|wyiyincu}}",
        "newsectionsummary": "/* $1 */ baluhay a tusil",
        "rc-enhanced-expand": "paazih pulita kalunasulitan",
        "img-auth-nopathinfo": "caay kataneng PATH_INFO aazihen-sulyang.\nmilacul kisu sefu-kikay caay patudu’ tina cesyun,\nhakay kisu pisaungay CGI ku palana’an a sefu-kikay, zumasatu caay midama img_auth sasahicaan.\npiazih tu tatenga’ay  https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "masetin patapabaway a dilyikotoling piazihan-tu-sulit inayi’ matuzu’ay nu misu a pazazan.",
        "img-auth-badtitle": "la’cus pisaungay \"$1\" patizeng kapahay a satangahan.",
-       "img-auth-nologinnWL": "caay henay kisu patalabu, zumasatu \"$1\" inayi’ ilabu nu mahasa piazihan-tu-sulit.",
        "img-auth-nofile": "tangan \"$1\" inayi’.",
        "img-auth-isdir": "imahini kisu mitanam misuped-miala dilyikotoling \"$1\".\nmahasa dada’ misuped-miala tangan.",
        "img-auth-streaming": "pabahel \"$1\" henay ayza",
        "revertpage": "mapatiku tuway [[Special:Contributions/$2|$2]] ([[User talk:$2|sasukamu]]) a mikawaway-kalumyiti sazikuzay nay [[User:$1|$1]] amisumad nu ayaway a baziyong",
        "revertpage-nouser": "mapatiku tu midimut misaungayay ku mikawaway-kalumyiti malasazikuz {{GENDER:$1|[[User:$1|$1]]}} masumad nu ayaway a baziyong",
        "rollback-success": "mapatiku tuway {{GENDER:$3|$1}} mapasanga’ay a mikawaway-kalumyiti;\nmisumad tatiku nay {{GENDER:$4|$2}} masumad nu ayaway sazikuzay a baziyong.",
-       "rollback-success-notify": "mapatiku $1 nikawawan mikawaway-kalumyiti;\nmisumad patiku ta $2 masumad nu ayaway a sazikuz cacay baziyong. [$3 paazih ku masumaday]",
        "sessionfailure-title": "kasasiket mungangaw",
        "sessionfailure": "kisu patalabu kasasiketan mahiza simunday,\nsaka pataayaw-milangat kasasiketan maalaw atu madebung, tina saungay mapalawpes tuway.\npitatiku ayaway a kasabelih, miliyaw maasip kya kasabelih pitaneng aca.",
        "changecontentmodel": "misumad lacul tatudungen misanga’",
        "allmessagesdefault": "pataayaw tu kawaw palatuh  a sulit",
        "allmessagescurrent": "ayzaay palatuh a sulit",
        "allmessagestext": "tina kakitizaan pasilsil sacahamin i MediaWiki pangangananay a salaedanay a sisetyimo palatuh.\namahica kisu maydih mikileh mikuwanay a MediaWiki sanuniyazu’en, piazih tu tatenga’ay [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki sanuniyazu’en] atu [https://translatewiki.net translatewiki.net].",
-       "allmessagesnotsupportedDB": "mapasatezep tuway <strong>$wgUseDatabaseMessages</strong> setin, la’cus pisaungay tina kasabelih.",
+       "allmessages-not-supported-database": "mapasatezep tuway <strong>$wgUseDatabaseMessages</strong> setin, la’cus pisaungay tina kasabelih.",
        "allmessages-filter-legend": "kilim",
        "allmessages-filter": "kilul misumad zasatu mikilim:",
        "allmessages-filter-unmodified": "caay henay misumad",
index 57be5aa..ff59468 100644 (file)
        "recentchanges-label-bot": "ይኸው ለውጥ በሎሌ ተደረገ።",
        "recentchanges-label-unpatrolled": "ይህ እርማት ገና አልተገመገመም",
        "recentchanges-legend-newpage": "$1 - አዲስ ገጽ",
-       "rcfilters-filtergroup-lastRevision": "የመጨረሻ ክለሳ",
+       "rcfilters-filtergroup-lastrevision": "የመጨረሻ ክለሳ",
        "rcnotefrom": "ከ'''$2''' ጀምሮ የተቀየሩት ገጾች (እስከ '''$1''' ድረስ) ክዚህ በታች ይታያሉ።",
        "rclistfrom": "(ከ $3 $2 ጀምሮ አዲስ ለውጦቹን ለማየት)",
        "rcshowhideminor": "ጥቃቅን ለውጦች $1",
        "minoreditletter": "ጥ",
        "newpageletter": "አ",
        "boteditletter": "B",
-       "number_of_watching_users_pageview": "[$1 የሚከታተሉ {{PLURAL:$1|ተጠቃሚ|ተጠቃሚዎች}}]",
        "newsectionsummary": "/* $1 */ አዲስ ክፍል",
        "rc-enhanced-expand": "ዝርዝሩን አሳይ (JavaScript ያስፈልጋል)",
        "rc-enhanced-hide": "ዝርዝሩን ደብቅ",
        "allmessagesdefault": "የቆየው ጽሕፈት",
        "allmessagescurrent": "ያሁኑ ጽሕፈት",
        "allmessagestext": "በ«MediaWiki» ክፍለ-ዊኪ ያሉት የድረገጽ መልክ መልእክቶች ሙሉ ዝርዝር ይህ ነው።\nPlease visit [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] and [https://translatewiki.net translatewiki.net] if you wish to contribute to the generic MediaWiki localisation.",
-       "allmessagesnotsupportedDB": "'''$wgUseDatabaseMessages''' ስለ ተዘጋ '''{{ns:special}}:Allmessages''' ሊጠቀም አይችልም።",
+       "allmessages-not-supported-database": "!!FUZZY!!'''$wgUseDatabaseMessages''' ስለ ተዘጋ '''{{ns:special}}:Allmessages''' ሊጠቀም አይችልም።",
        "allmessages-filter-legend": "ማጣሪያ",
        "allmessages-filter-all": "ሁሉ",
        "allmessages-language": "ቋንቋ፦",
index 6df9834..b68265d 100644 (file)
        "rcfilters-activefilters-show": "pahapinang",
        "rcfilters-days-show-days": "$1 romi’ad",
        "rcfilters-savedqueries-cancel-label": "Sawaden miforic",
-       "rcfilters-filtergroup-lastRevision": "safaelohay a pisalof",
+       "rcfilters-filtergroup-lastrevision": "safaelohay a pisalof",
        "rcnotefrom": " i kalaenoay{{PLURAL:$5|為}}nani  <strong>$3 $4</strong> nifalican tangasa anini (saadihayay mipahapinangan i<strong>$1</strong> ko nisadakan a codad).",
        "rclistfrom": "pahapinang to faelohay a falic nano $3 $2",
        "rcshowhideminor": "$1 sapado^do^ a mikawit",
index e26fee0..f6435e7 100644 (file)
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|usuario|usuarios}} cosirando]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} dimpués d'o cambio",
        "newsectionsummary": "Nueva sección: /* $1 */",
        "rc-enhanced-expand": "Amostrar detalles",
        "img-auth-nopathinfo": "Falta PATH_INFO.\n O suyo servidor no ye configurau ta pasar ista información.\nPuet que siga basau en CGI y no siga compatible con img_auth.\nSe veiga l'autorización d'a imachen en https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization",
        "img-auth-notindir": "A rota solicitada no ye en o directorio de cargas configurau",
        "img-auth-badtitle": "No s'ha puesto construyir un títol valito dende \"$1\".",
-       "img-auth-nologinnWL": "No ha encetau sesión y \"$1\" no ye en a lista blanca.",
        "img-auth-nofile": "No existe l'archivo \"$1\".",
        "img-auth-isdir": "Ye mirando d'acceder ta un directorio \"$1\".\nNomás ye premitito l'acceso ta os fichers.",
        "img-auth-streaming": "Streaming (lectura contina) \"$1\".",
        "allmessagesdefault": "texto por defecto",
        "allmessagescurrent": "texto actual",
        "allmessagestext": "Ista ye una lista de totz os mensaches disponibles en o espacio de nombres MediaWiki.\nVesite por favor [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation a pachina sobre localización de MediaWiki] y  [https://translatewiki.net translatewiki.net] si deseya contrebuyir t'a localización cheneral de MediaWiki.",
-       "allmessagesnotsupportedDB": "Ista pachina no ye disponible porque wgUseDatabaseMessages ye desactivato.",
+       "allmessages-not-supported-database": "Ista pachina no ye disponible porque wgUseDatabaseMessages ye desactivato.",
        "allmessages-filter-legend": "Filtro",
        "allmessages-filter": "Filtrar por estau de personalización:",
        "allmessages-filter-unmodified": "Sin modificar",
index 91191b7..a0c8293 100644 (file)
        "talk": "Mōtung",
        "views": "Sihþa",
        "toolbox": "Tōl",
+       "tool-link-userrights": "Andwend {{GENDER:$1|brucend}} heapas",
+       "tool-link-userrights-readonly": "Gehawa {{GENDER:$1|brucend}} heapas",
+       "tool-link-emailuser": "Send þissum {{GENDER:$1|brucend}} hrædærendgewrite",
        "imagepage": "Sēon ymelan tramet",
        "mediawikipage": "Sēon ǣrendgewrita tramet",
        "templatepage": "Sēon bysene tramet",
        "jumptonavigation": "þurhfōr",
        "jumptosearch": "sēcan",
        "view-pool-error": "Wālā, þā þegntōlas nū oferlīce wyrcaþ.\nTō mænige brūcendas gesēcaþ tō sēonne þisne tramet.\nWē biddaþ þæt þū abīde scortne tīman ǣr þū gesēce to sēonne þisne tramet eft.\n\n$1",
+       "generic-pool-error": "Eala, in hwile tide sindon þa þeowan ofergeladen.\nTo fela brucenda onginnaþ to hehawian þis geteoh.\nIc bide þec þe þu bide beforan þe þu aginne eft togang þisses geteoh.",
+       "pool-timeout": "Endhwilsearu abideð þæt loc",
        "pool-queuefull": "Pundfaldes forepenn is full",
        "pool-errorunknown": "Uncūþ wōh",
-       "pool-servererror": "Seo pundfaldgetalere þēgnung nis gearo",
+       "pool-servererror": "Seo pundfaldgetalere þēgnung nis gearo ($1).",
        "aboutsite": "Gecȳþness ymbe {{GRAMMAR:wrēgendlīc|{{SITENAME}}}}",
        "aboutpage": "Project:Gefrǣge",
        "copyright": "Man mæg innunge under $1 findan, būton þǣr hit is elles amearcod.",
        "error": "Wōh",
        "databaseerror": "Cȳþþuhordes wōh",
        "databaseerror-textcl": "Gecyþneshordfræge misgedwild belamp",
+       "databaseerror-query": "Æsce: $1",
+       "databaseerror-function": "Wice: $1",
        "databaseerror-error": "Wōg: $1",
        "laggedslavemode": "'''Warnung:''' Wēnunga næbbe se tramet nīwlīca nīwunga.",
        "readonly": "Ġifhord locen",
        "filedeleteerror": "Ne cūðe forlēosan þā ymelan \"$1\".",
        "directorycreateerror": "We ne mot scieppan ymbfeng \"$1\"",
        "directoryreadonlyerror": "Ymbfeng \"$1\" is ræd-anlice",
-       "directorynotreadableerror": "Ymbfeng \"S1\" nis rædlic",
+       "directorynotreadableerror": "Ymbfeng \"$1\" nis rædlic",
        "filenotfound": "Ne cūðe findan ymelan \"$1\".",
        "unexpected": "Unbeþoht weorþ: \"$1\"=\"$2\"",
        "formerror": "Wōh: ne cūðe cȳþþugewrit forþsendan.",
index 161ae49..9739c49 100644 (file)
        "index-category": "صفحات مفهرسة",
        "noindex-category": "صفحات غير مفهرسة",
        "broken-file-category": "صفحات تحوي وصلات ملفات معطوبة",
+       "category-header-numerals": "$1–$2",
        "about": "عن",
        "article": "صفحة محتوى",
        "newwindow": "(تفتح في نافذة جديدة)",
        "virus-scanfailed": "فشل المسح (كود $1)",
        "virus-unknownscanner": "مضاد فيروسات غير معروف:",
        "logouttext": "<strong>أنت الآن غير مسجل الدخول.</strong> قد ترى بعض الصفحات كما لو أنك ما زلت مسجل الدخول، وذلك حتى تفرغ التخزين المؤقت في متصفحك.",
+       "logging-out-notify": "تم تسجيل خروجك، يرجى الانتظار.",
+       "logout-failed": "لا يمكن تسجيل الخروج الآن: $1",
        "cannotlogoutnow-title": "لا يمكن تسجيل الخروج الآن",
        "cannotlogoutnow-text": "لا يمكن تسجيل الخروج عند استخدام $1",
        "welcomeuser": "أهلاً بك يا $1!",
        "botpasswords-editexisting": "تعديل كلمة سر موجودة للبوت",
        "botpasswords-label-needsreset": "(تحتاج كلمة المرور إلى إعادة الضبط)",
        "botpasswords-label-appid": "اسم البوت:",
-       "botpasswords-label-create": "Ø£Ù\86شأ",
+       "botpasswords-label-create": "Ø¥Ù\86شاء",
        "botpasswords-label-update": "تحديث",
        "botpasswords-label-cancel": "ألغ",
        "botpasswords-label-delete": "احذف",
        "page_first": "الأولى",
        "page_last": "الأخيرة",
        "histlegend": "اختيار الفرق: علم على صناديق النسخ للمقارنة واضغط قارن بين النسخ المختارة أو الزر بالأسفل.<br />\nمفتاح: (الحالي) = الفرق مع النسخة الحالية\n(السابق) = الفرق مع النسخة السابقة، ط = تغيير طفيف",
-       "history-fieldset-title": "اÙ\84بحث Ø¹Ù\86 المراجعات",
+       "history-fieldset-title": "تصÙ\81Ù\8aØ© المراجعات",
        "history-show-deleted": "المحذوفة فقط",
        "histfirst": "الأقدم",
        "histlast": "الأحدث",
        "historysize": "({{PLURAL:$1|1 بايت|$1 بايت}})",
-       "historyempty": "(فارغة)",
+       "historyempty": "فارغة",
        "history-feed-title": "تاريخ المراجعة",
        "history-feed-description": "تاريخ التعديل لهذه الصفحة في الويكي",
        "history-feed-item-nocomment": "$1 في $2",
        "rev-deleted-user-contribs": "[اسم المستخدم أو عنوان الأيبي تمت إزالته - التعديل مخفي من المساهمات]",
        "rev-deleted-text-permission": "'''حُذِفت''' مراجعة هذه الصفحة.\nيمكنك العثور على التفاصيل في [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سجل الحذف].",
        "rev-suppressed-text-permission": "هذه النسخة قد <strong>أخفيت</strong> ([{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} تفاصيل].)",
-       "rev-deleted-text-unhide": "'''حُذِفت''' مراجعة الصفحة هذه.\nيمكن العثور على تفاصيل في [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سجل الحذف].\nمازال بإمكانك [$1 رؤية هذه المراجعة] إذا أردت المتابعة.",
+       "rev-deleted-text-unhide": "<strong>حُذِفت</strong> مراجعة الصفحة هذه.\nيمكن العثور على التفاصيل في [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سجل الحذف].\nمازال بإمكانك [$1 رؤية هذه المراجعة] إذا أردت المتابعة.",
        "rev-suppressed-text-unhide": "'''أُخفيت''' مراجعة الصفحة هذه.\nيمكنك العثور على التفاصيل في [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} سجل الإخفاء].\nبإمكانك [$1 رؤية هذه المراجعة] إذا أردت المتابعة.",
        "rev-deleted-text-view": "'''حُذِفت''' مراجعة هذه الصفحة.\nيمكنك رؤيتها؛ ويمكنك العثور على التفاصيل في [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سجل الحذف].",
        "rev-suppressed-text-view": "'''أُخفيت''' مراجعة الصفحة هذه.\nيمكنك رؤيتها؛ ويمكنك العثور على التفاصيل في  [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} سجل الإخفاء].",
        "revdelete-suppress": "أخف البيانات عن مديري النظام والبقية",
        "revdelete-unsuppress": "إزالة الضوابط من المراجعات المسترجعة",
        "revdelete-log": "السبب:",
-       "revdelete-submit": "طبق على {{PLURAL:$1||المراجعة المختارة|المراجعتين المختارتين|المراجعات المختارة}}",
+       "revdelete-submit": "تطبÙ\8aق على {{PLURAL:$1||المراجعة المختارة|المراجعتين المختارتين|المراجعات المختارة}}",
        "revdelete-success": "تم تحديث رؤية المراجعات بنجاح.",
        "revdelete-failure": "'''تعذر تحديث رؤية المراجعة:'''\n$1",
        "logdelete-success": "تم ضبط رؤية السجلات بنجاح.",
        "right-reupload-own": "الكتابة على ملف موجود تم رفعه بواسطة نفس المستخدم",
        "right-reupload-shared": "الرفع على الملفات في مستودع الملفات المشترك محليا",
        "right-upload_by_url": "رفع ملف من عنوان مسار",
-       "right-purge": "تحديث كاش الموقع لصفحة بدون تأكيد",
+       "right-purge": "تحديث كاش الموقع للصفحة",
        "right-autoconfirmed": "غير متأثر بحدود المعدل",
        "right-bot": "تعامل كعملية أوتوماتيكية",
        "right-nominornewtalk": "عدم جعل التعديلات الطفيفة لصفحات النقاش تظهر برواز الرسائل الجديدة",
        "action-changetags": "أضف وأزل وسوما في مراجعات ومدخلات سجل فردية",
        "action-deletechangetags": "حذف الوسوم من قاعدة البيانات",
        "action-purge": "إفراغ كاش هذه الصفحة",
+       "action-apihighlimits": "استخدام حدود أعلى في استعلامات API",
+       "action-autoconfirmed": "غير متأثر بحدود المعدل المستندة إلى الآيبي",
+       "action-bigdelete": "حذف الصفحات ذات التواريخ الكبيرة",
+       "action-blockemail": "منع مستخدم من إرسال بريد إلكتروني",
+       "action-bot": "يًعامَل كعملية آلية",
+       "action-editprotected": "تعديل الصفحات التي حمايتها \"{{int:protect-level-sysop}}\"",
+       "action-editsemiprotected": "تعديل الصفحات التي حمايتها \"{{int:protect-level-autoconfirmed}}\"",
+       "action-editinterface": "تعديل واجهة المستخدم",
+       "action-editusercss": "تعديل ملفات CSS للمستخدمين الآخرين",
+       "action-edituserjson": "تعديل ملفات جسون للمستخدمين الآخرين",
+       "action-edituserjs": "تعديل ملفات جافاسكريبت للمستخدمين الآخرين",
+       "action-editsitecss": "تحرير CSS للموقع بأكمله",
+       "action-editsitejson": "تعديل جسون على مستوى الموقع",
+       "action-editsitejs": "تعديل جافاسكريبت على مستوى الموقع",
+       "action-editmyusercss": "تحرير ملفات CSS المستخدم الخاصة بك",
+       "action-editmyuserjson": "تحرير ملفات جسون المستخدم الخاصة بك",
+       "action-editmyuserjs": "تحرير ملفات جافا سكريبت المستخدم الخاصة بك",
+       "action-viewsuppressed": "عرض المراجعات المخفية بواسطة أي مستخدم",
+       "action-hideuser": "منع اسم مستخدم، مخفيا إياه عن العامة",
+       "action-ipblock-exempt": "تفادي عمليات منع الأيبي والمنع التلقائي ومنع النطاق",
+       "action-unblockself": "رفع المنع عن أنفسهم",
+       "action-noratelimit": "غير متأثر بحدود المعدل",
+       "action-reupload-own": "الكتابة على ملف موجود تم رفعه بواسطة نفس المستخدم",
+       "action-nominornewtalk": "عدم وجود تعديلات طفيفة على صفحات النقاشة تؤدي إلى ظهور رسائل جديدة",
+       "action-markbotedits": "التعليم على تعديلات الاسترجاع كتعديلات بوت",
+       "action-patrolmarks": "رؤية علامات المراجعة في أحدث التغييرات",
+       "action-override-export-depth": "تصدير الصفحات متضمنة الصفحات الموصولة حتى عمق 5",
+       "action-suppressredirect": "عدم إنشاء تحويلة من الاسم القديم عند نقل صفحة",
        "nchanges": "{{PLURAL:$1|لا تغييرات|تغيير واحد|تغييران|$1 تغييرات|$1 تغييرا|$1 تغيير}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|منذ الزيارة الأخيرة}}",
        "enhancedrc-history": "تاريخ",
        "rcfilters-savedqueries-already-saved": "هذه المرشحات محفوظة بالفعل. غير إعداداتك لإنشاء مرشح محفوظ جديد.",
        "rcfilters-restore-default-filters": "استرجاع المرشحات الافتراضية",
        "rcfilters-clear-all-filters": "مسح كل المرشحات",
-       "rcfilters-show-new-changes": "عرض Ø£Ø­Ø¯Ø« Ø§Ù\84تغÙ\8aÙ\8aرات",
+       "rcfilters-show-new-changes": "عرض Ø§Ù\84تغÙ\8aÙ\8aرات Ø§Ù\84جدÙ\8aدة Ù\85Ù\86Ø° $1",
        "rcfilters-search-placeholder": "رشح التغييرات (استخدم القائمة أو ابحث عن اسم المرشح)",
        "rcfilters-invalid-filter": "مرشح غير صحيح",
        "rcfilters-empty-filter": "لا مرشحات فعالة. كل المساهمات معروضة.",
        "rcfilters-filter-editsbyself-description": "مساهماتك الشخصية.",
        "rcfilters-filter-editsbyother-label": "التغييرات بواسطة الآخرين",
        "rcfilters-filter-editsbyother-description": "كل التغييرات باستثناء تغييراتك.",
-       "rcfilters-filtergroup-userExpLevel": "تسجيل المستخدم وخبرته",
+       "rcfilters-filtergroup-user-experience-level": "تسجيل المستخدم وخبرته",
        "rcfilters-filter-user-experience-level-registered-label": "مسجل الدخول",
        "rcfilters-filter-user-experience-level-registered-description": "المحررون المسجلون.",
        "rcfilters-filter-user-experience-level-unregistered-label": "غير المسجلين",
        "rcfilters-hideminor-conflicts-typeofchange-global": "مرشح \"التعديلات الطفيفة\" يتعارض مع مرشح واحد أو أكثر من مرشحات نوع التغيير، وذلك لأن بعض أنواع التغيير لا يمكن التعليم عليها ك\"طفيفة.\" المرشحات المتعارضة معلم عليها في مساحة المرشحات النشطة بالأعلى.",
        "rcfilters-hideminor-conflicts-typeofchange": "بعض أنواع التغييرات لا يمكن التعليم عليها ك\"طفيفة،\" لذا فهذا المرشح يتعارض مع مرشحات نوع التغيير التالية: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "مرشح نوع التغيير هذا يتعارض مع مرشح \"التعديلات الطفيفة\". بعض أنواع التغييرات لا يمكن التعليم عليها ك\"طفيفة.\"",
-       "rcfilters-filtergroup-lastRevision": "أحدث المراجعات",
+       "rcfilters-filtergroup-lastrevision": "أحدث المراجعات",
        "rcfilters-filter-lastrevision-label": "آخر مراجعة",
        "rcfilters-filter-lastrevision-description": "فقط أحدث التغييرات التي طرأت على الصفحة.",
        "rcfilters-filter-previousrevision-label": "ليس آخر مراجعة",
        "minoreditletter": "ط",
        "newpageletter": "ج‌",
        "boteditletter": "ب",
-       "number_of_watching_users_pageview": "[{{PLURAL:$1|لا مستخدمون يراقبون|مستخدم واحد يراقب|مستخدمان يراقبان|$1 مستخدمين يراقبون|$1 مستخدما يراقب|$1 مستخدم يراقب}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|بايت|بايت}} بعد التغيير",
        "newsectionsummary": "/* $1 */ قسم جديد",
        "rc-enhanced-expand": "عرض التفاصيل",
        "recentchanges-page-removed-from-category-bundled": "أزيلت [[:$1]] من التصنيف، [[Special:WhatLinksHere/$1|هذه الصفحة مضمنة في صفحات أخرى]]",
        "autochange-username": "تغيير آلي لميدياويكي",
        "upload": "رفع ملف",
-       "uploadbtn": "ارÙ\81ع Ø§Ù\84Ù\85Ù\84Ù\81",
+       "uploadbtn": "رفع الملف",
        "reuploaddesc": "إلغاء الرفع والرجوع إلى استمارة الرفع",
        "upload-tryagain": "أرسل وصف ملف معدل",
        "upload-tryagain-nostash": "ارفع الملف المعاد رفعه والوصف المعدل",
        "img-auth-nopathinfo": "معلومات المسار مفقودة;\nيجب إعداد خادمك لتمرير المتغير REQUEST_URI و/أو PATH_INFO variables،\nإذا كان كذلك، فحاول تمكين $wgUsePathInfo،\nانظر https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "المسار المطلوب غير موجود في مجلد الرفع المضبوط.",
        "img-auth-badtitle": "تعذر تشكيل عنوان صالح من \"$1\".",
-       "img-auth-nologinnWL": "لست والجا و\"$1\" ليست في القائمة البيضاء.",
        "img-auth-nofile": "الملف \"$1\" غير موجود.",
        "img-auth-isdir": "أنت تحاول الوصول إلى الدليل \"$1\".\nيسمح بوصول الملفات فقط.",
        "img-auth-streaming": "عرض \"$1\".",
        "delete-confirm": "حذف \"$1\"",
        "delete-legend": "حذف",
        "historywarning": "'''تنبيه:''' الصفحة التي تريد حذفها بها {{PLURAL:$1|نسخة|نسخة واحدة|نسختان|$1 نسخ|$1 نسخة}}. انظر",
-       "historyaction-submit": "أظÙ\87ر",
+       "historyaction-submit": "عرض Ø§Ù\84Ù\85راجعات",
        "confirmdeletetext": "أنت على وشك أن تقوم بحذف صفحة بالإضافة إلى كل تاريخها.\nمن فضلك التأكد من عزمك على الحذف، وبأنك مدرك للعواقب، وبأنك تقوم بهذا بالتوافق مع [[{{MediaWiki:Policy-url}}|السياسة]].",
        "actioncomplete": "انتهاء العملية",
        "actionfailed": "الفعل فشل",
        "deleting-backlinks-warning": "<strong>تحذير:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|صفحات أخرى]] تصل إلى أو تضمن الصفحة التي أنت على وشك حذفها.",
        "deleting-subpages-warning": "<strong>تحذير:</strong> الصفحة التي على وشك أن تحذفها لديها [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|صفحة فرعية|$1 صفحات فرعية|51=أكثر من 50 صفحة فرعية}}]].",
        "rollback": "التراجع عن التعديلات",
+       "rollback-confirmation-confirm": "يُرجى التأكيد:",
+       "rollback-confirmation-yes": "استرجاع",
+       "rollback-confirmation-no": "إلغاء",
        "rollbacklink": "استرجع",
        "rollbacklinkcount": "استرجع {{PLURAL:$1|لا تعديلات|تعديلا واحدا|تعديلين|$1 تعديلات|$1 تعديلاً|تعديل}}",
        "rollbacklinkcount-morethan": "استرجاع أكثر من {{PLURAL:$1|تعديل|تعديل|تعديلين|$1 تعديلات|$1 تعديلاً|$1 تعديل}}",
        "revertpage": "استرجع تعديلات [[Special:Contributions/$2|$2]] ([[User talk:$2|نقاش]]) حتى آخر مراجعة ل[[User:$1|$1]]",
        "revertpage-nouser": "استرجع تعديلات مستخدم مخفي حتى آخر مراجعة ل{{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "تم استرجاع تعديلات {{GENDER:$3|$1}}، حتى آخر نسخة بواسطة {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "تم استرجاع التعديلات بواسطة $1;\nتم التغيير إلى آخر مراجعة بواسطة $2. [$3 عرض التغييرات]",
        "sessionfailure-title": "فشل في الجلسة",
        "sessionfailure": "يبدو أنه هناك مشكلة في جلسة الدخول الخاصة بك؛\nلذلك فقد ألغيت هذه العملية كإجراء احترازي ضد الاختراق.\nمن فضلك أعد إرسال الاستمارة مرة أخرى.",
        "changecontentmodel": "تغيير نموذج المحتوى لصفحة",
        "mycontris": "مساهمات",
        "anoncontribs": "مساهمات",
        "contribsub2": "ل{{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "لـ{{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "حساب المستخدم \"$1\" غير مسجل.",
        "negative-namespace-not-supported": "النطاقات ذات القيم السالبة غير مدعومة.",
        "nocontribs": "لم يتم العثور على تغييرات تطابق هذه المحددات.",
        "blocklist-userblocks": "أخفِ منع الحسابات",
        "blocklist-tempblocks": "أخفِ المنع المؤقت",
        "blocklist-addressblocks": "أخفِ منع عنوان أيبي واحد",
+       "blocklist-type": "النوع:",
+       "blocklist-type-opt-all": "الكل",
+       "blocklist-type-opt-sitewide": "على مستوى الموقع",
+       "blocklist-type-opt-partial": "جزئي",
        "blocklist-rangeblocks": "أخفِ منع النطاقات",
        "blocklist-timestamp": "الزمن",
        "blocklist-target": "الهدف",
        "blocklist-editing-page": "الصفحات",
        "blocklist-editing-ns": "النطاقات",
        "ipblocklist-empty": "قائمة المنع فارغة.",
-       "ipblocklist-no-results": "عنوان الأيبي أو اسم المستخدم المطلوب غير ممنوع.",
+       "ipblocklist-no-results": "لم يتم العثور على عمليات منع مطابقة لعنوان الأيبي أو اسم المستخدم المطلوب.",
        "blocklink": "امنع",
        "unblocklink": "ارفع المنع",
        "change-blocklink": "تغيير المنع",
+       "empty-username": "(لا يوجد اسم مستخدم متاح)",
        "contribslink": "مساهمات",
        "emaillink": "أرسل بريدا إلكترونيا",
        "autoblocker": "تم منعك تلقائيا لأن الأيبي الخاص بك تم استخدامه مؤخرا بواسطة \"[[User:$1|$1]]\".\nالسبب المعطى لمنع $1 هو: \"$2\"",
        "allmessagesdefault": "النص الافتراضي",
        "allmessagescurrent": "النص الحالي",
        "allmessagestext": "هذه قائمة برسائل النظام المتوفرة في نطاق ميدياويكي.\nمن فضلك زر [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation ترجمة ميدياويكي] و [https://translatewiki.net ترانسليت ويكي دوت نت] لو كنت ترغب في المساهمة في ترجمة ميدياويكي الأساسية.",
-       "allmessagesnotsupportedDB": "هذه الصفحة لا يمكن استخدامها لأن '''$wgUseDatabaseMessages''' تم تعطيله.",
+       "allmessages-not-supported-database": "هذه الصفحة لا يمكن استخدامها لأن '''$wgUseDatabaseMessages''' تم تعطيله.",
        "allmessages-filter-legend": "المرشح",
        "allmessages-filter": "رشح حسب حالة التخصيص:",
        "allmessages-filter-unmodified": "غير معدل",
        "confirmemail_pending": "تم إرسال كود التأكيد إلى بريدك الإلكتروني مؤخراً؛\nإذا كنت قد أنشأت حسابك للتو، من الأفضل أن تنتظر بضع دقائق قبل أن تطلب كوداً آخر.",
        "confirmemail_send": "أرسل كود تأكيد",
        "confirmemail_sent": "تم إرسال رسالة التأكيد، شكرا لك.",
-       "confirmemail_oncreate": "تم إرسال كود تأكيد إلى عنوان بريدك الإلكتروني.\nالكود غير مطلوب للدخول إلى الموسوعة باسمك، ولكن يجب إدخاله قبل استخدامك أياً من خواص البريد الإلكتروني المستخدمة هنا في الويكي.",
+       "confirmemail_oncreate": "تم إرسال كود تأكيد إلى عنوان بريدك الإلكتروني.\nالكود غير مطلوب للدخول، ولكن يجب إدخاله قبل استخدامك أيًّا من خواص البريد الإلكتروني المستخدمة هنا في الويكي.",
        "confirmemail_sendfailed": "لم يتمكن {{SITENAME}} من إرسال رسالة التأكيد إليك.\nمن فضلك تأكد من عنوان بريدك الإلكتروني بحثاً عن حروف غير صحيحة.\n\nأرجع خادم البريد: $1",
        "confirmemail_invalid": "كود تأكيد غير صحيح.\nربما انتهت فترة صلاحيته.",
        "confirmemail_needlogin": "يجب عليك $1 لتأكيد بريدك الإلكتروني.",
        "confirm-unwatch-top": "إزالة هذه الصفحة من قائمة مراقبتك؟",
        "confirm-rollback-button": "موافق",
        "confirm-rollback-top": "استرجاع التعديلات لهذه الصفحة؟",
+       "confirm-rollback-bottom": "هذا الإجراء سيسترجع فورا التغييرات المحددة في هذه الصفحة.",
        "confirm-mcrrestore-title": "استرجاع مراجعة",
        "confirm-mcrundo-title": "الرجوع عن تغيير",
        "mcrundofailed": "الرجوع فشل",
        "passwordpolicies-policyflag-forcechange": "يجب أن تتغير عند تسجيل الدخول",
        "passwordpolicies-policyflag-suggestchangeonlogin": "اقتراح التغيير عند تسجيل الدخول",
        "easydeflate-invaliddeflate": "المحتوى المقدم لا يتم تفريغه بشكل صحيح",
-       "unprotected-js": "لأسباب تتعلق بالأمان; لا يمكن تحميل جافا سكريبت من الصفحات غير المحمية; الرجاء إنشاء جافا سكريبت فقط في نطاق ميدياويكي: أو كصفحة فرعية للمستخدم"
+       "unprotected-js": "لأسباب تتعلق بالأمان; لا يمكن تحميل جافا سكريبت من الصفحات غير المحمية; الرجاء إنشاء جافا سكريبت فقط في نطاق ميدياويكي: أو كصفحة فرعية للمستخدم",
+       "userlogout-continue": "إذا كنت ترغب في تسجيل الخروج، تُرجَى [$1 المتابعة إلى صفحة تسجيل الخروج].",
+       "userlogout-sessionerror": "فشل تسجيل الخروج بسبب خطأ في الجلسة، تُرجَى [$1 المحاولة مرة أخرى]."
 }
index 4f744e2..78f7f9f 100644 (file)
        "minoreditletter": "p",
        "newpageletter": "W",
        "boteditletter": "küdauwe",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|Kellufe|Kellufe}} wiñamüy]",
        "rc-enhanced-expand": "Adkintun doy dungu (JavaScript duamyengey)",
        "rc-enhanced-hide": "Ellkan doy dungu",
        "recentchangeslinked": "Koneltuyelelu kalekünulu wirin",
index f9a01ad..611627a 100644 (file)
        "cancel": "lġi",
        "moredotdotdot": "Kṫer...",
        "mypage": "'Ṣ-Ṣefḫa dyali",
-       "mytalk": "Ṣefḫa dyal n-niqaċ",
+       "mytalk": "صفحة ديال النقاش",
        "anontalk": "hdr maa had l'ip",
        "navigation": "Navigasyon",
        "and": "&#32;o",
        "search-external": "Qeleb ĝla bera",
        "searchdisabled": "{{SITENAME}} ma ĥedamċ.\nImken lik ṫqeleb fe google.\nLaḫed ana imken ikono l-indexaṫ dial {{SITENAME}} qdam o ma bqaoċ ṣalḫin.",
        "preferences": "ṫfḍilaṫ",
-       "mypreferences": "Ḫajaṫ li kanfeḍḍel",
+       "mypreferences": "حاجات اللي كانفضل",
        "prefs-edits": "ĝadad ṫ-ṫĝdilaṫ:",
        "prefs-skin": "skin",
        "skin-preview": "L-Prévizualizasyon",
        "rcshowhidebots-show": "وري",
        "rcshowhidebots-hide": "خبي",
        "rcshowhideliu": "$1 l-mosṫeĥdimin l-mċejjlin",
+       "rcshowhideliu-show": "وري",
        "rcshowhideliu-hide": "خبي",
        "rcshowhideanons": "$1 mosṫeĥdimin mĥebbyin",
        "rcshowhideanons-hide": "خبي",
        "minoreditletter": "ṣ",
        "newpageletter": "J",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 katchof  {{PLURAL:$1|mostkhdim|mostkhdimin}}]",
        "rc-change-size": "$1",
        "newsectionsummary": "/* $1 */ qism jdid",
        "rc-enhanced-expand": "Werri ṫ-ṫafaṣil (kayḫṫaj JavaScript)",
        "uploadstash-refresh": "aktwalizi qa'imaṫ l-milffaṫ",
        "img-auth-accessdenied": "lwosol trfd",
        "img-auth-badtitle": "ma ymkn-ċ ṫsayb ċi ĝonwan ṣḫiḫ mn \"$1\".",
-       "img-auth-nologinnWL": "ma rak-ċ daĥol o-\"$1\" maċi fl-qa'ima l-ḅiḍa.",
        "img-auth-nofile": "milef \"$1\" ma kayn-ċ.",
        "img-auth-streaming": "ard \"$1\".",
        "img-auth-noread": "l-mosṫĥdim ma ĝndo-ċ ṣ-ṣalaḫiyya baċ yqṛa \"$1\".",
        "emailuserfooter": "Had l-imayl ṣifto « $1 » le « $2 » be waṣitaṫ « Ṣifet ċi imayl le l-mosṫeḫdim » fe {{SITENAME}}.",
        "usermessage-summary": "Ĥella waḫed l-meṣaj sistém.",
        "usermessage-editor": "Morasil s-sistém",
-       "watchlist": "L-Lista de s-suivi dyalṫi",
-       "mywatchlist": "L-Lista dyal s-suivi",
+       "watchlist": "الليسطا ديال السويڤي",
+       "mywatchlist": "الليسطا ديال السويڤي",
        "watchlistfor2": "Le $1 $2",
        "nowatchlist": "Ma kayna ḫṫa ċi ṣefḫa fe l-lista dyal s-suivi dyalṫek.",
        "watchlistanontext": "Ĝafak $1 baċ ṫċof ola baċ ṫṣayeb ṣ-ṣefḫaṫ li fe l-lista dyal s-suivi.",
        "blanknamespace": "(Re'si)",
        "contributions": "L-mosahamaṫ dyal l-mosṫeĥdim",
        "contributions-title": "L-Mosahamaṫ dyal $1",
-       "mycontris": "L-mosahamaṫ dyawli",
+       "mycontris": "لمساهمات دياولي",
+       "anoncontribs": "لمساهمات",
        "contribsub2": "Le $1 ($2)",
        "uctop": "l-foq",
        "month": "Men ċher (o qdem)",
index f07fbd3..e0bdb06 100644 (file)
        "ok": "موافئ",
        "retrievedfrom": "اتجابت من \"$1\"",
        "youhavenewmessages": "{{PLURAL:$3|عندك}} $1 ($2).",
-       "youhavenewmessagesfromusers": "{{PLURAL:$4|عندك}} $1 من {{PLURAL:${{PLURAL:$3|}}3|يوزر واحد|يوزر واحد|اتنين يوزر |$3 يوزر|$3 يوزر}} ($2).",
+       "youhavenewmessagesfromusers": "{{PLURAL:$4|عندك}} $1 من {{PLURAL:${{PLURAL:$3|}}3|يوزر واحد|يوزر واحد|اتنين يوزر |$3 يوزر}} ($2).",
        "youhavenewmessagesmanyusers": "عندك $1 من يوزرات كتير  ($2).",
        "newmessageslinkplural": "{{PLURAL:$1|رساله جديده|999=رسايل جديده}}",
        "newmessagesdifflinkplural": "أحدث {{PLURAL:$1|تغيير|999=تغييرات}}",
        "virus-badscanner": "غلطه : ماسح فيروسات مش معروف: ''$1''",
        "virus-scanfailed": "المسح فشل(كود $1)",
        "virus-unknownscanner": "انتى فيروس مش معروف:",
-       "logouttext": "'''أنت دلوقتى مش مسجل دخولك.'''\n\nتقدر تكمل استعمال {{SITENAME}} على انك مجهول، أو [[Special:UserLogin|الدخول مرة تانيه]] بنفس الاسم أو باسم تانى.\n\nممكن تشوف بعض الصفحات  كأنك متسجل ، و دا علشان استعمال الصفحات المتخبية ف البراوزر بتاعك.",
+       "logouttext": "'''أنت دلوقتى مش مسجل دخولك.'''\n\nممكن تشوف بعض الصفحات  كأنك متسجل ، و دا علشان استعمال الصفحات المتخبية ف البراوزر بتاعك.",
        "welcomeuser": "أهلاً بيك يا $1!",
        "welcomecreation-msg": "اتفتحلك حساب.\nلو تحب ممكن تغير [[Special:Preferences|تفضيلاتك ف {{SITENAME}}]].",
        "yourname": "اليوزرنيم:",
        "nosuchusershort": "مافيش يوزر باسم $1\".\nاتاكد من تهجية الاسم.",
        "nouserspecified": "لازم تحدد اسم يوزر.",
        "login-userblocked": "اليوزر دا ممنوع من الدخول.",
-       "wrongpassword": "كلمة السر اللى كتبتها مش صحيحه. من فضلك حاول تانى.",
+       "wrongpassword": "كلمة السر اللى كتبتها مش صحيحه.\nمن فضلك حاول تانى.",
        "wrongpasswordempty": "كلمة السر المدخله كانت فاضيه.\nمن فضلك حاول تانى.",
        "passwordtooshort": "لازم تكون على الاقل{{PLURAL:$1|1 حرف|$1 حروف}}.",
        "password-name-match": "الباسورد بتاعتك لازم تكون مختلفه عن اسم اليوزر بتاعك.",
        "eauthentsent": "فيه ايميل تأكيد اتبعت  للعنوان اللى كتبته.\nعلشان تبعت اى ايميل تانى للحساب ده لازم تتبع التعليمات اللى فى الايميل اللى اتبعتلك  علشان تأكد ان  الحساب ده بتاعك .",
        "throttled-mailpassword": "بعتنالك علشان تفتكر الباسورد بتاعتك، فى خلال الـ{{PLURAL:$1|ساعة|$1 ساعة}} اللى فاتت.\nعلشان منع التخريب، ح نفكرك مرة و احدة بس كل\n{{PLURAL:$1|ساعة|$1 ساعة}}.",
        "mailerror": "غلط فى بعتان الايميل : $1",
-       "acct_creation_throttle_hit": "الناس اللى دخلت ع الويكى دا باستعمال عنوان الاى بى بتاعك فتحو {{PLURAL:$1|1 حساب|$1 حساب}} ف اليوم اللى فات دا, يعنى وصلو للحد الاقصى المسموح بيه فى الفترة الزمنيه المحدده..\nو عشان كدا, الزوار اللى بيدخلو بعنوان الاى بى دا مش مسموح لهم يفتحو حسابات اكتر فى الوقت الحالى .",
+       "acct_creation_throttle_hit": "الناس اللى دخلت ع الويكى دا باستعمال عنوان الاى بى بتاعك فتحو {{PLURAL:$1|1 حساب|$1 حساب}} ف اليوم اللى فات دا $2, يعنى وصلو للحد الاقصى المسموح بيه فى الفترة الزمنيه المحدده.\nو عشان كدا, الزوار اللى بيدخلو بعنوان الاى بى دا مش مسموح لهم يفتحو حسابات اكتر فى الوقت الحالى .",
        "emailauthenticated": "اتأكدنا من الايميل بتاعك يوم $2 الساعة $3.",
        "emailnotauthenticated": "لسة ما اتكدناش من الايميل بتاعك.\nمش ح يتبعتلك اى  ايميلات بخصوص الميزات دي.",
        "noemailprefs": "علشان الخصايص دى تشتغل لازم تحددلك عنوان ايميل.",
        "note": "'''ملحوظه:'''",
        "previewnote": "'''دى بروفه للصفحه بس.'''\nولسه ما تسييفتش! ،",
        "previewconflict": "البروفة دى بتبينلك فوق إزاى ح يكون شكل النص لو انت دوست على حفظ",
-       "session_fail_preview": "'''ما قدرناش  نحفظ التعديلات اللى قمت بيها نتيجة لضياع بيانات  الجلسه.\nالرجاء المحاولة مرة تانيه.\nفى حال استمرار المشكلة حاول  [[Special:UserLogou|تخرج]] وتدخل مرة تانيه .'''",
+       "session_fail_preview": "'''ما قدرناش  نحفظ التعديلات اللى قمت بيها نتيجة لضياع بيانات  الجلسه.\nالرجاء المحاولة مرة تانيه.\nفى حال استمرار المشكلة حاول  [[Special:UserLogout|تخرج]] وتدخل مرة تانيه .'''",
        "session_fail_preview_html": "'''ماقدرناش نعالج تعديلك بسبب ضياع بيانات الجلسة.'''\n\n''لأن {{SITENAME}} بها HTML هل الخام شغاله، البروفه مخفيه كاحتياط ضد هجمات الجافا سكريبت.''\n\n'''إذا كانت دى محاولة تعديل صادقه، من فضلك حاول مرة تانيه. إذا كانت لسه مش شغاله، حاول [[Special:UserLogout|تسجيل الخروج]] و تسجيل الدخول من جديد.'''",
        "token_suffix_mismatch": "'''تعديلك اترفض لأن عميلك غلط فى علامات الترقيم\nفى نص التعديل. التعديل اترفض علشان ما يبوظش نص المقالة.\nدا ساعات بيحصل لما تستعمل خدمة بروكسى مجهولة بايظة أساسها الويب.'''",
        "editing": "تعديل $1",
        "readonlywarning": "'''تحذير: قاعدة البيانات اتقفلت للصيانة، و علشان كدا انت مش ح تقدر تحفظ التعديلات اللى عملتها دلواتى.\nلو حبيت ممكن  تنسخ النص وتحفظه فى ملف نصى علشان تستعمله بعدين.'''\n\nالإدارى اللى قفلها كتب السبب دا $1",
        "protectedpagewarning": "'''تحذير:الصفحة دى اتقفلت بطريقه تخلى اليوزرات السيسوبات هما بس اللى يقدرو يعدلوها.'''\nاخر سجل محطوط تحت علشان المراجعه:",
        "semiprotectedpagewarning": "'''ملاحظه:''' الصفحه دى اتقفلت بطريقه تخلّى اليوزرات المتسجلين بس هما اللى يقدرو يعدّلوها.\nاخر سجل محطوط تحت علشان المراجعه:",
-       "cascadeprotectedwarning": "<strong>تحذير: الصفحة دى اتقفلت بطريقة تخلى اليوزرز السيوبات بس هم اللى يقدرو يعدلوها، ودا علشان هى مدموجة فى {{PLURAL:$1|الصفحة|الصفحات}} التالية واللى اتعملها حمتية بخاصية \"حماية الصفحات المدموجة\":</strong>",
+       "cascadeprotectedwarning": "<strong>تحذير: الصفحة دى اتقفلت بطريقة تخلى اليوزرز [[Special:ListGroupRights|السيوبات]] بس هم اللى يقدرو يعدلوها، ودا علشان هى مدموجة فى {{PLURAL:$1|الصفحة|الصفحات}} التالية واللى اتعملها حمتية بخاصية \"حماية الصفحات المدموجة\":</strong>",
        "titleprotectedwarning": "'''تحذير: الصفحه دى اتحمت بطريقه تخلّى [[Special:ListGroupRights|حقوق متحدده]] لازم تحتاجها علشان تعمل الصفحه.'''\nاخر سجل محطوط تحت علشان المراجعه:",
        "templatesused": "{{PLURAL:$1|القالب المستعمل |القوالب المستعمله }} ف الصفحه دى:",
        "templatesusedpreview": "{{PLURAL:$1|القالب المستعمل |القوالب المستعمله}} فى البروفه دى",
        "histfirst": "اول",
        "histlast": "آخر",
        "historysize": "({{PLURAL:$1|1 بايت|$1 بايت}})",
-       "historyempty": "(فاضى)",
+       "historyempty": "فاضى",
        "history-feed-title": "تاريخ المراجعة",
        "history-feed-description": "تاريخ التعديل بتاع الصفحة دى على الويكي",
        "history-feed-item-nocomment": "$1 فى $2",
        "revdelete-edit-reasonlist": "عدل أسباب المسح",
        "revdelete-offender": "صاحب المراجعة:",
        "suppressionlog": "سجل الإخفاء",
-       "suppressionlogtext": "تحت فى لستة بعمليات المسح والمنع اللى فيها محتوى مستخبى على الإداريين.\nشوف [[Special:IPBlockList|للستة المنع]] علشان تشوف عمليات المنع الشغالة دلوقتى .",
+       "suppressionlogtext": "تحت فى لستة بعمليات المسح والمنع اللى فيها محتوى مستخبى على الإداريين.\nشوف [[Special:BlockList|للستة المنع]] علشان تشوف عمليات المنع الشغالة دلوقتى .",
        "mergehistory": "دمج تواريخ الصفحة",
        "mergehistory-header": "الصفحة دى بتسمح لك بدمج نسخ تاريخ صفحة  فى صفحة تانية.\nاتأكد من أن التغيير دا ح يحافظ على استمرارية تاريخ الصفحة.",
        "mergehistory-box": "دمج تعديلات صفحتين:",
        "mergehistory-go": "عرض التعديلات اللى ممكن تتدمج",
        "mergehistory-submit": "دمج النسخ",
        "mergehistory-empty": "مافيش مراجعات ممكن دمجها.",
-       "mergehistory-done": "$3 {{PLURAL:$3|مراجعة|مراجعة}} من $1 تم دمجها بنجاح فى [[:$2]].",
+       "mergehistory-done": "$3 {{PLURAL:$3|مراجعة}} من $1 تم دمجها بنجاح فى [[:$2]].",
        "mergehistory-fail": "مش قادر يعمل دمج للتاريخ، لو سمحت تتأكد تانى من محددات الصفحة والزمن.",
        "mergehistory-no-source": "الصفحة المصدر $1  مش موجودة.",
        "mergehistory-no-destination": "الصفحه الهدف $1 مش موجوده.",
        "restoreprefs": "استرجع التظبيطات الاصليه",
        "prefs-editing": "تعديل",
        "searchresultshead": "تدوير",
-       "stub-threshold": "الحد لتنسيق <a href=\"#\" class=\"stub\">لينك البذرة</a>:",
+       "stub-threshold": "الحد لتنسيق لينك البذرة ($1):",
        "stub-threshold-disabled": "معطل",
        "recentchangesdays": "عدد الأيام المعروضة فى اخرالتغييرات:",
        "recentchangesdays-max": "(الحد الاقصى $1 {{PLURAL:$1|يوم|ايام}})",
        "editusergroup": "تعديل مجموعات اليوزر",
        "editinguser": "تغيير حقوق اليوزر بتاعه اليوزر '''[[User:$1|$1]]''' $2",
        "userrights-editusergroup": "تعديل مجموعات اليوزر",
-       "saveusergroups": "حفظ مجموعات اليوزر",
+       "saveusergroups": "حفظ مجموعات {{GENDER:$1|اليوزر}}",
        "userrights-groupsmember": "عضو في:",
        "userrights-groupsmember-auto": "عضو ضمنى فى :",
        "userrights-groups-help": "إنت ممكن تغير المجموعات اللى اليوزر دا عضو فيها .\n* صندوق متعلم يعنى اليوزر دا عضو فى المجموعة دي.\n* صندوق مش متعلم يعنى  اليوزر دا مش عضو فى المجموعة دي.\n* علامة * يعنى انك مش ممكن تشيل المجموعات بعد ما تضيفها و العكس بالعكس.",
        "minoreditletter": "ص",
        "newpageletter": "ج",
        "boteditletter": "ب",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1| يوزر مراقب|يوزر مراقب}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|بايت|بايتس}} بعد التغيير",
        "newsectionsummary": "/* $1 */ قسم جديد",
        "rc-enhanced-expand": "[اعرض التفاصيل]",
        "img-auth-nopathinfo": "PATH_INFO مش موجود.\nالخادم بتاعك مش مضبوط علشان يدى المعلومه دى.\nممكن يكون CGI-based ومايقدرش يدعم img_auth.\nبص على https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "المسار المطلوب مش فى مجلد الرفع المضبوط.",
        "img-auth-badtitle": "مش قادر يعمل عنوان صحيح من \"$1\".",
-       "img-auth-nologinnWL": "إنت مش مسجل الدخول و\"$1\" مش فى القايمه البيضا.",
        "img-auth-nofile": "الملف \"$1\" مش موجود",
        "img-auth-isdir": "إنت بتحاول تدخل مجلد \"$1\".\nدخول الملفات بس مسموح بيه.",
        "img-auth-streaming": "بيعرض \"$1\".",
        "filehist-comment": "تعليق",
        "imagelinks": "استخدام الفايل",
        "linkstoimage": "{{PLURAL:$1|الصفحة|ال$1 صفحة}} دى فيها وصله للفايل ده:",
-       "linkstoimage-more": "أكتر من $1 {{PLURAL:$1|صفحة تصل|صفحة تصل}} للملف ده .\nالقائمة التالية تعرض {{PLURAL:$1|أول وصلة صفحة|أول $1 وصلة صفحة}} للملف ده بس.\n[[Special:WhatLinksHere/$2|قائمة كاملة]] متوفرة.",
+       "linkstoimage-more": "أكتر من $1 {{PLURAL:$1|صفحة تصل}} للملف ده .\nالقائمة التالية تعرض {{PLURAL:$1|أول وصلة صفحة|أول $1 وصلة صفحة}} للملف ده بس.\n[[Special:WhatLinksHere/$2|قائمة كاملة]] متوفرة.",
        "nolinkstoimage": "مافيش صفحات بتوصل للفايل ده.",
        "morelinkstoimage": "عرض [[Special:WhatLinksHere/$1|لينكات اكتر]] للملف دا.",
        "duplicatesoffile": "{{PLURAL:$1| الملف|ال$1 ملف اللى بعده}} متكررين من الملف ده:\n([[Special:FileDuplicateSearch/$2| تفاصيل اكتر]]):",
        "allpagesbadtitle": "العنوان االلى اديته للصفحة مش نافع أو فيه لغات تانية أو بريفيكس إنترويكي.\nيمكن فيه حروف ماينفعش تنكتب بيها العناوين.",
        "allpages-bad-ns": "{{SITENAME}} مافيهاش نطاق \"$1\".",
        "categories": "تصانيف",
-       "categoriespagetext": "{{PLURAL:$1|التصنيف دا بيحتوى على|التصنيفات دى بتحتوى على}} صفحات او ميديا.\n[[Special:UnusedCategories|التصنيفات اللى مش مستعمله]] مش معروضه  هنا.\nشوف كمان [[Special:WantedCategories|التصنيفات المتعازه]].",
+       "categoriespagetext": "{{PLURAL:$1|التصنيف دا بيحتوى على|التصنيفات دى بتحتوى على}} صفحات او ميديا.\nشوف كمان [[Special:WantedCategories|التصنيفات المتعازه]].",
        "categoriesfrom": "اعرض التصانيف من أول:",
        "deletedcontributions": "تعديلات اليوزر الممسوحة",
        "deletedcontributions-title": "تعديلات اليوزر الممسوحة",
        "listusers-blocked": "(ممنوع)",
        "activeusers": "ليستة اليوزرات اللى ليهم نشاط",
        "activeusers-intro": "دى قايمه اليوزرات اللى عملوا نشاط فى آخر $1 {{PLURAL:$1|يوم|يوم}}.",
-       "activeusers-count": "$1 {{PLURAL:$1|تعديل|تعديل}} فى آخر {{PLURAL:$3|يوم|$3 يوم}}",
+       "activeusers-count": "$1 {{PLURAL:$1|تعديل}} فى آخر {{PLURAL:$3|يوم|$3 يوم}}",
        "activeusers-from": "عرض اليوزرات بداية من:",
        "activeusers-noresult": "مالقيناش اى يوزر",
        "listgrouprights": "حقوق مجموعات اليوزرز",
        "nowatchlist": "مافيش حاجة فى لستة مراقبتك.",
        "watchlistanontext": "لو سمحت اعمل لوجين لعرض أو تعديل الصفحات فى لستة مراقبتك.",
        "watchnologin": "مش متسجل",
-       "addedwatchtext": "تمت إضافة الصفحه  \"$1\"  [[Special:Watchlist|للستة الصفحات اللى بتراقبها]].\nالتعديلات اللى بعد كده ها تتحط على الصفحه دى، وصفحة المناقش الخاصه بها ها تتحط هناك. واسم الصفحة هايظهر  بخط <b>عريض</b> فى صفحة [[Special:RecentChanges|أحدث التعديلات]] لتسهيل تحديدها واكتشافها.",
+       "addedwatchtext": "تمت إضافة الصفحه \"[[:$1]]\" [[Special:Watchlist|للستة الصفحات اللى بتراقبها]].",
        "removedwatchtext": "الصفحه دى اتشالت \"[[:$1]]\" من [[Special:Watchlist|لستة الصفحات اللى بتراقبها]].",
        "watch": "راقب",
        "watchthispage": "راقب الصفحه دى",
        "unwatchthispage": "اتوقف عن المراقبة",
        "notanarticle": "دى مش صفحة بتاعة محتوى",
        "notvisiblerev": "النسحة اتمسحت",
-       "watchlist-details": "{{PLURAL:$1|$1 صفحه|$1 صفحه}} فى قايمه مراقبتك، بدون عد صفحات المناقشه.",
+       "watchlist-details": "{{PLURAL:$1|$1 صفحه}} فى قايمه مراقبتك، بدون عد صفحات المناقشه.",
        "wlheader-enotif": "*خاصية الاعلام بالايميل متفعلة",
-       "wlheader-showupdated": "الصفحات اللى اتغيرت  بعد زيارتك ليها اخر مرة معروضة بالخط '''العريض'''",
-       "wlnote": "تحت فى {{PLURAL:$1|آخر تغيير|آخر '''$1''' تغيير}} فى آخر {{PLURAL:$2|ساعه|'''$2''' ساعه}}، من الوقت $3، $4.",
+       "wlheader-showupdated": "الصفحات اللى اتغيرت  بعد زيارتك ليها اخر مرة معروضة بالخط <strong>التخين</strong>",
+       "wlnote": "تحت فى {{PLURAL:$1|آخر تغيير|آخر <strong>$1</strong> تغيير}} فى آخر {{PLURAL:$2|ساعه|<strong>$1</strong> ساعه}}، من الوقت $3، $4.",
        "wlshowlast": "عرض اخر $1 ساعات $2 ايام",
        "watchlist-options": "اختيارات قايمة المراقبة",
        "watching": "بيراقب...",
        "deletepage": "امسح الصفحه",
        "confirm": "أكد",
        "excontent": "المحتوى كان: '$1'",
-       "excontentauthor": "المحتوى كان: '$1' (والمساهم الوحيد كان '[[Special:Contributions/$2|$2]]')",
+       "excontentauthor": "المحتوى كان: \"$1\" والمساهم الوحيد كان \"[[Special:Contributions/$2|$2]]\" ([[User talk:$2|talk]])",
        "exbeforeblank": "المحتوى قبل التفضيه كان: '$1'",
        "delete-confirm": "مسح\"$1\"",
        "delete-legend": "مسح",
-       "historywarning": "'''تحذير:''' الصفحه اللى ها  تمسحها ليها تاريخ فيه تقريبا $1 {{PLURAL:$1|مراجعة|مراجعة}}:",
+       "historywarning": "'''تحذير:''' الصفحه اللى ها  تمسحها ليها تاريخ فيه تقريبا $1 {{PLURAL:$1|مراجعة}}:",
        "confirmdeletetext": "انت على وشك انك تمسح صفحه أو صوره و كل تاريخها.\nمن فضلك  اتأكد انك عايز المسح وبأنك فاهم نتايج  العمليه  دى. عمليات المسح لازم تتم بناء على [[{{MediaWiki:Policy-url}}|القواعد المتفق عليها]].",
        "actioncomplete": "العمليه خلصت",
        "actionfailed": "الفعل فشل",
        "editcomment": "ملخص التعديل كان: \"''$1''\".",
        "revertpage": "استرجع التعديلات بتاعة [[Special:Contributions/$2|$2]] ([[User talk:$2|مناقشة]]) لآخر نسخة بتاعة [[User:$1|$1]]",
        "revertpage-nouser": "استرجع التعديلات بتاعه (اسم اليوزر اتمسح) لغايه آخر نسخه بتاعه [[User:$1|$1]]",
-       "rollback-success": "استرجع تعديلات $1؛\nاسترجع لآخر نسخة بواسطة $2.",
+       "rollback-success": "استرجع تعديلات {{GENDER:$3|$1}}؛\nاسترجع لآخر نسخة بواسطة {{GENDER:$4|$2}}.",
        "sessionfailure": "الظاهر انه فى مشكلة فى جلسة دخولك دى ؛\nوعلشان كدا العملية دى اتلغت كإجراء احترازى ضد الاختراق.\nلو سمحت دوس على زرار\"رجوع\" علشان تحمل الصفحة اللى جيت منها مرة تانية، و بعدين حاول تاني.",
        "protectlogpage": "سجل الحمايه",
        "protectlogtext": "تحت فى لستة بالصفحات اللى اعملها حماية او اتشالت منها الحماية.\nشوف [[Special:ProtectedPages|لستة الصفحات المحمية]] لستة بعمليات حماية الصفحات الشغالة دلوقتي.",
        "undeletepagetext": "{{PLURAL:$1|الصفحة دى اتمسحت بس ليه|$1الصفحات دى اتمسحت بس ليه}} موجودة فى الارشيف و ممكن تترجع.\n\n\nالأرشيف ممكن يتنضف كل شوية.",
        "undelete-fieldset-title": "رجع النسخ",
        "undeleteextrahelp": "علشان ترجع تاريخ الصفحة كله، سيب كل الصناديق فاضية و دوس '''''ترجيع'''''.\nعلشان ترجع جزء من الصفحة، حط علامة فى الصناديق أدام التعديلات اللى عايز  ترجعهاو دوس '''''ترجيع'''''.\nلو دوست على  '''''إبتدى تاني'''''  التعليق ح يتمسح و كل العلامات  اللى فى الصناديق ح تتحذف.",
-       "undeleterevisions": "$1 {{PLURAL:$1|نسخة|نسخة}} اتحطت فى  الارشيف",
+       "undeleterevisions": "$1 {{PLURAL:$1|نسخة}} اتحطت فى  الارشيف",
        "undeletehistory": "لو رجعت الصفحة، كل المراجعات ح تترجع للتاريخ دا\nلو فى صفحة جديدة اتعملت بنفس الاسم بعد المسح، المراجعات المترجعة ح تبان فى التاريخ اللى فات.",
        "undeleterevdel": "الترجيع مش ح يحصل لو كان ح يسبب ان المراجعة تيجى فى راس الصفحة أو ان الملف يتمسح حتة منه .\nفى الحالات اللى زى كدا، لازم تبين أخر المراجعات الممسوحة.",
        "undeletehistorynoadmin": "الصفحة دى اتمسحت.\nسبب المسح موجود فى الملخص اللى تحت، كمان فى تفاصيل اليوزرز اللى عملو تعديل على الصفحة دى قبل ما تتمسح.\nنص المراجعات الممسوحة دى متوفرة بس للاداريين.",
        "sp-contributions-newbies-sub": "للحسابات الجديده",
        "sp-contributions-newbies-title": "مساهمات  اليوزر للحسابات الجديدة",
        "sp-contributions-blocklog": "سجل المنع",
-       "sp-contributions-deleted": "تعديلات اليوزر الممسوحه",
+       "sp-contributions-deleted": "تعديلات {{GENDER:$1|اليوزر}} الممسوحه",
        "sp-contributions-uploads": "مرفوعات",
        "sp-contributions-logs": "السجلات",
        "sp-contributions-talk": "مناقشه",
-       "sp-contributions-userrights": "ادارة حقوق اليوزر",
+       "sp-contributions-userrights": "ادارة حقوق {{GENDER:$1|اليوزر}}",
        "sp-contributions-blocked-notice": "اليوزر ده ممنوع دلوقتى.\nآخر عمليه منع في السجل موجوده تحت كمرجع:",
        "sp-contributions-search": "دور على مساهمات",
        "sp-contributions-username": "عنوان أيبى أو اسم يوزر:",
        "whatlinkshere-hideimages": "$1 وصله فايل",
        "whatlinkshere-filters": "فلاتر",
        "blockip": "بلوك {{GENDER:$1|اليوزر|اليوزره}}",
-       "blockiptext": "استخدم الاستمارة اللى تحت لمنع عنوان أيبى أو يوزر معين من الكتابة.\nدا لازم يحصل بس علشان تمنع التخريب ،و على حسب\n[[{{MediaWiki:Policy-url}}|السياسة]].\nاكتب سبب محدد تحت (يعنى مثلا، اكتب الصفحات المعينة اللى اتخربت بسببه).",
+       "blockiptext": "استخدم الاستمارة اللى تحت لمنع عنوان أيبى أو يوزر معين من الكتابة.\nدا لازم يحصل بس علشان تمنع التخريب ،و على حسب\n[[{{MediaWiki:Policy-url}}|السياسة]].\nاكتب سبب محدد تحت (يعنى مثلا، اكتب الصفحات المعينة اللى اتخربت بسببه).\nانت ممكن تمنع عناوين الايبى عن طريق [https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing CIDR]; اكبر نطاق مسموح بيه هوه /$1 ل IPv4 و /$2 ل IPv6.",
        "ipaddressorusername": "عنوان الأيبى أو اسم اليوزر:",
        "ipbreason": "السبب:",
        "ipbreason-dropdown": "*أسباب المنع المشهورة\n** تدخيل معلومات غلط\n** مسح المحتوى من الصفحات\n** سبام لينك لمواقع خارجية\n** كتابة كلام مالوش معنى فى الصفحات\n** سلوك عدواني/تحرش\n** إساءة استخدام اكتر من حسابات\n** اسم يوزر مش مقبول",
        "emailblock": "الإيميل ممنوع",
        "blocklist-nousertalk": "لا يمكنه تعديل صفحة نقاشه الخاصة",
        "ipblocklist-empty": "لستة المنع فاضية.",
-       "ipblocklist-no-results": "عÙ\86Ù\88اÙ\86 Ø§Ù\84Ø£Ù\8aبÙ\89 Ø£و اسم اليوزر المطلوب مش ممنوع.",
+       "ipblocklist-no-results": "عÙ\86Ù\88اÙ\86 Ø§Ù\84اÙ\8aبÙ\89 Ø§و اسم اليوزر المطلوب مش ممنوع.",
        "blocklink": "بلوك",
        "unblocklink": "شيل البلوك",
        "change-blocklink": "غير البلوك",
        "allmessagesdefault": "النص الاوتوماتيكي",
        "allmessagescurrent": "النص دلوقتى",
        "allmessagestext": "دى لستة برسايل النظام المتوفرة فى نطاق ميدياويكي.\nلو سمحت تزور[https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation ترجمة ميدياويكي] و [https://translatewiki.net بيتاويكي] لو كنت عايز تساهم فى ترجمة ميدياويكى الاصلية.",
-       "allmessagesnotsupportedDB": "الصفحة دى مش يمكن حد يستعملها علشان'''$wgUseDatabaseMessages''' متعطل.",
+       "allmessages-not-supported-database": "الصفحة دى مش يمكن حد يستعملها علشان'''$wgUseDatabaseMessages''' متعطل.",
        "allmessages-filter-legend": "فيلتر",
        "allmessages-filter": "فلتره بحالة التهيئه:",
        "allmessages-filter-unmodified": "مش متعدل",
        "import-nonewrevisions": "كل النسخ استوردت قبل كدا.",
        "xml-error-string": "$1 عند السطر $2، العمود $3 (بايت $4): $5",
        "import-upload": "حمل بيانات إكس إم إل",
-       "import-token-mismatch": "الداتا بتاعة الجلسة ضاعت. لو سمحت تحاول تاني.",
+       "import-token-mismatch": "الداتا بتاعة الجلسة ضاعت.\nانت ممكن تكون سجلت الخروج. '''لو سمحت اتاكد انك لسه مسجل الدخول و حاول تانى'''.\nلو كان لسه مش شغال، حاول[[Special:UserLogout|تسجيل الخروج]] و تسجيل الدخول تانى.",
        "import-invalid-interwiki": "ماينفعش تستورد من الويكى المتحدد.",
        "importlogpage": "سجل الاستيراد",
        "importlogpagetext": "استيرادات إدارية لصفحات ليها تاريخ تعديل من مواقع ويكى تانية.",
        "autosumm-replace": "تبديل الصفحة ب'$1'",
        "autoredircomment": "تحويل لـ [[$1]]",
        "autosumm-new": "ابتدا صفحه جديده بـ '$1'",
-       "size-bytes": "$1 بايت",
+       "size-bytes": "$1 {{PLURAL:$1|بايت}}",
        "size-kilobytes": "$1 كيلوبايت",
        "size-megabytes": "$1 ميجابايت",
        "size-gigabytes": "$1 جيجابايت",
index 3030ab4..24cc9d5 100644 (file)
        "rcfilters-filter-editsbyself-description": "আপোনাৰ নিজৰ অৱদানসমূহ।",
        "rcfilters-filter-editsbyother-label": "আনে কৰা সালসলনিসমূহ",
        "rcfilters-filter-editsbyother-description": "আপুনি কৰাখিনিৰ বাহিৰে আন সকলো সালসলনি।",
-       "rcfilters-filtergroup-userExpLevel": "সদস্য পঞ্জীয়ন আৰু অভিজ্ঞতা",
+       "rcfilters-filtergroup-user-experience-level": "সদস্য পঞ্জীয়ন আৰু অভিজ্ঞতা",
        "rcfilters-filter-user-experience-level-registered-label": "পঞ্জীয়নভুক্ত",
        "rcfilters-filter-user-experience-level-registered-description": "প্ৰৱেশ কৰা সম্পাদকসকল।",
        "rcfilters-filter-user-experience-level-unregistered-description": "প্ৰৱেশ নকৰা সম্পাদকসকল।",
        "minoreditletter": "অ",
        "newpageletter": "ন",
        "boteditletter": "ব",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|জন সদস্যই|জন সদস্যই}} এই পৃষ্ঠা নিৰীক্ষণ কৰিছে]",
        "rc-change-size-new": "$1 {{PLURAL:$1|বাইট}} যোগ দিয়া হ’ল",
        "newsectionsummary": "/* $1 */ নতুন অনুচ্ছেদ",
        "rc-enhanced-expand": "সবিশেষ দেখুৱাওক",
        "img-auth-nopathinfo": "সন্ধানহীন PATH_INFO।\nআপোনাৰ চাৰ্ভাৰ এই তথ্য প্ৰেৰণ কৰিবলে প্ৰস্তুত নহয়।\nই CGI-ভিত্তিক হ'ব পাৰে img_auth সমৰ্থন কৰিব নোৱাৰে।\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization চাওক।",
        "img-auth-notindir": "সজা হোৱা আপল’ড ডিৰেক্টৰিত অনুৰোধ কৰা পথটো নাই ।",
        "img-auth-badtitle": "\"$1\" ৰ পৰা কোনো বৈধ শিৰোনামা তৈয়াৰ কৰিব পৰা নগ’ল ।",
-       "img-auth-nologinnWL": "আপুনি প্ৰৱেশ কৰা নাই আৰু চকু ৰখা ৰখা পৃষ্ঠাতালিকাত \"$1\" নাই ।",
        "img-auth-nofile": "\"$1\" নামৰ ফাইলৰ কোনো অস্তিত্ব নাই ।",
        "img-auth-isdir": "আপুনি \"$1\" ডিৰেক্টৰিত প্ৰৱেশ কৰিবলৈ বিচাৰিছে ।\nকেৱল ফাইলতহে প্ৰৱেশ কৰিব পাৰিব ।",
        "img-auth-streaming": "\"$1\" স্ট্ৰিম হৈ আছে ।",
        "allmessagesdefault": "সাধাৰণ বাৰ্তা পাঠ্য",
        "allmessagescurrent": "বৰ্তমানৰ বাৰ্তাৰ পাঠ",
        "allmessagestext": "মিডিয়াৱিকি নামস্থানত থকা প্ৰণালী বাৰ্তাসমূহৰ তালিকা ইয়াত দিয়া হৈছে ।\nযদি আপুনি মিডিয়াৱিকিৰ স্থানীয়কৰণত আগ্ৰহী, তেন্তে অনুগ্ৰহ কৰি [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation মিডিয়াৱিকি স্থানীয়কৰণ] আৰু [https://translatewiki.net translatewiki.net] চাওক ।",
-       "allmessagesnotsupportedDB": "এই পৃষ্ঠা ব্যৱহাৰ কৰিব নোৱাৰি কাৰণ '''$wgUseDatabaseMessages''' নিষ্ক্ৰিয় কৰা হৈছে ।",
+       "allmessages-not-supported-database": "এই পৃষ্ঠা ব্যৱহাৰ কৰিব নোৱাৰি কাৰণ '''$wgUseDatabaseMessages''' নিষ্ক্ৰিয় কৰা হৈছে ।",
        "allmessages-filter-legend": "ছেকনী",
        "allmessages-filter": "স্বনিৰ্বাচন অৱস্থাৰে পৰিস্ৰাৱন কৰক:",
        "allmessages-filter-unmodified": "অপৰিৱৰ্তিত",
        "version-entrypoints-header-url": "ইউআৰএল",
        "version-libraries-version": "সংস্কৰণ",
        "redirect": "ফাইল, সদস্য, পৃষ্ঠা বা সংশোধন বা লগ আই ডি-ৰে পুনঃনিৰ্দেশ",
-       "redirect-summary": "এই বিশেষ পৃষ্ঠাটোৱে আপোনাক অন্য এটা ফাইললৈ (ফাইলৰ নাম), এটা পৃষ্ঠালৈ (সংশোধন আই ডি বা পৃষ্ঠা আই ডি), অথবা অন্য সদস্যৰ পৃষ্ঠালৈ (সদস্যৰ সাংখ্যিক আই ডি) পুনঃনির্দেশিত কৰিছে।\nব্যৱহাৰ: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], বা [[{{#Special:Redirect}}/user/101]]।",
+       "redirect-summary": "এই বিশেষ পৃষ্ঠাটোৱে আপোনাক অন্য এটা ফাইললৈ (ফাইলৰ নাম), এটা পৃষ্ঠালৈ (সংশোধন আই ডি বা পৃষ্ঠা আই ডি), অথবা অন্য সদস্যৰ পৃষ্ঠালৈ (সদস্যৰ সাংখ্যিক আই ডি), এটা সূচী ভুক্তিলৈ (প্ৰদত্ত সূচী ভুক্তি) পুনঃনির্দেশিত কৰিছে।\nব্যৱহাৰ: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]] বা [[{{#Special:Redirect}}/logid/186]]।",
        "redirect-submit": "যাওক",
        "redirect-lookup": "চাওক:",
        "redirect-value": "মূল্য:",
index 82d0214..e8af15e 100644 (file)
@@ -61,6 +61,7 @@
        "tog-norollbackdiff": "Nun amosar diferencies depués de facer una restauración",
        "tog-useeditwarning": "Avisame cuando salga d'una páxina d'edición con cambios ensin guardar",
        "tog-prefershttps": "Usar siempre una conexón segura en aniciando sesión",
+       "tog-showrollbackconfirmation": "Amosar una pantalla de confirmación al faer clic nun enllaz de reversión",
        "underline-always": "Siempre",
        "underline-never": "Nunca",
        "underline-default": "Predeterminao del aspeutu o del restolador",
        "returnto": "Volver a $1.",
        "tagline": "De {{SITENAME}}",
        "help": "Ayuda",
+       "help-mediawiki": "Ayuda sobro MediaWiki",
        "search": "Buscar",
        "search-ignored-headings": " #<!-- dexar esta llinia exautamente como ta --> <pre>\n# Testeres que nun se tendrán en cuenta na gueta.\n# Los cambios fechos equí son efeutivos nel momentu que s'indexa la páxina cola testera.\n# Puede forzase'l reindexáu d'una páxina faciendo una edición nula.\n# La sintaxis ye la siguiente:\n#   * Tolo qu'hai dende un caráuter «#» al fin de llinia ye un comentariu\n#   * Cada llinia nun-balera ye'l títulu exautu a descartar, incluyendo mayúscules y too.\nReferencies\nEnllaces esternos\nVer tamién\n #</pre> <!-- dexar esta llinia exautamente como ta -->",
        "searchbutton": "Guetar",
        "badarticleerror": "Esta aición nun puede facese nesta páxina.",
        "cannotdelete": "Nun pudo desaniciase la páxina o'l ficheru «$1».\nSeique daquién yá lo desaniciara.",
        "cannotdelete-title": "La páxina «$1» nun puede desaniciase",
+       "delete-scheduled": "La páxina «$1» ta programada pa desaniciase.\nTen paciencia.",
        "delete-hook-aborted": "Desaniciu albortáu pol enganche.\nNun conseñó esplicación.",
        "no-null-revision": "Nun pudo crease una nueva revisión nula pa la páxina «$1»",
        "badtitle": "Títulu incorreutu",
        "badretype": "Les contraseñes qu'escribisti nun concuayen.",
        "usernameinprogress": "Yá ta creándose una cuenta pa esti nome d'usuariu.\nEspera.",
        "userexists": "El nome d'usuariu conseñáu yá ta usándose.\nPor favor escueyi un nome diferente.",
+       "createacct-normalization": "El to nome d'usuariu va axustase a \"$2\" por cuenta de torgues técniques.",
        "loginerror": "Error d'aniciu de sesión",
        "createacct-error": "Error de creación de cuenta",
        "createaccounterror": "Nun pudo crease la cuenta: $1",
        "passwordtooshort": "Les contraseñes han de tener polo menos {{PLURAL:$1|1 caráuter|$1 caráuteres}}.",
        "passwordtoolong": "Les contraseñes nun puen ser mayores de {{PLURAL:$1|1 caráuter|$1 caráuteres}}.",
        "passwordtoopopular": "Les contraseñes más escoyíes de vezu nun pueden usase. Escueye una contraseña más difícil d'aldovinar.",
+       "passwordinlargeblacklist": "La contraseña qu'escribisti ta na llista de contraseñes más usaes. Escueyi una contraseña menos corriente.",
        "password-name-match": "La contraseña tien de ser distinta del nome d'usuariu.",
        "password-login-forbidden": "Ta torgao usar esti nome d'usuariu y contraseña.",
        "mailmypassword": "Reaniciar contraseña",
        "resetpass-abort-generic": "Una estensión encaboxó'l cambiu de la contraseña.",
        "resetpass-expired": "La to contraseña caducó. Configura una nueva contraseña p'aniciar sesión.",
        "resetpass-expired-soft": "La contraseña caducó y precisa cambiase. Escueye agora una contraseña nueva, o pulsia «{{int:authprovider-resetpass-skip-label}}» pa cambiala sero.",
+       "resetpass-validity": "La contraseña nun ye válida: $1\n\nConfigura una contraseña nueva p'aniciar sesión.",
        "resetpass-validity-soft": "La contraseña nun ye válida: $1\n\nEscueye agora una contraseña nueva, o pulsia «{{int:authprovider-resetpass-skip-label}}» pa cambiala sero.",
        "passwordreset": "Reaniciar contraseña",
        "passwordreset-text-one": "Completa esti formulariu pa recibir per corréu una contraseña temporal.",
        "savearticle": "Guardar la páxina",
        "savechanges": "Guardar los cambios",
        "publishpage": "Publicar la páxina",
-       "publishchanges": "Publicar los cambios",
+       "publishchanges": "Espublizar los cambeos",
        "savearticle-start": "Guardar la páxina...",
        "savechanges-start": "Guardar los cambios...",
        "publishpage-start": "Publicar la páxina...",
        "subject-preview": "Vista previa del asuntu:",
        "previewerrortext": "Hebo un error al intentar entever los cambios.",
        "blockedtitle": "L'usuariu ta bloquiáu",
+       "blocked-email-user": "<strong>El to usuariu tien bloquiáu l'unviu de correos electrónicos. Entá puedes editar otres páxines nesta wiki.</strong> Pues ver los detalles completos del bloquéu en [[Special:MyContributions|Contribuciones de la cuenta]].\n\nEl bloquéu fízolu $1.\n\nEl motivu dau ye <em>$2</em>.\n\n* Entamu de bloquéu: $8\n* Caducidá del bloquéu: $6\n* Bloquéu destináu a: $7\n* ID del bloquéu #$5",
+       "blockedtext-partial": "<strong>El to usuariu o direición IP tien bloquiáo facer cambeos nesta páxina. Entá pues editar otres páxines nesta wiki.</strong> Pues ver los detalles completos del bloquéu en [[Special:MyContributions|contribuciones de la cuenta]].\n\nEl bloquéu fízolu $1.\n\nEl motivu dau ye <em>$2</em>.\n\n* Entamu de bloquéu: $8\n* Caducidá del bloquéu: $6\n* Bloquéu destináu a: $7\n* ID del bloquéu #$5",
        "blockedtext": "<strong>El to nome d'usuariu o direición IP ta bloquiáu.</strong>\n\nEl bloquéu fexolu $1.\nEl motivu conseñáu ye <em>$2</em>.\n\n* Principiu del bloquéu: $8\n* Caducidá del bloquéu: $6\n* Usuariu a bloquiar: $7\n\nPuedes comunicate con $1 o con otru [[{{MediaWiki:Grouppage-sysop}}|alministrador]] p'aldericar sobre'l bloquéu.\nNun puedes usar la función «{{int:emailuser}}» a nun ser que tea especificada una direición de corréu electrónicu válida nes tos [[Special:Preferences|preferencies de cuenta]] y que nun tengas torgao usala.\nLa to direición IP actual ye $3, y la ID del bloquéu ye #$5.\nPor favor, incluye tolos detalles anteriores nes consultes que faigas.",
        "autoblockedtext": "La to direición IP bloquióse automáticamente porque usóla otru usuariu que foi bloquiáu por $1.\nEl motivu conseñáu ye:\n\n:<em>$2</em>\n\n* Principiu del bloquéu: $8\n* Caducidá del bloquéu: $6\n* Usuariu a bloquiar: $7\n\nPues ponete'n contautu con $1 o con otru de los [[{{MediaWiki:Grouppage-sysop}}|alministradores]] p'aldericar sobre'l bloquéu.\n\nTen en cuenta que nun pues usar la función «{{int:emailuser}}» a nun ser que tengas rexistrada una direición de corréu electrónicu válida nes [[Special:Preferences|preferencies d'usuariu]] y que nun tengas torgao usala.\n\nLa to direición IP actual ye $3, y la ID del bloquéu ye #$5.\nPor favor, incluye tolos detalles anteriores nes consultes que faigas.",
        "systemblockedtext": "El to nome d'usuariu o dirección IP bloquióse automáticamente pol software MediaWiki.\nEl motivu dau ye:\n\n:<em>$2</em>\n\n* Entamu del bloquéu: $8\n* Caducidá de bloquéu: $6\n* Destinatariu del bloquéu: $7\n\nLa to dirección IP actual ye $3.\nPor favor, incluye tolos anteriores en cualquier consulta que faigas.",
        "accmailtext": "Unvióse a $2 una contraseña xenerada al debalu pal usuariu [[User talk:$1|$1]]. Pue camudase na páxina ''[[Special:ChangePassword|camudar contraseña]]'' depués d'aniciar sesión.",
        "newarticle": "(Nuevu)",
        "newarticletext": "Siguisti un enllaz a un artículu qu'inda nun esiste.\nPa crear la páxina, empecipia a escribir nel cuadru d'embaxo (mira la [$1 páxina d'ayuda] pa más información).\nSi llegasti equí por enquivocu, calca nel botón <strong>atrás</strong> del to restolador.",
-       "anontalkpagetext": "----\n''Esta ye la páxina d'alderique pa un usuariu anónimu qu'inda nun creó una cuenta o que nun la usa.''\nPola mor d'ello ha usase la direición numbérica IP pa identificalu/la.\nTala IP pue compartise por varios usuarios.\nSi yes un usuariu anónimu y notes qu'hai comentarios irrelevantes empobinaos pa ti, por favor [[Special:CreateAccount|crea una cuenta]] o [[Special:UserLogin|anicia sesiín]] pa torgar futures confusiones con otros usuarios anónimos.",
+       "anontalkpagetext": "----\n<em>Esta ye la páxina d'alderique pa un usuariu anónimu qu'inda nun creó una cuenta o que nun la usa.</em>\nPola mor d'ello ha usase la direición numbérica IP como identificación.\nTala IP pué compartise por dellos usuarios.\nSi yes un usuariu anónimu y notes qu'hai comentarios ensin relevancia dirixíos pa ti, por favor [[Special:CreateAccount|crea una cuenta]] o [[Special:UserLogin|anicia sesión]] pa torgar futures confusiones con otros usuarios anónimos.",
        "noarticletext": "Nestos momentos nun hai testu nesta páxina.\nPuedes [[Special:Search/{{PAGENAME}}|buscar esti títulu de páxina]] n'otres páxines,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} buscar los rexistros rellacionaos],\no [{{fullurl:{{FULLPAGENAME}}|action=edit}} crear esta páxina]</span>.",
        "noarticletext-nopermission": "Nestos momentos nun hai testu nesta páxina.\nPuedes [[Special:Search/{{PAGENAME}}|buscar esti títulu de páxina]] n'otres páxines o <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} buscar los rexistros rellacionaos]</span>, pero nun tienes permisu pa crear esta páxina.",
        "missing-revision": "La revisión #$1 de la páxina llamada \"{{FULLPAGENAME}}\" nun esiste.\n\nDe vezu la causa d'esto ye siguir un enllaz antiguu del historial a una páxina que se desanició.\nSe puen alcontrar más detalles nel [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} rexistru de desanicios].",
        "defaultmessagetext": "Testu predetermináu",
        "content-failed-to-parse": "Fallu al analizar el conteníu $2 pal modelu $1: $3",
        "invalid-content-data": "Datos del conteníu inválidos",
-       "content-not-allowed-here": "El conteníu «$1» nun se permite na páxina [[:$2]]",
+       "content-not-allowed-here": "El conteníu «$1» nun se permite na páxina [[:$2]] del segmentu \"$3\"",
        "editwarning-warning": "Salir d'esta páxina pue causar la perda de cualesquier cambiu fechu.\nSi anició sesión, pue desactivar esti avisu na seición «{{int:prefs-editing}}» de les preferencies.",
        "editpage-invalidcontentmodel-title": "El modelu de conteníu nun tien sofitu",
        "editpage-invalidcontentmodel-text": "El modelu de conteníu «$1»nun tien sofitu.",
        "editpage-notsupportedcontentformat-title": "El formatu del conteníu nun tien sofitu",
        "editpage-notsupportedcontentformat-text": "El formatu del conteníu, $1, nun tien sofitu del modelu de conteníu $2.",
+       "slot-name-main": "Principal",
        "content-model-wikitext": "testu wiki",
        "content-model-text": "testu simple",
        "content-model-javascript": "JavaScript",
        "page_first": "primera",
        "page_last": "cabera",
        "histlegend": "Seleición de diferencies: marca los botones de les versiones que quies comparar y calca <i>enter</i> o al botón d'abaxo.<br />\nLleenda: '''({{int:cur}})''' = diferencies cola versión actual, '''({{int:last}})''' = diferencies cola versión anterior, '''{{int:minoreditletter}}''' = edición menor.",
-       "history-fieldset-title": "Buscar revisiones",
+       "history-fieldset-title": "Filtrar revisiones",
        "history-show-deleted": "Sólo desaniciaes por revisión",
        "histfirst": "lo más antiguo",
        "histlast": "lo más nuevo",
        "historysize": "({{PLURAL:$1|1 byte|$1 bytes}})",
-       "historyempty": "(balero)",
+       "historyempty": "balero",
        "history-feed-title": "Historial de revisiones",
        "history-feed-description": "Historial de revisiones d'esta páxina na wiki",
        "history-feed-item-nocomment": "$1 en $2",
        "timezonelegend": "Estaya horaria:",
        "localtime": "Hora llocal:",
        "timezoneuseserverdefault": "Usar la predeterminada de la wiki ($1)",
-       "timezoneuseoffset": "Otra (especificar allancia)",
+       "timezoneuseoffset": "Otra (especifica la diferencia horaria más abaxo)",
+       "timezone-useoffset-placeholder": "Valores d'exemplu: \"-07:00\" o \"01:00\"",
        "servertime": "Hora del sirvidor:",
        "guesstimezone": "Rellenar del navegador",
        "timezoneregion-africa": "África",
        "prefs-advancedwatchlist": "Opciones avanzaes",
        "prefs-displayrc": "Opciones de vista",
        "prefs-displaywatchlist": "Opciones de vista",
+       "prefs-changesrc": "Cambeos amosaos",
+       "prefs-changeswatchlist": "Cambeos amosaos",
+       "prefs-pageswatchlist": "Páxines vixilaes",
        "prefs-tokenwatchlist": "Pase",
        "prefs-diffs": "Diferencies",
        "prefs-help-prefershttps": "Esta preferencia aplicaráse nel siguiente aniciu de sesión.",
        "right-reupload-own": "Sustituir los ficheros esistentes xubíos por ún mesmu",
        "right-reupload-shared": "Anular llocalmente los ficheros del estoyu de multimedia compartíu",
        "right-upload_by_url": "Xubir ficheros dende una URL",
-       "right-purge": "Purgar sin confirmación la caché d'una páxina nel sitiu",
+       "right-purge": "Purgar la caché d'una páxina nel sitiu",
        "right-autoconfirmed": "Nun tar afeutáu por llendes de tasa basaes na IP",
        "right-bot": "Tratar como un procesu automatizáu",
        "right-nominornewtalk": "Nun amosar l'avisu de nuevos mensaxes cuando se faen ediciones menores en páxines d'alderique",
        "grant-delete": "Desaniciar páxines, revisiones y entraes del rexistru",
        "grant-editinterface": "Editar l'espaciu de nomes MediaWiki y los JSON del sitiu o d'usuariu",
        "grant-editmycssjs": "Editar los CSS/JSON/JavaScript d'usuariu propios",
-       "grant-editmyoptions": "Editar les preferencies d'usuariu propies",
+       "grant-editmyoptions": "Editar les preferencies d'usuariu y la configuración JSON",
        "grant-editmywatchlist": "Editar la llista de vixilancia propia",
        "grant-editsiteconfig": "Editar les páxines CSS/JS del sitiu o d'usuariu",
        "grant-editpage": "Editar páxines esistentes",
        "action-changetags": "amestar y desaniciar etiquetes arbitraries en revisiones individuales y entraes del rexistru",
        "action-deletechangetags": "desaniciar etiquetes de la base de datos",
        "action-purge": "purgar esta páxina",
+       "action-apihighlimits": "usar llendes mayores nes consultes API",
+       "action-autoconfirmed": "nun tar afeutáu por llendes de tasa basaes na IP",
+       "action-bigdelete": "desaniciar páxines con historiales grandes",
+       "action-blockemail": "bloquiar a un usuariu l'unviu de corréu electrónicu",
+       "action-bot": "ser tratáu como un procesu automatizáu",
+       "action-editprotected": "editar páxines protexíes como \"{{int:protect-level-sysop}}\"",
+       "action-editsemiprotected": "editar páxines protexíes como \"{{int:protect-level-autoconfirmed}}\"",
+       "action-editinterface": "editar la interfaz d'usuariu",
+       "action-editusercss": "editar los ficheros CSS d'otros usuarios",
+       "action-edituserjson": "editar los ficheros JSON d'otros usuarios",
+       "action-edituserjs": "editar los ficheros JavaScript d'otros usuarios",
+       "action-editsitecss": "editar CSS global del sitiu",
+       "action-editsitejson": "editar JSON global del sitiu",
+       "action-editsitejs": "editar JavaScript global del sitiu",
+       "action-editmyusercss": "editar los ficheros CSS d'usuariu propios",
+       "action-editmyuserjson": "editar los ficheros JSON d'usuariu propios",
+       "action-editmyuserjs": "editar los ficheros JavaScript d'usuariu propios",
+       "action-viewsuppressed": "ver revisiones anubríes de cualquier usuariu",
+       "action-hideuser": "bloquiar un nome d'usuariu, tapeciéndolu al públicu",
+       "action-ipblock-exempt": "saltar los bloqueos d'IP, los autobloqueos y los bloqueos de rangos",
+       "action-unblockself": "desbloquiase ún mesmu",
+       "action-noratelimit": "nun tar afeutáu polos llímites de tasa",
+       "action-reupload-own": "sustituir los ficheros esistentes xubíos por ún mesmu",
+       "action-nominornewtalk": "nun amosar l'avisu de nuevos mensaxes cuando se faen ediciones menores en páxines d'alderique",
+       "action-markbotedits": "marcar les ediciones revertíes como ediciones de bot",
+       "action-patrolmarks": "ver les marques de supervisión nos cambeos recientes",
+       "action-override-export-depth": "esportar páxines, incluyendo páxines enllazaes fasta una fondura de 5",
+       "action-suppressredirect": "nun crear redireiciones del orixe al treslladar páxines",
        "nchanges": "{{PLURAL:$1|un cambiu|$1 cambios}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|dende la última visita}}",
        "enhancedrc-history": "historial",
        "rcfilters-savedqueries-already-saved": "Yá se guardaron estos filtros. Cambia la configuración pa crear un Filtru guardáu nuevu.",
        "rcfilters-restore-default-filters": "Restaurar los filtros predeterminaos",
        "rcfilters-clear-all-filters": "Borrar tolos filtros",
-       "rcfilters-show-new-changes": "Ver los cambeos más recién",
+       "rcfilters-show-new-changes": "Ver los cambeos nuevos dende $1",
        "rcfilters-search-placeholder": "Filtriar cambeos (usa'l menú o busca'l nome del filtru)",
        "rcfilters-invalid-filter": "Filtru inválidu",
        "rcfilters-empty-filter": "Nun hai filtros activos. Amuésense toles contribuciones.",
        "rcfilters-filter-editsbyself-description": "Contribuciones de to.",
        "rcfilters-filter-editsbyother-label": "Cambios d'otros",
        "rcfilters-filter-editsbyother-description": "Tolos cambios menos los de to.",
-       "rcfilters-filtergroup-userExpLevel": "Rexistru d'usuarios y esperiencia",
+       "rcfilters-filtergroup-user-experience-level": "Rexistru d'usuarios y esperiencia",
        "rcfilters-filter-user-experience-level-registered-label": "Rexistraos",
        "rcfilters-filter-user-experience-level-registered-description": "Editores coneutaos.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Non rexistraos",
        "rcfilters-hideminor-conflicts-typeofchange-global": "El filtru «Ediciones menores» fai conflictu con un filtru «Tipu de cambiu» o más, porque dellos tipos de cambiu nun pueden designase como «menores». Los filtros que faen conflictu tan marcaos nel área de Filtros Activos, más arriba.",
        "rcfilters-hideminor-conflicts-typeofchange": "Dellos tipos de cambiu nun pueden designase como «menores», de manera qu'esti filtru fai conflictu colos siguientes filtros «Tipu de cambiu»: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Esti filtru de «Tipu de cambiu» fai conflictu col filtru «Ediciones menores». Dellos tipos de cambiu nun pueden designase como «menores».",
-       "rcfilters-filtergroup-lastRevision": "Últimes revisiones",
+       "rcfilters-filtergroup-lastrevision": "Últimes revisiones",
        "rcfilters-filter-lastrevision-label": "Última revisión",
        "rcfilters-filter-lastrevision-description": "Sólo el cambiu más recien d'una páxina.",
        "rcfilters-filter-previousrevision-label": "Non la cabera revisión",
        "rcfilters-watchlist-markseen-button": "Marcar tolos cambios como vistos",
        "rcfilters-watchlist-edit-watchlist-button": "Edita la to llista de páxines siguíes",
        "rcfilters-watchlist-showupdated": "Los cambeos fechos en páxines que nun visitasti desque se ficieron apaecen en <strong>negrina</strong>, con marcadores sólidos.",
-       "rcfilters-preference-label": "Tapecer la versión meyorada de Cambios recién",
-       "rcfilters-preference-help": "Revierte'l rediseñu de la interfaz de 2017 y toles ferramientes añadíes d'entós aquí.",
-       "rcfilters-watchlist-preference-label": "Tapecer la versión ameyorada de la Llista de siguimientu",
-       "rcfilters-watchlist-preference-help": "Desfai el rediseñu de la interfaz de 2017 y toles ferramientes añadíes d'entós acá.",
+       "rcfilters-preference-label": "Usar la interfaz ensin JavaScript",
+       "rcfilters-preference-help": "Carga los cambeos recién ensin filtros de busca nin funcionalidad de resaltáu.",
+       "rcfilters-watchlist-preference-label": "Usar la interfaz ensin JavaScript",
+       "rcfilters-watchlist-preference-help": "Carga la llista de siguimientu ensin filtros de busca nin la funcionalidad de resaltáu.",
        "rcfilters-filter-showlinkedfrom-label": "Amosar los cambios nes páxines enllazaes dende",
        "rcfilters-filter-showlinkedfrom-option-label": "<strong>Páxines enllazaes dende</strong> la páxina seleicionada",
        "rcfilters-filter-showlinkedto-label": "Amosar los cambios nes páxines qu'enllacen a",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|usuariu|usuarios}} vixilando]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} dempués del cambiu",
        "newsectionsummary": "/* $1 */ nueva seición",
        "rc-enhanced-expand": "Amosar detalles",
        "img-auth-nopathinfo": "Falta la información de ruta.\nEl to sirvidor tien de configurase pa pasar les variables REQUEST_URI y/o PATH_INFO.\nSi yá ta fecho, tenta activar $wgUsePathInfo.\nVer https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization",
        "img-auth-notindir": "El camín solicitáu nun ta nel direutoriu de xubíes configuráu.",
        "img-auth-badtitle": "Nun se pue construir un títulu validu dende \"$1\".",
-       "img-auth-nologinnWL": "Nun tas coneutáu y \"$1\" nun ta na llista blanca.",
        "img-auth-nofile": "El ficheru \"$1\" nun esiste.",
        "img-auth-isdir": "Tas tentando acceder al direutoriu \"$1\".\nNamái se permite l'accesu a ficheros.",
        "img-auth-streaming": "Unviando \"$1\".",
        "prefixindex": "Toles páxines col prefixu",
        "prefixindex-namespace": "Toles páxines col prefixu (espaciu de nomes $1)",
        "prefixindex-submit": "Amosar",
-       "prefixindex-strip": "Cortar el prefixu na llista",
+       "prefixindex-strip": "Despintar el prefixu nes resultancies",
        "shortpages": "Páxines curties",
        "longpages": "Páxines llargues",
        "deadendpages": "Páxines ensin salida",
        "delete-confirm": "Desaniciar «$1»",
        "delete-legend": "Desaniciar",
        "historywarning": "<strong>Avisu:</strong> La páxina que vas desaniciar tien un historial con $1 {{PLURAL:$1|revisión|revisiones}}:",
-       "historyaction-submit": "Amosar",
+       "historyaction-submit": "Amosar revisiones",
        "confirmdeletetext": "Tas a piques d'esborrar una páxina xunto con tol so historial.\nPor favor confirma que ye lo que quies facer, qu'entiendes les consecuencies, y que lo tas faciendo acordies coles [[{{MediaWiki:Policy-url}}|polítiques]].",
        "actioncomplete": "Aición completada",
        "actionfailed": "Falló l'aición",
        "deleting-backlinks-warning": "<strong>Avisu:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Otres páxines]] enllacen a, o trescluyen de, la páxina que tas a piques de desaniciar.",
        "deleting-subpages-warning": "<strong>Avisu:</strong> La páxina que vas desaniciar tien [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|una subpáxina|$1 subpáxines|51=más de 50 subpáxines}}]].",
        "rollback": "Revertir ediciones",
+       "rollback-confirmation-confirm": "Confirma:",
+       "rollback-confirmation-yes": "Reversión",
+       "rollback-confirmation-no": "Encaboxar",
        "rollbacklink": "revertir",
        "rollbacklinkcount": "revertir $1 {{PLURAL:$1|edición|ediciones}}",
        "rollbacklinkcount-morethan": "revertir más de $1 {{PLURAL:$1|edición|ediciones}}",
        "revertpage": "Revertíes les ediciones de [[Special:Contributions/$2|$2]] ([[User talk:$2|alderique]]) hasta la cabera versión de [[User:$1|$1]]",
        "revertpage-nouser": "Revertíes les ediciones de (usuariu desaniciáu) a la cabera revisión de {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Revertíes les ediciones de {{GENDER:$3|$1}}; devueltu a la última revisión de {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Revertíes les ediciones de $1 a la última revisión de $2. [$3 Ver cambeos]",
        "sessionfailure-title": "Fallu de sesión",
        "sessionfailure": "Paez qu'hai un problema col aniciu de sesión;\natayóse esta aición por precaución escontra secuestru de sesiones.\nUnvia'l formulariu otra vegada.",
        "changecontentmodel": "Cambiar el modelu de conteníu d'una páxina",
        "mycontris": "Collaboraciones",
        "anoncontribs": "Contribuciones",
        "contribsub2": "Pa {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "Pa {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "La cuenta d'usuariu «$1» nun ta rexistrada.",
+       "negative-namespace-not-supported": "Nun se permiten los espacios de nomes con valores negativos.",
        "nocontribs": "Nun s'atoparon cambeos que coincidan con esi criteriu.",
        "uctop": "actual",
        "month": "Dende'l mes (y anteriores):",
        "ipbreason": "Motivu:",
        "ipbreason-dropdown": "*Motivos comunes de bloquéu\n** Enxertamientu d'información falso\n** Dexar les páxines en blanco\n** Enllaces spam a páxines esternes\n** Enxertamientu de babayaes/enguedeyos nes páxines\n** Comportamientu intimidatoriu o d'acosu\n** Abusu de cuentes múltiples\n** Nome d'usuariu inaceutable",
        "ipb-hardblock": "Torgar que los usuarios coneutaos editen dende esta direición IP",
-       "ipbcreateaccount": "Torgar la creación de cuentes",
-       "ipbemailban": "Torgar al usuariu l'unviu de corréu electrónicu",
+       "ipbcreateaccount": "Creación de cuentes",
+       "ipbemailban": "Unviar correos",
        "ipbenableautoblock": "Bloquiar automáticamente la cabera direición IP usada por esti usuariu y toles IP posteriores dende les qu'intente editar",
        "ipbsubmit": "Bloquiar esti usuariu",
        "ipbother": "Otru periodu:",
        "ipboptions": "2 hores:2 hours,1 día:1 day,3 díes:3 days,1 selmana:1 week,2 selmanes:2 weeks,1 mes:1 month,3 meses:3 months,6 meses:6 months,1 añu:1 year,indefiníu:infinite",
        "ipbhidename": "Anubrir el nome d'usuariu d'ediciones y llistes",
        "ipbwatchuser": "Vixilar les páxines d'usuariu y d'alderique d'esti usuariu",
-       "ipb-disableusertalk": "Torgar qu'esti usuariu edite la so páxina d'alderique mentanto tea bloquiáu",
+       "ipb-disableusertalk": "Editar la páxina d'alderique propia",
        "ipb-change-block": "Volver a bloquiar l'usuariu con estos parámetros",
        "ipb-confirm": "Confirmar bloquéu",
+       "ipb-sitewide": "En tol sitiu",
+       "ipb-partial": "Parcial",
+       "ipb-sitewide-help": "Toles páxines de la wiki ya'l restu d'aiciones de contribución.",
+       "ipb-partial-help": "Páxines o espacios de nomes específicos.",
+       "ipb-pages-label": "Páxines",
+       "ipb-namespaces-label": "Espacios de nomes",
        "badipaddress": "Dirección IP inválida",
        "blockipsuccesssub": "Bloquéu fechu correctamente",
        "blockipsuccesstext": "[[Special:Contributions/$1|$1]] ta {{GENDER:$1|bloquiáu|bloquiada}}.<br />\nMira na [[Special:BlockList|llista de bloqueos]] pa revisar los bloqueos.",
        "ipb-blocklist": "Ver los bloqueos esistentes",
        "ipb-blocklist-contribs": "Collaboraciones de {{GENDER:$1|$1}}",
        "ipb-blocklist-duration-left": "falten $1",
+       "block-actions": "Acciones a bloquiar:",
        "block-expiry": "Caducidá:",
+       "block-options": "Opciones adicionales:",
+       "block-prevent-edit": "Edición",
+       "block-reason": "Motivu:",
+       "block-target": "Nome d'usuariu o direición IP:",
        "unblockip": "Desbloquiar usuariu",
        "unblockiptext": "Usa'l formulariu d'abaxo pa restablecer l'accesu d'escritura a una direicion IP o a un nome d'usuariu previamente bloquiáu.",
        "ipusubmit": "Desaniciar esti bloquéu",
        "blocklist-userblocks": "Anubrir los bloqueos de cuenta",
        "blocklist-tempblocks": "Anubrir los bloqueos temporales",
        "blocklist-addressblocks": "Anubrir los bloqueos d'IP simples",
+       "blocklist-type": "Triba:",
+       "blocklist-type-opt-all": "Toes",
+       "blocklist-type-opt-sitewide": "En tol sitiu",
+       "blocklist-type-opt-partial": "Parcial",
        "blocklist-rangeblocks": "Anubrir los bloqueos de rangu",
        "blocklist-timestamp": "Marca d'hora",
        "blocklist-target": "Oxetivu",
        "createaccountblock": "creación de cuentes desactivada",
        "emailblock": "corréu electrónicu desactiváu",
        "blocklist-nousertalk": "nun puede editar la páxina d'alderique propia",
+       "blocklist-editing": "edición",
+       "blocklist-editing-sitewide": "edición (en tol sitiu)",
+       "blocklist-editing-page": "páxines",
+       "blocklist-editing-ns": "espacios de nomes",
        "ipblocklist-empty": "La llista de bloqueos ta vacia.",
-       "ipblocklist-no-results": "La direición IP o nome d'usuariu solicitáu nun ta bloquiáu.",
+       "ipblocklist-no-results": "Nun s'alcontraron bloqueos pa la direición IP o nome d'usuariu solicitáu.",
        "blocklink": "bloquiar",
        "unblocklink": "desbloquiar",
        "change-blocklink": "camudar el bloquéu",
+       "empty-username": "(nun ta disponible'l nome d'usuariu)",
        "contribslink": "contribuciones",
        "emaillink": "unviar corréu",
        "autoblocker": "Bloquiáu automáticamente porque la so direición IP usóla de recién «[[User:$1|$1]]». El motivu del bloquéu de $1 ye «$2»",
        "move-watch": "Vixilar les páxines d'orixe y destín",
        "movepagebtn": "Treslladar la páxina",
        "pagemovedsub": "Treslláu correctu",
+       "cannotmove": "La páxina nun pudo treslladase {{PLURAL:$1|pol siguiente motivu|polos siguientes motivos}}:",
        "movepage-moved": "<strong>«$1» treslladóse a «$2»</strong>",
        "movepage-moved-redirect": "Creóse una redireición.",
        "movepage-moved-noredirect": "Desaniciose la creación d'una redireición.",
        "allmessagesdefault": "Testu predetermináu",
        "allmessagescurrent": "Testu actual del mensaxe",
        "allmessagestext": "Esta ye una llista de los mensaxes de sistema disponibles nel espaciu de nomes de MediaWiki.\nPor favor visita [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Llocalización de MediaWiki] y [https://translatewiki.net translatewiki.net] si quies contribuyer a la llocalización xenérica de MediaWiki.",
-       "allmessagesnotsupportedDB": "Esta páxina nun puede usase porque ta desactivao <strong>$wgUseDatabaseMessages</strong>.",
+       "allmessages-not-supported-database": "Esta páxina nun puede usase porque ta desactivao <strong>$wgUseDatabaseMessages</strong>.",
        "allmessages-filter-legend": "Peñerar",
        "allmessages-filter": "Peñerar por estáu de personalización:",
        "allmessages-filter-unmodified": "Ensin cambeos",
        "pageinfo-display-title": "Amosar el títulu",
        "pageinfo-default-sort": "Clave d'ordenación predeterminada",
        "pageinfo-length": "Llonxitú de la páxina (en bytes)",
+       "pageinfo-namespace": "Espaciu de nomes",
        "pageinfo-article-id": "ID de la páxina",
        "pageinfo-language": "Llingua del conteníu de la páxina",
        "pageinfo-language-change": "camudar",
        "pageinfo-category-files": "Númberu de ficheros",
        "pageinfo-user-id": "ID d'usuariu",
        "pageinfo-file-hash": "Valor del hash criptográficu",
+       "pageinfo-view-protect-log": "Ver el rexistru de protecciones d'esta páxina.",
        "markaspatrolleddiff": "Marcar como supervisada",
        "markaspatrolledtext": "Marcar esta páxina como supervisada",
        "markaspatrolledtext-file": "Marcar esta versión del ficheru como patrullada",
        "previousdiff": "← Edición más antigua",
        "nextdiff": "Edición más nueva →",
        "mediawarning": "'''Avisu''': Esta triba de ficheru pue contener códigu maliciosu.\nAl executalu pues comprometer el to sistema.",
-       "imagemaxsize": "Llende del tamañu d'imaxe: <br /><em>(pa les páxines de descripción de ficheru)</em>",
+       "imagemaxsize": "Llende del tamañu d'imaxe nes páxines de descripción de ficheros:",
        "thumbsize": "Tamañu de la miniatura:",
        "widthheightpage": "$1 × $2, $3 {{PLURAL:$3|páxina|páxines}}",
        "file-info": "tamañu de ficheru: $1, triba MIME: $2",
        "confirm-unwatch-top": "¿Desaniciar esta páxina de la to llista de vixilancia?",
        "confirm-rollback-button": "Aceutar",
        "confirm-rollback-top": "¿Revertir les ediciones a esta páxina?",
+       "confirm-rollback-bottom": "Esta aición revertirá nel intre los cambios seleicionaos d'esta páxina.",
+       "confirm-mcrrestore-title": "Restaurar una revisión",
        "confirm-mcrundo-title": "Desfacer un cambéu",
        "mcrundofailed": "Falló desfacer",
        "mcrundo-missingparam": "Faltan parámetros riquíos na solicitú.",
        "logentry-block-block": "$1 {{GENDER:$2|bloquió}} a {{GENDER:$4|$3}} con un tiempu de duración de $5 $6",
        "logentry-block-unblock": "$1 {{GENDER:$2|desbloquió a}} {{GENDER:$4|$3}}",
        "logentry-block-reblock": "$1 {{GENDER:$2|cambió}} la configuracion del bloquéu a {{GENDER:$4|$3}} con un tiempu de caducidá de $5 $6",
+       "logentry-partialblock-block-page": "{{PLURAL:$1|la páxina|les páxines}} $2",
+       "logentry-partialblock-block-ns": "{{PLURAL:$1|l'espaciu de nomes|los espacios de nomes}} $2",
+       "logentry-partialblock-block": "$1 {{GENDER:$2|bloquió}} a {{GENDER:$4|$3}} la edición de $7 con un tiempu de caducidá de $5 $6",
+       "logentry-partialblock-reblock": "$1 {{GENDER:$2|cambió}} la configuracion del bloquéu a {{GENDER:$4|$3}} pa torgar editar $7 con un tiempu de caducidá de $5 $6",
        "logentry-suppress-block": "$1 {{GENDER:$2|bloquió}} a {{GENDER:$4|$3}} con un tiempu de caducidá de $5 $6",
        "logentry-suppress-reblock": "$1 {{GENDER:$2|cambió}} la configuracion del bloquéu a {{GENDER:$4|$3}} con un tiempu de caducidá de $5 $6",
        "logentry-import-upload": "$1 {{GENDER:$2|importó}} $3 xubiendo un ficheru",
        "logentry-rights-autopromote": "$1 {{GENDER:$2|promocionó}} automáticamente de $4 a $5",
        "logentry-upload-upload": "$1 {{GENDER:$2|xubió}} $3",
        "logentry-upload-overwrite": "$1 {{GENDER:$2|xubió}} una versión nueva de $3",
-       "logentry-upload-revert": "$1 {{GENDER:$2|xubió}} $3",
+       "logentry-upload-revert": "$1 {{GENDER:$2|revirtió}} $3 a una versión anterior",
        "log-name-managetags": "Rexistru de xestión d'etiquetes",
        "log-description-managetags": "Esta páxina tien la llista de les xeres de xestión rellacionaes coles [[Special:Tags|etiquetes]]. El rexistru contien namái les aiciones feches manuamente por un alministrador; les etiquetes pueden crease o desaniciase pol software wiki ensin que quede grabada una entrada nesti rexistru.",
        "logentry-managetags-create": "$1 {{GENDER:$2|creó}} la etiqueta «$4»",
        "mw-widgets-titleinput-description-redirect": "redirixir a $1",
        "mw-widgets-categoryselector-add-category-placeholder": "Amestar una categoría...",
        "mw-widgets-usersmultiselect-placeholder": "Amestar más...",
+       "mw-widgets-titlesmultiselect-placeholder": "Amestar más...",
        "date-range-from": "Dende la data:",
        "date-range-to": "Ata la data:",
        "sessionmanager-tie": "Nun puen combinase dellos tipos de solicitú d'identificación: $1.",
        "log-action-filter-suppress-reblock": "Supresión d'usuariu por rebloquéu",
        "log-action-filter-upload-upload": "Nueva carga",
        "log-action-filter-upload-overwrite": "Recargar",
+       "log-action-filter-upload-revert": "Revertir",
        "authmanager-authn-not-in-progress": "L'autenticación nun ta en cursu o los datos de sesión perdiéronse. Por favor, vuelve de nueves al principiu.",
        "authmanager-authn-no-primary": "Les credenciales apurríes nun pudieron autentificase.",
        "authmanager-authn-no-local-user": "Les credenciales apurríes nun tán asociaes con nengún usuariu nesta wiki.",
        "passwordpolicies-policy-passwordcannotmatchblacklist": "La contraseña nun puede casar con contraseñes torgaes específicamente",
        "passwordpolicies-policy-maximalpasswordlength": "La llonxitú de la contraseña tien de ser menor que {{PLURAL:$1|1 caráuter|$1 caráuteres}}",
        "passwordpolicies-policy-passwordcannotbepopular": "La contraseña nun puede {{PLURAL:$1|ser la contraseña más popular|tar na llista de $1 contraseñes populares}}",
-       "easydeflate-invaliddeflate": "El conteníu dau nun ta comprimíu correutamente"
+       "passwordpolicies-policy-passwordnotinlargeblacklist": "La contraseña nun pué tar na llista de les 100.000 contraseñes más usaes.",
+       "passwordpolicies-policyflag-forcechange": "tien de camudase al aniciar sesión",
+       "passwordpolicies-policyflag-suggestchangeonlogin": "suxerir cambiu al aniciar sesión",
+       "easydeflate-invaliddeflate": "El conteníu dau nun ta comprimíu correutamente",
+       "userlogout-sessionerror": "Falló salir por un error de sesión. [$1 Tenta nuevamente]."
 }
index 8cfd032..1584882 100644 (file)
        "minoreditletter": "b",
        "newpageletter": "W",
        "boteditletter": "st",
-       "number_of_watching_users_pageview": "[$1 nedis {{PLURAL:$1|favesik|favesik}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} radimi betara",
        "newsectionsummary": "/* $1 */ warzaf gabot",
        "rc-enhanced-expand": "Pintanedira (JavaScript tir adraf)",
        "allmessagesdefault": "Omavaf krent",
        "allmessagescurrent": "Noelaf krent",
        "allmessagestext": "Batcoba tir vexala dem bolkstakseem koe MediaWiki yoltxo.\n\nVa [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] is [https://translatewiki.net translatewiki.net] vay woral ede va tulizukara va Mediawiki co-rowebel.",
-       "allmessagesnotsupportedDB": "Batu bu me zo rofaver kire '''$wgUseDatabaseMessages''' mea tir tegis.",
+       "allmessages-not-supported-database": "Batu bu me zo rofaver kire '''$wgUseDatabaseMessages''' mea tir tegis.",
        "thumbnail-more": "Tulogijara",
        "filemissing": "Gracaf iyeltak",
        "thumbnail_error": "Va $1 aluk redujara",
index d239129..28449c2 100644 (file)
        "minoreditletter": "छो",
        "newpageletter": "न",
        "boteditletter": "बॉ",
-       "number_of_watching_users_pageview": "[$1 ध्यान राखय वाले {{PLURAL:$1|सदस्य}}]",
        "rc-change-size-new": "बदलाव कय बाद $1 {{PLURAL:$1|बाइट}}",
        "newsectionsummary": "/* $1 */ नँवा अनुभाग",
        "rc-enhanced-expand": "विस्तृत जानकारी देखावा जाय",
        "img-auth-nopathinfo": "PATH_INFO मौजूद नाइ है।\nआप कय सर्वर मा इ जानकारी भेजय खत्तीर जमाव नाइ है।\nइ सी॰जी॰आई-आधारित होइ सकत है औ img_auth कय स्वीकार नाइ करत है।\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization देखें।",
        "img-auth-notindir": "अनुरोधित पथ जमावल अपलोड डायरेक्टरी मा नाइ है।",
        "img-auth-badtitle": "\"$1\" से एकठु वैध शीर्षक बनावे मा असमर्थ।",
-       "img-auth-nologinnWL": "आप लाग इन् नाइ करे हौ औ \"$1\" श्वेतसूची मा नाइ हौ।",
        "img-auth-nofile": "\"$1\" फाइल नाइ है।",
        "img-auth-isdir": "आप डायरेक्टरी \"$1\" खोलेक कोशिश करा जात है ।\nखालि फ़ाइल खोली जा सकत है।",
        "img-auth-streaming": "\"$1\"  स्ट्रीम होत है।",
        "allmessagesdefault": "सनेशा कय डिफ़ॉल्ट पाठ",
        "allmessagescurrent": "वर्तमान पाठ",
        "allmessagestext": "ये मीडियाविकि नामस्थान में उपलब्ध प्रणाली संदेशों की एक सूची है। यदि आप सामान्य मीडियाविकि क्षेत्रीयकरण में योगदान देना चाहें तो कृपया [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation मीडियाविकि क्षेत्रीयकरण] व [https://translatewiki.net translatewiki.net] को देखें।",
-       "allmessagesnotsupportedDB": "इस पृष्ठ का इस्तेमाल नहीं कर सकते क्योंकी '''$wgUseDatabaseMessages''' बंद हैं।",
+       "allmessages-not-supported-database": "इस पृष्ठ का इस्तेमाल नहीं कर सकते क्योंकी '''$wgUseDatabaseMessages''' बंद हैं।",
        "allmessages-filter-legend": "फिल्टर",
        "allmessages-filter": "अनुकूलन स्थिति कय आधार पे छाना जाय:",
        "allmessages-filter-unmodified": "अपरिवर्तित",
index b917b9d..2bd0bca 100644 (file)
@@ -33,7 +33,8 @@
                        "Neriman2003",
                        "Fitoschido",
                        "Toghrul Rahimli",
-                       "Vlad5250"
+                       "Vlad5250",
+                       "Hüseynzadə"
                ]
        },
        "tog-underline": "Keçidlərin altını xətlə:",
@@ -79,6 +80,7 @@
        "tog-norollbackdiff": "Geri qaytardıqdan sonra dəyişikliklər arasındakı fərqi göstərmə",
        "tog-useeditwarning": "Qeyd edilməmiş dəyişikliyə sahib bir dəyişiklik səhifəsindən çıxarkən məni xəbərdar et",
        "tog-prefershttps": "Daxil olarkən hər zaman mühafizə edilən bağlantıdan istifadə et.",
+       "tog-showrollbackconfirmation": "Bir rollback linkinə kliklədiyinizdə təsdiq sorğusunu göstərin",
        "underline-always": "Həmişə",
        "underline-never": "Heç vaxt",
        "underline-default": "Susmaya görə brouzer",
        "confirmable-confirm": "{{GENDER:$1|Siz}} əminsiniz?",
        "confirmable-yes": "Bəli",
        "confirmable-no": "Xeyr",
-       "thisisdeleted": "$1 bax və ya bərpa et?",
+       "thisisdeleted": "$1 baxmaq və ya bərpa etmək istəyirsinizmi?",
        "viewdeleted": "$1 göstərilsin?",
        "restorelink": "$1 silinmiş redaktəyə",
        "feedlinks": "Kanal növü:",
        "filerenameerror": "\"$1\" faylının adını \"$2\"-yə dəyişmək mümkün deyil",
        "filedeleteerror": "\"$1\" fayılını silə bilmədi.",
        "directorycreateerror": "\"$1\" direktoriyasını yaratmaq mümkün deyil",
-       "directoryreadonlyerror": "\"$1\" təlimatçısı yalnız oxunur.",
+       "directoryreadonlyerror": "\"$1\" təlimatçısı yalnız oxuna bilər.",
        "directorynotreadableerror": "\"$1\" təlimatçısı oxuna bilmir.",
        "filenotfound": "\"$1\" faylını tapa bilmədi.",
        "unexpected": "Uyğunsuzluq: \"$1\"=\"$2\".",
        "userlogin-signwithsecure": "Etibarlı bağlantıdan istifadə edin",
        "cannotlogin-title": "Daxil olmaq mümkün olmadı",
        "cannotlogin-text": "Daxil olmaq mümkün deyil.",
-       "cannotloginnow-title": "Daxil olmaq indi mümkün deyil",
+       "cannotloginnow-title": "Hazırda daxil olmaq mümkün deyil",
        "cannotloginnow-text": "$1 istifadə edərkən daxil olmaq mümkün deyil.",
        "cannotcreateaccount-title": "Hesablar yaradıla bilmədi",
        "cannotcreateaccount-text": "Bu vikidə birbaşa hesab yaratma aktiv deyil.",
        "createacct-reason-help": "Hesab yaratma qeydlərində göstərilən mesaj",
        "createacct-submit": "İstifadəçi hesabı yarat",
        "createacct-another-submit": "İstifadəçi hesabı yarat",
+       "createacct-continue-submit": "Hesab yaratmağı davam etdirin",
+       "createacct-another-continue-submit": "Hesab yaratmağı davam etdirin",
        "createacct-benefit-heading": "{{SITENAME}} sizin kimi insanlar tərəfindən yaradılır.",
        "createacct-benefit-body1": "{{PLURAL:$1|redaktə}}",
        "createacct-benefit-body2": "{{PLURAL:$1|səhifə|səhifə}}",
        "createacct-benefit-body3": "yeni {{PLURAL:$1|redaktor}}",
        "badretype": "Daxil etdiyiniz parol uyğun gəlmir.",
+       "usernameinprogress": "Bu istifadəçi adı üçün bir hesab yaratma artıq başlamışdır.\nZəhmət olmasa, gözləyin.",
        "userexists": "Daxil edilmiş ad artıq istifadədədir.\nLütfən başqa ad seçin.",
+       "createacct-normalization": "Texniki məhdudiyyətlər səbəbiylə istifadəçi adınız \"$2\" olaraq düzəldiləcək.",
        "loginerror": "Daxil olma xətası",
        "createacct-error": "Hesab yaratma xətası",
        "createaccounterror": "Bu istifadəçi adını yaratmaq mümkün olmadı: $1",
        "nocookieslogin": "{{SITENAME}} istifadəçilərin daxil ola bilməsi üçün \"cookie\"lərdən istifadə edir. Siz \"cookie\"lərin qəbuluna qadağa qoymusunuz. Lütfən, onların qəbuluna icazə verin və bir daha daxil olmağa cəhd edin.",
        "nocookiesfornew": "İstifadəçinin akkauntu yaradılmayıb, ona görə də biz onun mənbəsini təsdiqləyə bilmədik.\nKukların qoşulmasına əmin olduqdan sonra səhifəni yeniləyib bir daha sınayın.",
        "nocookiesforlogin": "{{int:nocookieslogin}}",
+       "createacct-loginerror": "Hesab müvəffəqiyyətlə yaradılıb, lakin avtomatik olaraq daxil olma mümkün olmadə. Zəhmət olmasa, [[Special:UserLogin|daxil olma]] səhifəsinə keçin.",
        "noname": "Siz mövcud olan istifadəçi adı daxil etməmisiniz.",
        "loginsuccesstitle": "Daxil oldunuz",
        "loginsuccess": "'''\"$1\" adı ilə sistemə daxil oldunuz.'''",
        "nosuchusershort": "\"$1\" adlı istifadəçi mövcud deyil. Yazdığınızı yoxlayın.",
        "nouserspecified": "İstifadəçi adı daxil etməlisiniz.",
        "login-userblocked": "Bu istifadəçi bloklanıb. Sistemə giriş üçün icazə verilmir.",
-       "wrongpassword": "Səhv parol. Təkrar yazın.",
+       "wrongpassword": "Yanlış istifadəçi adı və ya şifrə.\nZəhmət olmasa, bir daha cəhd edin.",
        "wrongpasswordempty": "Parol boş. Təkrar yazın.",
        "passwordtooshort": "Parolda ən azı {{PLURAL:$1|1 hərf yaxud simvol|$1 hərf yaxud simvol}} olmalıdır.",
+       "passwordtoolong": "Parolda ən azı {{PLURAL:$1|1 hərf yaxud simvol|$1 hərf yaxud simvol}} olmalıdır.",
+       "passwordtoopopular": "Çox istifadə edilən parollar seçilə bilməz. Xahiş edirik təxmin edilməsi daha çətin olan bir parol seçin.",
+       "passwordinlargeblacklist": "Daxil edilən parol çox istifadə edilən parolların siyahısında mövcuddur. Xahiş edirik daha bənzərsiz parol seçin.",
        "password-name-match": "Parol adınızdan fərqli olmalıdır.",
        "password-login-forbidden": "Bu istifadəçi adından və paroldan istifadə qadağan olunub.",
        "mailmypassword": "E-mail ilə yeni parol göndər",
        "passwordremindertitle": "{{SITENAME}} parol xatırladıcı",
-       "passwordremindertext": "Kimsə (ehtimal ki, siz özünüz, $1 IP ünvanından) {{SITENAME}} ($4) layihəsi \nüçün yeni bir parol göndərilməsini istəyib. \"$2\" adlı istifadəçi üçün müvəqqəti \nolaraq \"$3\" parolu yaradılıb. Əgər bu sizin istəyiniz əsasında olubsa, \nhesabınıza daxil olaraq yeni bir parol yaratmağınız vacibdir. Müvəqqəti parolunuz\n{{PLURAL:$5|1 gün|$5 gün}} ərzində qüvvədə olacaqdır.\n\nParol dəyişdirməni siz istəməmisinizsə və ya parolunuzu xatırladınızsa \nvə artıq parolunuzu dəyişdirmək istəmirsinizsə, bu mesaja əhəmiyyət vermədən \nəvvəlki parolunuzdan istifadə etməyə davam edə bilərsiniz.",
+       "passwordremindertext": "Kimsə ($1 IP ünvanından) {{SITENAME}} ($4) layihəsi \nüçün yeni bir parol göndərilməsini istəyib. \"$2\" adlı istifadəçi üçün müvəqqəti \nolaraq \"$3\" parolu yaradılıb. Əgər bu sizin istəyiniz əsasında olubsa, \nhesabınıza daxil olaraq yeni bir parol yaratmağınız vacibdir. Müvəqqəti parolunuz\n{{PLURAL:$5|1 gün|$5 gün}} ərzində qüvvədə olacaqdır.\n\nParol dəyişdirməni siz istəməmisinizsə və ya parolunuzu xatırladınızsa \nvə artıq parolunuzu dəyişdirmək istəmirsinizsə, bu mesaja əhəmiyyət vermədən \nəvvəlki parolunuzdan istifadə etməyə davam edə bilərsiniz.",
        "noemail": "\"$1\" adlı istifadəçi e-poçt ünvanını qeyd etməmişdir.",
        "noemailcreate": "Düzgün e-poçt ünvanı qeyd etməlisiniz",
        "passwordsent": "Yeni parol \"$1\" üçün qeydiyyata alınan e-poçt ünvanına göndərilmişdir.\nXahiş edirik, e-məktubu aldıqdan sonra yenidən daxil olasınız.",
        "createaccount-text": "Biriləri {{SITENAME}} saytında ($4) sizin e-poçt ünvanınızdan istifadə edərək, parolu \"$3\" olan, \"$2\" adlı bir hesab yaratdı.\n\nSayta daxil olmalı və parolunuzu dəyişdirməlisiniz.\n\nƏgər istifadəçi hesabını səhvən yaratmısınızsa, bu mesajı gözardı edə bilərsiniz.",
        "login-throttled": "Sistemə daxil olmaq üçün həddən artıq cəhd etmisiniz.\nYeni cəhd etməzdən əvvəl $1 gözləyin.",
        "login-abort-generic": "Giriş uğursuz alındı — ləğv olundu",
+       "login-migrated-generic": "Hesabınız köçürüldü və bu vikidə istifadəçi adınız artıq mövcud deyil.",
        "loginlanguagelabel": "Dil: $1",
        "suspicious-userlogout": "Sizin çıxış üçün cəhdiniz uğursuz alındı. Bu, brouzerin yaxud proksi-keşləmənin düzgün işləməməsindən qaynaqlanır.",
        "createacct-another-realname-tip": "Gərçək adınız istəyə bağlıdır.\nƏgər gərçək adınızı göstərsəniz, çalışmalarınıza müraciət etmək üçün istifadə ediləcəkdir.",
        "pt-login": "Daxil ol",
        "pt-login-button": "Daxil ol",
+       "pt-login-continue-button": "Daxil olmağa davam edin",
        "pt-createaccount": "Hesab yarat",
        "pt-userlogout": "Çıxış",
        "php-mail-error-unknown": "PHP-nin mail() funksiyasında naməlum xəta",
        "retypenew": "Yeni parolu təkrar yazın:",
        "resetpass_submit": "Parol yaradın və sistemə daxil olun",
        "changepassword-success": "Parolunuz dəyişdirildi!",
+       "changepassword-throttled": "Sistemə daxil olmaq üçün həddən artıq cəhd etmisiniz.\nYeni cəhd etməzdən əvvəl $1 gözləyin.",
+       "botpasswords": "Bot parolları",
+       "botpasswords-summary": "<em>Bot parolları</em> hesabın əsas giriş etmə məlumatlarını istifadə etmədən API vasitəsilə bir istifadəçi hesabına giriş imkanı verir. Bir bot parol ilə daxil olduqda mövcud istifadəçi hüquqları məhdudlaşdırıla bilər.\n\nNiyə bunu edə biləcəyinizi bilmirsinizsə, bunu etməməlisiniz. Heç kim sizdən bunlardan birini yaratmağı və ona verməyinizi istəməyəcək.",
+       "botpasswords-disabled": "Bot parolları söndürüldü.",
+       "botpasswords-no-central-id": "Bot parollarını istifadə etmək üçün mərkəzləşdirilmiş bir hesaba daxil olmalısınız.",
+       "botpasswords-existing": "Mövcud bot parolları",
+       "botpasswords-createnew": "Yeni bot parolu yarat",
+       "botpasswords-editexisting": "Mövcud bot parolunu redaktə et",
+       "botpasswords-label-needsreset": "(parol sıfırlanmalıdır)",
        "botpasswords-label-appid": "Bot adı:",
        "botpasswords-label-create": "Yarat",
        "botpasswords-label-update": "Yenilə",
        "botpasswords-label-cancel": "Ləğv et",
        "botpasswords-label-delete": "Sil",
+       "botpasswords-label-resetpassword": "Parolu sıfırla",
+       "botpasswords-label-grants": "Tətbiq edilən hüquqlar:",
+       "botpasswords-help-grants": "Hüquqlar, istifadəçi hesabınız tərəfindən artıq saxlanılan hüquqlara giriş imkanı verir. Burada bir hüquq verilərkən, istifadəçi hesabınızın başqa cür olmadığı heç bir haqqı təmin etmir. Daha ətraflı məlumat üçün [[Special:ListGrants| hüquqlar]] səhifəsinə baxın.",
+       "botpasswords-label-grants-column": "Hüquq verildi",
+       "botpasswords-bad-appid": "\"$1\" bot adı etibarlı deyil.",
+       "botpasswords-insert-failed": "Bot adı \"$1\" əlavə etməyib. Artıq əlavə edilsin?",
+       "botpasswords-update-failed": "\"$1\" bot adı yenilənmədi. Silinsin?",
+       "botpasswords-created-title": "Bot parolu yaradıldı",
+       "botpasswords-created-body": "\"$2\" adlı istifadəçinin \"$1\" bot adı üçün bot parolu yaradıldı.",
+       "botpasswords-updated-title": "Bot parolu yeniləndi",
+       "botpasswords-updated-body": "\"$2\" adlı istifadəçinin \"$1\" bot adı üçün bot parolu yeniləndi.",
+       "botpasswords-deleted-title": "Bot parolu silindi",
+       "botpasswords-deleted-body": "\"$2\" adlı istifadəçinin \"$1\" bot adı üçün bot parolu silindi.",
+       "botpasswords-newpassword": "<strong>$1</strong> ilə daxil olmaq üçün yeni parol: <strong>$2</strong>. <em> Gələcək arayış üçün qeyd edin. </em> <br> (Giriş adının nüfuzlu istifadəçi adı ilə eyni olmasını tələb edən köhnə botlara görə <strong>$3</strong> istifadəçi adını və <strong>$4</strong> parolunu da istifadə edə bilərsiniz)",
+       "botpasswords-no-provider": "BotPasswordsSessionProvider mövcud deyil.",
+       "botpasswords-restriction-failed": "Bot parol məhdudiyyətləri bu girişə mane olur.",
+       "botpasswords-invalid-name": "Göstərilən istifadəçi adı bot ayırıcısını (\"$1\") ehtiva etmir.",
+       "botpasswords-not-exist": "\"$1\" adlı istifadəçinin \"$2\" adlı bot şifrəsi yoxdur.",
+       "botpasswords-needs-reset": "\"$1\" adlı istifadəçinin \"$2\" bot adı üçün bot şifrəsi sıfırlanmalıdır.",
+       "botpasswords-locked": "Hesabınız kilidləndiyinə görə bot şifrəsi ilə giriş edə bilməzsiniz.",
        "resetpass_forbidden": "Parolu dəyişmək mümkün deyil",
+       "resetpass_forbidden-reason": "Şifrəni dəyişmək mümkün deyil: $1",
        "resetpass-no-info": "Bu səhifəni birbaşa açmaq üçün sistemə daxil olmalısınız.",
        "resetpass-submit-loggedin": "Parolu dəyiş",
        "resetpass-submit-cancel": "Ləğv et",
        "resetpass-wrong-oldpass": "Müvəqqəti və ya daimi parolda yanlışlıq var.\nOla bilər siz parolu müvəffəqiyyətlə dəyişmisiniz, yaxud yeni müvəqqəti parol üçün müraciət etmisiniz.",
+       "resetpass-recycled": "Şifrənizi mövcud şifrədən başqasına dəyişdirin.",
+       "resetpass-temp-emailed": "Siz müvəqqəti e-poçt kodu ilə daxil oldunuz. \nDaxil olmağı bitirmək üçün bura yeni bir şifrə yazmalısınız:",
        "resetpass-temp-password": "Müvəqqəti parol:",
        "resetpass-abort-generic": "Parol dəyişikliyi bir genişlənmə tərəfindən ləğv edildi.",
+       "resetpass-expired": "Şifrənizin müddəti doldu. Daxil olmaq üçün yeni bir şifrə təyin edin.",
+       "resetpass-expired-soft": "Şifrənizin müddəti başa çatdığı üçün dəyişdirilməlidir. Xahiş edirik, yeni bir şifrə seçin və ya daha sonra dəyişdirmək üçün \"{{int:authprovider-resetpass-skip-label}}\" düyməsinə basın.",
+       "resetpass-validity": "Şifrəniz etibarlı deyil: $1\n\nDaxil olmaq üçün yeni bir şifrə təyin edin.",
+       "resetpass-validity-soft": "Şifrəniz etibarlı deyil: $1\n\nXahiş edirik yeni bir şifrə seçin və ya daha sonra dəyişdirmək üçün \"{{int: authprovider-resetpass-skip-label}}\" düyməsinə basın.",
        "passwordreset": "Parolu yenilə",
        "passwordreset-text-one": "Parolunuzu sıfırlamaq üçün bu formanı doldurun.",
        "passwordreset-text-many": "{{PLURAL:$1|Parolunuzu sıfırlamaq üçün sahələrdən birini doldurun.}}",
        "passwordreset-email": "E-mail ünvanı:",
        "passwordreset-emailtitle": "{{SITENAME}} hesabın yaradılması",
        "passwordreset-emailtext-ip": "Kimsə, (ehtimal ki siz özünüz, $1 IP adresindən) {{SITENAME}} ($4) layihəsindəki hesabınızın \nparolunun yenilənməsini istəyib. Aşağıdakı istifadəçi {{PLURAL:$3|hesabı|hesabları}} bu e-poçt adresinə bağlıdır:\n\n$2\n\nBu müvəqqəti {{PLURAL:$3|parol|parollar}} {{PLURAL:$5|bir gün|$5 gün}} qüvvədə olacaqdır.\nSiz müvəqqəti parolla daxil olub yeni bir parol seçməlisiniz. Əgər parolun dəyişdirilməsini siz istəməmisinizsə və ya parolunuzu xatırladınızsa və artıq onu dəyişmək istəmirsinizsə, bu məktuba əhəmiyyət verməyərək köhnə parolunuzu istifadə etməyə davam edə bilərsiniz.",
+       "passwordreset-emailtext-user": "Kimsə, ($1 IP adresindən) {{SITENAME}} ($4) layihəsindəki hesabınızın \nparolunun sıfırlanmasını istəyib. Aşağıdakı istifadəçi {{PLURAL:$3|hesabı|hesabları}} bu e-poçt adresinə bağlıdır:\n\n$2\n\nBu müvəqqəti {{PLURAL:$3|parol|parollar}} {{PLURAL:$5|bir gün|$5 gün}} qüvvədə olacaqdır.\nSiz müvəqqəti parolla daxil olub yeni bir parol seçməlisiniz. Əgər parolun dəyişdirilməsini siz istəməmisinizsə və ya parolunuzu xatırladınızsa və artıq onu dəyişmək istəmirsinizsə, bu məktuba əhəmiyyət verməyərək köhnə parolunuzu istifadə etməyə davam edə bilərsiniz.",
        "passwordreset-emailelement": "İstifadəçi adı: \n$1\n\nMüvəqqəti parol: \n$2",
        "passwordreset-emailsentemail": "Əgər bu imeyl sizin istifadəçi hesabınıza bağlıdırsa, o halda parol sıfırlama məktubu ora göndəriləcək.",
+       "passwordreset-emailsentusername": "Əgər bu e-poçt sizin istifadəçi hesabınıza bağlıdırsa, o halda parol sıfırlama məktubu ora göndəriləcək.",
+       "passwordreset-nocaller": "Çağırıcı təmin edilməlidir",
+       "passwordreset-nosuchcaller": "Çağırıcı yoxdur: $1",
+       "passwordreset-ignored": "Parolun sıfırlanması işlənməmişdir. Bəlkə heç bir provayder qurulmayıb?",
        "passwordreset-invalidemail": "Səhv e-poçt",
+       "passwordreset-nodata": "Nə bir istifadəçi adı, nə də bir e-poçt ünvanı verilmədi.",
        "changeemail": "E-məktub ünvanını dəyiş və ya sil",
+       "changeemail-header": "E-poçt ünvanınızı dəyişdirmək üçün bu formanı tamamlayın. Hesabınızdakı hər hansı bir e-poçt ünvanının birləşməsini aradan qaldırmaq istəyirsinizsə, formu təqdim edərkən yeni e-poçt ünvanını boş buraxın.",
+       "changeemail-no-info": "Bu səhifəni birbaşa açmaq üçün sistemə daxil olmalısınız.",
        "changeemail-oldemail": "Hazırkı e-poçt ünvanı:",
        "changeemail-newemail": "Yeni e-poçt ünvanı:",
+       "changeemail-newemail-help": "E-poçt ünvanınızı çıxarmaq istəyirsinizsə, bu sahə boş olmalıdır. Unudulan bir parolu sıfırlaya bilməyəcəksiniz və e-poçt ünvanı çıxarıldıqda bu vikidən e-poçt ala bilməyəcəksiniz.",
        "changeemail-none": "(yoxdur)",
+       "changeemail-password": "Sizin {{SITENAME}} şifrəniz:",
        "changeemail-submit": "E-poçtu dəyiş",
+       "changeemail-throttled": "Sistemə daxil olmaq üçün həddən artıq cəhd etmisiniz.\nYeni cəhd etməzdən əvvəl $1 gözləyin.",
+       "changeemail-nochange": "Fərqli bir yeni e-poçt ünvanı daxil edin.",
+       "resettokens": "Jetonları sıfırla",
+       "resettokens-text": "Hesabınızla əlaqəli müəyyən şəxsi məlumatlara giriş imkanı verən jetonlar sıfırlana bilər.\n\nTəsadüfən kimsə ilə paylaşdığınız təqdirdə və ya hesabınız pozulduğu halda bunu etməlisiniz.",
+       "resettokens-no-tokens": "Sıfırlanacaq heç bir jeton yoxdur.",
+       "resettokens-tokens": "Jetonlar:",
+       "resettokens-token-label": "$1 (cari dəyər: $2)",
+       "resettokens-watchlist-token": "[[Special:Watchlist|İzləmə siyahınızdakı]] səhifələrdə dəyişikliklərin web feed-i (Atom / RSS) üçün jeton",
+       "resettokens-done": "Jetonlar sıfırlandı.",
+       "resettokens-resetbutton": "Seçilmiş jetonları sıfırla",
        "bold_sample": "Qalın mətn",
        "bold_tip": "Qalın mətn",
        "italic_sample": "Kursiv mətn",
        "publishchanges": "Dəyişiklikləri yayımla",
        "savearticle-start": "Səhifəni dərc et...",
        "savechanges-start": "Dəyişiklikləri yadda saxla...",
+       "publishpage-start": "Səhifəni yayımla...",
+       "publishchanges-start": "Dəyişiklikləri yayımla...",
        "preview": "Sınaq görüntüsü",
        "showpreview": "Sınaq göstərişi",
        "showdiff": "Dəyişiklikləri göstər",
+       "blankarticle": "<strong>Xəbərdarlıq:</strong> Yaratdığınız səhifə boşdur. Əgər bir daha \"$1\" düyməsinə klikləsəniz, səhifə heç bir məzmun olmadan yaradılacaq.",
        "anoneditwarning": "<strong>Diqqət:</strong> Siz sistemə daxil olmamısınız. Hər hansı dəyişiklik etsəniz, sizin IP-ünvanınız hamıya görünəcək. Əgər <strong>[$1 daxil olsanız]</strong> və ya <strong>[$2 hesab yaratsanız]</strong>, redaktələriniz sizin istifadəçi adınıza yazılacaq və digər üstünlüklər də qazanacaqsınız.",
        "anonpreviewwarning": "Sistemə daxil olmamısınız. \"Səhifəni qeyd et\" düyməsini bassanız IP ünvanınız səhifənin tarixçəsində qeyd olunacaq.",
        "missingsummary": "'''Xatırlatma.''' Siz dəyişikliklərin qısa şərhini verməmisiniz. \"Səhifəni qeyd et\" düyməsinə təkrar basandan sonra sizin dəyişiklikləriniz şərhsiz qeyd olunacaq.",
+       "selfredirect": "<strong>Xəbərdarlıq:</strong> Bu səhifəni özünüzə istiqamətləndirirsiniz.\nİstiqamətləndirmə üçün yanlış hədəf göstərə bilərsiniz və ya səhv səhifəni redaktə edə bilərsiniz.\nYenidən \"$1\" düyməsinə bassanız, yenidən istiqamətləndirmə yaradılacaq.",
        "missingcommenttext": "Zəhmət olmasa, şərh yazın.",
+       "missingcommentheader": "<strong>Xatırlatma:</strong> Bu şərh üçün bir mövzu vermədiniz.\nYenidən \"$1\" düyməsinə basarsanız, düzəlişiniz heçnəsiz saxlanacaq.",
        "summary-preview": "Dəyişikliyin izahının görünüşü:",
        "subject-preview": "Sərlövhə belə olacaq:",
+       "previewerrortext": "Redaktələrinizin sınaq görüntüsü göstərilərkən bir səhv baş verdi.",
        "blockedtitle": "İstifadəçi bloklanıb",
+       "blocked-email-user": "<strong>İstifadəçi adınız e-poçt göndərməkdən bloklanmışdır. Siz hələ də bu vikidə redaktə edə bilərsiniz.</strong> Tam blok detallarını [[Special:MyContributions|istifadəçi fəaliyyətləri]] səhifəsində görə bilərsiniz.\n\nBloklayan: $1\nVerilmiş səbəb:<em>$2</em>\n\n*Blokun başlaması: $8\n*Blokun bitməsi: $6\n*Blok məqsədi: $7\n*Blok ID:#$5",
+       "blockedtext-partial": "<strong>İstifadəçi adınız bu səhifəni redaktə etməkdən bloklanmışdır. Siz bu vikidə digər səhifələrdə redaktə edə bilərsiniz.</strong> Tam blok detallarını [[Special:MyContributions|istifadəçi fəaliyyətləri]] səhifəsində görə bilərsiniz.\n\nBloklayan: $1\nVerilmiş səbəb:<em>$2</em>\n\n*Blokun başlaması: $8\n*Blokun bitməsi: $6\n*Blok məqsədi: $7\n*Blok ID:#$5",
+       "blockedtext": "<strong>Sizin istifadəçi adınız və ya IP ünvanınız bloklanmışdır.</strong>\n\nBloklayan: $1\nSəbəb: <em>$2</em>\n\n*Blokun başlaması: $8\n*Blokun bitməsi: $6\n*Blok məqsədi:$7\n\nSiz $1 ilə və ya  [[{{MediaWiki:Grouppage-sysop}}|digər idarəçilərlə]] bloku müzakirə edə bilərsiniz.\n[[Special:Preferences|Nizamlamalarda]] etibarlı bir e-poçt ünvanı göstərilmədikcə və onu istifadə etməmisinizsə, \"{{int: emailuser}}\" funksiyasından istifadə edə bilməzsiniz.\nSizin IP ünvanınız: $3\nBlok ID: #$5\nXahiş etdiyiniz hər hansı bir sorğuda yuxarıda göstərilən məlumatları daxil edin.",
+       "autoblockedtext": "Sizin IP ünvanınız avtomatik olaraq bloklanıb, çünki digər bloklanmış istifadəçi tərəfindən istifadə edilib.\n\nBloklayan: $1\nSəbəb: <em>$2</em>\n\n*Blokun başlaması: $8\n*Blokun bitməsi: $6\n*Blok məqsədi:$7\n\nSiz $1 ilə və ya  [[{{MediaWiki:Grouppage-sysop}}|digər idarəçilərlə]] bloku müzakirə edə bilərsiniz.\n[[Special:Preferences|Nizamlamalarda]] etibarlı bir e-poçt ünvanı göstərilmədikcə və onu istifadə etməmisinizsə, \"{{int: emailuser}}\" funksiyasından istifadə edə bilməzsiniz.\nSizin IP ünvanınız: $3\nBlok ID: #$5\nXahiş etdiyiniz hər hansı bir sorğuda yuxarıda göstərilən məlumatları daxil edin.",
+       "systemblockedtext": "Sizin istifadəçi adınız və ya IP ünvanınız MediaWiki tərəfindən avtomatik olaraq bloklanıb.\n\nSəbəb: <em>$2</em>\n\n*Blokun başlaması: $8\n*Blokun bitməsi: $6\n*Blok məqsədi:$7\n\n\nSizin IP ünvanınız: $3\nXahiş etdiyiniz hər hansı bir sorğuda yuxarıda göstərilən məlumatları daxil edin.",
        "blockednoreason": "səbəb göstərilməyib",
        "whitelistedittext": "Dəyişiklik edə bilmək üçün $1.",
        "confirmedittext": "Siz elektron ünvanınızı səhifədə dəyişiklik etməzdən əvvəl göstərməlisiniz.\nZəhmət olmasa elektron ünvanınızı [[Special:Preferences|istifadəçi nizamlaması]] səhifənizdə göstərib təsdiq ediniz.",
        "accmailtext": "[[User talk:$1|$1]] üçün təsadüfi yolla yaradılmış parol $2 ünvanına göndərildi.\nHesabınıza daxil olduqdan sonra, parolunuzu ''[[Special:ChangePassword|parolu dəyiş]]'' səhifəsində dəyişdirə bilərsiniz.",
        "newarticle": "(Yeni)",
        "newarticletext": "Mövcud olmayan səhifəyə olan keçidi izlədiniz. Aşağıdakı sahəyə məzmununu yazaraq bu səhifəni '''siz''' yarada bilərsiniz. (əlavə məlumat üçün [$1 kömək səhifəsinə] baxın). Əgər bu səhifəyə səhvən gəlmisinizsə sadəcə olaraq brauzerin '''geri''' düyməsinə vurun.",
-       "anontalkpagetext": "----\n<em>Bu səhifə qeydiyyatdan keçməmiş və ya daxil olmamış anonim istifadəçiyə aid müzakirə səhifəsidir.</em>\nOna görə bu istifadəçini rəqəmlərdən ibarət IP ünvanı ilə müəyyən etmək məcburiyyətindəyik.\nBelə IP-ünvan bir neçə fərd tərəfindən istifadədə ola bilər.\nƏgər siz anonim istifadəçisinizsə və bu mesajın sizə aid olmadığını düşünürsünüzsə, onda [[Special:CreateAccount|qeydiyyatdan keçin]] və ya [[Special:UserLogin|daxil olun]] ki, digər anonim istifadəçilərlə qarışıqlıq yaşamayasınız.",
+       "anontalkpagetext": "----\n<em>Bu səhifə qeydiyyatdan keçməmiş və ya daxil olmamış anonim istifadəçiyə aid müzakirə səhifəsidir.</em>\nOna görə bu istifadəçini rəqəmlərdən ibarət IP ünvanı ilə müəyyən etmək məcburiyyətindəyik.\nBelə IP ünvan bir neçə fərd tərəfindən istifadədə ola bilər.\nƏgər siz anonim istifadəçisinizsə və bu mesajın sizə aid olmadığını düşünürsünüzsə, onda [[Special:CreateAccount|qeydiyyatdan keçin]] və ya [[Special:UserLogin|daxil olun]] ki, digər anonim istifadəçilərlə qarışıqlıq yaşamayasınız.",
        "noarticletext": "Hal-hazırda bu səhifə boşdur. Başqa səhifələrdə eyni adda səhifəni [[Special:Search/{{PAGENAME}}|axtara]], əlaqəli qeydlərə\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} baxa] və ya [{{fullurl:{{FULLPAGENAME}}|action=edit}} bu adda səhifəni yarada]</span> bilərsiniz.",
        "noarticletext-nopermission": "Hal-hazırda bu səhifə boşdur. Başqa səhifələrdə eyni adlı səhifəni [[Special:Search/{{PAGENAME}}| axtara]], <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} əlaqəli qeydlərə baxa] və ya səhifəni [{{fullurl:{{FULLPAGENAME}}|action=edit}} redaktə edə bilərsiniz]</span>, lakin sizin bu məqaləni yaratmaq hüququnuz yoxdur.",
+       "missing-revision": "\"{{FULLPAGENAME}}\" adlı səhifənin #$1 versiyası mövcud deyil.\n\nBu adətən silinmiş bir səhifəyə köhnəlmiş keçid bağlantısı ilə bağlıdır. Detallar üçün [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} silmə qeydlərinə] baxın.",
        "userpage-userdoesnotexist": "\"<nowiki>$1</nowiki>\" istifadəçi adı qeydiyyata alınmayıb.\nƏgər siz bu səhifəni yaratmaq/redaktə etmək istəyirsinizsə, xahiş edirik bunu yoxlayın.",
        "userpage-userdoesnotexist-view": "\"$1\" istifadəçi hesabı qeydiyyatda deyil",
        "blocked-notice-logextract": "Bu istifadəçi hal-hazırda bloklanmışdır.\nBloklama qeydlərinin sonuncusu aşağıda göstərilmişdir:",
+       "clearyourcache": "<strong>Qeyd:</strong> Yaddaşa verdikdən sonra dəyişikliklərin görünməsi üçün brauzerinizin keşindən yan keçilməsi lazım ola bilər. \n<strong>Mozilla / Firefox / Safari:</strong>''' <em>Reload</em> düyməsini basarkən eyni vaxtda <em>Shift</em>-i basılı tutun və ya ''Ctrl-Shift-R''-a basın. (Apple Mac-da ''Cmd-Shift-R''). '''İE''': ''Refresh'' düyməsini basarkən eyni vaxtda ''Ctrl''-i basılı tutun və ya ''Ctrl-F5''-ə basın. '''Conqueror:''' Sadəcə ''Reload'' düyməsinə və ya ''F5''-ə basın. '''Opera''' brauzeri istifadəçiləri ''Tools→Preferences''-dən ''cache''-lərini tamamilə təmizləməli ola bilərlər.",
        "usercssyoucanpreview": "'''İpucu:''' Qeyd etmədən əvvəl \"{{int:showpreview}}\"ə klikləyərək yeni CSSinizi yoxlayın.",
+       "userjsonyoucanpreview": "'''İpucu:''' Qeyd etməzdən əvvəl \"{{int:showpreview}}\" düyməsinə klikləyərək yeni JSON-unuzu yoxlayın.",
        "userjsyoucanpreview": "'''İpucu:''' Qeyd etmədən əvvəl \"{{int:showpreview}}\"ə klikləyərək yeni JavaScriptinizi yoxlayın.",
        "usercsspreview": "''Xatırladırıq ki, siz yalnız CSS-də sınaq göstərişi etmisiniz.'''\n'''Bu hələ yaddaşda saxlanılmayıb!'''",
+       "userjsonpreview": "''Xatırladırıq ki, siz yalnız JSON-da sınaq göstərişi etmisiniz.'''\n'''Bu hələ yaddaşda saxlanılmayıb!'''",
        "userjspreview": "''Xatırladırıq ki, siz yalnız JavaScript-də test/sınaq göstərişi etmisiniz.'''\n'''Bu hələ yaddaşda saxlanılmayıb!'''",
        "sitecsspreview": "''Xatırladırıq ki, siz yalnız CSS-də sınaq göstərişi etmisiniz.'''\n'''Bu hələ yaddaşda saxlanılmayıb!'''",
+       "sitejsonpreview": "''Xatırladırıq ki, siz yalnız JSON-da sınaq göstərişi etmisiniz.'''\n'''Bu hələ yaddaşda saxlanılmayıb!'''",
        "sitejspreview": "''Xatırladırıq ki, siz yalnız JavaScript kodunda sınaq göstərişi etmisiniz.'''\n'''Bu hələ yaddaşda saxlanılmayıb!'''",
+       "userinvalidconfigtitle": "<strong>Xəbərdarlıq:</strong> \"$1\" dərisi (skin) yoxdur.\nXüsusi css, .json, və .js səhifələri kiçik hərflə başlayır. Məsələn: {{ns:user}}:Foo/vector.css",
        "updated": "(yeniləndi)",
        "note": "'''Qeyd:'''",
        "previewnote": "<strong>Unutmayın ki, bu yalnız sınaq göstərişidir.</strong> Dəyişiklikləriniz hal-hazırda qeyd edilməmişdir!",
        "continue-editing": "Redaktə sahəsinə qayıt",
        "previewconflict": "Bu sınaq göstərişidir və yaddaşda saxlayacağınız təqdirdə mətnin redaktə səhifəsinin yuxarı hissəsində nəticənin necə olacağını göstərir.",
        "session_fail_preview": "Üzr istəyirik! Sizin redaktəniz saxlanmadı. \n\nOla bilsin ki, profilinizdən çıxmısınız. <strong>Lütfən hesabınıza daxil olmağınızı yoxlayın və təkrar cəhd edin</strong>. Problem həll olunmazsa, [[Special:UserLogout|hesabınızdan çıxın]] və yenidən daxil olun, həmçinin brauzerinizin bu saytdan kukiləri qəbul etdiyini yoxlayın.",
+       "session_fail_preview_html": "Üzr istəyirik! Sessiya məlumatlarının itirilməsi səbəbindən düzəlişiniz yayımlanmadı.\n\n<em> {{SITENAME}} saytında xammal HTML effektiv olduğundan, sınaq görüntüsü JavaScript hücumlarına qarşı tədbir kimi gizlidir.</em>\n\n<strong>Bu qanuni bir redaktə cəhdidirsə, yenidən cəhd edin. </strong>\nƏgər hələ də işləməsə, [[Special:UserLogout|çıxış]] edin və yenidən daxil olun və brauzerinizin bu saytda çərəzlərə (cookies) icazə verdiyini yoxlayın.",
+       "token_suffix_mismatch": "<strong>Redaktəniz rədd edildi, çünki müştəri düzəliş jetonundakı punktuasiya simvollarını qarışdırdı.</strong>\nDüzəliş səhifə mətninin korrupsiyasının qarşısını almaq üçün rədd edildi.\nBu, bir arqument \"web-based anonim proxy\" xidməti istifadə edərkən bəzən olur.",
+       "edit_form_incomplete": "<strong>Düzəliş formasının bir hissəsi serverə çatmadı; Redaktələrinizin sağlam olduğunu və yenidən cəhd etdiyini təkrarlayın.</strong>",
        "editing": "Redaktə $1",
        "creating": "Qurulur $1",
        "editingsection": "Redaktə $1 (bölmə)",
        "yourtext": "Mətniniz",
        "storedversion": "Qeyd edilmiş versiya",
        "editingold": "'''DİQQƏT! Siz bu səhifənin köhnə versiyasını redaktə edirsiniz. Məqaləni yaddaşda saxlayacağınız halda bu versiyadan sonra edilmiş hər bir dəyişiklik itiriləcək.'''",
+       "unicode-support-fail": "Brauzeriniz Yunikodu dəstəkləmədiyindən redaktəniz yadda saxlanılmadı.",
        "yourdiff": "Fərqlər",
        "copyrightwarning": "Xahiş olunur diqqətə alasınız ki, {{SITENAME}}dakı bütün fəaliyyətləriniz $2 lisenziyasına tabe olduğu hesab edilir (təfərrüat üçün bax: $1). Əgər yazdıqlarınızın əsaslı şəkildə redaktə edilməsini və istənildiyi vaxt başqa yerə ötürülməsini istəmirsinizsə, yazılarınızı burada dərc etməyin.\n<br />\nSiz eyni zamanda söz verirsiniz ki, bu yazıları siz özünüz yazmısınız və ya onları hamıya açıq mühitdən ya da buna bənzər mənbədən köçürmüsünüz.\n\n----\n\n<div style=\"font-weight: bold; font-size: 110%; color:red;\">MÜƏLLİF HÜQUQLARI İLƏ QORUNMUŞ HEÇ BİR İŞİ İCAZƏSİZ DƏRC ETMƏYİN!</div>",
+       "copyrightwarning2": "{{SITENAME}} saytında edilən bütün töhfələr digər istifadəçilər tərəfindən redaktə, dəyişdirilə və ya silinə bilər.\nYazılarınızın redaktə edilməsini istəmirsinizsə, buraya təqdim etməyin. <br />\nSiz də bunu özünüz yazdığınızı və ya ictimai bir domendən və ya digər bir etibarlı mənbədən kopyaladığınızı vəd edirsiniz (ətraflı məlumat üçün $1-ə baxın).",
+       "editpage-cannot-use-custom-model": "Bu səhifənin məzmun modeli dəyişdirilə bilməz.",
+       "longpageerror": "<strong>Xəta: Daxil etdiyiniz mətnin həcmi {{PLURAL:$2|bir kilobayt|$2 kilobayt}} limitini aşır və {{PLURAL:$1|bir kilobayt|$1 kilobayt}} həcmindədir.</strong>\nRedaktəniz yadda saxlanıla bilməz.",
+       "readonlywarning": "<strong>Xəbərdarlıq: Verilənlər bazası saxlamaq üçün kilidlənib, beləliklə, düzəlişlərinizi hazırda saxlaya bilməyəcəksiniz.</strong>\nMətni mətn faylına kopyalayıp yapışdırılmasını və daha sonra saxlamağınızı tövsiyə edirik.\n\nBunu kilidləyən sistem idarəçisi bu izahatı verdi: $1",
+       "protectedpagewarning": "<strong>Xəbərdarlıq:</strong> Bu səhifə mühafizə edildiyi üçün yalnız idarəçilər redaktə edə bilərlər.\n\nƏn son jurnal qeydi aşağıda verilmişdir:",
        "semiprotectedpagewarning": "'''Qeyd:''' Bu səhifə mühafizəli olduğu üçün onu yalnız qeydiyyatdan keçmiş istifadəçilər redaktə edə bilərlər.",
+       "cascadeprotectedwarning": "<strong>Xəbərdarlıq:</strong> Bu səhifə yalnız [[Special:ListGroupRights|xüsusi hüquqlara malik]] istifadəçilər tərəfindən redaktə ediləcək şəkildə mühafizə edilir. Çünki bu səhifə aşağıdakı kaskad mühafizə ilə qorunan {{PLURAL:$1|səhifəyə|səhifələrə}} daxildir:",
        "titleprotectedwarning": "'''DİQQƏT! Bu səhifə mühafizəlidir, yalnız [[Special:ListGroupRights|icazəsi olan]] istifadəçilər onu redaktə edə bilərlər.'''",
        "templatesused": "Bu səhifədə istifadə edilmiş {{PLURAL:$1|şablon|şablonlar}}:",
        "templatesusedpreview": "Bu sınaq göstərişində istifadə edilmiş {{PLURAL:$1|şablon|şablonlar}}:",
        "permissionserrors": "İcazə xətası",
        "permissionserrorstext": "Siz, bunu aşağıdakı {{PLURAL:$1|səbəbə|səbəblərə}} görə edə bilməzsiniz:",
        "permissionserrorstext-withaction": "Aşağıdakı {{PLURAL:$1|səbəbə|səbəblərə}} görə, $2 hüququnuz yoxdur:",
+       "contentmodelediterror": "<code>$1</code> <code>$2</code> səhifəsinin mövcud məzmun modelindən fərqləndiyi üçün bu versiyanı redaktə edə bilməzsiniz.",
        "recreate-moveddeleted-warn": "'''Diqqət! Siz əvvəllər silinmiş səhifəni bərpa etmək istəyirsiz.'''\n\nBu səhifəni yenidən yaratmağın nə qədər zəruri olduğunu bir daha yoxlayın.\nBu səhifə üçün silmə qeydləri aşağıda göstərilmişdir:",
        "moveddeleted-notice": "Bu səhifə silinmişdir.\nMəlumat üçün aşağıda bu səhifənin tarixçəsindən müvafiq silmə, mühafizə və köçmə qeydləri göstərilmişdir.",
+       "moveddeleted-notice-recent": "Üzr istəyirik, bu səhifə son vaxtlarda silinib (son 24 saat ərzində)\nBu səhifənin silinməsi, mühafizə edilməsi və yerdəyişmə qeydləri aşağıda verilmişdir.",
        "log-fulllog": "Bütöv məlumatı göstər",
        "edit-hook-aborted": "Düzəlişlər qarmaq-prosedur tərəfindən geri qaytarılıb.\nƏlavə izahat verilməyib.",
        "edit-gone-missing": "Səhifəni yeniləmək mümkün deyil.\nÇox güman ki, səhifə silinmişdir.",
        "revdelete-show-file-confirm": "\"<nowiki>$1</nowiki>\" faylının $2 $3 tarixli silinmiş bir redaktəsini görmək istədiyinizdən əminsizinizmi?",
        "revdelete-show-file-submit": "Bəli",
        "logdelete-selected": "Jurnalın {{PLURAL:$1|seçilmiş qeydi|seçilmiş qeydləri}}:",
+       "logdelete-text": "Silinən versiyalar jurnalda hələ də görünəcək, ancaq onların məzmununun müəyyən hissəsi iştirakçılar üçün əlçatmaz olacaqdır.",
+       "revdelete-text-others": "Əlavə məhdudiyyətlər müəyyən edilmədiyi halda, digər idarəçilər hələ də gizli məzmuna giriş edə, onu geri qaytara bilərlər.",
        "revdelete-legend": "Məhdudiyyətləri müəyyənləşdir:",
        "revdelete-hide-text": "Dəyişikliyin mətni",
        "revdelete-hide-image": "Faylın məzmununu gizlə",
        "username": "{{GENDER:$1|İstifadəçi adı}}:",
        "prefs-memberingroups": "{{GENDER:$2|Üzv}} olduğu {{PLURAL:$1|qrup}}:",
        "prefs-memberingroups-type": "$1",
-       "group-membership-link-with-expiry": "$1 ($2 qədər)",
+       "group-membership-link-with-expiry": "$1 ($2 tarixinə qədər)",
        "prefs-registration": "Qeydiyyat vaxtı:",
        "prefs-registration-date-time": "$1",
        "yourrealname": "Əsl adınız:",
        "yourlanguage": "Dil:",
        "yourvariant": "Dil variant;:",
        "yournick": "Ləqəb:",
+       "prefs-help-signature": "Müzakirə səhifələrindəki şərhlər \"<nowiki>~~~~</nowiki>\" işarələrinin köməyi ilə imzalanmalıdır. Bu, həmin şərhin sonuna sizin imzanızı və onun yazılma tarixini əlavə edir.",
        "badsig": "Səhv xam imza.\nHTML kodu yoxla.",
        "badsiglength": "İmzanız çox uzundur. İmza $1 {{PLURAL:$1|simvoldan|simvoldan}} uzun olmamalıdır.",
        "yourgender": "Hansı təsvir sizə daha uyğundur?",
        "gender-unknown": "Sizi nəzərdə tutarkən, proqram təminatı mümkün olduqca gender-neytral sözlərdən istifadə edəcək.",
        "gender-male": "Bu kişi istifadəçi viki-səhifələri redaktə edir",
        "gender-female": "Bu qadın istifadəçi viki-səhifələri redaktə edir",
+       "prefs-help-gender": "Bu nizamlama meyarı istəyinizə bağlıdır. \nProqram sizə müraciət etmək üçün bu dəyərdən və cinsiyyətiniz üzrə uyğun qrammatikadan istifadə edir.\nBu məlumat hər kəsə görünəcək.",
        "email": "E-məktub",
        "prefs-help-realname": "Həqiqi adınızı daxil etmək məcburi deyil.\nDaxil etsəniz, adınız redaktələrinizin müəllifliyinin təyin edilməsi üçün istifadə edilə bilər.",
        "prefs-help-email": "E-poçt ünvanınızı daxil etmək məcburi deyil.\nBu, parolunuzu unutduğunuz halda, sizə yeni parol göndərməyə imkan verir.",
        "rcfilters-filtergroup-authorship": "Redaktələrin müəllifliyi",
        "rcfilters-filter-editsbyself-label": "Öz dəyişiklikləriniz",
        "rcfilters-filter-editsbyother-label": "Başqalarının dəyişiklikləri",
-       "rcfilters-filtergroup-userExpLevel": "İstifadəçi qeydiyyatı və təcrübəsi",
+       "rcfilters-filtergroup-user-experience-level": "İstifadəçi qeydiyyatı və təcrübəsi",
        "rcfilters-filter-user-experience-level-registered-label": "Qeydiyyatlı",
        "rcfilters-filter-user-experience-level-unregistered-label": "Qeydiyyatsız",
        "rcfilters-filter-user-experience-level-newcomer-label": "Təcrübəsizlər",
        "rcfilters-filter-categorization-label": "Kateqoriya dəyişiklikləri",
        "rcfilters-filter-logactions-label": "Qeydiyyatlı redaktələr",
        "rcfilters-filter-logactions-description": "İnzibati tədbirlər, hesab yaradılmaları, səhifə silinmələri, yükləmələr…",
-       "rcfilters-filtergroup-lastRevision": "Son versiyalar",
+       "rcfilters-filtergroup-lastrevision": "Son versiyalar",
        "rcfilters-filter-lastrevision-label": "Hazırkı versiya",
        "rcfilters-filter-previousrevision-label": "Sonuncu olmayan versiya",
        "rcfilters-exclude-button-off": "Seçilənləri istisna et",
        "minoreditletter": "k",
        "newpageletter": "Y",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 izləyən istifadəçi]",
        "rc-change-size": "$1",
        "rc-change-size-new": "Dəyişiklikdən sonrakı ölçü: $1 bayt",
        "newsectionsummary": "/* $1 */ yeni bölmə",
        "mostrevisions": "Ən çox nəzərdən keçirilmiş (versiyalı) məqalələr",
        "prefixindex": "Prefiks indeksli bütün səhifələr",
        "prefixindex-submit": "Göstər",
+       "prefixindex-strip": "Nəticələrdə prefiksi gizlət",
        "shortpages": "Qısa səhifələr",
        "longpages": "Uzun səhifələr",
        "deadendpages": "Keçid verməyən səhifələr",
        "protectedtitles": "Mühafizəli başlıqlar",
        "listusers": "İstifadəçi siyahısı",
        "listusers-editsonly": "Yalnız redaktələri olan istifadəçiləri göstər",
+       "listusers-temporarygroupsonly": "Yalnız müvəqqəti istifadəçi qruplarında olan istifadəçiləri göstər",
        "listusers-creationsort": "Yaranma tarixinə görə sırala",
+       "listusers-desc": "Azalana doğru sırala",
        "usereditcount": "$1 {{PLURAL:$1|redaktə}}",
        "usercreated": "Saat $2, $1 tarixində {{GENDER:$3|qeydiyyatdan keçib}}",
        "newpages": "Yeni səhifələr",
        "listusers-blocked": "(bloklanıb)",
        "activeusers": "Aktiv istifadəçilərin siyahısı",
        "activeusers-count": "Son {{PLURAL:$3|gündə|$3 gündə}} $1 {{PLURAL:$1|redaktə|redaktə}}",
+       "activeusers-from": "İstifadəçi adı bu simvolla başlayanlardan sonrakıları göstər:",
        "activeusers-noresult": "İstifadəçi tapılmadı.",
        "listgrouprights": "İstifadəçi qruplarının hüquqları",
        "listgrouprights-summary": "Bu vikidə olan istifadəçi siyahıları və onların hüquqları aşağıda göstərilmişdir.\nFərdi hüquqlar haqqında əlavə məlumatı [[{{MediaWiki:Listgrouprights-helppage}}]] səhifəsində tapa bilərsiniz",
        "createaccountblock": "Yeni hesab yaratma bloklanıb",
        "emailblock": "E-mail bloklanıb",
        "blocklist-nousertalk": "Müzakirə səhifəsini redaktə edə bilməz.",
-       "blocklist-editing-page": "aəhifələr",
+       "blocklist-editing-page": "səhifələr",
        "blocklist-editing-ns": "adlar fəzası",
        "ipblocklist-empty": "Blok siyahısı boşdur.",
        "ipblocklist-no-results": "Tələb olunan IP ünvanı və ya istifadəçi bloklanmadı.",
        "confirm-purge-top": "Bu səhifə keşdən (cache) silinsin?",
        "confirm-watch-button": "OK",
        "confirm-unwatch-button": "OK",
-       "confirm-rollback-button": "TAMAM",
+       "confirm-rollback-button": "Oldu",
        "quotation-marks": "\"$1\"",
        "imgmultipageprev": "← əvvəlki səhifə",
        "imgmultipagenext": "sonrakı səhifə →",
index eb2430f..9136e58 100644 (file)
        "rcfilters-highlightbutton-title": "نتیجه‌لری هایلایتلا",
        "rcfilters-filtergroup-authorship": "دییشدیرن",
        "rcfilters-filter-editsbyself-description": "سیزین دییشدیرمه‌لرینیز",
-       "rcfilters-filtergroup-userExpLevel": "ایشلدن آدیازدیرما و تجروبه‌سی",
+       "rcfilters-filtergroup-user-experience-level": "ایشلدن آدیازدیرما و تجروبه‌سی",
        "rcfilters-filter-user-experience-level-registered-label": "آدیازدیریلمیش",
        "rcfilters-filter-user-experience-level-registered-description": "گیریش ائدن دییشدیرنلر.",
        "rcfilters-filter-user-experience-level-unregistered-label": "آدیازدیریلمامیش",
        "rcfilters-filter-newpages-label": "صفحه یاراتما",
        "rcfilters-filter-categorization-label": "بؤلمه دَییشیکلیکلری",
        "rcfilters-filter-logactions-label": "چالیشمالار ژورنالی",
-       "rcfilters-filtergroup-lastRevision": "سوْن نوسخه‌لر",
+       "rcfilters-filtergroup-lastrevision": "سوْن نوسخه‌لر",
        "rcfilters-filter-lastrevision-label": "سوْن نوسخه",
        "rcfilters-filter-previousrevision-label": "سوْن نوسخه اولمایان",
        "rcfilters-exclude-button-off": "سئچیلمیشلرین چیخاریلماسی",
        "minoreditletter": "ک",
        "newpageletter": "ی",
        "boteditletter": "ب",
-       "number_of_watching_users_pageview": "[{{PLURAL:$1|بیر|$1}} ایزله‌ین ایستیفاده‌چی]",
        "rc-change-size-new": "دَییشیکلیک‌دن سوْنرا {{PLURAL:|بیر|$1}} بایت",
        "newsectionsummary": "/* $1 */ یئنی بؤلمه",
        "rc-enhanced-expand": "تفصیل‌لری گؤستر",
        "img-auth-nopathinfo": "PATH_INFO یوخدور.\nسئروئرینیز بو معلوماتی کئچیرمک اوچون نیزاملانمامیش. \nسی‌جی‌آی اولا بیلر و img_auth دستکله‌نیلمیر اولا بیلر. \nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization صحیفه‌‌سینه باخین.",
        "img-auth-notindir": "ایسته‌دیگینیز يول قورولموش يوکله‌مه قوولوغونا دئيیل.",
        "img-auth-badtitle": "«$1» ایله اعتبارلی بیر مؤوضو یوخدور....",
-       "img-auth-nologinnWL": "گیریش ائتمه‌دینیز و «$1» آغ سیياهیدا دئيیل.",
        "img-auth-nofile": "فایل \"$1\" یوخدور.",
        "img-auth-isdir": "\"$1\" قوو‌لوغونا چیخماغا چالیشیرسینیز.\nیالنیز فایل مراجعتینه ایجازه وئریلیر.",
        "img-auth-streaming": "\"$1\" آخینی.",
        "allmessagesdefault": "دفالت دانیشیق متنی",
        "allmessagescurrent": "ایندیکی متن",
        "allmessagestext": "بۇ مئدیاویکی-ده اوْلان سیستم مئساژلاری‌نین سیاهی‌سی‌دیر. اگر مئدیاویکی-نی لوْکاللاشدیرماق ایشینده کؤمک ائتمک ایسه‌يیرسینیزسه، لطفاً [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] و [https://translatewiki.net translatewiki.net]-ه باش چکین.",
-       "allmessagesnotsupportedDB": "'''$ wgUseDatabaseMessages''' باغ‌لی اولدوغو اوچون '{{ns:special}}: Allmessages ایستیفاده‌یه آچیق دئییل.",
+       "allmessages-not-supported-database": "'''$ wgUseDatabaseMessages''' باغ‌لی اولدوغو اوچون '{{ns:special}}: Allmessages ایستیفاده‌یه آچیق دئییل.",
        "allmessages-filter-legend": "سۆزگَج",
        "allmessages-filter": "خصوصی ائتمک وضعیتینه گؤره فیلترلی:",
        "allmessages-filter-unmodified": "دییشدیریلممیش",
index 8a7e4bc..f4a706e 100644 (file)
        "rcfilters-filter-editsbyself-description": "Һинең өлөшөң",
        "rcfilters-filter-editsbyother-label": "Башҡа ҡатнашыусылар индергән үҙгәртеүҙәр",
        "rcfilters-filter-editsbyother-description": "Һинән башҡа барһының да үҙгәртеүҙәре",
-       "rcfilters-filtergroup-userExpLevel": "Ҡатнашыусыны теркәү һәм уның тәжрибәһе",
+       "rcfilters-filtergroup-user-experience-level": "Ҡатнашыусыны теркәү һәм уның тәжрибәһе",
        "rcfilters-filter-user-experience-level-registered-label": "Теркәлгән",
        "rcfilters-filter-user-experience-level-registered-description": "Теркәлгән мөхәррирҙәр",
        "rcfilters-filter-user-experience-level-unregistered-label": "Теркәлмәгән",
        "rcfilters-hideminor-conflicts-typeofchange-global": "\"Аҙ ғына үҙгәртеүҙәр\" фильтры башҡа бер йәки бер нисә фильтр менән талаша, сөнки билдәләнгән төр үҙгәрештәр \"аҙ ғына\" була алмай. Талашҡан фильтрҙар \"Әүҙем фильтрҙар\" өлкәһендә өҫтә күрһәтелгән.",
        "rcfilters-hideminor-conflicts-typeofchange": "Билдәләнгән үҙгәрештәр \"аҙ ғына\" тип атала алмай, шуға был фильтр үҙгәртеүҙәрҙең $1 фильтры менән талаша.",
        "rcfilters-typeofchange-conflicts-hideminor": "Был төҙәтеү һымаҡ фильтр \"аҙ ғына төҙәтеү\" фильтрҙары менән талаша. Билдәләнгән был төҙәтеүҙәр \"аҙ ғына\" була алмай.",
-       "rcfilters-filtergroup-lastRevision": "Һуңғы версиялар",
+       "rcfilters-filtergroup-lastrevision": "Һуңғы версиялар",
        "rcfilters-filter-lastrevision-label": "Ағымдағы версия",
        "rcfilters-filter-lastrevision-description": "Биттәге иң һуңғы үҙгәртеү генә",
        "rcfilters-filter-previousrevision-label": "Һуңғы версия түгел",
        "minoreditletter": "ә",
        "newpageletter": "Я",
        "boteditletter": "б",
-       "number_of_watching_users_pageview": "[$1 күҙәткән {{PLURAL:$1|ҡатнашыусы}}]",
        "rc-change-size-new": "Үҙгәртештән һуң күләм: $1 {{PLURAL:$1|1=байт|байт}}",
        "newsectionsummary": "/* $1 */ яңы бүлек",
        "rc-enhanced-expand": "Ваҡ-төйәгенә тиклем күрһәтергә",
        "img-auth-nopathinfo": "PATH_INFO юҡ.\nҺеҙҙең сервер был мәғлүмәтте ебәреү өсөн көйләнмәгән.\nУның CGI нигеҙендә эшләүе һәм img_auth ҡулланмауы мөмкин.\nТулыраҡ мәғлүмәт: https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization",
        "img-auth-notindir": "Һоралған юл көйләнгән тейәүҙәр директорияһына ҡарамай.",
        "img-auth-badtitle": "\"$1\" исеменән дөрөҫ исем төҙөп булмай.",
-       "img-auth-nologinnWL": "Һеҙ танылыу үтмәнегеҙ, \"$1\" аҡ исемлеккә кермәй.",
        "img-auth-nofile": "\"$1\" файлы юҡ.",
        "img-auth-isdir": "Һеҙ \"$1\" директорияһына керергә тырышаһығыҙ.\nФайлдарҙы асырға ғына рөхсәт бар.",
        "img-auth-streaming": "\"$1\" файлын эҙмә-эҙлекле тапшырыу.",
        "revertpage": "[[Special:Contributions/$2|$2]] ([[User talk:$2|фекер алышыу]]) уҙгәртеүҙәре [[User:$1|$1]] өлгөһөнә ҡайтарылды",
        "revertpage-nouser": "(Ҡатнашыусының исеме йәшерелгән) үҙгәртеүҙәре {{GENDER:$1|[[User:$1|$1]]}}өлгөһөнә ҡайтарылды",
        "rollback-success": "{{GENDER:$3|$1}} үҙгәртеүҙәре кире алынды; {{GENDER:$4|$2}} версияһына ҡайтарылды.",
-       "rollback-success-notify": "Төҙәтеүҙәр кире тейәлгән $1; һуңғы $2 версияға кире ҡайтыу. [$3 Үҙгәрештәрҙе күрһәтеү]",
        "sessionfailure-title": "Сеанс хатаһы",
        "sessionfailure": "Хәҙерге сеанста хаталар килеп сыҡҡан, булырға тейеш;\n\"сеансты баҫып алыу\"ға юл ҡуймау өсөн был ғәмәл үтәлмәне.\nАлдағы биткә кире  ҡайтығыҙ, битте яңыртығыҙ һәм яңынан ҡабатлап ҡарағыҙ.",
        "changecontentmodel": "Биттең контент моделен мөхәррирләү",
        "allmessagesdefault": "Ғәҙәттәге яҙма",
        "allmessagescurrent": "Хәҙерге яҙма",
        "allmessagestext": "Түбәндә MediaWiki исемдәр арауығында ҡулланылған система хәбәрҙәре исемлеге килтерелгән.\nӘгәр MediaWiki программаһын дөйөм локалләштереү эшенә үҙ өлөшөгөҙҙө керетергә теләһәгеҙ, [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki программаһын локалләштереү] битен һәм [https://translatewiki.net translatewiki.net] проектын ҡарап сығығыҙ.",
-       "allmessagesnotsupportedDB": "Был бит ҡулланыла алмай, сөнки '''$wgUseDatabaseMessages''' мөмкинлеге һүндерелгән.",
+       "allmessages-not-supported-database": "Был бит ҡулланыла алмай, сөнки '''$wgUseDatabaseMessages''' мөмкинлеге һүндерелгән.",
        "allmessages-filter-legend": "Һайлау",
        "allmessages-filter": "Үҙгәртеү торошо буйынса һайлау:",
        "allmessages-filter-unmodified": "Үҙгәртелмәгәндәр",
index 4c2c3c6..9679cb2 100644 (file)
@@ -8,17 +8,20 @@
                        "Naval Scene",
                        "Nemo bis",
                        "NoiX180",
-                       "아라"
+                       "아라",
+                       "Carma citrawati",
+                       "Joseagush",
+                       "Wandering ant"
                ]
        },
-       "tog-underline": "isinin garis ring beten pranala",
+       "tog-underline": "Garis ring beten pranala:",
        "tog-hideminor": "engkebang suntingan ring gentosan sane pinih anyar",
        "tog-hidepatrolled": "engkebang suntingan mapatrol ring gentosan sane pinih anyar",
        "tog-newpageshidepatrolled": "engkebang lembar mapatrol saking saking kepahan lembar anyar",
+       "tog-hidecategorization": "Engkebang kacané",
        "tog-extendwatchlist": "kembangang kepahan pangiwasan antuk nampilang samian panguwahan, nenten sane anyar kewanten",
        "tog-usenewrc": "aniang suntingan ring tampilan pagentosan sane pinih anyar lan kepahan pangiwasan manutin lembar",
        "tog-numberheadings": "isinin nomor murda anggen cara otomatis",
-       "tog-showtoolbar": "tampilang pekakas panyuntingan",
        "tog-editondblclick": "sunting lembar nganggen klik kaping pindo",
        "tog-editsectiononrightclick": "sayagayang panyuntingan kepahan anggen ngeklik tengen ring kepahan judul",
        "tog-watchcreations": "imbuhin lembar sane karyanin titiang ring kepahan pangiwasan",
@@ -33,9 +36,9 @@
        "tog-enotifminoredits": "taler kirimang titiang email ring panguwahan alit",
        "tog-enotifrevealaddr": "kirimang titiang alamat email ring catetan email",
        "tog-shownumberswatching": "tampilang akehnyane sane ngiwasin",
-       "tog-oldsig": "tanda tangan mangkin",
+       "tog-oldsig": "Tanda tangan mangkin",
        "tog-fancysig": "dadosang tanda tangan dados teks wiki (nenten pranala otomatis)",
-       "tog-uselivepreview": "anggen pratayang langsung(experimental)",
+       "tog-uselivepreview": "Anggen pratayang langsung ten anggen kaca sane malunan",
        "tog-forceeditsummary": "elingang titiang yening kotak ringkesan suntingan kari kosong",
        "tog-watchlisthideown": "engkebang panguwahan titiang saking kepahan pangiwasan",
        "tog-watchlisthidebots": "engkebang panguwahan bot ring kepahan pangiwasan",
        "tog-ccmeonemails": "kirimang titiang salinan email sane kirimang titiang ring anak lianan",
        "tog-diffonly": "sampunang katampilang daging lembar ring ungkur binanne suntingan",
        "tog-showhiddencats": "tampilang golongan sane kaengkebang",
-       "tog-norollbackdiff": "sampunang tampilang binanne sesampun ngewaliang",
+       "tog-norollbackdiff": "Sampunang tampilang binanne sesampun ngewaliang",
        "tog-useeditwarning": "elingang titiang yening ngalahin lembar panyuntingan sadurung nyimpen pagentosan",
-       "tog-prefershttps": "setata nganggen sambungan sane aman rikala malebu log",
-       "underline-always": "setata",
-       "underline-never": "nenten naenin",
+       "tog-prefershttps": "Setata nganggen sambungan sane aman rikala malebu log",
+       "underline-always": "Setata",
+       "underline-never": "Nénten naénin",
        "underline-default": "kulit utawi penjelajah paaban",
        "editfont-style": "model aksara ring kotak panyuntingan",
-       "editfont-default": "penjelajah paaban",
        "editfont-monospace": "aksara monospace",
        "editfont-sansserif": "aksara sans-serif",
        "editfont-serif": "aksara serif",
        "february": "Pébruari",
        "march": "Maret",
        "april": "April",
-       "may_long": "mungkin - minab",
+       "may_long": "Méi",
        "june": "Juni",
        "july": "Juli",
        "august": "Agustus",
        "september": "Séptémber",
        "october": "Oktober",
-       "november": "november",
+       "november": "Nopémber",
        "december": "Désémber",
        "january-gen": "Januari",
        "february-gen": "Pébruari",
        "january-date": "Januari $1",
        "february-date": "Februari $1",
        "march-date": "Maret $1",
+       "april-date": "April $1",
        "may-date": "Mei $1",
        "june-date": "Juni $1",
        "july-date": "Juli $1",
        "august-date": "Agustus $1",
+       "september-date": "September $1",
        "october-date": "Oktober $1",
+       "november-date": "November $1",
        "december-date": "Desember $1",
+       "period-am": "AM",
+       "period-pm": "PM",
        "pagecategories": "{{PLURAL:$1|golongan}}",
        "category_header": "lembar ring golongan \"$1\"",
        "subcategories": "sub golongan",
        "category-media-header": "lembar ring golongan \"$1\"",
        "category-empty": "\"mangkin, nenten madaging lembar utawi pekakas ring golongan puniki\"",
        "hidden-categories": "{{plural:$1|punduhan sane kaengkebang| punduhan sane kaengkebang}}",
+       "hidden-category-category": "Kategori mengkeb",
        "category-subcat-count": "{{PLURAL:$2| golongan puniki madue {{PLURAL:$1|$1 subkategori}} puniki, saking genepan $2.}}",
        "category-article-count": "{{PLURAL:$2|golongan puniki madue{{PLURAL:$1|$1 lembar}}, saking total $2.}}",
        "category-file-count": "{{PLURAL:$2|golongan puniki madue{{PLURAL:$1|$1 lembar}}, saking total $2.}}",
        "listingcontinuesabbrev": "samb.",
-       "noindex-category": "lembar sane nenten maindeks",
-       "about": "paindikan",
-       "newwindow": "bukak ring jendela anyar",
-       "cancel": "buwungang",
-       "mytalk": "Wicara",
-       "navigation": "pengarah",
-       "qbedit": "mecikang",
+       "noindex-category": "Lembar sane nenten maindeks",
+       "broken-file-category": "Suratan sane ngelah pranala usak",
+       "about": "Indik",
+       "newwindow": "(bukak ring jendela anyar)",
+       "cancel": "Buwung",
+       "mypage": "Kaca",
+       "mytalk": "Babaosan",
+       "anontalk": "Wicara",
+       "navigation": "Pengarah",
+       "and": "&#32;miwah",
        "faq": "FAQ (pitaken sane jagi katakonang)",
-       "faqpage": "Project: FAQ(pitaken sane jagi katakonang)",
-       "actions": "parilaksana",
+       "actions": "Parilaksana",
        "namespaces": "Genah pesengan",
        "variants": "kawentenan sane lianan",
+       "navigation-heading": "Menu navigasi",
        "errorpagetitle": "kaluputan",
        "returnto": "mabalik ring $1",
        "tagline": "Saka {{SITENAME}}",
        "help": "Tulung",
+       "help-mediawiki": "Pitulung MediaWiki",
        "search": "Rereh",
        "searchbutton": "Rereh",
        "searcharticle": "lanturang",
        "history": "sejarah pupulan",
        "history_short": "kawentenan sane lawas",
+       "history_small": "babad",
        "printableversion": "kawentenan lian sane macetak",
-       "permalink": "pranala ajeg",
+       "permalink": "Pranala ajeg",
+       "view": "cingakin",
+       "view-foreign": "Edengang ring $1",
        "edit": "Becikang",
-       "create": "ngawe",
-       "delete": "apus",
-       "protect": "nyaga",
+       "create": "Ngae",
+       "delete": "Apus",
+       "protect": "Nyaga",
        "protect_change": "gentos",
-       "newpage": "lembar anyar",
-       "talkpagelinktext": "Wicara",
+       "newpage": "Lembar Anyar",
+       "talkpagelinktext": "babaosan",
+       "specialpage": "Lembar sane kautamayang",
        "personaltools": "pekakas pribadi",
-       "talk": "rembug\n\nngarembug (kata kerja)",
+       "talk": "Rembug",
        "views": "Pekantenan",
        "toolbox": "Pekakas",
        "viewhelppage": "cingak lembar pamitutlung",
        "copyrightpage": "{{ns:project}}:hak cipta",
        "currentevents": "kawentenane mangkin",
        "currentevents-url": "Project:kawentenane mangkin",
-       "disclaimers": "nungkas",
+       "disclaimers": "Tulak",
        "disclaimerpage": "Project:Pengelidan lumrah",
        "edithelp": "pamitulung panguwahan",
-       "mainpage": "Kaca Utama",
-       "mainpage-description": "lembar utama",
+       "helppage-top-gethelp": "Tulung",
+       "mainpage": "Laman Utama",
+       "mainpage-description": "Lembar Utama",
        "portal": "Pintu nuju sekha",
        "portal-url": "Project:pamedal sekha",
-       "privacy": "kawicaksanaan padewekan",
+       "privacy": "Awig-awig genah praragan",
        "privacypage": "Project:kawicaksanan tanpaiket",
+       "ok": "OK",
        "retrievedfrom": "kapolihang saking \"$1\"",
        "youhavenewmessages": "{{PLURAL:$3|ida dane maduwe}} $1 ($2)",
-       "editsection": "gentos",
+       "youhavenewmessagesfromusers": "{{PLURAL:$4|You have}} $1 ring {{PLURAL:$3|another user|$3 users}} ($2).",
+       "youhavenewmessagesmanyusers": "Ida dane ngelah $1 saking liyane ($2).",
+       "editsection": "obah",
        "editold": "mecikang",
        "viewsourceold": "cingak witnyane",
        "editlink": "mecikang",
        "viewsourcelink": "cingak witnyane",
-       "editsectionhint": "ubah kepahan$1",
+       "editsectionhint": "Obah papalihan: $1",
        "toc": "kepahan dagingnyane",
+       "showtoc": "edengang",
+       "hidetoc": "engkebang",
+       "collapsible-expand": "buka",
+       "confirmable-confirm": "{{GENDER:$1|Ida}} dane yakin?",
+       "confirmable-yes": "Inggih",
+       "confirmable-no": "Nénten",
        "site-atom-feed": "$1 \"atom feed\"",
        "page-atom-feed": "$1 \"atom feed\"",
-       "red-link-title": "$1 (kaca tan wénten)",
+       "red-link-title": "$1 (laman tan wénten)",
        "nstab-main": "Kaca",
        "nstab-user": "sane nganggo",
        "nstab-special": "lembar sane kautamayang",
        "nstab-template": "templat",
        "nstab-help": "lembar pamitutlung",
        "nstab-category": "golongan",
+       "mainpage-nstab": "Laman utama",
+       "nosuchspecialpage": "Ten wenten lembar spesial",
+       "error": "kaluputan",
+       "databaseerror": "Database kaluputan",
        "missing-article": "data utama nenten prasida nemu tulisan saking lembar sane sepatutne wenten, inggih punika  $1, $2\n\nindike puniki biasane keranayang olih pranala kaon nuju pabenahan sane dumun lembar sane sampun kaicalang\n\nyening nenten puniki sane ngranayang, ida dane minab sampun manggihin kaiwangang ring sajeroning piranti lunak.\nDurus sadokang indik puniki rin silih sinunggil anak \n\n[[Special:ListUsers/sysop|Pengurus]], antuk ngetik alamat URL sane katuju",
        "missingarticle-rev": "(pabenahan#:$1)",
        "badtitle": "murda sane nenten manut",
        "badtitletext": "Judul halaman sane katagih nenten patut, kosong, atau judul antarbahasa atau antarwiki yang salah sambung.\n\nmurda lembar sane kaarsa nenten sida kaedengang, kosong, utawi murda murda antarbasa utawi antarwiki sane iwang",
        "viewsource": "cingak witnyane",
+       "viewsourcetext": "Ida dane dados ningalin lan kopi sumber saking suratan puniki",
        "yourname": "pesengan penganggen",
+       "userlogin-yourname": "Penganggen",
+       "userlogin-yourname-ph": "Isi Kruna sandi ida dane",
        "yourpassword": "kruna sandi",
+       "userlogin-yourpassword": "Kruna sandi",
        "yourpasswordagain": "jumunin kruna sandi",
-       "login": "malebu ring log",
+       "login": "Ngranjing log",
        "nav-login-createaccount": "malebu log / ngawe pepalihan",
-       "userlogin": "malebu log / ngawe pepalihan",
+       "logout": "Medal Log",
        "userlogout": "medal saking Log",
-       "nologin": "durung madue akun?$1",
-       "nologinlink": "ngajuang akun anyar",
+       "notloggedin": "Konden masuk log",
+       "userlogin-noaccount": "Durung madue akun?",
+       "userlogin-joinproject": "Indik {{SITENAME}}",
        "createaccount": "ngajuang akun anyar",
-       "gotaccount": "durung madue akun?$1",
-       "gotaccountlink": "malebu ring log",
-       "userlogin-resetlink": "Lali rerincian anggen mlebu ring log ida dane?",
        "mailmypassword": "nyumu ngaryanin kruna sandi",
        "loginlanguagelabel": "Basa: $1",
+       "pt-login": "Ngranjing log",
+       "pt-login-button": "Ngranjing log",
+       "pt-createaccount": "Ngajuang akun anyar",
+       "pt-userlogout": "Medal Log",
+       "botpasswords-label-create": "Ngae",
+       "botpasswords-label-cancel": "Buungan",
+       "botpasswords-label-delete": "Apus",
+       "botpasswords-label-resetpassword": "Nyumu kruna sandi",
+       "passwordreset": "Nyumu kruna sandi",
        "bold_sample": "teks puniki mesurat tebel",
        "bold_tip": "teks puniki mesurat tebel",
        "italic_sample": "teks puniki masurat sendeh",
        "savearticle": "simpen lembar",
        "preview": "tayangan sadurungnyane",
        "showpreview": "cingak sane lintang",
-       "showdiff": "cingak pagentosan",
-       "anoneditwarning": "\"Pingetan\" ida dane nenten kacatet malebu. Alamat IP ida dane jagi kacatet ring sejarah (indik sane dumunan) ring lembar puniki.",
+       "showdiff": "Cingak pagentosan",
+       "anoneditwarning": "<strong>Pingetan:</strong> Ida dané nénten kacatet ngranjing. Alamat IP ida dané jagi kacatet ring sejarah (indik sané dumunan) ring lembar puniki. Yening ida dane <strong>[$1 log in]</strong> utawi <strong>[$2 create an account]</strong>, your edits will be attributed to your username, along with other benefits.",
+       "loginreqlink": "Ngranjing log",
        "newarticle": "(Anyar)",
        "newarticletext": "ida dane ngiring pranala nuju lembar sane durung wenten. yening jagi ngaryanang lembar punika, ketik daging lembar ring kotak sane wenten ring beten puniki. (cingak [$1 lembar wantuan] anggen wacana salanturnyane). yening ida dane nenten nyelapang neked ring lembar puniki, klik tombol \"back\" ring \"penjelajah web\" ida dane.",
-       "noarticletext": "mangkin nenten wenten teks ring lembar puniki. ida dane prasida [[Special:Search/{{PAGENAME}}|ngarereh murda anggen lembar puniki]] ring lembar-lembar sane lianan, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ngarereh log sane mapaiketan], utawi [{{fullurl:{{FULLPAGENAME}}|action=edit}} ngubah lembar puniki]</span>.",
+       "noarticletext": "mangkin nenten wenten teks ring lembar puniki. ida dane prasida [[Special:Search/{{PAGENAME}}|ngrereh murda nganggen lembar puniki]] ring lembar-lembar sane lianan, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ngrereh log sane mapaiketan], utawi [{{fullurl:{{FULLPAGENAME}}|action=edit}} nguwah lembar puniki]</span>.",
        "noarticletext-nopermission": "mangkin nenten wenten teks ring lembar puniki. ida dane prasida [[Special:Search/{{PAGENAME}}|ngarereh murda anggen lembar puniki]] ring lembar-lembar sane lianan, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ngarereh log sane mapaiketan], utawi [{{fullurl:{{FULLPAGENAME}}|action=edit}} ngubah lembar puniki]</span>.",
        "previewnote": "\"elingang yening puniki wantah sane lintang.\" Panguwahan ida dane durung kasimpen!",
        "editing": "panguwahan $1",
        "template-protected": "nyayubang",
        "template-semiprotected": "(semi-penyaga)",
        "hiddencategories": "lembar niki inggih punika krama saking {{PLURAL:$1|1 golongan sane mengkeb|$1 golongan sane mengkeb}}",
-       "permissionserrorstext-withaction": "ida dane nenten madue kuasa malebu anggen $2, riantukan {{PLURAL:$1|alasan}} ring sor puniki:",
+       "permissionserrorstext-withaction": "ida dané nénten madué kuasa ngranjing anggén $2, riantukan {{PLURAL:$1|alasan}} ring sor puniki:",
        "recreate-moveddeleted-warn": "\"pingetan\" ida dane ngawe malih lembar sane naenin maapus.'''\n\nmangda kayunin malih napike pantes lanturang suntingan ida dane. puniki log pengapusan lan pangisidan saking lembar puniki:",
-       "moveddeleted-notice": "lembar puniki sampun kaapus. anggen pewarah, puniki log pangapus lan pengisidan lembar puniki",
+       "moveddeleted-notice": "Lembar puniki sampun kaapus.\nAnggen pewarah, proteksi, lan pengisidan log saking lembar puniki cingakin pustaka beten.",
+       "content-model-wikitext": "tulisan wiki",
        "post-expand-template-inclusion-warning": "pinget: ukuran templat sane keanggen kalangkung ageng. wenten templat sane kacampahang",
        "post-expand-template-inclusion-category": "lembar sane maukuran templat sane nglangkungin wates",
        "post-expand-template-argument-warning": "\"peminget\" lembar puniki madaging kiranglangkungnyane siki argumen templat anggen ukuran ekspansi sane kaliwat ageng. argumen-argumen punika sampun kacampahang.",
        "viewpagelogs": "cingak log ring lembar puniki",
        "currentrev-asof": "pabecikan sane anyar ring pinanggal$1",
        "revisionasof": "ngabecikang per $1",
-       "revision-info": "panguwahan per $1;$2",
+       "revision-info": "Panguwahan per $1 olih {{GENDER:$6|$2}}$7",
        "previousrevision": "← pabenahan sane dumun",
        "nextrevision": "panguwahan salanturnyane→",
        "currentrevisionlink": "panguwahan mangkin",
        "cur": "mangkin",
        "last": "sadurung",
        "histlegend": "pilih kalih tombol radio lantur pecik tombol \"bandingang\" anggen ngebandingang indik lianan. klik siki tanggal anggen nyingak indik lianan lembar ring pinanggal punika.<br />(skr)= binanne saking indik lianan sane mangkin, (untat) = binanne saking indik lianan sane dumunan, '''k''' = panguwahan alit, '''b''' = panguwahan bot, → = panguwahan kepahan, ← = reringkesan otomatis",
-       "history-fieldset-title": "napakin versi sane dumunan",
+       "history-fieldset-title": "Nyaringin révisi",
        "history-show-deleted": "wantah sane kaapus",
        "histfirst": "pinih suwe",
        "histlast": "pinih anyar",
        "yourrealname": "pesengan sujati",
        "prefs-help-email": "alamat email sane mawatek mamilih, nanging ngamerluang anggen nyumunin sandi yening ida dane lali",
        "prefs-help-email-others": "ida dane prasida milih anggen ngalugrain anak lianan ngubungin ida dane majalaran lembar penganggen utawi pangraos nenten ja perlu ngagah indik padewekan ida dane",
+       "right-writeapi": "nganggén API sasuratan",
        "newuserlogpage": "log penganggo anyar",
        "action-edit": "benahang lembar puniki",
        "nchanges": "$1{{PLURAL:$1|panguwahan|uwah-uwahan}}",
-       "recentchanges": "pagentosan sane anyar",
+       "enhancedrc-history": "babad",
+       "recentchanges": "Pagentosan anyar",
        "recentchanges-legend": "pilihan panguwahan sane anyar",
        "recentchanges-feed-description": "molihang pagentosan anyar ring wiki ring \"umpan\" puniki",
        "recentchanges-label-newpage": "panguwahan puniki ngaryanin lembar anyar",
        "recentchanges-label-minor": "niki panguwahan kidik",
        "recentchanges-label-bot": "penguwahan puniki kalaksanayang antuk bot",
        "recentchanges-label-unpatrolled": "panguwahan puniki durung kapatroli",
-       "rcnotefrom": "ring beten puniki inggih punika panguwahan saking <strong>$2</strong> (kaedengang ngantos <strong>$1</strong> panguwahan).",
+       "rcnotefrom": "Ring beten puniki inggih punika {{PLURAL:$5|panguwahan}} saking <strong>$3, $4</strong> (kaedengang ngantos <strong>$1</strong> panguwahan).",
        "rclistfrom": "edengang  penguwahan sane anyar wit saking $3 $2",
        "rcshowhideminor": "$1 uwahan kidik",
+       "rcshowhideminor-show": "Edengang",
+       "rcshowhideminor-hide": "Engkebang",
        "rcshowhidebots": "$1 bot",
+       "rcshowhidebots-show": "Edengang",
+       "rcshowhidebots-hide": "Engkebang",
        "rcshowhideliu": "$1 penganggo - penganggo terdaftar",
+       "rcshowhideliu-show": "Edengang",
+       "rcshowhideliu-hide": "engkebang",
        "rcshowhideanons": "$1 penganggo tan meadan",
+       "rcshowhideanons-show": "Edengang",
+       "rcshowhideanons-hide": "Engkebang",
        "rcshowhidepatr": "$1 suntingan sane kapatroli",
        "rcshowhidemine": "$1 uwahan titiang",
-       "rclinks": "edengang sane untat $1 gentosan anyar $2 dina kaping untat",
+       "rcshowhidemine-show": "Edengang",
+       "rcshowhidemine-hide": "Engkebang",
+       "rclinks": "Edengang untat $1 gentosan anyar $2 dina kaping untat",
        "diff": "bina",
        "hist": "kawentenan sane lian",
        "hide": "engkebang",
        "minoreditletter": "M",
        "newpageletter": "n",
        "boteditletter": "B",
+       "rc-change-size-new": "$1 {{PLURAL:$1|bita|bita}} sasampun kaobahin",
        "rc-enhanced-expand": "edengang rerincian",
        "rc-enhanced-hide": "engkebang rerincian",
        "recentchangeslinked": "pangentos sane wenten paiketane",
        "recentchangeslinked-toolbox": "pangentos sane wenten paiketane",
        "recentchangeslinked-title": "panguwahan sane mapaiketan ring $1",
-       "recentchangeslinked-summary": "lembar kautamayang puniki ngicenin kepahan penguwahan kaping untat ring lembar-lembar sana mapaiket. Lembar sane [[Special:Watchlist|ida dane iwasin]] mapinget antuk masurat tebel",
+       "recentchangeslinked-summary": "lembar kautamayang puniki ngicenin kepahan penguwahan kaping untat ring lembar-lembar sana mapaiket. Lembar sane [[Special:Watchlist|ida dane iwasin]] mapinget antuk sesuratan tebel",
        "recentchangeslinked-page": "adan lembar",
        "recentchangeslinked-to": "edengang panguwahan sakin lembar-lembar sane mapaiket antuk lembar-lembar sane kaedengang",
        "upload": "ngunggahang berkas",
        "filedesc": "pacutetan",
        "license": "kepahan lugra",
        "license-header": "kepahan lugra",
+       "imgfile": "pupulan",
        "file-anchor-link": "pupulan",
        "filehist": "sejarah pupulan",
        "filehist-help": "klik ring pinanggal/galah anggen nyingakin pupulan niki rikala punika",
        "filehist-comment": "tureksa",
        "imagelinks": "penganggen berkas",
        "linkstoimage": "nyarengin {{PLURAL:$1|pranala|$1pranala}} ring pupulan puniki",
-       "nolinkstoimage": "nenten wenten lembar sane medue pranala ring pupulan puniki",
+       "nolinkstoimage": "Nenten wenten lembar sane medue pranala ring pupulan puniki",
        "sharedupload-desc-here": "pupulan puniki mawit saking $1 lan minab kaanggen olih proyek-proyek sane lianan. Deskripsi saking [$2 lebar deskripsinyane] kaarahin ring ungkur puniki",
+       "upload-disallowed-here": "Ida dane tusing ngidang numpuk suratan pukini.",
        "randompage": "lembar acak",
        "statistics": "Statistik",
        "nbytes": "$1{{PLURAL:$1|bit}}",
        "pager-older-n": "{{PLURAL:$1|1 lewih suwe|$1 lewih anyar}}",
        "booksources": "pawiwitan buku",
        "booksources-search-legend": "rereh ring sumber buku",
+       "booksources-search": "Rereh",
        "log": "log",
        "allpages": "samian lembar",
        "allarticles": "samian lembar",
        "rollbacklink": "mabalik",
        "protectlogpage": "log penyaga",
        "protectedarticle": "nyaga \"[[$1]]\"",
+       "protect-default": "Izinkan mekejang",
+       "restriction-edit": "Becikang",
        "undeletelink": "cingak/uliang",
        "undeleteviewlink": "cingak",
        "namespace": "Genah pesengan",
        "invert": "uliang pilihan",
-       "blanknamespace": "utama",
+       "tooltip-invert": "Centang kotak puniki mangdané ngengkebang lembar sané kauwah ring genah wastan sané kapilih (miwah genah wastan sané mapaiketan yéning kacentang)",
+       "blanknamespace": "(Utama)",
        "contributions": "kawigunan {{GENDER:$1|penganggo}}",
        "contributions-title": "Kontribusi pangangge anggen $1",
        "mycontris": "kawigunan",
+       "anoncontribs": "Kawigunan",
        "contribsub2": "antuk {{GENDER:$3|$1}} ($2)",
        "uctop": "sane mangkin",
        "month": "mawit saking sasih (lan sadurungnyane)",
        "sp-contributions-blocklog": "log pemblokiran",
        "sp-contributions-uploads": "unggahang",
        "sp-contributions-logs": "log",
-       "sp-contributions-talk": "Wicara",
+       "sp-contributions-talk": "babaosan",
        "sp-contributions-search": "rereh anggen kawigunanne",
        "sp-contributions-username": "Alamat IP utawi pesengan panganggo:",
        "sp-contributions-toponly": "tampilang wantah panguwahan sane anyar",
+       "sp-contributions-newonly": "Tampilang wantah panguwahan sane anyar",
        "sp-contributions-submit": "rereh",
        "whatlinkshere": "Pranala balik",
        "whatlinkshere-title": "lembar-lembar sane maduwe pranala kaping \"$1\"",
        "whatlinkshere-page": "lembar",
-       "linkshere": "lembar puniki maduwe pranala ke '''[[:$1]]'''",
-       "nolinkshere": "lembar puniki maduwe pranala ke '''[[:$1]]'''",
+       "linkshere": "lembar puniki maduwe pranala ke '''$2'''",
+       "nolinkshere": "lembar puniki maduwe pranala ke '''$2'''",
        "isredirect": "lembar pangalihan",
        "istemplate": "sareng kasurat",
        "isimage": "pranala pupulan-pupulan",
        "whatlinkshere-links": "← pranala",
        "whatlinkshere-hideredirs": "$1 pangalihan",
        "whatlinkshere-hidetrans": "$1 transklusi",
-       "whatlinkshere-hidelinks": "$1 Pranala",
+       "whatlinkshere-hidelinks": "$1 pranala",
        "whatlinkshere-hideimages": "$1 pranala pupulan",
        "whatlinkshere-filters": "Panyaring",
        "ipboptions": "2 jam:2 hours,1 dina:1 day,3 dina:3 days,1 minggu:1 week,2 minggu:2 weeks,1 sasih:1 month,3 sasih:3 months,6 sasih:6 months,1 taun:1 year,tanpa wates:infinite",
        "allmessagesdefault": "teks lingga",
        "thumbnail-more": "ngedenang",
        "thumbnail_error": "luput ngaryanin bentuk cenik $1",
-       "tooltip-pt-userpage": "lembar sane kaanggen ida dane",
-       "tooltip-pt-mytalk": "lembar wicara ida dane",
-       "tooltip-pt-preferences": "Preferensi titiang",
+       "tooltip-pt-userpage": "Lembar sane {{GENDER:|kaanggen ida dane}}",
+       "tooltip-pt-mytalk": "Laman bebaosan {{GENDER:|Ida dané}}",
+       "tooltip-pt-preferences": "Preferensi {{GENDER:|Ida dane}}",
        "tooltip-pt-watchlist": "kepahan-kepahan lembar sane katinjo titiang",
-       "tooltip-pt-mycontris": "kepahan-kepahan kawigunan ida dane",
-       "tooltip-pt-login": "ida dane kaaturang malebu log, nanging nenten kaswadarmayang",
+       "tooltip-pt-mycontris": "Kepahan-kepahan kawigunan {{GENDER:|Ida dane}}",
+       "tooltip-pt-login": "ida dané kaaturang ngranjing log, nanging nénten kaswadarmayang",
        "tooltip-pt-logout": "medal saking Log",
+       "tooltip-pt-createaccount": "ragané mangda makarya akun miwah ngranjing log: yadiastun nénten kawajibang",
        "tooltip-ca-talk": "pabligbagan indik dagingnyane",
        "tooltip-ca-edit": "Sunting kaca iki. Nganggen tombol pratayang sadurunge nyimpen.",
        "tooltip-ca-addsection": "nyumunin kepahan anyar",
        "tooltip-n-randompage": "edengang polah-palih lembar",
        "tooltip-n-help": "genah anggen ngarereh",
        "tooltip-t-whatlinkshere": "kepahan sami lembar wiki sane maduwe pranala nuju lembar puniki",
-       "tooltip-t-recentchangeslinked": "pagentosan sane anyar lembar-lembar sane maduwe pranala nuju lembar puniki",
+       "tooltip-t-recentchangeslinked": "Pagentosan anyar lembar sane maduwe pranala nuju lembar puniki",
        "tooltip-feed-atom": "\"atom feed\" anggen lembar puniki",
-       "tooltip-t-contributions": "cingak kepahan kawigunan penganggo niki",
-       "tooltip-t-emailuser": "kirim email majeng ring penganggo puniki",
+       "tooltip-t-contributions": "Daptar kepahan kawigunan {{GENDER:$1|penganggo niki}}",
+       "tooltip-t-emailuser": "Ngirim surel majeng ring {{GENDER:$1|penganggo puniki}}",
        "tooltip-t-upload": "ngunggahang file",
-       "tooltip-t-specialpages": "kepahan sami lembar istimewa",
+       "tooltip-t-specialpages": "Kepahan sami lembar istimewa",
        "tooltip-t-print": "kawentenan lian sane macetak ring lembar puniki",
        "tooltip-t-permalink": "Pranala ajeg kaanggen ngubah lembar puniki",
        "tooltip-ca-nstab-main": "cingak dagingnyane lembar puniki",
        "tooltip-ca-nstab-help": "cingak lembar pamitutlung",
        "tooltip-ca-nstab-category": "cingak lembar kategori",
        "tooltip-minoredit": "pingetin puniki dados panguwahan kidik",
-       "tooltip-save": "simpen pagentosan ida dane",
-       "tooltip-preview": "pagentosan sane dumun duwen ida dane, mangda anggen niki sadurung jagi nyimpen!",
-       "tooltip-diff": "cingak pagentosan sane sampun ida dane laksanayang",
+       "tooltip-save": "Nyimpen pagentosan ida dane",
+       "tooltip-preview": "Pagentosan sane dumun duwen ida dane, mangda anggen niki sadurung jagi nyimpen!",
+       "tooltip-diff": "Cingak pagentosan sane sampun ida dane laksanayang",
        "tooltip-compareselectedversions": "cingak binane makekalih kepahan lembar sane kasudi",
        "tooltip-watch": "imbuhin lembar niki ring daftar paninjoan ida dane",
        "tooltip-rollback": "\"nguliang\" muwungan jagi ngabecikang ring lembar puniki nuju haturan sane untat ngangge apisan klik",
        "tooltip-undo": "\"nguliang\" ngabuwungin jagi ngabecikang niki lan ngagah kotak mecikang ngangge mode pratayang. dasar ipun prasida kaimbuhin ring kotak pamicutet",
        "tooltip-summary": "ngalebuang silih sinunggil ringkesan",
+       "simpleantispam-label": "Pamariksa anti-spam.\nPuniki <strong>wenten</strong> kaisi!",
+       "pageinfo-header-edits": "Babad becikang",
+       "pageinfo-display-title": "Edengang judul",
+       "pageinfo-article-id": "ID Halaman",
+       "pageinfo-toolboxlink": "Katérangan lembar",
        "previousdiff": "← Benahin sadurungnyane",
        "nextdiff": "panguwahan sane pinih anyar →",
        "file-info-size": "$1x$2 piksel, ukuran pupulan: $3, tipe MIME:$4",
        "file-nohires": "tan kasayagaang ukuran sane lewih ageng",
        "svg-long-desc": "pupulan SVG, nominal $1 × $2 piksel, geden pupulan: $3",
        "show-big-image": "pupulan sujati",
+       "show-big-image-preview": "agengnyané pratuduh:$1",
+       "show-big-image-other": "{{PLURAL:$2|Resolusi}} iianan: $1.",
+       "show-big-image-size": "$1 × $2 piksel",
        "sunday-at": "Redite jam $1",
        "bad_image_list": "bentukne sekadi puniki:\n\nwantah kepahan daftar ( baris sane kakawitin anggen tanda *) sane kaitung pranala kapertama ring baris mangda pranala ring berkas sane kaon.\nPranala-Pranala sane selanturnyane ring baris sane pateh kamanahang antuk pinangging, inggih punika lembar sane prasida ngedengang berkas punika.",
        "metadata": "metadata",
        "watchlisttools-view": "edengang panguwahan sane mapaiket",
        "watchlisttools-edit": "edengang lan uwahin kepangan paninjo",
        "watchlisttools-raw": "uwah kepahan paninjo mentah",
+       "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|bebaosan]])",
        "duplicate-defaultsort": "pingetan: sereg pangurutan lingga \"$2\" nyampahang sereg pangurutan lingga sadurunge \"$1\"",
        "specialpages": "lembar melulu",
        "external_image_whitelist": "#banggiang baris niki sapunapi kawentenanne<pre>\n#anggen fragmen akspresi reguler (wantah kepahan ring kekelaih//) ring sor puniki\n#fragmen-fragmen puniki jagi kaadungang sareng URL saking gambar-gambar eksternal (sane kasambungang langsung)\n#fragmen sane adung jagi katampilang dados gambar, sisanne wantah dados pranala kewanten\n#baris sane kakawitin antuk # jagi kadadosang baris komentar\n#niki nenten ngabinayang aksara ageng lan alit\n#genahang samian fragmen ekspresi reguler ring sor baris puniki. banggiang baris niki sapunapi kawentennane</pre>",
-       "tag-filter": "filter [[Special:Tags|tag]]:"
+       "tag-filter": "filter [[Special:Tags|tag]]:",
+       "tag-list-wrapper": "[[Special:Tags|{{PLURAL:$1|Tag}}]]: $2",
+       "tags-active-yes": "Inggih",
+       "logentry-newusers-create": "$1 {{GENDER:$2|makarya}} akun sané nuénang",
+       "searchsuggest-search": "Rereh ring {{SITENAME}}"
 }
index 7313f8d..d6c9cbe 100644 (file)
        "minoreditletter": "K",
        "newpageletter": "N",
        "boteditletter": "B",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|beówochtender|beówochtende}} Benutzer]",
        "rc-change-size-new": "$1 {{PLURAL:$1|Byte|Bytes}} noch da Endarung",
        "newsectionsummary": "Neicher Obschnit /* $1 */",
        "rc-enhanced-expand": "Details zoagn (braucht JavaScript)",
        "allmessagesdefault": "Standardtext",
        "allmessagescurrent": "Aktuella Text",
        "allmessagestext": "Des is a Listen vo de MediaWiki-Systemtextt.\nBsuach bittschee de Saiten [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki-Lokalisiarung] und [https://translatewiki.net translatewiki.net], wånn du de ån da Lokalisiarung vo MediaWiki betailing mechadst.",
-       "allmessagesnotsupportedDB": "'''Special:Allmessages''' is im Moment net möglich, wei de Datenbank offline is.",
+       "allmessages-not-supported-database": "'''Special:Allmessages''' is im Moment net möglich, wei de Datenbank offline is.",
        "thumbnail-more": "vagressan",
        "thumbnail_error": "Fehla ban Estejn vom Vorschaubuidl: $1",
        "importlogpage": "Import-Logbuach",
index 00e65d3..1aa60c6 100644 (file)
                        "Sultanselim baloch"
                ]
        },
-       "tog-underline": ":لینکانآ خط کش",
-       "tog-hideminor": "هوردین تغییراتآ ته نوکین تغییرات پناه کن",
+       "tog-underline": ":لینکاں کِشک کن",
+       "tog-hideminor": "ھوردݔں ٹگلاں پناہ کن",
        "tog-hidepatrolled": "ته نوکین تغییرات اصلاحاتی که گردگ بیتگن پناه کن",
-       "tog-newpageshidepatrolled": "پناه کتن صفحاتی که گردگ بوتگن چه لیست نوکین صفحه",
-       "tog-extendwatchlist": "لیست چارگ مزن کن دان کل تغییرات پیش داریت نه که فقط نوکینءَ",
-       "tog-usenewrc": "گرÙ\88پء ØªØºÛ\8cÛ\8cراÙ\86 ØªØ§Ú©Ø¡ Ù\88استÙ\87 Ù\85اÙ\86 Ù\86Ù\88Ú©Û\8cÙ\86 ØªØºÛ\8cÛ\8cراÙ\86 Ø¡Ù\8f Ú\86ارÙ\88Ú© Ù\84Û\8cست",
-       "tog-numberheadings": "اتÙ\88Ù\85اتÛ\8cÚ© Ø´Ù\85ارÙ\87 Ú©ØªÙ\86 Ø¹Ù\86اÙ\88Û\8cن",
-       "tog-editondblclick": "ویبتاکانء مان دو کلیک ٹگل بدئ",
+       "tog-newpageshidepatrolled": "تاکاتے کہ گندگ بیتگ اَنت پناہ کن",
+       "tog-extendwatchlist": "چارگ لیستءَ مزن کن کہ دراھیگݔں گندگ بہ بَنت",
+       "tog-usenewrc": "گرÙ\88پء ØªØ§Ú© Ø¡Ù\8f Ú\86ارگ Ù\84Û\8cستء Ù¹Ú¯Ù\84اں",
+       "tog-numberheadings": "سرگاÙ\84اں Ù\88تاÙ\88ت ØªØ±ØªÛ\8cÙ¾ Ú©ن",
+       "tog-editondblclick": "وبتاکاں پہ دو مݔن ٹگل دئے",
        "tog-editsectiononrightclick": "فعال کتن زرتگین بهرء اصلاح کتن گون کلیک زرتگین عنوانانء سرا",
-       "tog-watchcreations": "Ù\85Ù\86Û\8c Ø§Ú\88 Ú©ØªÚ¯Û\8cÙ\86 Ù¾Û\8cج Ù\88 Ø§Ù¾Ù\84Ù\88د Ú©ØªÚ¯Û\8cÙ\86 Ù\81اÛ\8cÙ\84اÙ\86Ø¡ Ú\86ارگ Ù\84Û\8cستء ØªÙ\88کا Ù\87Ù\88ار کن",
-       "tog-watchdefault": "منی اصلاح کتگین فایل و پیجانء چارگ لیستء توکا هوار کن",
-       "tog-watchmoves": "منی سُرینتگین فایل و پیجانء چارگ لیستء توکا هوار کن",
-       "tog-watchdeletion": "منی حذف کتگین فایل و پیجانء چارگ لیستء توکا هوار بکن",
-       "tog-watchrollback": "Ø¢ Ø¯Û\8cÙ\85اÙ\86Û\8c Ø¢Ú\88 Ú©Ù\88رتÛ\8cÙ\86 Ú©Ù\87 Ø¢Ù\88اÙ\86ا Ø¨Ø±Ú¯Ø±Ø¯Ø§Ù\86 Ú©Ù\88رتÙ\87 Ø§Ù\88Ù\86 Ù¾Ù\87 Ù\85Ù\86Û\8c Ù¾Û\8cÚ¯Û\8cرÛ\8c Ù\84Û\8cستÛ\8c Ù\87اتÛ\8cرا",
-       "tog-minordefault": "په طور پیش فرض کل اصلاحات آ په داب جزی مشخص کن",
+       "tog-watchcreations": "Ù\85Ù\86Û\8c Ø¬Û\8fÚ\88 Ú©Ù\8fتگÝ\94Úº ØªØ§Ú© Ø¡Ù\8f Ø³Ø±Ú¯Ý\94تکگÝ\94Úº Ù¾Ø§Û\8cÙ\84اں Ú\86ارگ Ù\84Û\8cستءÙ\8e Ú¾Û\8fر کن",
+       "tog-watchdefault": "منی ٹگل داتگݔں تاک ءُ پایلان چارگ لیستءَ ھۏر کن",
+       "tog-watchmoves": "منی سُرݔنتگݔں تاک ءُ پایلان چارگ لیستءَ ھۏر کن",
+       "tog-watchdeletion": "منی پاک کتگݔں تاک ءُ پایلان چارگ لیستءَ ھۏر کن",
+       "tog-watchrollback": "Ø¢ ØªØ§Ú©Ø§Úº Ú©Û\81 Ú\86ھر Ø¯Ø§ØªÚ¯Ù\86 Ù\85Ù\86Û\8c  Ú\86ارگ Ù\84Û\8cستءÙ\8e Ú¾Û\8fر Ú©Ù\86",
+       "tog-minordefault": "دراھیگݔں ٹگلاں پݔسری پئیما کن",
        "tog-previewontop": "بازبین پیش دار پیش چه جعبه اصلاح",
        "tog-previewonfirst": "ته اولین اصلاح بازبینی پیش دار",
        "tog-enotifwatchlistpages": "وهدی که یک پیج یان که فایلء ٹگل وارت پر منء ایمیل دیم بدئ",
        "tog-norollbackdiff": "تفاوتء حذف کن بعد چه اجرای یک ترینگ",
        "tog-useeditwarning": "وهدی دربیگ مان اصلاح کتگین پیج اگان تغییران سیو نبوت اتنت منء هشتار بدئ",
        "tog-prefershttps": "پر مان بوتنء واسته هروهدء یک ایمنین کنکشنء کارمرز بکن",
-       "underline-always": "یکسره",
-       "underline-never": "هچ وهد",
-       "underline-default": "وفاولتء پێم پر برۆزر یان پۆسته",
-       "editfont-style": "اصلاح کنۆکێن فۆنتء استایل",
-       "editfont-monospace": "Ù\81Û\86Ù\86ت Ú¯Û\86Ù\86 Ù\85اÙ\84Ù\88Ù\85Û\8eÙ\86 Ù¾Ø§Ø³Ù\84Ú¯",
-       "editfont-sansserif": "بئ گۆشگێن فۆنت",
-       "editfont-serif": "گۆشه دارێن فۆنت",
-       "sunday": "Û\8cÚ© Ø´Ù\85بÛ\8c",
-       "monday": "دÙ\88Ø´Ù\85بÛ\8c",
-       "tuesday": "سئه شمبی",
-       "wednesday": "Ú\86ارشÙ\85بÛ\8c",
-       "thursday": "Ù¾Ù\86Ú\86 Ø´Ù\85بÛ\8c",
-       "friday": "آدÛ\8cÙ\86Ú¯ Ù¬Ø¬Ù\88Ù\85ا",
-       "saturday": "Ø´Ù\85بÛ\8c",
-       "sun": "یک شمی",
-       "mon": "دÙ\88 Ø´Ù\85بÛ\8c",
-       "tue": "سئه شمبی",
-       "wed": "چار شمبی",
-       "thu": "پنچ شمبی",
-       "fri": "آدینگ٬ جوما",
-       "sat": "Ø´Ù\85بÛ\8c",
-       "january": "جنوری",
-       "february": "پیبروری",
+       "underline-always": "دراہءَ",
+       "underline-never": "هچبر",
+       "underline-default": "بروزر پݔسری پئیما",
+       "editfont-style": "پونتءِ ٹگلݔنگ",
+       "editfont-monospace": "Ù¾Ù\88Ù\86ت Ú¯Û\8f Ø­Ø¯",
+       "editfont-sansserif": "بے سریکݔں پونت",
+       "editfont-serif": "سریکی پونت",
+       "sunday": "Û\8cÚ© Ø´Ù\86بÛ\81",
+       "monday": "دÙ\88Ø´Ù\86بÛ\81",
+       "tuesday": "سئ شنبہ",
+       "wednesday": "Ú\86ارشÙ\86بÛ\81",
+       "thursday": "Ù¾Ù\86Ú\86 Ø´Ù\86بÛ\81",
+       "friday": "جÙ\88Ù\85Û\81/آدÝ\94Ù\86Ú¯",
+       "saturday": "Ø´Ù\86بÛ\81",
+       "sun": "درۏچ",
+       "mon": "سرÛ\8fÚ\86",
+       "tue": "چرۏچ",
+       "wed": "پرۏچ",
+       "thu": "شرۏچ",
+       "fri": "ھرۏچ",
+       "sat": "زرÛ\8fÚ\86",
+       "january": "ژانویہ",
+       "february": "پبرݔر",
        "march": "مارچ",
-       "april": "آپریل",
+       "april": "آپرݔل",
        "may_long": "می",
-       "june": "جون",
-       "july": "جولای",
+       "june": "جۏن",
+       "july": "جۏلی",
        "august": "آگوست",
-       "september": "سپٹامبر",
+       "september": "سپتمبر",
        "october": "اکتوبر",
        "november": "نوامبر",
        "december": "دسمبر",
-       "january-gen": "جنوری",
-       "february-gen": "پیبروری",
+       "january-gen": "جنۏری",
+       "february-gen": "پبرݔر",
        "march-gen": "مارچ",
-       "april-gen": "آپریل",
+       "april-gen": "آپرݔل",
        "may-gen": "می",
-       "june-gen": "جون",
-       "july-gen": "جولای",
+       "june-gen": "جۏن",
+       "july-gen": "جۏلی",
        "august-gen": "آگوست",
-       "september-gen": "سپٹامبر",
+       "september-gen": "سپتمبر",
        "october-gen": "اکتوبر",
        "november-gen": "نوامبر",
        "december-gen": "دسمبر",
-       "jan": "جنوری",
-       "feb": "پیبروری",
+       "jan": "جنو",
+       "feb": "پبر",
        "mar": "مارچ",
        "apr": "آپریل",
        "may": "می",
-       "jun": "جون",
-       "jul": "جولای",
-       "aug": "آگوست",
-       "sep": "سپٹ\tامبر",
+       "jun": "جۏن",
+       "jul": "جۏل",
+       "aug": "آگو",
+       "sep": "سپتمبر",
        "oct": "اکتوبر",
        "nov": "نوامبر",
        "dec": "دسمبر",
-       "january-date": "جنوری، بهارگاه $1",
-       "february-date": "پیبروری، اۆستپان $1",
-       "march-date": "مارچ، مۆلمان $1",
-       "april-date": "اپرÛ\8cÙ\84Ø\8c Ú©Ø±Ø§ $1",
-       "may-date": "مئ، سۆچکان $1",
-       "june-date": "جون، جلکان $1",
-       "july-date": "جولای، سهێل $1",
-       "august-date": "اگÙ\88ستØ\8c Ø³Ø§Ú\86اÙ\86 $1",
-       "september-date": "سپٹامبر، تۆمشان $1",
-       "october-date": "اکتۆبر، سارتان $1",
-       "november-date": "نوامبر، گۆپشان $1",
-       "december-date": "دسمبر، تۆمشان $1",
-       "period-am": "صبح",
-       "period-pm": "عصر",
+       "january-date": "جنۏری $1",
+       "february-date": "پبرݔر$1",
+       "march-date": "مارچ $1",
+       "april-date": "آپرÝ\94Ù\84 $1",
+       "may-date": "می $1",
+       "june-date": "جۏن $1",
+       "july-date": "جۏلی $1",
+       "august-date": "Ø¢Ú¯Ù\88ست $1",
+       "september-date": "سپتمبر $1",
+       "october-date": "اکتوبر $1",
+       "november-date": "نومبر $1",
+       "december-date": "دسمبر $1",
+       "period-am": "SW",
+       "period-pm": "BW",
        "pagecategories": "{{PLURAL:$1|دسته|دسته جات}}",
-       "category_header": "صÙ\81حات ØªÙ\87 Ø¯Ø³ØªÙ\87 \"$1\"",
-       "subcategories": "زیردسته جات",
-       "category-media-header": "مدیا ته دسته \"$1\"",
-       "category-empty": "''ای دسته ی هچ صفحه یا مدیا نیست''",
+       "category_header": "تاک Ù\85Û\81 Ø¯Ø³ØªÛ\81 \"$1\"",
+       "subcategories": "چݔردستہ",
+       "category-media-header": "رسانک مہ دستہ \"$1\"",
+       "category-empty": "<em>''اے دستگءَ ھچ رسانک نے''</em>",
        "hidden-categories": "{{PLURAL:$1|پناهین دسته|پناهین دسته جات}}",
        "hidden-category-category": "پناهین دسته جات",
        "category-subcat-count": "{{PLURAL:$2|ای دسته فقط جهلیگین زیر دسته ای هست..|ای دسته  جهلیگین {{PLURAL:$1|subcategory|$1 زیردسته}}, چه $2 کل.}}",
        "minoreditletter": "م",
        "newpageletter": "ن",
        "boteditletter": "ب",
-       "number_of_watching_users_pageview": "[$1 چارگنت {{PLURAL:$1|کاربر|کابران}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|بایت}} رند چه تغییر",
        "newsectionsummary": "/* $1 */ نوکین بخش",
        "rc-enhanced-expand": "جزئیاتء پیس دارگ",
        "img-auth-nopathinfo": "PATH_INFO موجود نیست.\nسرور شما برای ردکردن این مقدار تنظیم نشده‌است.\nممکن است مبتنی بر سی‌جی‌آی باشد و از img_auth پشتیبانی نکند.\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization را ببینید.",
        "img-auth-notindir": "مسیر درخواست شده در شاخهٔ بارگذاری تنظیم‌شده قرار ندارد.",
        "img-auth-badtitle": "امکان ایجاد یک عنوان مجاز از «$1» وجود ندارد.",
-       "img-auth-nologinnWL": "شما به سامانه وارد نشده‌اید و «$1» در فهرست سفید قرار ندارد.",
        "img-auth-nofile": "پایلی «$1» وجود نداریت.",
        "img-auth-isdir": "شما تلاش کرده‌اید به شاخهٔ «$1» دسترسی پیدا کنید.\nتنها دسترسی به پرونده مجاز است.",
        "img-auth-streaming": "در حال جاری ساختن «$1».",
        "allmessagesdefault": "پیش فرضین متن",
        "allmessagescurrent": "هنوکین متن",
        "allmessagestext": "شی یک لیستی چه کوله یان موجود ته نام فضای مدیا وی کی انت.\nلطفا بچاریت  [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] و [https://translatewiki.net translatewiki.net] اگر شما لوٹیت ته ملکی کتن مدیا وی کی کمک کنیت.",
-       "allmessagesnotsupportedDB": "ای صفحه نه تونیت استفاده بیت په چی که'''$wgUseDatabaseMessages''' غیر فعالنت.",
+       "allmessages-not-supported-database": "ای صفحه نه تونیت استفاده بیت په چی که'''$wgUseDatabaseMessages''' غیر فعالنت.",
        "allmessages-filter-legend": "فیلتر",
        "allmessages-filter": "فیلتر گون حالت دلواهی",
        "allmessages-filter-unmodified": "عوض نه بیتگین",
index 9534cc8..f29ed77 100644 (file)
        "minoreditletter": "s",
        "newpageletter": "B",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 naka-antabay sa {{PLURAL:$1|paragamit|mga paragamit}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} pagtatapos kan pagbabago",
        "newsectionsummary": "/* $1 */ bàgong seksyon",
        "rc-enhanced-expand": "Ipahiling an mga detalye",
        "img-auth-nopathinfo": "Nawawara an PATH_INFO.\nAn saimong serbidor dae naipamugtak tanganing makapasa kaining impormasyon.\nIni mapuwedeng yaon nakabase sa CGI asin dae makakasuporta sa img_auth.\nHilnga an https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "An hinahagad na agihan bakong naka-akma sa pankargang direktoryo.",
        "img-auth-badtitle": "Dae nakakapaggibo in sarong balidong titulog gikan sa \"$1\".",
-       "img-auth-nologinnWL": "Dae ka nakalaog asin \"$1\" mayo sa aprubadong listahan.",
        "img-auth-nofile": "An sagunson \"$1\" bakong eksistido.",
        "img-auth-isdir": "Ika naghingohang makalaog sa direktoryo \"$1\".\nMakakalaog ka sana sa sagunson na tinugot.",
        "img-auth-streaming": "Nagsusughay na \"$1\".",
        "allmessagesdefault": "Panugmad na tekstong mensahe",
        "allmessagescurrent": "Presenteng teksto",
        "allmessagestext": "Ini sarong listahan nin pansistemang mga mensahe na mananagboan sa espasyong-pangaran kan MediaWiki.\nPakibisita an [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Mediawiki Lokalisasyon] asin [https://translatewiki.net translatewiki.net] kun boot mong mag-ambag sa henerikong lokalisasyon kan MediaWiki.",
-       "allmessagesnotsupportedDB": "Dai pwedeng gamiton an '''{{ns:special}}:Allmessages''' ta sarado an '''$wgUseDatabaseMessages'''.",
+       "allmessages-not-supported-database": "Dai pwedeng gamiton an '''{{ns:special}}:Allmessages''' ta sarado an '''$wgUseDatabaseMessages'''.",
        "allmessages-filter-legend": "An Pansara",
        "allmessages-filter": "Pansara sa paagi kan estado nin kustomisasyon:",
        "allmessages-filter-unmodified": "Bakong modipikado",
index a693179..e634a37 100644 (file)
        "virus-scanfailed": "памылка сканаваньня (код $1)",
        "virus-unknownscanner": "невядомы антывірус:",
        "logouttext": "<strong>Вы выйшлі з сыстэмы.</strong>\n\nНекаторыя старонкі могуць яшчэ паказваць, нібы вы ў сыстэме. Каб гэтага пазьбегнуць, трэба ачысьціць кэш браўзэра.",
+       "logging-out-notify": "Вы выходзіце з сыстэмы, калі ласка, пачакайце.",
+       "logout-failed": "Цяпер немагчыма выйсьці: $1",
        "cannotlogoutnow-title": "Цяпер немагчыма выйсьці",
        "cannotlogoutnow-text": "Выхад з сыстэмы немагчымы пры выкарыстаньні $1.",
        "welcomeuser": "Вітаем, $1!",
        "last": "папярэдняя",
        "page_first": "першая",
        "page_last": "апошняя",
-       "histlegend": "Ð\9fаÑ\80аÑ\9eнанÑ\8cне: Ð¿Ð°Ð·Ð½Ð°Ñ\87Ñ\86е ÐºÑ\80опкамі дзьве вэрсіі для параўнаньня і націсьніце «ўвод» альбо кнопку ўнізе.<br />\nТлумачэньне: <strong>({{int:cur}})</strong> = адрозьненьні ад цяперашняй вэрсіі, <strong>({{int:last}})</strong> = адрозьненьні ад папярэдняй вэрсіі, <strong>{{int:minoreditletter}}</strong> = дробная праўка.",
-       "history-fieldset-title": "Ð\9fоÑ\88Ñ\83к вэрсіяў",
+       "histlegend": "Ð\9fаÑ\80аÑ\9eнанÑ\8cне: Ð°Ð´Ð·Ð½Ð°Ñ\87Ñ\86е Ð¿Ñ\83нкÑ\82амі дзьве вэрсіі для параўнаньня і націсьніце «ўвод» альбо кнопку ўнізе.<br />\nТлумачэньне: <strong>({{int:cur}})</strong> = адрозьненьні ад цяперашняй вэрсіі, <strong>({{int:last}})</strong> = адрозьненьні ад папярэдняй вэрсіі, <strong>{{int:minoreditletter}}</strong> = дробная праўка.",
+       "history-fieldset-title": "ФÑ\96лÑ\8cÑ\82аÑ\80 вэрсіяў",
        "history-show-deleted": "Толькі выдаленыя",
        "histfirst": "найстарэйшыя",
        "histlast": "найноўшыя",
        "historysize": "($1 {{PLURAL:$1|байт|байты|байтаў}})",
-       "historyempty": "(пуста)",
+       "historyempty": "пуста",
        "history-feed-title": "Гісторыя зьменаў",
        "history-feed-description": "Гісторыя зьменаў гэтай старонкі ў вікі",
        "history-feed-item-nocomment": "$1 у $2",
        "right-reupload-own": "Перазапіс уласных існых файлаў",
        "right-reupload-shared": "Перазапіс файлаў з агульнага сховішча лякальнымі",
        "right-upload_by_url": "Загрузка файлаў з URL-адрасу",
-       "right-purge": "аÑ\87Ñ\8bÑ\81Ñ\82ка ÐºÑ\8dÑ\88Ñ\83 Ñ\81Ñ\82аÑ\80онак Ð±Ñ\8fз Ð·Ð°Ð¿Ñ\8bÑ\82Ñ\83 Ð¿Ð°Ñ\86Ñ\8cвеÑ\80джанÑ\8cнÑ\8f",
+       "right-purge": "Ð\90Ñ\87Ñ\8bÑ\81Ñ\82ка ÐºÑ\8dÑ\88Ñ\83 Ñ\81айÑ\82Ñ\83 Ð´Ð»Ñ\8f Ñ\81Ñ\82аÑ\80онкÑ\96",
        "right-autoconfirmed": "Ня дзейнічаюць абмежаваньні хуткасьці па IP",
        "right-bot": "Лічыцца аўтаматычным працэсам",
        "right-nominornewtalk": "Не паведамляць удзельнікам пра новыя паведамленьні на іх старонках гутарак, калі зробленыя там праўкі былі дробнымі",
        "action-changetags": "дадаваньне і выдаленьне адвольных метак да асобных вэрсіяў і запісаў у журнале падзеяў",
        "action-deletechangetags": "выдаленьне метак з базы зьвестак",
        "action-purge": "ачыстку кэшу гэтай старонкі",
+       "action-apihighlimits": "ўжываньне падвышаных лімітаў у API-запытах",
+       "action-autoconfirmed": "адсутнасьць абмежаваньня хуткасьці паводле IP-адрасу",
+       "action-bigdelete": "выдаленьне старонак зь вялікай гісторыяй",
+       "action-blockemail": "блякаваньне ўдзельніку магчымасьці адпраўкі лістоў электроннай поштай",
+       "action-bot": "тое, каб лічыцца аўтаматычным працэсам",
+       "action-editprotected": "рэдагаваньне старонак, абароненых у рэжыме «{{int:protect-level-sysop}}»",
+       "action-editsemiprotected": "рэдагаваньне старонак, абароненых як «{{int:protect-level-autoconfirmed}}»",
+       "action-editinterface": "рэдагаваньне інтэрфэйсу карыстальніка",
+       "action-editusercss": "рэдагаваньне CSS-файлаў іншых удзельнікаў",
+       "action-edituserjson": "рэдагаваньне JSON-файлаў іншых удзельнікаў",
+       "action-edituserjs": "рэдагаваньне JavaScript-файлаў іншых удзельнікаў",
+       "action-editsitecss": "рэдагаваньне агульнасайтавага CSS",
+       "action-editsitejson": "рэдагаваньне агульнасайтавага JSON",
+       "action-editsitejs": "рэдагаваньне агульнасайтавага JavaScript",
+       "action-editmyusercss": "рэдагаваньне вашых уласных CSS-файлаў",
+       "action-editmyuserjson": "рэдагаваньне вашых уласных JSON-файлаў",
+       "action-editmyuserjs": "рэдагаваньне вашых уласных JavaScript-файлаў",
+       "action-viewsuppressed": "прагляд вэрсіяў, схаваных ад усіх удзельнікаў",
+       "action-hideuser": "блякаваньне імя ўдзельніка і яго хаваньне",
+       "action-ipblock-exempt": "абыход блякаваньняў IP-адрасоў, аўтаблякаваньняў і блякаваньняў дыяпазонаў",
+       "action-unblockself": "разблякаваньне самога сябе",
+       "action-noratelimit": "адсутнасьць абмежаваньня хуткасьці",
+       "action-reupload-own": "перазапіс уласных існых файлаў",
+       "action-nominornewtalk": "дробныя праўкі, якія не паведамляюць удзельніку пра зьмены на старонцы абмеркаваньня",
+       "action-markbotedits": "пазначэньне адкатаў як правак робатам",
+       "action-patrolmarks": "прагляд адзнакаў патруляваньня апошніх зьменаў",
+       "action-override-export-depth": "экспарт старонак, у тым ліку зьвязаных старонак з глыбінёй да 5",
+       "action-suppressredirect": "нестварэньне перанакіраваньняў з старонкі-крыніцы пры пераносе",
        "nchanges": "$1 {{PLURAL:$1|зьмена|зьмены|зьменаў}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|з апошняга візыту}}",
        "enhancedrc-history": "гісторыя",
        "rcfilters-savedqueries-already-saved": "Гэтыя фільтры ўжо захаваныя. Зьмяніце вашыя налады, каб стварыць новы захаваны фільтар.",
        "rcfilters-restore-default-filters": "Аднавіць фільтры па змоўчаньні",
        "rcfilters-clear-all-filters": "Ачысьціць усе фільтры",
-       "rcfilters-show-new-changes": "Ð\9fÑ\80аглÑ\8fдзеÑ\86Ñ\8c Ð½Ð°Ð¹Ð½Ð¾Ñ\9eÑ\88Ñ\8bÑ\8f Ð·Ñ\8cменÑ\8b",
+       "rcfilters-show-new-changes": "Ð\9fÑ\80аглÑ\8fдзеÑ\86Ñ\8c Ð½Ð¾Ð²Ñ\8bÑ\8f Ð·Ñ\8cменÑ\8b Ð· $1",
        "rcfilters-search-placeholder": "Фільтар зьменаў (ужывайце мэню ці пошук дзеля назвы фільтру)",
        "rcfilters-invalid-filter": "Няслушны фільтар",
        "rcfilters-empty-filter": "Няма актыўных фільтраў. Паказаны ўвесь унёсак.",
        "rcfilters-filter-editsbyself-description": "Ваш уласны ўнёсак.",
        "rcfilters-filter-editsbyother-label": "Зьмены, зробленыя іншымі",
        "rcfilters-filter-editsbyother-description": "Усе зьмены, за выключэньнем вашых.",
-       "rcfilters-filtergroup-userExpLevel": "Рэгістрацыя ўдзельнікаў і досьвед",
+       "rcfilters-filtergroup-user-experience-level": "Рэгістрацыя ўдзельнікаў і досьвед",
        "rcfilters-filter-user-experience-level-registered-label": "Зарэгістраваныя",
        "rcfilters-filter-user-experience-level-registered-description": "Рэдактары, якія ўвайшлі ў сыстэму.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Незарэгістраваныя",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Фільтар «Дробныя праўкі» канфліктуе з адным ці некалькімі фільтрамі «Тыпаў зьменаў», бо некаторыя тыпы зьменаў ня могуць быць вызначаныя як «дробныя». Канфліктныя фільтры пазначаныя ў разьдзеле актыўных фільтраў вышэй.",
        "rcfilters-hideminor-conflicts-typeofchange": "Некаторыя тыпы зьменаў ня могуць быць вызначаныя як «дробныя», таму гэты фільтар канфліктуе з наступнымі фільтрамі «Тыпаў зьменаў»: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Гэты фільтар тыпаў зьменаў канфліктуе зь фільтрам «Дробныя праўкі». Некаторыя тыпы зьменаў ня могуць быць вызначаныя як «дробныя».",
-       "rcfilters-filtergroup-lastRevision": "Цяперашнія вэрсіі",
+       "rcfilters-filtergroup-lastrevision": "Цяперашнія вэрсіі",
        "rcfilters-filter-lastrevision-label": "Цяперашняя вэрсія",
        "rcfilters-filter-lastrevision-description": "Толькі самая апошняя зьмена на старонцы.",
        "rcfilters-filter-previousrevision-label": "Ня самая апошняя вэрсія",
        "minoreditletter": "д",
        "newpageletter": "Н",
        "boteditletter": "р",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|назіральнік|назіральнікі|назіральнікаў}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|байт|байты|байтаў}} пасьля зьмены",
        "newsectionsummary": "/* $1 */ новы разьдзел",
        "rc-enhanced-expand": "Паказаць падрабязнасьці",
        "img-auth-nopathinfo": "Адсутнічаюць зьвесткі пра шлях.\nВаш сэрвэр мусіць быць наладжаны на пропуск зьменных REQUEST_URI і/ці PATH_INFO.\nКалі гэта так, паспрабуйце ўключыць $wgUsePathInfo.\nГлядзіце https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Запытаны шлях не належыць да каталёгу загрузкі, пазначанага ў канфігурацыі.",
        "img-auth-badtitle": "Немагчыма стварыць слушную назву з «$1».",
-       "img-auth-nologinnWL": "Вы не ўвайшлі ў сыстэму, а «$1» не знаходзіцца ў белым сьпісе.",
        "img-auth-nofile": "Файл «$1» не існуе.",
        "img-auth-isdir": "Вы спрабуеце атрымаць доступ да каталёгу «$1».\nДазволены толькі доступ да файлаў.",
        "img-auth-streaming": "Струменная перадача «$1».",
        "pager-newer-n": "$1 {{PLURAL:$1|навейшая|навейшыя|навейшых}}",
        "pager-older-n": "$1 {{PLURAL:$1|старэйшая|старэйшыя|старэйшых}}",
        "suppress": "Падавіць вэрсію",
-       "querypage-disabled": "Гэта спэцыяльная старонка адключаная для падвышэньня прадукцыйнасьці",
+       "querypage-disabled": "Гэтая спэцыяльная старонка адключаная для падвышэньня прадукцыйнасьці.",
        "apihelp": "Даведка API",
        "apihelp-no-such-module": "Модуль «$1» ня знойдзены.",
        "apisandbox": "Пясочніца API",
        "apisandbox-jsonly": "Для выкарыстаньня API-пясочніцы патрэбны JavaScript.",
-       "apisandbox-api-disabled": "API Ð·Ð°Ð±Ð°Ñ\80онены на гэтым сайце.",
+       "apisandbox-api-disabled": "API Ð°Ð´ÐºÐ»Ñ\8eÑ\87аны на гэтым сайце.",
        "apisandbox-intro": "Выкарыстоўвайце гэтую старонку для экспэрымэнтаў з <strong>API вэб-сэрвісу MediaWiki</strong>.\nЗьвяртайцеся да [[mw:API:Main page|дакумэнтацыі API]] для дадатковай інфармацыі па выкарыстаньні API. Напрыклад, [https://www.mediawiki.org/wiki/API#A_simple_example як атрымаць зьмест галоўнай старонкі]. Абярыце дзеяньне, каб пабачыць болей узораў.\n\nЗьвярніце ўвагу, што нягледзячы на тое, што гэта пясочніца, вашыя дзеяньні могуць унесьці зьмены ў вікі.",
        "apisandbox-submit": "Зрабіць запыт",
        "apisandbox-reset": "Ачысьціць",
        "booksources-search-legend": "Пошук кніг",
        "booksources-isbn": "ISBN:",
        "booksources-search": "Шукаць",
-       "booksources-text": "Ð\9dÑ\96жÑ\8dй Ð·Ð½Ð°Ñ\85одзÑ\96Ñ\86Ñ\86а Ñ\81Ñ\8cпÑ\96Ñ\81 Ñ\81паÑ\81Ñ\8bлак Ð½Ð° Ñ\96нÑ\88Ñ\8bÑ\8f Ñ\81айÑ\82Ñ\8b, Ñ\8fкÑ\96Ñ\8f Ð¿Ñ\80адаÑ\8eÑ\86Ñ\8c Ð½Ð¾Ð²Ñ\8bÑ\8f Ñ\96 Ð¿Ð°Ñ\82Ñ\80Ñ\8bманÑ\8bÑ\8f ÐºÐ½Ñ\96гÑ\96, Ñ\96 Ð¼Ð¾Ð³Ñ\83Ñ\86Ñ\8c Ñ\82акÑ\81ама Ð¼ÐµÑ\86Ñ\8c Ñ\96нÑ\84аÑ\80маÑ\86Ñ\8bÑ\8e Ð¿Ñ\80а ÐºÐ½Ñ\96гÑ\96, Ñ\8fкÑ\96Ñ\8f Ð\92ы шукаеце:",
+       "booksources-text": "Ð\9dÑ\96жÑ\8dй Ð·Ð½Ð°Ñ\85одзÑ\96Ñ\86Ñ\86а Ñ\81Ñ\8cпÑ\96Ñ\81 Ñ\81паÑ\81Ñ\8bлак Ð½Ð° Ñ\96нÑ\88Ñ\8bÑ\8f Ñ\81айÑ\82Ñ\8b, Ñ\8fкÑ\96Ñ\8f Ð¿Ñ\80адаÑ\8eÑ\86Ñ\8c Ð½Ð¾Ð²Ñ\8bÑ\8f Ñ\96 Ð¿Ð°Ñ\82Ñ\80Ñ\8bманÑ\8bÑ\8f ÐºÐ½Ñ\96гÑ\96, Ñ\96 Ð¼Ð¾Ð³Ñ\83Ñ\86Ñ\8c Ñ\82акÑ\81ама Ð¼ÐµÑ\86Ñ\8c Ñ\96нÑ\84аÑ\80маÑ\86Ñ\8bÑ\8e Ð¿Ñ\80а ÐºÐ½Ñ\96гÑ\96, Ñ\8fкÑ\96Ñ\8f Ð²ы шукаеце:",
        "booksources-invalid-isbn": "Пададзены няслушны ISBN; праверце, магчыма ўзьніклі памылкі пры пераносе нумару з арыгінальнай крыніцы.",
        "magiclink-tracking-rfc": "Старонкі, на якіх ужытыя магічныя спасылкі RFC",
        "magiclink-tracking-rfc-desc": "На гэтай старонцы ўжываюцца магічныя спасылкі RFC. Глядзіце [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Magic_links mediawiki.org] пра тое, як зладзіць міграцыю.",
        "alllogstext": "Сумесны паказ усіх журналаў падзеяў {{GRAMMAR:родны|{{SITENAME}}}}.\nВы можаце адфільтраваць вынікі па тыпе журналу, удзельніку (улічваецца рэгістар) ці старонцы (таксама ўлічваецца рэгістар).",
        "logempty": "Падобных запісаў у журнале няма.",
        "log-title-wildcard": "Шукаць назвы, якія пачынаюцца з гэтага тэксту",
-       "showhideselectedlogentries": "Ð\9fаказаÑ\86Ñ\8c\81Ñ\85аваÑ\86Ñ\8c Ð²Ñ\8bбÑ\80анÑ\8bÑ\8f Ð·Ð°Ð¿Ñ\96Ñ\81Ñ\8b Ñ\9e журнале",
+       "showhideselectedlogentries": "Ð\97Ñ\8cмÑ\8fнÑ\96Ñ\86Ñ\8c Ð±Ð°Ñ\87наÑ\81Ñ\8cÑ\86Ñ\8c Ð°Ð±Ñ\80анÑ\8bÑ\85 Ð·Ð°Ð¿Ñ\96Ñ\81аÑ\9e Ñ\83 журнале",
        "log-edit-tags": "Рэдагаваць меткі да абраных запісаў у журнале падзеяў",
        "checkbox-select": "Выбраць: $1",
        "checkbox-all": "усе",
        "allpages": "Усе старонкі",
        "nextpage": "Наступная старонка ($1)",
        "prevpage": "Папярэдняя старонка ($1)",
-       "allpagesfrom": "Паказаць старонкі, пачынаючы з:",
+       "allpagesfrom": "Паказаць старонкі ад:",
        "allpagesto": "Паказаць старонкі да:",
        "allarticles": "Усе старонкі",
        "allinnamespace": "Усе старонкі (прастора назваў: $1)",
        "allpagesbadtitle": "Пададзеная назва старонкі была няслушная ці пачыналася зь міжмоўнай ці міжвікі спасылкі. Яна яшчэ можа ўтрымліваць сымбалі, якія ня могуць ужывацца ў назвах.",
        "allpages-bad-ns": "{{SITENAME}} ня мае прасторы назваў «$1».",
        "allpages-hide-redirects": "Схаваць перанакіраваньні",
-       "cachedspecial-viewing-cached-ttl": "Ð\92Ñ\8b Ð¿Ñ\80аглÑ\8fдаеÑ\86е Ð·Ð°ÐºÑ\8dÑ\88аванÑ\83Ñ\8e Ð²Ñ\8dÑ\80Ñ\81Ñ\96Ñ\8e Ñ\81Ñ\82аÑ\80онкÑ\96, Ñ\8fкаÑ\8f Ð¼Ð°Ð³Ð»Ð° Ð±Ñ\8bÑ\86Ñ\8c Ð°Ð±Ð½Ð¾Ñ\9eленаÑ\8f $1 Ñ\82амÑ\83.",
-       "cachedspecial-viewing-cached-ts": "Ð\92Ñ\8b Ð¿Ñ\80аглÑ\8fдаеÑ\86е Ð·Ð°ÐºÑ\8dÑ\88аванÑ\83Ñ\8e Ð²Ñ\8dÑ\80Ñ\81Ñ\96Ñ\8e Ñ\81Ñ\82аÑ\80онкÑ\96, Ñ\8fкаÑ\8f Ð¼Ð¾Ð¶Ð° Ð±Ñ\8bÑ\86Ñ\8c Ð½ÐµÐ°ÐºÑ\82Ñ\83алÑ\8cнай.",
+       "cachedspecial-viewing-cached-ttl": "Вы праглядаеце кэшаваную вэрсію старонкі, якая магла быць абноўленая $1 таму.",
+       "cachedspecial-viewing-cached-ts": "Вы праглядаеце кэшаваную вэрсію старонкі, якая можа быць неактуальнай.",
        "cachedspecial-refresh-now": "Пабачыць апошнюю вэрсію.",
        "categories": "Катэгорыі",
        "categories-submit": "Паказаць",
        "categoriespagetext": "{{PLURAL:$1|1=Наступная катэгорыя існуе ў вікі і можа|Наступныя катэгорыі існуюць у вікі і могуць}} выкарыстоўвацца ці не выкарыстоўвацца.\nГлядзіце таксама [[Special:WantedCategories|сьпіс запатрабаваных катэгорыяў]].",
-       "categoriesfrom": "Паказаць катэгорыі, пачынаючы з:",
+       "categoriesfrom": "Паказаць катэгорыі ад:",
        "deletedcontributions": "Выдалены ўнёсак удзельніка",
        "deletedcontributions-title": "Выдалены ўнёсак удзельніка",
        "sp-deletedcontributions-contribs": "унёсак",
        "linksearch-pat": "Узор для пошуку:",
        "linksearch-ns": "Прастора назваў:",
        "linksearch-ok": "Шукаць",
-       "linksearch-text": "Ð\9cожна Ñ\9eжÑ\8bваÑ\86Ñ\8c Ñ\81Ñ\8bмбалÑ\96 Ð¿Ð°Ð´Ñ\81Ñ\82аноÑ\9eкÑ\96, Ð½Ð°Ð¿Ñ\80Ñ\8bклад, Â«*.wikipedia.org».\nÐ\9dеабÑ\85однÑ\8b Ð´Ð°Ð¼Ñ\8dн Ð¿ÐµÑ\80Ñ\88ага Ñ\9eзÑ\80оÑ\9eнÑ\8e, Ð½Ð°Ð¿Ñ\80Ñ\8bклад, Â«*.org».<br />\n{{PLURAL:$2|1=Ð\9fÑ\80аÑ\82акол, Ñ\8fкÑ\96 Ð¿Ð°Ð´Ñ\82Ñ\80Ñ\8bмлÑ\96ваеÑ\86Ñ\86а|Ð\9fÑ\80аÑ\82аколÑ\8b, Ñ\8fкÑ\96Ñ\8f Ð¿Ð°Ð´Ñ\82Ñ\80Ñ\8bмлÑ\96ваÑ\8eÑ\86Ñ\86а}}: $1 (дапомна http://, калі пратакол не пазначаны).",
+       "linksearch-text": "Ð\9cожна Ñ\9eжÑ\8bваÑ\86Ñ\8c Ñ\81Ñ\8bмбалÑ\96 Ð¿Ð°Ð´Ñ\81Ñ\82аноÑ\9eкÑ\96, Ð½Ð°Ð¿Ñ\80Ñ\8bклад, Â«*.wikipedia.org».\nÐ\9dеабÑ\85однÑ\8b Ð´Ð°Ð¼Ñ\8dн Ð¿ÐµÑ\80Ñ\88ага Ñ\9eзÑ\80оÑ\9eнÑ\8e, Ð½Ð°Ð¿Ñ\80Ñ\8bклад, Â«*.org».<br />\n{{PLURAL:$2|1=Ð\9fÑ\80аÑ\82акол, Ñ\8fкÑ\96 Ð¿Ð°Ð´Ñ\82Ñ\80Ñ\8bмлÑ\96ваеÑ\86Ñ\86а|Ð\9fÑ\80аÑ\82аколÑ\8b, Ñ\8fкÑ\96Ñ\8f Ð¿Ð°Ð´Ñ\82Ñ\80Ñ\8bмлÑ\96ваÑ\8eÑ\86Ñ\86а}}: $1 (па Ð·Ð¼Ð¾Ñ\9eÑ\87анÑ\8cнÑ\96 http://, калі пратакол не пазначаны).",
        "linksearch-line": "Спасылка на $1 з $2",
        "linksearch-error": "Сымбалі падстаноўкі могуць ужывацца толькі ў пачатку адрасоў.",
-       "listusersfrom": "Паказаць удзельнікаў, пачынаючы з:",
+       "listusersfrom": "Паказаць удзельнікаў ад:",
        "listusers-submit": "Паказаць",
        "listusers-noresult": "Удзельнікі ня знойдзеныя.",
        "listusers-blocked": "({{GENDER:$1|заблякаваны|заблякаваная}})",
        "activeusers": "Сьпіс актыўных удзельнікаў",
        "activeusers-intro": "Гэта сьпіс удзельнікаў, якія былі актыўнымі на працягу $1 {{PLURAL:$1|апошняга дня|апошніх дзён|апошніх дзён}}.",
        "activeusers-count": "$1 {{PLURAL:$1|дзеяньне|дзеяньні|дзеяньняў}} за $3 {{PLURAL:$3|апошні дзень|апошнія дні|апошніх дзён}}",
-       "activeusers-from": "Ð\9fаказваÑ\86Ñ\8c Ñ\9eдзелÑ\8cнÑ\96каÑ\9e, Ð¿Ð°Ñ\87Ñ\8bнаÑ\8eÑ\87Ñ\8b Ð·:",
+       "activeusers-from": "Ð\9fаказваÑ\86Ñ\8c Ñ\83дзелÑ\8cнÑ\96каÑ\9e Ð°Ð´:",
        "activeusers-groups": "Паказаць удзельнікаў, якія належаць да групаў:",
        "activeusers-excludegroups": "Выключыць удзельнікаў, якія належаць да групаў:",
        "activeusers-noresult": "Удзельнікі ня знойдзеныя.",
        "listgrouprights-addgroup-self": "можа дадаць уласны рахунак да {{PLURAL:$2|1=групы|групаў}}: $1",
        "listgrouprights-removegroup-self": "можа выдаліць уласны рахунак з {{PLURAL:$2|1=групы|групаў}}: $1",
        "listgrouprights-addgroup-self-all": "Можа дадаць уласны рахунак да ўсіх груп",
-       "listgrouprights-removegroup-self-all": "Ð\9cожа Ð²Ñ\8bдалÑ\96Ñ\86Ñ\8c Ñ\83лаÑ\81нÑ\8b Ñ\80аÑ\85Ñ\83нак Ð· Ñ\9eÑ\81Ñ\96Ñ\85 Ð³Ñ\80Ñ\83п",
+       "listgrouprights-removegroup-self-all": "Ð\92Ñ\8bдаленÑ\8cне Ñ\9eлаÑ\81нага Ñ\80аÑ\85Ñ\83нкÑ\83 Ð· Ñ\83Ñ\81Ñ\96Ñ\85 Ð³Ñ\80Ñ\83паÑ\9e",
        "listgrouprights-namespaceprotection-header": "Абмежаваньні прасторы назваў",
        "listgrouprights-namespaceprotection-namespace": "Прастора назваў",
        "listgrouprights-namespaceprotection-restrictedto": "Правы, якія дазваляюць удзельніку рэдагаваць",
        "trackingcategories-nodesc": "Апісаньне адсутнічае.",
        "trackingcategories-disabled": "Катэгорыя адключаная",
        "mailnologin": "Няма адрасу атрымальніка",
-       "mailnologintext": "Вам неабходна [[Special:UserLogin|ўвайсьці ў сыстэму]] і мець пацьверджаны адрас электроннай пошты ў Вашых [[Special:Preferences|наладах]], каб дасылаць лісты іншым удзельнікам.",
+       "mailnologintext": "Вы мусіце [[Special:UserLogin|ўвайсьці ў сыстэму]] і мець пацьверджаны адрас электроннай пошты ў вашых [[Special:Preferences|наладах]], каб дасылаць лісты іншым удзельнікам.",
        "emailuser": "Даслаць ліст",
-       "emailuser-title-target": "Адправіць гэта па электроннай пошце {{GENDER:$1|гэтаму ўдзельніку|гэтай удзельніцы}}",
-       "emailuser-title-notarget": "Ð\94аÑ\81лаÑ\86Ñ\8c Ð»Ñ\96Ñ\81Ñ\82 Ñ\9eдзелÑ\8cнÑ\96кÑ\83 Ñ\86Ñ\96 Ñ\9eдзелÑ\8cнÑ\96Ñ\86Ñ\8b Ð¿Ð° Ñ\8dлекÑ\82Ñ\80оннай Ð¿Ð¾Ñ\88Ñ\86е",
-       "emailpagetext": "Вы можаце выкарыстаць форму ніжэй, каб даслаць {{GENDER:$1|гэтаму ўдзельніку|гэтай удзельніцы}} ліст па электроннай пошце.\nАдрас электроннай пошты, які Вы пазначалі ў [[Special:Preferences|сваіх наладах]], будзе пазначаны ў полі ліста «Ад», і {{GENDER:$1|ўдзельнік|ўдзельніца}} зможа даслаць на гэты адрас адказ.",
-       "defemailsubject": "Ð\9bÑ\96Ñ\81Ñ\82 Ð· {{GRAMMAR:Ñ\80однÑ\8b|{{SITENAME}}}} Ð°Ð´ {{GENDER:$1|Ñ\83дзелÑ\8cнÑ\96ка|Ñ\83дзелÑ\8cнÑ\96Ñ\86Ñ\8b}} «$1»",
+       "emailuser-title-target": "Адправіць гэта электроннай поштай {{GENDER:$1|удзельніку|удзельніцы}}",
+       "emailuser-title-notarget": "Ð\94аÑ\81лаÑ\86Ñ\8c Ð»Ñ\96Ñ\81Ñ\82 Ñ\8dлекÑ\82Ñ\80оннай Ð¿Ð¾Ñ\88Ñ\82ай Ñ\83дзелÑ\8cнÑ\96кÑ\83 Ñ\86Ñ\96 Ñ\9eдзелÑ\8cнÑ\96Ñ\86Ñ\8b",
+       "emailpagetext": "Вы можаце выкарыстаць форму ніжэй, каб даслаць {{GENDER:$1|гэтаму ўдзельніку|гэтай удзельніцы}} ліст электроннай поштай.\nАдрас электроннай пошты, які вы пазначалі ў [[Special:Preferences|сваіх наладах]], будзе бачны ў полі ліста «Ад», і {{GENDER:$1|ўдзельнік|ўдзельніца}} зможа даслаць на гэты адрас адказ.",
+       "defemailsubject": "Ð\9bÑ\96Ñ\81Ñ\82 Ð°Ð´ {{GENDER:$1|Ñ\83дзелÑ\8cнÑ\96ка|Ñ\83дзелÑ\8cнÑ\96Ñ\86Ñ\8b}} {{GRAMMAR:Ñ\80однÑ\8b|{{SITENAME}}}} «$1»",
        "usermaildisabled": "Электронная пошта ўдзельніка адключаная",
        "usermaildisabledtext": "Вы ня можаце дасылаць электронныя лісты іншым удзельнікам {{GRAMMAR:родны|{{SITENAME}}}}",
        "noemailtitle": "Адрас электроннай пошты адсутнічае",
-       "noemailtext": "Ð\93Ñ\8dÑ\82Ñ\8b Ñ\83дзельнік не пазначыў слушны адрас электроннай пошты.",
+       "noemailtext": "Ð\93Ñ\8dÑ\82Ñ\8b Ñ\9eдзельнік не пазначыў слушны адрас электроннай пошты.",
        "nowikiemailtext": "Гэты ўдзельнік не дазволіў атрымліваць лісты па электроннай пошце ад іншых удзельнікаў.",
        "emailnotarget": "Неіснуючае ці няслушнае імя атрымальніка.",
        "emailtarget": "Увядзіце імя атрымальніка",
        "delete-confirm": "Выдаліць «$1»",
        "delete-legend": "Выдаліць",
        "historywarning": "<strong>Папярэджаньне</strong>: старонка, якую Вы зьбіраецеся выдаліць, мае гісторыю з $1 {{PLURAL:$1|вэрсіі|вэрсіяў|вэрсіяў}}:",
-       "historyaction-submit": "Паказаць",
+       "historyaction-submit": "Паказаць вэрсіі",
        "confirmdeletetext": "Зараз Вы выдаліце старонку разам з усёй гісторыяй зьменаў.\nКалі ласка, пацьвердзіце, што Вы зьбіраецеся гэта зрабіць і што Вы разумееце ўсе наступствы, а таксама робіце гэта ў адпаведнасьці з [[{{MediaWiki:Policy-url}}|правіламі]].",
        "actioncomplete": "Дзеяньне выкананае",
        "actionfailed": "Дзеяньне ня выкананае",
        "deleting-backlinks-warning": "<strong>Увага:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|іншыя старонкі]] ўключаюць або спасылаюцца на старонку, якую вы зьбіраецеся выдаліць.",
        "deleting-subpages-warning": "<strong>Папярэджаньне:</strong> старонка, якую вы зьбіраецеся выдаліць, мае [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|$1 падстаронку|$1 падстаронкі|$1 падстаронак|51=болей за 50 падстаронак}}]].",
        "rollback": "Адкаціць рэдагаваньні",
+       "rollback-confirmation-confirm": "Калі ласка, пацьвердзіце:",
+       "rollback-confirmation-yes": "Адкаціць",
+       "rollback-confirmation-no": "Адмяніць",
        "rollbacklink": "адкат",
        "rollbacklinkcount": "адкаціць $1 {{PLURAL:$1|рэдагаваньне|рэдагаваньні|рэдагаваньняў}}",
        "rollbacklinkcount-morethan": "адкаціць больш за $1 {{PLURAL:$1|рэдагаваньне|рэдагаваньні|рэдагаваньняў}}",
        "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-notify": "Адмененыя праўкі $1;\nвернутая папярэдняя вэрсія $2. [$3 Паказаць зьмены]",
        "sessionfailure-title": "Памылка сэсіі",
        "sessionfailure": "Магчыма ўзьніклі праблемы ў вашым цяперашнім сэансе працы;\nгэтае дзеяньне было скасаванае для прадухіленьня перахопу сэансу.\nКалі ласка, падайце форму яшчэ раз.",
        "changecontentmodel": "Зьмена мадэлі зьместу старонкі",
        "mycontris": "Унёсак",
        "anoncontribs": "Унёсак",
        "contribsub2": "Для {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "Для {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "Рахунак удзельніка «$1» не зарэгістраваны.",
        "negative-namespace-not-supported": "Прасторы назваў з адмоўнымі значэньнямі не падтрымліваюцца.",
        "nocontribs": "Ня знойдзена зьменаў, якія адпавядаюць гэтым крытэрыям.",
        "blocklist-userblocks": "Схаваць блякаваньні рахункаў",
        "blocklist-tempblocks": "Схаваць часовыя блякаваньні",
        "blocklist-addressblocks": "Схаваць блякаваньні асобных IP-адрасоў",
+       "blocklist-type": "Тып:",
+       "blocklist-type-opt-all": "Усе",
+       "blocklist-type-opt-sitewide": "На ўсім сайце",
+       "blocklist-type-opt-partial": "Частковае",
        "blocklist-rangeblocks": "Схаваць блякаваньні дыяпазонаў",
        "blocklist-timestamp": "Дата/час",
        "blocklist-target": "Мэта",
        "blocklist-editing-page": "старонкі",
        "blocklist-editing-ns": "прасторы назваў",
        "ipblocklist-empty": "Сьпіс блякаваньняў пусты.",
-       "ipblocklist-no-results": "Ð\9fаданÑ\8b IP-адÑ\80аÑ\81 Ð°Ð»Ñ\8cбо Ñ\96мÑ\8f Ñ\9eдзелÑ\8cнÑ\96ка Ð½Ðµ Ð·Ð°Ð±Ð»Ñ\8fкаванÑ\8bÑ\8f.",
+       "ipblocklist-no-results": "Ð\9dÑ\8f Ð·Ð½Ð¾Ð¹Ð´Ð·ÐµÐ½Ð° Ð±Ð»Ñ\8fкаванÑ\8cнÑ\8fÑ\9e Ð´Ð»Ñ\8f Ð¿Ð°Ð´Ð°Ð´Ð·ÐµÐ½Ð°Ð³Ð° IP-адÑ\80аÑ\81Ñ\83 Ð°Ð»Ñ\8cбо Ñ\96мÑ\8f Ñ\9eдзелÑ\8cнÑ\96ка.",
        "blocklink": "заблякаваць",
        "unblocklink": "разблякаваць",
        "change-blocklink": "зьмяніць блякаваньне",
+       "empty-username": "(імя ўдзельніка нядасягальнае)",
        "contribslink": "унёсак",
        "emaillink": "даслаць ліст",
        "autoblocker": "Вы аўтаматычна заблякаваныя, таму што Ваш IP-адрас нядаўна ўжываўся «[[User:$1|$1]]».\nПрычына блякаваньня $1 наступная: «$2»",
        "allmessagesdefault": "Тэкст па змоўчаньні",
        "allmessagescurrent": "Цяперашні тэкст",
        "allmessagestext": "Сьпіс усіх сыстэмных паведамленьняў, якія існуюць у прасторы назваў MediaWiki.\nКалі ласка, наведайце [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation старонку пра лякалізацыю MediaWiki] і [https://translatewiki.net translatewiki.net], калі Вы жадаеце ўдзельнічаць у перакладзе MediaWiki.",
-       "allmessagesnotsupportedDB": "'''{{ns:special}}:AllMessages''' не падтрымліваецца, таму што адключанае '''$wgUseDatabaseMessages'''.",
+       "allmessages-not-supported-database": "'''{{ns:special}}:AllMessages''' не падтрымліваецца, таму што адключанае '''$wgUseDatabaseMessages'''.",
        "allmessages-filter-legend": "Фільтар",
        "allmessages-filter": "Фільтар па стане зьменаў:",
        "allmessages-filter-unmodified": "Ня зьмененыя",
        "confirm-unwatch-top": "Выдаліць гэтую старонку з Вашага сьпісу назіраньня?",
        "confirm-rollback-button": "Так",
        "confirm-rollback-top": "Адкаціць праўкі на гэтай старонцы?",
+       "confirm-rollback-bottom": "Гэтае дзеяньне імгненна адкоціць абраныя зьмены гэтай старонкі.",
        "confirm-mcrrestore-title": "Аднавіць вэрсію",
        "confirm-mcrundo-title": "Адмяніць зьмену",
        "mcrundofailed": "Адмена не атрымалася",
        "passwordpolicies-policyflag-forcechange": "мусіць быць зьменены па ўваходзе",
        "passwordpolicies-policyflag-suggestchangeonlogin": "прапаноўваць зьмену па ўваходзе",
        "easydeflate-invaliddeflate": "Пададзены зьмест ня сьціснуты адпаведным чынам",
-       "unprotected-js": "З прычынаў бясьпекі JavaScript ня можа быць загружаны зь неабароненых сайтаў. Калі ласка, стварайце javascript выключна ў прасторы назваў MediaWiki: ці як падстаронку ўдзельніка"
+       "unprotected-js": "З прычынаў бясьпекі JavaScript ня можа быць загружаны зь неабароненых сайтаў. Калі ласка, стварайце javascript выключна ў прасторы назваў MediaWiki: ці як падстаронку ўдзельніка",
+       "userlogout-continue": "Калі вы захочаце выйсьці з сыстэмы, калі ласка, [$1 пераходзьце на старонку выхаду].",
+       "userlogout-sessionerror": "Выхад з сыстэмы не адбыўся праз памылку сэсіі. Калі ласка, [$1 паспрабуйце зноў]."
 }
index 979e34d..248b975 100644 (file)
@@ -81,6 +81,7 @@
        "tog-norollbackdiff": "Не паказваць розніцу ў выніку адкату",
        "tog-useeditwarning": "Папярэдзіць мяне, калі я пакідаю старонку з незахаванымі праўкамі",
        "tog-prefershttps": "Заўсёды выкарыстоўваць бяспечнае злучэнне па ўваходзе ў сістэму",
+       "tog-showrollbackconfirmation": "Паказваць акно пацвярджэння пры націску спасылкі адкату",
        "underline-always": "Заўсёды",
        "underline-never": "Ніколі",
        "underline-default": "Як у браўзеры",
        "returnto": "Вярнуцца да $1.",
        "tagline": "З пляцоўкі {{SITENAME}}",
        "help": "Даведка",
+       "help-mediawiki": "Дапамога пра MediaWiki",
        "search": "Знайсці",
        "search-ignored-headings": " #<!-- не змяняйце гэты радок --> <pre>\n# Загалоўкі, якія будзе ігнараваць рухавік пошуку.\n# Змены набудуць моц па наступным індэксаванні старонкі.\n# Вы можаце змусіць пераіндэксаванне старонкі, зрабіўшы пустое рэдагаванне.\n# Сінтаксіс наступны:\n#   * Усё ад сімвала \"#\" да канца радка - каментарый.\n#   * Кожны непусты радок - дакладны загаловак, які трэба ігнараваць, з рэгістрам і інш.\nКрыніцы\nСпасылкі\nГл. таксама\n #</pre> <!-- не змяняйце гэты радок -->",
        "searchbutton": "Знайсці",
        "ns-specialprotected": "Не дазволена правіць старонкі ў прасторы назваў {{ns:special}}.",
        "titleprotected": "Назва засцерагаецца ад стварэння; ахова пастаўлена ўдзельнікам: [[User:$1|$1]].\nТлумачэнне пастаноўкі пад ахову: <em>$2</em>.",
        "filereadonlyerror": "Немагчыма змяніць файл \"$1\", таму што файлавае сховішча \"$2\" зараз у рэжыме \"толькі для чытання\".\n\nСістэмны адміністратар, які абмежаваў доступ, патлумачыў гэта так: \"$3\".",
+       "invalidtitle": "Няслушная назва",
        "invalidtitle-knownnamespace": "Недапушчальны загаловак з прасторай імёнаў \"$2\" і тэкстам \"$3\"",
        "invalidtitle-unknownnamespace": "Недапушчальны загаловак з невядомым лікам прасторы імён $1 і тэкстам \"$2\"",
        "exception-nologin": "Вы не ўвайшлі ў сістэму",
        "resetpass-temp-password": "Тымчасовы пароль:",
        "resetpass-abort-generic": "Змяненне пароля было спынена прыстаўкаю.",
        "resetpass-expired": "Ваш пароль пратэрмінаваны. Калі ласка, устанавіце новы пароль для ўваходу ў сістэму.",
-       "resetpass-expired-soft": "Ваш пароль пратэрмінаваны, яго трэба замяніць. Калі ласка, выберыце новы пароль зараз, ці націсніце \"{{int:authprovider-resetpass-skip-label}}\", каб змяніць яго пазней.",
+       "resetpass-expired-soft": "Ваш пароль пратэрмінаваны і яго трэба замяніць. Калі ласка, выберыце новы пароль зараз, ці націсніце \"{{int:authprovider-resetpass-skip-label}}\", каб змяніць яго пазней.",
+       "resetpass-validity": "Ваш пароль няверны: $1 \n\nКалі ласка, устанавіце новы пароль для ўваходу ў сістэму.",
        "resetpass-validity-soft": "Ваш пароль недапушчальны: $1\n\nКалі ласка, выберыце новы пароль зараз, або націсніце \"{{int:authprovider-resetpass-skip-label}}\", каб скінуць яго пазней.",
        "passwordreset": "Выслаць мне новы пароль",
        "passwordreset-text-one": "Запоўніце гэту форму, каб атрымаць часовы пароль па эл.пошце.",
        "histfirst": "найстарэйшыя",
        "histlast": "найноўшыя",
        "historysize": "({{PLURAL:$1|1 байт|$1 байты|$1 байтаў}})",
-       "historyempty": "(пуста)",
+       "historyempty": "пуста",
        "history-feed-title": "Гісторыя версій",
        "history-feed-description": "Гісторыя версій гэтай старонкі",
        "history-feed-item-nocomment": "$1 на $2",
        "difference-missing-revision": "{{PLURAL:$2|$2 версія|$2 версіі|$2 версій}} гэтай розніцы ($1) {{PLURAL:$2|не знойдзена|не знойдзены}}.\n\nЗвычайна такое здараецца з-за пераходу па састарэлай спасылцы на розніцу ў старонцы, якая была выдалена.\nПадрабязнасці могуць быць у [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} журнале выдаленняў].",
        "searchresults": "Вынікі пошуку",
        "search-filter-title-prefix": "Шукаць толькі на старонках, назва якіх пачынаецца з «$1»",
+       "search-filter-title-prefix-reset": "Шукаць усе старонкі",
        "searchresults-title": "Вынікі пошуку «$1»",
        "titlematches": "Знойдзена ў назвах",
        "textmatches": "Знойдзена ў тэкстах",
        "group-autoconfirmed-member": "{{GENDER:$1|аўта-пацверджаны ўдзельнік|аўта-пацверджаная ўдзельніца}}",
        "group-bot-member": "{{GENDER:$1|бот}}",
        "group-sysop-member": "{{GENDER:$1|адміністратар}}",
+       "group-interface-admin-member": "{{GENDER:$1|адміністратар інтэрфейсу}}",
        "group-bureaucrat-member": "{{GENDER:$1|бюракрат}}",
        "group-suppress-member": "{{GENDER:$1|схоўваючы|схоўваючая}}",
        "grouppage-user": "{{ns:project}}:Удзельнікі",
        "grouppage-autoconfirmed": "{{ns:project}}:Аўтапацверджаныя ўдзельнікі",
        "grouppage-bot": "{{ns:project}}:Робаты",
        "grouppage-sysop": "{{ns:project}}:Адміністратары",
+       "grouppage-interface-admin": "{{ns:project}}:Адміністратары інтэрфейсу",
        "grouppage-bureaucrat": "{{ns:project}}:Бюракраты",
        "grouppage-suppress": "{{ns:project}}:Схоўваючыя",
        "right-read": "Чытаць старонкі",
        "right-reupload-own": "Запісваць паўзверх існуючага файла, які ўкладвалі самі",
        "right-reupload-shared": "Перамагаць файлы з агульнага сховішча тутэйшымі файламі",
        "right-upload_by_url": "Укладваць файлы з сеціўнага адраса (URL)",
-       "right-purge": "ЧÑ\8bÑ\81Ñ\86Ñ\96Ñ\86Ñ\8c ÐºÑ\8dÑ\88 Ð¿Ð»Ñ\8fÑ\86оÑ\9eкÑ\96 Ð´Ð»Ñ\8f Ñ\81Ñ\82аÑ\80онкÑ\96 Ð±ÐµÐ· Ð¿Ð°Ñ\86веÑ\80джаннÑ\8f",
+       "right-purge": "Ð\90Ñ\87Ñ\8bÑ\81Ñ\82ка ÐºÑ\8dÑ\88Ñ\83 Ð¿Ð»Ñ\8fÑ\86оÑ\9eкÑ\96 Ð´Ð»Ñ\8f Ñ\81Ñ\82аÑ\80онкÑ\96",
        "right-autoconfirmed": "Не падпарадкоўвацца абмежаванням хуткасці, накладзеным на IP",
        "right-bot": "Лічыцца аўтаматычным працэсам",
        "right-nominornewtalk": "Не паведамляць пра новыя паведамленні ў адказ на дробныя праўкі размоўных старонак",
        "grant-createaccount": "Ствараць уліковыя запісы",
        "grant-createeditmovepage": "Ствараць, правіць і пераносіць старонкі",
        "grant-delete": "Выдаляць старонкі, версіі і запісы ў журналах",
-       "grant-editinterface": "Правіць прасторы назваў MediaWiki і CSS/JSON/JavaScript удзельніка",
+       "grant-editinterface": "Правіць прасторы назваў MediaWiki і JSON сайту/удзельніка",
        "grant-editmycssjs": "Правіць Ваш карыстальніцкі CSS/JSON/JavaScript",
        "grant-editmyoptions": "Змяняць вашы настройкі",
        "grant-editmywatchlist": "Правіць ваш спіс назірання",
        "rcfilters-activefilters-hide": "Схаваць",
        "rcfilters-activefilters-show": "Паказаць",
        "rcfilters-activefilters-hide-tooltip": "Схаваць вобласць актыўных фільтраў",
+       "rcfilters-activefilters-show-tooltip": "Паказаць вобласць актыўных фільтраў",
        "rcfilters-advancedfilters": "Пашыраныя фільтры",
        "rcfilters-limit-title": "Вынікі для паказу",
        "rcfilters-limit-and-date-label": "$1 {{PLURAL:$1|змена|змены|змен}}, $2",
        "rcfilters-filter-editsbyself-description": "Ваш унёсак",
        "rcfilters-filter-editsbyother-label": "Змены іншых удзельнікаў",
        "rcfilters-filter-editsbyother-description": "Усе змены, акрамя Вашых",
-       "rcfilters-filtergroup-userExpLevel": "Рэгістрацыя ўдзельніка і яго вопыт",
+       "rcfilters-filtergroup-user-experience-level": "Рэгістрацыя ўдзельніка і яго вопыт",
        "rcfilters-filter-user-experience-level-registered-label": "Зарэгістраваныя",
        "rcfilters-filter-user-experience-level-registered-description": "Рэдактары, якія ўвайшлі ў сістэму.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Незарэгістраваныя",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Фільтр «малыя праўкі» канфліктуе з адным ці некалькімі фільтрамі Тыпу змен, бо пэўныя тыпы правак не могуць пазначаны як «малыя». Канфліктныя фільтры пазначаны ўверсе, у вобласці Актыўных фільтраў.",
        "rcfilters-hideminor-conflicts-typeofchange": "Пэўныя тыпы правак не могуць быць пазначаны як «малыя», таму гэты фільтр канфліктуе з наступным фільтрам Тыпа змены: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Гэты фільтр Тыпа змены канфліктуе з фільтрам «малых правак». Пэўныя тыпы правак не могуць быць пазначаны як «малыя».",
-       "rcfilters-filtergroup-lastRevision": "Апошнія версіі",
+       "rcfilters-filtergroup-lastrevision": "Апошнія версіі",
        "rcfilters-filter-lastrevision-label": "Актуальная версія",
        "rcfilters-filter-lastrevision-description": "Толькі самая апошняя змена на старонцы.",
        "rcfilters-filter-previousrevision-label": "Не апошняя версія",
        "rcfilters-watchlist-markseen-button": "Пазначыць усе змены як прагледжаныя",
        "rcfilters-watchlist-edit-watchlist-button": "Рэдагаваць Ваш спіс назіраных старонак",
        "rcfilters-watchlist-showupdated": "Змены старонак, якія Вы не наведвалі з таго часу, як яны адбыліся, выдзелены <strong>тлустым</strong> і пазначаны маркерам.",
-       "rcfilters-preference-label": "СÑ\85аваÑ\86Ñ\8c Ð¿Ð°Ð»ÐµÐ¿Ñ\88анÑ\83Ñ\8e Ð²ÐµÑ\80Ñ\81Ñ\96Ñ\8e Â«Ð\90поÑ\88нÑ\96Ñ\85 Ð·Ð¼ÐµÐ½Â»",
+       "rcfilters-preference-label": "Ð\92Ñ\8bкаÑ\80Ñ\8bÑ\81Ñ\82оÑ\9eваÑ\86Ñ\8c Ñ\96нÑ\82Ñ\8dÑ\80Ñ\84ейÑ\81 Ð±ÐµÐ· JavaScript",
        "rcfilters-preference-help": "Адкатвае рэдызайн інтэрфейсу 2017 года і ўсе інструменты, дададзеныя з тых часоў.",
-       "rcfilters-watchlist-preference-label": "СÑ\85аваÑ\86Ñ\8c Ð¿Ð°Ð»ÐµÐ¿Ñ\88анÑ\83Ñ\8e Ð²ÐµÑ\80Ñ\81Ñ\96Ñ\8e Ñ\81пÑ\96Ñ\81а Ð½Ð°Ð·Ñ\96Ñ\80аннÑ\8f",
+       "rcfilters-watchlist-preference-label": "Ð\92Ñ\8bкаÑ\80Ñ\8bÑ\81Ñ\82оÑ\9eваÑ\86Ñ\8c Ñ\96нÑ\82Ñ\8dÑ\80Ñ\84ейÑ\81 Ð±ÐµÐ· JavaScript",
        "rcfilters-watchlist-preference-help": "Адкатвае рэдызайн інтэрфейсу 2017 года і ўсе інструменты, дададзеныя з тых часоў.",
        "rcnotefrom": "Ніжэй {{PLURAL:$5|паказана змяненне|паказаны змены}} з <strong>$3, $4</strong> (не больш за <strong>$1</strong>).",
        "rclistfrom": "Паказаць змены з $3 $2",
        "minoreditletter": "д",
        "newpageletter": "Н",
        "boteditletter": "р",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|назіральнік|назіральнікі|назіральнікаў}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|байт|байты|байтаў}} пасля змены",
        "newsectionsummary": "/* $1 */ новы падраздзел",
        "rc-enhanced-expand": "Паказаць падрабязнасці",
        "recentchangeslinked-feed": "Звязаныя праўкі",
        "recentchangeslinked-toolbox": "Звязаныя праўкі",
        "recentchangeslinked-title": "Змяненні, якія датычаць \"$1\"",
-       "recentchangeslinked-summary": "Увядзіце імя старонкі, каб убачыць змяненні на старонках, якія спасылаюцца на дадзеную старонку ці на якія яна спасылаецца. (Каб убачыць складнікі катэгорыі, увядзіце Катэгорыя:Назва катэгорыі). Старонкі, якія ўваходзяць у [[Special:Watchlist|Ваш спіс назірання]], выдзелены <strong>тлустым шрыфтам</strong>.",
+       "recentchangeslinked-summary": "Увядзіце імя старонкі, каб убачыць змяненні на старонках, на якія яна спасылаецца або якія спасылаюцца на яе (каб убачыць складнікі катэгорыі, увядзіце {{ns:category}}:Назва катэгорыі). Змены старонак з [[Special:Watchlist|Вашага спісу назірання]] выдзелены <strong>тлустым шрыфтам</strong>.",
        "recentchangeslinked-page": "Назва старонкі:",
        "recentchangeslinked-to": "Паказваць, замест гэтага, змяненні на старонках, што спасылаюцца сюды",
        "recentchanges-page-added-to-category": "[[:$1]] дададзена ў катэгорыю",
        "img-auth-nopathinfo": "Адсутнічае PATH_INFO.\nВаш сервер не настроены на перадачу гэтых звестак.\nМагчыма, ён на аснове CGI і не падтрымлівае img_auth.\nГл. https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Запытаны шлях не ставіцца да наладжанага каталога ўкладанняў.",
        "img-auth-badtitle": "Немагчыма пабудаваць правільны загаловак з «$1».",
-       "img-auth-nologinnWL": "Вы не ўвайшлі ў сістэму, а «$1» не ўваходзіць ў белы спіс.",
        "img-auth-nofile": "Файл \" $1 \"не існуе.",
        "img-auth-isdir": "Вы спрабуеце атрымаць доступ да каталога \"$1\"\nДазволены доступ толькі да файлаў.",
        "img-auth-streaming": "Патокавая перадача «$1».",
        "listfiles_size": "Памер у байтах",
        "listfiles_description": "Апісанне",
        "listfiles_count": "Версіі",
-       "listfiles-show-all": "Уключыць старыя версіі відарысаў",
+       "listfiles-show-all": "Уключыць старыя версіі файлаў",
        "listfiles-latestversion": "Актуальная версія",
        "listfiles-latestversion-yes": "Так",
        "listfiles-latestversion-no": "Не",
        "filehist-filesize": "Аб'ём файла",
        "filehist-comment": "Тлумачэнне",
        "imagelinks": "Выкарыстанне файла",
-       "linkstoimage": "Наступн{{PLURAL:$1|ая старонка спасылаецца|ыя $1 старонкі спасылаюцца}} на гэты файл:",
+       "linkstoimage": "{{PLURAL:$1|Наступная $1 старонка выкарыстоўвае|Наступныя $1 старонкі выкарыстоўваюць|Наступныя $1 старонак выкарыстоўваюць}} гэты файл:",
        "linkstoimage-more": "На гэты файл існуюць спасылкі з больш як $1 {{PLURAL:$1|старонкі|старонак}}.\nНаступны пералік паказвае толькі {{PLURAL:$1|першую спасылку|першыя $1 з іх}}.\nТаксама ёсць [[Special:WhatLinksHere/$2|поўны пералік]].",
        "nolinkstoimage": "Няма старонак, якія б спасылаліся на файл.",
        "morelinkstoimage": "Паказаць [[Special:WhatLinksHere/$1|больш спасылак]] на гэты файл.",
        "statistics-files": "Укладзеныя файлы",
        "statistics-edits": "Праўкі старонак ад часу інсталяцыі {{SITENAME}}",
        "statistics-edits-average": "Колькасць правак на 1 старонку",
-       "statistics-users": "Registered [[Special:ListUsers|users]]",
+       "statistics-users": "Зарэгістраваныя ўдзельнікі",
        "statistics-users-active": "Актыўныя ўдзельнікі",
        "statistics-users-active-desc": "Удзельнікі, якія хоць нешта зрабілі за апошн{{PLURAL:$1|і дзень|ія $1 дзён}}",
        "pageswithprop": "Старонкі з уласцівасцю старонкі",
        "pageswithprop-legend": "Старонкі з пэўнай уласцівасцю",
        "pageswithprop-text": "На гэтай старонцы пералічаны старонкі, якія выкарыстоўваюць пэўную уласцівасць.",
        "pageswithprop-prop": "Назва ўласцівасці:",
+       "pageswithprop-reverse": "Сартаваць у зваротным парадку",
+       "pageswithprop-sortbyvalue": "Сартаваць па значэнню ўласцівасці",
        "pageswithprop-submit": "Перайсці",
        "pageswithprop-prophidden-long": "доўгае тэкставае значэнне ўласцівасці схавана ($1)",
        "pageswithprop-prophidden-binary": "двайковае значэнне ўласцівасці схавана ($1)",
        "doubleredirects": "Падвойныя перасылкі",
        "doubleredirectstext": "Тут пералічаныя старонкі-перасылкі, якія паказваюць на іншыя перасылкі.\nКожны радок утрымлівае спасылкі на першую і другую перасылкі, а таксама мэту другой перасылкі, якая звычайна і ёсць \"сапраўдная\" мэтавая старонка, на якую павінна была паказваць першая перасылка.\n<del>Закрэсленыя складнікі</del> ўжо былі папраўленыя.",
        "double-redirect-fixed-move": "Назва [[$1]] была перанесена.\nПасля аўтаматычнага абнаўлення зараз яна перасылае да [[$2]]",
-       "double-redirect-fixed-maintenance": "Аўтаматычнае выпраўленне падвойнай перасылкі з [[$1]] на [[$2]] цягам тэхнічнага абслугоўвання.",
+       "double-redirect-fixed-maintenance": "Аўтаматычнае выпраўленне падвойнай перасылкі з [[$1]] на [[$2]] цягам тэхнічнага абслугоўвання",
        "double-redirect-fixer": "Выпраўляльнік перасылак",
        "brokenredirects": "Паламаныя перасылкі",
        "brokenredirectstext": "Гэтыя перасылкі паказваюць на старонкі, якіх няма:",
        "prefixindex": "Старонкі з назвамі на ўзор",
        "prefixindex-namespace": "Усе старонкі з прэфіксам (прастора назваў «{{ns:$1}}»)",
        "prefixindex-submit": "Паказаць",
-       "prefixindex-strip": "Ð\9fÑ\80Ñ\8bбÑ\80аÑ\86Ñ\8c Ð¿Ñ\80Ñ\8dÑ\84Ñ\96кÑ\81 Ñ\83 Ð¿ÐµÑ\80алÑ\96кÑ\83",
+       "prefixindex-strip": "Ð\9fÑ\80Ñ\8bбÑ\80аÑ\86Ñ\8c Ð¿Ñ\80Ñ\8dÑ\84Ñ\96кÑ\81 Ñ\83 Ð²Ñ\8bнÑ\96каÑ\85",
        "shortpages": "Старонкі малога аб'ёму",
        "longpages": "Старонкі вялікага аб'ёму",
        "deadendpages": "Старонкі без спасылак",
        "protectedtitles-submit": "Паказаць назвы",
        "listusers": "Усе ўдзельнікі",
        "listusers-editsonly": "Толькі ўдзельнікі, якія маюць праўкі",
+       "listusers-temporarygroupsonly": "Паказваць толькі ўдзельнікаў у тымчасовых групах удзельнікаў",
        "listusers-creationsort": "У парадку датаў стварэння",
        "listusers-desc": "Парадкаваць да памяншэння",
        "usereditcount": "$1 {{PLURAL:$1|праўка|праўкі|правак}}",
        "deleting-backlinks-warning": "<strong>Увага:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Іншыя старонкі]] спасылаюцца на ці ўключаюць старонку, якую вы збіраецеся выдаліць.",
        "deleting-subpages-warning": "<strong>Увага:</strong> Старонка, якую Вы хочаце выдаліць, мае [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|$1 падстаронка|$1 падстаронкі|$1 падстаронак|51=болей за 50 падстаронак}}]].",
        "rollback": "Адкаціць праўкі",
+       "rollback-confirmation-confirm": "Калі ласка, пацвердзіце:",
+       "rollback-confirmation-yes": "Адкат",
+       "rollback-confirmation-no": "Адмяніць",
        "rollbacklink": "адкат",
        "rollbacklinkcount": "адкаціць $1 {{PLURAL:$1|праўку|праўкі|правак}}",
        "rollbacklinkcount-morethan": "адкаціць больш за $1 {{PLURAL:$1|праўку|праўкі|правак}}",
        "revertpage": "Праўкі аўтарства [[Special:Contributions/$2|$2]] ([[User talk:$2|размова]]) адкочаныя; вернута апошняя версія аўтарства [[User:$1|$1]]",
        "revertpage-nouser": "Праўкі (імя ўдзельніка схавана) адкочаны да версіі {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Адкочаны праўкі {{GENDER:$3|$1}}; вернута апошняя версія {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Адкочаны праўкі $1;\nвернута апошняя версія $2. [$3 Паказаць змены]",
        "sessionfailure-title": "Памылка сеансу",
        "sessionfailure": "Магчыма, ёсць праблемы з вашым сеансам працы ў сістэме. Таму вам было адмоўлена ў выкананні дзеяння, каб засцерагчыся ад захопу сеанса.\n\nВярніцеся на папярэднюю старонку, перазагрузіце яе і тады паспрабуйце зноў.",
        "changecontentmodel": "Змяніць мадэль змесціва старонкі",
        "allmessagesdefault": "Прадвызначаны тэкст",
        "allmessagescurrent": "Актуальны тэкст",
        "allmessagestext": "Пералік сістэмных паведамленняў, наяўных у прасторы назваў MediaWiki.\nКалі ласка, наведайце пляцоўкі [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] і [https://translatewiki.net translatewiki.net], калі жадаеце ўдзельнічаць у перакладзе MediaWiki.",
-       "allmessagesnotsupportedDB": "Немагчыма паказаць '''{{ns:special}}:{{:{{ns:mediawiki}}:Allmessages}}''', таму што не працуе '''$wgUseDatabaseMessages'''.",
+       "allmessages-not-supported-database": "Немагчыма паказаць '''{{ns:special}}:{{:{{ns:mediawiki}}:Allmessages}}''', таму што не працуе '''$wgUseDatabaseMessages'''.",
        "allmessages-filter-legend": "Фільтры",
        "allmessages-filter": "Са станам апрацоўкі:",
        "allmessages-filter-unmodified": "Нязмененыя",
index 00c6a04..baf3c3a 100644 (file)
@@ -90,6 +90,7 @@
        "tog-norollbackdiff": "Да не се показва разликата между редакциите след отмяна на редакции",
        "tog-useeditwarning": "Предупреждаване при опит за напускане на страница, отворена в режим на редактиране, без да са запазени промените",
        "tog-prefershttps": "Да се използва винаги защитена връзка при влизане",
+       "tog-showrollbackconfirmation": "Показване на диалогов прозорец за потвърждение при кликване върху препратката „Отмяна“",
        "underline-always": "Винаги",
        "underline-never": "Никога",
        "underline-default": "Според настройките на облика или браузъра",
        "page_first": "първа",
        "page_last": "последна",
        "histlegend": "Разлики: Изберете версиите, които желаете да сравните, чрез превключвателите срещу тях и натиснете Enter или бутона за сравнение.<br />\nЛегенда: <strong>({{int:cur}})</strong> = разлика с текущата версия, <strong>({{int:last}})</strong> = разлика с предишната версия, <strong>{{int:minoreditletter}}</strong> = малка промяна.",
-       "history-fieldset-title": "ТÑ\8aÑ\80Ñ\81ене Ð½Ð° Ð²ÐµÑ\80Ñ\81ии",
-       "history-show-deleted": "Само Ð·Ð° Ð¸Ð·Ñ\82Ñ\80иване Ð½Ð° Ð²ÐµÑ\80Ñ\81ии",
+       "history-fieldset-title": "ФилÑ\82Ñ\80иÑ\80ане Ð½Ð° Ñ\80едакÑ\86ии",
+       "history-show-deleted": "Само Ð¸Ð·Ñ\82Ñ\80иÑ\82и Ñ\80едакÑ\86ии",
        "histfirst": "най-стари",
        "histlast": "най-нови",
        "historysize": "({{PLURAL:$1|1 байт|$1 байта}})",
-       "historyempty": "(празна)",
+       "historyempty": "празнo",
        "history-feed-title": "Редакционна история",
        "history-feed-description": "Редакционна история на страницата в уикито",
        "history-feed-item-nocomment": "$1 в $2",
        "right-reupload-own": "Препокриване на съществуващ файл, качен от същия потребител",
        "right-reupload-shared": "Препокриване на едноименните файлове от общото мултимедийно хранилище с локални",
        "right-upload_by_url": "Качване на файл от URL адрес",
-       "right-purge": "Ð\98зÑ\87иÑ\81Ñ\82ване Ð½Ð° Ñ\81кладиÑ\80аноÑ\82о Ñ\81Ñ\8aдÑ\8aÑ\80жание Ð½Ð° Ñ\81Ñ\82Ñ\80аниÑ\86иÑ\82е Ð±ÐµÐ· Ð¿Ð¾ÐºÐ°Ð·Ð²Ð°Ð½Ðµ Ð½Ð° Ñ\81Ñ\82Ñ\80аниÑ\86а Ð·Ð° Ð¿Ð¾Ñ\82вÑ\8aÑ\80ждение",
+       "right-purge": "Ð\98зÑ\87иÑ\81Ñ\82ване Ð½Ð° Ñ\81кладиÑ\80аноÑ\82о Ñ\81Ñ\8aдÑ\8aÑ\80жание Ð½Ð° Ñ\81Ñ\82Ñ\80аниÑ\86аÑ\82а",
        "right-autoconfirmed": "Редактиране на полузащитени страници",
        "right-bot": "Третиране като автоматизиран процес",
        "right-nominornewtalk": "Малките промени по дискусионните страници не предизвикват известието за ново съобщение",
        "rcfilters-savedqueries-already-saved": "Тези филтри вече са съхранени. Променете настройките си, за да създадете нов Запазен филтър.",
        "rcfilters-restore-default-filters": "Възстановяване на филтрите по подразбиране",
        "rcfilters-clear-all-filters": "Изчистване на всички филтри",
-       "rcfilters-show-new-changes": "Ð\9fÑ\80еглед Ð½Ð° Ð½Ð°Ð¹-новиÑ\82е Ð¿Ñ\80омени",
+       "rcfilters-show-new-changes": "Ð\9fÑ\80еглед Ð½Ð° Ð¿Ñ\80омениÑ\82е Ð½Ð°Ð¿Ñ\80авени Ñ\81лед $1",
        "rcfilters-search-placeholder": "Филтриране на промените (използвайте менюто или търсете по име на филтър)",
        "rcfilters-invalid-filter": "Невалиден филтър",
        "rcfilters-empty-filter": "Няма активни филтри. Показани са всички редакции.",
        "rcfilters-filter-editsbyself-description": "Ваши редакции.",
        "rcfilters-filter-editsbyother-label": "Чужди редакции",
        "rcfilters-filter-editsbyother-description": "Всички редакции с изключение на вашите собствени.",
-       "rcfilters-filtergroup-userExpLevel": "Регистрация на потребителя и опит",
+       "rcfilters-filtergroup-user-experience-level": "Регистрация на потребителя и опит",
        "rcfilters-filter-user-experience-level-registered-label": "Регистрирани",
        "rcfilters-filter-user-experience-level-registered-description": "Влезли в системата редактори.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Нерегистрирани",
        "rcfilters-filter-logactions-label": "Записани в дневника действия",
        "rcfilters-filter-logactions-description": "Административни действия, създавания на сметки, изтривания на страници, качвания...",
        "rcfilters-hideminor-conflicts-typeofchange": "Определени видове промени не могат да бъдат отбелязвани като „малки“, така че този филтър противоречи със следните филтри за Вид на промяната: $1",
-       "rcfilters-filtergroup-lastRevision": "Текущи версии",
+       "rcfilters-filtergroup-lastrevision": "Текущи версии",
        "rcfilters-filter-lastrevision-label": "Текуща версия",
        "rcfilters-filter-lastrevision-description": "Само последната промяна на страница.",
        "rcfilters-filter-previousrevision-label": "Не последната версия",
        "newpageletter": "Н",
        "boteditletter": "б",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|наблюдаващ потребител|наблюдаващи потребители}}]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|байт|байта}} след редакцията",
        "newsectionsummary": "Нова тема /* $1 */",
        "img-auth-nopathinfo": "Липсва информация за пътя.\nВашият сървър трябва да бъде настроен да предава променливите REQUEST_URI и PATH_INFO .\nАко това е така, опитайте да активирате $wgUsePathInfo.\n\nВижте https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Търсеният път не е в настроената директория за качвания.",
        "img-auth-badtitle": "Грешка при изграждането на валидно заглавие от „$1“.",
-       "img-auth-nologinnWL": "Не сте влезли в системата и „$1“ не е в разрешения списък.",
        "img-auth-nofile": "Файлът „$1“ не съществува.",
        "img-auth-isdir": "Опитвате се да осъществите достъп до директорията „$1“.\nРазрешен е само достъп до файловете.",
        "img-auth-streaming": "Излъчване „$1“.",
        "delete-confirm": "Изтриване на „$1“",
        "delete-legend": "Изтриване",
        "historywarning": "<strong>Внимание:</strong> Страницата, която възнамерявате да изтриете, има история с приблизително $1 {{PLURAL:$1|редакция|редакции}}:",
-       "historyaction-submit": "Показване",
+       "historyaction-submit": "Показване на версии",
        "confirmdeletetext": "На път сте да изтриете страница заедно с цялата ѝ редакционна история.\nПотвърдете, че искате това, разбирате последствията и правите това в съответствие с [[{{MediaWiki:Policy-url}}|политиката]].",
        "actioncomplete": "Действието беше изпълнено",
        "actionfailed": "Действието не сполучи",
        "revertpage": "Премахване на [[Special:Contributions/$2|редакции на $2]] ([[User talk:$2|беседа]]); възвръщане към последната версия на [[User:$1|$1]]",
        "revertpage-nouser": "Връщане на редакции на скрит потребител до последната версия на [[User:$1|$1]]",
        "rollback-success": "Отменени редакции на {{GENDER:$3|$1}};\nвъзвръщане към последната версия на {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Премахнати редакции на $1;\nвръщане към последна версия на $2. [$3 Показване на промени]",
        "sessionfailure-title": "Прекъсната сесия",
        "sessionfailure": "Изглежда има проблем със сесията ви;\nдействието беше отказано като предпазна мярка срещу крадене на сесията.\nМоля, изпратете формуляра повторно.",
        "changecontentmodel": "Промяна на модела на съдържанието на страница",
        "blocklist-editing-page": "страници",
        "blocklist-editing-ns": "именни пространства",
        "ipblocklist-empty": "Списъкът на блокиранията е празен.",
-       "ipblocklist-no-results": "УказаниÑ\8fÑ\82 IP-адÑ\80еÑ\81 Ð¸Ð»Ð¸ Ð¿Ð¾Ñ\82Ñ\80ебиÑ\82ел Ð½Ðµ Ðµ Ð±Ð»Ð¾ÐºÐ¸Ñ\80ан.",
+       "ipblocklist-no-results": "Ð\9dе Ñ\81а Ð¾Ñ\82кÑ\80иÑ\82и Ð±Ð»Ð¾ÐºÐ¸Ñ\80аниÑ\8f Ð·Ð° Ð¸Ð·Ð±Ñ\80аниÑ\8f IP-адÑ\80еÑ\81 Ð¸Ð»Ð¸ Ð¿Ð¾Ñ\82Ñ\80ебиÑ\82ел.",
        "blocklink": "блокиране",
        "unblocklink": "отблокиране",
        "change-blocklink": "промяна на параметрите на блокирането",
        "ipb-otherblocks-header": "{{PLURAL:$1|Друго блокиране|Други блокирания}}",
        "unblock-hideuser": "Не можете да отблокирате този потребител, тъй като потребителското му име е скрито.",
        "ipb_cant_unblock": "Грешка: Не е намерен блок с номер $1. Вероятно потребителят е вече отблокиран.",
-       "ipb_blocked_as_range": "Грешка: IP-адресът $1 не може да бъде разблокиран, тъй като е част от блокирания регистър $2. Можете да разблокирате адреса, като разблокирате целия регистър.",
+       "ipb_blocked_as_range": "Грешка: IP-адресът $1 не може да бъде отблокиран, тъй като е част от блокирания регистър $2. Можете да отблокирате адреса, като отблокирате целия регистър.",
        "ip_range_invalid": "Невалиден диапазон на IP-адреси.",
        "ip_range_toolarge": "Забранено е блокиране на диапазони от IP адреси по-големи от /$1.",
        "ip_range_exceeded": "IP диапазонът превишава максималния диапазон. Позволен диапазон: /$1.",
        "sorbsreason": "IP-адресът Ви е записан като анонимно достъпен междинен сървър в DNSBL на {{SITENAME}}.",
        "sorbs_create_account_reason": "IP-адресът Ви е записан като анонимно достъпен междинен сървър в DNSBL на {{SITENAME}}.\nНе може да създадете сметка.",
        "cant-see-hidden-user": "Потребителят, който опитвате да блокирате, вече е блокиран и скрит. Тъй като нямате права да скривате потребители, не можете да видите или редактирате блокирането на потребителя.",
-       "ipbblocked": "Не можете да блокирате и разблокирате други потребители, защото Вие самият (самата) сте блокиран(а).",
-       "ipbnounblockself": "Нямате право да се разблокирате сам(а).",
+       "ipbblocked": "Не можете да блокирате и отблокирате други потребители, защото Вие самият (самата) сте блокиран(а).",
+       "ipbnounblockself": "Нямате право да се отблокирате сам(а).",
        "lockdb": "Заключване на базата от данни",
        "unlockdb": "Отключване на базата от данни",
        "lockdbtext": "Заключването на базата от данни ще попречи на всички потребители да редактират страници, да сменят своите настройки, да редактират своите списъци за наблюдение и на всички други техни действия, изискващи промени в базата данни.\nПотвърдете, че искате точно това и ще отключите базата от данни, когато привършите с работата по поддръжката.",
        "allmessagesdefault": "Текст по подразбиране",
        "allmessagescurrent": "Текущ текст",
        "allmessagestext": "Тази страница съдържа списък на системните съобщения от именното пространство „МедияУики“.\nПосетете [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] и [https://translatewiki.net translatewiki.net], ако желаете да допринесете за общото превеждане на софтуера МедияУики.",
-       "allmessagesnotsupportedDB": "Тази страница не може да бъде използвана, тъй като е изключена възможността <strong>$wgUseDatabaseMessages</strong>",
+       "allmessages-not-supported-database": "Тази страница не може да бъде използвана, тъй като е изключена възможността <strong>$wgUseDatabaseMessages</strong>",
        "allmessages-filter-legend": "Филтър",
        "allmessages-filter": "Филтриране по ниво на персонализация:",
        "allmessages-filter-unmodified": "Непроменени",
        "expand_templates_input": "Входящ уикитекст:",
        "expand_templates_output": "Резултат",
        "expand_templates_xml_output": "Изход на XML",
+       "expand_templates_html_output": "Суров HTML изход",
        "expand_templates_ok": "ОК",
        "expand_templates_remove_comments": "Премахване на коментари",
        "expand_templates_remove_nowiki": "Потискане на елементите <nowiki> в резултата",
        "pagelang-reason": "Причина",
        "pagelang-submit": "Изпращане",
        "pagelang-nonexistent-page": "Страницата $1 не съществува.",
+       "pagelang-unchanged-language": "Страницата $1 вече е със зададен език $2.",
+       "pagelang-unchanged-language-default": "Страницата $1 вече е със зададен език, съвпадащ с езика по подразбиране за това уики.",
+       "pagelang-db-failed": "Базата данни не успя да смени езика на страницата.",
        "right-pagelang": "Промяна езика на страница",
        "action-pagelang": "промяна езика на страницата",
        "log-name-pagelang": "Дневник на езиковите промени",
        "mediastatistics-header-multimedia": "Мултимедия",
        "mediastatistics-header-office": "Офис",
        "mediastatistics-header-total": "Всички файлове",
+       "json-error-state-mismatch": "Невалиден или грешно структуриран JSON",
+       "json-error-ctrl-char": "Грешка в контролния знак. Вероятно е неправилно кодиран",
        "json-error-syntax": "Синтактична грешка",
        "headline-anchor-title": "Препратка към този раздел",
        "special-characters-group-latin": "Латиница",
        "mw-widgets-abandonedit-discard": "Отказване на редакциите",
        "mw-widgets-abandonedit-keep": "Продължаване на редактирането",
        "mw-widgets-abandonedit-title": "Сигурни ли сте?",
-       "mw-widgets-dateinput-no-date": "Ð\94аÑ\82аÑ\82а Ð½Ðµ Ðµ Ð¸Ð·Ð±Ñ\80ана",
+       "mw-widgets-dateinput-no-date": "Ð\9dе Ðµ Ð¸Ð·Ð±Ñ\80ана Ð´Ð°Ñ\82а",
        "mw-widgets-dateinput-placeholder-day": "ГГГГ-ММ-ДД",
        "mw-widgets-dateinput-placeholder-month": "ГГГГ-ММ",
        "mw-widgets-mediasearch-input-placeholder": "Търсене на мултимедия",
        "mw-widgets-titleinput-description-redirect": "пренасочване към $1",
        "mw-widgets-categoryselector-add-category-placeholder": "Добавяне на категория...",
        "mw-widgets-usersmultiselect-placeholder": "Добавяне на още...",
+       "mw-widgets-titlesmultiselect-placeholder": "Добавяне на още...",
        "date-range-from": "От дата:",
        "date-range-to": "До дата:",
        "sessionprovider-generic": "$1 сесии",
        "log-action-filter-protect-move_prot": "Преместване на защитата",
        "log-action-filter-rights-rights": "Ръчна промяна",
        "log-action-filter-rights-autopromote": "Автоматична промяна",
+       "log-action-filter-suppress-event": "Потискане на дневника",
+       "log-action-filter-suppress-revision": "Потискане на версията",
+       "log-action-filter-suppress-delete": "Потискане на страницата",
+       "log-action-filter-suppress-block": "Потискане на потребителя чрез блокиране",
+       "log-action-filter-suppress-reblock": "Потискане на потребителя чрез повторно блокиране",
        "log-action-filter-upload-upload": "Ново качване",
        "log-action-filter-upload-overwrite": "Повторно качване",
        "log-action-filter-upload-revert": "Връщане",
index 2adfae0..0eaba93 100644 (file)
        "minoreditletter": "جز",
        "newpageletter": "نوک",
        "boteditletter": "ر",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|کار زوروک}} دیستینوک]",
        "rc-change-size-new": "$1 {{PLURAL:$1|بایٹ}} پد شه تغیرا",
        "newsectionsummary": "/* $1 */ نوکین بخش",
        "rc-enhanced-expand": "جزئیات ئی نشان داتین",
        "invalid-chunk-offset": "قطعه ئی ناموتبرین جابجايی",
        "img-auth-accessdenied": "دسترسی ئی منشا",
        "img-auth-badtitle": "یک مجازین ئینوانی جۆڑ کورتین ئی امکان شه «$1» ئا وجود نداریت.",
-       "img-auth-nologinnWL": "شما لوگین نه بوته ایت و بئ  «$1» ئی سپیتین لیست ئی تا وێت.",
        "img-auth-nofile": "«$1» ئی فایل موجود نه اینت.",
        "img-auth-isdir": "شما کوشش کورته ئیت که بئ «$1» ئی شاخه ئا دسترسی ودی بکنیت.\nتانا په فایل ئا دسترسی جایز اینت.",
        "img-auth-streaming": "بئ حال جاری کورتینی «$1» ئا.",
index 1e3c996..54a8edf 100644 (file)
        "rcfilters-filter-categorization-description": "श्रेणिन में जोड़ल भा बिलगावल पन्ना सभ के रेकार्ड।",
        "rcfilters-filter-logactions-label": "लॉग में दर्ज काम",
        "rcfilters-filter-logactions-description": "प्रबंधक एक्शन, खाता निर्माण, पन्ना हटावल, अपलोड...",
-       "rcfilters-filtergroup-lastRevision": "सबसे नया बदलाव",
+       "rcfilters-filtergroup-lastrevision": "सबसे नया बदलाव",
        "rcfilters-filter-lastrevision-label": "सबसे नया बदलाव",
        "rcnotefrom": "<strong>$3, $4</strong> से (<strong>$1</strong> तक ले के) {{PLURAL:$5|बदलाव|बदलाव सभ}} नीचे दिहल गइल बा।",
        "rclistfrom": "$2, $3 से शुरु होखे वाला नया बदलाव देखावल जाय",
        "minoreditletter": "छो",
        "newpageletter": "न",
        "boteditletter": "बॉ",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|प्रयोगकर्ता|प्रयोगकर्ता लोग}} के धियानसूची में बा]",
        "rc-change-size-new": "बदलाव के बाद $1 {{PLURAL:$1|बाइट|बाइट्स}}",
        "newsectionsummary": "/* $1 */ नया खंड",
        "rc-enhanced-expand": "डिटेल देखावल जाय",
index df13d46..7fd8b98 100644 (file)
@@ -9,33 +9,37 @@
                        "아라",
                        "Macofe",
                        "Fitoschido",
-                       "Vlad5250"
+                       "Vlad5250",
+                       "Mnam23"
                ]
        },
        "tog-underline": "Garisi di bawah tautan",
        "tog-hideminor": "Sungkupakan babakan sapalih dalam paubahan pahanyarnya",
        "tog-hidepatrolled": "Sungkupakan babakan taawasi dalam paubahan pahanyarnya",
        "tog-newpageshidepatrolled": "Sungkupakan tungkaran nang diitihi matan daptar tungkaran hanyar",
+       "tog-hidecategorization": "Patak tumbungnya tungkaran",
        "tog-extendwatchlist": "Singkaiakan daptar itihan hagan manampaiakan samunyaan paubahan, kada nang hanyar haja.",
-       "tog-usenewrc": "Purukakan panampaian paubahan pahanyarnya tingkat tinggi (parlu ada JavaScript)",
+       "tog-usenewrc": "Garumbungakan babakan di tampilan paubahan pahanyarnya wan daptar itihan badasar tungkaran",
        "tog-numberheadings": "Bari numur judul utumatis",
-       "tog-editondblclick": "Babak tutungkaran wan klik ganda (parlu ada JavaScript)",
-       "tog-editsectiononrightclick": "Kawa'akan mambabak sub-hagian lawan mang-klik kanan pada judul hagian (parlu ada JavaScript)",
+       "tog-editondblclick": "Babak tungkaran wan dua kali klik",
+       "tog-editsectiononrightclick": "Kawa'akan mambabak sub-hagian lawan mang-klik kanan pada judul hagian",
        "tog-watchcreations": "Tambahi tungkaran nang ulun ulah ka daptar itihan",
        "tog-watchdefault": "Tambahi tungkaran nang ulun babak ka daptar itihan ulun",
        "tog-watchmoves": "Tambahi tungkaran nang ulun pindah ka daptar itihan ulun",
        "tog-watchdeletion": "Tambahi tungkaran nang ulun hapus ka daptar itihan ulun",
+       "tog-watchuploads": "Tambahi barakas hanyar nang ulun unggah ka daptar itihan ulun",
+       "tog-watchrollback": "Tambahi tungkaran nang suah ulun bulikakan ka dalam daptar itihan ulun",
        "tog-minordefault": "Tandai samunyaan babakan sawagai babakan sapalih sacara baku",
        "tog-previewontop": "Tampaiakan titilikan sabalum kutak babak",
        "tog-previewonfirst": "Tampaiakan titilikan pada babakan panambaian",
        "tog-enotifwatchlistpages": "Kirimi ulun sur-él amun sabuting tungkaran dalam daptar itihan ulun baubah",
        "tog-enotifusertalkpages": "Surili ulun amun tungkaran pamandiran ulun baubah",
-       "tog-enotifminoredits": "Kirimi ulun sur-él jua amun ada babakan sapalih matan tungkaran-tungkaran",
+       "tog-enotifminoredits": "Kirimi ulun sur-él jua amun ada babakan sapalih",
        "tog-enotifrevealaddr": "Tampaiakan alamat sur-él ulun pada sur-él pamadahan",
        "tog-shownumberswatching": "Tampaiakan barapa pamakai nang maitihi",
        "tog-oldsig": "Tandateken nang sudah ada:",
        "tog-fancysig": "Tapsirakan tandatangan sawagai naskah wiki (kada batautan utumatis)",
-       "tog-uselivepreview": "Puruk titilikan langsung (parlu ada JavaScript) (cacubaan)",
+       "tog-uselivepreview": "Tampaiakan pratayang tanpa mamuat baasa tungkaran",
        "tog-forceeditsummary": "Ingatakan ulun wayah babuat sabuting kasimpulan babakan puang",
        "tog-watchlisthideown": "Sungkupakan babakan ulun di daptar itihan",
        "tog-watchlisthidebots": "Sungkupakan babakan bot di daptar itihan",
        "tog-ccmeonemails": "Surili ulun salinan suril nang ulun kirim ka pamakai lain",
        "tog-diffonly": "Kada usah manampaiakan isi tungkaran di bawah balain",
        "tog-showhiddencats": "Tampaiakan tutumbung tasungkup",
-       "tog-norollbackdiff": "Kada usah manampaiakan lainan imbah mambulikakan",
+       "tog-norollbackdiff": "Jangan tampaiakan lainan imbah mambulikakan",
        "tog-useeditwarning": "Ingatakan ulun pabila maninggalakan tungkaran pambabakan sabalum manyimpan parubahan",
        "underline-always": "Tarus",
        "underline-never": "Kada suah",
-       "underline-default": "Default Panjalajahan web",
+       "underline-default": "Kulimbit atawa panjalajah bawaan",
        "editfont-style": "Babak wilayah gaya tulisan",
        "editfont-monospace": "Tulisan Monospace",
        "editfont-sansserif": "Tulisan Sans-serif",
        "oct": "Ukt",
        "nov": "Nup",
        "dec": "Dis",
-       "pagecategories": "{{PLURAL:$1|Tumbung|Tutumbung}}",
-       "category_header": "Tutungkaran dalam tumbung ''$1''",
+       "pagecategories": "{{PLURAL:$1|Tumbung}}",
+       "category_header": "Tungkaran dalam tumbung \"$1\"",
        "subcategories": "Sub-tumbung",
-       "category-media-header": "Média dalam tumbung \"$1\"",
-       "category-empty": "\"Kada tadapat artikal maupun média dalam tumbung ini.\"",
-       "hidden-categories": "{{PLURAL:$1|Tumbung tasungkup|Tutumbung tasungkup}}",
+       "category-media-header": "Média dalam pilah \"$1\"",
+       "category-empty": "\"Kada tahaga tulisan maupun média dalam pilah ngini.\"",
+       "hidden-categories": "{{PLURAL:$1|Tumbung tapatak}}",
        "hidden-category-category": "Tumbung tasungkup",
-       "category-subcat-count": "{{PLURAL:$2|Tumbung ngini baisi asa sub-tumbung barikut.|Tumbung ngini baisi {{PLURAL:$1|sub-tumbung|$1 sub-tutumbung}} barikut, matan sabarataan $2.}}",
+       "category-subcat-count": "{{PLURAL:$2|Tumbung ngini baisi asa sub-tumbung nangkaya ngini.|Pilih ngini baisi {{PLURAL:$1|sub-tumbung|$1 sub-tumbung}}, matan sabarataan $2.}}",
        "category-subcat-count-limited": "Tumbung ini baisi {{PLURAL:$1|sub-tumbung|$1 sub-tutumbung}} barikut.",
-       "category-article-count": "{{PLURAL:$2|Tumbung ni baisi asa tungkaran barikut haja.|Tutumbung ngini baisi {{PLURAL:$1|tungkaran|$1 tutungkaran}}, matan $2 sabarataan.}}",
+       "category-article-count": "{{PLURAL:$2|Tumbung ngini baisi {{PLURAL:$1|$1 tungkaran}}, tumatan jumlah $2.}}",
        "category-article-count-limited": "Tumbung ini baisi {{PLURAL:$1|asa tungkaran|$1 tutungkaran}} barikut.",
-       "category-file-count": "{{PLURAL:$2|Tumbung ngini wastu baisi satu barakas barikut.|Tumbung ngini baisi {{PLURAL:$1|barakas|$1 babarakas}} barikut, matan $2 sabarataan.}}",
+       "category-file-count": "{{PLURAL:$2|Pilah ngini baisi {{PLURAL:$1|$1 barakas}}, matan jumlah $2.}}",
        "category-file-count-limited": "Tumbung ngini baisi {{PLURAL:$1|barakas|$1 barakas}} barikut.",
        "listingcontinuesabbrev": "samb.",
        "index-category": "Tungkaran tasusun bapadalakan kata",
-       "noindex-category": "Tungkaran kada tasusun bapadalakan kata",
+       "noindex-category": "Tungkaran nang diindéks",
        "broken-file-category": "Tutungkaran lawan tatautan barakas pagat",
        "about": "Pasal",
        "article": "Tungkaran isi",
        "newwindow": "(buka di lalungkang hanyar)",
        "cancel": "Walangi",
        "moredotdotdot": "Lainnya...",
-       "morenotlisted": "Salanjutnya...",
-       "mypage": "Tungkaran ulun",
-       "mytalk": "Pamandiran ulun",
-       "anontalk": "Pamandiran hagan alamat IP ini",
+       "morenotlisted": "Daptar ngini mungkin kada langkap",
+       "mypage": "Tungkaran",
+       "mytalk": "Pamandiran",
+       "anontalk": "Pamandiran",
        "navigation": "Napigasi",
        "and": "&#32;wan",
        "faq": "FAQ",
        "returnto": "Bulik ka $1.",
        "tagline": "Matan {{SITENAME}}",
        "help": "Patulung",
-       "search": "Gagai",
-       "searchbutton": "Gagai",
+       "search": "Pangikihan",
+       "searchbutton": "Kikih",
        "go": "Tulak",
        "searcharticle": "Tulak",
-       "history": "Tungkaran halam",
-       "history_short": "Tungkaran halam",
+       "history": "Sajarah tungkaran",
+       "history_short": "Sajarah",
+       "history_small": "riwayat",
        "updatedmarker": "Dihanyari tumatan ilangan pauncitan ulun",
        "printableversion": "Nang kawa dicitak",
        "permalink": "Tautan tatap",
        "print": "Citak",
-       "view": "Tiringi",
+       "view": "Baca",
+       "view-foreign": "Itihi di $1",
        "edit": "Babak",
+       "edit-local": "Babak pamaparan lukal",
        "create": "Ulah",
+       "create-local": "Tambah pamaparan lukal",
        "delete": "Hapus",
-       "undelete_short": "Walang mahapus {{PLURAL:$1|asa babakan|$1 bababakan}}",
+       "undelete_short": "Pasah hapus {{PLURAL:$1|$1 babakan}}",
        "viewdeleted_short": "Tiringi {{PLURAL:$1|asa babakan tahapus|$1 bababakan tahapus}}",
        "protect": "Lindungi",
        "protect_change": "ubah",
        "unprotect": "Palindungan",
        "newpage": "Tungkaran hanyar",
-       "talkpagelinktext": "Pandir",
+       "talkpagelinktext": "pandir",
        "specialpage": "Tungkaran istimiwa",
-       "personaltools": "Pakakas surang",
+       "personaltools": "Pakakas saurang",
        "talk": "Pamandiran",
-       "views": "Titiringan",
-       "toolbox": "Wadah pakakas",
+       "views": "Tampilan",
+       "toolbox": "Pakakas",
        "imagepage": "Tiringi tungkaran barakas",
        "mediawikipage": "Tiringi tungkaran pasan sistim",
        "templatepage": "Tiringi tungkaran citakan",
        "otherlanguages": "Dalam basa lain",
        "redirectedfrom": "(Diugahakan matan $1)",
        "redirectpagesub": "Tungkaran paugahan",
-       "lastmodifiedat": "Tungkaran ngini pauncitnya diubah pada $1, $2.",
+       "redirectto": "Maugahakan ka:",
+       "lastmodifiedat": "Halaman ngini pahabisan diubah wayah $1, pukul $2.",
        "viewcount": "Tungkaran ini sudah diungkai {{PLURAL:$1|kali|$1 kali}}.",
        "protectedpage": "Tungkaran nang dilindungi",
-       "jumpto": "Malacung ka",
+       "jumpto": "Malacung ka:",
        "jumptonavigation": "napigasi",
        "jumptosearch": "gagai",
        "view-pool-error": "Ampuni, server lagi limpuar kabaratan wayah ini.\nKabanyakan pamakai nang handak maniringi tungkaran ini.\nMuhun hadangi ha' sapandang sabalum Pian cubai pulang maungkai tungkaran ini.\n\n$1",
        "aboutpage": "Project:Pasal",
        "copyright": "Isi tasadia sasuai lawan $1.",
        "copyrightpage": "{{ns:project}}:Hak cipta",
-       "currentevents": "Kajadian wayahini",
-       "currentevents-url": "Project:Kajadian wayahini",
+       "currentevents": "Garamaan",
+       "currentevents-url": "Project:Garamaan",
        "disclaimers": "Panyangkalan",
        "disclaimerpage": "Project:Panyangkalan umum",
        "edithelp": "Patulung mambabak",
+       "helppage-top-gethelp": "Patulung",
        "mainpage": "Tungkaran Tatambaian",
-       "mainpage-description": "Tungkaran Tatambaian",
+       "mainpage-description": "Tungkaran tatambaian",
        "policy-url": "Project:Kaaripan",
-       "portal": "Saképéng bubuhan",
-       "portal-url": "Project:Saképéng bubuhan",
+       "portal": "Lawang bubuhan",
+       "portal-url": "Project:Lawang bubuhan",
        "privacy": "Kaaripan paribadi",
        "privacypage": "Project:Kaaripan paribadi",
        "badaccess": "Parijinan tasalah",
        "youhavenewmessages": "Pian baisi $1 ($2)",
        "youhavenewmessagesfromusers": "Pian baisi $1 matan {{PLURAL:$3|$3 pamakai lain}} ($2).",
        "youhavenewmessagesmanyusers": "Pian baisi $1 matan pamakai lain ($2).",
-       "newmessageslinkplural": "{{PLURAL:$1|pasan hanyar}}",
-       "newmessagesdifflinkplural": "{{PLURAL:$1|paubahan}} pahabisnya",
+       "newmessageslinkplural": "{{PLURAL:$1|sabuting pasan hanyar|999=pasan hanyar}}",
+       "newmessagesdifflinkplural": "{{PLURAL:$1|paubahan|999=paubahan}} pauncitnya",
        "youhavenewmessagesmulti": "Pian baisi pasan hanyar dalam $1",
        "editsection": "babak",
        "editold": "babak",
        "viewsourceold": "tiringi asal mulanya",
        "editlink": "babak",
-       "viewsourcelink": "tiringi asal mulanya",
+       "viewsourcelink": "tiring asal mulanya",
        "editsectionhint": "Babak hagian: $1",
        "toc": "Isi",
        "showtoc": "tampaiakan",
        "site-atom-feed": "Kitihan Atum $1",
        "page-rss-feed": "Kitihan RSS ''$1''",
        "page-atom-feed": "Kitihan Atum ''$1''",
-       "red-link-title": "$1 (tungkaran baluman ada)",
+       "red-link-title": "$1 (halaman baluman ada)",
        "sort-descending": "Surtir baturun",
        "sort-ascending": "Surtir banaik",
        "nstab-main": "Tungkaran",
        "nstab-template": "Citakan",
        "nstab-help": "Patulung",
        "nstab-category": "Tumbung",
+       "mainpage-nstab": "Tungkaran tatambaian",
        "nosuchaction": "Kadada palakuan nangkaitu",
        "nosuchactiontext": "Tindakan nang diminta URL kada sah.\nPian tagasnya salah katik URL, atawa maumpati sabuting tautan nang kada bujur.\nNgini jua bisa ai ada bug di parangkat lunak nang dipuruk {{SITENAME}}.",
        "nosuchspecialpage": "Kadada tungkaran istimiwa nangitu",
        "laggedslavemode": "'''Paringatan:''' Tungkaran ngini tagasnya kada baisi paubahan pahanyarnya.",
        "readonly": "Basisdata tasunduk",
        "enterlockreason": "Buati sabuting alasan manyunduk, tamasuk jua wayah kapan handak dibuka pulang sundukannya.",
-       "readonlytext": "Basisdata lagi disunduk hagan masukan hanyar wan paubahan lain, pinanya pang lagi ada jadwal paharaguan basis data, limbah ngini akan babulik nangkaya biasa.\n\nPambakal nang manyunduk mamadahi nangkaini: $1",
+       "readonlytext": "Basisdata lagi disunduk gasan masukan hanyar wan paubahan lain, pinanya pang lagi ada jadwal paharaguan basis data, limbah ngini akan babulik nangkaya biasa.\n\nPambakal nang manyunduk mamadahi nangkaini: $1",
        "missing-article": "Basisdata kada ulihan manggagai kata matan tungkaran nang saharusnya ada, bangaran \"$1\" $2.\n\nNangkaini biasanya dimargakan tautan lawas ka sabuting tungkaran nang halamnya sudah dihapus.\n\nMunnya lainan ngini pasalnya, Pian mungkin batamu bug dalam perangkat lunak.\nSilakan lapurakan ngini ka saurang [[Special:ListUsers/sysop|pambakal]], ulah catatan URL nang ditulaki",
        "missingarticle-rev": "(ralatan#: $1)",
        "missingarticle-diff": "(Lain: $1, $2)",
        "cannotdelete-title": "Kada kawa mahapus tungkaran \"$1\"",
        "delete-hook-aborted": "Pahapusan diwalangakan ulih kait parser.\nKadada katarangan.",
        "badtitle": "Judul buruk",
-       "badtitletext": "Judul tungkaran nang diminta kada sah, kada baisi, atawa kada pasnya tautan judul antar-basa atawa antar-wiki.\nNangini kawa baisi satu atawa labih hurup nang saharusnya kadada di judul.",
+       "badtitletext": "Judul tungkaran nang diminta kada sah, kada baisi, atawa kada pasnya tautan judul antar-basa atawa antar-wiki.\nNangini kawa baisi sabuting atawa labih hurup nang saharusnya kadada di judul.",
        "perfcached": "Data barikut adalah timbuluk wan pina kada mutakhir. A maximum of {{PLURAL:$1|one result is|$1 results are}} available in the cache.",
        "perfcachedts": "Data nang dudi ni adalah timbuluk, wan tauncit dihahanyari pada $1. A maximum of {{PLURAL:$4|one result is|$4 results are}} available in the cache.",
        "querypage-no-updates": "Pamugaan matan tungkaran ngini rahat dipajahkan. Data nang ada di sia wayahini kada akan dimuat ulang.",
-       "viewsource": "Tiringi asal mulanya",
+       "viewsource": "Janaki asal mulanya",
        "viewsource-title": "Tiringi asalmula matan $1",
        "actionthrottled": "Kalakuan dikiripi",
-       "actionthrottledtext": "Sawagai sabuting takaran anti-spam, Pian dibabatasi hagan balalaku kababanyakan dalam parhatan handap, wan Pian sudah limpuari batasan ngini.\nMuhun cubai pulang dalam babarapa minit.",
-       "protectedpagetext": "Tungkaran ngini sudah dilindungi hagan mancagah babakan.",
-       "viewsourcetext": "Pian kawa maniringi wan manyalin asal mula tungkaran ngini:",
-       "viewyourtext": "Pian kawa maniringi wan salain asalmula matan '''babakan pian''' ka tungkaran ngini:",
-       "protectedinterface": "Tungkaran ini manyadiakan naskah antarmuha gasan parangkat lunak, wan dilindungi hagan mancagah tasalah puruk.",
+       "actionthrottledtext": "Pian dibatasi gasan manggawi tindakan ngini talalu banyak dalam waktu handap, wan Pian sudah limpua batas nang dibarii. Silahkan cuba baasa imbah babarapa manit.",
+       "protectedpagetext": "Tungkaran ngini sudah disunduk gasan mancagah babakan.",
+       "viewsourcetext": "Pian kawa maniringi wan manyalin asal-mula tungkaran ngini.",
+       "viewyourtext": "Pian kawa maniringi wan manyalin asalmula matan '''babakan pian''' ka tungkaran ngini:",
+       "protectedinterface": "Tungkaran ngini manyadiakan naskah antarmuha gasan parangkat lunak, wan dilindungi tahadap panyalahpakaian. Gasan manambah atawa mambabak tarjamahan pada sabarataan wiki, muhun pakai [https://translatewiki.net translatewiki.net], pruyik palukalan MediaWiki.",
        "editinginterface": "'''Paringatan:''' Pian mambabak sabuting tungkaran nang dipuruk hagan manyadiakan naskah antarmuha gasan parangkat lunak.\nPaubahan ka tungkaran ngini akan bapangaruh matan tampaian antarmuha gasan pamakai lain.\nGasan tarjamahan, muhun pakai [https://translatewiki.net/wiki/Main_Page?setlang=bjn translatewiki.net], rangka gawian palokalan MediaWiki.",
-       "cascadeprotected": "Tungkaran ini sudah dilindungi matan pambabakan, marga nangini tamasuk dalam {{PLURAL:$1|tungkaran|tutungkaran}} dudi nang dilindungi \"barénténg\": $2",
+       "cascadeprotected": "Tungkaran ini sudah dilindungi matan pambabakan, maraga nangini tamasuk dalam {{PLURAL:$1|tungkaran|tutungkaran}} dudi nang dilindungi \"barénténg\": $2",
        "namespaceprotected": "Pian kada baisi ijin hagan mambabak tutungkaran dalam ngaran kamar '''$1'''.",
        "customcssprotected": "Pian kada baisi ijin mambabak tungkaran CSS ngini, karana ngini baisi setelan paribadi pamakai lain.",
        "customjsprotected": "Pian kada baisi ijin mambabak tungkaran JavaScript ngini, karana ngini baisi setelan paribadi pamakai lain.",
        "ns-specialprotected": "Tungkaran istimiwa kada kawa dibabak.",
        "titleprotected": "Judul ngini dilindungi matan paulahan ulih [[User:$1|$1]].\nAlasan nang dibariakan adalah <em>$2</em>.",
-       "filereadonlyerror": "Kada kawa mamudipikasi data \"$1\" marga repositori data \"$2\" ada di modus read-only.\n\nAdministrator nang takunci nintu manawarakan panjalasan: \"$3\".",
+       "filereadonlyerror": "Kada kawa mamudipikasi barakas \"$1\" maraga barakas repositori \"$2\" ada di modus baca-wara.\n\nPambakal nang manyunduknya mambarii panjalasan: \"$3\".",
        "invalidtitle-knownnamespace": "Judul nang kada sah lawan ruang-ngaran \"$2\" wan teks \"$3\"",
        "invalidtitle-unknownnamespace": "Judul nang kada sah lawan numur ruang ngaran kada dikatahui $1 wan teks \"$2\"",
        "exception-nologin": "Balum babuat log",
-       "exception-nologin-text": "Tungkaran atawa tindakan ngini maharusakan Pian babuat log di wiki ngini.",
+       "exception-nologin-text": "Silahkan babuat log gasan kawa maaksis tungkaran atau gawian ngini",
        "virus-badscanner": "Konpigurasi buruk: pamindai virus kada dipinandui: ''$1''",
        "virus-scanfailed": "Pamindaian gagal (kudi $1)",
        "virus-unknownscanner": "Antivirus kada dipinandui:",
-       "logouttext": "'''Pian parhatan ni sudah kaluar log.'''\n\nPian kawa manyambung hagan mangguna'akan {{SITENAME}} kada bangaran, atawa Pian kawa <span class='plainlinks'>[$1 babuat log pulang]</span> sawagai pamakai nang sama atawa sawagai pamakai balain.\nCatatan bahwasa babarapa tungkaran pinanya masih ha tarus manampaiakan Pian masih babuat log, sampai Pian mahabisakan timbuluk panjalajah web Pian.",
+       "logouttext": "<strong>Pian wayahini kaluar log.</strong>\n\n\nIngatakan bahwa babarapa tungkaran mungkin masih manampaiakan pian kaya masih babuat log, sampai pian mambarasihi singgahan panjalajah pian.",
        "welcomeuser": "Salamat datang,  $1 !",
-       "welcomecreation-msg": "==Salamat datang, $1!==\nAkun Pian sudah diulah.\nJangan kada ingat hagan maubah [[Special:Preferences|kakatujuan {{SITENAME}}]] Pian.",
+       "welcomecreation-msg": "Akun pian sudah diulah.\nPian kawa maubah [[Special:Preferences|preperensi]] {{SITENAME}} amun pian handak.",
        "yourname": "Ngaran pamakai:",
+       "userlogin-yourname": "Ngaran pamakai",
+       "userlogin-yourname-ph": "Masukakan ngaran pamakai Pian",
        "yourpassword": "Katasunduk:",
+       "userlogin-yourpassword": "Katasunduk",
+       "userlogin-yourpassword-ph": "Masukakan kata sandi",
+       "createacct-yourpassword-ph": "Masukakan katasunduk",
        "yourpasswordagain": "Katik pulang katasunduk:",
+       "createacct-yourpasswordagain": "Pastiakan katasunduk",
+       "createacct-yourpasswordagain-ph": "Masukakan pulang katasunduk",
+       "userlogin-remembermypassword": "Biarakan ulun tatap babuat",
        "yourdomainname": "Domain Pian:",
        "password-change-forbidden": "Pian kada kawa ma-ubah kata sunduk pada wiki ngini.",
        "externaldberror": "Ada kasalahan apakah kacucukan basis data atawa Pian kada bulih mamutakhirakan akun luar.",
-       "login": "Babuat",
+       "login": "Babuat log",
        "nav-login-createaccount": "Babuat log / ulah akun",
        "logout": "Kaluar",
        "userlogout": "Kaluar",
        "notloggedin": "Balum babuat log",
+       "userlogin-noaccount": "Balum baisi akun?",
+       "userlogin-joinproject": "Gabung {{SITENAME}}",
        "createaccount": "Ulah akun",
-       "createaccountmail": "Malalui suril",
+       "userlogin-resetpassword-link": "Lupa kata sandi?",
+       "userlogin-helplink2": "Patulung babuat log",
+       "createacct-emailoptional": "Alamat surél/email (bagusnya diisi)",
+       "createacct-email-ph": "Masukakan alamat email Pian",
+       "createaccountmail": "Pakai kata sunduk acak pahadangan wan kirim ka surèl nang dikahandaki",
+       "createacct-submit": "Ulah akun Pian",
+       "createacct-benefit-heading": "{{SITENAME}} diulah ulih urang-urang nangkaya Pian.",
+       "createacct-benefit-body1": "{{PLURAL:$1|babakan}}",
+       "createacct-benefit-body2": "{{PLURAL:$1|tungkaran}}",
+       "createacct-benefit-body3": "{{PLURAL:$1|sumbangan}} pahabisnya",
        "badretype": "Katasunduk nang Pian buati kada pas.",
        "userexists": "Ngaran pamakai nang dibuati hudah dipuruk urang lain.\nMuhun pilih sabuting ngaran lain.",
        "loginerror": "Kasalahan babuat log",
        "nocookieslogin": "{{SITENAME}} mangguna'akan ''cookies'' hagan pamakai babuat log.\n''Cookies'' Pian lagi kada kawa.\nMuhun kawa'akan nang itu wan cubai pulang.",
        "nocookiesfornew": "Akun pamakai kada ta'ulah, sualnya kami kada kawa mamastiakan asal mula.\nYakinakan Pian hudah mangkawa-akan cookies, muat pulang tungkaran naya wan cubai ja lagi.",
        "noname": "Ngaran pamakai nang Pian ajuakan kada sah.",
-       "loginsuccesstitle": "Kulihan babuat log",
+       "loginsuccesstitle": "Kawa babuat log",
        "loginsuccess": "'''Pian parhatan ni babuat log dalam {{SITENAME}} sawagai \"$1\".'''",
-       "nosuchuser": "Kadada pamakai bangaran \"$1\".\nNgaran pamakai adalah kasus marinci.\nLihati pulang ijaan Pian, atawa [[Special:CreateAccount|ulah sabuting akun hanyar]]",
+       "nosuchuser": "Kadada pamakai nang bangaran \"$1\".\nNgaran pamakai adalah kasus marinci.\nLihati pulang hijaan Pian, atawa [[Special:CreateAccount|ulah akun hanyar]]",
        "nosuchusershort": "Kadada pamakai bangaran \"$1\".\nLihati pulang ijaan Pian.",
        "nouserspecified": "Pian harus ma'ajuakan sabuting ngaran pamakai.",
        "login-userblocked": "Pamakai naya diblukir. Babuat log kada dibulihakan.",
        "passwordtooshort": "Kata sunduk musti paling sadikit {{PLURAL:$1|1 karaktir|$1 karaktir}}.",
        "password-name-match": "Kata sunduk Pian musti babida lawan ngaran pamakai Pian.",
        "password-login-forbidden": "Mamakai ngaran wan katasunduk nangini hudah ditangati.",
-       "mailmypassword": "Kirimi kata sunduk hanyar",
+       "mailmypassword": "Bulikakan katasunduk",
        "passwordremindertitle": "Kata sunduk pahadangan gasan {{SITENAME}}",
-       "passwordremindertext": "Ada urang (pinanya Pian, matan alamat IP $1) maminta sabuting katasunduk hanyar gasan {{SITENAME}} ($4). Sabuting katasunduk pahadangan gasan pamakai \"$2\" hudah diulah wan disetel ka \"$3\". Amun bujur Pian nang maminta, Pian parlu babuat log wan mamilih katasunduk hanyar wayah ni jua. Katasunduk pahadangan Pian akan kadaluarsa dalam {{PLURAL:$5|asa hari|$5 hari}}.\n\nAmun urang lain nang maminta ngini, atawa amun Pian sudah paingatan awan katasunduk Pian, wan Pian kada handak maubahnya, Pian kawa kada mahuwal pasan ngini wan manyambung mamakai katasunduk lawas Pian.",
+       "passwordremindertext": "Ada urang (pinanya Pian, matan alamat IP $1) maminta sabuting katasunduk hanyar gasan {{SITENAME}} ($4). Sabuting katasunduk pahadangan gasan pamakai \"$2\" hudah diulah wan disetel ka \"$3\". Amun bujur Pian nang maminta, Pian parlu babuat log wan mamilih katasunduk hanyar wayahini jua. Katasunduk pahadangan Pian pacangan kadaluarsa dalam {{PLURAL:$5|sahari|$5 hari}}.\n\nAmun urang lain nang maminta ngini, atawa amun Pian sudah ingat lawan katasunduk Pian, wan Pian kada handak maubahnya, Pian kawa kada maharung pasan ngini wan manyambung mamakai katasunduk lawas Pian.",
        "noemail": "Kadada alamat suril tarakam gasan pamakai \"$1\".",
        "noemailcreate": "Pian parlu manyadiakan sabuting alamat suril nang sah",
        "passwordsent": "Sabuting kata sunduk hanyar sudah dikirim ka suril tadaptar gasan \"$1\".\nMuhun babuat log pulang habis Pian manarima nangini.",
-       "blocked-mailpassword": "Alamat IP Pian diblukir hagan mambabak, wan kada dibulihakan mamakai pungsi pamulihan kata sunduk hagan mancagah salah puruk.",
-       "eauthentsent": "Sabuting suril payakinan hudah dikirim ka alamat suril.\nSabalum ada suril lain nang takirim ka akun, Pian akan parlu maumpati anjuran dalam suril nangitu, hagan mayakinakan bahwasanya akun nangitu bujur-bujur ampun Pian.",
+       "blocked-mailpassword": "Alamat IP Pian diblukir matan pambabakan. Gasan mancagah panyalahpakaian, pian kada dibulihakan gasan mambulikakan kata sunduk pian matan alamat IP ngini.",
+       "eauthentsent": "Sabuting suril gasan payakinan sudah dikirim ka alamat suril.\nSabalum ada suril lain nang takirim ka akun, Pian harus maumpati anjuran dalam suril nangitu, gasan mayakinakan bahwasanya akun nangitu bujur-bujur ampun Pian.",
        "throttled-mailpassword": "Sabuting pangingat kata sunduk hudah takirim, dalam {{PLURAL:$1|jam|$1 jam}} pauncitnya. Hagan mancagah salah puruk, asa pangingat kata sunduk haja nang dikirim saban {{PLURAL:$1|jam|$1 jam}}.",
        "mailerror": "Kasalahan pangiriman suril: $1",
-       "acct_creation_throttle_hit": "Pa'ilang wiki nangini mamuruk alamat IP Pian hudah maulah {{PLURAL:$1|1 akun|$1 akun}} dalam asa harian ini, dimana nangitu jumlah paling banyak nang diijinakan. Sawagai hasilnya, pa'ilang awan alamat IP nangini kada kawa maulah akun pulang gasan pahadangan.",
-       "emailauthenticated": "Alamat suril Pian rasuk pada  $2, $3",
-       "emailnotauthenticated": "Alamat suril Pian baluman dirasukakan.\nKadada suril nang akan dikirim maumpati pitur.",
+       "acct_creation_throttle_hit": "Pa'ilang wiki nangini mamuruk alamat IP Pian sudah maulah {{PLURAL:$1|1 akun|$1 akun}} dalam $2 hahanyaran, dimana nangitu jumlah paling banyak nang diijinakan.\nSawagai hasilnya, pa'ilang awan alamat IP nangini kada kawa maulah akun pulang gasan pahadangan.",
+       "emailauthenticated": "Alamat suril Pian rasuk pada  $3, $2",
+       "emailnotauthenticated": "Alamat suril Pian balum dirasukakan.\nKadada suril nang pacangan dikirim gasan pitur imbahnya.",
        "noemailprefs": "Ajuakan sabuting alamat suril dalam kakatujuan Pian gasan pitur-pitur ini bagawi.",
        "emailconfirmlink": "Yakinakan alamat suril Pian",
        "invalidemailaddress": "Alamat suril ini kada kawa ditarima karana pormat kada sah.\nMuhun buati sabuting alamat suril nang bujur pormatnya atawa puangkan haja isian itu.",
        "cannotchangeemail": "Akun alamat suril kada kawa diganti pada wiki ngini.",
        "emaildisabled": "Situs naya kada kawa mangirim suril.",
        "accountcreated": "Akun diulah",
-       "accountcreatedtext": "Akun pamakai gasan $1 sudah diulah.",
+       "accountcreatedtext": "Akun pamakai gasan [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|pandiri]]) sudah diulah.",
        "createaccount-title": "Paulahan akun gasan {{SITENAME}}",
        "createaccount-text": "Ada urang nang maulah akun gasan alamat suril Pian pada {{SITENAME}} ($4) bangaran \"$2\", awan kata sunduk \"$3\".\nPian dianjurakan babuat log wan maubah kata sunduk Pian parhatan ni.\n\nPian kawa kada mahual pasan ngini, amun paulahan akun ini adalah kasalahan.",
-       "login-throttled": "Pian sudah kabanyakan mancuba babuat log.\nMuhun hadangi dahulu sapandang hanyar cubai pulang.",
-       "login-abort-generic": "Pian kada ruhui babuat  log - Diwalangi",
+       "login-throttled": "Pian sudah kabanyakan mancuba babuat log.\nMuhun hadangi dahulu $1 hanyar cubai pulang.",
+       "login-abort-generic": "Pian kada ruhui babuat log - Diwalangi",
        "loginlanguagelabel": "Basa: $1",
        "suspicious-userlogout": "Pamintaan Pian hagan kaluar log kada ditarima marga nangkaya dikirim matan panjalajah web rakai atawa tatangkap proxy.",
+       "pt-login": "Babuat log",
+       "pt-login-button": "Babuat log",
+       "pt-createaccount": "Ulah akun",
+       "pt-userlogout": "Kaluar log",
        "php-mail-error-unknown": "Kasalahan kada dipinandui dalam pungsi surat () PHP",
        "user-mail-no-addy": "Mancuba mangirim suril kada baalamat suril.",
        "user-mail-no-body": "Manarai hagan mangirim suril puang atawa talalu handap.",
        "changepassword": "Ubah katasunduk",
-       "resetpass_announce": "Pian babuat log awan sabuting kode samantara nang disurili.\nHagan manuntungakan babuat log, Pian musti manyetel sabuting katasunduk hanyar di sia:",
+       "resetpass_announce": "Gasan manuntungakan babuat log, Pian musti mamasukakan sabuting katasunduk hanyar.",
        "resetpass_header": "Ubah katasunduk akun",
        "oldpassword": "Katasunduk lawas:",
        "newpassword": "Katasunduk hanyar:",
        "retypenew": "Katik pulang katasunduk hanyar:",
        "resetpass_submit": "Setel katasunduk wan babuat log",
-       "changepassword-success": "Katasunduk Pian bahasil diubah!\nWayah ni Pian sudah babuat log...",
+       "changepassword-success": "Katasunduk Pian bahasil diubah!",
        "resetpass_forbidden": "Katasunduk kada kawa diubah",
        "resetpass-no-info": "Pian musti babuat log hagan babuat ka tungkaran ini langsung.",
        "resetpass-submit-loggedin": "Ubah katasunduk",
-       "resetpass-submit-cancel": "Walangi",
-       "resetpass-wrong-oldpass": "Katasunduk samantara atawa wayah ni kada sah.\nPian pinanya sudah barhasil maubah katasunduk Pian atawa maminta sabuting katasunduk samantara hanyar.",
+       "resetpass-submit-cancel": "Pasahakan",
+       "resetpass-wrong-oldpass": "Katasunduk samantara atawa wayah ni kada sah.\nPian pinanya sudah barhasil maubah katasunduk Pian atawa maminta sabuting katasunduk pahadangan nang hanyar.",
        "resetpass-temp-password": "Katasunduk samantara:",
-       "passwordreset": "Bulikakan setelan katasunduk",
+       "passwordreset": "Ubah kata sandi",
        "passwordreset-disabled": "Mambulikakan setelan katasunduk dipajahakan hagan wiki ngini.",
        "passwordreset-username": "Ngaran pamakai:",
        "passwordreset-domain": "Dumain:",
        "passwordreset-email": "Alamat suril:",
        "passwordreset-emailtitle": "Rarincian akun pada {{SITENAME}}",
-       "passwordreset-emailtext-ip": "Ada urang (pinanya Pian, matan alamat IP $1) maminta sabuting pangingat hagan rarincian akun Pian gasan {{SITENAME}} ($4). Pamakai barikut {{PLURAL:$3|akun|akun}}\ntarait awan suril:\n\n$2\n\n{{PLURAL:$3|katasunduk pahadangan ngini|kakatasunduk pahadangan ngini}} akan kadaluarsa dalam {{PLURAL:$5|asa hari|$5 hari}}.\nPian parlu babuat log wan mamilih katasunduk hanyar wayah ni jua. Amun urang lain nang maminta ngini, atawa amun Pian sudah paingatan awan katasunduk Pian, wan Pian kada handak maubahnya, Pian kawa kada mahuwal pasan ngini wan manyambung mamuruk katasunduk lawas Pian.",
+       "passwordreset-emailtext-ip": "Ada urang (pinanya Pian, matan alamat IP $1) maminta sabuting pangingat rarincian akun Pian gasan {{SITENAME}} ($4). Pamakai barikut {{PLURAL:$3|akun|akun}}\ntarait awan suril:\n\n$2\n\n{{PLURAL:$3|katasunduk pahadangan ngini|kakatasunduk pahadangan ngini}} akan kadaluarsa dalam {{PLURAL:$5|sahari|$5 hari}}.\nPian parlu babuat log wan mamilih katasunduk hanyar wayah ni jua. Amun urang lain nang maminta ngini, atawa amun Pian sudah paingatan awan katasunduk Pian, wan Pian kada handak maubahnya, Pian kawa kada maharung pasan ngini wan manyambung mamuruk katasunduk lawas Pian.",
        "passwordreset-emailtext-user": "Ada urang (pinanya Pian, matan alamat IP $1) maminta sabuting pangingat hagan rarincian akun Pian gasan {{SITENAME}} ($4). Pamakai barikut {{PLURAL:$3|akun|akun}}\ntarait awan suril:\n\n$2\n\n{{PLURAL:$3|katasunduk pahadangan ngini|kakatasunduk pahadangan ngini}} akan kadaluarsa dalam {{PLURAL:$5|asa hari|$5 hari}}.\nPian parlu babuat log wan mamilih katasunduk hanyar wayah ini jua. Amun urang lain nang maminta ngini, atawa amun Pian sudah paingatan awan katasunduk Pian, wan Pian kada handak maubahnya, Pian kawa kada mahuwal pasan ngini wan manyambung mamuruk katasunduk lawas Pian.",
        "passwordreset-emailelement": "Ngaran pamakai: \n$1\n\nKatasunduk pahadangan: \n$2",
-       "passwordreset-emailsentemail": "Sabuting suril pangingat sudah takirim.",
-       "changeemail": "Ganti alamat suril",
-       "changeemail-header": "Ganti akun alamat suril",
+       "passwordreset-emailsentemail": "Amun alamat suril ngini barait lawan akun pian, maka suril gasan mambulikakan katasunduk pacangan dikirim.",
+       "changeemail": "Babak atawa hapus alamat suril",
+       "changeemail-header": "Langkapi formulir ngini gasan mambabak alamat suril pian. Amun pian handak mahapus sabarataan alamat suril nang barait lawan akun pian, kosongakan alamat suril wayah mangirim formulir.",
        "changeemail-no-info": "Pian musti babuat log hagan babuat ka tungkaran ngini langsung.",
        "changeemail-oldemail": "Alamat suril wayah ni:",
        "changeemail-newemail": "Alamat suril puga:",
        "sig_tip": "Tandatangan Pian lawan tanda waktu",
        "hr_tip": "Garis horisontal",
        "summary": "Kasimpulan:",
-       "subject": "Subyek/judul:",
+       "subject": "Parihal:",
        "minoredit": "Ngini adalah babakan sapalih",
        "watchthis": "Itihi tungkaran ngini",
        "savearticle": "Simpan tungkaran",
        "preview": "Tilik",
        "showpreview": "Tampaiakan titilikan",
        "showdiff": "Tampaiakan paubahan",
-       "anoneditwarning": "'''Paringatan:''' Pian baluman babuat log.\nAlamat IP Pian akan dirakam dalam tungkaran babakan halam",
+       "anoneditwarning": "<strong>Paringatan:</strong> Pian kada masuk log. Alamat IP Pian pacangan talihat wan urang lain amun Pian handak maubah sasuatu. Amun Pian <strong>[$1 babuat log]</strong> atawa <strong>[$2 maulah akun]</strong>, babakan Pian pacangan diatribusiakan ka ngaran pamakai Pian, taumpat lawan babagai kauntungan lainnya.",
        "anonpreviewwarning": "''Pian baluman babuat log. Manyimpan akan tarakam alamat IP Pian pada sajarah bahari tungkaran ngini.''",
        "missingsummary": "'''Pangingat:''' Pian kada manyadiakan sabuting kasimpulan babakan.\nAmun Pian klik \"$1\" pulang, babakan Pian tasimpan kada bakasimpulan.",
-       "missingcommenttext": "Muhun buati sabuting kumintar di bawah ngini.",
+       "missingcommenttext": "Muhun buati sabuting kumintar.",
        "missingcommentheader": "'''Pangingat:''' Pian kada manyadiakan sabuting subjek/judul gasan kumin ngini.\nAmun Pian klik \"$1\" pulang, babakan Pian tasimpan kada basubjek/bajudul.",
-       "summary-preview": "Tilikan kasimpulan:",
-       "subject-preview": "Titilikan subyek/judul:",
+       "summary-preview": "Tilikan kasimpulan mambabak:",
+       "subject-preview": "Titilikan parihal:",
        "blockedtitle": "Pamakai diblukir",
-       "blockedtext": "'''Ngaran pamakai Pian atawa alamat IP sudah diblukir.'''\n\nPamblukiran diulah ulih $1.\nAlasannya ''$2''.\n\n* Mulai diblukir: $8\n* Kadaluarsa blukir: $6\n* Tujuan pamblukiran: $7\n\nPian kawa mangiyau $1 atawa [[{{MediaWiki:Grouppage-sysop}}|pambakal lainnya]] hagan mamandirakan pamblukiran nangini.\nPian kada kawa mamakai pitur 'surili pamakai naya' amun kadada sabuting alamat suril nang sah nang diajukan dalam [[Special:Preferences|kakatujuan akun]] Pian wan Pian kada lagi diblukir mamakai nangini. \nAlamat IP Pian parhatan ini $3, wan ID nang diblukir adalah $5.\nMuhun sampaiakan samunyaan rarinci di atas dalam parmintaan nang Pian ulah.",
+       "blockedtext": "'''Ngaran pamakai Pian atawa alamat IP sudah diblukir.'''\n\nPamblukiran diulah ulih $1.\nAlasannya ''$2''.\n\n* Mulai diblukir: $8\n* Kadaluarsa blukir: $6\n* Tujuan pamblukiran: $7\n\nPian kawa mangiyau $1 atawa [[{{MediaWiki:Grouppage-sysop}}|pambakal]] lainnya gasan mamandirakan pamblukiran nangini.\nPian kada kawa mamakai pitur {{int:emailuser}} kacuali pian sudah mamasukakan alamat suril nang sah nang diajukan dalam [[Special:Preferences|kakatujuan akun]] Pian wan Pian kada lagi diblukir gasan mamakainya. \nAlamat IP Pian parhatan ini $3, wan ID nang diblukir adalah $5.\nMuhun sampaiakan samunyaan rarinci di atas dalam parmintaan nang Pian ulah.",
        "autoblockedtext": "Alamat IP Pian sudah utumatis diblukir karana dipuruk ulih pamakai lain, nang diblukir ulih $1.\nAlasannya: ''$2''.\n\n* Mulai diblukir: $8\n* Kadaluarsa blukir: $6\n* Tujuan pamblukiran: $7\n\nPian kawa mangiwau $1 atawa nang lain [[{{MediaWiki:Grouppage-sysop}}|pambakal]] hagan mamandirakan pamblukiran nangini.\n\nCatatan Pian kada kawa mamuruk pitur 'surili pamakai naya' amun kadada sabuah alamat suril nang sah nang tadaptar dalam [[Special:Preferences|kakatujuan akun]] Pian wan  Pian kada lagi diblukir mamuruk nangini. \n\nAlamat IP Pian parhatan ini $3, wan ID nang diblukir adalah $5.\nMuhun sampaiakan samunyaan rarinci di atas dalam parmintaan nag Pian ulah.",
        "blockednoreason": "kadada alasan nang diunjukakan",
        "whitelistedittext": "Pian harus $1 hagan mambabak tungkaran.",
        "loginreqlink": "Babuat log",
        "loginreqpagetext": "Pian musti $1 hagan maniringi rungkaran-tungkaran lain.",
        "accmailtitle": "Katasunduk takirim.",
-       "accmailtext": "Sabuting katasunduk babarang gasan [[User talk:$1|$1]] sudah dikirim ka $2.\n\nKatasunduk gasan pamakai hanyar nangini kawa diubah pintang tungkaran ''[[Special:ChangePassword|ubah katasunduk]]'' wayah babuat log.",
+       "accmailtext": "Sabuting katasunduk babarang gasan [[User talk:$1|$1]] sudah dikirim ka $2.\n\nKatasunduk gasan pamakai hanyar nangini kawa diubah di tungkaran ''[[Special:ChangePassword|ubah katasunduk]]'' imbah babuat log.",
        "newarticle": "(Hanyar)",
-       "newarticletext": "Pian maumpati sabuah tautan ka tungkaran nang baluman ada lagi. Gasan maulah tungkaran, mulai ja mangatik pada kutak di bawah (lihati [$1 tungkaran patulung] gasan panjalasan labih). Amun Pian ka sia cagaran tasalah, klik picikan '''back''' di panjalajah web Pian.",
-       "anontalkpagetext": "----''Ngini adalah tungkaran pamandiran gasan pamakai kada bangaran nang baluman ma-ulah akun pulang, atawa  kada mamakainya. Kami tapaksa mamakai numurik alamat IP hagan maminanduinya.\nAlamat IP nangkaini kawaai dipuruk ulih babarapa pamakai.\nAmun Pian adalah pamuruk kada bangaran wan marasa kumin nang kada pas ta ka Pian, muhun [[Special:CreateAccount|ulah sabuah akun]] or [[Special:UserLogin|babuat log]] hagan mahindari kabingungan awan pamuruk kada bangaran lain kaina.",
-       "noarticletext": "Parhatan ni kadada naskah di tungkaran ngini.\nPian kawa [[Special:Search/{{PAGENAME}}|manggagai gasan judul ngini]] pintang tungkaran lain,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} manggagai log barait].</span>,\natawa [{{fullurl:{{FULLPAGENAME}}|action=edit}} mambabak tungkaran ngini]</span>.",
-       "noarticletext-nopermission": "Parhatan ni kadada naskah di tungkaran ngini.\nPian kawa [[Special:Search/{{PAGENAME}}|manggagai gasan judul ngini]] pintang tungkaran lain,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} manggagai log barait].</span>.",
+       "newarticletext": "Pian maumpati tautan ka tungkaran nang balum tasadia.Amun handak maulah tungkaran itu, katiklah isi tungkaran di kutak di bawah ngini (janaki [$1 tungkaran patulung] gasan maklumat labih lanjut). Amun pian kada bakurinah sampai ka tungkaran ngini, kalik picikan <strong>back</strong> di panjalajah wéb Pian.",
+       "anontalkpagetext": "----''Ngini adalah tungkaran pamandiran gasan pamakai kada bangaran nang baluman ma-ulah akun pulang, atawa  kada mamakainya. Kami tapaksa mamakai numurik alamat IP hagan maminanduinya.\nAlamat IP nangkaini kawaai dipuruk ulih babarapa pamakai.\nAmun Pian adalah pamakai kada bangaran wan marasa kumin nang kada pas ta ka Pian, muhun [[Special:CreateAccount|ulah sabuah akun]] atawa [[Special:UserLogin|babuat log]] gasan mahindari kabingungan awan pamakai kada bangaran lain kaina.",
+       "noarticletext": "Damini kadada naskah di tungkaran ngini.\nPian kawa [[Special:Search/{{PAGENAME}}|manggagai gasan judul tungkaran ngini]] di tutungkaran lain, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} mancari log tarait], atawa [{{fullurl:{{FULLPAGENAME}}|action=edit}} maulah tungkaran ngini]</span>.",
+       "noarticletext-nopermission": "Wayahini kadada naskah di tungkaran ngini.\nPian kawa [[Special:Search/{{PAGENAME}}|manggagai gasan judul tungkaran ngini]] di tutungkaran lain, atawa <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} manggagai log tarait]</span>, tagal Pian kada baisi ijin gasan maulah tungkaran ngini",
        "userpage-userdoesnotexist": "Akun pamakai \"<nowiki>$1</nowiki>\" kada tadaptar.\nMuhun pariksa/ditukui amun Pian handak maulah/mambabak tungkaran ngini.",
        "userpage-userdoesnotexist-view": "Akun pamakai \"$1\" kada tadaptar.",
        "blocked-notice-logextract": "Pamakai nangini parhatan diblukir.\nLog blukir pahabisannya tasadia di bawah ngini gasan rujukan:",
-       "clearyourcache": "x'''Catatan: Habis manyimpan, Pian harus malingarakan cache panjalajah web Pian hagan malihat paubahan.'''\n*'''Firefox/Safari:''' tahan ''Shift'' parhatan klik ''Reload'', atawa picik ''Ctrl-F5'' atawa ''Ctrl-R'' (''Command-R'' pada sabuting Mac);\n* '''Google Chrome:''' picik ''Ctrl-Shift-R'' (''Command-Shift-R''  pada sabuting Mac)\n*'''Internet Explorer:''' tahan ''Ctrl'' parhatan klik ''Refresh,'' atawa picik ''Ctrl-F5''\n* '''Konqueror:''' kalik ''Reload'' atawa picik ''F5''\n*'''Opera:''' barasihakan cache pada ''Tools → Preferences''",
+       "clearyourcache": "<strong>Catatan:</strong>Limbah disimpan, Pian mungkin parlu malincau talih paramban wéb gasan malihat paubahan.\n* <strong>Firefox/Safari:</strong> Tahan <em>Shift</em> wayah dikalik <em>Reload</em>, atawa tikin <em>Ctrl-F5</em> atawa <em>Ctrl-R</em> (<em>⌘-R</em> di Mac)\n* <strong>Google Chrome:</strong> Tikin <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> di Mac)\n* <strong>Internet Explorer:</strong> Tikin <em>Ctrl</em> wayah dikalik <em>Refresh</em>, atawa tikin <em>Ctrl-F5</em>\n* <strong>Opera:</strong> Tulak ka <em>Menu → Settings </em> (<em>Opera → Preferences</em> di Mac) lalu ka <em>Privacy & security → Clear browsing data → Cached images and files</em>.",
        "usercssyoucanpreview": "'''Tip:''' Puruk picikan \"{{int:showpreview}}\" hagan tis CSS hanyar Pian sabalum manyimpan.",
        "userjsyoucanpreview": "'''Tip:''' Puruk picikan \"{{int:showpreview}}\" hagan tis JavaScript hanyar Pian sabalum manyimpan.",
        "usercsspreview": "'''Ingatakan bahwasa Pian manilik pamakai CSS Pian haja.'''\n'''Nangini baluman tasimpan pulang!'''",
        "userjspreview": "'''Ingatakan bahwasa Pian tis/manilik pamakai JavaScript Pian.'''\n'''Nangini baluman tasimpan pulang!'''",
        "sitecsspreview": "'''Ingatakan bahwasa Pian manilik CSS ini haja.'''\n'''Nangini lagi baluman tasimpan!'''",
        "sitejspreview": "'''Ingatakan bahwasa Pian manilik JavaScript code ini haja.'''\n'''Nangini lagi baluman tasimpan!'''",
-       "userinvalidconfigtitle": "'''Paringatan:''' Kadada kulit \"$1\".\nInatakan bahwasa saragam  tungkaran-tungkaran .css wan .js mamuruk aksara halus, cuntuh {{ns:user}}:Foo/vector.css sawagai tandingan {{ns:user}}:Foo/Vector.css.",
+       "userinvalidconfigtitle": "'''Paringatan:''' Kadada kulimbit \"$1\".\nTungkaran-tungkaran .css, .json wan .js ulahan mamuruk aksara halus, cuntuh {{ns:user}}:Foo/vector.css sawagai tandingan {{ns:user}}:Foo/Vector.css.",
        "updated": "(Dihanyarakan)",
        "note": "'''Catatan:'''",
        "previewnote": "'''Ingatakanlah bahwasa ngini titilikan haja''' Paubahan Pian baluman disimpan!",
        "continue-editing": "Lanjutakan mambabak",
        "previewconflict": "Titilikan ini mancarminakan naskah dalam naskah wilayah atas babakan sawagai mana ini akan mancungul amun disimpan.",
-       "session_fail_preview": "'''Ampun! Kami kada kawa manarusakan babakan Pian karana kahilangan sési data.'''\nCubai pang sa'asa pulang.\nAmun magun kada kulihan, cubai [[Special:UserLogout|kaluar log]] wan imbah itu babuat log pulang.",
-       "session_fail_preview_html": "'''Kami kada kawa manarusakan babakan Pian marga kahilangan wayah data.'''\n\n''Marga {{SITENAME}} mangkawa'akan HTML mantah, titilikan disungkupakan sawagai pancagahan sarangan Javascript.''\n\n'''Amun nangini adalah sabuting parcubaan babakan nang sabujurnya, muhun cubai lagi.'''\nAmun ngini masih haja kada bagawi, cubai [[Special:UserLogout|kaluar log]] wan babuat log pulang.",
+       "session_fail_preview": "Maap! Kami kada kawa mamproses babakan pian maraga tahapusnya data sesi.\n\n\nPian mungkin sudah kaluar log. <strong>Muhun pastiakan pian masih babuat log wan cubai baasa</strong>.\nAmun masih kada kawa,ubai [[Special:UserLogout|kaluar log]] wan babuat log basa, wan cek bahwa panjalajah pian maizinakan kuki matan situs ngini.",
+       "session_fail_preview_html": "'''Kami kada kawa manarusakan babakan Pian marga kahilangan wayah data.'''\n\n''Marga {{SITENAME}} mangkawa'akan HTML mantah, titilikan disungkupakan sawagai pancagahan sarangan Javascript.''\n\n'''Amun nangini adalah sabuting parcubaan babakan nang sabujurnya, muhun cubai lagi.'''\nAmun ngini masih haja kada kawa, cubai [[Special:UserLogout|kaluar log]] wan babuat log pulang, wan cek panjalajah pian manarima kuki matan situs ngini.",
        "token_suffix_mismatch": "'''Babakan Pian sudah kada ditarima marga aplikasi Pian mahancuri tanda baca pada babakan token.'''\nBabakan ini kada ditarima hagan mancagah kasalahan pada naskah tungkaran.\nNangini bahanu tajadi amun Pian mamuruk sabuting layanan proxy buggy bapandal web kada bangaran.",
        "edit_form_incomplete": "'''Babarapa hagian matan purmulir babakan kada sampai server; pariksa pulang apakah babakan Pian tatap utuh wan cubai lagi.'''",
        "editing": "Mambabak $1",
        "copyrightwarning": "Muhun dicatat bahwasanya samunyaan sumbangan ka {{SITENAME}} adalah sudah dipartimbangkan disabarakan di bawah $2 (lihati $1 gasan rincian). Amun Pian kada handak tulisan Pian dibabak wan disabarakan, kada usah mangirim ini ka sia. <br />\nPian jua bajanji ka kami amun Pian manulis ini saurangan, atawa manjumput ini matan sabuah asal mula ampun umum atawa asal mula lainnya nang samacam.\n'''Jangan kirimkan gawian bahak cipta kada baijin!'''",
        "copyrightwarning2": "Muhun dicatat bahwasanya samunyaan sumbangan ka {{SITENAME}} kawa dibabak, diubah, atawa dibuang awan panyumbang lainnya.\nAmun Pian kada hakun tulisan Pian dibabak kada baumpat lalu, lalu ai kada usah manyumbang di sia.<br />\nPian jua bajanji ka kami amun Pian manulis ini saurangan, atawa manjumput ini matan sabuah asal mula ampun umum atawa nang samacam asal mula bibas (lihati $1 gasan rarincian).\n'''Jangan kirimkan gawian bahak cipta kada baijin!'''",
        "longpageerror": "'''Kasalahan: Naskah nang Pian kirim panjangnya {{PLURAL:$1|asa kilubita|$1 kilubita}}, nangapa tapanjang pada pamanjangnya nang kawa {{PLURAL:$2|asa kilubita|$2 kilubita}}.'''\nNangini kada kawa disimpan.",
-       "readonlywarning": "'''Paringatan: Basis data sudah tasunduk gasan diharagu, jadinya Pian kada kawa manyimpan babakab Pian parhatan ini.'''\nPian kawa amun handak cut-n-paste naskah ka sabuah barakas naskah wan simpan ini gasan kaina.\n\nPambakal nang manyunduk manjalasakan kaini: $1",
+       "readonlywarning": "'''Paringatan: Basis data disunduk gasan diharagu, jadinya Pian kada kawa manyimpan babakan Pian wayahini.'''\nPian mungkin bagusnya manyalin wan malikap naskah ka sabuah barakas naskah wan simpan ngini gasan kainah.\n\nPambakal nang manyunduk manjalasakan kaini: $1",
        "protectedpagewarning": "'''Paringatan: Tungkaran ngini sudah dilindungi nang akibatnya pamakai awan hak istimiwa pambakal nang kawa mambabak ini.'''\nLog masuk pauncitnya disadiakan di bawah gasan rujukan:",
        "semiprotectedpagewarning": "'''Catatan:''' Tungkaran ngini sudah dilindungi nang akibatnya pamakai tadaptar haja nang kawa mambabak.\nLog masuk pauncitnya disadiakan di bawah gasan rujukan:",
-       "cascadeprotectedwarning": "'''Paringatan:''' Tungkaran ngini sudah dilindungi nang akibatnya pamakai awan hak istimiwa pambakal haja nang kawa mambabak, sualnya ngini tamasuk dalam baumpat parlindungan barénténg {{PLURAL:$1|tungkaran|tutungkaran}}:",
+       "cascadeprotectedwarning": "<strong>Paringatan:</strong> Tungkaran ngini dilindungi jadinya pamakai lawan [[Special:ListGroupRights|hak aksis batantu] wara nang kawa mambabaknya maraga ditransklusiakan dalam {{PLURAL:$1|tungkaran|tungkaran-tungkaran}} nang dilindungi barinting.",
        "titleprotectedwarning": "'''Paringatan: Tungkaran ngini sudah dilindungi nang akibatnya [[Special:ListGroupRights|hak khas]] diparluakan hagan maulah ngini.'''\nLog masuk pauncitnya disadiakan di bawah gasan rujukan:",
-       "templatesused": "{{PLURAL:$1|Citakan|Citakan}} nang digunakan di tungkaran ngini:",
-       "templatesusedpreview": "{{PLURAL:$1|Citakan|Citakan}} nang digunakan di titilikan ngini:",
+       "templatesused": "{{PLURAL:$1|Citakan|Cicitakan}} nang dipakai di tungkaran ngini:",
+       "templatesusedpreview": "{{PLURAL:$1|Citakan|Cicitakan}} nang dipakai di titilikan ngini:",
        "templatesusedsection": "{{PLURAL:$1|Citakan|Cicitakan}} nang diguna'akan di hagian ini:",
        "template-protected": "(dilindungi)",
        "template-semiprotected": "(semi-dilindungi)",
-       "hiddencategories": "Tungkaran ini adalah angguta matan {{PLURAL:$1|1 tumbung tasungkup|$1 tumbung tasungkup}}:",
+       "hiddencategories": "Halaman ngini adalah angguta matan {{PLURAL:$1|1 pilah tatukup|$1 pilah tatukup}}:",
        "nocreatetext": "{{SITENAME}} lagi mambatasi kakawaan maulah tungkaran hanyar.\nPian kawa babulik wan mambabak sabuah tungkaran nag ada, atawa [[Special:UserLogin|lbabuat log atawa baulah sabuah akun]]",
        "nocreate-loggedin": "Pian kada baisi ijin hagan maulah tungkaran-tungkaran hanyar.",
        "sectioneditnotsupported-title": "Pambabakan hagian kada didukung",
        "sectioneditnotsupported-text": "Pambabakan hagian kada didukung pada tungkaran ini.",
-       "permissionserrors": "Parijinan tasalah",
+       "permissionserrors": "Kasalahan hak aksés",
        "permissionserrorstext": "Pian kada baisi ijin gasan malakuakan itu, karana {{PLURAL:$1|alasan|alasan}} ini:",
        "permissionserrorstext-withaction": "Pian kada baisi ijin gasan $2, karana {{PLURAL:$1|alasan|alasan}} ini:",
        "recreate-moveddeleted-warn": "'''Paringatan: Pian maulah pulang sabuah tungkaran nang sabalumnya dihapus.'''\n\nPian partimbangakan dahulu sasuaikah hagan manarusakan pambabakan tungkaran ini.\nLog pahapusan wan paugahan gasan tungkaran ini disadiakan di sia:",
-       "moveddeleted-notice": "Tungkaran ini sudah dihapus.\nLog pahapusan wan paugahan gasan tungkaran ini disadiakan di bawah ini gasan rujukan.",
+       "moveddeleted-notice": "Tungkaran ini sudah dihapus.\nLog pahapusan, palindungan, wan pamindahan matan tungkaran itu tasadia di bawah ini sabagai rujukan.",
        "log-fulllog": "Tiringi samunyaan log",
        "edit-hook-aborted": "Babakan ditinggalakan ulih kakait parser.\nIni kadada panjalasan.",
        "edit-gone-missing": "Kada kawa mamutakhirakan tungkaran ini.\nIni cungul pinanya sudah tahapus.",
        "defaultmessagetext": "Naskah baku pasan",
        "content-failed-to-parse": "Gagal manjabarakan isi $2 gasan model $1: $3",
        "invalid-content-data": "Data isi kada sah",
-       "content-not-allowed-here": "Isi \"$1\" kada diijinakan di tungkaran [[:$2]]",
+       "content-not-allowed-here": "Isi \"$1\" kada diijinakan di tungkaran [[:$2]] di bagian \"$3\"",
        "content-model-wikitext": "teks wiki",
        "content-model-text": "teks polos",
        "content-model-javascript": "JavaScript",
        "parser-template-recursion-depth-warning": "Citakan batas kadalaman recursi limpuar ($1)",
        "language-converter-depth-warning": "Batas kadalaman pangonversi basa limpuar ($1)",
        "node-count-exceeded-category": "Tungkaran di mana node-count tarlalui",
-       "node-count-exceeded-warning": "Tungkaran malabihi node-count",
+       "node-count-exceeded-warning": "Tungkaran malabihi jumlah node",
        "expansion-depth-exceeded-category": "Tungkaran dimana kadalaman ikspansi talalui",
        "expansion-depth-exceeded-warning": "Tungkaran malabihi kadalaman ikspansi",
        "parser-unstrip-loop-warning": "Lingkaran unstrip taditiksi",
        "undo-norev": "Babakan kada kawa diwalangi karana ini kadada atawa tahapus.",
        "undo-summary": "←Mawalangakan ralatan $1 ulih [[Special:Contributions/$2|$2]] ([[User talk:$2|Pandir]])",
        "cantcreateaccount-text": "Paulahan akun matan alamat IP ('''$1''') sudah diblukir ulih [[User:$3|$3]].\n\nAlasan nang dibari ulih $3 adalah ''$2''",
-       "viewpagelogs": "Tiringi log tungkaran ini",
+       "viewpagelogs": "Janaki log tungkaran ini",
        "nohistory": "Kadada halam babakan gasan tungkaran ini.",
        "currentrev": "Ralatan pahabisannya",
        "currentrev-asof": "Ralatan pahanyarnya pada $1",
        "revisionasof": "Ralatan matan $1",
-       "revision-info": "Ralatan pada $1 ulih $2",
-       "previousrevision": "←Ralatan talawas",
+       "revision-info": "Ralatan par $1 ulih {{GENDER:$6|$2}}$7",
+       "previousrevision": "←Ralatan sabalumnya",
        "nextrevision": "Ralatan salanjutnya→",
        "currentrevisionlink": "Ralatan wayahini",
-       "cur": "dmn",
+       "cur": "wyhni",
        "next": "dudi",
        "last": "sblm",
        "page_first": "Panambaian",
        "page_last": "Pauncitan",
        "histlegend": "Pilihan mananding: tandai kutak-kutak radiu ralatan-ralatan nang handak ditanding wan picik enter atawa picikan di bawah.<br />Legend: '''({{int:cur}})''' =lainnya awan ralatan pahanyarnya, '''({{int:last}})''' = lainnya awan ralatan sabalumnya, '''{{int:minoreditletter}}''' = babakan sapalih.",
-       "history-fieldset-title": "Tangadahi halam",
-       "history-show-deleted": "Nang dihapus haja",
-       "histfirst": "Palawasnya",
-       "histlast": "Pahanyarnya",
+       "history-fieldset-title": "Ralatan nang disaring",
+       "history-show-deleted": "Babakan nang dihapus haja",
+       "histfirst": "palawasnya",
+       "histlast": "pahanyarnya",
        "historysize": "($1 {{PLURAL:$1|bita|bibita}})",
-       "historyempty": "(kusung)",
-       "history-feed-title": "Ralatan halam",
-       "history-feed-description": "Ralatan halam gasan tungkaran ini pada wiki",
+       "historyempty": "kusung",
+       "history-feed-title": "Riwayat ralatan",
+       "history-feed-description": "Riwayat ralatan gasan tungkaran ngini pada wiki",
        "history-feed-item-nocomment": "$1 wayah $2",
        "history-feed-empty": "Tungkaran nang diminta kadada.\nIni pinanya sudah dihapus matan wiki ini, atawa dingarani lain.\nCubai [[Special:Search|gagai di wiki ini]] gasan tungkaran hanyar bakarabat.",
        "rev-deleted-comment": "(kasimpulan babakan dibuang)",
-       "rev-deleted-user": "(ngaran pamuruk dibuang)",
-       "rev-deleted-event": "(log palakuan dibuang)",
-       "rev-deleted-user-contribs": "[ngaran pamuruk atawa alamat IP dibuang - babakan disungkupakan matan daptar sumbangan]",
+       "rev-deleted-user": "(ngaran pamakai dihapus)",
+       "rev-deleted-event": "(rincian log dihapus)",
+       "rev-deleted-user-contribs": "[ngaran pamakai atawa alamat IP dibuang - babakan disungkupakan matan daptar sumbangan]",
        "rev-deleted-text-permission": "Ralatan tungkaran ini sudah '''dihapus'''.\nRarincian kawa diugai dalam [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} log pahapusan].",
        "rev-deleted-text-unhide": "Ralatan tungkaran ini sudah '''dihapus'''.\nRarincian kawa diugai dalam [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} log pahapusan].\nSawagai pambakal Pian masih kawa [$1 maniringi ralatan ini] amun Pian hakun manarusakan.",
        "rev-suppressed-text-unhide": "Ralatan tungkaran ini sudah '''ditikin'''.\nRarincian kawa diugai dalam [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} log panikinan].\nSawagai pambakal Pian masih kawa [$1 maniringi ralatan ini] amun Pian hakun manarusakan.",
        "rev-suppressed-unhide-diff": "Asa matan ralatan-ralatan nang balain ini sudah '''ditikin'''.\nRarincian kawa diugai dalam [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} log panikinan].\nSawagai pambakal Pian masih kawa [$1 maniringi nang balain ini] amun Pian hakun manarusakan.",
        "rev-deleted-diff-view": "Asa matan ralatan-ralatan nang balain ini sudah '''dihapus'''.\nSawagai saurang pambakal Pian kawa nang balain ini; rarincian kawa diugai dalam [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} log pahapusan].",
        "rev-suppressed-diff-view": "Asa matan ralatan-ralatan nang balain ini sudah '''ditikin'''.\nSawagai saurang pambakal Pian kawa nang balain ini; rarincian kawa diugai dalam [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} log panikinan].",
-       "rev-delundel": "tampaiakan/sungkupakan",
+       "rev-delundel": "ubah tampilan",
        "rev-showdeleted": "tampaiakan",
        "revisiondelete": "Hapus/kada mahapus ralatan-ralatan",
        "revdelete-nooldid-title": "Ralatan nag dituju kada sah",
-       "revdelete-nooldid-text": "Pian kada maajuakan sabuah ralatan(-ralatan) tatuju hagan malakuakan pungsi ini, ralatan nang dituju kadada, atawa Pian mancuba manyungkupakan ralatan parhatan ini.",
+       "revdelete-nooldid-text": "Pian kada maajuakan sabuah ralatan tatuju gasan malakuakan pungsi ini, ralatan nang dituju kadada, atawa Pian mancuba mamatak ralatan hahanyaran.",
        "revdelete-no-file": "Barakas nang diajuakan kadada.",
        "revdelete-show-file-confirm": "Pian bujurkah handak maniringi sabuah ralatan tahapus matan barakas \"<nowiki>$1</nowiki>\" $2 pada $3?",
        "revdelete-show-file-submit": "Iya-ai",
        "logdelete-selected": "{{PLURAL:$1|Log kajadian tapilih|Log kakajadian tapilih}}:",
        "revdelete-confirm": "Muhun yakinakan bahwasa Pian handak manggawi ini, bahwasa Pian paham sabab akibat, wan bahwasa Pian manggawi ini bapandal awan [[{{MediaWiki:Policy-url}}|kaaripan]].",
-       "revdelete-suppress-text": "Panikinan parlu dipuruk gasan kakasus baumpat ini:\n* Pina kawa jadi panjalasan pitnah\n* balalabihan panjalasan kada sasuai paribadi\n*: ''alamat badiam wan numur talipun, numur kaamanan susial, dll.''",
+       "revdelete-suppress-text": "Pamatakan ralatan dipakai gasan kasus-kasus imbahini <strong>wara</strong>:\n* informasi bapotensi mampitnah\n* informasi paribadi nang kada sapantasnha\n* <em>alamat rumah wan numur telepon, nomor kartu identitas, wan nang lain.</em>",
        "revdelete-legend": "Setel panampaian tabatas",
-       "revdelete-hide-text": "Sungkupakan naskah ralatan",
+       "revdelete-hide-text": "Teks ralatan",
        "revdelete-hide-image": "Sungkupakan isi barakas",
-       "revdelete-hide-name": "Sungkupakan palakuan wan nang dituju",
-       "revdelete-hide-comment": "Sungkupakan kasimpulan babakan",
-       "revdelete-hide-user": "Sungkupakan ngaran pamuruk/alamat IP pambabak",
+       "revdelete-hide-name": "Patak nang dituju wan parameter",
+       "revdelete-hide-comment": "Kasimpulan babakan",
+       "revdelete-hide-user": "Ngaran pamakai/alamat IP pambabak",
        "revdelete-hide-restricted": "Sungkupakan data matan pambakal nangkaya nang lain",
        "revdelete-radio-same": "(Ditangati maubah)",
-       "revdelete-radio-set": "Iya-ai",
-       "revdelete-radio-unset": "Kada",
+       "revdelete-radio-set": "Dipatak",
+       "revdelete-radio-unset": "Talihat",
        "revdelete-suppress": "Sungkupakan data matan pambakal nangkaya nang lain",
        "revdelete-unsuppress": "Buang pambatasan pada ralatan-ralatan nang dibulikakan",
        "revdelete-log": "Alasan:",
        "revdelete-submit": "Lamar hagan mamilih {{PLURAL:$1|ralatan|ralatan-ralatan}}",
-       "revdelete-success": "'''Panampaian ralatan bakulihan dimutakhirakan.'''",
+       "revdelete-success": "Katarlihatan ralatan kawa dihanyari.",
        "revdelete-failure": "'''Panampaian ralatan kada kawa dimutakhirakan:'''\n$1",
-       "logdelete-success": "'''Log panampaian bahasil disetel.'''",
+       "logdelete-success": "Log panampaian bahasil disetel.",
        "logdelete-failure": "'''Log panampaian kada kawa disetel:'''\n$1",
        "revdel-restore": "Ubah tampilan",
        "pagehist": "Sajarah tungkaran",
        "revdelete-no-change": "'''Paringatan:''' nang batanggal $1, $2 sudah baisi setélan kakawaan-dilihati.",
        "revdelete-concurrent-change": "Kasalahan magaganti nang batanggal $1, $2: nangini cungulnya suah diubah ulih urang lain pas Pian handak magaganti ini.\nMuhun pariksa lolog.",
        "revdelete-only-restricted": "Kasalahan manyungkup ngan batanggal $1, $2: Pian kada kawa manikin matan tiringan ulih papambakal kadada jua mamilih asa matan pilihan kawa-malihati.",
-       "revdelete-reason-dropdown": "*Aalasan umum pahapusan\n** Palangaran hak cipta\n** Kakadasasuaian panjalasan paribadi\n** Pina kawa jadi panjalasan pitnah",
+       "revdelete-reason-dropdown": "*Alasan umum pahapusan\n** Palanggaran hak cipta\n** Kumintar atawa informasi pribadi nang kada pantas\n** Ngaran pamakai nang kada pantas\n** Bapotensi mancamarakan ngaran baik",
        "revdelete-otherreason": "Alasan lain/tatambahan:",
        "revdelete-reasonotherlist": "Alasan lain",
        "revdelete-edit-reasonlist": "Aalasan pahapusan babakan",
        "mergehistory-same-destination": "Tungkaran-tungkaran asal mula wan tatuju kada kawa sama",
        "mergehistory-reason": "Alasan:",
        "mergelog": "Log panggabungan",
-       "revertmerge": "Walang panggabungan",
+       "revertmerge": "Pasah panggabungan",
        "mergelogpagetext": "Di bawah adalah daptar nang paling hanyar panggabungan matan sabuah tungkaran halam ka dalam nang lain.",
-       "history-title": "Ralatan halam matan ''$1''",
+       "history-title": "Sajarah ralatan matan \"$1\"",
+       "difference-title": "$1: Pabidaan ralatan",
        "difference-multipage": "(Nang balain antar tungkaran-tungkaran)",
        "lineno": "Baris $1:",
        "compareselectedversions": "Tandingakan ralatan nang dipilih",
        "showhideselectedversions": "Tampaiakan/sungkupakan ralatan-ralatan",
-       "editundo": "walangi",
-       "diff-multi-manyusers": "({{PLURAL:$1|Asa ralatan tangah|$1 raralatan tangah}} ulih labih pada $2 {{PLURAL:$2|pamuruk|papamuruk}} kada ditampaiakan)",
+       "editundo": "bulikakan",
+       "diff-empty": "(Kadada bida)",
+       "diff-multi-sameuser": "({{PLURAL:$1|$1 ralatan antara}} ulih pamakai nang sama kada ditampaiakan)",
+       "diff-multi-otherusers": "({{PLURAL:$1|Satu ralatan antara|$1 ralatan antara}} ulih {{PLURAL:$2|satu pamakai lainnya|$2 pamakai}} kada ditampaiakan)",
+       "diff-multi-manyusers": "({{PLURAL:$1|Satu|$1}} ralatan antara ulih labih matan $2 {{PLURAL:$2|satu|$2}} pamakai kada ditampaiakan)",
        "searchresults": "Kulihan panggagaian",
-       "searchresults-title": "Kulihan gagai gasan \"$1\"",
+       "searchresults-title": "Kulihan panggagaian gasan \"$1\"",
        "titlematches": "Judul tungkaran pas",
        "textmatches": "Naskah tungkaran pas",
        "notextmatches": "Kadada tungkaran banaskah pas",
        "prevn": "{{PLURAL:$1|$1}} tadahulu",
-       "nextn": "{{PLURAL:$1|$1}} dudinya",
+       "nextn": "{{PLURAL:$1|$1}} imbahnya",
        "prevn-title": "Tadahulu $1 {{PLURAL:$1|kulihan|kulihan-kulihan}}",
-       "nextn-title": "Tadudi $1 {{PLURAL:$1|kulihan|kulihan-kulihan}}",
-       "shown-title": "Tampaiakan $1 {{PLURAL:$1|kulihan|kukulihan}} par tungkatan",
+       "nextn-title": "$1 {{PLURAL:$1|kulihan|kulihan-kulihan}} imbahnya",
+       "shown-title": "Tampaiakan $1 {{PLURAL:$1|kulihan|kukulihan}} par tungkaran",
        "viewprevnext": "Tiringi ($1 {{int:pipe-separator}} $2) ($3)",
        "searchmenu-exists": "'''Ada tungkaran bangaran \"[[:$1]]\" dalam wiki ini.'''",
-       "searchmenu-new": "'''Maulah tungkaran \"[[:$1]]\" dalam wiki ngini!'''",
+       "searchmenu-new": "<strong>Ulah tungkaran \"[[:$1]]\" di wiki ngini!</strong> {{PLURAL:$2|0=|Itihi jua tungkaran nang didapatakan matan panggagaian Pian.|Itihi jua hasil panggagaian nang didapatakan.}}",
        "searchprofile-articles": "Tungkaran isi",
        "searchprofile-images": "Multimadia",
        "searchprofile-everything": "Samunyaan",
        "searchprofile-articles-tooltip": "Panggagaian pada $1",
        "searchprofile-images-tooltip": "Panggagaian barakas",
        "searchprofile-everything-tooltip": "Panggagaian sabarataan isi (tamasuk tutungkaran pamandiran)",
-       "searchprofile-advanced-tooltip": "Panggagaian pada ragam ngaran kakamar",
+       "searchprofile-advanced-tooltip": "Panggagaian pada ngaran-kamar tatantu",
        "search-result-size": "$1 ({{PLURAL:$2|1 ujar|$2 uujar}})",
        "search-result-category-size": "{{PLURAL:$1|1 angguta|$1 aangguta}} ({{PLURAL:$2|1 subtumbung|$2 subtutumbung}}, {{PLURAL:$3|1 barakas|$3 babarakas}})",
-       "search-redirect": "(Paugahan $1)",
+       "search-redirect": "(Diugahakan matan $1)",
        "search-section": "(hagian $1)",
+       "search-file-match": "(rasuk lawan isi barakas)",
        "search-suggest": "Nginikah maksud Pian: $1",
-       "search-interwiki-caption": "Dingsanak rangka gawian",
-       "search-interwiki-default": "Kulihan $1",
+       "search-interwiki-caption": "Kulihat matan rangka gawian dangsanak",
+       "search-interwiki-default": "Kulihan matan $1:",
        "search-interwiki-more": "(lagi)",
        "search-relatedarticle": "Bakulaan",
        "searchrelated": "bakulaan",
        "searchall": "samunyaan",
        "showingresults": "Di bawah ngini ditampaiakan hingga {{PLURAL:$1|'''1''' kulihan|'''$1''' kukulihan}}, dimulai matan #'''$2'''.",
-       "search-nonefound": "Kadada kulihan nang pas awan parmintaan.",
+       "search-showingresults": "{{PLURAL:$4|Kulihan <strong>$1</strong> matan <strong>$3</strong>|Kulihan <strong>$1 - $2</strong> matan <strong>$3</strong>}}",
+       "search-nonefound": "Kadada kulihan nang pas lawan parmintaan.",
        "powersearch-legend": "Panggagaian mahir",
        "powersearch-ns": "Manggagai di ngaran kamar:",
        "powersearch-togglelabel": "Pilihi:",
        "search-external": "Panggagaian luar",
        "searchdisabled": "{{SITENAME}} panggagaian kada kawa\nPian kawa manggagai lung Google parhatan ini.\nCatatan nang dihaharnya matan isi {{SITENAME}} kawa-ai sudah kadaluarsa.",
        "preferences": "Kakatujuan",
-       "mypreferences": "Nang ulun katuju",
+       "mypreferences": "Kakatujuan",
        "prefs-edits": "Rikinan babakan-babakan:",
        "prefs-skin": "Kulimbit",
        "skin-preview": "Titilikan",
        "prefs-watchlist": "Paitihan",
        "prefs-watchlist-days": "Rikinan hari-hari ditampaiakan di daptar itihan:",
        "prefs-watchlist-days-max": "Maksimum $1 {{PLURAL:$1|hari|hahari}}",
-       "prefs-watchlist-edits": "Rikinan paningginya matan paubahan hagan ditampaiakan pada singkaian daptar itihan:",
+       "prefs-watchlist-edits": "Rikinan paningginya matan paubahan gasan ditampaiakan pada daptar itihan:",
        "prefs-watchlist-edits-max": "Rikinan paningginya:1000",
        "prefs-watchlist-token": "Token itihan:",
        "prefs-misc": "Balalain",
        "prefs-resetpass": "Ubah katasunduk",
-       "prefs-changeemail": "Ganti suril",
+       "prefs-changeemail": "Babak atawa hapus alamat suril",
        "prefs-setemail": "Setel sabuah alamat suril",
        "prefs-email": "Pipilihan suril",
        "prefs-rendering": "Pancungulan",
        "saveprefs": "Simpan",
-       "restoreprefs": "Bulikakan samunyaan sesetélan default",
+       "restoreprefs": "Bulikakan samunyaan sesetélan bawaan (di sabarataan seksi)",
        "prefs-editing": "Pambabakan",
        "searchresultshead": "Gagai",
-       "stub-threshold": "Ambang watas gasan pormat <a href=\"#\" class=\"stub\">taautan rintisan</a>:",
+       "stub-threshold": "Ambang watas gasan pormat tautan rintisan ($1):",
        "stub-threshold-disabled": "Kada kawa-akan",
        "recentchangesdays": "Jumlah hari nang manampaiakan paubahan pahanyarnya:",
        "recentchangesdays-max": "Paling lawas $1 {{PLURAL:$1|hari|hahari}}",
-       "recentchangescount": "Rikinan babakan nang ditampaiakan default:",
-       "prefs-help-recentchangescount": "Ngini tamasuk paubahan pahanyarnya, sajarah halam tungkaran, wan log-log.",
+       "recentchangescount": "Rikinan babakan default gasan ditampaiakan di paubahan pahanyarnya, riwayat tungkaran, wan di tungkaran log:",
+       "prefs-help-recentchangescount": "Rikinan paningginya: 1000",
        "savedprefs": "Kakatujuan Pian sudah ham disimpan.",
        "timezonelegend": "Waktu banua:",
        "localtime": "Waktu damintu:",
        "timezoneregion-europe": "Irupa",
        "timezoneregion-indian": "Lalautan Hindia",
        "timezoneregion-pacific": "Lalautan Pasipik",
-       "allowemail": "Kawa'akan pamakai lain mangirim suril",
-       "prefs-searchoptions": "Papilihan manggagai",
+       "allowemail": "Kawa'akan pamakai lain mangirim suril lawan ulun",
+       "prefs-searchoptions": "Gagai",
        "prefs-namespaces": "Ngaran kamar",
        "default": "default",
        "prefs-files": "Barakas",
        "prefs-custom-css": "Saragamakan CSS",
        "prefs-custom-js": "Saraganakan JavaScript",
-       "prefs-common-config": "Babagi CSS/JavaScript gasan samunyaan skin:",
+       "prefs-common-config": "Babagi CSS/JavaScript gasan samunyaan kulimbit:",
        "prefs-reset-intro": "Pian kawa mamuruk tungkaran ini hagan setel bulik kakatujuan Pian ka default situs.\nIni kada kawa diwalangi.",
        "prefs-emailconfirm-label": "Payakinakan suril:",
        "youremail": "Suril:",
-       "username": "Ngaran pamuruk:",
-       "prefs-memberingroups": "Angguta matan {{PLURAL:$1|galambang|gagalambang}}:",
+       "username": "{{GENDER:$1|Ngaran pamakai}}:",
+       "prefs-memberingroups": "{{GENDER:$2|Angguta}}{{PLURAL:$1|galambang|gagalambang}}:",
        "prefs-registration": "Waktu pandaptaran:",
        "yourrealname": "Ngaran asli:",
        "yourlanguage": "Bahasa:",
        "prefs-help-signature": "Kumintar pada tungkaran pamandiran parlu ditandatangani awan \"<nowiki>~~~~</nowiki>\" nangapa akan taubah jadi tandatangan Pian wan waktu wayahini.",
        "badsig": "Tandatangan mantah kada sah.\nPariksa tag HTML.",
        "badsiglength": "Tapak tangan Sampian talalu panjang. Jangan malabihi pada $1 {{PLURAL:$1|karakter|karakter}}.",
-       "yourgender": "Janis kalamin:",
-       "gender-unknown": "Kada diajuakan",
-       "gender-male": "Lalakian",
-       "gender-female": "Bibinian",
-       "prefs-help-gender": "Opsional: dipuruk gasan mambaiki manyambat gindir ulih parangkat lunak. Panjalasan ngini akan tasingkai hagan umum.",
+       "yourgender": "Kaya apa pian handak dijalasakan?",
+       "gender-unknown": "Wayah manyambat pian, parangkat lunak pacangan mamakai kata netral wayah parlu",
+       "gender-male": "Inya (lakian) mambabak tungkaran wiki",
+       "gender-female": "Inya (binian) mambabak tungkaran wiki",
+       "prefs-help-gender": "Paraturan katujuan ngini opsional.\nParangkat lambik mamakai nilainya gasan maarahakan pian wan manyambat pian ka sabarataan pamakaian mamakai hiauan janis kalamin.\nInformasi nginji pacangan publik.",
        "email": "Suril",
        "prefs-help-realname": "Ngaran bujur adalah pilihan haja.\nAmun Pian mamilih manyadiakan ini, ini akan dipuruk gasan paminanduan kulihan gawian Pian.",
        "prefs-help-email": "Alamat suril adalah opsional, tagal pun parlu gasan mambulikakan setelan katasunduk, amunai Pian kada ingatan.",
        "prefs-diffs": "Bida",
        "userrights": "Pangalulaan hak-hak pamuruk",
        "userrights-lookup-user": "Mangalula gagalambang pamuruk",
-       "userrights-user-editname": "Buati sabuah ngaran pamuruk:",
+       "userrights-user-editname": "Masukakan ngaran pamakai:",
        "editusergroup": "Babak galambang pamuruk",
        "editinguser": "Ma-ubah hak ungkai pamuruk '''[[User:$1|$1]]''' $2",
        "userrights-editusergroup": "Babak galambang pamuruk",
        "userrights-groupsmember-auto": "Angguta tasirat matan:",
        "userrights-groups-help": "Pian kawa maubah galambang pamuruk ngini:\n* Kutak awan tanda cek artnya galambang pamuruk nang basangkutan\n* Kutak kada batanda cek artinya pamuruk ngini lainan angguta galambang ngitu\n* Tanda * manandai bahwasa Pian kada kawa mawalangi galambang ngitu amun Pian sudah manambahinya, atawa kabalikannya.",
        "userrights-reason": "Alasan:",
-       "userrights-no-interwiki": "Pian kada baisi ijin hagan mambabak hak pamuruk di wiki lain.",
+       "userrights-no-interwiki": "Pian kada baisi hak gasan maubah hak pamakai di wiki nang lain.",
        "userrights-nodatabase": "Basis data $1 kadada atawa lainan lukal.",
        "userrights-changeable-col": "Gagalambang nang Pian kawa ubah",
        "userrights-unchangeable-col": "Gagalambang nang Pian kada kawa ubah",
        "group-sysop-member": "{{GENDER:$1|pambakal}}",
        "group-bureaucrat-member": "{{GENDER:$1|birukrat}}",
        "group-suppress-member": "{{GENDER:$1|pangawas}}",
-       "grouppage-user": "{{ns:project}}: Pamuruk",
-       "grouppage-autoconfirmed": "{{ns:project}}: Pamuruk utumatis diyakinakan",
+       "grouppage-user": "{{ns:project}}: Pamakai",
+       "grouppage-autoconfirmed": "{{ns:project}}:Pamakai takunfirmasi utumatis",
        "grouppage-bot": "{{ns:project}}:Bot",
        "grouppage-sysop": "{{ns:project}}:Pambakal",
        "grouppage-bureaucrat": "{{ns:project}}:Birukrat",
        "right-minoredit": "Tandai bababakan sawagai sapalih",
        "right-move": "Mamindahakan tungkaran",
        "right-move-subpages": "Ugahakan tutungkaran awan subtumgkaran-nya",
-       "right-move-rootuserpages": "Ugahakan akar tutungkaran pamuruk",
+       "right-move-rootuserpages": "Mamindahakan tungkaran utama pamakai",
        "right-movefile": "Mamindahakan barakas",
        "right-suppressredirect": "Kada maulah paugahan matan tutungkaran asal mula parhatan tutungkan pindahan",
        "right-upload": "Unggahakan barakas",
        "right-bot": "Ditindak sawagai sabuah proses utumatis",
        "right-nominornewtalk": "Kadada babakan sapalih di tutungkaran pamandiran nang mancungulakan tampaian pasan puga",
        "right-apihighlimits": "Mamuruk watas kueri API tatinggi",
-       "right-writeapi": "Puruk panulisan API",
+       "right-writeapi": "Pakai panulisan API",
        "right-delete": "Mahapus tungkaran",
        "right-bigdelete": "Hapus tutungkaran awan hahalam ganal",
-       "right-deletelogentry": "Hapus wan walangakan pahapusan masukan log tartantu",
+       "right-deletelogentry": "Mahapus wan mamasahakan pahapusan masukan log tartantu",
        "right-deleterevision": "Mahapus wan mawalangi hapus raralatan tatantu matan tutungkaran",
        "right-deletedhistory": "Tiringi mamasukan halam tahapus, kada banaskah tarait",
        "right-deletedtext": "Tiringi naskah tahapus wan paubahan antar raralatan nang tahapus",
        "right-undelete": "Mambulikakan sabuah tungkaran tahapus",
        "right-suppressrevision": "Maniring pulang wan mambulikakan raralatan matan papambakal",
        "right-suppressionlog": "Tiringi log paribadi",
-       "right-block": "Blukir pamuruk lain mambabak",
-       "right-blockemail": "Blukir saurang pamuruk mangirimi suril",
+       "right-block": "Blukir pamakai lain matan pambabakan",
+       "right-blockemail": "Mamblukir pangiriman surél ulih pamakai",
        "right-hideuser": "Blukir sabuah ngaranpamuruk, sungkupakan ini matan umum",
        "right-ipblock-exempt": "Liwati blukir IP, blukir-utumatis wan aria blukir",
        "right-unblockself": "Lapas blukirnya surang",
        "right-protect": "Ubah tingkat parlindungan wan babakan tutungkaran nang diindungi",
        "right-editprotected": "Babak tungkaran nang dilindungi (kada parlindungan barenteng)",
-       "right-editinterface": "Babak antarmuha pamuruk ini",
+       "right-editinterface": "Mambabak antarmuha pamakai",
        "right-editusercss": "Babak pamruk lain babarakas CSS",
-       "right-edituserjson": "Babak pamuruk lain babarakas JSON",
-       "right-edituserjs": "Babak pamuruk lain babarakas JavaScript",
-       "right-rollback": "Mambulikakan hancap bababakan matan pamuruk tauncit nang mambabak sabuah tungkaran tatantu",
+       "right-edituserjson": "Mambabak barakas JSON pamakai lain",
+       "right-edituserjs": "Mambabak barakas JS pamakai lain",
+       "right-rollback": "Mambulikakan hancap babakan pamakai pauncitnya nang mambabak tungkaran tartantu",
        "right-markbotedits": "Tandai bababakan dibulikakan sawagai bababakan bot",
        "right-noratelimit": "Kada pangaruh awan watas rating",
        "right-import": "Impur tutungkaran matan wiwiki lain",
        "right-patrolmarks": "Tiringi tanda paubahan pahanyarnya",
        "right-unwatchedpages": "Tiringi sabuah daptar tutungkaran nang kada diitihi",
        "right-mergehistory": "Gabungakan halam matan tutungkaran",
-       "right-userrights": "Babak sabarataan hak pamuruk",
-       "right-userrights-interwiki": "Babak hahak pamuruk matan papamuruk wiwiki balain",
+       "right-userrights": "Babak sabarataan hak pamakai",
+       "right-userrights-interwiki": "Mambabak hak para pamakai di wiki lain",
        "right-siteadmin": "Sunduk wan buka sunduk basis data",
        "right-override-export-depth": "Ekspur tutungkaran tamasuk tutungkaran tataut sampai kadalaman 5",
        "right-sendemail": "Mangirim suril ka papamuruk lain",
        "newuserlogpage": "Log pamakai hanyar",
-       "newuserlogpagetext": "Ngini adalah sabuah log paulahan pamuruk.",
+       "newuserlogpagetext": "Di bawah ini log pandaptaran pamakai hanyar",
        "rightslog": "Log paubahan hak masuk",
        "rightslogtext": "Nangini sabuting log paubahan ka hak pamakai.",
        "action-read": "baca tungkaran ini",
        "action-edit": "babak tungkaran ini",
        "action-createpage": "ulah tutungkaran",
        "action-createtalk": "ulah tutungkaran pamandiran",
-       "action-createaccount": "ulah akun pamuruk ini",
+       "action-createaccount": "ulah akun pamakai ini",
        "action-minoredit": "tandai babakan ini sawagai sapalih",
        "action-move": "pindahakan tungkaran ini",
        "action-move-subpages": "pindahakan tungkaran ini, wan sub-tutungkarannya",
-       "action-move-rootuserpages": "mamindahakan akar tutungkaran pamuruk",
+       "action-move-rootuserpages": "mamindahakan laman utama pamakai",
        "action-movefile": "pindahakan barakas ini",
        "action-upload": "hunggahakan barakas ini",
        "action-reupload": "manimpa barakas nang ada",
        "action-undelete": "kada jadi mahapus tungkaran ini",
        "action-suppressrevision": "tilik wan bulikakan ralatan tasungkup ini",
        "action-suppressionlog": "tiringi log paribadi ini",
-       "action-block": "blukir pamuruk ini matan mambabak",
+       "action-block": "Blukir pamakai ngini matan mambabak",
        "action-protect": "Ubah tingkat parlindungan tungkaran ngini",
-       "action-rollback": "Mambulikakan hancap bababakan matan pamuruk tauncit nang mambabak sabuah tungkaran tatantu.",
+       "action-rollback": "Mambulikakan hancap babakan matan pamakai pauncitnya nang mambabak tungkaran tartantu.",
        "action-import": "Impur tungkaran ngini matan wiki lain",
        "action-importupload": "Impur tungkaran ngini matan sabuah barakas hunggahan",
        "action-patrol": "tandai babakan nang lain sawagai ta'awasi",
        "action-autopatrol": "Tandai babakan Pian sawagai ta'awasi",
        "action-unwatchedpages": "tiringi daptar tutungkaran nang kada diitihi",
        "action-mergehistory": "gabungakan halam matan tungkaran ngini",
-       "action-userrights": "babak sabarataan hak pamuruk",
-       "action-userrights-interwiki": "babak hak pamuruk matan papamuruk dalam wiwiki lain",
+       "action-userrights": "babak sabarataan hak pamakai",
+       "action-userrights-interwiki": "mambabak hak aksés matan pamakai di wiki lain",
        "action-siteadmin": "sunduk atawa bukasunduk basisdata",
        "action-sendemail": "Kirim suril",
        "nchanges": "$1 {{PLURAL:$1|paubahan|paubahan}}",
+       "enhancedrc-history": "sajarah",
        "recentchanges": "Paubahan pahanyarnya",
        "recentchanges-legend": "Pilihan paubahan pahanyarnya",
        "recentchanges-summary": "Jajak paubahan wiki pahanyarnya pada tungkaran ngini",
+       "recentchanges-noresult": "Kadada paubahan dalam rantang waktu ngini nang rasuk lawan syarat.",
        "recentchanges-feed-description": "Susuri paubahan pahanyarnya dalam wiki di kitihan ini",
        "recentchanges-label-newpage": "Babakan ngini maulah sabuting tungkaran hanyar",
-       "recentchanges-label-minor": "Ngini sabuting babakan sapalih",
-       "recentchanges-label-bot": "Babakan ngini digawi ulih saikung bot",
+       "recentchanges-label-minor": "Ngini babakan sapalih",
+       "recentchanges-label-bot": "Babakan ngini digawi ulih bot",
        "recentchanges-label-unpatrolled": "Babakan ngini baluman ta'awasi",
-       "recentchanges-legend-newpage": "$1 - tungkaran puga",
-       "rcnotefrom": "Di bawah ngini paubahan tumatan '''$2''' (ditampaiakan sampai '''$1''' paubahan)",
+       "recentchanges-label-plusminus": "Paubahan ukuran tungkaran dalam bita",
+       "recentchanges-legend-heading": "<strong>Katarangan:</strong>",
+       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (tiringi jua [[Special:NewPages|daptar tungkaran hanyar]])",
+       "rcnotefrom": "Di bawah ngini adalah {{PLURAL:$5|paubahan}} tumatan <strong>$3, $4</strong> (ditampaiakan sampai <strong>$1</strong> paubahan).",
        "rclistfrom": "Tampaiakan paubahan pahanyarnya matan $3 $2",
        "rcshowhideminor": "$1 pambabakan sapalih",
+       "rcshowhideminor-show": "Tampaiakan",
+       "rcshowhideminor-hide": "Sungkupakan",
        "rcshowhidebots": "$1 bot",
-       "rcshowhideliu": "$1 pamakai nang babuat di log",
+       "rcshowhidebots-show": "Tampaiakan",
+       "rcshowhidebots-hide": "Sungkupakan",
+       "rcshowhideliu": "$1 pamakai tadaptar",
+       "rcshowhideliu-show": "Tampaiakan",
+       "rcshowhideliu-hide": "Sungkupakan",
        "rcshowhideanons": "$1 pamakai kada bangaran",
+       "rcshowhideanons-show": "Tampaiakan",
+       "rcshowhideanons-hide": "Sungkupakan",
        "rcshowhidepatr": "$1 babakan ta'awasi",
        "rcshowhidemine": "$1 babakan ulun",
-       "rclinks": "Tampaiakan $1 paubahan pahanyarnya dalam $2 hari tauncit",
+       "rcshowhidemine-show": "Tampaiakan",
+       "rcshowhidemine-hide": "Sungkupakan",
+       "rclinks": "Tampaiakan $1 paubahan pahanyarnya dalam $2 hari pahabisnya",
        "diff": "bida",
-       "hist": "halam",
+       "hist": "riwayat",
        "hide": "Sungkupakan",
        "show": "Tampaiakan",
        "minoreditletter": "s",
        "newpageletter": "H",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|pa'itihi|papa'itihi}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|bita|bita}} limbah paubahan",
        "newsectionsummary": "/* $1 */ hagian hanyar",
        "rc-enhanced-expand": "Tampaiakan rincian (parlu ada JavaScript)",
        "recentchangeslinked-feed": "Paubahan tarait",
        "recentchangeslinked-toolbox": "Paubahan tarait",
        "recentchangeslinked-title": "Paubahan nang tarait lawan \"$1\"",
-       "recentchangeslinked-summary": "Ngini sabuting daptar paubahan nang diulah hahanyar ngini pada tungkaran batautan matan sabuting tungkaran tartantu (atawa ka angguta matan sabuah tumbung tartantu).\nTutungkaran dalam [[Special:Watchlist|daptar itihan Pian]] ditandai '''kandal'''.",
+       "recentchangeslinked-summary": "Masukakan ngaran halaman gasan malihat paubahan pada tungkaran tarait matan atawa ka tungkaran ngintu (amun handak malihat angguta sabuting tumbung, masukakan {{ns:category}}). Paubahan pada [[Special:Watchlist|daptar itihan Pian]] talihat <strong>dicitak kandal</strong>.",
        "recentchangeslinked-page": "Ngaran tungkaran:",
-       "recentchangeslinked-to": "Tampaiakan paubahan matan tutungkaran nang bataut lawan tungkaran nang disurungakan",
-       "upload": "Hunggahakan barakas",
+       "recentchangeslinked-to": "Tampaiakan paubahan matan tutungkaran nang barait lawan tungkaran nang disurungakan",
+       "upload": "Unggah barakas",
        "uploadbtn": "Hunggahakan barakas",
-       "reuploaddesc": "Walang mahunggah wan babulik ka purmulir hunggahan",
+       "reuploaddesc": "Babulik ka furmulir paunggahan",
        "upload-tryagain": "Kirim katarangan barakas taubah",
        "uploadnologin": "Baluman babuat log",
        "uploadnologintext": "Pian musti [[Special:UserLogin|babuat log]] amun handak mahunggah babarakas.",
        "zip-bad": "Barakas ngini korup atawa pinanya barakas ZIP nang kada kawa dibaca.\nBarakas ngini kada kawa dipariksa  gasan kaamanan.",
        "zip-unsupported": "Barakas ngini adalah sabuah barakas ZIP nang dipuruk pitur ZIP nang kada disukung ulih MediaWiki.\nNgini kada kawa dipariksa gasan kaamanan.",
        "uploadstash": "Simpanan hunggahan",
-       "uploadstash-summary": "Tungkaran ngini manyadiakan ungkaian ka babarakas nang tahunggah (atawa dalam proses hunggahan) tapi baluman ditarbitakan ka wiki.\nBabarakas ngini kada kawa dilihat ka siapa pun kacuali pamuruk nang mahunggahnya.",
+       "uploadstash-summary": "Tungkaran ngini manyadiaakan ungkaian ka barakas nang taunggah (atawa dalam prosés unggahan) tapi baluman ditarbitakan ka wiki.\nBarakas ngini kada kawa dijanaki ka siapa pun kacuali pamakai nang maunggahnya.",
        "uploadstash-clear": "Kalarakan babarakas simpanan.",
        "uploadstash-nofiles": "Pian kada baisi babarakas simpanan.",
        "uploadstash-badtoken": "Aksi kada ruhui dilaksanaakan, pinanya karana babakan Pian sudah kadaluarsa. Cubai pulang.",
        "img-auth-nopathinfo": "PATH_INFO hilang.\nServer Pian kada disetel hagan malimpatakan panjalasan ngini.\nNgini karana CGI-based wan kada manyukung img_auth.\nJanaki https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Jalur nang diminta kada ta'atur lawan direktori hunggahan.",
        "img-auth-badtitle": "Kada kawa mambangun sabuah judul sah matan \"$1\".",
-       "img-auth-nologinnWL": "Pian kada kawa babuat log wan '$1\" kadada dalam daptar putih.",
        "img-auth-nofile": "Barakas \"$1\" kadada.",
        "img-auth-isdir": "Pian mancuba hagan maungkai sabuah direktori \"$1\".\nHanya maungkai barakas dibulihakan.",
        "img-auth-streaming": "Streaming \"$1\".",
        "img-auth-public": "Pungsi img_auth.php mangaluarakan babarakas matan sabuah wiki paribadi.\nWiki ngini diatur sawagai wiki umum.\nGasan kaamanan baik, img_auth.php dipajahakan.",
-       "img-auth-noread": "Pamuruk kada baisi hak ungkai hagan mambaca \"$1\".",
+       "img-auth-noread": "Pamakai kada baisi hak ungkai gasan mambaca \"$1\".",
        "http-invalid-url": "URL kada sah: $1",
        "http-invalid-scheme": "URL lawan skema \"$1\" kada disukung.",
        "http-request-error": "Maminta HTTP gagal karana kasalah kada dikatahui.",
        "listfiles_thumb": "Pahalusan",
        "listfiles_date": "Tanggal",
        "listfiles_name": "Ngaran",
-       "listfiles_user": "Pamuruk",
+       "listfiles_user": "Pamakai",
        "listfiles_size": "Ukuran",
        "listfiles_description": "Pamaparan",
        "listfiles_count": "Janis",
        "file-anchor-link": "Barakas",
-       "filehist": "Barakas halam",
-       "filehist-help": "Klik pada tanggal/waktu gasan maniringi barakas ngini pada wayah itu.",
+       "filehist": "Riwayat barakas",
+       "filehist-help": "Klik pada tanggal/waktu gasan manjanaki barakas ngini wayah itu.",
        "filehist-deleteall": "hapus samunyaan",
        "filehist-deleteone": "hapus",
        "filehist-revert": "bulikakan",
-       "filehist-current": "daminian",
+       "filehist-current": "wayahini",
        "filehist-datetime": "Tanggal/Waktu",
-       "filehist-thumb": "Pahalusan",
+       "filehist-thumb": "Miniatur",
        "filehist-thumbtext": "Pahalusan gasan bantuk per $1",
-       "filehist-nothumb": "Kadada thumbnail",
+       "filehist-nothumb": "Kadada miniatur",
        "filehist-user": "Pamakai",
        "filehist-dimensions": "Matra",
        "filehist-filesize": "Ukuran barakas",
        "filehist-comment": "Ulasan",
        "imagelinks": "Tautan barakas",
-       "linkstoimage": "{{PLURAL:$1|tautan tungkaran|$1 tautan tungkaran}} dudi ka barakas ngini:",
-       "linkstoimage-more": "Labihan pada $1 {{PLURAL:$1|tatautan tungkaran|tautan tutungkaran}} ka barakas ngini.\nDaptar barikut manampaiakan {{PLURAL:$1|tautan panambaian tungkaran|$1 panambaian tatautan tungkaran}} ka barakas ngini haja.\nSabuah [[Special:WhatLinksHere/$2|daptar hibak]] tasadia.",
-       "nolinkstoimage": "Kadada tutungkaran nang bataut ka barakas ngini.",
+       "linkstoimage": "{{PLURAL:$1|Tungkaran|$1 tungkaran}} nangini mamakai barakas ngini:",
+       "linkstoimage-more": "Labih daripada $1 {{PLURAL:$1|pamakaian tungkaran|pamakaian tutungkaran}} ka barakas ngini.\nDaptar barikut manampaiakan {{PLURAL:$1|tungkaran panambaian|$1 tungkaran panambaiam}} nang mamakai barakas ngini haja.\nSabuah [[Special:WhatLinksHere/$2|daptar hibak]] tasadia.",
+       "nolinkstoimage": "Kadada tutungkaran nang mamakai barakas ngini.",
        "morelinkstoimage": "Tiringi [[Special:WhatLinksHere/$1|tautan lagi]] ka barakas ngini.",
        "linkstoimage-redirect": "$1 (barakas paugahan) $2",
        "duplicatesoffile": "Barikut {{PLURAL:$1|barakas panggandaan|$1 babarakas panggandaan}} matan barakas ngini ([[Special:FileDuplicateSearch/$2|rarincian labih]]):",
        "uploadnewversion-linktext": "Buatakan bantuk nang labih hanyar matan barakas ini",
        "shared-repo-from": "matan $1",
        "shared-repo": "suatu repositori basama",
+       "upload-disallowed-here": "Pian kada kawa manimpa barakas ngini.",
        "filerevert": "Bulikakan $1",
        "filerevert-legend": "Bulikakan barakas",
        "filerevert-intro": "Pian mambulikakan '''[[Media:$1|$1]]''' ka macam [$4 pada $3, $2].",
        "statistics": "Statistik",
        "statistics-header-pages": "Statistik tungkaran",
        "statistics-header-edits": "Statistik babakan",
-       "statistics-header-users": "Statistik pamuruk",
+       "statistics-header-users": "Statistik pamakai",
        "statistics-header-hooks": "Statistik lainnya",
        "statistics-articles": "Tungkaran isi",
        "statistics-pages": "Jumlah tungkaran",
        "statistics-files": "Barakas nang dihunggahakan",
        "statistics-edits": "Jumlah babakan tumatan {{SITENAME}} dimulai",
        "statistics-edits-average": "Rata-rata babakan par tungkaran",
-       "statistics-users": "Jumlah pamuruk tadaptar",
-       "statistics-users-active": "Jumlah pamuruk aktip",
-       "statistics-users-active-desc": "Pamuruk nang sudah malakukan suatu aksi dalam {{PLURAL:$1|sahari|$1 hari}} tauncit.",
+       "statistics-users": "Jumlah pamakai tadaptar",
+       "statistics-users-active": "Jumlah pamakai aktip",
+       "statistics-users-active-desc": "Pamakai nang sudah malakukan suatu gawian dalam {{PLURAL:$1|sahari|$1 hari}} pauncitnya.",
        "doubleredirects": "Paugahan ganda",
        "doubleredirectstext": "Tungkaran ngini mandaptar tutungkaran nang maugah ka tutungkaran ugahan lain.\nTiap baris mangandung tautan ka ugahan panambaian wan kadua, sasarannya adalah ugahn kadua, nang biasanya tungkaran sasaran \"sabujurnya\", nang ugahan partama tuju.\nMasukan nang <del>Disilangi</del> sudah dibaiki.",
        "double-redirect-fixed-move": "[[$1]] sudah dipindahakan.\nNgini wayah ini sudah diugahakan ka [[$2]].",
        "protectedpagesempty": "Kadada tutungkaran nang masih dilindungi awan paramitir ngitu.",
        "protectedtitles": "Jujudul nang dilindungi",
        "protectedtitlesempty": "Kadada jujudul nang masih dilindungi awan paramitir ngitu.",
-       "listusers": "Daptar pamuruk",
+       "listusers": "Daptar pamakai",
        "listusers-editsonly": "Tiringi papamuruk awan babakan",
        "listusers-creationsort": "Susun ulih tanggal paulahan",
        "usereditcount": "$1 {{PLURAL:$1|babakan|bababakan}}",
        "unusedimagestext": "Babarakas barikut ada tagal kada diumpatakan di tungkaran mamana.\nMuhun catat bahwasa situs web lain pina-ai bataut ka sabuah barakas awan sabuah URL langsung, wan karana ngini masih-ha didaptar di sia biar gin aktip dipuruk.",
        "unusedcategoriestext": "Tumbung tutungkaran barikut ada, walaupun kadada tungkaran lain atawa tumbung mamuruknya.",
        "notargettitle": "Kadada tujuan",
-       "notargettext": "Pian kada maajuakan sabuah tungkaran atawa pamuruk sasaran malakuakan palakuan ini.",
+       "notargettext": "Pian kada manantuakan tungkaran atawa pamakai tujuan tugas ngini.",
        "nopagetitle": "Kadada tungkaran sasaran",
        "nopagetext": "Tungkaran sasaran nang Pian ajuakan kadada.",
        "pager-newer-n": "{{PLURAL:$1|labih hanyar 1|labih hanyar $1}}",
        "suppress": "Pangawasan",
        "querypage-disabled": "Tungkaran istimiwa ngini dikada-kawakan gasan alasan ginawi.",
        "booksources": "Buku bamula",
-       "booksources-search-legend": "Gagai gasan buku asal mula",
+       "booksources-search-legend": "Kikih di asal mula buku",
+       "booksources-search": "Kikih",
        "booksources-text": "Di bawah adalah sabuah daptar tautan ka situs lain nang manjual bubuku hanyar wan bakas, wan jua baisi panjalasan labih pasal bubuku nang Pian ugai:",
        "booksources-invalid-isbn": "ISBN nang dibari mancungul kada sah; pariksa kalua-ai tasalah marekap matan asal-mula aslinya.",
        "specialloguserlabel": "Pamakai:",
-       "speciallogtitlelabel": "Tujuan (judul atawa pamakai):",
+       "speciallogtitlelabel": "Tujuan (judul atawa {{ns:user}}:ngaran pamakai gasan pamakai)",
        "log": "Log",
        "all-logs-page": "Samunyaan log umum",
-       "alllogstext": "Tampaian baimbai matan sabataan log nang ada matan {{SITENAME}}.\nPian kada mawatasi tiringan lawan mamilih sabuah macam log, ngaran-pamuruk (sansitip kapital), atawa tungkaran tapangaruh (sansitip kapital jua).",
+       "alllogstext": "Tampaian baimbai matan sabataan log nang ada matan {{SITENAME}}.\nPian kada mawatasi tiringan lawan mamilih sabuah macam log, ngaran-pamakai (sansitip kapital), atawa tungkaran tapangaruh (sansitip kapital jua).",
        "logempty": "Kadada barang nang parsis pintang log.",
        "log-title-wildcard": "Gagai judul ba-awalan awan naskah ngini",
        "showhideselectedlogentries": "Tampaiakan/sungkupakan masukan log tapilih",
        "categories": "Tutumbung",
        "categoriespagetext": "{{PLURAL:$1|tumbung mangandung|tutumbung mangandung}} barikut baisi tutungkaran atawa midia.\n[[Special:UnusedCategories|Tumbung kada dipuruk]] kada ditampaiakan di sia.\nJanaki jua [[Special:WantedCategories|tutumbung nang dihandaki]].",
        "categoriesfrom": "Manampaiakan tutumbung mulai matan:",
-       "deletedcontributions": "Hapus sumbangan pamuruk",
-       "deletedcontributions-title": "Hapus sumbangan pamuruk",
+       "deletedcontributions": "Sumbangan nang dihapus",
+       "deletedcontributions-title": "Sumbangan nang dihapus",
        "sp-deletedcontributions-contribs": "Sumbangan",
        "linksearch": "Manggagai tautan luar",
        "linksearch-pat": "Gagai bapola:",
        "linksearch-error": "Kartu-liar mancungul pintang awalan matan ngaranhost.",
        "listusersfrom": "Manampaiakan papamuruk mulai matan:",
        "listusers-submit": "Tampaiakan",
-       "listusers-noresult": "Kadada pamuruk tatamu.",
+       "listusers-noresult": "Pamakai kada tahaga.",
        "listusers-blocked": "(diblukir)",
-       "activeusers": "Daptar pamuruk aktip",
+       "activeusers": "Daptar pamakai aktip",
        "activeusers-intro": "Ngini adalah sabuah daptar papamuruk sabuah bantuk kagiatan dalam tauncit $1 {{PLURAL:$1|hari|hahari}}.",
        "activeusers-count": "$1 {{PLURAL:$1|babak|babakan}} dalam tauncit {{PLURAL:$3|hari|$3 hahari}}",
        "activeusers-from": "Manampaiakan papamuruk mulai matan:",
        "activeusers-noresult": "Kadada papamuruk tatamu.",
-       "listgrouprights": "Galambang hak pamuruk",
-       "listgrouprights-summary": "Barikut adalah sabuah daptar matan galambang pamuruk nang ada di wiki ngini, lawan hak ungkai masing-masing.\nAda di [[{{MediaWiki:Listgrouprights-helppage}}|tambahan panjalasan]] pasal hak par urangan.",
+       "listgrouprights": "Daptar hak galambang",
+       "listgrouprights-summary": "Nangini daptar galambang pamakai nang tahaga di wiki ini, lawan daptar hak maungkai bubuhannya. Maklumat salanjutnya sual hak masing-masing kawa ditamuakan di [[{{MediaWiki:Listgrouprights-helppage}}|tungkaran patulung hak pamakai]].",
        "listgrouprights-key": "* <span class=\"listgrouprights-granted\">Hak nang balaku</span>\n* <span class=\"listgrouprights-revoked\">Hak nang dicukut</span>",
        "listgrouprights-group": "Galambang",
        "listgrouprights-rights": "Hak",
        "mailnologintext": "Pian musti [[Special:UserLogin|babuat log]] wan baisi sabuah alamat suril sah di [[Special:Preferences|kakatujuan]] Pian hagan mangirim suril ka papamuruk lain.",
        "emailuser": "Suril pamakai",
        "emailpagetext": "Pian kawa mamuruk purmulir di bawah hagan mangirim sabuah suril ka pamuruk ngini.\nAlamat sril Pian pintang [[Special:Preferences|kakatujuan pamuruk Pian]] akan cungul  sawagai \"Matan\" alamat suril, lalu-ai panarima akan kawa langsung mambalas ka Pian.",
-       "defemailsubject": "Suril {{SITENAME}} matan pamuruk \"$1\"",
-       "usermaildisabled": "Suril pamuruk dipajahakan",
+       "defemailsubject": "Surél {{SITENAME}} matan pamakai \"$1\"",
+       "usermaildisabled": "Surél pamakai dipajahakan",
        "usermaildisabledtext": "Pian kada kawa mangirim suril ka papamuruk lain di wiki ngini",
        "noemailtitle": "Kadada alamat suril",
-       "noemailtext": "Pamuruk ngini kada baisi sabuah alamat suril sah nang diajuakan.",
-       "nowikiemailtext": "Pamuruk ngini sudah mamilih kada manarima suril matan papamuruk lain.",
+       "noemailtext": "Pamakai ngini kada baisi alamat surél sah nang diajuakan.",
+       "nowikiemailtext": "Pamakai ngini sudah mamilih kada manarima surél matan pamakai lain.",
        "emailnotarget": "Kada-tasadia atawa ngaranpamuruk kada sah gasan panarima.",
        "emailtarget": "Buati ngaranpamuruk panarima",
        "emailusername": "Ngaranpamuruk:",
        "emailusernamesubmit": "Kirim",
-       "email-legend": "Kirimi sabuah suril ka pamuruk {{SITENAME}} lain",
+       "email-legend": "Kirimi surél ka pamakai {{SITENAME}} lainnya",
        "emailfrom": "Matan:",
        "emailto": "Hagan:",
        "emailsubject": "Parihal:",
        "emailuserfooter": "Suril ngini dikirim ulih $1 hagan $2 lung pungsi \"Suril pamuruk\" pada {{SITENAME}}.",
        "usermessage-summary": "Tinggalakan sistim pasan.",
        "usermessage-editor": " Sistim panyampai pasan",
-       "watchlist": "Daptar itihan ulun",
-       "mywatchlist": "Daptar itihan ulun",
+       "watchlist": "Daptar itihan",
+       "mywatchlist": "Daptar itihan",
        "watchlistfor2": "Gasan $1 $2",
        "nowatchlist": "Pian kada baisi apa pun pada daptar itihan Pian.",
        "watchlistanontext": "Muhun $1 hagan maniringi atawa mambabak nang dalam daptar itihan Pian.",
        "removedwatchtext": "Tungkaran \"[[:$1]]\" sudah dihapus matan [[Special:Watchlist|daptar itihan]] Pian.",
        "watch": "Itih",
        "watchthispage": "Itihi tungkaran ini",
-       "unwatch": "walang maitihi",
+       "unwatch": "Pasah maitihi",
        "unwatchthispage": "Mandak maitihi",
        "notanarticle": "Lainan sabuting tungkaran isi",
-       "notvisiblerev": "Ralatan tauncit ulih saurang pamuruk babida sudah dihapus",
-       "watchlist-details": "{{PLURAL:$1|$1 tungkaran|$1 tungkaran}} dalam daptar itihan Pian, kada mahitung tungkaran pamandiran.",
+       "notvisiblerev": "Ralatan sudah dihapus",
+       "watchlist-details": "Tahaga {{PLURAL:$1|$1 tungkaran|$1 tungkaran}} di daptar itihan Pian, (tamasuk tungkaran pamandiran).",
        "wlheader-enotif": "Suril pamadahan dipajahi.",
-       "wlheader-showupdated": "Tutungkaran nang ba-ubah tumatan ilangan tauncit Pian ditampaiakan dalam '''hurup kandal'''",
-       "wlnote": "Di bawah naya adalah {{PLURAL:$1|paubahan|'''$1''' paubahan}} tauncit dalam '''$2''' jam tauncit, par $3, $4.",
+       "wlheader-showupdated": "Tutungkaran nang ba-ubah tumatan ilangan tauncit Pian ditampaiakan dalam <strong>hurup kandal</strong>.",
+       "wlnote": "Dibawah ngini adalah {{PLURAL:$1|paubahan pahabisan|<strong>$1</strong> paubahan pahabisan}} dalam {{PLURAL:$2|sajam|<strong>$2</strong> jam}} par $3, $4.",
        "wlshowlast": "Tampaiakan $1 jam $2 hari pahabisan",
        "watchlist-options": "Pilihan daptar itihan",
        "watching": "Maitihi...",
        "unwatching": "Kada jadi maitihi...",
        "watcherrortext": "Sabuting kasalahan tajadi parhatan setelan paitihan Pian diubah gasan \"$1\".",
        "enotif_reset": "Tandai samunyaan tutungkaran sudah diilangi",
-       "enotif_impersonal_salutation": "Pamuruk {{SITENAME}}",
+       "enotif_impersonal_salutation": "Pamakai {{SITENAME}}",
        "enotif_subject_deleted": "Tungkaran $1 di {{SITENAME}} hudah dihapus ulih {{gender:$2|$2}}",
        "enotif_subject_created": "Tungkaran $1 di {{SITENAME}} hudah diulah ulih {{gender:$2|$2}}",
        "enotif_subject_moved": "Tungkaran $1 di {{SITENAME}} hudah dipindahakan ulih {{gender:$2|$2}}",
        "delete-warning-toobig": "Tungkaran ngini baisi halam babakan ganal, labih pada $1 {{PLURAL:$1|ralatan|raralatan}}.\nMahapus ngini kawa mangaruhi databasis oparasi {{SITENAME}};\njalanakan awan ba-a-awas.",
        "rollback": "Gulung bulik babakan",
        "rollbacklink": "bulikakan",
+       "rollbacklinkcount": "bulikakan $1 {{PLURAL:$1|babakan}}",
        "rollbackfailed": "Guling-bulik luput",
        "cantrollback": "Kada kawa mambalikakan babakan;\npanyumbang tauncit adalah asa-asanya panulis tungkaran ngini.",
-       "alreadyrolled": "Kada kawa malakukan pambulikan ka ralatan tauncit [[:$1]] ulih [[User:$2|$2]] ([[User talk:$2|pandir]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]);\npamuruk lain sudah mambabak atawa malakukan pambulikan lawan tungkaran ini.\n\nBabakan tauncit dilakukan ulih [[User:$3|$3]] ([[User talk:$3|pandir]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
+       "alreadyrolled": "Kada kawa malakukan pambulikan ka ralatan pauncitnya [[:$1]] ulih [[User:$2|$2]] ([[User talk:$2|pandir]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]);\npamakai lain sudah mambabak atawa malakukan pambulikan lawan tungkaran ngini.\n\nBabakan pauncitnya dilakukan ulih [[User:$3|$3]] ([[User talk:$3|pandir]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
        "editcomment": "Kumintar pambabakan adalah: <em>$1</em>.",
        "revertpage": "←Babakan [[Special:Contributions/$2|$2]] ([[User talk:$2|pandir]]) dibulikakan ka ralatan tauncit ulih [[User:$1|$1]]",
        "revertpage-nouser": "Pambulikan babakan ulih (pamuruk dihapus) ka babakan tauncit ulih [[User:$1|$1]]",
        "protect-locked-dblock": "Tingkat palindungan kada kawa diubah marga ada sabuting sunduk databasis aktip.\nDi sia adalah setelan pahanyarnya gasan tungkaran '''$1''':",
        "protect-locked-access": "Akun Pian kada baisi ijin gasan maubah tingkatan palindungan tungkaran.\nDi sia adalah pangaturan wayah ini gasan tungkaran '''$1''':",
        "protect-cascadeon": "Tungkaran ini rahatan dilindungi lantaran diumpatakan dalam {{PLURAL:$1|tungkaran|tungkaran-tungkaran}} barikut nang sudah aktip palindungan barénténgnya.\nPian kawa maubah tingkatan palindungan gasan tungkaran ini, tagal ini kada pacang mangaruhi palindungan barénténg.",
-       "protect-default": "Bulihakan samua pamuruk",
+       "protect-default": "Bulihakan samunyaan pamakai",
        "protect-fallback": "Wastu gasan pamakai lawan ijin \"$1\"",
        "protect-level-autoconfirmed": "Blukir pamakai hanyar wan kada tadaptar",
        "protect-level-sysop": "Wastu pambakal",
        "namespace_association": "Ruang-ngaran tarait",
        "tooltip-namespace_association": "Pariksa kutak ngini hagan maumpatakan jua ruang-ngaran pamandiran atawa judul tarait awan ruang-ngaran tapilih",
        "blanknamespace": "(Tatambaian)",
-       "contributions": "Sumbangan pamakai",
+       "contributions": "Sumbangan {{GENDER:$1|pamakai}}",
        "contributions-title": "Sumbangan pamakai gasan $1",
-       "mycontris": "Sumbangan ulun",
-       "contribsub2": "Gasan $1 ($2)",
+       "mycontris": "Sumbangan",
+       "anoncontribs": "Sumbangan",
+       "contribsub2": "Gasan {{GENDER:$3|$1}} ($2)",
        "nocontribs": "Kadada paubahan nang rasuk lawan syarat itu.",
-       "uctop": " atas",
+       "uctop": "wayah ini",
        "month": "Matan bulan (wan sabalumnya):",
        "year": "Matan tahun (wan sabalumnya):",
        "sp-contributions-newbies": "Tampaiakan sumbangan papamakai hanyar haja",
        "sp-contributions-newbies-title": "Sumbangan pamakai gasan akun hanyar",
        "sp-contributions-blocklog": "Log blukir",
        "sp-contributions-deleted": "Tahapus sumbangan pamuruk",
-       "sp-contributions-uploads": "hunggahan",
+       "sp-contributions-uploads": "unggahan",
        "sp-contributions-logs": "log",
        "sp-contributions-talk": "pandir",
        "sp-contributions-userrights": "pangalulaan hak-hak pamuruk",
-       "sp-contributions-blocked-notice": "Pamuruk ngini parhatan diblukir.\nLog blukir pahabisannya tasadia di bawah ni gasan rujukan:",
+       "sp-contributions-blocked-notice": "Pamakai ngini parhatan diblukir.\nLog blukir pahabisnya tasadia di bawah ngini gasan rujukan:",
        "sp-contributions-blocked-notice-anon": "Alamat IP ngini parhatan ini diblukir.\nLog blukir pahabisannya tasadia di bawah ngini gasan rujukan:",
-       "sp-contributions-search": "Gagai gasan sumbangan",
+       "sp-contributions-search": "Kikihi sumbangan",
        "sp-contributions-username": "Alamat IP atawa ngaran-pamakai:",
        "sp-contributions-toponly": "Tampaiakan wastu ralatan nang paling atas (pauncitnya)",
-       "sp-contributions-submit": "Gagai",
-       "whatlinkshere": "Tautan apa di sia",
+       "sp-contributions-newonly": "Hanya tampaiakan babakan nang barupa paulahan tungkaran",
+       "sp-contributions-submit": "Kikih",
+       "whatlinkshere": "Tautan balik",
        "whatlinkshere-title": "Tungkaran-tungkaran nang batautan ka ''$1''",
        "whatlinkshere-page": "Tungkaran:",
-       "linkshere": "Tungkaran-tungkaran barikut batautan ka '''$2''':",
+       "linkshere": "Tungkaran-tungkaran barikut batautan ka <strong>$2</strong>:",
        "nolinkshere": "Kadada tutungkaran tataut ka '''$2'''.",
        "nolinkshere-ns": "Kadada tutungkaran tataut ka '''$2''' dalam ruang-ngaran nang dipilih.",
        "isredirect": "tungkaran paugahan",
        "whatlinkshere-hideredirs": "$1 paugahan",
        "whatlinkshere-hidetrans": "$1 transklusi",
        "whatlinkshere-hidelinks": "$1 tautan",
-       "whatlinkshere-hideimages": "$1 tautan pancitraan",
+       "whatlinkshere-hideimages": "$1 tautan barakas",
        "whatlinkshere-filters": "Saringan",
        "autoblockid": "Blukir utumatis #$1",
-       "block": "Blukir pamuruk",
-       "unblock": "Lapas blukir pamuruk",
+       "block": "Blukir pamakai",
+       "unblock": "Buka blukir pamakai",
        "blockip": "Blukir pamuruk",
        "blockiptext": "Puruk purmulir di bawah hagan mamblukir hak ungkai manulis matan sabuah alamat IP atawa ngaran-pamuruk.\nNgini dipuruk hagan mancagah vandalisma haja, wan sasuai awan [[{{MediaWiki:Policy-url}}|kabijakan]].\nIsi sabuah alasan khas di bawah (gasan cuntuh, manulisakan tutungkaran nang suah divandal)",
-       "ipaddressorusername": "Alamat IP atawa ngaran pamuruk:",
+       "ipaddressorusername": "Alamat IP atawa ngaran pamakai:",
        "ipbreason": "Alasan:",
-       "ipbreason-dropdown": "*Alasan awam pamblukiran\n** Mambuati panjalasan salah\n** Mambuang isi matan tutungkaran\n** Spam tautan ka luar\n** Mambuati pandiran kusung/ratik ka tutungkaran\n** Parilaku palecehan/intimidasi\n** Panyalahpurukan akun banyak\n** Ngaran-pamuruk kada-kawa-ditarima",
-       "ipb-hardblock": "Cagah pamuruk tadaptar gasan mambabak matan alamat IP ngini",
+       "ipbreason-dropdown": "*Alasan umum\n** Vandalisma\n** Mambariakan katarangan kada bujur alias palsu\n** Mahilangakan isi tungkaran\n** Spam tautan ka situs luar\n** Mangaradau ka tungkaran\n** Parilaku intimidasi/mancapa\n** Manyalahgunaakan babarapa akun\n** Ngaran pamakai kada layak",
+       "ipb-hardblock": "Tangati pamakai tadaptar gasan mambabak matan alamat IP ngini",
        "ipbcreateaccount": "Tangkal paulahan akun",
        "ipbemailban": "Tangkal pamuruk mangirimi suril",
-       "ipbenableautoblock": "Utumatis blukir alamat IP tauncit dipuruk ulih pamuruk ngini, wan sabarataan aalamat IP nang cuba dipuruk matan",
-       "ipbsubmit": "Blukir pamuruk ngini",
+       "ipbenableautoblock": "Utumatis blukir alamat IP pauncitnya nang dipakai pamakai ngini, wan sabarataan alamat IP nang cuba dipakai gasan mambabak.",
+       "ipbsubmit": "Blukir pamakai ngini",
        "ipbother": "Wayah lain:",
        "ipboptions": "2 jam:2 hours,1 hari:1 day,3 hari:3 days,1 minggu:1 week,2 minggu:2 weeks,1 bulan:1 month,3 bulan:3 months,6 bulan:6 months,1 tahun:1 year,salawasan:infinite",
        "ipbhidename": "Sungkupakan ngaranpamuruk matan babakan wan dadaptar",
-       "ipbwatchuser": "Itihi tutungkaran pamuruk wan pamandiran pamuruk ngini",
+       "ipbwatchuser": "Itihi tungkaran pamakai wan pamandiran pamakai ngini",
        "ipb-disableusertalk": "Tangkal pamuruk ngini mambabak tungkaran pamandirannya wayah diblukir",
-       "ipb-change-block": "Blukir pulang pamuruk lawan setelan ngingini",
+       "ipb-change-block": "Blukir pulang pamakai lawan setélan ngini",
        "ipb-confirm": "Yakinakan blukir",
        "badipaddress": "Alamat IP kada sah",
        "blockipsuccesssub": "Pamblukiran ruhui",
        "blockipsuccesstext": "[[Special:Contributions/$1|$1]] hudah diblukir.<br />\nJanaki [[Special:BlockList|daptar dibluk]] hagan maniring-pulang blukir.",
        "ipb-blockingself": "Pian pasal mamblukir Pian surang! Bujurkah Pian mahandaki ngitu?",
-       "ipb-confirmhideuser": "Pian pasal mamblukir saurang pamuruk awan \"sungkupakan pamuruk\" di-kawa-akan. Ngini akan manikin/kadada ngaran pamuruk dalam samunyaan daptar wan log masukan. Pian yakin kah handak manggawi ngitu?",
+       "ipb-confirmhideuser": "Pian handak mamblukir saurang pamakai lawan \"sungkupakan pamakai\" di-kawa-akan. Ngini akan manikin/kadada ngaran pamakai dalam samunyaan daptar wan log masukan. Pian yakin kah handak manggawi ngitu?",
        "ipb-edit-dropdown": "Aalasan pamblukiran babakan",
        "ipb-unblock-addr": "Mahilangakan blukir $1",
        "ipb-unblock": "Lapas blukir sabuah ngaranpamuruk atawa alamat IP",
        "ipb-blocklist": "Tiringi blukir nang ada",
        "ipb-blocklist-contribs": "Sumbangan gasan $1",
        "block-expiry": "Kadaluwarsa:",
-       "unblockip": "Lapas blukir pamuruk",
-       "unblockiptext": "Puruk purmulir di bawah hagan manyimpan-pulang hak ungkai manulai sabuah alamat IP atawa ngaran-pamuruk nang sabalumnya diblukir.",
+       "unblockip": "Buka blukir pamakai",
+       "unblockiptext": "Pakai purmulir di bawah gasan manyimpan-pulang hak ungkai manulis sabuting alamat IP atawa ngaran-pamakai nang sabalumnya diblukir.",
        "ipusubmit": "Buang blukir ngini",
        "unblocked": "[[User:$1|$1]] sudah dicabut blukirnya",
        "unblocked-range": "$1 sudah dilapas blukirnya",
        "unblocked-id": "Blukir $1 sudah dibuang",
-       "blocklist": "Pamuruk tablukir",
+       "blocklist": "Daptar pamakai nang diblukir",
        "ipblocklist": "Pamakai tablukir",
-       "ipblocklist-legend": "Ugai saurang pamuruk tablukir",
+       "ipblocklist-legend": "Gagai saurang pamakai nang diblukir",
        "blocklist-userblocks": "Sungkupakan pamblukiran akun",
        "blocklist-tempblocks": "Sungkupakan pamblukiran samantara",
        "blocklist-addressblocks": "Sungkupakan pamblukiran asa IP",
        "emaillink": "kirim suril",
        "autoblocker": "Utumatis blukir karana alamat IP Pian hahanyar ni dipuruk ulih \"[[User:$1|$1]]\".\nAlasan nang dibari gasan pamblukiran $1 adalah: \"$2\"",
        "blocklogpage": "Log blukir",
-       "blocklog-showlog": "Pamuruk ngini diblukir sabalumnya.\nLog blukir disadiakan di bawah gasan rujukan:",
-       "blocklog-showsuppresslog": "Pamuruk ngini diblukir wan disungkupakan sabalumnya.\nLog panikinan disadiakan di bawah gasan rujukan:",
+       "blocklog-showlog": "Pamakai ngini diblukir sabalumnya.\nLog blukir disadiaakan di bawah gasan rujukan:",
+       "blocklog-showsuppresslog": "Pamakai ngini diblukir wan disungkupakan sabalumnya.\nLog panikinan disadiaakan di bawah gasan rujukan:",
        "blocklogentry": "mamblukir [[$1]] sampai wayah $2 $3",
        "reblock-logentry": "setelan blukir diubah gasan [[$1]] awan sabuah wayah kadaluarsa $2 $3",
-       "blocklogtext": "Ngini adalah log matan blukir wan lapas-blukir pamuruk.\nBlukir alamat IP utumatis kada tadaptar.\nJanaki [[Special:BlockList|daptar diblukir]] gasan daptar uprasi dibabat wan pamblukiran pahanyarnya.",
+       "blocklogtext": "Ngini itu log aksi pamblukiran wan pambukaan blukir ka pamakai.\nAlamat IP nang diblukir sacara utumatis kada tahaga di dalam daptar ngini.\nLihat [[Special:BlockList|daptar pamblukiran]] gasan samunyaan pamakai nang wayahini diblukir.",
        "unblocklogentry": "Mahilangakan blukir \"$1\"",
        "block-log-flags-anononly": "papamuruk kada bangaran haja",
        "block-log-flags-nocreate": "Paulahan akun dipajahakan",
        "block-log-flags-noemail": "suril diblukir",
        "block-log-flags-nousertalk": "kada kawa mambabak tungkaran pamandiran surang",
        "block-log-flags-angry-autoblock": "paningkatan utumatis-blukir dikawa-akan",
-       "block-log-flags-hiddenname": "ngaran-pamuruk tasungkup",
+       "block-log-flags-hiddenname": "ngaran pamakai tasuhuk",
        "range_block_disabled": "Ka-kawa-an pambakal hagan maulah blukir wilayah dikada-kawakan.",
        "ipb_expiry_invalid": "Wayah kadaluwarsa kada sah.",
-       "ipb_expiry_temp": "Pamblukiran ngaran-pamuruk tasungkup musti tatap.",
+       "ipb_expiry_temp": "Pamblukiran ngaran-pamakai tasuhuk musti tatap.",
        "ipb_hide_invalid": "Kada kawa manikin akun ngini; ngini pinanya baisi banyak banar babakan.",
        "ipb_already_blocked": "\"$1\" sudah diblukir",
        "ipb-needreblock": "$1 sudah diblukir. Pian handakkah maubah setelan ngini?",
        "ipb-otherblocks-header": "{{PLURAL:$1|pamblukiran|papamblukiran}} lain",
-       "unblock-hideuser": "Pian kada kawa malapas blukir  pamuruk ngini, karana ngaran pamuruknya sudah disungkupakan.",
+       "unblock-hideuser": "Pian kada kawa malapas blukir pamakai ngini, marga ngaran pamakainya sudah disungkupakan.",
        "ipb_cant_unblock": "Kasalahan: ID tablukir $1 kada ta-ugai. Ngini pinanya sudah dilapas-blukirnya.",
        "ipb_blocked_as_range": "Kasalahan: Alamat IP $1 kada diblukir langsung wan kada kawa dilaps-blukirnya.\nNgini, kayapa pun, diblukir sawagai palihan wilayah $2, nang kawa-ai dilapas-blukirnya.",
        "ip_range_invalid": "Jarak IP kada sah.",
        "proxyblockreason": "Alamat IP Pian diblukir karana ngini sabuah pruksi tabuka.\nMuhun hubungi Panyadia Layan Internet Pian atawa sukungan tiknik wan padahi sidin pasal masalah ka-amanan sarius ngini.",
        "sorbsreason": "Alamat IP Pian tadaptar sawagai pruksi tabuka dalam DNSBL dipuruk ulih {{SITENAME}}.",
        "sorbs_create_account_reason": "Alamat IP Pian tadaptar sawagai pruksi tabuka dalam DNSBL dipuruk ulih {{SITENAME}}.\nPian kada kawa maulah sabuah akun",
-       "cant-see-hidden-user": "Pamuruk nang Pian cuba blukir sudah diblukir wan tasungkup.\nTumatan Pian kada baisi hak mnyungkupakan pamuruk, Pian kada kawa manjanaki atawa mambabak pamblukiran pamuruk.",
-       "ipbblocked": "Pian kada kawa mamblukir atau malapas blukir pamuruk lain, karana Pian surang diblukir",
+       "cant-see-hidden-user": "Pamakai nang Pian cuba blukir sudah diblukir wan tasuhuk.\nSalawas Pian kada baisi hak manyungkupakan pamakai, Pian kada kawa manjanaki atawa mambabak pamblukiran pamakai.",
+       "ipbblocked": "Pian kada kawa mamblukir atau malapas blukir pamakai lain, marga Pian saurang diblukir.",
        "ipbnounblockself": "Pian kada dibulihakan malapas blukir Pian surang",
        "lockdb": "Sunduk basisdata",
        "unlockdb": "Lapas sunduk basisdata",
-       "lockdbtext": "Manyunduk data basis akan mamandakakan kakawa-an samunyaan pamuruk mambabak tutungkaran, maubah kakatujuan sidin, mambabak paitihin sidin, wan nang lainnya nang parlu maubah dalam data basis.\nMuhun yakinakan nang ngini bujur nang handak Pian gawi, wan Pian akan malapas-sunduk data basis amun paharaguan Pian tuntung.",
-       "unlockdbtext": "Malapas-sunduk data basis akan manyimpan-pulang kakawa-an samunyaan pamuruk hagan mambabak tutungkaran, maubah kakatujuan sidin, mambabak paitihan sidin, wan nang lainnya nang parlu maubah dalam data basis.\nMuhun yakinakan nang ngini nang Pian handak gawi.",
+       "lockdbtext": "Manyunduk basis data akan maampihakan kamampuan samunyaan pamakai mambabak tungkaran, maubah kakatujuan sidin, mambabak paitihin sidin, wan nang lainnya nang parlu diubah dalam basis data.\nMuhun yakinakan nangini bujur nang handak Pian gawi, wan Pian akan malapas-sunduk basis data amun paharaguan tuntung.",
+       "unlockdbtext": "Malapas sunduk basis data akan manyimpan-pulang kamampuan samunyaan pamakai gasan mambabak tungkaran, maubah kakatujuan sidin, mambabak paitihan sidin, wan nang lainnya nang parlu diubah dalam basis data.\nMuhun yakinakan nang ngini nang Pian handak gawi.",
        "lockconfirm": "I'ih, ulun bujuran handak manyunduk basisdata.",
        "unlockconfirm": "I'ih, ulun bujuran handak malapas sunduk basisdata.",
        "lockbtn": "Sunduk basisdata",
        "movepagetext": "Mamakai purmulir di bawah akan mangganti ngaran sabuting tungkaran, mamindahakan samunyaan halam ka ngaran nang hanyar. Judul lawas akan jadi sabuting tungkaran paugahan ka judul hanyar. Pian kawa mahanyari bahwasanya paugahan-paugahan manuju ka judul nang samustinya langsung. Amun kada, pastiakan pariksa gasan [[Special:DoubleRedirects|ganda]] atawa [[Special:BrokenRedirects|paugahan pagat]]. Pian batanggung jawab gasan mamastiakan tautan-tautan tatarusan manuju ka mana nang samustinya.\n\nCatatan bahwasanya tungkaran '''kada''' akan tapindah amun sudah ada tungkaran nang bangaran hanyar ngitu, kacuali amun tungkaran itu puang atawa sabuting paugahan wan kadada halam babakan.\n\n'''Paringatan!'''\nIni kawa maakibatakan paubahan kada taduga wan drastis gasan sabuting tungkaran rami; muhun mamastiakan Pian paham akibatnya sabalum manarusakan.",
        "movepagetext-noredirectfixer": "Mamakai purmulir di bawah akan mangganti ngaran sabuting tungkaran, mamindahakan samunyaan halam ka ngaran nang hanyar.\nJudul lawas akan jadi sabuting tungkaran paugahan ka judul hanyar.\nPastiakan pariksa gasan [[Special:DoubleRedirects|ganda]] atawa [[Special:BrokenRedirects|paugahan pagat]].\nPian batanggung jawab gasan mamastiakan tautan-tautan tatarusan manuju ka mana nang samustinya.\n\nCatatan bahwasanya tungkaran '''kada''' akan tapindah amun sudah ada tungkaran nang bangaran hanyar ngitu, kacuali amun tungkaran itu puang atawa sabuah paugahan wan kadada halam babakan.\n\n'''Paringatan!'''\nIni kawa maakibatakan paubahan kada taduga wan drastis gasan sabuah tungkaran rami; \nmuhun mamastiakan Pian paham akibatnya sabalum manarusakan.",
        "movepagetalktext": "Tungkaran pamandiran tarait akan langsung dipindahakan baimbai wan ini '''kacuali amun:'''\n*Sabuah tungkaran pamandiran nang kada puang sudah baisi awan judul hanyar, atawa\n*Pian kada manyuntring kutak di bawah.",
-       "moveuserpage-warning": "'''Paringatan:''' Pian pasal mamindahakan sabuah tungkaran pamuruk. Muhun catat tungkaran ngitu haja nang dipindah wan pamuruknya gin akan ''kada'' dingarani-pulang.",
-       "movenologintext": "Pian musti saurang pamuruk tadaptar wan [[Special:UserLogin|babuat log]] hagan mamindahakan sabuah tungkaran.",
+       "moveuserpage-warning": "'''Paringatan:''' Pian parhatan mamindahakan tungkaran pamakai. Parlu Pian tahu lamun cuma tungkaran nang akan dipindahakan tapi pamakai ''kada'' baganti ngaran.",
+       "movenologintext": "Pian musti manjadi pamakai tadaptar wan [[Special:UserLogin|babuat log]] gasan mamindahakan suatu tungkaran.",
        "movenotallowed": "Pian kada baisi ijin hagan mamindahakan tutungkaran.",
        "movenotallowedfile": "Pian kada baisi ijin hagan mamindahakan babarakas.",
-       "cant-move-user-page": "Pian kada baisi ijin hagan mamindahakan tutungkaran pamuruk (hagian matan sub-tutungkaran).",
-       "cant-move-to-user-page": "Pian kada baisi ijin hagan mamindahakan tutungkaran pamuruk (kacuali hagan sabuah sub-tutungkaran pamuruk).",
+       "cant-move-user-page": "Pian kada baisi ijin gasan mamindahakan tungkaran pamakai (tapisah matan sub-tutungkaran).",
+       "cant-move-to-user-page": "Pian kada baisi ijin gasan mamindahakan tungkaran ka suatu tungkaran pamakai (kacuali ka sub-tutungkaran pamakai).",
        "newtitle": "Ka judul hanyar:",
        "move-watch": "Itihi tungkaran asal mula wan tungkaran tujuan",
        "movepagebtn": "Pindahakan tungkaran",
        "imageinvalidfilename": "Ngaran barakas tujuan kada sah",
        "fix-double-redirects": "Mutakhirakan babarapa paugahan nang manitik ka judul asli",
        "move-leave-redirect": "Ulah paugahan ka judul hanyar",
-       "protectedpagemovewarning": "'''Paringatan''': Tungkaran ngini sudah dilindungi laluai pamuruk awan hak istimiwa pambakal haja nang kawa mamindahakan ngini.\nLog masuk pauncitan disadiakan di bawah gasan rujukan:",
+       "protectedpagemovewarning": "'''Paringatan''': Tungkaran ngini sudah dikunci wan cuma pamakai nang baisi hak pambakal haja nang kawa mamindahakannya.\nMasukan catatan pauncitnya disadiaakan di bawah gasan rujukan:",
        "semiprotectedpagemovewarning": "'''Catatan:''' Tungkaran ngini sudah dilindungi laluai pamuruk tadaptar haja nang kawa mamindahakan ngini.\nLog masuk pauncitan disadiakan di bawah gasan rujukan:",
        "move-over-sharedrepo": "==Barakas ada==\n[[:$1]] ada pintangan panyimpanan babagi. Mamindahakan sabuah barakas ka judul ngini akan manulis-tindih barakas babagi.",
        "file-exists-sharedrepo": "Ngaran barakas nang dipilih sudah dipuruk pintangan panyimpanan babagi.\nMuhun pilih ngaran lain.",
        "allmessagesdefault": "Naskah baku pasan",
        "allmessagescurrent": "Naskah pasan wayahini.",
        "allmessagestext": "Ngini adalah sabuah daptar pasan sistem tasadia dalam ruang-ngaran MediaWiki.\nMuhun ilangi [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] wan [https://translatewiki.net translatewiki.net] amun Pian hakun manyumbang palukalan umum MediaWiki.",
-       "allmessagesnotsupportedDB": "Tungkaran ngini kada kawa dipuruk karana '''$wgUseDatabaseMessages''' sudah dipajahakan.",
+       "allmessages-not-supported-database": "Tungkaran ngini kada kawa dipuruk karana '''$wgUseDatabaseMessages''' sudah dipajahakan.",
        "allmessages-filter-legend": "Saringan",
        "allmessages-filter": "Saringan lawan kaadaan kustom:",
        "allmessages-filter-unmodified": "Kada digaganti",
        "import-logentry-upload-detail": "$1 {{PLURAL:$1|ralatan|raralatan}}",
        "import-logentry-interwiki-detail": "$1 {{PLURAL:$1|ralatan|raralatan}} matan $2",
        "javascripttest": "Mantis JavaScript",
-       "tooltip-pt-userpage": "Tungkaran pamakai Pian",
-       "tooltip-pt-anonuserpage": "Tungkaran pamuruk matan alamat IP Pian mambabak sawagai",
-       "tooltip-pt-mytalk": "Tungkaran pamandiran Pian",
+       "tooltip-pt-userpage": "Tungkaran {{GENDER:|pamakai Pian}}",
+       "tooltip-pt-anonuserpage": "Tungkaran pamakai IP Pian",
+       "tooltip-pt-mytalk": "Tungkaran {{GENDER:|pamandiran Pian}}",
        "tooltip-pt-anontalk": "Pamandiran pasal bababakan matan alamat IP ngini",
-       "tooltip-pt-preferences": "Nang Pian katuju",
+       "tooltip-pt-preferences": "Kakatujuan {{GENDER:|Pian}}",
        "tooltip-pt-watchlist": "Daptar tungkaran-tungkaran nang Pian itihi paubahannya",
-       "tooltip-pt-mycontris": "Daptar sumbangan Pian",
+       "tooltip-pt-mycontris": "Daptar sumbangan {{GENDER:|Pian}}",
        "tooltip-pt-login": "Pian sabaiknya babuat ka dalam log; tagal ngini kada kawajiban pang",
-       "tooltip-pt-logout": "Kaluar",
+       "tooltip-pt-logout": "Kaluar log",
+       "tooltip-pt-createaccount": "Pian dianjurakan gasan maulah akun wan babuat log; tagal, hal ngintu kada wajib",
        "tooltip-ca-talk": "Pamandiran pasal isi tungkaran",
-       "tooltip-ca-edit": "Pian kawa mambabak tungkaran ngini. Tabéngkéng amun mamakai picikan titilikan sabalum manyimpan",
+       "tooltip-ca-edit": "Babak tungkaran ngini",
        "tooltip-ca-addsection": "Mulai hagian hanyar",
        "tooltip-ca-viewsource": "Tungkaran ngini dilindungi. Pian kawa maniring asal mulanya.",
-       "tooltip-ca-history": "Raralatan bahari tungkaran ngini",
+       "tooltip-ca-history": "Ralatan bahari tungkaran ngini",
        "tooltip-ca-protect": "Lindungi tungkaran ini",
        "tooltip-ca-unprotect": "Ganti parlindungan tungkaran ngini",
        "tooltip-ca-delete": "Hapus tungkaran ini",
        "tooltip-ca-move": "Pindahakan tungkaran ngini",
        "tooltip-ca-watch": "Tambahi tungkaran ngini ka daptar itihan Pian",
        "tooltip-ca-unwatch": "Buang tungkaran ngini matan daptar itihan Pian",
-       "tooltip-search": "Gagai {{SITENAME}}",
-       "tooltip-search-go": "Tulak ka sabuah tungkaran bangaran sama munnya sudah ada",
-       "tooltip-search-fulltext": "Gagai tungkaran nang baisi naskah nangkaya ngini",
+       "tooltip-search": "Gagai di {{SITENAME}}",
+       "tooltip-search-go": "Tulak ka sabuting halaman bangaran sama amun sudah ada",
+       "tooltip-search-fulltext": "Gagai tungkaran nang baisi naskah nang kaya ngini",
        "tooltip-p-logo": "Ilangi tungkaran tatambaian",
        "tooltip-n-mainpage": "Ilangi tungkaran tatambaian",
-       "tooltip-n-mainpage-description": "Ilangi Tungkaran Tatambaian",
-       "tooltip-n-portal": "Pasal rangka-gawian, apa nang kawa pian gawi, di mana maugai sasuatu",
-       "tooltip-n-currentevents": "Gagai panjalasan prihal paristiwa damini",
+       "tooltip-n-mainpage-description": "Ilangi tungkaran tatambaian",
+       "tooltip-n-portal": "Pasal rangka-gawian, apa nang kawa pian gawi, di mana gasan manggagai sasuatu",
+       "tooltip-n-currentevents": "Gagai panjalasan pasal garamaan",
        "tooltip-n-recentchanges": "Daptar paubahan pahanyarnya dalam wiki",
-       "tooltip-n-randompage": "Tampaiakan sabuah babarang tungkaran",
-       "tooltip-n-help": "Wadah maugai patulung",
-       "tooltip-t-whatlinkshere": "Daptar samunyaan tungkaran wiki nang ada tautan ka sia",
-       "tooltip-t-recentchangeslinked": "Paubahan pahanyarnya dalam tutungkaran tataut matan tungkaran ngini",
+       "tooltip-n-randompage": "Tampaiakan babarang tungkaran",
+       "tooltip-n-help": "Wadah manggagai patulung",
+       "tooltip-t-whatlinkshere": "Daptar samunyaan tungkaran wiki nang ada tautan ka sini",
+       "tooltip-t-recentchangeslinked": "Paubahan pahanyarnya dalam tungkaran nang baisi tautan tumatan tungkaran ngini",
        "tooltip-feed-rss": "Kitihan RSS gasan tungkaran ini",
        "tooltip-feed-atom": "Kitihan Atum gasan tungkaran ngini",
-       "tooltip-t-contributions": "Sabuah daptar sumbangan pamakai ngini",
-       "tooltip-t-emailuser": "Kirimi surel ka pamakai ini",
-       "tooltip-t-upload": "Hunggahakan babarakas",
+       "tooltip-t-contributions": "Daptar sumbangan {{GENDER:$1|pamakai ngini}}",
+       "tooltip-t-emailuser": "Kirimi suril ka {{GENDER:$1|pamakai ngini}}",
+       "tooltip-t-upload": "Unggah barakas",
        "tooltip-t-specialpages": "Daptar samunyaan tungkaran istimiwa",
-       "tooltip-t-print": "Nang kawa dicitaknya tungkaran ngini",
-       "tooltip-t-permalink": "Tautan tatap ka raralatan tungkaran ngini",
-       "tooltip-ca-nstab-main": "Tiringi tungkaran isi",
+       "tooltip-t-print": "Vérsi citak tungkaran ngini",
+       "tooltip-t-permalink": "Tautan tatap ka ralatan tungkaran ngini",
+       "tooltip-ca-nstab-main": "Tiring tungkaran isi",
        "tooltip-ca-nstab-user": "Tiring tungkaran pamakai",
        "tooltip-ca-nstab-media": "Tiringi tungkaran media",
-       "tooltip-ca-nstab-special": "Nangini sabuah tungkaran istimiwa nang kada kawa dibabak.",
-       "tooltip-ca-nstab-project": "Tiringi tungkaran rangka gawian",
-       "tooltip-ca-nstab-image": "Tiringi barakas tungkaran",
-       "tooltip-ca-nstab-mediawiki": "Tiring sistim pasan",
-       "tooltip-ca-nstab-template": "Tiringi citakan",
+       "tooltip-ca-nstab-special": "Ngini tungkaran istimiwa, kada kawa dibabak.",
+       "tooltip-ca-nstab-project": "Janaki tungkaran rangka gawian",
+       "tooltip-ca-nstab-image": "Tiringi tungkaran barakas",
+       "tooltip-ca-nstab-mediawiki": "Janaki pasan sistem",
+       "tooltip-ca-nstab-template": "Janaki citakan",
        "tooltip-ca-nstab-help": "Tiringi tungkaran patulung",
-       "tooltip-ca-nstab-category": "Lihati tungkaran tumbung",
-       "tooltip-minoredit": "Tandai ini sabagai sabuah pambabakan sapalih",
+       "tooltip-ca-nstab-category": "Tiring tungkaran tumbung",
+       "tooltip-minoredit": "Tandai ngini sabagai sabutik pambabakan sapalih",
        "tooltip-save": "Simpan paubahan Pian",
-       "tooltip-preview": "Tilik paubahan Pian, muhun pakai ngini sabalum manyimpan!",
+       "tooltip-preview": "Tilik paubahan Pian. Muhun pakai ngini sabalum manyimpan.",
        "tooltip-diff": "Tampaiakan nang apa paubahan nang Pian ulah",
        "tooltip-compareselectedversions": "Lihati nang balain antara dua ralatan tungkaran tapilih ngini",
        "tooltip-watch": "Tambahakan tungkaran ini ka daptar itihan Pian",
        "tooltip-watchlistedit-raw-submit": "Hanyari daptar itihan",
        "tooltip-recreate": "Ulah pulang tungkaran biar gin suah dihapus",
        "tooltip-upload": "Mulai pangunggahan",
-       "tooltip-rollback": "Bulikakan ka babakan-babakan tungkaran ngini matan panyumbang tauncit dalam sakali klik.",
-       "tooltip-undo": "Mamantukakan ralatan ngini wan mambuka kutak pambabakan lawan mode tilik. Alasan kawa ditambahakan di kutak kasimpulan.",
+       "tooltip-rollback": "\"Pambulik\" mawalang babakan-babakan di tungkaran ngini ka panyumbang pahabisan dalam satu kali kalik.",
+       "tooltip-undo": "\"Bulikakan\" mawalangi ralatan ngini wan mambuka kutak pambabakan lawan mode tilik. Alasan kawa ditambahakan di kutak kasimpulan.",
        "tooltip-preferences-save": "Simpan kakatujuan",
-       "tooltip-summary": "Buati sabuah kasimpulan handap",
+       "tooltip-summary": "Buati sabuting kasimpulan handap",
        "anonymous": "{{PLURAL:$1|panuruk|papamuruk}} kada-bangaran {{SITENAME}}",
-       "siteuser": "Pamuruk {{SITENAME}} $1",
-       "anonuser": "Pamuruk kada bangaran {{SITENAME}} $1",
+       "siteuser": "Pamakai {{SITENAME}} $1",
+       "anonuser": "Pamakai kada bangaran {{SITENAME}} $1",
        "lastmodifiedatby": "Tungkaran ngini tauncit diubah pada $1, $2 ulih $3",
        "othercontribs": "Dipandalakan pada gawian ulih $1.",
        "others": "lainnya",
        "siteusers": "{{PLURAL:$2|pamuruk|papamuruk}} {{SITENAME}} $1",
-       "anonusers": "{{PLURAL:$2|pamuruk|papamuruk}} kada bangaran {{SITENAME}} $1",
+       "anonusers": "{{PLURAL:$2|pamakai|pamakai}} kada bangaran {{SITENAME}} $1",
        "creditspage": "Tungkaran kridit",
        "nocredits": "Kadada panjalasan kridit tasadia gasan tungkaran ngini.",
        "spamprotectiontitle": "Saringan pancagah spam",
        "spam_reverting": "Mambulikakan ka ralatan tauncit nang kada mangandung tatautan ka $1",
        "spam_blanking": "Samunyaan raralatan mangandung tatautan ka $1, dikusungakan",
        "spam_deleting": "Samunyaan raralatan nang isinya tatautan ka $1, dipuangakan",
+       "simpleantispam-label": "Pamariksaan anti-spam.\n<strong>Jangan</strong> diisi!",
        "pageinfo-title": "Panjalasan gasan ''$1''",
        "pageinfo-not-current": "Maaf, kada mungkin mambariakan maklumat ngini ka ralatan lawas.",
        "pageinfo-header-basic": "Maklumat pandal",
        "pageinfo-default-sort": "Kunci urut baku",
        "pageinfo-length": "Panjang tungkaran (dalam bita)",
        "pageinfo-article-id": "ID Tungkaran",
-       "pageinfo-language": "Bahasa isi tungkaran",
-       "pageinfo-robot-policy": "Status masin panggagai",
-       "pageinfo-robot-index": "Kawa diindeks",
-       "pageinfo-robot-noindex": "Kada kawa diindeks",
+       "pageinfo-language": "Basa isi tungkaran",
+       "pageinfo-content-model": "Mudil isi tungkaran",
+       "pageinfo-robot-policy": "Pangindéksan ulih robot",
+       "pageinfo-robot-index": "Dibulihakan",
+       "pageinfo-robot-noindex": "Kada dibulihakan",
        "pageinfo-watchers": "Jumlah pa-itih tungkaran",
        "pageinfo-few-watchers": "Kurang matan $1 {{PLURAL:$1|pa-ilang}}",
-       "pageinfo-redirects-name": "Paugahan ka tungkaran ngini",
+       "pageinfo-redirects-name": "Jumlah paugahan ka tungkaran ngini",
        "pageinfo-subpages-name": "Subtungkaran tungkaran ngini",
        "pageinfo-subpages-value": "$1 ($2 {{PLURAL:$2|paugahan|paugahan}}; $3 {{PLURAL:$3|non-paugahan|non-paugahan}})",
        "pageinfo-firstuser": "Pa-ulah tungkaran",
        "pageinfo-authors": "Rikinan panulis nang balain",
        "pageinfo-recent-edits": "Jumlah babakan damini (dalam $1 pauncitnya)",
        "pageinfo-recent-authors": "Jumlah panulis nang babida damini",
-       "pageinfo-magic-words": "{{PLURAL:$1|Kata|Kata}} ajaib ($1)",
-       "pageinfo-hidden-categories": "{{PLURAL:$1|tumbung|tutumbung}}",
-       "pageinfo-templates": "{{PLURAL:$1|Citakan|Citakan}} nang ditransklusi ($1)",
+       "pageinfo-magic-words": "{{PLURAL:$1|Kata|Kata-kata}} ajaib ($1)",
+       "pageinfo-hidden-categories": "{{PLURAL:$1|Pilah|Pilah}} tatukup ($1)",
+       "pageinfo-templates": "{{PLURAL:$1|Citakan|Cicitakan}} nang ditransklusi ($1)",
        "pageinfo-transclusions": "{{PLURAL:$1|Tungkaran|Tutungkaran}} ditransklusikan pada ( $1 )",
-       "pageinfo-toolboxlink": "Maklumat tungkaran",
+       "pageinfo-toolboxlink": "Panjalasan tungkaran",
        "pageinfo-redirectsto": "Ba-ugah ka",
        "pageinfo-redirectsto-info": "Maklumat",
        "pageinfo-contentpage": "Dirikin sabagai tungkaran isi",
        "filedelete-old-unregistered": "Ralatan barakas nang diajuakan \"$1\" kadada dalam data basis.",
        "filedelete-current-unregistered": "Barakas nang diajuakan \"$1\" kadada dalam data basis.",
        "filedelete-archive-read-only": "Direktori arkip \"$1\" kada kawa ditulisi ulih webserver.",
-       "previousdiff": "← Ralatan talawas",
+       "previousdiff": "← Ralatan sabalumnya",
        "nextdiff": "Ralatan labih hanyar →",
        "mediawarning": "'''Paringatan''': Barakas ngini pinanya mangandung kudi babahaya.\nManarusakan ngini, kawa manyarang sistem Pian.",
        "imagemaxsize": "Watas takaran gambar: <br />''(gasan barakas tutungkaran diskripsi)''",
        "file-info-size": "$1 × $2 piksel, ukuran barakas: $3, tipe MIME: $4",
        "file-info-size-pages": "$1 × $2 piksal, takaran barakas: $3, macam MIME: $4, $5 {{PLURAL:$5|tungkaran|tutungkaran}}",
        "file-nohires": "Kadada tasadia resolusi tapancau.",
-       "svg-long-desc": "Barakas SVG, nominal $1 × $2 piksel, basar barakas: $3",
-       "show-big-image": "Ukuran hibak",
+       "svg-long-desc": "Barakas SVG, nominal $1 × $2 piksel, ganal barakas: $3",
+       "show-big-image": "Ukuran asli",
        "show-big-image-preview": "Takaran tilikan ngini: $1.",
        "show-big-image-other": "{{PLURAL:$2|Risulusi|Risulusi}} lain: $1.",
        "show-big-image-size": "$1 × $2 piksal",
        "ago": "$1 lalu",
        "bad_image_list": "Purmatnya nangkaya di bawah ni:\n\nDaptar buting (baris bamula wan *) haja nang dipartimbangkan.\nTautan ta'asa dalam sabuah baris mustinya sabuah tautan ka barakas nang buruk.\nTautan-tautan abis tu pada baris sama dipartimbangkan sabagai pangacualian, nangkaya tungkaran-tungkaran di mana barakas itu ada.",
        "metadata": "Metadata",
-       "metadata-help": "Barakas ngini mangandung panjalasan tambahan, mungkin ditambahakan ulih kudakan atawa paundai nang dipurukakan gasan maulah atawa digitalisasi barakas. Amun barakas ngini sudah diubah, parincian nang ada mungkin kada sapanuhnya sasuai lawan barakas nang diubah.",
+       "metadata-help": "Barakas ngini mangandung panjalasan tambahan, mungkin ditambahakan ulih kudakan atawa paundai nang dipakai gasan maulah atawa digitalisasi barakas. Amun barakas ngini sudah diubah, parincian nang ada mungkin kada sapanuhnya sasuai lawan barakas nang diubah.",
        "metadata-expand": "Tampaiakan tambahan rincian",
        "metadata-collapse": "Sungkupakan tambahan rincian",
        "metadata-fields": "Pancitraan metadata tadaptar dalam pasan ngini akan masuk dalam tungkaran pancitraan wayah tabel metadata tasungkup. Nang lainnya cagaran babaku tasungkup.\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
        "namespacesall": "samunyaan",
        "monthsall": "samunyaan",
        "confirmemail": "Yakinakan alamat suril",
-       "confirmemail_noemail": "Pian kada baisi sabuah alamat suril nang sah dalam [[Special:Preferences|kakatujuan pamuruk]] Pian.",
+       "confirmemail_noemail": "Pian kada manjulungi alamat surél nang sah dalam [[Special:Preferences|kakatujuan pamakai]] Pian.",
        "confirmemail_text": "{{SITENAME}} mawajibakan Pian mayakinakan alamat suril Pian sabalum pitur-pitur suril dipurukakan.\nPicik tumbul di bawah ngini hagan mangirimi Pian sabuah suril payakinan ka alamat Pian.\nSi suril akan ada di dalam sabuah tautan bakudi;\nHandak si tautan ka panjalajah Pian hagan mayakinakan bahwasa alamat suril Pian sah.",
        "confirmemail_pending": "Sabuah kudi payakinan sudah tasuril ka Pian;\nAmun Pian hahanyar ni maulah akun Pian, Pian kawa lah mahadangi babarapa minit gasan ngini hagan sampai sabalum mancuba maminta sabuah kudi hanyar.",
        "confirmemail_send": "Surili sabua kudi payakinan",
        "confirmemail_body_changed": "Sasaurang, pinanya Pian, malan alamat IP $1,\nsudah mangganti alamat suril sabuah akun \"$2\" awan alamat suril ngini pada {{SITENAME}}.\n\nHagan mayakinakan bahwasa akun ngini bujur ampun Pian wan ma-aktip-akan pulang\npipitur suril pada {{SITENAME}}, ungkai tautan ngini ka panjalajah Pian;\n\n$3\n\nAmun si akun *kada* bujur ampun Pian, umpati tautan ngini\nhagan mawalangi payakinan alamat suril:\n\n$5\n\nKudi payakinan ngini akan kadaluarsa pada $4.",
        "confirmemail_body_set": "Sasaurang, pinanya Pian, malan alamat IP $1,\nsudah manyetel alamat suril sabuah akun \"$2\" awan alamat suril ngini pada {{SITENAME}}.\n\nHagan mayakinakan bahwasa akun ngini bujur ampun Pian wan ma-aktip-akan pulang\npipitur suril pada {{SITENAME}}, ungkai tautan ngini ka panjalajah Pian;\n\n$3\n\nAmun si akun *kada* bujur ampun Pian, umpati tautan ngini\nhagan mawalangi payakinan alamat suril:\n\n$5\n\nKudi payakinan ngini akan kadaluarsa pada $4.",
        "confirmemail_invalidated": "Payakinan alamat suril diwalangi",
-       "invalidateemail": "Walangi suril payakinan",
+       "invalidateemail": "Pasahakan kunfirmasi surél",
        "scarytranscludedisabled": "[Transklusi intarwiki dipajahakan]",
        "scarytranscludefailed": "[Pangambilan citakan $1 gagal]",
        "scarytranscludetoolong": "[URL kapanjangan]",
        "confirm-unwatch-button": "OK",
        "confirm-unwatch-top": "Buang tungkaran ini matan paitihan Pian?",
        "imgmultipageprev": "← tungkaran sabalumnya",
-       "imgmultipagenext": "tungkaran barikutnya →",
+       "imgmultipagenext": "tungkaran salanjutnya →",
        "imgmultigo": "Tulak!",
        "imgmultigoto": "Tulak ka tungkaran $1",
        "ascending_abbrev": "naik",
        "watchlistedit-raw-done": "Daptar itihan Pian sudah dipugai",
        "watchlistedit-raw-added": "{{PLURAL:$1|1 judul|$1 jujudul}} ditambahi:",
        "watchlistedit-raw-removed": "{{PLURAL:$1|1 judul|$1 jujudul}} dibuangi:",
+       "watchlisttools-clear": "Barasihi daptar itihan",
        "watchlisttools-view": "Tampaiakan paubahan tarait",
        "watchlisttools-edit": "Tiringi wan babak daptar itihan",
        "watchlisttools-raw": "Babak daptar itihan mantah",
        "version-software-product": "Produk",
        "version-software-version": "Virsi",
        "version-entrypoints-header-url": "URL",
+       "redirect": "Paugahan badasarakan ID barakas, pamakai, tungkaran, ralatan, atawa log",
+       "redirect-summary": "Tungkaran istimiwa ngini baugah ka barakas (sasuai ngarannya), halaman (sasuai ID ralatan atawa ID tungkaran), tungkaran pamakai (sasuai ID pamakai), atawa buatan log (ID lognya). Pamakaian: [[{{#Special:Redirect}}/file/Cuntuh.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]], or [[{{#Special:Redirect}}/logid/186]].",
+       "redirect-submit": "Lanjut",
+       "redirect-lookup": "Panggagaian:",
+       "redirect-value": "Nilai:",
+       "redirect-user": "ID pamakai",
+       "redirect-page": "ID Tungkaran",
+       "redirect-revision": "Ralatan tungkaran",
+       "redirect-file": "Ngaran barakas",
        "fileduplicatesearch": "Gagai gasan babarakas baganda",
        "fileduplicatesearch-summary": "Gagai gasan babarakas baganda bapandal nilai hash.",
        "fileduplicatesearch-filename": "Ngaran barakas:",
        "specialpages-group-login": "Babuat log / mandaptar",
        "specialpages-group-changes": "Paubahan pahanyarnya wan log",
        "specialpages-group-media": "Lapuran wan pamuatan barakas",
-       "specialpages-group-users": "Pamuruk wan hak pamuruk",
+       "specialpages-group-users": "Pamakai wan hak pamakai",
        "specialpages-group-highuse": "Tungkaran pamakaian tinggi",
        "specialpages-group-pages": "Daptar tungkaran",
        "specialpages-group-pagetools": "Pakakas tungkaran",
        "tags": "Tag paubahan sah",
        "tag-filter": "Saringan [[Special:Tags|Tag]]:",
        "tag-filter-submit": "Saringan",
+       "tag-list-wrapper": "[[Special:Tags|{{PLURAL:$1|Tag}}]]: $2",
        "tags-title": "Gantungan",
        "tags-intro": "Tungkaran ngini mandaptar gantungan nang diciri-i parangkat lunak sabuah babakan, wan artinya.",
        "tags-tag": "Gantungan ngaran",
        "tags-display-header": "Pancungulan pada daptar paubahan.",
        "tags-description-header": "Diskripsi hibak matan arti",
        "tags-hitcount-header": "Gantungan diganti",
+       "tags-active-yes": "Inggih",
+       "tags-active-no": "Kada",
        "tags-edit": "babak",
-       "tags-hitcount": "$1 {{PLURAL:$1|paubahan|paubahan}}",
+       "tags-hitcount": "$1 {{PLURAL:$1|paubahan}}",
        "comparepages": "Bandingakan tutungkaran",
        "compare-page1": "Tungkaran 1",
        "compare-page2": "Tungkaran 2",
        "htmlform-int-toohigh": "Nilai nang Pian ajuakan kapancauan pada maksimal $1",
        "htmlform-required": "Nilai ngini nang diparluakan",
        "htmlform-submit": "Kirim",
-       "htmlform-reset": "Walangi paubahan",
+       "htmlform-reset": "Bulikakan paubahan",
        "htmlform-selectorother-other": "Lain-lain",
-       "logentry-delete-delete": "$1 mahapus tungkaran $3",
-       "logentry-delete-restore": "$1 dibulikakan tungkaran $3",
+       "logentry-delete-delete": "$1 {{GENDER:$2|mahapus}} tungkaran $3",
+       "logentry-delete-restore": "$1 {{GENDER:$2|mambulikakan}}tungkaran $3 ($4)",
        "logentry-delete-event": "$1 mangganti kakawaan dijanaki {{PLURAL:$5|sabuah log kajadian|$5 log kajadian}} pintangan $3: $4",
-       "logentry-delete-revision": "$1 mangganti kakawaan dijanaki {{PLURAL:$5|sabuah ralatan|$5 ralatan}} pintangan tungkaran $3: $4",
+       "logentry-delete-revision": "$1 {{GENDER:$2|maubah}} tampaian {{PLURAL:$5|$5 ralatan}} di tungkaran $3: $4",
        "logentry-delete-event-legacy": "$1 mangganti kakawaan dijanaki log kajadian pintangan $3",
        "logentry-delete-revision-legacy": "$1 mangganti kakawaan dijanaki ralatan pintangan tungkaran $3",
        "logentry-suppress-delete": "$1 ditikin tungkaran $3",
        "logentry-suppress-revision-legacy": "$1 mangganti kakawaan dijanaki ralatan pintangan tungkaran $3 lawan rahasia",
        "revdelete-content-hid": "Isi disungkupakan",
        "revdelete-summary-hid": "babak kasimpulan tasungkup",
-       "revdelete-uname-hid": "ngaran-pamuruk tasungkup",
+       "revdelete-uname-hid": "ngaran pamakai disungkupakan",
        "revdelete-content-unhid": "Isi kada disungkupakan",
        "revdelete-summary-unhid": "babak kasimpulan kada tasungkup",
-       "revdelete-uname-unhid": "ngaran-pamuruk kada tasungkup",
+       "revdelete-uname-unhid": "ngaran pamakai kada disungkupakan",
        "revdelete-restricted": "Talamar pambatasan hagan pambakal-pambakal",
        "revdelete-unrestricted": "Buang pambatasan gasan pambakal-pambakal",
-       "logentry-move-move": "$1 mamindahakan tungkaran $3 ka $4",
-       "logentry-move-move-noredirect": "$1 diugah tungkaran $3 ka $4 awan-kada maninggalakan sabuah paugahan",
-       "logentry-move-move_redir": "$1 diugah tungkaran $3 ka $4 lung paugahan",
+       "logentry-move-move": "$1 {{GENDER:$2|mamindahakan}} tungkaran $3 ka $4",
+       "logentry-move-move-noredirect": "$1 {{GENDER:$2|mamindahakan}} tungkaran $3 ka $4 kada pakai maulah paugahan",
+       "logentry-move-move_redir": "$1 {{GENDER:$2|mamindahakan}} tungkaran $3 ka $4 manimpa paugahan lawas",
        "logentry-move-move_redir-noredirect": "$1 diugah tungkaran $3 ka $4 lung sabuah paugahan awan-kada maninggalakan sabuah paugahan",
        "logentry-patrol-patrol": "$1 diciri'i ralatan $4 matan tungkaran $3 taawasi",
-       "logentry-patrol-patrol-auto": "$1 utumatis diciri'i ralatan $4 matan tungkaran $3 taawasi",
+       "logentry-patrol-patrol-auto": "$1 utumatis {{GENDER:$2|manandai}} ralatan $4 matan tungkaran $3 taitihi",
        "logentry-newusers-newusers": "$1 ma-ulah sabuting akun pamakai",
-       "logentry-newusers-create": "$1 ma-ulah sabuting akun pamakai",
+       "logentry-newusers-create": "$1 {{GENDER:$2|maulah}} akun pamakai",
        "logentry-newusers-create2": "$1 ma-ulah sabuting akun pamakai $3",
-       "logentry-newusers-autocreate": "Akun $1 utumatis diulah",
+       "logentry-newusers-autocreate": "Akun $1 {{GENDER:$2|diulah}} sacara utumatis",
+       "logentry-upload-upload": "$1 {{GENDER:$2|ma-unggah}} $3",
+       "logentry-upload-overwrite": "$1{{GENDER:$2|maunggah}} versi hanyar $3",
        "rightsnone": "(kadada)",
        "feedback-adding": "Manambahi kitihanbalik ka tungkaran...",
        "feedback-bugcheck": "Harat! hanyar dipariksa bahwasa ngini lainan salah asa [$1 bug nang dipinandui].",
        "feedback-bugnew": "Ulun mamariksa. Malapurakan sabuah bug hanyar",
-       "feedback-bugornote": "Pabila Pian siap manjalasakan sabuah masalah taknik rinci muhun [lapurakan sabuah bug $1].\nSalain ngitu, Pian kawa mamuruk prmulir nyaman di bawah ngini. Kumintar Pian akan ditambahi ka si tungkaran \"[$3 $2]\", baimbai awan ngaran-pamuruk Pian wan panjalajah nagn Pian puruk.",
-       "feedback-cancel": "Walangi",
+       "feedback-bugornote": "Lamun Pian sudah siap gasan mamaparakan masalah téknis sacara rinci silakan [$1 malapurakan bug].\nLamun kada, Pian kawa mamakai purmulir mudah di bawah ngini. Kumintar Pian akan ditambahakan ka tungkaran \"[$3 $2]\", baimbai lawan ngaran pamakai Pian wan apa paramban nang Pian pakai.",
+       "feedback-cancel": "Pasah",
        "feedback-close": "Sudah",
        "feedback-error1": "Kasalahan: kulihan matan API kada-dipinandui",
        "feedback-error2": "Kasalahan: Babakan gagal",
        "feedback-subject": "Parihal:",
        "feedback-submit": "Kirim",
        "feedback-thanks": "Tarimakasih! jitihanbalik Pian sudah dipusakan ka si tungkaran \"[$2 $1]\".",
-       "searchsuggest-search": "Gagai",
+       "searchsuggest-search": "Gagai {{SITENAME}}",
        "searchsuggest-containing": "isian ...",
        "api-error-stashfailed": "Kasalahan intarnal: server gagal manyimban barakas samantara.",
        "api-error-unknown-warning": "Paringatan kada dipinandui: \"$1\".",
        "api-error-unknownerror": "Kasalahan kada dipinandui: \"$1\".",
+       "duration-days": "$1 {{PLURAL:$1|hari}}",
        "special-characters-group-latin": "Latin",
        "special-characters-group-ipa": "IPA",
        "special-characters-group-symbols": "Simbul",
        "special-characters-group-gujarati": "Gujarati",
        "special-characters-group-thai": "Thai",
        "special-characters-group-lao": "Lao",
-       "special-characters-group-khmer": "Khmer"
+       "special-characters-group-khmer": "Khmer",
+       "randomrootpage": "Tungkaran dasar sambarang"
 }
index f364c67..c5f501e 100644 (file)
        "tog-watchlisthidecategorization": "পাতার শ্রেণীবদ্ধকরণ লুকিয়ে রাখা হোক",
        "tog-ccmeonemails": "অন্য ব্যবহারকারীর কাছে আমার পাঠানো ইমেইলের একটি প্রতিলিপি আমাকে পাঠানো হোক",
        "tog-diffonly": "পার্থক্যের নিচে পাতার বিষয়বস্তু না দেখানো হোক",
-       "tog-showhiddencats": "লà§\81à¦\95ায়িত à¦¬à¦¿à¦·à¦¯à¦¼à¦¶à§\8dরà§\87ণà§\80সমà§\82হ à¦¦à§\87à¦\96ানà§\8b à¦¹à§\8bà¦\95",
+       "tog-showhiddencats": "লà§\81à¦\95ানà§\8b à¦¬à¦¿à¦·à¦¯à¦¼à¦¶à§\8dরà§\87ণà§\80সমà§\82হ à¦¦à§\87à¦\96ান",
        "tog-norollbackdiff": "রোলব্যাকের পরে সংস্করণগুলির পার্থক্য না দেখানো হোক",
        "tog-useeditwarning": "কোনো সম্পাদনা পাতা ত্যাগের সময় পরিবর্তনগুলি সংরক্ষিত না হয়ে থাকলে আমাকে সাবধান করা হোক",
        "tog-prefershttps": "অ্যাকাউন্টে প্রবেশ করার সময় সবসময় নিরাপদ সংযোগ ব্যবহার করুন",
+       "tog-showrollbackconfirmation": "একটি রোলব্যাক লিঙ্ক ক্লিক করার সময় একটি নিশ্চিতকরণ বার্তা দেখান",
        "underline-always": "সব সময়",
        "underline-never": "কখনো নয়",
        "underline-default": "আবরণ বা ব্রাউজারে যেমনভাবে নির্দিষ্ট করা আছে",
        "subcategories": "উপবিষয়শ্রেণীসমূহ",
        "category-media-header": "\"$1\" বিষয়শ্রেণীতে অন্তর্ভুক্ত মিডিয়া ফাইলগুলি",
        "category-empty": "<em>এই বিষয়শ্রণীতে বর্তমানে কোন পাতা বা মিডিয়া ফাইল নেই।</em>",
-       "hidden-categories": "{{PLURAL:$1|লà§\81à¦\95ায়িত বিষয়শ্রেণী}}",
-       "hidden-category-category": "লà§\81à¦\95ায়িত বিষয়শ্রেণীসমূহ",
+       "hidden-categories": "{{PLURAL:$1|লà§\81à¦\95ানà§\8b বিষয়শ্রেণী}}",
+       "hidden-category-category": "লà§\81à¦\95ানà§\8b বিষয়শ্রেণীসমূহ",
        "category-subcat-count": "{{PLURAL:$2|এই বিষয়শ্রেণীতে কেবলমাত্র নিচের উপবিষয়শ্রেণীটি আছে।|এই বিষয়শ্রেণীতে অন্তর্ভুক্ত মোট $2টি উপবিষয়শ্রেণীর মধ্যে {{PLURAL:$1|$1টি উপবিষয়শ্রেণী}} নিচে দেখানো হয়েছে।}}",
        "category-subcat-count-limited": "এই বিষয়শ্রেণীতে নিচের {{PLURAL:$1|উপবিষয়শ্রেণী|$1টি উপবিষয়শ্রেণী}} আছে।",
        "category-article-count": "{{PLURAL:$2|এই বিষয়শ্রেণীতে কেবল নিচের পাতাটি আছে।|এই বিষয়শ্রেণীতে অন্তর্ভুক্ত মোট $2টি পাতার মধ্যে {{PLURAL:$1|$1টি পাতা}} নিচে দেখানো হল।}}",
        "querypage-no-updates": "এই পাতার জন্য হালনাগাদ নিষ্ক্রিয় করা হয়েছে। এখানে রাখা উপাত্তগুলি এ মুহূর্তে হালনাগাদ করা হবে না।",
        "viewsource": "উৎস দেখুন",
        "viewsource-title": "$1-এর উৎস দেখুন",
-       "actionthrottled": "à¦\95াà¦\9cà§\87র à¦\97তি à¦§à§\80রà¦\95রণ",
+       "actionthrottled": "à¦\95রà§\8dম à¦§à§\80রà¦\95রা",
        "actionthrottledtext": "অপব্যবহার প্রতিরোধক সমাধান হিসেবে এই কাজটি খুব কম সময়ে অনেক বেশিবার সম্পাদন করার উপর সীমা বেঁধে দেওয়া হয়েছে, এবং আপনি সেই সীমা অতিক্রম করেছেন।\nঅনুগ্রহ করে কয়েক মিনিট পরে আবার চেষ্টা করুন।",
        "protectedpagetext": "সম্পাদনা অথবা অন্যান্য কাজে বাধা দিতে এই পাতাটিকে সুরক্ষিত করা হয়েছে।",
        "viewsourcetext": "আপনি এই পাতাটি দেখতে এবং উৎসের প্রতিলিপি করতে পারবেন।",
        "badretype": "আপনার প্রবেশ করানো পাসওয়ার্ডটি মিলছে না।",
        "usernameinprogress": "এই ব্যবহারকারী নামের জন্য একটি অ্যাকাউন্ট তৈরি আগে থেকেই চলছে। দয়া করে অপেক্ষা করুন।",
        "userexists": "এই ব্যবহারকারী নামটি ইতমধ্যে ব্যবহার করা হয়েছে।\nঅনুগ্রহ করে অন্য নাম বেছে নিন।",
+       "createacct-normalization": "কারিগরি সীমাবদ্ধতার কারণে আপনার ব্যবহারকারীর নাম সামঞ্জস্য করে \"$2\" করা হবে।",
        "loginerror": "প্রবেশ করতে সমস্যা হয়েছে",
        "createacct-error": "অ্যাকাউন্ট তৈরিতে ত্রুটি",
        "createaccounterror": "অ্যাকাউন্ট তৈরি হয়নি: $1",
        "templatesusedsection": "এই অনুচ্ছেদে ব্যবহৃত {{PLURAL:$1|টেমপ্লেট|টেমপ্লেটসমূহ}}:",
        "template-protected": "(সুরক্ষিত)",
        "template-semiprotected": "(অর্ধ-সুরক্ষিত)",
-       "hiddencategories": "à¦\8fà¦\87 à¦ªà¦¾à¦¤à¦¾à¦\9fি {{PLURAL:$1|১à¦\9fি à¦²à§\81à¦\95ায়িত à¦¬à¦¿à¦·à¦¯à¦¼à¦¶à§\8dরà§\87ণà§\80র|$1à¦\9fি à¦²à§\81à¦\95ায়িত বিষয়শ্রেণীর}} সদস্য:",
+       "hiddencategories": "à¦\8fà¦\87 à¦ªà¦¾à¦¤à¦¾à¦\9fি {{PLURAL:$1|১à¦\9fি à¦²à§\81à¦\95ানà§\8b à¦¬à¦¿à¦·à¦¯à¦¼à¦¶à§\8dরà§\87ণà§\80র|$1à¦\9fি à¦²à§\81à¦\95ানà§\8b বিষয়শ্রেণীর}} সদস্য:",
        "edittools": "<!-- সম্পাদনা এবং আপলোড ফরমের নীচে এখানের লেখা দেখানো হবে। -->",
        "edittools-upload": "-",
        "nocreatetext": "{{SITENAME}}-এ নতুন পাতা সৃষ্টি করার ক্ষমতা সীমাবদ্ধ করা হয়েছে।\nআপনি ফিরে গিয়ে ইতিমধ্যে বিদ্যমান কোন পাতা সম্পাদনা করতে পারেন, অথবা [[Special:UserLogin|অ্যাকাউন্টে প্রবেশ কিংবা অ্যাকাউন্ট সৃষ্টি করতে পারেন]]।",
        "edit-gone-missing": "পাতাটি হালনাগাদ হয়নি।\nসম্ভবতঃ পাতাটি মুছে ফেলা হয়েছে।",
        "edit-conflict": "সম্পাদনা সংঘাত।",
        "edit-no-change": "আপনার সম্পাদনাটি উপেক্ষা করা হয়েছে, কারণ লেখাতে কোনো পরিবর্তন করা হয়নি।",
+       "edit-slots-cannot-add": "নিচের {{PLURAL:$1|স্লটটি|স্লটসমূহ}} এখানে সমর্থিত নয়: $2।",
+       "edit-slots-cannot-remove": "নিচের {{PLURAL:$1|স্লট|স্লটসমূহ}} প্রয়োজন এবং বাদ দেওয়া যাবে না: $2।",
+       "edit-slots-missing": "নিচের {{PLURAL:$1|স্লট|স্লটসমূহ}} পাওয়া যায়নি: $2।",
        "postedit-confirmation-created": "পাতাটি তৈরি করা হয়েছে।",
        "postedit-confirmation-restored": "পাতাটি পুনরুদ্ধার করা হয়েছে।",
        "postedit-confirmation-saved": "আপনার সম্পাদনা সংরক্ষিত হয়েছে।",
        "converter-manual-rule-error": "ম্যানুয়াল ভাষা রূপান্তর নিয়মে ত্রুটি পাওয়া গিয়েছে",
        "undo-success": "সম্পাদনাটি বাতিল করা যাবে। অনুগ্রহ করে নিচের তুলনাটি পরীক্ষা করে দেখুন ও নিশ্চিত করুন যে এটাই আপনি করতে চান, এবং তারপর নিচের সম্পাদনাগুলি সংরক্ষণ করে সম্পাদনাটির বাতিল প্রক্রিয়া সমাপ্ত করুন।",
        "undo-failure": "এ সম্পাদনা মধ্যবর্তী সম্পাদনাসমূহের কারণে পূর্বাবস্থায় ফিরিয়ে নেওয়া যাবে না।",
+       "undo-main-slot-only": "এই সম্পাদনাটি পূর্বাবস্থায় নেওয়া যাবে না কারণ এখানকার বিষয়বস্তু প্রধান স্লটের বাইরে।",
        "undo-norev": "সম্পাদনাটি বাতিল করা যাচ্ছেনা কারণ এটি আর নেই বা মুছে ফেলা হয়েছে।",
        "undo-nochange": "সম্পাদনাটি পূর্বেই বাতিল করা হয়েছে।",
        "undo-summary": "[[Special:Contributions/$2|$2]] ([[User talk:$2|আলাপ]])-এর সম্পাদিত $1 নম্বর সংশোধনটি বাতিল করা হয়েছে",
-       "undo-summary-username-hidden": "à¦\8fà¦\95à¦\9cন à¦²à§\81à¦\95ায়িত ব্যবহারকারীর করা $1 নং সংশোধনটি বাতিল করা হয়েছে",
+       "undo-summary-username-hidden": "à¦\8fà¦\95à¦\9cন à¦²à§\81à¦\95ানà§\8b ব্যবহারকারীর করা $1 নং সংশোধনটি বাতিল করা হয়েছে",
        "cantcreateaccount-text": "[[User:$3|$3]] এই আইপি ঠিকানা('''$1''') থেকে অ্যাকাউন্ট সৃষ্টিতে বাধা দিয়েছেন।\n\n$3-এর দেয়া কারণ হল ''$2''",
        "cantcreateaccount-range-text": "[[User:$3|$3]] কর্তৃক আইপি ঠিকানার ব্যাপ্তি <strong>$1</strong>-এর মধ্যে অ্যাকাউন্ট তৈরি করা অবরুদ্ধ করা হয়েছে। যাতে আপনার আইপি ঠিকানাও (<strong>$4</strong>) রয়েছে। \n\n$3 কর্তৃক <em>$2</em> কারণ দেখানো হয়েছে।",
        "viewpagelogs": "এই পাতার জন্য লগগুলো দেখুন",
        "page_first": "প্রথম",
        "page_last": "শেষ",
        "histlegend": "পার্থক্য নির্বাচন: যে সংস্করণগুলি তুলনা করতে চান, সেগুলি চিহ্নিত করে এন্টার বা নিচের বোতামটি টিপুন।<br />\nনির্দেশিকা: <strong>({{int:cur}})</strong> = বর্তমান সংস্করণের সাথে পার্থক্য, <strong>({{int:last}})</strong> = পূর্বের সংস্করণের সাথে পার্থক্য,  <strong>{{int:minoreditletter}}</strong> = অনুল্লেখ্য সম্পাদনা।",
-       "history-fieldset-title": "সà¦\82শà§\8bধিত à¦¸à¦\82সà§\8dà¦\95রণà§\87র à¦\9cনà§\8dয à¦\85নà§\81সনà§\8dধান à¦\95রুন",
+       "history-fieldset-title": "সà¦\82শà§\8bধনà¦\97à§\81লি à¦\9bাà¦\81à¦\95ুন",
        "history-show-deleted": "শুধুমাত্র অপসারিত সংশোধন",
        "histfirst": "সবচেয়ে পুরনো",
        "histlast": "সবচেয়ে নতুন",
        "historysize": "({{PLURAL:$1|১ বাইট|$1 বাইট}})",
-       "historyempty": "(খালি)",
+       "historyempty": "খালি",
        "history-feed-title": "সংশোধনের ইতিহাস",
        "history-feed-description": "এই উইকিতে এই পাতার সংশোধনের ইতিহাস",
        "history-feed-item-nocomment": "$2-এ $1",
        "revdelete-hide-user": "সম্পাদকের ব্যবহারকারী নাম/আইপি ঠিকানা",
        "revdelete-hide-restricted": "প্রশাসকবৃন্দ এবং অন্যদের ক্ষেত্রে এই ডাটা রোধ করো",
        "revdelete-radio-same": "(পরিবর্তন করবেন না)",
-       "revdelete-radio-set": "লà§\81à¦\95ায়িত",
+       "revdelete-radio-set": "লà§\81à¦\95ানà§\8b",
        "revdelete-radio-unset": "দৃশ্যমান",
        "revdelete-suppress": "সব প্রশাসক ও অন্যান্যদের কাছ থেকে উপাত্ত লুকিয়ে রাখা হোক।",
        "revdelete-unsuppress": "সংশোধন পুনঃস্থাপনের উপর সীমাবদ্ধতা দূর করো",
        "right-reupload-own": "নিজের দ্বারা আপলোডকৃত ফাইল যা ইতিমধ্যেই বিদ্যমান, সেটি মুছে পুনরায় নতুন করে আপলোড করা",
        "right-reupload-shared": "স্থানীয়ভাবে শেয়ার্ড মিডিয়া রিপোজিটরীর ফাইল ওভাররাইড",
        "right-upload_by_url": "URL থেকে ফাইল আপলোড",
-       "right-purge": "নিশà§\8dà¦\9aিতà¦\95রণ à¦\9bাড়াà¦\87 সাইটের ক্যাশ শোধন করা",
+       "right-purge": "à¦\8fà¦\95à¦\9fি à¦ªà¦¾à¦¤à¦¾à¦° à¦\9cনà§\8dয সাইটের ক্যাশ শোধন করা",
        "right-autoconfirmed": "অর্ধ-সুরক্ষিত পাতা সম্পাদনা",
        "right-bot": "সয়ংক্রিয় পদ্ধতি হিসাবে চিহ্নিত করণ",
        "right-nominornewtalk": "বার্তা লেখার মত আলাপ পাতায় কোনো অনুল্লেখ্য সম্পাদনা নেই",
        "right-browsearchive": "অপসারিত পাতা অনুসন্ধান করো",
        "right-undelete": "পাতাটি পুনরুদ্ধার করুন",
        "right-suppressrevision": "যেকোন ব্যবহারকারী থেকে পাতার নির্দিষ্ট সংশোধন দেখুন, লুকিয়ে  রাখুন এবং প্রকাশ্যে আনুন",
-       "right-viewsuppressed": "যà§\87à¦\95à§\8bন à¦¬à§\8dযবহারà¦\95ারà§\80র à¦\95াà¦\9b à¦¥à§\87à¦\95à§\87 à¦²à§\81à¦\95ায়িত সংস্করণগুলি দেখুন",
+       "right-viewsuppressed": "যà§\87à¦\95à§\8bন à¦¬à§\8dযবহারà¦\95ারà§\80র à¦\95াà¦\9b à¦¥à§\87à¦\95à§\87 à¦²à§\81à¦\95ানà§\8b সংস্করণগুলি দেখুন",
        "right-suppressionlog": "ব্যক্তিগত লগ দেখাও",
        "right-block": "সম্পাদনা করতে কোনো ব্যবহারকারীকে বাঁধা দাও",
        "right-blockemail": "ই-মেইল পাঠাতে কোনো ব্যবহারকারীকে বাঁধা দাও",
        "action-changetags": "নির্দিষ্ট সংস্করণ এবং লগ ভুক্তিগুলিতে যথেচ্ছভাবে ট্যাগ সংযোজন ও অপসারণ করা",
        "action-deletechangetags": "ডাটাবেজ থেকে ট্যাগ অপসরণ করার",
        "action-purge": "এই পাতাটি শোধন করুন",
+       "action-apihighlimits": "API কোয়েরিতে আরো উচ্চতর সীমা ব্যবহার করার",
+       "action-autoconfirmed": "আইপি-ভিত্তিক রেট সীমার দ্বারা প্রভাবিত না হবার",
+       "action-bigdelete": "বিশাল ইতিহাস সম্বলিত পাতা অপসারণ করার",
+       "action-blockemail": "কোনো ব্যবহারকারীকে ই-মেইল পাঠানো থেকে বাধা দেয়ার",
+       "action-bot": "স্বয়ংক্রিয় পদ্ধতি হিসাবে চিহ্নিতকরণ করার",
+       "action-editprotected": "\"{{int:protect-level-sysop}}\" হিসেবে সুরক্ষিত পাতা সম্পাদনা করার",
+       "action-editsemiprotected": "\"{{int:protect-level-autoconfirmed}}\" হিসেবে সুরক্ষিত পাতা সম্পাদনা করার",
+       "action-editinterface": "ব্যবহারকারী ইন্টারফেস সম্পাদনা করার",
+       "action-editusercss": "অন্য ব্যবহারকারীগণের CSS ফাইল সম্পাদনা করার",
+       "action-edituserjson": "অন্য ব্যবহারকারীগণের JSON ফাইল সম্পাদনা করার",
+       "action-edituserjs": "অন্য ব্যবহারকারীগণের জাভাস্ক্রিপ্ট ফাইল সম্পাদনা করার",
+       "action-editsitecss": "সাইটব্যাপী CSS সম্পাদনা করার",
+       "action-editsitejson": "সাইটব্যাপী JSON সম্পাদনা করার",
+       "action-editsitejs": "সাইটব্যাপী জাভাস্ক্রিপ্ট সম্পাদনা করার",
+       "action-editmyusercss": "স্ব ব্যবহারকারীর CSS ফাইল সম্পাদনা করার",
+       "action-editmyuserjson": "স্ব ব্যবহারকারী JSON ফাইল সম্পাদনা করার",
+       "action-editmyuserjs": "স্ব ব্যবহারকারী জাভাস্ক্রিপ্ট ফাইল সম্পাদনা করার",
+       "action-viewsuppressed": "যেকোন ব্যবহারকারীর কাছ থেকে লুকানো সংস্করণগুলি দেখার",
+       "action-hideuser": "ব্যবহারকারীকে বাধা দেয়ার, এবং তা সর্বসাধারণের দৃষ্টিসীমা থেকে লুকানোর",
+       "action-ipblock-exempt": "আইপি বাধা, স্বয়ংক্রিয় বাধা ও পরিসীমার বাধা এড়ানোর",
+       "action-unblockself": "নিজেকে বাধামুক্ত করার",
+       "action-noratelimit": "রেট সীমার দ্বারা প্রভাবিত না হবার",
+       "action-reupload-own": "নিজের দ্বারা আপলোডকৃত ফাইল পুনর্লিখনের",
+       "action-nominornewtalk": "আলোচনার পৃষ্ঠাগুলিতে অনুল্লেখ্য সম্পাদনা নেই নতুন বার্তা প্রম্পট ট্রিগার করার",
+       "action-markbotedits": "ফেরত আনা সম্পাদনাসমূহকে বট সম্পাদনা হিসেবে চিহ্নিত করার",
+       "action-patrolmarks": "সাম্প্রতিক পরিবর্তনের পরীক্ষণের চিহ্ন দেখার",
+       "action-override-export-depth": "৫-এর গভীরতা পর্যন্ত সংযোগকৃত পাতাসহ পাতাগুলি রপ্তানি করার",
+       "action-suppressredirect": "পাতা স্থানান্তর করার সময় উৎস পাতা থেকে পুনর্নির্দেশ তৈরী করার",
        "nchanges": "$1টি {{PLURAL:$1|পরিবর্তন}}",
        "enhancedrc-since-last-visit": "{{PLURAL:$1|সর্বশেষ প্রদর্শনের পর}} $1টি",
        "enhancedrc-history": "ইতিহাস",
        "rcfilters-savedqueries-already-saved": "এই ছাঁকনিগুলি ইতিমধ্যে সংরক্ষণ করা হয়েছে। একটি নতুন সংরক্ষিত ছাঁকনি তৈরি করতে আপনার সেটিং পরিবর্তন করুন।",
        "rcfilters-restore-default-filters": "পূর্বনির্ধারিত ছাঁকনি পুনরুদ্ধার করুন",
        "rcfilters-clear-all-filters": "সব ছাঁকনি পরিষ্কার করুন",
-       "rcfilters-show-new-changes": "নতুনতর পরিবর্তনসমূহ দেখুন",
+       "rcfilters-show-new-changes": "$1 থেকে নতুনতর পরিবর্তনসমূহ দেখুন",
        "rcfilters-search-placeholder": "সাম্প্রতিক পরিবর্তনসমূহ ছাঁকুন (ব্রাউজ বা টাইপ করা শুরু করুন)",
        "rcfilters-invalid-filter": "অকার্যকর ছাঁকনি",
        "rcfilters-empty-filter": "কোনো সক্রিয় ফিল্টার নেই। সমস্ত অবদান দেখানো হয়েছে।",
        "rcfilters-filter-editsbyself-description": "আপনার নিজস্ব অবদান।",
        "rcfilters-filter-editsbyother-label": "অন্যদের দ্বারা পরিবর্তিত",
        "rcfilters-filter-editsbyother-description": "আপনার নিজস্বগুলি ছাড়া সকল পরিবর্তন।",
-       "rcfilters-filtergroup-userExpLevel": "ব্যবহারকারী নিবন্ধন ও অভিজ্ঞতা",
+       "rcfilters-filtergroup-user-experience-level": "ব্যবহারকারী নিবন্ধন ও অভিজ্ঞতা",
        "rcfilters-filter-user-experience-level-registered-label": "নিবন্ধিত",
        "rcfilters-filter-user-experience-level-registered-description": "প্রবেশকৃত সম্পাদকবৃন্দ।",
        "rcfilters-filter-user-experience-level-unregistered-label": "অনিবন্ধিত",
        "rcfilters-filter-watchlist-notwatched-description": "আপনার নজরতালিকায় থাকা পাতাগুলি ব্যতীয় সবকিছু।",
        "rcfilters-filtergroup-watchlistactivity": "নজরতালিকার কার্যক্রম",
        "rcfilters-filter-watchlistactivity-unseen-label": "অদেখা পরিবর্তন",
+       "rcfilters-filter-watchlistactivity-unseen-description": "পাতাসমূহের পরিবর্তন ঘটার পর থেকে আপনি যেসব পাতা পরিদর্শন করেননি।",
        "rcfilters-filter-watchlistactivity-seen-label": "দেখা পরিবর্তন",
+       "rcfilters-filter-watchlistactivity-seen-description": "পাতাসমূহের পরিবর্তন ঘটার পর থেকে আপনি যেসব পাতা পরিদর্শন করেছেন।",
        "rcfilters-filtergroup-changetype": "পরিবর্তনের ধরন",
        "rcfilters-filter-pageedits-label": "পাতার সম্পাদনা",
        "rcfilters-filter-pageedits-description": "উইকি বিষয়বস্তু, আলোচনা, বিষয়শ্রেণীর বিবরণ... ইত্যাদিতে সম্পাদনা",
        "rcfilters-hideminor-conflicts-typeofchange-global": "\"অনুল্লেখ্য সম্পাদনা\" ছাঁকনিটির সাথে এক বা ততোধিক \"পরিবর্তনের ধরন\"-সংক্রান্ত ছাঁকনির সংঘর্ষ আছে, কারণ কিছু নির্দিষ্ট ধরনের সম্পাদনা \"অনুল্লেখ্য\" হিসেবে চিহ্নিত করা সম্ভব নয়। সংঘর্ষে থাকা ছাঁকনিগুলিকে উপরের \"সক্রিয় ছাঁকনিসমূহ\" এলাকাতে চিহ্নিত করা হয়েছে।",
        "rcfilters-hideminor-conflicts-typeofchange": "কিছু নির্দিষ্ট ধরনের সম্পাদনা \"অনুল্লেখ্য\" হিসেবে চিহ্নিত করা সম্ভব নয়, তাই এই ছাঁকনিটির সাথে নিম্নোক্ত পরিবর্তনের ধরন ছাঁকনিগুলির সংঘর্ষ আছে: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "এই \"পরিবর্তনের ধরন\"-সংক্রান্ত ছাঁকনিটির সাথে \"অনুল্লেখ্য সম্পাদনা\" ছাঁকনিটির সংঘর্ষ আছে। কিছু নির্দিষ্ট ধরনের সম্পাদনা \"অনুল্লেখ্য\" হিসেবে চিহ্নিত করা সম্ভব নয়।",
-       "rcfilters-filtergroup-lastRevision": "সর্বশেষ সংস্করণ",
+       "rcfilters-filtergroup-lastrevision": "সর্বশেষ সংস্করণ",
        "rcfilters-filter-lastrevision-label": "সর্বশেষ সংশোধন",
        "rcfilters-filter-lastrevision-description": "শুধুমাত্র একটি পাতার সর্বশেষ সাম্প্রতিক পরিবর্তন।",
        "rcfilters-filter-previousrevision-label": "সর্বশেষ সংশোধন নয়",
        "rcfilters-preference-help": "ছাঁকনিগুলি অনুসন্ধান বা আলোকপাতকরণ কার্যকারিতা ছাড়া সাম্প্রতিক পরিবর্তন লোড করে",
        "rcfilters-watchlist-preference-label": "জাভাস্ক্রিপ্টহীন ইন্টারফেস ব্যবহার করুন",
        "rcfilters-watchlist-preference-help": "ছাঁকনি অনুসন্ধান বা আলোকপাতকরণ বৈশিষ্ট্য ছাড়া নজরতালিকা লোড করে।",
+       "rcfilters-filter-showlinkedfrom-label": "এটি থেকে সংযোগকারী পাতাসমূহের পরিবর্তন দেখান",
+       "rcfilters-filter-showlinkedfrom-option-label": "নির্বাচিত পাতাটি থেকে <strong>সংযোগকারী পাতাসমূহ</strong>",
+       "rcfilters-filter-showlinkedto-label": "এটিতে সংযোগকারী পাতাসমূহের পরিবর্তন দেখান",
+       "rcfilters-filter-showlinkedto-option-label": "নির্বাচিত পাতাটিতে <strong>সংযোগকারী পাতাসমূহ</strong>",
        "rcfilters-target-page-placeholder": "একটি পাতার নাম (বা বিষয়শ্রেণী) লিখুন",
        "rcnotefrom": "<strong>$2</strong>টা থেকে সংঘটিত পরিবর্তনগুলি (সর্বোচ্চ <strong>$1টি</strong> দেখানো হয়েছে)।",
        "rclistfromreset": "তারিখ নির্বাচন পুনঃস্থাপন করুন",
        "minoreditletter": "অ",
        "newpageletter": "ন",
        "boteditletter": "ব",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|জন ব্যবহারকারী|জন ব্যবহারকারী}} এই পাতার উপর নজর রাখছেন]",
        "rc-change-size-new": "পরিবর্তনের পর $1 {{PLURAL:$1|বাইট}}",
        "newsectionsummary": "/* $1 */ নতুন অনুচ্ছেদ",
        "rc-enhanced-expand": "বিস্তারিত দেখাও",
        "uploaded-script-svg": "আপলোডকৃত SVG ফাইলে স্ক্রিপ্টযোগ্য উপাদান \"$1\" পাওয়া গেছে।",
        "uploaded-hostile-svg": "আপলোড করা SVG ফাইলের শৈলী উপাদানে অনিরাপদ সিএসএস পাওয়া গেছে।",
        "uploaded-event-handler-on-svg": "এসভিজি ফাইলের জন্য <code>$1=\"$2\"</code> ইভেন্ট-হ্যান্ডলার বৈশিষ্ট্যটি নির্ধারণ করা অনুমোদিত নয়।",
-       "uploaded-href-attribute-svg": "এসভিজি ফাইলের href বৈশিষ্ট্যগুলির জন্য কেবলমাত্র http:// বা https:// লক্ষ্যগুলি অনুমোদিত; কিন্তু <code>&lt;$1 $2=\"$3\"&gt;</code> পাওয়া গেছে।",
+       "uploaded-href-attribute-svg": "<a> উপাদান শুধুমাত্র উপাত্তে সংযোগ (href) করা যাবে: (এম্বেড করা ফাইল), http:// বা https://, বা খণ্ডিত (#, একই-নথি) লক্ষ্যগুলি। অন্যান্য উপাদানের জন্য, যেমন <image>, কেবলমাত্র উপাত্ত: ও খণ্ড অনুমোদিত। আপনার এসভিজি রপ্তানি করার সময় ছবি এম্বেড করার চেষ্টা করুন। <code>&lt;$1 $2=\"$3\"&gt;</code> পাওয়া গেছে।",
        "uploaded-href-unsafe-target-svg": "অনিরাপদ উপাত্তে href পাওয়া গেছে: আপলোডকৃত SVG ফাইলে URI লক্ষ্য ছিল <code>&lt;$1 $2=\"$3\"&gt;</code>।",
        "uploaded-animate-svg": "\"animate\" ট্যাগটি পাওয়া গেছে যা আপলোডকৃত এসভিজি ফাইলের <code>&lt;$1 $2=\"$3\"&gt;</code> - এই \"from\" অ্যাট্রিবিউটটি ব্যবহার করে href পরিবর্তন করতে পারে।",
        "uploaded-setting-event-handler-svg": "ইভেন্ট-হ্যান্ডলার অ্যাট্রিবিউট নির্ধারণ করতে বাধা দেওয়া হয়েছে। আপলোডকৃত এসভিজি ফাইলে <code>&lt;$1 $2=\"$3\"&gt;</code> খুঁজে পাওয়া গেছে।",
        "img-auth-nopathinfo": "পথের তথ্য পাওয়া যাচ্ছে না।\nআপনার সার্ভার অবশ্যই REQUEST_URI ও/বা PATH_INFO চলক অতিক্রম করাতে সমর্থ হতে হবে।\nযদি এটি তাই হয়, তবে $wgUsePathInfo সক্রিয় করার চেষ্টা করুন।\nবিস্তারিত জানতে https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization দেখুন।",
        "img-auth-notindir": "অনুরোধকৃত পাথটি কনফিগার করা আপলোড ডিরেক্টরী নয়।",
        "img-auth-badtitle": "\"$1\" থেকে একটি সঠিক শিরনাম তৈরী করা যাচ্ছে না।",
-       "img-auth-nologinnWL": "আপনি প্রবেশ করেননি এবং \"$1\" নজরতালিকায় নেই।",
        "img-auth-nofile": "ফাইল \"$1\" নাই।",
        "img-auth-isdir": "আপনি \"$1\" ডিরেক্টরী দেখতে চেষ্ঠা করছেন।\nশুধুমাত্র ফাইল দেখার অনুমতি রয়েছে।",
        "img-auth-streaming": "স্ট্রিমিং \"$1\"।",
        "delete-confirm": "\"$1\" অপসারণ",
        "delete-legend": "অপসারণ",
        "historywarning": "<strong>সতর্কীকরণ:</strong> যে পাতাটি আপনি মুছে ফেলতে যাচ্ছেন তার ইতিহাসে প্রায় $1টি {{PLURAL:$1|সংশোধন}} রয়েছে:",
-       "historyaction-submit": "দà§\87à¦\96াà¦\93",
+       "historyaction-submit": "সà¦\82শà§\8bধন à¦¦à§\87à¦\96ান",
        "confirmdeletetext": "আপনি একটি পাতা সেটির সমস্ত ইতিহাসসহ মুছে ফেলতে যাচ্ছেন।\nঅনুগ্রহ করে নিশ্চিত করুন আপনি আসলেই এটি করতে চান, আপনি এর ফলাফল সম্পর্কে অবহিত, এবং আপনি [[{{MediaWiki:Policy-url}}|নীতিমালা]] মেনে এটি করছেন।",
        "actioncomplete": "কাজটি নিষ্পন্ন হয়েছে",
        "actionfailed": "অ্যাকশন ব্যর্থ",
        "deleting-backlinks-warning": "<strong>সতর্কীকরণ:</strong> আপনি যেটি মুছে ফেলতে যাচ্ছেন তা [[Special:WhatLinksHere/{{FULLPAGENAME}}|অন্যান্য পাতাসমূহে]] সংযুক্ত অথবা অন্তর্ভুক্ত রয়েছে।",
        "deleting-subpages-warning": "<strong>সতর্কীকরণ:</strong> আপনি যে পাতাটি মুছে ফেলতে যাচ্ছেন তাঁর [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|একটি উপপাতা|$1টি উপপাতা|51=৫০টির বেশী}}]] রয়েছে।",
        "rollback": "সম্পাদনা ফিরিয়ে নিন",
+       "rollback-confirmation-confirm": "দয়া করে নিশ্চিত করুন:",
+       "rollback-confirmation-yes": "পুনর্বহাল করুন",
+       "rollback-confirmation-no": "বাতিল করুন",
        "rollbacklink": "পুনর্বহাল",
        "rollbacklinkcount": "$1টি {{PLURAL:$1|সম্পাদনা}} রোলব্যাক করুন",
        "rollbacklinkcount-morethan": "$1টির বেশি {{PLURAL:$1|সম্পাদনা}} রোলব্যাক করুন",
        "revertpage": "[[Special:Contributions/$2|$2]] ([[User talk:$2|আলাপ]])-এর সম্পাদিত সংস্করণ হতে [[User:$1|$1]]-এর সম্পাদিত সর্বশেষ সংস্করণে ফেরত যাওয়া হয়েছে",
        "revertpage-nouser": "একজন গোপন ব্যবহারকারী কর্তৃক সম্পাদিত সম্পাদনাটি বাতিলপূর্বক {{GENDER:$1|[[User:$1|$1]]}}-এর সর্বশেষ সম্পাদনায় ফেরত যাওয়া হয়েছে",
        "rollback-success": "{{GENDER:$3|$1}}-এর সম্পাদনাগুলি পূর্বাবস্থায় ফিরিয়ে নেওয়া হয়েছে; {{GENDER:$4|$2}}-এর করা শেষ সংস্করণে পাতাটি ফেরত নেওয়া হয়েছে।",
-       "rollback-success-notify": "$1-এর সম্পাদনাগুলি বাতিল করা হয়েছে; \n$2-এর করা শেষ সংস্করণে ফেরত নেওয়া হয়েছে। [$3 পরিবর্তন দেখুন]",
        "sessionfailure-title": "সেশন পরিত্যক্ত",
        "sessionfailure": "আপনার প্রবেশ সেশনে একটি সমস্যা হয়েছে বলে মনে হচ্ছে;\nসেশন হাইজ্যাক প্রতিরোধের উপায় হিসেবে এই কাজটি বাতিল করা হয়েছে।\nদয়া করে ফরমটি পুনরায় জমা দিন।",
        "changecontentmodel": "একটি পাতার বিষয়বস্তুর রূপ পরিবর্তন",
        "mycontris": "অবদান",
        "anoncontribs": "অবদান",
        "contribsub2": "{{GENDER:$3|$1}} ($2)-এর জন্য",
+       "contributions-subtitle": "{{GENDER:$3|$1}}-এর জন্য",
        "contributions-userdoesnotexist": "ব্যবহারকারী অ্যাকাউন্ট \"$1\" অনিবন্ধিত।",
        "nocontribs": "এই শর্তগুলির সাথে মিলে যায়, এমন কোন পরিবর্তন খুঁজে পাওয়া যায়নি।",
        "uctop": "বর্তমান",
        "sp-contributions-blocked-notice": "এই ব্যবহারকারী বর্তমানে বাধাদানকৃত অবস্থায় রয়েছেন।\nতথ্যসূত্র হিসেবে সাম্প্রতিক বাধাদান লগের ভুক্তিটি নিচে দেওয়া হলো:",
        "sp-contributions-blocked-notice-anon": "এই আইপি ঠিকানাটি বর্তমানে বাধাদানকৃত অবস্থায় রয়েছে।\nতথ্যসূত্র হিসেবে সাম্প্রতিক বাধাদান লগের ভুক্তিটি নিচে দেওয়া হলো:",
        "sp-contributions-search": "অবদানসমূহের জন্য অনুসন্ধান",
-       "sp-contributions-username": "আইপি (IP) ঠিকানা অথবা ব্যবহারকারীর নাম:",
+       "sp-contributions-username": "আইপি ঠিকানা অথবা ব্যবহারকারীর নাম:",
        "sp-contributions-toponly": "শুধুমাত্র সেই সম্পাদনাগুলি দেখাও যেগুলো সাম্প্রতিক সংস্করণের অন্তর্ভুক্ত",
        "sp-contributions-newonly": "শুধুমাত্র পাতা সৃষ্টি করা সম্পাদনাগুলি দেখাও",
        "sp-contributions-hideminor": "অনুল্লেখ্য সম্পাদনাগুলি লুকিয়ে রাখা হোক",
        "blocklist-userblocks": "অ্যাকাউন্ট বাধা লুকানো হোক",
        "blocklist-tempblocks": "অস্থায়ী বাধা লুকাও",
        "blocklist-addressblocks": "একক আইপি বাধা লুকানো হোক",
+       "blocklist-type": "ধরন:",
+       "blocklist-type-opt-all": "সব",
+       "blocklist-type-opt-sitewide": "সাইটব্যাপী",
+       "blocklist-type-opt-partial": "আংশিক",
        "blocklist-rangeblocks": "রেঞ্জ ব্লকসমূহ লুকান",
        "blocklist-timestamp": "সময়বার্তা",
        "blocklist-target": "লক্ষ্য",
        "blocklogpage": "বাধা দানের লগ",
        "blocklog-showlog": "এই ব্যবহারকারীকে পূর্বেও বাধা প্রদান করা হয়েছিলো।\nতথ্যসূত্র হিসেবে তাই পূর্বের বাধাদানের লগটি নিচে প্রদর্শন করা হচ্ছে:",
        "blocklog-showsuppresslog": "এই ব্যবহারকারীকে পূর্বেও বাধা প্রদান ও লুকানো হয়েছিলো।\nতথ্যসূত্র হিসেবে তাই পূর্বের অপসারণ লগটি নিচে প্রদর্শন করা হচ্ছে:",
-       "blocklogentry": "[[$1]] à¦\95à§\87 $2 à¦®à§\87য়াদের জন্য বাধাদান করেছেন $3",
-       "reblock-logentry": "[[$1]] এর ব্লক সেটিং পরিবর্তন করা হয়েছে যেটি শেষ হবে $2 $3 সময়ে",
+       "blocklogentry": "[[$1]] à¦\95à§\87 $2 à¦¸à¦®à¦¯à¦¼ের জন্য বাধাদান করেছেন $3",
+       "reblock-logentry": "[[$1]]-এর বাধাদান সেটিং পরিবর্তন করেছেন যেটি শেষ হবার মেয়াদ $2 $3",
        "blocklogtext": "এটি ব্যবহারকারীদেরকে বাধা দানের বা বাধা তুলে নেওয়ার লগ।\nস্বয়ংক্রিয়ভাবে বাধাদানকৃত আইপি ঠিকানাগুলি এখানে তালিকাবদ্ধ করা হয়নি।\nবর্তমানে সক্রিয় নিষিদ্ধকরণ ও বাধাদানের তালিকার জন্য [[Special:BlockList| বাধাদান তালিকা]] দেখুন।",
        "unblocklogentry": "$1-এর উপর বাধা তুলে নেয়া হয়েছে",
        "block-log-flags-anononly": "কেবল বেনামী ব্যবহারকারীরা",
        "block-log-flags-noemail": "ই-মেইলে বাধা আছে",
        "block-log-flags-nousertalk": "নিজের আলাপের পাতা সম্পাদনা করতে পারবে না",
        "block-log-flags-angry-autoblock": "উন্নত অটোব্লক সক্রিয়",
-       "block-log-flags-hiddenname": "ব্যবহারকারীনাম লুকায়িত",
+       "block-log-flags-hiddenname": "ব্যবহারকারী নাম লুক্কায়িত",
        "range_block_disabled": "প্রশাসকের পক্ষে আইপি ঠিকানার শ্রেণী বাধাদানের ক্ষমতা নিষ্ক্রিয় আছে।",
        "ipb_expiry_invalid": "মেয়াদোত্তীর্ণকাল অবৈধ।",
        "ipb_expiry_old": "মেয়াদোত্তীর্ণের সময় অতীত হয়েছে।",
        "ipb_expiry_temp": "লুকানো ব্যবহারকারীনাম বাধা চিরস্থায়ী হতে হবে।",
        "ipb_hide_invalid": "এই অ্যাকাউন্ট বাধা দেয়া সম্ভব নয়; এটি {{PLURAL:$1|একের অধিক|$1টি}} সম্পাদনা করেছে।",
+       "ipb_hide_partial": "লুকানো ব্যবহারকারী নামের বাধাদান অবশ্যই সাইটব্যপী হতে হবে।",
        "ipb_already_blocked": "\"$1\" ইতিমধ্যে বাধাপ্রাপ্ত।",
        "ipb-needreblock": "$1 ইতিমধ্যেই বাধাপ্রাপ্ত আছেন। আপনি কি সেটিংস পরিবর্তন করতে চান?",
        "ipb-otherblocks-header": "অন্যান্য {{PLURAL:$1|বাধা|বাধাসমূহ}}",
        "allmessagesdefault": "আদি টেক্সট",
        "allmessagescurrent": "বর্তমান টেক্সট",
        "allmessagestext": "এটি মিডিয়াউইকি নামস্থানে অন্তর্ভুক্ত সিস্টেম বার্তাগুলোর একটি তালিকা।\nআপনি যদি সাধারণ মিডিয়াউইকির স্থানীয়করণে অবদান রাখতে আগ্রহী হন, অনুগ্রহ করে [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation মিডিয়াউইকি স্থানীয়করণ] এবং [https://translatewiki.net translatewiki.net] দেখুন।",
-       "allmessagesnotsupportedDB": "এই পাতা ব্যবহার করা যাবে না কারণ '''$wgUseDatabaseMessages''' বন্ধ করে রাখা আছে।",
+       "allmessages-not-supported-database": "এই পাতা ব্যবহার করা যাবে না কারণ '''$wgUseDatabaseMessages''' বন্ধ করে রাখা আছে।",
        "allmessages-filter-legend": "ছাঁকনি",
        "allmessages-filter": "Filter by customization state:",
        "allmessages-filter-unmodified": "অপরিবর্তিত",
        "pageinfo-robot-noindex": "অনুনমোদিন",
        "pageinfo-watchers": "পাতাটি প্রদর্শনের সংখ্যা",
        "pageinfo-visiting-watchers": "পাতা পর্যবেক্ষকদের সংখ্যা যারা সাম্প্রতিক সম্পাদনাগুলি পরিদর্শন করেছেন",
-       "pageinfo-few-watchers": "$1 জন {{PLURAL:$1|নজরকারীও}} কম",
+       "pageinfo-few-watchers": "$1 à¦\9cন {{PLURAL:$1|নà¦\9cরà¦\95ারà§\80রà¦\93}} à¦\95ম",
        "pageinfo-few-visiting-watchers": "সাম্প্রতিক সম্পাদনাগুলি সম্ভবত একজন নজরকারী পর্যবেক্ষক করেছেন বা করেনি",
        "pageinfo-redirects-name": "এই পাতায় পুননির্দেশনাসমূহের সংখ্যা",
        "pageinfo-subpages-name": "এই পাতার উপপাতাসমূহ",
        "metadata-help": "এই ফাইলে অতিরিক্ত কিছু তথ্য আছে। সম্ভবত যে ডিজিটাল ক্যামেরা বা স্ক্যানারের মাধ্যমে এটি তৈরি বা ডিজিটায়িত করা হয়েছিল, সেটি কর্তৃক তথ্যগুলি যুক্ত হয়েছে। যদি ফাইলটি তার আদি অবস্থা থেকে পরিবর্তিত হয়ে থাকে, কিছু কিছু বিবরণ পরিবর্তিত ফাইলটির জন্য প্রযোজ্য না-ও হতে পারে।",
        "metadata-expand": "সম্প্রসারিত সবিস্তারে দেখাও",
        "metadata-collapse": "সম্প্রসারিত বিবরণ দেখান",
-       "metadata-fields": "à¦\8fà¦\87 à¦¬à¦¾à¦°à§\8dতায় à¦¤à¦¾à¦²à¦¿à¦\95াভà§\81à¦\95à§\8dত à¦\9aিতà§\8dর à¦®à§\87à¦\9fাডাà¦\9fা à¦\95à§\8dষà§\87তà§\8dরà¦\97à§\81লি à¦\9bবির à¦ªà¦¾à¦¤à¦¾à¦¯à¦¼ à¦ªà§\8dরদরà§\8dশন à¦\95রা à¦¹à¦¬à§\87, à¦¯à¦\96ন à¦®à§\87à¦\9fাডাà¦\9fা à¦¸à¦¾à¦°à¦£à¦¿à¦\9fি à¦¸à¦\82à¦\95à§\81à¦\9aিত à¦\95রা à¦¹à¦¬à§\87। à¦\85নà§\8dয à¦\95à§\8dষà§\87তà§\8dরà¦\97à§\81লি à¦¸à§\8dবাভাবিà¦\95 à¦\85বসà§\8dথায় à¦²à§\81à¦\95ায়িত থাকবে।\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
+       "metadata-fields": "à¦\8fà¦\87 à¦¬à¦¾à¦°à§\8dতায় à¦¤à¦¾à¦²à¦¿à¦\95াভà§\81à¦\95à§\8dত à¦\9aিতà§\8dর à¦®à§\87à¦\9fাডাà¦\9fা à¦\95à§\8dষà§\87তà§\8dরà¦\97à§\81লি à¦\9bবির à¦ªà¦¾à¦¤à¦¾à¦¯à¦¼ à¦ªà§\8dরদরà§\8dশন à¦\95রা à¦¹à¦¬à§\87, à¦¯à¦\96ন à¦®à§\87à¦\9fাডাà¦\9fা à¦¸à¦¾à¦°à¦£à¦¿à¦\9fি à¦¸à¦\82à¦\95à§\81à¦\9aিত à¦\95রা à¦¹à¦¬à§\87। à¦\85নà§\8dয à¦\95à§\8dষà§\87তà§\8dরà¦\97à§\81লি à¦¸à§\8dবাভাবিà¦\95 à¦\85বসà§\8dথায় à¦²à§\81à¦\95ানà§\8b থাকবে।\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
        "namespacesall": "সমস্ত",
        "monthsall": "সমস্ত",
        "confirmemail": "ই-মেইলের ঠিকানা নিশ্চিত করুন",
        "specialpages-group-developer": "ডেভলপারের সরঞ্জাম",
        "blankpage": "খালি পাতা",
        "intentionallyblankpage": "এই পাতাটি ইচ্ছা করে খালি রাখা হয়েছে",
+       "disabledspecialpage-disabled": "এই পৃষ্ঠাটি একজন সিস্টেম প্রশাসক দ্বারা নিষ্ক্রিয় করা হয়েছে।",
        "external_image_whitelist": "  #এই লাইন ঠিক যেমন আছে<প্রাক> তেমন রাখুন<pre>\n #রেগুলার এক্সপ্রেশনের টুকরা নীচে (শুধুমাত্র অংশ / / মধ্যে যে যায়) বসান\n#এইগুলি এক্সটার্নাল (hotlinked) ইমেজের URL-এর সাথে মেলানো হবে\n#যেগুলি মিলবে, সেগুলি চিত্র হিসাবে প্রদর্শিত হবে, অন্যথায় শুধুমাত্র ইমেজ লিঙ্ক প্রদর্শিত হবে\n#যে লাইনের প্রারম্ভে # আছে সেই লাইনগুলি মন্তব্যসমূহ হিসাবে ব্যবহার করা হয়\n#এটি কেস-অসংবেদী\n\n#এই রেখার উপরের regex টুকরা বসান. এই লাইন ঠিক যেমন আছে তেমন রাখুন</pre>",
        "tags": "বৈধ পরিবর্তন ট্যাগ",
        "tag-filter": "[[Special:Tags|ট্যাগ]] ছাঁকনি:",
        "logentry-suppress-revision": "$1 গোপনে {{PLURAL:$5|একটি সংস্করণের|$5টি সংস্করণের}} দৃশ্যমানতা {{GENDER:$2|পরিবর্তন}} করেছেন $3: $4",
        "logentry-suppress-event-legacy": "$1 গোপনে $3টায় লগ ইভেন্টসমূহের দৃশ্যমানতা {{GENDER:$2|পরিবর্তন}} করেছেন",
        "logentry-suppress-revision-legacy": "$1 গোপনে $3টায় সংস্করণসমূহের দৃশ্যমানতা {{GENDER:$2|পরিবর্তন}} করেছেন",
-       "revdelete-content-hid": "বিষয়বস্তু লুকায়িত",
-       "revdelete-summary-hid": "সম্পাদনা সারাংশ লুকায়িত",
-       "revdelete-uname-hid": "ব্যবহারকারী নাম লুকায়িত",
+       "revdelete-content-hid": "বিষয়বসà§\8dতà§\81 à¦²à§\81à¦\95à§\8dà¦\95ায়িত",
+       "revdelete-summary-hid": "সম্পাদনার সারাংশ লুকানো",
+       "revdelete-uname-hid": "বà§\8dযবহারà¦\95ারà§\80 à¦¨à¦¾à¦® à¦²à§\81à¦\95à§\8dà¦\95ায়িত",
        "revdelete-content-unhid": "বিষয়বস্তু প্রদর্শিত",
        "revdelete-summary-unhid": "সম্পাদনা সারাংশ প্রদর্শিত",
        "revdelete-uname-unhid": "ব্যবহারকারী নাম প্রদর্শিত",
        "revdelete-unrestricted": "এই সীমাবদ্ধতা প্রশাসকের ক্ষেত্রে তুলে নাও",
        "logentry-block-block": "$1 {{GENDER:$4|$3}} কে $5 মেয়াদের জন্য {{GENDER:$2|বাধাদান}} করেছেন $6",
        "logentry-block-unblock": "$1 {{GENDER:$4|$3}}-এর উপর থেকে বাধা তুলে {{GENDER:$2|নিয়েছেন}}",
-       "logentry-block-reblock": "$1 {{GENDER:$4|$3}}-এর জন্য বাধাদান সেটিং $5 সময়ের জন্য {{GENDER:$2|পরিবর্তন}} করেছেন $6",
+       "logentry-block-reblock": "$1 {{GENDER:$4|$3}}-এর বাধাদান সেটিং {{GENDER:$2|পরিবর্তন করেছেন}} যেটি শেষ হবার মেয়াদ $5 $6",
+       "logentry-partialblock-block-page": "$2 {{PLURAL:$1|পাতাটি|পাতাগুলি}}",
+       "logentry-partialblock-block-ns": "$2 {{PLURAL:$1|নামস্থানটি|নামস্থানগুলি}}",
+       "logentry-partialblock-block": "$1 {{GENDER:$4|$3}} কে $7 সম্পাদনা করা থেকে $5 সময়ের জন্য {{GENDER:$2|বাধাদান করেছেন}} $6",
+       "logentry-partialblock-reblock": "$1 $7তে সম্পাদনা করা প্রতিরোধ করে {{GENDER:$4|$3}}-এর বাধাদান সেটিং {{GENDER:$2|পরিবর্তন করেছেন}} যেটি শেষ হবার মেয়াদ $5 $6",
+       "logentry-non-editing-block-block": "$1 {{GENDER:$4|$3}} কে সম্পাদনা-ছাড়া নির্দিষ্ট কর্ম করা থেকে $5 সময়ের জন্য {{GENDER:$2|বাধাদান করেছেন}} $6",
+       "logentry-non-editing-block-reblock": "$1 সম্পাদনা-ছাড়া নির্দিষ্ট কর্মের জন্য {{GENDER:$4|$3}}-এর বাধাদান সেটিং {{GENDER:$2|পরিবর্তন করেছেন}} যেটি শেষ হবার মেয়াদ $5 $6",
        "logentry-suppress-block": "$1 {{GENDER:$4|$3}} কে $5 মেয়াদের জন্য {{GENDER:$2|বাধাদান}} করেছেন $6",
-       "logentry-suppress-reblock": "$1 {{GENDER:$4|$3}}-à¦\8fর à¦\9cনà§\8dয à¦¬à¦¾à¦§à¦¾à¦¦à¦¾à¦¨ à¦¸à§\87à¦\9fিà¦\82 $5 à¦¸à¦®à¦¯à¦¼à§\87র à¦\9cনà§\8dয {{GENDER:$2|পরিবরà§\8dতন}} à¦\95রà§\87à¦\9bà§\87ন $6",
+       "logentry-suppress-reblock": "$1 {{GENDER:$4|$3}}-à¦\8fর à¦¬à¦¾à¦§à¦¾à¦¦à¦¾à¦¨ à¦¸à§\87à¦\9fিà¦\82 {{GENDER:$2|পরিবরà§\8dতন à¦\95রà§\87à¦\9bà§\87ন}} à¦¯à§\87à¦\9fি à¦¶à§\87ষ à¦¹à¦¬à¦¾à¦° à¦®à§\87য়াদ $5 $6",
        "logentry-import-upload": "$1 ফাইল আপলোড দ্বারা $3 {{GENDER:$2|আমদানি করেছেন}}",
        "logentry-import-upload-details": "$1 ফাইল আপলোড দ্বারা $3 {{GENDER:$2|আমদানি করেছেন}} ($4টি {{PLURAL:$4|সংশোধন}})",
        "logentry-import-interwiki": "$1 অন্য একটি উইকিতে থেকে $3 {{GENDER:$2|আমদানি করেছে}}",
        "expand_templates_generate_xml": "XML পার্স বৃক্ষ দেখাও",
        "expand_templates_generate_rawhtml": "এইচটিএমএল দেখাও",
        "expand_templates_preview": "প্রাকদর্শন",
-       "expand_templates_preview_fail_html": "<em>{{SITENAME}}-এ raw HTML সক্রিয় আছে ও সেশন উপাত্ত হারিয়ে গিয়েছে, জাভাস্ক্রিপ্ট ভিত্তিক আক্রমণ থেকে প্রতিরক্ষার জন্য প্রাকদর্শনটি লুকায়িত আছে।</em>\n\n<strong>যদি এটি সম্পাদনার একটি বৈধ প্রচেষ্টা হয়, তবে অনুগ্রহ করে আবার চেষ্টা করুন।</strong>\nযদি তারপরেও কাজ না হয়, তবে অ্যাকাউন্ট থেকে [[Special:UserLogout|বেরিয়ে গিয়ে]] আবার প্রবেশ করুন, এবং পরীক্ষা করে দেখুন যে আপনার ব্রাউজারে এই সাইট থেকে কুকি অনুমতি দেয়।",
-       "expand_templates_preview_fail_html_anon": "<em>{{SITENAME}}-à¦\8f raw HTML à¦¸à¦\95à§\8dরিয় à¦\86à¦\9bà§\87 à¦\93 à¦\86পনি à¦ªà§\8dরবà§\87শ à¦\95রà§\87ন à¦¨à¦¿, à¦\9cাভাসà§\8dà¦\95à§\8dরিপà§\8dà¦\9f à¦­à¦¿à¦¤à§\8dতিà¦\95 à¦\86à¦\95à§\8dরমণ à¦¥à§\87à¦\95à§\87 à¦ªà§\8dরতিরà¦\95à§\8dষার à¦\9cনà§\8dয à¦ªà§\8dরাà¦\95দরà§\8dশনà¦\9fি à¦²à§\81à¦\95ায়িত à¦\86à¦\9bà§\87।</em>\n\n<strong>যদি à¦\8fà¦\9fি à¦¸à¦®à§\8dপাদনার à¦\8fà¦\95à¦\9fি à¦¬à§\88ধ à¦ªà§\8dরà¦\9aà§\87ষà§\8dà¦\9fা à¦¹à¦¯à¦¼, à¦¤à¦¬à§\87 à¦\85নà§\81à¦\97à§\8dরহ à¦\95রà§\87  [[Special:UserLogin|প্রবেশ করুন]] ও আবার চেষ্টা করুন।</strong>",
+       "expand_templates_preview_fail_html": "<em>যেহেতু {{SITENAME}}-এ raw HTML সক্রিয় আছে ও সেশন উপাত্ত হারিয়ে গিয়েছে, জাভাস্ক্রিপ্ট ভিত্তিক আক্রমণ থেকে প্রতিরক্ষার জন্য প্রাকদর্শনটি লুকানো আছে।</em>\n\n<strong>যদি এটি সম্পাদনার একটি বৈধ প্রচেষ্টা হয়, তবে অনুগ্রহ করে আবার চেষ্টা করুন।</strong>\nযদি তারপরেও কাজ না হয়, তবে অ্যাকাউন্ট থেকে [[Special:UserLogout|বেরিয়ে গিয়ে]] আবার প্রবেশ করুন, এবং পরীক্ষা করে দেখুন যে আপনার ব্রাউজারে এই সাইট থেকে কুকি অনুমতি দেয়।",
+       "expand_templates_preview_fail_html_anon": "<em>{{SITENAME}}-à¦\8f raw HTML à¦¸à¦\95à§\8dরিয় à¦\86à¦\9bà§\87 à¦\93 à¦\86পনি à¦ªà§\8dরবà§\87শ à¦\95রà§\87ন à¦¨à¦¿, à¦¤à¦¾à¦\87 à¦\9cাভাসà§\8dà¦\95à§\8dরিপà§\8dà¦\9f à¦­à¦¿à¦¤à§\8dতিà¦\95 à¦\86à¦\95à§\8dরমণ à¦¥à§\87à¦\95à§\87 à¦ªà§\8dরতিরà¦\95à§\8dষার à¦\9cনà§\8dয à¦ªà§\8dরাà¦\95দরà§\8dশনà¦\9fি à¦²à§\81à¦\95ানà§\8b à¦\86à¦\9bà§\87।</em>\n\n<strong>যদি à¦\8fà¦\9fি à¦¸à¦®à§\8dপাদনার à¦\8fà¦\95à¦\9fি à¦¬à§\88ধ à¦ªà§\8dরà¦\9aà§\87ষà§\8dà¦\9fা à¦¹à¦¯à¦¼, à¦¤à¦¬à§\87 à¦\85নà§\81à¦\97à§\8dরহ à¦\95রà§\87 [[Special:UserLogin|প্রবেশ করুন]] ও আবার চেষ্টা করুন।</strong>",
        "expand_templates_input_missing": "আপনাকে অন্তত কিছু ইনপুট লেখা প্রদান করতে হবে।",
        "pagelanguage": "পাতার ভাষা পরিবর্তন করুন",
        "pagelang-name": "পাতা",
        "passwordpolicies-policy-passwordcannotmatchblacklist": "পাসওয়ার্ড বিশেষত কালো তালিকাভুক্ত পাসওয়ার্ডের সাথে মিলতে পারবে না",
        "passwordpolicies-policy-maximalpasswordlength": "পাসওয়ার্ড $1 {{PLURAL:$1|অক্ষরের}} চেয়ে কম দীর্ঘ হতে হবে",
        "passwordpolicies-policy-passwordnotinlargeblacklist": "পাসওয়ার্ড ১,০০,০০০ সর্বাধিক ব্যবহৃত পাসওয়ার্ডের তালিকায় থাকতে পারবে না।",
-       "unprotected-js": "নিরাপত্তার কারণে জাভাস্ক্রিপ্ট অনিরাপদ পৃষ্ঠা থেকে লোড করা যাবে না। শুধুমাত্র মিডিয়াউইকি: নামস্থান বা ব্যবহারকারী উপপাতায় জাভাস্ক্রিপ্ট তৈরি করুন"
+       "unprotected-js": "নিরাপত্তার কারণে জাভাস্ক্রিপ্ট অনিরাপদ পৃষ্ঠা থেকে লোড করা যাবে না। শুধুমাত্র মিডিয়াউইকি: নামস্থান বা ব্যবহারকারী উপপাতায় জাভাস্ক্রিপ্ট তৈরি করুন",
+       "userlogout-continue": "আপনি যদি প্রস্থান করতে চান দয়া করে [$1 প্রস্থান পাতায় যান]।"
 }
index a031eef..797f84f 100644 (file)
        "rcfilters-filter-pageedits-label": "آلشدکاریٱل بٱلگاْ",
        "rcfilters-filter-newpages-label": "راسد کردن بٱلگاْ",
        "rcfilters-filter-categorization-label": "آلشدکاری دٱسداْیٱل",
-       "rcfilters-filtergroup-lastRevision": "آخری ڤانیٱریٱل",
+       "rcfilters-filtergroup-lastrevision": "آخری ڤانیٱریٱل",
        "rcfilters-filter-lastrevision-label": "آخری ڤانیٱری",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:نیڌ</strong> $1",
        "rcfilters-target-page-placeholder": "نوم یٱ بٱلگاْ(یا دٱسداْ) ناْ بزنین",
index 578152c..c4aa322 100644 (file)
        "index-category": "Pajennoù menegeret",
        "noindex-category": "Pajennoù n'int ket menegeret",
        "broken-file-category": "Pajennoù enno liamm torr war-zu restroù",
+       "categoryviewer-pagedlinks": "($1) ($2)",
+       "category-header-numerals": "$1–$2",
        "about": "Diwar-benn",
        "article": "Pennad",
        "newwindow": "(digeriñ en ur prenestr nevez)",
        "returnto": "Distreiñ d'ar bajenn $1.",
        "tagline": "Eus {{SITENAME}}",
        "help": "Skoazell",
+       "help-mediawiki": "Skoazell evit MediaWiki",
        "search": "Klask",
        "search-ignored-headings": " #<!-- lezel al linenn-mañ tre evel m'emañ --> <pre>\n# Titloù a vo lezet a-gostez gant ar c'hlask.\n# Ar c'hemmoù graet amañ a vo lakaet e pleustr kerkent ha menegeret ar bajenn gant an titl.\n# Gallout a rit forsiñ un advenegeriñ ma rit ur c'hemm goullo en ur bajenn.\n# Setu penaos emañ an ereadur :\n#   * Kement linenn zo, adalek an arouezenn \"#\" betek dibenn al linenn a zo un evezhiadenn.\n#   * Kement linenn ha n'eo ket goullo a verk an titl rik a zo da vezañ lezet a-gostez, pennlizherennoù hag all.\nDaveennoù\nLiammoù diavaez\nGwelet ivez\n #</pre> <!-- lezel al linenn-mañ tre evel m'emañ -->",
        "searchbutton": "Klask",
        "versionrequired": "Rekis eo Stumm $1 MediaWiki",
        "versionrequiredtext": "Rekis eo stumm $1 MediaWiki evit implijout ar bajenn-mañ. Sellit ouzh [[Special:Version]]",
        "ok": "Mat eo",
+       "pagetitle": "$1 - {{SITENAME}}",
+       "pagetitle-view-mainpage": "{{SITENAME}}",
+       "backlinksubtitle": "← $1",
        "retrievedfrom": "Adtapet diwar « $1 »",
        "youhavenewmessages": "$1 zo ganeoc'h ($2).",
        "youhavenewmessagesfromusers": "{{PLURAL:$4|Bez' hoc'h eus}} $1 a-berzh {{PLURAL:$3|un implijer all|$3 implijer}} ($2).",
        "site-atom-feed": "Lanv Atom evit $1",
        "page-rss-feed": "Lanv RSS evit \"$1\"",
        "page-atom-feed": "Lanv Atom evit \"$1\"",
+       "feed-atom": "Atom",
+       "feed-rss": "RSS",
        "red-link-title": "$1 (n'eus ket eus ar bajenn-mañ)",
        "sort-descending": "Urzhiañ war-draoñ",
        "sort-ascending": "Urzhiañ war-laez",
        "nocookiesnew": "Krouet eo bet ar gont implijer met n'oc'h ket kevreet. {{SITENAME}} a implij toupinoù evit ar c'hevreañ met diweredekaet eo an toupinoù ganeoc'h. Trugarez da weredekaat anezho ha da gevreañ en-dro.",
        "nocookieslogin": "{{SITENAME}} a implij toupinoù evit kevreañ met diweredekaet eo an toupinoù ganeoc'h. Trugarez da weredekaat anezho ha da gevreañ en-dro.",
        "nocookiesfornew": "N'eo ket bet krouet ar gont implijer peogwir n'eus ket bet gallet gwiriañ an orin anezhi.\nGwiriit eo bet gweredekaet an toupinoù, adkargit ar bajenn ha klaskit en-dro.",
+       "nocookiesforlogin": "{{int:nocookieslogin}}",
        "createacct-loginerror": "Krouet eo bet ar gont ervat met n'hallit ket kevreañ en un doare emgefre. [[Special:UserLogin|Kevreit gant an dorn]].",
        "noname": "N'hoc'h eus lakaet anv implijer ebet.",
        "loginsuccesstitle": "Kevreet oc'h.",
        "template-semiprotected": "(damwarezet)",
        "hiddencategories": "{{PLURAL:$1|1 rummad kuzhet|$1 rummad kuzhet}} m'emañ rollet ar bajenn-mañ :",
        "edittools": "<!-- Diskouezet e vo an destenn kinniget amañ dindan ar sternioù kemmañ ha kargañ. -->",
+       "edittools-upload": "-",
        "nocreatetext": "Strishaet eo bet an tu da grouiñ pajennoù nevez war {{SITENAME}}.\nGallout a rit mont war-gil ha lakaat kemmañ ur bajenn zo anezhi dija, pe [[Special:UserLogin|en em enrollañ ha krouiñ ur gont]].",
        "nocreate-loggedin": "N'oc'h ket aotreet da grouiñ pajennoù nevez.",
        "sectioneditnotsupported-title": "N'eo ket skoret ar c'hemmañ rannoù",
        "editpage-invalidcontentmodel-text": "N'eo ket skoret ar patrom danvez \"$1\".",
        "editpage-notsupportedcontentformat-title": "Furmad endalc'had ha n'eo ket kemeret e karg",
        "editpage-notsupportedcontentformat-text": "N'eo ket skoret ar patrom $1 gant ar patrom danvez $2.",
+       "slot-name-main": "Pennañ",
        "content-model-wikitext": "wikitestenn",
        "content-model-text": "testenn blaen",
        "content-model-javascript": "Javascript",
        "content-model-css": "CSS",
+       "content-model-json": "JSON",
        "content-json-empty-object": "Elfenn goullo",
        "content-json-empty-array": "Taolenn c'houllo",
        "deprecated-self-close-category": "Pajennoù a ra gant tikedennoù HTML emserriñ direizh",
        "page_first": "kentañ",
        "page_last": "diwezhañ",
        "histlegend": "Sellet ouzh an diforc'hioù : lakait un ask adal d'ar stummoù a fell deoc'h keñveriañ ha pouezit war kadarnaat pe war ar bouton en traoñ.<br />\nAlc'hwez : (red) = diforc'hioù gant ar stumm a-vremañ,\n(diwez) = diforc'hioù gant ar stumm kent, D = kemm dister",
-       "history-fieldset-title": "Klask adweladennoù",
+       "history-fieldset-title": "Silañ an adweladennoù",
        "history-show-deleted": "Stumm diverket hepken",
        "histfirst": "koshañ",
        "histlast": "nevezañ",
        "historysize": "({{PLURAL:$1|$1 okted|$1 okted}})",
-       "historyempty": "(goullo)",
+       "historyempty": "goullo",
        "history-feed-title": "Istor ar c'hemmoù",
        "history-feed-description": "Istor ar c'hemmoù degaset war ar bajenn-mañ eus ar wiki",
        "history-feed-item-nocomment": "$1 d'an $2",
        "mergehistory-comment": "Kendeuzet [[:$1]] gant [[:$2]] : $3",
        "mergehistory-same-destination": "N'hall ket ar pajennoù kein hag ar pajennoù tal bezañ an hevelep re",
        "mergehistory-reason": "Abeg :",
+       "mergehistory-revisionrow": "$1 ($2) $3 . . $4 $5 $6",
        "mergelog": "Marilh ar c'hendeuzadennoù",
        "revertmerge": "Nullañ ar c'hendeuziñ",
        "mergelogpagetext": "Setu aze roll kendeuzadennoù diwezhañ un eil pajenn istor gant eben.",
        "youremail": "Postel :",
        "username": "{{GENDER:$1|Anv implijer|Anv implijerez}}:",
        "prefs-memberingroups": "{{GENDER:$2|Ezel}} eus {{PLURAL:$1|ar strollad|ar strolladoù}}:",
+       "prefs-memberingroups-type": "$1",
        "group-membership-link-with-expiry": "$1 (betek $2)",
        "prefs-registration": "Deiziad enskrivañ :",
+       "prefs-registration-date-time": "$1",
        "yourrealname": "Anv gwir*",
        "yourlanguage": "Yezh an etrefas&nbsp;",
        "yourvariant": "Adstumm yezh :",
        "prefs-advancedwatchlist": "Dibarzhioù araokaet",
        "prefs-displayrc": "Dibarzhioù diskwel",
        "prefs-displaywatchlist": "Dibarzhioù diskwel",
+       "prefs-changesrc": "Kemmoù war wel",
+       "prefs-changeswatchlist": "Kemmoù war wel",
+       "prefs-pageswatchlist": "Pajennoù evezhiet",
        "prefs-tokenwatchlist": "Jedouer",
        "prefs-diffs": "Diforc'hioù",
        "prefs-help-prefershttps": "Efediñ a ray an dibarzh-mañ kentañ gwech ma kevreoc'h.",
        "saveusergroups": "Enrollañ strolladoù an {{GENDER:$1|implijer|implijerez}}",
        "userrights-groupsmember": "Ezel eus :",
        "userrights-groupsmember-auto": "Ezel emplegat eus :",
+       "userrights-groupsmember-type": "$1",
        "userrights-groups-help": "Cheñch strolladoù an implijer a c'hallit ober.\n* Ul log asket a verk emañ an implijer er strollad.\n* Ul log diask a verk n'emañ ket an implijer er strollad.\n* Ur * a verk n'hallit ket dilemel ar strollad ur wech bet ouzhpennet ganeoc'h, pe ar c'hontrol.\n* Ur # a verk e c'hallit astenn termen an emezelañ er strollad hepken ; n'hallit ket berraat anezhañ.",
        "userrights-reason": "Abeg :",
        "userrights-no-interwiki": "N'oc'h ket aotreet da gemmañ ar gwirioù implijer war wikioù all.",
        "userrights-nodatabase": "N'eus ket eus an diaz titouroù $1 pe n'eo ket lec'hel.",
        "userrights-changeable-col": "Ar strolladoù a c'hallit cheñch",
        "userrights-unchangeable-col": "Ar strolladoù n'hallit ket cheñch",
+       "userrights-irreversible-marker": "$1*",
+       "userrights-no-shorten-expiry-marker": "$1#",
        "userrights-expiry-current": "A ya d'e dermen d'an $1",
        "userrights-expiry-none": "Didermen",
        "userrights-expiry": "Termen :",
        "group-autoconfirmed": "Implijerien bet kadarnaet ent emgefre",
        "group-bot": "Robotoù",
        "group-sysop": "Merourien",
+       "group-interface-admin": "Merourien an etrefas",
        "group-bureaucrat": "Burevidi",
        "group-suppress": "Diverkerien",
        "group-all": "(pep tra)",
        "group-autoconfirmed-member": "{{GENDER:$1|Implijer bet kadarnaet ent emgefre}}",
        "group-bot-member": "{{GENDER:$1|robot}}",
        "group-sysop-member": "{{GENDER:$1|merour}}",
+       "group-interface-admin-member": "{{GENDER:$1|merour an etrefas|merourez an etrefas}}",
        "group-bureaucrat-member": "{{GENDER:$1|bureviad}}",
        "group-suppress-member": "{{GENDER:$1|diverker|diverkerez}}",
        "grouppage-user": "{{ns:project}}:Implijerien",
        "grouppage-autoconfirmed": "{{ns:project}}: Implijerien bet kadarnaet ent emgefre",
        "grouppage-bot": "{{ns:project}}:Botoù",
        "grouppage-sysop": "{{ns:project}}:Merourien",
+       "grouppage-interface-admin": "{{ns:project}}:Merourien etrefas",
        "grouppage-bureaucrat": "{{ns:project}}: Burevidi",
        "grouppage-suppress": "{{ns:project}}: Diverkerien",
        "right-read": "Lenn ar pajennoù",
        "right-reupload-own": "Frikañ ur restr bet pellgarget gant an-unan",
        "right-reupload-shared": "Gwaskañ restroù ent lec'hel war an diellaoueg vedia rannet",
        "right-upload_by_url": "Enporzhiañ ur restr adal ur chomlec'h URL",
-       "right-purge": "Spujañ krubuilh ar pajennoù hep kadarnaat",
+       "right-purge": "Spurjañ krubuilh ur bajenn eus al lec'hienn",
        "right-autoconfirmed": "Na vezañ trubuilhet gant ar bevennoù kas liammet ouzh ar chomlec'hioù IP",
        "right-bot": "Plediñ ganti evel gant un argerzh emgefre",
        "right-nominornewtalk": "Arabat diskouez ar c'hemenn \"Kemennoù nevez zo ganeoc'h\" pa vez lakaet kemmoù dister e pajenn gaozeal un implijer",
        "action-deletechangetags": "Diverkañ tikedennoù a-ziwar an diaz-roadennoù",
        "action-purge": "spurjañ ar bajenn-mañ",
        "nchanges": "$1 {{PLURAL:$1|kemm|kemm}}",
+       "ntimes": "$1×",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|abaoe ho kweladenn diwezhañ}}",
        "enhancedrc-history": "istor",
        "recentchanges": "Kemmoù diwezhañ",
        "recentchanges-label-plusminus": "Kemmet eo ment ar bajenn eus an niver-mañ a oktedoù",
        "recentchanges-legend-heading": "<strong>Alc'hwez :</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (gwelet ivez [[Special:NewPages|roll ar pajennoù nevez]])",
+       "recentchanges-legend-plusminus": "(<em>±123</em>)",
        "recentchanges-submit": "Diskouez",
        "rcfilters-tag-remove": "Dilemel '$1'",
        "rcfilters-other-review-tools": "Ostilhoù reizhañ all",
        "rcfilters-filter-editsbyself-description": "Ar c'hemmoù graet ganeoc'h.",
        "rcfilters-filter-editsbyother-label": "Kemmet gant tud all",
        "rcfilters-filter-editsbyother-description": "An holl gemmoù nemet ar re graet ganeoc'h.",
-       "rcfilters-filtergroup-userExpLevel": "Live skiant-prenañ (evit an implijer enrollet hepken)",
+       "rcfilters-filtergroup-user-experience-level": "Live skiant-prenañ (evit an implijer enrollet hepken)",
        "rcfilters-filter-user-experience-level-registered-label": "Marilhet",
        "rcfilters-filter-user-experience-level-registered-description": "Aozerien gevreet.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Divarilh",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Tabut zo etre ar sil \"Kemmoù dister\" hag unan pe meur a sil a Seurt kemmoù peogwir n'haller merkañ kemmoù zo evel \"dister\". Kavet e vo ar siloù o tabutal e takad ar siloù gweredekaet, a-us.",
        "rcfilters-hideminor-conflicts-typeofchange": "Seurtoù kemmoù zo n'hallont ket bezañ merket evel \"dister,\", rak se ez eus tabut etre ar sil-mañ ha siloù ar Seurtoù kemmoù da heul : $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Tabut zo etre ar sil-mañ Seurt kemmoù gant sil ar \"c'hemmoù dister\". Kemmoù zo n'hallont ket bezañ merket evel \"dister\".",
-       "rcfilters-filtergroup-lastRevision": "Stumm a-vremañ pe stumm red",
+       "rcfilters-filtergroup-lastrevision": "Stumm a-vremañ pe stumm red",
        "rcfilters-filter-lastrevision-label": "Stumm a-vremañ pe stumm red",
        "rcfilters-filter-lastrevision-description": "Kemm diwezhañ graet ouzh ur bajenn.",
        "rcfilters-filter-previousrevision-label": "Stummoù koshoc'h",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:not</strong> $1",
        "rcfilters-exclude-button-off": "Skarzhañ ar re dibabet",
        "rcfilters-exclude-button-on": "Re dibabet skarzhet",
+       "rcfilters-view-tags": "Kemmoù merket",
        "rcfilters-filter-showlinkedfrom-label": "Diskouez ar c'hemmoù war ar bajennoù liammet",
        "rcfilters-filter-showlinkedto-label": "Diskouez ar c'hemmoù war ar bajennoù liammet",
        "rcfilters-target-page-placeholder": "Skrivañ anv ar bajenn (pe rummad)",
        "minoreditletter": "D",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|implijer o heuliañ|implijer}} o heuliañ]",
+       "unpatrolledletter": "!",
+       "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|okted|okted}} goude kemmañ",
        "newsectionsummary": "/* $1 */ rann nevez",
        "rc-enhanced-expand": "Diskouez ar munudoù",
        "img-auth-nopathinfo": "Mankout a ra ar PATH_INFO.\nN'eo ket kefluniet ho servijer evit reiñ an titour-mañ.\nMarteze eo diazezet war CGI ha n'hall ket skorañ img_auth.\nGwelet https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization",
        "img-auth-notindir": "N'emañ ket an hent merket er c'havlec'h enporzhiañ kefluniet.",
        "img-auth-badtitle": "Dibosupl krouiñ un titl reizh adalek \"$1\".",
-       "img-auth-nologinnWL": "N'oc'h ket kevreet ha n'emañ ket \"$1\" war ar roll gwenn",
        "img-auth-nofile": "n'eus ket eus ar restr \"$1\".",
        "img-auth-isdir": "Klakset hoc'h eus monet d'ar c'havlec'h \"$1\".\nN'haller monet nemet d'ar restroù.",
        "img-auth-streaming": "O lenn en ur dremen \"$1\"",
        "uploadnewversion-linktext": "Kargañ ur stumm nevez eus ar restr-mañ",
        "shared-repo-from": "eus $1",
        "shared-repo": "ur sanailh rannet",
+       "shared-repo-name-wikimediacommons": "Wikimedia Commons",
        "upload-disallowed-here": "Ne c'hallit ket erlec'hiañ ar restr-mañ",
        "filerevert": "Disteuler $1",
        "filerevert-legend": "Disteuler ar restr",
        "apisandbox-request-selectformat-label": "Diskouez roadennoù ar reked evel :",
        "apisandbox-request-format-url-label": "Neudennad reked an URL",
        "apisandbox-request-url-label": "Goulenn URL :",
+       "apisandbox-request-format-json-label": "JSON",
        "apisandbox-request-json-label": "Goulenn JSON :",
        "apisandbox-request-time": "Pad ar goulenn : {{PLURAL:$1|$1 ms}}",
        "apisandbox-results-fixtoken": "Reizhañ ar jedouer ha kas en-dro",
        "deleteprotected": "Ne c'hallit ket dilemel ar bajenn-mañ rak gwarezet eo bet.",
        "deleting-backlinks-warning": "<strong>Taolit pled :</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Pajennoù all]] zo enno liammoù war-zu ar bajenn emaoc'h o vont da zilemel pe a zo treuzkludet ar bajenn enno.",
        "rollback": "disteuler ar c'hemmoù",
+       "rollback-confirmation-no": "Nullañ",
        "rollbacklink": "disteuler",
        "rollbacklinkcount": "disteurel $1 {{PLURAL:$1|kemm}}",
        "rollbacklinkcount-morethan": "disteurel ouzhpenn $1 {{PLURAL:$1|kemm}}",
        "revertpage": "Kemmoù distaolet gant [[Special:Contributions/$2|$2]] ([[User talk:$2|Kaozeal]]); adlakaet d'ar stumm diwezhañ a-gent gant [[User:$1|$1]]",
        "revertpage-nouser": "Disteuler kemmoù un implijer kuzhet ha distreiñ d'ar stumm diwezhañ gant an {{GENDER:$1|[[implijer :$1|$1]]}}",
        "rollback-success": "Nullet ar c'hemmoù gant {{GENDER:$3|$1}};\nadlakaet diouzh ar stumm diwezhañ gant {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Nullet ar c'hemmoù gant $1;\nadlakaet diouzh ar stumm diwezhañ gant $2. [$3 Diskouez ar c'hemmoù]",
        "sessionfailure-title": "Fazi dalc'h",
        "sessionfailure": "Evit doare ez eus ur gudenn gant ho talc'h;\nNullet eo bet an ober-mañ a-benn en em wareziñ diouzh an tagadennoù preizhañ.\nKlikit war \"kent\" hag adkargit ar bajenn oc'h deuet drezi; goude klaskit en-dro.",
        "changecontentmodel": "Cheñch patrom danvez ur bajenn",
        "protect-fallback": "Degemer hepken an implijerien gant an aotre \"$1\"",
        "protect-level-autoconfirmed": "Degemer hepken an implijerien emgadarnaet",
        "protect-level-sysop": "Aotren ar verourien hepken",
+       "protect-summary-desc": "[$1=$2] ($3)",
        "protect-summary-cascade": "Gwareziñ dre skalierad",
        "protect-expiring": "a zeu d'e dermen d'an $1",
        "protect-expiring-local": "a ya d'e dermen d'an $1",
        "undelete-error-long": "Fazioù zo bet kavet e-ser diziverkañ ar restr :\n\n$1",
        "undelete-show-file-confirm": "Ha sur oc'h e fell deoc'h sellet ouzh ur stumm diverket eus ar restr \"<nowiki>$1</nowiki>\" a sav d'an $2 da $3?",
        "undelete-show-file-submit": "Ya",
+       "undelete-revision-row2": "$1 ($2) $3 . . $4 $5 $6 $7 $8",
        "namespace": "Esaouenn anv :",
        "invert": "Eilpennañ an dibab",
        "tooltip-invert": "Askañ ar voest-mañ da guzhat ar c'hemmoù er pajennoù stag ouzh an esaouenn anv diuzet (hag an esaouenn anv stag, m'emañ asket)",
        "uctop": "red",
        "month": "Abaoe miz (hag a-raok) :",
        "year": "Abaoe bloaz (hag a-raok) :",
+       "date": "Abaoe an (hag a-raok) :",
        "sp-contributions-newbies": "Diskouez hepken degasadennoù ar c'hontoù nevez",
        "sp-contributions-newbies-sub": "Evit an implijerien nevez",
        "sp-contributions-newbies-title": "Degasadennoù implijer evit ar c'hontoù nevez",
        "ipb-change-block": "Adstankañ an implijer-mañ gant an hevelep arventennoù",
        "ipb-confirm": "Kadarnaat ar stankadenn",
        "ipb-pages-label": "Pajennoù",
+       "ipb-namespaces-label": "Esaouennoù anv",
        "badipaddress": "Kamm eo ar chomlec'h IP.",
        "blockipsuccesssub": "Stankadenn deuet da benn vat",
        "blockipsuccesstext": "Stanket eo bet [[Special:Contributions/$1|$1]].<br />\nSellit ouzh [[Special:BlockList|roll ar chomlec'hioù IP ha kontoù stanket]] evit gwiriañ ar stankadennoù.",
        "ipb-blocklist-contribs": "Degasadennoù evit $1",
        "ipb-blocklist-duration-left": "$1 a chom",
        "block-expiry": "Pad ar stankadenn",
+       "block-prevent-edit": "O kemmañ",
+       "block-reason": "Abeg :",
+       "block-target": "Anv implijer pe chomlec'h IP :",
        "unblockip": "Distankañ ur chomlec'h IP",
        "unblockiptext": "Grit gant ar furmskrid a-is evit adsevel ar moned skrivañ ouzh ur chomlec'h IP bet stanket a-gent.",
        "ipusubmit": "Paouez gant ar stankadenn-mañ",
        "blocklist-nousertalk": "n'hall ket kemmañ e bajenn gaozeal dezhañ e-unan",
        "blocklist-editing": "O kemmañ",
        "blocklist-editing-sitewide": "o kemmañ (al lec'hienn a-bezh)",
+       "blocklist-editing-page": "pajennoù",
+       "blocklist-editing-ns": "esaouennoù anv",
        "ipblocklist-empty": "Goullo eo roll ar stankadennoù.",
        "ipblocklist-no-results": "An anv implijer pe ar chomlec'h IP goulennet n'eo ket stanket anezhañ.",
        "blocklink": "stankañ",
        "ip_range_toolarge": "N'eo ket aotreet stankañ pajennoù brasoc'h evit /$1.",
        "proxyblocker": "Stanker proksi",
        "proxyblockreason": "Stanket eo bet hoc'h IP rak ur proksi digor eo. Trugarez da gelaouiñ ho pourvezer moned ouzh ar Genrouedad pe ho skoazell deknikel eus ar gudenn surentez-mañ.",
+       "sorbs": "DNSBL",
        "sorbsreason": "Rollet eo ho chomlec'h IP evel ur proksi digor en DNSBL implijet gant {{SITENAME}}.",
        "sorbs_create_account_reason": "Rollet eo ho chomlec'h IP evel ur proksi digor war an DNSBL implijet gant {{SITENAME}}. N'hallit ket krouiñ ur gont",
        "softblockrangesreason": "N'eo ket aotreet kemmañ netra ebet gan tho chomlec'h IP ($1). Kevreit mar plij.",
        "allmessagesdefault": "Kemennadenn dre ziouer",
        "allmessagescurrent": "Kemennadenn zo bremañ",
        "allmessagestext": "Setu roll ar c'hemennadennoù reizhiad a c'haller kaout en esaouennoù anv MediaWiki.\nKit da welet [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Lec'heladur MediaWiki] ha [https://translatewiki.net translatewiki.net] mar fell deoc'h kemer perzh e lec'heladur boutin MediaWiki.",
-       "allmessagesnotsupportedDB": "N'haller ket kaout {{ns:special}}:AllMessages rak diweredekaet eo bet wgUseDatabaseMessages.",
+       "allmessages-not-supported-database": "N'haller ket kaout {{ns:special}}:AllMessages rak diweredekaet eo bet wgUseDatabaseMessages.",
        "allmessages-filter-legend": "Sil",
        "allmessages-filter": "Silañ dre stad ar c'hemmoù",
        "allmessages-filter-unmodified": "Digemm",
        "tooltip-undo": "\"Dizober\" a zistaol ar c'hemm-mañ hag a zigor ar prenestr skridaozañ er mod rakwelet.\nTalvezout a ra da ouzhpennañ un displegadenn er c'hombod diverrañ.",
        "tooltip-preferences-save": "Enrollañ ar penndibaboù",
        "tooltip-summary": "Skrivit un diveradenn verr",
+       "interlanguage-link-title": "$1 – $2",
+       "interlanguage-link-title-nonlang": "$1 – $2",
        "common.css": "/** Talvezout a raio ar CSS lakaet amañ evit an holl wiskadurioù */",
        "print.css": "/* Talvezout a raio ar CSS lakaet amañ evit ar moullañ */",
        "noscript.css": "/* Talvezout a raio ar CSS lakaet amañ evit an implijerien o deus diweredekaet JavaScript */",
        "pageinfo-few-watchers": "Nebeutoc'h eget $1 {{PLURAL:$1|lenner}}",
        "pageinfo-few-visiting-watchers": "Gallout a ra bezañ, pe get, un implijer o teurel ur sell ouzh ar c'hemmoù diwezhañ",
        "pageinfo-redirects-name": "Niver a adkasoù war-zu ar bajenn-mañ",
+       "pageinfo-redirects-value": "$1",
        "pageinfo-subpages-name": "Ispajennoù eus ar bajenn-mañ",
        "pageinfo-subpages-value": "$1 ($2 {{PLURAL:$2|kasadur|kasadurioù}}; $3 {{PLURAL:$3|nann kasaduri|nann kasadurioù}})",
        "pageinfo-firstuser": "Krouer ar bajenn",
        "confirm-mcrundo-title": "Dizober ur c'hemm",
        "mcrundofailed": "Dizober c'hwitet",
        "mcrundo-missingparam": "Arventennoù rekis d'ar reked a vank.",
+       "ellipsis": "...",
+       "percent": "$1%",
+       "parentheses": "($1)",
+       "parentheses-start": "(",
+       "parentheses-end": ")",
+       "brackets": "[$1]",
        "quotation-marks": "« $1 »",
        "imgmultipageprev": "← pajenn gent",
        "imgmultipagenext": "pajenn war-lerc'h →",
        "imgmultigo": "Mont !",
        "imgmultigoto": "Mont d'ar bajenn $1",
+       "img-lang-opt": "$2 ($1)",
        "img-lang-default": "(yezh dre ziouer)",
        "img-lang-info": "Diskouez ar skeudenn-mañ e $1. $2",
        "img-lang-go": "Mont",
        "log-action-filter-suppress-reblock": "Diverkañ implijerien dre stankadennoù lies",
        "log-action-filter-upload-upload": "Enporzhiadenn nevez",
        "log-action-filter-upload-overwrite": "Adenporzhiañ",
+       "log-action-filter-upload-revert": "Disteuler",
        "authmanager-authn-not-in-progress": "Ne'z a ket war-raok an dilesadur pe kollet ez eus bet roadennoù dalc'h marteze. Adkrogit adalek ar penn-kentañ.",
        "authmanager-authn-no-primary": "N'eus ket bet gallet gwiriañ an titouroù kred lakaet.",
        "authmanager-authn-no-local-user": "An titouroù anaout pourchaset n'int ket liammet gant implijer ebet er wiki-mañ.",
index f3591a5..6d19937 100644 (file)
        "rcfilters-filter-editsbyself-description": "Vaši vlastiti doprinosi.",
        "rcfilters-filter-editsbyother-label": "Tuđe izmjene",
        "rcfilters-filter-editsbyother-description": "Sve izmjene osim Vaših.",
-       "rcfilters-filtergroup-userExpLevel": "Korisnička registracija i iskustvo",
+       "rcfilters-filtergroup-user-experience-level": "Korisnička registracija i iskustvo",
        "rcfilters-filter-user-experience-level-registered-label": "Registrirani",
        "rcfilters-filter-user-experience-level-registered-description": "Prijavljeni urednici.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Anonimni",
        "rcfilters-filter-logactions-description": "Administrativne radnje, pravljenje računa, brisanje stranica, postavljanje datoteka…",
        "rcfilters-hideminor-conflicts-typeofchange": "Određene vrste izmjena ne mogu se označiti \"manjim\", tako da je ovaj filter u sukobu sa sljedećim filterima za vrstu izmjene: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Ovaj filter za vrstu izmjene u sukobu je s filterom za \"manje izmjene\". Izvjesne vrste izmjena ne mogu se označiti kao \"manje\".",
-       "rcfilters-filtergroup-lastRevision": "Posljednje izmjene",
+       "rcfilters-filtergroup-lastrevision": "Posljednje izmjene",
        "rcfilters-filter-lastrevision-label": "Posljednja izmjena",
        "rcfilters-filter-lastrevision-description": "Samo najnovija izmjena na stranici.",
        "rcfilters-filter-previousrevision-label": "Nije posljednja izmjena",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|korisnik|korisnika}} koji pregledaju]",
        "rc-change-size-new": "$1 {{PLURAL:$1|bajt|bajta|bajtova}} poslije izmjene",
        "newsectionsummary": "/* $1 */ novi odlomak",
        "rc-enhanced-expand": "Prikaži detalje",
        "img-auth-nopathinfo": "Nedostaje PATH_INFO.\nVaš server nije postavljen da daje ovu informaciju.\nMožda je zasnovan na CGI koji ne podržava img_auth.\nPogledajte https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Zahtjevana putanja nije u direktoriju podešenom za postavljanje.",
        "img-auth-badtitle": "Ne mogu napraviti valjani naslov iz \"$1\".",
-       "img-auth-nologinnWL": "Niste prijavljeni i \"$1\" nije na spisku dozvoljenih.",
        "img-auth-nofile": "Datoteka \"$1\" ne postoji.",
        "img-auth-isdir": "Pokušavate pristupiti direktoriju \"$1\".\nDozvoljen je samo pristup datotekama.",
        "img-auth-streaming": "Tok \"$1\".",
        "revertpage": "Vraćene izmjene {{GENDER:$2|korisnika|korisnice}} [[Special:Contributions/$2|$2]] ([[User talk:$2|razgovor]]) na posljednju izmjenu {{GENDER:$1|korisnika|korisnice}} [[User:$1|$1]]",
        "revertpage-nouser": "Vraćene izmjene skrivenog korisnika na posljednju reviziju, koju je {{GENDER:$1|napravio|napravila}} [[User:$1|$1]]",
        "rollback-success": "Vraćene izmjene {{GENDER:$3|korisnika|korisnice}} $1 na posljednju verziju {{GENDER:$4|korisnika|korisnice}} $2.",
-       "rollback-success-notify": "Vraćenje izmjene korisnika $1;\nvraćeno na posljednju izmjenu korisnika $2. [$3 Prikaži izmjene]",
        "sessionfailure-title": "Greška u sesiji",
        "sessionfailure": "Izgleda da postoji problem sa vašom sesijom; ova akcija je otkazana kao prevencija protiv napadanja sesija. Kliknite \"back\" (''nazad'') i osvježite stranicu sa koje ste došli, i opet pokušajte.",
        "changecontentmodel": "Promijeni model sadržaja stranice",
        "allmessagesdefault": "Predodređeni tekst",
        "allmessagescurrent": "Trenutni tekst",
        "allmessagestext": "Ovo je spisak sistemskih poruka u dostupnih u imenskom prostoru MediaWiki.\nPosjetite [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation lokalizaciju MediaWikija] i [https://translatewiki.net translatewiki.net] ako želite doprinijeti općoj lokalizaciji MediaWikija.",
-       "allmessagesnotsupportedDB": "Ova stranica ne može biti korištena jer je <i>wgUseDatabaseMessages</i> isključen.",
+       "allmessages-not-supported-database": "Ova stranica ne može biti korištena jer je <i>wgUseDatabaseMessages</i> isključen.",
        "allmessages-filter-legend": "Filter",
        "allmessages-filter": "Filter po stanju podešavanja:",
        "allmessages-filter-unmodified": "Neizmijenjeno",
index 86bce96..fa47f8c 100644 (file)
        "tog-norollbackdiff": "No mostris les diferències després de realitzar una reversió",
        "tog-useeditwarning": "Avisa'm quan surti d'una pàgina d'edició amb canvis sense desar",
        "tog-prefershttps": "Utilitza sempre una connexió segura en iniciar una sessió",
+       "tog-showrollbackconfirmation": "Mostra una petició de confirmació en clicar un enllaç de reversió",
        "underline-always": "Sempre",
        "underline-never": "Mai",
        "underline-default": "Per defecte del navegador",
        "confirmable-no": "No",
        "thisisdeleted": "Voleu mostrar o restaurar $1?",
        "viewdeleted": "Voleu mostrar $1?",
-       "restorelink": "{{PLURAL:$1|una versió esborrada|$1 versions esborrades}}",
+       "restorelink": "{{PLURAL:$1|una versió suprimida|$1 versions suprimides}}",
        "feedlinks": "Sindicació:",
        "feed-invalid": "La subscripció no és vàlida pel tipus de sindicament.",
        "feed-unavailable": "Els canals de sindicació no estan disponibles",
        "page_first": "primera",
        "page_last": "última",
        "histlegend": "Simbologia: (act) = diferència amb la versió actual,\n(prev) = diferència amb la versió anterior, m = modificació menor",
-       "history-fieldset-title": "Cerca revisions",
-       "history-show-deleted": "Només revisions esborrades",
+       "history-fieldset-title": "Filtra les revisions",
+       "history-show-deleted": "Només revisions suprimides",
        "histfirst": "les més antigues",
        "histlast": "les més noves",
        "historysize": "({{PLURAL:$1|1 octet|$1 octets}})",
-       "historyempty": "(buit)",
+       "historyempty": "buit",
        "history-feed-title": "Historial de revisió",
        "history-feed-description": "Historial de revisió per a aquesta pàgina del wiki",
        "history-feed-item-nocomment": "$1 a $2",
        "right-deleterevision": "Esborrar i restaurar versions específiques de pàgines",
        "right-deletedhistory": "Veure els historials esborrats sense consultar-ne el text",
        "right-deletedtext": "Veure el text esborrat i els canvis entre revisions esborrades",
-       "right-browsearchive": "Cercar pàgines esborrades",
-       "right-undelete": "Restaurar pàgines esborrades",
+       "right-browsearchive": "Cercar pàgines suprimides",
+       "right-undelete": "Restaurar pàgines suprimides",
        "right-suppressrevision": "Mostra, amaga i revela revisions específiques de pàgines d'un usuari",
        "right-viewsuppressed": "Mostra les revisions amagades de qualsevol usuari",
        "right-suppressionlog": "Veure registres privats",
        "action-deletelogentry": "suprimeix les entrades de registre",
        "action-deletedhistory": "mostra l'historial esborrat d'una pàgina",
        "action-deletedtext": "mostra el text de la revisió eliminada",
-       "action-browsearchive": "cercar pàgines esborrades",
+       "action-browsearchive": "cercar pàgines suprimides",
        "action-undelete": "restaura les pàgines",
        "action-suppressrevision": "revisa i restaura les revisions ocultes",
        "action-suppressionlog": "visualitzar aquest registre privat",
        "rcfilters-filter-editsbyself-description": "Les vostres pròpies contribucions.",
        "rcfilters-filter-editsbyother-label": "Canvis d'altres",
        "rcfilters-filter-editsbyother-description": "Tots els canvis excepte els vostres.",
-       "rcfilters-filtergroup-userExpLevel": "Registre d'usuaris i experiència",
+       "rcfilters-filtergroup-user-experience-level": "Registre d'usuaris i experiència",
        "rcfilters-filter-user-experience-level-registered-label": "Registrats",
        "rcfilters-filter-user-experience-level-registered-description": "Editors que han iniciat sessió",
        "rcfilters-filter-user-experience-level-unregistered-label": "No registrats",
        "rcfilters-filter-categorization-description": "Registres de pàgines afegides o suprimides de les categories.",
        "rcfilters-filter-logactions-label": "Accions registrades",
        "rcfilters-filter-logactions-description": "Accions administratives, creacions de comptes, eliminacions de pàgines, càrregues…",
-       "rcfilters-filtergroup-lastRevision": "Darreres revisions",
+       "rcfilters-filtergroup-lastrevision": "Darreres revisions",
        "rcfilters-filter-lastrevision-label": "Darrera revisió",
        "rcfilters-filter-lastrevision-description": "Només el canvi més recent a una pàgina.",
        "rcfilters-filter-previousrevision-label": "No la darrera revisió",
        "rcfilters-watchlist-markseen-button": "Marca tots els canvis com a vistos",
        "rcfilters-watchlist-edit-watchlist-button": "Editeu la vostra llista de pàgines seguides",
        "rcfilters-watchlist-showupdated": "Els canvis fets en pàgines que no heu visitat des que s'efectuaren apareixen en <strong>negreta</strong> amb un punt sòlid al costat.",
-       "rcfilters-preference-label": "Amaga la versió millorada de Canvis recents",
-       "rcfilters-watchlist-preference-label": "Amaga la versió millorada de la llista de seguiment",
+       "rcfilters-preference-label": "Utilitza la interfície sense JavaScript",
+       "rcfilters-watchlist-preference-label": "Utilitza la interfície sense JavaScript",
        "rcfilters-filter-showlinkedfrom-label": "Mostra els canvis en les pàgines enllaçades des de",
        "rcfilters-filter-showlinkedfrom-option-label": "<strong>Pàgines enllaçades des de</strong> la pàgina seleccionada",
        "rcfilters-filter-showlinkedto-label": "Mostra els canvis a les pàgines que enllacin a",
        "newpageletter": "N",
        "boteditletter": "b",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[{{PLURAL:$1|Un usuari vigila|$1 usuaris vigilen}} aquesta pàgina]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} després del canvi",
        "newsectionsummary": "/* $1 */ secció nova",
        "img-auth-nopathinfo": "Hi manca la informació del camí.\nCal configurar el servidor per passar les variables REQUEST_URI i/o PATH_INFO.\nConsulteu https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization",
        "img-auth-notindir": "No s'ha trobat la ruta sol·licitada al directori de càrrega configurat.",
        "img-auth-badtitle": "No s'ha pogut construir un títol vàlid a partir de \"$1\".",
-       "img-auth-nologinnWL": "No has iniciat sessió i \"$1\" no està a la llista blanca.",
        "img-auth-nofile": "No existeix el fitxer \"$1\".",
        "img-auth-isdir": "Esteu intentant accedir al directori «$1».\nNomés teniu permès accedir als fitxers.",
        "img-auth-streaming": "Lectura corrent de \"$1\".",
        "categories-submit": "Mostra",
        "categoriespagetext": "{{PLURAL:$1|La següent categoria conté|Les següents categories contenen}} pàgines, o fitxers multimèdia.\n[[Special:UnusedCategories|Les categories no usades]] no s'hi mostren.\nVegeu també [[Special:WantedCategories|les categories sol·licitades]].",
        "categoriesfrom": "Mostra les categories que comencen a:",
-       "deletedcontributions": "Contribucions esborrades",
-       "deletedcontributions-title": "Contribucions esborrades",
+       "deletedcontributions": "Contribucions suprimides",
+       "deletedcontributions-title": "Contribucions suprimides",
        "sp-deletedcontributions-contribs": "contribucions",
        "linksearch": "Cerca d'enllaços externs",
        "linksearch-pat": "Patró de cerca:",
        "delete-confirm": "Supressió de la pàgina «$1»",
        "delete-legend": "Suprimeix",
        "historywarning": "<strong>Avís:</strong> la pàgina que esteu a punt d'eliminar té un historial amb $1 {{PLURAL:$1|revisió|revisions}}:",
-       "historyaction-submit": "Mostra",
+       "historyaction-submit": "Mostra les revisions",
        "confirmdeletetext": "Esteu a punt d'esborrar de forma permanent una pàgina o imatge i tot el seu historial de la base de dades.\nConfirmeu que realment ho voleu fer, que enteneu les\nconseqüències, i que el que esteu fent està d'acord amb la [[{{MediaWiki:Policy-url}}|política]] del projecte.",
        "actioncomplete": "Acció realitzada",
        "actionfailed": "L'acció ha fallat",
        "deleteprotected": "No podeu eliminar la pàgina perquè ha estat protegida.",
        "deleting-backlinks-warning": "<strong>Atenció:</strong>\n[[Special:WhatLinksHere/{{FULLPAGENAME}}|Altres pàgines]] enllacen aquí o inclouen la pàgina que esteu a punt de suprimir.",
        "rollback": "Reverteix edicions",
+       "rollback-confirmation-confirm": "Confirmeu:",
+       "rollback-confirmation-no": "Cancel·la",
        "rollbacklink": "Reverteix",
        "rollbacklinkcount": "reverteix $1 {{PLURAL:$1|edició|edicions}}",
        "rollbacklinkcount-morethan": "reverteix més de $1 {{PLURAL:$1|edició|edicions}}",
        "revertpage": "Revertides les edicions de [[Special:Contributions/$2|$2]] ([[User talk:$2|discussió]]) a l'última versió de [[User:$1|$1]]",
        "revertpage-nouser": "Edicions revertides per un usuari ocult a l'última revisió de {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Revertides les edicions de {{GENDER:$3|$1}}; recuperant la darrera versió de {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Modificacions revertides per $1;\ns'ha revertit a la darrera versió de $2. [$3 Mostra els canvis]",
        "sessionfailure-title": "Error de sessió",
        "sessionfailure": "S'ha produït un error amb la vostra sessió. S'ha anul·lat aquesta acció en prevenció de pirateig de sessió. Premeu «Torna», recarregueu la pàgina des d'on veniu i torneu-ho a intentar.",
        "changecontentmodel": "Canvia el model de contingut d'una pàgina",
        "restriction-level-autoconfirmed": "semiprotegida",
        "restriction-level-all": "qualsevol nivell",
        "undelete": "Restaura una pàgina esborrada",
-       "undeletepage": "Mostra i restaura pàgines esborrades",
+       "undeletepage": "Mostra i restaura pàgines suprimides",
        "undeletepagetitle": "'''A continuació teniu revisions eliminades de [[:$1]]'''.",
        "viewdeletedpage": "Visualitza les pàgines eliminades",
        "undeletepagetext": "{{PLURAL:$1|S'ha eliminat la pàgina següent, però encara és a l'arxiu i pot ser restaurada|S'han eliminat les $1 pàgines següents, però encara són a l'arxiu i poden ser restaurades}}.\nL'arxiu pot ser netejat periòdicament.",
        "cannotundelete": "Hi ha hagut un error en algunes o totes les restauracions:\n$1",
        "undeletedpage": "'''S'ha restaurat «$1»'''\n\nConsulteu el [[Special:Log/delete|registre d'esborraments]] per a veure els esborraments i els restauraments més recents.",
        "undelete-header": "Vegeu [[Special:Log/delete|el registre d'eliminació]] per a veure les pàgines eliminades recentment.",
-       "undelete-search-title": "Cerca de pàgines esborrades",
-       "undelete-search-box": "Cerca pàgines esborrades",
+       "undelete-search-title": "Cerca de pàgines suprimides",
+       "undelete-search-box": "Cerca pàgines suprimides",
        "undelete-search-prefix": "Mostra pàgines que comencin:",
        "undelete-search-full": "Mostra títols de pàgines que continguin:",
        "undelete-search-submit": "Cerca",
        "anoncontribs": "Contribucions",
        "contribsub2": "Per a {{GENDER:$3|$1}} ($2)",
        "contributions-userdoesnotexist": "El compte d'usuari «$1» no està registrat.",
+       "negative-namespace-not-supported": "No es permeten espais de noms amb valors negatius.",
        "nocontribs": "No s’ha trobat cap canvi que encaixés amb aquests criteris.",
        "uctop": "darrera",
        "month": "Mes (i anteriors):",
        "year": "Any (i anteriors):",
+       "date": "Des de la data (i abans):",
        "sp-contributions-newbies": "Mostra les contribucions dels usuaris novells",
        "sp-contributions-newbies-sub": "Per a novells",
        "sp-contributions-newbies-title": "Contribucions dels comptes d'usuari més nous",
        "sp-contributions-blocklog": "Registre de blocatges",
        "sp-contributions-suppresslog": "contribucions suprimides de {{GENDER:$1|l'usuari|la usuària}}",
-       "sp-contributions-deleted": "Contribucions de {{GENDER:$1|l'usuari|la usuària}} esborrades",
+       "sp-contributions-deleted": "contribucions de {{GENDER:$1|l’usuari|la usuària}} suprimides",
        "sp-contributions-uploads": "càrregues",
        "sp-contributions-logs": "registres",
        "sp-contributions-talk": "discussió",
        "ipb-confirm": "Confirma el blocatge",
        "ipb-sitewide": "A tot el lloc web",
        "ipb-partial": "Parcial",
+       "ipb-partial-help": "Pàgines específiques o espais de noms.",
        "ipb-pages-label": "Pàgines",
        "ipb-namespaces-label": "Espais de noms",
        "badipaddress": "L'adreça IP no té el format correcte.",
        "blocklist-userblocks": "Amaga blocatges de compte",
        "blocklist-tempblocks": "Amaga els blocatges temporals",
        "blocklist-addressblocks": "Amaga blocatges d'una sola IP",
+       "blocklist-type": "Tipus:",
+       "blocklist-type-opt-all": "Tot",
+       "blocklist-type-opt-partial": "Parcial",
        "blocklist-rangeblocks": "Amaga els blocatges de rang",
        "blocklist-timestamp": "Marca horària",
        "blocklist-target": "Usuari blocat",
        "allmessagesdefault": "Text per defecte",
        "allmessagescurrent": "Text actual",
        "allmessagestext": "Tot seguit hi ha una llista dels missatges del sistema que es troben en l'espai de noms ''MediaWiki''. La traducció genèrica d'aquests missatges no s'hauria de fer localment sinó en la traducció del programari MediaWiki. Si voleu ajudar-hi, visiteu [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] i [https://translatewiki.net translatewiki.net].",
-       "allmessagesnotsupportedDB": "No es pot processar '''{{ns:special}}:Allmessages''' perquè la variable '''$wgUseDatabaseMessages''' està desactivada.",
+       "allmessages-not-supported-database": "No es pot processar '''{{ns:special}}:Allmessages''' perquè la variable '''$wgUseDatabaseMessages''' està desactivada.",
        "allmessages-filter-legend": "Filtre",
        "allmessages-filter": "Filtra per l'estat de personalització:",
        "allmessages-filter-unmodified": "Sense modificar",
        "passwordpolicies-policy-maximalpasswordlength": "Les contrasenyes han de tenir menys de $1 {{PLURAL:$1|caràcter|caràcters}} d'extensió",
        "passwordpolicies-policy-passwordcannotbepopular": "Les contrasenya no pot ser {{PLURAL:$1|la contrasenya popular|a la llista de $1 contrasenyes populars}}",
        "passwordpolicies-policy-passwordnotinlargeblacklist": "La contrasenya no pot ser a la llista de les 100.000 contrasenyes més utilitzades habitualment.",
+       "passwordpolicies-policyflag-forcechange": "cal canviar a l'inici de sessió",
+       "passwordpolicies-policyflag-suggestchangeonlogin": "suggereix canvi a l'inici de sessió",
        "easydeflate-invaliddeflate": "El contingut proporcionat no està deflactat adequadament",
        "unprotected-js": "Per motius de seguretat, el JavaScript no es pot carregar de les pàgines desprotegides. Creeu javascript en l'espai de noms MediaWiki o en una subpàgina d'usuari"
 }
index a3f2ce2..359d6ed 100644 (file)
        "allmessagesdefault": "默認其消息文字",
        "allmessagescurrent": "現時其文字",
        "allmessagestext": "茲是敆MediaWiki命名空間裏勢系統消息其蜀萆單單。\n如果汝卜想貢獻通用其MediaWiki基本地化服務,起動汝訪問[https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki本地化]共[https://translatewiki.net translatewiki.net]。",
-       "allmessagesnotsupportedDB": "茲蜀頁𣍐使其,因為'''$wgUseDatabaseMessages'''已經乞禁止去了。",
+       "allmessages-not-supported-database": "茲蜀頁𣍐使其,因為'''$wgUseDatabaseMessages'''已經乞禁止去了。",
        "thumbnail-more": "Huóng-duâi",
        "importlogpage": "Dô̤-ĭk nĭk-cê",
        "tooltip-pt-userpage": "{{GENDER:|汝其用戶}}頁",
index 36b7f36..e919277 100644 (file)
        "postedit-confirmation-created": "АгӀо кхоьллина.",
        "postedit-confirmation-restored": "АгӀо меттахӀотта йина.",
        "postedit-confirmation-saved": "Хьан нисдар дӀаяздина.",
+       "postedit-confirmation-published": "Хьан нисдар дӀаяздина.",
        "edit-already-exists": "Керла агӀо кхолла цатарло.\nИза хӀинцале йолуш ю.",
        "defaultmessagetext": "Ӏадйитаран кепаца йоза",
        "content-failed-to-parse": "Чулацам $2 богӀуш бац $1: $3.",
        "invalid-content-data": "Хилийта йиш йоцу хаамаш",
        "content-not-allowed-here": "Чулацам \"$1\" [[:$2]] агӀонгахь хилийта йиш яц",
+       "editwarning-warning": "Кхий агӀо схьаелича ахьа бина хийцамаш дӀабала мега.\nАхьа системехь регистраци йина елахь, хьа йиш ю «{{int:prefs-editing}}» декъехь хӀара дӀахьедар дӀадайа хьайн нисдаран гӀирс чохь.",
        "editpage-notsupportedcontentformat-title": "Чулацаман тайпа ловш яц",
        "content-model-wikitext": "вики-йоза",
        "content-model-text": "цхьалхе йоза",
        "rcfilters-filter-editsbyself-description": "Хьан нисдарш.",
        "rcfilters-filter-editsbyother-label": "Кхечу декъашхойн нисдарш",
        "rcfilters-filter-editsbyother-description": "Дерриге нисдарш, хьайнаш диссалц.",
-       "rcfilters-filtergroup-userExpLevel": "Декъашхочун регистраци а, цуна зеделларг а",
+       "rcfilters-filtergroup-user-experience-level": "Декъашхочун регистраци а, цуна зеделларг а",
        "rcfilters-filter-user-experience-level-registered-label": "ДӀабазбелларш",
        "rcfilters-filter-user-experience-level-registered-description": "Чубаьлла декъашхой.",
        "rcfilters-filter-user-experience-level-unregistered-label": "ДӀабазбаланзарш",
        "rcfilters-filter-categorization-description": "Категорийн, агӀонаш тӀетохар а, дӀаяхар а.",
        "rcfilters-filter-logactions-label": "Урхаллица динарш",
        "rcfilters-filter-logactions-description": "Куьйгалхоша динарг, дӀабазбалар, агӀонаш дӀаяхар, файлаш чуяхар...",
-       "rcfilters-filtergroup-lastRevision": "Карара верси",
+       "rcfilters-filtergroup-lastrevision": "Карара верси",
        "rcfilters-filter-lastrevision-label": "Карара верси",
        "rcfilters-filter-lastrevision-description": "АгӀона уггаре тӀеххьара хийцамаш.",
        "rcfilters-filter-previousrevision-label": "Хьалхара версеш",
        "minoreditletter": "ж",
        "newpageletter": "К",
        "boteditletter": "б",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|тӀехьожу декъашхо|тӀехьожу декъашхой}}]",
        "rc-change-size-new": "Хийцам бин чул тӀехьа болу барам: $1 {{PLURAL:$1|байт}}",
        "newsectionsummary": "/* $1 */ Керла тема",
        "rc-enhanced-expand": "Гайта мадарра",
        "recentchangeslinked-toolbox": "Дихкина нисдарш",
        "recentchangeslinked-title": "Дихкина нисдарш «$1»",
        "recentchangeslinked-summary": "ХӀара хийцам биначу агӀонийн могӀам бу, тӀетовжар долуш хьагучу агӀон (я хьагойтуш йолучу категорена).\nАгӀонаш юькъа йогӀуш йолу хьан [[Special:Watchlist|тергаме могӀам чохь]] '''къастийна ю'''.",
-       "recentchangeslinked-page": "АгӀон цӀе:",
+       "recentchangeslinked-page": "АгӀонан цӀе:",
        "recentchangeslinked-to": "Кхечу агӀор, гайта хийцамаш агӀонашца, хӀоттийначу агӀонтӀе хьажорг йолуш",
        "recentchanges-page-added-to-category": "[[:$1]] категори чу тоьхна",
        "recentchanges-page-added-to-category-bundled": "[[:$1]] а, [[Special:WhatLinksHere/$1|{{PLURAL:$2|цхьа агӀо|$2 агӀо}}]] а категорин тӀетоьхна",
        "movenotallowed": "Хьан бакъо яц керла агӀонаш кхолла.",
        "movenotallowedfile": "Хьан файлийн цӀерш хийца бакъо яц.",
        "cant-move-user-page": "Хьан бакъо яц декъашхойн коьрта агӀонийн цӀерш хийца.",
-       "cant-move-to-user-page": "Хьан бакъо яц агӀона цӀе декъашхочун агӀон тӀе хийца (бухара агӀон тӀе хийца мега).",
+       "cant-move-to-user-page": "Хьан бакъо яц агӀона цӀе декъашхочун агӀонан тӀе хийца (бухара агӀонан тӀе хийца мега).",
        "cant-move-category-page": "Хьан категорийн цӀерш хийца бакъо яц.",
        "cant-move-to-category-page": "Хьан категорийн цӀерш хийца бакъо яц.",
        "newtitle": "Керла цӀе",
        "move-watch": "ХӀара агӀо тергаме могӀанан юкъатоха",
-       "movepagebtn": "АгӀон цӀе хийца",
+       "movepagebtn": "АгӀонан цӀе хийца",
        "pagemovedsub": "АгӀонан цӀе хийцина",
-       "movepage-moved": "'''АгӀон цӀе «$1» хийцина → «$2»'''",
+       "cannotmove": "АгӀонан цӀе хуьйцила дац {{PLURAL:$1|1=лахахь гойту бахьна|лахахь гойту бахьнаш}}:",
+       "movepage-moved": "'''АгӀонан цӀе «$1» хийцина → «$2»'''",
        "movepage-moved-redirect": "Кхоьллина дӀасахьажорг.",
        "movepage-moved-noredirect": "ДӀасхьажорг кхоллар дохина.",
        "articleexists": "ХӀарасанна цӀе йолу агӀо йолуш ю йа ахьа гойтуш йолу цӀе магош яц.\nДехар до, харжа кхин цӀе.",
-       "movetalk": "Цуьнца йогӀуш йолу дийцаре агӀон цӀе хийцар",
+       "movetalk": "Цуьнца йогӀуш йолу дийцаре агӀонан цӀе хийцар",
        "move-subpages": "Бухара агӀонийн цӀерш хийца($1 кхаччалц)",
        "move-talk-subpages": "ЦӀе хийца бухара агӀонийн а, агӀонийн дийцаре а ($1  кхаччалц)",
        "movepage-page-exists": "Агӏо $1 йолуш ю цундела и ша юху дӏаязъян йиш яц.",
        "allmessagesdefault": "Ӏадйитаран кепаца йоза",
        "allmessagescurrent": "Карарчу хенан йоза",
        "allmessagestext": "ХӀара «MediaWiki» цӀерийн меттигера системан хаамийн могӀа бу.\nХьайна MediaWiki тая лууш делахь, дехар до, проект [https://translatewiki.net translatewiki.net] [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation юьйцучу хьажа].",
-       "allmessagesnotsupportedDB": "'''$wgUseDatabaseMessages''' дӀаяйина хилар бахьнехь хӀара агӀо дӀачӀаьгӀна ю.",
+       "allmessages-not-supported-database": "'''$wgUseDatabaseMessages''' дӀаяйина хилар бахьнехь хӀара агӀо дӀачӀаьгӀна ю.",
        "allmessages-filter-legend": "Луьттург",
        "allmessages-filter": "Луьттург оцу хьола хийцамца:",
        "allmessages-filter-unmodified": "Хийцан йоцурш",
        "tooltip-ca-protect": "Ларъе агӀо хийцамаш цабайта",
        "tooltip-ca-unprotect": "Хийца хӀокху агӀона ларъяр",
        "tooltip-ca-delete": "ДӀаяккха хӀара агӀо",
-       "tooltip-ca-move": "АгӀон цӀе хийца",
+       "tooltip-ca-move": "АгӀонан цӀе хийца",
        "tooltip-ca-watch": "ТӀетоха хӀара агӀо сан тергаме могӀанан юкъа",
        "tooltip-ca-unwatch": "ДӀаяккха хӀара агӀо хьай тергаме могӀанан юкъар",
        "tooltip-search": "Лаха иза дош",
-       "tooltip-search-go": "Билгала и санна цӀе йолучу агӀон чу дехьа гӀо",
+       "tooltip-search-go": "Билгала и санна цӀе йолучу агӀоне дехьа гӀо",
        "tooltip-search-fulltext": "Лаха агӀонаш ше чулацамехь хӀара йоза долуш",
        "tooltip-p-logo": "Коьрта агӀона дехьа гӀо",
        "tooltip-n-mainpage": "Коьрта агӀона дехьа гӀо",
        "table_pager_limit_label": "АгӀона чохь гойтуш ю оццул:",
        "table_pager_limit_submit": "Кхочушдé",
        "table_pager_empty": "Цакарийна",
-       "autosumm-blank": "Ð\90гÓ\8fон Ñ\87Ñ\83лаÑ\86ам Ð´Ó\8fабяккхина",
+       "autosumm-blank": "Ð\90гÓ\80онан Ð±ÐµÑ\80Ñ\80иге Ñ\87Ñ\83лаÑ\86ам Ð´Ó\80абяккхина",
        "autosumm-replace": "АгӀона чуьраниг хийцина → «$1»",
        "autoredircomment": "[[$1]] тӀе хьажийна",
        "autosumm-removed-redirect": "ДӀаяьккхина дӀасхьажог [[$1]]",
        "tag-mw-removed-redirect": "дӀаяьккхина дӀасхьажорг",
        "tag-mw-changed-redirect-target": "хийцаран бахьна ду дӀасахьажорг",
        "tag-mw-blank": "цӀанъяр",
+       "tag-mw-replace": "хийцар",
        "tag-mw-rollback": "Юхаяккха",
        "tag-mw-undo": "юхаяккхар",
        "tags-title": "Билгалонаш",
index 66d0f05..5309d1e 100644 (file)
@@ -9,7 +9,8 @@
                        "Shirayuki",
                        "아라",
                        "Macofe",
-                       "Fanjiayi"
+                       "Fanjiayi",
+                       "Cuatro Remos"
                ]
        },
        "tog-underline": "Na'raya i inachetton:",
index f8e43e4..60a6acd 100644 (file)
        "rcfilters-filter-editsbyself-description": "بەشدارییەکانی خۆت.",
        "rcfilters-filter-editsbyother-label": "گۆڕانکارییەکانی کەسانی تر",
        "rcfilters-filter-editsbyother-description": "ھەموو گۆڕانکارییەکان بێجگە لەوەی خۆت",
-       "rcfilters-filtergroup-userExpLevel": "ئەزموونی بەکارھێنەران",
+       "rcfilters-filtergroup-user-experience-level": "ئەزموونی بەکارھێنەران",
        "rcfilters-filter-user-experience-level-registered-label": "تۆمارکراو",
        "rcfilters-filter-user-experience-level-registered-description": "ئەو بەکارھێنەرانەی لە ژوورەوەن",
        "rcfilters-filter-user-experience-level-unregistered-label": "تۆمارنەکراوەکان",
        "rcfilters-filter-categorization-label": "گۆڕانکاری پۆلەکان",
        "rcfilters-filter-logactions-label": "کردارە لۆگییەکان",
        "rcfilters-filter-logactions-description": "کردارە بەڕێوەبەرییەکان، دروستکردنی ھەژمارەکان، سڕینەوەی پەڕەکان، بارکردنەکان...",
-       "rcfilters-filtergroup-lastRevision": "دوایین پێداچوونەوەکان",
+       "rcfilters-filtergroup-lastrevision": "دوایین پێداچوونەوەکان",
        "rcfilters-filter-lastrevision-label": "دوایین پێداچوونەوە",
        "rcfilters-filter-lastrevision-description": "تەنیا دوایین گۆڕانکاری سەر پەڕەکان.",
        "rcfilters-filter-previousrevision-label": "دوایین گۆڕانکاری نا",
        "minoreditletter": "ب",
        "newpageletter": "ن",
        "boteditletter": "بۆت",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|بەکارھێنەر}}ی چاودێر]",
        "rc-change-size-new": "$1 {{PLURAL:$1|بایت}} پاش گۆڕانکاری",
        "newsectionsummary": "/* $1 */ بەشی نوێ",
        "rc-enhanced-expand": "وردەکارییەکان نیشان بدە",
        "allmessagesdefault": "دەقی بنەڕەتی",
        "allmessagescurrent": "دەقی ھەنووکە",
        "allmessagestext": "ئەمە لیستێکە لە پەیامەکانی بەردەست لە بۆشایی‌ناوی میدیاویکی.\nتکایە سەردانی [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation ناوچەیی‌کردنی میدیاویکی] و [https://translatewiki.net translatewiki.net] بکە ئەگەر دەتەوێ لە ناوچەیی‌کردنی میدیاویکی بە گشتی بەشداری بکەیت.",
-       "allmessagesnotsupportedDB": "ئەم لاپەڕە ناتوانی بەکاربێت لەبەر ئەوەی '''$wgUseDatabaseMessages''' لەکار خستراوە.",
+       "allmessages-not-supported-database": "ئەم لاپەڕە ناتوانی بەکاربێت لەبەر ئەوەی '''$wgUseDatabaseMessages''' لەکار خستراوە.",
        "allmessages-filter-legend": "پاڵێو",
        "allmessages-filter-unmodified": "نەگۆڕدراو",
        "allmessages-filter-all": "هەموو",
        "logentry-import-upload": "$1 {{GENDER:$2|بارکرد}} $3 بە بەکارھێنانی [[special:Import|بارکەر]]",
        "logentry-import-interwiki": "$1 $3ی لە ویکییەکی ترەوە ھاوردەکرد",
        "logentry-import-interwiki-details": "$1 $3ی لە $5ەوە ھەناردە کرد ($4 بەسەرداچوونەوە)",
+       "logentry-merge-merge": "$1 $3ی لەگەڵ $4 تێکەڵکرد (بەسەرداچوونەکان لە $5 زیاترن)",
        "logentry-move-move": "$1 پەڕەی $3ی {{GENDER:$2|گواستەوە}} بۆ $4",
        "logentry-move-move-noredirect": "$1 پەڕەی $3ی بە بێ بەجێھشتنی ڕەوانەکەرێک {{GENDER:$2|گواستەوە}} بۆ $4",
        "logentry-move-move_redir": "$1 پەڕەی $3 {{GENDER:$2|گواستەوە}} بۆ $4 کە پێشتر ڕەوانەکەر بوو",
index 83ff3be..311e82b 100644 (file)
        "allmessagesdefault": "Testu predefinitu",
        "allmessagescurrent": "Testu attuale",
        "allmessagestext": "Ista pagina riperturia a lista di tutti i messagi dispunibili in u spaziu MediaWiki. Per cuntribuì à a lucalizazione generica di MediaWiki, visità [[translatewiki:|Translatewiki.net]].",
-       "allmessagesnotsupportedDB": "Ista pagina ùn hè dispunibile perchè '''$wgUseDatabaseMessages''' ùn hè micca attivu.",
+       "allmessages-not-supported-database": "Ista pagina ùn hè dispunibile perchè '''$wgUseDatabaseMessages''' ùn hè micca attivu.",
        "allmessages-filter-legend": "Filtru",
        "allmessages-filter": "Filtrà per statu di mudifica:",
        "allmessages-filter-unmodified": "Micca mudificati",
index 660deed..48797ce 100644 (file)
        "minoreditletter": "к",
        "newpageletter": "Я",
        "boteditletter": "б",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|1=къулланыджы|къулланыджы}} козете]",
        "rc-change-size-new": "Денъиштирильген сонъ $1 {{PLURAL:$1|байт|байт}}",
        "newsectionsummary": "/* $1 */ янъы болюк",
        "rc-enhanced-expand": "Тафсилятыны косьтер",
index 552ef2f..18a354f 100644 (file)
        "minoreditletter": "k",
        "newpageletter": "Y",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|qullanıcı|qullanıcı}} közete]",
        "rc-change-size-new": "Deñiştirilgen soñ $1 {{PLURAL:$1|bayt|bayt}}",
        "newsectionsummary": "/* $1 */ yañı bölük",
        "rc-enhanced-expand": "Tafsilâtını köster",
index 2834381..cb6b65b 100644 (file)
@@ -42,7 +42,8 @@
                        "Ed g2s",
                        "Radana",
                        "Jan Růžička",
-                       "Jaroslav Cerny"
+                       "Jaroslav Cerny",
+                       "Slepi"
                ]
        },
        "tog-underline": "Podtrhávat odkazy:",
@@ -88,6 +89,7 @@
        "tog-norollbackdiff": "Po vrácení změny nezobrazovat porovnání rozdílů",
        "tog-useeditwarning": "Upozornit, když budu opouštět editaci bez uložení změn",
        "tog-prefershttps": "Po přihlášení vždy používat zabezpečené připojení",
+       "tog-showrollbackconfirmation": "Při kliknutí na odkaz pro vrácení editace zobrazit žádost o potvrzení",
        "underline-always": "Vždy",
        "underline-never": "Nikdy",
        "underline-default": "Podle nastavení prohlížeče nebo vzhledu",
        "badaccess-group0": "Nemáte oprávnění k provedení požadované činnosti.",
        "badaccess-groups": "Požadovanou činnost smějí provádět jen uživatelé ve {{PLURAL:$2|skupině|skupinách}} $1.",
        "versionrequired": "Vyžadována MediaWiki verze $1",
-       "versionrequiredtext": "Pro použití této stránky je vyžadováno MediaWiki verze $1. Vizte [[Special:Version|stránku verze]].",
+       "versionrequiredtext": "Pro použití této stránky je vyžadováno MediaWiki verze $1. Viz [[Special:Version|stránku verze]].",
        "ok": "OK",
        "pagetitle": "$1 – {{SITENAME}}",
        "retrievedfrom": "Citováno z „$1“",
        "virus-scanfailed": "prověřování selhalo (kód $1)",
        "virus-unknownscanner": "neznámý antivirus:",
        "logouttext": "<strong>Nyní jste odhlášeni.</strong>\n\nNěkteré stránky se mohou i nadále zobrazovat, jako byste byli dosud přihlášeni, dokud nevyprázdníte cache prohlížeče.",
+       "logging-out-notify": "Probíhá vaše odhlašování, prosím čekejte.",
+       "logout-failed": "Momentálně se nelze odhlásit: $1",
        "cannotlogoutnow-title": "Momentálně se nelze odhlásit",
        "cannotlogoutnow-text": "Odhlášení není možné, když se používají $1.",
        "welcomeuser": "Vítejte, uživateli $1!",
        "page_first": "první",
        "page_last": "poslední",
        "histlegend": "(teď) = rozdíly oproti nynější verzi, (předchozí) = rozdíly oproti předchozí verzi, <b>m</b> = malá editace",
-       "history-fieldset-title": "Hledat revize",
+       "history-fieldset-title": "Filtrovat revize",
        "history-show-deleted": "Pouze smazané",
        "histfirst": "nejstarší",
        "histlast": "nejnovější",
        "historysize": "({{PLURAL:$1|1 bajt|$1 bajty|$1 bajtů}})",
-       "historyempty": "(prázdné)",
+       "historyempty": "prázdné",
        "history-feed-title": "Historie editací",
        "history-feed-description": "Historie editací této stránky",
        "history-feed-item-nocomment": "$1 v $2",
        "revdelete-edit-reasonlist": "Editovat důvody smazání",
        "revdelete-offender": "Autor revize:",
        "suppressionlog": "Kniha utajení",
-       "suppressionlogtext": "Toto je seznam mazání a blokování zahrnující skrytí obsahu i před správci.\nVizte též [[Special:BlockList|seznam všech probíhajících bloků]].",
+       "suppressionlogtext": "Toto je seznam mazání a blokování zahrnující skrytí obsahu i před správci.\nViz též [[Special:BlockList|seznam všech probíhajících bloků]].",
        "mergehistory": "Slučování historií stránek",
        "mergehistory-header": "Tato stránka Vám umožní sloučit historii verzí jedné zdrojové stránky s novější stránkou.\nUjistěte se, že tato změna udrží souvislost a posloupnost verzí v historii.",
        "mergehistory-box": "Sloučení verzí dvou stránek:",
        "right-reupload-own": "Přepisování souborů nahraných sebou samotným",
        "right-reupload-shared": "Nahrávání lokálních souborů k potlačení těch ve sdíleném úložišti",
        "right-upload_by_url": "Nahrávání souborů z URL adres",
-       "right-purge": "Vyčištění vyrovnávací paměti stránky bez potvrzovacího dialogu",
+       "right-purge": "Vyčištění vyrovnávací paměti stránky",
        "right-autoconfirmed": "Imunita vůči rychlostním limitům založeným na IP adrese",
        "right-bot": "Být považován za automatický proces",
-       "right-nominornewtalk": "Nevypisování oznámení o nové zprávě po malých úpravách diskusní stránky",
+       "right-nominornewtalk": "Potlačení oznámení o nové zprávě po malých úpravách diskusní stránky",
        "right-apihighlimits": "Používání vyšších limitů v API dotazech",
        "right-writeapi": "Používání zapisovacího API",
        "right-delete": "Mazání stránek",
        "right-viewmyprivateinfo": "Prohlížení vlastních soukromých údajů (např. e-mailová adresa, skutečné jméno)",
        "right-editmyprivateinfo": "Změna vašich soukromých údajů (např. e-mailová adresa, skutečné jméno)",
        "right-editmyoptions": "Změna vašich uživatelských nastavení",
-       "right-rollback": "Rychlý revert Ãºprav posledního uživatele editujícího danou stránku",
+       "right-rollback": "Rychlé vracení zpÄ\9bt editací posledního uživatele editujícího danou stránku",
        "right-markbotedits": "Označování revertů jako editace bota",
        "right-noratelimit": "Imunita vůči rychlostním limitům",
        "right-import": "Import stránek z jiných wiki",
        "action-changetags": "přidávat libovolné značky na jednotlivé revize a protokolovací záznamy a odebírat je",
        "action-deletechangetags": "mazat značky z databáze",
        "action-purge": "vyčistit vyrovnávací paměť této stránky",
+       "action-apihighlimits": "používat vyšší limity v API dotazech",
+       "action-autoconfirmed": "nebýt omezeni rychlostními limity na dané IP adrese",
+       "action-bigdelete": "mazat stránky s dlouhou historií",
+       "action-blockemail": "zablokovat uživateli možnost posílání e-mailů",
+       "action-bot": "být označen jako \"bot\"",
+       "action-editprotected": "editovat stránky zamčené na „{{int:protect-level-sysop}}“",
+       "action-editsemiprotected": "editovat stránky zamčené na „{{int:protect-level-autoconfirmed}}“",
+       "action-editinterface": "upravovat uživatelské rozhraní",
+       "action-editusercss": "upravovat CSS soubory ostatních uživatelů",
+       "action-edituserjson": "upravovat JSON soubory ostatních uživatelů",
+       "action-edituserjs": "upravovat JavaScriptové soubory ostatních uživatelů",
+       "action-editsitecss": "upravovat CSS celého projektu",
+       "action-editsitejson": "upravovat JSON celého projektu",
+       "action-editsitejs": "upravovat JavaScript celého projektu",
+       "action-editmyusercss": "upravovat vlastní uživatelské CSS soubory",
+       "action-editmyuserjson": "upravovat vlastní uživatelské JSON soubory",
+       "action-editmyuserjs": "upravovat vlastní uživatelský JavaScript",
+       "action-viewsuppressed": "prohlížet revize skryté všem uživatelům",
+       "action-hideuser": "zablokovat uživatelské jméno a skrýt jej",
+       "action-ipblock-exempt": "obcházet blokování IP adres, jejich rozsahů a autobloků",
+       "action-unblockself": "odblokovat sebe sama",
+       "action-noratelimit": "nebýt omezeni rychlostními limity",
+       "action-reupload-own": "přepisovat sebou nahrané soubory",
+       "action-nominornewtalk": "potlačit oznámení o nové zprávě při malých úpravách diskusní stránky",
+       "action-markbotedits": "označovat reverty jako editace bota",
+       "action-patrolmarks": "prohlížet si záznamy o prověření v posledních změnách",
+       "action-override-export-depth": "exportovat stránky včetně odkazovaných stránek až do hloubky 5",
+       "action-suppressredirect": "nevyrábět při přesouvání stránek přesměrování z původního názvu",
        "nchanges": "$1 {{PLURAL:$1|změna|změny|změn}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|od poslední návštěvy}}",
        "enhancedrc-history": "historie",
        "recentchanges-label-unpatrolled": "Tato změna dosud nebyla prověřena",
        "recentchanges-label-plusminus": "Velikost stránky se změnila o tolik bajtů",
        "recentchanges-legend-heading": "<strong>Legenda:</strong>",
-       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (vizte též [[Special:NewPages|seznam nových stránek]])",
+       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (viz též [[Special:NewPages|seznam nových stránek]])",
        "recentchanges-legend-plusminus": "(''±123'')",
        "recentchanges-submit": "Zobrazit",
        "rcfilters-tag-remove": "Odebrat '$1'",
        "rcfilters-savedqueries-already-saved": "Tyto filtry jsou již uloženy. K uložení nového je třeba změnit jejich nastavení.",
        "rcfilters-restore-default-filters": "Obnovit výchozí filtry",
        "rcfilters-clear-all-filters": "Zrušit všechny filtry",
-       "rcfilters-show-new-changes": "Zobrazit nejnovější změny",
+       "rcfilters-show-new-changes": "Zobrazit změny od $1",
        "rcfilters-search-placeholder": "Filtrovat poslední změny (použijte menu nebo vyhledejte název filtru)",
        "rcfilters-invalid-filter": "Neplatný filtr",
        "rcfilters-empty-filter": "Žádné aktivní filtry. Zobrazeny jsou všechny příspěvky.",
        "rcfilters-filter-editsbyself-description": "Vaše vlastní příspěvky.",
        "rcfilters-filter-editsbyother-label": "Změny ostatních",
        "rcfilters-filter-editsbyother-description": "Všechny změny kromě vašich.",
-       "rcfilters-filtergroup-userExpLevel": "Registrace a zkušenost uživatelů",
+       "rcfilters-filtergroup-user-experience-level": "Registrace a zkušenost uživatelů",
        "rcfilters-filter-user-experience-level-registered-label": "Registrovaní",
        "rcfilters-filter-user-experience-level-registered-description": "Přihlášení editoři.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Neregistrovaní",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Filtr „Malé editace“ je v konfliktu s jedním nebo více filtry podle typu změny, protože určité typy změn nelze označit jako malé. Dotyčné filtry jsou označeny nahoře, v prostoru „Aktivní filtry“.",
        "rcfilters-hideminor-conflicts-typeofchange": "Určité typy změn nelze označit jako malé, tento filtr je proto v konfliktu s následujícími filtry podle typu změny: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Tento filtr podle typu změny je v konfliktu s filtrem „Malé editace“. Určité typy změn nelze označit jako malé.",
-       "rcfilters-filtergroup-lastRevision": "Aktuální verze",
+       "rcfilters-filtergroup-lastrevision": "Aktuální verze",
        "rcfilters-filter-lastrevision-label": "Aktuální verze",
        "rcfilters-filter-lastrevision-description": "Jen poslední změna stránky.",
        "rcfilters-filter-previousrevision-label": "Ne nejnovější revize",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "r",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|sledující uživatel|sledující uživatelé|sledujících uživatelů}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|bajt|bajty|bajtů}} po změně",
        "newsectionsummary": "Nová sekce /* $1 */",
        "rc-enhanced-expand": "Zobrazit detaily",
        "lockmanager-fail-closelock": "Soubor se zámkem pro „$1“ nelze zavřít.",
        "lockmanager-fail-deletelock": "Soubor se zámkem pro „$1“ nelze smazat.",
        "lockmanager-fail-acquirelock": "Zámek pro „$1“ nelze získat.",
-       "lockmanager-fail-openlock": "Soubor zámku „$1“ nelze otevřít. Ujistěte se, že váš adresář nahraných souborů je správně nakonfigurován a že váš webový server má povolení k zápisu do tohoto adresáře. Pro další informace vizte https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgUploadDirectory.",
+       "lockmanager-fail-openlock": "Soubor zámku „$1“ nelze otevřít. Ujistěte se, že váš adresář nahraných souborů je správně nakonfigurován a že váš webový server má povolení k zápisu do tohoto adresáře. Pro další informace viz https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgUploadDirectory.",
        "lockmanager-fail-releaselock": "Zámek pro „$1“ nelze uvolnit.",
        "lockmanager-fail-db-bucket": "Nelze navázat spojení s dostatečným počtem databází zámků v bloku $1.",
        "lockmanager-fail-db-release": "Uzamčení databáze $1 nelze uvolnit.",
        "uploadstash-zero-length": "Soubor má nulovou délku.",
        "invalid-chunk-offset": "Neplatný posun bloku",
        "img-auth-accessdenied": "Přístup odepřen",
-       "img-auth-nopathinfo": "Chybí informace o cestě.\nVáš server musí být nastaven tak, aby předával proměnné REQUEST_URI nebo PATH_INFO.\nPokud je, zkuste zapnout $wgUsePathInfo.\nVizte https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
+       "img-auth-nopathinfo": "Chybí informace o cestě.\nVáš server musí být nastaven tak, aby předával proměnné REQUEST_URI nebo PATH_INFO.\nPokud je, zkuste zapnout $wgUsePathInfo.\nViz https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Požadovaná cesta nespadá pod nakonfigurovaný adresář s načtenými soubory.",
        "img-auth-badtitle": "Z „$1“ nelze vytvořit platný název stránky.",
-       "img-auth-nologinnWL": "Nejste přihlášen(a) a „$1“ není na bílé listině.",
        "img-auth-nofile": "Soubor „$1“ neexistuje.",
        "img-auth-isdir": "Pokoušíte se zobrazit adresář „$1“.\nDovolen je pouze přístup k souborům.",
        "img-auth-streaming": "Přenáší se „$1“.",
        "brokenredirectstext": "Tato přesměrování vedou na neexistující stránky:",
        "brokenredirects-edit": "editovat",
        "brokenredirects-delete": "smazat",
-       "withoutinterwiki": "Stránky bez mezijazykových odkazů (interwiki)",
+       "withoutinterwiki": "Stránky bez mezijazykových odkazů",
        "withoutinterwiki-summary": "Tyto stránky neobsahují žádný mezijazykový odkaz:",
        "withoutinterwiki-legend": "Prefix",
        "withoutinterwiki-submit": "Zobrazit",
        "unusedimages": "Nepoužívané soubory",
        "wantedcategories": "Chybějící kategorie",
        "wantedpages": "Chybějící stránky",
-       "wantedpages-summary": "Seznam neexistujících stránek, na které vede nejvíce odkazů, kromě stránek, na které odkazují jen přesměrování. Pro seznam neexistujících stránek, na které odkazují přesměrování, vizte [[{{#special:BrokenRedirects}}|seznam přerušených přesměrování]].",
+       "wantedpages-summary": "Seznam neexistujících stránek, na které vede nejvíce odkazů, kromě stránek, na které odkazují jen přesměrování. Pro seznam neexistujících stránek, na které odkazují přesměrování, viz [[{{#special:BrokenRedirects}}|seznam přerušených přesměrování]].",
        "wantedpages-badtitle": "Výsledky obsahují neplatný název: $1",
        "wantedfiles": "Chybějící soubory",
        "wantedfiletext-cat": "Následující soubory se používají, ale neexistují. Soubory ze vzdálených úložišť zde mohou být uvedeny, přestože existují. Taková falešná pozitiva budou zobrazena <del>přeškrtnutě</del>. Stránky, které vkládají neexistující soubory, jsou navíc uvedeny v [[:$1]].",
        "index-category-desc": "Stránka obsahuje kouzelné slovo <code><nowiki>__INDEX__</nowiki></code> (a je ve jmenném prostoru, ve kterém je tento příznak dovolen), takže je indexována roboty, přestože by normálně nebyla.",
        "post-expand-template-inclusion-category-desc": "Stránka je po rozbalení všech šablon větší než <code>$wgMaxArticleSize</code>, takže některé šablony rozbaleny nebyly.",
        "post-expand-template-argument-category-desc": "Stránka je po rozbalení argumentu šablony (něco v trojitých závorkách, např. <code>{{{Foo}}}</code>) větší než <code>$wgMaxArticleSize</code>.",
-       "expensive-parserfunction-category-desc": "Stránka používá příliš mnoho náročných funkcí syntaktického analyzátoru (jako <code>#ifexist</code>). Vizte [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgExpensiveParserFunctionLimit Manual:$wgExpensiveParserFunctionLimit].",
+       "expensive-parserfunction-category-desc": "Stránka používá příliš mnoho náročných funkcí syntaktického analyzátoru (jako <code>#ifexist</code>). Viz [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgExpensiveParserFunctionLimit Manual:$wgExpensiveParserFunctionLimit].",
        "broken-file-category-desc": "Stránka obsahuje nefunkční odkaz na soubor (odkaz pro vložení souboru, který neexistuje).",
        "hidden-category-category-desc": "Kategorie ve svém textu obsahuje <code><nowiki>__HIDDENCAT__</nowiki></code>, což způsobuje, že se na stránkách implicitně nezobrazuje v rámečku odkazů na kategorie.",
        "trackingcategories-nodesc": "Popis není k dispozici.",
        "enotif_subject_moved": "$2 {{gender:$2|přesunul|přesunula}} stránku $1 na {{grammar:6sg|{{SITENAME}}}}",
        "enotif_subject_restored": "$2 {{gender:$2|obnovil|obnovila}} stránku $1 na {{grammar:6sg|{{SITENAME}}}}",
        "enotif_subject_changed": "$2 {{gender:$2|změnil|změnila}} stránku $1 na {{grammar:6sg|{{SITENAME}}}}",
-       "enotif_body_intro_deleted": "$2 {{gender:$2|smazal|smazala}} $PAGEEDITDATE na {{grammar:6sg|{{SITENAME}}}} stránku $1, vizte $3.",
-       "enotif_body_intro_created": "V $PAGEEDITDATE {{gender:$2|založil|založila}} $2 na {{grammar:6sg|{{SITENAME}}}} stránku $1, vizte aktuální verzi na $3 .",
-       "enotif_body_intro_moved": "V $PAGEEDITDATE {{gender:$2|přesunul|přesunula}} $2 na {{grammar:6sg|{{SITENAME}}}} stránku $1, vizte aktuální verzi na $3 .",
-       "enotif_body_intro_restored": "V $PAGEEDITDATE {{gender:$2|obnovil|obnovila}} $2 na {{grammar:6sg|{{SITENAME}}}} stránku $1, vizte aktuální verzi na $3 .",
-       "enotif_body_intro_changed": "V $PAGEEDITDATE {{gender:$2|změnil|změnila}} $2 na {{grammar:6sg|{{SITENAME}}}} stránku $1, vizte aktuální verzi na $3 .",
-       "enotif_lastvisited": "Pro všechny změny od vaší minulé návštěvy vizte $1",
+       "enotif_body_intro_deleted": "$2 {{gender:$2|smazal|smazala}} $PAGEEDITDATE na {{grammar:6sg|{{SITENAME}}}} stránku $1, viz $3.",
+       "enotif_body_intro_created": "V $PAGEEDITDATE {{gender:$2|založil|založila}} $2 na {{grammar:6sg|{{SITENAME}}}} stránku $1, viz aktuální verzi na $3 .",
+       "enotif_body_intro_moved": "V $PAGEEDITDATE {{gender:$2|přesunul|přesunula}} $2 na {{grammar:6sg|{{SITENAME}}}} stránku $1, viz aktuální verzi na $3 .",
+       "enotif_body_intro_restored": "V $PAGEEDITDATE {{gender:$2|obnovil|obnovila}} $2 na {{grammar:6sg|{{SITENAME}}}} stránku $1, viz aktuální verzi na $3.",
+       "enotif_body_intro_changed": "V $PAGEEDITDATE {{gender:$2|změnil|změnila}} $2 na {{grammar:6sg|{{SITENAME}}}} stránku $1, viz aktuální verzi na $3 .",
+       "enotif_lastvisited": "Pro všechny změny od vaší minulé návštěvy viz $1",
        "enotif_lastdiff": "Tuto změnu si můžete prohlédnout na $1",
        "enotif_anon_editor": "anonymní uživatel $1",
        "enotif_body": "Vážený uživateli $WATCHINGUSERNAME,\n\n$PAGEINTRO $NEWPAGE\n\nShrnutí editace: $PAGESUMMARY $PAGEMINOREDIT\n\nUživatele, který změnu provedl, můžete kontaktovat:\ne-mailem: $PAGEEDITOR_EMAIL\nna wiki: $PAGEEDITOR_WIKI\n\nDo doby, než stránku navštívíte jako přihlášený uživatel, vám další oznámení k této stránce nebudou zasílána. Případně si můžete vynulovat příznaky ve svém seznamu sledovaných stránek.\n\nS pozdravem váš zasílač hlášení {{grammar:2sg|{{SITENAME}}}}\n\n--\nZměnit nastavení e-mailových oznámení můžete na\n{{canonicalurl:{{#special:Preferences}}}}\n\nNastavení sledovaných stránek může změnit na\n{{canonicalurl:Special:Watchlist/edit}}\n\nStránku můžete ze svých sledovaných vyřadit na\n$UNWATCHURL\n\nRady a kontakt:\n$HELPPAGE",
        "delete-confirm": "Smazání stránky „$1“",
        "delete-legend": "Smazat",
        "historywarning": "<strong>Varování:</strong> Stránka, kterou se chystáte smazat, má historii s $1 {{PLURAL:$1|revizí|revizemi}}:",
-       "historyaction-submit": "Zobrazit",
+       "historyaction-submit": "Zobrazit revize",
        "confirmdeletetext": "Chystáte se smazat stránku s celou její historií. Prosím potvrďte, že to opravdu chcete učinit, že si uvědomujete důsledky a že je to v souladu s [[{{MediaWiki:Policy-url}}|pravidly]].",
        "actioncomplete": "Provedeno",
        "actionfailed": "Operace se nezdařila",
        "deleting-backlinks-warning": "<strong>Upozornění:</strong> Stránka, kterou se chystáte smazat, je [[Special:WhatLinksHere/{{FULLPAGENAME}}|na jiných stránkách]] odkazována nebo je do nich vložena.",
        "deleting-subpages-warning": "<strong>Upozornění:</strong> Stránka, kterou se chystáte smazat, má [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|podstránku|$1 podstránky|$1 podstránek|51=více než 50 podstránek}}]].",
        "rollback": "Vrátit zpět editace",
+       "rollback-confirmation-confirm": "Potvrďte prosím:",
+       "rollback-confirmation-yes": "Vrátit zpět",
+       "rollback-confirmation-no": "Storno",
        "rollbacklink": "vrácení zpět",
        "rollbacklinkcount": "vrácení $1 {{PLURAL:$1|editace|editací}} zpět",
        "rollbacklinkcount-morethan": "vrácení více než $1 {{PLURAL:$1|editace|editací}} zpět",
        "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-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.",
-       "rollback-success-notify": "Editace uživatele $1 byly vráceny;\nobnovena poslední verze od uživatele $2. [$3 Zobrazit změny]",
        "sessionfailure-title": "Chyba relace",
        "sessionfailure": "Nastal problém s vaším přihlášením;\nvámi požadovaná činnost byla zrušena jako prevence před neoprávněným přístupem.\nStiskněte tlačítko „zpět“, obnovte stránku, ze které jste přišli, a zkuste činnost znovu.",
        "changecontentmodel": "Změnit model obsahu stránky",
        "undeletecomment": "Důvod:",
        "cannotundelete": "Některá nebo všechna obnovení se nezdařila:\n$1",
        "undeletedpage": "<strong>Stránka „$1“ byla obnovena</strong>\n\nZáznam o posledních mazáních a obnoveních najdete v [[Special:Log/delete|knize smazaných stránek]].",
-       "undelete-header": "Vizte nedávno smazané stránky v [[Special:Log/delete|knize smazaných stránek]].",
+       "undelete-header": "Viz nedávno smazané stránky v [[Special:Log/delete|knize smazaných stránek]].",
        "undelete-search-title": "Hledání smazaných stránek",
        "undelete-search-box": "Hledání smazaných stránek",
        "undelete-search-prefix": "Zobrazit stránky začínající na:",
        "mycontris": "Příspěvky",
        "anoncontribs": "Příspěvky",
        "contribsub2": "{{GENDER:$3|uživatele|uživatelky}} $1 ($2)",
+       "contributions-subtitle": "{{GENDER:$3|uživatele|uživatelky}} $1",
        "contributions-userdoesnotexist": "Uživatelský účet „$1“ není zaregistrován.",
        "negative-namespace-not-supported": "Jmenné prostory se zápornými hodnotami nejsou podporovány.",
        "nocontribs": "Nenalezeny žádné změny vyhovující kritériím.",
        "blocklist-userblocks": "Skrýt zablokované účty",
        "blocklist-tempblocks": "Skrýt dočasná zablokování",
        "blocklist-addressblocks": "Skrýt blokování jedné IP adresy",
+       "blocklist-type": "Typ:",
+       "blocklist-type-opt-all": "Vše",
+       "blocklist-type-opt-sitewide": "Na celém projektu",
+       "blocklist-type-opt-partial": "Částečný",
        "blocklist-rangeblocks": "Skrýt blokování rozsahů",
        "blocklist-timestamp": "Datum a čas",
        "blocklist-target": "Cíl",
        "blocklist-editing-page": "stránky",
        "blocklist-editing-ns": "jmenné prostory",
        "ipblocklist-empty": "Seznam probíhajících bloků je prázdný.",
-       "ipblocklist-no-results": "Požadovaná IP adresa nebo uživatelské jméno není blokováno.",
+       "ipblocklist-no-results": "Nebylo nalezeno žádné zablokování dané IP adresy nebo uživatele.",
        "blocklink": "zablokovat",
        "unblocklink": "odblokovat",
        "change-blocklink": "změnit blok",
+       "empty-username": "(uživatelské jméno není dostupné)",
        "contribslink": "příspěvky",
        "emaillink": "poslat e-mail",
        "autoblocker": "Automatické zablokování kvůli tomu, že vaši IP adresu nedávno používal uživatel „[[User:$1|$1]]“.\nDůvod zablokování uživatele $1: „$2“",
        "blocklog-showsuppresslog": "{{GENDER:$1|Tento uživatel byl zablokován a skryt|Tato uživatelka byla zablokována a skryta}}. Zde je pro přehled zobrazen výpis záznamu utajení:",
        "blocklogentry": "blokuje „[[$1]]“ s časem vypršení $2 $3",
        "reblock-logentry": "mění nastavení bloku „[[$1]]“ s časem vypršení $2 $3",
-       "blocklogtext": "Toto je kniha úkonů blokování a odblokování uživatelů.\nAutomaticky blokované IP adresy nejsou vypsány.\nVizte též [[Special:BlockList|seznam všech probíhajících bloků]].",
+       "blocklogtext": "Toto je kniha úkonů blokování a odblokování uživatelů.\nAutomaticky blokované IP adresy nejsou vypsány.\nViz též [[Special:BlockList|seznam všech probíhajících bloků]].",
        "unblocklogentry": "odblokovává „$1“",
        "block-log-flags-anononly": "pouze anonymní uživatelé",
        "block-log-flags-nocreate": "vytváření účtů zablokováno",
        "allmessagesdefault": "Původní text",
        "allmessagescurrent": "Aktuální text",
        "allmessagestext": "Toto je seznam všech hlášení dostupných ve jmenném prostoru MediaWiki.\nPokud si přejete přispívat k lokalizaci softwaru MediaWiki, navštivte [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation lokalizační stránku na mediawiki.org] a [https://translatewiki.net server translatewiki.net].",
-       "allmessagesnotsupportedDB": "{{ns:special}}:AllMessages není podporováno, neboť wgUseDatabaseMessages je vypnuto.",
+       "allmessages-not-supported-database": "{{ns:special}}:AllMessages není podporováno, neboť wgUseDatabaseMessages je vypnuto.",
        "allmessages-filter-legend": "Filtr",
        "allmessages-filter": "Filtr podle stavu:",
        "allmessages-filter-unmodified": "Neupraveno",
        "import-logentry-interwiki-detail": "{{PLURAL:$1|naimportována $1 revize|naimportovány $1 revize|naimportováno $1 revizí}} z $2",
        "javascripttest": "Testování JavaScriptu",
        "javascripttest-pagetext-unknownaction": "Neznámá akce „$1“.",
-       "javascripttest-qunit-intro": "Vizte [$1 dokumentaci testování] na mediawiki.org",
+       "javascripttest-qunit-intro": "Viz [$1 dokumentaci testování] na mediawiki.org",
        "tooltip-pt-userpage": "{{GENDER:|Vaše uživatelská}} stránka",
        "tooltip-pt-anonuserpage": "Uživatelská stránka pro IP adresu, ze které editujete",
        "tooltip-pt-mytalk": "{{GENDER:|Vaše}} diskusní stránka",
        "spamprotectiontext": "Stránka, kterou jste se {{GENDER:|pokusil|pokusila|pokusil(a)}} uložit, byla zablokována protispamovým filtrem. Pravděpodobnou příčinou je odkaz na externí stránku, která je na černé listině.",
        "spamprotectionmatch": "Následující text spustil náš filtr proti spamu: $1",
        "spambot_username": "Systémový čistič spamu",
-       "spam_reverting": "Revert na poslední verzi neobsahující odkazy na $1",
+       "spam_reverting": "Vrácení zpět na poslední verzi neobsahující odkazy na $1",
        "spam_blanking": "Všechny verze obsahovaly odkazy na $1, vyprázdněno",
        "spam_deleting": "Všechny verze obsahovaly odkazy na $1, smazáno",
        "simpleantispam-label": "Antispamová kontrola.\n<strong>NEVYPLŇUJTE</strong> následující!",
        "confirm-unwatch-top": "Vyjmout tuto stránku ze sledovaných?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Vrátit editace této stránky?",
+       "confirm-rollback-bottom": "Tato akce okamžitě zruší vybrané změny této stránky.",
        "confirm-mcrrestore-title": "Obnovit revizi",
        "confirm-mcrundo-title": "Vrátit zpět změnu",
        "mcrundofailed": "Vrácení editace zpět se nezdařilo",
        "tag-mw-blank-description": "Editace, které vyprázdní stránku",
        "tag-mw-replace": "Nahrazeno",
        "tag-mw-replace-description": "Editace, které odstraňují více než 90 % obsahu stránky",
-       "tag-mw-rollback": "Rychlý revert",
+       "tag-mw-rollback": "Rychlé vrácení zpÄ\9bt",
        "tag-mw-rollback-description": "Editace, jimiž byly předchozí editace vráceny zpět pomocí rychlého revertu",
        "tag-mw-undo": "Vrácení zpět",
        "tag-mw-undo-description": "Editace, jimiž se ruší předchozí editace pomocí odkazu „zrušit editaci“",
        "edit-error-long": "Chyby:\n\n$1",
        "revid": "revize $1",
        "pageid": "Stránka s ID $1",
-       "interfaceadmin-info": "$1\n\nOprávnění editovat celoprojektové soubory s CSS/JS/JSON bylo nedávno odděleno z oprávnění <code>editinterface</code>. Pokud nerozumíte, proč se vám zobrazuje tato chyba, vizte [[mw:MediaWiki_1.32/interface-admin]].",
+       "interfaceadmin-info": "$1\n\nOprávnění editovat celoprojektové soubory s CSS/JS/JSON bylo nedávno odděleno z oprávnění <code>editinterface</code>. Pokud nerozumíte, proč se vám zobrazuje tato chyba, viz [[mw:MediaWiki_1.32/interface-admin]].",
        "rawhtml-notallowed": "Značky &lt;html&gt; nelze používat mimo běžné stránky.",
        "gotointerwiki": "Opustit {{GRAMMAR:4sg|{{SITENAME}}}}",
        "gotointerwiki-invalid": "Zadaný název je neplatný.",
        "passwordpolicies-policyflag-forcechange": "nutné změnit při přihlášení",
        "passwordpolicies-policyflag-suggestchangeonlogin": "navrhnout změnu při přihlášení",
        "easydeflate-invaliddeflate": "Poskytnutý obsah nebyl správně zkomprimován",
-       "unprotected-js": "Z bezpečnostních důvodů nelze načítat JavaScript z nechráněných stran. Vyrábějte prosím JavaScriptové skripty jen ve jmenném prostoru MediaWiki: nebo jako uživatelskou podstránku"
+       "unprotected-js": "Z bezpečnostních důvodů nelze načítat JavaScript z nechráněných stran. Vyrábějte prosím JavaScriptové skripty jen ve jmenném prostoru MediaWiki: nebo jako uživatelskou podstránku",
+       "userlogout-continue": "Pokud se chcete odhlásit, [$1 pokračujte na odhlašovací stránku].",
+       "userlogout-sessionerror": "Kvůli chybě sezení se odhlášení nezdařilo. [$1 Zkuste to prosím znovu]."
 }
index f4a37ae..9a8ba3f 100644 (file)
        "rcfilters-filter-editsbyself-description": "Twòje gwôsné dzejania.",
        "rcfilters-filter-editsbyother-label": "Zjinaczi, chtërne zrobilë jinszi brëkòwnicë.",
        "rcfilters-filter-editsbyother-description": "Wszëtczé zjinaczi, òkróm twòjich.",
-       "rcfilters-filtergroup-userExpLevel": "Registracjô brëkòwnika i jegò doswiôdczenié",
+       "rcfilters-filtergroup-user-experience-level": "Registracjô brëkòwnika i jegò doswiôdczenié",
        "rcfilters-filter-user-experience-level-registered-label": "Zaregistrowóni",
        "rcfilters-filter-user-experience-level-registered-description": "Zalogòwóni brëkòwnicë",
        "rcfilters-filter-user-experience-level-unregistered-label": "Niezaregistrowóni",
        "rcfilters-filter-categorization-description": "Dodanié abò rëmniãcé starnë z kategòrie.",
        "rcfilters-filter-logactions-label": "Dzejania notérowóné w registru",
        "rcfilters-filter-logactions-description": "Dzejania sprôwników, ùsôdzanié kònt, rëmanié starnów, sélanié lopków...",
-       "rcfilters-filtergroup-lastRevision": "Òstatné wersje.",
+       "rcfilters-filtergroup-lastrevision": "Òstatné wersje.",
        "rcfilters-filter-lastrevision-label": "Nônowszô wersjô",
        "rcfilters-filter-lastrevision-description": "Leno nônowszi zjinaczi dlô kòżdi starnë.",
        "rcfilters-filter-previousrevision-label": "Wersje jiné niż nônowszô.",
        "alreadyrolled": "Ni mòże copnąc slédny edicëji starnë [[:$1]], chtërny ùsôdzcą je [[User:$2|$2]] ([[User talk:$2|Diskùsëjô]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]);\nchtos jiny ju zeditowôł starnã abò copnął zmianë.\n\nSlédnym ùsódzcą starnë bëł [[User:$3|$3]] ([[User talk:$3|Diskùsëjô]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
        "revertpage": "Edicje brëkòwnika [[Special:Contributions/$2|$2]] ([[User talk:$2|diskùsjô]]) òstałë òdrzucóné. Aùtorã przëwrócóny wersji je [[User:$1|$1]].",
        "rollback-success": "Copniãto edicje {{GENDER:$3|brëkòwnika|brëkòwniczczi}} $1;\ndoprowadzóno nazôd slédną wersëjã ùsôdzcë {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Edicje brëkòwnika $1 òstałë òdrzucóné; \nòsta przëwrócónô òstatnô wersjô, aùtorã chtërny je $2. [$3 Pòkażë zjinaczi]",
        "protectlogpage": "Zazychrowóné",
        "protectedarticle": "zazychrowónô [[$1]]",
        "modifiedarticleprotection": "zmienionô léga zazychrowaniô [[$1]]",
        "allmessagesdefault": "Domëslny tekst",
        "allmessagescurrent": "Aktualny tekst",
        "allmessagestext": "To je zestôwk systemòwëch ògłosów przistãpnëch w rumie mionów MediaWiki.\nProszã zazdrzë na [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Lokalizacëjô MediaWiki] ë [https://translatewiki.net translatewiki.net] jeżlë chcesz dolmaczëc softwôrã MediaWiki.",
-       "allmessagesnotsupportedDB": "'''{{ns:special}}:Allmessages''' nie mòże bëc brëkòwónô, temù że '''$wgUseDatabaseMessages''' je wëłączony.",
+       "allmessages-not-supported-database": "'''{{ns:special}}:Allmessages''' nie mòże bëc brëkòwónô, temù że '''$wgUseDatabaseMessages''' je wëłączony.",
        "thumbnail-more": "Zwikszi",
        "import": "Impòrtëjë starnë",
        "importlogpage": "Log jimpòrtu",
index bf6d7d7..51f10b8 100644 (file)
        "rcfilters-filter-minor-label": "Кăштах тӳрлетнисем",
        "rcfilters-filter-major-label": "Ахаль тӳрлетнисем",
        "rcfilters-filter-categorization-label": "Категорине улăштарнисем",
-       "rcfilters-filtergroup-lastRevision": "Юлашки версисем",
+       "rcfilters-filtergroup-lastrevision": "Юлашки версисем",
        "rcfilters-filter-lastrevision-label": "Хальхи верси",
        "rcfilters-filter-previousrevision-label": "Юлашки верси мар",
        "rclistfrom": "$2, $3 тытăнса çĕнĕ улăшăнисене кăтартни",
index 4b7e31c..a55f7eb 100644 (file)
        "accmailtext": "Anfonwyd cyfrinair a grewyd ar hap ar gyfer [[User talk:$1|$1]] at $2. Gellir newid y cyfrinair hwn ar y dudalen ''[[Special:ChangePassword|newid cyfrinair]]'', wrth fewngofnodi.",
        "newarticle": "(Newydd)",
        "newarticletext": "Rydych chi wedi dilyn cysylltiad i dudalen sydd heb gael ei chreu eto.\nI greu'r dudalen, dechreuwch deipio yn y blwch isod (gweler y [$1 dudalen gymorth] am fwy o wybodaeth).\nOs daethoch yma ar ddamwain, cliciwch botwm '''n&ocirc;l''' y porwr.",
-       "anontalkpagetext": "----''Dyma dudalen sgwrs ar gyfer defnyddiwr anhysbys sydd heb greu cyfrif eto, neu nad yw'n ei ddefnyddio. Felly mae'n rhaid inni ddefnyddio'r cyfeiriad IP i'w (h)adnabod. Mae cyfeiriadau IP yn gallu cael eu rhannu rhwng nifer o ddefnyddwyr. Os ydych chi'n ddefnyddiwr anhysbys ac yn teimlo'ch bod wedi derbyn sylwadau amherthnasol, [[Special:CreateAccount|crëwch gyfrif]] neu [[Special:UserLogin|mewngofnodwch]] i osgoi cael eich drysu gyda defnyddwyr anhysbys eraill o hyn ymlaen.''",
+       "anontalkpagetext": "<em>Dyma dudalen sgwrs ar gyfer defnyddiwr anhysbys sydd heb greu cyfrif eto, neu nad yw'n ei ddefnyddio.</em>\nFelly mae'n rhaid inni ddefnyddio'r cyfeiriad IP i'w adnabod.\nMae cyfeiriadau IP yn gallu cael eu rhannu rhwng nifer o ddefnyddwyr.\nOs ydych chi'n ddefnyddiwr anhysbys ac yn teimlo'ch bod wedi derbyn sylwadau amherthnasol, [[Special:CreateAccount|crëwch gyfrif]] neu [[Special:UserLogin|mewngofnodwch]] i osgoi cael eich drysu gyda defnyddwyr anhysbys eraill o hyn ymlaen.",
        "noarticletext": "Mae'r dudalen hon yn wag ar hyn o bryd.\nGallwch [[Special:Search/{{PAGENAME}}|chwilio am y teitl hwn]] ar ddalennau eraill, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} chwilio drwy'r logiau perthnasol], neu [{{fullurl:{{FULLPAGENAME}}|action=edit}} fe allwch greu'r ddalen hon]</span>.",
        "noarticletext-nopermission": "Mae'r dudalen hon yn wag ar hyn o bryd.\nGallwch [[Special:Search/{{PAGENAME}}|chwilio am y teitl hwn]] ar dudalennau eraill, neu gallwch <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} chwilio drwy'r logiau perthnasol]</span>, ond nid yw'r gallu gennych i ddechrau'r dudalen o'r dechrau cyntaf.",
        "missing-revision": "Nid yw'r diwygiad #$1 o'r dudalen \"{{FULLPAGENAME}}\" ar gael.\n\nFel arfer, fe ddigwydd hyn wrth ddilyn hen gyswllt i dudalen sydd wedi ei dileu.\nGallwch weld y manylion yn y [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} lòg dileu].",
        "histfirst": "cynharaf",
        "histlast": "diweddaraf",
        "historysize": "({{PLURAL:$1|$1 beit|$1 beit|$1 feit|$1 beit|$1 beit|$1 beit}})",
-       "historyempty": "(gwag)",
+       "historyempty": "gwag",
        "history-feed-title": "Hanes diwygio",
        "history-feed-description": "Hanes diwygio'r dudalen hon ar y wici",
        "history-feed-item-nocomment": "$1 am $2",
        "rcfilters-other-review-tools": "Teclynau adolygu eraill",
        "rcfilters-group-results-by-page": "Canlyniadau'r grwp bob yn ddalen",
        "rcfilters-activefilters": "Hidlau sydd ar waith",
+       "rcfilters-activefilters-hide": "Cuddio",
        "rcfilters-advancedfilters": "Ffiltrau ychwanegol",
        "rcfilters-limit-title": "Canlyniadau a ddangosir",
        "rcfilters-date-popup-title": "Cyfnod (i'w chwilio)",
        "rcfilters-filter-editsbyself-description": "Eich cyfraniadau chi.",
        "rcfilters-filter-editsbyother-label": "Newidiadau gan eraill",
        "rcfilters-filter-editsbyother-description": "Pob golygiad ond nid gennych chi.",
-       "rcfilters-filtergroup-userExpLevel": "Cofrestriad y Defnyddiwr a'i brofiad",
+       "rcfilters-filtergroup-user-experience-level": "Cofrestriad y Defnyddiwr a'i brofiad",
        "rcfilters-filter-user-experience-level-registered-label": "Cofrestrwyd",
        "rcfilters-filter-user-experience-level-registered-description": "Golygyddion sydd wedi mewngofnodi.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Heb gofrestru",
        "rcfilters-filter-watchlist-watchednew-label": "Newidiadau newydd i'ch Rhestr Wylio",
        "rcfilters-filter-watchlist-notwatched-label": "Heb fod yn eich Rhestr Wylio",
        "rcfilters-filter-watchlist-notwatched-description": "Popeth ar wahan i'r newidiadau i'ch Rhestr Wylio.",
+       "rcfilters-filter-watchlistactivity-unseen-label": "Newidiadau heb eu gweld gennych",
+       "rcfilters-filter-watchlistactivity-unseen-description": "Newidiadau i'r tudalennau nad ydych wedi ymweld â nhw.",
+       "rcfilters-filter-watchlistactivity-seen-label": "Newidiadau wedi eu gweld gennych",
+       "rcfilters-filter-watchlistactivity-seen-description": "Newidiadau i dudalennau rydych wedi ymweld â nhw ers iddynt gael eu newid.",
        "rcfilters-filtergroup-changetype": "Math o newid",
        "rcfilters-filter-pageedits-label": "Golygiadau i'r ddalen",
        "rcfilters-filter-pageedits-description": "Golygiadau i gynnwys wici, y sgyrsiau, categoriau...",
        "rcfilters-filter-categorization-label": "Newidiadau i'r Categoriau",
        "rcfilters-filter-categorization-description": "Cofnodion y dalennau a ychwanegwyd neu a symudwyd o'r categoriau.",
        "rcfilters-filter-logactions-label": "Gwriansow kovskrifys",
-       "rcfilters-filtergroup-lastRevision": "Yr adolygiadau diweddaraf",
+       "rcfilters-filtergroup-lastrevision": "Yr adolygiadau diweddaraf",
        "rcfilters-filter-lastrevision-label": "Yr adolygiad diweddaraf",
        "rcfilters-filter-lastrevision-description": "Dim ond yn newidiadau diweddaraf i'r ddalen.",
        "rcfilters-filter-previousrevision-label": "Nid yr adolygiad diweddaraf",
        "rcfilters-liveupdates-button": "Diweddariadau, byw (''Live updates'')",
        "rcfilters-liveupdates-button-title-on": "Diffod y 'Diweddariadau, byw'",
        "rcfilters-liveupdates-button-title-off": "Arddangos newidiadau wrth iddynt ddigwydd",
+       "rcfilters-watchlist-markseen-button": "Marcio'r newidiadau fel rhai a welwyd",
        "rcfilters-watchlist-edit-watchlist-button": "Golygwch eich Rhestr Wylio",
+       "rcfilters-watchlist-showupdated": "Mae tudalennau sydd wedi eu newid ers i chi ymweld â nhw ddiwethaf wedi'u <strong>hamlygu</strong>.",
        "rcfilters-preference-label": "Cuddio'r fersiwn ddiweddaraf o Newidiadau Diweddaraf",
        "rcnotefrom": "Isod rhestrir pob newid er <strong>$3, $4</strong> (ymddengys <strong>$1</strong> ohonynt).",
        "rclistfromreset": "Ailosod dyddiad yr hyn rydych wedi'i ddewis",
        "rclistfrom": "Dangos newidiadau newydd, gan ddechrau ers $3 $2",
        "rcshowhideminor": "$1 golygiadau bychain",
        "rcshowhideminor-show": "Dangoser",
-       "rcshowhideminor-hide": "Cuddier",
+       "rcshowhideminor-hide": "Cuddio",
        "rcshowhidebots": "$1 botiau",
        "rcshowhidebots-show": "Dangoser",
-       "rcshowhidebots-hide": "Cuddier",
+       "rcshowhidebots-hide": "Cuddio",
        "rcshowhideliu": "$1 o ddefnyddwyr cofrestredig",
        "rcshowhideliu-show": "Dangoser",
-       "rcshowhideliu-hide": "Cuddier",
+       "rcshowhideliu-hide": "Cuddio",
        "rcshowhideanons": "$1 defnyddwyr anhysbys",
        "rcshowhideanons-show": "Dangoser",
-       "rcshowhideanons-hide": "Cuddier",
+       "rcshowhideanons-hide": "Cuddio",
        "rcshowhidepatr": "$1 golygiadau wedi derbyn ymweliad patrôl",
        "rcshowhidepatr-show": "Dangoser",
-       "rcshowhidepatr-hide": "Cuddier",
+       "rcshowhidepatr-hide": "Cuddio",
        "rcshowhidemine": "$1 fy ngolygiadau",
        "rcshowhidemine-show": "Dangoser",
-       "rcshowhidemine-hide": "Cuddier",
+       "rcshowhidemine-hide": "Cuddio",
        "rcshowhidecategorization": "Categoreiddio tudalen $1",
        "rcshowhidecategorization-show": "Dangos",
        "rcshowhidecategorization-hide": "Cuddio",
        "rclinks": "Dangos y $1 newid diweddaraf yn y $2 diwrnod diwethaf",
        "diff": "gwahan",
        "hist": "hanes",
-       "hide": "Cuddier",
+       "hide": "Cuddio",
        "show": "Dangoser",
        "minoreditletter": "B",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|defnyddwyr|defnyddiwr|ddefnyddiwr|defnyddiwr|defnyddiwr|o ddefnyddwyr}} yn gwylio]",
        "rc-change-size-new": "$1 {{PLURAL:$1|beit}} wedi'r newid",
        "newsectionsummary": "/* $1 */ adran newydd",
        "rc-enhanced-expand": "Dangos y manylion",
        "recentchangeslinked-feed": "Newidiadau perthnasol",
        "recentchangeslinked-toolbox": "Newidiadau perthnasol",
        "recentchangeslinked-title": "Newidiadau cysylltiedig â \"$1\"",
-       "recentchangeslinked-summary": "Rhowch enw dalen i weld newidiadau ar ddalenau sy'n cyfeirio neu'n dolennu iddi. I weld aelodau o gategori, nodwch Categori:Enw'r categori. Bydd newidiadau i unrhyw ddalen sydd o fewn eich [[Special:Watchlist|Rhestr Wylio]] mewn ffont <strong>trwm</strong>.",
+       "recentchangeslinked-summary": "Rhowch enw dalen i weld newidiadau ar dudalennau sy'n cyfeirio neu'n dolennu iddi. I weld aelodau o gategori, nodwch {{ns:category}}:Enw'r categori. Bydd newidiadau i unrhyw dudalen sydd o fewn eich [[Special:Watchlist|Rhestr Wylio]] mewn ffont <strong>trwm</strong>.",
        "recentchangeslinked-page": "Tudalen:",
        "recentchangeslinked-to": "Dangos newidiadau i'r tudalennau â chyswllt arnynt sy'n arwain at y dudalen a enwir",
        "recentchanges-page-added-to-category": "Ychwanegwyd [[:$1]] at y categori",
        "img-auth-nopathinfo": "PATH_INFO yn eisiau.\nNid yw'ch gweinydd wedi ei osod i fedru pasio'r wybodaeth hon.\nEfallai ei fod wedi ei seilio ar CGI, ac heb fod yn gallu cynnal img_auth.\nGweler https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Nid yw'r llwybr y gwneuthpwyd cais amdano yn y cyfeiriadur uwchlwytho ffurfweddedig.",
        "img-auth-badtitle": "Ddim yn gallu gwneud teitl dilys o \"$1\".",
-       "img-auth-nologinnWL": "Nid ydych wedi mewngofnodi ac nid yw \"$1\" ar y rhestr wen.",
        "img-auth-nofile": "Nid oes ffeil a'r enw \"$1\" ar gael.",
        "img-auth-isdir": "Rydych yn ceisio cyrchu cyfeiriadur o'r enw \"$1\".\nDim ond ffeiliau y cewch eu cyrchu.",
        "img-auth-streaming": "Wrthi'n ffrydio \"$1\".",
        "filehist-filesize": "Maint y ffeil",
        "filehist-comment": "Sylw",
        "imagelinks": "Defnydd y ffeil",
-       "linkstoimage": "Mae'r {{PLURAL:$1|tudalen|dudalen|tudalennau|tudalennau|tudalennau|tudalennau}} isod yn cysylltu i'r ddelwedd hon:",
-       "linkstoimage-more": "Mae mwy na $1 {{PLURAL:$1|tudalen yn|dudalen yn|dudalen yn|o dudalennau'n|o dudalennau'n|o dudalennau'n}} cysylltu at y ffeil hon.\nMae'r rhestr ganlynol yn dangos y {{PLURAL:$1|$1 cysylltiad cyntaf}} at y ffeil hon yn unig. Mae [[Special:WhatLinksHere/$2|rhestr lawn]] ar gael.",
-       "nolinkstoimage": "Nid oes cyswllt ar unrhyw dudalen yn arwain at y ffeil hon.",
+       "linkstoimage": "Mae'r {{PLURAL:$1|tudalennau a ddefnyddir|$1 tudalennau a ddefnyddir}} isod yn cysylltu i'r ddelwedd hon:",
+       "linkstoimage-more": "Mae mwy na $1 {{PLURAL:$1|un tudalen yn|o dudalennau'n}} yn defnyddio'r ffeil hon.\nMae'r rhestr ganlynol yn dangos y {{PLURAL:$1|$1 tudalen cyntaf}} sy'n defnyddio'r ffeil hon yn unig.\nMae [[Special:WhatLinksHere/$2|rhestr lawn]] ar gael.",
+       "nolinkstoimage": "Nid oes tudalennau'n defnyddio'r ffeil hon.",
        "morelinkstoimage": "Gweld [[Special:WhatLinksHere/$1|rhagor o gysylltiadau]] at y ffeil hon.",
        "linkstoimage-redirect": "$1 (tudalen ffeil sy'n ailgyfeirio) $2",
        "duplicatesoffile": "Mae'r {{PLURAL:$1||ffeil|$1 ffeil|$1 ffeil|$1 ffeil|$1 ffeil}} canlynol yn union debyg i'r ffeil hon ([[Special:FileDuplicateSearch/$2|rhagor o fanylion]]):",
        "revertpage": "Wedi gwrthdroi golygiadau gan [[Special:Contributions/$2|$2]] ([[User talk:$2|Sgwrs]]); wedi adfer y golygiad diweddaraf gan [[User:$1|$1]]",
        "revertpage-nouser": "Wedi gwrthdroi golygiadau gan ddefnyddiwr cudd; wedi adfer y golygiad diweddaraf gan {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Gwrthdrowyd y golygiadau gan {{GENDER:$3|$1}};\nailosodwyd y golygiad olaf gan {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Gwrthdrowyd y golygiadau gan $1;\nailosodwyd y golygiad olaf gan $2. [$3 Dangoser y gwahaniaeth]",
        "sessionfailure-title": "Sesiwn wedi methu",
        "sessionfailure": "Mae'n debyg fod yna broblem gyda'ch sesiwn mewngofnodi; diddymwyd y weithred er mwyn diogelu'r sustem rhag ddefnyddwyr maleisus. Gwasgwch botwm 'nôl' eich porwr ac ail-lwythwch y dudalen honno, yna ceisiwch eto.",
        "changecontentmodel-title-label": "Teitl y ddalen",
        "allmessagesdefault": "Testun rhagosodedig",
        "allmessagescurrent": "Testun cyfredol",
        "allmessagestext": "Dyma restr o'r holl negeseuon yn y parth MediaWici.\nOs ydych am gyfrannu at y gwaith o gyfieithu ar gyfer holl prosiectau MediaWiki ar y cyd, mae croeso i chi ymweld â [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] a [https://translatewiki.net translatewiki.net].",
-       "allmessagesnotsupportedDB": "Nid yw '''{{ns:special}}:PobNeges''' yn cael ei gynnal gan fod '''$wgUseDatabaseMessages''' wedi ei ddiffodd.",
+       "allmessages-not-supported-database": "Nid yw '''{{ns:special}}:PobNeges''' yn cael ei gynnal gan fod '''$wgUseDatabaseMessages''' wedi ei ddiffodd.",
        "allmessages-filter-legend": "Hidl",
        "allmessages-filter": "Hidlo yn ôl eu cyflwr addasu:",
        "allmessages-filter-unmodified": "Heb eu haddasu",
index cd90f56..fd44443 100644 (file)
                        "Jorn Ari",
                        "Fnielsen",
                        "Weblars",
-                       "Kranix"
+                       "Kranix",
+                       "Psl85",
+                       "Dipsacus fullonum"
                ]
        },
        "tog-underline": "Understreg link:",
        "tog-hideminor": "Skjul mindre ændringer i listen over seneste ændringer",
-       "tog-hidepatrolled": "Skjul overvågede redigeringer i seneste ændringer",
-       "tog-newpageshidepatrolled": "Skjul overvågede sider på listen over nye sider",
+       "tog-hidepatrolled": "Skjul patruljerede redigeringer i seneste ændringer",
+       "tog-newpageshidepatrolled": "Skjul patruljerede sider på listen over nye sider",
        "tog-hidecategorization": "Skjul kategorisering af sider",
        "tog-extendwatchlist": "Udvid overvågningslisten til at vise alle ændringer og ikke kun den nyeste",
        "tog-usenewrc": "Gruppér ændringer efter side i listen over seneste ændringer og i overvågningslisten",
        "tog-norollbackdiff": "Vis ikke forskel efter udførelse af en tilbagerulning",
        "tog-useeditwarning": "Advar mig, hvis jeg forlader en redigeringsside med ændringer, der ikke er gemt.",
        "tog-prefershttps": "Brug altid en sikker forbindelse, når jeg er logget ind",
+       "tog-showrollbackconfirmation": "Bed om bekræftelse når der bliver klikket på et tilbagerulningslink",
        "underline-always": "Altid",
        "underline-never": "Aldrig",
        "underline-default": "Standard for browseren eller udseendet",
        "edithelp": "Hjælp til redigering",
        "helppage-top-gethelp": "Hjælp",
        "mainpage": "Forside",
-       "mainpage-description": "Hovedside",
+       "mainpage-description": "Forside",
        "policy-url": "Project:Politik",
        "portal": "Fællesskabs portal",
        "portal-url": "Project:Fællesskabs portal",
        "cannotlogoutnow-title": "Kan ikke logge af på nuværende tidspunkt",
        "cannotlogoutnow-text": "Det er ikke muligt at logge af når du bruger $1.",
        "welcomeuser": "Velkommen, $1!",
-       "welcomecreation-msg": "Din konto er blevet oprettet.\nDu kan ændre dine {{SITENAME}} [[Special:Indstilling|indstillinger]] hvis du ønsker.",
+       "welcomecreation-msg": "Din konto er blevet oprettet.\nDu kan ændre dine {{SITENAME}} [[Special:Preferences|indstillinger]] hvis du ønsker.",
        "yourname": "Brugernavn:",
        "userlogin-yourname": "Brugernavn",
        "userlogin-yourname-ph": "Indtast dit brugernavn",
        "badretype": "De indtastede adgangskoder er ikke ens.",
        "usernameinprogress": "En oprettelse af konto for dette brugernavn er allerede i gang.\nVent venligst.",
        "userexists": "Det brugernavn, du har valgt, er allerede i brug.\nVælg venligst et andet brugernavn.",
+       "createacct-normalization": "Dit brugernavn vil blive ændret til \"$2\" på grund af tekniske begrænsninger.",
        "loginerror": "Logon mislykket",
        "createacct-error": "Fejl ved kontooprettelse",
        "createaccounterror": "Kunne ikke oprette brugerkonto: $1",
        "content-json-empty-array": "Tomt matrix",
        "deprecated-self-close-category": "Sider, der bruger ugyldige, selvlukkende HTML-tags",
        "deprecated-self-close-category-desc": "Siden bruger ugyldige selvlukkende HTML tags, som <code>&lt;b/></code> eller <code>&lt;span/></code>. De vil snart blive ændret i overensstemmelse med HTML5-specifikationen, så de ikke kan bruges i wikitext.",
+       "duplicate-args-warning": "<strong>Advarsel</strong>: [[:$1]] kalder [[:$2]] med mere end en værdi for \"$3\"-parameteren. Kun den sidst angivne værdi vil blive brugt.",
        "duplicate-args-category": "Sider der bruger samme argument mere end en gang i en skabelon",
        "duplicate-args-category-desc": "Siden indeholder en skabelon hvor et argument er brugt mere end en gang, som <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> eller <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
        "expensive-parserfunction-warning": "Advarsel: Der er for mange beregningstunge oversætter-funktionskald på denne side.\n\nDer bør være færre end {{PLURAL:$2|$2 kald}}, lige nu er der {{PLURAL:$1|$1 kald}}.",
        "post-expand-template-argument-category": "Sider med udeladte skabelonparametre",
        "parser-template-loop-warning": "Skabelonløkke fundet: [[$1]]",
        "template-loop-category": "Sider med skabelonløkker",
+       "template-loop-category-desc": "Siden indeholder en skabelonløkke, det vil sige en skabelon som kalder sig selv rekursivt.",
        "parser-template-recursion-depth-warning": "En skabelon er rekursivt inkluderet for mange gange ($1)",
        "language-converter-depth-warning": "Dybdegrænse for sprogkonvertering overskredet ($1)",
        "node-count-exceeded-category": "Sider hvor antal noder er overskredet",
        "page_first": "Starten",
        "page_last": "Enden",
        "histlegend": "Forklaring: (nuværende) = forskel til den nuværende\nversion, (forrige) = forskel til den forrige version, M = mindre ændring",
-       "history-fieldset-title": "Søg efter versioner",
+       "history-fieldset-title": "Filtrer versioner",
        "history-show-deleted": "Kun slettede revisioner",
        "histfirst": "ældste",
        "histlast": "nyeste",
        "historysize": "($1 {{PLURAL:$1|Byte|Bytes}})",
-       "historyempty": "(tom)",
+       "historyempty": "tom",
        "history-feed-title": "Versionshistorie",
        "history-feed-description": "Versionshistorie for denne side i {{SITENAME}}",
        "history-feed-item-nocomment": "$1 med $2",
        "right-reupload-own": "Overskrive en eksisterende fil, som er lagt op af brugeren selv",
        "right-reupload-shared": "Lægge en lokal fil op, selvom den allerede findes centralt",
        "right-upload_by_url": "Lægge en fil op fra en URL",
-       "right-purge": "Nulstille sidens cache uden bekræftelse",
+       "right-purge": "Nulstil sidens cache for en side",
        "right-autoconfirmed": "Påvirkes ikke af IP-baserede hastighedsgrænser",
        "right-bot": "Redigeringer markeres som robot",
        "right-nominornewtalk": "Mindre ændringer på diskussionssider markerer ikke disse med nyt indhold",
        "action-changetags": "tilføje og fjerne vilkårlige tags for enkelte versioner og logposter",
        "action-deletechangetags": "slette tags fra databasen",
        "action-purge": "rense denne side",
+       "action-bigdelete": "slet sider med store historikker",
+       "action-blockemail": "bloker en bruger fra at sende e-mails",
+       "action-bot": "blive behandlet som en automatiseret proces",
        "nchanges": "$1 {{PLURAL:$1|ændring|ændringer}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|siden sidste besøg}}",
        "enhancedrc-history": "historik",
        "rcfilters-savedqueries-add-new-title": "Gem nuværende filterindstillinger",
        "rcfilters-restore-default-filters": "Gendan standardfiltre",
        "rcfilters-clear-all-filters": "Ryd alle filtre",
-       "rcfilters-show-new-changes": "Vis seneste ændringer",
+       "rcfilters-show-new-changes": "Vis seneste ændringer siden $1",
        "rcfilters-search-placeholder": "Filtrer ændringer (brug menuen eller søg på filternavn)",
        "rcfilters-invalid-filter": "Ugyldigt filter",
        "rcfilters-empty-filter": "Ingen aktive filtre. All bidrag vises.",
        "rcfilters-filter-editsbyself-description": "Dine egne bidrag.",
        "rcfilters-filter-editsbyother-label": "Ændringer af andre",
        "rcfilters-filter-editsbyother-description": "Alle ændringer undtagen din egen.",
-       "rcfilters-filtergroup-userExpLevel": "Brugerregistrering og -erfaring",
+       "rcfilters-filtergroup-user-experience-level": "Brugerregistrering og -erfaring",
        "rcfilters-filter-user-experience-level-registered-label": "Registrerede",
        "rcfilters-filter-user-experience-level-registered-description": "Indloggede brugere",
        "rcfilters-filter-user-experience-level-unregistered-label": "Uregistreret",
        "rcfilters-filter-categorization-description": "Optegnelser af at sider bliver tilføjet til eller fjernet fra kategorier.",
        "rcfilters-filter-logactions-label": "Loggede handlinger",
        "rcfilters-filter-logactions-description": "Administrative handlinger, kontooprettelser, sidesletninger, uploads...",
-       "rcfilters-filtergroup-lastRevision": "Seneste revisioner",
+       "rcfilters-filtergroup-lastrevision": "Seneste revisioner",
        "rcfilters-filter-lastrevision-label": "Seneste revision",
        "rcfilters-filter-lastrevision-description": "Kun den seneste ændring af en side.",
        "rcfilters-filter-previousrevision-label": "Ikke den seneste revision",
        "rcfilters-liveupdates-button-title-off": "Vis nye ændringer når de sker",
        "rcfilters-watchlist-markseen-button": "Marker alle ændringer som set",
        "rcfilters-watchlist-edit-watchlist-button": "Rediger din liste med overvågede sider",
-       "rcfilters-watchlist-showupdated": "Ændringer til sider du ikke har besøgt siden ændringerne blev gjort vises med <strong>fed</strong>.",
+       "rcfilters-watchlist-showupdated": "Ændringer til sider du ikke har besøgt siden ændringerne blev gjort vises med <strong>fed</strong> skrift.",
        "rcfilters-preference-label": "Brug grænsefladesnittet uden JavaScript",
+       "rcfilters-preference-help": "Indlæser Seneste ændringer uden mulighed for søgning med filter eller for fremhævelse.",
        "rcfilters-watchlist-preference-label": "Brug grænsefladesnittet uden JavaScript",
        "rcfilters-watchlist-preference-help": "Indlæser overvågningslisten uden mulighed for søgning med filter eller fremhævelse.",
        "rcfilters-filter-showlinkedfrom-label": "Vis ændringer på sider hvortil der linkes fra",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|overvågende bruger|overvågende brugere}}]",
        "rc-change-size": "$1 {{PLURAL:$1|Byte|Bytes}}",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} efter ændring",
        "newsectionsummary": "/* $1 */ nyt afsnit",
        "img-auth-nopathinfo": "PATH_INFO mangler.\nDin server er ikke sat op til at give denne information.\nDen bruger måske CGI og understøtter ikke img_auth.\nSe https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Den ønskede sti er ikke i det opsatte oplægningskatalog.",
        "img-auth-badtitle": "Kan ikke lave en gyldig titel ud fra \"$1\".",
-       "img-auth-nologinnWL": "Du er ikke logget ind, og \"$1\" er ikke på hvidlisten.",
        "img-auth-nofile": "Filen \"$1\" findes ikke.",
        "img-auth-isdir": "Du forsøger at få adgang til kataloget \"$1\".\nKun adgang til filer tillades.",
        "img-auth-streaming": "Sender \"$1\".",
        "delete-confirm": "Slet \"$1\"",
        "delete-legend": "Slet",
        "historywarning": "<strong>Advarsel:</strong> Siden du er ved at slette har en historie med $1 {{PLURAL:$1|version|versioner}}:",
-       "historyaction-submit": "Vis",
+       "historyaction-submit": "Vis revisioner",
        "confirmdeletetext": "Du er ved at slette en side sammen med hele dens tilhørende historik.\nBekræft venligst at du virkelig vil gøre dette, at du forstår konsekvenserne, og at du gør det i overensstemmelse med [[{{MediaWiki:Policy-url}}|retningslinjerne]].",
        "actioncomplete": "Gennemført",
        "actionfailed": "Handlingen mislykkedes",
        "deleteprotected": "Du kan ikke slette denne side, fordi den er beskyttet.",
        "deleting-backlinks-warning": "<strong>Advarsel:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Andre sider]] henviser til eller inkluderer den side, du er ved at slette.",
        "rollback": "Fjern redigeringer",
+       "rollback-confirmation-confirm": "Bekræft venligst:",
+       "rollback-confirmation-yes": "Tilbagerul",
+       "rollback-confirmation-no": "Fortryd",
        "rollbacklink": "rul tilbage",
        "rollbacklinkcount": "rul {{PLURAL:$1|en redigering|$1 redigeringer}} tilbage",
        "rollbacklinkcount-morethan": "rul mere end {{PLURAL:$1|en redigering|$1 redigeringer}} tilbage",
        "ipb-change-block": "Forny brugerens blokering med disse indstillinger",
        "ipb-confirm": "Bekræft blokering",
        "ipb-partial": "Delvist",
+       "ipb-partial-help": "Specifikke sider eller navnerum.",
        "ipb-pages-label": "Sider",
        "ipb-namespaces-label": "Navnerum",
        "badipaddress": "IP-adressen/brugernavnet er udformet forkert eller eksistere ikke.",
        "blocklist-userblocks": "Skjul blokeringer af kontoer",
        "blocklist-tempblocks": "Skjul midlertidige blokeringer",
        "blocklist-addressblocks": "Skjul enkel IP blokeringer",
+       "blocklist-type": "Type:",
+       "blocklist-type-opt-all": "Alle",
+       "blocklist-type-opt-partial": "Delvis",
        "blocklist-rangeblocks": "Skjul blokeringsklasser",
        "blocklist-timestamp": "Tidsstempel",
        "blocklist-target": "Mål",
        "allmessagesdefault": "Standardtekst",
        "allmessagescurrent": "Nuværende tekst",
        "allmessagestext": "Dette er en liste med alle systembeskeder i MediaWiki-navnerummet.\nBesøg venligst [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki-lokalisering] og [https://translatewiki.net translatewiki.net] hvis du ønsker at bidrage til den generelle lokalisering (oversættelse og andre lokale tilpasninger) af MediaWiki.",
-       "allmessagesnotsupportedDB": "{{ns:special}}:AllMessages ikke understøttet fordi wgUseDatabaseMessages er slået fra.",
+       "allmessages-not-supported-database": "{{ns:special}}:AllMessages ikke understøttet fordi wgUseDatabaseMessages er slået fra.",
        "allmessages-filter-legend": "Filtrér",
        "allmessages-filter": "Filtrér efter tilpasningsstatus:",
        "allmessages-filter-unmodified": "Uændret",
        "autosumm-replace": "Erstatter sidens indhold med \"$1\"",
        "autoredircomment": "Omdirigering til [[$1]] oprettet",
        "autosumm-removed-redirect": "Fjernede omdirigering til [[$1]]",
+       "autosumm-changed-redirect-target": "Ændrede omdirigeringsmål fra [[$1]] til [[$2]]",
        "autosumm-new": "Oprettede siden med \"$1\"",
        "autosumm-newblank": "Oprettede tom side",
        "lag-warn-normal": "Ændringer som er nyere end {{PLURAL:$1|et sekund|$1 sekunder}}, vises muligvis ikke i denne liste.",
        "watchlistedit-normal-done": "{{PLURAL:$1|1 side|$1 sider}} er fjernet fra din overvågningsliste:",
        "watchlistedit-raw-title": "Direkte redigering af overvågningsliste",
        "watchlistedit-raw-legend": "Direkte redigering af overvågningsliste",
-       "watchlistedit-raw-explain": "Siderne i din overvågningsliste er vist nedenfor, og kan ændres ved at tilføje og fjerne fra listen;\nen side per linie\nNår du er færdig, klik \"{{int:Watchlistedit-raw-submit}}\".\nDu kan også [[Special:EditWatchlist|bruge standard editoren]].",
+       "watchlistedit-raw-explain": "Siderne i din overvågningsliste er vist nedenfor, og kan ændres ved at tilføje og fjerne fra listen;\nen side per linje\nNår du er færdig, klik \"{{int:Watchlistedit-raw-submit}}\".\nDu kan også [[Special:EditWatchlist|bruge standard-editoren]].",
        "watchlistedit-raw-titles": "Sider:",
        "watchlistedit-raw-submit": "Opdater overvågningsliste",
        "watchlistedit-raw-done": "Din overvågningsliste blev opdateret.",
        "tag-list-wrapper": "[[Special:Tags|{{PLURAL:$1|Tag|Tags}}]]: $2",
        "tag-mw-new-redirect": "Ny omdirigering",
        "tag-mw-removed-redirect": "Fjernede omdirigering",
-       "tag-mw-changed-redirect-target": "Omdigeringsmål ændret",
+       "tag-mw-changed-redirect-target": "Omdirigeringsmål ændret",
        "tag-mw-blank": "Sidetømning",
        "tag-mw-blank-description": "Redigeringer som tømmer en side",
        "tag-mw-replace": "Erstattet",
        "dberr-again": "Prøv at vente et par minutter og opdater så siden igen.",
        "dberr-info": "(Kan ikke tilgå databasen: $1)",
        "dberr-info-hidden": "(Kan ikke tilgå databasen)",
-       "htmlform-invalid-input": "Det er problemer med dine angivelser",
+       "htmlform-invalid-input": "Der er problemer med de angivne data.",
        "htmlform-select-badoption": "Den angivne værdi er ikke gyldigt valg.",
        "htmlform-int-invalid": "Den angivne værdi er ikke et heltal.",
        "htmlform-float-invalid": "Den angivne værdi er ikke et tal.",
        "authpage-cannot-login": "Kunne ikke starte login.",
        "cannotauth-not-allowed-title": "Adgang nægtet",
        "cannotauth-not-allowed": "Du har ikke tilladelse til at bruge denne side",
+       "changecredentials": "Skift adgangskode",
+       "changecredentials-submit": "Skift adgangskode",
        "removecredentials": "Fjern akkreditiver",
        "removecredentials-submit": "Fjern akkreditiver",
        "removecredentials-invalidsubpage": "$1 er ikke en gyldig type for akkreditiver.",
index 4da907f..02be168 100644 (file)
        "zip-bad": "Die Datei ist beschädigt oder eine aus anderweitigen Gründen nicht lesbare ZIP-Datei.\nSie kann daher keiner ordnungsgemässen Sicherheitsüberprüfung unterzogen werden.",
        "zip-unsupported": "Diese ZIP-Datei verfügt über Komprimierungseigenschaften, die nicht von MediaWiki unterstützt werden.\nSie kann daher keiner ordnungsgemässen Sicherheitsüberprüfung unterzogen werden.",
        "img-auth-badtitle": "Aus «$1» kann kein gültiger Titel erstellt werden.",
-       "img-auth-nologinnWL": "Du bist nicht angemeldet und «$1» ist nicht in der weissen Liste.",
        "img-auth-nofile": "Datei «$1» existiert nicht.",
        "img-auth-isdir": "Du versuchst, auf ein Verzeichnis «$1» zuzugreifen.\nNur Dateizugriff ist erlaubt.",
        "img-auth-streaming": "Lade «$1».",
index 5f1e48f..52813b9 100644 (file)
        "upload-dialog-button-cancel": "Abbrechen",
        "uploadstash-badtoken": "Das Entfernen der vorab gespeicherten Dateien war erfolglos, vielleicht weil Ihre Sitzungsdaten abgelaufen sind. Bitte versuchen Sie es erneut.",
        "img-auth-nopathinfo": "PATH_INFO fehlt.\nIhr Server ist nicht dafür eingerichtet, diese Information weiterzugeben.\nSie könnte CGI-gestützt sein und kann daher img_auth nicht ermöglichen.\nSiehe auch http://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
-       "img-auth-nologinnWL": "Sie sind nicht angemeldet und „$1“ ist nicht in der weißen Liste.",
        "img-auth-isdir": "Sie versuchen, auf ein Verzeichnis „$1“ zuzugreifen.\nNur Dateizugriff ist erlaubt.",
        "upload-curl-error6-text": "Die angegebene URL ist nicht erreichbar. Prüfen Sie sowohl die URL auf Fehler als auch den Online-Status der Seite.",
        "upload-curl-error28-text": "Die Seite braucht zu lange, um zu antworten. Prüfen Sie, ob die Seite online ist, warten Sie einen kurzen Moment und versuchen Sie es dann erneut. Es kann sinnvoll sein, es zu einem anderen Zeitpunkt erneut zu versuchen.",
index f23fc0e..0c15d1f 100644 (file)
@@ -95,7 +95,9 @@
                        "ToBeFree",
                        "PerfektesChaos",
                        "Kurt Jansson",
-                       "McDutchie"
+                       "McDutchie",
+                       "Johanna Strodt (WMDE)",
+                       "Andi-3"
                ]
        },
        "tog-underline": "Links unterstreichen:",
        "tog-hidepatrolled": "Kontrollierte Änderungen in den „Letzten Änderungen“ ausblenden",
        "tog-newpageshidepatrolled": "Kontrollierte Seiten bei den „Neuen Seiten“ ausblenden",
        "tog-hidecategorization": "Kategorisierungen von Seiten ausblenden",
-       "tog-extendwatchlist": "Alle Änderungen in der Beobachtungsliste anzeigen, nicht nur die aktuellsten",
+       "tog-extendwatchlist": "Alle Änderungen in der Beobachtungsliste anzeigen, nicht nur die letzten",
        "tog-usenewrc": "Änderungen auf „Letzte Änderungen“ und der Beobachtungsliste nach Seite gruppieren",
        "tog-numberheadings": "Überschriften automatisch nummerieren",
        "tog-editondblclick": "Seiten mit Doppelklick bearbeiten",
        "tog-norollbackdiff": "Unterschiede nach dem Zurücksetzen nicht anzeigen",
        "tog-useeditwarning": "Warnen, sofern eine zur Bearbeitung geöffnete Seite verlassen wird, die nicht gespeicherte Änderungen enthält",
        "tog-prefershttps": "Immer eine sichere Verbindung benutzen, solange ich angemeldet bin",
-       "tog-showrollbackconfirmation": "Beim Klicken auf einen Zurücksetzen-Link eine Bestätigungsaufforderung anzeigen",
+       "tog-showrollbackconfirmation": "Bei Klick auf „kommentarlos zurücksetzen“ eine Sicherheitsabfrage anzeigen",
        "underline-always": "immer",
        "underline-never": "nie",
        "underline-default": "abhängig von der Benutzeroberfläche oder Browsereinstellung",
        "virus-badscanner": "Fehlerhafte Konfiguration: unbekannter Virenscanner: <em>$1</em>",
        "virus-scanfailed": "Scan fehlgeschlagen (Code $1)",
        "virus-unknownscanner": "Unbekannter Virenscanner:",
-       "logouttext": "<strong>Du bist nun abgemeldet.</strong>\n\nBeachte, dass einige Seiten noch anzeigen können, dass du angemeldet bist, solange du nicht deinen Browsercache geleert hast.",
+       "logouttext": "<strong>Du bist nun abgemeldet.</strong>\n\nBeachte, dass einige Seiten noch anzeigen können, dass du angemeldet wärst, solange du nicht deinen Browsercache leerst.",
+       "logging-out-notify": "Du wurdest abgemeldet. Bitte warten.",
+       "logout-failed": "Abmeldung derzeit nicht möglich: $1",
        "cannotlogoutnow-title": "Abmeldung nicht erfolgreich",
        "cannotlogoutnow-text": "Eine Abmeldung ist mit Verwendung von $1 nicht möglich.",
        "welcomeuser": "Willkommen, $1!",
        "previewnote": "'''Dies ist nur eine Vorschau.'''\nDie Seite wurde noch nicht gespeichert!",
        "continue-editing": "Zum Bearbeitungsfeld gehen",
        "previewconflict": "Diese Vorschau gibt den Inhalt des oberen Textfeldes wieder. So wird die Seite aussehen, wenn du jetzt speicherst.",
-       "session_fail_preview": "Entschuldigung! Wir konnten deine Bearbeitung nicht verarbeiten, da Sitzungsdaten verloren gegangen sind.\n\nDu wurdest eventuell abgemeldet. <strong>Bitte verifiziere, dass du noch angemeldet bist und versuche es erneut</strong>.\nFalls dies nicht funktioniert, versuche dich [[Special:UserLogout|abzumelden]] und anschließend wieder anzumelden und überprüfe, ob dein Browser Cookies von dieser Website akzeptiert.",
+       "session_fail_preview": "Entschuldigung! Wir konnten deine Bearbeitung nicht verarbeiten, da Sitzungsdaten verloren gegangen sind.\n\nDu wurdest eventuell abgemeldet. <strong>Bitte stelle sicher, dass du noch angemeldet bist, und versuche es erneut</strong>.\nFalls dies nicht funktioniert, versuche dich [[Special:UserLogout|abzumelden]] und anschließend wieder anzumelden und überprüfe, ob dein Browser Cookies von dieser Website akzeptiert.",
        "session_fail_preview_html": "Deine Bearbeitung konnte nicht gespeichert werden, da Sitzungsdaten verloren gegangen sind.\n\n<em>Da in {{SITENAME}} das Speichern von reinem HTML aktiviert ist, wurde die Vorschau ausgeblendet, um JavaScript-Attacken vorzubeugen.</em>\n\n<strong>Bitte versuche es erneut, indem du unter der folgenden Textvorschau nochmals auf „Seite speichern“ klickst.</strong>\nSollte das Problem bestehen bleiben, [[Special:UserLogout|melde dich ab]] und danach wieder an. Überprüfe, ob dein Browser Cookies von dieser Website akzeptiert.",
        "token_suffix_mismatch": "'''Deine Bearbeitung wurde zurückgewiesen, da dein Browser Zeichen im Bearbeiten-Token verstümmelt hat.\nEine Speicherung kann den Seiteninhalt zerstören. Dies geschieht bisweilen durch die Benutzung eines anonymen Proxy-Dienstes, der fehlerhaft arbeitet.'''",
        "edit_form_incomplete": "'''Der Inhalt des Bearbeitungsformulars hat den Server nicht vollständig erreicht. Bitte prüfe deine Bearbeitungen auf Vollständigkeit und versuche es erneut.'''",
        "templatesusedsection": "{{PLURAL:$1|Die folgende Vorlage wird|Folgende Vorlagen werden}} in diesem Abschnitt verwendet:",
        "template-protected": "(schreibgeschützt)",
        "template-semiprotected": "(schreibgeschützt für unangemeldete und neue Benutzer)",
-       "hiddencategories": "Diese Seite ist in {{PLURAL:$1|1 versteckter Kategorie|$1 versteckten Kategorien}} enthalten:",
+       "hiddencategories": "Diese Seite ist in {{PLURAL:$1|einer versteckten Kategorie|$1 versteckten Kategorien}} enthalten:",
        "edittools": "<!-- Dieser Text wird unter dem „Bearbeiten“-Formular sowie dem „Hochladen“-Formular angezeigt. -->",
        "nocreatetext": "Auf {{SITENAME}} wurde das Erstellen neuer Seiten eingeschränkt. Du kannst bestehende Seiten ändern oder dich [[Special:UserLogin|anmelden]].",
        "nocreate-loggedin": "Du hast nicht die erforderliche Berechtigung, um neue Seiten erstellen zu können.",
        "page_first": "Anfang",
        "page_last": "Ende",
        "histlegend": "Zur Anzeige der Änderungen einfach die zu vergleichenden Versionen auswählen und die Schaltfläche „{{int:compareselectedversions}}“ klicken.<br />\n* ({{int:cur}}) = Unterschied zur aktuellen Version, ({{int:last}}) = Unterschied zur vorherigen Version\n* Uhrzeit/Datum = Version zu dieser Zeit, Benutzername/IP-Adresse des Bearbeiters, {{int:minoreditletter}} = Kleine Änderung",
-       "history-fieldset-title": "Nach Versionen suchen",
+       "history-fieldset-title": "Versionen filtern",
        "history-show-deleted": "Nur gelöschte Versionen zeigen",
        "histfirst": "älteste",
        "histlast": "neueste",
        "historysize": "({{PLURAL:$1|1 Byte|$1 Bytes}})",
-       "historyempty": "(leer)",
+       "historyempty": "leer",
        "history-feed-title": "Versionsgeschichte",
        "history-feed-description": "Versionsgeschichte dieser Seite in {{SITENAME}}",
        "history-feed-item-nocomment": "$1 am $3 um $4 Uhr",
        "right-reupload-own": "Überschreiben einer zuvor selbst hochgeladenen Datei",
        "right-reupload-shared": "Lokales Überschreiben einer in einem gemeinsam genutzten Repositorium vorhandenen Datei",
        "right-upload_by_url": "Dateien von einer URL-Adresse hochladen",
-       "right-purge": "Seitencache leeren ohne Rückfrage",
+       "right-purge": "Seitencache leeren",
        "right-autoconfirmed": "Keine Beschränkung durch IP-basierte Limits",
        "right-bot": "Behandlung als automatischer Prozess",
        "right-nominornewtalk": "Kleine Bearbeitungen an Diskussionsseiten führen zu keiner „Neue Nachrichten“-Anzeige",
        "action-changetags": "beliebige Markierungen zu einzelnen Versionen und Logbucheinträgen hinzuzufügen und zu entfernen",
        "action-deletechangetags": "Markierungen aus der Datenbank zu löschen",
        "action-purge": "den Cache dieser Seite zu leeren",
+       "action-apihighlimits": "höhere Beschränkungen in API-Anfragen zu verwenden",
+       "action-autoconfirmed": "nicht von IP-basierten Limits betroffen zu sein",
+       "action-bigdelete": "Seiten mit großer Versionsgeschichte zu löschen",
+       "action-blockemail": "Benutzer am Versenden von E-Mails zu hindern",
+       "action-bot": "als automatischer Prozess behandelt zu werden",
+       "action-editprotected": "Seiten zu bearbeiten, die als „{{int:protect-level-sysop}}“ geschützt sind",
+       "action-editsemiprotected": "Seiten zu bearbeiten, die als „{{int:protect-level-autoconfirmed}}“ geschützt sind",
+       "action-editinterface": "Systemnachrichten und Benutzeroberflächen zu bearbeiten",
+       "action-editusercss": "fremde CSS-Dateien zu bearbeiten",
+       "action-edituserjson": "JSON-Dateien anderer Benutzer zu bearbeiten",
+       "action-edituserjs": "fremde JavaScript-Dateien zu bearbeiten",
+       "action-editsitecss": "wikiweit CSS zu bearbeiten",
+       "action-editsitejson": "wikiweites JSON zu bearbeiten",
+       "action-editsitejs": "wikiweites JavaScript zu bearbeiten",
+       "action-editmyusercss": "eigene Benutzer-CSS-Dateien zu bearbeiten",
+       "action-editmyuserjson": "eigene Benutzer-JSON-Dateien zu bearbeiten",
+       "action-editmyuserjs": "eigene Benutzer-JavaScript-Dateien zu bearbeiten",
+       "action-viewsuppressed": "vor jedem Benutzer versteckte Versionen anzusehen",
+       "action-hideuser": "Benutzernamen zu sperren und zu verbergen",
+       "action-ipblock-exempt": "IP-Sperren, automatische Sperren und Bereichssperren zu umgehen",
+       "action-unblockself": "dich zu entsperren",
+       "action-noratelimit": "nicht von Limits betroffen zu sein",
+       "action-reupload-own": "eine zuvor selbst hochgeladene Datei zu überschreiben",
+       "action-nominornewtalk": "dass kleine Bearbeitungen an Diskussionsseiten nicht die „Neue Nachrichten“-Anzeige auslösen",
+       "action-markbotedits": "schnell zurückgesetzte Bearbeitungen als Bot-Bearbeitung zu markieren",
+       "action-patrolmarks": "Kontrollmarkierungen in den letzten Änderungen anzusehen",
+       "action-override-export-depth": "Seiten einschließlich verlinkter Seiten bis zu einer Tiefe von 5 zu exportieren",
+       "action-suppressredirect": "beim Verschieben die Erstellung einer Weiterleitung zu unterdrücken",
        "nchanges": "$1 {{PLURAL:$1|Änderung|Änderungen}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|seit dem letzten Besuch}}",
        "enhancedrc-history": "Versionsgeschichte",
        "rcfilters-savedqueries-already-saved": "Diese Filter sind bereits gespeichert. Ändere deine Einstellungen, um einen neuen Gespeicherten Filter zu erstellen.",
        "rcfilters-restore-default-filters": "Standardfilter wiederherstellen",
        "rcfilters-clear-all-filters": "Alle Filter löschen",
-       "rcfilters-show-new-changes": "Neueste Änderungen ansehen",
+       "rcfilters-show-new-changes": "Neue Änderungen seit $1 ansehen",
        "rcfilters-search-placeholder": "Änderungen filtern (Menü oder Suche für den Filternamen verwenden)",
        "rcfilters-invalid-filter": "Ungültiger Filter",
        "rcfilters-empty-filter": "Keine aktiven Filter. Es werden alle Beiträge angezeigt.",
        "rcfilters-filter-editsbyself-description": "Deine eigenen Beiträge.",
        "rcfilters-filter-editsbyother-label": "Änderungen von anderen",
        "rcfilters-filter-editsbyother-description": "Alle Änderungen außer deine eigenen.",
-       "rcfilters-filtergroup-userExpLevel": "Benutzeranmeldung und -erfahrung",
+       "rcfilters-filtergroup-user-experience-level": "Benutzeranmeldung und -erfahrung",
        "rcfilters-filter-user-experience-level-registered-label": "Angemeldet",
        "rcfilters-filter-user-experience-level-registered-description": "Angemeldete Autoren.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Unangemeldet",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Der Filter „Kleine Bearbeitungen“ kollidiert mit einem oder mehreren Änderungstypfiltern, da bestimmte Änderungstypen nicht als „klein“ festgelegt werden können. Die kollidierenden Filter sind oben im Bereich der aktiven Filter markiert.",
        "rcfilters-hideminor-conflicts-typeofchange": "Bestimmte Änderungstypen können nicht als „klein“ festgelegt werden, so dass dieser Filter mit den folgenden Änderungstypfiltern kollidiert: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Dieser Änderungstypfilter kollidiert mit dem Filter „Kleine Bearbeitungen“. Bestimmte Änderungstypen können nicht als „klein“ festgelegt werden.",
-       "rcfilters-filtergroup-lastRevision": "Aktuellste Versionen",
+       "rcfilters-filtergroup-lastrevision": "Aktuellste Versionen",
        "rcfilters-filter-lastrevision-label": "Aktuellste Version",
        "rcfilters-filter-lastrevision-description": "Nur die aktuellste Änderung an einer Seite.",
        "rcfilters-filter-previousrevision-label": "Nicht die aktuellste Version",
        "minoreditletter": "K",
        "newpageletter": "N",
        "boteditletter": "B",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|beobachtender|beobachtende}} Benutzer]",
        "rc-change-size": "$1 {{PLURAL:$1|Byte|Bytes}}",
        "rc-change-size-new": "$1 {{PLURAL:$1|Byte|Bytes}} nach der Änderung",
        "newsectionsummary": "Neuer Abschnitt /* $1 */",
        "img-auth-nopathinfo": "Fehlende Pfadinformationen.\nDein Server muss so aufgesetzt sein, dass die Variablen REQUEST_URI und/oder PATH_INFO übergeben werden.\nFalls zutreffend, versuche, $wgUsePathInfo zu aktivieren.\nSiehe https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Der gewünschte Pfad ist nicht im konfigurierten Uploadverzeichnis.",
        "img-auth-badtitle": "Aus „$1“ kann kein gültiger Titel erstellt werden.",
-       "img-auth-nologinnWL": "Du bist nicht angemeldet und „$1“ ist nicht in der weißen Liste.",
        "img-auth-nofile": "Datei „$1“ existiert nicht.",
        "img-auth-isdir": "Du versuchst, auf ein Verzeichnis „$1“ zuzugreifen.\nNur Dateizugriff ist erlaubt.",
        "img-auth-streaming": "Lade „$1“.",
        "unusedimages": "Verwaiste Dateien",
        "wantedcategories": "Gewünschte Kategorien",
        "wantedpages": "Gewünschte Seiten",
-       "wantedpages-summary": "Liste nicht vorhandener Seiten mit den meisten Links auf diese Seiten, ausschließlich solche, die nur Weiterleitungen haben. Für eine Liste nicht vorhandener Seiten mit Weiterleitungen, siehe [[{{#special:BrokenRedirects}}|die Liste defekter Weiterleitungen]].",
+       "wantedpages-summary": "Liste der am häufigsten verlinkten, aber nicht vorhandenen Seiten. Hiervon ausgenommen sind Seiten, die ausschließlich als Ziele defekter Weiterleitungen dienen. Siehe dafür [[{{#special:BrokenRedirects}}|die Liste defekter Weiterleitungen]].",
        "wantedpages-badtitle": "Ungültiger Titel im Ergebnis: $1",
        "wantedfiles": "Gewünschte Dateien",
        "wantedfiletext-cat": "Die folgenden Dateien werden verwendet, sind jedoch nicht vorhanden. Vorhandene Dateien aus fremden Repositorien können dennoch hier aufgelistet sein und werden <del>durchgestrichen</del> dargestellt. Zusätzlich werden Seiten, die nicht vorhandene Dateien enthalten, in die [[:$1]] eingeordnet.",
        "delete-confirm": "Löschen von „$1“",
        "delete-legend": "Löschen",
        "historywarning": "<strong>Achtung:</strong> Die Seite, die du löschen möchtest, hat eine Versionsgeschichte mit {{PLURAL:$1|einer Version|$1 Versionen}}:",
-       "historyaction-submit": "Anzeigen",
+       "historyaction-submit": "Versionen anzeigen",
        "confirmdeletetext": "Du bist dabei, eine Seite mit allen zugehörigen älteren Versionen zu löschen. Bitte bestätige dazu, dass du dir der Konsequenzen bewusst bist, und dass du in Übereinstimmung mit den [[{{MediaWiki:Policy-url}}|Richtlinien]] handelst.",
        "actioncomplete": "Aktion beendet",
        "actionfailed": "Aktion fehlgeschlagen",
        "deleting-backlinks-warning": "<strong>Warnung:</strong> Es verweisen noch [[Special:WhatLinksHere/{{FULLPAGENAME}}|andere Seiten]] auf diese zu löschende Seite oder sie ist noch an anderer Stelle eingebunden.",
        "deleting-subpages-warning": "<strong>Warnung:</strong> Die Seite, die du löschen möchtest, hat [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|eine Unterseite|$1 Unterseiten|51=über 50 Unterseiten}}]].",
        "rollback": "Zurücksetzen der Änderungen",
+       "rollback-confirmation-confirm": "Bitte bestätigen:",
+       "rollback-confirmation-yes": "Zurücksetzen",
+       "rollback-confirmation-no": "Abbrechen",
        "rollbacklink": "Zurücksetzen",
        "rollbacklinkcount": "{{PLURAL:$1|Eine Version|$1 Versionen}} zurücksetzen",
        "rollbacklinkcount-morethan": "Mehr als {{PLURAL:$1|eine Version|$1 Versionen}} zurücksetzen",
        "revertpage": "Änderungen von [[Special:Contributions/$2|$2]] ([[User talk:$2|Diskussion]]) wurden auf die letzte Version von [[User:$1|$1]] zurückgesetzt",
        "revertpage-nouser": "Änderungen von einem versteckten Benutzer rückgängig gemacht und letzte Version von {{GENDER:$1|[[User:$1|$1]]}} wiederhergestellt",
        "rollback-success": "Die Änderungen von {{GENDER:$3|$1}} wurden rückgängig gemacht und die letzte Version von {{GENDER:$4|$2}} wurde wiederhergestellt.",
-       "rollback-success-notify": "Bearbeitungen von $1 rückgängig gemacht;\nzurückgeändert auf die letzte Version von $2. [$3 Änderungen zeigen]",
        "sessionfailure-title": "Sitzungsfehler",
        "sessionfailure": "Es gab ein Problem bei der Übertragung deiner Benutzerdaten.\nDiese Aktion wurde daher sicherheitshalber abgebrochen, um eine falsche Zuordnung deiner Änderungen zu einem anderen Benutzer zu verhindern.\nBitte sende das Formular erneut ab.",
        "changecontentmodel": "Inhaltsmodell einer Seite ändern",
        "mycontris": "Beiträge",
        "anoncontribs": "Beiträge",
        "contribsub2": "Von {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "Für {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "Das Benutzerkonto „$1“ ist nicht vorhanden.",
        "negative-namespace-not-supported": "Namensräume mit negativen Werten werden nicht unterstützt.",
        "nocontribs": "Es wurden keine Benutzerbeiträge mit diesen Kriterien gefunden.",
        "blocklist-userblocks": "Benutzersperren ausblenden",
        "blocklist-tempblocks": "Befristete Sperren ausblenden",
        "blocklist-addressblocks": "Sperren einzelner IP-Adressen ausblenden",
+       "blocklist-type": "Typ:",
+       "blocklist-type-opt-all": "Alle",
+       "blocklist-type-opt-sitewide": "Wikiweit",
+       "blocklist-type-opt-partial": "Teilweise",
        "blocklist-rangeblocks": "Bereichssperren ausblenden",
        "blocklist-timestamp": "Zeitstempel",
        "blocklist-target": "Ziel",
        "blocklist-editing-page": "Seiten",
        "blocklist-editing-ns": "Namensräume",
        "ipblocklist-empty": "Die Liste enthält keine Einträge.",
-       "ipblocklist-no-results": "Die gesuchte IP-Adresse/der Benutzername ist nicht gesperrt.",
+       "ipblocklist-no-results": "Für die angeforderte IP-Adresse/den angeforderten Benutzernamen wurden keine übereinstimmenden Sperren gefunden.",
        "blocklink": "Sperren",
        "unblocklink": "Freigeben",
        "change-blocklink": "Sperre ändern",
+       "empty-username": "(kein Benutzername verfügbar)",
        "contribslink": "Beiträge",
        "emaillink": "E-Mail senden",
        "autoblocker": "Automatische Sperre, da du eine gemeinsame IP-Adresse mit [[User:$1|$1]] benutzt.\nGrund der Benutzersperre: „$2“",
        "allmessagesdefault": "Standardtext",
        "allmessagescurrent": "Aktueller Text",
        "allmessagestext": "Dies ist eine Liste der MediaWiki-Systemtexte.\nGehe auf [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki-Lokalisierung] und [https://translatewiki.net translatewiki.net], wenn du dich an der Übersetzung von MediaWiki beteiligen möchtest.",
-       "allmessagesnotsupportedDB": "Diese Spezialseite steht nicht zur Verfügung, da sie über den Parameter <tt>$wgUseDatabaseMessages</tt> deaktiviert wurde.",
+       "allmessages-not-supported-database": "Diese Spezialseite steht nicht zur Verfügung, da sie über den Parameter <tt>$wgUseDatabaseMessages</tt> deaktiviert wurde.",
        "allmessages-filter-legend": "Filter",
        "allmessages-filter": "Filter für angepassten Zustand:",
        "allmessages-filter-unmodified": "Unverändert",
        "tooltip-watchlistedit-raw-submit": "Beobachtungsliste aktualisieren",
        "tooltip-recreate": "Seite neu erstellen, obwohl sie gelöscht wurde",
        "tooltip-upload": "Hochladen starten",
-       "tooltip-rollback": "Macht alle letzten Änderungen der Seite, die vom gleichen Benutzer vorgenommen worden sind, durch nur einen Klick rückgängig.",
+       "tooltip-rollback": "Macht alle letzten Änderungen der Seite, die vom selben Benutzer vorgenommen worden sind, durch nur einen Klick rückgängig.",
        "tooltip-undo": "Macht lediglich diese eine Änderung rückgängig und zeigt das Resultat in der Vorschau an, damit in der Zusammenfassungszeile eine Begründung angegeben werden kann.",
        "tooltip-preferences-save": "Einstellungen speichern",
        "tooltip-summary": "Gib eine kurze Zusammenfassung ein.",
        "pageinfo-robot-index": "Erlaubt",
        "pageinfo-robot-noindex": "Nicht erlaubt",
        "pageinfo-watchers": "Anzahl der Beobachter dieser Seite",
-       "pageinfo-visiting-watchers": "Anzahl der Beobachter dieser Seite, die die letzten Bearbeitungen besucht haben",
+       "pageinfo-visiting-watchers": "Anzahl der Beobachter dieser Seite, welche die letzten Bearbeitungen besucht haben",
        "pageinfo-few-watchers": "Weniger als {{PLURAL:$1|ein|$1}} Beobachter",
        "pageinfo-few-visiting-watchers": "Es könnte einen beobachtenden Benutzer geben oder nicht, der die letzten Bearbeitungen besucht hat",
        "pageinfo-redirects-name": "Anzahl der Weiterleitungen zu dieser Seite",
        "confirm-unwatch-top": "Diese Seite von der persönlichen Beobachtungsliste entfernen?",
        "confirm-rollback-button": "Okay",
        "confirm-rollback-top": "Bearbeitungen an dieser Seite zurücksetzen?",
+       "confirm-rollback-bottom": "Diese Aktion wird sofort die ausgewählten Änderungen an dieser Seite zurücksetzen.",
        "confirm-mcrrestore-title": "Eine Version wiederherstellen",
        "confirm-mcrundo-title": "Eine Änderung rückgängig machen",
        "mcrundofailed": "Rückgängigmachung fehlgeschlagen",
        "passwordpolicies-policyflag-forcechange": "muss bei der Anmeldung geändert werden",
        "passwordpolicies-policyflag-suggestchangeonlogin": "Änderung bei der Anmeldung vorschlagen",
        "easydeflate-invaliddeflate": "Der angegebene Inhalt ist nicht ordnungsgemäß komprimiert",
-       "unprotected-js": "Aus Sicherheitsgründen kann JavaScript-Code nicht mehr von ungeschützten Seiten geladen werden. Erstelle die JavaScript-Seite bitte ausschließlich im Namensraum „MediaWiki“ oder als Benutzerunterseite."
+       "unprotected-js": "Aus Sicherheitsgründen kann JavaScript-Code nicht mehr von ungeschützten Seiten geladen werden. Erstelle die JavaScript-Seite bitte ausschließlich im Namensraum „MediaWiki“ oder als Benutzerunterseite.",
+       "userlogout-continue": "Falls du dich abmelden möchtest, [$1 fahre bitte auf der Abmeldeseite fort].",
+       "userlogout-sessionerror": "Abmeldung aufgrund eines Sitzungsfehlers fehlgeschlagen. Bitte [$1 erneut versuchen]."
 }
index 8df2180..6d425cf 100644 (file)
        "edithelp": "Peştdariya vurnayışi",
        "helppage-top-gethelp": "Peşti",
        "mainpage": "Perra Seri",
-       "mainpage-description": "Perra seri",
+       "mainpage-description": "Pela seri",
        "policy-url": "Project:Terzê hereketi",
        "portal": "Portalê cemati",
        "portal-url": "Project:Portalê cemati",
        "badaccess-groups": "No fealiyeto ke şıma waşt, tenya karberanê {{PLURAL:$2|grubi|gruban ra yewi}} rê akerdeyo: $1.",
        "versionrequired": "No $1 MediaWiki lazımo",
        "versionrequiredtext": "Gırweynayışê ena perre rê gani versiyonê $1ê MediaWiki bo. \n[[Special:Version|Versiyonê perre]] bıvêne.",
-       "ok": "Temam",
+       "ok": "TEMAM",
        "pagetitle": "$1 – {{SITENAME}}",
        "pagetitle-view-mainpage": "{{SITENAME}}",
        "backlinksubtitle": "← $1",
        "showtoc": "bımocne",
        "hidetoc": "bınımne",
        "collapsible-collapse": "Teng ke",
-       "collapsible-expand": "Hira ke",
+       "collapsible-expand": "Hera kerê",
        "confirmable-confirm": "{{GENDER:$1|Şıma}} pêbawerê?",
        "confirmable-yes": "Eya",
        "confirmable-no": "Nê",
        "thisisdeleted": "Bıvêne ya zi $1 peyser biya?",
        "viewdeleted": "$1 bıvin?",
        "restorelink": "{{PLURAL:$1|jew vurnayış besteriya|$1 vurnayışi besteriyaye}}",
-       "feedlinks": "Warikerdış:",
+       "feedlinks": "Weyiyekerdış:",
        "feed-invalid": "Qeydey cıresnayışê  beğşi nêvêreno.",
        "feed-unavailable": "Cıresnayışê şebekey çıniyê",
        "site-rss-feed": "$1 Cıresnayışê RSSi",
        "nstab-template": "Şablon",
        "nstab-help": "Perra pasti",
        "nstab-category": "Kategoriye",
-       "mainpage-nstab": "Perra seri",
+       "mainpage-nstab": "Pela seri",
        "nosuchaction": "Fealiyeto wınasi çıniyo",
        "nosuchactiontext": "URL ra kar qebul nêbı.\nŞıma belka URL şaş nuşt, ya zi gıreyi şaş ra ameyi.\nKeyepelê {{SITENAME}} eşkeno xeta eşkera bıkero.",
        "nosuchspecialpage": "Pela hısusiya wınasiyên çıniya.",
        "userlogin-loggedin": "Tı xora namey {{GENDER:$1|$1}} ra kewtê/kewtay cı.\nFormê cêrêni bıgureyne ke namey karberio bin ra cı kewê.",
        "userlogin-reauth": "Eger ke {{GENDER:$1|$1}} şımayê se xo araşt kerdışirê fına ronıştış akerê.",
        "userlogin-createanother": "Zewbi hesab vıraz",
-       "createacct-emailrequired": "Adresa e-postey",
+       "createacct-emailrequired": "Adresa e-posteyi",
        "createacct-emailoptional": "Adresa e-postey (mecburi niya)",
        "createacct-email-ph": "Adresa e-posteyê xo cıkewe",
        "createacct-another-email-ph": "Adresa e-posta de fi",
        "acct_creation_throttle_hit": "Yew ten IP adresê şıma xebıtnayo u kewto no wiki, $2roco peyin de {{PLURAL:$1|1 hesabi|$1 hesaban}} vıraşto.\nxulasa ney kesê ke IP adresê şıma xebıtneni hini nêeşkeni ney ra zêdêr hesab akeri.",
        "emailauthenticated": "E-postay şıma $2 sehat $3 dı biya araşt",
        "emailnotauthenticated": "Adresa e-pota da şıma qebul nébiya.\nQandé céréna şımaré teba do nérışiyo.",
-       "noemailprefs": "Hesab biyo a.",
+       "noemailprefs": "Seba gurenayışê nê xısusiyetan yew adresa e-posteyi cı kerê.",
        "emailconfirmlink": "E-postayê xo araşt kerê",
        "invalidemailaddress": "No format de nuştışê e-postayi qebul nêbeno. Yew formato meqbul de adresê e-posta bınuse ya zi veng bıverde.",
        "cannotchangeemail": "E-postay hesabi ena wiki sera nêvurneyêno.",
        "passwordreset-emaildisabled": "Na wikid hısusiyeté e-posta dewera vıcyayé",
        "passwordreset-username": "Namey karberi:",
        "passwordreset-domain": "Domain:",
-       "passwordreset-email": "Adresa e-postey:",
+       "passwordreset-email": "Adresa e-posteyi:",
        "passwordreset-emailtitle": "Hesab timarê {{SITENAME}}",
        "passwordreset-emailtext-ip": "Jeweri, {{SITENAME}} ra (ma heta şımayê, $1 IP adresi ra) ($4) teferuatê hesabdê şıma  va wa biyaro xo viri. Karbero ke cêrdeyo {{PLURAL:$3|hesaba|eno hesaba}} ena e-posta adresiya aleqey cı esto:\n\n$2\n\n{{PLURAL:$3|ena parola idaretena|ena parola idareten}} {{PLURAL:$5|jew roc|$5  roca}}rêya.\nEna parolaya deqewe de u xorê ju parolaya newi bıweçine. Parolaya şıma emaya şıma viri se  yana  ena e-posta şıma nê weştase u şıma qayıl niye parolaya xo bıvurnese, ena mesacer peygoş bıkerê.",
        "passwordreset-emailtext-user": "$1 enê karberi, {{SITENAME}}  ra ($4) teferuatê hesab dê şıma  va wa biyaro xo viri. Karbero ke cêrdeyo {{PLURAL:$3|hesaba|eno hesaba}} ena e-posta adresiya aleqey cı esto:\n\n$2\n\n{{PLURAL:$3|ena parola idaretena|ena parola idareten}} {{PLURAL:$5|jew roc|$5  roca}}rêya.\nEna parolaya deqewe de u xorê ju parolaya newi bıweçine. Parolaya şıma emaya şıma viri se  yana  ena e-posta şıma nê weştase u şıma qayıl niye parolaya xo bıvurnese, ena mesacer peygoş bıkerê.",
        "watchthis": "Na pele de seyr ke",
        "savearticle": "Pele qeyd ke",
        "savechanges": "Vurnayışan qeyd ke",
-       "publishpage": "Riperri bare ke",
-       "publishchanges": "Vırnayışan qeyd ke",
+       "publishpage": "Pele qeyd ke",
+       "publishchanges": "Vurnayışan qeyd ke",
        "savearticle-start": "Pele qeyd ke...",
        "savechanges-start": "Vurnayışan qeyd ke...",
        "publishpage-start": "Pele weşane...",
        "newarticle": "(Newe)",
        "newarticletext": "To yew gıre tıkna be ra yew pela ke hewna çıniya.\nSeba afernayışê pele ra, qutiya metnê cêrêni bıgurene (seba melumati qaytê [$1 pela peşti] ke).\nEke be ğeletine ameya tiya, wa gocega <strong>peyser</strong>i programê xo de bıtıkne.",
        "anontalkpagetext": "----''Na pele, pela karberana ke hesab anêkerdo ya zi yê karberana ke hesab kerdo a, labelê be hesabê xo ra nêkewtê cı.'' \nNê sebeb ra adresa ma IPyi xebetnenime û nê adresanê IPyi her kes nêşeno bıvêno. Eke şıma qayil niyê wına bo, xo rê [[Special:CreateAccount|yew hesab vırazê]] ya zi [[Special:UserLogin|hesab akerê]].",
-       "noarticletext": "Ena perrer de hewna theba çıni yo.\nTı şenê zerreyê pelanê binan de [[Special:Search/{{PAGENAME}}|qandê  sernameyê ena pele cı geyre]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} qeydan miyan de cı geyre],\nya zi [{{fullurl:{{FULLPAGENAME}}|action=edit}} ena pele vıraze]</span>.{{MediaWiki mesaca pera newi}}",
+       "noarticletext": "Ena pele de hewna theba çıniyo.\nTı şenê zerreyê pelanê binan de [[Special:Search/{{PAGENAME}}|qandê sernameyê ena pele cı geyre]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} qeydan miyan de cı geyre],\nya zi [{{fullurl:{{FULLPAGENAME}}|action=edit}} ena pele vıraze]</span>.",
        "noarticletext-nopermission": "Ena pele de hewna theba çıniyo.\nTı şenay zerreyê pelanê binan de [[Special:Search/{{PAGENAME}}|seba sernameyê na pele cı geyre]], ya zi <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} qeydan miyan de cı geyre]</span>, ema destur çıniyo ke na pele vırazê.",
        "missing-revision": "Rewizyonê name dê pela da #$1 \"{{FULLPAGENAME}}\" dı çıniyo.\n\nNo normal de tarix dê pelanê besterneyan dı ena xırabin asena.\nDetayê besternayışi [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} tiya dı] aseno.",
        "userpage-userdoesnotexist": "Hesabê karberi \"<nowiki>$1</nowiki>\" qeyd nêbiyo.\nKerem ke, tı ke wazenay na pele bafernê/bıvurnê, qontrol ke.",
        "template-protected": "(şeveknaye)",
        "template-semiprotected": "(nime staryayış)",
        "hiddencategories": "Ena per de {{PLURAL:$1|1 kategoriyo nımıte|$1 kategoriyê nımıtey}} muhtewa benê:",
-       "edittools": "<div id=\"specialcharss\" class=\"toccolours specialchars\" style=\"margin-top:.5em; padding: .3em .5em; font-size: 100%; color:#aaa; text-align:left;\" title=\"{{int:bw-edittools-tooltip}}\">\n<p class=\"specialbasic\" id=\"Standard\">\n'''{{int:bw-edittools-lead-in}}''' \n<charinsert>Á á É é Í í Ó ó Ú ú Ý ý</charinsert> –\n<charinsert>À à È è Ì ì Ò ò Ù ù </charinsert> –\n<charinsert> â Ê ê Î î Ô ô Û û </charinsert> –\n<charinsert>Ä ä Ë ë Ï ï Ö ö Ü ü Ÿ ÿ</charinsert> –\n<charinsert>Æ æ Ø ø Œ œ ẞ ß </charinsert> –\n<charinsert>Å å Ů ů </charinsert> –\n<charinsert>àã Ẽ ẽ ɛ̃ Ĩ ĩ Ñ ñ Õ õ ɔ̃ Ũ ũ </charinsert> –\n<charinsert>Рð Þ þ </charinsert> –\n<charinsert>Ç ç Ģ ģ Ķ ķ Ļ ļ Ņ ņ Ŗ ŗ Ş ş Ţ ţ </charinsert> –\n<charinsert>Ć ć Ĺ ĺ Ń ń Ŕ ŕ Ś ś Ý ý Ź ź </charinsert> –\n<charinsert>Č č Ď ď Ľ ľ Ň ň Ř ř Š š Ť ť Ž ž </charinsert> –\n<charinsert>Ǎ ǎ Ě ě Ǐ ǐ Ǒ ǒ Ǔ ǔ </charinsert> –\n<charinsert>Ā ā Ē ē Ī ī Ō ō Ū ū </charinsert> –\n<charinsert>ǖ ǘ ǚ ǜ </charinsert> –\n<charinsert>Ĉ ĉ Ĝ ĝ Ĥ ĥ Ĵ ĵ Ŝ ŝ Ŵ ŵ Ŷ ŷ </charinsert> –\n<charinsert>Ă ă Ğ ğ Ŭ ŭ </charinsert> –\n<charinsert>Ċ ċ Ė ė Ġ ġ Għ għ İ ı Ż ż </charinsert> –\n<charinsert>Ą ą Ę ę Į į Ų ų </charinsert> –\n<charinsert>Ő ő Ű ű </charinsert> –\n<charinsert>Đ đ Ħ ħ Ł ł Ŀ ŀ </charinsert> –\n<charinsert>Ɖ ɖ Ɛ ɛ Ƒ ƒ Ɣ ɣ Ŋ ŋ Ɔ ɔ Ʋ ʋ </charinsert> -\n<charinsert>Ə ə </charinsert> –\n<charinsert>– — ’</charinsert> –\n<charinsert>~ | ° ¹ ² ³ ⅛ ¼ ⅓ ⅜ ½ ⅝ ¾ ⅔ ⅞ € $ ¥ £ † × ← → ↔ ↑ ± ≠ © ® ™ ‰ «+» ‹+› „+“ „+” ‚+‘ ¡ ¿ …</charinsert> –\n<charinsert>&amp;nbsp; &nbsp; [[Category:+]] #REDIRECT[[+]] {{msg-mw|+|notext=1}} &#33;!FUZZY!! ~~~~  &lt;nowiki>+</nowiki></charinsert>\n<charinsert>ڈ ڑ ٹ </charinsert>\n<charinsert>ټ څ ځ ډ ړ ږ ښ ڼ ؤ ي ې ۍ ئ </charinsert>\n<charinsert>{{{+}}} {{+}} {{subst:+}} <noinclude>+</noinclude></charinsert>\n<charinsert>&lt;!--&nbsp;+&nbsp;--> &lt;br&nbsp;/></charinsert>\n</p></div>",
+       "edittools": "<!-- Beno ke no metın bınê formanê vurnayışi û barkerdışi de bımocniyo. -->",
        "edittools-upload": "-",
        "nocreatetext": "{{SITENAME}}, Perrê newey vıraştış rê destur çıniyo.\nŞıma şenê tepeya şorê u eke şıma qeydbiyayey [[Special:UserLogin|şıma şenê yew hesab akerê]], eke şıma niyê [[Special:UserLogin|şıma şenê qeyd bıbê]].",
        "nocreate-loggedin": "Desturê şıma çıniyo ke pelanê neweyan vırazê.",
        "viewpagelogs": "Qeydanê na pele bımocne",
        "nohistory": "Verorê vurnayışanê na perer çıni yo.",
        "currentrev": "Çımraviyarnayışo rocane",
-       "currentrev-asof": "$1 ra tepeya çım ra viyarnayışê cı'yo peyên",
+       "currentrev-asof": "Çımraviyarnayışê $1iyo peyên",
        "revisionasof": "Çımraviyarnayışê $1",
        "revision-info": "Vurnayışo ke $1 de terefê {{GENDER:$6|$2}}$7 ra biyo",
        "previousrevision": "← Çımraviyarnayışo kıhanêr",
        "currentrevisionlink": "Tewr halê peyn",
        "cur": "ferq",
        "next": "bahdoyên",
-       "last": "peyên",
+       "last": "verên",
        "page_first": "verên",
        "page_last": "peyên",
        "histlegend": "Ferqê weçinayışi: Qutiya versiyonan qandé  têversanayış işaret ke u dest be ''enter''i ya zi gocega cêrêne rone.<br />\nCetwel: <strong>({{int:ferq}})</strong> = ferqê versiyonê peyêni, <strong>({{int:peyên}})</strong> = ferqê versiyonê verêni, <strong>{{int:q}}</strong> = vırnayışo werdiyo.",
-       "history-fieldset-title": "Çım ra viyarnayışan cı geyre",
+       "history-fieldset-title": "Çımraviyarnayışan parzûn ke",
        "history-show-deleted": "Tenya çımraviyarnayışanê esterıteyan bımocne",
        "histfirst": "Verênêr",
        "histlast": "Peyênêr",
        "historysize": "({{PLURAL:$1|1 bayt|$1 bayti}})",
-       "historyempty": "(veng)",
+       "historyempty": "veng",
        "history-feed-title": "Tarixê çımraviyarnayışi",
        "history-feed-description": "Wiki de tarixê çım ra viyarnayışë na perer",
        "history-feed-item-nocomment": "$1 miyanê $2i de",
        "prevn": "{{PLURAL:$1|$1}} verên",
        "nextn": "{{PLURAL:$1|$1}} peyên",
        "prev-page": "Perra verêne",
-       "next-page": "pela peyco",
+       "next-page": "pela bahdoyêne",
        "prevn-title": "$1o verên  {{PLURAL:$1|netice|neticeyan}}",
        "nextn-title": "$1o ke yeno {{PLURAL:$1|netice|neticey}}",
        "shown-title": "Her pele sero $1 {{PLURAL:$1|netici|netica}} bımocne",
        "searchprofile-articles": "Pelê zerreki",
        "searchprofile-images": "Multimedya",
        "searchprofile-everything": "Her çi",
-       "searchprofile-advanced": "Hirayên",
+       "searchprofile-advanced": "Herayên",
        "searchprofile-articles-tooltip": "$1 de cı geyre",
        "searchprofile-images-tooltip": "Dosya cı geyre",
        "searchprofile-everything-tooltip": "Tedeesteyan hemine cı geyre (pelanê werênayışi zi tey)",
        "prefs-misc": "ê bini",
        "prefs-resetpass": "Parola bıvurne",
        "prefs-changeemail": "E-postay bıvurne ya zi wedarne",
-       "prefs-setemail": "E-posta adresiyê xo saz kerê",
+       "prefs-setemail": "Adresa eposteyi cı kerê",
        "prefs-email": "Tercihê e-maili",
        "prefs-rendering": "Asayış",
        "saveprefs": "Qeyd ke",
        "email-blacklist-label": "Wa nê karberi mı rê mesac nêrışê:",
        "prefs-searchoptions": "Cı geyre",
        "prefs-namespaces": "Heruna nameyan",
-       "default": "qısur",
+       "default": "hesabiyaye",
        "prefs-files": "Dosyeyi",
        "prefs-custom-css": "CSSê xasi",
        "prefs-custom-json": "JSONo xısusi",
        "prefs-common-config": "CSS/JSON/JavaScripto ke seba heme cildan rê vıla biyo:",
        "prefs-reset-intro": "ena pele de şıma tercihanê xo şenê bıçarnê be tercihanê keyepelê ke verê coy eyar biy.\nNa game tepeya nêerziyena.",
        "prefs-emailconfirm-label": "Tesdiqiya E-posta:",
-       "youremail": "E-posta:",
+       "youremail": "E-poste:",
        "username": "{{GENDER:$1|Namey karberi}}:",
        "prefs-memberingroups": "{{GENDER:$2|Ezayê}} {{PLURAL:$1|grube|gruban}}:",
        "prefs-memberingroups-type": "$1",
        "group-membership-link-with-expiry": "$1 (heta $2)",
        "prefs-registration": "Wextê qeydbiyayışi",
        "prefs-registration-date-time": "$1",
-       "yourrealname": "Nameyo raştay",
+       "yourrealname": "Nameyo raştıkên:",
        "yourlanguage": "Zıwan:",
        "yourvariant": "Varyante miyandê zuwani:",
        "prefs-help-variant": "Zerrey ena viki mocnayışi rê varyant yana ortografi re şıre tercihan dê xo.",
        "prefs-help-signature": "Mışewreyê ke pelanê werênayışi derê, gani be \"<nowiki>~~~~</nowiki>\" ra imza bıbê, no bahdo beno çerxê imza û wadeyê zemani.",
        "badsig": "Îmzayê tu raşt niyo.\nEtiketê HTMLî kontrol bike.",
        "badsiglength": "İmzaya şıma zaf derga.\nA gani be $1 {{PLURAL:$1|karakter|karakteran}} ra zêde mebo.",
-       "yourgender": "Şeklê xitabi?",
-       "gender-unknown": "Çımhal tı kerdê etiket, Nusner do çekuya Nerimaki cinsiyeti de şeno bıkar no",
-       "gender-male": "Perané wiki camérd deyne ezo vırnena",
-       "gender-female": "Perané wiki cıni deyne eza vırnena",
-       "prefs-help-gender": "Na tercih keyfiya.\nNa nustenek ercana qısan de qandé grameri karneyéna, na malumater herkes şeno bıvino .",
-       "email": "E-posta",
+       "yourgender": "Şımayê xo seni tarif kenê?",
+       "gender-unknown": "Nuşteker şıma ra behskerdış de, hende ke cı dest ra bêro, cınsiyeto elaqeyın gureneno.",
+       "gender-male": "Oyo pelanê wikiyi vurneno",
+       "gender-female": "Aya pelanê wikiyi vurnena",
+       "prefs-help-gender": "No eyarê tercihi keyfiyo.\nNo nuşteker xıtabkerdış de ercê xo u ê binan rê şıma ra behskerdış de cınsiyetê grameriyê hewli gureneno.\nNo melumat her kesi rê aseno.",
+       "email": "E-poste",
        "prefs-help-realname": "Nameyo raşt waştena şıma rê mendo.\nEka tu wazene ke nameyo raşt xo bide, ma nameyo raşt ti iştirakanê ti de mocnenê.",
        "prefs-help-email": "Dayışê adresa e-postey keyfiyo, labelê seba eyarê parola lazıma, wexto ke şıma naye xo vira kerê.",
        "prefs-help-email-others": "Pera ğoya kerderi de zew link vırazése karberé bini şımaré şenê mesac bırşé. Lakin e-posta adresa şıma héç cayé de niasena.",
        "userrights-conflict": "Heqan de karberi de dıbare vıcyayo! Kerem ke vurnayışane xo çımser ra ravyarne  u tesdiq keri.",
        "group": "Grube:",
        "group-user": "Karberi",
-       "group-autoconfirmed": "Karberê ke otomatikmen biyê araşt",
+       "group-autoconfirmed": "Karberê otomatikraştbiyayeyi",
        "group-bot": "Boti",
        "group-sysop": "İdarekari",
        "group-interface-admin": "İdarekarê namnişani",
        "group-suppress": "Pawıteri",
        "group-all": "(pêro)",
        "group-user-member": "{{GENDER:$1|karber}}",
-       "group-autoconfirmed-member": "{{GENDER:$1|Karberê ke otomatikmen biyê araşt}}",
+       "group-autoconfirmed-member": "{{GENDER:$1|Karberê otomatikraştbiyayeyi}}",
        "group-bot-member": "{{GENDER:$1|bot}}",
        "group-sysop-member": "{{GENDER:$1|İdarekar}}",
        "group-interface-admin-member": "{{GENDER:$1|idarekarê namnişani}}",
        "group-bureaucrat-member": "{{GENDER:$1|buroqrat}}",
        "group-suppress-member": "{{GENDER:$1|Temaşekar}}",
        "grouppage-user": "{{ns:project}}:Karberi",
-       "grouppage-autoconfirmed": "{{ns:project}}:Karberê ke otomatikmen biyê araşt",
+       "grouppage-autoconfirmed": "{{ns:project}}:Karberê otomatikraştbiyayeyi",
        "grouppage-bot": "{{ns:project}}:Boti",
        "grouppage-sysop": "{{ns:project}}:İdarekeri",
        "grouppage-interface-admin": "{{ns:project}}:İdarekarê namnişani",
        "grant-group-page-interaction": "Peran na tesiri",
        "grant-group-file-interaction": "Medya na tesiri",
        "grant-group-watchlist-interaction": "Lista da xoya tesir",
-       "grant-group-email": "e-poste bırışe",
+       "grant-group-email": "E-poste bırışe",
        "grant-group-high-volume": "Performansa aktiviteya vengê berzi",
        "grant-group-customization": "Xısusikerdış û tercihi",
        "grant-group-administration": "Performans hereketa idarey",
        "grant-basic": "Heqê basiti",
        "grant-viewdeleted": "Besteryaya peran u dosyaya bıasne",
        "grant-viewmywatchlist": "Lista serykerdışê xo bıvêne",
-       "newuserlogpage": "Roceka karberanê newa",
+       "newuserlogpage": "Qeydê karberanê neweyan",
        "newuserlogpagetext": "No yew qeydê afernayışanê karberio.",
        "rightslog": "Qeydê heqanê karberi",
        "rightslogtext": "Ena listeyê loganê ke heqqa karbaranî mucneno.",
        "action-userrights": "heqqa karberanê hemî bivurne",
        "action-userrights-interwiki": "heqqa karberanê ke wikiyê binî de hemî bivurne",
        "action-siteadmin": "Databasei kılit ke ya zi a ke",
-       "action-sendemail": "e-posta bırşe",
+       "action-sendemail": "e-poste bırışe",
        "action-editmyoptions": "Tercihanê xo bıvurne",
        "action-editmywatchlist": "Lista xoya ewniyayışi bıvırnê",
        "action-viewmywatchlist": "Listeyseyran de xo bıvin",
        "action-applychangetags": "Vurnayışana piya etiket kerdışi zi dezge fi",
        "action-deletechangetags": "etitikan danegeh ra bestere",
        "action-purge": "Ane perer newe ke",
+       "action-editinterface": "miyanriyê karberi bıvurne",
+       "action-editusercss": "dosyeyanê CSSyê karberanê binan bıvurne",
+       "action-edituserjson": "dosyeyanê JSONiyê karberanê binan bıvurne",
+       "action-edituserjs": "dosyeyanê JavaScriptiyê karberanê binan bıvurne",
+       "action-editsitecss": "pelehira CSSyi bıvurne",
+       "action-editsitejson": "pelehira JSONi bıvurne",
+       "action-editsitejs": "pelehira JavaScripti bıvurne",
+       "action-editmyusercss": "dosyeyanê CSSyê karberiya xo bıvurne",
+       "action-editmyuserjson": "dosyeyanê JSONiyê karberiya xo bıvurne",
+       "action-editmyuserjs": "dosyeyanê JavaScriptiyê karberiya xo bıvurne",
        "nchanges": "$1 {{PLURAL:$1|vurnayış|vurnayışi}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|ziyaretê peyêni ra nata}}",
        "enhancedrc-history": "tarix",
        "rcfilters-savedqueries-add-new-title": "Eyarê parzûnê newcudi qeyd kerê",
        "rcfilters-restore-default-filters": "Parzûnê ke estê peyser biya",
        "rcfilters-clear-all-filters": "Parzûnan pêro pak kerê",
-       "rcfilters-show-new-changes": "Vurnayışanê neweyan bımocne",
+       "rcfilters-show-new-changes": "$1 ra nat vurnayışanê neweyan bımocne",
        "rcfilters-search-placeholder": "Vurnayışanê peyênan parzûn kerê (menuyi bıgurenê ya zi nameyê parzûni cıgeyrê)",
        "rcfilters-invalid-filter": "Parzûno nêravêrde",
        "rcfilters-empty-filter": "Parzûnê aktifi çıniyê. İştırakê cı pêro mocniyenê.",
        "rcfilters-filtergroup-authorship": "Wayiriya iştırakan",
        "rcfilters-filter-editsbyself-label": "Vurnayışê şıma",
        "rcfilters-filter-editsbyself-description": "İştırakê şıma.",
-       "rcfilters-filter-editsbyother-label": "Ê binan ra vurnayışi",
+       "rcfilters-filter-editsbyother-label": "Vurnayışê merdımanê binan",
        "rcfilters-filter-editsbyother-description": "Bê vurnayışanê şıma vurnayışi pêro.",
-       "rcfilters-filtergroup-userExpLevel": "Qeydê karberi u tecrube",
+       "rcfilters-filtergroup-user-experience-level": "Qeydê karberi u tecrube",
        "rcfilters-filter-user-experience-level-registered-label": "Qeydıni",
        "rcfilters-filter-user-experience-level-registered-description": "İdarekarê cıkewteyi.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Bêqeydıni",
        "rcfilters-filter-user-experience-level-newcomer-label": "Ameyayeyê neweyi",
        "rcfilters-filter-user-experience-level-newcomer-description": "Karberê qeydınê ke 10 ra kemi vurnayışi ya zi 4 rocan ra fealiyetê xo estê.",
        "rcfilters-filter-user-experience-level-learner-label": "Musayoği",
+       "rcfilters-filter-user-experience-level-learner-description": "Vurnayoğê qeydınê ke cerrebnayışê cı \"Neweameyoği\" û \"Karberê westay\"an miyan dero.",
        "rcfilters-filter-user-experience-level-experienced-label": "Karberê mısayeyi",
+       "rcfilters-filter-user-experience-level-experienced-description": "Vurnayoğê qeydınê ke 30 roce ra zêdêr fealiyet û wayirê 500 ra zêdêr vurnayışanê.",
        "rcfilters-filtergroup-automated": "İştırakê otomatiki",
        "rcfilters-filter-bots-label": "Bot",
        "rcfilters-filter-bots-description": "Terefê hacetanê otomatikan ra vurnayışi vıraziyayi.",
        "rcfilters-filter-watchlistactivity-unseen-label": "Vuriyayışê ke nêvêniyê",
        "rcfilters-filter-watchlistactivity-seen-label": "Vuriyayışê ke vêniyê",
        "rcfilters-filtergroup-changetype": "Tewrê vurnayışi",
-       "rcfilters-filter-pageedits-label": "Vuriyayışê pelan",
+       "rcfilters-filter-pageedits-label": "Vurriyayışê pelan",
+       "rcfilters-filter-pageedits-description": "Vurnayışê zerrekê wikiyi, werênayışi, şınasiya kategoriyan...",
        "rcfilters-filter-newpages-label": "Vıraştışê pelan",
        "rcfilters-filter-newpages-description": "Vurnayışê ke pelanê newiyab vırazenê.",
        "rcfilters-filter-categorization-label": "Vuriyayışê kategoriyan",
        "rcfilters-filter-categorization-description": "Kategoriyan ra qeydê cıkerdış u wedardışê pelan.",
        "rcfilters-filter-logactions-label": "Rocekê iştırakan",
-       "rcfilters-filtergroup-lastRevision": "Çımraviyarnayışê tewr peyêni",
+       "rcfilters-filter-logactions-description": "Karberiya xızmetkaran, vıraştışê hesaban, esterıtışê pelan, barkerdışi...",
+       "rcfilters-filtergroup-lastrevision": "Çımraviyarnayışê tewr peyêni",
        "rcfilters-filter-lastrevision-label": "Çımraviyarnayışo peyên",
        "rcfilters-filter-lastrevision-description": "Tenya vurnayışê yew peleyo tewr peyên.",
        "rcfilters-filter-previousrevision-label": "Çımraviyarnayışo peyên niyo",
+       "rcfilters-filter-previousrevision-description": "Heme vurnayışê ke \"çımraviyarnayışo peyên\" niyê.",
        "rcfilters-filter-excluded": "Xarıc",
        "rcfilters-tag-prefix-namespace-inverted": "$1 <strong>:nê</strong>",
        "rcfilters-exclude-button-off": "Weçinayeyi ciya bıtepışê",
        "newpageletter": "N",
        "boteditletter": "b",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 ho seyr keno {{PLURAL:$1|karber|karberî}}]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|bayt|bayti}} ra dıma vurnayış",
        "newsectionsummary": "/* $1 */ qısımo newe",
        "rc-enhanced-expand": "Detaya bıvin (JavaScript lazımo)",
        "rc-enhanced-hide": "Melumat bınımne",
        "rc-old-title": "\"$1\"i orcinalê cı vıraşt",
-       "recentchangeslinked": "Vırnayışê bestiyaey",
-       "recentchangeslinked-feed": "Vırnayışê bestiyaey",
-       "recentchangeslinked-toolbox": "Vırnayışê bestiyaey",
+       "recentchangeslinked": "Vurnayışê eleqeyıni",
+       "recentchangeslinked-feed": "Vurnayışê eleqeyıni",
+       "recentchangeslinked-toolbox": "Vurnayışê eleqeyıni",
        "recentchangeslinked-title": "Heqa \"$1\" de vurnayışi",
        "recentchangeslinked-summary": "Yew nameyê pele cıkewe ke vurnayışanê ke pele de ya zi naye ra gıre biyê, inan bıvênê. Seba ke ezayanê yew kategoriye bıvênê, „{{ns:category}}:''nameyê kategoriye''“ cıkewe. Vurnayışê pelanê ke [[Special:Watchlist|lista şımaya seyrkedışi]] derê, <strong>qalınd</strong> bêli kerdê.",
        "recentchangeslinked-page": "Namey perrer:",
        "img-auth-nopathinfo": "PATH_INFO kemiyo.\nTeqdimkerê şıma seba ravurnayışê nê melumati eyar nêkerdo.\nBeno ke be CGI-bıngeyın bo u img_auth rê desteg nêbeno.\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization Selahiyetê resımi bıvêne.",
        "img-auth-notindir": "Patikayê ke ti wazeno direktorê bar biyayişî de çin o.",
        "img-auth-badtitle": "\"$1\" ra nieşkeno yew seroğê raştî virazî.",
-       "img-auth-nologinnWL": "Ti cikewte ni yo u \"$1\" listeyo sipê de çin o.",
        "img-auth-nofile": "Dosyaya ''$1'' çıniya.",
        "img-auth-isdir": "\"$1\" şıma gêrenî bıresî tiya.\nşıma têna eşkenî bıresi dosya.",
        "img-auth-streaming": "\"$1\" stream keno.",
        "listfiles-userdoesnotexist": "Hesabê karberi \"$1\" qeyd nêbiyo.",
        "imgfile": "dosya",
        "listfiles": "Lista Dosya",
-       "listfiles_thumb": "Resmo qıckek",
+       "listfiles_thumb": "Resımo qıckek",
        "listfiles_date": "Deme",
        "listfiles_name": "Name",
        "listfiles_user": "Karber",
        "filehist-revert": "Peyd bıgi",
        "filehist-current": "nıkayên",
        "filehist-datetime": "Tarix/Zeman",
-       "filehist-thumb": "Resmo qıckek",
+       "filehist-thumb": "Resımo qıckek",
        "filehist-thumbtext": "Thumbnail qe versiyonê $1",
        "filehist-nothumb": "Thumbnail çin o.",
        "filehist-user": "Karber",
        "unusedtemplates": "Şablonê ke nêguriyenê",
        "unusedtemplatestext": "no pel, {{ns:template}} pelê ke pelê binan de nêaseni, ninan keno.",
        "unusedtemplateswlh": "linkanê binî",
-       "randompage": "Perra raştameyiye",
+       "randompage": "Pela raştameyiye",
        "randompage-nopages": "Na {{PLURAL:$2|heruna namey|heruna nameyan}} de nê peli çıniyê: $1.",
        "randomincategory": "Ena kategoriye dı pela raştameye",
        "randomincategory-invalidcategory": "\"$1\" yew nameyê kategoriya vêrdiye niyo.",
        "ncategories": "$1 {{PLURAL:$1|Kategori|Kategoriy}}",
        "ninterwikis": "$1 {{PLURAL:$1|interwiki|interwikiy}}",
        "nlinks": "$1 {{PLURAL:$1|link|linkî}}",
-       "nmembers": "$1 {{PLURAL:$1|eza|ezayan}}",
+       "nmembers": "$1 {{PLURAL:$1|eza|ezayi}}",
        "nmemberschanged": "$1 → $2 {{PLURAL:$1|eza|ezayan}}",
        "nrevisions": "$1 {{PLURAL:$1|vurnayış|vurnayışi}}",
        "nimagelinks": "$1 {{PLURAL:$1|pele de|pelan de}} gureyeno",
        "apisandbox-fetch-token": "Cayê otomatiki pırr ke",
        "apisandbox-add-multi": "Cı ke",
        "apisandbox-submit-invalid-fields-title": "Tay çiy ters şı",
-       "apisandbox-results": "Peyniy",
+       "apisandbox-results": "Neticeyi",
        "apisandbox-sending-request": "API waştış rışêno...",
        "apisandbox-request-url-label": "URL waştış:",
        "apisandbox-request-json-label": "Waştışê JSON'i:",
        "checkbox-none": "Çıniyo",
        "checkbox-invert": "Dimlaşt ke",
        "allpages": "Pêro peli",
-       "nextpage": "Pela peyco ($1)",
+       "nextpage": "Pela bahdoyêne ($1)",
        "prevpage": "Pela veri ($1)",
        "allpagesfrom": "Herfa kı pa liste bo:",
        "allpagesto": "Perranê ke ena herfe qediyenê bımotne:",
        "delete-confirm": "\"$1\" bestere",
        "delete-legend": "Bestere",
        "historywarning": "'''Teme:''' Pela ke şıma esterenê tede yew viyarte be teqriben $1 {{PLURAL:$1|versiyon esto|versiyoni estê}}:",
-       "historyaction-submit": "Bımocne",
+       "historyaction-submit": "Versiyonan bımocne",
        "confirmdeletetext": "Tı ho yew pele u tarixê pele wederneno.\nTı ra rica keno, tı zani tı ho sekeno, tı zani neticeyanê eno wedarnayışi u tı zani tı ser [[{{MediaWiki:Policy-url}}|poliçe]] kar keno.",
        "actioncomplete": "Kar bi temam",
        "actionfailed": "kar nêbı",
        "delete-warning-toobig": "no pel wayirê tarixê vurnayiş ê derg o, $1 {{PLURAL:$1|revizyonê|revizyonê}} seri de.\nhewn a kerdışê ıney {{SITENAME}} şuxul bıne gırano;\nbı diqqet dewam kerê.",
        "deleteprotected": "Şıma nêşenê ena perer esternê,  çıkı per starya ya.",
        "rollback": "vurnayişan tepiya bıger",
+       "rollback-confirmation-yes": "Peyser biya",
+       "rollback-confirmation-no": "Bıtexelne",
        "rollbacklink": "ageyrayış",
        "rollbacklinkcount": "$1 {{PLURAL:$1|vurnayış|vurnayışi}} peyd gıroti",
        "rollbacklinkcount-morethan": "$1 {{PLURAL:$1|vurnayış|vuranyışi}} tewr peyd gırot",
        "isredirect": "pera hetenayışi",
        "istemplate": "Açarnayene",
        "isimage": "gırey dosye",
-       "whatlinkshere-prev": "{{PLURAL:$1|veror|veror $1}}",
+       "whatlinkshere-prev": "{{PLURAL:$1|verên|verên $1}}",
        "whatlinkshere-next": "{{PLURAL:$1|verni|verni $1}}",
        "whatlinkshere-links": "← gırey",
        "whatlinkshere-hideredirs": "Hetenayışê $1",
        "blocklist-userblocks": "Kılitkerdışê hesaban bınımne",
        "blocklist-tempblocks": "Kılitkerdışan mıweqet bınımne",
        "blocklist-addressblocks": "Tenya kılitkerdışanê IPy bınımne",
+       "blocklist-type": "Babet:",
+       "blocklist-type-opt-all": "Pêro",
+       "blocklist-type-opt-sitewide": "Pelehira",
+       "blocklist-type-opt-partial": "Qısmi",
        "blocklist-rangeblocks": "Kılitkerdışanê rêzkiyan bınımne",
        "blocklist-timestamp": "İmzay demi",
        "blocklist-target": "Menzil",
        "blocklist-editing-page": "peli",
        "blocklist-editing-ns": "Heruna nameyan",
        "ipblocklist-empty": "Listay kılit kerdışi venga.",
-       "ipblocklist-no-results": "Adresa IPya waştiye ya zi nameyê karberi kılit nêbiyo.",
+       "ipblocklist-no-results": "Adresa IPya waştiye û nameyê karberiyo waşteyi rê kılitkerdışo vêrde çıniyo.",
        "blocklink": "kılit ke",
        "unblocklink": "ake",
        "change-blocklink": "kılitkerdışi bıvurne",
        "allmessagesdefault": "Metnê mesacê hesabiyayey",
        "allmessagescurrent": "Nuşteyê mesacê rocaneyi",
        "allmessagestext": "na liste, listeya mesajê cayê nameyê wikimedya yo.\neke şıma qayili paşt bıdi mahalli kerdışê wikimedyayi, kerem kerê pelê [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation mahalli kerdışê wikimedyayi] u [https://translatewiki.net translatewiki.net] ziyaret bıkerê.",
-       "allmessagesnotsupportedDB": "'''$wgUseDatabaseMessages''' qefelnaye yo u ey ra '''{{ns:special}}:Allmessages''' karkerdışi re akerde niyo.",
+       "allmessages-not-supported-database": "'''$wgUseDatabaseMessages''' qefelnaye yo u ey ra '''{{ns:special}}:Allmessages''' karkerdışi re akerde niyo.",
        "allmessages-filter-legend": "Parzûn",
        "allmessages-filter": "goreyê xususi kerdışi re filtre bıker",
        "allmessages-filter-unmodified": "Nivurnaye",
        "djvu_no_xml": "Qe DjVu nieşkenî XML fetch bikî",
        "thumbnail-temp-create": "İdare dosyay resimiya nêvırazêna",
        "thumbnail-dest-create": "Resimo werdiyo keyd nêbeno",
-       "thumbnail_invalid_params": "Parametreya thumbnailî raşt niyşê",
+       "thumbnail_invalid_params": "Parametreya xıraba resimanê werdiyan",
        "thumbnail_toobigimagearea": "Ebadê $1 ra gırd dosyeyi",
        "thumbnail_dest_directory": "Nieşkenî direktorê destinasyonî virazî",
        "thumbnail_image-type": "Tipê resimî kebul nibeno",
        "tooltip-search": "{{SITENAME}} de cı geyre",
        "tooltip-search-go": "Ebe nê namey tami şo yew pela ke esta",
        "tooltip-search-fulltext": "Pelan miyan de nê metıni cı geyre",
-       "tooltip-p-logo": "Şo perra seri",
-       "tooltip-n-mainpage": "Şo perra seri",
-       "tooltip-n-mainpage-description": "Şo perra seri",
+       "tooltip-p-logo": "Şo pela seri",
+       "tooltip-n-mainpage": "Şo pela seri",
+       "tooltip-n-mainpage-description": "Şo pela seri",
        "tooltip-n-portal": "Heqa procey de, kes çı şeno bıkero, çı kamca vêniyeno",
        "tooltip-n-currentevents": "Vurnayışanê peyênan de melumatê pey bıvêne",
        "tooltip-n-recentchanges": "Wiki de yew lista vurnayışanê peyênan",
        "tooltip-ca-nstab-category": "Pela kategoriye bıvêne",
        "tooltip-minoredit": "Ney vırnayışo werdi nışan bıkerê",
        "tooltip-save": "Vurnayışanê xo qeyd ke",
-       "tooltip-publish": "Vırnayışê xo aşkera ke",
+       "tooltip-publish": "Vurnayışê xo qeyd ke",
        "tooltip-preview": "Vurnayışanê xo çım ra bıviyarnê. Qeydkerdış ra ver bıgurê cı!",
        "tooltip-diff": "Kamci vırnayışê ke şıma nuştey sero kerdê, inan bıvênê.",
        "tooltip-compareselectedversions": "Ena per de ferqê rewziyonan de dı weçinaya bıvinê",
        "tooltip-preferences-save": "Terciha qeyd ke",
        "tooltip-summary": "Xulasa kılmek bınuse",
        "interlanguage-link-title": "$1 - $2",
+       "group-autoconfirmed.css": "/* CSSyo ke tiya roniyo, karberanê otomatikraştbiyayeyan rê tesir keno */",
+       "group-autoconfirmed.js": "/* No JavaScript teyna seba karberanê otomatikraştbiyayeyan rê do bar bo */",
        "anonymous": "{{PLURAL:$1|karberê|karberê}} anonimi yê keyepelê {{SITENAME}}i",
        "siteuser": "karberê {{SITENAME}}i $1",
        "anonuser": "karberê anonim o {{SITENAME}}i $1",
        "pageinfo-hidden-categories": "{{PLURAL:$1|Kategoriya nımıtiye|Kategoriyê nımıtey}} ($1)",
        "pageinfo-templates": "{{PLURAL:$1|Şablono|Şablonê}} ke mocniyenê ($1)",
        "pageinfo-transclusions": "{{PLURAL:$1|1 Pele|$1 Pelan}} de bestiya pıra",
-       "pageinfo-toolboxlink": "Melumatê perre",
+       "pageinfo-toolboxlink": "Melumatê pele",
        "pageinfo-redirectsto": "Beno hetê",
        "pageinfo-redirectsto-info": "melumat",
        "pageinfo-contentpage": "Zey jû pela zerreki hesebiyena",
        "nextdiff": "Vurnayışo peyên →",
        "mediawarning": "'''Teme''': Na dosya de belkia kodê xırabıni estê.\nGurênayışê nae de, beno ke sistemê şıma zerar bıvêno.",
        "imagemaxsize": "Sinorê ebadê resımiyo ke pelanê şınasnayışê dosyeyan dero:",
-       "thumbsize": "Ebadê Thumbnaili",
+       "thumbsize": "Ebado werdi:",
        "widthheight": "$1 - $2",
        "widthheightpage": "$1 × $2, $3 {{PLURAL:$3|pele|peli}}",
        "file-info": "ebatê dosyayi: $1, MIME tip: $2",
        "recreate": "Werzayne",
        "unit-pixel": "px",
        "confirm-purge-title": "Na pele pak ke",
-       "confirm_purge_button": "Temam",
+       "confirm_purge_button": "TEMAM",
        "confirm-purge-top": "Vervirê na pele bestere?",
        "confirm-purge-bottom": "Pakkerdışê yew perre virê verêni estereno u çımraviyarnayışê peyêni gêno ver.",
        "confirm-watch-button": "TEMAM",
        "brackets": "[$1]",
        "quotation-marks": "\"$1\"",
        "imgmultipageprev": "← pela veri",
-       "imgmultipagenext": "pela peyco →",
+       "imgmultipagenext": "pela bahdoyêne →",
        "imgmultigo": "Şo!",
        "imgmultigoto": "Şo pela da $1",
        "img-lang-default": "(zıwano hesabiyaye)",
        "img-lang-go": "Şo",
        "ascending_abbrev": "berz",
        "descending_abbrev": "nızm",
-       "table_pager_next": "Pela peyco",
+       "table_pager_next": "Pela bahdoyêne",
        "table_pager_prev": "Pela veri",
        "table_pager_first": "Pela sıfteyêne",
        "table_pager_last": "Pela peyêne",
        "table_pager_limit_label": "Her pele ra xacetan",
        "table_pager_limit_submit": "Şo",
        "table_pager_empty": "Netice çıniyo",
-       "autosumm-blank": "Pele de her çi wederna",
+       "autosumm-blank": "Pele kerde veng",
        "autosumm-replace": "Maqale pê '$1' vuriya",
        "autoredircomment": "heteneya [[$1]]",
+       "autosumm-removed-redirect": "[[$1]] ra serşıkıtış dariya we",
+       "autosumm-changed-redirect-target": "Hedefê serşıkıtışi heruna [[$1]] ra vurniya era [[$2]]",
        "autosumm-new": "Pela vıraziyê, '$1' bıvinê",
        "autosumm-newblank": "Pera veng vıraziyê",
        "size-bytes": "$1 {{PLURAL:$1|bayt|bayti}}",
        "tag-list-wrapper": "[[Special:Tags|{{PLURAL:$1|Etiket|Etiketi}}]]: $2",
        "tag-mw-contentmodelchange": "vurnayışê modelê zerreki",
        "tag-mw-new-redirect": "Serşıkıtışo newe",
-       "tag-mw-blank": "Vengkerdış",
+       "tag-mw-removed-redirect": "Serşıkıtış dariya we",
+       "tag-mw-changed-redirect-target": "Hedefê serşıkıtışi vurniya",
+       "tag-mw-blank": "Pel veng kerdış",
        "tag-mw-blank-description": "Vengiya na pele bıvurne",
-       "tag-mw-replace": "Zerrek vurriya",
+       "tag-mw-replace": "Vera cı vurniya",
+       "tag-mw-replace-description": "No vurnayış %90 ra zêde zerrekê yew pele dareno we",
        "tag-mw-rollback": "Peyserardış",
-       "tag-mw-undo": "Peyser bıgê",
+       "tag-mw-undo": "Peyser gırotış",
        "tags-title": "Etiketi",
        "tags-intro": "Ena pele etiketê ke be vurnayışê nuşiyayışi ra nişan biyê û maneyê inan lista kena.",
        "tags-tag": "Nameyê etiketi",
        "htmlform-datetime-placeholder": "SSSS-AA-RR SS:DD:SS",
        "logentry-delete-delete": "$1 perra $3 {{GENDER:$2|esterıte}}",
        "logentry-delete-restore": "$1 pela $3 ($4) {{GENDER:$2|peyser arde}}",
+       "restore-count-revisions": "{{PLURAL:$1|1 çımraviyarnayış|$1 çımraviyarnayışi}}",
        "restore-count-files": "{{PLURAL:$1|1 dosya|$1 dosyeyi}}",
        "logentry-delete-event": "$1 $3: $4 de asayışê {{PLURAL:$5|cıkerdışi|cıkerdışan}} {{GENDER:$2|vurna}}",
        "logentry-delete-revision": "$1 pela $3: $4 de asayışê {{PLURAL:$5|yew revizyoni|$5 revizyonan}} {{GENDER:$2|vurna}}",
        "revdelete-unrestricted": "vergırewtışê ke xızmekaran rê dariyê we",
        "logentry-partialblock-block-page": "{{PLURAL:$1|pele|peli}} $2",
        "logentry-partialblock-block-ns": "{{PLURAL:$1|cayê nameyi|cayê nameyan}} $2",
-       "logentry-move-move": "$1 perra $3 {{GENDER:$2|kırışt}} $4",
+       "logentry-move-move": "$1, pela $3 ra {{GENDER:$2|kırışt}} pela $4",
        "logentry-move-move-noredirect": "$1, pera $3'i bêhetenayış {{GENDER:$2|kırışt}} pera $4`i",
        "logentry-move-move_redir": "$1 {{GENDER:$2|kırışna}} riperr $3 be $4 weçarnayış sera.",
        "logentry-move-move_redir-noredirect": "$1 {{GENDER:$2|berd}} riperrê $3 be $4 weçarnayış sera, weçarnayış nêverda.",
        "expand_templates_output": "netice",
        "expand_templates_xml_output": "XML vıraştış",
        "expand_templates_html_output": "Xam vetey HTML",
-       "expand_templates_ok": "temam",
+       "expand_templates_ok": "TEMAM",
        "expand_templates_remove_comments": "Tefsiran wedare",
        "expand_templates_remove_nowiki": "neticeyan de etiketê <nowiki> yan çap bıker",
        "expand_templates_generate_xml": "Dara XML arêdayoği bımocne",
        "log-action-filter-delete-revision": "Esterıtışê çımraviyarnayışi",
        "log-action-filter-import-interwiki": "Zerrenayışê Transwikiyi",
        "log-action-filter-import-upload": "Ebe barkerdışê XMLi ra zerre ke",
+       "log-action-filter-protect-protect": "Şeveknayış",
+       "log-action-filter-protect-modify": "Vurnayışê şeveknayışi",
+       "log-action-filter-protect-unprotect": "Şeveknayışi wedare",
+       "log-action-filter-protect-move_prot": "Şeveknayışê berdışi",
+       "log-action-filter-rights-rights": "Vurnayışo manuel",
+       "log-action-filter-rights-autopromote": "Vurnayışo otomatik",
+       "log-action-filter-upload-upload": "Barkerdışo newe",
+       "log-action-filter-upload-overwrite": "Anciya bar kerê",
        "log-action-filter-upload-revert": "Wegeyrayış",
+       "authmanager-email-label": "E-poste",
+       "authmanager-email-help": "Adresa e-posteyi",
+       "authmanager-realname-label": "Nameyo raştıkên",
+       "authmanager-realname-help": "Nameyê karberiyo raştıkên",
        "authprovider-resetpass-skip-label": "Ravêre",
        "authprovider-resetpass-skip-help": "Peysereştışê parola ra bıvêre.",
        "authform-notoken": "Tokeno kemi",
        "changecredentials": "Malumatanê karberi bıvurnê",
        "removecredentials": "Kamiye wedarne",
        "removecredentials-submit": "Kamiyer wedarne",
+       "credentialsform-account": "Nameyê hesabi:",
+       "linkaccounts": "Hesabê gıreyi",
+       "linkaccounts-success-text": "Hesab gıre biyo.",
+       "linkaccounts-submit": "Hesabê gıreyi",
+       "unlinkaccounts": "Hesabo bêgıre",
+       "edit-error-short": "Xeta: $1",
+       "edit-error-long": "Xeteyi:\n\n$1",
        "revid": "Revizyonê $1",
        "pageid": "IDyê pela $1",
        "gotointerwiki": "{{SITENAME}} ra abırriyeno",
+       "pagedata-title": "Dayiyê pele",
+       "passwordpolicies": "Politikaya parola",
        "passwordpolicies-group": "Grube",
        "passwordpolicies-policies": "Politikeyi",
        "passwordpolicies-policy-minimalpasswordlength": "Parola gani tewr senık be {{PLURAL:$1|1 karakter|$1 karakteran}} derg bo"
index ef1a578..ccd9218 100644 (file)
        "minoreditletter": "S",
        "newpageletter": "N",
        "boteditletter": "B",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|wobglědowaŕ|wobglědowarja|wobglědowarje}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|byta|byty|bytow}} pó změnje",
        "newsectionsummary": "Nowy wótrězk /* $1 */",
        "rc-enhanced-expand": "Drobnostki pokazaś",
        "img-auth-nopathinfo": "PATH_INFO felujo.\nTwój serwer njejo konfigurěrowany, aby toś te informacije dalej pósrědnił.\nMóžo na CGI bazěrowaś a njamóžo img_auth pódpěraś.\nGlědaj https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Pominana šćažka njejo w konfigurěrowanem nagraśowem zapisu.",
        "img-auth-badtitle": "Njejo móžno z \"$1\" płaśiwy titel twóriś.",
-       "img-auth-nologinnWL": "Njejsy pśizjawjony a \"$1\" njejo w běłej lisćinje.",
        "img-auth-nofile": "Dataja \"$1\" njeeksistěrujo.",
        "img-auth-isdir": "Wopytujoš na zapis \"$1\" pśistup měś.\nJano datajowy pśistup jo dowólony.",
        "img-auth-streaming": "\"$1\" se tšuga.",
        "allmessagesdefault": "Standardny tekst",
        "allmessagescurrent": "Aktualny tekst",
        "allmessagestext": "How jo lisćina systemowych powěsćow w mjenowem rumje MediaWiki.\nPšosym wobglědaj [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation lokalizaciju MediaWiki] a [https://translatewiki.net translatewiki.net], jolic coš k lokalizaciji MediaWiki pśinosowaś.",
-       "allmessagesnotsupportedDB": "'''{{ns:special}}:Allmessages''' njejo tuchylu móžno, dokulaž jo datowa banka offline.",
+       "allmessages-not-supported-database": "'''{{ns:special}}:Allmessages''' njejo tuchylu móžno, dokulaž jo datowa banka offline.",
        "allmessages-filter-legend": "Filter",
        "allmessages-filter": "Pó pśiměrjeńskem stawje filtrěrowaś:",
        "allmessages-filter-unmodified": "Njezměnjony",
index dbed2cb..dfa08ea 100644 (file)
        "rcfilters-filter-editsbyself-description": "तमरा आफ्फुनाइ योगदानन",
        "rcfilters-filter-editsbyother-label": "अउर हताँ अरियाऽ फेरबदेलाअन",
        "rcfilters-filter-editsbyother-description": "तमरा आफ्फुनाइ बाहेक अउर सप्पै फेरबदेलाअन।",
-       "rcfilters-filtergroup-lastRevision": "छाड्डीबारोः संशोधन",
+       "rcfilters-filtergroup-lastrevision": "छाड्डीबारोः संशोधन",
        "rcfilters-filter-lastrevision-label": "छाड्डीबारोः संशोधन",
        "rclistfrom": "$3 $2 देखिका नयाँ परिवर्तनहरू देखाउन्या",
        "rcshowhideminor": "$1 सानतिनो सम्पादन",
index 613f8f5..74b255a 100644 (file)
@@ -3,28 +3,61 @@
                "authors": [
                        "Cbrown1023",
                        "Natsubee",
-                       "아라"
+                       "아라",
+                       "Aguve",
+                       "Latercio2000",
+                       "Hello903hello"
                ]
        },
+       "tog-underline": "Flitete ɖe kadodo te:",
        "tog-hideminor": "Ɣla tɔtrɔ suewo le tɔtrɔ yeyeawo me",
-       "tog-watchcreations": "Tsɔ axa siwo gɔme medze kpakple axa siwo meda ɖe afisia la kpe ɖe axa siwo ŋu nyeƒe ŋku le la ŋu",
+       "tog-hidepatrolled": "Ɣla asitɔtrɔ siwo wowɔ la le tɔtrɔ yeyewo me",
+       "tog-newpageshidepatrolled": "Ɣla axa siwo wowɔ tɔtrɔwo la le axa yeyewo me",
+       "tog-hidecategorization": "Ɣla axawo mama ɖe hatsotsowo me",
+       "tog-extendwatchlist": "Keke Tɔtrɔkpɔƒe la ne nàkpɔ tɔtrɔwo katã, ke menye yeyetɔwo ko o",
+       "tog-usenewrc": "Ƒo tɔtrɔwo nu ƒu le woƒe axawo nu le tɔtrɔ yeyewo kple tɔtrɔkpɔƒea",
+       "tog-numberheadings": "Xexlẽdzesinana tanyawo",
+       "tog-editondblclick": "Netrɔ asi le axawo ŋu ne wozi edzi zi eve",
+       "tog-editsectiononrightclick": "Tiae be woate ŋu atrɔ akpa ne wozi eƒe tanyawo dzi",
+       "tog-watchcreations": "Tsɔ axa siwo mewɔ kple nyatagba siwo meda ɖe nye tɔtrɔkpɔƒe",
        "tog-watchdefault": "Tsɔ axawo kpakple nutatawo siwo ŋu metrɔ asi le la kpe ɖe axa siwo ŋu nyeƒe ŋku le la ŋu",
        "tog-watchmoves": "Tsɔ  axawo kpakple nutatawo siwo ƒe nɔƒe meɖɔli la kpe ɖe axa siwo ŋu nyeƒe ŋku le la ŋu",
        "tog-watchdeletion": "Tsɔ  axawo kpakple nutatawo siwo metutu la kpe ɖe axa siwo ŋu nyeƒe ŋku le la ŋu",
-       "tog-enotifwatchlistpages": "Ɖo du nam ne axa aɖe alo nutata aɖe si ŋu nyeƒe ŋku le la trɔ",
+       "tog-watchuploads": "Da nyatakagba yeye siwo medana ɖi ɖe nye tɔtrɔkpɔƒe",
+       "tog-watchrollback": "Tsɔ axawo ɖɔlii tɔtrɔ siwo me mete fli ɖo le nye tɔtrɔkpɔƒea.",
+       "tog-minordefault": "Nede dzesi tɔtrɔwo katã be wonye tɔtrɔ suewo ɣesiaɣi.",
+       "tog-previewontop": "Aɖaka ƒe nɔnɔme nedze gbã hafi woatrɔ emenuwo",
+       "tog-previewonfirst": "Eƒe nɔnɔme nedze ne wowɔ tɔtrɔ gbãtɔ",
+       "tog-enotifwatchlistpages": "Ɖo email ɖem ne axa alo nyatakagba siwo le tɔtrɔkpɔƒe la trɔ",
+       "tog-enotifusertalkpages": "Ɖo Email ɖem ne nane trɔ le nye dzeɖoƒea",
+       "tog-enotifminoredits": "Ɖo Email ɖem ne nu sue aɖe trɔ le nye axawo alo nyatagbawo hã ŋu",
+       "tog-enotifrevealaddr": "Nye email adrɛs la nedze le nyanyanana ƒe emailwo me.",
+       "tog-shownumberswatching": "Axaʋulawo ƒe xexlẽme nedze",
+       "tog-oldsig": "Wò asidenute si li:",
+       "tog-fancysig": "Bu asidenude abe wikinuŋɔŋlɔ ene (menye kadodo leɖokuisi o)",
+       "tog-uselivepreview": "Vayiawo nedze evɔ megagbugbɔ axaawo ʋu o",
+       "tog-forceeditsummary": "Na manya ne mele nuŋɔŋlɔʋuƒo gbɔlo ɖom ɖa",
+       "tog-watchlisthideown": "Nye tɔtrɔwo megadze le tɔtrɔkpɔƒe la o",
+       "tog-watchlisthidebots": " Robot-tɔtrɔwo megadze le nukpɔƒea o",
+       "tog-watchlisthideminor": "Tɔtrɔ suewo megadze le tɔtrɔkpɔƒe o",
+       "tog-watchlisthideliu": "Ezãla siwo ge ɖe eme ƒe tɔtrɔwo megadze le tɔtrɔkpɔƒe la o",
+       "tog-watchlistreloadautomatically": "Nukpɔƒea neʋu le eɖokui si ne wotrɔ sranui aɖe (JavaSkript hã)",
        "tog-useeditwarning": "Na nyanyam ne mele asiɖem le axa si ŋu wome dzra tɔtrɔwo ɖo vɔ la o.",
        "underline-always": "Ɣesiaɣi",
        "underline-never": "Gbeɖe",
-       "sunday": "Kɔsiɖagbe",
-       "monday": "Dzoɖagbe",
-       "tuesday": "Brãɖagbe",
-       "wednesday": "Kuɖagbe",
-       "thursday": "Yawoɖagbe",
-       "friday": "Fiɖagbe",
-       "saturday": "Memleɖagbe",
-       "sun": "Kɔs",
+       "editfont-style": "Trɔ akpa la ƒe nuŋlɔtsyã",
+       "editfont-sansserif": "Sans-serif nuŋlɔtsyã",
+       "editfont-serif": "Serif Nuŋlɔtsyã",
+       "sunday": "Kwasiɖa",
+       "monday": "Dzoɖa",
+       "tuesday": "Braɖa",
+       "wednesday": "Kuɖa",
+       "thursday": "Yawoɖa",
+       "friday": "Fiɖa",
+       "saturday": "Memleɖa",
+       "sun": "Kwa",
        "mon": "Dzo",
-       "tue": "Brã",
+       "tue": "Br",
        "wed": "Kuɖ",
        "thu": "Yaw",
        "fri": "Fiɖ",
@@ -33,7 +66,7 @@
        "february": "Dzodze",
        "march": "Tedoxe",
        "april": "Afɔfiɛ",
-       "may_long": "Damɛ",
+       "may_long": "Dame",
        "june": "Masa",
        "july": "Siamlɔm",
        "august": "Dasiamime",
@@ -45,7 +78,7 @@
        "february-gen": "Dzodze",
        "march-gen": "Tedoxe",
        "april-gen": "Afɔfiɛ",
-       "may-gen": "Damɛ",
+       "may-gen": "Dame",
        "june-gen": "Masa",
        "july-gen": "Siamlɔm",
        "august-gen": "Dasiamime",
@@ -57,7 +90,7 @@
        "feb": "Dzod",
        "mar": "Ted",
        "apr": "Afɔ",
-       "may": "Damɛ",
+       "may": "Dam",
        "jun": "Mas",
        "jul": "Sia",
        "aug": "Das",
        "february-date": "Dzodze $1",
        "march-date": "Tedoxe $1",
        "april-date": "Afɔfiɛ $1",
-       "may-date": "Damɛ $1",
+       "may-date": "Dame $1",
        "june-date": "Masa $1",
        "july-date": "Siamlɔm $1",
        "august-date": "Dasiamime $1",
        "october-date": "Kele $1",
        "november-date": "Adeɛmekpɔxe $1",
        "december-date": "Dzome $1",
-       "listingcontinuesabbrev": "yi dzi",
-       "about": "Ŋutinya",
+       "period-am": "ŊDI",
+       "period-pm": "ŊDƆ",
+       "pagecategories": "{{PLURAL:$1|Hatsotso|Hatsotsowo}}",
+       "category_header": "Axa siwo le hatsotso \"$1\"",
+       "hidden-categories": "{{PLURAL:$1||Hatsotso ɣaɣla|Hatsotso ɣaɣla}}",
+       "listingcontinuesabbrev": "yi edzi",
+       "about": "Eŋunya",
        "newwindow": "(eʋua fesre yeye)",
-       "cancel": "Dzudzɔ etɔtrɔ",
-       "mypage": "Axa nye",
-       "mytalk": "Nyeƒe nyamedzroƒe",
-       "navigation": "Mɔtabiala",
-       "and": "&#32;kpakple",
-       "qbfind": "Di",
-       "qbbrowse": "To eme",
-       "qbedit": "Trɔ asi le eŋu",
-       "qbpageoptions": "Axa sia",
-       "qbmyoptions": "Nyeƒe axawo",
-       "errorpagetitle": "Vodada",
-       "returnto": "Gbugbɔ yi $1.",
+       "cancel": "Tasii",
+       "moredotdotdot": "Bubuwo",
+       "morenotlisted": "Anɔ eme be menye wo katãe nye esia o.",
+       "mypage": "Axa",
+       "mytalk": "Dzeɖoƒe",
+       "anontalk": "Dzeɖoƒe",
+       "navigation": "Nuʋuʋu",
+       "and": "&#32;kple",
+       "faq": "Nya Siwo Wobiana Edziedzi",
+       "actions": "Nuwɔnawo",
+       "namespaces": "Ŋkɔteƒewo",
+       "variants": "Dzesiŋkɔwo",
+       "navigation-heading": "Nuʋunuwo",
+       "errorpagetitle": "Kuxi",
+       "returnto": "Trɔ yi $1.",
        "tagline": "Tso {{SITENAME}}",
        "help": "Kpekpeɖeŋu",
+       "help-mediawiki": "Kpekpeɖeŋu tso MediaWiki ŋu",
        "search": "Dii",
        "searchbutton": "Dii",
        "go": "Yi",
        "searcharticle": "Yi",
-       "history": "Axa sia ƒe tata xoxoawo",
-       "history_short": "Xoxoawo",
+       "history": "Axa ƒe nu ʋuvayiawo",
+       "history_short": "Nu Ʋuvayiwo",
+       "history_small": "nu ʋuvayiwo",
+       "printableversion": "Esi woate ŋu ata",
+       "permalink": "Kadodo liɖaa",
        "view": "Tata",
+       "view-foreign": "Kpɔe le $1",
        "edit": "Trɔ asi le eŋu",
        "create": "Dze egɔme",
-       "editthispage": "Ðɔ axa sia ɖo",
-       "create-this-page": "Dze axa sia gɔme",
        "delete": "Tutui",
-       "deletethispage": "Tutu axa sia",
-       "protect": "Dzɔ eŋu",
-       "protect_change": "ɖɔlii",
-       "protectthispage": "Dzɔ axa sia ŋu",
+       "protect": "Kpɔ eta",
+       "protect_change": "Trɔe",
        "newpage": "Axa yeye",
-       "talkpagelinktext": "Nyamedzroƒe",
-       "specialpage": "Axa Tɔxe",
-       "personaltools": "Wòƒe dɔwɔnuwo",
-       "talk": "Nyamedzroƒe",
-       "toolbox": "Dɔwɔnuɖaka",
+       "talkpagelinktext": "dzeɖoƒe",
+       "specialpage": "Axa tɔxɛ",
+       "personaltools": "Wò dɔwɔnuwo",
+       "talk": "Nyamedzodzro",
+       "views": "Dzedzeme",
+       "toolbox": "Dɔwɔnuwo",
        "otherlanguages": "Le gbe bubuwo me",
        "redirectedfrom": "(Woɖo wò ɖe afii tso $1)",
-       "lastmodifiedat": "Wó ɖɔ axa sia ɖo susue le $2 le ŋkeke $1 dzi.",
+       "redirectto": "Trɔe yi:",
+       "lastmodifiedat": "Zi mamlɛtɔ si wotrɔ asi le axa sia ŋue nye $1, ga $2.",
        "viewcount": "Wokpɔ axa sia zi {{PLURAL:$1|ɖeka|$1 sɔ̃}}.",
        "jumpto": "Dzo yi:",
-       "jumptonavigation": "kuɖɔɖoɖo",
+       "jumptonavigation": "nuʋuʋu",
        "jumptosearch": "dii",
-       "aboutsite": "{{SITENAME}} ŋutinya",
-       "aboutpage": "Project:Ŋutinya",
+       "pool-errorunknown": "Kuxi manyamanya aɖe",
+       "aboutsite": "{{SITENAME}} Ŋu Nya",
+       "aboutpage": "Project: Eŋunya",
        "copyright": "Nusiwo le afii le $1 mɔɖeɖea te.",
        "copyrightpage": "{{ns:project}}:Mɔɖeɖewo",
-       "currentevents": "Amaneɛ",
-       "currentevents-url": "Project:Nusiwo le dzɔdzɔm",
-       "disclaimers": "Nuxlɔ̃amenyawo",
-       "edithelp": "Kpekpeɖeŋu na etɔtrɔ",
-       "mainpage": "Axa do Ŋgɔ",
-       "mainpage-description": "Axa do ŋgɔ",
-       "portal": "Takpekpewɔƒe",
-       "portal-url": "Project:Takpekpewɔƒe",
-       "badaccess": "Mɔɖeɖe vodada",
-       "badaccess-group0": "Se meɖe mɔ be nawɔ nusi wòle babiam be yeawɔ o.",
-       "retrievedfrom": "Nuŋɔŋlɔ sia tso \"$1\"",
-       "youhavenewmessages": "$1 le asiwo ($2).",
-       "youhavenewmessagesmulti": "Du yeyewo le asiwo le $1",
+       "currentevents": "Nyadzɔdzɔ yeyewo",
+       "currentevents-url": "Project:Nyadzɔdzɔ yeyewo",
+       "disclaimers": "Kplɔasilemenyawo",
+       "disclaimerpage": "Project:Kplɔasilemenya vevi",
+       "edithelp": "Nutɔtrɔ ŋuti kpekpeɖeŋu",
+       "helppage-top-gethelp": "Kpekpeɖeŋu",
+       "mainpage": "Axa Gba͂tɔ",
+       "mainpage-description": "Axa gbãtɔ",
+       "portal": "Godoƒe",
+       "portal-url": "Project:Godoƒe",
+       "privacy": "Ameŋunyatakaka Ŋuti Ɖoɖo",
+       "privacypage": "Project:Ameŋunyatata ŋuti ɖoɖo",
+       "badaccess": "Mɔɖeɖe ƒe kuxi",
+       "badaccess-group0": "Mɔɖeɖe meli be nàwɔ nu si nèdi be yeawɔ o.",
+       "ok": "YOO",
+       "retrievedfrom": "Woɖee tso \"$1\"",
+       "youhavenewmessages": "$1 va ɖo ($2).",
+       "newmessageslinkplural": "{{PLURAL:$1|gbedeasiɖoɖa yeye|999=gbedeasiɖoɖa yeyewo}}",
+       "youhavenewmessagesmulti": "Du yeyewo vaɖo na wò $1",
        "editsection": "trɔ asi le eŋu",
        "editold": "trɔ asi le eŋu",
-       "viewsourceold": "kpɔ alesi wó ŋlɔe",
-       "editlink": "trɔ asi le eŋu",
-       "viewsourcelink": "kpɔ alesi woŋlɔe",
+       "viewsourceold": "kpɔ dzɔƒea",
+       "editlink": "trɔe",
+       "viewsourcelink": "kpɔ dzɔƒea",
        "editsectionhint": "Trɔ akpa: $1",
        "toc": "Emenyawo",
        "showtoc": "fia",
        "hidetoc": "ɣla",
-       "thisisdeleted": "Kpɔ $1 alo wòa gbugbɔe ve hã?",
-       "viewdeleted": "Wòa kpɔ $1 a?",
+       "collapsible-collapse": "Neɣlae",
+       "collapsible-expand": "Kekee",
+       "confirmable-yes": "Ɛ̃",
+       "confirmable-no": "Ao",
+       "thisisdeleted": "Kpɔ $1 alo woa gbugbɔ ɖe tsa͂tɔa ɖe go?",
+       "viewdeleted": "Kpɔ $1?",
+       "restorelink": "{{PLURAL:$1|ekpɔ tɔtrɔ ɖeka |ekpɔ tɔtrɔ $1}}",
+       "feedlinks": "Nukakala:",
+       "feed-invalid": "Nukakala ƒomevi sia mede o.",
+       "site-rss-feed": "RSS Nukakala $1",
+       "site-atom-feed": "Atom nubiabia $1",
+       "page-atom-feed": "\"$1\" Atom Nukakala",
        "red-link-title": "$1 (womeŋlɔ axa sia haɖeke o)",
        "nstab-main": "Axa",
-       "nstab-user": "Ezãla axa",
+       "nstab-user": "Ezãla ƒe axa",
+       "nstab-media": "Media ƒe axa",
        "nstab-special": "Axa tɔxe",
+       "nstab-project": "Dɔwɔna ƒe axa",
        "nstab-image": "Agbalẽ",
        "nstab-mediawiki": "Du",
-       "error": "Vodada",
-       "badarticleerror": "Wòmateŋu awɔ nusia le axa sia dzi o.",
+       "nstab-template": "Ɖeŋu",
+       "nstab-help": "Kpekpeɖeŋu ƒe axa",
+       "nstab-category": "Hatsotso",
+       "mainpage-nstab": "Axa vevitɔ",
+       "nosuchaction": "Mete ŋu wɔe o",
+       "nosuchactiontext": "Mete ŋu ʋu URL la o.\nƉewohĩ mèŋlɔ URL nyuie o alo kadodo si nèbe neʋu la mede o.\nAte ŋu anye hã be kuxi aɖe le kɔpiutaɖoɖo si zãm {{SITENAME}} le la me.",
+       "nosuchspecialpage": "Axa tɔxɛ sia meli o",
+       "nospecialpagetext": "<strong>Èbia be neʋu axa tɔxɛ aɖe si meli o.</strong>\n\nÀte ŋu akpɔ axa tɔxɛ siwo li la le [[Special:SpecialPages|{{int:specialpages}}]].",
+       "error": "Kuxi",
+       "databaseerror-query": "Gbeɖeɖe: $1",
+       "databaseerror-function": "Dɔwɔɖoɖo: $1",
+       "databaseerror-error": "Kuxi: $1",
+       "internalerror": "Ememekuxi",
+       "internalerror_info": "Ememekuxi: $1",
+       "internalerror-fatal-exception": "Kuxi sesẽ ƒomevi si nye \"$1\"",
+       "filecopyerror": "Mate ŋu akɔpi nutsɔ \"$1\" yi \"$2\" o.",
+       "filerenameerror": "Mete ŋu gbugbɔ ŋkɔ na nutsɔ \"$1\" be \"$2\" o.",
+       "badarticleerror": "Womateŋu awɔ nusia le axa sia dzi o.",
        "cannotdelete": "Womateŋu atutu axa sia alo axa \"$1\" o.\nƉewomahĩ ame aɖe tutui xoxo.",
        "badtitle": "Tanya gbegblẽ",
        "viewsource": "Kpɔ alesi wowɔe",
-       "remembermypassword": "Ɖo ŋku nyeƒe dzesi ŋkɔ dzi le mɔ sia dzi (vaseɖe {{PLURAL:$1|ŋkeke|ŋkeke}} $1 megbe)",
+       "userlogin-yourname": "Ezazãŋkɔ",
+       "userlogin-yourname-ph": "Mɔʋunya",
+       "userlogin-yourpassword": "Mɔʋunya",
+       "userlogin-yourpassword-ph": "Ŋlɔ wò mɔʋunya",
+       "createacct-yourpassword-ph": "Ŋlɔ mɔʋunya",
+       "createacct-yourpasswordagain": "Ɖo kpe mɔʋunyaa dzi",
+       "createacct-yourpasswordagain-ph": "Gaŋlɔ mɔʋunya ake",
+       "userlogin-remembermypassword": "Mígaɖem le eme o",
        "login": "Ge ɖe eme",
-       "nav-login-createaccount": "Geɖe me / Ŋlɔ ŋkɔ",
-       "userlogin": "Ge ɖe eme / ŋlɔ ŋkɔ daɖi",
+       "nav-login-createaccount": "Geɖe me / Ƞlɔ ŋkɔ",
        "logout": "Do le eme",
        "userlogout": "Do le eme",
-       "nologin": "Wòmeŋlɔ ŋkɔ oa? '''$1'''.",
-       "nologinlink": "Ŋlɔ ŋkɔ daɖi",
-       "createaccount": "Ŋlɔ ŋkɔ daɖi",
-       "gotaccount": "Wò ŋlɔ ŋkɔ xoxoa? '''$1'''.",
-       "gotaccountlink": "Ge ɖe eme",
-       "loginsuccesstitle": "Wò ge ɖe eme azɔ̃.",
-       "loginsuccess": "'''Wò le {{SITENAME}} me fifia abe \"$1\" ene.'''",
-       "nouserspecified": "Elebe na ŋlɔ ŋkɔ si wò zãna",
-       "acct_creation_throttle_hit": "Wiki sia zãla aɖe tso wò ''IP address'' ŋlɔ {{PLURAL:$1|1 ŋkɔ|$1 ŋkɔwo}} le ŋkeke si vayi me xoxo. Mɔɖeɖe le na ŋkɔ  ɖeka ko ŋɔŋlɔ le ŋkeke ɖeka me.<br />\nLe esiata la, ''IP address'' sia zãlawo mekpɔ mɔ aŋlɔ ŋkɔ bubuwo fifia o.",
+       "userlogin-noaccount": "Ezazãŋkɔŋɔŋlɔ mele asiwò oa?",
+       "userlogin-joinproject": "Ŋlɔ ŋkɔ ɖe {{SITENAME}}",
+       "createaccount": "Ƞlɔ ŋkɔ da ɖi",
+       "userlogin-resetpassword-link": "Èŋlɔ wò mɔʋunyaa bea?",
+       "userlogin-helplink2": "Míkpe ɖe ŋunye mage ɖe eme",
+       "createacct-emailoptional": "Email adrɛs (ne èlɔ̃)",
+       "createacct-email-ph": "Ŋlɔ wò email adrɛs",
+       "createacct-submit": "Kpe wò ezazãŋkɔŋɔŋlɔ ɖo",
+       "createacct-benefit-heading": "Ame siwo le abe wò ene koe trɔ asi le {{SITENAME}} la ŋu.",
+       "createacct-benefit-body1": "{{PLURAL:$1|nugbugbɔŋlɔ|nugbugbɔŋlɔwo}}",
+       "createacct-benefit-body2": "{{PLURAL:$1|axa|axawo}}",
+       "createacct-benefit-body3": "yeyetɔ {{PLURAL:$1|contributor|contributors}}",
+       "loginsuccesstitle": "Ège ɖe eme.",
+       "loginsuccess": "'''Ele {{SITENAME}} me fifia abe \"$1\" ene.'''",
+       "nouserspecified": "Elebe na ŋlɔ wò dzesideŋkɔ",
+       "passwordtoolong": "Mɔʋunyawo mate ŋu adidi wu {{PLURAL:nuŋlɔdzesi $1|nuŋlɔdzesi 1|nuŋlɔdzesi $1}}.",
+       "acct_creation_throttle_hit": "Wiki sia zãla siwo zã wò IP adrɛs la wɔ {{PLURAL:ŋkɔŋlɔɖi $1|ŋkɔŋlɔɖi 1|ŋkɔŋlɔɖi $1}} xoxo le ŋkeke $2 va yi me, esiae nye gbogbotɔ si woɖe mɔ be woawɔ le ɣeyiɣi ƒe didime ma me. Eya ta ame aɖeke magate ŋu azã IP adrɛs sia fifia aŋlɔ ŋkɔ ɖi o.",
+       "emailauthenticated": "Woɖo kpe wò email adrɛs la dzi le $2 le ga $3.",
        "loginlanguagelabel": "Gbe: $1",
-       "sig_tip": "Dzesiwò kple gaƒoƒoa",
-       "subject": "Ta nya:",
+       "pt-login": "Ge ɖe eme",
+       "pt-login-button": "Ge Ɖe Eme",
+       "pt-createaccount": "Kpe ezazãŋkɔŋɔŋlɔ ɖo",
+       "pt-userlogout": "Do Le Eme",
+       "oldpassword": "Mɔʋunya xoxo:",
+       "newpassword": "Mɔʋunya yeye:",
+       "retypenew": "Gbugbɔ ŋlɔ mɔʋunyaa:",
+       "resetpass_submit": "Tia mɔʋunya eye nàge ɖe eme",
+       "changepassword-success": "Wò mɔʋunya la trɔ!",
+       "changepassword-throttled": "Ètee kpɔ be yeage ɖe eme hedo kpoe zi geɖe akpa le ɣeyiɣi kpui siawo me. Taflatsɛ lala $1 hafi nàgatee kpɔ.",
+       "botpasswords": "Mɔʋunya mɔ̀kpakpatɔwo",
+       "botpasswords-label-appid": "Ŋkɔ mɔ̀kpakpatɔ",
+       "botpasswords-label-create": "Wɔe",
+       "botpasswords-label-update": "Yeyetɔ Neɖɔlii",
+       "botpasswords-label-cancel": "Tasii",
+       "botpasswords-label-delete": "Tutui",
+       "botpasswords-label-resetpassword": "Trɔ mɔʋunyaa",
+       "resetpass-submit-loggedin": "Trɔ mɔʋunya",
+       "resetpass-submit-cancel": "Tasii",
+       "resetpass-wrong-oldpass": "Mɔʋunya si wona wò gbɔ alo wò mɔʋunya mede o.\n\nƉewohĩ ètrɔ wò mɔʋunya alo nèbia be woana bubu ye.",
+       "resetpass-recycled": "Taflatsɛ trɔ wò mɔʋunya wòato vovo na esi zãm nèle fifia.",
+       "resetpass-temp-emailed": "Èzã mɔʋunya si wona gbɔ la tsɔ le gegem ɖe eme.\nHafi nàte ŋu age ɖe eme keŋkeŋ la, ŋlɔ mɔʋunya yeye ɖe afi sia:",
+       "passwordreset": "Trɔ mɔʋunyaa",
+       "passwordreset-username": "Ezazãŋkɔ:",
+       "passwordreset-domain": "Nuwɔƒe:",
+       "passwordreset-email": "Email adrɛs:",
+       "passwordreset-emailtitle": "Ŋkɔŋlɔɖi ŋuti nyatakaka le {{ƉƆTEƑEŊKƆ}}",
+       "passwordreset-invalidemail": "Email adrɛs la mede o",
+       "passwordreset-nodata": "Mèŋlɔ ezazãŋkɔ alo email adrɛs aɖeke o",
+       "changeemail": "Trɔ email adrɛs alo ɖee ɖa",
+       "changeemail-header": "Kpe nyatakaka sia ɖo ne èdi be yeatrɔ wò email adrɛs la. Ke ne èdi be yeaɖe email ɖe sia ɖe si le wò ŋkɔŋlɔɖia me ɖa la, ke gblẽ afi si woɖo be woaŋlɔ email yeye ɖo la ɖi ƒuƒlu ne èle nyatakaka sia ɖom ɖa.",
+       "changeemail-no-info": "Ele be nàge ɖe eme hafi ate ŋu aʋu axa sia tẽe.",
+       "changeemail-oldemail": "Email adrɛs fifitɔ:",
+       "changeemail-newemail": "Email adrɛs yeye:",
+       "changeemail-none": "(ɖeke o)",
+       "changeemail-password": "Wò {{SITENAME}} ƒe mɔʋunya:",
+       "changeemail-submit": "Trɔ email la",
+       "changeemail-throttled": "Ètee kpɔ be yeage ɖe eme hedo kpoe zi geɖe akpa le ɣeyiɣi kpui siawo me. Taflatsɛ lala $1 hafi nàgatee kpɔ.",
+       "changeemail-nochange": "Taflatsɛ ŋlɔ email adrɛs yeye.",
+       "resettokens-watchlist-token": "Ɖɔɖeɖɔdzi nukakala (Atom/RSS) ƒe mɔfiadzesi nyaŋui ƒe [[Special:Tɔtrɔkpɔƒe|tɔtrɔ siwo wowɔ le axa siwo le wò tɔtrɔkpɔƒe ŋu]]",
+       "bold_sample": "Nuŋɔŋlɔ toto",
+       "bold_tip": "Nuŋɔŋlɔ toto",
+       "italic_sample": "Nuŋɔŋlɔ biɖeŋgɔ",
+       "italic_tip": "Nuŋɔŋlɔ biɖeŋgɔ",
+       "sig_tip": "Wò asidenute kple gaƒoƒoa",
+       "subject": "Tanya:",
        "minoredit": "Esia nye tɔtrɔ sue aɖe ko",
-       "watchthis": "Le ŋku ɖe axa sia ŋu",
+       "watchthis": "Kpɔ axa sia",
        "savearticle": "Dzra axa sia ɖo",
        "preview": "Kpɔe do ŋgɔ",
        "showpreview": "Fiae do ŋgɔ",
-       "showdiff": "Fia tɔtrɔwo",
+       "showdiff": "Fia tɔtrɔawo",
+       "loginreqlink": "ge ɖe eme",
+       "loginreqpagetext": "Taflatsɛ $1 ne nàkpɔ axa bubuwo.",
        "newarticle": "(Yeye)",
-       "newarticletext": "Eva ɖo axa si gɔme womedze haɖeke o. Ne wòadi be yeadze egɔme la, dze nuŋlɔm ɖe go sia me le afi sia ɖome (kpɔ [$1 kpekpeɖeŋu nyawo] na kpekpeɖeŋu bubuwo). Ne wòme ɖoe be yeava afii hafi o la, ekema tia '''megbe''' eye wòa gbugbɔ ayi afisi wòtso va.",
-       "previewnote": "'''Ɖo ŋku edzi be wole afii fiam do ŋgɔ, wome dzrae ɖo haɖeke o!'''",
+       "newarticletext": "Eva ɖo axa si gɔme womedze haɖeke o. Ne Nedi be yeadze egɔme la, dze nuŋɔŋlɔ͂ ɖe go sia me le afii (kpɔ [$1 kpekpeɖeŋu nyawo] na kpekpeɖeŋu bubuwo). Ne meɖoe be yeava afisia hafi o la, ekema tia '''megbe''' eye nagbugbɔ ayi afisi netso va.",
+       "previewnote": "<strong>Ɖo ŋkui be nua ƒe dzedzeme koe nye esia.</strong>\nWomekpɔ dzra tɔtrɔ siwo nèwɔ la ɖo haɖe o!",
        "editing": "$1 na etɔtrɔ",
-       "editingsection": "le $1 (ƒe akpa aɖe) trɔm",
+       "editingsection": "Nele $1 (ƒe akpa aɖe) trɔm",
        "yourtext": "Wò nuŋɔŋlɔ",
        "yourdiff": "Vovototowo",
-       "copyrightwarning": "Taflatse, mítsɔe be nusiwo katã netsɔ kpe ɖe {{SITENAME}} ŋu lii fãa le $2 la nu (kpɔ $1 me nyawo). Ne madze ŋuwò be amebubuwo natrɔ asi le nusiwo newɔ ŋuti o, eye woagbugbɔ dɔsiwo newɔ ama na amebubuwo fãa o la, mega dae ɖe afisia o.<br /> Wòle ŋugbe dom na mí bena wò ŋutɔe ŋlɔ nusiawo, alo etsɔe tso afisi mɔɖeɖe li fãa be amesiame na tsɔ nuwo tso afima fãa. '''Mega da nusiwo ŋu mɔɖeɖe meli na o la ɖe afisia o!'''",
+       "copyrightwarning": "Taflatse, mide dzesi be nusiwo katã mietsɔ kpe ɖe {{SITENAME}} ŋu lii fãa le $2 la nu (kpɔ $1 me nyawo). Ne madze ŋuwò be amebubuwo natrɔ asi le nusiwo neŋlɔ ŋuti o, eye woagbugbɔ dɔsiwo newɔ ama na amebubuwo fãa o la, mega dae ɖe afisia o.<br /> Nele kakaɖedzi nam mí be wò ŋutɔe ŋlɔ nusiawo, alo etsɔe tso afisi mɔɖeɖe li fãa be amesiame na tsɔ nuwo tso fãa. '''Mega da nusiwo ŋu mɔɖeɖe meli o la ɖe afisia o!'''",
+       "templatesused": "wozã {{PLURAL:$1|Template|Templates}} le axa sia:",
        "permissionserrorstext-withaction": "Se meɖe mɔ bena na $2 o, le {{PLURAL:$1|ta|ta}}:",
-       "edit-already-exists": "Wòmateŋu adze axa sia gɔme o.<br />\nWo ŋlɔe xoxo.",
-       "currentrev-asof": "Tata susue le $1 dzi",
+       "edit-already-exists": "Mateŋu adze axa sia gɔme o.<br />\nWoli xoxo.",
+       "currentrev": "Asitɔtrɔ yeyetɔ",
+       "currentrev-asof": "Asitɔtrɔ mamlea le $1 dzi",
        "revisionasof": "Tataa le $1",
-       "revision-info": "Tataa le $1 si $2 wɔ",
+       "revision-info": "Asitɔtrɔ si wowɔ le $1 eye ame si wɔe nye {{GENDER:$6|$2}}$7",
        "previousrevision": "← Tata xoxoa",
        "nextrevision": "Tata yeyea →",
-       "currentrevisionlink": "Tata susuea",
+       "currentrevisionlink": "Tata yeyetɔ",
        "cur": "yeyea",
-       "next": "eyome",
-       "last": "mamlea",
+       "next": "ŋgɔgbe",
+       "last": "doŋgɔ",
        "page_first": "gbãtɔ",
-       "page_last": "mamlea",
-       "histlegend": "Vovo tatia: de dzesi tata siwo ƒe vovototowo wò di be yea kpɔ ɖa eye na tia 'enter' alo kpe si le eɖome.<br />\nGɔmeɖeɖe: '''({{int:cur}})''' = vovototo tso tata mamlea gbɔ, '''({{int:last}})''' = vovototo tso tata si do ŋgɔ gbɔ, '''{{int:minoreditletter}}''' = tɔtrɔ sue.",
-       "history-show-deleted": "Esiwo wotutu ko",
-       "histfirst": "Xoxoɔwu",
-       "histlast": "Yeyeɛwu",
+       "page_last": "mamlɛ",
+       "histlegend": "Titia vovo: de dzesi tata siwo ƒe vovototowo nedi be yea kpɔ ɖa, eye na tia 'enter' alo kpe si le eɖome.<br />\nGɔmeɖeɖe: '''({{int:cur}})''' = vovototo tso tata mamlea gbɔ, '''({{int:last}})''' = vovototo tso tata si do ŋgɔ gbɔ, '''{{int:minoreditletter}}''' = tɔtrɔ suɛ.",
+       "history-fieldset-title": "Sra asitɔtrɔawo me",
+       "history-show-deleted": "Asitɔtrɔ siwo wotutu ko",
+       "histfirst": "Xoxotɔ",
+       "histlast": "Yeyetɔ",
+       "historysize": "({{PLURAL:$1|bite 1|bite $1}})",
+       "historyempty": "ƒuƒlu",
+       "history-feed-title": "Asitɔtrɔ vayiawo",
+       "history-feed-description": "Wiki ƒe axa sia ƒe asitɔtrɔ vayiawo",
        "history-feed-item-nocomment": "$1 le $2",
-       "history-feed-empty": "Axa si dim wòle meli o.\nDewomahĩ, wotutui le wiki sia dzi alo wotrɔ eƒe ŋkɔ.\nZã [[Special:Search|nuwo didi le wiki sia dzi]] kpɔ na axa yeyeawo.",
+       "history-feed-empty": "Axa si dim nele meli o.\nDewomahĩ, wotutui ɖa le wiki sia dzi alo wotrɔ eƒe ŋkɔ.\nZã [[Special:Search|nuwo didi le wiki sia dzi]] kpɔ na axa yeyeawo.",
        "rev-delundel": "fia/ɣla",
        "rev-showdeleted": "fia",
        "revdelete-radio-same": "(megatrɔe o)",
-       "revdelete-radio-set": "Yo",
-       "revdelete-radio-unset": "Kpao",
-       "history-title": "\"$1\" ƒe tata xoxoawo",
+       "revdelete-radio-set": "Ɣaɣla",
+       "revdelete-radio-unset": "Dzedze",
+       "history-title": "Asitɔtrɔ vayi si wowɔ le \"$1\"",
+       "difference-title": "Vovototo siwo le numetoto \"$1\" me",
        "lineno": "Fli $1:",
-       "compareselectedversions": "Kpɔ tata siwo wotia la",
-       "searchresults": "Nusiwo wòdi",
+       "compareselectedversions": "Tsɔ esiwo netia la tsɔ kpli wonɔewo",
+       "editundo": "gbugbɔe",
+       "diff-multi-sameuser": "({{AGBƆSƆSƆTƆ:$1|Ezalãa ƒe numetoto ɖeka|$1 intermediate revisions}} medze o)",
+       "searchresults": "Nusiwo nedi",
        "searchresults-title": "Nusiwo wofɔ le \"$1\" didi me",
-       "notextmatches": "Axa aɖeke ƒe nyawo mesɔ kple nyasiawo o.",
-       "prevn": "{{PLURAL:$1|$1}} do ŋgɔ",
-       "nextn": "{{PLURAL:$1|$1}} yometɔwo",
+       "notextmatches": "Axa aɖeke ƒe nyawo mesɔ kple esiawo o.",
+       "prevn": "{{PLURAL:$1|$1}} esiwo do ŋgɔ",
+       "nextn": "{{PLURAL:$1|$1}} esiwo tii ɖo",
+       "prev-page": "axa doŋgɔ",
+       "next-page": "axa kplɔeɖo",
        "viewprevnext": "Kpɔ ($1 {{int:pipe-separator}} $2) ($3)",
        "searchmenu-exists": "'''Axa si ŋkɔ enye \"[[:$1]]\" le wiki sia dzi'''",
        "searchmenu-new": "'''Dze axa \"[[:$1]]\" sia ŋlɔm ɖe wiki la dzi!'''",
-       "searchprofile-everything": "Nuɖesiaɖe",
+       "searchprofile-articles": "Edzinuwo ƒe axawo",
+       "searchprofile-images": "Mediahawo",
+       "searchprofile-everything": "Ɖe sia ɖe",
+       "searchprofile-advanced": "Deŋgɔtɔ",
        "searchprofile-articles-tooltip": "Dii le $1",
+       "searchprofile-images-tooltip": "Di faelwo",
+       "searchprofile-everything-tooltip": "Di nuwo katã (dzeɖoƒewo hã)",
+       "searchprofile-advanced-tooltip": "Dii le ŋkɔŋlɔƒe tiatia",
        "search-result-size": "$1 ({{PLURAL:$2|nya 1|nya $2}})",
        "search-suggest": "Ɖe wò be: $1",
-       "search-interwiki-more": "(kɔ kpe ɖe eŋu)",
-       "searchall": "wokatã",
-       "powersearch-toggleall": "Wokatã",
+       "search-interwiki-more": "(Geɖe wu)",
+       "searchall": "wo katã",
+       "powersearch-toggleall": "Wo katã",
        "preferences": "Didiwo",
-       "mypreferences": "Nyeƒe didiwo",
+       "mypreferences": "Tiatiawɔƒe",
        "skin-preview": "Kpɔe do ŋgɔ",
-       "prefs-watchlist-days-max": "Maximum $1 {{PLURAL:$1|day|days}}",
+       "prefs-watchlist-days-max": "{{PLURAL:$1|Ŋkeke|Ŋkeke}} agbɔsɔsɔ gbogbotɔe nye $1",
+       "prefs-misc": "Nu Kpotokpotoewo",
+       "prefs-resetpass": "Trɔ mɔʋunyaa",
        "timezoneregion-africa": "Afrika",
+       "timezoneregion-america": "Amerika",
+       "timezoneregion-antarctica": "Antarktika",
+       "timezoneregion-arctic": "Arctik",
+       "timezoneregion-asia": "Asia",
+       "timezoneregion-atlantic": "Atlantik-ƒu",
+       "timezoneregion-australia": "Australia",
+       "timezoneregion-europe": "Europa",
+       "timezoneregion-indian": "India-ƒu",
+       "timezoneregion-pacific": "Pasifik-ƒu",
        "yourlanguage": "Gbe:",
        "yournick": "Dzesi",
        "gender-male": "Ŋutsu",
        "group": "Hame:",
        "group-bot": "Bɔtwo",
        "group-sysop": "Dɔdzikpɔlawo",
-       "group-all": "(wokatã)",
-       "newuserlogpage": "Ŋkɔŋlɔla yeyewo ƒe xexlẽme",
+       "group-all": "(wo katã)",
+       "newuserlogpage": "Ƞkɔŋlɔla yeyeawo ƒe ŋutinya",
        "action-read": "xlẽ axa sia",
        "action-edit": "trɔ asi le axa sia ŋu",
-       "recentchanges": "Tɔtrɔ yeyewo",
+       "enhancedrc-history": "ʋuvayiawo",
+       "recentchanges": "Tɔtrɔ yeyeawo",
        "recentchanges-legend": "Tatiawo na tɔtrɔ yeyewo",
+       "recentchanges-label-newpage": "Tɔtrɔ sia to axa yeye vae",
+       "recentchanges-label-minor": "Tɔtrɔ vi aɖe koe",
+       "recentchanges-label-bot": "Mɔ́a ŋutɔe wɔ tɔtrɔ sia",
        "rcnotefrom": "Tɔtrɔwo siwo wowɔ tso '''$2''' (wofia vaseɖe '''$1''') le afii.",
        "rclistfrom": "Fia tɔtrɔ yeyewo tso $3 $2",
        "rcshowhideminor": "$1 tɔtrɔ suewo",
+       "rcshowhideminor-show": "Nedze",
+       "rcshowhideminor-hide": "Neɣla",
        "rcshowhidebots": "$1 bɔtwo",
+       "rcshowhidebots-show": "Nedze",
        "rcshowhideliu": "$1 ezãla siwo ŋlɔ ŋkɔ",
+       "rcshowhideliu-hide": "Neɣla",
        "rcshowhideanons": "$1 ŋkɔ maŋlɔlawo",
-       "rcshowhidemine": "$1 nyeƒe tɔtrɔwo",
+       "rcshowhideanons-show": "Nedze",
+       "rcshowhideanons-hide": "Neɣla",
+       "rcshowhidemine": "$1 nye tɔtrɔwo",
+       "rcshowhidemine-show": "Nedze",
+       "rcshowhidemine-hide": "Neɣla",
        "rclinks": "Fia tɔtrɔ $1 mamleawo le ŋkeke $2 siwo vayi me",
        "diff": "tɔtrɔ",
        "hist": "xoxo",
        "show": "Fia",
        "minoreditletter": "s",
        "newpageletter": "Y",
+       "boteditletter": "b",
+       "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} le etɔtrɔ megbe",
        "recentchangeslinked": "Tɔtrɔ siwo kaa afii",
        "recentchangeslinked-feed": "Tɔtrɔ siwo kaa afii",
        "recentchangeslinked-toolbox": "Tɔtrɔ siwo kaa afii",
        "recentchangeslinked-title": "Tɔtrɔ siwo ku ɖe \"$1\" ŋu",
+       "recentchangeslinked-summary": "Esiae nye tɔtrɔ siwo wowɔ le kadodo siwo woʋu tso axa aɖe koŋ (alo axawo ƒe hatsotso aɖe).\nWoŋlɔ axa siwo le [[Special:Watchlist|your watchlist]] dzi nuwo kple <strong> nuŋɔŋlɔ tòto</strong>.",
        "recentchangeslinked-page": "Axaa ƒe ŋkɔ",
        "upload": "Ɖo agbalẽ ɖa",
        "uploadbtn": "Ɖo agbalẽ ɖa",
+       "imgfile": "fael",
        "file-anchor-link": "Agbalẽ",
-       "filehist": "Axa sia ƒe tata xoxoawo",
+       "filehist": "Nutsɔ ʋuvayiwo",
        "filehist-help": "Tia ŋkeke/gaƒoƒo ɖeka ne wòadi be yea kpɔ axa sia ƒe tata le ɣemaɣi",
        "filehist-deleteone": "tutui",
        "filehist-datetime": "Ŋkeke/Gaƒoƒo",
        "filehist-user": "Ezãla",
+       "imagelinks": "Nyatakagbaa zazã",
        "linkstoimage": "Axa {{PLURAL:$1|sia|$1 siawo}} ku ɖe agbalẽ sia ŋu.",
+       "nolinkstoimage": "Axa aɖeke medo ka kple fael sia o.",
        "sharedupload": "Agbalɛ̃ sia tso $1 eye dɔ (''alo project'') bubuawo woateŋu azãe fãa.",
+       "sharedupload-desc-here": "Nyatakagba sia tso $1 eye ɖoɖo bubuwo hã anya nɔ ezãm.\nEŋutinyatakakawo dze [$2 nyatakagba ŋuti nya] le ete.",
+       "upload-disallowed-here": "Màte ŋu atutu fael sia o.",
        "filedelete-submit": "Tutui",
        "mimesearch": "MIME me didi",
        "randompage": "Axaa ɖe ko",
        "randompage-nopages": "Axa aɖeke mele \"$1\" o.",
+       "randomincategory-submit": "Yi",
        "statistics": "Akɔntawo",
        "brokenredirects-edit": "trɔ asi le eŋu",
        "brokenredirects-delete": "tutui",
        "fewestrevisions": "Axawo siwo womeɖɔɖo zã o",
+       "nbytes": "$1 {{PLURAL:$1|bite|bitewo}}",
        "wantedpages": "Axawo siwo le hahĩam",
        "mostrevisions": "Axawo siwo woɖɔɖo wu",
        "shortpages": "Axa kpuiwo",
        "pager-older-n": "{{PLURAL:$1|1 xoxoa|$1 xoxoawo}}",
        "booksources": "Agbalɛ̃wo ƒe tsoƒe",
        "booksources-search-legend": "Di agbalẽwo ƒe tsoƒewo",
+       "booksources-search": "Di",
        "specialloguserlabel": "Ezãla:",
        "speciallogtitlelabel": "Ta nya:",
        "allpages": "Axawo katã",
        "delete-confirm": "Tutu \"$1\"",
        "delete-legend": "Tutui",
        "actioncomplete": "Wowɔe vɔ",
+       "dellogpage": "Tutu nu ʋuʋuawo",
        "dellogpagetext": "Afisia wofia axa mamleawo siwo wotutu la",
+       "rollbacklink": "gbugbɔ tɔtrɔa",
        "prot_1movedto2": "[[$1]] wohee yi [[$2]]",
        "protect-default": "Namɔ ezãlawo katã",
        "protect-level-autoconfirmed": "Xemɔ na ame yeyewo kple ŋkɔmaŋlɔlawo",
        "undeleteviewlink": "kpɔe",
        "undelete-search-submit": "Dii",
        "undelete-show-file-submit": "Yo",
+       "namespace": "Ŋkɔŋlɔƒe",
        "invert": "Trɔ tatiawo tu",
-       "contributions": "Ezãla ƒe nuŋɔŋlɔwo",
+       "blanknamespace": "(Vevitɔ)",
+       "contributions": "{{ŊUTSU/NYƆNU:$1|Ezãla}} ƒe asikpeɖeŋuwo",
        "contributions-title": "$1 ƒe nuŋɔŋlɔwo",
        "mycontris": "Nyeƒe nuŋɔŋlɔwo",
        "contribsub2": "Na $1 ($2)",
-       "uctop": "(tametɔ)",
+       "uctop": "tametɔ",
        "month": "Tso ɣleti (kple do ŋgɔ):",
        "year": "Tso ƒe (kple do ŋgɔ):",
        "sp-contributions-newbies": "Fia ŋkɔŋlɔla yeyewo ƒe ɖɔɖɔɖowo ko.",
        "sp-contributions-talk": "Nyamedzroƒe",
        "sp-contributions-search": "Di nuŋɔŋlɔwo",
        "sp-contributions-submit": "Dii",
-       "whatlinkshere": "Nusiwo kaa afii ŋu",
+       "whatlinkshere": "Kadodo si le afi sia",
        "whatlinkshere-title": "Axawo siwo ku ɖe \"$1\" ŋu",
        "whatlinkshere-page": "Axa:",
-       "linkshere": "Axa siwo le afisia ku ɖe '''[[:$1]]''' ŋu:",
-       "nolinkshere": "Axa aɖeke meku ɖe '''[[:$1]]''' ŋu o.",
+       "linkshere": "Axa siwo le afisia ku ɖe '''$2''' ŋu:",
+       "nolinkshere": "Axa aɖeke meku ɖe '''$2''' ŋu o.",
+       "isredirect": "trɔ axa yi afi bubu",
+       "isimage": "fael ƒe kadodo",
        "whatlinkshere-prev": "{{PLURAL:$1|do ŋgɔ|$1 do ŋgɔ}}",
        "whatlinkshere-next": "{{PLURAL:$1|eyome|$1 eyome}}",
+       "whatlinkshere-links": "← kadodowo",
        "blockip": "Xe mɔ na ezãla sia",
-       "blockip-legend": "Xe mɔ na ezãla sia",
-       "ipbexpiry": "Nuwuwu:",
        "ipboptions": "gaƒoƒo 2:2 hours,ŋkeke 1:1 day,ŋkeke 3:3 days,kɔsiɖa 1:1 week,kɔsiɖa 2:2 weeks,ɣleti 1:1 month,ɣleti 3:3 months,ɣleti 6:6 months,ƒe 1:1 year,tegbe:infinite",
        "blockipsuccesssub": "Mɔxexea dze edzi",
        "ipb-unblock-addr": "Ɖe $1 ƒe mɔxexe ɖa",
        "ipb-blocklist": "Kpɔ mɔxexe siwo li xoxo",
        "ipb-blocklist-contribs": "$1 ƒe nuŋɔŋlɔwo",
+       "block-expiry": "Nuwuwu:",
        "ipusubmit": "Ɖe mɔxexe sia ɖa",
        "ipblocklist-submit": "Dii",
        "infiniteblock": "tegbee",
        "blocklogentry": "xemɔ na [[$1]] vaseɖe $2 megbe $3",
        "block-log-flags-nocreate": "wo xemɔ na ŋkɔ ŋɔŋlɔ",
        "move-page-legend": "Ɖɔli eƒe nɔƒe",
-       "movearticle": "Ɖɔli eƒe nɔƒe:",
        "newtitle": "Yi ɖe tanya yeye la:",
        "move-watch": "Le ŋku ɖe axa sia ŋu",
        "movepagebtn": "Ɖɔli eƒe nɔƒe",
        "movepage-moved": "'''Wohe \"$1\" vayi \"$2\"'''",
        "articleexists": "Tanya alo ŋkɔ sia nye axa bubu aɖe tɔ xoxo, alo eda se dzi.\nTia ŋkɔ alo tanya bubu.",
        "cantmove-titleprotected": "Wòmateŋu ahe axa aɖeke va afii o, elabena wo xemɔ na tanya sia ƒe ŋɔŋlɔ",
+       "movelogpage": "Ɖe nu ʋuʋuawo dzoe",
        "export": "Ɖo axa siawo ɖa",
        "allmessages": "Gbeƒãɖeɖewo",
        "allmessages-filter-all": "Wokatã",
        "tooltip-pt-mycontris": "Wò nuŋɔŋlɔwo ƒe xexlẽme",
        "tooltip-pt-login": "Togbɔ be menye ɖe wò hĩa o tse la, mía ve nuwò bena na ŋlɔ ŋkɔ",
        "tooltip-pt-logout": "Do le eme",
-       "tooltip-ca-edit": "Wòateŋu aɖɔ axa sia ɖo.\nNe ewɔvɔ la, tia \"Fiae do ŋgɔ\" kpea gbã hafi na dzrae ɖo.",
+       "tooltip-pt-createaccount": "Míedi dzi ƒo na wò be nàkpe ezazãŋkɔŋɔŋlɔ yeye ɖo eye nàge ɖe eme; ke hã, mehiã godoo o",
+       "tooltip-ca-talk": "Nyamedzodzro tso edzinuwo ƒe axa ŋu",
+       "tooltip-ca-edit": "Trɔ asi le axa sia ŋu",
        "tooltip-ca-addsection": "Dze akpa yeye gɔme",
        "tooltip-ca-viewsource": "Wo dokpɔ ɖe axa sia ŋu.\nWòateŋu akpɔ alesi woŋlɔe.",
        "tooltip-ca-history": "Axa sia ƒe tata xoxoawo",
        "tooltip-ca-protect": "Dzɔ axa sia ŋu",
        "tooltip-ca-delete": "Tutu axa sia",
        "tooltip-ca-move": "Ɖɔli axa sia ƒe nɔƒe",
+       "tooltip-ca-watch": "Dzra axa sia ɖo ɖe wò axadadzraɖoƒe",
        "tooltip-search": "Dii {{SITENAME}}",
        "tooltip-search-go": "Yi axa si ƒe ŋkɔ enye esia ne woŋlɔe xoxo",
        "tooltip-search-fulltext": "Di nyasiawo le axawo me.",
+       "tooltip-p-logo": "Yi axa vevitɔ",
        "tooltip-n-mainpage": "Yi axa si do ŋgɔ",
        "tooltip-n-mainpage-description": "Yi axa si do ŋgɔ",
+       "tooltip-n-portal": "Nu siwo tso dɔwɔna la ŋu, nu siwo nàte ŋu awɔ, afi siwo nàte ŋu akpɔ nuawo le",
+       "tooltip-n-currentevents": "Kpɔ nu siwo le dzɔdzɔm fifia ŋuti nyatakakawo",
        "tooltip-n-recentchanges": "Tɔtrɔ yeyewo le wiki sia me.",
        "tooltip-n-randompage": "Kpɔ axa ɖesiaɖe ko",
        "tooltip-n-help": "Nuwo srɔ̃ƒe",
        "tooltip-t-contributions": "Kpɔ nusiwo amesia ŋlɔ",
        "tooltip-t-upload": "Ɖo nutatawo kple nuƒoƒowo ɖa",
        "tooltip-t-specialpages": "Axa tɔxewo ƒe xexlẽme",
+       "tooltip-t-print": "Axa ƒomevi si woate ŋu ata",
+       "tooltip-t-permalink": "Asitɔtrɔ si wowɔ le axa sia ƒe kadodo liɖaa",
        "tooltip-ca-nstab-main": "Kpɔ axa si tanyawo le",
-       "tooltip-ca-nstab-special": "Axa sia nye axa tɔxe.  Wò mateŋu atrɔ nu aɖeke le edzi o.",
+       "tooltip-ca-nstab-special": "Esia nye axa tɔxɛ, eye womate ŋu atrɔe o",
+       "tooltip-ca-nstab-image": "Kpɔ fael la ƒe axa",
        "tooltip-minoredit": "Esia nye tɔtrɔ sue aɖe ko",
        "tooltip-save": "Dzra wòƒe tɔtrɔwo ɖo",
        "tooltip-preview": "Kpɔ wò ɖɔɖɔɖowo do ŋgɔ, mía ve nuwo bena na zãe hafi na dzrae ɖo!",
        "tooltip-diff": "Fia tɔtrɔ siwo newɔ le nuŋɔŋlɔa me",
        "tooltip-compareselectedversions": "Kpɔ vovototwo le axa sia ƒe tata eve siwo wotia la me",
+       "tooltip-summary": "Ŋlɔ numeɖeɖe kpui aɖe",
+       "simpleantispam-label": "Ŋkuléle ɖe Anti-spam ŋu.\nŊlɔ esia <strong> ɖe eme ke menye esia </strong> o!",
+       "pageinfo-subpages-name": "Axa sia ƒe axamexɛwo ƒe xexlẽme",
+       "pageinfo-magic-words": "Madziki {{GBƆSƆSƆTƆ:$1|nya|nyawo}} ($1)",
+       "pageinfo-toolboxlink": "Axaa ŋuti nyatakaka",
        "previousdiff": "← Tata xoxoa",
        "nextdiff": "Tɔtrɔ yeyea →",
+       "file-nohires": "Kɔ̀kɔme si de ŋgɔ wu meli o.",
+       "show-big-image-size": "$1 × $2 pixelwo",
        "newimages": "Nutata yeyewo",
        "ilsubmit": "Dii",
        "namespacesall": "wokatã",
        "version": "Tata",
        "fileduplicatesearch-submit": "Dii",
        "specialpages": "Axa tɔxewo",
+       "tag-list-wrapper": "[[Tɔxɛ: Desidenyawo|{{PLURAL:$1|Desidenya|Desidenyawo}}]]: $2",
        "tags-edit": "trɔ asi le eŋu",
+       "logentry-move-move": "$1 {{ŊUTSU/NYƆNU:$2|moved}} axa $3 yi $4",
+       "logentry-newusers-create": "Ezazãŋkɔ $1 la {{AMENYENYE:$2|wɔ vɔ}}",
+       "logentry-upload-upload": "Nedze",
+       "searchsuggest-search": "Di {{SITENAME}}",
        "expand_templates_preview": "Kpɔe do ŋgɔ"
 }
index 45f0c13..32114a4 100644 (file)
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[vésta da {{PLURAL:$1|un utèint|$1 utèint}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|byte}} dôp la mudéfica",
        "newsectionsummary": "/* $1 */ sesiòn nōva",
        "rc-enhanced-expand": "Fà vèder i particulêr.",
index 160b2c2..1e0b8e9 100644 (file)
        "tog-norollbackdiff": "Παράλειψη εμφάνισης διαφορών μετά την εκτέλεση επαναφοράς",
        "tog-useeditwarning": "Προειδοποίηση όταν εγκαταλείπω μία σελίδα επεξεργασίας χωρίς να έχω πρώτα αποθηκεύσει τις αλλαγές",
        "tog-prefershttps": "Να γίνεται πάντα χρήση ασφαλούς σύνδεσης ενώ είμαι σε σύνδεση",
+       "tog-showrollbackconfirmation": "Εμφάνιση μιας ερώτησης επιβεβαίωσης όταν πατάτε ένα σύνδεσμο αναστροφής",
        "underline-always": "Πάντα",
        "underline-never": "Ποτέ",
        "underline-default": "Προεπιλογή από θέμα εμφάνισης ή από περιηγητή",
        "returnto": "Επιστροφή στη σελίδα $1.",
        "tagline": "Από {{SITENAME}}",
        "help": "Βοήθεια",
+       "help-mediawiki": "Βοήθεια για το MediaWiki",
        "search": "Αναζήτηση",
        "search-ignored-headings": "#<!-- αφήστε αυτή τη γραμμή όπως είναι --> <pre>\n# Επικεφαλίδες που θα αγνοηθούν από την αναζήτηση.\n# Αλλαγές σε αυτό ισχύουν μόλις η σελίδα με τον τίτλο ευρετηριαστεί.\n# Μπορείτε να επιβάλετε επανευρετηρίαση της σελίδας κάνοντας μια κενή επεξεργασία.\n# Η σύνταξη είναι ως εξής:\n# * Όλα από ένα χαρακτήρα \"#\" μέχρι το τέλος της γραμμής είναι ένα σχόλιο.\n# * Κάθε μη κενή γραμμή είναι ο ακριβής τίτλος που θα αγνοήσει, κεφαλαία/πεζά και τα πάντα.\nΠαραπομπές\nΕξωτερικοί σύνδεσμοι\nΔείτε επίσης\n #</pre> <!-- leave this line exactly as it is -->",
        "searchbutton": "Αναζήτηση",
        "history_short": "Ιστορικό",
        "history_small": "ιστορικό",
        "updatedmarker": "ενημερώθηκαν από την τελευταία επίσκεψή μου",
-       "printableversion": "Î\95κÏ\84Ï\85Ï\80Ï\8eÏ\83ιμη Î­ÎºÎ´Î¿Ï\83η",
+       "printableversion": "Î\88κδοÏ\83η ÎµÎºÏ\84Ï\8dÏ\80Ï\89Ï\83ηÏ\82",
        "permalink": "Σταθερός σύνδεσμος",
        "print": "Εκτύπωση",
        "view": "Προβολή",
        "badarticleerror": "Η ενέργεια αυτή δεν μπορεί να εκτελεσθεί σε αυτήν τη σελίδα.",
        "cannotdelete": "Η σελίδα ή το αρχείο «$1» δεν μπόρεσε να διαγραφεί.\nΕνδεχομένως να έχει ήδη διαγραφεί από κάποιον άλλον.",
        "cannotdelete-title": "Δεν είναι δυνατή η διαγραφή της σελίδας «$1»",
+       "delete-scheduled": "Η σελίδας «$1» είναι προγραμματισμένη για διαγραφή.\nΠαρακαλούμε έχετε υπομονή.",
        "delete-hook-aborted": "Η επεξεργασία ματαιώθηκε από το άγκιστρο του συντακτικού αναλυτή.\nΔεν έδωσε εξήγηση.",
        "no-null-revision": "Δεν ήταν δυνατή η δημιουργία νέας μηδενικής αναθεώρησης για τη σελίδα «$1»",
        "badtitle": "Ακατάλληλος τίτλος",
        "customcssprotected": "Δεν έχετε δικαιώματα για να επεξεργαστείτε αυτή τη σελίδα CSS, επειδή περιέχει προσωπικές ρυθμίσεις άλλου χρήστη.",
        "customjsonprotected": "Δεν έχετε δικαιώματα για να επεξεργαστείτε αυτή τη σελίδα JSON, επειδή περιέχει προσωπικές ρυθμίσεις άλλου χρήστη.",
        "customjsprotected": "Δεν έχετε δικαιώματα για να επεξεργαστείτε αυτή τη σελίδα JavaScript, επειδή περιέχει προσωπικές ρυθμίσεις άλλου χρήστη.",
+       "sitecssprotected": "Δεν έχετε την άδεια να επεξεργαστείτε αυτήν τη σελίδα CSS επειδή μπορεί να επηρεάσει όλους τους επισκέπτες.",
+       "sitejsonprotected": "Δεν έχετε την άδεια να επεξεργαστείτε αυτήν τη σελίδα JSON επειδή μπορεί να επηρεάσει όλους τους επισκέπτες.",
+       "sitejsprotected": "Δεν έχετε την άδεια να επεξεργαστείτε αυτήν τη σελίδα JavaScript επειδή μπορεί να επηρεάσει όλους τους επισκέπτες.",
        "mycustomcssprotected": "Δεν έχετε άδεια για να επεξεργαστείτε αυτήν τη σελίδα CSS.",
        "mycustomjsonprotected": "Δεν έχετε άδεια για να επεξεργαστείτε αυτήν τη σελίδα JSON.",
        "mycustomjsprotected": "Δεν έχετε άδεια για να επεξεργαστείτε αυτήν τη σελίδα JavaScript.",
        "userlogin-yourname": "Όνομα χρήστη",
        "userlogin-yourname-ph": "Εισαγάγετε το όνομα χρήστη σας",
        "createacct-another-username-ph": "Εισαγάγετε το όνομα χρήστη",
-       "yourpassword": "Î\9aÏ\89δικÏ\8cÏ\82:",
-       "userlogin-yourpassword": "Î\9aÏ\89δικÏ\8cÏ\82",
+       "yourpassword": "ΣÏ\85νθημαÏ\84ικÏ\8c:",
+       "userlogin-yourpassword": "ΣÏ\85νθημαÏ\84ικÏ\8c",
        "userlogin-yourpassword-ph": "Εισαγάγετε το συνθηματικό σας",
        "createacct-yourpassword-ph": "Εισαγωγή κωδικού",
        "yourpasswordagain": "Επαναπληκτρολόγηση κωδικού:",
        "badretype": "Οι κωδικοί που έχετε δηλώσει δεν συμφωνούν μεταξύ τους.",
        "usernameinprogress": "Είναι ήδη σε εξέλιξη δημιουργία λογαριασμού για αυτό το όνομα χρήστη.\nΠαρακαλούμε περιμένετε.",
        "userexists": "Το όνομα χρήστη που εισαγάγατε βρίσκεται ήδη σε χρήση.\nΠαρακαλούμε, διαλέξτε ένα διαφορετικό.",
+       "createacct-normalization": "Το όνομα χρήστη σας θα προσαρμοστεί σε «$2» λόγω τεχνικών περιορισμών.",
        "loginerror": "Σφάλμα σύνδεσης",
        "createacct-error": "Σφάλμα δημιουργίας λογαριασμού",
        "createaccounterror": "Δεν ήταν δυνατή η δημιουργία λογαριασμού: $1",
        "nosuchusershort": "Δεν υπάρχει χρήστης με το όνομα \"$1\". Παρακαλούμε ελέγξτε την ορθογραφία.",
        "nouserspecified": "Πρέπει να ορίσετε ένα όνομα χρήστη.",
        "login-userblocked": "Αυτός ο χρήστης έχει αποκλειστεί. Δεν επιτρέπεται σύνδεση.",
-       "wrongpassword": "Εισήχθη λανθασμένο όνομα χρήστη ή κωδικός.\nΠαρακαλούμε προσπαθήστε ξανά.",
-       "wrongpasswordempty": "Î\9f ÎºÏ\89δικÏ\8cÏ\82 Ï\80Ï\81Ï\8cÏ\83βαÏ\83ηÏ\82 Ï\80οÏ\85 ÎµÎ¹Ï\83άÏ\87θηκε Î®Ï\84αν ÎºÎµÎ½Ï\8cÏ\82. Παρακαλούμε προσπαθήστε ξανά.",
+       "wrongpassword": "Εισήχθη λανθασμένο όνομα χρήστη ή συνθηματικό.\nΠαρακαλούμε προσπαθήστε ξανά.",
+       "wrongpasswordempty": "Το Ï\83Ï\85νθημαÏ\84ικÏ\8c Ï\80οÏ\85 ÎµÎ¹Ï\83ήÏ\87θη Î®Ï\84αν ÎºÎµÎ½Ï\8c. Παρακαλούμε προσπαθήστε ξανά.",
        "passwordtooshort": "Οι κωδικοί πρέπει να περιέχουν τουλάχιστον {{PLURAL:$1|1 χαρακτήρα|$1 χαρακτήρες}}.",
        "passwordtoolong": "Οι κωδικοί πρόσβασης δεν μπορούν να υπερβαίνουν {{PLURAL:$1|τον 1 χαρακτήρα|τους $1 χαρακτήρες}}.",
        "passwordtoopopular": "Κοινότυπα συνθηματικά που τείνουν να επιλέγονται συχνά από τους χρήστες δεν μπορούν να χρησιμοποιηθούν. Παρακαλούμε επιλέξτε ένα συνθηματικό που είναι πιο δύσκολο να μαντεφθεί.",
-       "passwordinlargeblacklist": "Î\9f ÎºÏ\89δικÏ\8cÏ\82 Ï\80Ï\81Ï\8cÏ\83βαÏ\83ηÏ\82 Ï\80οÏ\85 ÎµÎ¹Ï\83ήÏ\87θηκε ÎµÎ¯Î½Î±Î¹ Ï\83ε Î¼Î¹Î± Î»Î¯Ï\83Ï\84α Ï\80ολÏ\8d ÎºÎ¿Î¹Î½Ï\8eν ÎºÏ\89δικÏ\8eν Ï\80Ï\81Ï\8cÏ\83βαÏ\83ηÏ\82 Ï\80οÏ\85 Ï\87Ï\81ηÏ\83ιμοÏ\80οιοÏ\8dνÏ\84αι. Î Î±Ï\81ακαλÏ\8e Î´Î¹Î±Î»Î­Î¾Ï\84ε Î­Î½Î±Î½ Ï\80ιο Ï\83Ï\85νηθιÏ\83μένο ÎºÏ\89δικÏ\8c Ï\80Ï\81Ï\8cÏ\83βαÏ\83ηÏ\82.",
+       "passwordinlargeblacklist": "Το Ï\83Ï\85νθημαÏ\84ικÏ\8c Ï\80οÏ\85 ÎµÎ¹Ï\83ήÏ\87θη ÎµÎ¯Î½Î±Î¹ Ï\83ε Î¼Î¹Î± Î»Î¯Ï\83Ï\84α Ï\80ολÏ\8d Ï\83Ï\85Ï\87νά Ï\87Ï\81ηÏ\83ιμοÏ\80οιοÏ\8dμενÏ\89ν Ï\83Ï\85νθημαÏ\84ικÏ\8eν. Î Î±Ï\81ακαλοÏ\8dμε ÎµÏ\80ιλέξÏ\84ε ÎºÎ¬Ï\80οιο Ï\80ιο Î¼Î¿Î½Î±Î´Î¹ÎºÏ\8c Ï\83Ï\85νθημαÏ\84ικÏ\8c.",
        "password-name-match": "Ο κωδικός σου θα πρέπει να είναι διαφορετικός από το όνομα χρήστη σου.",
        "password-login-forbidden": "Η χρήση αυτού του ονόματος χρήστη και συνθηματικού έχουν  απαγορευτεί.",
        "mailmypassword": "Επαναφορά κωδικού",
-       "passwordremindertitle": "Καινούργιος προσωρινός κωδικός για το {{SITENAME}}",
+       "passwordremindertitle": "Καινούργιο προσωρινό συνθηματικό για το {{SITENAME}}",
        "passwordremindertext": "Κάποιος (από τη διεύθυνση IP $1) αιτήθηκε νέο συνθηματικό για τον ιστότοπο {{SITENAME}} ($4). Έχει δημιουργηθεί το προσωρινό συνθηματικό «$3» για το χρήστη «$2». Αν ήταν αυτή η πρόθεσή σας, θα πρέπει να συνδεθείτε και να αλλάξετε το συνθηματικό σας τώρα. Το προσωρινό σας συνθηματικό θα λήξει σε {{PLURAL:$5|μια ημέρα|$5 ημέρες}}.\n\nΕάν αυτό το αίτημα έγινε από κάποιον τρίτο, ή αν θυμηθήκατε το συνθηματικό σας και δεν επιθυμείτε πλέον να το αλλάξετε, μπορείτε να αγνοήσετε αυτό το μήνυμα και να συνεχίσετε να χρησιμοποιείτε το παλιό σας συνθηματικό.",
        "noemail": "Δεν έχει καθοριστεί ηλεκτρονική διεύθυνση για τον χρήστη \"$1\".",
        "noemailcreate": "Είναι απαραίτητο να υποβάλλετε μια έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου",
-       "passwordsent": "Σας έχει σταλεί ένας νέος κωδικός στην ηλεκτρονική διέθυνση που δηλώσατε για \"$1\".\nΣας παρακαλούμε να ξανασυνδεθείτε μόλις τον λάβετε.",
+       "passwordsent": "Σας έχει σταλεί ένα νέο συνθηματικό στη διεύθυνση ηλεκτρονικού ταχυδρομείου που δηλώσατε για «$1».\nΠαρακαλούμε να ξανασυνδεθείτε μόλις το λάβετε.",
        "blocked-mailpassword": "Η διεύθυνση IP σας δεν έχει δικαίωμα επεξεργασίας. Για την αποφυγή κατάχρησης, δεν επιτρέπεται να χρησιμοποιήσετε την λειτουργία ανάκτησης κωδικού πρόσβασης από αυτήν την IP.",
        "eauthentsent": "Ένα μήνυμα επαλήθευσης έχει σταλεί στην ηλεκτρονική διεύθυνση που έχετε δηλώσει.\nΠριν αρχίσει η αποστολή μηνυμάτων στη συγκεκριμένη διεύθυνση, πρέπει να ακολουθήσετε τις οδηγίες που βρίσκονται στο μήνυμα που σας έχει σταλεί, για να επαληθεύσετε ότι η συγκεκριμένη ηλεκτρονική διεύθυνση ανήκει πραγματικά σε εσάς.",
        "throttled-mailpassword": "Ένα email επαναφοράς κωδικού έχει ήδη αποσταλεί, μέσα {{PLURAL:$1|στην τελευταία ώρα|στις τελευταίες $1 ώρες}}.\nΓια την αποφυγή κατάχρησης, μόνο ένα email επαναφοράς κωδικού θα στέλνεται ανά {{PLURAL:$1|ώρα|$1 ώρες}}.",
        "resetpass_announce": "Για να ολοκληρώσετε τη σύνδεση πρέπει να καθορίσετε νέο συνθηματικό.",
        "resetpass_text": "<!-- Προσθέστε κείμενο εδώ -->",
        "resetpass_header": "Αλλαγή κωδικού πρόσβασης",
-       "oldpassword": "Παλιός κωδικός",
-       "newpassword": "Νέος κωδικός πρόσβασης",
+       "oldpassword": "Παλιό συνθηματικό:",
+       "newpassword": "Νέο συνθηματικό:",
        "retypenew": "Πληκτρολογήστε ξανά το νέο συνθηματικό:",
        "resetpass_submit": "Καθορίστε συνθηματικό και συνδεθείτε",
-       "changepassword-success": "Î\9f ÎºÏ\89δικÏ\8cÏ\82 Ï\80Ï\81Ï\8cÏ\83βαÏ\83ήÏ\82 σας άλλαξε!",
+       "changepassword-success": "Το Ï\83Ï\85νθημαÏ\84ικÏ\8c σας άλλαξε!",
        "changepassword-throttled": "Κάνατε πάρα πολλές πρόσφατες απόπειρες σύνδεσης.\nΠαρακαλούμε περιμένετε $1 προτού ξαναδοκιμάσετε.",
        "botpasswords": "Συνθηματικά για ρομπότ",
        "botpasswords-summary": "<em>Τα συνθηματικά για ρομπότ</em> επιτρέπουν πρόσβαση σε λογαριασμό χρήστη μέσω του API χωρίς να χρησιμοποιούνται τα κύρια διαπιστευτήρια σύνδεσης του λογαριασμού. Τα διαθέσιμα δικαιώματα χρήστη όταν είναι σε σύνδεση μέσω συνθηματικού για ρομπότ μπορεί να είναι περιορισμένα.\n\nΑν δεν ξέρετε γιατί να το κάνετε αυτό, καλύτερα να μην το κάνετε. Κανείς ποτέ δεν πρέπει να σας ζητήσει να δημιουργήσετε ένα τέτοιο συνθηματικό και να του το γνωστοποιήσετε.",
        "botpasswords-existing": "Υπάρχοντα συνθηματικά ρομπότ",
        "botpasswords-createnew": "Δημιουργία νέου συνθηματικού ρομπότ",
        "botpasswords-editexisting": "Επεξεργασία υπάρχοντος συνθηματικού ρομπότ",
+       "botpasswords-label-needsreset": "(το συνθηματικό θέλει ανανέωση)",
        "botpasswords-label-appid": "Όνομα του ρομπότ:",
        "botpasswords-label-create": "Δημιουργία",
        "botpasswords-label-update": "Ενημέρωση",
        "botpasswords-updated-body": "Το συνθηματικό για το ρομπότ με όνομα «$1» του χρήστη «$2» ενημερώθηκε.",
        "botpasswords-deleted-title": "Το συνθηματικό του ρομπότ διαγράφηκε",
        "botpasswords-deleted-body": "Το συνθηματικό για το όνομα μποτ \"$1\" του χρήστη \"$2\" διαγράφηκε.",
-       "botpasswords-newpassword": "Î\9f Î½Î­Î¿Ï\82 ÎºÏ\89δικÏ\8cÏ\82 Ï\80Ï\81Ï\8cÏ\83βαÏ\83ηÏ\82 Î³Î¹Î± Î½Î± Ï\83Ï\85νδεθείÏ\84ε Î¼Îµ Ï\84ο <strong>$1</strong> ÎµÎ¯Î½Î±Î¹ <strong>$2</strong>. <em>ΠαÏ\81ακαλοÏ\8dμε Ï\83ημειÏ\8eÏ\83Ï\84ε Ï\84ο Î³Î¹Î± Î¼ÎµÎ»Î»Î¿Î½Ï\84ική Î±Î½Î±Ï\86οÏ\81ά.</em><br />(Î\93ια Ï\80αλιά bot Ï\80οÏ\85 Î±Ï\80αιÏ\84οÏ\8dν Ï\84ο Ï\8cνομα Ï\83Ï\8dνδεÏ\83ηÏ\82 Î½Î± ÎµÎ¯Î½Î±Î¹ Ï\84ο Î¯Î´Î¹Î¿ Î¼Îµ Ï\84ο Ï\84ελικÏ\8c Ï\8cνομα Ï\87Ï\81ήÏ\83Ï\84η, Î¼Ï\80οÏ\81είÏ\84ε ÎµÏ\80ίÏ\83ηÏ\82 Î½Î± Ï\87Ï\81ηÏ\83ιμοÏ\80οιήÏ\83εÏ\84ε Ï\84ο  <strong>$3</strong> Ï\89Ï\82 Ï\8cνομα Ï\87Ï\81ήÏ\83Ï\84η ÎºÎ±Î¹ <strong>$4</strong> Ï\89Ï\82 ÎºÏ\89δικό.)",
+       "botpasswords-newpassword": "Το Î½Î­Î¿ Ï\83Ï\85νθημαÏ\84ικÏ\8c Î³Î¹Î± Î½Î± Ï\83Ï\85νδεθείÏ\84ε Î¼Îµ Ï\84ο <strong>$1</strong> ÎµÎ¯Î½Î±Î¹ <strong>$2</strong>. <em>ΠαÏ\81ακαλοÏ\8dμε Ï\83ημειÏ\8eÏ\83Ï\84ε Ï\84ο Î³Î¹Î± Î¼ÎµÎ»Î»Î¿Î½Ï\84ική Î±Î½Î±Ï\86οÏ\81ά.</em><br />(Î\93ια Ï\80αλιά Ï\81ομÏ\80Ï\8cÏ\84 Ï\80οÏ\85 Î±Ï\80αιÏ\84οÏ\8dν Ï\84ο Ï\8cνομα Ï\83Ï\8dνδεÏ\83ηÏ\82 Î½Î± ÎµÎ¯Î½Î±Î¹ Ï\84ο Î¯Î´Î¹Î¿ Î¼Îµ Ï\84ο ÎµÎ½Î´ÎµÏ\87Ï\8cμενο Ï\8cνομα Ï\87Ï\81ήÏ\83Ï\84η, Î¼Ï\80οÏ\81είÏ\84ε ÎµÏ\80ίÏ\83ηÏ\82 Î½Î± Ï\87Ï\81ηÏ\83ιμοÏ\80οιήÏ\83εÏ\84ε Ï\84ο <strong>$3</strong> Ï\89Ï\82 Ï\8cνομα Ï\87Ï\81ήÏ\83Ï\84η ÎºÎ±Î¹ Ï\84ο <strong>$4</strong> Ï\89Ï\82 Ï\83Ï\85νθημαÏ\84ικό.)",
        "botpasswords-no-provider": "Το BotPasswordsSessionProvider δεν είναι διαθέσιμο.",
        "botpasswords-restriction-failed": "Περιορισμοί κωδικών πρόσβασης bot εμποδίζουν τη συγκεκριμένη σύνδεση.",
        "botpasswords-invalid-name": "Το όνομα χρήστη που ορίζεται δεν περιέχει το διαχωριστικό συνθηματικού ρομπότ («$1»).",
        "botpasswords-not-exist": "Ο χρήστης «$1» δεν έχει συνθηματικό για ρομπότ με όνομα «$2».",
+       "botpasswords-needs-reset": "Το συνθηματικό για το ρομπότ με όνομα «$2» {{GENDER:$1|του χρήστη|της χρήστριας}} «$1» χρειάζεται ανανέωση.",
+       "botpasswords-locked": "Δεν μπορείτε να συνδεθείτε με συνθηματικό μποτ καθώς ο λογαριασμός σας είναι κλειδωμένος.",
        "resetpass_forbidden": "Οι κωδικοί πρόσβασης δεν μπορούν να αλλαχθούν",
        "resetpass_forbidden-reason": "Οι κωδικοί πρόσβασης δεν μπορούν να αλλαχθούν: $1",
        "resetpass-no-info": "Πρέπει να είστε συνδεδεμένος για να δείτε αυτήν την σελίδα απευθείας",
        "resetpass-submit-loggedin": "Αλλαγή κωδικού",
        "resetpass-submit-cancel": "Ακύρωση",
        "resetpass-wrong-oldpass": "Μη έγκυρο προσωρινό ή τρέχον συνθηματικό.\nΜπορεί να έχετε ήδη αλλάξει το συνθηματικό σας ή να έχετε αιτηθεί νέο προσωρινό συνθηματικό.",
-       "resetpass-recycled": "ΠαÏ\81ακαλοÏ\8dμε ÎµÏ\80αναÏ\86έÏ\81εÏ\84ε Ï\84ο Ï\83Ï\85νθημαÏ\84ικÏ\8c Ï\83αÏ\82 ÎµÏ\80ιλέγονÏ\84αÏ\82 κάτι διαφορετικό από το τρέχον συνθηματικό σας.",
+       "resetpass-recycled": "ΠαÏ\81ακαλοÏ\8dμε Î±Î»Î»Î¬Î¾Ï\84ε Ï\84ο Ï\83Ï\85νθημαÏ\84ικÏ\8c Ï\83αÏ\82 Ï\83ε κάτι διαφορετικό από το τρέχον συνθηματικό σας.",
        "resetpass-temp-emailed": "Έχετε συνδεθεί με έναν προσωρινό κωδικό μέσω ηλεκτρονικού ταχυδρομείου.\nΓια να ολοκληρώσετε τη σύνδεσή σας, πρέπει να ορίσετε νέο συνθηματικό εδώ:",
-       "resetpass-temp-password": "Προσωρινός κωδικός:",
+       "resetpass-temp-password": "Προσωρινό συνθηματικό:",
        "resetpass-abort-generic": "Η αλλαγή του κωδικού έχει απορριφθεί από μια προέκταση.",
        "resetpass-expired": "Το συνθηματικό σας έχει λήξει. Παρακαλούμε καθορίστε νέο συνθηματικό για να συνδεθείτε.",
-       "resetpass-expired-soft": "Το συνθηματικό σας έχει λήξει και πρέπει να γίνει επαναφορά του. Παρακαλούμε επιλέξτε νέο συνθηματικό τώρα, ή κάντε κλικ στο «{{int:authprovider-resetpass-skip-label}}» για το επαναφέρετε αργότερα.",
-       "resetpass-validity-soft": "Ο κωδικός πρόσβασής σας δεν είναι έγκυρος: $1\n\nΠαρακαλούμε επιλέξτε έναν νέο κωδικό πρόσβασης τώρα, ή πατήστε «{{int:authprovider-resetpass-skip-label}}» για να τον επαναφέρετε αργότερα.",
+       "resetpass-expired-soft": "Το συνθηματικό σας έχει λήξει και πρέπει να αλλάξει. Παρακαλούμε επιλέξτε νέο συνθηματικό τώρα, ή κάντε κλικ στο «{{int:authprovider-resetpass-skip-label}}» για το αλλάξετε αργότερα.",
+       "resetpass-validity": "Το συνθηματικό σας δεν ισχύει: $1 \n\nΠαρακαλούμε καθορίστε νέο συνθηματικό για να συνδεθείτε.",
+       "resetpass-validity-soft": "Το συνθηματικό σας δεν είναι έγκυρο: $1\n\nΠαρακαλούμε επιλέξτε νέο συνθηματικό τώρα, ή πατήστε «{{int:authprovider-resetpass-skip-label}}» για να το αλλάξετε αργότερα.",
        "passwordreset": "Επαναφορά κωδικού",
        "passwordreset-text-one": "Συμπληρώστε αυτήν τη φόρμα για να λάβετε ένα προσωρινό συνθηματικό μέσω ηλεκτρονικού ταχυδρομείου.",
        "passwordreset-text-many": "{{PLURAL:$1|Συμπληρώστε ένα από τα πεδία για να λάβετε προσωρινό συνθηματικό μέσω ηλεκτρονικού ταχυδρομείου.}}",
        "passwordreset-emailtitle": "Λεπτομέρειες λογαριασμού για {{SITENAME}}",
        "passwordreset-emailtext-ip": "Κάποιος (κατά πάσα πιθανότητα εσείς, από την διεύθυνση IP $1) αιτήθηκε επαναφορά του συνθηματικού σας στον ιστότοπο {{SITENAME}} ($4).  {{PLURAL:$3|Ο ακόλουθος λογαριασμός|Οι ακόλουθοι λογαριασμοί}} χρήστη συνδέονται με αυτήν τη διεύθυνση ηλεκτρονικού ταχυδρομείου:\n\n$2\n\n{{PLURAL:$3|Αυτό το προσωρινό συνθηματικό θα λήξει| Αυτά τα προσωρινά συνθηματικά θα λήξουν}} σε {{PLURAL:$5|μία ημέρα|$5 ημέρες}}.\nΘα πρέπει να συνδεθείτε και να επιλέξετε νέο συνθηματικό τώρα. Αν κάποιος άλλος έκανε αυτό το αίτημα ή αν θυμηθήκατε το αρχικό συνθηματικό σας και δεν επιθυμείτε πια να το αλλάξετε, μπορείτε να αγνοήσετε αυτό το μήνυμα και να συνεχίσετε να χρησιμοποιείτε το παλιό σας συνθηματικό.",
        "passwordreset-emailtext-user": "Ο χρήστης $1 στον ιστότοπο {{SITENAME}} ζήτησε μια επαναφορά του συνθηματικού σας για τον ιστότοπο {{SITENAME}} ($4). {{PLURAL:$3|Ο ακόλουθος λογαριασμός|Οι ακόλουθοι λογαριασμοί}} χρήστη συνδέονται με αυτήν τη διεύθυνση ηλεκτρονικού ταχυδρομείου:\n\n$2\n\n{{PLURAL:$3|Αυτό το προσωρινό συνθηματικό θα λήξει| Αυτά τα προσωρινά συνθηματικά θα λήξουν}} σε {{PLURAL:$5|μία ημέρα|$5 ημέρες}}.\nΘα πρέπει να συνδεθείτε και να επιλέξετε νέο συνθηματικό τώρα. Αν κάποιος άλλος έκανε αυτό το αίτημα ή αν θυμηθήκατε το αρχικό συνθηματικό σας και δεν επιθυμείτε πια να το αλλάξετε, μπορείτε να αγνοήσετε αυτό το μήνυμα και να συνεχίσετε να χρησιμοποιείτε το παλιό σας συνθηματικό.",
-       "passwordreset-emailelement": "Όνομα χρήστη: \n$1\n\nΠροσωρινός κωδικός πρόσβασης:\n$2",
+       "passwordreset-emailelement": "Όνομα χρήστη: \n$1\n\nΠροσωρινό συνθηματικό:\n$2",
        "passwordreset-emailsentemail": "Αν αυτή η διεύθυνση ηλεκτρονικού ταχυδρομείου συνδέεται με το  λογαριασμό σας, τότε  θα σας αποσταλεί μήνυμα ηλεκτρονικού ταχυδρομείου για την επαναφορά του κωδικού πρόσβασης.",
        "passwordreset-emailsentusername": "Αν υπάρχει μια διεύθυνση ηλεκτρονικού ταχυδρομείου που συνδέεται με αυτό το όνομα χρήστη, τότε θα σας αποσταλεί ένα μήνυμα ηλεκτρονικού ταχυδρομείου για την επαναφορά του κωδικού πρόσβασης.",
        "passwordreset-nocaller": "Πρέπει να γίνει   κλήση",
        "changeemail-newemail": "Νέα διεύθυνση ηλεκτρονικού ταχυδρομείου:",
        "changeemail-newemail-help": "Αυτό το πεδίο θα πρέπει να μείνει κενό αν θέλετε να καταργήσετε τη διεύθυνσή σας ηλεκτρονικού ταχυδρομείου. Αν η διεύθυνση ηλεκτρονικού ταχυδρομείου καταργηθεί, δεν θα μπορείτε να επαναφέρετε τον κωδικό πρόσβασης σε περίπτωση που τον ξεχάσετε και δεν θα λαμβάνετε μηνύματα ηλεκτρονικού ταχυδρομείου από αυτό το wiki.",
        "changeemail-none": "(κανένα)",
-       "changeemail-password": "Î\9f ÎºÏ\89δικÏ\8cÏ\82 Ï\80Ï\81Ï\8cÏ\83βαÏ\83ήÏ\82 σας στο εγχείρημα {{SITENAME}}:",
+       "changeemail-password": "Το Ï\83Ï\85νθημαÏ\84ικÏ\8c σας στο εγχείρημα {{SITENAME}}:",
        "changeemail-submit": "Αλλαγή διεύθυνσης ηλεκτρονικού ταχυδρομείου",
        "changeemail-throttled": "Κάνατε πάρα πολλές απόπειρες σύνδεσης.\nΠαρακαλούμε περιμένετε $1 προτού ξαναδοκιμάσετε.",
        "changeemail-nochange": "Παρακαλούμε εισαγάγετε διαφορετική νέα διεύθυνση ηλεκτρονικού ταχυδρομείου.",
        "subject-preview": "Προεπισκόπηση θέματος:",
        "previewerrortext": "Παρουσιάστηκε σφάλμα κατά την προσπάθεια για να κάνετε προεπισκόπηση των αλλαγών σας.",
        "blockedtitle": "Ο χρήστης έχει υποστεί φραγή.",
+       "blocked-email-user": "<strong>Το όνομα χρήστη σας έχει φραγεί από το να στέλνει email. Μπορείτε ακόμη να επεξεργάζεστε άλλες σελίδες σε αυτό το wiki.</strong> Μπορείτε να δείτε πλήρεις λεπτομέρειες φραγής στις [[Special:MyContributions|συνεισφορές λογαριασμού]].\n\nΗ φραγή έγινε από τον $1.\n\nΗ αιτία που δόθηκε είναι <em>$2</em>.\n\n* Έναρξη φραγής: $8\n* Λήξη φραγής: $6\n* Επιδιωκόμενος αποκλεισμένος: $7\n* Block ID #$5",
+       "blockedtext-partial": "<strong>Το όνομα χρήστη ή η IP σας έχει φραγεί από το να κάνει αλλαγές σε αυτή τη σελίδα. Μπορείτε ακόμη να επεξεργάζεστε άλλες σελίδες σε αυτό το wiki.</strong> Μπορείτε να δείτε πλήρεις λεπτομέρειες φραγής στις [[Special:MyContributions|συνεισφορές λογαριασμού]].\n\nΗ φραγή έγινε από τον $1.\n\nΗ αιτία που δόθηκε είναι <em>$2</em>.\n\n* Έναρξη φραγής: $8\n* Λήξη φραγής: $6\n* Επιδιωκόμενος αποκλεισμένος: $7\n* Block ID #$5",
        "blockedtext": "<strong>Το όνομα χρήστη σας ή η διεύθυνση IP σας έχει υποστεί φραγή.</strong>\n\nΗ φραγή έγινε από τον/την $1.\nΗ αιτιολογία που δόθηκε είναι: <em>$2</em>.\n\n* Έναρξη φραγής: $8\n* Λήξη φραγής: $6\n* Η φραγή προορίζεται για το χρήστη: $7\n\nΜπορείτε να απευθυνθείτε στον/στην $1 ή σε κάποιον άλλον [[{{MediaWiki:Grouppage-sysop}}|διαχειριστή]] για να συζητήσετε τη φραγή.\nΔεν μπορείτε να χρησιμοποιήσετε την δυνατότητα \"{{int:emailuser}}\" εκτός αν μια έγκυρη ηλεκτρονική διεύθυνση έχει οριστεί στις [[Special:Preferences|προτιμήσεις χρήστη]] σας.\nΗ τρέχουσα διεύθυνση IP σας είναι $3, και ο αριθμός αναγνώρισης της φραγής είναι #$5.\nΠαρακαλούμε περιλαμβάνετε οποιοδήποτε ή και τα δύο από αυτά σε οποιαδήποτε ερωτήματα σας.",
-       "autoblockedtext": "Η διεύθυνση IP σας έχει υποστεί φραγή αυτόματα επειδή χρησιμοποιήθηκε από έναν άλλο χρήστη, ο οποίος και αποκλείστηκε από τον/την $1.\nΗ αιτιολόγηση που δόθηκε είναι η εξής:\n\n:<em>$2</em>\n\n* Έναρξη φραγής: $8\n* Λήξη φραγής: $6\n* Επιδιωκόμενος αποκλεισμένος: $7\n\nΜπορείτε να επικοινωνήσετε με τον/την $1 ή με κάποιον από τους άλλους [[{{MediaWiki:Grouppage-sysop}}|διαχειριστές]] για να συζητήσετε τη φραγή.\n\nΝα σημειωθεί ότι δεν μπορείτε να χρησιμοποιήσετε τη λειτουργία «αποστολή μηνύματος ηλεκτρονικού ταχυδρομείου σε αυτόν τον χρήστη» εκτός αν έχετε μια έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου καταχωρισμένη στις [[Special:Preferences|προτιμήσεις χρήστη]] σας.\n\nΗ τρέχουσα διεύθυνση IP σας είναι $3 και το αναγνωριστικό της φραγής σας είναι #$5. Παρακαλούμε συμπεριλάβετε τις παραπάνω λεπτομέρειες σε όποια ερωτήματα κάνετε.",
+       "autoblockedtext": "Η διεύθυνση IP σας έχει υποστεί φραγή αυτόματα επειδή χρησιμοποιήθηκε από έναν άλλο χρήστη, ο οποίος και αποκλείστηκε από τον/την $1.\nΗ αιτιολόγηση που δόθηκε είναι η εξής:\n\n:<em>$2</em>\n\n* Έναρξη φραγής: $8\n* Λήξη φραγής: $6\n* Επιδιωκόμενος αποκλεισμένος: $7\n\nΜπορείτε να επικοινωνήσετε με τον/την $1 ή με κάποιον από τους άλλους [[{{MediaWiki:Grouppage-sysop}}|διαχειριστές]] για να συζητήσετε τη φραγή.\n\nΝα σημειωθεί ότι δεν μπορείτε να χρησιμοποιήσετε τη λειτουργία «{{int:emailuser}}» εκτός αν έχετε μια έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου καταχωρισμένη στις [[Special:Preferences|προτιμήσεις χρήστη]] σας.\n\nΗ τρέχουσα διεύθυνση IP σας είναι $3 και το αναγνωριστικό της φραγής σας είναι #$5. Παρακαλούμε συμπεριλάβετε τις παραπάνω λεπτομέρειες σε όποια ερωτήματα κάνετε.",
        "systemblockedtext": "Το όνομα χρήστη σας ή η διεύθυνση IP έχει αποκλειστεί αυτόματα από το MediaWiki.\nΗ αιτία που δόθηκε είναι:\n\n:<em>$2</em>\n\n* Έναρξη φραγής: $8\n* Λήξη φραγής: $6\n* Στόχος φραγής: $7\n\nΗ τρέχουσα διεύθυνση IP σας είναι $3.\nΠαρακαλούμε να συμπεριλάβετε όλα τα παραπάνω στοιχεία σε τυχόν απορίες σας.",
        "blockednoreason": "δεν δόθηκε λόγος",
        "whitelistedittext": "Πρέπει να $1 για να επεξεργαστείτε σελίδες.",
        "loginreqtitle": "Απαιτείται η σύνδεση του χρήστη.",
        "loginreqlink": "συνδεθείτε",
        "loginreqpagetext": "Πρέπει να $1 για να δείτε άλλες σελίδες.",
-       "accmailtitle": "Î\9f ÎºÏ\89δικÏ\8cÏ\82 έχει σταλεί.",
+       "accmailtitle": "Το Ï\83Ï\85νθημαÏ\84ικÏ\8c έχει σταλεί.",
        "accmailtext": "Ένας τυχαία παρηγμένος κωδικός για {{GENDER:$1|τον|την}} [[User talk:$1|$1]] έχει σταλεί στο $2.\n\nΜπορεί να αλλαχθεί από την σελίδα ''[[Special:ChangePassword|αλλαγή κωδικού]]'' μετά τη σύνδεση.",
        "newarticle": "(Νέο)",
        "newarticletext": "Ακολουθήσατε ένα σύνδεσμο προς μια σελίδα που δεν υπάρχει ακόμα. \nΓια να δημιουργήσετε τη σελίδα, αρχίστε να πληκτρολογείτε στο παρακάτω πλαίσιο (δείτε τη [$1 σελίδα βοήθειας] για περισσότερες πληροφορίες).\nΑν έχετε βρεθεί εδώ κατά λάθος, πατήστε το κουμπί '''πίσω''' στον περιηγητή σας.",
-       "anontalkpagetext": "----''Αυτή η σελίδα συζήτησης προορίζεται για ανώνυμο χρήστη που δεν έχει δημιουργήσει ακόμα λογαριασμό ή που δεν τον χρησιμοποιεί. Έτσι για την ταυτοποίηση ενός ανώνυμου χρήστη χρησιμοποιείται η διεύθυνση IP του. Είναι όμως πιθανόν η διεύθυνση αυτή να είναι κοινή για πολλούς διαφορετικούς χρήστες.  Αν είστε ανώνυμος χρήστης και νομίζετε ότι άσχετα σχόλια απευθύνθηκαν σε σας, παρακαλούμε να [[Special:CreateAccount|δημιουργήσετε ένα λογαριασμό]] ή να  [[Special:UserLogin|συνδεθείτε]] για να αποφεύγεται η μελλοντική σύγχυση με άλλους ανώνυμους χρήστες.''",
+       "anontalkpagetext": "----''Αυτή η σελίδα συζήτησης προορίζεται για ανώνυμο χρήστη που δεν έχει δημιουργήσει ακόμα λογαριασμό ή που δεν τον χρησιμοποιεί. Έτσι για την ταυτοποίηση ενός ανώνυμου χρήστη χρησιμοποιείται η διεύθυνση IP τους. Είναι όμως πιθανόν η διεύθυνση αυτή να είναι κοινή για πολλούς διαφορετικούς χρήστες.  Αν είστε ανώνυμος χρήστης και νομίζετε ότι άσχετα σχόλια απευθύνθηκαν σε σας, παρακαλούμε να [[Special:CreateAccount|δημιουργήσετε ένα λογαριασμό]] ή να  [[Special:UserLogin|συνδεθείτε]] για να αποφεύγεται η μελλοντική σύγχυση με άλλους ανώνυμους χρήστες.''",
        "noarticletext": "Δεν υπάρχει προς το παρόν κείμενο σε αυτή τη σελίδα. \nΜπορείτε να [[Special:Search/{{PAGENAME}}|αναζητήσετε αυτόν τον τίτλο σελίδας]] σε άλλες σελίδες,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} να αναζητήσετε τις σχετικές καταγραφές],\nή να [{{fullurl:{{FULLPAGENAME}}|action=edit}} δημιουργήσετε αυτή τη σελίδα]</span>.",
        "noarticletext-nopermission": "Δεν υπάρχει προς το παρόν κείμενο σε αυτή τη σελίδα.\nΜπορείτε να [[Special:Search/{{PAGENAME}}|αναζητήσετε αυτόν τον τίτλο σελίδας]] σε άλλες σελίδες, ή <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} να ψάξετε στις σχετικές καταγραφές]</span>, αλλά δεν έχετε την άδεια να δημιουργήσετε αυτή τη σελίδα.",
        "missing-revision": "Δεν υπάρχει αναθεώρηση με αριθμό $1 για τη σελίδα με όνομα «{{FULLPAGENAME}}».\n\nΑυτό συνήθως προκαλείται από παλιό σύνδεσμο ιστορικού προς σελίδα που έχει διαγραφεί.\nΛεπτομέρειες θα βρείτε στο [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ημερολόγιο καταγραφής διαγραφών].",
        "userjsonpreview": "<strong>Σας υπενθυμίζουμε ότι κάνετε απλώς έλεγχο/προεπισκόπηση της ρύθμισης JSON σας. Δεν έχει αποθηκευθεί ακόμα!</strong>",
        "userjspreview": "'''Σας υπενθυμίζουμε ότι κάνετε απλώς έλεγχο/προεπισκόπηση του JavaScript του χρήστη -δεν το έχετε ακόμα αποθηκεύσει!'''",
        "sitecsspreview": "<strong>Θυμηθείτε ότι είναι απλώς μια προεπισκόπηση αυτού του CSS.\nΔεν έχει αποθηκευτεί ακόμα!</strong>",
+       "sitejsonpreview": "<strong>Θυμηθείτε ότι είναι απλώς μια προεπισκόπηση αυτής της ρύθμισης JSON.\nΔεν έχει αποθηκευτεί ακόμα!</strong>",
        "sitejspreview": "''' Θυμηθείτε ότι κάνετε μόνο προεπισκόπηση σ'αυτόν τον κώδικα JavaScript.'' '\n'' ' Δεν τον έχετε αποθηκεύσει ακόμη!'' '",
        "userinvalidconfigtitle": "<strong>Προσοχή:<strong> Δεν υπάρχει skin με τίτλο \"$1\". Θυμηθείτε οι προσαρμοσμένες σελίδες .css, .json, .js χρησιμοποιούν έναν τίτλο με μικρά γράμματα, π.χ. {{ns:user}}:Foo/vector.css σε αντίθεση με το {{ns:user}}:Foo/Vector.css.",
        "updated": "(Ενημερώθηκε)",
        "semiprotectedpagewarning": "<strong>Σημείωση:</strong> Αυτή η σελίδα έχει προστατευτεί ώστε μόνο αυτοεπιβεβαιωμένοι χρήστες μπορούν να την επεξεργαστούν.\nΗ πιο πρόσφατη καταχώρηση στο αρχείο καταγραφής παρέχεται παρακάτω για αναφορά:",
        "cascadeprotectedwarning": "<strong>Προσοχή:</strong> Αυτή η σελίδα έχει κλειδωθεί ώστε μόνο χρήστες με [[Special:ListGroupRights|συγκεκριμένα δικαιώματα]] να μπορούν να την επεξεργαστούν, επειδή περιλαμβάνεται {{PLURAL:$1|στην ακόλουθη|στις ακόλουθες}} διαδοχικά (cascaded) {{PLURAL:$1|προστατευμένη σελίδα|προστατευμένες σελίδες}}:",
        "titleprotectedwarning": "'''Προειδοποίηση: Αυτή η σελίδα έχει κλειδωθεί ώστε χρειάζονται [[Special:ListGroupRights|ειδικά δικαιώματα]] για να δημιουργηθεί.'''\nΗ πιο πρόσφατη καταχώρηση στο αρχείο καταγραφής παρέχεται παρακάτω για αναφορά:",
-       "templatesused": "{{PLURAL:$1|Πρότυπο που χρησιμοποιείται|Πρότυπα που χρησιμοποιούνται}} σε αυτή τη σελίδα:",
-       "templatesusedpreview": "{{PLURAL:$1|Πρότυπο που χρησιμοποιείται|Πρότυπα που χρησιμοποιούνται}} σε αυτή την προεπισκόπηση:",
-       "templatesusedsection": "{{PLURAL:$1|Πρότυπο|Πρότυπα}} που χρησιμοποιούνται σε αυτή την ενότητα:",
+       "templatesused": "{{PLURAL:$1|Πρότυπο που χρησιμοποιείται|Πρότυπα που χρησιμοποιούνται}} σε αυτήν τη σελίδα:",
+       "templatesusedpreview": "{{PLURAL:$1|Πρότυπο που χρησιμοποιείται|Πρότυπα που χρησιμοποιούνται}} σε αυτήν την προεπισκόπηση:",
+       "templatesusedsection": "{{PLURAL:$1|Πρότυπο|Πρότυπα}} που χρησιμοποιούνται σε αυτήν την ενότητα:",
        "template-protected": "(προστατευμένη)",
        "template-semiprotected": "(ημιπροστατευμένη)",
        "hiddencategories": "Αυτή η σελίδα είναι μέλος {{PLURAL:$1|μίας κρυμμένης κατηγορίας|$1 κρυμμένων κατηγοριών}}:",
        "edit-conflict": "Σύγκρουση επεξεργασιών.",
        "edit-no-change": "Η επεξεργασία σας αγνοήθηκε, επειδή δεν έγινε καμία αλλαγή στο κείμενο.",
        "edit-slots-cannot-add": "Τα ακόλουθα σημεία στίξεως εφαρμόζονται εδώ {{PLURAL:$1|slot is|slots are}} : $2.",
+       "edit-slots-cannot-remove": "{{PLURAL:$1|Η ακόλουθη υποδοχή είναι απαραίτητη και δεν μπορεί να αφαιρεθεί|Οι ακόλουθες υποδοχές είναι απαραίτητες και δεν μπορούν να αφαιρεθούν}}: $2.",
        "edit-slots-missing": "Το επόμενο {{PLURAL:$1|κενό|slots are}} λείπει: $2.{{PLURAL:$1|}}",
        "postedit-confirmation-created": "Η σελίδα δημιουργήθηκε.",
        "postedit-confirmation-restored": "Η σελίδα έχει αποκατασταθεί.",
        "defaultmessagetext": "Προεπιλεγμένο κείμενο μηνύματος",
        "content-failed-to-parse": "Απέτυχε η ανάλυση  περιεχομένου του $2 για το μοντέλο $1:$3",
        "invalid-content-data": "Μη έγκυρα δεδομένα περιεχομένου",
-       "content-not-allowed-here": "Το περιεχόμενο «$1» δεν επιτρέπεται στη σελίδα [[:$2]]",
+       "content-not-allowed-here": "Το περιεχόμενο «$1» δεν επιτρέπεται στη σελίδα [[:$2]] στην υποδοχή «$3»",
        "editwarning-warning": "Αφήνοντας αυτή τη σελίδα μπορεί να έχει ως συνέπεια να χαθούν κάποιες αλλαγές που έχετε κάνει.\nΑν έχετε συνδεθεί, μπορείτε να απενεργοποιήσετε αυτή την προειδοποίηση στην  ενότητα \"{{int:prefs-editing}}\"  των προτιμήσεών σας.",
        "editpage-invalidcontentmodel-title": "Δεν υποστηρίχτηκε το μοντέλο περιεχομένου",
        "editpage-invalidcontentmodel-text": "Το μοντέλο ''$1'' δεν υποστηρίχτηκε.",
        "converter-manual-rule-error": "Εντοπίστηκε σφάλμα σε μη αυτόματο κανόνα μετατροπής γλώσσας",
        "undo-success": "Η επεξεργασία μπορεί να αναιρεθεί.\nΠαρακαλούμε ελέγξτε την σύγκριση παρακάτω για να επιβεβαιώσετε ότι είναι αυτό το οποίο θέλετε να κάνετε και έπειτα αποθηκεύστε τις αλλαγές παρακάτω για να ολοκληρώσετε την αναίρεση της επεξεργασίας.",
        "undo-failure": "Η επεξεργασία δεν μπορούσε να αναστραφεί λόγω αντικρουόμενων ενδιάμεσων επεξεργασιών.",
+       "undo-main-slot-only": "Η επεξεργασία δεν μπορεί να αναιρεθεί επειδή εμπλέκει περιεχόμενο έξω από τη κύρια υποδοχή.",
        "undo-norev": "Η ανάκληση αυτής της επεξεργασίας δεν ηταν δυνατό να πραγματοποιηθεί επειδή δεν υπάρχει ή επειδή έχει διαγραφεί.",
        "undo-nochange": "Η επεξεργασία φαίνεται να έχει ήδη αναιρεθεί.",
-       "undo-summary": "Αναίρεση αναθεώρησης $1 από {{GENDER:$2|τον|την}} [[Special:Contribs/$2|$2]] ([[User talk:$2|Συζήτηση]])",
+       "undo-summary": "Αναίρεση αναθεώρησης $1 από {{GENDER:$2|τον|την}} [[Special:Contributions/$2|$2]] ([[User talk:$2|Συζήτηση]])",
        "undo-summary-username-hidden": "Αναίρεση αναθεώρησης $1 από ένα κρυμμένο χρήστη",
        "cantcreateaccount-text": "Η δημιουργία λογαριασμού από αυτή τη διεύθυνση IP ('''$1''') έχει αποτραπεί από τον [[User:$3|$3]].\n\nΟ λόγος που δόθηκε από τον $3 είναι ''$2''",
        "cantcreateaccount-range-text": "Η δημιουργία λογαριασμού από διευθύνσεις IP στην περιοχή  <strong>$1</strong>, που περιλαμβάνει τη δική σας διεύθυνση IP (<strong>$4</strong>), έχει αποκλειστεί από τον [[User:$3|$3]].\n\nΗ αιτιολογία που δόθηκε από τον $3 είναι \"$2\"",
        "page_first": "πρώτη",
        "page_last": "τελευταία",
        "histlegend": "Επιλογή διαφορών: Μαρκάρετε τα κουτάκια επιλογής των εκδόσεων που θέλετε να συγκρίνετε και πατήστε το enter ή το κουμπί στο κάτω μέρος.<br />\nΥπόμνημα: '''({{int:cur}})''' = διαφορά από την τελευταία έκδοση, '''({{int:last}})''' = διαφορά από την προηγούμενη έκδοση, '''{{int:minoreditletter}}''' = μικροαλλαγή.",
-       "history-fieldset-title": "ΠεÏ\81ιήγηÏ\83η Ï\83Ï\84ο Î¹Ï\83Ï\84οÏ\81ικÏ\8c αλλαγών",
+       "history-fieldset-title": "ΦιλÏ\84Ï\81άÏ\81ιÏ\83μα αλλαγών",
        "history-show-deleted": "Διαγεγραμμένες μόνο",
        "histfirst": "η πιο παλιά",
        "histlast": "η πιο πρόσφατη",
        "historysize": "({{PLURAL:$1|1 byte|$1 bytes}})",
-       "historyempty": "(άδειο)",
+       "historyempty": "άδειο",
        "history-feed-title": "Ιστορικό εκδόσεων",
        "history-feed-description": "Ιστορικό αναθεωρήσεων για αυτή τη σελίδα στο wiki",
        "history-feed-item-nocomment": "$1 στις $2",
        "diff-paragraph-moved-toold": "Η παράγραφος αφαιρέθηκε. Πατήστε στο κουμπί για να πάτε σε προηγούμενη τοποθεσία.",
        "difference-missing-revision": "{{PLURAL:$2|Μία αναθεώρηση|$2 αναθεωρήσεις}} αυτής της διαφοράς ($1) δεν {{PLURAL:$2|μπόρεσε να βρεθεί|μπόρεσαν να βρεθούν}}.\n\nΑυτό συνήθως προκαλείται από παλιό σύνδεσμο διαφοράς προς σελίδα που έχει διαγραφεί.\nΛεπτομέρειες θα βρείτε στο [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ημερολόγιο καταγραφής διαγραφών].",
        "searchresults": "Αποτελέσματα αναζήτησης",
+       "search-filter-title-prefix": "Αναζήτηση μόνο σελίδων που ο τίτλος τους ξεκινά με «$1»",
        "search-filter-title-prefix-reset": "Αναζήτηση όλων των σελίδων",
        "searchresults-title": "Αποτελέσματα αναζήτησης για \"$1\"",
        "titlematches": "Τίτλοι άρθρων που ανταποκρίνονται",
        "textmatches": "Κείμενα σελίδων που ανταποκρίνονται:",
        "notextmatches": "Δεν υπάρχουν αντίστοιχα κείμενα σελίδων.",
-       "prevn": "{{PLURAL:$1|$1}} προηγουμένων",
-       "nextn": "{{PLURAL:$1|$1}} επόμενων",
+       "prevn": "$1 {{PLURAL:$1|προηγούμενου|προηγουμένων}}",
+       "nextn": "$1 {{PLURAL:$1|επόμενου|επόμενων}}",
        "prev-page": "προηγούμενη σελίδα",
        "next-page": "επόμενη σελίδα",
        "prevn-title": "{{PLURAL:$1|Προηγούμενο $1 αποτέλεσμα|Προηγούμενα $1 αποτελέσματα}}",
        "prefs-watchlist-token": "Σημείο λίστας παρακολούθησης:",
        "prefs-watchlist-managetokens": "Διαχείριση tokens",
        "prefs-misc": "Διάφορες ρυθμίσεις",
-       "prefs-resetpass": "Αλλαγή κωδικού",
+       "prefs-resetpass": "Αλλαγή συνθηματικού",
        "prefs-changeemail": "Αλλαγή ή αφαίρεση της διεύθυνσης ηλεκτρονικού ταχυδρομείου",
        "prefs-setemail": "Ορίστε μια διεύθυνση ηλεκτρονικού ταχυδρομείου",
        "prefs-email": "Επιλογές διεύθυνσης ηλεκτρονικού ταχυδρομείου",
        "prefs-advancedwatchlist": "Προηγμένες επιλογές",
        "prefs-displayrc": "Εμφάνιση επιλογών",
        "prefs-displaywatchlist": "Επιλογές εμφάνισης",
+       "prefs-changesrc": "Αλλαγές που εμφανίζονται",
+       "prefs-changeswatchlist": "Αλλαγές που εμφανίζονται",
+       "prefs-pageswatchlist": "Παρακολουθούμενες σελίδες",
        "prefs-tokenwatchlist": "Κλειδί",
        "prefs-diffs": "Διαφορές",
        "prefs-help-prefershttps": "Αυτή η προτίμηση θα τεθεί σε ισχύ στην επόμενή σας σύνδεση.",
        "group-autoconfirmed-member": "{{GENDER:$1|αυτοεπιβεβαιωμένος χρήστης|αυτοεπιβεβαιωμένη χρήστρια}}",
        "group-bot-member": "ρομπότ",
        "group-sysop-member": "{{GENDER:$1|διαχειριστής|διαχειρίστρια}}",
-       "group-interface-admin-member": "{{GENDER:$1|διαχειριστής διεπαφής}}",
+       "group-interface-admin-member": "{{GENDER:$1|διαχειριστής|διαχειρίστρια}} διεπαφής",
        "group-bureaucrat-member": "{{GENDER:$1|γραφειοκράτης|γραφειοκράτις}}",
        "group-suppress-member": "{{GENDER:$1|επιτηρητής|επιτηρήτρια}}",
        "grouppage-user": "{{ns:project}}:Χρήστες",
        "right-editusercss": "Μεταγραφή των αρχείων CSS άλλων χρηστών",
        "right-edituserjson": "Μεταγραφή των αρχείων JSON άλλων χρηστών",
        "right-edituserjs": "Μεταγραφή των αρχείων JS άλλων χρηστών",
+       "right-editsitecss": "Επεξεργασία CSS ιστότοπου",
+       "right-editsitejson": "Επεξεργασία JSON ιστότοπου",
+       "right-editsitejs": "Επεξεργασία JavaScript ιστότοπου",
        "right-editmyusercss": "Επεξεργασία των ιδιωτικών αρχείων CSS χρήστη",
        "right-editmyuserjson": "Επεξεργασία των ιδιωτικών αρχείων JSON χρήστη",
        "right-editmyuserjs": "Επεξεργασία των ιδιωτικών αρχείων JavaScript χρήστη",
        "grant-createaccount": "Δημιουργία λογαριασμών",
        "grant-createeditmovepage": "Δημιουργία, επεξεργασία και μετακίνηση σελίδων",
        "grant-delete": "Διαγραφή σελίδων, αναθεωρήσεων και καταχωρίσεων σε αρχεία καταγραφής",
-       "grant-editinterface": "Επεξεργασία του ονοματοχώρου Mediawiki και των CSS/JSON/JavaScript των χρηστών",
+       "grant-editinterface": "Επεξεργασία του ονοματοχώρου Mediawiki και JSON ιστότοπου/χρηστών",
        "grant-editmycssjs": "Επεξεργασία των CSS/JSON/JavaScript του χρήστη σας",
-       "grant-editmyoptions": "Επεξεργασία των προτιμήσεων χρήστη σας",
+       "grant-editmyoptions": "Επεξεργασία των προτιμήσεων χρήστη σας και ρυθμίσεων JSON",
        "grant-editmywatchlist": "Επεξεργασία της λίστας παρακολούθησής σας",
+       "grant-editsiteconfig": "Επεξεργασία CSS/JS ιστότoπου και χρηστών",
        "grant-editpage": "Επεξεργασία υπαρχουσών σελίδων",
        "grant-editprotected": "Επεξεργασία προστατευμένων σελίδων",
        "grant-highvolume": "Επεξεργασία υψηλού όγκου",
        "action-changetags": "πρόσθεση και αφαίρεση αυθαίρετων ετικετών σε μεμονωμένες εκδόσεις και καταχωρήσεις καταγραφών",
        "action-deletechangetags": "διαγράψετε ετικέτες από τη βάση δεδομένων",
        "action-purge": "εκκαθάριση αυτής της σελίδας",
+       "action-apihighlimits": "χρήση μεγαλύτερων ορίων για ερωτήματα API",
+       "action-editinterface": "επεξεργασία της διεπαφής χρήστη",
+       "action-editusercss": "επεξεργασία αρχείων CSS άλλων χρηστών",
+       "action-edituserjson": "επεξεργασία αρχείων JSON άλλων χρηστών",
+       "action-edituserjs": "επεξεργασία αρχείων JavaScript άλλων χρηστών",
+       "action-editsitecss": "επεξεργασία CSS ιστότοπου",
+       "action-editsitejson": "επεξεργασία JSON ιστότοπου",
+       "action-editsitejs": "επεξεργασία JavaScript ιστότοπου",
+       "action-editmyusercss": "επεξεργασία των ιδιωτικών αρχείων CSS χρήστη",
+       "action-editmyuserjson": "επεξεργασία των ιδιωτικών αρχείων JSON χρήστη",
+       "action-editmyuserjs": "επεξεργασία των ιδιωτικών αρχείων JavaScript χρήστη",
+       "action-viewsuppressed": "προβολή αναθεωρήσεων κρυμμένων από κάθε χρήστη",
+       "action-hideuser": "φραγή ενός ονόματος χρήστη, αποκρύπτοντάς το από το κοινό",
+       "action-ipblock-exempt": "παράκαμψη φραγών σε διευθύνσεις IP, αυτόματων φραγών και φραγών σε IP range",
+       "action-unblockself": "αναίρεση φραγής του εαυτού",
+       "action-reupload-own": "αντικατάσταση ενός ήδη υπάρχοντος αρχείου που έχει ανέβει από τον ίδιο",
+       "action-nominornewtalk": "μικρές αλλαγές σε σελίδες συζήτησης να μην ενεργοποιούν την ειδοποίηση νέου μηνύματος",
+       "action-markbotedits": "σήμανση αναιρέσεων επεξεργασιών ως επεξεργασιών μποτ",
+       "action-patrolmarks": "προβολή σημάνσεων ελέγχου πρόσφατων αλλαγών",
        "nchanges": "$1 {{PLURAL:$1|αλλαγή|αλλαγές}}",
        "ntimes": "$1×",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|από την τελευταία επίσκεψη}}",
        "rcfilters-savedqueries-already-saved": "Αυτά τα φίλτρα έχουν ήδη αποθηκευτεί. Αλλάξετε τις παραμέτρους για να δημιουργήσετε ένα νέο Αποθηκευμένο Φίλτρο.",
        "rcfilters-restore-default-filters": "Επαναφορά προεπιλεγμένων φίλτρων",
        "rcfilters-clear-all-filters": "Εκκαθάριση όλων των φίλτρων",
-       "rcfilters-show-new-changes": "Προβολή νεότερων αλλαγών",
+       "rcfilters-show-new-changes": "Προβολή νεότερων αλλαγών από $1",
        "rcfilters-search-placeholder": "Φιλτράρισμα πρόσφατων αλλαγών (περιηγηθείτε ή αρχίστε να πληκτρολογείτε)",
        "rcfilters-invalid-filter": "Μη έγκυρο φίλτρο",
        "rcfilters-empty-filter": "Χωρίς ενεργά φίλτρα. Εμφανίζονται όλες οι συνεισφορές.",
        "rcfilters-filter-editsbyself-description": "Οι δικές σας συνεισφορές.",
        "rcfilters-filter-editsbyother-label": "Αλλαγές από άλλους",
        "rcfilters-filter-editsbyother-description": "Όλες οι αλλαγές εκτός από τις δικές σας.",
-       "rcfilters-filtergroup-userExpLevel": "Εγγραφή χρήστη και εμπειρία",
+       "rcfilters-filtergroup-user-experience-level": "Εγγραφή χρήστη και εμπειρία",
        "rcfilters-filter-user-experience-level-registered-label": "Εγγεγραμμένοι",
        "rcfilters-filter-user-experience-level-registered-description": "Συνδεδεμένοι συντάκτες.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Μη εγγεγραμμένοι",
        "rcfilters-filter-categorization-description": "Καταγραφές σελίδων που προστίθενται ή αφαιρούνται από κατηγορίες.",
        "rcfilters-filter-logactions-label": "Καταγραφόμενες ενέργειες",
        "rcfilters-filter-logactions-description": "Διαχειριστικές ενέργειες, δημιουργίες λογαριασμών, διαγραφές σελίδων, ανεβάσματα αρχείων…",
-       "rcfilters-filtergroup-lastRevision": "Πρόσφατες αναθεωρήσεις",
+       "rcfilters-filtergroup-lastrevision": "Πρόσφατες αναθεωρήσεις",
        "rcfilters-filter-lastrevision-label": "Τρέχουσα αναθεώρηση",
        "rcfilters-filter-lastrevision-description": "Μόνο η πλέον πρόσφατη αλλαγή σε σελίδα.",
        "rcfilters-filter-previousrevision-label": "Μη πρόσφατη αναθεώρηση",
        "rcfilters-watchlist-markseen-button": "Σημειώστε όλες τις αλλαγές ως εξετασμένες",
        "rcfilters-watchlist-edit-watchlist-button": "Διορθώστε τη λίστα παρακολούθησης",
        "rcfilters-watchlist-showupdated": "Σελίδες που έχουν υποστεί αλλαγές από την τελευταία φορά που τις επισκεφθήκατε εμφανίζονται με '''έντονους χαρακτήρες'''.",
-       "rcfilters-preference-label": "Î\91Ï\80Ï\8cκÏ\81Ï\85Ï\88η Ï\84ηÏ\82 Î²ÎµÎ»Ï\84ιÏ\89μένηÏ\82 Î­ÎºÎ´Î¿Ï\83ηÏ\82 Ï\84Ï\89ν Î Ï\81Ï\8cÏ\83Ï\86αÏ\84Ï\89ν Î\91λλαγÏ\8eν",
-       "rcfilters-preference-help": "Î\91ναÏ\83Ï\84έλλει Ï\84ον ÎµÏ\80αναÏ\83Ï\87εδιαÏ\83μÏ\8c Î´Î¹ÎµÏ\80αÏ\86ήÏ\82 2017 ÎºÎ±Î¹ Ï\8cλα Ï\84α ÎµÏ\81γαλεία Ï\80οÏ\85 Ï\80Ï\81οÏ\83Ï\84έθηκαν Ï\83Ï\84η Ï\83Ï\85νέÏ\87εια ÎºÎ±Î¹ Î±Ï\80Ï\8c Ï\84Ï\8cÏ\84ε.",
+       "rcfilters-preference-label": "ΧÏ\81ήÏ\83η Î´Î¹ÎµÏ\80αÏ\86ήÏ\82 Ï\87Ï\89Ï\81ίÏ\82 JavaScript",
+       "rcfilters-preference-help": "ΦοÏ\81Ï\84Ï\8eνει Ï\84ιÏ\82 Î Ï\81Ï\8cÏ\83Ï\86αÏ\84εÏ\82 Î\91λλαγέÏ\82 Ï\87Ï\89Ï\81ίÏ\82 Ï\86ίλÏ\84Ï\81α Î±Î½Î±Î¶Î®Ï\84ηÏ\83ηÏ\82 Î® Î»ÎµÎ¹Ï\84οÏ\85Ï\81γία ÎµÏ\80ιÏ\83ήμανÏ\83ηÏ\82.",
        "rcfilters-watchlist-preference-label": "Χρήση πίνακα διεπαφής όχι-JavaScript",
-       "rcfilters-watchlist-preference-help": "Φορτώσεις Watchlist χωρίς φίλτρα ή τονισμό με χρώμα.",
+       "rcfilters-watchlist-preference-help": "Φορτώνει την Λίστα Παρακολούθησης χωρίς φίλτρα αναζήτησης ή λειτουργία επισήμανσης.",
        "rcfilters-filter-showlinkedfrom-option-label": "<strong>Σελίδες που συνδέονται από</strong> τη επιλεγμένη σελίδα",
        "rcfilters-filter-showlinkedto-label": "Εμφάνιση αλλαγών σε σελίδες που συνδέουν σε",
        "rcfilters-target-page-placeholder": "Εισαγάγετε όνομα σελίδας (ή κατηγορίας)",
        "minoreditletter": "μ",
        "newpageletter": "Ν",
        "boteditletter": "ρ",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|χρήστης|χρήστες}} παρακολουθούν]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} μετά από την αλλαγή",
        "newsectionsummary": "/* $1 */ νέα ενότητα",
        "rc-enhanced-expand": "Εμφάνιση λεπτομερειών",
        "img-auth-nopathinfo": "Λείπει το PATH_INFO.\nΟ διακομιστής σας δεν είναι ρυθμισμένος για να περάσει αυτές τις πληροφορίες.\nΜπορεί να είναι βασισμένος σε CGI και να μην υποστηρίζει img_atuh.\nΔείτε https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization",
        "img-auth-notindir": "Η ζητούμενη διαδρομή δεν βρίσκεται στον διαμορφωμένο αρχειοκατάλογο επιφορτώσεων",
        "img-auth-badtitle": "Αδύνατη η κατασκευή έγκυρου τίτλου από \"$1\".",
-       "img-auth-nologinnWL": "Δεν έχετε συνδεθεί και η \"$1\" δεν είναι στην άσπρη λίστα.",
        "img-auth-nofile": "Το αρχείο \"$1\" δεν υπάρχει",
        "img-auth-isdir": "Προσπαθείτε να αποκτήσετε πρόσβαση στον αρχειοκατάλογο \"$1\".\nΜόνον η πρόσβαση σε αρχεία είναι επιτρεπτή.",
        "img-auth-streaming": "Ροή \"$1\".",
        "statistics-articles": "Σελίδες περιεχομένου",
        "statistics-pages": "Σελίδες",
        "statistics-pages-desc": "Όλες οι σελίδες του wiki, συμπεριλαμβανομένων των σελίδων συζήτησης, ανακατευθύνσεων, κλπ.",
-       "statistics-files": "Αρχεία που έχουν επιφορτωθεί",
+       "statistics-files": "Ανεβασμένα αρχεία",
        "statistics-edits": "Επεξεργασίες σελίδων από τη δημιουργία του εγχειρήματος {{SITENAME}}",
        "statistics-edits-average": "Μέσος όρος επεξεργασιών ανά σελίδα",
        "statistics-users": "Εγγεγραμμένοι χρήστες",
        "prefixindex": "Όλες οι σελίδες με πρόθεμα",
        "prefixindex-namespace": "Όλες οι σελίδες με πρόθεμα (ονοματοχώρος $1)",
        "prefixindex-submit": "Προβολή",
-       "prefixindex-strip": "Î\91Ï\86αίÏ\81εÏ\83η Ï\84οÏ\85 Ï\80Ï\81οθέμαÏ\84οÏ\82 Ï\83Ï\84η Î»Î¯Ï\83τα",
+       "prefixindex-strip": "Î\91Ï\80Ï\8cκÏ\81Ï\85Ï\88η Ï\84οÏ\85 Ï\80Ï\81οθέμαÏ\84οÏ\82 Ï\83Ï\84α Î±Ï\80οÏ\84ελέÏ\83ματα",
        "shortpages": "Σύντομες σελίδες",
        "longpages": "Εκτενείς σελίδες",
        "deadendpages": "Αδιέξοδες σελίδες",
        "booksources-text": "Παρακάτω είναι μια λίστα συνδέσμων σε άλλους ιστοτόπους οι οποίοι πωλούν νέα και μεταχειρισμένα βιβλία, και μπορεί επίσης να έχουν περισσότερες πληροφορίες για βιβλία για τα οποία ψάχνετε:",
        "booksources-invalid-isbn": "Το δοσμένο ISBN δεν φαίνεται να είναι έγκυρο· ελέγξτε για λάθη κατά την αντιγραφή από την αρχική πηγή.",
        "specialloguserlabel": "",
-       "speciallogtitlelabel": "Στόχος (τίτλος ή {{ns:user}}:χρήστης για χρήστη):",
+       "speciallogtitlelabel": "Στόχος (τίτλος ή «{{ns:user}}:Τάδε» για χρήστη):",
        "log": "Αρχεία καταγραφών",
        "logeventslist-submit": "Προβολή",
+       "logeventslist-more-filters": "Εμφάνιση επιπρόσθετων καταγραφών:",
+       "logeventslist-tag-log": "Καταγραφές ετικετών",
        "all-logs-page": "Όλες οι δημόσιες καταγραφές γεγονότων",
        "alllogstext": "Εποπτική εμφάνιση όλων των ενεργειών φόρτωσης αρχείων, διαγραφής, προστασίας, φραγής και όλων των καταγραφών των διαχειριστών στο αρχείο γεγονότων του {{SITENAME}}. Μπορείτε να περιορίσετε τα αποτελέσματα που εμφανίζονται επιλέγοντας συγκεκριμένο είδος γεγονότων, όνομα χρήστη ή τη σελίδα που επηρεάστηκε.",
        "logempty": "Δεν υπάρχουν στοιχεία που να ταιριάζουν στο αρχείο καταγραφών.",
-       "log-title-wildcard": "Î\91ναζήÏ\84ηÏ\83ε Ï\84ίÏ\84λοÏ\85Ï\82 που αρχίζουν με αυτό το κείμενο",
+       "log-title-wildcard": "Î\91ναζήÏ\84ηÏ\83η Ï\84ίÏ\84λÏ\89ν που αρχίζουν με αυτό το κείμενο",
        "showhideselectedlogentries": "Αλλαγή ορατότητας των επιλεγμένων καταχωρήσεων στο αρχείο καταγραφής συμβάντων",
        "log-edit-tags": "Επεξεργασία ετικετών των επιλεγμένων καταχωρήσεων του αρχείου καταγραφής",
        "checkbox-select": "Επιλογή: $1",
        "cachedspecial-refresh-now": "Προβολή τελευταίας.",
        "categories": "Κατηγορίες",
        "categories-submit": "Εμφάνιση",
-       "categoriespagetext": "Οι ακόλουθες {{PLURAL:$1|κατηγορία περιέχει|κατηγορίες περιέχουν}} σελίδες ή μέσα.\nΟι [[Special:UnusedCategories|αχρησιμοποίητες κατηγορίες]] δεν εμφανίζονται εδώ.\nΔείτε επίσης τις [[Special:WantedCategories|ζητούμενες κατηγορίες]].",
+       "categoriespagetext": "{{PLURAL:$1|Η ακόλουθη κατηγορία υπάρχει|Οι ακόλουθες κατηγορίες υπάρχουν}} σε αυτό το wiki, και μπορεί ή μπορεί να μην είναι {{PLURAL:$1|αχρησιμοποίητη|αχρησιμοποίητες}}.\nΔείτε επίσης τις [[Special:WantedCategories|ζητούμενες κατηγορίες]].",
        "categoriesfrom": "Εμφάνιση κατηγοριών που αρχίζουν από:",
        "deletedcontributions": "Διαγεγραμμένες συνεισφορές χρήστη",
        "deletedcontributions-title": "Διαγεγραμμένες συνεισφορές χρήστη",
        "delete-confirm": "Διαγραφή του \"$1\"",
        "delete-legend": "Διαγραφή",
        "historywarning": "<strong>Προσοχή:</strong> Η σελίδα που πρόκειται να διαγράψετε έχει ιστορικό με περίπου $1 {{PLURAL:$1|επεξεργασία|επεξεργασίες}}:",
-       "historyaction-submit": "Προβολή",
+       "historyaction-submit": "Προβολή αναθεωρήσεων",
        "confirmdeletetext": "Πρόκειται να διαγράψετε οριστικά από τη βάση δεδομένων μια σελίδα (ή μια εικόνα) μαζί με το ιστορικό της. Παρακαλούμε επιβεβαιώστε ότι θέλετε πραγματικά να το κάνετε, ότι αντιλαμβάνεσθε τις συνέπειες και ότι το κάνετε σύμφωνα με την [[{{MediaWiki:Policy-url}}|πολιτική]].",
        "actioncomplete": "Η ενέργεια ολοκληρώθηκε.",
        "actionfailed": "Η ενέργεια απέτυχε",
        "deleteprotected": "Δεν μπορείτε να διαγράψετε αυτή τη σελίδα επειδή είναι προστατευόμενη.",
        "deleting-backlinks-warning": "<strong>Προσοχή:</strong>  [[Special:WhatLinksHere/{{FULLPAGENAME}}|Άλλες σελίδες]] συνδέουν ή ενσωματώνουν τη σελίδα που πρόκειται να διαγράψετε.",
        "rollback": "Επαναφορά επεξεργασιών",
+       "rollback-confirmation-no": "Ακύρωση",
        "rollbacklink": "αναστροφή",
        "rollbacklinkcount": "Αναστροφή $1 {{PLURAL:$1|επεξεργασίας|επεξεργασιών}}",
        "rollbacklinkcount-morethan": "αναστροφή περισσότερων από $1 {{PLURAL:$1|επεξεργασία|επεξεργασίες}}",
        "revertpage": "Ανάκληση των αλλαγών [[Special:Contributions/$2|$2]] ([[User talk:$2|συζήτηση]]) επιστροφή στην προηγούμενη αναθεώρηση [[User:$1|$1]]",
        "revertpage-nouser": "Αναστράφηκαν οι επεξεργασίες από τον (όνομα χρήστη αφαιρέθηκε) στη τελευταία έκδοση από τον/την {{GENDER:$1|[[User:$1|$1]]}}φ",
        "rollback-success": "Αναστροφή επεξεργασιών από {{GENDER:$3|τον|την}} $1, επιστροφή στην προηγούμενη έκδοση από {{GENDER:$4|τον|την}} $2.",
-       "rollback-success-notify": "Αναίρεση επεξεργασιών από $1; επιστροφή στην τελευταία αναθεώρηση από $2.[$3 Εμφάνιση αλλαγών]",
-       "sessionfailure-title": "Η συνεδρία απέτυχε",
-       "sessionfailure": "Υπάρχει πρόβλημα με τη σύνδεσή σας -η ενέργεια αυτή ακυρώθηκε προληπτικά για την αντιμετώπιση τυχόν πειρατείας συνόδου (session hijacking). Παρακαλoύμε πατήστε \"Επιστροφή\", ξαναφορτώστε τη σελίδα από την οποία φθάσατε εδώ και προσπαθήστε ξανά.",
+       "sessionfailure-title": "Αποτυχία περιόδου σύνδεσης",
+       "sessionfailure": "Φαίνεται ότι υπάρχει κάποιο πρόβλημα με την περίοδο σύνδεσής σας.\nΑυτή η ενέργεια ακυρώθηκε ως προφύλαξη για την αντιμετώπιση τυχόν σφετερισμού της περιόδου σύνδεσης από κάποιον τρίτο (session hijacking).\nΠαρακαλούμε υποβάλετε ξανά τη φόρμα.",
        "changecontentmodel": "Αλλαγή μοντέλου περιεχομένου της σελίδας",
        "changecontentmodel-legend": "Μοντέλο περιεχομένου σελίδας",
        "changecontentmodel-title-label": "Τίτλος σελίδας",
        "uctop": "τρέχουσα",
        "month": "Από το μήνα (και νωρίτερα):",
        "year": "Από το έτος (και νωρίτερα):",
+       "date": "Από ημερομηνία (και νωρίτερα):",
        "sp-contributions-newbies": "Εμφάνιση των συνεισφορών των νέων λογαριασμών μόνο",
        "sp-contributions-newbies-sub": "Για νέους λογαριασμούς",
        "sp-contributions-newbies-title": "Συνεισφορές χρηστών για νέους λογαριασμούς",
        "ipbreason": "Αιτία:",
        "ipbreason-dropdown": "*Συχνοί λόγοι φραγής\n** Εισαγωγή λανθασμένων πληροφοριών\n** Αφαίρεση περιεχομένου από σελίδες\n** Σύνδεσμοι τύπου spam σε εξωτερικούς ιστοτόπους\n** Εισαγωγή ασυναρτησιών σε σελίδες\n** Εκφοβιστική συμπεριφορά/παρενόχληση\n** Κατάχρηση πολλαπλών λογαριασμών\n** Απαράδεκτο όνομα χρήστη",
        "ipb-hardblock": "Αποτρέψετε σε συνδεδεμένους χρήστες την επεξεργασία από αυτήν τη διεύθυνση IP",
-       "ipbcreateaccount": "Î\91Ï\80οÏ\84Ï\81οÏ\80ή Î´Î·Î¼Î¹Î¿Ï\85Ï\81γίαÏ\82 λογαριασμού",
-       "ipbemailban": "Î\91Ï\80οÏ\84Ï\81οÏ\80ή Î±Ï\80οÏ\83Ï\84ολήÏ\82 e-mail Î±Ï\80Ï\8c Ï\84ον Ï\87Ï\81ήÏ\83Ï\84η",
+       "ipbcreateaccount": "Î\94ημιοÏ\85Ï\81γία λογαριασμού",
+       "ipbemailban": "Î\91Ï\80οÏ\83Ï\84ολή email",
        "ipbenableautoblock": "Φράξε αυτόματατα την τελευταία διεύθυνση IP που χρησιμοποιήθηκε από αυτό τον χρήστη, και όποιες ακόλουθες IP από τις οποίες δοκιμάζει να επεξεργαστεί",
        "ipbsubmit": "Φραγή αυτού του χρήστη",
        "ipbother": "Άλλη ώρα",
        "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",
        "ipbhidename": "Απόκρυψη ονόματος χρήστη από επεξεργασίες και καταλόγους",
        "ipbwatchuser": "Παρακολούθηση των σελίδων 'χρήστη' και 'συζήτησης χρήστη' αυτού του χρήστη",
-       "ipb-disableusertalk": "Î\91Ï\80οÏ\84Ï\81έÏ\88Ï\84ε Î±Ï\85Ï\84Ï\8c Ï\84ο Ï\87Ï\81ήÏ\83Ï\84η Î±Ï\80Ï\8c Ï\84ην ÎµÏ\80εξεÏ\81γαÏ\83ία Ï\84ηÏ\82 Î´Î¹ÎºÎ® Ï\84οÏ\85 Ï\83ελίδαÏ\82 Ï\83Ï\85ζήÏ\84ηÏ\83ηÏ\82, ÎµÎ½Ï\8e ÎµÎ¯Î½Î±Î¹ Î±Ï\80οκλειÏ\83μένος",
+       "ipb-disableusertalk": "Î\95Ï\80εξεÏ\81γαÏ\83ία Ï\84ηÏ\82 Î´Î¹ÎºÎ® Ï\84οÏ\85 Ï\83ελίδαÏ\82 Ï\83Ï\85ζήÏ\84ηÏ\83ης",
        "ipb-change-block": "Επαναφραγή του χρήστη με αυτές τις ρυθμίσεις",
        "ipb-confirm": "Επιβεβαίωση φραγής",
        "ipb-partial": "Μερική",
        "ipb-pages-label": "Σελίδες",
+       "ipb-namespaces-label": "Ονοματοχώροι",
        "badipaddress": "Άκυρη διεύθυνση IP.",
        "blockipsuccesssub": "Η φραγή ολοκληρώθηκε επιτυχώς.",
        "blockipsuccesstext": "{{GENDER:$1|Ο|Η}} [[Special:Contributions/$1|$1]] έχει υποστεί φραγή.<br />\nΔείτε τον [[Special:BlockList|κατάλογο φραγών]] για να εποπτεύσετε τις φραγές.",
        "ipb-blocklist-contribs": "Συνεισφορές {{GENDER:$1|του $1|της $1}}",
        "ipb-blocklist-duration-left": "Απομένουν $1",
        "block-expiry": "Λήξη",
+       "block-reason": "Αιτία:",
        "unblockip": "Άρση φραγής χρήστη",
        "unblockiptext": "Χρησιμοποιήστε την παρακάτω φόρμα για να αποκαταστήσετε την πρόσβαση σε επεξεργασία, σε μια διεύθυνση IP ή σε ένα χρήστη που είχε αποκλειστεί με φραγή.",
        "ipusubmit": "Άρση φραγής",
        "createaccountblock": "δημιουργία λογαριασμού μπλοκαρισμένη",
        "emailblock": "το ηλεκτρονικό ταχυδρομείο έχει απενεργοποιηθεί",
        "blocklist-nousertalk": "δεν μπορεί να επεξεργαστεί τη σελίδα συζήτησής του",
+       "blocklist-editing-page": "σελίδες",
+       "blocklist-editing-ns": "ονοματοχώροι",
        "ipblocklist-empty": "Η λίστα φραγών είναι άδεια.",
        "ipblocklist-no-results": "Η ζητούμενη διεύθυνση IP ή το όνομα χρήστη δεν είναι φραγμένα.",
        "blocklink": "φραγή",
        "fix-double-redirects": "Ενημερώστε όποια ανακατεύθυνση σκοπεύει προς τον αρχικό τίτλο",
        "move-leave-redirect": "Αφήστε πίσω μια ανακατεύθυνση",
        "protectedpagemovewarning": "Προειδοποίηση'' ':''' Αυτή η σελίδα έχει κλειδωθεί ώστε μόνο χρήστες με δικαιώματα διαχειριστή μπορούν να την μετακινήσουν.\nΗ πιο πρόσφατη καταχώρηση του αρχείου καταγραφής παρέχεται παρακάτω για αναφορά:",
-       "semiprotectedpagemovewarning": "'''Σημείωση:''' Αυτή η σελίδα έχει κλειδωθεί έτσι ώστε μόνο οι εγγεγραμμένοι χρήστες να μπορούν να την μετακινήσουν.\nΗ πιο πρόσφατη καταχώρηση του αρχείου καταγραφής παρέχεται παρακάτω για αναφορά:",
+       "semiprotectedpagemovewarning": "<strong>Σημείωση:</strong> Αυτή η σελίδα έχει προστατευθεί έτσι ώστε μόνο αυτοεπιβεβαιωμένοι χρήστες να μπορούν να την μετακινήσουν.\nΗ πιο πρόσφατη καταχώρηση του αρχείου καταγραφής παρέχεται παρακάτω για αναφορά:",
        "move-over-sharedrepo": "== Το αρχείο υπάρχει ==\nΤο [[:$1]] υπάρχει σε ένα κοινό αποθετήριο. Η μετακίνηση ενός αρχείου προς αυτόν τον τίτλο θα παρακάμψει το κοινό αρχείο.",
        "file-exists-sharedrepo": "Το όνομα αρχείου που επιλέχθηκε είναι ήδη σε χρήση σε ένα κοινό χώρο αποθήκευσης.\nΠαρακαλούμε επιλέξτε ένα άλλο όνομα.",
        "export": "Εξαγωγή σελίδων",
        "allmessagesdefault": "Προεπιλεγμένο κείμενο μηνύματος",
        "allmessagescurrent": "Παρόν κείμενο",
        "allmessagestext": "Αυτή είναι μια λίστα με όλα τα μηνύματα συστήματος που βρίσκονται στην περιοχή MediaWiki.\nΠαρακαλούμε επισκεφθείτε τα [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] και [https://translatewiki.net translatewiki.net] αν επιθυμείτε να συνεισφέρετε σε μια γενική μετάφραση του MediaWiki.",
-       "allmessagesnotsupportedDB": "Αυτή η σελίδα δεν υποστηρίζεται επειδή το ''wgUseDatabaseMessages'' είναι απενεργοποιημένο.",
+       "allmessages-not-supported-database": "Αυτή η σελίδα δεν υποστηρίζεται επειδή το ''wgUseDatabaseMessages'' είναι απενεργοποιημένο.",
        "allmessages-filter-legend": "Φίλτρο",
        "allmessages-filter": "Ταξινόμηση βάσει της δήλωσης προσαρμογής:",
        "allmessages-filter-unmodified": "Ατροποποίητο",
        "pageinfo-category-subcats": "Αριθμός υποκατηγοριών",
        "pageinfo-category-files": "Αριθμός αρχείων",
        "pageinfo-user-id": "Αναγνωριστικό χρήση",
+       "pageinfo-view-protect-log": "Δείτε το αρχείο καταγραφών προστασίας για αυτή τη σελίδα.",
        "markaspatrolleddiff": "Σήμανση ως ελεγμένο",
        "markaspatrolledtext": "Σήμανση αυτής της σελίδας ως ελεγμένης",
        "markaspatrolledtext-file": "Επισημάνετε αυτή τη έκδοση του αρχείου ως ελεγμένη",
        "markedaspatrollederror-noautopatrol": "Δεν επιτρέπεται να σημάνετε τις δικές σας αλλάγες ως υπό περιπολία.",
        "markedaspatrollednotify": "Αυτή η αλλαγή σε $1 έχει επισημανθεί ως ελεγμένη.",
        "markedaspatrollederrornotify": "Σήμανση ως ελεγμένη απέτυχε.",
-       "patrol-log-page": "Î\91Ï\81Ï\87είο ÎºÎ±Ï\84αγÏ\81αÏ\86ήÏ\82 Ï\80εÏ\81ιÏ\80ολιών",
+       "patrol-log-page": "Î\9aαÏ\84αγÏ\81αÏ\86έÏ\82 ÎµÎ»Î­Î³Ï\87Ï\89ν ÎµÏ\80εξεÏ\81γαÏ\83ιών",
        "patrol-log-header": "Αυτό είναι μητρώο ελεγμένων αναθεωρήσεων.",
        "confirm-markpatrolled-button": "Εντάξει",
        "deletedrevision": "Η παλιά έκδοση της $1 διαγράφτηκε",
        "previousdiff": "← Παλαιότερη επεξεργασία",
        "nextdiff": "Νεότερη επεξεργασία →",
        "mediawarning": "'''Προειδοποίηση''': Το αρχείο αυτό μπορεί να περιέχει κακοπροαίρετο κώδικα.\nΕκτελώντας το, μπορεί να βλάψει το σύστημα του υπολογιστή σας.",
-       "imagemaxsize": "Όριο μεγέθους εικόνων:<br />''(στις σελίδες περιγραφής εικόνων)''",
+       "imagemaxsize": "Όριο μεγέθους εικόνων στις σελίδες περιγραφής εικόνων:",
        "thumbsize": "Μέγεθος μικρογραφίας:",
        "widthheightpage": "$1 × $2, $3 {{PLURAL:$3|σελίδα|σελίδες}}",
        "file-info": "μέγεθος αρχείου: $1, τύπος MIME: $2",
        "confirmemail": "Επιβεβαίωση διεύθυνσης ηλεκτρονικού ταχυδρομείου",
        "confirmemail_noemail": "Δεν έχετε ορίσει μια έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου στις [[Special:Preferences|προτιμήσεις χρήστη]] σας.",
        "confirmemail_text": "Το σύστημα χρειάζεται να επαληθεύσει τη διεύθυνση e-mail που δώσατε για να χρησιμοποιήσετε τις δυνατότητες αλληλογραφίας. Κάνετε κλικ στο παρακάτω κουμπί και θα σας αποσταλεί μήνυμα επαλήθευσης στη διεύθυνσή σας. Στο μήνυμα αυτό θα εμφανίζεται ένας σύνδεσμος που Θα περιέχει τον κωδικό επαλήθευσης -ακολουθήστε το σύνδεσμο αυτό για να μπορέσει το σύστημα να επαληθεύσει τη διεύθυνση αλληλογραφίας σας.",
-       "confirmemail_pending": "Ένας κωδικός επιβεβαίωσης σας έχει ήδη σταλεί μέσω μηνύματος e-mail. Αν δημιουργήσατε\nπρόσφατα το λογαριασμό σας, μπορεί να θέλετε να περιμένετε μερικά λεπτά\nγια να φτάσει αυτό πριν προσπαθήσετε να ζητήσετε ένα νέο κωδικό.",
+       "confirmemail_pending": "Ένας κωδικός επιβεβαίωσης σας έχει ήδη σταλεί μέσω μηνύματος ηλεκτρονικού ταχυδρομείου. \nΑν δημιουργήσατε πρόσφατα το λογαριασμό σας, ίσως θα θέλετε να περιμένετε μερικά λεπτά για να φτάσει το μήνυμα πριν προσπαθήσετε να ζητήσετε νέο κωδικό.",
        "confirmemail_send": "Αποστολή κωδικού επαλήθευσης με e-mail .",
        "confirmemail_sent": "Στάλθηκε το μήνυμα ηλεκτρονικού ταχυδρομείου για επιβεβαίωση.",
        "confirmemail_oncreate": "Ένας κωδικός επιβεβαίωσης σας έχει σταλεί στην διεύθυνση e-mail σας.\nΑυτός ο κωδικός δεν είναι απαραίτητος για να συνδεθείτε, αλλά θα χρειαστεί\nνα τον παρέχετε πριν ενεργοποιήσετε οποιαδήποτε χαρακτηριστικά βασισμένα σε e-mail, σε αυτό το wiki.",
        "confirm-unwatch-top": "Κατάργηση αυτής της σελίδας από τη λίστα παρακολούθησης σας;",
        "confirm-rollback-button": "Εντάξει",
        "confirm-rollback-top": "Επαναφέρετε τις επεξεργασίες σε αυτή τη σελίδα;",
+       "confirm-mcrrestore-title": "Επαναφορά αναθεώρησης",
+       "confirm-mcrundo-title": "Αναίρεση αλλαγής",
+       "mcrundofailed": "Η αναίρεση απέτυχε",
        "semicolon-separator": "•&#32;",
        "quotation-marks": "«$1»",
        "imgmultipageprev": "← προηγούμενη σελίδα",
        "redirect-file": "Όνομα αρχείου",
        "redirect-logid": "Αναγνωριστικό μητρώου",
        "redirect-not-exists": "Η τιμή δε βρέθηκε",
+       "redirect-not-numeric": "Η τιμή δεν είναι αριθμητική",
        "fileduplicatesearch": "Αναζήτηση για διπλά αρχεία",
        "fileduplicatesearch-summary": "Αναζήτηση για διπλά αρχεία με βάση την τιμή hash του αρχείου.",
        "fileduplicatesearch-filename": "Όνομα αρχείου:",
        "logentry-newusers-newusers": "Ο λογαριασμός χρήστη $1 {{GENDER:$2|δημιουργήθηκε}}",
        "logentry-newusers-create": "Ο λογαριασμός χρήστη $1 {{GENDER:$2|δημιουργήθηκε}}",
        "logentry-newusers-create2": "Ο λογαριασμός χρήστη $3 δημιουργήθηκε από {{GENDER:$2|τον|την}} $1",
-       "logentry-newusers-byemail": "Î\9f Î»Î¿Î³Î±Ï\81ιαÏ\83μÏ\8cÏ\82 Ï\87Ï\81ήÏ\83Ï\84η $3 Î´Î·Î¼Î¹Î¿Ï\85Ï\81γήθηκε Î±Ï\80Ï\8c {{GENDER:$2|Ï\84ον|Ï\84ην}} $1 ÎºÎ±Î¹ Î¿ ÎºÏ\89δικÏ\8cÏ\82 Ï\80Ï\81Ï\8cÏ\83βαÏ\83ηÏ\82 ÎµÏ\83Ï\84άλη μέσω ηλεκτρονικού ταχυδρομείου",
+       "logentry-newusers-byemail": "Î\9f Î»Î¿Î³Î±Ï\81ιαÏ\83μÏ\8cÏ\82 Ï\87Ï\81ήÏ\83Ï\84η $3 Î´Î·Î¼Î¹Î¿Ï\85Ï\81γήθηκε Î±Ï\80Ï\8c {{GENDER:$2|Ï\84ον|Ï\84ην}} $1 ÎºÎ±Î¹ Î±Ï\80εÏ\83Ï\84άλη Ï\83Ï\85νθημαÏ\84ικÏ\8c μέσω ηλεκτρονικού ταχυδρομείου",
        "logentry-newusers-autocreate": "Ο λογαριασμός χρήστη $1 δημιουργήθηκε αυτόματα",
        "logentry-protect-protect": "$1 {{GENDER:$2|προστατευμένος|προστατευμένη}} $3 $4",
        "logentry-protect-modify": "$1 {{GENDER:$2|άλλαξε}} επίπεδο προστασίας για $3 $4",
        "logentry-rights-autopromote": "$1 {{GENDER:$2|προωθήθηκε}} αυτόματα από το $4 στο $5",
        "logentry-upload-upload": "{{GENDER:$2|Ο|Η}} $1 ανέβασε το $3",
        "logentry-upload-overwrite": "{{GENDER:$2|Ο|Η}} $1 ανέβασε μια νέα έκδοση του $3",
-       "logentry-upload-revert": "{{GENDER:$2|Î\9f\97}} $1 Î±Î½Î­Î²Î±Ï\83ε Ï\84ο $3",
+       "logentry-upload-revert": "{{GENDER:$2|Î\9f\97}} $1 ÎµÏ\80ανέÏ\86εÏ\81ε Ï\84ο $3 Ï\83ε Î¼Î¹Î± Ï\80αλιά Î­ÎºÎ´Î¿Ï\83η",
        "log-name-managetags": "Αρχείο καταγραφών διαχείρισης ετικετών",
        "log-description-managetags": "Αυτή η σελίδα περιέχει εργασίες διαχείρισης που σχετίζονται με τις [[Special:Tags|ετικέτες]]. Το αρχείο καταγραφής περιέχει μόνο οι ενέργειες που πραγματοποιούνται με το χέρι  από κάποιον διαχειριστή· ετικέτες μπορούν να δημιουργηθούν ή να διαγραφούν από το λογισμικό wiki, χωρίς κάποια καταχώριση να καταχωρίζεται σε αυτό το αρχείο καταγραφής.",
        "logentry-managetags-create": "{{GENDER:$2|Ο|Η}} $1 δημιούργησε την ετικέτα «$4»",
        "expand_templates_generate_xml": "Εμφάνιση δέντρου συντακτικής ανάλυσης XML",
        "expand_templates_generate_rawhtml": "Εμφάνιση ανεπεξέργαστης HTML",
        "expand_templates_preview": "Προεπισκόπηση",
-       "expand_templates_preview_fail_html": "<em>Επειδή το {{SITENAME}} επιτρέπει την εισαγωγή ακατέργαστου HTML και υπήρξε μια απώλεια των δεδομένων συνόδου, η προεπισκόπηση είναι κρυμμένη ως ένα προληπτικό μέτρο κατά επιθέσεων JavaScript.</em>\n\n<strong>Αν αυτή είναι μια θεμιτή προσπάθεια προεπισκόπησης, παρακαλούμε δοκιμάστε ξανά.</strong>\nΑν εξακολουθεί να μην λειτουργεί, δοκιμάστε να [[Special:UserLogout|αποσυνδεθείτε]] και να συνδεθείτε ξανά και βεβαιωθείτε ότι το πρόγραμμα περιήγησής σας επιτρέπει cookies από αυτόν τον ιστότοπο.",
+       "expand_templates_preview_fail_html": "<em>Επειδή το {{SITENAME}} επιτρέπει την εισαγωγή ακατέργαστου HTML και υπήρξε μια απώλεια δεδομένων της περιόδου σύνδεσης, η προεπισκόπηση είναι κρυμμένη ως προληπτικό μέτρο κατά επιθέσεων JavaScript.</em>\n\n<strong>Αν αυτή είναι μια θεμιτή απόπειρα προεπισκόπησης, παρακαλούμε δοκιμάστε ξανά.</strong>\nΑν εξακολουθεί να μην λειτουργεί, δοκιμάστε να [[Special:UserLogout|αποσυνδεθείτε]] και να συνδεθείτε ξανά και βεβαιωθείτε ότι το πρόγραμμα περιήγησής σας επιτρέπει cookies από αυτόν τον ιστότοπο.",
        "expand_templates_preview_fail_html_anon": "<em>Επειδή το {{SITENAME}} έχει ενεργοποιημένη raw HTML και δεν είστε συνδεδεμένοι, η προεπισκόπηση είναι κρυμμένη ως ένα προληπτικό μέτρο ενάντια σε επιθέσεις JavaScript.</em>\n\n<strong>Αν αυτό είναι δικαιολογημένη απόπειρα προεπισκόπησης, παρακαλούμε να [[Special:UserLogin|συνδεθείτε]] και δοκιμάστε πάλι.</strong>",
        "pagelanguage": "Αλλαγή γλώσσας σελίδας",
        "pagelang-name": "Σελίδα",
        "special-characters-title-minus": "σύμβολο πλην",
        "mw-widgets-abandonedit": "Είστε βέβαιοι ότι θέλετε να αφήσετε την κατάσταση επεξεργασίας χωρίς να αποθηκεύσετε πρώτα;",
        "mw-widgets-abandonedit-discard": "Απόρριψη επεξεργασιών",
-       "mw-widgets-abandonedit-keep": "ΣÏ\85νεÏ\87ίÏ\83Ï\84ε Ï\84ην ÎµÏ\80εξεÏ\81γαÏ\83ία",
+       "mw-widgets-abandonedit-keep": "ΣÏ\85νέÏ\87εια ÎµÏ\80εξεÏ\81γαÏ\83ίαÏ\82",
        "mw-widgets-abandonedit-title": "Είσαι σίγουρος;",
        "mw-widgets-dateinput-no-date": "Καμία ημερομηνία δεν επιλέχθηκε",
        "mw-widgets-dateinput-placeholder-day": "ΕΕΕΕ-ΜΜ-ΗΗ",
        "mw-widgets-titlesmultiselect-placeholder": "Προσθήκη περισσότερων...",
        "date-range-from": "Από ημερομηνία:",
        "date-range-to": "Έως ημερομηνία:",
-       "sessionprovider-generic": "$1 συνεδρίες",
-       "sessionprovider-mediawiki-session-cookiesessionprovider": "Ï\83Ï\85νεδÏ\81ίεÏ\82 Î¼Îµ Î²Î¬Ï\83η Ï\84α cookies",
+       "sessionprovider-generic": "Περίοδοι σύνδεσης $1",
+       "sessionprovider-mediawiki-session-cookiesessionprovider": "Ï\80εÏ\81ίοδοι Ï\83Ï\8dνδεÏ\83ηÏ\82 Î²Î±Ï\83ιÏ\83μένεÏ\82 Ï\83ε cookies",
        "sessionprovider-nocookies": "Τα Cookies μπορούν να απενεργοποιηθούν. Βεβαιωθείτε ότι έχετε ενεργοποιημένα τα cookies και ξεκινήστε πάλι.",
        "randomrootpage": "Τυχαία κύρια σελίδα",
        "log-action-filter-block": "Τύπος φραγής:",
        "authmanager-email-help": "Διεύθυνση ηλεκτρονικού ταχυδρομείου:",
        "authmanager-realname-label": "Πραγματικό όνομα",
        "authmanager-realname-help": "Πραγματικό όνομα του χρήστη",
-       "authmanager-provider-temporarypassword": "Προσωρινός κωδικός",
+       "authmanager-provider-temporarypassword": "Προσωρινό συνθηματικό",
        "authprovider-resetpass-skip-label": "Παράβλεψη",
        "authprovider-resetpass-skip-help": "Παράβλεψη της επαναφοράς του κωδικού πρόσβασης.",
        "specialpage-securitylevel-not-allowed-title": "Δεν επιτρέπεται",
        "edit-error-short": "Σφάλμα: $1",
        "edit-error-long": "Σφάλματα: \n\n$1",
        "revid": "αναθεώρηση $1",
+       "interfaceadmin-info": "$1\n\nΟι άδειες για την επεξεργασία καθολικών αρχείων CSS/JS/JSON διαχωρίστηκαν πρόσφατα από το δικαίωμα <code>editinterface</code>. Εάν δεν καταλαβαίνετε γιατί εμφανίζεται αυτό το σφάλμα, ανατρέξτε στο [[mw:MediaWiki_1.32/interface-admin]].",
+       "gotointerwiki-invalid": "Ο καθορισμένος τίτλος δεν είναι έγκυρος.",
        "pagedata-title": "Δεδομένα σελίδας",
        "pagedata-bad-title": "Μη έγκυρος τίτλος: $1.",
-       "passwordpolicies-policy-passwordnotinlargeblacklist": "Ο κωδικός πρόσβασης δεν μπορεί να είναι στην λίστα των 100.000 πιο συνηθισμένων κωδικών πρόσβασης."
+       "unregistered-user-config": "Για λόγους ασφαλείας δεν είναι δυνατή η φόρτωση υποσελίδων χρήστη JavaScript, CSS και JSON για μη εγγεγραμμένους χρήστες.",
+       "passwordpolicies": "Πολιτικές συνθηματικού",
+       "passwordpolicies-summary": "Αυτή είναι μια λίστα με τις ισχύουσες πολιτικές συνθηματικού για τις ομάδες χρηστών που καθορίζονται σε αυτό το wiki.",
+       "passwordpolicies-group": "Ομάδα",
+       "passwordpolicies-policies": "Πολιτικές",
+       "passwordpolicies-policy-minimalpasswordlength": "Το συνθηματικό πρέπει να έχει μήκος τουλάχιστον $1 {{PLURAL:$1|χαρακτήρα|χαρακτήρων}}",
+       "passwordpolicies-policy-minimumpasswordlengthtologin": "Το συνθηματικό πρέπει να έχει μήκος τουλάχιστον $1 {{PLURAL:$1|χαρακτήρα|χαρακτήρων}} για να είναι δυνατή η σύνδεση",
+       "passwordpolicies-policy-passwordcannotmatchusername": "Το συνθηματικό δεν μπορεί να είναι ίδιο με το όνομα χρήστη",
+       "passwordpolicies-policy-passwordcannotmatchblacklist": "Το συνθηματικό δεν μπορεί να είναι ακριβώς ίδιο με κάποιο από τα συνθηματικά που βρίσκονται σε μαύρη λίστα",
+       "passwordpolicies-policy-maximalpasswordlength": "Το συνθηματικό πρέπει να έχει μήκος λιγότερο από $1 {{PLURAL:$1|χαρακτήρα|χαρακτήρες}}",
+       "passwordpolicies-policy-passwordcannotbepopular": "Το συνθηματικό δεν μπορεί να είναι {{PLURAL:$1|το δημοφιλέστερο συνθηματικό|στη λίστα με τα $1 δημοφιλέστερα συνθηματικά}}",
+       "passwordpolicies-policy-passwordnotinlargeblacklist": "Το συνθηματικό δεν μπορεί να είναι στην λίστα των 100.000 συνηθέστερα χρησιμοποιούμενων συνθηματικών.",
+       "passwordpolicies-policyflag-forcechange": "πρέπει να αλλαχθεί κατά τη σύνδεση",
+       "unprotected-js": "Για λόγους ασφαλείας δεν μπορεί να φορτωθεί JavaScript από μη προστατευμένες σελίδες. Παρακαλούμε δημιουργήστε javascript μόνο στον ονοματοχώρο MediaWiki: ή ως υποσελίδα χρήστη"
 }
index 28e0b05..71f5633 100644 (file)
        "virus-scanfailed": "scan failed (code $1)",
        "virus-unknownscanner": "unknown antivirus:",
        "logouttext": "<strong>You are now logged out.</strong>\n\nNote that some pages may continue to be displayed as if you were still logged in, until you clear your browser cache.",
+       "logging-out-notify": "You are being logged out, please wait.",
+       "logout-failed": "Cannot log out now: $1",
        "cannotlogoutnow-title": "Cannot log out now",
        "cannotlogoutnow-text": "Logging out is not possible when using $1.",
        "welcomeuser": "Welcome, $1!",
        "page_first": "first",
        "page_last": "last",
        "histlegend": "Diff selection: Mark the radio boxes of the revisions to compare and hit enter or the button at the bottom.<br />\nLegend: <strong>({{int:cur}})</strong> = difference with latest revision, <strong>({{int:last}})</strong> = difference with preceding revision, <strong>{{int:minoreditletter}}</strong> = minor edit.",
-       "history-fieldset-title": "Search for revisions",
+       "history-fieldset-title": "Filter revisions",
        "history-show-deleted": "Revision deleted only",
        "history_copyright": "-",
        "histfirst": "oldest",
        "histlast": "newest",
        "historysize": "({{PLURAL:$1|1 byte|$1 bytes}})",
-       "historyempty": "(empty)",
+       "historyempty": "empty",
        "history-feed-title": "Revision history",
        "history-feed-description": "Revision history for this page on the wiki",
        "history-feed-item-nocomment": "$1 at $2",
        "right-reupload-own": "Overwrite existing files uploaded by oneself",
        "right-reupload-shared": "Override files on the shared media repository locally",
        "right-upload_by_url": "Upload files from a URL",
-       "right-purge": "Purge the site cache for a page without confirmation",
+       "right-purge": "Purge the site cache for a page",
        "right-autoconfirmed": "Not be affected by IP-based rate limits",
        "right-bot": "Be treated as an automated process",
        "right-nominornewtalk": "Not have minor edits to discussion pages trigger the new messages prompt",
        "action-changetags": "add and remove arbitrary tags on individual revisions and log entries",
        "action-deletechangetags": "delete tags from the database",
        "action-purge": "purge this page",
+       "action-apihighlimits": "use higher limits in API queries",
+       "action-autoconfirmed": "not be affected by IP-based rate limits",
+       "action-bigdelete": "delete pages with large histories",
+       "action-blockemail": "block a user from sending email",
+       "action-bot": "be treated as an automated process",
+       "action-editprotected": "edit pages protected as \"{{int:protect-level-sysop}}\"",
+       "action-editsemiprotected": "edit pages protected as \"{{int:protect-level-autoconfirmed}}\"",
+       "action-editinterface": "edit the user interface",
+       "action-editusercss": "edit other users' CSS files",
+       "action-edituserjson": "edit other users' JSON files",
+       "action-edituserjs": "edit other users' JavaScript files",
+       "action-editsitecss": "edit sitewide CSS",
+       "action-editsitejson": "edit sitewide JSON",
+       "action-editsitejs": "edit sitewide JavaScript",
+       "action-editmyusercss": "edit your own user CSS files",
+       "action-editmyuserjson": "edit your own user JSON files",
+       "action-editmyuserjs": "edit your own user JavaScript files",
+       "action-viewsuppressed": "view revisions hidden from any user",
+       "action-hideuser": "block a username, hiding it from the public",
+       "action-ipblock-exempt": "bypass IP blocks, auto-blocks and range blocks",
+       "action-unblockself": "unblock oneself",
+       "action-noratelimit": "not be affected by rate limits",
+       "action-reupload-own": "overwrite existing files uploaded by oneself",
+       "action-nominornewtalk": "not have minor edits to discussion pages trigger the new messages prompt",
+       "action-markbotedits": "mark rolled-back edits as bot edits",
+       "action-patrolmarks": "view recent changes patrol marks",
+       "action-override-export-depth": "export pages including linked pages up to a depth of 5",
+       "action-suppressredirect": "not create redirects from source pages when moving pages",
        "nchanges": "$1 {{PLURAL:$1|change|changes}}",
        "ntimes": "$1×",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|since last visit}}",
        "rcfilters-savedqueries-already-saved": "These filters are already saved. Change your settings to create a new Saved Filter.",
        "rcfilters-restore-default-filters": "Restore default filters",
        "rcfilters-clear-all-filters": "Clear all filters",
-       "rcfilters-show-new-changes": "View newest changes",
+       "rcfilters-show-new-changes": "View new changes since $1",
        "rcfilters-search-placeholder": "Filter changes (use menu or search for filter name)",
        "rcfilters-invalid-filter": "Invalid filter",
        "rcfilters-empty-filter": "No active filters. All contributions are shown.",
        "rcfilters-filter-editsbyself-description": "Your own contributions.",
        "rcfilters-filter-editsbyother-label": "Changes by others",
        "rcfilters-filter-editsbyother-description": "All changes except your own.",
-       "rcfilters-filtergroup-userExpLevel": "User registration and experience",
+       "rcfilters-filtergroup-user-experience-level": "User registration and experience",
        "rcfilters-filter-user-experience-level-registered-label": "Registered",
        "rcfilters-filter-user-experience-level-registered-description": "Logged-in editors.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Unregistered",
        "rcfilters-hideminor-conflicts-typeofchange-global": "The \"Minor edits\" filter conflicts with one or more Type of change filters, because certain types of change cannot be designated as \"minor\". The conflicting filters are marked in the Active filters area, above.",
        "rcfilters-hideminor-conflicts-typeofchange": "Certain types of change cannot be designated as \"minor\", so this filter conflicts with the following Type of Change filters: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "This Type of change filter conflicts with the \"Minor edits\" filter. Certain types of change cannot be designated as \"minor\".",
-       "rcfilters-filtergroup-lastRevision": "Latest revisions",
+       "rcfilters-filtergroup-lastrevision": "Latest revisions",
        "rcfilters-filter-lastrevision-label": "Latest revision",
        "rcfilters-filter-lastrevision-description": "Only the most recent change to a page.",
        "rcfilters-filter-previousrevision-label": "Not the latest revision",
        "newpageletter": "N",
        "boteditletter": "b",
        "unpatrolledletter": "!",
-       "number_of_watching_users_RCview": "[$1]",
-       "number_of_watching_users_pageview": "[$1 watching {{PLURAL:$1|user|users}}]",
+       "number-of-watching-users-for-recent-changes": "[$1]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} after change",
        "newsectionsummary": "/* $1 */ new section",
        "img-auth-nopathinfo": "Missing path information.\nYour server must be set up to pass the REQUEST_URI and/or PATH_INFO variables.\nIf it is, try enabling $wgUsePathInfo.\nSee https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Requested path is not in the configured upload directory.",
        "img-auth-badtitle": "Unable to construct a valid title from \"$1\".",
-       "img-auth-nologinnWL": "You are not logged in and \"$1\" is not in the whitelist.",
        "img-auth-nofile": "File \"$1\" does not exist.",
        "img-auth-isdir": "You are trying to access a directory \"$1\".\nOnly file access is allowed.",
        "img-auth-streaming": "Streaming \"$1\".",
        "delete-confirm": "Delete \"$1\"",
        "delete-legend": "Delete",
        "historywarning": "<strong>Warning:</strong> The page you are about to delete has a history with $1 {{PLURAL:$1|revision|revisions}}:",
-       "historyaction-submit": "Show",
+       "historyaction-submit": "Show revisions",
        "confirmdeletetext": "You are about to delete a page along with all of its history.\nPlease confirm that you intend to do this, that you understand the consequences, and that you are doing this in accordance with [[{{MediaWiki:Policy-url}}|the policy]].",
        "actioncomplete": "Action complete",
        "actionfailed": "Action failed",
        "deleting-backlinks-warning": "<strong>Warning:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Other pages]] link to or transclude the page you are about to delete.",
        "deleting-subpages-warning": "<strong>Warning:</strong> The page you are about to delete has [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|a subpage|$1 subpages|51=over 50 subpages}}]].",
        "rollback": "Roll back edits",
+       "rollback-confirmation-confirm": "Please confirm:",
+       "rollback-confirmation-yes": "Rollback",
+       "rollback-confirmation-no": "Cancel",
        "rollbacklink": "rollback",
        "rollbacklinkcount": "rollback $1 {{PLURAL:$1|edit|edits}}",
        "rollbacklinkcount-morethan": "rollback more than $1 {{PLURAL:$1|edit|edits}}",
        "revertpage": "Reverted edits by [[Special:Contributions/$2|$2]] ([[User talk:$2|talk]]) to last revision by [[User:$1|$1]]",
        "revertpage-nouser": "Reverted edits by a hidden user to last revision by {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Reverted edits by {{GENDER:$3|$1}};\nchanged back to last revision by {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Reverted edits by $1;\nchanged back to last revision by $2. [$3 Show changes]",
        "sessionfailure-title": "Session failure",
        "sessionfailure": "There seems to be a problem with your login session;\nthis action has been canceled as a precaution against session hijacking.\nPlease resubmit the form.",
        "changecontentmodel" : "Change content model of a page",
        "mycontris": "Contributions",
        "anoncontribs": "Contributions",
        "contribsub2": "For {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "For {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "User account \"$1\" is not registered.",
        "negative-namespace-not-supported": "Namespaces with negative values are not supported.",
        "nocontribs": "No changes were found matching these criteria.",
        "blocklist-userblocks": "Hide account blocks",
        "blocklist-tempblocks": "Hide temporary blocks",
        "blocklist-addressblocks": "Hide single IP blocks",
+       "blocklist-type": "Type:",
+       "blocklist-type-opt-all": "All",
+       "blocklist-type-opt-sitewide": "Sitewide",
+       "blocklist-type-opt-partial": "Partial",
        "blocklist-rangeblocks": "Hide range blocks",
        "blocklist-timestamp": "Timestamp",
        "blocklist-target": "Target",
        "blocklist-editing-page": "pages",
        "blocklist-editing-ns": "namespaces",
        "ipblocklist-empty": "The block list is empty.",
-       "ipblocklist-no-results": "The requested IP address or username is not blocked.",
+       "ipblocklist-no-results": "No matching blocks found for the requested IP address or username.",
        "blocklink": "block",
        "unblocklink": "unblock",
        "change-blocklink": "change block",
+       "empty-username": "(no username available)",
        "contribslink": "contribs",
        "emaillink": "send email",
        "autoblocker": "Autoblocked because your IP address has been recently used by \"[[User:$1|$1]]\".\nThe reason given for $1's block is \"$2\"",
        "allmessagesdefault": "Default message text",
        "allmessagescurrent": "Current message text",
        "allmessagestext": "This is a list of system messages available in the MediaWiki namespace.\nPlease visit [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] and [https://translatewiki.net translatewiki.net] if you wish to contribute to the generic MediaWiki localisation.",
-       "allmessagesnotsupportedDB": "This page cannot be used because <strong>$wgUseDatabaseMessages</strong> has been disabled.",
+       "allmessages-not-supported-database": "This page cannot be used because <strong>$wgUseDatabaseMessages</strong> has been disabled.",
        "allmessages-filter-legend": "Filter",
        "allmessages-filter": "Filter by customization state:",
        "allmessages-filter-unmodified": "Unmodified",
        "confirm-unwatch-top": "Remove this page from your watchlist?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Revert edits to this page?",
+       "confirm-rollback-bottom": "This action will instantly rollback the selected changes to this page.",
        "confirm-mcrrestore-title": "Restore a revision",
        "confirm-mcrundo-title": "Undo a change",
        "mcrundofailed": "Undo failed",
        "log-action-filter-newusers-create": "Creation by anonymous user",
        "log-action-filter-newusers-create2": "Creation by registered user",
        "log-action-filter-newusers-autocreate": "Automatic creation",
-       "log-action-filter-newusers-byemail": "Creation with password sent by e-mail",
+       "log-action-filter-newusers-byemail": "Creation with password sent by email",
        "log-action-filter-patrol-patrol": "Manual patrol",
        "log-action-filter-patrol-autopatrol": "Automatic patrol",
        "log-action-filter-protect-protect": "Protection",
        "passwordpolicies-policyflag-forcechange": "must change on login",
        "passwordpolicies-policyflag-suggestchangeonlogin": "suggest change on login",
        "easydeflate-invaliddeflate": "Content provided is not properly deflated",
-       "unprotected-js": "For security reasons JavaScript cannot be loaded from unprotected pages. Please only create javascript in the MediaWiki: namespace or as a User subpage"
+       "unprotected-js": "For security reasons JavaScript cannot be loaded from unprotected pages. Please only create javascript in the MediaWiki: namespace or as a User subpage",
+       "userlogout-continue": "If you wish to log out please [$1 continue to the log out page].",
+       "userlogout-sessionerror": "Log out failed due to session error. Please [$1 try again]."
 }
index 6c060c5..d350c34 100644 (file)
@@ -55,7 +55,9 @@
                        "Joao Xavier",
                        "Surfo",
                        "YvesNevelsteen",
-                       "Vlad5250"
+                       "Vlad5250",
+                       "Mirin",
+                       "Etrapani"
                ]
        },
        "tog-underline": "Substrekado de ligiloj:",
@@ -74,7 +76,7 @@
        "tog-watchdeletion": "Aldoni paĝojn kaj dosierojn, kiujn mi forigas, al mia atentaro",
        "tog-watchuploads": "Aldoni novajn dosierojn, kiujn mi alŝutos, al mia atentaro",
        "tog-watchrollback": "Aldoni paĝojn, kie mi amasmalfaris, al mia atentaro.",
-       "tog-minordefault": "Marki defaŭlte ĉiujn redaktojn kiel etajn",
+       "tog-minordefault": "Marki implicite ĉiujn redaktojn kiel etajn",
        "tog-previewontop": "Montri antaŭrigardon antaŭ redaktilo",
        "tog-previewonfirst": "Montri antaŭrigardon je unua redakto",
        "tog-enotifwatchlistpages": "Sendi al mi retmesaĝon kiam paĝo aŭ dosiero en mia atentaro estas ŝanĝita",
        "badretype": "La pasvortoj kiujn vi entajpis, ne kongruas.",
        "usernameinprogress": "Kontokreado por ĉi tiu uzantnomo jam estas prilaborata. Bonvolu atendi.",
        "userexists": "La enigita uzantnomo jam estas uzata.\nBonvolu elekti alian nomon.",
+       "createacct-normalization": "Via uzantnomo ŝanĝiĝos al \"$2\" pro teknikaj kialoj.",
        "loginerror": "Ensaluta eraro",
        "createacct-error": "Eraro pri kreado de konto",
        "createaccounterror": "Ne eblis krei konton: $1",
        "postedit-confirmation-saved": "Via redakto estas konservita.",
        "postedit-confirmation-published": "Via redakto estas publikigita.",
        "edit-already-exists": "Ne eblis krei novan paĝon.\nĜi jam ekzistas.",
-       "defaultmessagetext": "Defaŭlta mesaĝa teksto",
+       "defaultmessagetext": "Implicita mesaĝa teksto",
        "content-failed-to-parse": "Oni malsukcesis analizi $2-entenon laŭ la $1-modelo: $3",
        "invalid-content-data": "Enhavo estas malvalida",
-       "content-not-allowed-here": "Enhavo de $1 ne estas permesita en paĝo [[:$2]]",
+       "content-not-allowed-here": "Enhavo de $1 ne estas permesita en paĝo [[:$2]] en kanalo \"$3\"",
        "editwarning-warning": "Forlaso de ĉi tiu paĝo kaŭzos al vi perdi iun ajn ŝanĝojn kiujn vi faris.\nSe vi estas ensalutinta, vi povas malŝalti ĉi tiun averton en la sekcio \"{{int:prefs-editing}}\" de viaj preferoj.",
        "editpage-invalidcontentmodel-title": "Enhava modelo ne subtenata",
        "editpage-invalidcontentmodel-text": "La enhava modelo \"$1\" ne estas subtenata.",
        "page_first": "unua",
        "page_last": "lasta",
        "histlegend": "Klarigo: (nuna) = vidu malsamojn kompare kun la nuna versio, (antaŭa) = malsamojn kompare kun la antaŭa versio, <strong>E</strong> = malgranda redakteto",
-       "history-fieldset-title": "Serĉi versiojn",
+       "history-fieldset-title": "Filtri versiojn",
        "history-show-deleted": "Nur forigitaj revizioj",
        "histfirst": "plej malnova",
        "histlast": "plej nova",
        "historysize": "({{PLURAL:$1|1 bajto|$1 bajtoj}})",
-       "historyempty": "(malplena)",
+       "historyempty": "malplena",
        "history-feed-title": "Historio de redaktoj",
        "history-feed-description": "Revizia historio por ĉi tiu paĝo en la vikio",
        "history-feed-item-nocomment": "$1 ĉe $2",
        "prefs-email": "Retpoŝtaj opcioj",
        "prefs-rendering": "Aspekto",
        "saveprefs": "Konservi preferojn",
-       "restoreprefs": "Restarigi ĉiujn defaŭltajn preferojn",
+       "restoreprefs": "Restarigi ĉiujn implicitajn preferojn",
        "prefs-editing": "Redaktado",
        "searchresultshead": "Serĉi",
        "stub-threshold": "Ligilformatigo de ĝermoj ($1):",
        "savedrights": "La uzanto-grupoj de {{GENDER:$1|$1}} estis konservitaj.",
        "timezonelegend": "Horzono:",
        "localtime": "Loka tempo:",
-       "timezoneuseserverdefault": "Uzi defaŭlton de servilo ($1)",
+       "timezoneuseserverdefault": "Uzi implicitaĵon de servilo ($1)",
        "timezoneuseoffset": "Alia (Enigu diferencon)",
        "servertime": "Servila tempo:",
        "guesstimezone": "Plenigita el la foliumilo",
        "timezoneregion-indian": "Hinda Oceano",
        "timezoneregion-pacific": "Pacifiko",
        "allowemail": "Ebligi akceptadon de retmesaĝoj de aliaj uzantoj",
+       "email-allow-new-users-label": "Permesi retpoŝtojn de ek-novaj uzantoj",
        "email-blacklist-label": "Malpermesu al jenaj uzantoj mesaĝi al mi:",
        "prefs-searchoptions": "Serĉi",
        "prefs-namespaces": "Nomspacoj",
        "prefs-custom-json": "Propra JSON",
        "prefs-custom-js": "Propra JS",
        "prefs-common-config": "Komuna CSS/JSON/JavaScript por ĉiuj etosoj:",
-       "prefs-reset-intro": "Vi povas uzi ĉi tiun paĝon por restarigi viajn agordojn al la originalaj defaŭltoj.\nĈi tiel ne estus malfarebla.",
+       "prefs-reset-intro": "Vi povas uzi ĉi tiun paĝon por restarigi viajn agordojn al la originalaj implicitaĵoj.\nĈi tiel ne estus malfarebla.",
        "prefs-emailconfirm-label": "Retpoŝta konfirmado:",
        "youremail": "Retadreso:",
        "username": "{{GENDER:$1|Uzantnomo}}:",
        "action-changetags": "aldoni kaj forigi arbitrajn etikedojn ĉe unuopaj revizioj kaj protokoleroj",
        "action-deletechangetags": "Forigi etikedojn de la datenbazo.",
        "action-purge": "malplenigi servilan kaŝmemoron",
+       "action-bigdelete": "forigi paĝojn kun grandaj historioj",
+       "action-blockemail": "Malpermesi al uzanto sendi retpoŝton.",
+       "action-editinterface": "redakti la fasadon",
+       "action-editusercss": "redakti CSS-dosierojn de aliaj uzantoj",
+       "action-edituserjson": "redakti JSON-dosierojn de aliaj uzantoj",
+       "action-edituserjs": "redakti JavaScript-dosierojn de aliaj uzantoj",
+       "action-editsitecss": "redakti tutretejan CSS-dosierojn",
+       "action-editsitejson": "redakti tutretejan JSON-dosierojn",
+       "action-editsitejs": "redakti tutretejan JavaScript-dosierojn",
+       "action-editmyusercss": "redakti proprajn CSS-dosierojn",
+       "action-editmyuserjson": "redakti proprajn JSON-dosierojn",
+       "action-editmyuserjs": "redakti proprajn JavaScript-dosierojn",
+       "action-unblockself": "malforbari oni mem",
        "nchanges": "$1 {{PLURAL:$1|ŝanĝo|ŝanĝoj}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|ekde lasta vizito}}",
        "enhancedrc-history": "historio",
        "rcfilters-savedqueries-new-name-label": "Nomo",
        "rcfilters-savedqueries-new-name-placeholder": "Priskribas la celon de la filtrilo",
        "rcfilters-savedqueries-apply-label": "Krei filtrilon",
-       "rcfilters-savedqueries-apply-and-setdefault-label": "Krei defaŭltan filtrilon",
+       "rcfilters-savedqueries-apply-and-setdefault-label": "Krei implicitan filtrilon",
        "rcfilters-savedqueries-cancel-label": "Nuligi",
        "rcfilters-savedqueries-add-new-title": "Konservi la nunajn filtrilajn agordojn",
        "rcfilters-restore-default-filters": "Restarigi defaŭltajn filtrilojn",
        "rcfilters-filter-editsbyself-description": "Viaj kontribuoj.",
        "rcfilters-filter-editsbyother-label": "ŝanĝoj faritaj de aliuloj",
        "rcfilters-filter-editsbyother-description": "Ĉiuj ŝanĝoj, escepte de viaj.",
-       "rcfilters-filtergroup-userExpLevel": "Registriĝo kaj spertonivelo de uzanto",
+       "rcfilters-filtergroup-user-experience-level": "Registriĝo kaj spertonivelo de uzanto",
        "rcfilters-filter-user-experience-level-registered-label": "Registritaj",
        "rcfilters-filter-user-experience-level-registered-description": "Ensalutitaj redaktantoj.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Neregistritaj",
        "rcfilters-filter-categorization-description": "Registroj de paĝoj aldonitaj aŭ forigitaj de kategorioj",
        "rcfilters-filter-logactions-label": "Registritaj agoj",
        "rcfilters-filter-logactions-description": "Administraciaj agoj, kontaj kreoj, paĝaj forigoj, alŝutoj…",
-       "rcfilters-filtergroup-lastRevision": "Lastaj revizioj",
+       "rcfilters-filtergroup-lastrevision": "Lastaj revizioj",
        "rcfilters-filter-lastrevision-label": "Lasta revizio",
        "rcfilters-filter-lastrevision-description": "Nur la plej lasta ŝanĝo al paĝo.",
        "rcfilters-filter-previousrevision-label": "Ne la lasta revizio",
        "rcfilters-filter-excluded": "Ekskludita",
        "rcfilters-exclude-button-off": "Ekskludi la elektitajn",
        "rcfilters-exclude-button-on": "Ekskludante la elektitajn",
+       "rcfilters-view-tags": "Redaktoj kun etikedoj",
+       "rcfilters-view-namespaces-tooltip": "Filtri rezultojn laŭ nomspaco",
+       "rcfilters-view-tags-tooltip": "Filtri rezultojn laŭ redaktaj etikedoj",
+       "rcfilters-view-return-to-default-tooltip": "Reen al ĉefa filtra menuo",
+       "rcfilters-view-tags-help-icon-tooltip": "Lerni plu pri Redaktaj Etikedoj",
        "rcfilters-liveupdates-button": "Aŭtomata ĝisdatigo",
        "rcfilters-liveupdates-button-title-on": "Malŝalti aŭtomatajn ĝisdatigojn",
        "rcfilters-liveupdates-button-title-off": "Montri novajn ŝanĝojn dum ili okazas",
        "rcfilters-watchlist-markseen-button": "Marku ĉiujn ŝanĝojn viditaj",
        "rcfilters-watchlist-edit-watchlist-button": "Redakti vian atentaron",
        "rcfilters-watchlist-showupdated": "Ŝanĝoj en paĝoj, kiujn vi ne vizitis post la ŝanĝo, aperas <strong>grase</strong>, kun plenigitaj buletoj.",
+       "rcfilters-preference-label": "Uzi fasadon sen JavaScript",
+       "rcfilters-watchlist-preference-label": "Uzi fasadon ne uzantan JavaScript",
        "rcfilters-target-page-placeholder": "Enigu nomon de paĝo (aŭ kategorio)",
        "rcnotefrom": "Malsupre estas la {{PLURAL:$5|ŝanĝo|ŝanĝoj}} ekde <strong>$3, $4</strong> (montrante ĝis <strong>$1</strong>).",
        "rclistfrom": "Montri novajn ŝanĝojn ekde \"$3 $2\"",
        "minoreditletter": "e",
        "newpageletter": "N",
        "boteditletter": "r",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|priatentanta uzanto|priatentantaj uzantoj}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|bitoko|bitokoj}} post ŝanĝo",
        "newsectionsummary": "/* $1 */ nova sekcio",
        "rc-enhanced-expand": "Montri detalojn (per JavaScript)",
        "upload-form-label-infoform-date": "Dato",
        "upload-form-label-own-work-message-generic-local": "Mi konfirmas ke mi alŝutas tiun dosieron respektante pri la uzadokondiĉoj kaj permesopolitikoj de  {{SITENAME}}.",
        "upload-form-label-not-own-work-message-generic-local": "Se vi ne eblas alŝuti tiun dosieron respektante de politikoj de {{SITENAME}}, bonvolu fermi tiun dialogon kaj provi denove kun alia metodo.",
-       "upload-form-label-not-own-work-local-generic-local": "Vi eble ŝatu egale pravi [[Special:Upload|la defaŭltan paĝon]].",
+       "upload-form-label-not-own-work-local-generic-local": "Vi eble ŝatu egale pravi [[Special:Upload|la implicitan paĝon]].",
        "upload-form-label-own-work-message-generic-foreign": "Mi komprenas ke mi alŝutas tiun dosieron al komunigita deponejo. Mi konfirmas ke mi faras tiun respektante de la uzadtermoj kaj de la permisilopolitikoj tie.",
        "upload-form-label-not-own-work-message-generic-foreign": "Se vi ne eblas alŝuti tiun dosieron respektante de politikoj de komuna deponejo, bonvolu fermi tiun dialogon kaj provi denove kun alia metodo.",
        "upload-form-label-not-own-work-local-generic-foreign": "Vi ankaŭ eble dezirus provi per uzi [[Special:Upload|la alŝutan paĝon sur {{SITENAME}}]], se ĉi tiu dosiero povas esti alŝutita tie respektante de iliaj politikoj.",
        "uploadstash-refresh": "Aktualigi la dosierliston.",
        "uploadstash-thumbnail": "Vidi bildeton",
        "uploadstash-exception": "Ne eblas alŝuti en kaŝkonservejon ($1): \"$2\".",
+       "uploadstash-bad-path": "Vojo ne ekzistas.",
+       "uploadstash-bad-path-invalid": "Vojo ne estas valida.",
+       "uploadstash-bad-path-unknown-type": "Nekonata tipo \"$1\".",
        "uploadstash-bad-path-unrecognized-thumb-name": "Nerekonita miniatura nomo.",
+       "uploadstash-no-extension": "Dosiersufikso estas nula.",
+       "uploadstash-zero-length": "Longo de dosiero estas nul.",
        "invalid-chunk-offset": "Malvalida deŝovo de dosierpeco",
        "img-auth-accessdenied": "Atingo malpermisita",
        "img-auth-nopathinfo": "Mankas informo pri vojo.\nVia servilo estu agordita por sendi la variablojn REQUEST_URI kaj/aŭ PATH_INFO.\nSe ĝi jam estas, provu aktivigon de $wgUsePathInfo.\nVidu https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Petita vojo ne estas en la konfigurita alŝuta dosierujo.",
        "img-auth-badtitle": "Ne povas konstrui validan titolon de \"$1\".",
-       "img-auth-nologinnWL": "Vi ne estas ensalutita kaj \"$1\" ne estas en la blankalisto.",
        "img-auth-nofile": "Dosiero \"$1\" ne ekzistas.",
        "img-auth-isdir": "Vi provas atingi dosierujon \"$1\".\nNur dosiera atingo estas permesita.",
        "img-auth-streaming": "Elsendfluante \"$1\".",
        "http-timed-out": "HTTP-peto eltempiĝis.",
        "http-curl-error": "Eraro venigante URL-on: $1",
        "http-bad-status": "Estis problemo dum la HTTP-peto: $1 $2",
+       "http-internal-error": "Interna eraro de HTTP.",
        "upload-curl-error6": "URL-o ne estis atingebla",
        "upload-curl-error6-text": "La donata URL-o ne estis atingita. Bonvolu rekontroli ke la URL-o estas korekta kaj la retejo funkcias.",
        "upload-curl-error28": "Tempolimo de alŝuto atingita",
        "speciallogtitlelabel": "Celo (titolo aŭ  {{ns:user}}:salutnomo por uzanto):",
        "log": "Protokoloj",
        "logeventslist-submit": "Montri",
+       "logeventslist-patrol-log": "Patrolprotokolo",
+       "logeventslist-tag-log": "Protokolo de etikedoj",
        "all-logs-page": "Ĉiuj publikaj protokoloj",
        "alllogstext": "Suma kompilaĵo de ĉiuj protokoloj de {{SITENAME}}.\nVi povas plistrikti la mendon per selektado de protokola speco, la salutnomo (inkluzivante uskladon) aŭ la efika paĝo (ankaŭ inkluzivas uskladon).",
        "logempty": "Neniaj artikoloj en la protokolo.",
        "post-expand-template-argument-category-desc": "La paĝo post etendo de ŝablona argumento (io en triobla krampo, kiel <code>{{{argumento}}}</code>) estas pli longa ol <code>$wgMaxArticleSize</code> .",
        "expensive-parserfunction-category-desc": "La paĝo uzas tro multajn multekostajn funkciojn (kiel <code>#ifexist</code>). Vidu [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgExpensiveParserFunctionLimit Manual:$wgExpensiveParserFunctionLimit].",
        "broken-file-category-desc": "La paĝo enhavas malvalidan ligilon al dosiero (ligilo por uzi dosieron kvankam la dosiero ne ekzistas).",
-       "hidden-category-category-desc": "La kategorio enhavas <code><nowiki>__HIDDENCAT__</nowiki></code>, kio preventas ĝian defaŭltan montradon en la kesto kun kategoriaj ligiloj.",
+       "hidden-category-category-desc": "La kategorio enhavas <code><nowiki>__HIDDENCAT__</nowiki></code>, kio preventas ĝian implicitan montradon en la kesto kun kategoriaj ligiloj.",
        "trackingcategories-nodesc": "Neniu priskribo estas disponebla.",
        "trackingcategories-disabled": "Kategorio estas malaktivigita",
        "mailnologin": "Neniu alsendota adreso",
        "enotif_lastdiff": "Por rigardi ĉi tiun ŝanĝon, vidu $1",
        "enotif_anon_editor": "anonima uzanto $1",
        "enotif_body": "Kara $WATCHINGUSERNAME,\n\n$PAGEINTRO $NEWPAGE\n\nRedaktinta resumo:\n$PAGESUMMARY $PAGEMINOREDIT\n\nResumo pri la ŝanĝo de la redaktinto: $PAGESUMMARY $PAGEMINOREDIT\n\nKontaktu la redaktinton:\nretpoŝte: $PAGEEDITOR_EMAIL\nvikie: $PAGEEDITOR_WIKI\n\nNe estos aliaj avertoj kaze de sekvaj agoj krom se vi vizitus ĉi tiun paĝon ensalutite. Vi povas ankaŭ malaktivigi la avertsignalon por ĉiuj priatentitaj paĝoj de via atentaro.\n\n            Sincere via, la avertsistemo de {{SITENAME}}\n\n--\nPor ŝanĝi vian retpoŝtan avertadajn preferojn, klaku\n{{canonicalurl:{{#special:Preferences}}}}\n\nPor ŝanĝi vian preferojn de la atentaro, klaku\n{{canonicalurl:{{#special:EditWatchlist}}}}\n\nPor forigi ĉi tiun paĝon de via atentaro, klaku\n$UNWATCHURL\n\nKomentoj kaj plia helpo:\n$HELPPAGE",
+       "enotif_minoredit": "Ĉi tiu estas redakteto",
        "created": "kreita",
        "changed": "ŝanĝita",
        "deletepage": "Forigi paĝon",
        "delete-confirm": "Forigi \"$1\"",
        "delete-legend": "Forigi",
        "historywarning": "<strong>Averto:</strong> La forigota paĝo havas historion kun $1 {{PLURAL:$1|revizio|revizioj}}:",
-       "historyaction-submit": "Montri",
+       "historyaction-submit": "Montri reviziojn",
        "confirmdeletetext": "Vi forigos la artikolon aŭ dosieron kaj forviŝos ĝian tutan historion el la datumaro.<br /> Bonvolu konfirmi, ke vi vere intencas tion, kaj ke vi komprenas la sekvojn, kaj ke vi ja sekvas la [[{{MediaWiki:Policy-url}}|regulojn pri forigado]].",
        "actioncomplete": "Ago farita",
        "actionfailed": "Ago malsukcesis",
        "dellogpage": "Protokolo pri forigoj",
        "dellogpagetext": "Jen listo de la plej lastaj forigoj.",
        "deletionlog": "protokolo pri forigoj",
+       "log-name-create": "Protokolo de paĝo-kreado",
        "logentry-create-create": "$1 {{GENDER:$2|kreis}} paĝon $3",
        "reverted": "Malfaris al antaŭa revisio",
        "deletecomment": "Kialo:",
        "deleteprotected": "Vi ne povas forigi ĉi tiun paĝon ĉar ĝi estis protektita.",
        "deleting-backlinks-warning": "<strong>Atentigo:</strong>\n[[Special:WhatLinksHere/{{FULLPAGENAME}}|Aliaj paĝoj]] ligas al aŭ transkludas tiun ĉi forigotan paĝon.",
        "rollback": "Restarigi antaŭan redakton",
+       "rollback-confirmation-confirm": "Bonvolu konfirmi:",
+       "rollback-confirmation-yes": "Amasmalfari",
+       "rollback-confirmation-no": "Nuligi",
        "rollbacklink": "malfari",
        "rollbacklinkcount": "nuligi $1 {{PLURAL:$1|redakton|redaktojn}}",
        "rollbacklinkcount-morethan": "nuligi pli ol $1 {{PLURAL:$1|redakton|redaktojn}}",
        "revertpage": "Malfaris redaktojn de [[Special:Contributions/$2|$2]] ([[User talk:$2|diskuto]]) al la lasta versio de [[User:$1|$1]]",
        "revertpage-nouser": "Restarigis redaktojn de (salutnomo forigita) al lasta revizio de {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Restaris redaktojn de {{GENDER:$3|$1}}; ŝanĝis al lasta versio de {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Malfaritis redaktojn far $1;\nŝanĝis al la lasta reviziaĵo far $2. [$3 Prezenti ŝanĝojn]",
        "sessionfailure-title": "Seanco malsukcesis",
        "sessionfailure": "Ŝajnas, ke estas problemo kun via ensalutado;\nĈi ago estis nuligita por malhelpi fiensalutadon.\nBonvolu resendi la formularoj",
        "changecontentmodel": "Ŝanĝi la enhavomodelon de paĝo",
        "changecontentmodel-emptymodels-text": "La enhavo en [[:$1]] ne transtipeblas al iu ajn tipo.",
        "log-name-contentmodel": "Ŝanĝprotokolo de enhavomodelo",
        "log-description-contentmodel": "Ĉi tiu paĝo montras ŝanĝojn de la enhavomodelo de paĝoj, kaj paĝojn kreitajn kun enhavomodelo aparta de la norma.",
-       "logentry-contentmodel-new": "$1 {{GENDER:$2|kreis}} la paĝo $3 per uzado de ne-defaŭlta enhavomodelo \"$5\"",
+       "logentry-contentmodel-new": "$1 {{GENDER:$2|kreis}} la paĝo $3 per uzado de malimplicita enhavomodelo \"$5\"",
        "logentry-contentmodel-change": "$1 {{GENDER:$2|ŝanĝis}} la enhavomodelon de la paĝo $3 el \"$4\" al \"$5\"",
        "logentry-contentmodel-change-revertlink": "restarigi",
        "logentry-contentmodel-change-revert": "restarigi",
        "ipbreason": "Kialo:",
        "ipbreason-dropdown": "*Oftaj kialoj de forbaro\n** Enmetas malveraĵojn\n** Forviŝas entenon el paĝoj\n** Entrudas ligilojn al eksteraj paĝaroj\n** Enmetas sensencaĵojn\n** Terurigema sinteno\n** Misuzo de pluraj salutnomoj\n** Neakceptebla uzanto-nomo",
        "ipb-hardblock": "Malpermesi ensalutitajn uzantoj de redaktante ĉi tiun IP-adreson",
-       "ipbcreateaccount": "Preventi kreadon de konto",
-       "ipbemailban": "Malebligi al uzanto sendi retpoŝton.",
+       "ipbcreateaccount": "Kreado de konto",
+       "ipbemailban": "Sendado de retpoŝta mesaĝo",
        "ipbenableautoblock": "Aŭtomate forbaru la lastan IP-adreson uzitan de la uzanto, kaj ĉiajn subsekvantajn adresojn el kiuj tiu provos redakti",
        "ipbsubmit": "Bloki la uzanton",
        "ipbother": "Alia daŭro:",
        "ipb-sitewide": "Tutreteja",
        "ipb-partial": "Parta",
        "ipb-pages-label": "Paĝoj",
+       "ipb-namespaces-label": "Nomspacoj",
        "badipaddress": "Neniu uzanto, aŭ la IP-adreso estas misformita.",
        "blockipsuccesssub": "Forbaro sukcesis.",
        "blockipsuccesstext": "[[Special:Contributions/$1|$1]] estas forbarita. <br />\nVidu la [[Special:BlockList|liston de forbaroj]] por kontroli.",
        "ipb-blocklist-contribs": "Kontribuoj de {{GENDER:$1|$1}}",
        "ipb-blocklist-duration-left": "$1 restas",
        "block-expiry": "Blokdaŭro",
+       "block-prevent-edit": "Redaktado",
+       "block-reason": "Kialo:",
+       "block-target": "Uzantnomo aŭ IP-adreso:",
        "unblockip": "Malforbari IP-adreson/nomon",
        "unblockiptext": "Per la jena formulo vi povas repovigi al iu\nforbarita IP-adreso/nomo la povon enskribi en la vikio.",
        "ipusubmit": "Forigi ĉi tiun forbaron",
        "blocklist-userblocks": "Kaŝi konto-forbarojn",
        "blocklist-tempblocks": "Kaŝi provizorajn forbarojn",
        "blocklist-addressblocks": "Kaŝi unuopajn IP-adresajn forbarojn",
+       "blocklist-type": "Tipo:",
+       "blocklist-type-opt-all": "Ĉio",
+       "blocklist-type-opt-sitewide": "Tutreteje",
+       "blocklist-type-opt-partial": "Parte",
        "blocklist-rangeblocks": "Kaŝi blokojn de intervalo",
        "blocklist-timestamp": "Tempindiko",
        "blocklist-target": "Celo",
        "blocklist-nousertalk": "ne povas redakti sian propran diskuto-paĝon",
        "blocklist-editing": "redaktado",
        "blocklist-editing-sitewide": "redaktado (tutreteja)",
+       "blocklist-editing-page": "paĝoj",
+       "blocklist-editing-ns": "nomspacoj",
        "ipblocklist-empty": "La forbarlibro estas malplena.",
        "ipblocklist-no-results": "Ĉi tiu IP-adreso aŭ salutnomo ne estas forbarita.",
        "blocklink": "forbari",
        "unblocklink": "restarigi",
        "change-blocklink": "ŝanĝi forbaron",
+       "empty-username": "(neniu uzantnomo disponeblas)",
        "contribslink": "kontribuoj",
        "emaillink": "sendi retpoŝton",
        "autoblocker": "Aŭtomate forbarita, ĉar via IP-adreso estis lastatempe uzita de \"[[User:$1|$1]]\".\nLa kialo donita por la forbaro de $1 estis: \"$2\"",
        "export-manual": "Aldoni paĝojn per uzanta efiko",
        "allmessages": "Ĉiuj mesaĝoj",
        "allmessagesname": "Nomo",
-       "allmessagesdefault": "Defaŭlta teksto",
+       "allmessagesdefault": "Implicita teksto",
        "allmessagescurrent": "Nuna teksto",
        "allmessagestext": "Ĉi tio estas listo de ĉiuj mesaĝoj haveblaj en la MediaWiki-nomspaco.\nBonvolu aliri [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki-Asimilado] kaj [https://translatewiki.net translatewiki.net]\nse vi volus kontribui al la komuna MediaWiki-asimilado.",
-       "allmessagesnotsupportedDB": "{{ns:special}}:Allmessages ne subtenata ĉar la variablo wgUseDatabaseMessages estas malkonektita.",
+       "allmessages-not-supported-database": "{{ns:special}}:Allmessages ne subtenata ĉar la variablo wgUseDatabaseMessages estas malkonektita.",
        "allmessages-filter-legend": "Filtri",
        "allmessages-filter": "Filtri laŭ ŝanĝada stato",
        "allmessages-filter-unmodified": "Neŝanĝitaj",
        "import-interwiki-history": "Kopiu ĉiujn historiajn versiojn por ĉi tiu pago.",
        "import-interwiki-templates": "Inkluzivi ĉiujn ŝablonojn",
        "import-interwiki-submit": "Enporti",
-       "import-mapping-default": "Importi al defaŭltaj lokoj",
+       "import-mapping-default": "Importi al implicitaj lokoj",
        "import-mapping-namespace": "Importi en nomspacon:",
        "import-mapping-subpage": "Importi kiel subpaĝojn de la jena paĝo:",
        "import-upload-filename": "Dosiernomo:",
        "pageinfo-display-title": "Montrita titolo",
        "pageinfo-default-sort": "Pravaloro de ordiga ŝlosilo",
        "pageinfo-length": "Paĝgrandeco (en bajtoj)",
+       "pageinfo-namespace": "Nomspaco",
        "pageinfo-article-id": "Paĝa identigo",
        "pageinfo-language": "Lingvo de paĝa enhavo",
        "pageinfo-language-change": "ŝanĝi",
        "confirm-unwatch-top": "Ĉu forigi tiun ĉi paĝon el via atentaro?",
        "confirm-rollback-button": "Bone",
        "confirm-rollback-top": "Malfaru redaktojn al ĉi tiu paĝo?",
+       "confirm-mcrundo-title": "Malfari ŝanĝon",
+       "mcrundofailed": "Malfaro malsukcesis",
        "quotation-marks": "„$1“",
        "imgmultipageprev": "← antaŭa paĝo",
        "imgmultipagenext": "sekva paĝo →",
        "imgmultigo": "Ek!",
        "imgmultigoto": "Iri al paĝo $1",
-       "img-lang-default": "(defaŭlta lingvo)",
+       "img-lang-default": "(implicita lingvo)",
        "img-lang-info": "Bildigi tiun ĉi bildon en $1. $2",
        "img-lang-go": "Ek",
        "ascending_abbrev": "sprn",
        "hebrew-calendar-m12-gen": "elulo",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|diskuto]])",
        "timezone-local": "Loka",
-       "duplicate-defaultsort": "'''Averto:''' Defaŭlta ordiga ŝlosilo \"$2\" anstataŭigas pli fruan defaŭltan ordigan ŝlosilon \"$1\".",
+       "duplicate-defaultsort": "'''Averto:''' Implicita ordiga ŝlosilo \"$2\" anstataŭigas pli fruan defaŭltan ordigan ŝlosilon \"$1\".",
        "duplicate-displaytitle": "<strong>Atentigo:</strong> La montrata titolo \"$2\" transpasas la antaŭan titolon \"$1\".",
        "restricted-displaytitle": "<strong>Averto:</strong> Vidiga titolo \"$1\" estis ignorita pro tio ke ĝi ne estas ekvivalenta al la efektiva titolo de la paĝo.",
        "invalid-indicator-name": "<strong>Eraro:</strong> Atributo de la paĝstata indikilo <code>name</code> maldevas esti malplena.",
        "redirect-file": "Dosiernomo",
        "redirect-logid": "Protokola identigilo",
        "redirect-not-exists": "Valoro ne trovita",
+       "redirect-not-numeric": "Valoro ne estas nombra",
        "fileduplicatesearch": "Serĉu duplikatajn dosierojn",
        "fileduplicatesearch-summary": "Serĉi duplikatajn dosierojn bazite de haketvaloro.",
        "fileduplicatesearch-filename": "Dosiernomo:",
        "tag-list-wrapper": "[[Special:Tags|{{PLURAL:$1|Etikedo|Etikedoj}}]]: $2",
        "tag-mw-contentmodelchange": "ŝanĝo de enhavomodelo",
        "tag-mw-contentmodelchange-description": "Redaktoj kiuj [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:ChangeContentModel ŝanĝas la enhavmodelon] de paĝo",
+       "tag-mw-replace": "Anstataŭiginta",
+       "tag-mw-rollback": "Amasmalfari",
+       "tag-mw-undo": "Malfari",
        "tags-title": "Etikedoj",
        "tags-intro": "Ĉi tiu paĝo montras la etikedojn kun kiuj la programaro markus redakton, kaj iliaj signifoj.",
        "tags-tag": "Etikeda nomo",
        "compare-title-not-exists": "La titolo kiun vi specifis ne ekzistas.",
        "compare-revision-not-exists": "La revizio kiun vi specifis ne ekzistas.",
        "diff-form": "Malsamoj",
+       "diff-form-submit": "Montri diferencojn",
        "permanentlink": "Konstanta ligilo",
+       "permanentlink-revid": "Identigilo de revizio",
+       "permanentlink-submit": "Iri al revizio",
        "dberr-problems": "Bedaŭrinde, ĉi tiu retejo suferas pro teknikaj problemoj.",
        "dberr-again": "Bonvolu atendi kelkajn minutojn kaj reŝargi.",
        "dberr-info": "(Ne eblas konekti la datumbazon: $1)",
        "logentry-tag-update-revision": "$1 {{GENDER:$2|ĝisdatigis}} etikedojn de la revizio $4 de la paĝo $3 ({{PLURAL:$7|aldonita|aldonitaj}} $6; {{PLURAL:$9|forigita|forigitaj}} $8)",
        "logentry-tag-update-logentry": "$1 {{GENDER:$2|ĝisdatigis}} etikedojn de la protokolero $5 de la paĝo $3 ({{PLURAL:$7|aldonita|aldonitaj}} $6; {{PLURAL:$9|forigita|forigitaj}} $8)",
        "rightsnone": "(nenia)",
+       "rightslogentry-temporary-group": "$1 (portempa, ĝis $2)",
        "feedback-adding": "Aldonanta respondon al la paĝo...",
        "feedback-back": "Reen",
        "feedback-bugcheck": "Bonega! Nur konfirmu ke ĝi ne jam ekzistas inter la [$1 konataj cimoj].",
        "pagelanguage": "Ŝanĝi paĝan lingvon",
        "pagelang-name": "Paĝo",
        "pagelang-language": "Lingvo",
-       "pagelang-use-default": "Uzi defaŭltan lingvon",
+       "pagelang-use-default": "Uzi implicitan lingvon",
        "pagelang-select-lang": "Elekti la lingvon",
        "pagelang-reason": "Kialo",
        "pagelang-submit": "Ek!",
        "log-name-pagelang": "Protokolo pri lingvajn ŝanĝojn",
        "log-description-pagelang": "Jen protokolo pri ŝanĝoj de paĝaj lingvoj.",
        "logentry-pagelang-pagelang": "$1 {{GENDER:$2|ŝanĝis}} paĝan lingvon pri $3 el $4 al $5.",
-       "default-skin-not-found": "Ups! La defaŭlta etoso por via vikio, difinita en <code dir=\"ltr\">$wgDefaultSkin</code> kiel <code>$1</code> ne estas disponebla.\n\nŜajnas, ke via instalaĵo enhavas {{PLURAL:$4|jenan etoson|jenajn etosojn}}. Vidu [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manlibro:Agordado de etosoj] por informoj kiel {{PLURAL:$4|ĝin ŝalti|ilin ŝalti kaj elekti la defaŭltan}}.\n\n$2\n\n; Se vi ĵus instalis MediaWiki:\n: Vi probable instalis de git aŭ rekte de fontokodo per alia metodo. Tio estas antaŭsupozata. MediaWiki 1.24 kaj pli novaj versioj enhavas neniun etoson en la ĉefa deponejo. Provu instali iujn etosojn de [https://www.mediawiki.org/wiki/Category:All_skins etosa dosierujo en mediawiki.org] per jenaj metodoj:\n:* Elŝutu [https://www.mediawiki.org/wiki/Download pakitan instalilon], kiu enhavas kelkajn etosojn kaj etendaĵojn. Vi povas de ĝi kopii kaj alglui la dosierujon <code>skins/</code>.\n:* Elŝutu unuopajn pakitajn etosojn de [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* [https://www.mediawiki.org/wiki/Download_from_Git#Using_Git_to_download_MediaWiki_skins Uzu Git por elŝuti etosojn].\n: Tio maldevus interkolizii kun via git-deponejo se vi estas evoluiganto de MediaWiki.\n\n; Se vi ĵus promociis MediaWiki:\n: MediaWiki 1.24 kaj pli novaj ne plu aŭtomate ŝaltas instalitajn etosojn (vidu [https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery Manlibro:Aŭtomata malkovrado de etosoj]). Vi povas alglui {{PLURAL:$5|jenan linion|jenajn liniojn}} al <code>LocalSettings.php</code> por ŝalti {{PLURAL:$5|la instalitan etoson|ĉiujn instalitajn etosojn}}:\n\n<pre dir=\"ltr\">$3</pre>\n\n; Se vi ĵus modifis <code>LocalSettings.php</code>:\n: Denove kontrolu nomon de etosoj pro eblaj mistajpoj.",
+       "default-skin-not-found": "Ups! La implicilta etoso por via vikio, difinita en <code dir=\"ltr\">$wgDefaultSkin</code> kiel <code>$1</code> ne estas disponebla.\n\nŜajnas, ke via instalaĵo enhavas {{PLURAL:$4|jenan etoson|jenajn etosojn}}. Vidu [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manlibro:Agordado de etosoj] por informoj kiel {{PLURAL:$4|ĝin ŝalti|ilin ŝalti kaj elekti la implicitaĵon}}.\n\n$2\n\n; Se vi ĵus instalis MediaWiki:\n: Vi probable instalis de git aŭ rekte de fontokodo per alia metodo. Tio estas antaŭsupozata. MediaWiki 1.24 kaj pli novaj versioj enhavas neniun etoson en la ĉefa deponejo. Provu instali iujn etosojn de [https://www.mediawiki.org/wiki/Category:All_skins etosa dosierujo en mediawiki.org] per jenaj metodoj:\n:* Elŝutu [https://www.mediawiki.org/wiki/Download pakitan instalilon], kiu enhavas kelkajn etosojn kaj etendaĵojn. Vi povas de ĝi kopii kaj alglui la dosierujon <code>skins/</code>.\n:* Elŝutu unuopajn pakitajn etosojn de [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* [https://www.mediawiki.org/wiki/Download_from_Git#Using_Git_to_download_MediaWiki_skins Uzu Git por elŝuti etosojn].\n: Tio maldevus interkolizii kun via git-deponejo se vi estas evoluiganto de MediaWiki.\n\n; Se vi ĵus promociis MediaWiki:\n: MediaWiki 1.24 kaj pli novaj ne plu aŭtomate ŝaltas instalitajn etosojn (vidu [https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery Manlibro:Aŭtomata malkovrado de etosoj]). Vi povas alglui {{PLURAL:$5|jenan linion|jenajn liniojn}} al <code>LocalSettings.php</code> por ŝalti {{PLURAL:$5|la instalitan etoson|ĉiujn instalitajn etosojn}}:\n\n<pre dir=\"ltr\">$3</pre>\n\n; Se vi ĵus modifis <code>LocalSettings.php</code>:\n: Denove kontrolu nomon de etosoj pro eblaj mistajpoj.",
        "default-skin-not-found-no-skins": "Ups! La defaŭlta etoso por via vikio, difinita en <code>$wgDefaultSkin</code> kiel <code>$1</code> ne estas disponebla.\n\nVi havas neniun instalitan etson.\n\n; Se vi ĵus instalis aŭ promocii MediaWiki:\n: Vi probable instalis de git aŭ rekte de fontokodo per alia metodo. Tio estas antaŭspozata. MediaWiki 1.24 kaj pli novaj versioj enhavas neniun etoson en la ĉefa deponejo. Provu instali iujn etosojn de [https://www.mediawiki.org/wiki/Category:All_skins etosa dosierujo en mediawiki.org] per jenaj metodoj:\n:* Elŝutu [https://www.mediawiki.org/wiki/Download pakitan instalilon], kiu enhavas kelkajn eosojn kaj etendaĵojn. Vi povas de ĝi kopii kaj alglui la dosierujon <code>skins/</code>.\n:* Elŝutu unuopajn pakitajn etosojn de [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* [https://www.mediawiki.org/wiki/Download_from_Git#Using_Git_to_download_MediaWiki_skins Uzu Git por elŝuti etosojn].\n: Tio maldevus interkolizii kun via git-deponejo se vi estas evoluiganto de MediaWiki. Vidu [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manlibro:Agordado de etosoj] por informoj kiel ŝalti etosojn kaj elekti la defaŭltan.",
        "default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (ŝalta)",
        "default-skin-not-found-row-disabled": "* <code>$1</code> / $2 (<strong>malŝalta</strong>)",
        "special-characters-group-thai": "Taja",
        "special-characters-group-lao": "laŭa",
        "special-characters-group-khmer": "kmera",
+       "special-characters-group-canadianaboriginal": "Kanada Indiĝena",
        "special-characters-title-endash": "mallonga streketo",
        "special-characters-title-emdash": "longa streketo",
        "special-characters-title-minus": "minus-signo",
        "mw-widgets-categoryselector-add-category-placeholder": "Aldoni kategorion",
        "mw-widgets-usersmultiselect-placeholder": "Aldoni pliajn...",
        "mw-widgets-titlesmultiselect-placeholder": "Aldoni pliajn...",
+       "date-range-from": "De dato:",
+       "date-range-to": "Ĝis dato:",
        "sessionmanager-tie": "Kombini diversajn tipojn de ensaluta peto ne estas permisita: $1.",
        "sessionprovider-generic": "$1 seancoj",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "kuketaj seancoj",
        "log-action-filter-suppress-reblock": "Forigi uzanton per reforbari",
        "log-action-filter-upload-upload": "Novalŝuta",
        "log-action-filter-upload-overwrite": "Realŝuta",
+       "log-action-filter-upload-revert": "Restarigi",
        "authmanager-authn-not-in-progress": "Aŭtentigado ne estas progresanta aŭ la seancaj datumoj perdiĝis. Bonvolu provi denove ekde la komenco.",
        "authmanager-authn-no-primary": "La provizita legitimaĵo ne povus esti aŭtentikigita.",
        "authmanager-authn-no-local-user": "La provizitaj legitimaĵoj ne estas asociitaj kun ajna uzanto de ĉi tiu vikio.",
        "edit-error-long": "Eraroj:\n\n$1",
        "revid": "revizio $1",
        "pageid": "Identigilo de paĝo $1",
+       "gotointerwiki": "Elirante retejon {{SITENAME}}",
        "pagedata-title": "Paĝaj datumoj",
+       "pagedata-bad-title": "Nevalida titolo: \"$1\".",
+       "passwordpolicies": "Reguloj pri pasvortoj",
        "passwordpolicies-group": "Grupo",
        "passwordpolicies-policies": "Politiko",
        "passwordpolicies-policy-minimalpasswordlength": "Pasvortoj devas esti longaj almenaŭ  $1 {{PLURAL:$1|1 signon|$1 signojn}}.",
index 4fbc4ec..aacefc9 100644 (file)
                        "Carlosmg.dg",
                        "Mynor Archila",
                        "Jorge Ubilla",
-                       "Marcelo9987"
+                       "Marcelo9987",
+                       "Cuatro Remos",
+                       "Ryo567"
                ]
        },
        "tog-underline": "Enlaces a subrayar:",
        "virus-scanfailed": "ha fallado el análisis (código $1)",
        "virus-unknownscanner": "antivirus desconocido:",
        "logouttext": "<strong>Tu sesión ha finalizado.</strong>\n\nPuede que algunas páginas continúen mostrándose como si la sesión estuviera iniciada hasta que actualices la caché de tu navegador.",
+       "logging-out-notify": "Se está cerrando la sesión, espera unos segundos.",
+       "logout-failed": "Error al cerrar sesión: $1",
        "cannotlogoutnow-title": "No se puede cerrar sesión ahora",
        "cannotlogoutnow-text": "No se puede cerrar sesión cuando se usa $1.",
        "welcomeuser": "¡Bienvenido/a, $1!",
        "page_first": "primeras",
        "page_last": "últimas",
        "histlegend": "Selección de diferencias: marca las casillas correspondientes a las versiones a comparar y pulsa Intro o el botón de abajo.<br />\nLeyenda: <strong>({{int:cur}})</strong> = diferencias con la versión actual,\n<strong>({{int:last}})</strong> = diferencias con la versión anterior, <strong>{{int:minoreditletter}}</strong> = edición menor.",
-       "history-fieldset-title": "Buscar revisiones",
+       "history-fieldset-title": "Filtrar revisiones",
        "history-show-deleted": "Solo revisiones eliminadas",
        "histfirst": "primeras",
        "histlast": "recientes",
        "historysize": "({{PLURAL:$1|1 byte|$1 bytes}})",
-       "historyempty": "(vacío)",
+       "historyempty": "vacío",
        "history-feed-title": "Historial de revisiones",
        "history-feed-description": "Historial de revisiones de esta página en el wiki",
        "history-feed-item-nocomment": "$1 en $2",
        "right-reupload-own": "Subir una nueva versión de un archivo propio",
        "right-reupload-shared": "Sobrescribir localmente archivos presentes en el repositorio multimedia compartido",
        "right-upload_by_url": "Subir un archivo a traves de un URL",
-       "right-purge": "Purgar la antememoria de una página sin confirmación",
+       "right-purge": "Purgar la caché de una página en el servidor",
        "right-autoconfirmed": "No resultar afectado por los límites de frecuencia de edición para las IP",
        "right-bot": "Ser tratado como un proceso automático",
        "right-nominornewtalk": "No accionar el aviso de mensajes nuevos al realizar ediciones menores en páginas de discusión",
        "action-changetags": "agregar y quitar etiquetas arbitrarias a revisiones individuales y entradas del registro",
        "action-deletechangetags": "eliminar etiquetas de la base de datos",
        "action-purge": "purgar esta página",
+       "action-bigdelete": "eliminar las páginas con historiales grandes",
+       "action-bot": "ser tratado como un proceso automatizado",
+       "action-editprotected": "Editar páginas protegidas como «{{int:protect-level-sysop}}»",
+       "action-editsemiprotected": "Editar páginas protegidas como «{{int:protect-level-autoconfirmed}}»",
+       "action-editinterface": "editar la interfaz de usuario",
+       "action-editusercss": "editar archivos CSS de otros usuarios",
+       "action-edituserjson": "editar archivos JSON de otros usuarios",
+       "action-edituserjs": "editar archivos JavaScript de otros usuarios",
+       "action-editsitecss": "editar CSS global de la web",
+       "action-editsitejson": "editar JSON global de la web",
+       "action-editsitejs": "editar JavaScript global de la web",
+       "action-editmyusercss": "editar tus propios archivos CSS",
+       "action-editmyuserjson": "editar tus propios archivos JSON",
+       "action-editmyuserjs": "editar tus propios archivos JavaScript",
+       "action-viewsuppressed": "ver revisiones ocultas de cualquier usuario",
+       "action-hideuser": "bloquear un nombre de usuario, haciéndolo invisible",
+       "action-ipblock-exempt": "evitar bloques de IP, autobloqueos y bloqueos a distancia",
+       "action-unblockself": "desbloquearse a sí mismo",
+       "action-reupload-own": "sobrescribir archivos existentes subidos por uno mismo",
+       "action-suppressredirect": "no crear redirecciones de las páginas al trasladarlas",
        "nchanges": "$1 {{PLURAL:$1|cambio|cambios}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|desde la última visita}}",
        "enhancedrc-history": "historial",
        "rcfilters-savedqueries-already-saved": "Ya se guardaron estos filtros. Modifica tu configuración para crear un filtro guardado nuevo.",
        "rcfilters-restore-default-filters": "Restaurar filtros predeterminados",
        "rcfilters-clear-all-filters": "Borrar todos los filtros",
-       "rcfilters-show-new-changes": "Ver los cambios más recientes",
+       "rcfilters-show-new-changes": "Ver cambios nuevos desde $1",
        "rcfilters-search-placeholder": "Filtrar cambios (utiliza el menú o busca el nombre de un filtro)",
        "rcfilters-invalid-filter": "Filtro no válido",
        "rcfilters-empty-filter": "No hay filtros activos. Se muestran todas las contribuciones.",
        "rcfilters-filter-editsbyself-description": "Tus propias contribuciones",
        "rcfilters-filter-editsbyother-label": "Cambios de otros",
        "rcfilters-filter-editsbyother-description": "Todos los cambios, excepto los tuyos.",
-       "rcfilters-filtergroup-userExpLevel": "Registro de usuario y experiencia",
+       "rcfilters-filtergroup-user-experience-level": "Registro de usuario y experiencia",
        "rcfilters-filter-user-experience-level-registered-label": "Registrados",
        "rcfilters-filter-user-experience-level-registered-description": "Usuarios conectados.",
        "rcfilters-filter-user-experience-level-unregistered-label": "No registrados",
        "rcfilters-hideminor-conflicts-typeofchange-global": "El filtro \"Ediciones menores\" está en conflicto con uno o más Tipos de filtros de Cambio, ya que ciertos tipos de cambio no pueden ser designados como \"menores\". Los filtros en conflicto están marcados en el área Filtros activos, anterior.",
        "rcfilters-hideminor-conflicts-typeofchange": "Ciertos tipos de cambio no pueden ser designados como \"menores\", por lo que este filtro entra en conflicto con los siguientes  Tipos de filtros de Cambio: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Este filtro «Tipo de cambio» entra en conflicto con el filtro «Ediciones menores». Hay ciertos tipos de cambios que no pueden denominarse «menores».",
-       "rcfilters-filtergroup-lastRevision": "Últimas revisiones",
+       "rcfilters-filtergroup-lastrevision": "Últimas revisiones",
        "rcfilters-filter-lastrevision-label": "Última revisión",
        "rcfilters-filter-lastrevision-description": "Solo el cambio más reciente a una página.",
        "rcfilters-filter-previousrevision-label": "No la revisión más reciente",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|usuario|usuarios}} vigilando]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} después del cambio",
        "newsectionsummary": "Sección nueva: /* $1 */",
        "rc-enhanced-expand": "Mostrar detalles",
        "img-auth-nopathinfo": "Falta la información de ruta.\nEl servidor tiene que estar configurado para proporcionar las variables REQUEST_URI y/o PATH_INFO.\nSi lo está, intentá habilitar $wgUsePathInfo.\nConsulte https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "La ruta solicitada no figura en la carpeta de subidas configurada.",
        "img-auth-badtitle": "Incapaz de construir un título válido de «$1».",
-       "img-auth-nologinnWL": "No has iniciado sesión y «$1» no está en la lista blanca.",
        "img-auth-nofile": "El archivo «$1» no existe.",
        "img-auth-isdir": "Estás tratando de acceder a un directorio «$1».\nSolo se permite el acceso a los archivos.",
        "img-auth-streaming": "Streaming «$1».",
        "delete-confirm": "Borrar «$1»",
        "delete-legend": "Borrar",
        "historywarning": "<strong>Atención:</strong> la página que estás a punto de borrar tiene un historial con $1 {{PLURAL:$1|revisión|revisiones}}:",
-       "historyaction-submit": "Mostrar",
+       "historyaction-submit": "Mostrar revisiones",
        "confirmdeletetext": "Estás a punto de borrar una página, así como todo su historial.\nConfirma que realmente quieres hacer esto, que entiendes las consecuencias y que lo estás haciendo de acuerdo con [[{{MediaWiki:Policy-url}}|las normativas]].",
        "actioncomplete": "Se ha realizado la acción",
        "actionfailed": "Ha fallado la acción",
        "deleting-backlinks-warning": "<strong>Atención:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|otras páginas]] enlazan o transcluyen la página que estás a punto de borrar.",
        "deleting-subpages-warning": "<strong>Atención:</strong> la página que estás a punto de borrar tiene [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|una subpágina|$1 subpáginas|51=más de 50 subpáginas}}]].",
        "rollback": "Revertir ediciones",
+       "rollback-confirmation-confirm": "Por favor, confirma:",
+       "rollback-confirmation-yes": "Revertir",
+       "rollback-confirmation-no": "Cancelar",
        "rollbacklink": "revertir",
        "rollbacklinkcount": "revertir $1 {{PLURAL:$1|edición|ediciones}}",
        "rollbacklinkcount-morethan": "revertir más de $1 {{PLURAL:$1|edición|ediciones}}",
        "revertpage": "Revertidos los cambios de [[Special:Contributions/$2|$2]] ([[User talk:$2|disc.]]) a la última edición de [[User:$1|$1]]",
        "revertpage-nouser": "Revertidas las ediciones hechas por un usuario oculto a la última revisión hecha por {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Revertidas las ediciones de {{GENDER:$3|$1}};\nrecuperada la última versión de {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Revertidas las ediciones de $1 hasta la última revisión de $2. [$3 Ver cambios]",
        "sessionfailure-title": "Error de sesión",
        "sessionfailure": "Parece que hay un problema con tu sesión;\nse ha cancelado esta acción como medida de precaución contra el robo de sesiones.\nEnvía el formulario otra vez.",
        "changecontentmodel": "Cambiar el modelo de contenido de una página",
        "mycontris": "Contribuciones",
        "anoncontribs": "Contribuciones",
        "contribsub2": "Para {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "Para {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "La cuenta de usuario «$1» no está registrada.",
        "negative-namespace-not-supported": "Los espacios de nombres con valores negativos no están permitidos",
        "nocontribs": "No se encontraron cambios que cumplieran estos criterios.",
        "blocklist-userblocks": "Ocultar bloqueos de cuenta",
        "blocklist-tempblocks": "Ocultar bloqueos temporales",
        "blocklist-addressblocks": "Ocultar bloqueos de una sola dirección IP",
+       "blocklist-type": "Tipo:",
+       "blocklist-type-opt-all": "Todo",
+       "blocklist-type-opt-sitewide": "En toda la web",
+       "blocklist-type-opt-partial": "Parcial",
        "blocklist-rangeblocks": "Ocultar bloqueos por intervalo",
        "blocklist-timestamp": "Marca de tiempo",
        "blocklist-target": "Destino",
        "blocklist-editing-page": "páginas",
        "blocklist-editing-ns": "Espacios de nombres",
        "ipblocklist-empty": "La lista de bloqueos está vacía.",
-       "ipblocklist-no-results": "El nombre de usuario o IP indicado no está bloqueado.",
+       "ipblocklist-no-results": "El nombre de usuario o IP indicado no coincide.",
        "blocklink": "bloquear",
        "unblocklink": "desbloquear",
        "change-blocklink": "cambiar bloqueo",
+       "empty-username": "(nombre de usuario no disponible)",
        "contribslink": "contribuciones",
        "emaillink": "enviar correo electrónico",
        "autoblocker": "Has sido bloqueado automáticamente porque tu dirección IP ha sido usada recientemente por «[[User:$1|$1]]».\nEl motivo por el que se bloqueó a [[User:$1|$1]] es «$2».",
        "allmessagesdefault": "Texto predeterminado",
        "allmessagescurrent": "Texto actual",
        "allmessagestext": "Esta es una lista de mensajes del sistema disponibles en el espacio de nombres MediaWiki.\nVisita [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Regionalización de MediaWiki] y [https://translatewiki.net translatewiki.net] si deseas contribuir a la regionalización genérica de MediaWiki.",
-       "allmessagesnotsupportedDB": "Esta página no está disponible porque <strong>$wgUseDatabaseMessages</strong> está desactivado.",
+       "allmessages-not-supported-database": "Esta página no está disponible porque <strong>$wgUseDatabaseMessages</strong> está desactivado.",
        "allmessages-filter-legend": "Filtro",
        "allmessages-filter": "Filtrar por estado de personalización:",
        "allmessages-filter-unmodified": "Sin modificar",
        "recreate": "Recrear",
        "confirm-purge-title": "Purgar esta página",
        "confirm_purge_button": "Aceptar",
-       "confirm-purge-top": "¿Quieres vaciar la antememoria de esta página?",
-       "confirm-purge-bottom": "Purgar una página limpia la antememoria y fuerza a que aparezca la versión más actual.",
+       "confirm-purge-top": "¿Quieres vaciar la caché de esta página?",
+       "confirm-purge-bottom": "Purgar una página limpia la caché y fuerza a que aparezca la versión más actual.",
        "confirm-watch-button": "Aceptar",
        "confirm-watch-top": "¿Añadir esta página a tu lista de seguimiento?",
        "confirm-unwatch-button": "Aceptar",
index 97d256c..5827dba 100644 (file)
@@ -78,6 +78,7 @@
        "tog-norollbackdiff": "Ära näita erinevusi pärast tühistamist",
        "tog-useeditwarning": "Hoiata mind, kui lahkun redigeerimisleheküljelt muudatusi salvestamata",
        "tog-prefershttps": "Kasuta sisselogimisel alati turvalist ühendust",
+       "tog-showrollbackconfirmation": "Küsi tühistamislingile klõpsamise järel kinnitust",
        "underline-always": "Alati",
        "underline-never": "Mitte kunagi",
        "underline-default": "Kujunduse või brauseri vaikeväärtus",
        "category_header": "Leheküljed kategoorias \"$1\"",
        "subcategories": "Alamkategooriad",
        "category-media-header": "Failid kategoorias \"$1\"",
-       "category-empty": "<em>Selles kategoorias pole praegu ühtegi lehekülge ega meediafaili.</em>",
+       "category-empty": "<em>Selles kategoorias pole praegu ühtegi lehekülge ega faili.</em>",
        "hidden-categories": "{{PLURAL:$1|Peidetud kategooria|Peidetud kategooriad}}",
        "hidden-category-category": "Peidetud kategooriad",
        "category-subcat-count": "{{PLURAL:$2|Selles kategoorias on ainult järgmine alamkategooria.|{{PLURAL:$1|Järgmine alamkategooria|Järgmised $1 alamkategooriat}} on selles kategoorias (kokku $2).}}",
        "sort-ascending": "Järjesta tõusvalt",
        "nstab-main": "Artikkel",
        "nstab-user": "Kasutaja leht",
-       "nstab-media": "Meedialeht",
+       "nstab-media": "Meediumileht",
        "nstab-special": "Eri",
        "nstab-project": "Projektileht",
        "nstab-image": "Fail",
        "badretype": "Sisestatud paroolid ei lange kokku.",
        "usernameinprogress": "Selle kasutajanimega konto loomine on juba pooleli.\nPalun oota.",
        "userexists": "Sisestatud kasutajanimi on juba kasutusel.\nPalun valige uus nimi.",
+       "createacct-normalization": "Tehniliste piirangute tõttu kohandatakse sinu kasutajanimi kujule \"$2\".",
        "loginerror": "Viga sisselogimisel",
        "createacct-error": "Tõrge konto loomisel",
        "createaccounterror": "Kasutajakonto loomine ebaõnnestus: $1",
        "page_first": "esimene",
        "page_last": "viimane",
        "histlegend": "Märgi versioonid, mida tahad võrrelda ja vajuta võrdlemisnupule.\nLegend: (viim) = erinevused võrreldes viimase redaktsiooniga,\n(eel) = erinevused võrreldes eelmise redaktsiooniga, P = pisimuudatus",
-       "history-fieldset-title": "Redaktsioonide otsimine",
+       "history-fieldset-title": "Redaktsioonide filtreerimine",
        "history-show-deleted": "Üksnes kustutatud redaktsioonid",
        "histfirst": "vanimad",
        "histlast": "uusimad",
        "historysize": "({{PLURAL:$1|1 bait|$1 baiti}})",
-       "historyempty": "(tühi)",
+       "historyempty": "tühi",
        "history-feed-title": "Redigeerimiste ajalugu",
        "history-feed-description": "Selle lehekülje redigeerimiste ajalugu",
        "history-feed-item-nocomment": "$1 – $2",
        "right-reupload-own": "Üle kirjutada enda üles laaditud faile",
        "right-reupload-shared": "Asendada kohalikus vikis jagatud failivaramu faile",
        "right-upload_by_url": "Faile internetiaadressilt üles laadida",
-       "right-purge": "Tühjendada lehekülje vahemälu kinnituseta",
+       "right-purge": "Tühjendada lehekülje vahemälu",
        "right-autoconfirmed": "Hoiduda IP-aadressi põhistest piirangumääradest",
-       "right-bot": "Olla koheldud kui automaadistatud toimimisviis",
-       "right-nominornewtalk": "Teha arutelulehekülgedel pisimuudatusi, ilma et lehekülg märgitaks uuena",
+       "right-bot": "Olla käsitatud automaatse protsessina",
+       "right-nominornewtalk": "Teha arutelulehekülgedel pisimuudatusi ilma uue sõnumi teadet esile kutsumata",
        "right-apihighlimits": "Kasutada API-päringutes kõrgemaid limiite",
        "right-writeapi": "Kasutada kirjutamise rakendusliidest",
        "right-delete": "Lehekülgi kustutada",
-       "right-bigdelete": "Pikkade ajalugudega lehekülgi kustutada",
+       "right-bigdelete": "Kustutada suure ajalooga lehekülgi",
        "right-deletelogentry": "Kustutada ja taastada logisissekandeid",
        "right-deleterevision": "Kustutada ja taastada lehekülgede teatud redaktsioone",
        "right-deletedhistory": "Vaadata kustutatud ajalookirjeid ilma seotud tekstita",
        "right-editsitecss": "Redigeerida saidiülest CSS-i",
        "right-editsitejson": "Redigeerida saidiülest JSON-i",
        "right-editsitejs": "Redigeerida saidiülest JavaScripti",
-       "right-editmyusercss": "Redigeerida oma CSS-kasutajafaile",
-       "right-editmyuserjson": "Redigeerida oma JSON-kasutajafaile",
-       "right-editmyuserjs": "Redigeerida oma JavaScript-kasutajafaile",
+       "right-editmyusercss": "Redigeerida enda CSS-faile",
+       "right-editmyuserjson": "Redigeerida enda JSON-faile",
+       "right-editmyuserjs": "Redigeerida enda JS-faile",
        "right-viewmywatchlist": "Vaadata oma jälgimisloendit",
        "right-editmywatchlist": "Redigeerida oma jälgimisloendit. Pane tähele, et mõne toiminguga lisatakse lehekülgi siiski ka ilma selle õiguseta.",
        "right-viewmyprivateinfo": "Vaadata oma eraandmeid (nt e-posti aadress, pärisnimi)",
        "action-changetags": "käsitsi rakendatavaid märgiseid üksikute redaktsioonide ega logisissekannete juures lisada ega eemaldada",
        "action-deletechangetags": "märgiseid andmebaasist kustutada",
        "action-purge": "lehekülje vahemälu tühjendada",
+       "action-apihighlimits": "API-päringutes kõrgemaid limiite kasutada",
+       "action-autoconfirmed": "IP-aadressi põhistest piirangumääradest hoiduda",
+       "action-bigdelete": "suurte ajalugudega lehekülgi kustutada",
+       "action-blockemail": "kasutajal e-kirjade saatmist keelata",
+       "action-bot": "olla käsitatud automaatse protsessina",
+       "action-editprotected": "redigeerida lehekülgi kaitsetasemega \"{{int:protect-level-sysop}}\"",
+       "action-editsemiprotected": "redigeerida lehekülgi kaitsetasemega \"{{int:protect-level-autoconfirmed}}\"",
+       "action-editinterface": "kasutajaliidest redigeerida",
+       "action-editusercss": "redigeerida teiste kasutajate CSS-faile",
+       "action-edituserjson": "redigeerida teiste kasutajate JSON-faile",
+       "action-edituserjs": "redigeerida teiste kasutajate JS-faile",
+       "action-editsitecss": "redigeerida saidiülest CSS-i",
+       "action-editsitejson": "redigeerida saidiülest JSON-i",
+       "action-editsitejs": "redigeerida saidiülest JavaScripti",
+       "action-editmyusercss": "redigeerida enda CSS-faile",
+       "action-editmyuserjson": "redigeerida enda JSON-faile",
+       "action-editmyuserjs": "redigeerida enda JS-faile",
+       "action-viewsuppressed": "vaadata kõigi kasutajate eest varjatud redaktsioone",
+       "action-hideuser": "blokeerida kasutajanime, peites selle avalikkuse eest",
+       "action-ipblock-exempt": "mööduda automaatsetest blokeeringutest ning aadressivahemiku- ja IP-blokeeringutest",
+       "action-unblockself": "eemaldada enda blokeeringut",
+       "action-noratelimit": "hoiduda piirangumääradest",
+       "action-reupload-own": "enda üles laaditud faile üle kirjutada",
+       "action-nominornewtalk": "teha arutelulehekülgedel pisimuudatusi ilma uue sõnumi teadet esile kutsumata",
+       "action-markbotedits": "märkida muudatuse tühistamist robotimuudatuseks",
+       "action-patrolmarks": "vaadata viimaste muudatuste kontrollimise märkeid",
+       "action-override-export-depth": "eksportida lehekülgi, kaasates viidatud leheküljed kuni viienda tasemeni",
+       "action-suppressredirect": "ümbersuunamist loomata lehekülgi teisaldada",
        "nchanges": "$1 {{PLURAL:$1|muudatus|muudatust}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|viimase vaatamise järel}}",
        "enhancedrc-history": "ajalugu",
        "rcfilters-savedqueries-already-saved": "Need filtrid on juba salvestatud. Muuda sätteid, et koostada uus salvestatud filter.",
        "rcfilters-restore-default-filters": "Taasta vaikefiltrid",
        "rcfilters-clear-all-filters": "Eemalda kõik filtrid",
-       "rcfilters-show-new-changes": "Vaata uusimaid muudatusi",
+       "rcfilters-show-new-changes": "Vaata uusi muudatusi alates: $1",
        "rcfilters-search-placeholder": "Filtreeri muudatusi (kasuta menüüd või tipi filtri nimi)",
        "rcfilters-invalid-filter": "Vigane filter",
        "rcfilters-empty-filter": "Aktiivsed filtrid puuduvad. Näidatakse kogu kaastööd.",
        "rcfilters-filter-editsbyself-description": "Sinu enda muudatused.",
        "rcfilters-filter-editsbyother-label": "Teiste muudatused",
        "rcfilters-filter-editsbyother-description": "Kõik muudatused peale sinu enda omade.",
-       "rcfilters-filtergroup-userExpLevel": "Registreerumine ja kasutaja kogemus",
+       "rcfilters-filtergroup-user-experience-level": "Registreerumine ja kasutaja kogemus",
        "rcfilters-filter-user-experience-level-registered-label": "Registreerunud",
        "rcfilters-filter-user-experience-level-registered-description": "Sisse logitud kasutajad.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Registreerumata",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Filter \"{{int:rcfilters-filter-minor-label}}\" on konfliktis vähemalt ühe muudatuste tüübifiltriga, sest teatud tüüpi muudatusi ei saa märkida pisimuudatusteks. Konfliktsed filtrid on ära märgitud ülal aktiivsete filtrite loendis.",
        "rcfilters-hideminor-conflicts-typeofchange": "Teatud tüüpi muudatusi ei saa märkida pisimuudatusteks. Seetõttu on see filter konfliktis järgmiste tüübifiltritega: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "See muudatuste tüübifilter on konfliktis filtriga \"{{int:rcfilters-filter-minor-label}}\". Teatud tüüpi muudatusi ei saa märkida pisimuudatusteks.",
-       "rcfilters-filtergroup-lastRevision": "Viimased redaktsioonid",
+       "rcfilters-filtergroup-lastrevision": "Viimased redaktsioonid",
        "rcfilters-filter-lastrevision-label": "Viimane redaktsioon",
        "rcfilters-filter-lastrevision-description": "Ainult muudatus, mis on leheküljel kõige viimane.",
        "rcfilters-filter-previousrevision-label": "Pole viimane redaktsioon",
        "minoreditletter": "P",
        "newpageletter": "U",
        "boteditletter": "R",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|jälgiv kasutaja|jälgivat kasutajat}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|bait|baiti}} pärast muudatust",
        "newsectionsummary": "/* $1 */ uus alaosa",
        "rc-enhanced-expand": "Näita üksikasju",
        "img-auth-nopathinfo": "Puudub teave tee kohta.\nServer peab olema seadistatud edastama muutujaid REQUEST_URI ja/või PATH_INFO.\nKui on, siis proovi lubada säte $wgUsePathInfo.\nVaata lehekülge https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Soovitud salvestuskoht pole üleslaadimiskataloogi all.",
        "img-auth-badtitle": "Väljendist \"$1\" ei saa sobivat pealkirja moodustada.",
-       "img-auth-nologinnWL": "Sa pole sisselogitud ja \"$1\" pole valges nimekirjas.",
        "img-auth-nofile": "Faili \"$1\" pole.",
        "img-auth-isdir": "Sa üritad kausta \"$1\" juurde pääseda.\nLubatud on ainult juurdepääs failidele.",
        "img-auth-streaming": "Faili \"$1\" voogedastus.",
        "delete-confirm": "Lehekülje \"$1\" kustutamine",
        "delete-legend": "Kustutamine",
        "historywarning": "<strong>Hoiatus:</strong> Kustutataval leheküljel on {{PLURAL:$1|ühe redaktsiooniga|$1 redaktsiooniga}} ajalugu:",
-       "historyaction-submit": "Näita",
+       "historyaction-submit": "Näita redaktsioone",
        "confirmdeletetext": "Sa oled andmebaasist kustutamas lehekülge koos kogu tema ajalooga.\nPalun kinnita, et tahad seda tõepoolest teha, et sa mõistad tagajärgi ja et sinu tegevus on kooskõlas siinse [[{{MediaWiki:Policy-url}}|sisekorraga]].",
        "actioncomplete": "Toiming sooritatud",
        "actionfailed": "Toiming ebaõnnestus",
        "deleting-backlinks-warning": "<strong>Hoiatus:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Teised leheküljed]] viitavad leheküljele, mida oled kustutamas, või see lehekülg on kasutuses mallina.",
        "deleting-subpages-warning": "<strong>Hoiatus:</strong> Oled kustutamas lehekülge, millel on [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|alamlehekülg|$1 alamlehekülge|51=üle 50 alamlehekülje}}]].",
        "rollback": "Tühista muudatused",
+       "rollback-confirmation-confirm": "Palun kinnita:",
+       "rollback-confirmation-yes": "tühista",
+       "rollback-confirmation-no": "loobu",
        "rollbacklink": "tühista",
        "rollbacklinkcount": "tühista {{PLURAL:$1|üks muudatus|$1 muudatust}}",
        "rollbacklinkcount-morethan": "tühista üle {{PLURAL:$1|ühe muudatuse|10 muudatuse}}",
        "revertpage": "Tühistati kasutaja [[Special:Contributions/$2|$2]] ([[User talk:$2|arutelu]]) tehtud muudatused ja pöörduti tagasi viimasele muudatusele, mille tegi [[User:$1|$1]].",
        "revertpage-nouser": "Tühistati peidetud kasutaja muudatused ja pöörduti tagasi viimasele muudatusele, mille tegi [[User:$1|$1]].",
        "rollback-success": "Tühistati muudatused, mille tegi {{GENDER:$3|$1}};\npöörduti tagasi viimasele muudatusele, mille tegi {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Tühistatud kasutaja $1 tehtud muudatused;\npöördutud tagasi kasutaja $2 viimase redaktsiooni juurde. [$3 Näita muudatusi]",
        "sessionfailure-title": "Seansiviga",
        "sessionfailure": "Näib, et sinu sisselogimisseanss on probleemne.\nSeansiärandamise vastase ettevaatusabinõuna on see toiming tühistatud.\nPalun saada vorm uuesti.",
        "changecontentmodel": "Lehekülje sisumudeli muutmine",
        "mycontris": "Kaastöö",
        "anoncontribs": "Kaastöö",
        "contribsub2": "Kasutaja {{GENDER:$3|$1}} ($2) kaastöö",
+       "contributions-subtitle": "{{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "Kasutajakonto \"$1\" pole registreeritud.",
        "negative-namespace-not-supported": "Negatiivse väärtusega nimeruumide tugi puudub.",
        "nocontribs": "Antud kriteeriumitele vastavaid muudatusi ei leitud.",
        "ipb-confirm": "Kinnita blokeering",
        "ipb-sitewide": "Saidiülene",
        "ipb-partial": "Osaline",
+       "ipb-sitewide-help": "Viki kõigi lehekülgede muutmine ja kogu ülejäänud kaastöö.",
+       "ipb-partial-help": "Teatud lehekülgede või nimeruumide muutmine.",
        "ipb-pages-label": "Leheküljed",
        "ipb-namespaces-label": "Nimeruumid",
        "badipaddress": "Vigane IP-aadress",
        "blocklist-userblocks": "Peida kontod",
        "blocklist-tempblocks": "Peida ajutised",
        "blocklist-addressblocks": "Peida üksikud IP-aadressid",
+       "blocklist-type": "Tüüp:",
+       "blocklist-type-opt-all": "Kõik",
+       "blocklist-type-opt-sitewide": "Saidiülene",
+       "blocklist-type-opt-partial": "Osaline",
        "blocklist-rangeblocks": "Peida vahemikublokeeringud",
        "blocklist-timestamp": "Ajatempel",
        "blocklist-target": "Blokeeritav",
        "blocklist-editing-page": "leheküljed",
        "blocklist-editing-ns": "nimeruumid",
        "ipblocklist-empty": "Blokeerimiste loend on tühi.",
-       "ipblocklist-no-results": "Nõutud IP-aadress või kasutajatunnus ei ole blokeeritud.",
+       "ipblocklist-no-results": "Päritud IP-aadressile või kasutajanimele vastavaid blokeeringuid ei leitud.",
        "blocklink": "blokeeri",
        "unblocklink": "lõpeta blokeerimine",
        "change-blocklink": "muuda blokeeringut",
        "allmessagesdefault": "Vaiketekst",
        "allmessagescurrent": "Praegune tekst",
        "allmessagestext": "See on loend kõikidest olemasolevatest süsteemisõnumitest MediaWiki nimeruumis.\nKui soovid MediaWiki tarkvara tõlkimises osaleda, siis vaata lehti [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki lokaliseerimine] ja [https://translatewiki.net translatewiki.net].",
-       "allmessagesnotsupportedDB": "Seda lehekülge ei saa kasutada, sest '''$wgUseDatabaseMessages''' ei tööta.",
+       "allmessages-not-supported-database": "Seda lehekülge ei saa kasutada, sest '''$wgUseDatabaseMessages''' ei tööta.",
        "allmessages-filter-legend": "Filter",
        "allmessages-filter": "Muutmisoleku filter:",
        "allmessages-filter-unmodified": "Muutmata",
        "tooltip-t-permalink": "Püsilink lehekülje sellele redaktsioonile",
        "tooltip-ca-nstab-main": "Vaata sisulehekülge",
        "tooltip-ca-nstab-user": "Näita kasutaja lehte",
-       "tooltip-ca-nstab-media": "Vaata meedialehte",
+       "tooltip-ca-nstab-media": "Vaata meediumilehte",
        "tooltip-ca-nstab-special": "See on erilehekülg ja seda ei saa redigeerida.",
        "tooltip-ca-nstab-project": "Näita projekti lehte",
        "tooltip-ca-nstab-image": "Vaata faili lehekülge",
        "confirm-unwatch-top": "Kas eemaldad selle lehekülje oma jälgimisloendist?",
        "confirm-rollback-button": "Sobib",
        "confirm-rollback-top": "Kas tühistad sellel leheküljel tehtud muudatused?",
+       "confirm-rollback-bottom": "See toiming tühistab koheselt valitud muudatused sellel leheküljel.",
        "confirm-mcrrestore-title": "Redaktsiooni taastamine",
        "confirm-mcrundo-title": "Muudatuse eemaldamine",
        "mcrundofailed": "Eemaldamine ebaõnnestus",
        "logentry-rights-autopromote": "$1 {{GENDER:$2|viidi}} automaatselt üle teise rühma; enne oli $4, nüüd on $5",
        "logentry-upload-upload": "$1 {{GENDER:$2|laadis üles}} faili $3",
        "logentry-upload-overwrite": "$1 {{GENDER:$2|laadis üles}} uue versiooni failist $3",
-       "logentry-upload-revert": "$1 {{GENDER:$2|laadis üles}} faili $3",
+       "logentry-upload-revert": "$1 {{GENDER:$2|taastas}} faili $3 vanema versiooni",
        "log-name-managetags": "Märgiste haldamise logi",
        "log-description-managetags": "Sellel leheküljel on toodud [[Special:Tags|märgiste]] haldamisega seotud tegevused. Logis on ainult toimingud, mida administraatorid on teinud käsitsi. Siin puuduvad logisissekanded viki tarkvaras koostatud või sealt kustutatud märgiste kohta.",
        "logentry-managetags-create": "$1 {{GENDER:$2|koostas}} märgise \"$4\"",
        "default-skin-not-found-no-skins": "Oih! Sinu viki vaikekujundus, milleks muutuja <code dir=\"ltr\">$wgDefaultSkin</code> järgi on <code>$1</code>, pole saadaval.\n\nÜhtegi kujundust pole paigaldatud.\n\n; Kui oled MediaWiki just paigaldanud või täiendasid seda:\n: Paigaldasid tarkvara ilmselt Giti kaudu või otse lähtekoodist või mõnel muul viisil. See on ootuspärane. MediaWiki 1.24 ja uuemad versioonid ei sisalda peahoidlas ühtegi kujundust. Proovi [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org-i kujunduste kataloogist] mõni kujundus paigaldada. Selleks saad:\n:* laadida alla [https://www.mediawiki.org/wiki/Download lintarhiivi paigaldaja], mis sisaldab mitut kujundust ja tarkvaralisa. Saad sealt kleepimiseks kopeerida kausta <code dir=\"ltr\">skins/</code>;\n:* [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org-ist] kindla kujunduse lintarhiivi alla laadida;\n:* [https://www.mediawiki.org/wiki/Download_from_Git#Using_Git_to_download_MediaWiki_skins kasutada Giti, et kujundusi alla laadida].\n: Selle tegemine ei tohiks häirida Giti hoidlat, kui oled MediaWiki arendaja. Vaata [https://www.mediawiki.org/wiki/Manual:Skin_configuration kujunduste häälestusjuhendist], kuidas kujundusi lubada ja kuidas valida vaikekujundus.",
        "default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (lubatud)",
        "default-skin-not-found-row-disabled": "* <code>$1</code> / $2 (<strong>keelatud</strong>)",
-       "mediastatistics": "Meediastatistika",
+       "mediastatistics": "Failide arvandmestik",
        "mediastatistics-summary": "Arvandmed üles laaditud failitüüpide kohta. See käib ainult failide viimaste versioonide kohta. Vanu ja kustutatud versioone pole arvesse võetud.",
        "mediastatistics-nbytes": "{{PLURAL:$1|$1 bait|$1 baiti}} ($2; $3%)",
        "mediastatistics-bytespertype": "Failide kogusuurus selles alaosas: $1 {{PLURAL:$1|bait|baiti}} ($2; $3%).",
        "log-action-filter-suppress-reblock": "Kasutaja varjamine taasblokeerimise teel",
        "log-action-filter-upload-upload": "Uus üleslaadimine",
        "log-action-filter-upload-overwrite": "Uuesti üleslaadimine",
+       "log-action-filter-upload-revert": "Taastamine",
        "authmanager-authn-not-in-progress": "Autentimine pole teoksil või seansiandmed läksid kaduma. Palun alusta uuesti.",
        "authmanager-authn-no-primary": "Ette antud autentimisandmeid ei õnnestunud autentida.",
        "authmanager-authn-no-local-user": "Ette antud autentimisandmed pole selles vikis seotud ühegi kasutajaga.",
        "passwordpolicies-policy-maximalpasswordlength": "Parool peab olema $1 {{PLURAL:$1|märgist}} lühem.",
        "passwordpolicies-policy-passwordcannotbepopular": "Parool ei tohi olla {{PLURAL:$1|populaarne parool|$1 populaarse parooli loendis}}.",
        "passwordpolicies-policy-passwordnotinlargeblacklist": "Parool ei saa olla 100&nbsp;000 kõige levinuma parooli loendis.",
+       "passwordpolicies-policyflag-forcechange": "peab muutma sisselogimisel",
+       "passwordpolicies-policyflag-suggestchangeonlogin": "soovita muutmist sisselogimisel",
        "easydeflate-invaliddeflate": "Ette antud sisu ei ole õigesti vähendatud",
-       "unprotected-js": "Turvalisuse huvides ei saa JavaScripti laadida kaitsmata lehekülgedelt. Palun koosta JavaScripti ainult nimeruumis MediaWiki või kasutajate nimeruumi alamleheküljel."
+       "unprotected-js": "Turvalisuse huvides ei saa JavaScripti laadida kaitsmata lehekülgedelt. Palun koosta JavaScripti ainult nimeruumis MediaWiki või kasutajate nimeruumi alamleheküljel.",
+       "userlogout-continue": "Kui soovid välja logida, siis palun [$1 mine väljalogimise leheküljele].",
+       "userlogout-sessionerror": "Väljalogimine ebaõnnestus seansitõrke tõttu. Palun [$1 proovi uuesti]."
 }
index e8e435f..b5924e2 100644 (file)
@@ -34,7 +34,9 @@
                        "Iñaki LL",
                        "Amaia",
                        "Matěj Suchánek",
-                       "CiaPan"
+                       "CiaPan",
+                       "Egonichan",
+                       "Isabel.losaneko"
                ]
        },
        "tog-underline": "Azpimarratu loturak:",
@@ -80,6 +82,7 @@
        "tog-norollbackdiff": "Lehengoratze bat egin ondoren ezberdintasunak ez erakutsi",
        "tog-useeditwarning": "Abisa nazazu gorde gabeko aldaketak eginez edizio orrialde bat uzten dudanean",
        "tog-prefershttps": "Erabili beti konexio seguru bat sartzerakoan",
+       "tog-showrollbackconfirmation": "Zabaldu baieztapen-leiho bat atzera-jotze esteka batean klik egiterakoan",
        "underline-always": "Beti",
        "underline-never": "Inoiz ez",
        "underline-default": "Lehenetsitako nabigatzailea",
        "editfont-monospace": "Monospace iturria",
        "editfont-sansserif": "Sans-serif iturria",
        "editfont-serif": "Serif iturria",
-       "sunday": "Igandea",
-       "monday": "Astelehena",
-       "tuesday": "Asteartea",
-       "wednesday": "Asteazkena",
-       "thursday": "Osteguna",
-       "friday": "Ostirala",
-       "saturday": "Larunbata",
+       "sunday": "igandea",
+       "monday": "astelehena",
+       "tuesday": "asteartea",
+       "wednesday": "asteazkena",
+       "thursday": "osteguna",
+       "friday": "ostirala",
+       "saturday": "larunbata",
        "sun": "Iga",
        "mon": "Asl",
        "tue": "Asr",
        "badretype": "Idatzitako pasahitzak ez dira berdinak.",
        "usernameinprogress": "Erabiltzaile honetarako kontu eraketa martxan dago jadanik. Mesedez, itxaron.",
        "userexists": "Aukeratutako erabiltzaile izena hartuta dago.\nMesedez beste bat aukeratu.",
+       "createacct-normalization": "Zure erabiltzaile-izena \"$2\" izango da murriztapen teknikoen ondorioz.",
        "loginerror": "Errorea saioa hastean",
        "createacct-error": "Kontua sortzerakoan arazoa",
        "createaccounterror": "Ezin izan da kontua sortu: $1",
        "subject-preview": "Gaiaren aurrebista:",
        "previewerrortext": "Errore bat gertatu da aldaketak aurrezten saiatzean.",
        "blockedtitle": "Erabiltzailea blokeatuta dago",
+       "blocked-email-user": "<strong> Zure erabiltzailea blokeatua izan da eta ezin duzu mezurik bidali. Oraindik wiki honetako beste orri batzuk editatu ditzakezu.</strong> Blokeoaren detaile guztiak hemen ikus ditzakezu [[Special:MyContributions|account contributions]].\n\nBlokeoa $1-(e)k egin zuen.\n\nBlokeoaren arrazoiak hauek dira <em>$2</em>.\n\n*Blokeoa hemen hasten da: $8\n*Blokeoa amaitzen da: $6\n*Berariazko blokeoa: $7\n*Blokeoaren ID #$5",
+       "blockedtext-partial": "<strong>Zure erabiltzailea edo IP helbidea blokeatua izan da eta ezin du aldaketarik egin orrialde honetan. Wiki honetako beste orrialdeak oraindik editatu ditzakezu.</strong> Blokeoaren xehetasun guztiak hemen ikus ditzakezu: [[Special:MyContributions|account contributions]].\n\nBlokeoa $1-(e)k egin du.\n\nBlokeoaren arrazoia <em>$2</em> da.\n\n* Blokeoaren hasiera: $8\n* Blokeoaren amaiera: $6\n* Berariazko blokeoa: $7\n* Blokeoaren IDa #$5 da.",
        "blockedtext": "<strong> Zure erabiltzaile izena edo IP helbidea blokeatuta dago. </strong>\n\nBlokeoa $1-ek ezarri du.\nEmandako arrazoia hau da: ''$2''.\n\n* Blokeoaren hasiera: $8\n* Blokeoaren bukaera: $6\n* Blokeatua: $7\n\nBlokeoari buruz eztabaidatzeko, jo ezazu $1 edo beste [[{{MediaWiki:Grouppage-sysop}}|administratzaile]] batengana.\n\"{{int:emailuser}}\" tresna erabili ahal izateko, ezinbestekoa da zure [[Special:Preferences|hobespenetan]] baliozkoa den helbide elektroniko bat emanda izatea, eta tresna hori erabiltzeko aukera blokeatu ez izana.\nOrain duzun IP helbidea $3 da, eta blokeoaren zenbakia #$5.\nMesedez, eman aipatutako datu hauek guztiak, blokeoari buruzko edozein eskaera egitean.",
        "autoblockedtext": "Zure IP helbidea automatikoki blokeaturik dago, $1-ek blokeatutako beste erabiltzaile batek erabili zuelako. Emandako arrazoia hau da:\n\n:<em>$2</em>\n\n* Blokeoaren hasiera: $8\n* Blokeoaren bukaera: $6\n* Blokeatua: $7\n\nBlokeoari buruz eztabaidatzeko, jo ezazu $1 edo beste [[{{MediaWiki:Grouppage-sysop}}|administratzaile]] batengana.\n\n\"{{int:emailuser}}\" tresna erabili ahal izateko, ezinbestekoa da zure [[Special:Preferences|hobespenetan]] baliozkoa den helbide elektroniko bat emanda izatea, eta tresna hori erabiltzeko aukera blokeatu ez izana.\n\nOrain duzun IP helbidea $3 da, eta blokeoaren zenbakia #$5.\n\nMesedez, eman itzazu aipatutako datu guztiak, blokeoari buruzko edozein eskaera egitean.",
        "systemblockedtext": "Zure erabiltzaile izena edo IP helbidea MediaWiki-k automatikoki blokeatu du.\nHau da emandako arrazoia:\n\n:<em>$2</em>\n\n*Bloke sarrera: $8\n*Blokearen iraungintzea: $6\n*Blokeo helburua: $7\n\nZure uneko IP helbidea: $3.\nSartu goiko xehetasun guztiak egiten dituzun kontsulta guztietan mesedez.",
        "edit-gone-missing": "Ezin da orria eguneratu. Ezabatu omen dute.",
        "edit-conflict": "Aldaketa gatazka.",
        "edit-no-change": "Zure edizioa baztertu da testua aldatu ez duzulako.",
+       "edit-slots-cannot-add": "Hurrengo {{PLURAL:$1|eremua|eremuak}} ez {{PLURAL:$1|dago|daude}} $2-n sostengatuta.",
+       "edit-slots-cannot-remove": "{{PLURAL:$1|slot is|slots are}} behar da eta $2 ezin da ezabatu",
+       "edit-slots-missing": "Hurrengo {{PLURAL:$1|eremua|eremuak}} falta {{PLURAL:$1|da|dira}}: $2",
        "postedit-confirmation-created": "Orrialdea sortu da.",
        "postedit-confirmation-restored": "Orrialdea leheneratua izan da.",
        "postedit-confirmation-saved": "Zure aldaketa gorde da.",
        "defaultmessagetext": "Testu lehenetsia",
        "content-failed-to-parse": "Ezin izan da $2(r)en edukia parseatu $1 modeloarentzat: $3",
        "invalid-content-data": "Eduki datu baliogabea",
-       "content-not-allowed-here": "\"$1\" edukia ez dago baimendua [[:$2]] orrialdean",
+       "content-not-allowed-here": "\"$1\"-(e)n edukia ez dago baimenduta [[:$2]] orrialdeko \"$3\" posizioan",
        "editwarning-warning": "Orri honetatik irteten bazara, egindako aldaketak galdu egingo dira, beharbada.\nSaioa hasi baduzu, mezu hau kendu dezakezu zure hobespenen orriko «{{int:prefs-editing}}» atalean.",
        "editpage-invalidcontentmodel-title": "Eduki eredua ez da onartzen.",
        "editpage-invalidcontentmodel-text": "$1 eduki eredua ezin da erabili.",
        "histfirst": "zaharrena",
        "histlast": "berriena",
        "historysize": "({{PLURAL:$1|byte 1|$1 byte}})",
-       "historyempty": "(hutsik)",
+       "historyempty": "hutsik",
        "history-feed-title": "Berrikuspenen historia",
        "history-feed-description": "Wikiko orrialde honen berrikuspenen historia",
        "history-feed-item-nocomment": "nork: $1 noiz: $2",
        "right-reupload-own": "Norberak igotako fitxategi baten gainean idatzi",
        "right-reupload-shared": "Media biltegi komun batean dauden fitxategiak lokalki gainpasa",
        "right-upload_by_url": "URL helbide batetik fitxategi bat igo",
-       "right-purge": "Leku honen katxea garbitu konfirmaziorik gabeko orrialde batentzat",
+       "right-purge": "Web-orrialdearen cachea garbitu",
        "right-autoconfirmed": "Erdi-babestuak dauden orriak aldatu",
        "right-bot": "Prozesu automatikoki gisa jokatu",
        "right-nominornewtalk": "Estabaida orrietan aldaketa txikirik ez edukitzea mezu berrietan",
        "grant-createaccount": "Kontuak sortu",
        "grant-createeditmovepage": "Orrialdeak sortu, aldatu eta mugitu",
        "grant-delete": "Ezabatu orriak, berrikuspenak eta sarrerak",
-       "grant-editinterface": "MediaWiki izen eremua eta CSS/JSON/JavaScript erabiltzailea aldatu",
+       "grant-editinterface": "MediaWiki izen eremua eta web-orri zabalera/erabiltzailea JSON editatu",
        "grant-editmycssjs": "Zure CSS/JSON/JavaScript erabiltzailea aldatu",
-       "grant-editmyoptions": "Aldatu zure hobespenak",
+       "grant-editmyoptions": "Zure erabiltzaile hobespenak eta JSON konfigurazioa aldatu",
        "grant-editmywatchlist": "Zure jarraipen zerrenda aldatu",
        "grant-editsiteconfig": "Gune osoaren eta erabiltzaileen CSS/JS aldatu",
        "grant-editpage": "Aldatu dauden orrialdeak",
        "rcfilters-filter-editsbyself-description": "Zure ekarpenak",
        "rcfilters-filter-editsbyother-label": "Besteek egindako aldaketak",
        "rcfilters-filter-editsbyother-description": "Aldaketa guztiak norberarenak izan ezik.",
-       "rcfilters-filtergroup-userExpLevel": "Erabiltzailearen erregistroa eta esperientzia",
+       "rcfilters-filtergroup-user-experience-level": "Erabiltzailearen erregistroa eta esperientzia",
        "rcfilters-filter-user-experience-level-registered-label": "Erregistratuak",
        "rcfilters-filter-user-experience-level-registered-description": "Sesioa hasi duten editoreak.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Ez erregistratuak",
        "rcfilters-hideminor-conflicts-typeofchange-global": "\"Aldaketa txikiak\" iragazkiak gatazka sortzen du Aldaketa-mota iragazki bat(zu)ekin, aldaketa mota batzuk ezin baitira \"txikiak\" izendatu. Gatazka iragazkiak Iragazki aktiboen eremuan daude markaturik, goian.",
        "rcfilters-hideminor-conflicts-typeofchange": "Zenbait aldaketa mota ezin dira \"txikiak\" bezala izendatu, beraz, iragazkiak hurrengo aldaketa motak dituzten iragazkiekin gatazkak ditu: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Aldaketa iragazki mota honek \"Aldaketa txikiak\" iragazkiarekin gatazkan jartzen da. Zenbait aldaketa motak ezin du \"txikiak\" iragazki izena jaso.",
-       "rcfilters-filtergroup-lastRevision": "Azken berrikuspenak",
+       "rcfilters-filtergroup-lastrevision": "Azken berrikuspenak",
        "rcfilters-filter-lastrevision-label": "Azken berrikuspena",
        "rcfilters-filter-lastrevision-description": "Orrialde bati eginiko aldaketarik berriena.",
        "rcfilters-filter-previousrevision-label": "Ez da azken berrikuspena",
        "rcfilters-watchlist-markseen-button": "Aldaketa guztiak ikusitakoak bezala markatu",
        "rcfilters-watchlist-edit-watchlist-button": "Zure ikusitako orrien zerrenda aldatu",
        "rcfilters-watchlist-showupdated": "Azkenengo aldaketak egin zirenetik bisitatu ez dituzun orrietan eman diren aldaketak <strong>lodi estiloan</strong> daude, markatzaile sendoekin.",
-       "rcfilters-preference-label": "Azkenengo Aldaketen hobetutako bertsioa ezkutatu",
-       "rcfilters-preference-help": "2017 interfazearen birmoldaketa eta geroztik gehitu diren tresna guztietara bueltatzen da.",
-       "rcfilters-watchlist-preference-label": "Ezkutatu jarraipen zerrendaren bertsio hobetua",
-       "rcfilters-watchlist-preference-help": "Alderantzikatu 2017ko interfaze diseinu berria eta ordutik eta ordura arte gehitutako tresnak.",
+       "rcfilters-preference-label": "non-JavaScript interfazea erabili",
+       "rcfilters-preference-help": "Azken aldaketak kargatu bilaketa iragazkiak edo funtzio nabarmenduak erabili gabe",
+       "rcfilters-watchlist-preference-label": "non-JavaScript interfazea erabili",
+       "rcfilters-watchlist-preference-help": "Jarraipen lista kargatu bilaketa iragazkiak edo funtzio nabarmenduak erabili gabe",
        "rcfilters-filter-showlinkedfrom-label": "-tik linkatutako orrietako aldaketak erakutsi",
        "rcfilters-filter-showlinkedfrom-option-label": "hautatutako orritik <strong>linkatutako orriak</strong>",
        "rcfilters-filter-showlinkedto-label": "-ra linkatutako orrietako aldaketak erakutsi",
        "minoreditletter": "t",
        "newpageletter": "B",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|lankide|lankide}} jarraitzen]",
        "rc-change-size-new": "{{PLURAL:$1|Byte 1|$1 byte}} aldaketaren ostean",
        "newsectionsummary": "/* $1 */ atal berria",
        "rc-enhanced-expand": "Erakutsi xehetasunak",
        "uploadstash-zero-length": "Fitxategiaren luzeera zero da.",
        "invalid-chunk-offset": "Desplazamendu zati baliogabea",
        "img-auth-accessdenied": "Sarbide ukatua",
-       "img-auth-nopathinfo": "PATH_INFO falta da.\nZure zerbitzaria ez dago informazio hau pasatzeko konfiguratuta.\nCGI-oinarriduna izan daiteke, img_auth onartzen ez duena.\nIkusi https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
+       "img-auth-nopathinfo": "Bideratze informazioa falta da.\nZure zerbitzaria konfiguratua egon behar du REQUEST_URI eta/edo PATH_INFO aldagaiak gainditzeko.\nBaldin badago, saiatu $wgUsePathInfo gaitzen.\nIkusi https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Eskatutako bidea ez dago kofiguratutako igoera-direktorioan.",
        "img-auth-badtitle": "Ezin izan da baleko izenbururik eraiki \"$1\" izenetik abiatuta",
-       "img-auth-nologinnWL": "Ez duzu saioa hasi eta \"$1\" ez dago zerrenda zurian.",
        "img-auth-nofile": "Ez dago \"$1\" fitxategirik.",
        "img-auth-isdir": "\"$1\" direktorio batera iristen saiatzen ari zara.\nFitxategien sarbidea baino ez da onartzen.",
        "img-auth-streaming": "\"$1\" sekuentziatzen.",
        "prefixindex": "Orri guztiak aurrizkiekin",
        "prefixindex-namespace": "$1 izentartean honako aurrizkia duten orrialde guztiak:",
        "prefixindex-submit": "Erakutsi",
-       "prefixindex-strip": "Zerrendako aurrizkia kendu",
+       "prefixindex-strip": "Emaitzetan aurrizkiak ezkutatu",
        "shortpages": "Orrialde laburrak",
        "longpages": "Orrialde luzeak",
        "deadendpages": "Orrialde itsuak",
        "cachedspecial-refresh-now": "Azkena ikusi.",
        "categories": "Kategoriak",
        "categories-submit": "Erakutsi",
-       "categoriespagetext": "Ondorengo {{PLURAL:$1|kategoria honek|kategoria hauek}} orriak edo fitxategiak {{PLURAL:$1|dauzka|dauzkate}}.\n[[Special:UnusedCategories|Erabili gabeko kategoriak]] ez dira hemen erakusten.\nIkus, gainera, [[Special:WantedCategories|kategoriarik eskatuenak]].",
+       "categoriespagetext": "Ondorengo {{PLURAL:$1|kategoria existitu|kategoriak existitu}} wikian, eta erabilita edo erabili gabe egon daitezke.\nIkus, gainera, [[Special:WantedCategories|kategoriarik eskatuenak]].",
        "categoriesfrom": "Honela hasten diren kategoriak erakutsi:",
        "deletedcontributions": "Ezabatutako ekarpenak",
        "deletedcontributions-title": "Ezabatutako ekarpenak",
        "deleting-backlinks-warning": "<strong>Abisua:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Beste orriek]] ezabatzear zauden orrira linkatu edo doaz.",
        "deleting-subpages-warning": "<strong>Oharra:</strong> Ezabatuko duzun orrialdeak [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|a subpage|$1 subpages|51=over 50 subpages}}]] dauka.",
        "rollback": "Desegin aldaketak",
+       "rollback-confirmation-confirm": "Mesedez baieztatu:",
+       "rollback-confirmation-yes": "Desegin",
+       "rollback-confirmation-no": "Utzi",
        "rollbacklink": "desegin",
        "rollbacklinkcount": "desegin {{PLURAL:$1|edizio bat|$1 edizio}}",
        "rollbacklinkcount-morethan": "desegin {{PLURAL:$1|edizio bat|$1 edizio}} baino gehiago",
        "revertpage": "[[Special:Contributions/$2|$2]] ([[User talk:$2|talk]]) wikilariaren aldaketak deseginda, edukia [[User:$1|$1]] wikilariaren azken bertsiora itzuli da.",
        "revertpage-nouser": "{{GENDER:$1|[[User:$1|$1]]}}-n azken berrikuspena ezkutatutako erabiltzaile batek egindako leheneraketa aldaketak.",
        "rollback-success": "{{GENDER:$3|$1}}; wikilariaren aldaketak deseginda,\nedukia {{GENDER:$4|$2}} wikilariaren azken bertsiora itzuli da.",
-       "rollback-success-notify": "$1k leheneratutako aldaketal;\nazkenengo berrikusketara aldatu da berriz $2ren eskutik. [$3 Erakutsi aldaketak]",
        "sessionfailure-title": "Saio-akatsa",
        "sessionfailure": "Badirudi saioarekin arazoren bat dagoela; ekintza hau ezeztatua izan da, saio bahiketa saihesteko neurri bezala. Mesedez, nabigatzaileko \"atzera\" botoian klik egin, hona ekarri zaituen orrialde hori berriz kargatu, eta saiatu berriz.",
        "changecontentmodel": "Aldatu orri bateko eduki eredua",
        "mycontris": "Ekarpenak",
        "anoncontribs": "Ekarpenak",
        "contribsub2": "{{GENDER:$3|$1(r)entzat}} ($2)",
+       "contributions-subtitle": "{{GENDER:$3|$1(r)entzat}}",
        "contributions-userdoesnotexist": "\"$1\" erabiltzaile-kontua ez dago erregistraturik.",
+       "negative-namespace-not-supported": "Balio negatiboko izen eremuak ez daude babestuak.",
        "nocontribs": "Ez da ezaugarri horiekin bat datorren aldaketarik aurkitu.",
        "uctop": "azken aldaketa",
        "month": "Hilabetea (eta lehenagokoak):",
        "ipbreason": "Arrazoia:",
        "ipbreason-dropdown": "*Blokeaketa arrazoi arruntak\n** Benetakoa ez den informazioa ezartzea\n** Orrialdetatik edukia ezabatzea\n** Spam-a edota kanpoko loturak ezarri\n** Bandalismoa egitea\n** Beste erabiltzaileei mehatxatzea\n** Kontu ugari erabiltzea\n** Erabiltzaile izen desegokia",
        "ipb-hardblock": "Galarazi izena emandako erabiltzaileek IP helbide honetatik editatzea",
-       "ipbcreateaccount": "Debekatu konturik sortzea",
-       "ipbemailban": "Galarazi erabiltzaile honi mezu elektronikoak bidal ditzan",
+       "ipbcreateaccount": "Sortu erabiltzailea",
+       "ipbemailban": "Mezu bat bidali",
        "ipbenableautoblock": "Erabiltzaile honek erabilitako azken IP helbidea automatikoki blokeatu, eta baita erabili dezakeen beste edozein IP ere",
        "ipbsubmit": "Blokeatu erabiltzaile hau",
        "ipbother": "Beste denbora-tarte bat",
        "ipboptions": "2 ordu:2 hours,1 egun:1 day,3 egun:3 days,astebete:1 week,2 aste:2 weeks,hilabete:1 month,3 hilabete:3 months,6 hilabete:6 months,urtebete:1 year,betiko:infinite",
        "ipbhidename": "Lankide izena aldaketa eta zerrendetatik ezkutatu",
        "ipbwatchuser": "Egin jarraipena erabiltzaile honen erabiltzaile eta eztabaida orriei",
-       "ipb-disableusertalk": "Galarazi erabiltzaile honi bere eztabaida orria editatzea, blokeatuta dagoen aldian",
+       "ipb-disableusertalk": "Haien hitz-egiteko orrialde propioa editatu",
        "ipb-change-block": "Berriz blokeatu erabiltzailea, parametro hauekin",
        "ipb-confirm": "Blokeoa baieztatu",
+       "ipb-sitewide": "web-orrialdea",
+       "ipb-partial": "Partzial",
+       "ipb-sitewide-help": "Wikiko edozein orrialde eta beste ekarpen ekintza guztiak",
+       "ipb-partial-help": "Orrialde edo izen-eremu zehatzak",
        "ipb-pages-label": "Orrialdeak",
        "ipb-namespaces-label": "Izen-tarteak",
        "badipaddress": "Baliogabeko IP helbidea",
        "ipb_expiry_old": "Epemuga iraganean dago.",
        "ipb_expiry_temp": "Izkutuan dauden lankide izenen blokeoa betierekikoa izan behar du.",
        "ipb_hide_invalid": "Ezin izan da kontu hau ezabatu; {{PLURAL:$1|one edit|$1 edits}} baino gehiago baiditu.",
+       "ipb_hide_partial": "Izkutuan dauden erabiltzaile blokeatuak orrialde osorako blokeatuak egon behar dute.",
        "ipb_already_blocked": "\"$1\" badago blokeatuta",
        "ipb-needreblock": "$1 dagoeneko blokeaturik dago. Ezarpenak aldatu nahi al dituzu?",
        "ipb-otherblocks-header": "Bestelako {{PLURAL:$1|blokeoa|blokeoak}}",
        "move-watch": "Orrialde hau jarraitu",
        "movepagebtn": "Mugitu orria",
        "pagemovedsub": "Mugimendua eginda",
+       "cannotmove": "Orrialdea ezin da mugitua izan hurrengo ekintzarako: {{PLURAL:$1|reason|reasons}}:",
        "movepage-moved": "'''\"$1\" \"$2\"(e)ra mugitu da'''",
        "movepage-moved-redirect": "Birbideratze orri bat sortu da.",
        "movepage-moved-noredirect": "Birbideratzea sortzeko aukera kendu da.",
        "allmessagesdefault": "Testu lehenetsia",
        "allmessagescurrent": "Oraingo testua",
        "allmessagestext": "MediaWikin erabiltzen diren mezu guztien zerrenda.\nMesedez bisitatu [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki] eta [https://translatewiki.net translatewiki.net] orrialdeak MediaWikira ekarpenak egin badituzu.",
-       "allmessagesnotsupportedDB": "Ezin da '''{{ns:special}}:Allmessages''' erabili '''$wgUseDatabaseMessages''' ezgaituta dagoelako.",
+       "allmessages-not-supported-database": "Ezin da '''{{ns:special}}:Allmessages''' erabili '''$wgUseDatabaseMessages''' ezgaituta dagoelako.",
        "allmessages-filter-legend": "Iragazi",
        "allmessages-filter": "Aldaketa-egoeraren arabera iragazi:",
        "allmessages-filter-unmodified": "Aldatugabeak",
        "pageinfo-category-files": "Fitxategi kopurua",
        "pageinfo-user-id": "Erabiltzaile IDa",
        "pageinfo-file-hash": "Hash balioa",
+       "pageinfo-view-protect-log": "Erregistro babesak ikusi orrialde honetarako",
        "markaspatrolleddiff": "Patruilatutzat markatu",
        "markaspatrolledtext": "Artikulu hau patruilatutzat markatu",
        "markaspatrolledtext-file": "Fitxategi honen bertsioa patruilatutzat markatu",
        "previousdiff": "← Aldaketa zaharragoa",
        "nextdiff": "Aldaketa berriagoa →",
        "mediawarning": "'''Oharra''': Fitxategi honek kode mingarria izan lezake.\nZure sisteman exekutatzea arriskutsua izan liteke.",
-       "imagemaxsize": "Irudiaren tamainaren muga:<br />''(fitxategia deskribatzen duten orrietarako)''",
+       "imagemaxsize": "Irudiaren tamainaren muga fitxategia deskribatzen duten orrietarako:",
        "thumbsize": "Irudi txikiaren tamaina:",
        "widthheightpage": "$1 × $2, $3 {{PLURAL:$3|orri|orri}}",
        "file-info": "fitxategiaren tamaina: $1, MIME mota: $2",
        "seconds-ago": "Orain dela {{PLURAL:$1|segundu bat|$1 segundu}}",
        "monday-at": "Astelehena $1(e)tan",
        "tuesday-at": "Asteartea $1(e)tan",
-       "wednesday-at": "Asteazkena $1(e)tan",
+       "wednesday-at": "asteazkenean (ordua: $1)",
        "thursday-at": "Osteguna $1(e)tan",
        "friday-at": "Ostirala $1(e)tan",
        "saturday-at": "Larunbata $1(e)tan",
        "confirm-unwatch-top": "Orrialde hau zure jarraipen-zerrendatik kendu?",
        "confirm-rollback-button": "Ados",
        "confirm-rollback-top": "Orrialde honen edizioak leheneratu?",
+       "confirm-rollback-bottom": "Ekintza honek orrialde honetan hautatutako aldaketak zuzenean desegingo ditu.",
+       "confirm-mcrrestore-title": "Errebisio bat berritu",
        "confirm-mcrundo-title": "Aldaketa bat desegin",
        "mcrundofailed": "Desegiteak akatsa",
        "mcrundo-missingparam": "Beharrezko eskaera parametroak falta dira.",
+       "mcrundo-changed": "Diff-a ikusi zenuen azken alditik orrialdea aldatu egin da. Mesedez, aldaketak errebisatu.",
+       "mcrundo-parse-failed": "Errebisio berriaren analisia huts egin du: $1",
        "word-separator": "&#32;",
        "quotation-marks": "«$1»",
        "imgmultipageprev": "← aurreko orrialdea",
        "redirect-file": "Fitxategiaren izena",
        "redirect-logid": "Log IDa",
        "redirect-not-exists": "Ez da baliorik aurkitu",
+       "redirect-not-numeric": "Balio ez-zenbakizkoa",
        "fileduplicatesearch": "Artxibo bikoiztuen bilaketa",
        "fileduplicatesearch-summary": "Bikoiztutako fitxategiak bilatu bere hash balioaren arabera.",
        "fileduplicatesearch-filename": "Fitxategi izena:",
        "specialpages-group-developer": "Garatzaileen tresnak",
        "blankpage": "Orrialde txuria",
        "intentionallyblankpage": "Orri hau nahita utzi da hutsik",
+       "disabledspecialpage-disabled": "Orrialde hau sistemako administratzaile batek desgaitu du.",
        "external_image_whitelist": " #Lerro hau utzi dagoen bezala<pre>\n#Jarri espresio zati erregularrak (bakarrik // artean doan zatia) azpian\n#Hauek kanpo irudien URLekin lotuko dira\n#Lotutako horiek irudi bezala agertuko dira, bestela lotura besterik ez da agertuko\n# #-arekin hasten diren lerroak iruzkin bezala hartuko dira\n# Hau case-insensitive da\n\n#Jarri regex zatiak lerro honen gainetik. Lerro hau utzi dagoen bezala</pre>",
        "tags": "Etiketa aldaketa zuzena",
        "tag-filter": "[[Special:Tags|Etiketa]] iragazkia:",
        "logentry-block-block": "$1 {{GENDER:$2|administratzaileak}} {{GENDER:$4|$3}} blokeatu du. Iraupena: $5 $6",
        "logentry-block-unblock": "$1 {{GENDER:$2|administratzaileak}} {{GENDER:$4|$3}} wikilaria desblokeatu du",
        "logentry-block-reblock": "$1 administratzaileak {{GENDER:$4|$3}} wikilariaren blokeoa {{GENDER:$2|aldatu du}}. Blokeoaldia: $5 $6",
+       "logentry-partialblock-block-page": "$2 {{PLURAL:$1|orrialdea|orrialdeak}}",
+       "logentry-partialblock-block-ns": "$2 {{PLURAL:$1|izen-eremua|izen-eremuak}}",
+       "logentry-partialblock-block": "$1 {{GENDER:$2|blokeatuta}} {{GENDER:$4|$3}} $7 ediziotik  bukaerako denbora honekin $5 $6",
        "logentry-suppress-block": "$1 {{GENDER:$2|administratzaileak}} {{GENDER:$4|$3}} blokeatu du. Iraupena: $5 $6",
        "logentry-suppress-reblock": "$1 administratzaileak {{GENDER:$4|$3}} wikilariaren blokeoa {{GENDER:$2|aldatu du}}. Blokeoaldia: $5 $6",
        "logentry-import-upload": "$1(e)k $3 {{GENDER:$2|inportatu du}} fitxategi-igoera bidez",
        "logentry-rights-autopromote": "$1 automatikoki $4tik $5ra  {{GENDER:$2|igo}} egin zaio",
        "logentry-upload-upload": "$1(e)k $3 {{GENDER:$2|igo du}}",
        "logentry-upload-overwrite": "$1(e)k $3(r)en bertsio berria {{GENDER:$2|igo du}}",
-       "logentry-upload-revert": "$1(e)k $3 {{GENDER:$2|igo du}}",
+       "logentry-upload-revert": "$1(e)k $3 bertsio zahar batera {{GENDER:$2|itzuli du}}",
        "log-name-managetags": "Etiketa kudeatze erregistroa",
        "log-description-managetags": "Orrialde honetan [[Special:Tags|etiketekin]] lotutako kudeaketa-zereginak zerrendatzen dira. Saioak administratzaileak eskuz egiten dituen ekintzak soilik ditu; Wiki softwarerrarekin etiketak sortu edo ezabatzeko ahalmenarekin erregistro honetan erregistratutako sarrerarik gabe.",
        "logentry-managetags-create": "$1 lankideak \"$4\" etiketa {{GENDER:$2|sortu du}}",
        "passwordpolicies-policy-passwordcannotmatchusername": "Pasahitza ezin da erabiltzaile izenaren berdina izan",
        "passwordpolicies-policy-passwordcannotmatchblacklist": "Pasahitza ezin da zerrenda beltzean zehaztutakoren bat izan",
        "passwordpolicies-policy-maximalpasswordlength": "Pasahitza ezin da {{PLURAL:$1|karaktere $1|$1 karaktere}} baino luzeagoa izan",
-       "passwordpolicies-policy-passwordcannotbepopular": "Pasahitza ezin da {{PLURAL:$1|pasahitz erabiliena izan|$1 pasahitz erabilienen zerrendan egon}}"
+       "passwordpolicies-policy-passwordcannotbepopular": "Pasahitza ezin da {{PLURAL:$1|pasahitz erabiliena izan|$1 pasahitz erabilienen zerrendan egon}}",
+       "passwordpolicies-policy-passwordnotinlargeblacklist": "Pasahitza ezin da egon\"100.000 pasahitz erabilien\" listan.",
+       "passwordpolicies-policyflag-forcechange": "Saioa hastean aldatzea derrigorrezkoa",
+       "passwordpolicies-policyflag-suggestchangeonlogin": "Aholkuak saioa hastean aldatu",
+       "unprotected-js": "Segurtasun arrazoiengatik JavaScript ezin da babesik gabeko orrialdetan kargatu. Soilik MediaWiki atal hauetan erabili JavaScript: Izen-eremuak edo erabiltzaile orrialdetan"
 }
index ae49993..fad6f20 100644 (file)
@@ -2,7 +2,8 @@
        "@metadata": {
                "authors": [
                        "Esbardu",
-                       "Xuacu"
+                       "Xuacu",
+                       "Enolp"
                ]
        },
        "exif-imagewidth": "Anchor",
@@ -29,7 +30,7 @@
        "exif-datetime": "Data y hora de cambiu del ficheru",
        "exif-imagedescription": "Títulu de la imaxe",
        "exif-make": "Fabricante de la cámara",
-       "exif-model": "Modelu de cámara",
+       "exif-model": "Modelu de la cámara",
        "exif-software": "Software usáu",
        "exif-artist": "Autor",
        "exif-copyright": "Titular del Copyright",
@@ -63,6 +64,7 @@
        "exif-lightsource": "Fonte de la lluz",
        "exif-flash": "Flax",
        "exif-focallength": "Llonxitú focal de la lente",
+       "exif-focallength-format": "$1 mm",
        "exif-subjectarea": "Área del suxetu",
        "exif-flashenergy": "Enerxía del flax",
        "exif-focalplanexresolution": "Resolución X del planu focal",
@@ -89,7 +91,7 @@
        "exif-gpsversionid": "Versión de la etiqueta GPS",
        "exif-gpslatituderef": "Llatitú Norte o Sur",
        "exif-gpslatitude": "Llatitú",
-       "exif-gpslongituderef": "Llonxitú Este o Oeste",
+       "exif-gpslongituderef": "Llonxitú este u oeste",
        "exif-gpslongitude": "Llonxitú",
        "exif-gpsaltituderef": "Referencia d'altitú",
        "exif-gpsaltitude": "Altitú",
        "exif-compression-6": "JPEG (antiguu)",
        "exif-copyrighted-true": "Con drechos d'autor",
        "exif-copyrighted-false": "Drechos d'autor ensin configurar",
+       "exif-photometricinterpretation-0": "Blancu y prietu (El prietu ye 0)",
        "exif-photometricinterpretation-1": "Blancu y prietu (El prietu ye 0)",
+       "exif-photometricinterpretation-3": "Paleta",
+       "exif-photometricinterpretation-4": "Mázcara de tresparencia",
+       "exif-photometricinterpretation-5": "Separaos (Probablemente CMYK)",
+       "exif-photometricinterpretation-8": "CIE L*a*b*",
+       "exif-photometricinterpretation-9": "CIE L*a*b* (codificación ICC)",
+       "exif-photometricinterpretation-10": "CIE L*a*b* (codificación ITU)",
        "exif-unknowndate": "Fecha desconocida",
        "exif-orientation-1": "Normal",
        "exif-orientation-2": "Voltiada horizontalmente",
index bbe1483..72b8e6c 100644 (file)
        "exif-imagedescription": "Judul gambar",
        "exif-make": "Pabrikan kudakan",
        "exif-model": "Mudil kudakan",
-       "exif-software": "Parangkat lunak dipuruk",
+       "exif-software": "Parangkat lunak",
        "exif-artist": "Pa-ulah",
        "exif-copyright": "Pamingkut hak-rekap",
-       "exif-exifversion": "Parsi Exif",
+       "exif-exifversion": "rsi Exif",
        "exif-flashpixversion": "Manyukung parsi Flashpix",
        "exif-colorspace": "Kamar kalir",
        "exif-componentsconfiguration": "Arti matan tiap kumpunin",
        "exif-compressedbitsperpixel": "Muda kumprasi gambar",
        "exif-pixelxdimension": "Lingai gambar",
        "exif-pixelydimension": "Pancau gambar",
-       "exif-usercomment": "Kumintar pamuruk",
+       "exif-usercomment": "Kumintar pamakai",
        "exif-relatedsoundfile": "Barkas suara bahubung",
        "exif-datetimeoriginal": "Tanggal wan wayah paulahan data",
        "exif-datetimedigitized": "Tanggal wan wayah digitalisasi",
index 03fc793..f09c093 100644 (file)
        "exif-gpsdifferential": "GPS differential correction",
        "exif-coordinate-format": "$1° $2′ $3″ $4",
        "exif-jpegfilecomment": "Vatışê dosyada JPEG'i",
-       "exif-keywords": "Qesa kelimey",
+       "exif-keywords": "Çekuyên kıliti",
        "exif-worldregioncreated": "Mıntıqaya dınyaya ke tede resım gêriyayayo",
        "exif-countrycreated": "Dewleta ke tede resım gêriyayayo",
        "exif-countrycodecreated": "Kodê dewleta ke tede resım anciyayo",
        "exif-compression-32773": "PackBits (Macintosh RLE)",
        "exif-compression-32946": "Deflate (PKZIP)",
        "exif-compression-34712": "JPEG2000",
-       "exif-copyrighted-true": "Heqê telifiye",
+       "exif-copyrighted-true": "Heqa telifi",
        "exif-copyrighted-false": "Telifiya waziyeta eyara",
        "exif-photometricinterpretation-0": "Siya u Sıpe (Sıpe 0 o)",
        "exif-photometricinterpretation-1": "Siya u sıpê (Siya 0)",
index 09c1772..4fd895c 100644 (file)
@@ -8,7 +8,8 @@
                        "Robin van der Vliet",
                        "Tlustulimu",
                        "Yekrats",
-                       "YvesNevelsteen"
+                       "YvesNevelsteen",
+                       "Mirin"
                ]
        },
        "exif-imagewidth": "Larĝeco",
        "exif-compression-8": "Malŝveli (Adobe)",
        "exif-copyrighted-true": "Sub aŭtorrajto",
        "exif-copyrighted-false": "Sub publika domajno",
+       "exif-photometricinterpretation-0": "Nigra-blanka (blanko estas 0)",
        "exif-photometricinterpretation-1": "Nigra kaj blanka (nigra estas 0)",
+       "exif-photometricinterpretation-3": "Paletro",
+       "exif-photometricinterpretation-4": "Masko de travideblo",
+       "exif-photometricinterpretation-5": "Apartigita (Verŝajne Cejanblua-Fuksina-Flava-Nigra)",
+       "exif-photometricinterpretation-8": "CIE L*a*b*",
+       "exif-photometricinterpretation-9": "CIE L*a*b* (laŭ enkodigo de ICC)",
+       "exif-photometricinterpretation-10": "CIE L*a*b* (laŭ enkodigo de ITU)",
        "exif-unknowndate": "Nekonata dato",
        "exif-orientation-1": "Normala",
        "exif-orientation-2": "Spegulumita horizontale",
index 13454d1..9c4c047 100644 (file)
@@ -4,7 +4,8 @@
                        "Ebraminio",
                        "Huji",
                        "Meisam",
-                       "ZxxZxxZ"
+                       "ZxxZxxZ",
+                       "Reza1615"
                ]
        },
        "exif-imagewidth": "عرض",
@@ -52,6 +53,7 @@
        "exif-exposuretime": "زمان نوردهی",
        "exif-exposuretime-format": "$1 ثانیه ($2)",
        "exif-fnumber": "ضریب اف",
+       "exif-fnumber-format": "f/$1",
        "exif-exposureprogram": "برنامهٔ نوردهی",
        "exif-spectralsensitivity": "حساسیت طیفی",
        "exif-isospeedratings": "درجه‌بندی سرعت ایزو",
        "exif-compression-4": "رمزگذاری نمابر سی‌سی‌آی‌تی‌تی گروه ۴",
        "exif-copyrighted-true": "دارای حق تکثیر",
        "exif-copyrighted-false": "وضعیت حق‌تکثیر تعیین نشده است",
+       "exif-photometricinterpretation-0": "سیاه و سفید (سفید ۰ است)",
        "exif-photometricinterpretation-1": "سیاه و سفید (سیاه ۰ است)",
+       "exif-photometricinterpretation-3": "پالت",
+       "exif-photometricinterpretation-4": "شفافیت پوشش",
+       "exif-photometricinterpretation-5": "جداشده (احتمالاُ CMYK)",
+       "exif-photometricinterpretation-8": "CIE L*a*b*",
+       "exif-photometricinterpretation-9": "CIE L*a*b* (رمزنگاری ICC)",
+       "exif-photometricinterpretation-10": "CIE L*a*b* (رمزنگاری ITU)",
        "exif-unknowndate": "تاریخ نامعلوم",
        "exif-orientation-1": "عادی",
        "exif-orientation-2": "افقی پشت و روشده",
index 67bb561..f7c9141 100644 (file)
        "exif-compression-4": "CCITT Grupa 4 faks kodiranje",
        "exif-copyrighted-true": "Zaštićeno autorskim pravom",
        "exif-copyrighted-false": "Status autorskih prava nije postavljen",
+       "exif-photometricinterpretation-0": "Crno-bijelo (bijela je 0)",
        "exif-photometricinterpretation-1": "Crno-bijelo (crna je 0)",
+       "exif-photometricinterpretation-3": "Paleta",
+       "exif-photometricinterpretation-4": "Maska prozirnosti",
+       "exif-photometricinterpretation-5": "Separirano (vjerojatno CMYK)",
+       "exif-photometricinterpretation-8": "CIE L*a*b*",
+       "exif-photometricinterpretation-9": "CIE L*a*b* (ICC kodiranje)",
+       "exif-photometricinterpretation-10": "CIE L*a*b* (ITU kodiranje)",
        "exif-unknowndate": "nepoznat datum",
        "exif-orientation-1": "Normalno",
        "exif-orientation-2": "Zrcaljeno po horizontali",
index 9ba8e44..a323e26 100644 (file)
        "exif-compression-6": "JPEG (vecchio)",
        "exif-copyrighted-true": "Protetto da copyright",
        "exif-copyrighted-false": "Status del copyright non impostato",
+       "exif-photometricinterpretation-0": "Bianco e nero (bianco è 0)",
        "exif-photometricinterpretation-1": "Bianco e nero (nero è 0)",
+       "exif-photometricinterpretation-3": "Tavolozza",
+       "exif-photometricinterpretation-4": "Maschera di trasparenza",
+       "exif-photometricinterpretation-5": "Separato (probabilmente CMYK)",
+       "exif-photometricinterpretation-8": "CIE L*a*b*",
+       "exif-photometricinterpretation-9": "CIE L*a*b* (codifica ICC)",
+       "exif-photometricinterpretation-10": "CIE L*a*b* (codifica ITU)",
        "exif-unknowndate": "Data sconosciuta",
        "exif-orientation-1": "Normale",
        "exif-orientation-2": "Capovolto orizzontalmente",
index 0c5ed54..353ad9c 100644 (file)
        "exif-compression-34712": "JPEG2000",
        "exif-copyrighted-true": "著作権あり",
        "exif-copyrighted-false": "著作権情報未設定",
-       "exif-photometricinterpretation-0": "黒と白(白が0です)",
+       "exif-photometricinterpretation-0": "黒と白(白が0)",
        "exif-photometricinterpretation-1": "黒と白(黒が0)",
        "exif-photometricinterpretation-2": "RGB",
-       "exif-photometricinterpretation-3": "Palette",
-       "exif-photometricinterpretation-5": "Separated (Probably CMYK)",
+       "exif-photometricinterpretation-3": "パレット",
+       "exif-photometricinterpretation-4": "透明マスク",
+       "exif-photometricinterpretation-5": "分版 (おそらく CMYK)",
        "exif-photometricinterpretation-6": "YCbCr",
        "exif-photometricinterpretation-8": "CIE L*a*b*",
        "exif-photometricinterpretation-9": "CIE L*a*b* (ICC エンコード)",
index c777d92..d2c0a33 100644 (file)
        "exif-exposureprogram-2": "Program normal",
        "exif-exposureprogram-3": "Prioritas diafragma",
        "exif-exposureprogram-4": "Prioritas panutup",
-       "exif-exposureprogram-5": "Program kréatif (condong menyang jroning bilik (''depth of field''))",
+       "exif-exposureprogram-5": "Program cipta (condhong marang jeroning babagan)",
        "exif-exposureprogram-6": "Program aksi (condhong marang kacepetan rana)",
        "exif-exposureprogram-7": "Modus potret (kanggo foto ''closeup'' mawa latar wuri ora fokus)",
        "exif-exposureprogram-8": "Modus pamandhangan (''landscape'') (kanggo foto pamandhangan mawa latar wuri fokus)",
index 8b02c4a..f124df2 100644 (file)
@@ -7,7 +7,8 @@
                        "Klutzy",
                        "Kwj2772",
                        "Mooozi",
-                       "아라"
+                       "아라",
+                       "Revi"
                ]
        },
        "exif-imagewidth": "너비",
        "exif-photometricinterpretation-3": "팔레트",
        "exif-photometricinterpretation-4": "투명 마스크",
        "exif-photometricinterpretation-5": "분리 (아마도 CMYK)",
+       "exif-photometricinterpretation-8": "CIE L*a*b*",
        "exif-photometricinterpretation-9": "CIE L*a*b* (ICC 인코딩)",
        "exif-photometricinterpretation-10": "CIE L*a*b* (ITU 인코딩)",
        "exif-photometricinterpretation-32803": "컬러 필터 어레이",
index bcd7ca4..2b8491a 100644 (file)
@@ -78,7 +78,7 @@
        "exif-exposuremode": "Beliichtungsmodus",
        "exif-whitebalance": "Wäissofgläich",
        "exif-digitalzoomratio": "Digitalzoom",
-       "exif-focallengthin35mmfilm": "Brennwäit (Klengbildäquivalent)",
+       "exif-focallengthin35mmfilm": "Brennwäit (Klengbildequivalenz)",
        "exif-scenecapturetype": "Aart vun der Opnam",
        "exif-gaincontrol": "Verstäerkung",
        "exif-contrast": "Kontrast",
index 4c19e31..43c77e8 100644 (file)
        "exif-writer": "نیسنه",
        "exif-languagecode": "زون",
        "exif-iimversion": "نسقه آی آی ام",
-       "exif-iimcategory": "دسه",
+       "exif-iimcategory": "دٱسٱ",
        "exif-iimsupplementalcategory": "دسه یا اضافی",
        "exif-datetimeexpires": "وا نها دش استفاده نبوئه",
        "exif-datetimereleased": "ول بیه د",
index 5253e8d..89a5d4b 100644 (file)
        "exif-gpsspeed-n": "Јазли",
        "exif-gpsdestdistance-k": "Километри",
        "exif-gpsdestdistance-m": "Милји",
-       "exif-gpsdestdistance-n": "Ð\9dаÑ\83Ñ\82иÑ\87ки милји",
+       "exif-gpsdestdistance-n": "Ð\9cоÑ\80Ñ\81ки милји",
        "exif-gpsdop-excellent": "Одлична ($1)",
        "exif-gpsdop-good": "Добра ($1)",
        "exif-gpsdop-moderate": "Умерена ($1)",
index b0ad6c0..e3839a7 100644 (file)
        "exif-compression-4": "CCITT Group 4, факс куодтааһына",
        "exif-copyrighted-true": "Ааптар быраабынан араҥаччыланар",
        "exif-copyrighted-false": "Бас билиитэ чопчуламматах",
+       "exif-photometricinterpretation-0": "Хара уонна маҥан (маҥан - 0).",
        "exif-photometricinterpretation-1": "Хара уонна маҥан (хара - 0).",
+       "exif-photometricinterpretation-3": "Өҥ палитрата",
+       "exif-photometricinterpretation-4": "Дьэҥкир мааска",
+       "exif-photometricinterpretation-5": "Хайытыллыбыт (арааһа CMYK)",
+       "exif-photometricinterpretation-8": "CIE L*a*b*",
+       "exif-photometricinterpretation-9": "CIE L*a*b* (ICC-кодирование)",
+       "exif-photometricinterpretation-10": "CIE L*a*b* (ITU-кодирование)",
        "exif-unknowndate": "Күнэ-ыйа биллибэт",
        "exif-orientation-1": "Нуорма",
        "exif-orientation-2": "Сытыары көстүбүт",
index cc10dd9..a00befb 100644 (file)
        "exif-gpsspeedref": "వేగపు కొలమానం",
        "exif-gpsspeed": "GPS రిసీవరు వేగం",
        "exif-gpstrackref": "కదలిక దిశ కోసం మూలం",
-       "exif-gpstrack": "à°\95దలిà°\95 à°¯à±\8aà°\95à±\8dà°\95 à°¦à°¿à°¶",
+       "exif-gpstrack": "కదలిక దిశ",
        "exif-gpsimgdirectionref": "బొమ్మ దిశ కోసం మూలం",
-       "exif-gpsimgdirection": "à°¬à±\8aà°®à±\8dà°® à°¯à±\8aà°\95à±\8dà°\95 à°¦à°¿à°¶",
+       "exif-gpsimgdirection": "బొమ్మ దిశ",
        "exif-gpsmapdatum": "వాడిన జియోడెటిక్ సర్వే డేటా",
        "exif-gpsdestlatituderef": "గమ్యస్థాన రేఖాంశం కోసం మూలం",
-       "exif-gpsdestlatitude": "à°\97à°®à±\8dయసà±\8dథానà°\82 à°¯à±\8aà°\95à±\8dà°\95 అక్షాంశం",
+       "exif-gpsdestlatitude": "à°\97à°®à±\8dయసà±\8dథానపà±\81 అక్షాంశం",
        "exif-gpsdestlongituderef": "గమ్యస్థాన అక్షాంశం కోసం మూలం",
-       "exif-gpsdestlongitude": "à°\97à°®à±\8dయసà±\8dథానà°\82 à°¯à±\8aà°\95à±\8dà°\95 రేఖాంశం",
+       "exif-gpsdestlongitude": "à°\97à°®à±\8dయసà±\8dథానపà±\81 రేఖాంశం",
        "exif-gpsdestbearingref": "గమ్యస్థాన బేరింగు కోసం మూలం",
        "exif-gpsdestbearing": "గమ్యస్థానం బేరింగు",
        "exif-gpsdestdistanceref": "గమ్యస్థానానీ ఉన్న దూరం కోసం మూలం",
        "exif-dc-relation": "సంబంధిత మీడియా",
        "exif-dc-rights": "హక్కులు",
        "exif-dc-source": "మీడియా మూలము",
-       "exif-dc-type": "à°®à±\80డియా à°¯à±\8aà°\95à±\8dà°\95 à°°à°\95à°®à±\81",
+       "exif-dc-type": "మాధà±\8dయమ à°°à°\95à°\82",
        "exif-rating-rejected": "తిరస్కరించబడింది",
        "exif-isospeedratings-overflow": "65535 కంటే ఎక్కువ",
        "exif-iimcategory-ace": "కళలు, సంస్కృతి, వినోదం",
index 28ea042..015a1fb 100644 (file)
        "minoreditletter": "c",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|usuáriu está|usuárius están}} vehilandu]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} dempués el chambu",
        "newsectionsummary": "/* $1 */ seción nueva",
        "rc-enhanced-expand": "muestral detallis (es mestel JavaScript)",
        "allmessagesdefault": "Testu pol defeutu",
        "allmessagescurrent": "Testu atual",
        "allmessagestext": "Esta es una lista e mensahis del sistema disponibris nel espaciu e nombris MediaWiki:\nPol favol, vesita [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] i [https://translatewiki.net translatewiki.net] si quieis colabutal.",
-       "allmessagesnotsupportedDB": "Nu se puei gastal esta páhina polque '''$wgUseDatabaseMessages''' está desativau.",
+       "allmessages-not-supported-database": "Nu se puei gastal esta páhina polque '''$wgUseDatabaseMessages''' está desativau.",
        "thumbnail-more": "Agrandal",
        "filemissing": "Archivu escambulliu",
        "thumbnail_error": "Marru criandu cuairu: $1",
index c386ee2..12f9368 100644 (file)
@@ -72,7 +72,9 @@
                        "Physicsch",
                        "Nbi",
                        "Amjad Khan",
-                       "Ahmad252"
+                       "Ahmad252",
+                       "FarsiNevis",
+                       "Moyogo"
                ]
        },
        "tog-underline": "خط کشیدن زیر پیوندها:",
        "tog-norollbackdiff": "بعد از واگردانی، تفاوت نشان داده نشود",
        "tog-useeditwarning": "زمان خروج از صفحهٔ ویرایش در صورت داشتن ویرایش‌های‌ ذخیره‌نشده به من هشدار داده شود",
        "tog-prefershttps": "هنگامی که به سامانه وارد شده‌ام، همواره از اتصال امن استفاده شود",
+       "tog-showrollbackconfirmation": "نمایش یک هشدار در هنگام کلیک بر دکمه واگردانی",
        "underline-always": "همیشه",
        "underline-never": "هرگز",
        "underline-default": "پیش‌فرض پوسته یا مرورگر",
        "returnto": "بازگشت به $1.",
        "tagline": "از {{SITENAME}}",
        "help": "راهنما",
+       "help-mediawiki": "راهنما درباره مدیاویکی",
        "search": "جستجو",
        "search-ignored-headings": "#<!-- این صفحه را درست همانطور که هست رها کنید --> <pre>\n# سر‌فصل‌هایی که توسط جستجو نادیده گرفته خواهندشد.‌\n# تأثیر تغییرات زمانی رخ می‌دهد که صفحهٔ حاوی آن سرفصل، نمایه شود.\n# شما می‌توانید با انجام یک ویرایش پوچ صفحه را وادار به دوباره نمایه‌شدن کنید.\n# نحو به شرح زیر است:\n#  *هر چه از یک نویسهٔ «#» تا آخر خط بیاید، یک توضیح است.\n#  *هر خط بدون فاصله، دقیقاً عنوانی است که نادیده گرفته می‌شود (با رعایت بزرگی و کوچکی حروف).\nمنابع\nپیوند به بیرون\nهمچنین ببینید\n#</pre> <!-- leave this line exactly as it is -->",
        "searchbutton": "جستجو",
        "badretype": "گذرواژه‌هایی که وارد کرده‌اید یکسان نیستند.",
        "usernameinprogress": "ایجاد حساب برای این نام کاربر در جریان است. لطفا صبور باشید.",
        "userexists": "نام کاربری‌ای که وارد کردید قبلاً استفاده شده‌است.\nلطفاً یک نام دیگر انتخاب کنید.",
+       "createacct-normalization": "نام کاربری شما به دلایل فنی به «$2» تبدیل خواهد شد.",
        "loginerror": "خطا در ورود به سامانه",
        "createacct-error": "خطای ایجاد حساب کاربری",
        "createaccounterror": "امکان ساختن این حساب وجود ندارد: $1",
        "resetpass-abort-generic": "تغییر گذرواژه به دست یکی از افزونه‌ها لغو شده است.",
        "resetpass-expired": "رمز عبور شما منقضی شده‌است. لطفاً برای ورود رمز عبور جدیدی را تنظیم کنید.",
        "resetpass-expired-soft": "رمز عبور شما منقضی شده‌است و نیاز به تغییر دارد. لطفاً اکنون رمز عبور جدیدی را انتخاب کنید، یا برای تغییر آن در آینده، دکمهٔ «{{int:authprovider-resetpass-skip-label}}» را کلیک کنید.",
-       "resetpass-validity": "لطفا برای ورود گذرواژه جدیدی را انتخاب کنید",
+       "resetpass-validity": "گذرواژه شما معتبر نیست: $1\n\nلطفا برای ورود گذرواژه جدیدی را انتخاب کنید.",
        "resetpass-validity-soft": "گذرواهٔ شما صحیح نیست: $1\n\nلطفاً یک گذرواژهٔ تازه الآن انتخاب کنید یا بر «{{int:authprovider-resetpass-skip-label}}» کلیک کنید که دوباره آن را بعداً تغییر دهید.",
        "passwordreset": "بازنشانی گذرواژه",
        "passwordreset-text-one": "برای بازنشانی گذرواژه‌تان این فرم را کامل کنید.",
        "subject-preview": "پیش‌نمایش موضوع:",
        "previewerrortext": "در زمان تلاش برای نمایش دادن تغییرات شما، خطایی رخ داد.",
        "blockedtitle": "کاربر بسته شده‌است",
-       "blockedtext-partial": "<strong>حساب کاربری یا آدرس آی‌پی شما از انجام تغییرات در این صفحه منع شده‌است. شما همچنان می‌توانید در دیگر صفحه‌های این ویکی ویرایش کنید.</strong> برای مشاهده جزئیات کامل قطع دسترسی به [[ویژه:مشارکت‌های من|مشارکت‌های حساب]] مراجعه کنید.\n\nاین قطع دسترسی توسط $1 انجام گرفته‌است.\n\nدلیل قطع دسترسی <em>$2</em> است.\n\n* زمان آغاز قطع دسترسی: $8\n* زمان پایان قطع دسترسی: $6\n* موارد مورد نظر: $7\n* شناسه قطع دسترسی: #$5",
+       "blocked-email-user": "<strong>دسترسی حساب کاربری شما از ارسال ایمیل قطع شده است. شما همچنان می‌توانید سایر صفحات این ویکی را ویرایش کنید.</strong>می‌توانید جزئیات کامل قطع دسترسی را در [[Special:MyContributions|مشارکت‌های حساب]] ببینید.\n\nقطع دسترسی توسط $1 انجام شده است.\n\nدلیل داده‌شده <em>$2</em> بوده است.\n\n* شروع قطع دسترسی: $8\n* اتمام قطع دسترسی: $6\n* هدف قطع دسترسی: $7\n* شناسه قطع دسترسی #$5",
+       "blockedtext-partial": "<strong>حساب کاربری یا آدرس آی‌پی شما از انجام تغییرات در این صفحه منع شده‌است. شما همچنان می‌توانید در دیگر صفحه‌های این ویکی ویرایش کنید.</strong> برای مشاهده جزئیات کامل قطع دسترسی به [[Special:MyContributions|مشارکت‌های حساب]] مراجعه کنید.\n\nاین قطع دسترسی توسط $1 انجام گرفته‌است.\n\nدلیل قطع دسترسی <em>$2</em> است.\n\n* زمان آغاز قطع دسترسی: $8\n* زمان پایان قطع دسترسی: $6\n* موارد مورد نظر: $7\n* شناسه قطع دسترسی: #$5",
        "blockedtext": "<strong>دسترسی حساب کاربری یا نشانی آی‌پی شما بسته شده‌است.</strong>\n\nاین قطع دسترسی توسط $1 انجام شده است.\nدلیل ارائه‌شده چنین است: <em>$2</em>\n\n* شروع قطع دسترسی: $8\n* پایان قطع دسترسی: $6\n* کاربری هدف قطع دسترسی: $7\n\nشما می‌توانید با $1 یا [[{{MediaWiki:Grouppage-sysop}}|مدیری]] دیگر تماس بگیرید و در این باره صحبت کنید.\nتوجه کنید که شما نمی‌توانید از قابلیت «{{int:emailuser}}» استفاده کنید مگر آنکه آدرس ایمیل معتبری در [[Special:Preferences|ترجیحات کاربری]] خودتان ثبت کرده باشید و نیز باید امکان استفاده از این قابلیت برای شما قطع نشده باشد.\nنشانی آی‌پی فعلی شما $3 و شمارهٔ قطع دسترسی شما $5 است.\nلطفاً تمامی جزئیات فوق را در کلیهٔ درخواست‌هایی که در این باره مطرح می‌کنید ذکر کنید.",
        "autoblockedtext": "دسترسی نشانی آی‌پی شما قطع شده‌است، زیرا این نشانی آی‌پی توسط کاربر دیگری استفاده شده که دسترسی او توسط $1 قطع شده‌است.\nدلیل ارائه‌شده چنین است:\n\n:''$2''\n\n* شروع قطع دسترسی: $8\n* پایان قطع دسترسی: $6\n* کاربری هدف قطع دسترسی: $7\n\nشما می‌توانید با $1 یا [[{{MediaWiki:Grouppage-sysop}}|مدیری]] دیگر تماس بگیرید و در این باره صحبت کنید.\nتوجه کنید که شما نمی‌توانید از قابلیت «{{int:emailuser}}» استفاده کنید مگر آنکه نشانی ایمیل معتبری در [[Special:Preferences|ترجیحات کاربری]] خودتان ثبت کرده باشید و نیز باید امکان استفاده از این قابلیت برای شما قطع نشده باشد.\nنشانی آی‌پی فعلی شما $3 و شمارهٔ قطع دسترسی شما $5 است.\nلطفاً تمامی جزئیات فوق را در کلیهٔ درخواست‌هایی که در این باره مطرح می‌کنید ذکر کنید.",
        "systemblockedtext": "نام کاربری یا نشانی آی‌پی شما خودکار توسط مدیاویکی مسدود شده‌است.\nدلیل ارائه‌شده:\n\n:<em>$2</em>\n\n* آغاز بلاک: $8\n* پایان بلاک: $6\n* قطع دسترسی‌شده مورد نظر: $7\n\nنشانی آی‌پی کنونی شما $3 است.\nخواهشمند است تمام جزئیات بالا را در هر پرس‌وجویی که انجام می‌دهید قرار دهید.",
        "accmailtext": "یک گذرواژهٔ تصادفی برای [[User talk:$1|$1]] به $2 فرستاده شد. می‌توان آن را از صفحهٔ ''[[Special:ChangePassword|تغییر گذرواژه]]'' که هنگام ثبت ورود نمایش می‌یابد تغییر داد.",
        "newarticle": "(تازه)",
        "newarticletext": "شما پیوندی را دنبال کرده‌اید و به صفحه‌ای رسیده‌اید که هنوز وجود ندارد.\nبرای ایجاد صفحه، در مستطیل زیر شروع به نوشتن کنید (برای اطلاعات بیشتر به [$1 صفحهٔ راهنما] مراجعه کنید).\nاگر به اشتباه اینجا آمده‌اید، دکمهٔ «بازگشت» مرورگرتان را بزنید.",
-       "anontalkpagetext": "----<em>این صفحهٔ بحث برای کاربر گمنامی است که هنوز حسابی درست نکرده است یا از آن استفاده نمی‌کند.\nبنا بر این برای شناسایی‌اش مجبوریم از نشانی آی‌پی عددی استفاده کنیم.</em>\nچنین نشانی‌های آی‌پی ممکن است توسط چندین کاربر به شکل مشترک استفاده شود.\nاگر شما کاربر گمنامی هستید و تصور می‌کنید اظهار نظرات نامربوط به شما صورت گرفته است، لطفاً برای پیشگیری از اشتباه گرفته شدن با کاربران گمنام دیگر در آینده [[Special:CreateAccount|حسابی ایجاد کنید]] یا [[Special:UserLogin|به سامانه وارد شوید]].",
+       "anontalkpagetext": "----<em>این صفحهٔ بحث برای کاربر گمنامی است که هنوز حسابی درست نکرده است یا از آن استفاده نمی‌کند.\nبنا بر این برای شناسایی‌اش مجبوریم از نشانی آی‌پی عددی استفاده کنیم.</em> \nچنین نشانی‌های آی‌پی ممکن است توسط چندین کاربر به شکل مشترک استفاده شود.\nاگر شما کاربر گمنامی هستید و تصور می‌کنید اظهار نظرات نامربوط به شما صورت گرفته است، لطفاً برای پیشگیری از اشتباه گرفته شدن با کاربران گمنام دیگر در آینده [[Special:CreateAccount|حسابی ایجاد کنید]] یا [[Special:UserLogin|به سامانه وارد شوید]].",
        "noarticletext": "این صفحه هم‌اکنون دارای هیچ متنی نیست.\nشما می‌توانید در صفحه‌های دیگر [[Special:Search/{{PAGENAME}}|عنوان این صفحه را جستجو کنید]]،\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} سیاهه‌های مرتبط را جستجو کنید]،\nیا [{{fullurl:{{FULLPAGENAME}}|action=edit}} این صفحه را ایجاد کنید]</span>.",
        "noarticletext-nopermission": "این صفحه هم‌اکنون متنی ندارد.\nشما می‌توانید در دیگر صفحات [[Special:Search/{{PAGENAME}}|این عنوان را جستجو کنید]]،\nیا <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} سیاهه‌های مرتبط را بگردید]</span> ولی شما اجازه ایجاد این صفحه را ندارید.",
        "missing-revision": "ویرایش #$1 از صفحهٔ «{{FULLPAGENAME}}» موجود نیست.\n\nاین اتفاق معمولاً در اثر دنبال کردن پیوندی به تاریخچهٔ یک صفحهٔ حذف‌شده پیش می‌آید.\nمی‌توانید جزئیات بیشتر را در [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سیاههٔ حذف] بیابید.",
        "edit-gone-missing": "امکان به‌روز کردن صفحه وجود ندارد.\nبه نظرمی‌رسد که صفحه حذف شده باشد.",
        "edit-conflict": "تعارض ویرایشی.",
        "edit-no-change": "ویرایش شما نادیده گرفته شد، زیرا تغییری در متن داده نشده بود.",
+       "edit-slots-cannot-add": "این {{PLURAL:$1|اسلات|اسلات‌ها}} پشتیبانی نمی‌شود: $2.",
+       "edit-slots-cannot-remove": "امکان حذف این {{PLURAL:$1|اسلات|اسلات‌ها}} وجود ندارد: $2.",
+       "edit-slots-missing": "این {{PLURAL:$1|اسلات|اسلات‌ها}} ناموجود است: $2.",
        "postedit-confirmation-created": "صفحه ایجاد شده است.",
        "postedit-confirmation-restored": "صفحه بازیابی شده است.",
        "postedit-confirmation-saved": "ویرایش شما ذخیره شد.",
        "defaultmessagetext": "متن پیش‌فرض پیغام",
        "content-failed-to-parse": "عدم موفقیت در تجزیه محتوای $2 برای مدل $1: $3",
        "invalid-content-data": "داده محتوای نامعتبر",
-       "content-not-allowed-here": "محتوای «$1» در صفحهٔ [[:$2]] مجاز نیست",
+       "content-not-allowed-here": "محتوای «$1» در صفحهٔ [[:$2]] بخش «$3» مجاز نیست",
        "editwarning-warning": "خروج از این صفحه ممکن است باعث شود که شما هر شانسی که به وجود آورده‌اید را از دست بدهید.\nاگر شما وارد سامانه شده‌اید، می‌توانید این هشدار را در بخش «{{int:prefs-editing}}» ترجیحاتتان غیرفعال کنید.",
        "editpage-invalidcontentmodel-title": "مدل محتوای پشتیبانی نشده",
        "editpage-invalidcontentmodel-text": "مدل محتوای «$1» پشتیبای نمی‌شود.",
        "page_first": "نخست",
        "page_last": "واپسین",
        "histlegend": "انتخاب تفاوت: دکمه‌های گرد کنار ویرایش‌هایی که می‌خواهید با هم مقایسه کنید را علامت بزنید و دکمهٔ Enter را بزنید یا دکمهٔ پایین را فشار دهید.<br />\nاختصارات: '''({{int:cur}})''' = تفاوت با نسخهٔ فعلی، '''({{int:last}})''' = تفاوت با نسخهٔ قبلی، '''({{int:minoreditletter}})''' = ویرایش جزئی.",
-       "history-fieldset-title": "جستجو برای نسخه‌ها",
+       "history-fieldset-title": "فیلتر کردن نسخه‌ها",
        "history-show-deleted": "فقط نسخه‌های حذف شده",
        "histfirst": "قدیمی‌ترین",
        "histlast": "جدیدترین",
        "historysize": "({{PLURAL:$1|۱ بایت|$1 بایت}})",
-       "historyempty": "(خالی)",
+       "historyempty": "خالی",
        "history-feed-title": "تاریخچهٔ ویرایش‌ها",
        "history-feed-description": "تاریخچهٔ ویرایش‌های این صفحه در ویکی",
        "history-feed-item-nocomment": "$1 در $2",
        "prefs-displayrc": "گزینه‌های نمایش",
        "prefs-displaywatchlist": "گزینه‌های نمایش",
        "prefs-changesrc": "نمایش تغییرات",
+       "prefs-changeswatchlist": "نمایش تغییرات",
        "prefs-pageswatchlist": "صفحه‌های پی‌گیری‌شده",
        "prefs-tokenwatchlist": "بلیط",
        "prefs-diffs": "تفاوت‌ها",
        "right-reupload-own": "بارگذاری دوبارهٔ پرونده‌ای که پیش از این توسط همان کاربر بارگذاری شده‌است",
        "right-reupload-shared": "باطل‌کردن محلی پرونده‌های مشترک",
        "right-upload_by_url": "بارگذاری پرونده از یک نشانی اینترنتی",
-       "right-purge": "پاک‌کردن میانگیر صفحه بدون مشاهدهٔ صفحهٔ تأیید",
+       "right-purge": "پاک‌کردن میانگیر صفحه",
        "right-autoconfirmed": "از محدودیت‌های سرعت آی‌پی‌-محور تاثیر نمی‌گیرد",
        "right-bot": "تلقی‌شده به عنوان یک فرآیند خودکار",
        "right-nominornewtalk": "ویرایش جزئی صفحه‌های بحث به شکلی که باعث اعلان پیغام تازه نشود",
        "grant-delete": "حذف صفحات، نسخه‌های ویرایش و سیاهه ورودی",
        "grant-editinterface": "ویرایش صفحه‌های جی‌سان کاربری یا سراسری و فضای نام مدیاویکی",
        "grant-editmycssjs": "ویرایش  CSS /جاوااسکریپت/JSON  کاربری",
-       "grant-editmyoptions": "اولویت‌های کاربری را ویرایش کنید",
+       "grant-editmyoptions": "اولویت‌های کاربری و پیکربندی JSON را ویرایش کنید",
        "grant-editmywatchlist": "ویرایش فهرست پی‌گیری‌هایتان",
        "grant-editsiteconfig": "ویرایش گسترده CSS/JS کاربر",
        "grant-editpage": "ویرایش صفحات موجود",
        "grant-uploadfile": "بارگذاری پرونده‌های جدید",
        "grant-basic": "دسترسی‌های اولیه",
        "grant-viewdeleted": "مشاهدهٔ پرونده و صفحات حذف شده",
-       "grant-viewmywatchlist": "مشاهدۀ فهرست پیگیری‌هایتان",
+       "grant-viewmywatchlist": "مشاهدهٔ فهرست پیگیری‌هایتان",
        "grant-viewrestrictedlogs": "دیدن سیاه‌های محدود شده",
        "newuserlogpage": "سیاههٔ ایجاد کاربر",
        "newuserlogpagetext": "این سیاهه‌ای از نام‌های کاربری تازه‌ساخته‌شده است.",
        "action-changetags": "افزودن یا حذف برچسب قراردادی بر روی نسخه یا سیاهه ورودی‌ها",
        "action-deletechangetags": "حذف برچسب‌ها از پایگاه داده",
        "action-purge": "خالی‌کردن میانگیر این صفحه",
+       "action-apihighlimits": "افزایش محدودیت‌ها برای پرسمان‌های رابط برنامه‌نویسی",
+       "action-autoconfirmed": "از محدودیت‌های سرعت آی‌پی‌-محور تاثیر نمی‌گیرد",
+       "action-bigdelete": "حذف صفحه‌های دارای تاریخچهٔ بزرگ",
+       "action-blockemail": "قطع دسترسی دیگر کاربران برای ارسال ایمیل",
+       "action-bot": "تلقی‌شده به عنوان یک فرآیند خودکار",
+       "action-editprotected": "ویرایش صفحه‌های محافظت‌شده به عنوان «{{int:protect-level-sysop}}»",
+       "action-editsemiprotected": "ویرایش صفحه محافظت‌شده به عنوان «{{int:protect-level-autoconfirmed}}»",
+       "action-editinterface": "ویرایش واسط کاربری",
+       "action-editusercss": "ویرایش صفحه‌های CSS دیگر کاربرها",
+       "action-edituserjson": "ویرایش پرونده‌های JSON دیگر کاربرها",
+       "action-edituserjs": "ویرایش صفحه‌های JS دیگر کاربرها",
+       "action-editsitecss": "ویرایش گسترده CSS وب‌گاه",
+       "action-editsitejson": "ویرایش گسترده JSON وب‌گاه",
+       "action-editsitejs": "ویرایش گسترده JavaScript وب‌گاه",
+       "action-editmyusercss": "پرونده‌های سی‌اس‌اس کاربری خود را ویرایش کنید",
+       "action-editmyuserjson": "پرونده‌های JSON کاربری خود را ویرایش کنید",
+       "action-editmyuserjs": "پرونده‌های جاوااسکریپت کاربری خود را ویرایش کنید",
+       "action-viewsuppressed": "مشاهده نسخه‌هایی که از کاربران مخفی شده‌اند",
+       "action-hideuser": "قطع دسترسی کاربر و پنهان کردن آن از دید عموم",
+       "action-ipblock-exempt": "تأثیر نپذیرفتن از قطع دسترسی‌های آی‌پی، خودکار یا فاصله‌ای",
+       "action-unblockself": "بازکردن دسترسی خود",
+       "action-noratelimit": "تاثیر نپذیرفتن از محدودیت سرعت",
+       "action-reupload-own": "بارگذاری دوبارهٔ پرونده‌ای که پیش از این توسط همان کاربر بارگذاری شده‌است",
+       "action-nominornewtalk": "ویرایش جزئی صفحه‌های بحث به شکلی که باعث اعلان پیغام تازه نشود",
+       "action-markbotedits": "علامت زدن ویرایش‌های واگردانی‌شده به عنوان ویرایش ربات",
+       "action-patrolmarks": "مشاهدهٔ برچسب گشت تغییرات اخیر",
+       "action-override-export-depth": "برون‌بری صفحه‌ها شامل صفحه‌های پیوند شده تا عمق ۵",
+       "action-suppressredirect": "انتقال صفحه بدون ایجاد تغییرمسیر از نام قبلی",
        "nchanges": "$1 تغییر",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|از آخرین بازدید}}",
        "enhancedrc-history": "تاریخچه",
        "rcfilters-filter-editsbyself-description": "ویرایش‌های شما.",
        "rcfilters-filter-editsbyother-label": "تغییریافته توسط دیگران",
        "rcfilters-filter-editsbyother-description": "همهٔ تغییرات به جز تغییرات شما.",
-       "rcfilters-filtergroup-userExpLevel": "ثبت نام و درجهٔ تجربه کاربر",
+       "rcfilters-filtergroup-user-experience-level": "ثبت نام و درجهٔ تجربه کاربر",
        "rcfilters-filter-user-experience-level-registered-label": "ثبت شده",
        "rcfilters-filter-user-experience-level-registered-description": "ویرایشگران وارد شده به سامانه.",
        "rcfilters-filter-user-experience-level-unregistered-label": "ثبت‌نام نکرده",
        "rcfilters-hideminor-conflicts-typeofchange-global": "پالایهٔ «ویرایش جزئی» با یک یا چند تا از پالایه‌های «نوع تغییرات» تعارض دارد چرا که برخی از انواع تغییرات را نمی‌توان به عنوان «جزئی» علامت زد. پالایه‌های دیگر در قسمت «پالایه‌های فعال» در بالا نشان داده شده‌اند.",
        "rcfilters-hideminor-conflicts-typeofchange": "برخی از انواع تغییرات را نمی‌توان به عنوان «جزئی» علامت زد، به همین خاطر این پالایه با پالایه‌های «نوع تغییرات» که در ادامه آمده در تعارض است: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "این پالایهٔ «نوع تغییرات» با پالایهٔ «تغییرات جزئی» در تعارض است. برخی از انواع تغییرات را نمی‌توان به عنوان «جزئی» علامت زد.",
-       "rcfilters-filtergroup-lastRevision": "آخرین نسخه‌ها",
+       "rcfilters-filtergroup-lastrevision": "آخرین نسخه‌ها",
        "rcfilters-filter-lastrevision-label": "آخرین نسخه",
        "rcfilters-filter-lastrevision-description": "تنها آخرین تغییر در صفحه.",
        "rcfilters-filter-previousrevision-label": "به جز آخرین نسخه",
        "rcfilters-watchlist-markseen-button": "نشانه‌گذاری تمام تغییرات به‌عنوان خوانده‌شده",
        "rcfilters-watchlist-edit-watchlist-button": "ویرایش فهرست صفحه‌های پی‌گیری‌هایتان",
        "rcfilters-watchlist-showupdated": "تغییرات صفحاتی که شما از زمانی که تغییر بازدیدشان نکرده‌اید به صورت <strong>پررنگ</strong> و با نشانگر توپر نمایش می‌یابد.",
-       "rcfilters-preference-label": "مخفی کردن نسخه بهبود یافته تغییرات اخیر",
-       "rcfilters-preference-help": "تغییرات رابط کاربری که در سال ۲۰۱۷ اضافه شده است را بر می‌گرداند.",
+       "rcfilters-preference-label": "استفاده واسط بدون جاوااسکریپت",
+       "rcfilters-preference-help": "نمایش تغییرات اخیر بدون پالایه‌های جستجو یا قابلیت پررنگ کردن.",
        "rcfilters-watchlist-preference-label": "استفاده واسط بدون جاوااسکریپت",
-       "rcfilters-watchlist-preference-help": "Ù\88اگرداÙ\86 Ø¯Ø± Ø³Ø§Ù\84 Û²Û°Û±Û· Ø¯Ù\88بارÙ\87 Ø·Ø±Ø§Ø­Û\8c Ø´Ø¯ Ù\88 ØªÙ\85اÙ\85 Ø§Ø¨Ø²Ø§Ø±Ù\87ا Ø§Ø¶Ø§Ù\81Ù\87 Ù\88 Ø§Ø² Ø¢Ù\86 Ø²Ù\85اÙ\86 Ø¨Ù\87 Ø¨Ø¹Ø¯ Ø§Ø¶Ø§Ù\81Ù\87 Ø´Ø¯Ù\86د.",
+       "rcfilters-watchlist-preference-help": "Ù\86Ù\85اÛ\8cØ´ Ù\81Ù\87رست Ù¾Û\8câ\80\8cÚ¯Û\8cرÛ\8c Ø¨Ø¯Ù\88Ù\86 Ù¾Ø§Ù\84اÛ\8cÙ\87â\80\8cÙ\87اÛ\8c Ø¬Ø³ØªØ¬Ù\88 Û\8cا Ù\82ابÙ\84Û\8cت Ù¾Ø±Ø±Ù\86Ú¯ Ú©Ø±Ø¯Ù\86.",
        "rcfilters-filter-showlinkedfrom-label": "نمایش تغییرات صفحاتی که پیوند شده‌اند",
        "rcfilters-filter-showlinkedfrom-option-label": "<strong>صفحات پیوند به</strong> صفحهٔ انتخاب شده",
        "rcfilters-filter-showlinkedto-label": "نمایش تغییرات در صفحاتی که در ون این صفحه پیوند شده‌اند",
        "rcshowhidebots": "$1 ربات‌ها",
        "rcshowhidebots-show": "نمایش",
        "rcshowhidebots-hide": "نهفتن",
-       "rcshowhideliu": "$1 کاربران ثبت‌نام‌کردە",
+       "rcshowhideliu": "$1 کاربران ثبت‌نام‌کرده",
        "rcshowhideliu-show": "نمایش",
        "rcshowhideliu-hide": "نهفتن",
        "rcshowhideanons": "$1 کاربران ناشناس",
        "minoreditletter": "جز",
        "newpageletter": "نو",
        "boteditletter": "ر",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|کاربر}} پی‌گیرنده]",
        "rc-change-size-new": "$1 {{PLURAL:$1|بایت}} پس از تغییر",
        "newsectionsummary": "/* $1 */ بخش جدید",
        "rc-enhanced-expand": "نمایش جزئیات",
        "img-auth-nopathinfo": "مسیر اطلاعات موجود نیست.\nسرورتان برای ردکردن متغییرهای REQUEST_URI و/یا PATH_INFO باید تنظیم شود.\nاگر مبتنی قصد فعال‌کردن wgUsePathInfo دارد.\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization را ببینید.",
        "img-auth-notindir": "مسیر درخواست شده در شاخهٔ بارگذاری تنظیم‌شده قرار ندارد.",
        "img-auth-badtitle": "امکان ایجاد یک عنوان مجاز از «$1» وجود ندارد.",
-       "img-auth-nologinnWL": "شما به سامانه وارد نشده‌اید و «$1» در فهرست سفید قرار ندارد.",
        "img-auth-nofile": "پرونده «$1» وجود ندارد.",
        "img-auth-isdir": "شما تلاش کرده‌اید به شاخهٔ «$1» دسترسی پیدا کنید.\nتنها دسترسی به پرونده مجاز است.",
        "img-auth-streaming": "در حال جاری ساختن «$1».",
        "move": "انتقال",
        "movethispage": "انتقال این صفحه",
        "unusedimagestext": "پرونده‌های زیر موجودند اما در هیچ صفحه‌ای به کار نرفته‌اند.\nلطفاً توجه داشته باشید که دیگر وبگاه‌ها ممکن است با یک نشانی اینترنتی مستقیم به یک پرونده پیوند دهند، و با وجود این که در استفادهٔ فعال هستند در این جا فهرست شوند.",
+       "unusedimagestext-categorizedimgisused": "فایل موردنظر موجود است اما در هیچ صفحه‌ای استفاده نشده است. تصاویر رده‌بندی‌شده حتی اگر در هیچ صفحه‌ای درج نشده باشند، به عنوان تصاویر مورداستفاده محسوب می‌شوند.\nلطفا توجه داشته باشید که دیگر وب‌سایت‌ها ممکن است به صورت مستقیم به یک فایل پیوند داده باشند و با وجود اینکه آن فایل فعال محسوب می‌شود در اینجا لیست شده باشد.",
        "unusedcategoriestext": "این رده‌ها وجود دارند ولی هیچ مقاله یا ردهٔ دیگری از آنها استفاده نمی‌کند.",
        "notargettitle": "مقصدی نیست",
        "notargettext": "شما صفحهٔ یا کاربر مقصدی برای انجام این عمل روی آن مشخص نکرده‌اید.",
        "delete-confirm": "حذف «$1»",
        "delete-legend": "حذف",
        "historywarning": "<strong>هشدار:</strong> صفحه‌ای که در حال پاک کردن آن هستید دارای یک تاریخچه همراه با $1 {{PLURAL:$1|بازبینی|بازبینی}} است:",
-       "historyaction-submit": "نمایش",
+       "historyaction-submit": "نمایش نسخه‌ها",
        "confirmdeletetext": "شما در حال حذف کردن یک صفحه یا تصویر از پایگاه‌های داده همراه با تمام تاریخچهٔ آن هستید.\nلطفاً این عمل را تأیید کنید و اطمینان حاصل کنید که عواقب این کار را می‌دانید و این عمل را مطابق با [[{{MediaWiki:Policy-url}}|سیاست‌ها]] انجام می‌دهید.",
        "actioncomplete": "عمل انجام شد",
        "actionfailed": "عمل ناموفق بود",
        "deleting-backlinks-warning": "<strong>هشدار:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|صفحه‌های دیگری]] هستند که به صفحه‌ای که شما در حال حذف آن هستید پیوند دارند یا آن را تراگنجانیده‌اند.",
        "deleting-subpages-warning": "<strong>هشدار:</strong> صفحه‌ای که شما می‌خواهید حذف کنید [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|یک زیرصفحه|$1 زیرصفحه|51=بیش از پنجاه زیرصفحه}}]] دارد.",
        "rollback": "واگردانی ویرایش‌ها",
+       "rollback-confirmation-confirm": "لطفاً تأیید کنید:",
+       "rollback-confirmation-yes": "واگردانی",
+       "rollback-confirmation-no": "انصراف",
        "rollbacklink": "واگردانی",
        "rollbacklinkcount": "واگردانی $1 ویرایش",
        "rollbacklinkcount-morethan": "واگردانی بیش از $1 ویرایش",
        "revertpage": "ویرایش [[Special:Contributions/$2|$2]] ([[User talk:$2|بحث]]) به آخرین تغییری که [[User:$1|$1]] انجام داده بود واگردانده شد",
        "revertpage-nouser": "ویرایش‌های انجام‌شده توسط (نام کاربری حذف شده) به آخرین ویرایش [[User:$1|$1]] واگردانی شد.",
        "rollback-success": "ویرایش‌های {{GENDER:$3|$1}} واگردانی شد؛\nصفحه به آخرین ویرایش {{GENDER:$4|$2}} برگردانده شد.",
-       "rollback-success-notify": "ویرایش‌های توسط $1 واگردانی شد؛\nبه آخرین نسخه توسط $2 بازگردانی شد. [$3 نمایش تغییرات]",
        "sessionfailure-title": "خطای نشست کاربری",
        "sessionfailure": "به نظر می‌رسد مشکلی در مورد نشست کاربری شما وجود دارد؛\nعمل درخواست شده در اقدامی پیشگیرانه در برابر ربوده‌شدن اطلاعات نشست کاربری، لغو شد.\nلطفاً فرم را از نو بارگذاری کنید.",
        "changecontentmodel": "ویرایش نمونه محتوای یک صفحه",
        "mycontris": "مشارکت‌ها",
        "anoncontribs": "مشارکت‌ها",
        "contribsub2": "برای {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "برای {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "حساب کاربری «$1» ثبت نشده‌است.",
+       "negative-namespace-not-supported": "فضاهای نام با مقدار منفی پشتیبانی نمی‌شوند.",
        "nocontribs": "هیچ تغییری با این مشخصات یافت نشد.",
        "uctop": "نسخهٔ کنونی",
        "month": "در این ماه (و پیش از آن):",
        "ipb-blocklist": "دیدن قطع دسترسی‌های موجود",
        "ipb-blocklist-contribs": "مشارکت‌های $1",
        "ipb-blocklist-duration-left": "$1 باقی مانده",
+       "block-actions": "اقدامات قطع دسترسی شده:",
        "block-expiry": "زمان سرآمدن:",
+       "block-options": "گزینه‌های بیشتر:",
        "block-prevent-edit": "در حال ویرایش",
        "block-reason": "دلیل:",
        "block-target": "نام کاربری یا آدرس آی‌پی:",
        "blocklist-userblocks": "پنهان کردن بسته‌شدن‌های حساب",
        "blocklist-tempblocks": "پنهان کردن بستن‌های موقت",
        "blocklist-addressblocks": "پنهان کردن تک آی‌پی‌های بسته شده",
+       "blocklist-type": "نوع:",
+       "blocklist-type-opt-all": "همه",
+       "blocklist-type-opt-partial": "جزئی",
        "blocklist-rangeblocks": "پنهان کردن قطع دسترسی بازه‌ها",
        "blocklist-timestamp": "برچسب زمان",
        "blocklist-target": "هدف",
        "emailblock": "ایمیل بسته‌شده",
        "blocklist-nousertalk": "نمی‌تواند صفحهٔ بحث خود را ویرایش کند",
        "blocklist-editing": "در حال ویرایش",
+       "blocklist-editing-sitewide": "ویرایش (کل ویکی)",
        "blocklist-editing-page": "صفحات",
        "blocklist-editing-ns": "فضاهای نام",
        "ipblocklist-empty": "فهرست بسته‌شدن‌ها خالی‌است.",
-       "ipblocklist-no-results": "دسترسی حساب کاربری یا نشانی آی‌پی مورد نظر قطع نیست.",
+       "ipblocklist-no-results": "دسترسی حساب کاربری یا نشانی آی‌پی موردنظر، قطع نیست.",
        "blocklink": "بستن",
        "unblocklink": "باز شود",
        "change-blocklink": "تغییر قطع دسترسی",
        "ipb_expiry_old": "زمان سرآمدن در گذشته‌است.",
        "ipb_expiry_temp": "قطع دسترسی کاربرهای پهنان باید همیشگی باشد.",
        "ipb_hide_invalid": "قادر به سرکوب این حساب نیست; این بیشتر از {{PLURAL:$1|یک ویرایش|$1 ویرایش‌ها}} دارد.",
+       "ipb_hide_partial": "قطع دسترسی با پنهان کردن نام کاربری حتما باید یک قطع دسترسی سراسری باشد",
        "ipb_already_blocked": "«$1» همین الان هم بسته‌است",
        "ipb-needreblock": "دسترسی $1 از قبل بسته است. آیا می‌خواهید تنظیمات آن را تغییر دهید؟",
        "ipb-otherblocks-header": "سایر {{PLURAL:$1|قطع دسترسی‌ها|قطع دسترسی‌ها}}",
        "move-watch": "پی‌گیری صفحه‌های مبدأ و مقصد",
        "movepagebtn": "صفحه منتقل شود",
        "pagemovedsub": "انتقال با موفقیت انجام شد",
+       "cannotmove": "این صفحه قابل انتقال نیست به {{PLURAL:$1|دلیل|دلایل}}:",
        "movepage-moved": "'''«$1» به «$2» منتقل شد'''",
        "movepage-moved-redirect": "یک تغییرمسیر ایجاد شد.",
        "movepage-moved-noredirect": "از ایجاد تغییرمسیر ممانعت شد.",
+       "movepage-delete-first": "صفحه مقصد تعداد زیادی نسخه برای حذف دارد. لطفا ابتدا صفحه را دستی حذف کنید و سپس دوباره سعی کنید.",
        "articleexists": "صفحه‌ای با این نام از قبل وجود دارد، یا نامی که انتخاب کرده‌اید معتبر نیست.\nلطفاً نام دیگری انتخاب کنید.",
        "cantmove-titleprotected": "شما نمی‌توانید صفحه را به این نشانی انتقال دهید، چرا که عنوان جدید در برابر ایجاد محافظت شده‌است",
        "movetalk": "صفحهٔ بحث هم منتقل شود",
        "allmessagesdefault": "متن پیش‌فرض پیغام",
        "allmessagescurrent": "متن کنونی پیغام",
        "allmessagestext": "این فهرستی از پیغام‌های سامانه‌ای موجود در فضای نام مدیاویکی است.\nچنانچه مایل به مشارکت در محلی‌سازی مدیاویکی هستید لطفاً [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation محلی‌سازی مدیاویکی] و [https://translatewiki.net translatewiki.net] را ببینید.",
-       "allmessagesnotsupportedDB": "این صفحه نمی‌تواند استفاده شود به این دلیل که <strong>‎$wgUseDatabaseMessages</strong> غیرفعال شده است.",
+       "allmessages-not-supported-database": "این صفحه نمی‌تواند استفاده شود به این دلیل که <strong>‎$wgUseDatabaseMessages</strong> غیرفعال شده است.",
        "allmessages-filter-legend": "پالایه",
        "allmessages-filter": "پالودن بر اساس وضعیت شخصی‌سازی:",
        "allmessages-filter-unmodified": "تغییر نیافته",
        "pageinfo-category-files": "تعداد پرونده‌ها",
        "pageinfo-user-id": "شناسه کاربر",
        "pageinfo-file-hash": "مقدار هش",
+       "pageinfo-view-protect-log": "نمایش سیاهه محفاظت برای این صفحه.",
        "markaspatrolleddiff": "برچسب گشت بزن",
        "markaspatrolledtext": "به این صفحه برچسب گشت بزن",
        "markaspatrolledtext-file": "انتخاب این نسخهٔ پرونده به عنوان گشت خورده",
        "confirm-unwatch-top": "این صفحه از فهرست پی‌گیری‌های شما حذف شود؟",
        "confirm-rollback-button": "باشد",
        "confirm-rollback-top": "خنثی‌سازی ویرایش‌های این صفحه؟",
+       "confirm-rollback-bottom": "این عمل به سرعت تغییرات انتخاب‌شده در صفحه را واگردانی خواهد کرد.",
        "confirm-mcrrestore-title": "بازیابی نسخه",
        "confirm-mcrundo-title": "خنثی کردن تغییرات",
        "mcrundofailed": "واگردانی ناموفق بود",
+       "mcrundo-missingparam": "فقدان پارامترهای ضروری در درخواست",
+       "mcrundo-changed": "این صفحه از زمانی که شما تفاوت را دیده‌اید تغییر کرده است. تغییر جدید را مشاهده کنید.",
+       "mcrundo-parse-failed": "قادر به تجزیه نسخه جدید نیست: $1",
        "semicolon-separator": "؛&#32;",
        "comma-separator": "،&#32;",
        "percent": "$1٪",
        "specialpages-group-developer": "ابزارهای توسعه‌دهندگان",
        "blankpage": "صفحهٔ خالی",
        "intentionallyblankpage": "این صفحه به طور عمدی خالی گذاشته شده است.",
+       "disabledspecialpage-disabled": "این صفحه توسط یک مدیر غیرفعال شده‌است.",
        "external_image_whitelist": " #این سطر را همان‌گونه که هست رها کنید<pre>\n#عبارت‌های باقاعده (regex) را در زیر قرار دهید (فقط بخشی که بین // قرار می‌گیرد)\n#آن‌ها با نشانی اینترنتی تصاویر خارجی پیوند داده شده تطبیق داده می‌شوند\n#مواردی که مطابق باشند به صورت تصویر نمایش می‌یابند، و در غیر این صورت تنها یک پیوند به تصویر نمایش می‌یابد\n#سطرهایی که با # آغاز شوند به عنوان توضیحات در نظر گرفته می‌شوند\n#این سطرها به کوچکی و بزرگی حروف حساس هستند\n\n#عبارت‌های باقاعده (regex)  را زیر این سطر قرار دهید. این سطر را همان‌گونه که هست رها کنید</pre>",
        "tags": "برچسب‌های تغییر مجاز",
        "tag-filter": "پالایش [[Special:Tags|برچسب‌ها]]:",
        "logentry-block-block": "$1 {{GENDER:$4|$3}} را $5 {{GENDER:$2|بست}} $6",
        "logentry-block-unblock": "$1 {{GENDER:$4|$3}} را {{GENDER:$2|بازکرد}}",
        "logentry-block-reblock": "$1 {{GENDER:$2|تنظیمات}} بستن {{GENDER:$4|$3}} را به پایان قطع دسترسی $5 $6 تغییر داد.",
+       "logentry-partialblock-block-page": "{{PLURAL:$1|صفحه|صفحات}} $2",
+       "logentry-partialblock-block-ns": "{{PLURAL:$1|فضای نام|فضاهای نام}} $2",
+       "logentry-partialblock-block": "$1 {{GENDER:$4|$3}} را از ویرایش $7 با انقضای $5 $6 {{GENDER:$2|قطع دسترسی کرد}}",
+       "logentry-partialblock-reblock": "$1 {{GENDER:$2|تنظیمات}} بستن {{GENDER:$4|$3}} را به جلوگیری از ویرایش $7 و پایان قطع دسترسی $5 $6 تغییر داد",
+       "logentry-non-editing-block-block": "$1 {{GENDER:$4|$3}} را از اعمال مشخص‌شده غیرویرایشی با انقضای $5 $6 {{GENDER:$2|قطع دسترسی کرد}}",
+       "logentry-non-editing-block-reblock": "$1 {{GENDER:$2|تنظیمات}} بستن {{GENDER:$4|$3}} را به جلوگیری از اعمال مشخص‌شده غیرویرایشی و پایان قطع دسترسی $5 $6 تغییر داد.",
        "logentry-suppress-block": "$1 {{GENDER:$2|بسته شد}} {{GENDER:$4|$3}} با پایان قطع دسترسی در زمان $5 $6",
        "logentry-suppress-reblock": "$1 {{GENDER:$2|تنظیمات}} بستن برای  {{GENDER:$4|$3}} به پایان قطع دسترسی  $5 $6 تغییر یافت",
        "logentry-import-upload": "$1 $3 را توسط بارگذار پرونده {{GENDER:$2|درون‌ریزی کرد}}",
        "logentry-rights-autopromote": "$1 به طور خودکار از $4 به $5 {{GENDER:$2|ارتقاء یافت}}",
        "logentry-upload-upload": "$1 $3 را {{GENDER:$2|بارگذاری کرد}}",
        "logentry-upload-overwrite": "$1 نسخهٔ تازه‌ای از $3 را {{GENDER:$2|بارگذاری کرد}}",
-       "logentry-upload-revert": "$1 {{GENDER:$2|بارگذاری کرد}} $3",
+       "logentry-upload-revert": "$1 $3 را به نسخه قدیمی {{GENDER:$2|واگردانی کرد}}",
        "log-name-managetags": "تاریخچه مدیریت برچسب",
        "log-description-managetags": "این صفحه امور مدیریتی مربوط به [[Special:Tags|برچسب‌ها]] را فهرست می‌کند. سیاهه فقط حاوی فعالیت‌هایی است که توسط یک مدیر به صورت دستی انجام شده‌اند؛ برچسب‌ها ممکن است توسط نرم‌افزار ویکی ساخته یا حذف بشوند بدون اینکه هیچ ورودی در این سیاهه ثبت گردد.",
        "logentry-managetags-create": "$1 برچسب «$4» را {{GENDER:$2|ایجاد کرد}}",
        "log-action-filter-suppress-reblock": "مخفی‌سازی کاربر با بستن مجدد",
        "log-action-filter-upload-upload": "بارگذاری جدید",
        "log-action-filter-upload-overwrite": "بارگذاری دوباره",
+       "log-action-filter-upload-revert": "واگردانی",
        "authmanager-authn-not-in-progress": "ارزیابی ورود در جريان نيست یا اطلاعات جلسه کاری از بين رفته است. لطفاً دوباره از ابتدا شروع کنيد.",
        "authmanager-authn-no-primary": "اعتبارسنجی اطلاعات ارائه شده جهت ورود ميسر نيست",
        "authmanager-authn-no-local-user": "اطلاعات ورود ارائه شده با هيچ کاربری در اين ويکی مرتبط نيست",
        "passwordpolicies-policy-passwordcannotmatchblacklist": "گذرواژه نمی‌تواند مشابه گذرواژه‌های فهرست شده در فهرست سیاه باشد",
        "passwordpolicies-policy-maximalpasswordlength": "گذرواژه باید کمتر از $1 {{PLURAL:$1|نویسه|نویسه}} طول داشته باشد",
        "passwordpolicies-policy-passwordcannotbepopular": "گذرواژه نمی‌تواند {{PLURAL:$1|گذرواژه پراستفاده باشد|در فهرست $1 گذرواژه‌های پراستفاده باشد}}",
+       "passwordpolicies-policy-passwordnotinlargeblacklist": "گذرواژه نمی‌تواند یکی از ۱۰۰٬۰۰۰ گذرواژه پراستفاده باشد.",
+       "passwordpolicies-policyflag-forcechange": "در هنگام ورود باید تغییر دهید",
+       "passwordpolicies-policyflag-suggestchangeonlogin": "در هنگام ورود، پیشنهاد تغییر بده",
        "easydeflate-invaliddeflate": "محتوی تهیه‌شده به صورت درست خالی نشده‌است",
        "unprotected-js": "به دلایل امنیتی، جاوااسکریپت نمی‌تواند از صفحات محافظت‌نشده بارگیری شود. لطفا جاوااسکریپت را تنها در فضای نام مدیاویکی: و یا در زیرصفحهٔ کاربری خودتان ایجاد کنید."
 }
index 12caff8..2ffef38 100644 (file)
        "tog-norollbackdiff": "Älä näytä eroavaisuuksia, kun olet palauttanut muokkauksen palauta-työkalulla",
        "tog-useeditwarning": "Varoita minua, kun poistun muokkaussivulta tallentamatta muutoksia",
        "tog-prefershttps": "Käytä aina suojattua yhteyttä, kun olet kirjautunut sisään",
+       "tog-showrollbackconfirmation": "Näytä vahvistuspyyntö, kun palauta-linkkiä klikataan.",
        "underline-always": "Aina",
        "underline-never": "Ei koskaan",
        "underline-default": "Ulkoasun tai selaimen oletustapa",
        "nstab-category": "Luokka",
        "mainpage-nstab": "Etusivu",
        "nosuchaction": "Toimintoa ei ole olemassa",
-       "nosuchactiontext": "URL:ssä määritelty toiminto ei ole kelvollinen.\nOlet saattanut kirjoittaa URL:in väärin tai olet seurannut virheellistä linkkiä.\nKyseessä voi myös mahdollisesti olla virhe sivuston {{SITENAME}} käyttämässä ohjelmistossa.",
+       "nosuchactiontext": "URL:ssä määritelty toiminto ei ole kelvollinen.\nOlet saattanut kirjoittaa URL:in väärin tai olet seurannut virheellistä linkkiä.\nKyseessä voi myös mahdollisesti olla virhe {{GRAMMAR:genitive|{{SITENAME}}}} käyttämässä ohjelmistossa.",
        "nosuchspecialpage": "Kyseistä toimintosivua ei ole",
        "nospecialpagetext": "<strong>Ohjelmisto ei tunnista pyytämääsi toimintosivua.</strong>\n\nLuettelo toimintosivuista löytyy sivulta [[Special:SpecialPages|{{int:specialpages}}]].",
        "error": "Virhe",
        "welcomecreation-msg": "Käyttäjätunnuksesi on luotu.\nVoit nyt muuttaa {{GRAMMAR:genitive|{{SITENAME}}}} [[Special:Preferences|asetuksia]] itsellesi.",
        "yourname": "Käyttäjänimi:",
        "userlogin-yourname": "Käyttäjänimi",
-       "userlogin-yourname-ph": "Kirjoita käyttäjätunnus",
+       "userlogin-yourname-ph": "Kirjoita käyttäjänimi",
        "createacct-another-username-ph": "Lisää käyttäjätunnus",
        "yourpassword": "Salasana:",
        "userlogin-yourpassword": "Salasana",
        "createacct-loginerror": "Tunnus luotiin onnistuneesti, mutta automaattista sisäänkirjautumista ei voitu tehdä. Siirry [[Special:UserLogin|manuaaliseen kirjautumiseen]].",
        "noname": "Et ole määritellyt kelvollista käyttäjänimeä.",
        "loginsuccesstitle": "Olet kirjautunut sisään",
-       "loginsuccess": "'''Olet kirjautunut sivustolle {{SITENAME}} käyttäjänä $1.'''",
+       "loginsuccess": "<strong>Olet kirjautunut {{GRAMMAR:illative|{{SITENAME}}}} käyttäjänä \"$1\".</strong>",
        "nosuchuser": "Käyttäjää ”$1” ei ole olemassa.\nNimet ovat kirjainkoosta riippuvaisia. \nTarkista, kirjoititko nimen oikein, tai [[Special:CreateAccount|luo uusi käyttäjätunnus]].",
        "nosuchusershort": "Käyttäjää nimeltä ”$1” ei ole. Kirjoititko nimen oikein?",
        "nouserspecified": "Käyttäjätunnusta ei ole määritelty.",
        "passwordreset-email": "Sähköpostiosoite:",
        "passwordreset-emailtitle": "Tunnuksen tiedot {{GRAMMAR:inessive|{{SITENAME}}}}",
        "passwordreset-emailtext-ip": "Joku (todennäköisesti sinä, IP-osoitteesta $1) pyysi salasanasi\nvaihtamista sivustolla {{SITENAME}} ($4). {{PLURAL:$3|Seuraava käyttäjätunnus on|Seuraavat käyttäjätunnukset ovat}}\nyhdistettynä tähän sähköpostiosoitteeseen:\n\n$2\n\n{{PLURAL:$3|Tämä väliaikainen salasana vanhentuu|Nämä väliaikaiset salasanat vanhentuvat}} {{PLURAL:$5|yhden päivän|$5 päivän}} kuluttua.\nKirjaudu sisään nyt ja valitse uusi salasana heti. Jos joku toinen teki tämän pyynnön \ntai jos muistitkin vanhan salasanasi etkä halua enää muuttaa sitä,\nvoit jättää tämän viestin huomiotta ja jatkaa vanhan salasanasi käyttämistä.",
-       "passwordreset-emailtext-user": "Käyttäjä $1 pyysi muistutusta tunnuksesi tiedoista sivustolla {{SITENAME}} ($4).\n{{PLURAL:$3|Seuraava käyttäjätunnus on|Seuraavat käyttäjätunnukset ovat}} liitetty tähän sähköpostiosoitteeseen:\n\n$2\n\n{{PLURAL:$3|Tämä väliaikainen salasana vanhentuu|Nämä väliaikaiset salasanat vanhentuvat}} {{PLURAL:$5|yhden päivän|$5 päivän}} kuluttua.\nSinun kannattaa kirjautua sisään ja valita uusi salasana. Jos joku toinen teki tämän\npyynnön, tai muistat sittenkin vanhan salasanasi, etkä halua muuttaa sitä,\nvoit jättää tämän viestin huomiotta ja jatkaa vanhan salasanan käyttöä.",
+       "passwordreset-emailtext-user": "Käyttäjä $1 pyysi muistutusta tunnuksesi tiedoista {{GRAMMAR:inessive|{{SITENAME}}}} ($4).\n{{PLURAL:$3|Seuraava käyttäjätunnus on|Seuraavat käyttäjätunnukset ovat}} liitetty tähän sähköpostiosoitteeseen:\n\n$2\n\n{{PLURAL:$3|Tämä väliaikainen salasana vanhentuu|Nämä väliaikaiset salasanat vanhentuvat}} {{PLURAL:$5|yhden päivän|$5 päivän}} kuluttua.\nSinun kannattaa kirjautua sisään ja valita uusi salasana. Jos joku toinen teki tämän\npyynnön, tai muistat sittenkin vanhan salasanasi, etkä halua muuttaa sitä,\nvoit jättää tämän viestin huomiotta ja jatkaa vanhan salasanan käyttöä.",
        "passwordreset-emailelement": "Käyttäjätunnus: \n$1\n\nVäliaikainen salasana: \n$2",
        "passwordreset-emailsentemail": "Jos tämä on sinun tunnuksellesi rekisteröity sähköpostiosoite, salasanan uudistamisesta kertova viesti lähetetään.",
        "passwordreset-emailsentusername": "Jos on olemassa vastaava rekisteröity sähköpostiosoite, salasanan uudistamisesta kertova viesti lähetetään.",
        "userpage-userdoesnotexist": "Käyttäjätunnusta ”$1” ei ole rekisteröity. \nVarmista, haluatko luoda tämän sivun tai muokata sitä.",
        "userpage-userdoesnotexist-view": "Käyttäjätunnusta ”$1” ei ole rekisteröity.",
        "blocked-notice-logextract": "Tämä käyttäjä on tällä hetkellä estetty.\nAlla on viimeisin estolokin tapahtuma:",
-       "clearyourcache": "<strong>Huomautus:</strong> Selaimen välimuisti pitää tyhjentää asetusten tallentamisen jälkeen, jotta muutokset tulisivat voimaan.\n* <strong>Firefox ja Safari:</strong> Napsauta <em>Shift</em>-näppäin pohjassa <em>Päivitä</em>, tai paina <em>Ctrl-F5</em> tai <em>Ctrl-R</em> (<em>⌘-R</em> Macilla)\n* <strong>Google Chrome:</strong> Paina <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> Macilla)\n* <strong>Internet Explorer:</strong> Napsauta <em>Ctrl</em>-näppäin pohjassa <em>Päivitä</em> tai paina <em>Ctrl-F5</em>\n* <strong>Opera:</strong> <em>Menu → Settings</em> (<em>Opera → Preferences</em> Macilla) ja sitten <em>Privacy & security → Clear browsing data → Cached images and files</em>.",
+       "clearyourcache": "<strong>Huomautus:</strong> Selaimen välimuisti pitää tyhjentää asetusten tallentamisen jälkeen, jotta muutokset tulisivat voimaan.\n* <strong>Firefox ja Safari:</strong> Napsauta <em>Shift</em>-näppäin pohjassa <em>Päivitä</em>, tai paina <em>Ctrl-F5</em> tai <em>Ctrl-R</em> (<em>⌘-R</em> Macilla)\n* <strong>Google Chrome:</strong> Paina <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> Macilla)\n* <strong>Internet Explorer:</strong> Napsauta <em>Ctrl</em>-näppäin pohjassa <em>Päivitä</em> tai paina <em>Ctrl-F5</em>\n* <strong>Opera:</strong> <em>Valikko → Asetukset</em> (<em>Opera → Asetukset</em> Macilla) ja sitten <em>Tietosuoja ja turvallisuus → Tyhjennä selaustiedot → Välimuistissa olevat kuvat ja tiedostot</em>.",
        "usercssyoucanpreview": "Voit testata uutta CSS:ää ennen tallennusta käyttämällä painiketta ”{{int:showpreview}}”.",
        "userjsonyoucanpreview": "<strong>Vihje:</strong> Voit testata uutta JSONia ennen tallennusta käyttämällä painiketta ”{{int:showpreview}}”.",
        "userjsyoucanpreview": "Voit testata uutta JavaScriptiä ennen tallennusta käyttämällä painiketta ”{{int:showpreview}}”.",
        "continue-editing": "Siirry muokkauskenttään",
        "previewconflict": "Tämä esikatselu näyttää miltä muokkausalueella oleva teksti näyttää tallennettuna.",
        "session_fail_preview": "Muokkaustasi ei voitu tallentaa, koska istuntosi tiedot ovat kadonneet.\n\nSaatat olla kirjautunut ulos. '''Varmista, että olet edelleen kirjautunut sisään ja yritä uudelleen'''. Jos ongelma ei katoa, yritä [[Special:UserLogout|kirjautua ulos]] ja takaisin sisään, ja varmista, että selaimesi sallii evästeet tältä sivustolta.",
-       "session_fail_preview_html": "Valitettavasti muokkaustasi ei voitu käsitellä istunnon tietojen katoamisen vuoksi.\n\n<em>Koska sivustolla {{SITENAME}} on käytössä suodattamaton HTML-koodi, esikatselu on piilotettu JavaScript-hyökkäyksien torjumiseksi</em>\n\n<strong>Jos tämä on oikea muokkausyritys, yritä uudelleen.</strong> Jos ongelma ei katoa, yritä [[Special:UserLogout|kirjautua ulos]] ja takaisin sisään. Tarkista myös, että selaimesi sallii evästeet tältä sivustolta.",
+       "session_fail_preview_html": "Valitettavasti muokkaustasi ei voitu käsitellä istunnon tietojen katoamisen vuoksi.\n\n<em>Koska {{GRAMMAR:inessive|{{SITENAME}}}} on käytössä suodattamaton HTML-koodi, esikatselu on piilotettu JavaScript-hyökkäyksien torjumiseksi</em>\n\n<strong>Jos tämä on oikea muokkausyritys, yritä uudelleen.</strong> Jos ongelma ei katoa, yritä [[Special:UserLogout|kirjautua ulos]] ja takaisin sisään. Tarkista myös, että selaimesi sallii evästeet tältä sivustolta.",
        "token_suffix_mismatch": "'''Muokkauksesi on hylätty, koska asiakasohjelmasi ei osaa käsitellä välimerkkejä muokkaustarkisteessa. Syynä voi olla viallinen välityspalvelin.'''",
        "edit_form_incomplete": "'''Osa muokkauslomakkeesta ei saavuttanut palvelinta. Tarkista, että muokkauksesi ovat vahingoittumattomia ja yritä uudelleen.'''",
        "editing": "Muokataan sivua $1",
        "edit-gone-missing": "Sivun päivitys ei onnistunut.\nSe on ilmeisesti poistettu.",
        "edit-conflict": "Päällekkäinen muokkaus.",
        "edit-no-change": "Muokkauksesi sivuutettiin, koska tekstiin ei tehty mitään muutoksia.",
+       "edit-slots-cannot-add": "{{PLURAL:$1|Seuraava slotti ei ole tuettu|Seuraavat slotit eivät ole tuettuja}} täällä: $2.",
+       "edit-slots-cannot-remove": "{{PLURAL:$1|Seuraava slotti vaaditaan eikä sitä voi poistaa|Seuraavat alueet vaaditaan eikä niitä voida poistaa}}: $2.",
+       "edit-slots-missing": "{{PLURAL:$1|Seuraava slotti puuttuu|Seuraavat slotit puuttuvat}}: $2.",
        "postedit-confirmation-created": "Sivu on nyt luotu.",
        "postedit-confirmation-restored": "Sivu on nyt palautettu (aiempaan versioonsa).",
        "postedit-confirmation-saved": "Muokkauksesi on tallennettu.",
        "defaultmessagetext": "Viestin oletusteksti",
        "content-failed-to-parse": "Sisältö tyypiltään $2 ei jäsenny tyypiksi $1: $3",
        "invalid-content-data": "Virheellinen sisältö",
-       "content-not-allowed-here": "Sivun [[:$2]] sisältö ei voi olla tyyppiä $1.",
+       "content-not-allowed-here": "Sivun [[:$2]] sisältö ei voi olla tyyppiä \"$1\" slotissa \"$3\"",
        "editwarning-warning": "Tältä sivulta poistuminen saattaa aiheuttaa kaikkien tekemiesi muutosten katoamisen.\nJos olet kirjautunut sisään, voit poistaa tämän varoituksen käytöstä omien asetuksien osiossa ”{{int:prefs-editing}}”.",
        "editpage-invalidcontentmodel-title": "Sisältömalli ei ole tuettu",
        "editpage-invalidcontentmodel-text": "Sisältömalli ”$1” ei ole tuettu.",
        "page_first": "ensimmäinen sivu",
        "page_last": "viimeinen sivu",
        "histlegend": "Eroavaisuuksien valinta: Merkitse niiden versioiden valintaympyrät, joita haluat vertailla, ja paina enter tai alhaalla olevaa nappia.<br />\nSelitys: '''({{int:cur}})''' = eroavaisuudet uusimpaan versioon, '''({{int:last}})''' = eroavaisuudet edeltävään versioon, '''{{int:minoreditletter}}''' = pieni muutos.",
-       "history-fieldset-title": "Etsi versioita",
+       "history-fieldset-title": "Suodata versioita",
        "history-show-deleted": "Vain poistetut versiot",
        "histfirst": "vanhimmat",
        "histlast": "uusimmat",
        "historysize": "({{PLURAL:$1|1 tavu|$1 tavua}})",
-       "historyempty": "(tyhjä)",
+       "historyempty": "tyhjä",
        "history-feed-title": "Muutoshistoria",
        "history-feed-description": "Tämän sivun muutoshistoria",
        "history-feed-item-nocomment": "$1 ($2)",
        "right-reupload-own": "Korvata itsetallennettu tiedosto uudella tiedostolla",
        "right-reupload-shared": "Korvata yhteiseen mediavarastoon tallennettuja tiedostoja paikallisesti",
        "right-upload_by_url": "Tallentaa tiedostoja verkko-osoitteella",
-       "right-purge": "Tyhjentää sivuston välimuisti ilman varmennussivua",
+       "right-purge": "Tyhjentää sivuston välimuisti",
        "right-autoconfirmed": "IP-pohjaiset nopeusrajoitukset eivät ole voimassa",
        "right-bot": "Kohdellaan automaattisena prosessina",
        "right-nominornewtalk": "Tehdä pieniä muokkauksia käyttäjien keskustelusivuille siten, että käyttäjälle ei ilmoiteta siitä uutena viestinä",
        "action-changetags": "lisätä ja poistaa satunnaisia merkkauksia yksittäisissä sivuversioissa ja lokimerkinnöissä",
        "action-deletechangetags": "poistaa merkkauksia tietokannasta",
        "action-purge": "päivittää tämän sivun välimuistia",
+       "action-apihighlimits": "käyttää korkeampia rajoja API-kyselyissä",
+       "action-autoconfirmed": "ohittaa IP-pohjaisia nopeusrajoituksia",
+       "action-bigdelete": "poistaa sivuja, joilla on pitkä historia",
+       "action-blockemail": "estää käyttäjää lähettämästä sähköpostia",
+       "action-bot": "tulla kohdelluksi automaattisena prosessina",
+       "action-editprotected": "muokata sivuja, jotka on suojattu tasolle ”{{int:protect-level-sysop}}”",
+       "action-editsemiprotected": "muokata sivuja, jotka on suojattu tasolle ”{{int:protect-level-autoconfirmed}}”",
+       "action-editinterface": "muokata käyttöliittymää",
+       "action-editusercss": "muokata toisten käyttäjien CSS-tiedostoja",
+       "action-edituserjson": "muokata toisten käyttäjien JSON-tiedostoja",
+       "action-edituserjs": "muokata toisten käyttäjien JavaScript-tiedostoja",
+       "action-editsitecss": "muokata CSS-koodia koko sivustolla",
+       "action-editsitejson": "muokata JSON-koodia koko sivustolla",
+       "action-editsitejs": "muokata JavaScriptiä koko sivustolla",
+       "action-editmyusercss": "muokata omia CSS-tiedostoja",
+       "action-editmyuserjson": "muokkata omia JSON-tiedostoja",
+       "action-editmyuserjs": "muokata omia JavaScript-tiedostoja",
+       "action-viewsuppressed": "katsoa versioita, jotka on piilotettu jokaiselta käyttäjältä",
+       "action-hideuser": "estää käyttäjätunnus ja piilottaa se näkyvistä",
+       "action-ipblock-exempt": "ohittaa IP-, automaattiset ja osoitealue-estot",
+       "action-unblockself": "poistaa esto itseltään",
+       "action-noratelimit": "ohittaa nopeusrajoitukset",
+       "action-reupload-own": "korvata itsetallennettu tiedosto uudella tiedostolla",
+       "action-nominornewtalk": "tehdä pieniä muokkauksia käyttäjien keskustelusivuille siten, että käyttäjälle ei ilmoiteta siitä uutena viestinä",
+       "action-markbotedits": "merkitä muokkausten palauttaminen botilla tehdyksi",
+       "action-patrolmarks": "nähdä tarkastusmerkit tuoreissa muutoksissa",
+       "action-override-export-depth": "viedä sivuja sisältäen viitatut sivut viiden syvyydellä",
+       "action-suppressredirect": "siirtää sivuja luomatta automaattisia ohjauksia",
        "nchanges": "$1 {{PLURAL:$1|muutos|muutosta}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|viimeisen käynnin jälkeen}}",
        "enhancedrc-history": "historia",
        "recentchanges-feed-description": "Tällä sivulla voi seurata tuoreita {{GRAMMAR:illative|{{SITENAME}}}} tehtyjä muutoksia.",
        "recentchanges-label-newpage": "Tämä muutos loi uuden sivun",
        "recentchanges-label-minor": "Tämä on pieni muutos",
-       "recentchanges-label-bot": "Tämän muutoksen suoritti botti",
+       "recentchanges-label-bot": "Tämän muokkauksen teki botti",
        "recentchanges-label-unpatrolled": "Tätä muutosta ei ole vielä tarkastettu",
        "recentchanges-label-plusminus": "Sivun koon muutos tavuina",
        "recentchanges-legend-heading": "<strong>Selitys:</strong>",
        "rcfilters-savedqueries-already-saved": "Nämä suodattimet ovat jo tallennettu. Vaihda asetuksiasi luodaksesi uuden tallennetun suodattimen.",
        "rcfilters-restore-default-filters": "Palauta oletussuodattimet",
        "rcfilters-clear-all-filters": "Tyhjennä kaikki suodattimet",
-       "rcfilters-show-new-changes": "Näytä uusimmat muutokset",
+       "rcfilters-show-new-changes": "Näytä uudet muutokset $1 alkaen",
        "rcfilters-search-placeholder": "Suodata muutoksia (käytä valikkoa tai etsi suodattimen nimeä)",
        "rcfilters-invalid-filter": "Kelvoton suodatin",
        "rcfilters-empty-filter": "Ei aktiivisia suodattimia. Kaikki muutokset näytetään.",
        "rcfilters-filter-editsbyself-description": "Tekemäsi muutokset.",
        "rcfilters-filter-editsbyother-label": "Muiden muutokset",
        "rcfilters-filter-editsbyother-description": "Muiden käyttäjien tekemät muutokset.",
-       "rcfilters-filtergroup-userExpLevel": "Käyttäjän rekisteröinti ja kokemus",
+       "rcfilters-filtergroup-user-experience-level": "Käyttäjän rekisteröinti ja kokemus",
        "rcfilters-filter-user-experience-level-registered-label": "Rekisteröitynyt",
        "rcfilters-filter-user-experience-level-registered-description": "Sisäänkirjautuneet muokkaajat.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Rekisteröimätön",
        "rcfilters-hideminor-conflicts-typeofchange-global": "”Pienet muutokset” -suodatin on ristiriidassa yhden tai useamman Muutoksen tyyppi -suodattimen kanssa, koska joitain muutostyyppejä ei voida pitää ”pieninä”. Ristiriidassa oleva suodatin on merkittynä Aktiivisissa suodattimissa, yläpuolella.",
        "rcfilters-hideminor-conflicts-typeofchange": "Joitain muutostyyppejä ei voida määrittää ”pieneksi”, joten tämä suodatin on ristiriidassa seuraavien Muutoksen tyyppi suodattimien kanssa: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "”Muutoksen tyyppi” on ristiriidassa ”Pienet muutokset” -suodattimen kanssa. Joitain muutostyyppejä ei voida merkitä ”pieniksi”.",
-       "rcfilters-filtergroup-lastRevision": "Viimeisimmät versiot",
+       "rcfilters-filtergroup-lastrevision": "Viimeisimmät versiot",
        "rcfilters-filter-lastrevision-label": "Viimeisin versio",
        "rcfilters-filter-lastrevision-description": "Vain viimeisin muutos sivuun.",
        "rcfilters-filter-previousrevision-label": "Ei viimeisin muutos",
        "rcfilters-watchlist-edit-watchlist-button": "Muokkaa tarkkailemiasi sivuja",
        "rcfilters-watchlist-showupdated": "Muutokset sivuihin, joilla et ole vieraillut sen jälkeen kun muutokset on tehty, on <strong>lihavoitu</strong> ja värimerkitty.",
        "rcfilters-preference-label": "Käytä ilman JavaScriptiä toimivaa käyttöliittymää",
-       "rcfilters-preference-help": "Lataa tuoreimmat muutokset -näkymän ilman suodattimia tai korostustoimintoa.",
+       "rcfilters-preference-help": "Lataa tuoreimmat muutokset -näkymän ilman suodattimien haku- tai korostustoimintoa.",
        "rcfilters-watchlist-preference-label": "Käytä ilman JavaScriptiä toimivaa käyttöliittymää",
-       "rcfilters-watchlist-preference-help": "Lataa tarkkailulistan ilman suodattimia tai korostustoimintoa.",
+       "rcfilters-watchlist-preference-help": "Lataa tarkkailulistan ilman suodattimien haku- tai korostustoimintoa.",
        "rcfilters-filter-showlinkedfrom-label": "Näytä muutokset sivuilla, jonne on linkki sivulta",
        "rcfilters-filter-showlinkedfrom-option-label": "<strong>Sivut, joihin linkitetään</strong> valitulta sivulta",
        "rcfilters-filter-showlinkedto-label": "Näytä muutokset sivuilla, joista on linkki sivulle",
        "minoreditletter": "p",
        "newpageletter": "U",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|tarkkaileva käyttäjä|tarkkailevaa käyttäjää}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|tavu|tavua}} muutosten jälkeen",
        "newsectionsummary": "/* $1 */ uusi osio",
        "rc-enhanced-expand": "Näytä yksityiskohdat",
        "upload-form-label-own-work": "Tämä on oma työni",
        "upload-form-label-infoform-categories": "Luokat",
        "upload-form-label-infoform-date": "Päivämäärä",
-       "upload-form-label-own-work-message-generic-local": "Vakuutan, että tallennan tämän tiedoston noudattaen sivustolla {{SITENAME}} voimassa olevia käyttöehtoja sekä lisenssejä koskevia käytäntöjä.",
-       "upload-form-label-not-own-work-message-generic-local": "Jos et kykene tallentamaan tätä tiedostoa noudattaen niitä käytäntöjä, jotka ovat voimassa sivustolla {{SITENAME}}, sulje tämä dialogi ja kokeile jotain toista menetelmää.",
+       "upload-form-label-own-work-message-generic-local": "Vakuutan, että tallennan tämän tiedoston noudattaen {{GRAMMAR:inessive|{{SITENAME}}}} voimassa olevia käyttöehtoja sekä lisenssejä koskevia käytäntöjä.",
+       "upload-form-label-not-own-work-message-generic-local": "Jos et kykene tallentamaan tätä tiedostoa noudattaen niitä käytäntöjä, jotka ovat voimassa {{GRAMMAR:inessive|{{SITENAME}}}}, sulje tämä dialogi ja kokeile jotain toista menetelmää.",
        "upload-form-label-not-own-work-local-generic-local": "Voit myös kokeilla [[Special:Upload|yleistä tallentamista]].",
        "upload-form-label-own-work-message-generic-foreign": "Ymmärrän, että olen tallentamassa tätä tiedostoa yhteiseen mediasäilöön. Vakuutan, että teen tämän noudattaen asiaankuuluvia käyttöehtoja ja lisenssejä koskevia käytäntöjä.",
        "upload-form-label-not-own-work-message-generic-foreign": "Jos et kykene tallentamaan tätä tiedostoa noudattaen niitä käytäntöjä, jotka ovat voimassa yhteisessä mediasäilössä, sulje tämä dialogi ja kokeile jotain toista menetelmää.",
-       "upload-form-label-not-own-work-local-generic-foreign": "Voit myös kokeilla [[Special:Upload|tallennussivua sivustolla {{SITENAME}}]]. Saattaa olla, että tämän tiedoston tallentaminen sinne on mahdollista siellä voimassa olevien käytäntöjen mukaisesti.",
+       "upload-form-label-not-own-work-local-generic-foreign": "Voit myös kokeilla [[Special:Upload|tallennussivua {{GRAMMAR:inessive|{{SITENAME}}}}]]. Saattaa olla, että tämän tiedoston tallentaminen sinne on mahdollista siellä voimassa olevien käytäntöjen mukaisesti.",
        "backend-fail-stream": "Tiedoston $1 virtauttaminen epäonnistui.",
        "backend-fail-backup": "Tiedostoa $1 ei voitu varmuuskopioida.",
        "backend-fail-notexists": "Tiedostoa $1 ei ole olemassa.",
        "img-auth-nopathinfo": "Polkutiedot puuttuvat.\nPalvelimesi tulee olla määritelty välittämään REQUEST_URI- ja/tai PATH_INFO-muuttujat.\nJos näin on, kokeile ottaa $wgUsePathInfo käyttöön.\nLisätietoja löytyy sivulta https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Pyydetty polku ei ole asetuksissa tiedostojen tallennushakemistona.",
        "img-auth-badtitle": "”$1” ei kelpaa oikean otsikon muodostamiseen.",
-       "img-auth-nologinnWL": "Et ole kirjautunut sisään ja tiedosto ”$1” ei ole sallittujen tiedostojen luettelossa.",
        "img-auth-nofile": "Tiedostoa ”$1” ei ole.",
        "img-auth-isdir": "Yrität päästä hakemistoon ”$1”.\nVain tiedostoihin pääsy on sallittu.",
        "img-auth-streaming": "Toistetaan tiedostoa ”$1”.",
        "emailuser-title-target": "Lähetä sähköpostia tälle {{GENDER:$1|käyttäjälle}}",
        "emailuser-title-notarget": "Lähetä sähköpostia käyttäjälle",
        "emailpagetext": "Jos tämä {{GENDER:$1|käyttäjä}} on antanut asetuksissaan kelvollisen sähköpostiosoitteen, alla olevalla lomakkeella voit lähettää hänelle viestin. [[Special:Preferences|Omissa asetuksissasi]] annettu sähköpostiosoite näkyy sähköpostin lähettäjän osoitteena, jotta vastaanottaja voi suoraan vastata viestiin.",
-       "defemailsubject": "Sähköpostia käyttäjältä $1 sivustolta {{SITENAME}}",
+       "defemailsubject": "Sähköpostia käyttäjältä $1 {{GRAMMAR:elative|{{SITENAME}}}}",
        "usermaildisabled": "Käyttäjien sähköposti poistettu käytöstä",
        "usermaildisabledtext": "Et voi lähettää sähköpostia muille käyttäjille tässä wikissä",
        "noemailtitle": "Ei sähköpostiosoitetta",
        "emailccsubject": "Kopio lähettämästäsi viestistä osoitteeseen $1: $2",
        "emailsent": "Sähköposti lähetetty",
        "emailsenttext": "Sähköpostiviestisi on lähetetty.",
-       "emailuserfooter": "Tämän sähköpostin {{GENDER:$1|lähetti}} $1 vastaanottajalle {{GENDER:$2|$2}} käyttämällä ”{{int:emailuser}}” -toimintoa {{GRAMMAR:inessive|{{SITENAME}}}}. Jos vastaat tähän sähköpostiin, sinun sähköpostiviestisi lähetetään suoraan {{GENDER:$1|alkuperäiselle lähettäjälle}} ja samalla paljastetaan {{GENDER:$2|sinun}} sähköpostiosoitteesi {{GENDER:$1|hänelle}}.",
+       "emailuserfooter": "Tämän sähköpostin {{GENDER:$1|lähetti}} $1 vastaanottajalle {{GENDER:$2|$2}} käyttämällä ”{{int:emailuser}}” -toimintoa {{GRAMMAR:inessive|{{SITENAME}}}}. Jos vastaat tähän sähköpostiin, sähköpostiviestisi lähetetään suoraan {{GENDER:$1|alkuperäiselle lähettäjälle}} ja samalla paljastetaan {{GENDER:$2|sinun}} sähköpostiosoitteesi {{GENDER:$1|hänelle}}.",
        "usermessage-summary": "Jätetään järjestelmäviesti.",
        "usermessage-editor": "Järjestelmäviestittäjä",
        "watchlist": "Tarkkailulista",
        "watcherrortext": "Sivun ”$1” tarkkailulista-asetusten muutoksissa tapahtui virhe.",
        "enotif_reset": "Merkitse kaikki sivut nähdyiksi",
        "enotif_impersonal_salutation": "{{GRAMMAR:genitive|{{SITENAME}}}} käyttäjä",
-       "enotif_subject_deleted": "{{GENDER:$2|$2}} poisti {{GRAMMAR:elative|{{SITENAME}}}} sivun $1",
-       "enotif_subject_created": "{{GENDER:$2|$2}} loi {{GRAMMAR:illative|{{SITENAME}}}} sivun $1",
-       "enotif_subject_moved": "{{GENDER:$2|$2}} siirsi {{GRAMMAR:inessive|{{SITENAME}}}} sivun $1",
-       "enotif_subject_restored": "{{GENDER:$2|$2}} palautti {{GRAMMAR:inessive|{{SITENAME}}}} sivun $1",
-       "enotif_subject_changed": "{{GENDER:$2|$2}} muutti {{GRAMMAR:inessive|{{SITENAME}}}} sivua $1",
-       "enotif_body_intro_deleted": "{{GENDER:$2|$2}} poisti {{GRAMMAR:elative|{{SITENAME}}}} sivun $1 $PAGEEDITDATE ($3).",
+       "enotif_subject_deleted": "$2 {{GENDER:$2|poisti}} {{GRAMMAR:elative|{{SITENAME}}}} sivun $1",
+       "enotif_subject_created": "$2 {{GENDER:$2|loi}} {{GRAMMAR:illative|{{SITENAME}}}} sivun $1",
+       "enotif_subject_moved": "$2 {{GENDER:$2|siirsi}} {{GRAMMAR:inessive|{{SITENAME}}}} sivun $1",
+       "enotif_subject_restored": "$2 {{GENDER:$2|palautti}} {{GRAMMAR:inessive|{{SITENAME}}}} sivun $1",
+       "enotif_subject_changed": "$2 {{GENDER:$2|muutti}} {{GRAMMAR:inessive|{{SITENAME}}}} sivua $1",
+       "enotif_body_intro_deleted": "$2 {{GENDER:$2|poisti}} {{GRAMMAR:elative|{{SITENAME}}}} sivun $1 $PAGEEDITDATE ($3).",
        "enotif_body_intro_created": "{{GENDER:$2|$2}} loi {{GRAMMAR:inessive|{{SITENAME}}}} sivun $1 $PAGEEDITDATE. Sivun nykyinen versio on osoitteessa $3.",
        "enotif_body_intro_moved": "{{GENDER:$2|$2}} siirsi {{GRAMMAR:inessive|{{SITENAME}}}} sivun $1 $PAGEEDITDATE. Sivun nykyinen versio on osoitteessa $3.",
        "enotif_body_intro_restored": "{{GENDER:$2|$2}} palautti {{GRAMMAR:inessive|{{SITENAME}}}} sivun $1 $PAGEEDITDATE. Sivun nykyinen versio on osoitteessa $3.",
        "delete-confirm": "Poista ”$1”",
        "delete-legend": "Sivun poisto",
        "historywarning": "<strong>Varoitus:</strong> Sivulla, jota olet poistamassa, on muokkaushistoriaa ja sitä on muokattu $1 {{PLURAL:$1|kerran|kertaa}}:",
-       "historyaction-submit": "Näytä",
+       "historyaction-submit": "Näytä versiot",
        "confirmdeletetext": "Olet poistamassa sivun ja kaiken sen historian.\nVahvista, että olet aikeissa tehdä tämän ja että ymmärrät teon seuraukset ja teet poiston [[{{MediaWiki:Policy-url}}|käytäntöjen]] mukaisesti.",
        "actioncomplete": "Toiminto suoritettu",
        "actionfailed": "Toiminto epäonnistui",
        "deletereasonotherlist": "Muu syy",
        "deletereason-dropdown": "* Yleiset poistosyyt\n** Spam tai mainossivu\n** Vandalismi\n** Tekijänoikeusrikkomus\n** Sivun tekijän pyyntö\n** Virheellinen ohjaus",
        "delete-edit-reasonlist": "Muokkaa poistosyitä",
-       "delete-toobig": "Tällä sivulla on pitkä muokkaushistoria, yli $1 {{PLURAL:$1|versio|versiota}}. \nTämänkaltaisten sivujen poistamista on rajoitettu. Tällä ehkäistään sivuston {{SITENAME}} vaurioitumista tahattomasti.",
-       "delete-warning-toobig": "Tällä sivulla on pitkä muutoshistoria – yli $1 {{PLURAL:$1|versio|versiota}}. Näin suurien muutoshistorioiden poistaminen voi haitata sivuston suorituskykyä.",
+       "delete-toobig": "Tällä sivulla on pitkä muokkaushistoria, yli $1 {{PLURAL:$1|versio|versiota}}. \nTämänkaltaisten sivujen poistamista on rajoitettu. Tällä ehkäistään {{GRAMMAR:genitive|{{SITENAME}}}} vaurioitumista tahattomasti.",
+       "delete-warning-toobig": "Tällä sivulla on pitkä muutoshistoria – yli $1 {{PLURAL:$1|versio|versiota}}. Näin suurien muutoshistorioiden poistaminen voi haitata {{GRAMMAR:genitive|{{SITENAME}}}} suorituskykyä.",
        "deleteprotected": "Et voi poistaa tätä sivua, koska se on suojattu.",
        "deleting-backlinks-warning": "<strong>Varoitus:</strong> Sivulle, jota olet poistamassa, johtaa [[Special:WhatLinksHere/{{FULLPAGENAME}}|linkkejä muilta sivuilta]], taikka sivu on sisällytetty muuhun sivuun.",
        "deleting-subpages-warning": "<strong>Varoitus:</strong> Sivu jota olet poistamassa on [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|alasivu|$1 alasivua|51=yli 50 alasivua}}]].",
        "rollback": "palauta aiempaan versioon",
+       "rollback-confirmation-confirm": "Vahvista:",
+       "rollback-confirmation-yes": "Tee palautus",
+       "rollback-confirmation-no": "Peruuta",
        "rollbacklink": "palauta",
        "rollbacklinkcount": "palauta $1 {{PLURAL:$1|muutos|muutosta}}",
        "rollbacklinkcount-morethan": "palauta yli $1 {{PLURAL:$1|muutos|muutosta}}",
        "revertpage": "Käyttäjän [[Special:Contributions/$2|$2]] ([[User talk:$2|keskustelu]]) muokkaukset kumottiin ja sivu palautettiin viimeisimpään käyttäjän [[User:$1|$1]] tekemään versioon.",
        "revertpage-nouser": "Käyttäjän (käyttäjänimi poistettu) muokkaukset kumottiin ja sivu palautettiin viimeisimpään käyttäjän {{GENDER:$1|[[User:$1|$1]]}} tekemään versioon",
        "rollback-success": "Käyttäjän {{GENDER:$3|$1}} tekemät muokkaukset kumottiin ja sivu palautettiin käyttäjän {{GENDER:$4|$2}} versioon.",
-       "rollback-success-notify": "Kumottiin käyttäjän $1 muokkaukset; palautettiin viimeiseen käyttäjän $2 versioon. [$3 Näytä muutokset]",
        "sessionfailure-title": "Istuntovirhe",
        "sessionfailure": "Näyttää siltä, että tämänhetkisessä istunnossasi on jokin ongelma; \ntämä toiminto on peruutettu varotoimena istunnon kaappaamisen estämiseksi.\nLähetä lomake uudelleen.",
        "changecontentmodel": "Muuta sivun sisältömallia",
        "mycontris": "Muokkaukset",
        "anoncontribs": "Muokkaukset",
        "contribsub2": "Käyttäjän {{GENDER:$3|$1}} ($2) muokkaukset",
+       "contributions-subtitle": "Käyttäjän {{GENDER:$3|$1}} muokkaukset",
        "contributions-userdoesnotexist": "Käyttäjätunnusta ”$1” ei ole rekisteröity.",
+       "negative-namespace-not-supported": "Negatiivisia arvoja sisältäviä nimiavaruuksia ei tueta.",
        "nocontribs": "Näihin ehtoihin sopivia muokkauksia ei löytynyt.",
        "uctop": "uusin",
        "month": "Alkaen kuukaudesta (ja aiemmin):",
        "ipb-confirm": "Vahvista esto",
        "ipb-sitewide": "Sivuston laajuinen",
        "ipb-partial": "Osittainen",
+       "ipb-partial-help": "Tietyt sivut tai nimiavaruudet.",
        "ipb-pages-label": "Sivut",
        "ipb-namespaces-label": "Nimiavaruudet",
        "badipaddress": "IP-osoite on väärin muotoiltu.",
        "blocklist-userblocks": "Piilota tunnusten estot",
        "blocklist-tempblocks": "Piilota väliaikaiset estot",
        "blocklist-addressblocks": "Piilota yksittäiset IP-estot",
+       "blocklist-type": "Tyyppi:",
+       "blocklist-type-opt-all": "Kaikki",
+       "blocklist-type-opt-sitewide": "Sivuston laajuiset",
+       "blocklist-type-opt-partial": "Osittaiset",
        "blocklist-rangeblocks": "Piilota avaruusestot",
        "blocklist-timestamp": "Päiväys",
        "blocklist-target": "Kohde",
        "ip_range_toolow": "IP-alueet eivät käytännöllisesti katsoen ole sallittuja.",
        "proxyblocker": "Välityspalvelinesto",
        "proxyblockreason": "IP-osoitteestasi on estetty muokkaukset, koska se on avoin välityspalvelin. Ota yhteyttä Internet-palveluntarjoajaasi tai tekniseen tukeen ja kerro heille tästä tietoturvaongelmasta.",
-       "sorbsreason": "IP-osoitteesi on listattu avoimena välityspalvelimena DNSBL:n mustalla listalla sivustolla {{SITENAME}}.",
-       "sorbs_create_account_reason": "IP-osoitteesi on listattu avoimena välityspalvelimena DNSBL:n mustalla listalla sivustolla {{SITENAME}}. \nEt voi luoda käyttäjätunnusta.",
+       "sorbsreason": "IP-osoitteesi on listattu avoimena välityspalvelimena DNSBL:n mustalla listalla {{GRAMMAR:inessive|{{SITENAME}}}}.",
+       "sorbs_create_account_reason": "IP-osoitteesi on listattu avoimena välityspalvelimena DNSBL:n mustalla listalla {{GRAMMAR:inessive|{{SITENAME}}}}.\nEt voi luoda käyttäjätunnusta.",
        "softblockrangesreason": "Anonyymit muokkaukset eivät ole sallittuja IP-osoitteestasi ($1). Ole hyvä ja kirjaudu.",
        "xffblockreason": "Yhteydet IP-osoitteesta, joka löytyy sinun tai käyttämäsi välipalvelimen X-Forwarded-For-otsakkeesta, on estetty. Alkuperäinen estämisen syy oli: $1",
        "cant-see-hidden-user": "Käyttäjä, jota yrität estää, on jo estetty ja käyttäjänimi on piilotettu. \nKoska sinulla ei ole hideuser-oikeutta, et voi nähdä tai muuttaa käyttäjän estoasetuksia.",
        "allmessagesdefault": "Viestin tekstin perusmuoto",
        "allmessagescurrent": "Viestin teksti tällä hetkellä",
        "allmessagestext": "Tämä on luettelo järjestelmäviesteistä, jotka ovat saatavilla MediaWiki-nimiavaruudessa.\nJos haluat muokata MediaWikin yleistä kotoistusta, käy [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWikin kotoistussivuilla] ja sivustolla [https://translatewiki.net translatewiki.net].",
-       "allmessagesnotsupportedDB": "Tämä sivu ei ole käytössä, koska <tt>$wgUseDatabaseMessages</tt>-asetus on pois päältä.",
+       "allmessages-not-supported-database": "Tämä sivu ei ole käytössä, koska <tt>$wgUseDatabaseMessages</tt>-asetus on pois päältä.",
        "allmessages-filter-legend": "Suodata",
        "allmessages-filter": "Suodata muutosten perusteella",
        "allmessages-filter-unmodified": "Muuttamaton",
        "confirmemail_body_set": "Joku, todennäköisesti sinä, IP-osoitteesta $1 on vaihtanut {{GRAMMAR:inessive|{{SITENAME}}}} tunnuksen $2 sähköpostiosoitteeksi tämän osoitteen.\n\nVarmenna, että tämä tunnus kuuluu sinulle ja aktivoi sähköpostitoiminnot uudelleen avaamalla seuraava linkki selaimellasi:\n\n$3\n\nJos tunnus ei kuulu sinulle, peruuta sähköpostiosoitteen varmennus avaamalla seuraava linkki:\n\n$5\n\nVarmennuskoodi vanhenee $4.",
        "confirmemail_invalidated": "Sähköpostiosoitteen varmennus peruutettiin",
        "invalidateemail": "Sähköpostiosoitteen varmennuksen peruuttaminen",
-       "notificationemail_subject_changed": "Sivuston {{SITENAME}} rekisteröity sähköpostiosoite on vaihdettu",
-       "notificationemail_subject_removed": "Sivuston {{SITENAME}} rekisteröity sähköpostiosoite on poistettu",
-       "notificationemail_body_changed": "Joku, todennäköisesti sinä, IP-osoitteesta $1 on vaihtanut tunnuksen ”$2” sähköpostiosoitteeksi ”$3” sivustolla {{SITENAME}}.\n\nJos se et ollut sinä, ota yhteyttä sivuston ylläpitäjään välittömästi.",
-       "notificationemail_body_removed": "Joku, todennäköisesti sinä, IP-osoitteesta $1 on poistanut tunnuksen ”$2” sähköpostiosoitteen sivustolla {{SITENAME}}.\n\nJos se et ollut sinä, ota yhteyttä sivuston ylläpitäjään välittömästi.",
+       "notificationemail_subject_changed": "{{GRAMMAR:genitive|{{SITENAME}}}} rekisteröity sähköpostiosoite on vaihdettu",
+       "notificationemail_subject_removed": "{{GRAMMAR:genitive|{{SITENAME}}}} rekisteröity sähköpostiosoite on poistettu",
+       "notificationemail_body_changed": "Joku, todennäköisesti sinä, IP-osoitteesta $1 on vaihtanut tunnuksen ”$2” sähköpostiosoitteeksi ”$3” {{GRAMMAR:inessive|{{SITENAME}}}}.\n\nJos se et ollut sinä, ota yhteyttä sivuston ylläpitäjään välittömästi.",
+       "notificationemail_body_removed": "Joku, todennäköisesti sinä, IP-osoitteesta $1 on poistanut tunnuksen ”$2” sähköpostiosoitteen {{GRAMMAR:inessive|{{SITENAME}}}}.\n\nJos se et ollut sinä, ota yhteyttä sivuston ylläpitäjään välittömästi.",
        "scarytranscludedisabled": "[Wikienvälinen sisällytys ei ole käytössä]",
        "scarytranscludefailed": "[Mallineen hakeminen epäonnistui: $1]",
        "scarytranscludefailed-httpstatus": "[Mallineen hakeminen epäonnistui: $1 HTTP $2]",
        "version-license-not-found": "Tälle lisäosalle ei ole saatavissa tarkkoja lisenssitietoja.",
        "version-credits-title": "Laajennuksen $1 tekijätiedot",
        "version-credits-not-found": "Tälle laajenukselle ei löytynyt yksityiskohtaisia tekijätietoja.",
-       "version-poweredby-credits": "Tämä wiki käyttää '''[https://www.mediawiki.org/ MediaWikiä]'''. Copyright © 2001–$1 $2.",
+       "version-poweredby-credits": "Tämä wiki käyttää <strong>[https://www.mediawiki.org/ MediaWikiä]</strong>. Copyright © 2001–$1 $2.",
        "version-poweredby-others": "muut",
        "version-poweredby-translators": "translatewiki.net-kääntäjät",
        "version-credits-summary": "Haluamme kiittäen mainita seuraavat henkilöt, jotka ovat osallistuneet [[Special:Version|MediaWiki-ohjelmiston]] kehittämiseen.",
        "logentry-partialblock-block-page": "the {{PLURAL:$1|page|pages}} $2",
        "logentry-partialblock-block-ns": "the {{PLURAL:$1|namespace|namespaces}} $2",
        "logentry-partialblock-block": "$1 {{GENDER:$2|blocked}} {{GENDER:$4|$3}} from editing $7 with an expiration time of $5 $6",
-       "logentry-partialblock-reblock": "$1 {{GENDER:$2|muutti}} käyttäjän {{GENDER:$4|$3}} muokkauseston asetuksia estäen muokkausten tekemisen {{PLURAL:$8||sivuihin}} $7. Eston kesto on $5 $6",
+       "logentry-partialblock-reblock": "$1 {{GENDER:$2|muutti}} käyttäjän {{GENDER:$4|$3}} muokkauseston asetuksia estäen muokkausten tekemisen $7. Eston kesto on $5 $6",
        "logentry-non-editing-block-block": "$1 {{GENDER:$2|esti}} käyttäjää {{GENDER:$4|$3}} suorittamasta määrättyjä toimenpiteitä (lukuun ottamatta muokkaamista). Eston kesto on $5 $6",
        "logentry-non-editing-block-reblock": "$1 {{GENDER:$2|muutti}} käyttäjän {{GENDER:$4|$3}} toimintaeston asetuksia, jotka koskevat määrättyjä toimenpiteitä. Eston kesto on $5 $6",
        "logentry-suppress-block": "$1 {{GENDER:$2|esti}} käyttäjän {{GENDER:$4|$3}}. Eston kesto on $5 $6",
        "logentry-rights-autopromote": "Käyttäjän $1 oikeudet {{GENDER:$2|muuttuivat}} automaattisesti ryhmistä $4 ryhmiin $5",
        "logentry-upload-upload": "$1 {{GENDER:$2|tallensi}} tiedoston $3",
        "logentry-upload-overwrite": "$1 {{GENDER:$2|tallensi}} uuden version tiedostosta $3",
-       "logentry-upload-revert": "$1 {{GENDER:$2|tallensi}} tiedoston $3",
+       "logentry-upload-revert": "$1 {{GENDER:$2|palautti}} tiedoston $3 vanhaan versioon",
        "log-name-managetags": "Merkkausten hallinnan loki",
        "log-description-managetags": "Tällä sivulla on luettelo tehtävistä, jotka koskevat [[Special:Tags|merkkauksia]]. Lokissa ovat vain ne toimenpiteet, jotka ylläpitäjä on suorittanut käsin. Merkkauksia voi syntyä ja poistua myös wikin ohjelmiston kautta eivätkä ne näy tässä lokissa.",
        "logentry-managetags-create": "$1 {{GENDER:$2|on luonut}} merkkauksen ”$4”",
        "expand_templates_generate_xml": "Näytä XML-jäsennyspuu",
        "expand_templates_generate_rawhtml": "Näytä raaka HTML",
        "expand_templates_preview": "Esikatselu",
-       "expand_templates_preview_fail_html": "<em>Koska sivustolla {{SITENAME}} on käytössä suodattamaton HTML-koodi ja koska istunnon tiedot ovat kadonneet, esikatselu on piilotettu JavaScript-hyökkäyksien torjumiseksi.</em>\n\n<strong>Jos yritit esikatsella sivua, yritä uudestaan.</strong>\nJos esikatselu ei vieläkään toimi, yritä [[Special:UserLogout|kirjautua ulos]] ja sitten kirjautua uudestaan sisään. Tarkista myös, että selaimesi sallii evästeet tältä sivustolta.",
-       "expand_templates_preview_fail_html_anon": "<em>Koska sivustolla {{SITENAME}} on käytössä puhdas HTML-koodi ja koska et ole kirjautunut sisään, esikatselu on piilotettu JavaScript-hyökkäyksien torjumiseksi.</em>\n\n<strong>Jos olet oikealla asialla, [[Special:UserLogin|kirjaudu sisään]] ja yritä uudestaan.</strong>",
+       "expand_templates_preview_fail_html": "<em>Koska {{GRAMMAR:inessive|{{SITENAME}}}} on käytössä suodattamaton HTML-koodi ja koska istunnon tiedot ovat kadonneet, esikatselu on piilotettu JavaScript-hyökkäyksien torjumiseksi.</em>\n\n<strong>Jos yritit esikatsella sivua, yritä uudestaan.</strong>\nJos esikatselu ei vieläkään toimi, yritä [[Special:UserLogout|kirjautua ulos]] ja sitten kirjautua uudestaan sisään. Tarkista myös, että selaimesi sallii evästeet tältä sivustolta.",
+       "expand_templates_preview_fail_html_anon": "<em>Koska {{GRAMMAR:inessive|{{SITENAME}}}} on käytössä puhdas HTML-koodi ja et ole kirjautunut sisään, esikatselu on piilotettu JavaScript-hyökkäyksien torjumiseksi.</em>\n\n<strong>Jos olet oikealla asialla, [[Special:UserLogin|kirjaudu sisään]] ja yritä uudestaan.</strong>",
        "expand_templates_input_missing": "Sinun on annettava ainakin jotakin wikitekstiä syötteeksi.",
        "pagelanguage": "Sivun kielen vaihto",
        "pagelang-name": "Sivu",
        "log-description-pagelang": "Tämä on loki, johon merkitään muutokset sivujen kieliasetuksissa.",
        "logentry-pagelang-pagelang": "$1 {{GENDER:$2|muutti}} kielen sivulla $3 kielestä $4 kieleksi $5.",
        "default-skin-not-found": "Hupsista! Oletuksena tuleva ulkoasu wikillesi, joka on määritelty koodissa <code dir=\"ltr\">$wgDefaultSkin</code> muotoon <code>$1</code>, ei ole saatavilla.\n\nAlla on ohjeet englannin kielellä:\n\nYour installation seems to include the following {{PLURAL:$4|skin|skins}}. See [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual: Skin configuration] for information how to enable {{PLURAL:$4|it|them and choose the default}}.\n\n$2\n\n; If you have just installed MediaWiki:\n: You probably installed from git, or directly from the source code using some other method. This is expected. Try installing some skins from [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org's skin directory], by:\n:* Downloading the [https://www.mediawiki.org/wiki/Download tarball installer], which comes with several skins and extensions. You can copy and paste the <code>skins/</code> directory from it.\n:* Downloading individual skin tarballs from [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* [https://www.mediawiki.org/wiki/Download_from_Git#Using_Git_to_download_MediaWiki_skins Using Git to download skins].\n: Doing this should not interfere with your git repository if you're a MediaWiki developer.\n\n; If you have just upgraded MediaWiki:\n: MediaWiki 1.24 and newer no longer automatically enables installed skins (see [https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery Manual: Skin autodiscovery]). You can paste the following {{PLURAL:$5|line|lines}} into <code>LocalSettings.php</code> to enable {{PLURAL:$5|the|all}} installed {{PLURAL:$5|skin|skins}}:\n\n<pre dir=\"ltr\">$3</pre>\n\n; If you have just modified <code>LocalSettings.php</code>:\n: Double-check the skin names for typos.",
-       "default-skin-not-found-no-skins": "Hupsista! Oletusulkoasua sinun wikillesi ei ole saatavilla. Se on määritelty ulkoasuksi <code>$1</code> kohteessa <code>$wgDefaultSkin</code>.\n\nAlla on ohjeet englannin kielellä:\n\nYou have no installed skins.\n\n; If you have just installed or upgraded MediaWiki:\n: You probably installed from git, or directly from the source code using some other method. This is expected. MediaWiki 1.24 and newer doesn't include any skins in the main repository. Try installing some skins from [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org's skin directory], by:\n:* Downloading the [https://www.mediawiki.org/wiki/Download tarball installer], which comes with several skins and extensions. You can copy and paste the <code>skins/</code> directory from it.\n:* Downloading individual skin tarballs from [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* [https://www.mediawiki.org/wiki/Download_from_Git#Using_Git_to_download_MediaWiki_skins Using Git to download skins].\n: Doing this should not interfere with your git repository if you're a MediaWiki developer. See [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual: Skin configuration] for information how to enable skins and choose the default.",
+       "default-skin-not-found-no-skins": "Hupsista! Oletusulkoasua wikillesi ei ole saatavilla. Se on määritelty ulkoasuksi <code>$1</code> kohteessa <code>$wgDefaultSkin</code>.\n\nAlla on ohjeet englannin kielellä:\n\nYou have no installed skins.\n\n; If you have just installed or upgraded MediaWiki:\n: You probably installed from git, or directly from the source code using some other method. This is expected. MediaWiki 1.24 and newer doesn't include any skins in the main repository. Try installing some skins from [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org's skin directory], by:\n:* Downloading the [https://www.mediawiki.org/wiki/Download tarball installer], which comes with several skins and extensions. You can copy and paste the <code>skins/</code> directory from it.\n:* Downloading individual skin tarballs from [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* [https://www.mediawiki.org/wiki/Download_from_Git#Using_Git_to_download_MediaWiki_skins Using Git to download skins].\n: Doing this should not interfere with your git repository if you're a MediaWiki developer. See [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual: Skin configuration] for information how to enable skins and choose the default.",
        "default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (käytössä)",
        "default-skin-not-found-row-disabled": "* <code>$1</code> / $2 (<strong>ei käytössä</strong>)",
        "mediastatistics": "Median tilastotiedot",
        "log-action-filter-suppress-reblock": "Käyttäjätunnuksen häivyttäminen uudella estolla",
        "log-action-filter-upload-upload": "Uusi tallennus",
        "log-action-filter-upload-overwrite": "Päälletallennus",
+       "log-action-filter-upload-revert": "Palauta",
        "authmanager-authn-not-in-progress": "Varmennus ei ole käynnissä tai istunnon tiedot ovat hävinneet. Ole hyvä ja aloita uudelleen alusta.",
        "authmanager-authn-no-primary": "Annettua kirjautumistietoja ei pystytty varmentamaan.",
        "authmanager-authn-no-local-user": "Annetut kirjautumistiedot eivät kuulu millekään tämän wikin käyttäjistä.",
index 69e47a8..fb4e9ec 100644 (file)
        "minoreditletter": "s",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 ansar eftir {{PLURAL:$1|brúkara|brúkarum}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} eftir broyting",
        "newsectionsummary": "/* $1 */ nýtt innlegg",
        "rc-enhanced-expand": "Vís smálutir",
        "uploadstash-refresh": "Uppfrískað listan við fílum",
        "img-auth-accessdenied": "Atgongd noktað",
        "img-auth-badtitle": "Tað bar ikki til at gera eitt heiti útfrá \"$1\".",
-       "img-auth-nologinnWL": "Tú ert ikki ritað/ur inn, og \"$1\" er ikki á hvítalista.",
        "img-auth-nofile": "Fílan \"$1\" er ikki til",
        "img-auth-isdir": "Tú roynir at fáa atgongd til mappuna \"$1\".\nBert fílu atgongd er loyvd.",
        "img-auth-streaming": "Sendir \"$1\".",
        "allmessagesdefault": "Enskur tekstur",
        "allmessagescurrent": "Verandi tekstur",
        "allmessagestext": "Hetta er eitt yvirlit av tøkum kervisboðum í MediaWiki-navnarúmi.\nVinarliga vitja [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] og [https://translatewiki.net translatewiki.net] um tú ynskir at geva títt íkast til ta generisku MediaWiki lokalisatiónina.",
-       "allmessagesnotsupportedDB": "'''{{ns:special}}:AllMessages''' er ikki stuðlað orsakað av at '''$wgUseDatabaseMessages''' er sløkt.",
+       "allmessages-not-supported-database": "'''{{ns:special}}:AllMessages''' er ikki stuðlað orsakað av at '''$wgUseDatabaseMessages''' er sløkt.",
        "allmessages-filter-legend": "Filtur",
        "allmessages-filter-unmodified": "Óbroytt",
        "allmessages-filter-all": "Øll",
index f969845..9c48490 100644 (file)
                        "Alacabe",
                        "Eihel",
                        "Tektasc",
-                       "DSwissK"
+                       "DSwissK",
+                       "Moyogo"
                ]
        },
        "tog-underline": "Soulignement des liens :",
        "oct": "oct.",
        "nov": "nov.",
        "dec": "déc.",
-       "january-date": "{{PLURAL:$1|1=1ᵉʳ|$1}} janvier",
-       "february-date": "{{PLURAL:$1|1=1ᵉʳ|$1}} février",
-       "march-date": "{{PLURAL:$1|1=1ᵉʳ|$1}} mars",
-       "april-date": "{{PLURAL:$1|1=1ᵉʳ|$1}} avril",
-       "may-date": "{{PLURAL:$1|1=1ᵉʳ|$1}} mai",
-       "june-date": "{{PLURAL:$1|1=1ᵉʳ|$1}} juin",
-       "july-date": "{{PLURAL:$1|1=1ᵉʳ|$1}} juillet",
-       "august-date": "{{PLURAL:$1|1=1ᵉʳ|$1}} août",
-       "september-date": "{{PLURAL:$1|1=1ᵉʳ|$1}} septembre",
-       "october-date": "{{PLURAL:$1|1=1ᵉʳ|$1}} octobre",
-       "november-date": "{{PLURAL:$1|1=1ᵉʳ|$1}} novembre",
-       "december-date": "{{PLURAL:$1|1=1ᵉʳ|$1}} décembre",
+       "january-date": "{{PLURAL:$1|1=1<sup>er</sup>|$1}} janvier",
+       "february-date": "{{PLURAL:$1|1=1<sup>er</sup>|$1}} février",
+       "march-date": "{{PLURAL:$1|1=1<sup>er</sup>|$1}} mars",
+       "april-date": "{{PLURAL:$1|1=1<sup>er</sup>|$1}} avril",
+       "may-date": "{{PLURAL:$1|1=1<sup>er</sup>|$1}} mai",
+       "june-date": "{{PLURAL:$1|1=1<sup>er</sup>|$1}} juin",
+       "july-date": "{{PLURAL:$1|1=1<sup>er</sup>|$1}} juillet",
+       "august-date": "{{PLURAL:$1|1=1<sup>er</sup>|$1}} août",
+       "september-date": "{{PLURAL:$1|1=1<sup>er</sup>|$1}} septembre",
+       "october-date": "{{PLURAL:$1|1=1<sup>er</sup>|$1}} octobre",
+       "november-date": "{{PLURAL:$1|1=1<sup>er</sup>|$1}} novembre",
+       "december-date": "{{PLURAL:$1|1=1<sup>er</sup>|$1}} décembre",
        "period-am": "AM",
        "period-pm": "PM",
        "pagecategories": "{{PLURAL:$1|Catégorie|Catégories}}",
        "toc": "Sommaire",
        "showtoc": "afficher",
        "hidetoc": "masquer",
-       "collapsible-collapse": "Replier",
+       "collapsible-collapse": "Réduire",
        "collapsible-expand": "Développer",
        "confirmable-confirm": "Êtes-vous sûr{{GENDER:$1||e}} ?",
        "confirmable-yes": "Oui",
        "virus-scanfailed": "échec de l’analyse (code $1)",
        "virus-unknownscanner": "antivirus inconnu :",
        "logouttext": "<strong>Vous êtes à présent déconnecté{{GENDER:||e|(e)}}.</strong>\n\nNotez que certaines pages peuvent être encore affichées comme si vous étiez toujours connecté, jusqu’à ce que vous effaciez le cache de votre navigateur.",
+       "logging-out-notify": "Vous allez être déconnecté, veuillez attendre.",
+       "logout-failed": "Impossible de se déconnecter maintenant : $1",
        "cannotlogoutnow-title": "Impossible de se déconnecter maintenant",
        "cannotlogoutnow-text": "La déconnexion n’est pas possible en utilisant $1.",
        "welcomeuser": "Bienvenue, $1 !",
        "botpasswords-label-delete": "Supprimer",
        "botpasswords-label-resetpassword": "Réinitialiser le mot de passe",
        "botpasswords-label-grants": "Droits applicables :",
-       "botpasswords-help-grants": "Les autorisations permettent d’accéder aux droits déjà accordés à votre compte utilisateur. Activer une autorisation ici ne fournit l’accès à aucun droit que votre compte utilisateur n’aurait pas par ailleurs. Voyez le [[Special:ListGrants|tableau des autorisations]] pour plus d’information.",
+       "botpasswords-help-grants": "Les autorisations permettent d’accéder aux droits déjà accordés à votre compte utilisateur. Activer une autorisation ici ne fournit l’accès à aucun droit que votre compte utilisateur n’aurait pas par ailleurs. Voyez le [[Special:ListGrants|tableau des autorisations]] pour plus d’informations.",
        "botpasswords-label-grants-column": "Accordé",
        "botpasswords-bad-appid": "Le nom de robot « $1 » n’est pas valide.",
        "botpasswords-insert-failed": "Échec de l’ajout du nom de robot « $1 ». A-t-il déjà été ajouté ?",
        "page_first": "première",
        "page_last": "dernière",
        "histlegend": "Sélection du diff : cochez les boutons radio des versions à comparer et appuyez sur entrée ou sur le bouton en bas.<br />\nLégende : <strong>({{int:cur}})</strong> = différence avec la dernière version, <strong>({{int:last}})</strong> = différence avec la version précédente, <strong>{{int:minoreditletter}}</strong> = modification mineure.",
-       "history-fieldset-title": "Rechercher des révisions",
+       "history-fieldset-title": "Filtrer les versions",
        "history-show-deleted": "Révision supprimée uniquement",
        "histfirst": "les plus anciennes",
        "histlast": "les plus récentes",
        "historysize": "($1 octet{{PLURAL:$1||s}})",
-       "historyempty": "(vide)",
+       "historyempty": "vide",
        "history-feed-title": "Historique des versions",
        "history-feed-description": "Historique des versions pour cette page sur le wiki",
        "history-feed-item-nocomment": "$1 le $2",
        "prefs-emailconfirm-label": "Confirmation du courriel :",
        "youremail": "Courriel :",
        "username": "{{GENDER:$1|Nom d'utilisateur|Nom d'utilisatrice}} :",
-       "prefs-memberingroups": "{{GENDER:$2|Membre}} {{PLURAL:$1|du groupe|des groupes}} :",
+       "prefs-memberingroups": "{{GENDER:$2|Membre}} {{PLURAL:$1|du groupe|des groupes}}:",
        "prefs-memberingroups-type": "$1",
        "group-membership-link-with-expiry": "$1 (jusqu'à $2)",
        "prefs-registration": "Date d'inscription :",
        "right-reupload-own": "Écraser un fichier que l'on a soi-même importé",
        "right-reupload-shared": "Écraser localement des fichiers présents sur un dépôt partagé",
        "right-upload_by_url": "Importer un fichier depuis une adresse URL",
-       "right-purge": "Effacer une page du cache local sans demander de confirmation",
+       "right-purge": "Vider le cache du site pour une page",
        "right-autoconfirmed": "Ne pas être affecté par les limitations de débit liées aux adresses IP",
        "right-bot": "Être traité comme un processus automatisé",
        "right-nominornewtalk": "Ne pas déclencher la notification de nouveau message lorsqu'on effectue une modification mineure sur la page de discussion d'un utilisateur",
        "action-changetags": "ajouter et supprimer de façon arbitraire des balises sur des révisions individuelles et des entrées de journal",
        "action-deletechangetags": "supprimer des balises de la base de données",
        "action-purge": "purger cette page",
+       "action-apihighlimits": "utiliser des limites plus élevées dans les requêtes à l’API",
+       "action-autoconfirmed": "ne pas être impacté par les limites de taux basées sur l’IP",
+       "action-bigdelete": "supprimer des pages avec de grands historiques",
+       "action-blockemail": "empêcher un utilisateur d’envoyer des courriels",
+       "action-bot": "être traité comme un processus automatisé",
+       "action-editprotected": "modifier les pages protégées comme « {{int:protect-level-sysop}} »",
+       "action-editsemiprotected": "modifier des pages protégées avec le statut « {{int:protect-level-autoconfirmed}} »",
+       "action-editinterface": "modifier l’interface utilisateur",
+       "action-editusercss": "modifier les fichiers CSS d’autres utilisateurs",
+       "action-edituserjson": "modifier les fichiers JSON d’autres utilisateurs",
+       "action-edituserjs": "modifier les fichiers JavaScript d’autres utilisateurs",
+       "action-editsitecss": "modifier le CSS du site",
+       "action-editsitejson": "modifier le JSON du site",
+       "action-editsitejs": "modifier le JavaScript du site",
+       "action-editmyusercss": "modifier vos propres fichiers CSS utilisateur",
+       "action-editmyuserjson": "modifier vos propres fichiers JSON utilisateur",
+       "action-editmyuserjs": "modifier vos propres fichiers JavaScript utilisateur",
+       "action-viewsuppressed": "afficher les révisions masquées pour n’importe quel utilisateur",
+       "action-hideuser": "bloquer un nom d’utilisateur, en le masquant au public",
+       "action-ipblock-exempt": "contourner les blocages d’IP, blocages automatiques et blocages de plages d’IP",
+       "action-unblockself": "vous débloquer vous-même",
+       "action-noratelimit": "ne pas être impacté par les limites de taux",
+       "action-reupload-own": "écraser les fichiers existants que vous avez vous-même téléversés",
+       "action-nominornewtalk": "ne pas déclencher la notification de nouveaux messages lors de modifications mineures sur les pages de discussion",
+       "action-markbotedits": "marquer des modifications révoquées comme ayant été faites par un robot",
+       "action-patrolmarks": "voir les indications de relecture dans les modifications récentes",
+       "action-override-export-depth": "exporter les pages en incluant les pages liées jusqu’à une profondeur de 5 niveaux",
+       "action-suppressredirect": "ne pas créer de redirections depuis les pages sources lors du renommage",
        "nchanges": "$1 modification{{PLURAL:$1||s}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|depuis la dernière visite}}",
        "enhancedrc-history": "historique",
        "rcfilters-savedqueries-already-saved": "Ces filtres sont déjà enregistrés. Modifiez vos paramètres pour créer un nouveau Filtre enregistré.",
        "rcfilters-restore-default-filters": "Rétablir les filtres par défaut",
        "rcfilters-clear-all-filters": "Effacer tous les filtres",
-       "rcfilters-show-new-changes": "Afficher les modifications les plus récentes",
+       "rcfilters-show-new-changes": "Afficher les nouvelles modifications depuis $1",
        "rcfilters-search-placeholder": "Filtrer les modifications (utiliser le menu ou rechercher le nom d'un filtre)",
        "rcfilters-invalid-filter": "Filtre non valide",
        "rcfilters-empty-filter": "Aucun filtre actif. Toutes les contributions sont affichées.",
        "rcfilters-filter-editsbyself-description": "Vos propres contributions.",
        "rcfilters-filter-editsbyother-label": "Modifications faites par les autres.",
        "rcfilters-filter-editsbyother-description": "Toutes les modifications sauf les votres.",
-       "rcfilters-filtergroup-userExpLevel": "Enregistrement des utilisateurs et expérience",
+       "rcfilters-filtergroup-user-experience-level": "Enregistrement des utilisateurs et expérience",
        "rcfilters-filter-user-experience-level-registered-label": "Connecté",
        "rcfilters-filter-user-experience-level-registered-description": "Éditeurs connectés.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Non connecté",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Le filtre « Modifications mineures » est en conflit avec au moins un filtre de Type de modification, parce que certains types de modification ne peuvent être marqués comme « mineurs ». Les filtres en conflit sont marqués dans la zone Filtres actifs ci-dessus.",
        "rcfilters-hideminor-conflicts-typeofchange": "Certains types de modification ne peuvent pas être qualifiés de « mineurs », donc ce filtre est en conflit avec les filtres de Type de modification suivants : $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Ce filtre de Type de modification est en conflit avec le filtre « Modifications mineures ». Certains type sde modification ne peuvent pas être indiqués comme « mineurs ».",
-       "rcfilters-filtergroup-lastRevision": "Dernières révisions",
+       "rcfilters-filtergroup-lastrevision": "Dernières révisions",
        "rcfilters-filter-lastrevision-label": "Dernière révision",
        "rcfilters-filter-lastrevision-description": "Uniquement la dernière modification apportée à une page.",
        "rcfilters-filter-previousrevision-label": "Pas la dernière version",
        "newpageletter": "N",
        "boteditletter": "b",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 utilisateur{{PLURAL:$1||s}} en train de suivre]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|octet|octets}} après changement",
        "newsectionsummary": "/* $1 */ nouvelle section",
        "img-auth-nopathinfo": "Manque l'information de chemin.\nVotre serveur doit être paramétré pour transmettre la variable REQUEST_URI et/ou PATH_INFO .\nSi c'est le cas, essayez d'activer $wgUsePathInfo.\nVoir https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Le chemin demandé n'est pas le répertoire d'import configuré.",
        "img-auth-badtitle": "Impossible de construire un titre valide à partir de « $1 ».",
-       "img-auth-nologinnWL": "Vous n'êtes pas connecté et « $1 » n'est pas dans la liste blanche.",
        "img-auth-nofile": "Le fichier « $1 » n'existe pas.",
        "img-auth-isdir": "Vous essayez d'accéder au répertoire « $1 ».\nSeul l'accès aux fichiers est permis.",
        "img-auth-streaming": "Lecture en continu de « $1 ».",
        "movethispage": "Renommer cette page",
        "unusedimagestext": "Les fichiers suivants existent, mais ne sont inclus dans aucune page.\nVeuillez noter que d’autres sites peuvent accéder à ces fichiers à l’aide de liens directs (URLs), et donc qu’un fichier peut être listé ici alors qu’il est utilisé par ces sites.",
        "unusedimagestext-categorizedimgisused": "Les fichiers suivants existent mais ne sont inclus dans aucune page. Les images catégorisées sont considérées comme utilisées malgré qu'elles ne soient pas incluses dans aucune page.\nVeuillez noter que les autres sites web peuvent créer un lien vers un fichier à l'aide d'une URL directe, et donc peuvent encore être listés ici malgré qu'ils soient encore utilisés.",
-       "unusedcategoriestext": "Les pages de catégories suivantes existent, mais aucune page ou catégorie ne les utilise.",
+       "unusedcategoriestext": "Les pages de catégories suivantes existent, mais ne sont utilisées par aucune autre page ni catégorie.",
        "notargettitle": "Pas de cible",
        "notargettext": "Vous n'avez pas indiqué une page ou un utilisateur sur lequel vous souhaitez effectuer cette action.",
        "nopagetitle": "Page cible inexistante",
        "cachedspecial-refresh-now": "Voir le plus récent.",
        "categories": "Liste des catégories",
        "categories-submit": "Lister",
-       "categoriespagetext": "Sur le wiki, {{PLURAL:$1|la catégorie suivante existe et peut ou non être inutilisée|Les catégories suivantes existent et peuvent ou non être inutilisées}}.\nVoir aussi [[Special:WantedCategories|Les catégories demandées]].",
+       "categoriespagetext": "{{PLURAL:$1|La catégorie suivante existe|Les catégories suivantes existent}} sur le wiki, et {{PLURAL:$1|peut être inutilisée|peuvent être inutilisées}} ou non.\nVoir aussi [[Special:WantedCategories|les catégories les plus demandées]].",
        "categoriesfrom": "Afficher les catégories à partir de :",
        "deletedcontributions": "Contributions supprimées",
        "deletedcontributions-title": "Contributions supprimées",
        "delete-confirm": "Supprimer « $1 »",
        "delete-legend": "Supprimer",
        "historywarning": "<strong>Attention :</strong> la page que vous êtes sur le point de supprimer a un historique avec $1 {{PLURAL:$1|version|versions}} :",
-       "historyaction-submit": "Lister",
+       "historyaction-submit": "Afficher les versions",
        "confirmdeletetext": "Vous êtes sur le point de supprimer une page ou un fichier, ainsi que toutes ses versions antérieures historisées. Veuillez confirmer que c’est bien là ce que vous voulez faire, que vous en comprenez les conséquences et que vous faites ceci en accord avec les [[{{MediaWiki:Policy-url}}|règles internes]].",
        "actioncomplete": "Action effectuée",
        "actionfailed": "L'action a échoué",
        "deleting-backlinks-warning": "<strong>Attention :</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|D’autres pages]] lient vers ou incluent la page que vous allez supprimer.",
        "deleting-subpages-warning": "<strong>Attention :</strong> la page que vous essayez de supprimer possède  [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|une sous-page|$1 sous-pages|51=plus de 50 sous-pages}}]].",
        "rollback": "Révoquer les modifications",
+       "rollback-confirmation-confirm": "Veuillez confirmer :",
+       "rollback-confirmation-yes": "Révoquer",
+       "rollback-confirmation-no": "Annuler",
        "rollbacklink": "révoquer",
        "rollbacklinkcount": "révoquer $1 {{PLURAL:$1|modification|modifications}}",
        "rollbacklinkcount-morethan": "révoquer plus de $1 {{PLURAL:$1|modification|modifications}}",
        "revertpage": "Révocation des modifications de [[Special:Contributions/$2|$2]] ([[User talk:$2|discussion]]) vers la dernière version de [[User:$1|$1]]",
        "revertpage-nouser": "Révocation des modifications par un utilisateur masqué à la dernière version par {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Révocation des modifications effectuées par {{GENDER:$3|$1}} ;\nrétablissement de la dernière version par {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Modifications annulées par $1 ;\nretour à la dernière révision par $2. [$3 Voir les changements]",
        "sessionfailure-title": "Erreur de session",
        "sessionfailure": "Votre session de connexion semble avoir des problèmes ;\ncette action a été annulée en prévention d'un piratage de session.\nVeuillez soumettre le formulaire de nouveau.",
        "changecontentmodel": "Modifier le modèle de contenu d’une page",
        "mycontris": "Contributions",
        "anoncontribs": "Contributions",
        "contribsub2": "Pour {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "Pour {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "Le compte d’utilisateur « $1 » n’est pas enregistré.",
        "negative-namespace-not-supported": "Les espaces de noms avec des valeurs négatives ne sont pas supportés.",
        "nocontribs": "Aucune modification correspondant à ces critères n'a été trouvée.",
        "blocklist-userblocks": "Masquer les blocages de comptes",
        "blocklist-tempblocks": "Masquer les blocages temporaires",
        "blocklist-addressblocks": "Masquer les blocages d’adresses IP uniques",
+       "blocklist-type": "Type :",
+       "blocklist-type-opt-all": "Tous",
+       "blocklist-type-opt-sitewide": "Site entier",
+       "blocklist-type-opt-partial": "Partiel",
        "blocklist-rangeblocks": "Masquer les blocages sur intervalles",
        "blocklist-timestamp": "Date et heure",
        "blocklist-target": "Cible",
        "blocklist-editing-page": "pages",
        "blocklist-editing-ns": "espaces de noms",
        "ipblocklist-empty": "La liste des adresses IP bloquées est actuellement vide.",
-       "ipblocklist-no-results": "L'adresse IP ou l'utilisateur demandé n'est pas bloqué.",
+       "ipblocklist-no-results": "Aucun bloc correspondant trouvé pour l'adresse IP ou le nom d'utilisateur demandé.",
        "blocklink": "bloquer",
        "unblocklink": "débloquer",
        "change-blocklink": "modifier le blocage",
+       "empty-username": "(aucun nom d’utilisateur disponible)",
        "contribslink": "contributions",
        "emaillink": "envoyer un courriel",
        "autoblocker": "Vous avez été bloqué automatiquement parce que votre adresse IP a été récemment utilisée par « [[User:$1|$1]] ».\nLe motif fourni pour le blocage de $1 est « $2 »",
        "ip_range_toolarge": "Les plages de blocage plus grandes que /$1 ne sont pas autorisées.",
        "ip_range_exceeded": "L'intervalle des adresses IP est plus grand l'intervalle maximum. Intervalle autorisé : /$1 .",
        "ip_range_toolow": "Les intervalles d'adresses IP ne sont effectivement pas autorisés.",
-       "proxyblocker": "Bloqueur de mandataires",
-       "proxyblockreason": "Votre adresse IP a été bloquée car il s’agit d’un mandataire ouvert.\nVeuillez contacter votre fournisseur d’accès Internet ou votre soutien technique et l’informer de ce sérieux problème de sécurité.",
+       "proxyblocker": "Bloqueur de serveurs mandataires",
+       "proxyblockreason": "Votre adresse IP a été bloquée car c'est celle d’un serveur mandataire ouvert.\nVeuillez contacter votre fournisseur d’accès à Internet ou votre service d’assistance technique et l’informer de ce sérieux problème de sécurité.",
        "sorbsreason": "Votre adresse IP est listée comme mandataire ouvert dans le DNSBL utilisé par {{SITENAME}}.",
        "sorbs_create_account_reason": "Votre adresse IP est listée comme mandataire ouvert dans le DNSBL utilisé par {{SITENAME}}.\nVous ne pouvez pas créer un compte.",
        "softblockrangesreason": "Les contributions anonymes ne sont pas autorisées à partir de votre adresse IP ($1). Veuillez vous connecter.",
        "allmessagesdefault": "Message par défaut",
        "allmessagescurrent": "Message actuel",
        "allmessagestext": "Ceci est la liste des messages système disponibles dans l’espace de noms MediaWiki.\nVeuillez visiter la [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Régionalisation de MediaWiki] et [https://translatewiki.net/ translatewiki.net] si vous désirez contribuer à la régionalisation générique de MediaWiki.",
-       "allmessagesnotsupportedDB": "Cette page n’est pas utilisable car <strong>$wgUseDatabaseMessages</strong> a été désactivé.",
+       "allmessages-not-supported-database": "Cette page n’est pas utilisable car <strong>$wgUseDatabaseMessages</strong> a été désactivé.",
        "allmessages-filter-legend": "Filtrer",
        "allmessages-filter": "Filtrer par état de modification :",
        "allmessages-filter-unmodified": "Non modifié",
        "confirm-unwatch-top": "Supprimer cette page de votre liste de suivi ?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Révoquer les modifications de cette page ?",
+       "confirm-rollback-bottom": "Cette action annulera immédiatement les modifications sélectionnées sur cette page.",
        "confirm-mcrrestore-title": "Restaurer une version",
        "confirm-mcrundo-title": "Annuler une modification",
        "mcrundofailed": "L’annulation a échoué",
        "usercssispublic": "Veuillez noter : les sous-pages CSS ne doivent pas contenir de données confidentielles parce qu’elles sont visibles des autres utilisateurs.",
        "restrictionsfield-badip": "Adresse IP ou plage non valide : $1",
        "restrictionsfield-label": "Plages IP autorisées :",
-       "restrictionsfield-help": "Une adresse IP ou une plage CIDR par ligne. Pour tout activer, utiliser <pre>0.0.0.0/0\n::/0</pre>",
+       "restrictionsfield-help": "Une adresse IP ou une plage CIDR par ligne. Pour tout activer, utiliser :<pre>0.0.0.0/0\n::/0</pre>",
        "edit-error-short": "Erreur : $1",
        "edit-error-long": "Erreurs :\n\n$1",
        "revid": "version $1",
        "passwordpolicies-policyflag-forcechange": "doit changer à la reconnexion",
        "passwordpolicies-policyflag-suggestchangeonlogin": "suggérer une modification à la connexion",
        "easydeflate-invaliddeflate": "Le contenu fourni n'est pas correctement développé",
-       "unprotected-js": "Pour des raisons de sécurité, JavaScript ne peut pas être chargé depuis des pages non protégées. Veuillez ne créer du javascript que dans l’espace de noms MediaWiki: ou comme sous-page utilisateur"
+       "unprotected-js": "Pour des raisons de sécurité, JavaScript ne peut pas être chargé depuis des pages non protégées. Veuillez ne créer du javascript que dans l’espace de noms MediaWiki: ou comme sous-page utilisateur",
+       "userlogout-continue": "Si vous voulez vous déconnecter, veuillez [$1 continuer vers la page de déconnexion].",
+       "userlogout-sessionerror": "Déconnexion échouée à cause d’une erreur de session. Veuillez [$1 réessayer]."
 }
index 8314ad9..6cfd81b 100644 (file)
        "minoreditletter": "p",
        "newpageletter": "N",
        "boteditletter": "r",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|utilisator qu’est|utilisators que sont}} aprés siuvre]",
        "rc-change-size-new": "$1 octèt{{PLURAL:$1||s}} aprés changement",
        "newsectionsummary": "/* $1 */ novèla sèccion",
        "rc-enhanced-expand": "Montrar los dètalys",
        "img-auth-nopathinfo": "PATH_INFO entrovâblo.\nVoutron sèrvior est pas configurâ por passar cel’enformacion.\nPôt-étre que fonccione en CGI et recognêt vêr pas img_auth.\nVêde https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Lo chemin demandâ est pas lo rèpèrtouèro de tèlèchargement configurâ.",
        "img-auth-badtitle": "Y at pas moyen de construire un titro justo dês « $1 ».",
-       "img-auth-nologinnWL": "Vos éte pas branchiê et pués « $1 » est pas dedens la lista blanche.",
        "img-auth-nofile": "Lo fichiér « $1 » ègziste pas.",
        "img-auth-isdir": "Vos èprovâd d’arrevar u rèpèrtouèro « $1 ».\nSolament l’accès ux fichiérs est pèrmetu.",
        "img-auth-streaming": "Lèctura en continu de « $1 ».",
        "allmessagesdefault": "Tèxto du mèssâjo per dèfôt",
        "allmessagescurrent": "Tèxto du mèssâjo d’ora",
        "allmessagestext": "O est na lista des mèssâjos sistèmo disponiblos dedens l’èspâço de noms MediaWiki.\nSe vos plét, vesitâd la [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation localisacion de MediaWiki] et pués [https://translatewiki.net translatewiki.net] se vos voléd contribuar a la localisacion g·ènèrâla de MediaWiki.",
-       "allmessagesnotsupportedDB": "Cela pâge est pas empleyâbla, <strong>$wgUseDatabaseMessages</strong> est étâ dèsactivâ.",
+       "allmessages-not-supported-database": "Cela pâge est pas empleyâbla, <strong>$wgUseDatabaseMessages</strong> est étâ dèsactivâ.",
        "allmessages-filter-legend": "Filtro",
        "allmessages-filter": "Filtrar per ètat de pèrsonalisacion :",
        "allmessages-filter-unmodified": "Pas changiê",
index f5b4378..ccd3163 100644 (file)
        "minoreditletter": "L",
        "newpageletter": "N",
        "boteditletter": "B",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|brüker|brükern}}, diar tuluke]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} efter't feranrin",
        "newsectionsummary": "Nei kirew /* $1 */",
        "rc-enhanced-expand": "Enkelthaiden wise",
        "img-auth-nopathinfo": "Diar as nian informatjuun auer di wai.\nDan server skal so iinracht wees, dat a wariaabeln REQUEST_URI an/of PATH_INFO auerden wurd.\nWan det tudraapt, aktiwiare $wgUsePathInfo.\nÜüb det sidj https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization (ingelsk) stäänt diar muar auer.",
        "img-auth-notindir": "Detdiar fertiaknis as ei föörsen tu huuchschüüren.",
        "img-auth-badtitle": "Mä „$1“ küd nään tiitel maaget wurd.",
-       "img-auth-nologinnWL": "Dü beest ei uunmeldet, an „$1“ stäänt ei uun't whitelist.",
        "img-auth-nofile": "Diar as nään datei „$1“.",
        "img-auth-isdir": "Dü wel üüb en fertiaknis „$1“ tugrip. Dü mutst bluas üüb datein tugrip.",
        "img-auth-streaming": "„$1“ woort iinleesen.",
        "allmessagesdefault": "Standard tekst",
        "allmessagescurrent": "Aktuel tekst",
        "allmessagestext": "Det as en list mä MediaWiki-süsteemteksten.\nWees so gud an beschük a sidjen [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki-auersaatang] an [https://translatewiki.net translatewiki.net], wan dü bi't auersaaten mähalep meest.",
-       "allmessagesnotsupportedDB": "Detdiar spezial-sidj koon ei brükt wurd, auer <tt>$wgUseDatabaseMessages</tt> ei aktiif as.",
+       "allmessages-not-supported-database": "Detdiar spezial-sidj koon ei brükt wurd, auer <tt>$wgUseDatabaseMessages</tt> ei aktiif as.",
        "allmessages-filter-legend": "Filter",
        "allmessages-filter": "Filter för di uunpaaset stant:",
        "allmessages-filter-unmodified": "Ünferanert",
index 65186db..b2d0197 100644 (file)
        "minoreditletter": "p",
        "newpageletter": "G",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[tignude di voli di {{PLURAL:$1|un utent|$1 utents}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} dopo la modifiche",
        "newsectionsummary": "/* $1 */ gnove sezion",
        "rc-enhanced-expand": "Cjale i detais (al covente JavaScript)",
index 2ea80d4..736df63 100644 (file)
        "tog-hideminor": "Feroarings fan lytse betsjutting ferbergje yn Koartlyn feroare",
        "tog-hidepatrolled": "Markearre feroarings ferskûlje yn resinte feroarings",
        "tog-newpageshidepatrolled": "Markearre siden ferskûlje yn 'e list mei nije siden",
-       "tog-extendwatchlist": "Wreidzje folchlist út om alle wizigings sjen te litten, net allinnich de lêste wizigings",
-       "tog-usenewrc": "Utwreide ferzje fan 'Koartlyn feroare' brûke (JavaScript fereaske)",
+       "tog-hidecategorization": "Kategorisearjen fan siden ferbergje yn Koartlyn feroare",
+       "tog-extendwatchlist": "Folchlist útwreidzje om alle wizigings sjen te litten, net allinnich de lêste",
+       "tog-usenewrc": "Feroarings op side groepearje yn Koartlyn feroare en de folchlist",
        "tog-numberheadings": "Koppen fansels nûmerje",
-       "tog-editondblclick": "Dûbelklik jout bewurkingsside (freget JavaScript)",
-       "tog-editsectiononrightclick": "Rjochtsklik op sekjsetitels jout seksjebewurking (freget JavaScript)",
-       "tog-watchcreations": "Set siden dy't jo begjinne yn jo folchlist",
-       "tog-watchdefault": "Sides dy't jo feroare hawwe folgje",
-       "tog-watchmoves": "Siden dy't jo werneamd hawwe folgje",
+       "tog-editondblclick": "Dûbelklik jout bewurkingsside",
+       "tog-editsectiononrightclick": "Rjochtsklik op seksjetitels jout seksjebewurking",
+       "tog-watchcreations": "Siden dy't ik oanmeitsje en bestannen dy't ik oplaad, taheakje oan myn folchlist",
+       "tog-watchdefault": "Siden en bestannen dy't ik bewurkje, taheakje oan myn folchlist",
+       "tog-watchmoves": "Siden en bestannen dy't ik omneam, taheakje oan myn folchlist",
        "tog-watchdeletion": "Siden dy't jo wiske hawwe folgje",
-       "tog-minordefault": "Markearje alle feroarings standert as fan lytse betsjutting",
-       "tog-previewontop": "By it neisjen, bewurkingsfjild ûnderoan sette",
-       "tog-previewonfirst": "Lit foarbyld sjen by earste wiziging",
+       "tog-watchuploads": "Nije bestannen dy't ik oplaad, taheakje oan myn folchlist",
+       "tog-watchrollback": "Siden dêr't ik wizigings weromdraaid haw oan myn folchlist taheakje",
+       "tog-minordefault": "Alle feroarings standert as fan lytse betsjutting markearje",
+       "tog-previewontop": "Foarfertoaning werjaan boppe it bewurkingsfjild",
+       "tog-previewonfirst": "Foarfertoaning werjaan by it begjin fan 'e bewurking",
        "tog-enotifwatchlistpages": "E-mail my as in side op myn folchlist feroare is.",
        "tog-enotifusertalkpages": "E-mail my as myn oerlisside feroare wurdt",
        "tog-enotifminoredits": "E-mail my ek by feroarings fan lytse betsjutting oan siden en bestannen",
        "tog-enotifrevealaddr": "Myn e-mailadres sjen litte yn e-mailberjochten",
        "tog-shownumberswatching": "It tal meidoggers sjen litte dat dizze side folget",
-       "tog-oldsig": "Aktuele sinjatuerprintallyk:",
-       "tog-fancysig": "Sinjatuer as wikitekst behannelje (sûnder automatyske keppeling)",
-       "tog-uselivepreview": "\"Live proefbyld\" brûke",
-       "tog-forceeditsummary": "Warskôgje at ik de gearfetting leech lit.",
-       "tog-watchlisthideown": "Eigen bewurkings op myn folchlist ferbergje",
-       "tog-watchlisthidebots": "Lit gjin bot wizigings sjen yn de folchlist",
-       "tog-watchlisthideminor": "Feroarings fan lytse betsjutting ferbergje yn de folchlist",
-       "tog-watchlisthideliu": "Bewurkings fan oanmelde meidoggers op myn folchlist ferbergje",
-       "tog-watchlisthideanons": "Bewurkings fa anonyme meidoggers op myn folchlist ferbergje",
+       "tog-oldsig": "Jo besteande sinjatuer:",
+       "tog-fancysig": "Sinjatuer as wikitekst behannelje (sûnder in automatyske keppeling)",
+       "tog-uselivepreview": "Foarfertoanings werjaan sûnder it werladen fan 'e side",
+       "tog-forceeditsummary": "My melde oft ik de bewurkingsgearfetting leech lit",
+       "tog-watchlisthideown": "Myn bewurkings ferbergje yn 'e folchlist",
+       "tog-watchlisthidebots": "Botbewurkings ferbergje yn 'e folchlist",
+       "tog-watchlisthideminor": "Feroarings fan lytse betsjutting ferbergje yn 'e folchlist",
+       "tog-watchlisthideliu": "Bewurkings fan oanmelde meidoggers ferbergje yn 'e folchlist",
+       "tog-watchlistunwatchlinks": "Direkte folch-/ûntfolchmarkearders taheakje ({{int:Watchlist-unwatch-undo}}/{{int:Watchlist-unwatch}}) oan folchlistsiden mei wizigings (JavaScript fereaske foar omskeakelmooglikheid)",
+       "tog-watchlisthideanons": "Bewurkings fan anonime meidoggers ferbergje yn 'e folchlist",
        "tog-watchlisthidepatrolled": "Markearre feroarings op myn folchlist ferskûlje",
+       "tog-watchlisthidecategorization": "Kategorisearjen fan siden ferbergje yn 'e folchlist",
        "tog-ccmeonemails": "Stjoer my in kopy fan e-mails dy't ik nei oare meidoggers stjoer",
        "tog-diffonly": "Side-ynhâld dy't feroare wurdt net sjen litte",
        "tog-showhiddencats": "Ferburgen kategoryen werjaan",
-       "tog-norollbackdiff": "Feroarings weilitte nei tebekdraaien",
+       "tog-norollbackdiff": "Gjin ferskillen sjen litte nei it útfieren fan weromdraaien",
+       "tog-useeditwarning": "My warskôgje at ik in bewurkingsside mei net-bewarre wizigings ferlit",
+       "tog-showrollbackconfirmation": "Befêstigingsdialooch sjen litte by it klikken op 'weromdraaie'",
        "underline-always": "Altyd",
        "underline-never": "Nea",
        "underline-default": "Webblêder-standert",
-       "editfont-style": "Lettertypestyl bewurkingsfinster",
-       "editfont-monospace": "Monospaced lettertype",
+       "editfont-style": "Lettertypestyl bewurkingsfjild",
+       "editfont-monospace": "Net-proporsjoneel lettertype",
        "editfont-sansserif": "Skreefleas lettertype",
-       "editfont-serif": "Lettertype mei skreven",
+       "editfont-serif": "Lettertype mei skreef",
        "sunday": "snein",
        "monday": "moandei",
        "tuesday": "tiisdei",
        "noindex-category": "Net-yndeksearre siden",
        "categoryviewer-pagedlinks": "($1) ($2)",
        "about": "Oer",
-       "article": "Ynhâld side",
+       "article": "Ynhâldlike side",
        "newwindow": "(nij finster)",
        "cancel": "Annulearje",
        "moredotdotdot": "Mear...",
        "mypage": "Myn side",
-       "mytalk": "Myn oerlis",
-       "anontalk": "Oerlisside foar dit IP-adres",
+       "mytalk": "Oerlis",
+       "anontalk": "Oerlis",
        "navigation": "Navigaasje",
        "and": "&#32;en",
        "faq": "FAQ (faak stelde fragen)",
        "variants": "Farianten",
        "navigation-heading": "Navigaasjemenu",
        "errorpagetitle": "Flater",
-       "returnto": "Werom nei \"$1\".",
+       "returnto": "Werom nei $1.",
        "tagline": "Ut {{SITENAME}}",
        "help": "Help",
        "search": "Sykje",
        "searcharticle": "Side",
        "history": "Sideskiednis",
        "history_short": "Skiednis",
+       "history_small": "skiednis",
        "updatedmarker": "bewurke sûnt myn lêste besite",
        "printableversion": "Ofdrukferzje",
        "permalink": "Fêste keppeling",
        "create-local": "Lokale beskriuwing tafoegje",
        "delete": "Fuortsmite",
        "undelete_short": "$1 {{PLURAL:$1|ferzje|ferzjes}} weromsette",
-       "protect": "Skoattel",
+       "protect": "Skoattelje",
        "protect_change": "feroarje nivo fan skoatteljen",
        "unprotect": "Jou frij",
        "newpage": "Nije side",
        "talk": "Oerlis",
        "views": "Werjeften",
        "toolbox": "Ark",
+       "tool-link-userrights": "{{GENDER:$1|Meidochgroepen}} feroarje",
+       "tool-link-userrights-readonly": "{{GENDER:$1|Meidochgroepen}} besjen",
        "imagepage": "Besjoch bestânsside",
        "mediawikipage": "Berjochtside sjen litte",
        "templatepage": "Berjochtside lêze",
        "viewhelppage": "Helpside sjen litte",
        "categorypage": "Besjoch kategoryside",
        "viewtalkpage": "Oerlisside",
-       "otherlanguages": "In oare talen",
+       "otherlanguages": "Yn oare talen",
        "redirectedfrom": "(Trochwiisd fan $1)",
        "redirectpagesub": "Trochferwiis-side",
        "lastmodifiedat": "Dizze side is it lêst bewurke op $1 om $2.",
-       "viewcount": "Disse side is {{PLURAL:$1|ienris|$1 kear}} iepenslein.",
+       "viewcount": "Dizze side is {{PLURAL:$1|ienris|$1 kear}} iepenslein.",
        "protectedpage": "Skoattele side",
-       "jumpto": "Gean nei:",
+       "jumpto": "Spring nei:",
        "jumptonavigation": "navigaasje",
        "jumptosearch": "sykje",
        "view-pool-error": "Ekskuseare, de tsjinners hawwe it op it stuit te drok.\nTefolle meidoggers probearje dizze side te besjen.\nWachtsje efkes foardatsto op 'e nij tagong ta dizze side probearrest te krijen.\n\n$1",
        "pagetitle-view-mainpage": "{{SITENAME}}",
        "backlinksubtitle": "← $1",
        "retrievedfrom": "Untfongen fan \"$1\"",
-       "youhavenewmessages": "Jo hawwe $1 ($2).",
+       "youhavenewmessages": "{{PLURAL:$3|Jo hawwe}} $1 ($2).",
+       "youhavenewmessagesfromusers": "{{PLURAL:$4|Jo hawwe}} $1 fan {{PLURAL:$3|in oare meidogger|$3 meidoggers}} ($2).",
+       "youhavenewmessagesmanyusers": "Jo hawwe $1 fan in protte meidoggers ($2).",
        "newmessageslinkplural": "{{PLURAL:$1|in nij berjocht|999=nije berjochten}}",
        "newmessagesdifflinkplural": "lêste {{PLURAL:$1|feroaring|999=feroarings}}",
        "youhavenewmessagesmulti": "Jo hawwe nije berjochten op $1",
        "nstab-special": "Bysûndere side",
        "nstab-project": "Projektside",
        "nstab-image": "Bestân",
-       "nstab-mediawiki": "Berjocht",
+       "nstab-mediawiki": "Systeemberjocht",
        "nstab-template": "Berjocht",
        "nstab-help": "Helpside",
        "nstab-category": "Kategory",
        "mainpage-nstab": "Haadside",
        "nosuchaction": "Unbekende aksje.",
-       "nosuchactiontext": "De opdracht yn de URL is ûnjildich.\nMooglik hasto in typefout makke yn de URL of in ferkearde keppeling folge.\nIt soe likegoed in programmatuerflater fan {{SITENAME}} wêze kinne.",
+       "nosuchactiontext": "De opdracht yn de URL is ûnjildich.\nMooglik hawwe jo in typflater yn 'e URL makke of in ferkearde keppeling folge.\nIt soe likegoed in programmatuerflater fan {{SITENAME}} wêze kinne.",
        "nosuchspecialpage": "Gjin soksoarte bysûndere side",
        "nospecialpagetext": "<strong>Jo hawwe in ûnjildige bysûndere side opfrege.</strong>\n\nIn list fan jildige bysûndere siden stiet op [[Special:SpecialPages|{{int:specialpages}}]].",
        "error": "Flater",
        "protectedinterface": "Dizze side jout systeemteksten fan 'e software en is befeilige tsjin misbrûk. Asto oersettingen foar alle wiki's tafoegje of bewurkje wolst, kinsto [https://translatewiki.net/ translatewiki.net] brûke.",
        "editinginterface": "<strong>Warskôging:</strong> Jo bewurkje in side dy't brûkt wurdt foar systeemteksten foar de software.\nBewurkings op dizze side beynfloedzje de meidoggersynterface fan elkenien.",
        "cascadeprotected": "Dizze side is skoattele tsjin wizigjen, om't der in ûnderdiel útmakket fan de neikommende {{PLURAL:$1|side|siden}}, dy't skoattele {{PLURAL:$1|is|binne}} mei de \"ûnderlizzende siden\" opsje ynskeakele: $2",
-       "namespaceprotected": "Jo hawwe gjin rjochten om siden yn'e nammerûmte '''$1''' te bewurkjen.",
+       "namespaceprotected": "Jo hawwe gjin rjochten om siden yn'e nammeromte '''$1''' te bewurkjen.",
        "ns-specialprotected": "Siden yn'e nammerûmte {{ns:special}} kinne net bewurke wurde.",
        "titleprotected": "It oanmeitsjen fan dizze side is befeilige troch [[User:$1|$1]].\nDe oanfierde reden is <em>$2</em>.",
        "exception-nologin": "Net oanmeld",
        "exception-nologin-text-manual": "Jo moatte $1 om tagong ta dizze side of hanneling krije te kinnen.",
        "virus-badscanner": "Minne konfiguraasje: ûnbekende virusscanner: ''$1''",
-       "virus-scanfailed": "scannen is mislearre (koade $1)",
+       "virus-scanfailed": "scan is mislearre (koade $1)",
        "virus-unknownscanner": "ûnbekend antivirus:",
-       "logouttext": "<strong>Jo binne no ôfmeld.</strong>\n\nGuon siden kinne noch foar it ljocht komme, krekt as wiesto noch oanmeld. Asto de cache fan dyn webblêder leechhellest feroaret dat wer.",
+       "logouttext": "<strong>Jo binne no ôfmeld.</strong>\n\nTink derom dat guon siden trochgeand werjûn wurde kinne krekt as wiene jo noch oanmeld, oant jo de oerslach fan jo webblêder leegje.",
        "welcomeuser": "Wolkom, $1!",
        "yourname": "Meidochnamme:",
        "userlogin-yourname": "Meidochnamme",
        "userlogin-yourname-ph": "Jou jo meidochnamme",
-       "createacct-another-username-ph": "Jou jo meidochnamme",
+       "createacct-another-username-ph": "Jou de meidochnamme",
        "yourpassword": "Wachtwurd:",
        "userlogin-yourpassword": "Wachtwurd",
        "userlogin-yourpassword-ph": "Jou jo wachtwurd",
        "password-change-forbidden": "Op dizze wiky kinst gjin wachtwurden feroare",
        "externaldberror": "Der is in fout by it oanmelden by de database of jo hawwe gjin tastimming om jo ekstern account by te wurkjen.",
        "login": "Oanmelde",
+       "login-security": "Jo identiteit kontrolearje",
        "nav-login-createaccount": "Oanmelde",
        "logout": "Ofmelde",
        "userlogout": "Ofmelde",
        "notloggedin": "Net oanmeld",
-       "userlogin-noaccount": "Hasto gjin akkount?",
-       "userlogin-joinproject": "Meidwaan {{SITENAME}}",
+       "userlogin-noaccount": "Hawwe jo gjin akkount?",
+       "userlogin-joinproject": "Doch mei op {{SITENAME}}",
        "createaccount": "Registrearje",
        "userlogin-resetpassword-link": "Wachtwurd fergetten?",
+       "userlogin-helplink2": "Help by it oanmelden",
+       "userlogin-reauth": "Jo moatte jo nochris oanmelde, om te befêstigjen dat jo {{GENDER:$1|$1}} binne.",
        "createacct-emailrequired": "E-mailadres",
        "createacct-emailoptional": "E-mailadres (net ferplichte)",
        "createacct-email-ph": "E-mailadres ynfiere",
        "createacct-reason-ph": "Wêrom makkesto in oare akkount?",
        "createacct-submit": "Meitsje in akkount",
        "createacct-another-submit": "Meitsje in oare akkount",
-       "createacct-benefit-heading": "{{SITENAME}} is makke troch minsken krekt as dy.",
+       "createacct-benefit-heading": "{{SITENAME}} is makke troch minsken krekt as jo.",
        "createacct-benefit-body1": "{{PLURAL:$1|bewurking|bewurkings}}",
        "createacct-benefit-body2": "{{PLURAL:$1|side|siden}}",
        "createacct-benefit-body3": "aktive {{PLURAL:$1|skriuwer|skriuwers}}",
        "noname": "Jo hawwe gjin jildige meidochnamme opjûn.",
        "loginsuccesstitle": "Oanmelden slagge.",
        "loginsuccess": "<strong>Jo binne no oanmeld op {{SITENAME}} as \"$1\".</strong>",
-       "nosuchuser": "Der is gjin meidogger \"$1\".\nKontrolearje de stavering, of [[Special:CreateAccount|meitsje in nije meidogger oan]].",
+       "nosuchuser": "Der is gjin meidogger mei de namme \"$1\".\nMeidochnammen binne haadlettergefoelich.\nSjoch de stavering nei, of [[Special:CreateAccount|meitsje in nij akkount oan]].",
        "nosuchusershort": "Der is gjin meidogger mei de namme \"$1\". It is goed skreaun?",
        "nouserspecified": "Jo moatte in meidochnamme opjaan.",
-       "wrongpassword": "Meidochnamme en wachtwurd hearre net by elkoar. Besykje op 'e nij, of fier it wachtwurd twa kear yn en meitsje nije meidoggersynstellings.",
+       "wrongpassword": "Ferkearde meidochnamme of wachtwurd ynfolle.\nBesykje it nochris.",
        "wrongpasswordempty": "It opjûne wachtwurd wie leech. Besykje it nochris.",
        "passwordtooshort": "Wachtwurden moatte op syn minst {{PLURAL:$1|1 teken|$1 tekens}} lang wêze.",
        "password-name-match": "Jo wachtwurd moat oars wêze as jo meidochnamme.",
-       "mailmypassword": "E-mail my in nij wachtwurd.",
+       "mailmypassword": "Nij wachtwurd",
        "passwordremindertitle": "Nij tydlik wachtwurd foar {{SITENAME}}",
-       "passwordremindertext": "Immen (nei alle gedachten jo, fan ynternetadres $1) had in nij wachtwurd\nfoar {{SITENAME}} ($4) oanfrege. Der is in tydlik wachtwurd foar meidogger\n\"$2\"  makke en ynstelt as \"$3\". As dat jo bedoeling wie, melde jo jo dan\nno oan en kies in nij wachtwurd. Dyn tydlik wachtwurd komt yn {{PLURAL:$5|ien dei|$5 dagen}} te ferfallen.\nDer is in tydlik wachtwurd oanmakke foar meidogger \"$2\": \"$3\".\n\nAs immen oars as jo dit fersyk dien hat of at it wachtwurd jo tuskentiidsk wer yn 't sin kommen is en\njo it net langer feroarje wolle, dan kinne jo dit berjocht ferjitte en\nfierdergean mei it brûken fan jo âlde wachtwurd.",
+       "passwordremindertext": "Immen (mei it IP-adres $1) hat in nij\nwachtwurd  oanfrege foar {{SITENAME}} ($4). Der is in tydlik wachtwurd foar\nmeidogger \"$2\" oanmakke, en dat is \"$3\". At dat jo\ndoel wie, meld jo dan no oan en kies in nij wachtwurd.\nJo tydlik wachtwurd ferrint nei {{PLURAL:$5|ien dei|$5 dagen}}.\n\nAt immen oars dy oanfraach dien hat, of at jo jo wachtwurd wer witte\nen it net mear feroarje wolle, dan kinne jo dit berjocht negearje en\njo âlde wachtwurd brûken bliuwe.",
        "noemail": "Der is gjin e-postadres foar meidogger \"$1\".",
-       "passwordsent": "In nij wachtwurd is tastjoerd oan it e-postadres foar \"$1\". Jo kinne jo wer oanmelde as jo it wachtwurd ûntfongen hawwe.",
+       "passwordsent": "Der is in nij wachtwurd ferstjoerd nei it opjûne e-mailadres fan \"$1\".\nMeld jo nei ûntfangst op 'e nij oan.",
        "blocked-mailpassword": "Jo IP-adres is blokkearre foar it meitsjen fan feroarings. Om misbrûk tefoaren te kommen is it net mûglik in oar wachtwurd oan te freegjen.",
-       "eauthentsent": "Foar befêstiging is jo in netpostberjocht tastjoerd op it adres dat jo ynsteld hawwe. Der wurdt gjin oare netpost stjoerd, oant jo it adres befêstigje sa't it yn it netpostberjocht stiet.",
+       "eauthentsent": "Der is in befêstigingsmail nei it opjûne e-mailadres ferstjoerd.\nFoar't oare e-mails nei jo tastjoerd wurde, moatte jo de ynstruksjes yn de e-mail opfolgje, om te befêstigjen dat it akkount yndie jowes is.",
        "throttled-mailpassword": "Yn {{PLURAL:$1|de lêste oere|de lêste $1 oeren}} is der al in wachtwurdwink ferstjoerd.\nOm misbrûk tefoaren te kommen wurdt der mar ien wachtwurdwink yn 'e {{PLURAL:$1|oere|$1 oeren}} ferstjoerd.",
        "mailerror": "Flater by it ferstjoeren fan e-mail: $1",
        "acct_creation_throttle_hit": "Besikers fan dizze wiky mei itselde ynternet-adres as jo hawwe de ôfrûne $2 al {{PLURAL:$1|1 meidochnamme|$1 meidochnammen}} oanmakke, wat it maksimaal tasteane oantal is foar dizze perioade.\nDêrom kinne jo fan jo ynternet-adres ôf op dit stuit gjin nije meidochnammen oanmeitsje.",
        "resetpass-submit-cancel": "Annulearje",
        "resetpass-wrong-oldpass": "It momintele of tydlike wachtwurd is ûnjildich.\nMûglik hawwe Jo Jo wachtwurd al feroare of in nij tydlik wachtwurd oanfrege.",
        "resetpass-temp-password": "Tydlik wachtwurd:",
-       "passwordreset": "Wachtwurd ferfarskje",
+       "passwordreset": "Wachtwurd op 'e nij oanmeitsje",
+       "passwordreset-text-many": "{{PLURAL:$1|Folje ien fan 'e fjilden yn, en ûntfang in tydlik wachtwurd mei de e-mail.}}",
        "passwordreset-username": "Meidochnamme:",
        "passwordreset-domain": "Domein:",
        "passwordreset-email": "E-mailadres:",
        "passwordreset-emailtitle": "Akkountdetails op {{SITENAME}}",
        "passwordreset-emailelement": "Meidochnamme: \n$1\n\nTydlik wachtwurd: \n$2",
-       "changeemail": "Feroarje e-mailadres",
-       "changeemail-header": "Feroarje akkount e-mailadres",
+       "changeemail": "E-mailadres wizigje as wiskje",
+       "changeemail-header": "Folje dit formulier yn, om jo e-mailadres te feroarjen. At jo it oan jo akkount ferbûne e-mailadres graach wiskje wolle, lit it nije e-mailadres dan iepen en klik op wizigje.",
        "changeemail-no-info": "Jo moatte oanmeld wêze om streekrjocht tagong ta dizze side te hawwen.",
+       "changeemail-oldemail": "Hjoeddeisk e-mailadres:",
        "changeemail-newemail": "Nij e-mailadres:",
-       "changeemail-none": "(gjin)",
+       "changeemail-newemail-help": "Dit fjild moat leech bliuwe at jo jo e-mailadres wiskje wolle. At it e-mailadres wiske is, kinne jo in fergetten wachtwurd net op 'e nij ynstelle, en ûntfange jo gjin e-mails mear fan dizze wiki.",
+       "changeemail-none": "(gjint)",
        "changeemail-password": "Jo wachtwurd foar {{SITENAME}}:",
        "changeemail-submit": "E-mailadres wizigje",
-       "resettokens": "Kaaien ferfarskje",
+       "resettokens": "Kaaien fernije",
+       "resettokens-text": "Jo kinne de kaaien fernije dy't tagong jouwe ta beskate priveedata hearrend by jo akkount hjirre.\n\nJo moatte dat dwaan at jo dy by ûngelok mei immen dield hawwe, of at jo jo akkount net mear fertrouwe.",
+       "resettokens-no-tokens": "Der binne gjin kaaien om te fernijen.",
        "resettokens-tokens": "Kaaien:",
-       "resettokens-token-label": "$1 (hjoeddeistige wearde: $2)",
-       "resettokens-resetbutton": "Selektearre kaaien ferfarskje",
+       "resettokens-token-label": "$1 (hjoeddeiske wearde: $2)",
+       "resettokens-watchlist-token": "Kaai foar de webfied (Atom/RSS) fan [[Special:Watchlist|wizigings oan jo folchlistsiden]]",
+       "resettokens-done": "Kaaien fernijd.",
+       "resettokens-resetbutton": "Selektearre kaaien fernije",
        "bold_sample": "Fette tekst",
        "bold_tip": "Fette tekst",
        "italic_sample": "Skeane tekst",
        "headline_sample": "Koptekst",
        "headline_tip": "Underkopke",
        "nowiki_sample": "Foechje hjir platte tekst yn",
-       "nowiki_tip": "Negearje it wiki formaat",
+       "nowiki_tip": "Wiki-opmaak negearje",
        "image_sample": "Foarbyld.jpg",
        "image_tip": "Mediabestân",
        "media_tip": "Link nei bestân",
-       "sig_tip": "Jo hântekening mei dei en oere",
+       "sig_tip": "Jo sinjatuer mei dei en oere",
        "hr_tip": "Horizontale line (mei ferdrach brûke)",
        "summary": "Gearfetting:",
        "subject": "Underwerp:",
        "systemblockedtext": "Jo meidochnamme of ynternet-adres is automatysk útsletten troch MediaWiki.\nAs reden is opjûn:\n\n:<em>$2</em>\n\n* Begjin útsluting: $8\n* Ein útsluting: $6\n* Bedoeld út te sluten: $7\n\nJo hjoeddeisk ynternet-adres is $3.\nNim alle boppesteande gegevens op yn jo reäksjes.",
        "blockednoreason": "gjin reden opjûn",
        "whitelistedittext": "Jo moatte $1 om siden bewurkje te kinnen.",
-       "confirmedittext": "Jo moatte jo e-mailadres befêstichje foar't jo siden feroarje kinne.\nFier in e-mailadres yn by jo [[Special:Preferences|foarkarren]] en befêstichje it.",
+       "confirmedittext": "Jo moatte jo e-mailadres befêstigje foar't jo siden bewurkje kinne.\nStel by jo [[Special:Preferences|foarkarren]] in e-mailadres yn en befêstigje it.",
        "nosuchsectiontitle": "Dizze subkop bestiet net",
        "nosuchsectiontext": "Jo besochten in subkop te bewurkjen dy't net bestiet.",
        "loginreqtitle": "Oanmelding frege",
        "accmailtitle": "Wachtwurd ferstjoerd.",
        "accmailtext": "Samar in wachtwurd foar [[User talk:$1|$1]] is ferstjoerd nei $2. It kin wizige wurde op 'e side \n<em>[[Special:ChangePassword|Wachtwurd feroarje]]</em> nei oanmelden.",
        "newarticle": "(Nij)",
-       "newarticletext": "Jo hawwe in keppeling folge nei in side dêr't noch gjin tekst op stiet.\nOm sels tekst te meistjsen kinne jo dy gewoan yntype in dit bewurkingsfjild\n([$1 Mear ynformaasje oer bewurkjen].)\nOars kinne jo tebek mei de tebek-knop fan jo blêder.",
+       "newarticletext": "Jo hawwe in keppeling folge nei in side dêr't noch gjin tekst op stiet.\nBegjin mei skriuwen yn it fjild hjirûnder om de side oan te meitsjen (sjoch de [$1 helpside] foar mear ynformaasje).\nKlik op de <strong>tebek</strong>-knop fan jo webblêder at jo hjir by ûngelok telâne kommen binne.",
        "anontalkpagetext": "----\n<em>Dit is de oerlisside fan in ûnbekende meidogger; in meidogger dy't him/har net oanmeld hat.</em>\nOm't der gjin namme bekend is, wurdt it ynternet-adres brûkt om oan te jaan om wa't it giet.\nMar faak is it sa dat sa'n adres net altyd troch deselde persoan brûkt wurdt.\nAs jo it idee hawwe dat jo as ûnbekende meidogger opmerkings foar in oar krije, dan kinne jo jo [[Special:CreateAccount|registrearje]], of jo [[Special:UserLogin|oanmelde]]. Fan in oanmelde meidogger is it ynternet-adres net sichtber, en as oanmelde meidogger krije jo allinnich opmerkings dy't foar josels bedoeld binne.",
-       "noarticletext": "Der stjit noch gjin tekst op dizze side. Jo kinne\n[[Special:Search/{{PAGENAME}}|hjirboppe nei dy tekst sykje]], of [{{fullurl:{{FULLPAGENAME}}|action=edit}} de side skriuwe].",
+       "noarticletext": "Der stiet noch gjin tekst op dizze side.\nJo kinne [[Special:Search/{{PAGENAME}}|nei dizze sidenamme sykje]] yn oare siden,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} de besibbe lochs trochsykje]\nof [{{fullurl:{{FULLPAGENAME}}|action=edit}} dizze side oanmeitsje]</span>.",
        "userpage-userdoesnotexist": "Jo bewurkje in meidoggerside fan in meidogger dy't net bestiet (meidogger \"<nowiki>$1</nowiki>\").\nKontrolearje oft jo dizze side wol oanmeitsje/bewurkje wolle.",
        "userpage-userdoesnotexist-view": "It meidochakkount \"$1\" bestiet net.",
        "clearyourcache": "<strong>Opmerking:</strong> Nei it fêstlizzen kin it nedich wêze de oerslach fan dyn blêder te leegjen foardat de wizigings te sjen binne.\n* <strong>Firefox / Safari:</strong> Hâld <em>Shift</em> yntreaun wylst jo op <em>Dizze side fernije</em> klikke, of typ <em>Ctrl-F5</em> of <em>Ctrl-R</em> (<em>⌘-R</em> op in Mac)\n* <strong>Google Chrome:</strong> Typ <em>CTRL-Shift-R</em> (<em>⌘-Shift-R</em> op in Mac)\n* <strong>Internet Explorer:</strong> Hâld <em>Ctrl</em> yntreaun wylst jo <em>Vernieuwen'' klikke of typ <em>Ctrl-F5</em>\n* <strong>Opera:</strong> Leegje jo cache yn <em>Extra → Voorkeuren</em>",
        "userinvalidconfigtitle": "<strong>Warskôging:</strong> der is gjin skin \"$1\".\nTink derom: jo eigen .css- en .js-siden begjinne mei in lytse letter, bygelyks {{ns:user}}:Namme/vector.css ynsté fan {{ns:user}}:Namme/Vector.css.",
        "updated": "(Bewurke)",
        "note": "<strong>Opmerking:</strong>",
-       "previewnote": "<strong>Tink der om dat dit allinnich in foarfertoaning is!</strong>\nJo feroarings binne noch net fêstlein!",
+       "previewnote": "<strong>Tink derom dat dit allinnich in foarfertoaning is!</strong>\nJo feroarings binne noch net fêstlein!",
+       "continue-editing": "Gean nei it bewurkingsfjild",
        "previewconflict": "Dizze side belanget allinich it earste bewurkingsfjild oan.",
        "session_fail_preview": "<strong>Jo bewurking is net ferwurke, om't de sessygegevens ferlern gien binne.</strong>\nBesykje it nochris. As it dan noch net slagget, [[Special:UserLogout|meld jo dan ôf]] en wer oan.",
        "session_fail_preview_html": "<strong>Jo bewurking is net ferwurke, om't sesjegegevens ferlern gien binne.</strong>\n\n<em>Om't yn {{SITENAME}} rûge HTML ynskeakele is, is in foarfertoaning net mûglik as beskerming tsjin oanfallen mei JavaScript.</em>\n\n<strong>As dit in legitime bewurking is, besykje it dan fannijs.</strong>\nAs it dan  noch net slagget, [[Special:UserLogout|meld jo dan ôf]] en wer oan.",
        "editing": "Bewurkje \"$1\"",
        "creating": "$1 oanmeitsje",
        "editingsection": "Bewurkje $1 (seksje)",
-       "editingcomment": "Dwaande mei bewurkjen fan $1 (opmerking)",
+       "editingcomment": "Bewurkjen fan $1 (nij mêd)",
        "editconflict": "Tagelyk bewurke: \"$1\"",
        "explainconflict": "In oar hat de side feroare sûnt jo begûn binne mei it bewurkjen.\nIt earste bewurkingsfjild is hoe't de tekst wilens wurden is.\nJo feroarings stean yn it twadde fjild.\nDy wurde allinnich tapast safier as jo se yn it earste fjild ynpasse.\n'''Allinnich''' de tekst út it earste fjild kin fêstlein wurde.",
        "yourtext": "Jo tekst",
        "undo-norev": "De feroaring kin werom set wurde, omdat it net bestiet of is wiske.",
        "undo-summary": "Werom sette fan ferzje $1 fan [[Special:Contributions/$2|$2]] ([[User talk:$2|Oerlis]])",
        "cantcreateaccount-text": "Registraasje fan in meidogger fia dit IP-adres ('''$1''') is blokkearre troch [[User:$3|$3]].\n\nDe fan $3 opjûne reden is ''$2''",
-       "viewpagelogs": "Lochboek foar dizze side sjen litte",
+       "viewpagelogs": "Lochboek foar dizze side besjen",
        "nohistory": "Dit is de earste ferzje fan de side.",
        "currentrev": "Aktuele ferzje",
        "currentrev-asof": "Hjoeddeiske ferzje sûnt $1",
        "last": "foarige",
        "page_first": "earste",
        "page_last": "lêste",
-       "histlegend": "Ferskil oanjaan: Markearje de rûntsjes fan 'e te ferlykjen ferzjes, en druk op Enter of de knop ûnderoan.<br />\nLeginda: <strong>({{int:cur}})</strong> = ferskil mei de lêste ferzje, <strong>({{int:last}})</strong> = ferskil mei de eardere ferzje, <strong>{{int:minoreditletter}}</strong> = lytse feroaring.",
-       "history-fieldset-title": "Troch skiednis blêdzje",
+       "histlegend": "Ferskil oanjaan: Markearje de rûntsjes fan 'e te ferlykjen ferzjes, en druk op Enter of de knop ûnderoan.<br />\nLeginda: <strong>({{int:cur}})</strong> = ferskil mei de lêste ferzje, <strong>({{int:last}})</strong> = ferskil mei de eardere ferzje, <strong>{{int:minoreditletter}}</strong> = fan lytse betsjutting.",
+       "history-fieldset-title": "Ferzjes filterje",
        "histfirst": "âldste",
        "histlast": "nijste",
        "historysize": "({{PLURAL:$1|1 byte|$1 bytes}})",
        "history-feed-description": "Sideskiednis foar dizze side op de wiki",
        "history-feed-item-nocomment": "$1 op $2",
        "history-feed-empty": "De frege side bestiet net.\nFaaks is dy fuorthelle of omneamd.\n[[Special:Search|Sykje de wiki troch]] foar relevante nije siden.",
+       "history-edit-tags": "Lebels fan selektearre ferzjes bewurkje",
        "rev-deleted-comment": "(opmerking wiske)",
        "rev-deleted-user": "(meidochnamme fuorthelle)",
        "rev-deleted-event": "(lochrigel fuorthelle)",
        "mergehistory-into": "Bestimmingside:",
        "mergehistory-list": "Gearfoegbere bewurkingsskiednis",
        "mergehistory-merge": "De folgjende ferzjes fan [[:$1]] kinne gearfoege wurde nei [[:$2]].\nBrûk de kolom mei de karrûntsjes om allinne de ferzjes makke op en foar de oanjûne tiid gear te foegjen.\nTink derom it brûken fan de navigaasjeferwizings dy kolom op'e nij ynstelt.",
-       "mergehistory-go": "Besjen bewurkings dy't kombinearre wurde kinne",
+       "mergehistory-go": "Gearfoegbere bewurkings besjen",
        "mergehistory-submit": "Kombinearje ferzjes",
        "mergehistory-empty": "Gjin ferzjes kinne kombinearren wurde.",
        "mergehistory-done": "Kombinearjen slagge fan $3 {{PLURAL:$3|ferzje|ferzjes}} fan $1 no [[:$2]].",
        "history-title": "$1: ferzjeskiednis",
        "difference-title": "Ferskil tusken ferzjes fan \"$1\"",
        "lineno": "Rigel $1:",
-       "compareselectedversions": "Ferlykje selektearre ferzjes",
+       "compareselectedversions": "Selektearre ferzjes ferlykje",
        "showhideselectedversions": "Oantikke ferzjes wol/net sjen litte",
        "editundo": "weromsette",
        "diff-empty": "(Gjin ferskil)",
+       "diff-multi-sameuser": "({{PLURAL:$1|Ien tuskenferzje|$1 tuskenferzjes}} fan deselde meidogger net werjûn)",
+       "diff-multi-otherusers": "({{PLURAL:$1|Ien tuskenferzje|$1 tuskenferzjes}} fan {{PLURAL:$2|ien oare meidogger|$2 meidoggers}} net werjûn)",
+       "diff-multi-manyusers": "({{PLURAL:$1|Ien tuskenferzje|$1 tuskenferzjes}} fan mear as $2 {{PLURAL:$2|meidogger|meidoggers}} net werjûn)",
        "searchresults": "Sykresultaten",
        "searchresults-title": "Sykresultaten foar \"$1\"",
        "titlematches": "Titels",
        "textmatches": "Siden",
        "notextmatches": "Gjin siden",
-       "prevn": "foarige {{PLURAL:$1|$1}}",
-       "nextn": "folgende {{PLURAL:$1|$1}}",
+       "prevn": "{{PLURAL:$1|$1}} foargeand",
+       "nextn": "{{PLURAL:$1|$1}} neikommend",
        "prev-page": "foarige side",
        "next-page": "folgjende side",
        "prevn-title": "{{PLURAL:$1|Foarich risseltaat|Foarige $1 risseltaten}}",
        "nextn-title": "{{PLURAL:$1|Folgjend risseltaat|Folgjende $1 risseltaat}}",
        "shown-title": "Lit $1 {{PLURAL:$1|resultaat|resultaten}} de side sjen",
-       "viewprevnext": "($1 {{int:pipe-separator}} $2) ($3) besjen.",
-       "searchmenu-exists": "<strong>Der is in side mei namme \"[[:$1]]\" yn dizze wiki</strong>",
+       "viewprevnext": "Besjoch ($1 {{int:pipe-separator}} $2) ($3)",
+       "searchmenu-exists": "<strong>Der is in side mei de namme \"[[:$1]]\" op 'e wiki.</strong> {{PLURAL:$2|0=|Sjoch ek de oare sykresultaten.}}",
        "searchmenu-new": "<strong>Meitsje de side \"[[:$1]]\" op dizze wiki!</strong> {{PLURAL:$2|0=|Sjoch ek de side fûn mei jo sykopdracht.|Sjoch ek de sykresultaten dy't fûn binne.}}",
        "searchprofile-articles": "Ynhâldlike siden",
        "searchprofile-images": "Multymedia",
        "searchprofile-articles-tooltip": "Sykje yn $1",
        "searchprofile-images-tooltip": "Sykje om bestannen",
        "searchprofile-everything-tooltip": "Alle ynhâld trochsykje (ynklusyf oerlissiden)",
-       "searchprofile-advanced-tooltip": "Sykje yn oanjûne nammerûmten",
+       "searchprofile-advanced-tooltip": "Sykje yn oanjûne nammeromten",
        "search-result-size": "$1 ({{PLURAL:$2|1 wurd|$2 wurden}})",
        "search-redirect": "(trochferwizing $1)",
        "search-section": "(seksje $1)",
        "search-relatedarticle": "Besibbe",
        "searchrelated": "besibbe",
        "searchall": "alle",
-       "showingresults": "{{PLURAL:$1|<strong>1</strong> resultaat|<strong>$1</strong> resultaten}} fan #<strong>$2</strong> ôf.",
+       "showingresults": "Totaal {{PLURAL:$1|<strong>1</strong> resultaat|<strong>$1</strong> resultaten}}, hjirûnder werjûn fan #<strong>$2</strong> ôf.",
        "search-showingresults": "{{PLURAL:$4|Resultaat <strong>$1</strong> fan <strong>$3</strong>|Resultaten <strong>$1 - $2</strong> fan <strong>$3</strong>}}",
        "search-nonefound": "Der binne gjin resultaten foar jo sykopdracht.",
-       "powersearch-legend": "Sykje",
-       "powersearch-ns": "Sykje yn nammeromten:",
-       "powersearch-togglelabel": "Oantikje:",
-       "powersearch-toggleall": "Alle",
-       "powersearch-togglenone": "Gjin",
+       "powersearch-legend": "Utwreidich sykje",
+       "powersearch-ns": "Nammeromten trochsykje:",
+       "powersearch-togglelabel": "Oanfinke:",
+       "powersearch-toggleall": "Alles",
+       "powersearch-togglenone": "Gjint",
        "powersearch-remember": "Seleksje ûnthâlde foar sykopdrachten yn 'e takomst",
        "search-external": "Utwindich sykje",
-       "searchdisabled": "<p>Op it stuit stiet it trochsykjen fan tekst út omdat dizze funksje tefolle kompjûterkapasiteit ferget. As we nije apparatuer krije, en dy is ûnderweis, dan wurdt dizze funksje wer aktyf. Oant salang kinne jo sykje fia Google:</p>",
+       "searchdisabled": "Sykjen op {{SITENAME}} is útskeakele.\nJo kinne yn 'e tuskentiid mei Google sykje.\nTink derom dat harren yndeksearring fan 'e ynhâld op {{SITENAME}} ferâldere wêze kin.",
        "preferences": "Foarkarren",
        "mypreferences": "Foarkarren",
        "prefs-edits": "Tal bewurkings:",
        "skin-preview": "Proefbyld",
        "datedefault": "Gjin foarkar",
        "prefs-user-pages": "Meidoggersiden",
-       "prefs-personal": "Persoanlike gegevens",
+       "prefs-personal": "Meidogger",
        "prefs-rc": "Koartlyn feroare",
        "prefs-watchlist": "Folchlist",
-       "prefs-editwatchlist": "Folchlist bewurkje",
-       "prefs-watchlist-days": "Oantal dagen yn folchlist sjen litte:",
-       "prefs-watchlist-days-max": "Maksimaal $1 {{PLURAL:$1|dei|dagen}}",
-       "prefs-watchlist-edits": "Tal wizigings om sjen te litten yn de útwreide folchlist:",
-       "prefs-watchlist-edits-max": "Maksimum oantal: 1000",
+       "prefs-editwatchlist": "Folchlist bewurkjen",
+       "prefs-editwatchlist-label": "Yngongen op jo folchlist bewurkje:",
+       "prefs-editwatchlist-edit": "Titels op jo folchlist besjen en wiskje",
+       "prefs-editwatchlist-raw": "Rûge folchlist bewurkje",
+       "prefs-editwatchlist-clear": "Jo folchlist wiskje",
+       "prefs-watchlist-days": "Sichtber tal dagen yn 'e folchlist:",
+       "prefs-watchlist-days-max": "Maksimum $1 {{PLURAL:$1|dei|dagen}}",
+       "prefs-watchlist-edits": "Maksimaal sichtber tal wizigings yn 'e folchlist:",
+       "prefs-watchlist-edits-max": "Maksimumtal: 1000",
        "prefs-watchlist-token": "Folchlistkaai:",
+       "prefs-watchlist-managetokens": "Kaaien beheare",
        "prefs-misc": "Ferskaat",
        "prefs-resetpass": "Wachtwurd feroarje",
+       "prefs-changeemail": "E-mailadres wizigje as wiskje",
+       "prefs-setemail": "E-mailadres ynstelle",
        "prefs-email": "E-mail",
        "prefs-rendering": "Uterlik",
        "saveprefs": "Bewarje",
-       "restoreprefs": "Tebek nei de standertynstellings",
-       "prefs-editing": "Siden bewurkje",
+       "restoreprefs": "Alle standertynstellings weromsette (yn alle parten)",
+       "prefs-editing": "Bewurkjen",
        "searchresultshead": "Sykje",
        "stub-threshold": "Drompel foar markearring <a href=\"#\" class=\"stub\">stobbe</a> (bytes):",
        "stub-threshold-disabled": "Utskeakele",
-       "recentchangesdays": "Dagen om sjen te litten yn Koartlyn feroare:",
-       "recentchangesdays-max": "(maksimaal $1 {{PLURAL:$1|dei|dagen}})",
-       "recentchangescount": "Tal titels op 'Koartlyn feroare'",
+       "recentchangesdays": "Sichtber tal dagen yn Koartlyn feroare:",
+       "recentchangesdays-max": "Maksimum $1 {{PLURAL:$1|dei|dagen}}",
+       "recentchangescount": "Standert sichtber tal bewurkings yn Koartlyn feroare, sideskiednis en lochs:",
+       "prefs-help-recentchangescount": "Maksimumtal: 1000",
+       "prefs-help-watchlist-token2": "Dit is de geheime tagongskoade ta de webfied fan jo folchlist.\nImmen dy't it wit, sil jo folchlist lêze kinne, dus diel it mei gjinien.\nBy need [[Special:ResetTokens|kinne jo it fernije]].",
+       "prefs-help-tokenmanagement": "Jo kinne de geheime koade foar jo akkount, dy't tagong jout ta de Webfied fan jo folchlist, besjen en fernije. Immen dy't de tagongskoade wit, sil jo folchlist lêze kinne, dus diel it mei gjinien.",
        "savedprefs": "Jo foarkarren binne fêstlein.",
        "timezonelegend": "Tiidsône:",
        "localtime": "Pleatslike tiid:",
        "timezoneregion-indian": "Yndyske Oseaan",
        "timezoneregion-pacific": "Stille Oseaan",
        "allowemail": "Stean oare meidoggers ta my te e-mailen",
-       "prefs-searchoptions": "Sykje",
+       "prefs-searchoptions": "Sykjen",
        "prefs-namespaces": "Nammeromten",
        "default": "standert",
        "prefs-files": "Bestannen",
        "prefs-custom-js": "Persoanlik JS",
+       "prefs-reset-intro": "Jo kinne dizze side brûke, en set jo ynstellings werom nei de websteestandert.\nDat kin net ûngedien makke wurde.",
        "prefs-emailconfirm-label": "E-mailbefêstiging:",
        "youremail": "E-mail:",
        "username": "{{GENDER:$1|Meidochnamme}}:",
-       "prefs-memberingroups": "Lid fan {{PLURAL:$1|groep|groepen}}:",
+       "prefs-memberingroups": "{{GENDER:$2|Lid}} fan {{PLURAL:$1|groep|groepen}}:",
        "prefs-memberingroups-type": "$1",
        "prefs-registration-date-time": "$1",
        "yourrealname": "Jo wiere namme:",
        "yourlanguage": "Taal:",
-       "yournick": "Jo alias (foar sinjaturen)",
-       "badsig": "Unjildige ûndertekening; kontrolearje de HTML-tags.",
+       "yournick": "Nije sinjatuer:",
+       "badsig": "Unjildige sinjatuer yn koadefoarm.\nKontrolearje de HTML-tags.",
        "badsiglength": "Bynamme is te lang; dy moat koarter as $1 {{PLURAL:$1|teken|tekens}} wêze.",
        "yourgender": "Hoe wolsto beskreaun wurde?",
        "gender-unknown": "Ik wol dit net oanjûn",
        "prefs-dateformat": "Datumopmaak",
        "prefs-timeoffset": "Tiidsferskil",
        "prefs-advancedediting": "Algemiene opsjes",
-       "prefs-editor": "Tekstferwurker",
+       "prefs-editor": "Tekstbewurker",
        "prefs-preview": "Proefbyld",
        "prefs-advancedrc": "Avansearre opsjes",
        "prefs-advancedrendering": "Avansearre opsjes",
        "prefs-advancedsearchoptions": "Avansearre opsjes",
        "prefs-advancedwatchlist": "Avansearre opsjes",
-       "prefs-displayrc": "Werjefteopsjes",
-       "prefs-displaywatchlist": "Werjefteopsjes",
-       "prefs-tokenwatchlist": "Token",
+       "prefs-displayrc": "Werjefte-opsjes",
+       "prefs-displaywatchlist": "Werjefte-opsjes",
+       "prefs-changesrc": "Werjûne feroarings",
+       "prefs-changeswatchlist": "Werjûne feroarings",
+       "prefs-pageswatchlist": "Folchsiden",
+       "prefs-tokenwatchlist": "Kaai",
        "prefs-diffs": "Ferskillen",
        "userrights": "Behear fan meidoggerrjochten",
        "userrights-lookup-user": "Behear fan meidoggerrjochten",
        "userrights-user-editname": "Jou in meidochnamme:",
        "editusergroup": "Wizigje meidoggerrjochten",
        "editinguser": "Bewurkje meidoggerrjochten fan <strong>[[User:$1|$1]]</strong> $2",
-       "userrights-editusergroup": "Wizigje meidoggerrjochten",
+       "userrights-editusergroup": "{{GENDER:$1|Meidochgroepen}} bewurkje",
+       "userrights-viewusergroup": "{{GENDER:$1|Meidochgroepen}} besjen",
        "saveusergroups": "Meidoggerrjochten bewarje",
        "userrights-groupsmember": "Sit yn group:",
        "userrights-groupsmember-type": "$1",
        "right-deletedhistory": "Wiske ferzjes besjen, sûnder sjen te kinnen wat wiske is.",
        "right-browsearchive": "Wiske siden besjen",
        "right-undelete": "Wiske siden tebeksette",
-       "right-suppressrevision": "Ferskûle ferzjes besjen en tebeksette",
+       "right-suppressrevision": "Beskate sideferzjes fan in meidogger besjen, ferbergje of werombringe",
        "right-suppressionlog": "Net-publike logboeken besjen",
        "right-block": "Oare meidoggers de mûglikheid ta bewurkjen ôfnimme",
        "right-blockemail": "In meidogger it rjocht ta it ferstjoeren fan e-mail ôfnimme",
        "right-editusercss": "De CSS-bestannen fan oare meidoggers bewurkje",
        "right-edituserjson": "De JSON-bestannen fan oare meidoggers bewurkje",
        "right-edituserjs": "De JS-bestannen fan oare meidoggers bewurkje",
-       "right-rollback": "Gau de bewurkings omdraaie fan 'e lêste meidogger dy't in beskate side bewurke",
-       "right-markbotedits": "Tebekdraaide bewurkings markearje as botbewurkings",
+       "right-rollback": "Gau de bewurkings weromdraaie fan 'e lêste meidogger dy't in beskate side bewurke",
+       "right-markbotedits": "Weromdraaide bewurkings markearje as botbewurkings",
        "right-noratelimit": "Hat gjin tiidsôfhinklike beheinings",
        "right-import": "Siden út oare wiki's ymportearje",
        "right-importupload": "Siden ymportearje út in opladen bestân",
        "right-siteadmin": "De database blokkearje en wer frij jaan",
        "right-override-export-depth": "Alle siden oant en mei in keppelingsdjipte fan fiif fuortskriuwe",
        "grant-group-email": "E-mail stjoere",
+       "grant-rollback": "Wizigings oan siden weromdraaie",
        "newuserlogpage": "Ynskriuwingsloch",
        "newuserlogpagetext": "Dit is in loch fan meidoggers dy't de lêste tiid ynskreaun binne.",
-       "rightslog": "Rjochten-loch",
+       "rightslog": "Rjochtenloch",
        "rightslogtext": "Dit is in loch fan feroarings fan meidoggerrjochten.",
        "action-read": "dizze side besjen",
        "action-edit": "dizze side te bewurkjen",
        "action-suppressionlog": "dit beskerme logboek besjen",
        "action-block": "dizze meidogger in bewurkingsblokkade oplizze",
        "action-protect": "it befeiligingsnivo fan dizze side oanpasse",
-       "action-rollback": "gau de bewurkings omdraaien fan 'e lêste meidogger dy't in beskate side bewurke",
+       "action-rollback": "gau de bewurkings weromdraaien fan 'e lêste meidogger dy't in beskate side bewurke",
        "action-import": "dizze side fan in oare wiki ymportearje",
        "action-importupload": "siden ymportearjen út in opladen bestân",
        "action-patrol": "bewurkings fan oaren as kontrolearre beskôgje",
        "recentchanges": "Koartlyn feroare",
        "recentchanges-legend": "Opsjes foar resinte feroarings",
        "recentchanges-summary": "Folgje de lêste feroarings oan 'e wiki op dizze side.",
+       "recentchanges-noresult": "Gjin feroaring yn 'e opjûne perioade foldocht oan dizze kritearia.",
+       "recentchanges-notargetpage": "Jou hjirboppe in sidenamme, en besjoch feroarings foar dy side.",
        "recentchanges-feed-description": "Mei dizze feed kinne jo de nijste feroarings yn dizze wiki besjen.",
        "recentchanges-label-newpage": "Mei dizze wiziging is in nije side makke",
        "recentchanges-label-minor": "Dizze feroaring is fan lytse betsjutting",
        "recentchanges-label-bot": "Dizze bewurking is troch in bot útfierd",
-       "recentchanges-label-unpatrolled": "Dizze wiziging is noch net neisjûn",
+       "recentchanges-label-unpatrolled": "Dizze wiziging is noch net neisjoen",
        "recentchanges-label-plusminus": "De sidegrutte is mei dit oantal bytes wizige",
        "recentchanges-legend-heading": "<strong>Leginda:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}}<br />(sjoch ek de [[Special:NewPages|list mei nije siden]])",
+       "recentchanges-submit": "Werjaan",
+       "rcfilters-tag-remove": "'$1' fuortsmite",
        "rcfilters-legend-heading": "<strong>List fan ôfkoartings:</strong>",
-       "rcnotefrom": "Dit binne de feroarings sûnt <b>$2</b> (maksimaal <b>$1</b>).",
-       "rclistfrom": "Jou nije feroarings, begjinnende mei $3 $2",
-       "rcshowhideminor": "lytse feroarings $1",
+       "rcfilters-other-review-tools": "Oare oersjochmiddels",
+       "rcfilters-group-results-by-page": "Resultaten op side groepearje",
+       "rcfilters-activefilters": "Aktive filters",
+       "rcfilters-activefilters-hide": "Ynklappe",
+       "rcfilters-activefilters-show": "Utklappe",
+       "rcfilters-activefilters-hide-tooltip": "Fek mei Aktive filters ferbergje",
+       "rcfilters-activefilters-show-tooltip": "Fek mei Aktive filters sjen litte",
+       "rcfilters-advancedfilters": "Utwreide filters",
+       "rcfilters-limit-title": "Resultaten werjaan",
+       "rcfilters-limit-and-date-label": "$1 {{PLURAL:$1|feroaring|feroarings}}, $2",
+       "rcfilters-date-popup-title": "Tiidsperioade trochsykje",
+       "rcfilters-days-title": "Lêste dagen",
+       "rcfilters-hours-title": "Lêste oeren",
+       "rcfilters-days-show-days": "$1 {{PLURAL:$1|dei|dagen}}",
+       "rcfilters-days-show-hours": "$1 {{PLURAL:$1|oere|oeren}}",
+       "rcfilters-quickfilters": "Bewarre filters",
+       "rcfilters-quickfilters-placeholder-title": "Noch gjin filters bewarre",
+       "rcfilters-quickfilters-placeholder-description": "Klik op it blêdwizerikoan yn it fek mei Aktive filters hjirûnder, en bewarje jo filterynstellings om nochris te brûken.",
+       "rcfilters-savedqueries-defaultlabel": "Bewarre filters",
+       "rcfilters-savedqueries-rename": "Omneame",
+       "rcfilters-savedqueries-setdefault": "As standert ynstelle",
+       "rcfilters-savedqueries-unsetdefault": "As standert wiskje",
+       "rcfilters-savedqueries-remove": "Wiskje",
+       "rcfilters-savedqueries-new-name-label": "Namme",
+       "rcfilters-savedqueries-new-name-placeholder": "Beskriuw it doel fan it filter",
+       "rcfilters-savedqueries-apply-label": "Filter oanmeitsje",
+       "rcfilters-savedqueries-apply-and-setdefault-label": "Standertfilter oanmeitsje",
+       "rcfilters-savedqueries-cancel-label": "Annulearje",
+       "rcfilters-savedqueries-add-new-title": "De filterynstellings fan no bewarje",
+       "rcfilters-savedqueries-already-saved": "Dizze filters wurde al bewarre. Feroarje jo ynstellings om in nij filter bewarje te kinnen.",
+       "rcfilters-restore-default-filters": "Standertfilters werombringe",
+       "rcfilters-clear-all-filters": "Alle filters wiskje",
+       "rcfilters-show-new-changes": "Nijste feroarings besjen",
+       "rcfilters-search-placeholder": "Feroarings filterje (brûk it menu of sykje op filternamme)",
+       "rcfilters-empty-filter": "Gjin aktive filters. Alle bydragen wurde werjûn.",
+       "rcfilters-filterlist-feedbacklink": "Lit ús hearre wat jo fan dit filterark fine",
+       "rcfilters-highlightbutton-title": "Resultaten aksintuearje",
+       "rcfilters-highlightmenu-title": "Kies in kleur",
+       "rcfilters-highlightmenu-help": "Kleur kieze foar it aksintuearjen fan dizze eigenskip",
+       "rcfilters-filtergroup-authorship": "Skriuwer fan 'e bydragen",
+       "rcfilters-filter-editsbyself-label": "Wizigings fan jo",
+       "rcfilters-filter-editsbyself-description": "Jo eigen bydragen.",
+       "rcfilters-filter-editsbyother-label": "Wizigings fan oaren",
+       "rcfilters-filter-editsbyother-description": "Alle wizigings, útsein jo eigen.",
+       "rcfilters-filtergroup-user-experience-level": "Meidoggerynskriuwing en bedreaunens",
+       "rcfilters-filter-user-experience-level-registered-label": "Ynskreaun",
+       "rcfilters-filter-user-experience-level-registered-description": "Oanmelde bewurkers.",
+       "rcfilters-filter-user-experience-level-unregistered-label": "Net-ynskreaun",
+       "rcfilters-filter-user-experience-level-unregistered-description": "Bewurkers dy't net oanmeld binne.",
+       "rcfilters-filter-user-experience-level-newcomer-label": "Nijkommers",
+       "rcfilters-filter-user-experience-level-newcomer-description": "Ynskreaune bewurkers mei minder as 10 bewurkings of noch gjin 4 dagen dwaande.",
+       "rcfilters-filter-user-experience-level-learner-label": "Learders",
+       "rcfilters-filter-user-experience-level-learner-description": "Ynskreaune bewurkers waans ûnderfining falt tusken \"Nijkommers\" en \"Bedreaune meidoggers\".",
+       "rcfilters-filter-user-experience-level-experienced-label": "Bedreaune meidoggers",
+       "rcfilters-filter-user-experience-level-experienced-description": "Ynskreaune bewurkers mei mear as 500 bewurkings en 30 dagen dwaande.",
+       "rcfilters-filtergroup-automated": "Automatisearre bydragen",
+       "rcfilters-filter-bots-description": "Wizigings makke troch automatisearre helpmiddels.",
+       "rcfilters-filter-humans-label": "Minske (gjin bot)",
+       "rcfilters-filter-humans-description": "Wizigings makke troch minskehannen.",
+       "rcfilters-filtergroup-significance": "Belang",
+       "rcfilters-filter-minor-label": "Lytse betsjutting",
+       "rcfilters-filter-minor-description": "Feroarings troch de skriuwer lebele as fan lytse betsjutting.",
+       "rcfilters-filter-major-label": "Gjin lytse betsjutting",
+       "rcfilters-filter-major-description": "Feroarings net lebele as fan lytse betsjutting.",
+       "rcfilters-filtergroup-watchlist": "Folchlistsiden",
+       "rcfilters-filter-watchlist-watched-label": "Op 'e folchlist",
+       "rcfilters-filter-watchlist-watched-description": "Wizigings oan siden op jo folchlist.",
+       "rcfilters-filter-watchlist-watchednew-label": "Nije folchlistwizigings",
+       "rcfilters-filter-watchlist-watchednew-description": "Wizigings oan folchlistsiden dy't jo dêrnei noch net besocht hawwe.",
+       "rcfilters-filter-watchlist-notwatched-label": "Net op 'e folchlist",
+       "rcfilters-filter-watchlist-notwatched-description": "Alles, útsein wizigings oan jo folchlistsiden.",
+       "rcfilters-filtergroup-watchlistactivity": "Folchlistdrokte",
+       "rcfilters-filter-watchlistactivity-unseen-label": "Wizigings net sjoen",
+       "rcfilters-filter-watchlistactivity-unseen-description": "Wizigings oan siden dy't jo dêrnei noch net besocht hawwe.",
+       "rcfilters-filter-watchlistactivity-seen-label": "Wizigings sjoen",
+       "rcfilters-filter-watchlistactivity-seen-description": "Wizigings oan siden dy't jo dêrnei al besocht hawwe.",
+       "rcfilters-filtergroup-changetype": "Wizigingssoarte",
+       "rcfilters-filter-pageedits-label": "Sidebewurkings",
+       "rcfilters-filter-pageedits-description": "Wizigings oan wikiynhâld, diskusjes, kategorybeskriuwings …",
+       "rcfilters-filter-newpages-label": "Nije siden",
+       "rcfilters-filter-newpages-description": "Wizigings wêrmei't nije siden oanmakke wurde.",
+       "rcfilters-filter-categorization-label": "Kategoryferoarings",
+       "rcfilters-filter-categorization-description": "Ynfo oer siden taheakke oan, as weihelle út kategoryen.",
+       "rcfilters-filter-logactions-label": "Lochaksjes",
+       "rcfilters-filter-logactions-description": "Administrative hannelings, akkounts oanmeitsjen, siden wiskjen, bestannen opladen …",
+       "rcfilters-filtergroup-lastrevision": "Lêste ferzjes",
+       "rcfilters-filter-lastrevision-label": "Lêste ferzje",
+       "rcfilters-filter-lastrevision-description": "Allinnich de resintste wiziging fan in side.",
+       "rcfilters-filter-previousrevision-label": "Net de lêste ferzje",
+       "rcfilters-filter-previousrevision-description": "Alle wizigings dy't net de \"lêste ferzje\" binne.",
+       "rcfilters-filter-excluded": "Utsein",
+       "rcfilters-exclude-button-off": "Seleksje omkeare",
+       "rcfilters-exclude-button-on": "Omkearde seleksje",
+       "rcfilters-view-tags": "Lebele bewurkings",
+       "rcfilters-view-namespaces-tooltip": "Resultaten op nammeromte filterje",
+       "rcfilters-view-tags-tooltip": "Resultaten mei bewurkingslebels filterje",
+       "rcfilters-view-return-to-default-tooltip": "Werom nei it filterhaadmenu",
+       "rcfilters-view-tags-help-icon-tooltip": "Kom mear oan 'e weet oer Lebele bewurkings",
+       "rcfilters-liveupdates-button": "Daliks bywurkje",
+       "rcfilters-liveupdates-button-title-on": "Daliks bywurkjen stopje",
+       "rcfilters-liveupdates-button-title-off": "Nije feroarings op it stuit werjaan",
+       "rcfilters-watchlist-markseen-button": "Alle wizigings as sjoen markearje",
+       "rcfilters-watchlist-edit-watchlist-button": "Jo list mei folchsiden bewurkje",
+       "rcfilters-watchlist-showupdated": "Wizigings oan siden dy't jo dêrnei noch net besocht hawwe, wurde <strong>fet</strong>, mei opfolle rûntsjes markearre.",
+       "rcfilters-preference-label": "De JavaScript-leaze omjouwing brûke",
+       "rcfilters-preference-help": "Laadt Koartlyn feroare sûnder sykfilters of aksintuearmooglikheid.",
+       "rcfilters-watchlist-preference-label": "De JavaScript-leaze omjouwing brûke",
+       "rcfilters-watchlist-preference-help": "Laadt de Folchlist sûnder sykfilters of aksintuearmooglikheid.",
+       "rcfilters-filter-showlinkedfrom-label": "Feroarings werjaan op siden ferwiisd fan",
+       "rcfilters-filter-showlinkedfrom-option-label": "<strong>Siden ferwiisd fan</strong> de opjûne side",
+       "rcfilters-filter-showlinkedto-label": "Feroarings werjaan op siden ferwizend nei",
+       "rcfilters-filter-showlinkedto-option-label": "<strong>Siden ferwizend nei</strong> de opjûne side",
+       "rcfilters-target-page-placeholder": "Jou in sidenamme (of kategory)",
+       "rcnotefrom": "Hjirûnder {{PLURAL:$5|stiet de feroaring|steane de feroarings}} sûnt <strong>$3, $4</strong> (maksimaal <strong>$1</strong> werjûn).",
+       "rclistfromreset": "Datumseleksje werynstelle",
+       "rclistfrom": "Jou nije feroarings, begjinnend op $3, $2",
+       "rcshowhideminor": "Lytse feroarings $1",
        "rcshowhideminor-show": "werjaan",
        "rcshowhideminor-hide": "ferbergje",
-       "rcshowhidebots": "bots $1",
+       "rcshowhidebots": "Bots $1",
        "rcshowhidebots-show": "werjaan",
        "rcshowhidebots-hide": "ferbergje",
        "rcshowhideliu": "Registrearre meidoggers $1",
        "rcshowhideliu-show": "werjaan",
        "rcshowhideliu-hide": "ferbergje",
-       "rcshowhideanons": "$1 anonimen",
+       "rcshowhideanons": "Anonime meidoggers $1",
        "rcshowhideanons-show": "werjaan",
        "rcshowhideanons-hide": "ferbergje",
        "rcshowhidepatr": "kontrolearre bewurkings $1",
        "rcshowhidepatr-show": "werjaan",
        "rcshowhidepatr-hide": "ferbergje",
-       "rcshowhidemine": "$1 eigen bewurkings",
+       "rcshowhidemine": "Myn bewurkings $1",
        "rcshowhidemine-show": "werjaan",
        "rcshowhidemine-hide": "ferbergje",
-       "rclinks": "Jou $1 nije feroarings yn de lêste $2 dagen",
+       "rcshowhidecategorization": "Siden kategorisearjen $1",
+       "rcshowhidecategorization-show": "werjaan",
+       "rcshowhidecategorization-hide": "ferbergje",
+       "rclinks": "Jou de lêste $1 feroarings fan 'e lêste $2 dagen",
        "diff": "fersk.",
        "hist": "skied.",
        "hide": "gjin",
        "newpageletter": "N",
        "boteditletter": "b",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 folgjende {{PLURAL:$1|meidogger|meidoggers}}]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} nei wiziging",
        "newsectionsummary": "/* $1 */ nije seksje",
        "recentchangeslinked-feed": "Folgje keppelings",
        "recentchangeslinked-toolbox": "Folgje keppelings",
        "recentchangeslinked-title": "Feroarings yn ferbân mei \"$1\"",
-       "recentchangeslinked-summary": "Dizze spesjale side lit de lêste bewurkings sjen op siden dy't keppele wurde fan in spesifisearre side ôf (of fan in spesifisearre Kategory ôf). Siden dy't op [[Special:Watchlist|jo folchlist]] steane, wurde '''tsjûk''' werjûn.",
+       "recentchangeslinked-summary": "Jou in sidenamme, en besjoch de feroarings op siden dy't keppele binne fan as nei dy side. (Jou {{ns:category}}:Kategorynamme om de leden fan in kategory te besjen). Wizigings oan siden op [[Special:Watchlist|jo Folchlist]] wurde <strong>fet</strong> werjûn.",
        "recentchangeslinked-page": "Sidenamme:",
        "recentchangeslinked-to": "Feroarings oan siden mei ferwizings nei dizze side besjen",
-       "upload": "Bied bestân oan",
-       "uploadbtn": "Bied bestân oan",
-       "reuploaddesc": "Werom nei oanbied-side.",
+       "recentchanges-page-added-to-category": "[[:$1]] oan kategory taheakke",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] oan kategory taheakke; [[Special:WhatLinksHere/$1|dizze side is opnommen yn oare siden]]",
+       "recentchanges-page-removed-from-category": "[[:$1]] út kategory weihelle",
+       "recentchanges-page-removed-from-category-bundled": "[[:$1]] út kategory weihelle; [[Special:WhatLinksHere/$1|dizze side is opnommen yn oare siden]]",
+       "upload": "Bestân oanbiede",
+       "uploadbtn": "Bestân oplade",
+       "reuploaddesc": "Opladen annulearje en weromgean nei it oanbiedformulier",
        "uploadnologin": "Net oanmeld",
        "uploadnologintext": "Jo moatte $1 om bestannen oplade te kinnen.",
        "upload_directory_missing": "De heechlaadmap ($1) is der net en koe net oanmakke wurde troch de webserver.",
        "upload-preferred": "Oanwiisde bestânstypen: $1.",
        "upload-prohibited": "Ferbeane bestânstypen: $1.",
        "uploadlogpage": "Oanbiedloch",
-       "uploadlogpagetext": "List fan de lêst oanbeane bestannen. (Tiid oanjûn as UTC).",
+       "uploadlogpagetext": "Hjirûnder stiet in list fan 'e meast resint opladen bestannen.\nSjoch de [[Special:NewFiles|galery mei nije bestannen]] foar in fisueler oersjoch.",
        "filename": "Bestânsnamme",
        "filedesc": "Omskriuwing",
        "fileuploadsummary": "Gearfetting:",
        "listfiles-latestversion-no": "Nee",
        "file-anchor-link": "Bestân",
        "filehist": "Bestânsskiednis",
-       "filehist-help": "Klik op in tiid om de ferzje fan it bestân op dat stuit te sjen.",
+       "filehist-help": "Klik op in datum/tiid, en besjoch it bestân sa't it op dat stuit wie.",
        "filehist-deleteall": "wiskje alles",
        "filehist-deleteone": "fuortsmite",
        "filehist-revert": "werom sette",
        "filehist-current": "lêste",
-       "filehist-datetime": "Tiid",
+       "filehist-datetime": "Datum/tiid",
        "filehist-thumb": "Miniatuer",
        "filehist-thumbtext": "Miniatuer foar de ferzje sûnt $1",
        "filehist-nothumb": "Gjin miniatuerôfbylding",
        "nolinkstoimage": "Der binne gjin siden oan dit ôfbyld keppele.",
        "morelinkstoimage": "[[Special:WhatLinksHere/$1|Mear ferwizings]] nei dit bestân besjen.",
        "duplicatesoffile": "{{PLURAL:$1|It|De}} neikommend{{PLURAL:$1|&#32;bestân is|e $1 bestannen binne}} identyk oan dit bestân ([[Special:FileDuplicateSearch/$2|mear bysûnderheden]]):",
-       "sharedupload": "Dit bestân komt fan $1 en kin ek troch oare projekten brûkt wurde.",
+       "sharedupload": "Dit bestân komt fan $1, en kin ek troch oare projekten brûkt wurde.",
+       "sharedupload-desc-here": "Dit bestân komt fan $1, en kin ek troch oare projekten brûkt wurde.\nDe beskriuwing op syn [$2 bestânsside] dêre wurdt hjirûnder werjûn.",
        "filepage-nofile": "Der bestiet gjin bestân mei sa'n namme.",
        "filepage-nofile-link": "Der bestiet gjin bestân mei sa'n namme [bied $1 oan].",
        "uploadnewversion-linktext": "Bied in nije ferzje fan dit bestân oan",
        "randompage-nopages": "Der binne gjin siden yn'e nammeromte \"$1\".",
        "randomincategory-category": "Kategory:",
        "randomredirect": "Samar in trochferwizing",
-       "randomredirect-nopages": "Der binne gjin trochferwizings yn'e nammerûmte \"$1\".",
+       "randomredirect-nopages": "Der binne gjin trochferwizings yn'e nammeromte \"$1\".",
        "statistics": "Statistyk",
        "statistics-header-pages": "Sidestatistiken",
        "statistics-header-edits": "Bewurkingsstatistiken",
        "notargettext": "Jo hawwe net sein oer hokfoar side jo dit witte wolle.",
        "nopagetitle": "Side bestiet net",
        "nopagetext": "De side dy't jo in oare namme jaan wolle bestiet net.",
-       "pager-newer-n": "{{PLURAL:$1|nijere 1|nijere $1}}",
+       "pager-newer-n": "{{PLURAL:$1|1 nijer|$1 nijer}}",
        "pager-older-n": "{{PLURAL:$1|1 âlder|$1 âlder}}",
        "suppress": "Tafersjoch",
        "apihelp": "API-help",
        "specialloguserlabel": "Utfierder:",
        "speciallogtitlelabel": "Doel (sidetitel of {{ns:user}}:meidochnamme foar meidogger):",
        "log": "Lochs",
+       "logeventslist-submit": "Werjaan",
+       "logeventslist-more-filters": "Oanfoljende lochs werjaan:",
+       "logeventslist-patrol-log": "Neisjochloch",
+       "logeventslist-tag-log": "Lebelloch",
        "all-logs-page": "Alle iepenbiere lochboeken",
        "alllogstext": "Gearfoege werjefte fan alle beskikbere lochs op {{SITENAME}}.\nJo kinne it byld beheine troch it kiezen fan in lochtype, de meidochnamme (haadlettergefoelich) of de oanbelangjende side (ek haadlettergefoelich).",
        "logempty": "Gjin treffers yn it loch.",
        "log-title-wildcard": "Siden sykje dy't mei dizze namme begjinne",
+       "log-edit-tags": "Lebels fan selektearre lochrigels bewurkje",
+       "checkbox-select": "Seleksje: $1",
+       "checkbox-all": "Alles",
+       "checkbox-none": "Gjint",
+       "checkbox-invert": "Omkeard",
        "allpages": "Alle siden",
        "nextpage": "Folgjende side ($1)",
        "prevpage": "Foargeande side ($1)",
        "allpagessubmit": "Los!",
        "allpagesprefix": "Siden sjen litte dy't begjinne mei:",
        "allpagesbadtitle": "De opjûne sidenamme is ûnjildich of hat in yntertaal- of ynterwikifoarheaksel.\nMûglik befettet de namme karakters dy't net brûkt wurde meie yn sidenammen.",
-       "allpages-bad-ns": "{{SITENAME}} hat gjin nammerûmte \"$1\".",
+       "allpages-bad-ns": "{{SITENAME}} hat gjin nammeromte \"$1\".",
        "categories": "Kategoryen",
        "categoriespagetext": "De folgjende {{PLURAL:$1|kategory bestiet|kategoryen bestean}} op 'e wiki, en {{PLURAL:$1|is|binne}} al of net brûkt.\nSjoch ek [[Special:WantedCategories|Net-besteande kategoryen mei ferwizings]].",
        "categoriesfrom": "Kategoryen werjaan fan .. ôf:",
        "watchlistfor2": "Foar $1 $2",
        "nowatchlist": "Jo hawwe gjin siden op jo folchlist.",
        "watchlistanontext": "Jo moatte $1 om siden op jo folchlist besjen of bewurkje te kinnen.",
-       "watchnologin": "Net oanmeld yn",
+       "watchnologin": "Net oanmeld",
        "addwatch": "Oan folchlist tafoegje",
        "addedwatchtext": "\"[[:$1]]\" en de bybehearrende oerlisside binne tafoege oan jo [[Special:Watchlist|folchlist]].",
        "removedwatchtext": "De side \"[[:$1]]\" stiet net mear op jo folchlist.",
        "watch": "Folgje",
        "watchthispage": "Folgje dizze side",
-       "unwatch": "Ferjit",
+       "unwatch": "Net folgje",
        "unwatchthispage": "Ferjit dizze side",
-       "notanarticle": "Dit kin net folge wurde.",
-       "watchlist-details": "Jo folchlist hat {{PLURAL:$1|$1 side|$1 siden}}, oerlissiden net meiteld.",
-       "wlnote": "Dit {{PLURAL:$1|is de lêste feroaring|binne de lêste '''$1''' feroarings}} yn de lêste {{PLURAL:$2|oer|'''$2''' oeren}}.",
+       "notanarticle": "Gjin ynhâldlike side",
+       "watchlist-details": "Op jo Folchlist {{PLURAL:$1|stiet $1 side|steane $1 siden}} (plus oerlissiden).",
+       "wlheader-enotif": "E-mailnotifikaasje is ynskeakele.",
+       "wlheader-showupdated": "Siden dy't wizige binne nei't jo dy it lêst besocht hawwe, wurde <strong>fet</strong> werjûn.",
+       "wlnote": "Hjirûnder {{PLURAL:$1|stiet de lêste feroaring|steane de lêste <strong>$1</strong> feroarings}} fan 'e lêste {{PLURAL:$2|oere|<strong>$2</strong> oeren}}, sûnt $3, $4.",
        "wlshowlast": "Lit feroarings sjen fan de lêste $1 oeren $2 dagen",
+       "watchlist-hide": "Ferbergje",
+       "watchlist-submit": "Werjaan",
+       "wlshowtime": "Tiidsperioade fan werjefte:",
+       "wlshowhideminor": "lytse feroarings",
+       "wlshowhideliu": "registrearre meidoggers",
+       "wlshowhideanons": "anonime meidoggers",
+       "wlshowhidemine": "myn bewurkings",
+       "wlshowhidecategorization": "siden kategorisearjen",
+       "watchlist-options": "Folchlistopsjes",
        "watching": "Dwaande mei op'e folchlist te setten ...",
        "unwatching": "Dwaande mei fan'e folchlist ôf te heljen ...",
+       "enotif_reset": "Alle wizigings as besocht markearje",
        "enotif_impersonal_salutation": "meidogger fan {{SITENAME}}",
        "enotif_body": "Bêste $WATCHINGUSERNAME,\n\n$PAGEINTRO $NEWPAGE\n\nGearfetting: $PAGESUMMARY $PAGEMINOREDIT\n\nFoar oerlis mei meidogger:\nnetpost: $PAGEEDITOR_EMAIL\nwiki: $PAGEEDITOR_WIKI\n\nFierdere meldings wurde jo net tastjoerd, oant jo de side lêzen hawwe. Op jo folchlist kinne jo op 'e nij meldings foar al jo folge siden freegje.\n\nJo freonlike {{SITENAME}}-meldingssysteem.\n\n--\nGean nei {{canonicalurl:{{#special:Preferences}}}}\nom jo netpostynstellings te feroarjen.\n\nGean nei {{canonicalurl:{{#special:EditWatchlist}}}}\nom jo folchlistynstellings te feroarjen.\n\nOm de side fan jo folchlist te ferwiderjen, gean nei\n$UNWATCHURL\n\nReaksjes en fierdere help:\n$HELPPAGE",
        "created": "oanmakke",
        "delete-confirm": "\"$1\" fuortsmite",
        "delete-legend": "Fuortsmite",
        "historywarning": "<strong>Warskôging:</strong> De side dy't jo wiskje wolle hat skiednis:",
+       "historyaction-submit": "Ferzjes werjaan",
        "confirmdeletetext": "Jo binne dwaande mei it foar altyd wiskjen fan in side\nof ôfbyld, tegearre mei alle skiednis, út de databank.\nBefêstigje dat jo dat wier dwaan wolle. Befêstigje dat dat is wat jo witte wat it gefolch\nis en dat jo dit dogge neffens de [[{{MediaWiki:Policy-url}}]].",
        "actioncomplete": "Dien",
        "deletedtext": "\"$1\" is wiske.\nSjoch \"$2\" foar in list fan wat resint wiske is.",
        "dellogpage": "Wiskloch",
        "dellogpagetext": "Dit is wat der resint wiske is.\n(Tiden oanjûn as UTC).",
        "deletionlog": "wiskloch",
+       "log-name-create": "Side-oanmeitsingsloch",
+       "logentry-create-create": "$1 {{GENDER:$2|hat}} de side $3 makke",
        "reverted": "Weromset nei eardere ferzje",
        "deletecomment": "Reden:",
        "deleteotherreason": "Oare/eventuele reden:",
        "deletereasonotherlist": "Oare reden",
        "deletereason-dropdown": "*Faak-brûkte redenen\n** Frege troch de skriuwer\n** Skeining fan auteursrjocht\n** Fandalisme",
-       "rollback": "Bewurkings omdraaie",
-       "rollbacklink": "omdraaie",
-       "rollbacklinkcount": "$1 {{PLURAL:$1|bewurking|bewurkings}} omdraaie",
-       "rollbacklinkcount-morethan": "mear as $1 {{PLURAL:$1|bewurking|bewurkings}} omdraaie",
-       "rollbackfailed": "Omdraaie net slagge",
+       "rollback": "Wizigings weromdraaie",
+       "rollback-confirmation-yes": "Weromdraaie",
+       "rollbacklink": "weromdraaie",
+       "rollbacklinkcount": "$1 {{PLURAL:$1|bewurking|bewurkings}} weromdraaie",
+       "rollbacklinkcount-morethan": "mear as $1 {{PLURAL:$1|bewurking|bewurkings}} weromdraaie",
+       "rollbackfailed": "Weromdraaien fan wizigings net slagge.",
        "cantrollback": "Dizze feroaring kin net werom setten wurde, om't der mar ien skriuwer is.",
-       "alreadyrolled": "Kin de feroaring fan [[:$1]] troch [[User:$2|$2]] ([[User talk:$2|oerlis]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]) net werom sette;\nin oar hat de feroaring werom set, of oars wat oan de side feroare.\n\nDe lêste feroaring wie fan [[User:$3|$3]] ([[User talk:$3|oerlis]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
+       "alreadyrolled": "Kin de wiziging fan [[:$1]] troch [[User:$2|$2]] ([[User talk:$2|oerlis]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]) net weromdraaie;\nin oar hat de wiziging weromdraaid, of oars wat oan de side feroare.\n\nDe lêste wiziging wie fan [[User:$3|$3]] ([[User talk:$3|oerlis]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
        "editcomment": "De gearfetting wie: <em>$1</em>.",
        "revertpage": "Bewurkings fan [[Special:Contributions/$2|$2]] ([[User talk:$2|oerlis]]) weromset ta de lêste ferzje fan [[User:$1|$1]]",
-       "rollback-success": "Bewurkings fan {{GENDER:$3|$1}} omdraaid;\nde lêste ferzje fan {{GENDER:$4|$2}} weromset.",
+       "rollback-success": "Wizigings fan {{GENDER:$3|$1}} weromdraaid;\nde lêste ferzje fan {{GENDER:$4|$2}} weromset.",
+       "log-name-contentmodel": "Ynhâldsmodelloch",
        "protectlogpage": "Skoattelloch",
        "protectlogtext": "Hjirûnder wurdt it skoateljen en frijjaan fan siden oanjûn.\nSjoch [[Special:ProtectedPages|Skoattele side]] foar mear ynformaasje.",
        "protectedarticle": "\"[[$1]]\" skoattele",
        "mycontris": "Bydragen",
        "anoncontribs": "Bydragen",
        "contribsub2": "Foar {{GENDER:$3|$1}} ($2)",
-       "nocontribs": "Der binne gjin feroarings fûn dyt't hjirmei oerienkomme.",
+       "contributions-subtitle": "Foar {{GENDER:$3|$1}}",
+       "nocontribs": "Der binne gjin feroarings fûn dy't oan dizze kritearia foldwaan.",
        "uctop": "lêste feroaring",
        "month": "Fan moanne (en earder):",
        "year": "Fan jier (en earder):",
+       "date": "Fan datum (en earder):",
        "sp-contributions-newbies": "Allinne bydragen fan nije akkounts besjen",
-       "sp-contributions-newbies-sub": "Foar nijlingen",
+       "sp-contributions-newbies-sub": "Foar nije akkounts",
        "sp-contributions-newbies-title": "Bydragen fan nije meidoggers",
-       "sp-contributions-blocklog": "Blokkearlochboek",
-       "sp-contributions-deleted": "Wiske meidogger bydragen",
+       "sp-contributions-blocklog": "útslútloch",
+       "sp-contributions-deleted": "wiske {{GENDER:$1|meidogger}}bydragen",
+       "sp-contributions-uploads": "opladen",
+       "sp-contributions-logs": "lochs",
        "sp-contributions-talk": "oerlis",
-       "sp-contributions-userrights": "behear fan meidoggerrjochten",
+       "sp-contributions-userrights": "behear fan {{GENDER:$1|meidogger}}rjochten",
        "sp-contributions-search": "Sykje nei bydragen",
        "sp-contributions-username": "IP-adres of meidochnamme:",
+       "sp-contributions-toponly": "Allinne de lêste ferzjes werjaan",
+       "sp-contributions-newonly": "Allinne nij oanmakke siden werjaan",
+       "sp-contributions-hideminor": "Lytse feroarings ferbergje",
        "sp-contributions-submit": "Sykje",
        "whatlinkshere": "Wat is hjirmei keppele?",
        "whatlinkshere-title": "Siden dy't keppele binne mei \"$1\"",
        "whatlinkshere-page": "Side:",
-       "linkshere": "Dizze siden binne keppele oan '''$2''':",
+       "linkshere": "De neikommende siden ferwize nei <strong>$2</strong>:",
        "nolinkshere": "Der binne gjin siden oan '''$2''' keppele.",
        "nolinkshere-ns": "Gjin siden yn de keazen nammeromte keppelje nei '''$2'''.",
        "isredirect": "synonym",
        "istemplate": "opnaam",
        "isimage": "bestânskeppeling",
-       "whatlinkshere-prev": "{{PLURAL:$1|foarige|foarige $1}}",
-       "whatlinkshere-next": "{{PLURAL:$1|folgjende|folgjende $1}}",
+       "whatlinkshere-prev": "{{PLURAL:$1|foargeande|$1 foargeand}}",
+       "whatlinkshere-next": "{{PLURAL:$1|neikommende|$1 neikommend}}",
        "whatlinkshere-links": "← keppelings",
        "whatlinkshere-hideredirs": "$1 trochferwizings",
        "whatlinkshere-hidetrans": "$1 trânsklúzjes",
        "blocklist-reason": "Reden",
        "ipblocklist-submit": "Sykje",
        "infiniteblock": "trochgeand",
-       "blocklink": "slút út",
-       "unblocklink": "lit yn",
-       "change-blocklink": "blokkade feroarje",
+       "blocklink": "útslute",
+       "unblocklink": "ynlitte",
+       "change-blocklink": "útsluting feroarje",
        "contribslink": "bydragen",
        "emaillink": "e-mail stjoere:",
        "autoblocker": "Automatysk útsletten om't jo ynternet-adres okkerdeis brûkt is troch \"[[User:$1|$1]]\".\nAs reden foar de útsluting fan $1 is opjûn \"$2\"",
        "movepagetext": "Dit werneamt in side, mei alle sideskiednis.\nDe âlde titel wurdt in trochferwizing nei de nije.\nKeppelings mei de âlde side wurde net feroare;\ngean sels nei of't der dûbele of misse ferwizings binne.\nIt hinget fan jo ôf of't de siden noch keppelen binne sa't it mient wie.\n\nDe side wurdt '''net''' werneamt as der al in side mei dy namme is, útsein as it in side\nsûnder skiednis is en de side leech is of in trochferwizing is. Sa kinne jo in side\ndaalks weromneame as jo in flater meitsje, mar jo kinne in oare side net oerskriuwe.",
        "movepagetalktext": "As der in oerlisside by heart, dan bliuwt dy oan de side keppele, '''útsein''':\n*De nije sidenamme yn in oare nammeromte is,\n*Der keppele oan de nije namme al in net-lege oerlisside is, of\n*Jo dêr net foar kieze.\n\nIn dizze gefallen is it oan jo hoe't jo de oerlisside omneame of ynfoegje wolle.",
        "movenologintext": "Jo moatte [[Special:UserLogin|oanmeld]] wêze om in side wer te neamen.",
-       "newtitle": "As nij titel",
+       "newtitle": "Nije titel:",
        "move-watch": "Folch dizze side",
        "movepagebtn": "Side omneame",
        "pagemovedsub": "Werneamen slagge",
        "movepage-moved": "<strong>\"$1\" hjit no \"$2\"</strong>",
+       "movepage-moved-redirect": "In trochferwizing is oanmakke.",
        "articleexists": "Der is al in side mei dy namme, of oars is de namme dy't jo oanjûn hawwe net tastien. Besykje it op 'e nij.",
        "movetalk": "Titel fan oerlisside ek feroarje, as dy der is.",
        "movepage-page-moved": "De side $1 is werneamd nei $2.",
-       "movelogpage": "Omneamloch",
+       "movelogpage": "Side-omneamloch",
        "movelogpagetext": "Dit is in list fan feroare titels.",
        "movereason": "Reden:",
        "revertmove": "werom sette",
        "delete_and_move_text": "== Wiskjen nedich ==\nDe doelside \"[[:$1]]\" is der al.\nMoat dy wiske wurde om plak te meitsjen foar it werneamen?",
        "delete_and_move_confirm": "Ja, wiskje de side",
-       "delete_and_move_reason": "Wiske om plak te meitsjen foar in werneamde side",
+       "delete_and_move_reason": "Wiske en meitsje plak foar it werneamen fan \"[[$1]]\"",
        "export": "Eksportearje",
        "exportall": "Alle siden eksportearje",
        "export-submit": "Eksportearje",
        "import-logentry-upload-detail": "$1 {{PLURAL:$1|ferzje|ferzjes}}",
        "import-logentry-interwiki-detail": "$1 {{PLURAL:$1|ferzje|ferzjes}} fan $2",
        "tooltip-pt-userpage": "Jo {{GENDER:|meidogger}}side",
-       "tooltip-pt-mytalk": "Jo oerlisside",
+       "tooltip-pt-mytalk": "{{GENDER:|Jo}} oerlisside",
+       "tooltip-pt-anontalk": "Oerlis oer bewurkings fan dit IP-adres ôf",
        "tooltip-pt-preferences": "Myn foarkarynstellings",
-       "tooltip-pt-watchlist": "List fan siden dy'sto besjochst op feroarings",
+       "tooltip-pt-watchlist": "List fan siden dy't jo besjogge op feroarings",
        "tooltip-pt-mycontris": "Oersjocht fan jo bydragen",
+       "tooltip-pt-anoncontribs": "List fan wizigings makke fan dit IP-adres ôf",
        "tooltip-pt-login": "Jo wurde fan herten útnûge jo oan te melden, mar it hoecht net.",
        "tooltip-pt-logout": "Ofmelde",
        "tooltip-pt-createaccount": "Jo wurde fan herten útnûge in akkount oan te meitsjen en jo oan te melden, mar it hoecht net.",
-       "tooltip-ca-talk": "Oerlis oer dizze side",
+       "tooltip-ca-talk": "Oerlis oer de sideynhâld",
        "tooltip-ca-edit": "Dizze side bewurkje",
-       "tooltip-ca-addsection": "In opmerking tafoegje oan de oerlis-side.",
-       "tooltip-ca-viewsource": "Dizze side is befeilige, mar jo kinne de boarne wol besjen.",
+       "tooltip-ca-addsection": "In nij mêd tafoegje",
+       "tooltip-ca-viewsource": "Dizze side is skoattele, mar jo kinne de boarne wol besjen.",
        "tooltip-ca-history": "Eardere ferzjes fan dizze side",
        "tooltip-ca-protect": "Dizze side befeiligje",
        "tooltip-ca-delete": "Dizze side weidwaan",
        "tooltip-ca-undelete": "Fuorthelle bewurkings fan dizze side weromsette",
-       "tooltip-ca-move": "Dizze side ferskowe",
+       "tooltip-ca-move": "Dizze side omneame",
        "tooltip-ca-watch": "Dizze side oan jo folchlist taheakje",
        "tooltip-ca-unwatch": "Dizze side fan jo folchlist ôfhelje",
        "tooltip-search": "{{SITENAME}} trochsykje",
        "tooltip-search-fulltext": "De siden foar dizze tekst sykje",
        "tooltip-p-logo": "Haadside",
        "tooltip-n-mainpage": "Gean nei de haadside",
-       "tooltip-n-mainpage-description": "Nei de haadside gean",
+       "tooltip-n-mainpage-description": "Gean nei de haadside",
        "tooltip-n-portal": "Oer it projekt: wat jo dwaan kinne, wêr jo dingen fine",
        "tooltip-n-currentevents": "Eftergrûnynformaasje oer rinnende saken",
        "tooltip-n-recentchanges": "List fan de lêste feroarings oan 'e wiki",
        "tooltip-t-specialpages": "List fan alle bysûndere siden",
        "tooltip-t-print": "Ofdrukferzje fan dizze side",
        "tooltip-t-permalink": "Bliuwende keppeling nei dizze ferzje fan 'e side",
-       "tooltip-ca-nstab-main": "Ynhâldlike side sjen litte",
+       "tooltip-ca-nstab-main": "De sideynhâld sjen litte",
        "tooltip-ca-nstab-user": "Besjoch de meidoggerside",
        "tooltip-ca-nstab-special": "Dit is in bysûndere side, en kin net bewurke wurde",
        "tooltip-ca-nstab-project": "Projektside sjen litte",
        "tooltip-ca-nstab-image": "De bestânsside sjen litte",
-       "tooltip-ca-nstab-mediawiki": "Systeemberjocht sjen litte",
-       "tooltip-ca-nstab-template": "Sjabloan sjen litte",
+       "tooltip-ca-nstab-mediawiki": "It systeemberjocht sjen litte",
+       "tooltip-ca-nstab-template": "It berjocht sjen litte",
        "tooltip-ca-nstab-help": "Helpside sjen litte",
        "tooltip-ca-nstab-category": "Kategory-side sjen litte",
        "tooltip-minoredit": "Markearje dizze feroaring as fan lytse betsjutting",
        "tooltip-save": "Jo feroarings bewarje",
        "tooltip-preview": "Oerlêze foar't de side fêstlein is!",
        "tooltip-diff": "Sjen litte hokker feroarings jo yn'e tekst makke hawwe.",
-       "tooltip-compareselectedversions": "Sjoch de ferskillen tusken de twa keazen ferzjes fan dizze side.",
+       "tooltip-compareselectedversions": "Sjoch de ferskillen tusken de twa keazen ferzjes fan dizze side",
        "tooltip-watch": "Foegje dizze side ta oan jo folchlist [alt-w]",
-       "tooltip-rollback": "\"Omdraaie\" keart de bewurking(s) fan 'e lêste bydrager oan dizze side yn ien klik om",
+       "tooltip-watchlistedit-normal-submit": "Titels wiskje",
+       "tooltip-watchlistedit-raw-submit": "Folchlist bywurkje",
+       "tooltip-upload": "Opladen starte",
+       "tooltip-rollback": "\"Weromdraaie\" set dizze side yn ien klik werom nei hoe't er wie foar't de lêste bydrager syn bewurkings trochfierde",
+       "tooltip-undo": "\"Weromsette\" makket dizze wiziging ûngedien, en iepenet it bewurkingsformulier. Hjirtroch kin yn 'e gearfetting in reden tafoege wurde.",
+       "tooltip-preferences-save": "Foarkarren bewarje",
        "interlanguage-link-title": "$1 – $2",
        "interlanguage-link-title-nonlang": "$1 – $2",
        "common.js": "/* Alles wat hjir oan JavaScript delset wurdt, wurdt foar alle meidoggers laden foar eltse side! */",
        "pageinfo-authors": "Auteurs totaal",
        "pageinfo-magic-words": "{{PLURAL:$1|Magysk wurd|Magyske wurden}} ($1)",
        "pageinfo-toolboxlink": "Sidegegevens",
-       "pageinfo-redirectsto-info": "ynformaasje",
+       "pageinfo-redirectsto-info": "ynfo",
        "pageinfo-contentpage-yes": "Ja",
        "pageinfo-protect-cascading-yes": "Ja",
        "pageinfo-category-info": "Kategory-ynformaasje",
        "markedaspatrollederror": "Kin net as kontrolearre markearre wurde",
        "markedaspatrollederrortext": "Jo moatte in ferzje oanjaan dy't jo as kontrolearre markearje.",
        "markedaspatrollederror-noautopatrol": "Jo meie jo eigen bewurkings net sels markearre.",
+       "patrol-log-page": "Neisjochloch",
        "previousdiff": "← Eardere ferskillen",
        "nextdiff": "Neikommende ferskillen →",
-       "imagemaxsize": "Behein ôfmjittings fan ôfbyld op beskriuwingsside ta:",
-       "thumbsize": "Mjitte fan miniatueren:",
+       "imagemaxsize": "Beheining fan 'e ôfbyldingsgrutte op bestânsbeskriuwingssiden:",
+       "thumbsize": "Miniatuergrutte:",
        "widthheight": "$1 × $2",
        "widthheightpage": "$1 × $2, $3 {{PLURAL:$3|side|siden}}",
        "file-info": "bestânsgrutte: $1, MIME-type: $2",
        "show-big-image": "Oarspronklik bestân",
        "show-big-image-other": "Oare {{PLURAL:$2|resolúsje|resolúsjes}}: $1.",
        "show-big-image-size": "$1 × $2 pixels",
-       "newimages": "Nije ôfbylden",
+       "newimages": "Galery mei nije ôfbylden",
        "imagelisttext": "Dit is in list fan '''$1''' {{PLURAL:$1|bestân|bestannen}}, op $2.",
+       "newimages-summary": "Dizze bysûndere side lit de lêst opladen bestannen sjen.",
        "newimages-legend": "Filter",
        "noimages": "Neat te sjen.",
        "ilsubmit": "Sykje",
        "bydate": "datum",
+       "sp-newimages-showfrom": "Nije bestannen besjen fan $2, $1 ôf",
        "video-dims": "$1, $2 × $3",
        "seconds-abbrev": "$1 s",
        "minutes-abbrev": "$1 min",
        "metadata-langitem-default": "$1",
        "namespacesall": "alle",
        "monthsall": "alle",
-       "confirmemail": "Befêstigjen netpostadres",
+       "confirmemail": "E-mailadres befêstigje",
        "confirmemail_text": "{{SITENAME}} freget dat jo jo netpostadres befêstigje eart jo hjir netpost brûke. Brûk de knop hjirûnder om josels in befêstigingskoade ta te stjoeren op it adres dat jo opjûn hawwe. Iepenje de koade dan yn jo blêder om te befêstigjen dat jo netpostadres jildich is.",
        "confirmemail_send": "Stjoer in befêstigingskoade",
        "confirmemail_sent": "Befêstiginskoade tastjoerd.",
        "confirmemail_invalid": "Dizze befêstiginskoade jildt net (mear).\nFaaks is de koade ferrûn.",
        "confirmemail_needlogin": "Jo moatte $1 om jo e-mailadres befêstigje te kinnen.",
        "confirmemail_success": "Jo netpostadres is befêstige. Jo kinne jo no oanmelde en de wiki brûke.",
-       "confirmemail_loggedin": "Jo netpostadres is no befêstige.",
-       "confirmemail_subject": "Netpost-befêstigingskoade foar {{SITENAME}}",
+       "confirmemail_loggedin": "Jo e-mailadres is no befêstige.",
+       "confirmemail_subject": "Befêstiging e-mailadres foar {{SITENAME}}",
        "confirmemail_body": "Immen, nei gedachten jo, hat him by {{SITENAME}} oanmelde as \"$2\", mei dit netpostadres ($1).\n\nHjirtroch komme ek de netpostfunksjes fan {{SITENAME}} foar jo beskikber. Iepenje de neikommende keppeling om te befêstigjen dat jo wier josels by {{SITENAME}} mei dit netpostadres oanmelde hawwe:\n\n$3\n\nAt jo dat *net* wienen, brûk dy keppeling dan net, en klik hjir:\n\n$5\n\nDizze befêstigingskoade ferrint dan op $4.",
        "scarytranscludetoolong": "[URL-adres is te lang]",
        "confirmrecreate": "Sûnt jo begûn binne dizze side te bewurkjen, hat meidogger [[User:$1|$1]] ([[User talk:$1|oerlis]]) de side wiske. De reden dy't derfoar jûn waard wie:\n: ''$2''\nWolle jo de side wier op 'e nij skriuwe?",
        "confirm-watch-button": "OK",
        "confirm-unwatch-button": "OK",
        "confirm-unwatch-top": "Dizze side fan myn folchlist ôfhelje",
+       "confirm-rollback-bottom": "Dizze hanneling sil de oanjûne sidewizigings fuortdaliks weromdraaie.",
        "semicolon-separator": ";&#32;",
        "comma-separator": ",&#32;",
        "colon-separator": ":&#32;",
        "autosumm-blank": "Alle ynhâld fan de side weismiten",
        "autosumm-replace": "Side ferfong mei '$1'",
        "autoredircomment": "Ferwiist troch nei [[$1]]",
-       "autosumm-new": "Nije Side: $1",
+       "autosumm-removed-redirect": "Trochferwizing nei [[$1]] wiske",
+       "autosumm-changed-redirect-target": "Trochferwizingsdoel feroare fan [[$1]] nei [[$2]]",
+       "autosumm-new": "Side makke mei \"$1\"",
        "size-bytes": "$1 B",
        "size-kilobytes": "$1 KB",
        "size-megabytes": "$1 MB",
        "bitrate-zetabits": "$1 Zbps",
        "bitrate-yottabits": "$1 Ybps",
        "watchlistedit-normal-title": "Folchlist bewurkje",
-       "watchlistedit-normal-submit": "Siden wiskje",
-       "watchlistedit-raw-titles": "Siden:",
-       "watchlistedit-raw-submit": "Folchlist bewurkje",
+       "watchlistedit-normal-legend": "Titels fan de folchlist ôfhelje",
+       "watchlistedit-normal-explain": "De titels op jo folchlist wurde hjirûnder werjûn.\nFink oan en klik op \"{{int:Watchlistedit-normal-submit}}\", om der in titel ôf te heljen.\nJo kinne ek [[Special:EditWatchlist/raw|de rûge list bewurkje]].",
+       "watchlistedit-normal-submit": "Titels wiskje",
+       "watchlistedit-normal-done": "Der {{PLURAL:$1|is ien inkelde titel|binne $1 titels}} fan jo folchlist ôfhelle:",
+       "watchlistedit-raw-title": "Rûge folchlist bewurkje",
+       "watchlistedit-raw-legend": "De rûge folchlist bewurkje",
+       "watchlistedit-raw-explain": "De titels op jo folchlist wurde hjirûnder werjûn, en kinne bewurke wurde troch it taheakjen oan en ôfheljen fan de list;\nien titel op in rigel.\nKlik op \"{{int:Watchlistedit-raw-submit}}\" at jo klear binne.\nJo kinne ek [[Special:EditWatchlist|de standertbewurker brûke]].",
+       "watchlistedit-raw-titles": "Titels:",
+       "watchlistedit-raw-submit": "Folchlist bywurkje",
+       "watchlistedit-raw-done": "Jo folchlist is bywurke.",
        "watchlistedit-raw-added": "{{PLURAL:$1|1 side is|$1 siden binne}} tafoege:",
-       "watchlistedit-raw-removed": "{{PLURAL:$1|1 side|$1 siden}} wiske:",
+       "watchlistedit-raw-removed": "Der {{PLURAL:$1|is 1 titel|binne $1 titels}} ôfhelle:",
+       "watchlistedit-clear-title": "Folchlist wiskje",
+       "watchlistedit-clear-legend": "De folchlist wiskje",
+       "watchlistedit-clear-explain": "Alle titels sille fan jo folchlist ôfhelle wurde",
        "watchlistedit-clear-titles": "Titels:",
-       "watchlisttools-view": "Folchlist besjen",
+       "watchlistedit-clear-submit": "Folchlist wiskje (Dit is definityf!)",
+       "watchlistedit-clear-done": "Jo folchlist is wiske.",
+       "watchlistedit-clear-removed": "Der {{PLURAL:$1|is 1 titel|binne $1 titels}} ôfhelle:",
+       "watchlisttools-clear": "Folchlist wiskje",
+       "watchlisttools-view": "Relevante wizigings besjen",
        "watchlisttools-edit": "Folchlist besjen en bewurkje",
        "watchlisttools-raw": "Rûge folchlist bewurkje",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|oerlis]])",
        "specialpages-group-spam": "Spamhelpmiddels",
        "blankpage": "Side is leech",
        "intentionallyblankpage": "Dizze side is bewust leech lizzen en wurdt brûkt foar benchmarks, ensfh.",
+       "tag-filter": "[[Special:Tags|Lebelfilter]]:",
        "tag-list-wrapper": "[[Special:Tags|{{PLURAL:$1|Lebel|Lebels}}]]: $2",
+       "tag-mw-contentmodelchange": "ynhâldsmodel wizige",
+       "tag-mw-contentmodelchange-description": "Bewurkings dy't it [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:ChangeContentModel ynhâldsmodel fan 'e side wizigje]",
+       "tag-mw-new-redirect": "Nije trochferwizing",
+       "tag-mw-new-redirect-description": "Bewurkings dy't in nije trochferwizing meitsje, as in side yn in trochferwizing feroarje",
+       "tag-mw-removed-redirect": "Trochferwizing wiske",
+       "tag-mw-removed-redirect-description": "Bewurkings dy't in besteande trochferwizing yn gjin trochferwizing feroarje",
+       "tag-mw-changed-redirect-target": "Trochferwizingsdoel feroare",
+       "tag-mw-changed-redirect-target-description": "Bewurkings dy't it einpunt fan in trochferwizing feroarje",
+       "tag-mw-blank": "Leechmeitsjen",
+       "tag-mw-blank-description": "Bewurkings dy't siden leechmeitsje",
+       "tag-mw-replace": "Ferfongen",
+       "tag-mw-replace-description": "Bewurkings dy't mear as 90% fan 'e sideynhâld wiskje",
+       "tag-mw-rollback": "Weromdraaid",
+       "tag-mw-rollback-description": "Bewurkings mei de keppeling 'weromdraaie', dy't foargeande wizigings weromdraaid hawwe",
+       "tag-mw-undo": "Weromset",
+       "tag-mw-undo-description": "Bewurkings mei de keppeling 'weromsette', dy't foargeande wizigings weromset hawwe",
+       "tags-title": "Lebels",
+       "tags-intro": "Op dizze side steane de lebels en har betsjutting, wêrmei't de programmatuer bewurkings markearje kin.",
+       "tags-tag": "Lebelnamme",
+       "tags-display-header": "Werjefte yn feroaringslisten",
+       "tags-description-header": "Folsleine beskriuwing fan 'e betsjutting",
        "tags-source-header": "Boarne",
        "tags-active-header": "Aktyf?",
+       "tags-hitcount-header": "Lebele bewurkings",
        "tags-actions-header": "Aksjes",
        "tags-active-yes": "Ja",
        "tags-active-no": "Nee",
+       "tags-source-extension": "Definiearre yn de programmatuer",
+       "tags-source-manual": "Hânmjittich taheakke troch meidoggers en bots",
+       "tags-source-none": "Net mear yn gebrûk",
        "tags-edit": "bewurkje",
        "tags-delete": "fuortsmite",
        "tags-activate": "aktivearje",
        "tags-deactivate": "deaktivearje",
        "tags-hitcount": "$1 {{PLURAL:$1|bewurking|bewurkings}}",
+       "tags-create-tag-name": "Lebelnamme:",
        "tags-create-reason": "Reden:",
        "tags-delete-reason": "Reden:",
        "tags-activate-reason": "Reden:",
        "htmlform-yes": "Ja",
        "htmlform-cloner-create": "Mear tafoegje",
        "htmlform-cloner-delete": "Fuortsmite",
+       "htmlform-date-placeholder": "JJJJ-MM-DD",
+       "logentry-delete-delete": "$1 {{GENDER:$2|hat}} de side $3 wiske",
+       "logentry-delete-delete_redir": "$1 {{GENDER:$2|hat}} de trochferwizing $3 by it oerskriuwen wiske",
        "revdelete-restricted": "hat beheinings oplein oan behearders",
        "revdelete-unrestricted": "hat beheinings foar behearders goedmakke",
+       "logentry-move-move": "$1 {{GENDER:$2|hat}} de side $3 omneamd ta $4",
+       "logentry-move-move-noredirect": "$1 {{GENDER:$2|hat}} de side $3 omneamd ta $4 sûnder in trochferwizing efter te litten",
+       "logentry-move-move_redir": "$1 {{GENDER:$2|hat}} de side $3 omneamd ta $4 fan de trochferwizing",
+       "logentry-move-move_redir-noredirect": "$1 {{GENDER:$2|hat}} de side $3 omneamd ta $4 fan de trochferwizing, sûnder in trochferwizing efter te litten",
        "logentry-newusers-create": "It meidochakkount $1 is {{GENDER:$2|oanmakke}}",
        "logentry-newusers-autocreate": "It meidochakkount $1 is automatysk {{GENDER:$2|oanmakke}}",
        "logentry-upload-upload": "$1 hat $3 {{GENDER:$2|opladen}}",
        "logentry-upload-overwrite": "$1 hat in nije ferzje fan $3 {{GENDER:$2|opladen}}",
+       "log-name-tag": "Lebelloch",
        "rightsnone": "(gjin)",
        "feedback-back": "Foarige",
        "feedback-cancel": "Annulearje",
        "special-characters-group-bangla": "Bengaalsk",
        "special-characters-group-tamil": "Tamyl",
        "special-characters-group-telugu": "Telugu",
-       "special-characters-group-thai": "Tai"
+       "special-characters-group-thai": "Tai",
+       "mw-widgets-dateinput-no-date": "Gjin datum keazen",
+       "mw-widgets-dateinput-placeholder-day": "JJJJ-MM-DD",
+       "mw-widgets-usersmultiselect-placeholder": "Mear tafoegje...",
+       "mw-widgets-titlesmultiselect-placeholder": "Mear tafoegje...",
+       "date-range-from": "Fan datum:",
+       "date-range-to": "Oant datum:"
 }
index c0c3832..548af56 100644 (file)
@@ -22,7 +22,8 @@
                        "Macofe",
                        "Tem",
                        "Nmacu",
-                       "ديفيد"
+                       "ديفيد",
+                       "Xqt"
                ]
        },
        "tog-underline": "Folínte faoi naisc:",
        "rcfilters-filter-editsbyself-description": "Do chuid iarrachtaí féin",
        "rcfilters-filter-editsbyother-label": "Athruithe déanta ag daoine eile",
        "rcfilters-filter-editsbyother-description": "Gach athrú seachas do chinn féin.",
-       "rcfilters-filtergroup-userExpLevel": "Clárú úsáideoirí agus taithí",
+       "rcfilters-filtergroup-user-experience-level": "Clárú úsáideoirí agus taithí",
        "rcfilters-filter-user-experience-level-registered-label": "Cláraithe",
        "rcfilters-filter-user-experience-level-registered-description": "Eagarthóirí atá logáilte isteach.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Neamhchláraithe",
        "rcfilters-filter-categorization-label": "Athruithe ar chatagóirí",
        "rcfilters-filter-categorization-description": "Taifid de leathanaigh a cuireadh le nó a baineadh ó chatagóirí.",
        "rcfilters-filter-logactions-label": "Gníomhartha logáilte",
-       "rcfilters-filtergroup-lastRevision": "Leaganacha reatha",
+       "rcfilters-filtergroup-lastrevision": "Leaganacha reatha",
        "rcfilters-filter-lastrevision-description": "Díreach an t-athrú is déanaí den leathanach.",
        "rcfilters-filter-previousrevision-label": "Ní an leagan reatha é seo",
        "rcfilters-filter-previousrevision-description": "Gach athrú nach an \"leagan reatha\" é",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[{{PLURAL:$1|úsáideoir amháin|$1 úsáideoirí}} ag faire]",
        "rc-change-size-new": "$1 {{PLURAL:$1|bheart|beart}} tar éis an athraithe",
        "newsectionsummary": "/* $1 */ mír nua",
        "rc-enhanced-expand": "Taispeáin mionsonraithe",
        "allmessagesdefault": "Téacs réamhshocraithe",
        "allmessagescurrent": "Téacs reatha",
        "allmessagestext": "Is liosta é seo de theachtaireachtaí córais atá le fáil san ainmspás MediaWiki.\nTabhair cuairt ar [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] agus [https://translatewiki.net translatewiki.net] le do thoil más mian leat cur leis an logánú ginearálta MediaWiki.",
-       "allmessagesnotsupportedDB": "Ní féidir an leathanach seo a úsáid dá bharr gur díchumasaíodh '''$wgUseDatabaseMessages'''.",
+       "allmessages-not-supported-database": "Ní féidir an leathanach seo a úsáid dá bharr gur díchumasaíodh '''$wgUseDatabaseMessages'''.",
        "allmessages-filter-all": "Uile",
        "allmessages-language": "Teanga:",
        "allmessages-filter-submit": "Gabh",
        "ilsubmit": "Cuardaigh",
        "bydate": "de réir dáta",
        "sp-newimages-showfrom": "Taispeáin íomhánna nua as $2, $1",
-       "days": "{{PLURAL:$1|$1 lá}}",
+       "days": "$1 lá",
        "bad_image_list": "Is é seo a leanas an formáid:\n\nNíl ach míreanna liosta amháin (línte ag tosú le *) san áireamh.\nIs riachtanach gur nasc do dhrochchomhad é an chéad nasc ar líne.\nIs eisceachtaí iad na naisc eile ar an líne céanna, .i. leathanaigh gur féidir an comhad a bheith orthu go hinlíne.",
        "metadata": "Meiteasonraí",
        "metadata-help": "Tá breis eolais sa comhad seo, curtha, is dócha, as ceamara digiteach ná scanóir a chruthaigh ná a digitigh é.\nMá tá an comhad mionathraithe as an bunleagan, b'fhéidir nach mbeidh ceann de na sonraí fágtha sa comhad atá athruithe.",
index 1461d7a..3a0ac70 100644 (file)
        "minoreditletter": "细",
        "newpageletter": "新",
        "boteditletter": "机",
-       "number_of_watching_users_pageview": "[$1只监视用户]",
        "newsectionsummary": "/* $1 */ 新段落",
        "rc-enhanced-expand": "显到细节(需要 JavaScript)",
        "rc-enhanced-hide": "弆到细节",
        "allmessagesdefault": "默认文字",
        "allmessagescurrent": "眼前𠮶文字",
        "allmessagestext": "个首列到全部制定得正𠮶系统界面。\nPlease visit [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] and [https://translatewiki.net translatewiki.net] if you wish to contribute to the generic MediaWiki localisation.",
-       "allmessagesnotsupportedDB": "'''{{ns:special}}:系统界面功能'''关卟嘞('''$wgUseDatabaseMessages''')。",
+       "allmessages-not-supported-database": "'''{{ns:special}}:系统界面功能'''关卟嘞('''$wgUseDatabaseMessages''')。",
        "thumbnail-more": "放大",
        "filemissing": "寻伓到档案",
        "thumbnail_error": "缩略图冇扤正: $1",
index 267f4e0..3cd8559 100644 (file)
        "minoreditletter": "細",
        "newpageletter": "新",
        "boteditletter": "機",
-       "number_of_watching_users_pageview": "[$1隻監視用戶]",
        "newsectionsummary": "/* $1 */ 新段落",
        "rc-enhanced-expand": "顯到細節(需要 JavaScript)",
        "rc-enhanced-hide": "弆到細節",
        "allmessagesdefault": "默認文字",
        "allmessagescurrent": "眼前嗰文字",
        "allmessagestext": "箇首列到全部制定得正嗰系統界面。\nPlease visit [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] and [https://translatewiki.net translatewiki.net] if you wish to contribute to the generic MediaWiki localisation.",
-       "allmessagesnotsupportedDB": "'''{{ns:special}}:系統界面功能'''關卟嘞('''$wgUseDatabaseMessages''')。",
+       "allmessages-not-supported-database": "'''{{ns:special}}:系統界面功能'''關卟嘞('''$wgUseDatabaseMessages''')。",
        "thumbnail-more": "放大",
        "filemissing": "尋伓到檔案",
        "thumbnail_error": "縮略圖冇扤正: $1",
index c033735..6fd1e82 100644 (file)
        "view": "Lir",
        "view-foreign": "Wè asou $1",
        "edit": "Modifyé",
-       "edit-local": "Modifyé dèskripsyon lokal",
+       "edit-local": "Modifyé dèskripsyon lokal-a",
        "create": "Kréyé",
        "create-local": "Ajouté roun dèskripsyon lokal",
        "delete": "Siprimen",
        "newmessageslinkplural": "{{PLURAL:$1|oun nouvèl mésaj|dé nouvèl mésaj}}",
        "newmessagesdifflinkplural": "{{PLURAL:$1|dannyé modifikasyon}}",
        "youhavenewmessagesmulti": "Zòt gen dé nouvèl mésaj asou $1.",
-       "editsection": "Modifyé",
+       "editsection": "modifyé",
        "editold": "modifyé",
        "viewsourceold": "wè sours-a",
        "editlink": "modifyé",
        "yourpasswordagain": "Konfirmen modipas-a :",
        "createacct-yourpasswordagain": "Konfirmen modipas-a",
        "createacct-yourpasswordagain-ph": "Rantré òkò menm modipas-a",
-       "userlogin-remembermypassword": "Gardé mo sésyon aktiv",
+       "userlogin-remembermypassword": "Gadé mo sésyon agtiv",
        "userlogin-signwithsecure": "Itilizé roun konnègsyon sékirizé",
        "cannotlogin-title": "Enposib di konnègté so kò",
        "cannotlogin-text": "Konnègsyon-an pa posib",
        "cannotcreateaccount-title": "Kréyasyon di kont enposib",
        "cannotcreateaccount-text": "Kréyasyon-an dirèk di kont itilizatò pa fika agtivé asou sa wiki.",
        "yourdomainname": "Zòt domenn :",
-       "password-change-forbidden": "Zòt pa pouvé modifyé mo di pas asou sa wiki.",
+       "password-change-forbidden": "Zòt pa pouvé chanjé modipas-ya asou sa wiki.",
        "externaldberror": "Swé roun lérò prodjwi so kò asou baz-a di data d'otantifikasyon, swé zòt pa otorizé à mété à jou zòt kont ègstèrn.",
        "login": "Konnègsyon",
        "login-security": "Vérifyé zòt idantité",
        "createacct-benefit-body1": "modifikasyon{{PLURAL:$1|}}",
        "createacct-benefit-body2": "paj{{PLURAL:$1|}}",
        "createacct-benefit-body3": "{{PLURAL:$1|kontribitò résan}}",
-       "badretype": "Mo di pas ki zòt sézi pa ka korèsponn.",
+       "badretype": "Modipas-ya ki zòt sézi pa ka korèsponn.",
        "usernameinprogress": "Oun kréyasyon di kont pou sa non d'itilizatò ja an kour.\nSouplé, pasyanté.",
        "userexists": "Non d'itilizatò sézi ja itilizé.\nSouplé, chwézi roun non diféran.",
        "loginerror": "Lérò di konnègsyon",
        "nosuchusershort": "I pa gen kontribitò ké non-an « $1 ».\nSouplé, vérifyé lòrtograf.",
        "nouserspecified": "Zòt divèt sézi roun non d'itilizatò.",
        "login-userblocked": "{{GENDER:$1|Sa itilizatò}} bloké. Konnègsyon-an pa otorizé.",
-       "wrongpassword": "Non d'itilizatò oben mo di pas enkorèk.\nSouplé, éséyé òkò.",
+       "wrongpassword": "Non-an di itilizatò oben modipas enkorèk.\nSouplé, éséyé òkò.",
        "wrongpasswordempty": "Zòt pa rantré pyès modipas.\nSouplé, éséyé òkò.",
        "passwordtooshort": "Zòt mo di pas divèt kontni omwen $1 karaktèr{{PLURAL:$1|}}.",
-       "passwordtoolong": "Mo di pas pa pouvé dépasé $1 karaktèr{{PLURAL:$1|}}.",
-       "passwordtoopopular": "Mo di pas ki tròp kouran pa pouvé fika itilizé. Souplé, chwézi roun mo di pas pli difisil à douviné.",
+       "passwordtoolong": "Modipas-ya pa pouvé dépasé $1 karagtèr{{PLURAL:$1|}}.",
+       "passwordtoopopular": "Modipas ki tròp kouran pa pouvé fika itilizé. Souplé, chwézi roun modipas ki pi difisil pou sonjé.",
        "password-name-match": "Zòt mo di pas divèt fika diféran di zòt non d'itilizatò.",
        "password-login-forbidden": "Litilizasyon-an di sa non d'itilizatò oben di sa modipas sa entèrdi.",
        "mailmypassword": "Réynisyalizé modipas-a",
        "passwordremindertitle": "Nouvèl modipas tanporèr pou {{SITENAME}}",
-       "passwordremindertext": "Tchèk moun (dipi adrès IP-a $1) doumandé roun modipas nòv pou {{SITENAME}} ($4). Oun modipas tanporèr pou itilizatò-a\n« $2 » té kréyé é sa « $3 ». Si sala té zòt entansyon,\nzòt divèt konnègté zòt kò é chwézi roun modipas nòv.\nZòt modipas tanporèr ké èspiré annan $5 jou{{PLURAL:}}.\n\nSi zòt pa lotò di sa doumann, oben si zòt ka souvni zòt kò atchwèlman di zòt modipas é zòt pli ka swété an chanjé, zòt pouvé ignoré sa mésaj é kontinwé di itilizé zòt ansyen modipas.",
+       "passwordremindertext": "Tchèk moun (dipi adrès IP-a $1) doumandé roun modipas nòv pou {{SITENAME}} ($4). Oun modipas tanporèr pou itilizatò-a\n« $2 » té kréyé é sa « $3 ». Si sa té zòt lentansyon,\nzòt divèt konnègté zòt kò é chwézi roun modipas nòv.\nZòt modipas tanporèr ké èspiré annan $5 jou{{PLURAL:}}.\n\nSi zòt pa lotò di sa doumann, oben si zòt routrouvé zòt modipas é zòt pli ka swété chanjé li, zòt pouvé ignoré sa mésaj é kontinwé di itilizé zòt ansyen modipas.",
        "noemail": "Pyès adrès di kourilèt fika anréjistré pou itilizatò-a « $1 ».",
        "noemailcreate": "Zòt divèt fourni roun adrès di kourilèt valid",
        "passwordsent": "Roun nouvèl modipas fika voyé bò'd adrès-a di kourilèt di itilizatò « $1 ».\nSouplé, roukonnègté zòt kò apré ki zòt rousouvri li.",
        "user-mail-no-addy": "Enposib di voyé roun kourilèt san adrès di kourilèt.",
        "user-mail-no-body": "Lésè di voyé di roun kourilèt ké roun kò vid oben anòrmalman kourt.",
        "changepassword": "Chanjé di modipas",
-       "resetpass_announce": "Pou tèrminé zòt enskripsyon, zòt divèt fourni roun mo di pas nòv.",
+       "resetpass_announce": "Pou tèrminen zòt lenskripsyon, zòt divèt fourni roun modipas nòv.",
        "resetpass_text": "<!-- Ajouté tègs-a isi -->",
        "resetpass_header": "Chanjé modipas-a di kont",
        "oldpassword": "Ansyen modipas :",
        "newpassword": "Nouvèl modipas :",
        "retypenew": "Konfirmen modipas nòv-a :",
        "resetpass_submit": "Chanjé modipas-a é konnègté so kò.",
-       "changepassword-success": "Zòt modipas modifyé !",
+       "changepassword-success": "Zòt modipas chanjé !",
        "changepassword-throttled": "Zòt fè tròp di tantativ di konnègsyon résaman. \nSouplé, antann $1 anvan di réyéséyé.",
        "botpasswords": "Modipas di robo",
        "botpasswords-summary": "<em>Modipas-ya di robo</em> ka pèrmèt di agsédé à roun kont itilizatò vya API-a san itilizé idantifyan-yan di konnègsyon prensipal. Drwè itilizatò-ya ki disponnib lò to konnègté ké roun modipas robo pouvé fika rédjwi.\n\nSi zòt pa ka wè poukisa zòt ké lé fè sa, a ki zòt pa benzwen di fè sa. Pésonn divèt janmen doumandé zòt di an jénéré roun é di bay li.",
        "botpasswords-disabled": "Modipas-ya di robo dézagtivé.",
        "botpasswords-no-central-id": "Pou itilizé modipas-ya di robo, zòt divèt fika konnègté à roun kont ki santralizé.",
        "botpasswords-existing": "Modipas di robo ki ka ègzisté",
-       "botpasswords-createnew": "Kréyé roun mo di pas nòv di robo",
+       "botpasswords-createnew": "Kréyé roun nouvèl modipas di robo",
        "botpasswords-editexisting": "Modifyé roun modipas di robo ki ka ègzisté",
        "botpasswords-label-needsreset": "(Modipas-a divèt fika réynisyalizé)",
        "botpasswords-label-appid": "Non di robo :",
        "botpasswords-newpassword": "Nouvèl modipas-a pou konnègté so kò à<strong>$1</strong> sa <strong>$2</strong>. <em>Souplé, anréjistré li pou fè référans asou li iltèryòrman.</em><br> (Pou ansyen robo-ya ki ka nésésité ki non-an ki fourni pou konnègsyon-an ka fika menm-an ki non-an di itilizatò évantchwèl, zòt pouvé osi itilizé <strong>$3</strong> kou non di itilizatò é <strong>$4</strong> kou modipas).",
        "botpasswords-no-provider": "BotPasswordsSessionProvider pa disponnib.",
        "botpasswords-restriction-failed": "Rèstrigsyon-yan di modipas di robo ka anpéché sa konnègsyon.",
-       "botpasswords-invalid-name": "Non-an d'itilizatò spésifyé pa ka kontni di séparatò di mo di pas di robo (« $1 »).",
+       "botpasswords-invalid-name": "Non-an d'itilizatò ki èspésifyé pa ka kontni di séparatò di modipas di robo (« $1 »).",
        "botpasswords-not-exist": "{{GENDER:$1|Itilizatò|Itilizatris}}-a « $1 » pa gen di mo di pas di robo nonmen « $2 ».",
        "botpasswords-needs-reset": "Modipas-a di robo di non « $2 » di itilizatò-a « $1 » divèt fika réynisyalizé.",
        "resetpass_forbidden": "Modipas-ya pa pouvé fika chanjé.",
-       "resetpass_forbidden-reason": "Mo di pas pa pouvé fika modifyé : $1",
+       "resetpass_forbidden-reason": "Modipas-ya pa pouvé fika chanjé : $1",
        "resetpass-no-info": "Zòt divèt fika konnègté pou agsédé dirèkman à sa paj.",
        "resetpass-submit-loggedin": "Chanjé di modipas",
        "resetpass-submit-cancel": "Annilé",
        "resetpass-expired-soft": "Zòt modipas èspiré, é divèt fika modifyé. Souplé, chwézi roun nouvèl atchwèlman oben kliké asou « {{int:authprovider-resetpass-skip-label}} » pou fè li plita.",
        "resetpass-validity-soft": "Zòt modipas pa valid : $1\n\nSouplé, chwézi roun nouvèl modipas atchwèlman, oben kliké asou « {{int:authprovider-resetpass-skip-label}} » pou modifyé li plita.",
        "passwordreset": "Réynisyalizasyon di modipas",
-       "passwordreset-text-one": "Ranplisé sa fòrmilèr pou zòt mo di pas.",
+       "passwordreset-text-one": "Ranpli sa fòrmilèr pou réynisyalizé zòt modipas.",
        "passwordreset-emaildisabled": "Fongsyonnalité-ya di kourilèt fika dézagtivé asou sa wiki.",
        "passwordreset-username": "Non di itilizatò :",
        "passwordreset-domain": "Domenn :",
        "showpreview": "Prévizwèlizé",
        "showdiff": "Wè modifikasyon-yan",
        "anoneditwarning": "<strong>Panga :</strong> zòt pa konnègté. Zòt adrès IP ké vizib pa tout moun si zòt ka fè dé modifikasyon. Si zòt <strong>[$1 ka konnègté zòt kò]</strong> oben <strong>[$2 kréyé roun kont]</strong>, zòt modifikasyon ké fika atribiyé à zòt pròp non di itilizatò é zòt ké gen ròt avantaj.",
+       "blockedtitle": "Itilizatò-a bloké.",
        "blockedtext": "<strong>Zòt kont itilizatò oben zòt adrès IP fika bloké.</strong>\n\nBlokaj té éfègtchwé pa $1.\nRézon-an ki évoké ka swiv : <em>$2</em>.\n\n* Koumansman di blokaj : $8\n* Lèspirasyon di blokaj : $6\n* Kont bloké : $7.\n\nZòt pouvé kontagté $1 oben rounòt [[{{MediaWiki:Grouppage-sysop}}|administratò]] pou diskité apropo di sa.\nZòt pouvé itilizé fongsyon-an « {{int:emailuser}} » rounso si roun adrès di kourilèt valid sa èspésifyé annan zòt [[Special:Preferences|préférans]] é rounso si sa fongsyonnalité pa fika bloké ba zòt.\nZòt adrès IP atchwèl sa $3 é zòt idantifyan di blokaj sa $5.\nSouplé, enkli tout détay-ya lasou'l annan chak rékèt ki zòt ké fè.",
+       "blockednoreason": "pyès rézon bay",
        "loginreqlink": "konnègté so kò",
+       "accmailtitle": "Modipas voyé.",
+       "newarticle": "(Nòv)",
        "newarticletext": "Zòt swiv roun lyannaj bò'd roun paj ki pa ka ègzisté òkò. \nAfen di kréyé sa paj, rantré zòt tègs annan bwèt-a ki apré (zòt pouvé konsilté [$1 paj di lèd-a] pou plis di lenfòrmasyon).\nSi zòt vini{{GENDER:|}} isi pa lérò, kliké asou bouton-an <strong>Viré</strong> di zòt navigatò.",
        "anontalkpagetext": "----\n<em>Zòt asou paj-q di diskisyon di roun itilizatò annonnim ki pa òkò kréyé di kont oben ki pa ka itilizé roun</em>.\nPou sa rézon, nou divèt itilizé so adrès IP pou idantifyé li.\nOun adrès konran IP pouvé fika patajé pa plizyò itilizatò.\nSi zòt sa roun itiliza{{GENDER:|ò}} annonnim é si zòt ka kontasté ki dé koumantèr ki pa ka konsèrnen zòt, fika adrésé ba zòt, zòt pouvé [[Special:CreateAccount|kréyé roun kont]] oben [[Special:UserLogin|konnègté zòt kò]] pou évité tout konfizyon fitir ké ròt kontribitò annonnim.",
        "noarticletext": "I pa gen atchwèlman pyès tègs asou sa paj.\nZòt pouvé [[Special:Search/{{PAGENAME}}|lansé oun sasé asou sa tit]] annan ròt paj-ya,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} sasé annan lopérasyon-yan ki lyannen]\noben [{{fullurl:{{FULLPAGENAME}}|action=edit}} kréyé sa paj]</span>.",
        "noarticletext-nopermission": "I pa gen atchwèlman pyès tègs asou sa paj.\nZòt pouvé [[Special:Search/{{PAGENAME}}|fè roun sasé asou sa tit]] annan ròt paj-ya,\noben <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|paj={{FULLPAGENAMEE}}}} sasé annan journal-ya ki asosyé]</span>, mé zòt pa gen pèrmisyon-an di kréyé sa paj.",
        "userpage-userdoesnotexist-view": "Kont itilizatò-a « $1 » pa anréjistré.",
        "clearyourcache": "<strong>Nòt :</strong> apré zòt anréjistré zòt modifikasyon, zòt divèt fòrsé roucharjman konplè di kach di zòt navigatò pou wè chanjman-yan.\n* <strong>Firefox / Safari :</strong> mentni touch-a <em>Maj</em> (<em>Shift</em>) an klikan asou bouton-an <em>Atchwalizé</em> oben présé <em>Ctrl-F5</em> oben <em>Ctrl-R</em> (<em>⌘-R</em> asou roun Mac) \n* <strong>Google Chrome :</strong> apiyé asou <em>Ctrl-Maj-R</em> (<em>⌘-Shift-R</em> asou roun Mac) \n* <strong>Internet Explorer :</strong> mentni touch-a <em>Ctrl</em> an klikan asou bouton-an <em>Atchwalizé</em> oben présé <em>Ctrl-F5</em> \n* <strong>Opera :</strong> alé annan <em>Menu → Settings</em> (<em>Opera → Préférences</em> asou roun Mac) é answit à <em>Konfidansyalité & sékrité → Éfasé data di lésplorasyon-yan → Zimaj ké fiché an kach</em>.",
+       "updated": "(Mizajou)",
+       "note": "<strong>Nòt :</strong>",
        "previewnote": "<strong>Pa bliyé ki a jis roun prévizwèlizasyon.</strong>\nZòt modifikasyon pa òkò fika anréjistré !",
        "continue-editing": "Alé kot zonn di modifikasyon",
        "editing": "Modifikasyon di $1",
        "recentchanges-label-minor": "Sa modifikasyon sa minò.",
        "recentchanges-label-bot": "Sa modifikasyon té fika éfègtchwé pa roun robo.",
        "recentchanges-label-unpatrolled": "Sa modifikasyon pa té òkò réli.",
-       "recentchanges-label-plusminus": "Tay di paj-a chanjé di sa nonm d'oktè.",
+       "recentchanges-label-plusminus": "Tay-a di paj-a chanjé di sa nonm di ògtè.",
        "recentchanges-legend-heading": "<strong>Léjann :</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (wè osi [[Special:NewPages|lis dé nouvèl paj]]).",
        "rcnotefrom": "Anba {{PLURAL:$5|modifikasyon-an ki éfègtchwé|modifikasyon-yan ki éfègtchwé}} dipi <strong>$3, $4</strong> (afiché jouk <strong>$1</strong>).",
        "pageinfo-magic-words": "{{PLURAL:$1|Mo majik}} ($1)",
        "pageinfo-hidden-categories": "{{PLURAL:$1|Katégori kaché|}} ($1)",
        "pageinfo-templates": "{{PLURAL:$1|Modèl enkli}} ($1)",
-       "pageinfo-toolboxlink": "Lenfòrmasyon asou paj-a",
+       "pageinfo-toolboxlink": "Lenfòrmasyon asou paj",
        "pageinfo-contentpage": "Konté kou paj di kontni",
        "pageinfo-contentpage-yes": "Enren",
        "patrol-log-page": "Journal dé roulèktir",
index 495fd47..5f499a4 100644 (file)
        "rcfilters-filter-editsbyself-description": "Na mùthaidhean a rinn thu fhèin.",
        "rcfilters-filter-editsbyother-label": "Mùthaidhean a rinn daoine eile",
        "rcfilters-filter-editsbyother-description": "Gach mùthadh ach an fheadhainn agad fhèin.",
-       "rcfilters-filtergroup-userExpLevel": "Clàradh is eòlas a’ chleachdaiche",
+       "rcfilters-filtergroup-user-experience-level": "Clàradh is eòlas a’ chleachdaiche",
        "rcfilters-filter-user-experience-level-registered-label": "Air clàradh a-steach",
        "rcfilters-filter-user-experience-level-registered-description": "Deasaichean a rinn clàradh a-steach.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Gun chlàradh a-steach",
        "rcfilters-filter-newpages-label": "Cruthachadh duilleige",
        "rcfilters-filter-newpages-description": "Deasachadh a chruthaich duilleag ùr.",
        "rcfilters-filter-logactions-label": "Gnìomhan logaichte",
-       "rcfilters-filtergroup-lastRevision": "Na mùthaidhean as ùire",
+       "rcfilters-filtergroup-lastrevision": "Na mùthaidhean as ùire",
        "rcfilters-filter-lastrevision-label": "Am mùthadh mu dheireadh",
        "rcfilters-filter-lastrevision-description": "Dìreach an t-àtharrachadh as ùire air duilleag.",
        "rcfilters-liveupdates-button": "Ùrachadh beò",
        "newpageletter": "Ù",
        "boteditletter": "bt",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[Tha $1 {{PLURAL:$1|chleachdaiche|chleachdaiche|cleachdaichean|cleachdaiche}} a' cumail sùil air]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|bhaidht|bhaidht|baidhtichean|baidht}} às dèidh an atharrachaidh",
        "newsectionsummary": "Earrann ùr /* $1 */",
        "img-auth-nopathinfo": "Tha PATH_INFO a dhìth.\nCha deach am frithealaiche agad a shuidheachadh ach an doireadh e am fiosrachadh seo seachad.\nDh'fhaoidte gu bheil e stèidhichte air CGI 's chan urrainn dha taic a chur ri img_auth.\nFaic https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Chan eil an t-slighe a chaidh iarraidh san t-slighe luchdaidh suas a chaidh a rèiteachadh.",
        "img-auth-badtitle": "Cha ghabh tiotal dligheach a thogail o \"$1\".",
-       "img-auth-nologinnWL": "Chan eil thu air logadh a-steach 's chan eil \"$1\" air a' gheal-liosta.",
        "img-auth-nofile": "Chan eil am faidhle \"$1\" ann.",
        "img-auth-isdir": "Tha thu a' feuchainn ris a' phasgan \"$1\" inntrigeadh.\nChan fhaod thu ach faidhlichean inntrigeadh.",
        "img-auth-streaming": "A' sruthadh \"$1\".",
        "revertpage": "Deasachaidhean a chaidh a thilleadh leis [[Special:Contributions/$2|$2]] ([[User talk:$2|an deasbaireachd]]) dhan mhùthadh mu dheireadh le [[User:$1|$1]]",
        "revertpage-nouser": "Deasachaidhean a chaidh a thilleadh le cleachdaiche falaichte dhan mhùthadh mu dheireadh le [[User:$1|$1]]",
        "rollback-success": "Na deasachaidhean a chaidh a thilleadh le $1;\nchaidh an tilleadh gun mhùthadh mu dheireadh le $2.",
-       "rollback-success-notify": "Na deasachaidhean a chaidh a thilleadh le $1;\nchaidh an tilleadh gun mhùthadh mu dheireadh le $2. [$3 Seall na h-atharraichean]",
        "sessionfailure-title": "Trioblaid leis an t-seisean",
        "sessionfailure": "Tha duilgheadas ann leis an seisean logaidh a-steach agad a-rèir coltais;\nchaidh sgur dhen ghnìomh seo a chum dìon o session hijacking.\nTill dhan duilleag roimhpe, ath-luchdaich an duilleag ud 's feuch ris a-rithist an uairsin.",
        "logentry-contentmodel-change-revertlink": "till",
        "allmessagesdefault": "Teacsa bunaiteach na teachdaireachd",
        "allmessagescurrent": "Teacsa na teachdaireachd an-dràsta",
        "allmessagestext": "Seo liosta de theachdaireachdan an t-siostaim a tha ri làimh ann an ainm-spàs MediaWiki.\nTadhail air [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Ionadaileadh MediaWiki] is [https://translatewiki.net translatewiki.net] ma tha thu airson pàirt a ghabhail ann an ionadaileadh MediaWiki.",
-       "allmessagesnotsupportedDB": "Cha ghabh an duilleag seo cleachdadh on a chaidh <strong>$wgUseDatabaseMessages</strong> a chur à comas.",
+       "allmessages-not-supported-database": "Cha ghabh an duilleag seo cleachdadh on a chaidh <strong>$wgUseDatabaseMessages</strong> a chur à comas.",
        "allmessages-filter-legend": "Criathrag",
        "allmessages-filter": "Criathraich le staid a' ghnàthachaidh:",
        "allmessages-filter-unmodified": "Gun atharrachadh",
index 0cf2e45..3218534 100644 (file)
        "page_first": "primeira",
        "page_last": "derradeira",
        "histlegend": "Selección de diferenzas: Marque as versións que queira comparar e prema no botón ao final.<br />\nLenda: '''({{int:cur}})''' = diferenza coa versión actual, '''({{int:last}})''' = diferenza coa versión precedente, '''{{int:minoreditletter}}''' = edición pequena.",
-       "history-fieldset-title": "Buscar revisións",
+       "history-fieldset-title": "Filtrar revisións",
        "history-show-deleted": "Só con borrados de revisións",
        "histfirst": "as máis antigas",
        "histlast": "as máis novas",
        "historysize": "({{PLURAL:$1|1 byte|$1 bytes}})",
-       "historyempty": "(baleiro)",
+       "historyempty": "baleiro",
        "history-feed-title": "Historial de revisións",
        "history-feed-description": "Historial de revisións desta páxina no wiki",
        "history-feed-item-nocomment": "$1 o $2",
        "right-reupload-own": "Sobrescribir un ficheiro existente cargado polo mesmo usuario",
        "right-reupload-shared": "Sobrescribir localmente ficheiros do repositorio multimedia",
        "right-upload_by_url": "Cargar ficheiros desde un enderezo URL",
-       "right-purge": "Purgar a caché dunha páxina do wiki sen a páxina de confirmación",
+       "right-purge": "Purgar a caché do sitio para unha páxina",
        "right-autoconfirmed": "Non ser afectado polos límites de frecuencia ligados aos enderezos IP",
        "right-bot": "Ser tratado coma un proceso automatizado",
        "right-nominornewtalk": "As edicións pequenas nas páxinas de conversa non lanzan o aviso de mensaxes novas",
        "action-changetags": "engadir e quitar etiquetas arbitrarias a revisións individuais e entradas do rexistro",
        "action-deletechangetags": "borrar etiquetas da base de datos",
        "action-purge": "purgar esta páxina",
+       "action-apihighlimits": "usar límites máis altos nas peticións á API",
+       "action-autoconfirmed": "non estar afectado polos límites de frecuencia baseados en enderezos IP",
+       "action-bigdelete": "borrar páxinas con historiais extensos",
+       "action-blockemail": "bloquear un usuario fronte ao envío dun correo electrónico",
+       "action-bot": "ser tratado como un proceso automatizado",
+       "action-editprotected": "editar páxinas protexidas con \"{{int:protect-level-sysop}}\"",
+       "action-editsemiprotected": "editar páxinas protexidas con \"{{int:protect-level-autoconfirmed}}\"",
+       "action-editinterface": "editar a interface de usuario",
+       "action-editusercss": "editar ficheiros CSS doutros usuarios",
+       "action-edituserjson": "editar ficheiros JSON doutros usuarios",
+       "action-edituserjs": "editar ficheiros JavaScript doutros usuarios",
+       "action-editsitecss": "editar CSS global do sitio",
+       "action-editsitejson": "editar JSON global do sitio",
+       "action-editsitejs": "editar JavaScript global do sitio",
+       "action-editmyusercss": "editar os ficheiros CSS propios",
+       "action-editmyuserjson": "editar os ficheiros JSON propios",
+       "action-editmyuserjs": "editar os ficheiros JavaScript propios",
+       "action-viewsuppressed": "ver revisións agochadas de calquera usuario",
+       "action-hideuser": "bloquear un nome de usuario, agochándoo do público",
+       "action-ipblock-exempt": "evitar bloqueos de IPs, autobloqueos e bloqueos de rango",
+       "action-unblockself": "desbloquearse a si mesmo",
+       "action-noratelimit": "non estar afectado polos límites de frecuencia",
+       "action-reupload-own": "sobrescribir ficheiros existentes cargados por un mesmo",
        "nchanges": "$1 {{PLURAL:$1|modificación|modificacións}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|desde a última visita}}",
        "enhancedrc-history": "historial",
        "rcfilters-savedqueries-already-saved": "Estes filtros xa están gardados. Cambie a súa configuración para crear un filtro gardado novo.",
        "rcfilters-restore-default-filters": "Restaurar os filtros por defecto",
        "rcfilters-clear-all-filters": "Borrar todos os filtros",
-       "rcfilters-show-new-changes": "Amosar os cambios máis recentes",
+       "rcfilters-show-new-changes": "Amosar novos cambios dende $1",
        "rcfilters-search-placeholder": "Filtrar os cambios (use o menú ou procure o nome dun filtro)",
        "rcfilters-invalid-filter": "Filtro no válido",
        "rcfilters-empty-filter": "Non hai filtros activos. Móstranse tódalas contribucións.",
        "rcfilters-filter-editsbyself-description": "As súas contribucións",
        "rcfilters-filter-editsbyother-label": "Modificacións doutros.",
        "rcfilters-filter-editsbyother-description": "Tódolos cambios, excepto os seus.",
-       "rcfilters-filtergroup-userExpLevel": "Rexistro de usuarios e experiencia",
+       "rcfilters-filtergroup-user-experience-level": "Rexistro de usuarios e experiencia",
        "rcfilters-filter-user-experience-level-registered-label": "Rexistrados",
        "rcfilters-filter-user-experience-level-registered-description": "Editores autenticados.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Non rexistrados",
        "rcfilters-hideminor-conflicts-typeofchange-global": "O filtro \"edicións menores\" está en conflito con un ou máis filtros Tipo de modificación, porque certos tipos de modificación non poden designarse como \"menores\". Os filtros en conflito están marcados na zona Filtros activos, arriba.",
        "rcfilters-hideminor-conflicts-typeofchange": "Certos tipos de modificación non poden designarse como \"menores\", polo que este filtro entra en conflito cos seguintes filtros Tipo de modificaciónː $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Este filtro Tipo de modificación entra en conflito co filtro \"Modificacións menores\". Certos tipos de modificación non poden designarse como \"menores\".",
-       "rcfilters-filtergroup-lastRevision": "Últimas revisións",
+       "rcfilters-filtergroup-lastrevision": "Últimas revisións",
        "rcfilters-filter-lastrevision-label": "Últimas revisións",
        "rcfilters-filter-lastrevision-description": "Só a última modificación a unha páxina.",
        "rcfilters-filter-previousrevision-label": "Non a última edición",
        "newpageletter": "N",
        "boteditletter": "b",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|usuario|usuarios}} vixiando]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} despois da modificación",
        "newsectionsummary": "Nova sección: /* $1 */",
        "img-auth-nopathinfo": "Falta a información da ruta.\nO seu servidor debe configurarse para pasar as variables REQUEST_URI e/ou PATH_INFO.\nSe o está, ténteo de novo activando $wgUsePathInfo.\nVexa https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "A ruta solicitada non está no directorio de carga configurado.",
        "img-auth-badtitle": "Non é posible construír un título válido a partir de \"$1\".",
-       "img-auth-nologinnWL": "Non accedeu ao sistema e \"$1\" non está na lista de branca.",
        "img-auth-nofile": "O ficheiro \"$1\" non existe.",
        "img-auth-isdir": "Está intentando acceder ao directorio \"$1\".\nSó se permite o acceso ao ficheiro.",
        "img-auth-streaming": "Secuenciando \"$1\".",
        "delete-confirm": "Borrar \"$1\"",
        "delete-legend": "Borrar",
        "historywarning": "<strong>Atención:</strong> A páxina que está a piques de borrar ten un historial con $1 {{PLURAL:$1|revisión|revisións}}:",
-       "historyaction-submit": "Amosar",
+       "historyaction-submit": "Amosar revisións",
        "confirmdeletetext": "Está a piques de borrar de xeito permanente unha páxina con todo o seu historial.\nPor favor, confirme que é realmente a súa intención, que comprende as consecuencias e que está obrando de acordo coas [[{{MediaWiki:Policy-url}}|políticas]].",
        "actioncomplete": "Completouse a acción",
        "actionfailed": "Fallou a acción",
        "deleting-backlinks-warning": "<strong>Atención:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Outras páxinas]] conteñen unha ligazón ou unha transclusión da páxina que está a piques de borrar.",
        "deleting-subpages-warning": "<strong>Aviso:</strong> A páxina que quere eliminar ten [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|unha subpáxina|$1 subpáxinas|51=máis de 50 subpáxinas}}]].",
        "rollback": "Reverter as edicións",
+       "rollback-confirmation-confirm": "Por favor, confirme:",
+       "rollback-confirmation-yes": "Reverter",
+       "rollback-confirmation-no": "Cancelar",
        "rollbacklink": "reverter",
        "rollbacklinkcount": "reverter $1 {{PLURAL:$1|edición|edicións}}",
        "rollbacklinkcount-morethan": "reverter máis de $1 {{PLURAL:$1|edición|edicións}}",
        "revertpage": "Desfixéronse as edicións de [[Special:Contributions/$2|$2]] ([[User talk:$2|conversa]]); cambiado á última versión feita por [[User:$1|$1]]",
        "revertpage-nouser": "Desfixéronse as edicións dun usuario agochado; cambiado á última versión feita por {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Desfixéronse as edicións de {{GENDER:$3|$1}};\nvolveuse á última edición, feita por {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Revertéronse as edicións de $1;\nrestaurouse a última revisión de $2. [$3 Amosar os cambios]",
        "sessionfailure-title": "Erro de sesión",
        "sessionfailure": "Parece que hai un problema co rexistro da súa sesión;\nesta acción cancelouse como precaución fronte ao secuestro de sesións.\nPor favor, volva enviar o formulario.",
        "changecontentmodel": "Cambiar o modelo de contido dunha páxina",
        "mycontris": "Contribucións",
        "anoncontribs": "Contribucións",
        "contribsub2": "De {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "Para{{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "A conta de usuario \"$1\" non está rexistrada.",
        "negative-namespace-not-supported": "Non están soportados os espazos de nomes con valore negativos.",
        "nocontribs": "Non se deron atopado cambios con eses criterios.",
        "blocklist-userblocks": "Agochar os bloqueos de contas",
        "blocklist-tempblocks": "Agochar os bloqueos temporais",
        "blocklist-addressblocks": "Agochar os bloqueos a enderezos IP únicos",
+       "blocklist-type": "Tipo:",
+       "blocklist-type-opt-all": "Todos",
+       "blocklist-type-opt-sitewide": "En todo o sitio",
+       "blocklist-type-opt-partial": "Parciais",
        "blocklist-rangeblocks": "Agochar os bloqueos de rango",
        "blocklist-timestamp": "Data e hora",
        "blocklist-target": "Destino",
        "allmessagesdefault": "Texto predeterminado",
        "allmessagescurrent": "Texto actual da mensaxe",
        "allmessagestext": "Esta é unha lista de todas as mensaxes dispoñibles no espazo de nomes MediaWiki.\nPor favor, visite a páxina de [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation localización] e [https://translatewiki.net translatewiki.net] se quere contribuír á localización xenérica de MediaWiki.",
-       "allmessagesnotsupportedDB": "Esta páxina non está dispoñible porque '''$wgUseDatabaseMessages''' está desactivado.",
+       "allmessages-not-supported-database": "Esta páxina non está dispoñible porque '''$wgUseDatabaseMessages''' está desactivado.",
        "allmessages-filter-legend": "Filtrar",
        "allmessages-filter": "Filtrar por estado de personalización:",
        "allmessages-filter-unmodified": "Inalteradas",
        "confirm-unwatch-top": "Quere eliminar esta páxina da lista de vixilancia?",
        "confirm-rollback-button": "Aceptar",
        "confirm-rollback-top": "Quere reverter as edicións desta páxina?",
+       "confirm-rollback-bottom": "Esta acción reverterá de forma instantánea os cambios seleccionados desta páxina.",
        "confirm-mcrrestore-title": "Restaurar unha revisión",
        "confirm-mcrundo-title": "Desfacer un cambio",
        "mcrundofailed": "Erro ao desfacer",
index b7822e4..510a3e4 100644 (file)
        "minoreditletter": "جؤز",
        "newpageletter": "نؤ",
        "boteditletter": "ر",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|کارگير}} پىگير]",
        "rc-change-size-new": "$1 {{PLURAL:$1|باىت}} تغييرˇ پسي",
        "recentchangeslinked": "مۊرتبطˇ تغىيرؤن",
        "recentchangeslinked-feed": "مۊرتبطˇ تغييرؤن",
index ccbe44d..2fa9ca5 100644 (file)
        "rcfilters-filter-minor-label": "Dhakte bodol",
        "rcfilters-filter-pageedits-label": "Panacheo sompadonam",
        "rcfilters-filter-categorization-label": "Vorgache bodol",
-       "rcfilters-filtergroup-lastRevision": "Akherchim uzollnnim",
+       "rcfilters-filtergroup-lastrevision": "Akherchim uzollnnim",
        "rcfilters-filter-lastrevision-label": "Sogleanvon novi uzollnni",
        "rcfilters-tag-prefix-namespace-inverted": "$1 <strong>:nhoi</strong>",
        "rcnotefrom": "Sokoil <strong>$3, $4<strong> savn {{PLURAL:$5|zalelem bodol dilam|zalelem bodol dileant}} (<strong>$1<strong> meren {{PLURAL:$5|dakhoilam|dakhoileant}}).",
index 13fa0db..e9fe2a1 100644 (file)
        "minoreditletter": "μ",
        "newpageletter": "Ν",
        "boteditletter": "αὐτ",
-       "number_of_watching_users_pageview": "[$1 ἐφορᾶν {{PLURAL:$1|χρώμενον|χρωμένους}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|δυφιολέξις|δυφιολέξεις}} μεθύστερον μεταβολής",
        "newsectionsummary": "/* $1 */ νέον τμῆμα",
        "rc-enhanced-expand": "Δεικνύναι λεπτομέρειας (ἀπαιτεῖ JavaScript)",
        "allmessagesname": "Ὄνομα",
        "allmessagesdefault": "Προεπειλεγμένον κείμενον",
        "allmessagescurrent": "Τρέχον κείμενον",
-       "allmessagesnotsupportedDB": "Ἥδε ἡ δέλτος ἄχρηστός ἐστὶν ἐπεί τὸ '''wgUseDatabaseMessages''' ἀνενεργὸν κατέστη.",
+       "allmessages-not-supported-database": "Ἥδε ἡ δέλτος ἄχρηστός ἐστὶν ἐπεί τὸ '''wgUseDatabaseMessages''' ἀνενεργὸν κατέστη.",
        "allmessages-filter-legend": "Διηθητήριον",
        "allmessages-filter": "Ταξινόμησις κατὰ κατάστασιν προσαρμογῆς:",
        "allmessages-filter-unmodified": "Μὴ τροποποιηθέν",
index f765589..68276e8 100644 (file)
        "minoreditletter": "C",
        "newpageletter": "N",
        "boteditletter": "B",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|Benutzer, wu beobachtet|Benutzer, wu beobachte}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|Byte|Byte}} no dr Änderig",
        "newsectionsummary": "Neje Abschnitt /* $1 */",
        "rc-enhanced-expand": "Detail aazeige",
        "img-auth-nopathinfo": "PATH_INFO fählt.\nDyy Server isch nit derfir yygrichtet, die Information wyterzgee.\nS chennt CGI-basiert syy un unterstitzt img_auth nit.\nLueg https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Dr gwinscht Pfad isch nit im konfigurierte Uploadverzeichnis.",
        "img-auth-badtitle": "Giltige Titel vu „$1“ cha nit aagleit wäre.",
-       "img-auth-nologinnWL": "Du bisch nit aagmäldet un „$1“ isch nit in dr wyße Lischt.",
        "img-auth-nofile": "Datei „$1“ git s nit.",
        "img-auth-isdir": "Du versuechsch, uf e Verzeichnis „$1“ zuezgryfe.\nNume Dateizuegriff isch erlaubt.",
        "img-auth-streaming": "Am Lade vu „$1“.",
        "allmessagesdefault": "Standardtext",
        "allmessagescurrent": "jetzige Tekscht",
        "allmessagestext": "Des isch e Lischt vu allene meglige Syschtemnochrichte us em MediaWiki Namensruum.\nLueg au uf [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Lokalisierig] un [https://translatewiki.net translatewiki.net], wänn Du zue dr MediaWiki-Lokalisierig wit byytrage.",
-       "allmessagesnotsupportedDB": "'''{{ns:special}}:Allmessages''' cha nit bruucht wärde will '''$wgUseDatabaseMessages''' abgschalte isch.",
+       "allmessages-not-supported-database": "'''{{ns:special}}:Allmessages''' cha nit bruucht wärde will '''$wgUseDatabaseMessages''' abgschalte isch.",
        "allmessages-filter-legend": "Filter",
        "allmessages-filter": "Filter fir dr aapasst Zuestand:",
        "allmessages-filter-unmodified": "Nit gänderet",
index 9ca872d..232d087 100644 (file)
        "minoreditletter": "નાનું",
        "newpageletter": "નવું",
        "boteditletter": "બૉટ",
-       "number_of_watching_users_pageview": "[$1 જોઇરહેલ  {{PLURAL:$1|સભ્ય|સભ્યો}}]",
        "rc-change-size-new": "બદલાયા પછી $1 {{PLURAL:$1|બાઈટ|બાઇટ્સ}}",
        "newsectionsummary": "/* $1 */ નવો વિભાગ",
        "rc-enhanced-expand": "વિગતો બતાવો",
        "img-auth-nopathinfo": "પથ માહિતી ગાયબ.\nઆ માહિતી પસાર કરવા તમારું સર્વર સજ્જ નથી.\nતે કદાચ CGI-આધારિત હોય અને img_authને આધાર ન આપે.\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization. જુઓ",
        "img-auth-notindir": "અર્જીત પથ ચડાવેલ ફાઈલની ડીરેક્ટરીમાં નથી",
        "img-auth-badtitle": "\"$1\" માટે વૈધ શીર્ષક ન શોધી શકાયું",
-       "img-auth-nologinnWL": "તમે પ્રવેશ કર્યો નથી અને અને : $1 ધવલ યાદિમાં નથી.",
        "img-auth-nofile": " ફાઇલ \"$1\" અસ્તિત્વમાં નથી",
        "img-auth-isdir": "તમે ડયરેક્ટરી \"$1\" ને પહોંચવાનો પ્રયાસ કરો છો.\nમાત્ર ફાઇલ સુધે પહોંચવાની પરવાનગી છે.",
        "img-auth-streaming": "ચિત્ર માહીતી  \"$1\" ઉતરી રહી છે.",
        "allmessagesdefault": "મૂળ સંદેશ",
        "allmessagescurrent": "વર્તમાન દસ્તાવેજ",
        "allmessagestext": "આ મિડિયાવિકિ નામસ્થળમાં આવેલ પ્રણાલીજનિત સંદેશાની યાદી આ મુજબ છે.\nજો તમે મિડિયાયાવિકિના સ્થાનીયકરણમાં મદદરૂપ થવા ઇચ્છતા હોવ તો કૃપયા [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] અને [https://translatewiki.net translatewiki.net]ની મુલાકાત લો.",
-       "allmessagesnotsupportedDB": "આ પાનું ન વાપરી શકાશે કેમકે '''$wgUseDatabaseMessages'''  નિષ્ક્રીય કરાયું છે",
+       "allmessages-not-supported-database": "આ પાનું ન વાપરી શકાશે કેમકે '''$wgUseDatabaseMessages'''  નિષ્ક્રીય કરાયું છે",
        "allmessages-filter-legend": "ચાળણી",
        "allmessages-filter": "સ્થાનીયકરણ સ્થિતિ દ્વારા ચાળો",
        "allmessages-filter-unmodified": "અસંપાદિત",
index 9362132..a9c4ba1 100644 (file)
        "viewprevnext": "Duba ($1 {{int:pipe-separator}} $2) ($3)",
        "searchmenu-new": "''Zaku iya ƙirƙirar shafin \"[[:$1]]\"''.",
        "searchprofile-everything": "Duk abin da",
+       "searchprofile-articles-tooltip": "Nemo a $1",
        "search-result-size": "$1 ({{PLURAL:$2|1 kalma|$2 kalmomi}})",
        "search-redirect": "(an turo daga $1)",
        "search-section": "(sashe $1)",
        "imagelinks": "Amfani da fayil",
        "linkstoimage": "{{PLURAL:$1|Wannan shafi yana|wanɗannan shafuna $1 suna}} amfani da wannan fayil:",
        "sharedupload": "Wannan fayil na da tushe daga $1 kuma wasu shire-shire suna iya amfani da shi.",
+       "sharedupload-desc-here": "Wannan hoto yazo daga $1 kuma za'a iya amfani dashi a wasu projects.\nAnan kasa an nuna [$2 asalin bayanin shi]",
        "uploadnewversion-linktext": "Ɗauki sabon zubi na wannan fayil",
        "upload-disallowed-here": "Ba zaku iya sabunta wannan hoto ba",
        "filerevert-comment": "Dalili:",
index 1637e48..ceb8e3a 100644 (file)
        "minoreditletter": "se-mì",
        "newpageletter": "Sîn",
        "boteditletter": "kî",
-       "number_of_watching_users_pageview": "[$1隻用戶關注]",
        "rc-change-size-new": "Kiên-kói heu ke $1 vi-ngièn-chû",
        "rc-enhanced-expand": "展示細節 (愛有JavaScript)",
        "rc-enhanced-hide": "隱藏細節",
        "allmessagesdefault": "默認信息文字",
        "allmessagescurrent": "Tông-chhièn ke vùn-sṳ",
        "allmessagestext": "Liá-piên lie̍t-chhut só-yû hí-khó thin-chṳ ke ne-thúng kie-mien.\nPlease visit [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] and [https://translatewiki.net translatewiki.net] if you wish to contribute to the generic MediaWiki localisation.",
-       "allmessagesnotsupportedDB": "Ne-thúng kie-mien kûng-yung chhu-yî kôan-pit chong-thai (wgUseDatabaseMessages)。",
+       "allmessages-not-supported-database": "!!FUZZY!!!!FUZZY!!Ne-thúng kie-mien kûng-yung chhu-yî kôan-pit chong-thai (wgUseDatabaseMessages)。",
        "thumbnail-more": "Piong-thai",
        "filemissing": "Mò-fap cháu-to tóng-on",
        "thumbnail_error": "建立縮略圖差錯:$1",
index 8f8c6b9..cee2cc1 100644 (file)
        "virus-scanfailed": "הסריקה נכשלה (קוד: $1)",
        "virus-unknownscanner": "אנטי־וירוס בלתי־ידוע:",
        "logouttext": "<strong>יצאתם מהחשבון.</strong>\n\nשימו לב שייתכן שדפים מסוימים ימשיכו להיות מוצגים כאילו אתם עדיין מחוברים לחשבון, עד שתנקו את המטמון של הדפדפן שלכם.",
+       "logging-out-notify": "מתבצעת יציאה מהחשבון, נא להמתין.",
+       "logout-failed": "לא ניתן לצאת מהחשבון עכשיו: $1",
        "cannotlogoutnow-title": "לא ניתן לצאת מהחשבון עכשיו",
        "cannotlogoutnow-text": "היציאה מהחשבון אינה אפשרית בעת שימוש ב{{GRAMMAR:תחילית|$1}}.",
        "welcomeuser": "ברוך בואך, $1!",
        "page_first": "ראשון",
        "page_last": "אחרון",
        "histlegend": "בחירת גרסאות להשוואה: יש לבחור את הגרסאות שברצונך להשוות ולאחר מכן להקיש על Enter או ללחוץ על הכפתור שלמטה.<br />\nמקרא: <strong>({{int:cur}})</strong> = השוואה עם הגרסה הנוכחית, <strong>({{int:last}})</strong> = השוואה עם הגרסה הקודמת, <strong>{{int:minoreditletter}}</strong> = עריכה משנית.",
-       "history-fieldset-title": "×\97×\99פ×\95ש גרסאות",
+       "history-fieldset-title": "ס×\99× ×\95×\9f גרסאות",
        "history-show-deleted": "גרסאות מוסתרות בלבד",
        "histfirst": "הישנות ביותר",
        "histlast": "החדשות ביותר",
        "historysize": "({{PLURAL:$1|בית אחד|$1 בתים}})",
-       "historyempty": "(ריק)",
+       "historyempty": "ריק",
        "history-feed-title": "היסטוריית גרסאות",
        "history-feed-description": "היסטוריית הגרסאות של הדף הזה בוויקי",
        "history-feed-item-nocomment": "$1 ב־$2",
        "right-reupload-own": "העלאת גרסאות חדשות של קבצים קיימים שהועלו על־ידי המשתמש עצמו",
        "right-reupload-shared": "דריסה מקומית של קבצים מאתר קובצי המדיה המשותף",
        "right-upload_by_url": "העלאת קבצים מכתובת אינטרנט (URL)",
-       "right-purge": "ניקוי זיכרון המטמון של דף ללא מעבר בדף אישור",
+       "right-purge": "ניקוי זיכרון המטמון של דף",
        "right-autoconfirmed": "עקיפת ההגבלה על קצב הפעולות שניתן לבצע מכתובת IP מסוימת",
-       "right-bot": "×\94ת×\99×\99×\97ס×\95ת ×\9cער×\99×\9b×\95ת ×\9b×\90×\95×\98×\95×\9e×\98×\99×\95ת",
+       "right-bot": "ק×\91×\9cת ×\94ת×\99×\99×\97ס×\95ת ×\9bת×\94×\9c×\99×\9a ×\90×\95×\98×\95×\9e×\98×\99",
        "right-nominornewtalk": "ביטול שליחת התראה על הודעה חדשה למשתמש בעת עריכה משנית בדף השיחה שלו",
        "right-apihighlimits": "שימוש ב־API עם פחות הגבלות",
        "right-writeapi": "שימוש ב־API לשינוי דפים",
        "right-blockemail": "חסימת משתמשים משליחת דואר אלקטרוני",
        "right-hideuser": "חסימת שם משתמש תוך הסתרתו מהציבור",
        "right-ipblock-exempt": "עקיפת חסימות של כתובות IP, חסימות אוטומטיות וחסימות טווחים",
-       "right-unblockself": "ש×\97ר×\95ר ×\97ס×\99×\9e×\94 ×©×\9c ×\94×\9eשת×\9eש ×¢×¦×\9e×\95",
+       "right-unblockself": "ש×\97ר×\95ר ×©×\9c ×\94×\9eשת×\9eש ×¢×¦×\9e×\95 ×\9e×\97ס×\99×\9e×\94",
        "right-protect": "שינוי רמות הגנה של דפים ועריכת דפים המוגנים בהגנה מדורגת",
        "right-editprotected": "עריכת דפים המוגנים ברמת ההגנה \"{{int:protect-level-sysop}}\"",
        "right-editsemiprotected": "עריכת דפים המוגנים ברמת ההגנה \"{{int:protect-level-autoconfirmed}}\"",
        "right-editmyprivateinfo": "עריכת המידע הפרטי של המשתמש עצמו (כגון: כתובת דוא\"ל, שם אמיתי)",
        "right-editmyoptions": "עריכת ההעדפות של המשתמש עצמו",
        "right-rollback": "שחזור מהיר של העריכות שנעשו על־ידי העורך האחרון בדפים",
-       "right-markbotedits": "ס×\99×\9e×\95×\9f ×¢×¨×\99×\9b×\95ת ×\9eש×\95×\97×\96ר×\95ת ×\9bעריכות של בוט",
+       "right-markbotedits": "ס×\99×\9e×\95×\9f ×¢×¨×\99×\9b×\95ת ×©×©×\95×\97×\96ר×\95 ×\91ת×\95ר עריכות של בוט",
        "right-noratelimit": "עקיפת ההגבלה על קצב הפעולות",
        "right-import": "ייבוא דפים מאתרי ויקי אחרים",
        "right-importupload": "ייבוא דפים באמצעות העלאת קבצים",
        "action-changetags": "להוסיף או להסיר תגיות מגרסאות ומרשומות יומן",
        "action-deletechangetags": "למחוק תגיות מבסיס הנתונים",
        "action-purge": "לנקות את זיכרון המטמון של דף זה",
+       "action-apihighlimits": "להשתמש ב־API עם פחות הגבלות",
+       "action-autoconfirmed": "לעקוף את ההגבלה על קצב הפעולות שניתן לבצע מכתובת IP מסוימת",
+       "action-bigdelete": "למחוק דפים המכילים כמות גדולה של עריכות בהיסטוריית הגרסאות",
+       "action-blockemail": "לחסום משתמשים משליחת דואר אלקטרוני",
+       "action-bot": "לקבל התייחסות כתהליך אוטומטי",
+       "action-editprotected": "לערוך דפים המוגנים ברמת ההגנה \"{{int:protect-level-sysop}}\"",
+       "action-editsemiprotected": "לערוך דפים המוגנים ברמת ההגנה \"{{int:protect-level-autoconfirmed}}\"",
+       "action-editinterface": "לערוך את ממשק המשתמש",
+       "action-editusercss": "לערוך קובצי CSS של משתמשים אחרים",
+       "action-edituserjson": "לערוך קובצי JSON של משתמשים אחרים",
+       "action-edituserjs": "לערוך קובצי JavaSript של משתמשים אחרים",
+       "action-editsitecss": "לערוך קובצי CSS של האתר כולו",
+       "action-editsitejson": "לערוך קובצי JSON של האתר כולו",
+       "action-editsitejs": "לערוך קובצי JavaScript של האתר כולו",
+       "action-editmyusercss": "לערוך קובצי CSS של עצמך",
+       "action-editmyuserjson": "לערוך קובצי JSON של עצמך",
+       "action-editmyuserjs": "לערוך קובצי JavaScript של עצמך",
+       "action-viewsuppressed": "לצפות בגרסאות שהוסתרו מכל המשתמשים",
+       "action-hideuser": "לחסום שם משתמש תוך הסתרתו מהציבור",
+       "action-ipblock-exempt": "לעקוף חסימות של כתובות IP, חסימות אוטומטיות וחסימות טווחים",
+       "action-unblockself": "לשחרר את עצמך מחסימה",
+       "action-noratelimit": "לעקוף את ההגבלה על קצב הפעולות",
+       "action-reupload-own": "להעלות גרסאות חדשות של קבצים קיימים שהעלית בעצמך",
+       "action-nominornewtalk": "לבטל שליחת התראה על הודעה חדשה למשתמש בעת עריכה משנית בדף השיחה שלו",
+       "action-markbotedits": "לסמן עריכות ששוחזרו בתור עריכות של בוט",
+       "action-patrolmarks": "להבחין בין עריכות שנבדקו לעריכות שטרם נבדקו בדף השינויים האחרונים",
+       "action-override-export-depth": "לייצא דפים כולל הדפים המקושרים (עד עומק של 5 דפים)",
+       "action-suppressredirect": "להימנע מיצירת הפניות מדפי המקור בעת העברת דפים",
        "nchanges": "{{PLURAL:$1|שינוי אחד|$1 שינויים}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|מאז ביקורך האחרון}}",
        "enhancedrc-history": "היסטוריה",
        "rcfilters-savedqueries-already-saved": "מסננים אלה כבר נשמרו. באפשרותך לשנות את ההגדרות שלך כדי ליצור ולשמור מסנן חדש.",
        "rcfilters-restore-default-filters": "שחזור למסנני ברירת המחדל",
        "rcfilters-clear-all-filters": "מחיקת כל המסננים",
-       "rcfilters-show-new-changes": "×\94צ×\92ת ×\94ש×\99× ×\95×\99×\99×\9d ×\94×\97×\93ש×\99×\9d ×\91×\99×\95תר",
+       "rcfilters-show-new-changes": "×\94צ×\92ת ×\94ש×\99× ×\95×\99×\99×\9d ×\94×\97×\93ש×\99×\9d ×\9e×\90×\96 $1",
        "rcfilters-search-placeholder": "סינון שינויים (ניתן להשתמש בתפריט או לחפש שם מסנן)",
        "rcfilters-invalid-filter": "מסנן בלתי־תקין",
        "rcfilters-empty-filter": "אין מסננים פעילים. כל התרומות מוצגות.",
        "rcfilters-filter-editsbyself-description": "תרומות שביצעת בעצמך.",
        "rcfilters-filter-editsbyother-label": "שינויים של אחרים",
        "rcfilters-filter-editsbyother-description": "כל השינויים מלבד אלה שלך.",
-       "rcfilters-filtergroup-userExpLevel": "הרשמת משתמשים ורמת ניסיון",
+       "rcfilters-filtergroup-user-experience-level": "הרשמת משתמשים ורמת ניסיון",
        "rcfilters-filter-user-experience-level-registered-label": "רשומים",
        "rcfilters-filter-user-experience-level-registered-description": "עורכים שנכנסו לחשבון.",
        "rcfilters-filter-user-experience-level-unregistered-label": "לא רשומים",
        "rcfilters-hideminor-conflicts-typeofchange-global": "מסנן \"עריכות משניות\" מתנגש עם מסנן אחד או יותר של סוג השינויים, כי סוגים מסוימים של שינויים אינם יכולים להיות מסווגים בתור \"משניים\". המסננים המתנגשים מסומנים באזור המסננים הפעילים לעיל.",
        "rcfilters-hideminor-conflicts-typeofchange": "סוגים מסוימים של שינויים אינם יכולים להיות מסווגים כ\"משניים\", כך שמסנן זה מתנגש עם מסנן סוג השינויים הבא: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "מסנן סוג השינויים הזה מתנגש עם מסנן \"עריכות משניות\". סוגים מסוימים של שינויים אינם יכולים מסווגים כ\"משניים\".",
-       "rcfilters-filtergroup-lastRevision": "גרסאות אחרונות",
+       "rcfilters-filtergroup-lastrevision": "גרסאות אחרונות",
        "rcfilters-filter-lastrevision-label": "הגרסה האחרונה",
        "rcfilters-filter-lastrevision-description": "רק השינוי האחרון בדף.",
        "rcfilters-filter-previousrevision-label": "לא הגרסה האחרונה",
        "minoreditletter": "מ",
        "newpageletter": "ח",
        "boteditletter": "ב",
-       "number_of_watching_users_pageview": "[{{PLURAL:$1|משתמש אחד עוקב|$1 משתמשים עוקבים}} אחרי הדף]",
        "rc-change-size-new": "{{PLURAL:$1|בית אחד|$1 בתים}} לאחר השינוי",
        "newsectionsummary": "/* $1 */ פסקה חדשה",
        "rc-enhanced-expand": "הצגת הפרטים",
        "img-auth-nopathinfo": "חסר מידע על הנתיב.\nהשרת חייב להיות מוגדר להעברת המשתנים REQUEST_URI ו/או PATH_INFO.\nאם הוא אכן מוגדר כך, ניתן לנסות להפעיל את ‎$wgUsePathInfo.\nלמידע נוסף: https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization",
        "img-auth-notindir": "הנתיב המבוקש אינו בתיקיית ההעלאות שהוגדרה.",
        "img-auth-badtitle": "לא ניתן ליצור כותרת תקינה מתוך \"$1\".",
-       "img-auth-nologinnWL": "לא נכנסת לחשבון, והדף \"$1\" אינו ברשימה המותרת.",
        "img-auth-nofile": "הקובץ \"$1\" אינו קיים.",
        "img-auth-isdir": "ניסית לגשת לתיקייה \"$1\".\nרק גישה לקבצים מותרת.",
        "img-auth-streaming": "מתבצעת הזרמה של \"$1\".",
        "logeventslist-patrol-log": "יומן שינויים בדוקים",
        "logeventslist-tag-log": "יומן תגיות",
        "all-logs-page": "כל היומנים הציבוריים",
-       "alllogstext": "זוהי תצוגה משולבת של כל סוגי היומנים הזמינים ב{{grammar:תחילית|{{SITENAME}}}}.\nניתן לצמצם את התצוגה על־ידי בחירת סוג היומן, שם המשתמש (תלוי־רישיות) או הדף המושפע (גם כן תלוי־רישיות).",
+       "alllogstext": "זוהי תצוגה משולבת של כל סוגי היומנים הזמינים ב{{GRAMMAR:תחילית|{{SITENAME}}}}.\nניתן לצמצם את התצוגה על־ידי בחירת סוג היומן, שם המשתמש (תלוי־רישיות) או הדף המושפע (גם כן תלוי־רישיות).",
        "logempty": "אין פריטים תואמים ביומן.",
        "log-title-wildcard": "חיפוש כותרות המתחילות באותיות אלה",
        "showhideselectedlogentries": "שינוי מצב התצוגה של פעולות היומן שנבחרו",
        "delete-confirm": "מחיקת הדף \"$1\"",
        "delete-legend": "מחיקה",
        "historywarning": "<strong>אזהרה:</strong> לדף שעומד להימחק יש היסטוריית שינויים של {{PLURAL:$1|גרסה אחת|$1 גרסאות}}:",
-       "historyaction-submit": "×\94צ×\92×\94",
+       "historyaction-submit": "×\94צ×\92ת ×\94×\92רס×\90×\95ת",
        "confirmdeletetext": "ניתן להשתמש בטופס שלהלן כדי למחוק דף יחד עם כל ההיסטוריה שלו.\nנא לאשר שזה אכן מה שהתכוונת לעשות, שהתוצאות של הפעולה הזו ידועות לך, ושהמעשה מבוצע בהתאם ל[[{{MediaWiki:Policy-url}}|נוהלי האתר]].",
        "actioncomplete": "הפעולה בוצעה",
        "actionfailed": "הפעולה נכשלה",
        "deleting-backlinks-warning": "<strong>אזהרה:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|דפים אחרים]] מקשרים לדף זה (שעומד להימחק) או מכלילים אותו.",
        "deleting-subpages-warning": "<strong>אזהרה:</strong> לדף שעומד להימחק יש [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|דף משנה|$1 דפי משנה|51=יותר מ־50 דפי משנה}}]].",
        "rollback": "שחזור עריכות",
+       "rollback-confirmation-confirm": "לאישורך:",
+       "rollback-confirmation-yes": "שחזור",
+       "rollback-confirmation-no": "ביטול",
        "rollbacklink": "שחזור",
        "rollbacklinkcount": "שחזור {{PLURAL:$1|עריכה אחת|$1 עריכות}}",
        "rollbacklinkcount-morethan": "שחזור יותר מ{{PLURAL:$1|עריכה אחת|־$1 עריכות}}",
        "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-notify": "שוחזר מעריכות של $1\nלעריכה האחרונה של $2. [$3 הצגת שינויים]",
        "sessionfailure-title": "בעיה בחיבור",
        "sessionfailure": "נראה שיש בעיה בחיבור שלך לאתר;\nפעולה זו בוטלה כאמצעי זהירות נגד התחזות לתקשורת ממחשבך.\nנא לשלוח מחדש את הטופס.",
        "changecontentmodel": "שינוי מודל התוכן של דף",
        "mycontris": "תרומות",
        "anoncontribs": "תרומות",
        "contribsub2": "עבור {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "עבור {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "חשבון המשתמש \"$1\" אינו רשום.",
        "negative-namespace-not-supported": "אין תמיכה במרחבי שם בעלי ערך שלילי.",
        "nocontribs": "לא נמצאו שינויים המתאימים לקריטריונים אלו.",
        "blocklist-userblocks": "הסתרת חסימות של משתמשים רשומים",
        "blocklist-tempblocks": "הסתרת חסימות זמניות",
        "blocklist-addressblocks": "הסתרת חסימות של כתובות IP בודדות",
+       "blocklist-type": "סוג:",
+       "blocklist-type-opt-all": "הכול",
+       "blocklist-type-opt-sitewide": "כל האתר",
+       "blocklist-type-opt-partial": "חלקית",
        "blocklist-rangeblocks": "הסתרת חסימות טווחים",
        "blocklist-timestamp": "תאריך ושעה",
        "blocklist-target": "המשתמש שנחסם",
        "blocklist-editing-page": "דפים",
        "blocklist-editing-ns": "מרחבי שם",
        "ipblocklist-empty": "רשימת המשתמשים החסומים ריקה.",
-       "ipblocklist-no-results": "ש×\9d ×\94×\9eשת×\9eש ×\90×\95 ×\9bת×\95×\91ת ×\94Ö¾IP ×\94×\9e×\91×\95קש×\99×\9d ×\90×\99× ×\9d ×\97ס×\95×\9eים.",
+       "ipblocklist-no-results": "×\9c×\90 × ×\9eצ×\90×\95 ×\97ס×\99×\9e×\95ת ×\9eת×\90×\99×\9e×\95ת ×\9cש×\9d ×\94×\9eשת×\9eש ×\90×\95 ×\9bת×\95×\91ת ×\94Ö¾IP ×\94×\9e×\91×\95קשים.",
        "blocklink": "חסימה",
        "unblocklink": "שחרור החסימה",
        "change-blocklink": "שינוי החסימה",
+       "empty-username": "(שם המשתמש אינו זמין)",
        "contribslink": "תרומות",
        "emaillink": "שליחת דוא\"ל",
        "autoblocker": "נחסמתם באופן אוטומטי משום שאתם חולקים את כתובת ה־IP שלכם עם [[User:$1|$1]].\nהסיבה שניתנה לחסימת $1 היא \"$2\"",
        "allmessagesdefault": "טקסט ברירת המחדל של ההודעה",
        "allmessagescurrent": "הטקסט הנוכחי של ההודעה",
        "allmessagestext": "זוהי רשימה של הודעות המערכת במרחב השם \"{{ns:mediawiki}}\".\nניתן לבקר בדף [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] ובאתר [https://translatewiki.net translatewiki.net] כדי לתרום לתרגום הכללי של מדיה־ויקי.",
-       "allmessagesnotsupportedDB": "לא ניתן להשתמש בדף זה כיוון ש־<strong dir=\"ltr\">$wgUseDatabaseMessages</strong> מבוטל.",
+       "allmessages-not-supported-database": "לא ניתן להשתמש בדף זה כיוון ש־<strong dir=\"ltr\">$wgUseDatabaseMessages</strong> מבוטל.",
        "allmessages-filter-legend": "סינון",
        "allmessages-filter": "סינון לפי מצב ההודעה:",
        "allmessages-filter-unmodified": "הודעות שלא שונו",
        "confirm-unwatch-top": "להסיר את הדף הזה מרשימת המעקב שלך?",
        "confirm-rollback-button": "אישור",
        "confirm-rollback-top": "לשחזר את העריכות בדף זה?",
+       "confirm-rollback-bottom": "פעולה זו תשחזר באופן מיידי את השינויים שבחרת בדף זה.",
        "confirm-mcrrestore-title": "שחזור גרסה",
        "confirm-mcrundo-title": "ביטול שינוי",
        "mcrundofailed": "הביטול נכשל",
        "passwordpolicies-policyflag-forcechange": "לדרוש שינוי בעת כניסה לחשבון",
        "passwordpolicies-policyflag-suggestchangeonlogin": "להציע שינוי בעת כניסה לחשבון",
        "easydeflate-invaliddeflate": "התוכן שהועבר אינו דחוס כנדרש",
-       "unprotected-js": "מסיבות אבטחה, לא ניתן לטעון JavaScript מדפים שאינם מוגנים. ניתן ליצור סקריפטי JavaScript רק במרחב השם \"מדיה ויקי:\" או בדפי משנה של דף המשתמש."
+       "unprotected-js": "מסיבות אבטחה, לא ניתן לטעון JavaScript מדפים שאינם מוגנים. ניתן ליצור סקריפטי JavaScript רק במרחב השם \"מדיה ויקי:\" או בדפי משנה של דף המשתמש.",
+       "userlogout-continue": "יש [$1 להמשיך לדף היציאה מהחשבון] כדי לצאת מהחשבון.",
+       "userlogout-sessionerror": "היציאה מהחשבון נכשלה בשל שגיאת אימות. יש [$1 לנסות שוב]."
 }
index efe06b4..6fae3ea 100644 (file)
        "rcfilters-filter-editsbyself-description": "आपके अपने योगदान।",
        "rcfilters-filter-editsbyother-label": "दूसरों के द्वारा बदलाव",
        "rcfilters-filter-editsbyother-description": "आपके बदलावों को छोड़ कर सभी के बदलाव।",
-       "rcfilters-filtergroup-userExpLevel": "उपयोगकर्ता पंजीकरण और अनुभव",
+       "rcfilters-filtergroup-user-experience-level": "उपयोगकर्ता पंजीकरण और अनुभव",
        "rcfilters-filter-user-experience-level-registered-label": "पंजीकृत",
        "rcfilters-filter-user-experience-level-registered-description": "लॉग-इन संपादक।",
        "rcfilters-filter-user-experience-level-unregistered-label": "अपंजीकृत",
        "rcfilters-hideminor-conflicts-typeofchange-global": "\"लघु संपादन\" फ़िल्टर एक या एक से अधिक प्रकार के परिवर्तन फ़िल्टर के साथ संघर्ष करता है, क्योंकि कुछ प्रकार के परिवर्तन को \"लघु\" के रूप में निर्दिष्ट नहीं किया जा सकता है। परस्पर विरोधी फिल्टर ऊपर सक्रिय फिल्टर क्षेत्र में चिह्नित हैं।",
        "rcfilters-hideminor-conflicts-typeofchange": "कुछ प्रकार के परिवर्तन को \"लघु\" के रूप में निर्दिष्ट नहीं किया जा सकता है\", इसलिए यह फ़िल्टर निम्न प्रकार के परिवर्तन फिल्टर के साथ संघर्ष करता है: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "इस प्रकार का परिवर्तन फ़िल्टर \"लघु संपादन\" फ़िल्टर के साथ संघर्ष करता है। कुछ प्रकार के परिवर्तन को \"लघु\" के रूप में निर्दिष्ट नहीं किया जा सकता है।",
-       "rcfilters-filtergroup-lastRevision": "नया अवतरण",
+       "rcfilters-filtergroup-lastrevision": "नया अवतरण",
        "rcfilters-filter-lastrevision-label": "नया अवतरण",
        "rcfilters-filter-lastrevision-description": "पृष्ठ का सबसे हाल में हुआ बदलाव",
        "rcfilters-filter-previousrevision-label": "पहले के अवतरण",
        "minoreditletter": "छो",
        "newpageletter": "न",
        "boteditletter": "बॉ",
-       "number_of_watching_users_pageview": "[$1 ध्यान रखने वाले {{PLURAL:$1|सदस्य}}]",
        "rc-change-size-new": "बदलाव के बाद $1 {{PLURAL:$1|बाइट}}",
        "newsectionsummary": "/* $1 */ नया अनुभाग",
        "rc-enhanced-expand": "विस्तृत जानकारी दिखाएँ",
        "img-auth-nopathinfo": "पाथ जानकारी उपलब्ध नहीं है।\nआपके सर्वर को REQUEST_URI तथा/अथवा PATH_INFO चरों को पास करने के लिये सेट अप होना चाहिये। अगर ऐसा है तो $wgUsePathInfo को सक्रिय करने का प्रयास करें।  \nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization देखें।",
        "img-auth-notindir": "अनुरोधित पथ जमाई हुई अपलोड डायरेक्टरी में नहीं है।",
        "img-auth-badtitle": "\"$1\" से एक वैध शीर्षक बनाने में असमर्थ।",
-       "img-auth-nologinnWL": "आपने सत्रारंभ नहीं किया हुआ है और \"$1\" श्वेतसूची में नहीं है।",
        "img-auth-nofile": "फ़ाइल \"$1\" मौजूद नहीं है।",
        "img-auth-isdir": "आप डायरेक्टरी \"$1\" खोलने की कोशिश कर रहे हैं।\nकेवल फ़ाइल खोली जा सकती है।",
        "img-auth-streaming": "\"$1\" को स्ट्रीम किया जा रहा है।",
        "revertpage": "[[Special:Contributions/$2|$2]] ([[User talk:$2|Talk]]) के संपादनों को हटाकर [[User:$1|$1]] के अन्तिम अवतरण को पूर्ववत किया",
        "revertpage-nouser": "(सदस्य नाम हटाया गया है) के संपादनों को हटाकर {{GENDER:$1|[[User:$1|$1]]}} के अन्तिम अवतरण को पूर्ववत किया।",
        "rollback-success": "{{GENDER:$3|$1}} के संपादन हटाए;\n{{GENDER:$4|$2}} द्वारा संपादित अन्तिम अवतरण को पुनर्स्थापित किया।",
-       "rollback-success-notify": "$1 के सम्पादन वापिस लौटाए;\n$2 द्वारा संपादित अंतिम संस्करण पुनर्स्थापित किया। [$3 बदलाव दिखाएँ]",
        "sessionfailure-title": "सत्र विफलता",
        "sessionfailure": "ऐसा प्रतीत होता है कि आपके लॉगिन सत्र के साथ कोई समस्या है।\nसत्र अपहरण से बचाने के लिए सावधानी के तौर पर आपका यह क्रियाकलाप रद्द कर दिया गया है।\nकृपया प्रपत्र दोबारा जमा करें।",
        "changecontentmodel": "पन्ने का सामग्री प्रारूप बदलें",
        "allmessagesdefault": "डिफॉल्ट पाठ",
        "allmessagescurrent": "वर्तमान पाठ",
        "allmessagestext": "ये मीडियाविकि नामस्थान में उपलब्ध प्रणाली संदेशों की एक सूची है। यदि आप सामान्य मीडियाविकि क्षेत्रीयकरण में योगदान देना चाहें तो कृपया [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation मीडियाविकि क्षेत्रीयकरण] व [https://translatewiki.net translatewiki.net] को देखें।",
-       "allmessagesnotsupportedDB": "इस पृष्ठ का इस्तेमाल नहीं कर सकते क्योंकी '''$wgUseDatabaseMessages''' बंद हैं।",
+       "allmessages-not-supported-database": "इस पृष्ठ का इस्तेमाल नहीं कर सकते क्योंकी '''$wgUseDatabaseMessages''' बंद हैं।",
        "allmessages-filter-legend": "छानें",
        "allmessages-filter": "अनुकूलन स्थिति के आधार पर छानें:",
        "allmessages-filter-unmodified": "अपरिवर्तित",
index 3590351..9502c4c 100644 (file)
        "rcfilters-filter-editsbyself-description": "Aap ke karaa gais badlao.",
        "rcfilters-filter-editsbyother-label": "Duusra jan ke karaa gais badlao",
        "rcfilters-filter-editsbyother-description": "Badlao jiske duusraa jan karin hai (aap nai)",
-       "rcfilters-filtergroup-userExpLevel": "Sadasya ke registration aur anbhao",
+       "rcfilters-filtergroup-user-experience-level": "Sadasya ke registration aur anbhao",
        "rcfilters-filter-user-experience-level-registered-label": "Register kar dewa gais",
        "rcfilters-filter-user-experience-level-registered-description": "Editors, jon abhi logged in hai.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Jon abhi registered nai hai",
        "rcfilters-hideminor-conflicts-typeofchange-global": "The \"Minor edits\" filter conflicts with one or more Type of change filters, because certain types of change cannot be designated as \"minor\". The conflicting filters are marked in the Active filters area, above.",
        "rcfilters-hideminor-conflicts-typeofchange": "Certain types of change cannot be designated as \"minor\", so this filter conflicts with the following Type of Change filters: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "This Type of change filter conflicts with the \"Minor edits\" filter. Certain types of change cannot be designated as \"minor\".",
-       "rcfilters-filtergroup-lastRevision": "Abhi ke badlao",
+       "rcfilters-filtergroup-lastrevision": "Abhi ke badlao",
        "rcfilters-filter-lastrevision-label": "Abhi ke badlao",
        "rcfilters-filter-lastrevision-description": "Panna ke khaali sab se recent badlao.",
        "rcfilters-filter-previousrevision-label": "Sab se latest revision nai hai",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|user|users}} ke dekhta hae]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} badlao ke baad",
        "newsectionsummary": "/* $1 */ nawaa vibhag",
        "rc-enhanced-expand": "Details dekhao",
        "img-auth-nopathinfo": "Aap ke server ke ii jankari de khatir set up nai karaa gais hae\nSaait ii CGI-based hoi aur img_auth ke nai support karat hoi.\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization ke dekho.",
        "img-auth-notindir": "Maanga gais path configured upload directory me me nai hae.",
        "img-auth-badtitle": "\"$1\" se kanuni title ke nai banae sakaa hae.",
-       "img-auth-nologinnWL": "Aap logged in nai hae aur \"$1\" whitelist me nai hae.",
        "img-auth-nofile": "File \"$1\" nai hae.",
        "img-auth-isdir": "Aap directory \"$1\" me jaae mangtaa hae.\nKhaali file me jaawe ke ijajat hae",
        "img-auth-streaming": "\"$1\" ke stream karaa jaawe hae.",
        "revertpage": "[[Special:Contributions/$2|$2]] ([[User talk:$2|Talk]]) ke badlao ke [[User:$1|$1]] ke aakhri badlao ke jaise kar dewa gais hai.",
        "revertpage-nouser": "Reverted edits by a hidden user to last revision by {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Reverted edits by {{GENDER:$3|$1}};\nchanged back to last revision by {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "$1 ke badlao ke pahile jaise kar dewa gais hai;\nbadlao ke $2 ke aakhri version kar dewa gais hai.[$3 Show changes]",
        "sessionfailure-title": "Session fail hoe gais hae",
        "sessionfailure": "Aap ke login session me kuch karrbarr hai.\niske cancel kar dewa gais hai jisse ki koi iisession ke hijack nai kar.\nMeharbani kar ke  \"back\" ke press kar ke jon pana se aap aae rahaa ke fir se load karo, tab fir kosis karo.",
        "changecontentmodel": "Panna ke content model ke badlo",
        "allmessagesdefault": "Default text",
        "allmessagescurrent": "Abhi ke text",
        "allmessagestext": "Ii ek system sandes ke suchi hai jon ki MediaWiki namespace me pawa jaae sake hai.\nAgar aap generic MediaWiki localisation ke yogdaan de mangtaa hai tab meharbani kar ke [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] aur [https://translatewiki.net translatewiki.net]  pe jao.",
-       "allmessagesnotsupportedDB": "Ii panna ke kaam me nai lawa jaae sake hai kahe ki '''$wgUseDatabaseMessages''' ke band kar dewa gais hai.",
+       "allmessages-not-supported-database": "Ii panna ke kaam me nai lawa jaae sake hai kahe ki '''$wgUseDatabaseMessages''' ke band kar dewa gais hai.",
        "allmessages-filter-legend": "Chaalo",
        "allmessages-filter": "Customisation state se chhaano",
        "allmessages-filter-unmodified": "Badlawa nai gais hae",
index 42210b9..b325872 100644 (file)
        "minoreditletter": "m",
        "newpageletter": "B",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 ginabantayan {{PLURAL:$1|naga-usar|mga naga-usar}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|mga byte}} pagkatapos sang pag-ilis",
        "newsectionsummary": "/* $1 */ bag-o nga seksyon",
        "rc-enhanced-expand": "Ipakita ang mga detalye",
index c585e50..c5718b9 100644 (file)
@@ -87,6 +87,7 @@
        "tog-norollbackdiff": "Izostavi razliku nakon vraćanja",
        "tog-useeditwarning": "Upozori me kad napuštam stranicu za uređivanje bez spremanja izmjena",
        "tog-prefershttps": "Uvijek koristi sigurnu vezu kod prijave",
+       "tog-showrollbackconfirmation": "Prikaži odzivnu poruku za potvrđivanje škljocaja na poveznicu za brzo uklanjanje",
        "underline-always": "Uvijek",
        "underline-never": "Nikad",
        "underline-default": "Prema postavkama preglednika",
        "help": "Pomoć",
        "help-mediawiki": "Pomoć o MediaWikiju",
        "search": "Traži",
+       "search-ignored-headings": " #<!-- ne mijenjajte ništa u ovom retku --> <pre>\n# Zaglavlja koja će biti zanemarena pri pretrazi.\n# Izmjene koje ovdje načinite stupit će na snagu čim se stranica sa zaglavljem indeksira.\n# Možete forsirati da se stranica indeksira tako što ćete izvršiti prazno uređivanje.\n# Sintaksa je sljedeća:\n#   * Sve od znaka \"#\" pa do kraja retka je komentar.\n#   * Svaki redak koji nije prazan jest točan naziv koji će biti zanemaren, s tim da se razlikuju mala i velika slova i sve ostalo.\nIzvori\nVanjske poveznice\nVidi i\n #</pre> <!-- ne mijenjajte ništa u ovom retku -->",
        "searchbutton": "Traži",
        "go": "Kreni",
        "searcharticle": "Kreni",
        "pool-timeout": "Istek vremena (''timeout'') čekajući zaključavanje",
        "pool-queuefull": "Red čekanja je pun",
        "pool-errorunknown": "Nepoznata pogrješka",
+       "pool-servererror": "Usluga brojača redaka nije dostupna ($1).",
        "poolcounter-usage-error": "Greška korištenja: $1",
        "aboutsite": "O projektu {{SITENAME}}",
        "aboutpage": "Project:O_projektu_{{SITENAME}}",
        "badarticleerror": "Ovu radnju nije moguće izvesti s tom stranicom.",
        "cannotdelete": "Ne može se obrisati stranica ili datoteka \"$1\".\nMoguće je da ju je netko drugi već obrisao.",
        "cannotdelete-title": "Brisanje stranice \"$1\" nije moguće",
+       "delete-scheduled": "Stranica »$1« predviđena je za brisanje.\nMolimo Vas, budite strpljivi.",
        "delete-hook-aborted": "Brisanje prekinuto softverskim priključkom (hook).\nNema obrazloženja ili poruke o pogrješci.",
        "no-null-revision": "Ne mogu stvoriti praznu izmjenu stranice \"$1\"",
        "badtitle": "Loš naslov",
        "title-invalid-talk-namespace": "Traženi naziv stranice odnosi se na stranicu rasprave koja ne može postojati.",
        "title-invalid-characters": "Traženi naslov stranice sadrži znakove koji nisu valjani: »$1«.",
        "title-invalid-relative": "Naslov ima relativan put. Relativni putovi u naslovu su nevažeći, jer ih web pretraživač često ne može doseći.",
+       "title-invalid-magic-tilde": "Traženi naslov stranice sadrži nevrijedeću nizanicu čarobnih znakova ‒ tildi (<nowiki>~~~</nowiki>).",
        "title-invalid-too-long": "Naslov stranice je predugačak. Naslov ne smije biti duži od $1 {{PLURAL:$1|bajt|bajtova}} u UTF-8 kodiranju.",
+       "title-invalid-leading-colon": "Traženi naslov stranice sadrži nevrijedeće dvotočje na početku.",
        "perfcached": "Sljedeći podaci su iz međuspremnika i možda nisu najsvježiji. Međuspremnik sadrži $1 {{PLURAL:$1|rezultat|rezultata}} pretraživanja.",
        "perfcachedts": "Sljedeći podaci su iz međuspremnika i posljednji puta su ažurirani u $1. Međuspremnik sadrži $4 {{PLURAL:$4|rezultat|rezultata}} pretraživanja.",
        "querypage-no-updates": "Osvježavanje ove stranice je trenutačno onemogućeno. Nove promjene neće biti vidljive.",
        "customcssprotected": "Ne možete uređivati ovu CSS stranicu zato što ona sadrži osobne postavke drugog suradnika.",
        "customjsonprotected": "Ne možete uređivati ovu JSON stranicu zato što ona sadrži osobne postavke drugog suradnika.",
        "customjsprotected": "Ne možete uređivati ovu JavaScript stranicu zato što ona sadrži osobne postavke drugog suradnika.",
+       "sitecssprotected": "Nemate dopuštenje za mijenjanje ove stranice CSS-a jer to može utjecati na sve posjetitelje.",
+       "sitejsonprotected": "Nemate dopuštenje za mijenjanje ove stranice JSON-a jer to može utjecati na sve posjetitelje.",
+       "sitejsprotected": "Nemate dopuštenje za mijenjanje ove stranice JavaScripta jer to može utjecati na sve posjetitelje.",
        "mycustomcssprotected": "Nemate ovlasti za uređivanje ove CSS stranice.",
        "mycustomjsonprotected": "Nemate ovlasti za uređivanje ove JSON stranice.",
        "mycustomjsprotected": "Nemate ovlasti za uređivanje ove JavaScript stranice.",
        "ns-specialprotected": "Stranice u imenskom prostoru ''{{ns:special}}'' ne mogu se uređivati.",
        "titleprotected": "Ovaj naslov je od kreiranja zaštitio suradnik [[User:$1|$1]], uz razlog: <em>$2</em>.",
        "filereadonlyerror": "Ne mogu izmijeniti datoteku \"$1\" jer je spremište \"$2\" dostupno samo za čitanje.\n\nAdministrator koji je zaključao spremište naveo je sljedeći razlog: \"$3\".",
+       "invalidtitle": "Neispravan naslov",
        "invalidtitle-knownnamespace": "Neispravan naziv imenskog prostora \"$2\" i teksta \"$3\"",
        "invalidtitle-unknownnamespace": "Neispravan naziv imenskog prostora broj $1 i teksta \"$2\"",
        "exception-nologin": "Niste prijavljeni",
        "createacct-reason": "Razlog",
        "createacct-reason-ph": "Zašto stvarate još jedan račun?",
        "createacct-reason-help": "Poruka koja se prikazuje u evidenciji stvaranja suradničkih računa",
-       "createacct-submit": "Stvorite svoj suradnički račun",
+       "createacct-submit": "Stvori svoj suradnički račun",
        "createacct-another-submit": "Otvori račun",
        "createacct-continue-submit": "Pritisni za stvaranje računa",
        "createacct-another-continue-submit": "Nastavi za stvaranje računa",
        "badretype": "Unesene zaporke nisu istovjetne.",
        "usernameinprogress": "Stvaranje računa za ovo suradničko ime upravo je u tijeku.\nMolimo, pričekajte.",
        "userexists": "Uneseno suradničko ime već je u upotrebi.\nUnesite neko drugo ime.",
+       "createacct-normalization": "Vaše će suradničko ime biti prilagođeno na »$2« zbog tehničkih ograničenja.",
        "loginerror": "Pogrješka u prijavi",
        "createacct-error": "Pogrješka u stvaranju računa",
        "createaccounterror": "Ne može se stvoriti račun: $1",
        "nocookiesnew": "Suradnički račun je otvoren, ali niste uspješno prijavljeni. Naime, {{SITENAME}} koristi kolačiće (''cookies'') u procesu prijave. Isključili ste kolačiće. Molim uključite ih i pokušajte ponovo s Vašim novim imenom i lozinkom.",
        "nocookieslogin": "{{SITENAME}} koristi kolačiće (''cookies'') u procesu prijave. Isključili ste kolačiće. Molim uključite ih i pokušajte ponovo.",
        "nocookiesfornew": "Suradnički račun nije napravljen, jer nismo mogli potvrditi njegov izvor.\nProvjerite jesu li kolačići (''cookies'') omogućeni, ponovo učitajte ovu stranicu i pokušajte opet.",
+       "createacct-loginerror": "Račun je uspješno stvoren, ali Vas nije bilo moguće automatski prijaviti. Molimo Vas, nastavite s [[Special:UserLogin|ručnim prijavljivanjem]].",
        "noname": "Niste unijeli valjano suradničko ime.",
        "loginsuccesstitle": "Prijava uspješna",
        "loginsuccess": "Prijavili ste se na wiki kao \"$1\".",
        "changepassword-success": "Zaporka je uspješno postavljena!",
        "changepassword-throttled": "Nedavno ste se previše puta pokušali prijaviti.\nMolimo Vas pričekajte $1 prije nego što pokušate ponovno.",
        "botpasswords": "Zaporke botova",
+       "botpasswords-summary": "<em>Zaporke botova</em> omogućuju pristup suradničkom računu preko API-ja bez da se koriste podatci o prijavi glavnoga računa. Dostupna suradnička prava mogla bi biti ograničena kada se prijavite na ovaj način.\n\nAko ne znate kako bi Vam ovo poslužilo, vjerojatno to ne biste trebali raditi. Nitko nikada ne treba od Vas tražiti da napravite ovakve zaporke i da mu ih date.",
        "botpasswords-disabled": "Zaporke botova su onemogućene.",
        "botpasswords-no-central-id": "Za uporabu zaporki botova, morate biti prijavljeni na središnji račun.",
        "botpasswords-existing": "Postojeće zaporke botova",
        "botpasswords-createnew": "Stvorite novu zaporku bota",
        "botpasswords-editexisting": "Uredite postojeću zaporku bota",
+       "botpasswords-label-needsreset": "(zaporku treba ponovo postaviti)",
        "botpasswords-label-appid": "Ime bota:",
        "botpasswords-label-create": "Stvori",
        "botpasswords-label-update": "Ažuriraj",
        "botpasswords-label-delete": "Izbriši",
        "botpasswords-label-resetpassword": "Ponovno postavljanje lozinke",
        "botpasswords-label-grants": "Primjenjive dozvole:",
-       "botpasswords-help-grants": "Svaka dozvola daje pristup navedenim suradničkim pravima koja su već dodjeljena suradničkom računu. Vidjeti [[Special:ListGrants|tablicu dozvola]] za više informacija.",
+       "botpasswords-help-grants": "Dozvole omogućavaju pristup suradničkim pravima koja su već dodijeljena suradničkom računu. Omogućavanjem dozvola ovdje ne daje se pristup svim pravima koja Vaš suradnički račun inače ne bi imao. Za više informacija vidite [[Special:ListGrants|popis dozvola]].",
        "botpasswords-label-grants-column": "Odobreno",
        "botpasswords-bad-appid": "Ime bota \"$1\" nije valjano.",
        "botpasswords-insert-failed": "Nije moguće dodavanje imena bota \"$1\". Možda je već dodano?",
        "botpasswords-update-failed": "Nije moguće ažurirati bot s imenom \"$1\". Možda je izbrisan?",
        "botpasswords-created-title": "Stvorena bot zaporka",
+       "botpasswords-created-body": "Zaporka za bota imena »$1« {{GENDER:$2|suradnika|suradnice}} »$2« stvorena je.",
        "botpasswords-updated-title": "Zaporka za Vašeg bota obnovljena je",
        "botpasswords-updated-body": "Zaporka za bota imena »$1« {{GENDER:$2|suradnika|suradnice}} »$2« obnovljena je.",
        "botpasswords-deleted-title": "Zaporka je za Vašeg bota uklonjena",
        "passwordreset-domain": "Domena:",
        "passwordreset-email": "E-mail adresa:",
        "passwordreset-emailtitle": "Pojedinosti o računu na {{SITENAME}}",
-       "passwordreset-emailtext-ip": "Netko (vjerojatno Vi, s IP adrese $1) zatražio je podsjetnik za Vaše detalje računa\nza {{SITENAME}} ($4). Sljedeći {{PLURAL:$3|račun suradnika je|računi suradnika su}}\npovezani s ovom e-mail adresom:\n\n$2\n\n{{PLURAL:$3|Ova privremena zaporka|Ove privremene zaporke}} će isteći u {{PLURAL:$5|jedan dan|$5 dana}}.\nTrebate se prijaviti i odabrati novu zaporku. Ukoliko je netko drugi napravio ovaj\nzahtjev, ili ako ste se sjetili Vaše izvorne zaporke, a više je ne želite promijeniti, \nmožete zanemariti ovu poruku i nastavite koristiti staru zaporku.",
-       "passwordreset-emailtext-user": "Suradnik $1 na {{SITENAME}} zatražio je podsjetnik o pojedinostima vašeg računa za {{SITENAME}}\n($4). Sljedeći {{PLURAL:$3|račun suradnika je|računi suradnika su}} povezani s ovom e-mail adresom:\n\n$2\n\n{{PLURAL:$3|Ova privremena zaporka|Ove privremene zaporke}} će isteći u {{PLURAL:$5|jedan dan|$5 dana}}.\nTrebate se prijaviti i odabrati novu zaporku. Ukoliko je netko drugi napravio ovaj\nzahtjev, ili ako ste se sjetili Vaše izvorne zaporke, a više je ne želite promijeniti, \nmožete zanemariti ovu poruku i nastavite koristiti staru zaporku.",
+       "passwordreset-emailtext-ip": "Netko (vjerojatno Vi, s IP adrese $1) zatražio je podsjetnik za Vaše detalje računa\nza {{SITENAME}} ($4). Sljedeći {{PLURAL:$3|račun suradnika je|računi suradnika su}}\npovezani s ovom e-mail adresom:\n\n$2\n\n{{PLURAL:$3|Ova privremena zaporka|Ove privremene zaporke}} će isteći za {{PLURAL:$5|jedan dan|$5 dana}}.\nTrebate se prijaviti i odabrati novu zaporku. Ukoliko je netko drugi napravio ovaj\nzahtjev, ili ako ste se sjetili Vaše izvorne zaporke, a više je ne želite promijeniti, \nmožete zanemariti ovu poruku i nastavite koristiti staru zaporku.",
+       "passwordreset-emailtext-user": "Suradnik $1 na {{SITENAME}} zatražio je podsjetnik o pojedinostima vašeg računa za {{SITENAME}}\n($4). Sljedeći {{PLURAL:$3|račun suradnika je|računi suradnika su}} povezani s ovom e-mail adresom:\n\n$2\n\n{{PLURAL:$3|Ova privremena zaporka|Ove privremene zaporke}} će isteći za {{PLURAL:$5|jedan dan|$5 dana}}.\nTrebate se prijaviti i odabrati novu zaporku. Ukoliko je netko drugi napravio ovaj\nzahtjev, ili ako ste se sjetili Vaše izvorne zaporke, a više je ne želite promijeniti, \nmožete zanemariti ovu poruku i nastavite koristiti staru zaporku.",
        "passwordreset-emailelement": "Suradničko ime: \n$1\n\nPrivremena zaporka: \n$2",
        "passwordreset-emailsentemail": "Ako je ova adresa povezana s Vašim suradničkim računom, na nju će biti poslan podsjetnik na zaporku.",
        "passwordreset-emailsentusername": "Ukoliko je ova adresa povezana s Vašim suradničkim računom, na istu će biti poslan podsjetnik sa zaporkom.",
        "showpreview": "Prikaži kako će izgledati",
        "showdiff": "Prikaži promjene",
        "blankarticle": "<strong>Upozorenje:</strong> Stvorili ste stranicu koja je prazna.\nAko iznova pritisnete na \"$1\", stranica će biti stvorena bez ikakvog sadržaja.",
-       "anoneditwarning": "<strong>Upozorenje:</strong> niste prijavljeni. Ako napravite uređivanje, Vaša IP adresa će biti javno vidljiva. Ako se <strong>[$1 prijavite]</strong> ili <strong>[$2 stvorite račun]</strong>, Vaša uređivanja će biti pridružena suradničkom imenu, zajedno s ostalim pogodnostima.",
+       "anoneditwarning": "<strong>Upozorenje:</strong> niste prijavljeni. Ako napravite uređivanje, Vaša IP adresa bit će javno vidljiva. Ako se <strong>[$1 prijavite]</strong> ili <strong>[$2 stvorite račun]</strong>, Vaša će uređivanja biti pripisana Vašem suradničkom imenu, zajedno s ostalim pogodnostima.",
        "anonpreviewwarning": "<em>Niste prijavljeni. Spremanjem izmjena Vaša će IP adresa ostati zabilježena u povijesti uređivanja ove stranice.</em>",
        "missingsummary": "'''Podsjetnik:''' Niste unijeli sažetak promjena. Ako ponovno kliknete na \"Sačuvaj stranicu\", Vaše će promjene biti snimljene bez sažetka.",
        "selfredirect": "<strong>Upozorenje:</strong> Stvarate preusmjeravanje na isti članak.\nMožda ste izabrali pogrješnu odredišnu stranicu za preusmjeravanje ili uređujete pogrješnu stranicu.\nAko pritisnete na \"$1\" još jednom, preusmjeravanje će svejedno biti stvoreno.",
        "page_first": "prva",
        "page_last": "zadnja",
        "histlegend": "Izbor za usporedbu: označi kružiće pokraj dvije inačice koje želiš usporediti i pritisni \"Enter\" ili tipku na dnu.<br />\nUputa: <strong>({{int:cur}})</strong> = razlika od trenutačne inačice, <strong>({{int:last}})</strong> = razlika od prethodne inačice, <strong>{{int:minoreditletter}}</strong> = manja promjena.",
-       "history-fieldset-title": "Pretraži izmjene",
+       "history-fieldset-title": "Filtriranje inačica",
        "history-show-deleted": "Samo izbrisane izmjene",
        "histfirst": "najstarije",
        "histlast": "najnovije",
        "historysize": "({{PLURAL:$1|$1 bajt|$1 bajta|$1 bajtova}})",
-       "historyempty": "(prazna stranica)",
+       "historyempty": "prazno",
        "history-feed-title": "Povijest promjena",
        "history-feed-description": "Povijest promjena ove stranice na wikiju",
        "history-feed-item-nocomment": "$1 u (test) $2",
        "logdelete-selected": "{{PLURAL:$1|Odabrani zapis u evidenciji|Odabrani zapisi u evidenciji}}:",
        "revdelete-text-text": "Izbrisane izmjene će i dalje biti vidljive u povijesti stranice, ali dijelovi sadržaja neće biti javno vidljivi.",
        "revdelete-text-file": "Izbrisane inačice datoteke će i dalje biti vidljive u povijesti datoteke, ali neki dijelovi sadržaja neće biti javno vidljivi.",
-       "logdelete-text": "Izbrisane izmjene i dalje će biti vidljive u evidencijama, ali dijelovi njihova sadržaja biti će nedostupni za javnost.",
+       "logdelete-text": "Izbrisane evidencijske radnje i dalje će se pojavljivati u evidencijama, ali dijelovi njihova sadržaja bit će nedostupni za javnost.",
        "revdelete-text-others": "Ostali administratori na projektu moći će pristupiti izbrisanom sadržaju i vratiti ga, osim ako nisu postavljena dodatna ograničenja.",
        "revdelete-confirm": "Molimo potvrdite da namjeravate ovo učiniti, da razumijete posljedice i da to činite u skladu s [[{{MediaWiki:Policy-url}}|pravilima]].",
        "revdelete-suppress-text": "Sklanjanje uređivanja treba raditi <strong>iznimno</strong> u sljedećih par slučajeva:\n* moguće klevetničke informacije\n* neprikladne osobne informacije \n*: <em>kućna adresa i broj telefona, JMBG ili OIB, itd.</em>",
        "recentchangescount": "Zadani broj izmjena koje se prikazuju u nedavnim promjenama, povijesti stranica i u evidencijama:",
        "prefs-help-recentchangescount": "Najveći broj: 1000",
        "prefs-help-watchlist-token2": "Ovo je tajni ključ prema sažetku Vašeg popisa praćenja. \nSvaki suradnik kojem je poznat, moći će čitati Vaš popis praćenih stranica. Ne dijelite ga ni s kim.\nAko je potrebno možete ga [[Special:ResetTokens|ponovo postaviti]].",
+       "prefs-help-tokenmanagement": "Možete vidjeti te ponovo zadati tajni ključ za svoj račun kojim možete pristupiti svemrežnom izvodu Vašega popisa praćenja. Svatko tko zna ključ moći će čitati Vaš popis praćenja, stoga ga nemojte dijeliti.",
        "savedprefs": "Vaše postavke su sačuvane.",
        "savedrights": "Suradnička su prava {{GENDER:$1|suradnika $1|suradnice $1}} spremljena.",
        "timezonelegend": "Vremenska zona:",
        "prefs-help-gender": "Postavljanje ove mogućnosti je opcionalno.\nProgramska oprema koristi danu vrijednost kako bi Vam se obratila i spomenula Vas drugima rabeći odgovarajući gramatički rod.\nOvaj podatak bit će javno dostupan.",
        "email": "Adresa elektroničke pošte *",
        "prefs-help-realname": "Pravo ime nije obvezno. Ako ga navedete, može biti rabljeno za pripisivanje Vaših doprinosa.",
-       "prefs-help-email": "E-mail adresa nije obvezna, ali je potrebna za obnovu lozinke u slučaju da ju zaboravite.",
-       "prefs-help-email-others": "Također možete odabrati da vas ostali kontaktiraju preko vaše suradničke ili stranice za razgovor bez javnog otkrivanja vašeg identiteta.",
+       "prefs-help-email": "Adresa e-pošte nije obvezna, ali je potrebna u slučaju ponovnih postavljanja zaporke, ako zaboravite Vašu zaporku.",
+       "prefs-help-email-others": "Također možete dopustiti drugima da Vas kontaktiraju preko poveznice na lijevoj strani Vaše stranice odnosno stranice za razgovor.\nVaša adresa e-pošte ne će biti prikazana drugim suradnicima koji Vas kontaktiraju.",
        "prefs-help-email-required": "Potrebno je navesti adresu e-pošte (e-mail).",
        "prefs-info": "Osnovni podatci",
        "prefs-i18n": "Internacionalizacija",
        "right-move-rootuserpages": "Premještanje osnovne stranice suradnika",
        "right-move-categorypages": "Premještanje kategorizacijskih stranica",
        "right-movefile": "Premještanje datoteka",
-       "right-suppressredirect": "Ne raditi preusmjeravanje od starog imena prilikom premještanja stranice",
+       "right-suppressredirect": "Ne stvaranje preusmjeravanja od izvornih stranica prilikom premještanja stranica",
        "right-upload": "Postavljanje datoteka",
        "right-reupload": "Postavljanje nove inačice datoteke",
        "right-reupload-own": "Postavljanje nove inačice vlastite datoteke",
        "right-reupload-shared": "Lokalno postavljanje novih inačica datoteka na zajedničkom poslužitelju",
        "right-upload_by_url": "Postavljanje datoteke s URL adrese",
-       "right-purge": "Čišćenje priručne memorije stranice bez stranice za potvrdu",
+       "right-purge": "Brisanje međuspremnika stranice",
        "right-autoconfirmed": "Uređivanje stranica zaštićenih za neprijavljene suradnike",
        "right-bot": "Izmjene su tretirane kao automatski proces (bot)",
        "right-nominornewtalk": "Izbjegavanje prikazivanja obavijesti o novim porukama kad je označeno da je izmjena manja",
        "grant-editpage": "Uređivanje postojećih stranica",
        "grant-editprotected": "Uređivanje zaštićenih stranica",
        "grant-highvolume": "Uređivanja velikog opsega",
+       "grant-patrol": "Ophodnja izmjena stranica",
        "grant-rollback": "Brzo uklanjanje izmjena stranica",
        "grant-sendemail": "Slanje e-poruka drugim suradnicima",
        "grant-uploadeditmovefile": "Postavljanje, zamjena i premještanje datoteka",
        "action-viewmyprivateinfo": "pregled Vaših privatnih podataka",
        "action-editmyprivateinfo": "uredite svoje privatne podatke",
        "action-purge": "osvježite priručnu memoriju ove stranice",
+       "action-markbotedits": "označavanje izmjena uklonjenih brzim uklanjanjem kao botovskih uređivanja",
+       "action-patrolmarks": "pregled oznaka ophođenja na nedavnim promjenama",
+       "action-override-export-depth": "izvoz stranica uključujući povezane stranice do dubine od 5 stranica",
+       "action-suppressredirect": "ne stvaranje preusmjeravanja s izvornih stranica pri premještanju stranica",
        "nchanges": "{{PLURAL:$1|$1 promjena|$1 promjene|$1 promjena}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|uređivanje od Vašeg posljednjeg posjeta|uređivanja od Vašeg posljednjeg posjeta}}",
        "enhancedrc-history": "povijest",
        "rcfilters-savedqueries-add-new-title": "Spremi trenutačne postavke filtra",
        "rcfilters-restore-default-filters": "Vrati zadane filtre",
        "rcfilters-clear-all-filters": "Očisti sve filtre",
-       "rcfilters-show-new-changes": "Vidi najnovije izmjene",
+       "rcfilters-show-new-changes": "Vidi najnovije promjene nakon $1",
        "rcfilters-search-placeholder": "Filtriraj promjene (rabite izbornik ili potražite ime filtra)",
        "rcfilters-invalid-filter": "Filter nije valjan",
        "rcfilters-empty-filter": "Nema aktivnih filtara. Prikazani su svi doprinosi.",
        "rcfilters-filter-editsbyself-description": "Vaša uređivanja.",
        "rcfilters-filter-editsbyother-label": "Promjene drugih suradnika",
        "rcfilters-filter-editsbyother-description": "Sve promjene osim Vaših.",
-       "rcfilters-filtergroup-userExpLevel": "Suradnička registracija i iskustvo",
+       "rcfilters-filtergroup-user-experience-level": "Suradnička registracija i iskustvo",
        "rcfilters-filter-user-experience-level-registered-label": "Registrirani",
        "rcfilters-filter-user-experience-level-registered-description": "Prijavljeni suradnici.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Neregistrirani",
        "rcfilters-filter-humans-label": "Osoba (ne bot)",
        "rcfilters-filter-humans-description": "Uređivanja koja su napravili suradnici.",
        "rcfilters-filtergroup-reviewstatus": "Stanje pregledanja",
+       "rcfilters-filter-reviewstatus-unpatrolled-description": "Uređivanja koja nisu ručno ili automatski označena ophođenima.",
        "rcfilters-filter-reviewstatus-unpatrolled-label": "Neophođeno",
+       "rcfilters-filter-reviewstatus-manual-description": "Uređivanja koja su ručno označena ophođenima.",
+       "rcfilters-filter-reviewstatus-manual-label": "Ručno ophođeno",
+       "rcfilters-filter-reviewstatus-auto-description": "Uređivanja suradnika s pravima, čiji je rad automatski označen ophođenim.",
+       "rcfilters-filter-reviewstatus-auto-label": "Autoophođenni",
        "rcfilters-filtergroup-significance": "Važnost",
        "rcfilters-filter-minor-label": "Manja uređivanja",
        "rcfilters-filter-minor-description": "Uređivanja koja je suradnik označio manjim.",
        "rcfilters-filter-watchlist-notwatched-description": "Sve izmjene na stranicama osim onih na popisu praćenja.",
        "rcfilters-filtergroup-watchlistactivity": "Aktivnost na popisu praćenja",
        "rcfilters-filter-watchlistactivity-unseen-label": "Nepregledane izmjene",
+       "rcfilters-filter-watchlistactivity-unseen-description": "Promjene na stranicama koje niste posjetili otkad su se promjene dogodile.",
        "rcfilters-filter-watchlistactivity-seen-label": "Pregledane izmjene",
        "rcfilters-filter-watchlistactivity-seen-description": "Izmjene na stranicama koje ste posjetili otkako su načinjene.",
        "rcfilters-filtergroup-changetype": "Vrste promjena",
        "rcfilters-filter-categorization-description": "Uređivanja kojima se dodaju ili uklanjanju stranice iz kategorija.",
        "rcfilters-filter-logactions-label": "Radnje zabilježene u evidencijama",
        "rcfilters-filter-logactions-description": "Administrativne radnje, stvaranja računa, brisanje stranica, postavljanja datoteka...",
-       "rcfilters-filtergroup-lastRevision": "Najnovija uređivanja",
+       "rcfilters-filtergroup-lastrevision": "Najnovija uređivanja",
        "rcfilters-filter-lastrevision-label": "Najnovija izmjena",
        "rcfilters-filter-lastrevision-description": "Samo najnovija izmjena na pojedinoj stranici.",
        "rcfilters-filter-previousrevision-label": "Nije najnovija izmjena",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|suradnik|suradnika|suradnika}} prati ovu stranicu]",
        "rc-change-size-new": "$1 {{PLURAL:$1|bajt|bajta|bajtova}} poslije uređivanja",
        "newsectionsummary": "/* $1 */ novi odlomak",
        "rc-enhanced-expand": "Pokaži detalje (potreban JavaScript)",
        "img-auth-nopathinfo": "Nedostaje informacija o putanji.\nVaš poslužitelj mora biti postavljen tako da prosljeđuje varijable REQUEST_URI i/ili PATH_INFO.\nAko je tako, probajte omogućiti $wgUsePathInfo.\n[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization?uselang=hr Pogledajte stranicu o autorizaciji slika]",
        "img-auth-notindir": "Zahtjevana putanja nije u direktoriju podešenom za postavljanje.",
        "img-auth-badtitle": "Ne mogu stvoriti valjani naslov iz \"$1\".",
-       "img-auth-nologinnWL": "Niste prijavljeni i \"$1\" nije na popisu dozvoljenih.",
        "img-auth-nofile": "Datoteka \"$1\" ne postoji.",
        "img-auth-isdir": "Pokušavate pristupiti direktoriju \"$1\".\nDozvoljen je samo pristup datotekama.",
        "img-auth-streaming": "Tok \"$1\".",
        "nolicense": "Ništa nije odabrano",
        "licenses-edit": "Uredi izbor licencija",
        "license-nopreview": "(Prikaz nije moguć)",
-       "upload_source_url": " (izabrali ste datoteku s valjanog, javno dostupnog URL-a)",
-       "upload_source_file": "(izabrali ste datoteku s Vašeg računala)",
+       "upload_source_url": "(izabrana datoteka s valjanog, javno dostupnog URL-a)",
+       "upload_source_file": "(izabrana datoteka s Vašeg računala)",
        "listfiles-delete": "izbriši",
        "listfiles-summary": "Ova stranica pokazuje sve postavljene datoteke.\nKad je filtriran po suradniku, popis prikazuje samo one datoteke čije je posljednje inačice postavio taj suradnik.",
        "listfiles_search_for": "Traži ime slike:",
        "delete-confirm": "Pobriši »$1«",
        "delete-legend": "Izbriši",
        "historywarning": "<strong>Upozorenje:</strong> stranica koju želite izbrisati ima starije izmjene s $1 {{PLURAL:$1|inačicom|inačice|inačica}}:",
-       "historyaction-submit": "Prikaži",
+       "historyaction-submit": "Prikaži inačice",
        "confirmdeletetext": "Zauvijek ćete izbrisati stranicu ili sliku zajedno s prijašnjim inačicama.\nMolim potvrdite svoju namjeru, da razumijete posljedice i da ovo radite u skladu s [[{{MediaWiki:Policy-url}}|pravilima]].",
        "actioncomplete": "Radnja je dovršena",
        "actionfailed": "Radnja nije uspjela",
        "deleting-backlinks-warning": "<strong>Upozorenje:</strong> \nbrišete stranicu koja je uključena u [[Special:WhatLinksHere/{{FULLPAGENAME}}|druge]] ili druge stranice povezuju na nju.",
        "deleting-subpages-warning": "<strong>Upozorenje:</strong> Stranica koju ste nakanili izbrisati ima [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|$1 podstranicu|$1 podstranice|$1 podstranica|51=preko 50 podstranica}}]].",
        "rollback": "Ukloni posljednju promjenu",
+       "rollback-confirmation-confirm": "Molimo Vas, potvrdite:",
+       "rollback-confirmation-yes": "ukloni",
+       "rollback-confirmation-no": "otkaži",
        "rollbacklink": "ukloni",
        "rollbacklinkcount": "ukloni $1 {{PLURAL:$1|uređivanje|uređivanja}}",
        "rollbacklinkcount-morethan": "ukloni više od $1 {{PLURAL:$1|uređivanje|uređivanja}}",
        "revertpage": "uklonjena promjena {{GENDER:$2|suradnika|suradnice}} [[Special:Contributions/$2|$2]] ([[User talk:$2|razgovor]]), vraćeno na posljednju inačicu {{GENDER:$1|suradnika|suradnice}} [[User:$1|$1]]",
        "revertpage-nouser": "Vraćene izmjene suradnika (suradničko ime uklonjeno) na posljednju inačicu suradnika [[User:$1|$1]]",
        "rollback-success": "Uklonjeno uređivanje {{GENDER:$3|suradnika|suradnice}} $1; vraćeno na posljednju inačicu {{GENDER:$4|suradnika|suradnice}} $2.",
-       "rollback-success-notify": "Uklonili ste izmjene suradnika $1;\nvraćeno na posljednju izmjenu suradnika $2. [$3 Prikaži izmjene]",
        "sessionfailure-title": "Prekid sesije",
        "sessionfailure": "Izgleda da postoji problem s Vašom prijavom; ta radnja otkazana je kao način sprječavanja zlouporabe. Molimo ponovno pošaljite obrazac.",
        "changecontentmodel": "Promjena modela sadržaja stranice",
        "mycontris": "Doprinosi",
        "anoncontribs": "Doprinosi",
        "contribsub2": "Za {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "Za {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "Suradnički račun \"$1\" nije registriran.",
+       "negative-namespace-not-supported": "Imenski prostori s negativnim vrijednostima nisu podržani.",
        "nocontribs": "Nema promjena koje udovoljavaju ovim kriterijima.",
        "uctop": "vrh",
        "month": "Od mjeseca (i ranije):",
        "sp-contributions-newonly": "Pokaži samo stranice koje je suradnik započeo",
        "sp-contributions-hideminor": "Sakrij manje izmjene",
        "sp-contributions-submit": "Traži",
+       "sp-contributions-outofrange": "Nije moguće pokazati rezultate. Traženi raspon IP adresa veći je od CIDR limita /$1.",
        "whatlinkshere": "Što vodi ovamo",
        "whatlinkshere-title": "Stranice koje vode na »$1«",
        "whatlinkshere-page": "Stranica:",
        "emailblock": "e-pošta je blokirana",
        "blocklist-nousertalk": "bez uređivanja vlastite stranice za razgovor",
        "ipblocklist-empty": "Popis blokiranja je prazan.",
-       "ipblocklist-no-results": "Tražena IP adresa ili suradničko ime nije blokirano.",
+       "ipblocklist-no-results": "Za traženu IP adresu ili suradničko ime nema pronađenih podudarnih blokiranja.",
        "blocklink": "blokiraj",
        "unblocklink": "deblokiraj",
        "change-blocklink": "promijeni blokiranje",
        "move-page-legend": "Premjesti stranicu",
        "movepagetext": "Uporabom ovog obrasca ćete preimenovati stranicu i premjestiti povijest uređivanja na novo ime.\nStari će naslov preusmjeravati na stranicu s novim imenom.\nMožete odabrati automatsko ažuriranje preusmjeravanja na izvorni naslov.\nAko se ne odlučite na to, provjerite [[Special:DoubleRedirects|dvostruka]] ili [[Special:BrokenRedirects|neispravna preusmjeravanja]].\nDužni ste provjeriti da sve poveznice i dalje nastave voditi na prave stranice.\n\nStranica se <strong>ne će</strong> premjestiti ako već postoji stranica s novim naslovom, osim u slučaju prazne stranice ili stranice za preusmjeravanje koja nema nikakvih starih izmjena.\nTo znači da možete preimenovati stranicu natrag odakle je preimenovana ako napravite grešku, ali ne možete prepisati preko postojeće stranice.\n\n<strong>Napomena:</strong>\novo može biti drastična i neočekivana promjena kad su u pitanju popularne stranice. Molimo dobro razmislite prije nego što preimenujete stranicu.",
        "movepagetext-noredirectfixer": "Pomoću donjeg obrasca ćete preimenovati stranicu i premjestiti sve stare izmjene na novo ime. \nStari će se naslov pretvoriti u stranicu koja automatski preusmjerava na novi naslov. \nBudite sigurni da ste provjerili [[Special:DoubleRedirects|dvostruka]] ili [[Special:BrokenRedirects|nevaljana preusmjeravanja]]. \nVi ste odgovorni za to da poveznice i dalje povezuju tamo gdje treba.\n\nImajte na umu da stranica <strong>ne će</strong> biti premještena ako već postoji stranica s novim naslovom, osim u slučaju stranice za preusmjeravanje koja nema nikakvih starih izmjena. \nTo znači da stranicu možete preimenovati u prethodno ime ako ste pogriješili te ne možete pisati preko postojeće stranice. \n\n<strong>Napomena:</strong>\nOvo može biti drastična i neočekivana promjena kad su u pitanju popularne stranice; \nbudite sigurni da razumijete posljedice ove akcije prije nastavka.",
-       "movepagetalktext": "Ako označite ovu kvačicu, pripadajuća stranica za razgovor biti će automatski premještena na novo ime osim ako već postoji stranica za razgovor koja nije prazna. \n\nU tom slučaju morat ćete ručno premjestiti ili spojiti stranice.",
+       "movepagetalktext": "Ako kvačicom označite ovu kućicu, pripadajuća stranica za razgovor bit će automatski premještena na novo ime, osim ako tamo već postoji stranica za razgovor koja nije prazna.\n\nU tom ćete slučaju morati ručno premjestiti ili spojiti stranice, ako to želite.",
        "moveuserpage-warning": "'''Upozorenje:''' Premještate suradničku stranicu. Imajte na umu da će stranica biti premještena, ali suradnik ''ne će'' biti preimenovan.",
        "movenologintext": "Ako želite premjestiti stranicu morate biti [[Special:UserLogin|prijavljeni]].",
        "movenotallowed": "Nemate pravo premještanja stranica.",
        "move-watch": "Prati ovu stranicu",
        "movepagebtn": "Premjesti stranicu",
        "pagemovedsub": "Premještanje uspjelo",
+       "cannotmove": "Stranica ne može biti premještena, zbog {{PLURAL:$1|sljedećeg razloga|sljedećih razloga}}:",
        "movepage-moved": "<strong>Stranica »$1« premještena je na »$2«</strong>.",
        "movepage-moved-redirect": "Načinjeno je preusmjeravanje.",
        "movepage-moved-noredirect": "Stvaranje preusmjeravanja bilo je izostavljeno.",
        "allmessagesdefault": "Prvotni tekst",
        "allmessagescurrent": "Trenutačni tekst",
        "allmessagestext": "Ovo je popis poruka sustava u imenskom prostoru MediaWiki. Molimo posjetite [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation lokalizaciju MediaWikija] i [https://translatewiki.net translatewiki.net] ako želite doprinijeti lokalizaciji MediaWiki softvera.",
-       "allmessagesnotsupportedDB": "Ova stranica ne može biti korištena jer je isključen parametar '''$wgUseDatabaseMessages'''.",
+       "allmessages-not-supported-database": "Ova stranica ne može biti korištena jer je isključen parametar '''$wgUseDatabaseMessages'''.",
        "allmessages-filter-legend": "Filtriraj",
        "allmessages-filter": "Filtriraj prema prilagođenom obliku:",
        "allmessages-filter-unmodified": "Nepreinačeno",
        "confirmemail_body": "Netko, vjerojatno Vi, s IP adrese $1 otvorio je\nsuradnički račun pod imenom \"$2\" s ovom adresom e-pošte na {{SITENAME}}.\n\nKako biste potvrdili da je ovaj suradnički račun uistinu Vaš i\nomogućili funkcije e-pošte na {{SITENAME}}, otvorite u Vašem\npregledniku sljedeću poveznicu:\n\n$3\n\nAko to *niste* Vi, slijedite ovu poveznicu za poništavanje potvrde:\n\n$5\n\nValjanost ovog potvrdnog kȏda istječe na $4.",
        "confirmemail_body_changed": "Netko, vjerojatno Vi, s IP adrese $1,\npromijenio je adresu e-pošte suradničkog računa \"$2\" u ovu adresu na {{SITENAME}}.\n\nKako biste potvrdili da je ovaj suradnički račun uistinu Vaš te uključili\nmogućnosti e-pošte na {{SITENAME}}, otvorite u Vašem pregledniku sljedeću poveznicu:\n\n$3\n\nUkoliko suradnički račun *ne* pripada Vama, slijedite ovu poveznicu\nza poništavanje potvrde adrese e-pošte:\n\n$5\n\nValjanost ovog potvrdnog koda istječe $4.",
        "confirmemail_body_set": "Netko, najvjerojatnije vi, s IP adrese $1,\notvorio je suradnički račun pod imenom \"$2\" s ovom adresom e-pošte na {{SITENAME}}.\n\nKako biste potvrdili da je ovaj suradnički račun uistinu vaš i uključili \nmogućnosti e-poruka na {{SITENAME}}, otvorite u vašem pregledniku sljedeću poveznicu:\n\n$3\n\nAko ovaj suradnički račun *ne* pripada vama, slijedite ovaj link \nkako biste poništili potvrdu adrese elektroničke pošte:\n\n$5\n\nValjanost ovog potvrdnog kȏda istječe u $4",
-       "confirmemail_invalidated": "Potvrda E-mail adrese je otkazana",
+       "confirmemail_invalidated": "Potvrda adrese e-pošte je otkazana",
        "invalidateemail": "Poništi potvrđivanje elektroničke pošte",
        "notificationemail_subject_changed": "Registrirana adresa e-pošte na projektu {{SITENAME}} je promijenjena",
        "notificationemail_subject_removed": "Registrirana adresa e-pošte na projektu {{SITENAME}} je uklonjena",
        "redirect-page": "ID stranice",
        "redirect-revision": "Inačica stranice",
        "redirect-file": "Datotečno ime",
+       "redirect-not-exists": "Vrijednost nije pronađena",
        "fileduplicatesearch": "Traži kopije datoteka",
        "fileduplicatesearch-summary": "Traži kopije datoteka na temelju njihove hash vrijednosti.",
        "fileduplicatesearch-filename": "Ime datoteke:",
        "feedback-back": "Natrag",
        "feedback-bugcheck": "Izvrsno! Molimo provjerite da se ne radi o nekom [$1 poznatom \"bugu\"].",
        "feedback-bugnew": "Provjereno. Prijavi novi \"bug\"",
-       "feedback-bugornote": "Ako ste spremni detaljno opisati tehnički problem molimo [$1 prijavite \"bug\"].\nInače, možete ispuniti jednostavan obrazac u nastavku. Vaš komentar biti će dodan na stranicu \"[$3 $2]\", zajedno s vašim suradničkim imenom i imenom internetskog preglednika koji rabite.",
+       "feedback-bugornote": "Ako ste spremni detaljno opisati tehnički problem molimo [$1 prijavite \"bug\"].\nInače, možete ispuniti jednostavan obrazac u nastavku. Vaš komentar bit će dodan na stranicu \"[$3 $2]\", zajedno s Vašim suradničkim imenom i imenom internetskoga preglednika koji rabite.",
        "feedback-cancel": "Odustani",
        "feedback-close": "Riješeno",
        "feedback-external-bug-report-button": "Arhiviraj tehnički zadatak",
        "limitreport-unstrip-size": "Veličina nakon proširenja unstrip",
        "limitreport-unstrip-size-value": "$1/$2 {{PLURAL:$2|bajt|bajta|bajtova}}",
        "expandtemplates": "Prikaz sadržaja predložaka",
-       "expand_templates_intro": "Ova posebna stranica omogućuje unos wikiteksta i prikazuje njegov rezultat,\nuključujući i (rekurzivno, tj. potpuno) sve uključene predloške u wikitekstu.\nPrikazuje i rezultate funkcija kao <nowiki>{{</nowiki>#language:...}} i varijabli\nkao <nowiki>{{</nowiki>CURRENTDAY}}. Funkcionira pozivanjem parsera same MedijeWiki.",
+       "expand_templates_intro": "Ova posebna stranica uzima wikitekst i proširuje sve predloške u njemu rekurzivno.\nOna također proširuje parserske funkcije poput\n<code><nowiki>{{</nowiki>#language:…}}</code> i varijable poput\n<code><nowiki>{{</nowiki>CURRENTDAY}}</code>. U principu, proširuje gotovo sve između dvostrukih vitičastih zagrada.",
        "expand_templates_title": "Kontekstni naslov stranice, za {{FULLPAGENAME}} i sl.:",
        "expand_templates_input": "Ulazni tekst:",
        "expand_templates_output": "Rezultat",
        "pagedata-bad-title": "Naslov nije valjan: $1.",
        "passwordpolicies": "Pravila za zaporke",
        "passwordpolicies-summary": "Ovo je popis pravila za zaporke za suradničke grupe definirane na ovom wikiju.",
+       "passwordpolicies-group": "Skupina",
+       "passwordpolicies-policies": "Pravila",
        "passwordpolicies-policy-minimalpasswordlength": "Zaporka mora sadržavati najmanje {{PLURAL:$1|1 znak|$1 znaka|$1 znakova}}",
        "passwordpolicies-policy-minimumpasswordlengthtologin": "Da biste se prijavili, zaporka mora sadržavati najmanje {{PLURAL:$1|1 znak|$1 znaka|$1 znakova}}",
        "passwordpolicies-policy-passwordcannotmatchusername": "Zaporka ne može biti ista kao i suradničko ime",
index 5c4d2b8..7d3988f 100644 (file)
        "minoreditletter": "K",
        "newpageletter": "N",
        "boteditletter": "B",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|beobachtender|beobachtende}} Benutzer]",
        "rc-change-size-new": "$1 {{PLURAL:$1|Byte|Bytes}} noh der Ännrung",
        "newsectionsummary": "Neier Abschnitt /* $1 */",
        "rc-enhanced-expand": "Einzelheite oonzeiche",
        "img-auth-nopathinfo": "Die Oongäb PATH_INFO fehlt.\nDer Server ist net dafoar ingerichtet, die Information weiterzugebe.\nSie könnt CGI-gestützt sin und kann dodrum \"img_auth\" (Authentifizierung von dem Dateiuffruf) net unnerstütze.\nSieh ooch https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization (englisch).",
        "img-auth-notindir": "Der gewünschte Paad ist net im konfigurierte Uploadverzeichnis.",
        "img-auth-badtitle": "Aus \"$1\" kann ken gülticher Titel erstellt sin.",
-       "img-auth-nologinnWL": "Du bist net oongemeldt und \"$1\" ist net in der weiss List.",
        "img-auth-nofile": "Datei \"$1\" existiert net.",
        "img-auth-isdir": "Du versuchst, uff en Verzeichnis \"$1\" zuzugreife.\nNuar Dateizugriff ist erlaubt.",
        "img-auth-streaming": "Loode \"$1\".",
        "allmessagesdefault": "Standardtext",
        "allmessagescurrent": "Aktueller Text",
        "allmessagestext": "Das ist en List von der MediaWiki-Systemtexte.\nBittschön besuch die Seite [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki-Lokalisierung] und [https://translatewiki.net translatewiki.net], soweit du dich an der Lokalisierung von MediaWiki beteiliche möchst.",
-       "allmessagesnotsupportedDB": "Die Spezialseit steht net zur Verfüchung, weil sie üwer den Parameter <tt>$wgUseDatabaseMessages</tt> deaktiviert woard.",
+       "allmessages-not-supported-database": "Die Spezialseit steht net zur Verfüchung, weil sie üwer den Parameter <tt>$wgUseDatabaseMessages</tt> deaktiviert woard.",
        "allmessages-filter-legend": "Filter",
        "allmessages-filter": "Filter für oongepasst Zustand:",
        "allmessages-filter-unmodified": "Unverännert",
index 5a38b4d..3cca0cb 100644 (file)
        "rcfilters-filter-newpages-label": "Wutworjenje stronow",
        "rcfilters-filter-newpages-description": "Změny, kotrež wutworja nowe strony.",
        "rcfilters-filter-categorization-label": "Kategorijowe změny",
-       "rcfilters-filtergroup-lastRevision": "Najnowše wersije",
+       "rcfilters-filtergroup-lastrevision": "Najnowše wersije",
        "rcfilters-filter-lastrevision-label": "Najnowša wersija",
        "rcnotefrom": "Deleka so {{PLURAL:$5|změna|změnje|změny}} wot <strong>$3, $4</strong> {{PLURAL:$5|pokazuje|pokazujetej|pokazuja}} (hač k <strong>$1</strong>).",
        "rclistfrom": "Jenož změny wot $3, $2 pokazać.",
        "minoreditletter": "S",
        "newpageletter": "N",
        "boteditletter": "B",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|wobkedźbowacy wužiwar|wobkedźbowacaj wužiwarjej|wobkedźbowacy wužiwarjo|wobkedźbowacych wužiwarjow}}]",
        "rc-change-size": "$1 {{PLURAL:$1|bajt|bajtaj|bajty|bajtow}}",
        "rc-change-size-new": "$1 {{PLURAL:$1|bajt|bajtaj|bajty|bajtow}} po změnje",
        "newsectionsummary": "Nowy wotrězk: /* $1 */",
        "img-auth-nopathinfo": "PATH_INFO faluje.\nTwój serwer njeje za to konfigurował, zo by tute informacije dale posrědkował.\nBy móhł na CGI bazować a ani njemóže img_auth podpěrać.\nHlej https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Požadana šćežka w konfigurowanym nahraćowym zapisu njeje.",
        "img-auth-badtitle": "Njeje móžno z \"$1\" płaćiwy titul tworić.",
-       "img-auth-nologinnWL": "Njejsy přizjewjeny a \"$1\" w běłej lisćinje njeje.",
        "img-auth-nofile": "Dataja \"$1\" njeeksistuje.",
        "img-auth-isdir": "Popsytuješ na zapis \"$1\" přistup měć.\nJenož datajowy přistup je dowoleny.",
        "img-auth-streaming": "\"$1\" so prudźi.",
        "allmessagesdefault": "Standardny tekst",
        "allmessagescurrent": "Aktualny tekst",
        "allmessagestext": "To je lisćina systemowych zdźělenkow, kotrež w mjenowym rumje MediaWiki k dispoziciji steja. Prošu wopytaj [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation lokalizaciju MediaWiki] a [https://translatewiki.net translatewiki.net], jeli chceš k powšitkownej lokalizaciji MediaWiki přinošować.",
-       "allmessagesnotsupportedDB": "Tuta strona njeda so wužiwać, dokelž '''$wgUseDatabaseMessages''' bu znjemóžnjeny.",
+       "allmessages-not-supported-database": "Tuta strona njeda so wužiwać, dokelž '''$wgUseDatabaseMessages''' bu znjemóžnjeny.",
        "allmessages-filter-legend": "Filter",
        "allmessages-filter": "Po přiměrjenskim stawje filtrować:",
        "allmessages-filter-unmodified": "Njezměnjeny",
        "tooltip-ca-nstab-category": "kategorijnu stronu wobhladać",
        "tooltip-minoredit": "jako snadnu změnu woznamjenić",
        "tooltip-save": "změny składować",
+       "tooltip-publish": "Twoje změny wozjewić",
        "tooltip-preview": "twoje změny přehladnyć, prošu čiń to do składowanja!",
        "tooltip-diff": "změny pokazać, kotrež sy w teksće činił",
        "tooltip-compareselectedversions": "rozdźěle mjez wubranymaj wersijomaj tuteje strony pokazać",
index 4915b7b..a45cdec 100644 (file)
@@ -98,6 +98,7 @@
        "tog-norollbackdiff": "Ne jelenjenek meg az eltérések visszaállítás után",
        "tog-useeditwarning": "Figyelmeztessen, ha szerkesztéskor a módosítások mentése nélkül akarom elhagyni a lapot",
        "tog-prefershttps": "Mindig biztonságos kapcsolatot használjon, amikor be vagyok jelentkezve",
+       "tog-showrollbackconfirmation": "Megerősítés kérése, amikor a visszaállítás linkre kattintasz",
        "underline-always": "mindig",
        "underline-never": "soha",
        "underline-default": "Felület és böngésző alapértelmezése szerint",
        "badretype": "A megadott jelszavak nem egyeznek.",
        "usernameinprogress": "Egy fiók létrehozása ezzel a névvel már folyamatban van.\nKérlek, várj.",
        "userexists": "A megadott felhasználónév már foglalt.\nKérlek, válassz másikat!",
+       "createacct-normalization": "A felhasználóneved a következőre fog változni technikai korlátozások miatt: „$2”.",
        "loginerror": "Hiba történt a bejelentkezés során",
        "createacct-error": "Fióklétrehozási hiba",
        "createaccounterror": "Nem sikerült létrehozni a felhasználói fiókot: $1",
        "page_first": "első",
        "page_last": "utolsó",
        "histlegend": "Eltérések kijelölése: jelöld ki az összehasonlítandó változatokat, majd nyomd meg az Enter billentyűt, vagy az alul lévő gombot.<br />\nJelmagyarázat: (akt) = eltérés az aktuális változattól, (előző) = eltérés az előző változattól, a = apró szerkesztés",
-       "history-fieldset-title": "Keresés a laptörténetben",
+       "history-fieldset-title": "Változatok szűrése",
        "history-show-deleted": "Csak a törölt változatok",
        "histfirst": "legelső",
        "histlast": "legutolsó",
        "historysize": "({{PLURAL:$1|egy|$1}} bájt)",
-       "historyempty": "(üres)",
+       "historyempty": "üres",
        "history-feed-title": "Laptörténet",
        "history-feed-description": "Az oldal laptörténete a wikiben",
        "history-feed-item-nocomment": "$1, $2-n",
        "right-reupload-own": "a saját maga által feltöltött fájlok felülírása",
        "right-reupload-shared": "felülírhatja a közös megosztóhelyen lévő fájlokat helyben",
        "right-upload_by_url": "fájl feltöltése URL-cím alapján",
-       "right-purge": "oldal gyorsítótárának ürítése megerősítés nélkül",
+       "right-purge": "oldal gyorsítótárának ürítése",
        "right-autoconfirmed": "Nem érinti az IP-alapú szerkesztéskorlátozás",
        "right-bot": "automatikus folyamatként való kezelés",
        "right-nominornewtalk": "felhasználói lapok apró szerkesztésével nem jelenik meg az új üzenet értesítés",
        "action-changetags": "egyedi változtatások és napló bejegyzések tetszőleges címkével való ellátása és törlése",
        "action-deletechangetags": "címkék törlése az adatbáziból",
        "action-purge": "oldal gyorsítótárának ürítése",
+       "action-apihighlimits": "nagyobb mennyiségű lekérdezés az API-n keresztül",
+       "action-autoconfirmed": "IP-alapú sebességkorlát figyelmen kívül hagyása",
+       "action-bigdelete": "nagy laptörténetű lapok törlése",
+       "action-blockemail": "szerkesztő e-mail küldési lehetőségének blokkolása",
+       "action-bot": "automatikus folyamatként való kezelés",
+       "action-editprotected": "„{{int:protect-level-sysop}}” védelmi szintű lapok szerkesztése",
+       "action-editsemiprotected": "„{{int:protect-level-autoconfirmed}}” védelmi szintű lapok szerkesztése",
+       "action-editinterface": "felhasználói felület szerkesztése",
+       "action-editusercss": "más felhasználók CSS fájljainak szerkesztése",
+       "action-edituserjson": "más felhasználók JSON fájljainak szerkesztése",
+       "action-edituserjs": "más felhasználók JavaScript fájljainak szerkesztése",
+       "action-editsitecss": "CSS-lapok szerkesztése",
+       "action-editsitejson": "JSON-lapok szerkesztése",
+       "action-editsitejs": "JavaScript-lapok szerkesztése",
+       "action-editmyusercss": "saját szerkesztői CSS-fájlok szerkesztése",
+       "action-editmyuserjson": "saját szerkesztői JSON-fájlok szerkesztése",
+       "action-editmyuserjs": "saját szerkesztői JavaScript-fájlok szerkesztése",
+       "action-viewsuppressed": "minden felhasználó elől elrejtett változtatások megtekintése",
+       "action-hideuser": "felhasználói név blokkolása és elrejtése a külvilág elől",
+       "action-ipblock-exempt": "IP-, auto- és tartományblokkok megkerülése",
+       "action-unblockself": "saját felhasználói fiók blokkjának feloldása",
+       "action-noratelimit": "sebességkorlát figyelmen kívül hagyása",
+       "action-reupload-own": "a saját maga által feltöltött fájlok felülírása",
+       "action-nominornewtalk": "vitalapok apró szerkesztése új üzenetről való értesítés kiküldése nélkül",
+       "action-markbotedits": "visszaállított szerkesztések botként való jelölése",
+       "action-patrolmarks": "járőrök jelzéseinek megtekintése a friss változásokban",
+       "action-override-export-depth": "lapok exportálása a hivatkozott lapokkal együtt, legfeljebb 5-ös mélységig",
+       "action-suppressredirect": "átirányítások készítésének kihagyása a lapok régi nevén átnevezéskor",
        "nchanges": "$1 változtatás",
        "enhancedrc-since-last-visit": "$1 az utolsó látogatás óta",
        "enhancedrc-history": "történet",
        "rcfilters-savedqueries-already-saved": "Ezek a szűrők már el lettek mentve. Módosítsd a beállításokat egy új mentett szűrő készítéséhez.",
        "rcfilters-restore-default-filters": "Alapértelmezett szűrők visszaállítása",
        "rcfilters-clear-all-filters": "Összes szűrő kikapcsolása",
-       "rcfilters-show-new-changes": "Legfrissebb változtatások megtekintése",
+       "rcfilters-show-new-changes": "$1 óta történt friss változtatások megtekintése",
        "rcfilters-search-placeholder": "Változtatások szűrése (használd a menüt vagy keress szűrőkre)",
        "rcfilters-invalid-filter": "Érvénytelen szűrő",
        "rcfilters-empty-filter": "Nincs aktív szűrő. Minden közreműködés látható.",
        "rcfilters-filter-editsbyself-description": "A te hozzájárulásaid.",
        "rcfilters-filter-editsbyother-label": "Mások módosításai",
        "rcfilters-filter-editsbyother-description": "Minden változtatás a tieidet kivéve.",
-       "rcfilters-filtergroup-userExpLevel": "Felhasználói regisztráció és tapasztalat",
+       "rcfilters-filtergroup-user-experience-level": "Felhasználói regisztráció és tapasztalat",
        "rcfilters-filter-user-experience-level-registered-label": "Regisztrált",
        "rcfilters-filter-user-experience-level-registered-description": "Bejelentkezett szerkesztők.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Nem regisztrált",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Az „apró változtatás” szűrő ütközik egy vagy több „változtatás típusa” szűrővel, mert bizonyos változtatástípusok nem jelölhetők aprónak. Az ütköző szűrők meg vannak jelölve a fenti Aktív szűrők részen.",
        "rcfilters-hideminor-conflicts-typeofchange": "Bizonyos változtatástípusok nem jelölhetők „aprónak”, így ez a szűrő ütközik a következő „változtatás típusa” szűrőkkel: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Ez a változtatástípus-szűrő ütközik az „apró változtatások” szűrővel. Bizonyos változtatástípusok nem jelölhetők aprónak.",
-       "rcfilters-filtergroup-lastRevision": "Legutóbbi változat",
+       "rcfilters-filtergroup-lastrevision": "Legutóbbi változat",
        "rcfilters-filter-lastrevision-label": "Legutóbbi változat",
        "rcfilters-filter-lastrevision-description": "Egy lap legfrissebb változtatása",
        "rcfilters-filter-previousrevision-label": "Régebbi változatok",
        "minoreditletter": "a",
        "newpageletter": "Ú",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[Jelenleg {{PLURAL:$1|egy|$1}} felhasználó figyeli]",
        "rc-change-size-new": "$1 bájt módosítás után",
        "newsectionsummary": "/* $1 */ (új szakasz)",
        "rc-enhanced-expand": "Részletek megjelenítése",
        "img-auth-nopathinfo": "Hiányzó PATH_INFO.\nA szerver nincs beállítva, hogy továbbítsa ezt az információt.\nLehet, hogy CGI-alapú, és nem támogatja az img_auth-ot.\nLásd https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization!",
        "img-auth-notindir": "A kért elérési út nincs a beállított feltöltési könyvtárban.",
        "img-auth-badtitle": "Nem sikerült érvényes címet készíteni a(z) „$1” szövegből.",
-       "img-auth-nologinnWL": "Nem vagy bejelentkezve, és a(z) „$1” nincs az engedélyezési listán.",
        "img-auth-nofile": "A fájl („$1”) nem létezik.",
        "img-auth-isdir": "Megpróbáltál hozzáférni a(z) „$1” könyvtárhoz, azonban csak a fájlokhoz lehet.",
        "img-auth-streaming": "„$1” továbbítása.",
        "delete-confirm": "$1 törlése",
        "delete-legend": "Törlés",
        "historywarning": "<strong>Figyelem:</strong> a lapnak, amit törölni készülsz, $1 változattal rendelkező laptörténete van:",
-       "historyaction-submit": "Mutat",
+       "historyaction-submit": "Változatok megjelenítése",
        "confirmdeletetext": "Egy lapot vagy fájlt készülsz törölni a teljes laptörténetével együtt.\nKérjük, erősítsd meg, hogy valóban ezt szeretnéd tenni, átlátod a következményeit, és hogy a műveletet a [[{{MediaWiki:Policy-url}}|törlési irányelvekkel]] összhangban végzed.",
        "actioncomplete": "Művelet végrehajtva",
        "actionfailed": "A művelet nem sikerült",
        "deleting-backlinks-warning": "<strong>Figyelem:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Más lapok]] hivatkoznak a törlendő oldalra (vagy beillesztik azt).",
        "deleting-subpages-warning": "<strong>Figyelem:</strong> A törlésre jelölt lapnak [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|van egy allapja|$1 allapja van|51=több mint 50 allapja van}}]].",
        "rollback": "Szerkesztések visszaállítása",
+       "rollback-confirmation-confirm": "Kérlek erősítsd meg:",
+       "rollback-confirmation-yes": "Visszaállítás",
+       "rollback-confirmation-no": "Mégse",
        "rollbacklink": "visszaállítás",
        "rollbacklinkcount": "$1 szerkesztés visszaállítása",
        "rollbacklinkcount-morethan": "több mint $1 szerkesztés visszaállítása",
        "revertpage": "Visszaállítottam a lap korábbi változatát [[Special:Contributions/$2|$2]] ([[User talk:$2|vita]]) szerkesztéséről [[User:$1|$1]] szerkesztésére",
        "revertpage-nouser": "Visszaállítottam a lap korábbi változatát (szerkesztőnév eltávolítva) szerkesztéséről [[User:$1|$1]] szerkesztésére",
        "rollback-success": "{{GENDER:$3|$1}} szerkesztéseit visszaállítottam {{GENDER:$4|$2}} utolsó változatára.",
-       "rollback-success-notify": "$1 szerkesztései visszaállítva;\nhelyreállítva $2 utolsó változata. [$3 Változtatások megtekintése]",
        "sessionfailure-title": "Munkamenethiba",
        "sessionfailure": "Úgy látszik, hogy probléma van a bejelentkezési munkameneteddel;\nez a művelet a munkamenet eltérítése miatti óvatosságból megszakadt.\nKérjük, küldd el újra az űrlapot.",
        "changecontentmodel": "A lap tartalommodelljének megváltoztatása",
        "month": "E hónap végéig:",
        "year": "Eddig az évig:",
        "date": "Eddig a dátumig:",
-       "sp-contributions-newbies": "Csak a nemrég regisztrált szerkesztők közreműködéseinek mutatása",
+       "sp-contributions-newbies": "Csak a nemrég regisztrált szerkesztők közreműködéseit mutassa",
        "sp-contributions-newbies-sub": "Új szerkesztők lapjai",
        "sp-contributions-newbies-title": "Új szerkesztők közreműködései",
        "sp-contributions-blocklog": "Blokkolási napló",
        "ipb-confirm": "Blokk megerősítése",
        "ipb-sitewide": "Teljes körű",
        "ipb-partial": "Részleges",
+       "ipb-sitewide-help": "A wiki összes lapja és minden egyéb közreműködési művelet.",
+       "ipb-partial-help": "Meghatározott lapok vagy névterek.",
        "ipb-pages-label": "Lapok",
        "ipb-namespaces-label": "Névterek",
        "badipaddress": "Érvénytelen IP-cím",
        "blocklist-userblocks": "Fiókblokkolások elrejtése",
        "blocklist-tempblocks": "Ideiglenes blokkolások elrejtése",
        "blocklist-addressblocks": "IP-címek blokkolásainak elrejtése",
+       "blocklist-type": "Típus:",
+       "blocklist-type-opt-all": "Összes",
+       "blocklist-type-opt-sitewide": "Teljes körű",
+       "blocklist-type-opt-partial": "Részleges",
        "blocklist-rangeblocks": "Tartományblokkok elrejtése",
        "blocklist-timestamp": "Időbélyeg",
        "blocklist-target": "Célpont",
        "blocklist-editing-page": "lapok",
        "blocklist-editing-ns": "névterek",
        "ipblocklist-empty": "A blokkoltak listája üres.",
-       "ipblocklist-no-results": "A kért IP-cím vagy felhasználónév nem blokkolt.",
+       "ipblocklist-no-results": "Nem található blokk a kért IP-címhez vagy felhasználónévhez.",
        "blocklink": "blokkolás",
        "unblocklink": "blokk feloldása",
        "change-blocklink": "blokkolás módosítása",
+       "empty-username": "(felhasználónév nem elérhető)",
        "contribslink": "szerkesztései",
        "emaillink": "e-mail küldése",
        "autoblocker": "Az általad használt IP-cím autoblokkolva van, mivel korábban a kitiltott „[[User:$1|$1]]” használta. ($1 blokkolásának indoklása: „'''$2'''”) Ha nem te vagy $1, lépj kapcsolatba valamelyik adminisztrátorral, és kérd az autoblokk feloldását. Ne felejtsd el megírni neki, hogy kinek szóló blokkba ütköztél bele!",
        "ipb_expiry_old": "A lejárati idő a múltban van.",
        "ipb_expiry_temp": "A láthatatlan felhasználóinév-blokkok lehetnek állandóak.",
        "ipb_hide_invalid": "A felhasználói fiókot nem lehet elrejteni; több mint $1 szerkesztése van.",
+       "ipb_hide_partial": "Felhasználói nevek elrejtésekor és blokkolásakor a blokknak az egész wikire ki kell terjednie.",
        "ipb_already_blocked": "\"$1\" már blokkolva",
        "ipb-needreblock": "$1 már blokkolva van. Meg szeretnéd változtatni a beállításokat?",
        "ipb-otherblocks-header": "További {{PLURAL:$1|blokk|blokkok}}",
        "allmessagesdefault": "Alapértelmezett szöveg",
        "allmessagescurrent": "Jelenlegi szöveg",
        "allmessagestext": "Ezen a lapon a MediaWiki-névtérben elérhető rendszerüzenetek listája látható.\nHa részt szeretnél venni a MediaWiki fordításában, látogass el a [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation], valamint a [https://translatewiki.net translatewiki.net] oldalra.",
-       "allmessagesnotsupportedDB": "A '''''{{ns:special}}:Allmessages''''' lap nem használható, mert a '''$wgUseDatabaseMessages''' ki van kapcsolva.",
+       "allmessages-not-supported-database": "A '''''{{ns:special}}:Allmessages''''' lap nem használható, mert a '''$wgUseDatabaseMessages''' ki van kapcsolva.",
        "allmessages-filter-legend": "Elemek szűrése",
        "allmessages-filter": "Módosítás állapota:",
        "allmessages-filter-unmodified": "nem módosított",
        "confirm-unwatch-top": "El szeretnéd távolítani a lapot a figyelőlistádról?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Visszavonod a változtatásokat?",
+       "confirm-rollback-bottom": "Ez a művelet azonnal visszaállítja a lap kiválasztott változtatásait.",
        "confirm-mcrrestore-title": "Egy változat visszaállítása",
        "confirm-mcrundo-title": "Egy változtatás visszavonva",
        "mcrundofailed": "A visszavonás nem sikerült",
        "mcrundo-missingparam": "Kötelező paraméterek hiányoznak a kérésből.",
        "mcrundo-changed": "A változtatások megtekintése óta az oldal megváltozott. Kérlek, tekintsd meg az új változtatásokat.",
+       "mcrundo-parse-failed": "Az új változat feldolgozása sikertelen: $1",
        "ellipsis": "…",
        "quotation-marks": "„$1”",
        "imgmultipageprev": "← előző oldal",
        "passwordpolicies-policy-maximalpasswordlength": "A jelszó legfeljebb $1 karakter hosszú lehet",
        "passwordpolicies-policy-passwordcannotbepopular": "A jelszó nem {{PLURAL:$1|lehet a gyakran használt jelszó|szerepelhet a(z) $1 leggyakrabban használt jelszó listáján}}",
        "passwordpolicies-policy-passwordnotinlargeblacklist": "A jelszó nem szerepelhet a 100 000 leggyakrabban használt jelszó listáján .",
-       "unprotected-js": "Biztonsági okokból JavaScript nem tölthető be védtelen lapokról. Kérlek egyedül a MediaWiki névtérben készíts JavaScriptet, vagy szerkesztői allapként."
+       "passwordpolicies-policyflag-forcechange": "lecserélés követelése bejelentkezéskor",
+       "passwordpolicies-policyflag-suggestchangeonlogin": "lecserélés ajánlása bejelentkezéskor",
+       "unprotected-js": "Biztonsági okokból JavaScript nem tölthető be védtelen lapokról. Kérlek egyedül a MediaWiki névtérben készíts JavaScriptet, vagy szerkesztői allapként.",
+       "userlogout-continue": "Amennyiben ki szeretnél jelentkezni, [$1 használd a kijelentkezési oldalt].",
+       "userlogout-sessionerror": "Sikertelen kijelentkezés munkamenethiba miatt. Kérlek [$1 próbáld újra]."
 }
index 5cb261c..0fabf7c 100644 (file)
@@ -33,7 +33,8 @@
                        "23artashes",
                        "Fitoschido",
                        "Սահակ",
-                       "ديفيد"
+                       "ديفيد",
+                       "Azniv Stepanian"
                ]
        },
        "tog-underline": "ընդգծել հղումները՝",
        "mainpage": "Գլխավոր էջ",
        "mainpage-description": "Գլխավոր էջ",
        "policy-url": "Project:Կանոնակարգ",
-       "portal": "Խորհրդարան",
+       "portal": "Համայնքային պորտալ",
        "portal-url": "Project:Համայնքային պորտալ",
        "privacy": "Գաղտնիության քաղաքականություն",
        "privacypage": "Project:Գաղտնիության քաղաքականություն",
        "mypreferencesprotected": "Դուք բավարար իրավունքներ չունեք Ձեր նախընտրությունները խմբագրելու համար։",
        "ns-specialprotected": "«{{ns:special}}» անվանատարածքի էջերը չեն կարող խմբագրվել։",
        "titleprotected": "Այս անվանմամբ էջի ստեղծումը արգելվել է [[User:$1|$1]] մասնակցի կողմից։\nՏրված պատճառն է՝ <em>$2</em>։",
+       "invalidtitle": "Սխալ վերնագիր",
        "exception-nologin": "Չեք մտել համակարգ",
        "exception-nologin-text": "Խնդրում ենք, մուտք գործեք՝ այս էջը դիտելու կամ գործողությունը կատարելու համար։",
        "virus-badscanner": "Սխալ կարգավորւմ։ Անծանոթ վիրուսների զննիչ. ''$1''",
        "virus-scanfailed": "զննման սխալ (կոդ $1)",
        "virus-unknownscanner": "անծանոթ հակավիրուս՝",
-       "logouttext": "<strong>Դուք դուրս եկաք համակարգից։</strong>\n\nԻ նկատի ունեցեք, որ որոշ էջեր կարող են ցուցադրվել այնպես՝ ինչպես եթե դեռ համակարգում լինեիք մինչև որ չջնջեք ձեր զննարկիչի հիշապահեստը։",
+       "logouttext": "<strong>Դուք դուրս եկաք համակարգից։</strong>\n\nՆկատի ունեցեք, որ որոշ էջեր կարող են ցուցադրվել այնպես, ինչպես համակարգում լինելու դեպքում, քանի դեռ չէիք ջնջել զննարկիչի հիշապահեստը։",
        "cannotlogoutnow-title": "Այժմ դուրս գալ անհնար է",
        "cannotlogoutnow-text": "$1 օգտագործելիս դուրս գալն անհնար է:",
        "welcomeuser": "Բարի գալո՜ւստ, $1",
        "createacct-another-submit": "Ստեղծել հաշիվ",
        "createacct-continue-submit": "Շարունակել ստեղծել հաշիվ",
        "createacct-another-continue-submit": "Շարունակել ստեղծել հաշիվ",
-       "createacct-benefit-heading": "{{SITENAME}}՝ ստեղծվում է ձեր պես մարդկանց կողմից։",
+       "createacct-benefit-heading": "{{SITENAME}}՝ ստեղծվում է ձեզ պես մարդկանց կողմից։",
        "createacct-benefit-body1": "{{PLURAL:$1|խմբագրում}}",
        "createacct-benefit-body2": "{{PLURAL:$1|էջ}}",
        "createacct-benefit-body3": "վերջերս ակտիվ {{PLURAL:$1|մասնակից}}",
        "savechanges": "Պահպանել փոփոխությունները",
        "publishpage": "Ստեղծել էջը",
        "publishchanges": "Պահպանել",
+       "savearticle-start": "Հիշել էջը...",
+       "savechanges-start": "Հիշել փոփոխությունները...",
+       "publishpage-start": "Հրապարակել էջը...",
        "publishchanges-start": "Պահպանել…",
        "preview": "Նախադիտում",
        "showpreview": "Նախադիտել",
        "userjsyoucanpreview": "'''Հուշում.''' Էջը հիշելուց առաջ օգտվեք «{{int:showpreview}}» կոճակից՝ ձեր նոր JS-նիշքը ստուգելու համար։",
        "usercsspreview": "'''Նկատի ունեցեք, որ դուք միայն նախադիտում եք ձեր մասնակցի CSS-նիշքը. այն դեռ հիշված չէ՛։'''",
        "userjspreview": "'''Նկատի ունեցեք, որ դուք միայն նախադիտում եք ձեր մասնակցի JavaScript-նիշքը. այն դեռ հիշված չէ՛։'''",
-       "userinvalidconfigtitle": "'''Զգուշացում.''' «$1» տեսք չի գտնվել։ Ի նկատի ունեցեք, որ մասնակցային .css և .js էջերը ունեն փոքրատառ անվանումներ, օր.՝ «{{ns:user}}:Ոմն/vector.css», և ոչ թե «{{ns:user}}:Ոմն/Vector.css»։",
+       "userinvalidconfigtitle": "'''Զգուշացում.''' «$1» տեսք չի գտնվել։ Նկատի ունեցեք, որ մասնակցային .css և .js էջերը ունեն փոքրատառ անվանումներ, օր.՝ «{{ns:user}}:Ոմն/vector.css», և ոչ թե «{{ns:user}}:Ոմն/Vector.css»։",
        "updated": "(Թարմացված)",
        "note": "'''Ծանուցում.'''",
        "previewnote": "'''Սա միայն նախադիտումն է. ձեր կատարած փոփոխությունները դեռ չե՛ն հիշվել։'''",
        "edit-already-exists": "Հրարավոր չէ նոր էջ ստեղծել․ այն արդեն գոյություն ունի։",
        "defaultmessagetext": "Լռելյան տեքստը",
        "editwarning-warning": "Այս էջը լքելով դուք կարող եք կորցնել ձեր կատարած փոփոխությունները։\nԵթե դուք գրանցված եք համակարգում, կարող եք անջատել այս նախազգուշացումը ձեր նախընրությունների «{{int:prefs-editing}}» բաժնում։",
+       "slot-name-main": "Հիմնական",
        "content-model-wikitext": "վիքիտեքստ",
        "content-model-text": "պարզ տեքստ",
        "content-model-javascript": "ՋավաՍկրիպտ",
        "diff-empty": "(Տարբերություն չկա)",
        "diff-multi-sameuser": "(Միևնույն մասնակցի {{PLURAL:$1|մեկ միջանկյալ տարբերակ|$1 միջանկյալ տարբերակներ}} թաքցված է)",
        "searchresults": "Որոնման արդյունքներ",
+       "search-filter-title-prefix-reset": "Որոնել բոլոր էջեր",
        "searchresults-title": "«$1»-ի որոնման արդյունքներ",
        "titlematches": "Համընկած հոդվածների անվանումներ",
        "textmatches": "Համընկած տեքստերով էջեր",
        "search-result-category-size": "{{PLURAL:$1|անդամ}} ({{PLURAL:$2|ենթակատեգորիա}}, {{PLURAL:$3|նիշք}})",
        "search-redirect": "(վերահղում $1 էջից)",
        "search-section": "(բաժին $1)",
+       "search-category": "(կատեգորիա $1)",
        "search-file-match": "(համապատասխանում է նիշքի բովանդակությանը)",
        "search-suggest": "Գուցե նկատի ունե՞ք՝ $1",
        "search-interwiki-caption": "Կից նախագծեր",
        "powersearch-toggleall": "Բոլորը",
        "powersearch-togglenone": "Ոչ մեկը",
        "search-external": "Արտաքին որոնում",
-       "searchdisabled": "{{SITENAME}} Õ¯Õ¡ÕµÖ\84Õ« Õ¶Õ¥Ö\80Ö\84Õ«Õ¶ Õ¸Ö\80Õ¸Õ¶Õ¸Ö\82Õ´Õ¨ Õ¡Õ¶Õ»Õ¡Õ¿Õ¾Õ¡Õ® Õ§Ö\89 Ô´Õ¸Ö\82Ö\84 Õ¯Õ¡Ö\80Õ¸Õ² Õ¥Ö\84 Õ¸Ö\80Õ¸Õ¶Õ¥Õ¬ Õ¯Õ¡ÕµÖ\84Õ« ÕºÕ¡Ö\80Õ¸Ö\82Õ¶Õ¡Õ¯Õ¸Ö\82Õ©ÕµÕ¸Ö\82Õ¶Õ¨ Õ¡Ö\80Õ¿Õ¡Ö\84Õ«Õ¶ Õ¸Ö\80Õ¸Õ¶Õ´Õ¡Õ¶ Õ·Õ¡Ö\80ÕªÕ«Õ¹Õ¶Õ¥Ö\80Õ¸Õ¾ (Google, Yahoo...), Õ½Õ¡Õ¯Õ¡ÕµÕ¶, Õ« Õ¶Õ¯Õ¡Õ¿Õ« Õ¸Ö\82Õ¶Õ¥Ö\81Õ¥Ö\84, Õ¸Ö\80 Õ¯Õ¡ÕµÖ\84Õ« Õ«Ö\80Õ¥Õ¶Ö\81 Õ«Õ¶Õ¤Õ¥Ö\84Õ½Õ¶Õ¥Ö\80Õ¨ Õ¯Õ¡Ö\80Õ¸Õ² Õ¥Õ¶ Õ°Õ¶Õ¡Ö\81Õ¡Õ® Õ¬Õ«Õ¶Õ¥Õ¬Ö\89",
+       "searchdisabled": "{{SITENAME}} կայքի ներքին որոնումը անջատված է։ Դուք կարող եք որոնել կայքի պարունակությունը արտաքին որոնման շարժիչներով (Google, Yahoo...), սակայն, նկատի ունեցեք, որ կայքի իրենց ինդեքսները կարող են հնացած լինել։",
        "preferences": "Նախընտրություններ",
        "mypreferences": "Նախընտրություններ",
        "prefs-edits": "Խմբագրումների քանակը.",
        "prefs-rc": "Վերջին փոփոխություններ",
        "prefs-watchlist": "Հսկացանկ",
        "prefs-editwatchlist": "Խմբագրել հսկացանկը",
+       "prefs-editwatchlist-clear": "Մաքրել հսկացանկը",
        "prefs-watchlist-days": "Հսկացանկում ցուցադրվող օրերի թիվը՝",
        "prefs-watchlist-days-max": "Առավելագույնը $1 {{PLURAL:$1|օր}}",
        "prefs-watchlist-edits": "Ընդարձակված հսկացանկում ցուցադրվող օրերի թիվը՝",
        "grant-group-email": "Ուղարկել էլ. նամակ",
        "grant-createaccount": "Ստեղծել հաշիվներ",
        "grant-createeditmovepage": "Ստեղծել․ խմբագրել և տեղափոխել էջեր",
+       "grant-uploadfile": "Բեռնել նոր նիշքեր",
        "grant-basic": "Հիմնական իրավունքներ",
+       "grant-viewmywatchlist": "Դիտել ձեր հսկացանկը",
        "newuserlogpage": "Մասնակիցների գրանցման տեղեկամատյան",
        "newuserlogpagetext": "Սա նոր մասնակիցների գրանցման տեղեկամատյանն է.",
        "rightslog": "Մասնակցի իրավունքների տեղեկամատյան",
        "action-read": "կարդալ այս էջը",
        "action-edit": "խմբագրել այս էջը",
        "action-createpage": "Ստեղծել էջ",
+       "action-createtalk": "Ստեղծել քննարկման էջ",
        "action-createaccount": "ստեղծել այս մասնակցային հաշիվը",
        "action-move": "տեղափոխել այս էջը",
        "action-move-rootuserpages": "տեղափոխել մասնակցի էջի արմատը",
        "rcfilters-other-review-tools": "Վերանայման այլ գործիքներ",
        "rcfilters-group-results-by-page": "Արդյունքները խմբավորել էջերով",
        "rcfilters-activefilters": "Ակտիվ զտիչներ",
+       "rcfilters-activefilters-hide": "Թաքցնել",
+       "rcfilters-activefilters-show": "Ցուցադրել",
        "rcfilters-advancedfilters": "Ընդլայնված ֆիլտրեր",
        "rcfilters-limit-title": "Ցուցադրվող արդյունքներ",
        "rcfilters-limit-and-date-label": "$1 {{PLURAL:$1|փոփոխություն|փոփոխություններ}}, $2",
        "rcfilters-filtergroup-authorship": "Ներդրումների հեղինակ",
        "rcfilters-filter-editsbyself-label": "Ձեր խմբագրումներ",
        "rcfilters-filter-editsbyother-label": "Այլոց փոփոխությունները",
-       "rcfilters-filtergroup-userExpLevel": "Մասնակիցների գրանցում և փորձ",
+       "rcfilters-filtergroup-user-experience-level": "Մասնակիցների գրանցում և փորձ",
        "rcfilters-filter-user-experience-level-registered-label": "Գրանցված",
        "rcfilters-filter-user-experience-level-unregistered-label": "Չգրանցված",
        "rcfilters-filter-user-experience-level-newcomer-label": "Նորեկներ",
        "rcfilters-filter-pageedits-label": "Էջի խմբագրումներ",
        "rcfilters-filter-newpages-label": "Նոր էջեր",
        "rcfilters-filter-logactions-label": "Մուտք գործած գործողություններ",
-       "rcfilters-filtergroup-lastRevision": "Ամենավերջին տարբերակ",
+       "rcfilters-filtergroup-lastrevision": "Ամենավերջին տարբերակ",
        "rcfilters-filter-previousrevision-label": "Ոչ վերջին տարբերակ",
        "rcfilters-view-tags": "Պիտակված խմբագրումներ",
        "rcfilters-liveupdates-button": "Կենդանի թարմացումներ",
        "minoreditletter": "չ",
        "newpageletter": "Ն",
        "boteditletter": "բ",
-       "number_of_watching_users_pageview": "[$1 հսկող {{PLURAL:$1|մասնակից|մասնակիցներին}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|բայթ|բայթ}} փոփոխությունից հետո",
        "newsectionsummary": "/* $1 */ Նոր բաժին",
        "rc-enhanced-expand": "Ցուցադրել մանրամասներ (պահանջում է ՋավաՍկրիպտ)",
        "upload-misc-error-text": "Տեղի ունեցավ անհայտ սխալ բեռնման ընթացքում։ Խնդրում ենք ստուգել URL-հասցեի ճշտությունն ու հասանելիությունը և փորձել կրկին։ Սխալի կրկնման դեպքում կապնվեք համակարգային ադմինիստրատորի հետ։",
        "upload-dialog-title": "Բեռնել նիշք",
        "upload-dialog-button-cancel": "Չեղարկել",
+       "upload-dialog-button-back": "Հետ",
        "upload-dialog-button-done": "Արված է",
        "upload-dialog-button-save": "Հիշել",
        "upload-dialog-button-upload": "Բեռնել",
        "upload-form-label-infoform-title": "Մանրամասներ",
        "upload-form-label-infoform-name": "Անուն",
+       "upload-form-label-infoform-description": "Նկարագրություն",
        "upload-form-label-usage-filename": "Նիշքի անուն",
        "upload-form-label-own-work": "Սա իմ անձնական աշխատանքն է",
        "upload-form-label-infoform-categories": "Կատեգորիաներ",
        "license-nopreview": "(Նախադիտումը մատչելի չէ)",
        "upload_source_url": " (գործուն, հանրամատչելի URL-հասցե)",
        "upload_source_file": " (նիշք ձեր համակարգչի վրա)",
+       "listfiles-delete": "ջնջել",
        "listfiles_search_for": "Որոնել պատկերի անվամբ.",
        "imgfile": "նիշք",
        "listfiles": "Նիշքերի ցանկ",
        "listfiles_size": "Չափ",
        "listfiles_description": "Նկարագրություն",
        "listfiles_count": "Տարբերակ",
+       "listfiles-latestversion": "Ընթացիկ տարբերակ",
        "listfiles-latestversion-yes": "Այո",
        "listfiles-latestversion-no": "Ոչ",
        "file-anchor-link": "Նիշք",
        "unusedtemplateswlh": "այլ հղումներ",
        "randompage": "Պատահական էջ",
        "randompage-nopages": "Այս անվանատարածքում էջեր չկան։",
+       "randomincategory-category": "Կատեգորիա:",
+       "randomincategory-legend": "Կատեգորիայի պատահական էջ",
        "randomincategory-submit": "Անցնել",
        "randomredirect": "Պատահական վերահղում",
        "randomredirect-nopages": "Այս անվանատարածքում վերահղումներ չկան։",
        "protectedpages": "Պաշտպանված էջեր",
        "protectedpages-noredirect": "Թաքցնել վերահղումները",
        "protectedpagesempty": "Ներկայումս չկան պաշտպանված էջեր նշված պարամետրերով։",
+       "protectedpages-page": "Էջ",
+       "protectedpages-expiry": "Լրանում է",
        "protectedpages-submit": "Ցույց տալ էջերը",
+       "protectedpages-unknown-timestamp": "Անհայտ",
        "protectedtitles": "Պաշտպանված անվանումներ",
        "protectedtitles-submit": "Ցույց տալ վերնագրերը",
        "listusers": "Մասնակիցների ցանկ",
        "notargettext": "Դուք չեք նշել նպատակային էջ կամ մասնակից այս ֆունկցիայի գործածման համար։",
        "pager-newer-n": "{{PLURAL:$1|ավելի թարմ 1|ավելի թարմ $1}}",
        "pager-older-n": "{{PLURAL:$1|ավելի հին 1|ավելի հին $1}}",
+       "apisandbox-reset": "Մաքրել",
+       "apisandbox-retry": "Կրկնել",
+       "apisandbox-examples": "Օրինակներ",
+       "apisandbox-add-multi": "Ավելացնել",
+       "apisandbox-results": "Արդյունք",
+       "apisandbox-continue": "Շարունակել",
+       "apisandbox-continue-clear": "Մաքրել",
        "booksources": "Գրքային աղբյուրներ",
        "booksources-search-legend": "Գրքի մասին տեղեկությունների որոնում",
        "booksources-search": "Որոնել",
        "alllogstext": "{{SITENAME}} կայքի տեղեկամատյանների համընդհանուր ցանկ։\nԴուք կարող եք սահմանափակել արդյունքները ըստ տեղեկամատյանի տեսակի, մասնակցի անունի կամ համապատասխան էջի։",
        "logempty": "Տեղեկամատյանում չկան համընկնող տարրեր։",
        "log-title-wildcard": "Որոնել այս տեքստով սկսվող անվանումներ",
+       "checkbox-all": "Բոլորը",
+       "checkbox-none": "Ոչ մեկը",
        "allpages": "Բոլոր էջերը",
        "nextpage": "Հաջորդ էջը ($1)",
        "prevpage": "Նախորդ էջը ($1)",
        "deletedcontributions-title": "Մասնակցի ջնջված ներդրում",
        "sp-deletedcontributions-contribs": "ներդրում",
        "linksearch": "Արտաքին հղումներ",
+       "linksearch-ns": "Անվանատարածք.",
        "linksearch-ok": "Որոնել",
        "linksearch-line": " \n$1-ը հղվել է $2 ից",
        "listusersfrom": "Ցուցադրել մասնակիցներին՝ սկսած.",
        "activeusers": "Ակտիվ մասնակիցների ցանկ",
        "activeusers-noresult": "Այդպիսի մասնակիցներ չեն գտնվել։",
        "activeusers-submit": "Ցույց տալ ակտիվ մասնակիցներին",
+       "listgrouprights-group": "Խումբ",
+       "listgrouprights-rights": "Իրավունքներ",
        "listgrouprights-members": "(անդամների ցանկ)",
        "listgrouprights-addgroup": "Ավելացնեել {{PLURAL:$2|խումբ|խմբեր}}՝  $1",
+       "listgrouprights-namespaceprotection-namespace": "Անվանատարածք",
+       "listgrants-rights": "Իրավունքներ",
        "mailnologin": "Ուղարկման հասցե չկա",
        "mailnologintext": "Անհրաժեշտ է [[Special:UserLogin|մտնել համակարգ]] և ունենալ գործող էլ-փոստի հասցե ձեր [[Special:Preferences|նախընտրություններում]]՝ ուրիշ մասնակիցներին էլեկտրոնային նամակներ ուղարկելու համար։",
        "emailuser": "էլ-նամակ ուղարկել այս մասնակցին",
        "delete-edit-reasonlist": "Խմբագրել ջնջման պատճառները",
        "deleting-backlinks-warning": "'''Զգուշացում''', ձեր կողմից ջնջվող էջին հղվում են [[Special:WhatLinksHere/{{FULLPAGENAME}}|այլ հոդվածներ]]:",
        "rollback": "Հետ գլորել խմբագրումները",
+       "rollback-confirmation-confirm": "Խնդրում ենք հաստատել.",
+       "rollback-confirmation-no": "Չեղարկել",
        "rollbacklink": "հետ գլորել",
        "rollbacklinkcount": "հետ գլորել $1 {{PLURAL:$1|խմբագրում}}",
        "rollbacklinkcount-morethan": "հետ գլորել ավելի քան $1 {{PLURAL:$1|խմբագրում|խմբագրում}}",
        "rollback-success": "Հետ են շրջվել $1 մասնակցի խմբագրումները. վերադարձվել է $2 մասնակցի վերջին տարբերակին։",
        "sessionfailure-title": "Սեսիայի խափանում",
        "sessionfailure": "Կարծես խնդիր է առաջացել կապված ձեր ընթացիկ աշխատանքային սեսիայի հետ.\nայս գործողությունը բեկանվել է սեսիայի հափշտակման կանխման նպատակով։\nԽնդրում ենք սեղմել «back» կոճակը և վերբեռնել այն էջը որտեղից եկել եք ու փորձել կրկին։",
+       "changecontentmodel-reason-label": "Պատճառ՝",
+       "changecontentmodel-submit": "Փոխել",
+       "logentry-contentmodel-change-revertlink": "հետ շրջել",
+       "logentry-contentmodel-change-revert": "հետ շրջել",
        "protectlogpage": "Պաշտպանման տեղեկամատյան",
        "protectlogtext": "Ստորև բերված է պաշտպանված և պաշտպանումից հանված էջերի ցանկը։ Տես նաև [[Special:ProtectedPages|ներկայումս պաշտպանված էջերի ցանկը]]։",
        "protectedarticle": "պաշտպանվեց «[[$1]]» էջը",
        "tooltip-invert": "Նշե՛ք տվյալ անվանատարածքի և կից անվանատարածքների (եթե նշված է) էջերի փոփոխությունները թաքցնելու համար։",
        "namespace_association": "Կից անվանատարածք",
        "tooltip-namespace_association": "Նշեք տվյալ անվանատարածքի հետ կապված քննարկումների անվանատարածքը նույնպես ներառելու համար։",
-       "blanknamespace": "(Գլխավոր)",
+       "blanknamespace": "(Հիմնական)",
        "contributions": "{{GENDER:$1|Մասնակցի}} ներդրում",
        "contributions-title": "$1 մասնակցի ներդրումը",
        "mycontris": "Ներդրում",
        "anoncontribs": "Ներդրումներ",
        "contribsub2": "{{GENDER:$3|$1}}-ի ներդրումները ($2)",
+       "contributions-subtitle": "{{GENDER:$3|$1}}-ի համար",
        "nocontribs": "Այս չափանիշներին համապատասխանող փոփոխություններ չեն գտնվել։",
        "uctop": " վերջինը",
        "month": "Սկսած ամսից (և վաղ)՝",
        "sp-contributions-username": "IP-հասցե կամ մասնակցի անուն.",
        "sp-contributions-toponly": "Ցույց տալ միայն այն խմբագրումները, որոնք վերջին փոփոխություն են",
        "sp-contributions-newonly": "Ցույց տալ միայն նոր էջերի խմբագրումները",
+       "sp-contributions-hideminor": "Թաքցնել չնչին խմբագրումները",
        "sp-contributions-submit": "Որոնել",
        "whatlinkshere": "Այստեղ հղվող էջերը",
        "whatlinkshere-title": "Էջեր, որոնք հղում են դեպի «$1»",
        "ipbwatchuser": "Հսկացանկում ավելացնել մասնակցի էջն ու քննարկման էջը",
        "ipb-disableusertalk": "Արգելել մասնակցին խմբագրել իր քննարկման էջն արգելափակման ընթացքում",
        "ipb-pages-label": "Էջեր",
+       "ipb-namespaces-label": "Անվանատարածքներ",
        "badipaddress": "Սխալ IP-հասցե",
        "blockipsuccesssub": "Արգելափակումը կատարված է",
        "blockipsuccesstext": "[[Special:Contributions/$1|«$1»]] արգելափակված է։\n<br />Տես [[Special:BlockList|արգելափակված IP-հասցեների ցանկը]]։",
        "ipb-blocklist": "Դիտել գործող արգելափակումները",
        "ipb-blocklist-contribs": "$1 մասնակցի ներդրումը",
        "block-expiry": "Մարման ժամկետ.",
+       "block-reason": "Պատճառ՝",
        "unblockip": "Արգելափակումից հանել մասնակցին",
        "unblockiptext": "Օգտագործեք ստորև ձևը՝ նախկինում արգելափակված IP-հասցեի կամ մասնակցի գրելու հնարավորությունը վերականգնելու համար։",
        "ipusubmit": "Հանել արգելափակումը",
        "unblocked": "[[User:$1|$1]] մասնակիցը անարգելված է։",
        "unblocked-id": "$1 արգելափակումը հանված է",
        "blocklist": "Արգելափակված մասնակիցներ։",
+       "autoblocklist-submit": "Որոնել",
        "ipblocklist": "Արգելափակված IP-հասցեները և մասնակիցները",
        "ipblocklist-legend": "Արգելափակված մասնակցի որոնում",
        "blocklist-expiry": "Լրանում է",
+       "blocklist-reason": "Պատճառ",
        "ipblocklist-submit": "Որոնել",
        "infiniteblock": "ընդմիշտ",
        "expiringblock": "կմարվի $1 $2",
        "createaccountblock": "մասնակցային հաշվի ստեղծումը արգելափակված է",
        "emailblock": "էլ-փոստը արգելափակված",
        "blocklist-nousertalk": "չի կարող խմբագրել իր քննարկման էջը",
+       "blocklist-editing-page": "էջեր",
+       "blocklist-editing-ns": "անվանատարածքներ",
        "ipblocklist-empty": "Արգելափակումների ցանկը դատարկ է։",
        "ipblocklist-no-results": "Նշված IP-հասցեն կամ մասնակցի անունը արգելափակված չէ։",
        "blocklink": "արգելափակել",
        "movepage-page-unmoved": "$1 էջը հնարավոր չէր վերանվանել $2",
        "movelogpage": "Տեղափոխման տեղեկամատյան",
        "movelogpagetext": "Ստորև բերված է վերանվանված էջերի ցանկը։",
+       "movesubpage": "{{PLURAL:$1|Ենթաէջ|Ենթաէջեր}}",
        "movenosubpage": "Այս էջը ենթաէջեր չունի",
        "movereason": "Պատճառ.",
        "revertmove": "հետ շրջել",
        "allmessagesdefault": "Ուղերձի լռելյայն տեքստ",
        "allmessagescurrent": "Ընթացիկ տեքստ",
        "allmessagestext": "Ստորև բերված է «MediaWiki» անվանատարածքի բոլոր համակարգային ուղերձների ցանկը։\nPlease visit [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] and [https://translatewiki.net translatewiki.net] if you wish to contribute to the generic MediaWiki localisation.",
-       "allmessagesnotsupportedDB": "Այս էջը չի գործում, քանի որ '''$wgUseDatabaseMessages''' հատկանիշը անջատված է։",
+       "allmessages-not-supported-database": "Այս էջը չի գործում, քանի որ '''$wgUseDatabaseMessages''' հատկանիշը անջատված է։",
        "allmessages-filter-all": "Բոլորը",
        "allmessages-language": "Լեզու",
        "allmessages-filter-submit": "Անցնել",
+       "allmessages-filter-translate": "Թարգմանել",
        "thumbnail-more": "Ընդարձակել",
        "filemissing": "Նման նիշք չկա",
        "thumbnail_error": "Պատկերիկի ստեղծման սխալ. $1",
        "import": "Էջերի ներմուծում",
        "importinterwiki": "Միջվիքի ներմուծում",
        "import-interwiki-text": "Նշեք վիքի և ներմուծվող էջի անվանումը։\nՓոփոխումների ժամանակները և խմբագրողների անունները կպահպանվեն։\nԲոլոր միջվիքի ներմուծման գործողությունները գրանցվում են [[Special:Log/import|ներմուծման տեղեկամատյանում]]։",
+       "import-interwiki-sourcewiki": "Աղբյուր վիքի.",
+       "import-interwiki-sourcepage": "Աղբյուր էջ.",
        "import-interwiki-history": "Պատճենել այս էջի փոփոխումների լրիվ պատմությունը",
        "import-interwiki-submit": "Ներմուծել",
        "import-upload-filename": "Նիշքի անուն․",
        "pageinfo-display-title": "Վերնագիր",
        "pageinfo-default-sort": "Լռելյայն տեսակավորման բանալի",
        "pageinfo-length": "Ծավալ (բայթերով)",
+       "pageinfo-namespace": "Անվանատարածք",
        "pageinfo-article-id": "Էջի N",
        "pageinfo-language": "Բովանդակության լեզու",
        "pageinfo-language-change": "փոխել",
        "pageinfo-content-model": "Էջի բովանդակության մոդելը",
+       "pageinfo-content-model-change": "փոխել",
        "pageinfo-robot-policy": "Կարգավիճակը որոնողական համակարգերում",
        "pageinfo-robot-index": "ինդեքսավորվող",
        "pageinfo-robot-noindex": "ինդեքսավորվող չէ",
        "pageinfo-contentpage": "Հաշվառված որպես բովանդակային էջ",
        "pageinfo-contentpage-yes": "Այո",
        "pageinfo-protect-cascading-yes": "Այո",
+       "pageinfo-category-pages": "Էջերի քանակ",
+       "pageinfo-category-subcats": "Ենթակատեգորիաների քանակ",
+       "pageinfo-category-files": "Հոդվածների քանակ",
+       "pageinfo-user-id": "Մասնակցի ID-ն",
        "markaspatrolleddiff": "Նշել որպես ստուգված",
        "markaspatrolledtext": "Նշել այս էջը որպես ստուգված",
        "markedaspatrolled": "Նշված է որպես ստուգված",
        "minutes": "{{PLURAL:$1|$1 րոպե|$1 րոպե}}",
        "hours": "{{PLURAL:$1|$1 ժամ|$1 ժամ}}",
        "days": "{{PLURAL:$1|$1 օր|$1 օր}}",
+       "weeks": "{{PLURAL:$1|$1 շաբաթ|$1 շաբաթներ}}",
+       "months": "{{PLURAL:$1|$1 ամիս|$1 ամիսներ}}",
+       "years": "{{PLURAL:$1|$1 տարի|$1 տարիներ}}",
        "ago": "$1 առաջ",
        "bad_image_list": "Գրաձևը հետևյալն է.\n\nՀաշվի են առնվելու միայն ցանկի տարրերը (* սիմվոլով սկսվող տողերը)։\nՏողի առաջին հղումը պետք է լինի դեպի արգելված պատկերը։\nՏողի հետագա հղումները ընկալվելու են որպես բացառություններ, այսինքն էջեր, որտեղ նշված պատկերի փակցնումը չի արգելվում։",
        "metadata": "Մետատվյալներ",
        "confirm-watch-top": "Ավելացնե՞լ ձեր հսկացանկին",
        "confirm-unwatch-button": "Լավ",
        "confirm-unwatch-top": "Հեռացնե՞լ Ձեր հսկացանկից։",
+       "confirm-rollback-button": "Լավ",
        "imgmultipageprev": "← նախորդ էջ",
        "imgmultipagenext": "հաջորդ էջ →",
        "imgmultigo": "Անցնե՛լ",
        "imgmultigoto": "Անցնել $1 էջը",
+       "img-lang-go": "Անցնել",
        "ascending_abbrev": "աճմ. կարգ.",
        "descending_abbrev": "նվազ",
        "table_pager_next": "Հաջորդ էջ",
        "watchlistedit-raw-done": "Ձեր հսկացանկը թարմացված է։",
        "watchlistedit-raw-added": "Ավելացվեց {{PLURAL:$1|1 անվանում|$1 անվանում}}.",
        "watchlistedit-raw-removed": "Հեռացվեց {{PLURAL:$1|1 անվանում|$1 անվանում}}.",
+       "watchlistedit-clear-title": "Մաքրել հսկացանկը",
+       "watchlistedit-clear-legend": "Մաքրել հսկացանկը",
        "watchlisttools-clear": "Մաքրել հսկացանկը",
        "watchlisttools-view": "Փոփոխությունները հսկացանկում",
        "watchlisttools-edit": "Դիտել և խմբագրել հսկացանկը",
        "watchlisttools-raw": "Խմբագրել հում հսկացանկը",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|քննարկում]])",
        "version": "ՄեդիաՎիքի տարբերակը",
+       "version-editors": "Խմբագիրներ",
        "version-ext-license": "Արտոնագիր",
        "version-ext-colheader-name": "Ընդլայնում",
        "version-ext-colheader-version": "Տարբերակ",
        "version-ext-colheader-license": "Արտոնագիր",
+       "version-ext-colheader-description": "Նկարագրություն",
+       "version-ext-colheader-credits": "Հեղինակներ",
        "version-license-title": "Արտոնագիր $1-ի համար",
        "version-poweredby-credits": "Այս վիքին աշխատում է '''[https://www.mediawiki.org/ MediaWiki]'''֊ով, copyright © 2001-$1 $2։",
+       "version-poweredby-translators": "translatewiki.net թարգմանիչներ",
+       "version-software-version": "Տարբերակ",
+       "version-libraries-library": "Գրադարան",
+       "version-libraries-version": "Տարբերակ",
+       "version-libraries-license": "Արտոնագիր",
+       "version-libraries-description": "Նկարագրություն",
+       "version-libraries-authors": "Հեղինակներ",
        "redirect": "Վերահղում նիշքի, մասնակցի, էջի, տարբերակի կամ գրանցամատյանի նույնականացման համարից",
        "redirect-submit": "Անցնել",
        "redirect-lookup": "Որոնում՝",
        "tag-filter": "[[Special:Tags|Պիտակների]] զտիչ՝",
        "tag-filter-submit": "Ֆիլտրել",
        "tag-list-wrapper": "[[Special:Tags|{{PLURAL:$1|Պիտակ}}]]: $2",
+       "tag-mw-new-redirect": "Նոր վերահղում",
        "tags-title": "Պիտակներ",
        "tags-source-header": "Աղբյուր",
        "tags-actions-header": "Գործողություններ",
        "compare-invalid-title": "Ձեր նշած վերնագիրը անվավեր է։",
        "compare-title-not-exists": "Ձեր նշած վերնագիրը գոյություն չունի:",
        "compare-revision-not-exists": "Ձեր նշած փոփոխությունը գոյություն չունի։",
+       "diff-form": "Տարբերությունները",
+       "permanentlink": "Մշտական հղում",
        "dberr-problems": "Այս կայքում առաջացել են տեխնիկական խնդիրներ։ Հայցում ենք ձեր ներողությունը։",
        "dberr-again": "Փորձեք մի քանի րոպե սպասել և վերաբեռնել էջը։",
        "htmlform-submit": " \nՀաշվել",
+       "htmlform-selectorother-other": "Այլ",
+       "htmlform-no": "Ոչ",
+       "htmlform-yes": "Այո",
+       "htmlform-title-not-exists": "$1՝ գոյություն չունի",
        "logentry-delete-delete": "$1 {{GENDER:$2|ջնջեց}} $3 էջը",
        "logentry-delete-restore": "$1 վերականգնեց $3 ($4) էջը",
+       "restore-count-files": "{{PLURAL:$1|1 նիշք|$1 նիշքեր}}",
        "logentry-delete-event": "$1 փոխեց տեղեկամատյանի {{PLURAL:$5|1 գրանցման|$5 գրանցումների}} տեսանելությունը $3-ում. $4",
        "logentry-delete-revision": "$1 {{GENDER:$2|փոխեց}} {{PLURAL:$5|1 խմբագրման|$5 խմբագրումների}} տեսանելիությունը $3 էջում․ $4",
        "logentry-delete-event-legacy": "$1 փոխեց տեղեկամատյանի գրանցումների տեսանելությունը $3-ում",
        "feedback-close": "Արված է",
        "feedback-message": "Հաղորդագրություն․",
        "feedback-subject": "Թեմա.",
+       "feedback-thanks-title": "Շնորհակալություն",
        "searchsuggest-search": "Որոնել {{SITENAME}} կայքում",
        "duration-seconds": "$1 {{PLURAL:$1|վայրկյան}}",
        "duration-minutes": "$1 {{PLURAL:$1|րոպե}}",
        "duration-centuries": "$1 {{PLURAL:$1|դար}}",
        "duration-millennia": "$1 {{PLURAL:$1|հազարամյակ}}",
        "expandtemplates": "Կաղապարների ընդարձակում",
+       "expand_templates_ok": "Լավ",
+       "pagelang-name": "Էջ",
+       "pagelang-language": "Լեզու",
+       "pagelang-select-lang": "Ընտրեք լեզուն",
+       "pagelang-reason": "Պատճառ",
+       "pagelang-submit": "Հաստատել",
        "pagelang-nonexistent-page": "$1 էջը գոյություն չունի",
+       "mediastatistics-nbytes": "{{PLURAL:$1|$1 բայթ|$1 բայթեր}} ($2; $3%)",
+       "mediastatistics-header-total": "Բոլոր նիշքեր",
        "special-characters-group-latin": "Լատիներեն",
        "special-characters-group-latinextended": "Լատիներեն ընդլայնված",
        "special-characters-group-ipa": "ՄՀԱ (IPA)",
        "date-range-from": "Սկսած՝",
        "date-range-to": "Մինչև՝",
        "randomrootpage": "Պատահական կենտրոնական էջ",
-       "authmanager-create-from-login": "Հաշիվ ստեղծելու համար, խնդրում ենք լրացնել ստորև դաշտերը"
+       "authmanager-create-from-login": "Հաշիվ ստեղծելու համար, խնդրում ենք լրացնել ստորև դաշտերը",
+       "authprovider-resetpass-skip-label": "Բաց թողնել",
+       "passwordpolicies-group": "Խումբ"
 }
index a3d2128..eb63102 100644 (file)
@@ -5,9 +5,19 @@
                        "Armeniki",
                        "Azniv Stepanian",
                        "Rajemian",
-                       "Դավիթ Սարոյան"
+                       "Դավիթ Սարոյան",
+                       "Kareyac"
                ]
        },
+       "tog-underline": "Ընդգծել յղումները․",
+       "tog-hideminor": "Թաքցնել չնչին խմբագրումները վերջին փոփոխութիւններու ցանկէն",
+       "tog-extendwatchlist": "Տարածել հսկացանկը՝ ցոյց տալով բոլոր փոփոխութիւնները, ոչ միայն վերջինները",
+       "tog-numberheadings": "Ինքնահամարակալել վերնագիրները",
+       "tog-editondblclick": "Խմբագրել էջերը կրկնակի սեղմամբ",
+       "tog-shownumberswatching": "Ցոյց տալ հսկող մասնակիցներուն թիւը",
+       "tog-watchlisthideown": "Թաքցնել իմ խմբագրումները հսկացանկէն",
+       "tog-watchlisthidebots": "Խմբագրումներս թաքցնել հսկացանկէն",
+       "tog-watchlisthideminor": "Խմբագրումներս թաքցնել հսկացանկէն",
        "underline-always": "Միշտ",
        "underline-never": "Երբեք",
        "editfont-serif": "Սերիֆ տառատեսակ",
        "december-date": "$1 Դեկտեմբեր",
        "period-am": "Նախ Կէսօր",
        "period-pm": "Կէսօրէն Յետոյ",
-       "pagecategories": "{{PLURAL:$1|Ստորոգութիւն|Ստորոգութիւններ}}",
+       "pagecategories": "{{PLURAL:$1|Կատեգորիա|Կատեգորիաներ}}",
        "category_header": "«$1» ստորոգութեան մէջ էջեր",
-       "subcategories": "ÔµÕ¶Õ©Õ¡Õ½Õ¿Õ¸Ö\80Õ¸Õ£Õ¸Ö\82Õ©Õ«Ö\82Õ¶ներ",
+       "subcategories": "ÔµÕ¶Õ©Õ¡Õ¯Õ¡Õ¿Õ¥Õ£Õ¸Ö\80Õ«Õ¡ներ",
        "category-media-header": "\"$1\" ստորոգութեան հաղորդամիջոց",
        "category-empty": "<em>Այս ստորոգութիւնը ներկայիս դատարկ է։<em>",
-       "hidden-categories": "{{PLURAL:$1|Թաքուն ստորոգութիւն|Թաքուն ստորոգութիւններ}}",
-       "hidden-category-category": "Ô¹Õ¡Ö\84Ö\81Õ¸Ö\82Õ¡Õ® Õ½Õ¿Õ¸Ö\80Õ¸Õ£Õ¸Ö\82Õ©Õ«Ö\82Õ¶ներ",
+       "hidden-categories": "{{PLURAL:$1|Թաքցուած կատեգորիա|Թաքցուած կատեգորիաներ}}",
+       "hidden-category-category": "Ô¹Õ¡Ö\84Ö\81Õ¸Ö\82Õ¡Õ® Õ¯Õ¡Õ¿Õ¥Õ£Õ¸Ö\80Õ«Õ¡ներ",
        "category-subcat-count": "{{PLURAL:$2|Այս ստորոգութիւնը ունի միայն հետեւեալ ենթաստորոգութիւնը։|Այս ստորոգութիւնը ունի հետեւեալ {{PLURAL:$1|ենթաստորոգութիւն|ենթաստորոգութիւններ}}ը՝ ընդհանուր $2էն։}}",
        "category-subcat-count-limited": "Այս ստորոգութիւնը ունի հետեւեալ {{PLURAL:$1|ենթաստորոգութիւն|$1 ենթաստորոգութիւններ}}։",
        "category-article-count": "{{PLURAL:$2|Այս ստորոգութիւնը կը պարունակէ միայն հետեւեալ էջը։|Ստորեւ այս ստորոգութեան ընդհանուր $2էն {{PLURAL:$1|էջը|$1 էջերը}}։}}",
        "category-article-count-limited": "Այս ստորոգութիւնի մէջ կը գտնուին հետեւեալ {{PLURAL:$1|էջը|$1 էջերը}}։",
        "category-file-count": "{{PLURAL:$2|Այս ստորոգութիւնը կը պարունակէ միայն հետեւեալ էջը։|Ստորեւ այս ստորոգութեան ընդհանուր $2-էն {{PLURAL:$1|էջը|$1 էջերը}}։}}",
-       "category-file-count-limited": "Ô±ÕµÕ½ Õ½Õ¿Õ¸Ö\80Õ¸Õ£Õ¸Ö\82Õ©Õ«Ö\82Õ¶Õ« մէջ կը գտնուին հետեւեալ  {{PLURAL:$1|նիշքը|$1 նիշքերը}}։",
+       "category-file-count-limited": "Ô±ÕµÕ½ Õ½Õ¿Õ¸Ö\80Õ¸Õ£Õ¸Ö\82Õ©Õ¥Õ¡Õ¶ մէջ կը գտնուին հետեւեալ  {{PLURAL:$1|նիշքը|$1 նիշքերը}}։",
        "listingcontinuesabbrev": "շար.",
        "index-category": "Չցուցակագրուած էջեր",
        "noindex-category": "Չցուցակագրուած էջեր",
        "views": "Տեսնուած",
        "toolbox": "Գործիքներ",
        "tool-link-userrights": "Փոխել {{GENDER:$1|գործածող}} խումբեր",
-       "tool-link-userrights-readonly": "Õ\8fÕ¥Õ½Õ¶Õ¡լ {{GENDER:$1|գործածող}} խումբեր",
+       "tool-link-userrights-readonly": "Õ\8fÕ¥Õ½Õ¶Õ¥լ {{GENDER:$1|գործածող}} խումբեր",
        "tool-link-emailuser": "Ղրկել ասիկա էլ-նամակով {{GENDER:$1|գործածողին}}",
        "imagepage": "Դիտել նիշքի էջը",
        "mediawikipage": "Դիտել հաղորդագրութեան էջը",
        "disclaimerpage": "Project:Պատասխանատուութեան ընդհանուր բացասում",
        "edithelp": "Խմբագրութեան ուղեցոյց",
        "helppage-top-gethelp": "Օգնութիւն",
-       "mainpage": "Գլխաւոր էջ",
-       "mainpage-description": "Գլխաւոր էջ",
+       "mainpage": "Գլխաւոր Էջ",
+       "mainpage-description": "Գլխաւոր Էջ",
+       "policy-url": "Project:Քաղաքականութիւն",
        "portal": "Համայնքային դարպաս",
        "portal-url": "Project:Համայնքային դարպաս",
        "privacy": "Սեփական տուեալներու պահպանման քաղաքականութիւն",
        "badaccess-group0": "Արտունութիւն չունիք այս գործողութիւնը կատարել:",
        "badaccess-groups": "Տուեալ գործողութիւնը միայն $1 {{PLURAL:$2|խումբի|խումբերի}} մասնակիցները կ՛րնան կատարել։",
        "ok": "Լաւ",
+       "pagetitle": "$1 - {{SITENAME}}",
        "retrievedfrom": "Վերցուած է «$1» էջէն",
        "youhavenewmessages": "{{PLURAL:$3|Դուք ունիք}} $1 ($2)։",
        "youhavenewmessagesfromusers": "{{PLURAL:$4|Դուք ունիք}} $1 {{PLURAL:$3|այլ մասնակից|$3 մասնակիցէն}} ($2):",
        "nstab-mediawiki": "Հաղորդագրութիւն",
        "nstab-template": "Կաղապար",
        "nstab-help": "Օգնութեան էջ",
-       "nstab-category": "Ստորոգութիւն",
-       "mainpage-nstab": "Գլխաւոր էջ",
+       "nstab-category": "Կատեգորիա",
+       "mainpage-nstab": "Գլխաւոր Էջ",
        "nosuchaction": "Այս գործողութիւնը չկայ",
        "nosuchspecialpage": "Այդպիսի յատուկ էջ չկայ",
        "nospecialpagetext": "<strong> Ձեր խնդրած յատուկ էջը անվաւեր է։</strong>\n\nՎաւերական յատուկ էջերու ցանկը կը գտնէք այստեղ՝ [[Special:SpecialPages|{{int:յատուկէջեր}}]].",
+       "error": "Սխալ",
        "databaseerror-query": "Հարցակէտ. $1",
        "databaseerror-function": "Գործառնութիւն. $1",
        "databaseerror-error": "Սխալ. $1",
        "viewsource": "Տեսնել աղբիւրը",
        "viewsource-title": "Տեսնել $1 էջի աղբիւրը",
        "viewsourcetext": "Կրնաք այս էջին աղբիւրը տեսնել ու ընդօրինակել։",
-       "yourname": "Գործածողի անուն.",
-       "userlogin-yourname": "Մասնակցային անուն",
-       "userlogin-yourname-ph": "Մուտքագրեցէ'ք ձեր մասնակցային անունը",
-       "createacct-another-username-ph": "Մուտքագրէք գործածողի անունը",
-       "yourpassword": "Գաղտնաբառ.",
+       "invalidtitle": "Անվաւեր վերնագիր",
+       "exception-nologin": "Դուք մուտք չէք գործած համակարգ",
+       "cannotlogoutnow-title": "Այժմ դուք չէք կրնար դուրս գալ",
+       "welcomeuser": "Բարի գալո՜ւստ, $1",
+       "welcomecreation-msg": "Ձեր հաշիւը ստեղծուած է։\nՉմոռնաք փոփոխել ձեր [[Special:Preferences|նախընտրութիւնները]]։",
+       "yourname": "Մասնակիցի անուն",
+       "userlogin-yourname": "Մասնակիցի անուն",
+       "userlogin-yourname-ph": "Մուտքագրեցէ'ք ձեր մասնակիցի անունը",
+       "createacct-another-username-ph": "Մուտքագրեցէ՛ք ձեր մասնակիցի անունը",
+       "yourpassword": "Անցաբառ՝",
        "userlogin-yourpassword": "Անցաբառ",
        "userlogin-yourpassword-ph": "Մուտքագրեցէ'ք ձեր անցաբառը",
-       "createacct-yourpassword-ph": "Մուտքագրեցէ'ք անցաբառ մը",
-       "yourpasswordagain": "Նորէն մուտքագրէք գաղտնաբառը",
-       "createacct-yourpasswordagain": "Հաստատեցէ'ք անցաբառը",
-       "createacct-yourpasswordagain-ph": "Դարձեալ մուտքագրեցէ'ք անցաբառը",
+       "createacct-yourpassword-ph": "Մուտքագրեցէ՛ք անցաբառ մը",
+       "yourpasswordagain": "Դարձեալ մուտքագրեցէ՛ք անցաբառը",
+       "createacct-yourpasswordagain": "Հաստատեցէ՛ք անցաբառը",
+       "createacct-yourpasswordagain-ph": "Դարձեալ մուտքագրեցէ՛ք անցաբառը",
        "userlogin-remembermypassword": "Մնալ համակարգին մէջ",
+       "cannotloginnow-title": "Այժմ դուք չէք կրնար մուտք գործել",
+       "cannotcreateaccount-title": "Չէք կրնար հաշիւներ ստեղծել",
+       "password-change-forbidden": "Այս Ուիքիին մէջ դուք չէք կրնար անցաբառեր փոխել։",
        "login": "Մուտք գործել",
+       "login-security": "Հաստատեցէէ՛ք Ձեր ինքնութիւնը",
+       "nav-login-createaccount": "Մուտք գործել/Հաշիւ ստեղծել",
+       "logout": "Դուրս գալ",
+       "userlogout": "Դուրս գալ",
+       "notloggedin": "Դուք մուտք չէք գործած համակարգ",
        "userlogin-noaccount": "Հաշիւ չունի՞ք։",
        "userlogin-joinproject": "Միացէ՛ք {{SITENAME}} նախագիծին",
        "createaccount": "Հաշիւ ստեղծել",
        "userlogin-resetpassword-link": "Անցաբառը մոռցա՞ծ էք",
        "userlogin-helplink2": "Մուտք գործելու օգնութիւն",
-       "createacct-emailoptional": "Իմակահասցէ (ոչ պարտադիր)",
-       "createacct-email-ph": "Մուտքագրեցէ՛ք ձեր իմակահասցէն",
+       "userlogin-createanother": "Այլ հաշիւ ստեղծել",
+       "createacct-emailrequired": "Ելեկտրոնային հասցէ",
+       "createacct-emailoptional": "Ելեկտրոնային հասցէ (ոչ պարտադիր)",
+       "createacct-email-ph": "Մուտքագրեցէ՛ք ձեր ելեկտրոնային հասցէն",
+       "createacct-another-email-ph": "Մուտքագրեցէ՛ք ձեր ելեկտրոնային հասցէն",
+       "createacct-realname": "Իրական անուն (ոչ պարտադիր)",
        "createacct-reason": "Պատճառ",
        "createacct-submit": "Ստեղծել ձեր հաշիւը",
+       "createacct-another-submit": "Հաշիւ ստեղծել",
+       "createacct-continue-submit": "Շարունակեցէ՛ք հաշիւի ստեղծումը",
+       "createacct-another-continue-submit": "Շարունակեցէ՛ք հաշիւի ստեղծումը",
        "createacct-benefit-heading": "{{SITENAME}}՝ ստեղծուած է ձեզի պէս մարդոց կողմէ։",
        "createacct-benefit-body1": "{{PLURAL:$1|խմբագրում}}",
        "createacct-benefit-body2": "$1 {{PLURAL:$1|էջ}}",
        "createacct-benefit-body3": "վերջին {{PLURAL:$1|մասնակից}}",
+       "badretype": "Ձեր նշած անցաբառերը իրարու չեն համապատասխաներ։",
+       "loginerror": "Մուտքի սխալ",
+       "createacct-error": "Հաշուի ստեղծման սխալ",
        "loginsuccesstitle": "Բարեյաջող մուտք",
        "loginsuccess": "'''Դուք մուտք գործեցիք {{SITENAME}}, իբր \"$1\"։'''",
        "nouserspecified": "Հարկաւոր է նշել մասնակցին անունը։",
        "password-login-forbidden": "Այս մասնակիցի անունը եւ գաղտաբարի օգտագործումը արգիլուած է:",
        "mailmypassword": "Վերականգնել գաղտնաբառը",
        "passwordremindertitle": "Նոր ժամանակաւոր գաղտնաբառ {{grammar:genitive|{{SITENAME}}}} համար",
+       "emailconfirmlink": "Հաստատեցէ՛ք ձեր ելեկտրոնային հասցէն",
        "accountcreated": "Հաշիւը ստեղծուեցաւ:",
        "loginlanguagelabel": "Լեզու՝ $1",
        "pt-login": "Մուտք գործել",
        "pt-userlogout": "Դուրս գալ",
        "php-mail-error-unknown": "Անյայտ սխալ PHP-ի mail() կախարկութեան մէջ:",
        "changepassword": "Գաղտնաբառը փոխել",
-       "newpassword": "Նոր գաղտնաբառը.",
+       "resetpass_header": "Փոխել հաշիւի անցաբառը",
+       "oldpassword": "Հին անցաբառը.",
+       "newpassword": "Նոր անցաբառը.",
        "retypenew": "Նորէն մուտքագրէք գաղտնաբառը",
-       "changepassword-success": "Ձեր գաղտնաբառը փոխուեցաւ։",
+       "resetpass_submit": "Հաստատեցէ՛ք անցաբառը եւ մուտք գործեցէ՛ք համակարգ",
+       "changepassword-success": "Ձեր անցաբառը փոխուեցաւ։",
+       "botpasswords-label-appid": "Մեքենայիկի անուն՝",
        "botpasswords-label-create": "Ստեղծել",
+       "botpasswords-label-update": "Թարմացնել",
        "botpasswords-label-cancel": "Չեղարկել",
        "botpasswords-label-delete": "Ջնջել",
        "botpasswords-label-resetpassword": "Վերականգնել գաղտնաբառը",
+       "botpasswords-label-grants-column": "Արտօնութիւնը տրուած է",
+       "botpasswords-bad-appid": "\"$1\" մեքենայիկին անունը չէ վաւերացուած:",
+       "botpasswords-created-title": "Մեքենայիկին անցաբառը ստեղծուեցաւ",
+       "botpasswords-deleted-title": "Մեքենայիկին անցաբառը ջնջուեցաւ",
+       "resetpass_forbidden": "Անցաբառերը չեն կրնար փոխել",
+       "resetpass-submit-loggedin": "Անցաբառը փոխել",
        "resetpass-submit-cancel": "Չեղարկել",
        "resetpass-temp-password": "Ժամանակաւոր գաղտնաբառ.",
        "passwordreset": "Վերականգնել անցաբառը",
+       "passwordreset-username": "Մասնակիցի անուն՝",
        "passwordreset-domain": "Համակարգիչի պետութիւն.",
-       "passwordreset-email": "Ô·Õ¬-Õ¶Õ¡Õ´Õ¡Õ¯Õ¡Õ« Õ°Õ¡Õ½Ö\81Õ§Õ¶.",
+       "passwordreset-email": "ÔµÕ¬Õ¥Õ¯Õ¿Ö\80Õ¸Õ¶Õ¡ÕµÕ«Õ¶ Õ°Õ¡Õ½Ö\81Õ§â\80¤",
        "passwordreset-emailtitle": "{{SITENAME}} հաշիւի մանրամասները",
+       "passwordreset-invalidemail": "Անվաւեր ելեկտրոնային հասցէ",
+       "changeemail": "Փոխել կամ հանել ելեկտրոնային հասցէն",
+       "changeemail-oldemail": "Այժմու ելեկտրոնային հասցէ․",
+       "changeemail-newemail": "Նոր ելեկտրոնային հասցէ․",
+       "changeemail-none": "(ոչ մէկ)",
+       "changeemail-password": "Ձեր {{SITENAME}} անցաբառը՝",
+       "changeemail-submit": "Փոխել ելեկտրոնային հասցէն",
        "bold_sample": "Շեշտուած տառերով գրութիւն",
        "bold_tip": "Շեշտուած տառերով գրութիւն",
        "italic_sample": "Շեղատառ գրութիւն",
        "headline_tip": "Երկրորդ մակարդակի վերնագիր",
        "nowiki_sample": "Մուտքագրեցէ՛ք չձեւաւորուած գրութիւնը այստեղ",
        "nowiki_tip": "Անտեսել ուիքի ձեւաւորումը",
+       "image_sample": "Օրինակ.jpg",
        "image_tip": "Ներփակ նիշք",
+       "media_sample": "Օրինակ.jpg",
        "media_tip": "Նիշքին յղումը",
        "sig_tip": "Ձեր ստորագրութիւնը ժամակնիքով",
        "hr_tip": "Հորիզոնական գիծ (գործածել խնայողաբար)",
        "preview": "Կանխաստուգել",
        "showpreview": "Կանխաստուգել",
        "showdiff": "Ցուցնել փոփոխութիւնները",
-       "anoneditwarning": "<strong>Զգուշացում։</strong> Մուտք գործած չէք համակարգ։ Որեւէ խմբագրումի պարագային ձեր IP հասցէն տեսանելի կը դառնայ բոլորին։ Եթե <strong>[$1 մուտք գործէք]</strong> կամ <strong>[$2 ստեղծէք մասնակցային հաշիւ]</strong>, ձեր կատարած խմբագրումները կը կապուին ձեր մասնակցային անունին հետ, ինչպէս նաեւ կ՚ունենաք այլ առաւելութիւններ։",
-       "blockedtext": "<strong>Ձեր մասնակցային անոիւնը կամ IP հասցէն արգելակուած է։</strong>\n\nԱրգելակումը կատարուած է $1ի կողմէ.\nՊարտճառը՝ <em>$2</em>.\n\n* Արգելակման սկիբժ՝ $8\n* Արգելակման աւարտ՝ $6\n* արգելակուած առարկայ՝ $7\n\nԿրնաք կապուիլ $1ի կամ այլ անդատներու հետ [[{{MediaWiki:Grouppage-sysop}}|վարիչ]] արգելակման մասին զրուցելու համար.\nՉէք կրնար օգտագործել \"{{int:emailuser}}\" հնարաւորութիւնը բացի եթէ նշած էք իմակի վաւերական հասցէ մը ձեր [[Special:Preferences|account preferences]] եւ արգելակուած չէ վեր անոր օգտագործումը.\nՁեր ընթացիկ IP հասցէն է $3, եւ արգելակման ինքնութեան համարն է #$5.\nԿը շնդրենք որ այս մանրամասնութիւնները նշէք ձեր բոլոր թղթակցութիւններուն մէջ։",
-       "loginreqlink": "մուտք գործել",
+       "anoneditwarning": "<strong>Զգուշացում։</strong> Մուտք գործած չէք համակարգ։ Որեւէ խմբագրումի պարագային ձեր IP հասցէն տեսանելի կը դառնայ բոլորին։ Եթէ <strong>[$1 մուտք գործէք]</strong> կամ <strong>[$2 ստեղծէք մասնակիցի հաշիւ]</strong>, ձեր կատարած խմբագրումները կը կապուին ձեր մասնակիցի անունին հետ, ինչպէս նաեւ կ՚ունենաք այլ առաւելութիւններ։",
+       "blockedtitle": "Մասնակիցը արգելափակուած է",
+       "blockedtext": "<strong>Ձեր մասնակցային անունը կամ IP հասցէն արգելակուած է։</strong>\n\nԱրգելակումը կատարուած է $1ի կողմէ.\nՊարտճառը՝ <em>$2</em>.\n\n* Արգելակման սկիբժ՝ $8\n* Արգելակման աւարտ՝ $6\n* արգելակուած առարկայ՝ $7\n\nԿրնաք կապուիլ $1ի կամ այլ անդատներու հետ [[{{MediaWiki:Grouppage-sysop}}|վարիչ]] արգելակման մասին զրուցելու համար.\nՉէք կրնար օգտագործել \"{{int:emailuser}}\" հնարաւորութիւնը բացի եթէ նշած էք իմակի վաւերական հասցէ մը ձեր [[Special:Preferences|account preferences]] եւ արգելակուած չէ վեր անոր օգտագործումը.\nՁեր ընթացիկ IP հասցէն է $3, եւ արգելակման ինքնութեան համարն է #$5.\nԿը շնդրենք որ այս մանրամասնութիւնները նշէք ձեր բոլոր թղթակցութիւններուն մէջ։",
+       "loginreqtitle": "Կը խնդրուի մուտք գործել համակարգ",
+       "loginreqlink": "Մուտք գործել",
+       "newarticle": "(Նոր)",
        "newarticletext": "Դուք յղուած էք տակաւին գոյութիւն չունեցող էջի մը։\nԷջը ստեղծելու համար, մեքենագրեցէք ներքեւի տուփիկին մէջ (յաւելեալ տեղեկութեանց համար տե՛ս [$1 օգնութեան ցուցմունքներու էջը])։\nԵթէ սխալմամբ հոս հասած էք, սեղմել դիտարկիչի <strong>ետ</strong> կոճակը։",
        "anontalkpagetext": "<em> Այս էջը առայժմ հաշիւ չստեղծած, կամ հաշիւ չօգտագործող, անանուն մասնակիցներու քննարկման էջն է։</em>\nՈւրեմն որպէս ինքնութիւն ստիպուած ենք օգտագործել անոնց IP հասցէն։\nԱյսպիսի IP հասցէ կրնան ունենալ մէկէ աւելի մասնակիցներ։\nԵթէ դուք անանուն մասնակից էք եւ կը խորհիք որ անկապ դիտողութիւններու թիրախ դարձած էք, կը խնդրուի [[Special:CreateAccount|Հաշիւ ստեղծել]] կամ [[Special:UserLogin|մուտք գործել]] խուսափելու համար ապագային այլ անդանուն մասնակիցներու հետ շփոթուելու հնարաւորութենէն։",
        "noarticletext": "Ներկայիս այս էջին վրայ որեւէ գրութիւն չկայ։\nԴուք կրնաք [[Special:Search/{{PAGENAME}}|որոնել այս անուանումը]] այլ էջերու մէջ, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} որոնել համապատասխան տեղեկամատեանները] կամ [{{fullurl:{{FULLPAGENAME}}|action=edit}} ստեղծել նոր էջ այս անուանումով]</span>։",
        "noarticletext-nopermission": "Ներկայիս այս էջին վրայ որեւէ գրութիւն չկայ։\nԿրնաք [[Special:Search/{{PAGENAME}}|այս վերնագիրով էջը որոնել]] այլ էջերու մէջ, կամ <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} որոնել համապատասխան տեղեկատետրերը], սակայն իրաւունք չունիք այս էջը ստեղծելու։",
        "userpage-userdoesnotexist-view": "«$1» անունով գրանցուած մասնակից չկայ։",
        "clearyourcache": "<strong>Նշում՝</strong> Պահելէ ետք կրնայ ըլլալ որ պէտք ունենաք մաքրելու դիտարկիչին պաշարը (cache) փոփոխութիւնները կարենալ տեսնելու համար։\n* <strong>Firefox / Safari:</strong> Սեղմած պահել <em>Shiftը</em> մինչ կը սեղմէք  <em>Reload</em>, կամ ալ սեղմել <em>Ctrl-F5</em> կամ <em>Ctrl-R</em> (<em>⌘-R</em> Macի վրայ)\n* <strong>Google Chrome:</strong> Սեղմել <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> Macի վրայ)\n* <strong>Internet Explorer:</strong> Սեղմած պահել <em>Ctrl</em> մինչ կը սեղմէք  <em>Refresh</em>, կամ ալ սեղմել <em>Ctrl-F5</em>\n* <strong>Opera:</strong> Երթալ <em>Menu → Settings</em> (<em>Opera → Preferences</em> Macի վրայ) եւ ապա <em>Privacy & security → մաքրել թերթատման տեղեկութիւնները → Պաշարի մէջ դրուած նկարներ եւ նիշքեր</em>.",
+       "updated": "(Թարմացուած)",
        "previewnote": "<strong>Յիշել որ ասիկա միայն կանխաստուգում է. ձեր կատարած փոփոխութիւնները տակաւին չեն պահուած։<strong>",
        "continue-editing": "Շարունակել խմբագրել",
        "editing": "Կը խմբագրուի՝ $1 էջը",
        "creating": "«$1» էջի ստեղծում",
        "editingsection": "$1 բաժինի խմբագրում",
+       "yourtext": "Ձեր գրութիւնը",
+       "storedversion": "Պահուած տարբերակ",
        "yourdiff": "Տարբերութիւններ",
        "templatesused": "Այս էջին մէջ օգտագործուած {{PLURAL:$1|կաղապարը|կաղապարները}}.",
        "templatesusedpreview": "{{PLURAL:$1|Կաղապար}} օգտագործուած այս կանխաստուգումին մէջ՝",
        "recreate-moveddeleted-warn": "<strong>Զգուշացում. Նախապէս ջնջուած էջ մը պիտի վերստեղծուի։<strong>\n\nԿը խնդրուի մտածել այս էջի խմբագրման նպատակայարմարութեան մասին։ \nՁեր դիւրութեան համար ներքեւ կը գտնէք այս էջի ջնջումին և տեղափոխումին տեղեկատետրերը։",
        "moveddeleted-notice": "Այս էջը ջնջուած է։\nԷջին ջնջումի, պահպանումի եւ փոխադրումի տեղեկատետրը տրամադրելի է ներքեւ որպէս տեղեկութիւն։",
        "edit-conflict": "Խմբագրման ընհարում։",
+       "postedit-confirmation-created": "Էջը ստեղծուած է։",
+       "postedit-confirmation-saved": "Ձեր խմբագրումը պահուած է:",
+       "postedit-confirmation-published": "Ձեր խմբագրումը հրատարակուած է:",
+       "slot-name-main": "Գլխաւոր",
        "content-model-wikitext": "ուիքիթէքսթ",
        "content-model-text": "պարզ բնաբան",
        "content-model-javascript": "ՃաւաՍքրիփթ",
        "history-fieldset-title": "Որոնել տարբերակներ",
        "histfirst": "հնագոյն",
        "histlast": "նորագոյն",
+       "historyempty": "պարապ",
        "history-feed-title": "Վերանայումներու ցուցակ",
        "history-feed-description": "Ուիքիի այս էջին վերանայումներու ցուցակը",
        "history-feed-item-nocomment": "$1՝ $2",
        "rev-delundel": "ցուցնել/թաքցնել",
        "rev-showdeleted": "Ցուցադրել",
        "revdelete-show-file-submit": "Այո",
+       "revdelete-hide-image": "Թաքցնել նիշքին բովանդակութիւնը",
+       "revdelete-radio-unset": "Տեսանելի",
        "revdelete-log": "Պատճառ.",
+       "pagehist": "Էջի պատմութիւն",
        "revdelete-reasonotherlist": "Ուրիշ պատճառ.",
+       "revdelete-edit-reasonlist": "Խմբագրել ջնջման պատճառները",
        "mergehistory-reason": "Պատճառ.",
        "mergelog": "Ձուլման տեղեկատետր",
        "history-title": "«$1»ի վերանայումներու ցուցակ",
        "diff-multi-otherusers": "(նոյն մասնակիցի ցոյց չտրուած {{PLURAL:$1|մէկ միջանկեալ վերանայում|$2 միջանկեալ վերանայումներ}})",
        "searchresults": "Որոնման արդիւնքներ",
        "searchresults-title": "«$1»-ի որոնման արդիւնքները",
+       "notextmatches": "Չկան համապատասխան գրութիւնով էջեր",
        "prevn": "նախորդ {{PLURAL:$1|$1}}",
        "nextn": "յաջորդ {{PLURAL:$1|$1}}",
        "prev-page": "նախորդ էջ",
        "search-result-category-size": "{{PLURAL:$1|1 անդամ|$1 անդամներ}} ({{PLURAL:$2|1 ենթաստորոգութիւն|$2 ենթաստորոգութիւններ}}, {{PLURAL:$3|1 նիշք|$3 նիշքեր}})",
        "search-redirect": "(Վերայղուած է $1-էն)",
        "search-section": "(բաժին $1)",
-       "search-category": "(Õ½Õ¿Õ¸Ö\80Õ¸Õ£Õ¸Ö\82Õ©Õ«Ö\82Õ¶ $1)",
+       "search-category": "(Õ¯Õ¡Õ¿Õ¥Õ£Õ¸Ö\80Õ«Õ¡ $1)",
        "search-file-match": "(համապատասխան է նիշքի բովանդակութեան)",
        "search-suggest": "$1 Նկատի ունի՞ք",
+       "search-interwiki-default": "$1 արդիւնք.",
        "search-interwiki-more": "(աւելի)",
        "search-interwiki-more-results": "աւելի շատ արդիւնքներ",
        "search-relatedarticle": "Հարակից",
        "searchall": "բոլոր",
        "search-showingresults": "{{PLURAL:$4|<strong>$1</strong> արդիւնք <strong>$3</strong>-էն|<strong>$1 - $2</strong> արդիւնքներ <strong>$3</strong>-էն}}",
        "search-nonefound": "Որոնումին համապատասխանող արդիւնքներ չգտնուեցան",
+       "powersearch-toggleall": "Բոլոր",
+       "powersearch-togglenone": "Ոչ մէկ",
+       "search-external": "Արտաքին որոնում",
+       "preferences": "Նախընտրութիւններ",
        "mypreferences": "Նախընտրութիւններ",
        "skin-preview": "Նախադիտել",
+       "prefs-watchlist": "Հսկողութեան ցանկ",
+       "prefs-editwatchlist-clear": "Մաքրել հսկողութեան ցանկը",
+       "saveprefs": "Յիշել",
+       "searchresultshead": "Որոնել",
        "stub-threshold-sample-link": "օրինակ",
        "timezoneregion-africa": "Ափրիկէ",
        "timezoneregion-america": "Ամերիկա",
        "timezoneregion-europe": "Եւրոպա",
        "timezoneregion-indian": "Հնդկական Ովկիանոս",
        "timezoneregion-pacific": "Խաղաղ Ովկիանոս",
-       "youremail": "Էլեկտրական Նամակ",
-       "email": "Էլեկտրական Նամակ",
+       "prefs-searchoptions": "Որոնել",
+       "prefs-namespaces": "Անուանատարածքներ",
+       "default": "լռելեան",
+       "youremail": "Ելեկտրոնային նամակ․",
+       "yourlanguage": "Լեզու.",
+       "email": "Ելեկտրոնային նամակ",
+       "prefs-info": "Հիմնական տուեալներ",
+       "prefs-signature": "Ստորագրութիւն",
+       "prefs-editor": "Խմբագրող",
+       "prefs-preview": "Նախադիտել",
        "group": "Խումբ.",
        "group-bot": "Մեքենայիկներ",
        "group-sysop": "Վարիչներ",
+       "group-sysop-member": "{{GENDER:$1|վարիչ}}",
        "grouppage-bot": "{{ns:project}}:Մեքենայիկներ",
        "grouppage-sysop": "{{ns:project}}:Վարիչներ",
        "right-writeapi": "API գիրի օգտագործումը",
        "recentchanges-label-plusminus": "Էջին ծաւալը փոխուեցաւ այսքան պայթով",
        "recentchanges-legend-heading": "<strong>Ծանօթ.՝</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (տե՛ս նաեւ՝  [[Special:NewPages|նոր էջերու ցանկ]])",
+       "rcfilters-activefilters": "Աշխոյժ զտիչներ",
+       "rcfilters-limit-title": "Ցուցադրուող արդիւնքներ",
        "rcnotefrom": "Ներքեւ {{PLURAL:$5|փոփոխութիւնն է|փոփոխութիւններն են}} սկսեալ <strong>$3, $4</strong> (մինչեւ <strong>$1</strong> ցոյց տրուած).",
        "rclistfrom": "Ցոյց տալ նոր փոփոխութիւնները սկսած $3 $2",
        "rcshowhideminor": "$1 չնչին խմբագրումներ",
        "upload-disallowed-here": "Այս նիշքը կարելի չէ ջնջել ու փոխարինել։",
        "randompage": "Պատահական էջ",
        "statistics": "Վիճակագրութիւն",
+       "statistics-header-pages": "Էջերու վիճակագրութիւն",
+       "statistics-header-edits": "Խմբագրումներու վիճակագրութիւն",
+       "statistics-header-users": "Մասնակիցներու վիճակագրութիւն",
+       "statistics-pages-desc": "Ուիքիի բոլոր էջերը՝ ներառեալ քննարկման էջերը, վերայղումները եւ այլն",
+       "statistics-files": "Բեռնուած նիշքեր",
+       "statistics-edits-average": "Իւրաքանչիւր էջի խմբագրումներուն միջին թիւը",
+       "statistics-users-active": "Աշխոյժ մասնակիցներ",
        "double-redirect-fixer": "Վերայղումներու շտկիչ",
        "nbytes": "$1 {{PLURAL:$1|պայթ}}",
        "nmembers": "$1 {{PLURAL:$1|անդամ|անդամներ}}",
        "move": "Տեղափոխել այս էջը",
        "pager-newer-n": "{{PLURAL:$1|նոր 1|աւելի նոր $1}}",
        "pager-older-n": "{{PLURAL:$1|աւելի հին 1|աւելի հին $1}}",
+       "apisandbox-results": "Արդիւնքներ",
        "booksources": "Գիրքի աղբիւրներ",
        "booksources-search-legend": "Որոնել գիրքի մասին",
        "booksources-search": "Որոնել",
        "allpagessubmit": "‎Յառաջանալ",
        "allpages-hide-redirects": "Թաքցնել վերայղումները",
        "categories": "Ստորոգութիւններ",
+       "activeusers": "Աշխոյժ մասնակիցներու ցանկ",
+       "activeusers-submit": "Ցոյց տալ աշխոյժ մասնակիցները",
        "listgrouprights-members": "(անդամներու ցանկ)",
-       "emailuser": "էլ-նամակ ուղարկել այս մասնակիցին",
+       "emailuser": "Ե-նամակ ուղարկել այս մասնակիցին",
        "usermessage-editor": "Համակարգային սուրհանդակի անուն",
        "watchlist": "Հսկողութեան ցանկ",
        "mywatchlist": "Հսկողութեան ցանկ",
        "tooltip-diff": "Ցոյց տալ ձեր կատարած փոփոխութիւնները գրութեան մէջ",
        "tooltip-compareselectedversions": "Տեսնել այս էջին ընտրուած երկու տարբերակներուն միջեւ տարբերութիւնները",
        "tooltip-watch": "Աւելցնել այս էջը ձեր հսկողութեան ցանկին վրայ",
+       "tooltip-watchlistedit-raw-submit": "Թարմացնել Հսկացանկը",
        "tooltip-rollback": "«Յետարկում»ը մէկ սեղմումով վերջին մասնակիցին կատարած բոլոր խմբագրումները ետ կ՚ընէ",
        "tooltip-undo": "«Յետարկել»ը կը շրջէ կատարուած փոփոխութիւնը եւ խմբագրումը կը տրամադրէ կանխաստուգման վիճակով, թոյլ տալով նշել պատճառը ամփոփումին մէջ։",
        "tooltip-summary": "Մուտքագրեցէ՛ք հակիրճ ամփոփում մը",
        "imgmultipagenext": "յաջորդ էջը →",
        "imgmultigo": "Անցնի՛լ",
        "imgmultigoto": "Անցնիլ $1 էջը",
+       "watchlistedit-raw-submit": "Թարմացնել Հսկացանկը",
+       "watchlistedit-clear-title": "Մաքրել հսկողութեան ցանկը",
+       "watchlistedit-clear-legend": "Մաքրել հսկողութեան ցանկը",
        "watchlisttools-clear": "Մաքրել հսկողութեան ցանկը",
        "watchlisttools-view": "Ցուցադրել փոփոխութիւնները",
        "watchlisttools-edit": "Տեսնել եւ խմբագրել հսկողութեան ցանկը",
        "logentry-delete-delete": "$1 {{GENDER:$2|ջնջեց}} $3 էջը",
        "logentry-delete-restore": "$1 {{GENDER:$2|վերականգնեց}} $3 ($4) էջը",
        "logentry-delete-revision": "$1 {{GENDER:$2|փոխեց}} {{PLURAL:$5|1 խմբագրման|$5 խմբագրումներու}} տեսանելիութիւնը $3 էջին վրայ՝ $4",
-       "revdelete-content-hid": "բովանդակութիւնը թաքնուած",
+       "revdelete-content-hid": "Թաքուն բովանդակութիւն",
        "logentry-move-move": "$1 տեղափոխեց էջը «$3»-էն «$4»",
        "logentry-move-move-noredirect": "$1ը {{GENDER:$2|տեղափոխեց}} էջ $3էն էջ $4 առանց վերայղում ձգելու",
        "logentry-move-move_redir": "$1 {{GENDER:$2|տեղափոխեց}} էջ $3ը վերայղելով դէպի էջ $4",
        "logentry-newusers-autocreate": "$1 մասնակցային հաշիւը {{GENDER:$2|ստեղծուած է}} ինքնաբերաբար",
        "logentry-upload-upload": "$1 {{GENDER:$2|ներբեռնուած է}} $3",
        "logentry-upload-overwrite": "$1 {{GENDER:$2|վերբեռնեց}} $3ի նոր տարբերակ",
+       "feedback-cancel": "Չեղարկել",
        "searchsuggest-search": "Որոնել {{SITENAME}} կայքին մէջ",
        "duration-days": "$1 {{PLURAL:$1|օր}}",
+       "special-characters-group-latin": "Լատիներէն",
+       "special-characters-group-arabic": "Արաբերէն",
        "randomrootpage": "Պատահական արմատ էջ"
 }
index 02a2b82..1b95b4e 100644 (file)
        "page_first": "prime",
        "page_last": "ultime",
        "histlegend": "Pro comparar duo versiones: marca lor circulos correspondente, e preme <code>Enter</code> o clicca le button in basso.<br />\nLegenda: '''({{int:cur}})''' = comparar con le version actual,\n'''({{int:last}})''' = comparar con le version precedente, '''{{int:minoreditletter}}''' = modification minor.",
-       "history-fieldset-title": "Cercar versiones",
+       "history-fieldset-title": "Filtrar versiones",
        "history-show-deleted": "Solmente versiones delite",
        "histfirst": "le plus ancian",
        "histlast": "le plus nove",
        "historysize": "({{PLURAL:$1|1 byte|$1 bytes}})",
-       "historyempty": "(vacue)",
+       "historyempty": "vacue",
        "history-feed-title": "Historia de versiones",
        "history-feed-description": "Historia del versiones de iste pagina in le wiki",
        "history-feed-item-nocomment": "$1 a $2",
        "right-reupload-own": "Superscriber un file anteriormente incargate per uno mesme",
        "right-reupload-shared": "Supplantar localmente le files del respositorio commun de media",
        "right-upload_by_url": "Incargar un file ab un adresse URL",
-       "right-purge": "Purgar le cache de un pagina in le sito sin confirmation",
+       "right-purge": "Purgar le cache de un pagina in le sito",
        "right-autoconfirmed": "Non esser subjecte al limites de frequentia a base de adresse IP",
        "right-bot": "Esser tractate como processo automatic",
        "right-nominornewtalk": "Non reciper notification de nove messages quando se face modificationes minor in le pagina de discussion",
        "right-deletedtext": "Vider texto delite e differentias inter versiones delite",
        "right-browsearchive": "Cercar paginas delite",
        "right-undelete": "Restaurar un pagina",
-       "right-suppressrevision": "Vider, celar e revelar versiones specific de paginas de qualcunque usator",
-       "right-viewsuppressed": "Vider versiones celate de qualcunque usator",
+       "right-suppressrevision": "Vider, celar e revelar versiones specific de paginas pro qualcunque usator",
+       "right-viewsuppressed": "Vider versiones celate pro tote le usatores",
        "right-suppressionlog": "Vider registros private",
        "right-block": "Blocar altere usatores de facer modificationes",
        "right-blockemail": "Blocar un usator de inviar e-mail",
        "action-changetags": "adder e remover qualcunque etiquettas sur individual versiones e entratas de registro",
        "action-deletechangetags": "deler etiquettas del base de datos",
        "action-purge": "purgar iste pagina",
+       "action-apihighlimits": "usar limites plus alte in consultas via API",
+       "action-autoconfirmed": "non esser subjecte al limites de frequentia a base de adresse IP",
+       "action-bigdelete": "deler paginas con historias longe",
+       "action-blockemail": "blocar un usator de inviar e-mail",
+       "action-bot": "esser tractate como processo automatic",
+       "action-editprotected": "modificar paginas protegite con \"{{int:protect-level-sysop}}\"",
+       "action-editsemiprotected": "modificar paginas protegite como \"{{int:protect-level-autoconfirmed}}\"",
+       "action-editinterface": "modificar le interfacie de usator",
+       "action-editusercss": "modificar le files CSS de altere usatores",
+       "action-edituserjson": "modificar le files JSON de altere usatores",
+       "action-edituserjs": "modificar le files JavaScript de altere usatores",
+       "action-editsitecss": "modificar le CSS global del sito",
+       "action-editsitejson": "modificar le JSON global del sito",
+       "action-editsitejs": "modificar le JavaScript global del sito",
+       "action-editmyusercss": "modificar le files CSS del proprie usator",
+       "action-editmyuserjson": "modificar le files JSON del proprie usator",
+       "action-editmyuserjs": "modificar le files JavaScript del proprie usator",
+       "action-viewsuppressed": "vider versiones celate pro tote le usatores",
+       "action-hideuser": "blocar un nomine de usator, celante lo del publico",
+       "action-ipblock-exempt": "contornar le blocadas de adresses IP, blocadas automatic e blocadas de intervallos IP",
+       "action-unblockself": "disblocar te mesme",
+       "action-noratelimit": "non esser subjecte al limites de frequentia de actiones",
+       "action-reupload-own": "superscriber un file anteriormente incargate per te mesme",
+       "action-nominornewtalk": "non reciper notification de nove messages quando tu face modificationes minor in le pagina de discussion",
+       "action-markbotedits": "marcar modificationes de reversion como facite per un bot",
+       "action-patrolmarks": "vider marcas de patrulia in le modificationes recente",
+       "action-override-export-depth": "exportar paginas includente paginas ligate usque a un profunditate de 5",
+       "action-suppressredirect": "non rediriger le ancian nomine verso le nove quando se renomina un pagina",
        "nchanges": "$1 {{PLURAL:$1|modification|modificationes}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|desde le ultime visita}}",
        "enhancedrc-history": "historia",
        "rcfilters-savedqueries-already-saved": "Iste filtros es jam salveguardate. Cambia tu configuration pro crear un nove filtro salveguardate.",
        "rcfilters-restore-default-filters": "Restaurar filtros predefinite",
        "rcfilters-clear-all-filters": "Rader tote le filtros",
-       "rcfilters-show-new-changes": "Vider le modificationes le plus recente",
+       "rcfilters-show-new-changes": "Vider le modificationes apportate desde $1",
        "rcfilters-search-placeholder": "Filtrar le modificationes (usa le menu o cerca le nomine del filtro)",
        "rcfilters-invalid-filter": "Filtro non valide",
        "rcfilters-empty-filter": "Nulle filtro active. Tote le contributiones es monstrate.",
        "rcfilters-filter-editsbyself-description": "Tu proprie contributiones.",
        "rcfilters-filter-editsbyother-label": "Modificationes facite per alteres",
        "rcfilters-filter-editsbyother-description": "Tote le modificationes excepte le tues.",
-       "rcfilters-filtergroup-userExpLevel": "Registration e experientia del usator",
+       "rcfilters-filtergroup-user-experience-level": "Registration e experientia del usator",
        "rcfilters-filter-user-experience-level-registered-label": "Registrate",
        "rcfilters-filter-user-experience-level-registered-description": "Redactores que ha aperite session.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Non registrate",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Le filtro \"Modificationes minor\" es in conflicto con un o plure filtros \"Typo de cambiamento\", perque certe typos de cambiamento non pote esser assignate como \"minor\". Le filtros in conflicto es marcate in le area \"Filtros active\" supra.",
        "rcfilters-hideminor-conflicts-typeofchange": "Certe typos de cambiamento non pote esser assignate como \"minor\", dunque iste filtro es in conflicto con le sequente filtros \"Typo de cambiamento\": $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Iste filtro \"Typo de cambiamento\" es in conflicto con le filtro \"Modificationes minor\". Certe typos de cambiamento non pote esser assignate como \"minor\".",
-       "rcfilters-filtergroup-lastRevision": "Ultime versiones",
+       "rcfilters-filtergroup-lastrevision": "Ultime versiones",
        "rcfilters-filter-lastrevision-label": "Ultime version",
        "rcfilters-filter-lastrevision-description": "Solmente le modification le plus recente de un pagina.",
        "rcfilters-filter-previousrevision-label": "Non le ultime version",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[observate per $1 {{PLURAL:$1|usator|usatores}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} post cambio",
        "newsectionsummary": "/* $1 */ nove section",
        "rc-enhanced-expand": "Revelar detalios",
        "img-auth-nopathinfo": "Le information sur le percurso manca.\nLe servitor debe esser configurate pro passar le variabiles REQUEST_URI e/o PATH_INFO.\nSi illo lo es, essaya activar $wgUsePathInfo.\nVide https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Le cammino requestate non es in le directorio de incargamentos configurate.",
        "img-auth-badtitle": "Impossibile construer un titulo valide ex \"$1\".",
-       "img-auth-nologinnWL": "Tu non ha aperite un session e \"$1\" non es in le lista blanc.",
        "img-auth-nofile": "File \"$1\" non existe.",
        "img-auth-isdir": "Tu tenta acceder a un directorio \"$1\".\nSolmente le accesso a files es permittite.",
        "img-auth-streaming": "Fluxo de \"$1\" comenciate.",
        "delete-confirm": "Deler \"$1\"",
        "delete-legend": "Deler",
        "historywarning": "<strong>Attention:</strong> Le pagina que tu vole deler ha un historia de circa $1 {{PLURAL:$1|version|versiones}}:",
-       "historyaction-submit": "Monstrar",
+       "historyaction-submit": "Monstrar versiones",
        "confirmdeletetext": "Tu va deler un pagina con tote su historia.\nPer favor confirma que tu ha le intention de facer isto, que tu comprende le consequentias, e que tu face isto in accordo con [[{{MediaWiki:Policy-url}}|le politicas]].",
        "actioncomplete": "Action complete",
        "actionfailed": "Action fallite",
        "deleting-backlinks-warning": "<strong>Attention:</strong> Il ha [[Special:WhatLinksHere/{{FULLPAGENAME}}|altere paginas]] que liga a o transclude le pagina que tu es sur le puncto de deler.",
        "deleting-subpages-warning": "<strong>Attention:</strong> Le pagina que tu es sur le puncto de deler ha [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|un subpagina|$1 subpaginas|51=plus de 50 subpaginas}}]].",
        "rollback": "Revocar modificationes",
+       "rollback-confirmation-confirm": "Per favor confirma:",
+       "rollback-confirmation-yes": "Revocar",
+       "rollback-confirmation-no": "Cancellar",
        "rollbacklink": "revocar",
        "rollbacklinkcount": "revocar $1 {{PLURAL:$1|modification|modificationes}}",
        "rollbacklinkcount-morethan": "revocar plus de $1 {{PLURAL:$1|modification|modificationes}}",
        "revertpage": "Reverteva modificationes per [[Special:Contributions/$2|$2]] ([[User talk:$2|Discussion]]) al ultime version per [[User:$1|$1]]",
        "revertpage-nouser": "Reverteva modificationes per un usator celate al ultime version per {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Revocava modificationes per {{GENDER:$3|$1}};\nretornava al version per {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Modificationes de $1 revertite;\nultime version de $2 restaurate. [$3 Monstrar cambiamentos]",
        "sessionfailure-title": "Error de session",
        "sessionfailure": "Il pare haber un problema con tu session;\niste action ha essite cancellate como precaution contra le robamento de sessiones.\nPer favor, resubmitte le formulario.",
        "changecontentmodel": "Cambiar le modello de contento de un pagina",
        "mycontris": "Contributiones",
        "anoncontribs": "Contributiones",
        "contribsub2": "Pro {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "Pro {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "Le conto de usator \"$1\" non es registrate.",
        "negative-namespace-not-supported": "Le spatios de nomines con valores negative non es supportate.",
        "nocontribs": "Nulle modification correspondente a iste criterios ha essite trovate.",
        "blocklist-userblocks": "Celar blocadas de conto",
        "blocklist-tempblocks": "Celar blocadas temporari",
        "blocklist-addressblocks": "Celar blocadas de singule adresse IP",
+       "blocklist-type": "Typo:",
+       "blocklist-type-opt-all": "Totes",
+       "blocklist-type-opt-sitewide": "Tote le sito",
+       "blocklist-type-opt-partial": "Partial",
        "blocklist-rangeblocks": "Celar blocadas de gruppos de adresses IP",
        "blocklist-timestamp": "Data e hora",
        "blocklist-target": "Objectivo",
        "blocklist-editing-page": "paginas",
        "blocklist-editing-ns": "spatios de nomines",
        "ipblocklist-empty": "Le lista de blocadas es vacue.",
-       "ipblocklist-no-results": "Le adresse IP o nomine de usator que tu requestava non es blocate.",
+       "ipblocklist-no-results": "Nulle blocadas trovate que corresponde al adresse IP o nomine de usator requestate.",
        "blocklink": "blocar",
        "unblocklink": "disblocar",
        "change-blocklink": "cambiar blocada",
+       "empty-username": "(nulle nomine de usator disponibile)",
        "contribslink": "contributiones",
        "emaillink": "inviar e-mail",
        "autoblocker": "Automaticamente blocate perque tu adresse IP ha recentemente essite usate per \"[[User:$1|$1]]\".\nLe motivo specificate pro blocar $1 es \"''$2''\"",
        "allmessagesdefault": "Texto predefinite",
        "allmessagescurrent": "Texto actual",
        "allmessagestext": "Isto es un lista de messages de systema disponibile in le spatio de nomines MediaWiki.\nPer favor visita [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] e [https://translatewiki.net translatewiki.net] si tu desira contribuer al localisation general de MediaWiki.",
-       "allmessagesnotsupportedDB": "Iste pagina non pote esser usate proque '''$wgUseDatabaseMessages''' ha essite disactivate.",
+       "allmessages-not-supported-database": "Iste pagina non pote esser usate proque '''$wgUseDatabaseMessages''' ha essite disactivate.",
        "allmessages-filter-legend": "Filtro",
        "allmessages-filter": "Filtrar per stato de personalisation:",
        "allmessages-filter-unmodified": "Non modificate",
        "confirm-unwatch-top": "Remover iste pagina de tu observatorio?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Reverter le modificationes a iste pagina?",
+       "confirm-rollback-bottom": "Iste action revocara instantaneemente le modificationes seligite de iste pagina.",
        "confirm-mcrrestore-title": "Restaurar version",
        "confirm-mcrundo-title": "Disfacer un modification",
        "mcrundofailed": "Disfaction fallite",
        "passwordpolicies-policyflag-forcechange": "debe cambiar al apertura de session",
        "passwordpolicies-policyflag-suggestchangeonlogin": "suggerer cambio al apertura de session",
        "easydeflate-invaliddeflate": "Le contento fornite non es correctemente comprimite",
-       "unprotected-js": "Pro motivos de securitate, non es possibile cargar codice JavaScript de paginas non protegite. Crea JavaScript solmente in le spatio de nomines \"MediaWiki:\" o como un subpagina de usator."
+       "unprotected-js": "Pro motivos de securitate, non es possibile cargar codice JavaScript de paginas non protegite. Crea JavaScript solmente in le spatio de nomines \"MediaWiki:\" o como un subpagina de usator.",
+       "userlogout-continue": "Si tu vole clauder le session, [$1 continua al pagina pro clauder session].",
+       "userlogout-sessionerror": "Le clausura del session ha fallite a causa de un error de session. Per favor [$1 reproba]."
 }
index 7ad95e2..751bcf7 100644 (file)
@@ -62,7 +62,9 @@
                        "Fitoschido",
                        "Palladin911",
                        "Bagas Chrisara",
-                       "Pebaryan"
+                       "Pebaryan",
+                       "Veracious",
+                       "Mnam23"
                ]
        },
        "tog-underline": "Garis bawahi pranala:",
        "tog-norollbackdiff": "Jangan tampilkan perbedaan setelah melakukan pengembalian",
        "tog-useeditwarning": "Ingatkan saya bila meninggalkan halaman penyuntingan sebelum menyimpan perubahan",
        "tog-prefershttps": "Selalu gunakan koneksi aman ketika masuk log",
+       "tog-showrollbackconfirmation": "Tampilkan konfirmasi ketika mengeklik pranala pengembalian",
        "underline-always": "Selalu",
        "underline-never": "Tidak pernah",
        "underline-default": "Kulit atau penjelajah bawaan",
        "virus-scanfailed": "Pemindaian gagal (kode $1)",
        "virus-unknownscanner": "Antivirus tidak dikenal:",
        "logouttext": "'''Anda telah keluar log dari sistem.'''\n\nIngatlah bahwa beberapa halaman mungkin masih menampilkan anda seperti masih masuk log, sampai Anda membersihkan singgahan penjelajah web Anda.",
+       "logging-out-notify": "Anda sedang keluar log, mohon menunggu.",
+       "logout-failed": "Tidak dapat keluar log saat ini: $1",
        "cannotlogoutnow-title": "Tidak dapat keluar log saat ini",
        "cannotlogoutnow-text": "Keluar log tidak memungkinkan ketika menggunakan $1.",
        "welcomeuser": "Selamat datang,  $1 !",
        "badretype": "Kata sandi yang Anda masukkan salah.",
        "usernameinprogress": "Pembuatan akun untuk nama pengguna ini sedang dijalankan. Silahkan tunggu.",
        "userexists": "Nama pengguna yang dimasukkan telah digunakan.\nSilakan tentukan nama yang lain.",
+       "createacct-normalization": "Nama pengguna anda akan diubah menjadi $2 dikarenakan dilarang secara teknis.",
        "loginerror": "Kesalahan masuk log",
        "createacct-error": "Pembuatan akun gagal",
        "createaccounterror": "Tidak dapat membuat akun: $1",
        "page_first": "pertama",
        "page_last": "terakhir",
        "histlegend": "Pilih dua tombol radio lalu tekan tombol ''bandingkan'' untuk membandingkan versi. Klik suatu tanggal untuk melihat versi halaman pada tanggal tersebut.<br />(skr) = perbedaan dengan versi sekarang, (akhir) = perbedaan dengan versi sebelumnya, '''k''' = suntingan kecil, '''b''' = suntingan bot, → = suntingan bagian, ← = ringkasan otomatis",
-       "history-fieldset-title": "Cari revisi",
+       "history-fieldset-title": "Saring revisi",
        "history-show-deleted": "Revisi yang dihapus saja",
        "histfirst": "terlama",
        "histlast": "terbaru",
        "historysize": "($1 {{PLURAL:$1|bita|bita}})",
-       "historyempty": "(kosong)",
+       "historyempty": "kosong",
        "history-feed-title": "Riwayat revisi",
        "history-feed-description": "Riwayat revisi halaman ini di wiki",
        "history-feed-item-nocomment": "$1 pada $2",
        "group-sysop": "Pengurus",
        "group-interface-admin": "Pengurus antarmuka",
        "group-bureaucrat": "Birokrat",
-       "group-suppress": "Pengawas",
+       "group-suppress": "Pemberedel",
        "group-all": "(semua)",
        "group-user-member": "{{GENDER:$1| pengguna}}",
        "group-autoconfirmed-member": "{{GENDER:$1|pengguna terkonfimasi otomatis}}",
        "group-sysop-member": "{{GENDER:$1|pengurus}}",
        "group-interface-admin-member": "{{GENDER:$1|pengurus antarmuka}}",
        "group-bureaucrat-member": "{{GENDER:$1|birokrat}}",
-       "group-suppress-member": "{{GENDER:$1|pengawas}}",
+       "group-suppress-member": "{{GENDER:$1|pemberedel}}",
        "grouppage-user": "{{ns:project}}:Pengguna",
        "grouppage-autoconfirmed": "{{ns:project}}:Pengguna terkonfirmasi otomatis",
        "grouppage-bot": "{{ns:project}}:Bot",
        "grouppage-sysop": "{{ns:project}}:Pengurus",
        "grouppage-interface-admin": "{{ns:project}}:Pengurus antarmuka",
        "grouppage-bureaucrat": "{{ns:project}}:Birokrat",
-       "grouppage-suppress": "{{ns:project}}:Peredam",
+       "grouppage-suppress": "{{ns:project}}:Beredel",
        "right-read": "Membaca halaman",
        "right-edit": "Sunting halaman",
        "right-createpage": "Membuat halaman baru (yang bukan halaman pembicaraan)",
        "right-reupload-own": "Menimpa berkas yang sudah ada yang dimuat oleh pengguna yang sama",
        "right-reupload-shared": "Menolak berkas-berkas pada penyimpanan media lokal bersama",
        "right-upload_by_url": "Memuatkan berkas dari sebuah alamat URL",
-       "right-purge": "Menghapus singgahan suatu halaman tanpa halaman konfirmasi",
+       "right-purge": "Menghapus singgahan suatu halaman",
        "right-autoconfirmed": "Tidak dipengaruhi rate limit berbasis IP",
        "right-bot": "Diperlakukan sebagai sebuah proses otomatis",
        "right-nominornewtalk": "Ketiadaan suntingan kecil di halaman pembicaraan memicu tampilan pesan baru",
        "right-writeapi": "Menggunakan API penulisan",
        "right-delete": "Menghapus halaman",
        "right-bigdelete": "Menghapus halaman dengan banyak versi terdahulu",
-       "right-deletelogentry": "Hapus dan batalkan penghapusan entri log tertentu",
+       "right-deletelogentry": "Menghapus dan membatalkan penghapusan entri log tertentu",
        "right-deleterevision": "Menghapus dan membatalkan penghapusan revisi tertentu suatu halaman",
        "right-deletedhistory": "Melihat entri-entri revisi yang dihapus, tanpa teks yang berhubungan",
        "right-deletedtext": "Melihat teks yang dihapus dan perubahan antara revisi yang dihapus",
        "right-ipblock-exempt": "Mengabaikan pemblokiran IP, pemblokiran otomatis, dan rentang pemblokiran",
        "right-unblockself": "Lepaskan blokir sendiri",
        "right-protect": "Ubah tingkat pelindungan dan sunting halaman yang dilindungi beruntun",
-       "right-editprotected": "Sunting halaman yang dilindungi sebagai \"{{int:protect-level-sysop}}\"",
-       "right-editsemiprotected": "Sunting halaman yang dilindungi sebagai \"{{int:protect-level-autoconfirmed}}\"",
+       "right-editprotected": "Menyunting halaman yang dilindungi sebagai \"{{int:protect-level-sysop}}\"",
+       "right-editsemiprotected": "Menyunting halaman yang dilindungi sebagai \"{{int:protect-level-autoconfirmed}}\"",
        "right-editcontentmodel": "Edit model konten halaman",
        "right-editinterface": "Menyunting antarmuka pengguna",
        "right-editusercss": "Menyunting berkas CSS pengguna lain",
-       "right-edituserjson": "Sunting berkas JSON pengguna lain",
+       "right-edituserjson": "Menyunting berkas JSON pengguna lain",
        "right-edituserjs": "Menyunting berkas JS pengguna lain",
-       "right-editsitecss": "Sunting CSS untuk keseluruhan situs",
-       "right-editsitejson": "Sunting JSON untuk keseluruhan situs",
-       "right-editsitejs": "Sunting JavaScript untuk keseluruhan situs",
+       "right-editsitecss": "Menyunting CSS untuk keseluruhan situs",
+       "right-editsitejson": "Menyunting JSON untuk keseluruhan situs",
+       "right-editsitejs": "Menyunting JavaScript untuk keseluruhan situs",
        "right-editmyusercss": "Sunting berkas CSS pengguna Anda",
        "right-editmyuserjson": "Sunting berkas JSON pengguna Anda",
        "right-editmyuserjs": "Sunting berkas JavaScript pengguna Anda",
-       "right-viewmywatchlist": "Lihat daftar pantauan Anda",
-       "right-editmywatchlist": "Sunting daftar pantau Anda. Masih ada cara menambahkan halaman tanpa harus memiliki hak ini.",
-       "right-viewmyprivateinfo": "Lihat data pribadi Anda (alamat surel, nama asli, dll.)",
-       "right-editmyprivateinfo": "Sunting data pribadi Anda (alamat surel, nama asli, dll.)",
-       "right-editmyoptions": "Sunting preferensi Anda",
+       "right-viewmywatchlist": "Melihat daftar pantauan Anda sendiri",
+       "right-editmywatchlist": "Menyunting daftar pantau Anda sendiri. Beberapa tindakan tetap akan menambahkan halaman tanpa hak ini.",
+       "right-viewmyprivateinfo": "Melihat data pribadi Anda sendiri (misal: alamat surel, nama asli)",
+       "right-editmyprivateinfo": "Menyunting data pribadi Anda sendiri (misal: alamat surel, nama asli)",
+       "right-editmyoptions": "Menyunting preferensi Anda sendiri",
        "right-rollback": "Mengembalikan dengan cepat suntingan-suntingan pengguna terakhir yang menyunting halaman tertentu",
        "right-markbotedits": "Menandai pengembalian revisi sebagai suntingan bot",
        "right-noratelimit": "Tidak dipengaruhi oleh pembatasan jumlah suntingan",
        "action-userrights-interwiki": "menyunting hak akses dari pengguna di wiki lain",
        "action-siteadmin": "mengunci atau membuka kunci basis data",
        "action-sendemail": "kirim surel",
-       "action-editmyoptions": "sunting preferensi Anda",
-       "action-editmywatchlist": "sunting daftar pantauan Anda",
+       "action-editmyoptions": "menyunting preferensi Anda",
+       "action-editmywatchlist": "menyunting daftar pantauan Anda",
        "action-viewmywatchlist": "lihat daftar pantau Anda",
        "action-viewmyprivateinfo": "lihat informasi pribadi Anda",
-       "action-editmyprivateinfo": "sunting informasi pribadi Anda",
+       "action-editmyprivateinfo": "menyunting informasi pribadi Anda",
        "action-editcontentmodel": "mengedit model konten sebuah halaman",
        "action-managechangetags": "buat dan matikan tag",
        "action-applychangetags": "terapkan tag bersamaan dengan perubahan Anda",
        "action-changetags": "menambah dan menghapus tag semaunya pada revisi individu dan entri log",
        "action-deletechangetags": "hapus tag dari basis data",
        "action-purge": "hapus singgahan halaman ini",
+       "action-apihighlimits": "menggunakan batasan yang lebih tinggi dalam kueri API",
+       "action-autoconfirmed": "tidak dipengaruhi rate limit berbasis IP",
+       "action-bigdelete": "hapus halaman dengan banyak versi terdahulu",
+       "action-blockemail": "blokir pengiriman surel oleh pengguna",
+       "action-bot": "diperlakukan sebagai sebuah proses otomatis",
+       "action-editprotected": "menyunting halaman yang dilindungi sebagai \"{{int:protect-level-sysop}}\"",
+       "action-editsemiprotected": "sunting halaman yang dilindungi sebagai \"{{int:protect-level-autoconfirmed}}\"",
+       "action-editinterface": "sunting antarmuka pengguna",
+       "action-editusercss": "sunting berkas CSS pengguna lain",
+       "action-edituserjson": "sunting berkas JSON pengguna lain",
+       "action-edituserjs": "sunting berkas JS pengguna lain",
+       "action-editsitecss": "menyunting CSS untuk keseluruhan situs",
+       "action-editsitejson": "sunting JSON untuk keseluruhan situs",
+       "action-editsitejs": "sunting JavaScript untuk keseluruhan situs",
+       "action-editmyusercss": "sunting berkas CSS pengguna Anda",
+       "action-editmyuserjson": "sunting berkas JSON pengguna Anda",
+       "action-editmyuserjs": "sunting berkas JavaScript pengguna Anda",
+       "action-viewsuppressed": "lihat revisi yang disembunyikan dari semua pengguna",
+       "action-hideuser": "blokir nama pengguna dan sembunyikan dari publik",
+       "action-ipblock-exempt": "abaikan pemblokiran IP, pemblokiran otomatis, dan rentang pemblokiran",
+       "action-unblockself": "lepaskan blokir sendiri",
+       "action-noratelimit": "jangan dipengaruhi oleh pembatasan jumlah suntingan",
+       "action-reupload-own": "menimpa berkas yang sudah ada yang dimuat oleh pengguna yang sama",
+       "action-nominornewtalk": "tiadakan suntingan kecil di halaman pembicaraan yang memicu tampilan pesan baru",
+       "action-markbotedits": "tandai pengembalian revisi sebagai suntingan bot",
+       "action-patrolmarks": "lihat penandaan patroli perubahan terbaru",
+       "action-override-export-depth": "ekspor halaman termasuk halaman-halaman terkait hingga kedalaman 5",
+       "action-suppressredirect": "jangan membuat pengalihan dari nama lama ketika memindahkan halaman",
        "nchanges": "$1 {{PLURAL:$1|perubahan|perubahan}}",
+       "ntimes": "$1×",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|sejak kunjungan terakhir}}",
        "enhancedrc-history": "riwayat",
        "recentchanges": "Perubahan terbaru",
        "rcfilters-savedqueries-already-saved": "Penyaringan ini telah tersimpan. Ubah pengaturan Anda untuk membuat saringan filter tersimpan baru.",
        "rcfilters-restore-default-filters": "Kembalikan filter bawaan",
        "rcfilters-clear-all-filters": "Hapus semua penyaringan",
-       "rcfilters-show-new-changes": "Tampilkan perubahan terbaru",
+       "rcfilters-show-new-changes": "Tampilkan perubahan baru sejak $1",
        "rcfilters-search-placeholder": "Filter perubahan terbaru (gunakan menu atau pencarian untuk menyaring nama)",
        "rcfilters-invalid-filter": "Penyqringan tidak sah",
        "rcfilters-empty-filter": "Tidak ada filter aktif. Semua kontribusi ditampilkan.",
        "rcfilters-filter-editsbyself-description": "Kontribusi saya",
        "rcfilters-filter-editsbyother-label": "Suntingan orang lain",
        "rcfilters-filter-editsbyother-description": "Semua perubahan kecuali perubahan milik sendiri.",
-       "rcfilters-filtergroup-userExpLevel": "Pendaftaran dan pengalaman pengguna",
+       "rcfilters-filtergroup-user-experience-level": "Pendaftaran dan pengalaman pengguna",
        "rcfilters-filter-user-experience-level-registered-label": "Terdaftar",
        "rcfilters-filter-user-experience-level-registered-description": "Penyunting masuk log",
        "rcfilters-filter-user-experience-level-unregistered-label": "Tidak terdaftar",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Tapis \"Suntingan kecil\" konflik dengan satu atau lebih jenis tapis perubahan lain, karena jenis perubahan tertentu tidak dapat ditandai sebagai \"kecil\".Tapis yang berkonflik ditandai di area Tapis aktif, di atas.",
        "rcfilters-hideminor-conflicts-typeofchange": "Jenis perubahan tertentu tidak dapat ditandai sebagai \"kecil\", jadi tapis ini berkonflik dengan tapis Jenis Perubahan ini: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Tapis Jenis perubahan ini berkonflik dengan tapis \"Suntingan kecil\". Jenis perubahan tertentu tidak dapat ditandai sebagai \"kecil\".",
-       "rcfilters-filtergroup-lastRevision": "Revisi terbaru",
+       "rcfilters-filtergroup-lastrevision": "Revisi terbaru",
        "rcfilters-filter-lastrevision-label": "Revisi terbaru",
        "rcfilters-filter-lastrevision-description": "Hanya perubahan terbaru pada halaman ini.",
        "rcfilters-filter-previousrevision-label": "Bukan revisi terbaru",
        "rcfilters-liveupdates-button-title-off": "Tampilkan perubahan baru ketika perubahan tersebut terjadi",
        "rcfilters-watchlist-markseen-button": "Tandai semua perubahan sebagai terlihat",
        "rcfilters-watchlist-edit-watchlist-button": "Sunting daftar pantauan Anda",
-       "rcfilters-watchlist-showupdated": "Perubahan di halaman-halaman yang belum Anda kunjungi sejak perubahan terjadi ditampilkan dalam <strong>huruf terbal</strong>, dan tanda titik tebal di daftar.",
+       "rcfilters-watchlist-showupdated": "Perubahan di halaman-halaman yang belum Anda kunjungi sejak perubahan terjadi ditampilkan dalam <strong>huruf tebal</strong>, dan tanda titik tebal di daftar.",
        "rcfilters-preference-label": "Gunakan antarmuka non-Javascript",
        "rcfilters-preference-help": "Muat perubahan terbaru tanpa tapis pencarian atau fungsi penyorotan",
        "rcfilters-watchlist-preference-label": "Gunakan antarmuka non-Javascript",
        "newpageletter": "B",
        "boteditletter": "b",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|pemantau|pemantau}}]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|bita}} setelah perubahan",
        "newsectionsummary": "/* $1 */ bagian baru",
        "img-auth-nopathinfo": "Informasi jalur hilang.\nPeladen Anda harus diatur untuk meloloskan variabel REQUEST_URI dan/atau PATH_INFO.\nJika sudah, coba aktifkan $wgUsePathInfo.\nLihat https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Alur yang diminta tidak diatur dalam direktori ungahan.",
        "img-auth-badtitle": "Tidak dapat membangun judul yang sah dari \"$1\".",
-       "img-auth-nologinnWL": "Anda tidak masuk log dan \"$1\" tidak dalam daftar putih.",
        "img-auth-nofile": "Berkas \"$1\" tidak ada.",
        "img-auth-isdir": "Anda mencoba mengakses direktori \"$1\".\nHanya akses berkas di bolehkan.",
        "img-auth-streaming": "Streaming \"$1\".",
        "upload-curl-error28": "Pemuatan lewat waktu",
        "upload-curl-error28-text": "Situs yang dituju terlalu lambat merespon. Tolong cek apakah situs tersebut aktif, tunggu sebentar, dan coba lagi. Mungkin Anda perlu mencobanya di saat yang lebih longgar.",
        "license": "Jenis lisensi:",
-       "license-header": "Jenis lisensi",
+       "license-header": "Lisensi",
        "nolicense": "Tidak ada yang dipilih",
        "licenses-edit": "Sunting pilihan lisensi",
        "license-nopreview": "(Pratayang tak tersedia)",
        "nopagetext": "Halaman yang Anda tuju tidak ditemukan.",
        "pager-newer-n": "{{PLURAL:$1|1 lebih baru|$1 lebih baru}}",
        "pager-older-n": "{{PLURAL:$1|$1 lebih lama}}",
-       "suppress": "Sembunyikan",
+       "suppress": "Beredel",
        "querypage-disabled": "Halaman istimewa ini dinonaktifkan demi alasan kinerja.",
        "apihelp": "Bantuan API",
        "apihelp-no-such-module": "Modul \"$1\" tidak ditemukan.",
        "apisandbox-request-selectformat-label": "Tampilkan permintaan data sebagai:",
        "apisandbox-request-format-url-label": "String kueri URL",
        "apisandbox-request-url-label": "URL Permintaan:",
+       "apisandbox-request-format-json-label": "JSON",
        "apisandbox-request-json-label": "Meminta JSON:",
        "apisandbox-request-time": "Lama permintaan: {{PLURAL:$1|$1 ms}}",
        "apisandbox-results-fixtoken": "Perbaiki token dan kirim kembali",
        "apisandbox-alert-field": "Nilai dalam kolom ini tidak valid.",
        "apisandbox-continue": "Lanjutkan",
        "apisandbox-continue-clear": "Kosongkan",
+       "apisandbox-continue-help": "{{int:apisandbox-continue}} akan [https://www.mediawiki.org/wiki/API:Query#Continuing_queries melanjutkan] permintaan terakhir; {{int:apisandbox-continue-clear}} akan membersihkan semua parameter berkelanjutan",
        "apisandbox-param-limit": "Masukan <kbd>max</kbd> untuk menggunakan batas maksimum.",
        "apisandbox-multivalue-all-namespaces": "$1 (Semua ruang nama)",
        "apisandbox-multivalue-all-values": "$1 (Semua nilai)",
        "delete-confirm": "Hapus \"$1\"",
        "delete-legend": "Hapus",
        "historywarning": "<strong>Peringatan:</strong> Laman yang akan Anda hapus memiliki riwayat dengan $1 perubahan:",
-       "historyaction-submit": "Tampilkan",
+       "historyaction-submit": "Tampilkan revisi",
        "confirmdeletetext": "Anda akan menghapus halaman atau berkas ini secara permanen berikut semua sejarahnya dari basis data. Pastikan bahwa Anda memang ingin melakukannya, mengetahui segala akibatnya, dan apa yang Anda lakukan ini adalah sejalan dengan [[{{MediaWiki:Policy-url}}|kebijakan {{SITENAME}}]].",
        "actioncomplete": "Proses selesai",
        "actionfailed": "Eksekusi gagal",
        "deleting-backlinks-warning": "<strong>Peringatan:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Halaman lain]] mengarah atau memiliki transklusi ke halaman yang akan Anda hapus.",
        "deleting-subpages-warning": "<strong>Peringatan:</strong> Halaman yang akan Anda hapus memiliki [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|subhalaman|$1 subhalaman|51=lebih dari 50 subhalaman}}]].",
        "rollback": "Kembalikan suntingan",
+       "rollback-confirmation-confirm": "Silakan konfirmasi:",
+       "rollback-confirmation-yes": "Kembalikan",
+       "rollback-confirmation-no": "Batal",
        "rollbacklink": "kembalikan",
        "rollbacklinkcount": "kembalikan $1 {{PLURAL:$1|suntingan}}",
        "rollbacklinkcount-morethan": "kembalikan lebih dari $1 {{PLURAL:$1|suntingan|suntingan}}",
        "revertpage": "←Suntingan [[Special:Contributions/$2|$2]] ([[User talk:$2|bicara]]) dibatalkan ke versi terakhir oleh [[User:$1|$1]]",
        "revertpage-nouser": "Mengembalikan suntingan oleh (nama pengguna dihapus) ke suntingan terakhir oleh [[User:$1|$1]]",
        "rollback-success": "Pembatalan suntingan oleh {{GENDER:$3|$1}}; dibatalkan ke versi terakhir oleh {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Mengembalikan suntingan oleh $1; rubah kembali untuk revisi terakhir oleh $2. [$3 Lihat perubahan]",
        "sessionfailure-title": "Kegagalan sesi",
        "sessionfailure": "Sepertinya ada masalah dengan sesi log Anda; log Anda telah dibatalkan sebagai antisipasi untuk mencegah pembajakan. Silakan tekan tombol \"kembali\" dan muat kembali halaman sebelum Anda masuk, lalu coba lagi.",
        "changecontentmodel": "Ubah model isi sebuah halaman",
        "mycontris": "Kontribusi",
        "anoncontribs": "Kontribusi",
        "contribsub2": "Untuk {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "Untuk {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "Pengguna \"$1\" tidak terdaftar.",
        "negative-namespace-not-supported": "Ruangnama dengan nilai negatif tidak didukung.",
        "nocontribs": "Tidak ada perubahan yang sesuai dengan kriteria tersebut.",
        "ipb-confirm": "Konfirmasi blokir",
        "ipb-sitewide": "Keseluruhan situs",
        "ipb-partial": "Parsial",
+       "ipb-sitewide-help": "Semua halaman di wiki dan aksi kontribusi lainnya",
        "ipb-partial-help": "Halaman atau ruangnama khusus.",
        "ipb-pages-label": "Halaman",
        "ipb-namespaces-label": "Ruang nama",
        "blocklist-userblocks": "Sembunyikan pemblokiran akun",
        "blocklist-tempblocks": "Sembunyikan pemblokiran sementara",
        "blocklist-addressblocks": "Sembunyikan pemblokiran IP tunggal",
+       "blocklist-type": "Jenis:",
+       "blocklist-type-opt-all": "Semua",
+       "blocklist-type-opt-sitewide": "Keseluruhan situs",
+       "blocklist-type-opt-partial": "Parsial",
        "blocklist-rangeblocks": "Menyembunyikan jangkauan blokir (http://www.mediawiki.org/wiki/Help:Range_blocks)",
        "blocklist-timestamp": "Stempel waktu",
        "blocklist-target": "Target",
        "blocklist-editing-page": "laman",
        "blocklist-editing-ns": "Ruang nama",
        "ipblocklist-empty": "Daftar pemblokiran kosong.",
-       "ipblocklist-no-results": "Alamat IP atau pengguna yang diminta tidak diblokir.",
+       "ipblocklist-no-results": "Tidak ada pemblokiran untuk alamat IP atau nama pengguna yang diminta.",
        "blocklink": "blokir",
        "unblocklink": "hilangkan blokir",
        "change-blocklink": "ubah pemblokiran",
+       "empty-username": "(nama pengguna tidak tersedia)",
        "contribslink": "kontrib",
        "emaillink": "kirim surel",
        "autoblocker": "Diblokir secara otomatis karena alamat IP Anda digunakan oleh \"[[User:$1|$1]]\".\nAlasan yang diberikan untuk pemblokiran $1 adalah: \"$2\"",
        "ipb_expiry_old": "Waktu kedaluwarsa adalah pada masa lampau.",
        "ipb_expiry_temp": "Pemblokiran atas nama pengguna yang disembunyikan harus permanen.",
        "ipb_hide_invalid": "Tak dapat menutup akun ini; akun tersebut memiliki {{PLURAL:$1|satu suntingan|$1 suntingan}}.",
+       "ipb_hide_partial": "Pemblokiran penyembunyian nama pengguna harus merupakan pemblokiran keseluruhan situs",
        "ipb_already_blocked": "\"$1\" telah diblokir.",
        "ipb-needreblock": "$1 sudah diblokir. Apakah Anda ingin mengubah set pemblokiran yang bersangkutan?",
        "ipb-otherblocks-header": "{{PLURAL:$1|Blok|Blok}} lain",
        "allmessagesdefault": "Teks baku",
        "allmessagescurrent": "Teks sekarang",
        "allmessagestext": "Ini adalah daftar semua pesan sistem yang tersedia dalam ruang nama MediaWiki.\nSilakan kunjungi [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Pelokalan MediaWiki] dan [https://translatewiki.net translatewiki.net] jika Anda ingin berkontribusi untuk pelokalan generik MediaWiki.",
-       "allmessagesnotsupportedDB": "Halaman ini tidak dapat digunakan karena '''$wgUseDatabaseMessages''' telah dimatikan.",
+       "allmessages-not-supported-database": "Halaman ini tidak dapat digunakan karena '''$wgUseDatabaseMessages''' telah dimatikan.",
        "allmessages-filter-legend": "Penyaring",
        "allmessages-filter": "Saring dengan keadaan kustomisasi:",
        "allmessages-filter-unmodified": "Tidak diubah",
        "import-mapping-subpage": "Impor sebagai subhalaman dari halaman berikut:",
        "import-upload-filename": "Nama berkas:",
        "import-upload-username-prefix": "Awalan interwiki:",
+       "import-assign-known-users": "Berikan suntingan-suntingan ke pengguna lokal, untuk nama-nama pengguna yang ada di wiki ini.",
        "import-comment": "Komentar:",
        "importtext": "Silakan ekspor berkas dari wiki sumber dengan menggunakan [[Special:Export|fasilitas ekspor]].\nSimpan ke komputer Anda dan unggah ke sini.",
        "importstart": "Mengimpor halaman...",
        "group-bot.css": "/* CSS di sini hanya mempengaruhi bot */",
        "group-sysop.css": "/* CSS di sini hanya mempengaruhi pengurus */",
        "group-bureaucrat.css": "/* CSS di sini hanya mempengaruhi birokrat */",
+       "common.json": "/* JSON apa pun yang ada di sini akan dimuat untuk semua pengguna ketika memuat semua halaman. */",
        "common.js": "/* JavaScript yang ada di sini akan diterapkan untuk semua kulit. */",
        "group-autoconfirmed.js": "/* Semua JavaScript di sini hanya dimuatkan untuk pengguna terkonfirmasi otomatis */",
        "group-bot.js": "/* Semua JavaScript di sini hanya dimuatkan untuk bot */",
        "confirm-unwatch-top": "Hapus halaman ini dari daftar pantauan Anda?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Kembalikan suntingan ke halaman ini?",
+       "confirm-rollback-bottom": "Tindakan ini akan mengembalikan revisi terkait ke halaman ini.",
        "confirm-mcrrestore-title": "Kembalikan revisi",
        "confirm-mcrundo-title": "Balikkan perubahan",
        "mcrundofailed": "Pembatalan gagal",
        "mcrundo-missingparam": "Parameter yang dibutuhkan ketika diminta tidak tersedia.",
        "mcrundo-changed": "Halaman ini telah diubah sejak Anda melihat diff. Mohon tinjau perubahan terbaru.",
+       "mcrundo-parse-failed": "Galat dalam menguraikan revisi baru: $1",
        "semicolon-separator": ";&#32;",
        "comma-separator": ",&#32;",
        "colon-separator": ":&#32;",
        "pipe-separator": "&#32;|&#32;",
        "word-separator": "&#32;",
        "ellipsis": "...",
+       "parentheses": "($1)",
        "quotation-marks": "\"$1\"",
        "imgmultipageprev": "← halaman sebelumnya",
        "imgmultipagenext": "halaman selanjutnya →",
        "autosumm-changed-redirect-target": "Ubah target pengalihan dari [[$1]] ke [[$2]]",
        "autosumm-new": "←Membuat halaman berisi '$1'",
        "autosumm-newblank": "Membuat halaman kosong",
+       "size-bytes": "$1 {{PLURAL:$1|bita}}",
+       "size-pixel": "$1 {{PLURAL:$1|piksel}}",
        "lag-warn-normal": "Perubahan yang lebih baru dari $1 {{PLURAL:$1|detik|detik}} mungkin tidak muncul di daftar ini.",
        "lag-warn-high": "Karenanya besarnya keterlambatan basis data server, perubahan yang lebih baru dari $1 {{PLURAL:$1|detik|detik}} mungkin tidak muncul di daftar ini.",
        "watchlistedit-normal-title": "Sunting daftar pantauan",
        "logentry-partialblock-block-ns": "{{PLURAL:$1|ruangnama|ruangnama}} $2",
        "logentry-partialblock-block": "$1 {{GENDER:$2|memblokir}} {{GENDER:$4|$3}} dari penyuntingan $7 dengan waktu kedaluwarsa $5 $6",
        "logentry-partialblock-reblock": "$1 {{GENDER:$2|mengubah}} pengaturan blokir pada {{GENDER:$4|$3}} untuk mencegah penyuntingan pada $7 dengan masa pemblokiran $5 $6",
+       "logentry-non-editing-block-block": "$1 {{GENDER:$2|memblokir}} {{GENDER:$4|$3}} dari tindakan-tindakan nonsuntingan terkait dengan waktu kedaluwarsa $5 $6",
+       "logentry-non-editing-block-reblock": "$1 {{GENDER:$2|mengubah}} pemblokiran {{GENDER:$4|$3}} dari tindakan-tindakan nonsuntingan terkait dengan waktu kedaluwarsa $5 $6",
        "logentry-suppress-block": "$1 {{GENDER:$2|memblokir}} {{GENDER:$4|$3}} dengan waktu kedaluwarsa $5 $6",
        "logentry-suppress-reblock": "$1 {{GENDER:$2|mengubah}} pemblokiran {{GENDER:$4|$3}} dengan waktu kedaluwarsa $5 $6",
        "logentry-import-upload": "$1 {{GENDER:$2|mengimpor}} $3 melalui pemuatan berkas",
        "limitreport-templateargumentsize-value": "$1/$2 {{PLURAL:$2|bita}}",
        "limitreport-expansiondepth": "Kedalaman ekspansi tertinggi",
        "limitreport-expensivefunctioncount": "Perhitungan fungsi parser yang mahal",
+       "limitreport-unstrip-depth": "Kedalaman rekursi Unstrip",
+       "limitreport-unstrip-size": "Ukuran Unstrip setelah ekspansi",
        "limitreport-unstrip-size-value": "$1/$2 {{PLURAL:$2|bita|bita}}",
        "expandtemplates": "Pengembangan templat",
        "expand_templates_intro": "Halaman istimewa ini mengambil teks dan mengembangkan semua templat di dalamnya secara rekursif. Halaman ini juga menerjemahkan semua fungsi parser seperti <code><nowiki>{{</nowiki>#language:…}}</code> dan variabel seperti <code><nowiki>{{</nowiki>CURRENTDAY}}</code>. Bahkan bisa dibilang mengembangkan segala sesuatu yang berada di antara dua tanda kurung.",
        "passwordpolicies-policy-passwordcannotbepopular": "Kata sandi tidak boleh {{PLURAL:$1|kata sandi populer|dalam senarai $1 kata sandi populer}}",
        "passwordpolicies-policy-passwordnotinlargeblacklist": "Kata sandi tidak boleh termasuk dalam daftar 100.000 kata sandi yang paling umum digunakan.",
        "passwordpolicies-policyflag-forcechange": "wajib diganti ketika masuk log",
-       "unprotected-js": "Karena alasan keamanan Javascript tidak dapat dimuat dari halaman yang tidak dilindungi. Mohon hanya buat javascript di ruangnama MediaWiki: atau sebagai subhalaman  Pengguna"
+       "passwordpolicies-policyflag-suggestchangeonlogin": "sarankan penggantian ketika masuk log",
+       "easydeflate-invaliddeflate": "Isi yang disediakan tidak dikempiskan secara tepat",
+       "unprotected-js": "Karena alasan keamanan Javascript tidak dapat dimuat dari halaman yang tidak dilindungi. Mohon hanya buat javascript di ruangnama MediaWiki: atau sebagai subhalaman  Pengguna",
+       "userlogout-continue": "Jika Anda yakin untuk keluar log, silakan [$1 melanjutkan].",
+       "userlogout-sessionerror": "Gagal keluar log karena galat sesi. Silakan [$1 coba lagi]."
 }
index ea128ce..ddfc75b 100644 (file)
@@ -47,7 +47,7 @@
        "tog-ccmeonemails": "Sipu iye e-mail m na sipu ndi ozor",
        "tog-diffonly": "É zìkwàlà ihe nọr na ihü di okpúrù íchiè",
        "tog-showhiddencats": "Zi ébéonọr zonari a zonari",
-       "tog-norollbackdiff": "Kwà diff mgbe byárá na mgbe láázú mèchàrà",
+       "tog-norollbackdiff": "egosila ndíiche ma í gosipútacha otu ebe a di na mbú",
        "tog-useeditwarning": "gwam mgbe m hapụrụ ihu akwụkwọ nhaziri na echekwaghị ihe ndị m gbamworo",
        "tog-prefershttps": "gbaa mbọ na eji njikọta doro anya mgbe ọbụla ị chọrọ ibanye n'ịntanetị",
        "underline-always": "M̀gbèọbụlà",
        "category-file-count-limited": "Nkeá {{PLURAL:$1|usòrò dị|usòrò $1 dị}} na ébéanọr nkeá.",
        "listingcontinuesabbrev": "gàzi.",
        "index-category": "Ẹdẹle Ihü",
-       "noindex-category": "Ihü ẹdẹlebu",
+       "noindex-category": "enweghị ihu akwụkwọ na-egosi usoro nhazi nakwa ebe akwụkwọ di",
        "broken-file-category": "Ihü nwere jkọdọ na ga fail gbajírí",
        "about": "Màkà",
        "article": "Ihü ihe dị",
        "help": "Inyeáká",
        "help-mediawiki": "Enyemaka gbasara MidiyaWiki",
        "search": "Tùwe",
+       "search-ignored-headings": "#</pre><!--hapụ akara a otu ọdi-->",
        "searchbutton": "Tùwe",
        "go": "Gá",
        "searcharticle": "Gá",
        "pool-queuefull": "Pool kyu zùrù",
        "pool-errorunknown": "Nsogbu nke námaghi",
        "pool-servererror": "pulu kauta sava adịghị ugbu a",
-       "poolcounter-usage-error": "e nwere nsogbu",
+       "poolcounter-usage-error": "e nwere nsogbu: $1",
        "aboutsite": "Màkà {{SITENAME}}",
        "aboutpage": "Project:Màkà",
        "copyright": "Ihe di ime nọr okpúrụ $1",
        "ok": "Ngwanu",
        "retrievedfrom": "Wefụtàrà ya shí ''$1''",
        "youhavenewmessages": "I nwèrè $1 ($2).",
+       "youhavenewmessagesfromusers": "{{PLURAL:$4|I nwere}}$1 site na {{PLURAL:$3|Onye ọru ọzọ|$3 ndi ọru}} ($2).",
+       "youhavenewmessagesmanyusers": "I nwere $1 si na ọtụtụ ndi ọru ($2)",
+       "newmessageslinkplural": "{{PLURAL:$1|ozi ọhụrụ|999=ozi ọhuru}}",
+       "newmessagesdifflinkplural": "ikpeazu{{PLURAL:$1|mgbanwe|999=mgbanwe}}",
        "youhavenewmessagesmulti": "Inwere eziohu na $1",
        "editsection": "mèzi",
        "editold": "mèzi",
        "nospecialpagetext": "<strong>Í chọrọ ihü mkpà nke à díghị ézíbóté.</strong>\n\nNdetu màkà ihü mkpà nke à díghị ézíbóté nọ nà [[Special:SpecialPages|{{int:specialpages}}]].",
        "error": "Nsogbú",
        "databaseerror": "Nsogbu nọr na njikota ómárí",
+       "databaseerror-query": "Ajụjụ:$1",
+       "databaseerror-function": "Ọrụ:$1",
+       "databaseerror-error": "Mmejọ:$1",
        "laggedslavemode": "'''Gé ntị:''' Ihüá nwèríkí bu na o nwéghị ihe gáránirú na ógè nso.",
        "readonly": "Njikota ómárí gbachịrị",
        "missing-article": "Njidé uche nsónùsòrò ènwéghịki tuó mkpụrụ edemede nke ihü nke áhù o kwèshírí hü, nke ha gùrù \"$1\" $2.\n\nIhe méré na mgbe ndiá bu ihe diff dáfùrù na ógè ndụ ya ma jikodo ákíkó mbu nke ótù ihü à gbákáshíálá.\n\nÓ bú nà ọ búghị ihe mèrè, ȯ nwèríkí bu Í gbákọtàrà àkà na áká nsónùsòrò.\nBiko chi ihe á na áká [[Special:ListUsers/sysop|onye íshí]], dètú URL.",
        "userlogin-yourname-ph": "Denye aha njirimara gi",
        "yourpassword": "Okwúngáfè:",
        "userlogin-yourpassword": "Okwungafè",
+       "createacct-yourpassword-ph": "Denye okwu ngafe",
        "yourpasswordagain": "Detuari mkpurụ okwu ejị a gafẹ:",
+       "createacct-yourpasswordagain": "Gosi okwu ngafe",
+       "createacct-yourpasswordagain-ph": "Denye okwu ngafe ọzọ",
        "yourdomainname": "Obí gi:",
        "login": "Detùba",
        "nav-login-createaccount": "Banyé / ké buwá",
        "notloggedin": "I bátà bò",
        "userlogin-joinproject": "Bàkọ {{SITENAME}}",
        "createaccount": "Ké otụ buwa",
+       "createacct-emailoptional": "adreesị ozi intanetị (ma ichọ)",
+       "createacct-email-ph": "Denye adreesị ozi ịntanetị gi",
        "createaccountmail": "na e-mail",
+       "createacct-submit": "Mehe ebe ọrụ",
        "createacct-benefit-heading": "{{SITENAME}} sì nà aka ndị dị kà gị.",
        "createacct-benefit-body1": "{{PLURAL:$1|ḿmezi}}",
+       "createacct-benefit-body2": "{{PLURAL:$1|ihuakwụkwọ|ihuakwụkwọ ndi ọzọ}}",
+       "createacct-benefit-body3": "ọhuru {{PLURAL:$1|onye inyeaka|ndi inyeaka}}",
        "badretype": "Mkpurụ okwu ejị a gafẹ é jëghị.",
        "userexists": "Áhè ọ'bànifé tírí di na áká onye ozor.\nBíkó nwèré áhà nke ozor.",
        "loginerror": "Nsogbu ngbe I choro I bata",
        "mergelog": "Tìkȯtá ndétu-nchèta",
        "revertmerge": "Emẹkotala",
        "history-title": "Ákíkó mbu màkà orü nọr na élú \"$1\"",
+       "difference-title": "ndimiche nọ na nyochaa nke \"$1\"",
        "lineno": "Ahiri $1:",
        "compareselectedversions": "Sikwụ orü áká dị",
        "editundo": "me la àzụ",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|ọ'bànifé|ọ'bànifé}} ne lé anya]",
        "rc-change-size-new": "{{PLURAL:$1|byte}} $1 ǹkè mgbanwè fọ̀rọ̀",
        "newsectionsummary": "/* $1 */ nkeji ohúrù",
        "rc-enhanced-expand": "Zi ihe di ime (Í gí nwere JavaScript)",
index fa3f46d..81cd38d 100644 (file)
        "rcfilters-filter-editsbyself-description": "Dagiti bukodmo a kontribusion.",
        "rcfilters-filter-editsbyother-label": "Dagiti sinukatan ti sabali",
        "rcfilters-filter-editsbyother-description": "Amin a sinuksukatan malaksid ti bukodmo.",
-       "rcfilters-filtergroup-userExpLevel": "Rehistrasion ti agar-aramat ken sanay",
+       "rcfilters-filtergroup-user-experience-level": "Rehistrasion ti agar-aramat ken sanay",
        "rcfilters-filter-user-experience-level-registered-label": "Nakarehistro",
        "rcfilters-filter-user-experience-level-registered-description": "Dagiti nakastrek nga editor.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Saan a nakarehistro",
        "rcfilters-filter-categorization-description": "Dagiti rekord ti pampanid a mainaynayon wenno maik-ikkat manipud kadagiti kategoria.",
        "rcfilters-filter-logactions-label": "Dagiti aksion a nailista",
        "rcfilters-filter-logactions-description": "Dagiti aksion nga administratibo, dagiti panagpartuat iti pakabilangan, dagiti panagikkat iti panid, dagiti panangikarga…",
-       "rcfilters-filtergroup-lastRevision": "Dagiti kaudian a rebision",
+       "rcfilters-filtergroup-lastrevision": "Dagiti kaudian a rebision",
        "rcfilters-filter-lastrevision-label": "Kaudian a rebision",
        "rcfilters-filter-previousrevision-label": "Saan a ti kaudian a rebision",
        "rcfilters-filter-previousrevision-description": "Amin a sinuksukatan a saan a \"kaudian a rebision\".",
        "minoreditletter": "m",
        "newpageletter": "B",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 nga agbuybuya {{PLURAL:$1|nga agar-aramat|kadagiti agar-aramat}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|a byte|kadagiti byte}} kalpasan ti panagsukat",
        "newsectionsummary": "/* $1 */ baro a seksion",
        "rc-enhanced-expand": "Ipakita dagiti salaysay",
        "img-auth-nopathinfo": "Ti servermo ket saan a naisaad nga agipasa iti daytoy a pakaammo.\nMabalin a naibatay iti CGI ken saan a makasuporta ti img_auth.\nKitaen ti https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization .",
        "img-auth-notindir": "Ti kiniddaw a dalan ket saan nga adda iti naaramid a direktorio ti pagikargaan",
        "img-auth-badtitle": "Saan a makaaramid ti umisu a titulo manipud iti \"$1\".",
-       "img-auth-nologinnWL": "Saanka a nakastrek ken ti \"$1\" ket awan idiay mabalin a listaan.",
        "img-auth-nofile": "Awan ti papeles ti \"$1\".",
        "img-auth-isdir": "Padpadasem ti mangserrek ti direktorio ti \"$1\".\nTi laeng panagserrek ti papeles ti maipalubos.",
        "img-auth-streaming": "Agip-ipan iti \"$1\".",
        "revertpage": "Insubli ti panagurnos babaen ni [[Special:Contributions/$2|$2]] ([[User talk:$2|tungtungan]]), naisubli iti naudi a rebision babaen ni [[User:$1|$1]]",
        "revertpage-nouser": "Naisubli dagiti inurnos babaen ti nailemmeng nga agar-aramat iti kinaudi a rebision babaen ni {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Naibabawi dagiti panagurnos babaen ni {{GENDER:$3|$1}};\nnaisubli manen ti naudi a rebision babaen ni {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Naibabawi dagiti panagurnos babaen ni $1;\nisubli ti naudi a rebision babaen ni $2. [$3 Ipakita dagiti binaliwan]",
        "sessionfailure-title": "Napaay ti sesion",
        "sessionfailure": "Adda parikut ti sesion ti panagserrekmo;\ndaytoy nga aramid ket naibabawi a kas pagpawilan ti panaghijack ti sesion.\nPangngaasi nga ited manen ti porma.",
        "changecontentmodel": "Baliwan ti modelo ti linaon ti panid",
        "allmessagesdefault": "Kasisigud a teksto ti mensahe",
        "allmessagescurrent": "Agdama a teksto ti mensahe",
        "allmessagestext": "Daytoy ti listaan dagiti mensahe ti sistema a magun-od iti nagan ti espasio ti MediaWiki.\nPangngaasi a bisitaen ti [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Lokalisasion ti MediaWiki] ken [https://translatewiki.net translatewiki.net] no kayatmo ti agparawad kadagiti sapasap a panagipatarus ti MediaWiki.",
-       "allmessagesnotsupportedDB": "Daytoy a panid ket saan a musar gapu ta nabaldado ti <strong>$wgUseDatabaseMessages</strong>.",
+       "allmessages-not-supported-database": "Daytoy a panid ket saan a musar gapu ta nabaldado ti <strong>$wgUseDatabaseMessages</strong>.",
        "allmessages-filter-legend": "Sagat",
        "allmessages-filter": "Sagaten babaen ti naipaduma a kasasaad:",
        "allmessages-filter-unmodified": "Saan a nabaliwan",
index 301ba80..df4c54e 100644 (file)
@@ -81,7 +81,7 @@
        "march": "Мутт-хьал",
        "april": "Тушол",
        "may_long": "села",
-       "june": "Этинга ''(июнь)''",
+       "june": "Этинга",
        "july": "Баьцамеа",
        "august": "Мяцхали",
        "september": "Михий",
@@ -93,7 +93,7 @@
        "march-gen": "Мутт-хьал",
        "april-gen": "Тушол",
        "may-gen": "Села",
-       "june-gen": "Этинга ''(июнь)'' бетта",
+       "june-gen": "Этинга",
        "july-gen": "Баьцамеа",
        "august-gen": "Мяцхали",
        "september-gen": "Михий",
        "mar": "мутт-хьал",
        "apr": "Tушоли",
        "may": "села",
-       "jun": "Этинга ''(июн)''",
+       "jun": "этинга",
        "jul": "Баьцамеа",
        "aug": "Мяцхали",
        "sep": "Михий",
        "march-date": "Мутт-хьал $1",
        "april-date": "Тушол $1",
        "may-date": "Села $1",
-       "june-date": "Этинга ''(июнь)'' $1",
+       "june-date": "Этинга $1",
        "july-date": "Баьцамеа $1",
        "august-date": "Мяцхали $1",
        "september-date": "Михий $1",
        "watchthis": "Зем бе укх оагӀонна",
        "savearticle": "ОагӀув дIаязъе",
        "savechanges": "ДIаязъе оагӀув",
+       "publishpage": "Хьакхолла оагIув",
        "publishchanges": "ДIаязъе оагӀув",
        "publishchanges-start": "ДIаязъе оагӀув…",
        "preview": "Хьалххе бIаргтохар",
        "rcfilters-filter-editsbyself-description": "Шун къахьегам.",
        "rcfilters-filter-editsbyother-label": "Кхыболча доакъашхоша даь хувцамаш",
        "rcfilters-filter-editsbyother-description": "Деррига тоадараьш, хьа дараш доацаш.",
-       "rcfilters-filtergroup-userExpLevel": "Доакъашхочун регистраци а цун поалхам а",
+       "rcfilters-filtergroup-user-experience-level": "Доакъашхочун регистраци а цун поалхам а",
        "rcfilters-filter-user-experience-level-registered-label": "ДӀаязбеннараш",
        "rcfilters-filter-user-experience-level-registered-description": "Ражача дIаэйтта доакъашхой.",
        "rcfilters-filter-user-experience-level-unregistered-label": "ДӀаязбеннабоацараш",
        "rcfilters-filter-categorization-description": "ОагIаташ чура араяьхача е оагIаташта тIатехача оагIонех лаьца.",
        "rcfilters-filter-logactions-label": "Протокол лелаеш хьадаьр",
        "rcfilters-filter-logactions-description": "Администратораш хьадаьр, дагара йоазонаш кхоллар, оагIонаш дIаяхар, файлаш хьачуяхар...",
-       "rcfilters-filtergroup-lastRevision": "ТIехьара эршаш",
+       "rcfilters-filtergroup-lastrevision": "ТIехьара эршаш",
        "rcfilters-filter-lastrevision-label": "Карара эрш",
        "rcfilters-filter-lastrevision-description": "ОагIон тIа алхха тIехьара хинна хувцам.",
        "rcfilters-filter-previousrevision-label": "ТIехьара йоаца эрш",
index 70ed457..b9d7a2f 100644 (file)
@@ -63,6 +63,7 @@
        "tog-norollbackdiff": "Omisar difero-komparo pos retrorulo",
        "tog-useeditwarning": "Avertez se me probos klozar ula pagino sen sparar mea modifiki ed edituri",
        "tog-prefershttps": "Sempre uzar sekura konekto kande facar log in",
+       "tog-showrollbackconfirmation": "Demandez konfirmo, se ligilo por retromodifikar kliktesos",
        "underline-always": "Sempre",
        "underline-never": "Nulatempe",
        "underline-default": "Pre-ajustaji pri sub-strekizar ligili",
        "help": "Helpo",
        "help-mediawiki": "Helpo pri MediaWiki",
        "search": "Sercho",
-       "search-ignored-headings": " #<!-- mantenez ica lineo sen modifiki --> <pre>\n# Tituli qui ignoresos per la sistemo di serchado.\n# Modifiki en ca parto efikeskos balde pos la titulo di la pagino adicionesos a l'indexo.\n# Tu povas acelerar la riindexigo di la pagino facante nihila editado.\n# La sintaxo esas quale infre:\n#   * Omna texti qui finas kun la signo \"#\" fine de la lineo, esas komentaro.\n#   * Omna lineo ne blanka - to esas: skriptata -, esas l'exakta titulo por ignorar la diferi inter mayuskula e minuskula literi, ed altra.\nReferi\nExtera ligili\nVidez anke\n #</pre> <!-- mantenez ica lineo sen modifiki -->",
+       "search-ignored-headings": " #<!-- mantenez ica lineo sen modifiki --> <pre>\n# Tituli qui ignoresos dal sistemo di serchado.\n# Modifiki en ca parto efikeskos balde pos la titulo di la pagino adicionesos a l'indexo.\n# Tu povas acelerar la riindexigo di la pagino facante nihila editado.\n# La sintaxo esas quale infre:\n#   * Omna texti qui finas kun la signo \"#\" fine de la lineo, esas komentaro.\n#   * Omna lineo ne blanka - to esas: skriptata -, esas l'exakta titulo por ignorar la diferi inter mayuskula e minuskula literi, ed altra.\nReferi\nExtera ligili\nVidez anke\n #</pre> <!-- mantenez ica lineo sen modifiki -->",
        "searchbutton": "Serchez",
        "go": "Irar",
        "searcharticle": "Irez",
        "undelete_short": "Restaurar {{PLURAL:$1|1 redakto|$1 redakti}}",
        "viewdeleted_short": "Vidar {{PLURAL:$1|1 redakto efacita|$1 redakti efacita}}",
        "protect": "Protektar",
-       "protect_change": "chanjar",
+       "protect_change": "modifikar",
        "unprotect": "Desprotektar",
        "newpage": "Nova pagino",
        "talkpagelinktext": "Diskutez",
        "title-invalid-interwiki": "La demandita pagino-titulo kontenas inter-wiki-ala ligilo, olqua ne povas uzesar en tituli.",
        "title-invalid-talk-namespace": "La demandita pagino-titulo referas a diskuto-pagino, qua ne existas.",
        "title-invalid-characters": "La demandita pagino-titulo kontenas ne-valida literi: \"$1\".",
+       "title-invalid-relative": "La titulo di la pagino havas la nomizita \"relativi\". Tituli di pagini kun \"relativi\" (./, ../) esas nevalida, pro freque la retonavigilo dil uzero ne povas trovar li.",
        "title-invalid-magic-tilde": "La pagino demandata kontenas nevalida 'magiala' intersequo di tildi =>(<nowiki>~~~</nowiki>).",
        "title-invalid-too-long": "La pagino demandata esas tre longa. Ol mustas esar min longa kam $1 {{PLURAL:$1|byte|bytes}} segun la kodexado UTF-8.",
        "title-invalid-leading-colon": "La pagino demandata kontenas nevalida bi-punto en lua komenco.",
        "badretype": "La pasovorti vu donis ne esas sama.",
        "usernameinprogress": "Kontokreado por ita uzero duras. Voluntez vartar.",
        "userexists": "La uzeronomo ja selektesis antee.\nVoluntez elektar diferanta uzeronomo.",
+       "createacct-normalization": "Vua uzero-nomo adaptesos a $2, pro teknikala motivi.",
        "loginerror": "Eroro enirante",
        "createacct-error": "Eroro pri kontokreado",
        "createaccounterror": "Ne povis krear konto: $1",
        "passwordtooshort": "Pasovorti mustas kontenar adminime {{PLURAL:$1|1 signo|$1 signi}}.",
        "passwordtoolong": "Pasovorti ne mustas esar plu longa kam {{PLURAL:$1|1 litero|$1 literi}}.",
        "passwordtoopopular": "Pasovorti tre facila ne povas uzesar. Voluntez selektar pasovorto nefacila por divinar.",
+       "passwordinlargeblacklist": "La pasovorto quon vu selektis esas tre ordinare uzata e/o facila por deskovrar. Voluntez selektar plu bona pasovorto.",
        "password-name-match": "Pasovorto mustas diferar de vua uzeronomo.",
        "password-login-forbidden": "La uzo di ita uzeronomo e pasovorto es interdiktita.",
        "mailmypassword": "Sendez nova pasovorto per e-posto",
        "botpasswords-updated-body": "La pasovorto por la 'bot' nomizita \"$1\" del {{GENDER:$2|uzero}} \"$2\" kreesis.",
        "botpasswords-deleted-title": "La pasovorto por la 'bot' efacesis",
        "botpasswords-deleted-body": "La pasovorto por la 'bot' nomizita \"$1\" del {{GENDER:$2|uzero}} \"$2\" kreesis.",
+       "botpasswords-newpassword": "La nova pasovorto por enirar <strong>$1</strong> esas <strong>$2</strong>.\n<em>Voluntez memorigar to por futura refero.</em> <br> (Por anciena ''bot-''i, qui bezonas la nomo di 'login' esar la sama kam l'eventuala nomo dil uzero, vu anke povas uzar <strong>$3</strong> kom uzero-nomo, e <strong>$4</strong> kom pasovorto.)",
+       "botpasswords-no-provider": "\"BotPasswordsSessionProvider\" ne esas disponebla.",
+       "botpasswords-restriction-failed": "Restrikti pri pasovorti koncerne ''bot''-i impedas vua 'log in'.",
        "botpasswords-not-exist": "L'uzero \"$1\" ne havas pasovorto nomizita \"$2\" por lua 'bot'.",
        "botpasswords-needs-reset": "La pasovorto por la 'bot' nomizita \"$1\" dal {{GENDER:$2|uzero}} \"$2\" mustas rikreesar.",
        "botpasswords-locked": "Vu ne povas facar 'login' per robotala pasovorto (bot password), pro ke vua konto blokusesis.",
        "resetpass-abort-generic": "La modifiko dil pasovorto interuptesis per ula 'extension'.",
        "resetpass-expired": "Vua pasovorto perdis la valideso. Voluntez krear nova pasovorto por facar 'log in'.",
        "resetpass-expired-soft": "Vua pasovorto perdis la valideso e mustas modifikesar. Voluntez selektar nova pasovorto, o kliktez \"{{int:authprovider-resetpass-skip-label}}\" por modifikar ol pose.",
+       "resetpass-validity": "Vua pasovorto \"$1\" esas nevalida. Voluntez krear nova pasovorto por facar 'log in'.",
        "resetpass-validity-soft": "Vua pasovorto esas nevalida: $1\n\nVoluntez selektar nova pasovorto, o kliktez \"{{int:authprovider-resetpass-skip-label}}\" por modifikar ol pose.",
        "passwordreset": "Sendez nova pasovorto per e-posto",
        "passwordreset-text-one": "Garnisez ica formulario por recevar provizora pasovorto per vua e-posto.",
        "anoneditwarning": "<strong>Averto:</strong> Vu ne eniris.\nVua IP-adreso esos videbla publike se vu redaktos. Se vu <strong>[$1 enirus]</strong> od <strong>[$2 kreus konto]</strong>, vua redakti atribuesos a vua uzeronomo, kune kun altra bonaji.",
        "anonpreviewwarning": "<em>Vu ne eniris. Konservar chanji registragos vua IP-adreso en la redakto-historio di ta pagino.</em>",
        "missingsummary": "<strong>Atencez:</strong> Vu ne furnisis titulo por ica komento.\nSe vu itere kliktos \"$1\", vua editado salveskos sen ula titulo.",
-       "selfredirect": "<strong>Atencez:</strong> Vu ridirektis ica pagino ad ol ipsa.\nPosible vu informis nekorekta skopo por la ridirekturo, o vu skribabas che nekorekta pagino.\nSe vu iter kliktos \"$1\", la ridirekturo kreesos, irgamaniere.",
+       "selfredirect": "<strong>Atencez:</strong> Ca pagino ridirektesas ad ol ipsa.\nPosible vu informis nekorekta skopo por la ridirekturo, o vu redaktas nekorekta pagino.\nSe vu itere kliktos \"$1\", la ridirekturo kreesos, irgamaniere.",
        "missingcommenttext": "Voluntez skribar komento.",
        "missingcommentheader": "<strong>Atencez:</strong> Vu ne furnisis titulo por ica komento.\nSe vu itere kliktos \"$1\", vua editado salveskos sen ula titulo.",
        "summary-preview": "Previdado di la rezumo:",
        "subject-preview": "Previdado di la temo:",
        "previewerrortext": "Eventis eroro kande on probis krear previdado pri vua modifikuri.",
        "blockedtitle": "La uzero esas blokusita",
+       "blockedtext-partial": "<strong>Vua uzero-nomo od IP-adreso blokusesis koncerne modifikuri en ca pagino. Vu ankore povas redaktar altra pagini en ca Wiki.</strong> Vu povas vidar omna detali pri la blokuso en [[Special:MyContributions|account contributions]].\n\n$1 blokusis vu. La motivo esis <em>$2</em>.\n\n* Komenco dil blokuso: $8\n* Fino dil blokuso: $6\n* Motivo dil blokuso: $7\n* Blokuso #$5",
        "blockedtext": "<strong>Vua uzantonomo od IP-adreso blokusesis.</strong>\n\n$1 blokusis vu.\nLa motivo esis <em>$2</em>.\n\n* Komenco di la blokuso: $8\n* Fino di la blokuso: $6\n* Motivo dil blokuso: $7\n\nVu povas kontaktar $1 od altra [[{{MediaWiki:Grouppage-sysop}}|administrero]] por diskutar la blokuso.\nVu ne povas uzar \"email this user\" por sendar e-posto ecepte se valida email indikesis en tua [[Special:Preferences|preferaji dil uzanto]], e se vu ne blokusesis por uzar ol.\nVua nuna IP-adreso esas $3, e la ID dil blokuso esas #$5.\nVoluntez inkluzor omna detali adsupre en omna demandi quin vu facos.",
        "autoblockedtext": "<strong>Vua uzantonomo od IP-adreso blokusesis.</strong>\n\n$1 blokusis vu.\nLa motivo esis <em>$2</em>.\n\n* Komenco di la blokuso: $8\n* Fino di la blokuso: $6\n* Persono blokusata: $7\n\nVu povas kontaktar $1 od altra [[{{MediaWiki:Grouppage-sysop}}|administrero]] por diskutar pri la blokuso.\nVu ne povas uzar \"email this user\" por sendar e-posto, ecepte se valida email indikesis en tua [[Special:Preferences|preferaji dil uzero]], e se vu ne blokusesis por uzar ol.\nVua nuna IP-adreso esas $3, e la ID dil blokuso esas #$5.\nVoluntez inkluzor omna detali adsupre en omna demandi quin vu facos.",
        "systemblockedtext": "Vua uzero-nomo od IP-adreso blokusabis automatale da MediaWiki.\nLa motivo esas:\n\n:<em>$2</em>\n\n* Komenco di la blokuso: $8\n* Fino di la blokuso: $6\n* Persono blokuzata: $7\n\nVua nuna IP-adreso esas $3.\nVoluntez inkluzar omna detalii furnisita adsupre, en irga demandi quin vu facos.",
        "blockednoreason": "nula motivo donesis",
        "whitelistedittext": "Vu mustas $1 por redaktar pagini.",
+       "confirmedittext": "Vu mustas konfirmar vua adreso di e-posto ante ke vu povas redaktar pagini. Voluntez informar e validigar vua e-posto adreso tra vua [[Special:Preferences|preferaji di uzero]].",
        "nosuchsectiontitle": "On ne povis trovar la seciono",
        "nosuchsectiontext": "Vu probis redaktar seciono qua na existas.\nOl posible movesis od efacesis dum ke vu vidabis la pagino.",
        "loginreqtitle": "Eniro esas postulata",
        "anontalkpagetext": "----\n<em>Yen la diskuto-pagino por anonima uzero, qua ankore ne kreis konto, o se kreis, ne uzas ol.</em>\nDo, ni mustas uzar la IP-adreso por identifikar li.\nCa IP-adreso povas uzesar da multa uzeri.\nSe vu esas anonima uzero e kreas ke nerelevanta komenti sendesis a vu, voluntez [[Special:CreateAccount|krear konto]], o [[Special:UserLogin|facar 'log in']] por preventar futura konfundo kun altra anonima uzeri.",
        "noarticletext": "Til nun ne existas texto en ica pagino.\nVu povas [[Special:Search/{{PAGENAME}}|serchar ica titulo]] en altra pagini, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} serchar en la relata registri], o [{{fullurl:{{FULLPAGENAME}}|action=edit}} redaktar ica pagino]</span>.",
        "noarticletext-nopermission": "Til nun ne existas texto en ica pagino.\nVu povas [[Special:Search/{{PAGENAME}}|serchar ica titulo]] en altra pagini, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} serchar en la relata registri], o [{{fullurl:{{FULLPAGENAME}}|action=edit}} redaktar ica pagino]</span>, tamen vu ne havas permiso por krear ica pagino.",
+       "missing-revision": "La revizo $1 de la pagino \"{{FULLPAGENAME}}\" ne existas.\n\nLa frequa kauzo di ta mesajo esas existar ligilo por ula pagino qua efacesis antee.\nDetali pri to esas lektebla en la [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} deletion log].",
        "userpage-userdoesnotexist": "Uzeronomo \"$1\" ne registragesis.\nVoluntez konfirmar se vu volas krear/redaktar ica pagino.",
        "userpage-userdoesnotexist-view": "L'uzeronomo \"$1\" ne enrejistresis.",
        "blocked-notice-logextract": "Ica uzero nun esas blokusita.\nLa lasta protokolo pri blokuso esas videbla adinfre, por refero:",
        "note": "'''Noto:'''",
        "previewnote": "<strong>Atencez ke ico esas nur prevido.</strong> Ol ne registragesis ankore!",
        "continue-editing": "Irez a la redakto-areo",
-       "session_fail_preview": "'''Pardonez! Ni ne povis traktar vua redakto pro perdo di sesiono donaji.'''\nVoluntez probar itere.\nSe ol ankore nefuncionas, probez [[Special:UserLogout|ekirar]] e pose enirar.",
+       "session_fail_preview": "Pardonez! Ni ne povis traktar vua redakto pro perdo di informi de la sesiono.\n\nPosible vua sesiono finis. <strong>Voluntez verifikar se vu duras esar konektata, e probez itere.</strong>\n\nSe to ankore nefuncionar, probez [[Special:UserLogout|ekirar]] e seque rienirar.",
        "session_fail_preview_html": "Pardonez! Ni ne povis recevar vua redakto pro perdajo di dati.\n\n<em>Pro ke la wiki {{SITENAME}} permisas uzar bruta HTML, la previdado celesas por preventar ataki uzante JavaScript.</em>\n\n<strong>Se la probo di redakto esas legitima, voluntez itere sendar ol.</strong>\nSe duros ne funcionar, facez [[Special:UserLogout|logout]] ed itere facez login. Videz se vua retonavigilo (browser) permisas uzar 'cookies' de ica retosituo.",
+       "edit_form_incomplete": "<strong>Kelka parti de la redakto-formulario ne sendesis a la centrala komputero. Verifikez du foyi se vua redakti esas integra, e probez itere sendar li.</strong>",
        "editing": "Vu redaktas $1",
        "creating": "Vu kreas $1",
        "editingsection": "Vu redaktas $1 (seciono)",
        "unicode-support-fail": "Semblas ke vua retnavigilo ne suportas Unicode. To bezonesas por redaktar ica pagino e, pro to, vua redakto ne konservesis.",
        "yourdiff": "Diferi",
        "copyrightwarning": "Voluntez memorar ke omna kontributi a {{SITENAME}} esas sub la $2 (Videz $1 por detali).\nSe vu ne deziras ke altri modifikez vua artikli od oli distributesez libere, lore voluntez ne skribar oli hike.<br />\nPublikigante vua skribajo hike, vu asertas ke olu skribesis da vu ipsa o kopiesis de libera fonto.\n'''NE SENDEZ ARTIKLI KUN ''COPYRIGHT'' SEN PERMISO!'''",
+       "editpage-cannot-use-custom-model": "La modelo pri kontenajo di ca pagino ne povas modifikesar.",
+       "longpageerror": "<strong>Eroro: La texto quon vu sendis esas granda de {{PLURAL:$1|1 bicoko* (kbyte)|$1 bicoki* (kbytes)}}, e to esas plu granda kam {{PLURAL:$2|1 kbyte|$2 kbytes}}.</strong>\nLa texto ne povis prezervesar.",
        "protectedpagewarning": "<strong>Averto: Ica pagino esas protektita por ke nur uzeri kun administero-yuri povas redaktar ol.</strong>\nLa maxim recenta en-registrago provizesas:",
        "semiprotectedpagewarning": "<strong>Noto:</strong> Ica pagino protektesis, do nur enrejistrita uzeri povos modifikar ol.\nLa lasta modifiko en lua stando ('log') montresas adinfre, quale refero:",
        "cascadeprotectedwarning": "<strong>Noto:</strong> Ica pagino protektesis, do nur uzeri kun [[Special:ListGroupRights|specifika yuri]] povas redaktar ol, pro ol interpozesas en la sequanta {{PLURAL:$1|pagino|pagini}}, protektita en kaskado:",
        "templatesusedpreview": "{{PLURAL:$1|Shablono|Shabloni}} uzata en ica prevido:",
        "templatesusedsection": "{{PLURAL:$1|Shablono|Shabloni}} uzata en ica seciono:",
        "template-protected": "(protektita)",
-       "template-semiprotected": "(mi-protektita)",
+       "template-semiprotected": "(miprotektita)",
        "hiddencategories": "Ca pagino esas membro di {{PLURAL:$1|1 celita kategorio|$1 celita kategorii}}:",
+       "nocreate-loggedin": "Vu ne povas krear nova pagini.",
        "permissionserrors": "Eroro permisal",
        "permissionserrorstext-withaction": "Vu ne darfas $2, pro la {{PLURAL:$1|kauzo|kauzi}} sequanta:",
        "recreate-moveddeleted-warn": "<strong>Atencez: Vu rikreos pagino qua antee efacesis.</strong>\n\nVu mustas konsiderar se esos konvenanta o ne riskribor ol.\nPor vua konoco, la motivo dil antea efaco montresas hike:",
        "moveddeleted-notice": "Ica pagino efacesis.\nL'efaco-registraro e la movo-registraro di la pagino povas videsar sequante, por konsulto.",
        "moveddeleted-notice-recent": "Pardonez, ica pagino efacesis recente (dum la lasta 24 hori).\nL'informo (log) pri l'efaco, la protektado e/o movo di la pagino povas videsar adinfre, por konsulto.",
        "log-fulllog": "Videz kompleta protokolo ('log')",
+       "edit-gone-missing": "Ne povis aktualigar la pagino.\nSemblas ke ol efacesis.",
        "edit-conflict": "Konflikto di editi.",
+       "edit-no-change": "Vua redakto ignoresis, pro nula modifikuro facesis en la texto.",
+       "edit-slots-cannot-add": "La sequanta {{{{PLURAL:$1|parto|parti}} ne suportesas hike: $2.",
        "postedit-confirmation-created": "La pagino kreesis.",
+       "postedit-confirmation-restored": "La pagino itere kreesis.",
        "postedit-confirmation-saved": "Vua redakto konservesis",
        "postedit-confirmation-published": "Vua redakturo publikigesis.",
        "edit-already-exists": "Ne povis krear nova pagino.\nOl ja existas.",
        "defaultmessagetext": "Ordinara mesajo-texto",
        "invalid-content-data": "Nevalida kontenajo",
+       "slot-name-main": "Precipua",
        "content-model-wikitext": "texto Wiki",
        "content-model-text": "simpla texto",
        "content-model-javascript": "JavaScript",
        "page_first": "unesma",
        "page_last": "finala",
        "histlegend": "Selektado por diferi: markizez la versioni por komparar e presez 'Enter' o la butono adinfre.<br />\nSurskriburo: '''({{int:cur}})''' = diferi kun la nuna versiono,\n'''({{int:last}})''' = diferi kun l'antea versiono,\n'''{{int:minoreditletter}}''' = mikra redakturo.",
-       "history-fieldset-title": "Serchar revizi",
+       "history-fieldset-title": "Serchar revizuri",
        "history-show-deleted": "Revizo nure efacita",
        "histfirst": "Maxim anciena",
        "histlast": "Maxim nova",
        "historysize": "({{PLURAL:$1|1 bicoko|$1 bicoki}})",
-       "historyempty": "(vakua)",
+       "historyempty": "vakua",
        "history-feed-title": "Historio di redakti",
        "history-feed-description": "Historio di redakti por ta pagino en la wikio",
        "history-feed-item-nocomment": "$1 ye $2",
+       "history-feed-empty": "La pagino demandata ne existas.\nPosible ol efacesis de la Wiki, o lua nomo modifikesis.\nVoluntez [[Special:Search|serchar en la Wiki]] pri nova pagini relevanta.",
        "history-edit-tags": "Redaktar etiketi de la versioni/revizi selektita",
        "rev-deleted-comment": "(rezumo di redakti forigesis)",
        "rev-deleted-user": "(uzantonomo forigita)",
        "rev-deleted-event": "(detali dil registro forigesis)",
        "rev-deleted-user-contribs": "[Uzero od IP-adreso eliminita - la redakto celesis de la kontributaji]",
+       "rev-deleted-text-permission": "La revizo de ca pagino <strong>efacesis</strong>.\nDetali pri to povas videsar en la [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} deletion log].",
        "rev-deleted-unhide-diff": "Un ek la revizuri de ica difero <strong>efacesis</strong>.\nVu povas lektar la detali che la [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} protokolo pri efacado].\nVu ankore povas [$1 vidar la difero], se vu deziros kontinuar.",
        "rev-delundel": "montrar/celar",
        "rev-showdeleted": "montrar",
        "revisiondelete": "Efacar/Restaurar revizi",
+       "revdelete-no-file": "L'arkivo mencionata ne existas.",
        "revdelete-show-file-submit": "Yes",
        "revdelete-text-text": "Versioni efacata duros aparar en la pagino-historio, tamen parto ek lia kontenaji ne restos publike videbla.",
+       "revdelete-hide-text": "Revizata texto",
        "revdelete-hide-image": "Celar kontenajo dil arkivo",
+       "revdelete-hide-name": "Celez emo e parametri",
        "revdelete-hide-comment": "Rezumo di redakto",
        "revdelete-hide-user": "uzeronomo di redaktanto/IP-adreso",
        "revdelete-radio-same": "(ne modifikez)",
        "savedprefs": "Vua preferaji registragesis.",
        "timezonelegend": "Tempala zono:",
        "localtime": "Lokala tempo:",
-       "timezoneuseoffset": "Altra (definez precize)",
+       "timezoneuseoffset": "Altra (informez precize la tempo-difero)",
+       "timezone-useoffset-placeholder": "Exemple pri valori: \"-07:00\" o \"01:00\"",
        "servertime": "Kloko en la servanto:",
        "guesstimezone": "Obtenar la kloko dil \"browser\"",
        "timezoneregion-africa": "Afrika",
        "prefs-custom-json": "Ordinara JSON",
        "prefs-custom-js": "Ordinara JavaScript",
        "prefs-common-config": "CSS/JSON/JavaScript partigita da omna 'skins':",
+       "prefs-reset-intro": "Vu povas uzar ca pagino por riinformar vua preferaji kom 'default'.\nVu ne povas desfacar ta modifiko.",
        "prefs-emailconfirm-label": "Konfirmado dil e-posto (e-mail):",
        "youremail": "Vua e-adreso:",
        "username": "{{GENDER:$1|Uzeronomo}}:",
        "prefs-advancedwatchlist": "Progresiva selektaji (advanced options)",
        "prefs-displayrc": "Montrez selektebli",
        "prefs-displaywatchlist": "Montrez selektebli",
+       "prefs-changesrc": "Modifikuri montrata",
+       "prefs-changeswatchlist": "Modifikuri montrata",
+       "prefs-pageswatchlist": "Pagini surveyata",
        "prefs-tokenwatchlist": "Token",
        "prefs-diffs": "Diferi",
        "prefs-help-prefershttps": "Ica preferajo efektigesos dum vua sequanta 'login'.",
        "saveusergroups": "Konservez la grupi di {{GENDER:$1|uzero}}",
        "userrights-groupsmember": "Membro di:",
        "userrights-groupsmember-auto": "Implicita membro de:",
-       "userrights-groups-help": "Vu povas modifikar la grupi en qua ica uzero esas:\n* Markizita buxo indikas grupi en qui la uzero esas.\n* Ne markizita buxo indikas grupo en qua l'uzero ne esas.\n* La signo ''*'' indikas ke vu ne povas removar la grupo pos adicionar la membro, o removar la membro de la grupo.\n* La signo # indikas ke vu nur povas ajornar l'expiro-dato di la membresko en ca grupo; vu ne povas anticipar ol.",
+       "userrights-groups-help": "Vu povas modifikar la grupi en qua ica uzero esas:\n* Markizita buxi indikas grupi en qui la uzero esas.\n* Buxi sen markizo indikas grupi en qui l'uzero ne esas.\n* La signo ''*'' indikas ke vu ne povas removar la grupo pos adicionar membro, o removar membro de la grupo.\n* La signo # indikas ke vu nur povas ajornar l'expiro-dato di la membresko en ca grupo; vu ne povas anticipar ol.",
        "userrights-reason": "Motivo:",
        "userrights-changeable-col": "Grupi quin vu povas chanjar",
        "userrights-unchangeable-col": "Grupi quin vu ne povas chanjar",
        "right-suppressrevision": "Vidar, celar e deskovrar specifika revizi di pagini de irga uzero",
        "right-blockemail": "Blokusar uzero pri sendar e-posto",
        "right-unblockself": "Desblokusar su",
+       "right-protect": "Modifikar la protekto-nivelo e la pagini protektata en serio",
        "right-viewmywatchlist": "Vidar vua propra atenco-listo",
        "right-editmyoptions": "Modifikar vua propra preferaji",
        "right-rollback": "Rapide retrorular la redakti da la lasta uzero qua redaktis specigita pagino",
        "recentchanges": "Recenta chanji",
        "recentchanges-legend": "Recenta chanji preferaji",
        "recentchanges-summary": "Regardez la maxim recenta chanji en Wiki per ica pagino.",
-       "recentchanges-noresult": "Ne eventis modifiki segun ci kriterii, dum la periodo mencionita.",
+       "recentchanges-noresult": "Ne eventis modifikuri segun ca kriterii, dum la periodo mencionata.",
        "recentchanges-feed-description": "Regardez la maxim recenta chanji en la Wiki por ica pagino.",
        "recentchanges-label-newpage": "Ca redaktajo kreis nova pagino",
        "recentchanges-label-minor": "Ica es mikra redaktajo",
        "rcfilters-filter-editsbyself-description": "Vua propra kontributaji",
        "rcfilters-filter-editsbyother-label": "Modifikuri da altri",
        "rcfilters-filter-editsbyother-description": "Omna modififuri, ecepte vua propra.",
-       "rcfilters-filtergroup-userExpLevel": "Registro e nivelo di konoco dil uzero",
+       "rcfilters-filtergroup-user-experience-level": "Registro e nivelo di konoco dil uzero",
        "rcfilters-filter-user-experience-level-registered-label": "Enrejistrita",
        "rcfilters-filter-user-experience-level-registered-description": "Enrejistrita redakteri.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Sen registro",
        "rcfilters-filter-categorization-description": "Registri pri pagini qui adjuntesis o removesis de kategorii.",
        "rcfilters-filter-logactions-label": "Agadi enrejistrata",
        "rcfilters-filter-logactions-description": "Agadi dal administreri, kreado di konti, efaco di pagini, sendo di arkivi...",
-       "rcfilters-filtergroup-lastRevision": "Maxim recenta modifikuri",
+       "rcfilters-filtergroup-lastrevision": "Maxim recenta modifikuri",
        "rcfilters-filter-lastrevision-label": "Nuna versiono",
        "rcfilters-filter-lastrevision-description": "Nur la maxim recenta modifikuro di ula pagino.",
        "rcfilters-filter-previousrevision-label": "Ne esas la lasta modifikuro",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "r",
-       "number_of_watching_users_pageview": "[$1 observanta {{PLURAL:$1|uzero|uzeri}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|bicoko|bicoki}} pos la modifiki",
        "newsectionsummary": "/* $1 */ nova seciono",
        "rc-enhanced-expand": "Montrez detali",
        "pageswithprop-text": "Ica pagino listas pagini qui havas partikulara propraji.",
        "pageswithprop-submit": "Irez",
        "doubleredirects": "Duopla ridirektili",
+       "doubleredirectstext": "Ca pagino montras pagini qui ridirektas ad altra ridirekto-pagini.\nSingla lineo kontenas ligili al unesma e a la duesma ridirekto, ed anke la emo di la duesma ridirekto, qua ordinare esas la \"vera\" emo-pagino a quo l'unesma ridirekto mustus apuntar.\n<del>Surstrekizata ligili</del> reparesis.",
+       "double-redirect-fixed-move": "[[$1]] movesis.\nOl automatale rinovigesis, e nun ol apuntas a [[$2]].",
        "double-redirect-fixer": "Reparar ridirekti",
        "brokenredirects": "Ridirektili nekorekta",
        "brokenredirectstext": "La sequanta ridirektili ligas a ne-existanta pagini:",
        "longpages": "Longa pagini",
        "deadendpages": "Pagini sen ekiraji",
        "protectedpages": "Protektita pagini",
+       "protectedpages-filters": "Filtrili:",
+       "protectedpages-indef": "Nur nedefinita protekturi",
+       "protectedpages-summary": "Ca pagino listizas existanta pagini qui esas protektata nun. Por listo pri tituli protektata kontre kreado, videz [[{{#special:ProtectedTitles}}|{{int:protectedtitles}}]].",
+       "protectedpages-cascade": "Nur protekti ligata",
+       "protectedpages-noredirect": "Celar ridirekti",
+       "protectedpages-page": "Pagino",
+       "protectedpages-expiry": "Finos ye",
+       "protectedpages-params": "Parametri di protektado",
+       "protectedpages-submit": "Montrez pagini",
+       "protectedpages-unknown-timestamp": "Nekonocata",
+       "protectedpages-unknown-performer": "Nekonocata uzero",
        "protectedtitles": "Protektita tituli",
        "listusers": "Uzerolisto",
        "listusers-editsonly": "Montrez nur uzeri qui facis redakti",
        "mailnologintext": "Vu mustas [[Special:UserLogin|enirir]] e havar valida e-adreso en vua [[Special:Preferences|preferaji]] por sendar e-posto ad altra uzanti.",
        "emailuser": "Sendar e-posto a ca uzero",
        "emailuser-title-notarget": "Sendar e-posto al uzero",
+       "emailpagetext": "Vu povas uzar la sequanta pagino por sendar e-posto al {{GENDER:$1|uzero}}.\nL'adreso di e-posto quon vu mencionis en [[Special:Preferences|vua preferaji]] aparos en la \"De\" adreso de la mesajo, do la recevero de vua mesajo povos respondar direte a vu.",
        "defemailsubject": "{{SITENAME}} e-mesaji de uzero \"$1\"",
        "usermaildisabledtext": "Vu ne povas sendar e-posto ad altra uzeri en ca Wiki",
        "noemailtitle": "Ne esas e-adreso",
        "confirm": "Konfirmez",
        "excontent": "La kontenajo esis: \"$1\"",
        "excontentauthor": "la kontenajo esis: \"$1\", e l'unika redaktero esis \"[[Special:Contributions/$2|$2]]\" ([[User talk:$2|talk]])",
-       "exbeforeblank": "La kontenajo ante efaco esis: '$1'",
+       "exbeforeblank": "La kontenajo ante l'efaco esis: '$1'",
        "delete-confirm": "Efacar \"$1\"",
        "delete-legend": "Efacar",
        "historywarning": "<strong>Averto:</strong> La pagino quan vu efaceskas havas historio kun $1 {{PLURAL:$1|revizo|revizi}}:",
        "sessionfailure": "Semblas ke eventis problemo kun vua sesiono di 'login';\nta agado abrogesis, quale presorgo kontre sequestro di sesiono ('hijacking').\nVoluntez risendar la formulario, plenigita.",
        "changecontentmodel": "Chanjar la konteno-modelo di (u)la pagino",
        "changecontentmodel-title-label": "Titulo di la pagino",
+       "changecontentmodel-model-label": "Nova modelo pri kontenajo",
+       "changecontentmodel-reason-label": "Motivo:",
+       "changecontentmodel-submit": "Modifikar",
        "log-name-contentmodel": "Registro di la modifikuri en la modelo pri kontenajo",
        "logentry-contentmodel-change-revertlink": "restaurar",
        "logentry-contentmodel-change-revert": "restaurar",
        "protect-unchain-permissions": "Desblokusar altra selekti pri protektado",
        "protect-text": "Hike vu povas vidar e modifikar la nivelo di protekto di la pagino <strong>$1</strong>.",
        "protect-cascadeon": "Ica pagino esas nune protektita, pro ke existas kopio de ol en {{PLURAL:$1|pagino qua|pagini qui}} protektesas \"seriale\" (cascade protection).\nModifiki en la nivelo di protektado por ica pagino ne modifikos la \"protekto seriala\".",
-       "protect-default": "Permisar omna uzanti",
+       "protect-default": "Permisar omna uzeri",
        "protect-fallback": "Permisez nur uzeri kun permiso \"$1\"",
        "protect-level-autoconfirmed": "Permisar nur uzeri automatale konfirmata",
        "protect-level-sysop": "Permisar nur administreri",
        "protect-cascade": "Protektar pagini inkluzita en ica pagino (protekto en sequo)",
        "protect-othertime": "Altra tempo:",
        "protect-othertime-op": "altra tempo",
+       "protect-existing-expiry": "Nuna expiro-tempo: $3, $2",
+       "protect-existing-expiry-infinity": "Nuna expiro-tempo di la protektado: nefinita",
        "protect-otherreason": "Altra/suplementala motivo:",
        "protect-otherreason-op": "Altra motivo",
        "protect-dropdown": "*Frequa motivi por protektado\n** Intensa vandalismo\n** Intensa atako per 'spam'\n** Redakto-milito neutila\n** Pagino multe vizitata",
        "protect-expiry-options": "1 horo:1 hour,1 dio:1 day,1 semano:1 week,2 semani:2 weeks,1 monato:1 month,3 monati:3 months,6 monati:6 months,1 yaro:1 year,nefinita:infinite",
        "restriction-type": "Permiso:",
+       "restriction-level": "Nivelo di restrikto:",
        "minimum-size": "Minima grandeso",
        "maximum-size": "Maxima grandeso:",
        "pagesize": "(bicoki)",
        "restriction-move": "Movar",
        "restriction-create": "Krear",
        "restriction-upload": "Adkargar",
+       "restriction-level-sysop": "komplete protektita",
+       "restriction-level-autoconfirmed": "miprotektita",
+       "restriction-level-all": "irga nivelo",
        "undelete": "Vidar efacita pagini",
        "undeletepage": "Vidar e restaurar efacita pagini",
        "undeletepagetitle": "<strong>Yen la efacita versioni di la pagino [[:$1|$1]]</strong>.",
        "undeleteinvert": "Inversigar selektajo",
        "undeletecomment": "Motivo:",
        "undeletedpage": "<strong>$1 restauresis</strong>\n\nVidez la [[Special:Log/delete|'log' pri efaci]] por vidar omna recenta efaci e restauri.",
+       "undelete-search-title": "Serchez efacita pagini",
        "undelete-search-box": "Serchez efacita pagini",
+       "undelete-search-prefix": "Montrez pagini de:",
        "undelete-search-submit": "Serchar",
        "undelete-show-file-submit": "Yes",
        "namespace": "Nomaro:",
        "ipblocklist-submit": "Serchar",
        "ipblocklist-otherblocks": "Altra {{PLURAL:$1|blokuso|blokusi}}",
        "infiniteblock": "nefinita",
+       "expiringblock": "finas ye $2 kloki, en $1",
        "emailblock": "e-posto blokusita",
        "blocklist-nousertalk": "ne povas redaktar lua propra diskuto-pagino",
        "blocklink": "blokusar",
        "blocklog-showlog": "Ica uzero ja blokusesis antee.\nInfre esas l'informo pri la blokuso, por vua konoco:",
        "blocklogentry": "blokusis [[$1]] dum periodo di $2 $3",
        "reblock-logentry": "modifikis la tempo di blokuso [[$1]] por durado di $2 $3",
+       "blocklogtext": "Ca esas protokolo pri agadi di blokuso o desblokuso.\nL'adresi IP automatale blokusata ne montresas che la listo.\nVidez la [[Special:BlockList|listo pri blokuso]] por la nuna listo pri blokusi e proskriptadi.",
        "unblocklogentry": "desblokusis \"$1\"",
+       "block-log-flags-anononly": "nur anonima uzeri",
        "block-log-flags-nocreate": "ne povas krear konto",
        "block-log-flags-noautoblock": "automatala blokuso nekapabligata",
        "block-log-flags-noemail": "e-posto blokusita",
        "delete_and_move_reason": "Efacita por permisar la chanjo di la nomo di la pagino \"[[$1]]\"",
        "move-leave-redirect": "Mantenez ridirektilo inter la du",
        "export": "Exportacar pagini",
+       "exporttext": "Vu povas exportacar la texto e historio pri redakto de ula pagino o grupo di pagini envelopata en ula XML.\nCa povas importacar por altra wiki tra l'uzo di MediaWiki, per la [[Special:Import|pagino di importaco]].\n\nPor exportar pagini, mencionez la titulo en la texto-buxo adinfre, un titulo per singla lineo, e selektez se vu deziras vidar la nuna ed anke l'antea redakturi (singla antea revizo en singla lineo), o nur vidar la nuna revizo e l'informi pri ol.\n\nIn the latter case you can also use a link, for example [[{{#Special:Export}}/{{MediaWiki:Mainpage}}]] for the page \"[[{{MediaWiki:Mainpage}}]]\".",
        "exportcuronly": "On inkluzas nur la nuna revizo, ne la kompleta versionaro",
        "export-addcattext": "Adjuntar pagini ek kategorio:",
        "export-addcat": "Adjuntar",
        "tooltip-n-recentchanges": "Listo di recenta chanji en la wiki.",
        "tooltip-n-randompage": "Vizitez hazarda pagino",
        "tooltip-n-help": "La loko por trovar ulo.",
-       "tooltip-t-whatlinkshere": "Listo di omna Wikipagini qui ligesas adhike",
+       "tooltip-t-whatlinkshere": "Listo pri omna Wikipagini qui ligesas adhike",
        "tooltip-t-recentchangeslinked": "Recenta chanji di pagini ligita de ca pagino",
        "tooltip-feed-rss": "RSS provizero por ica pagino",
        "tooltip-feed-atom": "Atom provizero por ica pagino",
        "pageinfo-hidden-categories": "Celita {{PLURAL:$1|kategorio|kategorii}} ($1)",
        "pageinfo-templates": "Inkluzis {{PLURAL:$1|shablono|shabloni}} ($1)",
        "pageinfo-toolboxlink": "Informo di ca pagino",
+       "pageinfo-redirectsto": "Ridirektar a",
        "pageinfo-contentpage": "Konsiderita kontenajo-pagino",
        "pageinfo-contentpage-yes": "Yes",
+       "pageinfo-category-total": "Totalo di membri",
+       "pageinfo-category-pages": "Quanto di pagini",
+       "pageinfo-category-subcats": "Quanto di subkategorii",
+       "pageinfo-category-files": "Quanto di arkivi",
        "markaspatrolledtext": "Patroliar ica pagino",
        "patrol-log-page": "Protokolo pri patroliado",
        "previousdiff": "← Plu anciena versiono",
        "tags-update-blocked": "Dum ke {{GENDER:$1|vu}} blokusabos, vu ne povos modifikar od efacar etiketi.",
        "tags-edit-chosen-no-results": "Trovesis nula etiketo qua koincidas kun to",
        "tags-edit-reason": "Motivo:",
+       "compare-page1": "Pagino 1",
+       "compare-page2": "Pagino 2",
        "dberr-problems": "Pardonez! Ica retopagino subisas teknikala problemi.",
        "dberr-again": "Voluntez vartar kelka minuti, e riprobez acesar ol.",
        "dberr-info": "(Ne povis acesar la datumaro: $1)",
        "expand_templates_output": "Rezulto",
        "expand_templates_ok": "O.K.",
        "expand_templates_preview": "Previdar",
+       "pagelanguage": "Modifikar la linguo di la pagino",
        "pagelang-language": "Linguo",
+       "right-pagelang": "Modifikar l'idiomo di la pagino",
        "mediastatistics-nbytes": "{{PLURAL:$1|$1 bicoko*|$1 bicoki*}} ($2; $3%)",
        "special-characters-group-latin": "Latina",
        "special-characters-group-latinextended": "Latina extensita",
        "mw-widgets-dateinput-no-date": "Nula dato selektita",
        "mw-widgets-dateinput-placeholder-day": "YYYY-MM-DD",
        "mw-widgets-titleinput-description-redirect": "Ridirektar ad $1",
+       "date-range-to": "Til (dato):",
        "sessionprovider-nocookies": "''Bisquiti'' forsan esas desacendita. Certigez ke vu acendar ''bisquiti'' e riprobez.",
        "randomrootpage": "Hazarda radikopagino",
        "log-action-filter-delete": "Tipo di efacado:",
+       "log-action-filter-managetags": "Tipo di agado por jerar l'etiketo:",
        "log-action-filter-all": "Omno",
        "log-action-filter-contentmodel-change": "Modifiko di la kontenajo di ula modelo",
        "log-action-filter-suppress-reblock": "User suppression by reblock",
-       "authprovider-resetpass-skip-label": "Preterpasar"
+       "authprovider-resetpass-skip-label": "Preterpasar",
+       "authpage-cannot-login-continue": "Ne povis durar l'eniro-procedi. Posible vua sesiono finis pos kelka tempo sen uzo."
 }
index 39d3335..442287e 100644 (file)
        "botpasswords-label-cancel": "Hætta við",
        "botpasswords-label-delete": "Eyða",
        "botpasswords-label-resetpassword": "Endurstilla lykilorðið",
+       "botpasswords-label-grants": "Tiltækar heimildir:",
        "botpasswords-bad-appid": "Vélmennanafnið „$1“ er ógilt.",
        "botpasswords-created-title": "Vélmennalykilorð var búið til",
        "botpasswords-updated-title": "Vélmennalykilorð var uppfært",
        "prefs-help-prefershttps": "Þessi stilling tekur gildi í næsta skiptið sem þú skráir þig inn.",
        "prefswarning-warning": "Þú hefur gert breytingar á kjörstillingum þínum sem ekki er búið að vista.\nEf þú ferð af þessari síðu án þess að smella á \"$1\" verða kjörstillingar þínar ekki uppfærðar.",
        "prefs-tabs-navigation-hint": "Ábending: Þú getur notað vinstri og hægri örvalyklana til að flakka á milli flipa í flipalistanum.",
-       "userrights": "Notandaréttindi",
+       "userrights": "Réttindi notenda",
        "userrights-lookup-user": "Velja notanda",
        "userrights-user-editname": "Skráðu notandanafn:",
        "editusergroup": "Hlaða inn notanda hópum",
        "rcfilters-filter-editsbyself-description": "Þín eigin framlög.",
        "rcfilters-filter-editsbyother-label": "Breytingar eftir aðra",
        "rcfilters-filter-editsbyother-description": "Allar breytingar nema þínar eigin.",
-       "rcfilters-filtergroup-userExpLevel": "Skráning notanda og reynsla",
+       "rcfilters-filtergroup-user-experience-level": "Skráning notanda og reynsla",
        "rcfilters-filter-user-experience-level-registered-label": "Skráð/ur",
        "rcfilters-filter-user-experience-level-registered-description": "Innskráðir notendur.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Óskráður",
        "rcfilters-filter-categorization-description": "Skrá um að síðum hefur verið bætt við eða þær fjarlægðar úr flokkum.",
        "rcfilters-filter-logactions-label": "Skráðar aðgerðir",
        "rcfilters-filter-logactions-description": "Stjórnendaaðgerðir, nýir aðgangar, eyðingar á síðum, upphleðslur…",
-       "rcfilters-filtergroup-lastRevision": "Nýjustu útgáfur",
+       "rcfilters-filtergroup-lastrevision": "Nýjustu útgáfur",
        "rcfilters-filter-lastrevision-label": "Nýjasta útgáfa",
        "rcfilters-filter-lastrevision-description": "Eingöngu nýjasta breytingin á síðu.",
        "rcfilters-filter-previousrevision-label": "Ekki nýjasta útgáfa",
        "newpageletter": "N",
        "boteditletter": "v",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[{{PLURAL:$1|notandi skoðandi|$1 notendur skoðandi}}]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|bæt|bæti}} eftir breytingu",
        "newsectionsummary": "Nýr hluti: /* $1 */",
        "img-auth-nopathinfo": "Vantar upplýsingar um slóð.\nÞjónninn þinn er ekki stilltur til að senda REQUEST_URI og/eða PATH_INFO breyturnar.\nEf svo er, prófaðu að virkja $wgUsePathInfo.\nSkoðaðu https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Umbeðin slóð var ekki í stilltri innhleðslumöppu.",
        "img-auth-badtitle": "Mistókst að búa til gildan titil útfrá „$1”.",
-       "img-auth-nologinnWL": "Þú ert ekki skráð(ur) inn og „$1“ er ekki á hvítlista.",
        "img-auth-nofile": "Skráin \"$1\" er ekki til.",
        "img-auth-isdir": "Þú ert að reyna að nálgast möppuna „$1“.\nAðeins skráaraðgangur er leyfður.",
        "img-auth-streaming": "Streymi \"$1\".",
        "speciallogtitlelabel": "Beinist að (titill eða {{ns:user}}:notandanafn fyrir notanda):",
        "log": "Aðgerðaskrár",
        "logeventslist-submit": "Birta",
+       "logeventslist-patrol-log": "Yfirferðarskrá",
+       "logeventslist-tag-log": "Aðgerðaskrá yfir merki",
        "all-logs-page": "Allar aðgerðir",
        "alllogstext": "Safn allra aðgerðaskráa {{SITENAME}}.\nÞú getur takmarkað listann með því að velja tegund aðgerðaskráar, notandanafn, eða síðu.",
        "logempty": "Engin slík aðgerð fannst.",
        "listgrouprights-namespaceprotection-header": "Takmarkanir nafnrýmis",
        "listgrouprights-namespaceprotection-namespace": "Nafnrými",
        "listgrouprights-namespaceprotection-restrictedto": "Réttindi sem leyfa notanda að breyta",
+       "listgrants": "Veittar heimildir",
        "listgrants-rights": "Réttindi",
        "listgrants-grant-display": "$1 <code>($2)</code>",
        "trackingcategories-name": "Heiti skilaboða",
        "revertpage": "Tók aftur breytingar [[Special:Contributions/$2|$2]] ([[User talk:$2|spjall]]), breytt til síðustu útgáfu [[User:$1|$1]]",
        "revertpage-nouser": "Tók aftur breytingar falins notanda til síðustu útgáfu {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Tók til baka breytingar eftir {{GENDER:$3|$1}};\nsetti yfir á síðustu útgáfu eftir {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Tók aftur breytingar $1;\nbreytti í síðustu útgafu $2. [$3 Sýna breytingar]",
        "sessionfailure-title": "Mistök í setu",
        "sessionfailure": "Líklega er vandamál með innskráningarsetuna þína;\nhætt hefur verið við þessa aðgerð sem vörn gegn mögulegu samskiptaráni setunar.\nReyndu að senda upplýsingarnar aftur inn.",
        "changecontentmodel": "Breyta efnislíkani síðu",
        "allmessagesdefault": "Sjálfgefinn texti skilaboða",
        "allmessagescurrent": "Núverandi texti",
        "allmessagestext": "Þetta er listi yfir kerfismeldingar í MediaWiki-nafnrýminu.\nSkoðaðu vefinn fyrir [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki-staðfærsluna] og [https://translatewiki.net translatewiki.net] ef þú vilt taka þátt í almennri MediaWiki-staðfærslu.",
-       "allmessagesnotsupportedDB": "Það er ekki hægt að nota <strong>$wgUseDatabaseMessages</strong> því hefur verið gert óvirkt.",
+       "allmessages-not-supported-database": "Það er ekki hægt að nota <strong>$wgUseDatabaseMessages</strong> því hefur verið gert óvirkt.",
        "allmessages-filter-legend": "Sía",
        "allmessages-filter": "Sía með breytingarstöðu:",
        "allmessages-filter-unmodified": "Óbreytt",
        "specialpages-group-highuse": "Mest notuðu síðurnar",
        "specialpages-group-pages": "Listar yfir síður",
        "specialpages-group-pagetools": "Síðuverkfæri",
-       "specialpages-group-wiki": "Gögn og tól",
+       "specialpages-group-wiki": "Gögn og verkfæri",
        "specialpages-group-redirects": "Tilvísaðar kerfissíður",
        "specialpages-group-spam": "Amasendingasíur",
        "specialpages-group-developer": "Forritaratól",
index 6eac855..3f4d276 100644 (file)
                        "Malore",
                        "Ruthven",
                        "Manfredi26",
-                       "Albe Albe 460"
+                       "Albe Albe 460",
+                       "Senpremì",
+                       "Ignazio Cannata"
                ]
        },
        "tog-underline": "Sottolinea i collegamenti:",
        "tog-norollbackdiff": "Non mostrare il confronto tra versioni dopo aver effettuato un rollback",
        "tog-useeditwarning": "Avvisa quando si esce da una pagina di modifica con modifiche non salvate",
        "tog-prefershttps": "Usa sempre una connessione sicura quando si effettua l'accesso",
+       "tog-showrollbackconfirmation": "Mostra una richiesta di conferma quando si clicca su un link di rollback",
        "underline-always": "Sempre",
        "underline-never": "Mai",
        "underline-default": "Impostazioni predefinite del browser o del tema",
        "returnto": "Torna a $1.",
        "tagline": "Da {{SITENAME}}.",
        "help": "Aiuto",
+       "help-mediawiki": "Aiuto su MediaWiki",
        "search": "Ricerca",
        "search-ignored-headings": " #<!-- lascia questa riga esattamente come è --> <pre>\n# Elenco delle intestazioni che saranno ignorate dalla ricerca.\n# Le modifiche a questa pagina saranno effettive non appena la pagina sarà indicizzata.\n# Puoi forzare la re-indicizzazione di una pagina effettuando una modifica nulla.\n# La sintassi è la seguente:\n#   * Tutto dal carattere \"#\" alla fine della riga è un commento\n#   * Tutte le righe non vuote sono le intestazioni esatte da ignorare, maiuscolo/minuscolo e tutto\nNote\nVoci correlate\nCollegamenti esterni\n #</pre> <!-- lascia questa riga esattamente come è -->",
        "searchbutton": "Ricerca",
        "badarticleerror": "Operazione non consentita per questa pagina.",
        "cannotdelete": "Non è stato possibile cancellare la pagina o il file \"$1\".\nPotrebbe essere stato già cancellato da qualcun altro.",
        "cannotdelete-title": "Impossibile cancellare la pagina \"$1\"",
+       "delete-scheduled": "La pagina \"$1\" è stata programmata per la cancellazione.\nAbbi pazienza.",
        "delete-hook-aborted": "La cancellazione è stata annullata dall'hook.\nNon è stata restituita alcuna spiegazione.",
        "no-null-revision": "Non è stato possibile creare una versione nulla per la pagina \"$1\"",
        "badtitle": "Titolo non corretto",
        "ns-specialprotected": "Le pagine speciali non possono essere modificate.",
        "titleprotected": "La creazione di una pagina con questo titolo è stata bloccata da [[User:$1|$1]].\nLa motivazione è la seguente: <em>$2</em>.",
        "filereadonlyerror": "Non è stato possibile modificare il file \"$1\" poiché il repository di file \"$2\" è in modalità di sola lettura.\n\nL'amministratore di sistema che lo ha bloccato ha fornito questa motivazione: \"$3\".",
+       "invalidtitle": "Titolo non valido",
        "invalidtitle-knownnamespace": "Titolo non valido con namespace \"$2\" e testo \"$3\"",
        "invalidtitle-unknownnamespace": "Titolo non valido con namespace sconosciuto \"$1\" e testo \"$2\"",
        "exception-nologin": "Accesso non effettuato",
        "invalidemailaddress": "L'indirizzo e-mail indicato ha un formato non valido. Inserire un indirizzo valido o svuotare la casella.",
        "cannotchangeemail": "Gli indirizzi e-mail non possono essere modificati in questo wiki.",
        "emaildisabled": "Questo sito non può inviare messaggi di posta elettronica.",
-       "accountcreated": "Accesso creato",
+       "accountcreated": "Utenza creata",
        "accountcreatedtext": "È stata creata un'utenza per [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|msg]]).",
        "createaccount-title": "Creazione di un accesso a {{SITENAME}}",
        "createaccount-text": "Qualcuno ha creato un accesso a {{SITENAME}} ($4) a nome di $2, associato a questo indirizzo di posta elettronica. La password per l'utente \"$2\" è impostata a \"$3\".\nÈ opportuno eseguire un accesso quanto prima e cambiare la password immediatamente.\n\nSe l'accesso è stato creato per errore, si può ignorare questo messaggio.",
        "botpasswords-restriction-failed": "Le restrizioni di password bot impediscono questo accesso.",
        "botpasswords-invalid-name": "Il nome utente indicato non contiene il separatore per password bot (\"$1\").",
        "botpasswords-not-exist": "L'utente \"$1\" non dispone di una password bot chiamata \"$2\".",
+       "botpasswords-needs-reset": "La password per il bot di nome \"$2\" {{GENDER:$1|dell'utente}} \"$1\" deve essere reimpostata.",
+       "botpasswords-locked": "Non puoi accedere con una password bot poiché la tua utenza è bloccata.",
        "resetpass_forbidden": "Non è possibile modificare le password",
        "resetpass_forbidden-reason": "Non è possibile modificare le password: $1",
        "resetpass-no-info": "Devi aver effettuato l'accesso per accedere a questa pagina direttamente.",
        "userpage-userdoesnotexist-view": "L'utenza \"$1\" non è registrata.",
        "blocked-notice-logextract": "Questo utente è attualmente bloccato.\nL'ultimo elemento del registro dei blocchi è riportato di seguito per informazione:",
        "clearyourcache": "<strong>Nota:</strong> dopo aver salvato, potrebbe essere necessario pulire la cache del proprio browser per vedere i cambiamenti. \n*<strong>Firefox / Safari:</strong> tenere premuto il tasto delle maiuscole <em>Shift</em> e fare clic su <em>Ricarica</em>, oppure premere <em>Ctrl-F5</em> o <em>Ctrl-R</em> (<em>⌘-R</em> su Mac)\n*<strong>Google Chrome:</strong> premere <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> su un Mac)\n*<strong>Internet Explorer:</strong> tenere premuto il tasto <em>Ctrl</em> e fare clic su <em>Aggiorna</em>, oppure premere <em>Ctrl-F5</em>\n* <strong>Opera:</strong> Vai nel <em>Menu → Impostazioni</em> (<em>Opera → Preferenze</em> su un Mac) e poi in <em>Privacy & sicurezza → Pulisci dati del browser → Immagini e file nella cache</em>.",
-       "usercssyoucanpreview": "'''Suggerimento:''' usa il pulsante 'Visualizza anteprima' per provare il tuo nuovo CSS prima di salvarlo.",
-       "userjsyoucanpreview": "'''Suggerimento:''' usa il pulsante 'Visualizza anteprima' per provare il tuo nuovo JavaScript prima di salvarlo.",
+       "usercssyoucanpreview": "<strong>Suggerimento:<strong> usa il pulsante \"{{int:showpreview}}\" per provare il tuo nuovo CSS prima di salvarlo.",
+       "userjsonyoucanpreview": "<strong>Suggerimento:<strong> usa il pulsante \"{{int:showpreview}}\" per provare il tuo nuovo JSON prima di salvarlo.",
+       "userjsyoucanpreview": "<strong>Suggerimento:<strong> usa il pulsante \"{{int:showpreview}}\" per provare il tuo nuovo JavaScript prima di salvarlo.",
        "usercsspreview": "'''Questa è solo un'anteprima del proprio CSS personale. Le modifiche non sono ancora state salvate!'''",
        "userjsonpreview": "<strong>Questa è solo un'anteprima per provare il proprio JSON personale; le modifiche non sono ancora state salvate!</strong>",
        "userjspreview": "'''Questa è solo un'anteprima per provare il proprio JavaScript personale; le modifiche non sono ancora state salvate!'''",
        "page_first": "prima",
        "page_last": "ultima",
        "histlegend": "Confronto tra versioni: selezionare le caselle corrispondenti alle versioni desiderate e premere Invio o il pulsante in basso.\n\nLegenda: '''({{int:cur}})''' = differenze con la versione attuale, '''({{int:last}})''' = differenze con la versione precedente, '''{{int:minoreditletter}}''' = modifica minore",
-       "history-fieldset-title": "Ricerca per versioni",
+       "history-fieldset-title": "Filtra versioni",
        "history-show-deleted": "Solo versioni cancellate",
        "histfirst": "prima",
        "histlast": "ultima",
        "historysize": "({{PLURAL:$1|1 byte|$1 byte}})",
-       "historyempty": "(vuota)",
+       "historyempty": "vuota",
        "history-feed-title": "Cronologia",
        "history-feed-description": "Cronologia della pagina su questo sito",
        "history-feed-item-nocomment": "$1 il $2",
        "right-reupload-own": "Sovrascrive un file esistente caricato dallo stesso utente",
        "right-reupload-shared": "Sovrascrive localmente file presenti nell'archivio condiviso",
        "right-upload_by_url": "Carica un file da un indirizzo URL",
-       "right-purge": "Pulisce la cache del sito senza conferma",
+       "right-purge": "Pulisce la cache del sito per una pagina",
        "right-autoconfirmed": "Non soggetto al limite di azioni per IP",
        "right-bot": "Da trattare come processo automatico",
        "right-nominornewtalk": "Fa sì che le modifiche minori alle pagine di discussione non facciano comparire l'avviso di nuovo messaggio",
        "right-editusercss": "Modifica i file CSS di altri utenti",
        "right-edituserjson": "Modifica i file JSON di altri utenti",
        "right-edituserjs": "Modifica i file JS di altri utenti",
+       "right-editsitecss": "Modifica CSS del sito",
+       "right-editsitejson": "Modifica JSON del sito",
+       "right-editsitejs": "Modifica JavaScript del sito",
        "right-editmyusercss": "Modifica il file CSS del proprio utente",
        "right-editmyuserjson": "Modifica il file JSON del proprio utente",
        "right-editmyuserjs": "Modifica il file JavaScript del proprio utente",
        "rcfilters-activefilters-hide": "Nascondi",
        "rcfilters-activefilters-show": "Mostra",
        "rcfilters-activefilters-hide-tooltip": "Nascondi area dei filtri attivi",
+       "rcfilters-activefilters-show-tooltip": "Mostra area dei filtri attivi",
        "rcfilters-advancedfilters": "Filtri avanzati",
        "rcfilters-limit-title": "Risultati da mostrare",
        "rcfilters-limit-and-date-label": "$1 {{PLURAL:$1|modifica|modifiche}}, $2",
        "rcfilters-savedqueries-already-saved": "Questi filtri sono già salvati. Modifica le impostazioni per creare un nuovo filtro salvato.",
        "rcfilters-restore-default-filters": "Ripristina i filtri predefiniti",
        "rcfilters-clear-all-filters": "Pulisci tutti i filtri",
-       "rcfilters-show-new-changes": "Visualizza le modifiche più recenti",
+       "rcfilters-show-new-changes": "Visualizza le modifiche dal $1",
        "rcfilters-search-placeholder": "Filtra le modifiche (usa il menu o cerca il nome del filtro)",
        "rcfilters-invalid-filter": "Filtro non valido",
        "rcfilters-empty-filter": "Nessun filtro attivo. Sono mostrati tutti i contributi.",
        "rcfilters-filter-editsbyself-description": "I tuoi contributi.",
        "rcfilters-filter-editsbyother-label": "Modifiche di altri",
        "rcfilters-filter-editsbyother-description": "Tutte le modifiche eccetto le tue.",
-       "rcfilters-filtergroup-userExpLevel": "Registrazione utente ed esperienza",
+       "rcfilters-filtergroup-user-experience-level": "Registrazione utente ed esperienza",
        "rcfilters-filter-user-experience-level-registered-label": "Registrato",
        "rcfilters-filter-user-experience-level-registered-description": "Contributori che hanno effettuato l'accesso.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Non registrato",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Il filtro \"Modifiche minori\" è in confitto con uno o più dei filtri \"Tipo di modifica\", perché certe modifiche non possono essere indicate come \"minori\". I filtri in conflitto sono indicati nell'area \"Filtri attivi\" qui sopra.",
        "rcfilters-hideminor-conflicts-typeofchange": "Alcuni tipi di modifiche non possono essere indicate come \"minori\", quindi questo filtro è in conflitto con i seguenti filtri \"Tipo di modifica\": $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Questo filtro \"Tipo di modifica\" è in conflitto con il filtro \"Modifiche minori\". Alcuni tipi di modifiche non possono essere indicati come \"minori\".",
-       "rcfilters-filtergroup-lastRevision": "Ultime versioni",
+       "rcfilters-filtergroup-lastrevision": "Ultime versioni",
        "rcfilters-filter-lastrevision-label": "Versione attuale",
        "rcfilters-filter-lastrevision-description": "Solo l'ultima modifica ad una pagina.",
        "rcfilters-filter-previousrevision-label": "Non l'ultima versione",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[osservata da {{PLURAL:$1|un utente|$1 utenti}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte}} dopo la modifica",
        "newsectionsummary": "/* $1 */ nuova sezione",
        "rc-enhanced-expand": "Mostra dettagli",
        "img-auth-nopathinfo": "Informazioni mancanti sul percorso.\nIl server deve essere è impostato per passare le variabili REQUEST_URI e/o PATH_INFO.\nSe è così, abilita $wgUsePathInfo.\nVedi https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization",
        "img-auth-notindir": "Il percorso richiesto non si trova nella directory di upload configurata.",
        "img-auth-badtitle": "Impossibile costruire un titolo valido da \"$1\".",
-       "img-auth-nologinnWL": "Non si è effettuato l'accesso e \"$1\" non è nella whitelist.",
        "img-auth-nofile": "File \"$1\" non esiste.",
        "img-auth-isdir": "Si sta tentando di accedere a una directory \"$1\".\nSolo l'accesso ai file è consentito.",
        "img-auth-streaming": "\"$1\" in streaming.",
        "delete-confirm": "Cancella \"$1\"",
        "delete-legend": "Cancella",
        "historywarning": "'''Attenzione:''' La pagina che stai per cancellare ha una cronologia con $1 {{PLURAL:$1|versione|versioni}}:",
-       "historyaction-submit": "Mostra",
+       "historyaction-submit": "Mostra versioni",
        "confirmdeletetext": "Stai per cancellare una pagina con tutta la sua cronologia. Per cortesia, conferma che è tua intenzione procedere a tale cancellazione, che hai piena consapevolezza delle conseguenze della tua azione e che essa è conforme alle linee guida stabilite in [[{{MediaWiki:Policy-url}}]].",
        "actioncomplete": "Azione completata",
        "actionfailed": "Azione fallita",
        "deleting-backlinks-warning": "<strong>Attenzione:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|altre pagine]] contengono collegamenti o inclusioni alla pagina che stai per cancellare.",
        "deleting-subpages-warning": "<strong>Attenzione:</strong> la pagina che stai per cancellare ha [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|una sotto-pagina|$1 sotto-pagine|51=più di 50 sotto-pagine}}]].",
        "rollback": "Annulla le modifiche",
+       "rollback-confirmation-confirm": "Per favore conferma:",
+       "rollback-confirmation-yes": "Rollback",
+       "rollback-confirmation-no": "Annulla",
        "rollbacklink": "rollback",
        "rollbacklinkcount": "rollback di {{PLURAL:$1|una modifica|$1 modifiche}}",
        "rollbacklinkcount-morethan": "rollback di più di {{PLURAL:$1|una modifica|$1 modifiche}}",
        "revertpage": "Annullate le modifiche di [[Special:Contributions/$2|$2]] ([[User talk:$2|discussione]]), riportata alla versione precedente di [[User:$1|$1]]",
        "revertpage-nouser": "Annullate le modifiche di un utente nascosto, riportata alla versione precedente di {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Annullate le modifiche di {{GENDER:$3|$1}}; pagina riportata all'ultima versione di {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Annullate le modifiche di $1;\npagina riportata all'ultima revisione di $2. [$3 Mostra le modifiche]",
        "sessionfailure-title": "Sessione fallita",
        "sessionfailure": "Si è verificato un problema nella sessione che identifica l'accesso; il sistema non ha eseguito il comando impartito per precauzione. Invia nuovamente il modulo.",
        "changecontentmodel": "Modifica il modello di contenuto di una pagina",
        "mycontris": "contributi",
        "anoncontribs": "contributi",
        "contribsub2": "Per {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "Per {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "L'utenza \"$1\" non è registrata.",
        "negative-namespace-not-supported": "I namespace con valori negativi non sono supportati.",
        "nocontribs": "Non sono state trovate modifiche che soddisfino i criteri di ricerca.",
        "ipb-confirm": "Conferma il blocco",
        "ipb-sitewide": "Completo",
        "ipb-partial": "Parziale",
+       "ipb-sitewide-help": "Ogni pagina sul wiki e tutte le altre azioni di contribuzione.",
+       "ipb-partial-help": "Specifiche pagine o namespace.",
        "ipb-pages-label": "Pagine",
        "ipb-namespaces-label": "Namespace",
        "badipaddress": "Indirizzo IP non valido.",
        "blocklist-userblocks": "Nascondi i blocchi degli utenti registrati",
        "blocklist-tempblocks": "Nascondi i blocchi temporanei",
        "blocklist-addressblocks": "Nascondi i blocchi di un solo IP",
+       "blocklist-type": "Tipo:",
+       "blocklist-type-opt-all": "Tutto",
+       "blocklist-type-opt-partial": "Parziale",
        "blocklist-rangeblocks": "Nascondi i blocchi di range",
        "blocklist-timestamp": "Data e ora",
        "blocklist-target": "Destinazione",
        "blocklist-editing-page": "pagine",
        "blocklist-editing-ns": "namespace",
        "ipblocklist-empty": "L'elenco dei blocchi è vuoto.",
-       "ipblocklist-no-results": "L'indirizzo IP o il nome utente richiesto non è bloccato.",
+       "ipblocklist-no-results": "Nessun blocco trovato che corrisponde all'indirizzo IP o nome utente richiesto.",
        "blocklink": "blocca",
        "unblocklink": "sblocca",
        "change-blocklink": "cambia blocco",
+       "empty-username": "(nessun nome utente disponibile)",
        "contribslink": "contributi",
        "emaillink": "invia email",
        "autoblocker": "Bloccato automaticamente perché l'indirizzo IP è condiviso con l'utente \"[[User:$1|$1]]\".\nIl blocco dell'utente $1 è stato imposto per il seguente motivo: \"$2\".",
        "blocklog-showlog": "Questo utente è stato bloccato in precedenza. Il registro dei blocchi è riportato di seguito per informazione:",
        "blocklog-showsuppresslog": "Questo utente è stato bloccato e nascosto in precedenza. Il registro delle rimozioni è riportato di seguito per informazione:",
        "blocklogentry": "ha bloccato [[$1]] per un periodo di $2 $3",
-       "reblock-logentry": "ha cambiato le impostazioni del blocco per [[$1]] con una scadenza di $2 $3",
+       "reblock-logentry": "ha modificato le impostazioni del blocco per [[$1]] con una scadenza di $2 $3",
        "blocklogtext": "Di seguito sono elencate le azioni di blocco e sblocco utenti.\nGli indirizzi IP bloccati automaticamente non sono elencati.\nConsultare l'[[Special:BlockList|elenco dei blocchi]] per l'elenco dei bandi o blocchi attualmente operativi.",
        "unblocklogentry": "ha sbloccato $1",
        "block-log-flags-anononly": "solo utenti anonimi",
        "allmessagesdefault": "Testo predefinito",
        "allmessagescurrent": "Testo attuale",
        "allmessagestext": "Questa è la lista di tutti i messaggi di sistema disponibili nel namespace MediaWiki.\nVisita [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] e [https://translatewiki.net translatewiki.net] se vuoi contribuire alla localizzazione generica di MediaWiki.",
-       "allmessagesnotsupportedDB": "Non è possibile utilizzare questa pagina perché il flag '''$wgUseDatabaseMessages''' non è attivo.",
+       "allmessages-not-supported-database": "Non è possibile utilizzare questa pagina perché il flag '''$wgUseDatabaseMessages''' non è attivo.",
        "allmessages-filter-legend": "Filtro",
        "allmessages-filter": "Filtra per stato di modifica:",
        "allmessages-filter-unmodified": "Non modificati",
        "confirm-unwatch-button": "OK",
        "confirm-unwatch-top": "Rimuovere questa pagina dalla tua lista degli osservati speciali?",
        "confirm-rollback-button": "OK",
-       "confirm-rollback-top": "Ripristinare le modifiche di questa pagina?",
+       "confirm-rollback-top": "Annullare le modifiche a questa pagina?",
+       "confirm-rollback-bottom": "Questa azione annullerà istantaneamente le modifiche selezionate a questa pagina.",
        "confirm-mcrrestore-title": "Ripristina una versione",
        "confirm-mcrundo-title": "Annulla una modifica",
        "mcrundofailed": "Annullamento fallito",
        "logentry-partialblock-block-page": "{{PLURAL:$1|della pagina|delle pagine}} $2",
        "logentry-partialblock-block-ns": "{{PLURAL:$1|del|dei}} namespace $2",
        "logentry-partialblock-block": "$1 {{GENDER:$2|ha bloccato}} {{GENDER:$4|$3}} alla modifica $7 con una scadenza di $5 $6",
-       "logentry-partialblock-reblock": "$1 {{GENDER:$2|ha modificato}} le impostazioni del blocco per {{GENDER:$4|$3}} bloccando la modifica $7 con una scadenza di $5 $6",
+       "logentry-partialblock-reblock": "$1 {{GENDER:$2|ha modificato}} le impostazioni del blocco per {{GENDER:$4|$3}} precludendo{{GENDER:$4|gli|le|gli}} la modifica $7 con una scadenza di $5 $6",
        "logentry-non-editing-block-block": "$1 {{GENDER:$2|ha bloccato}} {{GENDER:$4|$3}} in specifiche azioni non di modifica con una scadenza di $5 $6",
+       "logentry-non-editing-block-reblock": "$1 {{GENDER:$2|ha modificato}} le impostazioni del blocco per {{GENDER:$4|$3}} precludendo{{GENDER:$4|gli|le|gli}} specifiche azioni non di modifica con una scadenza di $5 $6",
        "logentry-suppress-block": "$1 {{GENDER:$2|ha bloccato}} {{GENDER:$4|$3}} con una scadenza di $5 $6",
        "logentry-suppress-reblock": "$1 {{GENDER:$2|ha modificato}} le impostazioni del blocco per {{GENDER:$4|$3}} con una scadenza di $5 $6",
        "logentry-import-upload": "$1 {{GENDER:$2|ha importato}} $3 tramite caricamento",
        "passwordpolicies-policy-passwordcannotbepopular": "La password non può essere {{PLURAL:$1|la password più popolare|nell'elenco delle $1 password più popolari}}",
        "passwordpolicies-policy-passwordnotinlargeblacklist": "La password non può essere nell'elenco delle 100 000 password utilizzate più comunemente.",
        "easydeflate-invaliddeflate": "Il contenuto fornito non è compresso correttamente",
-       "unprotected-js": "Per motivi di sicurezza, non è possibile caricare JavaScript da pagine non protette. Crea javascript solo nel namespace MediaWiki o come sottopagina Utente"
+       "unprotected-js": "Per motivi di sicurezza, non è possibile caricare JavaScript da pagine non protette. Crea javascript solo nel namespace MediaWiki o come sottopagina Utente",
+       "userlogout-continue": "Se vuoi uscire [$1 vai alla pagina di logout].",
+       "userlogout-sessionerror": "Logout non riuscito per un errore nella sessione. [$1 Riprova]."
 }
index aa0949c..65ff3d0 100644 (file)
        "tog-norollbackdiff": "巻き戻し後の差分を表示しない",
        "tog-useeditwarning": "変更を保存せずに編集画面から離れようとしたら警告",
        "tog-prefershttps": "ログインする際、常に安全な接続を使用する",
+       "tog-showrollbackconfirmation": "巻き戻しリンクをクリックした際に確認画面を表示する",
        "underline-always": "常に付ける",
        "underline-never": "常に付けない",
        "underline-default": "外装またはブラウザーの既定値を使用",
        "badretype": "入力したパスワードが一致しません。",
        "usernameinprogress": "この利用者名のためのアカウント作成は、すでに進行中です。お待ちください。",
        "userexists": "入力した利用者名は既に使用されています。\n別の利用者名を指定してください。",
+       "createacct-normalization": "技術的制限により指定された利用者名は「$2」として登録されます。",
        "loginerror": "ログインのエラー",
        "createacct-error": "アカウント作成エラー",
        "createaccounterror": "アカウントを作成できませんでした: $1",
        "botpasswords-existing": "既存のボット用パスワード",
        "botpasswords-createnew": "ボット用パスワードの新規作成",
        "botpasswords-editexisting": "既存のボットのパスワードを編集",
-       "botpasswords-label-needsreset": "(パスワードをリセットする必要があります)",
+       "botpasswords-label-needsreset": "(パスワードのリセットが必要です)",
        "botpasswords-label-appid": "ボット名:",
        "botpasswords-label-create": "作成",
        "botpasswords-label-update": "更新",
        "botpasswords-invalid-name": "指定された利用者名には、ボット用パスワードの区切りである「$1」 が含まれていません。",
        "botpasswords-not-exist": "利用者「$1」はボット「$2」のパスワードを所持していません。",
        "botpasswords-needs-reset": "{{GENDER:$1|利用者}}「$1」のボット名「$2」のためのパスワードはリセットする必要があります。",
-       "botpasswords-locked": "アカウントがロックされているため、bot用パスワードではログインできません。",
+       "botpasswords-locked": "アカウントがロックされているため、ボット用パスワードでログインできません。",
        "resetpass_forbidden": "パスワードは変更できません",
        "resetpass_forbidden-reason": "パスワードは変更できません: $1",
        "resetpass-no-info": "このページに直接アクセスするためにはログインしている必要があります。",
        "page_first": "先頭",
        "page_last": "末尾",
        "histlegend": "差分の選択: 比較したい版のラジオボタンを選択し、Enterキーを押すか、下部のボタンを押します。<br />\n凡例: <strong>({{int:cur}})</strong>=最新版との比較、<strong>({{int:last}})</strong>=直前の版との比較、<strong>{{int:minoreditletter}}</strong>=細部の編集",
-       "history-fieldset-title": "版の検索",
+       "history-fieldset-title": "版の絞り込み",
        "history-show-deleted": "削除版のみ",
        "histfirst": "最古",
        "histlast": "最新",
        "historysize": "({{PLURAL:$1|$1バイト}})",
-       "historyempty": "(空)",
+       "historyempty": "",
        "history-feed-title": "版の履歴",
        "history-feed-description": "このウィキのこのページに関する変更履歴",
        "history-feed-item-nocomment": "$2に$1による",
        "right-reupload-own": "自身がアップロードした既存のファイルに上書き",
        "right-reupload-shared": "共有メディアリポジトリ上のファイルにローカルで上書き",
        "right-upload_by_url": "URL からファイルをアップロード",
-       "right-purge": "確認なしでサイト上のページ・キャッシュを破棄",
+       "right-purge": "サイト上のページ キャッシュを破棄",
        "right-autoconfirmed": "IPベースの速度制限を受けない",
        "right-bot": "自動処理と認識させる",
        "right-nominornewtalk": "議論ページの細部の編集をした際に、新着メッセージとして通知しない",
        "action-changetags": "個々の版および記録項目への任意のタグの追加と除去",
        "action-deletechangetags": "データベースからタグの削除",
        "action-purge": "このページのキャッシュ破棄",
+       "action-apihighlimits": "API要求でのより高い制限値の使用",
+       "action-bigdelete": "大きな履歴があるページの削除",
+       "action-blockemail": "利用者のメール送信のブロック",
+       "action-editprotected": "「{{int:protect-level-sysop}}」の保護を設定されたページの編集",
+       "action-editsemiprotected": "「{{int:protect-level-autoconfirmed}}」の保護を設定されたページの編集",
+       "action-editinterface": "ユーザーインターフェースの編集",
+       "action-editusercss": "他の利用者のCSSファイルの編集",
+       "action-edituserjson": "他の利用者のJSONファイルの編集",
+       "action-edituserjs": "他の利用者のJavaScriptファイルの編集",
+       "action-editsitecss": "サイト全体のCSSの編集",
+       "action-editsitejson": "サイト全体のJSONの編集",
+       "action-editsitejs": "サイト全体のJavaScriptの編集",
+       "action-editmyusercss": "自分のCSSファイルの編集",
+       "action-editmyuserjson": "自分のJSONファイルの編集",
+       "action-editmyuserjs": "自分のJavaScriptファイルの編集",
+       "action-viewsuppressed": "すべての利用者から隠された版の閲覧",
+       "action-ipblock-exempt": "IPブロック、自動ブロック、広域ブロックの回避",
+       "action-unblockself": "自分に対するブロックの解除",
+       "action-reupload-own": "自分がアップロードした既存のファイルへの上書き",
+       "action-patrolmarks": "最近の更新での巡回済み印の閲覧",
+       "action-override-export-depth": "リンク先ページの5階層まで含めた書き出し",
+       "action-suppressredirect": "転送ページの作成を伴わないページの移動",
        "nchanges": "$1 {{PLURAL:$1|回の変更}}",
        "ntimes": "$1×",
        "enhancedrc-since-last-visit": "最終閲覧以降 $1 {{PLURAL:$1|件}}",
        "rcfilters-savedqueries-already-saved": "これらのフィルタは既に保存されています。設定を変更して、新しい保存フィルタを作成します。",
        "rcfilters-restore-default-filters": "標準設定の絞り込み条件を適用",
        "rcfilters-clear-all-filters": "すべてのフィルターをクリア",
-       "rcfilters-show-new-changes": "最新の変更を表示",
+       "rcfilters-show-new-changes": "$1 から最新の変更を表示",
        "rcfilters-search-placeholder": "絞り込みを行う(メニューから選択、またはフィルター名で検索)",
        "rcfilters-invalid-filter": "無効なフィルター",
        "rcfilters-empty-filter": "絞り込みは行われていません。全ての項目が表示されます。",
        "rcfilters-filter-editsbyself-description": "自分の投稿記録を絞り込む",
        "rcfilters-filter-editsbyother-label": "自分以外の編集",
        "rcfilters-filter-editsbyother-description": "自分以外の利用者による編集",
-       "rcfilters-filtergroup-userExpLevel": "利用者登録及び経験",
+       "rcfilters-filtergroup-user-experience-level": "利用者登録及び経験",
        "rcfilters-filter-user-experience-level-registered-label": "登録済み",
        "rcfilters-filter-user-experience-level-registered-description": "ログイン済みの編集者",
        "rcfilters-filter-user-experience-level-unregistered-label": "未登録",
        "rcfilters-hideminor-conflicts-typeofchange-global": "「細部の編集」として絞り込めない項目を「細部の編集」として絞り込もうとしています。競合している項目は項目選択欄で強調表示されています。",
        "rcfilters-hideminor-conflicts-typeofchange": "細部の編集として絞り込めない以下の項目を絞り込もうとしています: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "「細部の編集」の絞り込みと競合しています。この項目を「細部の編集」として絞り込むことはできません。",
-       "rcfilters-filtergroup-lastRevision": "最新版",
+       "rcfilters-filtergroup-lastrevision": "最新版",
        "rcfilters-filter-lastrevision-label": "最新版",
        "rcfilters-filter-lastrevision-description": "ページの最新の変更のみ",
        "rcfilters-filter-previousrevision-label": "最新版より古い版",
        "rcfilters-view-tags-help-icon-tooltip": "タグ付けされた編集とは",
        "rcfilters-liveupdates-button": "自動読み込み",
        "rcfilters-liveupdates-button-title-on": "自動読み込みを停止",
-       "rcfilters-liveupdates-button-title-off": "æ\96°ã\81\97ã\81\84ç·¨é\9b\86ã\82\92å\8d³åº§ã\81«èª­ã\81¿è¡¨ç¤ºã\81\99ã\82\8b",
+       "rcfilters-liveupdates-button-title-off": "新しい編集を即座に表示する",
        "rcfilters-watchlist-markseen-button": "すべての変更を訪問済みにする",
        "rcfilters-watchlist-edit-watchlist-button": "ウォッチリストを編集",
        "rcfilters-watchlist-showupdated": "最終訪問以降に変更されたページは、塗りつぶされた丸印と一緒に、<strong>太字</strong>で表示されます。",
        "newpageletter": "新",
        "boteditletter": "ボ",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[{{PLURAL:$1|$1 人の利用者}}がウォッチしています]",
        "rc-change-size": "$1",
        "rc-change-size-new": "変更後は $1 {{PLURAL:$1|バイト}}",
        "newsectionsummary": "/* $1 */ 新しい節",
        "uploadstash-file-not-found-missing-content-type": "コンテンツタイプヘッダーがありません。",
        "uploadstash-file-not-found-not-exists": "パスが見つからないか、またはプレーンファイルではありません。",
        "uploadstash-file-too-large": "$1バイトを超えるファイルは提供できません。",
-       "uploadstash-not-logged-in": "ユーザーはログインしていません。ファイルはユーザーに属している必要があります。",
-       "uploadstash-wrong-owner": "このファイル($1)は現在のユーザーに属していません。",
+       "uploadstash-not-logged-in": "利用者はログインしていません。ファイルは利用者に属している必要があります。",
+       "uploadstash-wrong-owner": "このファイル ($1) は現在の利用者に属していません。",
        "uploadstash-no-such-key": "そのような鍵($1)は削除できません。",
        "uploadstash-no-extension": "拡張機能がnullです。",
        "uploadstash-zero-length": "ファイルのサイズがゼロです。",
        "img-auth-nopathinfo": "URL のパス情報が見つかりません。\nサーバーは、変数 REQUEST_URI または PATH_INFO の一方または両方でパス情報を渡すように構成する必要があります。\nすでに設定済みの場合は、$wgUsePathInfo を有効にすることをお試しください。\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization をご覧ください。",
        "img-auth-notindir": "要求されたパスは、設定済みのアップロード先ディレクトリ内にありません。",
        "img-auth-badtitle": "「$1」からは有効なページ名を構築できません。",
-       "img-auth-nologinnWL": "ログインしておらず、さらに「$1」はホワイトリストに入っていません。",
        "img-auth-nofile": "ファイル「$1」は存在しません。",
        "img-auth-isdir": "ディレクトリ「$1」にアクセスしようとしています。\nファイルへのアクセスのみが許可されています。",
        "img-auth-streaming": "「$1」を転送中。",
        "delete-confirm": "「$1」の削除",
        "delete-legend": "削除",
        "historywarning": "<strong>警告:</strong> 削除しようとしているページには、$1版の履歴があります:",
-       "historyaction-submit": "表示",
+       "historyaction-submit": "更新を表示",
        "confirmdeletetext": "ページをすべての履歴とともに削除しようとしています。\n本当にこの操作を行いたいか、操作の結果を理解しているか、およびこの操作が[[{{MediaWiki:Policy-url}}|方針]]に従っているかどうか、確認してください。",
        "actioncomplete": "操作を完了しました",
        "actionfailed": "操作に失敗しました",
        "delete-warning-toobig": "このページには、 $1版を超える編集履歴があります。\n削除すると、{{SITENAME}}のデータベース処理に大きな負荷がかかります。\n十分に注意してください。",
        "deleteprotected": "このページは保護されているため削除できません。",
        "deleting-backlinks-warning": "<strong>警告:</strong> 削除しようとしているページは、[[Special:WhatLinksHere/{{FULLPAGENAME}}|他のページ]]からリンクまたは参照読み込みされています。",
-       "deleting-subpages-warning": "<strong>警告:</strong>削除しようとしているページは、[[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|サブページ|$1 個のサブページ|51=50 個以上のサブページ}}]]があります。",
+       "deleting-subpages-warning": "<strong>警告:</strong> 削除しようとしているページには、[[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|下位ページ|$1 件の下位ページ|51=50 件以上の下位ページ}}]]があります。",
        "rollback": "編集を巻き戻し",
+       "rollback-confirmation-yes": "巻き戻し",
+       "rollback-confirmation-no": "キャンセル",
        "rollbacklink": "巻き戻し",
        "rollbacklinkcount": "$1{{PLURAL:$1|編集}}を巻き戻し",
        "rollbacklinkcount-morethan": "$1{{PLURAL:$1|編集}}以上を巻き戻し",
        "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-notify": "$1による編集を差し戻しました。\n$2による直前の版へ変更されました。[$3 変更を表示]",
        "sessionfailure-title": "セッションの失敗",
        "sessionfailure": "ログインのセッションに問題が発生しました。\nセッション乗っ取りを防ぐため、操作を取り消しました。\nフォームを再送信してください。",
        "changecontentmodel": "ページのコンテンツ・モデルの変更",
        "mycontris": "投稿記録",
        "anoncontribs": "投稿記録",
        "contribsub2": "利用者: {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "{{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "利用者アカウント「$1」は登録されていません。",
        "negative-namespace-not-supported": "負の値で指定される名前空間はサポートされていません。",
        "nocontribs": "これらの条件に一致する変更は見つかりませんでした。",
        "ipb-confirm": "ブロックの確認",
        "ipb-sitewide": "サイト全体",
        "ipb-partial": "部分的",
+       "ipb-sitewide-help": "ウィキにおける各ページとその他の投稿操作。",
        "ipb-partial-help": "特定のページまたは名前空間。",
        "ipb-pages-label": "ページ",
        "ipb-namespaces-label": "名前空間",
        "blocklist-userblocks": "アカウントのブロックを非表示",
        "blocklist-tempblocks": "期限付きブロックを非表示",
        "blocklist-addressblocks": "単一 IP のブロックを非表示",
+       "blocklist-type": "種類:",
+       "blocklist-type-opt-all": "すべて",
+       "blocklist-type-opt-sitewide": "サイト全体",
+       "blocklist-type-opt-partial": "部分的",
        "blocklist-rangeblocks": "範囲ブロックを非表示",
        "blocklist-timestamp": "日時",
        "blocklist-target": "対象",
        "blocklist-editing-page": "ページ",
        "blocklist-editing-ns": "名前空間",
        "ipblocklist-empty": "ブロック一覧は空です。",
-       "ipblocklist-no-results": "æ\8c\87å®\9aã\81\95ã\82\8cã\81\9fIPã\82¢ã\83\89ã\83¬ã\82¹ã\81¾ã\81\9fã\81¯å\88©ç\94¨è\80\85å\90\8dã\81¯ã\83\96ã\83­ã\83\83ã\82¯ã\81\95ã\82\8cã\81¦ã\81\84ã\81¾ã\81\9bã\82\93。",
+       "ipblocklist-no-results": "æ\8c\87å®\9aã\81\95ã\82\8cã\81\9fIPã\82¢ã\83\89ã\83¬ã\82¹ã\81¾ã\81\9fã\81¯å\88©ç\94¨è\80\85å\90\8dã\81«ä¸\80è\87´ã\81\99ã\82\8bã\83\96ã\83­ã\83\83ã\82¯ã\81¯è¦\8bã\81¤ã\81\8bã\82\8aã\81¾ã\81\9bã\82\93ã\81§ã\81\97ã\81\9f。",
        "blocklink": "ブロック",
        "unblocklink": "ブロック解除",
        "change-blocklink": "設定を変更",
        "cant-move-category-page": "カテゴリのページを移動させる権限がありません。",
        "cant-move-to-category-page": "ページをカテゴリのページに移動させる権限がありません。",
        "cant-move-subpages": "下位のページを移動する権限がありません。",
-       "namespace-nosubpages": "名前空間「$1」はサブページが許可されていません。",
+       "namespace-nosubpages": "名前空間「$1」は下位ページが許可されていません。",
        "newtitle": "新しいページ名:",
        "move-watch": "移動元と移動先ページをウォッチ",
        "movepagebtn": "ページを移動",
        "allmessagesdefault": "既定のメッセージ文",
        "allmessagescurrent": "現在のメッセージ文",
        "allmessagestext": "これは MediaWiki 名前空間で利用できるシステム メッセージの一覧です。\nMediaWiki 全般のローカライズ (地域化) に貢献したい場合は、[https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki のローカライズ]や [https://translatewiki.net?setlang=ja translatewiki.net] をご覧ください。",
-       "allmessagesnotsupportedDB": "<strong>$wgUseDatabaseMessages</strong>が無効のため、このページを使用できません。",
+       "allmessages-not-supported-database": "<strong>$wgUseDatabaseMessages</strong>が無効のため、このページを使用できません。",
        "allmessages-filter-legend": "絞り込み",
        "allmessages-filter": "変更状態により絞り込む:",
        "allmessages-filter-unmodified": "変更なし",
        "import-mapping-subpage": "次のページの下位ページとしてインポート:",
        "import-upload-filename": "ファイル名:",
        "import-upload-username-prefix": "インターウィキ接頭辞:",
-       "import-assign-known-users": "指定されたユーザーがこのウィキに存在する場合そのユーザーに編集を割り当てる",
+       "import-assign-known-users": "指定された利用者がこのウィキに存在する場合その利用者に編集を割り当てる",
        "import-comment": "コメント:",
        "importtext": "元のウィキで[[Special:Export|書き出し機能]]を使用してファイルに書き出してください。\nそれをコンピューターに保存した後、こちらへアップロードしてください。",
        "importstart": "ページを取り込み中...",
        "confirm-unwatch-top": "このページをウォッチリストから除去しますか?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "このページの編集を差し戻しますか?",
+       "confirm-rollback-bottom": "この操作はこのページに対する指定した変更即座に巻き戻します。",
        "confirm-mcrrestore-title": "版を復帰",
        "confirm-mcrundo-title": "直前の変更を取り消す",
        "mcrundofailed": "取り消しに失敗しました",
        "logentry-block-block": "$1 が {{GENDER:$4|$3}} を$5{{GENDER:$2|ブロックしました}} $6",
        "logentry-block-unblock": "$1 が {{GENDER:$4|$3}} の{{GENDER:$2|ブロックを解除しました}}",
        "logentry-block-reblock": "$1 が {{GENDER:$4|$3}} のブロックの期限を$5に{{GENDER:$2|変更しました}} $6",
+       "logentry-partialblock-block-page": "{{PLURAL:$1|ページ}} $2",
+       "logentry-partialblock-block-ns": "{{PLURAL:$1|名前空間}} $2",
+       "logentry-partialblock-block": "$1 が {{GENDER:$4|$3}} に対して $7 からの編集を $5 {{GENDER:$2||ブロックしました}} $6",
+       "logentry-partialblock-reblock": "$1 が {{GENDER:$4|$3}} に対する $7 のブロックの期限を $5 に{{GENDER:$2|変更しました}} $6",
        "logentry-suppress-block": "$1 が {{GENDER:$4|$3}} を$5で{{GENDER:$2|ブロックしました}} $6",
        "logentry-suppress-reblock": "$1 が {{GENDER:$4|$3}} のブロックの期限を$5に{{GENDER:$2|変更しました}} $6",
        "logentry-import-upload": "$1 がファイルをアップロードして $3 を{{GENDER:$2|インポートしました}}",
        "logentry-rights-autopromote": "$1 が $4 から $5 に自動的に{{GENDER:$2|昇格しました}}",
        "logentry-upload-upload": "$1 が $3 を {{GENDER:$2|アップロードしました}}",
        "logentry-upload-overwrite": "$1 が $3 の新しいバージョンを {{GENDER:$2|アップロードしました}}",
-       "logentry-upload-revert": "$1 が $3 を {{GENDER:$2|アップロードしました}}",
+       "logentry-upload-revert": "$1 が $3 を元の版に {{GENDER:$2|巻き戻しました}}",
        "log-name-managetags": "タグ管理記録",
        "log-description-managetags": "このページは[[Special:Tags|タグ]]に関係する管理タスクをリストアップしています。ログには管理者によって手動で実行された操作の記録しか記載されていません。ウィキ・ソフトウェアによって、ログを残さずにタグが作成・削除されている場合があります。",
        "logentry-managetags-create": "$1 がタグ「$4」を{{GENDER:$2|作成しました}}",
        "log-action-filter-suppress-reblock": "再ブロックによる利用者の秘匿",
        "log-action-filter-upload-upload": "新規アップロード",
        "log-action-filter-upload-overwrite": "再アップロード",
+       "log-action-filter-upload-revert": "差し戻し",
        "authmanager-authn-not-in-progress": "認証が行われていない、またはセッションデータが失われました。最初からやり直してください。",
        "authmanager-authn-no-primary": "指定された証明情報を認証できませんでした。",
        "authmanager-authn-no-local-user": "指定された証明情報は、このウィキのどの利用者にも関連付けられていません。",
        "unlinkaccounts": "アカウントの関連付け解除",
        "unlinkaccounts-success": "アカウントの関連付けが解除されました。",
        "authenticationdatachange-ignored": "認証データの変更は処理されませんでした。プロバイダーが設定されていない可能性があります。",
-       "userjsispublic": "注意: JavaScript のサブページは第三者が閲覧可能なため、機微な情報を含めないでください。",
-       "userjsonispublic": "注意: JSON のサブページは第三者が閲覧可能なため、機微な情報を含めないでください。",
-       "usercssispublic": "注意: CSS のサブページは第三者が閲覧可能なため、機微な情報を含めないでください。",
+       "userjsispublic": "注意: JavaScript の下位ページは第三者が閲覧可能なため、機微な情報を含めないでください。",
+       "userjsonispublic": "注意: JSON の下位ページは第三者が閲覧可能なため、機微な情報を含めないでください。",
+       "usercssispublic": "注意: CSS の下位ページは第三者が閲覧可能なため、機微な情報を含めないでください。",
        "restrictionsfield-badip": "無効な IP アドレス、またはその範囲: $1",
        "restrictionsfield-label": "許可する IP の範囲:",
        "restrictionsfield-help": "一行につき、単一の IP アドレス、もしくは CIDR による範囲。全帯域からの接続を許可する場合: <pre>0.0.0.0/0\n::/0</pre>",
        "undelete-cantedit": "このページを編集する許可がないため復元できません。",
        "undelete-cantcreate": "同名のページが存在せず、このページを作成する許可がないため復元できません。",
        "pagedata-title": "ページ・データ",
-       "pagedata-text": "このページは、ページへのデータインターフェースを提供します。サブページの構文を使用して、URLにページタイトルを入力してください。\n* コンテンツのネゴシエーションは、クライアントのAcceptヘッダーに基づいて適用されます。つまり、ページデータはクライアントが優先する形式で提供されます。",
+       "pagedata-text": "このページは、ページへのデータインターフェースを提供します。下位ページの構文を使用して、URLにページ名を入力してください。\n* コンテンツのネゴシエーションは、クライアントのAcceptヘッダーに基づいて適用されます。つまり、ページデータはクライアントが優先する形式で提供されます。",
        "pagedata-not-acceptable": "該当する形式が見つかりません。対応している MIME タイプ: $1",
        "pagedata-bad-title": "「$1」は無効なページ名です。",
-       "unregistered-user-config": "セキュリティ上の理由から、JavaScript、CSSおよびJSONの利用者サブページは、登録されていない利用者に対しては読み込みできません。",
+       "unregistered-user-config": "セキュリティ上の理由から、JavaScript、CSSおよびJSONの利用者下位ページは、登録されていない利用者に対しては読み込みできません。",
        "passwordpolicies": "パスワードポリシー",
        "passwordpolicies-summary": "これは、このウィキで定義されている利用者グループの有効なパスワードポリシーの一覧です。",
        "passwordpolicies-group": "グループ",
        "passwordpolicies-policy-passwordcannotmatchblacklist": "パスワードは、特にブラックリストに載っているものと一致するものは設定できません",
        "passwordpolicies-policy-maximalpasswordlength": "パスワードは$1{{PLURAL:$1|文字}}以下でなければなりません",
        "passwordpolicies-policy-passwordcannotbepopular": "パスワードは{{PLURAL:$1|一般的なものにすることはできません|一般的な$1個のパスワードのリストと一致するものにすることはできません}}",
+       "passwordpolicies-policy-passwordnotinlargeblacklist": "一般的に使われるパスワード10万項目のリストに含まれるパスワードは使用できません。",
+       "passwordpolicies-policyflag-forcechange": "ログイン時に変更を強制",
+       "passwordpolicies-policyflag-suggestchangeonlogin": "ログイン時に変更を提案",
        "easydeflate-invaliddeflate": "提供されたコンテンツが適切に圧縮されていません",
-       "unprotected-js": "セキュリティ上の理由から、JavaScriptは保護されていないページからロードすることはできません。MediaWiki: 名前空間内、または利用者サブページとしてのみjavascriptを作成してください。"
+       "unprotected-js": "セキュリティ上の理由から、JavaScriptは保護されていないページからは読み込みできません。MediaWiki: 名前空間内、利用者下位ページのいずれかでのみjavascriptを作成してください。",
+       "userlogout-continue": "ログアウトを行いたい場合、[$1 ログアウトページから実施]してください。",
+       "userlogout-sessionerror": "セッションエラーによりログアウトに失敗しました。再度 [$1 試行して]ください。"
 }
index 265bb3d..cb0e674 100644 (file)
        "and": "&#32;lan",
        "faq": "Pitakon Kerep",
        "actions": "Lelabuhan",
-       "namespaces": "Mandala aran",
+       "namespaces": "Mandhala aran",
        "variants": "Varian",
        "navigation-heading": "Menu navigasi",
        "errorpagetitle": "Masalah",
        "returnto": "Bali menyang $1.",
        "tagline": "Saka {{SITENAME}}",
        "help": "Pitulung",
+       "help-mediawiki": "Pitulung bab MediaWiki",
        "search": "Golèk",
        "search-ignored-headings": " #<!-- lirwakaké waé larik iki kaya asliné --> <pre>\n# Sesirah kang bakal dilirwakaké déning golèkan.\n# Owahan tumrap iki bakal katon nalika sesirahé wis diindhèks.\n# Panjenengan bisa meksa ngindhèks ulang kaca kanthi ngayahi besutan kosong.\n# Sintaksisé kaya mangkéné:\n#   * Samubarang saka karakter \"#\" tumeka pungkasané larik iku minangka tanggepan.\n#   * Saben larik kang ora kosong iku sesirah kang kudu dilirwakaké lan samubarangé.\nRujukan\nPranala njaba\nUga delengen\n #</pre> <!-- lirwakaké baé larik iki kaya asliné -->",
        "searchbutton": "Golèk",
        "no-null-revision": "Ora isa nggawe revisi 'null' anyar kanggo kaca \"$1\"",
        "badtitle": "Sesirah ala",
        "badtitletext": "Sesirah kaca kang panjenengan suwun ora trep, kosong, utawa salah nggayut menyang sesirah antarabasa utawa antarawiki.\nTulisané bokmanawa ngemu karakter kang ora kena kaanggo ing sesirah.",
-       "title-invalid-empty": "Sesirah kaca kang panjenengan karsakaké kosong utawa mung ngemu jenengé mandala aran.",
+       "title-invalid-empty": "Sesirah kaca kang kopéngini kosong utawa mung ngemu jenenging mandhala aran.",
        "title-invalid-utf8": "Sesirah kaca kang panjenengan karsakaké ngemu reroncèn UTF-8 kang ora trep.",
        "title-invalid-interwiki": "Sesirah kaca kang panjenengan karsakaké ngemu pranala interwiki kang ora bisa katrapaké ing sesirah.",
        "title-invalid-talk-namespace": "Sesirah kaca kang dikarepaké ngener ing kaca parembugan kang ora ana.",
        "editinginterface": "<strong>Pepéling:</strong> Panjenengan lagi mbesut kaca kang ngemu tulisan kanggo mukantarané piranti alus.\nNgowahi kaca iki bakal mrabawani cakrik mukantarané panganggo liya ing wiki iki.",
        "translateinterface": "Saperlu nambah utawa ngowah pertalan tumrap kabèh wiki, mangga anggoa [https://translatewiki.net/ translatewiki.net] minangka proyèk panglokaling MediaWiki.",
        "cascadeprotected": "Kaca iki wis direksa saka besutan amarga katransklusi ing {{PLURAL:$1|kaca|kaca-kaca}} kang kareksa mawa pilihan \"runut\" murub:\n$2",
-       "namespaceprotected": "Panjenengan ora duwé idin kanggo mbesut kaca ing mandala aran <strong>$1</strong>.",
+       "namespaceprotected": "Kowé ora kawogan mbesut kaca ing mandhala aran <strong>$1</strong>.",
        "customcssprotected": "Panjenengan ora diidinaké mbesut kaca CSS iki amarga isiné setèlan pribadhi panganggo liyané.",
        "customjsprotected": "Panjenengan ora diidinaké mbesut kaca JavaScript iki amarga isiné setèlan pribadhi panganggo liyané.",
        "mycustomcssprotected": "Sampèyan ora duwé idin kanggo ngowah kaca CSS iki.",
        "titleprotected": "Irah-irahan iki direksa ora olèh digawé déning [[User:$1|$1]].\nAlesané yaiku <em>$2</em>.",
        "filereadonlyerror": "Ora bisa ndandani barkas \"$1\" amarga panyimpenan barkas \"$2\" mung bisa diwaca.\n\nPangurus sistem kang ngunci iku njlèntrèhaké: \"$3\".",
        "invalidtitle": "Sesirah ora trep",
-       "invalidtitle-knownnamespace": "Irah-irahan ora sah mawa bilik jeneng \"$2\" lan tèks \"$3\"",
-       "invalidtitle-unknownnamespace": "Judhul ora trep mawa angka $1 lan tèks \"$2\" bilik jeneng kang ora dingertèni",
+       "invalidtitle-knownnamespace": "Sesirah ora trep mawa mandhala aran \"$2\" lan tulisan \"$3\"",
+       "invalidtitle-unknownnamespace": "Sesirah ora trep mawa angka $1 lan tulisan \"$2\" mandhala aran kang ora kaweruhan",
        "exception-nologin": "Durung mlebu log",
        "exception-nologin-text": "Sumangga panjenengan mlebu log supaya bisa ngaksès kaca utawa laku iki.",
        "exception-nologin-text-manual": "Tulung $1 kanggo ngakses kaca utawa kelakon iki.",
        "botpasswords-label-cancel": "Wurung",
        "botpasswords-label-delete": "Busak",
        "botpasswords-label-resetpassword": "Balèni gawé tembung wadi",
+       "botpasswords-bad-appid": "Jeneng bot \"$1\" ora trep.",
+       "botpasswords-insert-failed": "Wurung nambah jeneng bot \"$1\". Apa wis tinambahaké sadurungé?",
        "resetpass_forbidden": "Tembung wadi ora bisa diganti",
        "resetpass-no-info": "Panjenengan kudu mlebu log saperlu langsung ngaksès kaca iki.",
        "resetpass-submit-loggedin": "Ganti tembung wadi",
        "accmailtext": "Tembung sandi sembarang kanggo [[User talk:$1|$1]] wis dikirim menyang $2.\n\nTembung sandi iki bisa diganti ing kaca <em>[[Special:ChangePassword|salin tembung sandi]]</em> sawisé mlebu log.",
        "newarticle": "(Anyar)",
        "newarticletext": "Panjenengan ngetuti pranala kang durung ana.\nKanggo nggawé kaca, gagéa ngetik ing kothak ngisor iki (deleng [$1 kaca pitulung] ngenani katerangané).\nManawa panjenengan tekan kéné awit ora sengaja, kliken tumbul <strong>balik</strong> ana ing pangluruné panjenengan.",
-       "anontalkpagetext": "----\n<em>Iki kaca parembugané panganggo anonim kang durung gawé akun, utawa kang ora nganggo akuné.</em>\nMula, awak dhéwé kudu nganggo alamat IP-né awujud angka kanggo nglacak dhèwèké.\nAlamat IP mangkono bisa dianggo déning sawenèh panganggo.\nManawa panjenengan panganggo anonim lan rumasa yèn ana tanggepan kang ora ilok dieneraké marang panjenengan, mangga [[Special:CreateAccount|gawéa akun]] utawa [[Special:UserLogin|mlebua log]] kanggo ngéndhani salah pangira karo panganggo anonim liyané ing tembé buri.",
+       "anontalkpagetext": "----\n<em>Iki kaca parembugané panganggo anonim kang durung gawé akun, utawa kang ora nganggo akuné.</em>\nMula, awak dhéwé kudu nganggo alamat IP wujud angka kanggo nglacak dhèwèké.\nAlamat IP mangkono bisa dianggo sawatara wong.\nManawa kowé minangka panganggo anonim lan rumasa yèn ana tanggepan kang ora ilok dieneraké marang awakmu, mangga [[Special:CreateAccount|gawéa akun]] utawa [[Special:UserLogin|mlebua log]] kanggo ngéndhani bingung marang panganggo anonim liyané ing tembé buri.",
        "noarticletext": "Saiki kaca iki durung ana tulisané.\nPanjenengan bisa (1) [[Special:Search/{{PAGENAME}}|nggolèki sesirahing kaca iki]] ing kaca liyané, (2)\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} nggolèki log kang magepokan],\nutawa (3) [{{fullurl:{{FULLPAGENAME}}|action=edit}} nggawé kaca iki]</span>.",
        "noarticletext-nopermission": "Saiki lagi ora ana tèks ing kaca iki. \nPanjenengan bisa [[Special:Search/{{PAGENAME}}|nggolèk sesirah kaca iki]] ing kaca liyané, \nutawa <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{urlencode:{{FULLPAGENAME}}}}}} nggolèk ing log kang gegayutan]</span>, nanging panjenengan ora kawogan nggawé kaca iki.",
        "missing-revision": "Révisi #$1 saka kaca aran \"{{FULLPAGENAME}}\" ora ana.\n\nIki biyasané kasababaké awit nututi pranala sajarah kang wis lawas saka kaca kang wis binusek.\nRerincèné bisa digolèki ing [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} log besakan].",
        "editpage-invalidcontentmodel-text": "Modhèl kontèn \"$1\" ora sinengkuyung.",
        "editpage-notsupportedcontentformat-title": "Formal kontèn ora sinengkuyung",
        "editpage-notsupportedcontentformat-text": "Format kontèn $1 ora disengkuyung modhèl kontèn $2.",
+       "slot-name-main": "Pokok",
        "content-model-wikitext": "tulisan wiki",
        "content-model-text": "tulisan barès",
        "content-model-javascript": "JavaScript",
        "page_first": "kapisan",
        "page_last": "pungkasan",
        "histlegend": "Kanggo mbandhingaké: Tandhani kothak radhioning révisi-révisi kang arep dibandhingaké lan pencèt ''Enter'' utawa tombol ing ngisor.<br />\nLegéndhah: <strong>({{int:cur}})</strong> = bédané karo révisi pungkasan, <strong>({{int:last}})</strong> = bédané karo révisi sadurungé, <strong>{{int:minoreditletter}}</strong> = besutan cilik.",
-       "history-fieldset-title": "Golèk owahan",
+       "history-fieldset-title": "Saring révisi",
        "history-show-deleted": "Mligi owahan kang binusek",
        "histfirst": "lawas dhéwé",
        "histlast": "anyar dhéwé",
        "historysize": "($1 {{PLURAL:$1|bét|bét}})",
-       "historyempty": "(suwung)",
+       "historyempty": "kosong",
        "history-feed-title": "Sajarah owahan",
        "history-feed-description": "Sajarah owahaning kaca iki ing wiki",
        "history-feed-item-nocomment": "$1 ing $2",
        "searchprofile-articles-tooltip": "Golèkan ing $1",
        "searchprofile-images-tooltip": "Golèk barkas",
        "searchprofile-everything-tooltip": "Golèk kabèh kontèn (kalebu ing kaca parembugan)",
-       "searchprofile-advanced-tooltip": "Golèk ing mandala aran tinamtu",
+       "searchprofile-advanced-tooltip": "Golèk ing mandhala aran tinamtu",
        "search-result-size": "$1 ({{PLURAL:$2|1 tembung|$2 tembung}})",
        "search-result-category-size": "{{PLURAL:$1|1 anggota|$1 anggota}} ({{PLURAL:$2|1 subkategori|$2 subkategori}}, {{PLURAL:$3|1 barkas|$3 barkas}})",
        "search-redirect": "(alihan saka $1)",
        "search-nonefound": "Ora ana asil kang mathuk kuwèri.",
        "search-nonefound-thiswiki": "Ora ana kasil kang jumbuh karo panjalukan ing situs iki.",
        "powersearch-legend": "Panggolèkan sabanjuré (''advance search'')",
-       "powersearch-ns": "Golèk ing mandala aran:",
+       "powersearch-ns": "Golèk ing mandhala aran:",
        "powersearch-togglelabel": "Pilih:",
        "powersearch-toggleall": "Kabèh",
        "powersearch-togglenone": "Ora ana",
        "timezoneregion-pacific": "Samodra Pasifik",
        "allowemail": "Idinaké panganggo liyané ngirimi layang-èl",
        "prefs-searchoptions": "Golèk",
-       "prefs-namespaces": "Mandala aran",
+       "prefs-namespaces": "Mandhala aran",
        "default": "baku",
        "prefs-files": "Barkas",
        "prefs-custom-css": "CSS priangga",
        "rcfilters-filter-editsbyself-description": "Pisumbangé panjenengan dhéwé.",
        "rcfilters-filter-editsbyother-label": "Owah-owahané liyan",
        "rcfilters-filter-editsbyother-description": "Kabèh owahan kajaba duwèké panjenengan.",
-       "rcfilters-filtergroup-userExpLevel": "Pandhaftaran lan pangalaman pangguna",
+       "rcfilters-filtergroup-user-experience-level": "Pandhaftaran lan pangalaman pangguna",
        "rcfilters-filter-user-experience-level-registered-label": "Kadhaftar",
        "rcfilters-filter-user-experience-level-registered-description": "Pambesut kang mlebu log.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Ora kadhaftar",
        "rcfilters-filter-categorization-description": "Cathethan ngenani mlebu-metuné kaca saka kategori.",
        "rcfilters-filter-logactions-label": "Laku ing jero log",
        "rcfilters-filter-logactions-description": "Laku administratif, panggawé akun, pambusak kaca, unggahan...",
-       "rcfilters-filtergroup-lastRevision": "Révisi pungkasan",
+       "rcfilters-filtergroup-lastrevision": "Révisi pungkasan",
        "rcfilters-filter-lastrevision-label": "Révisi pungkasan",
        "rcfilters-filter-lastrevision-description": "Mung owahaning kaca kang anyar dhéwé.",
        "rcfilters-filter-previousrevision-label": "Dudu révisi pungkasan",
        "rcfilters-filter-previousrevision-description": "Kabèh owahan kang dudu \"révisi pungkasan\".",
        "rcfilters-view-tags": "Besutan kang tinengeran",
-       "rcfilters-view-namespaces-tooltip": "Saring kasilé miturut mandala-arané",
+       "rcfilters-view-namespaces-tooltip": "Saring kasilé miturut mandhala arané",
        "rcfilters-view-tags-tooltip": "Saring kasilé nganggo tengering besutan",
        "rcnotefrom": "Ing ngisor iki {{PLURAL:$5|owah-owahan}} kawit <strong>$3, $4</strong> (kang kapacak nganti <strong>$1</strong> owah-owahan).",
        "rclistfrom": "Tuduhaké owah-owahan anyar kawit $2, $3",
        "minoreditletter": "c",
        "newpageletter": "A",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|cacahé kang ngawasi|cacahé kang ngawasi}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|bèt|bèt}} sawisé kaowahan",
        "newsectionsummary": "/* $1 */ pérangan anyar",
        "rc-enhanced-expand": "Tuduhaké princèn",
        "img-auth-nopathinfo": "Kélangan PATH_INFO.\nSasana panjenengan durung disetèl kanggo ngliwati inpormasi iki.\nMungkin amarga abasis-CGI lan ora bisa nyengkuyung img_auth.\nWaca https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Alur kang dijaluk dudu dirèktori unggah kakonpigurasi.",
        "img-auth-badtitle": "Ora bisa ngyasa sesirah kang trep saka \"$1\".",
-       "img-auth-nologinnWL": "Panjenengan durung mlebu log lan \"$1\" ora ing pratélan putih.",
        "img-auth-nofile": "Barkas \"$1\" ora ana.",
        "img-auth-isdir": "Panjenengan lagi njajal ngaksès dirèktori \"$1\".\nNamung aksès barkas kang dililakaké.",
        "img-auth-streaming": "Striming \"$1\".",
        "download": "undhuh",
        "unwatchedpages": "Kaca kang ora ingawasan",
        "listredirects": "Pratélan alihan",
-       "unusedtemplates": "Cithakan kang ora kanggo",
-       "unusedtemplatestext": "Kaca iki isi kabèh kaca ing mandala aran {{ns:template}} kang ora kaanggo ing kaca liya.\nAja lali mesthèkaké ana-orané pranala liya kang ngener cithakané sadurungé panjenengan mbusek.",
+       "unusedtemplates": "Cithakan kang ora kaanggo",
+       "unusedtemplatestext": "Kaca iki isi kabèh kaca ing mandhala aran {{ns:template}} kang ora kaanggo ing kaca liya.\nAja lali mesthèkaké ana-orané pranala liya kang ngener cithakané sadurung kobusek.",
        "unusedtemplateswlh": "pranala liya-liyané",
        "randompage": "Kaca sembarang",
-       "randompage-nopages": "Ora ana kaca ing {{PLURAL:$2||}}bilik jeneng iki:$1.",
+       "randompage-nopages": "Ora ana kaca ing {{PLURAL:$2|mandhala aran|mandhala aran}} iki:$1.",
        "randomincategory": "Sembarang kaca ing kategori",
        "randomincategory-invalidcategory": "\"$1\" dudu jeneng kategori kang trep.",
        "randomincategory-nopages": "Ora ana kaca ing kategori [[:Category:$1|$1]].",
        "randomincategory-legend": "Sembarang kaca ing kategori",
        "randomincategory-submit": "Menyang",
        "randomredirect": "Pangalihan sembarang",
-       "randomredirect-nopages": "Ora ana alih-alihan ing mandala aran \"$1\".",
+       "randomredirect-nopages": "Ora ana alih-alihan ing mandhala aran \"$1\".",
        "statistics": "Statistik",
        "statistics-header-pages": "Statistik kaca",
        "statistics-header-edits": "Pétungan besutan",
        "withoutinterwiki-summary": "Kaca-kaca ing ngisor iki ora nggayut menyang vèrsi basa liyané.",
        "withoutinterwiki-legend": "Préfiks",
        "withoutinterwiki-submit": "Tuduhna",
-       "fewestrevisions": "Artikel kang owahé sithik dhéwé",
+       "fewestrevisions": "Artikel kang owahé sathithik dhéwé",
        "nbytes": "$1 {{PLURAL:$1|bét|bét}}",
        "ncategories": "$1 {{PLURAL:$1|kategori|kategori}}",
        "ninterwikis": "$1 {{PLURAL:$1|interwiki|interwiki}}",
        "uncategorizedcategories": "Kategori kang tanpa kategori",
        "uncategorizedimages": "Barkas kang tanpa kategori",
        "uncategorizedtemplates": "Cithakan kang durung kawènèhan kategori",
-       "unusedcategories": "Kategori kang ora kanggo",
-       "unusedimages": "Barkas kang ora kanggo",
+       "unusedcategories": "Kategori kang ora kaanggo",
+       "unusedimages": "Barkas kang ora kaanggo",
        "wantedcategories": "Kategori kang kapéngini",
        "wantedpages": "Kaca kang kapéngini",
        "wantedpages-badtitle": "Sesirah ora sah ing omboyakan kasil: $1",
        "mostinterwikis": "Kaca mawa interwiki akèh dhéwé",
        "mostrevisions": "Kaca mawa pangowahan kang akèh dhéwé",
        "prefixindex": "Kabèh kaca mawa ater-ater",
-       "prefixindex-namespace": "Kabèh kaca mawa ater-ater (bilik jeneng $1)",
+       "prefixindex-namespace": "Kabèh kaca mawa ater-ater (mandhala aran $1)",
        "prefixindex-submit": "Tuduhaké",
        "prefixindex-strip": "Busak ater-ater saka pratélan",
        "shortpages": "Kaca kang cendhak",
        "apisandbox-continue-clear": "Resiki",
        "apisandbox-continue-help": "{{int:apisandbox-continue}} bakal [https://www.mediawiki.org/wiki/API:Query#Continuing_queries mbanjuraké] panyuwunané kang pungkasan; {{int:apisandbox-continue-clear}} bakal ngresiki paramèter kang magepokan.",
        "apisandbox-param-limit": "Isinen <kbd>max</kbd> saperlu nganggo watesan maksimum.",
-       "apisandbox-multivalue-all-namespaces": "$1 (Kabèh mandala aran)",
+       "apisandbox-multivalue-all-namespaces": "$1 (Kabèh mandhala aran)",
        "apisandbox-multivalue-all-values": "$1 (Kabèh aji)",
        "booksources": "Sumber buku",
        "booksources-search-legend": "Golèk sumber buku",
        "allpagesfrom": "Pitontonaké kaca kang kawiwitan:",
        "allpagesto": "Tampilaké kaca dipungkasi ing:",
        "allarticles": "Kabèh kaca",
-       "allinnamespace": "Kabèh kaca (mandala aran $1)",
+       "allinnamespace": "Kabèh kaca (mandhala aran $1)",
        "allpagessubmit": "Menyang",
        "allpagesprefix": "Tuduhaké kaca mawa ater-ater:",
        "allpagesbadtitle": "Sesirah kang panjengan karsakaké ora trep utawa ngemu ater-ater antarabasa utawa antarawiki.\nSesirah iku bokmanawa ngemu karakter kang ora bisa kaanggo ing sesirah.",
-       "allpages-bad-ns": "{{SITENAME}} ora duwé mandala aran \"$1\".",
+       "allpages-bad-ns": "{{SITENAME}} ora duwé mandhala aran \"$1\".",
        "allpages-hide-redirects": "Dhelikaké alihan",
        "cachedspecial-viewing-cached-ttl": "Panjenengan lagi ndeleng vèrsi cadhangan saka kaca iki, kang bisa dadi lawasé wis $1.",
        "cachedspecial-viewing-cached-ts": "Panjenengan lagi ndeleng vèrsi cadhangan saka kaca iki, kang bisa dadi ora padha karo kasunyatan.",
        "sp-deletedcontributions-contribs": "pasumbang",
        "linksearch": "Golèkan pranala njaba",
        "linksearch-pat": "Polah ing gegolèkan:",
-       "linksearch-ns": "Bilik nama:",
+       "linksearch-ns": "Mandhala aran:",
        "linksearch-ok": "Golèk",
        "linksearch-text": "Tanda bintang seperti \"*.wikipedia.org\" dapat digunakan.\nPerlu sedikitnya satu domain tingkat atas, misalnya \"*.org\".<br />\n{{PLURAL:$2|Protokol|Protokol}} yang didukung: $1 (menggunakan http:// bila protokol tidak ditentukan)",
        "linksearch-line": "$1 disambung saka $2",
        "listgrouprights-removegroup-self": "Mbusek {{PLURAL:$2|golongan|golongan}} saka akuné dhéwé: $1",
        "listgrouprights-addgroup-self-all": "Nambahaké kabèh grup menyang akuné dhéwé",
        "listgrouprights-removegroup-self-all": "Busak kabèh golongan saka akuné dhéwé",
-       "listgrouprights-namespaceprotection-header": "Watesan mandala aran",
-       "listgrouprights-namespaceprotection-namespace": "Mandala aran",
+       "listgrouprights-namespaceprotection-header": "Watesan mandhala aran",
+       "listgrouprights-namespaceprotection-namespace": "Mandhala aran",
        "listgrouprights-namespaceprotection-restrictedto": "Hak kang ngidinaké panganggo mbesut",
        "listgrants": "Idin",
        "listgrants-grant": "Idin",
        "protect-title": "Owahi tataran rereksané \"$1\"",
        "protect-title-notallowed": "Deleng tataran rereksan saka \"$1\"",
        "prot_1movedto2": "$1 dialihaké menyang $2",
-       "protect-badnamespace-title": "Bilik jeneng kang ora bisa dijagani",
-       "protect-badnamespace-text": "Kaca ing bilik jeneng iki ora bisa dijagani.",
+       "protect-badnamespace-title": "Mandhala aran kang ora bisa rineksa",
+       "protect-badnamespace-text": "Kaca ing mandhala aran iki ora bisa rineksa.",
        "protect-norestrictiontypes-text": "Kaca iki ora isa diproteksi.",
        "protect-norestrictiontypes-title": "Kaca kang ora bisa diproteksi",
        "protect-legend": "Konfirmasi rereksan",
        "undelete-error-long": "Masalah nalika wurung mbusak barkas:\n\n$1",
        "undelete-show-file-confirm": "Apa panjenengan yakin arep mirsani révisi berkas \"<nowiki>$1</nowiki>\" kang wis kabusak ing $2 jam $3?",
        "undelete-show-file-submit": "Ya",
-       "namespace": "Mandala aran:",
+       "namespace": "Mandhala aran:",
        "invert": "Balèkaké pilihan",
-       "tooltip-invert": "Centhang kothak iki kanggo ndhelikaké owahan saka kaca-kaca ing njero bilik jeneng kapilih (lan bilik jeneng kakait yèn dicenthang)",
-       "namespace_association": "Mandala aran magepokan",
-       "tooltip-namespace_association": "Centhang kothak iki kanggo nglebokaké uga bilik jeneng gumenan utawa subyèk kang kakait karo bilik jeneng kapilih",
+       "tooltip-invert": "Cénthang kothak iki kanggo ndhelikaké owahan saka kaca-kaca ing mandhala aran kapilih (lan mandhala aran gegayutan yèn kacénthang)",
+       "namespace_association": "Mandhala aran magepokan",
+       "tooltip-namespace_association": "Cénthang kothak iki kanggo nglebokaké uga mandhala aran parembugan utawa subyèk kang gegayutan karo mandhala aran kapilih",
        "blanknamespace": "(Pokok)",
        "contributions": "Pisumbanging {{GENDER:$1|panganggo}}",
        "contributions-title": "Pisumbanging panganggo $1",
        "mycontris": "Pasumbang",
        "anoncontribs": "Pasumbang",
        "contribsub2": "Kanggo {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "Marang {{GENDER:$3|$1}}",
        "nocontribs": "Owah-owahan kang cocog karo wewaton mangkono ora tinemu.",
        "uctop": "saiki",
        "month": "Saka wulan (lan sadurungé):",
        "whatlinkshere-page": "Kaca:",
        "linkshere": "Kaca-kaca ing ngisor iki nggayut menyang <strong>$2</strong>:",
        "nolinkshere": "Ora ana kaca kang nduwé pranala menyang '''$2'''.",
-       "nolinkshere-ns": " Ora ana kaca kang nduwé pranala menyang '''$2''' ing bilik jeneng kang kapilih.",
+       "nolinkshere-ns": "Ora ana kaca kang nduwé pranala menyang <strong>$2</strong> ing mandhala aran kang kapilih.",
        "isredirect": "kaca lih-lihan",
        "istemplate": "tranklusi",
        "isimage": "pranala barkas",
        "delete_and_move_confirm": "Ya, busak kaca iku.",
        "delete_and_move_reason": "Dibusak kanggo sarana ngalihaké saka \"[[$1]]\"",
        "selfmove": "Sesirah sumber lan tujuan padha;\nora bisa ngalih menyang tujuan kang padha.",
-       "immobile-source-namespace": "Ora bisa mindhahaké kaca jroning bilik jeneng \"$1\"",
-       "immobile-target-namespace": "Ora bisa mindhahaké kaca menyang bilik jeneng \"$1\"",
+       "immobile-source-namespace": "Ora bisa ngalih kaca ing mandhala aran \"$1\"",
+       "immobile-target-namespace": "Ora bisa ngalih kaca menyang mandhala aran \"$1\"",
        "immobile-target-namespace-iw": "Pranala interwiki dudu tujuan kang trep tumrap pangalihé kaca.",
        "immobile-source-page": "Kaca iki ora bisa dilih-lih.",
        "immobile-target-page": "Ora bisa mindhahaké menyang irah-irahan tujuan kasebut.",
        "bad-target-model": "Tujuan kang diarepaké nganggo gagrag isi kang béda. Ora bisa ngganti $1 dadi $2.",
-       "imagenocrossnamespace": "Ora bisa mindhahaké gambar menyang bilik nama non-gambar",
-       "nonfile-cannot-move-to-file": "Ora bisa ngalih non-barkas menyang mandala aran barkas.",
+       "imagenocrossnamespace": "Ora bisa ngalih barkas menyang mandhala aran non-barkas",
+       "nonfile-cannot-move-to-file": "Ora bisa ngalih non-barkas menyang mandhala aran barkas.",
        "imagetypemismatch": "Èkstènsi anyar berkas ora cocog karo jenisé",
        "imageinvalidfilename": "Jeneng barkas tujuan ora trep.",
        "fix-double-redirects": "Dandani kabèh pangalihan gandha kang tumuju marang irah-irahan asli",
        "export-submit": "Èkspor",
        "export-addcattext": "Tambahna kaca saka kategori:",
        "export-addcat": "Tambahna",
-       "export-addnstext": "Nambahaké kaca saka bilik jeneng:",
+       "export-addnstext": "Wuwuh kaca saka mandhala aran:",
        "export-addns": "Tambah",
        "export-download": "Simpen dadi barkas",
        "export-templates": "Lebokaké cithakan",
        "allmessagesname": "Jeneng",
        "allmessagesdefault": "Tèks baku",
        "allmessagescurrent": "Tèks saiki",
-       "allmessagestext": "Iki pratélan layang sistem kang ana ing mandala aran MediaWiki.\nMangga manjing [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Panglokalan MediaWiki] lan [https://translatewiki.net translatewiki.net] manawa panjenengan arep nyumbang ing panglokalan MediaWiki kangasli.",
-       "allmessagesnotsupportedDB": "Kaca iki ora bisa dienggo amarga '''$wgUseDatabaseMessages''' dipatèni.",
+       "allmessagestext": "Iki pratélan layang sistem kang ana ing mandhala aran MediaWiki.\nMangga mlebu [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Panglokalan MediaWiki] lan [https://translatewiki.net translatewiki.net] manawa kowé arep nyumbang ing panglokalan MediaWiki kang asli.",
+       "allmessages-not-supported-database": "Kaca iki ora bisa dienggo amarga '''$wgUseDatabaseMessages''' dipatèni.",
        "allmessages-filter-legend": "Penyaring",
        "allmessages-filter": "Saring nganggo kahanan kustomisasi:",
        "allmessages-filter-unmodified": "Ora diowahi",
        "import-interwiki-templates": "Katutna kabèh cithakan",
        "import-interwiki-submit": "Impor",
        "import-mapping-default": "Impor menyang panggonan gawan",
-       "import-mapping-namespace": "Impor menyang mandala aran:",
+       "import-mapping-namespace": "Impor menyang mandhala aran:",
        "import-mapping-subpage": "Impor minangka anak kaca iki:",
        "import-upload-filename": "Jeneng barkas:",
        "import-comment": "Komentar:",
        "import-error-edit": "Kaca \"$1\" ora kaimpor amarga panjenengan ora kawogan mbesut iku.",
        "import-error-create": "Kaca \"$1\" ora diimpor amarga panjenengan ora dililakaké nggawé iku.",
        "import-error-interwiki": "Kaca \"$1\" ora diimpor amarga jenengé dicadhangaké kango pranala njaba (interwiki).",
-       "import-error-special": "Kaca \"$1\" ora diimpor amarga darbèké mandala aran mirunggan kang ora nglilakaké anané kaca.",
+       "import-error-special": "Kaca \"$1\" ora kaimpor amarga kalebu ing mandhala aran mirunggan kang ora ngolèhaké ananing kaca.",
        "import-error-invalid": "Kaca \"$1\" ora diimpor amarga jenengé ora trep kanggo wiki iki.",
        "import-error-unserialize": "Révisi $2 saka kaca \"$1\" ora bisa diurutaké. Révisi iku dilapuraké supaya nganggo modhèl kontèn $3 kang diurutaké minangka $4.",
        "import-options-wrong": "{{PLURAL:$2|Opsi|Opsi}} salah: <nowiki>$1</nowiki>",
        "authmanager-provider-password": "Otèntifikasi adhedhasar tembung wadi",
        "authmanager-provider-password-domain": "Otèntifikasi adhedhasar tembung wadi lan dhomain",
        "authmanager-provider-temporarypassword": "Tembung wadi sauntara",
-       "authprovider-resetpass-skip-label": "Langkahi",
+       "authprovider-resetpass-skip-label": "Lumpati",
        "credentialsform-account": "Jeneng akun:",
        "cannotlink-no-provider-title": "Ora ana akun kang bisa digayutaké",
        "cannotlink-no-provider": "Ora ana akun kang bisa digayutaké.",
index 1790630..e8c3520 100644 (file)
        "mergehistory-go": "აჩვენეთ გაერთიანებული ცვლილებები",
        "mergehistory-submit": "ცვლილებების შერწყმა",
        "mergehistory-empty": "რაიმე ცვლილების შერწყმა შეუძლებელია.",
-       "mergehistory-done": "$3 {{PLURAL:$3|á\83¨á\83\94á\83¡á\83¬á\83\9dá\83 á\83\94á\83\91á\83\90\83¨á\83\94á\83¡á\83¬á\83\9dá\83 á\83\94á\83\91á\83\94á\83\91á\83\98}} $1-á\83\93á\83\90á\83\9c á\83¬á\83\90á\83 á\83\9bá\83\90á\83¢á\83\94á\83\91á\83\98á\83\97 {{PLURAL:$3|á\83¨á\83\94á\83\94á\83 á\83¬á\83§á\83\90\83¨á\83\94á\83\94á\83 á\83¬á\83§á\83\90}} [[:$2]]-á\83¡.",
+       "mergehistory-done": "$3 {{PLURAL:$3|á\83ªá\83\95á\83\9aá\83\98á\83\9aá\83\94á\83\91á\83\90\83ªá\83\95á\83\9aá\83\98á\83\9aá\83\94á\83\91á\83\90}} á\83\92á\83\95á\83\94á\83 á\83\93á\83\98 $1 á\83¬á\83\90á\83 á\83\9bá\83\90á\83¢á\83\94á\83\91á\83\98á\83\97 {{PLURAL:$3|á\83¨á\83\94á\83\94á\83 á\83¬á\83§á\83\90\83¨á\83\94á\83\94á\83 á\83¬á\83§á\83\90}} á\83\92á\83\95á\83\94á\83 á\83\93á\83¡ [[:$2]].",
        "mergehistory-fail": "ვერ მოხერხდა გვერდების ისტორიის გაერთიანება, გთხოვთ შეამოწმოთ გვერდის პაარამეტრები და დრო.",
        "mergehistory-fail-bad-timestamp": "მიმდევრობა არასწორია.",
        "mergehistory-fail-invalid-source": "წყაროს გვერდი არასწორია.",
        "rcfilters-filter-editsbyself-description": "თქვენი წვლილი.",
        "rcfilters-filter-editsbyother-label": "სხვა მომხმარებლების ცვლილებები",
        "rcfilters-filter-editsbyother-description": "ყველა ცვლილება, გარდა საკუთარისა.",
-       "rcfilters-filtergroup-userExpLevel": "მომხმარებლის რეგისტრაცია და გამოცდილება",
+       "rcfilters-filtergroup-user-experience-level": "მომხმარებლის რეგისტრაცია და გამოცდილება",
        "rcfilters-filter-user-experience-level-registered-label": "რეგისტრირებულები",
        "rcfilters-filter-user-experience-level-registered-description": "შესული რედაქტორები.",
        "rcfilters-filter-user-experience-level-unregistered-label": "არარეგისტრირებულები",
        "rcfilters-hideminor-conflicts-typeofchange-global": "„მცირე რედაქტირების“ ფილტრი კონფლიქტშია ერთი ან რამდენიმე ცვლილების ტიპის ფილტრთან, რადგან ცვლილების რამდენიმე ტიპი არ ინიშნება როგორც „მცირე“. კონფლიქტური ფილტრები მონიშნულია აქტიური ფილტრების არეალში, ზემოთ.",
        "rcfilters-hideminor-conflicts-typeofchange": "ცვლილების რამდენიმე ტიპი არ ინიშნება როგორც „მცირე“, ასე რომ ეს ფილტრი კონფლიქტშია ცვლილების ტიპის შემდეგ ფილტრებთან: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "ეს ცვლილების ტიპის ფილტრი კონფლიქტშია „მცირე რედაქტირების“ ფილტრთან. ცვლილების ზოგიერთი ტიპი ვერ ინიშნება, როგორც „მცირე“.",
-       "rcfilters-filtergroup-lastRevision": "ბოლო ცვლილებები",
+       "rcfilters-filtergroup-lastrevision": "ბოლო ცვლილებები",
        "rcfilters-filter-lastrevision-label": "ბოლო ცვლილება",
        "rcfilters-filter-lastrevision-description": "მხოლოდ ბოლო ცვლილება გვერდზე.",
        "rcfilters-filter-previousrevision-label": "ბოლო ცვლილების გარდა",
        "newpageletter": "ა",
        "boteditletter": "რ",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 მომხმარებლის/ები კონტროლი]",
        "rc-change-size": "$1",
        "rc-change-size-new": "ზომა ცვლილების შემდეგ არის: {{PLURAL:$1|ბაიტი|ბაიტი}}",
        "newsectionsummary": "/* $1 */ ახალი სექცია",
        "img-auth-nopathinfo": "დაკარგულია PATH_INFO.\nთქვენი სერვერი არ არის მომართული ამ ინფორმაციის გადასაცემად.\nშესაძლოა, ის მუშაობს CGI-ის ბაზაზე და არ გააჩნია img_auth მხარდაჭერა.\n[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization იხილეთ სურათის ავტორიზაცია.]",
        "img-auth-notindir": "მოთხოვნილი გზა არ შეესაბამება ატვირთვის ფოლდერს.",
        "img-auth-badtitle": "შეუძლებელია სწორი სათაურის შექმნა \"$1\"-დან.",
-       "img-auth-nologinnWL": "თქვენ არ შესულხართ სისტემაში, ხოლო «$1» არ არის თეთრ სიაში.",
        "img-auth-nofile": "ფაილი \"$1\" არ არსებობს.",
        "img-auth-isdir": "თქვენ ცდილობთ «$1» კატალოგთან მისავლის მიგნებას.\nნებადართულია მხოლოდ ფაილებთან კავშირი.",
        "img-auth-streaming": "ნაკადური გადაცემა «$1».",
        "revertpage": "[[Special:Contributions/$2|$2]]-ის რედაქტირება გაუქმდა; აღდგა ბოლოს [[User:$1|$1]]-ის მიერ რედაქტირებული ვერსია",
        "revertpage-nouser": "მომხმარებლის (მომხმარებლის სახელი დამალულია) ცვლილებები დაბრუნებულია ვერსიაზე {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "გაუქმდა რედაქტირება {{GENDER:$3|$1}}-ის მიერ;\nდაბრუნდა ვერსიაზე, რომელიც განახორციელა {{GENDER:$4|$2}}-მ.",
-       "rollback-success-notify": "გაუმქდა $1-ის მიერ განხორციელებული რედაქტირებები;\nდაბრუნდე ვერსიაზე, რომელიც განახორციელა $2-მ. [$3 ცვლილებების ნახვა]",
        "sessionfailure-title": "სეანსის შეცდომა",
        "sessionfailure": "ჩანს, რომ პრობლემაა თქვენი რეგისტრაციის სესიისათვის;\nეს მოქმედება შეჩერდა თქვენი სესიაში შემოჭრის თავიდან ასაცილებლად.\nგთხოვთ, დააწკაპუნოთ ღილაკს „უკან“ და თავიდან ჩართოთ გვერდი, რომლიდანაც შემოხვედით და სცადოთ განმეორებით.",
        "changecontentmodel": "გვერდის კონტენტური მოდელის შეცვლა",
        "allmessagesdefault": "სტანდარტული ტექსტი",
        "allmessagescurrent": "მიმდინარე ტექსტი",
        "allmessagestext": "ეს არის სისემურ შეტყობინებათა სია «MediaWiki» სახელთა სივრცეში.\nგთხოვთ ეწვიოთ  [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation ლოკალიზაციის აღმწერ] გვერდს [https://translatewiki.net translatewiki.net] პროექტს, თუ გსურთ MediaWiki ლოკალიზაციაში წვლილის შეტანა.",
-       "allmessagesnotsupportedDB": "ამ გვერდის გამოყენება შეუძლებელია, რადგან\n<strong>$wgUseDatabaseMessages</strong> გამორთულია.",
+       "allmessages-not-supported-database": "ამ გვერდის გამოყენება შეუძლებელია, რადგან\n<strong>$wgUseDatabaseMessages</strong> გამორთულია.",
        "allmessages-filter-legend": "ფილტრი",
        "allmessages-filter": "ფილტრი ცვლილებების სტატუსით:",
        "allmessages-filter-unmodified": "უცვლელი",
        "logentry-import-upload-details": "$1-მ {{GENDER:$2|გადაიტანა}} $3 ფაილის ატვირთვით ($4 {{PLURAL:$4|ცვლილება|ცვლილება}})",
        "logentry-import-interwiki": "$1 {{GENDER:$2|იმპორტირებული}} $3 სხვა ვიკიდან",
        "logentry-import-interwiki-details": "$1-მ {{GENDER:$2|გადაიტანა}} $3 $5-ზე ($4 {{PLURAL:$4|ცვლილება|ცვლილება}})",
-       "logentry-merge-merge": "მომხმარებელმა $1 {{GENDER:$2|გააერთიანა}} $3 $4-ში ($5-მდე ვერსია)",
+       "logentry-merge-merge": "მომხმარებელმა $1 გვერდი $3 {{GENDER:$2|გააერთიანა}} გვერდში $4 ($5-მდე ვერსია)",
        "logentry-move-move": "მომხმარებელმა $1 გვერდი „$3“ {{GENDER:$2|გადაიტანა}} გვერდზე „$4“",
        "logentry-move-move-noredirect": "მომხმარებელმა $1 გვერდი „$3“ {{GENDER:$2|გადაიტანა}} გვერდზე „$4“ გადამისამართების დატოვების გარეშე",
        "logentry-move-move_redir": "მომხმარებელმა $1 გვერდი „$3“ {{GENDER:$2|გადაიტანა}} გვერდზე „$4“ გადამისამართებაზე",
index 0960e29..2b9f369 100644 (file)
        "minoreditletter": "k",
        "newpageletter": "T",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[Baqlag'an {{PLURAL:$1|1 paydalanıwshı|$1 paydalanıwshı}}]",
        "newsectionsummary": "/* $1 */ taza bo'lim",
        "rc-enhanced-expand": "Tolıq mag'lıwmattı ko'rsetiw (JavaScriptti talap etedi)",
        "rc-enhanced-hide": "Tolıq mag'lıwmattı jasırıw",
index 50e4981..0c0e824 100644 (file)
                        "SlimaneAmiri",
                        "Sayem AtVkm",
                        "Fitoschido",
-                       "Vlad5250"
+                       "Vlad5250",
+                       "K Messaoudi"
                ]
        },
-       "tog-underline": "Aderrer n iseɣwan:",
+       "tog-underline": "Aderrer n yiseɣwan:",
        "tog-hideminor": "Ffer ibeddilen ifessasen deg yibeddilen imaynuten",
-       "tog-hidepatrolled": "Ffer ibeddilen yettwaɣran deg yibeddilen imaynuten",
-       "tog-newpageshidepatrolled": "Ffer isebtar yettwaɣran deg tebdart n isebtar imaynten",
-       "tog-hidecategorization": "Ffer taggayin n isebtar",
-       "tog-extendwatchlist": "Ssemɣer umuɣ n uɛessi iwakken ad muqleɣ akk n wayen zemreɣ ad beddleɣ",
-       "tog-usenewrc": "Ssegrew ibeddlen s usebtar deg ibeddilen imaynuten d umuɣ n uḍfar",
+       "tog-hidepatrolled": "Ffer ibeddilen yettwaɣran seg yibeddilen imaynuten",
+       "tog-newpageshidepatrolled": "Ffer isebtar yettwaɣran seg tebdart n yisebtar imaynten",
+       "tog-hidecategorization": "Ffer taggayin n yisebtar",
+       "tog-extendwatchlist": "Ssemɣer umuɣ n uɛessi iwakken ad d-iban akk wayen izemren ad ibeddel",
+       "tog-usenewrc": "Ssegrew ibeddilen s usebtar deg yibeddilen imaynuten d wumuɣ n uḍfar",
        "tog-numberheadings": "Izwal ɣur-sen imḍanen mebla ma serseɣ-iten",
-       "tog-editondblclick": "Beddel isebtar mi wekkiɣ snat n tikwal",
-       "tog-editsectiononrightclick": "Ssermed abeddel n tigezmi s ukliki ayeffus ɣef izwal",
+       "tog-editondblclick": "Beddel isebtar s uttekki snat n tikwal",
+       "tog-editsectiononrightclick": "Ssermed abeddel n tgezmi s uttekki ayeffus ɣef yizwal",
        "tog-watchcreations": "Rnu isebtar i xelqeɣ deg wumuɣ n uɛessi inu",
        "tog-watchdefault": "Rnu isebtar i ttbeddileɣ deg wumuɣ n uɛessi inu",
        "tog-watchmoves": "Rnu isebtar i smimḍeɣ deg wumuɣ n uɛessi inu",
        "rcfilters-filter-editsbyself-description": "Ittekkiyen-ik",
        "rcfilters-filter-editsbyother-label": "Asnifel n wiyaḍ",
        "rcfilters-filter-editsbyother-description": "Akk ibeddilen slid wid iynek(m).",
-       "rcfilters-filtergroup-userExpLevel": "Asekles n iseqdacen aked tarmit",
+       "rcfilters-filtergroup-user-experience-level": "Asekles n iseqdacen aked tarmit",
        "rcfilters-filter-user-experience-level-registered-label": "Yeqqen",
        "rcfilters-filter-user-experience-level-registered-description": "Imaẓragen uqqinen.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Ur yeqqin ara",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|aɛessas|iɛessasen}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|atamḍan|itamḍanen}} seld abeddel",
        "newsectionsummary": "/* $1 */ tigezmi tamaynut",
        "rc-enhanced-expand": "Ẓeṛ ttfaṣil",
        "img-auth-nopathinfo": "Yexus BATH_INFU.\nAqeddac inek/inem ur yeseɣwer ara iwakken ad i ɛeddi talɣut agi.\nAhat i lḥu  s CGI dɣa ur s-yezmer ara i img_auth.\nẒeṛ https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Abrid yesuteren mačči d akaram n taktert yellan deg tawila.",
        "img-auth-badtitle": "Ulamek an ssali azwel i ɣbelen seg « $1 ».",
-       "img-auth-nologinnWL": "Ur teqqneḍ ara dɣa « $1 » ur yella ara deg umuɣ amellal.",
        "img-auth-nofile": "Afaylu « $1 » ulac it.",
        "img-auth-isdir": "Tɛerdeḍ ad ldiḍ akaram « $1 ».\nTzemreḍ kan ad ldiḍ ifuyla.",
        "img-auth-streaming": "Taɣuri tamaɣlalt n « $1 ».",
        "allmessagesdefault": "Aḍris ameslugen",
        "allmessagescurrent": "Aḍris n tura",
        "allmessagestext": "Wagi d-umuɣ n inzan yestufan deg tallunt MediaWiki.\nẒeṛ [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] dɣa [https://translatewiki.net translatewiki.net] ma tebɣiḍ ad ɛiweneḍ i usideg imcettel n MediaWiki.",
-       "allmessagesnotsupportedDB": "'''{{ns:special}}:Allmessages''' ut yezmir ara ad yettuseqdac axaṭer '''$wgUseDatabaseMessages''' yettwakkes.",
+       "allmessages-not-supported-database": "'''{{ns:special}}:Allmessages''' ut yezmir ara ad yettuseqdac axaṭer '''$wgUseDatabaseMessages''' yettwakkes.",
        "allmessages-filter-legend": "Tastayt",
        "allmessages-filter": "Ṣeffi s addad n ubeddil :",
        "allmessages-filter-unmodified": "Ur yebeqqeḍ ara",
index d80fa5d..485daf5 100644 (file)
        "minoreditletter": "ش",
        "newpageletter": "ج",
        "boteditletter": "ب",
-       "number_of_watching_users_pageview": "[باقىلاعان $1 قاتىسۋشى]",
        "newsectionsummary": "/* $1 */ جاڭا ٴبولىم",
        "recentchangeslinked": "قاتىستى وزگەرىستەر",
        "recentchangeslinked-feed": "قاتىستى وزگەرىستەر",
        "allmessagesdefault": "ادەپكى ٴماتىنى",
        "allmessagescurrent": "اعىمدىق ٴماتىنى",
        "allmessagestext": "مىندا {{ns:mediawiki}} ەسىم اياسىندا جەتىمدى جۇيە حابار ٴتىزىمى بەرىلەدى.\nەگەر امبەباپ MediaWiki جەرسىندىرۋگە ۇلەس قوسقىڭىز كەلسە [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki جەرسىندىرۋ بەتىنە] جانە [https://translatewiki.net translatewiki.net جوباسىنا] بارىپ شىعىڭىز.",
-       "allmessagesnotsupportedDB": "'''$wgUseDatabaseMessages''' وشىرىلگەن سەبەبىنەن '''{{ns:special}}:AllMessages''' بەتى قولدانىلمايدى.",
+       "allmessages-not-supported-database": "!!FUZZY!!'''$wgUseDatabaseMessages''' وشىرىلگەن سەبەبىنەن '''{{ns:special}}:AllMessages''' بەتى قولدانىلمايدى.",
        "thumbnail-more": "ۇلكەيتۋ",
        "filemissing": "جوعالعان فايل",
        "thumbnail_error": "نوباي قۇرۋ قاتەسى: $1",
index 65e16d0..3d33aef 100644 (file)
        "minoreditletter": "ш",
        "newpageletter": "Ж",
        "boteditletter": "б",
-       "number_of_watching_users_pageview": "[бақылаған $1 қатысушы]",
        "rc-change-size-new": "Өңдеуден кейінгі көлемі: $1 {{PLURAL:$1|байт|байт}}",
        "newsectionsummary": "/* $1 */ жаңа бөлім",
        "rc-enhanced-expand": "Толық ақпаратты көрсету",
        "img-auth-nopathinfo": "PATH_INFO жоқ.\nБұл ақпаратты жөнелтуге сіздің серверіңіз келмейді.\nБұл мүмкін GGL-ге негізделген және img_auth қолдамайды. \nМына бетті қараңыз https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Түзетілген жүктеу каталогында сіз қалаған жол жоқ.",
        "img-auth-badtitle": "«$1» дегеннен жарамды атау құрай алмады.",
-       "img-auth-nologinnWL": "Сіз кірмегенсіз және «$1» ақтізімде жоқ.",
        "img-auth-nofile": "«$1» файлы жоқ.",
        "img-auth-isdir": "«$1» каталогына қатынауды байқап көрудесіз.\nТек файл қатынауы рұқсат етіледі.",
        "img-auth-streaming": "«$1» ағуда.",
        "allmessagesdefault": "Әдепкі мәтіні",
        "allmessagescurrent": "Ағымдық мәтіні",
        "allmessagestext": "Мында {{ns:mediawiki}} есім аясында жетімді жүйе хабар тізімі беріледі.\nЕгер әмбебап MediaWiki жерсіндіруге үлес қосқыңыз келсе [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki жерсіндіру бетіне] және [https://translatewiki.net translatewiki.net жобасына] барып шығыңыз.",
-       "allmessagesnotsupportedDB": "'''$wgUseDatabaseMessages''' өшірілген себебінен '''{{#special:AllMessages}}''' беті қолданылмайды.",
+       "allmessages-not-supported-database": "'''$wgUseDatabaseMessages''' өшірілген себебінен '''{{#special:AllMessages}}''' беті қолданылмайды.",
        "allmessages-filter-legend": "Сүзгі",
        "allmessages-filter": "Өзгеру статусы бойынша сүзгілеу",
        "allmessages-filter-unmodified": "Өзгертілмегендер",
index 9a1f6a8..b1ba914 100644 (file)
        "minoreditletter": "ş",
        "newpageletter": "J",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[baqılağan $1 qatıswşı]",
        "newsectionsummary": "/* $1 */ jaña bölim",
        "recentchangeslinked": "Qatıstı özgerister",
        "recentchangeslinked-feed": "Qatıstı özgerister",
        "allmessagesdefault": "Ädepki mätini",
        "allmessagescurrent": "Ağımdıq mätini",
        "allmessagestext": "Mında {{ns:mediawiki}} esim ayasında jetimdi jüýe xabar tizimi beriledi.\nEger ämbebap MediaWiki jersindirwge üles qosqıñız kelse [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki jersindirw betine] jäne [https://translatewiki.net translatewiki.net jobasına] barıp şığıñız.",
-       "allmessagesnotsupportedDB": "'''$wgUseDatabaseMessages''' öşirilgen sebebinen '''{{ns:special}}:AllMessages''' beti qoldanılmaýdı.",
+       "allmessages-not-supported-database": "!!FUZZY!!'''$wgUseDatabaseMessages''' öşirilgen sebebinen '''{{ns:special}}:AllMessages''' beti qoldanılmaýdı.",
        "thumbnail-more": "Ülkeýtw",
        "filemissing": "Joğalğan faýl",
        "thumbnail_error": "Nobaý qurw qatesi: $1",
index 3e8f3bb..370d98e 100644 (file)
        "rcfilters-filter-editsbyself-description": "ការរួមចំណែករបស់អ្នក។",
        "rcfilters-filter-editsbyother-label": "បន្លាស់ប្ដូរដែលអ្នកដទៃបានធ្វើ",
        "rcfilters-filter-editsbyother-description": "បន្លាស់ប្ដូរទាំងអស់ក្រៅពីបន្លាស់ប្ដូររបស់អ្នក។",
-       "rcfilters-filtergroup-userExpLevel": "ការចុះឈ្មោះអ្នកប្រើប្រាស់និងបទពិសោធន៍",
+       "rcfilters-filtergroup-user-experience-level": "ការចុះឈ្មោះអ្នកប្រើប្រាស់និងបទពិសោធន៍",
        "rcfilters-filter-user-experience-level-registered-label": "អ្នកចុះឈ្មោះហើយ",
        "rcfilters-filter-user-experience-level-registered-description": "អ្នកកែប្រែដែលបានកត់ឈ្មោះចូល។",
        "rcfilters-filter-user-experience-level-unregistered-label": "អ្នកមិនទាន់ចុះឈ្មោះ",
        "rcfilters-filter-categorization-description": "កំណត់ត្រាពីការបន្ថែមឬដកចេញទំព័រពីចំណាត់ថ្នាក់ក្រុម។",
        "rcfilters-filter-logactions-label": "កំណត់ត្រាសកម្មភាព",
        "rcfilters-filter-logactions-description": "សកម្មភាពរបស់អភិបាល ការបង្កើតគណនី ការលុបអត្ថបទចោល ការផ្ទុកឯកសារឡើង...",
-       "rcfilters-filtergroup-lastRevision": "កំណែថ្មីបំផុត",
+       "rcfilters-filtergroup-lastrevision": "កំណែថ្មីបំផុត",
        "rcfilters-filter-lastrevision-label": "កំណែថ្មីបំផុត",
        "rcfilters-filter-lastrevision-description": "បង្ហាញតែបន្លាស់ប្ដូរថ្មីៗបំផុតរបស់ទំព័រមួយ។",
        "rcfilters-filter-previousrevision-label": "មិនមែនកំណែថ្មីបំផុត",
        "minoreditletter": "តិច",
        "newpageletter": "ថ្មី",
        "boteditletter": "យន្ត",
-       "number_of_watching_users_pageview": "[មាន{{PLURAL:$1|អ្នកប្រើប្រាស់|អ្នកប្រើប្រាស់}}$1នាក់កំពុងមើល]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|បៃ|បៃ}} បន្ទាប់ពីបន្លាស់ប្ដូរ",
        "newsectionsummary": "/* $1 */ ផ្នែកថ្មី",
        "uploadstash-thumbnail": "មើលកូនរូបភាព",
        "img-auth-accessdenied": "ហាមចូល",
        "img-auth-badtitle": "មិនអាចបង្កើតចំណងជើងមានសុពលភាពពី \"$1\"។",
-       "img-auth-nologinnWL": "អ្នកមិនទាន់បានកត់ឈ្មោះចូល ហើយ \"$1\" មិនស្ថិតនៅក្នុងបញ្ជីស។",
        "img-auth-nofile": "គ្មានឯកសារឈ្មោះ \"$1\"ទេ។",
        "img-auth-noread": "អ្នកប្រើប្រាស់មិនមានសិទ្ធិចូលអាន \"$1\" ទេ។",
        "http-invalid-url": "URLមិនត្រឹមត្រូវ៖ $1",
        "allmessagesname": "ឈ្មោះ",
        "allmessagesdefault": "អត្ថបទលំនាំដើម",
        "allmessagescurrent": "អត្ថបទបច្ចុប្បន្ន",
-       "allmessagesnotsupportedDB": "ទំព័រនេះមិនអាចប្រើប្រាស់បានទេព្រោះ '''$wgUseDatabaseMessages''' ត្រូវបានបិទមិនឱ្យប្រើ។",
+       "allmessages-not-supported-database": "ទំព័រនេះមិនអាចប្រើប្រាស់បានទេព្រោះ '''$wgUseDatabaseMessages''' ត្រូវបានបិទមិនឱ្យប្រើ។",
        "allmessages-filter-legend": "តំរង",
        "allmessages-filter-unmodified": "មិន​បានកែសម្រួល",
        "allmessages-filter-all": "ទាំងអស់",
index 0dcd512..0dd9322 100644 (file)
        "minoreditletter": "ಚು",
        "newpageletter": "ಹೊ",
        "boteditletter": "ಬಾ",
-       "number_of_watching_users_pageview": "[$1 ವೀಕ್ಷಿಸುತ್ತಿರುವ {{PLURAL:$1|ಸದಸ್ಯ|ಸದಸ್ಯರು}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} ಬದಲಾವಣೆಯ ನಂತರ",
        "newsectionsummary": "/* $1 */ ಹೊಸ ವಿಭಾಗ",
        "rc-enhanced-expand": "ವಿವರಗಳನ್ನು ತೋರಿಸು",
index f6e8a3d..8fdb8ed 100644 (file)
        "tog-norollbackdiff": "되돌리기 후 차이를 보지 않기",
        "tog-useeditwarning": "바꾼 내용을 저장하지 않고 편집 페이지를 벗어날 때 내게 알리기",
        "tog-prefershttps": "로그인하는 동안 항상 보안 연결 사용",
-       "tog-showrollbackconfirmation": "롤백 ë§\81í\81¬ë¥¼ í\81´ë¦­í\95  ë\95\8c í\99\95ì\9d¸ í\94\84롬í\94\84í\8a¸ë¥¼ í\91\9cì\8b\9cí\95©ë\8b\88ë\8b¤",
+       "tog-showrollbackconfirmation": "ë\90\98ë\8f\8c리기 ë§\81í\81¬ë¥¼ í\81´ë¦­í\95  ë\95\8c í\99\95ì\9d¸ì°½ì\9d\84 í\91\9cì\8b\9c",
        "underline-always": "항상",
        "underline-never": "항상 긋지 않기",
        "underline-default": "스킨 또는 브라우저 기본값",
        "badretype": "입력한 비밀번호가 일치하지 않습니다.",
        "usernameinprogress": "이 사용자 이름에 대한 계정 생성이 이미 시작되었습니다. 기다려 주세요.",
        "userexists": "입력한 사용자 계정 이름이 이미 사용되고 있습니다.\n다른 이름을 선택하세요.",
+       "createacct-normalization": "당신의 사용자 이름은 기술적 한계로 인해 $2(으)로 조정됩니다.",
        "loginerror": "로그인 오류",
        "createacct-error": "계정 만들기 오류",
        "createaccounterror": "계정을 만들 수 없습니다: $1",
        "accmailtext": "[[User talk:$1|$1]]님의 비밀번호를 임의로 만들어 $2(으)로 보냈습니다. 로그인하고 나서 <em>[[Special:ChangePassword|비밀번호를 바꿀]]</em> 수 있습니다.",
        "newarticle": "(새 문서)",
        "newarticletext": "아직 없는 문서의 링크를 따라왔습니다.\n새 문서를 만들려면 아래 상자에 내용을 입력하면 됩니다. (자세한 내용은 [$1 도움말 문서]를 참조하세요)\n만약 잘못 찾아왔다면, 브라우저의 '''뒤로''' 버튼을 눌러 주세요.",
-       "anontalkpagetext": "----\n여기는 계정을 만들지 않았거나 사용하고 있지 않은 익명 사용자를 위한 토론 문서입니다. 익명 사용자를 구별하기 위해서는 숫자로 된 IP 주소를 사용해야만 합니다. IP 주소는 여러 사람이 공유할 수 있습니다. 자신과 관계없는 의견이 남겨져 있어 불쾌하다는 생각이 든다면 [[Special:CreateAccount|계정을 만들고]] [[Special:UserLogin|로그인해서]] 다른 사용자들에게 줄 혼란을 줄일 수 있습니다.",
+       "anontalkpagetext": "----\n<em>여기는 계정을 만들지 않았거나 사용하고 있지 않은 익명 사용자를 위한 토론 문서입니다.</em> 익명 사용자를 구별하기 위해서는 숫자로 된 IP 주소를 사용해야만 합니다. IP 주소는 여러 사람이 공유할 수 있습니다. 자신과 관계없는 의견이 남겨져 있어 불쾌하다는 생각이 든다면 [[Special:CreateAccount|계정을 만들거나]] [[Special:UserLogin|로그인해서]] 다른 사용자들에게 줄 혼란을 줄일 수 있습니다.",
        "noarticletext": "이 문서가 현재 존재하지 않습니다.\n이 문서와 제목이 비슷한 문서가 있는지 [[Special:Search/{{PAGENAME}}|검색하거나]],\n이 문서에 관련된 <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 기록]을 확인하거나,\n문서를 직접 [{{fullurl:{{FULLPAGENAME}}|action=edit}} 생성]</span>할 수 있습니다.",
        "noarticletext-nopermission": "이 문서가 현재 존재하지 않습니다.\n이 문서와 제목이 비슷한 문서가 있는지 [[Special:Search/{{PAGENAME}}|검색하거나]], 이 문서에 관련된 <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 기록]을 확인할 수 있습니다.</span> 그러나 이 문서를 만들 수 있는 권한은 없습니다.",
        "missing-revision": "\"{{FULLPAGENAME}}\"이라는 문서의 #$1판이 존재하지 않습니다.\n\n이 문제는 주로 삭제된 문서를 가리키는 오래된 문서 역사 링크로 인해 발생합니다.\n자세한 내용은 [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 삭제 기록]에서 확인할 수 있습니다.",
        "page_first": "처음",
        "page_last": "마지막",
        "histlegend": "차이 선택: 비교하려는 판의 라디오 상자를 선택한 다음 엔터나 아래의 버튼을 누르세요.<br />\n설명: <strong>({{int:cur}})</strong> = 최신 판과 비교, <strong>({{int:last}})</strong> = 이전 판과 비교, <strong>{{int:minoreditletter}}</strong>= 사소한 편집",
-       "history-fieldset-title": "특정판 검색",
+       "history-fieldset-title": "특정판 필터링",
        "history-show-deleted": "특정판이 삭제된 것만",
        "histfirst": "오래됨",
        "histlast": "최신",
        "historysize": "({{PLURAL:$1|1 바이트|$1 바이트}})",
-       "historyempty": "(비었음)",
+       "historyempty": "비었음",
        "history-feed-title": "편집 역사",
        "history-feed-description": "이 문서의 편집 역사",
        "history-feed-item-nocomment": "$2에 $1님의 편집",
        "gender-unknown": "언급할 때 소프트웨어는 가능한 항상 중성적인 단어를 사용합니다.",
        "gender-male": "남성이 위키 문서를 편집합니다.",
        "gender-female": "여성이 위키 문서를 편집합니다.",
-       "prefs-help-gender": "이 환경 설정은 선택 사항입니다.\n소프트웨어는 적절한 성별 문법을 사용하여 다른 사용자에게 당신을 언급하는 것을 해결하기 위해 사용됩니다.\n이 정보는 공개됩니다.",
+       "prefs-help-gender": "이 환경 설정은 선택 사항입니다.\n소프트웨어가 적절한 성별 문법으로 당신을 호칭하고 타인에게 당신을 언급하기 위해 사용됩니다.\n이 정보는 공개됩니다.",
        "email": "이메일",
        "prefs-help-realname": "실명은 선택 사항입니다.\n실명을 입력하면 당신의 기여에 대한 저작자 표시에 쓰이게 될 수 있습니다.",
        "prefs-help-email": "이메일 주소 입력은 선택 사항입니다. 다만 비밀번호를 잊었을 때 비밀번호를 재설정하기 위해 필요합니다.",
        "right-reupload-own": "자신이 이미 올린 파일 덮어쓰기",
        "right-reupload-shared": "공용의 파일을 무시하고 로컬에서 파일 올리기",
        "right-upload_by_url": "URL 주소에서 파일 올리기",
-       "right-purge": "확인 없이 문서의 캐시를 새로 고침",
+       "right-purge": "문서의 사이트 캐시를 새로 고침",
        "right-autoconfirmed": "IP 기반의 속도 제한에 영향을 받지 않음",
        "right-bot": "봇의 편집으로 취급",
        "right-nominornewtalk": "토론 문서에서 사소한 편집으로 새 메시지 알림을 보내지 않기",
        "action-changetags": "문서의 특정 판과 특정 기록 항목에 임의의 태그를 추가하거나 제거하기",
        "action-deletechangetags": "데이터베이스에서 태그를 지우기",
        "action-purge": "이 문서 새로 고침",
+       "action-editinterface": "사용자 인터페이스 문서 편집",
+       "action-editusercss": "다른 사용자의 CSS 파일 편집",
+       "action-edituserjson": "다른 사용자의 JSON 파일 편집",
+       "action-edituserjs": "다른 사용자의 자바스크립트 파일 편집",
+       "action-editsitecss": "사이트 CSS 편집",
+       "action-editsitejson": "사이트 JSON 편집",
+       "action-editsitejs": "사이트 자바스크립트 편집",
+       "action-editmyusercss": "자신의 사용자 CSS 파일 편집하기",
+       "action-editmyuserjson": "자신의 사용자 JSON 파일 편집하기",
+       "action-editmyuserjs": "자신의 사용자 자바스크립트 파일 편집하기",
+       "action-viewsuppressed": "어떤 사용자도 보지 못하도록 감춰진 판 보기",
+       "action-unblockself": "자신을 차단 해제하기",
        "nchanges": "$1개 {{PLURAL:$1|바뀜}}",
        "enhancedrc-since-last-visit": "{{PLURAL:$1|마지막 방문 이후}} $1개",
        "enhancedrc-history": "역사",
        "rcfilters-savedqueries-already-saved": "이 필터는 이미 저장되어 있습니다. 새로운 저장된 필터를 만들려면 설정을 변경하십시오.",
        "rcfilters-restore-default-filters": "기본 필터로 복구",
        "rcfilters-clear-all-filters": "필터 모두 지우기",
-       "rcfilters-show-new-changes": "최신 변경사항 보기",
+       "rcfilters-show-new-changes": "$1 이후 새 변경사항 보기",
        "rcfilters-search-placeholder": "필터 변경(메뉴를 사용하거나 필터 이름을 검색하세요)",
        "rcfilters-invalid-filter": "유효하지 않은 필터",
        "rcfilters-empty-filter": "활성화된 필터가 없습니다. 모든 기여가 표시됩니다.",
        "rcfilters-filter-editsbyself-description": "당신의 기여.",
        "rcfilters-filter-editsbyother-label": "다른 사용자의 변경사항",
        "rcfilters-filter-editsbyother-description": "나 이외의 모든 변경사항.",
-       "rcfilters-filtergroup-userExpLevel": "사용자 등록 및 경험",
+       "rcfilters-filtergroup-user-experience-level": "사용자 등록 및 경험",
        "rcfilters-filter-user-experience-level-registered-label": "등록됨",
        "rcfilters-filter-user-experience-level-registered-description": "로그인한 편집자.",
        "rcfilters-filter-user-experience-level-unregistered-label": "등록 안 됨",
        "rcfilters-hideminor-conflicts-typeofchange-global": "특정한 유형의 변경사항을 \"사소한 편집\"으로 지정할 수 없기 때문에 \"사소한 편집\" 필터는 하나 이상의 변경사항 유형 필터와 충돌합니다. 충돌되는 필터들은 위의 사용 중인 필터 영역에 표시됩니다.",
        "rcfilters-hideminor-conflicts-typeofchange": "특정한 종류의 변경사항은 \"사소한 편집\"으로 지정할 수 없으므로 이 필터는 다음 유형의 변경사항 필터와 충돌합니다: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "이 유형의 변경사항 필터는 \"사소한 편집\" 필터와 충돌합니다. 특정한 종류의 변경사항은 \"사소한 편집\"으로 지정할 수 없습니다.",
-       "rcfilters-filtergroup-lastRevision": "최신판",
+       "rcfilters-filtergroup-lastrevision": "최신판",
        "rcfilters-filter-lastrevision-label": "최신판",
        "rcfilters-filter-lastrevision-description": "문서의 가장 최근 바뀜만.",
        "rcfilters-filter-previousrevision-label": "최신판이 아님",
        "minoreditletter": "잔글",
        "newpageletter": "새글",
        "boteditletter": "봇",
-       "number_of_watching_users_pageview": "[{{PLURAL:$1|사용자}} $1명이 주시하고 있음]",
        "rc-change-size-new": "바꾼 후 $1 {{PLURAL:$1|바이트}}",
        "newsectionsummary": "/* $1 */ 새 문단",
        "rc-enhanced-expand": "자세한 내용 보기",
        "img-auth-nopathinfo": "경로 정보가 없습니다.\n서버가 REQUEST_URI 및 PATH_INFO 변수를 넘길 수 있도록 설정되어야 합니다.\n이러한 경우 $wgUsePathInfo를 활성화해 보십시오.\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization 를 참고하십시오.",
        "img-auth-notindir": "요청한 경로가 설정한 올리기 디렉터리에 없습니다.",
        "img-auth-badtitle": "\"$1\"에서 올바른 제목을 만들 수 없습니다.",
-       "img-auth-nologinnWL": "로그인하지 않았으며 \"$1\" 파일은 화이트리스트에 존재하지 않습니다.",
        "img-auth-nofile": "\"$1\" 파일이 없습니다.",
        "img-auth-isdir": "\"$1\" 디렉터리에 접근을 시도했습니다.\n파일에만 접근할 수 있습니다.",
        "img-auth-streaming": "\"$1\" 파일을 전송하는 중입니다.",
        "delete-confirm": "\"$1\" 삭제",
        "delete-legend": "삭제",
        "historywarning": "<strong>경고:</strong> 삭제하려고 하는 문서에 {{PLURAL:$1|판}} $1개의 역사가 있습니다:",
-       "historyaction-submit": "보이기",
+       "historyaction-submit": "판 보이기",
        "confirmdeletetext": "문서와 문서 역사를 삭제하려고 합니다.\n삭제하려는 문서가 맞는지, 이 문서를 삭제하는 것이 [[{{MediaWiki:Policy-url}}|정책]]에 맞는 행동인지를 확인해 주세요.",
        "actioncomplete": "동작 완료",
        "actionfailed": "명령 실패",
        "deleting-backlinks-warning": "<strong>경고:</strong> 삭제하려는 문서가 [[Special:WhatLinksHere/{{FULLPAGENAME}}|다른 문서]]에 링크되어 있거나 끼워져 있습니다.",
        "deleting-subpages-warning": "<strong>경고:</strong> 삭제하려는 문서에 [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|하나의 하위 문서|$1개의 하위 문서|51=50개 이상의 하위 문서}}]]가 있습니다.",
        "rollback": "편집 되돌리기",
+       "rollback-confirmation-confirm": "확인해 주십시오:",
+       "rollback-confirmation-yes": "되돌리기",
+       "rollback-confirmation-no": "취소",
        "rollbacklink": "되돌리기",
        "rollbacklinkcount": "{{PLURAL:$1|편집}} $1회 되돌리기",
        "rollbacklinkcount-morethan": "{{PLURAL:$1|편집}} $1회 이상 되돌리기",
        "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-notify": "$1의 편집을 되돌렸습니다.\n$2의 마지막 판으로 바뀌었습니다. [$3 차이 보기]",
        "sessionfailure-title": "세션 실패",
        "sessionfailure": "로그인 세션에 문제가 발생한 것 같습니다.\n세션 하이재킹을 막기 위해 동작이 취소되었습니다.\n양식을 다시 제출해 주십시오.",
        "changecontentmodel": "문서의 콘텐츠 모델을 변경",
        "mycontris": "기여",
        "anoncontribs": "기여",
        "contribsub2": "{{GENDER:$3|$1}}($2)의 기여",
+       "contributions-subtitle": "{{GENDER:$3|$1}}의 기여",
        "contributions-userdoesnotexist": "\"$1\" 사용자 계정은 등록되어 있지 않습니다.",
        "nocontribs": "지정한 조건과 일치하는 바뀜을 찾을 수 없습니다.",
        "uctop": "최신",
        "blocklist-userblocks": "계정에 대한 차단 숨기기",
        "blocklist-tempblocks": "기한이 정해진 차단을 숨기기",
        "blocklist-addressblocks": "단일 IP 차단을 숨기기",
+       "blocklist-type": "유형:",
+       "blocklist-type-opt-all": "모두",
+       "blocklist-type-opt-sitewide": "사이트 전체",
+       "blocklist-type-opt-partial": "부분",
        "blocklist-rangeblocks": "광역 차단을 숨기기",
        "blocklist-timestamp": "시간 기록",
        "blocklist-target": "대상",
        "blocklist-editing-page": "문서",
        "blocklist-editing-ns": "이름공간",
        "ipblocklist-empty": "차단 목록이 비어 있습니다.",
-       "ipblocklist-no-results": "요청한 IP 주소나 사용자는 차단되지 않았습니다.",
+       "ipblocklist-no-results": "요청한 IP 주소나 사용자 이름과 일치하는 차단을 찾을 수 없습니다.",
        "blocklink": "차단",
        "unblocklink": "차단 해제",
        "change-blocklink": "차단 설정 바꾸기",
+       "empty-username": "(사용 가능한 사용자 이름 없음)",
        "contribslink": "기여",
        "emaillink": "이메일 보내기",
        "autoblocker": "당신의 IP 주소는 최근에 \"[[User:$1|$1]]\"님이 사용하였기 때문에 자동으로 차단되었습니다.\n$1님이 차단된 이유는 다음과 같습니다: \"$2\"",
        "allmessagesdefault": "기본 메시지 글",
        "allmessagescurrent": "현재 문자열",
        "allmessagestext": "미디어위키 이름공간에 있는 모든 시스템 메시지의 목록입니다.\n미디어위키의 번역 작업에 관심이 있으면 [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation 미디어위키 지역화]나 [https://translatewiki.net translatewiki.net]에 참가해주세요.",
-       "allmessagesnotsupportedDB": "'''$wgUseDatabaseMessages'''가 비활성화되어 있어서 이 문서를 사용할 수 없습니다.",
+       "allmessages-not-supported-database": "'''$wgUseDatabaseMessages'''가 비활성화되어 있어서 이 문서를 사용할 수 없습니다.",
        "allmessages-filter-legend": "필터",
        "allmessages-filter": "수정 상태로 거르기:",
        "allmessages-filter-unmodified": "수정되지 않음",
        "confirmemail_body_set": "당신일 수도 있는 $1 IP 주소를 사용하는 사용자가\n{{SITENAME}}의 \"$2\" 계정의 이메일 주소를 지정하였습니다.\n\n이 계정이 당신의 계정이고 {{SITENAME}}에서 이메일 기능을\n활성화하려면 아래 주소를 열어서 이메일 인증을 해 주세요:\n\n$3\n\n당신의 계정이 아니라면,\n이메일 인증 신청을 취소하기 위해 아래의 주소를 열어주세요:\n\n$5\n\n인증 코드는 $4에 만료됩니다.",
        "confirmemail_invalidated": "이메일 확인이 취소됨",
        "invalidateemail": "이메일 확인 취소",
-       "notificationemail_subject_changed": "{{SITENAME}}ì\9d\98 등록된 이메일 주소가 변경되었습니다",
-       "notificationemail_subject_removed": "{{SITENAME}}ì\9d\98 등록된 이메일 주소가 제거되었습니다",
+       "notificationemail_subject_changed": "{{SITENAME}}ì\97\90 등록된 이메일 주소가 변경되었습니다",
+       "notificationemail_subject_removed": "{{SITENAME}}ì\97\90 등록된 이메일 주소가 제거되었습니다",
        "notificationemail_body_changed": "당신일 수도 있는 IP 주소 $1에 속하는 사용자가\n{{SITENAME}}의 사용자 \"$2\" 계정의 이메일 주소를 \"$3\"(으)로 바꾸었습니다.\n\n지금 이 글을 보고 계신 사용자로 추정되지만 만약 본인이 아닌 경우, 지금 바로 사이트 관리자에게 문의하십시오.",
        "notificationemail_body_removed": "당신일 수도 있는 IP 주소 $1에 속하는 사용자가 {{SITENAME}}의 사용자 \"$2\" 계정의 이메일 주소를 제거하였습니다.\n\n지금 이 글을 보고 계신 사용자로 추정되지만 만약 본인이 아닌 경우, 지금 바로 사이트 관리자에게 문의하십시오.",
        "scarytranscludedisabled": "[인터위키가 비활성되어 있습니다]",
        "passwordpolicies-policy-passwordnotinlargeblacklist": "비밀번호는 가장 흔히 쓰이는 비밀번호 100,000개 목록에 속할 수 없습니다.",
        "passwordpolicies-policyflag-suggestchangeonlogin": "로그인할 때 변경 제안",
        "easydeflate-invaliddeflate": "주어진 컨텐츠가 적절히 압축되지 않았습니다",
-       "unprotected-js": "보안 상의 이유로 자바스크립트는 보호되지 않은 문서로부터 불러올 수 없습니다. 미디어위키: 이름공간이나 사용자의 하위 문서에서만 자바스크립트를 만들어 주십시오."
+       "unprotected-js": "보안 상의 이유로 자바스크립트는 보호되지 않은 문서로부터 불러올 수 없습니다. 미디어위키: 이름공간이나 사용자의 하위 문서에서만 자바스크립트를 만들어 주십시오.",
+       "userlogout-continue": "로그아웃하려면 [$1 페이지 로그아웃 문서로 이동하십시오].",
+       "userlogout-sessionerror": "세션 오류로 인해 로그아웃을 실패했습니다. [$1 다시 시도]해 주십시오."
 }
index a7fc11b..8243fe5 100644 (file)
        "minoreditletter": "г",
        "newpageletter": "Дж",
        "boteditletter": "б",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|кёзюнде тутуучу къошулуучу}}]",
        "rc-change-size": "$1",
        "rc-change-size-new": "Тюрлениуден сора ёлчеми: $1 {{PLURAL:$1|байт}}",
        "newsectionsummary": "/* $1 */ Джангы бёлюм",
        "img-auth-nopathinfo": "<code>PATH_INFO</code> джокъду.\nСерверигиз бу билгилени джиберир ючюн джарашмагъанды.\nCGI тамалында ишлерге эмда <code>img_auth</code> бла ишлемезге болур.\nКъарагъыз: https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Изленнген джол джюклениулени папкасы бла байламлы тюлдю.",
        "img-auth-badtitle": "«$1» бла джараулу башлыкъ этилмейди.",
-       "img-auth-nologinnWL": "Сиз системагъа кирмедигиз, эмда «$1» акъ тизмеде тюлдю.",
        "img-auth-nofile": "«$1» файл джокъду.",
        "img-auth-isdir": "«$1» каталогга кирирге излейсиз.\nКъуру файллагъа кирирге эркинлик барды.",
        "img-auth-streaming": "«$1» ырхы бериу",
        "allmessagesdefault": "Оригинал текст",
        "allmessagescurrent": "Хайырлана тургъан текст",
        "allmessagestext": "Бу тизме MediaWiki ат аламында бар болгъан система билдириулени тизмесиди.\nMediaWiki локализациясына юлюш къошаргъа излей эсегиз, [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki локализация] бла [https://translatewiki.net translatewiki.net] сайтлагъа киригиз.",
-       "allmessagesnotsupportedDB": "'''$wgUseDatabaseMessages''' джабыкъ болгъаны ючюн '''{{ns:special}}:Allmessages''' хайырланыугъа ачыкъ тюлдю.",
+       "allmessages-not-supported-database": "'''$wgUseDatabaseMessages''' джабыкъ болгъаны ючюн '''{{ns:special}}:Allmessages''' хайырланыугъа ачыкъ тюлдю.",
        "allmessages-filter-legend": "Фильтр",
        "allmessages-filter": "Тюрлендириуюне кёре фильтрлендир:",
        "allmessages-filter-unmodified": "Тюрлендирилмеген",
index a3792e8..1f89c96 100644 (file)
        "newpageletter": "N",
        "boteditletter": "B",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[{{PLURAL:$1|eine|$1|kein}} Oppasser]",
        "rc-change-size": "$1 {{PLURAL:$1|Byte|Bytes}}",
        "rc-change-size-new": "$1 {{PLURAL:$1|Byte|Bytes|Bytes}} noh dem Ändere",
        "newsectionsummary": "Neuje Afschnet /* $1 */",
        "img-auth-nopathinfo": "De <code xml:lang=\"en\" lang=\"en\" dir=\"rtl\">PATH_INFO</code> fäält.\nDä Webßööver es nit doför ennjerescht, di Ennfommazjuhn wigger ze jävve.\nHä künnd_op <code xml:lang=\"en\" lang=\"en\" dir=\"rtl\">CGI</code> opjebout sin, un dröm <code xml:lang=\"en\" lang=\"en\" dir=\"rtl\">img_auth</code> nit ongschtöze künne. Loor em [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization Handbohch] noh, wat domed es.",
        "img-auth-notindir": "Dä aanjefroochte Pat is nit em enjeschtallte Verzeischneß för et Huhlaade.",
        "img-auth-badtitle": "Uß „$1“ löht sesch kein jöltijje Övverschreff maache.",
-       "img-auth-nologinnWL": "Do bes nit ennjelogg, un „$1“ es nit op dä Leß met de zohjelohße Datteiname.",
        "img-auth-nofile": "En Dattei „$1“ jidd_et nit.",
        "img-auth-isdir": "Do wells op et Verzeishneß „$1“ zohjriife, ävver mer darref bloß op Datteie zohjriife.",
        "img-auth-streaming": "Mer sin „$1“ aam schecke.",
        "revertpage": "Änderunge vun däm Metmaacher „[[Special:Contributions/$2|$2]]“ ([[User talk:$2|däm sing Klaafsigg]]) fottjeschmeße, un doför de lätzde Väsjohn vum „[[User:$1|$1]]“ widder zeröckjehollt",
        "revertpage-nouser": "Änderunge vun enem Metmaacher, däm singe Name vershtoche es, retuur jemaat op de letzte Version {{GENDER:$1|vum|vum|vumm Metmaacher|vun dä|vum}} [[User:$1|$1]]",
        "rollback-success": "De Änderungen vum $1 zeröckjenumme, un dobei de letzte Version vum $2 widder jehollt.",
-       "rollback-success-notify": "Änderonge {{GENDER:$1|vum|vum|vumm Metmaacher|vun dä|vum}} „$1“ sin zerök jenumme un di Sigg es op der Schtand vun doför {{GENDER:$2|vum|vum|vumm Metmaacher|vun dä|vum}} „$2“ jesaz. [$3 Belohr, wat derbeij veränndert wood]",
        "sessionfailure-title": "Fähler met dä Daate vum Enlogge",
        "sessionfailure": "Et jov wall e täschnesch Problehm met Dingem Login. Dröm ham_mer dat us Vörseesch jäz nix jemaht, domet mer nit velleich Ding Änderong däm verkihrte Metmaacher ongerjubele. Jangk zeröck un versöhk et noch ens.",
        "changecontentmodel": "Et Modäll vum Ennhald vun ene Sigg verändere",
        "allmessagesdefault": "Dä standaadmäßije Tex",
        "allmessagescurrent": "Esu es dä Tex jetz",
        "allmessagestext": "Heh kütt en Liss met Texte, Texstöck, un Nohreechte em Appachtemeng „MediaWiki“ — Do draan Ändere löht et Wiki anders ußsin, dat darf dröm nit Jede maache.\nWenn De jenerell aan [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki singe Översezung] jet anders han wells, do jangk noh [https://translatewiki.net translatewiki.net].",
-       "allmessagesnotsupportedDB": "<strong>Dat wor nix!</strong> Mer künne „{{#special:allmessages}}“ nit zeije, <code>$wgUseDatabaseMessages</code> es usjeschalt!",
+       "allmessages-not-supported-database": "<strong>Dat wor nix!</strong> Mer künne „{{#special:allmessages}}“ nit zeije, <code>$wgUseDatabaseMessages</code> es usjeschalt!",
        "allmessages-filter-legend": "Ußsöhke — wat för en Täxte o Nohreeshte aazeije?",
        "allmessages-filter": "Zohshtand:",
        "allmessages-filter-unmodified": "nit jeändert",
index 574636f..af92424 100644 (file)
        "minoreditletter": "B",
        "newpageletter": "Nû",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[{{PLURAL:$1|bikarhênerek|$1 bikarhêner}} vê rûpelê {{PLURAL:$1|dişopîne|dişopînin}}.]",
        "rc-change-size-new": "Piştî guhertinê $1 {{PLURAL:$1|bayt}}",
        "newsectionsummary": "/* $1 */ beşeke nû",
        "rc-enhanced-expand": "Hûragahiyan nîşan bide",
        "allmessagesname": "Nav",
        "allmessagescurrent": "Nivîsa niha",
        "allmessagestext": "Lîsteya hemû peyamên MediaWikiyê.",
-       "allmessagesnotsupportedDB": "'''{{ns:special}}:Allmessages''' nikare were bikaranîn ji ber ku '''$wgUseDatabaseMessages''' hatiye jêbirin.",
+       "allmessages-not-supported-database": "'''{{ns:special}}:Allmessages''' nikare were bikaranîn ji ber ku '''$wgUseDatabaseMessages''' hatiye jêbirin.",
        "allmessages-filter-legend": "Parzûn",
        "allmessages-filter-unmodified": "Neguhertî",
        "allmessages-filter-all": "Hemû",
index 6cdee09..848847b 100644 (file)
        "page_first": "биринчи",
        "page_last": "ахырынчы",
        "histlegend": "Тюзлевлерден сайлав: тенглешдирмеге сюеген бары тюрлерин белгилеп '''{{int:compare-submit}}''' бас.<br />\nАчыкълавлар: '''({{int:cur}})''' — гьалиги тюрюнден башгъалыкъ; '''({{int:last}})''' — алдагъы тюрюнден башгъалыкъ; '''{{int:minoreditletter}}''' — увакъ тюзелтив.",
-       "history-fieldset-title": "Тюзлевлеге излев",
+       "history-fieldset-title": "Тюзлев сюзгюч",
        "histfirst": "инг эсгилер",
        "histlast": "инг янгылар",
-       "historyempty": "(бош)",
+       "historyempty": "бош",
        "history-feed-title": "Тюзлевлер тарихи",
        "history-feed-description": "Бу сагьифаны викиде тюзлев тарихи",
        "history-feed-item-nocomment": "$1 $2 заманда",
        "watchlist-options": "Тергев тизмени кюйлевлери",
        "enotif_reset": "Бары да сагьифаланы къаралгъандай белгилемек",
        "dellogpage": "Тайдырыв гюнделиги",
+       "rollback-confirmation-no": "Гери алмакъ",
        "rollbacklink": "гери алмакъ",
        "rollbacklinkcount": "$1 {{PLURAL:$1|тюзлевню}} къайтармакъ",
        "protectlogpage": "Якълав гюнделиги",
index e2a5c64..e886728 100644 (file)
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "a",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|usor observans|usores observantes}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|octetus|octeti}} post recensionem",
        "newsectionsummary": "/* $1 */ nova pars",
        "rc-enhanced-expand": "Minima monstrare",
        "allmessagesdefault": "Textus originalis nuntii",
        "allmessagescurrent": "Textus recens nuntii",
        "allmessagestext": "Hic est index omnium nuntiorum in MediaWiki.",
-       "allmessagesnotsupportedDB": "Haec pagina non adhiberi potest, quia '''$wgUseDatabaseMessages''' non iam agitur.",
+       "allmessages-not-supported-database": "Haec pagina non adhiberi potest, quia '''$wgUseDatabaseMessages''' non iam agitur.",
        "allmessages-filter-legend": "Filtrum",
        "allmessages-filter-all": "Omnia",
        "allmessages-language": "Lingua:",
index 5d1ece3..e8b26fc 100644 (file)
        "page_first": "éischt",
        "page_last": "lescht",
        "histlegend": "Fir d'Ännerungen unzeweisen: Klickt déi zwou Versiounen un, déi solle verglach ginn.<br />\n*(aktuell) = Ënnerscheed mat der aktueller Versioun,\n*(lescht) = Ënnerscheed mat der aler Versioun,\n*k = Kleng Ännerung.",
-       "history-fieldset-title": "No Versioune sichen",
+       "history-fieldset-title": "Versioune filteren",
        "history-show-deleted": "Nëmme geläscht Versiounen",
        "histfirst": "eelst",
        "histlast": "neist",
        "historysize": "({{PLURAL:$1|1 Byte|$1 Byten}})",
-       "historyempty": "(eidel)",
+       "historyempty": "eidel",
        "history-feed-title": "Historique vun de Versiounen",
        "history-feed-description": "Versiounshistorique fir dës Säit op der Wiki",
        "history-feed-item-nocomment": "$1 ëm $2",
        "right-reupload-own": "E Fichier iwwerschreiwen deen Dir selwer eropgelueden hutt",
        "right-reupload-shared": "Lokalt Iwwerschreiwe vun engem Fichier deen an engem gemeinsam benotzte Repertoire steet",
        "right-upload_by_url": "Fichiere vun enger URL-Adress eroplueden",
-       "right-purge": "De Säitecache eidel maachen ouni nozefroen",
+       "right-purge": "De Säitecache fir eng Säit eidel maachen",
        "right-autoconfirmed": "Net betraff vun IP-baséierten Zäitlimiten",
        "right-bot": "Als automatesche Prozess behandelen (Bot)",
        "right-nominornewtalk": "Kleng Ännerungen op Diskussiounssäite léisen de Banner vun de neie Messagen net aus",
        "rcfilters-savedqueries-already-saved": "Dës Filtere si scho gespäichert. Ännert Är Astellunge fir en neie Gespäicherte Filter unzeleeën.",
        "rcfilters-restore-default-filters": "Standardfiltere restauréieren",
        "rcfilters-clear-all-filters": "All Filteren eidelmaachen",
-       "rcfilters-show-new-changes": "Rezentst Ännerunge weisen",
+       "rcfilters-show-new-changes": "Nei Ännerungen zanter $1 weisen",
        "rcfilters-search-placeholder": "Ännerunge filteren (benotzt de Menü oder sicht nom Numm vum Filter)",
        "rcfilters-invalid-filter": "Net valabele Filter",
        "rcfilters-empty-filter": "Keen aktive Filter. All Kontributioune gi gewisen.",
        "rcfilters-filter-editsbyself-description": "Är eegen Ännerungen.",
        "rcfilters-filter-editsbyother-label": "Ännerunge vun Aneren",
        "rcfilters-filter-editsbyother-description": "All Ännerunge ausser Ären eegenen.",
-       "rcfilters-filtergroup-userExpLevel": "Umeldung an Erfarung vu Benotzer",
+       "rcfilters-filtergroup-user-experience-level": "Umeldung an Erfarung vu Benotzer",
        "rcfilters-filter-user-experience-level-registered-label": "Ugemellt",
        "rcfilters-filter-user-experience-level-registered-description": "Ageloggt Auteuren.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Net-ugemellt",
        "rcfilters-filter-logactions-label": "Protokolléiert Aktiounen",
        "rcfilters-filter-logactions-description": "Administrativ Aktiounen, Uleeë vu Benotzerkonten, Läsche vu Säiten, Eropgeluede Fichieren, ...",
        "rcfilters-hideminor-conflicts-typeofchange": "Verschidden Type vu Ännerunge kënnen net als \"kleng\" markéiert ginn, dofir ass dëse Filter a Konflikt mat dësem Typ vun Ännerungsfilteren: $1",
-       "rcfilters-filtergroup-lastRevision": "Lescht Versiounen",
+       "rcfilters-filtergroup-lastrevision": "Lescht Versiounen",
        "rcfilters-filter-lastrevision-label": "Lescht Versioun",
        "rcfilters-filter-lastrevision-description": "Nëmmen déi lescht Ännerung op enger Säit.",
        "rcfilters-filter-previousrevision-label": "Net déi lescht Versioun",
        "minoreditletter": "k",
        "newpageletter": "N",
        "boteditletter": "B",
-       "number_of_watching_users_pageview": "[$1 Benotzer {{PLURAL:$1|iwwerwaacht|iwwerwaachen}}]",
        "rc-change-size": "$1 {{PLURAL:$1|Byte|Bytes}}",
        "rc-change-size-new": "$1 {{PLURAL:$1|Byte|Bytes}} no der Ännerung",
        "newsectionsummary": "Neien Abschnitt /* $1 */",
        "img-auth-nopathinfo": "PATH_INFO feelt.\nÄre Server ass net agestallt fir déi Informatioun weiderzeginn.\nEt kann u CGI leien an datt imag_auth net ënnerstëtzt gëtt.\nKuckt https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization",
        "img-auth-notindir": "De gefrote Pad ass net am Upload-Repertoire agestallt.",
        "img-auth-badtitle": "Aus \"$1\" ka kee valabelen Titel gemaach ginn.",
-       "img-auth-nologinnWL": "Dir sidd net ageloggt a(n) \"$1\" ass net op der Wäisser Lëscht.",
        "img-auth-nofile": "De Fichier \"$1\" gëtt et net.",
        "img-auth-isdir": "Dir versicht op de Repertoire \"$1\" zouzegräifen.\nNèemmen Datenofruff ass erlaabt.",
        "img-auth-streaming": "\"$1\" lueden.",
        "delete-confirm": "Läsche vu(n) \"$1\"",
        "delete-legend": "Läschen",
        "historywarning": "<strong>Opgepasst:</strong> D'Säit déi Dir läsche wëllt huet en Historique mat $1 {{PLURAL:$1|Versioun|Versiounen}}:",
-       "historyaction-submit": "Weisen",
+       "historyaction-submit": "Versioune weisen",
        "confirmdeletetext": "Dir sidd am Gaang, eng Säit mat hirem kompletten Historique vollstänneg aus der Datebank ze läschen.\nW.e.g. confirméiert, datt Dir dëst wierklech wëllt, datt Dir d'Konsequenze verstitt, an datt dat Ganzt am Aklang mat de [[{{MediaWiki:Policy-url}}|Richtlinne]] geschitt.",
        "actioncomplete": "Aktioun ofgeschloss",
        "actionfailed": "Aktioun huet net funktionéiert",
        "deleting-backlinks-warning": "<strong>Opgepasst:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Aner Säite]] linken op déi Säit déi Dir am Gaang sidd ze läschen oder déi Säit Déi Dir am Gaang sidd ze läschen ass an aner Säiten agebonn.",
        "deleting-subpages-warning": "<strong>Opgepasst:</strong> D'Säit, déi Dir läsche wëllt, huet [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|eng Ënnersäit|$1 Ënnersäiten|51=méi wéi 50 Ënnersäiten}}]].",
        "rollback": "Ännerungen zrécksetzen",
+       "rollback-confirmation-confirm": "W.e.g. Konfirméieren",
+       "rollback-confirmation-yes": "Zrécksetzen",
+       "rollback-confirmation-no": "Ofbriechen",
        "rollbacklink": "Zrécksetzen",
        "rollbacklinkcount": "{{PLURAL:$1|Eng Ännerung|$1 Ännerungen}} zrécksetzen",
        "rollbacklinkcount-morethan": "méi wéi {{PLURAL:$1|Eng Ännerung|$1 Ännerungen}} zrécksetzen",
        "revertpage": "Ännerunge vum [[Special:Contributions/$2|$2]] ([[User talk:$2|Diskussioun]]) zréckgesat op déi lescht Versioun vum [[User:$1|$1]]",
        "revertpage-nouser": "Zréckgesaten Ännerungen duerch e verstoppte Benotzer op déi lescht Versioun vum {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "D'Ännerunge vum {{GENDER:$3|$1}} goufen zréckgesat op déi lescht Versioun vum {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Zréckgesat Ännerunge vum $1:\nzréckgeännert op déi lescht Versioun vum $2. [$3 Ännerunge weisen]",
        "sessionfailure-title": "Setzungsfeeler",
        "sessionfailure": "Et schéngt e Problem mat Ärer Sessioun ze ginn;\nDës Aktioun gouf aus Sécherheetsgrënn ofgebrach, fir ze verhënneren datt Är Sessioun piratéiert ka ginn.\nSchéckt de Formulaire w.e.g. nach eng Kéier.",
        "changecontentmodel": "De Modell vum Inhalt vun enger Säit änneren",
        "blocklist-userblocks": "Benotzerspäre verstoppen",
        "blocklist-tempblocks": "Temporär Späre verstoppen",
        "blocklist-addressblocks": "Eenzel IP-Späre verstoppen",
+       "blocklist-type": "Typ:",
+       "blocklist-type-opt-all": "All",
+       "blocklist-type-opt-partial": "Partiell",
        "blocklist-rangeblocks": "Späre vu ganzen IP-Beräicher verstoppen",
        "blocklist-timestamp": "Zäitstempel",
        "blocklist-target": "Zil",
        "blocklink": "spären",
        "unblocklink": "Spär ophiewen",
        "change-blocklink": "Spär änneren",
+       "empty-username": "(kee Benotzernumm disponibel)",
        "contribslink": "Kontributiounen",
        "emaillink": "Mail schécken",
        "autoblocker": "Dir sidd automatesch gespaart well Är IP-Adress rezent vum \"[[User:$1|$1]]\" benotzt gouf.\nDe Grond dee fir d'Spär vum $1 ugi gouf ass: \"$2\".",
        "allmessagesdefault": "Standardtext",
        "allmessagescurrent": "Aktuellen Text",
        "allmessagestext": "Dëst ass eng Lëscht vun alle '''Messagen am MediaWiki:Nummraum, déi vun der MediaWiki-Software benotzt ginn.\nBesicht w.e.g. [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisatioun] an [https://translatewiki.net translatewiki.net] wann Dir wëllt bei de MediaWiki Iwwersetzunge matschaffen.",
-       "allmessagesnotsupportedDB": "Dës Säit kann net benotzt gi well '''$wgUseDatabaseMessages''' ausgeschalt ass.",
+       "allmessages-not-supported-database": "Dës Säit kann net benotzt gi well '''$wgUseDatabaseMessages''' ausgeschalt ass.",
        "allmessages-filter-legend": "Filter",
        "allmessages-filter": "Filter nom ugepassten Zoustand:",
        "allmessages-filter-unmodified": "Net geännert",
index 699f8d3..8a8a608 100644 (file)
        "rcfilters-filter-editsbyself-description": "Tua propre contribuis.",
        "rcfilters-filter-editsbyother-label": "Cambias par otras",
        "rcfilters-filter-editsbyother-description": "Tota cambias estra la tuas.",
-       "rcfilters-filtergroup-userExpLevel": "Rejistra e esperia de usor",
+       "rcfilters-filtergroup-user-experience-level": "Rejistra e esperia de usor",
        "rcfilters-filter-user-experience-level-registered-label": "Autenticida",
        "rcfilters-filter-user-experience-level-registered-description": "Editores autenticida.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Anonim",
        "rcfilters-hideminor-conflicts-typeofchange-global": "La filtro \"Editas minor\" desacorda con un o plu filtros de \"Spesie de cambia\", car alga spesies de cambia no pote es indicada como \"minor\". La filtros desacordante es marcada en la area \"Filtros ativa\", a supra.",
        "rcfilters-hideminor-conflicts-typeofchange": "Alga spesies de cambia no pote es indicada como \"minor\", donce esta filtro desacorda con la filtros seguente de \"Spesie de cambia\": $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Esta filtro de \"Spesie de cambia\" desacorda con la filtro \"Editas minor\". Alga spesies de cambia no pote es indicada como \"minor\".",
-       "rcfilters-filtergroup-lastRevision": "Revisas la plu resente",
+       "rcfilters-filtergroup-lastrevision": "Revisas la plu resente",
        "rcfilters-filter-lastrevision-label": "Revisa la plu tarda",
        "rcfilters-filter-lastrevision-description": "Sola la cambia la plu resente a un paje.",
        "rcfilters-filter-previousrevision-label": "No la revisa la plu tarda",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|usor|usores}} monitorinte]",
        "rc-change-size-new": "$1 {{PLURAL:$1|bait|baites}} pos cambia",
        "newsectionsummary": "/* $1 */ parte nova",
        "rc-enhanced-expand": "Mostra detalias",
        "img-auth-nopathinfo": "PATH_INFO manca.\nTua servador no es ajustada per envia esta informa.Cisa lo usa CGI e no pote suporta img_auth.\nVide https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "La adirije solisitada no es en la arcivo definida per cargas.",
        "img-auth-badtitle": "Un titulo valida no ia pote es construida de \"$1\".",
-       "img-auth-nologinnWL": "Tu no es autenticida e \"$1\" no es en la lista blanca.",
        "img-auth-nofile": "Fix \"$1\" no esiste.",
        "img-auth-isdir": "Tu atenta asede un arcivo \"$1\".\nSola asede de fixes es permeteda.",
        "img-auth-streaming": "\"$1\" flue.",
        "revertpage": "Editas par [[Special:Contributions/$2|$2]] ([[User talk:$2|discute]]) ia es reversada a la revisa la plu resente par [[User:$1|$1]]",
        "revertpage-nouser": "Editas par un usor ascondeda ia es reversada a la revisa la plu resente par [[User:$1|$1]]",
        "rollback-success": "Editas par {{GENDER:$3|$1}} ia es reversada e cambiada a la revisa la plu resente par {{GENDER:$4|$2}}",
-       "rollback-success-notify": "Editas par $1 ia es reversada e cambiada a la revisa la plu resente par $2. [$3 Mostra cambias]",
        "sessionfailure-title": "Fali de sesion",
        "sessionfailure": "Lo pare ce tua sesion de autentici ave un problem; esta ata ia es canselada per proteje contra saisis de sesion. Reenvia la formulario, per favore.",
        "changecontentmodel": "Cambia model de contenida de un paje",
        "allmessagesdefault": "Testo inisial de mesaje",
        "allmessagescurrent": "Testo presente de mesaje",
        "allmessagestext": "Esta es un lista de mesajes de sistem disponable en la spasio de nom MediaWiki.\nSi tu vole contribui a la tradui jeneral de MediaWiki, per favore visita [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Locali de MediaWiki] e [https://translatewiki.net translatewiki.net].",
-       "allmessagesnotsupportedDB": "Esta paje no pote es usada car <strong>$wgUseDatabaseMessages</strong> es descomutada.",
+       "allmessages-not-supported-database": "Esta paje no pote es usada car <strong>$wgUseDatabaseMessages</strong> es descomutada.",
        "allmessages-filter-legend": "Filtri",
        "allmessages-filter": "Filtri par state de ajusta",
        "allmessages-filter-unmodified": "Nonalterada",
index e175788..6ec72cc 100644 (file)
@@ -19,7 +19,8 @@
                        "Macofe",
                        "Matma Rex",
                        "Robin van der Vliet",
-                       "Vlad5250"
+                       "Vlad5250",
+                       "PiefPafPier"
                ]
        },
        "tog-underline": "Links óngersjtriepe",
        "recentchanges-label-unpatrolled": "Dees bewirking is nog neet gekónterleerd",
        "recentchanges-label-plusminus": "Dees paginagruuedje is verangerdj mit dit aantaal aan bytes",
        "recentchanges-legend-heading": "<strong>Legenda:</strong>",
-       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (zuuch ouch [[Special:NewPages|de nuuj pagina's]])",
+       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}}<br />(zuuch ouch [[Special:NewPages|de nuuj pagina's]])",
        "recentchanges-submit": "Tuin",
        "rcfilters-tag-remove": "Sjaf '$1' weg",
        "rcfilters-legend-heading": "<strong>Lies mit aafkórtinge:</strong>",
        "rcfilters-filter-editsbyself-description": "Dien eige biedraag.",
        "rcfilters-filter-editsbyother-label": "Verangeringe door angere",
        "rcfilters-filter-editsbyother-description": "Alle verangere behauve die die det se zelf höbs gemaak.",
-       "rcfilters-filtergroup-userExpLevel": "Gebroekersregistrasie en -ervaring",
+       "rcfilters-filtergroup-user-experience-level": "Gebroekersregistrasie en -ervaring",
        "rcfilters-filter-user-experience-level-registered-label": "Vasgelag",
        "rcfilters-filter-user-experience-level-registered-description": "Aangemelde bewirkers.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Neet-vasgelag",
        "rcfilters-hideminor-conflicts-typeofchange-global": "De \"kleine bewirkinge\"-filter is in stried mit ein of mieëder saorte verangeringsfilters, ómdet bestumde saorte verangeringe neet es \"klein\" kinne waere aangeweze. De in stried zeendje filters zint gemarkeerd in 't Aktieve-filtervak hiebaove.",
        "rcfilters-hideminor-conflicts-typeofchange": "Bestumde saorte aan verangeringe kónne neet waer aangemirk es \"klein\", dus deze filter is in stried mit de volgende saorte verangeringsfilters: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Dit type aan verangeringsfilter is in stried mit de \"kleine verangeringe\"-filter. Bestumde types aan verangeringe kónne neet es \"klein\" waere aangeweze.",
-       "rcfilters-filtergroup-lastRevision": "Litste versies",
+       "rcfilters-filtergroup-lastrevision": "Litste versies",
        "rcfilters-filter-lastrevision-label": "Litste versie",
        "rcfilters-filter-lastrevision-description": "Allein de recènste verangering aan de pagina.",
        "rcfilters-filter-previousrevision-label": "Neet de litste versie",
        "minoreditletter": "K",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|keer|keer}} op 'ne volglies]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} nao verangering",
        "newsectionsummary": "/* $1 */ nuje subkop",
        "rc-enhanced-expand": "Toean details",
        "img-auth-nopathinfo": "PATH_INFO óntbrèk.\nDiene server is neet ingesteld om dees informatie door te gaeve.\nMisjien gebroek deze CGI, en dan wört img_auth neet ongersteund.\nZuuch https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization aafbeildingsrechte veur mee informatie.",
        "img-auth-notindir": "'t Ópgevraogdje paad is neet de ingestelde uploadmap.",
        "img-auth-badtitle": "Kèn geine geldige paginanaam make van \"$1\".",
-       "img-auth-nologinnWL": "Doe bös neet aangemeld en \"$1\" steit neet op de witte lies.",
        "img-auth-nofile": "Bestandj \"$1\" besteit neet.",
        "img-auth-isdir": "Doe probeers de map \"$1\" te benadere.\nAllein toegank toet bestenj is toegestange.",
        "img-auth-streaming": "\"$1\" stroumendj.",
        "revertpage": "Wieziginge door [[Special:Contributions/$2|$2]] ([[User talk:$2|Euverlik]]) trukgedriejd tot de lètste versie door [[User:$1|$1]]",
        "revertpage-nouser": "Verangeringe door 'ne verstaoke gebroeker trökgedrejd nao de litste versie van {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Verangeringe door {{GENDER:$3|$1}} trökgedrejd;\nlitste versie van {{GENDER:$4|$2}} herstèld.",
-       "rollback-success-notify": "De verangeringe door $1 zint trökgedrejd;\nde litste versie van $2 is herstèld. [$3 Tuin verangeringe]",
        "sessionfailure-title": "Sessiefout",
        "sessionfailure": "'t Liek op det se e perbleem höbs mit dien aanmeldingssessie;\ndees hanjeling is aafgebraoke oet veurzörg taenge 'nen hack.\nVersjik estebleef 't formeleer.",
        "changecontentmodel": "Bewirk inhawdsmodel van pagina",
        "allmessagesdefault": "Obligaten teks",
        "allmessagescurrent": "Hujige teks",
        "allmessagestext": "Dit is 'n lies van alle systeemberichte besjikbaar in de MediaWiki-naamruumde.\nBezeuk [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki-lokalisatie] en [https://translatewiki.net translatewiki.net] es doe wils biedrage aon lokalisatie.",
-       "allmessagesnotsupportedDB": "Deze pagina kan neet gebroek waere omdet '''$wgUseDatabaseMessages''' oet steit.",
+       "allmessages-not-supported-database": "Deze pagina kan neet gebroek waere omdet '''$wgUseDatabaseMessages''' oet steit.",
        "allmessages-filter-legend": "Filter",
        "allmessages-filter": "Filter óp aangepas:",
        "allmessages-filter-unmodified": "Ónaangepas",
index 0e19814..cb6b134 100644 (file)
        "rcfilters-filter-editsbyself-description": "I to contributi.",
        "rcfilters-filter-editsbyother-label": "E modiffiche di atri",
        "rcfilters-filter-editsbyother-description": "Tutte e modiffiche sarvo e to.",
-       "rcfilters-filtergroup-userExpLevel": "Livèllo d'esperiença (solo pe i utenti registræ)",
+       "rcfilters-filtergroup-user-experience-level": "Livèllo d'esperiença (solo pe i utenti registræ)",
        "rcfilters-filter-user-experience-level-registered-label": "Registròu",
        "rcfilters-filter-user-experience-level-registered-description": "Contributoî conesci.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Non registròu",
        "rcfilters-hideminor-conflicts-typeofchange-global": "O filtro \"Modiffiche minoî\" o l'è in confito con un ò ciu filtri \"Tipo de modiffica\", percose çerte modiffiche no poeuan ese indicæ comme \"minoî\". I filtri in conflito son indicæ inte l'area \"Filtri attivi\" chì de d'ato.",
        "rcfilters-hideminor-conflicts-typeofchange": "Gh'è di tipi de modiffiche che no poeuan ese indicæ comme \"minoî\", quindi questo filtro o l'è in conflito co-i seguenti filtri \"Tipo de modiffica\": $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Questo filtro \"Tipo di modifica\" o l'è in conflito co-o  filtro \"Modiffiche minoî\". Çerti tipi de modiffiche no poeuan ese indicæ comme \"minoî\".",
-       "rcfilters-filtergroup-lastRevision": "Ùrtime verscioìn",
+       "rcfilters-filtergroup-lastrevision": "Ùrtime verscioìn",
        "rcfilters-filter-lastrevision-label": "Urtima revixon",
        "rcfilters-filter-lastrevision-description": "Solo e modiffiche ciu recenti a 'na pagina.",
        "rcfilters-filter-previousrevision-label": "No l'urtima versción",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[osservâ da {{PLURAL:$1|un utente|$1 utenti}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} doppo a modiffica",
        "newsectionsummary": "/* $1 */ neuva seçion",
        "rc-enhanced-expand": "Fanni vedde i detaggi",
        "img-auth-nopathinfo": "PATH_INFO mancante.\nO server o no l'è impostou pe passâ quest'informaçion.\nO poriæ ese basou insce CGI e o no poeu supportâ img_auth.\nAmia https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "O percorso domandou o no l'è inta directory de upload configuâ.",
        "img-auth-badtitle": "Imposcibile construe un tittolo vallido da \"$1\".",
-       "img-auth-nologinnWL": "No t'ê introu e \"$1\" o no l'è inta whitelist.",
        "img-auth-nofile": "O file \"$1\" o no l'existe.",
        "img-auth-isdir": "Ti çerchi d'accede a 'na directory \"$1\".\nL'è consentio solo l'accesso a-i file.",
        "img-auth-streaming": "\"$1\" in streaming.",
        "revertpage": "Annullou e modiffiche de [[Special:Contributions/$2|$2]] ([[User talk:$2|discuscion]]), riportâ a-a verscion precedente de [[User:$1|$1]]",
        "revertpage-nouser": "Annullou e modiffiche de un utente ascoso, riportâ a-a verscion precedente de {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Annullou e modiffiche de {{GENDER:$3|$1}}; paggina riportâ a l'urtima verscion de {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Annullou e modiffiche de $1;\npaggina riportâ a l'urtima revixon de $2. [$3 Mostra e modiffiche]",
        "sessionfailure-title": "Sescion fallia",
        "sessionfailure": "S'è veificou un problema inta sescion ch'a l'identiffica l'accesso; o scistema o no l'ha eseguio o comando impartio pe precauçion. Torna a-a paggina precedente co-o tasto 'Inderê' do to browser, recarega a paggina e riproeuva.",
        "changecontentmodel": "Cangia o modello de contegnuo de 'na paggina",
        "allmessagesdefault": "Testo predefinio",
        "allmessagescurrent": "Testo corrente",
        "allmessagestext": "Sta chie a l'è a lista de tutti i messaggi de scistema disponibili into namespace MediaWiki.\nVixita [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] e [https://translatewiki.net translatewiki.net] se ti voeu contribuî a-a localizzaçion generrica de MediaWiki.",
-       "allmessagesnotsupportedDB": "No l'è poscibbile doeuviâ sta paggina perchè o flag '''$wgUseDatabaseMessages''' o no l'è attivo.",
+       "allmessages-not-supported-database": "No l'è poscibbile doeuviâ sta paggina perchè o flag '''$wgUseDatabaseMessages''' o no l'è attivo.",
        "allmessages-filter-legend": "Filtro",
        "allmessages-filter": "Filtra pe stato de modiffica:",
        "allmessages-filter-unmodified": "Non modificæ",
index 72db9a2..fb8d8d7 100644 (file)
        "minoreditletter": "جز",
        "newpageletter": "نو",
        "boteditletter": "ر",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|کاربر}} پی‌گیرنده]",
        "rc-change-size-new": " $1دؤما تۀقیر دائن{{PLURAL:$1|بایت|بایتل}}",
        "newsectionsummary": "/* $1 */ بەخش نوو",
        "rc-enhanced-expand": "نمایش جزئیات",
        "img-auth-nopathinfo": "PATH_INFO موجود نیست.\nسرور شما برای ردکردن این مقدار تنظیم نشده‌است.\nممکن است مبتنی بر سی‌جی‌آی باشد و از img_auth پشتیبانی نکند.\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization را ببینید.",
        "img-auth-notindir": "مسیر درخواست شده در شاخهٔ بارگذاری تنظیم‌شده قرار ندارد.",
        "img-auth-badtitle": "امکان ایجاد یک عنوان مجاز از «$1» وجود ندارد.",
-       "img-auth-nologinnWL": "شما به سامانه وارد نشده‌اید و «$1» در فهرست سفید قرار ندارد.",
        "img-auth-nofile": "پرونده «$1» وجود ندارد.",
        "img-auth-isdir": "شما تلاش کرده‌اید به شاخهٔ «$1» دسترسی پیدا کنید.\nتنها دسترسی به پرونده مجاز است.",
        "img-auth-streaming": "در حال جاری ساختن «$1».",
        "allmessagesdefault": "متن پیش‌فرض پیغام",
        "allmessagescurrent": "متن کنونی پیغام",
        "allmessagestext": "این فهرستی از پیغام‌های سامانه‌ای موجود در فضای نام مدیاویکی است.\nچنانچه مایل به مشارکت در محلی‌سازی مدیاویکی هستید لطفاً [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation محلی‌سازی مدیاویکی] و [https://translatewiki.net translatewiki.net] را ببینید.",
-       "allmessagesnotsupportedDB": "این صفحه نمی‌تواند استفاده شود به این دلیل که <bdi>'''$wgUseDatabaseMessages'''</bdi> غیرفعال شده‌است.",
+       "allmessages-not-supported-database": "این صفحه نمی‌تواند استفاده شود به این دلیل که <bdi>'''$wgUseDatabaseMessages'''</bdi> غیرفعال شده‌است.",
        "allmessages-filter-legend": "پالانۀل/فیلترۀل",
        "allmessages-filter": "پالودن بر اساس وضعیت شخصی‌سازی:",
        "allmessages-filter-unmodified": "نگؤەڕیائە/تغییرنیافته",
index 06ae51e..8fda790 100644 (file)
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[tignìda d'öcc de {{PLURAL:$1|1 ütènt|$1 ütèncc}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} dopo la mudìfica",
        "newsectionsummary": "/* $1 */ sezión növa",
        "rc-enhanced-expand": "Fà ved i detai",
index 1ade781..e5f17c0 100644 (file)
                        "Lorestani"
                ]
        },
-       "tog-underline": "Ù\87Ù\88Ù\85 Ù¾Ø¦Û\8cڤأÙ\86د Ø²Û\8cرخأط دار:",
-       "tog-hideminor": "قام کئردئن ڤیرایشتیا کوچئک مین آلئشتیا تازە",
-       "tog-hidepatrolled": "قام کئردئن ڤیرایشتیا تیە دیار کئردە مین آلئشتیا تازە",
-       "tog-newpageshidepatrolled": "بألگە یا تیە دیار کئردە نە مئن نومگە بألگە یا تازە قام کو",
-       "tog-hidecategorization": "قام کئردئن جأرغە کاری بألگە یا",
-       "tog-extendwatchlist": "سئÛ\8cÙ\84 Ø¨Ø£Ø±Ú¯Û\95 Ù\86Û\95 Ø³Û\8c Ù\86ئشÙ\88Ù\99 Ø¯Ø£Ø¦Ù\86 ØªØ£Ù\85Ù\88Ù\99Ù\85 Ø¢Ù\84ئشتÛ\8cا Ú¤Ø§ Ú©Ù\88 Ù\86Û\95 Ù\81Ø£Ù\82أط Ø³Û\8c Ø¨Û\8cشتئر ØªØ§Ø²Û\95 Ø¨Ø§Ú¤Û\8cا.",
-       "tog-usenewrc": "دأسە بأنی آلئشتیا ڤا بألگە د آلئشتیا تازە و سئیل بأرگ",
-       "tog-numberheadings": "سربٱÙ\84Ú¯Ù± Ø®Ù\88د Ø´Ù\85ارشت کو",
-       "tog-editondblclick": "بألگە یا نە ڤا د نۊ پوٙرنیئن ڤیرایئشت بأکیت",
-       "tog-editsectiononrightclick": "بأرجا ڤیرایئشت نە ڤا راس پوٙرنییئن د بأرجا داسوٙنیا کونئشتگأر کو",
-       "tog-watchcreations": "بألگە یایی کئ مئ رأڤأندیاری کئمە و جانیایی کئ مئ سوڤار کئمە ئضاف کو د سئیل بأرگە مئ",
-       "tog-watchdefault": "بألگە یایی کئ مئ رأڤأندیاری کئمە و جانیایی کئ مئ سوڤار کئمە ئضاف کو د سئیل بأرگە مئ",
-       "tog-watchmoves": "بألگە یایی و جانیایی کئ مئ جا ڤئ جا کئمە ئضاف کو د سئیل بأرگە مئ",
-       "tog-watchdeletion": "بألگە یایی و جانیایی کئ مئ پاکسا کئمە ئضاف کو د سئیل بأرگە مئ",
-       "tog-watchrollback": "هأمە بألگە یا نە د جایی کئ مئ می رئم ڤأ دئماتأر د د سئیل بأرگئم ئضاف کو.",
-       "tog-minordefault": "هأمە ڤیرایئشتیا کوچئک نە ڤا حال و بار پیش فأرض بییئن نئشوٙ دار کو.",
-       "tog-previewontop": "Ù¾Û\8cØ´ Ø³Ø¦Û\8cÙ\84 Ù\86Û\95 Ø¯Ø¦Ù\85ا Ø¬Ø£Ú¤Û\95 Ú¤Û\8cراÛ\8cئشت Ù\86ئشÙ\88Ù\99 Ø¨Û\8cÛ\8cÛ\95",
-       "tog-previewonfirst": "Ù¾Û\8cØ´ Ø³Ø¦Û\8cÙ\84 Ù\86Û\95 Ø¯ Ø£Ú¤Ø£Ù\84Û\8c Ú¤Û\8cراÛ\8cئشت Ù\86ئشÙ\88Ù\99 Ø¨Û\8cÛ\8cÛ\95",
-       "tog-enotifwatchlistpages": "ئوسئ کئ یئ گئل بألگە یا جانیا د سئیل بأرگئ مئ آلئشت بوٙه مئنە ڤا أنجومانامە خأڤأر کو",
-       "tog-enotifusertalkpages": "د گاتی کئ بألگە گأپئسن کاریار آلشت کاری بی مئنە ڤا أنجومانامە خأڤأر کو",
-       "tog-enotifminoredits": "هأمچئنی ئوسئ کئ ڤیرایئشتیا کوچئکی د بألگە یا یا جانیایا أنجوم بوە مئنە ڤارئسیاری بأک",
-       "tog-enotifrevealaddr": "تÛ\8cر Ù\86ئشÙ\88Ù\99Ù\86 Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95 Ù\85ئÙ\86Û\95 Ø¯ Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95 Ø¯Û\8cارکÙ\88 Ø¯Û\8cارÛ\8c Ø¨Ø£Ú©",
-       "tog-shownumberswatching": "أنازە کاریاریایی کئ د حال و بال دیئن هئن دیاری بأک",
-       "tog-oldsig": "ئÙ\85ضاÛ\8cÛ\8c Ù\87Û\8c:",
-       "tog-fancysig": "ڤا Ø¦Ù\85ضا Ú\86Û\8c Û\8cئ Ú¯Ø¦Ù\84 Ú¤Û\8cÚ©Û\8c Ù\86Û\8cسئسÛ\95 Ø±Ø£Ù\81تار Ø¨Ø£Ú©",
-       "tog-uselivepreview": "Ù¾Û\8cØ´ Ø³Ø¦Û\8cÙ\84 Ø²Ø¦Ù\86Û\95 Ú¤Ø¦ Ú©Ø§Ø± Ø¨Ø¦یر",
-       "tog-forceeditsummary": "مئنە د گاتی کئ یئ گئل چئکئسە ڤیرایئشت حالی میا ڤامین ڤئ یە توف کونوٙ ڤارسیاری بأک",
-       "tog-watchlisthideown": "Ú¤Û\8cراÛ\8cئشتÛ\8cا Ù\85ئÙ\86Û\95 Ø¯ Ø³Ø¦Û\8cÙ\84 Ø¨Ø£Ø±Ú¯ Ù\86ئÙ\87Ù\88Ù\99 Ø¨Ø£Ú©",
-       "tog-watchlisthidebots": "Ú¤Û\8cراÛ\8cئشتÛ\8cا Ø¨Ù\88ت Ù\86Û\95 Ø¯ Ø³Ø¦Û\8cÙ\84 Ø¨Ø£Ø±Ú¯ Ù\86ئÙ\87Ù\88Ù\99 Ø¨Ø£Ú©",
-       "tog-watchlisthideminor": "Ú¤Û\8cراÛ\8cئشÛ\8cا Ú©Ù\88Ú\86ئک Ù\86Û\95 Ø¯ Ø³Ø¦Û\8cÙ\84 Ø¨Ø£Ø±Ú¯ Ù\86ئÙ\87Ù\88Ù\99 Ø¨Ø£Ú©",
-       "tog-watchlisthideliu": "ڤبرایشتیایی نە کئ ڤئ دأس کاریاریا ڤامین ئوٙماە أنجوم گئرئتە د سئیل بأرگ نئهوٙ بأک",
-       "tog-watchlisthideanons": "Ú¤Û\8cراÛ\8cئشتÛ\8cا Ú©Ø§Ø±Û\8cارÛ\8cاÛ\8cÛ\8c Ú©Ø¦ Ù\86ادÛ\8cارئÙ\86 Ø¯ Ø³Ø¦Û\8cÙ\84 Ø¨Ø£Ø±Ú¯ Ù\86ئÙ\87Ù\88Ù\99 Ø¨Ø£Ú©",
-       "tog-watchlisthidepatrolled": "Ú¤Û\8cراÛ\8cشتÛ\8cاÛ\8cÛ\8c Ú©Ù\87 Ù\87اÙ\86 Ø¯ ØªÛ\8cÛ\95 Ø±Ø£Ø³ Ø¯ Ø³Ø¦Û\8cÙ\84 Ø¨Ø£Ø±Ú¯ Ù\82ام کو",
-       "tog-watchlisthidecategorization": "قام کئردئن جأرغە کاری بألگە یا",
-       "tog-ccmeonemails": "ڤورداشتە یا أنجومانامه یا مئنە کئ سی کاریاریا هأنی کئل می کئم سیم کئل بأک",
-       "tog-diffonly": "بألگە یایی کئ د ڤأر گئرتە فأرخیا هارئن دیاریشوٙ بأک",
-       "tog-showhiddencats": "دأسە یا نئهوٙ بییأنئ دیاری بأک",
+       "tog-underline": "Ù\87Ù\88Ù\85 Ù¾Ø§Ù\9bÚ¤Ù±Ù\86 Ø²Ø½Ø±Ø®Ù±Øª دار:",
+       "tog-hideminor": "قایم کردن ڤیرایشؽا کوچک مؽن آلشتؽا تازٱ",
+       "tog-hidepatrolled": "قایم کردن ڤیرایشتؽا تیٱ دؽار کردٱ مؽن آلشتؽا تازٱ",
+       "tog-newpageshidepatrolled": "بٱلگٱیا تیٱ دؽار کردٱ ناْ مؽن نومگٱ بٱلگٱیا تازٱ قایم کو",
+       "tog-hidecategorization": "قایم کردن جٱرغٱ کاری بٱلگٱیا",
+       "tog-extendwatchlist": "ساÙ\9bÙ\84Ù\9b Ø¨Ù±Ø±Ú¯ Ù\86اÙ\92 Ø³Û\8c Ù\86Ø´Ù\88Ý© Ø¯Ø§Ù\9bئÙ\86 ØªÙ\85Ù\88Ù\85 Ø¢Ù\84شتؽا Ú¤Ø§ Ú©Ù\88Ø\8c Ù\86Ù± Ù\81Ù\82ٱت Ø³Û\8c Ø¨Ø½Ø´ØªØ± ØªØ§Ø²Ù± Ø¨Ø§Ú¤Ø½ا.",
+       "tog-usenewrc": "دٱسٱ بٱنی آلشتؽا ڤا بٱلگٱ د آلشتؽا تازٱ ۉ ساٛلٛ بٱرگ",
+       "tog-numberheadings": "سربٱÙ\84Ú¯Ù± Ø®Ù\88ت Ø´Ù\85ارش کو",
+       "tog-editondblclick": "بٱلگٱیا ناْ ڤا د نۊ پۊرنیئن ڤیرایش بٱکؽت",
+       "tog-editsectiononrightclick": "بٱئرجا ڤیرایش ناْ ڤا راس پۊرنیئن د بٱئرجا داسونؽا کنشگٱر کو",
+       "tog-watchcreations": "بٱلگٱیایؽ کاْ ماْ رٱڤٱندؽاری کردمٱ ۉ جانؽایؽ کاْ ماْ سڤار کردمٱ اْزاف کو د ساٛلٛ بٱرگ ماْ",
+       "tog-watchdefault": "بٱلگٱیایؽ کاْ ماْ رٱڤٱندؽاری کردمٱ ۉ جانؽایؽ کاْ ماْ سڤار کردمٱ اْزاف کو د ساٛلٛ بٱرگ ماْ",
+       "tog-watchmoves": "بٱلگٱیا ۉ جانؽایؽ کاْ ماْ جا ڤ جا کردمٱ اْزاف کو د ساٛلٛ بٱرگ ماْ",
+       "tog-watchdeletion": "بٱلگٱیا ۉ جانؽایؽ کاْ ماْ پاکسا کردمٱ اْزاف کو ڤ ساٛلٛ بٱرگ ماْ",
+       "tog-watchrollback": "هٱمٱ بٱلگٱیا ناْ د جایی کاْ ماْ ماٛرم ڤا دماتر ڤ ساٛلٛ بٱرگ ماْ اْزاف کو.",
+       "tog-minordefault": "هٱمٱ ڤیرایشؽا کوچک ناْ ڤا هال ۉ بار پیش فٱرز بیئن نشوݩ دار کو.",
+       "tog-previewontop": "Ù¾Û\8cØ´ Ø³Ø§Ù\9bÙ\84Ù\9b Ù\86اÙ\92 Ø¯Ù\85ا Ø¬Ù±Ú¤Ù± Ú¤Û\8cراÛ\8cØ´ Ù\86Ø´Ù\88Ý© Ø¨Ø§Ù\9bÛ\8cÙ±",
+       "tog-previewonfirst": "Ù¾Û\8cØ´ Ø³Ø§Ù\9bÙ\84Ù\9b Ù\86اÙ\92 Ø¯ Ù±Ú¤Ù\84Û\8c Ú¤Û\8cراÛ\8cØ´ Ù\86Ø´Ù\88Ý© Ø¨Ø§Ù\9bÛ\8cÙ±",
+       "tog-enotifwatchlistpages": "ٱر یاٛ بٱلگٱ یا جانؽا د ساٛلٛ بٱرگ ماْ آلشت بۊئٱ ماْ ناْ ڤا ٱنجومانامٱ خڤٱر کو",
+       "tog-enotifusertalkpages": "ڤٱختؽ کاْ بٱلگٱ سالفٱ کاریاریم آلشت کاری بی ماْ ناْ ڤا ٱنجومانامٱ خڤٱر کو",
+       "tog-enotifminoredits": "ڤٱختؽ کاْ ڤیرایشؽا کوچکؽ د بٱلگٱیایا جانؽایا ٱنجوم بۊئٱ ماْ ناْ ڤارٱسیاری کو",
+       "tog-enotifrevealaddr": "تÛ\8cر Ù\86Ø´Ù\88Ý© Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù± Ù\85اÙ\92 Ù\86اÙ\92 Ø¯ Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù± Ø¯Ø½Ø§Ø±Ú©Ù\88 Ø¯Ø½Ø§Ø±Û\8c Ú©Ù\88",
+       "tog-shownumberswatching": "ٱندازٱ کاریارؽایی کاْ د هال ۉ بال دیئن هؽسن دؽاری کو",
+       "tog-oldsig": "اÙ\92Ù\85زا Ø§Û\8cسÙ\86Û\8c Ø´Ù\85ا:",
+       "tog-fancysig": "ڤا Ø§Ù\92Ù\85زا Ú\86Û\8c Û\8cاÙ\9b Ú¤Û\8cÚ©Û\8c Ù\86Û\8cسسٱ Ø±Ù±Ù\81تار Ú©Ù\88",
+       "tog-uselivepreview": "Ù¾Û\8cØ´ Ø³Ø§Ù\9bÙ\84Ù\9b Ø²Ù\86Ù± Ú¤ Ú©Ø§Ø± Ø¨Ø§Ù\9bیر",
+       "tog-forceeditsummary": "د گاتؽ کاْ یاٛ چکسٱ ڤیرایش هالؽ مؽا ڤامؽن ماْ ناْ  ڤارٱسیاری کو",
+       "tog-watchlisthideown": "Ú¤Û\8cراÛ\8cشؽا Ù\85اÙ\92 Ù\86اÙ\92 Ø¯ Ø³Ø§Ù\9bÙ\84Ù\9b Ø¨Ù±Ø±Ú¯ Ù\82اÛ\8cÙ\85 Ú©Ù\88",
+       "tog-watchlisthidebots": "Ú¤Û\8cراÛ\8cشؽا Ø¨Ù\88ت Ù\86اÙ\92 Ø¯ Ø³Ø§Ù\9bÙ\84Ù\9b Ø¨Ù±Ø±Ú¯ Ù\82اÛ\8cÙ\85 Ú©Ù\88",
+       "tog-watchlisthideminor": "Ú¤Û\8cراÛ\8cشؽا Ú©Ù\88Ú\86Ú© Ù\86اÙ\92 Ø¯ Ø³Ø§Ù\9bÙ\84Ù\9b Ø¨Ù±Ø±Ú¯ Ù\82اÛ\8cÙ\85 Ú©Ù\88",
+       "tog-watchlisthideliu": "ڤیرایشؽایؽ ناْ کاْ ڤ دٱس کاریارؽا ڤامؽن اومایٱ ٱنجوم گرتٱ د ساٛلٛ بٱرگ قایم کو",
+       "tog-watchlisthideanons": "Ú¤Û\8cراÛ\8cشؽا Ú©Ø§Ø±Û\8cارؽاÛ\8cؽ Ú©Ø§Ù\92 Ù\86ادؽارٱÙ\86 Ø¯ Ø³Ø§Ù\9bÙ\84Ù\9b Ø¨Ù±Ø±Ú¯ Ù\82اÛ\8cÙ\85 Ú©Ù\88",
+       "tog-watchlisthidepatrolled": "Ú¤Û\8cراÛ\8cشؽاÛ\8cؽ Ú©Ø§Ù\92 Ù\87اÙ\86 Ø¯ ØªÛ\8cÙ± Ø±Ù±Ø³ Ø¯ Ø³Ø§Ù\9bÙ\84Ù\9b Ø¨Ù±Ø±Ú¯ Ù\82اÛ\8cم کو",
+       "tog-watchlisthidecategorization": "قایم کردن جٱرغٱ کاری بٱلگٱیا",
+       "tog-ccmeonemails": "ڤرداشتٱیا ٱنجومانامٱیا ماْ ناْ کاْ سی کاریارؽا هنی کلٛ مؽکم سیم کلٛ کو",
+       "tog-diffonly": "بٱلگٱیایؽ کاْ د ڤٱر گترتٱ فٱرخؽا هارٱن دؽاریشو کو",
+       "tog-showhiddencats": "دٱسٱیا نهوݩ بیٱن دؽاری کو",
        "tog-norollbackdiff": "فأرخیا نە د یئ گئل ڤادئما رأتئن د بئین بوریت",
-       "tog-useeditwarning": "د گاتی کئ آلئشتیا ئمایە نأبینە د بألگە ڤیرایئشت ڤئ جا مئ نئم مئنە ڤارئسیاری بأک",
+       "tog-useeditwarning": "د گاتؽ کاْ آلشتؽا آمادٱ ناٛینٱ د بٱلگٱ ڤیرایش ڤ جا مٱنم ماْ ناْ ڤارٱسیاری کو",
        "tog-prefershttps": "هأمیشە د گاتی کئ مئ هام د ساموٙنە پئیڤأند أمن نە ڤئ کار بئیر",
        "underline-always": "همیشٱ",
-       "underline-never": "هیژۋخت",
-       "underline-default": "پوٙسە یا دوڤارتە نییأر پیش فأرض",
-       "editfont-style": "راساگÙ\87 Ù\81Ù\88Ù\86ت Ø´Û\8cڤات Ù\86Û\95 Ú¤Û\8cراÛ\8cئشت کو",
-       "editfont-monospace": "فونت تأک بألگە یی",
-       "editfont-sansserif": "Ù\81Ù\88Ù\86ت Ø³Ø§Ù\86 Ø³Ø¦Ø±Û\8cÙ\81",
-       "editfont-serif": "Ù\81Ù\88Ù\86ت Ø³Ø¦Ø±Ù\8aÙ\81",
+       "underline-never": "هیژ ڤٱخت",
+       "underline-default": "پۊسٱ یا دوئرتٱ نیٱر پیش فٱرز",
+       "editfont-style": "راساگٱ Ù\81Ù\88Ù\86ت Ø´Û\8cڤات Ù\86اÙ\92 Ú¤Û\8cراÛ\8cØ´ کو",
+       "editfont-monospace": "فونت تٱک بٱلگاٛیی",
+       "editfont-sansserif": "فونت سان سریف",
+       "editfont-serif": "فونت سريف",
        "sunday": "یاٛ شٱمٱ",
        "monday": "دۏشٱمٱ",
        "tuesday": "ساْ شٱمٱ",
        "thu": "پٱن شٱمٱ",
        "fri": "جۏمٱ",
        "sat": "شٱمٱ",
-       "january": "جانڤیٱ",
+       "january": "ژانڤیٱ",
        "february": "فڤریٱ",
        "march": "مارس",
-       "april": "آڤریل",
-       "may_long": "ماٛی",
-       "june": "جوئٱن",
+       "april": "آڤریلٛ",
+       "may_long": "ماٛ",
+       "june": "ژوئٱن",
        "july": "جۊلای",
        "august": "آگوست",
        "september": "سپتامر",
        "october": "اوکتوبر",
        "november": "نوڤامر",
        "december": "دسامر",
-       "january-gen": "جانڤیٱ",
+       "january-gen": "ژانڤیٱ",
        "february-gen": "فڤریٱ",
        "march-gen": "مارس",
-       "april-gen": "آڤریل",
+       "april-gen": "آڤریلٛ",
        "may-gen": "ماٛی",
        "june-gen": "ژوئٱن",
        "july-gen": "جۊلای",
        "october-gen": "اوکتوبر",
        "november-gen": "نوڤامر",
        "december-gen": "دسامر",
-       "jan": "جانڤیٱ",
+       "jan": "ژانڤیٱ",
        "feb": "فڤریٱ",
        "mar": "مارس",
-       "apr": "آڤریل",
-       "may": "ماٛی",
-       "jun": "جوئٱن",
+       "apr": "آڤریلٛ",
+       "may": "ماٛ",
+       "jun": "ژوئٱن",
        "jul": "جۊلای",
        "aug": "آگوست",
        "sep": "سپتامر",
        "oct": "اوکتوبر",
        "nov": "نوڤامر",
        "dec": "دسامر",
-       "january-date": "جانڤیە $1",
-       "february-date": "فئڤریە $1",
+       "january-date": "ژانڤیٱ $1",
+       "february-date": "فڤریٱ $1",
        "march-date": "مارس  $1",
-       "april-date": "آڤریل $1",
-       "may-date": "Ù\85ئÛ\8c $1",
-       "june-date": "جوٙأن $1",
-       "july-date": "جوٙلای $1",
+       "april-date": "آڤریلٛ $",
+       "may-date": "Ù\85اÙ\9b $1",
+       "june-date": "ژوئٱن $1",
+       "july-date": "جۊلای $1",
        "august-date": "آگوست $1",
-       "september-date": "سئپتامر $1",
-       "october-date": "ئوکتوبر $1",
+       "september-date": "سپتامر $1",
+       "october-date": "اوکتوبر $1",
        "november-date": "نوڤامر $1",
-       "december-date": "دئساÙ\85ر $1",
+       "december-date": "دسامر $1",
        "pagecategories": "{{PLURAL:$1|}}{{PLURAL:$1|دٱسٱ|دٱسٱيا}}",
        "category_header": "بٱلگٱیا مؽن دٱسٱ \"$1\"",
        "subcategories": "زؽر دٱسٱیا",
        "category-media-header": "ڤارسگٱر د دٱسٱ \"$1\"",
-       "category-empty": "اؽ دٱسٱ د راستٱکی د ڤٱرگرتٱ هیچ بٱلگٱ یا ڤارسگٱری نؽ",
+       "category-empty": "اؽ دٱسٱ د راسٱکی د ڤٱرگرتٱ هیچ بٱلگٱ یا ڤارسگٱری نؽ",
        "hidden-categories": "{{PLURAL:$1|دٱسٱ قایم بیٱ|دٱسٱیا قایم بیٱ}}",
-       "hidden-category-category": "دأسە یا قام بییە",
-       "category-subcat-count": "{{PLURAL:$2|اؽ دٱسٱ فقٱت زؽر دٱسٱیا دماگر هان دش.اؽ دٱسٱ {{PLURAL:$1|زؽردٱسٱ|$1 زؽردٱسٱیا}} ٱ , ڤ دٱر د $2 کولٛ.}}",
-       "category-subcat-count-limited": "ئÛ\8c Ø¯Ø£Ø³Û\95 Ù\87ا Ø¯ {{PLURAL:$1|زÛ\8cردأسÛ\95|$1 Ø²Û\8cردأسÛ\95 Û\8cا}} Û\8cÛ\8c Ú©Ø¦ Ù\87ا Ú¤Ø¦ Ø¯Ù\88Ù\85ئشÙ\88Ù\99",
+       "hidden-category-category": "دٱسٱیا قایم بیٱ",
+       "category-subcat-count": "{{PLURAL:$2|اؽ دٱسٱ فقٱت زؽر دٱسٱیا دماگر هان دش.اؽ دٱسٱ {{PLURAL:$1|زؽردٱسٱ|$1 زؽردٱسٱیا}} ئٱ , ڤ دٱر د $2 کولٛ.}}",
+       "category-subcat-count-limited": "اؽ Ø¯Ù±Ø³Ù± Ù\87ا Ø¯ {{PLURAL:$1|زؽردٱسٱ|$1 Ø²Ø½Ø±Ø¯Ù±Ø³Ù±Û\8cا}} Û\8cؽ Ú©Ø§Ù\92 Ù\87ا Ú¤ Ø¯Û\8fÙ\85Ø´Ù\88",
        "category-article-count": "{{PLURAL:$2|اؽ دٱسٱ د ڤٱرگرتٱ بٱلگٱ نهاییٱ.| {{PLURAL:$1| بٱلگٱ هؽ|$1 بٱلگٱیا هؽسن}} د اؽ دٱسٱ، ڤ دٱر د $2 کولٛ.}}",
-       "category-article-count-limited": "نئها {{PLURAL:$1|بألگە هی|$1بألگە یا هئن}} د دأسە ئیسئنی.",
+       "category-article-count-limited": "نوئا {{PLURAL:$1|بٱلگٱ هؽ|$1بٱلگٱیا هؽسن}} د دٱسٱ ایسنی.",
        "category-file-count": "{{PLURAL:$2|ای دٱسٱ فقٱت د ڤٱرگرتٱ جانؽا نهاییٱ.| نهایی {{PLURAL:$1|جانؽا هؽ|$1 جانیایا هؽسن}} د اؽ دٱسٱ، ڤ دٱر د کولٛ $2 .}}",
        "category-file-count-limited": " {{PLURAL:$1|[جانیا هی|1$جانیایا هین}} نئهایی هان د دأسە ئیسئنی.",
-       "listingcontinuesabbrev": "دومالٱ",
-       "index-category": "بØ£Ù\84Ú¯Û\95 Û\8cا Ø³Û\8cاÛ\95 Ø¯Ø§Ø±",
-       "noindex-category": "بٱلگٱیا بؽ سؽاهٱ",
-       "broken-file-category": "بٱلگٱیایی کاْ هوم پاٛڤٱن جانؽایا اْشگس ناْ دارٱن",
+       "listingcontinuesabbrev": "دۏمبالٱ",
+       "index-category": "بÙ±Ù\84Ú¯Ù±Û\8cا Ù\81Ù\87رست Ø¨Û\8cÙ±",
+       "noindex-category": "بٱلگٱیا بؽ فهرست",
+       "broken-file-category": "بٱلگٱیایؽ کاْ هوم پاٛڤٱن جانؽایا اْشگس ناْ دارٱن",
        "categoryviewer-pagedlinks": "($1) ($2)",
        "about": "دٱربارٱ",
-       "article": "مینوٙنە یا بألگە",
+       "article": "مؽنونٱیا بٱلگٱ",
        "newwindow": "(د یاٛ نیمدری تازٱ ڤازش کو)",
        "cancel": "ٱنجوم شیڤسن",
-       "moredotdotdot": "بیشتئر",
+       "moredotdotdot": "بؽشتر",
        "morenotlisted": "ئی نومگە کامئل بییە.",
-       "mypage": "بألگە",
+       "mypage": "بٱلگٱ",
        "mytalk": "چٱک چنٱ",
        "anontalk": "چٱک چنٱ",
        "navigation": "ناڤجۊری",
        "and": "&#32;ۉ",
-       "faq": "ئÙ\81 Ø¦Û\8c Ú©Û\8cÙ\88Ù\99",
-       "actions": "Ú©Ù\88Ù\86ئشتکاریا",
+       "faq": "اÙ\92Ù\81 Ø§Ù\9bÛ\8c Ú©Û\8cÛ\8a",
+       "actions": "Ú©Ù\88Ù\86Ø´کاریا",
        "namespaces": "نوم ڤارگٱیا",
        "variants": "آلشتگریٛا",
        "navigation-heading": "نوم جاگٱ ناڤگردی",
-       "errorpagetitle": "غألأط",
+       "errorpagetitle": "غلٱت",
        "returnto": "ڤرگٱشتن د $1.",
        "tagline": "د {{SITENAME}}",
        "help": "هومياری",
-       "search": "پاٛ جۊری",
-       "searchbutton": "پاٛ جۊری",
-       "go": "رو",
+       "search": "پاٛجۊری",
+       "searchbutton": "پاٛجۊری",
+       "go": "رۉ",
        "searcharticle": "رۉ",
        "history": "ڤیرگار بٱلگٱ",
        "history_short": "ڤیرگار",
-       "updatedmarker": "د Ø¢Ø®Ø¦Ø±Û\8c Ø¯Û\8cÛ\8cئÙ\86 Ù\85ئÙ\86Û\95 Ú¤Ø¦ هنگوم کو",
-       "printableversion": "نۏسخٱ پلا بینی",
-       "permalink": "Ù\87Ù\88Ù\85 Ù¾Ø§Ù\9bÚ¤Ù±Ù\86 Ù\87Ù±Ù\85Û\8cشاÙ\9bÛ\8cÛ\8c",
-       "print": "چاپ گئرئتئن",
+       "updatedmarker": "آخرÛ\8c Ø¯Û\8cئÙ\86 Ù\85اÙ\92 Ù\86اÙ\92 Ú¤ هنگوم کو",
+       "printableversion": "نۏسخٱ پلا بیئنی",
+       "permalink": "هوم پاٛڤٱن همیشاٛیی",
+       "print": "چاپ",
        "view": "دیئن",
-       "view-foreign": "د $1 ناْ بونؽت",
+       "view-foreign": "د $1 ناْ باٛینؽت",
        "edit": "ڤیرایش",
-       "edit-local": "تۉزی ڤلات نشینی نٱ آلشدکاری بٱکؽت",
+       "edit-local": "تۉزی ڤلات نشینی ناْ آلشتکاری بٱکؽت",
        "create": "دۏرس کردن",
        "create-local": "یاٛ تۉزی ڤلات نشینی اْزاف بٱکؽت",
        "delete": "پاکسا کردن",
-       "undelete_short": "Ù\86اپاکسا Ú©Ø¦Ø±Ø¯Ø¦Ù\86 {{PLURAL:$1|Û\8cئ Ú¯Ø¦Ù\84 Ú¤Û\8cراÛ\8cئشت|$1 Ú¤Û\8cراÛ\8cئشتÛ\8cا}}",
+       "undelete_short": "Ù\86اپاکسا Ú©Ø±Ø¯Ù\86 {{PLURAL:$1|Û\8cاÙ\9b Ú¤Û\8cراÛ\8cØ´|$1 Ú¤Û\8cراÛ\8cشؽا}}",
        "viewdeleted_short": "{{PLURAL:$1|}}سئیل بأکیت{{[PLURAL:$1|یئ گئل ڤیرایئشت پاکسا بییە|$1ڤیرایئشتیا پاکسا بیینە}}",
        "protect": "پر ۉ پیم بٱکؽت",
        "protect_change": "آلشت بٱکیٛت",
        "unprotect": "آلئشت دأئن پأر و پیم کاری",
        "newpage": "بٱلگٱ نۊ",
        "talkpagelinktext": "چٱک چنٱ",
-       "specialpage": "بألگە ڤیجە",
+       "specialpage": "بٱلگٱ ڤیژٱ",
        "personaltools": "ٱڤزارؽا شٱخسی",
        "talk": "گٱپ",
        "views": "دیئن",
        "toolbox": "ٱڤزارؽا",
-       "imagepage": "ديئن بألگە جانیا",
-       "mediawikipage": "ديئن بألگە پئيغوم",
-       "templatepage": "دیئن بٱلگٱ چۊٱ",
-       "viewhelppage": "ديئن بألگە هومیاری",
-       "categorypage": "ديئن بألگە دأسە بأنی",
-       "viewtalkpage": "دیئن چأک چئنە یا",
+       "imagepage": "ديئن بٱلگٱ جانؽا",
+       "mediawikipage": "ديئن بٱلگٱ پاٛغوم",
+       "templatepage": "دیئن بٱلگٱ چۊئٱ",
+       "viewhelppage": "ديئن بٱلگٱ هومیاری",
+       "categorypage": "ديئن بٱلگٱ دٱسٱ بٱنی",
+       "viewtalkpage": "دیئن چٱک چنٱیا",
        "otherlanguages": "ڤ زڤونیٛا هنی",
        "redirectedfrom": "(ڤاگٱردونی د$1)",
-       "redirectpagesub": "بألگە ڤاگأردوٙنی",
+       "redirectpagesub": "بٱلگٱ ڤاگٱردونی",
        "redirectto": "ڤاگٱردونی سی:",
        "lastmodifiedat": "اؽ بٱلگٱ ایسنؽا آلشت بیٱ د $1، د $2.",
-       "viewcount": "ئÛ\8c Ø¨Ø£Ù\84Ú¯Û\95 Ù\87ا Ø¯ Ø¯Ø£Ø³Ø±Ø¦Ø³Û\8c {{PLURAL:$1|Û\8cئ Ú¯Ø¦Ù\84|$1 Ú\86Ø£Ù\86 Ú¯Ø¦Ù\84}}.",
-       "protectedpage": "بألگە پأر و پیم کاری بییە",
+       "viewcount": "اؽ Ø¨Ù±Ù\84Ú¯Ù± Ù\87ا Ø¯ Ø¯Ù±Ø³Ø±Ø³Û\8c {{PLURAL:$1|Û\8cاÙ\9b Ú¯Ù\84Ù\9b|$1 Ú\86Ù±Ù\86 Ú¯Ù\84Ù\9b}}.",
+       "protectedpage": "بٱلگٱ پر ۉ پیم کاری بیٱ",
        "jumpto": "پرسن د:",
        "jumptonavigation": "ناڤجۊری",
-       "jumptosearch": "پاٛ جۊری",
+       "jumptosearch": "پاٛجۊری",
        "view-pool-error": "د بأدبأختی،ئیسئ رئسینە جایا فئرە شولوٙغە.\nکاریاریا فئرە یی میهان ئی بألگە نە سئیل بأکأن.\nدئما یە کئ میهایت د نۊ ئی بألگە نە سئیل بأکیت یئ گوری آهئرە داری بأکیت.",
-       "generic-pool-error": "د Ø¨Ø£Ø¯Ø¨Ø£Ø®ØªÛ\8cØ\8cئÛ\8cسئ Ø±Ø¦Ø³Û\8cÙ\86Û\95 Ø¬Ø§Û\8cا Ù\81ئرÛ\95 Ø´Ù\88Ù\84Ù\88Ù\99غÛ\95.\nکارÛ\8cارÛ\8cا Ù\81ئرÛ\95 Û\8cÛ\8c Ù\85Û\8cÙ\87اÙ\86 Ø¦Û\8c Ø¨Ø£Ù\84Ú¯Û\95 Ù\86Û\95 Ø³Ø¦Û\8cÙ\84 Ø¨Ø£Ú©Ø£Ù\86.\nدئÙ\85ا Û\8cÛ\95 Ú©Ø¦ Ù\85Û\8cÙ\87اÛ\8cت Ø¯ Ù\86Û\8a Ø¦Û\8c Ø¨Ø£Ù\84Ú¯Û\95 Ù\86Û\95 Ø³Ø¦Û\8cÙ\84 Ø¨Ø£Ú©Û\8cت Û\8cئ Ú¯Ù\88رÛ\8c Ø¢Ù\87ئرÛ\95 Ø¯Ø§Ø±Û\8c Ø¨Ø£Ú©Û\8cت.",
-       "pool-timeout": "گات Ø¢Ù\87ئرÛ\95 Ø¯Ø§Ø±Û\8c Ø³Û\8c Ù\82Ù\88Ù\84Ù\81 Ú©Ø¦Ø±Ø¯Ø¦Ù\86 ØªØ£Ù\85Ù\88Ù\85 Ø¨Û\8cÛ\8cÛ\95",
-       "pool-queuefull": "ئÙ\85اÛ\8cÛ\95 Ú©Ø§Ø±Û\8c Ú¯Ø¦Û\8c Ú¯Ø¦Ø±Ø¦ØªØ¦Ù\86 Ù¾Ù\88ر Ø¨Û\8cÛ\8cÛ\95",
-       "pool-errorunknown": "خأطا نادیار",
-       "pool-servererror": "پوٙل ئشمار خئذمأتگە د دأسرئس نی($1).",
-       "poolcounter-usage-error": "خأطا ڤئ کار گئرئتئن:$1",
-       "aboutsite": "دبارٱ {{SITENAME}}",
-       "aboutpage": "Project:دبارٱ",
+       "generic-pool-error": "اÛ\8cساÙ\92 Ø±Ù±Ø³Û\8cÙ\86Ù± Ø¬Ø§Û\8cا Ù\81رٱ Ø´Ù\84Ù\9bÛ\8aغٱ.\nکارÛ\8cارؽا Ù\81راÙ\9bÛ\8cؽ Ù\85ؽÙ\87اÙ\86 Ø§Ø½ Ø¨Ù±Ù\84Ú¯Ù± Ù\86اÙ\92 Ø³Ø§Ù\9bÙ\84Ù\9b Ø¨Ù±Ú©Ù±Ù\86.\nدÙ\85ا Û\8cÙ± Ú©Ø§Ù\92 Ù\85ؽÙ\87اÛ\8cت Ø¯ Ù\86Û\8a Ø§Ø½ Ø¨Ù±Ù\84Ú¯Ù± Ù\86اÙ\92 Ø³Ø§Ù\9bÙ\84Ù\9b Ø¨Ù±Ú©Ø½Øª Û\8cاÙ\9b Ú¯Ø±Ø½ Ø¢Ù\87رٱ Ø¯Ø§Ø±Û\8c Ø¨Ù±Ú©Ø½ت.",
+       "pool-timeout": "گات Ø¢Ù\87رٱ Ø¯Ø§Ø±Û\8c Ø³Û\8c Ù\82Ù\88Ù\84Ù\81 Ú©Ø±Ø¯Ù\86 ØªÙ\85Ù\88Ù\85 Ø¨Û\8cÙ±",
+       "pool-queuefull": "Ø¢Ù\85ادٱ Ú©Ø§Ø±Û\8c Ú¯Ø§Ù\9b Ú¯Ø±ØªÙ\86 Ù¾Ù\88ر Ø¨Û\8cÙ±",
+       "pool-errorunknown": "خٱتا نادؽار",
+       "pool-servererror": "پیلٛاْشمار خدمٱتگٱ د دٱسرس نؽ($1).",
+       "poolcounter-usage-error": "خٱتا ڤ کار گرتن:$1",
+       "aboutsite": "دٱربارٱ {{SITENAME}}",
+       "aboutpage": "Project:دٱربارٱ",
        "copyright": "مینۊنٱیا هان د دٱسرس $1 مٱر یٱ کاٛ ڤ یاٛ گاٛل شیڤاٛ هٱنی نیسٱنٱ بۊٱ.",
        "copyrightpage": "{{ns:project}}:کوپی رایت",
-       "currentevents": "روخ ڤنؽا ایسنی",
-       "currentevents-url": "Project:روخ ڤنؽا ایسنی",
-       "disclaimers": "تیٱپۊشکاریٛا",
+       "currentevents": "رÙ\88Ø® Ú¤Ù±Ù\86ؽا Ø§Û\8cسÙ\86Û\8c",
+       "currentevents-url": "Project:رÙ\88Ø® Ú¤Ù±Ù\86ؽا Ø§Û\8cسÙ\86Û\8c",
+       "disclaimers": "تیٱپۊشکاریا",
        "disclaimerpage": "پروژٱ: تیٱپۊشی کردن همٱگیر",
        "edithelp": "هومياری سی ڤیرایش",
        "helppage-top-gethelp": "هومياری",
        "portal-url": "پرۉژٱ:درآسونٱ کومولٱیکی",
        "privacy": "پۊلتیک رازینٱداری",
        "privacypage": "پرۉژٱ: راگوڤاری رازینٱ کاری کردن",
-       "badaccess": "خأطا صئلا دأئن",
-       "badaccess-group0": "Ø´Ù\88Ù\85ا ØµØ¦Ù\84ا Ø£Ù\86جÙ\88Ù\85 Ø¯Ø£Ø¦Ù\86 Ú©Ø§Ø±Û\8c Ù\86Û\95 Ú©Ø¦ Ù\85Û\8cÙ\87اÛ\8cت Ù\86ارÛ\8cت.",
-       "badaccess-groups": "ئÛ\8c Ú©Ø§Ø±Û\8c Ú©Ø¦ Ø´Ù\88Ù\85ا Ù\87استÛ\8cتÛ\95 Ø³Û\8c Ú©Ø§Ø±Û\8cارÛ\8cاÛ\8cÛ\8c Ú©Ø¦ Ù\87اÙ\86 Ø¯ {{PLURAL:$2|جأرغÛ\95\8cئ Ú¯Ø¦Ù\84 Ø¯ Ø¬Ø£Ø±ØºÛ\95 Û\8cا}}: $1 Ú©Ø£Ù\85 Ø¨Û\8cÛ\8cÛ\95.",
-       "versionrequired": "نوسقە $1 د مئدیاڤیکی هاستئنیە",
+       "badaccess": "خٱتا سلا داٛئن",
+       "badaccess-group0": "Ø´Ù\85ا Ø³Ù\84ا Ù±Ù\86جÙ\88Ù\85 Ø¯Ø§Ù\9bئÙ\86 Ú©Ø§Ø±Û\8c Ù\86اÙ\92 Ú©Ø§Ù\92 Ù\85ؽÙ\87اÛ\8cت Ù\86ارؽت.",
+       "badaccess-groups": "اؽ Ú©Ø§Ø±Ø½ Ú©Ø§Ù\92 Ø´Ù\85ا Ù\87استؽتٱ Ø³Û\8c Ú©Ø§Ø±Û\8cارؽاÛ\8cؽ Ú©Ø§Ù\92 Ù\87اÙ\86 Ø¯ {{PLURAL:$2|جٱرغٱ|Û\8cٱکؽ Ø¯ Ø¬Ù±Ø±ØºÙ±Û\8cا}}: $1 Ú©Ù±Ù\85 Ø¨Û\8cÙ±.",
+       "versionrequired": "نۏسخٱ $1 د مدیاڤیکی هاستنیئٱ",
        "versionrequiredtext": "نوسقە$1 مئدیاڤیکی سی ڤئ کار گئرئتئن د ئی بألگە هاستئنیە.\nسیئل ڤئ بأکیت[[Special:نوسقە|نوسقە بألگە]].",
-       "ok": "خوٙە",
+       "ok": "خۊئٱ",
        "pagetitle": "$1 - {{SITENAME}}",
        "pagetitle-view-mainpage": "{{SITENAME}}",
        "backlinksubtitle": "← $1",
        "retrievedfrom": "د نۊ زنٱ بیٱ د\"$1\"",
        "youhavenewmessages": "{{PLURAL:$3|شما دارؽت}} $1 ($2).",
        "youhavenewmessagesfromusers": "{{PLURAL:$4|شما}} $1 د {{PLURAL:$3|کاریار هنی|$3 کاریارؽا}}دارؽت($2).",
-       "youhavenewmessagesmanyusers": "Ø´Ù\88Ù\85ا Ø¯ $1 Ù\81ئرÛ\95 Ú©Ø§Ø±Û\8cار Ø¯Ø§Ø±Û\8cت($2).",
+       "youhavenewmessagesmanyusers": "Ø´Ù\85ا Ø¯ $1 Ù\81رٱ Ú©Ø§Ø±Û\8cار Ø¯Ø§Ø±Ø½ت($2).",
        "newmessageslinkplural": "{{PLURAL:$1|یاٛ پاٛغوم تازٱ|999=پاٛغومؽا تازٱ}}",
        "newmessagesdifflinkplural": "آخر {{PLURAL:$1|آلشت|آلشتؽا}}",
-       "youhavenewmessagesmulti": "Ø´Ù\88Ù\85ا Û\8cئ Ú¯Ø¦Ù\84 Ù¾Ø¦Û\8cغÙ\88Ù\85 ØªØ§Ø²Û\95 Ø¯ $1 Ø¯Ø§Ø±Û\8cت",
-       "editsection": "Ø¢Ù\84شدکاری",
+       "youhavenewmessagesmulti": "Ø´Ù\85ا Û\8cاÙ\9b Ù¾Ø§Ù\9bغÙ\88Ù\85 ØªØ§Ø²Ù± Ø¯ $1 Ø¯Ø§Ø±Ø½ت",
+       "editsection": "Ø¢Ù\84شتکاری",
        "editold": "ڤیرایش",
-       "viewsourceold": "ساÙ\9bÙ\84Ù\9b Ø¯ Ø³Ø±Ú\86Ø´Ù\85Ù± Ø¨Ù±Ú©Ø½Øª",
+       "viewsourceold": "ساٛلٛ سرچشمٱ بٱکؽت",
        "editlink": "ڤیرایش",
-       "viewsourcelink": "ساÙ\9bÙ\84Ù\9b Ø¯ Ø³Ø±Ú\86Ø´Ù\85Ù± Ø¨Ù±Ú©Ø½Øª",
+       "viewsourcelink": "ساٛلٛ سرچشمٱ بٱکؽت",
        "editsectionhint": "ڤیرایش یاٛ بٱئرجا:$1",
        "toc": "مؽنونٱیا",
-       "showtoc": "Ù\86ئشÙ\88Ù\99 Ø¯Ø£ئن",
-       "hidetoc": "قام کئردئن",
-       "collapsible-collapse": "جأم کئردئن",
-       "collapsible-expand": "گأپ کئلوٙن کئردئن",
-       "confirmable-confirm": "{{GENDER:$1|Ø´Ù\88Ù\85ا}} Ø¦Ø·Ù\85ئÙ\86Ù\88Ù\99Ù\86 Ø¯Ø§Ø±Û\8cت?",
-       "confirmable-yes": "هأری",
-       "confirmable-no": "نە",
-       "thisisdeleted": "دÛ\8cئÙ\86 Û\8cا Ú¤Ø¦Ø±Ú¯Ø£Ù\86Û\8cیئن $1?",
+       "showtoc": "Ù\86Ø´Ù\88Ý© Ø¯Ø§Ù\9bئن",
+       "hidetoc": "قایم کردن",
+       "collapsible-collapse": "جٱم کردن",
+       "collapsible-expand": "گٱپ کلون کردن",
+       "confirmable-confirm": "{{GENDER:$1|Ø´Ù\85ا}} Ø§Ù\92تÙ\85Û\8cÙ\86Ù\88Ý© Ø¯Ø§Ø±Ø½ت?",
+       "confirmable-yes": "عٱ",
+       "confirmable-no": "نٱ",
+       "thisisdeleted": "دÛ\8cئÙ\86 Û\8cا Ú¤Ø±Ú¯Ù±Ø±Ø¯Ù\86یئن $1?",
        "viewdeleted": "دیئن$1?",
-       "restorelink": "{{PLURAL:$1|Û\8cئ Ú¯Ø¦Ù\84 Ú¤Û\8cراÛ\8cئشت Ù¾Ø§Ú©Ø³Ø§ Ø¨Û\8cÛ\8cÛ\95|$1 Ú¤Û\8cراÛ\8cئشتÛ\8cا Ù¾Ø§Ú©Ø³Ø§ Ø¨Û\8cÛ\8cÛ\95}}",
-       "feedlinks": "هأڤال حوٙن:",
-       "feed-invalid": "جوٙر هومبأر بییە مینجا هأڤال حوٙن نادیار",
-       "feed-unavailable": "هأڤال حوٙنیا د دأسرئس نییئن",
-       "site-rss-feed": "هأڤال حوٙن RSS سی $1",
-       "site-atom-feed": "هوڤال هۊ Atom سی $1",
-       "page-rss-feed": "هأڤال حوٙن RSS سی «$1»",
-       "page-atom-feed": "هٱڤال هۊن Atom سی $1",
+       "restorelink": "{{PLURAL:$1|Û\8cاÙ\9b Ú¤Û\8cراÛ\8cØ´ Ù¾Ø§Ú©Ø³Ø§ Ø¨Û\8cÙ±|$1 Ú¤Û\8cراÛ\8cشؽا Ù¾Ø§Ú©Ø³Ø§ Ø¨Û\8cÙ±}}",
+       "feedlinks": "هڤال ڤٱن:",
+       "feed-invalid": "جۊر هومبٱر بیٱ مؽنجا هڤال ڤٱن نادؽار",
+       "feed-unavailable": "هڤال ڤٱنؽا د دٱسرس نؽسن",
+       "site-rss-feed": "هڤال ڤٱن RSS سی $1",
+       "site-atom-feed": "هڤال ڤٱن Atom سی $1",
+       "page-rss-feed": "هڤال ڤٱن RSS سی «$1»",
+       "page-atom-feed": "هڤال ڤٱن Atom سی $1",
        "feed-atom": "اتم",
        "feed-rss": "آر اس اس",
        "red-link-title": "$1(بٱلگٱ نؽسش)",
-       "sort-descending": "کأم بییئن سأرجاخود",
-       "sort-ascending": "زياد بيیئن سأرجادخود",
+       "sort-descending": "کٱم بیئن سٱرجاخود",
+       "sort-ascending": "زؽاد بيئن سٱرجادخود",
        "nstab-main": "بٱلگٱ",
        "nstab-user": "بٱلگٱ کاریار",
-       "nstab-media": "بألگە ڤارئسگأر",
+       "nstab-media": "بٱلگٱ ڤارٱسگٱر",
        "nstab-special": "بٱلگٱیا ڤیژٱ",
        "nstab-project": "بٱلگٱ پرۉژٱ",
        "nstab-image": "جانؽا",
        "nstab-mediawiki": "پاٛغوم",
-       "nstab-template": "چۊٱ",
-       "nstab-help": "بألگە هومیاری",
+       "nstab-template": "چۊئٱ",
+       "nstab-help": "بٱلگٱ هومیاری",
        "nstab-category": "دٱسٱ",
        "mainpage-nstab": "سرآسونٱ",
-       "nosuchaction": "چئنی کونئشتگأری نییئش",
-       "nosuchactiontext": "کارÛ\8c Ú©Ø¦ Ú¤Ø§ Û\8cÙ\88Ù\99 Ø¢Ø± Ø¦Ù\84 ØªÛ\8cار Ø¨Û\8cÛ\8cÛ\95 Ù\86ادÛ\8cارÛ\95.\nگاسÛ\8c Ø´Ù\88Ù\85ا Û\8cÙ\88Ù\99 Ø¢Ø± Ø¦Ù\84 Ù\86Û\95 Ø¯Ù\88رÙ\88س Ù\86Ø£Ù\86Û\8cسأÙ\86Û\8cتÛ\95Ø\8c Û\8cا Û\8cئ Ú¯Ø¦Ù\84 Ù\87Ù\88Ù\85 Ù¾Ø¦Û\8cڤأÙ\86د Ø¦Ø´ØªØ¦Ú¤Ø§ Ú¤Ø§Ø±Ø¦Ø¯ Ø¨Û\8cÛ\8cÛ\95.\nڤئ Ú¯Ø§Ø³Û\8c Û\8cئ Ú¯Ø¦Ù\84 Ø³Û\8cسئرÛ\8cÚ© Ø¯ Ù\86أرÙ\85 Ø£Ù\81زاز Ú¤Ø¦ Ú©Ø§Ø± Ú¯Ø¦Ø±Ø¦ØªÛ\95 Ø¨Û\8cÛ\8cÛ\95 Ú¤Ø§ {{SITENAME}} Ø¦Ø´Ø§Ø±Û\95 Ø¨Ø£Ú©Û\95.",
-       "nosuchspecialpage": "چنی بٱلگاٛ ڤیژاٛیی نؽسش",
+       "nosuchaction": "چنی کنشگٱری نؽسش",
+       "nosuchactiontext": "کارÛ\8c Ú©Ø§Ù\92 Ú¤Ø§ Û\8cÛ\8a Ø¢Ø± Ø§Ù\92Ù\84 ØªØ½Ø§Ø± Ø¨Û\8cÙ± Ù\86ادؽارٱ.\nگاسؽ Ø´Ù\85ا Û\8cÛ\8a Ø¢Ø± Ø§Ù\92Ù\84 Ù\86اÙ\92 Ø¯Û\8fرس Ù\86Ù±Ù\86Û\8cسأÙ\86ؽتٱØ\8c Û\8cا Û\8cاÙ\9b Ù\87Ù\88Ù\85 Ù¾Ø§Ù\9bÚ¤Ù±Ù\86 Ø§Ù\92شتبا Ú¤Ø§Ø±Ø¯ Ø¨Û\8cÙ±.\nگاسؽ Û\8cاÙ\9b Ø³Û\8cسرÛ\8cÚ© Ø¯ Ù\86ٱرÙ\85 Ù±Ù\81زاز Ú¤ Ú©Ø§Ø± Ú¯Ø±ØªÙ± Ø¨Û\8cÙ± Ú¤Ù± {{SITENAME}} Ø§Ù\92شارٱ Ø¨Ù±Ú©Ù±.",
+       "nosuchspecialpage": "چنی بٱلگٱ ڤیژاٛیؽ نؽسش",
        "nospecialpagetext": "<strong>شما یاٛ بٱلگٱ نادؽار ناْ هاستؽتٱ.</strong>\nگاسی یاٛ نومگٱ سی دؽاری داٛئن د بٱلگٱیا بایٱد د [[Special:SpecialPages|{{int:specialpages}}]] دؽاری بٱکٱ.",
-       "error": "خأطا",
-       "databaseerror": "خأطا د رئسینە گا",
-       "databaseerror-text": "Û\8cئ Ú¯Ø¦Ù\84 Ø®Ø£Ø·Ø§ Ø¬Ù\88ست Ú©Ø§Ø±Û\8c Ø¯ Ø±Ø¦Ø³Û\8cÙ\86Û\95 Ú¯Ø§ Ø¯Û\8cارÛ\8c Ú©Ø¦Ø±Ø¯Û\95.گاسÛ\8c Û\8cÛ\95 Û\8cئ Ú¯Ù\84 Ø³Û\8cسئرÛ\8cÚ© Ø¯ Ú©Ø§Ø± Ú¯Ø¦Ø±Ø¦ØªØ¦Ù\86 Ù\86أرÙ\85 Ø£Ù\81زار Ø±Ø§Ø³ Ø¨Ø£Ú©Û\95.",
-       "databaseerror-textcl": "Û\8cئ Ú¯Ø¦Ù\84 Ø®Ø£Ø·Ø§ Ø¬Ù\88ست Ú©Ø§Ø±Û\8c Ø¯ Ø±Ø¦Ø³Û\8cÙ\86Û\95 Ú¯Ø§ Ø¯Û\8cارÛ\8c Ú©Ø¦Ø±Ø¯Û\95.",
-       "databaseerror-query": "جوستکاری: $1",
-       "databaseerror-function": "Ø¢Ù\84ئشت Ú¤Ø£ن:$1",
-       "databaseerror-error": "خأطا: $1",
-       "laggedslavemode": "ڤارئسدار بوٙییت:گاسی بألگە د ڤأر گئرئتە ڤئ هئنگوم سازیا ئیسئنی نبوٙە",
-       "readonly": "رئسینە گا قولف بییە",
-       "enterlockreason": "دألیل قولف کئردئن نە بأنیسیت، کئ ڤە د ڤأرگئرئتە گات ڤا کئردئن قولف با",
+       "error": "خٱتا",
+       "databaseerror": "خٱتا د رٱسینٱگا",
+       "databaseerror-text": "Û\8cاÙ\9b Ø®Ù±ØªØ§ Ø¬Û\8fس Ú©Ø§Ø±Û\8c Ø¯ Ø±Ù±Ø³Û\8cÙ\86ٱگا Ø¯Ø½Ø§Ø±Û\8c Ú©Ø±Ø¯Ù±.گاسؽ Û\8cÙ± Û\8cاÙ\9b Ø³Û\8cسرÛ\8cÚ© Ø¯ Ú©Ø§Ø± Ú¯Ø±ØªÙ\86 Ù\86ٱرÙ\85 Ù±Ù\81زار Ø¯Û\8fرس Ø¨Ù±Ú©Ù±.",
+       "databaseerror-textcl": "Û\8cاÙ\9b Ø®Ù±ØªØ§ Ø¬Û\8fس Ú©Ø§Ø±Û\8c Ø¯ Ø±Ù±Ø³Û\8cÙ\86ٱگا Ø¯Ø½Ø§Ø±Û\8c Ú©Ø±Ø¯Ù±.",
+       "databaseerror-query": "جۏستکاری: $1",
+       "databaseerror-function": "Ø¢Ù\84شت Ú¤Ù±ن:$1",
+       "databaseerror-error": "خٱتا: $1",
+       "laggedslavemode": "ڤارٱسدار بۊیؽت:گاسؽ بٱلگٱ د ڤٱر گرتٱ ڤ هٱنگوم سازؽا ایسنی نمۊئٱ",
+       "readonly": "رٱسینٱگا قولف بیٱ",
+       "enterlockreason": "دلٛیلٛ قولف کردن ناْ بٱنیسؽت، کاْ ڤٱ د ڤٱرگرتٱ گات ڤا کردن قولف با",
        "readonlytext": "رئسینە گا ئیسئ سی دأئن ڤوروٙدی یا هأنی یا آلئشتگئریا هأنی قولف بییە، گاسی سی بییئن مأموٙلی رئسینە گایا ڤاگأردوٙنی بوٙە ڤئ حال و بال أڤئلی خوش.\nدیڤوٙنداری کئ ڤئنە قولف کئردە ڤئنە گوتە:$1",
        "missing-article": "رئسینە گا نئمی توٙنە بألگە یی نە باس بوٙأش و نوٙمئش $1و $2 با بأجوٙرە.\n\nمأموٙلأند سی یە کئ فأرخ هوم پئیڤأند ڤیرگار د ئو بألگە پاکسیا بییە دیاری نئمی کە.\n\nأر یە چی موهئمی سیتوٙ نی، گاسی شوما یئ گئل سیسئریک د نأرم أفزار خوتوٙ داریت.\nلوطف بأکیت ڤئنە سی ڤئنوٙ [[Special:نوٙمگە کاریاریا/سی یوٙسوٙپ|دیڤوٙنکاریا]]کئل بأکیت و دش دئباره تیرنئشوٙن آی پیتوٙ ڤئشوٙ بوٙییت.",
-       "missingarticle-rev": "(ڤانیأری#: $1)",
-       "missingarticle-diff": "(فأرخ: $1، $2)",
-       "readonly_lag": "ئÛ\8c Ø±Ø¦Ø³Û\8cÙ\86Û\95 Ú¯Ø§ Ù\82Ù\88Ù\84Ù\81 Ø¨Û\8cÛ\8cÛ\95 ØªØ§ Ú¯Ø§ØªÛ\8c Ú©Ø¦ Ø³Ø¦Ø±Ú¤Ø¦Ø± Ø±Ø¦Ø³Û\8cÙ\86Û\95 Ú¯Ø§ Ø¨Ø£Ø±Ø£Ø³Û\95 Ú¤Ø¦ Û\8cئ Ú¯Ø¦Ù\84 Ù\85Û\8cÙ\86جاڤأن.",
-       "internalerror": "خأطا مینجایی",
-       "internalerror_info": "خأطا مینجایی:$1",
-       "internalerror-fatal-exception": "تیە داشتئن مأرگبار جوٙر \"$1\"",
-       "filecopyerror": "نأبوٙە جانیا $1 د $2 ڤورداشتە بوٙە",
-       "filerenameerror": "نأبوٙە نوم جانیا $1 د $2 آلئشت کاری بوٙە.",
-       "filedeleteerror": "نأبوٙە جانیا $1 پاکسا بوٙە.",
-       "directorycreateerror": "نأبوٙە تیرنئشوٙنگە $1 راس بوٙە.",
-       "directoryreadonlyerror": "فأقأط بوٙە تیرنئشوٙنگە \"$1\" نە بوٙحوٙنی.",
-       "directorynotreadableerror": "تÛ\8cرÙ\86ئشÙ\88Ù\99Ù\86Ú¯Û\95 \"$1\" Ø­Ø£Ù\86ئÙ\86Û\8c Ù\86Û\8c.",
-       "filenotfound": "نأتوٙنیت جانیا $1 نە بأجوٙریت.",
-       "unexpected": "أرزایئت ناهاستە: \"$1\"=\"$2\".",
-       "formerror": "خأطا:نأبوٙە نوم بألگە نە ڤئ موٙ بوٙییت.",
-       "badarticleerror": "ئÛ\8c Ú©Ù\88Ù\86ئشتکارÛ\8c Ø¯ Ø¦Û\8c Ø¨Ø£Ù\84Ú¯Û\95 Ø£Ù\86جÙ\88Ù\85 Ù\86أبÙ\88Ù\99Û\95.",
-       "cannotdelete": "نأبوٙە بألگە یا جانیا $1 پاکسا با.\nگاسی د ئیسئنی کئسی تئر ڤئ نە پاکسا کئردە.",
-       "cannotdelete-title": "نأبوٙە بألگە $1 پاکسا با",
-       "delete-hook-aborted": "پاکسا کاری ڤا قولاڤ نئها گئری بیە.\nهیچ توضیی سیش نی.",
-       "no-null-revision": "سی بألگە $1 ڤانیأری خومثا نە راس بأکیت",
-       "badtitle": "داسوݩ گٱن",
-       "badtitletext": "داسوݩ بٱلگٱ هاستنی نادؽارٱ، یٱ یاٛ داسوݩ مؽنجا زڤونی یا مؽنجا ڤیکی اْشتبائٱ.\nگاسؽ یٱ د ڤٱر گرتٱ یاٛ کاراکتر یا چٱن تا کاراکتر با کاْ نمۊئٱ د داسونؽا ڤ کارشو گرت.",
-       "title-invalid-empty": "داسÙ\88Ù\99Ù\86 Ø¨Ø£Ù\84Ú¯Û\95 Ù\87استئÙ\86Û\8c Ø­Ø§Ù\84Û\8cÛ\95 Û\8cا Ù\81Ø£Ù\82أط Ù\85Û\8cÙ\86Ù\88Ù\99Ù\86Û\95 Ø¯Ø§Ø± Û\8cئ Ú¯Ø¦Ù\84 Ù\86Ù\88Ù\99Ù\85 Û\8cا Ù\86Ù\88Ù\99Ù\85 Ø¬Ø§Û\95.",
-       "title-invalid-utf8": "داسÙ\88Ù\99Ù\86 Ø¨Ø£Ù\84Ú¯Û\95 Ù\87استئÙ\86Û\8c Ù\85Û\8cÙ\86Ù\88Ù\99Ù\86Û\95 Ø¯Ø§Ø± Û\8cئ Ú¯Ø¦Ù\84 Ù\86ئÙ\85اجا UTF-8 Ù\86ادÛ\8cارÛ\95.",
-       "title-invalid-interwiki": "داسÙ\88Ù\99Ù\86 Ø¨Ø£Ù\84Ú¯Û\95 Ù\87استئÙ\86Û\8c Ù\85Û\8cÙ\86Ù\88Ù\99Ù\86Û\95 Ø¯Ø§Ø± Û\8cئ Ú¯Ø¦Ù\84 Ù\87Ù\88Ù\85 Ù¾Ø¦Û\8cڤأÙ\86دÛ\95 Ú©Ø¦ Ù\86أبÙ\88Ù\99Û\95 Ø¯ Ø¯Ø§Ø³Ù\88Ù\99Ù\86Û\8cا Ú¤Ø¦ Ú©Ø§Ø± Ú¯Ø¦Ø±Ø¦ØªÛ\95 Ø¨Ù\88Ù\99Û\95.",
-       "title-invalid-talk-namespace": "داسÙ\88Ù\99Ù\86 Ø¨Ø£Ù\84Ú¯Û\95 Ù\87استئÙ\86Û\8c Ú¤Ø¦ Û\8cئ Ú¯Ø¦Ù\84 Ø¨Ø£Ù\84Ú¯Û\95 Ú\86Ø£Ú© Ú\86ئÙ\86Û\95 Ú©Ø¦ Ù\86Û\8cÛ\8cئش Ø¦Ø´Ø§Ø±Û\95 Ù\85Û\8cÚ©Û\95.",
-       "title-invalid-characters": "داسÙ\88Ù\99Ù\86 Ø¨Ø£Ù\84Ú¯Û\95 Ù\87استئÙ\86Û\8c Ù\85Û\8cÙ\86Ù\88Ù\99Ù\86Û\95 Ø¯Ø§Ø± Û\8cئ Ú¯Ø¦Ù\84 Ú©Ø§Ø±Ø§Ú©ØªØ±Ù\87:$1 Ù\86ادÛ\8cارÛ\95.",
-       "title-invalid-relative": "داسÙ\88Ù\99Ù\86 Û\8cئ Ú¯Ø¦Ù\84 Ù\84ا Ù\87Ù\88Ù\85 Ø¯Ø£Ù\86Ú¯ Ø¯Ø§Ø±Û\95.داسÙ\88Ù\99Ù\86 Ø¨Ø£Ù\84Ú¯Û\95 Ù\87Ù\88Ù\85 Ø¯Ø£Ù\86Ú¯(./, ../) Ù\86ادÛ\8cارÛ\95Ø\8c Ø³Û\8c Û\8cÛ\95 Ú©Ø¦ Ú¤Ø¦Ù\86Ù\88Ù\99 Ø£Ú©Ø«Ø£Ø±Ø£Ù\86 Ø¯ Ú¯Ø§ØªÛ\8c Ú©Ø¦ Ø¯Ù\88ڤارتÛ\95 Ù\86Û\8cأر Ú¤Ø¦ Ø¯Ø£Ø³ Ú©Ø§Ø±Û\8cار Ø¯Ø£Ø³Û\8c Ø³Ø§Ø²Û\8c Ø¨Ù\88Ù\99Û\95 Ø¯Û\8cارÛ\8c Ù\86ئÙ\85Û\8cÚ©Ø£ن.",
-       "title-invalid-magic-tilde": "داسÙ\88Ù\99Ù\86 Ø¨Ø£Ù\84Ú¯Û\95 Ø­Ø§Ø³ØªØ¦Ù\86Û\8c Ù\85Û\8cÙ\86Ù\88Ù\99Ù\86Û\95 Ø¯Ø§Ø± Û\8cئ Ú¯Ø¦Ù\84 Ù\86ئÙ\85اجا Ø¬Ø§Ø¯Ù\88Ù\99Û\8cÛ\8c Ù\86ادÛ\8cارÛ\95(<nowiki>~~~</nowiki>).",
+       "missingarticle-rev": "(ڤانیٱری#: $1)",
+       "missingarticle-diff": "(فٱرخ: $1، $2)",
+       "readonly_lag": "اؽ Ø±Ù±Ø³Û\8cÙ\86ٱگا Ù\82Ù\88Ù\84Ù\81 Ø¨Û\8cÙ± ØªØ§ Ú¯Ø§ØªØ½ Ú©Ø§Ù\92 Ø³Ø±Ú¤Ø± Ø±Ù±Ø³Û\8cÙ\86ٱگا Ø¨Ù±Ø±Ù±Ø³Ù± Ú¤ Û\8cاÙ\9b Ù\85ؽÙ\86جاڤٱن.",
+       "internalerror": "خٱتا مؽنجایی",
+       "internalerror_info": "خٱتا مؽنجایی:$1",
+       "internalerror-fatal-exception": "تیٱ داشتن مٱرگبار جۊر \"$1\"",
+       "filecopyerror": "نمۊئٱ جانؽا $1 د $2 ڤرداشتٱ بۊئٱ",
+       "filerenameerror": "نمۊئٱ نوم جانؽا $1 د $2 آلشت کاری بۊئٱ.",
+       "filedeleteerror": "نمۊئٱ جانؽا $1 پاکسا بۊئٱ.",
+       "directorycreateerror": "نمۊئٱ تیرنشونگٱاٛ$1 دۏرس بۊئٱ.",
+       "directoryreadonlyerror": "فقٱت مۊئٱ تیرنشونگٱ \"$1\" ناْ بونی.",
+       "directorynotreadableerror": "تÛ\8cرÙ\86Ø´Ù\88Ù\86Ú¯Ù± \"$1\" Ú¤Ù±Ù\86Ù\86Û\8c Ù\86ؽ.",
+       "filenotfound": "نمؽ تونؽت جانؽا $1 ناْ بٱجۊرؽت.",
+       "unexpected": "ٱرزایش نهاستٱ: \"$1\"=\"$2\".",
+       "formerror": "خٱتا:نمۊئٱ نوم بٱلگٱ ناْ ڤمو بۉیؽت.",
+       "badarticleerror": "اؽ Ú©Ù\86شکارÛ\8c Ø¯ Ø§Ø½ Ø¨Ù±Ù\84Ú¯Ù± Ù±Ù\86جÙ\88Ù\85 Ù\86Ù\85Û\8aئٱ.",
+       "cannotdelete": "نمۊئٱ بٱلگٱیا جانؽا $1 پاکسا با.\nگاسؽ د ایسنی کٱسؽ تر ڤٱ ناْ پاکسا کردٱ.",
+       "cannotdelete-title": "نمۊئٱ بٱلگٱ $1 پاکسا با",
+       "delete-hook-aborted": "پاکسا کاری ڤا قولاڤ نوئاگیری بیٱ.\nهیچ تۉزیهی سیش نؽ.",
+       "no-null-revision": "سی بٱلگٱ $1 ڤانیٱری خونسا ناْ دۏرس بٱکؽت",
+       "badtitle": "داسون گٱن",
+       "badtitletext": "داسون بٱلگٱ هاستنی نادؽارٱ، یٱ یاٛ داسوݩ مؽنجا زڤونی یا مؽنجا ڤیکی اْشتبائٱ.\nگاسؽ یٱ د ڤٱر گرتٱ یاٛ کاراکتر یا چٱن تا کاراکتر با کاْ نمۊئٱ د داسونؽا ڤ کارشو گرت.",
+       "title-invalid-empty": "داسÙ\88Ù\86 Ø¨Ù±Ù\84Ú¯Ù± Ù\87استÙ\86Û\8c Ù\87اÙ\84Ù\9bÛ\8cÙ± Û\8cا Ù\81Ù\82ٱت Ù\85ؽÙ\86Ù\88Ù\86Ù± Ø¯Ø§Ø± Û\8cاÙ\9b Ù\86Ù\88Ù\85 Û\8cا Ù\86Ù\88Ù\85 Ø¬Ø§ Ø¦Ù±.",
+       "title-invalid-utf8": "داسÙ\88Ù\86 Ø¨Ù±Ù\84Ú¯Ù± Ù\87استÙ\86Û\8c Ù\85ؽÙ\86Ù\88Ù\86Ù± Ø¯Ø§Ø± Û\8cاÙ\9b Ù\86Ù\85اجا UTF-8 Ù\86ادؽارٱ.",
+       "title-invalid-interwiki": "داسÙ\88Ù\86 Ø¨Ù±Ù\84Ú¯Ù± Ù\87استÙ\86Û\8c Ù\85ؽÙ\86Ù\88Ù\86Ù± Ø¯Ø§Ø± Û\8cاÙ\9b Ù\87Ù\88Ù\85 Ù¾Ø§Ù\9bÚ¤Ù±Ù\86 Ø¦Ù± Ú©Ø§Ù\92 Ù\86Ù\85Û\8aئٱ Ø¯ Ø¯Ø§Ø³Ù\88Ù\86ؽا Ú¤ Ú©Ø§Ø± Ú¯Ø±ØªÙ± Ø¨Û\8aئٱ.",
+       "title-invalid-talk-namespace": "داسÙ\88Ù\86 Ø¨Ù±Ù\84Ú¯Ù± Ù\87استÙ\86Û\8c Ú¤ Û\8cاÙ\9b Ø¨Ù±Ù\84Ú¯Ù± Ú\86Ù±Ú© Ú\86Ù\86Ù± Ú©Ø§Ù\92 Ù\86ؽسش Ø§Ù\92شارٱ Ù\85ؽکٱ.",
+       "title-invalid-characters": "داسÙ\88Ù\86 Ø¨Ù±Ù\84Ú¯Ù± Ù\87استÙ\86Û\8c Ù\85ؽÙ\86Ù\88Ù\86Ù± Ø¯Ø§Ø± Û\8cاÙ\9b Ú©Ø§Ø±Ø§Ú©ØªØ±Ù±:$1 Ù\86ادؽارٱ.",
+       "title-invalid-relative": "داسÙ\88Ù\86 Û\8cاÙ\9b Ù\84Ù\9bا Ù\87Ù\88Ù\85 Ø¯Ù±Ù\86Ú³ Ø¯Ø§Ø±Ù±.داسÙ\88Ù\86 Ø¨Ù±Ù\84Ú¯Ù± Ù\87Ù\88Ù\85 Ø¯Ù±Ù\86Ú³(./, ../) Ù\86ادؽارٱØ\8c Ø³Û\8c Û\8cÙ± Ú©Ø§Ù\92 Ú¤Ù\86Ù\88 Ø¨Ø½Ø´ØªØ±Ø´Ù\88 Ø¯ Ú¯Ø§ØªØ½ Ú©Ø§Ù\92 Ø¯Ù\88ئارتٱ Ù\86Û\8cٱر Ú¤ Ø¯Ù±Ø³ Ú©Ø§Ø±Û\8cار Ø¯Ù±Ø³Û\8c Ø³Ø§Ø²Û\8c Ø¨Û\8aئٱ Ø¯Ø½Ø§Ø±Û\8c Ù\86Ù\85ؽکٱن.",
+       "title-invalid-magic-tilde": "داسÙ\88Ù\86 Ø¨Ù±Ù\84Ú¯Ù± Ù\87استÙ\86Û\8c Ù\85Û\8cÙ\86Ù\88Ù\86Ù± Ø¯Ø§Ø± Û\8cاÙ\9b Ù\86Ù\85اجا Ø¬Ø§Ø¯Û\8aÛ\8cÛ\8c Ù\86ادؽارٱ(<nowiki>~~~</nowiki>).",
        "title-invalid-too-long": "داسوٙن بألگە حاستئنی فئرە گأپە. د حال و بار رازینە کاری UTF-8 أنازە ڤئ نأباس د $1 بایت گأپتأر بوٙە.",
-       "title-invalid-leading-colon": "داسÙ\88Ù\99Ù\86 Ø¨Ø£Ù\84Ú¯Û\95 Ø­Ø§Ø³ØªØ¦Ù\86Û\8c Ù\85Û\8cÙ\86Ù\88Ù\99Ù\86Û\95 Ø¯Ø§Ø± Û\8cئ Ú¯Ø¦Ù\84 Ú©Ù\88Ù\84Ù\88Ù\99Ù\86 Ù\86ادÛ\8cار Ø¯ Ø£Ú¤Ø£Ù\84 Ú©Ø§Ø±Ø¦Ø´Û\95.",
+       "title-invalid-leading-colon": "داسÙ\88Ù\86 Ø¨Ù±Ù\84Ú¯Ù± Ù\87استÙ\86Û\8c Ù\85ؽÙ\86Ù\88Ù\86Ù± Ø¯Ø§Ø± Û\8cاÙ\9b Ú©Ù\88Ù\84Ù\88Ù\86 Ù\86ادؽار Ø¯ Ù±Ú¤Ù±Ù\84 Ú©Ø§Ø±Ø´Ù±.",
        "perfcached": "رئسینە یا نئهایی د ڤیرگە قام بییە موٙکیس بینە و گاسی هأنی ڤئ هئنگوم سازی نأبینە.بیشتئروٙنە {{PLURAL:$4|یئ گئل نأتیجە|$4 یئ گئل نأتیجە}} د ڤیرگە قام بییە هان د دأسرئس.",
-       "perfcachedts": "رئسÛ\8cÙ\86Û\95 Û\8cا Ù\86ئÙ\87اÛ\8cÛ\8c Ø¯ Ú¤Û\8cرگÛ\95 Ù\82اÙ\85 Ø¨Û\8cÛ\8cÛ\95 Ù\85Ù\88Ù\99Ú©Û\8cس Ø¨Û\8cÙ\86Û\95 Ù\88 Ú¯Ø§Ø³Û\8c Ù\87Ø£Ù\86Û\8c Ú¤Ø¦ Ù\87ئÙ\86Ú¯Ù\88Ù\85 Ø³Ø§Ø²Û\8c Ù\86أبÛ\8cÙ\86Û\95.بÛ\8cشتئرÙ\88Ù\99Ù\86Û\95 {{PLURAL:$4|Û\8cئ Ú¯Ø¦Ù\84 Ù\86أتÛ\8cجÛ\95|$4 Û\8cئ Ú¯Ø¦Ù\84 Ù\86أتÛ\8cجÛ\95}} Ø¯ Ú¤Û\8cرگÛ\95 Ù\82اÙ\85 Ø¨Û\8cÛ\8cÛ\95 Ù\87اÙ\86 Ø¯ Ø¯Ø£Ø³Ø±Ø¦س.",
-       "querypage-no-updates": "نأبوٙە ئی بألگە ڤئ هئنگوم سازی با.\nرئسینە یا ئیچئ تازە کاری نأبینە.",
-       "viewsource": "ساÙ\9bÙ\84Ù\9b Ø¯ Ø³Ø±Ú\86Ø´Ù\85Ù± Ø¨Ù±Ú©Ø½Øª",
-       "viewsource-title": "ساÙ\9bÙ\84Ù\9b Ø¯ Ø³Ø±Ú\86Ø´Ù\85Ù± $1 Ø¨Ù±Ú©Ø½Øª",
-       "actionthrottled": "Ú©Ù\88Ù\86ئشتکارÛ\8c Ù\86ئÙ\87اگئرÛ\8c Ø¨Û\8cÛ\8cÛ\95",
+       "perfcachedts": "رسÛ\8cÙ\86Ù±Û\8cا Ù\86Ù\87اÛ\8cÛ\8c Ø¯ Ú¤Û\8cرگٱ Ù\82اÛ\8cÙ\85 Ø¨Û\8cÙ± Ù\85Û\8aÚ©Û\8cس Ø¨Û\8cÙ\86Ù± Û\89 Ú¯Ø§Ø³Ø½ Ù\87Ù\86Û\8c Ú¤ Ù\87Ù\86Ú¯Ù\88Ù\85 Ø³Ø§Ø²Û\8c Ù\86اÙ\9bÛ\8cÙ±.بؽشترÙ\88Ù\86Ù± {{PLURAL:$4|Û\8cاÙ\9b Ù\86ٱتÛ\8cجٱ|$4 Û\8cاÙ\9b Ù\86ٱتÛ\8cجٱ}} Ø¯ Ú¤Û\8cرگٱ Ù\82اÛ\8cÙ\85 Ø¨Û\8cÙ± Ù\87اÙ\86 Ø¯ Ø¯Ù±Ø³Ø±س.",
+       "querypage-no-updates": "نمۊئٱ اؽ بٱلگٱ ڤ هنگوم سازی با.\nرسینٱیا ایچاْ تازٱ کاری ناٛیٱ.",
+       "viewsource": "ساٛلٛ سرچشمٱ بٱکؽت",
+       "viewsource-title": "ساٛلٛ سرچشمٱ $1 بٱکؽت",
+       "actionthrottled": "Ú©Ù\88Ù\86شکارÛ\8c Ù\86Ù\87اگÛ\8cرÛ\8c Ø¨Û\8cÙ±",
        "actionthrottledtext": "سی نئهاگئری د دأرتیچ بییئن ئسپأم نأبوٙە کئ شوما چئنی کاری نە د یئ گاتی کوٙتا چأن گئل أنجوم بئییت.\nلوطف بأکیت د چأن دئیقە هأنی د نۊ تئلاش بأکیت.",
-       "protectedpagetext": "نأبوٙە د ئی بألگە ڤیرایئشت کاریا کاریاریا هأنی نە سئیل بأکیت.",
+       "protectedpagetext": "نمۊئٱ د اؽ بٱلگٱ ڤیرایش کاریا کاریارؽا هنی ناْ ساٛلٛ بٱکؽت.",
        "viewsourcetext": "شما مؽ تونؽت سرچشمٱ اؽ بٱلگٱ ناْ ساٛلٛ بٱکؽت ۉ دش ڤردارؽت:",
        "viewyourtext": "شوما می توٙنیت سأرچئشمە ڤیرایئشتیا توٙنە د ئی بألگە سئیل بأکیت و دئشوٙ ڤئرداریت:",
-       "protectedinterface": "ئÛ\8c Ø¨Ø£Ù\84Ú¯Û\95 Ø³Û\8c Ù\86أرÙ\85 Ø£Ù\81زار Ú©Ø¦ Ù\87ا Ø¯ Ø¦Û\8c Ú¤Û\8cÚ©Û\8c Ù\86Û\8cسئسÛ\95 Ø¢Ù\85ادÛ\95 Ù\85Û\8cÚ©Û\95Ø\8cÙ\88 Ú¤Ø¦ Ø¯ Ù\85Ù\88زاحئÙ\85Û\95 Øª Ú©Ø§Ø±Û\8c Ù¾Ø£Ø± Ù\88 Ù¾Û\8cÙ\85 Ú©Ø§Ø±Û\8c Ø¨Û\8cÛ\95\nسÛ\8c Ø¦Ø¶Ø§Ù\81 Ú©Ø¦Ø±Ø¯Ø¦Ù\86 Û\8cا Ø¢Ù\84ئشت Ø¯Ø£Ø¦Ù\86 Ø¯ Ù\87Ø£Ù\85Û\95 Ú¤Û\8cÚ©Û\8c Û\8cا Ù\84Ù\88Ø·Ù\81 Ø¨Ø£Ú©Û\8cت [https://translatewiki.net/ translatewiki.net] Ù\86Û\95 Ú¤Ø¦ Ú©Ø§Ø± Ø¨Ø¦Û\8cرÛ\8cتØ\8c Ù¾Ù\88رÙ\88جÛ\95 Ú¤Ù\88Ù\84ات Ù\86ئشÛ\8cÙ\86 Ø³Ø§Ø²Û\8c Ú¤Û\8cÚ©Û\8cÙ\85ئدیا.",
-       "editinginterface": "<strong>ڤارئسکاری کئردئن:</strong> شوما داریت یئ گئل بألگە نە کئ سی یئ گئل نیسئسە یا نأرم أفزار پئیڤأندکار ڤئ کار گئرئتە بیە ڤیرایئشت میکیت.\nآلئشت دأئن ئی بألگە ری رئخت و بارت پئیڤأندکاری کئ کاریاری هأنی ڤئ نە ڤئ کار مئیرئن کارگئرایی دارە.",
-       "translateinterface": "سÛ\8c Ø¦Ø¶Ø§Ù\81 Ú©Ø¦Ø±Ø¯Ø¦Ù\86 Û\8cا Ø¢Ù\84ئشت Ø¯Ø£Ø¦Ù\86 Ú¤Ø§Ù\84ئرئسÛ\95 Û\8cا Ø¯ ØªØ£Ù\85Ù\88Ù\99Ù\85 Ú¤Û\8cÚ©Û\8c Û\8cاØ\8cÙ\84Ù\88Ø·Ù\81 Ø¨Ø£Ú©Û\8cت [https://translatewiki.net/ translatewiki.net] Ù\86Û\95 Ú¤Ø¦ Ú©Ø§Ø± Ø¨Ø¦Û\8cرÛ\8cتØ\8c Ù¾Ù\88رÙ\88جÛ\95 Ú¤Ù\88Ù\84ات Ù\86ئشÛ\8cÙ\86 Ø³Ø§Ø²Û\8c Ú¤Û\8cÚ©Û\8c Ù\85ئدیا.",
+       "protectedinterface": "اؽ Ø¨Ù±Ù\84Ú¯Ù± Ø³Û\8c Ù\86ٱرÙ\85 Ù±Ù\81زار Ú©Ø§Ù\92 Ù\87ا Ø¯ Ø§Ø½ Ú¤Û\8cÚ©Û\8c Ù\86Û\8cسسٱ Ø¢Ù\85ادٱ Ù\85ؽکٱ Û\89 Ú¤ Ø¯ Ù\85Ù\88زاÙ\87Ù\85ٱت Ú©Ø§Ø±Û\8c Ù¾Ø± Û\89 Ù¾Û\8cÙ\85 Ú©Ø§Ø±Û\8c Ø¨Û\8cÙ±\nسÛ\8c Ø§Ù\92زاÙ\81 Ú©Ø±Ø§Ù\9bÙ\86 Û\8cا Ø¢Ù\84شت Ø¯Ø§Ù\9bئÙ\86 Ø¯ Ù\87Ù±Ù\85Ù± Ú¤Û\8cÚ©Û\8c Û\8cا Ù\84Ù\88تÙ\81 Ø¨Ù±Ú©Ø½Øª [https://translatewiki.net/ translatewiki.net] Ù\86اÙ\92 Ú¤ Ú©Ø§Ø± Ø¨Ø§Ù\9bÛ\8cرؽتØ\8c Ù¾Ø±Û\89Ú\98Ù± Ú¤Ù\84ات Ù\86Ø´Û\8cÙ\86 Ø³Ø§Ø²Û\8c Ú¤Û\8cÚ©Û\8c Ù\85دیا.",
+       "editinginterface": "<strong>ڤارٱسکاری کردن:</strong> شما ها یاٛ بٱلگٱ ناْ کاْ سی یاٛ نیسسٱیا نٱرم ٱفزار پاٛڤٱنکار ڤ کار گرتٱ بیٱ ڤیرایش مؽکؽت.\nآلشت داٛئن اؽ بٱلگٱ ری دهۊل پاٛڤٱنکاری کاْ کاریارؽ هنی ڤٱ ناْ ڤ کار ماٛیرٱن کارگرایی دارٱ.",
+       "translateinterface": "سÛ\8c Ø§Ù\92زاÙ\81 Ú©Ø±Ø¯Ù\86 Û\8cا Ø¢Ù\84شت Ø¯Ø§Ù\9bئÙ\86 Ú¤Ù\84Ù\9bرسٱÛ\8cا Ø¯ ØªÙ\85Ù\88Ù\99Ù\85 Ú¤Û\8cÚ©Û\8c Û\8cا Ù\84Ù\88تÙ\81 Ø¨Ù±Ú©Ø½Øª [https://translatewiki.net/ translatewiki.net] Ù\86اÙ\92 Ú¤ Ú©Ø§Ø± Ø¨Ø§Ù\9bÛ\8cرؽتØ\8c Ù¾Ø±Û\89Ú\98Ù± Ú¤Ù\84ات Ù\86Ø´Û\8cÙ\86 Ø³Ø§Ø²Û\8c Ú¤Û\8cÚ©Û\8c Ù\85دیا.",
        "cascadeprotected": "ئی بألگە د ڤیرایئشت پأر و پیم کاری بییە سی یە کئ د ڤأر گئرئتە بألگە {{PLURAL:$1|ڤئ بألگە یە|ڤئنوٙ بألگە ن}} ە کئ ڤئ خوش ڤا نئماجا تاف نئمایی پأر و پیم کاری بیە و چیا هأنی د ئیچئ رأڤاندیاری بینە:\n$2",
-       "namespaceprotected": "Ø´Ù\88Ù\85ا ØµØ¦Ù\84ا Ú¤Û\8cراÛ\8cئشت Ø¨Ø£Ù\84Ú¯Û\95 Û\8cاÛ\8cÛ\8c Ú©Ø¦ Ù\87اÙ\86 Ø¯ Ù\86Ù\88Ù\85جا <strong>$1</strong> Ù\86ارÛ\8cت.",
-       "customcssprotected": "Ø´Ù\88Ù\85ا ØµØ¦Ù\84ا Ú¤Û\8cراÛ\8cئشت Ø¦Û\8c Ø¨Ø£Ù\84Ú¯Û\95 Ø³Û\8c Ø¦Ø³ Ø¦Ø³ Ù\86Û\95 Ù\86ارÛ\8cت Ø³Û\8c Û\8cÛ\95 Ú©Ø¦ Ù\85Û\8cزÙ\88Ù\99Ù\86کارÛ\8c Ø¯Ù\88Ù\99Ù\86ئسÙ\85Ø£Ù\86Û\8cا Ø´Ø£ØµÙ\82Û\8c Û\8cئ Ú¯Ø¦Ù\84 Ú©Ø§Ø±Û\8cار Ù\87Ø£Ù\86Û\8c Ù\87ا Ø¯Ø¦ش.",
-       "customjsprotected": "Ø´Ù\88Ù\85ا ØµØ¦Ù\84ا Ú¤Û\8cراÛ\8cئشت Ø¦Û\8c Ø¨Ø£Ù\84Ú¯Û\95 Ø¬Ø§Ú¤Ø§ Ø¦Ø³Ú©Ø±Û\8cپت Ù\86Û\95 Ù\86ارÛ\8cت Ø³Û\8c Û\8cÛ\95 Ú©Ø¦ Ù\85Û\8cزÙ\88Ù\99Ù\86کارÛ\8c Ø¯Ù\88Ù\99Ù\86ئسÙ\85Ø£Ù\86Û\8cا Ø´Ø£ØµÙ\82Û\8c Û\8cئ Ú¯Ø¦Ù\84 Ú©Ø§Ø±Û\8cار Ù\87Ø£Ù\86Û\8c Ù\87ا Ø¯Ø¦ش.",
-       "mycustomcssprotected": "Ø´Ù\88Ù\85ا ØµØ¦Ù\84ا Ú¤Û\8cراÛ\8cئشت Ú©Ø¦Ø±Ø¯Ø¦Ù\86 Ø¦Û\8c Ø¨Ø£Ù\84Ú¯Û\95 Ø³Û\8c Ø¦Ø³ Ø¦Ø³ Ù\86Û\95 Ù\86ارÛ\8cت.",
-       "mycustomjsprotected": "Ø´Ù\88Ù\85ا ØµØ¦Ù\84ا Ú¤Û\8cراÛ\8cئشت Ú©Ø¦Ø±Ø¯Ø¦Ù\86 Ø¦Û\8c Ø¨Ø£Ù\84Ú¯Û\95 Ø¬Ø§Ú¤Ø§ Ø¦Ø³Ú©Ø¦Ø±Û\8cپت Ù\86Û\95 Ù\86ارÛ\8cت.",
-       "myprivateinfoprotected": "Ø´Ù\88Ù\85ا ØµØ¦Ù\84ا Ú¤Û\8cراÛ\8cئشت Ú©Ø§Ø±Û\8c Ø¯Ù\88Ù\86ئسÙ\85Ø£Ù\86Û\8cا Ø´Ø£ØµÙ\82Û\8c Ø®Ù\88تÙ\88Ù\99Ù\86Û\95 Ù\86ارÛ\8cت.",
-       "mypreferencesprotected": "Ø´Ù\88Ù\85ا ØµØ¦Ù\84ا Ú¤Û\8cراÛ\8cئشت Ú©Ø§Ø±Û\8c Ú¤Û\8cجÛ\95 Û\8cÛ\8c Û\8cا Ù\87Ø£Ù\86Û\8c Ø®Ù\88تÙ\88Ù\99Ù\86Û\95 Ù\86ارÛ\8cت.",
-       "ns-specialprotected": "نبوٙە بألگە یا ڤئجە نع ڤیرایئشت کئرد.",
-       "titleprotected": "ئÛ\8c Ø¯Ø§Ø³Ù\88Ù\99Ù\86 Ø¯ Ø±Ø£Ú¤Ø£Ù\86دÛ\8cارÛ\8c Ú¤Ø¦ Ø¯Ø£Ø³ [[User:$1|$1]] Ù\86ئÙ\87اگئرÛ\8c Ø¨Û\8cÛ\8cÛ\95.\nدأÙ\84Û\8cÙ\84ئش Ú¤Ø¦ Ù\86Û\95<em>$2</em>.",
+       "namespaceprotected": "Ø´Ù\85ا Ø³Ù\84ا Ú¤Û\8cراÛ\8cØ´ Ø¨Ù±Ù\84Ú¯Ù±Û\8cاÛ\8cؽ Ú©Ø§Ù\92 Ù\87اÙ\86 Ø¯ Ù\86Ù\88Ù\85جا <strong>$1</strong> Ù\86ارؽت.",
+       "customcssprotected": "Ø´Ù\85ا Ø³Ù\84ا Ú¤Û\8cراÛ\8cØ´ Ø§Ø½ Ø¨Ù±Ù\84Ú¯Ù± Ø³Û\8c Ø§Ù\92س Ø§Ù\92س Ù\86اÙ\92 Ù\86ارؽت Ø³Û\8c Û\8cÙ± Ú©Ø§Ù\92 Ù\85Û\8cزÙ\88کارÛ\8c Ø¯Ù\88Ù\86سÙ\85Ù±Ù\86Û\8cا Ø´Ù±Ø®Ø³Û\8c Û\8cاÙ\9b Ú©Ø§Ø±Û\8cار Ù\87Ù\86Û\8c Ù\87ا Ø¯ش.",
+       "customjsprotected": "Ø´Ù\85ا Ø³Ù\84ا Ú¤Û\8cراÛ\8cØ´ Ø§Ø½ Ø¨Ù±Ù\84Ú¯Ù± Ø¬Ø§Ú¤Ø§ Ø§Ù\92سکرÛ\8cپت Ù\86اÙ\92 Ù\86ارؽت Ø³Û\8c Û\8cÙ± Ú© Ù\85Û\8cزÙ\88کارÛ\8c Ø¯Ù\88Ù\86سÙ\85Ù±Ù\86Û\8cا Ø´Ù±Ø®Ø³Û\8c Û\8cاÙ\9b Ú©Ø§Ø±Û\8cار Ù\87Ù\86Û\8c Ù\87ا Ø¯ش.",
+       "mycustomcssprotected": "Ø´Ù\85ا Ø³Ù\84ا Ú¤Û\8cراÛ\8cØ´ Ú©Ø±Ø¯Ù\86 Ø§Ø½ Ø¨Ù±Ù\84Ú¯Ù± Ø³Û\8c Ø§Ù\92س Ø§Ù\92س Ù\86اÙ\92 Ù\86ارؽت.",
+       "mycustomjsprotected": "Ø´Ù\85ا Ø³Ù\84ا Ú¤Û\8cراÛ\8cØ´ Ú©Ø±Ø¯Ù\86 Ø§Û\8c Ø¨Ù±Ù\84Ú¯Ù± Ø¬Ø§Ú¤Ø§ Ø§Ù\92سکرÛ\8cپت Ù\86اÙ\92 Ù\86ارؽت.",
+       "myprivateinfoprotected": "Ø´Ù\85ا Ø³Ù\84ا Ú¤Û\8cراÛ\8cØ´ Ú©Ø§Ø±Û\8c Ø¯Ù\88Ù\86سÙ\85Ù±Ù\86Û\8cا Ø´Ù±Ø®Ø³Û\8c Ø®Ù\88تÙ\88Ù\86اÙ\92 Ù\86ارؽت.",
+       "mypreferencesprotected": "Ø´Ù\85ا Ø³Ù\84ا Ú¤Û\8cراÛ\8cØ´ Ú©Ø§Ø±Û\8c Ú¤Û\8cÚ\98اÙ\9bÛ\8cÛ\8c Û\8cا Ø®Ù\88تÙ\88Ù\86اÙ\92 Ù\86ارؽت.",
+       "ns-specialprotected": "نمۊئٱ بٱلگٱیا ڤیژٱ ناْ ڤیرایش کرد.",
+       "titleprotected": "اؽ Ø¯Ø§Ø³Ù\88Ù\86 Ø¯ Ø±Ù±Ú¤Ù±Ù\86دؽارÛ\8c Ú¤ Ø¯Ù±Ø³ [[User:$1|$1]] Ù\86Ù\87اگÛ\8cرÛ\8c Ø¨Û\8cÙ±.\nدÙ\84Ù\9bÛ\8cÙ\84Ù\9bØ´ Ú¤ Ù\86Ù±<em>$2</em>.",
        "filereadonlyerror": "نأبوٙە جانیا \"$1\" نە آلئشت کاری بأکیت سی یە کئ ئمایە جا \"$2\" ئیسئ ها د حال و بال حأنئن.\n\nدیڤوٙنداری کئ ڤئ نە قولف کئردە ها د حال و بال گوتە دیاری \"$3\" .",
-       "invalidtitle-knownnamespace": "داسÙ\88Ù\99Ù\86 Ù\86ادÛ\8cار Ø³Û\8c Ù\86Ù\88Ù\85 Ø¬Ø§ \"$2\" Ù\88 Ù\86Û\8cسئسÛ\95 \"$3\"",
+       "invalidtitle-knownnamespace": "داسÙ\88Ù\86 Ù\86ادؽار Ø³Û\8c Ù\86Ù\88Ù\85 Ø¬Ø§ \"$2\" Û\89 Ù\86Û\8cسسٱ \"$3\"",
        "invalidtitle-unknownnamespace": "داسوٙن نادیار سی شومارە نادیار نوم جا \"$2\" و نیسئسە \"$3\"",
        "exception-nologin": "هنی نۏمایتٱ ڤامیٛن",
-       "exception-nologin-text": "Ù\84Ù\88Ø·Ù\81 Ø¨Ø£Ú©Û\8cت Ø¨Û\8cاÛ\8cت Ú¤Ø§Ù\85Û\8cÙ\86 Ø³Û\8c Û\8cÛ\95 Ú©Ø¦ Ø¯ Ø¦Û\8c Ø¨Ø£Ù\84Ú¯Û\95 Û\8cا Ú©Ù\88Ù\86ئشتکارÛ\8c Ø¯Ø£Ø³Ø±Ø¦Ø³Û\8c Ø¯Ø§Ø´ØªÙ\88Ù\99Û\8cÛ\8cت.",
-       "exception-nologin-text-manual": "Ù\84Ù\88Ø·Ù\81 Ø¨Ø£Ú©Û\8cت Ú¤Ø¦ $1 ØµØ¦Ù\84ا Ø¨Ø¦Û\8cتÙ\88Ù\99 Ú©Ø¦ Ø¯ Ø¦Û\8c Ø¨Ø£Ù\84Ú¯Û\95 Û\8cا Ú©Ù\88Ù\86ئشتکارÛ\8c Ø¯Ø£Ø³Ø±Ø¦Ø³Û\8c Ø¯Ø§Ø´ØªÙ\88Ù\99Û\95.",
-       "virus-badscanner": "سازڤارە گأن:ڤیروٙس نادیار:<em>$1</em>",
-       "virus-scanfailed": "زول بییئن شئکأس حأرد(رازینە $1)",
-       "virus-unknownscanner": "ڤیروٙس کوش نادیار",
-       "logouttext": "<strong>Ø´Ù\88Ù\85ا Ù\87Ø£Ù\86Û\8c Ù\86أرÛ\8cتÛ\95 Ú¤Ø¦ Ø¯Ø£Ø±.</strong>\n\nد Ú¤Û\8cرئتÙ\88Ù\99 Ø¨Ø§ Ú©Ø¦ Ú¤Û\8cرگÛ\95 Ù\86ئÙ\87Ù\88Ù\99 Ø£Ù\86جÙ\88Ù\85Û\8cارئتÙ\88Ù\99 Ù\86Û\95 Ù¾Ø§Ú©Ø³Ø§ Ù\86Ø£Ú©Û\8cتØ\8c Ø³Û\8c Û\8cÛ\95 Ú©Ø¦ Ú¯Ø§Ø³Û\8c Ù¾Ø§Ø±Ø¦ Û\8cÛ\8c Ø¯ Ø¨Ø£Ù\84Ú¯Û\95 Û\8cا Ø¬Ù\88Ù\99رÛ\8c Ø¯Û\8cارÛ\8c Ù\85Û\8c Ú©Ø£Ù\86 Ú\86Û\8c Û\8cÛ\95 Ú©Ø¦ Ù\85Ø£Ù\86Û\8cستÛ\8c Ø´Ù\88Ù\85ا Ù\87Ø£Ù\86Û\8c Ù\87اÛ\8cÛ\8cت Ú¤Ø£Ù\85Û\8cن.",
-       "welcomeuser": "Ø®Ù\88Ø´ Ø¦Ù\88Ù\99Ù\85اÛ\8cÛ\8cت،$1!",
-       "welcomecreation-msg": "حئساڤتوٙ دوروس بییە.\nد ڤیرئتوٙ نأروە کئ {{نوم دیارگە}} [[Special:Preferences|preferences]]  خوتوٙنە آلئشت بأکیت.",
+       "exception-nologin-text": "Ù\84Ù\88تÙ\81 Ø¨Ù±Ú©Ø½Øª Ø¨Ø½Ø§Û\8cؽت Ú¤Ø§Ù\85ؽÙ\86 Ø³Û\8c Û\8cÙ± Ú©Ø§Ù\92 Ø¯ Ø§Ø½ Ø¨Ù±Ù\84Ú¯Ù±Û\8cا Ú©Ù\88Ù\86شکارÛ\8c Ø¯Ù±Ø³Ø±Ø³Û\8c Ø¯Ø§Ø´ØªÛ\8aÛ\8cؽت.",
+       "exception-nologin-text-manual": "Ù\84Ù\88تÙ\81 Ø¨Ù±Ú©Ø½Øª Ú¤ $1 Ø³Ù\84ا Ø¨Ø§Ù\9bÛ\8cتÙ\88 Ú©Ø§Ù\92 Ø¯ Ø§Ø½ Ø¨Ù±Ù\84Ú¯Ù±Û\8cا Ú©Ù\88Ù\86شکارÛ\8c Ø¯Ù±Ø³Ø±Ø³Û\8c Ø¯Ø§Ø´ØªÛ\8aئٱ.",
+       "virus-badscanner": "سازڤارٱ گٱن:ڤیرۊس نادؽار:<em>$1</em>",
+       "virus-scanfailed": "زول بیئن شکٱس هٱرد(رازینٱ $1)",
+       "virus-unknownscanner": "ڤیرۊس کوش نادؽار:",
+       "logouttext": "<strong>Ø´Ù\85ا Ù\87Ù\86Û\8c Ù\86ٱرٱتؽتٱ Ú¤ Ø¯Ù±Ø±.</strong>\n\nÚ¤ Ú¤Û\8cرتÙ\88 Ø¨Ø§ Ú©Ø§Ù\92 Ú¤Û\8cرگٱ Ù\86Ù\87Ù\88Ý© Ù±Ù\86جÙ\88Ù\85Û\8cارÛ\8cتÙ\88 Ù\86اÙ\92 Ù¾Ø§Ú©Ø³Ø§ Ù\86ٱکؽتØ\8c Ø³Û\8c Û\8cÙ± Ú©Ø§Ù\92 Ú¯Ø§Ø³Ø½ Ù¾Ø§Ø±Ø§Ù\9bÛ\8cؽ Ø¯ Ø¨Ù±Ù\84Ú¯Ù±Û\8cا Ø¬Û\8aرؽ Ø¯Ø½Ø§Ø±Û\8c Ù\85ؽکٱÙ\86 Ú\86Û\8c Û\8cÙ± Ú©Ø§Ù\92 Ù\85Ù±Ù\86Û\8cستÛ\8c Ø´Ù\85ا Ù\87Ù\86Û\8c Ù\87اÛ\8cؽت Ú¤Ø§Ù\85ؽن.",
+       "welcomeuser": "خٱش Ø§Ù\88Ù\85اÛ\8cؽت،$1!",
+       "welcomecreation-msg": "هساو تو دۏرس بیٱ.\nد ڤیرتو نٱرۉئٱ کاْ {{نوم دؽارگٱ}} [[Special:Preferences|preferences]]  خوتو ناْ آلشت بٱکؽت.",
        "yourname": "نوم کاریاری:",
        "userlogin-yourname": "نوم کاریاری",
        "userlogin-yourname-ph": "نوم کاریاری توناْ بٱزنؽت",
-       "createacct-another-username-ph": "نوم کاریاری توٙنە بأزئنیت",
-       "yourpassword": "رازینە گوڤاردئن:",
-       "userlogin-yourpassword": "رازینٱ گوڤاردن",
+       "createacct-another-username-ph": "نوم کاریاری تو ناْ بٱزنؽت",
+       "yourpassword": "پٱسڤورد:",
+       "userlogin-yourpassword": "پٱسڤورد",
        "userlogin-yourpassword-ph": "رازینٱ گوئارسناْ بٱزاْ",
        "createacct-yourpassword-ph": "رازینٱ گوئاردن ناْ بٱزاْ",
-       "yourpasswordagain": "Û\8cئ Ú¯Ø¦Ù\84 Ù\87Ø£Ù\86Û\8c Ø±Ø§Ø²Û\8cÙ\86Û\95 Ú¯Ù\88ڤاردئÙ\86 Ù\86Û\95 Ø¨Ø£Ø²Û\95",
-       "createacct-yourpasswordagain": "رازینٱ گوئاردن ناْ پوشت دۏرس کو",
+       "yourpasswordagain": "Û\8cاÙ\9b Ù\87Ù\86Û\8c Ø±Ø§Ø²Û\8cÙ\86Ù± Ú¯Ù\88ئاردÙ\86 Ù\86اÙ\92 Ø¨Ù±Ø²Ø§Ù\92",
+       "createacct-yourpasswordagain": "پٱسڤورد تازٱ ناْ تٱیید كو",
        "createacct-yourpasswordagain-ph": "یاٛ گلٛ هنی رازینٱ گوئاردن بٱزٱ",
        "userlogin-remembermypassword": "مناْ د سامونٱ ڤادار",
-       "userlogin-signwithsecure": "ڤأصل بییئن أمن نە ڤئ کار بئیر",
-       "yourdomainname": "Ù¾Ù\88شگئر Ø´Ù\88ما:",
+       "userlogin-signwithsecure": "ڤٱسل بیئن ٱمن ناْ ڤ کار باٛیر",
+       "yourdomainname": "Ù¾Ù\88شگر Ø´ما:",
        "password-change-forbidden": "شوما نئمی توٙنیت رازینە گوڤاردئن خوتوٙنە د ئی ڤیکی آلئشت بأکیت.",
-       "externaldberror": "ئشتئڤاÛ\8cÛ\8c Ø¯ Ø¦Ø±ØªØ¦Ú¤Ø§Ø· Ú¤Ø§ Ø±Ø¦Ø³Û\8cÙ\86Û\95 Ú¯Ø§ Ù¾Û\8cØ´ Ø¦Ù\88Ù\99Ù\85اÛ\95 Û\8cا Ø´Ù\88Ù\85ا ØµØ¦Ù\84ا Û\8cØ£Ù\86Û\95 Ú©Ø¦ Û\8cئ Ú¯Ø¦Ù\84 Ø­Ø¦Ø³Ø§Ú¤ Ø®Ø§Ø±Ø¬Û\8c Ø®Ù\88تÙ\88Ù\99Ù\86Û\95 Ú¤Ø¦ Ù\87ئÙ\86Ú¯Ù\88Ù\85 Ø³Ø§Ø²Û\8c Ø¨Ø£Ú©Û\8cت Ù\86ارÛ\8cت.",
+       "externaldberror": "اÙ\92شتباÛ\8cؽ Ø¯ Ø§Ù\92رتبات Ú¤Ø§ Ø±Ø³Û\8cÙ\86ٱگا Ù¾Û\8cØ´ Ø§Ù\88Ù\85اÛ\8cÙ± Û\8cا Ø´Ù\85ا Ø³Ù\84ا Û\8cÙ± Ù\86اÙ\92 Ú©Ø§Ù\92 Û\8cاÙ\9b Ù\87ساÙ\88 Ø®Ø§Ø±Ø¬Û\8c Ø®Ù\88تÙ\88 Ù\86اÙ\92 Ú¤ Ù\87Ù\86Ú¯Ù\88Ù\85 Ø³Ø§Ø²Û\8c Ø¨Ù±Ú©Ø½Øª Ù\86ارؽت.",
        "login": "ڤامؽن اوماین",
-       "nav-login-createaccount": " ڤامین ئوٙمائن/راس کئردئن حئساڤ",
-       "logout": "د Ø³Ø§Ù\85Ù\88Ù\99Ù\86Û\95 Ø¯Ø¦Ø±Ø¦Ù\88Ù\99Ù\85ائن",
-       "userlogout": "د Ø³Ø§Ù\85Ù\88Ù\99Ù\86Û\95 Ø¯Ø¦Ø±Ø¦Ù\88Ù\99Ù\85ائن",
+       "nav-login-createaccount": " ڤامؽن اوماین/دۏرس کردن هساو",
+       "logout": "د Ø³Ø§Ù\85Ù\88Ù\86Ù± Ø¯Ø±Ø§Ù\88Ù\85اÛ\8cن",
+       "userlogout": "د Ø³Ø§Ù\85Ù\88Ù\86Ù± Ø¯Ø±Ø§Ù\88Ù\85اÛ\8cن",
        "notloggedin": "هنی نۏمایتٱ ڤامیٛن",
        "userlogin-noaccount": "یاٛ هساو نارؽت؟",
        "userlogin-joinproject": "ٱندوم دؽارگٱ {{SITENAME}} بۊئؽت",
        "createaccount": "هساو دۏرس بٱکؽت",
        "userlogin-resetpassword-link": "رازینٱ گوئارسن تو د ڤیرتو رٱتٱ؟",
        "userlogin-helplink2": "هومیاری کردن د تٱریق ڤامؽن اوماین",
-       "userlogin-loggedin": "Ø´Ù\88Ù\85ا Ø¦Û\8cسئ Ú\86Û\8c Û\8cئ Ú¯Ø¦Ù\84 {{GENDER:$1|$1}} Ø¦Ù\88Ù\99Ù\85اÛ\8cتÛ\95 Ú¤Ø§Ù\85Û\8cÙ\86\86Ù\88Ù\85 Ø¨Ø£Ù\84Ú¯Û\95 Ù\87ارÛ\8c Ù\86Û\95 Ø³Û\8c Ú¤Ø§Ù\85Û\8cÙ\86 Ø¦Ù\88Ù\99Ù\85ائÙ\86 Ú\86Û\8c Û\8cئ Ú¯Ø¦Ù\84 Ú©Ø§Ø±Û\8cار Ù\87Ø£Ù\86Û\8c Ø¨Ù\84Ú¯Ù\87 Ù\87ارÛ\8c Ø³Û\8c Ù\88ا Ù\85Û\8cÙ\86 Ø§Ù\88Ù\85ائÙ\86 Ú\86Û\8c Û\8cÙ\87 Ú¯Ù\84 Ú©Ø§Ø±Û\8cار Ù\87Ù\86Û\8c Ú¤Ø¦ Ú©Ø§Ø± Ø¨Ø¦Û\8cرÛ\8cت.",
-       "userlogin-createanother": "Û\8cئ Ú¯Ø¦Ù\84 Ø­Ø¦Ø³Ø§Ú¤ Ù\87Ø£Ù\86Û\8c Ø±Ø§Ø³ Ø¨Ø£Ú©Û\8cت",
-       "createacct-emailrequired": "تÛ\8cرÙ\86ئشÙ\88Ù\99Ù\86 Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95",
+       "userlogin-loggedin": "Ø´Ù\85ا Ø§Û\8cساÙ\92 Ú\86Û\8c Û\8cاÙ\9b {{GENDER:$1|$1}} Ø§Ù\88Ù\85اÛ\8cتٱ Ú¤Ø§Ù\85ؽÙ\86\86Ù\88Ù\85 Ø¨Ù±Ù\84Ú¯Ù± Ù\87ارÛ\8c Ù\86اÙ\92 Ø³Û\8c Ú¤Ø§Ù\85ؽÙ\86 Ø§Ù\88Ù\85اÛ\8cÙ\86 Ú\86Û\8c Û\8cاÙ\9b Ú©Ø§Ø±Û\8cار Ù\87Ù\86Û\8c Ø¨Ù±Ù\84Ú¯Ù± Ù\87ارÛ\8c Ø³Û\8c Ú¤Ø§ Ù\85ؽÙ\86 Ø§Ù\88Ù\85ابÙ\86 Ú\86Û\8c Û\8cاÙ\9b Ú©Ø§Ø±Û\8cار Ù\87Ù\86Û\8c Ú¤ Ú©Ø§Ø± Ø¨Ø§Ù\9bÛ\8cرؽت.",
+       "userlogin-createanother": "Û\8cاÙ\9b Ù\87ساÙ\88 Ù\87Ù\86Û\8c Ø¯Û\8fرس Ø¨Ù±Ú©Ø½ت",
+       "createacct-emailrequired": "تÛ\8cرÙ\86Ø´Ù\88Ý© Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù±",
        "createacct-emailoptional": "تیرنشوݩ ٱنجومانامٱ",
        "createacct-email-ph": "تیرنشوݩ ٱنجومانامٱ توناْ ڤارد بٱكؽت",
-       "createacct-another-email-ph": "تÛ\8cرÙ\86ئشÙ\88Ù\99Ù\86 Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95 ØªÙ\88Ù\99Ù\86Û\95 Ø¨Ø£Ø²Ø£Ù\86Û\8cت",
-       "createaccountmail": "Û\8cئ Ú¯Ø¦Ù\84 Ø±Ø§Ø²Û\8cÙ\86Û\95 Ú¯Ù\88ڤاردئÙ\86 Ù\85Ù\88ڤأÙ\82أتÛ\8cÙ\86Û\95 Ú¤Ø¦ Ú©Ø§Ø± Ø¨Ø¦Û\8cرÛ\8cت Ù\88 Ú¤Ø¦ Ù\86Û\95سÛ\8c Û\8cئ Ú¯Ø¦Ù\84 ØªÛ\8cرÙ\86ئشÙ\88Ù\99Ù\86 Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95 ØªÛ\8cار Ø¨Û\8cÛ\8cÛ\95 Ú©Ø¦Ù\84 Ø¨Ø£Ú©Û\8cت.",
-       "createacct-realname": "نوم راستأکی(مأژبوٙری نی)",
-       "createacct-reason": "دألیل",
-       "createacct-reason-ph": "سی چی شوما داریت یئ گئل حئساڤ هأنی راس میکید",
+       "createacct-another-email-ph": "تÛ\8cرÙ\86Ø´Ù\88Ý© Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù± ØªÙ\88Ù\86اÙ\92 Ø¨Ù±Ø²Ù\86ؽت",
+       "createaccountmail": "Û\8cاÙ\9b Ø±Ø§Ø²Û\8cÙ\86Ù± Ú¯Ù\88ئارسÙ\86 Ù\85Ù\88Ú¤Ù±Ù\82ٱتÛ\8cÙ\86اÙ\92 Ú¤ Ú©Ø§Ø± Ø¨Ø§Ù\9bرؽت Û\89 Ú¤Ù± Ù\86اÙ\92 Ø³Û\8c Û\8cاÙ\9b ØªÛ\8cرÙ\86Ø´Ù\88Ý© Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù± ØªÛ\8cار Ø¨Û\8cÙ± Ú©Ù\84Ù\9b Ø¨Ù±Ú©Ø½ت.",
+       "createacct-realname": "نوم راسٱکی(مٱژبۊری نؽ)",
+       "createacct-reason": "دلٛیلٛ",
+       "createacct-reason-ph": "سی چؽ شما دارؽت یاٛ هساو هنی دۏرس مؽکؽت",
        "createacct-submit": "هساو خوتوناْ دۏرس بٱکؽت",
        "createacct-another-submit": "یئ گئل حئساڤ هأنی راس بأکیت",
        "createacct-benefit-heading": "{{SITENAME}}  ڤ دٱس کٱسؽایؽ چی شما رٱڤٱندؽاری بیٱ.",
        "createacct-benefit-body1": "{{PLURAL:$1|ڤیرایش|ڤیرایشؽا}}",
        "createacct-benefit-body2": "{{PLURAL:$1|بٱلگٱ|بٱلگٱیا}}",
        "createacct-benefit-body3": "تازٱ{{PLURAL:$1|هومیار|ھومیاریا}}",
-       "badretype": "رازینە گوڤاردئنی کئ شمأ دأییتە هومدأنگی نارە.",
-       "usernameinprogress": "رأرڤأندیاری یئ گئل حئساڤ سی ئی نوم کاریاری ھا د پیشکئرد. یئ گوری آھئرە داری بأکیت.",
-       "userexists": "نوم کاریاری دە بییە ئیسئنی ڤئ کار گئرئتە بییە.\nلوطف بأکیت یئ گئل نوم هأنی نە ڤئرداریت.",
-       "loginerror": "خأطا ڤامین ئوٙمائن",
-       "createacct-error": "خأطا راس کئردئن حئساڤ",
-       "createaccounterror": "نأبوٙە حئساڤ کاریاری راس بأکیت:$1",
-       "nocookiesnew": "حئساڤ کاریاری راست بی، ڤألی شوما نیوٙمایتە ڤامین.کاریاری راس بی،اما شما وامئن نیامایئته.{{SITENAME}} کوٙکیا نە سی ئوٙمائن د ساموٙنە کاریاریاڤئ کار مئیرە.\nکوٙکیا شوما ناکوٙنئشتگأر بینە.\nلوطف بأکیت ڤئنوٙنە کونئشتگأر بأکیت، ئوٙسئ ڤا یئ گئل نوم کاریاری و رازینە گوڤاردئن هأنی بیاییت ڤامین.",
-       "nocookieslogin": "{{SITENAME}} کوٙکیا نە سی ئوٙمائن د ساموٙنە کاریاریاڤئ کار مئیرە.\nکوٙکیا شوما ناکوٙنئشتگأر بینە.\nلوطف بأکیت ڤئنوٙنە کونئشتگأر بأکیت و د نۊ تئلاش بأکیت.",
-       "nocookiesfornew": "حئساڤ کاریاری راس نأبیە، سی یە نە کئ ئیما نئمی توٙنیم سأرچئشمە ڤئنە پوشت راس کاری بأکیم.\nموطمأئن بوٙییت کئ کوٙکیا کونئشتگأر بینە، ئی بألگە نە د نوٙ سوٙڤار بأکیت و هأنی تئلاش بأکیت.",
+       "badretype": "رازینٱ گوئارسنؽ کاْ شما داٛیتٱ هومدٱنڳی نارٱ.",
+       "usernameinprogress": "رٱرڤٱندیاری یاٛ هساو سی اؽ نوم کاریاری ھا د پیشکرد. یاٛ گرؽ آھرٱ داری بٱکؽت.",
+       "userexists": "نوم کاریاری د بیٱ ایسنی ڤ کار گرتٱ بیٱ.\nلوتف بٱکؽت یاٛ نوم هنی ناْ ڤردارؽت.",
+       "loginerror": "خٱتا ڤا مؽن اوماین",
+       "createacct-error": "خٱتا دۏرس کردن هساو",
+       "createaccounterror": "نمۊئٱ هساو کاریاری دۏرس بٱکؽت:$1",
+       "nocookiesnew": "هساو کاریاری دۏرس بی، ڤلی شما نۏمایؽتٱ ڤامؽن.کاریاری دۏرس بی، ڤلی شما ڤامؽن نۏمایؽتٱ.{{SITENAME}} کۊکیا ناْ سی اوماین ڤ سامونٱ کاریاریا ڤ کار ماٛیرٱ.\nکۊکیا شما ناکونشگٱر بینٱ.\nلوتف بٱکؽت ڤنوناْ کونشگٱر بٱکؽت، اۊساْ ڤا یاٛ نوم کاریاری ۉ رازینٱ گوئارسن هنی بؽایؽت ڤامؽن.",
+       "nocookieslogin": "{{SITENAME}} کۊکیا ناْ سی اوماین ڤ سامونٱ کاریارؽا ڤ کار ماٛیرٱ.\nکۊکیا شما ناکونگٱر بینٱ.\nلوتف بٱکؽت ڤنوناْ کونشگٱر بٱکؽت ۉ د نۊ تٱفرٱ بٱکؽت.",
+       "nocookiesfornew": "هساو کاریاری دۏرس ناٛییٱ سی ینٱ کاْ اؽما نمؽ تونؽم سرچشمٱ ڤٱناْ پوشت راس کاری بٱکؽم.\nموتمٱعن بۊیؽت کاْ کۊکیا کونشگٱر بینٱ، اؽ بٱلگٱ ناْ د نۊ سڤار بٱکؽت ۉ هنی تٱفرٱ بٱکؽت.",
        "nocookiesforlogin": "{{int:nocookieslogin}}",
-       "noname": "Ø´Ù\88Ù\99Ù\85ا Û\8cئ Ú¯Ø¦Ù\84 Ù\86Ù\88Ù\85 Ú©Ø§Ø±Û\8cارÛ\8c Ø®Ù\88Ù\99 ØªÛ\8cار Ù\86أکئردÛ\8cتÛ\95.",
+       "noname": "Ø´Ù\85ا Û\8cاÙ\9b Ù\86Ù\88Ù\85 Ú©Ø§Ø±Û\8cارÛ\8c Ø®Û\8a ØªÛ\8cار Ù\86ٱکردؽتٱ.",
        "loginsuccesstitle": "ئوٙمائن ڤامین خوٙ بی",
-       "loginsuccess": "Ø´Ù\88Ù\99Ù\85ا Ø¦Û\8cسئ Ø¦Ù\88Ù\99Ù\85اÛ\8cتÛ\95 Ú¤Ø§Ù\85Û\8cن {{SITENAME}} د چی\"$1\".'",
+       "loginsuccess": "Ø´Ù\85ا Ø§Û\8cساÙ\92 Ø§Ù\88Ù\85اÛ\8cتٱ Ú¤Ø§Ù\85ؽن {{SITENAME}} د چی\"$1\".'",
        "nosuchuser": "چئنی کاریاری ڤا نوم\"$1\" نیئش.\nنوم کاریاری ڤئ حأرفیا حأساسە.\nرأڤئشت نیسأنئن توٙنە ڤارئسی بأکست،یا [[Special:ڤامین ئوٙمائن کاریار/ثأڤت نام کئردئن|یئ گئل حئساڤ تازه راس بأکیت]].",
-       "nosuchusershort": "چئنی کاریاری ڤا نوم $1 نی.\nنیسأنئن خوتوٙنە ڤارئسی بأکیت.",
-       "nouserspecified": "Ø´Ù\88Ù\85ا Ú¤Ø§Ø³ Û\8cئ Ú¯Ø¦Ù\84 Ù\86Ù\88Ù\85 Ú©Ø§Ø±Û\8cارÛ\8c ØªÛ\8cار Ø¨Ø£Ú©Û\8cت.",
-       "login-userblocked": "کاریا قولف بییە . شوما صئلا ڤامین ئوٙمائن ناریت.",
+       "nosuchusershort": "چنی کاریاری ڤا نوم $1 نی.\nنیسٱنن خوتوناْ ڤارسی بٱکؽت.",
+       "nouserspecified": "Ø´Ù\85ا Ø¨Ø§Û\8cٱد Û\8cاÙ\9b Ù\86Ù\88Ù\85 Ú©Ø§Ø±Û\8cارÛ\8c ØªÛ\8cار Ø¨Ù±Ú©Ø½ت.",
+       "login-userblocked": "کاریار قولف بیٱ. شما سلا ڤامؽن اوماین نارؽت.",
        "wrongpassword": "رازینە گوڤاردئنئتوٙ نە ئشتئڤا دأییتە.\nد نۊ تئلاش بأکیت.",
-       "wrongpasswordempty": "رازینە گوڤاردئنئتوٙ نە حالی دأییتە.\nد نۊ تئلاش بأکیت.",
-       "passwordtooshort": "رازینە گوڤاردئنئتوٙ با کأمتروٙنە {{PLURAL:$1|1 کاراکتئر|$1 کاراکتئریا}} با",
-       "passwordtoolong": "رازینە گوڤاردئنئتوٙ نە ڤاس بیشتئر د {{PLURAL:$1|1 کاراکتئر|$1 کاراکتئریا}} با",
-       "password-name-match": "رازینە گوڤاردئنئتوٙ بایأد ڤا نوم کاریاریتوٙ فأرخ داشتوٙە.",
-       "password-login-forbidden": "ڤئ کارگئرئتئن ئی نوم کاریاری و رازینە گوڤاردئن قأدئقأن بییە.",
-       "mailmypassword": "د Ù\86Û\8a Ø¯Ø£Ø¦Ù\86 Ø±Ø§Ø²Û\8cÙ\86Û\95 Ú¯Ù\88ڤاردئن",
-       "passwordremindertitle": "رازینە گوڤاردئن موڤأتی تازه سی {{SITENAME}}",
+       "wrongpasswordempty": "رازینٱ گوئارسن تو ناْ هالٛی داٛیؽتٱ.\nد نۊ تٱفرٱ بٱکؽت.",
+       "passwordtooshort": "رازینٱ گوئارسن تو بایٱد کٱمترونٱ {{PLURAL:$1|1 کاراکتر|$1 کاراکترؽا}} با",
+       "passwordtoolong": "رازینٱ گوئارسن تو بایٱد بؽشتر د {{PLURAL:$1|1 کاراکتر|$1 کاراکترؽا}} با",
+       "password-name-match": "رازینٱ گوئارسن تو بایٱد ڤا نوم کاریاری تو فٱرخ داشتۊئٱ.",
+       "password-login-forbidden": "ڤ کارگرتن اؽ نوم کاریاری ۉ رازینٱ گوئارسن مٱمنۊع بیٱ.",
+       "mailmypassword": "د Ù\86Û\8a Ø¯Ø§Ù\9bÛ\8cÙ\86 Ø±Ø§Ø²Û\8cÙ\86Ù± Ú¯Ù\88ئارسن",
+       "passwordremindertitle": "رازینٱ گوئارسن موڤٱقٱتی تازٱ سی {{SITENAME}}",
        "passwordremindertext": "یئ نأفأر (گاسی خوتوٙ،د تیرنئشوٙن آی پی $1) یئ گئل رازینە گوڤاردئن هأنی سی {{SITENAME}}($4) حاستە.یئ گئل رازینە گوڤاردئن موڤأقأتی سی کاریاری\"$2\" رأڤأندیاری بیە و د \"$3\" جاگئر بییە. أر یە نە حاستیتە،شما بایأد ئیسئ روٙییت ڤامین و یئ گئل رازینە گوڤاردئن هأنی نە ئنتئخاڤ بأکیت.\nرازینە گوڤاردئن موڤأقأتی د {{PLURAL:$5|یئ روٙ|$5 روٙزیا}}  تأموٙم بوٙە.\n\nأر یئ نأفأر هأنی ئی حاست نە داشتوٙە، یا أر رازینە گوڤاردئن توٙنە د ڤیرتوٙ ئوٙما، و أر حاستیت ڤئنە آلئشت کاری بأکیت، گاسی شوما د ئی پئیغوم تیە پوٙشی بأکیت و بئحایت ڤئ کار گئرئتئن رازینە گوڤاردئن دئماتریتوٙ نە دئماداری بأکیت.",
-       "noemail": "Ù\87Û\8cÚ\86 ØªÛ\8cرÙ\86ئشÙ\88Ù\99Ù\86 Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95 Û\8cÛ\8c Ø³Û\8c Ú©Ø§Ø±Û\8cار $1 Ø¶Ø£Ù\81Ø· Ù\86أبÛ\8cÛ\95.",
-       "noemailcreate": "Ø´Ù\88Ù\85ا Ø¨Ø§Û\8cأد Û\8cئ Ú¯Ø¦Ù\84 ØªÛ\8cرÙ\86ئشÙ\88Ù\99Ù\86 Ø£Ù\86جÙ\88Ù\85اÙ\86Û\95 Ø¬Ø§Ø¯Û\8cار Ø³Û\8c Ø®Ù\88تÙ\88Ù\99 Ø¯Ø§Ø´ØªÙ\88Ù\99Û\8cÛ\8cت.",
-       "passwordsent": "Û\8cئ Ú¯Ø¦Ù\84 Ø±Ø§Ø²Û\8cÙ\86Û\95 Ú¯Ù\88ڤاردئÙ\86 Ù\87Ø£Ù\86Û\8c Ú©Ø¦Ù\84 Ø¨Û\8cÛ\8cÛ\95 Ø³Û\8c ØªÛ\8cرÙ\86ئشÙ\88Ù\99Ù\86 Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95 Û\8cÛ\8c Ú©Ø¦ \"$1\" Ú¤Ø§Ø´ Ø«Ø£Ú¤Øª Ù\86اÙ\85 Ú©Ø¦Ø±Ø¯Û\95.\nخاÙ\87ئشت Ù\85Û\8c Ú©Û\8cÙ\85 Ù\87Ø£Ù\86Û\8c Ø±Ù\88Ù\99Û\8cÛ\8cت Ú¤Ø§Ù\85Û\8cÙ\86 Ù\88 Ø¦Ù\88Ù\99سئ Ø¨Ø¦Ø±Û\8cتئش.",
+       "noemail": "Ù\87Û\8cÚ\98 ØªÛ\8cرÙ\86Ø´Ù\88Ý© Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85اÙ\9bÛ\8cÛ\8c Ø³Û\8c Ú©Ø§Ø±Û\8cار $1 Ø²Ù±Ù\81ت Ù\86اÙ\9bÛ\8cÛ\8cÙ±.",
+       "noemailcreate": "Ø´Ù\85ا Ø¨Ø§Û\8cٱد Û\8cاÙ\9b ØªÛ\8cرÙ\86Ø´Ù\88Ý© Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù± Ø¬Ø§Ø¯Û\8cار Ø³Û\8c Ø®Ù\88تÙ\88 Ø¯Ø§Ø´ØªÛ\8aÛ\8cؽت.",
+       "passwordsent": "Û\8cاÙ\9b Ø±Ø§Ø²Û\8cÙ\86Ù± Ú¯Ù\88ئارسÙ\86 Ù\87Ù\86Û\8c Ú©Ù\84Ù\9b Ø¨Û\8cÙ± Ø³Û\8c ØªÛ\8cرÙ\86Ø´Ù\88Ý© Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85اÙ\9bÛ\8cÛ\8c Ú©Ø§Ù\92 \"$1\" Ú¤Ø§Ø´ Ø³Ù±Ø¨Øª Ù\86Ù\88Ù\85 Ú©Ø±Ø¯Ù±.\nخاÙ\87Ø´ Ù\85ؽکÙ\85 Ù\87Ù\86Û\8c Ø±Û\89Û\8cؽت Ú¤Ø§Ù\85ؽÙ\86 Û\89 Ø§Û\8aساÙ\92 Ø¨Ø§Ù\9bÛ\8cرتش.",
        "blocked-mailpassword": "نئها آی پی شوما سی ڤیرایئشت کاری گئرئتە بییە، هأنی صئلا یە نە نارە کئ د رازینە گوڤاردئن د نۊ کئل بییە سی نئهاگئری د گأن کاری نارە.",
-       "eauthentsent": "Û\8cئ Ú¯Ø¦Ù\84 Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95 Ù¾Ù\88شت Ø±Ø§Ø³Øª Ú©Ø¦Ø±Ø¯Ø¦Ù\86Û\8c Ø¯ Û\8cئ Ú¯Ø¦Ù\84Ù\9b ØªÛ\8cرÙ\86ئشÙ\88Ù\99Ù\86 Ú¤Û\8cجÛ\95 Ú©Ø¦Ù\84 Ø¨Û\8cÛ\8cÛ\95.\nدئÙ\85ا Û\8cÛ\95 Ú©Ø¦ Û\8cئ Ú¯Ø¦Ù\84 Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95 Ù\87Ø£Ù\86Û\8c Ø¯ Ø­Ø¦Ø³Ø§Ú¤ Ú©Ø¦Ù\84 Ø¨Ù\88Ù\99Ø£Ø\8c Ø´Ù\88Ù\85ا Ú¤Ø§Ø³ Ø¯Ø¦Ù\85ا Ø±Ø£Ø¯Û\8cارکÙ\88Ù\86Û\8c Ù\86Û\95 Ø¯ Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95 Ø¨Ø¦Û\8cرÛ\8cتØ\8c Ø³Û\8c Û\8cÛ\95 Ú©Ø¦ Ø­Ø¦Ø³Ø§Ú¤ Ø´Ù\88Ù\85ا Ø±Ø§Ø³ØªØ£Ú©Û\8c Ù¾Ù\88شت Ø±Ø§Ø³Øª Ø¨Ù\88Ù\99Ø£.",
-       "throttled-mailpassword": "Û\8cئ Ú¯Ø¦Ù\84 Ø±Ø§Ø²Û\8cÙ\86Û\95 Ú¯Ù\88ڤاردئÙ\86 Ø¯ Ù\86Û\8a Ø²Ø¦Ù\86Û\95 Ø¨Û\8cÛ\8cÛ\95 Ù\88 Ø¦Û\8cسئ Ú©Ø¦Ù\84 Ø¨Û\8cÛ\8cÛ\95Ø\8c Ø¯ Ø¢Ø®Ø¦Ø±Û\8c {{PLURAL:$1|ساعأت|$1 Ø³Ø§Ø¹Ø£ØªÛ\8cا}}.\nسÛ\8c Ù\86ئÙ\87اگئرÛ\8c Ø¯ Ø£Ø°Û\8cأت Ø¨Û\8cÛ\8cئÙ\86Ø\8c Ù\81Ø£Ù\82أط Û\8cئ Ú¯Ø¦Ù\84 Ø±Ø§Ø²Û\8cÙ\86Û\95 Ú¯Ù\88ڤاردئÙ\86 Ø¯ Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95 Ø¯ Ù\86Û\8a Ø²Ø¦Ù\86Û\95 Ø¨Û\8cÛ\8cÛ\95 Ø¯ Ù\87أر {{PLURAL:$1|ساعأت|$1 Ø³Ø§Ø¹Ø£ØªÛ\8cا}} Ú©Ø¦Ù\84 Ø¨Û\8cÛ\8cÛ\95.",
-       "mailerror": "خأطا د کئل بییئن أنجومانامە:$1",
+       "eauthentsent": "Û\8cاÙ\9b Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù± Ù¾Ù\88شت Ø¯Û\8fرس Ú©Ø±Ø¯Ù\86Û\8c Ø¯ Û\8cاÙ\9b ØªÛ\8cرÙ\86Ø´Ù\88Ý© Ú¤Û\8cÚ\98Ù± Ú©Ù\84Ù\9b Ø¨Û\8cÙ±.\nدÙ\85ا Û\8cÙ± Ú©Ø§Ù\92 Û\8cاÙ\9b Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù± Ù\87Ù\86Û\8c Ø¯ Ù\87ساÙ\88 Ú©Ù\84Ù\9b Ø¨Û\8aئٱØ\8c Ø´Ù\85ا Ø¨Ø§Û\8cٱد Ø¯Ù\85ا Ø±Ù±Ø¯Ø½Ø§Ø±Ú©Ù\88Ù\86Û\8c Ù\86اÙ\92 Ø¯ Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù± Ø¨Ø§Ù\9bÛ\8cرؽتØ\8c Ø³Û\8c Û\8cÙ± Ú©Ø§Ù\92 Ù\87ساÙ\88 Ø´Ù\85ا Ø±Ø§Ø³Ù±Ú©Û\8c Ù¾Ù\88شت Ø¯Û\8fرش Ø¨Û\8aئٱ.",
+       "throttled-mailpassword": "Û\8cاÙ\9b Ø±Ø§Ø²Û\8cÙ\86Ù± Ú¯Ù\88ئارسÙ\86 Ø¯ Ù\86Û\8a Ø²Ù\86Ù± Ø¨Û\8cÙ± Û\89 Ø§Û\8cساÙ\92 Ú©Ù\84Ù\9b Ø¨Û\8cÙ±Ø\8c Ø¯ Ø¢Ø®Ø±Û\8c {{PLURAL:$1|ساعٱت|$1 Ø³Ø§Ø¹Ù±ØªØ½Ø§}}.\nسÛ\8c Ù\86Ù\87اگÛ\8cرÛ\8c Ø¯ Ù±Ø²Û\8cٱت Ø¨Û\8cئÙ\86Ø\8c Ù\81Ù\82ٱت Û\8cاÙ\9b Ø±Ø§Ø²Û\8cÙ\86Ù± Ú¯Ù\88ئارسÙ\86 Ø¯ Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù± Ø¯ Ù\86Û\8a Ø²Ù\86Ù± Ø¨Û\8cÙ± Ø¯ Ù\87ٱر {{PLURAL:$1|ساعٱت|$1 Ø³Ø§Ø¹Ù±ØªØ½Ø§}} Ú©Ù\84Ù\9b Ø¨Û\8cÙ±.",
+       "mailerror": "خٱتا کلٛ بیئن ٱنجومانامٱ:$1",
        "acct_creation_throttle_hit": "سئل کاریا ئی ڤیکی تیرنئشوٙن آی پی شوما نە ڤئ کار گئرئتئنە د روٙز دئمایی {{PLURAL:$1|1 حئساڤ|$1 حئساڤیا}} نە رأڤأندیاری کئردئنە، و ڤئ د بیشتأروٙنە صئلا دأئنە د ئی دورە گاتی أنجوم بییە.\nد نأتیجە، سئل کاریایی کئ د ئی تیرنئشوٙن آی پی ڤئ کار گئرئتئنە نئمی توٙنئن حئساڤیا بیشتأری نە د ئی گات دوروس بأکأن.",
        "emailauthenticated": "تیرنئشوٙن أنجومانامە توٙ د $2 سی 3$ پوشت راسکاری بییە.",
-       "emailnotauthenticated": "تÛ\8cرÙ\86ئشÙ\88Ù\99Ù\86 Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95 Ø´Ù\88Ù\85ا ØªØ§ Ø¦Û\8cسئ Ù¾Ù\88شت Ø±Ø§Ø³ Ú©Ø§Ø±Û\8c Ù\86أبÛ\8cÛ\8cÛ\95.\nÙ\87Ø£Ù\86Û\8c Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95 Û\8cÛ\8c Ø³Û\8c Ø¦Û\8c Ú\86Û\8cا Ú©Ø¦ Ù\87اÙ\86 Ø±Û\8c Ù\86ئÙ\87ا Ú©Ø¦Ù\84 Ù\86أبÛ\8cÛ\8cÛ\95.",
-       "noemailprefs": "Û\8cئ Ú¯Ø¦Ù\84 ØªÛ\8cرÙ\86ئشÙ\88Ù\99Ù\86 Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95 Ø¯ Ú\86Û\8cا Ù\86ازار Ø´Ù\88Ù\85ا Ø³Û\8c Û\8cÛ\95 Ú©Ø¦ Ø¦Û\8c Ø®Ù\88صÙ\88Ù\99صÛ\8cأتÛ\8cا Ú©Ø§Ø± Ø¨Ø£Ú©Ø£Ù\86 Ø¦Ù\86تئخاڤ Ø¨Ø£Ú©Û\8cت.",
-       "emailconfirmlink": "تÛ\8cرÙ\86ئشÙ\88Ù\99Ù\86 Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95 ØªÙ\88Ù\99Ù\86Û\95 Ù¾Ù\88شت Ø±Ø§Ø³Ú©Ø§Ø±Û\8c Ø¨Ø£Ú©Û\8cت",
-       "invalidemailaddress": "تیرنشۊن ٱنجومانامٱ قٱڤۊل بیئنی سی یٱ کاٛ چی د ڤیر و باڤٱر میا ڤ شیڤٱ خۊیی نی.\nلوتف بٱکیت یاٛ گئل تیرنشۊن چۊٱ دار نٱ بٱزنیت یا ای جاگٱ نٱ هالی بٱنیت.",
-       "cannotchangeemail": "تÛ\8cرÙ\86ئشÙ\88Ù\99Ù\86 Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95 Ø­Ø¦Ø³Ø§Ú¤ Ø¯ Ø¦Û\8c Ú¤Û\8cÚ©Û\8c Ø¢Ù\84ئشت Ú©Ø§Ø±Û\8c Ù\86أبÙ\88Ù\99Ø£.",
-       "emaildisabled": "ئÛ\8c Ø¯Û\8cارگÛ\95 Ù\86ئÙ\85Û\8c ØªÙ\88Ù\99Ù\86Û\95 Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95 Ú©Ø¦Ù\84 Ø¨Ø£Ú©Û\95.",
-       "accountcreated": "حئساڤ راس بی",
+       "emailnotauthenticated": "تÛ\8cرÙ\86Ø´Ù\88Ý© Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù± Ø´Ù\85ا ØªØ§ Ø§Û\8cساÙ\92 Ù¾Ù\88شت Ø¯Û\8fرس Ú©Ø§Ø±Û\8c Ù\86اÙ\9bÛ\8cÛ\8cÙ±.\nÙ\87Ù\86Û\8c Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù± Û\8cÛ\8c Ø³Û\8c Ø§Û\8c Ú\86Û\8cا Ú©Ø§Ù\92 Ù\87اÙ\86 Ø±Û\8c Ù\86Ù\87ا Ú©Ù\84Ù\9b Ù\86اÙ\9bÛ\8cÛ\8cÙ±.",
+       "noemailprefs": "Û\8cاÙ\9b ØªÛ\8cرÙ\86Ø´Ù\88Ý© Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù± Ø¯ Ú\86Û\8cا Ù\86ازار Ø´Ù\85ا Ø³Û\8c Û\8cÙ± Ú©Ø§Ù\92 Ø§Ø½ Ø®Ù\88سÛ\8aسÛ\8cٱتؽا Ú©Ø§Ø± Ø¨Ù±Ú©Ù±Ù\86 Ø§Ù\92Ù\86تخاب Ø¨Ù±Ú©Ø½ت.",
+       "emailconfirmlink": "تÛ\8cرÙ\86Ø´Ù\88Ý© Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù± ØªÙ\88Ù\86اÙ\92 Ù¾Ù\88شت Ø±Ø§Ø³Ú©Ø§Ø±Û\8c Ø¨Ù±Ú©Ø½ت",
+       "invalidemailaddress": "تیرنشوݩ ٱنجومانامٱ قبۊل بیئنی نؽ سی یٱ کاْ چی د ڤیر ۉ باڤٱر مؽا ڤٱ شیڤٱ خۊیی نؽ.\nلوتف بٱکؽت یاٛ تیرنشوݩ چۊئٱ دار ناْ بٱزنؽت یا اؽ جاگٱ ناْ هالٛی باٛلٛؽت.",
+       "cannotchangeemail": "تÛ\8cرÙ\86Ø´Ù\88Ý© Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù± Ù\87ساÙ\88 Ø¯ Ø§Ø½ Ú¤Û\8cÚ©Û\8c Ø¢Ù\84شت Ú©Ø§Ø±Û\8c Ù\86Ù\85Û\8aئٱ.",
+       "emaildisabled": "اؽ Ø¯Ø½Ø§Ø±Ú¯Ù± Ù\86Ù\85ؽ ØªÙ\88Ù\86Ù± Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù± Ú©Ù\84Ù\9b Ø¨Ù±Ú©Ù±.",
+       "accountcreated": "هساو دۏرس بی",
        "accountcreatedtext": "حئساڤ کاریاری سی [[{{ns:کاریار}}:$1|$1]] ([[{{ns:کاریار چأک چئنە}}:$1|چأک چئنە]]) دوروس بییە.",
-       "createaccount-title": "حئساڤ سی {{SITENAME}} راس بی",
-       "createaccount-text": "Û\8cئ Ù\86Ø£Ù\81أر Ú¤Ø§ ØªÛ\8cرÙ\86ئشÙ\88Ù\99Ù\86 Ø£Ù\86جÙ\88Ù\85اÙ\86اÙ\85Û\95 ØªÙ\88Ù\99 Û\8cئ Ú¯Ø¦Ù\84 Ø­Ø³Ø§Ú¤ Ø±Ø§Ø³ Ú©Ø¦Ø±Ø¯Û\95 {{SITENAME}} ($4) Ù\88 Ø¦Ù\88سئ Ù\86Ù\88Ù\85ئشÛ\95 Ù\86Û\8cاÛ\95 \"$2\"Ø\8c Ú¤Ø§ Ø±Ø§Ø²Û\8cÙ\86Û\95 Ú¯Ù\88ڤاردئÙ\86 \"$3\".\nØ´Ù\88Ù\85ا Ù\87Ø£Ù\85Û\8c Ø¦Û\8cسئ Ø¨Ø§Û\8cأد Ø±Ù\88Û\8cÛ\8cت Ú¤Ø§Ù\85Û\8cÙ\86 Ù\88 Ø± Ø§Ø²Û\8cÙ\86Û\95 Ú¯Ù\88ڤاردئÙ\86 Ø®Ù\88تÙ\88Ù\99Ù\86Û\95 Ø¢Ù\84ئش Ú©Ø§Ø±Û\8c Ø¨Ø£Ú©Û\8cت.\n\nأر Ø´Ù\88Ù\85ا Ø¯ Ø¦Û\8c Ù¾Ø¦Û\8cغÙ\88Ù\85 Ø¦Ù\84تئÙ\81ات Ù\86Ø£Ú©Û\8cتØ\8c Ø¯ Ú¯Ø§Øª Ø±Ø£Ú¤Ø£Ù\86دÛ\8cارÛ\8c Ø¦Û\8c Ø­Ø¦Ø³Ø§Ú¤ Ø®Ø£Ø·Ø§ Ù¾Û\8cØ´ Ù\85Û\8cا.",
-       "login-throttled": "Ø´Ù\88Ù\85ا ØªØ§ Ø¦Û\8cسئ Ø³Û\8c Ú¤Ø§Ù\85Û\8cÙ\86 Ø¦Ù\88Ù\99Ù\85ائÙ\86 Ù\81ئرÛ\95 ØªØ¦Ù\84اش Ú©Ø¦Ø±Ø¯Û\8cتÛ\95.\n$1 Ù\84Ù\88Ø·Ù\81 Ø¨Ø£Ú©Û\8cت Ø³Û\8c ØªØ¦Ù\84اش Ù\87Ø£Ù\86Û\8c Ú¯Ù\88رÛ\8c Ø¨Ø¦Ø³Û\8cت.",
+       "createaccount-title": "هساو سی {{SITENAME}} دۏرس بی",
+       "createaccount-text": "Û\8cاÙ\9b Ù\86Ù±Ù\81ٱر Ú¤Ø§ ØªÛ\8cرÙ\86Ø´Ù\88Ý© Ù±Ù\86جÙ\88Ù\85اÙ\86اÙ\85Ù± ØªÙ\88 Û\8cاÙ\9b Ù\87ساÙ\88 Ø¯Û\8fرس Ú©Ø±Ø¯Ù± {{SITENAME}} ($4) Û\89 Ø§Û\8aساÙ\92 Ù\86Ù\88Ù\85شاÙ\92 Ù\86ؽاÛ\8cÙ± \"$2\"Ø\8c Ú¤Ø§ Ø±Ø§Ø²Û\8cÙ\86Ù± Ú¯Ù\88ئارسÙ\86 \"$3\".\nØ´Ù\85ا Ù\87اÙ\9b Ø§Û\8cساÙ\92 Ø¨Ø§Û\8cٱد Ø±Û\89Û\8cؽت Ú¤Ø§Ù\85ؽÙ\86 Û\89 Ø±Ø§Ø²Û\8cÙ\86Ù± Ú¯Ù\88ئارسÙ\86 Ø®Ù\88تÙ\88 Ù\86اÙ\92 Ø¢Ù\84شت Ú©Ø§Ø±Û\8c Ø¨Ù±Ú©Ø½Øª.\n\nٱر Ø´Ù\85ا Ú¤ Ø§Ø½ Ù¾Ø§Ù\9bغÙ\88Ù\85 Ø§Ù\92Ù\84تÙ\81ات Ù\86ٱکؽتØ\8c Ø¯ Ú¯Ø§Øª Ø±Ù±Ú¤Ù±Ù\86دؽارÛ\8c Ø§Ø½ Ù\87ساÙ\88 Ø®Ù±ØªØ§ Ù¾Û\8cØ´ Ù\85ؽا.",
+       "login-throttled": "Ø´Ù\85ا ØªØ§ Ø§Û\8cساÙ\92 Ø³Û\8c Ú¤Ø§Ù\85ؽÙ\86 Ø§Ù\88Ù\85اÛ\8cÙ\86 Ù\81رٱ ØªÙ±Ù\81رٱ Ú©Ø±Ø¯Ø½ØªÙ±.\n$1 Ù\84Ù\88تÙ\81 Ø¨Ù±Ú©Ø½Øª Ø³Û\8c ØªÙ±Ù\81رٱ Ù\87Ù\86Û\8c Ú¯Ø±Ø½ Ø¨Ø§Ù\9bسؽت.",
        "login-abort-generic": "ڤامین ئوٙمائن توٙ ناخوش سأرنجوم بی- گأن بی",
-       "login-migrated-generic": "حئساڤ کاریاری شوما جا ڤئ جا بییە، و نوم کاریاری شوما دە د ئی ڤیکی نیئش.",
-       "loginlanguagelabel": "زڤون:$1",
-       "suspicious-userlogout": "د حاست ڤئ دأر رأتئن شوما تیە پوشی بییە سی یە کئ ڤئ نأظأر یما کئ ڤئ سی یئ گئل دوڤارتە نیأر گأن یا یئ گئل پوروکسی کئ ها د ڤیرگە کأش کئل بییە.",
-       "createacct-another-realname-tip": "نوم راستأکی دئل ڤئ حاییە.\nأر شوما ڤئنە نئها ئمایە بأکیت، یە سی هوم نئسبأت دأئن کاریاری سی کاریاش ڤئ کار گئرئتئ بوٙە.",
+       "login-migrated-generic": "هساو کاریاری شما جا ڤ جا بیٱ، ۉ نوم کاریاری شما داٛ د اؽ ڤیکی نؽسش.",
+       "loginlanguagelabel": "زڤوݩ:$1",
+       "suspicious-userlogout": "د هاست ڤ دٱر رٱتن شما تیٱ پۊشی بیٱ سی یٱ کاْ ڤ نٱزٱر اؽما کاْ ڤٱ سی یاٛ دوئارتٱ نیٱر گٱن یا یاٛ پوروکسی کاْ ها د ڤیرگٱ کٱش کلٛ بیٱ.",
+       "createacct-another-realname-tip": "نوم راسٱکی دل بهایی ئٱ.\nٱر شما ڤٱ ناْ آمایٱ بٱکؽت، یٱ سی هوم نسبٱت داٛئن کاریاری سی کارؽاش ڤ کار گرتٱ مۊئٱ.",
        "pt-login": "ڤا مؽن اوماین",
-       "pt-login-button": "ڤامؽن اوماین",
+       "pt-login-button": "ڤا مؽن اوماین",
        "pt-createaccount": "هساو دۏرس بٱکؽت",
        "pt-userlogout": "د سامونٱ دروماین",
-       "php-mail-error-unknown": "خأطا نادیار د آلئشتگئر PHP's mail()",
-       "user-mail-no-addy": "سی کئل کئردئن أنجومانامە د یئ گئل أنجومانامە بی تیرنئشوٙن أنجومانامه تئلاش بییە.",
-       "user-mail-no-body": "سی کئل کئردئن أنجومانامە ڤا مینوٙنە حالی یا کوچئک بییئن سی دألیل یا غئر مأنطئقی بییئن ڤئ تئلاش بأکیت.",
-       "changepassword": "رارینە گوڤاردئن نە آلئشت بأکیت",
-       "resetpass_announce": "سی تأموم کئردئن ڤامین ئوٙمائن، شوما بایأد یئ گئل رازینە گوڤاردئن هأنی نە بأزئنیت.",
+       "php-mail-error-unknown": "خٱتا نادؽار د آلشتگٱر PHP's mail()",
+       "user-mail-no-addy": "سی کلٛ کردن ٱنجومانامٱ ڤ یاٛ ٱنجومانامٱ بؽ تیرنشوݩ ٱنجومانامٱ تلاش بیٱ.",
+       "user-mail-no-body": "سی کلٛ کردن ٱنجومانامٱ ڤا مؽنونٱ هالٛی یا کوچک بیئن سی دلٛیلٛ یا غاٛر مٱنتقی بیئن ڤٱ تٱفرٱ بٱکؽت.",
+       "changepassword": "رارینٱ گوئارسن ناْ آلشت بٱکؽت",
+       "resetpass_announce": "سی تموم کردن ڤامؽن اوماین، شما بایٱد یاٛ رازینٱ گوئارسن هنی ناْ بٱزنؽت.",
        "resetpass_text": "<!-- یه گل نیسسه ایچه اضاف بکیت -->",
-       "resetpass_header": "رازینە گوڤاردئن حئساڤئ توٙنە آلئشت بأکیت",
-       "oldpassword": "رازینە گوڤاردئن دئمایی:",
-       "newpassword": "رازینە گوڤاردئن تازە:",
-       "retypenew": "رازینە گوڤاردئن تازە نئ د نۊ أنجومیارنیسی بأکیت:",
-       "resetpass_submit": "رازینە گوڤاردئن نە بأزئنیت و بیاییت ڤامین",
+       "resetpass_header": "رازینٱ گوڤارسن هساو تو ناْ آلشت بٱکؽت",
+       "oldpassword": "رازینٱ گوڤارسن دمایی:",
+       "newpassword": "رازینٱ گوئارسن تازٱ:",
+       "retypenew": "رازینٱ گوئارسن تازٱ ناْ د نۊ ٱنجومیارنیسی بٱکؽت:",
+       "resetpass_submit": "رازینٱ گوئارسن ناْ بٱزنؽت ۉ بؽایؽت ڤامؽن",
        "changepassword-success": "رازینە گوڤاردئن شوما ڤا خوٙیی آلئشت کاری بی!",
-       "changepassword-throttled": "Ø´Ù\88Ù\85ا ØªØ§ Ø¦Û\8cسئ Ø³Û\8c Ú¤Ø§Ù\85Û\8cÙ\86 Ø¦Ù\88Ù\99Ù\85ائÙ\86 Ù\81ئرÛ\95 ØªØ¦Ù\84اش Ú©Ø¦Ø±Ø¯Û\8cتÛ\95.\n$1 Ù\84Ù\88Ø·Ù\81 Ø¨Ø£Ú©Û\8cت Ø³Û\8c ØªØ¦Ù\84اش Ù\87Ø£Ù\86Û\8c Ú¯Ù\88رÛ\8c Ø¨Ø¦Ø³Û\8cت.",
+       "changepassword-throttled": "Ø´Ù\88Ù\85ا ØªØ§ Ø§Û\8cساÙ\92 Ø³Û\8c Ú¤Ø§Ù\85ؽÙ\86 Ø§Ù\88Ù\85اÛ\8cÙ\86 Ù\81رٱ ØªÙ±Ù\81رٱ Ú©Ø±Ø¯Ø½ØªÙ±.\n$1 Ù\84Ù\88تÙ\81 Ø¨Ù±Ú©Ø½Øª Ø³Û\8c ØªÙ±Ù\81راÙ\9b Ù\87Ù\86Û\8c Ú¯Ø±Ø½ Ø¨Ø§Ù\9bسؽت.",
        "resetpass_forbidden": "نأبوٙە رازینە گوڤاردنیانە آلئشتکاری بأکیت",
        "resetpass-no-info": "شوما سی یە کئ د ئی بألگە دأسرئسی داشتوٙییت باس بیاییت ڤامین.",
        "resetpass-submit-loggedin": "رارینە گوڤاردئن نە آلئشت بأکیت",
        "resettokens-resetbutton": "نئشوٙنە گولئ ڤورچیە د نوٙ زئنە بینە",
        "bold_sample": "نیسسٱ مؽن پور",
        "bold_tip": "نیسسٱ مؽن پور",
-       "italic_sample": "نیسسٱ کٱج ۉ هار",
-       "italic_tip": "نیسسٱیا Ú©Ù±Ø¬ Û\89 Ú©Ù\88Ù\84Ù±",
+       "italic_sample": "نیسسٱیا هٱلٛ ۉ هار",
+       "italic_tip": "نیسسٱیا Ù\87Ù±Ù\84Ù\9b Û\89 Ù\87ار",
        "link_sample": "داسون هوم پاٛڤٱن",
        "link_tip": "هوم پاٛڤٱن مؽنجایی",
        "extlink_sample": "http://www.example.com داسون هوم پاٛڤٱن",
        "savearticle": "آمادٱ کردن بٱلگٱ",
        "preview": "پيش ساٛلٛ",
        "showpreview": "نشوݩ داٛئن پیش ساٛلٛ",
-       "showdiff": "نشوݩ داٛین آلشتکاریا",
-       "blankarticle": "<strong>زÙ\86ئار:</strong> Ø¨Ù\84Ú¯Ù\87 Ø§Û\8c Ú©Ù\87 Ø´Ù\85ا Ø¯Ø±Ù\88س Ú©Ø±Ø¯Û\8cتÙ\87 Ø­Ø§Ù\84Û\8cÙ\87.\nار Ø´Ù\85ا Ø¯ Ù\86Ù\88 Ø±Û\8c \"$1\" Ø¨Ù¾Ù\88رÙ\86Û\8cت, Ø¨Ù\84Ú¯Ù\87 Ù\88Ù\87 Ø´Ú©Ù\84 Ú©Ù\87 Ù\87Û\8cÚ\86 Ù\85Û\8cÙ\86Ù\88Ù\86Ù\87 Ø§Û\8c Ø¯Ø´ Ù\86با Ø¯Ø±Ù\88س Ø¨Ù\88ئÙ\87.",
-       "anoneditwarning": "<strong>زٱنڳیار:</strong> شما هنی نۏمایتٱ ڤامؽن. تیرنشوݩ آی پی شما سی هٱر گاتؽ کاْ آلشتکاری بٱکؽت سی کولٛ خٱلک دؽاری مؽکٱ. ٱر <strong>[$1 رۉییت ڤامؽن]</strong> یا <strong>[$2 یاٛ هساو کاریاری دۏرس بٱکؽت]</strong>، ڤیرایشتؽا شما ڤ نوم کاریاری خوتو دیاری مؽکٱ ۉ سی شما بؽترٱ.",
+       "showdiff": "نشوݩ داٛئن آلشتکاریا",
+       "blankarticle": "<strong>زÙ\86ئار:</strong> Ø¨Ù±Ù\84گاÙ\9bÛ\8cؽ Ø§Ù\92 Ø´Ù\85ا Ø¯Û\8fرس Ú©Ø±Ø¯Ø½ØªÙ± Ù\87اÙ\84Ù\9bÛ\8cÙ±.ٱر Ø´Ù\85ا Ø¯ Ù\86Û\8a Ø±Û\8c \"$1\" Ø¨Ù±Ù¾Û\8aرÙ\86ؽت, Ø¨Ù±Ù\84Ú¯Ù± Ú¤ Ø´Ú©Ù\84ؽ Ú©Ø§Ù\92 Ù\87Û\8cÚ\86 Ù\85Û\8cÙ\86Ù\88Ù\86اÙ\9bÛ\8cؽ Ø¯Ø´ Ù\86Û\8aئٱ Ø¯Û\8fرس Ù\85Û\8aئٱ.",
+       "anoneditwarning": "<strong>زٱنڳیار:</strong> شما هنی نۏمایتٱ ڤامؽن. تیرنشوݩ آی پی شما سی هٱر گاتؽ کاْ آلشتکاری بٱکؽت سی کولٛ خٱلک دؽاری مؽکٱ. ٱر <strong>[$1 رۉؽت ڤامؽن]</strong> یا <strong>[$2 یاٛ هساو کاریاری دۏرس بٱکؽت]</strong>، ڤیرایشؽا شما ڤ نوم کاریاری خوتو دؽاری مؽکٱ ۉ سی شما بؽترٱ.",
        "anonpreviewwarning": "<em>شوما نیوٙمایتە ڤامین. تیرنئشوٙن آی پی شوما د ڤیرگار ڤیرایئشت ئی بألگە ئمایە بوٙە.</em>",
        "missingsummary": "<strong>ڤیر دیارکو:</strong> شوما هأنی یئ گئل چئکئسە ڤیرایئشتی نە نئها ئمایە کاری نأکئردیتە.\nأر شوما د نۊ د ری \"$1\" بأپوٙرنیت، ڤیرایئشت کاری شوما حالی ئمایە بوٙە.",
-       "selfredirect": "<strong>Ù\87Ù\88شدار:</strong> Ø´Ù\88Ù\85ا Ø¯ Ø­Ø§Ù\84 Ù\88 Ø¨Ø§Ù\84 Ú¤Ø§Ú¯Ø£Ø±Ø¯Ù\88Ù\99Ù\86Û\8c Ø¦Û\8c Ø¨Ø£Ù\84Ú¯Û\95 Ø¯ Ø®Ù\88Ø´ Ù\87Û\8cÛ\8cÙ\86.\nگاسÛ\8c Ø¯Ø§Ù\84 Ø¦Ø´ØªØ¦Ú¤Ø§Û\8cÛ\8c Ø³Û\8c Ú¤Ø§Ú¯Ø£Ø±Ø¯Ù\88Ù\99Ù\86Û\8c Ø¦Ù\86تئخاڤ Ú©Ø¦Ø±Ø¯Û\8cتÛ\95Ø\8c Û\8cا Ú¯Ø§Ø³Û\8c Ø¨Ø£Ù\84Ú¯Û\95 Ù\86Û\95 Ø¦Ø´ØªØ¦Ú¤Ø§Û\8cÛ\8c Ú¤Û\8cراÛ\8cئشت Ú©Ø§Ø±Û\8c Ù\85Û\8c Ú©Û\8cت.\nأر Ø±Û\8c \"$1\" Ø¯Û\8a Ú¯Ø¦Ù\84 Ø¨Ø£Ù¾Ù\88Ù\99رÙ\86Û\8cتØ\8c Ú¤Ø§Ú¯Ø£Ø±Ø¯Ù\88Ù\99Ù\86Û\8c Ø±Ø§Ø³ Ù\85Ù\88Ù\99Û\95.",
+       "selfredirect": "<strong>Ù\87Ù\88شدار:</strong> Ø´Ù\85ا Ø¯ Ù\87اÙ\84 Û\89 Ø¨Ø§Ù\84 Ú¤Ø§Ú¯Ù±Ø±Ø¯Ù\88Ù\86Û\8c Ø§Ø½ Ø¨Ù±Ù\84Ú¯Ù± Ø¯ Ø®Ù\88Ø´ Ù\87ؽسؽت.\nگاسؽ Ø¯Ø§Ù\84 Ø§Ù\92شتباÛ\8cÛ\8c Ø³Û\8c Ú¤Ø§Ú¯Ù±Ø±Ø¯Ù\88Ù\86Û\8c Ø§Ù\92Ù\86تخاب Ú©Ø±Ø¯Ø½ØªÙ±Ø\8c Û\8cا Ú¯Ø§Ø³Ø½ Ø¨Ù±Ù\84Ú¯Ù± Ù\86اÙ\92 Ø§Ù\92شتباÛ\8cÛ\8c Ú¤Û\8cراÛ\8cØ´ Ù\85ؽکؽت.\nٱر Ø±Û\8c \"$1\" Ø¯Û\8f Ú¯Ù\84Ù\9b Ø¨Ù±Ù¾Û\8aرÙ\86ؽتØ\8c Ú¤Ø§Ú¯Ù±Ø±Ø¯Ù\88Ù\86Û\8c Ø¯Û\8fرس Ù\85Û\8aئٱ.",
        "missingcommenttext": "لوطف بأکیت ئیچئ ڤیر و باڤأرئ خوتوٙنە بأنیست.",
        "missingcommentheader": "<strong>د ڤیر ڤونا:</strong> شوما هأنی یئ گئل داسوٙن/سأرڤأن سی ئی ڤیر و باڤأر نئها ئمایە نأکئردیتە.\nأر شوما یئ گئل هأنی ری \"$1\" بأپوٙرنیت، ڤیرایئشت کاری شوما حالی ئمایە بوٙە.",
        "summary-preview": "چئکئسە پیش سئیل:",
        "newarticle": "تازە",
        "newarticletext": "شما هائؽت ڤا دما هوم پاٛڤٱنؽ اْ ڤوجۊد نارٱ.\nسی رٱڤٱندؽاری بٱلگٱ.شرۊ بٱکؽت مؽن جٱڤٱ هوری بٱنیسؽت (سی دونسن بؽشتر ساٛلٛ [$1 ] بٱکؽت).\nٱر شما سی اْشتبا کردن هائؽت ایچاْ، ری دۏگمٱ ڤادما رٱتن دوئارتٱ نیٱر بٱپۊرنؽت.",
        "anontalkpagetext": "----",
-       "noarticletext": "د ایسنؽا اؽ بٱلگٱ نیسسٱ ڤجۊد ناشتٱ.\nشما مؽ تونؽت د[[Special:Search/{{PAGENAME}}|بٱگٱردؽد]] د اؽ بٱلگٱ اؽ د بٱلگٱ هنی یا <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} د نۊ پاٛجۊری بۊئٱ]</span>، <span class=\"plainlinks\">[{{fullurl:{{FULLPAGENAME}}|action=edit}} یا ای بٱلگٱ ناْ ڤیرایش بٱکؽت]</span>.",
+       "noarticletext": "د ایسنؽا اؽ بٱلگٱ نیسسٱ ڤجۊد ناشتٱ.\nشما مؽ تونؽت د[[Special:Search/{{PAGENAME}}|ڤگٱردؽد]] د اؽ بٱلگٱ ڤ بٱلگٱ هنی یا <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} د نۊ پاٛجۊری بۊئٱ]</span>، <span class=\"plainlinks\">[{{fullurl:{{FULLPAGENAME}}|action=edit}} یا ای بٱلگٱ ناْ ڤیرایش بٱکؽت]</span>.",
        "noarticletext-nopermission": "د ایسنؽا اؽ بٱلگٱ نیسساٛیؽ ڤجۊد ناشتٱ.\nشما مؽ تونؽت د[[Special:Search/{{PAGENAME}}|بٱگردؽد]] د اؽ بٱلگٱیا د بٱلگٱ هنی یا <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} د نۊ پاٛجۊری بۊئٱ]</span>، <span class=\"plainlinks\">[{{fullurl:{{FULLPAGENAME}}|action=edit}}</span>.ڤلی شما سلا یٱناْ کاْ اؽ بٱلگٱ ناْ دۏرس بٱکؽت نارؽت.",
        "missing-revision": "ڤانئیأری #$1 د بألگە یی کئ نومئش ڤئنە \"{{FULLPAGENAME}}\" ڤوجوٙد نارە.\n\nگاسی سی یئ گئل ڤیرگار ڤئ هئنگوم نأبییە کئ د یئ گئل بألگە پاکسا بییە هوم پئیڤأند بییە رأڤأندیاری بییە.\nگاسی جوزئیات د[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} deletion log] دیاری بأکأن.",
        "userpage-userdoesnotexist": "حئساڤ کاریاری \"$1\" ثأڤت نأم نأبییە.\nأر میھایت ئی بألگە نئ بأسازیت یا ڤیرایئشت کاری بأکیت یئ گئل ڤارئسی أنجوم بئیتوٙ.",
        "semiprotectedpagewarning": "<strong>د ڤیر داشتوٙئیت:</strong> ئی بألگە سی یە کئ فأقأط کاریاریا ثأڤتئنام کئردە تونئسوٙئن دئش ڤیراشتکار بأکأن پأر و پیم بییە.\nآخئری پئھرئستنوٙمە دأئە بییە سی سأرچئشمە ھاری نئھا ئمایە بییە:",
        "cascadeprotectedwarning": "<strong>زئنار:</strong> ئی بألگە ڤئ دأس کاریاریایی کئ صئلا سأردیڤوٙنکاری دارن می توٙنە ڤیرایئشت کاری بوٙە سی یە کئ ئی بألگە ڤئ رأڤئشت تاف نئمایی پأر و پیم کاری بییە {{PLURAL:$1|بألگە|بألگە یا}}:",
        "titleprotectedwarning": "<strong>زئنار:ئی بألگە پأر و پیم بییە سی یە کئ [[Special:نومگە حوقوٙق کاریاری جأرغە|حوقوٙق ڤیجە]] بایأد ڤئنە رأڤأندیاری بأکأن.</strong>\nآخئری پئھرئستنوٙمە دأ بییە سی سأرچئشمە دأئن نئھا ئمایە بییە:",
-       "templatesused": "{{PLURAL:$1|چۊٱ|چۊٱ یا}} ڤ کار گرتٱ بیٱ د اؽ بٱلگٱ:",
-       "templatesusedpreview": "{{PLURAL:$1| چۊٱ|چۊٱ یا}} ڤ کار گرتٱ بیٱ د پیش ساٛلٛ :",
-       "templatesusedsection": "{{PLURAL:$1|چوٙأ|چوٙأ یا}} ڤئ کار گئرئتە بییە د ئی بأرجا:",
-       "template-protected": "(پٱر ۉ پیم بیٱ)",
-       "template-semiprotected": "(نسم ۉ نیمٱ پٱر ۉ پیم بیٱ)",
+       "templatesused": "{{PLURAL:$1|چۊئٱ|چۊئٱ یا}} ڤ کار گرتٱ بیٱ د اؽ بٱلگٱ:",
+       "templatesusedpreview": "{{PLURAL:$1| چۊئٱ|چۊئٱ یا}} ڤ کار گرتٱ بیٱ د پیش ساٛلٛ :",
+       "templatesusedsection": "{{PLURAL:$1|چۊئٱ|چۊئٱ یا}} ڤ کار گرتٱ بیٱ د اؽ بٱلگٱ:",
+       "template-protected": "(پر ۉ پیم بیٱ)",
+       "template-semiprotected": "(نسم ۉ نیمٱ پر ۉ پیم بیٱ)",
        "hiddencategories": "اؽ بٱلگٱ یٱکؽ د ٱندومؽا ٱ {{PLURAL:$1|1 hidden category|$1 hidden categories}} :",
        "edittools-upload": "-",
        "nocreatetext": "{{SITENAME}} سی رأڤأندیاری بألگە یا تازە نئھاگئری بییە.\nشوما می توٙنیت روئیت ڤادئما و بألگە ئی کئ بییشە ڤیرایئشت کاری بأکیت،[[Special:ڤامین ئوٙمائن کاریار|بیائیت ڤامین یا یە کئ یئ گئل حئساڤ دوروس بأکیت]].",
        "sectioneditnotsupported-text": "ڤیرایئشت بأرجایی د ئی بألگە نیئش.",
        "permissionserrors": "خٱتا سلا داٛئن",
        "permissionserrorstext": "شوما حأق ناریت ڤئنە أنجوم بئیت، سی{{PLURAL:$1|دألیل|دألیلیا}} نئھایی:",
-       "permissionserrorstext-withaction": "شما سی $2 سلا \nنھاگری نارؽت {{PLURAL:$1|دلٛیلٛ|دلٛیلٛؽا}}:",
-       "recreate-moveddeleted-warn": "'''ڤ ڤیرتو با:شما بٱلگاٛیی کاْ ھا ڤادما ۉ پاکسا بیٱ د نۊ دۏرس کردؽتٱ.'''\nبایٱد د ڤیرتو با کاْ آیا ھنی نوئاگیری ڤیرایش اؽ بٱلگٱ خۊئٱ.\nپاکسا کاری ۉ جا ڤ جا کاری اؽ بٱلگٱ سی هال ۉ بال پٱلٛٱمار شما آمادٱ بیٱ:",
-       "moveddeleted-notice": "اؽ بٱلگٱ پاکسا بیٱ.\nپاکسا کاری ۉ جا ڤ جا کاری اؽ بٱلگٱ سی هال ۉ بال پٱلٛٱمار شما آمادٱ بیٱ.",
+       "permissionserrorstext-withaction": "شما سی $2 سلا \nنھاگیری نارؽت {{PLURAL:$1|دلٛیلٛ|دلٛیلٛؽا}}:",
+       "recreate-moveddeleted-warn": "'''ڤ ڤیرتو با:شما بٱلگاٛیی کاْ ھا ڤادما ۉ پاکسا بیٱ د نۊ دۏرس کردؽتٱ.'''\nبایٱد د ڤیرتو با کاْ آیا ھنی نوئاگیری ڤیرایش اؽ بٱلگٱ خۊئٱ.\nپاکسا کاری ۉ جا ڤ جا کاری اؽ بٱلگٱ سی هال ۉ بار پٱلٛٱمار شما آمادٱ بیٱ:",
+       "moveddeleted-notice": "اؽ بٱلگٱ پاکسا بیٱ.\nپاکسا کاری ۉ جا ڤ جا کاری اؽ بٱلگٱ سی هال ۉ بار پٱلٛٱمار شما آمادٱ بیٱ.",
        "log-fulllog": "دیئن هأمە پئهئرستنوٙمە یا",
        "edit-hook-aborted": "ڤیرایئشت ڤا قولاڤ نئھاگئری بییە.\nھیچ توضیی سیش نی.",
        "edit-gone-missing": "نأبوٙە ئی بألگە نە ڤئ ھئنگوم بأکیت.\nچئنی ڤئ نأظأر میا کئ ڤئ پاکسا بییە.",
        "previousrevision": "ڤانیٱری زیتری ←",
        "nextrevision": "ڤانؽٱری تازٱتر",
        "currentrevisionlink": "آخری ڤانؽٱری",
-       "cur": "تازٱ باو",
+       "cur": "تازٱ بۊ",
        "next": "نئهایی",
        "last": "دمایی",
        "page_first": "أڤئلی",
        "page_last": "آخئر",
-       "histlegend": "اÙ\92Ù\86تخاب Ù\81ٱرخدار:جٱڤٱÛ\8cا Ø±Ø§Ø¯Û\8cÙ\88 Ù\86اÙ\92 Ø³Û\8c Ø¯Ù\88ئارٱ Ø¯Û\8cئÙ\86 Û\89 Ú¤Ø§Ø±Ø³Û\8c Ù\86Ø´Ù\88Ý© Ø¯Ø§Ø± Ø¨Ù±Ú©Ø½Øª Û\89 Û\8cا Ø±Û\8c Ø±Ù±ØªÙ\86 Ú©Ù\84Ù\9bÛ\8cÚ© Ø¨Ù±Ú©Ø½Øª .<br />\nشرح Ù\86Ù\88شتÙ\87: '''({{int:cur}})''' = ڤا آخری دوئارٱ دیئن فٱرخ دارٱ '''({{ int:last}})'''= ڤا دوئارٱ دیئن ٱنجوم داٛئنی فٱرخ دارٱ  '''{{int:minoreditletter}}''' =ڤیرایش کوچک.",
+       "histlegend": "اÙ\92Ù\86تخاب Ù\81ٱرخدار:جٱڤٱÛ\8cا Ø±Ø§Ø¯Û\8cÙ\88 Ù\86اÙ\92 Ø³Û\8c Ø¯Ù\88ئارٱ Ø¯Û\8cئÙ\86 Û\89 Ú¤Ø§Ø±Ø³Û\8c Ù\86Ø´Ù\88Ý© Ø¯Ø§Ø± Ø¨Ù±Ú©Ø½Øª Û\89 Û\8cا Ø±Û\8c Ø±Ù±ØªÙ\86 Ú©Ù\84Ù\9bÛ\8cÚ© Ø¨Ù±Ú©Ø½Øª .<br />\nتÛ\89سÛ\8cÙ\81 Ù\86Ú¤Û\8cسٱ: '''({{int:cur}})''' = ڤا آخری دوئارٱ دیئن فٱرخ دارٱ '''({{ int:last}})'''= ڤا دوئارٱ دیئن ٱنجوم داٛئنی فٱرخ دارٱ  '''{{int:minoreditletter}}''' =ڤیرایش کوچک.",
        "history-fieldset-title": "ڤیرگار دوئارٱ نیٱری",
        "history-show-deleted": "فقط پاكسا بيه",
        "histfirst": "قاٛیمی تریݩ",
        "rev-suppressed-unhide-diff": "وانئری ای بلگه <strong>پاکساگری بیه</strong>.\nجزئیات هان د  [{{fullurl:{{#Special:Log}}/پاکساگری کردن|بلگه={{نوم کامل بلگه}}}} پهرستنومه پاکساگری کردن].\nشما  هنی تونیت [$1ای وانئری نه بونیت] ار بهاییت.",
        "rev-deleted-diff-view": "وانئری ای بلگه <strong>پاکسا بیه</strong>.\nجزئیات هان د  [{{fullurl:{{#Special:Log}}/پاکسا کردن|بلگه={{نوم کامل بلگه}}}} پهرستنومه پاکساکردن].",
        "rev-suppressed-diff-view": "وانئری بلگه <strong>پاکساگری</strong>.\nجزئیات هان د  [{{fullurl:{{#Special:Log}}/پاکساگری کردن|بلگه={{نوم کامل بلگه}}}} پهرستنومه پاکساگری کردن].",
-       "rev-delundel": "آلشت هال ۉ بال ديئن",
+       "rev-delundel": "آلشت هال ۉ بار ديئن",
        "rev-showdeleted": "نئشوٙ دأئن",
        "revisiondelete": "پاکسا کردن/زنه کردن وانئریا",
        "revdelete-nooldid-title": "وانیری تمارزی بیه نامعتوره",
        "difference-title-multipage": "فرخ مینجا بلگه یا \"$1\" و \"$2\"",
        "difference-multipage": "(فرخ مینجا بلگه یا)",
        "lineno": "خٱت $1:",
-       "compareselectedversions": "دوئارٱ دی ینؽایؽ کاْ اْنتخاو بینٱ ناْ موقایسٱ بٱکؽت",
+       "compareselectedversions": "دوئارٱ دیئنؽایؽ کاْ اْنتخاو بینٱ ناْ موقایسٱ بٱکؽت",
        "showhideselectedversions": "شلک دیئن وانیریا انتخاو بیه نه آلشت بکید",
        "editundo": "ناٱنجومگر کردن",
        "diff-empty": "(بؽ فٱرق)",
        "prev-page": "بلگه دمايی",
        "next-page": "بلگه نهایی",
        "prevn-title": "زیتر $1 {{PLURAL:$1|نٱتیجٱ|نٱتيجٱيا}}",
-       "nextn-title": "دمایی $1 {{PLURAL:$1|نتيجٱ|نتيجيا}}",
-       "shown-title": "نشوݩ داٛین $1 {{PLURAL:$1|نتیجٱ|نتیجٱیا}} سی هار بٱلگٱ",
-       "viewprevnext": "ديین ($1 {{int:pipe-separator}} $2) ($3)",
+       "nextn-title": "دمایی $1 {{PLURAL:$1|نٱتيجٱ|نٱتيجؽا}}",
+       "shown-title": "نشوݩ داٛین $1 {{PLURAL:$1|نتیجٱ|نتیجٱیا}} سی هٱر بٱلگٱ",
+       "viewprevnext": "ديئن ($1 {{int:pipe-separator}} $2) ($3)",
        "searchmenu-exists": "'''ایچاْ بٱلگاٛیؽ هؽ ڤ نوم\"[[:$1]]\" کاْ ها د اؽ ڤیکی'''",
        "searchmenu-new": "'''اؽ بٱلگٱ ناْ دۏرس كو \"[[:$1]]\" د اؽ ڤیکی!'''",
        "searchprofile-articles": "بٱلگٱيا مؽنونٱ دار",
-       "searchprofile-images": "ڤارسگرؽا خلکمن",
+       "searchprofile-images": "ڤارسگرؽا Ø®Ù\84Ú©Ù\85Ù±Ù\86",
        "searchprofile-everything": "همٱ چی",
        "searchprofile-advanced": "پیشکردٱ",
        "searchprofile-articles-tooltip": "بٱگٱرد مؽن $1",
-       "searchprofile-images-tooltip": "جانؽایاناْ پاٛ جۊری کو",
-       "searchprofile-everything-tooltip": "همٱ مؽنونٱیا ناْ پۊ جۊری كو (شاملاْ بٱلگٱيا چٱک چنٱ)",
+       "searchprofile-images-tooltip": "جانؽایا ناْ پاٛ جۊری کو",
+       "searchprofile-everything-tooltip": "همٱ مؽنونٱیا ناْ پاٛ جۊری كو (شامل بٱلگٱيا چٱک چنٱ)",
        "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-interwiki-more": "(بیشتر)",
        "search-relatedarticle": "مرتوط",
        "searchrelated": "مرتوط",
-       "searchall": "Ù\87Ù±Ù\85Ù±",
+       "searchall": "همٱ",
        "showingresults": "نمائشت بیشترونه {{PLURAL:$1|'''۱''' نتیجه|'''$1''' نتیجه}} د هار، شرو د شماره'''$2'''.",
        "showingresultsinrange": "نمائشت بیشترونه {{PLURAL:$1|'''۱''' نتیجه|'''$1''' نتیجه}} د هار، شرو د شماره'''$2''' تا شماره '''$3'''.",
        "search-showingresults": "{{PLURAL:$4|نٱتیجٱیا<strong>$1</strong> د <strong>$3</strong>|نٱتیجٱیا<strong>$1 - $2</strong د <strong>$3</strong>}}",
        "enhancedrc-history": "ڤیرگار",
        "recentchanges": "آلشتؽا ایسنی",
        "recentchanges-legend": "گوزینٱیا آلشتؽا ایسنی",
-       "recentchanges-summary": "دۏ بؽشتر آلشتؽا تازباو ناْ د ڤیکی د اؽ بٱلگٱ پاٛجۊری کو.",
-       "recentchanges-noresult": "هیچ آلشتؽ د درازا دۉرٱ دؽار بیٱ ڤا اؽ ماٛعیاؽا یٱکی ناٛی.",
+       "recentchanges-summary": "دۏ بؽشتر آلشتؽا تازٱبۊ ناْ د ڤیکی د اؽ بٱلگٱ پاٛجۊری کو.",
+       "recentchanges-noresult": "Ù\87Û\8cÚ\86 Ø¢Ù\84شتؽ Ø¯ Ø¯Ø±Ø§Ø²Ø§ Ø¯Û\89رٱ Ø¯Ø½Ø§Ø± Ø¨Û\8cÙ± Ú¤Ø§ Ø§Ø½ Ù\85اÙ\9bعÛ\8cارؽا Û\8cÙ±Ú©Û\8c Ù\86اÙ\9bÛ\8c.",
        "recentchanges-feed-description": "دۏ بؽشتر آلشتؽا تازباو ناْ د ڤیکی کا ها د هڤال هون پاٛگیری کو.",
        "recentchanges-label-newpage": "اؽ ڤیرایش یاٛ بٱلگٱ تازٱ دۏرس کردٱ.",
        "recentchanges-label-minor": "یٱ یاٛ ڤیرایش کوچکٱ",
        "recentchanges-label-bot": "اؽ ڤيرايش ناْ ياٛ بوت ٱنجوم داٛیٱ",
-       "recentchanges-label-unpatrolled": "اؽ ڤيرايش هنی تيٱ ڤاداشت ناٛیٱ",
+       "recentchanges-label-unpatrolled": "اؽ ڤيرايش هنی تيٱ ڤاداشت ناٛیئٱ",
        "recentchanges-label-plusminus": "ٱندازٱ بٱلگٱ ڤ شماراٛ اؽ بایتؽا آلشت کردٱ.",
        "recentchanges-legend-heading": "<strong>میرات:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (همچنو باٛینؽت [[ڤیژٱ:بٱلگٱیا تازٱ|نوم گٱ بٱلگٱیا تازٱ]])",
        "rcshowhideminor-show": "نشوݩ داٛئن",
        "rcshowhideminor-hide": "قایم کردن",
        "rcshowhidebots": "$1 روباتؽا یا بوتؽا",
-       "rcshowhidebots-show": "نشوݩ داٛین",
+       "rcshowhidebots-show": "نشوݩ داٛئن",
        "rcshowhidebots-hide": "قایم کردن",
        "rcshowhideliu": "$1 کاریاریا سٱبت نوم کردٱ",
        "rcshowhideliu-show": "نشوݩ داٛئن",
        "diff": "فٱرق",
        "hist": "ڤیرگار",
        "hide": "قایم کردن",
-       "show": "نشوݩ داٛین",
+       "show": "نشوݩ داٛئن",
        "minoreditletter": "م",
        "newpageletter": "ن",
        "boteditletter": "ب",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 دینه {{PLURAL:$1|کاریار|کاریاریا}}]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|بایت|بایتؽا}} دما آلشتکاری",
        "newsectionsummary": "/* $1 */ بهرجا تازه",
        "rc-enhanced-expand": "جزيات نشون بيئه",
        "rc-enhanced-hide": "جزياته قام كو",
-       "rc-old-title": "ذاتا چی \"$1\" راس بیه",
+       "rc-old-title": "کاملٱن چی \"$1\"دۏرس بیٱ",
        "recentchangeslinked": "آلشتؽا تاٛ یٱکؽ",
        "recentchangeslinked-feed": "آلشتؽا تاٛ یٱک",
        "recentchangeslinked-toolbox": "آلشتؽا تاٛ یٱک",
        "img-auth-nopathinfo": "PATH_INFO نیئش.\nسرور شما سی گواردن ای انازه میزونکاری نبیه.\n شات د پایه سی جی آی با و حامین دار img_auth نبا.\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization سیل بکیت.",
        "img-auth-notindir": "مسیر حاسته بیه د لشک سوارکرد میزونکاری بیه نئ.",
        "img-auth-badtitle": "امکان راس کردن یه سرون مجازی د «$1» وجود ناره.",
-       "img-auth-nologinnWL": "شما هنی نیومایته وامین و «$1» د نوم گه اسبئ نیئش.",
        "img-auth-nofile": "فایل $1 وجود ناره.",
        "img-auth-isdir": "شما سی رسسن وه لشگ «$1» تلاش کردیته.\nتئنا می تونیت وه جانیا دسرسی داشتویت.",
        "img-auth-streaming": "د حال کل کردن \"$1\".",
        "upload-curl-error6-text": "تیرنشون اینترنتی که دئیته د دسرس نئ.\nلطف بکیت درستیشه و یه نه که تیرنشون اینترنی میزونکاری بیه وارسی بکیت.",
        "upload-curl-error28": "تموم بیئن مئلت سی سوار کرد",
        "upload-curl-error28-text": "ای دیارگه فره دیر دتو واکنشت نشو دئه.\nلطف بکیت سی یه که دیارگه کنشگتر و ری خطه یه گل وارسی بکیت، اوسه یه گر واستید و هنی تلاش بکیت.\nشایت بیتر با که د گات خلوتری هنی تلاش بکیت.",
-       "license": "ليانس دار بيئن",
-       "license-header": "د هال ۉ بال لیسانس دار بیئن",
+       "license": "Ù\84Ù\8aساÙ\86س Ø¯Ø§Ø± Ø¨Ù\8aئÙ\86",
+       "license-header": "د هال ۉ بار لیسانس دار بیئن",
        "nolicense": "هیچی انتخاو نبیه",
        "licenses-edit": "گزینه یا مجوز ویرایشت",
        "license-nopreview": "(پیش سیل د دسرس نئ)",
        "filehist-revert": "لٛرنیئن",
        "filehist-current": "تازٱ با",
        "filehist-datetime": "ڤيرگار/ڤٱخت",
-       "filehist-thumb": "عٱسک کوچک بیٱ",
+       "filehist-thumb": "عٱسگ کوچک بیٱ",
        "filehist-thumbtext": "كوچک کردن سی نۏسخٱ چی $1",
        "filehist-nothumb": "بؽ بٱن کلٛکی",
        "filehist-user": "کاریار",
        "imagelinks": "ڤ کار گرتن جانؽا",
        "linkstoimage": "دۏنبال بيٱ {{PLURAL:$1|ديس ڤنؽا بٱلگٱ|$1 ديس ڤنؽا بٱلگٱيا}} د اؽ فایلٛ:",
        "linkstoimage-more": "بؽشتر د $1 بٱلگٱ د اؽ جانؽا هوم پاٛڤٱن {{PLURAL:$1|بٱ|بینٱ}}.\nنومگٱ هاری تٱنڳؽا{{PLURAL:$1|ٱڤلی هوم پاٛڤٱن|ٱڤلی $1 هوم پاٛڤٱن}} د ؽ بٱلگٱ ناْ نشوݩ مؽ یٱ.\n[[Special:WhatLinksHere/$2|نومگٱ کامل]] ٱم هؽسش.",
-       "nolinkstoimage": "ایچاْ هیچ بٱلگاٛیی سی هوم پیاٛڤٱن بیین ڤا اؽ جانؽا نؽ",
+       "nolinkstoimage": "ایچاْ هیچ بٱلگاٛیی سی هوم پیاٛڤٱن بیئن ڤا اؽ جانؽا نؽ",
        "morelinkstoimage": " [[ویجه:چه هوم پیوندی ها ایچه/$1|هوم پیوندیا هنی]]سی ای جانیا نه بونیت.",
        "linkstoimage-redirect": "$1 (ڤاگٱردونی جانؽا) $2",
        "duplicatesoffile": "{{PLURAL:$1|جانیا|جانیایا}} هاری نسقه تکراری ای جانیا {{PLURAL:$1|هئ|هئن}} ([[Special:FileDuplicateSearch/$2|دونسمنیا هنی]]):",
        "speciallogtitlelabel": "هاستنی(داسون یا نوم کاریاری سی کاریار):",
        "log": "پهرستنومٱیا",
        "all-logs-page": "همٱ پهرستنومٱیا عومۊمی",
-       "alllogstext": "نمایش یٱ جا همٱ پهرستنومٱیا کاْ هان د{{SITENAME}}.\nمؽ تونؽت ڤا اْنتخاو نۉع پهرستنومٱ، نوم کاریاری(هٱساس ڤ کوچکی ۉ گٱپی هرفؽا) ۉ بٱلگٱیا آلشت کردٱ(هٱساس ۉ گٱپی ۉ کوچکی هرنیا) نمایش ناْ دیر د ڤیرتر بٱکؽت.\n\n{{SITENAME}}.",
+       "alllogstext": "نمایش یاٛ جا همٱ پهرستنومٱیا کاْ هان د{{SITENAME}}.\nمؽ تونؽت ڤا اْنتخاو نۉع پهرستنومٱ، نوم کاریاری(هٱساس ڤ کوچکی ۉ گٱپی هرفؽا) ۉ بٱلگٱیا آلشت کردٱ(هٱساس ۉ گٱپی ۉ کوچکی هٱرفؽا) نمایش ناْ دیر د ڤیرتر بٱکؽت.\n\n{{SITENAME}}.",
        "logempty": "او چی کاْ شما مؽهایت د پهرستنومٱ نؽسش.",
        "log-title-wildcard": "بلگه یایی نه پی جوری کو که وا ای سرون شرو موئن",
        "showhideselectedlogentries": "آلشت دئن ورتیه گر پهرستنومه یا انتخاو بیه",
        "notvisiblerev": "آخری وانئری که د دس یه کاریار هنی انجوم بیه پاکسا بیه.",
        "watchlist-details": "{{PLURAL:$1|$1 بلگٱ|$1 بلگٱیا}} د ساٛلٛ بٱرگتو هیچ بٱلگٱ قسٱ کردنی نؽ.",
        "wlheader-enotif": "ڤارئسیاری أنجومانامە کونئشتکار بییە.",
-       "wlheader-showupdated": "بٱلگٱیایی کاٛ د آخری گلٛؽ کاْ کاْ شما ساٛیلٛشو کردؽتٱ د <strong>تۊپور</strong>نشوݩ داٛئٱ بۊئٱن",
+       "wlheader-showupdated": "بٱلگٱیایی کاٛ د آخری گلٛؽ کاْ شما ساٛیلٛشو کردؽتٱ د <strong>تۊپور</strong>نشوݩ داٛئٱ بۊئٱن",
        "wlnote": "د هار {{PLURAL:$1|آلشت|<strong>$1</strong> آلشتؽ}} کاْ د {{PLURAL:$2|ساعت|<strong>$2</strong> ساعٱت}} دماتر ٱنجوم بیٱ هؽسش، ڤیرگار آخری ڤاجۊری ٱنجوم بیٱ هؽسش، ڤیرگار آخری ڤاجۊری: $3، $4",
        "wlshowlast": "آخری$1 ساعٱتؽا $2ۉ رۊزؽا نشوݩ باٛیٱ",
        "wlshowtime": "نئشوٙ دأئن د آخأر",
        "changecontentmodel-success-title": "حال و بال مینوٙنە آلئشتکاری بی",
        "logentry-contentmodel-change-revertlink": "لئرنیئن",
        "logentry-contentmodel-change-revert": "لئرنیئن",
-       "protectlogpage": "پٱر ۉ پیم کاری پهرستنومٱ",
+       "protectlogpage": "پر ۉ پیم کاری پهرستنومٱ",
        "protectlogtext": "د ھار یئ گئل نومگە د آلئشتیا ریتئراز پأر و پیم کاری بألگە یا ئوٙماە.\n[[Special:ProtectedPages|نومگە بألگە یا پأر و پیم کاری بییە]] نە سی دیئن نومگە پأر و پیم کاری کارگئرا بألگە یا نە سئیل بأکیت.",
-       "protectedarticle": "پأر Ù\88 Ù¾Û\8cÙ\85 Ú©Ø§Ø±Û\8c Ø¨Û\8cÛ\8cÛ\95 [[$1]]",
+       "protectedarticle": "پر Û\89 Ù¾Û\8cÙ\85 Ú©Ø§Ø±Û\8c Ø¨Û\8cÙ± [[$1]]",
        "modifiedarticleprotection": "ریتراز هفازٱت د \"[[$1]]\" آلشت بیٱ",
        "unprotectedarticle": "بلگه«[[$1]]» نه د پر و پیم دراورد",
        "movedarticleprotection": "میزونکاری پر و پیم بیین د «[[$2]]» وه «[[$1]]» جا وه جا بیه",
        "undelete-show-file-confirm": "آیا یه دل بئیته که میهایت یه گل نسقه پاکسا بیه د جانیا \"<nowiki>$1</nowiki>\" که ها د ویرگار $2 ساعت $3 نه سیل بکیت؟",
        "undelete-show-file-submit": "هأری",
        "namespace": "نوم جا",
-       "invert": "Ú¯Ù\84Ù\9bٱڤرÚ\86Û\8c Ø¨Û\8cئÙ\86 Ø¨Ù±Ø±Ø¹Ù±Ø³Ú© بۊئٱ",
+       "invert": "Ú¯Ù\84Ù\9bٱڤرÚ\86Û\8c Ø¨Û\8cئÙ\86 Ø¨Ù±Ø±Ø¹Ù±Ø³Ú¯ بۊئٱ",
        "tooltip-invert": "د ری اؽ جٱڤٱ بٱپۊرنؽت ۉ آلشتؽایؽ ناْ کاْ د مؽنجا نوم ڤرگٱ اْنتخاو بیٱ ٱنجوم بینٱ قایم بٱکؽت(ۉ ٱر نوم ڤرگٱ شریکی ڤارسی بیٱ)",
        "tooltip-whatlinkshere-invert": "ای جعون نه سی نهو کردن هوم پیوند بلگه یایی که نوم جاشو انتخاو بیه، انتخاو بکیت.",
        "namespace_association": "نوم جایا یٱکاگرتٱ",
        "sp-contributions-blocked-notice-anon": "ای آی پی ایسنی دسرسی ناره.\nآخری برشت د پهرستنومه ها د سرچشمه هاری:",
        "sp-contributions-search": "سی هومیارؽا پاٛ جۊر با",
        "sp-contributions-username": "نوم نشوݩ آی پی يا نوم كارڤٱری:",
-       "sp-contributions-toponly": "فقٱت ڤیرایشؽایی کاْ جۏز آخری دۉرٱن نشو باٛیٱ",
+       "sp-contributions-toponly": "فقٱت ڤیرایشؽایؽ کاْ جۏز آخری دۉرٱن نشو باٛیٱ",
        "sp-contributions-newonly": "فقٱت ڤیرایشؽایؽ کاْ هؽن دۏرس کردن بٱلگان نشوݩ باٛیٱ.",
        "sp-contributions-submit": "پاٛ جۊری",
        "whatlinkshere": "کوم هوم پاٛڤٱنؽا هان ایچاْ",
        "whatlinkshere-prev": "{{PLURAL:$1|نوئایی|نوئایی $1}}",
        "whatlinkshere-next": "{{PLURAL:$1|دمایی|دمایی $1}}",
        "whatlinkshere-links": "هوم پاٛڤٱنؽا",
-       "whatlinkshere-hideredirs": "$1 ڤرگٱردونیا",
-       "whatlinkshere-hidetrans": "$1 چٱن نتیجاٛیی",
+       "whatlinkshere-hideredirs": "$1 ڤرگٱردونؽا",
+       "whatlinkshere-hidetrans": "$1 چٱن نٱتیجاٛیی",
        "whatlinkshere-hidelinks": "هوم پاٛڤٱنؽا $1",
        "whatlinkshere-hideimages": "جانؽا هوم پاٛڤٱنؽا $1",
        "whatlinkshere-filters": "فيلٛترؽا",
        "blocklist-nousertalk": "نبوئه بلگه چک چنه خوتونه ویرایشت بکید",
        "ipblocklist-empty": "جاگه نوم گه حالیه",
        "ipblocklist-no-results": "دسرسی نوم کاریاری یا تیرنشون آی پی حاسته بیه نهاگری نبیه.",
-       "blocklink": "نوئاگری بۊئٱ",
+       "blocklink": "نوئاگیری بۊئٱ",
        "unblocklink": "بی قطی",
        "change-blocklink": "اجازه نديئن سی  آلشت",
        "contribslink": "هومیاریٛا",
        "blocklog-showlog": "تیرنشون ای آی پی دماتر نهاگیری بیه.\nنهاگری ای پهرستنومه وا سرچشمه هاری دروس بیه:",
        "blocklog-showsuppresslog": "تیرنشون ای آی پی دماتر نهاگیری بیه.\nنهاگری ای پهرستنومه وا سرچشمه هاری دروس بیه:",
        "blocklogentry": " [[$1]] ڤا یاٛ ڤٱخت تموم بیئن $2 ۉ $3  قلف بییٱ",
-       "reblock-logentry": "میزوکاری سی نهاگری[[$1]] آلشت بیه سی آخر نهاگری د $2 $3",
+       "reblock-logentry": "میزوکاری سی نهاگیری[[$1]] آلشت بیٱ سی آخر نهاگیری د $2 $3",
        "blocklogtext": "ای پهرستنومه سی نهاگری یا واز کردن دسرسی کاریاریائه.\nتیرنشونیا آی پی که خود انجومن نهاگری بینه د ایسنی نومگه کاری نبینه.\nسی نومگه نهاگریا و بسه بینیا د ایسنی روئیت د [[Special:BlockList|نومگه نهاگری بیه یا]].",
        "unblocklogentry": "وا کردن قلف $1",
        "block-log-flags-anononly": "فقط کاریاریایی که نادیارن",
        "allmessagesdefault": "سفارشت متنی پيش فرض",
        "allmessagescurrent": "نیسسه ایسنی پیغوم",
        "allmessagestext": "یه یه گل نومگه د پیغومیا سامونه یی یه که هان د نوم ورگه ویکی وارسگر.\nاری میهایت د ویکی وارسگر نه ولاتمن بکیت لطف بکیت [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation ولاتمن کردن ویکی وارسگر] و [https://translatewiki.net translatewiki.net] نه سیل بکیت.",
-       "allmessagesnotsupportedDB": "ای بلگه وه کار گرتنی نئ سی یه که <bdi>'''$wgUseDatabaseMessages'''</bdi> ناکنشتگر بیه.",
+       "allmessages-not-supported-database": "ای بلگه وه کار گرتنی نئ سی یه که <bdi>'''$wgUseDatabaseMessages'''</bdi> ناکنشتگر بیه.",
        "allmessages-filter-legend": "فیلتر",
        "allmessages-filter": "فیلتر کردن د اساس شخصی کردن:",
        "allmessages-filter-unmodified": "آلشت نبیه",
        "tooltip-ca-history": "دوئرٱ دیئن اؽ بٱلگٱ",
        "tooltip-ca-protect": "اؽ بٱلگٱ ناْ ڤیردار بٱکؽت",
        "tooltip-ca-unprotect": "پر و پیم گیری د ای بلگه نه آلشت بکیت",
-       "tooltip-ca-delete": "ای بلگه نه پاکسا کو",
+       "tooltip-ca-delete": "اؽ بٱلگٱ ناْ پاکسا کو",
        "tooltip-ca-undelete": "د نو زنه کردن ویرایشتیا ری ای بلگه دما یه که پاکساگری بان",
        "tooltip-ca-move": "اؽ بٱلگٱ ناْ جا ڤ جا كو",
        "tooltip-ca-watch": "اْزاف کردن اؽ بٱلگٱ ڤ نوم نڤشت پاٛگیریاتو",
        "tooltip-ca-unwatch": "ڤرداشتن اؽ بٱلگٱ ڤ نوم نڤشت پاٛگیریاتو",
        "tooltip-search": "پاٛ جۊری {{SITENAME}}",
-       "tooltip-search-go": "رۉ د بٱلگاٛیؽ کاْ یٱ نوم روسی ها مؽنش ٱلڤٱت ٱر دش بۊئٱ",
+       "tooltip-search-go": "رۉ د بٱلگاٛیؽ کاْ یٱ نوم راسی ها مؽنش ٱلڤٱت ٱر دش بۊئٱ",
        "tooltip-search-fulltext": "بٱلگٱیاناْ سی چنی نیسساٛیؽ پاٛ جۊری بٱکو.",
        "tooltip-p-logo": "ساٛلٛ سرآسونٱ بٱکؽت",
        "tooltip-n-mainpage": "سرآسونٱ ناْ ساٛلٛ بٱکؽت",
        "tooltip-n-mainpage-description": "سرآسونٱ ناْ ساٛلٛ بٱکؽت",
        "tooltip-n-portal": "دبارٱ پرۉژٱ؛ شما مؽ تونؽت چؽ بٱکؽت؛ د کوجا اؽ چیاناْ بٱجۊرؽت.",
-       "tooltip-n-currentevents": "ساڤÙ\86د Ø¯Ù\88Ù\86سÙ\85Ù\86Û\8cاÛ\8cؽ Ú©Ø§ Ù\87اÙ\86 Ø¯ Ø±Ù\88Ø® Ú¤Ù\86ؽا ØªØ§Ø²Ù± Ø¨Ø§Ú¤ دؽاری بٱک",
+       "tooltip-n-currentevents": "ساڤٱÙ\86 Ø¯Ù\88Ù\86سÙ\85Ù\86Û\8cاÛ\8cؽ Ú©Ø§ Ù\87اÙ\86 Ø¯ Ø±Ù\88Ø® Ú¤Ù±Ù\86ؽا ØªØ§Ø²Ù± Ø¨Û\8a دؽاری بٱک",
        "tooltip-n-recentchanges": "یاٛ نومگٱ سی آلشتکاریا د ڤیکی",
        "tooltip-n-randompage": "سڤار کرد بٱلگٱ بٱختٱکی",
        "tooltip-n-help": "یاٛ جاگٱ سی فٱمسن",
        "tooltip-ca-nstab-project": "ديئن بٱلگٱ پرۉژٱ",
        "tooltip-ca-nstab-image": "دیئن بٱلگٱ جانؽا",
        "tooltip-ca-nstab-mediawiki": "دیئن پاٛغوم سامونٱ",
-       "tooltip-ca-nstab-template": "ديئن چۊٱ",
+       "tooltip-ca-nstab-template": "ديئن چۊئٱ",
        "tooltip-ca-nstab-help": "ديئن بلگه هومیاری",
        "tooltip-ca-nstab-category": "دیئن بٱلگٱ دٱسٱ بٱنی",
        "tooltip-minoredit": "یٱ ناْ ڤ عونڤان هیردٱ ڤیرایش سٱبت کو",
        "tooltip-watchlistedit-raw-submit": "وه هنگوم سازی سیل برگ",
        "tooltip-recreate": "د نو راس کردن بلگه بی یه که و پاکساگری دماتر وه سیل بکیم",
        "tooltip-upload": "شرو د سوار کرد",
-       "tooltip-rollback": "\"ڤرگٱشتن\" لٛرسن د هال و بال ٱڤٱل سی اؽ بٱلگٱ سی یٱ کاْ هومیاری نؽایی بؽتر کاری بیٱ ڤا یاٛ پۊرنین.",
-       "tooltip-undo": "Ù±Ù\86جÙ\88Ù\85 Ù\86ٱگرتÙ\86 Ø§Ø½ Ú¤Û\8cراÛ\8cØ´. Ú¤Ø±Ú¯Ù±Ø±Ø¯ Û\89 Ù\87Ù±Ù\85Ù± Ù\81Ù\88رÙ\85ؽا Ú¤Û\8cراÛ\8cشؽاÙ\86اÙ\92 Ø¯ Ù\87اÙ\84ٱت Ù¾Û\8cØ´ Ø³Ø§Ù\9bÙ\84Ù\9b Ú¤Ø§Ú©Ù\88\8cÙ± Ø§Ù\92جازٱ Ù\85اÙ\9bئٱ Ø³Û\8c Ø§Ù\92زاÙ\81 Ú©Ø±Ø¯Ù\86 Û\8cاÙ\9b Ø¯Ù±Ù\84Ù\9bÛ\8cÙ\84Ù\9b Ø¯ Ú\86کسٱ.",
+       "tooltip-rollback": "\"ڤرگٱشتن\" لٛرسن د هال و بار ٱڤٱل سی اؽ بٱلگٱ سی یٱ کاْ هومیاری نؽایی بؽتر کاری بیٱ ڤا یاٛ پۊرنیئن.",
+       "tooltip-undo": "ٱنجوم نٱگرتن اؽ ڤیرایش. ڤرگٱرد ۉ همٱ فورمؽا ڤیرایشؽاناْ د هالٱت پیش ساٛلٛ ڤاکو.یٱ اْجازٱ ماٛئٱ سی اْزاف کردن یاٛ دٱلٛیلٛ د چکسٱ.",
        "tooltip-preferences-save": "اولويتيا نه ذخيره بكيد",
        "tooltip-summary": "ياٛ چكسٱ کوچک ڤارد بٱکؽت",
        "interlanguage-link-title": "$1-$2",
        "pageinfo-redirects-name": "شمارٱ ڤاگٱردونیا اؽ بٱلگٱ",
        "pageinfo-redirects-value": "$1",
        "pageinfo-subpages-name": "ٱندازٱ زؽر بٱلگٱیا اؽ بٱلگٱ",
-       "pageinfo-subpages-value": "$1 ($2 {{PLURAL:$2|ڤاگٱردونی|ڤاگٱردونیا}}; $3 {{PLURAL:$3|بؽ ڤاگٱردونی|بؽ ڤاگٱردونیا}})",
+       "pageinfo-subpages-value": "$1 ($2 {{PLURAL:$2|ڤاگٱردونی|ڤاگٱردونؽا}}; $3 {{PLURAL:$3|بؽ ڤاگٱردونی|بؽ ڤاگٱردونؽا}})",
        "pageinfo-firstuser": "بٱلگٱ دۏرس کن",
        "pageinfo-firsttime": "گات دۏرس بیئن بٱلگٱ",
        "pageinfo-lastuser": "آخری ڤیرایشکار",
        "pageinfo-recent-authors": "شمارٱ کولٛی نڤیسٱیا یٱکونٱ",
        "pageinfo-magic-words": "جادۊیی{{PLURAL:$1|کلٱمٱ|کلٱمٱیا}} ($1)",
        "pageinfo-hidden-categories": "$1{{PLURAL:$1|دٱسٱ|دٱسٱيا}} قایم بیٱ",
-       "pageinfo-templates": "{{PLURAL:$1|چۊٱ|چۊٱ یا}} ڤ کار گرتٱ بیٱ ($1)",
+       "pageinfo-templates": "{{PLURAL:$1|چۊئٱ|چۊئٱ یا}} ڤ کار گرتٱ بیٱ ($1)",
        "pageinfo-transclusions": "{{PLURAL:$1|بلگه|بلگه یا}} وه کار گرته بیه د ($1)",
        "pageinfo-toolboxlink": "دونسمٱنیٛا بٱلگٱ",
        "pageinfo-redirectsto": "واگردونی سی",
        "widthheight": "$1 × $2",
        "widthheightpage": "$1 × $2, $3 {{PLURAL:$3|بٱلگٱ|بٱلگٱیا}}",
        "file-info": "انازه جانیا: $1, MIME type: $2",
-       "file-info-size": "$1 × $2 پیکسل, ٱندازٱ فایل: $3, MIME نوع: $4",
+       "file-info-size": "$1 × $2 پیکسل, ٱندازٱ فایلٛ: $3, MIME نوع: $4",
        "file-info-size-pages": "$1 × $2 pixels, ٱندازٱ جانؽا: $3, MIME type: $4, $5 {{PLURAL:$5|بٱلگٱ|بٱلگٱیا}}",
-       "file-nohires": "عٱسک ڤٱن بالاترؽ دش نؽ",
+       "file-nohires": "عٱسگ ڤٱن بالاترؽ دش نؽ",
        "svg-long-desc": "جانؽا اْس ڤی جی, نومی $1 × $2 پیکسل, ٱندازٱ جانؽا: $3",
        "svg-long-desc-animated": "جانیا جمشدار اس وی جی .نومنا $1 × $2 پيكسل،انازه جانیا:$3",
        "svg-long-error": "جانیا اس وی جی نامعتور:$1",
        "yesterday-at": "دیرو د $1",
        "bad_image_list": "دونسمنديانه وه ای شلگ وارد بكيت:\n\nفقط سرخط يایی که وا * شرو بوئن د وير گرته بوئن. اولی چسب ون مئن هر سرخط، باید چسب ونی وه یک عسگ گن با.\nچسب ونيا نيایی د همو سرخط، وه عنوان چيا استثنادار د وير گرته بوئن",
        "metadata": "رسینٱیا فرٱ گٱپ",
-       "metadata-help": "اؽ فایلٛ شامل دونسمنیا هنی یٱ.شایت د دیر بیین رقٱم ڤٱن یا اسکنری کاْ سی راس کردنشو اْستفادٱ بیٱ، ڤ ایچاْ اْزاف بیٱ",
+       "metadata-help": "اؽ فایلٛ شامل دونسمنیا هنی یٱ.شایٱت د دیر بیئن رقٱم ڤٱن یا اْسکٱنرؽ کاْ سی دۏرس کردنشو اْستفادٱ بیٱ، ڤ ایچاْ اْزاف بیٱ",
        "metadata-expand": "نشو دئن جزییات دمادیسگری",
        "metadata-collapse": "قام کردن جزییات دمادیسگری",
        "metadata-fields": "رشتٱیا یا گٱپ دونسمنیا کاْ د اؽ پاٛغوم نومگٱ کاری بینٱ د ڤٱر گرتٱ بٱلگٱ عٱسک کاْ ڤٱختؽ جٱدڤٱل گٱپ دونسمنیا ڤاز مۊئٱ نشوݩ داٛیٱ بۊئٱن.\nچی یا هنی سی یٱ کا پیش فٱرزٱن قایم مۊئٱن.\n*راس کو\n*مودل\n*دم ڤٱخت ٱسل\n*ڤٱخت آشگار\n*اْف اْن شمارٱ\n*ایزو نرخ من سرعت\n*فوکالنس\n*هونٱرمٱن\n*کوپی رایت\n*هالٱت جی پی اْس \n*جی پی اْس گٱپ هالٱت\n*جی پی اْس هٱمٱ هالٱت",
        "metadata-langitem": "<strong>$2:</strong> $1",
        "metadata-langitem-default": "$1",
        "namespacesall": "همٱشو",
-       "monthsall": "Ù\87Ù±Ù\85Ù±",
+       "monthsall": "همٱ",
        "confirmemail": "پشت راس کردن تیرنشون انجومانامه",
        "confirmemail_noemail": "شما د بلگه [[Special:Preferences|ترجیحات کاریاری]] خوتو یه گل تیرنشون انجومانامه نامعتور نه دئیته.",
        "confirmemail_text": "ای ویکی، شما نه مژبور می که وه پشت راسکاری تیرنشون انجومانامه خوتو، دما د یه که خدمات انجومانامه نه وه کار د ایچه وه کار بئیریت می که.دگمه هاری نه کنشتیار بکیت تا یه گل انجومانامه پشت راسکاری سی تیرنشون انجومانامه شما کل بوئه. ای انجومانامه د ور گرته یه گل رازینه ئه. هوم پیوند نه د دوارته نیئر خوتو واز بکیت تا تیرنشون انجومانامه تو پشت راسکاری با.",
        "watchlistedit-too-many": "ایچه بلگه یا فره ای سی نشو دئن هئ.",
        "watchlisttools-clear": "پاک کردن ساٛلٛ بٱرگ",
        "watchlisttools-view": "آلشتؽا مٱربوت ناْ بونؽت",
-       "watchlisttools-edit": "ساٛلٛ بٱرگ بوینؽتو ۉ ڤیرایش بٱکؽت",
+       "watchlisttools-edit": "ساٛلٛ بٱرگ ناْ باٛینؽتو ۉ ڤیرایش بٱکؽت",
        "watchlisttools-raw": "ساٛلٛ بٱرگ ناْ ردیفی ڤیرایش کو",
        "iranian-calendar-m1": "فروردین",
        "iranian-calendar-m2": "اردیبهشت",
index dac0bcc..7d8daae 100644 (file)
@@ -40,7 +40,8 @@
                        "Manvydasz",
                        "Fitoschido",
                        "Matěj Suchánek",
-                       "Vlad5250"
+                       "Vlad5250",
+                       "Naktis"
                ]
        },
        "tog-underline": "Nuorodos pabraukimas:",
        "accmailtext": "Atsitiktinai sukurtas naudotojo [[User talk:$1|$1]] slaptažodis nusiųstas į $2.\n\nŠios naujos paskyros slaptažodis gali būti pakeistas <em>[[Special:ChangePassword|keisti slaptažodį]]</em> puslapyje beprisijungiant.",
        "newarticle": "(Naujas)",
        "newarticletext": "Jūs patekote į dar neegzistuojantį puslapį.\nNorėdami sukurti puslapį, pradėkite rašyti žemiau esančiame įvedimo lauke\n(plačiau [$1 pagalbos puslapyje]).\nJei patekote čia per klaidą, paprasčiausiai spustelkite  naršyklės mygtuką '''atgal'''.",
-       "anontalkpagetext": "----\n<em>Tai yra anoniminio naudotojo, nesusikūrusio arba nenaudojančio paskyros, aptarimų puslapis.</em>\nDėl to naudojamas IP adresas jo identifikavimui.\nŠis IP adresas gali priklausyti keliems naudotojams.\nJeigu Jūs esate anoniminis naudotojas ir atrodo, kad komentarai nėra skirti Jums, [[Special:CreateAccount|sukurkite paskyrą]] arba [[Special:UserLogin|prisijunkite]], ir nebūsite tapatinamas su kitais anoniminiais naudotojais.",
+       "anontalkpagetext": "----\n<em>Tai yra anoniminio naudotojo, nesusikūrusio arba nenaudojančio paskyros, aptarimų puslapis.</em>\nTodėl, norėdami juos identifikuoti, turime naudoti skaitinį IP adresą.\nŠis IP adresas gali priklausyti keliems naudotojams.\nJei esate anoniminis vartotojas ir manote, kad jums buvo nukreipti nesusiję komentarai, prašome [[Special:CreateAccount|sukurkite paskyrą]] arba [[Special:UserLogin|prisijunkite]], išvengti ateities painiavos su kitais anoniminiais naudotojais.",
        "noarticletext": "Šiuo metu šiame puslapyje nėra jokio teksto.\nJūs galite [[Special:Search/{{PAGENAME}}|ieškoti šio puslapio pavadinimo]] kituose puslapiuose,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ieškoti susijusių įrašų] arba [{{fullurl:{{FULLPAGENAME}}|action=edit}} sukurti šį puslapį]</span>.",
        "noarticletext-nopermission": "Šiuo metu šiame puslapyje nėra jokio teksto.\nJūs galite [[Special:Search/{{PAGENAME}}|ieškoti šio puslapio pavadinimo]] kituose puslapiuose,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ieškoti susijusių įrašų]</span>, tačiau jūs neturite teisės sukurti šio puslapio.",
        "missing-revision": "Puslapio peržiūra #$1 pavadinto „{{FULLPAGENAME}}“ neegzistuoja.\n\nTai paprastai atsitinka kai pasenusi nuoroda veda į puslapį, kuris buvo ištrintas.\nInformaciją galima rasti [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} deletion log].",
        "rcfilters-filter-editsbyself-description": "Jūsų keitimai.",
        "rcfilters-filter-editsbyother-label": "Kitų keitimai",
        "rcfilters-filter-editsbyother-description": "Visi keitimai, išskyrus jūsų.",
-       "rcfilters-filtergroup-userExpLevel": "Vartotojo registracija ir patirtis",
+       "rcfilters-filtergroup-user-experience-level": "Vartotojo registracija ir patirtis",
        "rcfilters-filter-user-experience-level-registered-label": "Registruoti",
        "rcfilters-filter-user-experience-level-registered-description": "Prisijungę naudotojai.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Neregistruoti",
        "rcfilters-filter-categorization-description": "Keitimai, kuriais puslapiai yra pridedami ar pašalinami iš kategorijų.",
        "rcfilters-filter-logactions-label": "Įrašyti į sąrašą veiksmai",
        "rcfilters-filter-logactions-description": "Administravimo veiksmai, paskyrų sukūrimai, puslapių trynimai, įkėlimai…",
-       "rcfilters-filtergroup-lastRevision": "Naujausios versijos",
+       "rcfilters-filtergroup-lastrevision": "Naujausios versijos",
        "rcfilters-filter-lastrevision-label": "Naujausia versija",
        "rcfilters-filter-lastrevision-description": "Tik naujausias puslapio keitimas.",
        "rcfilters-filter-previousrevision-label": "Ne naujausia versija",
        "minoreditletter": "S",
        "newpageletter": "N",
        "boteditletter": "a",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|stebintis naudotojas|stebintys naudotojai|stebinčių naudotojų}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|baitas|baitai|baitų}} po pakeitimo",
        "newsectionsummary": "/* $1 */ naujas skyrius",
        "rc-enhanced-expand": "Rodyti detales",
        "img-auth-nopathinfo": "Trūksta PATH_INFO.\nJūsų serveris nenustatytas perduoti šią informaciją.\nTai gali būti CGI paremta ir negali palaikyti img_auth.\nDaugiau informacijos https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization. žr.",
        "img-auth-notindir": "Užklaustas kelias nėra sukonfigūruotame įkėlimo kataloge.",
        "img-auth-badtitle": "Nepavyksta padaryti leistino pavadinimo iš „$1“.",
-       "img-auth-nologinnWL": "Jūs nesate prisijungęs ir „$1“ nėra baltajame sąraše.",
        "img-auth-nofile": "Failas „$1“ neegzistuoja.",
        "img-auth-isdir": "Jūs bandote pasiekti katalogą „$1“.\nLeidžiama prieiga tik prie failų.",
        "img-auth-streaming": "Siunčiamas „$1“.",
        "revertpage": "Atmestas [[Special:Contributions/$2|$2]] ([[User talk:$2|Aptarimas]]) pakeitimas; sugrąžinta [[User:$1|$1]] versija",
        "revertpage-nouser": "Atversti pakeitimai paslėpto vartotojo, grąžino prieš tai buvusią versiją {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Atmesti {{GENDER:$3|$1}} pakeitimai;\ngrąžinta prieš tai buvusi {{GENDER:$4|$2}} versija.",
-       "rollback-success-notify": "Atmesti $1 pakeitimai;\ngrąžinta prieš tai buvusi $2 versija. [$3 Rodyti skirtumus]",
        "sessionfailure-title": "Sesijos klaida",
        "sessionfailure": "Atrodo yra problemų su jūsų prisijungimo sesija; šis veiksmas buvo atšauktas kaip atsargumo priemonė prieš sesijos vogimą.\nPrašome iš naujo pateikti formą.",
        "changecontentmodel": "Keisti puslapio turinio modelį",
        "namespace_association": "Susijusi vardų sritis",
        "tooltip-namespace_association": "Įjunkite šią parinktį, kad taip pat įtrauktumėte aptarimų arba temos sritį, susijusią su pasirinkta sritimi",
        "blanknamespace": "(Pagrindinis)",
-       "contributions": "{{GENDER:$1|Naudotojo}} indėlis",
+       "contributions": "{{GENDER:$1|Naudotojo|Naudotojos}} indėlis",
        "contributions-title": "{{GENDER:$1|Naudotojo|Naudotojos}} $1 indėlis",
        "mycontris": "Indėlis",
        "anoncontribs": "Indėlis",
        "contribsub2": "Naudotojas: {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "{{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "Naudotojo paskyra „$1“ neužregistruota.",
        "nocontribs": "Jokie keitimai neatitiko šių kriterijų.",
        "uctop": "dabartinis",
        "allmessagesdefault": "Pradinis tekstas",
        "allmessagescurrent": "Dabartinis tekstas",
        "allmessagestext": "Čia pateikiamas sisteminių pranešimų sąrašas, esančių MediaWiki vardų srityje.\nAplankykite [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation „MediaWiki“ lokaliziciją] ir [https://translatewiki.net „translatewiki.net“], jei norite prisidėti prie bendrojo „MediaWiki“ lokalizavimo.",
-       "allmessagesnotsupportedDB": "Šis puslapis nepalaikomas, nes nuostata '''$wgUseDatabaseMessages''' yra išjungtas.",
+       "allmessages-not-supported-database": "Šis puslapis nepalaikomas, nes nuostata '''$wgUseDatabaseMessages''' yra išjungtas.",
        "allmessages-filter-legend": "Filtras",
        "allmessages-filter": "Perkošti pagal būseną:",
        "allmessages-filter-unmodified": "Nepakeisti",
        "tooltip-t-recentchangeslinked": "Paskutiniai keitimai puslapiuose, pasiekiamuose iš šio puslapio",
        "tooltip-feed-rss": "Šio puslapio RSS šaltinis",
        "tooltip-feed-atom": "Šio puslapio Atom šaltinis",
-       "tooltip-t-contributions": "Rodyti {{GENDER:$1|šio naudotojo}} keitimų sąrašą",
+       "tooltip-t-contributions": "Rodyti {{GENDER:$1|šio naudotojo|šios naudotojos}} keitimų sąrašą",
        "tooltip-t-emailuser": "Siųsti laišką {{GENDER:$1|šiam naudotojui}}",
        "tooltip-t-info": "Daugiau žinių apie šį puslapį",
        "tooltip-t-upload": "Įkelti rinkmenas",
index 1fc4446..47f22ba 100644 (file)
        "minoreditletter": "t",
        "newpageletter": "T",
        "boteditletter": "k",
-       "number_of_watching_users_pageview": "[$1 hmangtu {{PLURAL:$1||te}} vil mék]",
        "rc-change-size-new": "Tihdanglam hnuah {{PLURAL:$1|bait|bait}} $1",
        "newsectionsummary": "/* $1 */ hläwm thar",
        "rc-enhanced-expand": "Tilang kim rawh (JavaScript a ngai)",
index c3adb57..63b0040 100644 (file)
        "category-subcat-count-limited": "Šai kategorijai ir {{PLURAL:$1|$1 apakškategorijas|$1 apakškategorija|$1 apakškategorijas}}.",
        "category-article-count": "{{PLURAL:$2|Šajā kategorijā kopā ir $2 lapu, šobrīd ir {{PLURAL:$1|redzamas $1 no tām|redzama $1 no tām|redzamas $1 no tām}}.|Šī kategorija satur $2 lapu.|Šajā kategorijā kopā ir $2 lapas, šobrīd ir {{PLURAL:$1|redzamas $1 no tām|redzama $1 no tām|redzamas $1 no tām}}.}}",
        "category-article-count-limited": "Šajā kategorijā ir {{PLURAL:$1|šīs $1 lapas|šī $1 lapa|šīs $1 lapas}}.",
-       "category-file-count": "{{PLURAL:$2|Šajā kategorijā ir $2 failu, no kuriem {{PLURAL:$1|ir redzami $1|redzams ir $1|ir redzami $1}}.|Šī kategorija satur tikai $2 failu.|Šajā kategorijā ir $2 faili, no kuriem {{PLURAL:$1|ir redzami $1|redzams ir $1|ir redzami $1}}.}}",
+       "category-file-count": "{{PLURAL:$2|Šajā kategorijā ir $2 failu, no kuriem {{PLURAL:$1|ir redzami $1|redzams ir $1|ir redzami $1}}.|Šajā kategorijā ir $2 fails, no kura {{PLURAL:$1|ir redzami $1|redzams ir $1|ir redzami $1}}.|Šajā kategorijā ir $2 faili, no kuriem {{PLURAL:$1|ir redzami $1|redzams ir $1|ir redzami $1}}.}}",
        "category-file-count-limited": "Šajā kategorijā atrodas {{PLURAL:$1|šie $1 faili|tikai šis fails|šie $1 faili}}.",
        "listingcontinuesabbrev": " (turpinājums)",
        "index-category": "Indeksētās lapas",
        "page_first": "pirmā",
        "page_last": "pēdējā",
        "histlegend": "Atšķirību izvēle: atzīmē vajadzīgo versiju apaļās pogas un spied \"Salīdzināt izvēlētās versijas\".<br />\nApzīmējumi:\n\"ar pašreizējo\" = salīdzināt ar pašreizējo versiju,\n\"ar iepriekšējo\" = salīdzināt ar iepriekšējo versiju,\nm = maznozīmīgs labojums.",
-       "history-fieldset-title": "Versiju meklēšana",
+       "history-fieldset-title": "Filtrēt versijas",
        "history-show-deleted": "Tikai dzēstie labojumi",
        "histfirst": "Senākās",
        "histlast": "Jaunākās",
        "historysize": "({{PLURAL:$1|$1 baiti|1 baits|$1 baiti}})",
-       "historyempty": "(tukša)",
+       "historyempty": "tukša",
        "history-feed-title": "Versiju hronoloģija",
        "history-feed-description": "Šīs wiki lapas versiju hronoloģija",
        "history-feed-item-nocomment": "$1 : $2",
        "rcfilters-savedqueries-already-saved": "Šie filtri jau ir saglabāti. Izmaini savus iestatījumus, lai izveidotu jaunu saglabāto filtru.",
        "rcfilters-restore-default-filters": "Atjaunot noklusētos filtrus",
        "rcfilters-clear-all-filters": "Noņemt visus filtrus",
-       "rcfilters-show-new-changes": "Skatīt jaunās izmaiņas",
+       "rcfilters-show-new-changes": "Skatīt jaunās izmaiņas kopš $1",
        "rcfilters-search-placeholder": "Filtrēt pēdējās izmaiņas (pārlūko vai sāc rakstīt)",
        "rcfilters-invalid-filter": "Nederīgs filtrs",
        "rcfilters-empty-filter": "Nav aktīvu filtru. Tiek rādītas visas izmaiņas.",
        "rcfilters-filter-editsbyself-description": "Tevis veiktie labojumi.",
        "rcfilters-filter-editsbyother-label": "Citu labojumi",
        "rcfilters-filter-editsbyother-description": "Visas izmaiņas bez tavējām.",
-       "rcfilters-filtergroup-userExpLevel": "Dalībnieku reģistrācijas statuss un pieredze",
+       "rcfilters-filtergroup-user-experience-level": "Dalībnieku reģistrācijas statuss un pieredze",
        "rcfilters-filter-user-experience-level-registered-label": "Reģistrēti",
        "rcfilters-filter-user-experience-level-registered-description": "Pieslēgušies redaktori.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Nereģistrēti",
        "rcfilters-filter-categorization-description": "Ieraksti par lapu pievienošanu vai noņemšanu no kategorijām.",
        "rcfilters-filter-logactions-label": "Reģistrētās darbības",
        "rcfilters-filter-logactions-description": "Administratīvās darbības, kontu veidošana, lapu dzēšana, augšupielādes...",
-       "rcfilters-filtergroup-lastRevision": "Pašreizējās versijas",
+       "rcfilters-filtergroup-lastrevision": "Pašreizējās versijas",
        "rcfilters-filter-lastrevision-label": "Pašreizējā versija",
        "rcfilters-filter-lastrevision-description": "Tikai nesenākā lapas izmaiņa.",
        "rcfilters-filter-previousrevision-label": "Ne pēdējā versija",
        "minoreditletter": "m",
        "newpageletter": "J",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[šo lapu uzrauga $1 {{PLURAL:$1|dalībnieki|dalībnieks|dalībnieki}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|baiti|baits|baiti}} pēc izmaiņām",
        "newsectionsummary": "/* $1 */ jauna sadaļa",
        "rc-enhanced-expand": "Skatīt detaļas",
        "uploadstash-zero-length": "Faila garums ir nulle.",
        "img-auth-accessdenied": "Pieeja liegta",
        "img-auth-nopathinfo": "Trūkst PATH_INFO.\nJūsu serveris nav konfigurēts nodot šo informāciju.\nTas var būt bāzēts uz CGI un neatbalstīt img_auth.\nSkatīt https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
-       "img-auth-nologinnWL": "Jūs neesat iegājis un \"$1\" nav baltajā sarakstā.",
        "img-auth-nofile": "Fails \"$1\" nepastāv.",
        "img-auth-isdir": "Jūs mēģinājāt piekļūt direktorijai \"$1\".\nAtļauta ir tikai failu piekļuve.",
        "img-auth-streaming": "Straumē \"$1\".",
        "pageswithprop-submit": "Aiziet",
        "doubleredirects": "Divkāršas pāradresācijas lapas",
        "doubleredirectstext": "Šajā lapā ir uzskaitītas pāradresācijas lapas, kuras pāradresē uz citām pāradresācijas lapām.\nKatrā rindiņā ir saites uz pirmo un otro pāradresācijas lapu, kā arī pirmā rindiņa no otrās pāradresācijas lapas teksta, kas parasti ir faktiskā \"gala\" lapa, uz kuru vajadzētu būt saitei pirmajā lapā.\n<del>Nosvītrotie</del> ieraksti jau ir tikuši salaboti.",
-       "double-redirect-fixed-move": "[[$1]] bija ticis pārvietots, tas tagad ir pāradresācija uz [[$2]]",
+       "double-redirect-fixed-move": "[[$1]] ir ticis pārvietots.\nTas tika automātiski labots un tagad tas pāradresē uz [[$2]].",
        "double-redirect-fixed-maintenance": "Automātiski ar apkopes procesu labota dubultā pāradresācija no [[$1]] uz [[$2]].",
        "double-redirect-fixer": "Pāradresāciju labotājs",
        "brokenredirects": "Kļūdainas pāradresācijas",
        "delete-confirm": "Dzēst \"$1\"",
        "delete-legend": "Dzēšana",
        "historywarning": "'''Brīdinājums:''' Lapai, ko tu gatavojies dzēst, ir vēsture ar aptuveni $1 {{PLURAL:$1|versijām|versiju|versijām}}:",
-       "historyaction-submit": "Rādīt",
+       "historyaction-submit": "Rādīt versijas",
        "confirmdeletetext": "Tu tūlīt no datubāzes dzēsīsi lapu vai attēlu, kā arī to iepriekšējās versijas. Lūdzu, apstiprini, ka tu tiešām to vēlies darīt, ka tu apzinies sekas un ka tu to dari saskaņā ar [[{{MediaWiki:Policy-url}}|vadlīnijām]].",
        "actioncomplete": "Darbība pabeigta",
        "actionfailed": "Darbība neizdevās",
        "delete-toobig": "Šai lapai ir liela izmaiņu hronoloģija, vairāk nekā $1 {{PLURAL:$1|versijas|versija|versijas}}.\nŠādu lapu dzēšana ir atslēgta, lai novērstu nejaušus traucējumus {{grammar:lokatīvs|{{SITENAME}}}}.",
        "deleting-backlinks-warning": "'''Brīdinājums:''' uz lapu, ko grasies izdzēst, ved [[Special:WhatLinksHere/{{FULLPAGENAME}}|saites no citām lapām]].",
        "rollback": "Novērst labojumus",
+       "rollback-confirmation-confirm": "Lūdzu, apstiprini:",
+       "rollback-confirmation-no": "Atcelt",
        "rollbacklink": "novērst",
        "rollbacklinkcount": "atcelt $1 {{PLURAL:$1|labojumus|labojumu|labojumus}}",
        "rollbacklinkcount-morethan": "atcelt vairāk kā $1 {{PLURAL:$1|labojumus|labojumu|labojumus}}",
        "protect-cascadeon": "Šī lapa pašlaik ir aizsargāta, jo tā ir iekļauta {{PLURAL:$1|šajās lapās|šajā lapā|šajās lapās}} (mainot šīs lapas aizsardzības līmeni aizsardzība netiks noņemta):",
        "protect-default": "Atļaut visiem lietotājiem",
        "protect-fallback": "Atļaut tikai lietotājiem ar \"$1\" atļauju",
-       "protect-level-autoconfirmed": "Atļaut tikai pašpārbaudītajiem",
+       "protect-level-autoconfirmed": "Atļaut tikai reģistrētiem dalībniekiem",
        "protect-level-sysop": "Atļaut tikai administratoriem",
        "protect-summary-cascade": "kaskāde",
        "protect-expiring": "līdz $1 (UTC)",
        "blocklist-userblocks": "Paslēpt kontu bloķējumus",
        "blocklist-tempblocks": "Paslēpt pagaidu bloķējumus",
        "blocklist-addressblocks": "Paslēpt vienas IP adreses bloķējumus",
+       "blocklist-type": "Veids:",
+       "blocklist-type-opt-all": "Visi",
+       "blocklist-type-opt-sitewide": "Visā vietnē",
+       "blocklist-type-opt-partial": "Daļēji",
        "blocklist-rangeblocks": "Paslēpt IP adrešu diapazona blokus",
        "blocklist-timestamp": "Laiks",
        "blocklist-target": "Mērķis",
        "createaccountblock": "kontu veidošana atslēgta",
        "emailblock": "e-pasts bloķēts",
        "blocklist-nousertalk": "nevar izmainīt savu diskusiju lapu",
+       "blocklist-editing": "labošana",
+       "blocklist-editing-sitewide": "labošana (visā vietnē)",
        "blocklist-editing-page": "lapas",
        "blocklist-editing-ns": "vārdtelpas",
        "ipblocklist-empty": "Bloķēšanas saraksts ir tukšs.",
        "blocklink": "bloķēt",
        "unblocklink": "atbloķēt",
        "change-blocklink": "izmainīt bloku",
+       "empty-username": "(dalībnieka vārds nav pieejams)",
        "contribslink": "devums",
        "emaillink": "nosūtīt e-pastu",
        "autoblocker": "Tava IP ir nobloķēta automātiski, tāpēc, ka to nesen lietojis \"[[User:$1|$1]]\".\nViņa bloķēšanas iemesls bija: \"$2\"",
        "allmessagesdefault": "Noklusētais ziņojuma teksts",
        "allmessagescurrent": "Pašreizējais teksts",
        "allmessagestext": "Šajā lapā ir visu \"'''MediaWiki:'''\" lapās atrodamo sistēmas paziņojumu uzskaitījums.\nŠos paziņojumus var izmainīt tikai admini. Izmainot tos šeit, tie tiks izmainīti tikai šajā mediawiki instalācijā. Lai tos izmainītu visām pārējām, apskatieties [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] un [https://translatewiki.net translatewiki.net].",
-       "allmessagesnotsupportedDB": "Šī lapa nedarbojas, tāpēc, ka '''wgUseDatabaseMessages''' nedarbojas.",
+       "allmessages-not-supported-database": "Šī lapa nedarbojas, tāpēc, ka '''wgUseDatabaseMessages''' nedarbojas.",
        "allmessages-filter-legend": "Filtrs",
        "allmessages-filter": "Filtrēt pēc izmainīšanas statusa:",
        "allmessages-filter-unmodified": "Nemodificēti",
        "feedback-bugnew": "Es pārbaudīju. Ziņot par jaunu kļūdu",
        "feedback-cancel": "Atcelt",
        "feedback-close": "Gatavs",
+       "feedback-external-bug-report-button": "Izveidot tehnisko uzdevumu",
        "feedback-dialog-title": "Iesniegt atsauksmes",
        "feedback-error1": "Kļūda: API neatpazīts rezultāts",
        "feedback-error2": "Kļūda: Labojums neizdevās",
        "mw-widgets-dateinput-no-date": "Nav izvēlēts datums",
        "mw-widgets-mediasearch-noresults": "Nav atrasts neviens rezultāts.",
        "mw-widgets-titleinput-description-new-page": "lapa vēl nepastāv",
+       "mw-widgets-titleinput-description-redirect": "pāradresēt uz $1",
        "mw-widgets-categoryselector-add-category-placeholder": "Pievienot kategoriju...",
        "mw-widgets-usersmultiselect-placeholder": "Pievienot vēl...",
        "mw-widgets-titlesmultiselect-placeholder": "Pievienot vēl...",
        "date-range-to": "Līdz datumam:",
        "sessionprovider-generic": "$1 sesijas",
        "randomrootpage": "Nejauša saknes lapa",
+       "log-action-filter-block": "Bloķēšanas veids:",
        "log-action-filter-protect": "Aizsardzības veids:",
        "log-action-filter-suppress": "Cenzēšanas veids:",
        "log-action-filter-upload": "Augšupielādes veids:",
        "log-action-filter-managetags-delete": "Iezīmes dzēšana",
        "log-action-filter-managetags-activate": "Iezīmes aktivācija",
        "log-action-filter-managetags-deactivate": "Iezīmes deaktivācija",
+       "log-action-filter-protect-protect": "Aizsardzība",
+       "log-action-filter-protect-modify": "Aizsardzības izmaiņa",
+       "log-action-filter-protect-unprotect": "Aizsardzības atcelšana",
+       "log-action-filter-protect-move_prot": "Pārvietota aizsardzība",
+       "log-action-filter-rights-rights": "Manuāla izmaiņa",
+       "log-action-filter-rights-autopromote": "Automātiska izmaiņa",
        "log-action-filter-suppress-event": "Reģistra ieraksta cenzēšana",
        "log-action-filter-suppress-delete": "Lapas cenzēšana",
        "log-action-filter-upload-upload": "Jauna augšupielāde",
index 547af26..9c7c014 100644 (file)
        "blocked-notice-logextract": "該簿現鎖也。\n下列之記鎖,以察之:",
        "clearyourcache": "'''註:'''重取頁面,文方新焉。\n'''Mozilla / Firefox / Safari:'''押''Shift''並點''重新載入'',或合鍵''Ctrl-F5''或''Ctrl-R''(Mac為''Command-R'')。\n'''Konqueror:'''點''Reload'',或押''F5''。\n:''Opera:'''須至''Tools→Preferences''清謄本。\n'''Internet Explorer:'''押''Ctrl''並點''重新整理'',或合鍵''Ctrl-F5''。",
        "usercssyoucanpreview": "'''訣:'''CSS應先「{{int:showpreview}}」而後存。",
-       "userjsyoucanpreview": "'''訣:'''JavaScript應先「{{int:showpreview}}」而後存。",
+       "userjsyoucanpreview": "<strong>訣:</strong>JavaScript應先「{{int:showpreview}}」而後存。",
        "usercsspreview": "'''預覽簿CSS。'''\n'''尚未儲焉!'''",
        "userjspreview": "'''預覽簿JavaScript。'''\n'''尚未儲焉!'''",
        "sitecsspreview": "'''預覽此CSS。'''\n'''尚未儲焉!'''",
        "minoreditletter": "校",
        "newpageletter": "新",
        "boteditletter": "僕",
-       "number_of_watching_users_pageview": "[放有$1哨]",
        "rc-change-size-new": "纂後有$1字節",
        "newsectionsummary": "/* $1 */ 新節",
        "rc-enhanced-expand": "示細",
        "img-auth-nopathinfo": "PATH_INFO失之。\n爾之伺服器無此資料也。\n以CGI之本耳,無img_auth矣。\n閱https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization。",
        "img-auth-notindir": "求之徑無存貢錄中。",
        "img-auth-badtitle": "於「$1」無建效題也。",
-       "img-auth-nologinnWL": "爾未登簿,「$1」無在白名中。",
        "img-auth-nofile": "檔「$1」無存也。",
        "img-auth-isdir": "爾試問錄「$1」。\n只問檔也。",
        "img-auth-streaming": "流「$1」中。",
        "allmessagesdefault": "慣話文",
        "allmessagescurrent": "今話文",
        "allmessagestext": "此列MediaWiki官話。\n如貢正宗MediaWiki本地化,[https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki本地化]與[https://translatewiki.net translatewiki.net]閱之。",
-       "allmessagesnotsupportedDB": "'''$wgUseDatabaseMessages'''閉庫,'''無纂也。",
+       "allmessages-not-supported-database": "'''$wgUseDatabaseMessages'''閉庫,'''無纂也。",
        "allmessages-filter-legend": "濾",
        "allmessages-filter": "以易濾:",
        "allmessages-filter-unmodified": "無易",
index 5eafe6b..9ce3707 100644 (file)
        "rcfilters-filter-newpages-label": "प्रयोक्ता रचना लग",
        "rcfilters-filter-categorization-label": "श्रेणी परिवर्तन",
        "rcfilters-filter-logactions-label": "लॉग क कार्रवाई",
-       "rcfilters-filtergroup-lastRevision": "नूतन संशोधन",
+       "rcfilters-filtergroup-lastrevision": "नूतन संशोधन",
        "rcfilters-filter-lastrevision-label": "नूतन संशोधन",
        "rcfilters-filter-excluded": "अपवर्जित",
        "rcfilters-tag-prefix-namespace-inverted": " $1 <strong>:नैछि</strong>",
        "newpageletter": "न",
        "boteditletter": "ब",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 ध्यान राखैवाला {{PLURAL:$1|प्रयोक्ता|प्रयोक्तासभ}}]",
        "rc-change-size": "$1",
        "rc-change-size-new": "परिवर्तनक बाद $1 {{PLURAL:$1|बाइट}}",
        "newsectionsummary": "/* $1 */ नव अनुभाग",
        "img-auth-nopathinfo": "बाटक जानकारी नै अछि।\nअहाँक वितरक ऐ सूचनाकेँ प्रसारित नै कऽ सकत।\nई सी.जी.आइ.आधारित अछि आ चित्र-समर्थन केँ समर्थन नै दऽ सकत।\n[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization देखू image authorization.]",
        "img-auth-notindir": "आग्रह कएल रस्ता विन्यासित उपारोपित निर्देशिकामे नै अछि।",
        "img-auth-badtitle": "\"$1\" लेल कोनो मान्य शीर्षक नै बना सकल।",
-       "img-auth-nologinnWL": "अहाँ सम्प्रवेशित नै छी आ \"$1\" स्वीकृत सूचीमे नै अछि।",
        "img-auth-nofile": "संचिका \"$1\" नै अछि।",
        "img-auth-isdir": "अहाँ एकटा निर्देशिका \"$1\" मे प्रवेशक प्रयास कऽ रहल छी।\nमात्र संचिका प्रवेश मान्य छै।",
        "img-auth-streaming": "\"$1\" दृश्यस्यन्दन भऽ रहल अछि।",
        "revertpage": "सम्पादन आपस कएल गेल [[Special:Contributions/$2|$2]] ([[User talk:$2|talk]]) सँ अन्तिम संशोधन धरि एकरा द्वारा [[User:$1|$1]]।",
        "revertpage-nouser": "(प्रयोक्ताक नाम हटा देल गेल अछि) द्वारा केल गेल संपादनकेँ फेरसँ पुरान स्थितिमे आनि कऽ एकर पहिलुक [[User:$1|$1]] सँ बनल संस्करणकेँ फेरसँ ताजा संस्करण बनाऊ।",
        "rollback-success": "{{GENDER:$3|$1}} क संपादन हटाबी;\n{{GENDER:$4|$2}} द्वारा संपादित अन्तिम अवतरण क पुनर्स्थापित करू।",
-       "rollback-success-notify": "$1द्वारा पूर्ववत सम्पादन;\n$2द्वारा केल अन्तिम अवतरण पर वापस। [$3 परिवर्तन देखाबी]",
        "sessionfailure-title": "सत्र विफल भ गेल",
        "sessionfailure": "एहन लागैत अछि जे अहां के लागिन सत्र में कोनो त्रुटि अछि. सत्र अपहरण से बचाबय  सं सावधानीक लेल अहां के अहि क्रियाकलाप क रद्द क देल गेल. अहां पाछां के पृष्ठ पर जौउ आ पृष्ठ के फेर सं लोड क दोबारा कोशिश करू.",
        "changecontentmodel": "पृष्ठ सामग्री मोडल परिवर्तन करी",
        "allmessagesdefault": "पूर्वनिर्धारित सन्देश पाठ",
        "allmessagescurrent": "अखुनका सन्देश पाठ",
        "allmessagestext": "ई मिडियाविकी नामस्थानमे उपलब्ध संस्थागत सन्देशक सूची छी।\nकृपा कऽ देखी [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] आ [https://translatewiki.net translatewiki.net] जँ अहाँ मिडियाविकीक स्थानिकीकरणक मूलक अनुवादमे योगदान करए चाहै छी।",
-       "allmessagesnotsupportedDB": "ई पन्ना प्रयोगमे नै आनल जा सकैए कारण '''$wgUseDatabaseMessages''' अशक्त कएल अछि।",
+       "allmessages-not-supported-database": "ई पन्ना प्रयोगमे नै आनल जा सकैए कारण '''$wgUseDatabaseMessages''' अशक्त कएल अछि।",
        "allmessages-filter-legend": "चलनी",
        "allmessages-filter": "अपन हिसाबे अनुकूलित कऽ छाँटू:",
        "allmessages-filter-unmodified": "अपरिवर्तित",
index 66dc8ab..c5a2daa 100644 (file)
        "returnto": "Bali maring $1.",
        "tagline": "Sekang {{SITENAME}}",
        "help": "Réwang",
+       "help-mediawiki": "Pitulung MediaWiki",
        "search": "golet tulisan",
        "searchbutton": "Goleti",
        "go": "golet",
        "searcharticle": "Nuju maring",
        "history": "sejarah kaca",
        "history_short": "Sejarah kaca",
+       "history_small": "Sejarah",
        "updatedmarker": "diowahi wiwit kunjungan pungkasane inyong",
        "printableversion": "Edisi Cetak",
        "permalink": "Pranala permanèn",
        "talk": "bahas",
        "views": "Tampilan",
        "toolbox": "Pekakas",
+       "tool-link-userrights-readonly": "Deleng {{GENDER:$1|user}} klompok",
+       "tool-link-emailuser": "Imel {{GENDER:$1|user}}",
        "imagepage": "Deleng kaca berkas",
        "mediawikipage": "Ndeleng kaca pesen sistem",
        "templatepage": "Ndeleng kaca cithakan",
        "ns-specialprotected": "Kaca astaiwa ora teyeng disunting.",
        "titleprotected": "Judul kiye wis direksa ora olih digawe nang [[User:$1|$1]].\nAlesane yakuwe <em>$2</em>.",
        "filereadonlyerror": "Ora teyeng ngowaih berkas \"$1\" jalaran panyimpenan berkas \"$2\" ana nang mode-mung-teyeng-diwaca.\n\nAdministrator sing ngunci aweh keterangan: \"$3\".",
+       "invalidtitle": "Oranana judule",
        "invalidtitle-knownnamespace": "Irah-irahan ora sah nang bilikjeneng \"$2\" lan teks \"$3\"",
        "invalidtitle-unknownnamespace": "Judhul ora sah nang bilik jeneng sing ora dingerteni nomer $1 lan teks \"$2\"",
        "exception-nologin": "Urung mlebu",
        "cannotlogin-title": "Ora bisa mlebu log",
        "cannotlogin-text": "Ora mungkin mlebu log.",
        "cannotloginnow-title": "Ora teyeng mlebu siki",
+       "cannotloginnow-text": "Ora teyeng mlebu angger nganggo $1.",
        "cannotcreateaccount-title": "Ora bisa gawé akun",
        "yourdomainname": "Domain Rika:",
        "password-change-forbidden": "Rika ora teyeng ngowaih tembung sandhi nang wiki kiye.",
        "externaldberror": "Ana kesalahan otentikasi basis data utawa Rika ora olih nglakokna pemutakhiran maring akun eksternale Rika.",
        "login": "Melebu",
+       "login-security": "Verifikasi identitase rika",
        "nav-login-createaccount": "Mlebu / gawe kaca anggota (akun)",
        "logout": "Metu Log",
        "userlogout": "Metu Log",
        "minoredit": "Kiye suntingan cilik",
        "watchthis": "Awasi kaca kiyé",
        "savearticle": "Terbitna Kaca",
+       "savechanges": "Benaih owahan",
        "publishpage": "Pacak kacané",
+       "publishchanges": "Sebarna owahane...",
+       "savearticle-start": "Benaih kaca...",
+       "savechanges-start": "Benaih owahane...",
+       "publishpage-start": "Nyebarna kaca...",
+       "publishchanges-start": "Nyebarna owahan...",
        "preview": "Pra tayang",
        "showpreview": "Pra tayang",
        "showdiff": "Ndeleng bedané",
        "missingsummary": "'''Pènget:''' Rika ora nglebokna ringkesan panyuntingan. \nAngger Rika mencèt tombol Simpen maning, suntingane Rika bakal kasimpen tanpa ringkesan panyuntingan.",
        "missingcommenttext": "Tulung lebokna komentar nang ngisor kiye.",
        "missingcommentheader": "'''Pènget:''' Rika ora nglebokna subjek/judul nggo komentare Rika kiye. \nAngger Rika mencèt \"$1\" maning, suntingane Rika bakal kasimpen tanpa komentar kuwe.",
-       "summary-preview": "Pratayang ringkesan:",
-       "subject-preview": "Pratayang subyèk/judul:",
+       "summary-preview": "Pratayang ringkesane:",
+       "subject-preview": "Pratayang subyek/judul:",
        "blockedtitle": "Panganggo diblokir",
        "blockednoreason": "ora ana alesan sing diwènèhna",
        "whitelistedittext": "Rika kudu $1 ben teyeng nyunting artikel.",
        "updated": "(Dianyari)",
        "note": "'''Cathetan:'''",
        "previewnote": "'''Eling ya kiye tembe pratayang thok.'''\nOwahane Rika durung disimpen!",
+       "continue-editing": "Mayuh meng pengeditane",
        "previewconflict": "Pratayang kiye nidokna teks nang bagiyan dhuwur kotak suntingan teks kaya sing bakal katon nek Rika nyimpen.",
-       "session_fail_preview": "'''Nuwun sèwu, suntingan Rika ora teyeng diolah jalaran dhata sèsi kabusak.\nMonggo dijajal sepisan maning. \nAngger tetep ora teyeng, jajal [[Special:UserLogout|metu log]] disit lan mlebu log maning.",
-       "session_fail_preview_html": "'''Nuwun sèwu! Kita ora teyeng mrosès suntingan Rika jalaran data sési ilang.'''\n\n''Jalaran {{SITENAME}} ngidina panrapan HTML mentah, pratayang diumpetna minangka penggakan marang serangan Javascript.''\n\n'''Angger kiye kuwe upaya suntingan sing sah, monggo dijajal maning.'''\nNek esih tetep ora kasil, jajalen [[Special:UserLogout|metu log]] lan mlebu log maning.",
+       "session_fail_preview": "'''Nuwun sewu, suntingan Rika ora teyeng diolah jalaran dhata sesi kebusek.\nMonggo dijajal sepisan maning. \nAngger tetep ora teyeng, jajal [[Special:UserLogout|metu log]] disit lan mlebu log maning.",
+       "session_fail_preview_html": "'''Nuwun sewu! Kita ora teyeng mroses suntingan Rika jalaran data sesi ilang.'''\n\n''Jalaran {{SITENAME}} ngidina panrapan HTML mentah, pratayang diumpetna minangka penggakan marang serangan Javascript.''\n\n'''Angger kiye kuwe upaya suntingan sing sah, monggo dijajal maning.'''\nNek esih tetep ora kasil, jajalen [[Special:UserLogout|metu log]] lan mlebu log maning.",
        "editing": "Nyunting $1",
        "creating": "Gawe $1",
        "editingsection": "Nyunting $1 (bagiyan)",
        "edit-conflict": "Konflik panyuntingan.",
        "edit-no-change": "Suntingane Rika dijorna, jalaran Rika ora gawe owahan apa-apa nang teks.",
        "edit-already-exists": "Ora teyeng gawe kaca anyar.\nKiye anu wis ana.",
+       "slot-name-main": "Utamane",
        "expensive-parserfunction-warning": "'''Pènget:''' Kaca kiye isine kakehan gole nggunakna panggilan fungsi parser.\n\nKudune kuwe kurang sekang $2 {{PLURAL:$2|panggilan|panggilan}}, ningen sekiye wis ana {{PLURAL:$1|$1 panggilan|$1 panggilan}}.",
        "expensive-parserfunction-category": "Kaca sing nduwe panggilan fungsi parser sing kakehan",
        "post-expand-template-inclusion-warning": "'''Pènget:''' Ukurane cithakan sing dienggo kegedhèn.\nSawetara cithakan bakal ora dipelokna.",
        "revertpage": "Suntingane [[Special:Contributions/$2|$2]] ([[User talk:$2|dhiskusi]]) dibalekna maring versi pungkasan sekang [[User:$1|$1]]",
        "revertpage-nouser": "Mbalekna suntingan sekang (jeneng panganggo dibusek) ming revisi pungkasan sekang [[User:$1|$1]]",
        "rollback-success": "Mbalekna suntingane $1;\ndibalekna ming revisi pungkasan sekang $2.",
-       "rollback-success-notify": "Mbalekna besutan sekang $1; owah mbalik nggo revisi mburi sekang $2. [$3 Deleng owahane]",
        "sessionfailure-title": "Sèsi gagal",
        "sessionfailure": "Ketone lagi ana masalah karo sesi log-e Rika;\nloge Rika wis dibatalna nggo nyegah pambajakan.\nMonggo mbalik ming kaca sedurunge, dibaleni gole muatna kaca (reload) lan jajal diunggahna maning.",
        "protectlogpage": "Log pangreksan",
index cf14be6..e54ec91 100644 (file)
        "minoreditletter": "ё",
        "newpageletter": "О",
        "boteditletter": "р",
-       "number_of_watching_users_pageview": "[$1 ваны {{PLURAL:$1|тии|тиихть}}]",
        "newsectionsummary": "/* $1 */ од пялькс",
        "rc-enhanced-expand": "Няфтемс анцяйнятне (эряви JavaScript)",
        "rc-enhanced-hide": "Кяшемс анцяйнятне",
        "allmessagesdefault": "Апак полафтт текст",
        "allmessagescurrent": "Тяниень текст",
        "allmessagestext": "Тя MediaWiki-са васьфневи системонь пачфтематнень лувомась.\nЭняльттяма, сувак [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Локализациес] ди [https://translatewiki.net translatewiki.net-с] кда тонь мяльце тиемс эсь путксце марстонь MediaWiki локализациес.",
-       "allmessagesnotsupportedDB": "Тя лопас аш кода кунцемс сяс мес '''$wgUseDatabaseMessages'''лоткафоль.",
+       "allmessages-not-supported-database": "Тя лопас аш кода кунцемс сяс мес '''$wgUseDatabaseMessages'''лоткафоль.",
        "allmessages-language": "Кяль:",
        "allmessages-filter-submit": "Ётамс",
        "thumbnail-more": "Оцюлгофтомс",
index d4e3e7c..e3fa205 100644 (file)
        "rcfilters-filter-editsbyself-description": "Ny fandraisan'anjaranao.",
        "rcfilters-filter-editsbyother-label": "Ny fiovana nataon'ny sasany",
        "rcfilters-filter-editsbyother-description": "Fiovana rehetra afa-tsy ny anao.",
-       "rcfilters-filtergroup-userExpLevel": "Lentan'ny traikefa (ho an'ireo mpikambana nisoratra anarana ihany)",
+       "rcfilters-filtergroup-user-experience-level": "Lentan'ny traikefa (ho an'ireo mpikambana nisoratra anarana ihany)",
        "rcfilters-filter-user-experience-level-registered-label": "Nisoratra anarana",
        "rcfilters-filter-user-experience-level-registered-description": "Mpanova tafiditra.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Tsy nisoratra anarana",
        "rcfilters-filter-categorization-label": "Fiovana amin'ny sokajy",
        "rcfilters-filter-categorization-description": "Fandraiketana an'ireo pejy ampiana na esorina amin'ny sokajy.",
        "rcfilters-filter-logactions-label": "Asa voalaogy",
-       "rcfilters-filtergroup-lastRevision": "Reviziôna farany",
+       "rcfilters-filtergroup-lastrevision": "Reviziôna farany",
        "rcfilters-filter-lastrevision-label": "Reviziôna farany",
        "rcfilters-filter-lastrevision-description": "Ny fiovana vao haingana indrindra amin'ny pejy.",
        "rcfilters-filter-previousrevision-label": "Reviziôna nialoha",
        "minoreditletter": "k",
        "newpageletter": "V",
        "boteditletter": "r",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|mpikambana|mpikambana}} manara-maso]",
        "rc-change-size-new": "$1{{PLURAL:}} oktety taorian'ny fanovana",
        "newsectionsummary": "/* $1 */ fizarana vaovao",
        "rc-enhanced-expand": "Hijery ny antsipirihany",
        "img-auth-nopathinfo": "Tsy misy PATH_INFO.\nTsy voaparametatra ny lohamilinao hampita io fampahalalàna io.\nMety mampiasa CGI angamba ilay lohamilina ka tsy mahazaka an'i img_auth\nVangio ny https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Ny lalana nangatahana dia tsy ny petra-drakitra nokaonfigiorena.",
        "img-auth-badtitle": "Tsy afaka mamorona lohateny azo ampiasaina avy amin'ny « $1 ».",
-       "img-auth-nologinnWL": "Tsy mbola niditra ianao ary tsy ao amin'ny lisitra fotsy « $1 ».",
        "img-auth-nofile": "Tsy misy ny rakitra « $1 ».",
        "img-auth-isdir": "Nanandrana nakao amin'ny petra-drakitra « $1 » ianao.\nNy petra-drakitra misy rakitra ihany no azo aleha.",
        "img-auth-streaming": "Vaky streaming « $1 ».",
        "allmessagesdefault": "Dikan-teny tany am-boalohany",
        "allmessagescurrent": "Dikan-teny miasa ankehitriny",
        "allmessagestext": "Ity dia lisitry ny hafatra hita ao amin'ny anaran-tsehatra MediaWiki.\nAndana vangio ny [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Fandikana an'i Mediawiki] ary [https://translatewiki.net/ translatewiki.net] raha tia handray anjara amin'ny fandikana an'i Mediawiki amin'ny ankapobeny.",
-       "allmessagesnotsupportedDB": "Tsy mbola mandeha ny '''{{ns:special}}:Allmessages''' satria tsy mandeha koa ny '''$wgUseDatabaseMessages'''.",
+       "allmessages-not-supported-database": "Tsy mbola mandeha ny '''{{ns:special}}:Allmessages''' satria tsy mandeha koa ny '''$wgUseDatabaseMessages'''.",
        "allmessages-filter-legend": "Tantavanina",
        "allmessages-filter": "Hanasivana araka ny satam-panovana :",
        "allmessages-filter-unmodified": "Mbola tsy voaova",
index e7b6877..1f0dc81 100644 (file)
        "revdel-restore": "ganti tampilan",
        "pagehist": "Riwayaik laman",
        "deletedhist": "Riwayaik pangapuihan",
+       "revdelete-hide-current": "Gagal manyambunyian parubahan tanggal $2, $1: iko adolah parubahan paliang baru.\nParubahan ko indak dapek disambunyian.",
+       "revdelete-show-no-access": "Gagal manampilan parubahan tanggal $2, $1: parubahan ko alah ditandoi ''tabateh''.\nSanak indak punyo akses ka parubahan ko.",
+       "revdelete-modify-no-access": "Gagal maubah parubahan tanggal $2, $1: parubahan ko alah ditandoi ''tabateh''.\nSanak indak punyo akses ka parubahan ko.",
+       "revdelete-modify-missing": "Gagal maubah parubahan ID $1: parubahan ko indak ado di basis data!",
+       "revdelete-no-change": "<strong>Paringatan:</strong>Parubahan tanggal $2, $1 alah punyo aturan panyambunyian.",
+       "revdelete-concurrent-change": "Gagal maubah parubahan tanggal $2, $1: statusnyo mungkin alah diubah pangguno lain basamoan jo Sanak.\nCubo pareso catatan log.",
+       "revdelete-only-restricted": "Ado yang salah wakatu manyambunyian item tanggal $2, $1: Sanak indak dapek manyambunyiannyo dari panguruih tanpa mamiliah salah satu opsi panyambunyian lainnyo.",
        "revdelete-reason-dropdown": "*Alasan pangapuihan umum\n** Palanggaran hak cipta\n** Komentar atau informasi paribadi nan indak patuik\n** Namo pangguno nan indak patuik\n** Bapotensi mancemarkan namo baiak",
        "revdelete-otherreason": "Alasan lain/tambahan:",
        "revdelete-reasonotherlist": "Alasan lain",
        "revdelete-edit-reasonlist": "Alasan mangapuih laman",
        "revdelete-offender": "Pambuek reviri:",
        "suppressionlog": "Log pambanaman",
+       "suppressionlogtext": "Dibawah ko adolah daftar panghapuihan jo pamblokiran, tamasuak isi yang disambunyian dari panguruih.\nCaliak [[Special:BlockList|block list]] untuak daftar yang paliang baru.",
+       "mergehistory": "Riwayaik panggabuangan sajarah halaman",
+       "mergehistory-box": "Gabuang parubahan-parubahan dari duo halaman:",
+       "mergehistory-from": "Halaman sumber:",
+       "mergehistory-into": "Halaman tujuan:",
+       "mergehistory-go": "Tampilan suntiangan yang dapek digabuang",
+       "mergehistory-submit": "Gabuang revisi",
+       "mergehistory-empty": "Indak ado parubahan yang dapek digabuang.",
+       "mergehistory-done": "$3 {{PLURAL:$3|revision|revisions}} dari $1 {{PLURAL:$3|was|were}} berhasil digabuangan ka [[:$2]].",
+       "mergehistory-fail": "Indak dapek digabuang, mohon pareso baliak halaman jo parameter waktu.",
+       "mergehistory-fail-invalid-source": "Halaman asal indak sah.",
+       "mergehistory-fail-invalid-dest": "Halaman tujuan indak sah.",
+       "mergehistory-fail-self-merge": "Halaman sumber jo tujuannyo samo.",
        "mergehistory-reason": "Alasan:",
        "mergelog": "Log panggabuangan",
        "revertmerge": "Batal gabuang",
index 42680f9..c2a267d 100644 (file)
@@ -44,8 +44,8 @@
        "tog-watchuploads": "Ставај ги податотеките што ги подигам во набљудуваните",
        "tog-watchrollback": "Додај ги страниците сум ги отповикал во набљудувани",
        "tog-minordefault": "Обележувај ги сите уредувања како ситни по основно",
-       "tog-previewontop": "Ð\9fÑ\80икажи Ð³Ð¾ Ð¿Ñ\80егледоÑ\82 пред кутијата за уредување",
-       "tog-previewonfirst": "Ð\9fÑ\80икажи Ð¿Ñ\80еглед Ð½Ð° првото уредување",
+       "tog-previewontop": "Ð\9fÑ\80икажи Ð¿Ñ\80еглед пред кутијата за уредување",
+       "tog-previewonfirst": "Ð\9fÑ\80икажи Ð¿Ñ\80еглед Ð¿Ñ\80и првото уредување",
        "tog-enotifwatchlistpages": "Испраќај ми е-пошта при промена на страница или податотека од мојот список на набљудувања",
        "tog-enotifusertalkpages": "Испраќај ми е-пошта при промена на мојата разговорна страница",
        "tog-enotifminoredits": "Испраќај ми е-пошта и за ситни промени во страниците и податотеките",
@@ -53,7 +53,7 @@
        "tog-shownumberswatching": "Прикажи го бројот на корисници кои набљудуваат",
        "tog-oldsig": "Вашиот постоечки потпис:",
        "tog-fancysig": "Сметај го потписот за викитекст (без автоматска врска)",
-       "tog-uselivepreview": "Ð\9fÑ\80егледи Ð²Ð¾ Ð¶Ð¸Ð²Ð¾ без превчитување на страницата",
+       "tog-uselivepreview": "Ð\9fÑ\80икажÑ\83ваÑ\98 Ð¿Ñ\80егледи без превчитување на страницата",
        "tog-forceeditsummary": "Извести ме кога нема опис на промените",
        "tog-watchlisthideown": "Скриј мои уредувања од набљудуваните",
        "tog-watchlisthidebots": "Скриј ботовски уредувања од набљудуваните",
        "viewsourceold": "преглед на кодот",
        "editlink": "уреди",
        "viewsourcelink": "преглед на кодот",
-       "editsectionhint": "УÑ\80еди Ð³Ð¾ Ð¿Ð°Ñ\81Ñ\83Ñ\81оÑ\82: $1",
+       "editsectionhint": "УÑ\80еди Ð³Ð¾ Ð¾Ð´Ð´ÐµÐ»Ð¾Ñ\82 â\80\9e$1â\80\9c",
        "toc": "Содржина",
        "showtoc": "прикажи",
        "hidetoc": "скриј",
        "missingarticle-rev": "(измена#: $1)",
        "missingarticle-diff": "(разлика: $1, $2)",
        "readonly_lag": "Базата е автоматски заклучена додека помошните опслужувачи не се усогласат",
-       "nonwrite-api-promise-error": "HTTP-заглавиеÑ\82о â\80\9ePromise-Non-Write-API-Actionâ\80\9c Ð±ÐµÑ\88е Ð¸Ñ\81пÑ\80аÑ\82ено, Ð½Ð¾ Ð±Ð°Ñ\80аÑ\9aеÑ\82о Ð±ÐµÑ\88е Ñ\83паÑ\82ено ÐºÐ¾Ð½ Ð·Ð°Ð¿Ð¸Ñ\81ен Ð¼Ð¾Ð´Ñ\83л на API.",
+       "nonwrite-api-promise-error": "HTTP-заглавиеÑ\82о â\80\9ePromise-Non-Write-API-Actionâ\80\9c Ð±ÐµÑ\88е Ð¸Ñ\81пÑ\80аÑ\82ено, Ð½Ð¾ Ð±Ð°Ñ\80аÑ\9aеÑ\82о Ð±ÐµÑ\88е Ñ\83паÑ\82ено ÐºÐ¾Ð½ Ð¼Ð¾Ð´Ñ\83л Ð·Ð° Ð¿Ð¸Ñ\88Ñ\83ваÑ\9aе на API.",
        "internalerror": "Внатрешна грешка",
        "internalerror_info": "Внатрешна грешка: $1",
        "internalerror-fatal-exception": "Кобен исклучок на типот „$1“",
        "filecopyerror": "Не можeв да ја ископирам податотеката „$1“ во „$2“.",
        "filerenameerror": "Не можев да ја преименувам податотеката „$1“ во „$2“.",
-       "filedeleteerror": "Ð\9dе Ð¼Ð¾Ð¶Ðµ Ð´Ð° Ñ\81е Ð¸Ð·Ð±Ñ\80иÑ\88е податотеката „$1“.",
+       "filedeleteerror": "Ð\9dе Ð¼Ð¾Ð¶Ð°Ð¼ Ð´Ð° Ñ\98а Ð¸Ð·Ð±Ñ\80иÑ\88ам податотеката „$1“.",
        "directorycreateerror": "Не можеше да се создаде именикот „$1“.",
        "directoryreadonlyerror": "Папката „$1“ е само за читање.",
        "directorynotreadableerror": "Папката „$1“ не е читлива.",
        "virus-scanfailed": "неуспешно скенирање (код $1)",
        "virus-unknownscanner": "непознат антивирус:",
        "logouttext": "<strong>Сега сте одјавени.</strong>\n\nДа напоменеме дека некои страници може да продолжат да се прикажуваат како да сте најавени, сè додека не го исчистите меѓускладот на вашиот прелистувач.",
+       "logging-out-notify": "Ве одјавувам. Почекајте.",
+       "logout-failed": "Во моментов не можам да ве одјавам: $1",
        "cannotlogoutnow-title": "Во моментов не можам да ве одјавам",
        "cannotlogoutnow-text": "Не можам да ве одјавам кога се користи $1.",
-       "welcomeuser": "Добр едојдовте, $1!",
+       "welcomeuser": "Добре дојдовте, $1!",
        "welcomecreation-msg": "Вашата корисничка сметка е создадена.\nНе заборавајте да ги измените вашите [[Special:Preferences|{{SITENAME}} нагодувања]].",
        "yourname": "Корисничко име:",
        "userlogin-yourname": "Корисничко име",
        "userexists": "Корисничкото име што го внесовте е зафатено.\nИзберете друго име.",
        "createacct-normalization": "Вашето корисничко име ќе биде прилагодено во „$2“ поради техничките ограничувања.",
        "loginerror": "Грешка при најавувањето",
-       "createacct-error": "Ð\93Ñ\80еÑ\88ка Ð²Ð¾ Ñ\81оздаваÑ\9aеÑ\82о Ð½Ð° Ñ\81меÑ\82каÑ\82а",
+       "createacct-error": "Ð\93Ñ\80еÑ\88ка Ð¿Ñ\80и Ñ\81оздаваÑ\9aеÑ\82о Ð½Ð° Ñ\81меÑ\82ка",
        "createaccounterror": "Не можам да ја создадам сметката: $1",
        "nocookiesnew": "Корисничката сметка е создадена, но не сте најавени.\n{{SITENAME}} користи колачиња за најавување на корисници.\nВие имате оневозможено колачиња на вашиот прелистувач.\nОвозможете ги, па потоа најавете се со вашето корисничко име и лозинка.",
        "nocookieslogin": "{{SITENAME}} користи колачиња за најавување на корисници.\nВие го имате оневозможено користењето на колачиња на вашиот прелистувач.\nВе молиме активирајте ги и обидете се повторно.",
        "accountcreatedtext": "Корисничката сметка за [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|разговор]]) е направена.",
        "createaccount-title": "Создавање на сметка за {{SITENAME}}",
        "createaccount-text": "Некој направил сметка со вашата е-поштенска адреса на {{SITENAME}} ($4) со име „$2“ и  лозинка „$3“.\nБи требало сега да се пријавите и да ја промените вашата лозинка.\n\nМожете да ја занемарите оваа порака ако сметката била направена по грешка.",
-       "login-throttled": "Ð\98маÑ\82е Ð¿Ñ\80емногÑ\83 Ð¾Ð±Ð¸Ð´Ð¸ Ð·Ð° Ð½Ð°Ñ\98ава Ð·Ð° ÐºÑ\80аÑ\82ко Ð²Ñ\80еме.\nПочекајте $1 пред да се обидете повторно.",
+       "login-throttled": "Ð\9dапÑ\80авивÑ\82е Ð¿Ñ\80емногÑ\83 Ð¾Ð±Ð¸Ð´Ð¸ Ð·Ð° Ð½Ð°Ñ\98ава.\nПочекајте $1 пред да се обидете повторно.",
        "login-abort-generic": "Најавата е неуспешна — Откажано",
        "login-migrated-generic": "Вашата сметка е пренесена и корисничкото име веќе не постои на ова вики.",
        "loginlanguagelabel": "Јазик: $1",
        "blankarticle": "<strong>Предупредување:</strong> Страницата што ја создавате е празна.\nАко повторно стиснете на „$1“, страницата ќе биде создадена без никаква содржина во неа.",
        "anoneditwarning": "<strong>Предупредување:</strong> Не сте најавени. Вашата IP-адреса ќе биде јавно видлива ако уредувате. Ако <strong>[$1 се најавите]</strong> или <strong>[$2 направите сметка]</strong>, тогаш уредувањата ќе се припишуваат на вашето корисничко име, покрај другите погодности.",
        "anonpreviewwarning": "''Не сте најавени. Ако ја зачувате, Вашата IP-адреса ќе биде заведена во историјата на уредување на страницата.''",
-       "missingsummary": "'''Потсетник:''' Не внесовте опис на измените. Ако притиснете Зачувај повторно, вашите измени ќе се зачуваат без опис.",
+       "missingsummary": "<strong>Потсетник:</strong> Не внесовте опис на измените.\nАко притиснете „$1“ повторно, вашите измени ќе се зачуваат без опис.",
        "selfredirect": "<strong>Предупредување:</strong> Создавате пренасочување кон истата статија.\nМоже да сте укажале грешна целна страница, или пак уредувате погрешна страница.\nАко стиснете на „$1“ повторно, тогаш пренасочувањето бездруго ќе се создаде.",
        "missingcommenttext": "Внесете коментар.",
        "missingcommentheader": "<strong>Потсетување:</strong> Не внесовте наслов за овој коментар.\nАко повторно стиснете на „$1“, уредувањето ќе биде зачувано без наслов.",
        "nocreatetext": "{{SITENAME}} ја има ограничено можноста за создавање нови страници.\nМожете да се вратите назад и да уредувате постоечка страница или [[Special:UserLogin|најавете се или создајте нова корисничка сметка]].",
        "nocreate-loggedin": "Немате дозвола да создавате нови страници.",
        "sectioneditnotsupported-title": "Уредувањето на заглавија не е поддржано",
-       "sectioneditnotsupported-text": "Ð\9dа Ð¾Ð²Ð°Ð° Ñ\81Ñ\82аниÑ\86а Ð½Ðµ Ðµ Ð¿Ð¾Ð´Ð´Ñ\80жано Ñ\83Ñ\80едÑ\83ваÑ\9aеÑ\82о Ð½Ð° Ð·Ð°Ð³Ð»Ð°Ð²Ð¸Ñ\98а.",
+       "sectioneditnotsupported-text": "УÑ\80едÑ\83ваÑ\9aеÑ\82о Ð½Ð° Ð·Ð°Ð³Ð»Ð°Ð²Ð¸Ñ\98а Ð½Ðµ Ðµ Ð¿Ð¾Ð´Ð´Ñ\80жано Ð½Ð° Ð¾Ð²Ð°Ð° Ñ\81Ñ\82Ñ\80аниÑ\86а.",
        "permissionserrors": "Грешка со дозволата",
        "permissionserrorstext": "Немате дозвола да го направите тоа, од {{PLURAL:$1|следнава причина|следниве причини}}:",
        "permissionserrorstext-withaction": "Немате дозвола за $2, од {{PLURAL:$1|следнава причина|следниве причини}}:",
        "page_first": "прв",
        "page_last": "последен",
        "histlegend": "Разлика помеѓу преработките: Означете ги преработките што сакате да ги споредите и притиснете на Enter или копчето на дното од страницата.<br />\nЛегенда: '''({{int:cur}})''' = разлика со последна преработка, '''({{int:last}})''' = разлика со претходна преработка, '''{{int:minoreditletter}}''' = ситна промена.",
-       "history-fieldset-title": "Ð\9fÑ\80ебарај преработки",
+       "history-fieldset-title": "ФилÑ\82Ñ\80ирај преработки",
        "history-show-deleted": "Само избришани преработки",
        "histfirst": "најстари",
        "histlast": "најнови",
        "historysize": "({{PLURAL:$1|1 бајт|$1 бајти}})",
-       "historyempty": "(празно)",
+       "historyempty": "празно",
        "history-feed-title": "Историја на измените",
        "history-feed-description": "Историја на измените на оваа страница на викито",
        "history-feed-item-nocomment": "$1 на $2",
        "revdelete-suppress": "Притајувај податоци и од администраторите",
        "revdelete-unsuppress": "Отстрани ограничувања на обновени преработки",
        "revdelete-log": "Причина:",
-       "revdelete-submit": "Ð\9fÑ\80имени Ð²Ñ\80з {{PLURAL:$1|одбÑ\80ана Ð¿Ñ\80еÑ\80абоÑ\82ка|одбÑ\80ани преработки}}",
+       "revdelete-submit": "Ð\9fÑ\80имени Ð²Ñ\80з {{PLURAL:$1|избÑ\80анаÑ\82а Ð¿Ñ\80еÑ\80абоÑ\82ка|избÑ\80аниÑ\82е преработки}}",
        "revdelete-success": "Видливоста на преработката е изменета.",
        "revdelete-failure": "'''Видливоста на преработката не можеше да се измени:'''\n$1",
-       "logdelete-success": "Ð\94невникоÑ\82 Ð½Ð° Ð²Ð¸Ð´Ð»Ð¸Ð²Ð¾Ñ\81Ñ\82 Ðµ Ð¿Ð¾Ñ\81Ñ\82авен.",
+       "logdelete-success": "Ð\92идливоÑ\81Ñ\82а Ð½Ð° Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÐ¾Ñ\82 Ðµ Ð¿Ð¾Ñ\81Ñ\82авена.",
        "logdelete-failure": "'''Дневникот на видливост не може да биде нагоден:'''\n$1",
-       "revdel-restore": "Ð\9fÑ\80омена Ð½Ð° видливост",
+       "revdel-restore": "измени видливост",
        "pagehist": "Историја на страницата",
-       "deletedhist": "Историја на бришења",
+       "deletedhist": "Избришана историја",
        "revdelete-hide-current": "Грешка при сокривањето на ставката од $2, $1: Ова е тековната преработка.\nТаа не може да се скрива.",
        "revdelete-show-no-access": "Грешка при прикажување на ставката датирана на $2, $1: оваа ставка е означена како „ограничена“.\nНемате пристап до неа.",
        "revdelete-modify-no-access": "Грешка при промена на ставката датирана на $2, $1: оваа ставка била означена како „ограничена“.\nНемате пристап до неа.",
        "diff-multi-manyusers": "({{PLURAL:$1|Не е прикажана една меѓувремена преработка направена|Не се прикажани $1 меѓувремени преработки направени}} од повеќе од $2 {{PLURAL:$2|корисник|корисници}})",
        "diff-paragraph-moved-tonew": "Пасусот е преместен. Стиснете за да прејдете на новото место.",
        "diff-paragraph-moved-toold": "Пасусот е преместен. Стиснете за да прејдете на старото место.",
-       "difference-missing-revision": "Не пронајдов {{PLURAL:$2|една преработка|$2 преработки}} од оваа разлика ($1).\n\nОва обично се должи на застарена врска за разлики што води кон избришана страница.\nПовеќе подробности ќе најдете во [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} дневникот на бришења].",
+       "difference-missing-revision": "{{PLURAL:$2|Не е пронајдена|Не се пронајдени}} {{PLURAL:$2|една преработка|$2 преработки}} од оваа разлика ($1).\n\nОва обично се должи на застарена врска за разлики што води кон избришана страница.\nПовеќе подробности ќе најдете во [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} дневникот на бришења].",
        "searchresults": "Исход од пребарувањето",
        "search-filter-title-prefix": "Пребарување по страници чиј наслов почнува со „$1“",
        "search-filter-title-prefix-reset": "Пребарај по сите страници",
        "prefs-custom-json": "Прилагоден JSON",
        "prefs-custom-js": "Посебно JS",
        "prefs-common-config": "Заеднички CSS/JSON/JavaScript за сите рува:",
-       "prefs-reset-intro": "Може да ја користите оваа страница за враќање на вашите нагодувања на основно-зададените нагодувања на викито. Ова дејство е неповратно.",
+       "prefs-reset-intro": "Може да ја користите оваа страница за враќање на вашите нагодувања на стандардните нагодувања на мрежното место.\nОва дејство е неповратно.",
        "prefs-emailconfirm-label": "Потврда на е-пошта:",
        "youremail": "Е-пошта:",
        "username": "{{GENDER:$1|Корисничко име}}:",
        "right-suppressredirect": "Не прави пренасочување од старото име при преместување на страница",
        "right-upload": "Подигни податотеки",
        "right-reupload": "Заменување на постоечки податотеки",
-       "right-reupload-own": "Преснимување на постоечка податотека подигната од вас",
+       "right-reupload-own": "Презапишување врз постоечка податотека подигната од вас",
        "right-reupload-shared": "Презапис на едни податотеки врз други на заедничкото мултимедијално складиште месно",
        "right-upload_by_url": "Подигање на податотека од URL-адреса",
-       "right-purge": "Ð\91Ñ\80иÑ\88еÑ\9aе Ð¾Ð´ Ð¾Ð¿Ñ\81лÑ\83жÑ\83ваÑ\87ки Ð¼ÐµÑ\93Ñ\83Ñ\81клад Ð½Ð° Ñ\81Ñ\82Ñ\80аниÑ\86аÑ\82а Ð±ÐµÐ· Ð±Ð°Ñ\80аÑ\9aе Ð¿Ð¾Ñ\82вÑ\80да Ð·Ð° Ñ\82оа",
+       "right-purge": "Ð\91Ñ\80иÑ\88еÑ\9aе Ð½Ð° Ð¼ÐµÑ\93Ñ\83Ñ\81клад Ð½Ð° Ñ\81Ñ\82Ñ\80аниÑ\86а",
        "right-autoconfirmed": "Без ограничувања на стапки за IP-адреса",
        "right-bot": "Третиран како автоматски процес",
        "right-nominornewtalk": "Ситните уредувања на разговорни страници да не поттикнуваат потсетник за нова порака",
        "right-block": "Оневозможување на останати корисници да уредуваат",
        "right-blockemail": "Оневозможување корисници да праќаат е-пошта",
        "right-hideuser": "Блокирање корисници, сокривање од јавноста",
-       "right-ipblock-exempt": "Заобиколување на IP блокирања, авто-блокирања и блокирања на IP рангови",
+       "right-ipblock-exempt": "Заобиколување на IP-блокови, автоблокови и опсежни блокови",
        "right-unblockself": "Сопствено одблокирање",
        "right-protect": "Менување на степени на заштита и уредување на каскадно заштитени страници",
        "right-editprotected": "Уредување на страници заштитени како „{{int:protect-level-sysop}}“",
        "right-editsemiprotected": "Уредување на страници заштитени како „{{int:protect-level-autoconfirmed}}“",
        "right-editcontentmodel": "Уредување на содржинскиот модел на страница",
-       "right-editinterface": "Уредување на кориснички посредник",
-       "right-editusercss": "Уредување на CSS податотеки на други корисници",
+       "right-editinterface": "Уредување на корисничкиот посредник",
+       "right-editusercss": "Уредување на CSS-податотеки на други корисници",
        "right-edituserjson": "Уредување на JSON-податотеките на други корисници",
-       "right-edituserjs": "Уредување на JavaScript податотеки на други корисници",
+       "right-edituserjs": "Уредување на JavaScript-податотеки на други корисници",
        "right-editsitecss": "Уредување на CSS за цело вики",
        "right-editsitejson": "Уредување на JSON за цело вики",
        "right-editsitejs": "Уредување на JavaScript за цело вики",
-       "right-editmyusercss": "Уредување на сопствени кориснички каскадни стилски податотеки (CSS)",
+       "right-editmyusercss": "Уредување на сопствените кориснички каскадни стилски податотеки (CSS)",
        "right-editmyuserjson": "Уредување на сопствените кориснички JSON-податотеки",
-       "right-editmyuserjs": "Уредување на сопствени кориснички податотеки со JavaScript",
+       "right-editmyuserjs": "Уредување на сопствените кориснички податотеки со JavaScript",
        "right-viewmywatchlist": "Преглед на вашиот список на набљудувања",
        "right-editmywatchlist": "Уредување на вашите набљудувани. Извесни дејства сепак ќе ставаат страници во нив и без да го имате ова право.",
        "right-viewmyprivateinfo": "Преглед на сопствените лични податоци (на пр. е-пошта, вистинско име и презиме)",
        "grant-group-private-information": "Пристап до лични податоци за вас",
        "grant-group-other": "Разни активности",
        "grant-blockusers": "Блокирање и одблокирање корисници",
-       "grant-createaccount": "Ð\9fÑ\80авење сметки",
+       "grant-createaccount": "Создавање сметки",
        "grant-createeditmovepage": "Создавање, уредување и преместување страници",
        "grant-delete": "Бришење страници, преработки и дневнички записи",
        "grant-editinterface": "Уредување на именскиот простор „МедијаВики“ и JSON за цело вики/за корисник",
        "grant-editmycssjs": "Уредување на вашиот кориснички CSS/JSON/JavaScript",
-       "grant-editmyoptions": "Уредување на вашите кориснички нагодувања и поставеноста на JSON",
+       "grant-editmyoptions": "Уредување на вашите кориснички нагодувања и JSON-конфигурацијата",
        "grant-editmywatchlist": "Уредување на вашите набљудувани",
        "grant-editsiteconfig": "Уредување на CSS/JS за цело вики и за корисник",
        "grant-editpage": "Менување постоечки страници",
        "action-move-subpages": "преместување на оваа страница и нејзините потстраници",
        "action-move-rootuserpages": "преместување на основна корисничка страница",
        "action-move-categorypages": "преместување на категориски страници",
-       "action-movefile": "премести ја оваа податотека",
+       "action-movefile": "преместување на оваа податотека",
        "action-upload": "подигни ја податотекава",
        "action-reupload": "заменување на оваа постоечка податотека",
        "action-reupload-shared": "заменување на оваа податотека на заедничко складиште",
        "action-undelete": "обнова на страници",
        "action-suppressrevision": "преглед ја и обнова на скриени преработки",
        "action-suppressionlog": "преглед на овој личен дневник",
-       "action-block": "оневозможÑ\83ваÑ\9aе Ð½Ð° Ñ\83Ñ\80едÑ\83ваÑ\9aеÑ\82о Ð½Ð° ÐºÐ¾Ñ\80иÑ\81ников",
+       "action-block": "блокиÑ\80аÑ\9aе Ð½Ð° Ñ\83Ñ\80едÑ\83ваÑ\9aеÑ\82о Ð½Ð° Ð¾Ð²Ð¾Ñ\98 ÐºÐ¾Ñ\80иÑ\81ник",
        "action-protect": "измени го степенот на заштита на оваа страница",
        "action-rollback": "брзо отповикување на измени направени од последниот уредник на страницата",
        "action-import": "увоз на страници од друго вики",
        "action-changetags": "додавање и отстранување на произволни ознаки во поединечни преработки и дневнички записи",
        "action-deletechangetags": "бришење ознаки од базата",
        "action-purge": "превчитување на оваа страница",
+       "action-apihighlimits": "користење на помалку ограничени барања од извршникот",
+       "action-autoconfirmed": "без ограничувања на стапки за IP-адреса",
+       "action-bigdelete": "бришење на страници со долга историја",
+       "action-blockemail": "оневозможување корисници да праќаат е-пошта",
+       "action-bot": "бидете третирани како автоматски процес",
+       "action-editprotected": "уредување на страници заштитени како „{{int:protect-level-sysop}}“",
+       "action-editsemiprotected": "уредување на страници заштитени како „{{int:protect-level-autoconfirmed}}“",
+       "action-editinterface": "уредување на корисничкиот посредник",
+       "action-editusercss": "уредување на CSS-податотеки на други корисници",
+       "action-edituserjson": "уредување на JSON-податотеките на други корисници",
+       "action-edituserjs": "уредување на JavaScript-податотеки на други корисници",
+       "action-editsitecss": "уредување на CSS за цело вики",
+       "action-editsitejson": "уредување на JSON за цело вики",
+       "action-editsitejs": "уредување на JavaScript за цело вики",
+       "action-editmyusercss": "уредување на сопствените кориснички каскадни стилски податотеки (CSS)",
+       "action-editmyuserjson": "уредување на сопствените кориснички JSON-податотеки",
+       "action-editmyuserjs": "уредување на сопствените кориснички податотеки со JavaScript",
+       "action-viewsuppressed": "преглед на преработки скриени од било кој корисник",
+       "action-hideuser": "блокирање корисници, сокривање од јавноста",
+       "action-ipblock-exempt": "заобиколување на IP-блокови, автоблокови и опсежни блокови",
+       "action-unblockself": "блокирање на самите себеси",
+       "action-noratelimit": "да не бидете засегнати од временски ограничувања на уредување",
+       "action-reupload-own": "презапишување врз постоечка податотека подигната од вас",
+       "action-nominornewtalk": "ситните уредувања на разговорни страници да не поттикнуваат потсетник за нова порака",
+       "action-markbotedits": "означување на вратени уредувања како ботовски уредувања",
+       "action-patrolmarks": "преглед на одбележаните патролирања на скорешните промени",
+       "action-override-export-depth": "извезување на страници вклучувајќи поврзани страници со продорност до 5",
+       "action-suppressredirect": "не се прави пренасочување од старото име при преместување на страница",
        "nchanges": "$1 {{PLURAL:$1|промена|промени}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|од последната посаета}}",
        "enhancedrc-history": "историја",
        "rcfilters-savedqueries-already-saved": "Овие филтри се веќе зачувани. Сменете ги поставките за да направите нов зачуван филтер.",
        "rcfilters-restore-default-filters": "Поврати основни филтри",
        "rcfilters-clear-all-filters": "Тргни ги сите филтри",
-       "rcfilters-show-new-changes": "Ð\9fогл. Ð½Ð°Ñ\98нови Ð¿Ñ\80омени",
-       "rcfilters-search-placeholder": "Филтрирање на промени (со менито или пребарајте назив на филтер)",
+       "rcfilters-show-new-changes": "Ð\9fогл. Ð½Ð¾Ð²Ð¸ Ð¿Ñ\80омени Ð¾Ð´ $1 Ð½Ð°Ð²Ð°Ð¼Ñ\83",
+       "rcfilters-search-placeholder": "Филтрирање на промени (користете го менито или пребарајте назив на филтер)",
        "rcfilters-invalid-filter": "Неважечки филтер",
        "rcfilters-empty-filter": "Нема активни филтри. Прикажани се сите придонеси.",
        "rcfilters-filterlist-title": "Филтри",
        "rcfilters-filter-editsbyself-description": "Ваши сопствени придонеси.",
        "rcfilters-filter-editsbyother-label": "Туѓи промени",
        "rcfilters-filter-editsbyother-description": "Сите промени направени од други уредници",
-       "rcfilters-filtergroup-userExpLevel": "Корисничка регистрација и искусност",
+       "rcfilters-filtergroup-user-experience-level": "Корисничка регистрација и искусност",
        "rcfilters-filter-user-experience-level-registered-label": "Регистрирани",
        "rcfilters-filter-user-experience-level-registered-description": "Најавени уредници.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Нерегистрирани",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Филтерот „Ситни уредувања“ е спротиставен на еден или повеќе од филтрите за видови измена, бидејќи извеси видови не можат да се означат како ситни. Спротиставените филтри се означени во делот Неактивни филтри погоре.",
        "rcfilters-hideminor-conflicts-typeofchange": "Извезни видови промени не можат да се означат како „ситни“, па затоа овој филтер е во спротиставеност со следниве филтри за видови промени: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Овој филтер за видови промени е во спротиставеност со филтерот „Ситни уредувања“. Извсни видови промени не можат да се означат како „ситни“.",
-       "rcfilters-filtergroup-lastRevision": "Последни преработки",
+       "rcfilters-filtergroup-lastrevision": "Последни преработки",
        "rcfilters-filter-lastrevision-label": "Последна преработка",
        "rcfilters-filter-lastrevision-description": "Само најнови преработки во страница.",
        "rcfilters-filter-previousrevision-label": "Не последната преработка",
        "minoreditletter": "с",
        "newpageletter": "Н",
        "boteditletter": "б",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|корисник што набљудува|корисници што набљудуваат}}]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|бајт|бајти}} по промената",
        "newsectionsummary": "/* $1 */ ново заглавие",
        "upload-tryagain": "Поднеси изменет опис на податотеката",
        "upload-tryagain-nostash": "Поднеси преподигната податотека и изменет опис",
        "uploadnologin": "Не сте најавени",
-       "uploadnologintext": "Ð\9cоÑ\80а Ð´Ð° Ñ\81Ñ\82е $1 Ð·Ð° Ð´Ð° Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ð¿Ð¾Ð´Ð¸Ð³Ð°Ñ\82е.",
+       "uploadnologintext": "Ð\9cоÑ\80а Ð´Ð° Ñ\81Ñ\82е $1 Ð·Ð° Ð´Ð° Ð¿Ð¾Ð´Ð¸Ð³Ð½Ñ\83ваÑ\82е Ð¿Ð¾Ð´Ð°Ñ\82оÑ\82еки.",
        "upload_directory_missing": "Папката за подигање на слики ($1) не постои и не може да биде создадена од опслужувачот.",
        "upload_directory_read_only": "Опслужувачот не може да запишува во именикот за подигање ($1).",
        "uploaderror": "Грешка во подигањето",
        "upload-preferred": "{{PLURAL:$2|Претпочитан податотечен тип|Претпочитани податотечни типови}}: $1.",
        "upload-prohibited": "{{PLURAL:$2|Недозволен податотечен тип|Недозволени податотечни типови}}: $1.",
        "uploadlogpage": "Дневник на подигања",
-       "uploadlogpagetext": "Ð\9dаведен Ðµ список на најновите подигања на податотеки.\nПогледнете ја [[Special:NewFiles|галеријата на нови податотеки]] за нагледен преглед.",
+       "uploadlogpagetext": "Ð\9fодолÑ\83 Ðµ Ð½Ð°Ð²ÐµÐ´ÐµÐ½ список на најновите подигања на податотеки.\nПогледнете ја [[Special:NewFiles|галеријата на нови податотеки]] за нагледен преглед.",
        "filename": "Име на податотеката",
        "filedesc": "Опис",
        "fileuploadsummary": "Опис:",
        "ignorewarning": "Занемари ги предупредувањата и зачувај ја податотеката",
        "ignorewarnings": "Занемари предупредувања",
        "minlength1": "Името на податотеката мора да содржи барем една буква.",
-       "illegalfilename": "Името на податотеката „$1“ содржи знаци што не се дозволени во наслови на страници.\nПреименувајте ја подигнете ја повторно.",
+       "illegalfilename": "Ð\98меÑ\82о Ð½Ð° Ð¿Ð¾Ð´Ð°Ñ\82оÑ\82екаÑ\82а â\80\9e$1â\80\9c Ñ\81одÑ\80жи Ð·Ð½Ð°Ñ\86и Ñ\88Ñ\82о Ð½Ðµ Ñ\81е Ð´Ð¾Ð·Ð²Ð¾Ð»ÐµÐ½Ð¸ Ð²Ð¾ Ð½Ð°Ñ\81лови Ð½Ð° Ñ\81Ñ\82Ñ\80аниÑ\86и.\nÐ\9fÑ\80еименÑ\83ваÑ\98Ñ\82е Ñ\98а Ð¿Ð¾Ð´Ð°Ñ\82оÑ\82екаÑ\82а Ð¸ Ð¿Ð¾Ð´Ð¸Ð³Ð½ÐµÑ\82е Ñ\98а Ð¿Ð¾Ð²Ñ\82оÑ\80но.",
        "filename-toolong": "Имињата на податотеките не смеат да бидат подолги од 240 бајти.",
        "badfilename": "Името на податотеката е променето во „$1“.",
        "filetype-mime-mismatch": "Податотечната наставка „.$1“ не одговара на утврдениот MIME-тип на податотеката ($2).",
        "windows-nonascii-filename": "Опслужувачот не поддржува податотечни имиња со псоебни знаци.",
        "fileexists": "Податотека со ова име веќе постои. Проверете <strong>[[:$1]]</strong> ако не {{GENDER:|сте}} сигурни дали сакате да ја промените.\n[[$1|thumb]]",
        "filepageexists": "Описната страница на оваа податотека е веќе создадена на <strong>[[:$1]]</strong>, но не постои податотека со тоа име.\nОписот кој го внесовте нема да стои на описната страница.\nДоколку сакате описот да стои тука, ќе морате да го уредите рачно.\n[[$1|thumb]]",
-       "fileexists-extension": "Податотека со слично име веќе постои: [[$2|thumb]]\n* Име на податотека која се подигнува: <strong>[[:$1]]</strong>\n* Име на постоечката податотека: <strong>[[:$2]]</strong>\nДали можеби би сакале да користите покарактеристично име.",
+       "fileexists-extension": "Податотека со слично име веќе постои: [[$2|thumb]]\n* Име на податотека која се подигнува: <strong>[[:$1]]</strong>\n* Име на постоечката податотека: <strong>[[:$2]]</strong>\nДали можеби би сакале да користите покарактеристично име?",
        "fileexists-thumbnail-yes": "Се чини дека податотеката е слика со намалена големина ''(минијатура)''. [[$1|thumb]]\nПроверете ја податотеката <strong>[[:$1]]</strong>.\nАко податотеката која ја проверувате е истата слика во својата изворна големина тогаш не мора да ја подигате дополнително.",
        "file-thumbnail-no": "Името на податотеката почнува со <strong>$1</strong>.\nИзгледа дека е слика со намалена големина ''(мини, thumbnail)''.\nАко ја имате оваа слика во изворна големина, подигнете ја неја. Во спротивно сменете го името на податотеката.",
        "fileexists-forbidden": "Податотека со тоа име веќе постои и не може да биде заменета.\nАко и понатаму сакате да ја подигнете вашата податотеката, ве молиме вратете се назад и подигнете ја под друго име. [[File:$1|thumb|center|$1]]",
        "upload-form-label-own-work": "Ова е мое дело",
        "upload-form-label-infoform-categories": "Категории",
        "upload-form-label-infoform-date": "Датум",
-       "upload-form-label-own-work-message-generic-local": "Потврдувам дека податотекава ја подигам во согласност со условите на користење и правилата за лиценцирање на {{SITENAME}}.",
+       "upload-form-label-own-work-message-generic-local": "Потврдувам дека ја подигам податотекава во согласност со условите на користење и правилата за лиценцирање на {{SITENAME}}.",
        "upload-form-label-not-own-work-message-generic-local": "Ако не сте во можност да ја подигнете податотекава согласно правилата на {{SITENAME}}, затворете го дијалогов и обидете се на друг начин.",
        "upload-form-label-not-own-work-local-generic-local": "Можете да ја пробате и [[Special:Upload|стандардната страница за подигање]].",
        "upload-form-label-own-work-message-generic-foreign": "Разбирам дека ја подигам податотекава на заедничко складиште. Потврдувам дека со тоа ги почитувам тамошните услови на користење и лиценцните правила.",
        "img-auth-nopathinfo": "Недостасува информација за патеката.\nВашиот опслужувач мора да е наместен да ги дава променливите REQUEST_URI и/или PATH_INFO.\nАко е веќе наместен, овозможете го $wgUsePathInfo.\nПогл. https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Бараниот пат не води кон зададената папка за подигање.",
        "img-auth-badtitle": "Не може да се конструира важечки наслов од „$1“.",
-       "img-auth-nologinnWL": "Не сте најавени и „$1“ не е на списокот на допуштени.",
        "img-auth-nofile": "Податотеката „$1“ не постои.",
        "img-auth-isdir": "Се обидувате да пристапите до именикот „$1“.\nДопуштен е само податотечен пристап.",
        "img-auth-streaming": "Емитување на „$1“.",
        "uncategorizedtemplates": "Некатегоризирани преуредувања",
        "uncategorized-categories-exceptionlist": " # Содржи список на категории кои не треба да се споменуваат во Special:UncategorizedCategories. По една во секој нов ред што почнува со „*“. Редовите што почнуваат со друг знак (заклучно со празни места) ќе се занемарат. Користете „#“ за прибелешки.",
        "unusedcategories": "Неискористени категории",
-       "unusedimages": "Неискористени слики",
+       "unusedimages": "Неискористени податотеки",
        "wantedcategories": "Потребни категории",
        "wantedpages": "Потребни страници",
        "wantedpages-summary": "Список на непостоечки страници со највеќе врски што водат до нив, исклучувајќи страниците до кои водат само пренасочувања. Список на непостоечки страници до кои водат пренасочувања ќе најдете на [[{{#special:BrokenRedirects}}|списокот на прекинати пренасочувања]].",
        "apisandbox-dynamic-parameters": "Дополнителни параметри",
        "apisandbox-dynamic-parameters-add-label": "Додај параметар:",
        "apisandbox-dynamic-parameters-add-placeholder": "Назив на параметарот",
-       "apisandbox-dynamic-error-exists": "Праметарот по име „$1“ веќе постои.",
+       "apisandbox-dynamic-error-exists": "Параметар по име „$1“ веќе постои.",
        "apisandbox-templated-parameter-reason": "Овој [[Special:ApiHelp/main#main/templatedparams|шаблонизиран параметар]] се нуди според {{PLURAL:$1|вредноста|вредностите}} на $2.",
        "apisandbox-deprecated-parameters": "Застарени параметри",
        "apisandbox-fetch-token": "Самопополни ја шифрата",
        "notanarticle": "Не е статија",
        "notvisiblerev": "Преработката била избришана",
        "watchlist-details": "Во вашите набљудувани имате {{PLURAL:$1|$1 страница|$1 страници}} (не броејќи ги разговорните страници).",
-       "wlheader-enotif": "Ð\98звеÑ\81Ñ\82Ñ\83ваÑ\9aеÑ\82о Ð¿Ð¾ Ðµ-поÑ\88Ñ\82а Ðµ Ð²ÐºÐ»Ñ\83Ñ\87ено.",
+       "wlheader-enotif": "Ð\98звеÑ\81Ñ\82Ñ\83ваÑ\9aеÑ\82о Ð¿Ð¾ Ðµ-поÑ\88Ñ\82а Ðµ Ð¾Ð²Ð¾Ð·Ð¼Ð¾Ð¶ено.",
        "wlheader-showupdated": "Страниците кои се променети од вашата последна посета се прикажани со <strong>задебелени</strong> букви.",
        "wlnote": "Подолу {{PLURAL:$1|е прикажана последната промена|се прикажани последните <strong>$1</strong> промени}} во {{PLURAL:$2|последниов час|последниве <strong>$2</strong> часа}}, заклучно со $3, $4 ч.",
-       "wlshowlast": "Прикажи ги последните $1 часа, $2 дена,",
+       "wlshowlast": "Прикажи ги последните $1 часа, $2 дена",
        "watchlist-hide": "Скриј",
        "watchlist-submit": "Прикажи",
        "wlshowtime": "Период за приказ:",
        "delete-confirm": "Бришење на „$1“",
        "delete-legend": "Бришење",
        "historywarning": "<strong>Предупредување:</strong> Страницата што сакате да ја избришете има историја со {{PLURAL:$1|една преработка|$1 преработки}}:",
-       "historyaction-submit": "Прикажи",
+       "historyaction-submit": "Прикажи преработки",
        "confirmdeletetext": "На пат сте трајно да избришете страница заедно со нејзината историја.\nПотврдете дека имате намера да го направите ова, дека ги разбирате последиците од тоа и дека го правите во согласност со [[{{MediaWiki:Policy-url}}|правилата]].",
        "actioncomplete": "Дејството е извршено",
        "actionfailed": "Неуспешно дејство",
        "deleting-backlinks-warning": "<strong>Предупредување:</strong>  До страницата што сакате да ја избришете водат [[Special:WhatLinksHere/{{FULLPAGENAME}}|други страници]] или пак се превметнуваат во неа.",
        "deleting-subpages-warning": "<strong>Предупредување:</strong> Страницата што сакате да ја избришете има [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|потстраница|$1 потстраници|51=преку 50 потстраници}}]].",
        "rollback": "Отповикај промени",
+       "rollback-confirmation-confirm": "Потврдете:",
+       "rollback-confirmation-yes": "Отповикај",
+       "rollback-confirmation-no": "Откажи",
        "rollbacklink": "отповикај",
        "rollbacklinkcount": "отповикај $1 {{PLURAL:$1|уредување|уредувања}}",
        "rollbacklinkcount-morethan": "отповикај повеќе од $1 {{PLURAL:$1|уредување|уредувања}}",
        "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-notify": "Откажани уредувањата на $1;\nвратено на последната преработка на $2. [$3 Пок. промени]",
        "sessionfailure-title": "Седницата не успеа",
        "sessionfailure": "Се јави проблем со најавната седница;\nова дејство е откажано за да се спречи нејзина кражба.\nПоднесете го образецот повторно.",
        "changecontentmodel": "Промена на содржинскиот модел на страница",
        "undeletepagetext": "{{PLURAL:$1|Следната страница била избришана но сè уште е во архивот и може да биде вратена.|Следните $1 страници биле избришани но сè уште се во архивот и можат да бидат вратени.}}\nАрхивот може периодично да се чисти.",
        "undelete-fieldset-title": "Врати преработки",
        "undeleteextrahelp": "За да вратите целосна историја на една страница, отштиклирајте ги сите полиња и притиснете на „'''{{int:undeletebtn}}'''“.\nЗа да извршите делумно враќање, штиклирајте ги соодветните преработки за враќање и притиснете на „'''{{int:undeletebtn}}'''“.",
-       "undeleterevisions": "{{PLURAL:$1|Избришана една преработка|Избришани $1 преработки}}",
+       "undeleterevisions": "$1 {{PLURAL:$1|преработка е избришана|преработки се избришани}}",
        "undeletehistory": "Ако ја обновите страницата, сите преработки ќе бидат вратени во историјата.\nАко нова страница со исто име е создадена по бришењето, обновените преработки ќе се појават во претходната историја.",
        "undeleterevdel": "Избришаното нема да биде вратено ако тоа значи дека со тоа најгорната страница или преработката на податотеката делумно ќе се избрише.\nВо такви случаи, морате да ја отштиклирате или откриете (ако е скриена) најновата избришана преработка.",
        "undeletehistorynoadmin": "Оваа статија е избришана. Причината за бришењето е наведена подолу,\nзаедно со информации за корисникот кој ја уредувал страницата пред бришењето. Целиот текст\nод избришаните верзии е достапен само за администраторите.",
        "mycontris": "придонеси",
        "anoncontribs": "Придонеси",
        "contribsub2": "За {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "За {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "Корисничката сметка „$1“ не е регистрирана.",
        "negative-namespace-not-supported": "Не се поддржани именски простори со негативни вредности.",
        "nocontribs": "Не се пронајдени промени што одговараат на овој критериум.",
        "block-prevent-edit": "Уредување",
        "block-reason": "Причина:",
        "block-target": "Корисничко име или IP-адреса:",
-       "unblockip": "Ð\94еблокирај корисник",
+       "unblockip": "Ð\9eдблокирај корисник",
        "unblockiptext": "Користете го долниот образец да го вратите правото на пишување на претходно блокирана IP-адреса или корисничко име.",
        "ipusubmit": "Избриши го ова блокирање",
        "unblocked": "[[User:$1|$1]] беше деблокиран",
        "blocklist-userblocks": "Скриј блокирања на корис. сметки",
        "blocklist-tempblocks": "Скриј привремени блокирања",
        "blocklist-addressblocks": "Скри блокирања на поединечни IP-адреси",
+       "blocklist-type": "Вид:",
+       "blocklist-type-opt-all": "Сите",
+       "blocklist-type-opt-sitewide": "Насекаде",
+       "blocklist-type-opt-partial": "Делумно",
        "blocklist-rangeblocks": "Скриј опсежни блокови",
        "blocklist-timestamp": "Време и датум",
        "blocklist-target": "Цел",
        "blocklist-editing-page": "страници",
        "blocklist-editing-ns": "именски простори",
        "ipblocklist-empty": "Списокот на блокирања е празен.",
-       "ipblocklist-no-results": "Ð\91аÑ\80анаÑ\82а IP-адÑ\80еÑ\81а Ð¸Ð»Ð¸ ÐºÐ¾Ñ\80иÑ\81ниÑ\87ка Ñ\81меÑ\82ка Ð½Ðµ Ðµ Ð±Ð»Ð¾ÐºÐ¸Ñ\80ана.",
+       "ipblocklist-no-results": "Ð\9dе Ð½Ð°Ñ\98дов Ñ\82акви Ð±Ð»Ð¾ÐºÐ¾Ð²Ð¸ Ð½Ð° Ð¿Ð¾Ð±Ð°Ñ\80анаÑ\82а IP-адÑ\80еÑ\81а Ð¸Ð»Ð¸ ÐºÐ¾Ñ\80иÑ\81ниÑ\87ко Ð¸Ð¼Ðµ.",
        "blocklink": "блокирај",
        "unblocklink": "одблокирај",
        "change-blocklink": "промена на блок",
+       "empty-username": "(недостапно корисничко име)",
        "contribslink": "придонеси",
        "emaillink": "испрати е-пошта",
        "autoblocker": "Автоматски сте блокирани бидејќи вашата IP-адреса била скоро користена од „[[User:$1|$1]]“.\nНаведената причина за блокирање на $1 гласи: „$2“",
        "proxyblocker": "Блокер на застапници (proxy)",
        "proxyblockreason": "Вашата IP-адреса е блокирана бидејќи претставува отворен застапник (proxy).\nВе молиме контактирајте со вашиот семрежен услужник и или техничката поддршка и информирајте ги за овој сериозен безбедносен проблем.",
        "sorbs": "DNSBL",
-       "sorbsreason": "Вашата IP-адреса е запишана како отворен застапник (proxy) во DNSBL кој го користи {{SITENAME}}..",
+       "sorbsreason": "Вашата IP-адреса е запишана како отворен застапник (прокси) во DNSBL кој го користи {{SITENAME}}.",
        "sorbs_create_account_reason": "Вашата IP-адреса е наведена како отворен застапник (прокси) во DNSBL користена од {{SITENAME}}.\nНе можете да создадете корисничка сметка.",
        "softblockrangesreason": "Анонимните придонеси не се дозволени од вашата IP-адреса ($1). Најавете се.",
        "xffblockreason": "Блокирана е IP-адреса присутна во заглавието X-Forwarded-For, која е ваша или на застапничкиот опслужувач што го користите. Наведеното образложение гласи: $1",
        "allmessagesdefault": "Текст по основно",
        "allmessagescurrent": "Сегашен текст",
        "allmessagestext": "Ова е список на системските пораки расположиви за именскиот простор „МедијаВики“.\nОдете на [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Превод на МедијаВики] и [https://translatewiki.net translatewiki.net] ако сакате да придонесете кон општото преведување на МедијаВики.",
-       "allmessagesnotsupportedDB": "Оваа страница не може да се користи бидејќи '''$wgUseDatabaseMessages''' е исклучено.",
+       "allmessages-not-supported-database": "Оваа страница не може да се користи бидејќи '''$wgUseDatabaseMessages''' е исклучено.",
        "allmessages-filter-legend": "Филтер",
        "allmessages-filter": "Филтрирај по состојба на прилагодувањето:",
        "allmessages-filter-unmodified": "Неизменети",
        "pageinfo-category-files": "Број на податотеки",
        "pageinfo-user-id": "Корисничка назнака",
        "pageinfo-file-hash": "Тарабна вредност",
-       "pageinfo-view-protect-log": "Погл. го дневникот на заштити за страницава.",
+       "pageinfo-view-protect-log": "Преглед на дневникот на заштити за страницава.",
        "markaspatrolleddiff": "Означи како проверена верзија",
        "markaspatrolledtext": "Означи ја верзијата како проверена",
        "markaspatrolledtext-file": "Означи ја верзијава како испатролирана",
        "scarytranscludefailed-httpstatus": "[Преземањето на шаблонот не успеа за $1: HTTP $2]",
        "scarytranscludetoolong": "[Премногу долго URL]",
        "deletedwhileediting": "'''Предупредување''': Оваа страница беше избришана откако почнавте со нејзино уредување!",
-       "confirmrecreate": "Корисникот [[User:$1|$1]] ([[User talk:$1|разговор]]) {{GENDER:$1|ја избриша}} страницава откако вие почнавте со уредување, со причината:\n: ''$2''\nПотврдете дека навистина сакате да ја пресоздадете страницата.",
+       "confirmrecreate": "Корисникот [[User:$1|$1]] ([[User talk:$1|разговор]]) ја {{GENDER:$1|избриша}} страницава откако вие почнавте со уредување, со причината:\n: <em>$2</em>\nПотврдете дека навистина сакате да ја пресоздадете оваа страница.{{GENDER:$1|}}",
        "confirmrecreate-noreason": "Корисникот [[User:$1|$1]] ([[User talk:$1|разговор]]) {{GENDER:$1|ја избриша}} страницава откако почнавте да ја уредувате.  Потврдете дека навистина сакате да ја пресоздадете страницата.",
        "recreate": "Пресоздај",
        "unit-pixel": "п",
        "confirm-unwatch-top": "Да ја отстранам страницава од набљудуваните?",
        "confirm-rollback-button": "ОК",
        "confirm-rollback-top": "Да ги отповикам уредувањата на страницава?",
+       "confirm-rollback-bottom": "Ова дејство веднаш ќе ги отповика избраните промени на страницава.",
        "confirm-mcrrestore-title": "Поврати преработка",
        "confirm-mcrundo-title": "Откажи промена",
        "mcrundofailed": "Откажувањето не успеа",
        "version-variables": "Променливи",
        "version-editors": "Уредници",
        "version-antispam": "Спречување на спам",
-       "version-api": "Ð\98звÑ\80Ñ\88ниÑ\86и",
+       "version-api": "Ð\9fÑ\80иложник",
        "version-other": "Друго",
        "version-mediahandlers": "Ракувачи со мултимедијални содржини",
        "version-hooks": "Пресретник",
        "tags-deactivate-question": "На пат сте да ја деактивирате ознаката „$1“.",
        "tags-deactivate-reason": "Причина:",
        "tags-deactivate-not-allowed": "Не можам да ја деактивирам ознаката „$1“.",
-       "tags-deactivate-submit": "Ð\94екативирај",
+       "tags-deactivate-submit": "Ð\94еактивирај",
        "tags-apply-no-permission": "Немате дозвола да ставате ознаки за промени заедно со измените што ги правите.",
        "tags-apply-blocked": "Не можете да задавате ознаки за промени додека {{GENDER:$1|сте}} блокирани.",
        "tags-apply-not-allowed-one": "Не е дозволено ознаката „$1“ да се става рачно.",
        "tags-edit-manage-link": "Раководство со ознаки",
        "tags-edit-revision-selected": "{{PLURAL:$1|Одбрана преработка|Одбрани преработки}} на [[:$2]]:",
        "tags-edit-logentry-selected": "{{PLURAL:$1|Одбран настан од дневник|Одбрани настани од дневник}}:",
-       "tags-edit-revision-legend": "Ð\94одаÑ\98Ñ\82е Ð¸Ð»Ð¸ Ð¾Ñ\82Ñ\81Ñ\82Ñ\80анеÑ\82е Ð¾Ð·Ð½Ð°ÐºÐ¸ Ð¾Ð´ {{PLURAL:$1|пÑ\80еÑ\80абоÑ\82кава|сите $1 преработки}}",
+       "tags-edit-revision-legend": "Ð\94одаÑ\98Ñ\82е Ð¸Ð»Ð¸ Ð¾Ñ\82Ñ\81Ñ\82Ñ\80анеÑ\82е Ð¾Ð·Ð½Ð°ÐºÐ¸ Ð¾Ð´ {{PLURAL:$1|оваа Ð¿Ñ\80еÑ\80абоÑ\82ка|сите $1 преработки}}",
        "tags-edit-logentry-legend": "Додајте или отстранете ознаки од {{PLURAL:$1|овој дневнички запис|сите $1 дневнички записи}}",
        "tags-edit-existing-tags": "Постоечки ознаки",
        "tags-edit-existing-tags-none": "<em>Нема</em>",
        "tags-edit-new-tags": "Нови ознаки:",
-       "tags-edit-add": "Додај ги следниве ознаки:",
-       "tags-edit-remove": "Отстрани ги следниве ознаки:",
+       "tags-edit-add": "Додај ги овие ознаки:",
+       "tags-edit-remove": "Отстрани ги овие ознаки:",
        "tags-edit-remove-all-tags": "(отстрани ги сите ознаки)",
        "tags-edit-chosen-placeholder": "Одберете некои ознаки",
        "tags-edit-chosen-no-results": "Не пронајдов одговарачки ознаки",
        "duration-hours": "{{PLURAL:$1|еден час|$1 часа}}",
        "duration-days": "{{PLURAL:$1|еден ден|$1 дена}}",
        "duration-weeks": "$1 {{PLURAL:$1|недела|недели}}",
-       "duration-years": "{{PLURAL:$1|$1 година|$1 години}}",
+       "duration-years": "$1 {{PLURAL:$1|година|години}}",
        "duration-decades": "$1 {{PLURAL:$1|деценија|децении}}",
        "duration-centuries": "$1 {{PLURAL:$1|век|века}}",
        "duration-millennia": "$1 {{PLURAL:$1|милениум|милениуми}}",
        "mediastatistics-summary": "Статистики за подигнати типови податотеки. Се зема предвид само последната верзија на податотеката. Старите и избришаните верзии не се бројат.",
        "mediastatistics-nfiles": "$1 ($2 %)",
        "mediastatistics-nbytes": "{{PLURAL:$1|Еден бајт|$1 бајти}} ($2; $3%)",
-       "mediastatistics-bytespertype": "Ð\92кÑ\83пен Ð¾Ð±ÐµÐ¼ Ð½Ð° Ð¿Ð°Ñ\81Ñ\83Ñ\81от: {{PLURAL:$1|$1 бајт|$1 бајти}} ($2; $3%).",
+       "mediastatistics-bytespertype": "Ð\92кÑ\83пен Ð¾Ð±ÐµÐ¼ Ð½Ð° Ð¾Ð´Ð´ÐµÐ»от: {{PLURAL:$1|$1 бајт|$1 бајти}} ($2; $3%).",
        "mediastatistics-allbytes": "Вкупен обем на сите податотеки: {{PLURAL:$1|$1 бајт|$1 бајти}} ($2).",
        "mediastatistics-table-mimetype": "MIME-тип",
        "mediastatistics-table-extensions": "Можни додатоци",
        "log-action-filter-suppress-event": "Притајување дневник",
        "log-action-filter-suppress-revision": "Притајување преработка",
        "log-action-filter-suppress-delete": "Притајување страница",
-       "log-action-filter-suppress-block": "Притајување на корисникот преку блокирање",
-       "log-action-filter-suppress-reblock": "Притајување на корисникот преку преблокирање",
+       "log-action-filter-suppress-block": "Притајување на корисник со блокирање",
+       "log-action-filter-suppress-reblock": "Притајување на корисник со повторно блокирање",
        "log-action-filter-upload-upload": "Ново подигање",
        "log-action-filter-upload-overwrite": "Преподигање",
        "log-action-filter-upload-revert": "Отповикај",
        "authprovider-confirmlink-request-label": "Сметки кои треба да се поврзат",
        "authprovider-confirmlink-success-line": "$1: Успешно поврзано.",
        "authprovider-confirmlink-failed": "Поврзувањето на сметката не е целосно успешно: $1",
-       "authprovider-confirmlink-ok-help": "Ð\9fÑ\80одолжи Ð´Ð° Ð¿Ñ\80икажÑ\83ваÑ\88 пораки за неуспешно поврзување.",
+       "authprovider-confirmlink-ok-help": "Ð\9fÑ\80одолжи Ð¿Ð¾ Ð¿Ñ\80икажÑ\83ваÑ\9aеÑ\82о пораки за неуспешно поврзување.",
        "authprovider-resetpass-skip-label": "Прескокни",
        "authprovider-resetpass-skip-help": "Прескокни го задавањето на нова лозинка.",
        "authform-nosession-login": "Заверката е успешна, но вашиот прелистувач не може да „запомни“ дека сте најавени.\n\n$1",
        "gotointerwiki": "Го напуштате {{SITENAME}}",
        "gotointerwiki-invalid": "Укажаниот наслов е неважечки.",
        "gotointerwiki-external": "Го напуштате {{SITENAME}} упатени кон [[$2]], кое е посебно мрежно место.\n\n'''[$1 Продолжете кон $1]'''",
-       "undelete-cantedit": "Ð\9dе Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ñ\98а Ð²Ñ\80аÑ\82иÑ\82е Ð¸Ð·Ð±Ñ\80иÑ\88анаÑ\82а страница бидејќи уредувањето на страницава не ви е дозволено.",
+       "undelete-cantedit": "Ð\9dе Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ñ\98а Ð²Ñ\80аÑ\82иÑ\82е Ð¾Ð²Ð°а страница бидејќи уредувањето на страницава не ви е дозволено.",
        "undelete-cantcreate": "Не можете да ја вратите страницава бидејќи не постои страница со таков назив и не ви е дозволено да ја создадете.",
        "pagedata-title": "Податоци за страницата",
        "pagedata-text": "Страницава дава посредник за податоци за страниците. Укажете го насловот на страницата во URL-то, користејќи ја синтаксата за потстраници.\n* Префрлањето на содржината се заснова на заглавието Прифати на вашиот клиент. Ова значи дека податоците за страницата ќе бидат ставени во форматот кој го претпочита вашиот клиент.",
        "passwordpolicies-policyflag-forcechange": "мора да се промени при најава",
        "passwordpolicies-policyflag-suggestchangeonlogin": "предложи измена при најава",
        "easydeflate-invaliddeflate": "Содржината не е соодветно прочистена",
-       "unprotected-js": "JavaScript не може да се вчита од незаштитени страници од безбедносни причини. Создавајте JavaScript само во именскиот простор МедијаВики: или како корисничка потстраница"
+       "unprotected-js": "JavaScript не може да се вчита од незаштитени страници од безбедносни причини. Создавајте JavaScript само во именскиот простор МедијаВики: или како корисничка потстраница",
+       "userlogout-continue": "Ако сакате да се одјавите, [$1 продолжете на одјавната стрнаица].",
+       "userlogout-sessionerror": "Одјавата не успеа поради седничка грешка. [$1 Обидете се пак]."
 }
index e749618..262aeb1 100644 (file)
        "and": "&#32;ഒപ്പം",
        "faq": "പതിവുചോദ്യങ്ങൾ",
        "actions": "നടപടികൾ",
-       "namespaces": "നാമമേഖല",
+       "namespaces": "നാമമേഖലകൾ",
        "variants": "രൂപഭേദങ്ങൾ",
        "navigation-heading": "ഗമന വഴികാട്ടി",
        "errorpagetitle": "പിഴവ്",
        "history": "നാൾവഴി",
        "history_short": "നാൾവഴി",
        "history_small": "നാൾവഴി",
-       "updatedmarker": "à´\95à´´à´¿à´\9eàµ\8dà´\9e à´¸à´¨àµ\8dദർശനതàµ\8dതിനàµ\81 ശേഷം മാറ്റം വന്നത്",
+       "updatedmarker": "à´\95à´´à´¿à´\9eàµ\8dà´\9e à´¸à´¨àµ\8dദർശനതàµ\8dതിനàµ\8d ശേഷം മാറ്റം വന്നത്",
        "printableversion": "അച്ചടിരൂപം",
        "permalink": "സ്ഥിരംകണ്ണി",
        "print": "അച്ചടിയ്ക്കുക",
        "viewdeleted_short": "{{PLURAL:$1|മായ്ക്കപ്പെട്ട ഒരു തിരുത്തൽ|മായ്ക്കപ്പെട്ട $1 തിരുത്തലുകൾ}} കാണുക",
        "protect": "സം‌രക്ഷിക്കുക",
        "protect_change": "സംരക്ഷണമാനത്തിൽ മാറ്റം വരുത്തുക",
-       "unprotect": "à´¸à´\82à´°à´\95àµ\8dà´·à´£à´\82",
+       "unprotect": "à´¸à´\82à´°à´\95àµ\8dഷണതàµ\8dതിൽ à´®à´¾à´±àµ\8dà´±à´\82വരàµ\81à´¤àµ\8dà´¤àµ\81à´\95",
        "newpage": "പുതിയ താൾ",
        "talkpagelinktext": "സംവാദം",
        "specialpage": "പ്രത്യേക താൾ",
-       "personaltools": "à´¸àµ\8dà´µà´\95ാരàµ\8dയതാളàµ\81à´\95ൾ",
+       "personaltools": "à´µàµ\8dà´¯à´\95àµ\8dതിà´\97à´¤ à´\89à´ªà´\95à´°à´£à´\99àµ\8dà´\99ൾ",
        "talk": "സംവാദം",
        "views": "ദർശനീയത",
        "toolbox": "ഉപകരണങ്ങൾ",
        "versionrequired": "മീഡിയാവിക്കിയുടെ പതിപ്പ് $1 ആവശ്യമാണ്",
        "versionrequiredtext": "ഈ താൾ ഉപയോഗിക്കാൻ മീഡിയവിക്കി പതിപ്പ് $1 ആവശ്യമാണ്. കൂടുതൽ വിവരങ്ങൾക്ക് [[Special:Version|മീഡിയാവിക്കി പതിപ്പ് താൾ]] കാണുക.",
        "ok": "ശരി",
-       "retrievedfrom": "\"$1\" à´\8eà´¨àµ\8dà´¨ à´¤à´¾à´³à´¿àµ½à´¨à´¿à´¨àµ\8dà´¨àµ\81 ശേഖരിച്ചത്",
+       "retrievedfrom": "\"$1\" à´\8eà´¨àµ\8dà´¨ à´¤à´¾à´³à´¿àµ½à´¨à´¿à´¨àµ\8dà´¨àµ\8d ശേഖരിച്ചത്",
        "youhavenewmessages": "താങ്കൾക്ക് $1 ഉണ്ട് ($2).",
        "youhavenewmessagesfromusers": "താങ്കൾക്ക് {{PLURAL:$3|ഒരു ഉപയോക്താവ്|$3 ഉപയോക്താക്കൾ}} $1 ചേർത്തിട്ടുണ്ട് ($2).",
        "youhavenewmessagesmanyusers": "താങ്കൾക്ക് പലർ $1 ചേർത്തിട്ടുണ്ട് ($2).",
        "red-link-title": "$1 (ഇതുവരെ എഴുതപ്പെട്ടിട്ടില്ല)",
        "sort-descending": "അവരോഹണമായി ക്രമപ്പെടുത്തുക",
        "sort-ascending": "ആരോഹണമായി ക്രമപ്പെടുത്തുക",
-       "nstab-main": "à´²àµ\87à´\96à´¨à´\82",
+       "nstab-main": "താൾ",
        "nstab-user": "ഉപയോക്തൃതാൾ",
        "nstab-media": "മീഡിയാ താൾ",
        "nstab-special": "പ്രത്യേക താൾ",
        "userlogin-joinproject": "{{SITENAME}} സം‌രംഭത്തിൽ ചേരുക",
        "createaccount": "അംഗത്വമെടുക്കുക",
        "userlogin-resetpassword-link": "താങ്കൾ രഹസ്യവാക്ക് മറന്നോ?",
-       "userlogin-helplink2": "à´ªàµ\8dà´°à´µàµ\87ശിà´\95àµ\8dà´\95ാൻ à´¸à´¹à´¾à´¯à´®à´¾à´µà´¶àµ\8dയമàµ\86à´\99àµ\8dà´\95ിൽ",
+       "userlogin-helplink2": "à´ªàµ\8dà´°à´µàµ\87ശിà´\95àµ\8dà´\95ാനàµ\81à´³àµ\8dà´³ à´¸à´¹à´¾à´¯à´\82",
        "userlogin-loggedin": "താങ്കൾ ഇപ്പോൾ തന്നെ {{GENDER:$1|$1}} ആയി പ്രവേശിച്ചിരിക്കുന്നു.\nതാഴെ ഉള്ള ഫോം ഉപയോഗിച്ച് മറ്റൊരു ഉപയോക്താവായി പ്രവേശിക്കാവുന്നതാണ്.",
        "userlogin-reauth": "താങ്കൾ {{GENDER:$1|$1}} തന്നെയെന്ന് സ്ഥിരീകരിക്കാൻ ദയവായി വീണ്ടും ലോഗിൻ ചെയ്യുക.",
        "userlogin-createanother": "മറ്റൊരു അംഗത്വമെടുക്കുക",
        "badretype": "താങ്കൾ നൽകിയ രഹസ്യവാക്കുകൾ ഒത്തുപോകുന്നില്ല.",
        "usernameinprogress": "ഈ ഉപയോക്തൃനാമത്തിലുള്ള അംഗത്വ നിർമ്മിതി നടന്നുകൊണ്ടിരിക്കുന്നു.\nദയവായി കാത്തിരിക്കുക.",
        "userexists": "നൽകിയ ഉപയോക്തൃനാമം മുമ്പേ നിലവിലുണ്ട്.\nദയവായി മറ്റൊരു ഉപയോക്തൃനാമം തിരഞ്ഞെടുക്കുക.",
+       "createacct-normalization": "സാങ്കേതിക കാരണങ്ങളാൽ താങ്കളുടെ ഉപയോക്തൃനാമം \"$2\" എന്നാക്കി മാറ്റുന്നതാണ്.",
        "loginerror": "പ്രവേശനം സാധിച്ചില്ല",
        "createacct-error": "അംഗത്വസൃഷ്ടിക്കിടെ പിഴവുണ്ടായി",
        "createaccounterror": "അംഗത്വമെടുക്കാൻ കഴിഞ്ഞില്ല:$1",
        "resetpass-abort-generic": "രഹസ്യവാക്ക് മാറ്റുന്നത് ഒരു അനുബന്ധം തടഞ്ഞിരിക്കുന്നു.",
        "resetpass-expired": "താങ്കളുടെ രഹസ്യവാക്ക് കാലഹരണപ്പെട്ടിരിക്കുന്നു. പ്രവേശിക്കാനായി പുതിയ രഹസ്യവാക്ക് സജ്ജമാക്കുക.",
        "resetpass-expired-soft": "താങ്കളുടെ രഹസ്യവാക്ക് കാലഹരണപ്പെട്ടിരിക്കുന്നതിനാൽ മാറ്റേണ്ടതുണ്ട്. ഇപ്പോൾ തന്നെ പുതിയ രഹസ്യവാക്ക് തിരഞ്ഞെടുക്കുക അല്ലെങ്കിൽ പിന്നീട് മാറ്റുവാനായി \"{{int:authprovider-resetpass-skip-label}}\" ഞെക്കുക.",
+       "resetpass-validity": "താങ്കളുടെ രഹസ്യവാക്കിന് സാധുതയില്ല: $1\n\nപ്രവേശിക്കാനയി പുതിയ രഹസ്യവാക്ക് സജ്ജമാക്കുക.",
        "resetpass-validity-soft": "താങ്കളുടെ രഹസ്യവാക്ക് സാധുതയുള്ളതല്ല: $1\n\nദയവായി പുതിയൊരു രഹസ്യവാക്ക് ഇപ്പോൾ തന്നെ തിരഞ്ഞെടുക്കുക അല്ലെങ്കിൽ പിന്നീട് മാറ്റുന്നതിനായി \"{{int:authprovider-resetpass-skip-label}}\" ഞെക്കുക.",
        "passwordreset": "രഹസ്യവാക്ക് പുനഃക്രമീകരിക്കുക",
        "passwordreset-text-one": "രഹസ്യവാക്ക് പുനർസജ്ജീകരിക്കാനായി ഈ ഫോം പൂരിപ്പിക്കുക.",
        "editconflict": "തിരുത്തൽ സമരസപ്പെടായ്ക: $1",
        "explainconflict": "താങ്കൾ തിരുത്താൻ തുടങ്ങിയതിനു ശേഷം ഈ താൾ മറ്റാരോ തിരുത്തി സേവ് ചെയ്തിരിക്കുന്നു.\nമുകളിലുള്ള ടെക്സ്റ്റ് ഏരിയയിൽ നിലവിലുള്ള ഉള്ളടക്കം കാണിക്കുന്നു.\nതാങ്കൾ ഉള്ളടക്കത്തിൽ വരുത്തിയ മാറ്റങ്ങൾ താഴെയുള്ള ടെക്സ്റ്റ് ഏരിയയിൽ കാണിക്കുന്നു.\nതാങ്കളുടെ മാറ്റങ്ങൾ മുകളിലെ ടെക്സ്റ്റ് ഏരിയയിലേക്ക് സം‌യോജിപ്പിക്കുക.\nതാങ്കൾ '''സേവ് ചെയ്യുക''' എന്ന ബട്ടൺ അമർത്തുമ്പോൾ '''മുകളിലെ ടെക്സ്റ്റ് ഏരിയയിലുള്ള എഴുത്തുകൾ മാത്രമേ''' സേവ് ആവുകയുള്ളൂ.",
        "yourtext": "താങ്കൾ എഴുതി ചേർത്തത്",
-       "storedversion": "മുമ്പേയുള്ള നാൾപതിപ്പ്",
+       "storedversion": "à´®àµ\81à´®àµ\8dà´ªàµ\87à´¯àµ\81à´³àµ\8dà´³ à´¨à´¾àµ¾à´ªàµ\8dപതിപàµ\8dà´ªàµ\8d",
        "editingold": "'''മുന്നറിയിപ്പ്: താങ്കൾ ഈ താളിന്റെ ഒരു പഴയ പതിപ്പാണ്‌ തിരുത്തുന്നത്. ഇപ്പോൾ താങ്കൾ വരുത്തിയ മാറ്റങ്ങൾ സേവ് ചെയ്താൽ ഈ പതിപ്പിനു ശേഷം വന്ന മാറ്റങ്ങളെല്ലാം നഷ്ടമാകും.'''",
        "unicode-support-fail": "താങ്കളുടെ ബ്രൗസർ യൂണീകോഡ് പിന്തുണയ്ക്കുന്നില്ലെന്ന് കാണുന്നു. താളുകൾ തിരുത്താൻ അതാവശ്യമാണ്, അതുകൊണ്ട് താങ്കളുടെ തിരുത്ത് സേവ് ചെയ്തില്ല.",
        "yourdiff": "വ്യത്യാസങ്ങൾ",
        "viewpagelogs": "ഈ താളുമായി ബന്ധപ്പെട്ട രേഖകൾ കാണുക",
        "nohistory": "ഈ താളിന് നാൾവഴി ഇല്ല.",
        "currentrev": "ഇപ്പോഴുള്ള രൂപം",
-       "currentrev-asof": "$1 -ൽ നിലവിലുള്ള രൂപം",
+       "currentrev-asof": "$1-നു നിലവിലുള്ള രൂപം",
        "revisionasof": "$1-നു നിലവിലുണ്ടായിരുന്ന രൂപം",
        "revision-info": "$1-നു ഉണ്ടായിരുന്ന രൂപം സൃഷ്ടിച്ചത്:- {{GENDER:$6|$2}}$7",
        "previousrevision": "←പഴയ രൂപം",
        "page_first": "ആദ്യ",
        "page_last": "അവസാന",
        "histlegend": "വ്യത്യാസങ്ങൾ ഒത്തുനോക്കാൻ: ഒത്തുനോക്കേണ്ട പതിപ്പുകൾക്കൊപ്പമുള്ള റേഡിയോ ബട്ടൺ തിരഞ്ഞെടുത്ത് ''\"തിരഞ്ഞെടുത്ത പതിപ്പുകൾ തമ്മിലുള്ള വ്യത്യാസം കാണുക\"'' എന്ന ബട്ടൺ ഞെക്കുകയോ ''എന്റർ'' കീ അമർത്തുകയോ ചെയ്യുക.<br />\n\nസൂചന: (ഇപ്പോൾ) = നിലവിലുള്ള പതിപ്പുമായുള്ള വ്യത്യാസം, (മുമ്പ്) = തൊട്ടുമുൻപത്തെ പതിപ്പുമായുള്ള വ്യത്യാസം, (ചെ.) = ചെറിയ തിരുത്ത്.",
-       "history-fieldset-title": "നാൾവഴി à´ªà´°à´¿à´¶àµ\8bധന",
+       "history-fieldset-title": "നാൾവഴി à´\85à´°à´¿à´\9aàµ\8dà´\9aàµ\86à´\9fàµ\81à´\95àµ\8dà´\95àµ\81à´\95",
        "history-show-deleted": "നാൾപ്പതിപ്പ് മായ്ക്കപ്പെട്ടവ മാത്രം",
        "histfirst": "ഏറ്റവും പഴയവ",
        "histlast": "ഏറ്റവും പുതിയവ",
        "historysize": "({{PLURAL:$1|1 ബൈറ്റ്|$1 ബൈറ്റുകൾ}})",
-       "historyempty": "(ശൂന്യം)",
+       "historyempty": "ശൂന്യം",
        "history-feed-title": "നാൾവഴി",
        "history-feed-description": "വിക്കിയിൽ ഈ താളിന്റെ നാൾവഴി",
        "history-feed-item-nocomment": "$2 സമയത്ത് $1",
        "mergehistory-fail-bad-timestamp": "സമയമുദ്ര അസാധുവാണ്.",
        "mergehistory-fail-invalid-source": "സ്രോതസ്സ് താൾ അസാധുവാണ്.",
        "mergehistory-fail-invalid-dest": "ലക്ഷ്യതാൾ അസാധുവാണ്.",
+       "mergehistory-fail-no-change": "നാൾവഴി ലയനം വഴി നാൾപ്പതിപ്പുകൾ ഒന്നും ലയിപ്പിച്ചിട്ടില്ല. ദയവായി താളും സമയചരങ്ങളും പുനഃപരിശോധിക്കുക.",
        "mergehistory-fail-permission": "താങ്കൾക്ക് നാൾവഴികൾ ലയിപ്പിക്കാനുള്ള അനുമതി ഇല്ല.",
        "mergehistory-fail-self-merge": "സ്രോതസ്സ് - ലക്ഷ്യ താളുകൾക്ക് ഒരേ പേര്‌ ഉണ്ടാകാൻ പാടില്ല.",
        "mergehistory-fail-toobig": "{{PLURAL:$1|ഒരു നാൾപ്പതിപ്പിൽ|$1 നാൾപ്പതിപ്പുകൾ}} മാറ്റണമെന്നതിനാൽ നാൾവഴി ലയിപ്പിക്കാൽ നടത്താനാവില്ല.",
        "prefs-files": "പ്രമാണങ്ങൾ",
        "prefs-custom-css": "സ്വന്തം സി.എസ്.എസ്.",
        "prefs-custom-json": "ഐച്ഛിക ജെസൺ",
-       "prefs-custom-js": "à´¸àµ\8dവനàµ\8dà´¤à´\82 à´\9càµ\86.à´\8eà´¸àµ\8d.",
+       "prefs-custom-js": "à´¸àµ\8dവനàµ\8dà´¤à´\82 à´\9cാവാസàµ\8dà´\95àµ\8dà´°à´¿à´ªàµ\8dà´±àµ\8dà´±àµ\8d",
        "prefs-common-config": "എല്ലാ ദൃശ്യരൂപങ്ങൾക്കുമായി പങ്ക് വെയ്ക്കപ്പെട്ട സി.എസ്.എസ്./ജെസൺ/ജാവാസ്ക്രിപ്റ്റ്:",
        "prefs-reset-intro": "സൈറ്റിൽ സ്വതേയുണ്ടാവേണ്ട ക്രമീകരണങ്ങൾ പുനഃക്രമീകരിക്കാൻ താങ്കൾക്ക് ഈ താൾ ഉപയോഗിക്കാവുന്നതാണ്.\nഇത് തിരിച്ചു ചെയ്യാൻ സാദ്ധ്യമല്ല.",
        "prefs-emailconfirm-label": "ഇമെയിൽ സ്ഥിരീകരണം:",
        "right-reupload-own": "സ്വയം അപ്‌ലോഡ് ചെയ്ത പ്രമാണങ്ങൾക്കു മുകളിലേയ്ക്ക് പ്രമാണങ്ങൾ അപ്‌ലോഡ് ചെയ്യുക",
        "right-reupload-shared": "പങ്ക് വെയ്ക്കപ്പെട്ട മീഡിയ സംഭരണിയെ പ്രാദേശികമായി അതിലംഘിക്കുക",
        "right-upload_by_url": "യു.ആർ.എല്ലിൽ നിന്നും പ്രമാണങ്ങൾ അപ്‌ലോഡ് ചെയ്യുക",
-       "right-purge": "à´¸àµ\8dഥിരàµ\80à´\95à´°à´£à´\82 à´\92à´¨àµ\8dà´¨àµ\81à´\82 à´\87à´²àµ\8dലാതàµ\86 à´¸àµ\88à´±àµ\8dറിനàµ\8dà´±àµ\86 à´\95ാഷàµ\86 à´\92à´°àµ\81 à´¤à´¾à´³à´¿à´¨à´¾à´¯à´¿ à´ªàµ¼à´\9càµ\8d à´\9aàµ\86à´¯àµ\8dà´¯àµ\81à´\95",
+       "right-purge": "സൈറ്റിന്റെ കാഷെ ഒരു താളിനായി പർജ് ചെയ്യുക",
        "right-autoconfirmed": "ഐ.പി. അധിഷ്ഠിത പരിധികൾ ബാധകമല്ല",
        "right-bot": "യാന്ത്രിക പ്രവൃത്തിയായി കണക്കാക്കപ്പെടുന്നു",
        "right-nominornewtalk": "സംവാദം താളുകളിലെ ചെറുതിരുത്തലുകൾ പുതിയ സന്ദേശങ്ങളുണ്ടെന്ന അറിയിപ്പിനു കാരണമാകരുത്",
        "action-changetags": "ഒറ്റയൊറ്റ നാൾപ്പതിപ്പുകൾക്കും രേഖയിലെ ഉൾപ്പെടുത്തലുകൾക്കും ഐച്ഛിക ടാഗുകൾ ചേർക്കുക അല്ലെങ്കിൽ നീക്കംചെയ്യുക",
        "action-deletechangetags": "ഡേറ്റാബേസിൽ നിന്നും റ്റാഗുകൾ മായ്ക്കുക",
        "action-purge": "താൾ ശുദ്ധീകരിച്ചെടുക്കുക",
+       "action-bigdelete": "വലിയ നാൾവഴികളുള്ള താളുകൾ മായ്ക്കുക",
+       "action-blockemail": "ഇമെയിൽ അയക്കുന്നതിൽ നിന്നും ഒരു ഉപയോക്താവിനെ തടയുക",
+       "action-bot": "യാന്ത്രിക പ്രവൃത്തിയായി കണക്കാക്കുക",
+       "action-editprotected": "\"{{int:protect-level-sysop}}\" എന്ന് അടയാളപ്പെടുത്തി സംരക്ഷിച്ചിട്ടുള്ള താളുകൾ തിരുത്തുക",
+       "action-editsemiprotected": "\"{{int:protect-level-autoconfirmed}}\" എന്നടയാളപ്പെടുത്തി സംരക്ഷിച്ചിട്ടുള്ള താളുകൾ തിരുത്തുക",
+       "action-editinterface": "ഉപയോക്തൃ സമ്പർക്കമുഖം തിരുത്തുക",
+       "action-editusercss": "മറ്റ് ഉപയോക്താക്കളുടെ CSS പ്രമാണങ്ങൾ തിരുത്തുക",
+       "action-edituserjson": "മറ്റ് ഉപയോക്താക്കളുടെ ജെസൺ പ്രമാണങ്ങൾ തിരുത്തുക",
+       "action-edituserjs": "മറ്റ് ഉപയോക്താക്കളുടെ ജാവാസ്ക്രിപ്റ്റ് പ്രമാണങ്ങൾ തിരുത്തുക",
+       "action-editsitecss": "സൈറ്റ്-വ്യാപക സി.എസ്.എസ്. തിരുത്തുക",
+       "action-editsitejson": "സൈറ്റ്-വ്യാപക ജെസൺ തിരുത്തുക",
+       "action-editsitejs": "സൈറ്റ്-വ്യാപക ജാവാസ്ക്രിപ്റ്റ് തിരുത്തുക",
+       "action-editmyusercss": "താങ്കളുടെ സ്വന്തം ഉപയോക്തൃ സി.എസ്.എസ്. പ്രമാണങ്ങൾ തിരുത്തുക",
+       "action-editmyuserjson": "താങ്കളുടെ സ്വന്തം ഉപയോക്തൃ ജെസൺ പ്രമാണങ്ങൾ തിരുത്തുക",
+       "action-editmyuserjs": "താങ്കളുടെ സ്വന്തം ഉപയോക്തൃ ജാവാസ്ക്രിപ്റ്റ് പ്രമാണങ്ങൾ തിരുത്തുക",
+       "action-viewsuppressed": "ഉപയോക്താക്കളിൽ നിന്നും മറയ്ക്കപ്പെട്ട നാൾപ്പതിപ്പുകൾ കാണുക",
+       "action-hideuser": "പരസ്യമായി കാണപ്പെടുന്നതിൽ നിന്നും മറച്ച് ഒരു ഉപയോക്തൃനാമത്തെ തടയുക",
+       "action-ipblock-exempt": "ഐ.പി. തടയലുകൾ, സ്വതേയുള്ള തടയലുകൾ, റേഞ്ച് തടയലുകൾ ഒക്കെ ബാധകമല്ലാതിരിക്കുക",
+       "action-unblockself": "സ്വയം തടയൽ നീക്കുക",
+       "action-noratelimit": "പ്രവർത്തനങ്ങൾക്ക് പരിധികൾ ബാധകമല്ല",
+       "action-reupload-own": "സ്വയം അപ്‌ലോഡ് ചെയ്ത പ്രമാണങ്ങൾക്കു മുകളിലേയ്ക്ക് പ്രമാണങ്ങൾ അപ്‌ലോഡ് ചെയ്യുക",
+       "action-nominornewtalk": "സംവാദം താളുകളിലെ ചെറുതിരുത്തലുകൾ പുതിയ സന്ദേശങ്ങളുണ്ടെന്ന അറിയിപ്പിനു കാരണമാകരുത്",
+       "action-markbotedits": "മുൻപ്രാപനം നടത്തിയ തിരുത്തലുകൾ യാന്ത്രിക തിരുത്തലുകളായി അടയാളപ്പെടുത്തുക",
+       "action-patrolmarks": "പുതിയ മാറ്റങ്ങളിലെ റോന്തുചുറ്റൽ രേഖകൾ പരിശോധിക്കുക",
+       "action-override-export-depth": "കണ്ണിവത്കരിക്കപ്പെട്ട താളുകളുടെ ആഴം 5 വരെയുള്ള താളുകൾ കയറ്റുമതി ചെയ്യുക",
+       "action-suppressredirect": "താളുകൾ മാറ്റുമ്പോൾ സ്രോതസ്സ് താളിൽ തിരിച്ചുവിടലുകൾ സൃഷ്ടിക്കാതിരിക്കുക",
        "nchanges": "{{PLURAL:$1|ഒരു മാറ്റം|$1 മാറ്റങ്ങൾ}}",
        "enhancedrc-since-last-visit": "കഴിഞ്ഞ സന്ദർശനത്തിനു ശേഷം {{PLURAL:$1|ഒരെണ്ണം|$1 എണ്ണം}}",
        "enhancedrc-history": "നാൾവഴി",
        "rcfilters-savedqueries-already-saved": "ഈ അരിപ്പകൾ മുമ്പേ തന്നെ സേവ് ചെയ്തിട്ടുണ്ട്. പുതിയ സേവ് ചെയ്യാനുള്ള അരിപ്പ സൃഷ്ടിക്കാൻ താങ്കളുടെ സജ്ജീകരണങ്ങളിൽ മാറ്റം വരുത്തുക.",
        "rcfilters-restore-default-filters": "സ്വതേയുള്ള അരിപ്പകൾ പുനഃസ്ഥാപിക്കുക",
        "rcfilters-clear-all-filters": "എല്ലാ അരിപ്പകളും ഒഴിവാക്കുക",
-       "rcfilters-show-new-changes": "ഏറ്റവും പുതിയ മാറ്റങ്ങൾ കാണുക",
+       "rcfilters-show-new-changes": "$1 മുതലുള്ള പുതിയ മാറ്റങ്ങൾ കാണുക",
        "rcfilters-search-placeholder": "സമീപകാലമാറ്റങ്ങൾ അരിച്ചെടുക്കുക (മെനു ഉപയോഗിക്കുക അല്ലെങ്കിൽ അരിപ്പയുടെ പേരുപയോഗിച്ച് തിരയുക)",
        "rcfilters-invalid-filter": "അസാധുവായ അരിപ്പ",
        "rcfilters-empty-filter": "സജീവ അരിപ്പകൾ ഇല്ല. എല്ലാ സംഭാവനകളും പ്രദർശിപ്പിക്കുന്നു.",
        "rcfilters-filter-editsbyself-description": "താങ്കളുടെ സ്വന്തം സംഭാവനകൾ.",
        "rcfilters-filter-editsbyother-label": "മറ്റുള്ളവർ ചെയ്ത മാറ്റങ്ങൾ",
        "rcfilters-filter-editsbyother-description": "താങ്കൾ ചെയ്തവ ഒഴിച്ചുള്ള മാറ്റങ്ങൾ.",
-       "rcfilters-filtergroup-userExpLevel": "ഉപയോക്താക്കളുടെ തരവും പരിചയസമ്പത്തും",
+       "rcfilters-filtergroup-user-experience-level": "ഉപയോക്താക്കളുടെ തരവും പരിചയസമ്പത്തും",
        "rcfilters-filter-user-experience-level-registered-label": "രജിസ്റ്റേഡ്",
        "rcfilters-filter-user-experience-level-registered-description": "ലോഗിൻ ചെയ്തിട്ടുള്ള ലേഖകർ.",
        "rcfilters-filter-user-experience-level-unregistered-label": "രജിസ്റ്റർ ചെയ്യാത്തവർ",
        "rcfilters-filter-categorization-description": "വർഗ്ഗത്തിൽ ചേർത്തതും ഒഴിവാക്കിയതുമായ താളുകളുടെ വിവരങ്ങൾ.",
        "rcfilters-filter-logactions-label": "രേഖപ്പെടുത്തിയ പ്രവൃത്തികൾ",
        "rcfilters-filter-logactions-description": "കാര്യനിർവാഹക പ്രവർത്തനങ്ങൾ, അംഗത്വസൃഷ്ടികൾ, താൾ മായ്ക്കലുകൾ, അപ്‌ലോഡുകൾ...",
-       "rcfilters-filtergroup-lastRevision": "ഏറ്റവും പുതിയ നാൾപ്പതിപ്പുകൾ",
+       "rcfilters-filtergroup-lastrevision": "ഏറ്റവും പുതിയ നാൾപ്പതിപ്പുകൾ",
        "rcfilters-filter-lastrevision-label": "ഏറ്റവും പുതിയ നാൾപ്പതിപ്പ്",
        "rcfilters-filter-lastrevision-description": "താളിലെ ഏറ്റവും പുതിയ മാറ്റം മാത്രം.",
        "rcfilters-filter-previousrevision-label": "ഒടുവിലത്തെ നാൾപ്പതിപ്പ് അല്ലാത്തവ",
        "newpageletter": "(പു.)",
        "boteditletter": "(യ.)",
        "unpatrolledletter": "(!)",
-       "number_of_watching_users_pageview": "[{{PLURAL:$1|ഒരു ഉപയോക്താവ്|$1 ഉപയോക്താക്കൾ}} ഈ താൾ ശ്രദ്ധിക്കുന്നുണ്ട്]",
        "rc-change-size-new": "മാറ്റത്തിനു ശേഷം {{PLURAL:$1|ഒരു ബൈറ്റ്|$1 ബൈറ്റുകൾ}}",
        "newsectionsummary": "/* $1 */ പുതിയ ഉപവിഭാഗം",
        "rc-enhanced-expand": "അധികവിവരങ്ങൾ പ്രദർശിപ്പിക്കുക",
        "img-auth-nopathinfo": "പാത്ത് വിവരങ്ങൾ ലഭ്യമല്ല.\nതാങ്കളുടെ സെർവർ REQUEST_URI ഒപ്പം/അല്ലെങ്കിൽ PATH_INFO കൈമാറ്റം ചെയ്യാൻ കഴിയുന്നതായി സജ്ജീകരിച്ചിരിക്കേണ്ടതുണ്ട്.\nഅങ്ങനെ ചെയ്തിട്ടുണ്ടെങ്കിൽ $wgUsePathInfo സജ്ജമാക്കുക.\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization കാണുക.",
        "img-auth-notindir": "ആവശ്യപ്പെട്ട പാത അപ്‌‌ലോഡ് ഡയറക്റ്ററിയിൽ സജ്ജീകരിച്ചു നൽകിയിട്ടില്ല.",
        "img-auth-badtitle": "\"$1\" എന്നതിൽ നിന്ന് സാധുവായ തലക്കെട്ട് സൃഷ്ടിക്കാൻ കഴിയില്ല.",
-       "img-auth-nologinnWL": "താങ്കൾ ലോഗിൻ ചെയ്തിട്ടില്ല ഒപ്പം \"$1\" ശുദ്ധിപട്ടികയിൽ ഇല്ല.",
        "img-auth-nofile": "\"$1\" എന്ന പ്രമാണം നിലവിലില്ല.",
        "img-auth-isdir": "താങ്കൾ \"$1\" എന്ന ഡയറക്ടറി എടുക്കാനാണു ശ്രമിക്കുന്നത്.\nപ്രമാണങ്ങൾ എടുക്കാൻ മാത്രമേ അനുവദിക്കുള്ളു.",
        "img-auth-streaming": "സ്ട്രീമിങ് \"$1\".",
        "apisandbox-submit-invalid-fields-title": "ചില മണ്ഡലങ്ങൾ അസാധുവാണ്",
        "apisandbox-results": "ഫലങ്ങൾ",
        "apisandbox-request-url-label": "അഭ്യർത്ഥനാ യൂ.ആർ.എൽ.:",
-       "apisandbox-request-json-label": "JSON നുവേണ്ടി അപേക്ഷിക്കുക:",
+       "apisandbox-request-json-label": "ജെസൺ അപേക്ഷിക്കുക:",
        "apisandbox-request-time": "അഭ്യർത്ഥനയുടെ സമയം: {{PLURAL:$1|$1 മി.സെ.}}",
        "apisandbox-results-fixtoken": "ചീട്ട് ശരിയാക്കിയ ശേഷം വീണ്ടും സമർപ്പിക്കുക",
-       "apisandbox-results-fixtoken-fail": "\"$1\" à´\9fàµ\8bà´\95àµ\8dà´\95ൻ എടുക്കുന്നത്‌ പരാജയപെട്ടു.",
+       "apisandbox-results-fixtoken-fail": "\"$1\" à´\9aàµ\80à´\9fàµ\8dà´\9fàµ\8d എടുക്കുന്നത്‌ പരാജയപെട്ടു.",
        "apisandbox-alert-page": "ഈ താളിലെ ഫീൽഡുകൾ അസാധുവാണ്.",
        "apisandbox-continue": "തുടരുക",
        "apisandbox-continue-clear": "ശൂന്യമാക്കുക",
        "delete-confirm": "\"$1\" മായ്ക്കുക",
        "delete-legend": "മായ്ക്കുക",
        "historywarning": "<strong>മുന്നറിയിപ്പ്</strong>: താങ്കൾ മായ്ക്കുവാൻ പോകുന്ന താളിനു {{PLURAL:$1|ഒരു നാൾപ്പതിപ്പ്|$1 നാൾപ്പതിപ്പുകൾ}} ഉള്ള നാൾവഴി ഉണ്ട്:",
-       "historyaction-submit": "പ്രദർശിപ്പിക്കുക",
+       "historyaction-submit": "നാൾപàµ\8dപതിപàµ\8dà´ªàµ\81à´\95ൾ à´ªàµ\8dരദർശിപàµ\8dപിà´\95àµ\8dà´\95àµ\81à´\95",
        "confirmdeletetext": "താങ്കൾ ഒരു താൾ അതിന്റെ നാൾവഴിയടക്കം മായ്ക്കുവാൻ പോവുകയാണ്. ഈ ചെയ്തിയുടെ പരിണതഫലം താങ്കൾക്കറിയാമെന്നും, ഈ നടപടി [[{{MediaWiki:Policy-url}}|വിക്കിയുടെ നയം]] അനുസരിച്ചാണു ചെയ്യുന്നതെന്നും ഉറപ്പാക്കുക.",
        "actioncomplete": "പ്രവൃത്തി പൂർത്തിയായിരിക്കുന്നു",
        "actionfailed": "പ്രവൃത്തി പരാജയപ്പെട്ടിരിക്കുന്നു",
        "deleting-backlinks-warning": "<strong>മുന്നറിയിപ്പ്:</strong> മറ്റു താളുകളിൽ നിന്നും [[Special:WhatLinksHere/{{FULLPAGENAME}}|താളിലേയ്ക്കുള്ള കണ്ണികൾ]] അല്ലെങ്കിൽ ഉൾപ്പെടുത്തിയിട്ടുള്ള താളുകൾ താങ്കൾ മായ്ക്കാൻ പോവുകയാണ്.",
        "deleting-subpages-warning": "<strong>മുന്നറിയിപ്പ്:</strong> താങ്കൾ മായ്ക്കാൻ പോകുന്ന താളിന് [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|ഒരു ഉപതാൾ|$1 ഉപതാളുകൾ|51=അമ്പതിലധികം ഉപതാളുകൾ}}]] ഉണ്ട്.",
        "rollback": "തിരുത്തുകൾ റോൾബാക്ക് ചെയ്യുക",
+       "rollback-confirmation-confirm": "ദയവായി സ്ഥിരീകരിക്കുക:",
+       "rollback-confirmation-yes": "റോൾബാക്ക്",
+       "rollback-confirmation-no": "റദ്ദാക്കുക",
        "rollbacklink": "റോൾബാക്ക്",
        "rollbacklinkcount": "{{PLURAL:$1|ഒരു തിരുത്ത്|$1 തിരുത്തുകൾ}} മുൻപ്രാപനം ചെയ്യുക",
        "rollbacklinkcount-morethan": "{{PLURAL:$1|ഒന്നിലധികം തിരുത്തുകൾ|$1 എണ്ണത്തിലധികം തിരുത്തുകൾ}} മുൻപ്രാപനം ചെയ്യുക",
        "revertpage": "[[Special:Contributions/$2|$2]] ([[User talk:$2|സംവാദം]]) നടത്തിയ തിരുത്തലുകൾ നീക്കം ചെയ്തിരിക്കുന്നു; നിലവിലുള്ള പതിപ്പ് [[User:$1|$1]] സൃഷ്ടിച്ചതാണ്",
        "revertpage-nouser": "മറയ്ക്കപ്പെട്ട ഉപയോക്താവ് നടത്തിയ തിരുത്തലുകൾ {{GENDER:$1|[[User:$1|$1]]}} സൃഷ്ടിച്ച അവസാന പതിപ്പിലേയ്ക്ക് മുൻപ്രാപനം ചെയ്തിരിക്കുന്നു",
        "rollback-success": "{{GENDER:$3|$1}} ചെയ്ത തിരുത്ത് തിരസ്ക്കരിച്ചിരിക്കുന്നു; {{GENDER:$4|$2}} ചെയ്ത തൊട്ടു മുൻപത്തെ പതിപ്പിലേക്ക് സേവ് ചെയ്യുന്നു.",
-       "rollback-success-notify": "$1 ചെയ്ത തിരുത്തുകൾ തിരസ്ക്കരിച്ചിരിക്കുന്നു; $2 ചെയ്ത തൊട്ടു മുൻപത്തെ പതിപ്പിലേക്ക് സേവ് ചെയ്യുന്നു. [$3 മാറ്റങ്ങൾ കാണിക്കുക]",
        "sessionfailure-title": "സെഷൻ പരാജയപ്പെട്ടിരിക്കുന്നു",
        "sessionfailure": "താങ്കളുടെ ലോഗിൻ സെഷനിൽ പ്രശ്നങ്ങളുള്ളതായി കാണുന്നു;\nസെഷൻ തട്ടിയെടുക്കൽ ഒഴിവാക്കാനുള്ള മുൻകരുതലായി ഈ പ്രവൃത്തി റദ്ദാക്കിയിരിക്കുന്നു.\nദയവായി ഫോം വീണ്ടും സമർപ്പിക്കുക.",
        "changecontentmodel": "താളിന്റെ ഉള്ളടക്ക രീതി തിരുത്തുക",
        "mycontris": "സംഭാവനകൾ",
        "anoncontribs": "സംഭാവനകൾ",
        "contribsub2": "ഉപയോക്താവ് {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "ഉപയോക്താവ് {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "\"$1\" എന്ന ഉപയോക്തൃ അം‌ഗത്വം നിലവിലില്ല.",
        "nocontribs": "ഈ മാനദണ്ഡങ്ങളുമായി യോജിക്കുന്ന മാറ്റങ്ങൾ ഒന്നും കണ്ടില്ല.",
        "uctop": "നിലവിലുള്ളത്",
        "blocklist-userblocks": "അംഗത്വ തടയലുകൾ മറയ്ക്കുക",
        "blocklist-tempblocks": "താത്കാലിക തടയലുകൾ മറയ്ക്കുക",
        "blocklist-addressblocks": "ഒറ്റയൊറ്റ ഐ.പി. തടയലുകൾ മറയ്ക്കുക",
+       "blocklist-type": "തരം:",
+       "blocklist-type-opt-all": "എല്ലാം",
+       "blocklist-type-opt-sitewide": "സൈറ്റ്-വ്യാപകം",
+       "blocklist-type-opt-partial": "ഭാഗികം",
        "blocklist-rangeblocks": "പരിധിയടച്ചുള്ള തടയലുകൾ മറയ്ക്കുക",
        "blocklist-timestamp": "സമയമുദ്ര",
        "blocklist-target": "ലക്ഷ്യം",
        "blocklist-editing-page": "താളുകൾ",
        "blocklist-editing-ns": "നാമമേഖലകൾ",
        "ipblocklist-empty": "തടയൽപ്പട്ടിക ശൂന്യമാണ്‌.",
-       "ipblocklist-no-results": "à´\88 à´\90.പി. à´µà´¿à´²à´¾à´¸à´®àµ\8b à´\89പയàµ\8bà´\95àµ\8dà´¤àµ\83നാമമàµ\8b à´¤à´\9fà´\9eàµ\8dà´\9eà´¿à´\9fàµ\8dà´\9fà´¿ല്ല.",
+       "ipblocklist-no-results": "à´\86വശàµ\8dയപàµ\8dà´ªàµ\86à´\9fàµ\8dà´\9f à´\90.പി. à´µà´¿à´²à´¾à´¸à´®àµ\8b à´\89പയàµ\8bà´\95àµ\8dà´¤àµ\83നാമമàµ\8b à´\86യി à´ªàµ\8aà´°àµ\81à´¤àµ\8dതപàµ\8dà´ªàµ\86à´\9fàµ\81à´¨àµ\8dà´¨ à´¤à´\9fയലàµ\81à´\95ൾ à´\87ല്ല.",
        "blocklink": "തടയുക",
        "unblocklink": "സ്വതന്ത്രമാക്കുക",
        "change-blocklink": "തടയലിൽ മാറ്റം വരുത്തുക",
        "allmessagesdefault": "സ്വതേയുള്ള ഉള്ളടക്കം",
        "allmessagescurrent": "നിലവിലുള്ള ഉള്ളടക്കം",
        "allmessagestext": "ഇത് മീഡിയവിക്കി നാമമേഖലയിൽ ലഭ്യമായ വ്യവസ്ഥാസന്ദേശങ്ങളുടെ ഒരു പട്ടിക ആണ്‌.\nപ്രാമാണികമായ വിധത്തിൽ മീഡിയവിക്കിയുടെ പ്രാദേശീകരണം താങ്കൾ ഉദ്ദേശിക്കുന്നുവെങ്കിൽ ദയവായി [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation മീഡിയവിക്കി പ്രാദേശീകരണം], [https://translatewiki.net പരിഭാഷാവിക്കി] തുടങ്ങിയവ സന്ദർശിക്കുക.",
-       "allmessagesnotsupportedDB": "'''$wgUseDatabaseMessages''' ബന്ധിച്ചിരിക്കുന്നതു കാരണം ഈ താൾ ഉപയോഗിക്കുവാൻ സാദ്ധ്യമല്ല.",
+       "allmessages-not-supported-database": "'''$wgUseDatabaseMessages''' ബന്ധിച്ചിരിക്കുന്നതു കാരണം ഈ താൾ ഉപയോഗിക്കുവാൻ സാദ്ധ്യമല്ല.",
        "allmessages-filter-legend": "അരിപ്പ",
        "allmessages-filter": "പുനഃക്രമീകരിച്ച ക്രമത്തിൽ തിരഞ്ഞുവെയ്ക്കുക:",
        "allmessages-filter-unmodified": "തിരുത്തപ്പെടാത്തത്",
        "imgmultipagenext": "അടുത്ത താൾ →",
        "imgmultigo": "പോകൂ!",
        "imgmultigoto": "$1 താളിലേക്ക് പോകുക",
-       "img-lang-default": "(സ്വതേ വേണ്ട ഭാഷ)",
+       "img-lang-default": "(സ്വതേയുള്ള ഭാഷ)",
        "img-lang-info": "ഈ ചിത്രം ഈ ഭാഷയിൽ കാണിക്കുക: $1. $2",
        "img-lang-go": "പോകൂ",
        "ascending_abbrev": "ആരോഹണം",
        "logentry-rights-autopromote": "$1 എന്ന ഉപയോക്താവ് $4 എന്നതിൽ നിന്നും $5 എന്നതിലേയ്ക്ക് സ്വയമേവ {{GENDER:$2|ഉയർത്തപ്പെട്ടിരിക്കുന്നു}}",
        "logentry-upload-upload": "$1 $3 {{GENDER:$2|അപ്‌ലോഡ് ചെയ്തു}}",
        "logentry-upload-overwrite": "$1 ഒരു പുതിയ പതിപ്പ് $3 {{GENDER:$2|അപ്‌ലോഡ് ചെയ്തു}}",
-       "logentry-upload-revert": "$1 $3 {{GENDER:$2|അപ്‌ലോഡ് ചെയ്തു}}",
+       "logentry-upload-revert": "$3 പഴയ പതിപ്പിലേക്ക് $1 {{GENDER:$2|തിരിച്ചാക്കി}}",
        "log-name-managetags": "ടാഗ് കൈകാര്യ രേഖ",
        "log-description-managetags": "ഈ താളിൽ [[Special:Tags|ടാഗുകളുമായി]] ബന്ധപ്പെട്ട പ്രവൃത്തികളുടെ കാര്യനിർവഹണം ഉൾപ്പെടുത്തിയിരിക്കുന്നു. രേഖയിൽ ഒരു കാര്യനിർവ്വാഹക(ൻ) നടത്തിയ പ്രവൃത്തികൾ മാത്രമേ ഉൾപ്പെടുന്നുള്ളു; വിക്കി സോഫ്റ്റ്‌വേർ സൃഷ്ടിച്ചതോ നീക്കംചെയ്തതോ ആയ ടാഗുകൾ ഈ രേഖയിൽ ശേഖരിക്കുന്നില്ല.",
        "logentry-managetags-create": "\"$4\" എന്ന ടാഗ് $1 {{GENDER:$2|സൃഷ്ടിച്ചിരിക്കുന്നു}}",
        "authmanager-provider-password": "രഹസ്യവാക്ക്-അധിഷ്ഠിത സാധൂകരണം",
        "authmanager-provider-password-domain": "രഹസ്യവാക്ക്-ഡൊമൈൻ-അധിഷ്ഠിത സാധൂകരണം",
        "authmanager-provider-temporarypassword": "താത്കാലിക രഹസ്യവാക്ക്",
-       "authprovider-confirmlink-success-line": "$1: à´µà´¿à´\9cà´¯à´\95രമായി à´²à´¿à´\99àµ\8dà´\95àµ\8d à´\9aàµ\86à´¯്തു.",
+       "authprovider-confirmlink-success-line": "$1: à´µà´¿à´\9cà´¯à´\95രമായി à´\95à´£àµ\8dണി à´\9aàµ\87ർത്തു.",
        "authprovider-resetpass-skip-label": "മറികടക്കുക",
-       "authform-newtoken": "à´\9fàµ\8bà´\95àµ\8dà´\95ൺ കാണുന്നില്ല. $1",
-       "authform-notoken": "à´\9fàµ\8bà´\95àµ\8dà´\95ൺ കാണുന്നില്ല",
-       "authform-wrongtoken": "à´¤àµ\86à´±àµ\8dറായ à´\9fàµ\8bà´\95àµ\8dà´\95ൻ",
+       "authform-newtoken": "à´\9aàµ\80à´\9fàµ\8dà´\9fàµ\8d കാണുന്നില്ല. $1",
+       "authform-notoken": "à´\9aàµ\80à´\9fàµ\8dà´\9fàµ\8d കാണുന്നില്ല",
+       "authform-wrongtoken": "à´¤àµ\86à´±àµ\8dറായ à´\9aàµ\80à´\9fàµ\8dà´\9fàµ\8d",
        "specialpage-securitylevel-not-allowed-title": "അനുവദിച്ചിട്ടില്ല",
        "specialpage-securitylevel-not-allowed": "താങ്കളുടെ വ്യക്തിത്വം പരിശോധിക്കാൻ കഴിയാഞ്ഞതിനാൽ ഈ താൾ ഉപയോഗിക്കാൻ താങ്കളെ അനുവദിക്കാനാവില്ല.",
        "authpage-cannot-login": "പ്രവേശനം തുടങ്ങാൻ സാധിക്കുന്നില്ല.",
        "linkaccounts-submit": "അംഗത്വങ്ങൾ കണ്ണി ചേർക്കുക",
        "unlinkaccounts": "അംഗത്വങ്ങൾ കണ്ണി മാറ്റുക",
        "unlinkaccounts-success": "അംഗത്വം കണ്ണി മാറ്റി.",
+       "userjsispublic": "ദയവായി ശ്രദ്ധിക്കുക: ജാവാസ്ക്രിപ്റ്റ് ഉപതാളുകൾ മറ്റ് ഉപയോക്താക്കൾക്ക് കാണാൻ കഴിയും, അവയിൽ സ്വകാര്യവിവരങ്ങൾ ചേർക്കാതിരിക്കുക.",
+       "userjsonispublic": "ദയവായി ശ്രദ്ധിക്കുക: ജെസൺ ഉപതാളുകൾ മറ്റ് ഉപയോക്താക്കൾക്ക് കാണാൻ കഴിയും, അവയിൽ സ്വകാര്യവിവരങ്ങൾ ചേർക്കാതിരിക്കുക.",
+       "usercssispublic": "ദയവായി ശ്രദ്ധിക്കുക: സി.എസ്.എസ്. ഉപതാളുകൾ മറ്റ് ഉപയോക്താക്കൾക്ക് കാണാൻ കഴിയും, അവയിൽ സ്വകാര്യവിവരങ്ങൾ ചേർക്കാതിരിക്കുക.",
        "restrictionsfield-badip": "അസാധുവായ ഐ.പി. വിലാസം അല്ലെങ്കിൽ പരിധി:$1",
        "restrictionsfield-label": "അനുവദിച്ചിട്ടുള്ള ഐ.പി. പരിധികൾ:",
        "edit-error-short": "പിഴവ്: $1",
        "passwordpolicies-policy-passwordnotinlargeblacklist": "രഹസ്യവാക്ക്, പരക്കെ ഉപയോഗിക്കപ്പെടുന്ന 1,00,000 രഹസ്യവാക്കുകളുടെ പട്ടികയിൽ ഉള്ളതാവരുത്.",
        "passwordpolicies-policyflag-forcechange": "ലോഗിൻ മാറ്റിയിരിക്കണം",
        "passwordpolicies-policyflag-suggestchangeonlogin": "ലോഗിൻ മാറ്റാൻ നിർദ്ദേശിക്കുന്നു",
-       "unprotected-js": "സുരക്ഷാകാരണങ്ങളാൽ സംരക്ഷണമില്ലാത്ത താളുകളിൽ നിന്നും ജാവാസ്ക്രിപ്റ്റ് എടുത്തുപയോഗിക്കാൻ കഴിയില്ല. ജാവാസ്ക്രിപ്റ്റ് താളുകൾ മീഡിയവിക്കി: നാമമേഖലയിലോ ഉപയോക്തൃ ഉപതാളായോ മാത്രം സൃഷ്ടിക്കുക"
+       "unprotected-js": "സുരക്ഷാകാരണങ്ങളാൽ സംരക്ഷണമില്ലാത്ത താളുകളിൽ നിന്നും ജാവാസ്ക്രിപ്റ്റ് എടുത്തുപയോഗിക്കാൻ കഴിയില്ല. ജാവാസ്ക്രിപ്റ്റ് താളുകൾ മീഡിയവിക്കി: നാമമേഖലയിലോ ഉപയോക്തൃ ഉപതാളായോ മാത്രം സൃഷ്ടിക്കുക",
+       "userlogout-continue": "താങ്കൾ പുറത്ത് കടക്കാൻ ആഗ്രഹിക്കുന്നുവെങ്കിൽ [$1 ലോഗ് ഔട്ട് താളിലേക്ക് തുടരുക].",
+       "userlogout-sessionerror": "സെഷൻ പിഴവ് ഉണ്ടായതിനാൽ ലോഗ് ഔട്ട് പരാജയപ്പെട്ടു. ദയവായി [$1 വീണ്ടും ശ്രമിക്കുക]."
 }
index 291b7c9..24014e5 100644 (file)
@@ -21,7 +21,7 @@
                ]
        },
        "tog-underline": "Линкүүдийн доогуур зураас зур:",
-       "tog-hideminor": "Сүүлийн өөрчлөлтүүд дахь бага зэргийн засваруудыг нуух",
+       "tog-hideminor": "Сүүлийн өөрчлөлтүүд дэх бага зэргийн засваруудыг нуух",
        "tog-hidepatrolled": "Сүүлийн өөрчлөлтүүдэд манагдсан засваруудыг нуух",
        "tog-newpageshidepatrolled": "Шинэ хуудсуудын жагсаалтаас манагдаж буй хуудсуудыг нуух",
        "tog-extendwatchlist": "Хянах жагсаалтаа сүүлийн л засваруудыг бус бүх засварыг харуулахаар томруулах",
        "tog-numberheadings": "Гарчигуудыг автоматаар дэс дугаарлах",
        "tog-editondblclick": "Хоёр удаа дараад хуудсыг засварлах (ЖаваСкрипт)",
        "tog-editsectiononrightclick": "Хэсгийн гарчиг дээр баруун товчлуураар дарж засварладаг болгох (ЖаваСкрипт)",
-       "tog-watchcreations": "Ð\9cиний Ò¯Ò¯Ñ\81гÑ\8dÑ\81Ñ\8dн Ñ\85Ñ\83Ñ\83дÑ\81Ñ\83Ñ\83дÑ\8bг Ñ\85Ñ\8fнаÑ\85 Ð¶Ð°Ð³Ñ\81аалÑ\82анд Ð¾Ñ\80Ñ\83Ñ\83лаÑ\85",
-       "tog-watchdefault": "Ð\9cиний Ð·Ð°Ñ\81ваÑ\80лаÑ\81ан Ñ\85Ñ\83Ñ\83дÑ\81Ñ\83Ñ\83дÑ\8bг Ñ\85Ñ\8fнаÑ\85 Ð¶Ð°Ð³Ñ\81аалÑ\82анд Ð¾Ñ\80Ñ\83Ñ\83лаÑ\85",
-       "tog-watchmoves": "Ð\9cиний Ð·Ó©Ó©Ñ\81өн Ñ\85Ñ\83Ñ\83дÑ\81Ñ\83Ñ\83дÑ\8bг Ñ\85Ñ\8fнаÑ\85 Ð¶Ð°Ð³Ñ\81аалÑ\82анд Ð¾Ñ\80Ñ\83Ñ\83лаÑ\85",
-       "tog-watchdeletion": "Ð\9cиний Ñ\83Ñ\81Ñ\82гаÑ\81ан Ñ\85Ñ\83Ñ\83дÑ\81Ñ\83Ñ\83дÑ\8bг Ñ\85Ñ\8fнаÑ\85 Ð¶Ð°Ð³Ñ\81аалÑ\82анд Ð¾Ñ\80Ñ\83Ñ\83лаÑ\85",
+       "tog-watchcreations": "Миний үүсгэсэн хуудсуудыг хянах жагсаалтад оруулах",
+       "tog-watchdefault": "Миний засварласан хуудсуудыг хянах жагсаалтад оруулах",
+       "tog-watchmoves": "Миний зөөсөн хуудсуудыг хянах жагсаалтад оруулах",
+       "tog-watchdeletion": "Миний устгасан хуудсуудыг хянах жагсаалтад оруулах",
        "tog-minordefault": "Бүх засваруудаа бага зэргийн гэж автоматаар тэмдэглэх",
        "tog-previewontop": "Засварлах талбарын өмнө урьдчилж харсан байдлыг үзүүлэх",
        "tog-previewonfirst": "Эхний засварын үед урьдчилж харсан байдлыг үзүүлэх",
@@ -51,7 +51,7 @@
        "tog-watchlisthideliu": "Холбогдсон хэрэглэгчдээс хяналтын жагсаалт дахь засварыг нууцлах",
        "tog-watchlisthideanons": "Зочин хэрэглэгчдээс хяналтын жагсаалт дахь засваруудыг нуух",
        "tog-watchlisthidepatrolled": "Хянаж буй хуудсуудын жагсаалтаас манагдаж буй засваруудыг нуух",
-       "tog-ccmeonemails": "Бусад хэрэглэгчдэд явуулсан мэйлүүдыг над руу давхар илгээх",
+       "tog-ccmeonemails": "Бусад хэрэглэгчдэд явуулсан мэйлүүдийг над руу давхар илгээх",
        "tog-diffonly": "Өөрчлөлтөөс доогуурх хуудсын агуулгыг үзүүлэхгүй байх",
        "tog-showhiddencats": "Нуугдсан ангиллуудыг үзүүлэх",
        "tog-norollbackdiff": "Буцаасны дараа өөрчлөлтийг орхигдуулах",
@@ -59,7 +59,7 @@
        "tog-prefershttps": "Нэвтэрсэн үедээ үргэлж найдвартай сүлжээ хэрэглэнэ үү",
        "underline-always": "Байнга",
        "underline-never": "Хэзээ ч үгүй",
-       "underline-default": "Ð\92Ñ\8dб хөтөчийн үндсэн тохиргоо",
+       "underline-default": "ЦаÑ\85им хөтөчийн үндсэн тохиргоо",
        "editfont-style": "Засварлах талбарын фонт хэв маяг:",
        "editfont-monospace": "Нэг өргөнт фонт",
        "editfont-sansserif": "Санс-сериф фонт",
        "october-date": "Аравдугаар сарын $1",
        "november-date": "Арван нэгдүгээр сарын $1",
        "december-date": "Арван хоёрдугаар сарын $1",
-       "pagecategories": "{{PLURAL:$1|Анги|Ангилал}}",
+       "pagecategories": "{{PLURAL:$1|Ангилал|Ангилал}}",
        "category_header": "\"$1\" ангийн дан хуудас",
        "subcategories": "Ангийн бүлэг",
        "category-media-header": "\"$1\" ангийн файл",
-       "category-empty": "''Одоогоор энэ ангид хуудас, зургийн аль нь ч алга.''",
-       "hidden-categories": "{{PLURAL:$1|Нуугдсан анги|Нуугдсан ангиуд}}",
+       "category-empty": "''Ð\9eдоогооÑ\80 Ñ\8dнÑ\8d Ð°Ð½Ð³Ð¸Ð»Ð°Ð»Ð´ Ñ\85Ñ\83Ñ\83даÑ\81, Ð·Ñ\83Ñ\80гийн Ð°Ð»Ñ\8c Ð½Ñ\8c Ñ\87 Ð°Ð»Ð³Ð°.''",
+       "hidden-categories": "{{PLURAL:$1|Нуугдсан ангилал|Нуугдсан ангиллууд}}",
        "hidden-category-category": "Нуугдсан ангиллууд",
        "category-subcat-count": "{{PLURAL:$2|Тус ангид дараах ангийн хуудсууд хамаарна.|Тус ангид дараах $2 ангийн хуудсууд хамаарна.}}",
        "category-subcat-count-limited": "Энэ ангилалд {{PLURAL:$1| дэд ангилал|$1-н дэд ангилалууд}} байна.",
        "minoreditletter": "б",
        "newpageletter": "Ш",
        "boteditletter": "р",
-       "number_of_watching_users_pageview": "[$1 хэрэглэгч харж байна]",
        "rc-change-size-new": "Өөрчилсний дараа $1 {{PLURAL:$1|байт|байт}}",
        "newsectionsummary": "/* $1 */ шинэ хэсэг",
        "rc-enhanced-expand": "Дэлгэрэнгүй мэдээллийг үзүүлэх (ЖаваСкрипт хэрэглэгдэнэ)",
        "img-auth-nopathinfo": "PATH_INFO байхгүй байна.\nЭнэхүү мэдээллийг явуулахад сервер тань тохирогдоогүй байна.\nCGI-д тулгуурласан ба img_auth-г дэмжихгүй байж магадгүй.\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization -г харна уу.",
        "img-auth-notindir": "Тохируулсан оруулалтын директорид таны хүссэн зам байхгүй байна.",
        "img-auth-badtitle": "\"$1\"-с хүчинтэй гарчиг үүсгэж чадсангүй.",
-       "img-auth-nologinnWL": "Та нэвтрээгүй байгаа бөгөөд \"$1\" нь цагаан дансанд байхгүй байна.",
        "img-auth-nofile": "\"$1\" гэсэн файл байхгүй байна.",
        "img-auth-isdir": "Та \"$1\" гэсэн директорид хандах гэж оролдож байна.\nФайлын хандалт л зөвшөөрөгдөнө.",
        "img-auth-streaming": "\"$1\"-г тоглуулж байна.",
        "allmessagesdefault": "Анхны",
        "allmessagescurrent": "Одоогийн",
        "allmessagestext": "Энэ бол МедиаВики дахь системийн мэдэгдлүүдийн жагсаалт юм.\nМедиаВикиг орчуулах тухай мэдээллийг [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation МедиаВикигийн орчуулга], мөн [https://translatewiki.net translatewiki.net]-с авна уу.",
-       "allmessagesnotsupportedDB": "'''$wgUseDatabaseMessages''' нь унтарсан байгаа тул '''Special:Allmessages'''-г хэрэглэж болохгүй.",
+       "allmessages-not-supported-database": "'''$wgUseDatabaseMessages''' нь унтарсан байгаа тул '''Special:Allmessages'''-г хэрэглэж болохгүй.",
        "allmessages-filter-legend": "Шүүлтүүр",
        "allmessages-filter": "Өөрийн болгосон байдлаар нь шүүх:",
        "allmessages-filter-unmodified": "Өөрчлөөгүй",
index 1121a06..a235330 100644 (file)
        "site-atom-feed": "$1 ဒၞာဲ ဗလးပတိတ်",
        "page-rss-feed": "\"$1\" RSS feed",
        "page-atom-feed": "\"$1\" ဒၞာဲ ဗလးပတိတ်",
-       "red-link-title": "$1(á\80\99á\80¯á\80\80á\80ºá\80\9cá\80\9d်ဏအ် ဟွံပြာကတ်)",
+       "red-link-title": "$1(á\80\99á\80¯á\80\80á\80ºá\80\9cá\80­á\80\80်ဏအ် ဟွံပြာကတ်)",
        "sort-descending": "လၟေၚ်မစှေ်ကၠုၚ်ဒၟံၚ်",
        "sort-ascending": "လၟေၚ်မတိုန်ကၠုၚ်ဒၟံၚ်",
        "nstab-main": "မုက်လိက်",
        "accmailtitle": "ပြံၚ်ဏာ မအက္ခရ်ဗၞုက်",
        "newarticle": "(တၟိ)",
        "newarticletext": "မၞး စိုပ်အာ ဇရေင် မုက်လိက်လေန် မဟွံဂွံကၠောန်လဝ်ဏီရ၊၊\nသွက်ဂွံ ခၞံကၠောန် မုက်လိက်ဏအ်ဂှ် ပ္ဍဲခံက်အင် ဗွဲသၟဝ်ဏအ်ဂှ် စတက်စုတ် မလိက်ညိ\n(မိက်ဂွံ ဆက်တီ ပရူဏအ်မ္ဂး ဆက်ကျောဝ် ပ္ဍဲ[$1မုက်လိက်အရီုအဗင်]ညိ)။ ဟိုတ်နူဗၠေတ်တုဲ မၞး စိုပ်ကၠုင် ပ္ဍဲဒၞာဲဏအ်မ္ဂး ဍဵု <strong>back</strong> တုဲ ကလေင်အာ ဒၞာဲတြေံညိ၊၊",
-       "anontalkpagetext": "----\n<em>မုက်လိက်ဏအ်ဂှ် ဒှ်ဒၞာဲ သွက်မၞိဟ် မဟွံဗမံက်ယၟု၊ မၞိဟ်ဟွံဂွံကၠောန်လဝ် အကံက်တအ်ဏီ ဂွံပတိုန်လညာတ် ပါ်ပဲါရ၊၊</em>\nဟိုတ်ဂှ်ရ ပိုယ်ဒးစကာ မဂၞန် IP address သွက်ဂွံ တီညးတအ်ရ၊၊ IP address ဗီုဏအ်မွဲမွဲဂှ် ပါ်ပရအ်ဂွံ ညးလွပ် ဗွဲမဂၠိုင်ရ၊၊ ယဝ်ရ မၞးဂှ် ဒှ်ညးလွပ် မဟွံဗမံက်ယၟုမွဲ စှ်ေစိုတ် တင်ဂလာန်တအ်ဏအ်ဂှ် ဒှ်ဟွံထေက်မ္ဂး ပဂုန်တုဲ [[Special:CreateAccount|ခၞံကၠောန် အကံက်မွဲ]] ဟွံသေင်မ္ဂး [[Special:UserLogin|လုပ်လံက်အေန်]] သွက်ဂွံ ဝေင်ပဲါ ညးလွပ် မဟွံဗမံက်ယၟုတအ်တၞဟ်တအ်ရ၊၊",
+       "anontalkpagetext": "----\n<em>မုက်လိက်ဏအ်ဂှ် ဒှ်ဒၞာဲ သွက်မၞိဟ် မဟွံဗမံက်ယၟု၊ မၞိဟ်ဟွံဂွံကၠောန်လဝ် အကံက်တအ်ဏီ ဂွံပတိုန်လညာတ် ပါ်ပဲါရ၊၊</em>\nဟိုတ်ဂှ်ရ ပိုယ်ဒးစကာ မဂၞန် IP address သွက်ဂွံ တီ ညးတအ်ရ၊၊ IP address ဗီုဏအ်မွဲမွဲဂှ် ပါ်ပရအ်ဂွံ ညးလွပ် ဗွဲမဂၠိုင်ရ၊၊ ယဝ်ရ မၞးဂှ် ဒှ်ညးလွပ် မဟွံဗမံက်ယၟုမွဲတုဲ စှ်ေစိုတ် တင်ဂလာန်တအ်ဏအ်ဂှ် ဒှ်ဟွံထေက်မ္ဂး ပဂုန်တုဲ [[Special:CreateAccount|ခၞံကၠောန် အကံက်မွဲ]] ဟွံသေင်မ္ဂး [[Special:UserLogin|လုပ်လံက်အေန်]] သွက်ဂွံ ဝေင်ပဲါ ညးလွပ် မဟွံဗမံက်ယၟုတအ်တၞဟ်တအ်ရ၊၊",
        "noarticletext": "ပ္ဍဲမုက်လိက်ဏအ် လိက်ဟွံမွဲဏီရ၊၊\nမၞး ဂၠာဲကေတ်  [[Special:Search/{{PAGENAME}}|search for this page title]] ပ္ဍဲမုက်လိက်တၞဟ်မ္ဂး ကလိဂွံမာန်ရောင်၊၊\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} search the related logs],\nဟွံသေင်မ္ဂး  [{{fullurl:{{FULLPAGENAME}}|action=edit}} ခၞံကၠောန် လိက်မုက်ဏအ်ညိ၊၊]</span>.",
        "noarticletext-nopermission": "ပ္ဍဲမုက်လိက်ဏအ် လိက်ဟွံမဲဏီရ၊၊ မၞး ဂၠာဲကေတ် [[Special:Search/{{PAGENAME}}|search for this page title]] ပ္ဍဲမုက်လိက်တၞဟ်၊ ဟွံသေင်မ္ဂး ကလိဂွံမာန်ရ၊၊ <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} search the related logs]</span>, ဆဂး မၞးအခေါင် ခၞံကၠောန် မုက်လိက်ဏအ် ဟွံမဲ၊၊",
        "userpage-userdoesnotexist": "အကံက်ညးလွပ်$1ဂှ်ဟွံသ္ပလဝ်စၟတ်သမ္တီရ.\nသ္ပဂုဏ်တုဲစၟဳစၟတ်ရံၚ် ယဝ်ရမၞးမိက်ဂွံခၞံကၠောန်/ဒါန်မုက်လိက်ဏအ်.",
        "page_first": "ကိုပ်ကၠာ",
        "page_last": "ကြဴ",
        "histlegend": "တၞဟ်န ဂွံပတောအ်ၜတ် အကြာမူမပလေဝ်ဒါန်လဝ်တအ်ဂှ် ကဵုစၟတ် ပ္ဍဲခံက်အင်ရေဒဳယော radio boxes တုဲ ဍဵုenter ဟွံသေင်မ္ဂး ဍဵု ကောန်ဍေင် သၟဝ်ဂှ်ညိ၊၊ <br />Legend: <strong>({{int:cur}})</strong> = အရာမတၞဟ်ခြာ ကုမူလက္ကရဴအိုတ် <strong>({{int:last}})</strong> = အရာမတၞဟ်ခြာ ကုမူကၠာနူဂှ်၊၊ <strong>{{int:minoreditletter}}</strong> = မပလေဝ်ဒါန်လဝ် ညိည၊၊",
-       "history-fieldset-title": "á\80\82á\81 á\80¬á\80² á\80\99á\80°á\80\90á\80¼á\80±á\80ဂမၠိုင်",
+       "history-fieldset-title": "á\80\96á\80\8dá\80­á\80¯á\80\9fá\80º á\80¡á\80\9bá\80¬á\80\99á\80\95á\80\9cá\80±á\80\9dá\80ºá\80\9cá\80\9dá\80ºဂမၠိုင်",
        "histfirst": "တြေံအိုတ်",
        "histlast": "တၟိအိုတ်",
        "historysize": "({{PLURAL:$1|1 ဘာ်|$1 ဘာ်ဂမၠိုၚ်}})",
        "rcfilters-filter-pageedits-label": "စာမျက်နှာ တည်းဖြတ်မှုများ",
        "rcfilters-filter-newpages-label": "မခၞံကၠောန် မုက်လိက်",
        "rcfilters-filter-categorization-label": "လှာဲ ကဏ္ဍ",
-       "rcfilters-filtergroup-lastRevision": "မူမဒါန်လဝ် လက္ကရဴအိုတ်ဂမၠိုၚ်",
+       "rcfilters-filtergroup-lastrevision": "မူမဒါန်လဝ် လက္ကရဴအိုတ်ဂမၠိုၚ်",
        "rcfilters-filter-lastrevision-label": "မူမဒါန်လဝ် လက္ကရဴအိုတ်",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:ဟွံသေၚ်</strong> $1",
        "rcfilters-target-page-placeholder": "စုတ်ယၟုမုက်လိက် (ဟွံသေၚ် ကဏ္ဍ)",
        "sp-contributions-toponly": "ထ္ၜး အရာမပလေဝ်ဒါန်လဝ် လက္ကရဴအိုတ်ဂှ် ဟေင်ညိ",
        "sp-contributions-newonly": "ထ္ၜး မုက်လိက်မခၞံကၠောန်လဝ် ကၠာအိုတ်ဂှ် ဟေင်ညိ",
        "sp-contributions-submit": "ဂၠာဲ",
-       "whatlinkshere": "မု အဆက်အစပ် ကုအရာဂှ်",
+       "whatlinkshere": "မု အဆက်အစပ် ကုအရာဂှ်ရော",
        "whatlinkshere-title": "မုက်လိက် မဆက်လေန်လဝ် ကု \"$1\"",
        "whatlinkshere-page": "မုက်လိက် -",
        "linkshere": "မုက်လိက် ဗွဲသၟဝ်ဝွံ ဆက်စပ် ကဵု<strong>$2</strong>:",
index 615d474..eacae39 100644 (file)
        "rcfilters-filter-editsbyself-description": "आपली स्वतःची संपादने",
        "rcfilters-filter-editsbyother-label": "इतरांचे बदल",
        "rcfilters-filter-editsbyother-description": "आपल्या स्वतःच्या संपादनांशिवायचे सर्व बदल.",
-       "rcfilters-filtergroup-userExpLevel": "सदस्य नोंदणी व अनुभवाचा स्तर",
+       "rcfilters-filtergroup-user-experience-level": "सदस्य नोंदणी व अनुभवाचा स्तर",
        "rcfilters-filter-user-experience-level-registered-label": "नोंदणीकृत",
        "rcfilters-filter-user-experience-level-registered-description": "प्रवेशलेले संपादक.",
        "rcfilters-filter-user-experience-level-unregistered-label": "अ-नोंदणीकृत",
        "rcfilters-filter-categorization-description": "वर्गात जोडलेल्या अथवा वर्गातुन हटविलेल्या पानांच्या नोंदी.",
        "rcfilters-filter-logactions-label": "प्रवेशित क्रिया",
        "rcfilters-filter-logactions-description": "प्रशासकीय क्रिया, खाते निर्माण, पान वगळणे, अपभारणे...",
-       "rcfilters-filtergroup-lastRevision": "अद्यतनीत आवृत्त्या",
+       "rcfilters-filtergroup-lastrevision": "अद्यतनीत आवृत्त्या",
        "rcfilters-filter-lastrevision-label": "अद्यतनीत आवृत्ती",
        "rcfilters-filter-lastrevision-description": "एखाद्या पानातील सर्वात अलीकडील बदल.",
        "rcfilters-filter-previousrevision-label": "अद्यतनीत आवृत्ती नाही",
        "minoreditletter": "छो.ब.",
        "newpageletter": "न.पा.",
        "boteditletter": "सां.",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|सदस्याने|सदस्यांनी}} पहारा दिलेला आहे]",
        "rc-change-size-new": " बदलानंतर $1 {{PLURAL:$1|बाईट|बाईटस्}}",
        "newsectionsummary": "/* $1 */ नवीन विभाग",
        "rc-enhanced-expand": "तपशील दाखवा",
        "img-auth-nopathinfo": "मार्ग माहिती आढळली नाही.\nआपला सर्व्हर ही माहिती देण्यास अनुनत नाही.\nतो सीजीआय-आधारित व इमेज_ऑथला समर्थन न देऊ शकणारा असू शकतो.\nकृपया https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization  हे पहा.",
        "img-auth-notindir": "विनंती केलेला मार्ग अपभारण शब्दकोशाकरीता रचित नाही.",
        "img-auth-badtitle": "\"$1\" पासून वैध शीर्षक बनवण्यात अयशस्वी.",
-       "img-auth-nologinnWL": "तुम्ही प्रवेश घेतलेला नाही व \"$1\" श्वेतयादीत नाही.",
        "img-auth-nofile": "\"$1\" ही संचिका अस्तित्वात नाही.",
        "img-auth-isdir": "तुम्ही \"$1\" निदेशक वापरण्याचा प्रयत्न करत आहात.\nफक्त संचिका वापरण्याची परवानगी आहे.",
        "img-auth-streaming": "स्ट्रीमिंग \"$1\".",
        "allmessagesdefault": "अविचल संदेश मजकूर",
        "allmessagescurrent": "सध्याचा मजकूर",
        "allmessagestext": "मिडियाविकी नामविश्वात उपलब्ध सर्व प्रणाली संदेशांची ही यादी आहे. जर आपणास मिडियाविकि प्रजाति स्थानिकिकरणात योगदान करावयाचे असेल तर कृपया [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation मिडियाविकि स्थानिकीकरण] व [https://translatewiki.net ट्रांसलेटविकि.नेट]  ला भेट द्या.",
-       "allmessagesnotsupportedDB": "हे पान संपादित करता येत नाही कारण<strong>$wgUseDatabaseMessages</strong>अक्षम  आहे.",
+       "allmessages-not-supported-database": "हे पान संपादित करता येत नाही कारण<strong>$wgUseDatabaseMessages</strong>अक्षम  आहे.",
        "allmessages-filter-legend": "गाळक",
        "allmessages-filter": "कस्टमायझेशन स्टेटनुसार गाळणी लावा :",
        "allmessages-filter-unmodified": "असंपादित",
index 62e2047..c7e5cb1 100644 (file)
        "rightslogtext": "Ini ialah log perubahan terhadap hak pengguna.",
        "action-read": "membaca laman ini",
        "action-edit": "menyunting laman ini",
-       "action-createpage": "mencipta laman",
-       "action-createtalk": "mencipta laman perbincangan",
+       "action-createpage": "ciptakan laman ini",
+       "action-createtalk": "ciptakan laman perbincangan ini",
        "action-createaccount": "mencipta akaun pengguna ini",
        "action-history": "melihat sejarah halaman ini",
        "action-minoredit": "menanda suntingan ini sebagai suntingan kecil",
        "rcfilters-savedqueries-add-new-title": "Simpan tetapan penapis terkini",
        "rcfilters-show-new-changes": "Lihat perubahan terkini",
        "rcfilters-search-placeholder": "Penapis perubahan (guna menu atau carian untuk menapis nama)",
-       "rcfilters-filtergroup-userExpLevel": "Pendaftaran dan pengalaman pengguna",
+       "rcfilters-filtergroup-user-experience-level": "Pendaftaran dan pengalaman pengguna",
        "rcfilters-filter-user-experience-level-unregistered-label": "Tidak terdaftar",
        "rcfilters-filter-user-experience-level-unregistered-description": "Penyunting yang tidak log masuk.",
        "rcfilters-filter-humans-label": "Manusia (bukan bot)",
        "newpageletter": "B",
        "boteditletter": "b",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 pemantau]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 bait selepas perubahan",
        "newsectionsummary": "/* $1 */ bahagian baru",
        "img-auth-nopathinfo": "PATH_INFO tertinggal.\nPelayan anda tidak ditetapkan untuk menyampaikan maklumat ini.\nIa barangkali berdasarkan CGI dan tidak boleh menyokong img_auth.\nRujuk https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization",
        "img-auth-notindir": "Laluan yang diminta tiada dalam direktori muat naik yang telah dikonfigurasikan.",
        "img-auth-badtitle": "Tajuk yang sah tidak dapat dibina daripada \"$1\".",
-       "img-auth-nologinnWL": "Anda belum log masuk dan \"$1\" tiada dalam senarai putih.",
        "img-auth-nofile": "Fail \"$1\" tiada.",
        "img-auth-isdir": "Anda telah mencuba mencapai direktori \"$1\". Hanya capaian fail dibenarkan.",
        "img-auth-streaming": "\"$1\" sedang disalurkan.",
        "allmessagesdefault": "Teks mesej asal",
        "allmessagescurrent": "Teks pesanan semasa",
        "allmessagestext": "Ini ialah senarai pesanan sistem yang terdapat dalam ruang nama MediaWiki.\nSila lawat [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Penyetempatan MediaWiki] dan [https://translatewiki.net translatewiki.net] sekiranya anda mahu menyumbang dalam menyetempatkan dan menterjemah perisian MediaWiki.",
-       "allmessagesnotsupportedDB": "'''{{ns:special}}:Allmessages''' tidak boleh digunakan kerana '''$wgUseDatabaseMessages''' dipadamkan.",
+       "allmessages-not-supported-database": "'''{{ns:special}}:Allmessages''' tidak boleh digunakan kerana '''$wgUseDatabaseMessages''' dipadamkan.",
        "allmessages-filter-legend": "Penapisan",
        "allmessages-filter": "Tapis berdasarkan keadaan penempahan:",
        "allmessages-filter-unmodified": "Tidak diubah",
index ef34e3c..fb4628a 100644 (file)
        "minoreditletter": "m",
        "newpageletter": "Ġ",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[osservat minn {{PLURAL:$1|$1 utent|$1 utent}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} wara l-modifika",
        "newsectionsummary": "/* $1 */ sezzjoni ġdida",
        "rc-enhanced-expand": "Uri d-dettalji",
        "img-auth-nopathinfo": "PATH_INFO nieqes.\nIs-server tiegħek mhuwiex issettjat sabiex jgħaddi din l-informazzjoni.\nJista' jkun li huwa bbażat fuq CGI u ma jistax isostni img_auth.\nŻur https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Id-destinazzjoni rikjesta mhijiex fid-direttorju tat-tlugħ konfigurat.",
        "img-auth-badtitle": "Ma setax jinbena titlu validu minn \"$1\".",
-       "img-auth-nologinnWL": "M'intix fil-kont tiegħek u \"$1\" mhuwiex fil-lista l-bajda.",
        "img-auth-nofile": "Il-fajl \"$1\" ma jeżistix.",
        "img-auth-isdir": "Qiegħed tipprova taċċessa direttorju \"$1\".\nHuwa permess biss l-aċċess għal fajls.",
        "img-auth-streaming": "\"$1\" qiegħed fi ''streaming''.",
        "allmessagesdefault": "Test predefinit",
        "allmessagescurrent": "It-test attwali",
        "allmessagestext": "Din hija lista ta' messaġġi tas-sistema disponibbli fl-ispazju tal-isem MediaWiki.",
-       "allmessagesnotsupportedDB": "Il-paġna ma tistax tintuża għax '''$wgUseDatabaseMessages''' mhux attivat.",
+       "allmessages-not-supported-database": "Il-paġna ma tistax tintuża għax '''$wgUseDatabaseMessages''' mhux attivat.",
        "allmessages-filter-legend": "Filtru",
        "allmessages-filter": "Iffilitra skont l-istat ta' modifika:",
        "allmessages-filter-unmodified": "Mhux modifikati",
index a814420..0272ac0 100644 (file)
@@ -72,6 +72,7 @@
        "tog-norollbackdiff": "နောက်ပြန်ပြင်ဆင်ခြင်း လုပ်ဆောင်ပြီးပါက ကွဲပြားမှုကိုမပြပါနှင့်။",
        "tog-useeditwarning": "မသိမ်းရသေးသော ပြောင်းလဲမှုများ နှင့် တည်းဖြတ်ဆဲစာမျက်နှာမှ ထွက်သွားလျှင် သတိပေးပါ",
        "tog-prefershttps": "လော့ဂ်အင်ဝင်ချိန်တွင် လုံခြုံသော ဆက်သွယ်မှုကို အမြဲတမ်း အသုံးပြုရန်",
+       "tog-showrollbackconfirmation": "နောက်ပြန် ပြန်သွားရန်လင့်ခ်ကို နှိပ်သောအခါ အတည်ပြုချက်တောင်းခံပုံအား ပြသရန်",
        "underline-always": "အမြဲ",
        "underline-never": "ဘယ်သောအခါမျှ",
        "underline-default": "ဘရောက်ဆာ သို့ Skin default အတိုင်း",
        "changeemail-submit": "အီးမေးလ်ပြောင်းလဲရန်",
        "changeemail-throttled": "သင်သည် login ဝင်ရန် အကြိမ်မြောက်မြားစွာ ပြုလုပ်ခဲ့ပြီးဖြစ်သည်။\nကျေးဇူးပြု၍ ထပ်မဝင်ခင် $1 စောင့်ပေးပါ။",
        "changeemail-nochange": "မတူညီသော အီးမေးလ်လိပ်စာအသစ်ကို ကျေးဇူးပြု၍ ရိုက်ထည့်ပါ။",
+       "resettokens": "တိုကင်များကို ပြန်လည်ချိန်ညှိမည်",
+       "resettokens-tokens": "တိုကင်များ-",
        "resettokens-token-label": "$1 (လက်ရှိတန်ဖိုး: $2)",
        "resettokens-resetbutton": "ရွေးချယ်ထားသော တိုကင်များကို ပြန်ချိန်ရန်",
        "bold_sample": "စာလုံးမည်း",
        "copyrightwarning": "{{SITENAME}} တွင် ရေးသားမှုအားလုံးကို $2 အောက်တွင် ဖြန့်ဝေရန် ဆုံးဖြတ်ပြီး ဖြစ်သည်ကို ကျေးဇူးပြု၍ သတိပြုပါ။။ (အသေးစိတ်ကို $1 တွင်ကြည့်ပါ။)\nအကယ်၍ သင့်ရေးသားချက်များကို အညှာအတာမရှိ တည်းဖြတ်ခံရခြင်း၊ စိတ်တိုင်းကျ ဖြန့်ဝေခံရခြင်းတို့ကို အလိုမရှိပါက ဤနေရာတွင် မတင်ပါနှင့်။<br />\nသင်သည် ဤဆောင်းပါးကို သင်ကိုယ်တိုင်ရေးသားခြင်း၊ သို့မဟုတ် အများပြည်သူဆိုင်ရာဒိုမိန်းများ၊ ယင်းကဲ့သို့ လွတ်လပ်သည့် ရင်းမြစ်မှ ကူးယူထားခြင်း ဖြစ်ကြောင်းလည်း ဝန်ခံ ကတိပြုပါသည်။\n<strong>မူပိုင်ခွင့်ရှိသော စာ၊ပုံများကို ခွင့်ပြုချက်မရှိဘဲ မတင်ပါနှင့်။</strong>",
        "copyrightwarning2": "{{SITENAME}} တွင် ရေးသားမှုအားလုံးသည် အခြားပုံပိုးသူများ၏ တည်းဖြတ်၊ ပြောင်းလဲ၊ ဖယ်ရှားခံရနိုင်သည်ကို သတိပြုပါ။\nအကယ်၍ သင့်ရေးသားချက်များကို အညှာအတာမရှိ တည်းဖြတ်ခံရခြင်း၊ စိတ်တိုင်းကျ ဖြန့်ဝေခံရခြင်းတို့ကို အလိုမရှိပါက ဤနေရာတွင် မတင်ပါနှင့်။<br />\nသင်သည် ဤဆောင်းပါးကို သင်ကိုယ်တိုင်ရေးသားခြင်း၊ သို့မဟုတ် အများပြည်သူဆိုင်ရာဒိုမိန်းများ၊ ယင်းကဲ့သို့ လွတ်လပ်သည့် ရင်းမြစ်မှ ကူးယူထားခြင်း ဖြစ်ကြောင်းလည်း ဝန်ခံ ကတိပြုပါသည် (အသေးစိတ်ကို $1 တွင်ကြည့်ပါ)။\n<strong>မူပိုင်ခွင့်ရှိသော စာ၊ပုံများကို ခွင့်ပြုချက်မရှိဘဲ မတင်ပါနှင့်။</strong>",
        "editpage-cannot-use-custom-model": "ဤစာမျက်နှာ၏ မာတိကာမော်ဒယ်ကို မပြောင်းလဲနိုင်ခဲ့ပါ။",
+       "readonlywarning": "<strong>သတိပေးချက်: ပြုပြင်ထိန်းသိမ်းရေးအတွက် ဒေတာဘေ့စ်ကို ပိတ်ထားလိုက်ပါပြီ၊ ယခုလက်ရှိ တည်းဖြတ်နိုင်တာ့မည် မဟုတ်ပါ။</strong>\n\n\nယင်းအားပိတ်ခဲ့သည့် စနစ်အက်ဒမင်က ဤရှင်းပြချက်ကို ပေးထားပါသည်: $1",
        "protectedpagewarning": "<strong>သတိပေးချက်။ ဤစာမျက်နှာအား စီမံခန့်ခွဲသူအဆင့်ရှိသူများသာ ပြင်ဆင်နိုင်ရန် ကာကွယ်ထားသည်။</strong>\nနောက်ဆုံးမှတ်တမ်းအား ကိုးကားနိုင်ရန် အောက်တွင် ဖော်ပြထားသည်။",
        "semiprotectedpagewarning": "<strong>မှတ်ချက်။</strong> ဤစာမျက်နှာအား အလိုအလျောက် အတည်ပြုထားသော အသုံးပြုသူအဆင့်ရှိသူများသာ တည်းဖြတ်နိုင်ရန် ကာကွယ်ထားသည်။\nနောက်ဆုံးမှတ်တမ်းအား ကိုးကားနိုင်ရန် အောက်တွင် ဖော်ပြထားသည်။",
        "titleprotectedwarning": "<strong>သတိပေးချက်။ ဤစာမျက်နှာကို ကာကွယ်ထားပြီး ဖန်တီးနိုင်ရန်အတွက် [[Special:ListGroupRights|အထူး အခွင့်အရေးများ]]ရှိထားရန် လိုအပ်သည်။</strong>\nနောက်ဆုံးမှတ်တမ်းအား ကိုးကားနိုင်ရန် အောက်တွင် ဖော်ပြထားသည်။",
        "editpage-invalidcontentmodel-text": "မာတိကာမော်ဒယ် \"$1\" သည် မထောက်ပံ့ထားပါ။",
        "editpage-notsupportedcontentformat-title": "မာတိကာပုံစံသည် မထောက်ပံ့ထားပါ",
        "editpage-notsupportedcontentformat-text": "မာတိကာပုံစံ $1 အား မာတိကာမော်ဒယ် $2 မှ မထောက်ပံ့ထားပါ။",
+       "slot-name-main": "ပင်မ",
        "content-model-wikitext": "ဝီကီစာသား",
        "duplicate-args-category": "တမ်းပလိတ်တွင်းရှိ arguments ထပ်နေသော စာမျက်နှာများ",
        "post-expand-template-inclusion-warning": "'''သတိပေးချက် -''' တမ်းပလိတ်အရွယ်အစား ကြီးလွန်းနေသည်။\nအချို့တမ်းပလိတ်တို့ ပါဝင်မည်မဟုတ်။",
        "histfirst": "အဟောင်းဆုံး",
        "histlast": "အသစ်ဆုံး",
        "historysize": "({{PLURAL:$1|1 ဘိုက်|$1 ဘိုက်}})",
-       "historyempty": "(ဘာမှမရှိ)",
+       "historyempty": "ဘာမှမရှိ",
        "history-feed-title": "မူရာဇဝင်မှတ်တမ်း",
        "history-feed-description": "ဝီကီပေါ်ရှိ ဤစာမျက်နှာ၏ တည်းဖြတ်မှုရာဇဝင်",
        "history-feed-item-nocomment": "$2 က $1",
        "prefs-watchlist-edits": "စောင့်ကြည့်စာရင်းတွင် ပြရန် အပြောင်းအလဲတို့၏ အများဆုံး အရေအတွက်",
        "prefs-watchlist-edits-max": "အများဆုံးအရေအတွက် - ၁ဝဝဝ",
        "prefs-watchlist-token": "စောင့်ကြည့်စာရင်း တိုကင် -",
+       "prefs-watchlist-managetokens": "တိုကင်များကို စီမံခန့်ခွဲရန်",
        "prefs-misc": "အသေးအမွှား",
        "prefs-resetpass": "စကားဝှက် ပြောင်းရန်",
        "prefs-changeemail": "အီးမေးလိပ်စာ ပြင်ဆင် သို့ ဖယ်ရှားရန်",
        "rcfilters-filter-editsbyself-description": "သင်၏ ဆောင်ရွက်ချက်များ။",
        "rcfilters-filter-editsbyother-label": "အခြားသူများ၏ ပြောင်းလဲမှုများ",
        "rcfilters-filter-editsbyother-description": "သင့်ဆောင်ရွက်ချက်များမှ လွဲ၍ ပြောင်းလဲမှုများ အားလုံး။",
-       "rcfilters-filtergroup-userExpLevel": "အသုံးပြုသူ မှတ်ပုံတင်ထားခြင်းနှင့် အတွေ့အကြုံ",
+       "rcfilters-filtergroup-user-experience-level": "အသုံးပြုသူ မှတ်ပုံတင်ထားခြင်းနှင့် အတွေ့အကြုံ",
        "rcfilters-filter-user-experience-level-registered-label": "မှတ်ပုံတင်ထားသူ",
        "rcfilters-filter-user-experience-level-registered-description": "အကောင့်ဝင်ထားသည့် တည်းဖြတ်သူများ။",
        "rcfilters-filter-user-experience-level-unregistered-label": "မှတ်ပုံမတင်ထားသူ",
        "rcfilters-filter-categorization-description": "ကဏ္ဍများထဲသို့ စာမျက်နှာများ ပေါင်းထည့်ခြင်း သို့ ဖယ်ရှားခြင်း မှတ်တမ်းများ။",
        "rcfilters-filter-logactions-label": "အကောင့်ဝင်ထားသည့် ပြုလုပ်ချက်များ",
        "rcfilters-filter-logactions-description": "စီမံခန့်ခွဲရေး ပြုလုပ်ချက်များ၊ အကောင့် ဖန်တီးမှုများ၊ စာမျက်နှာ ဖျက်ခြင်းများ၊ ဖိုင်တင်ခြင်းများ...",
-       "rcfilters-filtergroup-lastRevision": "နောက်ဆုံး တည်းဖြတ်မူများ",
+       "rcfilters-filtergroup-lastrevision": "နောက်ဆုံး တည်းဖြတ်မူများ",
        "rcfilters-filter-lastrevision-label": "နောက်ဆုံး တည်းဖြတ်မူ",
        "rcfilters-filter-lastrevision-description": "စာမျက်နှာတစ်ခု၏ နောက်ဆုံးအကျဆုံး ပြောင်းလဲမှုသာလျှင်။",
        "rcfilters-filter-previousrevision-label": "နောက်ဆုံး တည်းဖြတ်မူမဟုတ်",
        "minoreditletter": "အရေးမကြီး",
        "newpageletter": "အသစ်",
        "boteditletter": "ဘော့",
-       "number_of_watching_users_pageview": "[စောင့်ကြည့်နေသော အသုံးပြုသူ $1 {{PLURAL:$1|ဦး|ဦး}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} ပြောင်းလဲပြီးနောက်",
        "newsectionsummary": "/* $1 */ အပိုင်းသစ်",
        "rc-enhanced-expand": "အသေးစိတ် ပြရန်",
        "allpages-hide-redirects": "ပြန်ညွှန်းများအား ဝှက်ရန်",
        "cachedspecial-viewing-cached-ttl": "သင်သည် $1 အချိန်ကြာသွားနိုင်သော ဤစာမျက်နှာ၏ cached ဗားရှင်းကို ကြည့်ရှုနေခြင်း ဖြစ်ပါသည်။",
        "cachedspecial-viewing-cached-ts": "သင်သည် ဤစာမျက်နှာ၏ အမှန်တကယ်မဟုတ်နိုင်သော cached ဗားရှင်းကို ကြည့်ရှုနေခြင်းဖြစ်သည်။",
+       "cachedspecial-refresh-now": "နောက်ဆုံးကို ကြည့်ရှုရန်။",
        "categories": "ကဏ္ဍများ",
        "categories-submit": "ပြသရန်",
        "categoriespagetext": "အောက်ပါ {{PLURAL:$1|ကဏ္ဍ|ကဏ္ဍများ}}သည် ဤဝီကီတွင် အသုံးပြု သို့မဟုတ် အသုံးမပြုထားခြင်း ဖြစ်နိုင်သည်။ [[Special:WantedCategories|အလိုရှိသော ကဏ္ဍများ]]ကိုလည်း ကြည့်ပါ။",
        "deleting-backlinks-warning": "<strong>သတိပေးချက်။</strong> သင်ဖျက်ပစ်တော့မည့် စာမျက်နှာအား [[Special:WhatLinksHere/{{FULLPAGENAME}}|အခြားစာမျက်နှာများမှ]] ချိတ်ဆက်ထားခြင်း သို့မဟုတ် ထည့်သွင်းထားခြင်း ရှိနေသည်။",
        "deleting-subpages-warning": "<strong>သတိပေးချက်။</strong> သင်ဖျက်တော့မည့် စာမျက်နှာတွင် [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|စာမျက်နှာခွဲ တစ်ခု|စာမျက်နှာခွဲ $1 ခု|51=စာမျက်နှာခွဲ ၅၀ ကျော်}}]] ရှိနေသည်။",
        "rollback": "နောက်ပြန်ပြင် တည်းဖြတ်မှုများ",
+       "rollback-confirmation-yes": "နောက်ပြန် ပြန်သွားရန်",
+       "rollback-confirmation-no": "မလုပ်တော့ပါ",
        "rollbacklink": "နောက်ပြန် ပြန်သွားရန်",
        "rollbacklinkcount": "{{PLURAL:$1|တည်းဖြတ်မှု|တည်းဖြတ်မှုများ}} $1 ကို နောက်ပြန်ပြင်ရန်",
        "rollbacklinkcount-morethan": "$1 ထက်ပိုသော {{PLURAL:$1|တည်းဖြတ်မှု|တည်းဖြတ်မှုများ}}ကို နောက်ပြန်ပြင်ရန်",
        "mycontris": "ဆောင်ရွက်ချက်များ",
        "anoncontribs": "ဆောင်ရွက်ချက်များ",
        "contribsub2": "{{GENDER:$3|$1}}အတွက် ($2)",
+       "contributions-subtitle": "{{GENDER:$3|$1}} အတွက်",
        "contributions-userdoesnotexist": "အသုံးပြုသူအကောင့် \"$1\" သည် မှတ်ပုံမတင်ထားပါ။",
        "nocontribs": "ဤသတ်မှတ်ချက်များနှင့် ကိုက်ညီသည့် ပြောင်းလဲမှုများ မရှိပါ။",
        "uctop": "လက်ရှိ",
        "ipb-disableusertalk": "ပိတ်ပင်ထားစဉ်အတွင်း ဤအသုံးပြုသူအား သူတို့၏ ကိုယ်ပိုင်ဆွေးနွေးချက် စာမျက်နှာကို ပြင်ဆင်ခြင်းမှ ပိတ်ပင်ရန်",
        "ipb-change-block": "အသုံးပြုသူအား ဤအပြင်အဆင်များဖြင့် ထပ်မံပိတ်ပင်ရန်",
        "ipb-confirm": "ပိတ်ပင်မှုကို အတည်ပြု",
+       "ipb-partial": "တစ်စိတ်တစ်ပိုင်း",
        "ipb-pages-label": "စာမျက်နှာများ",
+       "ipb-namespaces-label": "အမည်ညွှန်းများ",
        "badipaddress": "တရားမဝင်သော IP address",
        "blockipsuccesssub": "ပိတ်ပင်ခြင်း အောင်မြင်သည်",
        "blockipsuccesstext": "[[Special:Contributions/$1|$1]] ကို ပိတ်ပင်ထားပါသည်။<br />\nပိတ်ပင်မှုများကို ပြန်လည်ဆန်းစစ်ရန် [[Special:BlockList|ပိတ်ပင်မှု စာရင်း]]ကို ကြည့်ပါ။",
        "ipb-blocklist-contribs": "{{GENDER:$1|$1}} အတွက် ဆောင်ရွက်ချက်များ",
        "ipb-blocklist-duration-left": "$1 ကျန်ရှိ",
        "block-expiry": "သက်တမ်းကုန်လွန်ရက် -",
+       "block-prevent-edit": "တည်းဖြတ်ခြင်း",
+       "block-reason": "အ​ကြောင်း​ပြ​ချက်:",
+       "block-target": "အသုံးပြုသူအမည် သို့မဟုတ် အီးမေးလ်လိပ်စာ-",
        "unblockip": "အသုံးပြုသူကို ပိတ်ပင်ထားရာမှ ပြန်ဖွင့်ပေးရန်",
        "ipusubmit": "ဤပိတ်ပင်မှုကို ဖယ်ရှားရန်",
        "unblocked": "[[User:$1|$1]] ကို ပိတ်ပင်ထားရာမှ ပြန်ဖွင့်ပေးလိုက်သည်",
        "blocklist-userblocks": "အကောင့်ပိတ်ပင်မှုများ ဝှက်",
        "blocklist-tempblocks": "ယာယီပိတ်ပင်မှုများ ဝှက်",
        "blocklist-addressblocks": "အိုင်ပီတစ်ခုတည်းပိတ်ပင်မှု ဝှက်",
+       "blocklist-type-opt-all": "အားလုံး",
+       "blocklist-type-opt-partial": "တစ်စိတ်တစ်ပိုင်း",
        "blocklist-rangeblocks": "အကွာအဝေးလိုက် ပိတ်ပင်မှုများ ဝှက်",
        "blocklist-timestamp": "အချိန်တံဆိပ်",
        "blocklist-target": "ပစ်မှတ်",
        "createaccountblock": "အကောင့်ဖန်တီးခြင်းကို ပိတ်ထားသည်",
        "emailblock": "အီးမေးကို ပိတ်ပင်ထားသည်",
        "blocklist-nousertalk": "မိမိ၏ဆွေးနွေးချက်စာမျက်နှာကို တည်းဖြတ်မရနိုင်ပါ",
+       "blocklist-editing": "တည်းဖြတ်ခြင်း",
+       "blocklist-editing-page": "စာမျက်နှာများ",
+       "blocklist-editing-ns": "အမည်ညွှန်းများ",
        "ipblocklist-empty": "ပိတ်ပင်ထားမှုစာရင်းသည် ဗလာဖြစ်နေသည်။",
        "ipblocklist-no-results": "တောင်းဆိုလိုက်သော အိုင်ပီလိပ်စာ သို့မဟုတ် အသုံးပြုသူအမည်ကို မပိတ်ပင်ထားပါ။",
        "blocklink": "ပိတ်ပင်",
        "pageinfo-display-title": "ပြသခေါင်းစဉ်",
        "pageinfo-default-sort": "ပုံမှန် စာလုံးစီကီး",
        "pageinfo-length": "စာမျက်နှာ အလျား (ဘိုက်ဖြင့်)",
+       "pageinfo-namespace": "အမည်ညွှန်း",
        "pageinfo-article-id": "စာမျက်နှာ အိုင်ဒီ",
        "pageinfo-language": "စာမျက်နှာ စာကိုယ် ဘာသာစကား",
        "pageinfo-language-change": "ပြောင်းလဲရန်",
        "mediastatistics-bytespertype": "ဤအပိုင်းအတွက် စုစုပေါင်းဖိုင်အရွယ်အစား: {{PLURAL:$1|$1 ဘိုက်|$1 ဘိုက်}} ($2; $3%)။",
        "mediastatistics-allbytes": "ဖိုင်အားလုံးအတွက် စုစုပေါင်းဖိုင်အရွယ်အစား: {{PLURAL:$1|$1 ဘိုက်|$1 ဘိုက်}} ($2)။",
        "mediastatistics-table-count": "ဖိုင်များ အရေအတွက်",
+       "mediastatistics-header-unknown": "မသိရှိပါ",
+       "mediastatistics-header-audio": "အသံ",
+       "mediastatistics-header-video": "ဗီဒီယိုများ",
        "mediastatistics-header-total": "ဖိုင်အားလုံး",
        "special-characters-group-latin": "လက်တင်",
        "special-characters-group-symbols": "သင်္ကေတများ",
        "special-characters-group-greek": "ဂရိ",
        "special-characters-group-arabic": "အာရဗီ",
+       "special-characters-group-persian": "ပါရှန်း",
        "special-characters-group-hebrew": "ဟီးဘရူး",
        "special-characters-group-bangla": "ဘင်္ဂလား",
+       "special-characters-group-tamil": "တမီးလ်",
        "special-characters-group-thai": "ထိုင်း",
        "special-characters-group-lao": "လာအို",
        "special-characters-group-khmer": "ခမာ",
+       "special-characters-title-minus": "အနုတ် သင်္ကေတ",
+       "mw-widgets-abandonedit": "အရင်ဆုံး မသိမ်းဆည်းဘဲ တည်းဖြတ်ခြင်းပုံစံမှ ထွက်ခွာလိုသည်မှာ သေချာပါသလား",
        "mw-widgets-abandonedit-discard": "တည်းဖြတ်မှုများကို စွန့်လွတ်ရန်",
        "mw-widgets-abandonedit-keep": "တည်းဖြတ်ခြင်းကို ဆက်လုပ်ရန်",
        "mw-widgets-abandonedit-title": "သေချာပါသလား",
        "mw-widgets-titleinput-description-redirect": "$1 သို့ ပြန်ညွှန်း",
        "mw-widgets-categoryselector-add-category-placeholder": "ကဏ္ဍတစ်ခု ထည့်ပေါင်း...",
        "mw-widgets-usersmultiselect-placeholder": "ပို၍ ထည့်ပေါင်း...",
+       "mw-widgets-titlesmultiselect-placeholder": "ပို၍ ထည့်ပေါင်း...",
        "date-range-from": "နေ့စွဲမှ:",
        "date-range-to": "နေ့စွဲသို့:",
        "randomrootpage": "ကျပန်း အခြေ စာမျက်နှာ",
        "log-action-filter-protect-protect": "ကာကွယ်မှု",
        "log-action-filter-rights-rights": "လူဖြင့် ပြောင်းလဲမှု",
        "log-action-filter-rights-autopromote": "အလိုအလျောက် ပြောင်းလဲမှု",
+       "log-action-filter-upload-revert": "ပြန်ပြောင်းရန်",
        "authmanager-create-disabled": "အကောင့်ဖန်တီးခြင်းကို ပိတ်ထားသည်။",
        "authmanager-autocreate-noperm": "အလိုအလျာက် အကောင့်ဖန်တီးခြင်းကို ခွင့်မပြုပါ။",
        "authmanager-autocreate-exception": "ရှေ့ကအမှားများကြောင့် အလိုအလျာက် အကောင့်ဖန်တီးခြင်းကို ယာယီပိတ်ထားသည်။",
        "authmanager-realname-help": "အသုံးပြုသူ၏ အမည်ရင်း",
        "authmanager-provider-temporarypassword": "ယာယီစကားဝှက်",
        "authprovider-resetpass-skip-label": "ကျော်ရန်",
+       "specialpage-securitylevel-not-allowed-title": "ခွင့်မပြုပါ",
        "cannotauth-not-allowed-title": "ခွင့်ပြုချက် ငြင်းပယ်လိုက်သည်",
        "cannotauth-not-allowed": "သင်သည် ဤစာမျက်နှာကို အသုံးပြုခွင့်မရှိပါ",
        "userjsispublic": "ကျေးဇူးပြု၍ မှတ်သားပါ- JavaScript စာမျက်နှာခွဲများတွင် အခြားအသုံးပြုသူများ ကြည့်ရှုနိုင်သော လျို့ဝှက်အပ်သည့်အချက်အလက် မပါဝင်သင့်ပါ။",
index 2a466f2..fbfd2bd 100644 (file)
        "updated": "(Одолгавтозь)",
        "note": "'''Явт мель:'''",
        "previewnote": "'''Кирдтяя мельсэ, те ансяк васнянь невтевкс.'''\nПолавтоматне зярс апак вансто!",
+       "continue-editing": "Совамс витнеме-петнеме",
        "editing": "Витнят-петнят $1",
        "creating": "Шки-теи «$1»",
        "editingsection": "Витнемс-петнемс $1 (секциянть)",
        "page_first": "васенце",
        "page_last": "меельсе",
        "histlegend": "Версиянь кочкамось: тешксты невтезь версиятнень,  али лепштик Enter повнэнть.<br />\nЧарькодевтемат: (молиц.) = редямось молиця версиястонть; (и. молиц.) = редямось икеле молиця версиястонть; '''а''' = аволь седе ламо лиякстомтома.",
-       "history-fieldset-title": "Ð\92еÑ\88немÑ\81 Ð²ÐµÑ\80Ñ\81иÑ\8fÑ\82",
+       "history-fieldset-title": "Ð\9dолдамÑ\81 Ð²ÐµÑ\80Ñ\81иÑ\8fÑ\82 Ñ\81Ñ\83вÑ\82еменÑ\8c Ð¿Ð°Ñ\87к",
        "history-show-deleted": "Ансяк нардазь",
        "histfirst": "весемеде умонь",
        "histlast": "Меельце",
        "creditspage": "Лопасонть кинь путовксонзо",
        "spamprotectiontitle": "Шукшто ванстома филтра",
        "spambot_username": "MediaWiki-нь шукшто ванькскавтома",
+       "pageinfo-title": "«$1» лопадонть информация",
        "pageinfo-header-basic": "Васень информациязо",
        "pageinfo-header-edits": "Витнемс-петнемс юронзо-путовксонзо",
        "pageinfo-header-restrictions": "Лопанть ванстоманзо",
        "pageinfo-content-model": "Лопапотмонь парцун",
        "pageinfo-robot-policy": "Вешнема машинань индексэнь путомась",
        "pageinfo-robot-index": "Маштови",
+       "pageinfo-watchers": "Зяро лопанть ваныцятнеде",
        "pageinfo-few-watchers": "$1 эли седе ламо {{PLURAL:$1|ваныцянзо}} арасть",
        "pageinfo-redirects-name": "Зяро лопат печтевтезь те лопас",
        "pageinfo-subpages-name": "Те лопанть явкслопанзо",
        "redirect-lookup": "Вешнемс:",
        "redirect-user": "Теицянь идентификатор",
        "redirect-page": "Лопа ID",
+       "redirect-revision": "Версиянть нумерэзэ",
        "redirect-file": "Файлань лем",
        "fileduplicatesearch": "Вешнемс кавтаське файлат",
        "fileduplicatesearch-filename": "Файла лем:",
index 57c149d..0ec014c 100644 (file)
        "minoreditletter": "p",
        "newpageletter": "Y",
        "boteditletter": "T",
-       "number_of_watching_users_pageview": "[$1 tlatequitiltilīlli {{PLURAL:$1|tlachiya|tlachiyah}}]",
        "newsectionsummary": "Yancuīc tlahtōltzintli: /* $1 */",
        "recentchangeslinked": "Tlapatlaliztli tzonhuilizpan",
        "recentchangeslinked-feed": "Tlapatlaliztli tzonhuilizpan",
index 89ea2a3..dead74a 100644 (file)
        "rcfilters-filterlist-title": "Lū-thai",
        "rcfilters-filter-editsbyself-label": "Lí ê siu-kái",
        "rcfilters-filter-editsbyother-label": "Pa̍t-lâng ê siu-kái",
-       "rcfilters-filtergroup-userExpLevel": "Iōng-chiá teng-lio̍k kap keng-giām",
+       "rcfilters-filtergroup-user-experience-level": "Iōng-chiá teng-lio̍k kap keng-giām",
        "rcfilters-filter-bots-label": "Bot",
        "rcfilters-filter-humans-label": "Jîn-lūi (m̄-sī bot)",
        "rcfilters-filter-pageedits-label": "Ia̍h-bīn pian-chi̍p",
        "cantrollback": "Bô-hoat-tō· kā siu-kái ká-tńg--khì; téng ūi kòng-hiàn-chiá sī chit ia̍h î-it ê chok-chiá.",
        "alreadyrolled": "Bô-hoat-tō· kā [[User:$2|$2]] ([[User talk:$2|Thó-lūn]]) tùi [[:$1]] ê siu-kái ká-tńg-khì; í-keng ū lâng siu-kái a̍h-sī ká-tńg chit ia̍h. Téng 1 ūi siu-kái-chiá sī [[User:$3|$3]] ([[User talk:$3|Thó-lūn]]).",
        "editcomment": "Siu-kái phêng-lūn sī: <em>$1</em>.",
-       "protectedarticle": "pó-hō͘ \"[[$1]]\"",
+       "protectedarticle": "pó-hō͘ liáu \"[[$1]]\"",
        "protect-title": "Kái-piàn \"$1\" ê pó-hō͘ chân-kip",
        "prot_1movedto2": "[[$1]] sóa khì tī [[$2]]",
        "protect-legend": "Khak-tēng beh pó-hō·",
        "protectcomment": "Lí-iû:",
-       "protect-level-autoconfirmed": "Chí ín-chún chū-tōng khak-jīn iōng-chiá",
-       "protect-level-sysop": "Chí ín-chún koán-lí jîn-oân",
+       "protect-level-autoconfirmed": "Ta ín-chún chū-tōng khak-jīn iōng-chiá",
+       "protect-level-sysop": "Ta ín-chún koán-lí jîn-oân",
+       "protect-expiring": "chì $1 (UTC) kòe-kî",
+       "protect-expiring-local": "chì $1 kòe-kî",
        "protect-cascade": "Cascading protection - pó-hō͘ jīm-hô pau-hâm tī chit ia̍h ê ia̍h.",
        "restriction-edit": "Siu-kái",
        "restriction-move": "Sóa khì",
index 93402f3..75726e2 100644 (file)
        "rcfilters-filter-editsbyself-description": "Contribbute d'ê tuoie",
        "rcfilters-filter-editsbyother-label": "Cagnamiénte 'e ll'ate",
        "rcfilters-filter-editsbyother-description": "Tutt'ê cagni mancant'ê tuoie",
-       "rcfilters-filtergroup-userExpLevel": "Reggistrazione e sperienza 'e ll'utente",
+       "rcfilters-filtergroup-user-experience-level": "Reggistrazione e sperienza 'e ll'utente",
        "rcfilters-filter-user-experience-level-registered-label": "Reggistrato:",
        "rcfilters-filter-user-experience-level-registered-description": "Utenti ca stanno 'a dinto.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Nun reggistrato.",
        "rcfilters-filter-watchlistactivity-unseen-label": "Càgni nun visti",
        "rcfilters-filter-watchlistactivity-seen-label": "Càgni visti",
        "rcfilters-filter-watchlistactivity-seen-description": "Càgni a paggene ch'hê visto 'a cuanno facettero ll'urdimo cagnamiénto.",
-       "rcfilters-filtergroup-lastRevision": "Ùrdeme verziune",
+       "rcfilters-filtergroup-lastrevision": "Ùrdeme verziune",
        "rcfilters-filter-lastrevision-label": "Verzione 'e mmo",
        "rcfilters-watchlist-markseen-button": "Segna tutt'ê cagni comme visti",
        "rcfilters-watchlist-edit-watchlist-button": "Càgna 'e lista tuia d'ê paggene cuntrullate",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[osservata 'a {{PLURAL:$1|n'utente|$1 utente}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|byte}} aropp'ô cagnamiento",
        "newsectionsummary": "/* $1 */ sezziona nnova",
        "rc-enhanced-expand": "Fa vede dettaglie",
        "img-auth-nopathinfo": "PATH_INFO mancante.\n'O server nun è mpustato pe' passà sta nfurmazione.\nPuò darse ca, essenno basato ncopp'a CGI, nun putesse suppurtà img_auth.\nVide https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization",
        "img-auth-notindir": "'O percurzo addimannato nun se trova dint' 'e cartelle d'upload configurate.",
        "img-auth-badtitle": "Nun se può fravecà nu titolo valido 'a \"$1\".",
-       "img-auth-nologinnWL": "Nun site trasuto e \"$1\" nun è dint'a lista janca.",
        "img-auth-nofile": "File \"$1\" nun esiste.",
        "img-auth-isdir": "State pruvanno a trasì int' 'a cartella \"$1\".\nSulamente se può trasì a 'e file.",
        "img-auth-streaming": "\"$1\" 'n streaming.",
        "revertpage": "Cangiaje 'e cagnamiénte 'e [[Special:Contributions/$2|$2]] ([[User talk:$2|discussione]]), cu â verzione 'e pprimma 'e  [[User:$1|$1]]",
        "revertpage-nouser": "Annullate 'e cagnamiente 'e n'utente annascunnuto, è stata ripigliata ll'urdema verzione 'e {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Cagnamiente annullate 'a {{GENDER:$3|$1}};\ns'è turnato arreto a l'urdema verzione 'e {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Cagnamiente annullate 'a $1;\ns'è turnat arreto a l'urdema verzione 'e $2. [$3 Fà vedé 'e cagnamiente]",
        "sessionfailure-title": "Sessione fallita",
        "sessionfailure": "Pare ca stanno probbleme cu 'a sessiona toja;\nst'azione è stata fermata pe' precauzione annanz' 'e cavall' 'e troia;\nPe' piacere turnate arreto, carrecate n'ata vota 'a paggena pe pruvate n'ata vota.",
        "changecontentmodel": "Cagna 'o mudello 'e cuntenute 'e na paggena",
        "allmessagesdefault": "Mmasciata 'e testo predefinita",
        "allmessagescurrent": "Testo 'e mo",
        "allmessagestext": "Chest'è na lista 'e tutt' 'e mmasciate 'e sistema ca se ponno ascià dint' 'o namespace 'e Mediawiki.\nPe' piacere vedite [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Lucalizzazione 'e MediaWiki] e [https://translatewiki.net translatewiki.net] si vulite cuntribbuì â lucalizzaziona generica 'e MediaWiki.",
-       "allmessagesnotsupportedDB": "Sta paggena nun se può ausà pecché 'a funziona <strong>$wgUseDatabaseMessages</strong> è stata stutata.",
+       "allmessages-not-supported-database": "Sta paggena nun se può ausà pecché 'a funziona <strong>$wgUseDatabaseMessages</strong> è stata stutata.",
        "allmessages-filter-legend": "Filtro",
        "allmessages-filter": "Filtra cu nu stato personalizzate:",
        "allmessages-filter-unmodified": "Senza cagnamiente",
index 05016bf..026a5b8 100644 (file)
        "page_first": "første",
        "page_last": "siste",
        "histlegend": "Valg av diff: merk i radioboksene de revisjonene du ønsker å sammenligne og trykk enter eller knappen nederst på siden.<br />\nForklaring: '''({{int:cur}})''' = forskjell fra nåværende revisjon, '''({{int:last}})''' = forskjell fra foregående revisjon, '''{{int:minoreditletter}}''' = mindre endring.",
-       "history-fieldset-title": "Søk etter revisjoner",
+       "history-fieldset-title": "Filtrer revisjoner",
        "history-show-deleted": "Kun slettede revisjoner",
        "histfirst": "eldste",
        "histlast": "nyeste",
        "historysize": "({{PLURAL:$1|1 byte|$1 byte}})",
-       "historyempty": "(tom)",
+       "historyempty": "tom",
        "history-feed-title": "Revisjonshistorikk",
        "history-feed-description": "Revisjonshistorikk for denne siden",
        "history-feed-item-nocomment": "$1 på $2",
        "right-reupload-own": "Skrive over egne filer",
        "right-reupload-shared": "Skrive over delte filer lokalt",
        "right-upload_by_url": "Laste opp en fil via URL",
-       "right-purge": "Rense mellomlageret for sider",
+       "right-purge": "Rens mellomlageret for en side",
        "right-autoconfirmed": "Redigere halvlåste sider",
        "right-bot": "Bli behandlet som en automatisk prosess",
        "right-nominornewtalk": "Får ikke «Du har nye meldinger»-beskjeden ved mindre endringer på diskusjonsside",
        "action-changetags": "legg til og fjern vilkårlige merker på individuelle revisjoner og loggposter",
        "action-deletechangetags": "slette tagger fra databasen",
        "action-purge": "gjenoppfriske denne siden",
+       "action-apihighlimits": "bruke høyere grenser for API-spørringer",
+       "action-autoconfirmed": "ikke bli påvirket av IP-baserte hastighetsbegrensninger",
+       "action-bigdelete": "slette sider med lang historikk",
+       "action-blockemail": "blokkere en bruker fra å sende e-post",
+       "action-bot": "bli behandlet som en automatisert prosess",
+       "action-editprotected": "redigere sider som er beskyttet som «{{int:protect-level-sysop}}»",
+       "action-editsemiprotected": "redigere sider som er beskyttet som «{{int:protect-level-autoconfirmed}}»",
+       "action-editinterface": "redigere brukergrensesnittet",
+       "action-editusercss": "redigere andre brukeres CSS-filer",
+       "action-edituserjson": "redigere andre brukeres JSON-filer",
+       "action-edituserjs": "redigere andre brukeres JavaScript-filer",
+       "action-editsitecss": "redigere CSS som påvirker hele nettstedet",
+       "action-editsitejson": "redigere JSON som påvirker hele nettstedet",
+       "action-editsitejs": "redigere JavaScript som påvirker hele nettstedet",
+       "action-editmyusercss": "redigere dine egne CSS-filer",
+       "action-editmyuserjson": "redigere dine egne JSON-filer",
+       "action-editmyuserjs": "redigere dine egne JavaScript-filer",
+       "action-viewsuppressed": "viser skjulte revisjoner",
+       "action-hideuser": "blokkere et brukernavn og skjule det fra offentligheten",
+       "action-ipblock-exempt": "omgå IP-blokkeringer, autoblokkeringer og rekkeblokkeringer",
+       "action-unblockself": "avblokkere deg selv",
+       "action-noratelimit": "ikke bli påvirket av hastighetsbegrensninger",
+       "action-reupload-own": "overskrive eksisterende filer lastet opp av deg selv",
+       "action-nominornewtalk": "hindre at mindre redigeringer på diskusjonssider utløser spørsmål om nye meldinger",
+       "action-markbotedits": "markere tilbakestillinger som botredigeringer",
+       "action-patrolmarks": "vise patruljeringsmerker i siste endringer",
+       "action-override-export-depth": "eksportere sider inkludert lenkede sider til og med en lenkedybde på 5",
+       "action-suppressredirect": "ikke opprette omdirigeringer fra kildesider ved flytting av sider",
        "nchanges": "$1 {{PLURAL:$1|endring|endringer}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|siden forrige besøk}}",
        "enhancedrc-history": "historikk",
        "rcfilters-savedqueries-already-saved": "Disse filtrene er allerede lagret. Endre innstillingene dine for å opprette et nytt lagret filter.",
        "rcfilters-restore-default-filters": "Gjenopprett standardfiltre",
        "rcfilters-clear-all-filters": "Nullstill alle filtre",
-       "rcfilters-show-new-changes": "Vis de nyeste endringene",
+       "rcfilters-show-new-changes": "Vis nye endringer siden $1",
        "rcfilters-search-placeholder": "Filtrer endringer (bruk menyen eller søk etter et filternavn)",
        "rcfilters-invalid-filter": "Ugyldig filter",
        "rcfilters-empty-filter": "Ingen aktive filtre. Alle bidrag vises.",
        "rcfilters-filter-editsbyself-description": "Dine egne bidrag.",
        "rcfilters-filter-editsbyother-label": "Endringer av andre",
        "rcfilters-filter-editsbyother-description": "Alle endringer utenom dine egne.",
-       "rcfilters-filtergroup-userExpLevel": "Brukerregistrering og -erfaring",
+       "rcfilters-filtergroup-user-experience-level": "Brukerregistrering og -erfaring",
        "rcfilters-filter-user-experience-level-registered-label": "Registrerte",
        "rcfilters-filter-user-experience-level-registered-description": "Innloggede brukere.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Uregistrerte",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Filteret for «Mindre endringer» konflikterer med ett eller flere endringstypefiltre, fordi visse endringstyper ikke kan merkes som «mindre». De konflikterende fultrene merkes i området for aktive filtre ovenfor.",
        "rcfilters-hideminor-conflicts-typeofchange": "Visse endringstyper kan ikke merkes som «mindre», så dette filteret konflikterer med følgende endringstypefiltre: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Dette endringstypefilteret konflikterer med filteret for «Mindre endringer». Visse endringstyper kan ikke merkes som «mindre».",
-       "rcfilters-filtergroup-lastRevision": "Siste revisjoner",
+       "rcfilters-filtergroup-lastrevision": "Siste revisjoner",
        "rcfilters-filter-lastrevision-label": "Siste revisjon",
        "rcfilters-filter-lastrevision-description": "Kun den nyeste endringen av en side.",
        "rcfilters-filter-previousrevision-label": "Ikke den siste versjonen",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 overvåkende {{PLURAL:$1|bruker|brukere}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} etter endring",
        "newsectionsummary": "/* $1 */ ny seksjon",
        "rc-enhanced-expand": "Vis detaljer",
        "img-auth-nopathinfo": "Manglende stiinformasjon.\nTjeneren må være satt opp til å sende variablene REQUEST_URI og/eller PATH_INFO.\nOm den er det, prøv å slå på $wgUsePathInfo.\nSe https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization .",
        "img-auth-notindir": "Den ønskede stien finnes ikke i den oppsatte opplastingsmappa.",
        "img-auth-badtitle": "Kunne ikke lage en gyldig tittel ut fra «$1».",
-       "img-auth-nologinnWL": "Du er ikke logget inn, og «$1» er ikke på hvitelista.",
        "img-auth-nofile": "Filen «$1» finnes ikke.",
        "img-auth-isdir": "Du prøver å få tilgang til mappa «$1».\nKun filtilgang tillates.",
        "img-auth-streaming": "Sender «$1».",
        "delete-confirm": "Slett «$1»",
        "delete-legend": "Slett",
        "historywarning": "<strong>Advarsel:</strong> Siden du er i ferd med å slette har en historikk med $1 {{PLURAL:$1|revisjon|revisjoner}}:",
-       "historyaction-submit": "Vis",
+       "historyaction-submit": "Vis revisjoner",
        "confirmdeletetext": "Du holder på å slette en side sammen med historikken.\nBekreft at du virkelig vil slette denne siden, at du forstår konsekvensene og at du gjør det i samsvar med [[{{MediaWiki:Policy-url}}|retningslinjene]].",
        "actioncomplete": "Gjennomført",
        "actionfailed": "Handling mislyktes",
        "deleting-backlinks-warning": "<strong>Advarsel:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Andre sider]] lenker til eller inkluderer siden du er i ferd med å slette.",
        "deleting-subpages-warning": "<strong>Advarsel:</strong> Siden du er i ferd med å slette har [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|en underside|$1 undersider|51=over 50 undersider}}]].",
        "rollback": "Fjern redigeringer",
+       "rollback-confirmation-confirm": "Vennligst bekreft:",
+       "rollback-confirmation-yes": "Tilbakestill",
+       "rollback-confirmation-no": "Avbryt",
        "rollbacklink": "tilbakestill",
        "rollbacklinkcount": "tilbakestill {{PLURAL:$1|én endring|$1 endringer}}",
        "rollbacklinkcount-morethan": "tilbakestill mer enn $1 {{PLURAL:$1|endring|endringer}}",
        "revertpage": "Tilbakestilte endringer av [[Special:Contributions/$2|$2]] ([[User talk:$2|brukerdiskusjon]]) til siste versjon av [[User:$1|$1]]",
        "revertpage-nouser": "Tilbakestilt endringer av skjult bruker til siste versjon av\n{{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Tilbakestilte endringer av {{GENDER:$3|$1}}; endret til siste versjon av {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Tilbakestilte endringer av $1;\nendret tilbake til siste revisjon av $2. [$3 Vis endringer]",
        "sessionfailure-title": "Sesjonsfeil",
        "sessionfailure": "Det ser ut til å være et problem med innloggingen din, og handlingen ble avbrutt av sikkerhetshensyn. Vennlgist prøv å sende skjemaet en gang til.",
        "changecontentmodel": "Endre innholdsmodell for en side",
        "mycontris": "Bidrag",
        "anoncontribs": "Bidrag",
        "contribsub2": "For {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "For {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "Brukerkontoen «$1» er ikke registrert.",
        "negative-namespace-not-supported": "Navnerom med negative verdier støttes ikke.",
        "nocontribs": "Ingen endringer er funnet som passer disse kriteriene.",
        "blocklist-userblocks": "Skjul kontoblokkeringer",
        "blocklist-tempblocks": "Skjul midlertidige blokkeringer",
        "blocklist-addressblocks": "Skjul individuelle IP-blokkeringer",
+       "blocklist-type": "Type:",
+       "blocklist-type-opt-all": "Alle",
+       "blocklist-type-opt-sitewide": "Hele nettstedet",
+       "blocklist-type-opt-partial": "Delvis",
        "blocklist-rangeblocks": "Skjul intervallblokker",
        "blocklist-timestamp": "Tidsstempel",
        "blocklist-target": "Mål",
        "blocklist-editing-page": "sider",
        "blocklist-editing-ns": "navnerom",
        "ipblocklist-empty": "Blokkeringslisten er tom.",
-       "ipblocklist-no-results": "Den angitte IP-adressen eller brukeren er ikke blokkert.",
+       "ipblocklist-no-results": "Ingen blokkeringer funnet for den IP-adressen eller brukernavnet.",
        "blocklink": "blokker",
        "unblocklink": "opphev blokkering",
        "change-blocklink": "endre blokkering",
+       "empty-username": "(intet tilgjengelig brukernavn)",
        "contribslink": "bidrag",
        "emaillink": "send e-post",
        "autoblocker": "Du ble automatisk blokkert fordi IP-adressen din nylig ble brukt av «[[User:$1|$1]]». Grunnen som ble gitt til at «$1» ble blokkert var: «$2».",
        "allmessagesdefault": "Standardtekst",
        "allmessagescurrent": "Gjeldende beskjedtekst",
        "allmessagestext": "Dette er en liste over tilgjengelige systemmeldinger i MediaWiki-navnerommet.\nBesøk [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Oversettelse] og [https://translatewiki.net translatewiki.net] om du ønsker å bidra med oversettelse av MediaWiki.",
-       "allmessagesnotsupportedDB": "''{{ns:special}}:Allmessages'' kan ikke brukes fordi '''$wgUseDatabaseMessages''' er slått av.",
+       "allmessages-not-supported-database": "''{{ns:special}}:Allmessages'' kan ikke brukes fordi '''$wgUseDatabaseMessages''' er slått av.",
        "allmessages-filter-legend": "Filtrér",
        "allmessages-filter": "Filtrér etter tilpasningsgrad",
        "allmessages-filter-unmodified": "Uendret",
        "confirm-unwatch-top": "Fjern denne siden fra overvåkningslisten din?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Tilbakestill redigeringer på denne siden?",
+       "confirm-rollback-bottom": "Dette vil tilbakestille de valgte endringene til denne siden umiddelbart.",
        "confirm-mcrrestore-title": "Gjenopprett en revisjon",
        "confirm-mcrundo-title": "Fjern en endring",
        "mcrundofailed": "Fjerning mislyktes",
        "passwordpolicies-policyflag-forcechange": "må endres ved innlogging",
        "passwordpolicies-policyflag-suggestchangeonlogin": "foreslå endring ved innlogging",
        "easydeflate-invaliddeflate": "Det gitte innholdet er ikke riktig komprimert",
-       "unprotected-js": "Av sikkerhetsårsaker kan ikke JavaScript lastes fra ubeskyttede sider. Bare skap JavaScript i MediaWiki-navnerommet eller som en brukerunderside"
+       "unprotected-js": "Av sikkerhetsårsaker kan ikke JavaScript lastes fra ubeskyttede sider. Bare skap JavaScript i MediaWiki-navnerommet eller som en brukerunderside",
+       "userlogout-continue": "Hvis du ønsker å logge ut, [$1 fortsett til utloggingssiden].",
+       "userlogout-sessionerror": "Utlogging mislyktes på grunn av en øktfeil. [$1 Prøv igjen]."
 }
index f1ec37d..01d9425 100644 (file)
@@ -19,7 +19,8 @@
                        "Macofe",
                        "Matma Rex",
                        "Fitoschido",
-                       "Vlad5250"
+                       "Vlad5250",
+                       "PiefPafPier"
                ]
        },
        "tog-underline": "Verwiezingen onderstrepen",
        "recentchanges-summary": "Up disse syde kün jy de lätste wysigingen van disse wiki bekyken.",
        "recentchanges-noresult": "Der waren in disse periode gien wiezigingen die an de kriteria voldoon.",
        "recentchanges-feed-description": "Zeuk naor de alderleste wiezingen op disse wiki in disse voer.",
-       "recentchanges-label-newpage": "Mid disse bewarking is een nye syde an-emaked",
+       "recentchanges-label-newpage": "Mid disse bewarking is een nye syde anemaked",
        "recentchanges-label-minor": "Dit is een kleine wysiging",
        "recentchanges-label-bot": "Disse bewarking is uutevoord döär een bot",
        "recentchanges-label-unpatrolled": "Disse bewarking is noch neet nå-ekeaken",
        "recentchanges-label-plusminus": "Disse sydegroutte is mid dit antal bytes ewysigd",
        "recentchanges-legend-heading": "<strong>Legenda:</strong>",
-       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (see ouk de [[Special:NewPages|lyste mid nye syden]])",
+       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}}<br />(see ouk de [[Special:NewPages|lyste mid nye syden]])",
        "recentchanges-submit": "Bekiek",
        "rcfilters-legend-heading": "<strong>Lyste mid ofkortingen:</strong>",
        "rcfilters-group-results-by-page": "Resultaoten per zied groeperen",
        "rcfilters-filterlist-feedbacklink": "Låt uns weaten wat jy van disse (nye) filterhülpmiddels vinden",
        "rcfilters-highlightbutton-title": "Resultåten markeren",
        "rcfilters-highlightmenu-title": "Kies n kleur",
-       "rcfilters-filtergroup-userExpLevel": "Gebrukersanmelding en ervåring",
+       "rcfilters-filtergroup-user-experience-level": "Gebrukersanmelding en ervåring",
        "rcfilters-filter-user-experience-level-registered-label": "An-emeld",
        "rcfilters-filter-user-experience-level-registered-description": "An-emelde bewarkers.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Neet an-emelded",
        "rcfilters-filter-categorization-description": "Upgave van syden dee to-evoogd of vordedån wörden uut kategoryen.",
        "rcfilters-filter-logactions-label": "Eregistreerde aktys",
        "rcfilters-filter-logactions-description": "Administrative handelingen, nye kontos, et vortdoon van syden, upstüren van bestanden…",
-       "rcfilters-filtergroup-lastRevision": "Lätste versys",
+       "rcfilters-filtergroup-lastrevision": "Lätste versys",
        "rcfilters-filter-lastrevision-label": "Lätste versy",
        "rcfilters-filter-lastrevision-description": "Allinnig de lätste wysiging an een syde.",
        "rcfilters-filter-previousrevision-label": "Neet de lätste versy",
        "newpageletter": "N",
        "boteditletter": "B",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|keer|keer}} op n volglieste]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} nao de wieziging",
        "newsectionsummary": "Ny underwarp: /* $1 */",
        "rc-enhanced-expand": "Details bekieken",
        "img-auth-nopathinfo": "PATH_INFO ontbrik.\nJoew server is niet in-esteld um disse informasie deur te geven.\nMisschien gebruukt t CGI, en dan wörden img_auth niet ondersteund.\nZie https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization veur meer informasie.",
        "img-auth-notindir": "t Op-evreugen pad is niet bekend in de in-estelden inlaojmap",
        "img-auth-badtitle": "Kon gien geldige ziednaam maken van \"$1\".",
-       "img-auth-nologinnWL": "Je bin niet an-emeld en \"$1\" steet niet op de witte lieste.",
        "img-auth-nofile": "Bestaand \"$1\" besteet niet.",
        "img-auth-isdir": "Je proberen de map \"$1\" binnen te koemen.\nAllinnig toegang tot bestaanden is toe-estaon.",
        "img-auth-streaming": "Bezig mit t streumen van \"$1\".",
        "allmessagesdefault": "Standardtekste",
        "allmessagescurrent": "De leste versie",
        "allmessagestext": "Hieronder steet n lieste mit alle systeemteksten in de MediaWiki-naamruumte.\nKiek oek effen bie [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki-lokalisasie] en [https://translatewiki.net translatewiki.net] a'j biedragen willen an de algemene vertaling veur MediaWiki.",
-       "allmessagesnotsupportedDB": "Disse zied kan niet gebruukt wörden umdat '''$wgUseDatabaseMessages''' uutezet is.",
+       "allmessages-not-supported-database": "Disse zied kan niet gebruukt wörden umdat '''$wgUseDatabaseMessages''' uutezet is.",
        "allmessages-filter-legend": "Filter",
        "allmessages-filter": "Filtreer op wiezigingen:",
        "allmessages-filter-unmodified": "niet ewiezigd",
        "mediastatistics-header-audio": "Audio",
        "mediastatistics-header-video": "Video's",
        "mediastatistics-header-multimedia": "Interaktieve media",
-       "special-characters-group-latin": "Latien",
-       "special-characters-group-latinextended": "Latien uutgebreid",
-       "special-characters-group-ipa": "Internasionaal Klankeschrift",
+       "special-characters-group-latin": "Latyn",
+       "special-characters-group-latinextended": "Latyn üütgebreided",
+       "special-characters-group-ipa": "Internationaal Fonetisk Alfabet",
        "special-characters-group-symbols": "Symbolen",
-       "special-characters-group-greek": "Grieks",
-       "special-characters-group-cyrillic": "Kyrillies",
-       "special-characters-group-arabic": "Arabies",
-       "special-characters-group-arabicextended": "Arabies uutgebreid",
+       "special-characters-group-greek": "Gryksk",
+       "special-characters-group-greekextended": "Gryksk üütgebreided",
+       "special-characters-group-cyrillic": "Kyrillisk",
+       "special-characters-group-arabic": "Arabisk",
+       "special-characters-group-arabicextended": "Arabisk üütgebreided",
        "special-characters-group-persian": "Perzies",
-       "special-characters-group-hebrew": "Hebreeuws",
-       "special-characters-group-bangla": "Bengaals",
+       "special-characters-group-hebrew": "Hebreywsk",
+       "special-characters-group-bangla": "Bengaalsk",
        "special-characters-group-tamil": "Tamil",
        "special-characters-group-telugu": "Telugu",
-       "special-characters-group-sinhala": "Singalees",
+       "special-characters-group-sinhala": "Singaleesk",
        "special-characters-group-gujarati": "Gujarati",
        "special-characters-group-devanagari": "Devanagari",
-       "special-characters-group-thai": "Thai",
-       "special-characters-group-lao": "Laotiaans",
+       "special-characters-group-thai": "Taisk",
+       "special-characters-group-lao": "Laotiaansk",
        "special-characters-group-khmer": "Khmer",
+       "special-characters-group-canadianaboriginal": "Kanadeesk lettergreapenskrivt",
        "special-characters-title-endash": "liggend streepjen",
        "special-characters-title-emdash": "gedachtenstreepjen",
        "special-characters-title-minus": "minteken",
index 76a4237..192a852 100644 (file)
@@ -15,7 +15,8 @@
                        "Servien",
                        "Macofe",
                        "Fitoschido",
-                       "Vlad5250"
+                       "Vlad5250",
+                       "PiefPafPier"
                ]
        },
        "tog-underline": "Verwies ünnerstrieken",
        "recentchanges-label-bot": "Düsse Ännern worr maakt vun en Bot",
        "recentchanges-label-unpatrolled": "Düsse Ännern is noch nich kontrolleert worrn",
        "recentchanges-label-plusminus": "Disse Siedengrött is mit dit Antall Bytes ännert",
-       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (süh ok de [[Special:NewPages|List mit ne'e Sieden]])",
+       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}}<br />(süh ok de [[Special:NewPages|List mit ne'e Sieden]])",
        "rcnotefrom": "Dit sünd de Ännern siet <b>$2</b> (bet to <b>$1</b> wiest).",
        "rclistfrom": "Wies ne’e Ännern siet $3 $2",
        "rcshowhideminor": "lütte Ännern $1",
        "minoreditletter": "L",
        "newpageletter": "N",
        "boteditletter": "B",
-       "number_of_watching_users_pageview": "[{{PLURAL:$1|Een Bruker|$1 Brukers}}, de oppasst]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} achter Ännern",
        "newsectionsummary": "/* $1 */ nee Afsnitt",
        "rc-enhanced-expand": "Details wiesen (bruukt JavaScript)",
        "allmessagesdefault": "Standardtext",
        "allmessagescurrent": "Text nu",
        "allmessagestext": "Dit is de List vun de Systemnarichten, de dat in den MediaWiki-Naamruum gifft.",
-       "allmessagesnotsupportedDB": "{{ns:special}}:Allmessages is nich ünnerstütt, vun wegen dat wgUseDatabaseMessages utstellt is.",
+       "allmessages-not-supported-database": "{{ns:special}}:Allmessages is nich ünnerstütt, vun wegen dat wgUseDatabaseMessages utstellt is.",
        "allmessages-filter-all": "All",
        "allmessages-language": "Spraak:",
        "allmessages-filter-submit": "Los",
index 2e25acc..5ba3fbf 100644 (file)
        "newpageletter": "न",
        "boteditletter": "बो",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 निगरानी गर्दै{{PLURAL:$1|प्रयोगकर्ता|प्रयोगकर्ताहरु}}]",
        "rc-change-size": "$1",
        "rc-change-size-new": "परिवर्तनपछि $1 {{PLURAL:$1|बाइट|बाइट}}",
        "newsectionsummary": "/* $1 */ नयाँ खण्ड",
        "img-auth-nopathinfo": "PATH_INFO छैन। तपाईंको सर्भरले यो जानकारी पठाउन सेट गरिएको छैन। यो सिजिआइ-आधारित हुन् सक्छ र img_auth लाई स्वीकार गर्दैन। https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization हेर्नुहोस।",
        "img-auth-notindir": "अनुरोध गरिएको बाटो(पाथ) उर्ध्वभरण भनि तोकिएको बाटोमा पर्दैन ।",
        "img-auth-badtitle": "\"$1\" बाट मान्य शीर्षक निर्माण गर्न सकिएन ।",
-       "img-auth-nologinnWL": "तपाईंले लग इन गर्नुभएको छैन र \"$1\" श्वेतसूचीमा छैन।",
        "img-auth-nofile": "\"$1\" फाइल छैन।",
        "img-auth-isdir": "तपाईं डायरेक्टरी \"$1\" खोल्ने प्रयास गर्दैहुनुहुन्छ। मात्रै फाइल खोल्न सकिनेछ।",
        "img-auth-streaming": "\"$1\" बग्दै",
        "allmessagesdefault": "डिफल्ट सन्देश पाठ",
        "allmessagescurrent": "वर्तमान सन्देश पाठ",
        "allmessagestext": "यो मिडियाविकी नेमस्पेसमा पाइने सिस्टम सन्देशहरूको सूची हो।\nयदि तपाईँ व्यापक मिडियाविकी स्थानीयकरणमा योगदान गर्न चाहनुहुन्छ भने कृपया [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation]मा र [https://translatewiki.net translatewiki.net]मा जानुहोस्।",
-       "allmessagesnotsupportedDB": "<strong>$wgUseDatabaseMessages</strong> लाई निस्क्रिय गरिएकोले यो पृष्ठ प्रयोग गर्न सकिदैन ।",
+       "allmessages-not-supported-database": "<strong>$wgUseDatabaseMessages</strong> लाई निस्क्रिय गरिएकोले यो पृष्ठ प्रयोग गर्न सकिदैन ।",
        "allmessages-filter-legend": "फिल्टर",
        "allmessages-filter": "अनुकूल स्थितिको आधारमा छान्नुहोस्:",
        "allmessages-filter-unmodified": "असंशोधित",
index 126fa4e..e3a8817 100644 (file)
        "filename-bad-prefix": "De naam van het bestand dat je aan het uploaden bent begint met '''\"$1\"''', wat een niet-beschrijvende naam is die meestal automatisch door een digitale camera wordt gegeven.\nKies een duidelijke naam voor je bestand.",
        "uploadstash-badtoken": "Het uitvoeren van de handeling is mislukt. Dit komt mogelijk doordat je bewerkingsreferenties zijn verlopen. Probeer het opnieuw.",
        "img-auth-nopathinfo": "PATH_INFO ontbreekt.\nJe server is niet ingesteld om deze gegevens door te geven.\nMisschien gebruikt deze CGI, en dan wordt img_auth niet ondersteund.\nZie https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization voor meer informatie.",
-       "img-auth-nologinnWL": "Je bent niet aangemeld en \"$1\" staat niet op de witte lijst.",
        "img-auth-isdir": "Je probeert de map \"$1\" te benaderen.\nAlleen toegang tot bestanden is toegestaan.",
        "upload-curl-error28-text": "Het duurde te lang voordat de website antwoordde.\nControleer of de website beschikbaar is, wacht even en probeer het dan opnieuw.\nJe kunt het misschien proberen als het minder druk is.",
        "upload_source_file": "(een bestand op je computer)",
index c2d7cc0..9abf62c 100644 (file)
@@ -95,7 +95,9 @@
                        "Jeroen N",
                        "Bdijkstra",
                        "KlaasZ4usV",
-                       "Elroy"
+                       "Elroy",
+                       "PiefPafPier",
+                       "Ecthelion3"
                ]
        },
        "tog-underline": "Verwijzingen onderstrepen:",
        "tog-norollbackdiff": "Wijzigingen weglaten na terugdraaien",
        "tog-useeditwarning": "Waarschuwen als u een bewerkte pagina wilt verlaten die nog niet is opgeslagen",
        "tog-prefershttps": "Altijd een beveiligde verbinding gebruiken wanneer u bent aangemeld",
+       "tog-showrollbackconfirmation": "Toon een bevestigingsvenster wanneer er op een terugdraaien koppeling wordt geklikt.",
        "underline-always": "Altijd",
        "underline-never": "Nooit",
        "underline-default": "Standaardgedrag van vormgeving of webbrowser",
        "virus-scanfailed": "scannen is mislukt (code $1)",
        "virus-unknownscanner": "onbekend antivirusprogramma:",
        "logouttext": "<strong>U bent nu afgemeld.</strong>\n\nMogelijk worden sommige pagina's nog weergegeven alsof u aangemeld bent, totdat u de cache van uw browser leegt.",
+       "logging-out-notify": "U wordt afgemeld, een ogenblik geduld alstublieft.",
+       "logout-failed": "Het is niet mogelijk om nu af te melden: $1",
        "cannotlogoutnow-title": "Niet mogelijk om nu af te melden",
        "cannotlogoutnow-text": "Afmelden is niet mogelijk bij het gebruik van $1.",
        "welcomeuser": "Welkom, $1!",
        "userpage-userdoesnotexist": "Gebruikersaccount \"$1\" bestaat niet.\nControleer of u deze pagina wel wilt aanmaken/bewerken.",
        "userpage-userdoesnotexist-view": "Gebruikersaccount \"$1\" bestaat niet.",
        "blocked-notice-logextract": "Deze gebruiker is momenteel geblokkeerd.\nDe laatste regel uit het blokkeerlogboek wordt hieronder ter referentie weergegeven:",
-       "clearyourcache": "<strong>Opmerking:</strong> nadat u de wijzigingen hebt opgeslagen is het wellicht nodig uw browsercache te legen.\n* <strong>Firefox / Safari:</strong> houd <em>Shift</em> ingedrukt terwijl u op <em>Vernieuwen</em> klikt of druk op <em>Ctrl-F5</em> of <em>Ctrl-R</em> (<em>⌘-Shift-R</em> op een Mac)\n* <strong>Google Chrome:</strong> druk op <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> op een Mac)\n* <strong>Internet Explorer:</strong> houd <em>Ctrl</em> ingedrukt terwijl u op <em>Vernieuwen</em> klikt of druk op <em>Ctrl-F5</em>\n* '''Opera:''' ga naar <em>Menu → Instellingen</em> (<em>Opera → Voorkeuren</em> op een Mac) en daarna naar <em>Privacy & beveiliging → Browsegegevens wissen... →  Tijdelijk opgeslgen afbeeldingen en bestanden</em>.",
+       "clearyourcache": "<strong>Opmerking:</strong> nadat u de wijzigingen hebt opgeslagen is het wellicht nodig uw browsercache te legen.\n* <strong>Firefox / Safari:</strong> houd <em>Shift</em> ingedrukt terwijl u op <em>Vernieuwen</em> klikt of druk op <em>Ctrl-F5</em> of <em>Ctrl-R</em> (<em>⌘-Shift-R</em> op een Mac)\n* <strong>Google Chrome:</strong> druk op <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> op een Mac)\n* <strong>Internet Explorer:</strong> houd <em>Ctrl</em> ingedrukt terwijl u op <em>Vernieuwen</em> klikt of druk op <em>Ctrl-F5</em>\n* '''Opera:''' ga naar <em>Menu → Instellingen</em> (<em>Opera → Voorkeuren</em> op een Mac) en daarna naar <em>Privacy & beveiliging → Browsegegevens wissen... →  Tijdelijk opgeslagen afbeeldingen en bestanden</em>.",
        "usercssyoucanpreview": "'''Tip:''' gebruik de knop \"{{int:showpreview}}\" om uw nieuwe CSS te testen alvorens op te slaan.",
        "userjsonyoucanpreview": "'''Tip:''' gebruik de knop \"{{int:showpreview}}\" om uw nieuwe JSON te testen alvorens op te slaan.",
        "userjsyoucanpreview": "'''Tip:''' gebruik de knop \"{{int:showpreview}}\" om uw nieuwe JavaScript te testen alvorens op te slaan.",
        "nohistory": "Deze pagina is niet bewerkt.",
        "currentrev": "Huidige versie",
        "currentrev-asof": "Huidige versie van $2 om $3",
-       "revisionasof": "Versie van $2 om $3",
+       "revisionasof": "Versie van $1",
        "revision-info": "Versie door {{GENDER:$6|$2}} op $4 om $5$7",
        "previousrevision": "← Oudere versie",
        "nextrevision": "Nieuwere versie →",
        "histfirst": "oudste",
        "histlast": "nieuwste",
        "historysize": "({{PLURAL:$1|1 byte|$1 bytes}})",
-       "historyempty": "(leeg)",
+       "historyempty": "leeg",
        "history-feed-title": "Bewerkingsoverzicht",
        "history-feed-description": "Bewerkingsoverzicht voor deze pagina op de wiki",
        "history-feed-item-nocomment": "$1 op $3 om $4",
        "right-reupload-own": "Eigen bestandsuploads overschrijven",
        "right-reupload-shared": "Media uit de gedeelde mediadatabank lokaal overschrijven",
        "right-upload_by_url": "Bestanden uploaden via een URL",
-       "right-purge": "De cache van een pagina verversen zonder bevestiging",
+       "right-purge": "De cache van een pagina verversen",
        "right-autoconfirmed": "Uitgezonderd van IP-adresgebaseerde tijdsafhankelijke beperkingen",
        "right-bot": "Behandeld worden als een geautomatiseerd proces",
        "right-nominornewtalk": "Kleine bewerkingen aan een overlegpagina leiden niet tot een melding 'nieuwe berichten'",
        "right-browsearchive": "Verwijderde pagina's zoeken",
        "right-undelete": "Verwijderde pagina's terugplaatsen",
        "right-suppressrevision": "Specifieke versies bekijken, verbergen en weer zichtbaar maken op pagina's van elke gebruiker",
-       "right-viewsuppressed": "Versies verborgen door elke gebruiker bekijken",
+       "right-viewsuppressed": "Versies verborgen voor elke gebruiker bekijken",
        "right-suppressionlog": "Niet-openbare logboeken bekijken",
        "right-block": "Andere gebruikers de mogelijkheid ontnemen te bewerken",
        "right-blockemail": "Een gebruiker het recht ontnemen om e-mail te versturen",
        "right-hideuser": "Een gebruiker voor de overige gebruikers verbergen",
-       "right-ipblock-exempt": "IP-blokkades omzeilen",
+       "right-ipblock-exempt": "IP-blokkades, automatische blokkades en IP-bereik blokkades omzeilen",
        "right-unblockself": "Eigen gebruiker deblokkeren",
        "right-protect": "Beveiligingsniveaus wijzigen",
        "right-editprotected": "Pagina's bewerken die beveiligd zijn als \"{{int:protect-level-sysop}}\"",
        "action-changetags": "willekeurige labels toe te voegen aan en te verwijderen van versies en logboekregels",
        "action-deletechangetags": "labels uit de database te verwijderen",
        "action-purge": "deze pagina te verversen",
+       "action-apihighlimits": "de hogere limieten in API-zoekopdrachten te gebruiken",
+       "action-autoconfirmed": "uitgezonderd te zijn van IP-adresgebaseerde tijdsafhankelijke beperkingen",
+       "action-bigdelete": "pagina's met een grote geschiedenis te verwijderen",
+       "action-blockemail": "een gebruiker het recht te ontnemen om e-mail te versturen",
+       "action-bot": "behandeld te worden als een geautomatiseerd proces",
+       "action-editprotected": "pagina's bewerken die beveiligd zijn als \"{{int:protect-level-sysop}}\"",
+       "action-editsemiprotected": "pagina's bewerken die beveiligd zijn als \"{{int:protect-level-autoconfirmed}}\"",
+       "action-editinterface": "de gebruikersinterface te bewerken",
+       "action-editusercss": "de CSS-bestanden van andere gebruikers te bewerken",
+       "action-edituserjson": "de JSON-bestanden van andere gebruikers te bewerken",
+       "action-edituserjs": "de JavaScriptbestanden van andere gebruikers te bewerken",
+       "action-editsitecss": "wikibrede CSS te bewerken",
+       "action-editsitejson": "wikibrede JSON te bewerken",
+       "action-editsitejs": "wikibrede JavaScript te bewerken",
+       "action-editmyusercss": "uw eigen CSS-pagina's te bewerken",
+       "action-editmyuserjson": "uw eigen JSON-pagina's te bewerken",
+       "action-editmyuserjs": "uw eigen JavaScriptpagina's te bewerken",
+       "action-viewsuppressed": "versies verborgen voor elke gebruiker te bekijken",
+       "action-hideuser": "een gebruiker voor de overige gebruikers te verbergen",
+       "action-ipblock-exempt": "IP-blokkades, automatische blokkades en IP-bereik blokkades te omzeilen",
+       "action-unblockself": "uzelf te deblokkeren",
+       "action-noratelimit": "tijdsafhankelijke beperkingen te negeren",
+       "action-reupload-own": "uw eigen bestandsuploads te overschrijven",
+       "action-nominornewtalk": "kleine bewerkingen aan een overlegpagina niet te laten leiden tot een melding 'nieuwe berichten'",
+       "action-markbotedits": "teruggedraaide bewerkingen te markeren als botbewerkingen",
+       "action-patrolmarks": "controletekens in recente wijzigingen te zien",
+       "action-override-export-depth": "pagina's te exporteren, inclusief pagina's waarnaar verwezen wordt, tot een diepte van vijf",
+       "action-suppressredirect": "geen doorverwijzingen achter te laten bij het hernoemen van pagina's",
        "nchanges": "$1 {{PLURAL:$1|bewerking|bewerkingen}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|sinds uw laatste bezoek}}",
        "enhancedrc-history": "geschiedenis",
        "recentchanges-label-unpatrolled": "Deze bewerking is nog niet gecontroleerd",
        "recentchanges-label-plusminus": "Deze paginagrootte is met dit aantal bytes gewijzigd",
        "recentchanges-legend-heading": "<strong>Legenda:</strong>",
-       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (zie ook de [[Special:NewPages|lijst met nieuwe pagina's]])",
+       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}}<br />(zie ook de [[Special:NewPages|lijst met nieuwe pagina's]])",
        "recentchanges-legend-plusminus": "(<em>±123</em>)",
        "recentchanges-submit": "Weergeven",
        "rcfilters-tag-remove": "Verwijder '$1'",
        "rcfilters-savedqueries-already-saved": "Deze filters zijn al opgeslagen. Wijzig uw instellingen om een nieuw Filter op te slaan.",
        "rcfilters-restore-default-filters": "Standaard filters terugzetten",
        "rcfilters-clear-all-filters": "Alle filters verwijderen",
-       "rcfilters-show-new-changes": "Toon nieuwste wijzigingen",
+       "rcfilters-show-new-changes": "Toon nieuwe wijzigingen sinds $1",
        "rcfilters-search-placeholder": "Filter wijzigingen (gebruik het menu of zoek op filternaam)",
        "rcfilters-invalid-filter": "Ongeldig filter",
        "rcfilters-empty-filter": "Geen actieve filters. Alle bijdragen worden weergegeven.",
        "rcfilters-filter-editsbyself-description": "Uw eigen bijdragen.",
        "rcfilters-filter-editsbyother-label": "Wijzigingen door anderen",
        "rcfilters-filter-editsbyother-description": "Alle wijzigingen behalve die door u gemaakt zijn.",
-       "rcfilters-filtergroup-userExpLevel": "Gebruikersregistratie en ervaring",
+       "rcfilters-filtergroup-user-experience-level": "Gebruikersregistratie en ervaring",
        "rcfilters-filter-user-experience-level-registered-label": "Geregistreerd",
        "rcfilters-filter-user-experience-level-registered-description": "Aangemelde bewerkers.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Niet-geregistreerd",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Het \"Kleine bewerkingen\" filter conflicteert met een of meerdere soorten wijzigingenfilters, omdat bepaalde soorten wijzigingen niet als \"klein\" kunnen worden aangewezen. De conflicterende filters zijn gemarkeerd in het Actieve filter vak hierboven.",
        "rcfilters-hideminor-conflicts-typeofchange": "Bepaalde soorten wijzigingen kunnen niet worden aangemerkt als \"klein\", dus dit filter is in conflict met de volgende soorten wijzigingenfilters: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Dit type wijzigingsfilter is in conflict met het \"Kleine bewerkingen\" filter. Bepaalde type wijzigingen kunnen niet als \"klein\" worden aangewezen.",
-       "rcfilters-filtergroup-lastRevision": "Laatste versies",
+       "rcfilters-filtergroup-lastrevision": "Laatste versies",
        "rcfilters-filter-lastrevision-label": "Laatste versie",
        "rcfilters-filter-lastrevision-description": "Alleen de meest recente wijziging aan de pagina.",
        "rcfilters-filter-previousrevision-label": "Niet de laatste versie",
        "minoreditletter": "k",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|keer|keer}} op een volglijst]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} na de wijziging",
        "newsectionsummary": "/* $1 */ nieuwe subkop",
        "rc-enhanced-expand": "Details weergeven",
        "img-auth-nopathinfo": "Padinformatie ontbreekt.\nUw server moet ingesteld zijn om de REQUEST_URI en/of PATH_INFO variabelen door te geven.\nAls de server juist ingesteld is, kunt u proberen $wgUsePathInfo aan te zetten.\nZie https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization voor meer informatie.",
        "img-auth-notindir": "Het opgegeven pad is niet de ingestelde uploadmap.",
        "img-auth-badtitle": "Het was niet mogelijk een geldige paginanaam te maken van \"$1\".",
-       "img-auth-nologinnWL": "U bent niet aangemeld en \"$1\" staat niet op de witte lijst.",
        "img-auth-nofile": "Bestand \"$1\" bestaat niet.",
        "img-auth-isdir": "U probeert de map \"$1\" te benaderen.\nAlleen toegang tot bestanden is toegestaan.",
        "img-auth-streaming": "Bezig met het streamen van \"$1\".",
        "delete-confirm": "\"$1\" verwijderen",
        "delete-legend": "Verwijderen",
        "historywarning": "<strong>Waarschuwing:</strong> de pagina die u wilt verwijderen heeft ongeveer $1 {{PLURAL:$1|versie|versies}}:",
-       "historyaction-submit": "Weergeven",
+       "historyaction-submit": "Versies weergeven",
        "confirmdeletetext": "U staat op het punt een pagina te verwijderen, inclusief de geschiedenis.\nBevestig hieronder dat dit inderdaad uw bedoeling is, dat u de gevolgen begrijpt en dat de verwijdering overeenstemt met het [[{{MediaWiki:Policy-url}}|beleid]].",
        "actioncomplete": "Handeling voltooid",
        "actionfailed": "Handeling mislukt",
        "deleting-backlinks-warning": "<strong>Waarschuwing:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|andere pagina's]] gebruiken of verwijzen naar de pagina die u wilt verwijderen.",
        "deleting-subpages-warning": "<strong>Waarschuwing:</strong>De pagina die u wilt verwijderen heeft [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|een deelpagina|$1 deelpagina's|51=meer dan 50 deelpagina's}}]].",
        "rollback": "Wijzigingen ongedaan maken",
+       "rollback-confirmation-confirm": "Bevestig:",
+       "rollback-confirmation-yes": "Terugdraaien",
+       "rollback-confirmation-no": "Annuleren",
        "rollbacklink": "terugdraaien",
        "rollbacklinkcount": "{{PLURAL:$1|één bewerking|$1 bewerkingen}} terugdraaien",
        "rollbacklinkcount-morethan": "Meer dan {{PLURAL:$1|één bewerking|$1 bewerkingen}} terugdraaien",
        "revertpage": "Wijzigingen door [[Special:Contributions/$2|$2]] ([[User talk:$2|Overleg]]) hersteld tot de laatste versie door [[User:$1|$1]]",
        "revertpage-nouser": "Wijzigingen door een verborgen gebruiker teruggedraaid naar de laatste versie door {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Wijzigingen door {{GENDER:$3|$1}} ongedaan gemaakt;\nlaatste versie van {{GENDER:$4|$2}} hersteld.",
-       "rollback-success-notify": "De wijzigingen door $1 zijn teruggedraaid;\nde laatste versie van $2 is hersteld. [$3 Wijzigingen weergeven]",
        "sessionfailure-title": "Sessiefout",
        "sessionfailure": "Er lijkt een probleem te zijn met uw aanmeldsessie.\nUw handeling is gestopt uit voorzorg tegen een beveiligingsrisico (dat bestaat uit mogelijke \"hijacking\" van deze sessie).\nProbeer het formulier opnieuw te versturen.",
        "changecontentmodel": "Inhoudsmodel van pagina bewerken",
        "mycontris": "Bijdragen",
        "anoncontribs": "Bijdragen",
        "contribsub2": "Voor {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "Voor {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "Gebruikersaccount \"$1\" bestaat niet.",
        "negative-namespace-not-supported": "Naamruimten met negatieve waarden worden niet ondersteund.",
        "nocontribs": "Geen wijzigingen gevonden die aan de gestelde criteria voldoen.",
        "ipb-confirm": "Blokkade bevestigen",
        "ipb-sitewide": "Van de hele site",
        "ipb-partial": "Gedeeltelijk",
+       "ipb-sitewide-help": "Elke pagina op de wiki en alle andere handelingen.",
        "ipb-partial-help": "Specifieke pagina's of naamruimten.",
        "ipb-pages-label": "Pagina's",
        "ipb-namespaces-label": "Naamruimten",
        "blocklist-userblocks": "Geblokkeerde accounts verbergen",
        "blocklist-tempblocks": "Tijdelijke blokkades verbergen",
        "blocklist-addressblocks": "Blokkades van één IP-adres verbergen",
+       "blocklist-type": "Soort:",
+       "blocklist-type-opt-all": "Alle",
+       "blocklist-type-opt-sitewide": "Van de hele site",
+       "blocklist-type-opt-partial": "Gedeeltelijk",
        "blocklist-rangeblocks": "IP-adresblokken verbergen",
        "blocklist-timestamp": "Tijdstip",
        "blocklist-target": "Doel",
        "blocklist-editing-page": "pagina's",
        "blocklist-editing-ns": "naamruimten",
        "ipblocklist-empty": "De blokkeerlijst is leeg.",
-       "ipblocklist-no-results": "Dit IP-adres of deze gebruikersnaam is niet geblokkeerd.",
+       "ipblocklist-no-results": "Geen blokkades gevonden voor het IP-adres of de gebruikersnaam.",
        "blocklink": "blokkeren",
        "unblocklink": "blokkade opheffen",
        "change-blocklink": "blokkade wijzigen",
+       "empty-username": "(geen gebruikersnaam beschikbaar)",
        "contribslink": "bijdragen",
        "emaillink": "e-mail verzenden",
        "autoblocker": "Automatisch geblokkeerd omdat uw IP-adres onlangs gebruikt is door \"[[User:$1|$1]]\".\nDe reden voor blokkade van $1 is: ''$2''",
        "allmessagesdefault": "Standaardinhoud",
        "allmessagescurrent": "Huidige inhoud",
        "allmessagestext": "Hieronder staan de systeemberichten uit de MediaWiki-naamruimte.\nGa naar [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] en [https://translatewiki.net translatewiki.net] als u wilt bijdragen aan de algemene vertaling voor MediaWiki.",
-       "allmessagesnotsupportedDB": "Deze pagina kan niet worden gebruikt, omdat '''$wgUseDatabaseMessages''' is uitgeschakeld.",
+       "allmessages-not-supported-database": "Deze pagina kan niet worden gebruikt, omdat '''$wgUseDatabaseMessages''' is uitgeschakeld.",
        "allmessages-filter-legend": "Filter",
        "allmessages-filter": "Filteren op aangepast:",
        "allmessages-filter-unmodified": "Ongewijzigd",
        "confirm-unwatch-top": "Deze pagina verwijderen uit uw volglijst?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Bewerkingen op deze pagina ongedaan maken?",
+       "confirm-rollback-bottom": "Hierdoor zullen de geselecteerde wijzigingen meteen terugdraaien.",
        "confirm-mcrrestore-title": "Een versie terugplaatsen",
        "confirm-mcrundo-title": "Een wijziging ongedaan maken",
        "mcrundofailed": "Ongedaan maken mislukt",
        "passwordpolicies-policy-passwordcannotbepopular": "Watchwoord mag niet {{PLURAL:$1|overeenkomen met het bekende wachtwoord|voorkomen in de lijst met $1 bekende wachtwoorden}}",
        "passwordpolicies-policy-passwordnotinlargeblacklist": "Wachtwoorden mogen niet voorkomen in de lijst met 100.000 veelvoorkomende wachtwoorden.",
        "passwordpolicies-policyflag-forcechange": "moet gewijzigd worden bij het aanmelden",
-       "unprotected-js": "Vanwege veiligheidsredenen kan er geen JavaScript geladen worden vanaf onbeveiligde pagina's. Gelieve alleen JavaScript pagina's aan te maken in de MediaWiki: naamruimte of als een subpagina van een gebruikerspagina."
+       "passwordpolicies-policyflag-suggestchangeonlogin": "raad wijzigen aan bij het aanmelden",
+       "unprotected-js": "Vanwege veiligheidsredenen kan er geen JavaScript geladen worden vanaf onbeveiligde pagina's. Gelieve alleen JavaScript pagina's aan te maken in de MediaWiki: naamruimte of als een subpagina van een gebruikerspagina.",
+       "userlogout-continue": "Als u zich wilt afmelden, [$1 gaat u naar de afmeldpagina].",
+       "userlogout-sessionerror": "Afmelden is mislukt vanwege een fout met de sessie. [$1 Probeer het opnieuw]."
 }
index 0af2815..c5d67e2 100644 (file)
        "rcfilters-filter-editsbyself-description": "Dine eigne bidrag.",
        "rcfilters-filter-editsbyother-label": "Endringar av andre",
        "rcfilters-filter-editsbyother-description": "Alle endringar utanom dine eigne.",
-       "rcfilters-filtergroup-userExpLevel": "Røynslenivå (berre for registrerte brukarar)",
+       "rcfilters-filtergroup-user-experience-level": "Røynslenivå (berre for registrerte brukarar)",
        "rcfilters-filter-user-experience-level-registered-label": "Registrerte",
        "rcfilters-filter-user-experience-level-registered-description": "Innlogga brukarar.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Uregistrerte",
        "rcfilters-filter-categorization-description": "Oppføringar av sider som vert lagde til eller fjerna frå katerogiar.",
        "rcfilters-filter-logactions-label": "Loggførte handlingar",
        "rcfilters-filter-logactions-description": "Administrative handlingar, kontoopprettingar, sideslettingar, opplastingar …",
-       "rcfilters-filtergroup-lastRevision": "Siste versjonane",
+       "rcfilters-filtergroup-lastrevision": "Siste versjonane",
        "rcfilters-filter-lastrevision-label": "Siste versjonen",
        "rcfilters-filter-lastrevision-description": "Berre den aller siste endringa på ei side.",
        "rcfilters-filter-previousrevision-label": "Ikkje den siste versjonen",
        "minoreditletter": "s",
        "newpageletter": "n",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[{{PLURAL:$1|Éin brukar|$1 brukarar}} overvakar]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte}} etter endringa",
        "newsectionsummary": "/* $1 */ ny bolk",
        "rc-enhanced-expand": "Vis detaljar",
        "img-auth-nopathinfo": "PATH_INFO saknar.\nFiltenaren din er ikkje sett opp for å gje denne informasjonen.\nHan kan vera CGI-basert og ikkje stø img_auth.\nSjå https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Den ynskte filstien er ikkje i den oppsette opplastingskatalogen",
        "img-auth-badtitle": "Kan ikkje laga ein gyldig ttitel ut frå \"$1\".",
-       "img-auth-nologinnWL": "Du er ikkje logga inn, og \"$1\" er ikkje på kvitlista.",
        "img-auth-nofile": "Fila \"$1\" finst ikkje",
        "img-auth-isdir": "Du prøver å få tilgjenge til katalogen \"$1\".\nBerre tilgjenge til filer er tillete.",
        "img-auth-streaming": "Sendar \"$1\".",
        "speciallogtitlelabel": "Mål (tittel eller {{ns:user}}:brukarnamn for brukar):",
        "log": "Loggar",
        "logeventslist-submit": "Vis",
+       "logeventslist-more-filters": "Vis fleire loggar:",
        "all-logs-page": "Alle offentlege loggar",
        "alllogstext": "Kombinert vising av alle loggane på {{SITENAME}}. Du kan avgrense resultatet ved å velje loggtype, brukarnamn eller den sida som er påverka (hugs å skilje mellom store og små bokstavar)",
        "logempty": "Ingen element i loggen passar.",
        "ipb-unblock": "Opphev blokkeringa av eit brukarnamn eller ei IP-adresse",
        "ipb-blocklist": "Vis gjeldande blokkeringar",
        "ipb-blocklist-contribs": "Bidrag frå $1",
+       "block-actions": "Handlingar som skal blokkerast:",
        "block-expiry": "Opphøyrstid:",
        "unblockip": "Opphev blokkering",
        "unblockiptext": "Bruk skjemaet nedanfor for å oppheve blokkeringa av ein tidlegare blokkert brukar.",
        "allmessagesdefault": "Standardtekst",
        "allmessagescurrent": "Gjeldande meldingstekst",
        "allmessagestext": "Dette er ei liste over systemmeldingar i MediaWiki-namnerommet.\nVitja [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] og [https://translatewiki.net translatewiki.net] om du ynskjer å bidra til den generelle omsetjinga av MediaWiki.",
-       "allmessagesnotsupportedDB": "Denne sida kan ein ikkje bruka fordi «'''$wgUseDatabaseMessages'''» er slått av.",
+       "allmessages-not-supported-database": "Denne sida kan ein ikkje bruka fordi «'''$wgUseDatabaseMessages'''» er slått av.",
        "allmessages-filter-legend": "Filtrer",
        "allmessages-filter": "Filtrer etter tilpassingsgrad:",
        "allmessages-filter-unmodified": "Ikkje endra",
        "logentry-rights-autopromote": "$1 vart automatisk {{GENDER:$2|forfremja}} frå $4 til $5",
        "logentry-upload-upload": "$1 {{GENDER:$2|lasta opp}} $3",
        "logentry-upload-overwrite": "$1 {{GENDER:$2|lasta opp}} ein ny versjon av $3",
+       "log-name-managetags": "Merkehandsamingslogg",
        "log-name-tag": "Merkelogg",
        "rightsnone": "(ingen)",
        "rightslogentry-temporary-group": "$1 (mellombels, fram til $2)",
        "revid": "versjon $1",
        "interfaceadmin-info": "$1\n\nLøyva for endring av CSS/JS/JSON-filer som gjeld heile nettstaden vart nyleg skilde ut frå <code>editinterface</code>-retten. Om du ikkje skjøner kvifor du får denne feilmeldinga, sjå [[mw:MediaWiki_1.32/interface-admin]].",
        "passwordpolicies-policy-passwordcannotmatchusername": "Passordet kan ikkje vera det same som brukarnamnet",
-       "passwordpolicies-policy-passwordcannotmatchblacklist": "Passordet kan ikkje passa med svartelista passord"
+       "passwordpolicies-policy-passwordcannotmatchblacklist": "Passordet kan ikkje passa med svartelista passord",
+       "userlogout-sessionerror": "Utlogging gjekk ikkje grunna ein øktfeil. [$1 Freist om att]."
 }
diff --git a/languages/i18n/nqo.json b/languages/i18n/nqo.json
new file mode 100644 (file)
index 0000000..79a8397
--- /dev/null
@@ -0,0 +1,674 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Babamamadidianee",
+                       "Lancine.kounfantoh.fofana",
+                       "Lanciné.kounfantoh.fofana",
+                       "Youssoufkadialy",
+                       "Amire80",
+                       "Nafadji Mory Diané",
+                       "Babamamadidiane"
+               ]
+       },
+       "underline-always": "ߕߎ߬ߡߊ߬ ߓߍ߯",
+       "underline-never": "ߡߎ߰ߡߍ߫",
+       "sunday": "ߞߊ߯ߙߌߟߏ߲",
+       "monday": "ߞߐ߬ߓߊ߬ߟߏ߲",
+       "tuesday": "ߞߐ߬ߟߏ߲",
+       "wednesday": "ߞߎ߬ߣߎ߲߬ߟߏ߲",
+       "thursday": "ߞߎ߬ߣߎ߲߬ߟߏ߲",
+       "friday": "ߛߌ߬ߣߌ߲߬ߟߏ߲",
+       "saturday": "ߞߍ߲ߘߍߟߏ߲",
+       "sun": "ߞߊ߯ߙߌߟߏ߲",
+       "mon": "ߞߐ߬ߓߊ߬ߟߏ߲",
+       "tue": "ߞߐ߬ߟߏ߲",
+       "wed": "ߓߟߐߟߐ",
+       "thu": "ߞߎ߬ߣߎ߲߬ߟߏ߲",
+       "fri": "ߛߌ߬ߣߌ߲߬ߟߏ߲",
+       "sat": "ߞߍ߲ߘߍߟߏ߲",
+       "january": "ߓߌ߲ߠߊߥߎߟߋ߲",
+       "february": "ߞߏ߲ߞߏߜߍ",
+       "march": "ߕߙߊߓߊ",
+       "april": "ߞߏ߲ߞߏߘߌ߬ߓߌ",
+       "may_long": "ߘߓߊ߬ߕߊ",
+       "june": "ߥߊ߬ߛߌ߬ߥߙߊ",
+       "july": "ߞߊ߬ߙߌ߬ߝߐ",
+       "august": "ߘߓߊ߬ߓߌߟߊ",
+       "september": "ߕߎߟߊߝߌ߲",
+       "october": "ߞߏ߲ߓߌߕߌ߮",
+       "november": "ߣߍߣߍߓߊ",
+       "december": "ߞߏߟߌ߲ߞߏߟߌ߲",
+       "january-gen": "ߓߌ߲ߠߊߥߎߟߋ߲",
+       "february-gen": "ߞߏ߲ߞߏߜߍ",
+       "march-gen": "ߕߙߊߓߊ",
+       "april-gen": "ߞߏ߲ߞߏߘߌ߬ߓߌ",
+       "may-gen": "ߘߓߊ߬ߕߊ",
+       "june-gen": "ߥߊ߬ߛߌ߬ߥߙߊ",
+       "july-gen": "ߞߊ߬ߙߌ߬ߝߐ",
+       "august-gen": "ߘߓߊ߬ߕߊ",
+       "september-gen": "ߕߎߟߊߝߌ߲",
+       "october-gen": "ߞߏ߲ߓߌߕߌ߮",
+       "november-gen": "ߣߍߣߍߓߊ",
+       "december-gen": "ߞߏߟߌ߲ߞߏߟߌ߲",
+       "jan": "ߓߌ߲ߠߊߥߎߟߋ߲",
+       "feb": "ߞߏ߲ߞߏߜߍ",
+       "mar": "ߕߙߊߓߊ",
+       "apr": "ߞߏ߲ߞߏߘߓߌ",
+       "may": "ߘߓߊ߬ߕߊ",
+       "jun": "ߥߊ߬ߛߌ߬ߥߙߊ",
+       "jul": "ߞߊ߬ߙߌ߬ߝߐ",
+       "aug": "ߘߓߊ߬ߓߌߟߊ",
+       "sep": "ߕߎߟߊߝߌ߲",
+       "oct": "ߞߏ߲ߓߌߕߌ߱",
+       "nov": "ߣߍߣߍߓߊ",
+       "dec": "ߞߏߟߌ߲ߞߏߟߌ߲",
+       "january-date": "ߓߌ߲ߠߊߥߎߟߋ߲$1",
+       "february-date": "ߞߏ߲ߞߏߜߍ$1",
+       "march-date": "ߕߙߊߓߊ$1",
+       "april-date": "ߞߏ߲ߞߏߘߌ߬ߓߌ$1",
+       "may-date": "ߘߓߊ߬ߕߊ$1",
+       "june-date": "ߥߊ߬ߛߌ߬ߥߙߊ$1",
+       "july-date": "ߞߊ߬ߙߌ߬ߝߐ$1",
+       "august-date": "ߘߓߊ߬ߓߌ߬ߟߊ$1",
+       "september-date": "ߕߎߟߊߝߌ߲$1",
+       "october-date": "ߞߏ߲ߓߌߕߌ߮$1",
+       "november-date": "ߣߍߣߍߓߊ$1",
+       "december-date": "ߞߏߟߌ߲ߞߏߟߌ߲$1",
+       "pagecategories": "{{PLURAL:$1|ߦߌߟߡߊ|ߦߌߟߡߊ ߟߎ߬}}",
+       "category_header": "ߦߌߟߡߊ ߞߐߜߍ ߟߎ߬ $1",
+       "subcategories": "ߝߊ߬ߓߏ߲߬ ߘߋ߬ߣߍ߲ ߠߎ߬",
+       "category-media-header": "ߟߊߛߋߢߊ ߦߌߟߡߊ ߣߌ߲߬ ߘߐ߫ \"$1\"",
+       "category-empty": "<em>ߞߐߜߍ߫ ߥߟߊ߫ ߟߊߛߋߢߊ߫ ߝߏߌ߫ ߕߍ߫ ߦߌߟߡߊ ߣߌ߲߬ ߞߣߐ߫ ߕߋ߲߬ߕߋ߲߬.</em>",
+       "hidden-categories": "{{PLURAL:$1|ߦߌߟߡߊ߫ ߘߏ߲߰ߣߍ߲|ߦߌߟߡߊ߫ ߘߏ߲߰ߣߍ߲ ߠߎ߬}}",
+       "category-subcat-count": "{{PLURAL:$2|ߦߟߊߡߊߙߋ߲ ߣߌ߲߬ ߠߎ߫ ߜߊ߲߰ߛߊ߲ ߠߋ߫ ߦߋ߫ ߦߌߟߡߊ ߣߌ߲߬ ߘߐ߫.|ߦߌߟߡߊ ߣߊ߬ߕߐ ߟߎ߬ ߘߐ߫߸ {{PLURAL:$1|ߦߌߟߡߊߙߋ߲|$1 ߦߌߟߡߊߙߋ߲ ߠߎ߬}} ߟߋ߬ ߦߴߊ߬ ߘߐ߫߸ ߞߙߎߞߙߍ ߟߎ߬ ߞߐߞߊ߲߬ $2}}",
+       "category-article-count": "{{PLURAL:$2|ߞߐߜߍ ߣߌ߲߬ ߘߐߙߐ߲߫ ߠߋ߬ ߦߋ߫ ߦߌߟߡߊ ߣߌ߲߬ ߘߐ߫.|ߖߡߊ߬ߦߊ߫ ߕߐ߮ ߣߊ߬ߕߊ {{PLURAL:$1|ߞߐߜߍ ߦߋ߫|$1 ߞߐߜߍ ߦߋ߫}} ߟߋ߬ ߦߋ߫ ߦߌߟߡߊ߫ ߘߌ߫߸ ߞߙߎߞߙߍ $2 ߞߐߞߊ߲߬}}",
+       "category-file-count": "{{PLURAL:$2||ߞߐߕߐ߮ ߣߌ߲߬ ߜߊ߲߰ߛߊ߲ ߠߋ߫ ߦߋ߫ ߦߌߟߡߊ ߣߌ߲߬ ߘߐ߫.ߡߍ߲ ߠߎ߬ ߦߋ߫ ߣߌ߲߬ |{{PLURAL:$1||ߞߐߕߐ߮ ߦߋ߫|$1 ߞߐߕߐ߮ ߟߎ߬ ߦߋ߫}} ߦߌߟߡߊ ߣߌ߲߬ ߘߐ߫߸ ߞߙߎߞߙߍ ߣߌ߲߬ ߕߴߊ߬ ߘߐ߫2$.}}",
+       "listingcontinuesabbrev": "ߖߊ߬ߕߋ߬ߘߊ",
+       "index-category": "ߞߐߜߍ߫ ߓߊߕߐ߲ߛߐ߲ ߠߎ߬",
+       "noindex-category": "ߞߐߜߍ߫ ߘߐߕߐ߲ߛߐ߲ߦߊߓߊߟߌ ߟߎ߬",
+       "broken-file-category": "ߞߐߕߐ߯ ߕߌߢߍߣߍ߲߫ ߛߘߌ߬ߜߋ߲߬ ߞߐߜߍ ߟߎ߬",
+       "about": "ߡߊ߬ߘߎ߮",
+       "newwindow": "(ߊ߬ ߟߊߞߊ߬ ߝߢߐߘߊ߫ ߞߎߘߊ߫ ߟߊ߫)",
+       "cancel": "ߊ߬ ߘߐߛߊ߬",
+       "moredotdotdot": "ߡߊߞߊ߬ߝߏ߬...",
+       "morenotlisted": "ߛߙߍߘߍ ߣߌ߲߬ ߘߝߊߓߊߟߌ߫ ߓߍ߫ ߞߍ߫.",
+       "mypage": "ߞߐߜߍ",
+       "mytalk": "ߞߎߡߊ",
+       "anontalk": "ߢߊߝߐߞߣߍ",
+       "navigation": "ߛߏ߲߯ߓߊߟߌ",
+       "and": "&#32;ߊ߬ ߣߌ߫",
+       "actions": "ߞߍߟߌ ߟߎ߬",
+       "namespaces": "ߕߐ߮ ߞߣߍ",
+       "variants": "ߞߊ߲ߓߏߟߏ߲ ߠߎ߬",
+       "navigation-heading": "ߛߏ߲߯ߓߊߟߌ߫ ߓߏߟߏ߲ߘߊ",
+       "errorpagetitle": "ߝߎ߬ߕߎ߲߬ߕߌ",
+       "returnto": "ߌ ߞߐߛߊ߬ߦߌ߲߬ ߦߊ߲߬ ߡߊ߬ $1.",
+       "tagline": "ߞߊ߬ ߝߘߊ߫ {{SITENAMEP}}",
+       "help": "ߘߍ߬ߡߍ߲߬ߠߌ",
+       "help-mediawiki": "ߘߍ߬ߡߍ߲߬ߠߌ߲ ߞߊ߬ ߓߍ߲߬ ߥߞߌ-ߟߊߛߋߢߊߥߙߍ ߡߊ߬",
+       "search": "ߢߌߣߌ߲ߠߌ",
+       "searchbutton": "ߢߌߣߌ߲ߠߌ",
+       "go": "ߊ߬ ߢߌߣߌ߲߫",
+       "searcharticle": "ߥߊ߫/ߕߊ߯",
+       "history": "ߘߐߜߍ ߘߐ߬ߝߐ",
+       "history_short": "ߘߐ߬ߝߐ",
+       "history_small": "ߕߊ߬ߡߌ߲߬ߣߍ߲",
+       "printableversion": "ߛߌ߰ߘߊ߫ ߜߌ߬ߙߌ߲߬ߘߌ߬ߕߊ",
+       "permalink": "ߛߘߌ߬ߜߋ߲߬ ߓߟߏߕߍ߰ߓߊߟߌ",
+       "print": "ߜߌ߬ߙߌ߲߬ߘߌ߬ߟߌ",
+       "view": "ߊ߬ ߘߐߜߍ߫",
+       "view-foreign": "ߊ߬ ߦߋ߫ ߦߊ߲߬ $1",
+       "edit": "ߊ߬ ߡߊߦߟߍ߬ߡߊ߲߬",
+       "create": "ߟߊ߬ߘߊ߲߬ߠߌ",
+       "create-local": "ߕߌ߲߬ߞߎߘߎ߲ ߞߊ߲߬ߛߓߍ߬ߟߌ ߟߊߘߏ߲߬",
+       "delete": "ߊ߬ ߖߐ߬ߛߌ߬",
+       "undelete_short": "ߟߊ߬ߛߊ߬ߦߌ߲߬ߠߌ  {{PLURAL:$1|ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߞߋߟߋ߲߫|$1 ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ ߠߎ߬}}",
+       "protect": "ߊ߬ ߟߊߞߊ߲ߘߊ߫",
+       "protect_change": "ߊ߬ ߡߊߦߟߍ߬ߡߊ߲߫",
+       "unprotect": "ߟߊ߬ߞߊ߲߬ߘߊ߬ߟߌ ߡߊߝߊ߬ߟߋ߲߬ߠߌ",
+       "newpage": "ߘߐߜߍ߫ ߞߎߘߊ",
+       "talkpagelinktext": "ߓߊ߬ߘߏ",
+       "specialpage": "ߞߐߜߍ߫ ߞߙߍߞߙߍߣߍ߲",
+       "personaltools": "ߘߎ߲߬ߘߎ߬ߡߊ߬ ߖߐ߯ߙߊ ߠߎ߬",
+       "talk": "ߓߊ߬ߘߏ߬ߓߊ߬ߘߌߦߊ",
+       "views": "ߦߌ߬ߘߊ߬ߟߌ",
+       "toolbox": "ߖߐ߯ߙߊ߲ ߠߎ߬",
+       "tool-link-emailuser": "ߢߎߡߍߙߋ߲ߞߏ߲ߘߏ߫ ߟߊߕߊ߯ {{GENDER:$1|ߟߊߓߊ߯ߙߟߊ ߣߌ߲߬ ߡߊ߬ }}",
+       "imagepage": "ߞߐߕߐ߮ ߞߐߜߍ ߘߐߜߍ߫",
+       "mediawikipage": "ߗߋߛߓߍ ߞߐߜߍ ߘߐߜߍ߫",
+       "templatepage": "ߞߙߊߞߏ ߞߐߜߍ ߘߐߜߍ߫",
+       "viewhelppage": "ߡߊ߬ߘߍ߬ߡߍ߲߬ߠߌ߲ ߞߐߜߍ ߘߐߜߍ߫",
+       "categorypage": "ߦߌߟߡߊ ߞߐߜߍ ߘߐߜߍ߫",
+       "viewtalkpage": "ߢߊߝߐߞߣߍ ߞߐߜߍ ߘߐߜߍ߫",
+       "otherlanguages": "ߞߊ߲ ߜߘߍ߫ ߟߎ߫ ߘߐ߫",
+       "redirectedfrom": "(ߌ ߟߊߞߎ߲߬ߛߌ߲߬ߣߍ߲߫ ߞߊ߬ ߓߐ߫ $1)",
+       "redirectpagesub": "ߞߐߜߍ߫ ߟߊߞߎ߲߬ߛߌ߲߬ߣߍ߲",
+       "redirectto": "ߌ ߓߘߊ߫ ߟߊߞߎ߲߬ߛߌ߲߫ ߦߊ߲߬ ߠߊ߫:",
+       "lastmodifiedat": "ߞߐߜߍ ߣߌ߲߬ ߡߊߦߟߍ߬ߡߊ߲߬ ߟߊߓߊ߲ ߞߍ߫ ߘߊ߫ $1߸ $2",
+       "protectedpage": "ߞߐߜߍ߫ ߡߊߞߊ߲ߞߊ߲ߣߍ߲",
+       "jumpto": "ߌ ߜߊ߲߫ ߞߊ߬ ߕߊ߯:",
+       "jumptonavigation": "ߛߏ߲߯ߓߊߟߌ",
+       "jumptosearch": "ߊ߬ ߕߌߙߌ߲߫",
+       "pool-timeout": "ߘߊߕߎ߲߯ߠߌ߲ ߡߊ߬ߞߐ߬ߣߐ߲߬ߠߌ߲߬ ߕߎߡߊ ߓߘߊ߫ ߕߊ߬ߡߌ߲߬",
+       "pool-errorunknown": "ߝߌ߬ߟߌ߬ ߛߎ߲߫ ߟߐ߲ߓߊߟߌ",
+       "poolcounter-usage-error": "ߟߊߓߊ߯ߙߊߟߌ߫ ߝߟߌ $1",
+       "aboutsite": "ߞߊ߬ ߓߍ߲߬ {{SITENAME}}",
+       "aboutpage": "Project:ߞߊ߬ ߓߍ߲߬",
+       "copyrightpage": "{{ns:project}}:ߛߓߍߦߟߊ ߤߊߞߍ",
+       "currentevents": "ߞߍߞߎߘߊ ߡߍ߲ ߠߎ߫ ߛߋ߲߬ߠߊ߫",
+       "currentevents-url": "Project:ߞߍߞߎߘߊ ߡߍ߲ ߠߎ߫ ߛߋ߲߬ߠߊ߫",
+       "disclaimers": "ߖߊ߲߬ߘߐ߬ߓߌ߬ߟߊ߬ߟߌ ߟߎ߬",
+       "disclaimerpage": "Project:ߖߊ߲߬ߘߐ߬ߓߌ߬ߟߊ߬ߟߌ ߡߎ߰ߡߍ",
+       "edithelp": "ߡߊ߬ߦߟߍ߬ߢߊ߲߬ߠߌ߲ ߘߍ߬ߡߍ߲߬ߠߌ߲",
+       "helppage-top-gethelp": "ߘߍ߬ߡߍ߲߬ߠߌ",
+       "mainpage": "ߓߏ߬ߟߏ߲߬ߘߊ",
+       "mainpage-description": "ߓߏ߬ߟߏ߲߬ߘߊ",
+       "policy-url": "Projet:ߓߘߍ߬ߓߘߍ߬ߟߌ",
+       "portal": "ߟߊ߬ߛߣߍ߬ߟߌ ߓߏ߬ߟߏ߲߬ߘߊ",
+       "portal-url": "Project:ߟߊ߬ߛߣߍ߬ߟߌ ߓߏ߬ߟߏ߲߬ߘߊ",
+       "privacy": "ߘߎ߲߬ߘߎ߬ߡߊ߬ ߤߊߞߍ",
+       "privacypage": "Project:ߞߊ߬ ߓߍ߲߬ ߘߎ߲߬ߘߎ߬ߡߊ߬ ߤߊߞߍ ߡߊ߬",
+       "ok": "ߏ߬ߞߍ߫",
+       "retrievedfrom": "ߊ߬ ߟߊߛߐ߬ߘߐ߲߬ ߦߊ߲߬ \"$1\"",
+       "youhavenewmessages": "{{PLURAL:$3|ߌ ߓߘߊ߫ ߗߋߛߓߍ߫ ߞߎߘߊ ߛߐ߬ߘߐ߲߬$1  $2 }}",
+       "youhavenewmessagesfromusers": "{{PLURAL:$4|ߟߋ߬ ߦߴߌ ߓߟߏ߫}} $1 ߞߊ߬ ߓߐ߫ {{PLURAL:$3|ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ߬ ߜߘߍ߫|$3ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ ߟߎ߬}} ($2)",
+       "newmessageslinkplural": "{{PLURAL:$1|ߗߋߛߓߍ߫ ߞߎߘߊ߫|999=ߗߋߛߓߍ߫ ߞߎߘߊ߫ ߟߎ߫}}",
+       "newmessagesdifflinkplural": "{{PLURAL:$1|ߡߝߊ߬ߟߋ߲߬ߠߌ߲|999=ߡߝߊ߬ߟߋ߲߬ߠߌ߲ ߠߎ߬}} ߞߐ߯ߟߕߊ.",
+       "youhavenewmessagesmulti": "ߌ ߓߘߊ߫ ߗߋߛߓߍ߫ ߞߎߘߊ ߛߐ߬ߘߐ߲߬ $1 ߞߣߐ߫",
+       "editsection": "ߊ߬ ߡߊߦߟߍ߬ߡߊ߲߫",
+       "editold": "ߡߊߦߟߍ߬ߡߊ߲߬",
+       "viewsourceold": "ߊ߬ ߛߎ߲ ߘߐߜߍ߫",
+       "editlink": "ߊ߬ ߡߊߦߟߍ߬ߡߊ߲߬",
+       "viewsourcelink": "ߊ߬ ߛߎ߲ ߠߊߓߊ߯ߙߊ߫",
+       "editsectionhint": "ߦߌߟߡߊ ߡߊߝߊ߬ߟߋ߲߬ߠߌ:$1",
+       "toc": "ߞߣߐߘߐ",
+       "showtoc": "ߦߌ߬ߘߊ߬ߟߌ",
+       "hidetoc": "ߢߡߊߘߏ߲߯ߠߌ",
+       "collapsible-expand": "ߘߐ߬ߥߙߊ߬ߟߌ",
+       "confirmable-confirm": "ߌ ߛߍ߬ߓߍ߫ ߓߊ߬ {{GENDER:$1|}}؟",
+       "confirmable-yes": "ߐ߲߬ߤߐ߲߫",
+       "confirmable-no": "ߍ߲߬ߍ߲߫",
+       "thisisdeleted": "ߦߊ߯ߟߊ߫ ߦߴߊ߬ ߝߍ߬ ߞߵߊ߬ ߦߌ߬ߘߊ߬ ߥߟߊ߫ ߞߵߊ߬ ߟߊߛߊߦߌ߲߬ ߞߎߘߊߞߍ߫ ߓߊ߬ $1؟",
+       "viewdeleted": "ߦߌ߬ߘߊ߬ߟߌ ߓߊ߬ $1؟",
+       "site-atom-feed": "$1 ߝߕߌ ߓߊߟߏ",
+       "page-atom-feed": "$1 ߝߕߌ ߓߊߟߏ",
+       "red-link-title": "ߞߐߜߍ߫ ߕߍ߫ ߦߋ߲߬ $1",
+       "sort-descending": "ߛߙߊߛߌ߰ߟߌ ߖߌ߰ߟߌ߬ ߓߟߏߡߊ߬",
+       "sort-ascending": "ߛߙߊߛߌ߰ߟߌ ߦߟߍ߬ ߓߟߏߡߊ߬",
+       "nstab-main": "ߞߐߜߍ",
+       "nstab-user": "ߞߐߜߍ߫ ߟߊߓߊ߯ߙߕߊ",
+       "nstab-media": "ߟߊߛߋߢߊ߫ ߞߐߜߍ",
+       "nstab-special": "ߘߐߜߍ߫ ߓߟߏߡߊߞߊ߬ߣߍ߲",
+       "nstab-project": "ߖߊ߬ߕߋ߬ߘߐ߬ߛߌ߰ ߞߐߜߍ",
+       "nstab-image": "ߞߐߕߐ߮",
+       "nstab-mediawiki": "ߗߋߛߓߍ",
+       "nstab-template": "ߞߙߊߞߏ",
+       "nstab-help": "ߡߊ߬ߘߍ߬ߡߍ߲߬ߠߌ߲߬ ߞߐߜߍ",
+       "nstab-category": "ߦߌߟߡߊ",
+       "mainpage-nstab": "ߓߏ߬ߟߏ߲߬ߘߊ",
+       "nosuchaction": "ߞߍߟߌ߫ ߛߎ߮ ߏ߬ ߕߴߦߋ߲߬",
+       "nosuchspecialpage": "ߘߐߜߍ߫ ߓߟߏߡߊߞߊ߬ߣߍ߲߬ ߛߎ߮ ߏ߬ ߝߋ߲߫ ߕߍ߫ ߦߊ߲߬",
+       "nospecialpagetext": "<strong>ߊߟߎ߫ ߓߘߊ߫ ߞߐߜߍ߫ ߓߟߏߡߊߞߊ߬ߣߍ߲ ߘߏ߫ ߢߌߣߌ߲߫ ߡߍ߲ ߕߺߴߦߋ߲߬.</strong>\nߞߐߜߍ߫ ߓߟߏߡߊߞߊ߬ߣߍ߲߫ ߓߘߍ߬ߡߊ ߟߎ߬ ߛߙߍߘߍ ߦߋ߫ ߢߌ߲߬ ߠߋ߫ ߞߊ߲߬ [[Special:SpecialPages|{{int:specialpages}}]].",
+       "error": "ߝߎ߬ߕߎ߲߬ߕߌ",
+       "badtitle": "ߞߎ߲߬ߕߐ߰ ߖߎ߮",
+       "badtitletext": "ߞߐߜߍ߫ ߡߊߢߌ߬ߣߌ߲߬ߞߊ߬ߣߍ߲ ߞߎ߲߬ߕߐ߮ ߓߍ߲߬ߣߍ߲߬ ߕߍ߫߸ ߊ߬ ߘߐߞߏߟߏ߲ ߦߋ߫߸ ߥߟߊ߫ ߞߊ߲ ߠߎ߬ ߣߌ߫ ߢߐ߲߯ߕߍ߫ ߛߘߌ߬ߜߋ߲ ߓߍ߲߬ߓߊߟߌ ߤߊߡߊ߲߫ ߥߞߌ ߟߎ߬ ߕߍ߫ ߛߘߌ߬ߜߋ߲.\nߛߓߍߘߋ߲߫ ߞߋߟߋ߲߫ ߥߟߊ߫ ߛߌߦߊߡߊ߲ ߠߎ߬ ߟߋ߬ ߦߋ߫ ߞߍ߫ ߟߴߊ߬ ߘߐ߫߸ ߡߍ߲ ߠߎ߬ ߕߴߛߋ߫ ߞߍ߫ ߟߊ߫ ߞߎ߲߬ߕߐ߯ ߘߌ߫.",
+       "viewsource": "ߊ߬ ߛߎ߲ ߘߐߜߍ߫",
+       "viewsource-title": "ߣߌ߲߬ $1 ߛߎ߲ ߘߐߜߍ߫",
+       "viewsourcetext": "ߌ ߘߌ߫ ߛߋ߫ ߞߐߜߍ ߣߌ߲߬ ߛߎ߲ ߦߋ߫ ߟߊ߫߸ ߞߵߊ߬ ߓߊߓߌ߬ߟߊ߬",
+       "yourname": "ߟߊߓߊ߯ߙߊߟߊߕߐ߮:",
+       "userlogin-yourname": "ߟߊ߬ߓߊ߰ߙߊ߬ߟߌ߬ ߕߐ߮",
+       "userlogin-yourname-ph": "ߌ ߟߊ߫ ߟߊ߬ߓߊ߰ߙߊ߬ߟߌ߬ ߕߐ߮ ߟߊߘߏ߲߬",
+       "createacct-another-username-ph": "ߟߊߓߊ߯ߙߊߟߊߕߐ߮ ߟߊߘߏ߲߬",
+       "yourpassword": "ߕߊ߬ߡߌ߲߬ߞߊ߲:",
+       "userlogin-yourpassword": "ߕߊ߬ߡߌ߲߬ߞߊ߲",
+       "userlogin-yourpassword-ph": "ߌ ߟߊ߫ ߕߊ߬ߡߌ߲߬ߞߊ߲ ߠߊߘߏ߲߬",
+       "createacct-yourpassword-ph": "ߌ ߟߊ߫ ߕߊ߬ߡߌ߲߬ߞߊ߲ ߠߊߘߏ߲߬",
+       "yourpasswordagain": "ߕߊ߬ߡߌ߲߬ߞߊ߲ ߛߓߍ߫ ߞߎߘߊߞߍ߫",
+       "createacct-yourpasswordagain": "ߕߊ߬ߡߌ߲߬ߞߊ߲ ߡߊߛߊ߬ߦߌ߬",
+       "createacct-yourpasswordagain-ph": "ߌ ߟߊ߫ ߕߊ߬ߡߌ߲߬ߞߊ߲ ߠߊߘߏ߲߬ ߕߎ߲߯",
+       "userlogin-remembermypassword": "ߒ ߜߊ߲߬ߞߎ߲߬ߣߍ߲ ߕߏ߫ ߞߘߊߎ߫",
+       "login": "ߌ ߜߊ߲߬ߞߎ߲߬",
+       "userlogin-noaccount": "ߖߊ߬ߕߋ߬ߘߊ߬ ߕߴߌ ߓߟߏ߫ ߓߊ߬؟",
+       "userlogin-joinproject": "ߘߏ߫ ߟߊߞߊ߬ {{SITENAME}}",
+       "createaccount": "ߖߊ߬ߕߋ߬ߘߊ ߘߏ߫ ߟߊߞߊ߬",
+       "userlogin-resetpassword-link": "ߌ ߟߊ߫ ߕߊ߬ߡߌ߲߬ߞߊ߲ ߓߘߊ߫ ߓߐ߫ ߌ ߞߣߐ߫؟",
+       "userlogin-helplink2": "ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ߘߍ߬ߡߍ߲߬ߠߌ߲",
+       "createacct-emailoptional": "ߢߎߡߍߙߋ߲߫ ߞߏ߲ߘߏ",
+       "createacct-email-ph": "ߌ ߟߊ߫ ߢߎߡߍߙߋ߲߫ ߞߏ߲ߘߏ ߟߊߘߏ߲߬",
+       "createacct-submit": "ߖߊ߬ߕߋ߬ߘߊ ߘߏ߫ ߘߊߦߟߍ߬",
+       "createacct-benefit-heading": "{{SITENAME}} ߛߌ߲ߘߌߣߍ߲߫ ߦߴߌ ߢߐ߲߭ ߡߐ߱ ߟߎ߬ ߟߋ߬ ߓߟߏ߫",
+       "createacct-benefit-body1": "{{PLURAL:$1|ߊ߬ ߡߊߦߟߍ߬ߡߊ߲߬|ߊ߬ߟߎ߬ ߡߊߦߟߍ߬ߡߊ߲߬}}",
+       "createacct-benefit-body2": "$1 {{PLURAL:$1|ߘߐߜߍ|ߞߐߜߍ ߟߎ߬}}",
+       "createacct-benefit-body3": "ߕߊ߬ߡߌ߲߬ߣߍ߲߬ ߞߎߘߊ {{PLURAL:$1|ߓߟߏߓߌߟߊߢߐ߲߮ߞߊ߲ߠߊ|ߓߟߏߓߌߟߊߢߐ߲߮ߞߊ߲ߠߊ ߟߎ߬}}",
+       "loginlanguagelabel": "ߞߊ߲ $1",
+       "pt-login": "ߌ ߜߊ߲߬ߞߎ߲߬",
+       "pt-login-button": "ߌ ߜߊ߲߬ߞߎ߲߬",
+       "pt-createaccount": "ߖߊ߬ߕߋ߬ߘߊ ߘߏ߫ ߛߌ߲ߘߌ߫",
+       "pt-userlogout": "ߌ ߜߊ߲߬ߞߎ߲߬ߣߍ߲ ߓߐ߫",
+       "passwordreset": "ߕߊ߬ߡߌ߲߬ߞߊ߲ ߡߊߦߟߍ߬ߡߊ߲߬",
+       "bold_sample": "ߛߓߍߘߋ߲߫ ߞߎ߲ߓߊ",
+       "bold_tip": "ߛߓߍߘߋ߲߫ ߞߎ߲ߓߊ",
+       "italic_sample": "ߛߓߍߟߌ߫ ߡߊߖߍ߲߬ߞߍ߬ߣߍ߲",
+       "italic_tip": "ߛߓߍߟߌ߫ ߡߊߖߍ߲߬ߞߍ߬ߣߍ߲",
+       "link_sample": "ߛߘߌ߬ߜߋ߲ ߞߎ߲߬ߕߐ߮",
+       "link_tip": "ߞߣߐߘߐ߫ ߛߘߌߜߋ߲",
+       "extlink_sample": "ߛߘߌ߬ߜߋ߲ ߞߎ߲߬ߕߐ߮ http://www.example.com",
+       "extlink_tip": "ߞߣߐߟߊߘߐ߫ ߛߘߌߜߋ߲",
+       "headline_sample": "ߞߎ߲߬ߕߐ߮ ߛߓߍߟߌ",
+       "headline_tip": "ߞߊߓߋ ߂߲ ߞߎ߲߬ߕߐ߮",
+       "nowiki_sample": "ߛߓߍߟߌ߫ ߖߙߎߡߎ߲ߕߊ߲ ߠߊߘߏ߲߬ ߦߊ߲߬",
+       "nowiki_tip": "ߥߞߌ߫ ߛߏ߯ߙߏߟߌ ߡߊߓߌ߬ߟߊ߬",
+       "image_tip": "ߞߐߕߐ߮ ߘߐߘߏ߲߬ߣߍ߲",
+       "media_tip": "ߞߐߕߐ߮ ߛߘߌ߬ߜߋ߲",
+       "sig_tip": "ߌ ߟߊ߫ ߞߟߊ߬ߣߐ ߕߎ߬ߡߊ߬ߘߊ ߓߊ߬ߘߌ߬ߟߊ߲߬ߡߊ",
+       "hr_tip": "ߛߌ߬ߕߊ߬ߙߌ߬ ߢߊߡߌߟߏߡߊ (ߊ߬ ߕߐ߬ߝߍ߬ߦߊ߬ ߟߊߓߊ߯ߙߊ߫)",
+       "summary": "ߟߊ߬ߘߛߏ߬ߟߌ:",
+       "minoredit": "ߣߌ߲߬ ߦߋ߫ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߘߋ߬ߣߍ߲ ߘߏ߫ ߟߋ߬ ߘߌ߫",
+       "watchthis": "ߘߐߜߍ ߣߌ߲߬ ߘߐߜߍ߫",
+       "savearticle": "ߊ߬ ߟߊߞߎ߲߬ߘߎ߬",
+       "preview": "ߊ߬ ߘߐߜߍ߫ ߡߎߣߎ߲߬",
+       "showpreview": "ߢߍߦߋߟߌ ߘߐߜߍ߫",
+       "showdiff": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ ߠߎ߫ ߦߌ߬ߘߊ߬",
+       "anoneditwarning": "<strong>Warning:</strong> ߌ ߜߊ߲߬ߞߎ߲߬ߣߍ߲߬ ߕߍ߫.ߌ ߓߊ߯ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߛߎ߯-ߎ߯-ߛߎ߫ ߞߍ߫߸ ߌ ߟߊ߫ IP ߛߊ߲߬ߓߊ߬ߕߐ߮ ߘߌ߫ ߞߍ߫ ߦߋߕߊ ߘߌ߫.ߣߴߌ ߞߊ߬ ߜߊ߲߬ߞߎ߲߬ߠߌ߲߬ ߖߐ߲ߖߐ߲ ߞߍ߫ ߕߎ߬ߡߊ ߡߍ߲ <strong>[$1 log in]</strong> or <strong>[$2 create an account]</strong> ߌ ߟߊ߫ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߣߍ߲ ߠߎ߬ ߘߌ߫ ߓߌ߬ߟߊ߬ ߌ ߜߊ߲߬ߞߎ߲߬ ߕߐ߮ ߟߊ߫߸ ߊ߬ ߣߌ߫ ߣߝߊ߬ ߜߘߍ߫ ߟߎ߫.",
+       "blockedtext": "<strong>ߌ ߟߊ߫ ߟߊ߬ߓߊ߰ߙߊ߬ ߕߐ߮ ߥߟߊ߫ IP ߛߊ߲߬ߓߊ߬ߕߐ߮ ߓߘߊ߫ ߓߊ߬ߟߊ߲߬߸</strong>\n\nߌ ߓߊ߬ߟߊ߲߬ߣߍ߲߬ ߦߋ߫ $1 ߟߋ߬ ߓߟߏ߫.\nߞߎ߲߭ ߡߍ߲ ߦߴߊ߬ ߟ߫ߊ߫ <em>$2</em>.\n\n•ߓߊ߬ߟߊ߲߬ߠߌ߲ ߘߊߡߌ߬ߣߊ: $8\n•ߓߊ߬ߟߊ߲߬ߠߌ߲ ߛߕߊ ߝߊ: $6\n•ߓߊ߬ߟߊ߲߬ߠߌ߲ ߘߊ߬ߟߎ: $7 \n\nߌ ߘߌ߫ ߛߋ߫ ߗߋߛߓߍ ߗߋ߫ ߟߊ߫ $1 ߡߊ߬ ߥߟߊ߫ ߡߐ߰ ߜߘߍ߫ \n[[{{MediaWiki:Grouppage-sysop}}|administrator]] ߞߊ߬ ߘߊߘߐߖߊߥߏ ߞߍ߫ ߓߊ߬ߟߊ߲߬ߠߌ߲ ߞߊ߲߬.\nߌ ߕߍ߫ ߣߊ߬ ߛߋ߫ ߟߊ߫  \"{{int:emailuser}}\" ߟߊߓߊ߯ߙߊ߫ ߟߊ߫߸ ߟߊ߬ߓߊ߰ߙߊ߬ߢߊ߬ ߖߐ߲ߖߐ߲ ߡߍ߲ ߦߋ߫ ߦߋ߲߬߸ ߢߎߡߍߙߋ߲߫ ߞߏ߲ߘߏ߫ ߖߐ߲ߖߐ߲߫ ߓߟߏߡߊߞߊ߬ߣߍ߲ ߘߏ߫ ߦߴߌ ߟߊ߫ [[Special:Preferences|account preferences]] ߘߐ߫߸ ߊ߬ ߣߴߌ ߡߊ߫ ߓߊ߬ߟߊ߲߬ ߊ߬ ߟߊߓߊ߯ߙߊ ߞߏߛߐ߲߬ ߘߋ߫. ߌ ߟߊ߫ IP ߛߊ߲߬ߓߊ߬ߕߐ߮ ߦߋ߫ $3 ߟߋ߬ ߘߌ߫ ߕߊ߲߬߸ ߊ߬ ߣߴߌ ߟߊ߫ ߛߊ߲߬ߓߊ߬ߕߐ߮ ߓߊ߬ߟߊ߲߬ߣߍ߲ ߦߋ߫ #$5 ߟߋ߬ ߘߌ߫.\nߖߊ߰ߣߌ߲߬ ߌ ߦߋ߫ ߛߊ߲ߝߍ߫ ߝߊߙߊ߲ߝߊ߯ߛߌ ߣߌ߲߬ ߓߍ߯ ߟߊߘߏ߲߬ ߌ ߟߊ߫ ߢߌ߬ߣߌ߲߬ߞߊ߬ߟߌ ߘߐ߫.",
+       "loginreqlink": "ߌ ߜߊ߲߬ߞߎ߲߬",
+       "newarticletext": "ߌ ߓߘߊ߫ ߛߘߌ߬ߜߋ߲ ߘߏ߫ ߟߊߓߊ߬ߕߏ߬ ߞߐߜߍ ߘߏ߫ ߘߐ߫߸ ߡߍ߲ ߕߴߦߋ߲߬ ߡߎߣߎ߲߬.\nߣߵߌ ߦߴߊ߬ ߝߍ߫ ߞߊ߬ ߞߐߜߍ ߘߏ߫ ߟߊߘߊ߲߫߸ ߛߓߍߟߌ ߘߊߡߌ߬ߣߊ߬ ߘߎ߰ߟߊ߬ߘߐ߫ ߞߏ߲ߘߏ ߘߐ߫ (ߞߊ߬ [$1 ߘߍ߬ߡߍ߲߬ߠߌ߲ ߞߐߜߍ] ߦߋ߫߸ ߖߐ߲߬ߛߊ߬ ߌ ߘߌ߫ ߞߌ߬ߓߊ߬ߙߏ߬ ߖߐ߲ߖߐ߲ ߛߐ߬ߘߐ߲߬). ߣߵߌ ߘߏ߲߬ ߞߍ߫ ߘߊ߫ ߦߊ߲߬ ߝߎ߬ߕߎ߲߬ߕߌ߬ ߓߟߏߡߊ߬߸ ߌ ߟߊ߫ ߛߏ߲߯ߓߊߟߊ߲ <strong>back</strong> ߛߐ߲߬ߞߌ߲߫.",
+       "noarticletext": "ߛߓߍߟߌ߫ ߛߌ߫ ߕߍ߫ ߞߐߜߍ ߣߌ߲߭ ߞߊ߲߬ ߕߋ߲߫. ߌ ߘߌ߫ ߛߋ߫ ߞߐߜߍ ߣߌ߲߬ \n [[Special:Search/{{PAGENAME}}|search for this page title]] ߕߐ߮ ߢߌߣߌ߲߫ ߠߊ߫ ߞߐߜߍ ߕߐ߭ ߟߎ߬ ߘߐ߫߸  \n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} search the related logs],\nor [{{fullurl:{{FULLPAGENAME}}|action=edit}} create this page]</span>.",
+       "noarticletext-nopermission": "ߛߓߍߟߌ߫ ߛߌ߫ ߕߍ߫ ߞߐߜߍ ߣߌ߲߭ ߞߊ߲߬ ߕߋ߲߫.\nߌ ߘߌ߫ ߛߋ߫ [[Special:Search/{{PAGENAME}}|search for this page title]] ߢߌߣߌ߲߫ ߠߊ߫ ߞߐߜߍ ߕߐ߭ ߟߎ߬ ߘߐ߫߸ ߥߟߊ߫ <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} search the related logs]</span> ߞߏ߬ߣߌ߲߬ ߘߌ߬ߢߍ߬ ߞߍߣߍ߲߫ ߕߴߌ ߡߊ߬ ߞߐߜߍ߫ ߣߌ߲߬ ߠߊߞߊ߭ ߘߐ߫.",
+       "userpage-userdoesnotexist-view": "ߟߊ߬ߓߊ߰ߙߊ߬ ߖߊߕߋߘߊ \"$1\" ߟߊߞߎ߲߬ߘߎ߬ߣߍ߲߫ ߕߍ߫.",
+       "previewnote": "<strong>ߌ ߖߊ߲߬ߓߌ߬ߟߊ߬ ߞߏ߫ ߣߌ߲߬ ߦߋ߫ ߢߍߝߟߍߟߌ ߘߐߙߐ߲߫ ߠߋ߬ ߘߌ߫.</strong>\nߌ ߟߊ߫ ߡߝߊ߬ߟߋ߲߬ߠߌ ߟߎ߫ ߡߊ߫ ߟߊߞߎ߲߬ߘߎ߬ ߝߟߐ߫ ߘߋ߬߹",
+       "continue-editing": "ߥߊ߫ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߬ ߞߣߍ ߞߊ߲߬",
+       "editing": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߦߋ߫ ߛߋ߲߬ߠߊ߫ $1",
+       "creating": "$1 ߛߌ߲ߘߟߌ ߦߋ߫ ߛߋ߲߬ߠߊ߫",
+       "editingsection": "(ߛߌ߰ߘߊ߬) $1 ߡߊߦߟߍ߬ߡߊ߲ ߦߋ߫ ߛߋ߲߬ߠߊ߫",
+       "templatesused": "{{PLURAL:$1|ߞߙߊߞߏ|ߞߙߊߞߏ ߟߎ߫}} ߟߎ߫ ߟߊߓߊ߯ߙߊ߫ ߘߊ߫ ߞߐߜߍ ߣߌ߲߬ ߘߐ߫",
+       "templatesusedpreview": "{{PLURAL:$1|ߞߙߊߞߏ|ߞߙߊߞߏ ߟߎ߬}} ߟߋ߬ ߟߊߓߊ߯ߙߊ߫ ߣߍ߲߫ ߢߍߦߋߟߌ ߣߌ߲߬ ߘߐ߫",
+       "template-protected": "(ߊ߬ ߟߊߞߊ߲ߘߊߣߍ߲ ߠߋ߬)",
+       "template-semiprotected": "(ߟߊ߬ߞߊ߲߬ߘߊ߬ߟߌ-ߝߊ߲߬ߞߋ߬ߟߋ߲߬ߡߊ)",
+       "hiddencategories": "ߞߐߜߍ ߣߌ߲߬ ߦߋ߫ ߢߌ߲߬ ߠߎ߫ ߛߌ߲߬ߝߏ߲ ߠߋ߬ ߘߌ߫{{PLURAL:$1|}}",
+       "permissionserrors": "ߝߌ߬ߟߌ߫ ߘߌ߬ߢߍ߬ߒߧߋ",
+       "permissionserrorstext-withaction": "ߟߊ߬ߘߌ߬ߢߍ߬ߟߌ߬ ߛߌ߫ ߕߴߌ ߦߋ߫ ߞߊ߬ $2߸ {{PLURAL:$1|ߞߏߛߐ߲߬|ߟߎ߬ ߞߏߛߐ߲߬}}",
+       "recreate-moveddeleted-warn": "<strong>ߌ ߖߊ߲߬ߕߏ߫: ߌ ߦߋ߫ ߞߐߜߍ ߘߏ߫ ߟߋ߬ ߟߊߘߊ߲߫ ߞߏ ߘߐ߫ ߣߌ߲߬߸ ߡߍ߲ ߖߏ߬ߛߌ߬ߣߍ߲߬ ߡߎߣߎ߲߬.</strong> \nߌ ߓߛߌ߬ߞߌ߬ ߕߐ߫ ߟߋ߬ ߛߍ߲߸ ߣߴߌ ߘߌ߫ ߛߋ߫ ߞߐߜߍ ߣߌ߲߬ ߡߊߦߟߍ߬ߡߊ߲ ߘߊߓߊ߲߫ ߠߊ߫. \nߞߐߜߍ ߣߌ߲߬ ߦߟߌߣߐ ߖߏ߬ߛߌ߬ߣߍ߲ ߣߴߊ߬ ߛߋ߲߬ߓߐ߬ߣߍ߲ ߠߎ߬ ߡߊߘߊ߲ߣߍ߲߫ ߦߊ߲߬ ߠߋ ߟߊ߬ߣߐ߰ߦߊ߬ߟߌ ߘߌ߫:",
+       "moveddeleted-notice": "ߞߐߜߍ ߣߌ߲߬ ߓߘߊ߫ ߖߏ߬ߛߌ߬.\nߖߏ߬ߛߌ߬ߟߌ߸ ߟߊ߬ߞߊ߲߬ߘߊ߬ߟߌ߸ ߊ߬ ߣߌ߫ ߞߐߜߍ ߛߓߍߟߌ ߟߎ߬ ߛߋ߲߬ߓߐ߸ ߏ߬ ߟߎ߫ ߓߍ߯ ߡߊߛߐߣߍ߲߫ ߦߋ߫ ߘߎ߰ߟߊ ߘߐ߫.",
+       "content-model-wikitext": "ߥߞߌ߫ ߞߟߏߜߍ",
+       "undo-failure": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߕߍ߫ ߣߊ߬ ߛߋ߫ ߟߊ߫ ߘߐߛߊ߬ ߟߊ߫߸ ߝߘߏ߬ߒ߬ߡߊ߬ߟߌ߬ ߡߊߦߟߍߡߊ߲ߠߌ߲ ߞߏߛߐ߲߬.",
+       "viewpagelogs": "ߞߐߜߍ ߣߌ߲߬ ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ߠߎ߬ ߦߋ߫",
+       "currentrev-asof": "$1 ߟߊ߫ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߕߊ߬ߡߌ߲߬ߣߍ߲",
+       "revisionasof": "ߊ߬ ߡߊߛߊ߬ߦߌ߲ ߦߊ߲߬ ߓߊ߫ 1$",
+       "revision-info": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߣߍ߲߫ $1 ߟߋ߬ ߓߟߏ߫ {{GENDER:$6|$2}}$7",
+       "previousrevision": "→ ߡߊ߬ߛߊ߬ߦߌ߲߬ߠߌ߲ ߞߘߐ߬ߡߊ߲",
+       "nextrevision": "ߡߊ߬ߛߋ߬ߦߌ߲߬ߣߍ߲߬ ߞߎߘߊ ←",
+       "currentrevisionlink": "ߡߊ߬ߛߊ߬ߦߌ߲߬ߠߌ߲ ߕߊ߬ߡߌ߲߬ߣߍ߲",
+       "cur": "ߞߍߞߎߘߊ",
+       "last": "ߢߍߕߊ",
+       "history-fieldset-title": "ߣߐ߬ߡߊ߬ߛߊߦߌ߲ ߠߎ߬ ߛߍ߲ߛߍ߲߫",
+       "histfirst": "ߞߘߐ߬ߡߊ߲ ߠߎ߬",
+       "histlast": "ߞߎߘߊ ߟߎ߬",
+       "history-feed-title": "ߡߊ߬ߛߊ߬ߦߌ߲߬ߠߌ߲ ߘߐ߬ߝߐ",
+       "history-feed-description": "ߞߐߜߍ ߣߌ߲߬ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߘߐ߬ߝߐ߸ ߥߞߌ ߘߐ߫",
+       "rev-delundel": "ߊ߬ ߦߋߢߊ ߡߊߦߟߍ߬ߡߊ߲߫",
+       "mergelog": "ߥߴߌ ߜߊ߲߬ߞߎ߲߬",
+       "history-title": "$1 ߡߛߊ߬ߦߌ߲߬ߠߌ߲ ߘߐ߬ߝߐ",
+       "difference-title": "ߘߊ߲߬ߝߘߊ߬ߓߐ ߡߍ߲ ߦߋ߫ ߡߛߊ߬ߦߌ߲߬ߠߌ߲ $1 ߕߍ߫",
+       "lineno": "$1 ߛߌ߬ߕߊߙߌ:",
+       "compareselectedversions": "ߘߟߊߡߌߘߊ߫ ߛߎߥߊ߲ߘߌߣߍ߲ ߠߎ߬ ߟߊߢߐ߲߯ߡߊ߫",
+       "editundo": "ߊ߬ ߘߐߛߊ߬߸ ߊ߬ ߓߟߏߞߊ߬߸ ߊ߬ ߓߙߐߕߐ߫",
+       "diff-empty": "(ߝߊߙߊ߲ߝߊ߯ߛߌ߫ ߕߴߊ߬ߟߎ߬ ߕߍ߫)",
+       "diff-multi-sameuser": "({{PLURAL:$1|One intermediate revision|$1 intermediate revisions}} ߟߊ߬ߓߊ߰ߙߊ߬ ߞߋߟߋ߲ ߓߟߏ߫߸ ߏ߬ ߡߊ߫ ߦߌ߬ߘߊ߬)",
+       "diff-multi-otherusers": "({{PLURAL:$1|ߕߍ߯ߟߊߘߐ߫ ߡߛߊߦߌ߲ߠߌ߲߫ ߞߋߟߋ߲߫|ߕߍ߯ߟߊߘߐ߫ ߡߛߊߦߌ߲ߠߌ߲}} {{PLURAL:$2|ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ߫ ߘߏ߫ ߜߘߍ߫|ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ ߟߎ߬}} ߓߟߏ߫߸ ߏ߬ ߡߊ߫ ߦߌ߬ߘߊ߬)",
+       "searchresults": "ߢߌߣߌ߲ߠߌ߲ ߞߐߝߟߌ ߟߎ߬",
+       "searchresults-title": "ߢߌߣߌ߲ߠߌ߲ ߞߐߖߋߓߌ \"$1\"",
+       "prevn": "ߕߊ߬ߡߌ߲߬ߣߍ߲ ߠߎ߬ {{PLURAL:$1|$1}}",
+       "nextn": "$1{{PLURAL:$1|ߟߊߕߎ߲߰ߠߊ}}",
+       "prevn-title": "ߢߝߍߕߊ $1 {{PLURAL:$1|result|results}}",
+       "nextn-title": "ߢߍߕߊ $1 {{PLURAL:$1|ߞߐߖߋߓߌ}}",
+       "shown-title": "ߦߌߘߊߞߊ߬ $1{{PLURAL:$1|ߞߐߝߟߌ |ߞߐߝߟߌ ߟߎ߬ }} ߞߐߜߍ߫ ߞߋ߬ߟߋ߲߬ߞߋ߬ߟߋ߲߬ߠߊ",
+       "viewprevnext": "($1 {{int:pipe-separator}} $2) ($3) ߦߋ߫",
+       "searchmenu-exists": "</strong> ߞߐߜߍ ߘߏ߫ ߕߐ߯ ߦߋ߫ ߞߏ߫  \"[[:$1]]\" ߥߞߌ ߣߌ߲߬ ߘߐ߫.</strong> {{PLURAL:$2|0=|See also the other search results found.}}",
+       "searchmenu-new": "<strong>ߞߐߜߍ ߘߏ߫ ߟߊߘߊ߲߫ \"[[:$1]]\" ߥߞߌ ߣߌ߲߬ ߘߐ߫߹</strong>  {{PLURAL:$2|0=|ߣߌ߲߬ ߝߣߊ߫ ߘߐߜߍ߫ the page found with your search.|ߣߌ߲߬ ߝߣߊ߫ ߘߐߜߍ߫ the search results found.}}",
+       "searchprofile-articles": "ߞߐߜߍ ߞߣߐߘߐ",
+       "searchprofile-images": "ߡߍ߲ߕߊߦߋߕߊ",
+       "searchprofile-everything": "ߊ߬ ߡߎ߰ߡߍ",
+       "searchprofile-advanced": "ߖߊ߲߬ߝߊ߬ߣߍ߲",
+       "searchprofile-articles-tooltip": "ߊ߬ ߢߌߣߌ߲߫ $1 ߘߐ߫",
+       "searchprofile-images-tooltip": "ߞߐߕߐ߮ ߟߎ߬ ߢߌߣߌ߲߫",
+       "searchprofile-everything-tooltip": "ߊ߬ ߞߣߐߘߐ ߓߍ߯ ߢߌߣߌ߲߫ (ߤߊߟߌ߬ ߞߎߡߊߢߐ߲߯ߦߊ߫ ߞߐߜߍ ߟߎ߬)",
+       "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-section": "(ߕߍߕߍ߮ $1)",
+       "search-file-match": "(ߞߐߕߐ߮ ߞߣߐߘߐ ߓߘߊ߫ ߟߊߞߊ߬ߝߏ߬)",
+       "search-suggest": "ߌ ߞߊ߲߫ ߦߋ߫ ߣߌ߲߬ ߠߋ߬ ߡߊ߬ $1",
+       "searchall": "ߊ߬ ߓߍ߯",
+       "search-showingresults": "{{PLURAL:$4|Result <strong>$1</strong> of <strong>$3</strong>|Results <strong>$1 – $2</strong> of <strong>$3</strong>}}",
+       "search-nonefound": "ߖߋ߬ߓߟߌ߬ ߛߌ߫ ߕߍ߫ ߢߌ߬ߣߌ߲߬ߞߊ߬ߟߌ ߣߌ߲߫ ߞߊ߲߬.",
+       "mypreferences": "ߟߊ߬ߝߌ߬ߛߦߊ߬ߟߌ",
+       "group-bot": "ߓߏߕ",
+       "group-sysop": "ߞߎ߲߬ߠߊ߬ߛߌ߰ߟߊ",
+       "grouppage-bot": "{{ns:project}}:ߓߏߕ",
+       "grouppage-sysop": "{{ns:project}}:ߡߊ߬ߡߙߊ߬ߟߌ߬ߟߊ",
+       "right-writeapi": "ߛߓߍߟߌ API ߟߊߓߊ߯ߙߊ߫",
+       "newuserlogpage": "ߖߊ߬ߕߋ߬ߘߊ߬ ߓߘߊ߫ ߟߊߞߊ߬ ߌ ߜߊ߲߬ߞߎ߲߬",
+       "rightslog": "ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ ߜߊ߲߬ߞߎ߲߬ ߢߊ߬ ߓߘߍ",
+       "action-edit": "ߞߐߜߍ ߣߌ߲߬ ߡߊߦߟߍ߬ߡߊ߲߬",
+       "action-createaccount": "ߖߊ߬ߕߋ߬ߘߊ߬ ߟߊߓߊ߯ߙߕߊ ߣߌ߲߬ ߠߊߘߊ߲߫",
+       "enhancedrc-history": "ߕߊ߬ߡߌ߲߬ߣߍ߲",
+       "recentchanges": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߞߎߘߊ ߟߎ߬",
+       "recentchanges-legend": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߞߎߘߊ ߟߎ߫ ߟߊ߬ߓߍ߲߬ߢߐ߰ߡߦߊ߬ߘߊ",
+       "recentchanges-summary": "ߥߞߌ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߞߎ߲ߓߊ ߡߍ߲ ߠߎ߬ ߞߍߣߍ߲߫ ߞߐߜߍ ߣߌ߲߬ ߞߊ߲߬߸ ߏ߬ ߟߎ߫ ߣߐ߬ߣߐ߬.",
+       "recentchanges-noresult": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߬ ߛߌ߫ ߓߍ߲߬ߢߐ߲߰ߦߊ߬ߣߍ߲߬ ߕߍ߫ ߛߎߡߊ߲ߡߕߊ ߢߌ߲߬ ߠߎ߫ ߡߊ߬ ߕߎ߬ߡߊ߬ ߟߊߕߍ߰ߣߍ߲ ߦߌ߬ߘߊ ߘߐ߫.",
+       "recentchanges-label-newpage": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߣߌ߲߬ ߓߘߊ߫ ߘߐߜߍ߫ ߞߎߘߊ ߟߊߘߊ߲߫",
+       "recentchanges-label-minor": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߘߋ߬ߣߍ߲ ߠߋ߫ ߦߋ߫",
+       "recentchanges-label-bot": "ߡߐ߰ߡߐ߮ ߟߋ߫ ߣߐ߬ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ ߣߌ߲߬ ߞߍ߫ ߟߊ߫",
+       "recentchanges-label-unpatrolled": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߣߌ߲߬ ߡߊ߫ ߓߍ߬ߙߍ߲߬ߓߍ߬ߙߍ߲߬ ߡߎߣߎ߲߬",
+       "recentchanges-label-plusminus": "ߞߐߜߍ ߢߊ߲ߞߊ߲ ߓߘߊ߫ ߡߊߦߟߍ߬ߡߊ߲߫ ߞߵߊ߬ ߝߌ߬ߘߊ߲ ߦߙߌߞߊ ߣߌ߲߬ ߘߌ߫",
+       "recentchanges-legend-heading": "<strong>ߡߊ߬ߛߙߋ:</strong>",
+       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (ߣߌ߲߬ ߝߣߊ߫ ߦߋ߫ \n[[Special:NewPages|list of new pages]])",
+       "rcnotefrom": "ߘߎ߰ߟߊ ߘߐ߫ {{PLURAL:$5|is the change|are the changes}} ߞߊ߬ߦߌ߯ <strong>$3, $4</strong> (up to <strong>$1</strong> shown).",
+       "rclistfrom": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߞߎߘߊ ߟߎ߫ ߦߌ߬ߘߊ ߘߊߡߌ߬ߣߊ߬ ߣߌ߲߭ ߡߊ߬ $2, $3",
+       "rcshowhideminor": "$1 ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߘߋ߬ߣߍ߲",
+       "rcshowhideminor-show": "ߊ߬ ߦߌ߬ߘߊ߬",
+       "rcshowhideminor-hide": "ߊ߬ ߢߡߊߘߏ߲߰",
+       "rcshowhidebots": "$1 ߡߐ߰ߡߐ߮",
+       "rcshowhidebots-show": "ߊ߬ ߦߌ߬ߘߊ߬",
+       "rcshowhidebots-hide": "ߊ߬ ߢߡߊߘߏ߲߰",
+       "rcshowhideliu": "$1 ߟߊߓߊ߯ߙߊߓߊ߯ ߛߙߍߘߍߦߊߣߍ߲ ߠߎ߬",
+       "rcshowhideliu-show": "ߊ߬ ߦߌ߬ߘߊ߬",
+       "rcshowhideliu-hide": "ߊ߬ ߢߡߊߘߏ߲߰",
+       "rcshowhideanons": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߊ߫ ߕߐ߯ߒߕߊ߲ $1",
+       "rcshowhideanons-show": "ߦߌ߬ߘߊ߬ߟߌ",
+       "rcshowhideanons-hide": "ߊ߬ ߘߏ߲߰",
+       "rcshowhidepatr": "$1 ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ߣߍ߲߫ ߞߣߐ߬ߜߍ߲߬ߣߍ߲ ߠߎ߬",
+       "rcshowhidemine": "ߒ ߠߊ߫ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߣߍ߲ ߠߎ߬ $1",
+       "rcshowhidemine-show": "ߊ߬ ߦߌ߬ߘߊ߬",
+       "rcshowhidemine-hide": "ߊ߬ ߦߡߊߘߏ߲߰",
+       "rclinks": "ߕߋ߬ߟߋ $2 ߕߊ߬ߡߌ߲߬ߣߍ߲ ߣߌ߲߬ ߡߝߊ߬ߟߋ߲߬ߠߌ߲߬ ߟߊ߬ߓߊ߲ $1 ߦߌ߬ߘߊ߬",
+       "diff": "ߘߊ߲߬ߝߘߊ߬ߓߐ",
+       "hist": "ߕߊ߬ߡߌ߲߬ߣߍ߲",
+       "hide": "ߊ߬ ߢߡߊߘߏ߲߰",
+       "show": "ߊ߬ ߦߌ߬ߘߊ߬",
+       "minoreditletter": "ߡ",
+       "newpageletter": "ߞ",
+       "boteditletter": "ߓ",
+       "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}}  ߡߊ߬ߝߊ߬ߟߋ߲߬ߠߌ߲ ߞߐ߫",
+       "rc-old-title": "ߊ߬ ߓߊߞߘߐ ߟߊߘߊ߲߫ ߣߍ߲߫ ߦߋ߫ ߕߊ߲߬ ߠߋ߫ \"$1\"",
+       "recentchangeslinked": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߜߋ߲߬ߞߘߎ߬ߢߐ߲߰ߡߊ ߟߎ߬",
+       "recentchangeslinked-toolbox": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߫ ߓߌ߬ߟߊ߬ߢߐ߲߰ߡߊ",
+       "recentchangeslinked-title": "ߊ߬ ߟߌ߬ߤߟߊ ߡߊߦߟߍ߬ߡߊ߲߫ ߦߊ߲߬ \"$1\"",
+       "recentchangeslinked-summary": "ߞߐߜߍ ߕߐ߮ ߟߊߘߏ߲߬߸ ߞߊ߬ ߞߐߜߍ ߛߘߌ߬ߜߋ߲ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߦߋ߫߸ ߥߟߊ߫ \nߞߊ߬ ߝߘߊ߫ ߞߐߜߍ ߣߌ߲߬ ߠߊ߫. (ߖߐ߲߬ߛߊ߬ ߌ ߘߌ߫ ߦߌߟߡߊ ߛߌ߲߬ߝߏ߲ ߠߎ߬ ߦߋ߫߸ ߣߌ߲߬ ߠߊߘߏ߲߬ {{ns:category}}: ߦߌߟߡߊ ߕߐ߮). ߦߟߍ߬ߡߊ߲߬ ߡߍ߲ ߦߋ߫ ߞߐߜߍ ߣߌ߲߬ [[Special:Watchlist|your Watchlist]] ߘߐ߫߸ ߏ߬ ߦߋ߫ <strong>ߛߓߍߘߋ߲߫ ߞߎ߲ߓߊ</strong> ߟߋ߬ ߘߐ߫.",
+       "recentchangeslinked-page": "ߘߐߜߍ ߕߐ߮:",
+       "recentchangeslinked-to": "ߞߐߜߍ ߛߘߌ߬ߜߋ߲ ߠߎ߬ ߦߌ߬ߘߊ߬߸ ߞߊ߬ ߞߐߜߍ ߣߌ߬ ߞߋߟߋ߲ߘߌ߫",
+       "upload": "ߞߐߕߐ߮ ߟߊߦߟߍ߬",
+       "uploadlogpage": "ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ߘߏ߫ ߟߊߦߟߍ߬",
+       "filedesc": "ߟߊߘߛߏߣߍ߲",
+       "license": "ߟߊ߬ߘߌ߬ߢߍ߬ߟߌ ߦߴߌ ߘߐ߫:",
+       "license-header": "ߟߊ߬ߘߌ߬ߢߍ߬ߟߌ ߦߴߌ ߘߐ߫",
+       "imgfile": "ߞߐߕߐ߮",
+       "listfiles": "ߞߐߕߐ߮ ߛߙߍߘߍ",
+       "file-anchor-link": "ߞߐߕߐ߮",
+       "filehist": "ߞߐߕߐ߮ ߟߊ߫ ߘߐ߬ߝߐ",
+       "filehist-help": "ߕߎ߬ߡߊ߬ߘߊ/ߕߎ߬ߡߊ ߛߐ߲߬ߞߌ߲߬ ߓߊ߫߸ ߞߊ߬ ߕߎ߬ߡߊ߬ߘߊ ߞߐߕߐ߮ ߟߎ߬ ߦߋ߫.",
+       "filehist-revert": "ߊ߬ ߟߊߢߊ߬",
+       "filehist-current": "ߞߍߛߊ߲ߞߏ",
+       "filehist-datetime": "ߕߎ߬ߡߊ߬ߘߊ/ߕߎ߬ߡߊ߬ߟߊ߲",
+       "filehist-thumb": "ߞߝߊ߬ߟߋ߲ߛߋ߲",
+       "filehist-thumbtext": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߠߊߘߐ߯ߦߊߣߍ߲ ߡߍ߲ ߦߋ߫ $1",
+       "filehist-nothumb": "ߖߌ߬ߦߊ߬ ߘߐ߯ߡߊ߲߫ ߕߴߦߋ߲߬",
+       "filehist-user": "ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ",
+       "filehist-dimensions": "ߛߎߡߊ߲ߘߐ",
+       "filehist-comment": "ߞߊ߲߬ߝߐߟߌ",
+       "imagelinks": "ߞߐߕߐ߮ ߟߊߓߊ߯ߙߊ",
+       "linkstoimage": "ߞߐߕߐ߮ ߣߌ߲߬ {{PLURAL:$1|ߞߐߜߍ ߟߎ߬|$1 ߞߐߜߍ ߟߎ߬}}:",
+       "linkstoimage-more": "ߞߐߕߐ߮ ߣߌ߲߬ $1 {{PLURAL:$1|page uses|pages use}} ߠߊߓߊ߯ߙߊߓߊ߮ ߞߊߛߌߦߊ߫.\nߛߙߍߘߍ ߢߌ߲߬ ߠߎ߬ ߦߋ߫ {{PLURAL:$1|first page|first $1 pages}} ߞߐߕߐ߮ ߣߌ߲߬ ߞߋߟߋ߲߫ ߠߊߓߊ߯ߙߊߓߊ߮ ߟߎ߬ ߛߙߍߘߍ ߟߋ߬ ߦߌ߬ߘߊ߬ ߟߊ߫.\nߛߘߌ߬ߜߋ߲߬ [[Special:WhatLinksHere/$2|full list]] ߓߟߏߡߊߞߊ߬ߣߍ߲ ߦߋ߫ ߦߋ߲߬.",
+       "nolinkstoimage": " ߞߐߜߍ߫ ߛߌ߫ ߡߊ߫ ߞߐߕߐ߮ ߣߌ߲߬ ߠߊߓߊ߯ߙߊ߫ ߡߎߣߎ߲߬",
+       "linkstoimage-redirect": "$1 (ߞߐߕߐ߯ ߟߊߞߎ߲߬ߛߌ߲߬ߣߍ߲߬) $2",
+       "sharedupload-desc-here": "ߘߐ߬ߛߙߋ ߣߌ߲߬ ߦߋ߫ ߦߊ߲߬ ߠߋ߫ $1 ߖߊ߬ߕߋ߬ߘߐ߬ߛߌ߮ ߕߐ߭ ߟߎ߬ ߞߏ߬ߣߌ߲ ߘߌ߫ ߛߴߊ߬ ߟߊߓߊ߯ߙߊ߫ ߟߊ߫. ߊ߬ ߕߐ߯ ߛߓߍߟߌ ߦߙߐ [$2 ߞߐߕߐ߮ ߞߊ߲߬ߛߓߍߟߌ ߞߐߜߍ] ߟߋ߬ ߦߋ߫ ߘߎ߰ߟߊ ߘߐ߫ ߣߌ߲߬.",
+       "filepage-nofile": "ߕߐ߮ ߣߌ߲߬ ߞߐߕߐ߯ ߛߎ߯ ߕߍ߫ ߦߋ߲߬",
+       "upload-disallowed-here": "ߌ ߕߍߣߊ߬ ߞߐߜߍ ߣߌ߲߬ ߞߊ߲߬ߛߓߍ߫ ߟߊ߫.",
+       "randompage": "ߓߍ߲߬ߛߋ߲߬ߡߊ߬ ߞߐߜߍ",
+       "statistics": "ߖߊ߬ߕߋ߬ߛߎ߬ߓߐ ߟߎ߬",
+       "double-redirect-fixer": "ߟߊ߬ߞߎ߲߬ߛߌ߲߬ߠߌ߲ ߘߐߓߍ߲߬ߟߊ߲",
+       "nbytes": "$1 {{PLURAL:$1|byte|bytes}}",
+       "nmembers": "$1 {{PLURAL:$1|ߛߌ߲߬ߝߏ߲ |ߛߌ߲߬ߝߏ߲ ߠߎ߬}}",
+       "prefixindex": "ߞߐߜߍ ߡߍ߲ ߠߎ߬ ߓߍ߯ ߟߊߝߟߐߣߍ߲߫",
+       "listusers": "ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ ߛߙߍߘߍ",
+       "newpages": "ߘߐߜߍ߫ ߞߎߘߊ",
+       "move": "ߊ߬ ߛߋ߲߬ߓߐ߫",
+       "pager-newer-n": "{{PLURAL:$1|ߞߎߘߡߊ1|ߞߎߘߡߊ$1}}",
+       "pager-older-n": "{{PLURAL:$1|ߞߘߐ߬ߡߊ߲ ߁|ߞߘߐ߬ߡߊ߲ ߠߎ߬ $1}}",
+       "booksources": "ߞߊ߬ߝߊ ߛߎ߲",
+       "booksources-search-legend": "ߞߊ߬ߝߊ ߛߎ߲ ߕߌߙߌ߲߫",
+       "booksources-search": "ߢߌߣߌ߲ߠߌ߲",
+       "specialloguserlabel": "ߞߍߓߊ߮ :",
+       "speciallogtitlelabel": "ߞߏ߲߭ (ߞߎ߲߬ߕߐ߮ ߥߟߊ߫  {{ns:user}}: ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ ߟߊ߫ ߟߊ߬ߓߊ߰ߙߊ߬ ߕߐ߮):",
+       "log": "ߘߏ߲߬",
+       "all-logs-page": "ߝߘߏ߬ߓߊ߬ ߜߊ߲ߞߎ߲ߠߌ߲ ߠߎ߬ ߓߍ߯",
+       "logempty": "ߦߙߍߞߍߟߌ߫ ߛߌ߫ ߓߍ߲߬ߢߐ߲߰ߦߊ߬ߣߍ߲߬ ߕߍ߫ ߝߐ߰ߓߍ ߟߎ߬ ߘߐ߫.",
+       "allpages": "ߞߐߜߍ ߟߎ߬ ߓߍ߯",
+       "allarticles": "ߞߐߜߍ ߟߎ߬ ߓߍ߯",
+       "allpagessubmit": "ߥߊ߫",
+       "allpages-hide-redirects": "ߟߊ߬ߞߎ߲߬ߛߌ߲߬ߠߌ߲ ߢߡߊߘߏ߲߰",
+       "categories": "ߦߌߟߡߊ ߟߎ߬",
+       "listgrouprights-members": "(ߛߌ߲߬ߝߏ߲ ߠߎ߫ ߛߙߍߘߍ)",
+       "emailuser": "ߗߋߛߓߍ ߗߋ߫ ߣߌ߲߬ ߕߌ߭ ߡߊ߬",
+       "usermessage-editor": "ߞߊ߲ߞߋ߫ ߗߋߛߓߍ ߡߊߦߟߍ߬ߡߊ߲߬ߓߊ߮",
+       "watchlist": "ߣߐ߬ߝߍ߬ߜߍ߲߬ߛߙߍߘߍ",
+       "mywatchlist": "ߘߐߜߍ߫ ߘ߲ߜߍߕߊ",
+       "watchlistfor2": "ߞߏߛߐ߲߬ $1 $2",
+       "watch": "ߊ߬ ߘߐߜߍ߫",
+       "unwatch": "ߊ߬ ߞߍ߫ ߦߋߓߊߟߌ ߘߌ߫",
+       "watchlist-details": "ߌ ߟߊ߫ ߞߣߐ߬ߜߍ߲߬ ߛߙߍߘߍ ߟߎ߬ ߘߐ߫ {{PLURAL:$1|ߞߐߜߍ $1|ߞߐߜߍ ߟߎ߬ $1}}( ߊ߬ ߣߌ߫ ߢߊߝߐߟߌ߫ ߞߐߜߍ ߟߎ߬) ߓߍ߯ ߟߴߊ߬ ߞߣߐ߫.",
+       "wlheader-showupdated": "ߞߐߜߍ ߡߍ߲ ߠߎ߬ ߡߊߦߟߍ߬ߡߊ߲߬ߣߍ߲߬ ߌ ߟߊ߫ ߡߊ߬ߝߍ߬ߣߍ߲߬ߠߌ߲ ߞߐ߫߸ ߏ߬ ߟߎ߫ ߟߋ߬ ߦߌ߬ߘߊ߬ߣߍ߲߫ <strong>ߛߓߍߘߋ߲߫ ߞߎ߲ߓߊ</strong> ߘߐ߫.",
+       "wlnote": "ߘߎ߰ߟߊ ߘߐ߫ {{PLURAL:$1|is the last change|are the last <strong>$1</strong> changes}} ߞߐ߯ߟߕߊ ߘߐ߫ {{PLURAL:$2|hour|<strong>$2</strong> hours}}, as of $3, $4.",
+       "wlshowlast": "ߕߎ߬ߡߊ߬ߙߋ߲ $1 ߞߐߟߕߊ $2 ߕߋ߬ߟߋ ߟߎ߬ ߦߌ߬ߘߊ߬",
+       "watchlist-options": "ߞߣߐ߬ߜߍ߲߬ ߛߙߍߘߍ ߢߣߊߕߐߡߐ߲ ߠߎ߬",
+       "enotif_reset": "ߞߐߜߍ߫ ߞߎ߲ߝߊ߲ߓߐߣߍ߲ ߠߎ߬ ߓߍ߯ ߕߐ߰ߡߊ߬ߛߙߋ߫",
+       "dellogpage": "ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ߖߏ߬ߛߌ߬ߣߍ߲",
+       "rollbacklink": "ߌ ߞߐߛߊ߬ߦߌ߲߬ ߌ ߣߐ߭ߡߊ߬",
+       "rollbacklinkcount": "ߛߋ߬ߦߌ߲߬ ߌ ߣߐ߭ߡߊ߬ $1 {{PLURAL:$1|ߡߊߦߟߍ߬ߡߊ߲߫|ߟߎ߬ ߡߊߦߟߍ߬ߡߊ߲߫}}",
+       "protectlogpage": "ߜߊ߲߬ߞߎ߲߬ߠߌ߲߬ ߠߊߞߊ߲ߘߊߣߍ߲",
+       "protectedarticle": "ߟߊ߬ߞߊ߲߬ߘߊ߬ߣߍ߲ \"[[$1]]\"",
+       "modifiedarticleprotection": "ߟߊ߬ߞߊ߲߬ߘߊ߬ߟߌ ߞߊߓߋ ߡߊߦߟߍ߬ߡߊ߲߬ \"[[$1]]\"",
+       "protect-default": "ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ ߟߎ߬ ߓߍ߯ ߟߊߘߌ߬ߢߍ߬",
+       "restriction-edit": "ߊ߬ ߡߊߦߟߍ߬ߡߊ߲߬",
+       "restriction-move": "ߕߐ߯ߦߊ߫",
+       "namespace": "ߕߐ߯ ߛߓߍ ߞߣߍ:",
+       "invert": "ߓߊߕߐ߬ߡߐ߲߬ߣߍ߲ ߞߕߐߡߊߛߊ߬ߦߌ߲߬",
+       "tooltip-invert": "ߞߏ߲߬ߘߏ ߣߌ߲߬ ߘߐߜߍ߫߸ ߞߊ߬ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߠߎ߬ ߢߡߊߘߏ߲߰ ߞߐߜߍ ߟߎ߬ ߕߐ߯ ߞߣߍ߫ ߓߊߓߌ߬ߟߊ߬ߣߍ߲ ߘߐ߫ (ߊ߬ ߣߌ߫ ߕߐ߯ ߞߣߍ߫ ߓߟߏߘߏ߲߬ߣߍ߲ ߘߐߜߍߣߍ߲ ߠߎ߬)",
+       "namespace_association": "ߕߐ߯ ߓߟߏߘߏ߲߬ߣߍ߲߫ ߢߐ߲߰ߓߟߏ",
+       "tooltip-namespace_association": "ߞߏ߲߬ߘߏ ߣߌ߲߬ ߡߊߝߍߣߍ߲߫ ߓߊ߫ ߞߊ߬ ߓߊ߬ߘߏ߬ߓߊ߬ߘߌߦߊ ߥߟߊ߫ ߝߐߡߊ ߕߐ߮ ߞߣߍ ߡߍ߲ ߓߟߏߘߏ߲߬ߣߍ߲߫ ߦߋ߫ ߞߐߜߍ߫ ߓߊߕߐ߬ߡߐ߲߬ߣߍ߲ ߣߌ߲߬ ߘߐ߫߸ ߞߵߏ߬ ߟߊߘߏ߲߬.",
+       "blanknamespace": "(ߓߊߖߎ)",
+       "contributions": "ߓߟߏߡߊߜߍ߲ ߠߎ߬ {{GENDER:$1|ߟߊߓߊ߯ߙߟߊ}}",
+       "contributions-title": "ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ ߟߊ߫ ߓߟߏߓߌߟߊߢߐ߲߯ߞߊ߲ ߡߍ߲ ߦߋ߫$1",
+       "mycontris": "ߓߟߏߓߌߟߊߢߐ߲߯ߞߊ߲",
+       "anoncontribs": "ߓߟߏߓߌߟߊߢߐ߲߯ߞߊ߲ ߠߎ߬",
+       "contribsub2": "{{GENDER:$3|$1}} ߕߊ ($2)",
+       "nocontribs": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߬ ߛߌ߫ ߓߍ߲߬ߢߐ߲߰ߦߊ߬ߣߍ߲߬ ߕߍ߫ ߕߐ߰ߡߊ߬ߛߙߋ ߢߌ߲߬ ߠߎ߫ ߡߊ߬ ߣߺߴߊ߬ ߦߋߣߍ߲߫.",
+       "uctop": "ߞߍߛߊ߲ߞߏ",
+       "month": "ߞߵߊ߬ ߕߊ߬ ߞߊߙߏ ߡߊ߬ (ߊ߬ ߣߌ߫ ߞߊߙߏ ߞߎ߲߬ߝߟߐ ߘߐ߫):",
+       "year": "ߞߵߊ߬ ߕߊ߬ ߞߊߙߏ ߡߊ߬ (ߊ߬ ߣߌ߫ ߞߊߙߏ ߞߎ߲߬ߝߟߐ ߡߊ߬):",
+       "sp-contributions-newbies": "ߖߊ߬ߕߋ߬ߘߊ߬ ߞߎߘߊ ߟߎ߫ ߘߐߙߐ߲߫ ߠߊ߫ ߓߟߏߓߌߟߊߢߐ߲߯ߞߊ߲ ߦߌ߬ߘߊ߫ ߕߋ߲߬",
+       "sp-contributions-blocklog": "ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ߓߊ߬ߟߊ߲߬",
+       "sp-contributions-uploads": "ߟߊ߬ߦߟߍ߬ߟߌ ߟߎ߬",
+       "sp-contributions-logs": "ߘߏ߲߬ߠߌ߲ ߠߎ߬",
+       "sp-contributions-talk": "ߞߎߡߊߢߐ߲߯ߦߊ",
+       "sp-contributions-search": "ߓߟߏߓߌߟߊߢߐ߲߯ߞߊ߲ ߘߏ߫ ߢߌߣߌ߲߫",
+       "sp-contributions-username": "IP ߛߊ߲߬ߓߊ߬ߕߐ߮ ߥߟߊ߫ ߟߊ߬ߓߊ߰ߙߊ߬ߕߐ߮:",
+       "sp-contributions-toponly": "ߡߛߊ߬ߦߌ߲߬ߠߌ߲߬ ߠߊ߬ߓߊ߲ ߠߎ߬ ߘߐߙߐ߲߫ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߦߌ߬ߘߊ߬",
+       "sp-contributions-newonly": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߡߍ߲ ߣߊ߬ ߞߐߜߍ߫ ߟߊߘߊ߲ ߘߌ߫߸ ߏ߬ ߟߎ߫ ߘߐߙߐ߲߫ ߦߌ߬ߘߊ߬",
+       "sp-contributions-submit": "ߢߌߣߌ߲ߠߌ߲",
+       "whatlinkshere": "ߛߘߌ߬ߜߋ߲ ߢߎ߬ߡߊ߲߬ ߦߋ߫ ߦߊ߲߬",
+       "whatlinkshere-title": "ߞߐߜߍ ߡߍ߲ ߠߎ߫ ߛߘߌ߬ߣߍ߲߫ ߝߊ߲߭ ߣߌ߲߬ $1 ߡߊ߬",
+       "whatlinkshere-page": "ߘߐߜߍ:",
+       "linkshere": "ߞߐߜߍ ߟߎ߬ ߛߘߌ߬ߜߋ߲ ߡߍ߲ ߠߎ߬ ߦߋ߫ ߦߊ߲߬ <strong>$2</strong>:",
+       "nolinkshere": "ߞߐߜߍ߫ ߛߌ߫ ߟߎ߫ ߛߘߌ߬ߜߋ߲߬ ߕߍ߫ ߦߋ߲߬ <strong>$2</strong>.",
+       "isredirect": "ߞߎ߲߬ߕߋ߬ߟߋ߲߬ ߞߎߘߊ ߞߐߜߍ",
+       "istemplate": "ߘߐ߬ߘߏ߲߬ߠߌ߲",
+       "isimage": "ߞߐߕߐ߮ ߛߘߌ߬ߜߋ߲",
+       "whatlinkshere-prev": "{{PLURAL:$1|ߢߝߍߕߊ ߟߎ߬|ߢߝߍߕߊ ߟߎ߬ $1}}",
+       "whatlinkshere-next": "{{PLURAL:$1|ߢߍߕߊ|ߢߍߕߊ $1}}",
+       "whatlinkshere-links": "→ ߛߘߌ߬ߜߋ߲",
+       "whatlinkshere-hideredirs": "ߟߊ߬ߞߎ߲߬ߛߌ߲߬ߠߌ߲ ߠߎ߬ $1",
+       "whatlinkshere-hidetrans": "ߟߊ߬ߘߏ߲߬ߘߐ߬ߟߌ ߓߊ߲ߓߊ߲ߣߍ߲ $1",
+       "whatlinkshere-hidelinks": "ߛߘߌ߬ߜߋ߲$1",
+       "whatlinkshere-hideimages": "ߞߐߕߐ߮ ߛߘߌ߬ߜߋ߲$1",
+       "whatlinkshere-filters": "ߢߡߊߘߏ߲߰ߣߍ߲",
+       "ipboptions": "ߕߎ߬ߡߊ߬ߙߋ߲ ߂:2 hours, ߕߟߋ߬ ߁:1 day, ߕߋ߬ߟߋ ߃:3 days,ߞߎ߲߬ߢߐ߰ ߁:1 week, ߞߎ߲߬ߢߐ߮ ߂:2 weeks, ߞߊߙߏ߫ ߁:1 month, ߞߊߙߏ߫ ߃:3 months, ߞߊߙߏ߫ ߆:6 months,ߛߊ߲߬ ߁:1 year,ߤߊ߲߯ ߤߌ߲߯:infinite",
+       "infiniteblock": "ߘߊ߲߬ߓߊߟߌ",
+       "blocklink": "ߟߊ߬ߢߊ߬ߙߊ߲߬ߠߌ",
+       "contribslink": "ߡߊߛߐ߯ߟߌ",
+       "blocklogpage": "ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ߓߊ߬ߟߊ߲߬ߠߌ",
+       "blocklogentry": "ߊ߬ ߓߊ߬ߟߊ߲߬ߣߍ߲߬ ߦߋ߫ [[$1]] ߊ߬ ߕߎ߬ߡߊ ߕߊ߬ߡߌ߲ ߠߋ߬ ߞߏߛߐ߲߬ $2 $3",
+       "reblock-logentry": "ߣߌ߲߬ ߓߊ߬ߟߊ߲߬ߠߌ߲ ߟߊ߬ߓߍ߲߬ߢߐ߲߰ߡߊ ߡߊߦߟߍ߬ߡߊ߲߬  [[$1]] ߊ߬ ߕߎ߬ߡߊ ߛߕߊ ߝߊ ߕߎߡߊ ߟߊ߫ $2 $3",
+       "block-log-flags-nocreate": "ߖߊ߬ߕߋ߬ߘߊ ߛߌ߲ߘߟߌ ߟߊߕߐ߲",
+       "proxyblocker": "ߟߐ߲߬ߞߋ߬ߟߊ ߓߊ߬ߟߊ߲߬ߟߊ߲",
+       "movelogpage": "ߜߊ߲߬ߞߎ߲ ߓߐ߫ ߊ߬ ߡߊ߬",
+       "export": "ߞߐߜߍ ߟߎ߬ ߟߊߝߏ߬ߦߌ߬",
+       "thumbnail-more": "ߊ߬ ߟߊߞߎ߲߬ߓߦߊ߬",
+       "importlogpage": "ߟߊ߬ߛߣߍ߬ߟߌ ߞߣߍ",
+       "tooltip-pt-userpage": "{{GENDER:|ߌ ߟߊ߫ ߟߊ߬ߓߊ߰ߙߊ߬ߟߌ߬}} ߞߐߜߍ",
+       "tooltip-pt-mytalk": "{{GENDER:|ߌ ߟߊ߫}} ߞߎߡߊ߫ ߞߐߜߍ߫",
+       "tooltip-pt-preferences": "{{GENDER:|ߌ ߟߊ߫}} ߤߣߍߕߊ ߟߎ߬",
+       "tooltip-pt-watchlist": "ߌ ߟߊ߫ ߞߐߜߍ߫ ߡߊߦߟߍ߬ߡߊ߲߬ߕߊ ߜߋ߬ߟߎ߲߬ߣߍ߲ ߠߎ߬ ߛߙߍߘߍ",
+       "tooltip-pt-mycontris": "{{GENDER:|ߌ ߟߊ߫}} ߓߟߏߡߊߜߍ߲߫ ߛߙߍߘߍ ߟߎ߬",
+       "tooltip-pt-login": "ߌ ߡߊߘߌߦߊߣߍ߲߫ ߦߴߌ ߜߊ߲߬ߞߎ߲߫ ߸ ߘߌߦߊߜߏߦߊ߫ ߞߏ߬ߣߌ߲߬ ߕߍ߫",
+       "tooltip-pt-logout": "ߌ ߜߊ߲߬ߞߎ߲߬ ߓߐ߫",
+       "tooltip-pt-createaccount": "ߌ ߡߊߘߌߦߊߣߍ߲߫ ߦߋ߫ ߖߊ߬ߕߋ߬ߘߊ߫ ߟߊߞߊ߬ ߞߵߌ ߜߊ߲߬ߞߎ߲߫ ߸ ߓߊ߬ߙߌ߬ ߌ ߘߌߦߊߜߏߦߊߣߍ߲߫ ߕߍ߫",
+       "tooltip-ca-talk": "ߘߐ߬ߞߕߌ߬ߟߌ ߞߊ߬ ߓߍ߲߬ ߞߐߜߍ ߞߣߐߘߐ ߡߊ߬",
+       "tooltip-ca-edit": "ߞߐߜߍ ߣߌ߲߬ ߡߊߦߟߍ߬ߡߊ߲߬",
+       "tooltip-ca-addsection": "ߛߌ߰ߘߊ߬ ߞߎߘߊ߫ ߘߊߡߌ߬ߣߊ߬",
+       "tooltip-ca-viewsource": "ߞߐߜߍ ߣߌ߲߬ ߠߊߞߊ߲ߘߊߣߍ߲߫ ߠߋ߬.\nߌ ߘߌ߫ ߛߴߊ߬ ߛߎ߲ ߘߐߜߍ߫ ߟߊ߫",
+       "tooltip-ca-history": "ߞߐߜߍ ߣߌ߲߬ ߛߊߞߍߟߌ߫ ߕߊ߬ߡߌ߲߬ߣߍ߲ ߠߎ߫ ߘߐߜߍ߫",
+       "tooltip-ca-protect": "ߞߐߜߍ ߣߌ߲߬ ߠߊߞߊ߲ߘߊ߫",
+       "tooltip-ca-delete": "ߞߐߜߍ ߣߌ߲߬ ߖߏ߰ߛߌ߫",
+       "tooltip-ca-move": "ߘߐߜߍ ߣߌ߲߬ ߛߋ߲߬ߓߐ߫",
+       "tooltip-ca-watch": "ߞߐߜߍ ߣߌ߲߬ ߝߙߊ߬ ߌ ߟߊ߫ ߟߊߞߙߐ߬ߛߌ߬ߕߊ߬ ߛߙߍߘߍ ߟߎ߫ ߞߊ߲߬",
+       "tooltip-ca-unwatch": "ߞߐߜߍ ߣߌ߲߬ ߛߋ߲߬ߓߐ߫ ߌ ߟߊ߫ ߟߊߞߙߐ߬ߛߌ߬ߕߊ߬ ߛߙߍߘߍ ߘߐ߫",
+       "tooltip-search": "ߊ߬ ߢߌߣߌ߲߫ {{SITENAME}} ߘߐ߫",
+       "tooltip-search-go": "ߕߐ߮ ߣߌ߲߬ ߢߌߣߌ߲߫ ߞߐߜߍ߫ ߞߣߐ߫ ߣߴߊ߬ ߞߍ߫ ߘߊ߫ ߦߋ߲߬",
+       "tooltip-search-fulltext": "ߞߎߡߊߘߋ߲߫ ߣߌ߲߬ ߞߐߜߍ߫ ߟߎ߫ ߢߌߣߌ߲߫",
+       "tooltip-p-logo": "ߞߐߜߍ߫ ߓߏߟߏ߲ߘߊ ߡߊߝߍߣߍ߲߫",
+       "tooltip-n-mainpage": "ߞߐߜߍ߫ ߓߏߟߏ߲ߘߊ ߡߊߝߍߣߍ߲߫",
+       "tooltip-n-mainpage-description": "ߞߐߜߍ߫ ߓߏߟߏ߲ߘߊ ߡߊߝߍߣߍ߲߫",
+       "tooltip-n-portal": "ߞߊ߬ ߓߍ߲߬ ߣߕߊ߬ߘߐ߬ߛߌ ߡߊ߬ ߸ ߌ ߘߴߛߋ߫ ߡߎ߲߬ ߞߍ߫ ߟߊ߫ ߸ ߝߋ߲ ߠߎ߫ ߦߋ߫ ߛߐ߬ߘߐ߲߬ ߠߊ߫ ߡߌ߲߫",
+       "tooltip-n-currentevents": "ߌ ߟߊ߫ ߞߎ߲߬ߠߊ߬ߝߎߟߋ߲ ߡߊߞߊ߬ߝߏ߬ ߞߊ߬ ߓߍ߲߬ ߞߍߕߊ ߡߍ߲ ߠߎ߫ ߦߋ߫ ߛߋ߲߬ߠߊ߫",
+       "tooltip-n-recentchanges": "ߘߐ߬ߝߊ߬ߟߋ߲߬ߠߌ߬ ߞߎߘߊ ߟߎ߬ ߛߙߍߘߍ ߥߞߌ߫ ߞߣߐ߫",
+       "tooltip-n-randompage": "ߓߍ߲߬ߛߋ߲߬ߡߊ߬ ߞߐߜߍ ߘߏ߫ ߦߌ߬ߘߊ߬",
+       "tooltip-n-help": "ߊ߬ ߢߌߣߌ߲߫ ߦߙߐ",
+       "tooltip-t-whatlinkshere": "ߥߞߌ߫ ߞߐߜߍ ߓߍ߯ ߛߘߌ߬ߜߋ߲ ߠߋ߬ ߦߋ߫ ߦߊ߲߬",
+       "tooltip-t-recentchangeslinked": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߬ ߞߎߘߊ ߟߎ߬ ߞߐߜߍ߫ ߘߐ߫ ߡߍ߲ ߣߌ߫ ߞߐߜߍ ߣߌ߲߬ ߕߎ߲߰ߣߍ߲߫",
+       "tooltip-feed-atom": "ߞߐߜߍ ߣߌ߲߬ ߝߕߌ߫ ߓߊߟߏ",
+       "tooltip-t-contributions": "{{GENDER:$1|ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ}} ߟߊ߫ ߓߟߏߓߌߟߊߢߐ߲߮ߞߊ߲ ߛߙߍߘߍ",
+       "tooltip-t-emailuser": "ߢߎߡߍߙߋ߲ߞߏ߲ߘߏ ߟߊߕߊ߯ ߟߊߓߊ߯ߙߟߊ ߣߌ߲߬ ߡߊ߬{{GENDER:$1|ߟߊߓߊ߯ߙߟߊ}}",
+       "tooltip-t-upload": "ߞߐߕߐ߮ ߟߎ߫ ߟߊߦߟߍ߬",
+       "tooltip-t-specialpages": "ߘߎ߲߬ߘߎ߬ߡߊ߬ ߞߐߜߍ߫ ߟߎ߫ ߛߙߍߘߍ",
+       "tooltip-t-print": " ߞߐߜߍ ߣߌ߲߬  ߜߌ߬ߙߌ߲߬ߘߌ߬ߕߊ߬ߡߊ ߛߎ߮",
+       "tooltip-t-permalink": "ߞߐߜߍ ߣߌ߲߬ ߡߛߊ߬ߦߌ߲߬ߠߌ߲߬ ߛߘߌ߬ߜߋ߲߬ ߓߟߏߕߍ߰ߓߊߟߌ",
+       "tooltip-ca-nstab-main": "ߞߐߜߍ ߞߣߐߘߐ ߘߐߜߍ߫",
+       "tooltip-ca-nstab-user": "ߞߐߜߍ߫ ߟߊߓߊ߯ߙߕߊ ߘߐߜߍ߫",
+       "tooltip-ca-nstab-special": "ߣߌ߲߬ ߦߋ߫ ߘߐߜߍ߫ ߓߟߏߡߊߞߊ߬ߣߍ߲ ߠߋ߬ ߘߌ߫߸ ߊ߬ ߕߍ߫ ߛߋ߫ ߡߊߦߟߍ߬ߡߊ߲߬ ߠߊ߫",
+       "tooltip-ca-nstab-project": "ߖߊ߬ߕߋ߬ߘߐ߬ߛߌ߰ ߞߐߜߍ ߘߐߜߍ߫",
+       "tooltip-ca-nstab-image": "ߞߐߕߐ߮ ߞߐߜߍ ߟߎ߫ ߘߐߜߍ߫",
+       "tooltip-ca-nstab-mediawiki": "ߞߊ߲ߞߋ ߗߋߛߓߍ ߘߐߜߍ߫",
+       "tooltip-ca-nstab-template": "ߞߙߊߞߏ ߦߋ߫",
+       "tooltip-ca-nstab-category": "ߦߌߟߡߊ߫ ߞߐߜߍ ߟߎ߬ ߦߌ߬ߘߊ߬",
+       "tooltip-minoredit": "ߣߌ߲߬ ߞߍ߫ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߘߏ߫ ߘߌ߫",
+       "tooltip-save": "ߌ ߟߊ߫ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߣߍ߲ ߠߊߞߎ߲߬ߘߎ߬",
+       "tooltip-preview": "ߌ ߟߊ߫ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߣߍ߲ ߘߐߜߍ߫ ߡߎߣߎ߲߬. ߏ߬ ߞߴߊ߬ ߟߊߞߎ߲߬ߘߎ ߢߍ߫ ߖߊ߰ߣߌ߲߫.",
+       "tooltip-diff": "ߌ ߟߊ߫ ߛߓߍߟߌ߫ ߡߊߦߟߍ߬ߣߍ߲ ߦߌ߬ߘߊ߬",
+       "tooltip-compareselectedversions": "ߘߊ߲߬ߝߘߊ߬ߓߐ ߡߍ߲ ߦߋ߫ ߡߊ߬ߛߊ߬ߦߌ߲߬ߠߌ߲ ߓߊߕߐ߬ߡߐ߲߬ߣߍ߲ ߝߌ߬ߟߊ ߟߎ߬ ߕߍ߫ ߞߐߜߍ ߣߌ߲߬ ߘߐ߫߸ ߏ߬ ߦߋ߫",
+       "tooltip-watch": "ߞߐߜߍ ߣߌ߲߬ ߓߌ߬ߟߊ߬ ߌ ߟߊ߫ ߜߋ߬ߟߎ߬ߠߌ߲߬ ߛߙߍߘߍ ߘߐ߫",
+       "tooltip-rollback": "\"ߘߐߛߵߊ߬ ߡߊ߬\" ߓߟߏߓߌߟߊߢߐ߲߯ߞߊ߲ߠߊ ߟߊߓߊ߲ ߠߊ߫ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߡߊߛߊ߬ߦߌ߬ ߞߐߜߍ ߣߌ߲߬ ߘߐ߫ ߛߐ߲߬ߞߌ߲߬ߠߌ߲߬ ߞߋߟߋ߲߫ ߘߐ߫",
+       "tooltip-undo": "\"ߊ߬ ߘߐߛߊ߬\" ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߣߌ߲߬ ߞߐߛߊ߬ߦߌ߬ ߞߊ߬ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߝߊ߬ߘߌ ߟߊߞߊ߬ ߢߍߦߋߟߌ ߝߊ߬ߘߌ ߘߐ߫. ߊ߬ ߘߌ߫ ߖߡߊ߬ߙߌ߬ߦߊ ߘߌ߫ ߟߊ߬ߘߛߏ߬ߟߌ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߡߊ߬.",
+       "tooltip-summary": "ߟߊ߬ߘߛߏ߬ߣߍ߲߬ ߛߎ߬ߘߎ߲߬ߣߍ߲ ߘߏ߫ ߟߊߘߏ߲߬",
+       "simpleantispam-label": "ߛߑߔߊߡ ߛߌ߬ߣߊ ߡߊ߬ߝߍ߬ߣߍ߲߬ߠߌ߲.\nߊ߬ ߞߍ߫ <strong>not</strong> ߣߌ߲߬ ߠߝߊ߫߹",
+       "pageinfo-title": "ߞߟߊ߬ߟߐ߲ ߞߊ߲߬ \"$1\"",
+       "pageinfo-header-basic": "ߞߎ߲߬ߠߊ߬ߝߎ߬ߟߋ߲߬ ߓߊߖߎ ߟߎ߬",
+       "pageinfo-header-edits": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ ߘߐ߬ߝߐ",
+       "pageinfo-header-restrictions": "ߞߐߜߍ ߟߊ߬ߞߊ߲߬ߘߊ߬ߟߌ",
+       "pageinfo-header-properties": "ߞߐߜߍ ߘߎ߲߬ߘߎ߬ߡߊ ߟߎ߬",
+       "pageinfo-display-title": "ߞߎ߲߬ߕߐ߰ ߦߋߕߊ",
+       "pageinfo-default-sort": "ߊ߬ ߘߊ߲ߢߊ ߓߐ߫ ߛߓߍߘߋ߲",
+       "pageinfo-length": "ߞߐߜߍ ߥߊ߲߬ߥߊ߲ (bytes ߘߐ߫)",
+       "pageinfo-article-id": "ߞߐߜߍ ID",
+       "pageinfo-language": "ߞߐߜߍ ߣߌ߲߬ ߞߣߐߘߐ ߞߊ߲",
+       "pageinfo-content-model": "ߞߐߜߍ ߞߣߐߘߐ߫ ߞߙߊߞߏ",
+       "pageinfo-robot-policy": "ߡߐ߰ߡߐ߮ ߕߐ߰ߡߊ߬ߛߙߋ߬ߟߌ߬ ߣߐ ߟߋ߬",
+       "pageinfo-robot-index": "ߟߊߘߌ߬ߢߍ߬ߣߍ߲",
+       "pageinfo-robot-noindex": "ߟߊߘߌ߬ߢߍ߬ߓߊߟߌ",
+       "pageinfo-watchers": "ߞߐߜߍ߫ ߞߣߐ߬ߜߍ߲߬ߓߊ߮ ߟߎ߬ ߦߙߌߞߊ",
+       "pageinfo-few-watchers": "ߘߐ߯ߡߊ߲߫ $1{{PLURAL:$1|ߜߋ߬ߟߎ߲߬ߓߊ߮ |ߜߋ߬ߟߎ߲߬ߓߊ߮ ߟߎ߬}}",
+       "pageinfo-redirects-name": "ߓߌ߬ߟߊ߬ߣߍ߲ ߠߎ߬ ߦߙߌߞߊ ߞߐߜߍ ߣߌ߲߬ ߡߊ߬",
+       "pageinfo-subpages-name": "ߞߐߜߍߙߋ߲ ߦߙߌߞߊ ߡߍ߲ ߠߎ߬ ߦߋ߫ ߞߐߜߍ ߣߌ߲߬ ߘߐ߫",
+       "pageinfo-subpages-value": "$1 ($2{{PLURAL:$2|ߟߊ߬ߞߎ߲߬ߛߌ߲߬ߣߍ߲|ߟߊ߬ߞߎ߲߬ߛߌ߲߬ߣߍ߲ ߠߎ߬}}: $3 {{PLURAL:$3|ߟߊ߬ߞߎ߲߬ߛߌ߲߬ߓߊߟߌ}})",
+       "pageinfo-firstuser": "ߞߐߜߍ ߟߊߘߊ߲ߓߊ߮",
+       "pageinfo-firsttime": "ߞߐߜߍ ߟߊߘߊ߲߫ ߕߎߡߘߊ",
+       "pageinfo-lastuser": "ߡߊߦߟߍ߬ߡߊ߲߬ߓߊ߯ ߞߐߟߕߊ",
+       "pageinfo-lasttime": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߬ ߞߐߟߕߊ ߕߎ߬ߡߊ߬ߘߊ",
+       "pageinfo-edits": "ߡߊߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߠߎ߫ ߖߊ߬ߕߋ ߡߎ߰ߡߍ",
+       "pageinfo-authors": "ߛߓߍߦߟߊ߫ ߦߙߌߞߊ߫ ߖߊ߬ߕߋ߫ ߡߎ߰ߡߍ",
+       "pageinfo-recent-edits": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߟߊߓߊ߲ ߠߎ߬ ߖߊ߬ߕߋ (ߕߊ߬ߡߌ߲߬ߣߍ߲ ߞߘߐ߫ $1)",
+       "pageinfo-recent-authors": "ߞߐߛߊ߲߫ ߛߓߍߦߟߊ߫ ߓߐߣߍ߲ߢߐ߲߰ߡߊ ߟߎ߫ ߖߊ߬ߕߋ",
+       "pageinfo-magic-words": "ߛߎߓߊ߯ߦߊ߫ {{PLURAL:$1|ߞߎߡߊߘߋ߲|ߞߎߡߊߘߋ߲ ߠߎ߬ }}($1)",
+       "pageinfo-hidden-categories": "ߢߡߊߘߏ߲߰ߠߌ߲ {{PLURAL:$1|ߦߌߟߡߊ|ߦߌߟߡߊ ߟߎ߬(1$)}}",
+       "pageinfo-templates": "ߕߍߘߐߘߛߏߣߍ߲ {{PLURAL:$1|ߞߙߊ߬ߞߏ|ߞߙߊ߬ߞߏ ߟߎ߬}} $1",
+       "pageinfo-toolboxlink": "ߞߐߜߍ ߞߌ߬ߓߊ߬ߙߏ߬ߦߊ",
+       "pageinfo-contentpage": "ߊ߬ ߖߊ߬ߕߋ߬ ߞߣߐߘߐ߫ ߞߐߜߍ ߘߏ߫ ߘߌ߫",
+       "pageinfo-contentpage-yes": "ߐ߲߬ߤߐ߲߫",
+       "patrol-log-page": "ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ߓߍ߬ߙߍ߲߬ߓߍ߬ߙߍ߲߬",
+       "previousdiff": "→ ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߬ ߞߘߐ",
+       "nextdiff": "ߊ߬ ߡߊ߫ ߡߊߦߟߍ߬ߡߊ߲߬ ←",
+       "widthheightpage": "$1 × $2,$3 {{PLURAL:$3|page|pages}}",
+       "file-info-size": "$1 × $2 ߖߌ߬ߦߊ߬ߘߊ߲ߕߊ߸ ߞߐߕߐ߮ ߢߊ߲ߞߊ߲: $3߸ MIME ߛߎ߮ߦߊ:$4",
+       "file-info-size-pages": "$1 × $2 ߖߌ߬ߦߊ߬ߘߊ߲ߕߊ߸ ߞߐߕߐ߮ ߢߊ߲ߞߊ߲: $3߸ MIME ߛߎ߮ߦߊ: $4߸ $5 {{PLURAL:$5|ߞߐߜߍ|ߞߐߜߍ ߟߎ߬}}",
+       "file-nohires": "ߢߊߓߐߣߍ߲ ߛߊ߲ߘߐߕߊ߫ ߜߘߍ߫ ߕߍ߫ ߦߋ߲߬",
+       "svg-long-desc": "SVG ߞߐߕߐ߮, ߕߐ߯ߦߊߟߌ $1 × $2 ߖߌ߬ߦߊ߬ߘߊ߲ߕߊ, ߞߐߕߐ߮ ߢߊ߲ߞߊ߲: $3",
+       "show-big-image": "ߞߐߕߐ߮ ߓߊߛߎ߲",
+       "show-big-image-preview": "ߊ߬ ߢߍߦߋߟߌ ߢߊ߲ߞߊ߲: $1.",
+       "show-big-image-other": "{{PLURAL:$2|ߢߊߓߐߟߌ|ߢߊߓߐߟߌ ߟߎ߬}} ߕߐ߬ߡߊ $1.",
+       "show-big-image-size": "$1 × $2 ߖߌ߬ߦߊ߬ߘߊ߲ߕߊ",
+       "metadata": "ߡߋߕߊߘߊ߯ߕߊ߫",
+       "metadata-help": "ߞߌ߬ߓߊ߬ߙߏ߬ߦߊ߬ߟߌ߬ ߜߘߍ߫ ߟߎ߫ ߦߋ߫ ߞߐߕߐ߮ ߣߌ߲߬ ߘߐ߫߸ ߊ߬ ߟߊߘߏ߲߬ߣߍ߲߬ ߦߋ߫ ߞߍ߫ ߟߊ߫ ߞߍߟߊ߲߫ ߡߍ߲ߛߍ߲ߡߊ ߟߋ߫ ߟߊ߫ ߥߟߊ߫ ߖߌ߬ߦߊ߬ߕߍ߬ߟߊ߲߸ ߞߵߊ߬ ߟߊߓߊ߯ߙߊ߫ ߥߟߊ߫ ߞߵߊ߬ ߡߍ߲ߛߍ߲ߡߊ.\nߣߴߊ߬ ߡߊߦߟߍ߬ߡߊ߲߬ ߣߍ߲߬ ߞߍ߫ ߘߊ߫ ߞߊ߬ ߓߴߊ߬ ߛߎ߲ߞߎ߲ ߡߊ߬߸ ߞߌ߬ߓߊ߬ߙߏ߬ߦߊ ߘߏ߫ ߟߎ߫ ߕߍ߫ ߣߊ߬ ߟߊߞߊ߲߬ߘߏ߬ ߟߊ߫ ߞߐߕߐ߯ ߡߊߦߟߍ߬ߡߊ߲߬ߣߍ߲ ߘߐ߫.",
+       "metadata-fields": "ߡߋߕߊߘߕߊ ߖߌ߬ߦߊ߬ߓߍ ߞߣߍ ߡߍ߲ ߦߋ߫ ߗߋߛߓߍ ߣߌ߲߬ ߘߐ߫߸ ߏ߬ ߘߌ߫ ߣߵߊ߬ ߞߎ߲߬ߓߐ߫ ߖߌ߬ߦߊ߬ߓߍ ߞߐߜߍ ߘߐ߫ ߣߌ߫ ߡߋߕߊߘߕߊ ߥߟߊ߬ߟߋ߲ ߠߊߘߐ߯ߦߊ߫ ߘߊ߫.ߊ߬ ߕߐ߭ ߟߎ߬ ߢߡߊߘߏ߲߰ߣߍ߲ ߘߌ߫ ߕߏ߫ ߝߍ߭ ߞߏߛߐ߲߬.\n•ߊ߬ ߞߍ߫ \n•ߛߎ߯ߦߊ \n•ߕߎ߬ߡߊ߬ߘߊ ߣߌ߫ ߕߎ߬ߡߊ߬ߙߋ߲ ߓߐߛߎ߲ߡߊ \n•ߟߊ߬ߝߏߦߌ ߕߎ߬ߡߊ߬ߘߊ߬ ߖߐ߲ߖߐ߲ \n•ߞ ߝߙߍߕߍ \n•ߡ.ߛ.ߛ ߞߊߟߌߦߊ ߡߐ߬ߟߐ߲߬ߦߊ߬ߟߌ \n•ߕߊߞߎ߲ߡߊ ߥߊ߲߬ߥߊ߲ \n•ߞߎ߬ߛߊ߲ \n•ߓߊߦߟߍߡߊ߲ ߤߊߞߍ \n•ߖߌ߬ߦߊ߬ߓߍ ߞߊ߲߬ߛߓߍߟߌ \nGPS ߘߟߊߕߍ߮ \nGPS ߘߎ߰ߕߍߟߍ߲ \nGPS ߞߐߓߋ",
+       "namespacesall": "ߊ߬ ߓߍ߯",
+       "monthsall": "ߡߎ߰ߡߍ",
+       "imgmultipagenext": "ߞߐߜߍ ߣߊ߬ߕߐ ←",
+       "imgmultigo": "ߥߊ߫߹",
+       "imgmultigoto": "ߥߊ߫ ߞߐߜߍ ߣߌ߲߬ ߞߊ߲߬ $1",
+       "watchlisttools-clear": "ߜߋ߬ߟߎ߲߬ߠߌ߲߬ ߞߐߜߍ ߖߏ߬ߛߌ߬",
+       "watchlisttools-view": "ߡߊ߬ߦߟߍ߬ߡߊ߲߬ߠߌ߲߫ ߕߣߐ߬ߡߊ ߟߎ߫ ߦߌ߬ߘߊ߬ߟߌ",
+       "watchlisttools-edit": "ߜߋ߬ߟߎ߲߬ߠߌ߲߬ ߞߐߜߍ ߦߋ߫ ߞߵߊ߬ ߡߊߦߟߍ߬ߡߊ߲߫",
+       "watchlisttools-raw": "ߜߋ߬ߟߎ߲߬ߠߌ߲߬ ߞߐߜߍ ߡߎ߰ߡߍ ߡߊߦߟߍ߬ߡߊ߲߫",
+       "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|ߓߊ߬ߘߏ߬ߟߌ]])",
+       "redirect": "ߟߊߞߎ߲߬ߛߌ߲߬ߣߍ߲߬ ߦߋ߫ ߞߐߕߐ߮ ߓߟߏ߫߸ ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ߸ ߞߐߜߍ߸ ߡߛߊ߬ߦߌ߲߬ߠߌ߲߸ ߥߟߊ߫ ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ID",
+       "redirect-summary": "ߞߐߜߍ߫ ߓߟߏߡߊߞߊ߬ߣߍ߲ ߟߊߞߎ߲߬ߛߌ߲߬ߣߍ߲߬ ߦߋ߫ ߞߐߕߐ߮ (ߞߐߕߐ߮ ߕߐ߮ ߘߌ߫),ߞߐߜߍ (ߦߋ߫ ߡߛߊ߬ߦߌ߲߬ߠߌ߲ ID ߥߟߊ߫ ߞߐߜߍ ID ߘߌ ߞߊ߲߬), ߞߐߜߍ߫ ߟߊߓߊ߯ߙߕߊ ߦߋ߫ (ߟߊ߬ߓߊ߰ߙߟߊ߬ ߦߙߌߞߊ ID ߘߌ ߞߊ߲߬), ߥߟߊ߫ ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ߘߏ߲߬ߕߐ߬ߟߊ ߦߋ߫ (ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ID ߘߌ ߞߊ߲߬). ߟߊ߬ߓߊ߰ߙߊ߬ߟߌ:\n[[{{#Special:Redirect}}/file/Example.jpg]], \n[[{{#Special:Redirect}}/page/64308]],\n[[{{#Special:Redirect}}/revision/328429]], \n[[{{#Special:Redirect}}/user/101]], ߥߟߊ߫ \n[[{{#Special:Redirect}}/logid/186]].",
+       "redirect-submit": "ߕߊ߯",
+       "redirect-lookup": "ߊ߬ ߘߐߜߍ߫",
+       "redirect-value": "ߡߐ߬ߟߐ߲",
+       "redirect-user": "ߟߊߓߊ߯ߙߊߟߊ ߟߊ߫ ߡߊ߬ߟߐ߲߬ߝߙߍߕߍ",
+       "redirect-page": "ߞߐߜߍ߫ ߡߊߟߐ߲ߝߙߍߕߍ",
+       "redirect-revision": "ߞߐߜߍ ߣߐ߬ߡߊ߬ߛߊ߬ߦߌ߬ ߝߙߍߕߍ",
+       "redirect-file": "ߞߐߕߐ߯ ߕߐ߮",
+       "specialpages": "ߘߎ߲߬ߘߎ߬ߡߊ߬ ߞߐߜߍ ߟߎ߬",
+       "tag-filter": "[[Special:Tags|ߞߊ߲ߠߊߛߓߍ]] ߢߡߊߘߏ߲߰ߣߍ߲",
+       "tag-list-wrapper": "[[Special:Tags|{{PLURAL:$1|Tag|Tags}}]]: $2",
+       "tags-active-yes": "ߐ߲߬ߐ߲߬ߐ߲߫",
+       "tags-active-no": "ߍ߲߬ߍ߲ߍ߲߬",
+       "tags-hitcount": "{{PLURAL:$1|ߦߟߍ߬ߡߊ߲߬ߠߌ|$1 ߦߟߍ߬ߡߊ߲߬ߠߌ ߠߎ߬}}",
+       "logentry-delete-delete": "$1 {{GENDER:$2|deleted}} ߞߐߜߍ $3",
+       "logentry-delete-restore": "$1 $3($4) ߞߐߜߍ {{GENDER:$2|ߓߘߊ߫ ߟߊߛߊ߬ߦߌ߬ ߞߐ߫}}",
+       "logentry-delete-revision": "$1  {{GENDER:$2|ߓߘߊ߫ ߦߟߍ߬ߡߊ߲߬ߠߌ߲ ߞߍ߫}} ߣߌ߲߬ ߦߋߗߏ߮ ߟߊ߫ {{PLURAL:$5|a revision|$5 revisions}} ߞߐߜߍ ߣߌ߲߬ $3: $4 ߘߐ߫",
+       "revdelete-content-hid": "ߞߣߐߘߐ ߘߐ߲߰ߣߍ߲߫ ߠߋ߬",
+       "logentry-move-move": "$1 {{GENDER:$2|ߓߘߊ߫ ߞߐߜߍ}} ߓߐ߫ ߦߊ߲߬ $3 ߞߴߊ߬ ߟߊߕߊ߯ $4",
+       "logentry-move-move-noredirect": "$1 {{GENDER:$1|ߓߘߴߊ߬ ߓߐ߫ ߦߋ߲߬}} ߞߐߜߍ ߣߌ߲߬ $3 ߞߊ߬ ߥߴߊ߬ ߘߌ߫ $4 ߞߵߊ߬ ߕߘߍ߬ ߊ߬ ߡߴߊ߬ ߟߊߞߎ߲߬ߛߌ߲߫",
+       "logentry-move-move_redir": "$1 {{GENDER:$2|ߓߘߴߊ߬ ߓߐ߫ ߦߋ߲߬}} ߞߐߜߍ $3 ߞߵߊ߬ ߛߌ߰ $4 ߟߊ߬ߞߎ߲߬ߛߌ߲߬ߠߌ߲ ߓߟߏߡߊ߬",
+       "logentry-patrol-patrol-auto": "{{GENDER:$2|ߓߘߴߊ߬ ߢߊߣߐߦߊ߫}} ߟߊ߫ ߞߍߒߖߘߍߦߋ߫ $1 ߞߐߜߍ ߣߌ߲߬ $3 ߓߍ߬ߙߍ߲߬ߓߍ߬ߙߍ߲߬ߠߌ߲ ߡߊ߬ߛߊ߬ߦߌ߲߬ߠߌ߲ $4",
+       "logentry-newusers-create": "ߖߊ߬ߕߋ߬ߘߊ߬ ߟߊߓߊ߯ߙߕߊ $1 ߕߘߍ߬ ߦߋ߫ {{ߞߊ߬ߘߌ߬ߛߊ߬:$2|ߟߞߊ߬ߟߌ߬ߣߐ ߟߋ߬ ߘߌ߫}}",
+       "logentry-newusers-autocreate": "ߟߊߓߊ߯ߙߊߟߊ ߟߊ߫ ߖߊ߬ߕߋ߬ߘߊ $1{{GENDER:$2|ߟߊߘߊ߲߫ ߘߊ߫ }} ߞߍߒߖߘߍߦߋ߫ ߓߟߏߡߊ߬",
+       "logentry-upload-upload": "$1 {{GENDER:$2|ߟߊ߬ߦߟߍ߬ߟߌ߬ߣߐ ߟߋ߬}} $3",
+       "logentry-upload-overwrite": "$1 {{GENDER:$2|ߓߘߊ߫ ߟߊ߬ߦߟߍ߬ߟߌ ߞߍ߫}} ߞߊ߲ߦߟߍߡߊ߲߫ ߞߎߘߊ߫ ߣߌ߲߬ ߠߊ߫ $3",
+       "searchsuggest-search": "{{SITENAME}} ߊ߬ ߢߌߣߌ߲߫",
+       "duration-days": "$1 {{PLURAL:$1|ߟߏ߲|ߟߏ߲ ߠߎ߬}}",
+       "randomrootpage": "ߓߍ߲߬ߛߋ߲߬ߡߊ߬ ߞߐߜߍ ߓߏ߬ߞߊߘߌ"
+}
index 5fb4a80..f199643 100644 (file)
        "minoreditletter": "n",
        "newpageletter": "M",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 djinang-iny {{PLURAL:$1|niall}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} mila wallak",
        "rc-old-title": "goryat quadga jin $1",
        "recentchangeslinked": "Noyyang wallak",
index 3647af5..d05c38a 100644 (file)
        "rcfilters-filter-editsbyself-description": "Vòstras pròprias contribucions.",
        "rcfilters-filter-editsbyother-label": "Modificacions faitas pels autres.",
        "rcfilters-filter-editsbyother-description": "Totes los cambiaments a l'excepcion de los vòstres.",
-       "rcfilters-filtergroup-userExpLevel": "Registrament dels usatgièrs e experiéncia",
+       "rcfilters-filtergroup-user-experience-level": "Registrament dels usatgièrs e experiéncia",
        "rcfilters-filter-user-experience-level-registered-label": "Connectat",
        "rcfilters-filter-user-experience-level-registered-description": "Editors connectats.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Pas connectat",
        "rcfilters-filter-logactions-description": "Accions dels administrators, creacions de comptes, supressions de paginas, telecargaments...",
        "rcfilters-hideminor-conflicts-typeofchange": "D'unes tipes de cambiament pòdon pas èsser designats coma  \"minors\", doncas aqueste filtre es en conflicte amb los filtres  de Tipe de cambiament seguent: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Aqueste filtre «Tipe de cambiament» es en conflicte amb lo filtre «Edicions minoras». D'unes tipes de cambiaments  pòdon pas èstre considerats coma «minors».",
-       "rcfilters-filtergroup-lastRevision": "Darrièras revisions",
+       "rcfilters-filtergroup-lastrevision": "Darrièras revisions",
        "rcfilters-filter-lastrevision-label": "Darrièra revision",
        "rcfilters-filter-lastrevision-description": "Sonque lo cambiament de pagina lo mai recent.",
        "rcfilters-filter-previousrevision-label": "Pas la darrièra revision",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|utilizaire seguent|utilizaires seguents}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|octet|octets}} aprèp cambiament",
        "newsectionsummary": "/* $1 */ seccion novèla",
        "rc-enhanced-expand": "Vejatz los detalhs",
        "img-auth-nopathinfo": "PATH_INFO mancant. Vòstre servidor es pas parametrat per passar aquesta informacion.\nBenlèu que fonciona en CGI e supòrta pas img_atuh. Consultatz https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Lo camin demandat es pas lo repertòri de telecargament configurat.",
        "img-auth-badtitle": "Impossible de construire un títol valid a partir de « $1 ».",
-       "img-auth-nologinnWL": "Sètz pas connectat e « $1 » es pas dins la lista blanca.",
        "img-auth-nofile": "Lo fichièr « $1 » existís pas.",
        "img-auth-isdir": "Ensajatz d'accedir al repertòri « $1 ».\nSol l'accès als fichièrs es permesa.",
        "img-auth-streaming": "Lectura en continú de « $1 ».",
        "allmessagesdefault": "Messatge per defaut",
        "allmessagescurrent": "Messatge actual",
        "allmessagestext": "Aquò es la lista de totes los messatges disponibles dins l’espaci MediaWiki.\nVisitatz la [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Localizacion MediaWiki] e [https://translatewiki.net translatewiki.net] se desiratz contribuir a la localizacion MediaWiki generica.",
-       "allmessagesnotsupportedDB": "Aquesta pagina '''{{ns:special}}:Allmessages''' es pas utilizabla perque '''$wgUseDatabaseMessages''' es estat desactivat.",
+       "allmessages-not-supported-database": "Aquesta pagina '''{{ns:special}}:Allmessages''' es pas utilizabla perque '''$wgUseDatabaseMessages''' es estat desactivat.",
        "allmessages-filter-legend": "Filtre",
        "allmessages-filter": "Filtrar per estat de modificacion :",
        "allmessages-filter-unmodified": "Pas modificat",
index 433a98a..6dd890c 100644 (file)
@@ -7,7 +7,8 @@
                        "Mashoi7",
                        "Misosoof",
                        "Ghiutun",
-                       "Matma Rex"
+                       "Matma Rex",
+                       "Pyscowicz"
                ]
        },
        "tog-underline": "Linkien alleviivuamine:",
        "histfirst": "vahnin",
        "histlast": "uuzin",
        "historysize": "({{PLURAL:$1|1 baitu|$1 baitua}})",
-       "historyempty": "(tyhjy)",
+       "historyempty": "tyhjy",
        "history-feed-title": "Versiihistourii",
        "history-feed-description": "Tämän sivun versiihistourii",
        "history-feed-item-nocomment": "$1 ($2)",
        "logentry-newusers-create": "Käyttäi $1 oli perustettu $2",
        "logentry-upload-upload": "$1 {{GENDER:$2|päivitetty}} $3",
        "rightsnone": "(nimidä)",
-       "searchsuggest-search": "Eči",
+       "searchsuggest-search": "Eči {{SITENAME}}",
        "mw-widgets-abandonedit": "Tovengo tahtot mennä järilleh kačondutilah tallendamattah ezmäi?",
        "mw-widgets-abandonedit-discard": "Hylgiä kohendukset",
        "mw-widgets-abandonedit-keep": "Jatka edituičendua",
index 5c472e5..8e0b8d4 100644 (file)
        "minoreditletter": "ଟିକେ",
        "newpageletter": "ନୂଆ",
        "boteditletter": "ବଟ",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|ସଭ୍ୟ|ସଭ୍ୟଗଣା}}ଙ୍କୁ ଦେଖୁଅଛି]",
        "rc-change-size-new": "ବଦଳ ପରେ $1 {{PLURAL:$1|ବାଇଟ|ବାଇଟସବୁ}}",
        "newsectionsummary": "/* $1 */ ନୂଆ ଭାଗ",
        "rc-enhanced-expand": "ସବିଶେଷ ଦେଖାନ୍ତୁ",
        "img-auth-nopathinfo": "ପଥ_ବିବରଣୀ ମିଳୁ ନାହିଁ।\nଆପଣଙ୍କ ସର୍ଭରରେ ଏହି ତଥ୍ୟଟିକୁ ପଠାଇବା ନିମନ୍ତେ ବ୍ୟବସ୍ଥା କରାଯାଇନାହିଁ ।\nଏହା ସିଜିଆଇ-ଆଧାରିତ ହୋଇପାରେ ଓ ଆଇଏମଜି_ଅଉଥରେ କାମକରୁନଥାଇପାରେ  ।\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization ଦେଖନ୍ତୁ ।",
        "img-auth-notindir": "ଅନୁରୋଧ କରାଯାଇଥିବା ପଥ ସଂରଚିତ ଅପଲୋଡ଼ ତାଲିକା ନୁହେଁ ।",
        "img-auth-badtitle": "\"$1\"ରୁ ଏକ ସଠିକ ଶିରୋନାମା ଗଠନ କରିବାରେ ଅସଫଳ ହେଲୁଁ ।",
-       "img-auth-nologinnWL": "ଆପଣ ଲଗ ଇନ କରି ନାହାନ୍ତି ଓ \"$1\" ଏକ ଅନୁମୋଦିତ ତାଲିକାରେ ନାହିଁ ।",
        "img-auth-nofile": "\"$1\" ଫାଇଲଟି ଏଠାରେ ନାହିଁ ।",
        "img-auth-isdir": "ଆପଣ \"$1\" ସୂଚି ତାଲିକାଟି ଦେଖିବାକୁ ଚେଷ୍ଟା କରୁଛନ୍ତି ।\nଏଠାରେ କେବଳ ଫାଇଲ ଦେଖିବା ଅନୁମୋଦିତ ।",
        "img-auth-streaming": "\"$1\" ନିୟମିତ ଲୋଡ଼ ଚାଲିଅଛି ।",
        "allmessagesdefault": "ଆପେଆପେ ଚିଠିରେ ରହିବା କଥା",
        "allmessagescurrent": "ଏବେକର ସନ୍ଦେଶ ଲେଖା",
        "allmessagestext": "ଏଥିରେ ମିଡ଼ିଆଉଇକି ନେମସ୍ପେସରେ ଥିବା ସିଷ୍ଟମ ସନ୍ଦେଶର ଏକ ତାଲିକା ଦିଆଗଲା ।\nଯଦି ଆପଣ ମୂଳ ଦୟାକରି ମିଡ଼ିଆଉଇକି ଆଞ୍ଚଳିକୀକରଣରେ ଭାଗ ନେବା ପାଇଁ ଚାହାନ୍ତି ତେବେ [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation ମିଡ଼ିଆଉଇକି ଆଞ୍ଚଳିକୀକରଣ] ଓ [https://translatewiki.net translatewiki.net] ଦେଖନ୍ତୁ ।",
-       "allmessagesnotsupportedDB": "'''$wgUseDatabaseMessages''' ଅଚଳ କରାଯାଇଥିବାରୁ ଏହି ପୃଷ୍ଠାଟି ବ୍ୟବହାର କରାଯାଇପାରିବ ନାହିଁ ।",
+       "allmessages-not-supported-database": "'''$wgUseDatabaseMessages''' ଅଚଳ କରାଯାଇଥିବାରୁ ଏହି ପୃଷ୍ଠାଟି ବ୍ୟବହାର କରାଯାଇପାରିବ ନାହିଁ ।",
        "allmessages-filter-legend": "ଛାଣିବା",
        "allmessages-filter": "ଆପଣା ପସନ୍ଦରେ ଛାଣିବେ:",
        "allmessages-filter-unmodified": "ବଦଳାହୋଇନଥିବା",
index 1ad96b0..eb5ca49 100644 (file)
        "minoreditletter": "ਛੋ",
        "newpageletter": "ਨ",
        "boteditletter": "ਬੋਟ",
-       "number_of_watching_users_pageview": "[$1 ਵੇਖ ਰਹੇ ਹਨ {{PLURAL:$1|ਯੂਜ਼ਰ}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|ਬਾਈਟ|ਬਾਈਟਾਂ}} ਤਬਦੀਲੀ ਤੋਂ ਬਾਅਦ",
        "newsectionsummary": "/* $1 */ ਨਵਾਂ ਭਾਗ",
        "rc-enhanced-expand": "ਵੇਰਵੇ ਵੇਖਾਓ",
index cbad6d5..89af1a7 100644 (file)
        "rcfilters-filtergroup-watchlist": "Deng bulung a yati lu king babanten",
        "rcfilters-filter-watchlist-watched-label": "Deng atiu babanten",
        "rcfilters-filter-watchlist-notwatched-label": "Ala lu king babanten",
-       "rcfilters-filtergroup-lastRevision": "Kasalungsungan a pangayalili",
+       "rcfilters-filtergroup-lastrevision": "Kasalungsungan a pangayalili",
        "rcfilters-filter-lastrevision-label": "Kasalungsungan a pangayalili",
        "rcnotefrom": "Atilu king lalam deng miyalilan manibat anyang <b>$2</b> (angga king <b>$1</b> makalto).",
        "rclistfrom": "Pakit la reng bayung miyalilan manibat anyang $3 $2",
        "minoreditletter": "m",
        "newpageletter": "B",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 lalbe {{PLURAL:$1|talagamit|talagamit}}]",
        "newsectionsummary": "/* $1 */ bayung seksiyon/dake",
        "rc-enhanced-expand": "Pakit la reng detalle (mangailangan yang JavaScript)",
        "rc-enhanced-hide": "Isalikut la reng detalle",
        "allmessagesdefault": "Sulat a lunto nung alang mepili (default)",
        "allmessagescurrent": "Kasalungsungan a kulitan",
        "allmessagestext": "Deng makatuki ila reng system message a atyu king pirinan lagyu (namespace) ning MediaWiki.",
-       "allmessagesnotsupportedDB": "E maliaring gamitan ing bulung a ini uling ing '''$wgUseDatabaseMessages''' makapatda ya.",
+       "allmessages-not-supported-database": "E maliaring gamitan ing bulung a ini uling ing '''$wgUseDatabaseMessages''' makapatda ya.",
        "thumbnail-more": "Paragulan",
        "filemissing": "Ala yu ing file",
        "thumbnail_error": "Migkamaling maglalang thumbnail: $1",
index ccb9f47..45e0bac 100644 (file)
                        "DeRudySoulStorm",
                        "Railfail536",
                        "Vlad5250",
-                       "CiaPan"
+                       "CiaPan",
+                       "BadDog"
                ]
        },
        "tog-underline": "Podkreślenie linków:",
        "tog-norollbackdiff": "Nie pokazuj zmian po użyciu funkcji „cofnij”",
        "tog-useeditwarning": "Ostrzegaj mnie, gdy opuszczam stronę edycji bez zapisania zmian",
        "tog-prefershttps": "Zawsze używaj bezpiecznego połączenia po zalogowaniu",
-       "tog-showrollbackconfirmation": "Wyświetl komunikat potwierdzający kliknięcie linku wycofującego edycję",
+       "tog-showrollbackconfirmation": "Wyświetl komunikat potwierdzający kliknięcie linku wycofującego edycje",
        "underline-always": "Zawsze",
        "underline-never": "Nigdy",
        "underline-default": "według ustawień skórki lub przeglądarki",
        "virus-scanfailed": "skanowanie nieudane (błąd $1)",
        "virus-unknownscanner": "nieznany program antywirusowy:",
        "logouttext": "'''Nie jesteś już zalogowany.'''\n\nZauważ, że do momentu wyczyszczenia pamięci podręcznej przeglądarki niektóre strony mogą wyglądać tak, jakbyś wciąż był zalogowany.",
+       "logging-out-notify": "Zostałeś wylogowany, proszę czekać.",
+       "logout-failed": "Nie możesz się teraz wylogować: $1",
        "cannotlogoutnow-title": "Nie możesz się teraz wylogować",
        "cannotlogoutnow-text": "Podczas używania $1 wylogowanie nie jest niemożliwe.",
        "welcomeuser": "Witaj, $1!",
        "previewerrortext": "Wystąpił błąd podczas próby podglądu Twoich zmian.",
        "blockedtitle": "Użytkownik jest zablokowany",
        "blocked-email-user": "<strong>Twoje konto zostało wyłączone z wysyłania wiadomości emaili innym użytkownikom. Wciąż możesz edytować inne strony na wiki.</strong> Więcej szczegółów na temat blokady znajdziesz na swojej [[Special:MyContributions|stroni wkładu]].\n\nBlokada została nałożona przez $1.\n\nPodany powód to: <em>$2</em>.\n\n* Początek blokady: $8\n* Wygaśnięcie blokady: $6\n* Zablokowany został: $7\n* Identyfikator blokady: #$5",
-       "blockedtext-partial": "<strong>Twoje konto lub adres IP zostało wyłączone z dokonywania zmian na tej stronie. Wciąż możesz edytować inne strony na wiki.</strong> Więcej szczegółów na temat blokady znajdziesz na swojej [[Special:MyContributions|stroni wkładu]].\n\nBlokada została nałożona przez $1.\n\nPodany powód to: <em>$2</em>.\n\n* Początek blokady: $8\n* Wygaśnięcie blokady: $6\n* Zablokowany został: $7\n* Identyfikator blokady: #$5",
+       "blockedtext-partial": "<strong>Twoje konto lub adres IP zostało wyłączone z dokonywania zmian na tej stronie. Wciąż możesz edytować inne strony na wiki.</strong> Więcej szczegółów na temat blokady znajdziesz na swojej [[Special:MyContributions|stronie swojego wkładu]].\n\nBlokada została nałożona przez $1.\n\nPodany powód to: <em>$2</em>.\n\n* Początek blokady: $8\n* Wygaśnięcie blokady: $6\n* Zablokowany został: $7\n* Identyfikator blokady: #$5",
        "blockedtext": "<strong>Twoje konto lub adres IP zostały zablokowane.</strong>\n\nBlokada została nałożona przez $1.\nPodany powód to: <em>$2</em>.\n\n* Początek blokady: $8\n* Wygaśnięcie blokady: $6\n* Zablokowany został: $7\n\nW celu wyjaśnienia przyczyny zablokowania możesz się skontaktować z $1 lub innym [[{{MediaWiki:Grouppage-sysop}}|administratorem]].\nNie możesz użyć funkcji „{{int:emailuser}}”, jeśli brak jest poprawnego adresu e‐mail w Twoich [[Special:Preferences|preferencjach]] lub jeśli taka możliwość została Ci zablokowana.\nTwój obecny adres IP to $3, a numer identyfikacyjny blokady to #$5.\nProsimy o podanie obu tych informacji przy wyjaśnianiu blokady.",
        "autoblockedtext": "Ten adres IP został zablokowany automatycznie, gdyż korzysta z niego inny użytkownik, zablokowany przez administratora $1.\nPowód blokady:\n\n:<em>$2</em>\n\n* Początek blokady: $8\n* Wygaśnięcie blokady: $6\n* Zablokowany został: $7\n\nMożesz skontaktować się z $1 lub jednym z pozostałych [[{{MediaWiki:Grouppage-sysop}}|administratorów]] w celu uzyskania informacji o blokadzie.\n\nNie możesz użyć funkcji „{{int:emailuser}}”, jeśli brak jest poprawnego adresu e‐mail w Twoich [[Special:Preferences|preferencjach]] lub jeśli taka możliwość została Ci zablokowana.\n\nTwój obecny adres IP to $3, a numer identyfikacyjny blokady to #$5.\nProsimy o podanie obu tych numerów przy wyjaśnianiu blokady.",
        "systemblockedtext": "Twoja nazwa użytkownika lub adres IP zostały automatycznie zablokowane przez MediaWiki.\nPodany powód to:\n\n:<em>$2</em>\n\n* Początek blokady: $8\n* Wygaśnięcie blokady: $6\n* Zamierzano zablokować: $7\n\nTwój obecny adres IP to $3.\nProsimy o dołączenie powyższych szczegółów w jakichkolwiek zadawanych pytaniach.",
        "page_first": "początek",
        "page_last": "koniec",
        "histlegend": "Wybór porównania – zaznacz kropeczkami dwie wersje do porównania i wciśnij enter lub przycisk ''Porównaj wybrane wersje''.<br />\nLegenda: (bież.) – pokaż zmiany od tej wersji do bieżącej,\n(poprz.) – pokaż zmiany od wersji poprzedzającej, m – mała (drobna) zmiana",
-       "history-fieldset-title": "Szukaj wersji",
+       "history-fieldset-title": "Filtruj wersje",
        "history-show-deleted": "Tylko usunięte edycje",
        "histfirst": "od najstarszych",
        "histlast": "od najnowszych",
        "historysize": "({{PLURAL:$1|1 bajt|$1 bajty|$1 bajtów}})",
-       "historyempty": "(pusta)",
+       "historyempty": "pusta",
        "history-feed-title": "Historia wersji",
        "history-feed-description": "Historia wersji tej strony wiki",
        "history-feed-item-nocomment": "$1 o $2",
        "right-reupload-own": "Nadpisywanie wcześniej przesłanego pliku",
        "right-reupload-shared": "Lokalne nadpisywanie pliku istniejącego w repozytorium mediów",
        "right-upload_by_url": "Przesyłanie plików z adresu URL",
-       "right-purge": "Czyszczenie pamięci podręcznej stron bez pytania o potwierdzenie",
-       "right-autoconfirmed": "Wyłączenie z ograniczeń prędkości zakładanych na IP",
+       "right-purge": "Czyszczenie pamięci podręcznej stron",
+       "right-autoconfirmed": "Wyłączenie z ograniczeń przepustowości nałożonych na IP",
        "right-bot": "Oznaczanie edycji jako wykonanych automatycznie",
        "right-nominornewtalk": "Drobne zmiany na stronach dyskusji użytkowników nie włączają powiadomienia o nowej wiadomości",
        "right-apihighlimits": "Zwiększony limit w zapytaniach wykonywanych poprzez interfejs API",
        "action-changetags": "dodawania i usuwania dowolnych znaczników z poszczególnych wersji i wpisów w rejestrze",
        "action-deletechangetags": "usuwania znaczników z bazy danych",
        "action-purge": "wyczyść pamięć podręczną tej strony",
+       "action-apihighlimits": "używania zwiększonych limitów w zapytaniach wykonywanych poprzez interfejs API",
+       "action-autoconfirmed": "nie bycia objętym ograniczeniem przepustowości nałożonym na IP",
+       "action-bigdelete": "usuwania stron z długą historią edycji",
+       "action-blockemail": "blokowania użytkownikom możliwości wysyłania wiadomości",
+       "action-bot": "oznaczania edycji jako wykonanych automatycznie",
+       "action-editprotected": "edytowania stron zabezpieczonych na poziomie „{{int:protect-level-sysop}}”",
+       "action-editsemiprotected": "edytowania stron zabezpieczonych na poziomie „{{int:protect-level-autoconfirmed}}”",
+       "action-editinterface": "edytowania interfejsu użytkownika",
+       "action-editusercss": "edytowania plików CSS innych użytkowników",
+       "action-edituserjson": "edytowania plików JSON innych użytkowników",
+       "action-edituserjs": "edytowania plików JavaScript innych użytkowników",
+       "action-editsitecss": "edytowania plików CSS projektu",
+       "action-editsitejson": "edytowania plików JSON projektu",
+       "action-editsitejs": "edytowania plików JavaScript projektu",
+       "action-editmyusercss": "edytowania własnych plików CSS",
+       "action-editmyuserjson": "edytowania własnych plików JSON",
+       "action-editmyuserjs": "edytowania własnych plików JavaScript",
+       "action-viewsuppressed": "podglądu wersji ukrytych przed każdym użytkownikiem",
+       "action-hideuser": "blokowania użytkownika i ukrywania go od publiczności",
+       "action-ipblock-exempt": "obchodzenia blokad i blokad zakresów adresów IP",
+       "action-unblockself": "odblokowania samego siebie",
+       "action-noratelimit": "nie bycia objętym ograniczeniem przepustowości",
+       "action-reupload-own": "nadpisywania wcześniej przesłanych plików",
+       "action-nominornewtalk": "nie włączania powiadomień o nowej wiadomości na stronach dyskusji użytkowników poprzez wykonanie drobnej edycji",
+       "action-markbotedits": "oznaczania rewertu jako edycji bota",
+       "action-patrolmarks": "podglądu znaczników patrolowania ostatnich zmian",
+       "action-override-export-depth": "eksportowania stron wraz z linkowanymi do głębokości 5 linków",
+       "action-suppressredirect": "przenoszenia stron bez tworzenia przekierowania w miejscu starej nazwy",
        "nchanges": "$1 {{PLURAL:$1|zmiana|zmiany|zmian}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|od ostatniej wizyty}}",
        "enhancedrc-history": "historia",
        "rcfilters-savedqueries-already-saved": "Ten zestaw filtrów jest już zapisany. Zmień swoje ustawienia aby utworzyć nowy zestaw zapisanych filtrów.",
        "rcfilters-restore-default-filters": "Przywróć domyślne filtry",
        "rcfilters-clear-all-filters": "Wyczyść filtry",
-       "rcfilters-show-new-changes": "Zobacz nowsze zmiany",
+       "rcfilters-show-new-changes": "Zobacz zmiany od $1",
        "rcfilters-search-placeholder": "Filtruj zmiany (użyj menu lub wyszukaj według nazwy filtra)",
        "rcfilters-invalid-filter": "Nieprawidłowy filtr",
        "rcfilters-empty-filter": "Brak aktywnych filtrów. Wyświetlane są wszystkie zmiany.",
        "rcfilters-filter-editsbyself-description": "Czynności dokonane przez Ciebie.",
        "rcfilters-filter-editsbyother-label": "Zmiany dokonane przez innych",
        "rcfilters-filter-editsbyother-description": "Wszystkie zmiany oprócz Twoich.",
-       "rcfilters-filtergroup-userExpLevel": "Zarejestrowanie użytkownika i doświadczenie",
+       "rcfilters-filtergroup-user-experience-level": "Zarejestrowanie użytkownika i doświadczenie",
        "rcfilters-filter-user-experience-level-registered-label": "Zarejestrowani",
        "rcfilters-filter-user-experience-level-registered-description": "Zalogowani edytorzy.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Niezarejestrowani",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Filtr „Drobne zmiany” koliduje z jednym lub wieloma filtrami Rodzaju zmian, ponieważ niektóre rodzaje zmian nie mogą być uznawane za  „drobne”. Kolidujące filtry zostały powyżej odpowiednio zaznaczone na pasku aktywnych filtrów.",
        "rcfilters-hideminor-conflicts-typeofchange": "Niektóre rodzaje zmian nie mogą być uznawane za „drobne”, dlatego ten filtr koliduje z następującymi filtrami Rodzaju zmian: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Ten filtr Rodzaju zmian koliduje z filtrem „Drobne zmiany”. Nie wszystkie zmiany mogą być uznawane za „drobne”.",
-       "rcfilters-filtergroup-lastRevision": "Ostatnie wersje",
+       "rcfilters-filtergroup-lastrevision": "Ostatnie wersje",
        "rcfilters-filter-lastrevision-label": "Najnowsza wersja",
        "rcfilters-filter-lastrevision-description": "Tylko najnowsze zmiany dla każdej ze stron.",
        "rcfilters-filter-previousrevision-label": "Wersje inne niż najnowsza",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|obserwujący użytkownik|obserwujących użytkowników}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|bajt|bajty|bajtów}} po zmianie",
        "newsectionsummary": "/* $1 */ nowa sekcja",
        "rc-enhanced-expand": "Pokaż szczegóły",
        "img-auth-nopathinfo": "Brak informacji o ścieżce.\nSerwer musi być skonfigurowany tak, aby przekazywał zmienne REQUEST_URI lub PATH_INFO.\nJeżeli jest już odpowiednio skonfigurowany, spróbuj włączyć $wgUsePathInfo.\nWięcej o informacji o autoryzacji grafik na https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Żądana ścieżka nie jest w obrębie katalogu skonfigurowanego do przesyłania plików.",
        "img-auth-badtitle": "Nie można wygenerować prawidłowego tytuł z „$1”.",
-       "img-auth-nologinnWL": "Nie jesteś zalogowany, a „$1” nie jest na białej liście.",
        "img-auth-nofile": "Brak pliku „$1”.",
        "img-auth-isdir": "Próbujesz uzyskać dostęp do katalogu „$1”.\nDozwolony jest wyłącznie dostęp do plików.",
        "img-auth-streaming": "Strumieniowanie „$1”.",
        "delete-confirm": "Usuwanie „$1”",
        "delete-legend": "Usuń",
        "historywarning": "<strong>Uwaga:</strong> Strona, którą chcesz usunąć, ma {{PLURAL:$1|jedną starszą wersję|$1 starsze wersje|$1 starszych wersji}}:",
-       "historyaction-submit": "Pokaż",
+       "historyaction-submit": "Pokaż wersje",
        "confirmdeletetext": "Zamierzasz usunąć stronę razem z całą dotyczącą jej historią.\nUpewnij się, czy na pewno chcesz to zrobić, że rozumiesz konsekwencje i że robisz to w zgodzie z [[{{MediaWiki:Policy-url}}|zasadami]].",
        "actioncomplete": "Operacja wykonana",
        "actionfailed": "Operacja się nie powiodła",
        "deleting-backlinks-warning": "<strong>Uwaga:</strong> Do strony, którą masz zamiar usunąć, odwołują się [[Special:WhatLinksHere/{{FULLPAGENAME}}|inne strony]].",
        "deleting-subpages-warning": "<strong>Ostrzeżenie:</strong> Strona którą chcesz usunąć ma [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|jedną podstronę|$1 podstrony|$1 podstron|51=ponad 50 podstron}}]].",
        "rollback": "Cofnij edycję",
+       "rollback-confirmation-confirm": "Potwierdź:",
+       "rollback-confirmation-yes": "Wycofaj",
+       "rollback-confirmation-no": "Anuluj",
        "rollbacklink": "cofnij",
        "rollbacklinkcount": "cofnij $1 {{PLURAL:$1|edycję|edycje|edycji}}",
        "rollbacklinkcount-morethan": "cofnij więcej niż $1 {{PLURAL:$1|edycję|edycje|edycji}}",
        "revertpage": "Wycofano edycje użytkownika [[Special:Contributions/$2|$2]] ([[User talk:$2|dyskusja]]). Autor przywróconej wersji to [[User:$1|$1]].",
        "revertpage-nouser": "Wycofano edycje ukrytego użytkownika. Autor przywróconej wersji to {{GENDER:$1|[[User:$1|$1]]}}.",
        "rollback-success": "Wycofano edycje {{GENDER:$3|użytkownika|użytkowniczki}} $1;\nprzywrócono ostatnią wersję autorstwa {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Wycofano edycje użytkownika $1;\nprzywrócono ostatnią wersję autorstwa $2. [$3 Pokaż zmiany]",
        "sessionfailure-title": "Błąd sesji",
        "sessionfailure": "Wydaje się, że wystąpił błąd z Twoją sesją zalogowania;\nto działanie zostało anulowane, aby uniknąć przechwycenia sesji.\nPrześlij formularz jeszcze raz.",
        "changecontentmodel": "Edycja modelu zawartości strony",
        "mycontris": "Edycje",
        "anoncontribs": "Edycje",
        "contribsub2": "Dla {{GENDER:$3|użytkownika|użytkowniczki}} $1 ($2)",
+       "contributions-subtitle": "Dla {{GENDER:$3|użytkownika|użytkowniczki}} $1",
        "contributions-userdoesnotexist": "Konto użytkownika „$1” nie jest zarejestrowane.",
        "negative-namespace-not-supported": "Przestrzenie nazw z negatywnymi wartościami nie są wspierane.",
        "nocontribs": "Brak zmian odpowiadających tym kryteriom.",
        "blocklist-userblocks": "Ukryj blokady konta",
        "blocklist-tempblocks": "Ukryj tymczasowe blokady",
        "blocklist-addressblocks": "Ukryj blokady pojedynczych adresów IP",
+       "blocklist-type": "Typ:",
+       "blocklist-type-opt-all": "Wszystkie",
+       "blocklist-type-opt-sitewide": "Całkowite",
+       "blocklist-type-opt-partial": "Częściowe",
        "blocklist-rangeblocks": "Ukryj blokady zakresów",
        "blocklist-timestamp": "Sygnatura czasowa",
        "blocklist-target": "Cel",
        "blocklist-editing-page": "strony",
        "blocklist-editing-ns": "przestrzenie nazw",
        "ipblocklist-empty": "Lista blokad jest pusta.",
-       "ipblocklist-no-results": "Podany adres IP lub użytkownik nie jest zablokowany.",
+       "ipblocklist-no-results": "Nie znaleziono blokad dla podanego adresu IP lub użytkownika.",
        "blocklink": "zablokuj",
        "unblocklink": "odblokuj",
        "change-blocklink": "zmień blokadę",
+       "empty-username": "(nazwa użytkownika niedostępna)",
        "contribslink": "edycje",
        "emaillink": "wyślij e‐mail",
        "autoblocker": "Zablokowano Cię automatycznie, ponieważ twój adres IP był ostatnio używany przez „[[User:$1|$1]]”.\nPrzyczyna blokady $1 to: „$2”",
        "allmessagesdefault": "Tekst domyślny",
        "allmessagescurrent": "Tekst obecny",
        "allmessagestext": "Lista wszystkich komunikatów systemowych dostępnych w przestrzeni nazw MediaWiki.\nOdwiedź [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Tłumaczenie MediaWiki] oraz [https://translatewiki.net translatewiki.net], jeśli chcesz uczestniczyć w tłumaczeniu oprogramowania MediaWiki.",
-       "allmessagesnotsupportedDB": "Ta strona nie może być użyta, ponieważ zmienna '''$wgUseDatabaseMessages''' jest wyłączona.",
+       "allmessages-not-supported-database": "Ta strona nie może być użyta, ponieważ zmienna '''$wgUseDatabaseMessages''' jest wyłączona.",
        "allmessages-filter-legend": "Filtr",
        "allmessages-filter": "Filtrowanie według stanu modyfikacji:",
        "allmessages-filter-unmodified": "Niezmodyfikowane",
        "confirm-unwatch-top": "Usunąć tę stronę z listy obserwowanych?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Wycofać edycje tej strony?",
+       "confirm-rollback-bottom": "Ta akcja natychmiastowo wycofa wybrane zmiany wykonane na tej stronie.",
        "confirm-mcrrestore-title": "Odtwórz wersję",
        "confirm-mcrundo-title": "Cofnij zmianę",
        "mcrundofailed": "Cofnięcie nie powiodło się",
        "logentry-block-block": "$1 {{GENDER:$2|zablokował|zablokowała|zablokował(a)}} {{GENDER:$4|$3}}, czas blokady: $5 $6",
        "logentry-block-unblock": "$1 {{GENDER:$2|zdjął|zdjęła}} blokadę z {{GENDER:$4|$3}}",
        "logentry-block-reblock": "$1 {{GENDER:$2|zmienił|zmieniła}} ustawienia blokady dla {{GENDER:$4|$3}}, czas blokady: $5 $6",
-       "logentry-partialblock-block-page": "{{PLURAL:$1|strony|stron}}: $2",
-       "logentry-partialblock-block-ns": "przestrzeni nazw{{PLURAL:$1|:|}} $2",
+       "logentry-partialblock-block-page": "{{PLURAL:$1|strony|stron:}} $2",
+       "logentry-partialblock-block-ns": "przestrzeni {{PLURAL:$1|nazw:|nazw}} $2",
        "logentry-partialblock-block": "$1 {{GENDER:$2|wyłączył|wyłączyła}} {{GENDER:$4|$3}} z edytowania $7, czas blokady: $5 $6",
        "logentry-partialblock-reblock": "$1 {{GENDER:$2|zmienił|zmieniła}} ustawienia wyłączenia {{GENDER:$4|$3}} z edytowania $7, czas blokady: $5 $6",
        "logentry-non-editing-block-block": "$1 {{GENDER:$2|zablokował|zablokowała}} {{GENDER:$4|$3}} wykonywanie określonych operacji nieedycyjnych, czas blokady: $5 $6",
        "passwordpolicies-policyflag-forcechange": "musi zmienić po zalogowaniu",
        "passwordpolicies-policyflag-suggestchangeonlogin": "sugerowana zmiana po zalogowaniu",
        "easydeflate-invaliddeflate": "Dostarczona zawartość nie jest poprawnie skompresowana",
-       "unprotected-js": "Ze względów bezpieczeństwa kod JavaScript nie może zostać załadowany z niezabezpieczonych stron. Prosimy dodawać JavaScript w przestrzeni MediaWiki lub jako podstronę strony użytkownika."
+       "unprotected-js": "Ze względów bezpieczeństwa kod JavaScript nie może zostać załadowany z niezabezpieczonych stron. Prosimy dodawać JavaScript w przestrzeni MediaWiki lub jako podstronę strony użytkownika.",
+       "userlogout-continue": "Jeżeli chcesz się wylogować, [$1 przejdź so strony wylogowywania].",
+       "userlogout-sessionerror": "Wylogowywanie nie powiodło się ze względu na błąd związany z sesją. [$1 Spróbuj ponownie]."
 }
index 5f4aa25..fa6cb77 100644 (file)
        "minoreditletter": "c",
        "newpageletter": "N",
        "boteditletter": "t",
-       "number_of_watching_users_pageview": "[tnùa sot-euj da {{PLURAL:$1|n'utent|$1 utent}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|byte}} apress ij cambi",
        "newsectionsummary": "/* $1 */ session neuva",
        "rc-enhanced-expand": "Mostré ij detaj",
        "img-auth-nopathinfo": "PATH_INFO mancant.\nSò servent a l'é nen ampostà për passé costa anformassion.\nPeul desse ch'a sia basà an sij CGI e a peul pa mantnì img_auth.\nVarda https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Ël senté ciamà a l'é pa ant ël dossié configurà për carié.",
        "img-auth-badtitle": "As peul pa fesse un tìtol bon për \"$1\".",
-       "img-auth-nologinnWL": "A l'é pa intrà ant ël sistema e \"$1\" a l'é pa ant la lista bianca.",
        "img-auth-nofile": "L'archivi \"$1\" a esist pa.",
        "img-auth-isdir": "A l'é an camin ch'a preuve a intré ant un dossié \"$1\".\nAs peul mach avèj acess a j'archivi.",
        "img-auth-streaming": "Letura an continuà ëd \"$1\".",
        "allmessagesdefault": "Test che a-i sarìa se a-i fusso pa 'd modìfiche",
        "allmessagescurrent": "Test corent",
        "allmessagestext": "Costa-sì a l'é na lista dij mëssagi ëd sistema disponìbij ant lë spassi nominal MediaWiki.\nPër piasì, ch'a vìsita la [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Localisassion ëd MediaWiki] e [https://translatewiki.net translatewiki.net] se a veul contribuì a la localisassion general ëd MediaWiki.",
-       "allmessagesnotsupportedDB": "Sta pàgina-sì a peul pa esse dovrà përchè '''$wgUseDatabaseMessages''' a l'é stàit disabilità.",
+       "allmessages-not-supported-database": "Sta pàgina-sì a peul pa esse dovrà përchè '''$wgUseDatabaseMessages''' a l'é stàit disabilità.",
        "allmessages-filter-legend": "Filtr",
        "allmessages-filter": "Filtré për stat ëd përsonalisassion:",
        "allmessages-filter-unmodified": "Pa modificà",
index 127ef90..f1d9efb 100644 (file)
        "minoreditletter": "چھوٹا کم",
        "newpageletter": "نواں",
        "boteditletter": "بوٹ",
-       "number_of_watching_users_pageview": "[ $1 ویکھ رہیا اے{{PLURAL:$1|ورتن والا|والے}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|بائٹ|بائٹاں}} تبدیلی مگروں",
        "newsectionsummary": "/* $1 */ نواں پاسہ",
        "rc-enhanced-expand": "تفضیل وکھاؤ (جاوا سکرپٹ چائیدا اے)",
        "img-auth-nopathinfo": "گمی راہ بارے دس۔\nتواڈا سرور ایس جانکاری نوں نئیں گزار سکدا۔\nاے ۓۂـ- بیسد ہوسکدی اے یا تے img_auth نوں سپورٹ کردی اے۔\nویکھو https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization",
        "img-auth-notindir": "پچھیا گیا راہ بنائی گئی ڈائریکٹری چ نئیں اے۔",
        "img-auth-badtitle": "\"$1\" توں اک پکا سرناواں بنان چ ہار",
-       "img-auth-nologinnWL": "تسیں لاگان نئیں ہووے \"$1\"  چٹی لسٹ چ نئیں۔",
        "img-auth-nofile": "فائل \"$1\"  کوئی نئیں ہیگی۔",
        "img-auth-isdir": "تسیں اک ڈائریکٹری \"$1\"  نے جان دی کوشش کر رۓ اوہ۔\nصرف فائل تک جان دی اجازت اے۔",
        "img-auth-streaming": "سٹریمنگ \"$1\"۔",
        "allmessagesdefault": "ڈیفالٹ لکھائی",
        "allmessagescurrent": "موجودہ لکھائی",
        "allmessagestext": "ایہ لسٹ اے پربندھ سنیعیاں دی  جیہڑے میڈیاوکی دی ناں تھاں تے ہیگے نیں۔\nمہربانی کرکے [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] تے [https://translatewiki.net translatewiki.net] تے جاؤ۔\nاگر تسیں میڈیا وکی دے بولی وٹاندرے چ کم کرنا چاندے او۔",
-       "allmessagesnotsupportedDB": "اے صفہ نئیں ورتیا جاسکدا کیوں جے '''$wgUseDatabaseMessages''' روک دتا گیا اے۔",
+       "allmessages-not-supported-database": "اے صفہ نئیں ورتیا جاسکدا کیوں جے '''$wgUseDatabaseMessages''' روک دتا گیا اے۔",
        "allmessages-filter-legend": "فلٹر",
        "allmessages-filter": "کسٹمائزیشن سٹیٹ فلٹر ہوئي:",
        "allmessages-filter-unmodified": "ناں بدلیا گیا",
index 967d74d..650b7d0 100644 (file)
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|nadirīnts tērpautajs|nadirīntei tērpautajai}}]",
        "newsectionsummary": "/* $1 */ naunā sekciōni",
        "rc-enhanced-expand": "Waidinnais malkans (izkīnina JavaScript)",
        "rc-enhanced-hide": "Kliptinais malkans",
        "allmessagesdefault": "Auprestamins teksts",
        "allmessagescurrent": "Bigānts teksts",
        "allmessagestext": "Sta ast listi wisēisan waīstin preiēiminan en MediaWikis tītelin plattibin.\nMadli kāimalukeis [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] be [https://translatewiki.net translatewiki.net] ik tu kwaitēi delīkan īmtun en MediaWikis prōgraminin tulkausnai.",
-       "allmessagesnotsupportedDB": "Šī pāusan ni mazzi būtwei tērpautan, beggi wariābli '''$wgUseDatabaseMessages''' ast izklaūtan.",
+       "allmessages-not-supported-database": "Šī pāusan ni mazzi būtwei tērpautan, beggi wariābli '''$wgUseDatabaseMessages''' ast izklaūtan.",
        "allmessages-filter-legend": "Filtrīs",
        "allmessages-filter": "Filtrīs pa būsenin:",
        "allmessages-filter-unmodified": "Nikitawīdintan",
index 7148e91..7682ba3 100644 (file)
        "revdelete-text-file": "ړنگې شوې بڼې به لا تر اوسه پورې د مخ پېښليک کې ښکاري، خو د هغو ځينو برخو ته به عام خلک لاسرسی و نه لري.",
        "logdelete-text": "ړنگې شوې بڼې به لا تر اوسه پورې د مخ پېښليک کې ښکاري، خو د هغو ځينو برخو ته به عام خلک لاسرسی و نه لري.",
        "revdelete-text-others": "نور پازوالان به لا هم د پټ راز محتوياتو ته لاسرسی ومومي او دا یې له منځه یوسي، مګر که نه بل ډول مشخص شوی.",
-       "revdelete-confirm": "Ù\84Ø·Ù\81ا Ø¯Ø§ ØªØ§Û\8cÛ\8cد Ú©Ú\93ئ Ú\86Û\90 ØªØ§Ø³Ù\88 Ø¯Ø§ Ú©Ø§Ø± Ú©Ù\88Ù\84 ØºÙ\88اÚ\93ئØ\8c Ø¯Ø§ Ú\86Û\90 ØªØ§Ø³Ù\88 Ù¾Ø§Û\8cÙ\84Û\90 Ù¾Ù\87 Ù¾Ø§Ù\85 Ú©Û\90 Ù\84رئ Ø§Ù\88 ØªØ§Ø³Ù\88 Û\8cÛ\90 Ø³Ø±Ù\87 Ù\85طابÙ\82ت Ú©Ù\88ئ[[{{MediaWiki:Policy-url}}|پاÙ\84Û\8cسÛ\8d]].",
+       "revdelete-confirm": "Ù\84Ø·Ù\81ا Ø¯Ø§ ØªØ§Û\8cÛ\8cد Ú©Ú\93ئ Ú\86Û\90 ØªØ§Ø³Ù\88 Ø¯Ø§ Ú©Ø§Ø± Ú©Ù\88Ù\84 ØºÙ\88اÚ\93ئØ\8c ØªØ§Ø³Ù\88 Ù¾Ø§Û\8cÙ\84Û\90 Ù¾Ù\87 Ù¾Ø§Ù\85 Ú©Û\90 Ù\84رئ Ø§Ù\88 [[{{MediaWiki:Policy-url}}|پاÙ\84Û\8cسÛ\8d]] ØªÙ\87 Ù\85Ù\88 Ù\87Ù\85 Ù\81کر Ø¯Û\8c.",
        "revdelete-legend": "د ښکارېدنې محدوديتونه ټاکل",
        "revdelete-hide-text": "د مخکتنې متن",
        "revdelete-hide-image": "د دوتنې مېنځپانگه پټول",
        "rcfilters-filter-editsbyself-description": "ستاسو خپل بدلونونه.",
        "rcfilters-filter-editsbyother-label": "د نورو لخوا بدلونونه",
        "rcfilters-filter-editsbyother-description": "ټول بدلونونه پرته ستاسو له بدلونونو.",
-       "rcfilters-filtergroup-userExpLevel": "د کارن رجسټريشن او تجربه",
+       "rcfilters-filtergroup-user-experience-level": "د کارن رجسټريشن او تجربه",
        "rcfilters-filter-user-experience-level-registered-label": "ثبت شوی",
        "rcfilters-filter-user-experience-level-registered-description": "ننوتلي په سمونو کي.",
        "rcfilters-filter-user-experience-level-unregistered-label": "ناثبت",
        "rcfilters-hideminor-conflicts-typeofchange-global": "\"کوچني تغیرات\" د بدلون فلټرونو د یو یا څو ډولونو سره فلټرونه فلټر کړي، ځکه چې د بدلون ځینې ډولونه \"معمولی\" نه ګڼل کیدی. د منازعې فلټرونه د پورته فعال فلټر په ساحه کې نښه شوي دي.",
        "rcfilters-hideminor-conflicts-typeofchange": "د بدلون ځینې ډولونه نشي کولی \"لږ\" په توګه وټاکل شي، نو دا فلټر د لاندې ډول بدلون سره شخړې لري: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "د بدلون ډول فلټر شخړې د \"کوچنیو ترمیم\" فلټر سره. د بدلون ځینې ډولونه \"کوچنی\" په توګه ندی مشخص کیدی.",
-       "rcfilters-filtergroup-lastRevision": "اوسنۍ بڼې",
+       "rcfilters-filtergroup-lastrevision": "اوسنۍ بڼې",
        "rcfilters-filter-lastrevision-label": "اوسنۍ بڼه",
        "rcfilters-filter-lastrevision-description": "یواځی وروستی بدلون په پاڼه کې.",
        "rcfilters-filter-previousrevision-label": "وروستۍ بڼه نه",
        "newpageletter": "ن",
        "boteditletter": "ر",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1  {{PLURAL:$1|کتونکی کارن|کتونکي کارنان}}]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|بايټ|بايټونه}} د بدلون وروسته",
        "newsectionsummary": "/* $1 */ نوې برخه",
        "allmessagesdefault": "تلواليزه پيغام متن",
        "allmessagescurrent": "اوسنی پيغام متن",
        "allmessagestext": "دا د مېډياويکي په نوم-تشيال کې د غونډال د پيغامونو لړليک دی.\nکه چېرته تاسې د ميډياويکي په ځايتابه کې ونډې ترسره کول غواړۍ نو لطفاً [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation د ميډياويکي ځايتابه] او [https://translatewiki.net translatewiki.net] څخه ليدنه وکړۍ.",
-       "allmessagesnotsupportedDB": "'''Special:Allmessages''' ترېنه کار نه اخيستل کېږي ځکه چې '''$wgUseDatabaseMessages''' مړ دی.",
+       "allmessages-not-supported-database": "'''Special:Allmessages''' ترېنه کار نه اخيستل کېږي ځکه چې '''$wgUseDatabaseMessages''' مړ دی.",
        "allmessages-filter-legend": "چاڼگر",
        "allmessages-filter-unmodified": "نابدلېدلي",
        "allmessages-filter-all": "ټول",
index 857cd83..0bf3cbe 100644 (file)
                        "Ed g2s",
                        "Matěj Suchánek",
                        "Didifelisberto",
-                       "Tks4Fish"
+                       "Tks4Fish",
+                       "Luig"
                ]
        },
        "tog-underline": "Ligação sublinhada:",
        "virus-scanfailed": "a verificação falhou (código $1)",
        "virus-unknownscanner": "antivírus desconhecido:",
        "logouttext": "'''Agora você encontra-se desautenticado.'''\n\nNote que algumas páginas podem continuar sendo exibidas como se você ainda estivesse autenticado até que você limpe a ''cache'' do seu navegador.",
+       "logging-out-notify": "Você está sendo desconectado, por favor aguarde.",
+       "logout-failed": "Não é possível encerrar a sessão agora",
        "cannotlogoutnow-title": "Não é possível encerrar a sessão agora",
        "cannotlogoutnow-text": "Não é possível sair usando $1.",
        "welcomeuser": "Bem-vindo, $1!",
        "page_first": "primeira",
        "page_last": "última",
        "histlegend": "Como selecionar: marque as caixas de seleção das versões que deseja comparar e pressione enter ou clique no botão na parte inferior do formulário.<br />\nLegenda: <strong>({{int:cur}})</strong> = diferenças em relação a última versão, <strong>({{int:last}})</strong> = diferenças em relação a versão anterior, <strong>{{int:minoreditletter}}</strong> = edição menor.",
-       "history-fieldset-title": "Pesquisar revisões",
+       "history-fieldset-title": "Filtrar revisões",
        "history-show-deleted": "Apenas as revisões excluídas",
        "histfirst": "Mais antigas",
        "histlast": "Mais novas",
        "historysize": "({{PLURAL:$1|1 byte|$1 bytes}})",
-       "historyempty": "(vazio)",
+       "historyempty": "vazio",
        "history-feed-title": "Histórico de revisão",
        "history-feed-description": "Histórico de revisões para esta página neste wiki",
        "history-feed-item-nocomment": "$1 em $2",
        "right-reupload-own": "Sobrescrever um arquivo existente enviado pelo mesmo usuário",
        "right-reupload-shared": "Sobrescrever localmente arquivos no repositório partilhado de mídias",
        "right-upload_by_url": "Enviar um arquivo por um URL",
-       "right-purge": "Carregar a cache de uma página no site sem página de confirmação",
+       "right-purge": "Limpar o cache do site para uma página",
        "right-autoconfirmed": "Não ser afetado pelos limites de frequência baseados no número de IP",
        "right-bot": "Ser tratado como um processo automatizado",
        "right-nominornewtalk": "Não ter o aviso de novas mensagens despoletado quando são feitas edições menores a páginas de discussão",
        "action-changetags": "adicionar e remover etiquetas arbitrárias em revisões e ''logs'' individuais",
        "action-deletechangetags": "deletar marcações da base de dados",
        "action-purge": "purgar esta página",
+       "action-apihighlimits": "usar limites mais altos em consultas da API",
+       "action-autoconfirmed": "não ser afetado por limites de taxa baseados em IP",
+       "action-bigdelete": "excluir páginas com grandes históricos",
+       "action-blockemail": "bloquear um usuário de enviar e-mail",
+       "action-bot": "ser tratado como um processo automatizado",
+       "action-editprotected": "editar páginas protegidas como \"{{int:protect-level-sysop}}\"",
+       "action-editsemiprotected": "editar páginas protegidas como \"{{int:protect-level-autoconfirmed}}\"",
+       "action-editinterface": "editar a interface do usuário",
+       "action-editusercss": "editar arquivos CSS de outros usuários",
+       "action-edituserjson": "editar arquivos JSON de outros usuários",
+       "action-edituserjs": "editar arquivos JavaScript de outros usuários",
+       "action-editsitecss": "editar CSS de todo o site",
+       "action-editsitejson": "editar JSON em todo o site",
+       "action-editsitejs": "edite JavaScript em todo o site",
+       "action-editmyusercss": "edite seus próprios arquivos CSS de usuário",
+       "action-editmyuserjson": "editar seus próprios arquivos JSON do usuário",
+       "action-editmyuserjs": "editar seus próprios arquivos JavaScript de usuário",
+       "action-viewsuppressed": "ver revisões ocultas de qualquer usuário",
+       "action-hideuser": "bloquear um nome de usuário, escondendo-o do público",
+       "action-ipblock-exempt": "ignorar bloqueios IP, bloqueios automáticos e bloqueios de alcance",
+       "action-unblockself": "desbloquear a si mesmo",
+       "action-noratelimit": "não ser afetado por limites de taxa",
+       "action-reupload-own": "sobrescrever os arquivos existentes carregados por você",
+       "action-nominornewtalk": "não ter edições menores nas páginas de discussão aciona o novo prompt de mensagens",
+       "action-markbotedits": "marcar edições revertidas como edições de robô",
+       "action-patrolmarks": "ver marcas de patrulha de mudanças recentes",
+       "action-override-export-depth": "Exportar páginas incluindo páginas ligadas até uma profundidade de 5",
+       "action-suppressredirect": "Não crie redirecionamentos de páginas de origem ao mover páginas",
        "nchanges": "$1 {{PLURAL:$1|alteração|alterações}}",
        "ntimes": "$1×",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|desde a última visita}}",
        "rcfilters-savedqueries-already-saved": "Esses filtros já foram salvos. Altere suas configurações para criar um novo Filtro Salvo.",
        "rcfilters-restore-default-filters": "Restaurar filtros padrão",
        "rcfilters-clear-all-filters": "Limpar todos os filtros",
-       "rcfilters-show-new-changes": "Veja as novas mudanças",
+       "rcfilters-show-new-changes": "Ver as novas alterações desde $1",
        "rcfilters-search-placeholder": "Filtrar mudanças (usar o menu ou procurar o nome do filtro)",
        "rcfilters-invalid-filter": "Filtro inválido",
        "rcfilters-empty-filter": "Nenhum filtro ativo. Todas as contribuições são mostradas.",
        "rcfilters-filter-editsbyself-description": "Suas proprias contribuições.",
        "rcfilters-filter-editsbyother-label": "Mudanças de outros",
        "rcfilters-filter-editsbyother-description": "Todas as mudanças, exceto a sua.",
-       "rcfilters-filtergroup-userExpLevel": "Registro e experiência do usuário",
+       "rcfilters-filtergroup-user-experience-level": "Registro e experiência do usuário",
        "rcfilters-filter-user-experience-level-registered-label": "Registrados",
        "rcfilters-filter-user-experience-level-registered-description": "Editores registrados.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Não registrados",
        "rcfilters-hideminor-conflicts-typeofchange-global": "O filtro \"Edições menores\" conflita com um ou mais filtros de Tipo de Alteração, porque certos tipos de alteração não podem ser designadas como \"menores\". Os filtros em conflito estão marcados na área Filtros Ativos, acima.",
        "rcfilters-hideminor-conflicts-typeofchange": "Determinados tipos de alteração não podem ser designados como \"menor\", portanto, este filtro entra em conflito com os seguintes filtros de Tipo de Alteração: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Este filtro de Tipo de Alteração entra em conflito com o filtro \"Edições menores\". Certos tipos de mudança não podem ser designadas como \"menores\".",
-       "rcfilters-filtergroup-lastRevision": "Últimas revisões",
+       "rcfilters-filtergroup-lastrevision": "Últimas revisões",
        "rcfilters-filter-lastrevision-label": "Revisão atual",
        "rcfilters-filter-lastrevision-description": "Somente a mudança mais recente para uma página.",
        "rcfilters-filter-previousrevision-label": "Não é a última revisão",
        "newpageletter": "N",
        "boteditletter": "b",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[{{PLURAL:$1|$1 usuário|$1 usuários}} vigiando]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} após alterações",
        "newsectionsummary": "/* $1 */ nova seção",
        "img-auth-nopathinfo": "Informação do caminho em falta.\nO seu servidor tem de estar configurado para passar as variáveis REQUEST_URI e/ou PATH_INFO.\nSe já está, tente ativar $wgUsePathInfo.\nConsulte https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "O caminho solicitado não está no diretório configurado para envios.",
        "img-auth-badtitle": "Não é possível criar um título válido a partir de \"$1\".",
-       "img-auth-nologinnWL": "Você não está logado e \"$1\" não está na lista branca.",
        "img-auth-nofile": "Arquivo \"$1\" não existe.",
        "img-auth-isdir": "Você está tentando acessar o diretório \"$1\".\nSomente acesso ao arquivo é permitido.",
        "img-auth-streaming": "Realizando ''streaming'' de \"$1\".",
        "enotif_lastvisited": "Consulte $1 para todas as alterações efetuadas desde a sua última visita.",
        "enotif_lastdiff": "Acesse $1 para ver esta alteração.",
        "enotif_anon_editor": "usuário anônimo $1",
-       "enotif_body": "{{GENDER:$WATCHINGUSERNAME|Caro|Cara|Caro(a)}},\n\n$PAGEINTRO $NEWPAGE\n\nResumo do editor: $PAGESUMMARY $PAGEMINOREDIT\n\nContate o editor:\ne-mail: $PAGEEDITOR_EMAIL\nwiki: $PAGEEDITOR_WIKI\n\nAté que visite esta página, você não receberá mais notificações das alterações futuras.\nVocê pode também reativar as notificações para todas páginas na sua lista de páginas vigiadas.\n\nO seu sistema de notificação amigável da {{SITENAME}}\n\n--\nPara alterar as suas preferências das notificações por correio electrônico, visite\n{{canonicalurl:{{#special:Preferences}}}}\n\nPara alterar as suas preferências das páginas vigiadas, visite\n{{canonicalurl:{{#special:EditWatchlist}}}}\n\nPara retirar a página da lista de páginas vigiadas, visite\n$UNWATCHURL\n\nPara comentários e pedidos de ajuda:\n$HELPPAGE",
+       "enotif_body": "{{GENDER:$WATCHINGUSERNAME|Caro|Cara|Caro(a)}},\n\n$PAGEINTRO $NEWPAGE\n\nResumo do editor: $PAGESUMMARY $PAGEMINOREDIT\n\nContate o editor:\ne-mail: $PAGEEDITOR_EMAIL\nwiki: $PAGEEDITOR_WIKI\n\nAté que visite esta página, você não receberá mais notificações das alterações futuras.\nVocê pode também reativar as notificações para todas páginas na sua lista de páginas vigiadas.\n\nO seu sistema de notificação amigável da {{SITENAME}}\n\n--\nPara alterar as suas preferências das notificações por correio eletrônico, visite\n{{canonicalurl:{{#special:Preferences}}}}\n\nPara alterar as suas preferências das páginas vigiadas, visite\n{{canonicalurl:{{#special:EditWatchlist}}}}\n\nPara retirar a página da lista de páginas vigiadas, visite\n$UNWATCHURL\n\nPara comentários e pedidos de ajuda:\n$HELPPAGE",
        "enotif_minoredit": "Esta é uma edição menor",
        "created": "criada",
        "changed": "alterada",
        "delete-confirm": "Eliminar \"$1\"",
        "delete-legend": "Eliminar",
        "historywarning": "<strong>Aviso:</strong> A página que está prestes a eliminar tem um histórico com aproximadamente $1 {{PLURAL:$1|revisão|revisões}}:",
-       "historyaction-submit": "Exibir",
+       "historyaction-submit": "Mostrar revisões",
        "confirmdeletetext": "Encontra-se prestes a eliminar uma página juntamente com todo o seu histórico.\nPor favor, confirme que possui a intenção de fazer isto, que compreende as consequências e que encontra-se a fazer isto de acordo com as [[{{MediaWiki:Policy-url}}|políticas]] do projeto.",
        "actioncomplete": "Ação efetuada com sucesso",
        "actionfailed": "Falha na ação",
        "deleting-backlinks-warning": "'''Cuidado:''' [[Special:WhatLinksHere/{{FULLPAGENAME}}|outras páginas]] ligam ou redirecionam para a página que você está prestes a eliminar.",
        "deleting-subpages-warning": "<strong>Aviso:</strong> A página que você está prestes a excluir tem [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|uma subpágina|$1 subpáginas|51=mais de 50 subpáginas}}]].",
        "rollback": "Reverter edições",
+       "rollback-confirmation-confirm": "Por favor confirme:",
+       "rollback-confirmation-yes": "Reverter",
+       "rollback-confirmation-no": "Cancelar",
        "rollbacklink": "reverter",
        "rollbacklinkcount": "reverter $1 {{PLURAL:$1|edição|edições}}",
        "rollbacklinkcount-morethan": "reverter mais de $1 {{PLURAL:$1|edição|edições}}",
        "revertpage": "Foram revertidas as edições de [[Special:Contributions/$2|$2]] ([[User talk:$2|disc]]) para a última versão por [[User:$1|$1]]",
        "revertpage-nouser": "Revertidas as edições de um usuário oculto para a última revisão de {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Edições revertidas por {{GENDER:$3|$1}};\nalterado para a última revisão por {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Revertidas as edições de $1;\nMudança para a última revisão de $2. [$3 Mostrar alterações]",
        "sessionfailure-title": "Erro de sessão",
        "sessionfailure": "Parece haver um problema com sua sessão de login;\nEsta ação foi cancelada como uma precaução contra o seqüestro de sessão.\nPor favor, reenvie o formulário.",
        "changecontentmodel": "Alterar o modelo de conteúdo de uma página",
        "mycontris": "Contribuições",
        "anoncontribs": "Contribuições",
        "contribsub2": "Para {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "Para {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "A conta de usuário \"$1\" não está registrada.",
        "negative-namespace-not-supported": "Namespaces com valores negativos não são suportados.",
        "nocontribs": "Não foram encontradas mudanças com este critério.",
        "blocklist-userblocks": "Esconder bloqueios de contas",
        "blocklist-tempblocks": "Esconder bloqueios temporários",
        "blocklist-addressblocks": "Esconder bloqueios de IP único",
+       "blocklist-type": "Tipo:",
+       "blocklist-type-opt-all": "Todos",
+       "blocklist-type-opt-sitewide": "Em todo o site",
+       "blocklist-type-opt-partial": "Parcial",
        "blocklist-rangeblocks": "Ocultar bloqueios de faixas",
        "blocklist-timestamp": "Data e hora",
        "blocklist-target": "Destinatário",
        "blocklist-editing-page": "páginas",
        "blocklist-editing-ns": "domínios",
        "ipblocklist-empty": "A lista de bloqueios encontra-se vazia.",
-       "ipblocklist-no-results": "O endereço de IP ou nome de usuário procurado não se encontra bloqueado.",
+       "ipblocklist-no-results": "Nenhum bloqueio correspondente encontrado para o endereço IP ou nome de usuário solicitados.",
        "blocklink": "bloquear",
        "unblocklink": "desbloquear",
        "change-blocklink": "alterar bloqueio",
+       "empty-username": "(sem nome de usuário disponível)",
        "contribslink": "contribs",
        "emaillink": "enviar um e-mail",
        "autoblocker": "Você foi automaticamente bloqueado, pois o seu Endereço IP foi recentemente usado por \"[[User:$1|$1]]\". \nO motivo apresentado para o bloqueio de $1 é: \"$2\".",
        "allmessagesdefault": "Texto padrão",
        "allmessagescurrent": "Texto atual",
        "allmessagestext": "Esta é uma lista de todas as mensagens de sistema disponíveis no espaço nominal {{ns:mediawiki}}.\nAcesse [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] e [https://translatewiki.net translatewiki.net] caso deseje contribuir para traduções do MediaWiki feitas para uso geral.",
-       "allmessagesnotsupportedDB": "Esta página não pode ser utilizada, uma vez que '''$wgUseDatabaseMessages''' foi desativado.",
+       "allmessages-not-supported-database": "Esta página não pode ser utilizada, uma vez que '''$wgUseDatabaseMessages''' foi desativado.",
        "allmessages-filter-legend": "Filtro",
        "allmessages-filter": "Filtrar por estado de personalização:",
        "allmessages-filter-unmodified": "Não modificadas",
        "confirm-unwatch-top": "Remover esta página das páginas vigiadas?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Reverter edições nesta página?",
+       "confirm-rollback-bottom": "Essa ação reverterá instantaneamente as alterações selecionadas para esta página.",
        "confirm-mcrrestore-title": "Restaurar uma revisão",
        "confirm-mcrundo-title": "Desfazer uma mudança",
        "mcrundofailed": "A reversão falhou",
        "passwordpolicies-policyflag-forcechange": "deve mudar no login",
        "passwordpolicies-policyflag-suggestchangeonlogin": "sugerir mudança na entrada",
        "easydeflate-invaliddeflate": "O conteúdo fornecido não está devidamente comprimido",
-       "unprotected-js": "Por razões de segurança o JavaScript não pode ser carregado de páginas desprotegidas. Por favor, crie apenas javascript no MediaWiki: namespace ou como uma subpágina do usuário"
+       "unprotected-js": "Por razões de segurança o JavaScript não pode ser carregado de páginas desprotegidas. Por favor, crie apenas javascript no MediaWiki: namespace ou como uma subpágina do usuário",
+       "userlogout-continue": "Se pretende terminar a sessão [$1 continue para a página de saída], por favor.",
+       "userlogout-sessionerror": "A sua saída falhou devido a um erro da sessão. [$1 Tente novamente], por favor."
 }
index e54a79e..b550dd1 100644 (file)
        "page_first": "primeira",
        "page_last": "última",
        "histlegend": "Seleção de diferenças: use os botões de opção das revisões para marcar as versões que deseja comparar.\nPressione 'Enter' ou clique o botão abaixo.<br />\nLegenda: <strong>({{int:cur}})</strong> = diferenças para a versão atual,\n<strong>({{int:last}})</strong> = diferenças para a versão anterior,\n<strong>{{int:minoreditletter}}</strong> = edição menor.",
-       "history-fieldset-title": "Pesquisar revisões",
+       "history-fieldset-title": "Filtrar revisões",
        "history-show-deleted": "Somente revisões eliminadas",
        "histfirst": "Mais antigas",
        "histlast": "Mais novas",
        "historysize": "({{PLURAL:$1|1 byte|$1 bytes}})",
-       "historyempty": "(vazia)",
+       "historyempty": "vazia",
        "history-feed-title": "Histórico de revisões",
        "history-feed-description": "Histórico de edições para esta página nesta wiki",
        "history-feed-item-nocomment": "$1 em $2",
        "right-reupload-own": "Sobrescrever um ficheiro existente carregado pelo mesmo utilizador",
        "right-reupload-shared": "Sobrescrever localmente ficheiros no repositório partilhado de imagens",
        "right-upload_by_url": "Carregar um ficheiro de um endereço URL",
-       "right-purge": "Limpar a cache de uma página no servidor sem confirmação",
+       "right-purge": "Purgar a cache de uma página no servidor",
        "right-autoconfirmed": "Não ser afetado pelos limites de frequência de edição baseados em endereços IP",
        "right-bot": "Ser tratado como um processo automatizado",
        "right-nominornewtalk": "Não desencadear o aviso de mensagens novas ao fazer edições menores a páginas de discussão",
        "right-importupload": "Importar páginas de um ficheiro xml",
        "right-patrol": "Marcar edições de outros utilizadores como patrulhadas",
        "right-autopatrol": "Ter edições automaticamente marcadas como patrulhadas",
-       "right-patrolmarks": "Usar funcionalidades de patrulhagem das mudanças recentes",
+       "right-patrolmarks": "Ver marcações de patrulhamento das mudanças recentes",
        "right-unwatchedpages": "Ver uma lista de páginas não vigiadas",
        "right-mergehistory": "Fundir o histórico de edições de páginas",
        "right-userrights": "Editar todos os privilégios de utilizador",
        "action-changetags": "adicionar e remover etiquetas arbitrárias em revisões e entradas de registo individuais",
        "action-deletechangetags": "eliminar etiquetas da base de dados",
        "action-purge": "recarregar esta página",
+       "action-apihighlimits": "usar limites superiores nas consultas via API",
+       "action-autoconfirmed": "não ser afetado pelos limites de frequência de edição baseados em endereços IP",
+       "action-bigdelete": "eliminar páginas com um historial grande",
+       "action-blockemail": "impedir um utilizador de enviar correio eletrónico",
+       "action-bot": "ser tratado como um processo automatizado",
+       "action-editprotected": "editar páginas protegidas com \"{{int:protect-level-sysop}}\"",
+       "action-editsemiprotected": "editar páginas protegidas como \"{{int:protect-level-autoconfirmed}}\"",
+       "action-editinterface": "editar a interface de utilizador",
+       "action-editusercss": "editar os ficheiros CSS de outros utilizadores",
+       "action-edituserjson": "editar os ficheiros JSON de outros utilizadores",
+       "action-edituserjs": "editar os ficheiros JavaScript de outros utilizadores",
+       "action-editsitecss": "editar CSS global do ''site''",
+       "action-editsitejson": "editar JSON global do ''site''",
+       "action-editsitejs": "editar JavaScript global do ''site''",
+       "action-editmyusercss": "editar os seus próprios ficheiros CSS de utilizador",
+       "action-editmyuserjson": "editar os seus próprios ficheiros JSON de utilizador",
+       "action-editmyuserjs": "editar os seus próprios ficheiros JavaScript de utilizador",
+       "action-viewsuppressed": "ver revisões ocultadas de todos os utilizadores",
+       "action-hideuser": "bloquear um nome de utilizador, escondendo-o do público",
+       "action-ipblock-exempt": "contornar bloqueios de IP, bloqueios automáticos e bloqueios de gamas de IP",
+       "action-unblockself": "desbloquear-se a si próprio",
+       "action-noratelimit": "não ser afetado pelos limites de frequência de edição",
+       "action-reupload-own": "sobrescrever um ficheiro existente carregado pelo mesmo utilizador",
+       "action-nominornewtalk": "não desencadear o aviso de mensagens novas ao fazer edições menores a páginas de discussão",
+       "action-markbotedits": "marcar edições revertidas como edições de robôs",
+       "action-patrolmarks": "ver marcações de patrulhamento das mudanças recentes",
+       "action-override-export-depth": "exportar páginas incluindo páginas hiperligadas até uma profundidade de 5",
+       "action-suppressredirect": "não criar um redirecionamento do nome antigo quando uma página é movida",
        "nchanges": "$1 {{PLURAL:$1|alteração|alterações}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|desde a última visita}}",
        "enhancedrc-history": "histórico",
        "rcfilters-savedqueries-already-saved": "Estes filtros já foram gravados. Altera as suas configurações para criar um novo filtro gravado.",
        "rcfilters-restore-default-filters": "Restaurar os filtros padrão",
        "rcfilters-clear-all-filters": "Limpar todos os filtros",
-       "rcfilters-show-new-changes": "Mostrar as mudanças mais recentes",
+       "rcfilters-show-new-changes": "Ver novas alterações desde $1",
        "rcfilters-search-placeholder": "Filtrar mudanças (usar o menu ou procurar o nome do filtro)",
        "rcfilters-invalid-filter": "Filtro inválido",
        "rcfilters-empty-filter": "Não há filtros ativos. São mostradas todas as contribuições.",
        "rcfilters-filter-editsbyself-description": "As suas edições.",
        "rcfilters-filter-editsbyother-label": "Mudanças feitas por outros",
        "rcfilters-filter-editsbyother-description": "Todas as mudanças, exceto as feitas por si.",
-       "rcfilters-filtergroup-userExpLevel": "Registo de utilizadores e experiência",
+       "rcfilters-filtergroup-user-experience-level": "Registo de utilizadores e experiência",
        "rcfilters-filter-user-experience-level-registered-label": "Registados",
        "rcfilters-filter-user-experience-level-registered-description": "Editores autenticados.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Não registados",
        "rcfilters-hideminor-conflicts-typeofchange-global": "O filtro \"Edições menores\" entra em conflito com um ou mais filtros de Tipo de Modificação, porque certos tipos de modificações não podem ser classificados como \"menores\". Os filtros em conflito estão marcados na área Filtros Ativos, acima.",
        "rcfilters-hideminor-conflicts-typeofchange": "Certos tipos de modificações não podem ser classificados como \"menores\", portanto este filtro entra em conflito com os seguintes filtros de Tipo de Modificação: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Este filtro de Tipo de Modificação entra em conflito com o filtro \"Edições menores\". Certos tipos de modificações não podem ser classificados como \"menores\".",
-       "rcfilters-filtergroup-lastRevision": "Últimas revisões",
+       "rcfilters-filtergroup-lastrevision": "Últimas revisões",
        "rcfilters-filter-lastrevision-label": "Última revisão",
        "rcfilters-filter-lastrevision-description": "Só a mudança mais recente de uma página.",
        "rcfilters-filter-previousrevision-label": "Excepto a última revisão",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[{{PLURAL:$1|$1 utilizador|$1 utilizadores}} a vigiar]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} após mudança",
        "newsectionsummary": "/* $1 */ nova secção",
        "rc-enhanced-expand": "Mostrar detalhes",
        "img-auth-nopathinfo": "Informação do caminho em falta.\nO seu servidor tem de estar configurado para passar as variáveis REQUEST_URI e/ou PATH_INFO.\nSe já está, tente ativar $wgUsePathInfo.\nConsulte https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "O endereço especificado não conduz ao diretório de carregamento de ficheiros configurado.",
        "img-auth-badtitle": "Não é possível construir um título válido a partir de \"$1\".",
-       "img-auth-nologinnWL": "Não tem a sessão iniciada e o ficheiro \"$1\" não está na lista branca.",
        "img-auth-nofile": "O ficheiro \"$1\" não existe.",
        "img-auth-isdir": "Está a tentar aceder ao diretório \"$1\".\nSó é permitido o acesso a ficheiros.",
        "img-auth-streaming": "A trasmitir \"$1\".",
        "allpagesfrom": "Apresentar páginas desde:",
        "allpagesto": "Apresentar páginas até:",
        "allarticles": "Todas as páginas",
-       "allinnamespace": "Todas as páginas (domínio $1)",
+       "allinnamespace": "Todas as páginas (espaço nominal/domínio $1)",
        "allpagessubmit": "Ver",
        "allpagesprefix": "Apresentar páginas iniciadas por:",
        "allpagesbadtitle": "O título de página fornecido era inválido ou tinha um prefixo interlínguas ou interwikis.\nTalvez contenha um ou mais caracteres que não podem ser usados nos títulos.",
        "trackingcategories-summary": "Esta página lista as categorias de monitorização geradas automaticamente pelo software MediaWiki. Os nomes das categorias podem ser alterados modificando as mensagens de sistema relevantes no domínio {{ns:8}}.",
        "trackingcategories-msg": "Categoria monitorada",
        "trackingcategories-name": "Nome da mensagem",
-       "trackingcategories-desc": "Critérios de inclusão de categoria",
+       "trackingcategories-desc": "Critérios de inclusão da categoria",
        "restricted-displaytitle-ignored": "Páginas com títulos de apresentação ignorados",
        "restricted-displaytitle-ignored-desc": "Esta página tem um <code><nowiki>{{DISPLAYTITLE}}</nowiki></code> ignorado porque não é equivalente ao título verdadeiro da página.",
        "noindex-category-desc": "A página não é indexada por robôs porque contém a palavra mágica <code><nowiki>__NOINDEX__</nowiki></code> e está num espaço nominal onde esta palavra mágica é permitida.",
        "delete-confirm": "Eliminar \"$1\"",
        "delete-legend": "Eliminar",
        "historywarning": "<strong>Aviso:</strong> A página que está prestes a eliminar tem um histórico com aproximadamente $1 {{PLURAL:$1|revisão|revisões}}:",
-       "historyaction-submit": "Mostrar",
+       "historyaction-submit": "Mostrar revisões",
        "confirmdeletetext": "Está prestes a eliminar uma página juntamente com todo o seu histórico.\nConfirme que é realmente esta a sua intenção, que compreende as consequências e que o faz de acordo com as [[{{MediaWiki:Policy-url}}|políticas e recomendações]] do projeto, por favor.",
        "actioncomplete": "Operação executada",
        "actionfailed": "Operação falhou",
        "deleting-backlinks-warning": "<strong>Aviso:</strong> Existem [[Special:WhatLinksHere/{{FULLPAGENAME}}|páginas]] que contêm ligações para a página que está prestes a eliminar ou que a transcluem.",
        "deleting-subpages-warning": "<strong>Aviso:</strong> A página que está prestes a eliminar tem [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|uma subpágina|$1 subpáginas|51=mais de 50 subpáginas}}]].",
        "rollback": "Reverter edições",
+       "rollback-confirmation-confirm": "Confirme, por favor:",
+       "rollback-confirmation-yes": "Reverter",
+       "rollback-confirmation-no": "Cancelar",
        "rollbacklink": "reverter",
        "rollbacklinkcount": "reverter $1 {{PLURAL:$1|edição|edições}}",
        "rollbacklinkcount-morethan": "reverter mais do que $1 {{PLURAL:$1|edição|edições}}",
        "revertpage": "Foram revertidas as edições de [[Special:Contributions/$2|$2]] ([[User talk:$2|disc]]) para a última revisão de [[User:$1|$1]]",
        "revertpage-nouser": "Foram revertidas as edições de um utilizador oculto para a última revisão de {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Foram revertidas as edições de {{GENDER:$3|$1}}; reposta a última edição de {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Revertidas as edições de $1;\nMudança para a última revisão de $2. [$3 Mostrar alterações]",
        "sessionfailure-title": "Erro de sessão",
        "sessionfailure": "Foram detetados problemas com a sua sessão;\na operação foi cancelada como medida de proteção contra a intercetação de sessões.\nReenvie o formulário, por favor.",
        "changecontentmodel": "Alterar modelo de conteúdo de uma página",
        "protect-title-notallowed": "Ver o nível de proteção de \"$1\"",
        "prot_1movedto2": "moveu [[$1]] para [[$2]]",
        "protect-badnamespace-title": "Domínio não passível de proteção",
-       "protect-badnamespace-text": "Páginas neste domínio não podem ser protegidas.",
+       "protect-badnamespace-text": "As páginas neste espaço nominal/domínio não podem ser protegidas.",
        "protect-norestrictiontypes-text": "Esta página não pode ser protegida porque não há nenhum tipo de restrição disponível.",
        "protect-norestrictiontypes-title": "Página não passível de proteção",
        "protect-legend": "Confirmar proteção",
        "undelete-show-file-submit": "Sim",
        "namespace": "Espaço nominal:",
        "invert": "Inverter seleção",
-       "tooltip-invert": "Marque esta caixa para esconder as alterações a páginas no domínio selecionado (e no domínio associado, se escolheu fazê-lo)",
+       "tooltip-invert": "Marque esta caixa para esconder as alterações a páginas no espaço nominal/domínio selecionado (e no espaço nominal/domínio associado, se escolheu fazê-lo)",
        "tooltip-whatlinkshere-invert": "Marque esta caixa de seleção para ocultar ligações de páginas dentro do domínio selecionado.",
        "namespace_association": "Espaço nominal associado",
        "tooltip-namespace_association": "Marque esta caixa para incluir também o domínio de conteúdo ou de discussão associado à sua seleção",
        "mycontris": "Contribuições",
        "anoncontribs": "Contribuições",
        "contribsub2": "Para {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "De {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "A conta de utilizador \"$1\" não está registada.",
        "negative-namespace-not-supported": "Não são suportados espaços nominais com valores negativos.",
        "nocontribs": "Não foram encontradas alterações com este critério.",
        "blocklist-userblocks": "Ocultar bloqueios de contas",
        "blocklist-tempblocks": "Ocultar bloqueios temporários",
        "blocklist-addressblocks": "Ocultar bloqueios de um IP individual",
+       "blocklist-type": "Tipo:",
+       "blocklist-type-opt-all": "Todos",
+       "blocklist-type-opt-sitewide": "Todo o ''site''",
+       "blocklist-type-opt-partial": "Parciais",
        "blocklist-rangeblocks": "Ocultar bloqueios de gamas",
        "blocklist-timestamp": "Data e hora",
        "blocklist-target": "Destinatário",
        "blocklist-editing-page": "páginas",
        "blocklist-editing-ns": "espaços nominais",
        "ipblocklist-empty": "A lista de bloqueios encontra-se vazia.",
-       "ipblocklist-no-results": "O endereço IP ou nome de utilizador procurado não se encontra bloqueado.",
+       "ipblocklist-no-results": "Não foi encontrado nenhum bloqueio correspondente para o endereço IP ou nome de utilizador pedido.",
        "blocklink": "bloquear",
        "unblocklink": "desbloquear",
        "change-blocklink": "alterar bloqueio",
+       "empty-username": "(sem nome de utilizador)",
        "contribslink": "contribs",
        "emaillink": "enviar correio eletrónico",
        "autoblocker": "Foi automaticamente bloqueado, porque o seu endereço IP foi recentemente usado por \"[[User:$1|$1]]\". \nO motivo apresentado para o bloqueio de $1 é: \"$2\".",
        "export-submit": "Exportar",
        "export-addcattext": "Adicionar à lista páginas da categoria:",
        "export-addcat": "Adicionar",
-       "export-addnstext": "Adicionar páginas do domínio:",
+       "export-addnstext": "Adicionar páginas do espaço nominal/domínio:",
        "export-addns": "Adicionar",
        "export-download": "Gravar em ficheiro",
        "export-templates": "Incluir predefinições",
        "allmessagesdefault": "Texto padrão",
        "allmessagescurrent": "Texto atual",
        "allmessagestext": "Esta é a lista das mensagens de sistema disponíveis no domínio MediaWiki.\nSe deseja colaborar na localização genérica do MediaWiki, visite [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] e a [https://translatewiki.net translatewiki.net].",
-       "allmessagesnotsupportedDB": "Esta página não pode ser usada porque a <strong>$wgUseDatabaseMessages</strong> foi desativada.",
+       "allmessages-not-supported-database": "Esta página não pode ser usada porque a <strong>$wgUseDatabaseMessages</strong> foi desativada.",
        "allmessages-filter-legend": "Filtro",
        "allmessages-filter": "Filtrar pelo estado de personalização:",
        "allmessages-filter-unmodified": "Não modificadas",
        "confirm-unwatch-top": "Remover esta página da lista de páginas vigiadas?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Reverter as edições desta página?",
+       "confirm-rollback-bottom": "Essa operação reverterá instantaneamente as mudanças selecionadas desta página.",
        "confirm-mcrrestore-title": "Restaurar uma revisão",
        "confirm-mcrundo-title": "Desfazer uma mudança",
        "mcrundofailed": "A reversão falhou",
        "passwordpolicies-policyflag-forcechange": "deve mudar ao iniciar sessão",
        "passwordpolicies-policyflag-suggestchangeonlogin": "sugerir alteração ao iniciar sessão",
        "easydeflate-invaliddeflate": "O conteúdo fornecido não está devidamente comprimido",
-       "unprotected-js": "Por motivos de segurança o JavaScript de páginas desprotegidas não pode ser carregado. Crie javascript só no espaço nominal/domínio MediaWiki: ou numa subpágina do utilizador"
+       "unprotected-js": "Por motivos de segurança o JavaScript de páginas desprotegidas não pode ser carregado. Crie javascript só no espaço nominal/domínio MediaWiki: ou numa subpágina do utilizador",
+       "userlogout-continue": "Se pretende terminar a sessão [$1 prossiga para a página de saída], por favor.",
+       "userlogout-sessionerror": "A sua saída falhou devido a um erro da sessão. [$1 Tente novamente], por favor."
 }
index 790633b..10fdb84 100644 (file)
                        "The Discoverer",
                        "Bencemac",
                        "Zoranzoki21",
-                       "Woytecr"
+                       "Woytecr",
+                       "PiefPafPier",
+                       "Bagas Chrisara"
                ]
        },
        "sidebar": "{{notranslate}}",
        "tog-norollbackdiff": "Option in [[Special:Preferences]], 'Misc' tab. Only shown for users with the rollback right. By default a diff is shown below the return screen of a rollback. Checking this preference toggle will suppress that. {{Gender}}\n{{Identical|Rollback}}",
        "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-showrollbackconfirmation": "Toggle option used in [[Special:Preferences]] to enable/disable rollback confirmation prompt. Should be visible only to users with rollback rights.",
        "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}}",
        "category-article-count-limited": "This message is displayed at the top of a category page showing the number of pages in the category when not all pages in a category are counted.\n\nParameters:\n* $1 - number of pages shown",
        "category-file-count": "This message is displayed at the top of a category page showing the number of pages in the category.\n\nParameters:\n* $1 – number of files shown\n* $2 – total number of files in category",
        "category-file-count-limited": "This message is displayed at the top of a category page showing the number of pages in the category when not all pages in a category are counted.\n\nParameters:\n* $1 - number of files shown",
-       "listingcontinuesabbrev": "Shown in continuation of each first letter group. This message follows the first letter.\n\nSee http://test.wikipedia.org/wiki/Category:Test_ko?uselang={{SUBPAGENAME}}, for example.",
+       "listingcontinuesabbrev": "Shown in continuation of each first letter group. This message follows the first letter.\n\nThis is an abbreviation of the English word \"continued\". If the word is short in your language, the full stop in the end is not necessary.\n\nSee http://test.wikipedia.org/wiki/Category:Test_ko?uselang={{SUBPAGENAME}}, for example.",
        "index-category": "Name of the [[mw:Special:MyLanguage/Help:Tracking categories|tracking category]] where pages with the <nowiki>__INDEX__</nowiki> behavior switch are listed.\n\nFor description of this behavior switch see [[mw:Special:MyLanguage/Help:Magic_words#Behavior_switches|MediaWiki]].\n\nSee also:\n* {{msg-mw|Index-category-desc}}",
        "noindex-category": "Name of the [[mw:Special:MyLanguage/Help:Tracking categories|tracking category]] where pages with the <nowiki>__NOINDEX__</nowiki> behavior switch are listed.\n\nFor description of this behavior switch see [[mw:Special:MyLanguage/Help:Magic_words#Behavior_switches|MediaWiki]].\n\nSee also:\n* {{msg-mw|Noindex-category-desc}}",
        "broken-file-category": "Name of [[mw:Special:MyLanguage/Help:Tracking categories|tracking category]] where pages that embed files that do not exist (\"broken images\") are listed.\n\nSee also:\n* {{msg-mw|Broken-file-category-desc}}",
        "pool-servererror": "Error message. Parameters:\n* $1 - list of server addresses\n\nSee e.g. {{msg-mw|Poolcounter-desc}} (and the Pool Counter extension in general) for translation hints for “pool counter service”.",
        "poolcounter-usage-error": "Used as error message. Parameters:\n* $1 - non-localized string describing usage mistake.",
        "aboutsite": "Used as the label of the link that appears at the footer of every page on the wiki (in most of  the skins) and leads to the page that contains the site description. The link target is {{msg-mw|aboutpage}}.\n\n[[mw:Manual:Interface/Aboutsite|MediaWiki manual]].\n\n{{doc-important|Do not change <nowiki>{{SITENAME}}</nowiki>.}}\n\n{{Identical|About}}",
-       "aboutpage": "{{doc-important|Do not translate \"Project:\" part, for this is the namespace prefix.}}\n\nUsed as the target of the link that appears at the footer of every page on the wiki (in most of  the skins) and leads to the page that contains the site description. Therefore the content should be the same with the page name of the site description page. Only the message in the [[mw:Manual:$wgLanguageCode|site language]]  ([[MediaWiki:Aboutpage]]) is used. The link label is {{msg-mw|aboutsite}}.",
+       "aboutpage": "{{doc-important|Do not translate \"Project:\" part, for this is the namespace prefix.}}\n\nDo translate \"About\", however.\n\nUsed as the target of the link that appears at the footer of every page on the wiki (in most of  the skins) and leads to the page that contains the site description. Therefore the content should be the same with the page name of the site description page. Only the message in the [[mw:Manual:$wgLanguageCode|site language]]  ([[MediaWiki:Aboutpage]]) is used. The link label is {{msg-mw|aboutsite}}.",
        "copyright": "Parameters:\n* $1 - license name\n'''See also'''\n* {{msg-mw|Mobile-frontend-copyright}}",
        "copyrightpage": "{{doc-important|Do not change <nowiki>{{ns:project}}</nowiki>}}\n\n{{Identical|Copyright}}",
        "currentevents": "Standard link in the sidebar, for news.\n\nSee also {{msg-mw|Currentevents-url}} for the link URL.\n\nSee also:\n* {{msg-mw|Currentevents}}\n* {{msg-mw|Accesskey-n-currentevents}}\n* {{msg-mw|Tooltip-n-currentevents}}",
        "virus-scanfailed": "Used as error message. \"scan\" stands for \"virus scan\". Parameters:\n* $1 - exit code of virus scanner",
        "virus-unknownscanner": "Used as error message. This message is followed by the virus scanner name.",
        "logouttext": "Log out message. Parameters:\n* $1 - (Unused) an URL to [[Special:Userlogin]] containing <code>returnto</code> and <code>returntoquery</code> parameters",
+       "logging-out-notify": "The message when the user is being logged out",
+       "logout-failed": "Message when log out fails in notification popup. Parameters:\n* $1 - Error message",
        "cannotlogoutnow-title": "Error page title shown when logging out is not possible.",
        "cannotlogoutnow-text": "Error page text shown when logging out is not possible. Parameters:\n* $1 - Session type in use that makes it not possible to log out, from a message like {{msg-mw|sessionprovider-mediawiki-session-cookiesessionprovider}}.",
        "welcomeuser": "Text for a welcome heading that users see after registering a user account.\n\nParameters:\n* $1 - the username of the new user. See [[phab:T44215]]",
        "page_first": "This is part of the navigation message on the top and bottom of Special pages which are lists of things in alphabetical order, e.g. the '[[Special:Categories|Categories]]' special page. It is followed by the message {{msg-mw|Viewprevnext}}.\n{{Identical|First}}",
        "page_last": "This is part of the navigation message on the top and bottom of Special pages which are lists of things in alphabetical order, e.g. the '[[Special:Categories|Categories]]' special page. It is followed by the message {{msg-mw|Viewprevnext}}.\n\n{{Identical|Last}}",
        "histlegend": "Text in history page.\n\nSee also:\n* {{msg-mw|Cur}}\n* {{msg-mw|Last}}\n* {{msg-mw|Minoreditletter}}",
-       "history-fieldset-title": "Fieldset label in the edit history pages.",
+       "history-fieldset-title": "Form legend label in the edit history page.",
        "history-show-deleted": "CheckBox to show only per [[mw:Manual:RevisionDelete|RevisionDelete]] deleted versions.\n\nUsed in History and [[Special:Contributions]].",
        "history_copyright": "{{notranslate}}",
        "histfirst": "This is part of the navigation message on the top and bottom of Page History pages which are lists of things in date order, e.g. [{{canonicalurl:Support|action=history}} Page History of Support].\n\nIt is followed by the message {{msg-mw|Viewprevnext}}.\n{{Identical|Oldest}}",
        "right-reupload-own": "{{doc-right|reupload-own}}\nRight to upload a file under a file name that already exists, and that the same user has uploaded.\n\nRelated messages:\n* {{msg-mw|right-upload}}\n* {{msg-mw|right-reupload}}",
        "right-reupload-shared": "{{doc-right|reupload-shared}}\nThe right to upload a file locally under a file name that already exists in a shared database (for example Commons).\n\nRelated messages:\n* {{msg-mw|right-upload}}\n* {{msg-mw|right-reupload}}",
        "right-upload_by_url": "{{doc-right|upload_by_url}}",
-       "right-purge": "{{doc-right|purge}}\nThe right to use <code>&action=purge</code> in the URL, without needing to confirm it (by default, anonymous users need to confirm it).",
+       "right-purge": "{{doc-right|purge}}\nThe right to use <code>&action=purge</code> in the URL.",
        "right-autoconfirmed": "{{doc-right|autoconfirmed}}\nIf your account is older than [[mw:Manual:$wgAutoConfirmAge|wgAutoConfirmAge]] and if you have at least [[mw:Manual:$wgAutoConfirmCount|$wgAutoConfirmCount]] edits, you are in the '''group \"autoconfirmed\"''' (note that you can't see this group at [[Special:ListUsers]]).\nIf you are in that group, you have (by default) the '''right \"autoconfirmed\"''', which exempts you from certain rate limits (those based on your IP address or otherwise intended solely for new users). Other rate limits may still apply; see {{msg-mw|right-noratelimit}}.",
        "right-bot": "{{doc-right|bot}}",
        "right-nominornewtalk": "{{doc-right|nominornewtalk}}\nIf someone with this right (bots by default) edits a user talk page and marks it as minor (requires {{msg-mw|right-minoredit}}), the user will not get a notification \"You have new messages\".",
        "action-changetags": "{{doc-action|changetags}}",
        "action-deletechangetags": "{{doc-action|deletechangetags}}",
        "action-purge": "{{doc-action|purge}}",
+       "action-apihighlimits": "{{doc-action|apihighlimits}}",
+       "action-autoconfirmed": "{{doc-action|autoconfirmed}}",
+       "action-bigdelete": "{{doc-action|bigdelete}}",
+       "action-blockemail": "{{doc-action|blockemail}}",
+       "action-bot": "{{doc-action|bot}}",
+       "action-editprotected": "{{doc-action|editprotected}}",
+       "action-editsemiprotected": "{{doc-action|editsemiprotected}}",
+       "action-editinterface": "{{doc-action|editinterface}}",
+       "action-editusercss": "{{doc-action|editusercss}}",
+       "action-edituserjson": "{{doc-action|edituserjson}}",
+       "action-edituserjs": "{{doc-action|edituserjs}}",
+       "action-editsitecss": "{{doc-action|editsitecss}}",
+       "action-editsitejson": "{{doc-action|editsitejson}}",
+       "action-editsitejs": "{{doc-action|editsitejs}}",
+       "action-editmyusercss": "{{doc-action|editmyusercss}}",
+       "action-editmyuserjson": "{{doc-action|editmyuserjson}}",
+       "action-editmyuserjs": "{{doc-action|editmyuserjs}}",
+       "action-viewsuppressed": "{{doc-action|viewsuppressed}}",
+       "action-hideuser": "{{doc-action|hideuser}}",
+       "action-ipblock-exempt": "{{doc-action|ipblock-exempt}}",
+       "action-unblockself": "{{doc-action|unblockself}}",
+       "action-noratelimit": "{{doc-action|noratelimit}}",
+       "action-reupload-own": "{{doc-action|reupload-own}}",
+       "action-nominornewtalk": "{{doc-action|nominornewtalk}}",
+       "action-markbotedits": "{{doc-action|markbotedits}}",
+       "action-patrolmarks": "{{doc-action|patrolmarks}}",
+       "action-override-export-depth": "{{doc-action|override-export-depth}}",
+       "action-suppressredirect": "{{doc-action|suppressredirect}}",
        "nchanges": "Appears on enhanced watchlist and recent changes when page has more than one change on given date, linking to a diff of the changes.\n\nParameters:\n* $1 - the number of changes on that day (2 or more)\nThree messages are shown side-by-side: ({{msg-mw|Nchanges}} | {{msg-mw|Enhancedrc-since-last-visit}} | {{msg-mw|Enhancedrc-history}}).",
        "ntimes": "Used to indicate how many times an event occurred (eg. on enhanced recent change when a user did more than one change to the page). Parameters:\n* $1 - number (integer)",
        "enhancedrc-since-last-visit": "Appears on enhanced watchlist and recent changes when page has more than one change on given date and at least one that the user hasn't seen yet, linking to a diff of the unviewed changes.\n\nParameters:\n* $1 - the number of unviewed changes (1 or more)\nThree messages are shown side-by-side: ({{msg-mw|nchanges}} | {{msg-mw|enhancedrc-since-last-visit}} | {{msg-mw|enhancedrc-history}}).",
        "rcfilters-activefilters-show-tooltip": "Tooltip for the button that shows the active filters list and dropdown in [[Special:RecentChanges]].",
        "rcfilters-advancedfilters": "Title for the buttons allowing the user to switch to the various advanced filters views.",
        "rcfilters-limit-title": "Title for the options to change the number of results shown.",
-       "rcfilters-limit-and-date-label": "Title for the button that opens the operation to control how many results to show and in which time period to search. \n\nParameters: $1 - Number of results shown\n\n$2 - Time period to search. One of {{msg-mw|rcfilters-days-title}} or {{msg-mw|rcfilters-hours-title}} is used as $2\n{{Identical|Change}}",
+       "rcfilters-limit-and-date-label": "Title for the button that opens the operation to control how many results to show and in which time period to search. \n\nParameters: $1 - Number of results shown\n\n$2 - Time period to search. One of {{msg-mw|Rcfilters-days-show-days}} or {{msg-mw|Rcfilters-days-show-hours}} is used as $2\n{{Identical|Change}}",
        "rcfilters-date-popup-title": "Section title of date options on recent changes results",
        "rcfilters-days-title": "Title for the options to change the number of days for the results shown.",
        "rcfilters-hours-title": "Title for the options to change the number of hours for the results shown.",
        "rcfilters-savedqueries-already-saved": "Title for the popup in [[Special:RecentChanges]] that indicates that current set of filters is already saved. This is for a small popup, please try to use a short string.",
        "rcfilters-restore-default-filters": "Label for the button that resets filters to defaults",
        "rcfilters-clear-all-filters": "Title for the button that clears all filters",
-       "rcfilters-show-new-changes": "Label for the button to show new changes.",
+       "rcfilters-show-new-changes": "Label for the button to show new changes. Parameters:\n* $1 - timestamp from which new changes are available. It indicates that clicking the refresh link will bring changes newer than (or equal to) this timestamp. It is formatted according to the user's date, time and timezone preferences",
        "rcfilters-search-placeholder": "Placeholder for the filter search input. The first \"Filter\" is a verb, and the second \"filter\" is a noun.",
        "rcfilters-invalid-filter": "A label for an invalid filter.",
        "rcfilters-empty-filter": "Placeholder for the filter list when no filters were chosen.",
        "rcfilters-filter-editsbyself-description": "Description for the filter for showing edits made by the current user.",
        "rcfilters-filter-editsbyother-label": "Label for the filter for showing edits made by anyone other than the current user.",
        "rcfilters-filter-editsbyother-description": "Description for the filter for showing edits made by anyone other than the current user.",
-       "rcfilters-filtergroup-userExpLevel": "Title for the filter group for user experience levels.",
+       "rcfilters-filtergroup-user-experience-level": "Title for the filter group for user experience levels.",
        "rcfilters-filter-user-experience-level-registered-label": "Label for the filter for showing edits made by logged-in editors.",
        "rcfilters-filter-user-experience-level-registered-description": "Description for the filter for showing edits made by logged-in editors.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Label for the filter for showing edits made by anonymous editors.",
        "rcfilters-hideminor-conflicts-typeofchange-global": "The \"Minor edits\" filter is conflicting with one or more Type of Change filters, because certain types of change cannot be designated as \"minor.\" The conflicting filters are marked in the Active Filters area, above.\n\n\"Type of Change\" is {{msg-mw|Rcfilters-filtergroup-changetype}}.",
        "rcfilters-hideminor-conflicts-typeofchange": "Tooltip shown when hovering over the Minor edits tag, when a Type of Change filter is also selected.\n\n\"Minor edits\" is {{msg-mw|rcfilters-filter-minor-label}}.\n\n\"Type of change\" is {{msg-mw|rcfilters-filtergroup-changetype}}.\n\nThis indicates that no results will be shown.  Parameters:\n* $1 - Comma-separated string of selected Type of Change filters, e.g. \"Category, Logged Actions\"\n* $2 - Count of selected User Experience Level filters, for PLURAL",
        "rcfilters-typeofchange-conflicts-hideminor": "Tooltip shown when hovering over a Type of change filter tag, when the Minor edits filter is also selected.\n\n\"Minor edits\" is {{msg-mw|rcfilters-filter-minor-label}}.\n\n\"Type of change\" is {{msg-mw|rcfilters-filtergroup-changetype}}.\n\nThis indicates that no results will be shown.",
-       "rcfilters-filtergroup-lastRevision": "Title for the filter group for last revision",
+       "rcfilters-filtergroup-lastrevision": "Title for the filter group for last revision",
        "rcfilters-filter-lastrevision-label": "Title for the filter for showing changes on last revision of a page.",
        "rcfilters-filter-lastrevision-description": "Description for the filter for showing changes on last revision of a page.",
        "rcfilters-filter-previousrevision-label": "Title for the filter for showing changes on previous revisions of a page.",
        "hist": "Short form of \"history\". Used on [[Special:RecentChanges]], [[Special:Watchlist]], ...",
        "hide": "{{doc-actionlink}}\nOption text in [[Special:RecentChanges]], and in [[Special:WhatLinksHere]].\n\nSee also:\n* {{msg-mw|Show}}\n{{Identical|Hide}}",
        "show": "{{doc-actionlink}}\nOption text in [[Special:RecentChanges]], and in [[Special:WhatLinksHere]].\n\nSee also:\n* {{msg-mw|Hide}}\n{{Identical|Show}}",
-       "minoreditletter": "Very short form of \"'''minor edit'''\". Used in [[Special:RecentChanges]], [[Special:Watchlist]], [[Special:Contributions]] and history pages. This should be a single letter.",
-       "newpageletter": "Very short form of \"'''new page'''\". Used in [[Special:RecentChanges]], [[Special:Watchlist]] and [[Special:Contributions]]. This should be a single letter.",
-       "boteditletter": "Abbreviation of \"'''bot'''\". Appears in [[Special:RecentChanges]] and [[Special:Watchlist]]. This should be a single letter.",
-       "unpatrolledletter": "{{optional}}\n\nUsed in {{msg-mw|Recentchanges-label-legend}}, meaning \"unpatrolled\".",
-       "number_of_watching_users_RCview": "{{notranslate}}\nParameters:\n* $1 - number of users who are watching",
-       "number_of_watching_users_pageview": "Used if <code>$wgPageShowWatchingUsers</code> is true.\n* $1 - number of watching user(s)",
+       "minoreditletter": "Very short form of \"'''minor edit'''\". Used in [[Special:RecentChanges]], [[Special:Watchlist]], [[Special:Contributions]] and history pages.\n\n{{Rc single letters}}",
+       "newpageletter": "Very short form of \"'''new page'''\". Used in [[Special:RecentChanges]], [[Special:Watchlist]] and [[Special:Contributions]].\n\n{{Rc single letters}}",
+       "boteditletter": "Abbreviation of \"'''bot'''\". Appears in [[Special:RecentChanges]] and [[Special:Watchlist]].\n\n{{Rc single letters}}",
+       "unpatrolledletter": "{{optional}}\n\nUsed in {{msg-mw|Recentchanges-label-legend}}, meaning \"unpatrolled\".\n\n{{Rc single letters}}",
+       "number-of-watching-users-for-recent-changes": "{{notranslate}}\nParameters:\n* $1 - number of users who are watching",
        "rc-change-size": "{{optional}}\nDoes not work under $wgMiserMode ([[mwr:48986|r48986]]).\n\nParameters:\n* $1 - size of diff",
        "rc-change-size-new": "Tooltip when hovering a change list diff size. Parameters:\n* $1 - the resulting new size (in bytes)",
        "newsectionsummary": "Default summary when adding a new section to a page. Parameters:\n* $1 - section title",
        "img-auth-nopathinfo": "[[mw:Manual:Image Authorization|Manual:Image Authorization]]: Missing PATH_INFO - see english description\n{{Doc-important|This is plain text. Do not use any wiki syntax.}}",
        "img-auth-notindir": "[[mw:Manual:Image Authorization|Manual:Image Authorization]]: When the specified path is not in upload directory.",
        "img-auth-badtitle": "[[mw:Manual:Image Authorization|Manual:Image Authorization]]: Bad title, $1 is the invalid title",
-       "img-auth-nologinnWL": "[[mw:Manual:Image Authorization|Manual:Image Authorization]]: Logged in and file not whitelisted.  $1 is the file not in whitelist.",
        "img-auth-nofile": "[[mw:Manual:Image Authorization|Manual:Image Authorization]]: Non existent file, $1 is the file that does not exist.",
        "img-auth-isdir": "[[mw:Manual:Image Authorization|Manual:Image Authorization]]: Trying to access a directory instead of a file, $1 is the directory.",
        "img-auth-streaming": "[[mw:Manual:Image Authorization|Manual:Image Authorization]]: Is now streaming file specified by $1.",
        "upload-curl-error28": "See also:\n* {{msg-mw|Upload-curl-error28|title}}\n* {{msg-mw|Upload-curl-error28-text|body}}",
        "upload-curl-error28-text": "See also:\n* {{msg-mw|Upload-curl-error28|title}}\n* {{msg-mw|Upload-curl-error28-text|body}}",
        "license": "This appears in the upload form for the license drop-down. The header in the file description page is now at {{msg-mw|License-header}}.\n{{Identical|Licensing}}",
-       "license-header": "Used as section header in [[Special:Upload]].\n\nSee also:\n* {{msg-mw|Filedesc}}\n* {{msg-mw|Filestatus}}\n* {{msg-mw|Filesource}}\n{{Identical|Licensing}}",
+       "license-header": "Digunakan sebagai tajuk bagian pada [[Istimewa:Pengunggahan]].\n\nLihat pula:\n* {{msg-mw|Filedesc}}\n* {{msg-mw|Filestatus}}\n* {{msg-mw|Filesource}}\n{{Identical|Lisensi}}",
        "nolicense": "{{Identical|None selected}}",
        "licenses": "{{notranslate}}",
        "licenses-edit": "Label text for a link on Special:Upload to edit MediaWiki:Licenses",
        "delete-confirm": "Used as page title. Parameters:\n* $1 - the page title\n{{Identical|Delete}}",
        "delete-legend": "{{Identical|Delete}}",
        "historywarning": "Warning when about to delete a page that has history.\n\nFollowed by a link which points to the history page.\n\nParameters:\n* $1 - the number of revisions that the page has",
-       "historyaction-submit": "Submit button on history pages\n{{Identical|Show}}",
+       "historyaction-submit": "Submit button to show revisions on revision history pages",
        "confirmdeletetext": "Introduction shown when deleting a page.\n\nRefers to {{msg-mw|Policy-url}}.",
        "actioncomplete": "Used in several situations, for example when a page has been deleted.\n\nSee also:\n* {{msg-mw|Actionfailed|page title}}",
        "actionfailed": "Used as page title when the submit operation failed, in [[Special:RevisionDelete]].\n\nSee also:\n* {{msg-mw|Actioncomplete|page title}}",
        "deleting-backlinks-warning": "A warning shown when a page that is being deleted has at least one link to it or is transcluded in at least one page.",
        "deleting-subpages-warning": "A warning shown when a page that is being deleted has at least one subpage. $1 is the number of subpages of the page. For any number of subpages over 50, $1 will be 51.\nSee also:\n* {{msg-mw|Deleting-backlinks-warning}}",
        "rollback": "{{Identical|Rollback}}",
+       "rollback-confirmation-confirm": "Prompt which asks the user to confirm that they want to really perform the rollback action after clicking on the rollback button.",
+       "rollback-confirmation-yes": "Button text to confirm that a rollback should be executed.",
+       "rollback-confirmation-no": "Button text to cancel a rollback instead of executing it.\n{{Identical|Cancel}}",
        "rollbacklink": "{{Doc-actionlink}}\nThis link text appears on the recent changes page to users who have the \"rollback\" right.\nThis message has a tooltip {{msg-mw|tooltip-rollback}}\n{{Identical|Rollback}}",
-       "rollbacklinkcount": "{{doc-actionlink}}\nText of the rollback link showing the number of edits to be rolled back. See also {{msg-mw|rollbacklink}}.\n\nParameters:\n* $1 - the number of edits that will be rolled back. If $1 is over the value of <code>$wgShowRollbackEditCount</code> (default: 10) {{msg-mw|rollbacklinkcount-morethan}} is used.\n\nThe rollback link is displayed with a tooltip {{msg-mw|Tooltip-rollback}}",
+       "rollbacklinkcount": "{{doc-actionlink}}\nText of the rollback link showing the number of edits to be rolled back. The word \"rollback\" is supposed to be the same as in {{msg-mw|rollbacklink}}.\n\nParameters:\n* $1 - the number of edits that will be rolled back. If $1 is over the value of <code>$wgShowRollbackEditCount</code> (default: 10) {{msg-mw|rollbacklinkcount-morethan}} is used.\n\nThe rollback link is displayed with a tooltip {{msg-mw|Tooltip-rollback}}",
        "rollbacklinkcount-morethan": "{{doc-actionlink}}\nText of the rollback link when a greater number of edits is to be rolled back. See also {{msg-mw|rollbacklink}}.\n\nWhen the number of edits rolled back is smaller than [[mw:Special:MyLanguage/Manual:$wgShowRollbackEditCount|$wgShowRollbackEditCount]], {{msg-mw|rollbacklinkcount}} is used instead.\n\nParameters:\n* $1 - number of edits",
        "rollbackfailed": "{{Identical|Rollback}}",
        "rollback-missingparam": "Used as error message that rollback is accessed without the required parameters\n\nSee also:\n* {{msg-mw|Rollbackfailed}}",
        "revertpage": "Parameters:\n* $1 - username 1\n* $2 - username 2\n* $3 - (Optional) revision ID of the revision reverted to\n* $4 - (Optional) timestamp of the revision reverted to\n* $5 - (Optional) revision ID of the revision reverted from\n* $6 - (Optional) timestamp of the revision reverted from\nSee also:\n* {{msg-mw|Revertpage-nouser}}\n{{Identical|Revert}}",
        "revertpage-nouser": "This is a confirmation message a user sees after reverting, when the username of the version is hidden with RevisionDelete.\n\nIn other cases the message {{msg-mw|Revertpage}} is used.\n\nParameters:\n* $1 - username 1, can be used for GENDER\n* $2 - (Optional) username 2\n* $3 - (Optional) revision ID of the revision reverted to\n* $4 - (Optional) timestamp of the revision reverted to\n* $5 - (Optional) revision ID of the revision reverted from\n* $6 - (Optional) timestamp of the revision reverted from",
        "rollback-success": "This message shows up on screen after successful revert (generally visible only to admins). Parameters:\n* $1 - user whose changes have been reverted\n* $2 - user who produced version, which replaces reverted version\n* $3 - the first user's name, can be used for GENDER\n* $4 - the second user's name, can be used for GENDER\n{{Identical|Revert}}\n{{Identical|Rollback}}",
-       "rollback-success-notify": "Notification shown after a successful revert.\n* $1 - User whose changes have been reverted\n* $2 - User that made the edit that was restored\n* $3 - Url to the diff of the rollback\nSee also:\n* {{msg-mw|showdiff}}\n{{related|rollback-success}}\n{{Format|jquerymsg}}",
        "sessionfailure-title": "Used as title of the error message {{msg-mw|Sessionfailure}}.",
        "sessionfailure": "Used as error message.\n\nThe title for this error message is {{msg-mw|Sessionfailure-title}}.",
        "changecontentmodel": "Title of the change content model special page",
        "mycontris": "In the personal urls page section - right upper corner.\n\nSee also:\n* {{msg-mw|Mycontris}}\n* {{msg-mw|Accesskey-pt-mycontris}}\n* {{msg-mw|Tooltip-pt-mycontris}}\n{{Identical|Contribution}}",
        "anoncontribs": "Same as {{msg-mw|mycontris}} but used for non-logged-in users.\n\nSee also:\n* {{msg-mw|Accesskey-pt-anoncontribs}}\n* {{msg-mw|Tooltip-pt-anoncontribs}}\n{{Identical|Contribution}}",
        "contribsub2": "Contributions for \"user\" (links). Parameters:\n* $1 is an IP address or a username, with a link which points to the user page (if registered user).\n* $2 is list of tool links. The list contains a link which has text {{msg-mw|Sp-contributions-talk}}.\n* $3 is a plain text username used for GENDER.\n{{Identical|For $1}}",
+       "contributions-subtitle": "Successor to {{msg-mw|contribsub2}}. Contributions for \"user\". Parameters:\n* $1 is an IP address or a username, with a link which points to the user page (if registered user).",
        "contributions-userdoesnotexist": "This message is used in [[Special:Contributions]]. It is used to tell the user that the name he searched for doesn't exist.\n\nParameters:\n* $1 - a username\n{{Identical|Userdoesnotexist}}",
        "negative-namespace-not-supported": "This message is used in [[Special:Contributions]] to tell users that use namespaces with negative value. It not supported as associated namespace(s) doesn't exist.",
        "nocontribs": "Used in [[Special:Contributions]] and [[Special:DeletedContributions]].\n\nSee examples: [[Special:Contributions/x]] and [[Special:DeletedContributions/x]].\n\nParameters:\n* $1 - (Unused) the user name",
        "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-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}}",
+       "blocklist-type-opt-sitewide": "Used as option for dropdown box in [[Special:BlockList]]. This option indicates that only \"sitewide\" blocks will be listed.",
+       "blocklist-type-opt-partial": "Used as option for dropdown box in [[Special:BlockList]]. This option indicates that only \"partial\" blocks will be listed.",
        "blocklist-rangeblocks": "Used as the label for the multi-select checkbox in the form on [[Special:BlockList]].\n\nFor an explanation of \"range blocks\", see [[mw:Help:Range_blocks]]\n{{Related|Blocklist-blocks}}",
        "blocklist-timestamp": "This is a column header for dates and times in the table on the page [[Special:BlockList]].\n{{Identical|Timestamp}}",
        "blocklist-target": "The table header for the column containing the block targets, that is user names or IP-addresses linked to their respective user pages, in the table on the page [[Special:BlockList]].\n{{Identical|Target}}",
        "blocklink": "Display name for a link that, when selected, leads to a form where a user can be blocked. Used in page history and recent changes pages. Example: \"''UserName (Talk | contribs | '''block''')''\".\n\nUsed as link title in [[Special:Contributions]] and in [[Special:DeletedContributions]].\n\nSee also:\n* {{msg-mw|Sp-contributions-talk}}\n* {{msg-mw|Change-blocklink}}\n* {{msg-mw|Unblocklink}}\n* {{msg-mw|Sp-contributions-blocklog}}\n* {{msg-mw|Sp-contributions-uploads}}\n* {{msg-mw|Sp-contributions-logs}}\n* {{msg-mw|Sp-contributions-deleted}}\n* {{msg-mw|Sp-contributions-userrights}}\n{{Identical|Block}}",
        "unblocklink": "Used as link title in [[Special:Contributions]] and in [[Special:DeletedContributions]].\n\nSee also:\n* {{msg-mw|Sp-contributions-talk}}\n* {{msg-mw|change-blocklink}}\n* {{msg-mw|blocklink}}\n* {{msg-mw|sp-contributions-blocklog}}\n* {{msg-mw|sp-contributions-uploads}}\n* {{msg-mw|sp-contributions-logs}}\n* {{msg-mw|sp-contributions-deleted}}\n* {{msg-mw|sp-contributions-userrights}}\n{{Identical|Unblock}}",
        "change-blocklink": "Used to name the link on [[Special:Log]].\n\nAlso used as link title in [[Special:Contributions]] and in [[Special:DeletedContributions]].\n\nSee also:\n* {{msg-mw|Sp-contributions-talk}}\n* {{msg-mw|unblocklink}}\n* {{msg-mw|blocklink}}\n* {{msg-mw|sp-contributions-blocklog}}\n* {{msg-mw|sp-contributions-uploads}}\n* {{msg-mw|sp-contributions-logs}}\n* {{msg-mw|sp-contributions-deleted}}\n* {{msg-mw|sp-contributions-userrights}}",
+       "empty-username": "If no username is available to display for a log or history entry, such as because of an incorrect database entry, this message is displayed in place of the links to the user page/talk/contribs/etc.",
        "contribslink": "Short for \"contributions\". Used as display name for a link to user contributions on history pages, [[Special:RecentChanges]], [[Special:Watchlist]], etc.\n{{Identical|Contribution}}",
        "emaillink": "Used as display name for a link to send an e-mail to a user in the user tool links. Example: \"(Talk | contribs | block | send e-mail)\".\n\n{{Identical|E-mail}}",
        "autoblocker": "Used in [[Special:Block]].\n* $1 - target username\n* $2 - reason",
        "allmessagesdefault": "The header for the lower row of each column in the table of [[Special:AllMessages]].",
        "allmessagescurrent": "The header for the upper row of each column in the table of [[Special:AllMessages]].",
        "allmessagestext": "Summary displayed at the top of [[Special:AllMessages]].",
-       "allmessagesnotsupportedDB": "This message is displayed on [[Special:AllMessages]] on wikis were the configuration variable $wgUseDatabaseMessages is disabled. It means that the MediaWiki namespace is not used.",
+       "allmessages-not-supported-database": "This message is displayed on [[Special:AllMessages]] on wikis were the configuration variable $wgUseDatabaseMessages is disabled. It means that the MediaWiki namespace is not used.",
        "allmessages-filter-legend": "Used in [[Special:AllMessages]].\n\n{{Identical|Filter}}",
        "allmessages-filter": "Option used in [[Special:AllMessages]].",
        "allmessages-filter-unmodified": "Used in [[Special:AllMessages]].",
        "tooltip-watchlistedit-raw-submit": "Tooltip for {{msg-mw|watchlistedit-raw-submit}} (used as button on [[Special:EditWatchlist/raw]]).\n\nSee also:\n* {{msg-mw|Watchlistedit-raw-submit}}\n* {{msg-mw|Accesskey-watchlistedit-raw-submit}}\n* {{msg-mw|Tooltip-watchlistedit-raw-submit}}",
        "tooltip-recreate": "Used as tooltip for Recreate link.\n\nSee also:\n* {{msg-mw|Recreate}}\n* {{msg-mw|Tooltip-recreate}}",
        "tooltip-upload": "Used as tooltip for Upload button.\n\nSee also:\n* {{msg-mw|Uploadbtn}}\n* {{msg-mw|Accesskey-upload}}\n* {{msg-mw|Tooltip-upload}}",
-       "tooltip-rollback": "Tooltip of the rollback link on the history page and the diff view {{msg-mw|rollbacklinkcount}}\n{{Identical|Rollback}}\n{{Identical|Revert}}",
+       "tooltip-rollback": "Tooltip of the rollback link on the history page and the diff view {{msg-mw|rollbacklinkcount}}\n\nThe word \"Rollback\" must be the same as in the message {{msg-mw|rollbacklink}}.\n\n{{Identical|Rollback}}\n{{Identical|Revert}}",
        "tooltip-undo": "Tooltip of the undo link on the history page and the diff view {{msg-mw|editundo}}\n{{Identical|Undo}}{{Identical|Revert}}",
        "tooltip-preferences-save": "Used as tooltip for Save button.\n\nSee also:\n* {{msg-mw|Saveprefs}}\n* {{msg-mw|Accesskey-preferences-save}}\n* {{msg-mw|Tooltip-preferences-save}}",
        "tooltip-summary": "Used as tooltip for Summary input box in Editor page.\n\nSee also:\n* {{msg-mw|Summary}}\n* {{msg-mw|Accesskey-summary}}\n* {{msg-mw|Tooltip-summary}}",
        "confirm-unwatch-top": "Used as confirmation message.",
        "confirm-rollback-button": "Used as Submit button text.\n{{Identical|OK}}",
        "confirm-rollback-top": "Used as confirmation message.",
+       "confirm-rollback-bottom": "Used to describe the rollback action to the user.",
        "confirm-mcrrestore-title": "Title for the editless restore form.",
        "confirm-mcrundo-title": "Title for the editless undo form.",
        "mcrundofailed": "Title of the error page when an editless undo fails.",
        "hebrew-calendar-m10-gen": "{{optional}}\nName of month in Hebrew calendar.",
        "hebrew-calendar-m11-gen": "{{optional}}\nName of month in Hebrew calendar.",
        "hebrew-calendar-m12-gen": "{{optional}}\nName of month in Hebrew calendar.",
-       "signature": "This will be substituted in the signature (~<nowiki></nowiki>~~ or ~~<nowiki></nowiki>~~ excluding timestamp).\n\nParameters:\n* $1 - the username that is currently login\n* $2 - the customized signature which is specified in [[Special:Preferences|user's preferences]] as non-raw\nUse your language default parentheses ({{msg-mw|parentheses}}), but not use the message direct.\n\nSee also:\n* {{msg-mw|Signature-anon}} - signature for anonymous user",
+       "signature": "This will be substituted in the signature (~<nowiki></nowiki>~~ or ~~<nowiki></nowiki>~~ excluding timestamp).\n\nTranslate the word \"talk\" towards the end.\n\nParameters:\n* $1 - the username that is currently login\n* $2 - the customized signature which is specified in [[Special:Preferences|user's preferences]] as non-raw\n\nUse your language default parentheses ({{msg-mw|parentheses}}), but not use the message direct.\n\nSee also:\n* {{msg-mw|Signature-anon}} - signature for anonymous user",
        "signature-anon": "{{notranslate}}\nUsed as signature for anonymous user. Parameters:\n* $1 - username (IP address?)\n* $2 - nickname (IP address?)\nSee also:\n* {{msg-mw|Signature}} - signature for registered user",
        "timezone-utc": "{{optional}}",
        "timezone-local": "Label to indicate that a time is in the user's local timezone.\n{{Identical|Local}}",
        "mediastatistics-header-3d": "Header on [[Special:MediaStatistics]] for file types that are in the 3D category. Includes STL files.",
        "mediastatistics-header-total": "Header on [[Special:MediaStatistics]] for a summary of all file types.",
        "json-warn-trailing-comma": "A warning message notifying that JSON text was automatically corrected by removing erroneous commas.\n\nParameters:\n* $1 - number of commas that were removed\n{{Related|Json-error}}",
-       "json-error-unknown": "User error message when there’s an unknown error.\n\nThis error is shown if we received an unexpected value from PHP. See https://secure.php.net/manual/en/function.json-last-error.php\n\nParameters:\n* $1 - integer error code\n{{Related|Json-error}}",
-       "json-error-depth": "User error message when the maximum stack depth is exceeded.\nSee https://secure.php.net/manual/en/function.json-last-error.php\n{{Related|Json-error}}",
-       "json-error-state-mismatch": "User error message when underflow or the modes mismatch.\n\n'''Underflow''': A data-processing error arising when the absolute value of a computed quantity is smaller than the limits of precision of the computing device, retaining at least one significant digit.\n\nSee https://secure.php.net/manual/en/function.json-last-error.php\n{{Related|Json-error}}",
-       "json-error-ctrl-char": "User error message when an unexpected control character has been found.\nSee https://secure.php.net/manual/en/function.json-last-error.php\n{{Related|Json-error}}",
-       "json-error-syntax": "User error message when there is a syntax error; a malformed JSON.\nSee https://secure.php.net/manual/en/function.json-last-error.php\n{{Related|Json-error}}\n{{Identical|Syntax error}}",
-       "json-error-utf8": "User error message when there are malformed UTF-8 characters, possibly incorrectly encoded.\nSee https://secure.php.net/manual/en/function.json-last-error.php\n{{Related|Json-error}}",
-       "json-error-recursion": "PHP JSON encoding/decoding error. See https://secure.php.net/manual/en/function.json-last-error.php\n{{Related|Json-error}}",
-       "json-error-inf-or-nan": "PHP JSON encoding/decoding error. See https://secure.php.net/manual/en/function.json-last-error.php\n{{Related|Json-error}}",
-       "json-error-unsupported-type": "PHP JSON encoding/decoding error. See https://secure.php.net/manual/en/function.json-last-error.php\n{{Related|Json-error}}",
+       "json-error-unknown": "User error message when there’s an unknown error.\n\nThis error is shown if we received an unexpected value from PHP. See https://www.php.net/manual/en/function.json-last-error.php\n\nParameters:\n* $1 - integer error code\n{{Related|Json-error}}",
+       "json-error-depth": "User error message when the maximum stack depth is exceeded.\nSee https://www.php.net/manual/en/function.json-last-error.php\n{{Related|Json-error}}",
+       "json-error-state-mismatch": "User error message when underflow or the modes mismatch.\n\n'''Underflow''': A data-processing error arising when the absolute value of a computed quantity is smaller than the limits of precision of the computing device, retaining at least one significant digit.\n\nSee https://www.php.net/manual/en/function.json-last-error.php\n{{Related|Json-error}}",
+       "json-error-ctrl-char": "User error message when an unexpected control character has been found.\nSee https://www.php.net/manual/en/function.json-last-error.php\n{{Related|Json-error}}",
+       "json-error-syntax": "User error message when there is a syntax error; a malformed JSON.\nSee https://www.php.net/manual/en/function.json-last-error.php\n{{Related|Json-error}}\n{{Identical|Syntax error}}",
+       "json-error-utf8": "User error message when there are malformed UTF-8 characters, possibly incorrectly encoded.\nSee https://www.php.net/manual/en/function.json-last-error.php\n{{Related|Json-error}}",
+       "json-error-recursion": "PHP JSON encoding/decoding error. See https://www.php.net/manual/en/function.json-last-error.php\n{{Related|Json-error}}",
+       "json-error-inf-or-nan": "PHP JSON encoding/decoding error. See https://www.php.net/manual/en/function.json-last-error.php\n{{Related|Json-error}}",
+       "json-error-unsupported-type": "PHP JSON encoding/decoding error. See https://www.php.net/manual/en/function.json-last-error.php\n{{Related|Json-error}}",
        "headline-anchor-title": "Title tooltip for the section anchor symbol, which is a link to the current section. Can be interpreted both as a noun (\"this is a link\") or as a verb (\"use this to link\").",
        "special-characters-group-latin": "This is the name of a script, or alphabet, not a language.",
        "special-characters-group-latinextended": "The name of the Latin Extended character set.",
        "passwordpolicies-policyflag-forcechange": "Password policy flag that enforces changing invalid passwords on login.",
        "passwordpolicies-policyflag-suggestchangeonlogin": "Password policy flag that suggests changing invalid passwords on login.",
        "easydeflate-invaliddeflate": "Error message if the content passed to easydeflate was not deflated (compressed) properly",
-       "unprotected-js": "Error message shown when trying to load javascript via action=raw that is not protected"
+       "unprotected-js": "Error message shown when trying to load javascript via action=raw that is not protected",
+       "userlogout-continue": "Shown if user attempted to log out without a token specified. Probably the user clicked on an old link that hasn't been updated to use the new system. $1 - url that user should click on in order to log out.",
+       "userlogout-sessionerror": "Shown when a user tries to log out with an invalid token. $1 is url with correct token that user should click."
 }
index 84701bd..f31e786 100644 (file)
        "minoreditletter": "a",
        "newpageletter": "M",
        "boteditletter": "r",
-       "number_of_watching_users_pageview": "[$1 watiqachkaq {{PLURAL:$1|ruraq|ruraqkuna}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|byte}} hukchasqa kaptinña",
        "newsectionsummary": "Musuq raki: /* $1 */",
        "rc-enhanced-expand": "Imaymanachakunata rikuchiy",
        "img-auth-nopathinfo": "Manam kanchu PATH_INFO.\nSirwiqniykiqa manam churasqachu kaymanta willananpaq.\nCGI nisqawanchá tiksichasqa, chayrayku manachá img_auth nisqata q'imiyta atinchu.\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization nisqata qhaway.",
        "img-auth-notindir": "Mañakusqa ñanqa manam churaykusqa churkuna churanapi kachkanchu.",
        "img-auth-badtitle": "Manam atinichu \"$1\" nisqamanta chaniyuq sutita rurayta.",
-       "img-auth-nologinnWL": "Manam yaykusqa kachkankichu, \"$1\" nisqataq manam yuraq sutisuyupi kachkanchu.",
        "img-auth-nofile": "\"$1\" sutiyuq willañiqiqa manam kanchu.",
        "img-auth-isdir": "\"$1\" nisqa churanatam aypaykachachkanki.\nWillañiqilla aypayllam saqillasqa.",
        "img-auth-streaming": "\"$1\" nisqata purichispa.",
        "allmessagesdefault": "Ñawpaq qillqa",
        "allmessagescurrent": "Kunan kachkaq qillqa",
        "allmessagestext": "Kayqa MediaWiki suti k'itipi llamk'achinalla willaykunayuq sutisuyum.\nAma hina kaspa, [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] nisqata, [https://translatewiki.net translatewiki.net] nisqatapas watukuy, MediaWiki nisqata t'ikraywan yanapayta munaspaykiqa.",
-       "allmessagesnotsupportedDB": "Kay p'anqaqa manam llamk'achinallachu, '''$wgUseDatabaseMessages''' nisqaman ama nisqa kaptinmi.",
+       "allmessages-not-supported-database": "Kay p'anqaqa manam llamk'achinallachu, '''$wgUseDatabaseMessages''' nisqaman ama nisqa kaptinmi.",
        "allmessages-filter-legend": "Ch'illchina",
        "allmessages-filter": "Ch'illchina, allinchasqa kachkaykama:",
        "allmessages-filter-unmodified": "Mana hukchasqa",
index 6f80ace..6027826 100644 (file)
        "minoreditletter": "P",
        "newpageletter": "N",
        "boteditletter": "B",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|utilisader|utilisaders}} observeschan quest artitgel]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} suenter la midada",
        "newsectionsummary": "Nov chapitel /* $1 */",
        "rc-enhanced-expand": "Mussar detagls",
        "img-auth-nopathinfo": "PATH_INFO manca.\nTes server n'è betg configurà per surdar questa infurmaziun.\nEl basa forsa sin CGI è na sustegna betg img_auth.\nConsultescha https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Il percurs dumandà n'è betg en l'ordinatur da transferir configurà.",
        "img-auth-badtitle": "Nunpussaivel da construir in titel valid da \"$1\".",
-       "img-auth-nologinnWL": "Ti n'ès betg t'annunzia ed \"$1\" n'è betg sin la glista alva.",
        "img-auth-nofile": "Datoteca \"$1\" n'exista betg.",
        "img-auth-isdir": "Ti emprovas dad acceder l'ordinatur \"$1\".\nTi has be access a singulas datotecas.",
        "img-auth-streaming": "Stream da \"$1\".",
        "allmessagesdefault": "text original",
        "allmessagescurrent": "text actual",
        "allmessagestext": "Quai è ina glista da tut ils messadis dals differents tips da paginas da MediaWiki che vegnan utilisadas da la software MediaWiki.\nFai ina visita sin [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] e [https://translatewiki.net translatewiki.net] sche ti vuls gidar da translatar la software MediaWiki.",
-       "allmessagesnotsupportedDB": "Questa pagina na po betg vegnir mussada, perquai che '''$wgUseDatabaseMessages''' è vegnì deactivà.",
+       "allmessages-not-supported-database": "Questa pagina na po betg vegnir mussada, perquai che '''$wgUseDatabaseMessages''' è vegnì deactivà.",
        "allmessages-filter-legend": "Filtrar",
        "allmessages-filter": "Filtrar tenor standi da modificaziun:",
        "allmessages-filter-unmodified": "Betg modifitgà",
index 980836d..40900a3 100644 (file)
@@ -38,7 +38,8 @@
                        "Andrei Stroe",
                        "WebSourceContentRO",
                        "MSClaudiu",
-                       "Lucdrei"
+                       "Lucdrei",
+                       "Moyogo"
                ]
        },
        "tog-underline": "Sublinierea legăturilor:",
@@ -84,6 +85,7 @@
        "tog-norollbackdiff": "Nu arăta diferența după efectuarea unei reveniri",
        "tog-useeditwarning": "Avertizează-mă când părăsesc o pagină fără a salva modificările",
        "tog-prefershttps": "Utilizează întotdeauna o conexiune securizată când sunt autentificat(ă)",
+       "tog-showrollbackconfirmation": "Cere confirmarea când se face click pe o legătură de revenire",
        "underline-always": "Întotdeauna",
        "underline-never": "Niciodată",
        "underline-default": "Standardul temei sau al navigatorului",
        "badretype": "Parolele pe care le-ați introdus diferă.",
        "usernameinprogress": "Crearea unui cont pentru acest nume de utilizator este deja în derulare. Vă rugăm să așteptați.",
        "userexists": "Numele de utilizator pe care l-ați introdus este deja folosit.\nVă rugăm să alegeți un alt nume.",
+       "createacct-normalization": "Numele dumneavoastră de utilizator va fi modificat în „$2” din cauza unor limitări tehnice.",
        "loginerror": "Eroare de autentificare",
        "createacct-error": "Eroare la crearea contului",
        "createaccounterror": "Nu pot crea contul: $1",
        "page_first": "prima",
        "page_last": "ultima",
        "histlegend": "Legendă: (actuală) = diferențe față de versiunea curentă,\n(prec) = diferențe față de versiunea precedentă, M = modificare minoră",
-       "history-fieldset-title": "Caută versiuni anterioare",
+       "history-fieldset-title": "Filtrează versiuni",
        "history-show-deleted": "Doar versiuni șterse",
        "histfirst": "cele mai vechi",
        "histlast": "cele mai noi",
        "historysize": "({{PLURAL:$1|1 octet|$1 octeți|$1 de octeți}})",
-       "historyempty": "(gol)",
+       "historyempty": "gol",
        "history-feed-title": "Revizia istoricului",
        "history-feed-description": "Istoricul versiunilor pentru această pagină din wiki",
        "history-feed-item-nocomment": "$1 la $2",
        "right-reupload-own": "Suprascrie un fișier existent propriu",
        "right-reupload-shared": "Rescrie fișierele disponibile în depozitul partajat",
        "right-upload_by_url": "Încarcă un fișier de la o adresă URL",
-       "right-purge": "Curăță memoria cache pentru o pagină fără confirmare",
+       "right-purge": "Curăță cache-ul serverului pentru o pagină",
        "right-autoconfirmed": "Neafectat de limitele pe bază de IP ale raportului",
        "right-bot": "Tratare ca proces automat",
        "right-nominornewtalk": "Nu declanșează mesajul „Aveți un mesaj nou” atunci când efectuează o modificare minoră pe pagina de discuții a utilizatorului",
        "action-changetags": "adăugați și să înlăturați etichete arbitrare din versiuni și intrări de jurnal individuale",
        "action-deletechangetags": "ștergeți etichete din baza de date",
        "action-purge": "curățați cache-ul acestei pagini",
+       "action-apihighlimits": "folosiți limite mai mari în interogările API",
+       "action-autoconfirmed": "nu fiți afectați de limitări de viteză pe bază de IP",
+       "action-bigdelete": "ștergeți pagini cu istoricuri mari",
+       "action-blockemail": "blocați un utilizator de la a trimite e-mailuri",
+       "action-bot": "fiți tratat ca proces automat",
+       "action-editprotected": "editați pagini protejate ca „{{int:protect-level-sysop}}”",
+       "action-editsemiprotected": "editați pagini protejate ca „{{int:protect-level-autoconfirmed}}”",
+       "action-editinterface": "editați interfața utilizator",
+       "action-editusercss": "editați fișierele CSS ale altor utilizatori",
+       "action-edituserjson": "editați fișierele JSON ale altor utilizatori",
+       "action-edituserjs": "editați fișierele JavaScript ale altor utilizatori",
+       "action-editsitecss": "editați CSS la nivelul site-ului",
+       "action-editsitejson": "editați JSON la nivelul site-ului",
+       "action-editsitejs": "editați JavaScript la nivelul site-ului",
+       "action-editmyusercss": "vă editați propriile fișiere CSS de utilizator",
+       "action-editmyuserjson": "vă editați propriile fișiere JSON",
+       "action-editmyuserjs": "vă editați propriile fișiere JavaScript",
+       "action-viewsuppressed": "vedeți versiuni ascunse oricărui utilizator",
+       "action-hideuser": "blocați un nume de utilizator, ascunzându-l publicului",
+       "action-ipblock-exempt": "treceți peste blocările de IP, autoblocări sau blocări de game de IP-uri",
+       "action-unblockself": "vă deblocați",
+       "action-noratelimit": "nu fiți afectat de limitări de viteză",
+       "action-reupload-own": "suprascrieți un fișiere existent propriu",
        "nchanges": "$1 {{PLURAL:$1|modificare|modificări|de modificări}}",
        "ntimes": "$1×",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|de la ultima vizită}}",
        "rcfilters-hours-title": "Ultimele ore",
        "rcfilters-days-show-days": "$1 {{PLURAL:$1|zi|zile|de zile}}",
        "rcfilters-days-show-hours": "$1 {{PLURAL:$1|oră|ore|de ore}}",
-       "rcfilters-highlighted-filters-list": "FIltru: $1",
+       "rcfilters-highlighted-filters-list": "Filtru: $1",
        "rcfilters-quickfilters": "Filtre salvate",
        "rcfilters-quickfilters-placeholder-title": "Niciun filtru salvat deocamdată",
        "rcfilters-quickfilters-placeholder-description": "Pentru a salva setările de filtrare și a le refolosi mai târziu, faceți clic pe iconița de marcaje în zona de Filtre active de mai jos.",
        "rcfilters-savedqueries-already-saved": "Aceste filtre sunt deja salvate. Schimbați setările pentru a salva un nou filtru de căutare.",
        "rcfilters-restore-default-filters": "Restaurați filtrele prestabilite",
        "rcfilters-clear-all-filters": "Ștergeți toate filtrele",
-       "rcfilters-show-new-changes": "Arată schimbările mai noi",
+       "rcfilters-show-new-changes": "Arată schimbările mai noi de la $1",
        "rcfilters-search-placeholder": "Filtrați modificările recente (folosiți meniul sau căutați numele filtrului)",
        "rcfilters-invalid-filter": "Filtru invalid",
        "rcfilters-empty-filter": "Nu există filtre active. Toate contribuțiile sunt afișate.",
        "rcfilters-filter-editsbyself-description": "Contribuțiile tale.",
        "rcfilters-filter-editsbyother-label": "Contribuțiile altora",
        "rcfilters-filter-editsbyother-description": "Toate modificările cu excepția celor proprii.",
-       "rcfilters-filtergroup-userExpLevel": "Nivelul de experiență a utilizatorilor",
+       "rcfilters-filtergroup-user-experience-level": "Nivelul de experiență a utilizatorilor",
        "rcfilters-filter-user-experience-level-registered-label": "Înregistrat",
        "rcfilters-filter-user-experience-level-registered-description": "Editorii conectați.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Neînregistrat",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Filtrul \"Modificări minore\" se află în conflict cu unul sau mai multe filtre de tipul \"Modificare\", deoarece anumite tipuri de schimbări nu pot fi desemnate ca \"minore\". Filtrele conflictuale sunt marcate în zona Filtre Active, de mai sus.",
        "rcfilters-hideminor-conflicts-typeofchange": "Anumite tipuri de schimbări nu pot fi desemnate ca fiind \"minore\", astfel că acest filtru este în conflict cu următoarele tipuri de filtre de schimbări: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Acest tip de filtru al schimbărilor este în conflict cu filtrul \"Modificări minore\". Anumite tipuri de schimbări nu pot fi desemnate ca fiind \"minore\".",
-       "rcfilters-filtergroup-lastRevision": "Ultimele versiuni",
+       "rcfilters-filtergroup-lastrevision": "Ultimele versiuni",
        "rcfilters-filter-lastrevision-label": "Versiunea curentă",
        "rcfilters-filter-lastrevision-description": "Doar cea mai recentă modificare a unei pagini.",
        "rcfilters-filter-previousrevision-label": "Nu versiunea curentă",
        "newpageletter": "N",
        "boteditletter": "b",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|utilizator|utilizatori|de utilizatori}} care urmăresc]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|octet|octeți|de octeți}} după modificare",
        "newsectionsummary": "/* $1 */ secțiune nouă",
        "img-auth-nopathinfo": "Lipsește informația privitoare la căi.\n\nServerul dumneavoastră trebuie să fie setat pentru a transmite variabilele REQUEST_URI sau PATH_INFO.\n\nDacă face deja acest lucru, încercați să activați $wgUserPathInfo.\n\nVedeți https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Adresa cerută nu este în directorul pentru încărcări configurat.",
        "img-auth-badtitle": "Nu s-a putut construi un titlu valid din \"$1\".",
-       "img-auth-nologinnWL": "Nu sunteți autentificat și \"$1\" nu este pe lista albă.",
        "img-auth-nofile": "Fișierul \"$1\" nu există.",
        "img-auth-isdir": "Încercați să accesați directorul \"$1\".\nNumai accesul la fișiere este permis.",
        "img-auth-streaming": "Derularea continuă a \"$1\".",
        "filedelete": "Șterge $1",
        "filedelete-legend": "Șterge fișierul",
        "filedelete-intro": "Sunteți pe cale să ștergeți fișierul '''[[Media:$1|$1]]''' cu tot istoricul acestuia.",
-       "filedelete-intro-old": "Ştergi versiunea fișierului '''[[Media:$1|$1]]''' din [$4 $3, $2].",
+       "filedelete-intro-old": "Ștergi versiunea fișierului '''[[Media:$1|$1]]''' din [$4 $3, $2].",
        "filedelete-comment": "Motiv:",
        "filedelete-submit": "Șterge",
        "filedelete-success": "'''$1''' a fost șters.",
        "filedelete-reason-otherlist": "Alt motiv",
        "filedelete-reason-dropdown": "*Motive uzuale\n** Încălcare drepturi de autor\n** Fișier duplicat",
        "filedelete-edit-reasonlist": "Modifică motivele ștergerii",
-       "filedelete-maintenance": "Ştergerea sau restaurarea fișierelor este temporar dezactivată pe timpul lucrărilor de mentenanță.",
+       "filedelete-maintenance": "Ștergerea sau restaurarea fișierelor este temporar dezactivată pe timpul lucrărilor de mentenanță.",
        "filedelete-maintenance-title": "Fișierul nu a putut fi șters",
        "mimesearch": "Căutare MIME",
        "mimesearch-summary": "Această pagină permite filtrarea fișierelor în funcție de tipul MIME.\nDate de intrare: tip_de_conținut/subtip sau tip_de_conținut/*; ex. <code>image/jpeg</code>.",
        "querypage-disabled": "Această pagină specială este dezactivată din motive de performanță.",
        "apihelp": "Ajutor API",
        "apihelp-no-such-module": "Modulul „$1” nu a fost găsit.",
-       "apisandbox": "Cutia cu nisip pentru API",
-       "apisandbox-jsonly": "Este nevoie de JavaScript pentru a folosi Cutia cu nisip pentru API.",
+       "apisandbox": "Pagina de teste pentru API",
+       "apisandbox-jsonly": "Este nevoie de JavaScript pentru a folosi pagina de teste pentru API.",
        "apisandbox-api-disabled": "API este dezactivat pe acest site.",
        "apisandbox-intro": "Folosiți această pagină pentru a experimenta cu <strong>API-ul MediaWiki</strong>. Citiți [[mw:API:Main page|documentația API-ului]] pentru mai multe detalii de utilizare. Exemplu: [https://www.mediawiki.org/wiki/API#A_simple_example obțineți conținutul paginii principale]. Selectați o acțiune pentru a vedea mai multe exemple.",
        "apisandbox-submit": "Efectuați cererea",
        "apisandbox-sending-request": "Se trimite solicitarea API...",
        "apisandbox-loading-results": "Se obțin rezultatele API...",
        "apisandbox-results-error": "A apărut o eroare la încărcarea răspunsului solicitării API: $1.",
-       "apisandbox-results-login-suppressed": "Această cerere a fost procesată ca venind din partea unui utilizator neautentificat deoarece poate fi folosită pentru a evita verificările cu privire la originea comună făcute de browser. Metoda automată de administrare a token-urilor din groapa cu nisip pentru APU nu funcționează corect cu aceste cereri, vă rugăm să le completați manual.",
+       "apisandbox-results-login-suppressed": "Această cerere a fost procesată ca venind din partea unui utilizator neautentificat deoarece poate fi folosită pentru a evita verificările cu privire la originea comună făcute de browser. Metoda automată de administrare a token-urilor din pagina de teste pentru API nu funcționează corect cu aceste cereri, vă rugăm să le completați manual.",
        "apisandbox-request-selectformat-label": "Afișați datele solicitate ca:",
        "apisandbox-request-format-url-label": "Șir de interogări URL",
        "apisandbox-request-url-label": "URL cerere:",
        "excontent": "conținutul era: '$1'",
        "excontentauthor": "conținutul era: „$1”, iar unicul contribuitor a fost „[[Special:Contributions/$2|$2]]” ([[User talk:$2|discuție]])",
        "exbeforeblank": "conținutul înainte de golire era: '$1'",
-       "delete-confirm": "Şterge \"$1\"",
+       "delete-confirm": "Șterge \"$1\"",
        "delete-legend": "Şterge",
        "historywarning": "<strong>Atenție:</strong> istoricul paginii pe care o ștergeți conține $1 {{PLURAL:$1|versiune|versiuni|de versiuni}}:",
-       "historyaction-submit": "Afișează",
+       "historyaction-submit": "Afișează versiuni",
        "confirmdeletetext": "Sunteți pe cale să ștergeți permanent o pagină sau imagine din baza de date, împreună cu istoria asociată acesteia. Vă rugăm să confirmați alegerea făcută de dvs., faptul că înțelegeți consecințele acestei acțiuni și faptul că o faceți în conformitate cu [[{{MediaWiki:Policy-url}}|Politica oficială]].",
        "actioncomplete": "Acțiune completă",
        "actionfailed": "Acțiunea a eșuat",
        "deleting-backlinks-warning": "<strong>Atenție:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Alte pagini]] se leagă sau transclud pagina pe care doriți să o ștergeți.",
        "deleting-subpages-warning": "<strong>Atenție:</strong> Pagina pe care urmează s-o ștergeți are [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|o subpagină|$1 subpagini|$1 de subpagini|51=peste 50 de subpagini}}]].",
        "rollback": "Editări de revenire",
+       "rollback-confirmation-confirm": "Confirmați:",
+       "rollback-confirmation-yes": "Revenire",
+       "rollback-confirmation-no": "Anulare",
        "rollbacklink": "revenire",
        "rollbacklinkcount": "revenire asupra {{PLURAL:$1|unei modificări|a $1 modificări|a $1 de modificări}}",
        "rollbacklinkcount-morethan": "revenire asupra a mai mult de {{PLURAL:$1|o modificare|$1 modificări|$1 de modificări}}",
        "revertpage": "Anularea modificărilor efectuate de către [[Special:Contributions/$2|$2]] ([[User talk:$2|discuție]]) și revenire la ultima versiune de către [[User:$1|$1]]",
        "revertpage-nouser": "Anularea modificărilor efectuate de un utilizator ascuns și revenirea la ultima modificare de către {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Modificările făcute de {{GENDER:$3|$1}} au fost anulate;\nam revenit la ultima versiune de {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "S-a revenit asupra schimbărilor făcute de $1;\nam revenit la ultima versiune de $2. [$3 Arată schimbările]",
        "sessionfailure-title": "Eroare de sesiune",
        "sessionfailure": "Se pare că este o problemă cu sesiunea de autentificare; această acțiune a fost oprită ca o precauție împotriva furtului sesiunii. Vă rugăm să trimiteți formularul din nou.",
        "changecontentmodel": "Modificare model de conținut al unei pagini",
        "mycontris": "Contribuții",
        "anoncontribs": "Contribuții",
        "contribsub2": "Pentru {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "Pentru {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "Contul de utilizator „$1” nu este înregistrat.",
        "nocontribs": "Nu a fost găsită nici o modificare care să satisfacă acest criteriu.",
        "uctop": "actuală",
        "ipb-confirm": "Confirmare blocare",
        "ipb-sitewide": "Pe site",
        "ipb-partial": "Parțial",
+       "ipb-sitewide-help": "Toate paginile de pe wiki și toate celelalte acțiuni contributive.",
+       "ipb-partial-help": "Anumite pagini sau spații de nume.",
        "ipb-pages-label": "Pagini",
        "ipb-namespaces-label": "Spații de nume",
        "badipaddress": "Adresa IP este invalidă.",
        "blocklist-userblocks": "Ascunde conturile blocate",
        "blocklist-tempblocks": "Ascunde blocările temporare",
        "blocklist-addressblocks": "Ascunde adresele IP blocate",
+       "blocklist-type": "Tip:",
+       "blocklist-type-opt-all": "Toate",
+       "blocklist-type-opt-sitewide": "La nivel de site",
+       "blocklist-type-opt-partial": "Parțial",
        "blocklist-rangeblocks": "Ascunde blocările de gamă",
        "blocklist-timestamp": "Data și ora",
        "blocklist-target": "Utilizator/adresă IP",
        "blocklist-editing-page": "pagini",
        "blocklist-editing-ns": "spații de nume",
        "ipblocklist-empty": "Lista blocărilor este goală.",
-       "ipblocklist-no-results": "Nu există blocare pentru adresa IP sau numele de utilizator.",
+       "ipblocklist-no-results": "Nu există blocări pentru adresa IP sau numele de utilizator cerute.",
        "blocklink": "blochează",
        "unblocklink": "deblochează",
        "change-blocklink": "modifică blocarea",
+       "empty-username": "(nume de utilizator indisponibil)",
        "contribslink": "contribuții",
        "emaillink": "trimite e-mail",
        "autoblocker": "Blocat automat, deoarece adresa dumneavoastră IP a fost utilizată recent de „[[User:$1|$1]]”.\nMotivul blocării utilizatorului $1 este: „$2”",
        "ipb_expiry_old": "Timpul de expirare este din trecut.",
        "ipb_expiry_temp": "Blocarea numelor de utilizator ascunse trebuie să fie permanentă.",
        "ipb_hide_invalid": "Imposibil de suprimat acest cont; acesta are mai mult de {{PLURAL:$1|o modificare|$1 modificări|$1 de modificări}}.",
+       "ipb_hide_partial": "Blocările cu nume de utilizator ascuns trebuie să fie blocări la nivel de site.",
        "ipb_already_blocked": "„$1” este deja blocat",
        "ipb-needreblock": "$1 este deja blocat. Doriți să modificați parametrii?",
        "ipb-otherblocks-header": "{{PLURAL:$1|Altă blocare|Alte blocări}}",
        "allmessagesdefault": "Textul standard",
        "allmessagescurrent": "Textul curent",
        "allmessagestext": "Aceasta este lista completă a mesajelor disponibile în domeniul MediaWiki.\nVă rugăm să vizitați [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] și [https://translatewiki.net translatewiki.net] dacă vreți să contribuiți la localizarea programului MediaWiki generic.",
-       "allmessagesnotsupportedDB": "'''{{ns:special}}:Allmessages''' nu poate fi folosit deoarece opțiunea '''$wgUseDatabaseMessages''' este dezactivată.",
+       "allmessages-not-supported-database": "'''{{ns:special}}:Allmessages''' nu poate fi folosit deoarece opțiunea '''$wgUseDatabaseMessages''' este dezactivată.",
        "allmessages-filter-legend": "Filtru",
        "allmessages-filter": "Filtru după statutul de modificare:",
        "allmessages-filter-unmodified": "Nemodificat",
        "tooltip-ca-nstab-media": "Vezi pagina media",
        "tooltip-ca-nstab-special": "Aceasta este o pagină specială și nu poate fi modificată",
        "tooltip-ca-nstab-project": "Vezi pagina proiectului",
-       "tooltip-ca-nstab-image": "Vezi pagina fişierului",
+       "tooltip-ca-nstab-image": "Vezi pagina fișierului",
        "tooltip-ca-nstab-mediawiki": "Vedeți mesajul de sistem",
        "tooltip-ca-nstab-template": "Vezi formatul",
        "tooltip-ca-nstab-help": "Vezi pagina de ajutor",
        "confirm-unwatch-top": "Eliminați această pagină din lista de pagini urmărite?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Anulați editările asupra acestei pagini?",
+       "confirm-rollback-bottom": "Această acțiune va efectua o revenire automată asupra schimbărilor selectate operate în această pagină.",
        "confirm-mcrrestore-title": "Restaurează o versiune",
        "confirm-mcrundo-title": "Anulează o modificare",
        "mcrundofailed": "Anularea nu a reușit",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|discuție]])",
        "timezone-local": "Local",
        "duplicate-defaultsort": "'''Atenție:''' Cheia de sortare implicită („$2”) o înlocuiește pe precedenta („$1”).",
-       "duplicate-displaytitle": "<strong>Atenție:</strong> Titlul afișat „$2” înlocuieşte titlul afișat anterior, „$1”.",
+       "duplicate-displaytitle": "<strong>Atenție:</strong> Titlul afișat „$2” înlocuiește titlul afișat anterior, „$1”.",
        "restricted-displaytitle": "<strong>Atenție:</strong> Titlul de afișat \"$1\" a fost ignorat deoarece nu este echivalent cu titlul real al paginii.",
        "invalid-indicator-name": "<strong>Eroare:</strong> Parametrul <code>nume</code> al indicatorilor de stare a paginii nu trebuie să fie gol.",
        "version": "Versiune",
        "logentry-rights-autopromote": "$1 {{GENDER:$2|a fost promovat|a fost promovată}} în mod automat de la $4 la $5",
        "logentry-upload-upload": "$1 {{GENDER:$2|a încărcat}} $3",
        "logentry-upload-overwrite": "$1 {{GENDER:$2|a încărcat}} o versiune nouă pentru $3",
-       "logentry-upload-revert": "$1 {{GENDER:$2|a încărcat}} $3",
+       "logentry-upload-revert": "$1 {{GENDER:$2|a readus}} $3 la o versiune mai veche",
        "log-name-managetags": "Jurnal gestionare etichete",
        "log-description-managetags": "Această pagină listează activitățile de gestionare în ceea ce privește [[Special:Tags|etichetele]]. Jurnalul conține numai acțiunile efectuate manual de către un administrator; etichetele pot fi create sau șterse de software-ul wiki fără ca vreo intrare să fie înregistrată în acest jurnal.",
        "logentry-managetags-create": "$1 {{GENDER:$2|a creat}} eticheta „$4”",
        "expand_templates_generate_xml": "Arată arborele de analiză XML",
        "expand_templates_generate_rawhtml": "Arată HTML brut",
        "expand_templates_preview": "Previzualizare",
-       "expand_templates_preview_fail_html": "<em>Întrucât la {{SITENAME}} este activat HTML brut și a avut loc o pierdere a sesiunii de date, previzualizarea a fost ascunsă ca măsură de precauție împotriva atacurilor prin JavaScript.</em>\n\n<strong>Dacă aceasta este o încercare legitimă de a previzualiza, încercați din nou.</strong>\nDacă nici astfel nu funcționează, încercați să [[Special:UserLogout|închideţi sesiunea]] şi să vă autentificaţi din nou și să verificați dacă navigatorul dumneavoastră permite module cookie pentru acest site.",
+       "expand_templates_preview_fail_html": "<em>Întrucât la {{SITENAME}} este activat HTML brut și a avut loc o pierdere a sesiunii de date, previzualizarea a fost ascunsă ca măsură de precauție împotriva atacurilor prin JavaScript.</em>\n\n<strong>Dacă aceasta este o încercare legitimă de a previzualiza, încercați din nou.</strong>\nDacă nici astfel nu funcționează, încercați să [[Special:UserLogout|închideți sesiunea]] și să vă autentificați din nou și să verificați dacă navigatorul dumneavoastră permite module cookie pentru acest site.",
        "expand_templates_preview_fail_html_anon": "<em>Întrucât la {{SITENAME}} este activat HTML brut și nu v-ați autentificat, previzualizarea a fost ascunsă ca măsură de precauție împotriva atacurilor prin JavaScript.</em>\n\n<strong>Dacă aceasta este o încercare legitimă de a previzualiza, [[Special:UserLogin|autentificați-vă]] și încercați din nou.</strong>",
        "expand_templates_input_missing": "Trebuie să furnizați cel puțin un text ca date de intrare.",
        "pagelanguage": "Modificare limbă pagină",
        "log-action-filter-suppress-reblock": "Supresiunea utilizatorului după blocare",
        "log-action-filter-upload-upload": "Încărcare nouă",
        "log-action-filter-upload-overwrite": "Reîncărcare",
+       "log-action-filter-upload-revert": "Anulare",
        "authmanager-authn-not-in-progress": "Autentificarea nu este în progres sau sesiune așa că au fost pierdute date. Vă rugăm să începeți din nou de la început.",
        "authmanager-authn-no-primary": "Credențialele furnizate nu au putut fi autentificate.",
        "authmanager-authn-no-local-user": "Credențialele trimise nu sunt asociate cu orice utilizator de pe acest wiki.",
index 8f422cf..f65f312 100644 (file)
@@ -58,6 +58,7 @@
        "tog-norollbackdiff": "Non sce penzanne a le differenze apprisse l'esecuzione de 'nu rollback",
        "tog-useeditwarning": "Avvisave quanne jie lasse 'na pàgene cangiate senze ca agghie sarvate le cangiaminde",
        "tog-prefershttps": "Ause sembre 'na connessione secure quanne trase",
+       "tog-showrollbackconfirmation": "Fà 'ndrucà 'na richieste de conferme quanne ste cazze sus a 'nu collegamende de annullamende",
        "underline-always": "Sembre",
        "underline-never": "Maje",
        "underline-default": "Valore de default d'u browser o scheme",
        "badretype": "Le passuord ca è scritte non ge sonde uguale.",
        "usernameinprogress": "'Na ccrejazzione de 'nu cunde pe stu nome utende ste già in esecuzione.\nPe piacere, aspitte.",
        "userexists": "'U nome de l'utende ca è scritte jè già ausate.\nPe piacere scacchiane n'otre.",
+       "createacct-normalization": "'U nome utende tune avène corrette jndr'à \"$2\" purcé stonne de le restriziune tecniche.",
        "loginerror": "Errore de collegamende",
        "createacct-error": "Errore sus 'a ccrejazione d'u cunde",
        "createaccounterror": "Non ge puè ccrejà 'u cunde utende: $1",
        "page_first": "prime",
        "page_last": "urteme",
        "histlegend": "Differenze de selezione: signe le radio box de le versiune ca vuè cu combronde e cazze ''invio'' o 'u buttone ca ste sotte.<br />\nLeggenda: (cur) = differenze cu 'a versiona corrende,\n(last) = differenze ca 'a versione precedende, M = cangiaminde stuédeche.",
-       "history-fieldset-title": "cirche pe revisiune",
+       "history-fieldset-title": "Filtre le revisiune",
        "history-show-deleted": "Sule le revisiune scangellate",
        "histfirst": "Prime",
        "histlast": "Urteme",
        "historysize": "({{PLURAL:$1|1 byte|$1 bytes}})",
-       "historyempty": "(vacande)",
+       "historyempty": "vacande",
        "history-feed-title": "Storie de le revisiune",
        "history-feed-description": "Storie de le revisiune oe sta pàgene sus 'a le Uicchipèdie",
        "history-feed-item-nocomment": "$1 a $2",
        "right-reupload-own": "Sovrascrive 'nu file esistende carichete da quacchedune",
        "right-reupload-shared": "Sovrascrive le file sus a 'u repository de le media condivise locale",
        "right-upload_by_url": "Careche 'nu file da l'indirizze URL",
-       "right-purge": "Sdevache 'a cache d'u site pe 'na pàgene senza conferme",
+       "right-purge": "Sdevache 'a cache d'u site pe 'na pàgene",
        "right-autoconfirmed": "Cange le pàggene prutette a metà",
        "right-bot": "Adda essere trattate cumme a nu processe automateche",
        "right-nominornewtalk": "No scè ausanne le cangiaminde stuèdeche jndr'à le pàggene de le 'ngazzaminde quanne lasse messagge nuève",
        "rcfilters-savedqueries-already-saved": "Ste filtre onne state ggià reggistrate. Cange le 'mbostaziune pe ccrejà 'nu filtre nuève reggistrate.",
        "rcfilters-restore-default-filters": "Repristine le filtre de base",
        "rcfilters-clear-all-filters": "Pulizze tutte le filtre",
-       "rcfilters-show-new-changes": "'Ndruche le urteme cangiaminde",
+       "rcfilters-show-new-changes": "'Ndruche le cangiaminde nuève da $1",
        "rcfilters-invalid-filter": "Filtre invalide",
        "rcfilters-empty-filter": "Nisciune filtre attive. Tutte le condrebbute avènene fatte 'ndrucà.",
        "rcfilters-filterlist-title": "Filtre",
        "rcfilters-filter-editsbyself-description": "Condrebbute tune.",
        "rcfilters-filter-editsbyother-label": "Cangiaminde de l'otre",
        "rcfilters-filter-editsbyother-description": "Tuue le cangiaminde ma le tune none.",
-       "rcfilters-filtergroup-userExpLevel": "Reggistrazzione utende e esperienze",
+       "rcfilters-filtergroup-user-experience-level": "Reggistrazzione utende e esperienze",
        "rcfilters-filter-user-experience-level-registered-label": "Reggistrate",
        "rcfilters-filter-user-experience-level-registered-description": "Cangiature trasute.",
        "rcfilters-filter-user-experience-level-unregistered-label": "None reggistrate",
        "rcfilters-filter-categorization-label": "Cangiaminde de le categorije",
        "rcfilters-filter-logactions-label": "Aziune reggistrate",
        "rcfilters-filter-logactions-description": "Aziune amministrative, ccrejazziune de cunde utinde, scangallezziune de pàggene, carecaminde...",
-       "rcfilters-filtergroup-lastRevision": "Urteme revisiune",
+       "rcfilters-filtergroup-lastrevision": "Urteme revisiune",
        "rcfilters-filter-lastrevision-label": "Urtema revisione",
        "rcfilters-filter-lastrevision-description": "Sulamende le urteme cangiamende a 'na pàgene.",
        "rcfilters-filter-previousrevision-label": "Non g'è l'urtema versione",
        "newpageletter": "N",
        "boteditletter": "b",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|utende|utinde}} ca condrollene]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|byte}} apprisse 'u cangiamende",
        "newsectionsummary": "/* $1 */ seziona nove",
        "img-auth-nopathinfo": "No se iacchie 'u percorse d'a 'mbormnazione.\n'U server tune adda essere 'mbostate pe passà sta 'le variabbile REQUEST_URI e/o PATH_INFO.\nCe jè accussì, pruève a abbilità $wgUsePathInfo.\n'Ndruche https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "'U percorse richieste non ge stè jndr'à cartelle de carecamende configurate",
        "img-auth-badtitle": "Non ge se pò costruì 'nu titele valide da \"$1\".",
-       "img-auth-nologinnWL": "Tu non ge sì collegate e \"$1\" non ge stè jndr'à lista vianghe.",
        "img-auth-nofile": "File \"$1\" non g'esiste.",
        "img-auth-isdir": "Tu ste ppruève a trasè jndr'à cartelle \"$1\".\nSulamende le file ponne trasè.",
        "img-auth-streaming": "Streaming \"$1\".",
        "delete-confirm": "Scangille \"$1\"",
        "delete-legend": "Scangille",
        "historywarning": "<strong>Vide Bbuene:</strong> 'A pàgene ca ste scangille tène 'na storie de cangiaminde cu cchiù o mene $1 {{PLURAL:$1|revisione|revisiune}}:",
-       "historyaction-submit": "Fà 'ndrucà",
+       "historyaction-submit": "Fà 'ndrucà le revisiune",
        "confirmdeletetext": "Vide Bbuene, vide ca ste scangille 'na pàgene ca tène pure nu sbuenne de cangiaminde.\nConferme quidde ca ste face, ce si sicure ca è capite quidde ca ste cumbine e ce è corrette rispette a [[{{MediaWiki:Policy-url}}|le regole de scangellazione]], ce no statte quiete.",
        "actioncomplete": "Aziona Combletete",
        "actionfailed": "Aziona fallite",
        "deleteprotected": "Non ge puè scangellà sta pàgene purcé ha state protette.",
        "deleting-backlinks-warning": "<strong>Attenziò:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Otre pàggene]] appondene o vonne 'a pàgene ca tu vue ccù scangìlle.",
        "rollback": "Annulle le cangiaminde",
+       "rollback-confirmation-confirm": "Pe piacere conferme:",
        "rollbacklink": "annulle 'u cangiaminde",
        "rollbacklinkcount": "annulle $1 {{PLURAL:$1|cangiamende|cangiaminde}}",
        "rollbacklinkcount-morethan": "annulle cchiù de $1 {{PLURAL:$1|cangiamende|cangiaminde}}",
        "blocklist-editing-page": "pàggene",
        "blocklist-editing-ns": "namespace",
        "ipblocklist-empty": "'A liste de le blocche jè vacande.",
-       "ipblocklist-no-results": "L'indirizze IP ca è cerchete o 'u nome utende non ge sonde blocchete.",
+       "ipblocklist-no-results": "Nisciune blocche acchiate pe l'indirizze IP o 'u nome utende ca è cercate.",
        "blocklink": "blocche",
        "unblocklink": "sblocche",
        "change-blocklink": "cange 'u blocche",
        "allmessagesdefault": "Teste de default",
        "allmessagescurrent": "Teste corrende",
        "allmessagestext": "Queste jè 'na liste de tutte le messagge d'u sisteme ca se ponne acchià jndr'à le namespace de MediaUicchi.\nPe piacere vè vide [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Localizzazione de MediaUicchi] e [https://translatewiki.net translatewiki.net] ce tu vuè ccu condrebbuisce a 'a localizzazione de MediaUicchi.",
-       "allmessagesnotsupportedDB": "Sta pàgene non ge pò essere ausate purcè '''$wgUseDatabaseMessages''' ha state disabbilitate.",
+       "allmessages-not-supported-database": "Sta pàgene non ge pò essere ausate purcè '''$wgUseDatabaseMessages''' ha state disabbilitate.",
        "allmessages-filter-legend": "Filtre",
        "allmessages-filter": "Filtre cu 'nu state personalizzate:",
        "allmessages-filter-unmodified": "Senza cangiamende",
index 927448b..9e617e9 100644 (file)
                        "Cronolio",
                        "Nk88",
                        "Edward Chernenko",
-                       "Romanko Mikhail"
+                       "Romanko Mikhail",
+                       "Diralik",
+                       "1233qwer1234qwer4"
                ]
        },
        "tog-underline": "Подчёркивание ссылок:",
        "tog-norollbackdiff": "Не показывать разницу версий после выполнения отката",
        "tog-useeditwarning": "Предупреждать, когда я покидаю страницу с несохранёнными изменениями",
        "tog-prefershttps": "Всегда использовать защищённое соединение после представления системе",
+       "tog-showrollbackconfirmation": "Показывать подтверждение при нажатии ссылки для отката",
        "underline-always": "Всегда",
        "underline-never": "Никогда",
        "underline-default": "Использовать настройки браузера",
        "title-invalid-interwiki": "Запрашиваемое название страницы содержит интервики-ссылку, которая не может быть использована в названиях.",
        "title-invalid-talk-namespace": "Запрашиваемое название страницы ссылается на страницу обсуждения, которая не может существовать.",
        "title-invalid-characters": "Запрашиваемое название страницы содержит недопустимые символы: «$1».",
-       "title-invalid-relative": "Заголовок имеет относительный путь. Заголовки страниц с относительным путем (/,../) являются недействительными, так как они часто недоступны, когда обрабатываются браузером пользователя.",
+       "title-invalid-relative": "Заголовок имеет относительный путь. Заголовки страниц с относительным путём (/,../) являются недействительными, так как они часто недоступны, когда обрабатываются браузером пользователя.",
        "title-invalid-magic-tilde": "Запрашиваемый заголовок страницы содержит недопустимую последовательность тильды (<nowiki>~~~</nowiki>).",
        "title-invalid-too-long": "Запрашиваемый заголовок страницы слишком длинен. Он должен быть не более $1 {{PLURAL:$1|1=байта|байт}} в кодировке UTF-8.",
        "title-invalid-leading-colon": "Запрашиваемое название страницы содержит недопустимое двоеточие в начале.",
        "titleprotected": "Создание страницы с таким заголовком было запрещено участником [[User:$1|$1]].\nУказана следующая причина: <em>$2</em>.",
        "filereadonlyerror": "Не удаётся изменить файл «$1», так как хранилище «$2» находится в режиме «только для чтения».\n\nСистемный администратор, заблокировавший базу, оставил следующее объяснение: «$3».",
        "invalidtitle": "Недопустимое название",
-       "invalidtitle-knownnamespace": "Недопустимый заголовок с пространством имен «$2» и текстом «$3»",
+       "invalidtitle-knownnamespace": "Недопустимый заголовок с пространством имён «$2» и текстом «$3»",
        "invalidtitle-unknownnamespace": "Недопустимый заголовок с неизвестным номером пространства $1 и текстом «$2»",
        "exception-nologin": "Вы не представились системе",
        "exception-nologin-text": "Необходимо представиться, чтобы иметь доступ к этой странице или действию.",
        "cannotloginnow-title": "Невозможно войти прямо сейчас",
        "cannotloginnow-text": "Нельзя войти во время использования $1.",
        "cannotcreateaccount-title": "Невозможно создать учётные записи",
-       "cannotcreateaccount-text": "Прямое создание учетных записей не включено в этой вики.",
+       "cannotcreateaccount-text": "Прямое создание учётных записей не включено в этой вики.",
        "yourdomainname": "Ваш домен:",
        "password-change-forbidden": "Вы не можете изменить пароль в этой вики.",
        "externaldberror": "Произошла ошибка при аутентификации с помощью внешней базы данных или у вас недостаточно прав для внесения изменений в свою внешнюю учётную запись.",
        "createacct-email-ph": "Введите свой адрес электронной почты",
        "createacct-another-email-ph": "Введите адрес электронной почты",
        "createaccountmail": "Использовать сгенерированный случайным образом временный пароль и выслать его на указанный адрес электронной почты",
-       "createaccountmail-help": "Может использоваться, чтобы создать учетную запись для другого лица, не узнавая пароль.",
+       "createaccountmail-help": "Может использоваться, чтобы создать учётную запись для другого лица, не узнавая пароль.",
        "createacct-realname": "Настоящее имя (необязательно)",
        "createacct-reason": "Причина",
        "createacct-reason-ph": "Зачем вы создаёте другую учётную запись",
        "nosuchuser": "Участника с именем «$1» не существует.\nИмена участников чувствительны к регистру букв.\nПроверьте правильность написания имени или [[Special:CreateAccount|создайте новую учётную запись]].",
        "nosuchusershort": "Не существует участника с именем «$1». Проверьте написание имени.",
        "nouserspecified": "Вы должны указать имя участника.",
-       "login-userblocked": "Участник заблокирован. Вход в систему запрещен.",
+       "login-userblocked": "Участник заблокирован. Вход в систему запрещён.",
        "wrongpassword": "Введены неверные имя участника или пароль.\nПопробуйте ещё раз.",
        "wrongpasswordempty": "Пожалуйста, введите непустой пароль.",
        "passwordtooshort": "Пароль должен состоять не менее, чем из $1 {{PLURAL:$1|символа|символов}}.",
        "page_first": "первая",
        "page_last": "последняя",
        "histlegend": "Выбор версий: отметьте версии страницы, которые вы хотите сравнить, и нажмите <strong>{{int:compare-submit}}</strong>.<br />\nПояснения: <strong>({{int:cur}})</strong> — отличия от текущей версии; <strong>({{int:last}})</strong> — отличия от предшествующей версии; <strong>{{int:minoreditletter}}</strong> — незначительные изменения.",
-       "history-fieldset-title": "Ð\9fоиÑ\81к Ð¿Ñ\80авок",
+       "history-fieldset-title": "ФилÑ\8cÑ\82Ñ\80оваÑ\82Ñ\8c Ð¿Ñ\80авки",
        "history-show-deleted": "Только удалённые правки",
        "histfirst": "старейшие",
        "histlast": "новейшие",
        "historysize": "($1 {{PLURAL:$1|байт|байта|байт}})",
-       "historyempty": "(пусто)",
+       "historyempty": "пусто",
        "history-feed-title": "История изменений",
        "history-feed-description": "История изменений этой страницы в вики",
        "history-feed-item-nocomment": "$1 в $2",
        "revdelete-selected-text": "{{PLURAL:$1|Выбранная версия|Выбранные версии}} [[:$2]]:",
        "revdelete-selected-file": "{{PLURAL:$1|Выбранная версия файла|Выбранные версии файла}} [[:$2]]:",
        "logdelete-selected": "{{PLURAL:$1|1=Выбранная запись|Выбранные записи}} журнала:",
-       "revdelete-text-text": "Удалённые версии будут по-прежнему видны в истории страницы, но определенные части их содержимого будут недоступны для участников.",
-       "revdelete-text-file": "Удалённые версии файла будут по-прежнему видны в истории страницы, но определенные части их содержимого будут недоступны для участников.",
-       "logdelete-text": "Удалённые события будут по-прежнему видны в журналах, но определенные части их содержимого будут недоступны для участников.",
+       "revdelete-text-text": "Удалённые версии будут по-прежнему видны в истории страницы, но определённые части их содержимого будут недоступны для участников.",
+       "revdelete-text-file": "Удалённые версии файла будут по-прежнему видны в истории страницы, но определённые части их содержимого будут недоступны для участников.",
+       "logdelete-text": "Удалённые события будут по-прежнему видны в журналах, но определённые части их содержимого будут недоступны для участников.",
        "revdelete-text-others": "Другие администраторы по-прежнему будут иметь возможность доступа к скрытому содержимому и смогут восстановить его, если не установлены дополнительные ограничения.",
        "revdelete-confirm": "Пожалуйста, подтвердите, что вы действительно желаете совершить это действие, осознаёте последствия, делаете это в соответствии с [[{{MediaWiki:Policy-url}}|правилами]].",
        "revdelete-suppress-text": "Сокрытие может производиться <strong>только</strong> в следующих случаях:\n* потенциально клеветническая информация\n* неуместная личная информация\n*: <em>домашний адрес, номера телефонов, номер паспорта и т. д.</em>",
        "diff-multi-otherusers": "(не {{PLURAL:$1|показана $1 промежуточная версия|показаны $1 промежуточные версии|показано $1 промежуточных версий}} {{PLURAL:$2|$2 участника|$2 участников}})",
        "diff-multi-manyusers": "({{PLURAL:$1|не показана $1 промежуточная версия, сделанная|не показаны $1 промежуточные версии, сделанные|не показано $1 промежуточных версий, сделанных}} более чем {{PLURAL:$2|$2 участником|$2 участниками}})",
        "diff-paragraph-moved-tonew": "Параграф был перемещён. Нажмите, чтобы перейти к новому местоположению.",
-       "diff-paragraph-moved-toold": "Пункт был перемещен. Нажмите, чтобы перейти к старому местоположению.",
+       "diff-paragraph-moved-toold": "Пункт был перемещён. Нажмите, чтобы перейти к старому местоположению.",
        "difference-missing-revision": "Не {{PLURAL:$2|1=найдена|найдены}} {{PLURAL:$2|$2 версия|$2 версий|$2 версии|1=одна из версий}} для этого сравнения ($1).\n\nТакое обычно случается при переходе по устаревшей ссылке сравнения версий для страницы, которая была удалена.\nПодробности могут быть в [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} журнале удалений].",
        "searchresults": "Результаты поиска",
        "search-filter-title-prefix": "Искать только на страницах, название которых начинается с «$1»",
        "right-reupload-own": "Перезапись файлов, загруженных тем же участником",
        "right-reupload-shared": "Замена файлов из общих хранилищ локальными",
        "right-upload_by_url": "Загрузка файлов с адреса URL",
-       "right-purge": "Очистка кэша страниц без подтверждения",
+       "right-purge": "Очистка кэша страницы",
        "right-autoconfirmed": "Обход ограничений скорости на IP-адрес",
        "right-bot": "Автоматический процесс",
        "right-nominornewtalk": "Малые правки на страницах обсуждений участников не создают для них уведомление о новом сообщении",
        "action-changetags": "добавление и удаление произвольных меток на отдельных изменениях и записях в журнале",
        "action-deletechangetags": "удаление меток из базы данных",
        "action-purge": "очистку кэша этой страницы",
+       "action-apihighlimits": "использование высоких лимитов в API-запросах",
+       "action-autoconfirmed": "обход ограничений скорости на IP-адрес",
+       "action-bigdelete": "удаление страниц с длинными историями изменений",
+       "action-blockemail": "блокировка на отправку электронной почты",
+       "action-bot": "считаться автоматическим процессом",
+       "action-editprotected": "правка страниц, защищённых как «{{int:protect-level-sysop}}»",
+       "action-editsemiprotected": "правка страниц, защищённых как «{{int:protect-level-autoconfirmed}}»",
+       "action-editinterface": "правка пользовательского интерфейса",
+       "action-editusercss": "правка CSS-файлов других участников",
+       "action-edituserjson": "правка JSON-файлов других участников",
+       "action-edituserjs": "правка JavaScript-файлов других участников",
+       "action-editsitecss": "редактирование общесайтовых CSS-файлов",
+       "action-editsitejson": "редактирование общесайтовых JSON-файлов",
+       "action-editsitejs": "редактирование общесайтовых JavaScript-файлов",
+       "action-editmyusercss": "редактирование собственных CSS-файлов",
+       "action-editmyuserjson": "редактирование собственных JSON-файлов",
+       "action-editmyuserjs": "редактирование собственных JavaScript-файлов",
+       "action-viewsuppressed": "просмотр версий, скрытых от всех участников",
+       "action-hideuser": "запрет имени участника и его сокрытие",
+       "action-ipblock-exempt": "обход блокировок по IP, автоблокировок и блокировок диапазонов",
+       "action-unblockself": "разблокирование себя самого",
+       "action-noratelimit": "обход ограничений скорости",
+       "action-reupload-own": "перезапись существующих файлов, загруженных тем же участником",
+       "action-nominornewtalk": "малые правки на страницах обсуждений участников не создают для них уведомление о новом сообщении",
+       "action-markbotedits": "отметка откатываемых правок как правок бота",
+       "action-patrolmarks": "просмотр отметок о патрулировании в свежих правках",
+       "action-override-export-depth": "экспортирование страниц, включая связанные страницы с глубиной до 5",
+       "action-suppressredirect": "переименование страниц без создания перенаправления со старого имени",
        "nchanges": "$1 {{PLURAL:$1|изменение|изменения|изменений}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|с последнего посещения}}",
        "enhancedrc-history": "история",
        "rcfilters-savedqueries-already-saved": "Эти фильтры уже сохранены. Измените свои настройки, чтобы создать новый Сохранённый фильтр.",
        "rcfilters-restore-default-filters": "Восстановить фильтры по умолчанию",
        "rcfilters-clear-all-filters": "Очистить все фильтры",
-       "rcfilters-show-new-changes": "Последние изменения",
+       "rcfilters-show-new-changes": "Последние изменения, начиная с $1",
        "rcfilters-search-placeholder": "Фильтровать изменения (используйте меню или ищите по названию фильтра)",
        "rcfilters-invalid-filter": "Недопустимый фильтр",
        "rcfilters-empty-filter": "Нет активных фильтров. Показываются все правки.",
        "rcfilters-filter-editsbyself-description": "Ваш вклад.",
        "rcfilters-filter-editsbyother-label": "Изменения, внесённые другими участниками",
        "rcfilters-filter-editsbyother-description": "Все правки, кроме ваших собственных.",
-       "rcfilters-filtergroup-userExpLevel": "Регистрация участника и его опыт",
+       "rcfilters-filtergroup-user-experience-level": "Регистрация участника и его опыт",
        "rcfilters-filter-user-experience-level-registered-label": "Зарегистрированные",
        "rcfilters-filter-user-experience-level-registered-description": "Вошедшие редакторы.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Незарегистрированные",
        "rcfilters-filter-newpages-label": "Создания страниц",
        "rcfilters-filter-newpages-description": "Правки, приводящие к созданию новых страниц.",
        "rcfilters-filter-categorization-label": "Изменения категорий",
-       "rcfilters-filter-categorization-description": "Записи о страницах, добавленных или удаленных из категорий.",
+       "rcfilters-filter-categorization-description": "Записи о страницах, добавленных или удалённых из категорий.",
        "rcfilters-filter-logactions-label": "Протоколируемые действия",
        "rcfilters-filter-logactions-description": "Административные действия, создания учётных записей, удаления страниц, загрузки файлов…",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Фильтр \"малые правки\" конфликтует с одним или несколькими фильтрами, поскольку некоторые типы правок не могут быть названы малыми. Конфликтные фильтры отмечены вверху, в области Активных фильтров.",
        "rcfilters-hideminor-conflicts-typeofchange": "Определённые типы правок не могут быть названы «малыми», поэтому этот фильтр конфликтует со следующим фильтром типа правок: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Этот фильтр типа правок конфликтует с фильтром малых правок. Определённые типы правок не могут быть отмечены «малыми».",
-       "rcfilters-filtergroup-lastRevision": "Последние версии",
+       "rcfilters-filtergroup-lastrevision": "Последние версии",
        "rcfilters-filter-lastrevision-label": "Текущая версия",
        "rcfilters-filter-lastrevision-description": "Только самое последнее изменение на странице.",
        "rcfilters-filter-previousrevision-label": "Не последняя версия",
        "newpageletter": "Н",
        "boteditletter": "б",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|наблюдающий участник|наблюдающих участника|наблюдающих участников}}]",
        "rc-change-size-new": "Размер после изменения: $1 {{PLURAL:$1|байт|байта|байт}}",
        "newsectionsummary": "/* $1 */ новая тема",
        "rc-enhanced-expand": "Показать подробности",
        "upload_directory_missing": "Директория для загрузок ($1) отсутствует и не может быть создана веб-сервером.",
        "upload_directory_read_only": "Веб-сервер не имеет прав записи в папку ($1), в которой предполагается хранить загружаемые файлы.",
        "uploaderror": "Ошибка загрузки файла",
-       "upload-recreate-warning": "<strong>Внимание: файл с таким именем был удален или переименован.</strong>\n\nНиже представлены журналы удалений и переименований этой страницы:",
+       "upload-recreate-warning": "<strong>Внимание: файл с таким именем был удалён или переименован.</strong>\n\nНиже представлены журналы удалений и переименований этой страницы:",
        "uploadtext": "Воспользуйтесь этой формой для загрузки файлов на сервер.\nЧтобы просмотреть ранее загруженные файлы, обратитесь к [[Special:FileList|списку загруженных файлов]]. Загрузка файлов также записывается в [[Special:Log/upload|журнал загрузок]]; данные об удалённых файлах можно найти в [[Special:Log/delete|журнале удалений]].\n\nДля включения файла в статью вы можете использовать строки вида:\n* <strong><code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.jpg]]</nowiki></code></strong> для вставки полной версии файла;\n* <strong><code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.png|200px|thumb|left|описание]]</nowiki></code></strong> для вставки слева от текста уменьшенной до 200 пикселей по ширине версии файла с выводом под ним указанного описания;\n* <strong><code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:File.ogg]]</nowiki></code></strong> для вставки ссылки на файл, без отображения его содержимого на странице.",
        "upload-permitted": "{{PLURAL:$2|Разрешённый тип|Разрешённые типы}} файлов: $1.",
        "upload-preferred": "{{PLURAL:$2|Предпочтительный тип|Предпочтительные типы}} файлов: $1.",
        "img-auth-nopathinfo": "Отсутствует информация о пути.\nВаш сервер должен быть настроен для передачи переменных REQUEST_URI и/или PATH_INFO.\nЕсли это так, попробуйте включить $wgUsePathInfo.\nСм. https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Запрашиваемый путь не относится к настроенной папке загрузок.",
        "img-auth-badtitle": "Невозможно построить правильный заголовок из «$1».",
-       "img-auth-nologinnWL": "Вы не вошли в систему, а «$1» не входит в белый список.",
        "img-auth-nofile": "Файл «$1» не существует.",
        "img-auth-isdir": "Вы пытаетесь получить доступ к каталогу «$1».\nРазрешён только доступ к файлам.",
        "img-auth-streaming": "Потоковая передача «$1».",
        "apihelp-no-such-module": "Модуль «$1» не найден.",
        "apisandbox": "Песочница API",
        "apisandbox-jsonly": "Для использования API-песочницы требуется JavaScript.",
-       "apisandbox-api-disabled": "API отключен на этом сайте.",
+       "apisandbox-api-disabled": "API отключён на этом сайте.",
        "apisandbox-intro": "Используйте эту страницу для экспериментов с <strong>MediaWiki API</strong>.\nОбратитесь к документации API ([https://ru.wikipedia.org/w/api.php встроенной] или [[mw:API:Main page|внешней]]) для получения дополнительной информации об использовании API. Например, о том, [https://www.mediawiki.org/wiki/API#A_simple_example как получить содержание Заглавной страницы]. Выберите действие, чтобы увидеть другие примеры.\nОбратите внимание, что, хотя это и песочница, действия, выполненные на этой странице, могут внести изменения в вики.",
        "apisandbox-submit": "Сделать запрос",
        "apisandbox-reset": "Очистить",
        "delete-confirm": "$1: удаление",
        "delete-legend": "Удаление",
        "historywarning": "<strong>Внимание:</strong> Вы собираетесь удалить страницу, у которой есть история правок, содержащая $1 {{PLURAL:$1|версию|версии|версий}}:",
-       "historyaction-submit": "Показать",
+       "historyaction-submit": "Показать версии",
        "confirmdeletetext": "Вы запросили полное удаление страницы (или изображения) и всей её истории изменений. Пожалуйста, подтвердите, что вы действительно желаете это сделать, понимаете последствия своих действий, и делаете это в соответствии [[{{MediaWiki:Policy-url}}|с правилами]].",
        "actioncomplete": "Действие выполнено",
        "actionfailed": "Действие не выполнено",
        "deleting-backlinks-warning": "<strong>Предупреждение:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Другие страницы]] ссылаются на страницу, которую вы собираетесь удалить, или содержат её.",
        "deleting-subpages-warning": "<strong>Предупреждение:</strong> У страницы, которую вы собираетесь удалить, имеется [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|$1 подстраница|$1 подстраницы|$1 подстраниц|51=более 50 подстраниц}}]].",
        "rollback": "Откатить изменения",
+       "rollback-confirmation-confirm": "Пожалуйста, подтвердите:",
+       "rollback-confirmation-yes": "Откатить",
+       "rollback-confirmation-no": "Отмена",
        "rollbacklink": "откатить",
        "rollbacklinkcount": "откатить $1 {{PLURAL:$1|правку|правки|правок}}",
        "rollbacklinkcount-morethan": "откатить более $1 {{PLURAL:$1|правки|правок}}",
        "revertpage": "Откат правок [[Special:Contributions/$2|$2]] ([[User talk:$2|обсуждение]]) к версии [[User:$1|$1]]",
        "revertpage-nouser": "Откат правок (имя участника скрыто) к версии {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Откачены правки {{GENDER:$3|$1}}; возвращена последняя версия {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Откачены правки $1; возвращена последняя версия $2. [$3 Показать изменения]",
        "sessionfailure-title": "Ошибка сеанса",
        "sessionfailure": "Похоже, возникли проблемы с текущим сеансом работы;\nэто действие было отменено в целях предотвращения «захвата сеанса».\nПожалуйста, переотправьте форму.",
        "changecontentmodel": "Редактирование контентной модели страницы",
        "namespace": "Пространство имён:",
        "invert": "Обратить выбранное",
        "tooltip-invert": "Установите эту отметку, чтобы скрыть изменения на страницах, в пределах выбранного пространства имён (и связанных пространств имён, если указано)",
-       "tooltip-whatlinkshere-invert": "Установите этот флажок, чтобы Скрыть ссылки от страниц в выбранном пространстве имен.",
+       "tooltip-whatlinkshere-invert": "Установите этот флажок, чтобы скрыть ссылки от страниц в выбранном пространстве имён.",
        "namespace_association": "Связанное пространство",
        "tooltip-namespace_association": "Установите эту отметку, чтобы также включить пространство имён обсуждения (или предметное), связанное с выбранным пространством имён",
        "blanknamespace": "(Основное)",
        "mycontris": "Вклад",
        "anoncontribs": "Вклад",
        "contribsub2": "Вклад {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "Для {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "Не зарегистрировано учётной записи «$1».",
        "negative-namespace-not-supported": "Пространства имён с отрицательными значениями не поддерживаются.",
        "nocontribs": "Изменений, соответствующих заданным условиям, не найдено.",
        "ipb-confirm": "Подтвердить блокировку",
        "ipb-sitewide": "Во всём проекте",
        "ipb-partial": "Частичная",
+       "ipb-sitewide-help": "Каждая страница вики и все другие действия вклада.",
+       "ipb-partial-help": "Конкретные страницы или пространства имён.",
        "ipb-pages-label": "Страницы",
        "ipb-namespaces-label": "Пространства имён",
        "badipaddress": "IP-адрес записан в неправильном формате, или участника с таким именем не существует.",
        "blocklist-userblocks": "Скрыть блокировки учётных записей",
        "blocklist-tempblocks": "Скрыть временные блокировки",
        "blocklist-addressblocks": "Скрыть блокировки отдельных IP",
+       "blocklist-type": "Тип:",
+       "blocklist-type-opt-all": "Все",
+       "blocklist-type-opt-sitewide": "Во всём проекте",
+       "blocklist-type-opt-partial": "Частичная",
        "blocklist-rangeblocks": "Скрыть блокировки диапазонов",
        "blocklist-timestamp": "Дата/время",
        "blocklist-target": "Цель",
        "blocklist-editing-page": "страницы",
        "blocklist-editing-ns": "пространства имён",
        "ipblocklist-empty": "Список блокировок пуст.",
-       "ipblocklist-no-results": "Ð\97аданнÑ\8bй IP-адÑ\80еÑ\81 Ð¸Ð»Ð¸ Ð¸Ð¼Ñ\8f Ñ\83Ñ\87аÑ\81Ñ\82ника Ð½Ðµ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¸Ñ\80ованÑ\8b.",
+       "ipblocklist-no-results": "Ð\9dе Ð½Ð°Ð¹Ð´ÐµÐ½Ð¾ Ð±Ð»Ð¾ÐºÐ¸Ñ\80овок, Ñ\81ооÑ\82веÑ\82Ñ\81Ñ\82вÑ\83Ñ\8eÑ\89иÑ\85 Ð·Ð°Ð´Ð°Ð½Ð½Ð¾Ð¼Ñ\83 IP-адÑ\80еÑ\81Ñ\83 Ð¸Ð»Ð¸ Ð¸Ð¼ÐµÐ½Ð¸ Ñ\83Ñ\87аÑ\81Ñ\82ника.",
        "blocklink": "заблокировать",
        "unblocklink": "разблокировать",
        "change-blocklink": "изменить блокировку",
+       "empty-username": "(имя участника недоступно)",
        "contribslink": "вклад",
        "emaillink": "отправить письмо",
        "autoblocker": "Автоблокировка из-за того, что ваш IP-адрес недавно использовал «[[User:$1|$1]]».\nПричина блокировки $1: «$2»",
        "allmessagesdefault": "Текст по умолчанию",
        "allmessagescurrent": "Текущий текст",
        "allmessagestext": "Это список системных сообщений, доступных в пространстве имён «MediaWiki».\nЕсли вы хотите внести вклад в общую локализацию MediaWiki, пожалуйста, посетите страницу [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation описания локализации] и проект [https://translatewiki.net translatewiki.net].",
-       "allmessagesnotsupportedDB": "Эта страница недоступна, так как отключена опция '''$wgUseDatabaseMessages'''.",
+       "allmessages-not-supported-database": "Эта страница недоступна, так как отключена опция '''$wgUseDatabaseMessages'''.",
        "allmessages-filter-legend": "Фильтр",
        "allmessages-filter": "Фильтр по статусу изменения:",
        "allmessages-filter-unmodified": "Неизменённые",
        "interlanguage-link-title": "$1 — $2",
        "common.css": "/* Размещённый здесь CSS будет применяться ко всем темам оформления */",
        "print.css": "/* Размещённый здесь CSS будет применяться к версии для печати */",
-       "noscript.css": "/* Размещённый здесь CSS будет применяться для участников с отключенным JavaScript  */",
+       "noscript.css": "/* Размещённый здесь CSS будет применяться для участников с отключённым JavaScript  */",
        "group-autoconfirmed.css": "/* Размещённый здесь CSS будет применяться для автоподтверждённых участников */",
        "group-user.css": "/* Размещённый здесь CSS будет применяться только для зарегистрированных пользователей */",
        "group-bot.css": "/* Размещённый здесь CSS будет применяться только для ботов */",
        "confirmemail_invalidated": "Подтверждение адреса электронной почты отменено.",
        "invalidateemail": "Отмена подтверждения адреса электронной почты",
        "notificationemail_subject_changed": "Адрес электронной почты для {{SITENAME}} был изменён",
-       "notificationemail_subject_removed": "{{SITENAME}} зарегистрированный адрес электронной почты был удален",
-       "notificationemail_body_changed": "Кто-то (вероятно, вы) с IP-адреса $1,\nизменил адрес электронной почты учетной записи «$2» на «$3» на {{SITENAME}}.\n\nЕсли это были не вы, обратитесь к администратору сайта немедленно.",
+       "notificationemail_subject_removed": "{{SITENAME}} зарегистрированный адрес электронной почты был удалён",
+       "notificationemail_body_changed": "Кто-то (вероятно, вы) с IP-адреса $1\nизменил адрес электронной почты учётной записи «$2» на «$3» на сайте {{SITENAME}}.\n\nЕсли это были не вы, обратитесь к администратору сайта немедленно.",
        "notificationemail_body_removed": "Кто-то (вероятно, вы) с IP-адреса $1\nудалил адрес электронной почты учётной записи «$2» на {{SITENAME}}.\n\nЕсли это были не вы, обратитесь к администратору сайта немедленно.",
        "scarytranscludedisabled": "[Интервики-включение отключено]",
        "scarytranscludefailed": "[Ошибка обращения к шаблону $1]",
        "confirm-unwatch-top": "Удалить эту страницу из вашего списка наблюдения?",
        "confirm-rollback-button": "ОК",
        "confirm-rollback-top": "Откатить правки на этой странице?",
+       "confirm-rollback-bottom": "Это действие немедленно откатит выбранные изменения этой страницы.",
        "confirm-mcrrestore-title": "Восстановить версию",
        "confirm-mcrundo-title": "Отменить изменение",
        "mcrundofailed": "Отменить не удалось",
        "logentry-rights-autopromote": "$1 был{{GENDER:$2||а}} автоматически переведен{{GENDER:$2||а}} из $4 в $5",
        "logentry-upload-upload": "$1 загрузил{{GENDER:$2||а}} $3",
        "logentry-upload-overwrite": "$1 загрузил{{GENDER:$2||а}} новую версию $3",
-       "logentry-upload-revert": "$1 Ð·Ð°Ð³Ñ\80Ñ\83зил{{GENDER:$2||а}} $3",
+       "logentry-upload-revert": "$1 Ð²ÐµÑ\80нÑ\83л{{GENDER:$2||а}} $3 Ðº Ñ\81Ñ\82аÑ\80ой Ð²ÐµÑ\80Ñ\81ии",
        "log-name-managetags": "Журнал управления метками",
        "log-description-managetags": "На этой странице перечислены задачи, связанные с управлением [[Special:Tags|метками]]. Журнал содержит только действия, выполненные администратором вручную. Метки могут быть созданы или удалены с помощью программного обеспечения вики без добавления записей в этот журнал.",
        "logentry-managetags-create": "$1 создал{{GENDER:$2||а}} метку «$4»",
        "expand_templates_generate_rawhtml": "Показать HTML",
        "expand_templates_preview": "Предпросмотр",
        "expand_templates_preview_fail_html": "<em>Так как {{SITENAME}} разрешает использовать чистый HTML, предварительный просмотр отключён в качестве меры предотвращения JavaScript-атак.</em>\n\n<strong>Если это добросовестная попытка редактирования, пожалуйста, попробуйте ещё раз.</strong>\nЕсли не получается повторная правка, попробуйте [[Special:UserLogout|завершить сеанс]] работы, заново представиться и проверить, что ваш браузер разрешает использовать cookies на этом сайте.",
-       "expand_templates_preview_fail_html_anon": "<em>Поскольку на сайте {{SITENAME}} включен «сырой» HTML, а вы не авторизовались, предварительный просмотр скрыт в качестве меры предосторожности против JavaScript-атак.</em>\n\n<strong>Если это правомерная попытка предварительного просмотра, пожалуйста, [[Special:UserLogin|войдите]] и попробуйте ещё раз.",
+       "expand_templates_preview_fail_html_anon": "<em>Поскольку на сайте {{SITENAME}} включён «сырой» HTML, а вы не авторизовались, предварительный просмотр скрыт в качестве меры предосторожности против JavaScript-атак.</em>\n\n<strong>Если это правомерная попытка предварительного просмотра, пожалуйста, [[Special:UserLogin|войдите]] и попробуйте ещё раз.",
        "expand_templates_input_missing": "Вы должны вставить хоть какой-то текст.",
        "pagelanguage": "Изменение языка страницы",
        "pagelang-name": "Страница",
        "log-action-filter-suppress-reblock": "Сокрытие пользователя через повторное блокирование",
        "log-action-filter-upload-upload": "Новая загрузка",
        "log-action-filter-upload-overwrite": "Повторно загрузить",
+       "log-action-filter-upload-revert": "Откатить",
        "authmanager-authn-not-in-progress": "Проверка подлинности не выполняется или данные сессии были утеряны. Пожалуйста, начните снова с самого начала.",
        "authmanager-authn-no-primary": "Предоставленные учётные данные не могут быть проверены на подлинность.",
        "authmanager-authn-no-local-user": "Предоставленные учётные данные не связаны ни с одним участником этой вики.",
-       "authmanager-authn-no-local-user-link": "Предоставленные учётные данные корректны, но не связаны ни с одни участником этой вики. Войдите с помощью какого-то другого способа или создайте новую учётную запись, и у вас появится возможность привязать свои предыдущие учётные данные к этой учетной записи.",
+       "authmanager-authn-no-local-user-link": "Предоставленные учётные данные корректны, но не связаны ни с одни участником этой вики. Войдите с помощью какого-то другого способа или создайте новую учётную запись, и у вас появится возможность привязать свои предыдущие учётные данные к этой учётной записи.",
        "authmanager-authn-autocreate-failed": "Автоматическое создание локальной учётной записи не удалось: $1",
        "authmanager-change-not-supported": "Предоставленные учётные данные не могут быть изменены, так как они не будут использованы.",
        "authmanager-create-disabled": "Создание учётных записей отключено.",
        "cannotlink-no-provider-title": "Нет связываемых учётных записей",
        "cannotlink-no-provider": "Нет связываемых учётных записей.",
        "linkaccounts": "Связать учётные записи",
-       "linkaccounts-success-text": "Учетная запись была связана.",
+       "linkaccounts-success-text": "Учётная запись была связана.",
        "linkaccounts-submit": "Связать учётные записи",
        "unlinkaccounts": "Отвязать учётные записи",
-       "unlinkaccounts-success": "Учетная запись была отвязан.",
+       "unlinkaccounts-success": "Учётная запись была отвязан.",
        "authenticationdatachange-ignored": "Изменение данных для проверки подлинности не было обработано. Может быть, не был настроен ни один провайдер?",
        "userjsispublic": "Обратите внимание: подстраницы JavaScript не должны содержать конфиденциальные сведения, поскольку они доступны для просмотра другим участникам.",
        "userjsonispublic": "Обратите внимание: подстраницы JSON не должны содержать конфиденциальных данных, поскольку они доступны для просмотра другими участниками.",
        "gotointerwiki": "Покидаем {{grammar:accusative|{{SITENAME}}}}...",
        "gotointerwiki-invalid": "Указан некорректный заголовок.",
        "gotointerwiki-external": "Вы покидаете {{grammar:accusative|{{SITENAME}}}} для посещения стороннего сайта [[$2]].\n\n'''[$1 Перейти на $1]'''",
-       "undelete-cantedit": "Вы не можете восстановить эту страницу, поскольку у вас недостаточно прав для ее редактирования.",
-       "undelete-cantcreate": "Вы не можете восстановить эту страницу, поскольку она не существует, а у вас недостаточно прав для ее создания.",
+       "undelete-cantedit": "Вы не можете восстановить эту страницу, поскольку у вас недостаточно прав для её редактирования.",
+       "undelete-cantcreate": "Вы не можете восстановить эту страницу, поскольку она не существует, а у вас недостаточно прав для её создания.",
        "pagedata-title": "Данные страницы",
        "pagedata-text": "Эта страница предоставляет интерфейс к данным страниц. Пожалуйста, введите заголовок страницы в URL, используя синтаксис подстраниц.\n* Согласование содержимого применяется основываясь на заголовке Accept вашего клиента. Это означает, что данные страницы будут предоставлены в формате, предпочитаемом вашим клиентом.",
        "pagedata-not-acceptable": "Соответствующий формат не найден. Поддерживаемые MIME-типы: $1",
        "passwordpolicies-policy-passwordcannotbepopular": "Пароль не может соответствовать {{PLURAL:$1|самому часто используемому паролю|какому-либо из $1 самых часто используемых паролей}}",
        "passwordpolicies-policy-passwordnotinlargeblacklist": "Пароль не может соответствовать какому-либо из 100 000 самых часто используемых паролей.",
        "passwordpolicies-policyflag-forcechange": "необходимо изменить при входе",
+       "passwordpolicies-policyflag-suggestchangeonlogin": "предложить изменение при входе",
        "easydeflate-invaliddeflate": "Предоставленное содержимое не спущено надлежащим образом",
-       "unprotected-js": "По соображениям безопасности JavaScript нельзя загружать с незащищенных страниц. Пожалуйста, создавайте скрипты только в пространстве имён MediaWiki: или как подстраницы участника."
+       "unprotected-js": "По соображениям безопасности JavaScript нельзя загружать с незащищённых страниц. Пожалуйста, создавайте скрипты только в пространстве имён MediaWiki: или как подстраницы участника.",
+       "userlogout-continue": "Если вы хотите выйти, [$1 перейдите на страницу выхода].",
+       "userlogout-sessionerror": "Выход из системы не удался из-за ошибки сеанса. Пожалуйста, [$1 попробуйте ещё раз]."
 }
index d5e5473..0171ad6 100644 (file)
        "view": "Видіти",
        "view-foreign": "Видіти на $1",
        "edit": "Едітовати",
+       "edit-local": "Едітовати локальный опис",
        "create": "Створити",
+       "create-local": "Придати локальный опис",
        "delete": "Вымазати",
        "undelete_short": "Обновити $1 {{PLURAL:$1|верзію|верзії|верзії}}",
        "viewdeleted_short": "Видїти {{PLURAL:$1|змазанов едітаціёв|$1 змазаны едітації|$1 змазаных едітацій}}",
        "jumptonavigation": "навіґація",
        "jumptosearch": "Найти",
        "view-pool-error": "Перебачте, серверы суть теперь переладованы.\nТоту сторінку собі теперь пoзерать много хоснователїв.\nПросиме Вас, почекайте і спробуйте доступность пізнїше.\n\n$1",
+       "generic-pool-error": "Перебачте, серверы суть теперь переладованы.\nТоту сторінку собі теперь пoзерать много хоснователїв.\nПросиме Вас, почекайте і спробуйте доступность пізнїше.",
        "pool-timeout": "Час скінчіня чекать про замок",
        "pool-queuefull": "Фронта є повна",
        "pool-errorunknown": "Незнама хыба",
        "ns-specialprotected": "Шпеціалны сторінкы не є можне едітовати.",
        "titleprotected": "Створїня сторінкы з таков назвов было заборонене хоснователём [[User:$1|$1]] з причінов: <em>$2</em>.",
        "filereadonlyerror": "Не годно змінити файл „$1“, бо архів файлів „$2“ є теперь лем на чітаня.\n\nАдміністратор сервера, котрый архів заблоковав, додав тото пояснїня: „''$3''“.",
+       "invalidtitle": "Неприпустна назва",
        "invalidtitle-knownnamespace": "Непряавилна назва в просторї назв „$2“ і текстом „$3“",
        "invalidtitle-unknownnamespace": "Неправилна назва з незнамым чіслом простору назв $1 і текстом „$2“",
        "exception-nologin": "Не сьте приголошеный(а)",
        "resetpass_submit": "Наставити гесло і приголосити ся",
        "changepassword-success": "Ваше гесло было змінено!",
        "changepassword-throttled": "Зробили сьте дуже много спроб о приголошіня.\nПросиме Вас, почекайте $1 перед далшов спробов.",
+       "botpasswords-label-create": "Створити",
+       "botpasswords-label-update": "Обновити",
+       "botpasswords-label-cancel": "Зрушыти",
+       "botpasswords-label-delete": "Вымазати",
        "resetpass_forbidden": "Гесла не є можне змінити",
        "resetpass_forbidden-reason": "Гесла не є можне змінити: $1",
        "resetpass-no-info": "Ку тій сторінцї мають прямый приступ лем приголошены хоснователї.",
        "action-createpage": "створити тоту сторінку",
        "action-createtalk": "створити тоту діскузну сторінку",
        "action-createaccount": "Вытворїня того конта хоснователя",
+       "action-history": "зобразити історію той сторінкы",
        "action-minoredit": "означіти тото едітованя як мале",
        "action-move": "Переменовати тоту сторінку",
        "action-move-subpages": "переменованя той сторінкы зо вшыткыма єй підсторінками",
        "action-upload_by_url": "наладовати тот файл з URL адресы",
        "action-writeapi": "хосновати API про писаня",
        "action-delete": "Вымазати тоту сторінку",
-       "action-deleterevision": "вымазати тоту ревізію сторінкы",
-       "action-deletedhistory": "зобразити історію змазаных ревізій той сторінкы",
+       "action-deleterevision": "вымазаня ревізій",
+       "action-deletedhistory": "зобразити історію змазаных ревізій сторінкы",
+       "action-deletedtext": "зобразити змазаны тексты ревізії",
        "action-browsearchive": "глядати змазаны сторінкы",
        "action-undelete": "обновити тоту сторінку",
-       "action-suppressrevision": "Ñ\81конÑ\82Ñ\80олÑ\91ваÑ\82и Ñ\96 Ð¾Ð±Ð½Ð¾Ð²Ð¸Ñ\82и Ñ\82оÑ\82Ñ\83 Ñ\81Ñ\85ованÑ\83 Ñ\80евÑ\96зÑ\96Ñ\8e",
+       "action-suppressrevision": "Ñ\81конÑ\82Ñ\80олÑ\91ваÑ\82и Ñ\96 Ð¾Ð±Ð½Ð¾Ð²Ð¸Ñ\82и Ñ\81Ñ\85ованÑ\8b Ñ\80евÑ\96зÑ\96Ñ\97",
        "action-suppressionlog": "перегляд того пріватного лоґу",
        "action-block": "блокованя того хоснователя",
        "action-protect": "змінити рівень охраны той сторінкы",
        "action-rollback": "швыдко вернути управы послїднёго хоснователя едітуючого дану сторінку",
-       "action-import": "Ñ\96мпоÑ\80Ñ\82 Ñ\82ой Ñ\81Ñ\82оÑ\80Ñ\96нкÑ\8b з іншой вікі",
-       "action-importupload": "Ñ\96мпоÑ\80Ñ\82 Ñ\82ой Ñ\81Ñ\82оÑ\80Ñ\96нкÑ\8b Ð· файлу",
+       "action-import": "Ñ\96мпоÑ\80Ñ\82 Ñ\81Ñ\82оÑ\80Ñ\96нок з іншой вікі",
+       "action-importupload": "Ñ\96мпоÑ\80Ñ\82 Ñ\81Ñ\82оÑ\80Ñ\96нок Ð· Ð½Ð°Ð»Ð°Ð´Ð¾Ð²Ð°Ð½Ñ\8f файлу",
        "action-patrol": "позначіти чуджі едітованя як перевірены",
        "action-autopatrol": "означіти властных едітовань як патролованы",
        "action-unwatchedpages": "зображіня списку неслїдованых сторінок",
        "action-viewmywatchlist": "перезерати ваш список слїдованых сторінок",
        "action-viewmyprivateinfo": "перезерати вашы пріватны даны",
        "action-editmyprivateinfo": "едітовати вашы пріватны інформації",
+       "action-editcontentmodel": "едітовати модел обсягу сторінкы",
        "nchanges": "$1 {{PLURAL:$1|зміна|зміны|змін}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|од остатнёй навщівы}}",
        "enhancedrc-history": "історія",
        "minoreditletter": "м",
        "newpageletter": "Н",
        "boteditletter": "б",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|слїдуючій хоснователь|слїдуючі хоснователї|слїдуючіх хоснователїв}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|байтt|байты|байтів}} по змінї",
        "newsectionsummary": "/* $1 */ нова секція",
        "rc-enhanced-expand": "Вказати детайлы",
        "uploaderror": "Під час ладованя ся притрафила хыба",
        "upload-recreate-warning": "'''Увага: Файл з тов назвов быв оперед змазаный ці переменованый.'''\n\nТу є про перегляд зображеный список мазаня і переменованя той сторінкы:",
        "uploadtext": "Ниже даный формуларь служыть на наладовованя файлів. Уж наладованы файлы собі можете перезерати і глядати помочов [[Special:FileList|списку наладованых файлів]], кажде наладованя ся тыж зазначує до [[Special:Log/upload|книгы наладованя]], змазаня суть в [[Special:Log/delete|книзї змазаных сторінок]].\n\nПро вложіня образчіка до сторінкы хоснуйте єден із слїдуючіх способів запису:\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Файл.jpg]]</nowiki></code>''' до сторінкы вложыть цїлый образок,\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Файл.png|thumb|left|Попис]]</nowiki></code>''' вложыть нагляд в рамику зарівнанім на лівый бік, з пописом „Попис“,\n* '''<code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:Файл.ogg]]</nowiki></code>''' вложыть дірект одказ на файл, без того жебы ся зобразив на сторінцї.",
-       "upload-permitted": "Дозволены тіпы  файлів: $1.",
-       "upload-preferred": "Преферованы тіпы файлів: $1",
-       "upload-prohibited": "Заказаны тіпы файлів: $1.",
+       "upload-permitted": "{{PLURAL:$2|Дозволеный формат|Дозволены форматы}} файлів: $1.",
+       "upload-preferred": "{{PLURAL:$2|Преферованый формат|Преферованы форматы}} файлів: $1.",
+       "upload-prohibited": "{{PLURAL:$2|Заказаный формат|Заказаны форматы}} файлів: $1.",
        "uploadlogpage": "Лоґ наладованых файлів",
        "uploadlogpagetext": "Ниже найдете список найновшых файлів. Смотьте [[Special:NewFiles|ґалерію новых образків]] про веце візуалного нагляду.",
        "filename": "Назва файлу:",
        "largefileserver": "Розмір файлу є векшый як ліміт наставленый на сервері.",
        "emptyfile": "Файл, котрый сьте вложыли ся видить быти порожнїй. Могла то запричінити хыба в назві файлу. Просиме, перевірте ці сьте справды хотїли вложыти тот файл.",
        "windows-nonascii-filename": "Тота вікі не підпорує назвы файлів з шпеціалныма сімболами.",
-       "fileexists": "Файл з тов назвов уж екзістує, просиме посмотьте ся на <strong>[[:$1]]</strong>, покы не знаєте напевно, ці хочете тот файл нагородити.\n[[$1|thumb]]",
+       "fileexists": "Файл з тов назвов уж екзістує, просиме сконтролёвати <strong>[[:$1]]</strong>, покы не знаєте напевно, ці хочете тот файл нагородити.\n[[$1|thumb]]",
        "filepageexists": "Пописова сторінка про файл з тов назвов уж была на  <strong>[[:$1]]</strong> створена, але одповідаючій файл дотеперь не екзістує.\nЗгорнутя, котре ту зазначіте, ся на пописовій сторінцї не зобразить.\nКідь там хочете своє згорнутя зобразити, будете мусити дану сторінку едітовати мануално. [[$1|thumb]]",
        "fileexists-extension": "Уже екзістує файл з подобным іменом: [[$2|thumb]]\n* Назва наладованого файлу: <strong>[[:$1]]</strong>\n* Назва екзістуючого файлу: <strong>[[:$2]]</strong>\nВыберте іншу назву.",
        "fileexists-thumbnail-yes": "Тот файл є асі образчік в зменшеній великости ''(нагляд)''. [[$1|thumb]]\nПеревірте файл <strong>[[:$1]]</strong>.\nКідь є вказаный файл векшый, але інакше єднакый, не треба окремо наладовати ёго зменшену верзію.",
        "upload-too-many-redirects": "URL обсягує барз велё напрямлінь",
        "upload-http-error": "Стала ся хыба HTTP: $1",
        "upload-copy-upload-invalid-domain": "Наладовованя копірованём негодно з той домены.",
+       "upload-dialog-title": "Наладовати файл",
+       "upload-dialog-button-cancel": "Зрушыти",
+       "upload-dialog-button-back": "Назад",
+       "upload-dialog-button-done": "Готово",
+       "upload-dialog-button-save": "Уложыти",
+       "upload-dialog-button-upload": "Наладовати",
+       "upload-form-label-infoform-title": "Детайлы",
+       "upload-form-label-infoform-name": "Назва",
+       "upload-form-label-infoform-name-tooltip": "Куртый унікатный тітулок того файлу, котрый буде служыти як ёго назва. Можете хосновати обычайный текст і з павзами. Не вказуйте росшырїня файлу.",
+       "upload-form-label-infoform-description": "Опис",
+       "upload-form-label-infoform-description-tooltip": "Курто попиште вшыткы важны інформації о дїли.\nУ фотоґрафіях спомяните головны зображены обєкты, місце і окацію.",
+       "upload-form-label-usage-title": "Хоснованя",
+       "upload-form-label-infoform-categories": "Катеґорії",
+       "upload-form-label-infoform-date": "Датум",
        "backend-fail-stream": "Не вдало ся транслёвати файл $1.",
        "backend-fail-backup": "Не вдало ся створити резервну копію файлу $1.",
        "backend-fail-notexists": "Файл $1 не існує.",
        "img-auth-nopathinfo": "Ваш сервер не є наштелёваный так, жебы давав тоту інформацію.\nМоже фунґує помочов CGI і img_auth на нім не може фунґовати.\nПосмотьте https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Пожадована стежка не є в конфіґурованім адресарю із наладованыма файлами.",
        "img-auth-badtitle": "З „$1“  ся не дасть створити платна назва сторінкы.",
-       "img-auth-nologinnWL": "Не сьте приголошеный і „$1“ не є на білім списку.",
        "img-auth-nofile": "Файл «$1» не екзістує.",
        "img-auth-isdir": "Пробуєте приступовати до адресаря „$1“.\nДозволеный є лем приступ к файлам.",
        "img-auth-streaming": "Переношать ся „$1“.",
        "allmessagesdefault": "Штандартный текст",
        "allmessagescurrent": "Актуалный текст",
        "allmessagestext": "Тото є список вшыткых повідомлїнь доступных в просторї назв «MediaWiki».\nКідь хочете приспівати ку локалізації софтверу MediaWiki, навщівте [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation локалізачну сторінку на mediawiki.org] і [https://translatewiki.net сервер server translatewiki.net].",
-       "allmessagesnotsupportedDB": "{{ns:special}}:AllMessages не є підпороване, бо wgUseDatabaseMessages є выпнуте.",
+       "allmessages-not-supported-database": "{{ns:special}}:AllMessages не є підпороване, бо wgUseDatabaseMessages є выпнуте.",
        "allmessages-filter-legend": "Філтер",
        "allmessages-filter": "Філтер за станом:",
        "allmessages-filter-unmodified": "Незмінено",
index 0cf3de7..f0c7db2 100644 (file)
        "minoreditletter": "(लघु)",
        "newpageletter": "(नवीनम्)",
        "boteditletter": "(बोट्)",
-       "number_of_watching_users_pageview": "[$1 अवलोकयति {{PLURAL:$1|सदस्यः|सदस्याः}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} परिवर्तनपश्चात् ।",
        "newsectionsummary": "/* $1 */ नवीनविभागः",
        "rc-enhanced-expand": "विवरणानि दृश्यन्ताम्",
        "img-auth-nopathinfo": "पथसूची विनष्टा ।\nते वितारकः सूचनाः प्रेषयितुं संसिद्धः न ।\nएतत् CGI अवलम्बितं स्यात् अपि च img_auth अनुमोदनं न करोति ।\nSee https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "सुदृढितायाम् उत्तारणनिदेशिकायाम् अभ्यर्थितपथः नास्ति ।",
        "img-auth-badtitle": "\"$1\"तः मान्यशीर्षिकां निर्मातुं न शक्यते ।",
-       "img-auth-nologinnWL": "नामाभिलेखेन न प्रविष्टः अपिच $1 तु श्वेतावली न ।",
        "img-auth-nofile": "\"$1\" इति सञ्चिका न वर्तते ।",
        "img-auth-isdir": "भवान् \"$1\"निदेशिकाम् अभिगन्तुं यतते ।\nसञ्चिकाभिगमनम् एव अनुमतम् ।",
        "img-auth-streaming": "\"$1\"इत्यस्य प्रवाहिनी ।",
        "allmessagesdefault": "मूलसन्देशः",
        "allmessagescurrent": "सद्यः सन्देशपाठः ।",
        "allmessagestext": "मीडियाविकि इत्यनेन नामाकाशेन सह सल्लग्नानां यन्त्रजनीतानां सूचनानाम् आवलिः अत्र अस्ति । कृपया अत्र [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation], अत्र [https://translatewiki.net translatewiki.net] if you wish to contribute to the generic MediaWiki localisation. च गच्छतु ।",
-       "allmessagesnotsupportedDB": "अस्य पुटस्य उपयोगः नैव शक्यते यतः '''$wgUseDatabaseMessages''' तटास्थम् अस्ति ।",
+       "allmessages-not-supported-database": "अस्य पुटस्य उपयोगः नैव शक्यते यतः '''$wgUseDatabaseMessages''' तटास्थम् अस्ति ।",
        "allmessages-filter-legend": "शोधनी ।",
        "allmessages-filter": "ग्राहकीकरणस्य स्थितौ शोधनी ।",
        "allmessages-filter-unmodified": "अपरिष्कृतम् ।",
index 3680088..2b92620 100644 (file)
@@ -64,6 +64,7 @@
        "tog-norollbackdiff": "Төннөрүү кэнниттэн барыллар уратыларын көрдөрүмэ",
        "tog-useeditwarning": "Уларытыыларбын бигэргэппэккэ сирэйтэн тахсаары гыннахпына сэрэтээр",
        "tog-prefershttps": "Манна киирэргэ куруук көмүскэллээх холбонууну туттарга",
+       "tog-showrollbackconfirmation": "Сигэни баттаатахха дьайыыга бигэргэтиини көрдөр",
        "underline-always": "Куруук",
        "underline-never": "Аннынан тардыма",
        "underline-default": "Браузер туруоруутунан",
        "userlogout": "Тахсыы",
        "notloggedin": "Ааккын эппэтиҥ",
        "userlogin-noaccount": "Бэлиэтэнэ иликкин дуо?",
-       "userlogin-joinproject": "{{SITENAME}} Ñ\81иÑ\82им-Ñ\81иÑ\80гÑ\8d ÐºÐ¸Ð¸Ñ\80ии",
+       "userlogin-joinproject": "{{SITENAME}} Ñ\81иÑ\82им-Ñ\81иÑ\80гÑ\8d Ð±Ñ\8dлиÑ\8dÑ\82Ñ\8dнии",
        "createaccount": "Бэлиэтэнии",
        "userlogin-resetpassword-link": "Аһарык тылгын санаттараҕын дуо?",
        "userlogin-helplink2": "Киирэргэ көмө",
        "badretype": "Аһарыктарыҥ сөп түбэспэтилэр.",
        "usernameinprogress": "Бу аатынан бэлиэтэнии бара турар.\nБука диэн кэтэһэ түс.",
        "userexists": "Суруйбут аатыҥ бэлиэр баар.\nБука диэн, атын аатта тал.",
+       "createacct-normalization": "Эн бэлиэтэммит аатыҥ техника хааччаҕын учуоттаан маннык буолуо «$2».",
        "loginerror": "Ааккын система билбэтэ",
        "createacct-error": "Бэлиэтэнии кэмигэр алҕас таҕыста",
        "createaccounterror": "Саҥа аат бэлиэтиир кыах суох: $1",
        "resetpass-abort-generic": "Аһарыгы уларытыыны кэҥэтии тохтотто.",
        "resetpass-expired": "Аһарыгыҥ болдьоҕо ааспыт эбит. Бука диэн, саҥа аһарыкта туруорун.",
        "resetpass-expired-soft": "Аһарыгыҥ болдьоҕо бүппүт, онон уларытыллыахтаах эбит. Бука диэн атын аһарыкта суруй эбэтэр маны баттаан кэлин киллэрээр \"{{int:authprovider-resetpass-skip-label}}\".",
-       "resetpass-validity-soft": "Аһарыгыҥ алҕастаах: $1\n\nБука диэн саҥа аһарыкта суруй эбэтэр кэлин киллэриэххин баҕарар буоллаххына маны баттаа \"{{int:authprovider-resetpass-skip-label}}\"",
+       "resetpass-validity": "Аһарыгыҥ алҕастаах: $1\n\nСаҥа аһарыкта туруорун дуу.",
+       "resetpass-validity-soft": "Аһарыгыҥ алҕастаах: $1\n\nБука диэн саҥа аһарыкта суруй эбэтэр кэлин суруйуоххун баҕарар буоллаххына маны баттаа \n\"{{int:authprovider-resetpass-skip-label}}\"",
        "passwordreset": "Аһарыгы саҥаттан",
        "passwordreset-text-one": "Урукку аһарыгы уларытарга бу форманы толор.",
        "passwordreset-text-many": "{{PLURAL:$1|Быстах аһарыгы электрон почтаҕар ыыттарарга түннүктэртэн биирдэстэригэр суруй.}}",
        "subject-preview": "Аата маннык көстүөҕэ:",
        "previewerrortext": "Уларытыыгын бигэргэтиэх иннинэ көрдөрөргө алҕас таҕыста.",
        "blockedtitle": "Кыттааччы уларытар кыаҕа быһылынна",
-       "blockedtext": "'''Эн Ð°Ð°Ñ\82Ñ\8bÒ¥ Ñ\8dбÑ\8dÑ\82Ñ\8dÑ\80 IP-аадÑ\8bÑ\80Ñ\8bÒ»Ñ\8bÒ¥ Ð±Ð¾Ð±Ñ\83лÑ\83ннÑ\83лаÑ\80.'''\n\nÐ\91оппÑ\83Ñ\82 ÐºÐ¸Ò»Ð¸ $1.\nТөÑ\80Ò¯Ó©Ñ\82Ñ\8d: ''«$2»''.\n\n*Ð\91обÑ\83ллÑ\83бÑ\83Ñ\82: $8\n*Ð\91обÑ\83Ñ\83 Ð±Ð¾Ð»Ð´Ñ\8cоÒ\95о: $6\n*Ð\91обÑ\83лÑ\83нна: $7\n\nЭн $1 Ð´Ð¸Ñ\8dн ÐºÐ¸Ò»Ð¸Ñ\8dÑ\85Ñ\8d Ñ\8dбÑ\8dÑ\82Ñ\8dÑ\80 Ð°Ñ\82Ñ\8bн [[{{MediaWiki:Grouppage-sysop}}|админиÑ\81Ñ\82Ñ\80ааÑ\82аÑ\80га]] Ñ\81Ñ\83Ñ\80Ñ\83йан Ð±Ñ\8bһааÑ\80Ñ\81Ñ\8bаÑ\85Ñ\85Ñ\8bн Ñ\81өп.\nÐ\91олÒ\95ой, Ó©Ñ\81кө Ñ\80егиÑ\81Ñ\82Ñ\80аÑ\86иÑ\8fламмаÑ\82аÑ\85 Ð±Ñ\83оллаÑ\85Ñ\85Ñ\8bна, Ñ\8dбÑ\8dÑ\82Ñ\8dÑ\80 Ñ\8dл. Ð°Ð°Ð´Ñ\8bÑ\80Ñ\8bÑ\81кÑ\8bн [[Special:Preferences|бигÑ\8dÑ\80гÑ\8dппÑ\8dÑ\82Ñ\8dÑ\85]] Ð±Ñ\83оллаÑ\85Ñ\85Ñ\8bна, Ñ\8dбÑ\8dÑ\82Ñ\8dÑ\80 Ñ\81Ñ\83Ñ\80Ñ\83к Ñ\81Ñ\83Ñ\80Ñ\83йаÑ\80Ñ\8bÒ¥ Ð±Ð¾Ð±Ñ\83ллÑ\83бÑ\83Ñ\82 Ð±Ñ\83оллаÒ\95Ñ\8bна Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñ\81Ñ\82Ñ\80ааÑ\82аÑ\80га Ñ\81Ñ\83Ñ\80Ñ\83йаÑ\80 ÐºÑ\8bаÒ\95Ñ\8bÒ¥ Ñ\81Ñ\83оÑ\85.\nЭн IP-аадÑ\8bÑ\80Ñ\8bÒ»Ñ\8bÒ¥ â\80\94 $3, Ð±Ð¾Ð±Ñ\83Ñ\83 Ð½Ò¯Ó©Ð¼Ñ\8dÑ\80Ñ\8d â\80\94 #$5.\nÐ\9eнÑ\83 Ñ\81Ñ\83Ñ\80Ñ\83ккаÑ\80 ÐºÐ¸Ð»Ð»Ñ\8dÑ\80Ñ\8dÑ\8dр.",
+       "blockedtext": "'''Эн Ð±Ñ\8dлиÑ\8d-ааÑ\82Ñ\8bÒ¥ Ñ\8dбÑ\8dÑ\82Ñ\8dÑ\80 IP-аадÑ\8bÑ\80Ñ\8bÒ»Ñ\8bÒ¥ Ð±Ð¾Ð±Ñ\83ллÑ\83бÑ\83Ñ\82Ñ\82аÑ\80.'''\n\nÐ\91оппÑ\83Ñ\82 Ð´Ñ\8cаһабÑ\8bл - $1.\nТөÑ\80Ò¯Ó©Ñ\82үн Ð¼Ð°Ð½Ñ\8b Ñ\8bйÑ\8bбÑ\8bÑ\82: <em>$2</em>.\n\n*Ð\91обÑ\83ллÑ\83бÑ\83Ñ\82 ÐºÒ¯Ð½Ñ\8d\8bйа: $8\n*Ð\91обÑ\83Ñ\83 Ð±Ð¾Ð»Ð´Ñ\8cоÒ\95о: $6\n*Ð\91обÑ\83Ñ\83 Ñ\81оÑ\80Ñ\83га: $7\n\nЭн $1 Ð´Ð¸Ñ\8dн ÐºÐ¸Ò»Ð¸Ñ\8dÑ\85Ñ\8d Ñ\8dбÑ\8dÑ\82Ñ\8dÑ\80 Ð°Ñ\82Ñ\8bн [[{{MediaWiki:Grouppage-sysop}}|дÑ\8cаһабÑ\8bлга]] Ñ\81Ñ\83Ñ\80Ñ\83йан, Ð±Ñ\8bһааÑ\80Ñ\81Ñ\8bаÑ\85Ñ\85Ñ\8bн Ñ\81өп.\nÐ\91олÒ\95ой, Ó©Ñ\81көÑ\82Ó© Ñ\8dл. Ð°Ð°Ð´Ñ\8bÑ\80Ñ\8bÑ\81кÑ\8bн [[Special:Preferences|Ñ\82Ñ\83Ñ\80Ñ\83оÑ\80Ñ\83Ñ\83лаÑ\80гаÑ\80]] Ñ\8dппÑ\8dÑ\82Ñ\8dÑ\85 Ñ\8dбÑ\8dÑ\82Ñ\8dÑ\80 Ð±Ð¸Ð³Ñ\8dÑ\80гÑ\8dппÑ\8dÑ\82Ñ\8dÑ\85 Ð±Ñ\83оллаÑ\85Ñ\85Ñ\8bна, Ñ\8dбÑ\8dÑ\82Ñ\8dÑ\80 Ð±Ð¾Ð¿Ð¿Ñ\83Ñ\82 ÐºÐ¸Ò»Ð¸ Ñ\81Ñ\83Ñ\80Ñ\83к Ñ\81Ñ\83Ñ\80Ñ\83йаÑ\80гÑ\8bн Ð±Ð¾Ð¿Ð¿Ñ\83Ñ\82 Ð±Ñ\83оллаÒ\95Ñ\8bна, \"{{int:emailuser}}\" Ñ\84Ñ\83нкÑ\86иÑ\8fнÑ\8b Ñ\82Ñ\83һанаÑ\80 ÐºÑ\8bаÒ\95Ñ\8bÒ¥ Ñ\81Ñ\83оÑ\85.\nЭн IP-аадÑ\8bÑ\80Ñ\8bÒ»Ñ\8bÒ¥ â\80\94 $3, Ð±Ð¾Ð±Ñ\83Ñ\83 Ð½Ò¯Ó©Ð¼Ñ\8dÑ\80Ñ\8d â\80\94 #$5.\nÐ\9cанÑ\8b Ñ\81Ñ\83Ñ\80Ñ\83ккаÑ\80 Ñ\8bйаар.",
        "autoblockedtext": "Эн IP-аадырыскын ханнык эрэ бу бырайыакка кыттара бобуллубут киһи туһана сылдьыбыт, онон бу IP-аадырыс бобуулаах. Боппут администраатар ($1) ол төрүөтүн маннык суруйбут:\n\n:''$2''\n\n*Бобуллубут: $8\n*Бобуу болдьоҕо: $6\n*Бобулунна: $7\n\nЭн $1 диэн киһиэхэ эбэтэр атын [[{{MediaWiki:Grouppage-sysop}}|администраатарга]] сурук суруйан быһаарсыаххын сөп.\n\nБолҕой, өскө регистрацияламматах буоллаххына, эбэтэр эл. аадырыскын [[Special:Preferences|бигэргэппэтэх]]  буоллаххына, эбэтэр сурук суруйарыҥ бобуллубут буоллаҕына администраатарга суруйар кыаҕыҥ суох.\n\nIP-аадырыһыҥ $3, бобуу нүөмэрэ — #$5.\nОну суруккар киллэрээр.",
        "systemblockedtext": "Бэлиэ-ааккын эбэтэр IP-аадырыскын MediaWiki хааччахтаабыт.\nЫйыллыбыт төрүөтэ:\n\n:<em>$2</em>\n\n* Хааччах саҕаланыыта: $8\n* Хааччах уһуллуута: $6\n* Бүөлээһин соруга: $7\n\nЭн билиҥҥи IP-аадырыһыҥ $3.\nБыһаарсар буоллаххына, бу сибидиэнньэлэри этээр дуу.",
        "blockednoreason": "биир да биричиинэ сөп түбэспэт",
        "accmailtext": "[[User talk:$1|$1]] кыттааччыга түбэспиччэ бэлиэлэртэн оҥоһуллубут аһарык тыл бу аадырыска $2 ыытылынна.\nТиһиккэ бэлиэтэнэн баран аһарыккын ''[[Special:ChangePassword|уларытыаххын]]'' сөп.",
        "newarticle": "(Саҥа ыстатыйа)",
        "newarticletext": "Эн суох сирэйгэ киирэ сатаатыҥ.\nМаннык ааттаах саҥа ыстатыйаны оҥорор буоллаххына, аллара баар түннүккэ суруй\n(сиһ. [$1 көмөнү] көрүөххүн сөп).\nӨскө манна сыыһа киирбит буоллаххына интэриниэтиҥ бырагыраамматын \"төнүн\" диэххин сөп.",
-       "anontalkpagetext": "----\n<em>Бу аатын эппэтэх, бэлиэтэнэ илик эбэтэр бэлиэтэниэн баҕарбат кыттааччы сирэйэ.</em>\nОл иһин кинини чопчулаары IP-аадырыһын туттабыт.\nБу аадырыһы атын кыттааччылар эмиэ туһаныахтарын сөп.\nӨскөтө Эн ааккын эппэтэх кыттааччы Эйиэхэ туһуламматах суругу туттум дии саныыр буоллаххына, бука диэн, [[Special:CreateAccount|бэлиэтэн]] биитэр [[Special:UserLogin|урут бэлиэтэммит ааккынан киир]]. Оччоҕо булкуур тахсыа суоҕа.",
+       "anontalkpagetext": "----\n<em>Бу аатын эппэтэх, бэлиэтэнэ илик эбэтэр бэлиэтэниэн баҕарбат кыттааччы сирэйэ.</em>\nОл иһин кинини чопчулаары IP-аадырыһын туттабыт.\nБу аадырыһы атын кыттааччылар эмиэ туһаныахтарын сөп.\nӨскөтө Эн, ааккын эппэтэх кыттааччы буоллаххына, Эйиэхэ туһуламматах суругу туттум дии саныыр буоллаххына, бука диэн, [[Special:CreateAccount|бэлиэтэн]] биитэр [[Special:UserLogin|урут бэлиэтэммит ааккынан киир]]. Оччоҕо булкуур тахсыа суоҕа.",
        "noarticletext": "Билигин бу сирэй кураанах.\nБу аат атын ыстатыйаларга туттулларын [[Special:Search/{{PAGENAME}}|булуоххун сөп]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} сурунаалларга көрдүөххүн сөп],\nэбэтэр [{{fullurl:{{FULLPAGENAME}}|action=edit}} маннык ааттаах саҥа ыстатыйаны суруйуоххун сөп]</span>.",
        "noarticletext-nopermission": "Билигин бу сирэй кураанах.\nБу [[Special:Search/{{PAGENAME}}|ааты атын сирэйдэргэ көрдөөн көрүөххүн]] сөп,\nэбэтэр <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} сурунаалларга манна сыһыаннаах суруктары булуоххун сөп].</span> Бу сирэйи айар кыаҕыҥ суох.",
        "missing-revision": "«{{FULLPAGENAME}}» сирэй $1 барыла суох.\n\nМаннык үксүн хайыы-үйэ сотуллубут билэҕэ эргэрбит сигэнэн бардахха буолааччы.\nСиһилии баҕар [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} сотуу сурунаалыгар] баара буолуо.",
        "expansion-depth-exceeded-warning": "Сирэйгэ угуллубут билэлэр аһара элбээбиттэр",
        "parser-unstrip-loop-warning": "Сабыллыбатах pre көһүннэ",
        "unstrip-depth-warning": "Рекурсия ахсаана таһынан барбыт ($1)",
+       "unstrip-size-warning": "Unstrip ($1) кээмэйин лимиитэ куоһарыллыбыт",
+       "unstrip-size-category": "Unstrip кээмэйин лимиитэ куоһарыллыбыт сирэйдэр",
        "converter-manual-rule-error": "Тылы уларытыы быраабылатын алҕаһа таҕыста",
        "undo-success": "Правка может быть отменена. Пожалуйста, просмотрите сравнение версий, чтобы убедиться, что это именно те изменения, которые вас интересуют, и нажмите «Записать страницу», чтобы изменения вступили в силу.",
        "undo-failure": "Уларытыы төннөр кыаҕа суох. Ыккардынааҕы көннөрүүлэр бэйэ бэйэлэригэр сөп түбэспэттэр.",
+       "undo-main-slot-only": "Уларытыыны сотторор кыах суох, тоҕо диэтэххэ иһинээҕитигэр атын дааннайдар эмиэ бааллар.",
        "undo-norev": "Бу көннөрүү сотуллар кыаҕа суох, тоҕо диэтэххэ ончу суох эбэтэр номнуо сотуллубут.",
        "undo-nochange": "Бу уларытыы хайыы-үйэ сотуллубут курдук.",
        "undo-summary": "[[Special:Contributions/$2|$2]] кыттааччы ([[User talk:$2|ырытыы]] | [[Special:Contributions/$2|{{MediaWiki:Contribslink}}]]) $1 нүөмэрдээх уларытыытын сотон оннугар түһэрэргэ.",
        "page_first": "бастакы",
        "page_last": "бүтэһик",
        "histlegend": "Барыллары тэҥнииргэ икки радиокнопканы бэлиэтээ. <br />\nБыһаарыылар: (бил.) = билигин баар барылтан атына,\n(инн.) = инники баар барылтан атына, '''к.''' = улахан суолтата суох көннөрүү.",
-       "history-fieldset-title": "УлаÑ\80Ñ\8bÑ\82Ñ\8bÑ\8bлаÑ\80Ñ\8b ÐºÓ©Ñ\80дөөһүн",
+       "history-fieldset-title": "СиидÑ\8d Ñ\82оÑ\80Ñ\83мнаÑ\80а",
        "history-show-deleted": "Сотуллубуту эрэ",
        "histfirst": "саамай эргэ",
        "histlast": "саамай саҥа",
        "historysize": "({{PLURAL:$1|1 байт|$1 баайтаах}})",
-       "historyempty": "(кураанах)",
+       "historyempty": "кураанах",
        "history-feed-title": "Уларытыы историята",
        "history-feed-description": "Бу сирэй Биикигэ уларыйыытын историята",
        "history-feed-item-nocomment": "$1 манна $2",
        "diff-paragraph-moved-toold": "Параграф көһөрүллүбүт. Баттаан урукку сиригэр көс.",
        "difference-missing-revision": "$2 барыл бу тэҥнээһиҥҥэ ($1) көстүбэтэ.\n\nБу үксүн хайыы-үйэ сотуллубут сирэйи кытта тэҥнээри эргэрбит сигэнэн кэллэххэ баар буолааччы.\nСиһилии баҕар [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} сотуу сурунаалыгар] баара буолуо.",
        "searchresults": "Булулунна",
+       "search-filter-title-prefix": "Мантан саҕаланар «$1» сирэйдэри эрэ көрдөө",
+       "search-filter-title-prefix-reset": "Сирэйдэри барытын көрдөөһүн",
        "searchresults-title": "Көрдөөһүн түмүгэ \"$1\"",
        "titlematches": "Ыстатыйалар ааттара хоһулаһар",
        "textmatches": "Ыстатыйалар истэрэ хатыланар",
        "prefs-watchlist-edits": "Кэтээбил тиһигэр уларытыы көстүүтүн муҥутуур ахсаана:",
        "prefs-watchlist-edits-max": "Улааппыта: 1000",
        "prefs-watchlist-token": "Кэтэбил тиһигин бэлиэтэ (токен):",
+       "prefs-watchlist-managetokens": "Токеннары салайыы",
        "prefs-misc": "Атын туруоруулар",
        "prefs-resetpass": "Кирии тылы уларытыы",
        "prefs-changeemail": "Аадырыһы уларытыы уонна сотуу",
        "stub-threshold-disabled": "Арахсыбыт",
        "recentchangesdays": "Хас хонук иһинэн уларытыылары көрдөрөргө:",
        "recentchangesdays-max": "(улааппыта $1 күн)",
-       "recentchangescount": "Саҥа Ñ\83лаÑ\80Ñ\8bÑ\82Ñ\8bÑ\8bлаÑ\80 ÐºÓ©Ñ\80дөÑ\80үллÑ\8dр ахсааннара:",
-       "prefs-help-recentchangescount": "Ð\91Ñ\83 Ñ\81аҥа ÐºÓ©Ð½Ð½Ó©Ñ\80үүлÑ\8dÑ\80и, Ñ\81иÑ\80Ñ\8dй Ñ\83Ñ\81Ñ\82Ñ\83оÑ\80Ñ\83йалаÑ\80Ñ\8bн Ñ\83онна Ñ\81Ñ\83Ñ\80Ñ\83нааллаÑ\80Ñ\8b ÐºÓ©Ñ\80дөÑ\80Ó©Ñ\80.",
+       "recentchangescount": "Саҥа Ñ\83лаÑ\80Ñ\8bÑ\82Ñ\8bÑ\8bлаÑ\80 Ð¸Ñ\81пииһÑ\8dкÑ\82Ñ\8dÑ\80игÑ\8dÑ\80, Ñ\81иÑ\80Ñ\8dй Ñ\83Ñ\81Ñ\82Ñ\83оÑ\80Ñ\83йаÑ\82Ñ\8bгаÑ\80 Ñ\83онна Ñ\81Ñ\83Ñ\80Ñ\83нааллаÑ\80га ÐºÓ©Ñ\80дөÑ\80үллÑ\8dÑ\80 Ñ\83лаÑ\80Ñ\8bÑ\82Ñ\8bÑ\8bлар ахсааннара:",
+       "prefs-help-recentchangescount": "УлааппÑ\8bÑ\82а: 1000",
        "prefs-help-watchlist-token2": "Бу кэтиир испииһэгиҥ ситим-ханаалын кистэлэҥ күлүүһэ.\nБу күлүүһүнэн ким баҕарар эн испииһэккин көрүөн сөп, онон кимиэхэ да биэримэ. Хаһан баҕарар [[Special:ResetTokens|маны баттаан уларытыаххын]] сөп.",
        "savedprefs": "Эн туруорууларыҥ олохтоннулар.",
        "savedrights": "{{GENDER:$1|$1}} кыттааччы бөлөҕө бигэргэннэ.",
        "default": "чопчу ыйыллыбатаҕына маннык",
        "prefs-files": "Билэлэр",
        "prefs-custom-css": "Бэйэ CSS",
+       "prefs-custom-json": "Тус бэйэ JSON-а",
        "prefs-custom-js": "Бэйэ JS",
        "prefs-common-config": "Бары тиэмэлэргэ биир CSS/JS",
        "prefs-reset-intro": "Бу сирэй көмөтүнэн туруорууларгын саҥаттан туруорар турукка төннөрүөххүн сөп.\nМаны бигэргэттэххинэ билигин баар туруоруулары дэбигис сөргүппэккин.",
        "prefs-dateformat": "Күн-дьыл көрүҥэ (формаата)",
        "prefs-timeoffset": "Кэм уратыта",
        "prefs-advancedediting": "Сүрүн туруоруулар",
+       "prefs-developertools": "Оҥорооччу тэриллэрэ",
        "prefs-editor": "Эрэдээктэр",
        "prefs-preview": "Инники көрүү",
        "prefs-advancedrc": "Дириҥэтиллибит туруоруулар",
        "prefs-advancedwatchlist": "Дириҥэтиллибит туруоруулар",
        "prefs-displayrc": "Туруоруулары көрдөр",
        "prefs-displaywatchlist": "Көстүүтүн туруоруулара",
+       "prefs-changesrc": "Көстүбүт уларытыылар",
+       "prefs-changeswatchlist": "Көрдөр;ллэр уларытыылар",
+       "prefs-pageswatchlist": "Кэтэбилгэ сылдьар сирэйдэр",
        "prefs-tokenwatchlist": "Токен",
        "prefs-diffs": "Уратылара",
        "prefs-help-prefershttps": "Аныгыскы киириигэр үлэлиир буолуо.",
        "group-autoconfirmed": "Аптамаатынан бигэргэтиллибит кыттааччылар",
        "group-bot": "Роботтар",
        "group-sysop": "Дьаһабыллар",
+       "group-interface-admin": "Алтыһаан дьаһабыллара",
        "group-bureaucrat": "Бюрокрааттар",
        "group-suppress": "Ревизордар",
        "group-all": "(бары)",
        "group-autoconfirmed-member": "{{GENDER:$1|аптамаатынан бигэргэтиллибит кыттааччы}}",
        "group-bot-member": "{{GENDER:$1|робот}}",
        "group-sysop-member": "{{GENDER:$1|дьаһабыл}}",
+       "group-interface-admin-member": "{{GENDER:$1|алтыһаан дьаһабыла}}",
        "group-bureaucrat-member": "{{GENDER:$1|бүрэкирээт}}",
        "group-suppress-member": "{{GENDER:$1|ревизор}}",
        "grouppage-user": "{{ns:project}}:Кыттааччылар",
        "grouppage-autoconfirmed": "{{ns:project}}:Аптамаатынан бигэргэммит кыттааччылар",
        "grouppage-bot": "{{ns:project}}:Роботтар",
        "grouppage-sysop": "{{ns:project}}:Дьаһабыллар",
+       "grouppage-interface-admin": "{{ns:project}}:Алтыһаан дьаһабыллара",
        "grouppage-bureaucrat": "{{ns:project}}:Бюрокрааттар",
        "grouppage-suppress": "{{ns:project}}:Ревизордар",
        "right-read": "Сирэйдэри көрүү",
-       "right-edit": "СиÑ\80Ñ\8dйдÑ\8dÑ\80и Ñ\83ларытыы",
+       "right-edit": "Уларытыы",
        "right-createpage": "Сирэйдэри оҥоруу (ырытыы сирэйдэриттэн ураты)",
        "right-createtalk": "Ырытыы сирэйдэрин оҥоруу",
        "right-createaccount": "Саҥа кыттааччыны бэлиэтээһин",
        "right-reupload-own": "Билэлэри суруттарбыт киһи бэйэтэ иккистээн суруттарыыта",
        "right-reupload-shared": "Уопсай ыскылаат билэлэрин локальнай ыскылаат билэлэринэн уларытыы",
        "right-upload_by_url": "URL аадырыстан билэлэри киллэрии",
-       "right-purge": "Ð\9aÑ\8dÑ\8dһи Ð±Ð¸Ð³Ñ\8dÑ\80гÑ\8dÑ\82Ñ\8dÑ\80 Ñ\81иÑ\80Ñ\8dйÑ\8d Ñ\81Ñ\83оÑ\85 ыраастааһын",
+       "right-purge": "СиÑ\80Ñ\8dй ÐºÑ\8dÑ\8dһин ыраастааһын",
        "right-autoconfirmed": "IP түргэнигэр олоҕурбут хааччахтан тутулуктаныма",
        "right-bot": "аптамаат быһыытынан ааҕыллар",
        "right-nominornewtalk": "Ырытыы сирэйдэригэр кыра көннөрүүлэр суох буоллахтарына саҥа этии эрэсиимэ холбонор",
        "right-editusercss": "Атын кыттааччылар CSS-билэлэрин уларытыы",
        "right-edituserjson": "Атын кыттааччылар JSON-билэлэрин уларытыы",
        "right-edituserjs": "Атын кыттааччылар JS-билэлэрин уларытыы",
+       "right-editsitecss": "CSS-билэлэри уларытыы",
+       "right-editsitejson": "JSON-билэлэри уларытыы",
+       "right-editsitejs": "JavaScript-билэлэри уларытыы",
        "right-editmyusercss": "Кыттааччы CSS-билэтин уларытыы",
+       "right-editmyuserjson": "Тус  бэйэ JSON-билэлэрин уларытыы",
        "right-editmyuserjs": "Бэйэ JavaScript-билэлэрин уларытыы",
        "right-viewmywatchlist": "Бэйэ кэтиир тиһигин көрүү",
        "right-editmywatchlist": "Бэйэ кэтиир тиһигин уларытыы. Болҕой, сорох дьайыыларыҥ бу быраабы биэрбэтэҕиҥ да иһин сирэйдэри тиһиккэ эбиэхтэрин сөп.",
        "action-changetags": "ханнык баҕарар тиэктэри сурунаал биирдиилээн уларытыыларыгар уонна суруктарыгар эбэри уонна сотору көҥүллээ",
        "action-deletechangetags": "тиэктэри билии олоҕуттан сотуу",
        "action-purge": "сирэй кээһин ыраастааһын",
+       "action-bigdelete": "уһун устуоруйалаах сирэйдэри сотуу",
+       "action-blockemail": "эл. суругу ыытары бобуу",
+       "action-bot": "аптамаат быһыытынан ааҕыллар",
+       "action-editinterface": "кыттааччы алтыһаанын уларытыы",
+       "action-editusercss": "атын кыттааччылар CSS-билэлэрин уларытыы",
+       "action-edituserjson": "атын кыттааччылар JSON-билэлэрин уларытыы",
+       "action-edituserjs": "Атын кыттааччылар JavaScript-билэлэрин уларытыы",
+       "action-editsitecss": "ситим-сир CSS-билэлэрин уларытыы",
        "nchanges": "$1 {{PLURAL:$1|уларытыы|уларытыылар}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|тиһэх сылдьыыгыттан}}",
        "enhancedrc-history": "устуоруйата",
        "rcfilters-filter-editsbyself-description": "Бэйэҥ уларытыыларыҥ.",
        "rcfilters-filter-editsbyother-label": "Атыттар уларытыылара",
        "rcfilters-filter-editsbyother-description": "Атыттар уларытыылара (Эйиэниттэн ураты).",
-       "rcfilters-filtergroup-userExpLevel": "Бэлиэтэммитинэн уонна уопутун таһымынан",
+       "rcfilters-filtergroup-user-experience-level": "Бэлиэтэммитинэн уонна уопутун таһымынан",
        "rcfilters-filter-user-experience-level-registered-label": "Бэлиэтэммиттэр",
        "rcfilters-filter-user-experience-level-registered-description": "Киирбит эрэдээктэрдэр.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Бэлиэтэммэтэхтэр",
        "rcfilters-hideminor-conflicts-typeofchange-global": "\"Кыра көннөрүүлэр\" сиидэ атын сиидэни эбэтэр сиидэлэри кытта сөп түбэспэтэ, \nтоҕо диэтэххэ сорох көннөрүүлэр кыра дэнэллэрэ сатаммат эбит.\nСөп түбэспэт сиидэлэр үөһэ, Холбоммут сиидэлэр хонууларыгар бэлиэтэммиттэр.",
        "rcfilters-hideminor-conflicts-typeofchange": "Сорох көннөрүүлэр \"кыра\" диэн ааттанар кыахтара суох, онон сиидэ бу сиидэни кытта сөп түбэспэтэ: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Сиидэ бу көрүҥэ кыра көннөрүүлэр сиидэлэрин кытта тапсыбат. Сорох көннөрүүлэр \"кыра\" курдук бэлиэтэнэр кыахтара суох.",
-       "rcfilters-filtergroup-lastRevision": "Тиһэх барыллар",
+       "rcfilters-filtergroup-lastrevision": "Тиһэх барыллар",
        "rcfilters-filter-lastrevision-label": "Тиһэх барыл",
        "rcfilters-filter-lastrevision-description": "Сирэй тиһэх уларыйыыта эрэ.",
        "rcfilters-filter-previousrevision-label": "Тиһэх барыл буолбатах",
        "minoreditletter": "к",
        "newpageletter": "С",
        "boteditletter": "р",
-       "number_of_watching_users_pageview": "[$1 кэтиир {{PLURAL:$1|кыттааччы|кыттааччылар}}]",
        "rc-change-size-new": "Уларытыы кээмэйэ: $1 баайт",
        "newsectionsummary": "/* $1 */ саҥа сиэксийэ",
        "rc-enhanced-expand": "Сиһилии көрдөр",
        "recentchangeslinked-feed": "Сигэнэр уларытыылар",
        "recentchangeslinked-toolbox": "Сигэнэр уларытыылар",
        "recentchangeslinked-title": "\"$1\" кытта сибээстээх уларытыылар",
-       "recentchangeslinked-summary": "Сирэй аатын суруйдаххына киниэхэ эбэтэр кини сигэнэр сирэйдэрин уларытыы көстүөҕэ. (Категорияҕа киирэрэ сирэйдэри көрөргө маннык суруй: Category:Категория аата). [[Special:Watchlist|Кэтиир сирэйдэриҥ]] уларыйыыта <strong>модьу бичигинэн</strong> бэлиэтэммит.",
+       "recentchangeslinked-summary": "Сирэй аатын суруйдаххына киниэхэ эбэтэр кини сигэнэр сирэйдэрин уларытыы көстүөҕэ. (Категорияҕа киирэр сирэйдэри көрөргө маннык суруй: {{ns:category}}:Категория аата). [[Special:Watchlist|Кэтиир сирэйдэриҥ]] уларыйыыта <strong>модьу бичигинэн</strong> бэлиэтэнэр.",
        "recentchangeslinked-page": "Сирэй аата:",
        "recentchangeslinked-to": "Төттөрүтүн, ыйыллыбыт сирэйгэ сигэнэр сирэйдэри көрдөр",
        "recentchanges-page-added-to-category": "[[:$1]] категорияҕа эбилиннэ",
        "img-auth-nopathinfo": "PATH_INFO суох.\nЭн сиэрбэриҥ маннык сибидиэнньэни ыытарга туруоруллубатах эбит.\nБаҕар кини CGI олоҕурара буолуо ол иһин img_auth өйөөбөтө буолуо.\nМаны https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization көр.",
        "img-auth-notindir": "Көрдөөбүт суолуҥ эрдэттэн туруоруллубут хачайдыыр паапкаҕа сыһыана суох.",
        "img-auth-badtitle": "Мантан «$1» сөптөөх ааты оҥорор кыах суох.",
-       "img-auth-nologinnWL": "Эн тиһиликкэ киирбэтэххин, уонна «$1» үрүҥ (көҥүллэммит) тиһиккэ киирбэт эбит.",
        "img-auth-nofile": "«$1» билэ суох.",
        "img-auth-isdir": "Бу паапакаҕа «$1» киирэ сатыыгын.\nБилэлэргэ эрэ киирэр көҥүллэммит.",
        "img-auth-streaming": "Ботуогунан биэрии «$1».",
        "filehist-filesize": "Билэ кээмэйэ",
        "filehist-comment": "Хос быһаарыы",
        "imagelinks": "Билэни туттуу",
-       "linkstoimage": "Бу билэҕэ маннык атын {{PLURAL:$1|сирэй сигэнэр|$1 сирэйдэр сигэнэллэр}}:",
-       "linkstoimage-more": "$1 {{PLURAL:$1|сирэйтэн|сирэйтэн}} элбэх сирэй бу билэҕэ сигэнэр.\nОнтон бу тиһиккэ {{PLURAL:$1|$1 эрэ сигэ көһүннэ|$1 сигэ эрэ көһүннэ}}.\nӨссө [[Special:WhatLinksHere/$2|толору тиһиги]] көрүөххүн сөп.",
-       "nolinkstoimage": "Атын сирэйдэр бу билэҕэ сигэммэттэр.",
+       "linkstoimage": "Бу билэни бу {{PLURAL:$1|сирэй туһанар|$1 сирэйдэр туһаналлар}}:",
+       "linkstoimage-more": "$1 {{PLURAL:$1|сирэйтэн|сирэйтэн}} элбэх сирэй бу билэни туһанар.\nБу испииһэккэ {{PLURAL:$1|$1 эрэ туһанар сирэй көрдөрүлүннэ|$1 эрэ туһанар сирэй көрдөрүлүннэ}}.\nЭбии [[Special:WhatLinksHere/$2|толору испииһэги]] көрүөххүн сөп.",
+       "nolinkstoimage": "Атын сирэйдэр бу билэни туһамматтар.",
        "morelinkstoimage": "Бу билэҕэ [[Special:WhatLinksHere/$1|атын сигэлэри]] көрөргө.",
        "linkstoimage-redirect": "$1 (утаарыы-билэ) $2",
        "duplicatesoffile": "Бу билэ {{PLURAL:$1|дубликаата манна көстөр|$1 дубликаата манна көстөллөр}} ([[Special:FileDuplicateSearch/$2|сиһилии]]):",
        "revertpage": "([[User talk:$2|Ырытыы]]) көннөрүүлэрэ: [[Special:Contributions/$2|$2]] бу торумҥа: [[User:$1|$1]] төннөрүлүннүлэр",
        "revertpage-nouser": "Аата кистэммит киһи уларытыылара суох оҥоһуллан, ыстатыйа бу киһи барылыгар төннөрүлүннэ: {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "{{GENDER:$3|$1}} көннөрүүтэ сотулунна; {{GENDER:$4|$2}} барылыгар төннөрүлүннэ.",
-       "rollback-success-notify": "$1 уларытыылара сотулуннулар; \n$2 тиһэх торумугар төннөрүлүннэ. [$3 Уларытыыны көрдөр]",
        "sessionfailure-title": "Сиэссийэ алҕаһа",
        "sessionfailure": "Арааһа туох эрэ сатаммата, дьайыыҥ оҥоһуллубата. Браузергар \"Төнүн\" тимэҕи баттаа уонна бу иннинээҕи сирэйгин иккистээн киллэрэн көр.",
        "changecontentmodel": "Сирэй ис тутулун киэбин уларытыы",
        "allmessagesdefault": "Туспа этиллибэтэҕинэ суруллар тиэкис",
        "allmessagescurrent": "Билиҥҥи тиэкис",
        "allmessagestext": "Манна MediaWiki биллэриилэрин испииһэгэ көстөр.\nЭн MediaWiki алтыһаанын тылбаастыырга көмөлөһүөххүн баҕарар буоллаххына манна [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation МедиаВикини тылбаастааһын] уонна манна [https://translatewiki.net translatewiki.net] киир.",
-       "allmessagesnotsupportedDB": "'''{{ns:special}}:Allmessages''' туттуллар кыаҕа суох, тоҕо диэтэххэ '''$wgUseDatabaseMessages''' араарыллыбыт.",
+       "allmessages-not-supported-database": "'''{{ns:special}}:Allmessages''' туттуллар кыаҕа суох, тоҕо диэтэххэ '''$wgUseDatabaseMessages''' араарыллыбыт.",
        "allmessages-filter-legend": "Сиидэ",
        "allmessages-filter": "Уларытыы көрүҥүнэн наардыыр сиидэ:",
        "allmessages-filter-unmodified": "Уларытыллыбатахтар",
index 9768a57..4a743c5 100644 (file)
        "page_first": "ᱯᱟᱹᱦᱤᱞ",
        "page_last": "ᱢᱩᱪᱟᱹᱫ",
        "histlegend": "ᱮᱴᱟᱜ ᱵᱟᱪᱷᱟᱣ: ᱱᱟᱣᱟ ᱵᱚᱫᱚᱞᱠᱚ ᱛᱩᱞᱟᱹᱣ ᱢᱮᱱᱠᱷᱟᱱ, ᱨᱮᱰᱤᱭᱳ ᱵᱟᱠᱥᱚᱨᱮ ᱪᱤᱱ ᱮᱢ ᱠᱟᱛᱮ ᱵᱚᱞᱚᱜ ᱥᱮ ᱞᱟᱛᱟᱨ ᱨᱮᱱᱟᱜ ᱵᱟᱴᱚᱱ ᱞᱤᱱᱢᱮ᱾<br />\nᱩᱱᱩᱫᱩᱜ: <strong>({{int:cur}})</strong> = ᱱᱮᱛᱟᱨ ᱥᱩᱫᱷᱨᱟᱹᱣ ᱥᱟᱶᱛᱮ ᱥᱚᱝ, <strong>({{int:last}})</strong> = ᱞᱟᱦᱟ ᱨᱮᱭᱟᱜ ᱱᱟᱣᱟ ᱥᱩᱫᱷᱨᱟᱹᱣ ᱥᱟᱶᱛᱮ ᱥᱚᱝ, <strong>{{int:minoreditletter}}</strong> = ᱦᱩᱰᱤᱧ ᱥᱟᱯᱲᱟᱣ ᱾",
-       "history-fieldset-title": "ᱧᱮá±\9e á±\9fᱹᱨᱩ á±\9eá±\9fá±¹á±\9cᱤᱫ á±¥á±®á±¸á±«á±½á±¨á±\9f",
+       "history-fieldset-title": "ᱧᱮá±\9e á±\9fᱹᱨᱩ á±ªá±·á±\9fᱹᱱᱤ",
        "history-show-deleted": "ᱠᱷᱟᱹᱞᱤ ᱜᱮᱫ ᱜᱤᱰᱤᱭᱟᱜ ᱠᱚᱜᱮ",
        "histfirst": "ᱢᱟᱨᱮᱱᱟᱜ",
        "histlast": "ᱱᱟᱣᱟᱱᱟᱜ",
        "historysize": "({{PLURAL:$1 1 ᱵᱟᱭᱤᱴ $1 ᱵᱟᱭᱤᱴᱥ}})",
-       "historyempty": "(ᱠᱷᱟᱹᱞᱤ)",
+       "historyempty": "ᱠᱷᱟᱹᱞᱤ",
        "history-feed-title": "ᱥᱩᱫᱷᱨᱟᱹᱣ ᱱᱟᱜᱟᱢ",
        "history-feed-description": "ᱣᱤᱠᱤᱨᱮ ᱱᱤᱭᱟᱹ ᱥᱟᱦᱴᱟ ᱵᱚᱫᱚᱞ ᱨᱮᱱᱟᱜ ᱱᱟᱜᱟᱢ",
        "history-feed-item-nocomment": "$2 ᱨᱮ $1",
        "enhancedrc-history": "ᱱᱟᱜᱟᱢ",
        "recentchanges": "ᱨᱚᱠᱟ ᱵᱚᱫᱚᱞᱠᱚ",
        "recentchanges-legend": "ᱱᱟᱣᱟᱱᱟ ᱵᱚᱫᱚᱞ ᱛᱮᱭᱟᱜᱠᱚ",
-       "recentchanges-summary": "á±±á±\9aá±£á±\9f á±¥á±\9fᱦᱴá±\9fᱨᱮ á±©á±­á± á±¤ á±¨á±®á±­á±\9fá±\9c á±¡á±\9aá±\9bá±\9a á± á±·á±\9aá±± á±±á±\9fá±£á±\9f á±µá±\9aᱫá±\9aá±\9eá± á±\9a á±¯á±\9fᱸᱡá±\9fᱸᱭᱢᱮ᱾",
+       "recentchanges-summary": "á±±á±\9aᱶá±\9f á±¥á±\9fᱦᱴá±\9fᱨᱮ á±£á±¤á± á±¤ á±¨á±®á±­á±\9fá±\9c á±¡á±\9aá±\9bá±\9a á± á±·á±\9aá±± á±¨á±\9aá± á±\9f á±µá±\9aᱫá±\9aá±\9eá± á±\9a á±¯á±\9fᱸᱡá±\9fᱸᱭᱢᱮ ᱾",
        "recentchanges-noresult": "ᱮᱢᱞᱮᱱ ᱥᱚᱢᱚᱭ ᱵᱷᱤᱛᱤᱨ ᱨᱮ ᱵᱚᱫᱚᱞᱟᱜ ᱠᱚ ᱵᱟᱭ ᱢᱤᱫᱩᱜ ᱠᱟᱱᱟ ᱾",
-       "recentchanges-feed-description": "ᱱᱚᱣᱟ feed ᱨᱮ ᱩᱭᱠᱤ ᱨᱮᱭᱟᱜ ᱡᱚᱛᱚ ᱠᱷᱚᱱ ᱱᱟᱣᱟ ᱵᱚᱫᱚᱞᱠᱚ ᱯᱟᱸᱡᱟᱸᱭᱢᱮ᱾",
+       "recentchanges-feed-description": "ᱱᱚᱣᱟ ᱯᱷᱤᱰ ᱨᱮ ᱣᱤᱠᱤ ᱨᱮᱭᱟᱜ ᱡᱚᱛᱚ ᱠᱷᱚᱱ ᱱᱟᱣᱟ ᱵᱚᱫᱚᱞᱠᱚ ᱯᱟᱸᱡᱟᱸᱭᱢᱮ᱾",
        "recentchanges-label-newpage": "ᱱᱚᱣᱟ ᱥᱟᱯᱲᱟᱣ ᱢᱤᱫᱴᱮᱱ ᱱᱟᱣᱟ ᱥᱟᱦᱴᱟᱭ ᱛᱮᱭᱟᱨᱠᱮᱫᱟ",
        "recentchanges-label-minor": "ᱱᱚᱣᱟ ᱫᱚ ᱦᱩᱰᱤᱧ ᱥᱟᱯᱲᱟᱣ ᱠᱟᱱᱟ",
        "recentchanges-label-bot": "ᱱᱚᱣᱟ ᱥᱟᱯᱲᱟᱣ ᱫᱚ ᱵᱚᱴ ᱮ ᱠᱚᱨᱟᱣᱠᱟᱫᱟ",
index dee3859..6eda32b 100644 (file)
@@ -10,7 +10,8 @@
                        "Via maxima",
                        "Uharteko",
                        "Taxandru",
-                       "Macofe"
+                       "Macofe",
+                       "Zoranzoki21"
                ]
        },
        "tog-underline": "Sutalìnia sos ligòngios",
index 5e4e2cc..118c6e7 100644 (file)
        "minoreditletter": "n",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[taliata di {{PLURAL:$1|nu utenti|$1 utenti}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|byte}} appressu dû canciamentu",
        "newsectionsummary": "/* $1 */ sizzioni nova",
        "rc-enhanced-expand": "Ammustra li dittagghî",
        "img-auth-nopathinfo": "Variàbbili PATH_INFO ammancanti.\nLu tò server nun è mpustatu pi passari sta nfurmazzioni.\nPurrìa èssiri basatu supra a CGI e nun pò suppurtari img_auth.\nTalìa https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Lu caminu addumannatu nun è ntâ cartella cunfigurata pî carricamenti.",
        "img-auth-badtitle": "Nun fu pussìbbili custruiri nu tìtulu vàlidu a pàrtiri di \"$1\".",
-       "img-auth-nologinnWL": "Nun trasisti e \"$1\" nun è ntâ lista janca.",
        "img-auth-nofile": "Lu file \"$1\" nun esisti.",
        "img-auth-isdir": "Stai pruvannu a accèdiri a na cartella, \"$1\".\nÈ cunzintutu l'accessu sulu ê file.",
        "img-auth-streaming": "Trasmissioni di \"$1\".",
        "allmessagesdefault": "Testu pridifinitu",
        "allmessagescurrent": "Testu attuali",
        "allmessagestext": "Chista è na lista di missaggi di sistema chi s'attròvanu sutta MediaWiki:''nomu''.\nVisita [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] e [https://translatewiki.net translatewiki.net] si voi cuntribbuiri â localizzazioni generica di MediaWiki.",
-       "allmessagesnotsupportedDB": "'''{{ns:special}}:Allmessages''' nun è suppurtatu pirchì lu flag '''$wgUseDatabaseMessages''' nun è attivu.",
+       "allmessages-not-supported-database": "'''{{ns:special}}:Allmessages''' nun è suppurtatu pirchì lu flag '''$wgUseDatabaseMessages''' nun è attivu.",
        "allmessages-filter-legend": "Filtru",
        "allmessages-filter": "Filtru pi statu di canciamentu:",
        "allmessages-filter-unmodified": "Nun canciati",
index c1c3cb9..f8c75ee 100644 (file)
        "rcfilters-filter-editsbyself-description": "Yer awn contreebutions.",
        "rcfilters-filter-editsbyother-label": "Cheenges bi ithers",
        "rcfilters-filter-editsbyother-description": "Aw cheenges except yer awn.",
-       "rcfilters-filtergroup-userExpLevel": "Experience level (for registered uisers anerly)",
+       "rcfilters-filtergroup-user-experience-level": "Experience level (for registered uisers anerly)",
        "rcfilters-filter-user-experience-level-registered-label": "Registered",
        "rcfilters-filter-user-experience-level-registered-description": "Logged-in eeditors.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Unregistered",
        "rcfilters-hideminor-conflicts-typeofchange-global": "The \"Minor eedits\" filter conflicts wi ane or mair Teepe o cheenge filters, acause certain teeps o cheenge canna be designatit as \"minor\". The conflictin filters are merked in the Active filters aurie, abuin.",
        "rcfilters-hideminor-conflicts-typeofchange": "Certain teeps o cheenge canna be designatit as \"minor\", sae this filter conflicts wi the follaein Teepe o Cheenge filters: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "This Teepe o cheenge filter conflicts wi the \"Minor edits\" filter. Certain teeps o cheenge canna be designatit as \"minor\".",
-       "rcfilters-filtergroup-lastRevision": "Last reveesion",
+       "rcfilters-filtergroup-lastrevision": "Last reveesion",
        "rcfilters-filter-lastrevision-label": "Last reveesion",
        "rcfilters-filter-lastrevision-description": "The maist recent cheenge tae a page.",
        "rcfilters-filter-previousrevision-label": "Earlier reveesions",
        "minoreditletter": "s",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 watchin {{PLURAL:$1|uiser|uisers}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} efter chynge",
        "newsectionsummary": "/* $1 */ new section",
        "rc-enhanced-expand": "Shaw details",
        "img-auth-nopathinfo": "Missin PATH_INFO.\nYer server is no set up tae pass this information.\nIt micht be CGI-based n canna support img_auth.\nSee https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Requested path isna in the confeegured uplaid directerie.",
        "img-auth-badtitle": "Onable tae cræft ae valid title fae \"$1\".",
-       "img-auth-nologinnWL": "Ye'r naw loggit in n \"$1\" isna in the whiteleet.",
        "img-auth-nofile": "File \"$1\" disna exeest.",
        "img-auth-isdir": "Ye'r attemptin tae access ae directerie \"$1\".\nYinlie file access is premitit.",
        "img-auth-streaming": "Streamin \"$1\".",
        "allmessagesdefault": "Defaut message tex",
        "allmessagescurrent": "Message tex the nou",
        "allmessagestext": "This is ae leet o seestem messages available in the MediaWiki namespace.\nPlease veesit [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] n [https://translatewiki.net translatewiki.net] gif ye wish tae contreebute tae the generic MediaWiki localisation.",
-       "allmessagesnotsupportedDB": "This page canna be uised cause <strong>$wgUseDatabaseMessages</strong> haes been disablt.",
+       "allmessages-not-supported-database": "This page canna be uised cause <strong>$wgUseDatabaseMessages</strong> haes been disablt.",
        "allmessages-filter-legend": "Filter",
        "allmessages-filter": "Filter b custymization state:",
        "allmessages-filter-unmodified": "Onmodified",
index 4df56ae..29da774 100644 (file)
        "rcfilters-filter-editsbyself-label": "مون پاران تبديليون",
        "rcfilters-filter-editsbyself-description": "توھان جون پنھنجون ڀاڱيداريون.",
        "rcfilters-filter-editsbyother-label": "ٻين پاران تبديليون",
-       "rcfilters-filtergroup-userExpLevel": "واپرائيندڙن جي داخلا ۽ تجربو",
+       "rcfilters-filtergroup-user-experience-level": "واپرائيندڙن جي داخلا ۽ تجربو",
        "rcfilters-filter-user-experience-level-registered-label": "رجسٽر ٿيل",
        "rcfilters-filter-user-experience-level-registered-description": "داخل ٿيل ايڊيٽر.",
        "rcfilters-filter-user-experience-level-unregistered-label": "اڻرجسٽر ٿيل",
        "newpageletter": "نئون",
        "boteditletter": "گ",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|واپرائيندڙ|واپرائيندڙن}} کي نظر ۾ رکندي]",
        "rc-change-size-new": "$1 {{PLURAL:$1|بائيٽ|بائيٽس}} تبديليءَ کانپوءِ",
        "newsectionsummary": "/* $1 */ نئون سيڪشن",
        "rc-enhanced-expand": "تفصيل ڏيکاريو",
index 3811db9..4bc580f 100644 (file)
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[abbaidadda da {{PLURAL:$1|un'utenti|$1 utenti}}]",
        "newsectionsummary": "/* $1 */ noba sezzioni",
        "rc-enhanced-expand": "Musthrà dettagli (dumanda JavaScript)",
        "rc-enhanced-hide": "Cua dettàgli",
        "allmessagesdefault": "Testhu pridifiniddu",
        "allmessagescurrent": "Testhu attuari",
        "allmessagestext": "Chistha è la listha di tutti l'imbasciaddi di sisthema dipunìbiri i' lu tipu di pàgina MediaWiki.\nPa piazeri utirizà [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Lucarizazioni] e [https://translatewiki.net translatewiki.net] pa l'althri traduzioni.",
-       "allmessagesnotsupportedDB": "Chistha pàgina nò è supporthadda parchí l'indicadori '''$wgUseDatabaseMessages''' nò è attibuu.",
+       "allmessages-not-supported-database": "Chistha pàgina nò è supporthadda parchí l'indicadori '''$wgUseDatabaseMessages''' nò è attibuu.",
        "allmessages-filter-unmodified": "Nò mudifiggaddi",
        "allmessages-filter-all": "Tutti",
        "allmessages-filter-modified": "Mudifiggaddi",
index 48ffc2a..d4699ec 100644 (file)
        "show": "čájet",
        "minoreditletter": "u",
        "newpageletter": "O",
-       "number_of_watching_users_pageview": "[$1 čuovvujeaddji geavaheaddji]",
        "recentchangeslinked": "Dán siiddu varas rievdadusat",
        "recentchangeslinked-feed": "Dán siiddu varas rievdadusat",
        "recentchangeslinked-toolbox": "Dán siiddu varas rievdadusat",
index 48dec6a..3f3e7b3 100644 (file)
        "minoreditletter": "b",
        "newpageletter": "H",
        "boteditletter": "R",
-       "number_of_watching_users_pageview": "[$1 cait(o/ó)m cáminot]",
        "newsectionsummary": "/* $1 */ hunseccion",
        "recentchangeslinked": "Quiix hámíigonix",
        "recentchangeslinked-feed": "Quiix hámíigonix",
index 06bfd96..0aa3153 100644 (file)
        "newpageletter": "N",
        "boteditletter": "b",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 goo ma {{PLURAL:$1|goykaa|goykey}} guna]",
        "rc-change-size": "$1",
        "rc-change-size-new": "{{PLURAL:$1|cebsi}} $1 barmaa banda ga",
        "newsectionsummary": "/* $1 */ dunbu taaga",
        "img-auth-nopathinfo": "PATH_INFO ga kuma.\nWar feršikaa mana soolu alhabaroo woo bisandiyanoo se.\nSanda CGI-gorante no nd'a ši nd'a ši hin ka img_auth kanbe.\nSee https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Fondaa kaŋ hãandi ši zijandiyan fooloɲaa hansantaa ra.",
        "img-auth-badtitle": "Ši hin ka maa henna cin ka hun \"$1\" ga.",
-       "img-auth-nologinnWL": "War mana huru nda \"$1\" ši bara maašeede kaaraa ra.",
        "img-auth-nofile": "\"$1\" tuku ši bara.",
        "img-auth-isdir": "War goo ceeci ka huru \"$1\" fooloɲaa ra.\nTuku fondo de ma koy.",
        "img-auth-streaming": "\"$1\" mennandi.",
        "allmessagesdefault": "Tilasu alhabar hantum",
        "allmessagescurrent": "Sohõda alhabar hantum",
        "allmessagestext": "Woo ti dabariɲaa alhabar maašeede kaŋ ga bara MediaWiki maafarroo ra.\nGuna [https://www.mediawiki.org/wiki/Special:MyLanguage/MediaWiki šenni berandiyan] nda [https://translatewiki.net translatewiki.net] nda war ga boona ka kanbuzaamay tee MediaWiki dumi-kul berandiyan se.",
-       "allmessagesnotsupportedDB": "Moɲoo woo ši hin ka goyandi zama <strong>$wgUseDatabaseMessages</strong> n' ka kayandi.",
+       "allmessages-not-supported-database": "Moɲoo woo ši hin ka goyandi zama <strong>$wgUseDatabaseMessages</strong> n' ka kayandi.",
        "allmessages-filter-legend": "Fayhaya",
        "allmessages-filter": "Fay boŋhanseyan alhaali bande:",
        "allmessages-filter-unmodified": "Mana barmay",
index c24b779..d873734 100644 (file)
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "r",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|keravuojontis nauduotuos|keravuojontīs nauduotuojē|keravuojontiu nauduotuoju}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|baits|baitā|baitu}} pu pakeitėma",
        "newsectionsummary": "/* $1 */ naus skėrsnelis",
        "rc-enhanced-expand": "Ruodītė smolkmenas",
        "editcomment": "Padėrbėma paāškėnėms bova: <em>$1</em>.",
        "revertpage": "Atmests [[Special:Contributions/$2|$2]] ([[User talk:$2|aptarėms]]) pakeitėms; sogrōžints atmains, katron padėrba nauduotuos [[User:$1|$1]]",
        "rollback-success": "Atmestė $1 padėrbtė keitėmā; grōžints $2 padėrbts atmains.",
-       "rollback-success-notify": "Atmestė $1 padėrbtė keitėmā; grōžints $2 padėrbts atmains. [$3 ruodītė keitėmus]",
        "sessionfailure-title": "Sesėjės klaida",
        "sessionfailure": "Atruod ka īr biedū so Tamstas prėsėjongėmo; tas vēksmos bova grōžints kāp atsargoma prėimonė nu sesėjės vuogėma.\nPrašoum mīgtė „atgal“ ėr parkrautė poslapi ėš katruo atiejėt, ė pamieginkėt apent.",
        "changecontentmodel-title-label": "Poslapė pavadėnėms",
        "allmessagesdefault": "Pradėnis teksts",
        "allmessagescurrent": "Dabartėnis teksts",
        "allmessagestext": "Čė pateikamė sėstemėniu pranešėmu sārašos, esontis MediaWiki srėtie.",
-       "allmessagesnotsupportedDB": "'''{{ns:special}}:Allmessages''' nepalaikuoms īr, nes nustatīms '''$wgUseDatabaseMessages''' ėšjungts īr.",
+       "allmessages-not-supported-database": "!!FUZZY!!'''{{ns:special}}:Allmessages''' nepalaikuoms īr, nes nustatīms '''$wgUseDatabaseMessages''' ėšjungts īr.",
        "allmessages-filter-legend": "Kuošeklis",
        "allmessages-filter-unmodified": "Naparkeistė",
        "allmessages-filter-all": "Vėsė",
index 2689432..826c164 100644 (file)
        "botpasswords-label-resetpassword": "Stavite novu lozinku",
        "botpasswords-label-grants": "Primjenjive dozvole:",
        "botpasswords-help-grants": "Dozvole vam daje pristup pravima koja već imaju vaš račun. Omogućavanjem dodjele ovdje nećete primati prava koja više nemaju račun. Više informacija možete pronaći na [[Special:ListGrants|tablici dozvole]].",
+       "botpasswords-label-grants-column": "Odobreno",
+       "botpasswords-bad-appid": "Ime bota \"$1\" nije ispravno.",
+       "botpasswords-insert-failed": "Neuspjelo dodavanje imena bota \"$1\". Možda je već dodano?",
+       "botpasswords-update-failed": "Neuspjelo ažuriranje bota s imenom \"$1\". Možda je obrisan?",
+       "botpasswords-created-title": "Lozinka bota je napravljena",
+       "botpasswords-created-body": "Lozinka za bota \"$1\" {{GENDER:$2|korisnika|korisnice}} \"$2\" je napravljena.",
+       "botpasswords-updated-title": "Lozinka bota je izmjenjena",
+       "botpasswords-updated-body": "Lozinka za bota \"$1\" {{GENDER:$2|korisnika|korisnice}} \"$2\" je izmjenjena.",
+       "botpasswords-deleted-title": "Lozinka bota je obrisana",
+       "botpasswords-deleted-body": "Lozinka za bota \"$1\" {{GENDER:$2|korisnika|korisnice}} \"$2\" je obrisana.",
+       "botpasswords-no-provider": "BotPasswordsSessionProvider nije dostupan.",
+       "botpasswords-restriction-failed": "Ne možete se prijaviti zbog ograničenja lozinki za botove.",
+       "botpasswords-invalid-name": "Navedeno korisničko ime ne sadrži rastavni znak za lozinke botova (\"$1\").",
+       "botpasswords-not-exist": "Korisnik \"$1\" nema lozinku bota \"$2\".",
+       "botpasswords-needs-reset": "Lozinka za bota \"$2\" {{GENDER:$1|korisnika|korisnice}} \"$2\" mora se obnoviti.",
+       "botpasswords-locked": "Ne možete da se prijavite s botovskim lozinkom jer je vaš nalog zaključan.",
        "resetpass_forbidden": "Šifre ne mogu biti promjenjene",
+       "resetpass_forbidden-reason": "Lozinke ne mogu biti promijenjene: $1",
        "resetpass-no-info": "Morate biti prijavljeni da bi ste pristupili ovoj stranici direktno.",
        "resetpass-submit-loggedin": "Promijeni lozinku",
        "resetpass-submit-cancel": "Otkaži",
        "subject-preview": "Pretpregled naslova:",
        "previewerrortext": "Dogodila se greška prilikom prikazivanja vaših izmjena.",
        "blockedtitle": "Korisnik je blokiran",
-       "blockedtext": "'''Vaše korisničko ime ili IP adresa je blokirana.'''\n\nBlokada izvršena od strane $1.\nDati razlog je slijedeći: ''$2''.\n\n*Početak blokade: $8\n*Kraj perioda blokade: $6\n*Ime blokiranog korisnika: $7\n\nMožete kontaktirati $1 ili nekog drugog [[{{MediaWiki:Grouppage-sysop}}|administratora]] da biste razgovarali o blokadi.\n\nNe možete koristiti opciju ''Pošalji e-mail korisniku'' osim ako niste unijeli e-mail adresu u [[Special:Preferences|Vaše postavke]].\nVaša trenutna IP adresa je $3, a oznaka blokade je #$5.\nMolimo Vas da navedete gornje podatke u zahtjevu za deblokadu.",
-       "autoblockedtext": "Vaša IP adresa je automatski blokirana jer je korištena od strane drugog korisnika, a blokirao ju je $1.\nNaveden je slijedeći razlog:\n\n:''$2''\n\n* Početak blokade: $8\n* Kraj blokade: $6\n* Blokirani korisnik: $7\n\nMožete kontaktirati $1 ili nekog drugog iz grupe [[{{MediaWiki:Grouppage-sysop}}|administratora]] i zahtijevati da Vas deblokira.\n\nZapamtite da ne možete koristiti opciju \"pošalji e-mail ovom korisniku\" sve dok ne unesete validnu e-mail adresu pri registraciji u Vašim [[Special:Preferences|korisničkim postavkama]] te Vas ne spriječava ga je koristite.\n\nVaša trenutna IP adresa je $3, a ID blokade je $5.\nMolimo da navedete sve gore navedene detalje u zahtjevu za deblokadu.",
+       "blocked-email-user": "<strong>Vašem korisničkom imenu je zabranjeno slanje e-poruka. Još uvijek možete da uređujete druge stranice na ovom wikiju.</strong> \nSve pojedinosti o zabrani naći ćete u [[Special:MyContributions|doprinosima naloga]].\n\nZabranu je dao/la $1.\n\nNaveden je sljedeći razlog: <em>$2</em>.\n\n* Početak zabrane: $8\n* Istek zabrane: $6\n* Namijenjena korisniku/ci ili IP adresi: $7\n* ID zabrane #$5",
+       "blockedtext-partial": "<strong>Vašem korisničkom imenu ili IP adresi je zabranjeno pravljenje izmjena na ovoj stranici. Još uvijek možete da uređujete druge stranice na ovom wikiju.</strong> Sve pojedinosti o zabrani naći ćete u [[Special:MyContributions|doprinosima naloga]].\n\nZabranu je dao/la $1.\n\nNaveden je sljedeći razlog: <em>$2</em>.\n\n* Početak zabrane: $8\n* Istek zabrane: $6\n* Namijenjena korisniku/ci ili IP adresi: $7\n* ID zabrane #$5",
+       "blockedtext": "<strong>Vaše korisničko ime ili IP adresa je blokirana.</strong>\n\nBlokada izvršena od strane $1.\nDati razlog je slijedeći: <em>$2</em>.\n\n* Početak blokade: $8\n* Kraj perioda blokade: $6\n* Ime blokiranog korisnika: $7\n\nMožete kontaktirati $1 ili nekog drugog [[{{MediaWiki:Grouppage-sysop}}|administratora]] da biste razgovarali o blokadi.\nMožete koristiti opciju \"{{int:emailuser}}\" ako je navedena valjana adresa e-pošte u [[Special:Preferences|Vašim postavkama]] i Vam nije zabranjeno je koristiti.\nVaša trenutna IP adresa je $3, a oznaka blokade je #$5.\nMolimo Vas da navedete gornje podatke u zahtjevu za deblokadu.",
+       "autoblockedtext": "Vaša IP adresa je automatski blokirana jer je korištena od strane drugog korisnika, a blokirao ju je $1.\nNaveden je slijedeći razlog:\n\n:<em>$2</em>\n\n* Početak blokade: $8\n* Kraj blokade: $6\n* Blokirani korisnik: $7\n\nMožete kontaktirati $1 ili nekog drugog iz grupe [[{{MediaWiki:Grouppage-sysop}}|administratora]] i zahtijevati da Vas deblokira.\n\nZapamtite da ne možete koristiti opciju \"{{int:emailuser}}\" ukoliko nije unesena validna e-mail adresa u [[Special:Preferences|Vašim postavkama]] te Vas ne spriječava ga je koristite.\n\nVaša trenutna IP adresa je $3, a ID blokade je $5.\nMolimo da navedete sve gore navedene detalje u zahtjevu za deblokadu.",
+       "systemblockedtext": "MediaWiki je automatski blokirao Vaše korisničko ime ili IP-adresu.\nDat je sljedeći razlog:\n\n:<em>$2</em>\n\n* Početak bloka: $8\n* Istek bloka: $6\n* Blok je namijenjen za: $7\n\nVaša trenutna IP-adresa je $3.\nPrepišite sve gorenavedene pojedinosti ukoliko želite da vlasti pitaju za blok.",
        "blockednoreason": "razlog nije naveden",
        "whitelistedittext": "Da bi ste uređivali stranice, morate se $1.",
        "confirmedittext": "Morate potvrditi Vašu e-mail adresu prije nego počnete mijenjati stranice.\nMolimo da postavite i verifikujete Vašu e-mail adresu putem Vaših [[Special:Preferences|korisničkih opcija]].",
        "continue-editing": "Idi na područje uređivanja",
        "previewconflict": "Ovaj pretpregled reflektuje tekst u gornjem polju\nkako će izgledati ako pritisnete \"Snimi stranicu\".",
        "session_fail_preview": "Nažalost, nisam mogao obraditi izmjenu zbog gubitka podataka o sesiji.\n\nMožda ste odjavljeni. <strong>Provjerite jeste li i dalje prijavljeni i pokušajte ponovno.<strong>\nAko se problem nastavi pojavljivati, [[Special:UserLogout|odjavite se]] i ponovno prijavite, te provjerite da preglednik dopušta kolačiće s ovog sajta.",
-       "session_fail_preview_html": "'''Žao nam je! Nismo mogli da obradimo vašu izmjenu zbog gubitka podataka.'''\n\n''Zbog toga što {{SITENAME}} ima omogućen izvorni HTML, predpregled je sakriven kao predostrožnost protiv JavaScript napada.''\n\n'''Ako ste pokušali da napravite pravu izmjenu, molimo pokušajte ponovo. Ako i dalje ne radi, pokušajte da se [[Special:UserLogout|odjavite]] i ponovo prijavite.'''",
+       "session_fail_preview_html": "Žao nam je! Nismo mogli da obradimo vašu izmjenu zbog gubitka sesijskih podataka.\n\n<em>Zbog toga što {{SITENAME}} ima omogućen izvorni HTML, predpregled je sakriven kao predostrožnost protiv JavaScript napada.</em>\n\n<strong>Ako ste pokušali da napravite pravu izmjenu, molimo pokušajte ponovo.</strong>\nAko to ne riješi problem, pokušajte da se [[Special:UserLogout|odjavite]] i ponovo prijavite, i provjerite da preglednik dopušta kolačiće s ovog sajta.",
        "token_suffix_mismatch": "'''Vaša izmjena nije prihvaćena jer je Vaš web preglednik ubacio znakove interpunkcije u token uređivanja.'''\nIzmjena je odbačena da bi se spriječilo uništavanje teksta stranice.\nTo se događa ponekad kad korisite problematični anonimni proxy koji je baziran na web-u.",
        "edit_form_incomplete": "'''Neki dijelovi uređivačkog obrasca nisu došli do servera; dvaput provjerite da su vaše izmjene nepromjenjene i pokušajte ponovno.'''",
        "editing": "Uređujete $1",
        "editingsection": "Uređujete $1 (sekciju)",
        "editingcomment": "Uređujete $1 (nova sekcija)",
        "editconflict": "Sukobljenje izmjene: $1",
-       "explainconflict": "Neko drugi je promujenio ovu stranicu otkad ste Vi počeli da je mijenjate.\nGornje tekstualno polje sadrži tekst stranice koji trenutno postoji.\nVaše izmjene su prikazane u donjem tekstu.\nMoraćete da unesete svoje promjene u postojeći tekst.\n'''Samo''' tekst u gornjem tekstualnom polju će biti snimljen kad pritisnete \"$1\".",
+       "explainconflict": "Neko drugi je promijenio ovu stranicu otkad ste Vi počeli da je mijenjate.\nGornje tekstualno polje sadrži tekst stranice koji trenutno postoji.\nVaše izmjene su prikazane u donjem tekstu.\nMoraćete da unesete svoje promjene u postojeći tekst.\n<strong>Samo</strong> tekst u gornjem tekstualnom polju će biti snimljen kad pritisnete \"$1\".",
        "yourtext": "Vaš tekst / Ваш текст",
        "storedversion": "Uskladištena verzija",
        "editingold": "'''PAŽNJA:  Vi mijenjate stariju reviziju ove stranice.\nAko je snimite, sve promjene učinjene od ove revizije će biti izgubljene.'''",
        "page_first": "prva",
        "page_last": "zadnja",
        "histlegend": "Odabir razlika: označite radio dugme verzija za usporedbu i pritisnite enter ili dugme na dnu.<br />\nObjašnjenje: '''({{int:cur}})''' = razlika sa trenutnom verzijom,\n'''({{int:last}})''' = razlika sa prethodnom verzijom, '''{{int:minoreditletter}}''' = manja izmjena.",
-       "history-fieldset-title": "Pretraga izmjena",
+       "history-fieldset-title": "Filtriraj izmjene",
        "history-show-deleted": "Samo obrisane izmjene",
        "histfirst": "najstarije",
        "histlast": "najnovije",
        "historysize": "({{PLURAL:$1|1 bajt|$1 bajta|$1 bajtova}})",
-       "historyempty": "(prazno)",
+       "historyempty": "prazno",
        "history-feed-title": "Historija izmjena",
        "history-feed-description": "Historija promjena ove stranice na wikiju",
        "history-feed-item-nocomment": "$1 u $2",
        "mergehistory-comment": "Spojeno [[:$1]] u [[:$2]]: $3",
        "mergehistory-same-destination": "Izvorne i odredišne stranice ne mogu biti iste",
        "mergehistory-reason": "Razlog:",
-       "mergelog": "Registar spajanja",
+       "mergelog": "Evidencija spajanja",
        "revertmerge": "Ukini spajanje",
        "mergelogpagetext": "Ispod je spisak nedavnih spajanja historija stranica.",
        "history-title": "Historija izmjena stranice \"$1\"",
        "search-category": "(kategorija $1)",
        "search-file-match": "(odgovara sadržaju datoteke)",
        "search-suggest": "Da li ste mislili: $1",
-       "search-rewritten": "Ishod iz $1. Umjesto toga pretraži $2.",
+       "search-rewritten": "Ishod iz $1. Ili potražite ga $2.",
        "search-interwiki-caption": "Ishod s bratskih projekata",
        "search-interwiki-default": "Rezultati od $1:",
        "search-interwiki-more": "(više)",
        "recentchangesdays-max": "(najviše $1 {{PLURAL:$1|dan|dana}})",
        "recentchangescount": "Podrazumevani broj izmjena za prikaz u skorašnjim izmjenama, istorijama stranica i dnevnicima:",
        "prefs-help-recentchangescount": "Najveći broj: 1000",
-       "prefs-help-watchlist-token2": "Ovo je tajni ključ prema sažetku Vašeg popisa praćenja. Svaki suradnik kojem je poznat, moći će čitati Vaš popis praćenih stranica. Ne dijelite ga ni s kim. [[Special:ResetTokens|Kliknite ovdje ako ga želite ponovo postaviti]].",
+       "prefs-help-watchlist-token2": "Ovo je tajni ključ prema sažetku Vašeg popisa praćenja.\nSvaki suradnik kojem je poznat, moći će čitati Vaš popis praćenih stranica, pa zato ne dijelite ga ni s kim.\nAko je potrebno, [[Special:ResetTokens|možete staviti novi]].",
+       "prefs-help-tokenmanagement": "Možete pogledati i odnovno zadati tajni ključ za svoj nalog koji može da pristupi svemrežnom fidu Vašeg popisa praćenih. Svako ko zna ključ moći će da vam čita spisak praćenih — zato nikome ne govori.",
        "savedprefs": "Vaša postavke su snimljene.",
        "savedrights": "Korisnička prava {{GENDER:$1|$1}} su snimljena.",
        "timezonelegend": "Vremenska zona / Временска зона",
        "userrights-expiry": "Ističe:",
        "userrights-expiry-existing": "Postojeće vrijeme isticanja: $3, $2",
        "userrights-expiry-othertime": "Drugo vrijeme:",
+       "userrights-expiry-options": "1 dan:1 day,1 sedmica:1 week,1 mjesec:1 month,3 mjeseca:3 months,6 mjeseci:6 months,1 godina:1 year",
        "userrights-invalid-expiry": "Vrijeme isticanja grupe \"$1\" nije ispravno.",
        "userrights-expiry-in-past": "Vrijeme isticanja grupe \"$1\" je u prošlosti.",
        "userrights-cannot-shorten-expiry": "Ne možete ubrzati istek članstva u grupi \"$1\". To mogu učiniti samo korisnici s dozvolom za dodavanje ili uklanjanje ove grupe.",
        "right-reupload-own": "Postavljanje nove verzije datoteke koju je postavio korisnik",
        "right-reupload-shared": "Postavljanje novih lokalnih verzija datoteka identičnih onima u zajedničkoj ostavi",
        "right-upload_by_url": "Postavljanje datoteke sa URL adrese",
-       "right-purge": "Osvježavanje keša za stranice bez potvrde",
+       "right-purge": "Osvježavanje keša stranice",
        "right-autoconfirmed": "Izbjegavanje ograničenja stopa temeljenih na IP-u",
        "right-bot": "Postavljen kao automatski proces",
        "right-nominornewtalk": "Male izmjene na stranicama za razgovor ne uzrokuju obavještenje o novim porukama",
        "right-editsitejson": "Uređivanje JSON-a za cijelo wiki",
        "right-editsitejs": "Uređivanje JavaScripta za cijelo wiki",
        "right-editmyusercss": "Uredite svoje vlastite CSS datoteke",
+       "right-editmyuserjson": "Uređivanje vlastitih JSON datoteka",
        "right-editmyuserjs": "Uredite vlastite korisničke JavaScript datoteke",
        "right-viewmywatchlist": "Pregled vlastitog popisa praćenih stranica",
        "right-editmywatchlist": "Uređivanje vlastitih praćenih. Obratite pažnju da će neke akcije dodati stranice čak bez ovog prava.",
        "grant-delete": "Brisanje stranica, izmjena i unosa u zapisnicima",
        "grant-editinterface": "Uređivanje imenskog prostora \"MediaWiki\" i JSON za cijelo wiki/za korisnika",
        "grant-editmycssjs": "Uređivanje Vašeg korisničkog CSS/JSON/JavaScripta",
-       "grant-editmyoptions": "Uređivanje vaših korisničkih podešavanja i postavljenosti JSON-a",
+       "grant-editmyoptions": "Uređivanje vaših korisničkih podešavanja i JSON konfiguracije",
        "grant-editmywatchlist": "Uređivanje Vaših praćenih",
        "grant-editsiteconfig": "Uređivanje CSS/JS za cijelo wiki i za korisnika",
        "grant-editpage": "Uređivanje postojećih stranica",
        "grant-viewdeleted": "Pregled obrisanih datoteka i stranica",
        "grant-viewmywatchlist": "Pregled vaših praćenja",
        "grant-viewrestrictedlogs": "Pregledanje ograničenih unosa u zapisniku",
-       "newuserlogpage": "Registar novih korisnika",
+       "newuserlogpage": "Evidencija novih korisnika",
        "newuserlogpagetext": "Ovo je evidencija registracije novih korisnika.",
        "rightslog": "Evidencija korisničkih prava",
        "rightslogtext": "Ovo je evidencija izmjene korisničkih prava.",
        "action-changetags": "dodajte ili uklonite razne oznake na pojedinačnim verzijama i unosima u zapisnicima",
        "action-deletechangetags": "brišete oznake iz baze podataka",
        "action-purge": "preučitavanje ove stranice",
+       "action-apihighlimits": "korištenje viših ograničenja u API upitima",
+       "action-autoconfirmed": "izbjegavanje ograničenja stopa temeljenih na IP-u",
+       "action-bigdelete": "brisanje stranica sa velikom historijom",
+       "action-blockemail": "blokiranje korisnika da šalje e-mail",
+       "action-bot": "tretiranje kao automatski proces",
+       "action-editprotected": "uređivanje stranica zaštićenih kao \"{{int:protect-level-sysop}}\"",
+       "action-editsemiprotected": "uređivanje stranica zaštićenih kao \"{{int:protect-level-autoconfirmed}}\"",
+       "action-editinterface": "uređivanje korisničkog interfejsa",
+       "action-editusercss": "uređivanje CSS-datoteka drugih korisnika",
+       "action-edituserjson": "uređivanje JSON-datoteka drugih korisnika",
+       "action-edituserjs": "uređivanje JavaScript-datoteka drugih korisnika",
+       "action-editsitecss": "uređivanje CSS za cijelo wiki",
+       "action-editsitejson": "uređivanje JSONa za cijelo wiki",
+       "action-editsitejs": "uređivanje JavaScripta za cijelo wiki",
+       "action-editmyusercss": "uređivanje vlastitih CSS datoteka",
+       "action-editmyuserjson": "uređivanje vlastitih JSON datoteka",
+       "action-editmyuserjs": "uređivanje vlastitih JavaScript datoteka",
+       "action-viewsuppressed": "pregledaj izmjene skrivene od svih korisnika",
+       "action-hideuser": "blokiranje korisničkog imena, i njegovo sakrivanje od javnosti",
+       "action-ipblock-exempt": "zaobilaženje IP blokova, autoblokova i opsežnih blokova",
+       "action-unblockself": "deblokiraj samog sebe",
+       "action-noratelimit": "ne utječu na vremenska ograničenja uređivanja",
+       "action-reupload-own": "prezapis datoteke koju je postavio korisnik",
+       "action-nominornewtalk": "male izmjene na stranicama za razgovor ne uzrokuju obavještenje o novim porukama",
+       "action-markbotedits": "označavanje vraćenih izmjena kao izmjene bota",
+       "action-patrolmarks": "pregled oznaka patroliranja u spisku nedavnih izmjena",
+       "action-override-export-depth": "izvoz stranica uključujući povezane stranice do dubine od 5 linkova",
+       "action-suppressredirect": "ne se pravi preusmjerenje sa starog imena pri premještanju stranica",
        "nchanges": "$1 {{PLURAL:$1|izmjena|izmjene|izmjena}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|izmjena od Vaše posljedne posjete}}",
        "enhancedrc-history": "historija",
        "rcfilters-savedqueries-already-saved": "Ovi filteri su već sačuvani. Promenite postavke da biste napravili novi sačuvan filter.",
        "rcfilters-restore-default-filters": "Vrati podrazumevane filtere",
        "rcfilters-clear-all-filters": "Očisti sve filtre",
-       "rcfilters-show-new-changes": "Pogl. najnovije izmjene",
+       "rcfilters-show-new-changes": "Pogl. nove izmjene nakon $1",
        "rcfilters-search-placeholder": "Filtriranje promene (koristite meni ili potražite za naziv filtera)",
        "rcfilters-invalid-filter": "Nevažeći filter",
        "rcfilters-empty-filter": "Nema aktivnih filtera. Prikazani su svi doprinosi.",
        "rcfilters-filter-editsbyself-description": "Vaši vlastiti doprinosi.",
        "rcfilters-filter-editsbyother-label": "Tuđe promjene",
        "rcfilters-filter-editsbyother-description": "Sve promjene osim Vaših.",
-       "rcfilters-filtergroup-userExpLevel": "Korisnička registracija i iskustvo",
+       "rcfilters-filtergroup-user-experience-level": "Korisnička registracija i iskustvo",
        "rcfilters-filter-user-experience-level-registered-label": "Registrirani",
        "rcfilters-filter-user-experience-level-registered-description": "Prijavljeni urednici.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Neregistrirani",
        "rcfilters-filter-categorization-description": "Zapisi iz stavljanja stranica u kategorije ili njihovo uklanjanje iz njih.",
        "rcfilters-filter-logactions-label": "Zapisane radnje",
        "rcfilters-filter-logactions-description": "Administrativni postupci, pravljenje računa, brisanje stranica, otpremanje...",
-       "rcfilters-filtergroup-lastRevision": "Posljednje revizije",
+       "rcfilters-filtergroup-lastrevision": "Posljednje revizije",
        "rcfilters-filter-lastrevision-label": "Posljednja revizija",
        "rcfilters-filter-lastrevision-description": "Samo najnovije revizije u stranici.",
        "rcfilters-filter-previousrevision-label": "Nije posljednja revizija",
        "minoreditletter": "m/м",
        "newpageletter": "N/Н",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|korisnik|korisnika}} koji pregledaju]",
        "rc-change-size-new": "$1 {{PLURAL:$1|bajt|bajta|bajtova}} posle izmene",
        "newsectionsummary": "/* $1 */ nova sekcija",
        "rc-enhanced-expand": "Pokaži detalje",
        "upload-permitted": "{{PLURAL:$2|Podržana vrsta|Podržane vrste}} datoteka: $1.",
        "upload-preferred": "{{PLURAL:$2|Preferirana vrsta|Preferirane vrste}} datoteka: $1.",
        "upload-prohibited": "{{PLURAL:$2|Zabranjena vrsta|Zabranjene vrste}} datoteka: $1.",
-       "uploadlogpage": "Registar postavljanja",
+       "uploadlogpage": "Evidencija postavljanja",
        "uploadlogpagetext": "Ispod je popis najnovijih postavljanja datoteka.\nVidi [[Special:NewFiles|galeriju novih datoteka]] za slikovitiji pregled.",
        "filename": "Ime fajla / Име датотеке",
        "filedesc": "Sažetak - Опис",
        "img-auth-nopathinfo": "Nedostaje informacija o putanji.\nVaš server mora biti namjesten da prosleđuje varijable REQUEST_URI i/ili PATH_INFO.\nAko je već namjesten, omogućite $wgUsePathInfo.\nPogl. https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Zahtjevana putanja nije u direktorijumu podešenom za postavljanje.",
        "img-auth-badtitle": "Ne mogu napraviti valjani naslov iz \"$1\".",
-       "img-auth-nologinnWL": "Niste prijavljeni i \"$1\" nije na spisku dozvoljenih.",
        "img-auth-nofile": "Datoteka \"$1\" ne postoji.",
        "img-auth-isdir": "Pokušavate pristupiti direktorijumu \"$1\".\nDozvoljen je samo pristup datotekama.",
        "img-auth-streaming": "Tok \"$1\".",
        "querypage-disabled": "Ova posebna stranica je onemogućena jer smanjuje performanse.",
        "apihelp": "Pomoć s prilogom",
        "apihelp-no-such-module": "Modul \"$1\" nije pronađen.",
+       "apisandbox": "Izvršnički pješčanik",
+       "apisandbox-jsonly": "Upotreba ovoga izvršničkog pješčanika zahtijeva JavaScript.",
+       "apisandbox-api-disabled": "Izvršnik je onemogućen na ovom sajtu.",
        "apisandbox-intro": "Stranica služi za eksperimentiranje s <strong>API-jem MediaWiki</strong>.\n\nViše o korištenju ovog API-ja možete pronaći na [[mw:API:Main page|njegovoj dokumentaciji]]. Primjer: [https://www.mediawiki.org/wiki/API#A_simple_example preuzimanje sadržaja glavne stranice]. Odaberite radnju da biste vidjeli više primjera.\n\nImajte na umu da se ono što radite na ovoj stranici može odraziti na wikiju, iako je to pješčanik.",
        "apisandbox-submit": "Napravi zahtjev",
        "apisandbox-reset": "Očisti",
        "apisandbox-retry": "Pokušaj ponovo",
+       "apisandbox-loading": "Učitavam informacije o izvršničkom modulu \"$1\"...",
+       "apisandbox-load-error": "Došlo je do greške pri učitavanju informacija o izvršničkom modulu \"$1\": $2",
+       "apisandbox-no-parameters": "Izvršnički modul nema parametara.",
+       "apisandbox-helpurls": "Linkovi za pomoć",
+       "apisandbox-examples": "Primjeri",
+       "apisandbox-dynamic-parameters": "Dodatni parametri",
+       "apisandbox-dynamic-parameters-add-label": "Dodaj parametar:",
+       "apisandbox-dynamic-parameters-add-placeholder": "Naziv parametra",
+       "apisandbox-dynamic-error-exists": "Parametar pod nazivom \"$1\" već postoji.",
+       "apisandbox-templated-parameter-reason": "Ovaj [[Special:ApiHelp/main#main/templatedparams|šabloniziran parametar]] nudi se u {{PLURAL:$1|vrijednosti|vrijednostima}} $2.",
+       "apisandbox-deprecated-parameters": "Zastarjeli parametri",
+       "apisandbox-fetch-token": "Samoispuni žeton",
+       "apisandbox-add-multi": "Dodaj",
+       "apisandbox-submit-invalid-fields-title": "Neka polja nisu ispravna",
+       "apisandbox-submit-invalid-fields-message": "Ispravite naznačena polja i pokušajte ponovo.",
+       "apisandbox-results": "Ishod",
+       "apisandbox-sending-request": "Šaljem zahtjev izvršniku...",
+       "apisandbox-loading-results": "Prijem ishod izvršnika...",
+       "apisandbox-results-error": "Došlo je do greške prilikom učitavanja odgovora upita izvršniku: $1.",
+       "apisandbox-results-login-suppressed": "Zahtjev je obrađen kao prijavljeni korisnik jer se može koristiti za zaobilaženje istoizvorne mjere sigurnosti. Imajte na umu da automatski rad s izvršničkim tokenima ne radi ispravno s tim zahtjevima, pa ćete ga morati ispuniti ručno.",
+       "apisandbox-request-selectformat-label": "Prikaži zahtijevane podatke kao:",
+       "apisandbox-request-format-url-label": "URL nizka upita",
+       "apisandbox-request-url-label": "URL zahtjeva:",
+       "apisandbox-request-json-label": "Zatraži JSON:",
+       "apisandbox-request-time": "Vreme zahtjeva: {{PLURAL:$1|$1 milisekunda|$1 milisekunde|$1 milisekundi}}",
+       "apisandbox-results-fixtoken": "Ispravi žeton i pošalji ponovo",
+       "apisandbox-results-fixtoken-fail": "Nisam uspio dobiti žeton \"$1\".",
+       "apisandbox-alert-page": "Polja na ovoj stranici su nevažeća.",
+       "apisandbox-alert-field": "Vrijednost ovog polja je nevažeća.",
+       "apisandbox-continue": "Nastavi",
+       "apisandbox-continue-clear": "Očisti",
+       "apisandbox-continue-help": "{{int:apisandbox-continue}} će [https://www.mediawiki.org/wiki/API:Query#Continuing_queries nastaviti] s posljednjim zahtjevom; \"{{int:apisandbox-continue-clear}}\" će izbrisati parametre vezane uz nastavljenje.",
+       "apisandbox-param-limit": "Unesite <kbd>max</kbd> da bi ste koristili najgornju granicu.",
+       "apisandbox-multivalue-all-namespaces": "$1 (svi imenski prostori)",
+       "apisandbox-multivalue-all-values": "$1 (sve vrijednosti)",
        "booksources": "Književni izvori",
        "booksources-search-legend": "Traži književne izvore",
        "booksources-search": "Traži",
        "logeventslist-tag-log": "Evidencija oznaka",
        "all-logs-page": "Sve evidencije - Све евиденције",
        "alllogstext": "Zajednički prikaz svih dostupnih evidencija sa {{SITENAME}}.\nMožete specificirati prikaz izabiranjem specifičnog spiska, korisničkog imena ili promjenjenog članka (razlikovati velika slova).",
-       "logempty": "Ne postoji takav zapis.",
+       "logempty": "Nema pronađenih stavki u evidenciji.",
        "log-title-wildcard": "Traži naslove koji počinju s ovim tekstom",
        "showhideselectedlogentries": "Prikaži/sakrij izabrane zapise u evidenciji",
        "log-edit-tags": "Uredi oznake izabranih zapisničkih unosa",
        "delete-confirm": "Brisanje \"$1\"",
        "delete-legend": "Obriši",
        "historywarning": "<strong>Upozorenje</strong>: Stranica koju želite da obrišete ima historiju sa otprilike $1 {{PLURAL:$1|revizijom|revizije|revizija}}:",
-       "historyaction-submit": "Prikaži",
+       "historyaction-submit": "Prikaži revizije",
        "confirmdeletetext": "Upravo ćete obrisati stranicu sa svom njenom historijom.\nMolimo da potvrdite da ćete to učiniti, da razumijete posljedice te da to činite u skladu sa [[{{MediaWiki:Policy-url}}|pravilima]].",
        "actioncomplete": "Radnja završena\n\nРадња завршена",
        "actionfailed": "Akcija nije uspjela",
        "deleting-backlinks-warning": "<strong>Upozorenje:</strong>  Na stranicu koju želite izbrisati vode [[Special:WhatLinksHere/{{FULLPAGENAME}}|ostale stranice]] ili pak su uključene u nju.",
        "deleting-subpages-warning": "<strong>Upozorenje:</strong> Stranica koju želite izbrisati ima [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|podstranicu|$1 podstranice|$1 podstranica|51=preko 50 podstranica}}]].",
        "rollback": "Vrati izmjene",
+       "rollback-confirmation-confirm": "Molimo Vas, potvrdite:",
+       "rollback-confirmation-yes": "Vraćanje",
+       "rollback-confirmation-no": "Otkaži",
        "rollbacklink": "vrati",
        "rollbacklinkcount": "vrati $1 {{PLURAL:$1|izmjenu|izmjene|izmjena}}",
        "rollbacklinkcount-morethan": "vrati više od $1 {{PLURAL:$1|izmjene|izmjene|izmjena}}",
        "revertpage": "Vraćene izmjene [[Special:Contributions/$2|$2]] ([[User talk:$2|razgovor]]) na posljednju izmjenu korisnika [[User:$1|$1]]",
        "revertpage-nouser": "Vraćene izmjene skrivenog korisnika na posljednju reviziju, koju je {{GENDER:$1|napravio|napravila}} [[User:$1|$1]]",
        "rollback-success": "Vraćene su izmjene korisnika {{GENDER:$3|$1}};\nvraćeno na posljednju verziju koju je snimio {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Vraćene izmjene korisnika $1;\nvraćeno na posljednju izmjenu korisnika $2. [$3 Pok. promjene]",
        "sessionfailure-title": "Greška u sesiji",
-       "sessionfailure": "Izgleda da postoji problem sa vašom sesijom; ova akcija je otkazana kao prevencija protiv napadanja sesija. Kliknite \"back\" (''nazad'') i osvježite stranicu sa koje ste došli, i opet pokušajte.",
+       "sessionfailure": "Izgleda da postoji problem sa vašom sesijom;\nova radnja je otkazana kao prevencija protiv napadanja sesija.\nMolimo ponovno pošaljite obrazac.",
        "changecontentmodel": "Promijeni model sadržaja stranice",
        "changecontentmodel-legend": "Promijeni model sadržaja",
        "changecontentmodel-title-label": "Naslov stranice",
        "changecontentmodel-nodirectediting": "Model sadržaja $1 ne podržava izravno uređivanje",
        "changecontentmodel-emptymodels-title": "Nema dostupnih modela sadržaja",
        "changecontentmodel-emptymodels-text": "Model sadržaja stranice [[:$1]] se ne može pretvoriti ni u jedan drugi tip.",
-       "log-name-contentmodel": "Zapisnik promjene modela sadržaja",
+       "log-name-contentmodel": "Evidencija promjene modela sadržaja",
        "log-description-contentmodel": "Ova stranica navodi promjene u modelu sadržaja stranica, kao i stranice stvorene s modelom sadržaja koji se razlikuje od predodređenog.",
        "logentry-contentmodel-new": "$1 {{GENDER:$2|napravio je|napravila je}} stranicu $3 s nestandardnim modelom sadržaja \"$5\"",
        "logentry-contentmodel-change": "$1 {{GENDER:$2|promijenio|promijenila}} je model sadržaja stranice $3 iz \"$4\" u \"$5\"",
        "mycontris": "Doprinosi",
        "anoncontribs": "Doprinosi",
        "contribsub2": "Za {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "Za {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "Korisnički račun \"$1\" nije registrovan.",
        "negative-namespace-not-supported": "Nisu podržani imenski prostori s negativnim vrijednostima.",
        "nocontribs": "Nisu nađene promjene koje zadovoljavaju ove uslove.",
        "block": "Blokiraj korisnika",
        "unblock": "Odblokiraj korisnika",
        "blockip": "Blokiraj {{GENDER:$1|korisnika|korisnicu}}",
-       "blockiptext": "Upotrebite donji upitnik da biste uklonili prava pisanja sa određene IP adrese ili korisničkog imena.  \nOvo bi trebalo da bude urađeno samo da bi se spriječio vandalizam, i u skladu sa [[{{MediaWiki:Policy-url}}|smjernicama]]. \nUnesite konkretan razlog ispod (na primjer, navodeći koje konkretne stranice su vandalizovane).",
+       "blockiptext": "Upotrebite donji upitnik da biste uklonili prava pisanja sa određene IP adrese ili korisničkog imena.  \nOvo bi trebalo da bude urađeno samo da bi se spriječio vandalizam, i u skladu sa [[{{MediaWiki:Policy-url}}|smjernicama]]. \nUnesite konkretan razlog ispod (na primjer, navodeći koje konkretne stranice su vandalizovane).\nMožete blokirati IP-opsege koristeći [https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing sintaksu CIDR-a]; najveći dozvoljeni opseg za IPv4 je /$1, a za IPv6 /$2.",
        "ipaddressorusername": "IP adresa ili korisničko ime:",
        "ipbreason": "Razlog:",
        "ipbreason-dropdown": "*Najčešći razlozi blokiranja\n**Unošenje netačnih informacija\n**Uklanjanje sadržaja stranica\n**Postavljanje spam vanjskih linkova\n**Ubacivanje gluposti/grafita\n**Osobni napadi (ili napadačko ponašanje)\n**Čarapare (zloupotreba više korisničkih računa)\n**Neprihvatljivo korisničko ime",
        "blocklist-userblocks": "Sakrij blokade računa",
        "blocklist-tempblocks": "Sakrij privremene blokade",
        "blocklist-addressblocks": "Sakrij pojedinačne IP blokade",
+       "blocklist-type": "Vrsta:",
+       "blocklist-type-opt-all": "Sve",
+       "blocklist-type-opt-sitewide": "Na celom sajtu",
+       "blocklist-type-opt-partial": "Djelimično",
        "blocklist-rangeblocks": "Sakrij pojasna blokiranja",
        "blocklist-timestamp": "Vremenska oznaka",
        "blocklist-target": "Cilj",
        "blocklist-editing-page": "stranice",
        "blocklist-editing-ns": "imenski prostori",
        "ipblocklist-empty": "Spisak blokiranja je prazan.",
-       "ipblocklist-no-results": "Tražena IP adresa ili korisničko ime nisu blokirani.",
+       "ipblocklist-no-results": "Nisam našao takve blokove na traženoj IP adresi ili korisničkom imenu.",
        "blocklink": "blokiraj",
        "unblocklink": "Odblokiraj / Одблокирај",
        "change-blocklink": "promijeni blokadu",
        "allmessagesdefault": "Uobičajeni tekst",
        "allmessagescurrent": "Trenutni tekst",
        "allmessagestext": "Ovo je spisak sistemskih poruka u dostupnih u MediaWiki imenskom prostoru.\nMolimo posjetite [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki lokalizaciju] i [https://translatewiki.net translatewiki.net] ako želite doprinijeti općoj lokalizaciji MediaWikija.",
-       "allmessagesnotsupportedDB": "Ova stranica ne može biti korištena jer je '''$wgUseDatabaseMessages''' isključen.",
+       "allmessages-not-supported-database": "Ova stranica ne može biti korištena jer je '''$wgUseDatabaseMessages''' isključen.",
        "allmessages-filter-legend": "Filter",
        "allmessages-filter": "Filter po stanju podešavanja:",
        "allmessages-filter-unmodified": "Neizmijenjeno",
        "pageinfo-category-files": "Broj datoteka",
        "pageinfo-user-id": "Korisnička naznaka",
        "pageinfo-file-hash": "Tarabna vrijednost",
-       "pageinfo-view-protect-log": "Pogl. evidenciju zaštite ove stranice.",
+       "pageinfo-view-protect-log": "Vidi evidenciju zaštićivanja ove stranice.",
        "markaspatrolleddiff": "Označi kao patrolirano",
        "markaspatrolledtext": "Označi ovu stranicu kao patroliranu",
        "markaspatrolledtext-file": "Označi ovu verziju kao ispatroliranu",
        "confirmemail_subject": "{{SITENAME}} adresa e-pošte za potvrdu",
        "confirmemail_body": "Neko, vjerovatno Vi, je sa IP adrese $1 registrovao nalog \"$2\" sa ovom adresom e-pošte na {{SITENAME}}.\n\nDa potvrdite da ovaj nalog stvarno pripada vama i da aktivirate mogućnost e-pošte na {{SITENAME}}, otvorite ovaj link u vašem pregledniku:\n\n$3\n\nAko ovo niste vi, pratite ovaj link da prekinete prijavu:\n$5\n\nOvaj kod za potvrdu će isteći u $4.",
        "confirmemail_body_changed": "Neko, vjerovatno Vi, je sa IP adrese $1\nje promijenio adresu e-pošte računa \"$2\" na ovu adresu za {{SITENAME}}.\n\nDa potvrdite da ovaj nalog stvarno pripada Vama i da reaktivirate mogućnosti e-pošte na {{SITENAME}}, otvorite ovaj link u Vašem pregledniku:\n\n$3\n\nAko ovaj račun *ne* pripada Vama, pratite ovaj link da prekinete odobravanje adrese e-pošte:\n\n$5\n\nOvaj kod za potvrdu će isteći u $4.",
-       "confirmemail_body_set": "Netko, vjerovatno Vi, sa IP adrese $1,\nje postavio e-mail adresu za račun \"$2\" na ovoj adresi za {{SITENAME}}.\n\nDa potvrdite kako ovaj račun uistinu pripada Vama i reaktivirate\ne-mail postavke na {{SITENAME}}, otvoriti ovaj link u vašem pregledniku:\n\n$3\n\nAko račun *ne* pripada Vama, pratite ovaj link\nkako bi poništili potvrdu e-mail adrese:\n\n$5\n\nOvaj kod za potvrdu će isteći u $4.",
+       "confirmemail_body_set": "Netko, vjerovatno Vi, sa IP adrese $1,\nje postavio e-mail adresu za račun \"$2\" na ovoj adresi za {{SITENAME}}.\n\nDa potvrdite kako ovaj račun stvarno pripada Vama i da uključite\nmogućnosti e-pošte na {{SITENAME}}, otvorite ovaj link u Vašem pregledniku:\n\n$3\n\nAko račun *ne* pripada Vama, pratite ovaj link\nkako bi poništili potvrdu:\n\n$5\n\nOvaj kod za potvrdu će isteći u $4.",
        "confirmemail_invalidated": "Potvrda e-mail adrese otkazana",
        "invalidateemail": "Odustani od e-mail potvrde",
        "notificationemail_subject_changed": "Registrirana adresa e-pošte na projektu {{SITENAME}} je smijenjena",
        "confirm-unwatch-top": "Izbrisati ovu stranicu sa Vašeg spiska praćenja?",
        "confirm-rollback-button": "U redu",
        "confirm-rollback-top": "Ukloniti uređivanja na ovoj stranici?",
+       "confirm-rollback-bottom": "Ova će radnja odmah poništiti izabrane promjene ove stranice.",
        "confirm-mcrrestore-title": "Povrati reviziju",
        "confirm-mcrundo-title": "Otkaži promjenu",
        "mcrundofailed": "Otkazivanje nije uspjelo",
        "version-variables": "Promjenjive",
        "version-editors": "Urednici",
        "version-antispam": "Sprečavanje spama",
-       "version-api": "Prilozi",
+       "version-api": "Izvršnici",
        "version-other": "Ostalo",
        "version-mediahandlers": "Upravljači medije",
        "version-hooks": "Kuke",
        "tags-create-invalid-chars": "Nazivi oznaka ne smiju sadržavati zareze (<code>,</code>), uspravne (<code>|</code>) ni kose crte (<code>/</code>).",
        "tags-create-invalid-title-chars": "Imena oznaka ne smiju sadržavati znakove što se ne mogu koristiti u naslovima stranica.",
        "tags-create-already-exists": "Oznaka \"$1\" već postoji.",
+       "tags-create-warnings-above": "Pokušavajući stvoriti oznaku \"$1\" sam dogodio {{PLURAL:$2|sljedeće upozorenje|sljedeća upozorenja}}:",
+       "tags-create-warnings-below": "Želite li nastaviti stvaranje oznake?",
+       "tags-delete-title": "Izbriši oznaku",
+       "tags-delete-explanation-initial": "Brišete oznaku \"$1\" iz baze podataka.",
+       "tags-delete-explanation-in-use": "Bit će obrisana sa {{PLURAL:$2|jedne verzije ili unosa u zapisniku na kojim|svih $2 verzija i/ili unosa u zapisniku na kojima}} je primijenjena.",
+       "tags-delete-explanation-warning": "Ova radnja je <strong>nepovratna</strong> te se <strong>ne može poništiti</strong>. Ovo ne mogu uraditi čak ni administratori baze podataka. Zato, osigurajte da ovo stvarno je oznaka koju želite obrisati.",
+       "tags-delete-explanation-active": "<strong>Oznaka \"$1\" je i dalje aktivna te u budućnosti će se nastaviti primjenjivati.</strong> Kako biste ovo spriječili, otiđite na mjesto (ili mjesta) na kojima joj je postavljeno da se postavlja i onemogućite je tamo.",
+       "tags-delete-reason": "Razlog:",
+       "tags-delete-submit": "Nepovratno obriši ovu oznaku",
+       "tags-delete-not-allowed": "Oznake zadane dodatkom se ne mogu obrisati, osim ako to nije izričito dopušteno dodatkom.",
+       "tags-delete-not-found": "Oznaka \"$1\" ne postoji.",
+       "tags-delete-too-many-uses": "Oznaka \"$1\" primjenjuje se na više od {{PLURAL:$2|jedne revizije|$2 revizija}}, što znači da se ne može obrisati.",
+       "tags-delete-warnings-after-delete": "Oznaka \"$1\" je obrisana, ali naišao sam na {{PLURAL:$2|sljedeće upozorenje|sljedeća upozorenja}}:",
+       "tags-delete-no-permission": "Nemate dopuštenje da brišete oznake promjena.",
+       "tags-activate-title": "Aktiviraj oznaku",
+       "tags-activate-question": "Aktivirate oznaku \"$1\".",
+       "tags-activate-reason": "Razlog:",
+       "tags-activate-not-allowed": "Ne mogu aktivirati oznaku \"$1\".",
+       "tags-activate-not-found": "Oznaka \"$1\" ne postoji.",
+       "tags-activate-submit": "Aktiviraj",
+       "tags-deactivate-title": "Deaktiviraj oznaku",
+       "tags-deactivate-question": "Deaktivirate oznaku \"$1\".",
+       "tags-deactivate-reason": "Razlog:",
+       "tags-deactivate-not-allowed": "Ne mogu deaktivirati oznaku \"$1\".",
+       "tags-deactivate-submit": "Deaktiviraj",
+       "tags-apply-no-permission": "Nemate dopuštenje da stavljate oznake za promjene zajedno s izmjenama koje pravite.",
+       "tags-apply-blocked": "Ne možete zadavati oznake za promjenu dok {{GENDER:$1|ste}} blokirani.",
+       "tags-apply-not-allowed-one": "Nije dozvoljeno da se oznaka \"$1\" staje ručno.",
+       "tags-apply-not-allowed-multi": "Nije dozvoljeno da se {{PLURAL:$2|sljedeća oznaka staje ručno|sljedeće oznake staju ručno}}: $1",
+       "tags-update-no-permission": "Nemate dopuštenje da dodate ili uklonite oznake promjena sa zasebnih verzija ili zapisničkih unosa.",
+       "tags-update-blocked": "Ne možete dodavati niti uklanjati oznake za promjenu dok {{GENDER:$1|ste}} blokirani.",
+       "tags-update-add-not-allowed-one": "Nije dozvoljeno da se oznaka \"$1\" dodaje ručno.",
+       "tags-update-add-not-allowed-multi": "Nije dozvoljeno da se {{PLURAL:$2|sljedeća oznaka dodaje ručno|sljedeće oznake dodaju ručno}}: $1",
+       "tags-update-remove-not-allowed-one": "Nije dozvoljeno da se uklanja oznaka \"$1\".",
+       "tags-update-remove-not-allowed-multi": "Nije dozvoljeno da se {{PLURAL:$2|sljedeća oznaka uklanja ručno|sljedeće oznake uklanjaju ručno}}: $1",
+       "tags-edit-title": "Mijenjanje oznaka",
+       "tags-edit-manage-link": "Upravljaj oznakama",
+       "tags-edit-revision-selected": "{{PLURAL:$1|Odabrana izmjena|Odabrane izmjene}} [[:$2]]:",
+       "tags-edit-logentry-selected": "{{PLURAL:$1|Odabran unos registra|Odabrani unosi registra}}:",
+       "tags-edit-revision-legend": "Dodajte ili uklonite oznake sa {{PLURAL:$1|ove izmjene|svih $1 izmjena}}",
+       "tags-edit-logentry-legend": "Dodajte ili uklonite oznake sa {{PLURAL:$1|ovog zapisničkog unosa|svih $1 zapisničkih unosa}}",
+       "tags-edit-existing-tags": "Postojeće oznake:",
+       "tags-edit-existing-tags-none": "<em>Nema</em>",
+       "tags-edit-new-tags": "Nove oznake:",
+       "tags-edit-add": "Dodaj ove oznake:",
+       "tags-edit-remove": "Ukloni ove oznake:",
+       "tags-edit-remove-all-tags": "(ukloni sve oznake)",
+       "tags-edit-chosen-placeholder": "Odaberite neke oznake",
+       "tags-edit-chosen-no-results": "Nisam pronašao odgovarajuće oznake",
+       "tags-edit-reason": "Razlog:",
+       "tags-edit-revision-submit": "Primijeni izmjene {{PLURAL:$1|ovoj reviziji|svim $1 revizijama}}",
+       "tags-edit-logentry-submit": "Primijeni izmjene {{PLURAL:$1|ovom zapisničkom unosu|svim $1 zapisničkim unosima}}",
+       "tags-edit-success": "Izmjene su primijenjene.",
+       "tags-edit-failure": "Nisam mogao primijeniti izmjene:\n$1",
+       "tags-edit-nooldid-title": "Nevažeća odredišna revizija",
+       "tags-edit-nooldid-text": "Niste naveli odredišnu verziju na koju treba primijeniti izmjene, ili pak navedena verzija na postoji.",
+       "tags-edit-none-selected": "Odaberite bar jednu oznaku koju treba dodati ili ukloniti.",
        "comparepages": "Usporedi stranice",
        "compare-page1": "Stranica 1",
        "compare-page2": "Stranica 2",
        "authmanager-autocreate-noperm": "Automatsko pravljenje računa nije dozvoljeno.",
        "authmanager-autocreate-exception": "Automatsko pravljenje računa privremeno je onemogućeno zbog prijašnjih greški.",
        "authmanager-userdoesnotexist": "Korisnički račun \"$1\" nije registrovan.",
+       "authmanager-userlogin-remembermypassword-help": "Je li zaporka pohranjena dulje od trajanja sesije.",
+       "authmanager-username-help": "Korisničko ime za verifikaciju.",
+       "authmanager-password-help": "Lozinka za verifikaciju.",
+       "authmanager-domain-help": "Domen za vanjsku verifikaciju.",
+       "authmanager-retype-help": "Ponovite lozinku (za potvrdu).",
+       "authmanager-email-label": "E-pošta",
+       "authmanager-email-help": "Adresa e-pošte",
+       "authmanager-realname-label": "Pravo ime",
+       "authmanager-realname-help": "Pravo ime korisnika",
+       "authmanager-provider-password": "Verifikacija lozinkom",
+       "authmanager-provider-password-domain": "Verifikacija lozinkom i domenom",
+       "authmanager-provider-temporarypassword": "Privremena lozinka",
+       "authprovider-confirmlink-request-label": "Računi koji se trebaju povezati",
+       "authprovider-confirmlink-success-line": "$1: Uspješno povezano.",
+       "authprovider-confirmlink-failed": "Povezivanje računa nije uspjelo u potpunosti: $1",
+       "authprovider-confirmlink-ok-help": "Nastavi nakon prikazivanja poruka za neuspješno povezivanje.",
+       "authprovider-resetpass-skip-label": "Preskoči",
+       "authprovider-resetpass-skip-help": "Preskoči zadavanje nove lozinke.",
+       "authform-nosession-login": "Verifikacija je uspješna, ali vaš preglednik ne može \"zapamtiti\" da ste prijavljeni.\n\n$1",
+       "authform-nosession-signup": "Račun je napravljen, ali vaš preglednik ne može \"zapamtiti\" da ste prijavljeni.\n\n$1",
+       "authform-newtoken": "Nedostaje token. $1",
+       "authform-notoken": "Nedostaje token",
+       "authform-wrongtoken": "Pogrešan token",
+       "specialpage-securitylevel-not-allowed-title": "Nije dozvoljeno",
+       "specialpage-securitylevel-not-allowed": "Žao nam je, nije Vam dozvoljeno korištenje ove stranice jer nije moguće potvrditi vaš identitet.",
+       "authpage-cannot-login": "Ne mogu započeti prijavu.",
+       "authpage-cannot-login-continue": "Ne mogu nastaviti s prijavom. Najvjerovatnije vaša sesija je istekla.",
+       "authpage-cannot-create": "Ne mogu započeti stvaranje računa.",
+       "authpage-cannot-create-continue": "Ne mogu nastaviti s stvaranjem računa. Najvjerovatnije vaša sesija je istekla.",
+       "authpage-cannot-link": "Ne mogu započeti spajanje računa.",
+       "authpage-cannot-link-continue": "Ne mogu nastaviti sa spajanjem računa. Najvjerovatnije vaša sesija je istekla.",
+       "cannotauth-not-allowed-title": "Pristup je odbijen",
+       "cannotauth-not-allowed": "Nije vam dozvoljeno da koristite ovu stranicu",
        "userjsispublic": "Napomena: podstranice s JavaScriptom ne bi trebale sadržavati povjerljive podatke budući da ih drugi korisnici mogu vidjeti.",
        "userjsonispublic": "Imajte na umu: Podstranice s JSONom ne bi trebale sadržavati povjerljive podatke budući da su vidljive drugim korisnicima.",
        "usercssispublic": "Napomena: podstranice s CSS-om ne bi trebale sadržavati povjerljive podatke budući da ih drugi korisnici mogu vidjeti.",
        "edit-error-short": "Greška: $1",
        "edit-error-long": "Greške:\n\n$1",
        "revid": "izmjena $1",
-       "pageid": "ID stranice $1"
+       "pageid": "ID stranice $1",
+       "interfaceadmin-info": "$1\n\nDozvole za uređivanje CSS/JS/JSON datoteka preko cijelog wikija nedavno su odvojene od prava <code>editinterface</code>. Ako ne razumijete zašto ste dobili ovu grešku, pogl. [[mw:MediaWiki_1.32/interface-admin]].",
+       "rawhtml-notallowed": "&lt;html&gt;-oznake ne mogu se koristiti van normalnih stranica.",
+       "gotointerwiki": "Napuštate projekt {{SITENAME}}",
+       "gotointerwiki-invalid": "Navedeni naslov je nevalidan.",
+       "gotointerwiki-external": "Napuštate projekt {{SITENAME}} da biste posjetili zasebno mrežno mjesto [[$2]].\n\n<strong>[$1 Nastavljate na $1]</strong>",
+       "undelete-cantedit": "Ne možete vratiti ovu stranicu jer Vam nije dozvoljeno da je uređujete.",
+       "undelete-cantcreate": "Ne možete vratiti stranicu jer ne postoji stranica s tim nazivom i nije Vam dozvoljeno da je napravite.",
+       "pagedata-title": "Podaci o stranici",
+       "pagedata-text": "Stranica pruža posrednik za podaci za stranice. Navedite naslov stranice u URL-u pomoću sintakse podstranice.\n* Prebacivanje sadržaja temelji se na zaglavlju Prihvati vašeg klijenta. To znači da će podaci stranice biti stavljeni u formatu koji preferira vaš klijent.",
+       "pagedata-not-acceptable": "Nisam našao odgovarajući format. Podržane MIME-vrste: $1",
+       "pagedata-bad-title": "Nevalidan naslov: $1.",
+       "unregistered-user-config": "Iz bezbednosnih razloga JavaScript, CSS i JSON korisničke podstranice ne mogu biti učitane za neregistrovane korisnike.",
+       "passwordpolicies": "Pravila za lozinke",
+       "passwordpolicies-summary": "Ovo je popis djelotvornih pravila za zaporke za korisničke grupe određene na ovom wikiju.",
+       "passwordpolicies-group": "Grupa",
+       "passwordpolicies-policies": "Pravila",
+       "passwordpolicies-policy-minimalpasswordlength": "Lozinka mora da ima najmanje $1 {{PLURAL:$1|znak|znaka|znakova}}",
+       "passwordpolicies-policy-minimumpasswordlengthtologin": "Lozinka mora da ima najmanje $1 {{PLURAL:$1|znak|znaka|znakova}} da bi ste mogli da se prijavite",
+       "passwordpolicies-policy-passwordcannotmatchusername": "Lozinka ne može biti ista što i korisničko ime",
+       "passwordpolicies-policy-passwordcannotmatchblacklist": "Lozinka ne smije biti iz onih na crnom spisku",
+       "passwordpolicies-policy-maximalpasswordlength": "Lozinka ne mora biti više od $1 {{PLURAL:$1|znaka|znakova}}",
+       "passwordpolicies-policy-passwordcannotbepopular": "Lozinka ne može da bude {{PLURAL:$1|popularna|iz spiska $1 popularnih lozinki}}",
+       "passwordpolicies-policy-passwordnotinlargeblacklist": "Lozinka ne može biti na listi 100.000 najčešće korišćenih lozinki.",
+       "passwordpolicies-policyflag-forcechange": "mora se promjeniti pri prijavi",
+       "passwordpolicies-policyflag-suggestchangeonlogin": "predloži izmjenu pri prijavi",
+       "easydeflate-invaliddeflate": "Sadržaj nije ispravno pročišćen",
+       "unprotected-js": "JavaScript ne može da se učita sa nezaštićenih stranica iz bezbednosnih razloga. Samo napravite JavaScript u imenskom prostoru MediaWiki: ili kao korisničku podstranicu",
+       "userlogout-continue": "Ako se želite odjaviti, [$1 nastavite na odjavnoj strnaici].",
+       "userlogout-sessionerror": "Odjava nije uspjela zbog sesijske pogreške. [$1 Pokušajte ponovo]."
 }
index 4d09562..9a6a0d8 100644 (file)
        "newpageletter": "ⵎⵢⵏ",
        "boteditletter": "ⴱ",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 iżŗi {{PLURAL:$1|amsqdac|imsqdacn}}]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|ⴱⴰⵢⵜ|ⵉⴷ ⴱⴰⵢⵜ}} ⴷⴼⴼⵉⵔ ⵏ ⵓⵙⵏⴼⵍ",
        "newsectionsummary": "/* $1 */ ⵜⵉⴳⵣⵎⵉ ⵜⴰⵎⴰⵢⵏⵓⵜ",
index 3f55b49..93f4505 100644 (file)
        "page_first": "ဢွၼ်တၢင်း",
        "page_last": "လိုတ်းသုတ်း",
        "histlegend": "တွၼ်ႈတႃႇၼိူင်းၵၼ်တူၺ်း လွင်ႈမႄးထတ်း ႁဵၼ်းပၼ်မၢႆၶၼ် တီႈတိူၵ်ႈလိူၵ်ႈသၢင်ႈ သေ ၼဵၵ်းပၼ် Enter ဢမ်ႇၼၼ် ၼဵၵ်းပၼ်တီႈ ၼဵၼ် ဢၼ်မီးယူႇၽၢႆႇတႂ်ႈၼၼ်ႉလႄႈ။\nLegend:  <strong>({{int:cur}})</strong> = လွင်ႈပႅၵ်ႇပိူင်ႈၵၼ်တင်း ၶေႃႈမႄးထတ်းဝႆႉ ၵမ်းလိုၼ်းသုတ်း, <strong>({{int:last}})</strong> = လွင်ႈပႅၵ်ႇပိူင်ႈၵၼ်တင်း ၶေႃႈမႄးထတ်း ၽၢႆႇၼႃႈၼၼ်ႉ, <strong>{{int:minoreditletter}}</strong> = လွင်ႈမႄးထတ်းဢွၼ်ႇဢီႈ.",
-       "history-fieldset-title": "á\80\9eá\80½á\81µá\80ºá\82\88á\82\81á\82\83á\80\90á\82\83 á\81¶á\80±á\82\83á\82\88á\81¶á\80°á\81¼á\80ºá\82\89á\80¢á\81¢á\81¼á\80ºá\82\87",
+       "history-fieldset-title": "á\80\90á\80°á\80\9dá\80ºá\80\91á\80½á\80\84á\80º á\81¶á\80±á\82\83á\82\88á\81¶á\80°á\81¼á\80ºá\82\89á\82\81á\82\83",
        "history-show-deleted": "ၶေႃႈၶူၼ်ႉဢၢၼ်ႇ ဢၼ်​ယႃႉ​ဝႆႉ​ၼၼ်ႉၵွၺ်း",
        "histfirst": "ၵဝ်ႇသုတ်း",
        "histlast": "မႂ်ႇသုတ်း",
        "rcfilters-filter-editsbyself-description": "လွင်ႈၶဝ်ႈႁူမ်ႈ ၶွင်တူဝ်ၸဝ်ႈၵဝ်ႇ",
        "rcfilters-filter-editsbyother-label": "လွင်ႈလႅၵ်ႈလၢႆႈ တၢင်ႇၵေႃႉႁဵတ်း",
        "rcfilters-filter-editsbyother-description": "လွင်ႈလႅၵ်ႈလၢႆႈတၢင်းသဵင် လိူဝ်သေၶွင်တူဝ်ၸဝ်ႈၵဝ်ႇ",
-       "rcfilters-filtergroup-userExpLevel": "ၸၼ်ႉထၢၼ်ႈ တူဝ်ထူပ်း (တွၼ်ႈတႃႈ ၽူႈၸႂ်ႉတိုဝ်း ၸိူဝ်းတၢင်ႇဝႆႉ မႆၽၢင်ၵူၺ်း)",
+       "rcfilters-filtergroup-user-experience-level": "ၸၼ်ႉထၢၼ်ႈ တူဝ်ထူပ်း (တွၼ်ႈတႃႈ ၽူႈၸႂ်ႉတိုဝ်း ၸိူဝ်းတၢင်ႇဝႆႉ မႆၽၢင်ၵူၺ်း)",
        "rcfilters-filter-user-experience-level-registered-label": "တၢင်ႇမၢႆၾၢင်ဝႆႉယဝ်ႉ",
        "rcfilters-filter-user-experience-level-registered-description": "ၽူႈမႄးထတ်းၶဝ် ၶဝ်ႈလွၵ်ႉဢိၼ်ႇဝႆႉ",
        "rcfilters-filter-user-experience-level-unregistered-label": "ဢမ်ႇလႆႈတၢင်ႇမၢႆႇၽၢင်ဝႆႉ",
        "rcfilters-filter-newpages-label": "လွင်ႈၵေႃႇသၢင်ႈ ၼႃႈလိၵ်ႈ",
        "rcfilters-filter-newpages-description": "မႄးထတ်း ဢၼ်ႁဵတ်းပဵၼ် ၼႃႈလိၵ်ႈဢၼ်မႂ်ႇ",
        "rcfilters-filter-categorization-label": "လႅၵ်ႈလၢႆႈ ပိူင်ထၢၼ်ႈ",
-       "rcfilters-filtergroup-lastRevision": "ၵၢၼ်ၶူၼ်ႉၶႆႈ ၵမ်းလိုၼ်းသုတ်း",
+       "rcfilters-filtergroup-lastrevision": "ၵၢၼ်ၶူၼ်ႉၶႆႈ ၵမ်းလိုၼ်းသုတ်း",
        "rcfilters-filter-lastrevision-label": "ၵၢၼ်ၶူၼ်ႉၶႆႈ ၵမ်းလိုၼ်းသုတ်း",
        "rcfilters-filter-lastrevision-description": "ၸိူဝ်းဢၼ်မီးလွင်ႈလႅၵ်ႈလၢႆႈၸူး ၼႃႈလိၵ်ႈ ဢၼ်ပႆႇႁိုင်ၼၼ်ႉၵူၺ်း",
        "rcfilters-filter-previousrevision-label": "ဢမ်ႇၸႂ်ႈၵၢၼ်ၶူၼ်ႉၶႆႈ ၵမ်းလိုၼ်းသုတ်း",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 ပႂ်ႉတူၺ်း {{PLURAL:$1|ၽူႈၸႂ်ႉတိုဝ်း|ၽူႈၸႂ်ႉတိုဝ်းၶဝ်}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} ဝၢႆးသေလႅၵ်ႈလၢႆႈ",
        "newsectionsummary": "/* $1 */ ၵၼ်ဢၼ်မႂ်ႇ",
        "rc-enhanced-expand": "ၼႄပၼ် ႁူဝ်ယွႆႈမၼ်း",
        "invalid-chunk-offset": "ပွတ်းတူဝ်ၵၢမ်း ၽိတ်းပိူင်ႈ",
        "img-auth-accessdenied": "ၵၢၼ်ၸႂ်ႉတိုဝ်း ထုၵ်ႇထဵင်ၶိုၼ်း။",
        "img-auth-notindir": " သၢႆတၢင်းဢၼ်တုၵ်းယွၼ်းမႃးၼၼ်ႉ မၼ်းဢမ်ႇမီးၵႃႈတီႈၼႂ်း သၢႆတၢင်းလူတ်ႇၶိုၼ်ႈ ဢၼ်မႄးၵုမ်းဝႆႉ။",
-       "img-auth-nologinnWL": "ၸဝ်ႈၵဝ်ႇ ဢမ်ႇလႆႈၶဝ်ႈ လွၵ်ႉဢိၼ်ဝႆႉသေ \"$1\" ၼႆႉ မၼ်းဢမ်ႇမီးဝႆႉ တီႈၼႂ်း သဵၼ်ႈမၢႆၶၢဝ်။",
        "img-auth-nofile": "ၾၢႆႇ \"$1\" ၼႆႉ မၼ်းဢမ်ႇမီးဝႆႉ။",
        "img-auth-isdir": "ၸဝ်ႈၵဝ်ႇ တိုၵ်ႉၶတ်းၸႂ်ႉ ၶဝ်ႈၸႂ်ႉ ၾူဝ်ႇတိူဝ်ႇ \"$1\" ယူႇ။\nၶႂၢင်းဝႆႉပၼ် ၵၢၼ်ၸႂ်ႉတိုဝ်းၾၢႆႇၵူၺ်း။",
        "img-auth-streaming": "သၢႆလႆ \"$1\" ။",
        "contribslink": "ၶဝ်ႈႁူမ်ႈ",
        "emaillink": "သူင်ႇ ဢီးမေးလ်",
        "autoblocker": "ယွၼ်ႉပိူဝ်ႈဝႃႈ ႁဵင်းလိၵ်ႈဢၢႆႇၽီႇၸဝ်ႈၵဝ်ႇၼႆႉ ထုၵ်ႇၸႂ်ႉဝႆႉ ၼင်ႇ \"[[User:$1|$1]]\" လႄႈ ထုၵ်ႉႁႄးတတ်းၵႂႃႇ ႁင်းမၼ်း။\nလွင်ႈတၢင်း ဢၼ်ပၼ်ဝႆႉ တွၼ်ႈတႃႇ ႁႄႉတတ်း  $1 ၼႆႉတႄႉ ပဵၼ် \"$2\"�",
-       "blocklogpage": "မၢႆတမ်းၵၢၼ်ႁႄႉတတ်း",
+       "blocklogpage": "မၢႆတမ်းၵၢၼ်ႁႄႉတတ်း",
        "blocklog-showlog": "ၽူႈၸႂ်ႉတိုဝ်းၵေႃႉၼႆႉ မိူဝ်ႈပူၼ်ႉမႃး ယၢမ်ႈထုၵ်ႇႁႄႉတတ်းဝႆႉယဝ်ႉ။\nမၢႆတမ်းၵၢၼ်ႁႄႉတတ်း တွၼ်ႈတႃႇဢိင်ပိုင်ႈၼၼ်ႉ ၵမ်ႉထႅမ်ဝႆႉပၼ် ၽၢႆႇတႂ်ႈၼႆႉယူႇ :�",
        "blocklog-showsuppresslog": "ၽူႈၸႂ်ႉတိုဝ်းၵေႃႉၼႆႉ မိူဝ်ႈပူၼ်ႉမႃး ယၢမ်ႈထုၵ်ႁႄႉတတ်းလႄႈ ထုၵ်ႇသိူင်ႇဝႆႉ။\nမၢႆတမ်းႁူမ်ႇဝႆႉ တွၼ်ႈတႃႇပိုင်ႈဢိင်ၼၼ်ႉ ၼႄဝႆႉပၼ် ၼင်ႇၽၢႆႇတႂ်ႈၼႆႉ :�",
        "blocklogentry": "[[$1]] ၵေႃႉထုၵ်ႇႁႄႉတတ်းဝႆႉ တႃႇၶၢဝ်းယၢမ်းတေသုတ်းသဵင်ႈ $2 $3",
        "allmessagesdefault": "လိၵ်ႈၶေႃႈၶၢဝ်ႇ ပိူင်ႇၵႅဝ်ႈ",
        "allmessagescurrent": "လိၵ်ႈၶေႃႈၶၢဝ်ႇ ယၢမ်းလဵဝ်",
        "allmessagestext": "ဢၼ်ၼႆႉၼႆႉ ပဵၼ် သဵၼ်ႈမၢႆၶွင် ၶေႃႈၶၢဝ်ႇပိူင်သၢင်ႈ ဢၼ်ၸႂ်ႉလႆႈ တီႈၼႂ်း လွၵ်းၸိုဝ်ႈ ဝီႇၶီႇမီႇတီႇယႃႇ။ ၶႅၼ်းတေႃႈ ဢႅဝ်ႇလႄႇတူၺ်း [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] လႄႈ သင်ၸိူဝ်ႉဝႃႈ ၸဝ်ႈၵဝ်ႇ မီးၵၢင်ၸႂ် တွၼ်ႈတႃႇ ၶဝ်ႈႁူမ်ႈ  ဢၼ်ၵဵဝ်ႇလူၺ်ႈ လွင်ႈပိၼ်ႇၽႃႇသႃႇ ဝီႇၶီႇမီႇတီႇယႃႇ [https://translatewiki.net translatewiki.net] ။",
-       "allmessagesnotsupportedDB": "ၼႃႈလိၵ်ႈၼႆႉ တေဢမ်ႇၸၢင်ႈၸႂ်ႉ ယွၼ်ႉပိူဝ်ႈဝႃႈ <strong>$wgUseDatabaseMessages</strong>ၼႆႉ ထုၵ်ႇဢိုတ်းၸႂ်ႉဝႆႉ။",
+       "allmessages-not-supported-database": "ၼႃႈလိၵ်ႈၼႆႉ တေဢမ်ႇၸၢင်ႈၸႂ်ႉ ယွၼ်ႉပိူဝ်ႈဝႃႈ <strong>$wgUseDatabaseMessages</strong>ၼႆႉ ထုၵ်ႇဢိုတ်းၸႂ်ႉဝႆႉ။",
        "allmessages-filter-legend": "တူဝ်ထွင်",
        "allmessages-filter": "ထွင်ၼင်ႇ သၢႆငၢႆ လွင်ႈမႄးၵမ်ႉၸႂ်:",
        "allmessages-filter-unmodified": "ဢၼ်ဢမ်ႇမူၼ်ႉမႄးဝႆႉ",
index 15eb07f..669b5a0 100644 (file)
        "minoreditletter": "සුළු",
        "newpageletter": "නව",
        "boteditletter": "රොබෝ",
-       "number_of_watching_users_pageview": "[ {{PLURAL:$1| එක් පරිශීලකයෙක් මුර-කරයි|පරිශීලකවරුන් $1 ක් මුර-කරති}} ]",
        "rc-change-size": "$1",
        "rc-change-size-new": "වෙනස් කළ පසු {{PLURAL:$1|බයිට|බයිටයන්}} $1 ක්",
        "newsectionsummary": "/* $1 */ නව ඡේදය",
        "img-auth-nopathinfo": "PATH_INFO සපයා නොමැත.\nමෙම තොරතුරු සැපයීම සඳහා ඔබගේ සේවා දායකයේ පරිස්ථිතීන් සකසා නොමැත.\nඑය CGI-පාදක වූවක් විය හැකි අතර img_auth සඳහා සහය නොදක්වයි.\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization බලන්න.",
        "img-auth-notindir": "ඉල්ලුම් කළ පෙත වින්‍යසගත උඩුගත කිරීම් නාමාවලියේ නැත.",
        "img-auth-badtitle": "\"$1\" මඟින් වලංගු මාතෘකාවක් ගොඩනැගිය නොහැකිය.",
-       "img-auth-nologinnWL": "ඔබ ඇතුල් වී නොමැති අතර \"$1\" සුදු ලැයිස්තුවේ නොමැත.",
        "img-auth-nofile": "\"$1\" ගොනුව නොපවතී.",
        "img-auth-isdir": "ඔබ \"$1\" නාමාවලියට පිවිසීමට උත්සාහ කරයි.\nඅවසර ලබා දෙන්නේ ගොනු ප්‍රවේශය සඳහා පමණි.",
        "img-auth-streaming": "\"$1\" ප්‍රවාහය වෙමින් පවතී.",
        "allmessagesdefault": "සාමාන්‍ය පණිවුඩ පෙළ",
        "allmessagescurrent": "වත්මන් පෙළ",
        "allmessagestext": "මේ මාධ්‍යවිකි නාමඅවකාශයෙහිදී  හමුවන පද්ධති පණිවුඩයන් ලැයිස්තුවකි.\nවර්ගීය මාධ්‍යවිකි ප්‍රාදේශීයකරණයට දායක වීමට ඔබ රිසි නම් කරුණාකර [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation මාධ්‍යවිකි ප්‍රාදේශීයකරණය]  සහ [https://translatewiki.net බීටාවිකි] වෙත පිවිසෙන්න.",
-       "allmessagesnotsupportedDB": "'''$wgUseDatabaseMessages''' අක්‍රීය කොට ඇති බැවින්, මෙම පිටුව භාවිතා කල නොහැක.",
+       "allmessages-not-supported-database": "'''$wgUseDatabaseMessages''' අක්‍රීය කොට ඇති බැවින්, මෙම පිටුව භාවිතා කල නොහැක.",
        "allmessages-filter-legend": "පෙරහන",
        "allmessages-filter": "පාරිභෝගීකරණ තත්ත්වය අනුව පෙරීම:",
        "allmessages-filter-unmodified": "වෙනසකට නතු නොකල",
index e825d4b..6b462ae 100644 (file)
@@ -39,7 +39,8 @@
                        "Pmikolas44",
                        "Fitoschido",
                        "Matěj Suchánek",
-                       "Vlad5250"
+                       "Vlad5250",
+                       "Robert Važan"
                ]
        },
        "tog-underline": "Podčiarkovať odkazy:",
@@ -88,7 +89,7 @@
        "underline-always": "Vždy",
        "underline-never": "Nikdy",
        "underline-default": "Podľa nastavení prehliadača alebo témy vzhľadu",
-       "editfont-style": "Štýl písma oblasti na úpravy:",
+       "editfont-style": "Štýl písma v editore:",
        "editfont-monospace": "S pevnou šírkou znaku",
        "editfont-sansserif": "Bezpätkové písmo",
        "editfont-serif": "Pätkové písmo",
        "resetpass-expired": "Platnosť vášho hesla vypršala. Pre prihlásenie si nastavte nové heslo.",
        "resetpass-expired-soft": "Platnosť vášho hesla vypršala, musíte si nastaviť nové. Zvoľte si nové heslo nebo kliknite na „{{int:authprovider-resetpass-skip-label}}“ a nastavte si ho neskôr.",
        "resetpass-validity-soft": "Vaše heslo je neplatné: $1\n\nVyberte si nové heslo, alebo kliknite na „{{int:authprovider-resetpass-skip-label}}“ a nastavte si ho neskôr.",
-       "passwordreset": "Reset hesla",
+       "passwordreset": "Obnova hesla",
        "passwordreset-text-one": "Pre získanie nového hesla vyplňte tento formulár.",
        "passwordreset-text-many": "{{PLURAL:$1|Pre získanie nového hesla e-mailom, zadajte jeden z údajov.}}",
        "passwordreset-disabled": "Obnovenie hesla bolo na tejto wiki zakázané.",
        "changeemail-submit": "Zmeniť e-mail",
        "changeemail-throttled": "Uskutočnili ste príliš mnoho neúspešných pokusov o prihlásenie. Prosím, počkajte $1 predtým, než to skúsite znova.",
        "changeemail-nochange": "Zadajte prosím odlišnú e-mailovú adresu.",
-       "resettokens": "Obnoviť tokeny",
+       "resettokens": "Reinicializovať kľúče",
        "resettokens-text": "Tu môžete obnoviť tokeny, ktoré umožňujú prístup k určitým súkromným údajom spojeným s vaším účtom.\n\nMali by ste to urobiť, ak ste ich omylom niekomu poskytli alebo ak bolo vaše konto zneužité.",
        "resettokens-no-tokens": "Neexistujú žiadne tokeny, ktoré by bolo možné obnoviť.",
        "resettokens-tokens": "Tokeny:",
        "prefs-watchlist-days-max": "Najviac $1 {{PLURAL:$1|deň|dni|dní}}",
        "prefs-watchlist-edits": "Počet úprav, ktorý sa zobrazí v rozšírenom zozname sledovaných:",
        "prefs-watchlist-edits-max": "Maximum: 1000",
-       "prefs-watchlist-token": "Token zoznamu sledovaných?",
+       "prefs-watchlist-token": "Kľúč pre sledovanie stránok",
+       "prefs-watchlist-managetokens": "Správa kľúčov",
        "prefs-misc": "Rôzne",
        "prefs-resetpass": "Zmeniť heslo",
        "prefs-changeemail": "Zmeniť alebo odstrániť e-mailovú adresu",
        "recentchangescount": "Štandardne zobrazovaný počet úprav:",
        "prefs-help-recentchangescount": "Toto sa týka posledných úprav, histórií stránok a záznamov.",
        "prefs-help-watchlist-token2": "Toto je tajný kľúč k webovému kanálu vášho zoznamu sledovaných stránok.\nkaždý, kto ho pozná si bude môcť prečítať váš zoznam sledovaných stránok, preto ho nezverejňujte.\n[[Special:ResetTokens|Kliknite sem, ak potrebujete vytvoriť nový]].",
+       "prefs-help-tokenmanagement": "Môžete vidieť a reinicializovať tajný kľúč k vašemu účtu, ktorý poskytuje prístup k webovému kanálu vášho zoznamu sledovaných stránok. Ktokoľvek, kto pozná tento kľúč, môže čítať váš zoznam sledovaných stránok, tak kľúč nezdieľajte.",
        "savedprefs": "Vaše nastavenia boli uložené.",
        "savedrights": "Práva {{GENDER:$1|používateľa|používateľky}} $1 boli uložené.",
        "timezonelegend": "Časové pásmo:",
        "prefs-common-config": "Spoločné CSS/JS pre všetky témy:",
        "prefs-reset-intro": "Túto stránku môžete použiť na vrátenie predvolených hodnôt vašich nastavení.\nTúto operáciu nemožno vrátiť.",
        "prefs-emailconfirm-label": "Overenie e-mailu:",
-       "youremail": "Váš e-mail²",
+       "youremail": "Email:",
        "username": "{{GENDER:$1|Používateľské meno}}:",
        "prefs-memberingroups": "{{GENDER:$2|Člen|Členovia}} {{PLURAL:$1|skupiny|skupín}}:",
        "group-membership-link-with-expiry": "$1 (do $2)",
        "prefs-timeoffset": "Časový posun",
        "prefs-advancedediting": "Všeobecné možnosti",
        "prefs-developertools": "Vývojárske nástroje",
-       "prefs-editor": "Používateľ",
+       "prefs-editor": "Editor",
        "prefs-preview": "Náhľad",
        "prefs-advancedrc": "Rozšírené možnosti",
        "prefs-advancedrendering": "Rozšírené možnosti",
        "prefs-advancedwatchlist": "Rozšírené možnosti",
        "prefs-displayrc": "Možnosti zobrazenia",
        "prefs-displaywatchlist": "Možnosti zobrazenia",
-       "prefs-tokenwatchlist": "Token",
+       "prefs-changeswatchlist": "Zobrazené zmeny",
+       "prefs-pageswatchlist": "Sledované stránky",
+       "prefs-tokenwatchlist": "Kľúč",
        "prefs-diffs": "Rozdiely",
        "prefs-help-prefershttps": "Táto voľba sa prejaví pri vašom ďalšom prihlásení.",
        "prefswarning-warning": "Vykonali ste zmeny v nastaveniach, ktoré zatiaľ nie sú uložené. Ak túto stránku opustíte bez kliknutia na „$1“, vaše nastavenia sa neaktualizujú.",
        "rcfilters-other-review-tools": "Ďalšie kontrolné nástroje",
        "rcfilters-group-results-by-page": "Zoskupiť výsledky podľa stránky",
        "rcfilters-activefilters": "Aktívne filtre",
+       "rcfilters-activefilters-hide": "Skryť",
        "rcfilters-advancedfilters": "Pokročilé filtre",
        "rcfilters-limit-title": "Zobraziť zmeny",
        "rcfilters-limit-and-date-label": "{{PLURAL:$1|Jedna úprava|$1 úpravy|$1 úprav}}, $2",
        "rcfilters-savedqueries-apply-and-setdefault-label": "Vytvoriť predvolený filter",
        "rcfilters-savedqueries-cancel-label": "Zrušiť",
        "rcfilters-savedqueries-add-new-title": "Uložiť súčasné nastavenie filtrov",
+       "rcfilters-savedqueries-already-saved": "Tieto filtre sú už uložené. Zmeňte niektoré nastavenia, ak chcete vytvoriť nový uložený filter.",
        "rcfilters-restore-default-filters": "Obnoviť predvolené filtre",
        "rcfilters-clear-all-filters": "Zrušiť všetky filtre",
        "rcfilters-show-new-changes": "Zobraziť najnovšie zmeny",
        "rcfilters-filter-editsbyself-description": "Vaše vlastné príspevky.",
        "rcfilters-filter-editsbyother-label": "Zmeny ostatných používateľov",
        "rcfilters-filter-editsbyother-description": "Všetky zmeny okrem vašich.",
-       "rcfilters-filtergroup-userExpLevel": "Registrácia a skúsenosť používateľov",
+       "rcfilters-filtergroup-user-experience-level": "Registrácia a skúsenosť používateľov",
        "rcfilters-filter-user-experience-level-registered-label": "Registrácia",
        "rcfilters-filter-user-experience-level-registered-description": "Prihlásení redaktori.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Neregistrovaní",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Filter „Drobné úpravy“ je v konflikte s jedným alebo viacerými filtrami podľa typu zmeny, pretože určité typy zmien sa nedajú označiť ako drobné. Dané filtre sú označené hore, v priestore „Aktívne filtre“.",
        "rcfilters-hideminor-conflicts-typeofchange": "Isté druhy úprav sa nedajú označiť ako drobné, tento filter je preto v konflikte s nasledujúcimi filtrami podľa typu zmeny: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Tento filter podľa typu zmeny je v konflikte s filtrom „Drobné zmeny“. Isté druhy úprav sa nedajú označiť ako drobné.",
-       "rcfilters-filtergroup-lastRevision": "Posledné verzie",
+       "rcfilters-filtergroup-lastrevision": "Posledné verzie",
        "rcfilters-filter-lastrevision-label": "Aktuálna verzia",
        "rcfilters-filter-lastrevision-description": "Len posledná úprava stránky.",
        "rcfilters-filter-previousrevision-label": "Nie najnovšia revízia",
        "minoreditletter": "d",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|sledujúci používateľ|sledujúci používatelia|sledujúcich používateľov}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|bajt|bajty|bajtov}} po zmene",
        "newsectionsummary": "/* $1 */ nová sekcia",
        "rc-enhanced-expand": "Zobraziť podrobnosti",
        "recentchangeslinked-feed": "Súvisiace úpravy",
        "recentchangeslinked-toolbox": "Súvisiace úpravy",
        "recentchangeslinked-title": "Zmeny týkajúce sa „$1”",
-       "recentchangeslinked-summary": "Vložte názov článku, aby ste videli zmeny stránok, na ktoré odkazuje alebo ktoré odkazujú na danú stránku (aby ste videli články v kategórii, zadajte Kategória:Názov kategórie).\nStránky, ktoré sa nachádzajú vo vašom [[Special:Watchlist|zozname sledovaných]] sú vyznačené <strong>hrubo</strong>.",
+       "recentchangeslinked-summary": "Vložte názov stránky, aby ste videli zmeny iných stránok, na ktoré odkazuje alebo ktoré odkazujú na danú stránku. (Ak chcete vidieť stránky v kategórii, zadajte {{ns:category}}:Názov kategórie).\nStránky, ktoré sa nachádzajú vo vašom [[Special:Watchlist|zozname sledovaných]] sú vyznačené <strong>hrubo</strong>.",
        "recentchangeslinked-page": "Názov stránky:",
        "recentchangeslinked-to": "Zobraziť zmeny na stránkach, ''ktoré odkazujú na'' zadanú stránku",
        "recentchanges-page-added-to-category": "[[:$1]] zaradená do kategórie",
        "img-auth-nopathinfo": "Váš server nie je nastavený tak, aby poskytoval tieto informácie.\nMôže byť založený na CGI a nedokáže podporovať img_auth.\nPozri https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Požadovaná cesta nie je v nastavenom adresári na nahrávanie.",
        "img-auth-badtitle": "Nepodarilo sa zostaviť platný názov z „$1“.",
-       "img-auth-nologinnWL": "Nie ste prihlásený a „$1“ nie je na bielej listine.",
        "img-auth-nofile": "Súbor „$1“ neexistuje.",
        "img-auth-isdir": "Pokúšate sa o prístup k adresáru „$1“.\nJe povolený iba prístup k súborom.",
        "img-auth-streaming": "Streamovanie „$1“.",
        "filehist-filesize": "veľkosť súboru",
        "filehist-comment": "komentár",
        "imagelinks": "Použitie súboru",
-       "linkstoimage": "Na tento obrázok {{PLURAL:$1|odkazuje nasledujúca stránka|odkazujú nasledujúce $1 stránky|odkazuje nasledujúcich $1 stránok}}:",
+       "linkstoimage": "Na tento súbor {{PLURAL:$1|odkazuje nasledujúca stránka|odkazujú nasledujúce $1 stránky|odkazuje nasledujúcich $1 stránok}}:",
        "linkstoimage-more": "Viac ako $1 {{PLURAL:$1|stránka odkazuje|stránky odkazujú|stránok odkazuje}} na tento súbor.\nNasledovný zoznam zobrazuje {{PLURAL:$1|prvú stránku odkazujúcu|prvé $1 stránky odkazujúce|prvých $1 stránok odkazujúcich}} iba na tento súbor.\nMôžete si pozrieť [[Special:WhatLinksHere/$2|úplný zoznam]].",
-       "nolinkstoimage": "Žiadne stránky neobsahujú odkazy na tento obrázok.",
+       "nolinkstoimage": "Žiadne stránky neobsahujú odkazy na tento súbor.",
        "morelinkstoimage": "Zobraziť [[Special:WhatLinksHere/$1|ďalšie odkazy]] na tento súbor.",
        "linkstoimage-redirect": "$1 (presmerovanie súboru) $2",
        "duplicatesoffile": "{{PLURAL:$1|Nasledujúci súbor je duplikát|Nasledujúce $1 súbory sú duplikáty||Nasledujúcich $1 súborov sú duplikáty}} tohto súboru ([[Special:FileDuplicateSearch/$2|podrobnosti]]):",
        "speciallogtitlelabel": "Cieľ (názov alebo {{ns:user}}:Používateľské meno):",
        "log": "Záznamy",
        "logeventslist-submit": "Zobraziť",
+       "logeventslist-patrol-log": "Kniha preverených úprav",
+       "logeventslist-tag-log": "Kniha značiek",
        "all-logs-page": "Všetky verejné záznamy",
        "alllogstext": "Kombinované zobrazenie všetkých dostupných záznamov {{GRAMMAR:genitív|{{SITENAME}}}}.\nMôžete zúžiť rozsah, ak zvolíte typ záznamu, používateľské meno alebo dotyčnú stránku (záleží na veľkosti písmen).",
        "logempty": "V zázname neboli nájdené zodpovedajúce položky.",
        "listgrouprights-namespaceprotection-header": "Obmedzenia menných priestorov",
        "listgrouprights-namespaceprotection-namespace": "Menný priestor",
        "listgrouprights-namespaceprotection-restrictedto": "Práva umožňujúce redaktorovi upravovať",
+       "listgrants": "Skupiny oprávnení",
        "trackingcategories": "Sledovacie kategórie",
        "trackingcategories-summary": "Táto stránka obsahuje zoznam sledovacích kategórií, ktoré automaticky pridáva softvér MediaWiki. Ich mená je možné zmeniť úpravou príslušných systémových hlásení v mennom priestore {{ns:8}}.",
        "trackingcategories-msg": "Sledovacia kategória",
        "deletionlog": "záznam zmazaní",
        "log-name-create": "Záznam vytvorení stránok",
        "log-description-create": "Toto je zoznam posledných vytvorených stránok.",
+       "logentry-create-create": "$1 {{GENDER:$2|vytvoril|vytvorila|vytvoril(a)}} stránku $3",
        "reverted": "Obnovené na skoršiu verziu",
        "deletecomment": "Dôvod:",
        "deleteotherreason": "Iný/ďalší dôvod:",
        "revertpage": "Posledné úpravy používateľa [[Special:Contributions/$2|$2]] ([[User talk:$2|diskusia]]) vrátené; bola obnovená posledná úprava $1",
        "revertpage-nouser": "Vrátené úpravy od skrytého používateľa na poslednú revíziu od {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Úpravy $1 vrátené; obnovená posledná verzia od $2.",
-       "rollback-success-notify": "Úpravy používateľa $1 boli vrátené;\nobnovená posledná revízia od používateľa $2. [$3 Zobraziť zmeny]",
        "sessionfailure-title": "Chyba relácie",
        "sessionfailure": "Zdá sa, že je problém s vašou prihlasovacou reláciou;\ntáto akcia bola zrušená ako prevencia proti zneužitiu relácie (session).\nProsím, stlačte \"naspäť\", obnovte stránku, z ktorej ste sa sem dostali, a skúste to znova.",
        "changecontentmodel": "Zmeniť model obsahu stránky",
        "allmessagesdefault": "štandardný text",
        "allmessagescurrent": "aktuálny text",
        "allmessagestext": "Toto je zoznam všetkých správ dostupných v mennom priestore MediaWiki.\nProsím, navštívte [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] a [https://translatewiki.net translatewiki.net] ak chcete prispieť k všeobecnej lokalizácii MediaWiki.",
-       "allmessagesnotsupportedDB": "Túto stránku nemožno použiť, pretože '''$wgUseDatabaseMessages''' je vypnuté.",
+       "allmessages-not-supported-database": "Túto stránku nemožno použiť, pretože '''$wgUseDatabaseMessages''' je vypnuté.",
        "allmessages-filter-legend": "Filter",
        "allmessages-filter": "Filter podľa stavu prispôsobenia:",
        "allmessages-filter-unmodified": "Nezmenené",
        "pageinfo-display-title": "Zobrazovaný názov",
        "pageinfo-default-sort": "Predvolený kľúč zoraďovania:",
        "pageinfo-length": "Dĺžka stránky (v bajtoch)",
+       "pageinfo-namespace": "Menný priestor",
        "pageinfo-article-id": "ID stránky",
        "pageinfo-language": "Jazyk obsahu stránky",
        "pageinfo-language-change": "zmeniť",
        "pageinfo-category-subcats": "Počet podkategórií",
        "pageinfo-category-files": "Počet súborov",
        "pageinfo-user-id": "ID používateľa",
+       "pageinfo-view-protect-log": "Zobraziť knihu zamknutí tejto stránky.",
        "markaspatrolleddiff": "Označiť ako preverené",
        "markaspatrolledtext": "Označiť túto stránku ako preverenú",
        "markaspatrolledtext-file": "Označiť túto revíziu súboru ako preverenú",
        "specialpages": "Špeciálne stránky",
        "specialpages-note-top": "Legenda",
        "specialpages-note-restricted": "* Bežné špeciálne stránky.\n* <strong class=\"mw-specialpagerestricted\">Špeciálne stránky s obmedzeným prístupom.</strong>",
-       "specialpages-group-maintenance": "Údržbové správy",
+       "specialpages-group-maintenance": "Údržba",
        "specialpages-group-other": "Iné špeciálne stránky",
        "specialpages-group-login": "Prihlásenie / registrácia",
        "specialpages-group-changes": "Posledné úpravy a záznamy",
        "tag-mw-new-redirect": "Nové presmerovanie",
        "tag-mw-removed-redirect": "Zrušené presmerovanie",
        "tag-mw-changed-redirect-target": "Zmena presmerovania",
-       "tag-mw-blank": "Vyprázdnenie",
+       "tag-mw-blank": "Vybielenie",
        "tag-mw-replace": "Náhrada",
        "tag-mw-rollback": "Rollback",
        "tag-mw-undo": "Vrátenie",
        "compare-invalid-title": "Názov, ktorý ste zadali nie je platný.",
        "compare-title-not-exists": "Názov, ktorý ste zadali neexistuje.",
        "compare-revision-not-exists": "Revízia, ktorú ste zadali, neexistuje.",
-       "diff-form": "'''formulár'''",
+       "diff-form": "Rozdiely",
        "dberr-problems": "Prepáčte! Táto stránka má práve technické problémy.",
        "dberr-again": "Skúste niekoľko minút počkať a potom opäť načítať stránku.",
        "dberr-info": "(Spojenie s databázovým serverom neúspešné: $1)",
        "json-error-unsupported-type": "Odovzdaná hodnota nekódovateľného typu",
        "headline-anchor-title": "Odkaz na túto sekciu",
        "special-characters-group-latin": "Latinka",
-       "special-characters-group-latinextended": "Latina rozšírené",
+       "special-characters-group-latinextended": "Rozšírenie latinky",
        "special-characters-group-ipa": "IPA",
        "special-characters-group-symbols": "Symboly",
        "special-characters-group-greek": "Grécke",
        "special-characters-group-thai": "Thajské",
        "special-characters-group-lao": "Laoské",
        "special-characters-group-khmer": "Khmer",
+       "special-characters-group-canadianaboriginal": "Písmo pôvodných obyvateľov Kanady",
        "special-characters-title-endash": "pomlčka",
        "special-characters-title-emdash": "dlhá pomlčka",
        "special-characters-title-minus": "mínus",
        "changecredentials": "Zmena prihlasovacích údajov",
        "removecredentials": "Odstránenie prihlasovacích údajov",
        "userjsispublic": "Uvedomte si prosím, že podstránky s JavaScriptom by nemali obsahovať tajné údaje, pretože sú viditeľné ostatným používateľom.",
-       "usercssispublic": "Uvedomte si prosím, že podstránky s CSS by nemali obsahovať tajné údaje, pretože sú viditeľné ostatným používateľom."
+       "usercssispublic": "Uvedomte si prosím, že podstránky s CSS by nemali obsahovať tajné údaje, pretože sú viditeľné ostatným používateľom.",
+       "passwordpolicies": "Pravidlá pre heslá"
 }
index 807ddd5..597c591 100644 (file)
        "mainpage": "پہلا پرت",
        "mainpage-description": "پہلا پرت",
        "policy-url": "Project:پالیسی",
-       "portal": "بیٹھک",
+       "portal": "برادری دا پھاٹک",
        "portal-url": "Project:دیوان عام",
-       "privacy": "پرائیویسی پالیسی",
-       "privacypage": "Project:پرائیویسی پالیسی",
+       "privacy": "رازداری پالیسی",
+       "privacypage": "منصوبہ: رازداری پالیسی",
        "badaccess": "نقص اجازت",
        "ok": "ٹھیک ہے",
        "retrievedfrom": "\"$1\" توں گھدا",
        "history-fieldset-title": "دہرائی کیتے لبھت",
        "histfirst": "قدیم ترین",
        "histlast": "تازہ ترین",
-       "historyempty": "(خالی)",
+       "historyempty": "خالی",
        "history-feed-title": "ریویژن رکارڈ",
        "history-feed-description": "وکی تے ایں ورقے دی ریویژن ہسٹری",
        "history-feed-item-nocomment": "$2 کوں $1",
        "rcfilters-highlightmenu-title": "رنگ چݨو",
        "rcfilters-filter-bots-label": "ٻوٹ",
        "rcfilters-filter-minor-label": "معمولی تبدیلیاں",
-       "rcfilters-filtergroup-lastRevision": "موجودہ حالت",
+       "rcfilters-filtergroup-lastrevision": "موجودہ حالت",
        "rcfilters-filter-lastrevision-label": "موجودہ حالت",
        "rclistfrom": "$3 $2 توں تھیوݨ آلیاں نویاں تبدیلیاں ݙکھاؤ",
        "rcshowhideminor": "$1 معمولی تبدیلیاں",
        "ipb-pages-label": "ورقے",
        "block-reason": "سبب:",
        "autoblocklist-submit": "ڳولو",
+       "blocklist-type": "قسم:",
+       "blocklist-type-opt-all": "یکے",
        "blocklist-reason": "سبب:",
        "infiniteblock": "بے انت",
        "blocklist-editing": "زیر ترمیم",
index d93d7d2..c0f8f55 100644 (file)
        "virus-scanfailed": "pregled ni uspel (koda $1)",
        "virus-unknownscanner": "neznan antivirusni program:",
        "logouttext": "'''Odjavili ste se.'''\n\nNekatere strani bodo morda še naprej prikazane, kot da ste prijavljeni, dokler ne boste izpraznili predpomnilnika brskalnika.",
+       "logging-out-notify": "Trenutno vas odjavljamo. Prosimo, počakajte.",
+       "logout-failed": "Trenutno se ne morete odjaviti: $1",
        "cannotlogoutnow-title": "Trenutno se ne morete odjaviti",
        "cannotlogoutnow-text": "Odjava ni možna pri uporabi $1.",
        "welcomeuser": "$1, dobrodošli!",
        "page_first": "prva",
        "page_last": "zadnja",
        "histlegend": "Izbira primerjave: označite okroglo polje ob redakciji za primerjavo in stisnite enter ali gumb na dnu strani.<br />\nLegenda: '''({{int:cur}})''' = primerjava s trenutno redakcijo, '''({{int:last}})''' = primerjava s prejšnjo redakcijo, '''{{int:minoreditletter}}''' = manjše urejanje.",
-       "history-fieldset-title": "Iskanje redakcij",
+       "history-fieldset-title": "Filtrirajte redakcije",
        "history-show-deleted": "Samo izbrisana redakcija",
        "histfirst": "najstarejše",
        "histlast": "najnovejše",
        "historysize": "({{PLURAL:$1|$1 zlog|$1 zloga|$1 zlogi|$1 zlogov}})",
-       "historyempty": "(prazno)",
+       "historyempty": "prazno",
        "history-feed-title": "Zgodovina strani",
        "history-feed-description": "Zgodovina navedene strani {{GRAMMAR:rodilnik|{{SITENAME}}}}",
        "history-feed-item-nocomment": "$1 ob $2",
        "right-reupload-own": "Nadomeščanje obstoječih lastnih datotek",
        "right-reupload-shared": "Nalaganje lokalnih zamenjav za datoteke iz skupnih večpredstavnostnih skladišč",
        "right-upload_by_url": "Nalaganje datotek iz naslova URL",
-       "right-purge": "Osvežitev predpomnilnika strani, brez potrditve",
+       "right-purge": "Osvežitev predpomnilnika strani",
        "right-autoconfirmed": "Brez vplivov omejitev dejavnosti glede na IP",
        "right-bot": "Naj bo obravnavan kot avtomatiziran postopek",
        "right-nominornewtalk": "Urejanja pogovornih strani, ki niso označena kot manjša, sprožijo obvestilo o novem sporočilu",
        "right-editsemiprotected": "Urejanje strani, zaščitenih kot »{{int:protect-level-autoconfirmed}}«",
        "right-editcontentmodel": "Urejanje vsebinskega modela strani",
        "right-editinterface": "Urejanje uporabniškega vmesnika",
-       "right-editusercss": "Urejanje CSS datotek drugih uporabnikov",
+       "right-editusercss": "Urejanje CSS-datotek drugih uporabnikov",
        "right-edituserjson": "Urejanje JSON-datotek drugih uporabnikov",
        "right-edituserjs": "Urejanje JavaScript datotek drugih uporabnikov",
        "right-editsitecss": "Urejanje CSS spletišča",
        "right-userrights": "Urejanje vseh uporabniških pravic",
        "right-userrights-interwiki": "Urejanje uporabniških pravic uporabnikov na drugih wikijih",
        "right-siteadmin": "Zaklepanje in odklepanje baze podatkov",
-       "right-override-export-depth": "Izvoz strani, vključno s povezaimi straneh do globine 5",
+       "right-override-export-depth": "Izvoz strani, vključno s povezanimi stranmi do globine 5",
        "right-sendemail": "Pošiljanje e-pošte drugim uporabnikom",
        "right-managechangetags": "Ustvarjanje in (dez)aktivacijo [[Special:Tags|oznak]]",
        "right-applychangetags": "Uveljavitev [[Special:Tags|oznak]] skupaj s spremembami",
        "action-changetags": "dodajanje in odstranjevanje poljubnih oznak na posameznih redakcijah in dnevniških vnosih",
        "action-deletechangetags": "izbris oznak iz zbirke podatkov",
        "action-purge": "počiščenje strani",
+       "action-apihighlimits": "uporabo višje omejitve poizvedb API",
+       "action-autoconfirmed": "neomejitev dejavnosti glede na IP",
+       "action-bigdelete": "brisanje strani z obsežno zgodovino",
+       "action-blockemail": "preprečite pošiljanja e-pošte drugemu uporabniku",
+       "action-bot": "obravnavo kot avtomatiziran postopek",
+       "action-editprotected": "urejanje strani, zaščitenih kot »{{int:protect-level-sysop}}«,",
+       "action-editsemiprotected": "urejanje strani, zaščitenih kot »{{int:protect-level-autoconfirmed}}«,",
+       "action-editinterface": "urejanje uporabniškega vmesnika",
+       "action-editusercss": "urejanje CSS-datotek drugih uporabnikov",
+       "action-edituserjson": "urejanje JSON-datotek drugih uporabnikov",
+       "action-edituserjs": "urejanje JavaScript datotek drugih uporabnikov",
+       "action-editsitecss": "urejanje CSS spletišča",
+       "action-editsitejson": "urejanje JSON spletišča",
+       "action-editsitejs": "urejanje JavaScripta spletišča",
+       "action-editmyusercss": "urejanje svojih uporabniških datotek CSS",
+       "action-editmyuserjson": "urejanje svojih uporabniških datotek JSON",
+       "action-editmyuserjs": "urejanje svojih uporabniških datotek JavaScript",
+       "action-viewsuppressed": "ogled redakcij skritih pred vsemi uporabniki",
+       "action-hideuser": "blokiranje uporabnika in skritje pred javnostjo",
+       "action-ipblock-exempt": "izogib blokadam IP-naslova, samodejnim blokadam in blokadam območij",
+       "action-unblockself": "odblokiranje samega sebe",
+       "action-noratelimit": "izogib omejitvam dejavnosti",
+       "action-reupload-own": "nadomeščanje obstoječih lastnih datotek",
+       "action-nominornewtalk": "to, da urejanja pogovornih strani, ki niso označena kot manjša, ne sprožijo obvestila o novem sporočilu,",
+       "action-markbotedits": "označitev vrnjenih urejanj kot urejanja botov",
+       "action-patrolmarks": "ogled oznak nadzorov v zadnjih spremembah",
+       "action-override-export-depth": "izvoz strani, vključno s povezanimi stranmi do globine 5,",
+       "action-suppressredirect": "možnost izpuščanja preusmeritve pri premikanju strani",
        "nchanges": "$1 {{PLURAL:$1|sprememba|spremembi|spremembe|sprememb|sprememb}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|od zadnjega obiska}}",
        "enhancedrc-history": "zgodovina",
        "rcfilters-savedqueries-already-saved": "Te filtre ste že shranili. Uporabite svoje nastavitve, da ustvarite nov Shranjen filter.",
        "rcfilters-restore-default-filters": "Obnovi privzete filtre",
        "rcfilters-clear-all-filters": "Počisti vse filtre",
-       "rcfilters-show-new-changes": "Ogled najnovejših sprememb",
+       "rcfilters-show-new-changes": "Ogled novih sprememb od $1",
        "rcfilters-search-placeholder": "Filtriraj zadnje spremembe (uporabi meni ali vnesi ime filtra)",
        "rcfilters-invalid-filter": "Neveljaven filter",
        "rcfilters-empty-filter": "Ni dejavnih filtrov. Prikazani so vsi prispevki.",
        "rcfilters-filter-editsbyself-description": "Tvoja lastna urejanja.",
        "rcfilters-filter-editsbyother-label": "Spremembe drugih",
        "rcfilters-filter-editsbyother-description": "Vse spremembe razen tvojih.",
-       "rcfilters-filtergroup-userExpLevel": "Prijava in izkušnje uporabnika",
+       "rcfilters-filtergroup-user-experience-level": "Prijava in izkušnje uporabnika",
        "rcfilters-filter-user-experience-level-registered-label": "Registrirani",
        "rcfilters-filter-user-experience-level-registered-description": "Prijavljeni uporabniki.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Neregistrirani",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Filter »Manjša urejanja« je v sporu z enim ali več filtri Vrsta spremembe, ker nekaterih vrst urejanj ni možno označiti kot »manjša«. Filtri v sporu so označeni v območju Dejavni filtri zgoraj.",
        "rcfilters-hideminor-conflicts-typeofchange": "Nekaterih vrst sprememb ni možno označiti kot »manjše«, zato je ta filter v sporu z naslednjimi filtri Vrsta spremembe: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Ta filter Vrsta spremembe je v sporu s filtrom »Manjše urejanje«. Nekaterih vrst sprememb ni možno označiti kot »manjše«.",
-       "rcfilters-filtergroup-lastRevision": "Najnovejše redakcije",
+       "rcfilters-filtergroup-lastrevision": "Najnovejše redakcije",
        "rcfilters-filter-lastrevision-label": "Najnovejša redakcija",
        "rcfilters-filter-lastrevision-description": "Samo najnovejša sprememba strani.",
        "rcfilters-filter-previousrevision-label": "Nenajnovejša redakcija",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[temo {{PLURAL:$1|spremlja|spremljata|spremljajo|spremlja|spremlja}} $1 {{PLURAL:$1|uporabnik|uporabnika|uporabniki|uporabnikov|uporabnikov}}]",
        "rc-change-size-new": "po spremembi: $1 {{PLURAL:$1|zlog|zloga|zlogi|zlogov}}",
        "newsectionsummary": "/* $1 */ nov razdelek",
        "rc-enhanced-expand": "Pokaži podrobnosti",
        "img-auth-nopathinfo": "Manjka informacija o poti.\nVaš strežnik mora biti nastavljen tako, da posreduje spremenljivki REQUEST_URI in/ali PATH_INFO.\nČe je, poskusite omogočiti $wgUsePathInfo.\nOglejte si  https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Zahtevana pot ni v konfigurirani mapi za nalaganje.",
        "img-auth-badtitle": "Ni mogoče sestaviti veljavnega naslova iz »$1«.",
-       "img-auth-nologinnWL": "Niste prijavljeni in »$1« ni na seznamu dovoljenih datotek.",
        "img-auth-nofile": "Datoteka »$1« ne obstaja.",
        "img-auth-isdir": "Poskušate dostopati do mape »$1«.\nDovoljeno je samo dostopanje do datotek.",
        "img-auth-streaming": "Pretakanje »$1«.",
        "delete-confirm": "Brisanje »$1«",
        "delete-legend": "Izbriši",
        "historywarning": "<strong>Opozorilo:</strong> Stran, ki jo nameravate izbrisati, ima zgodovino s približno $1 {{PLURAL:$1|redakcijo|redakcijama|redakcijami}}:",
-       "historyaction-submit": "Prikaži",
+       "historyaction-submit": "Pokaži redakcije",
        "confirmdeletetext": "Iz zbirke podatkov boste izbrisali stran ali sliko skupaj z vso njeno zgodovino.\nProsimo, '''potrdite''', da to resnično želite, da razumete posledice dejanja in da se ravnate po [[{{MediaWiki:Policy-url}}|pravilih]].",
        "actioncomplete": "Poseg je končan",
        "actionfailed": "Dejanje spodletelo",
        "deleting-backlinks-warning": "<strong>Opozorilo:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Druge strani]] se povezujejo na ali vključujejo stran, ki jo nameravate izbrisati.",
        "deleting-subpages-warning": "<strong>Opozorilo:</strong> Stran, ki jo nameravate izbrisati, ima [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|podstran|$1 podstrani|51=več kot 50 podstrani}}]].",
        "rollback": "Vrni spremembe",
+       "rollback-confirmation-confirm": "Prosimo, potrdite:",
+       "rollback-confirmation-yes": "Vrni",
+       "rollback-confirmation-no": "Prekliči",
        "rollbacklink": "vrni",
        "rollbacklinkcount": "vrni $1 {{PLURAL:$1|urejanje|urejanji|urejanja|urejanj}}",
        "rollbacklinkcount-morethan": "vrni več kot $1 {{PLURAL:$1|urejanje|urejanji|urejanja|urejanj}}",
        "revertpage": "vrnitev sprememb uporabnika [[Special:Contributions/$2|$2]] ([[User talk:$2|pogovor]]) na zadnje urejanje uporabnika [[User:$1|$1]]",
        "revertpage-nouser": "vrnitev sprememb skritega uporabnika na zadnjo redakcijo {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Razveljavljene spremembe {{GENDER:$3|uporabnika|uporabnice}} $1;\nvrnjeno na urejanje {{GENDER:$4|uporabnika|uporabnice}} $2.",
-       "rollback-success-notify": "Povrnili smo urejanja $1;\nspremenjeno nazaj na zadnjo redakcijo $2. [$3 Prikaži spremembe]",
        "sessionfailure-title": "Neuspeh seje",
        "sessionfailure": "Zdi se, da z vašo sejo prijave obstaja težava;\nto dejanje smo preklicali, da bi preprečili morebitno ugrabitev seje. Prosimo, ponovno potrdite obrazec.",
        "changecontentmodel": "Spremeni model vsebine strani",
        "mycontris": "Prispevki",
        "anoncontribs": "Prispevki",
        "contribsub2": "Za {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "Za {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "Uporabniški račun »$1« ni registriran.",
        "negative-namespace-not-supported": "Imenski prostori z negativnimi vrednostmi niso podprti.",
        "nocontribs": "Ne najdem nobene merilom ustrezajoče spremembe.",
        "blocklist-userblocks": "skrij blokade računov",
        "blocklist-tempblocks": "skrij začasne blokade",
        "blocklist-addressblocks": "skrij blokade posameznih IP-naslovov",
+       "blocklist-type": "Vrsta:",
+       "blocklist-type-opt-all": "Vse",
+       "blocklist-type-opt-sitewide": "Po celotni strani",
+       "blocklist-type-opt-partial": "Delno",
        "blocklist-rangeblocks": "skrij blokade razponov",
        "blocklist-timestamp": "Časovni žig",
        "blocklist-target": "Cilj",
        "blocklist-editing-page": "strani",
        "blocklist-editing-ns": "imenski prostori",
        "ipblocklist-empty": "Seznam blokad je prazen.",
-       "ipblocklist-no-results": "Zahtevan IP-naslov ali uporabniško ime ni blokirano.",
+       "ipblocklist-no-results": "Ne najdemo ujemajočih blokov za zahtevan IP-naslov ali uporabniško ime.",
        "blocklink": "blokiraj",
        "unblocklink": "deblokiraj",
        "change-blocklink": "spremeni blokado",
+       "empty-username": "(uporabniško ime ni na voljo)",
        "contribslink": "prispevki",
        "emaillink": "pošljite e-pošto",
        "autoblocker": "Urejanje vam je bilo samodejno onemogočeno, saj je vaš IP-naslov pred kratkim uporabljal »[[User:$1|$1]]«.\nRazlog za blokado uporabnika $1 je: »$2«",
        "allmessagesdefault": "Prednastavljeno besedilo",
        "allmessagescurrent": "Trenutno besedilo",
        "allmessagestext": "Navedena so v imenskem prostoru MediaWiki dostopna sistemska sporočila.\nZa lokalizacijo in prevajanje obiščite [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki] in [https://translatewiki.net translatewiki.net] ter tako prispevajte k splošnemu prevodu programja.",
-       "allmessagesnotsupportedDB": "Te strani ni mogoče uporabljati, ker je bilo '''$wgUseDatabaseMessages''' izključeno.",
+       "allmessages-not-supported-database": "Te strani ni mogoče uporabljati, ker je bilo '''$wgUseDatabaseMessages''' izključeno.",
        "allmessages-filter-legend": "Filter",
        "allmessages-filter": "Filtriraj po prilagoditvenem stanju:",
        "allmessages-filter-unmodified": "Nespremenjen",
        "confirm-unwatch-top": "Odstranim stran z vašega spiska nadzorov?",
        "confirm-rollback-button": "V redu",
        "confirm-rollback-top": "Povrnemo urejanja te strani?",
+       "confirm-rollback-bottom": "Dejanje bo v trenutku vrnilo izbrane spremembe na strani.",
        "confirm-mcrrestore-title": "Obnovi redakcijo",
        "confirm-mcrundo-title": "Razveljavi spremembo",
        "mcrundofailed": "Razveljavitev ni uspela",
        "passwordpolicies-policyflag-forcechange": "treba spremeniti ob prijavi",
        "passwordpolicies-policyflag-suggestchangeonlogin": "predlagaj zamenjavo ob prijavi",
        "easydeflate-invaliddeflate": "Dana vsebina ni pravilno stisnjena",
-       "unprotected-js": "Iz varnostnih razlogov JavaScripta ni možno naložiti z nezaščitenih strani. Prosimo, da JavaScript ustvarite samo v imenskem prostoru MediaWiki ali kot uporabniško podstran."
+       "unprotected-js": "Iz varnostnih razlogov JavaScripta ni možno naložiti z nezaščitenih strani. Prosimo, da JavaScript ustvarite samo v imenskem prostoru MediaWiki ali kot uporabniško podstran.",
+       "userlogout-continue": "Če se želite odjaviti, [$1 pojdite na stran za odjavo].",
+       "userlogout-sessionerror": "Odjava je spodletela zaradi napake seje. Prosimo, [$1 poskusite znova]."
 }
index d1e509f..a56aa2c 100644 (file)
@@ -17,7 +17,8 @@
                        "아라",
                        "Macofe",
                        "Fitoschido",
-                       "Ghiutun"
+                       "Ghiutun",
+                       "ToBeFree"
                ]
        },
        "tog-underline": "Verknipfonga unterstreeicha:",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|beobachtender|beobachtende}} Nutzer]",
        "newsectionsummary": "Neuer Obschnitt /* $1 */",
        "rc-enhanced-expand": "Details oazeega (beneetigt JavaScript)",
        "rc-enhanced-hide": "Details verstecka",
        "allmessagesname": "Noame",
        "allmessagesdefault": "Standardtext",
        "allmessagestext": "Dies ies anne Liste dar MediaWiki-Systemtexte.\nBesiche de Seyta [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki-Lokalisierung] und [https://translatewiki.net translatewiki.net], wenn du diech oa dar Lokalisierung vu MediaWiki beteiliga mechtest.",
-       "allmessagesnotsupportedDB": "Diese Spezialseyte stieht ne zur Verfigung, do se ieber dann Parameter <tt>$wgUseDatabaseMessages</tt> deaktiviert wurde.",
+       "allmessages-not-supported-database": "Diese Spezialseyte stieht ne zur Verfigung, do se ieber dann Parameter <tt>$wgUseDatabaseMessages</tt> deaktiviert wurde.",
        "allmessages-filter-all": "Olle",
        "allmessages-language": "Sproache:",
        "allmessages-filter-submit": "Lus",
        "tooltip-watch": "Fiege diese Seite denner Beobachtungsliste hinzu",
        "tooltip-recreate": "Seite neu erstella, obwohl se geläscht wurde.",
        "tooltip-upload": "Huchloada starta",
-       "tooltip-rollback": "Moacht olle letzta Änderunga dar Seite, de vum gleichen Benutzer vurgenumma waan sein, dorch ocke eenen Klick rieckgängig.",
+       "tooltip-rollback": "Moacht olle letzta Änderunga dar Seite, de vum selben Benutzer vurgenumma waan sein, dorch ocke eenen Klick rieckgängig.",
        "tooltip-undo": "Moacht lediglich diese eene Änderung rieckgängig on zeigt doas Resultat ei dar Vorschau oa, damit ei dar Zusommafassungszeile eene Begründung angegeba waan koan.",
        "tooltip-summary": "Gib eine kurze Zusammenfassung ein",
        "anonymous": "{{PLURAL:$1|Anonymer Nutzer|Anonyme Nutzer}} uff {{SITENAME}}",
index 4288c4a..c2401af 100644 (file)
@@ -6,7 +6,8 @@
                        "Mimursal",
                        "Yariiska",
                        "아라",
-                       "Macofe"
+                       "Macofe",
+                       "Amire80"
                ]
        },
        "tog-underline": "Linkiga hoos ka calaamadeysan:",
        "allmessagesdefault": "Qoraalka la'isku ogyahay",
        "allmessagescurrent": "Qoraalka hada qoran",
        "allmessagestext": "Kan waa liiska fariimaha systemka oo laga heli karo xarun magaceedka MediaWiki.\nFadlan booqo [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] iyo [https://translatewiki.net translatewiki.net] hadii aad rabto in aad wax ku darsatid guud ahaanba MediaWiki ku fasirida luqadaada.",
-       "allmessagesnotsupportedDB": "'''{{ns:special}}:Allmessages''' la'ma isticmaalikaro, '''$wgUseDatabaseMessages''' oo dansan daraadeed.",
+       "allmessages-not-supported-database": "!!FUZZY!!'''{{ns:special}}:Allmessages''' la'ma isticmaalikaro, '''$wgUseDatabaseMessages''' oo dansan daraadeed.",
        "allmessages-language": "Luqad:",
        "allmessages-filter-submit": "Soco",
        "thumbnail-more": "Weyneey",
        "version-poweredby-others": "kuwa kale",
        "redirect-file": "Magaca faylka",
        "fileduplicatesearch-submit": "Raadi",
-       "specialpages": "bogagga khaaska ah",
+       "specialpages": "Bogagga khaaska ah",
        "specialpages-note-top": "Furaha",
        "specialpages-group-pages": "liiska maqaalada",
        "blankpage": "Bog masaxan",
index 22eca1b..004bb17 100644 (file)
        "rcfilters-filter-editsbyself-description": "Kontributet tuaja.",
        "rcfilters-filter-editsbyother-label": "Kontributet nga të tjerët",
        "rcfilters-filter-editsbyother-description": "Të gjitha ndryshimet përveç nga ti.",
-       "rcfilters-filtergroup-userExpLevel": "Përdoruesit e regjistruar dhe me eksperience",
+       "rcfilters-filtergroup-user-experience-level": "Përdoruesit e regjistruar dhe me eksperience",
        "rcfilters-filter-user-experience-level-registered-label": "Regjistruar",
        "rcfilters-filter-user-experience-level-registered-description": "Redaktorët e kyçur",
        "rcfilters-filter-user-experience-level-unregistered-label": "Ç'regjistruar",
        "rcfilters-filter-categorization-description": "Regjistri i faqeve të shtuara ose hequra nga kategoritë.",
        "rcfilters-filter-logactions-label": "Veprimet e regjistruara",
        "rcfilters-filter-logactions-description": "Veprimet administrative, krijimet e llogarive, fshirjet e faqeve, ngarkimet...",
-       "rcfilters-filtergroup-lastRevision": "Rishikimet e fundit",
+       "rcfilters-filtergroup-lastrevision": "Rishikimet e fundit",
        "rcfilters-filter-lastrevision-label": "Versioni më i fundit",
        "rcfilters-filter-lastrevision-description": "Vetëm dryshimet më të fundit në një faqe.",
        "rcfilters-filter-previousrevision-label": "Jo rishimet e fundit",
        "minoreditletter": "v",
        "newpageletter": "R",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 duke u mbikqyrur nga {{PLURAL:$1|përdorues|përdorues}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|bajt|bajtë}} pas ndryshimit",
        "newsectionsummary": "/* $1 */ seksion i ri",
        "rc-enhanced-expand": "Trego detajet",
        "img-auth-nopathinfo": "Mungon PATH_INFO.\nShërbyesi juaj nuk e kalon këtë informacion.\nMund të jetë CGI-bazuar dhe nuk mund të mbështesë img_auth.\nShiko https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Kërkesa nuk është në drejtorinë e ngarkimeve të konfiguruara.",
        "img-auth-badtitle": "Nuk mund të krihohej një titull i vlefshëm nga \"$1\".",
-       "img-auth-nologinnWL": "Ju nuk jeni i regjistruar dhe \"$1\" nuk është në listën e bardhë.",
        "img-auth-nofile": "Skeda \"$1\" nuk ekziston.",
        "img-auth-isdir": "Ju po përpiqeni të hyni në një drejtori \"$1\".\nVetëm  qasja e skedës është e lejuar.",
        "img-auth-streaming": "Duke ngarkuar \"$1\"",
        "allmessagesdefault": "Teksti i parazgjedhur",
        "allmessagescurrent": "Teksti i tanishëshm",
        "allmessagestext": "Kjo është një listë e të gjitha faqeve në hapësirën MediaWiki:\nJu lutemi vizitoni [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] dhe [https://translatewiki.net translatewiki.net] nëse dëshironi të kontribuoni në lokalizimin e përgjithshëm MediaWiki",
-       "allmessagesnotsupportedDB": "Kjo faqe nuk mund të përdoret sepse '''$wgUseDatabaseMessages''' është çaktivizuar.",
+       "allmessages-not-supported-database": "Kjo faqe nuk mund të përdoret sepse '''$wgUseDatabaseMessages''' është çaktivizuar.",
        "allmessages-filter-legend": "Filtër",
        "allmessages-filter": "Filtroni nga shteti",
        "allmessages-filter-unmodified": "E pandryshuar",
index 2bfc929..3cd2e59 100644 (file)
        "tog-numberheadings": "Аутоматски нумериши наслове",
        "tog-editondblclick": "Омогући уређивање страница двоструким кликом",
        "tog-editsectiononrightclick": "Омогући уређивање одељака десним кликом на њихове наслове",
-       "tog-watchcreations": "Додај странице које направим и датотеке које отпремим на мој списак надгледања",
-       "tog-watchdefault": "Додај странице и датотеке које уредим на мој списак надгледања",
-       "tog-watchmoves": "Додај странице и датотеке које преместим на мој списак надгледања",
-       "tog-watchdeletion": "Додај странице и датотеке које избришем на мој списак надгледања",
-       "tog-watchuploads": "Додај нове датотеке које отпремим на мој списак надгледања",
-       "tog-watchrollback": "Додај странице на којима сам извршио враћање измена на мој списак надгледања",
+       "tog-watchcreations": "Додаји странице које направим и датотеке које отпремим на мој списак надгледања",
+       "tog-watchdefault": "Додаји странице и датотеке које уредим на мој списак надгледања",
+       "tog-watchmoves": "Додаји странице и датотеке које преместим на мој списак надгледања",
+       "tog-watchdeletion": "Додаји странице и датотеке које избришем на мој списак надгледања",
+       "tog-watchuploads": "Додаји нове датотеке које отпремим на мој списак надгледања",
+       "tog-watchrollback": "Додаји странице на којима сам извршио враћање измена на мој списак надгледања",
        "tog-minordefault": "Подразумевано означавај све измене као мање",
        "tog-previewontop": "Приказуј претпреглед пре оквира за уређивање",
        "tog-previewonfirst": "Приказуј претпреглед при првој измени",
-       "tog-enotifwatchlistpages": "Ð\9fоÑ\88аљи ми е-поруку када се промени страница или датотека са мог списка надгледања",
+       "tog-enotifwatchlistpages": "Шаљи ми е-поруку када се промени страница или датотека са мог списка надгледања",
        "tog-enotifusertalkpages": "Пошаљи ми е-поруку кад се промени моја корисничка страница за разговор",
-       "tog-enotifminoredits": "Ð\9fоÑ\88аљи ми е-поруку и код мањих измена страница и датотека",
-       "tog-enotifrevealaddr": "Ð\9eÑ\82кÑ\80иÑ\98 Ð¼Ð¾Ñ\98Ñ\83 Ð°Ð´Ñ\80еÑ\81Ñ\83 Ðµ-поÑ\88Ñ\82е у е-порукама за обавештавање",
+       "tog-enotifminoredits": "Шаљи ми е-поруку и код мањих измена страница и датотека",
+       "tog-enotifrevealaddr": "Ð\9eÑ\82кÑ\80иÑ\98 Ð¼Ð¾Ñ\98Ñ\83 Ðµ-адÑ\80еÑ\81Ñ\83 у е-порукама за обавештавање",
        "tog-shownumberswatching": "Прикажи број корисника који надгледају",
        "tog-oldsig": "Ваш постојећи потпис:",
        "tog-fancysig": "Сматрај потпис као викитекст (без аутоматског повезивања)",
        "tog-uselivepreview": "Приказуј претпреглед без поновног учитавања странице",
-       "tog-forceeditsummary": "УпозоÑ\80и ме када не унесем опис измене",
+       "tog-forceeditsummary": "УпозоÑ\80аваÑ\98 ме када не унесем опис измене",
        "tog-watchlisthideown": "Сакривај моје измене са списка надгледања",
        "tog-watchlisthidebots": "Сакривај измене ботова са списка надгледања",
        "tog-watchlisthideminor": "Сакривај мање измене са списка надгледања",
        "tog-watchlisthideliu": "Сакривај измене пријављених корисника са списка надгледања",
-       "tog-watchlistreloadautomatically": "Аутоматски поново учитај списак надгледања кад год се филтер промени (потребан јаваскрипт)",
-       "tog-watchlistunwatchlinks": "Додај означиваче за прекид надгледања/нагледање ({{int:Watchlist-unwatch}}/{{int:Watchlist-unwatch-undo}}) на надгледане странице са променама (за функционалност пребацивања је потребан јаваскрипт)",
+       "tog-watchlistreloadautomatically": "Аутоматски поново учитај списак надгледања кад год се филтер промени (потребан JavaScript)",
+       "tog-watchlistunwatchlinks": "Додаји означиваче за прекид надгледања/нагледање ({{int:Watchlist-unwatch}}/{{int:Watchlist-unwatch-undo}}) на надгледане странице са променама (за функционалност пребацивања је потребан JavaScript)",
        "tog-watchlisthideanons": "Сакривај измене анонимних корисника са списка надгледања",
        "tog-watchlisthidepatrolled": "Сакривај патролиране измене са списка надгледања",
        "tog-watchlisthidecategorization": "Сакривај категоризацију страница",
-       "tog-ccmeonemails": "Ð\9fоÑ\88аљи ми копије е-порука које пошаљем другим корисницима",
+       "tog-ccmeonemails": "Шаљи ми копије е-порука које пошаљем другим корисницима",
        "tog-diffonly": "Не приказуј садржај странице испод разлика",
        "tog-showhiddencats": "Приказуј скривене категорије",
        "tog-norollbackdiff": "Не приказуј разлику након извршеног враћања",
-       "tog-useeditwarning": "УпозоÑ\80и ме када напуштам страницу за уређивање са несачуваним променама",
+       "tog-useeditwarning": "УпозоÑ\80аваÑ\98 ме када напуштам страницу за уређивање са несачуваним променама",
        "tog-prefershttps": "Увек користи безбедну везу док сам пријављен/а.",
-       "underline-always": "Увек",
-       "underline-never": "Ð\9dикад",
-       "underline-default": "Ð\9fрема теми или прегледачу",
+       "underline-always": "увек",
+       "underline-never": "никад",
+       "underline-default": "према теми или прегледачу",
        "editfont-style": "Стил фонта у оквиру за уређивање:",
-       "editfont-monospace": "Сразмерно широк фонт",
-       "editfont-sansserif": "Ð\91есерифни фонт",
-       "editfont-serif": "Серифни фонт",
+       "editfont-monospace": "сразмерно широк фонт",
+       "editfont-sansserif": "бесерифни фонт",
+       "editfont-serif": "серифни фонт",
        "sunday": "недеља",
        "monday": "понедељак",
        "tuesday": "уторак",
        "pool-servererror": "Услуга бројача редова није доступна ($1).",
        "poolcounter-usage-error": "Грешка при употреби: $1",
        "aboutsite": "О пројекту {{SITENAME}}",
-       "aboutpage": "Project:Ð\9e¿Ñ\80оÑ\98екÑ\82Ñ\83_{{SITENAME}}",
+       "aboutpage": "Project:Ð\9e½Ð°Ð¼Ð°",
        "copyright": "Садржај је доступан под лиценцом $1 осим ако је другачије наведено.",
        "copyrightpage": "{{ns:project}}:Ауторска права",
        "currentevents": "Актуелности",
        "feed-atom": "Atom",
        "feed-rss": "RSS",
        "red-link-title": "$1 (страница не постоји)",
-       "sort-descending": "СоÑ\80Ñ\82иÑ\80ај опадајуће",
-       "sort-ascending": "СоÑ\80Ñ\82иÑ\80ај растуће",
+       "sort-descending": "Ð\9fоÑ\80еÑ\92ај опадајуће",
+       "sort-ascending": "Ð\9fоÑ\80еÑ\92ај растуће",
        "nstab-main": "Страница",
        "nstab-user": "{{GENDER:{{BASEPAGENAME}}|Корисник|Корисница}}",
        "nstab-media": "Медији",
        "nosuchaction": "Нема такве радње",
        "nosuchactiontext": "Радња која је наведена у УРЛ-у није важећа.\nМожда сте погрешно откуцали УРЛ или сте следили покварену везу.\nОво такође може да указује на грешку у софтверу који користи {{SITENAME}}.",
        "nosuchspecialpage": "Нема такве посебне странице",
-       "nospecialpagetext": "<strong>Ð\97аÑ\85Ñ\82евали Ñ\81Ñ\82е Ð½ÐµÐ²Ð°Ð»Ð¸Ð´Ð½Ñ\83 Ð¿Ð¾Ñ\81ебнÑ\83 Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\83.</strong>\n\nСпиÑ\81ак Ð²Ð°Ð»Ð¸Ð´Ð½Ð¸Ñ\85 Ð¿Ð¾Ñ\81ебниÑ\85 Ñ\81Ñ\82Ñ\80аниÑ\86а Ð¼Ð¾Ð¶Ðµ Ð´Ð° Ñ\81е Ð¿Ñ\80онаÑ\92е на „[[Special:SpecialPages|{{int:specialpages}}]]”.",
+       "nospecialpagetext": "<strong>ТÑ\80ажили Ñ\81Ñ\82е Ð½ÐµÐ²Ð°Ð¶ÐµÑ\9bÑ\83 Ð¿Ð¾Ñ\81ебнÑ\83 Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\83.</strong>\n\nСпиÑ\81ак Ð²Ð°Ð¶ÐµÑ\9bиÑ\85 Ð¼Ð¾Ð¶Ðµ Ñ\81е Ð¿Ñ\80онаÑ\92и на „[[Special:SpecialPages|{{int:specialpages}}]]”.",
        "error": "Грешка",
        "databaseerror": "Грешка у бази података",
        "databaseerror-text": "Дошло је до грешке у упиту базе података. \nОво може да указује на грешку у софтверу.",
        "yourpasswordagain": "Поново унеси лозинку:",
        "createacct-yourpasswordagain": "Потврдите лозинку",
        "createacct-yourpasswordagain-ph": "Поново унесите лозинку",
-       "userlogin-remembermypassword": "Ð\9eÑ\81Ñ\82ави Ð¼Ðµ Ð¿Ñ\80иÑ\98авÑ\99еног/Ñ\83",
+       "userlogin-remembermypassword": "Ð\9dе Ð¾Ð´Ñ\98авÑ\99Ñ\83Ñ\98 Ð¼Ðµ",
        "userlogin-signwithsecure": "Користите безбедну везу",
        "cannotlogin-title": "Пријава није могућа",
        "cannotlogin-text": "Пријава није могућа",
        "userlogin-loggedin": "Већ сте пријављени као {{GENDER:$1|$1}}.\nКористите доњи образац да бисте се пријавили као други корисник.",
        "userlogin-reauth": "Морате да се поново пријавите да бисте верификовали да сте {{GENDER:$1|$1}}.",
        "userlogin-createanother": "Отвори још један налог",
-       "createacct-emailrequired": "Ð\90дÑ\80еÑ\81а Ðµ-поÑ\88Ñ\82е",
-       "createacct-emailoptional": "Ð\90дÑ\80еÑ\81а Ðµ-поÑ\88Ñ\82е (необавезно)",
-       "createacct-email-ph": "УнеÑ\81иÑ\82е Ð°Ð´Ñ\80еÑ\81Ñ\83 Ðµ-поÑ\88Ñ\82е",
-       "createacct-another-email-ph": "УнеÑ\81иÑ\82е Ð°Ð´Ñ\80еÑ\81Ñ\83 Ðµ-поÑ\88Ñ\82е",
-       "createaccountmail": "Ð\9aоÑ\80иÑ\81Ñ\82и Ð¿Ñ\80ивÑ\80еменÑ\83, Ð½Ð°Ñ\81Ñ\83миÑ\87нÑ\83 Ð»Ð¾Ð·Ð¸Ð½ÐºÑ\83 Ð¸ Ð¿Ð¾Ñ\88аÑ\99и Ñ\98е Ð½Ð° Ð½Ð°Ð²ÐµÐ´ÐµÐ½Ñ\83 Ð°Ð´Ñ\80еÑ\81Ñ\83 Ðµ-поÑ\88Ñ\82е",
+       "createacct-emailrequired": "Ð\95-адÑ\80еÑ\81а",
+       "createacct-emailoptional": "Ð\95-адÑ\80еÑ\81а (опÑ\86ионално)",
+       "createacct-email-ph": "УнеÑ\81иÑ\82е Ðµ-адÑ\80еÑ\81Ñ\83",
+       "createacct-another-email-ph": "УнеÑ\81иÑ\82е Ðµ-адÑ\80еÑ\81Ñ\83",
+       "createaccountmail": "Ð\9aоÑ\80иÑ\81Ñ\82и Ð¿Ñ\80ивÑ\80еменÑ\83, Ð½Ð°Ñ\81Ñ\83миÑ\87нÑ\83 Ð»Ð¾Ð·Ð¸Ð½ÐºÑ\83 Ð¸ Ð¿Ð¾Ñ\88аÑ\99и Ñ\98е Ð½Ð° Ð½Ð°Ð²ÐµÐ´ÐµÐ½Ñ\83 Ðµ-адÑ\80еÑ\81Ñ\83",
        "createaccountmail-help": "Може се користити да се некоме отвори налог без сазнања лозинке.",
        "createacct-realname": "Право име (опционално)",
        "createacct-reason": "Разлог",
        "mailmypassword": "Ресетуј лозинку",
        "passwordremindertitle": "{{SITENAME}} — привремена лозинка",
        "passwordremindertext": "Неко са IP адресе $1 је затражио нову лозинку на викију {{SITENAME}} ($4).\nСтворена је привремена лозинка за {{GENDER:$2|корисника|корисницу|корисника}} $2 која гласи $3.\nУколико је ово ваш захтев, сада се пријавите и поставите нову лозинку.\nПривремена лозинка истиче за {{PLURAL:$5|један дан|$5 дана}}.\n\nАко је неко други затражио промену лозинке, или сте се сетили ваше лозинке и не желите да је мењате, занемарите ову поруку.",
-       "noemail": "{{GENDER:$1|Ð\9aоÑ\80иÑ\81ник â\80\9e$1â\80\9d Ð½Ð¸Ñ\98е Ð½Ð°Ð²ÐµÐ¾|Ð\9aоÑ\80иÑ\81ниÑ\86а â\80\9e$1â\80\9d Ð½Ð¸Ñ\98е Ð½Ð°Ð²ÐµÐ»Ð°|Ð\9aоÑ\80иÑ\81ник/Ñ\86а â\80\9e$1â\80\9d Ð½Ð¸Ñ\98е Ð½Ð°Ð²ÐµÐ¾/ла}} Ð°Ð´Ñ\80еÑ\81Ñ\83 Ðµ-поÑ\88Ñ\82е.",
-       "noemailcreate": "Ð\9cоÑ\80аÑ\82е Ð´Ð° Ð½Ð°Ð²ÐµÐ´ÐµÑ\82е Ð²Ð°Ð¶ÐµÑ\9bÑ\83 Ð°Ð´Ñ\80еÑ\81Ñ\83 Ðµ-поÑ\88Ñ\82е.",
-       "passwordsent": "Ð\9dова Ð»Ð¾Ð·Ð¸Ð½ÐºÐ° Ñ\98е Ð¿Ð¾Ñ\81лаÑ\82а Ð½Ð° Ð°Ð´Ñ\80еÑ\81Ñ\83 Ðµ-поÑ\88Ñ\82е {{GENDER:$1|корисника|кориснице|корисника/це}} $1.\nПоново се пријавите након што је примите.",
+       "noemail": "{{GENDER:$1|Ð\9aоÑ\80иÑ\81ник â\80\9e$1â\80\9d Ð½Ð¸Ñ\98е Ð½Ð°Ð²ÐµÐ¾|Ð\9aоÑ\80иÑ\81ниÑ\86а â\80\9e$1â\80\9d Ð½Ð¸Ñ\98е Ð½Ð°Ð²ÐµÐ»Ð°|Ð\9aоÑ\80иÑ\81ник/Ñ\86а â\80\9e$1â\80\9d Ð½Ð¸Ñ\98е Ð½Ð°Ð²ÐµÐ¾/ла}} Ðµ-адÑ\80еÑ\81Ñ\83.",
+       "noemailcreate": "Ð\9cоÑ\80аÑ\82е Ð´Ð° Ð½Ð°Ð²ÐµÐ´ÐµÑ\82е Ð²Ð°Ð¶ÐµÑ\9bÑ\83 Ðµ-адÑ\80еÑ\81Ñ\83.",
+       "passwordsent": "Ð\9dова Ð»Ð¾Ð·Ð¸Ð½ÐºÐ° Ñ\98е Ð¿Ð¾Ñ\81лаÑ\82а Ð½Ð° Ðµ-адÑ\80еÑ\81Ñ\83 {{GENDER:$1|корисника|кориснице|корисника/це}} $1.\nПоново се пријавите након што је примите.",
        "blocked-mailpassword": "Уређивање са ваше IP адресе је блокирано. Ради спречавања злоупотребе, забрањена је и функција враћања лозинке са ње.",
-       "eauthentsent": "Е-порука о потврди је послата на наведену адресу е-поште.\nПре било којих других слања е-порука на налог, мораћете пратити упутства у е-поруци да бисте потврдили да је налог заиста ваш.",
+       "eauthentsent": "Е-порука са потврдом је послата на наведену е-адресу.\nПре било којих других слања е-порука на налог, мораћете пратити упутства у е-поруци да бисте потврдили да је налог заиста ваш.",
        "throttled-mailpassword": "Порука за промену лозинке је послата у {{PLURAL:$1|1=последњих сат времена|последња $1 сата|последњих $1 сати}}.\nДа бисмо спречили злоупотребу, подсетник шаљемо само једном у року од {{PLURAL:$1|1=сат времена|$1 сата|$1 сати}}.",
        "mailerror": "Грешка при слању поруке: $1",
        "acct_creation_throttle_hit": "Посетиоци овог викија који користе вашу Ај-Пи адресу су отворили {{PLURAL:$1|1=један налог|$1 налога}} у претходних $2, што је највећа дозвољена вредност у овом временском периоду.\nКао резултат тога, ти посетиоци тренутно не могу отварати више налога.",
-       "emailauthenticated": "Ð\92аÑ\88а Ð°Ð´Ñ\80еÑ\81а Ðµ-поÑ\88Ñ\82е је потврђена на дан $2 у $3 ч.",
-       "emailnotauthenticated": "Ð\92аÑ\88а Ð°Ð´Ñ\80еÑ\81а Ðµ-поÑ\88Ñ\82е још није потврђена.\nНиједна е-порука неће бити послата ни у једном од следећих случајева.",
-       "noemailprefs": "Ð\9dаведиÑ\82е Ð°Ð´Ñ\80еÑ\81Ñ\83 Ðµ-поÑ\88Ñ\82е у подешавањима за оспособљавање ових функција.",
-       "emailconfirmlink": "Ð\9fоÑ\82вÑ\80диÑ\82е Ð°Ð´Ñ\80еÑ\81Ñ\83 Ðµ-поÑ\88Ñ\82е",
-       "invalidemailaddress": "Ð\9dиÑ\98е Ð¼Ð¾Ð³Ñ\83Ñ\9bе Ð¿Ñ\80иÑ\85ваÑ\82иÑ\82и Ð°Ð´Ñ\80еÑ\81Ñ\83 Ðµ-поÑ\88Ñ\82е јер је у неважећем формату.\nУнесите добро форматирану адресу или оставите празно поље.",
-       "cannotchangeemail": "Ð\90дÑ\80еÑ\81е Ðµ-поÑ\88Ñ\82е налога не могу се променити на овом викију.",
+       "emailauthenticated": "Ð\92аÑ\88а Ðµ-адÑ\80еÑ\81а је потврђена на дан $2 у $3 ч.",
+       "emailnotauthenticated": "Ð\92аÑ\88а Ðµ-адÑ\80еÑ\81а још није потврђена.\nНиједна е-порука неће бити послата ни у једном од следећих случајева.",
+       "noemailprefs": "Ð\9dаведиÑ\82е Ðµ-адÑ\80еÑ\81Ñ\83 у подешавањима за оспособљавање ових функција.",
+       "emailconfirmlink": "Ð\9fоÑ\82вÑ\80диÑ\82е Ðµ-адÑ\80еÑ\81Ñ\83",
+       "invalidemailaddress": "Ð\9dиÑ\98е Ð¼Ð¾Ð³Ñ\83Ñ\9bе Ð¿Ñ\80иÑ\85ваÑ\82иÑ\82и Ðµ-адÑ\80еÑ\81Ñ\83 јер је у неважећем формату.\nУнесите добро форматирану адресу или оставите празно поље.",
+       "cannotchangeemail": "Ð\95-адÑ\80еÑ\81е налога не могу се променити на овом викију.",
        "emaildisabled": "Ова локација не може да шаље е-поруке.",
        "accountcreated": "Налог је отворен",
        "accountcreatedtext": "Кориснички налог [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|talk]]) је отворен.",
        "createaccount-title": "Отварање корисничког налога за {{SITENAME}}",
-       "createaccount-text": "Ð\9dеко Ñ\98е Ð¾Ñ\82воÑ\80ио Ð½Ð°Ð»Ð¾Ð³ Ñ\81а Ð²Ð°Ñ\88ом Ð°Ð´Ñ\80еÑ\81ом Ðµ-поÑ\88Ñ\82е на пројекту {{SITENAME}} ($4) под именом „$2” и са лозинком „$3”.\nОдмах требате да се пријавите и промените своју лозинку.\n\nМожете да занемарите ову поруку, ако је овај налог отворен грешком.",
+       "createaccount-text": "Ð\9dеко Ñ\98е Ð¾Ñ\82воÑ\80ио Ð½Ð°Ð»Ð¾Ð³ Ñ\81а Ð²Ð°Ñ\88ом Ðµ-адÑ\80еÑ\81ом на пројекту {{SITENAME}} ($4) под именом „$2” и са лозинком „$3”.\nОдмах требате да се пријавите и промените своју лозинку.\n\nМожете да занемарите ову поруку, ако је овај налог отворен грешком.",
        "login-throttled": "Превише пута сте покушали да се пријавите.\nСачекајте $1 пре него што покушате поново.",
        "login-abort-generic": "Неуспешна пријава – прекинуто",
        "login-migrated-generic": "Ваш налог је мигриран. Ваше корисничко више не постоји на овом викију.",
        "loginlanguagelabel": "Језик: $1",
        "suspicious-userlogout": "Ваш захтев за одјаву је одбијен јер изгледа да га је послао покварени прегледач или кеширани прокси.",
-       "createacct-another-realname-tip": "Ð\9fÑ\80аво Ð¸Ð¼Ðµ Ñ\98е Ð½ÐµÐ¾Ð±Ð°Ð²ÐµÐ·но.\nАко одаберете да га пружите, биће коришћено за приписивање вашег рада.",
+       "createacct-another-realname-tip": "Ð\9fÑ\80аво Ð¸Ð¼Ðµ Ñ\98е Ð¾Ð¿Ñ\86ионално.\nАко одаберете да га пружите, биће коришћено за приписивање вашег рада.",
        "pt-login": "Пријава",
        "pt-login-button": "Пријави ме",
        "pt-login-continue-button": "Настави пријављивање",
        "pt-createaccount": "Отварање налога",
        "pt-userlogout": "Одјави ме",
        "php-mail-error-unknown": "Непозната грешка у функцији PHP mail().",
-       "user-mail-no-addy": "Ð\9fокÑ\83Ñ\88али Ñ\81Ñ\82е Ð´Ð° Ð¿Ð¾Ñ\88аÑ\99еÑ\82е Ðµ-поÑ\80Ñ\83кÑ\83 Ð±ÐµÐ· Ð°Ð´Ñ\80еÑ\81е Ðµ-поÑ\88Ñ\82е.",
+       "user-mail-no-addy": "Ð\9fокÑ\83Ñ\88али Ñ\81Ñ\82е Ð´Ð° Ð¿Ð¾Ñ\88аÑ\99еÑ\82е Ðµ-поÑ\80Ñ\83кÑ\83 Ð±ÐµÐ· Ðµ-адÑ\80еÑ\81е.",
        "user-mail-no-body": "Покушали сте да пошаљете е-поруку са празним или неразумно кратким садржајем.",
-       "changepassword": "Ð\9fÑ\80омена Ð»Ð¾Ð·Ð¸Ð½ÐºÐµ",
+       "changepassword": "Ð\9fÑ\80омениÑ\82е Ð»Ð¾Ð·Ð¸Ð½ÐºÑ\83",
        "resetpass_announce": "Да бисте завршили пријаву, подесите нову лозинку овде.",
        "resetpass_text": "<!-- Овде унесите текст -->",
        "resetpass_header": "Промена лозинке налога",
        "passwordreset-emaildisabled": "Функција е-поште је онемогућена на овом викију.",
        "passwordreset-username": "Корисничко име:",
        "passwordreset-domain": "Домен:",
-       "passwordreset-email": "Ð\90дÑ\80еÑ\81а Ðµ-поÑ\88Ñ\82е:",
+       "passwordreset-email": "Ð\95-адÑ\80еÑ\81а:",
        "passwordreset-emailtitle": "Детаљи налога на викију {{SITENAME}}",
-       "passwordreset-emailtext-ip": "Ð\9dеко (веÑ\80оваÑ\82но Ð²Ð¸, Ñ\81а IP Ð°Ð´Ñ\80еÑ\81е $1) Ð·Ð°Ñ\82Ñ\80ажио Ñ\98е Ñ\80еÑ\81еÑ\82оваÑ\9aе Ð²Ð°Ñ\88е \nлозинке Ð·Ð° Ð¿Ñ\80оÑ\98екаÑ\82 {{SITENAME}} ($4). Ð¡Ð»ÐµÐ´ÐµÑ\9bи ÐºÐ¾Ñ\80иÑ\81ниÑ\87ки {{PLURAL:$3|налог Ñ\98е Ð¿Ð¾Ð²ÐµÐ·Ð°Ð½|налози Ñ\81Ñ\83 Ð¿Ð¾Ð²ÐµÐ·Ð°Ð½Ð¸}} \nÑ\81а Ð¾Ð²Ð¾Ð¼ Ð°Ð´Ñ\80еÑ\81ом Ðµ-поÑ\88Ñ\82е:\n\n$2\n\n{{PLURAL:$3|Ова привремена лозинка|Ове привремене лозинке}} истећи ће за {{PLURAL:$5|један дан|$5 дана}}.\nОдмах требате да се пријавите и одаберите нову лозинку. \nАко је неко други направио овај захтев или сте се сетили \nоригиналне лозинке, а не желите да је промените, \nможете да занемарите ову поруку и наставите да \nкористите своју стару лозинку.",
+       "passwordreset-emailtext-ip": "Ð\9dеко (веÑ\80оваÑ\82но Ð²Ð¸, Ñ\81а IP Ð°Ð´Ñ\80еÑ\81е $1) Ð·Ð°Ñ\82Ñ\80ажио Ñ\98е Ñ\80еÑ\81еÑ\82оваÑ\9aе Ð²Ð°Ñ\88е \nлозинке Ð·Ð° Ð¿Ñ\80оÑ\98екаÑ\82 {{SITENAME}} ($4). Ð¡Ð»ÐµÐ´ÐµÑ\9bи ÐºÐ¾Ñ\80иÑ\81ниÑ\87ки {{PLURAL:$3|налог Ñ\98е Ð¿Ð¾Ð²ÐµÐ·Ð°Ð½|налози Ñ\81Ñ\83 Ð¿Ð¾Ð²ÐµÐ·Ð°Ð½Ð¸}} \nÑ\81а Ð¾Ð²Ð¾Ð¼ Ðµ-адÑ\80еÑ\81ом:\n\n$2\n\n{{PLURAL:$3|Ова привремена лозинка|Ове привремене лозинке}} истећи ће за {{PLURAL:$5|један дан|$5 дана}}.\nОдмах требате да се пријавите и одаберите нову лозинку. \nАко је неко други направио овај захтев или сте се сетили \nоригиналне лозинке, а не желите да је промените, \nможете да занемарите ову поруку и наставите да \nкористите своју стару лозинку.",
        "passwordreset-emailtext-user": "Корисник/ца $1 затражио/ла је ресетовање ваше лозинке на пројекту {{SITENAME}} ($4).\nСледећи кориснички {{PLURAL:$3|налог је повезан|налози су повезани}} са овом адресом е-поште:\n\n$2\n\n{{PLURAL:$3|Привремена лозинка истиче|Привремене лозинке истичу}} за {{PLURAL:$5|један дан|$5 дана}}.\nОдмах требате да се пријавите и одаберите нову лозинку. \nАко је неко други направио овај захтев или сте се сетили \nоригиналне лозинке, а не желите да је промените, \nможете да занемарите ову поруку и наставите да \nкористите своју стару лозинку.",
        "passwordreset-emailelement": "Корисничко име: \n$1\n\nПривремена лозинка: \n$2",
-       "passwordreset-emailsentemail": "Ð\90ко Ñ\98е Ð¾Ð²Ð° Ð°Ð´Ñ\80еÑ\81а Ðµ-поÑ\88Ñ\82е повезана са вашим налогом, онда ће е-порука о ресетовању лозинке бити послата.",
-       "passwordreset-emailsentusername": "Ð\90ко Ð¿Ð¾Ñ\81Ñ\82оÑ\98и Ð°Ð´Ñ\80еÑ\81а Ðµ-поÑ\88Ñ\82е повезана са овим корисничким именом, онда ће е-порука о ресетовању лозинке бити послата.",
+       "passwordreset-emailsentemail": "Ð\90ко Ñ\98е Ð¾Ð²Ð° Ðµ-адÑ\80еÑ\81а повезана са вашим налогом, онда ће е-порука о ресетовању лозинке бити послата.",
+       "passwordreset-emailsentusername": "Ð\90ко Ð¿Ð¾Ñ\81Ñ\82оÑ\98и Ðµ-адÑ\80еÑ\81а повезана са овим корисничким именом, онда ће е-порука о ресетовању лозинке бити послата.",
        "passwordreset-nocaller": "Позивалац се мора навести",
        "passwordreset-nosuchcaller": "Позивалац не постоји: $1",
        "passwordreset-ignored": "Ресетовање лозинке није успело. Можда послужилац није конфигурисан?",
-       "passwordreset-invalidemail": "Ð\9dеважеÑ\9bа Ð°Ð´Ñ\80еÑ\81а Ðµ-поÑ\88Ñ\82е",
-       "passwordreset-nodata": "Ð\9aоÑ\80иÑ\81ниÑ\87ко Ð¸Ð¼Ðµ Ð¸ Ð°Ð´Ñ\80еÑ\81а Ðµ-поÑ\88Ñ\82е нису наведени",
-       "changeemail": "Ð\9fÑ\80омена Ð¸Ð»Ð¸ Ñ\83клаÑ\9aаÑ\9aе Ð°Ð´Ñ\80еÑ\81е Ðµ-поÑ\88Ñ\82е",
-       "changeemail-header": "Ð\94овÑ\80Ñ\88иÑ\82е Ð¾Ð²Ð°Ñ\98 Ð¾Ð±Ñ\80азаÑ\86 Ð´Ð° Ð±Ð¸ Ñ\81Ñ\82е Ð¿Ñ\80оменили Ð°Ð´Ñ\80еÑ\81Ñ\83 Ðµ-поÑ\88Ñ\82е. Ð\90ко Ð±Ð¸Ñ\81Ñ\82е Ð¶ÐµÐ»ÐµÐ»Ð¸ Ð´Ð° Ñ\83клониÑ\82е Ð¿Ð¾Ð²ÐµÐ·Ð°Ð½Ð¾Ñ\81Ñ\82 Ð±Ð¸Ð»Ð¾ ÐºÐ¾Ñ\98е Ð°Ð´Ñ\80еÑ\81е Ðµ-поÑ\88Ñ\82е Ñ\81а Ð²Ð°Ñ\88ег Ð½Ð°Ð»Ð¾Ð³Ð°, Ð¾Ñ\81Ñ\82авиÑ\82е Ð¿Ñ\80азно Ð¿Ð¾Ñ\99е Ð·Ð° Ð½Ð¾Ð²Ñ\83 Ð°Ð´Ñ\80еÑ\81Ñ\83 Ðµ-поÑ\88Ñ\82е када шаљете образац.",
+       "passwordreset-invalidemail": "Ð\9dеважеÑ\9bа Ðµ-адÑ\80еÑ\81а",
+       "passwordreset-nodata": "Ð\9aоÑ\80иÑ\81ниÑ\87ко Ð¸Ð¼Ðµ Ð¸ Ðµ-адÑ\80еÑ\81а нису наведени",
+       "changeemail": "Ð\9fÑ\80омена Ð¸Ð»Ð¸ Ñ\83клаÑ\9aаÑ\9aе Ðµ-адÑ\80еÑ\81е",
+       "changeemail-header": "Ð\94овÑ\80Ñ\88иÑ\82е Ð¾Ð²Ð°Ñ\98 Ð¾Ð±Ñ\80азаÑ\86 Ð´Ð° Ð±Ð¸ Ñ\81Ñ\82е Ð¿Ñ\80оменили Ðµ-адÑ\80еÑ\81Ñ\83. Ð\90ко Ð±Ð¸Ñ\81Ñ\82е Ð¶ÐµÐ»ÐµÐ»Ð¸ Ð´Ð° Ñ\83клониÑ\82е Ð¿Ð¾Ð²ÐµÐ·Ð°Ð½Ð¾Ñ\81Ñ\82 Ð±Ð¸Ð»Ð¾ ÐºÐ¾Ñ\98е Ðµ-адÑ\80еÑ\81е Ñ\81а Ð²Ð°Ñ\88ег Ð½Ð°Ð»Ð¾Ð³Ð°, Ð¾Ñ\81Ñ\82авиÑ\82е Ð¿Ñ\80азно Ð¿Ð¾Ñ\99е Ð·Ð° Ð½Ð¾Ð²Ñ\83 Ðµ-адÑ\80еÑ\81Ñ\83 када шаљете образац.",
        "changeemail-no-info": "Морате бити пријављени да бисте приступили овој страници.",
-       "changeemail-oldemail": "ТÑ\80енÑ\83Ñ\82на Ð°Ð´Ñ\80еÑ\81а Ðµ-поÑ\88Ñ\82е:",
-       "changeemail-newemail": "Ð\9dова Ð°Ð´Ñ\80еÑ\81а Ðµ-поÑ\88Ñ\82е:",
-       "changeemail-newemail-help": "Ð\9eво Ð¿Ð¾Ñ\99е Ñ\82Ñ\80еба Ð´Ð° Ð¾Ñ\81Ñ\82авиÑ\82е Ð¿Ñ\80азно Ð°ÐºÐ¾ Ð¶ÐµÐ»Ð¸Ñ\82е Ð´Ð° Ñ\83клониÑ\82е Ð°Ð´Ñ\80еÑ\81Ñ\83 Ðµ-поÑ\88Ñ\82е. Ð\9dеÑ\9bеÑ\82е Ð±Ð¸Ñ\82и Ñ\83 Ð¼Ð¾Ð³Ñ\83Ñ\9bноÑ\81Ñ\82и Ð´Ð° Ñ\80еÑ\81еÑ\82Ñ\83Ñ\98еÑ\82е Ð·Ð°Ð±Ð¾Ñ\80авÑ\99енÑ\83 Ð»Ð¾Ð·Ð¸Ð½ÐºÑ\83 Ð¸ Ð½ÐµÑ\9bеÑ\82е Ð¿Ñ\80имаÑ\82и Ðµ-поÑ\80Ñ\83ке Ñ\81а Ð¾Ð²Ð¾Ð³ Ð²Ð¸ÐºÐ¸Ñ\98а Ð°ÐºÐ¾ Ñ\98е Ð°Ð´Ñ\80еÑ\81а Ðµ-поÑ\88Ñ\82е уклоњена.",
+       "changeemail-oldemail": "ТÑ\80енÑ\83Ñ\82на Ðµ-адÑ\80еÑ\81а:",
+       "changeemail-newemail": "Ð\9dова Ðµ-адÑ\80еÑ\81а:",
+       "changeemail-newemail-help": "Ð\9eво Ð¿Ð¾Ñ\99е Ñ\82Ñ\80еба Ð´Ð° Ð¾Ñ\81Ñ\82авиÑ\82е Ð¿Ñ\80азно Ð°ÐºÐ¾ Ð¶ÐµÐ»Ð¸Ñ\82е Ð´Ð° Ñ\83клониÑ\82е Ðµ-адÑ\80еÑ\81Ñ\83. Ð\9dеÑ\9bеÑ\82е Ð±Ð¸Ñ\82и Ñ\83 Ð¼Ð¾Ð³Ñ\83Ñ\9bноÑ\81Ñ\82и Ð´Ð° Ñ\80еÑ\81еÑ\82Ñ\83Ñ\98еÑ\82е Ð·Ð°Ð±Ð¾Ñ\80авÑ\99енÑ\83 Ð»Ð¾Ð·Ð¸Ð½ÐºÑ\83 Ð¸ Ð½ÐµÑ\9bеÑ\82е Ð¿Ñ\80имаÑ\82и Ðµ-поÑ\80Ñ\83ке Ñ\81а Ð¾Ð²Ð¾Ð³ Ð²Ð¸ÐºÐ¸Ñ\98а Ð°ÐºÐ¾ Ñ\98е Ðµ-адÑ\80еÑ\81а уклоњена.",
        "changeemail-none": "(ништа)",
        "changeemail-password": "Ваша лозинка за пројекат {{SITENAME}}:",
        "changeemail-submit": "Промени е-пошту",
        "changeemail-throttled": "Превише пута сте покушали да се пријавите.\nМолимо вас да сачекате $1 пре него што покушате поново.",
-       "changeemail-nochange": "УнеÑ\81иÑ\82е Ð´Ñ\80Ñ\83гÑ\83 Ð°Ð´Ñ\80еÑ\81Ñ\83 Ðµ-поÑ\88Ñ\82е.",
+       "changeemail-nochange": "УнеÑ\81иÑ\82е Ð´Ñ\80Ñ\83гÑ\83 Ðµ-адÑ\80еÑ\81Ñ\83.",
        "resettokens": "Ресетовање токена",
        "resettokens-text": "Овде можете да ресетујете токене који омогућавају приступ одређеним приватним подацима повезаним са вашим налогом.\n\nТребали бисте то урадити ако их случајно поделите са неким или ако је ваш налог угрожен.",
        "resettokens-no-tokens": "Нема жетона за ресетовање.",
        "blockedtitle": "Корисник је блокиран",
        "blocked-email-user": "<strong>Вашем корисничком имену је блокирано слање е-порука. Још увек можете да уређујете друге странице на овом викију.</strong> Можете да видите потпуне детаље блокаде на [[Special:MyContributions|доприносима налога]].\n\nБлокаду је извршио/ла $1.\n\nНаведен је следећи разлог: <em>$2</em>.\n\n* Почетак блокаде: $8\n* Истек блокаде: $6\n* Намењена кориснику/ци или IP адреси: $7\n* ID блокаде #$5",
        "blockedtext-partial": "<strong>Вашем корисничком имену или IP адреси је блокирано прављење промена на овој страници. Још увек можете да уређујете друге странице на овом викију.</strong> Можете да видите потпуне детаље блокаде на [[Special:MyContributions|доприносима налога]].\n\nБлокаду је извршио/ла $1.\n\nНаведен је следећи разлог: <em>$2</em>.\n\n* Почетак блокаде: $8\n* Истек блокаде: $6\n* Намењена кориснику/ци или IP адреси: $7\n* ID блокаде #$5",
-       "blockedtext": "<strong>Ваше корисничко име или IP адреса је блокирана.</strong>\n\nБлокирање је {{GENDER:$4|извршио|извршила}} $1.\nРазлог је <em>$2</em>.\n\n* Почетак блокирања: $8\n* Истек блокирања: $6\n* Блокирани: $7\n\nМожете да се обратите {{GENDER:$4|кориснику|корисници}} $1 или [[{{MediaWiki:Grouppage-sysop}}|администратору]] ради дискусије о блокирању.\nНе можете да користите могућност „{{int:emailuser}}” осим ако сте унели валидну имејл адресу у својим [[Special:Preferences|подешавањима]] налога и нисте блокирани од коришћења исте.\nВаша тренутна IP адреса је $3, а ID блокирања #$5.\nНаведите све информације одозго при стварању било каквих упита.",
-       "autoblockedtext": "Ваша IP адреса је аутоматски блокирана јер ју је користио други корисник, кога је {{GENDER:$4|блокирао|блокирала|блокирао/ла}} $1.\nРазлог:\n\n:<em>$2</em>\n\n* Почетак блокаде: $8\n* Крај блокаде: $6\n* Име корисника: $7\n\nМожете да контактирате {{GENDER:$4|корисника|корисницу|корисника/цу}} $1 или другог [[{{MediaWiki:Grouppage-sysop}}|администратора]] да бисте расправљали о блокади.\n\nЗапамтите да не можете да користите функцију „{{int:emailuser}}“ осим ако сте навели важећу адресу е-поште у [[Special:Preferences|подешавањима]].\n\nВаша тренутна IP адреса је $3, а ID блокаде $5.\nУкључите све горње детаље при прављењу било каквих упита.",
+       "blockedtext": "<strong>Ваше корисничко име или IP адреса је блокирана.</strong>\n\nБлокирање је {{GENDER:$4|извршио|извршила}} $1.\nРазлог је <em>$2</em>.\n\n* Почетак блокирања: $8\n* Истек блокирања: $6\n* Блокирани: $7\n\nМожете да се обратите {{GENDER:$4|кориснику|корисници}} $1 или [[{{MediaWiki:Grouppage-sysop}}|администратору]] ради дискусије о блокирању.\nНе можете да користите функцију „{{int:emailuser}}” осим ако сте унели важећу е-адресу у својим [[Special:Preferences|подешавањима]] налога и нисте блокирани од коришћења исте.\nВаша тренутна IP адреса је $3, а ID блокирања #$5.\nНаведите све информације одозго при стварању било каквих упита.",
+       "autoblockedtext": "Ваша IP адреса је аутоматски блокирана јер ју је користио други корисник, кога је {{GENDER:$4|блокирао|блокирала|блокирао/ла}} $1.\nРазлог:\n\n:<em>$2</em>\n\n* Почетак блокаде: $8\n* Крај блокаде: $6\n* Име корисника: $7\n\nМожете да контактирате {{GENDER:$4|корисника|корисницу|корисника/цу}} $1 или другог [[{{MediaWiki:Grouppage-sysop}}|администратора]] да бисте расправљали о блокади.\n\nЗапамтите да не можете да користите функцију „{{int:emailuser}}“ осим ако сте навели важећу е-адресу у [[Special:Preferences|подешавањима]].\n\nВаша тренутна IP адреса је $3, а ID блокаде $5.\nУкључите све горње детаље при прављењу било каквих упита.",
+       "systemblockedtext": "Медијавики је аутоматски блокирао ваше корисничко име или IP адресу.\nНаведен је следећи разлог:\n\n:<em>$2</em>\n\n* Почетак блокирања: $8\n* Истек блокирања: $6\n* Блокирање је намењено за: $7\n\nВаша тренурна IP адреса $3.\nУкључите све горенаведене детаље при прављењу било којих упита.",
        "blockednoreason": "разлог није наведен",
        "whitelistedittext": "$1 да бисте уређивали странице.",
-       "confirmedittext": "Ð\9cоÑ\80аÑ\82е Ð´Ð° Ð¿Ð¾Ñ\82вÑ\80диÑ\82е Ð°Ð´Ñ\80еÑ\81Ñ\83 Ðµ-поÑ\88Ñ\82е пре уређивања страница.\nПоставите и проверите ваљаност адресе преко [[Special:Preferences|подешавања]].",
+       "confirmedittext": "Ð\9cоÑ\80аÑ\82е Ð´Ð° Ð¿Ð¾Ñ\82вÑ\80диÑ\82е Ðµ-адÑ\80еÑ\81Ñ\83 пре уређивања страница.\nПоставите и проверите ваљаност адресе преко [[Special:Preferences|подешавања]].",
        "nosuchsectiontitle": "Није могуће пронаћи одељак",
        "nosuchsectiontext": "Покушали сте да уредите одељак који не постоји.\nМожда је премештен или избрисан док сте прегледали страницу.",
        "loginreqtitle": "Потребна је пријава",
        "updated": "(ажурирано)",
        "note": "<strong>Напомена:</strong>",
        "previewnote": "<strong>Не заборавите да је ово само претпреглед.</strong>\nВаше промене још нису сачуване!",
-       "continue-editing": "Ð\9fÑ\80еÑ\92и Ð½Ð° Ð¾Ð±Ð°Ñ\81Ñ\82 Ñ\83Ñ\80еÑ\92иваÑ\9aа",
+       "continue-editing": "Ð\9fÑ\80еÑ\92и Ð½Ð° Ð¾Ð±Ð»Ð°Ñ\81Ñ\82 Ð·Ð° Ñ\83Ñ\80еÑ\92иваÑ\9aе",
        "previewconflict": "Овај преглед осликава како ће изгледати текст у текстуалном оквиру.",
        "session_fail_preview": "Извињавамо се! Нисмо могли да обрадимо вашу измену због губитка података сесије.\n\nМожда сте одјављени. <strong>Проверите да ли сте пријављени и покушајте поново</strong>.\nАко и даље не ради, покушајте да се [[Special:UserLogout|одјавите]] и поново пријавите, те проверите да ли су на вашем претраживачу дозвољени колачићи са овог сајта.",
        "session_fail_preview_html": "Нисмо могли да обрадимо вашу измену због губитка података сесије.\n\n<em>Будући да је на овом викију омогућен унос HTML ознака, преглед је сакривен као мера предострожности против напада преко јаваскрипта.</em>\n\n<strong>Ако сте покушали да направите праву измену, покушајте поново.<strong>\nАко и даље не ради, покушајте да се [[Special:UserLogout|одјавите]] и поново пријавите и проверите да ли ваш прегледач дозвољава колачиће са овог сајта.",
        "copyrightwarning": "Имајте на уму да се сви доприноси на овом викију сматрају као објављени под лиценцом $2 (више на $1).\nАко не желите да се ваши текстови мењају и размењују без ограничења, онда их не шаљите овде.<br />\nИсто тако обећавате да сте Ви аутор текста, или да сте га умножили са извора који је у јавном власништву.\n<strong>Не шаљите радове заштићене ауторским правима без дозволе!</strong>",
        "copyrightwarning2": "Имајте на уму да се сви доприноси на овом викију могу мењати, враћати или брисати од других корисника.\nАко не желите да се ваши текстови слободно мењају и расподељују, не шаљите их овде.<br />\nИсто тако обећавате да сте ви аутор текста, или да сте га умножили с извора који је у јавном власништву (више на $1).\n<strong>Не шаљите радове заштићене ауторским правима без дозволе!</strong>",
        "editpage-cannot-use-custom-model": "Модел садржаја ове странице се не може променити.",
-       "longpageerror": "<strong>Грешка: текст који сте унели је величине {{PLURAL:$1|један килобајт|$1 килобајта}}, што је веће од {{PLURAL:$2|дозвољеног једног килобајта|дозвољена $2 килобајта|дозвољених $2 килобајта}}.</strong>\nСтраница не може бити сачувана.",
+       "longpageerror": "<strong>Грешка: текст који сте проследили је величине {{PLURAL:$1|један килобајт|$1 килобајта}}, што је веће од {{PLURAL:$2|дозвољеног једног килобајта|дозвољена $2 килобајта|дозвољених $2 килобајта}}.</strong>\nСтраница не може бити сачувана.",
        "readonlywarning": "<strong>Упозорење: база података је закључана ради одржавања, тако да тренутно нећете моћи да сачувате измене.</strong>\nМожда бисте желели сачувати текст за касније у некој текстуалној датотеци.\n\nСистемски администратор је навео следеће објашњење: $1",
        "protectedpagewarning": "<strong>Упозорење: Ова страница је заштићена, тако да само корисници са администраторским овлашћењима могу да је уређују.</strong>\nНајновији унос у дневнику је наведен испод као референца:",
        "semiprotectedpagewarning": "<strong>Напомена:</strong> Ова страница је заштићена, тако да само аутоматски потврђени корисници могу да је уређују.\nНајновији унос у дневнику је наведен испод као референца:",
        "page_first": "прва",
        "page_last": "последња",
        "histlegend": "Избор разлика: означите кутијице измена за упоређивање и притисните enter или дугме на дну.<br />\nОбјашњење: <strong>({{int:cur}})</strong> = разлика са најновијом изменом, <strong>({{int:last}})</strong> = разлика са претходном изменом, <strong>{{int:minoreditletter}}</strong> = мања измена.",
-       "history-fieldset-title": "Ð\9fÑ\80еÑ\82Ñ\80ага измена",
+       "history-fieldset-title": "ФилÑ\82Ñ\80иÑ\80аÑ\9aе измена",
        "history-show-deleted": "Само избрисане измене",
        "histfirst": "најстарије",
        "histlast": "најновије",
        "revdelete-edit-reasonlist": "Уреди разлоге за брисање",
        "revdelete-offender": "Аутор измене:",
        "suppressionlog": "Дневник сакривања",
-       "suppressionlogtext": "Испод се налази списак брисања и блокирања који укључује садржај сакривен од администратора. Погледајте [[Special:BlockList|списак блокирања]] за списак тренутних операција забрана и блокирања.",
+       "suppressionlogtext": "Испод се налази списак брисања и блокирања који укључује садржај сакривен од администратора. Погледајте [[Special:BlockList|списак блокирања]] за списак текућих забрана и блокирања.",
        "mergehistory": "Обједињавање историја странице",
        "mergehistory-header": "Ова страница вам допушта да обједините историју измена неке изворне странице у новију страницу.\nУверите се да ће ова промена оставити непромењен садржај историје странице.",
-       "mergehistory-box": "Обједини измене двеју страница:",
+       "mergehistory-box": "Обједињавање измена двеју страница:",
        "mergehistory-from": "Изворна страница:",
        "mergehistory-into": "Одредишна страница:",
        "mergehistory-list": "Обједињива историја измена",
        "mergehistory-revisionrow": "$1 ($2) $3 . . $4 $5 $6",
        "mergelog": "Дневник обједињавања",
        "revertmerge": "растави",
-       "mergelogpagetext": "Ð\98Ñ\81под Ñ\98е списак најновијих обједињавања историја једне странице у другу.",
+       "mergelogpagetext": "Ð\98Ñ\81под Ñ\81е Ð½Ð°Ð»Ð°Ð·Ð¸ списак најновијих обједињавања историја једне странице у другу.",
        "history-title": "Историја измена странице „$1”",
        "difference-title": "Разлика између измена на страници „$1”",
        "difference-title-multipage": "Разлика између страница „$1“ и „$2“",
        "diff-paragraph-moved-toold": "Пасус је премештен. Кликните да пређете на стару локацију.",
        "difference-missing-revision": "{{PLURAL:$2|Једна измена|$2 измене}} ове разлике ($1) не {{PLURAL:$2|постоји|постоје}}.\n\nОво се обично дешава када пратите застарелу везу до странице која је избрисана.\nДетаље можете да пронађете у [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} дневнику брисања].",
        "searchresults": "Резултати претраге",
+       "search-filter-title-prefix": "Само претражује на страницама чији наслов почиње са „$1”",
        "search-filter-title-prefix-reset": "Претражи све странице",
        "searchresults-title": "Резултати претраге за „$1“",
        "titlematches": "Наслов странице одговара",
        "prefs-rc": "Скорашње измене",
        "prefs-watchlist": "Списак надгледања",
        "prefs-editwatchlist": "Уређивање списка надгледања",
-       "prefs-editwatchlist-label": "Уреди уносе на списку надгледања:",
-       "prefs-editwatchlist-edit": "Приказ и уклањање наслова са списка надгледања",
-       "prefs-editwatchlist-raw": "Уређивање необрађеног списка надгледања",
-       "prefs-editwatchlist-clear": "ЧиÑ\88Ñ\9bеÑ\9aе Ñ\81пиÑ\81ка надгледања",
+       "prefs-editwatchlist-label": "Уредите уносе на списку надгледања:",
+       "prefs-editwatchlist-edit": "Погледајте и уклоните наслове са списка надгледања",
+       "prefs-editwatchlist-raw": "Уредите необрађен списак надгледања",
+       "prefs-editwatchlist-clear": "Ð\9eÑ\87иÑ\81Ñ\82иÑ\82е Ñ\81пиÑ\81ак надгледања",
        "prefs-watchlist-days": "Број дана у списку надгледања:",
        "prefs-watchlist-days-max": "Највише $1 {{PLURAL:$1|дан|дана|дана}}",
        "prefs-watchlist-edits": "Највећи број промена приказаних на списку надгледања:",
        "prefs-watchlist-edits-max": "Највећи број: 1000",
        "prefs-watchlist-token": "Токен списка надгледања:",
-       "prefs-watchlist-managetokens": "УпÑ\80авÑ\99аÑ\9aе токенима",
+       "prefs-watchlist-managetokens": "УпÑ\80авÑ\99аÑ\98 токенима",
        "prefs-misc": "Разно",
        "prefs-resetpass": "Промена лозинке",
-       "prefs-changeemail": "Ð\9fÑ\80омена Ð¸Ð»Ð¸ Ñ\83клаÑ\9aаÑ\9aе Ð°Ð´Ñ\80еÑ\81е Ðµ-поÑ\88Ñ\82е",
-       "prefs-setemail": "Ð\9fоÑ\81Ñ\82авÑ\99аÑ\9aе Ð°Ð´Ñ\80еÑ\81е Ðµ-поÑ\88Ñ\82е",
+       "prefs-changeemail": "Ð\9fÑ\80омениÑ\82е Ð¸Ð»Ð¸ Ñ\83клониÑ\82е Ðµ-адÑ\80еÑ\81Ñ\83",
+       "prefs-setemail": "Ð\9fоÑ\81Ñ\82авÑ\99аÑ\9aе Ðµ-адÑ\80еÑ\81е",
        "prefs-email": "Опције е-поште",
        "prefs-rendering": "Изглед",
        "saveprefs": "Сачувај",
        "searchresultshead": "Претрага",
        "stub-threshold": "Праг за форматирање веза као клице ($1):",
        "stub-threshold-sample-link": "пример",
-       "stub-threshold-disabled": "Ð\9eнемогућено",
+       "stub-threshold-disabled": "онемогућено",
        "recentchangesdays": "Број дана у скорашњим изменама:",
        "recentchangesdays-max": "Највише $1 {{PLURAL:$1|дан|дана}}",
        "recentchangescount": "Подразумевани број измена за приказ у скорашњим изменама, историјама страница и дневницима:",
        "savedrights": "Корисничке групе {{GENDER:$1|корисника|кориснице}} $1 су сачуване.",
        "timezonelegend": "Временска зона:",
        "localtime": "Локално време:",
-       "timezoneuseserverdefault": "Ð\9aористи подразумеване вредности викија ($1)",
-       "timezoneuseoffset": "Ð\94руго (наведите одступање испод)",
+       "timezoneuseserverdefault": "користи подразумеване вредности викија ($1)",
+       "timezoneuseoffset": "друго (наведите одступање испод)",
        "timezone-useoffset-placeholder": "Примери вредности: „-07:00” или „01:00”",
        "servertime": "Време на серверу:",
-       "guesstimezone": "Ð\9fопуни из прегледача",
+       "guesstimezone": "попуни из прегледача",
        "timezoneregion-africa": "Африка",
        "timezoneregion-america": "Америка",
        "timezoneregion-antarctica": "Антарктик",
        "timezoneregion-europe": "Европа",
        "timezoneregion-indian": "Индијски океан",
        "timezoneregion-pacific": "Тихи океан",
-       "allowemail": "Дозволи другим корисницима да ми шаљу е-поруке",
-       "email-allow-new-users-label": "Дозволи примање е-порука од новајлија",
-       "email-blacklist-label": "Забрани овим корисницима да ми шаљу е-поруке:",
+       "allowemail": "Дозвољавај другим корисницима да ми шаљу е-поруке",
+       "email-allow-new-users-label": "Дозвољавај е-поруке од потпуно нових корисника",
+       "email-blacklist-label": "Забрањуј следећим корисницима да ми шаљу е-поруке:",
        "prefs-searchoptions": "Претрага",
        "prefs-namespaces": "Именски простори",
        "default": "подразумевано",
        "prefs-files": "Датотеке",
-       "prefs-custom-css": "прилагођени Це-Ес-Ес",
+       "prefs-custom-css": "прилагођени CSS",
        "prefs-custom-json": "Прилагођени ЈСОН",
-       "prefs-custom-js": "прилагођени јаваскрипт",
-       "prefs-common-config": "Дељени Це-Ес-Ес/ЈСОН/јаваскрипт за све теме:",
+       "prefs-custom-js": "прилагођени JavaScript",
+       "prefs-common-config": "Дељени CSS/JSON/JavaScript за све теме:",
        "prefs-reset-intro": "Можете користити ову страницу да поново поставите своја подешавања на подразумеване вредности сајта.\nОво се не може опозвати.",
        "prefs-emailconfirm-label": "Потврда е-поште:",
        "youremail": "Е-пошта:",
        "badsig": "Неважећи необрађени потпис.\nПроверите HTML тагове.",
        "badsiglength": "Ваш потпис је предугачак.\nНе сме бити дужи од $1 {{PLURAL:$1|знака|знака|знакова}}.",
        "yourgender": "Како желите да се представите?",
-       "gender-unknown": "Кад вас спомиње, софтвер ће користити родно неутралне речи кад год је то могуће",
+       "gender-unknown": "Кад вас помиње, софтвер ће користити родно неутралне речи кад год је то могуће",
        "gender-male": "Он уређује вики странице",
        "gender-female": "Она уређује вики странице",
-       "prefs-help-gender": "Ð\9fоÑ\81Ñ\82авÑ\99аÑ\9aе Ð¾Ð²Ð¾Ð³ Ð¿Ð¾Ð´ÐµÑ\88аваÑ\9aа Ñ\98е Ð½ÐµÐ¾Ð±Ð°Ð²ÐµÐ·Ð½Ð¾.\nСоÑ\84Ñ\82веÑ\80 ÐºÐ¾Ñ\80иÑ\81Ñ\82и Ð´Ð°Ñ\82Ñ\83 Ð²Ñ\80едноÑ\81Ñ\82 Ð´Ð° Ð±Ð¸ Ð²Ð°Ð¼ Ñ\81е Ð¾Ð±Ñ\80аÑ\82ио Ð¸ Ñ\81поменуо вас другима користећи одговарајући граматички род.\nОва информација ће бити јавна.",
+       "prefs-help-gender": "Ð\9fоÑ\81Ñ\82авÑ\99аÑ\9aе Ð¾Ð²Ð¾Ð³ Ð¿Ð¾Ð´ÐµÑ\88аваÑ\9aа Ñ\98е Ð¾Ð¿Ñ\86ионално.\nСоÑ\84Ñ\82веÑ\80 ÐºÐ¾Ñ\80иÑ\81Ñ\82и Ð´Ð°Ñ\82Ñ\83 Ð²Ñ\80едноÑ\81Ñ\82 Ð´Ð° Ð±Ð¸ Ð²Ð°Ð¼ Ñ\81е Ð¾Ð±Ñ\80аÑ\82ио Ð¸ поменуо вас другима користећи одговарајући граматички род.\nОва информација ће бити јавна.",
        "email": "Е-пошта",
-       "prefs-help-realname": "Ð\9fÑ\80аво Ð¸Ð¼Ðµ Ñ\98е Ð½ÐµÐ¾Ð±Ð°Ð²ÐµÐ·но.\nАко је пружено, биће коришћено за приписивање вашег рада.",
-       "prefs-help-email": "Ð\90дÑ\80еÑ\81а Ðµ-поÑ\88Ñ\82е Ñ\98е Ð½ÐµÐ¾Ð±Ð°Ð²ÐµÐ·на, али је потребна за ресетовање лозинке, ако је заборавите.",
-       "prefs-help-email-others": "ТакоÑ\92е Ð¼Ð¾Ð¶ÐµÑ\82е Ð¾Ð°Ð±Ñ\80аÑ\82и Ð´Ð° Ð´Ð¾Ð¿Ñ\83Ñ\81Ñ\82иÑ\82е Ð´Ñ\80Ñ\83гима Ð´Ð° Ð²Ð°Ñ\81 ÐºÐ¾Ð½Ñ\82акÑ\82иÑ\80аÑ\98Ñ\83 Ð¿Ñ\80еко Ðµ-поÑ\88Ñ\82е Ð¿Ñ\83Ñ\82ем Ð²ÐµÐ·Ðµ Ð½Ð° Ð²Ð°Ñ\88оÑ\98 ÐºÐ¾Ñ\80иÑ\81ниÑ\87коÑ\98 Ñ\81Ñ\82Ñ\80аниÑ\86и Ð¸Ð»Ð¸ Ñ\81Ñ\82Ñ\80аниÑ\86и Ð·Ð° Ñ\80азговоÑ\80.\nÐ\92аÑ\88а Ð°Ð´Ñ\80еÑ\81а Ðµ-поÑ\88Ñ\82е неће бити приказана другим корисницима који вас контактирају.",
-       "prefs-help-email-required": "Ð\9fоÑ\82Ñ\80ебна Ñ\98е Ð°Ð´Ñ\80еÑ\81а Ðµ-поÑ\88Ñ\82е.",
+       "prefs-help-realname": "Ð\9fÑ\80аво Ð¸Ð¼Ðµ Ñ\98е Ð¾Ð¿Ñ\86ионално.\nАко је пружено, биће коришћено за приписивање вашег рада.",
+       "prefs-help-email": "Ð\95-адÑ\80еÑ\81а Ñ\98е Ð¾Ð¿Ñ\86ионална, али је потребна за ресетовање лозинке, ако је заборавите.",
+       "prefs-help-email-others": "ТакоÑ\92е Ð¼Ð¾Ð¶ÐµÑ\82е Ð¾Ð´Ð°Ð±Ñ\80аÑ\82и Ð´Ð° Ð´Ð¾Ð¿Ñ\83Ñ\81Ñ\82иÑ\82е Ð´Ñ\80Ñ\83гима Ð´Ð° Ð²Ð°Ñ\81 ÐºÐ¾Ð½Ñ\82акÑ\82иÑ\80аÑ\98Ñ\83 Ð¿Ñ\83Ñ\82ем Ðµ-поÑ\88Ñ\82е Ð¿Ñ\80еко Ð²ÐµÐ·Ðµ Ð½Ð° Ð²Ð°Ñ\88оÑ\98 ÐºÐ¾Ñ\80иÑ\81ниÑ\87коÑ\98 Ñ\81Ñ\82Ñ\80аниÑ\86и Ð¸Ð»Ð¸ Ñ\81Ñ\82Ñ\80аниÑ\86и Ð·Ð° Ñ\80азговоÑ\80.\nÐ\92аÑ\88а Ðµ-адÑ\80еÑ\81а неће бити приказана другим корисницима који вас контактирају.",
+       "prefs-help-email-required": "Ð\9fоÑ\82Ñ\80ебна Ñ\98е Ðµ-адÑ\80еÑ\81а.",
        "prefs-info": "Основне информације",
        "prefs-i18n": "Интернационализација",
        "prefs-signature": "Потпис",
        "right-reupload-own": "замењивање сопствених датотека",
        "right-reupload-shared": "локално замењивање датотека на дељеном спремишту медија",
        "right-upload_by_url": "отпремање датотека са УРЛ-а",
-       "right-purge": "чишћење кеш меморије странице без потврде",
+       "right-purge": "чишћење кеш меморије странице",
        "right-autoconfirmed": "без ограничавања ставки за IP адресе",
        "right-bot": "сматрање измена као аутоматски процес",
        "right-nominornewtalk": "непоседовање мањих измена на страницама за разговор отвара прозор за нове поруке",
        "right-editusercss": "уређивање туђих Це-Ес-Ес датотека",
        "right-edituserjson": "уређивање туђих ЈСОН датотека",
        "right-edituserjs": "уређивање туђих јаваскрипт датотека",
+       "right-editsitecss": "уређивање CSS-а на нивоу сајта",
+       "right-editsitejson": "уређивање JSON-а на нивоу сајта",
+       "right-editsitejs": "Уређивање JavaScript-а на нивоу сајта",
        "right-editmyusercss": "уређивање сопствених Це-Ес-Ес датотека",
        "right-editmyuserjson": "уређивање сопствених ЈСОН датотека",
        "right-editmyuserjs": "уређивање сопствених јаваскрипт датотека",
        "right-viewmywatchlist": "преглед сопственог списка надгледања",
        "right-editmywatchlist": "уређивање сопственог списка надгледања; неке предузете радње ће свеједно додати странице на списак и без овог права",
-       "right-viewmyprivateinfo": "пÑ\80еглед Ñ\81опÑ\81Ñ\82вениÑ\85 Ð¿Ñ\80иваÑ\82ниÑ\85 Ð¿Ð¾Ð´Ð°Ñ\82ака (нпÑ\80. Ð°Ð´Ñ\80еÑ\81е Ðµ-поÑ\88Ñ\82е, Ð¿Ñ\80аво Ð¸Ð¼Ðµ)",
-       "right-editmyprivateinfo": "Ñ\83Ñ\80еÑ\92иваÑ\9aе Ñ\81опÑ\81Ñ\82вениÑ\85 Ð¿Ñ\80иваÑ\82ниÑ\85 Ð¿Ð¾Ð´Ð°Ñ\82ака (нпÑ\80. Ð°Ð´Ñ\80еÑ\81е Ðµ-поÑ\88Ñ\82е, правог имена)",
+       "right-viewmyprivateinfo": "пÑ\80еглед Ñ\81опÑ\81Ñ\82вениÑ\85 Ð¿Ñ\80иваÑ\82ниÑ\85 Ð¿Ð¾Ð´Ð°Ñ\82ака (нпÑ\80. Ðµ-адÑ\80еÑ\81е, Ð¿Ñ\80авог Ð¸Ð¼ÐµÐ½Ð°)",
+       "right-editmyprivateinfo": "Ñ\83Ñ\80еÑ\92иваÑ\9aе Ñ\81опÑ\81Ñ\82вениÑ\85 Ð¿Ñ\80иваÑ\82ниÑ\85 Ð¿Ð¾Ð´Ð°Ñ\82ака (нпÑ\80. Ðµ-адÑ\80еÑ\81е, правог имена)",
        "right-editmyoptions": "уређивање сопствених подешавања",
        "right-rollback": "брзо враћање измена последњег корисника који је мењао одређену страницу",
        "right-markbotedits": "означавање враћених измена као измене бота",
        "action-changetags": "додате и уклоните разне ознаке на појединачним изменама и уносима у дневницима",
        "action-deletechangetags": "бришете ознаке из базе података",
        "action-purge": "освежите ову страницу",
+       "action-blockemail": "блокирате кориснику слање е-порука",
+       "action-editsitecss": "уређујете CSS на новоу сајта",
+       "action-editsitejson": "уређујете JSON на нивоу сајта",
+       "action-editsitejs": "уређујете JavaScript на новоу сајта",
+       "action-hideuser": "блокирате корисничко име, сакривајући га од јавности",
        "nchanges": "$1 {{PLURAL:$1|промена|промене|промена}}",
        "ntimes": "$1×",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|измена од ваше последње посете}}",
        "recentchanges-network": "Због техничког проблема, није могуће учитати резултате. Покушајте да освежите страницу.",
        "recentchanges-notargetpage": "Унесите име странице изнад да бисте видели промене сродне с овом страницом",
        "recentchanges-feed-description": "Пратите недавне промене на викију у овом фиду.",
-       "recentchanges-label-newpage": "Ð\9dова страница",
-       "recentchanges-label-minor": "Ð\9cања измена",
-       "recentchanges-label-bot": "Ð\91оÑ\82овÑ\81ка Ð¸Ð·Ð¼ÐµÐ½Ð°",
-       "recentchanges-label-unpatrolled": "Ð\9dепаÑ\82Ñ\80олиÑ\80ана Ð¸Ð·Ð¼Ðµна",
+       "recentchanges-label-newpage": "Ð\9eвом Ð¸Ð·Ð¼ÐµÐ½Ð¾Ð¼ Ð½Ð°Ð¿Ñ\80авÑ\99ена Ñ\98е Ð½ова страница",
+       "recentchanges-label-minor": "Ð\9eво Ñ\98е Ð¼ања измена",
+       "recentchanges-label-bot": "Ð\9eвÑ\83 Ð¸Ð·Ð¼ÐµÐ½Ñ\83 Ñ\98е Ð½Ð°Ð¿Ñ\80авио Ð±Ð¾Ñ\82",
+       "recentchanges-label-unpatrolled": "Ð\9eва Ð¸Ð·Ð¼ÐµÐ½Ð° Ñ\98оÑ\88 Ð½Ð¸Ñ\98е Ð¿Ð°Ñ\82Ñ\80олиÑ\80ана",
        "recentchanges-label-plusminus": "Промена величине странице у бајтовима",
        "recentchanges-legend-heading": "<strong>Легенда:</strong>",
-       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} ([[Special:NewPages|списак нових страница]])",
+       "recentchanges-legend-newpage": "Нова страница ([[Special:NewPages|списак]])",
        "recentchanges-legend-plusminus": "(<em>±123</em>)",
        "recentchanges-submit": "Прикажи",
        "rcfilters-tag-remove": "Уклоните филтер „$1“",
        "rcfilters-savedqueries-already-saved": "Ови филтери су већ сачувани. Промените своја подешавања да бисте направили нове сачуване филтере.",
        "rcfilters-restore-default-filters": "Врати подразумеване филтере",
        "rcfilters-clear-all-filters": "Обришите све филтере",
-       "rcfilters-show-new-changes": "Ð\9dаÑ\98новиÑ\98е Ð¿Ñ\80омене",
+       "rcfilters-show-new-changes": "Ð\9dове Ð¿Ñ\80омене Ð¾Ð´ $1",
        "rcfilters-search-placeholder": "Филтрирајте промене (користите мени или претрагу за име филтера)",
        "rcfilters-invalid-filter": "Неважећи филтер",
        "rcfilters-empty-filter": "Нема активних филтера. Сви доприноси су приказани.",
        "rcfilters-filter-editsbyself-description": "Ваши сопствени доприноси.",
        "rcfilters-filter-editsbyother-label": "Промене других",
        "rcfilters-filter-editsbyother-description": "Све промене осим ваших.",
-       "rcfilters-filtergroup-userExpLevel": "Корисничка регистрација и искуство",
+       "rcfilters-filtergroup-user-experience-level": "Корисничка регистрација и искуство",
        "rcfilters-filter-user-experience-level-registered-label": "Регистровани",
        "rcfilters-filter-user-experience-level-registered-description": "Пријављени уредници.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Нерегистровани",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Филтер за „мање” измене је у сукобу са једним или више филтера типа промена, зато што одређени типови промена не могу да се означе као „мање”. Сукобљени филтери су означени у подручју Активни филтери, изнад.",
        "rcfilters-hideminor-conflicts-typeofchange": "Одређени типови промена не могу да се означе као „мање”, тако да је овај филтер у сукобу са следећим филтерима типа промена: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Овај филтер типа измене је у сукобу са филтером за „мање” измене. Одређени типови измена не могу да се означе као „мање”.",
-       "rcfilters-filtergroup-lastRevision": "Најновије измене",
+       "rcfilters-filtergroup-lastrevision": "Најновије измене",
        "rcfilters-filter-lastrevision-label": "Најновија измена",
        "rcfilters-filter-lastrevision-description": "Само најновија промена на страници.",
        "rcfilters-filter-previousrevision-label": "Није најновија измена",
        "newpageletter": "Н",
        "boteditletter": "б",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|корисник надгледа|корисника надгледају|корисника надгледају}}]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|бајт|бајта|бајтова}} после промене",
        "newsectionsummary": "/* $1 */ нови одељак",
        "upload": "Отпремање датотеке",
        "uploadbtn": "Отпреми датотеку",
        "reuploaddesc": "Назад на образац за отпремање",
-       "upload-tryagain": "Пошаљи измењени опис датотеке",
+       "upload-tryagain": "Проследи измењени опис датотеке",
        "upload-tryagain-nostash": "Пошаљите ре-отпремљену датотеку и измењен опис",
        "uploadnologin": "Нисте пријављени",
        "uploadnologintext": "$1 да бисте отпремали датотеке.",
        "upload-preferred": "Препоручени {{PLURAL:$2|тип|типови}} датотека: $1.",
        "upload-prohibited": "Забрањени {{PLURAL:$2|тип|типови}} датотека: $1.",
        "uploadlogpage": "Дневник отпремања",
-       "uploadlogpagetext": "Ð\98Ñ\81под Ñ\98е Ñ\81пиÑ\81ак Ð½ÐµÐ´Ð°Ð²Ð½Ð¸Ñ\85 Ð¾Ñ\82пÑ\80емаÑ\9aа.\nÐ\9fогледаÑ\98Ñ\82е [[Special:NewFiles|галеÑ\80иÑ\98Ñ\83 Ð½Ð¾Ð²Ð¸Ñ\85 Ð´Ð°Ñ\82оÑ\82ека]] Ð·Ð° Ð»ÐµÐ¿Ñ\88и преглед.",
+       "uploadlogpagetext": "Ð\98Ñ\81под Ñ\81е Ð½Ð°Ð»Ð°Ð·Ð¸ Ñ\81пиÑ\81ак Ð½Ð°Ñ\98новиÑ\98иÑ\85 Ð¾Ñ\82пÑ\80емаÑ\9aа.\nÐ\9fогледаÑ\98Ñ\82е [[Special:NewFiles|галеÑ\80иÑ\98Ñ\83 Ð½Ð¾Ð²Ð¸Ñ\85 Ð´Ð°Ñ\82оÑ\82ека]] Ð·Ð° Ð²Ð¸Ð·Ñ\83елниÑ\98и преглед.",
        "filename": "Назив датотеке",
        "filedesc": "Опис измене",
        "fileuploadsummary": "Опис измене:",
        "filetype-unwanted-type": "<strong>„.$1“</strong> је непожељан тип датотеке.\n{{PLURAL:$3|Пожељан тип датотеке је|Пожељни типови датотека су}} $2.",
        "filetype-banned-type": "<strong>„.$1“</strong> {{PLURAL:$4|није допуштен тип датотеке|нису допуштени типови датотека}}.\n{{PLURAL:$3|Дозвољен тип датотеке је|Дозвољени типови датотека су}} $2.",
        "filetype-missing": "Ова датотека нема проширење (нпр. „.jpg“).",
-       "empty-file": "Ð\9fоÑ\81лаÑ\82а Ð´Ð°Ñ\82оÑ\82ека је празна.",
+       "empty-file": "Ð\94аÑ\82оÑ\82ека ÐºÐ¾Ñ\98Ñ\83 Ñ\81Ñ\82е Ð¿Ñ\80оÑ\81ледили је празна.",
        "file-too-large": "Послата датотека је превелика.",
        "filename-tooshort": "Назив датотеке је прекратак.",
        "filetype-banned": "Овај тип датотеке је забрањен.",
        "upload-file-error-text": "Дошло је до унутрашње грешке при отварању привремене датотеке на серверу.\nКонтактирајте [[Special:ListUsers/sysop|администратора]].",
        "upload-misc-error": "Непозната грешка при слању датотеке",
        "upload-misc-error-text": "Дошло је до непознате грешке при отпремању датотеке.\nПроверите да ли је УРЛ важећи и доступан, па покушајте поново.\nАко се проблем буде поново јавио, обратите се [[Special:ListUsers/sysop|администратору]].",
-       "upload-too-many-redirects": "Адреса садржи превише преусмерења",
+       "upload-too-many-redirects": "URL садржи превише преусмерења",
        "upload-http-error": "Дошло је до HTTP грешке: $1",
        "upload-copy-upload-invalid-domain": "Примерци отпремања нису доступни на овом домену.",
        "upload-dialog-disabled": "Отпремања датотека коришћењем овог дијалога су онемогућена на овом викију.",
        "uploadstash-nofiles": "Немате сакривене датотеке.",
        "uploadstash-badtoken": "Извршавање ове радње није успело, разлог томе може бити истек времена за уређивање. Покушајте поново.",
        "uploadstash-errclear": "Брисање датотека није успело.",
-       "uploadstash-refresh": "Освежи списак датотека",
+       "uploadstash-refresh": "Освежи листу датотека",
        "uploadstash-thumbnail": "прикажи сличицу",
        "uploadstash-exception": "Не могу сачувати датотеку у складиште ($1): „$2“.",
        "uploadstash-bad-path": "Путања не постоји.",
        "img-auth-nopathinfo": "Недостају информације о путањи.\nВаш сервер мора да буде подешен да пропушта промењиве REQUEST_URI и/или PATH_INFO.\nАко јесте, покушајте са омогућавањем $wgUsePathInfo.\nПогледајте https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Тражена путања није у подешеном директоријуму за отпремање.",
        "img-auth-badtitle": "Није могуће саставити важећи наслов из „$1”.",
-       "img-auth-nologinnWL": "Нисте пријављени и „$1” није на списку дозвољених.",
        "img-auth-nofile": "Датотека „$1“ не постоји.",
        "img-auth-isdir": "Покушавате да приступите фасцикли „$1“.\nДозвољен је само приступ датотекама.",
        "img-auth-streaming": "Учитавам „$1“...",
        "img-auth-public": "Сврха img_auth.php је да прослеђује датотеке из приватних викија.\nОвај вики је постављен као јавни.\nРади сигурности, img_auth.php је онемогућен.",
        "img-auth-noread": "Корисник нема приступ за читање „$1“.",
        "http-invalid-url": "Неважећи УРЛ: $1",
-       "http-invalid-scheme": "Адресе са шемом „$1“ нису подржане.",
+       "http-invalid-scheme": "URL-ови са шемом „$1” нису подржани.",
        "http-request-error": "HTTP захтев није прошао због непознате грешке.",
        "http-read-error": "HTTP грешка при читању.",
        "http-timed-out": "Захтев HTTP је истекао.",
        "unwatchedpages": "Ненадгледане странице",
        "listredirects": "Списак преусмерења",
        "listduplicatedfiles": "Списак датотека са дупликатима",
-       "listduplicatedfiles-summary": "Ово је списак датотека које су дупликат неких других датотека. Само локалне датотеке су приказане.",
+       "listduplicatedfiles-summary": "Ово је списак датотека чија је најновија верзија дупликат неких других датотека. Само локалне датотеке су приказане.",
        "listduplicatedfiles-entry": "[[:File:$1|$1]] има [[$3|{{PLURAL:$2|један дупликат|$2 дупликата}}]].",
        "unusedtemplates": "Некоришћени шаблони",
        "unusedtemplatestext": "Ова страница наводи све странице у именском простору {{ns:template}} које нису укључене ни на једној другој страници.\nПре брисања проверите да ли друге странице воде до тих шаблона.",
        "pageswithprop-text": "Ова страна излистава стране које имају одређену особину",
        "pageswithprop-prop": "Име особине:",
        "pageswithprop-reverse": "Поређај у супротном редоследу",
-       "pageswithprop-sortbyvalue": "СоÑ\80Ñ\82иÑ\80ај по вредности својства",
+       "pageswithprop-sortbyvalue": "Ð\9fоÑ\80еÑ\92ај по вредности својства",
        "pageswithprop-submit": "Иди",
        "pageswithprop-prophidden-long": "сакривено дуго текстуално својство ($1)",
        "pageswithprop-prophidden-binary": "сакривено дуго бинарно својство ($1)",
        "unusedimages": "Некоришћене датотеке",
        "wantedcategories": "Тражене категорије",
        "wantedpages": "Тражене странице",
-       "wantedpages-summary": "СпиÑ\81ак Ð½ÐµÐ¿Ð¾Ñ\81Ñ\82оÑ\98еÑ\9bиÑ\85 Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\81а Ð½Ð°Ñ\98виÑ\88е Ð²ÐµÐ·Ð° Ð´Ð¾ Ñ\9aиÑ\85, Ð½Ð° Ð¾Ð²Ð¾Ð¼ Ñ\81пиÑ\81кÑ\83 Ñ\81е Ð½Ðµ Ð½Ð°Ð»Ð°Ð·Ðµ Ñ\81Ñ\82Ñ\80аниÑ\86е Ð´Ð¾ ÐºÐ¾Ñ\98иÑ\85 Ð²Ð¾Ð´Ðµ Ð¿Ñ\80еÑ\83Ñ\81меÑ\80еÑ\9aа. Ð\97а Ñ\81пиÑ\81ак Ð¿Ð¾ÐºÐ²Ð°Ñ\80ениÑ\85 Ð¿Ñ\80еÑ\83Ñ\81меÑ\80еÑ\9aа погледајте [[{{#special:BrokenRedirects}}|списак покварених преусмерења]].",
+       "wantedpages-summary": "СпиÑ\81ак Ð½ÐµÐ¿Ð¾Ñ\81Ñ\82оÑ\98еÑ\9bиÑ\85 Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\81а Ð½Ð°Ñ\98виÑ\88е Ð²ÐµÐ·Ð° Ð½Ð° Ñ\9aиÑ\85, Ð½Ð° Ð¾Ð²Ð¾Ð¼ Ñ\81пиÑ\81кÑ\83 Ñ\81е Ð½Ðµ Ð½Ð°Ð»Ð°Ð·Ðµ Ñ\81Ñ\82Ñ\80аниÑ\86е Ð´Ð¾ ÐºÐ¾Ñ\98иÑ\85 Ð²Ð¾Ð´Ðµ Ð¿Ñ\80еÑ\83Ñ\81меÑ\80еÑ\9aа. Ð\97а Ñ\81пиÑ\81ак Ð¿Ð¾ÐºÐ²Ð°Ñ\80ениÑ\85 Ð¿Ñ\80еÑ\83Ñ\81меÑ\80еÑ\9aа, погледајте [[{{#special:BrokenRedirects}}|списак покварених преусмерења]].",
        "wantedpages-badtitle": "Невалидан наслов у скупу резултата: $1",
        "wantedfiles": "Тражене датотеке",
        "wantedfiletext-cat": "Следеће датотеке се користе, али не постоје. Датотеке из других ризница могу бити наведене иако не постоје. Такве датотеке ће бити <del>поништене</del> са списка. Поред тога, странице које садрже непостојеће датотеке се налазе [[:$1|овде]].",
        "protectedpages": "Заштићене странице",
        "protectedpages-filters": "Филтери:",
        "protectedpages-indef": "Само неограничене заштите",
-       "protectedpages-summary": "Ð\9dа Ð¾Ð²Ð¾Ñ\98 Ñ\81Ñ\82Ñ\80аниÑ\86и Ñ\81е Ð½Ð°Ð»Ð°Ð·Ð¸ Ñ\81пиÑ\81ак Ð¿Ð¾Ñ\81Ñ\82оÑ\98еÑ\9bиÑ\85 Ñ\81Ñ\82Ñ\80аниÑ\86а ÐºÐ¾Ñ\98е Ñ\81Ñ\83 Ñ\82Ñ\80енÑ\83Ñ\82но Ð·Ð°Ñ\88Ñ\82иÑ\9bене. Ð\97а Ñ\81пиÑ\81ак наслова који су заштићени од прављења, погледајте [[{{#special:ProtectedTitles}}|{{int:protectedtitles}}]].",
+       "protectedpages-summary": "Ð\9eва Ñ\81Ñ\82Ñ\80аниÑ\86а Ð½Ð°Ð²Ð¾Ð´Ð¸ Ð¿Ð¾Ñ\81Ñ\82оÑ\98еÑ\9bе Ñ\81Ñ\82Ñ\80аниÑ\86е ÐºÐ¾Ñ\98е Ñ\81Ñ\83 Ñ\82Ñ\80енÑ\83Ñ\82но Ð·Ð°Ñ\88Ñ\82иÑ\9bене. Ð\97а Ð»Ð¸Ñ\81Ñ\82Ñ\83 наслова који су заштићени од прављења, погледајте [[{{#special:ProtectedTitles}}|{{int:protectedtitles}}]].",
        "protectedpages-cascade": "Само преносиве заштите",
        "protectedpages-noredirect": "Сакриј преусмерења",
        "protectedpagesempty": "Нема заштићених страница с овим параметрима.",
        "protectedpages-unknown-timestamp": "нема",
        "protectedpages-unknown-performer": "нема",
        "protectedtitles": "Заштићени наслови",
-       "protectedtitles-summary": "Ð\9dа Ð¾Ð²Ð¾Ñ\98 Ñ\81Ñ\82Ñ\80аниÑ\86и Ñ\81е Ð½Ð°Ð»Ð°Ð·Ðµ Ð½Ð°Ñ\81лови ÐºÐ¾Ñ\98и Ñ\81Ñ\83 Ñ\82Ñ\80енÑ\83Ñ\82но Ð·Ð°Ñ\88Ñ\82иÑ\9bени Ð¾Ð´ Ð¿Ñ\80авÑ\99еÑ\9aа. Ð\97а Ñ\81пиÑ\81ак постојећих страница које су заштићене, погледајте [[{{#special:ProtectedPages}}|{{int:protectedpages}}]].",
+       "protectedtitles-summary": "Ð\9eва Ñ\81Ñ\82Ñ\80аниÑ\86а Ð½Ð°Ð²Ð¾Ð´Ð¸ Ð½Ð°Ñ\81лове ÐºÐ¾Ñ\98и Ñ\81Ñ\83 Ñ\82Ñ\80енÑ\83Ñ\82но Ð·Ð°Ñ\88Ñ\82иÑ\9bени Ð¾Ð´ Ð¿Ñ\80авÑ\99еÑ\9aа. Ð\97а Ð»Ð¸Ñ\81Ñ\82Ñ\83 постојећих страница које су заштићене, погледајте [[{{#special:ProtectedPages}}|{{int:protectedpages}}]].",
        "protectedtitlesempty": "Нема заштићених наслова с овим параметрима.",
        "protectedtitles-submit": "Прикажи наслове",
        "listusers": "Списак корисника",
        "listusers-editsonly": "Прикажи само кориснике који су уређивали",
        "listusers-temporarygroupsonly": "Прикажи само кориснике у привременим корисничким групама",
-       "listusers-creationsort": "СоÑ\80Ñ\82иÑ\80аÑ\98 Ð¿Ð¾ Ð´Ð°Ñ\82Ñ\83мÑ\83 Ð¿Ñ\80авÑ\99еÑ\9aа",
+       "listusers-creationsort": "Ð\9fоÑ\80еÑ\92аÑ\98 Ð¿Ð¾ Ð´Ð°Ñ\82Ñ\83мÑ\83 Ð¾Ñ\82ваÑ\80аÑ\9aа Ð½Ð°Ð»Ð¾Ð³а",
        "listusers-desc": "Поређај у опадајућем редоследу",
        "usereditcount": "$1 {{PLURAL:$1|измена|измене|измена}}",
        "usercreated": "{{GENDER:$3|је направио|је направила|је направио}} дана $1 у $2",
        "booksources-search-legend": "Претражи штампане изворе",
        "booksources-isbn": "ISBN:",
        "booksources-search": "Претражи",
-       "booksources-text": "Ð\98Ñ\81под Ñ\81е Ð½Ð°Ð»Ð°Ð·Ð¸ Ñ\81пиÑ\81ак Ð²ÐµÐ·Ð° ÐºÐ° Ñ\81аÑ\98Ñ\82овима који се баве продајом нових и половних књига, а који би могли имати додатне податке о књигама које тражите:",
+       "booksources-text": "Ð\98Ñ\81под Ñ\81е Ð½Ð°Ð»Ð°Ð·Ð¸ Ñ\81пиÑ\81ак Ð²ÐµÐ·Ð° Ð½Ð° Ð´Ñ\80Ñ\83ге Ñ\81аÑ\98Ñ\82ове који се баве продајом нових и половних књига, а који би могли имати додатне податке о књигама које тражите:",
        "booksources-invalid-isbn": "Наведени ISBN број није валидан. Проверите да није дошло до грешке при копирању из првобитног извора.",
        "magiclink-tracking-rfc": "Странице са чаробним RFC везама",
        "magiclink-tracking-pmid": "Странице са чаробним PMID везама",
        "activeusers-noresult": "Корисник није пронађен.",
        "activeusers-submit": "Прикажи активне кориснике",
        "listgrouprights": "Права корисничких група",
-       "listgrouprights-summary": "Следи списак корисничких група на овом викију, заједно с правима приступа.\nПогледајте [[{{MediaWiki:Listgrouprights-helppage}}|више детаља]] о појединачним правима.",
+       "listgrouprights-summary": "Следи листа корисничких група дефинисаних на овом викију, заједно са повезаним правима приступа.\nМожда постоји [[{{MediaWiki:Listgrouprights-helppage}}|више информација]] о појединачним правима.",
        "listgrouprights-key": "Легенда:\n* <span class=\"listgrouprights-granted\">Додељено право</span>\n* <span class=\"listgrouprights-revoked\">Укинуто право</span>",
        "listgrouprights-group": "Група",
        "listgrouprights-rights": "Права",
        "listgrants-rights": "Права",
        "listgrants-grant-display": "$1 <code>($2)</code>",
        "trackingcategories": "Категорије за праћење",
-       "trackingcategories-summary": "Ова посебна страница је списак категорија које су део Медијавикија, оне се аутоматски ажурирају и њихови називи се могу мењати уређивањем системских порука у именском простору {{ns:8}}.",
+       "trackingcategories-summary": "Ова страница наводи категорије за праћење које аутоматски попуњава софтвер Медијавики. Њихова имена се могу променити изменом одговарајућих системских порука у именском простору {{ns:8}}.",
        "trackingcategories-msg": "Категорије за праћење",
        "trackingcategories-name": "Име поруке",
        "trackingcategories-desc": "Које странице се налазе у категорији",
        "trackingcategories-nodesc": "Опис није доступан.",
        "trackingcategories-disabled": "Категорија је онемогућена",
        "mailnologin": "Нема адресе за слање",
-       "mailnologintext": "Ð\9cоÑ\80аÑ\82е Ð´Ð° Ñ\81е [[Special:UserLogin|пÑ\80иÑ\98авиÑ\82е]] Ð¸ Ð¸Ð¼Ð°Ñ\82е Ð²Ð°Ð¶ÐµÑ\9bи Ð°Ð´Ñ\80еÑ\81Ñ\83 Ðµ-поÑ\88Ñ\82е у [[Special:Preferences|подешавањима]] да бисте слали е-поруке другим корисницима.",
+       "mailnologintext": "Ð\9cоÑ\80аÑ\82е Ð´Ð° Ñ\81е [[Special:UserLogin|пÑ\80иÑ\98авиÑ\82е]] Ð¸ Ð¸Ð¼Ð°Ñ\82е Ð²Ð°Ð¶ÐµÑ\9bи Ðµ-адÑ\80еÑ\81Ñ\83 у [[Special:Preferences|подешавањима]] да бисте слали е-поруке другим корисницима.",
        "emailuser": "Пошаљи е-поруку овом кориснику/ци",
        "emailuser-title-target": "Слање е-поруке {{GENDER:$1|кориснику|корисници|кориснику/ци}}",
-       "emailuser-title-notarget": "СлаÑ\9aе Ð¸Ð¼ÐµÑ\98ла кориснику",
-       "emailpagetext": "Ð\9cожеÑ\82е Ð´Ð° ÐºÐ¾Ñ\80иÑ\81Ñ\82иÑ\82е Ð´Ð¾Ñ\9aи Ð¾Ð±Ñ\80азаÑ\86 Ð´Ð° Ð¿Ð¾Ñ\88аÑ\99еÑ\82е Ð¸Ð¼ÐµÑ\98л {{GENDER:$1|овом ÐºÐ¾Ñ\80иÑ\81никÑ\83|овоÑ\98 ÐºÐ¾Ñ\80иÑ\81ниÑ\86и}}.\nÐ\98меÑ\98л ÐºÐ¾Ñ\98и Ñ\81Ñ\82е Ñ\83нели Ñ\83 Ð²Ð°Ñ\88им [[Special:Preferences|подеÑ\88аваÑ\9aима]] Ñ\9bе Ñ\81е Ð¿Ñ\80иказаÑ\82и Ñ\83 Ð¿Ð¾Ñ\99Ñ\83 â\80\9eÐ\9eдâ\80\9c, тако да ће прималац моћи да вам одговори директно.",
+       "emailuser-title-notarget": "СлаÑ\9aе Ðµ-поÑ\80Ñ\83ке кориснику",
+       "emailpagetext": "Ð\9cожеÑ\82е Ð´Ð° ÐºÐ¾Ñ\80иÑ\81Ñ\82иÑ\82е Ð´Ð¾Ñ\9aи Ð¾Ð±Ñ\80азаÑ\86 Ð´Ð° Ð¿Ð¾Ñ\88аÑ\99еÑ\82е Ðµ-поÑ\80Ñ\83кÑ\83 {{GENDER:$1|овом ÐºÐ¾Ñ\80иÑ\81никÑ\83|овоÑ\98 ÐºÐ¾Ñ\80иÑ\81ниÑ\86и}}.\nÐ\95-адÑ\80еÑ\81а ÐºÐ¾Ñ\98и Ñ\81Ñ\82е Ñ\83нели Ñ\83 Ð²Ð°Ñ\88им [[Special:Preferences|подеÑ\88аваÑ\9aима]] Ñ\9bе Ñ\81е Ð¿Ñ\80иказаÑ\82и Ñ\83 Ð¿Ð¾Ñ\99Ñ\83 â\80\9eÐ\9eдâ\80\9d, тако да ће прималац моћи да вам одговори директно.",
        "defemailsubject": "{{SITENAME}} — е-порука од {{GENDER:$1|корисника|кориснице|корисника/це}} „$1”",
        "usermaildisabled": "Корисничка е-пошта је онемогућена",
        "usermaildisabledtext": "Не можете да шаљете е-поруке другим корисницима на овом викију",
-       "noemailtitle": "Ð\9dема Ð°Ð´Ñ\80еÑ\81е Ðµ-поÑ\88Ñ\82е",
-       "noemailtext": "Ð\9eваÑ\98 ÐºÐ¾Ñ\80иÑ\81ник Ð½Ð¸Ñ\98е Ð½Ð°Ð²ÐµÐ¾ Ð²Ð°Ð¶ÐµÑ\9bÑ\83 Ð°Ð´Ñ\80еÑ\81Ñ\83 Ðµ-поÑ\88Ñ\82е.",
+       "noemailtitle": "Ð\9dема Ðµ-адÑ\80еÑ\81е",
+       "noemailtext": "Ð\9eваÑ\98 ÐºÐ¾Ñ\80иÑ\81ник Ð½Ð¸Ñ\98е Ð½Ð°Ð²ÐµÐ¾ Ð²Ð°Ð¶ÐµÑ\9bÑ\83 Ðµ-адÑ\80еÑ\81Ñ\83.",
        "nowikiemailtext": "Овај корисник је одабрао да не прима е-поруке од других корисника.",
        "emailnotarget": "Непостојеће или наважеће корисничко име примаоца.",
        "emailtarget": "Унос корисничког имена примаоца",
        "emailusername": "Корисничко име:",
-       "emailusernamesubmit": "Пошаљи",
+       "emailusernamesubmit": "Проследи",
        "email-legend": "Слање е-поруке кориснику/ци пројекта {{SITENAME}}",
        "emailfrom": "Од:",
        "emailto": "За:",
        "emailccsubject": "Копија поруке кориснику/ци $1: $2",
        "emailsent": "Е-порука је послата",
        "emailsenttext": "Ваша е-порука је послата.",
-       "emailuserfooter": "Ð\9eвÑ\83 Ðµ-поÑ\80Ñ\83кÑ\83 Ñ\98е {{GENDER:$1|поÑ\81лао|поÑ\81лала|поÑ\81лао/ла}} $1 {{GENDER:$2|коÑ\80иÑ\81никÑ\83|коÑ\80иÑ\81ниÑ\86и|коÑ\80иÑ\81никÑ\83\86и}} $2 Ð¿Ð¾Ð¼Ð¾Ñ\9bÑ\83 Ð¾Ð¿Ñ\86иÑ\98е â\80\9e{{int:emailuser}}â\80\9d Ð½Ð° Ð¿Ñ\80оÑ\98екÑ\82Ñ\83 {{SITENAME}}. Ð\90ко Ð¾Ð´Ð³Ð¾Ð²Ð¾Ñ\80иÑ\82е Ð½Ð° Ð¾Ð²Ñ\83 Ðµ-поÑ\80Ñ\83кÑ\83, {{GENDER:$2|ваÑ\88а}} Ðµ-поÑ\80Ñ\83ка Ð±Ð¸Ñ\9bе Ð½ÐµÐ¿Ð¾Ñ\81Ñ\80едно Ð¿Ñ\80оÑ\81леÑ\92ена ÐºÐ° {{GENDER:$1|оÑ\80игиналном Ð¿Ð¾Ñ\88иÑ\99аоÑ\86Ñ\83}}, Ñ\87име Ñ\9bеÑ\82е {{GENDER:$2|мÑ\83\98оÑ\98}} Ð¾Ñ\82кÑ\80иÑ\82и {{GENDER:$2|адÑ\80еÑ\81Ñ\83 Ðµ-поÑ\88Ñ\82е}}.",
+       "emailuserfooter": "Ð\9eвÑ\83 Ðµ-поÑ\80Ñ\83кÑ\83 Ñ\98е {{GENDER:$1|поÑ\81лао|поÑ\81лала|поÑ\81лао/ла}} $1 {{GENDER:$2|коÑ\80иÑ\81никÑ\83|коÑ\80иÑ\81ниÑ\86и|коÑ\80иÑ\81никÑ\83\86и}} $2 Ð¿Ð¾Ð¼Ð¾Ñ\9bÑ\83 Ð¾Ð¿Ñ\86иÑ\98е â\80\9e{{int:emailuser}}â\80\9d Ð½Ð° Ð¿Ñ\80оÑ\98екÑ\82Ñ\83 {{SITENAME}}. Ð\90ко Ð¾Ð´Ð³Ð¾Ð²Ð¾Ñ\80иÑ\82е Ð½Ð° Ð¾Ð²Ñ\83 Ðµ-поÑ\80Ñ\83кÑ\83, {{GENDER:$2|ваÑ\88а}} Ðµ-поÑ\80Ñ\83ка Ð±Ð¸Ñ\9bе Ð½ÐµÐ¿Ð¾Ñ\81Ñ\80едно Ð¿Ñ\80оÑ\81леÑ\92ена ÐºÐ° {{GENDER:$1|оÑ\80игиналном Ð¿Ð¾Ñ\88иÑ\99аоÑ\86Ñ\83}}, Ñ\87име Ñ\9bеÑ\82е {{GENDER:$2|мÑ\83\98оÑ\98}} Ð¾Ñ\82кÑ\80иÑ\82и {{GENDER:$2|е-адÑ\80еÑ\81Ñ\83}}.",
        "usermessage-summary": "Слање системске поруке.",
        "usermessage-editor": "Уређивач системских порука",
        "usermessage-template": "MediaWiki:UserMessage",
        "addwatch": "Додавање на списак надгледања",
        "addedwatchtext": "Страница „[[:$1]]“ и њена страница за разговор је додата на ваш [[Special:Watchlist|списак надгледања]].",
        "addedwatchtext-talk": "Страница „[[:$1]]” и њена придружена страница је додата на ваш [[Special:Watchlist|списак надгледања]]",
-       "addedwatchtext-short": "СÑ\82Ñ\80аниÑ\86а â\80\9e$1â\80\9c Ñ\98е Ð´Ð¾Ð´Ð°Ñ\82а Ð½Ð° Ð²Ð°Ñ\88 списак надгледања.",
+       "addedwatchtext-short": "СÑ\82Ñ\80аниÑ\86а â\80\9e$1â\80\9d Ñ\98е Ð´Ð¾Ð´Ð°Ñ\82а Ð½Ð° списак надгледања.",
        "removewatch": "Уклони са списка надгледања",
        "removedwatchtext": "Страница „[[:$1]]“ и њена страница за разговор је уклоњена са вашег [[Special:Watchlist|списка надгледања]].",
        "removedwatchtext-talk": "\"[[:$1]]\" и његове повезане странице су уклоњене са вашег [[Special:Watchlist|списка надгледања]].",
        "enotif_lastvisited": "За све промене од последње посете, погледајте $1.",
        "enotif_lastdiff": "Да бисте видели ову промену, погледајте $1.",
        "enotif_anon_editor": "анониман корисник $1",
-       "enotif_body": "Ð\9fоÑ\88Ñ\82овани $WATCHINGUSERNAME,\n \t\n$PAGEINTRO $NEWPAGE\n\nРезиме Ñ\83Ñ\80еÑ\92иваÑ\87а: $PAGESUMMARY $PAGEMINOREDIT\n\nÐ\9aонÑ\82акÑ\82:\nмеÑ\98л: $PAGEEDITOR_EMAIL\nвики: $PAGEEDITOR_WIKI\n\nÐ\9dеÑ\9bе Ð±Ð¸Ñ\82и Ð´Ñ\80Ñ\83гиÑ\85 Ð¾Ð±Ð°Ð²ÐµÑ\88Ñ\82еÑ\9aа Ñ\83 Ñ\81лÑ\83Ñ\87аÑ\98Ñ\83 Ð´Ð°Ñ\99иÑ\85 Ð¸Ð·Ð¼ÐµÐ½Ð° Ñ\83колико Ð½Ðµ Ð¿Ð¾Ñ\81еÑ\82иÑ\82е Ð¾Ð²Ñ\83 Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\83 ÐºÐ°Ð´Ð° Ñ\81Ñ\82е Ð¿Ñ\80иÑ\98авÑ\99ени.\nÐ\9cожеÑ\82е Ð¸ Ð´Ð° Ð¿Ð¾Ð½Ð¸Ñ\88Ñ\82иÑ\82е Ð¿Ð¾Ð´ÐµÑ\88аваÑ\9aа Ð¾Ð±Ð°Ð²ÐµÑ\88Ñ\82еÑ\9aа Ð·Ð° Ñ\81ве Ñ\81Ñ\82Ñ\80аниÑ\86е Ñ\83 Ð²Ð°Ñ\88ем Ñ\81пиÑ\81кÑ\83 Ð½Ð°Ð´Ð³Ð»ÐµÐ´Ð°Ñ\9aа.\n\nСÑ\80даÑ\87ан Ð¿Ð¾Ð·Ð´Ñ\80ав, {{SITENAME}}\n\n--\nÐ\94а Ð±Ð¸Ñ\81Ñ\82е Ð¿Ñ\80оменили Ð¿Ð¾Ð´ÐµÑ\88аваÑ\9aа Ð¸Ð¼ÐµÑ\98л Ð¾Ð±Ð°Ð²ÐµÑ\88Ñ\82еÑ\9aа, посетите\n{{canonicalurl:{{#special:Preferences}}}}\n\nДа бисте променили подешавања списка надгледања, посетите\n{{canonicalurl:{{#special:EditWatchlist}}}}\n\nДа бисте уклонили ову страницу са списка надгледања, посетите\n$UNWATCHURL\n\nПодршка и даља помоћ:\n$HELPPAGE",
+       "enotif_body": "Ð\9fоÑ\88Ñ\82овани $WATCHINGUSERNAME,\n \t\n$PAGEINTRO $NEWPAGE\n\nРезиме Ñ\83Ñ\80еÑ\92иваÑ\87а: $PAGESUMMARY $PAGEMINOREDIT\n\nÐ\9aонÑ\82акÑ\82:\nпоÑ\88Ñ\82а: $PAGEEDITOR_EMAIL\nвики: $PAGEEDITOR_WIKI\n\nÐ\9dеÑ\9bе Ð±Ð¸Ñ\82и Ð´Ñ\80Ñ\83гиÑ\85 Ð¾Ð±Ð°Ð²ÐµÑ\88Ñ\82еÑ\9aа Ñ\83 Ñ\81лÑ\83Ñ\87аÑ\98Ñ\83 Ð´Ð°Ñ\99иÑ\85 Ð¸Ð·Ð¼ÐµÐ½Ð° Ñ\83колико Ð½Ðµ Ð¿Ð¾Ñ\81еÑ\82иÑ\82е Ð¾Ð²Ñ\83 Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\83 ÐºÐ°Ð´Ð° Ñ\81Ñ\82е Ð¿Ñ\80иÑ\98авÑ\99ени.\nÐ\9cожеÑ\82е Ð¸ Ð´Ð° Ð¿Ð¾Ð½Ð¸Ñ\88Ñ\82иÑ\82е Ð¿Ð¾Ð´ÐµÑ\88аваÑ\9aа Ð¾Ð±Ð°Ð²ÐµÑ\88Ñ\82еÑ\9aа Ð·Ð° Ñ\81ве Ñ\81Ñ\82Ñ\80аниÑ\86е Ñ\83 Ð²Ð°Ñ\88ем Ñ\81пиÑ\81кÑ\83 Ð½Ð°Ð´Ð³Ð»ÐµÐ´Ð°Ñ\9aа.\n\nСÑ\80даÑ\87ан Ð¿Ð¾Ð·Ð´Ñ\80ав, {{SITENAME}}\n\n--\nÐ\94а Ð±Ð¸Ñ\81Ñ\82е Ð¿Ñ\80оменили Ð¿Ð¾Ð´ÐµÑ\88аваÑ\9aа Ð¾Ð±Ð°Ð²ÐµÑ\88Ñ\82аваÑ\9aа Ð¿Ñ\83Ñ\82ем Ðµ-поÑ\88Ñ\82е, посетите\n{{canonicalurl:{{#special:Preferences}}}}\n\nДа бисте променили подешавања списка надгледања, посетите\n{{canonicalurl:{{#special:EditWatchlist}}}}\n\nДа бисте уклонили ову страницу са списка надгледања, посетите\n$UNWATCHURL\n\nПодршка и даља помоћ:\n$HELPPAGE",
        "enotif_minoredit": "Ово је мања измена",
        "created": "направљена",
        "changed": "измењена",
        "delete-confirm": "Брисање странице „$1“",
        "delete-legend": "Брисање",
        "historywarning": "<strong>Упозорење:</strong> Страница коју желите да избришете има историју са $1 {{PLURAL:$1|ревизијом|измене|измена}}:",
-       "historyaction-submit": "Прикажи",
+       "historyaction-submit": "Прикажи измене",
        "confirmdeletetext": "Управо ћете избрисати страницу, укључујући и њену историју.\nПотврдите своју намеру, да разумете последице и да ово радите у складу са [[{{MediaWiki:Policy-url}}|правилима]].",
        "actioncomplete": "Радња је завршена",
        "actionfailed": "Радња није успела",
        "deletedtext": "Страница „$1“ је избрисана.\nПогледајте $2 за запис недавних брисања.",
        "dellogpage": "Дневник брисања",
-       "dellogpagetext": "Ð\98Ñ\81под Ñ\98е Ñ\81пиÑ\81ак Ð½ÐµÐ´Ð°Ð²Ð½их брисања.",
+       "dellogpagetext": "Ð\98Ñ\81под Ñ\81е Ð½Ð°Ð»Ð°Ð·Ð¸ Ñ\81пиÑ\81ак Ð½Ð°Ñ\98новиÑ\98их брисања.",
        "deletionlog": "дневник брисања",
        "log-name-create": "Дневник прављења страница",
-       "log-description-create": "Ð\98Ñ\81под Ñ\98е Ñ\81пиÑ\81ак Ð½ÐµÐ´Ð°Ð²Ð½их прављења страница.",
+       "log-description-create": "Ð\98Ñ\81под Ñ\81е Ð½Ð°Ð»Ð°Ð·Ð¸ Ñ\81пиÑ\81ак Ð½Ð°Ñ\98новиÑ\98их прављења страница.",
        "logentry-create-create": "$1 је {{GENDER:$2|направио|направила}} страницу $3",
        "reverted": "Враћено на ранију измену",
        "deletecomment": "Разлог:",
        "deleting-backlinks-warning": "<strong>Упозорење:</strong> бришете страницу која је укључена у [[Special:WhatLinksHere/{{FULLPAGENAME}}|друге странице]] или друге странице воде на њу.",
        "deleting-subpages-warning": "<strong>Упозорење:</strong> Страница коју желите избрисати има [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|подстраницу|$1 подстранице|$1 подстраница|51=преко 50 подстраница}}]].",
        "rollback": "Врати измене",
+       "rollback-confirmation-confirm": "Потврдите:",
+       "rollback-confirmation-yes": "Врати",
+       "rollback-confirmation-no": "Откажи",
        "rollbacklink": "врати",
        "rollbacklinkcount": "врати $1 {{PLURAL:$1|измену|измене|измена}}",
        "rollbacklinkcount-morethan": "врати више од $1 {{PLURAL:$1|измене|измене|измена}}",
        "revertpage": "Враћене измене {{GENDER:$2|корисника|кориснице}} [[Special:Contributions/$2|$2]] ([[User talk:$2|разговор]]) на последњу измену {{GENDER:$1|корисника|кориснице}} [[User:$1|$1]]",
        "revertpage-nouser": "Враћене измене скривеног корисника на последњу измену {{GENDER:$1|корисника|кориснице}} [[User:$1|$1]]",
        "rollback-success": "Враћене измене {{GENDER:$1|корисника|кориснице}} {{GENDER:$3|$1}}  на последњу измену {{GENDER:$2|корисника|кориснице}} {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Враћене измене корисника $1;\nвраћено на последњу измену корисника $2. [$3 Прикажи промене]",
        "sessionfailure-title": "Сесија је окончана",
        "sessionfailure": "Изгледа да постоји проблем с вашом сесијом;\nова радња је отказана да би се избегла злоупотреба.\nМолимо, поново пошаљите образац.",
        "changecontentmodel": "Промена модела садржаја странице",
        "logentry-contentmodel-change-revertlink": "врати",
        "logentry-contentmodel-change-revert": "врати",
        "protectlogpage": "Дневник заштите",
-       "protectlogtext": "Ð\98Ñ\81под Ñ\98е Ñ\81пиÑ\81ак Ð·Ð°Ñ\88Ñ\82иÑ\9bениÑ\85 Ñ\81Ñ\82Ñ\80аниÑ\86а.\nÐ\9fогледаÑ\98Ñ\82е [[Special:ProtectedPages|Ñ\81пиÑ\81ак Ð·Ð°Ñ\88Ñ\82иÑ\9bениÑ\85 Ñ\81Ñ\82Ñ\80аниÑ\86а]] Ð·Ð° Ð²Ð¸Ñ\88е Ð´ÐµÑ\82аÑ\99а.",
+       "protectlogtext": "Ð\98Ñ\81под Ñ\81е Ð½Ð°Ð»Ð°Ð·Ð¸ Ñ\81пиÑ\81ак Ð¿Ñ\80омена Ð·Ð°Ñ\88Ñ\82иÑ\82е Ñ\81Ñ\82Ñ\80аниÑ\86а.\nÐ\9fогледаÑ\98Ñ\82е [[Special:ProtectedPages|Ñ\81пиÑ\81ак Ð·Ð°Ñ\88Ñ\82иÑ\9bениÑ\85 Ñ\81Ñ\82Ñ\80аниÑ\86а]] Ð·Ð° Ñ\82екÑ\83Ñ\9bе Ð·Ð°Ñ\88Ñ\82иÑ\82е Ñ\81Ñ\82Ñ\80аниÑ\86а.",
        "protectedarticle": "је {{GENDER:|заштитио|заштитила}} страницу „[[$1]]“",
        "modifiedarticleprotection": "је {{GENDER:|променио|променила}} ниво заштите странице „[[$1]]“",
        "unprotectedarticle": "је скинуо заштиту са странице „[[$1]]“",
        "mycontris": "Доприноси",
        "anoncontribs": "Доприноси",
        "contribsub2": "За {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "За {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "Кориснички налог „$1“ није отворен.",
+       "negative-namespace-not-supported": "Именски простори са негативним вредностима нису подржани.",
        "nocontribs": "Нису пронађене промене које одговарају овим критеријумима.",
        "uctop": "тренутна",
        "month": "од месеца (и раније):",
        "blocklist-userblocks": "Сакриј блокаде налога",
        "blocklist-tempblocks": "Сакриј привремене блокаде",
        "blocklist-addressblocks": "Сакриј појединачне блокаде IP-а",
+       "blocklist-type": "Тип:",
+       "blocklist-type-opt-all": "Све",
+       "blocklist-type-opt-sitewide": "На нивоу сајта",
+       "blocklist-type-opt-partial": "Делимично",
        "blocklist-rangeblocks": "Сакриј блокаде опсега",
        "blocklist-timestamp": "Временска ознака",
        "blocklist-target": "Корисник",
        "blocklist-editing-page": "странице",
        "blocklist-editing-ns": "именски простори",
        "ipblocklist-empty": "Списак блокирања је празан.",
-       "ipblocklist-no-results": "ТÑ\80ажена IP Ð°Ð´Ñ\80еÑ\81а Ð¸Ð»Ð¸ ÐºÐ¾Ñ\80иÑ\81ниÑ\87ко Ð¸Ð¼Ðµ Ð½Ð¸Ñ\98е Ð±Ð»Ð¾ÐºÐ¸Ñ\80ано.",
+       "ipblocklist-no-results": "Ð\9dиÑ\81Ñ\83 Ð¿Ñ\80онаÑ\92ена Ð¾Ð´Ð³Ð¾Ð²Ð°Ñ\80аÑ\98Ñ\83Ñ\9bа Ð±Ð»Ð¾ÐºÐ¸Ñ\80аÑ\9aа Ñ\82Ñ\80ажене IP Ð°Ð´Ñ\80еÑ\81е Ð¸Ð»Ð¸ ÐºÐ¾Ñ\80иÑ\81ниÑ\87ког Ð¸Ð¼ÐµÐ½Ð°.",
        "blocklink": "блокирај",
        "unblocklink": "деблокирај",
        "change-blocklink": "промени блокаду",
        "blocklog-showsuppresslog": "{{GENDER:$1|Овај корисник је раније блокиран и сакривен|Ова корисница је раније блокирана и сакривена}}.\nДневник сакривања је наведен испод као референца:",
        "blocklogentry": "је блокирао [[$1]] са временом истицања од $2 $3",
        "reblock-logentry": "је {{GENDER:|променио|променила}} подешавања блокирања за {{GENDER:$1|корисника|корисницу}} [[$1]] са временом истека од $2 ($3)",
-       "blocklogtext": "Ð\9eво Ñ\98е Ð´Ð½ÐµÐ²Ð½Ð¸Ðº Ñ\80адÑ\9aи Ð±Ð»Ð¾ÐºÐ¸Ñ\80аÑ\9aа Ð¸ Ð´ÐµÐ±Ð»Ð¾ÐºÐ¸Ñ\80аÑ\9aа ÐºÐ¾Ñ\80иÑ\81ника.\nÐ\90Ñ\83Ñ\82омаÑ\82Ñ\81ки Ð±Ð»Ð¾ÐºÐ¸Ñ\80ане IP Ð°Ð´Ñ\80еÑ\81е Ð½Ð¸Ñ\81Ñ\83 Ð½Ð°Ð²ÐµÐ´ÐµÐ½Ðµ.\nÐ\9fогледаÑ\98Ñ\82е [[Special:BlockList|Ñ\81пиÑ\81ак Ð±Ð»Ð¾ÐºÐ¸Ñ\80аÑ\9aа]] Ð·Ð° Ñ\81пиÑ\81ак Ñ\82Ñ\80енÑ\83Ñ\82ниÑ\85 Ð¾Ð¿ÐµÑ\80аÑ\86иÑ\98а Ð·Ð°Ð±Ñ\80ана и блокирања.",
+       "blocklogtext": "Ð\9eво Ñ\98е ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98а Ñ\80адÑ\9aи Ð±Ð»Ð¾ÐºÐ¸Ñ\80аÑ\9aа Ð¸ Ð´ÐµÐ±Ð»Ð¾ÐºÐ¸Ñ\80аÑ\9aа ÐºÐ¾Ñ\80иÑ\81ника.\nÐ\90Ñ\83Ñ\82омаÑ\82Ñ\81ки Ð±Ð»Ð¾ÐºÐ¸Ñ\80ане IP Ð°Ð´Ñ\80еÑ\81е Ð½Ð¸Ñ\81Ñ\83 Ð½Ð°Ð²ÐµÐ´ÐµÐ½Ðµ.\nÐ\9fогледаÑ\98Ñ\82е [[Special:BlockList|лиÑ\81Ñ\82Ñ\83 Ð±Ð»Ð¾ÐºÐ¸Ñ\80аÑ\9aа]] Ð·Ð° Ñ\82Ñ\80енÑ\83Ñ\82но Ð¾Ð¿ÐµÑ\80аÑ\82ивне Ð·Ð°Ð±Ñ\80ане и блокирања.",
        "unblocklogentry": "је деблокирао $1",
        "block-log-flags-anononly": "само анонимни корисници",
        "block-log-flags-nocreate": "онемогућено отварање налога",
        "ipb_expiry_old": "Време истека је у прошлости.",
        "ipb_expiry_temp": "Сакривене блокаде корисника морају бити трајне.",
        "ipb_hide_invalid": "Не могу да потиснем овај налог; има више од {{PLURAL:$1|једне измене|$1 измена}}.",
+       "ipb_hide_partial": "Блокирања сакривених корисничких имена морају бити на нивоу сајта.",
        "ipb_already_blocked": "„$1“ је већ блокиран.",
        "ipb-needreblock": "$1 је већ блокиран. Желите ли да промените подешавања?",
        "ipb-otherblocks-header": "{{PLURAL:$1|Друга блокада|Друге блокаде}}",
        "movepage-page-unmoved": "Страница $1 не може да се премести на $2.",
        "movepage-max-pages": "Највише $1 {{PLURAL:$1|страница је премештена|странице су премештене|страница је премештено}} и више не може да буде аутоматски премештено.",
        "movelogpage": "Дневник премештања",
-       "movelogpagetext": "Испод се налази списак премештања страница.",
+       "movelogpagetext": "Испод се налази списак свих премештања страница.",
        "movesubpage": "{{PLURAL:$1|Подстраница|Подстранице}}",
        "movesubpagetext": "Ова страница има $1 {{PLURAL:$1|подстраницу приказану|подстранице приказане|подстраница приказаних}} испод.",
        "movenosubpage": "Ова страница нема подстрана.",
        "exportall": "Извези све странице",
        "exportcuronly": "Укључи само тренутну измену, не целу историју",
        "exportnohistory": "----\n'''Напомена:''' извоз пуне историје страница преко овог обрасца је онемогућено из техничких разлога.",
-       "exportlistauthors": "Укључи целокупан списак доприносилаца за сваку страницу",
+       "exportlistauthors": "Укључи потпуну листу доприносилаца за сваку страницу",
        "export-submit": "Извези",
        "export-addcattext": "Додај странице из категорије:",
        "export-addcat": "Додај",
        "allmessagesname": "Назив",
        "allmessagesdefault": "Подразумевани текст",
        "allmessagescurrent": "Актуелни текст поруке",
-       "allmessagestext": "Ð\9eво Ñ\98е Ñ\81пиÑ\81ак Ñ\81иÑ\81Ñ\82емÑ\81киÑ\85 Ð¿Ð¾Ñ\80Ñ\83ка Ð´Ð¾Ñ\81Ñ\82Ñ\83пниÑ\85 Ñ\83 Ð¸Ð¼ÐµÐ½Ñ\81ком Ð¿Ñ\80оÑ\81Ñ\82оÑ\80Ñ\83 â\80\9eÐ\9cедиÑ\98авикиâ\80\9c.\nÐ\9fоÑ\81еÑ\82иÑ\82е [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Ð\9cедиÑ\98авики Ð»Ð¾ÐºÐ°Ð»Ð¸Ð·Ð°Ñ\86иÑ\98Ñ\83] и [https://translatewiki.net translatewiki.net] ако желите да допринесете општој локализацији Медијавикија.",
-       "allmessagesnotsupportedDB": "Ова страница не може да се користи јер је '''$wgUseDatabaseMessages''' онемогућен.",
+       "allmessagestext": "Ð\9eво Ñ\98е Ñ\81пиÑ\81ак Ñ\81иÑ\81Ñ\82емÑ\81киÑ\85 Ð¿Ð¾Ñ\80Ñ\83ка Ð´Ð¾Ñ\81Ñ\82Ñ\83пниÑ\85 Ñ\83 Ð¸Ð¼ÐµÐ½Ñ\81ком Ð¿Ñ\80оÑ\81Ñ\82оÑ\80Ñ\83 â\80\9eÐ\9cедиÑ\98авикиâ\80\9d.\nÐ\9fоÑ\81еÑ\82иÑ\82е [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Ð»Ð¾ÐºÐ°Ð»Ð¸Ð·Ð°Ñ\86иÑ\98Ñ\83 Ð\9cедиÑ\98авикиÑ\98а] и [https://translatewiki.net translatewiki.net] ако желите да допринесете општој локализацији Медијавикија.",
+       "allmessages-not-supported-database": "Ова страница не може да се користи јер је '''$wgUseDatabaseMessages''' онемогућен.",
        "allmessages-filter-legend": "Филтер",
        "allmessages-filter": "Филтрирај по стању:",
        "allmessages-filter-unmodified": "неизмењене",
        "pageinfo-header-restrictions": "Заштита странице",
        "pageinfo-header-properties": "Својства странице",
        "pageinfo-display-title": "Наслов за приказ",
-       "pageinfo-default-sort": "Ð\9fодÑ\80азÑ\83мевани ÐºÑ\99Ñ\83Ñ\87 Ñ\81оÑ\80Ñ\82иÑ\80ања",
+       "pageinfo-default-sort": "Ð\9fодÑ\80азÑ\83мевани ÐºÑ\99Ñ\83Ñ\87 Ñ\80еÑ\92ања",
        "pageinfo-length": "Дужина странице (у бајтовима)",
        "pageinfo-namespace": "Именски простор",
        "pageinfo-article-id": "ID странице",
        "file-no-thumb-animation": "<strong>Напомена: Због техничких ограничења, сличице ове датотеке неће да се анимирају.</strong>",
        "file-no-thumb-animation-gif": "'''Напомена: због техничких ограничења, минијатуре GIF слика високе резолуције као што је ова неће се анимирати.'''",
        "newimages": "Галерија нових датотека",
-       "imagelisttext": "Ð\98Ñ\81под Ñ\98е Ñ\81пиÑ\81ак Ð¾Ð´ '''$1''' {{PLURAL:$1|датотеке|датотеке|датотека}} поређаних $2.",
+       "imagelisttext": "Ð\98Ñ\81под Ñ\81е Ð½Ð°Ð»Ð°Ð·Ð¸ Ñ\81пиÑ\81ак Ð¾Ð´ <strong>$1</strong> {{PLURAL:$1|датотеке|датотеке|датотека}} поређаних $2.",
        "newimages-summary": "Ова посебна страница приказује последње отпремљене датотеке.",
        "newimages-legend": "Филтер",
        "newimages-label": "Назив датотеке (или њен део):",
        "metadata-langitem-default": "$1",
        "namespacesall": "сви",
        "monthsall": "све",
-       "confirmemail": "Ð\9fоÑ\82вÑ\80да Ð°Ð´Ñ\80еÑ\81е Ðµ-поÑ\88Ñ\82е",
-       "confirmemail_noemail": "Ð\9dиÑ\81Ñ\82е Ð¿Ð¾Ñ\81Ñ\82авили Ð²Ð°Ð¶ÐµÑ\9bÑ\83 Ð°Ð´Ñ\80еÑ\81Ñ\83 Ðµ-поÑ\88Ñ\82е у [[Special:Preferences|корисничким подешавањима]].",
-       "confirmemail_text": "{{SITENAME}} Ð·Ð°Ñ\85Ñ\82ева Ð´Ð° Ð¿Ñ\80овеÑ\80иÑ\82е Ð²Ð°Ñ\99аноÑ\81Ñ\82 Ð¸Ð¼ÐµÑ\98л-адÑ\80еÑ\81е Ð¿Ñ\80е Ð½ÐµÐ³Ð¾ Ñ\88Ñ\82о Ð¿Ð¾Ñ\87неÑ\82е Ð´Ð° ÐºÐ¾Ñ\80иÑ\81Ñ\82иÑ\82е Ñ\84Ñ\83нкÑ\86иÑ\98Ñ\83 Ð¸Ð¼ÐµÑ\98ла.\nÐ\90кÑ\82ивиÑ\80аÑ\98Ñ\82е Ð´Ñ\83гме Ð¸Ñ\81под Ð´Ð° Ð±Ð¸Ñ\81Ñ\82е Ð¿Ð¾Ñ\81лали Ð¼ÐµÑ\98л Ð·Ð° Ð¿Ð¾Ñ\82вÑ\80дÑ\83 Ð½Ð° Ñ\81воÑ\98Ñ\83 Ð°Ð´Ñ\80еÑ\81Ñ\83.\nÐ\9cеÑ\98л Ñ\9bе Ñ\83кÑ\99Ñ\83Ñ\87иваÑ\82и Ð²ÐµÐ·Ñ\83 Ñ\81а ÐºÐ¾Ð´Ð¾Ð¼;\nÑ\83Ñ\87иÑ\82аÑ\98Ñ\82е Ð²ÐµÐ·Ñ\83 Ñ\83 Ñ\81вом Ð¿Ñ\80егледаÑ\87Ñ\83 Ð´Ð° Ð±Ð¸Ñ\81Ñ\82е Ð¿Ð¾Ñ\82вÑ\80дили Ð´Ð° Ñ\98е Ð²Ð°Ñ\88а Ð¸Ð¼ÐµÑ\98л-адреса важећа.",
-       "confirmemail_pending": "Ð\9aод Ð·Ð° Ð¿Ð¾Ñ\82вÑ\80дÑ\83 Ð²Ð°Ð¼ Ñ\98е Ð²ÐµÑ\9b Ð¿Ð¾Ñ\81лаÑ\82 Ð¸Ð¼ÐµÑ\98лом.\nАко сте недавно отворили налог, можда треба да сачекате неколико минута да пристигне пре него што поново затражите нови код.",
+       "confirmemail": "Ð\9fоÑ\82вÑ\80да Ðµ-адÑ\80еÑ\81е",
+       "confirmemail_noemail": "Ð\9dиÑ\81Ñ\82е Ð¿Ð¾Ñ\81Ñ\82авили Ð²Ð°Ð¶ÐµÑ\9bÑ\83 Ðµ-адÑ\80еÑ\81Ñ\83 у [[Special:Preferences|корисничким подешавањима]].",
+       "confirmemail_text": "{{SITENAME}} Ð·Ð°Ñ\85Ñ\82ева Ð´Ð° Ð¿Ñ\80овеÑ\80иÑ\82е Ð²Ð°Ñ\99аноÑ\81Ñ\82 Ðµ-адÑ\80еÑ\81е Ð¿Ñ\80е Ð½ÐµÐ³Ð¾ Ñ\88Ñ\82о Ð¿Ð¾Ñ\87неÑ\82е Ð´Ð° ÐºÐ¾Ñ\80иÑ\81Ñ\82иÑ\82е Ñ\84Ñ\83нкÑ\86иÑ\98Ñ\83 Ðµ-поÑ\88Ñ\82е.\nÐ\90кÑ\82ивиÑ\80аÑ\98Ñ\82е Ð´Ñ\83гме Ð¸Ñ\81под Ð´Ð° Ð±Ð¸Ñ\81Ñ\82е Ð¿Ð¾Ñ\81лали Ð¿Ð¾Ñ\80Ñ\83кÑ\83â\80\82Ñ\81а Ð¿Ð¾Ñ\82вÑ\80дом Ð½Ð° Ñ\81воÑ\98Ñ\83 Ð°Ð´Ñ\80еÑ\81Ñ\83.\nÐ\9fоÑ\80Ñ\83ка Ñ\9bе Ñ\83кÑ\99Ñ\83Ñ\87иваÑ\82и Ð²ÐµÐ·Ñ\83 Ñ\81а ÐºÐ¾Ð´Ð¾Ð¼;\nÑ\83Ñ\87иÑ\82аÑ\98Ñ\82е Ð²ÐµÐ·Ñ\83 Ñ\83 Ñ\81вом Ð¿Ñ\80егледаÑ\87Ñ\83 Ð´Ð° Ð±Ð¸Ñ\81Ñ\82е Ð¿Ð¾Ñ\82вÑ\80дили Ð´Ð° Ñ\98е Ð²Ð°Ñ\88а Ðµ-адреса важећа.",
+       "confirmemail_pending": "Ð\9aод Ð·Ð° Ð¿Ð¾Ñ\82вÑ\80дÑ\83 Ð²Ð°Ð¼ Ñ\98е Ð²ÐµÑ\9b Ð¿Ð¾Ñ\81лаÑ\82 Ðµ-поÑ\88Ñ\82ом.\nАко сте недавно отворили налог, можда треба да сачекате неколико минута да пристигне пре него што поново затражите нови код.",
        "confirmemail_send": "Пошаљи код за потврду",
        "confirmemail_sent": "Потврдна порука је послата.",
-       "confirmemail_oncreate": "Ð\9aôд Ð·Ð° Ð¿Ð¾Ñ\82вÑ\80дÑ\83 Ñ\98е Ð¿Ð¾Ñ\81лаÑ\82 Ð½Ð° Ð²Ð°Ñ\88Ñ\83 Ð¸Ð¼ÐµÑ\98л-адÑ\80еÑ\81Ñ\83.\nÐ\9eваÑ\98 ÐºÃ´Ð´ Ð½Ð¸Ñ\98е Ð½ÐµÐ¾Ð¿Ñ\85одан Ð·Ð° Ð¿Ñ\80иÑ\98авÑ\99иваÑ\9aе, Ð°Ð»Ð¸ Ñ\9bеÑ\82е Ð¼Ð¾Ñ\80аÑ\82и Ð´Ð° Ð³Ð° Ð½Ð°Ð²ÐµÐ´ÐµÑ\82е Ð¿Ñ\80е Ð¾Ð¼Ð¾Ð³Ñ\83Ñ\9bаваÑ\9aа Ð±Ð¸Ð»Ð¾ ÐºÐ°ÐºÐ²Ð¸Ñ\85 Ñ\84Ñ\83нкÑ\86иÑ\98а Ð·Ð°Ñ\81нованиÑ\85 Ð½Ð° Ð¸Ð¼ÐµÑ\98лÑ\83 на викију.",
-       "confirmemail_sendfailed": "{{SITENAME}} Ð½Ðµ Ð¼Ð¾Ð¶Ðµ Ð´Ð° Ð¿Ð¾Ñ\88аÑ\99е Ðµ-поÑ\80Ñ\83кÑ\83 Ð·Ð° Ð¿Ð¾Ñ\82вÑ\80дÑ\83.\nÐ\9fÑ\80овеÑ\80иÑ\82е Ð´Ð° Ð»Ð¸ Ñ\98е Ð°Ð´Ñ\80еÑ\81а Ðµ-поÑ\88Ñ\82е Ñ\81адÑ\80жи Ð½ÐµÐ²Ð°Ð¶ÐµÑ\9bе Ð·Ð½Ð°Ðºе.\n\nПошиљалац је вратио грешку: $1",
+       "confirmemail_oncreate": "Ð\9aôд Ð·Ð° Ð¿Ð¾Ñ\82вÑ\80дÑ\83 Ñ\98е Ð¿Ð¾Ñ\81лаÑ\82 Ð½Ð° Ð²Ð°Ñ\88Ñ\83 Ðµ-адÑ\80еÑ\81Ñ\83.\nÐ\9eваÑ\98 ÐºÃ´Ð´ Ð½Ð¸Ñ\98е Ð½ÐµÐ¾Ð¿Ñ\85одан Ð·Ð° Ð¿Ñ\80иÑ\98авÑ\99иваÑ\9aе, Ð°Ð»Ð¸ Ñ\9bеÑ\82е Ð¼Ð¾Ñ\80аÑ\82и Ð´Ð° Ð³Ð° Ð½Ð°Ð²ÐµÐ´ÐµÑ\82е Ð¿Ñ\80е Ð¾Ð¼Ð¾Ð³Ñ\83Ñ\9bаваÑ\9aа Ð±Ð¸Ð»Ð¾ ÐºÐ°ÐºÐ²Ð¸Ñ\85 Ñ\84Ñ\83нкÑ\86иÑ\98а Ð·Ð°Ñ\81нованиÑ\85 Ð½Ð° Ðµ-поÑ\88Ñ\82и на викију.",
+       "confirmemail_sendfailed": "{{SITENAME}} Ð½Ðµ Ð¼Ð¾Ð¶Ðµ Ð´Ð° Ð¿Ð¾Ñ\88аÑ\99е Ð¿Ð¾Ñ\80Ñ\83кÑ\83 Ñ\81а Ð¿Ð¾Ñ\82вÑ\80дом.\nÐ\9fÑ\80овеÑ\80иÑ\82е Ð´Ð° Ð»Ð¸ Ðµ-адÑ\80еÑ\81а Ñ\81адÑ\80жи Ð½ÐµÐ²Ð°Ð¶ÐµÑ\9bе Ð·Ð½Ð°ÐºÐ¾Ð²е.\n\nПошиљалац је вратио грешку: $1",
        "confirmemail_invalid": "Неважећи код за потврду.\nКод је можда истекао.",
-       "confirmemail_needlogin": "$1 Ð´Ð° Ð±Ð¸Ñ\81Ñ\82е Ð¿Ð¾Ñ\82вÑ\80дили Ð°Ð´Ñ\80еÑ\81Ñ\83 Ðµ-поÑ\88Ñ\82е.",
-       "confirmemail_success": "Ð\92аÑ\88а Ð°Ð´Ñ\80еÑ\81а Ðµ-поÑ\88Ñ\82е је потврђена.\nСада можете да се [[Special:UserLogin|пријавите]] и уживате у викију.",
-       "confirmemail_loggedin": "Ð\92аÑ\88а Ð°Ð´Ñ\80еÑ\81а Ðµ-поÑ\88Ñ\82е је сада потврђена.",
-       "confirmemail_subject": "{{SITENAME}} â\80\93 Ð¿Ð¾Ñ\82вÑ\80да Ð°Ð´Ñ\80еÑ\81е Ðµ-поÑ\88Ñ\82е",
-       "confirmemail_body": "Ð\9dеко, Ð²ÐµÑ\80оваÑ\82но Ð\92и, Ñ\81а IP Ð°Ð´Ñ\80еÑ\81е $1,\nÑ\80егиÑ\81Ñ\82Ñ\80овао Ñ\98е Ð½Ð°Ð»Ð¾Ð³ â\80\9e$2â\80\9c Ñ\81а Ð¾Ð²Ð¾Ð¼ Ð¸Ð¼ÐµÑ\98л Ð°Ð´Ñ\80еÑ\81ом Ð½Ð° Ð¿Ñ\80оÑ\98екÑ\82Ñ\83 {{SITENAME}}.\n\nÐ\94а Ð±Ð¸Ñ\81Ñ\82е Ð¿Ð¾Ñ\82вÑ\80дили Ð´Ð° Ð¾Ð²Ð°Ñ\98 Ð½Ð°Ð»Ð¾Ð³ Ñ\81Ñ\82ваÑ\80но Ð¿Ñ\80ипада Ð²Ð°Ð¼Ð° Ð¸ Ð°ÐºÑ\82ивиÑ\80али Ñ\84Ñ\83нкÑ\86иÑ\98Ñ\83 Ð¸Ð¼ÐµÑ\98ла Ð½Ð° Ð¿Ñ\80оÑ\98екÑ\82Ñ\83 {{SITENAME}}, Ð¾Ñ\82воÑ\80иÑ\82е Ð¾Ð²Ð° Ñ\83 Ð¿Ñ\80егледаÑ\87Ñ\83:\n\n$3\n\nÐ\90ко Ð²Ð¸ *ниÑ\81Ñ\82е* Ñ\80егиÑ\81Ñ\82Ñ\80овали Ð½Ð°Ð»Ð¾Ð³, Ð¿Ñ\80аÑ\82иÑ\82е Ð¾Ð²Ñ\83 Ð²ÐµÐ·Ñ\83\nда Ð±Ð¸Ñ\81Ñ\82е Ð¾Ñ\82казали Ð¿Ð¾Ñ\82вÑ\80дÑ\83 Ð¸Ð¼ÐµÑ\98л адресе:\n\n$5\n\nОвај код за потврду истиче у $4.",
-       "confirmemail_body_changed": "Неко, вероватно Ви, с IP адресе $1,\nпроменио је имејл адресу налога „$2“ у ову адресу на пројекту {{SITENAME}}.\n\nДа бисте потврдили да овај налог стварно припада вама и поново активирали функцију имејла, отворите следећу везу у прегледачу:\n\n$3\n\nАко налог *не* припада вама, пратите следећу везу да откажете потврду имејл адресе:\n\n$5\n\nОвај код за потврду истиче $6 у $7",
-       "confirmemail_body_set": "Неко, вероватно Ви, с IP адресе $1,\nпроменио је имејл адресу налога „$2“ у ову адресу на {{SITENAME}}.\n\nДа бисмо потврдили да овај налог стварно припада вама и поново активирали\nфункцију имејла на {{SITENAME}}, отворите следећу везу у прегледачу:\n\n$3\n\nАко налог *не* припада вама, пратите следећу везу да откажете потврду имејл адресе:\n\n$5\n\nОвај код за потврду истиче $4.",
-       "confirmemail_invalidated": "Ð\9fоÑ\82вÑ\80да Ð°Ð´Ñ\80еÑ\81е Ðµ-поÑ\88Ñ\82е је отказана",
+       "confirmemail_needlogin": "$1 Ð´Ð° Ð±Ð¸Ñ\81Ñ\82е Ð¿Ð¾Ñ\82вÑ\80дили Ðµ-адÑ\80еÑ\81Ñ\83.",
+       "confirmemail_success": "Ð\92аÑ\88а Ðµ-адÑ\80еÑ\81а је потврђена.\nСада можете да се [[Special:UserLogin|пријавите]] и уживате у викију.",
+       "confirmemail_loggedin": "Ð\92аÑ\88а Ðµ-адÑ\80еÑ\81а је сада потврђена.",
+       "confirmemail_subject": "{{SITENAME}} â\80\93 Ð¿Ð¾Ñ\82вÑ\80да Ðµ-адÑ\80еÑ\81е",
+       "confirmemail_body": "Ð\9dеко, Ð²ÐµÑ\80оваÑ\82но Ð\92и, Ñ\81а IP Ð°Ð´Ñ\80еÑ\81е $1,\nÑ\80егиÑ\81Ñ\82Ñ\80овао Ñ\98е Ð½Ð°Ð»Ð¾Ð³ â\80\9e$2â\80\9c Ñ\81а Ð¾Ð²Ð¾Ð¼ Ðµ-адÑ\80еÑ\81ом Ð½Ð° Ð¿Ñ\80оÑ\98екÑ\82Ñ\83 {{SITENAME}}.\n\nÐ\94а Ð±Ð¸Ñ\81Ñ\82е Ð¿Ð¾Ñ\82вÑ\80дили Ð´Ð° Ð¾Ð²Ð°Ñ\98 Ð½Ð°Ð»Ð¾Ð³ Ñ\81Ñ\82ваÑ\80но Ð¿Ñ\80ипада Ð²Ð°Ð¼Ð° Ð¸ Ð°ÐºÑ\82ивиÑ\80али Ñ\84Ñ\83нкÑ\86иÑ\98е Ðµ-поÑ\88Ñ\82е Ð½Ð° Ð¿Ñ\80оÑ\98екÑ\82Ñ\83 {{SITENAME}}, Ð¾Ñ\82воÑ\80иÑ\82е Ð¾Ð²Ñ\83 Ð²ÐµÐ·Ñ\83 Ñ\83 Ð¿Ñ\80егледаÑ\87Ñ\83:\n\n$3\n\nÐ\90ко Ð²Ð¸ *ниÑ\81Ñ\82е* Ñ\80егиÑ\81Ñ\82Ñ\80овали Ð½Ð°Ð»Ð¾Ð³, Ð¿Ñ\80аÑ\82иÑ\82е Ð¾Ð²Ñ\83 Ð²ÐµÐ·Ñ\83\nда Ð±Ð¸Ñ\81Ñ\82е Ð¾Ñ\82казали Ð¿Ð¾Ñ\82вÑ\80дÑ\83 Ðµ-адресе:\n\n$5\n\nОвај код за потврду истиче у $4.",
+       "confirmemail_body_changed": "Неко, вероватно Ви, са IP адресе $1,\nпроменио је е-адресу налога „$2” у ову адресу на пројекту {{SITENAME}}.\n\nДа бисте потврдили да овај налог стварно припада вама и поново активирали функције е-поште, отворите следећу везу у прегледачу:\n\n$3\n\nАко налог *не* припада вама, пратите следећу везу да откажете потврду е-адресе:\n\n$5\n\nОвај код за потврду истиче $6 у $7",
+       "confirmemail_body_set": "Неко, вероватно Ви, са IP адресе $1,\nпроменио је е-адресу налога „$2” у ову адресу на {{SITENAME}}.\n\nДа бисмо потврдили да овај налог стварно припада вама и поново активирали\nфункције е-поште на пројекту {{SITENAME}}, отворите следећу везу у прегледачу:\n\n$3\n\nАко налог *не* припада вама, пратите следећу везу да откажете потврду е-адресе:\n\n$5\n\nОвај код за потврду истиче $4.",
+       "confirmemail_invalidated": "Ð\9fоÑ\82вÑ\80да Ðµ-адÑ\80еÑ\81е је отказана",
        "invalidateemail": "Отказивање потврде е-поште",
-       "notificationemail_subject_changed": "РегиÑ\81Ñ\82Ñ\80ована Ð¸Ð¼ÐµÑ\98л адреса на пројекту {{SITENAME}} је промењена",
-       "notificationemail_subject_removed": "РегиÑ\81Ñ\82Ñ\80ована Ð¸Ð¼ÐµÑ\98л адреса на пројекту {{SITENAME}} је уклоњена",
-       "notificationemail_body_changed": "Неко, вероватно Ви је променио имејл адресу налога из $2“ у „$3“ са IP адресе $1 на сајту {{SITENAME}}.\n\nАко ово нисте били Ви, одмах обавестите администраторе сајта.",
-       "notificationemail_body_removed": "Неко, вероватно Ви, с IP адресе $1, \nуклонио је имејл адресу за налог „$2“ на {{SITENAME}}.\n\nАко ово нисте били Ви, контактирајте администраторе сајта одмах.",
+       "notificationemail_subject_changed": "РегиÑ\81Ñ\82Ñ\80ована Ðµ-адреса на пројекту {{SITENAME}} је промењена",
+       "notificationemail_subject_removed": "РегиÑ\81Ñ\82Ñ\80ована Ðµ-адреса на пројекту {{SITENAME}} је уклоњена",
+       "notificationemail_body_changed": "Неко, вероватно Ви, са IP адресе $1,\nпроменио је е-адресу налога из „$2” у „$3” на пројекту {{SITENAME}}.\n\nАко ово нисте били Ви, одмах се обратите администратору сајта.",
+       "notificationemail_body_removed": "Неко, вероватно Ви, са IP адресе $1, \nуклонио је е-адресу налога „$2” на пројекту {{SITENAME}}.\n\nАко ово нисте били Ви, одмах се обратите администратору сајта.",
        "scarytranscludedisabled": "[Међувики укључивање шаблона је онемогућено]",
        "scarytranscludefailed": "[Добављање шаблона за $1 није успело]",
        "scarytranscludefailed-httpstatus": "[Не могу да преузмем шаблон $1: HTTP $2]",
        "watchlistedit-normal-done": "{{PLURAL:$1|1=Једна страница је уклоњена|$1 странице су уклоњене|$1 страница је уклоњено}} с вашег списка надгледања:",
        "watchlistedit-raw-title": "Уређивање необрађеног списка надгледања",
        "watchlistedit-raw-legend": "Уређивање необрађеног списка надгледања",
-       "watchlistedit-raw-explain": "Ð\9dаÑ\81лови Ñ\81а Ñ\81пиÑ\81ка Ð½Ð°Ð´Ð³Ð»ÐµÐ´Ð°Ñ\9aа Ñ\81Ñ\83 Ð¿Ñ\80иказани Ð¸Ñ\81под Ð¸ Ð¼Ð¾Ð³Ñ\83 Ñ\81е Ñ\83Ñ\80еÑ\92иваÑ\82и Ð´Ð¾Ð´Ð°Ð²Ð°Ñ\9aем Ð¸Ð»Ð¸ Ñ\83клаÑ\9aаÑ\9aем Ñ\81Ñ\82авки Ñ\81а Ñ\81пиÑ\81ка;\nÑ\98едан Ð½Ð°Ñ\81лов Ð¿Ð¾ Ñ\80едÑ\83.\nÐ\9aада Ð·Ð°Ð²Ñ\80Ñ\88иÑ\82е, ÐºÐ»Ð¸ÐºÐ½Ð¸Ñ\82е Ð½Ð° â\80\9e{{int:Watchlistedit-raw-submit}}â\80\9c.\nÐ\9cожеÑ\82е Ð´Ð° [[Special:EditWatchlist|коÑ\80иÑ\81Ñ\82иÑ\82е Ð¸ Ð¾Ð±Ð¸Ñ\87ан уређивач]].",
+       "watchlistedit-raw-explain": "Ð\9dаÑ\81лови Ñ\81а Ñ\81пиÑ\81ка Ð½Ð°Ð´Ð³Ð»ÐµÐ´Ð°Ñ\9aа Ñ\81Ñ\83 Ð¿Ñ\80иказани Ð¸Ñ\81под Ð¸ Ð¼Ð¾Ð³Ñ\83 Ñ\81е Ñ\83Ñ\80еÑ\92иваÑ\82и Ð´Ð¾Ð´Ð°Ð²Ð°Ñ\9aем Ð¸Ð»Ð¸ Ñ\83клаÑ\9aаÑ\9aем Ñ\81Ñ\82авки Ñ\81а Ñ\81пиÑ\81ка;\nÑ\98едан Ð½Ð°Ñ\81лов Ð¿Ð¾ Ñ\80едÑ\83.\nÐ\9aада Ð·Ð°Ð²Ñ\80Ñ\88иÑ\82е, ÐºÐ»Ð¸ÐºÐ½Ð¸Ñ\82е Ð½Ð° â\80\9e{{int:Watchlistedit-raw-submit}}â\80\9d.\nÐ\9cожеÑ\82е Ð´Ð° [[Special:EditWatchlist|коÑ\80иÑ\81Ñ\82иÑ\82е Ð¸ Ñ\81Ñ\82андаÑ\80дни уређивач]].",
        "watchlistedit-raw-titles": "Наслови:",
        "watchlistedit-raw-submit": "Ажурирај списак",
        "watchlistedit-raw-done": "Ваш списак надгледања је ажуриран.",
        "tag-mw-undo": "поништење",
        "tag-mw-undo-description": "Измене које поништавају претходне измене",
        "tags-title": "Ознаке",
-       "tags-intro": "Ð\9dа Ð¾Ð²Ð¾Ñ\98 Ñ\81Ñ\82Ñ\80аниÑ\86и Ñ\98е Ð½Ð°Ð²ÐµÐ´ÐµÐ½ Ñ\81пиÑ\81ак Ð¾Ð·Ð½Ð°ÐºÐ° Ñ\81 ÐºÐ¾Ñ\98има Ð¿Ñ\80огÑ\80ам Ð¼Ð¾Ð¶Ðµ Ð´Ð° Ð¾Ð·Ð½Ð°Ñ\87и Ð¸Ð·Ð¼ÐµÐ½Ðµ Ð¸ Ñ\9aегово значење.",
-       "tags-tag": "Ð\9dазив ознаке",
+       "tags-intro": "Ð\9eва Ñ\81Ñ\82Ñ\80аниÑ\86а Ð½Ð°Ð²Ð¾Ð´Ð¸ Ð¾Ð·Ð½Ð°ÐºÐµ ÐºÐ¾Ñ\98има Ñ\81оÑ\84Ñ\82веÑ\80 Ð¼Ð¾Ð¶Ðµ Ð´Ð° Ð¾Ð·Ð½Ð°Ñ\87и Ð¸Ð·Ð¼ÐµÐ½Ðµ, Ñ\82е Ñ\9aиÑ\85ово значење.",
+       "tags-tag": "Ð\98ме ознаке",
        "tags-display-header": "Изглед на списковима промена",
        "tags-description-header": "Опис значења",
        "tags-source-header": "Извор",
        "tags-deactivate-question": "Деактивирате ознаку „$1“.",
        "tags-deactivate-reason": "Разлог:",
        "tags-deactivate-not-allowed": "Није могуће деактивирати ознаку „$1”.",
-       "tags-deactivate-submit": "Ð\94екативирај",
+       "tags-deactivate-submit": "Ð\94еактивирај",
        "tags-apply-no-permission": "Немате дозволу да примените ознаке промена заједно са својим променама.",
        "tags-apply-blocked": "Не можете да примените ознаке промена заједно са вашим променама све док {{GENDER:$1|сте}} блокирани.",
        "tags-update-no-permission": "Немате дозволу да додате или уклоните ознаке промена из појединачних измена или уноса у дневнику.",
        "htmlform-int-toolow": "Наведена вредност је испод минимума од $1",
        "htmlform-int-toohigh": "Наведена вредност је изнад максимума од $1",
        "htmlform-required": "Ова вредност је обавезна.",
-       "htmlform-submit": "Постави",
+       "htmlform-submit": "Проследи",
        "htmlform-reset": "Врати промене",
        "htmlform-selectorother-other": "Друго",
        "htmlform-no": "Не",
        "logentry-block-unblock": "$1 је {{GENDER:$2|деблокирао|деблокирала}} {{GENDER:$4|$3}}",
        "logentry-block-reblock": "$1 је {{GENDER:$2|променио|променила}} подешавања за блокирање {{GENDER:$4|корисника|кориснице}} {{GENDER:$4|$3}} у трајању од $5 $6",
        "logentry-partialblock-block-page": "{{PLURAL:$1|странице|страница}} $2",
-       "logentry-partialblock-block": "$1 је {{GENDER:$2|блокирао|блокирала}} уређивање $7 {{GENDER:$4|кориснику|корисници|кориснику/ци}} $3 са временом истека од $5 $6",
+       "logentry-partialblock-block-ns": "{{PLURAL:$1|именског простора|именских простора}} $2",
+       "logentry-partialblock-block": "$1 је {{GENDER:$2|блокирао|блокирала}} уређивање $7 {{GENDER:$4|кориснику|корисници}} $3 са временом истека од $5 $6",
+       "logentry-partialblock-reblock": "$1 је {{GENDER:$2|променио}} подешавања блокирања {{GENDER:$4|корисника|кориснице}} $3 спречавањем измена $7 са временом истека од $5 $6",
        "logentry-non-editing-block-block": "$1 је {{GENDER:$2|блокирао|блокирала}} одређене неуређивачке радње {{GENDER:$4|кориснику|корисници|кориснику/ци}} $3 са временом истека од $5 $6",
        "logentry-non-editing-block-reblock": "$1 је {{GENDER:$2|променио|променила}} подешавања блокаде одређених неуређивачких радњи {{GENDER:$4|кориснику|корисници|кориснику/ци}} $3 са временом истека од $5 $6",
        "logentry-suppress-block": "$1 је {{GENDER:$2|блокирао|блокирала}} {{GENDER:$4|$3}} у трајању од $5 $6",
        "logentry-newusers-newusers": "$1 је {{GENDER:$2|отворио|отворила}} кориснички налог",
        "logentry-newusers-create": "$1 је {{GENDER:$2|отворио|отворила}} кориснички налог",
        "logentry-newusers-create2": "$1 је {{GENDER:$2|отворио|отворила}} кориснички налог $3",
-       "logentry-newusers-byemail": "$1 Ñ\98е {{GENDER:$2|оÑ\82воÑ\80ио|оÑ\82воÑ\80ила}} ÐºÐ¾Ñ\80иÑ\81ниÑ\87ки Ð½Ð°Ð»Ð¾Ð³ $3 Ð¸ Ð»Ð¾Ð·Ð¸Ð½ÐºÐ° Ñ\98е Ð¿Ð¾Ñ\81лаÑ\82а Ð½Ð° Ð¸Ð¼ÐµÑ\98л",
+       "logentry-newusers-byemail": "$1 Ñ\98е {{GENDER:$2|оÑ\82воÑ\80ио|оÑ\82воÑ\80ила}} ÐºÐ¾Ñ\80иÑ\81ниÑ\87ки Ð½Ð°Ð»Ð¾Ð³ $3 Ð¸ Ð»Ð¾Ð·Ð¸Ð½ÐºÐ° Ñ\98е Ð¿Ð¾Ñ\81лаÑ\82а Ð½Ð° Ðµ-поÑ\88Ñ\82Ñ\83",
        "logentry-newusers-autocreate": "$1 је аутоматски {{GENDER:$2|отворио|отворила}} кориснички налог",
        "logentry-protect-move_prot": "$1 је {{GENDER:$2|преместио|преместила}} подешавања заштите са $4 на $3",
        "logentry-protect-unprotect": "$1 je {{GENDER:$2|скинуо|скинула}} заштиту са странице $3",
        "logentry-upload-overwrite": "$1 је {{GENDER:$2|отпремио|отпремила}} нову верзију датотеке $3",
        "logentry-upload-revert": "$1 је {{GENDER:$2|вратио|вратила}} датотеку $3 на старију верзију",
        "log-name-managetags": "Дневник управљања ознакама",
-       "log-description-managetags": "Ð\9dа Ð¾Ð²Ð¾Ñ\98 Ñ\81Ñ\82Ñ\80аниÑ\86и Ñ\81е Ð½Ð°Ð»Ð°Ð·Ð¸ Ñ\81пиÑ\81ак Ð¸Ð·Ð¼ÐµÐ½Ð° Ñ\83 Ð²ÐµÐ·Ð¸ [[Special:Tags|ознака]]. Ð\94невник Ñ\81адÑ\80жи Ñ\81амо Ñ\80адÑ\9aе ÐºÐ¾Ñ\98е Ñ\81Ñ\83 Ñ\80Ñ\83Ñ\87но Ð¸Ð·Ð²Ñ\80Ñ\88или Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñ\81Ñ\82Ñ\80аÑ\82оÑ\80и; Ñ\83ноÑ\81и Ð·Ð° Ð¾Ð·Ð½Ð°ÐºÐµ ÐºÐ¾Ñ\98е Ñ\98е Ð½Ð°Ð¿Ñ\80авио Ð¸Ð»Ð¸ Ð¸Ð·Ð±Ñ\80иÑ\81ао Ð²Ð¸ÐºÐ¸ Ñ\81оÑ\84Ñ\82веÑ\80, Ð° Ð½Ðµ Ð½Ð°Ð»Ð°Ð·Ðµ Ñ\81е Ñ\83 Ð¾Ð²Ð¾Ð¼ Ð´Ð½ÐµÐ²Ð½Ð¸ÐºÑ\83.",
+       "log-description-managetags": "Ð\9eва Ñ\81Ñ\82Ñ\80аниÑ\86а Ð½Ð°Ð²Ð¾Ð´Ð¸ Ð·Ð°Ð´Ð°Ñ\82ке Ñ\83пÑ\80авÑ\99аÑ\9aа Ñ\83 Ð²ÐµÐ·Ð¸ Ñ\81а [[Special:Tags|ознакама]]. Ð\95виденÑ\86иÑ\98а Ñ\81адÑ\80жи Ñ\81амо Ñ\80адÑ\9aе ÐºÐ¾Ñ\98е Ñ\81Ñ\83 Ñ\80Ñ\83Ñ\87но Ð¸Ð·Ð²Ñ\80Ñ\88или Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñ\81Ñ\82Ñ\80аÑ\82оÑ\80и; Ñ\83ноÑ\81и Ð·Ð° Ð¾Ð·Ð½Ð°ÐºÐµ ÐºÐ¾Ñ\98е Ñ\98е Ð½Ð°Ð¿Ñ\80авио Ð¸Ð»Ð¸ Ð¸Ð·Ð±Ñ\80иÑ\81ао Ð²Ð¸ÐºÐ¸ Ñ\81оÑ\84Ñ\82веÑ\80, Ð° Ð½Ðµ Ð½Ð°Ð»Ð°Ð·Ðµ Ñ\81е Ñ\83 Ð¾Ð²Ð¾Ñ\98 ÐµÐ²Ð¸Ð´ÐµÐ½Ñ\86иÑ\98и.",
        "logentry-managetags-create": "$1 је {{GENDER:$2|направио|направила}} ознаку „$4“",
        "logentry-managetags-delete": "$1 је {{GENDER:$2|избрисао|избрисала}} ознаку „$4” (уклоњена је из $5 {{PLURAL:$5|измене или уноса у дневнику|измена и/или уноса у дневнику}})",
        "logentry-managetags-activate": "$1 је {{GENDER:$2|активирао|активирала}} ознаку „$4“ за употребу од стране корисника и ботова",
        "authmanager-domain-help": "Домен за спољашњу потврду идентитета.",
        "authmanager-retype-help": "Поновите лозинку да би сте потврдили.",
        "authmanager-email-label": "Е-пошта",
-       "authmanager-email-help": "Ð\90дÑ\80еÑ\81а Ðµ-поÑ\88Ñ\82е:",
+       "authmanager-email-help": "Ð\95-адÑ\80еÑ\81а",
        "authmanager-realname-label": "Право име",
        "authmanager-realname-help": "Право име корисника",
        "authmanager-provider-password": "Потврда идентитета лозинком",
        "pagedata-bad-title": "Невалидан наслов: $1.",
        "unregistered-user-config": "Из безбедоносних разлога, јаваскрипт, Це-Ес-Ес и ЈСОН корисничке подстранице не могу бити учитане за нерегистроване кориснике.",
        "passwordpolicies": "Правила за лозинке",
-       "passwordpolicies-summary": "Ð\9eво Ñ\98е Ñ\81пиÑ\81ак Ð´ÐµÐ»Ð¾Ñ\82воÑ\80ниÑ\85 Ñ\81меÑ\80ниÑ\86а Ð·Ð° Ð»Ð¾Ð·Ð¸Ð½ÐºÐµ Ð·Ð° ÐºÐ¾Ñ\80иÑ\81ниÑ\87ке Ð³Ñ\80Ñ\83пе Ð¾Ð´Ñ\80еÑ\92ене на овом викију.",
+       "passwordpolicies-summary": "Ð\9eво Ñ\98е Ñ\81пиÑ\81ак Ð´ÐµÐ»Ð¾Ñ\82воÑ\80ниÑ\85 Ñ\81меÑ\80ниÑ\86а Ð·Ð° Ð»Ð¾Ð·Ð¸Ð½ÐºÐµ Ð·Ð° ÐºÐ¾Ñ\80иÑ\81ниÑ\87ке Ð³Ñ\80Ñ\83пе Ð´ÐµÑ\84иниÑ\81ане на овом викију.",
        "passwordpolicies-group": "Група",
        "passwordpolicies-policies": "Правила",
        "passwordpolicies-policy-display": "<span class=\"passwordpolicies-policy\">$1 <code>($2)</code></span>",
index f089ca0..ac8efbb 100644 (file)
        "rcfilters-filter-editsbyself-description": "Vaši sopstveni doprinosi.",
        "rcfilters-filter-editsbyother-label": "Promene drugih",
        "rcfilters-filter-editsbyother-description": "Sve promene osim vaših.",
-       "rcfilters-filtergroup-userExpLevel": "Korisnička registracija i iskustvo",
+       "rcfilters-filtergroup-user-experience-level": "Korisnička registracija i iskustvo",
        "rcfilters-filter-user-experience-level-registered-label": "Registrovani",
        "rcfilters-filter-user-experience-level-registered-description": "Prijavljeni urednici.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Neregistrovani",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Filter za „manje” izmene je u sukobu sa jednim ili više filtera tipa promena, zato što određeni tipovi promena ne mogu da se označe kao „manje”. Sukobljeni filteri su označeni u području Aktivni filteri, iznad.",
        "rcfilters-hideminor-conflicts-typeofchange": "Određeni tipovi promena ne mogu da se označe kao „manje”, tako da je ovaj filter u sukobu sa sledećim filterima tipa promena: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Ovaj filter tipa izmene je u sukobu sa filterom za „manje” izmene. Određeni tipovi izmena ne mogu da se označe kao „manje”.",
-       "rcfilters-filtergroup-lastRevision": "Najnovije izmene",
+       "rcfilters-filtergroup-lastrevision": "Najnovije izmene",
        "rcfilters-filter-lastrevision-label": "Najnovija izmena",
        "rcfilters-filter-lastrevision-description": "Samo najnovija promena na stranici.",
        "rcfilters-filter-previousrevision-label": "Nije najnovija izmena",
        "newpageletter": "N",
        "boteditletter": "b",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|korisnik nadgleda|korisnika nadgledaju|korisnika nadgledaju}}]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|bajt|bajta|bajtova}} posle promene",
        "newsectionsummary": "/* $1 */ novi odeljak",
        "img-auth-nopathinfo": "Nedostaju informacije o putanji.\nVaš server mora da bude podešen da propušta promenjive REQUEST_URI i/ili PATH_INFO.\nAko jeste, pokušajte sa omogućavanjem $wgUsePathInfo.\nPogledajte https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Tražena putanja nije u podešenom direktorijumu za otpremanje.",
        "img-auth-badtitle": "Nije moguće sastaviti važeći naslov iz „$1”.",
-       "img-auth-nologinnWL": "Niste prijavljeni i „$1” nije na spisku dozvoljenih.",
        "img-auth-nofile": "Datoteka „$1“ ne postoji.",
        "img-auth-isdir": "Pokušavate da pristupite fascikli „$1“.\nDozvoljen je samo pristup datotekama.",
        "img-auth-streaming": "Učitavam „$1“...",
        "revertpage": "Vraćene izmene {{GENDER:$2|korisnika|korisnice}} [[Special:Contributions/$2|$2]] ([[User talk:$2|razgovor]]) na poslednju izmenu {{GENDER:$1|korisnika|korisnice}} [[User:$1|$1]]",
        "revertpage-nouser": "Vraćene izmene skrivenog korisnika na poslednju izmenu {{GENDER:$1|korisnika|korisnice}} [[User:$1|$1]]",
        "rollback-success": "Vraćene izmene {{GENDER:$1|korisnika|korisnice}} {{GENDER:$3|$1}}  na poslednju izmenu {{GENDER:$2|korisnika|korisnice}} {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Vraćene izmene korisnika $1;\nvraćeno na poslednju izmenu korisnika $2. [$3 Prikaži promene]",
        "sessionfailure-title": "Sesija je okončana",
        "sessionfailure": "Izgleda da postoji problem s vašom sesijom;\nova radnja je otkazana da bi se izbegla zloupotreba.\nMolimo, ponovo pošaljite obrazac.",
        "changecontentmodel": "Promena modela sadržaja stranice",
        "allmessagesdefault": "Podrazumevani tekst",
        "allmessagescurrent": "Aktuelni tekst poruke",
        "allmessagestext": "Ovo je spisak sistemskih poruka dostupnih u imenskom prostoru „Medijaviki“.\nPosetite [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Medijaviki lokalizaciju] i [https://translatewiki.net translatewiki.net] ako želite da doprinesete opštoj lokalizaciji Medijavikija.",
-       "allmessagesnotsupportedDB": "Ova stranica ne može da se koristi jer je '''$wgUseDatabaseMessages''' onemogućen.",
+       "allmessages-not-supported-database": "Ova stranica ne može da se koristi jer je '''$wgUseDatabaseMessages''' onemogućen.",
        "allmessages-filter-legend": "Filter",
        "allmessages-filter": "Filtriraj po stanju:",
        "allmessages-filter-unmodified": "neizmenjene",
index 5cf1a0f..10ab182 100644 (file)
@@ -12,7 +12,8 @@
                        "아라",
                        "Macofe",
                        "Fitoschido",
-                       "Vlad5250"
+                       "Vlad5250",
+                       "PiefPafPier"
                ]
        },
        "tog-underline": "Ferwiese unnerstriekje:",
        "recentchanges-label-minor": "Litje Annerenge",
        "recentchanges-label-bot": "Annerenge truch n Bot",
        "recentchanges-label-unpatrolled": "Nit-kontrollierde Annerenge",
-       "recentchanges-legend-newpage": "$1 - näie Siede",
+       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}}<br />(Sjuch uk ju [[Special:NewPages|Lieste mäd näie Sieden]])",
        "rcnotefrom": "Anwiesd wäide do Annerengen siet '''$2''' (max. '''$1''' Iendraage).",
        "rclistfrom": "Bloot näie Annerengen siet $3 $2 wiese.",
        "rcshowhideminor": "Litje Annerengen $1",
        "minoreditletter": "L",
        "newpageletter": "Näi",
        "boteditletter": "B",
-       "number_of_watching_users_pageview": "[$1 beooboachtjende {{PLURAL:$1|Benutser|Benutsere}}]",
        "rc-change-size": "$1 {{PLURAL:$1|Byte|Bytes}}",
        "newsectionsummary": "Näie Apsats /* $1 */",
        "rc-enhanced-expand": "Details anwiese (bruukt JavaScript)",
        "img-auth-nopathinfo": "PATH_INFO failt.\nDie Server is nit deerfoar iengjucht, disse Information fääretoureeken.\nJu kuud CGI-basierd weese un unnerstutset img_auth nit.\nSjuch https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Dät wonskede Paad is nit in dät konfigurierde Uploadferteeknis.",
        "img-auth-badtitle": "Uut „$1“ kon naan gultigen Tittel moaked wäide.",
-       "img-auth-nologinnWL": "Du bäst nit anmälded un „$1“ is nit in ju wiete Lieste.",
        "img-auth-nofile": "Doatäi „$1“ bestoant nit.",
        "img-auth-isdir": "Du fersäkst, ap n Ferteeknis „$1“ toutougriepen.\nBloot Doatäitougriep is ferlööwed.",
        "img-auth-streaming": "„$1“ leede.",
        "allmessagesdefault": "Standardtext",
        "allmessagescurrent": "Dissen Text",
        "allmessagestext": "Dit is ne Lieste fon aal System-Ättergjuchte do in dän MediaWiki-Noomenruum tou Ferföigenge stounde.\nBesäik jädden [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] un [https://translatewiki.net translatewiki.net], wan du mee-oarbaidje wolt an ju MediaWiki-Sortierenge.",
-       "allmessagesnotsupportedDB": "Disse Spezioalsiede stoant nit tou Ferföigenge, deer ju uur dän Parameter <tt>$wgUseDatabaseMessages</tt> deaktivierd wuude.",
+       "allmessages-not-supported-database": "Disse Spezioalsiede stoant nit tou Ferföigenge, deer ju uur dän Parameter <tt>$wgUseDatabaseMessages</tt> deaktivierd wuude.",
        "allmessages-filter-legend": "Sieuwe",
        "allmessages-filter": "Sieuwe foar anpaaseden Toustand:",
        "allmessages-filter-unmodified": "Uunferannerd",
index a81ab20..c2a2729 100644 (file)
        "page_first": "mimiti",
        "page_last": "tung-tung",
        "histlegend": "Pilihan béda: tandaan wadah buleud vérsina pikeun ngabandingkeun sarta pencét énter atawa tombol di handap.<br />\nKaterangan: (kiw) = bédana jeung vérsi kiwari,\n(ahir) = bédana jeung vérsi nu harita, m = éditan minor.",
-       "history-fieldset-title": "Paluruh vérsi heubeul",
+       "history-fieldset-title": "Saring révisi",
        "history-show-deleted": "Ukur ngahapus révisi",
        "histfirst": "pangheubeulna",
        "histlast": "panganyarna",
        "rcfilters-filter-editsbyself-description": "Kontribusi anjeun.",
        "rcfilters-filter-editsbyother-label": "Éditan ku batur",
        "rcfilters-filter-editsbyother-description": "Sakumna éditan iwal nu kuring.",
-       "rcfilters-filtergroup-userExpLevel": "Padaptaran sarta pangalaman pamaké",
+       "rcfilters-filtergroup-user-experience-level": "Padaptaran sarta pangalaman pamaké",
        "rcfilters-filter-user-experience-level-registered-label": "Kadaptar",
        "rcfilters-filter-user-experience-level-registered-description": "Éditor asup log.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Teu kadaptar",
        "rcfilters-filter-categorization-label": "Parobahan kategori",
        "rcfilters-filter-categorization-description": "Rékaman kaca nu geus ditambahkeun atawa dipupus tina kategori.",
        "rcfilters-filter-logactions-label": "Tarékah kacatet",
-       "rcfilters-filtergroup-lastRevision": "Révisi panganyarna",
+       "rcfilters-filtergroup-lastrevision": "Révisi panganyarna",
        "rcfilters-filter-lastrevision-label": "Révisi panganyarna",
        "rcfilters-filter-lastrevision-description": "Ngan parobahan panganyarna di ieu kaca.",
        "rcfilters-filter-previousrevision-label": "Lain révisi panganyarna",
        "minoreditletter": "m",
        "newpageletter": "A",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|ngawaskeun|ngawaskeun}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|bit|bit}} sanggeus robah",
        "newsectionsummary": "/* $1 */ bagean anyar",
        "rc-enhanced-expand": "Témbongkeun rincian",
        "invalid-chunk-offset": "Opsét potongan teu valid",
        "img-auth-accessdenied": "Aksés ditolak",
        "img-auth-badtitle": "Teu bisa nyieun judul nu valid tina \"$1\".",
-       "img-auth-nologinnWL": "Anjeun teu asup log sarta \"$1\" teu dina daptar bodas.",
        "img-auth-nofile": "Berkas \"$1\" henteu aya.",
        "img-auth-isdir": "Anjeun nyoba ngaksés diréktori \"$1\".\nNgan aksés berkas wungkul nu diwenangkeun.",
        "img-auth-streaming": "Palidan \"$1\".",
        "filehist-comment": "Kamandang",
        "imagelinks": "Pamakéan berkas",
        "linkstoimage": "Ieu berkas dipaké ku {{PLURAL:$1|kaca|$1 kaca}} di handap:",
-       "linkstoimage-more": "Leuwih ti $1 {{PLURAL:$1|kaca|kaca}} nu maké ieu berkas.\nBéréndélan di handap némbongkeun {{PLURAL:$1|kaca kahiji|$1 kaca mimiti}} nu maké ieu berkas hungkul.\n[[Special:WhatLinksHere/$2|Béréndélan lengkepna]] ogé aya.",
+       "linkstoimage-more": "Leuwih ti $1 {{PLURAL:$1|kaca nu maké|kaca nu maké}}  ieu berkas.\nBéréndélan di handap némbongkeun {{PLURAL:$1|kaca kahiji|$1 kaca mimiti}} nu maké ieu berkas hungkul.\n[[Special:WhatLinksHere/$2|Béréndélan lengkepna]] ogé aya.",
        "nolinkstoimage": "Euweuh kaca anu maké ieu berkas.",
        "morelinkstoimage": "Témbong [[Special:WhatLinksHere/$1|tutumbu lianna]] ka ieu berkas.",
        "linkstoimage-redirect": "$1 (pangalihan berkas) $2",
        "allmessagesdefault": "Téks ti dituna",
        "allmessagescurrent": "Téks kiwari",
        "allmessagestext": "Ieu mangrupa daptar talatah sistim nu aya na spasi ngaran MediaWiki:.",
-       "allmessagesnotsupportedDB": "Kaca ieu teu dirojong sabab '''$wgUseDatabaseMessages''' pareum.",
+       "allmessages-not-supported-database": "Kaca ieu teu dirojong sabab '''$wgUseDatabaseMessages''' pareum.",
        "allmessages-filter-legend": "Ayakan",
        "allmessages-filter": "Saring ku kaayaan kustomisasi:",
        "allmessages-filter-unmodified": "Teu diropéa",
index aca767d..5cd8455 100644 (file)
        "tog-norollbackdiff": "Visa inte diff efter tillbakarullning",
        "tog-useeditwarning": "Varna mig om jag lämnar en redigeringssida med osparade ändringar",
        "tog-prefershttps": "Använd alltid en säker anslutning medan jag är inloggad",
+       "tog-showrollbackconfirmation": "Visa en bekräftelsedialog när man klickar på en tillbakarullningslänk",
        "underline-always": "Alltid",
        "underline-never": "Aldrig",
        "underline-default": "Webbläsarens eller utseendets standardinställning",
        "page_first": "första",
        "page_last": "sista",
        "histlegend": "Val av diff: markera i klickrutorna för att jämföra versioner och tryck enter eller knappen längst ner.<br />\nFörklaring: '''({{int:cur}})''' = skillnad mot senaste version; '''({{int:last}})''' = skillnad mot föregående version; '''{{int:minoreditletter}}''' = mindre ändring.",
-       "history-fieldset-title": "Sök efter sidversioner",
+       "history-fieldset-title": "Filtrera sidversioner",
        "history-show-deleted": "Endast raderade sidversioner",
        "histfirst": "äldsta",
        "histlast": "nyaste",
        "historysize": "({{PLURAL:$1|1 byte|$1 byte}})",
-       "historyempty": "(tom)",
+       "historyempty": "tom",
        "history-feed-title": "Versionshistorik",
        "history-feed-description": "Versionshistorik för denna sida på wikin",
        "history-feed-item-nocomment": "$1 den $2",
        "right-reupload-own": "Skriv över egna filer",
        "right-reupload-shared": "Skriv över delade filer lokalt",
        "right-upload_by_url": "Ladda upp en fil genom en webbadress",
-       "right-purge": "Rensa cachen för en sida utan att bekräfta",
+       "right-purge": "Rensa webbplatscachen för en sida",
        "right-autoconfirmed": "Påverkas inte av IP-baserade hastighetsgränser",
        "right-bot": "Behandlas som en automatisk process",
        "right-nominornewtalk": "Mindre ändringar på diskussionssidor ger inte besked om nya meddelanden",
        "action-changetags": "lägg till och ta bort godtyckliga märken på individuella sidversioner och loggposter",
        "action-deletechangetags": "radera märken från databasen",
        "action-purge": "rensa denna sida",
+       "action-apihighlimits": "använda högre gränser i API-frågor",
+       "action-autoconfirmed": "inte påverkas av IP-baserade hastighetsgränser",
+       "action-bigdelete": "radera sidor med stor historik",
+       "action-blockemail": "blockera användare från att skicka e-post",
+       "action-bot": "behandlas som en automatisk process",
+       "action-editprotected": "redigera skyddade sidor som \"{{int:protect-level-sysop}}\"",
+       "action-editsemiprotected": "redigera skyddade sidor som \"{{int:protect-level-autoconfirmed}}\"",
+       "action-editinterface": "redigera användargränssnittet",
+       "action-editusercss": "redigera andra användares CSS-filer",
+       "action-edituserjson": "redigera andra användares JSON-filer",
+       "action-edituserjs": "redigera andra användares JavaScript-filer",
+       "action-editsitecss": "redigera CSS för hela webbplatsen",
+       "action-editsitejson": "redigera JSON för hela webbplatsen",
+       "action-editsitejs": "redigera JavaScript för hela webbplatsen",
+       "action-editmyusercss": "redigera dina egna CSS-filer",
+       "action-editmyuserjson": "redigera dina egna JSON-filer",
+       "action-editmyuserjs": "redigera dina egna JavaScript-filer",
+       "action-viewsuppressed": "se sidversioner som dolts från alla användare",
+       "action-hideuser": "blockera ett användarnamn och dölj det från allmänheten",
+       "action-ipblock-exempt": "kringgå IP-blockeringar, autoblockeringar och IP-intervallsblockeringar",
+       "action-unblockself": "avblockera dig själv",
+       "action-noratelimit": "inte påverkas av hastighetsgränser",
+       "action-reupload-own": "skriva över befintliga filer som du själv har laddat upp",
+       "action-nominornewtalk": "förhindra att mindre ändringar på diskussionssidor ger besked om nya meddelanden",
+       "action-markbotedits": "markera tillbakarullningar som robotändringar",
+       "action-patrolmarks": "se markeringar av opatrullerade ändringar i senaste ändringarna",
+       "action-override-export-depth": "exportera sidor inklusive länkade sidor till ett djup på 5",
+       "action-suppressredirect": "inte skapa omdirigeringar från ursprungssidan vid sidflyttning",
        "nchanges": "$1 {{PLURAL:$1|ändring|ändringar}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|sedan senaste besöket}}",
        "enhancedrc-history": "historik",
        "rcfilters-savedqueries-already-saved": "Dessa filter har redan sparats. Ändra dina inställningar för att skapa ett nytt sparat filter.",
        "rcfilters-restore-default-filters": "Återställ standardfilter",
        "rcfilters-clear-all-filters": "Rensa alla filter",
-       "rcfilters-show-new-changes": "Visa de nyaste ändringarna",
+       "rcfilters-show-new-changes": "Visa de nyaste ändringarna sedan $1",
        "rcfilters-search-placeholder": "Filtrera senaste ändringar (använd menyn eller sök efter filternamn)",
        "rcfilters-invalid-filter": "Ogiltigt filter",
        "rcfilters-empty-filter": "Inga aktiva filter. Alla bidrag visas.",
        "rcfilters-filter-editsbyself-description": "Dina egna bidrag.",
        "rcfilters-filter-editsbyother-label": "Ändringar av andra",
        "rcfilters-filter-editsbyother-description": "Alla ändringar förutom dina egna.",
-       "rcfilters-filtergroup-userExpLevel": "Användarregistrering och -erfarenhet",
+       "rcfilters-filtergroup-user-experience-level": "Användarregistrering och -erfarenhet",
        "rcfilters-filter-user-experience-level-registered-label": "Registrerade",
        "rcfilters-filter-user-experience-level-registered-description": "Inloggade redigerare.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Oregistrerade",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Filtret \"Mindre redigering\" är i konflikt med en eller flera ändringstypfilter, eftersom vissa ändringstyper inte kan betecknas som \"mindre\". Filtren som är i konflikt är markerade i området med aktiva filter ovan.",
        "rcfilters-hideminor-conflicts-typeofchange": "Vissa ändringstyper kan inte betecknas som \"mindre\", så detta filter är i konflikt med följande ändringstypfilter: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Detta ändringstypfilter är i konflikt med filtret \"Mindre ändringar\". Vissa ändringstyper kan inte betecknas som \"mindre\".",
-       "rcfilters-filtergroup-lastRevision": "Senaste versioner",
+       "rcfilters-filtergroup-lastrevision": "Senaste versioner",
        "rcfilters-filter-lastrevision-label": "Senaste version",
        "rcfilters-filter-lastrevision-description": "Endast senaste ändringen av en sida.",
        "rcfilters-filter-previousrevision-label": "Inte den senaste versionen",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 bevakande {{PLURAL:$1|användare|användare}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte}} efter ändring",
        "newsectionsummary": "/* $1 */ nytt avsnitt",
        "rc-enhanced-expand": "Visa detaljer",
        "img-auth-nopathinfo": "Sökvägsinformation saknas.\nDin server måste vara inställd för att ge variablerna REQUEST_URI och/eller PATH_INFO.\nOm den är det, försök att aktivera $wgUsePathInfo.\n[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization Se bildbehörighet.]",
        "img-auth-notindir": "Den önskade sökvägen finns inte i den inställda uppladdningskatalogen.",
        "img-auth-badtitle": "Kan inte skapa en giltig titel från \"$1\"",
-       "img-auth-nologinnWL": "Du är inte inloggad och \"$1\" finns inte i vitlistan.",
        "img-auth-nofile": "Filen \"$1\" finns inte.",
        "img-auth-isdir": "Du försöker få åtkomst till en katalog \"$1\".\nEndast åtkomst till filer är tillåten.",
        "img-auth-streaming": "Strömmar \"$1\".",
        "delete-confirm": "Radera \"$1\"",
        "delete-legend": "Radera",
        "historywarning": "<strong>Varning:</strong> Sidan du håller på att radera har en historik med $1 {{PLURAL:$1|version|versioner}}:",
-       "historyaction-submit": "Visa",
+       "historyaction-submit": "Visa sidversioner",
        "confirmdeletetext": "Du håller på att ta bort en sida med hela dess historik.\nBekräfta att du förstår vad du håller på med och vilka konsekvenser detta leder till, och att du följer [[{{MediaWiki:Policy-url}}|riktlinjerna]].",
        "actioncomplete": "Genomfört",
        "actionfailed": "Handlingen misslyckades",
        "deleting-backlinks-warning": "<strong>Varning:</strong>\n[[Special:WhatLinksHere/{{FULLPAGENAME}}|Andra sidor]] länkar till eller inkluderar sidan som du är på väg att radera.",
        "deleting-subpages-warning": "<strong>Varning:</strong> Sidan du håller på att radera har [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|en undersida|$1 undersidor|51=över 50 undersidor}}]].",
        "rollback": "Rulla tillbaka ändringar",
+       "rollback-confirmation-confirm": "Var god bekräfta:",
+       "rollback-confirmation-yes": "Rulla tillbaka",
+       "rollback-confirmation-no": "Avbryt",
        "rollbacklink": "rulla tillbaka",
        "rollbacklinkcount": "rulla tillbaka $1 {{PLURAL:$1|redigering|redigeringar}}",
        "rollbacklinkcount-morethan": "rulla tillbaka mer än $1 {{PLURAL:$1|redigering|redigeringar}}",
        "revertpage": "Återställde redigeringar av  [[Special:Contributions/$2|$2]] ([[User talk:$2|användardiskussion]]) till senaste versionen 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}}.",
-       "rollback-success-notify": "Återställde ändringar av $1;\nändrade tillbaka till senaste sidversion av $2. [$3 Visa ändringar]",
        "sessionfailure-title": "Sessionsfel",
        "sessionfailure": "Någonting med din inloggningssession är på tok;\ndin begärda åtgärd har avbrutits för att förhindra att någon kapar din session.\nSkicka formuläret igen.",
        "changecontentmodel": "Ändra innehållsmodell för en sida",
        "mycontris": "Bidrag",
        "anoncontribs": "Bidrag",
        "contribsub2": "För {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "För {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "Användarkontot \"$1\" är inte registrerat.",
        "negative-namespace-not-supported": "Namnrymder med negativa värden stöds inte.",
        "nocontribs": "Inga ändringar som motsvarar dessa kriterier hittades.",
        "blocklist-userblocks": "Dölj kontoblockeringar",
        "blocklist-tempblocks": "Dölj tillfälliga blockeringar",
        "blocklist-addressblocks": "Dölj enskilda IP-blockeringar",
+       "blocklist-type": "Typ:",
+       "blocklist-type-opt-all": "Alla",
+       "blocklist-type-opt-sitewide": "Hela webbplatsen",
+       "blocklist-type-opt-partial": "Delvist",
        "blocklist-rangeblocks": "Dölj intervallblockeringar",
        "blocklist-timestamp": "Tidsstämpel",
        "blocklist-target": "Mål",
        "blocklist-editing-page": "sidor",
        "blocklist-editing-ns": "namnrymder",
        "ipblocklist-empty": "Listan över blockeringar är tom.",
-       "ipblocklist-no-results": "Den angivna IP-adressen eller användaren är inte blockerad.",
+       "ipblocklist-no-results": "Inga blockeringar som stämmer överens med den angivna IP-adressen eller användarnamnet hittades.",
        "blocklink": "blockera",
        "unblocklink": "ta bort blockering",
        "change-blocklink": "ändra blockering",
+       "empty-username": "(inget tillgängligt användarnamn)",
        "contribslink": "bidrag",
        "emaillink": "skicka e-post",
        "autoblocker": "Automatisk blockerad eftersom din IP-adress nyligen använts av \"[[User:$1|$1]]\".\nMotiveringen som angavs för blockeringen av $1 var: \"$2\".",
        "allmessagesdefault": "Standardtext",
        "allmessagescurrent": "Nuvarande text",
        "allmessagestext": "Detta är en lista över alla systemmeddelanden i namnrymden MediaWiki.\nBesök [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] eller [https://translatewiki.net translatewiki.net] om du vill bidra till översättningen av MediaWiki.",
-       "allmessagesnotsupportedDB": "Den här sidan kan inte användas eftersom '''$wgUseDatabaseMessages''' är avstängd.",
+       "allmessages-not-supported-database": "Den här sidan kan inte användas eftersom '''$wgUseDatabaseMessages''' är avstängd.",
        "allmessages-filter-legend": "Filtrera",
        "allmessages-filter": "Filtrera efter anpassningsgrad:",
        "allmessages-filter-unmodified": "Ej modifierad",
        "confirm-unwatch-top": "Ta bort denna sida från din bevakningslista?",
        "confirm-rollback-button": "OK",
        "confirm-rollback-top": "Återställ redigeringar på denna sida?",
+       "confirm-rollback-bottom": "Denna åtgärd kommer rulla tillbaka de markerade ändringarna på denna sida direkt.",
        "confirm-mcrrestore-title": "Återställ en sidversion",
        "confirm-mcrundo-title": "Ångra en ändring",
        "mcrundofailed": "Misslyckades att ångra",
        "passwordpolicies-policyflag-forcechange": "måste ändras vid inloggning",
        "passwordpolicies-policyflag-suggestchangeonlogin": "föreslå ändring vid inloggning",
        "easydeflate-invaliddeflate": "Innehåll som tillhandahålls är inte helt komprimerat",
-       "unprotected-js": "Av säkerhetsskäl kan inte JavaScript läsas in från oskyddade sidor. Skapa endast JavaScript i namnrymden MediaWiki: eller som en användarundersida."
+       "unprotected-js": "Av säkerhetsskäl kan inte JavaScript läsas in från oskyddade sidor. Skapa endast JavaScript i namnrymden MediaWiki: eller som en användarundersida.",
+       "userlogout-continue": "Om du vill logga ut, var god [$1 fortsätt till utloggningssidan].",
+       "userlogout-sessionerror": "Utloggning misslyckades p.g.a. sessionsfel. Var god [$1 försök igen]."
 }
index 7857def..d8ff5dd 100644 (file)
@@ -21,7 +21,8 @@
                        "Muddyb",
                        "Fitoschido",
                        "Rance",
-                       "Vlad5250"
+                       "Vlad5250",
+                       "Yasen igra"
                ]
        },
        "tog-underline": "Wekea mstari viungo:",
@@ -46,7 +47,7 @@
        "tog-enotifminoredits": "Pia nitumie barua pale mabadiliko ya ukurasa yanapokuwa madogo tu.",
        "tog-enotifrevealaddr": "Onyesha anwani ya barua pepe yangu katika barua pepe za taarifa",
        "tog-shownumberswatching": "Onyesha idadi ya watumiaji waangalizi",
-       "tog-oldsig": "Sahihi iliyopo:",
+       "tog-oldsig": "Sahihi iliyopo yenu:",
        "tog-fancysig": "Weka sahihi tu (bila kujiweka kiungo yenyewe)",
        "tog-uselivepreview": "Tumia kihakikio cha papohapo",
        "tog-forceeditsummary": "Nishtue pale ninapoingiza muhtasari mtupu wa kuhariri",
        "nstab-template": "Kigezo",
        "nstab-help": "Msaada",
        "nstab-category": "Jamii",
+       "mainpage-nstab": "Mwanzo",
        "nosuchaction": "Kitendo hiki hakipo",
        "nosuchactiontext": "Haiwezikani kutenda kitendo kilichoandikwa kwenye KISARA.\nLabda ulikosea kuandika KISARA, au kiungo ulichofuata ina kasoro.\nAu labda kuna hitilafu kwenye programu inayotumika na {{SITENAME}}.",
        "nosuchspecialpage": "Ukurasa maalum huu hakuna",
        "minoredit": "Haya ni mabadiliko madogo",
        "watchthis": "Fuatilia ukurasa huu",
        "savearticle": "Hifadhi ukurasa",
+       "savechanges": "Hifadhi mabadiliko",
        "preview": "Hakiki",
        "showpreview": "Onyesha hakikisho la mabadiliko",
        "showdiff": "Onyesha mabadiliko",
        "recentchanges-label-plusminus": "Ukubwa ukurasa kubadilishwa na hii idadi ya baiti",
        "recentchanges-legend-heading": "<strong>Simulizi:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (pia tazama [[Special:NewPages|orodha ya kurasa mpya]])",
+       "rcfilters-filter-editsbyself-description": "Michango yenu.",
        "rcnotefrom": "Hapo chini {{PLURAL:$5|is the change|yaonekana mabadiliko}} tangu <strong>$3,$4</strong> (hadi <strong>$1</strong>tunaonyesha).",
        "rclistfrom": "Onyesha mabadiliko mapya kuanzia $3 $2",
        "rcshowhideminor": "$1 mabadiliko madogo",
        "minoreditletter": "d",
        "newpageletter": "P",
        "boteditletter": "r",
-       "number_of_watching_users_pageview": "[idadi ya {{PLURAL:$1|watumiaji}} wanaoufuatilia ni $1]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} baada ya mabadiliko",
        "newsectionsummary": "/* $1 */ mjadala mpya",
        "rc-enhanced-expand": "Onyesha maelezo",
        "uploadstash-refresh": "Zimua orodha ya mafaili",
        "img-auth-accessdenied": "Ruksa imekataliwa",
        "img-auth-badtitle": "Haiwezi kuunda mada halali kutoka \"$1\".",
-       "img-auth-nologinnWL": "Haujaingia na \"$1\" haiko kwa orodha ya walioidhinishwa.",
        "img-auth-nofile": "Hakuna faili la \"$1\".",
        "img-auth-isdir": "",
        "img-auth-streaming": "Inapeperusha \"$1\".",
        "contributions": "Michango ya {{GENDER:$1|mtumiaji}}",
        "contributions-title": "Michango ya mtumiaji $1",
        "mycontris": "Michango",
+       "anoncontribs": "Michango",
        "contribsub2": "Kwa {{GENDER:$3|$1}} ($2)",
        "nocontribs": "Mabadiliko yanayolingana na vigezo vilivyoulizwa hayakupatikana.",
        "uctop": "ya kisasa",
        "whatlinkshere-hidelinks": "$1 viungo",
        "whatlinkshere-hideimages": "Viungo vya faili $1",
        "whatlinkshere-filters": "Machujio",
+       "whatlinkshere-submit": "Nenda",
        "block": "Kumzuia mtumiaji",
        "unblock": "Kuacha kumzuia mtumiaji",
        "blockip": "Zuia mtumiaji",
        "allmessagesdefault": "Ujumbe uliopo bidhaa pepe",
        "allmessagescurrent": "Ujumbe unapo sasa hivi",
        "allmessagestext": "Hii ni orodha ya jumbe za mfumo zilizopo katika eneo la MediaWiki.\nUkitaka kusaidia kazi ya kutohoa MediaWiki yote katika lugha nyingi, tafadhali uende tovuti ya [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Kutohoa MediaWiki Kwenye Lugha Nyingi] na [https://translatewiki.net translatewiki.net].",
-       "allmessagesnotsupportedDB": "Ukurasa huu hauwezi kutumika kwa sababu '''$wgUseDatabaseMessages''' imelemazwa.",
+       "allmessages-not-supported-database": "Ukurasa huu hauwezi kutumika kwa sababu '''$wgUseDatabaseMessages''' imelemazwa.",
        "allmessages-filter-legend": "Chuja",
        "allmessages-filter": "Zichujwe kwa hali ya kutengenezwa:",
        "allmessages-filter-unmodified": "Zisizotengenezwa",
        "imgmultipagenext": "ukurasa ujao →",
        "imgmultigo": "Nenda!",
        "imgmultigoto": "Uende kwenye ukurasa wa $1",
+       "img-lang-go": "Enda",
        "ascending_abbrev": "pand",
        "descending_abbrev": "shuk",
        "table_pager_next": "Ukurasa ujao",
        "version-software-version": "Toleo",
        "version-entrypoints-header-url": "KISARA Kioneshi Sanifu Raslimali",
        "redirect-submit": "Nenda",
+       "redirect-file": "Jina la faili",
        "fileduplicatesearch": "Tafuta mafaili ya nakili",
        "fileduplicatesearch-summary": "Kutafuta mafaili ya nakili kwa kuzingatia thamani za reli.",
        "fileduplicatesearch-filename": "Jina la faili:",
        "tag-filter-submit": "Chuja",
        "tags-title": "Tagi",
        "tags-description-header": "Maelezo kamili ya maana",
+       "tags-active-yes": "Ndiyo",
+       "tags-active-no": "Siyo",
        "tags-edit": "hariri",
        "tags-hitcount": "{{PLURAL:$1|badiliko|mabadiliko}} $1",
        "comparepages": "Linganisha kurasa",
index 2b789cd..0fe4b17 100644 (file)
        "minoreditletter": "d",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|dowajůncy pozůr užytkowńik|dowajůncych pozůr užytkowńikůw}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|bajt|bajty|bajtōw}} po pōmianie",
        "newsectionsummary": "/* $1 */ nowo tajla",
        "rc-enhanced-expand": "Pokoż szczygůły",
        "allmessagesdefault": "Tekst důmyślny",
        "allmessagescurrent": "Tekst uobecny",
        "allmessagestext": "Uoto lista wšyjstkych kůmůńikatůw systymowych dostympnych w přestřyńi mjan MedjaWiki.\nUodwjydź [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Tuůmačyńy MediaWiki] a tyž [https://translatewiki.net translatewiki.net] kejbyś chćou učestńičyć w tuůmačyńu uoprůgramowańo MediaWiki.",
-       "allmessagesnotsupportedDB": "Ta zajta ńy može być užyta, bez tůž co zmjynna '''$wgUseDatabaseMessages''' je wůuůnčůno.",
+       "allmessages-not-supported-database": "Ta zajta ńy može być užyta, bez tůž co zmjynna '''$wgUseDatabaseMessages''' je wůuůnčůno.",
        "thumbnail-more": "Zwjynksz",
        "filemissing": "Ńyma pliku.",
        "thumbnail_error": "Feler při gynerowańu mińatury: $1",
index 5aac8b4..ae882f2 100644 (file)
        "rcfilters-filtergroup-changetype": "மாற்ற வகை",
        "rcfilters-filter-pageedits-label": "பக்க தொகுப்புகள்",
        "rcfilters-filter-newpages-label": "பக்க உருவாக்கங்கள்",
-       "rcfilters-filtergroup-lastRevision": "அண்மைய திருத்தங்கள்",
+       "rcfilters-filtergroup-lastrevision": "அண்மைய திருத்தங்கள்",
        "rcfilters-filter-lastrevision-label": "அண்மைய திருத்தம்",
        "rcfilters-filter-excluded": "தவிர்க்கப்பட்டது",
        "rcnotefrom": "கீழே காணப்படுவது <strong>$3, $4</strong> இலிருந்து செய்யப்பட்ட (<strong>$1</strong> வரைக் காட்டப்பட்டுள்ளது) {{PLURAL:$5|மாற்றமாகும்.|மாற்றங்களாகும்.}}",
        "minoreditletter": "சி",
        "newpageletter": "பு",
        "boteditletter": "தா",
-       "number_of_watching_users_pageview": "[இப்பக்க்த்தை {{PLURAL:$1|ஒரு பயனர் பார்கிறார்|$1 பயனர்கள் பார்கிறார்கள்}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|பைட்டு|பைட்டுகள்}} -மாற்றத்திற்குப் பிறகு",
        "newsectionsummary": "/* $1 */ புதிய பகுதி",
        "rc-enhanced-expand": "விவரத்தை காட்டு",
        "img-auth-nopathinfo": "PATH_INFO காணவில்லை.\nஉங்கள் வழங்கி இந்தத் தகவலை அனுப்ப அமைக்கப்படவில்லை\nஇது சிஜிஐ (CGI)- அடிப்படையிலானதாகவோ img_auth-ஐ ஆதரக்காததாகவோ இருக்கலாம் .\nபார்க்கவும் https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "கோரிய பாதை இந்த குறிப்பிட்ட தகவலேற்று கோப்புறையில் இல்லை.",
        "img-auth-badtitle": "செல்லத்தக்க தலைப்பு \"$1\" ஐ கட்ட இயலவில்லை.",
-       "img-auth-nologinnWL": "நீங்கள் புகுபதிகை செய்யவில்லை, மேலும் \"$1\"  அனுமதிக்கப்பெற்ற பட்டியலில் இல்லை",
        "img-auth-nofile": "கோப்பு \"$1\" இல்லை.",
        "img-auth-isdir": "நீங்கள் ஒரு \"$1\" என்னும் கோப்பு அடைவை (டைரக்டரியை) அணுக முயல்கிறீர்கள். கோப்பை மட்டுமே அணுக அனுமதிக்கப்படும்.",
        "img-auth-streaming": "தொடரோடி \"$1\".",
        "allmessagesdefault": "இயல்பிருப்பு உரை",
        "allmessagescurrent": "தற்போதைய உரை",
        "allmessagestext": "இது மீடியாவிக்கி பெயர்வெளியிலுள்ள எல்லா முறைமை தகவல்களினதும் பட்டியலாகும்.\nமொழிபெயர்ப்பில் உதவ விரும்பின் அருள்கூர்ந்து [https://translatewiki.net பீட்டாவிக்கி], [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation மீடியாவிக்கி மொழியாக்க]  தளங்களுக்குச் செல்லவும்.",
-       "allmessagesnotsupportedDB": "'''$wgUseDatabaseMessages''' முடக்கப்பட்டுள்ளப் படியால் இப்பக்கததை பயன்படுத்த முடியாது.",
+       "allmessages-not-supported-database": "'''$wgUseDatabaseMessages''' முடக்கப்பட்டுள்ளப் படியால் இப்பக்கததை பயன்படுத்த முடியாது.",
        "allmessages-filter-legend": "வடிகட்டி",
        "allmessages-filter": "தனிப்பயனாக்கத்தின்படி வடிகட்டு.",
        "allmessages-filter-unmodified": "மாற்றம் செய்யப்படாதது",
index 70b956d..9d80d0c 100644 (file)
        "rcfilters-filter-newpages-label": "Ps’rux zngazyan",
        "rcfilters-filter-categorization-label": "Pintbcyan na sinbahan",
        "rcfilters-filter-logactions-label": "Miru’ sa bbiru’",
-       "rcfilters-filtergroup-lastRevision": "Spzyang giqas na sinnbah",
+       "rcfilters-filtergroup-lastrevision": "Spzyang giqas na sinnbah",
        "rcnotefrom": "Kwara’ nyux kyahu’ ka {{PLURAL:$5|yasa quw}} qaniy ga, aring sa <strong>$3 $4</strong> ga, yasa pinsbah niya’ krayryax (ana pzyux ga ini’ hzinas sa  <strong>$1</strong>).",
        "rclistfrom": "Inkahul misan sinbahan sa $2, $3",
        "rcshowhideminor": "$1 mszik sa ssr’tun",
index 82a5cdd..cc67fdb 100644 (file)
        "rcfilters-filter-editsbyself-description": "ಇರೆನ ಸ್ವಂತದ ಕಾಣಿಕೆಲು",
        "rcfilters-filter-editsbyother-label": "ಇತರೆರ್ ಮಲ್ತಿನ ಬದಲಾವಣೆಲು",
        "rcfilters-filter-editsbyother-description": "ಇರೆನ ಸ್ವಂತದ ಬುಡುದು, ಮಾತಾ ಬದಲಾವಣೆಲು",
-       "rcfilters-filtergroup-userExpLevel": "ಬಳಕೆದಾರೆ ನೊಂದಣಿ ಬೊಕ ಅನುಭವ",
+       "rcfilters-filtergroup-user-experience-level": "ಬಳಕೆದಾರೆ ನೊಂದಣಿ ಬೊಕ ಅನುಭವ",
        "rcfilters-filter-user-experience-level-registered-label": "ನೋಂದಾಯಿನ",
        "rcfilters-filter-user-experience-level-registered-description": "ಉಳಗಮನ ಆತಿನ ಸಂಪಾದಕೆರ್",
        "rcfilters-filter-user-experience-level-unregistered-label": "ಅನೊಂದಾಯಿತ",
        "rcfilters-hideminor-conflicts-typeofchange-global": "\"ಕಿನ್ಯ ಸಂಪಾದಿಲು\" ಅರಿಪೆ ಒಂಜಿ ಇಜಿಂಡ ಹೆಚ್ಚಿನ ಅರಿಪೆಲ ಒಟ್ಟುಗು ಸಂಘರ್ಷೊಡು ಉಂಡು, ಕಾರಣ ಕೆಲ ಬಗೆತ ಬದಲಾವಣೆಲೆನ್ \" ಕಿನ್ಯ \" ಇಂದ್ ಪಣೆರೆ ಆಪುಜಿ. ಸಂಘರ್ಷದ ಅರಿಪೆಲೆನ್,  ಮಿತ್ತ್'ದ  ಸಕ್ರಿಯ ಅರಿಪೆಲೆನ ಜಾಗೊಡು ಗುರುತು ಮಲ್ಪುಂಡು.",
        "rcfilters-hideminor-conflicts-typeofchange": " ಕೆಲ ಬಗೆತ ಬದಲಾವಣೆಲೆನ್ \" ಕಿನ್ಯ \" ಇಂದ್ ಪಣೆರೆ ಆಪುಜಿ. ಅಂಚಾದ್  ಈ  ಅರಿಪೆ,  ಈ ದುಂಬುದ  $1 ಅರಿಪೆಲೆನ ಬದಲಾವಣೆಡ್ ಸಂಘರ್ಷ ಮಲ್ಪುಂಡು:",
        "rcfilters-typeofchange-conflicts-hideminor": "ಈ ಬಗೆತ  ಅರಿಪೆಲೆನ ಬದಲಾವಣೆ \"ಕಿನ್ಯ ಸಂಪಾದಿಲು\" ಅರಿಪೆದ ಒಟ್ಟುಗು ಸಂಘರ್ಷ ಮಲ್ಪುಂಡು: ಕೆಲ ಬಗೆತ ಬದಲಾವಣೆಲೆನ್ \" ಕಿನ್ಯ \" ಇಂದ್ ಪಣೆರೆ ಆಪುಜಿ.",
-       "rcfilters-filtergroup-lastRevision": "ಇಂಚೊದ ಪಡಿಪಾಟೊಲು",
+       "rcfilters-filtergroup-lastrevision": "ಇಂಚೊದ ಪಡಿಪಾಟೊಲು",
        "rcfilters-filter-lastrevision-label": "ಇಂಚೊದ ಪಡಿಪಾಟ",
        "rcfilters-filter-lastrevision-description": "ಒಂಜಿ ಪುಟೊಕು ಅತಿ ಇಂಚೊದ ಬದಲಾವಣೆ ಮಾತ್ರಾ",
        "rcfilters-filter-previousrevision-label": "ಇಂಚೊದ ಪಡಿಪಾಟ ಅತ್ತ್",
        "minoreditletter": "ಕಿ",
        "newpageletter": "ಪೊ",
        "boteditletter": "ಬಾ",
-       "number_of_watching_users_pageview": "[$1 ತೂಪಿನ {{PLURAL:$1|ಬಳಕೆದಾರೆ|ಬಳಕೆದಾರೆರ್}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|ಬೈಟ್|ಬೈಟ್‍ಲು}}ಬದಲಾವಣೆಡ್ದ್ ಬುಕ್ಕೊ",
        "newsectionsummary": "\n/* $1 */ಪೊಸ ವಿಭಾಗ",
        "rc-enhanced-expand": "ವಿವರೊಲೆನ್ ತೊಜಾವ್",
index c79eead..886e81f 100644 (file)
@@ -27,7 +27,8 @@
                        "WP MANIKHANTA",
                        "SrihariThalla",
                        "Fitoschido",
-                       "Pavan santhosh.s"
+                       "Pavan santhosh.s",
+                       "MSG17"
                ]
        },
        "tog-underline": "లంకె క్రీగీత:",
        "mytalk": "చర్చ",
        "anontalk": "చర్చ",
        "navigation": "మార్గసూచీ",
-       "and": "&#32;మరియు",
+       "and": ",&#32;",
        "faq": "తరచూ అడిగే ప్రశ్నలు",
        "actions": "పనులు",
        "namespaces": "పేరుబరులు",
        "permissionserrors": "అనుమతి లోపం",
        "permissionserrorstext": "కింద పేర్కొన్న {{PLURAL:$1|కారణం|కారణాల}} మూలంగా, ఆ పని చెయ్యడానికి మీకు అనుమతిలేదు:",
        "permissionserrorstext-withaction": "ఈ క్రింది {{PLURAL:$1|కారణం|కారణాల}} వల్ల, $2 అనుమతి మీకు లేదు:",
-       "recreate-moveddeleted-warn": "<strong>à°¹à±\86à°\9aà±\8dà°\9aà°°à°¿à°\95: à°\87à°\82à°¤à°\95à±\81 à°®à±\81à°¨à±\81à°ªà±\81 à°\92à°\95సారి à°¤à±\8aà°²à°\97à°¿à°\82à°\9aà°¿à°¨ à°ªà±\87à°\9cà±\80ని à°®à°³à±\8dà°²à±\80 à°¸à±\83à°·à±\8dà°\9fà°¿à°¦à±\8dదామని à°®à±\80à°°à±\81 à°ªà±\8dరయతà±\8dనిసà±\8dà°¤à±\81à°¨à±\8dనారà±\81.</strong>\n\nà°\88 à°ªà±\87à°\9cà±\80à°ªà±\88 à°®à°¾à°°à±\8dà°ªà±\81à°²à±\81 à°\9aà±\87à°¸à±\87à°®à±\81à°\82à°¦à±\81, à°\85వి à°\87à°\95à±\8dà°\95à°¡ à°\89à°\82à°¡à°¤à°\97ినవà±\87నా à°\95ాదా à°\85ని à°\92à°\95సారి à°\86à°²à±\8bà°\9aà°¿à°\82à°\9aà°\82à°¡à°¿.\nà°®à±\80 à°¸à±\8cలభà±\8dà°¯à°\82 à°\95à±\8aà°°à°\95à±\81 à°\88 à°ªà±\87à°\9cà±\80 à°¯à±\8aà°\95à±\8dà°\95 à°¤à±\8aà°²à°\97à°¿à°\82à°ªà±\81, à°¤à°°à°²à°¿à°\82à°ªà±\81 à°\9aà°¿à°\9fà±\8dà°\9fాలనà±\81 à°\87à°\95à±\8dà°\95à°¡ à°\87à°\9aà±\8dà°\9aà°¾à°\82:",
-       "moveddeleted-notice": "à°\88 à°ªà±\87à°\9cà±\80ని à°¤à±\8aà°²à°\97à°¿à°\82à°\9aారà±\81.\nà°\88 à°ªà±\87à°\9cà±\80 à°¯à±\8aà°\95à±\8dà°\95 à°¤à±\8aà°²à°\97à°¿à°\82à°ªà±\81, à°¸à°\82à°°à°\95à±\8dà°·à°£, à°¤à°°à°²à°¿à°\82à°ªà±\81 చిట్టాను క్రింద ఇచ్చాం.",
+       "recreate-moveddeleted-warn": "<strong>హెచ్చరిక: ఇంతకు మునుపు ఒకసారి తొలగించిన పేజీని మళ్లీ సృష్టిద్దామని మీరు ప్రయత్నిస్తున్నారు.</strong>\n\nఈ పేజీపై మార్పులు చేసేముందు, అవి ఇక్కడ ఉండతగినవేనా కాదా అని ఒకసారి ఆలోచించండి.\nమీ సౌలభ్యం కొరకు ఈ పేజీ తొలగింపు, తరలింపు చిట్టాలను ఇక్కడ ఇచ్చాం:",
+       "moveddeleted-notice": "à°\88 à°ªà±\87à°\9cà±\80ని à°¤à±\8aà°²à°\97à°¿à°\82à°\9aారà±\81.\nసమాà°\9aారానిà°\95à±\88 à°\88 à°ªà±\87à°\9cà±\80 à°¤à±\8aà°²à°\97à°¿à°\82à°ªà±\81, à°¸à°\82à°°à°\95à±\8dà°·à°£, à°¤à°°à°²à°¿à°\82à°ªà±\81à°² చిట్టాను క్రింద ఇచ్చాం.",
        "moveddeleted-notice-recent": "సారీ, ఈ పేజీని ఈమధ్యే తొలగించారు (గత 24 గంటల్లో).\nఈ పేజీకి సంబంధించిన తొలగింపు, సంరక్షణ, తరలింపు లాగ్‌లను కింద ఇచ్చాం.",
        "log-fulllog": "పూర్తి చిట్టాని చూడండి",
        "edit-hook-aborted": "కొక్కెం ఈ మార్పుని విచ్ఛిన్నం చేసింది.\nఅది ఎటువంటి వివరణా ఇవ్వలేదు.",
        "editwarning-warning": "ఈ పేజీని వదిలివెళ్ళడం వల్ల మీరు చేసిన మార్పులను కోల్పోయే అవకాశం ఉంది.\nమీరు లాగిన్ అయివుంటే, ఈ హెచ్చరికని మీ అభిరుచులలోని \"{{int:prefs-editing}}\"  విభాగంలో అచేతనం చేసుకోవచ్చు.",
        "editpage-notsupportedcontentformat-title": "పాఠ్యపు ఆకృతికి మద్దతు లేదు",
        "editpage-notsupportedcontentformat-text": "$2 పాఠ్యపు మోడల్, పాఠ్యపు ఆకృతి $1 కి మద్దతు ఇవ్వదు",
+       "slot-name-main": "ప్రధాన",
        "content-model-wikitext": "వికీపాఠ్యం",
        "content-model-text": "సాదా పాఠ్యం",
        "content-model-javascript": "జావాస్క్రిప్ట్",
        "page_first": "మొదటి",
        "page_last": "చివరి",
        "histlegend": "తేడా ఎంపిక: సంచికల యొక్క రేడియో బాక్సులను ఎంచుకొని ఎంటర్‌ నొక్కండి, లేదా పైన/ కింద ఉన్న మీటను నొక్కండి.<br />\nసూచిక: <strong>({{int:cur}})</strong> = ప్రస్తుత సంచికతో కల తేడాలు, <strong>({{int:last}})</strong> = ఇంతకు ముందరి సంచికతో గల తేడాలు, <strong>{{int:minoreditletter}}</strong> = చిన్న మార్పు",
-       "history-fieldset-title": "à°\95à±\82à°°à±\8dà°ªà±\81à°² à°\95à±\8bà°¸à°\82 à°µà±\86à°¤à°\95à°\82à°¡à°¿",
+       "history-fieldset-title": "à°\95à±\82à°°à±\8dà°ªà±\81à°² à°µà°¡à°ªà±\8bà°¤",
        "history-show-deleted": "తొలగించినవి మాత్రమే",
        "histfirst": "అతి పాతవి",
        "histlast": "సరికొత్త",
        "historysize": "({{PLURAL:$1|ఒక బైటు|$1 బైట్లు}})",
-       "historyempty": "(ఖాళీ)",
+       "historyempty": "ఖాళీ",
        "history-feed-title": "కూర్పుల చరిత్ర",
        "history-feed-description": "ఈ పేజీకి వికీలో కూర్పుల చరిత్ర",
        "history-feed-item-nocomment": "$2 న $1",
        "mergelog": "విలీనాల చిట్టా",
        "revertmerge": "విలీనాన్ని రద్దుచెయ్యి",
        "mergelogpagetext": "ఒక పేజీ చరితాన్ని మరో పేజీ చరితం లోకి ఇటీవల చేసిన విలీనాల జాబితా ఇది.",
-       "history-title": "\"$1\" à°¯à±\8aà°\95à±\8dà°\95 à°\95à±\82à°°à±\8dà°ªà±\81à°² à°\9aà°°à°¿à°¤à±\8dà°°",
-       "difference-title": "\"$1\" à°¯à±\8aà°\95à±\8dà°\95 à°\95à±\82à°°à±\8dà°ªà±\81à°² à°®à°§à±\8dà°¯ à°¤à±\87డాలà±\81",
+       "history-title": "\"$1\" కూర్పుల చరిత్ర",
+       "difference-title": "\"$1\" కూర్పుల మధ్య తేడాలు",
        "difference-title-multipage": "\"$1\", \"$2\" పేజీల మధ్య తేడా",
        "difference-multipage": "(పేజీల మధ్య తేడా)",
        "lineno": "పంక్తి $1:",
        "showhideselectedversions": "ఎంచుకున్న కూర్పులను చూపించు/దాచు",
        "editundo": "రద్దుచెయ్యి",
        "diff-empty": "(తేడా లేదు)",
-       "diff-multi-sameuser": "(ఇదే వాడుకరి యొక్క {{PLURAL:$1|ఒక మధ్యంతర కూర్పును|$1 మధ్యంతర కూర్పులను}} చూపించలేదు)",
+       "diff-multi-sameuser": "(ఇదే వాడుకరి {{PLURAL:$1|మధ్యంతర కూర్పును|$1 మధ్యంతర కూర్పులను}} చూపించడంలేదు)",
        "diff-multi-otherusers": "({{PLURAL:$2|మరో వాడుకరి|$2 వాడుకరుల}} యొక్క {{PLURAL:$1|ఒక మధ్యంతర కూర్పును|$1 మధ్యంతర కూర్పులను}} చూపించలేదు)",
        "diff-multi-manyusers": "$2 కంటే ఎక్కువ ({{PLURAL:$2|ఒక వాడుకరి|వాడుకరుల}} యొక్క {{PLURAL:$1|ఒక మధ్యంతర కూర్పును|$1 మధ్యంతర కూర్పులను}} చూపించట్లేదు)",
        "diff-paragraph-moved-tonew": "పేరాగ్రాఫును తరలించాం. కొత్త స్థానానికి వెళ్ళేందుకు నొక్కండి.",
        "group": "గుంపు:",
        "group-user": "వాడుకరులు",
        "group-autoconfirmed": "ఆటోమాటిగ్గా నిర్ధారించబడిన వాడుకరులు",
-       "group-bot": "బాట్లు",
+       "group-bot": "బాట్లు",
        "group-sysop": "నిర్వాహకులు",
        "group-interface-admin": "ఇంటర్‌ఫేసు నిర్వాహకులు",
        "group-bureaucrat": "అధికారులు",
        "action-purge": "ఈ పేజీని పర్జ్ చేసే",
        "nchanges": "{{PLURAL:$1|ఒక మార్పు|$1 మార్పులు}}",
        "enhancedrc-since-last-visit": "{{PLURAL:$1|చివరి సందర్శన తరువాత}}, $1",
-       "enhancedrc-history": "à°\9aà°°à°¿à°¤à°\82",
+       "enhancedrc-history": "à°\9aà°°à°¿à°¤à±\8dà°°",
        "recentchanges": "ఇటీవలి మార్పులు",
        "recentchanges-legend": "ఇటీవలి మార్పుల ఎంపికలు",
        "recentchanges-summary": "వికీలో ఇటీవలే జరిగిన మార్పులను ఈ పేజీలో గమనించవచ్చు.",
        "rcfilters-filter-editsbyself-description": "మీ స్వంత దిద్దుబాట్లు.",
        "rcfilters-filter-editsbyother-label": "ఇతరుల దిద్దుబాట్లు",
        "rcfilters-filter-editsbyother-description": "మీరు చేసినవి కాకుండా మిగిలిన దిద్దుబాట్లన్నీ.",
-       "rcfilters-filtergroup-userExpLevel": "వాడుకరి నమోదు, అనుభవం",
+       "rcfilters-filtergroup-user-experience-level": "వాడుకరి నమోదు, అనుభవం",
        "rcfilters-filter-user-experience-level-registered-label": "నమోదైనవారు",
        "rcfilters-filter-user-experience-level-registered-description": "లాగినై ఉన్న వాడుకరులు.",
        "rcfilters-filter-user-experience-level-unregistered-label": "నమోదు కానివారు",
        "rcfilters-filter-logactions-label": "చిట్టాల్లోకి చేరిన కార్యకలాపాలు",
        "rcfilters-filter-logactions-description": "నిర్వాహక పనులు, ఖాతాల సృష్టి, పేజీ తొలగింపులు, ఎక్కింపులు...",
        "rcfilters-hideminor-conflicts-typeofchange": "కొన్ని రకాల మార్పులను \"చిన్న\" మార్పులుగా సూచించ జాలరు. అంచేత ఈ వడపోత కింది మార్పు రకాల వడపోతలతో ఘర్షిస్తోంది: $1",
-       "rcfilters-filtergroup-lastRevision": "ఇటీవలి కూర్పులు",
+       "rcfilters-filtergroup-lastrevision": "ఇటీవలి కూర్పులు",
        "rcfilters-filter-lastrevision-label": "ఇటీవలి కూర్పు",
        "rcfilters-filter-lastrevision-description": "పేజీలో ఇటీవల జరిగిన చిట్టచివరి మార్పు.",
        "rcfilters-filter-previousrevision-label": "ఇటీవలి కూర్పు కాదు",
        "rcfilters-watchlist-markseen-button": "మార్పులన్నీ చూసినట్లుగా గుర్తించు",
        "rcfilters-watchlist-edit-watchlist-button": "మీ వీక్షణ జాబితాను సవరించండి",
        "rcfilters-watchlist-showupdated": "మీ గత సందర్శన తరువాత మారిన పేజీలు '''బొద్దుగా'''ను, నింపిన గుండ్రని చుక్కల ద్వారానూ చూపించాం.",
-       "rcfilters-preference-label": "à°\87à°\9fà±\80వలి à°®à°¾à°°à±\8dà°ªà±\81à°² à°¯à±\8aà°\95à±\8dà°\95 à°®à±\86à°°à±\81à°\97à±\88à°¨ à°\95à±\82à°°à±\8dà°ªà±\81à°¨à±\81 à°¦à°¾à°\9aు",
+       "rcfilters-preference-label": "à°\9cావాసà±\8dà°\95à±\8dà°°à°¿à°ªà±\8dà°\9fà±\81 à°\85వసరà°\82à°²à±\87ని à°\85à°\82తరవరà±\8dతిని à°µà°¾à°¡ు",
        "rcfilters-filter-showlinkedfrom-option-label": "ఎంచుకున్న పేజీ నుండి <strong>లింకైన పేజీలు</strong>",
        "rcfilters-filter-showlinkedto-option-label": "ఎంచుకున్న పేజీకి <strong>లింకైన పేజీలు</strong>",
        "rcfilters-target-page-placeholder": "పేజీ (లేదా వర్గం) పేరు ఇవ్వండి",
        "minoreditletter": "చి",
        "newpageletter": "కొ",
        "boteditletter": "బా",
-       "number_of_watching_users_pageview": "[వీక్షిస్తున్న వాడుకరులు: {{PLURAL:$1|ఒక్కరు|$1}}]",
        "rc-change-size-new": "మార్పు తర్వాత $1 {{PLURAL:$1|బైటు|బైట్లు}}",
        "newsectionsummary": "/* $1 */ కొత్త విభాగం",
        "rc-enhanced-expand": "వివరాలను చూపించు",
        "img-auth-nopathinfo": "PATH_INFO లేదు.\nమీ సర్వరు ఈ సమాచారాన్ని పంపించేందుకు అనువుగా అమర్చి లేదు.\nఅది CGI ఆధారితమై ఉండొచ్చు. అంచేత img_auth కు అనుకూలంగా లేదు.\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization చూడండి.",
        "img-auth-notindir": "అభ్యర్థించిన తోవ ఎక్కింపు సంచయంలో లేదు.",
        "img-auth-badtitle": "\"$1\" నుండి సరైన శీర్షికని నిర్మించలేకపోయాం.",
-       "img-auth-nologinnWL": "మీరు లాగినయి లేరు. పైగా \"$1\" అనేది తెల్లజాబితాలో లేదు.",
        "img-auth-nofile": "\"$1\" అనే ఫైలు ఉనికిలో లేదు.",
        "img-auth-isdir": "మీరు \"$1\" అనే సంచయాన్ని చూడడానికి ప్రయత్నిస్తున్నారు.\nఫైళ్ళను చూడడానికి మాత్రమే అనుమతివుంది.",
        "img-auth-streaming": "\"$1\" ను ప్రసారిస్తున్నాం.",
        "filehist-current": "ప్రస్తుత",
        "filehist-datetime": "తేదీ/సమయం",
        "filehist-thumb": "నఖచిత్రం",
-       "filehist-thumbtext": "$1 à°¨à°¾à°\9fà°¿ à°\95à±\82à°°à±\8dà°ªà±\81 à°¯à±\8aà°\95à±\8dà°\95 à°¨à°\96à°\9aà°¿à°¤à±\8dà°°à°\82",
+       "filehist-thumbtext": "$1 నాటి కూర్పు నఖచిత్రం",
        "filehist-nothumb": "నఖచిత్రం లేదు",
        "filehist-user": "వాడుకరి",
        "filehist-dimensions": "కొలతలు",
        "newpages-submit": "చూపించు",
        "newpages-username": "వాడుకరి పేరు:",
        "ancientpages": "పాత పేజీలు",
-       "move": "తరలిà°\82à°\9aు",
+       "move": "తరలిà°\82à°ªు",
        "movethispage": "ఈ పేజీని తరలించు",
        "unusedimagestext": "ఈ క్రింది ఫైళ్ళు ఉన్నాయి కానీ వాటిని ఏ పేజీలోనూ ఉపయోగించట్లేదు.\nఇతర వెబ్ సైట్లు సూటి URL ద్వారా ఇక్కడి ఫైళ్ళకు లింకు ఇవ్వవచ్చు. ఆ విధంగా క్రియాశీలంగా వాడుకలో ఉన్నప్పటికీ, అటువంటివి ఈ జాబితాలో చేరి ఉండవచ్చునని గమనించండి.",
        "unusedcategoriestext": "కింది వర్గాలకు పేజీలైతే ఉన్నాయి గానీ, వీటిని వ్యాసాలు గానీ, ఇతర వర్గాలు గానీ ఉపయోగించడం లేదు.",
        "booksources-text": "కొత్త, పాత పుస్తకాలు అమ్మే ఇతర సైట్లకు లింకులు కింద ఇచ్చాం. మీరు వెతికే పుస్తకాలకు సంబంధించిన మరింత సమాచారం కూడా అక్కడ దొరకొచ్చు:",
        "booksources-invalid-isbn": "మీరిచ్చిన ISBN సరైనదిగా అనిపించుటలేదు; అసలు మూలాన్నుండి కాపీ చేయడంలో పొరపాట్లున్నాయేమో చూసుకోండి.",
        "specialloguserlabel": "కర్త:",
-       "speciallogtitlelabel": "లక్ష్యం (శీర్షిక లేదా వాడుకరి యొక్క {{ns:user}}:వాడుకరిపేరు):",
+       "speciallogtitlelabel": "లక్ష్యం (శీర్షిక లేదా {{ns:user}}:వాడుకరిపేరు):",
        "log": "చిట్టాలు",
        "logeventslist-submit": "చూపించు",
        "all-logs-page": "అన్ని బహిరంగ చిట్టాలు",
        "delete-confirm": "\"$1\"ని తొలగించు",
        "delete-legend": "తొలగించు",
        "historywarning": "<strong>హెచ్చరిక:</strong> మీరు తొలగించబోయే పేజీకి $1 {{PLURAL:$1|కూర్పు|కూర్పుల}} చరిత్ర ఉంది:",
-       "historyaction-submit": "చూపించు",
+       "historyaction-submit": "à°\95à±\82à°°à±\8dà°ªà±\81లనà±\81 à°\9aà±\82పిà°\82à°\9aà±\81",
        "confirmdeletetext": "మీరో పేజీనో, బొమ్మనో దాని చరిత్రతోపాటుగా శాశ్వతంగా డేటాబేసు నుండి తీసెయ్యబోతున్నారు. మీరు చెయ్యదలచింది ఇదేననీ, దీని పర్యవసానాలు మీకు తెలుసనీ, దీన్ని [[{{MediaWiki:Policy-url}}|నిభందనల]] ప్రకారమే చేస్తున్నారనీ నిర్ధారించుకోండి.",
        "actioncomplete": "పని పూర్తయింది",
        "actionfailed": "చర్య విఫలమైంది",
        "deleting-backlinks-warning": "<strong>హెచ్చరిక:</strong> మీరు తొలగించబోతున్న పేజీకి [[Special:WhatLinksHere/{{FULLPAGENAME}}|ఇతర పేజీల]] నుండి లింకులు ఉన్నాయి. లేదా ఇతర పేజీల్లో అది ట్రాన్స్‍క్లూడు అవుతోంది.",
        "deleting-subpages-warning": "<strong>హెచ్చరిక:</strong> మీరు తొలగించబోతున్న పేజీకి [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|ఒక ఉపపేజీ ఉంది|$1 ఉపపేజీలున్నాయి|51=50 కి పైగా ఉపపేజీలున్నాయి}}]].",
        "rollback": "దిద్దుబాట్లను రద్దుచేయి",
+       "rollback-confirmation-no": "రద్దుచేయి",
        "rollbacklink": "రద్దుచేయి",
        "rollbacklinkcount": "$1 {{PLURAL:$1|మార్పును|మార్పులను}} రద్దుచేయి",
        "rollbacklinkcount-morethan": "$1 కంటే ఎక్కువ {{PLURAL:$1|మార్పును|మార్పులను}} రద్దుచేయి",
        "revertpage": "[[Special:Contributions/$2|$2]] ([[User talk:$2|చర్చ]]) చేసిన మార్పులను [[User:$1|$1]] చివరి కూర్పు వరకు తిప్పికొట్టారు.",
        "revertpage-nouser": "దాగి ఉన్న వాడుకరి చేసిన మార్పులను [[User:$1|$1]] చివరి కూర్పు వరకు తిప్పికొట్టారు",
        "rollback-success": "{{GENDER:$3|$1}} చేసిన దిద్దుబాట్లను వెనక్కు తీసుకెళ్ళారు; తిరిగి {{GENDER:$4|$2}} చేసిన చివరి కూర్పుకు మార్చారు.",
-       "rollback-success-notify": "$1 చేసిన దిద్దుబాట్లను వెనక్కు తీసుకెళ్ళారు;\nతిరిగి $2 చేసిన చివరి కూర్పుకు మార్చారు. [$3 మార్పులు చూపించు]",
        "sessionfailure-title": "సెషను వైఫల్యం",
        "sessionfailure": "మీ లాగిన్ సెషనుతో ఏదో సమస్య ఉన్నట్లుంది;\nసెషను హైజాకు కాకుండా ఈ చర్యను రద్దు చేసాం.\nఫారమును తిరిగి సమర్పించండి.",
        "changecontentmodel": "పేజీ కంటెంటు మోడలును మార్చు",
        "protectlogtext": "ఈ క్రింద ఉన్నది పేజీల సంరక్షణలకు జరిగిన మార్పుల జాబితా.\nప్రస్తుతం అమలులో ఉన్న సంరక్షణలకై [[Special:ProtectedPages|సంరక్షిత పేజీల జాబితా]]ను చూడండి.",
        "protectedarticle": "\"[[$1]]\" సంరక్షించబడింది.",
        "modifiedarticleprotection": "\"[[$1]]\" సంరక్షణ స్థాయిని మార్చారు",
-       "unprotectedarticle": "\"[[$1]]\" à°¯à±\8aà°\95à±\8dà°\95 సంరక్షణను తొలగించారు",
+       "unprotectedarticle": "\"[[$1]]\" à°¨à±\81à°\82à°¡à°¿ సంరక్షణను తొలగించారు",
        "movedarticleprotection": "సంరక్షణా అమరికని \"[[$2]]\" నుండి \"[[$1]]\"కి మార్చారు",
        "protectedarticle-comment": "\"[[$1]]\" ను {{GENDER:$2|సంరక్షించారు}}",
        "modifiedarticleprotection-comment": "\"[[$1]]\" యొక్క {{GENDER:$2|సంరక్షణ స్థాయిని మార్చారు}}",
        "unprotectedarticle-comment": "\"[[$1]]\" ను {{GENDER:$2|సంరక్షణ నుండి తీసివేసారు}}",
        "protect-title": "\"$1\" యొక్క సంరక్షణ స్థాయి మార్పు",
-       "protect-title-notallowed": "\"$1\" à°¯à±\8aà°\95à±\8dà°\95 à°¸à°\82à°°à°\95à±\8dà°·à°£ à°¸à±\8dథాయి",
+       "protect-title-notallowed": "\"$1\" సంరక్షణ స్థాయి",
        "prot_1movedto2": "$1, $2కు తరలించబడింది",
        "protect-badnamespace-title": "సంరక్షించజాలని పేరుబరి",
        "protect-badnamespace-text": "ఈ పేరుబరిలో ఉన్న పేజీలను సంరక్షించలేరు.",
        "whatlinkshere-links": "← లంకెలు",
        "whatlinkshere-hideredirs": "$1 దారిమార్పులు",
        "whatlinkshere-hidetrans": "$1 ట్రాన్స్‌క్లూజన్లు",
-       "whatlinkshere-hidelinks": "$1 లింకులు",
+       "whatlinkshere-hidelinks": "లంకెలు $1",
        "whatlinkshere-hideimages": "$1 దస్త్రపు లంకెలు",
        "whatlinkshere-filters": "వడపోతలు",
        "whatlinkshere-submit": "వెళ్ళు",
        "ipbreason": "కారణం:",
        "ipbreason-dropdown": "*సాధారణ నిరోధ కారణాలు\n** తప్పు సమాచారాన్ని చొప్పించడం\n** పేజీల్లోని సమాచారాన్ని తీసెయ్యడం\n** బయటి సైట్లకు లంకెలతో స్పాము చెయ్యడం\n** పేజీల్లోకి చెత్తను ఎక్కించడం\n** బెదిరింపు ప్రవర్తన/వేధింపులు\n** అనేక ఖాతాలను సృష్టించి దుశ్చర్యకు పాల్పడడం\n** అనుచితమైన వాడుకరి పేరు",
        "ipb-hardblock": "లాగినై ఉన్న వాడుకరులు ఈ ఐపీ అడ్రసు నుంచి మార్పుచేర్పులు చెయ్యకుండా నిరోధించండి",
-       "ipbcreateaccount": "à°\96ాతా à°¸à±\83à°·à±\8dà°\9fిని à°¨à°¿à°µà°¾à°°à°¿à°\82à°\9aు",
-       "ipbemailban": "వాడà±\81à°\95రిని à°\88-à°®à±\86యిలà±\8d à°\9aà±\86à°¯à±\8dà°¯à°\95à±\81à°\82à°¡à°¾ à°¨à°¿à°µà°¾à°°à°¿à°\82à°\9aà±\81",
+       "ipbcreateaccount": "à°\96ాతా à°¸à±\83à°·à±\8dà°\9fà°¿à°\82à°ªు",
+       "ipbemailban": "à°\88à°®à±\86యిలà±\81 à°ªà°\82పిà°\82à°\9aà°¡à°\82",
        "ipbenableautoblock": "ఈ వాడుకరి వాడిన చివరి ఐపీ అడ్రసును, అలాగే ఆ తరువాత వాడే అడ్రసులను కూడా ఆటోమాటిగ్గా నిరోధించు",
        "ipbsubmit": "ఈ వాడుకరిని నిరోధించు",
        "ipbother": "వేరే గడువు",
        "ipboptions": "2 గంటలు:2 hours,ఒక రోజు:1 day,3 రోజులు:3 days,ఒక వారం:1 week,2 వారాలు:2 weeks,ఒక నెల:1 month,3 నెలలు:3 months,6 నెలలు:6 months,ఒక సంవత్సరం:1 year,ఎప్పటికీ:infinite",
        "ipbhidename": "మార్పులు, జాబితాల నుండి ఈ వాడుకరిపేరుని దాచు",
        "ipbwatchuser": "ఈ వాడుకరి వాడుకరి పేజీ, చర్చాపేజీలను వీక్షణలో ఉంచు",
-       "ipb-disableusertalk": "నిరà±\8bà°§à°\82à°²à±\8b à°\89à°\82à°¡à°\97à°¾ à°\88 à°µà°¾à°¡à±\81à°\95à°°à°¿ à°¤à°¨ à°¸à±\8dà°µà°\82à°¤ à°\9aà°°à±\8dà°\9a à°ªà±\87à°\9cà±\80à°²à±\8b à°®à°¾à°°à±\8dà°ªà±\81à°\9aà±\87à°°à±\8dà°ªà±\81à°²à±\81 à°\9aà±\86à°¯à±\8dà°¯à°\95à±\81à°\82à°¡à°¾ à°¨à°¿à°°à±\8bధిà°\82à°\9aà±\81",
+       "ipb-disableusertalk": "తన à°¸à±\8dà°µà°\82à°¤ à°\9aà°°à±\8dà°\9a à°ªà±\87à°\9cà±\80à°²à±\8b à°®à°¾à°°à±\8dà°ªà±\81à°²à±\81 à°\9aà±\86à°¯à±\8dయడà°\82",
        "ipb-change-block": "ఈ అమరికలతో వాడుకరిని పునర్నిరోధించు",
        "ipb-confirm": "నిరోధాన్ని ధృవపరచండి",
        "ipb-sitewide": "సైట్ వ్యాప్తంగా",
        "ipb-blocklist-contribs": "{{GENDER:$1|$1}} మార్పులు-చేర్పులు",
        "ipb-blocklist-duration-left": "ఇంకా $1 మిగిలి ఉంది.",
        "block-expiry": "అంతమయ్యే గడువు",
+       "block-reason": "కారణం:",
+       "block-target": "వాడుకరి పేరు లేదా ఐపీ చిరునామా:",
        "unblockip": "వాడుకరిపై నిరోధాన్ని తొలగించు",
        "unblockiptext": "కింది ఫారం ఉపయోగించి, నిరోధించబడిన ఐ.పీ. చిరునామా లేదా వాడుకరికి తిరిగి రచనలు చేసే అధికారం ఇవ్వవచ్చు.",
        "ipusubmit": "ఈ నిరోధాన్ని తొలగించు",
        "blocklist-userblocks": "ఖాతా నిరోధాలను దాచు",
        "blocklist-tempblocks": "తాత్కాలిక నిరోధాలను దాచు",
        "blocklist-addressblocks": "ఏకైక ఐపీ నిరోధాలను దాచు",
+       "blocklist-type": "రకం:",
+       "blocklist-type-opt-all": "అన్నీ",
+       "blocklist-type-opt-sitewide": "సైటు వ్యాప్తంగా",
+       "blocklist-type-opt-partial": "పాక్షికం",
        "blocklist-rangeblocks": "శ్రేణి నిరోధకాలను దాచు",
        "blocklist-timestamp": "కాలముద్ర",
        "blocklist-target": "గమ్యం",
        "allmessagesdefault": "అప్రమేయ సందేశపు పాఠ్యం",
        "allmessagescurrent": "ప్రస్తుత పాఠ్యం",
        "allmessagestext": "మీడియావికీ పేరుబరిలో ఉన్న అంతరవర్తి సందేశాల జాబితా ఇది.\nసాధారణ మీడియావికీ స్థానికీకరణకి మీరు తోడ్పడాలనుకుంటే, దయచేసి [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation మీడియావికీ స్థానికీకరణ] మరియు [https://translatewiki.net ట్రాన్స్&zwnj;లేట్&zwnj;వికీ.నెట్] సైట్లను చూడండి.",
-       "allmessagesnotsupportedDB": "'''$wgUseDatabaseMessages''' అన్నది అచేతనం చేసి ఉన్నందువల్ల ఈ పేజీని వాడలేరు.",
+       "allmessages-not-supported-database": "'''$wgUseDatabaseMessages''' అన్నది అచేతనం చేసి ఉన్నందువల్ల ఈ పేజీని వాడలేరు.",
        "allmessages-filter-legend": "వడపోత",
        "allmessages-filter": "కస్టమైజేషను స్థితిని బట్టి వడకట్టు:",
        "allmessages-filter-unmodified": "మార్చబడనివి",
        "tooltip-pt-anoncontribs": "ఈ IP అడ్రసు నుండి చేసిన దిద్దుబాట్ల జాబితా",
        "tooltip-pt-login": "మిమ్మల్ని లాగినవమని ప్రోత్సహిస్తున్నాం; కానీ అది తప్పనిసరేమీ కాదు.",
        "tooltip-pt-login-private": "ఈ వికీని వాడాలంటే మీరు లాగినై ఉండాలి.",
-       "tooltip-pt-logout": "లాà°\97à±\8cà°\9fà°µండి",
+       "tooltip-pt-logout": "నిషà±\8dà°\95à±\8dరమిà°\82à°\9aండి",
        "tooltip-pt-createaccount": "మీరొక ఖాతాని సృష్టించుకొని ప్రవేశించటాన్ని సమర్ధిస్తున్నాము; కానీ, అది అవసరం కాదు, ఐచ్ఛికం మాత్రమే.",
        "tooltip-ca-talk": "విషయపు పేజీ గురించి చర్చ",
        "tooltip-ca-edit": "ఈ పేజీని సవరించండి",
        "tooltip-ca-addsection": "కొత్త విభాగాన్ని మొదలుపెట్టండి",
        "tooltip-ca-viewsource": "ఈ పుటని సంరక్షించారు. మీరు దీని మూలాన్ని చూడవచ్చు",
-       "tooltip-ca-history": "à°\88 à°ªà±\87à°\9cà±\80 à°¯à±\8aà°\95à±\8dà°\95 à°µà±\86à°¨à±\81à°\95టి కూర్పులు",
+       "tooltip-ca-history": "à°\88 à°ªà±\87à°\9cà±\80 à°®à±\81à°¨à±\81à°ªటి కూర్పులు",
        "tooltip-ca-protect": "ఈ పేజీని సంరక్షించండి",
        "tooltip-ca-unprotect": "ఈ పేజీ సంరక్షణను మార్చండి",
        "tooltip-ca-delete": "ఈ పేజీని తొలగించండి",
        "tooltip-n-mainpage": "మొదటి పేజీ చూడండి",
        "tooltip-n-mainpage-description": "మొదటి పేజీ చూడండి",
        "tooltip-n-portal": "ప్రాజెక్టు గురించి, మీరేం చేయవచ్చు, సమాచారం ఎక్కడ దొరుకుతుంది",
-       "tooltip-n-currentevents": "వరà±\8dతమాన à°\98à°\9fనల à°¯à±\8aà°\95à±\8dà°\95 à°¨à±\87పథà±\8dయానà±\8dని à°¤à±\86à°²à±\81à°¸à±\81à°\95à±\8bà°\82à°¡à°¿",
+       "tooltip-n-currentevents": "వర్తమాన ఘటనల నేపథ్యాన్ని తెలుసుకోండి",
        "tooltip-n-recentchanges": "వికీలో ఇటీవల జరిగిన మార్పుల జాబితా.",
        "tooltip-n-randompage": "ఓ యాదృచ్చిక పేజీని చూడండి",
        "tooltip-n-help": "నేర్చుకునే చోటు",
        "tooltip-t-emailuser": "ఈ {{GENDER:$1|వాడుకరికి}} ఓ ఈమెయిలు పంపండి",
        "tooltip-t-info": "ఈ పేజీ గురించి మరింత సమాచారం",
        "tooltip-t-upload": "దస్త్రాలను ఎక్కించండి",
-       "tooltip-t-specialpages": "à°\85à°¨à±\8dని à°ªà±\8dà°°à°¤à±\8dà°¯à±\87à°\95 à°ªà±\81à°\9fà°² జాబితా",
-       "tooltip-t-print": "ఈ పేజీ యొక్క ముద్రణా రూపు",
-       "tooltip-t-permalink": "à°ªà±\87à°\9cà±\80 à°¯à±\8aà°\95à±\8dà°\95 à°\88 à°\95à±\82à°°à±\8dà°ªà±\81à°\95à°¿ à°¶à°¾à°¶à±\8dవత à°²à°\82à°\95à±\86",
+       "tooltip-t-specialpages": "à°ªà±\8dà°°à°¤à±\8dà°¯à±\87à°\95 à°ªà±\87à°\9cà±\80లనà±\8dనిà°\9fà°¿ జాబితా",
+       "tooltip-t-print": "ఈ పేజీకి ముద్రించుకోదగ్గ కూర్పు",
+       "tooltip-t-permalink": "ఈ కూర్పుకి శాశ్వత లంకె",
        "tooltip-ca-nstab-main": "విషయపు పేజీని చూడండి",
        "tooltip-ca-nstab-user": "వాడుకరి పేజీని చూడండి",
        "tooltip-ca-nstab-media": "మీడియా పేజీని చూడండి",
-       "tooltip-ca-nstab-special": "à°\87ది à°\92à°\95 à°ªà±\8dà°°à°¤à±\8dà°¯à±\87à°\95 à°ªà±\87à°\9cà±\80, à°¦à±\80à°¨à±\8dని à°®à±\80à°°à±\81 à°¸à°°à°¿à°¦à°¿à°¦à±\8dదలà±\87à°°à±\81",
+       "tooltip-ca-nstab-special": "ఇది ఒక ప్రత్యేక పేజీ, దీన్ని సరిదిద్దలేరు",
        "tooltip-ca-nstab-project": "ప్రాజెక్టు పేజీని చూడండి",
        "tooltip-ca-nstab-image": "ఫైలు పేజీని చూడండి",
        "tooltip-ca-nstab-mediawiki": "వ్యవస్థా సందేశం చూడండి",
index d58e1e0..7d9374b 100644 (file)
        "minoreditletter": "х",
        "newpageletter": "Нав",
        "boteditletter": "б",
-       "number_of_watching_users_pageview": "[$1 пайгирикунанда {{PLURAL:$1|корбар|корбарон}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|байт}} пас аз тағйир",
        "newsectionsummary": "/* $1 */ бахши ҷадид",
        "rc-enhanced-expand": "Намоиши ҷузъиёт",
        "editcomment": "Хулосаи вироиш ин буд: <em>$1</em>.",
        "revertpage": "Вироиши [[Special:Contributions/$2|$2]] ([[User talk:$2|Баҳс]]) вогардонида шуд ба охирин тағйире, ки [[User:$1|$1]] анҷом дода буд",
        "rollback-success": "Вироишҳои $1 вогардонӣ шуд; саҳифа ба вироиши $2 баргардонида шуд.",
-       "rollback-success-notify": "Вироишоти $1 вогардонида шуд ба охирин вироише, ки  $2 анҷом дода буд. [$3 Намоиши тавофут]",
        "sessionfailure": "Ба назар мерасад, мушкилие дар мавриди нишасти корбарии шумо вуҷуд дорад; амали дархостшуда ба унвони иқдоми пешгирона дар баробари рабуда шудани иттилооти нишасти корбарӣ, лағв шуд. Лутфан тугмаи \"бозгашт\"-ро дар мурургари худ пахш кунед ва саҳифае, ки аз он инҷо расидаед муҷаддадан фарохонӣ кунед, сипас муҷаддадан боз саъй кунед.",
        "protectlogpage": "Гузориши муҳофизат",
        "protectlogtext": "Дар зер феҳристи қуфл карданҳо ва аз қуфл озод шуданҳо омада аст. Барои иттилооти бештар ба [[Special:ProtectedPages|феҳристи саҳифаҳои муҳофизатшуда]] нигаред.",
        "allmessagesdefault": "Матни қарордодӣ",
        "allmessagescurrent": "Матни кунунӣ",
        "allmessagestext": "Ин феҳристи паёмҳои системавии дастрас дар фазои номи MediaWiki мебошад.\nАгар майли ҳиссагузорӣ карданро ба маҳалликунонии MediaWiki доред, пас лутфан ба саҳифаҳои [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Маҳалликунонии MediaWiki] ва [https://translatewiki.net translatewiki.net] гузаред.",
-       "allmessagesnotsupportedDB": "Аз ин саҳифа наметавон истифода бурд, чун '''$wgUseDatabaseMessages''' ғайрифаъол гардонида шудааст.",
+       "allmessages-not-supported-database": "Аз ин саҳифа наметавон истифода бурд, чун '''$wgUseDatabaseMessages''' ғайрифаъол гардонида шудааст.",
        "allmessages-filter-legend": "Филтр",
        "allmessages-filter-unmodified": "Тағйирнаёфта",
        "allmessages-filter-all": "Ҳама",
index b4d26f2..f9d3200 100644 (file)
        "minoreditletter": "x",
        "newpageletter": "Nav",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 pajgirikunanda {{PLURAL:$1|korbar|korbaron}}]",
        "newsectionsummary": "/* $1 */ baxşi çadid",
        "rc-enhanced-expand": "Namoişi çuz'ijot (nijozmand ba Çava Skript)",
        "rc-enhanced-hide": "Pinhoni çuz'ijot",
        "allmessagesdefault": "Matni qarordodī",
        "allmessagescurrent": "Matni kununī",
        "allmessagestext": "In fehristi pajomhoi sistemaviji dastras dar fazoi nomi MediaWiki meboşad.\nAgar majli hissaguzorī kardanro ba mahallikunoniji MediaWiki dored, pas lutan sahifahoi [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Mahallikunoniji MediaWiki] va [https://translatewiki.net translatewiki.net] nigared.",
-       "allmessagesnotsupportedDB": "Az in sahifa nametavon istifoda burd, cun '''$wgUseDatabaseMessages''' ƣajrifa'ol gardonida şudaast.",
+       "allmessages-not-supported-database": "Az in sahifa nametavon istifoda burd, cun '''$wgUseDatabaseMessages''' ƣajrifa'ol gardonida şudaast.",
        "allmessages-filter-legend": "Filtr",
        "allmessages-filter-all": "Hama",
        "allmessages-language": "Zabon:",
index 70ef7bf..a13fe24 100644 (file)
@@ -77,6 +77,7 @@
        "tog-norollbackdiff": "ไม่แสดงผลต่างหลังดำเนินการย้อนรวดเดียว",
        "tog-useeditwarning": "เตือนฉันเมื่อออกจากหน้าแก้ไขโดยมีการเปลี่ยนแปลงที่ยังไม่บันทึก",
        "tog-prefershttps": "ใช้การเชื่อมต่อปลอดภัยทุกครั้งเมื่อเข้าสู่ระบบแล้ว",
+       "tog-showrollbackconfirmation": "แสดงตัวพร้อมยืนยันเมื่อคลิกลิงก์ย้อนรวดเดียว",
        "underline-always": "ทุกครั้ง",
        "underline-never": "ไม่",
        "underline-default": "ค่าปริยายของหน้าตาหรือเบราว์เซอร์",
        "moredotdotdot": "ดูเพิ่ม...",
        "morenotlisted": "รายการนี้อาจไม่สมบูรณ์",
        "mypage": "หน้า",
-       "mytalk": "à¸\9eูà¸\94à¸\84ุย",
-       "anontalk": "à¸\9eูà¸\94à¸\84ุย",
+       "mytalk": "คุย",
+       "anontalk": "คุย",
        "navigation": "การนำทาง",
        "and": "&#32;และ",
        "faq": "คำถามที่พบบ่อย",
        "perfcachedts": "ข้อมูลต่อไปนี้ถูกเก็บในแคชและถูกปรับล่าสุดเมื่อ $1 มีผลลัพธ์สูงสุด $4 รายการในแคชได้",
        "querypage-no-updates": "ขณะนี้ปิดใช้งานการปรับหน้านี้ \nข้อมูลในที่นี้จะไม่รีเฟรชเป็นปัจจุบัน",
        "viewsource": "ดูต้นฉบับ",
-       "viewsource-title": "à¸\94ูà¹\82à¸\84à¹\89à¸\94สำหรับ $1",
+       "viewsource-title": "à¸\94ูà¸\95à¹\89à¸\99à¸\89à¸\9aัà¸\9aสำหรับ $1",
        "actionthrottled": "ปฏิบัติการถูกจำกัด",
        "actionthrottledtext": "เพื่อเป็นมาตรการป้องกันการละเมิด คุณจึงถูกจำกัดมิให้กระทำสิ่งนี้ติดต่อกันหลายครั้งเกินไปในช่วงระยะเวลาสั้น ๆ ซึ่งขณะนี้คุณเลยขีดจำกัดนี้แล้ว \nกรุณารอสักครู่แล้วลองอีกครั้ง",
        "protectedpagetext": "หน้านี้ถูกล็อกเพื่อป้องกันการแก้ไขหรือปฏิบัติการอื่น",
        "cannotchangeemail": "ไม่สามารถเปลี่ยนที่อยู่อีเมลบนวิกินี้",
        "emaildisabled": "เว็บไซต์นี้ไม่สามารถส่งอีเมล",
        "accountcreated": "สร้างบัญชีแล้ว",
-       "accountcreatedtext": "สรà¹\89าà¸\87à¸\9aัà¸\8dà¸\8aีà¸\9cูà¹\89à¹\83à¸\8aà¹\89สำหรัà¸\9a [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|à¸\9eูà¸\94à¸\84ุย]]) à¹\81ลà¹\89ว",
+       "accountcreatedtext": "สร้างบัญชีผู้ใช้สำหรับ [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|คุย]]) แล้ว",
        "createaccount-title": "การสร้างบัญชีสำหรับ {{SITENAME}}",
        "createaccount-text": "มีบางคนสร้างบัญชีโดยใช้ที่อยู่อีเมลของคุณบน {{SITENAME}} ($4) โดยใช้ชื่อ \"$2\" และรหัสผ่าน \"$3\" \nคุณควรเข้าสู่ระบบและเปลี่ยนรหัสผ่านทันที\n\nคุณอาจเพิกเฉยข้อความนี้ หากการสร้างบัญชีนี้เป็นความผิดพลาด",
        "login-throttled": "ที่ผ่านมาคุณพยายามล็อกอินมากครั้งเกินไป\nกรุณารอ $1 ก่อนลองอีกครั้ง",
        "page_first": "แรกสุด",
        "page_last": "ท้ายสุด",
        "histlegend": "การเลือกผลต่าง: เลือกปุ่มของสองรุ่นที่ต้องการเปรียบเทียบ และกดป้อนเข้าหรือปุ่มด้านล่าง<br />\nคำอธิบาย: <strong>({{int:cur}})</strong> = ผลต่างกับรุ่นแก้ไขล่าสุด, <strong>({{int:last}})</strong> = ผลต่างกับรุ่นแก้ไขก่อนหน้า, <strong>{{int:minoreditletter}}</strong> = การแก้ไขเล็กน้อย",
-       "history-fieldset-title": "à¸\84à¹\89à¸\99หารุ่นแก้ไข",
+       "history-fieldset-title": "à¸\81รอà¸\87รุ่นแก้ไข",
        "history-show-deleted": "เฉพาะรุ่นแก้ไขที่ถูกลบ",
        "histfirst": "แรกสุด",
        "histlast": "ล่าสุด",
        "historysize": "($1 ไบต์)",
-       "historyempty": "(ว่าง)",
+       "historyempty": "ว่าง",
        "history-feed-title": "ประวัติรุ่นแก้ไข",
        "history-feed-description": "ประวัติรุ่นแก้ไขของหน้านี้ในวิกิ",
        "history-feed-item-nocomment": "$1 เมื่อ $2",
        "userrights-groupsmember": "สมาชิกของ:",
        "userrights-groupsmember-auto": "สมาชิกโดยปริยายของ:",
        "userrights-groupsmember-type": "$1",
-       "userrights-groups-help": "à¸\84ุà¸\93สามารà¸\96à¹\80à¸\9bลีà¹\88ยà¸\99à¹\81à¸\9bลà¸\87à¸\81ลุà¹\88มà¸\97ีà¹\88à¸\9cูà¹\89à¹\83à¸\8aà¹\89รายà¸\99ีà¹\89อยูà¹\88:\n* à¸\81ลà¹\88อà¸\87à¸\97ีà¹\88มีà¹\80à¸\84รืà¹\88อà¸\87หมายà¸\96ูà¸\81 à¸«à¸¡à¸²à¸¢à¸\84วามวà¹\88า à¸\9cูà¹\89à¹\83à¸\8aà¹\89อยูà¹\88à¹\83à¸\99à¸\81ลุà¹\88มà¸\99ัà¹\89à¸\99\n* à¸\81ลà¹\88อà¸\87à¸\97ีà¹\88à¹\84มà¹\88มีà¹\80à¸\84รืà¹\88อà¸\87หมายà¸\96ูà¸\81 à¸«à¸¡à¸²à¸¢à¸\84วามวà¹\88า à¸\9cูà¹\89à¹\83à¸\8aà¹\89à¹\84มà¹\88à¹\84à¸\94à¹\89อยูà¹\88à¹\83à¸\99à¸\81ลุà¹\88มà¸\99ัà¹\89à¸\99\n* à¹\80à¸\84รืà¹\88อà¸\87หมาย * à¸\8aีà¹\89วà¹\88าà¸\84ุà¸\93à¹\84มà¹\88สามารà¸\96à¸\99ำà¸\81ลุà¹\88มà¸\99ัà¹\89à¸\99ออà¸\81à¹\84à¸\94à¹\89à¹\80มืà¹\88อà¸\84ุà¸\93à¹\80à¸\9eิà¹\88มà¸\81ลุà¹\88มà¸\99ัà¹\89à¸\99à¹\84à¸\9bà¹\81ลà¹\89ว à¸«à¸£à¸·à¸­à¸\81ลัà¸\9aà¸\81ัà¸\99\n* à¹\80à¸\84รืà¹\88อà¸\87หมาย # à¸\9aี้ว่าคุณสามารถแก้คืนเวลาหมดอายุของสมาชิกภาพกลุ่มนี้เท่านั้น คุณไม่สามารถร่นเวลาหมดอายุได้",
+       "userrights-groups-help": "à¸\84ุà¸\93สามารà¸\96à¹\80à¸\9bลีà¹\88ยà¸\99à¹\81à¸\9bลà¸\87à¸\81ลุà¹\88มà¸\97ีà¹\88à¸\9cูà¹\89à¹\83à¸\8aà¹\89รายà¸\99ีà¹\89อยูà¹\88:\n* à¸\81ลà¹\88อà¸\87à¸\97ีà¹\88มีà¹\80à¸\84รืà¹\88อà¸\87หมายà¸\96ูà¸\81 à¸«à¸¡à¸²à¸¢à¸\84วามวà¹\88า à¸\9cูà¹\89à¹\83à¸\8aà¹\89อยูà¹\88à¹\83à¸\99à¸\81ลุà¹\88มà¸\99ัà¹\89à¸\99\n* à¸\81ลà¹\88อà¸\87à¸\97ีà¹\88à¹\84มà¹\88มีà¹\80à¸\84รืà¹\88อà¸\87หมายà¸\96ูà¸\81 à¸«à¸¡à¸²à¸¢à¸\84วามวà¹\88า à¸\9cูà¹\89à¹\83à¸\8aà¹\89à¹\84มà¹\88à¹\84à¸\94à¹\89อยูà¹\88à¹\83à¸\99à¸\81ลุà¹\88มà¸\99ัà¹\89à¸\99\n* à¹\80à¸\84รืà¹\88อà¸\87หมาย * à¸\8aีà¹\89วà¹\88าà¸\84ุà¸\93à¹\84มà¹\88สามารà¸\96à¸\99ำà¸\81ลุà¹\88มà¸\99ัà¹\89à¸\99ออà¸\81à¹\84à¸\94à¹\89à¹\80มืà¹\88อà¸\84ุà¸\93à¹\80à¸\9eิà¹\88มà¸\81ลุà¹\88มà¸\99ัà¹\89à¸\99à¹\84à¸\9bà¹\81ลà¹\89ว à¸«à¸£à¸·à¸­à¸\81ลัà¸\9aà¸\81ัà¸\99\n* à¹\80à¸\84รืà¹\88อà¸\87หมาย # à¸\8aี้ว่าคุณสามารถแก้คืนเวลาหมดอายุของสมาชิกภาพกลุ่มนี้เท่านั้น คุณไม่สามารถร่นเวลาหมดอายุได้",
        "userrights-reason": "เหตุผล:",
        "userrights-no-interwiki": "คุณไม่มีสิทธิแก้ไขสิทธิผู้ใช้บนวิกิอื่น",
        "userrights-nodatabase": "ไม่มีฐานข้อมูล $1 หรือฐานข้อมูลอยู่บนเครื่องอื่น",
        "right-reupload-own": "บันทึกทับไฟล์เดิมที่คุณอัปโหลดเอง",
        "right-reupload-shared": "บันทึกทับไฟล์บนคลังร่วมสื่อท้องถิ่น",
        "right-upload_by_url": "อัปโหลดไฟล์จากยูอาร์แอล",
-       "right-purge": "ลà¹\89าà¸\87à¹\81à¸\84à¸\8aà¸\82อà¸\87à¹\80วà¹\87à¸\9aà¹\84à¸\8bà¸\95à¹\8cà¹\82à¸\94ยà¹\84มà¹\88ยืà¸\99ยัà¸\99",
+       "right-purge": "ลà¹\89าà¸\87à¹\81à¸\84à¸\8aà¸\82อà¸\87à¹\80วà¹\87à¸\9aà¹\84à¸\8bà¸\95à¹\8cสำหรัà¸\9aหà¸\99à¹\89าหà¸\99ึà¹\88à¸\87",
        "right-autoconfirmed": "ไม่ได้รับผลจากขีดจำกัดอัตรายึดเลขที่อยู่ไอพี",
        "right-bot": "กำหนดเป็นกระบวนการอัตโนมัติ",
        "right-nominornewtalk": "หากไม่มีการแก้ไขเล็กน้อยในหน้าอภิปรายจะทำให้การแจ้งข้อความใหม่ปรากฏ",
        "action-changetags": "เพิ่มและลบป้ายระบุคงค่าต่อรุ่นแก้ไขและหน่วยปูมหนึ่ง",
        "action-deletechangetags": "ลบป้ายระบุออกจากฐานข้อมูล",
        "action-purge": "ล้างหน้านี้",
+       "action-autoconfirmed": "ไม่ได้รับผลจากข้อจำกัดอัตราที่ยึดไอพี",
+       "action-bigdelete": "ลบหน้าที่มีประวัติมาก",
+       "action-blockemail": "กันผู้ใช้ไม่ให้ส่งอีเมล",
+       "action-bot": "ถือเป็นกระบวนการอัตโนมัติ",
+       "action-editprotected": "แก้ไขหน้าที่ป้องกันแบบ \"{{int:protect-level-sysop}}\"",
+       "action-editsemiprotected": "แก้ไขหน้าที่ป้องกันแบบ \"{{int:protect-level-autoconfirmed}}\"",
+       "action-editinterface": "แก้ไขอินเตอร์เฟซผู้ใช้",
+       "action-viewsuppressed": "ดูรุ่นแก้ไขที่ถูกซ่อนจากผู้ใช้อื่นทุกคน",
+       "action-hideuser": "บล็อกชื่อผู้ใช้ ซ่อนไม่ให้สาธารณะเห็น",
+       "action-ipblock-exempt": "ข้ามการบล็อกไอพี บล็อกอัตโนมัติและบล็อกเป็นช่วง",
+       "action-unblockself": "ปลดบล็อกตัวเอง",
+       "action-noratelimit": "ไม่ได้รับผลกระทบจากขีดจำกัดอัตรา",
+       "action-reupload-own": "เขียนทับไฟล์เดิมที่ตัวเองอัปโหลด",
+       "action-nominornewtalk": "ไม่ให้การแก้ไขเล็กน้อยในหน้าอภิปรายดำเนินการตัวพร้อมสารใหม่",
        "nchanges": "$1 การเปลี่ยนแปลง",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|ตั้งแต่การเยี่ยมชมครั้งสุดท้าย}}",
        "enhancedrc-history": "ประวัติ",
        "rcfilters-savedqueries-already-saved": "ตัวกรองเหล่านี้บันทุกแล้ว เปลี่ยนการตั้งค่าของคุณเพื่อสร้างตัวกรองที่บันทึกแล้วใหม่",
        "rcfilters-restore-default-filters": "คืนค่าตัวกรองปริยาย",
        "rcfilters-clear-all-filters": "ล้างตัวกรองทั้งหมด",
-       "rcfilters-show-new-changes": "à¸\94ูà¸\81ารà¹\80à¸\9bลีà¹\88ยà¸\99à¹\81à¸\9bลà¸\87ลà¹\88าสุà¸\94",
+       "rcfilters-show-new-changes": "à¸\94ูà¸\81ารà¹\80à¸\9bลีà¹\88ยà¸\99à¹\81à¸\9bลà¸\87à¹\83หมà¹\88à¸\95ัà¹\89à¸\87à¹\81à¸\95à¹\88 $1",
        "rcfilters-search-placeholder": "กรองการเปลี่ยนแปลง (ใช้รายการเลือกหรือค้นหาชื่อตัวกรอง)",
        "rcfilters-invalid-filter": "ตัวกรองไม่ถูกต้อง",
        "rcfilters-empty-filter": "ไม่มีตัวกรองเปิดใช้งาน แสดงการแก้ไขทั้งหมด",
        "rcfilters-filter-editsbyself-description": "การแก้ไขของคุณเอง",
        "rcfilters-filter-editsbyother-label": "การแก้ไขของผู้อื่น",
        "rcfilters-filter-editsbyother-description": "การแก้ไขทั้งหมดยกเว้นของคุณ",
-       "rcfilters-filtergroup-userExpLevel": "การลงทะเบียนผู้ใช้และประสบการณ์",
+       "rcfilters-filtergroup-user-experience-level": "การลงทะเบียนผู้ใช้และประสบการณ์",
        "rcfilters-filter-user-experience-level-registered-label": "ผู้ใช้ลงทะเบียน",
        "rcfilters-filter-user-experience-level-registered-description": "ผู้ใช้ล็อกอิน",
        "rcfilters-filter-user-experience-level-unregistered-label": "ผู้ใช้ไม่ลงทะเบียน",
        "rcfilters-hideminor-conflicts-typeofchange-global": "ตัวกรอง \"แก้ไขเล็กน้อย\" ขัดแย้งกับชนิดตัวกรองการเปลี่ยนแปลงตั้งแต่หนึ่งตัวกรอง เพราะการเปลี่ยนแปลงบางประเภทไม่สามารถตั้งให้เป็น \"เล็กน้อย\" ตัวกรองที่ขัดแย้งนี้มีการทำเครื่องหมายไว้ในพื้นที่ตัวกรองที่กำลังเปิดใช้งานด้านบน",
        "rcfilters-hideminor-conflicts-typeofchange": "การเปลี่ยนแปลงบางประเภทไม่สามารถตั้งให้เป็น \"เล็กน้อย\" ฉะนั้นตัวกรองนี้จึงขัดแย้งกับตัวกรองชนิดการเปลี่ยนแปลงต่อไปนี้: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "ตัวกรองชนิดการเปลี่ยนแปลงนี้ขัดแย้งกับตัวกรอง \"เล็กน้อย\" การเปลี่ยนแปลงบางประเภทไม่สามารถตั้งให้เป็น \"เล็กน้อย\"",
-       "rcfilters-filtergroup-lastRevision": "รุ่นล่าสุด",
+       "rcfilters-filtergroup-lastrevision": "รุ่นล่าสุด",
        "rcfilters-filter-lastrevision-label": "รุ่นล่าสุด",
        "rcfilters-filter-lastrevision-description": "เฉพาะการเปลี่ยนแปลงล่าสุดของหน้า",
        "rcfilters-filter-previousrevision-label": "ไม่ใช่รุ่นล่าสุด",
        "newpageletter": "ม",
        "boteditletter": "บ",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 ผู้ใช้เฝ้าดู]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 ไบต์หลังเปลี่ยนแปลง",
        "newsectionsummary": "/* $1 */ ส่วนใหม่",
        "upload-form-label-own-work": "นี่เป็นงานสร้างสรรค์ของฉันเอง",
        "upload-form-label-infoform-categories": "หมวดหมู่",
        "upload-form-label-infoform-date": "วันที่",
+       "upload-form-label-own-work-message-generic-local": "ฉันยืนยันว่าฉันกำลังอัปโหลดไฟล์นี้ตามข้อกำหนดการใช้งานและนโยบายสัญญาอนุญาตทาง{{SITENAME}}",
+       "upload-form-label-not-own-work-message-generic-local": "หากคุณไม่สามารถอัปโหลดไฟล์นี้ภายใต้นโยบายของ{{SITENAME}} กรุณาปิดคำโต้ตอบนี้และลองวิธีอื่น",
        "upload-form-label-not-own-work-local-generic-local": "คุณอาจต้องการทดลองใช้[[Special:Upload|หน้าอัปโหลดปริยาย]]",
        "backend-fail-backup": "ไม่สามารถสำรองไฟล์ \"$1\"",
        "backend-fail-notexists": "ไม่มีไฟล์ $1",
        "img-auth-nopathinfo": "PATH_INFO สูญหาย\nเซิร์ฟเวอร์ของคุณอาจไม่ได้ถูกตั้งให้ส่งสารสนเทศนี้\nอาจเป็นแบบ CGI-based และไม่สามารถสนับสนุน img_auth\nดูที่ https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization",
        "img-auth-notindir": "ที่อยู่ที่ร้องขอไม่ได้อยู่ในสารบบอัพโหลดที่กำหนดไว้",
        "img-auth-badtitle": "ไม่สามารถสร้างชื่อเรื่องที่ถูกต้องจาก \"$1\"",
-       "img-auth-nologinnWL": "คุณไม่ได้เข้าสู่ระบบและ \"$1\" ไม่ได้อยู่ในรายชื่อผู้ใช้ที่ได้รับอนุญาต (whitelist)",
        "img-auth-nofile": "ไม่มีไฟล์ \"$1\"",
        "img-auth-isdir": "คุณกำลังพยายามเข้าถึงสารบบ \"$1\"\nอนุญาตเฉพาะการเข้าถึงไฟล์",
        "img-auth-streaming": "กำลังดึงข้อมูล \"$1\"",
        "linkstoimage-redirect": "$1 (ไฟล์เปลี่ยนทาง) $2",
        "duplicatesoffile": "$1 ไฟล์ต่อไปนี้ เป็นไฟล์เดียวกับไฟล์นี้ ([[Special:FileDuplicateSearch/$2|รายละเอียดเพิ่มเติม]]):",
        "sharedupload": "ไฟล์นี้มาจาก $1 และอาจมีใช้ในโครงการอื่น",
-       "sharedupload-desc-there": "ไฟล์นี้มาจาก $1 และอาจใช้บนโครงการอื่น\nกรุณาดู[หน้าคำอธิบายไฟล์ $2] สำหรับข้อมูลเพิ่มเติม",
+       "sharedupload-desc-there": "ไฟล์นี้มาจาก $1 และอาจใช้บนโครงการอื่น\nกรุณาดูสารสนเทศเพิ่มเติมที่ [$2 หน้าคำอธิบายไฟล์]",
        "sharedupload-desc-here": "ไฟล์นี้มาจาก $1 และอาจมีใช้ในโครงการอื่น\nคำอธิบายใน[$2 หน้าคำอธิบายไฟล์]แสดงไว้ด้านล่างนี้",
        "sharedupload-desc-edit": "ไฟล์นี้มาจาก $1 และอาจมีใช้ในโครงการอื่น\nคุณอาจต้องการแก้ไขคำอธิบายใน[$2 หน้าคำอธิบายไฟล์]นั้น",
        "sharedupload-desc-create": "ไฟล์นี้มาจาก $1 และอาจมีใช้ไฟล์นี้ในโครงการอื่น\nคุณอาจต้องการแก้ไขคำอธิบายใน[$2 หน้าคำอธิบายไฟล์]นั้น",
        "suppress": "ระงับ",
        "querypage-disabled": "หน้าพิเศษนี้ถูกปิดใช้งานด้วยเหตุผลด้านสมรรถภาพ",
        "apihelp-no-such-module": "ไม่พบมอดูล \"$1\"",
+       "apisandbox": "ทดลองเขียนเอพีไอ",
        "apisandbox-api-disabled": "ไซต์นี้ไม่เปิดใช้ API",
        "apisandbox-submit": "ส่งคำขอ",
        "apisandbox-reset": "ล้าง",
        "categoriesfrom": "แสดงหมวดหมู่เริ่มจาก:",
        "deletedcontributions": "การเข้ามีส่วนร่วมของผู้ใช้ที่ถูกลบ",
        "deletedcontributions-title": "การเข้ามีส่วนร่วมของผู้ใช้ที่ถูกลบ",
-       "sp-deletedcontributions-contribs": "à¹\80รืà¹\88อà¸\87à¸\97ีà¹\88มีส่วนร่วม",
+       "sp-deletedcontributions-contribs": "à¸\81ารà¹\80à¸\82à¹\89ามีส่วนร่วม",
        "linksearch": "ค้นหาลิงก์ภายนอก",
        "linksearch-pat": "รูปแบบการค้นหา:",
        "linksearch-ns": "เนมสเปซ:",
        "unwatchthispage": "เลิกเฝ้าดูหน้านี้",
        "notanarticle": "ไม่ใช่หน้าเนื้อหา",
        "notvisiblerev": "รุ่นล่าสุดโดยผู้ใช้อีกคนถูกลบแล้ว",
-       "watchlist-details": "มี $1 หน้าในรายการเฝ้าดูของคุณ (รวมหน้าคุย)",
+       "watchlist-details": "{{PLURAL:$1|มี $1 หน้า|มี $1 หน้า}}ในรายการเฝ้าดูของคุณ (รวมหน้าคุย)",
        "wlheader-enotif": "เปิดใช้งานการแจ้งเตือนผ่านอีเมล",
        "wlheader-showupdated": "หน้าที่มีการเปลี่ยนแปลงตั้งแต่คุณเยี่ยมครั้งสุดท้ายแสดงด้วย<strong>ตัวหนา</strong>",
        "wlnote": "ด้านล่างเป็น{{PLURAL:$1|การเปลี่ยนแปลงหลังสุด| <strong>$1</strong> การเปลี่ยนแปลงหลังสุด}} ใน{{PLURAL:$2|ชั่วโมง| <strong>$2</strong> ชั่วโมง}}ที่หลังสุด จนถึง $3, $4",
        "delete-confirm": "ลบ \"$1\"",
        "delete-legend": "ลบ",
        "historywarning": "<strong>คำเตือน:</strong> หน้าที่คุณกำลังลบมีประวัติ $1 {{PLURAL:$1|รุ่น}}:",
-       "historyaction-submit": "แสดง",
+       "historyaction-submit": "แสดงรุ่นแก้ไข",
        "confirmdeletetext": "คุณกำลังลบหน้า รวมทั้งประวัติทั้งหมดของหน้า\nกรุณายืนยันว่าคุณเจตนา เข้าใจผลกระทบ และการกระทำนี้สอดคล้องกับ[[{{MediaWiki:Policy-url}}|นโยบาย]]",
        "actioncomplete": "ปฏิบัติการสำเร็จ",
        "actionfailed": "ปฏิบัติการล้มเหลว",
        "deleting-backlinks-warning": "<strong>คำเตือน:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|หน้าอื่น]]เชื่อมโยงมายังหรือดึงข้อมูลจากหน้าที่คุณกำลังจะลบ",
        "deleting-subpages-warning": "<strong>คำเตือน:</strong> หน้าที่คุณกำลังจะลบมี[[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|หน้าย่อย $ หน้า|51=มากกว่า 50 หน้า}}]]",
        "rollback": "ย้อนการแก้ไขรวดเดียว",
+       "rollback-confirmation-confirm": "กรุณายืนยัน:",
+       "rollback-confirmation-yes": "ย้อนรวดเดียว",
+       "rollback-confirmation-no": "ยกเลิก",
        "rollbacklink": "ย้อนรวดเดียว",
        "rollbacklinkcount": "ย้อนรวดเดียว $1 การแก้ไข",
        "rollbacklinkcount-morethan": "ย้อนรวดเดียวกว่า $1 การแก้ไข",
        "editcomment": "คำอธิบายการแก้ไขคือ: <em>$1</em>",
        "revertpage": "ย้อนการแก้ไขโดย [[Special:Contributions/$2|$2]] ([[User talk:$2|คุย]]) ไปยังรุ่นแก้ไขล่าสุดโดย [[User:$1|$1]]",
        "revertpage-nouser": "ย้อนการแก้ไขโดยผู้ใช้ไม่ระบุชื่อไปยังรุ่นล่าสุดโดย {{GENDER:$1|[[User:$1|$1]]}}",
-       "rollback-success": "ย้อนการแก้ไขโดย $1; \nเปลี่ยนกลับไปรุ่นล่าสุดโดย $2",
-       "rollback-success-notify": "ย้อนการแก้ไขโดย $1;\nเปลี่ยนกลับไปรุ่นล่าสุดโดย $2 [$3 แสดงการเปลี่ยนแปลง]",
+       "rollback-success": "ย้อนการแก้ไขโดย {{GENDER:$3|$1}};\nเปลี่ยนกลับไปรุ่นล่าสุดโดย {{GENDER:$4|$2}}",
        "sessionfailure-title": "เซสชันล้มเหลว",
        "sessionfailure": "ดูเหมือนมีปัญหากับเซสชันการเข้าสู่ระบบของคุณ\nการกระทำนี้ถูกยกเลิกเพื่อเป็นการป้องกันการลักลอบเซสชันไว้ก่อน \nกรุณากรอกแบบฟอร์มใหม่อีกครั้ง",
        "changecontentmodel-title-label": "ชื่อหน้า:",
        "logentry-contentmodel-change-revert": "ย้อน",
        "protectlogpage": "ปูมการป้องกัน",
        "protectlogtext": "ด้านล่างเป็นรายการการเปลี่ยนแปลงการล็อกหน้า\nดู[[Special:ProtectedPages|รายการหน้าที่ถูกล็อก]]สำหรับการล็อกหน้าที่มีผลอยู่ในปัจจุบัน",
-       "protectedarticle": "à¹\84à¸\94à¹\89à¸\9bà¹\89อà¸\87à¸\81ัà¸\99 \"[[$1]]\"",
+       "protectedarticle": "à¸\9bà¹\89อà¸\87à¸\81ัà¸\99 \"[[$1]]\" à¹\81ลà¹\89ว",
        "modifiedarticleprotection": "เปลี่ยนระดับการล็อกของ \"[[$1]]\"",
        "unprotectedarticle": "ยกเลิกการล็อกจาก \"[[$1]]\"",
-       "movedarticleprotection": "ยà¹\89ายà¸\81ารà¸\95ัà¹\89à¸\87à¸\84à¹\88าà¸\81ารลà¹\87อà¸\81à¸\88าà¸\81 \"[[$2]]\" à¹\84à¸\9b \"[[$1]]\"",
-       "protectedarticle-comment": "ป้องกัน \"[[$1]]\"",
+       "movedarticleprotection": "ยà¹\89ายà¸\81ารà¸\95ัà¹\89à¸\87à¸\84à¹\88าà¸\81ารà¸\9bà¹\89อà¸\87à¸\81ัà¸\99à¸\88าà¸\81 \"[[$2]]\" à¹\84à¸\9b \"[[$1]]\" à¹\81ลà¹\89ว",
+       "protectedarticle-comment": "ป้องกัน \"[[$1]]\" แล้ว",
        "modifiedarticleprotection-comment": "{{GENDER:$2|}}เปลี่ยนระดับการล็อกสำหรับ \"[[$1]]\"",
-       "unprotectedarticle-comment": "{{GENDER:$2|}}ปลดล็อก \"[[$1]]\"",
+       "unprotectedarticle-comment": "{{GENDER:$2|ยกเลิกการป้องกัน}}จาก \"[[$1]]\"",
        "protect-title": "เปลี่ยนระดับการล็อกสำหรับ \"$1\"",
        "protect-title-notallowed": "ดูระดับการล็อกของ \"$1\"",
        "prot_1movedto2": "ย้าย [[$1]] เป็น [[$2]]",
        "mycontris": "ส่วนร่วม",
        "anoncontribs": "ส่วนร่วม",
        "contribsub2": "สำหรับ {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "สำหรับ {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "บัญชีผู้ใช้ \"$1\" ยังไม่ได้ลงทะเบียน",
+       "negative-namespace-not-supported": "ไม่รองรับเนมสเปซที่มีค่าเป็นลบ",
        "nocontribs": "ไม่พบการเปลี่ยนแปลงตรงกับเงื่อนไขเหล่านี้",
        "uctop": "ปัจจุบัน",
        "month": "ตั้งแต่เดือน (และก่อนหน้า):",
        "proxyblockreason": "เลขที่อยู่ไอพีของคุณถูกบล็อกเนื่องจากเป็นพร็อกซีเปิด กรุณาติดต่อผู้ให้บริการอินเทอร์เน็ตหรือฝ่ายสนับสนุนเทคนิคขององค์การคุณ และแจ้งให้พวกเขาทราบถึงปัญหาความปลอดภัยร้ายแรงนี้",
        "sorbsreason": "เลขที่อยู่ไอพีของคุณอยู่ในพร็อกซีเปิดในส่วน DNSBL ที่ {{SITENAME}} ใช้",
        "sorbs_create_account_reason": "เลขที่อยู่ไอพีของคุณอยู่ในพร็อกซีเปิดในส่วน DNSBL ที่ {{SITENAME}} ใช้ \nคุณไม่สามารถสร้างบัญชีได้",
+       "softblockrangesreason": "ไม่อนุญาตการมีส่วนร่วมแบบนิรามจากเลขที่อยู่ไอพีของคุณ ($1) กรุณาล็อกอิน",
        "cant-see-hidden-user": "ผู้ใช้ที่คุณกำลังพยายามระงับนั้นได้ถูกระงับหรือซ่อนเดิมอยู่แล้ว เนื่องจากคุณไม่มีสิทธิซ่อนผู้ใช้ คุณจึงไม่สามารถดูหรือแก้ไขการระงับผู้ใช้ได้",
        "ipbblocked": "คุณไม่สามารถบล็อกหรือปลดบล็อกผู้ใช้คนอื่น เนื่องจากคุณกำลังถูกบล็อก",
        "ipbnounblockself": "คุณไม่ได้รับอนุญาตให้ปลดบล็อกตนเอง",
        "move-watch": "เฝ้าดูหน้าต้นทางและหน้าปลายทาง",
        "movepagebtn": "ย้ายหน้า",
        "pagemovedsub": "ย้ายสำเร็จ",
+       "cannotmove": "ไม่สามารถย้ายหน้านี้ได้ ด้วยเหตุผลต่อไปนี้:",
        "movepage-moved": "<strong>เปลี่ยนชื่อ \"$1\" เป็น \"$2\" แล้ว</strong>",
        "movepage-moved-redirect": "สร้างหน้าเปลี่ยนทางแล้ว",
        "movepage-moved-noredirect": "การสร้างหน้าเปลี่ยนทางถูกระงับ",
+       "movepage-delete-first": "หน้าเป้าหมายมีรุ่นแก้ไขมากเกินไปทำให้ลบหน้าระหว่างที่ย้ายหน้าไม่ได้ กรุณาลบหน้าด้วยมือก่อนแล้วลองอีกครั้ง",
        "articleexists": "หน้าที่ต้องการมีอยู่แล้ว หรือชื่อที่เลือกไม่ถูกต้อง กรุณาเลือกชื่อใหม่",
        "cantmove-titleprotected": "คุณไม่สามารถเปลี่ยนชื่อหน้าเป็นชื่อนี้ได้ เนื่องจากชื่อเรื่องใหม่ถูกป้องกันมิให้สร้าง",
        "movetalk": "ย้ายหน้าคุยที่สัมพันธ์",
        "allmessagesdefault": "เนื้อหาข้อความปริยาย",
        "allmessagescurrent": "ข้อความปัจจุบัน",
        "allmessagestext": "นี่คือรายการข้อความของระบบที่อยู่ในเนมสเปซมีเดียวิกิ\nกรุณาอ่านหน้า[https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation เทศวิวัตน์ของมีเดียวิกิ] และ [https://translatewiki.net translatewiki.net] หากคุณอยากที่จะช่วยแปลข้อความของระบบมีเดียวิกิ",
-       "allmessagesnotsupportedDB": "หน้านี้ไม่สามารถใช้งานได้เนื่องจาก '''$wgUseDatabaseMessages''' ถูกระงับการใช้งาน",
+       "allmessages-not-supported-database": "หน้านี้ไม่สามารถใช้งานได้เนื่องจาก '''$wgUseDatabaseMessages''' ถูกระงับการใช้งาน",
        "allmessages-filter-legend": "กรอง",
        "allmessages-filter": "กรองตามสถานะที่เลือก:",
        "allmessages-filter-unmodified": "ไม่ดัดแปร",
        "tag-list-wrapper": "[[Special:Tags|{{PLURAL:$1|Tag|ป้ายระบุ}}]]: $2",
        "tag-mw-new-redirect": "เปลี่ยนทางใหม่",
        "tag-mw-new-redirect-description": "การแก้ไขที่สร้างหน้าเปลี่ยนทางใหม่หรือเปลี่ยนแปลงหน้าเป็นหน้าเปลี่ยนทาง",
-       "tag-mw-removed-redirect": "ลà¸\9aหà¸\99à¹\89าà¹\80à¸\9bลà¹\88ีà¹\88ยà¸\99à¸\97าà¸\87",
+       "tag-mw-removed-redirect": "ลบหน้าเปลี่ยนทาง",
        "tag-mw-removed-redirect-description": "การแก้ไขี่เปลี่ยนหน้าเปลีี่ยนทางเดิมให้มิใช่หน้าเปลี่ยนทาง",
        "tag-mw-changed-redirect-target": "เปลี่ยนเป้าหมายหน้าเปลี่ยนทาง",
        "tag-mw-changed-redirect-target-description": "การแก้ไขที่เปลี่ยนเป้าหมายของหน้าเปลี่ยนทาง",
        "logentry-newusers-byemail": "บัญชีผู้ใช้ $3 ถูกสร้างขึ้นโดย $1 และส่งรหัสผ่านไปทางอีเมลแล้ว",
        "logentry-newusers-autocreate": "บัญชีผู้ใช้ $1 ถูกสร้างขึ้นอัตโนมัติ",
        "logentry-protect-move_prot": "$1 ย้ายการตั้งค่าการล็อกจาก $4 ไป $3",
-       "logentry-protect-unprotect": "$1 ลบการล็อกจาก $3",
-       "logentry-protect-protect": "$1 {{GENDER:$2|à¹\84à¸\94à¹\89à¸\9bà¹\89อà¸\87à¸\81ัà¸\99}} $3 $4",
-       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|à¹\84à¸\94à¹\89à¸\9bà¹\89อà¸\87à¸\81ัà¸\99}} $3 $4 [à¸\95à¹\88อà¹\80รียà¸\87]",
+       "logentry-protect-unprotect": "$1 {{GENDER:$2|ยกเลิก}}การป้องกันจาก $3",
+       "logentry-protect-protect": "$1 {{GENDER:$2|ป้องกัน}} $3 $4",
+       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|ป้องกัน}} $3 $4 [ต่อเรียง]",
        "logentry-protect-modify": "$1 เปลี่ยนระดับการตั้งค่าสำหรับ $3 $4",
        "logentry-protect-modify-cascade": "$1 เปลี่ยนระดับการตั้งค่าสำหรับ $3 $4 [ต่อเรียง]",
        "logentry-rights-rights": "$1 {{GENDER:$2|เปลี่ยน}}กลุ่มสมาชิกของ $3 จาก $4 เป็น $5",
        "log-name-tag": "ปูมป้ายระบุ",
        "log-description-tag": "หน้านี้แสดงเมื่อผู้ใช้เพิ่มหรือลบ[[Special:Tags|ป้ายระบุ]]จากรุ่นแก้ไขหรือรายการปูมอันใดอันหนึ่ง ปูมนี้ไม่แสดงรายการการกระทำติดป้ายระบุเมื่อเกิดเป็นส่้วนหนึ่งของการแก้ไข การลบหรือการกระทำที่คล้ายกัน",
        "rightsnone": "(ไม่มี)",
+       "rightslogentry-temporary-group": "$1 (ชั่วคราว จนถึง $2)",
        "feedback-adding": "เพิ่มคำติชมเข้าไปที่หน้า...",
        "feedback-bugcheck": "ยอดเยี่ยม! เพียงตรวจสอบว่าจุดบกพร่องนั้นมิใช่หนึ่งใน[$1 จุดบกพร่องที่ทราบแล้ว]",
        "feedback-bugnew": "ฉันตรวจสอบแล้ว รายงานจุดบกพร่องใหม่",
        "log-action-filter-newusers-byemail": "การสร้างโดยรหัสผ่านที่ส่งทางอีเมล",
        "log-action-filter-patrol-patrol": "การตรวจสอบหน้าด้วยมือ",
        "log-action-filter-patrol-autopatrol": "การตรวจสอบหน้าอัตโนมัติ",
-       "log-action-filter-protect-protect": "à¸\81ารลà¹\87อà¸\81",
-       "log-action-filter-protect-modify": "à¸\81ารà¹\81à¸\81à¹\89à¹\84à¸\82à¸\81ารลà¹\87อà¸\81",
-       "log-action-filter-protect-unprotect": "à¸\9bลà¸\94ลà¹\87อà¸\81",
-       "log-action-filter-protect-move_prot": "à¸\81ารลà¹\87อà¸\81ที่ถูกย้าย",
+       "log-action-filter-protect-protect": "à¸\81ารà¸\9bà¹\89อà¸\87à¸\81ัà¸\99",
+       "log-action-filter-protect-modify": "à¸\81ารà¹\81à¸\81à¹\89à¹\84à¸\82à¸\81ารà¸\9bà¹\89อà¸\87à¸\81ัà¸\99",
+       "log-action-filter-protect-unprotect": "à¹\80ลิà¸\81à¸\9bà¹\89อà¸\87à¸\81ัà¸\99",
+       "log-action-filter-protect-move_prot": "à¸\81ารà¸\9bà¹\89อà¸\87à¸\81ัà¸\99ที่ถูกย้าย",
        "log-action-filter-rights-rights": "การเปลี่ยนด้วยมือ",
        "log-action-filter-rights-autopromote": "การเปลี่ยนอัตโนมัติ",
        "log-action-filter-suppress-event": "การระงับปูม",
        "passwordpolicies-policy-passwordcannotmatchusername": "ห้ามรหัสผ่านซ้ำกับชื่อผู้ใช้",
        "passwordpolicies-policy-passwordcannotmatchblacklist": "ห้ามรหัสผ่านตรงกับรหัสผ่านที่ขึ้นบัญชีดำโดยเจาะจง",
        "passwordpolicies-policy-maximalpasswordlength": "รหัสผ่านจะต้องมีความยาวน้อยกว่า $1 อักขระ",
-       "passwordpolicies-policy-passwordcannotbepopular": "ห้ามรหัสผ่านเป็น{{PLURAL:$1|รหัสผ่านยอดนิยม|ติดรายการ $1 รหัสผ่านยอดนิยม}}"
+       "passwordpolicies-policy-passwordcannotbepopular": "ห้ามรหัสผ่านเป็น{{PLURAL:$1|รหัสผ่านยอดนิยม|ติดรายการ $1 รหัสผ่านยอดนิยม}}",
+       "userlogout-continue": "หากคุณต้องการออกจากระบบ โปรด[$1 ดำเนินการต่อไปยังหน้าออกจากระบบ]",
+       "userlogout-sessionerror": "การออกจากระบบล้มเหลวเนื่องจากเซสชันผิดพลาด โปรด[$1 ลองอีกครั้ง]"
 }
index 2ca7e8b..3fa6e91 100644 (file)
        "minoreditletter": "uj",
        "newpageletter": "T",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|ulanyjy|ulanyjy}} gözegçilik edýär]",
        "newsectionsummary": "/* $1 */ täze bölüm",
        "rc-enhanced-expand": "Jikme-jikligi görkez",
        "rc-enhanced-hide": "Jikme-jiklikleri gizle",
        "img-auth-nopathinfo": "PATH_INFO ýok.\nSerweriňiz bu maglumaty geçirmeklik üçin sazlanmandyr.\nCGI esaslanýan hem-de img_auth-y goldamaýan bolmagy mümkin.\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization sahypasyna serediň.",
        "img-auth-notindir": "Talap edlýän ýol sazlanan ýükleme direktoriýasynda däl.",
        "img-auth-badtitle": "\"$1\" bilen dogry bir at gurup bolanok.",
-       "img-auth-nologinnWL": "Sessiýa açmansyňyz, \"$1\" bolsa ak sanawda däl.",
        "img-auth-nofile": "\"$1\" faýly ýok.",
        "img-auth-isdir": "\"$1\" katalogyna barmaga synanyşýarsyňyz.\nDiňe faýla barmaklyga rugsat berilýär.",
        "img-auth-streaming": "\"$1\" akymlaýyn görkezilýär.",
        "allmessagesdefault": "Gaýybana habarlaşyk teksti",
        "allmessagescurrent": "Häzirki habarlaşyk teksti",
        "allmessagestext": "Bu sanaw MediaWiki at giňişliginde bar bolan ulgam habarlaşyklarynyň sanawydyr.\nUmumy MediaWiki lokalizasiýasyna goşan goşmak isleýän bolsaňyz, [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki lokalizasiýasy] we [https://translatewiki.net translatewiki.net] sahypalaryna baryp görmegiňizi haýyş edýäris.",
-       "allmessagesnotsupportedDB": "'''$wgUseDatabaseMessages''' ýapykdygy zerarly bu sahypany ulanyp bolmaýar.",
+       "allmessages-not-supported-database": "'''$wgUseDatabaseMessages''' ýapykdygy zerarly bu sahypany ulanyp bolmaýar.",
        "allmessages-filter-legend": "Filtr",
        "allmessages-filter": "Üýtgediş statusy boýunça filtr:",
        "allmessages-filter-unmodified": "Üýtgedilmedik",
index 2a8d093..215c2de 100644 (file)
        "newpageletter": "B",
        "boteditletter": "b",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 binabantayang {{PLURAL:$1|tagagamit|mga tagagamit}}]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte}} pagkaraan ng pagbabago",
        "newsectionsummary": "/* $1 */ bagong seksyon",
        "img-auth-nopathinfo": "Nawawala ang PATH_INFO.\nAng tagapaghain mo ay hindi nakatakda na magpasa ng ganitong kabatiran.\nMaaaring pang-CGI ito at hindi sumusuporta ng img_auth.\nTingnan ang https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Ang hiniling na daan ay wala sa loob ng isinaayos na direktoryo ng pagkarga.",
        "img-auth-badtitle": "Hindi nagawang makabuo ng tanggap na pamagat mula sa \"$1\".",
-       "img-auth-nologinnWL": "Hindi ka nakalagda at ang \"$1\" ay wala sa puting talaan.",
        "img-auth-nofile": "Hindi umiiral ang talaksang \"$1\".",
        "img-auth-isdir": "Sinusubok mong puntahan ang direktoryong \"$1\".\nTanging ang pagpunta lang sa talaksan ang pinapayagan.",
        "img-auth-streaming": "Pinapaagos ang \"$1\".",
        "allmessagesdefault": "Tinakdang teksto",
        "allmessagescurrent": "Kasalukuyang teksto",
        "allmessagestext": "Isa itong talaan ng mga mensahe ng sistema na makukuha mula sa namespace ng MediaWiki.\nPakidalaw ang [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Lokalisasyong MediaWiki] at [https://translatewiki.net translatewiki.net] kung ibig mong magambag sa heneriko o pangkalahatang lokalisasyon ng MediaWiki.",
-       "allmessagesnotsupportedDB": "Hindi magagamit ang '''{{ns:special}}:AllMessages''' dahil hindi gumagana ang '''$wgUseDatabaseMessages'''.",
+       "allmessages-not-supported-database": "Hindi magagamit ang '''{{ns:special}}:AllMessages''' dahil hindi gumagana ang '''$wgUseDatabaseMessages'''.",
        "allmessages-filter-legend": "Salain",
        "allmessages-filter": "Salain ayon sa katayuan ng pagbabagay:",
        "allmessages-filter-unmodified": "Hindi pa nababago",
index bfa144d..d47c030 100644 (file)
@@ -5,7 +5,8 @@
                        "Ganbarzada",
                        "Tuzkozbir",
                        "Гусейн",
-                       "아라"
+                       "아라",
+                       "Baskervill"
                ]
        },
        "tog-underline": "Линки жинтоно ријә быкәш:",
        "newuserlogpage": "Иштирокәкон ғеидијоти журнал",
        "action-edit": "Ым сәһифә сәрост кардеј",
        "nchanges": "$1 {{PLURAL:$1|дәгиши|дәгишон}}",
+       "enhancedrc-history": "Tarıx",
        "recentchanges": "Ән нујә дәгишон",
        "recentchanges-legend": "Ән нујә дәгишон кукон",
        "recentchanges-summary": "Тәмшо быкән бы сәһифәдә че вики охоминә дәгишон нишо доә быән.",
index 8387a26..069bdb9 100644 (file)
        "allmessagesdefault": "Tohi tuʻunga",
        "allmessagescurrent": "Tohi lolotonga",
        "allmessagestext": "Ko e hokohoko ʻeni ʻo e ngaahi tala fakafounga kātoa ʻi he vā hingoa ''MediaWiki''.",
-       "allmessagesnotsupportedDB": "ʻOku ʻikai ngāueʻaki mo e '''{{ns:special}}:Allmessages''' koeʻuhi ʻoku kamosiʻi mate ʻa e '''$wgUseDatabaseMessages'''.",
+       "allmessages-not-supported-database": "!!FUZZY!!ʻOku ʻikai ngāueʻaki mo e '''{{ns:special}}:Allmessages''' koeʻuhi ʻoku kamosiʻi mate ʻa e '''$wgUseDatabaseMessages'''.",
        "filemissing": "ʻOku pulia ʻa e faile",
        "import": "Hū mai ngaahi peesi",
        "importinterwiki": "Hū mai ʻo e fakalava ''wiki''",
index 2ad4915..4333659 100644 (file)
        "page_first": "ilk",
        "page_last": "son",
        "histlegend": "Fark seçimi: Karşılaştırmayı istediğiniz 2 sürümün önündeki daireleri işaretleyip, \"{{int:Compareselectedversions}}\" düğmesine basın.<br />\nTanımlar: '''({{int:cur}})''' = son revizyon ile arasındaki fark, '''({{int:last}})''' = bir önceki revizyon ile arasındaki fark, '''{{int:minoreditletter}}''' = küçük değişiklik.",
-       "history-fieldset-title": "Geçmişe gözat",
+       "history-fieldset-title": "Revizyonları filtrele",
        "history-show-deleted": "Sadece silinen sürümler",
        "histfirst": "en eski",
        "histlast": "en yeni",
        "historysize": "({{PLURAL:$1|1 bayt|$1 bayt}})",
-       "historyempty": "(boş)",
+       "historyempty": "boş",
        "history-feed-title": "Değişiklik geçmişi",
        "history-feed-description": "Viki üzerindeki bu sayfanın değişiklik geçmişi.",
        "history-feed-item-nocomment": "$1, $2'de",
        "right-reupload-own": "Kendisinin yüklediği bir dosyanın üzerine yaz",
        "right-reupload-shared": "Paylaşılan ortam deposundaki dosyaları yerel olarak geçersiz kıl",
        "right-upload_by_url": "Bir URL adresinden dosya yükle",
-       "right-purge": "Doğrulama yapmadan bir sayfa için site belleğini temizle",
+       "right-purge": "Bir sayfa için site önbelleğini temizle",
        "right-autoconfirmed": "IP-tabanlı hız limitleri etkilenme",
        "right-bot": "Otomatik bir işlem gibi muamele gör",
        "right-nominornewtalk": "Kullanıcı tartışma sayfalarında yaptığı küçük değişiklikler kullanıcıya yeni mesaj bildirimiyle bildirilmez",
        "grant-delete": "Sayfaları, sürümleri ve günlük girdileri sil",
        "grant-editinterface": "MediaWiki alanadını, sitewide'ı ve kullanıcı JSON'unu düzenle",
        "grant-editmycssjs": "Kullanıcı CSS/JSON/JavaScript'ini düzenle",
-       "grant-editmyoptions": "Kullanıcı tercihlerini Düzenle",
+       "grant-editmyoptions": "Kullanıcı tercihlerinizi ve JSON yapılandırmanızı düzenleyin",
        "grant-editmywatchlist": "İzleme listeni düzenle",
        "grant-editsiteconfig": "Sitewide ve kullanıcı CSS/JS değiştir",
        "grant-editpage": "Mevcut sayfaları düzenle",
        "rcfilters-savedqueries-already-saved": "Bu filtreler zaten kaydedildi. Yeni bir Kayıtlı Filtre oluşturmak için ayarlarınızı değiştirin.",
        "rcfilters-restore-default-filters": "Varsayılan süzgeçleri geri getir",
        "rcfilters-clear-all-filters": "Tüm süzgeçleri temizle",
-       "rcfilters-show-new-changes": "Yeni değişiklikleri görüntüle",
+       "rcfilters-show-new-changes": "$1 tarihinden bu yana yapılan yeni değişiklikleri görüntüleyin",
        "rcfilters-search-placeholder": "Son değişiklikleri filtrele (menüyü kullanın veya süzgeç adını arayın)",
        "rcfilters-invalid-filter": "Geçersiz süzgeç",
        "rcfilters-empty-filter": "Etkin süzgeç bulunmuyor. Tüm katkıları gösteriliyor.",
        "rcfilters-filter-editsbyself-description": "Kendi katkılarınız.",
        "rcfilters-filter-editsbyother-label": "Başkalarının düzenlemeleri",
        "rcfilters-filter-editsbyother-description": "Kendi düzenlemeleriniz hariç bütün düzenlemeler.",
-       "rcfilters-filtergroup-userExpLevel": "Kullanıcı kaydı ve deneyim",
+       "rcfilters-filtergroup-user-experience-level": "Kullanıcı kaydı ve deneyim",
        "rcfilters-filter-user-experience-level-registered-label": "Kayıtlı",
        "rcfilters-filter-user-experience-level-registered-description": "Oturum açmış editörler.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Kayıtlı olmayan",
        "rcfilters-filter-categorization-description": "Kategorilere eklenen veya kaldırılan sayfaların kayıtları.",
        "rcfilters-filter-logactions-label": "Günlüğü tutulan işlemler",
        "rcfilters-filter-logactions-description": "Hizmetli işlemleri, hesap oluşturmalar, sayfa silmeler, yüklemeler...",
-       "rcfilters-filtergroup-lastRevision": "En son sürümler",
+       "rcfilters-filtergroup-lastrevision": "En son sürümler",
        "rcfilters-filter-lastrevision-label": "Son revizyon",
        "rcfilters-filter-lastrevision-description": "Bir sayfadaki en yeni değişiklik.",
        "rcfilters-filter-previousrevision-label": "Son revizyon değil",
        "rcfilters-watchlist-markseen-button": "Tüm değişiklikleri görüldü olarak işaretle",
        "rcfilters-watchlist-edit-watchlist-button": "İzlenen sayfaların listesini düzenle",
        "rcfilters-watchlist-showupdated": "Gerçekleştirilen değişikliklerden bu yana ziyaret etmediğiniz sayfalarda yapılan değişiklikler <strong>koyu</strong> renktedir.",
-       "rcfilters-preference-label": "Son değişikliklerin geliştirilmiş sürümünü gizle",
-       "rcfilters-preference-help": "2017 arayüz tasarımını ve bu andan sonra eklenen tüm araçları geri alır.",
-       "rcfilters-watchlist-preference-label": "İzleme listesinin geliştirilmiş sürümünü gizle",
-       "rcfilters-watchlist-preference-help": "2017 arayüz tasarımını ve bu andan sonra eklenen tüm araçları geri alır.",
+       "rcfilters-preference-label": "JavaScript olmayan bir arayüz kullanın",
+       "rcfilters-preference-help": "Filtre olmadan arama yapma veya işlevselliği vurgulamadan SonDeğişiklikler'i yükler.",
+       "rcfilters-watchlist-preference-label": "JavaScript olmayan bir arayüz kullanın",
+       "rcfilters-watchlist-preference-help": "Filtre Listesini arama olmadan veya işlevselliği vurgulayarak İzleme Listesi'ni yükler.",
        "rcfilters-target-page-placeholder": "Bir sayfa (ya da kategori) adı girin",
        "rcnotefrom": "<strong>$3, $4</strong> tarihinden itibaren yapılan {{PLURAL:$5|değişiklik|değişiklik}} aşağıdadır (<strong>$1</strong> tarhine kadar olanlar gösterilmektedir).",
        "rclistfromreset": "Tarih seçimini sıfırla",
        "minoreditletter": "k",
        "newpageletter": "Y",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 izlenilen {{PLURAL:$1|kullanıcı|kullanıcı}}]",
        "rc-change-size-new": "Değişiklikten sonraki boyut: $1 {{PLURAL:$1|bayt|bayt}}",
        "newsectionsummary": "/* $1 */ yeni başlık",
        "rc-enhanced-expand": "Ayrıntıları göster",
        "img-auth-nopathinfo": "Eksik path bilgilendirmesi.\nSunucunuz REQUEST_URI and/or PATH_INFO değişlenlerini geçirmek için ayarlanmış olmalıdır.\nEğer etkinse, $wgUsePathInfo'i etkinleştirmeyi deneyin.\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization sayfasına bakın.",
        "img-auth-notindir": "İstenen yol yapılandırılmış yükleme dizininde değil.",
        "img-auth-badtitle": "\"$1\" ile geçerli bir başlık yapılamıyor.",
-       "img-auth-nologinnWL": "Giriş yapmadınız ve \"$1\" beyaz listede değil.",
        "img-auth-nofile": "\"$1\" dosyası mevcut değil.",
        "img-auth-isdir": "\"$1\" dizinine erişmeye çalışıyorsunuz.\nSadece dosya erişimine izin veriliyor.",
        "img-auth-streaming": "\"$1\" oynatılıyor.",
        "apisandbox-loading-results": "API sonuçları alınıyor...",
        "apisandbox-results-error": "API sorgusu yanıtı yüklenirken bir hata oluştu: $1.",
        "apisandbox-request-url-label": "İstek URL:",
-       "apisandbox-request-time": "İstek zamanı: $1",
+       "apisandbox-request-time": "İstek zamanı: {{PLURAL:$1|$1 ms}}",
        "apisandbox-continue": "Devam et",
        "apisandbox-continue-clear": "Temizle",
        "apisandbox-multivalue-all-namespaces": "$1 (Tüm isim alanları)",
        "watchlistanontext": "Lütfen izleme listenizdeki maddeleri görmek ya da değiştirmek için oturum açın.",
        "watchnologin": "Oturum açık değil.",
        "addwatch": "İzleme listesine ekle",
-       "addedwatchtext": "\"[[:$1]]\" sayfası [[Special:Watchlist|izleme listenize]] eklenmiştir.\nBundan sonra, bu sayfaya ve ilgili tartışma sayfasına yapılacak değişiklikler burada listelenecek.",
+       "addedwatchtext": "\"[[:$1]]\" ve ona ait tartışma sayfası [[Special:Watchlist|izleme listenize]] eklenmiştir.",
        "addedwatchtext-short": "\"$1\" sayfası izleme listenize eklendi.",
        "removewatch": "İzleme listesinden kaldır",
-       "removedwatchtext": "\"[[:$1]]\" sayfası, tartışma sayfası ile birlikte [[Special:Watchlist|izleme listenizden]] silinmiştir.",
+       "removedwatchtext": "\"[[:$1]]\" ve ona ait tartışma sayfası ile birlikte [[Special:Watchlist|izleme listenizden]] silinmiştir.",
        "removedwatchtext-short": "\"$1\" sayfası izleme listenizden çıkarıldı.",
        "watch": "izle",
        "watchthispage": "Sayfayı izle",
        "enotif_body_intro_moved": "{{SITENAME}} sayfası $1, $2 tarafından $PAGEEDITDATE tarihinde {{GENDER:$2|taşındı}}, mevcut revizyon için bakınız: $3.",
        "enotif_body_intro_restored": "{{SITENAME}} sayfası $1, $2 tarafından $PAGEEDITDATE tarihinde {{GENDER:$2|geri getirildi}}, mevcut revizyon için bakınız: $3.",
        "enotif_body_intro_changed": "{{SITENAME}} sayfası $1, $2 tarafından $PAGEEDITDATE tarihinde {{GENDER:$2|değiştirildi}}, mevcut revizyon için bakınız: $3.",
-       "enotif_lastvisited": "Son ziyaretinizden bu yana olan tüm değişiklikleri görmek için $1'e bakın.",
+       "enotif_lastvisited": "Son ziyaretinizden bu yana yapılan tüm değişiklikler için bakınız: $1",
        "enotif_lastdiff": "Bu değişikliği görmek için, $1 sayfasına bakınız.",
        "enotif_anon_editor": "anonim kullanıcı $1",
        "enotif_body": "Sayın $WATCHINGUSERNAME,\n\n$PAGEINTRO $NEWPAGE\n\nEditörün girdiği özet: $PAGESUMMARY $PAGEMINOREDIT\n\nEditörün iletişim bilgileri:\ne-posta: $PAGEEDITOR_EMAIL\nviki: $PAGEEDITOR_WIKI\n\nBahsi geçen sayfayı oturum açarak ziyaret edinceye kadar sayfayla ilgili başka bildirim gönderilmeyecektir. Ayrıca izleme listenizdeki tüm sayfaların bildirim durumlarını sıfırlayabilirsiniz.\n\n{{SITENAME}} bildirim sistemi\n\n--\nE-posta bildirim ayarlarınızı değiştirmek için aşağıdaki sayfayı ziyaret ediniz:\n{{canonicalurl:{{#special:Preferences}}}}\n\nİzleme listesi ayarlarınızı değiştirmek için aşağıdaki sayfayı ziyaret ediniz:\n{{canonicalurl:{{#special:EditWatchlist}}}}\n\nSayfayı izleme listenizden silmek için aşağıdaki sayfayı ziyaret ediniz:\n$UNWATCHURL\n\nGeri bildirim ve daha fazla yardım için:\n$HELPPAGE",
        "deletepage": "Sayfayı sil",
        "confirm": "Onayla",
        "excontent": "eski içerik: '$1'",
-       "excontentauthor": "eski içerik: '$1' ('[[Special:Contributions/$2|$2]]' katkıda bulunmuş olan tek kullanıcı)",
+       "excontentauthor": "eski içerik: '$1' ve katkıda bulunmuş olan tek kullanıcı \"[[Special:Contributions/$2|$2]]\" ([[User talk:$2|mesaj]])",
        "exbeforeblank": "Silinmeden önceki içerik: '$1'",
        "delete-confirm": "\"$1\" sayfasını sil",
        "delete-legend": "Sil",
        "historywarning": "<strong>Uyarı:</strong> Silmek üzere olduğunuz sayfanın yaklaşık olarak $1 sürüme sahip bir geçmişi var:",
-       "historyaction-submit": "Göster",
+       "historyaction-submit": "Revizyonları göster",
        "confirmdeletetext": "Bu sayfayı veya dosyayı tüm geçmişi ile birlikte veritabanından kalıcı olarak silmek üzeresiniz.\nBu işlemden kaynaklı doğabilecek sonuçların farkında iseniz ve işlemin [[{{MediaWiki:Policy-url}}|Silme kurallarına]] uygun olduğuna eminseniz, işlemi onaylayın.",
        "actioncomplete": "İşlem tamamlandı",
        "actionfailed": "İşlem başarısız oldu",
        "mycontris": "Katkılar",
        "anoncontribs": "Katkılar",
        "contribsub2": "{{GENDER:$3|$1}} ($2) tarafından",
+       "contributions-subtitle": "{{GENDER:$3|$1}} için",
        "contributions-userdoesnotexist": "\"$1\" kullanıcı hesabı kayıtlı değil.",
        "nocontribs": "Bu kriterlere uyan değişiklik bulunamadı",
        "uctop": "güncel",
        "sp-contributions-newbies-sub": "Yeni kullanıcılar için",
        "sp-contributions-newbies-title": "Yeni hesaplar için kullanıcı katkıları",
        "sp-contributions-blocklog": "engelleme günlüğü",
-       "sp-contributions-suppresslog": "kullanıcının silinen katkıları",
-       "sp-contributions-deleted": "kullanıcının silinen katkıları",
+       "sp-contributions-suppresslog": "{{GENDER:$1|kullanıcının}} baskılanmış katkıları",
+       "sp-contributions-deleted": "{{GENDER:$1|kullanıcının}} silinen katkıları",
        "sp-contributions-uploads": "yüklenenler",
        "sp-contributions-logs": "günlükler",
        "sp-contributions-talk": "mesaj",
        "allmessagesdefault": "Varsayılan ileti metni",
        "allmessagescurrent": "Kullanımdaki metin",
        "allmessagestext": "Bu liste, MediaWiki ad alanında bulunan sistem iletilerinin listesidir.\nGenel MediaWiki yerelleştirmesine katkıda bulunmak isterseniz, lütfen [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Yerelleştirmesi] ve [https://translatewiki.net translatewiki.net] sayfalarını ziyaret edin.",
-       "allmessagesnotsupportedDB": "Bu sayfa kullanılamıyor, çünkü <strong>$wgUseDatabaseMessages</strong> devre dışı bırakıldı.",
+       "allmessages-not-supported-database": "Bu sayfa kullanılamıyor, çünkü <strong>$wgUseDatabaseMessages</strong> devre dışı bırakıldı.",
        "allmessages-filter-legend": "Filtre",
        "allmessages-filter": "Özelleştirme durumuna göre filtrele:",
        "allmessages-filter-unmodified": "Değiştirilmemiş",
        "expand_templates_generate_xml": "XML derleyici ağacını göster",
        "expand_templates_generate_rawhtml": "Ham HTML göster",
        "expand_templates_preview": "Önizleme",
-       "expand_templates_preview_fail_html": "<em>{{SITENAME}} işlenmemiş HTML koduna izin verdiği ve oturum verilerinde kayıp yaşandığı için, ön izleme, JavaScript saldırılarına karşı önlem olarak gizlendi.</em>\n\n<strong>Eğer meşru bir ön izleme girişimi idiyse, tekrar deneyiniz.</strong>\nYine de çalışmıyorsa, [[Special:UserLogout|oturum kapamayı]] ve tekrar açmayı deneyin.",
+       "expand_templates_preview_fail_html": "<em>{{SITENAME}} işlenmemiş HTML koduna izin verdiği ve oturum verilerinde kayıp yaşandığı için, ön izleme, JavaScript saldırılarına karşı önlem olarak gizlendi.</em>\n\n<strong>Eğer bu meşru bir ön izleme girişimi idiyse, tekrar deneyiniz.</strong>\nYine de çalışmıyorsa, [[Special:UserLogout|oturum kapatıp]] tekrar açmayı deneyin ve tarayıcınızın bu siteden çerezlere izin verip vermediğini kontrol edin.",
        "expand_templates_preview_fail_html_anon": "<em>{{SITENAME}} işlenmemiş HTML koduna izin verdiği ve oturum verilerinde kayıp yaşandığı için, ön izleme, JavaScript saldırılarına karşı önlem olarak gizlendi.</em>\n\n<strong>Eğer meşru bir ön izleme girişimi idiyse, lütfen  [[Special:UserLogin|oturum açarak]] tekrar deneyin.</strong>",
        "expand_templates_input_missing": "En azından bazı giriş viki metni sağlamak zorundasınız.",
        "pagelanguage": "Sayfanın dilini değiştir",
index cf123d4..66341a6 100644 (file)
        "rcfilters-activefilters-show": "pqita",
        "rcfilters-days-show-days": "jiyax",
        "rcfilters-savedqueries-cancel-label": "pkungat",
-       "rcfilters-filtergroup-lastRevision": "Bgurah bi muda smalu",
+       "rcfilters-filtergroup-lastrevision": "Bgurah bi muda smalu",
        "rcnotefrom": "truma nii {{PLURAL:$5asaw }}hiya nanak <strong>$3 $4</strong> paah na niya kmpriyux (lala bi pqita <strong>$1</strong> gntuan).",
        "rclistfrom": "pqita paah $3 $2 kmpriyux bgurah siida",
        "rcshowhideminor": "$1 smsul smmalu patas",
index c46e25d..ee83ec7 100644 (file)
        "minoreditletter": "к",
        "newpageletter": "Я",
        "boteditletter": "б",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|күзәтүче кулланучы}}]",
        "rc-change-size-new": "Кертелгән үзгәрешләр белән бергә зурлык: $1 {{PLURAL:$1|байт}}",
        "newsectionsummary": "/* $1 */ яңа бүлек",
        "rc-enhanced-expand": "Ваклыкларны күрсәтү",
        "img-auth-nopathinfo": "<code>PATH_INFO</code> күрсәтелмәгән.\nСезнең сервер әлеге мәгълүматларны бирүгә көйләнмәгән.\nБәлки ул CGI нигезендә эшлидер һәм <code>img_auth</code> белән эш итмидер.\nТулырак мәгълүмат: https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Соралган юл көйләнгән йөкләү тасмасына карамый.",
        "img-auth-badtitle": "«$1» исеменән дөрес атама төзеп булмый.",
-       "img-auth-nologinnWL": "Сез теркәлмәгәнсез, «$1» ак исемлектә түгел.",
        "img-auth-nofile": "«$1» файлы юк.",
        "img-auth-streaming": "«$1» агымлы тапшыруы.",
        "http-invalid-url": "Ялган URL: $1",
index f2e25e1..cb09220 100644 (file)
        "minoreditletter": "k",
        "newpageletter": "Y",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|küzätep tora qullanuçı}}]",
        "rc-change-size-new": "üzgäreştän soñ $1 {{PLURAL:$1|bayt}}",
        "newsectionsummary": "/* $1 */ yaña bülek",
        "rc-enhanced-expand": "Waqlıqlarnı kürsätü (JavaScript kiräk)",
index 5617165..9c6550d 100644 (file)
@@ -89,7 +89,7 @@
        "subcategories": "Адаккы бөлүктер",
        "category-media-header": "«$1» деп бөлүкте файлдар",
        "category-empty": "''Амгы бо бөлүкте медиа база арыннар чок.''",
-       "hidden-categories": "{{PLURAL:$1|1=Ð\9aөзүлбеÑ\81 Ð°Ò£Ð³Ñ\8bлал|Ð\9aөзүлбеÑ\81 аңгылалдар}}",
+       "hidden-categories": "{{PLURAL:$1|1=ЧажÑ\8bÑ\80ган Ð°Ò£Ð³Ñ\8bлал|ЧажÑ\8bÑ\80ган аңгылалдар}}",
        "hidden-category-category": "Чажыт бөлүктер",
        "category-subcat-count": "{{PLURAL:$2|1=Ук аңгылал чүгле дараазында иштики аңгылалдыг.|Ук аңгылалда бар-ла $2 иштики аңгылалдарның $1 иштики аңгылалы көстүп турар.}}",
        "category-subcat-count-limited": "Ук аңгылалда {{PLURAL:$1|1=бир|$1}} иштики аңгылал бар.",
        "categorypage": "Бөлүктүң арынын көөрү",
        "viewtalkpage": "Чугааны көөрү",
        "otherlanguages": "Өске дылдарга",
-       "redirectedfrom": "($1 ÐºÐ°Ñ\82ап Ñ\87оÑ\80Ñ\83Ñ\82кан)",
+       "redirectedfrom": "($1 Ð°Ñ\80Ñ\8bндан Ñ\88илÑ\87Ñ\8dÑ\8dн)",
        "redirectpagesub": "шигледир арын",
-       "lastmodifiedat": "Бо арын сөөлгү катап $1-ның хүнүнде, $2 турда өскерилген.",
+       "lastmodifiedat": "Бо арын сөөлгү катап $1 хүнде, $2 турда эдиттинген.",
        "protectedpage": "Камгалаган арын",
        "jumpto": "Шилчиир:",
        "jumptonavigation": "навигация",
        "badaccess": "Алдаг:Эргеңер чок.",
        "versionrequired": "МедиаВикиниң $1 үндүреризи херек",
        "ok": "Чөп",
-       "retrievedfrom": "Дөзү - «$1»",
+       "retrievedfrom": "Дөзү  «$1»",
        "youhavenewmessages": "Силерде $1 ($2) бар.",
        "youhavenewmessagesmulti": "«$1» деп арында силерге чаа чагаалар бар.",
        "editsection": "эдер",
        "editlink": "эдер",
        "viewsourcelink": "Үндезин кодту көөр",
        "editsectionhint": "«$1» салбырны эдер",
-       "toc": "Ð\94опÑ\87Ñ\83зÑ\83",
+       "toc": "Ð\94олÑ\83 Ñ\83Ñ\82казÑ\8b",
        "showtoc": "көргүзери",
        "hidetoc": "чажырары",
        "collapsible-collapse": "Кызырар",
        "userlogin-yourname-ph": "Бүрүткедир адыңар киириңер",
        "yourpassword": "Чажыт сөс",
        "userlogin-yourpassword": "Пароль",
+       "createacct-yourpassword-ph": "Уруңну (парольду) киириңер",
        "yourpasswordagain": "Чажыт сөзүңерни катап бижиңер:",
+       "createacct-yourpasswordagain": "Уруңну (парольду) бадыткаңар",
+       "createacct-yourpasswordagain-ph": "Уруңну (парольду) ам база киириңер",
        "login": "Кирери",
        "nav-login-createaccount": "Кирери / бүрүткел бижикти чогаадыры",
        "logout": "Үнери",
        "login-abort-generic": "Системаже таптыг эвес кирип тур силер",
        "loginlanguagelabel": "Дыл: $1",
        "pt-login": "Кирер",
-       "pt-createaccount": "Ð\91Ò¯Ñ\80Ò¯Ñ\82кел Ð±Ð¸Ð¶Ð¸Ðº ÐºÑ\8bлÑ\8bр",
+       "pt-createaccount": "Ð\91Ò¯Ñ\80Ò¯Ñ\82кенир",
        "pt-userlogout": "Үнер",
        "php-mail-error-unknown": "PHP-ниң mail() ажыл-чорудулгазында билбес алдаг бар.",
        "changepassword": "Чажыт сөстү өскертири",
        "nohistory": "Бо арынның өскерлиишкин төөгүзү чок.",
        "currentrev": "Амгы үе үндүрери",
        "currentrev-asof": "Амгы $1 үениң бижээни",
-       "revisionasof": "$1 версиязы",
+       "revisionasof": "$1 янзы-хевири",
        "revision-info": "$2 киржикчиниң $1 хүнүнде киирилдези",
-       "previousrevision": "←Амдыы арын",
-       "nextrevision": "Ð\90Ñ\80Ñ\82Ñ\8bк Ñ\87аа Ò¯Ð½Ð´Ò¯Ñ\80еÑ\80и→",
+       "previousrevision": "← Эрги арын",
+       "nextrevision": "Чаа Ð°Ñ\80Ñ\8bн →",
        "currentrevisionlink": "Амгы үе үндүрери",
        "cur": "амгы",
        "next": "дараазында",
        "minoreditletter": "б",
        "newpageletter": "Ч",
        "boteditletter": "р",
-       "number_of_watching_users_pageview": "[$1 хайгаараар {{PLURAL:$1|ажыглакчы}}]",
        "rc-change-size-new": "Өскертилге соонда хемчээли:$1 {{PLURAL:$1|байт}}",
        "newsectionsummary": "/* $1 */ чаа салбыр",
        "rc-enhanced-expand": "Тодаларны көргүзери (JavaScript херек)",
        "unwatchedpages": "Хайгаарабас арыннар",
        "unusedtemplates": "Ажыглаан эвес майыктар",
        "unusedtemplateswlh": "өске холбаалар",
-       "randompage": "Душ бооп таваржып келген арын",
+       "randompage": "Дужар арын",
        "statistics": "Статистика",
        "statistics-pages": "Арыннар",
        "brokenredirects-edit": "өскертири",
        "newpages": "Чаа арыннар",
        "newpages-username": "Ажыглакчының ады:",
        "ancientpages": "Эң эрги арыннар",
-       "move": "Шимчээри",
+       "move": "Өскээр адаар",
        "movethispage": "Бо арынны шимчээри",
        "pager-newer-n": "{{PLURAL:$1|артык чаа}}",
        "pager-older-n": "{{PLURAL:$1|артык эрги}}",
        "newtitle": "Чаа ат:",
        "move-watch": "Бо арынны хайгаараары",
        "movepagebtn": "Арынны шимчээри",
-       "movelogpage": "ШимÑ\87Ñ\8dÑ\8dÑ\80инге Ð¶Ñ\83Ñ\80нал",
+       "movelogpage": "Ð\90Ñ\82 Ó©Ñ\81кеÑ\80илгелеÑ\80иниң Ð¶Ñ\83Ñ\80налÑ\8b",
        "movereason": "Чылдагаан:",
        "revertmove": "эгидип тургузары",
        "export": "Арынар үндүр дамчыдары",
        "tooltip-pt-logout": "Үнери",
        "tooltip-pt-createaccount": "Албан эвес-даа болза, бүрүткел бижикти кылгаш, системаже кирерин силерге саналдап тур бис.",
        "tooltip-ca-talk": "Кол арынны сайгарары",
-       "tooltip-ca-edit": "Ð\91о арынны эдер",
-       "tooltip-ca-addsection": "Чаа салбыр кылыр",
+       "tooltip-ca-edit": "Ук арынны эдер",
+       "tooltip-ca-addsection": "Чаа салбыр тургузуп кылыр",
        "tooltip-ca-viewsource": "Бо арынны өскертилгелерден камгалап каан, чогум ону көрүп, ооң үндезин кодун хоолгалап ап болур силер.",
        "tooltip-ca-history": "Арынның өскерлиишкиннериниң дептери",
        "tooltip-ca-protect": "Бо арынны камгалаары",
        "tooltip-ca-delete": "Бо арынны ырадыры",
-       "tooltip-ca-move": "Ð\91о Ð°Ñ\80Ñ\8bннÑ\8b Ñ\88имÑ\87Ñ\8dÑ\8dÑ\80и",
+       "tooltip-ca-move": "Ð\90Ñ\80Ñ\8bннÑ\8b Ó©Ñ\81кÑ\8dÑ\8dÑ\80 Ð°Ð´Ð°Ð°Ñ\80",
        "tooltip-ca-watch": "Бо арынны хайгааралыңар даңзызынче немээр",
        "tooltip-ca-unwatch": "Силерниң хайгаарал даңзызындан бо арынны ырадыры",
-       "tooltip-search": "{{grammar:locative|{{SITENAME}}}} дилээр",
+       "tooltip-search": "{{grammar:locative|{{SITENAME}}}} Ð¸Ñ\88Ñ\82инден Ð´Ð¸Ð»Ñ\8dÑ\8dÑ\80",
        "tooltip-search-go": "Шак ындыг аттыг арынче шилчиир",
-       "tooltip-search-fulltext": "Ð\90йÑ\8bÑ\82Ñ\82Ñ\8bнган сөзүглелдиг арыннарны дилээр",
+       "tooltip-search-fulltext": "Ук сөзүглелдиг арыннарны дилээр",
        "tooltip-p-logo": "Кол арынче кирер",
        "tooltip-n-mainpage": "Кол арынче шилчиир",
        "tooltip-n-mainpage-description": "Кол арынче кирер",
        "confirm-unwatch-button": "Чөп",
        "imgmultipageprev": "← эрткен арын",
        "imgmultipagenext": "дараазында арын →",
-       "imgmultigo": "Go!",
+       "imgmultigo": "Шилчиир!",
        "table_pager_next": "Дараазында арын",
        "table_pager_prev": "Эрткен арын",
        "table_pager_first": "Бирги арын",
index c205503..13c119e 100644 (file)
        "rcfilters-filter-watchlist-watched-label": "كۆزىتىش تىزىملىكىدە",
        "rcfilters-filter-newpages-label": "بەت قۇرۇلدى",
        "rcfilters-filter-categorization-label": "تۈر ئۆزگەرتىلدى",
-       "rcfilters-filtergroup-lastRevision": "ئاخىرقى نەشىرلىرى",
+       "rcfilters-filtergroup-lastrevision": "ئاخىرقى نەشىرلىرى",
        "rcfilters-filter-lastrevision-label": "ئاخىرقى نەشىرى",
        "rcfilters-view-tags": "بەلگە قويۇلغان تەھرىرلەش",
        "rcnotefrom": "تۆۋەندىكىسى '''$2''' نىڭ ئۆزگەرتىشى (ئەڭ كۆپ بولغاندا '''$1''' كۆرسىتىدۇ )",
        "newpageletter": "يېڭى",
        "boteditletter": "ماشىنا ئادەم",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1  {{PLURAL:$1|ئىشلەتكۈچى|ئىشلەتكۈچى}}كۆزىتىۋاتىدۇ]",
        "rc-change-size": "$1",
        "rc-change-size-new": "ئۆزگەرتكەندىن كېيىن $1 {{PLURAL:$1|بايت}}",
        "newsectionsummary": "* $1 * يېڭى ئابزاس",
        "img-auth-nopathinfo": "يوقالغان PATH_INFO.\nمۇلازىمىتىرىڭىز بۇ ئۇچۇرنى يوللاشنى تەڭشىمىگەن.\nئۇ CGI ئاساسىدا بولغاچقا img_auth نى قوللىمايدۇ. تۆۋەندىكى ئادرېستىن كۆرۈڭ\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization",
        "img-auth-notindir": "سەپلەنگەن يۈكلەش مۇندەرىجىسىدىن ئىلتىماس قىلغان يولنى تاپالمىدى.",
        "img-auth-badtitle": "\"$1\" ئۈچۈن ئىناۋەتلىك ماۋزۇ قۇرالمىدى.",
-       "img-auth-nologinnWL": "سىز تېخى تىزىمغا كىرمىدىڭىز، \"$1\" ئاق تىزىملىكتە ئەمەس.",
        "img-auth-nofile": "\"$1\" ھۆججەت  مەۋجۇد ئەمەس.",
        "img-auth-isdir": "سىز \"$1\" مۇندەرىجىنى زىيارەت قىلىشنى سىناۋاتىسىز.\nپەقەت ھۆججەت زىيارەت قىلىشقىلا يول قويۇلغان.",
        "img-auth-streaming": "\"$1\" ئاقتۇرۇۋاتىدۇ.",
        "allmessagesdefault": "كۆڭۈلدىكى ئۇچۇر تېكستى",
        "allmessagescurrent": "نۆۋەتتىكى ئۇچۇر تېكستى",
        "allmessagestext": "بۇ جايدا تەڭشىگىلى بولىدىغان ھەممە سىستېما كۆرۈنۈش ئۇچۇرلىرى كۆرسىتىلدى.\nئەگەر ھەقىقىي يەرلەشتۈرۈلگەن MediaWiki غا تۆھپە قوشماقچى بولسىڭىز[https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki يەرلىكلەشتۈرۈش] ۋە [https://translatewiki.net translatewiki.net] نى زىيارەت قىلىڭ.",
-       "allmessagesnotsupportedDB": "بۇ بەتنى ئىشلەتكىلى بولمايدۇ، سەۋەبى '''$wgUseDatabaseMessages''' چەكلەنگەن.",
+       "allmessages-not-supported-database": "بۇ بەتنى ئىشلەتكىلى بولمايدۇ، سەۋەبى '''$wgUseDatabaseMessages''' چەكلەنگەن.",
        "allmessages-filter-legend": "سۈزگۈچ",
        "allmessages-filter": "ئىختىيارىچە سۈزگۈچ ھالىتى:",
        "allmessages-filter-unmodified": "ئۆزگەرتىلمىگەن",
index ef4f285..66236b4 100644 (file)
@@ -78,7 +78,8 @@
                        "Movses",
                        "Esk78",
                        "Vlad5250",
-                       "Олександр М."
+                       "Олександр М.",
+                       "Gzhegozh"
                ]
        },
        "tog-underline": "Підкреслювання посилань:",
        "page_first": "перша",
        "page_last": "остання",
        "histlegend": "Вибір версії: позначте у кружечках версії для порівняння і натисніть «Enter» або кнопку внизу.<br />\nПояснення: <strong>({{int:cur}})</strong> = відмінності від поточної версії, <strong>({{int:last}})</strong> = відмінності від попередньої версії, <strong>{{int:minoreditletter}}</strong> = незначне редагування.",
-       "history-fieldset-title": "Ð\9fоÑ\88Ñ\83к Ð²ÐµÑ\80Ñ\81Ñ\96й",
+       "history-fieldset-title": "ФÑ\96лÑ\8cÑ\82Ñ\80Ñ\83ваÑ\82и Ð²ÐµÑ\80Ñ\81Ñ\96Ñ\97",
        "history-show-deleted": "Лише вилучені версії",
        "histfirst": "найдавніші",
        "histlast": "найновіші",
        "historysize": "($1 {{PLURAL:$1|байт|байти|байтів}})",
-       "historyempty": "(порожня)",
+       "historyempty": "порожня",
        "history-feed-title": "Історія редагувань",
        "history-feed-description": "Історія редагувань цієї сторінки в вікі",
        "history-feed-item-nocomment": "$1 в $2",
        "right-reupload-own": "перезаписування існуючих файлів, завантажених тим самим користувачем",
        "right-reupload-shared": "підміна файлів зі спільного сховища локальними",
        "right-upload_by_url": "завантаження файлів за URL-адресами",
-       "right-purge": "очищення кешу сторінки без необхідності підтвердження",
+       "right-purge": "очищення кешу сторінки",
        "right-autoconfirmed": "без обмежень швидкості за IP",
        "right-bot": "автоматична обробка",
        "right-nominornewtalk": "незначні редагування на сторінках обговорень користувачів не викликають попередження про нові повідомлення",
        "action-changetags": "додавання або вилучення будь-яких міток для певних версій сторінок або записів журналів",
        "action-deletechangetags": "вилучення міток з бази даних",
        "action-purge": "очищення кешу цієї сторінки",
+       "action-apihighlimits": "використання вищих лімітів у API-запитах",
+       "action-autoconfirmed": "без обмежень швидкості за IP",
+       "action-bigdelete": "вилучення сторінок з великою історією",
+       "action-blockemail": "блокування користувача від надсилання електронної пошти",
+       "action-bot": "вважатися автоматичним процесом",
+       "action-editprotected": "редагування сторінок з рівнем захисту «{{int:protect-level-sysop}}»",
+       "action-editsemiprotected": "редагування сторінок з рівнем захисту «{{int:protect-level-autoconfirmed}}»",
+       "action-editinterface": "редагування інтерфейсу користувача",
+       "action-editusercss": "редагування CSS-файлів інших користувачів",
+       "action-edituserjson": "редагування JSON-файлів інших користувачів",
+       "action-edituserjs": "редагування JavaScript-файлів інших користувачів",
+       "action-editsitecss": "редагування загального CSS",
+       "action-editsitejson": "редагування загального JSON",
+       "action-editsitejs": "редагування загального JavaScript",
+       "action-editmyusercss": "редагування власних CSS-файлів користувача",
+       "action-editmyuserjson": "редагування власних JSON-файлів користувача",
+       "action-editmyuserjs": "редагування власних JavaScript-файлів користувача",
+       "action-viewsuppressed": "перегляд змін, прихованих від усіх користувачів",
+       "action-hideuser": "блокування імені користувача і приховування його",
+       "action-ipblock-exempt": "уникнення IP-блокування, автоблокування і блокування діапазонів",
+       "action-unblockself": "розблоковування себе",
+       "action-noratelimit": "звільнення від обмежень швидкості",
+       "action-reupload-own": "перезаписування існуючих файлів, завантажених тим самим користувачем",
+       "action-nominornewtalk": "незначні редагування на сторінках обговорень користувачів не викликають попередження про нові повідомлення",
+       "action-markbotedits": "позначення відкинутих редагувань як редагування бота",
+       "action-patrolmarks": "перегляд позначок патрулювання у нових редагуваннях",
+       "action-override-export-depth": "експорт сторінок, включаючи пов'язані сторінки з глибиною до 5",
+       "action-suppressredirect": "нестворення перенаправлення зі старої назви на нову при перейменуванні сторінки",
        "nchanges": "$1 {{PLURAL:$1|зміна|зміни|змін}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|зміна з останнього візиту|зміни з останнього візиту|змін з останнього візиту}}",
        "enhancedrc-history": "історія",
        "rcfilters-savedqueries-already-saved": "Ці фільтри вже збережено. Змініть свої налаштування щоб створити новий Збережений фільтр.",
        "rcfilters-restore-default-filters": "Відновити стандартні фільтри",
        "rcfilters-clear-all-filters": "Очистити фільтри",
-       "rcfilters-show-new-changes": "Ð\9fеÑ\80еглÑ\8fнÑ\83Ñ\82и Ð½Ð°Ð¹Ð½Ð¾Ð²Ñ\96Ñ\88Ñ\96 Ð·Ð¼Ñ\96ни",
+       "rcfilters-show-new-changes": "Ð\9fеÑ\80еглÑ\8fнÑ\83Ñ\82и Ð½Ð¾Ð²Ñ\96 Ð·Ð¼Ñ\96ни Ð· $1",
        "rcfilters-search-placeholder": "Фільтруйте редагування (використовуйте меню, або скористайтесь пошуком фільтра за назвою)",
        "rcfilters-invalid-filter": "Недійсний фільтр",
        "rcfilters-empty-filter": "Без фільтрів. Показано всі зміни.",
        "rcfilters-filter-editsbyself-description": "Ваш власний внесок.",
        "rcfilters-filter-editsbyother-label": "Зміни, здійснені іншими",
        "rcfilters-filter-editsbyother-description": "Усі зміни, за винятком Ваших власних.",
-       "rcfilters-filtergroup-userExpLevel": "Реєстрація користувача і його досвід",
+       "rcfilters-filtergroup-user-experience-level": "Реєстрація користувача і його досвід",
        "rcfilters-filter-user-experience-level-registered-label": "Зареєстровані",
        "rcfilters-filter-user-experience-level-registered-description": "Користувачі, що увійшли в систему.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Незареєстровані",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Фільтр «Незначні редагування» конфліктує з одним або більше фільтрів за типом змін, оскільки певні типи змін не можна позначити як «незначні». Конфліктні фільтри позначені в ділянці активних фільтрів угорі.",
        "rcfilters-hideminor-conflicts-typeofchange": "Певні типи змін не можна позначити як «незначні», тож цей фільтр конфліктує з такими фільтрами за типом змін: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Цей фільтр за типом змін конфліктує з фільтром «Незначні редагування». Певні типи змін не можна позначати як «незначні».",
-       "rcfilters-filtergroup-lastRevision": "Останні версії",
+       "rcfilters-filtergroup-lastrevision": "Останні версії",
        "rcfilters-filter-lastrevision-label": "Поточна версія",
        "rcfilters-filter-lastrevision-description": "Лише остання зміна на сторінці.",
        "rcfilters-filter-previousrevision-label": "Не остання версія",
        "newpageletter": "Н",
        "boteditletter": "б",
        "unpatrolledletter": "!",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|користувач спостерігає|користувачі спостерігають|користувачів спостерігають}}]",
        "rc-change-size": "$1",
        "rc-change-size-new": "Розмір після зміни: $1 {{PLURAL:$1|байт|байти|байтів}}",
        "newsectionsummary": "/* $1 */ нова тема",
        "img-auth-nopathinfo": "Відсутня інформація про шлях.\nВаш сервер слід налаштувати для передачі змінних REQUEST_URI та/або PATH_INFO.\nЯкщо він налаштований, спробуйте увімкнути $wgUsePathInfo.\nПерегляньте [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization Відкриття доступу до зображень]",
        "img-auth-notindir": "Проханий шлях не відноситься до теки завантажень, вказаної в налаштуваннях.",
        "img-auth-badtitle": "Не можна побудувати правильний заголовок з «$1».",
-       "img-auth-nologinnWL": "Ви не ввійшли в систему, а «$1» не входить у білий список.",
        "img-auth-nofile": "Файл «$1» не існує.",
        "img-auth-isdir": "Ви пробуєте отримати доступ до каталогу «$1».\nДозволений тільки доступ до файлів.",
        "img-auth-streaming": "Потокова передача «$1».",
        "logeventslist-tag-log": "Журнал міток",
        "all-logs-page": "Усі публічні журнали",
        "alllogstext": "Комбінований показ журналів {{grammar:genitive|{{SITENAME}}}}.\nВи можете відфільтрувати результати за типом журналу, іменем користувача (враховується регістр) або зазначеною сторінкою (також враховується регістр).",
-       "logempty": "У Ð¶Ñ\83Ñ\80налÑ\96 Ð½ÐµÐ¼Ð°Ñ\94 Ð¿Ð¾Ð´Ñ\96бних записів.",
+       "logempty": "У Ð¶Ñ\83Ñ\80налÑ\96 Ð½ÐµÐ¼Ð°Ñ\94 Ð²Ñ\96дповÑ\96дних записів.",
        "log-title-wildcard": "Знайти заголовки, що починаються з цих символів",
        "showhideselectedlogentries": "Показати/приховати виділені записи журналу",
        "log-edit-tags": "Змінити мітки для вибраних записів журналів",
        "unwatchthispage": "Скасувати спостереження",
        "notanarticle": "Не стаття",
        "notvisiblerev": "Версія була вилучена",
-       "watchlist-details": "У Ð\92аÑ\88омÑ\83 Ñ\81пиÑ\81кÑ\83 Ñ\81поÑ\81Ñ\82еÑ\80еженнÑ\8f $1 {{PLURAL:$1|Ñ\81Ñ\82оÑ\80Ñ\96нка|Ñ\81Ñ\82оÑ\80Ñ\96нки|Ñ\81Ñ\82оÑ\80Ñ\96нок}} (плÑ\8eÑ\81 сторінки обговорення).",
+       "watchlist-details": "У Ð\92аÑ\88омÑ\83 Ñ\81пиÑ\81кÑ\83 Ñ\81поÑ\81Ñ\82еÑ\80еженнÑ\8f $1 {{PLURAL:$1|Ñ\81Ñ\82оÑ\80Ñ\96нка|Ñ\81Ñ\82оÑ\80Ñ\96нки|Ñ\81Ñ\82оÑ\80Ñ\96нок}} (а Ñ\89е сторінки обговорення).",
        "wlheader-enotif": "Сповіщення електронною поштою ввімкнено.",
        "wlheader-showupdated": "Сторінки, що змінилися після Вашого останнього їх відвідування, виділені '''жирним''' шрифтом.",
        "wlnote": "Нижче наведено {{PLURAL:$1|останнє $1 редагування|останні $1 редагування|останні $1 редагувань}} за {{PLURAL:$2|останню|останні|останні}} <strong>$2</strong> {{PLURAL:$2|годину|години|годин}}, на час $3 $4.",
        "delete-confirm": "Вилучення «$1»",
        "delete-legend": "Вилучення",
        "historywarning": "<strong>Попередження:</strong> Сторінка, яку ви збираєтеся вилучити, має історію редагувань з приблизно $1 {{PLURAL:$1|1=версії|версій}}:",
-       "historyaction-submit": "Показати",
+       "historyaction-submit": "Показати версії",
        "confirmdeletetext": "Ви збираєтесь вилучити сторінку і всі її журнали редагувань з бази даних.\nБудь ласка, підтвердіть, що Ви бажаєте зробити це, повністю розумієте наслідки і що робите це у відповідності з [[{{MediaWiki:Policy-url}}|правилами]].",
        "actioncomplete": "Дію виконано",
        "actionfailed": "Виконати дію не вдалося",
        "deleting-backlinks-warning": "<strong>Попередження:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|інші сторінки]] посилаються або містять сторінку, яку Ви маєте намір видалити.",
        "deleting-subpages-warning": "<strong>Попередження:</strong> Сторінка, яку Ви маєте намір вилучити, має [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|$1 підсторінку|$1 підсторінки|$1 підсторінок|51=понад 50 підсторінок}}]].",
        "rollback": "Відкинуто редагування",
+       "rollback-confirmation-confirm": "Будь ласка, підтвердіть:",
+       "rollback-confirmation-yes": "Відкинути",
+       "rollback-confirmation-no": "Скасувати",
        "rollbacklink": "відкинути",
        "rollbacklinkcount": "відкинути $1 {{PLURAL:$1|редагування|редагування|редагувань}}",
        "rollbacklinkcount-morethan": "відкинути понад $1 {{PLURAL:$1|редагування|редагування|редагувань}}",
        "revertpage": "Відкинуто редагування [[Special:Contributions/$2|$2]] ([[User talk:$2|обговорення]]) до зробленого [[User:$1|$1]]",
        "revertpage-nouser": "Відкинуто редагування прихованого користувача до останньої версії, зробленої {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Відкинуті редагування {{GENDER:$3|користувача|користувачки}} $1; повернення до версії {{GENDER:$4|користувача|користувачки}} $2.",
-       "rollback-success-notify": "Відкинуті редагування користувача $1; \nповернено до останньої версії користувача $2. [$3 Показати зміни]",
        "sessionfailure-title": "Помилка сеансу",
        "sessionfailure": "Здається, виникли проблеми з поточним сеансом роботи;\nцю дію скасовано, щоб запобігти «захопленню сеансу».\nБудь ласка, надішліть форму ще раз.",
        "changecontentmodel": "Змінити модель вмісту сторінки",
        "mycontris": "Внесок",
        "anoncontribs": "Внесок",
        "contribsub2": "Для {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "Для {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "Обліковий запис користувача  «$1» не зареєстровано.",
        "negative-namespace-not-supported": "Не підтримуються простори назв із від'ємними значеннями.",
        "nocontribs": "Редагувань, що відповідають заданим умовам, не знайдено.",
        "blocklist-userblocks": "Сховати блокування облікових записів",
        "blocklist-tempblocks": "Сховати тимчасові блокування",
        "blocklist-addressblocks": "Приховати блокування окремих IP-адрес",
+       "blocklist-type": "Тип:",
+       "blocklist-type-opt-all": "Всі",
+       "blocklist-type-opt-sitewide": "У всій вікі",
+       "blocklist-type-opt-partial": "Частково",
        "blocklist-rangeblocks": "Приховати блокування діапазонів",
        "blocklist-timestamp": "Часова позначка",
        "blocklist-target": "Мета",
        "blocklist-editing-page": "сторінки",
        "blocklist-editing-ns": "простори назв",
        "ipblocklist-empty": "Список блокувань порожній.",
-       "ipblocklist-no-results": "Ð\97апÑ\80оÑ\85анÑ\96 IP-адÑ\80еÑ\81а Ð°Ð±Ð¾ Ñ\96м'Ñ\8f ÐºÐ¾Ñ\80иÑ\81Ñ\82Ñ\83ваÑ\87а Ð½Ðµ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ñ\96.",
+       "ipblocklist-no-results": "Ð\9dе Ð·Ð½Ð°Ð¹Ð´ÐµÐ½Ð¾ Ð±Ð»Ð¾ÐºÑ\83ванÑ\8c Ð´Ð»Ñ\8f Ð·Ð°Ð·Ð½Ð°Ñ\87еноÑ\97 IP-адÑ\80еÑ\81и Ð°Ð±Ð¾ Ñ\96менÑ\96 ÐºÐ¾Ñ\80иÑ\81Ñ\82Ñ\83ваÑ\87а.",
        "blocklink": "заблокувати",
        "unblocklink": "розблокувати",
        "change-blocklink": "змінити блокування",
+       "empty-username": "(ім'я користувача недоступне)",
        "contribslink": "внесок",
        "emaillink": "Надіслати повідомлення електронною поштою",
        "autoblocker": "Доступ заблоковано автоматично, тому що ви використовуєте ту саму адресу, що й \"[[User:$1|$1]]\". Причина блокування $1: \"$2\".",
        "allmessagesdefault": "Стандартний текст",
        "allmessagescurrent": "Поточний текст",
        "allmessagestext": "Це список усіх системних повідомлень, які доступні в просторі назв «MediaWiki».\nБудь ласка, відвідайте [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] і [https://translatewiki.net translatewiki.net], якщо ви хочете зробити внесок до спільної локалізації MediaWiki.",
-       "allmessagesnotsupportedDB": "Ця сторінка не може використовуватися, оскільки вимкнена опція '''$wgUseDatabaseMessages'''.",
+       "allmessages-not-supported-database": "Ця сторінка не може використовуватися, оскільки вимкнена опція '''$wgUseDatabaseMessages'''.",
        "allmessages-filter-legend": "Фільтр",
        "allmessages-filter": "Фільтр за внесеними змінами:",
        "allmessages-filter-unmodified": "Незмінені",
        "confirm-unwatch-top": "Вилучити цю сторінку з вашого списку спостереження?",
        "confirm-rollback-button": "Гаразд",
        "confirm-rollback-top": "Відкотити редагування цієї сторінки?",
+       "confirm-rollback-bottom": "Ця дія миттєво відкотить обрані зміни на цій сторінці.",
        "confirm-mcrrestore-title": "Відновити версію",
        "confirm-mcrundo-title": "Скасувати зміну",
        "mcrundofailed": "Помилка скасування",
        "passwordpolicies-policyflag-forcechange": "має бути змінено при вході",
        "passwordpolicies-policyflag-suggestchangeonlogin": "запропонувати зміну при вході",
        "easydeflate-invaliddeflate": "Наданий вміст не стиснений належним чином",
-       "unprotected-js": "З міркувань безпеки JavaScript не можна запускати з незахищених сторінок. Будь ласка, створюйте javascript лише в просторі MediaWiki, або як особисту підсторінку користувача."
+       "unprotected-js": "З міркувань безпеки JavaScript не можна запускати з незахищених сторінок. Будь ласка, створюйте javascript лише в просторі MediaWiki, або як особисту підсторінку користувача.",
+       "userlogout-continue": "Якщо Ви хочете вийти із системи, [$1 перейдіть на сторінку виходу].",
+       "userlogout-sessionerror": "Вихід із системи не відбувся через помилку сесії. Будь ласка, [$1 спробуйте знову]."
 }
index 81bbff4..cb80d47 100644 (file)
@@ -40,7 +40,8 @@
                        "Fitoschido",
                        "Dcljr",
                        "Bukhari",
-                       "Sajidkhan"
+                       "Sajidkhan",
+                       "Hmfs.ind"
                ]
        },
        "tog-underline": "ربط کی خط کشیدگی:",
        "nstab-category": "زمرہ",
        "mainpage-nstab": "صفحۂ اول",
        "nosuchaction": "مطلوبہ اقدام موجود نہیں",
-       "nosuchactiontext": "URL کی جانب سے مختص کیا گیا عمل درست نہیں.\nآپ نے شاید URL غلط لکھا، یا کسی غیر صحیح ربط کی پیروی کی ہے.\n{{اِس سے SITENAME کے زیرِ استعمال مصنع لطیف میں کھٹمل کی نشاندہی کا بھی اندیشہ ہے}}.",
+       "nosuchactiontext": "URL کی جانب سے مختص کیا گیا عمل درست نہیں۔\nآپ نے شاید URL غلط لکھا ہے یا کسی نادرست ربط پر کلک کیا ہے۔\nاِس سے {{SITENAME}} کے زیرِ استعمال سافٹ ویئر میں کسی خامی کی موجودگی کا بھی اندیشہ ہے۔",
        "nosuchspecialpage": "کوئی ایسا خاص صفحہ نہیں",
        "nospecialpagetext": "<strong>آپ نے ایک غیر موجود خصوصی صفحہ کی درخواست کی ہے۔</strong>\n\nدرست خاص صفحات کی ایک فہرست [[Special:SpecialPages|{{int:specialpages}}]] پر دیکھی جاسکتی ہے۔",
        "error": "نقص",
        "rcfilters-filter-editsbyself-description": "آپ کی اپنی شراکتیں",
        "rcfilters-filter-editsbyother-label": "دیگر صارفین کی تبدیلیاں",
        "rcfilters-filter-editsbyother-description": "آپ کی تبدیلیوں کے سوا تمام تبدیلیاں",
-       "rcfilters-filtergroup-userExpLevel": "صارف کا اندراج اور تجربہ",
+       "rcfilters-filtergroup-user-experience-level": "صارف کا اندراج اور تجربہ",
        "rcfilters-filter-user-experience-level-registered-label": "مندرج",
        "rcfilters-filter-user-experience-level-registered-description": "لاگ ان ہو کر ترمیم کرنے والے صارفین",
        "rcfilters-filter-user-experience-level-unregistered-label": "غیر مندرج",
        "rcfilters-hideminor-conflicts-typeofchange-global": "«معمولی ترامیم» والا فلٹر «تبدیلی کی نوعیت» والے ایک یا زائد فلٹروں سے متعارض ہو جاتا ہے کیونکہ کچھ مخصوص قسم کی تبدیلیاں \"معمولی\" نہیں کہلاتیں۔ یہ متعارض فلٹر اوپر موجود «فعال فلٹر» کے تحت نمایاں کر دیے گئے ہیں۔",
        "rcfilters-hideminor-conflicts-typeofchange": "مخصوص قسم کی تبدیلیاں \"معمولی\" نہیں کہلاتیں، اس صورت میں یہ فلٹر درج ذیل «تبدیلی کی نوعیت» فلٹروں سے متعارض ہو جاتا ہے: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "اس نوعیت کی تبدیلی والا فلٹر «معمولی ترامیم» والے فلٹر سے متعارض ہو جاتا ہے؛ کیونکہ کچھ مخصوص قسم کی تبدیلیاں \"معمولی\" نہیں کہلاتیں۔",
-       "rcfilters-filtergroup-lastRevision": "تازہ ترین نسخے",
+       "rcfilters-filtergroup-lastrevision": "تازہ ترین نسخے",
        "rcfilters-filter-lastrevision-label": "تازہ ترین نسخہ",
        "rcfilters-filter-lastrevision-description": "صفحے کی محض حالیہ ترین تبدیلی",
        "rcfilters-filter-previousrevision-label": "تازہ ترین نسخہ کے سوا",
        "minoreditletter": "م",
        "newpageletter": "نیا ..",
        "boteditletter": " خودکار",
-       "number_of_watching_users_pageview": "[$1 مشاہد {{PLURAL:$1|صارف|صارفین}}]",
        "rc-change-size-new": "تبدیلی کے بعد $1 {{PLURAL:$1|بائٹ}}",
        "newsectionsummary": "/* $1 */ نیا قطعہ",
        "rc-enhanced-expand": "تفصیلات دکھائیں",
        "img-auth-nopathinfo": "PATH_INFO مفقود ہے۔\nآپ کے سرور کو اس معلومات کی ترسیل کے لیے مرتب نہیں کیا گیا ہے۔\nممکن ہے یہ سی جی آئی پر مبنی ہو اور img_auth کو قبول نہ کرتا ہو۔\nبراہ کرم https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization کو ملاحظہ کریں۔",
        "img-auth-notindir": "اپلوڈ کے لیے ترتیب شدہ ڈائرکٹری میں درخواست کردہ راستہ موجود نہیں ہے۔",
        "img-auth-badtitle": "«$1» سے کسی درست عنوان کی تشکیل نہیں کی جا سکتی۔",
-       "img-auth-nologinnWL": "آپ داخل نہیں ہیں اور فہرست سفید میں «$1» نہیں ہے۔",
        "img-auth-nofile": "فائل «$1» موجود نہیں ہے۔",
        "img-auth-isdir": "آپ «$1» ڈائرکٹری کو کھولنے کی کوشش کر رہے ہیں۔\nمحض فائل تک رسائی کی اجازت ہے۔",
        "img-auth-streaming": "«$1» کی نمائش جاری ہے۔",
        "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-notify": "$1 کی ترامیم واپس پھیر دی گئیں؛\nصفحہ واپس $2 کی آخری ترمیم کی جانب منتقل کر دیا گیا۔ [$3 تبدیلیاں دکھائیں]",
        "sessionfailure-title": "نشست میں خامی",
        "sessionfailure": "معلوم ہوتا ہے کہ آپ کی لاگ ان نشست میں کوئی مسئلہ درپیش ہے؛\nاس صورت میں نشست کے اغوا کا خدشہ ہوتا ہے، چنانچہ پیش بندی کے طور پر آپ کے اقدام کو مسترد کر دیا گیا ہے۔\nبراہ کرم دوبارہ کوشش کریں۔",
        "changecontentmodel": "صفحہ کے مواد کے ماڈل میں تبدیلی کریں",
        "allmessagesdefault": "طے شدہ متن",
        "allmessagescurrent": "موجودہ متن",
        "allmessagestext": "ذیل میں میڈیاویکی نام فضا میں دستیاب نظامی پیغامات کی فہرست موجود ہے۔\nاگر آپ میڈیاویکی کا ترجمہ کرنا چاہتے ہیں تو [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation میڈیاویکی مقامیت کاری] اور [https://translatewiki.net translatewiki.net] ملاحظہ فرمائیں۔",
-       "allmessagesnotsupportedDB": "اس صفحہ کو استعمال نہیں کیا جا سکتا کیونکہ <strong>$wgUseDatabaseMessages</strong> کو غیر فعال کر دیا گیا ہے۔",
+       "allmessages-not-supported-database": "اس صفحہ کو استعمال نہیں کیا جا سکتا کیونکہ <strong>$wgUseDatabaseMessages</strong> کو غیر فعال کر دیا گیا ہے۔",
        "allmessages-filter-legend": "مقطر",
        "allmessages-filter": "تلاش بلحاظ:",
        "allmessages-filter-unmodified": "غیر تبدیل شدہ",
index 5a67ffb..8829b5a 100644 (file)
        "rcfilters-savedqueries-add-new-title": "Amaldagi filtrlar eslab qolinsin",
        "rcfilters-search-placeholder": "Oʻzgarishlarni filtrlash (menyudan foydalaning yoki filtr nomini kiriting)",
        "rcfilters-filterlist-title": "Filtrlar",
-       "rcfilters-filtergroup-userExpLevel": "Foydalanuvchining tajriba darajasi",
+       "rcfilters-filtergroup-user-experience-level": "Foydalanuvchining tajriba darajasi",
        "rcfilters-filter-bots-label": "Bot",
        "rcfilters-filter-minor-label": "Kichik tahrirlar",
        "rcfilters-filter-major-label": "Oddiy tahrirlar",
index 8a06201..abaa944 100644 (file)
        "minoreditletter": "p",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[osservà da {{PLURAL:$1|un utente|$1 utenti}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte}} dopo ła modifega",
        "newsectionsummary": "/* $1 */ sezion nova",
        "rc-enhanced-expand": "Mostra detaji",
        "img-auth-nopathinfo": "Manca el PATH_INFO.\nEl to server no'l xe mia configurà par pasar sta informasion.\nMagari el xe basà su CGI e no'l suporta img_auth.\nVarda https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "El percorso richiesto no'l se cata in te la cartèla de caricamento configurà.",
        "img-auth-badtitle": "No se riesse a costruir un titolo valido da \"$1\".",
-       "img-auth-nologinnWL": "No te sì autenticà e \"$1\" no'l xe mia in te la lista bianca.",
        "img-auth-nofile": "El file \"$1\" no l'esiste mia.",
        "img-auth-isdir": "Te sì drio sercar de entrar in te la cartèla \"$1\".\nXe parmesso entrar solo in tei file, no in te le cartèle.",
        "img-auth-streaming": "Streaming de \"$1\".",
        "allmessagesdefault": "Testo predefinìo",
        "allmessagescurrent": "Testo come che el xe desso",
        "allmessagestext": "Sta quà l'è na lista de tuti i messagi disponibili nel namespace MediaWiki.\nPar piaser visita [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] e [https://translatewiki.net translatewiki.net] se te voli jutarne par la traduzion del software MediaWiki ne le varie lengue.",
-       "allmessagesnotsupportedDB": "'''{{ns:special}}:Allmessages''' no'l xè supportà parché '''$wgUseDatabaseMessages''' no'l xè ativo.",
+       "allmessages-not-supported-database": "'''{{ns:special}}:Allmessages''' no'l xè supportà parché '''$wgUseDatabaseMessages''' no'l xè ativo.",
        "allmessages-filter-legend": "Filtro",
        "allmessages-filter": "Filtra par stato de personalixassion:",
        "allmessages-filter-unmodified": "Mia modificà",
index 55b8ae5..4b45ef2 100644 (file)
        "minoreditletter": "p",
        "newpageletter": "U",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|kaclii kävutai|kaclijad kävutajad}}]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|bait|baitad}} jäl'ges toižetamišt",
        "newsectionsummary": "/* $1 */ uz' jaguz",
        "allmessagesname": "Nimi",
        "allmessagesdefault": "Tekst augotižjärgendusen mödhe",
        "allmessagescurrent": "Nügüdläine tekst",
-       "allmessagesnotsupportedDB": "Nece lehtpol' ei ole kävutamižes, sikš miše '''$wgUseDatabaseMessages'''-opcii ei ole radmas.",
+       "allmessages-not-supported-database": "Nece lehtpol' ei ole kävutamižes, sikš miše '''$wgUseDatabaseMessages'''-opcii ei ole radmas.",
        "allmessages-filter-legend": "Fil'tr",
        "allmessages-filter": "Fil'tr toižetusen statusan mödhe:",
        "allmessages-filter-unmodified": "Toižetamatomad",
index 823f589..9d2fabd 100644 (file)
        "rcfilters-filter-editsbyself-description": "Các sửa đổi do bạn tạo ra.",
        "rcfilters-filter-editsbyother-label": "Sửa đổi của người khác",
        "rcfilters-filter-editsbyother-description": "Các sửa đổi của người khác.",
-       "rcfilters-filtergroup-userExpLevel": "Trạng thái đăng nhập và trình độ của người dùng",
+       "rcfilters-filtergroup-user-experience-level": "Trạng thái đăng nhập và trình độ của người dùng",
        "rcfilters-filter-user-experience-level-registered-label": "Đã đăng ký",
        "rcfilters-filter-user-experience-level-registered-description": "Người dùng đã đăng nhập.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Vô danh",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Bộ lọc \"Các sửa đổi nhỏ\" mâu thuẫn với một hoặc nhiều bộ lọc Loại sửa đổi, bởi có một số loại sửa đổi không thể được đánh dấu là \"nhỏ\". Các bộ lọc mâu thuẫn với nhau được đánh dấu trong mục Bộ lọc hiện hành ở trên.",
        "rcfilters-hideminor-conflicts-typeofchange": "Một số loại sửa đổi không thể được đánh dấu là \"nhỏ\", do đó bộ lọc này mâu thuẫn với các bộ lọc Loại sửa đổi dưới đây: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Bộ lọc Loại sửa đổi này mâu thuẫn với bộ lọc \"Các sửa đổi nhỏ\". Có một số loại sửa đổi không thể được đánh dấu là \"nhỏ\".",
-       "rcfilters-filtergroup-lastRevision": "Phiên bản mới nhất",
+       "rcfilters-filtergroup-lastrevision": "Phiên bản mới nhất",
        "rcfilters-filter-lastrevision-label": "Phiên bản mới nhất",
        "rcfilters-filter-lastrevision-description": "Chỉ sửa đổi mới nhất trên một trang.",
        "rcfilters-filter-previousrevision-label": "Không phải phiên bản mới nhất",
        "minoreditletter": "n",
        "newpageletter": "M",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 người đang xem]",
        "rc-change-size-new": "$1 byte sau thay đổi",
        "newsectionsummary": "Đề mục mới: /* $1 */",
        "rc-enhanced-expand": "Xem chi tiết",
        "img-auth-nopathinfo": "Thiếu thông tin đường dẫn.\nMáy chủ của bạn phải được thiết lập để truyền biến REQUEST_URI và/hoặc biến PATH_INFO.\nNếu đã được thiết lập, hãy thử kích hoạt $wgUsePathInfo.\nXem [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization hướng dẫn điều khiển truy cập hình ảnh].",
        "img-auth-notindir": "Đường dẫn yêu cầu không nằm trong thư mục cấu hình tải lên.",
        "img-auth-badtitle": "Không thể tạo tựa đề hợp lệ từ “$1”.",
-       "img-auth-nologinnWL": "Bạn chưa đăng nhập và “$1” không nằm trong danh sách trắng.",
        "img-auth-nofile": "Không tồn tại tập tin “$1”.",
        "img-auth-isdir": "Bạn đang cố truy cập vào thư mục “$1”.\nChỉ cho phép truy cập tập tin mà thôi.",
        "img-auth-streaming": "Đang truyền “$1”.",
        "revertpage": "Đã lùi lại sửa đổi của [[Special:Contributions/$2|$2]] ([[User talk:$2|Thảo luận]]) quay về phiên bản cuối của [[User:$1|$1]]",
        "revertpage-nouser": "Đã lùi lại sửa đổi của người dùng ẩn quay về phiên bản cuối của {{GENDER:$1}}[[User:$1|$1]]",
        "rollback-success": "Đã hủy sửa đổi của {{GENDER:$3}}$1;\nquay về phiên bản cuối của {{GENDER:$4}}$2.",
-       "rollback-success-notify": "Đã hủy sửa đổi của $1;\nquay về phiên bản cuối của $2. [$3 Xem thay đổi]",
        "sessionfailure-title": "Phiên thất bại",
        "sessionfailure": "Dường như có trục trặc với phiên đăng nhập của bạn; thao tác này đã bị hủy để tránh việc cướp quyền đăng nhập. Xin hãy gửi lại biểu mẫu.",
        "changecontentmodel": "Thay đổi kiểu nội dung của một trang",
        "allmessagesdefault": "Nội dung mặc định",
        "allmessagescurrent": "Nội dung hiện thời",
        "allmessagestext": "Đây là toàn bộ thông điệp hệ thống có trong không gian tên MediaWiki.\nMời vào [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation?uselang=vi Địa phương hóa MediaWiki] và [https://translatewiki.net/wiki/?uselang=vi translatewiki.net] nếu bạn muốn đóng góp dịch chung cả MediaWiki.",
-       "allmessagesnotsupportedDB": "Trang này không dùng được vì biến '''$wgUseDatabaseMessages''' đã bị tắt.",
+       "allmessages-not-supported-database": "Trang này không dùng được vì biến '''$wgUseDatabaseMessages''' đã bị tắt.",
        "allmessages-filter-legend": "Bộ lọc",
        "allmessages-filter": "Lọc theo tình trạng sửa đổi:",
        "allmessages-filter-unmodified": "Chưa sửa",
index 7559227..0a1371e 100644 (file)
        "minoreditletter": "p",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[{{PLURAL:$1|geban|gebans}} galädöl $1]",
        "rc-change-size-new": "{{PLURAL:$1|jölät|jöläts}} $1 po votükam",
        "newsectionsummary": "/* $1 */ diläd nulik",
        "rc-enhanced-expand": "Jonön patis",
        "allmessagesdefault": "Vödem rigädik",
        "allmessagescurrent": "Vödem nuik",
        "allmessagestext": "Is binon lised sitanunas valik lonöföl in nemaspad: Sitanuns.\nGebolös [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Topükami ela MediaWiki] ed el [https://translatewiki.net translatewiki.net] if vilol keblünön topükame valemik ela MediaWiki.",
-       "allmessagesnotsupportedDB": "Pad at no kanon pagebön bi el '''$wgUseDatabaseMessages''' penemögükon.",
+       "allmessages-not-supported-database": "Pad at no kanon pagebön bi el '''$wgUseDatabaseMessages''' penemögükon.",
        "allmessages-filter-legend": "Sul",
        "allmessages-filter-unmodified": "Penevotüköl",
        "allmessages-filter-all": "Valik",
index 62d063b..b01582d 100644 (file)
        "minoreditletter": "ts",
        "newpageletter": "V",
        "boteditletter": "rb",
-       "number_of_watching_users_pageview": "[{{PLURAL:$1|$1 perräkaejat|üts perräkaeja}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|bait|baiti}} peräst muutmist",
        "rc-enhanced-expand": "Näütäq ütsikasjo",
        "rc-enhanced-hide": "Käkiq ütsikas'aq ärq",
        "allmessagesdefault": "Vaikimiisi tekst",
        "allmessagescurrent": "Parhillanõ tekst",
        "allmessagestext": "Taan nimekirän ommaq kõik MediaWiki nimeruumi tallitusteedüseq.\nPlease visit [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] and [https://translatewiki.net translatewiki.net] if you wish to contribute to the generic MediaWiki localisation.",
-       "allmessagesnotsupportedDB": "Taad lehte saa-i pruukiq, selle et '''$wgUseDatabaseMessages'''-säädmine om välän.",
+       "allmessages-not-supported-database": "Taad lehte saa-i pruukiq, selle et '''$wgUseDatabaseMessages'''-säädmine om välän.",
        "thumbnail-more": "Suurõndaq",
        "filemissing": "Olõ-i teedüstüt",
        "thumbnail_error": "Väikupildi luuminõ lää-s kõrda: $1",
index d204bcd..1a26982 100644 (file)
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[shuvou pa $1 {{PLURAL:$1|uzeu|uzeus}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|octet|octets}} après l' candjmint",
        "newsectionsummary": "/* $1 */ novele seccion",
        "rc-enhanced-expand": "Mostrer les detays",
        "allmessagesdefault": "Tecse prémetou",
        "allmessagescurrent": "Tecse pol moumint",
        "allmessagestext": "Çouchal est ene djivêye des messaedjes sistinme k' i gn a dins l' espåce di lomaedje ''MediaWiki:''.\nLoukîz les pådjes sol [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Locålijhaedje di MediaWiki] et \n[https://translatewiki.net/ translatewiki.net] si vos vloz pårticiper avou l' ratournaeje djenerike di MediaWiki.",
-       "allmessagesnotsupportedDB": "'''{{ns:special}}:AllMessages''' n' est nén sopoirté paski '''$wgUseDatabaseMessages''' est dismetou.",
+       "allmessages-not-supported-database": "'''{{ns:special}}:AllMessages''' n' est nén sopoirté paski '''$wgUseDatabaseMessages''' est dismetou.",
        "allmessages-filter-legend": "Passete",
        "allmessages-filter": "Sorlon l' estat d' candjaedje:",
        "allmessages-filter-unmodified": "Nén candjîs",
index cc87a70..d35b2b9 100644 (file)
        "minoreditletter": "g",
        "newpageletter": "B",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 nagbabatay hin {{PLURAL:$1|gumaramit|mga gumaramit}}]",
        "rc-change-size-new": "$1 {{PLURAL:$1|nga byte|nga mga byte}} kahuman han pagbag-o",
        "newsectionsummary": "/* $1 */ bag-o nga bahin",
        "rc-enhanced-expand": "Igpakita an detalye",
index 5f0ad27..ccf44ba 100644 (file)
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[{{PLURAL:$1|jëfandikukat moo koy topp|$1 jëfandikukat ñoo koy topp}}]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} ginnaaw coppite gi",
        "newsectionsummary": "/* $1 */ xaaj bu bees",
index ce821d7..194fe5f 100644 (file)
        "allmessagesdefault": "默认文本",
        "allmessagescurrent": "当前文本",
        "allmessagestext": "该个是MediaWiki名字空间里可用个系统消息列表。如果想搭MediaWiki个本地化贡献翻译,请访问[https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki本地化]搭[https://translatewiki.net translatewiki.net]。",
-       "allmessagesnotsupportedDB": "'''{{ns:special}}:Allmessages''' 呒处显示,因为 '''$wgUseDatabaseMessages''' 关勒浪。",
+       "allmessages-not-supported-database": "'''{{ns:special}}:Allmessages''' 呒处显示,因为 '''$wgUseDatabaseMessages''' 关勒浪。",
        "thumbnail-more": "放大",
        "filemissing": "文件寻弗着哉",
        "importlogpage": "导入记录",
index 8ef8fb3..c3f9d6e 100644 (file)
        "minoreditletter": "ჭ.რ.",
        "newpageletter": "ახ.",
        "boteditletter": "ბ",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|მომხმარებლის|მომხმარებლის}} კონტროლი]",
        "rc-change-size-new": "ზჷმა თირუაშ უკული რე: {{PLURAL:$1|ბაიტი|ბაიტი}}",
        "newsectionsummary": "/* $1 */ ახალი სექცია",
        "rc-enhanced-expand": "დეტალების  ჩვენება",
index 304e56b..a8933d2 100644 (file)
        "rcfilters-activefilters-show": "pinakita’",
        "rcfilters-days-show-days": "$1 hahila:",
        "rcfilters-savedqueries-cancel-label": "kayni’",
-       "rcfilters-filtergroup-lastRevision": " ’ima SaSo’ pinonrowa’",
+       "rcfilters-filtergroup-lastrevision": " ’ima SaSo’ pinonrowa’",
        "rcnotefrom": "hani wahoer{{PLURAL:$5| ’ima}} ’aring <strong>$3 $4</strong> pinara:an ka pyenti: (kapakita’ <strong>$1</strong> ).",
        "rclistfrom": "pinakita’ ray $3 $2 ka ’ima SaSo’ sinapih",
        "rcshowhideminor": "$1 pinaybiil bienji",
index c4bcc04..7adbe7b 100644 (file)
        "page_first": "ערשט",
        "page_last": "לעצט",
        "histlegend": "פֿארגלייכן  אויסקלויב: צייכנט די קנעפלעך פֿון די ווערסיעס צו פֿארגלײַכן, און קלאפט  Enter אדער דאס קנעפל '''{{int:compareselectedversions}}'''.<br />\nשליסל: '''({{int:cur}})''' = אונטערשייד פֿון לויפֿיגער ווערסיע, '''({{int:last}})''' = אונטערשייד פֿון פֿריערדיגער ווערסיע, '''({{int:last}})''' = מינערדיקע רעדאקטירונג",
-       "history-fieldset-title": "×\96×\95×\9bן ווערסיעס",
+       "history-fieldset-title": "פֿ×\99×\9c×\98ערן ווערסיעס",
        "history-show-deleted": "נאר אויסגעמעקטע ווערסיעס",
        "histfirst": "עלטסטע",
        "histlast": "נײַעסטע",
        "historysize": "({{PLURAL:$1|1 בייט|$1 בייטן}})",
-       "historyempty": "(ליידיג)",
+       "historyempty": "ליידיג",
        "history-feed-title": "ווערסיע היסטאריע",
        "history-feed-description": "ווערסיע היסטאריע פאר דעם בלאט אויפן וויקי",
        "history-feed-item-nocomment": "$1 אין $2",
        "right-reupload-own": "איבערשרײַבן עקזיסטירנדע טעקעס וואָס מ'האט אַליין אַרויפֿגעלאָדן",
        "right-reupload-shared": "אריבערשרייבן טעקעס אויפן געמיינזאם מעדיע רעפאזיטאריום",
        "right-upload_by_url": "ארויפֿלאָדן טעקעס פֿון אַ URL",
-       "right-purge": "ליידיקן דעם זייטל־זאפאס פאר א בלאט אן באשטעטיקונג",
+       "right-purge": "ליידיקן דעם זייטל־זאפאס פאר א בלאט",
        "right-autoconfirmed": "רעדאקטירן האלב-געשיצטע בלעטער",
        "right-bot": "באַהאַנדלונג ווי אַן אויטאמאַטישער פראצעס",
        "right-nominornewtalk": "מינערדיקע רעדאקטירונגען צו שמועס בלעטער זאלן נישט שאפן די \"נייע מודעות\" מעלדונג",
        "grant-oversight": "באהאלטן באניצער און אונטערדריקן ווערסיעס",
        "grant-patrol": "פאטראלירן ענדערונגען צו בלעטער",
        "grant-privateinfo": "צוטריט צו פריוואטער אינפֿארמאציע",
+       "grant-protect": "שיצן און באפֿרייען בלעטער",
        "grant-rollback": "צוריקזעצען ענדערונגען צו בלעטער",
        "grant-sendemail": "שיקן ע-פאסט צו אנדערע באניצער",
        "grant-uploadeditmovefile": "ארויפֿלאדן, טוישן און באוועגן טעקעס",
        "action-applychangetags": "אנווענדן טאגן צוזאמען מיט אייערע ענדערונגען",
        "action-deletechangetags": "אויסמעקן טאגן פון דער דאטנבאזע",
        "action-purge": "אויסרייניגן דעם דאזיגן בלאט",
+       "action-editinterface": "רעדאַקטירן די באַניצער אייבערפֿלאַך",
+       "action-editusercss": "רעדאַקטירן אַנדערע באַניצערס CSS טעקעס",
+       "action-edituserjson": "רעדאַקטירן אַנדערע באַניצערס JSON טעקעס",
+       "action-edituserjs": "רעדאַקטירן אַנדערע באַניצערס JavaScript טעקעס",
+       "action-editmyusercss": "רעדאקטירן אײַערע אייגענע באניצער CSS טעקעס",
+       "action-editmyuserjson": "רעדאקטירן אײַערע אייגענע באניצער CSS טעקעס",
+       "action-unblockself": "זיך אליין אויפֿשפאַרן",
        "nchanges": "{{PLURAL:$1|ענדערונג|$1 ענדערונגען}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|זײַט לעצטן וויזיט}}",
        "enhancedrc-history": "היסטאריע",
        "rcfilters-savedqueries-apply-label": "שאפן פילטער",
        "rcfilters-savedqueries-cancel-label": "אַנולירן",
        "rcfilters-clear-all-filters": "אפראמען אלע פֿילטערן",
-       "rcfilters-show-new-changes": "×\95×\95×\99×\99×\96×\9f ×\93×\99 × ×\99×\99עס×\98×¢ ×¢× ×\93ער×\95× ×\92×¢×\9f",
+       "rcfilters-show-new-changes": "×\95×\95×\99×\99×\96×\9f × ×\99×\99×¢ ×¢× ×\93ער×\95× ×\92×¢×\9f ×\96×\99×\99×\98 $1",
        "rcfilters-search-placeholder": "פֿילטערן ענדערונגען (ניצט מעניו אדער זוכט פֿילטער־נאמען)",
        "rcfilters-invalid-filter": "אומגילטיגער פֿילטער",
        "rcfilters-empty-filter": "קיין אַקטיווע פילטערס. אלע ביישטייערונגען געוויזן.",
        "rcfilters-filter-pageedits-label": "בלאט רעדאקטירונגען",
        "rcfilters-filter-newpages-label": "בלאַט־שאַפֿונגען",
        "rcfilters-filter-categorization-label": "קאטעגאריע־ענדערונגען",
-       "rcfilters-filtergroup-lastRevision": "לעצטע ווערסיעס",
+       "rcfilters-filtergroup-lastrevision": "לעצטע ווערסיעס",
        "rcfilters-filter-lastrevision-label": "לעצטע ווערסיע",
        "rcfilters-filter-previousrevision-label": "נישט די לעצטע ווערסיעס",
        "rcfilters-filter-excluded": "אויסגעשלאסן",
        "minoreditletter": "מ",
        "newpageletter": "נ",
        "boteditletter": "ב",
-       "number_of_watching_users_pageview": "[{{PLURAL:$1|איין באַניצער פאַסט|$1 באַניצערס פאַסן}} אויף]",
        "rc-change-size-new": "$1 {{PLURAL:$1|בייט|בייטן}} נאך דער ענדערונג",
        "newsectionsummary": "/* $1 */ נייע אפטיילונג",
        "rc-enhanced-expand": "צייגן דעטאלן",
        "img-auth-accessdenied": "צוטריט אָפגעזאָגט",
        "img-auth-notindir": "געשיכטעס שטעג איז נישט אין דער קאנפיגורטער ארויפלאד־דירעקטאריע.",
        "img-auth-badtitle": "קען נישט שאפֿן א גילטיקן טיטל פֿון \"$1\"",
-       "img-auth-nologinnWL": "איר זענט נישט ארײַנלאגירט און \"$1\" איז נישט אין דער ווײַסער ליסטע.",
        "img-auth-nofile": "טעקע \"$1\" עקזיסטירט נישט.",
        "img-auth-isdir": "איר פֿארזיכט צוצוטרעטן אן ארכיוו \"$1\".\nנאר טעקע צוטריט איז ערלויבט.",
        "img-auth-streaming": "שטראָמענדיק \"$1\".",
        "apisandbox-retry": "פרובירן נאכאמאל",
        "apisandbox-helpurls": "הילף לינקען",
        "apisandbox-examples": "ביישפילן",
+       "apisandbox-dynamic-parameters": "נאך פאראמעטערס",
        "apisandbox-dynamic-parameters-add-label": "צולייגן פאראמעטער:",
        "apisandbox-dynamic-parameters-add-placeholder": "פאראמעטער נאמען",
        "apisandbox-dynamic-error-exists": "ס׳איז שוין פֿאראן א פאראמעטער מיטן נאמען \"$1.",
        "delete-confirm": "אויסמעקן $1",
        "delete-legend": "אויסמעקן",
        "historywarning": "<strong>אכטונג:</strong> איר גייט אויסמעקן א בלאט וואָס האט א היסטאריע מיט $1 {{PLURAL:$1|ווערסיע|ווערסיעס}}:",
-       "historyaction-submit": "ווייזן",
+       "historyaction-submit": "ווייזן ווערסיעס",
        "confirmdeletetext": "איר גייט איצט אויסמעקן א בלאט צוזאַמען מיט זײן גאנצער היסטאריע.\n\nביטע באשטעטיגט אז דאס איז טאקע אייער כוונה, אז איר פארשטייט פולערהייט די קאנסקווענסן פון דעם אַקט, און אז דאס איז אין איינקלאנג מיט [[{{MediaWiki:Policy-url}}|דער פאליסי]].",
        "actioncomplete": "די אַקציע אָט זיך דורכגעפֿירט",
        "actionfailed": "אקציע דורכגעפאלן",
        "dellogpagetext": "ווייטער איז א ליסטע פון די מערסט לעצטיגע אויסמעקונגען.",
        "deletionlog": "אויסמעקונג לאג",
        "log-name-create": "בלאַט־שאַפֿונג לאגבוך",
+       "log-description-create": "אונטן איז א ליסטע פון די מערסט לעצטיגע שאפֿונגען.",
+       "logentry-create-create": "$1 {{GENDER:$2|האט געשאפֿן}} בלאט $3",
        "reverted": "צוריקגעשטעלט צו פֿריערדיקער באַאַרבעטונג",
        "deletecomment": "אורזאַך:",
        "deleteotherreason": "אנדער/נאך אן אורזאך:",
        "deleteprotected": "איר קענט נישט אויסמעקן דעם בלאט ווײַל ער איז געשיצט.",
        "deleting-backlinks-warning": "</strong>ווארענוג:<strong>\n[[Special:WhatLinksHere/{{FULLPAGENAME}}|אנדערע בלעטער]]  פארבינדן צום בלאט אדער אריבערשליסן דעם בלאט איר האלט ביי אויסמעקן.",
        "rollback": "צוריקדרייען רעדאַקטירונגען",
+       "rollback-confirmation-confirm": "זייט אזוי גוט באשטעטיקן:",
+       "rollback-confirmation-yes": "צוריקדרייען",
+       "rollback-confirmation-no": "אַנולירן",
        "rollbacklink": "צוריקדרייען",
        "rollbacklinkcount": "צוריקדרייען $1 {{PLURAL:$1|רעדאקטירונג|רעדאקטירונגען}}",
        "rollbacklinkcount-morethan": "צוריקדרייען מער ווי $1 {{PLURAL:$1|רעדאקטירונג|רעדאקטירונגען}}",
        "undelete-search-title": "זוכן אויסגעמעקטע בלעטער",
        "undelete-search-box": "זוכן אויסגעמעקטע בלעטער",
        "undelete-search-prefix": "ווײַז בלעטער וואס הייבן אן מיט:",
+       "undelete-search-full": "ווייזן בלאט־טיטלען וואס אנטהאלטן:",
        "undelete-search-submit": "זוכן",
        "undelete-no-results": "נישט געטראפן קיין צוגעפאסטע בלעטער אין אויסמעקונג ארכיוו.",
        "undelete-cleanup-error": "גרײַז בײַם אויסמעקן נישט געניצטע ארכיוו טעקע \"$1\".",
        "mycontris": "בײַשטײַערונגען",
        "anoncontribs": "בײַשטײַערונגען",
        "contribsub2": "פֿאַר {{GENDER:$3|$1}} ($2)",
+       "contributions-subtitle": "פֿאַר {{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "באניצער קאנטע \"$1\" איז נישט איינגעשריבן.",
        "nocontribs": "נישט געטראפן קיין ענדערונגען צוזאמעגעפאסט מיט די קריטעריעס.",
        "uctop": "לויפֿיק",
        "ipbreason": "אורזאַך:",
        "ipbreason-dropdown": "* פֿארשפרייטע בלאקירן סיבות\n** ארײַנלייגן פֿאלשע אינפֿארמאציע\n** אויסמעקן אינהאַלט פֿון בלעטער\n** פֿארפֿלייצן לינקען צו דרויסנדיקע ערטער\n** ארײַנלייגן שטותים/טאָטעריש אין בלעטער\n** סטראשעט און שטערט\n** קרומבאניצן מערערע קאנטעס\n** באַניצער נאָמען פראבלעמאַטיש",
        "ipb-hardblock": "פארמיידן אריינלאגירטע באניצער פון רעדאקטירן פון דעם IP־אדרעס",
-       "ipbcreateaccount": "פֿ×\90ַר×\9eײַ×\93×\9f ×©×\90ַפֿ×\9f ×§×\90× ×\98עס",
-       "ipbemailban": "פֿ×\90ר×\9eײַ×\93×\9f ×\91×\90Ö·× ×\99צער ×¤×\95×\9f ×©×\99ק×\9f ×¢Ö¾×¤×\90ס×\98",
+       "ipbcreateaccount": "שאַפֿן קאנטעס",
+       "ipbemailban": "שיקן ע־פאסט",
        "ipbenableautoblock": "אויטאמאַטיש בלאקירן דעם לעצטן IP אַדרעס פֿון דעם באַניצער, און אַבי וועלכן IP אַדרעס ער פרובירט צו ניצן",
        "ipbsubmit": "בלאקירן דעם באַניצער",
        "ipbother": "אַנדער צײַט",
        "ipboptions": "2 שעהן:2 hours,\n1 טאָג:1 day,\n3 טעג:3 days,\n1 װאָך:1 week,\n2 װאָכן:2 weeks,\n1 מאָנאַט:1 month,\n3 מאָנאַטן:3 months,\n6 מאָנאַטן:6 months,\n1 יאָר:1 year,\nאויף אייביק:infinite",
        "ipbhidename": "באַהאַלטן באַניצער נאָמען פֿון רעדאַקטירונגען און רשימות",
        "ipbwatchuser": "אויפֿפאַסן דעם באַניצערס באַניצער און רעדן בלעטער",
-       "ipb-disableusertalk": "פ×\90ר×\9eײַ×\93×\9f ×\93×¢×\9d ×\91×\90× ×\99צער ×¤×\95×\9f ×¨×¢×\93×\90ק×\98×\99ר×\9f ×\96ײַ×\9f ×\90×\99×\99×\92×¢× ×¢×\9d ×¨×¢×\93×\9f ×\91×\9c×\90×\98 ×\91שעת ×¢×¨ ×\90×\99×\96 ×\91×\9c×\90ק×\99רט",
+       "ipb-disableusertalk": "רע×\93×\90ק×\98×\99ר×\9f ×\93×¢×\9d ×\90×\99×\99×\92×¢× ×¢×\9d ×¨×¢×\93×\9f ×\91×\9c×\90ט",
        "ipb-change-block": "ווידער-בלאקירן דעם באניצער מיט די דאזיקע אײַנשטעלונגען",
        "ipb-confirm": "באַשטעטיקן בלאָק",
+       "ipb-sitewide": "אויפן גאנצץ וועבזייטל",
        "ipb-partial": "טיילווײַז",
        "ipb-pages-label": "בלעטער",
+       "ipb-namespaces-label": "נאָמענטיילן",
        "badipaddress": "נישט קיין גוטער IP אַדרעס.",
        "blockipsuccesssub": "בלאק איז דורכגפירט מיט דערפֿאלג",
        "blockipsuccesstext": "באַניצער [[Special:Contributions/$1|$1]] <br />איז פֿאַרשפאַרט.\nזעט די [[Special:BlockList|ליסטע פון בלאקירטע באַניצער]] כדי צו זען די בלאקירונגען.",
        "ipb-blocklist-contribs": "בײַשטײַערונגען פֿון {{GENDER:$1|$1}}",
        "ipb-blocklist-duration-left": "נאך $1",
        "block-expiry": "אויסגיין:",
+       "block-reason": "אורזאַך:",
+       "block-target": "באניצער־נאמען אדער IP-אדרעס:",
        "unblockip": "אויפֿבלאקירן באניצער",
        "unblockiptext": "מיט דעם פארמולאר קענט איר צוריקשטעלן שרייבן ערלויבניש צו אן IP אדרעס אדער באניצער נאמען וואס איז געווען בלאקירט.",
        "ipusubmit": "אוועקנעמען דעם בלאק",
        "unblocked-id": "בלאק $1 איז געווארן אַראָפגענומען.",
        "unblocked-ip": "[[Special:Contributions/$1|$1]] איז געווארן אויפבלאקירט.",
        "blocklist": "בלאקירטע באַניצער",
+       "autoblocklist": "אויטאמאטישע בלאקירונגען",
        "autoblocklist-submit": "זוכן",
        "ipblocklist": "בלאקירטע באַניצער",
        "ipblocklist-legend": "געפֿינען א בלאקירטן באניצער",
        "blocklist-userblocks": "באהאלטן קאנטע בלאקן",
        "blocklist-tempblocks": "באהאלטן צײַטווײַליקע בלאקן",
        "blocklist-addressblocks": "באהאלטן ענצעלע IP בלאקן",
+       "blocklist-type": "טיפ:",
+       "blocklist-type-opt-all": "אַלע",
+       "blocklist-type-opt-sitewide": "אויפן גאנצץ וועבזייטל",
+       "blocklist-type-opt-partial": "טיילווײַז",
        "blocklist-timestamp": "צײַטשטעמפל",
        "blocklist-target": "ציל",
        "blocklist-expiry": "גייט אויס:",
        "emailblock": "בליצפאסט בלאקירט",
        "blocklist-nousertalk": "קען נישט רעדאַקטירן דעם אייגענעם רעדן בלאַט",
        "blocklist-editing": "רעדאקטירן",
+       "blocklist-editing-ns": "נאָמענטיילן",
        "ipblocklist-empty": "בלאקירן ליסטע איז  ליידיג.",
-       "ipblocklist-no-results": "×\93ער ×\92×¢×\96×\95×\9b×\98ער IP ×\90Ö·×\93רעס ×\90Ö¸×\93ער ×\91×\90Ö·× ×\99צער × ×\90×\9e×¢×\9f ×\90×\99×\96 × ×\99×\98 ×¤Ö¿×\90ַרשפ×\90ַר×\98.",
+       "ipblocklist-no-results": "ק×\99×\99×\9f ×¤×\90ַסנ×\93×\99קע ×¤Ö¿×\90ַרשפ×\90ַר×\95× ×\92×¢×\9f × ×\99ש×\98 ×\92×¢×\98ר×\90פֿ×\9f ×¤Ö¿×\90ַר×\9f ×\92×¢×\96×\95×\9b×\98×\9f IP ×\90Ö·×\93רעס ×\90Ö¸×\93ער ×\91×\90Ö·× ×\99צער־נ×\90×\9e×¢×\9f.",
        "blocklink": "ארויסטרייבן",
        "unblocklink": "באַפֿרײַען",
        "change-blocklink": "ענדערן בלאק",
        "allmessagesdefault": "גרונטלעכער טעקסט",
        "allmessagescurrent": "איצטיגער טעקסט",
        "allmessagestext": "אט דאס איז א ליסטע פון אלע סיסטעם מעלדונגען וואס זענען פאראן אין דעם  {{ns:mediawiki}}  נאמענטייל, וואס באדינען דעם אויפהאלט פונעם סייט.\n\nסיסאפן קענען ענדערן די מעלדונגען דורך דרוקן אויפן נאמען פון דער מעלדונג.\n\nביטע באזוכט [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation מעדיעוויקי לאקאליזאציע] און [https://translatewiki.net בעטאוויקי] אויב איר ווילט ביישטייערן צו דער גענערישער מעדיעוויקי לאקאליזאציע.",
-       "allmessagesnotsupportedDB": "מען קען זיך נישט באניצן מיט דעם בלאט וויבאלד די $wgUseDatabseMessages איז געווארן בטל.",
+       "allmessages-not-supported-database": "מען קען זיך נישט באניצן מיט דעם בלאט וויבאלד די $wgUseDatabseMessages איז געווארן בטל.",
        "allmessages-filter-legend": "פילטער",
        "allmessages-filter": "פֿילטערן לויטן סטאטוס פון מעלדונג:",
        "allmessages-filter-unmodified": "נישט מאדיפֿיצירט",
        "confirm-unwatch-button": "יאָ",
        "confirm-unwatch-top": "אראפנעמען דעם בלאט פון אייער אויפפאסונג ליסטע?",
        "confirm-rollback-button": "יאָ",
+       "confirm-mcrrestore-title": "צוריקשטעלן א רעוויזיע",
+       "confirm-mcrundo-title": "צוריקשטעלן אן ענדערונג",
+       "mcrundofailed": "צוריקשטעלן דורכגעפאלן",
        "quotation-marks": "„$1“",
        "imgmultipageprev": "→ פֿריערדיגער בלאַט",
        "imgmultipagenext": "צום קומענדיגן בלאט ←",
        "autosumm-blank": "אויסגעליידיקט דעם בלאט",
        "autosumm-replace": "פֿאַרבײַט דעם בלאַט מיט '$1'",
        "autoredircomment": "ווייטערפירן צו [[$1]]",
+       "autosumm-removed-redirect": "אַוועקגענומען ווייטערפֿירונג צו בלאַט [[$1]]",
        "autosumm-changed-redirect-target": "געענדערט ווייטערפירונג ציל פון בלאט [[$1]] צו בלאט [[$2]]",
        "autosumm-new": "געשאַפֿן בלאַט מיט '$1'",
        "autosumm-newblank": "ליידיגן בלאט געשאפן",
        "hebrew-calendar-m11-gen": "אב",
        "hebrew-calendar-m12-gen": "אלול",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|רעדן]])",
+       "timezone-local": "לאקאַל",
        "duplicate-defaultsort": "'''ווארענונג:''' גרונט סארטשליסל \"$2\" פֿאָרט איבערן פֿריערדיגן גרונט סארטשליסל \"$1\".",
        "duplicate-displaytitle": "<strong>ווארענונג:</strong> דער אויסשטעלונג־טיטל \"$2\" שרייבט איבער דעם פריערדיקן אויסשטעלונג־טיטל \"$1\".",
        "restricted-displaytitle": "<strong>ווארענונג:</strong> דער אויסשטעלונג־טיטל \"$1\" איז געווארן איגנארירט ווייל ער שטימט נישט מיטן עכטן טיטל פונעם בלאַט.",
        "version-entrypoints-header-url": "URL",
        "version-libraries-library": "ביבליאטעק",
        "version-libraries-version": "ווערסיע",
+       "version-libraries-license": "ליצענץ",
        "redirect": "ווייטערפֿירן לויט טעקע, באַניצער, בלאַט, ווערסיע אדער לאגבוך אידענטיפֿצירער",
        "redirect-submit": "גייט",
        "redirect-lookup": "זוכן:",
        "tags-create-submit": "שאַפֿן",
        "tags-delete-reason": "אורזאַך:",
        "tags-activate-reason": "גרונד:",
+       "tags-activate-submit": "אקטיוויזירן",
        "tags-deactivate-reason": "אורזאַך:",
+       "tags-edit-new-tags": "נייע טאַגן:",
        "comparepages": "פאַרגלייַכן בלעטער",
        "compare-page1": "עמוד 1",
        "compare-page2": "עמוד 2",
index fda47cb..d80af9b 100644 (file)
        "minoreditletter": "k",
        "newpageletter": "T",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[{{PLURAL:$1|Oníṣe $1|Àwọn oníṣe $1}} ún ṣe ìmójútó]",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} lẹ́yìn àtúnṣe",
        "newsectionsummary": "/* $1 */ abala tuntun",
        "rc-enhanced-expand": "Ìfihàn ẹ̀kúnrẹ́rẹ́",
        "img-auth-nopathinfo": "Kò sí PATH_INFO.\nẸ̀rọ-ìwọ̀fà yín kò létò láti mú dátà yìí kọjá.\nO ṣe é ṣe kó jẹ́ ti CGI tí kò ní ìtìlẹ́yìn fún img_auth.\nẸ wo [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization àṣẹ àwòrán.]",
        "img-auth-notindir": "Ojúọ̀nà tí ẹ tọrọ kò ní nínú àpò ìrùsókè alátòsílẹ̀.",
        "img-auth-badtitle": "Àkọlé oníìbámu kò ṣe é dá láti \"$1\".",
-       "img-auth-nologinnWL": "Ẹ kò tíì wọlẹ́ bẹ́ẹ̀sìni \"$1\" kò sí nínú àtòjọ funfun.",
        "img-auth-nofile": "Fáìlì \"$1\" kò sí.",
        "img-auth-isdir": "Ẹ̀ úngbira láti bọ́sí àpò \"$1\".\nÌbọ́sí fáìlì nìkan ló jẹ́ gbígbà láyè.",
        "img-auth-streaming": "Ó únṣe ìgbéhànjáde \"$1\".",
        "allmessagesdefault": "Ìkọ ìránṣẹ́ àtìbẹ̀rẹ̀",
        "allmessagescurrent": "Ìkọ ìránṣẹ́ lọ́wọ́",
        "allmessagestext": "Èyí ni àtòjọ àwọn ìránṣẹ́ sístẹ́mù tó wà nínú orúkọàyè MediaWiki.\nẸ lọ sí [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] àti [https://translatewiki.net translatewiki.net] tí ẹ bá fẹ́ kópa nínú ìyèdèpadà ìsiṣẹ́ MediaWiki.",
-       "allmessagesnotsupportedDB": "Ojúewé yìí kò ṣe é lò nítorípé '''$wgUseDatabaseMessages''' ti jẹ́ dídálẹkun.",
+       "allmessages-not-supported-database": "Ojúewé yìí kò ṣe é lò nítorípé '''$wgUseDatabaseMessages''' ti jẹ́ dídálẹkun.",
        "allmessages-filter-legend": "Ajọ̀",
        "allmessages-filter": "Ajọ̀ gẹ́gẹ́bí ipò ìṣàyàn:",
        "allmessages-filter-unmodified": "Àìtúnṣe",
index 6cd17f6..0be038f 100644 (file)
@@ -35,7 +35,8 @@
                        "Hello903hello",
                        "Fitoschido",
                        "Kanashimi",
-                       "Roy17"
+                       "Roy17",
+                       "Tang891228"
                ]
        },
        "tog-underline": "連結加底線:",
@@ -80,6 +81,7 @@
        "tog-norollbackdiff": "進行反轉之後唔睇差異",
        "tog-useeditwarning": "當我離開未保存好嘅修改嗰陣警告我",
        "tog-prefershttps": "簽到後繼續用加密連線",
+       "tog-showrollbackconfirmation": "撳「反轉」掣嘅時候要撳確認",
        "underline-always": "全部",
        "underline-never": "永不",
        "underline-default": "瀏覽器或瀏覽器膚色預設",
        "returnto": "返去$1。",
        "tagline": "出自{{SITENAME}}",
        "help": "幫手",
+       "help-mediawiki": "MediaWiki幫助",
        "search": "搵嘢",
        "searchbutton": "搵嘢",
        "go": "去",
        "title-invalid-talk-namespace": "所請求嘅版面標題指去未開嘅討論版。",
        "title-invalid-characters": "所請求嘅版面標題有「$1」呢個無效字符。",
        "title-invalid-relative": "標題有相對路徑。因為用戶嘅瀏覽器經常處理唔到相對路徑(./, ../),所以相對路徑無效。",
-       "title-invalid-magic-tilde": "所請求嘅版面標題有無效嘅波浪線魔字(<nowiki>~~~</nowiki>)。",
+       "title-invalid-magic-tilde": "所請求嘅版面標題有無效嘅波浪線魔字(<nowiki>~~~</nowiki>)。",
        "title-invalid-too-long": "所請求嘅版面標題太長。標題用UTF-8編碼嗰時嘅長度唔應該超過 $1 {{PLURAL:$1|字節}}",
        "title-invalid-leading-colon": "所請求嘅版面標題開頭有無效冒號。",
        "perfcached": "以下嘅資料係嚟自快取,可能唔係最新嘅。 最多有{{PLURAL:$1|一個結果|$1個結果}}響快取度。",
        "badretype": "你入嘅密碼前後不一。",
        "usernameinprogress": "呢個名嘅戶口已經開緊。\n請等等。",
        "userexists": "你入嘅用戶名已經有人用咗。\n唔該揀過個名啦。",
+       "createacct-normalization": "基於技術限制,你嘅用戶名會調整做「$2」。",
        "loginerror": "登入錯誤",
        "createacct-error": "開戶口出錯",
        "createaccounterror": "開唔到戶口:$1",
        "undo-failure": "呢個編輯唔能夠取消,由於同途中嘅編輯有衝突。",
        "undo-norev": "呢個編輯唔能夠取消,由於佢唔存在或者刪除咗。",
        "undo-nochange": "呢個編輯睇嚟經已一早取消咗。",
-       "undo-summary": "取消由[[Special:Contributions/$2|$2]] ([[User talk:$2|對話]])所做嘅修訂 $1",
+       "undo-summary": "取消由[[Special:Contributions/$2|$2]]([[User talk:$2|傾偈]])所做嘅修訂 $1",
        "undo-summary-username-hidden": "取消匿埋咗嘅用戶嘅修改版本 $1",
        "cantcreateaccount-text": "由呢個IP地址 ('''$1''') 開嘅新戶口已經被[[User:$3|$3]]封鎖。\n\n當中俾$3封鎖嘅原因係''$2''",
        "cantcreateaccount-range-text": "由呢個IP地址範圍<strong>$1</strong>(包括你個IP <strong>$4</strong>)開嘅新戶口已經畀[[User:$3|$3]]封鎖咗。\n\n$3畀嘅理由係<em>$2</em>",
        "page_first": "最頭",
        "page_last": "最尾",
        "histlegend": "選擇唔同版本:響兩個唔同版本嘅圓框分別撳一下,再撳最底的「比較被選修訂」掣以作比較。<br />\n說明:'''({{int:cur}})'''= 同最新修訂版本嘅差別,'''({{int:last}})'''= 同前一個修訂版本嘅差別,'''{{int:minoreditletter}}''' = 小修改。",
-       "history-fieldset-title": "編輯紀錄",
+       "history-fieldset-title": "篩選編輯紀錄",
        "history-show-deleted": "只顯示刪除咗嘅修訂",
        "histfirst": "最舊",
        "histlast": "最新",
        "historysize": "($1 {{PLURAL:$1|byte|bytes}})",
-       "historyempty": "(空)",
+       "historyempty": "",
        "history-feed-title": "修訂歷史",
        "history-feed-description": "響哩個wiki嘅哩一頁嘅修訂歷史",
        "history-feed-item-nocomment": "$1 響 $2",
        "history-feed-empty": "要求嘅頁面並唔存在。\n佢可能響哩個 wiki 度刪除咗或者改咗名。\n試吓[[Special:Search|響哩個wiki度搵]]有關新頁面嘅資料。",
-       "history-edit-tags": "編輯已經揀咗嘅分頁",
+       "history-edit-tags": "改揀咗嘅改動嘅標籤",
        "rev-deleted-comment": "(編輯摘要已經移除咗)",
        "rev-deleted-user": "(用戶名已經移除咗)",
        "rev-deleted-event": "(日誌詳情已經移除咗)",
        "right-reupload-own": "覆蓋由同一位上載嘅檔案",
        "right-reupload-shared": "於本地無視共用媒體檔案庫上嘅檔案",
        "right-upload_by_url": "由一個URL上載檔案",
-       "right-purge": "唔需要確認之下清除網站快取",
+       "right-purge": "清除版面嘅緩衝記憶體",
        "right-autoconfirmed": "唔受IP嘅利用率限制影響",
        "right-bot": "視為一個自動程序",
        "right-nominornewtalk": "小編輯唔引發新信息提示",
        "grant-editprotected": "改保護咗嘅版",
        "grant-highvolume": "大量編輯",
        "grant-oversight": "收埋用戶同禁止顯示修訂",
+       "grant-rollback": "反轉一啲版面嘅修改",
        "grant-sendemail": "寄電郵畀其他用戶",
        "grant-uploadeditmovefile": "上載、𠖫同搬檔",
        "grant-uploadfile": "上載新檔案",
        "action-writeapi": "用來寫API",
        "action-delete": "刪呢版",
        "action-deleterevision": "刪呢次修訂",
+       "action-deletelogentry": "剷日誌項目",
        "action-deletedhistory": "睇呢版嘅刪除歷史",
        "action-browsearchive": "搵刪咗嘅版",
        "action-undelete": "反刪呢一版",
        "rcfilters-filter-editsbyself-description": "你嘅貢獻。",
        "rcfilters-filter-editsbyother-label": "其他人改嘅嘢",
        "rcfilters-filter-editsbyother-description": "所有改過嘅嘢(除咗你自己)",
-       "rcfilters-filtergroup-userExpLevel": "開戶口同經驗",
+       "rcfilters-filtergroup-user-experience-level": "開戶口同經驗",
        "rcfilters-filter-user-experience-level-registered-label": "註冊咗",
        "rcfilters-filter-user-experience-level-registered-description": "簽到咗嘅編者。",
        "rcfilters-filter-user-experience-level-unregistered-label": "未註冊",
        "rcfilters-hideminor-conflicts-typeofchange-global": "「細修改」篩選條件同另一個或者幾個篩選條件有衝突,皆因有啲改動唔可以係「細修改」。衝突嘅篩選條件已經喺上面用緊嘅篩選條件嗰度標示。",
        "rcfilters-hideminor-conflicts-typeofchange": "有啲改動唔可以係「細修改」,所以呢個篩選條件同呢啲篩選條件有衝突:$1",
        "rcfilters-typeofchange-conflicts-hideminor": "呢個篩選條件同「細修改」篩選條件有衝突。有啲改動唔可以係「細修改」。",
-       "rcfilters-filtergroup-lastRevision": "最新嘅修訂",
+       "rcfilters-filtergroup-lastrevision": "最新嘅修訂",
        "rcfilters-filter-lastrevision-label": "最新嘅修訂",
        "rcfilters-filter-lastrevision-description": "只係頁面最近嘅一次改動。",
        "rcfilters-filter-previousrevision-label": "唔係最新嘅修訂",
        "minoreditletter": "m",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1位用戶監視]",
        "rc-change-size-new": "改完後係$1位元組",
        "newsectionsummary": "/* $1 */ 新小節",
        "rc-enhanced-expand": "顯示細節",
        "uploadstash-bad-path": "路徑唔存在。",
        "uploadstash-bad-path-invalid": "路徑無效。",
        "uploadstash-bad-path-unknown-type": "未知嘅類型「$1」。",
+       "uploadstash-no-extension": "副檔名係空嘅。",
        "uploadstash-zero-length": "檔案長度係零。",
        "invalid-chunk-offset": "非法偏移塊",
        "img-auth-accessdenied": "拒絕通行",
        "img-auth-nopathinfo": "無路徑資訊。\n你嘅伺服器一定要傳遞REQUEST_URI以及/或者係PATH_INFO變數。\n如果已經係噉,請試下開著$wgUsePathInfo。\n睇吓 https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization 。",
        "img-auth-notindir": "所請求嘅路徑唔響個已經設定咗嘅上載目錄。",
        "img-auth-badtitle": "唔能夠由\"$1\"整一個有效標題。",
-       "img-auth-nologinnWL": "你而家無登入,\"$1\"唔響個白名單度。",
        "img-auth-nofile": "檔案\"$1\"唔存在。",
        "img-auth-isdir": "你試過通行一個目錄\"$1\"。\n只係可以通行檔案。",
        "img-auth-streaming": "串流緊\"$1\"。",
        "delete-confirm": "刪除\"$1\"",
        "delete-legend": "刪除",
        "historywarning": "<strong>警告:</strong>你要刪除嘅頁面有大約$1次嘅修訂:",
-       "historyaction-submit": "顯示",
+       "historyaction-submit": "顯示修改記錄",
        "confirmdeletetext": "你準備刪除一個頁面或者圖像,包括佢嘅所有歷史版本。\n請確認你打算噉做,而且你知道後果係點,加上確認你噉做冇違反到[[{{MediaWiki:Policy-url}}]]。",
        "actioncomplete": "搞掂",
        "actionfailed": "搞唔掂",
        "delete-warning-toobig": "呢一版有一個好大量嘅編輯歷史,過咗$1次修訂。刪除佢可能會擾亂{{SITENAME}}嘅資料庫操作;響繼續嗰陣請小心。",
        "deleteprotected": "你唔可以刪呢版,因為佢畀人保護咗。",
        "deleting-backlinks-warning": "<strong>警告:</strong>有[[Special:WhatLinksHere/{{FULLPAGENAME}}|其他版]]連過來或嵌咗你準備刪嘅呢版。",
+       "deleting-subpages-warning": "<strong>警告:</strong>你刪緊嘅呢版有[[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|1版|$1版|51=超過50版}}]]子頁。",
        "rollback": "反轉修改",
+       "rollback-confirmation-confirm": "請確認:",
+       "rollback-confirmation-yes": "反轉",
+       "rollback-confirmation-no": "取消",
        "rollbacklink": "反轉",
        "rollbacklinkcount": "反轉 $1 次修改",
        "rollbacklinkcount-morethan": "反轉超過$1次嘅{{PLURAL:$1|edit|修改}}",
        "mycontris": "個人貢獻",
        "anoncontribs": "貢獻",
        "contribsub2": "{{GENDER:$3|$1}}嘅貢獻 ($2)",
+       "contributions-subtitle": "{{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "用戶「$1」未有註冊。",
        "nocontribs": "搵唔到符合呢啲條件嘅修改。",
        "uctop": "最新",
        "allmessagesdefault": "預設訊息文字",
        "allmessagescurrent": "現時訊息文字",
        "allmessagestext": "以下係 MediaWiki 空間名入邊現有系統信息嘅清單。\n如果想貢獻正宗嘅MediaWiki本地化嘅話,請參閱[https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki本地化]同埋[https://translatewiki.net translatewiki.net]。",
-       "allmessagesnotsupportedDB": "呢一版唔可以用,因為'''$wgUseDatabaseMessages'''已經閂咗。",
+       "allmessages-not-supported-database": "呢一版唔可以用,因為'''$wgUseDatabaseMessages'''已經閂咗。",
        "allmessages-filter-legend": "過濾",
        "allmessages-filter": "以自定狀況過濾:",
        "allmessages-filter-unmodified": "未改過",
        "confirm-unwatch-button": "好",
        "confirm-unwatch-top": "喺你嘅監視清單度刪走呢一版?",
        "confirm-rollback-button": "好",
+       "confirm-rollback-bottom": "呢個動作會立即反轉晒揀咗嘅修改。",
+       "confirm-mcrundo-title": "還原一個改動",
        "comma-separator": "、",
        "word-separator": "",
        "parentheses": "($1)",
        "tag-mw-blank": "清空",
        "tag-mw-replace": "換咗",
        "tag-mw-rollback": "反轉",
+       "tag-mw-rollback-description": "用「反轉」掣將之前修改打回頭嘅修改",
+       "tag-mw-undo": "還原",
+       "tag-mw-undo-description": "用「還原」掣還原之前修改嘅修改",
        "tags-title": "標籤",
        "tags-intro": "呢一版列示咗個軟件標示嘅編輯,同埋佢哋嘅解釋。",
        "tags-tag": "標籤名",
        "tags-hitcount": "$1次更改",
        "tags-create-reason": "原因:",
        "tags-create-submit": "開",
+       "tags-delete-explanation-warning": "呢個動作<strong>冇得返轉頭</strong>,係<strong>還原唔到</strong>嘅,就算資料庫管理員都還原唔到。唔該諗清楚你係咪想刪走呢個標籤。",
        "tags-delete-reason": "原因:",
        "tags-activate-title": "啟用標籤",
        "tags-activate-reason": "原因:",
        "passwordpolicies-policy-passwordcannotmatchusername": "密碼唔可以同用戶名一樣",
        "passwordpolicies-policy-passwordcannotmatchblacklist": "密碼唔可以同列入咗黑名單嘅密碼一樣",
        "passwordpolicies-policy-maximalpasswordlength": "密碼一定要短過$1個{{PLURAL:$1|字元}}長",
-       "passwordpolicies-policy-passwordcannotbepopular": "密碼唔可以{{PLURAL:$1|係最常見嘅密碼|喺最常見嘅$1個密碼一覽度}}"
+       "passwordpolicies-policy-passwordcannotbepopular": "密碼唔可以{{PLURAL:$1|係最常見嘅密碼|喺最常見嘅$1個密碼一覽度}}",
+       "unprotected-js": "基於安全理由,JavaScript唔可以由未保護嘅版載入。請淨係喺MediaWiki: 空間名或者係用戶子頁度開JavaScript。"
 }
index 0a18cd8..55de82f 100644 (file)
        "minoreditletter": "k",
        "newpageletter": "N",
        "boteditletter": "b",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|keêr|keêr}} op een volglieste]",
        "newsectionsummary": "/* $1 */ nieuwe subkop",
        "rc-enhanced-expand": "Details weerheven (JavaScript vereist)",
        "rc-enhanced-hide": "Verbarg details",
        "allmessagesdefault": "Standerttekst",
        "allmessagescurrent": "Tekst van noe",
        "allmessagestext": "Dit is 'n liest van aolle systeemteksten die-an in de MediaWiki-naemruumte stae.",
-       "allmessagesnotsupportedDB": "'''{{ns:special}}:Allmessages''' kan nie gebruukt ore om'at '''$wgUseDatabaseMessages''' uutgeschaekeld staet.",
+       "allmessages-not-supported-database": "!!FUZZY!!'''{{ns:special}}:Allmessages''' kan nie gebruukt ore om'at '''$wgUseDatabaseMessages''' uutgeschaekeld staet.",
        "thumbnail-more": "Verhroôt",
        "thumbnail_error": "Fout bie 't anmaek'n van de miniatuuraofbeêldienge: $1",
        "tooltip-pt-userpage": "Mien gebrukersbladzie",
index bb144ad..7b8eb25 100644 (file)
                        "GoForceX",
                        "Ff98sha",
                        "VulpesVulpes825",
-                       "佛壁灯"
+                       "佛壁灯",
+                       "94rain",
+                       "Viztor"
                ]
        },
        "tog-underline": "链接下划线:",
        "tog-norollbackdiff": "执行回退后不显示差异",
        "tog-useeditwarning": "当我离开编辑页面时,如果有尚未保存的更改,请提醒我",
        "tog-prefershttps": "在登录后总是使用安全连接",
+       "tog-showrollbackconfirmation": "当点击回退链接时显示确认提示",
        "underline-always": "始终",
        "underline-never": "从不",
        "underline-default": "皮肤或浏览器默认设置",
        "page_first": "首页",
        "page_last": "末页",
        "histlegend": "差异选择:选中要对比的版本的单选按钮,按Enter键或下方的按钮。<br />说明:<strong>({{int:cur}})</strong>=与最后版本之间的差异,<strong>({{int:last}})</strong>=与上一版本之间的差异,<strong>{{int:minoreditletter}}</strong>=小编辑。",
-       "history-fieldset-title": "搜索修订版本",
+       "history-fieldset-title": "筛选修订版本",
        "history-show-deleted": "仅限修订版本删除",
        "histfirst": "最旧",
        "histlast": "最新",
        "historysize": "($1字节)",
-       "historyempty": "(空)",
+       "historyempty": "",
        "history-feed-title": "版本历史",
        "history-feed-description": "本wiki的该页面的版本历史",
        "history-feed-item-nocomment": "$2 $1",
        "right-reupload-own": "覆盖自己上传的文件",
        "right-reupload-shared": "本地覆盖共享文件库的文件",
        "right-upload_by_url": "从URL上传文件",
-       "right-purge": "æ\97 ç¡®è®¤æ¸\85é\99¤é¡µé\9d¢ç¼\93å­\98",
+       "right-purge": "清除页面缓存",
        "right-autoconfirmed": "不受基于IP的速率限制",
        "right-bot": "被视为自动程序",
        "right-nominornewtalk": "不使小编辑在讨论页面引发新信息提示",
        "action-changetags": "在个别修订和日志记录中添加和移除任意标签",
        "action-deletechangetags": "从数据库删除标签",
        "action-purge": "刷新此页面",
+       "action-apihighlimits": "在API查询中使用更高的上限",
+       "action-autoconfirmed": "不受基于IP的速率限制",
+       "action-bigdelete": "删除有大型历史的页面",
+       "action-blockemail": "阻止用户发送电子邮件",
+       "action-bot": "被视为自动程序",
+       "action-editprotected": "编辑保护级别为“{{int:protect-level-sysop}}”的页面",
+       "action-editsemiprotected": "编辑保护级别为“{{int:protect-level-autoconfirmed}}”的页面",
+       "action-editinterface": "编辑用户界面",
+       "action-editusercss": "编辑其他用户的CSS文件",
+       "action-edituserjson": "编辑其他用户的JSON文件",
+       "action-edituserjs": "编辑其他用户的JavaScript文件",
+       "action-editsitecss": "编辑全站CSS",
+       "action-editsitejson": "编辑全站JSON",
+       "action-editsitejs": "编辑全站JavaScript",
+       "action-editmyusercss": "编辑您的用户CSS文件",
+       "action-editmyuserjson": "编辑您的用户JSON文件",
+       "action-editmyuserjs": "编辑您的用户JavaScript文件",
+       "action-viewsuppressed": "查看被隐藏的任何用户的修订",
+       "action-hideuser": "封禁并隐藏用户名",
+       "action-ipblock-exempt": "绕过IP封禁、自动封禁和段封禁",
+       "action-unblockself": "自我解封",
+       "action-noratelimit": "不受速率限制影响",
+       "action-reupload-own": "覆盖自己上传的文件",
+       "action-nominornewtalk": "不使小编辑在讨论页面引发新信息提示",
+       "action-markbotedits": "标记回退编辑为机器人编辑",
+       "action-patrolmarks": "查看最近更改的巡查标记",
+       "action-override-export-depth": "导出页面,包括最多5层链接",
+       "action-suppressredirect": "移动页面时不创建来源页面的重定向",
        "nchanges": "$1次更改",
        "enhancedrc-since-last-visit": "{{PLURAL:$1|自上次访问}}有$1次",
        "enhancedrc-history": "历史",
        "rcfilters-savedqueries-already-saved": "这些过滤器已保存。更改您的设置以创建新的保存过滤器。",
        "rcfilters-restore-default-filters": "恢复默认过滤器",
        "rcfilters-clear-all-filters": "清空所有过滤器",
-       "rcfilters-show-new-changes": "显示最新更改",
+       "rcfilters-show-new-changes": "显示自$1以来的最新更改",
        "rcfilters-search-placeholder": "过滤器更改(使用用于过滤器名称的菜单或搜索功能)",
        "rcfilters-invalid-filter": "无效过滤器",
        "rcfilters-empty-filter": "没有应用的过滤器。所有贡献都已显示。",
        "rcfilters-filter-editsbyself-description": "您自己的贡献。",
        "rcfilters-filter-editsbyother-label": "他人更改",
        "rcfilters-filter-editsbyother-description": "除您本人做出的所有更改。",
-       "rcfilters-filtergroup-userExpLevel": "用户注册及经验",
+       "rcfilters-filtergroup-user-experience-level": "用户注册及经验",
        "rcfilters-filter-user-experience-level-registered-label": "已注册",
        "rcfilters-filter-user-experience-level-registered-description": "已登录的编辑者。",
        "rcfilters-filter-user-experience-level-unregistered-label": "未注册",
        "rcfilters-hideminor-conflicts-typeofchange-global": "“小编辑”过滤器与一个或多个更改类型过滤器冲突,因为其中某种更改类型不可指定为“小编辑”。冲突过滤器已在上方活跃过滤器中被标记。",
        "rcfilters-hideminor-conflicts-typeofchange": "某种更改类型不可指定为“小编辑”,因此该过滤器与以下更改类型过滤器相冲突:$1",
        "rcfilters-typeofchange-conflicts-hideminor": "这种更改类型过滤器与“小编辑”过滤器相冲突。某种更改类型不可指定为“小编辑”。",
-       "rcfilters-filtergroup-lastRevision": "最新修订版本",
+       "rcfilters-filtergroup-lastrevision": "最新修订版本",
        "rcfilters-filter-lastrevision-label": "最新修订版本",
        "rcfilters-filter-lastrevision-description": "只显示对页面的最近一次更改。",
        "rcfilters-filter-previousrevision-label": "不是最新修订版本",
        "minoreditletter": "小",
        "newpageletter": "新",
        "boteditletter": "机",
-       "number_of_watching_users_pageview": "[$1个关注用户]",
        "rc-change-size-new": "更改后有$1字节",
        "newsectionsummary": "/* $1 */ 新章节",
        "rc-enhanced-expand": "显示细节",
        "img-auth-nopathinfo": "缺少路径信息。您的服务器必须适当配置以跳过REQUEST_URI和/或PATH_INFO变量。如果有,请尝试启用$wgUsePathInfo。请参见https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization。",
        "img-auth-notindir": "在已设置的上传目录中找不到请求的路径。",
        "img-auth-badtitle": "无法为“$1”创建合法的标题。",
-       "img-auth-nologinnWL": "您尚未登录,且“$1”不在白名单上。",
        "img-auth-nofile": "文件“$1”不存在。",
        "img-auth-isdir": "您正试图访问目录“$1”。您只能访问文件。",
        "img-auth-streaming": "流式化“$1”中。",
        "delete-confirm": "删除“$1”",
        "delete-legend": "删除",
        "historywarning": "<strong>警告:</strong>您将要删除的页面有约$1次{{PLURAL:$1|修订}}的历史:",
-       "historyaction-submit": "显示",
+       "historyaction-submit": "显示版本",
        "confirmdeletetext": "您即将删除一个页面或图像以及其历史。请确定您要进行此项操作,并且了解其后果,同时您的行为符合[[{{MediaWiki:Policy-url}}|方针]]。",
        "actioncomplete": "操作完成",
        "actionfailed": "操作失败",
        "deleting-backlinks-warning": "<strong>警告:</strong>有[[Special:WhatLinksHere/{{FULLPAGENAME}}|其他页面]]链接至或包含您要删除的页面。",
        "deleting-subpages-warning": "<strong>警告:</strong>您要删除的页面有[[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|$1个子页面|51=超过50个子页面}}]]。",
        "rollback": "回退编辑",
+       "rollback-confirmation-confirm": "请确认:",
+       "rollback-confirmation-yes": "回退",
+       "rollback-confirmation-no": "取消",
        "rollbacklink": "回退",
        "rollbacklinkcount": "回退$1次编辑",
        "rollbacklinkcount-morethan": "回退超过$1次的编辑",
        "revertpage": "恢复[[Special:Contributions/$2|$2]]([[User talk:$2|讨论]])的编辑至[[User:$1|$1]]的最后版本",
        "revertpage-nouser": "恢复隐藏用户的编辑至{{GENDER:$1|[[User:$1|$1]]}}的最后版本",
        "rollback-success": "已恢复{{GENDER:$3|$1}}的编辑;更改回{{GENDER:$4|$2}}的最后版本。",
-       "rollback-success-notify": "已回退$1的编辑,更改回$2的最后版本。[$3 显示更改]",
        "sessionfailure-title": "会话无效",
        "sessionfailure": "似乎您的登录会话有问题;为了防止会话劫持,这个操作已经被取消。请重新提交表单。",
        "changecontentmodel": "更改一个页面的内容模型",
        "mycontris": "贡献",
        "anoncontribs": "贡献",
        "contribsub2": "{{GENDER:$3|$1}}的贡献($2)",
+       "contributions-subtitle": "{{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "用户“$1”尚未注册。",
        "negative-namespace-not-supported": "不支持带有负值的命名空间",
        "nocontribs": "没有找到匹配这些规则的更改。",
        "ipb-confirm": "确认封禁",
        "ipb-sitewide": "全站范围",
        "ipb-partial": "部分的",
+       "ipb-sitewide-help": "在维基上的所有页面以及其它贡献行为。",
+       "ipb-partial-help": "特殊页面或名字空间。",
        "ipb-pages-label": "页面",
        "ipb-namespaces-label": "名字空间",
        "badipaddress": "无效IP地址",
        "blocklist-userblocks": "隐藏账户封禁",
        "blocklist-tempblocks": "隐藏临时封禁",
        "blocklist-addressblocks": "隐藏单个IP封禁",
+       "blocklist-type": "类型:",
+       "blocklist-type-opt-all": "全部",
+       "blocklist-type-opt-sitewide": "全站",
+       "blocklist-type-opt-partial": "部分的",
        "blocklist-rangeblocks": "隐藏IP段封禁",
        "blocklist-timestamp": "时间",
        "blocklist-target": "目标",
        "blocklist-editing-page": "页面",
        "blocklist-editing-ns": "名字空间",
        "ipblocklist-empty": "封禁列表为空。",
-       "ipblocklist-no-results": "请æ±\82ç\9a\84IPå\9c°å\9d\80æ\88\96ç\94¨æ\88·å\90\8d没æ\9c\89被封禁。",
+       "ipblocklist-no-results": "请æ±\82ç\9a\84IPå\9c°å\9d\80æ\88\96ç\94¨æ\88·å\90\8dæ\9cª被封禁。",
        "blocklink": "封禁",
        "unblocklink": "解封",
        "change-blocklink": "更改封禁",
+       "empty-username": "没有用户名",
        "contribslink": "贡献",
        "emaillink": "发送电子邮件",
        "autoblocker": "因为您与“[[User:$1|$1]]”共享一个IP地址而被自动封禁。$1被封禁的理由是“$2”",
        "allmessagesdefault": "默认信息文字",
        "allmessagescurrent": "当前信息文字",
        "allmessagestext": "此处列出了MediaWiki名字空间下的所有有效系统消息。如果想为MediaWiki的本地化贡献翻译,请访问[https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki本地化]和[https://translatewiki.net translatewiki.net]。",
-       "allmessagesnotsupportedDB": "此页面无法使用,因为'''$wgUseDatabaseMessages'''已被设置关闭。",
+       "allmessages-not-supported-database": "此页面无法使用,因为'''$wgUseDatabaseMessages'''已被设置关闭。",
        "allmessages-filter-legend": "过滤",
        "allmessages-filter": "按自定义状态过滤:",
        "allmessages-filter-unmodified": "未修改",
        "confirm-unwatch-top": "从监视列表中删除此页吗?",
        "confirm-rollback-button": "确定",
        "confirm-rollback-top": "回退此页面的编辑么?",
+       "confirm-rollback-bottom": "此操作会立即回退对于此页面的所选更改。",
        "confirm-mcrrestore-title": "还原版本",
        "confirm-mcrundo-title": "撤销一次更改",
        "mcrundofailed": "撤销失败",
        "passwordpolicies-policy-passwordcannotbepopular": "密码不能{{PLURAL:$1|是最常见的密码|在$1个最常见密码的列表中}}",
        "passwordpolicies-policy-passwordnotinlargeblacklist": "密码不能在100000个最常用的密码列表中。",
        "passwordpolicies-policyflag-forcechange": "必须在登录时更改",
+       "passwordpolicies-policyflag-suggestchangeonlogin": "建议在登录时更改",
        "easydeflate-invaliddeflate": "提供的内容未被适当缩小",
-       "unprotected-js": "基于安全原因,JavaScript不能在未保护页面中载入。请在 MediaWiki : 命名空间或者用户子页面中添加JavaScript。"
+       "unprotected-js": "基于安全原因,JavaScript不能在未保护页面中载入。请在 MediaWiki : 命名空间或者用户子页面中添加JavaScript。",
+       "userlogout-continue": "如果你希望登出请[$1 点这里]。",
+       "userlogout-sessionerror": "登出失败,会话错误。请[$1 重试]"
 }
index 79b07c1..79fb70f 100644 (file)
                        "Hello903hello",
                        "Luuva",
                        "Davidzdh",
-                       "WQL"
+                       "WQL",
+                       "Tang891228"
                ]
        },
        "tog-underline": "底線標示連結:",
        "tog-norollbackdiff": "執行回退後略過差異比對",
        "tog-useeditwarning": "未儲存離開編輯頁面時警告我",
        "tog-prefershttps": "永遠使用安全連線來登入",
-       "tog-showrollbackconfirmation": "當點擊回退連結時秀出確認提示畫面",
+       "tog-showrollbackconfirmation": "當點擊回退連結時顯示確認提示",
        "underline-always": "永遠使用",
        "underline-never": "永不使用",
        "underline-default": "外觀或瀏覽器預設",
        "clearyourcache": "<strong>注意:</strong>在您儲存之後您必須清除瀏覽器快取才可看到最新的變更。\n* <strong>Firefox / Safari:</strong>按住 <em>Shift</em> 時點選 <em>重新整理</em>,或按 <em>Ctrl-F5</em> 或 <em>Ctrl-R</em> (Mac 則為 <em>⌘-R</em>) \n* <strong>Google Chrome:</strong>按 <em>Ctrl-Shift-R</em> (Mac 則為 <em>⌘-Shift-R</em>) \n* <strong>Internet Explorer:</strong>按住 <em>Ctrl</em> 時點選 <em>重新整理</em>,或按 <em>Ctrl-F5</em>\n* <strong>Opera:</strong>前往 <em>選單 → 設定</em> (在 Mac 為 <em>Opera → 偏好設定</em>) 然後再到 <em>隱私 & 安全性 → 清除瀏覽資料 → 已快取的圖片與檔案</em>。",
        "usercssyoucanpreview": "<strong>提示:</strong>在儲存之前使用 \"{{int:showpreview}}\" 按鈕來測試您的新 CSS 。",
        "userjsonyoucanpreview": "<strong>提示:</strong>在儲存之前使用 \"{{int:showpreview}}\" 按鈕來測試您的新 JSON。",
-       "userjsyoucanpreview": "<strong>提示:</strong>在儲存之前使用 \"{{int:showpreview}}\" 按鈕來測試您的新 JavaScript 。",
+       "userjsyoucanpreview": "<strong>提示:</strong>在儲存之前使用「{{int:showpreview}}」按鈕來測試您的新 JavaScript。",
        "usercsspreview": "<strong>您目前正預覽您的使用者 CSS,CSS 還尚未儲存!</strong>",
        "userjsonpreview": "<strong>請注意您僅是在測試/預覽您的使用者 JSON 設定,內容還尚未儲存!</strong>",
        "userjspreview": "<strong>您目前正預覽您的使用者 JavaScript,JavaScript 還尚未儲存!</strong>",
        "page_first": "第一頁",
        "page_last": "最後頁",
        "histlegend": "比對選擇的版本差異:選擇要比對修訂版本的單選方塊並點選底部的按鈕進行比對。<br />\n符號說明:<strong>({{int:cur}})</strong> = 與最新的修訂版本比對,<strong>({{int:last}})</strong> = 與前一筆修訂版本比對,<strong>{{int:minoreditletter}}</strong> = 次要修訂。",
-       "history-fieldset-title": "搜尋修訂",
+       "history-fieldset-title": "篩選修訂",
        "history-show-deleted": "只顯示已刪除的修訂",
        "histfirst": "最舊",
        "histlast": "最新",
        "historysize": "($1 位元組)",
-       "historyempty": "(空)",
+       "historyempty": "",
        "history-feed-title": "修訂歷史",
        "history-feed-description": "本 Wiki 上此頁面的修訂歷史",
        "history-feed-item-nocomment": "$1 於 $2",
        "rev-suppressed-text-view": "此頁面修訂已被 <strong>禁止顯示</strong>。\n您可繼續檢視修訂,可至 [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} 禁止顯示日誌] 取得詳細資訊。",
        "rev-deleted-no-diff": "因頁面的其中一次修訂已被 <strong>刪除</strong>,您無法檢視差異。\n可至 [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 刪除日誌] 取得詳細資訊。",
        "rev-suppressed-no-diff": "因頁面的其中一次修訂已被 <strong>刪除</strong>,您無法檢視差異。",
-       "rev-deleted-unhide-diff": "檢視差異的其中一個修訂已被 <strong>刪除</strong>。\n可至 [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 刪除日誌] 取得詳細資料。\n若您要繼續,您仍可以 [$1 檢視此差異]。",
+       "rev-deleted-unhide-diff": "檢視差異的其中一個修訂已被 <strong>刪除</strong>。可至[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 刪除日誌]取得詳細資料。若您要繼續,您仍可以[$1 檢視此差異]。",
        "rev-suppressed-unhide-diff": "檢視差異的其中一個修訂已被 <strong>禁止顯示</strong>。\n可至 [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} 禁止顯示日誌] 取得詳細資訊。\n若您要繼續,您仍可以 [$1 檢視此差異]。",
        "rev-deleted-diff-view": "檢視差異的其中一個修訂已被 <strong>刪除</strong>。\n您可繼續檢視差異,可至 [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 刪除日誌] 取得詳細資訊。",
        "rev-suppressed-diff-view": "檢視差異的其中一個修訂已被 <strong>禁止顯示</strong>。\n您可繼續檢視差異,可至 [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} 禁止顯示日誌] 取得詳細資訊。",
        "right-suppressredirect": "移動頁面時不在原頁面位置建立重新導向頁面",
        "right-upload": "上傳檔案",
        "right-reupload": "覆蓋現有的檔案",
-       "right-reupload-own": "覆蓋自己上傳的檔案",
+       "right-reupload-own": "覆蓋自己上傳的現有檔案",
        "right-reupload-shared": "覆蓋共用媒體檔案庫於本地的檔案",
        "right-upload_by_url": "使用 URL 上傳檔案",
-       "right-purge": "不須確認即清除網站的頁面快取",
+       "right-purge": "清除頁面的站台快取",
        "right-autoconfirmed": "不受基於IP的使用頻率限制",
        "right-bot": "將其視為自動程序",
        "right-nominornewtalk": "不顯示討論頁面中次要編輯的新訊息提示",
        "right-block": "封鎖其他使用者的編輯權限",
        "right-blockemail": "封鎖使用者傳送電子郵件",
        "right-hideuser": "封鎖使用者名稱,避免公開顯示",
-       "right-ipblock-exempt": "略過 IP 封鎖、自動封鎖及範圍封鎖檢查",
+       "right-ipblock-exempt": "略過IP封鎖、自動封鎖及範圍封鎖檢查",
        "right-unblockself": "解除封鎖自己",
        "right-protect": "更改保護層級及編輯被連鎖保護的頁面",
        "right-editprotected": "編輯保護層級為「{{int:protect-level-sysop}}」的頁面",
        "right-editmyprivateinfo": "編輯自己的隱私資料 (如:電子郵件地址及真實姓名)",
        "right-editmyoptions": "編輯自己的偏好設定",
        "right-rollback": "快速回退最後一位使用者對某一頁面的編輯",
-       "right-markbotedits": "標示還原編輯為機人編輯",
+       "right-markbotedits": "標示還原編輯為機人編輯",
        "right-noratelimit": "不受使用頻率限制",
        "right-import": "由其他 Wiki 匯入頁面",
        "right-importupload": "由檔案上傳匯入頁面",
        "right-userrights": "編輯所有使用者的權限",
        "right-userrights-interwiki": "編輯使用者在其它 Wiki 上的權限",
        "right-siteadmin": "鎖定和解除鎖定資料庫",
-       "right-override-export-depth": "匯出頁面包含連結內容,深度上限為 5 層",
+       "right-override-export-depth": "匯出頁面包含連結內容,深度上限為5層",
        "right-sendemail": "傳送電子郵件聯絡其他使用者",
        "right-managechangetags": "建立並自資料庫 (取消) 啟用 [[Special:Tags|標籤]]",
        "right-applychangetags": "連同自己的變更一起套用[[Special:Tags|標籤]]",
        "action-changetags": "加入與移除任何於各別修訂與日誌項目的標籤",
        "action-deletechangetags": "從資料庫刪除標籤",
        "action-purge": "清除此頁面",
+       "action-apihighlimits": "提高API查詢上限值",
+       "action-autoconfirmed": "不受基於IP的使用頻率限制",
+       "action-bigdelete": "刪除有大量歷史記錄的頁面",
+       "action-blockemail": "封鎖使用者傳送電子郵件",
+       "action-bot": "將其視為自動程序",
+       "action-editprotected": "編輯保護層級為「{{int:protect-level-sysop}}」的頁面",
+       "action-editsemiprotected": "編輯保護層級為「{{int:protect-level-autoconfirmed}}」的頁面",
+       "action-editinterface": "編輯使用者介面",
+       "action-editusercss": "編輯其他使用者的 CSS 檔",
+       "action-edituserjson": "編輯其他使用者的 JSON 檔",
+       "action-edituserjs": "編輯其他使用者的 JavaScript 檔",
+       "action-editsitecss": "編輯全站 CSS",
+       "action-editsitejson": "編輯全站 JSON",
+       "action-editsitejs": "編輯全站 JavaScript",
+       "action-editmyusercss": "編輯您自己的使用者 CSS 檔",
+       "action-editmyuserjson": "編輯您自己的使用者 JSON 檔",
+       "action-editmyuserjs": "編輯自己的 JavaScript 檔",
+       "action-viewsuppressed": "檢視所有使用者隱藏的修訂",
+       "action-hideuser": "封鎖使用者名稱,避免公開顯示",
+       "action-ipblock-exempt": "略過IP封鎖、自動封鎖及範圍封鎖檢查",
+       "action-unblockself": "解除封鎖自己",
+       "action-noratelimit": "不受使用頻率限制",
+       "action-reupload-own": "覆蓋自己上傳的現有檔案",
+       "action-nominornewtalk": "不顯示討論頁面中次要編輯的新訊息提示",
+       "action-markbotedits": "標示還原編輯為機器人編輯",
+       "action-patrolmarks": "檢視近期變更的巡查標記",
+       "action-override-export-depth": "匯出頁面包含連結內容,深度上限為5層",
+       "action-suppressredirect": "移動頁面時不在原頁面位置建立重新導向頁面",
        "nchanges": "$1 次變更",
        "enhancedrc-since-last-visit": "{{PLURAL:$1|自上次拜訪}}有$1次",
        "enhancedrc-history": "歷史",
        "rcfilters-savedqueries-already-saved": "這些篩選已被儲存。變更您的設定,來建立新的已儲存篩選。",
        "rcfilters-restore-default-filters": "還原預設過濾條件",
        "rcfilters-clear-all-filters": "清除所有篩選條件",
-       "rcfilters-show-new-changes": "檢視新變更",
+       "rcfilters-show-new-changes": "檢視自$1以來的新變更",
        "rcfilters-search-placeholder": "篩選變更(使用選單或搜尋篩選名稱)",
        "rcfilters-invalid-filter": "無效的篩選條件",
        "rcfilters-empty-filter": "沒有使用中的過濾條件。已顯示所有的貢獻。",
        "rcfilters-filter-editsbyself-description": "您的貢獻",
        "rcfilters-filter-editsbyother-label": "其他人的變更",
        "rcfilters-filter-editsbyother-description": "除了您以外的所有變更。",
-       "rcfilters-filtergroup-userExpLevel": "使用者註冊及經驗",
+       "rcfilters-filtergroup-user-experience-level": "使用者註冊及經驗",
        "rcfilters-filter-user-experience-level-registered-label": "已註冊",
        "rcfilters-filter-user-experience-level-registered-description": "已登入編輯者。",
        "rcfilters-filter-user-experience-level-unregistered-label": "未註冊",
        "rcfilters-hideminor-conflicts-typeofchange-global": "\"次要編輯\" 過濾條件與一個或多個變更類型篩選條件衝突,因為某些變更類型無法指定為 \"次要\"。衝突的篩選條件已在上方使用的篩選條件區域中標示。",
        "rcfilters-hideminor-conflicts-typeofchange": "某些變更類型無法指定為 \"次要\",所以此篩選條件與以下變更類型的篩選條件衝突:$1",
        "rcfilters-typeofchange-conflicts-hideminor": "此變更類型過濾條件與 \"次要編輯\" 過濾條件衝突,某些變更類型無法指定為 \"次要\"。",
-       "rcfilters-filtergroup-lastRevision": "最新修訂版本",
+       "rcfilters-filtergroup-lastrevision": "最新修訂版本",
        "rcfilters-filter-lastrevision-label": "最新修訂版本",
        "rcfilters-filter-lastrevision-description": "只包括對頁面的近期變更。",
        "rcfilters-filter-previousrevision-label": "不是最新修訂版本",
        "minoreditletter": "小",
        "newpageletter": "新",
        "boteditletter": "機",
-       "number_of_watching_users_pageview": "[$1 位正在監視的使用者]",
        "rc-change-size-new": "變更後為$1位元組",
        "newsectionsummary": "/* $1 */ 新章節",
        "rc-enhanced-expand": "顯示詳細資料",
        "img-auth-nopathinfo": "缺少路徑資訊。\n您的伺服器必須設定來傳遞 REQUEST_URI 以及/或 PATH_INFO 變數。\n若已如此,請嘗試啟動 $wgUsePathInfo。\n請參考 https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization。",
        "img-auth-notindir": "已設定的上傳目錄清單中不存在您指定的路徑。",
        "img-auth-badtitle": "無法使用 \"$1\" 建立有效的標題。",
-       "img-auth-nologinnWL": "您尚未登入,且 \"$1\" 並未在允許清單上。",
        "img-auth-nofile": "檔案 \"$1\" 不存在。",
        "img-auth-isdir": "您正嘗試存取目錄 \"$1\",\n僅允許存取檔案。",
        "img-auth-streaming": "傳輸 \"$1\" 中。",
        "booksources-search": "搜尋",
        "booksources-text": "下列清單包含其他銷售新書籍或二手書籍的網站連結,可會有你想尋找書籍的進一部資訊:",
        "booksources-invalid-isbn": "您提供的 ISBN 不正確,請檢查複製的來源是否有誤。",
-       "magiclink-tracking-rfc": "使用 RFC 魔連結的頁面",
-       "magiclink-tracking-rfc-desc": "此頁面使用 RFC 魔法連結的頁面,請參考 [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Magic_links mediawiki.org] 的如何遷移。",
-       "magiclink-tracking-pmid": "使用 PMID 魔連結的頁面",
-       "magiclink-tracking-pmid-desc": "此頁面使用 PMID 魔法連結的頁面,請參考 [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Magic_links mediawiki.org] 的如何遷移。",
-       "magiclink-tracking-isbn": "使用 ISBN 魔連結的頁面",
-       "magiclink-tracking-isbn-desc": "此頁面使用 ISBN 魔法連結的頁面,請參考 [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Magic_links mediawiki.org] 的如何遷移。",
+       "magiclink-tracking-rfc": "使用 RFC 魔連結的頁面",
+       "magiclink-tracking-rfc-desc": "此頁面使用RFC魔術連結,請參考[https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Magic_links mediawiki.org]以了解如何遷移。",
+       "magiclink-tracking-pmid": "使用 PMID 魔連結的頁面",
+       "magiclink-tracking-pmid-desc": "此頁面使用PMID魔術連結,請參考[https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Magic_links mediawiki.org]以了解如何遷移。",
+       "magiclink-tracking-isbn": "使用 ISBN 魔連結的頁面",
+       "magiclink-tracking-isbn-desc": "此頁面使用ISBN魔術連結,請參考[https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Magic_links mediawiki.org]以了解如何遷移。",
        "specialloguserlabel": "執行者:",
        "speciallogtitlelabel": "目標(標題或以 {{ns:user}}:使用者名稱 表示使用者):",
        "log": "日誌",
        "activeusers-noresult": "查無使用者。",
        "activeusers-submit": "顯示活動中的使用者",
        "listgrouprights": "使用者群組權限",
-       "listgrouprights-summary": "以下為此 Wiki 的使用者群組清單,以及相關的存取權限。\n您可以在 [[{{MediaWiki:Listgrouprights-helppage}}|詳細資訊]] 找到有關個別權限的資訊。",
+       "listgrouprights-summary": "以下為此 Wiki 的使用者群組清單,以及相關的存取權限。您可以在[[{{MediaWiki:Listgrouprights-helppage}}|詳細資訊]]找到有關個別權限的資訊。",
        "listgrouprights-key": "說明:\n* <span class=\"listgrouprights-granted\">已授予的權限</span>\n* <span class=\"listgrouprights-revoked\">已撤銷的權限</span>",
        "listgrouprights-group": "群組",
        "listgrouprights-rights": "權限",
        "post-expand-template-inclusion-category-desc": "展開模板後大小超過 <code>$wgMaxArticleSize</code> 導致部份模板未正常展開的頁面。",
        "post-expand-template-argument-category-desc": "展開模板參數後大小超過 <code>$wgMaxArticleSize</code> 的頁面 (有些於三括號中,如 <code>{{{Foo}}}</code>)。",
        "expensive-parserfunction-category-desc": "頁面使用太多消耗系統資源的解析器函數 (如 <code>#ifexist</code>)。\n請參考 [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgExpensiveParserFunctionLimit Manual:$wgExpensiveParserFunctionLimit]。",
-       "broken-file-category-desc": "含有損壞檔案連結的頁面 (內嵌檔案連結的檔案不存在)。",
+       "broken-file-category-desc": "含有損壞檔案連結的頁面(內嵌檔案連結的檔案不存在)。",
        "hidden-category-category-desc": "內容中使用 <code><nowiki>__HIDDENCAT__</nowiki></code> 的分類,可隱藏預設在頁面上顯示的分類連結方塊。",
        "trackingcategories-nodesc": "沒有可用的描述。",
        "trackingcategories-disabled": "已停用分類",
        "delete-confirm": "刪除 \"$1\"",
        "delete-legend": "刪除",
        "historywarning": "<strong>警告:</strong>您正要刪除的頁面內含 $1 次{{PLURAL:$1|的修訂}}歷史:",
-       "historyaction-submit": "顯示",
+       "historyaction-submit": "顯示修訂",
        "confirmdeletetext": "您正要刪除一個頁面或圖片以及其所有歷史。請確定您要進行此操作,並了解其後果,同時您的行為符合[[{{MediaWiki:Policy-url}}|方針]]。",
        "actioncomplete": "操作完成",
        "actionfailed": "操作失敗",
        "deleting-backlinks-warning": "<strong>警告:</strong>您正要刪除的頁面有[[Special:WhatLinksHere/{{FULLPAGENAME}}|其他頁面]]連結或引用。",
        "deleting-subpages-warning": "<strong>警告:</strong>您要刪除的頁面有[[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|$1個子頁面|51=超過50個子頁面}}]]。",
        "rollback": "復原編輯",
+       "rollback-confirmation-confirm": "請確認:",
+       "rollback-confirmation-yes": "回退",
+       "rollback-confirmation-no": "取消",
        "rollbacklink": "回退",
        "rollbacklinkcount": "還原 $1 次編輯",
        "rollbacklinkcount-morethan": "回退超過 $1 次{{PLURAL:$1|編輯}}",
        "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-notify": "已還原 $1 所做的編輯;\n變更回由 $2 修訂的最後一個版本。[$3 顯示變更]",
        "sessionfailure-title": "連線階段失敗",
        "sessionfailure": "您的登入連線階段似乎有問題,為了預防連線階段受到劫持攻擊,此動作已經被取消。請重新提交表單。",
        "changecontentmodel": "變更頁面的內容模型",
        "mycontris": "貢獻",
        "anoncontribs": "貢獻",
        "contribsub2": "{{GENDER:$3|$1}}的貢獻($2)",
+       "contributions-subtitle": "{{GENDER:$3|$1}}",
        "contributions-userdoesnotexist": "使用者帳號 \"$1\" 尚未註冊。",
        "negative-namespace-not-supported": "不支援帶有負值的命名空間。",
        "nocontribs": "沒有找到符合條件的變更。",
        "ipb-confirm": "確認封鎖",
        "ipb-sitewide": "全站範圍",
        "ipb-partial": "部分",
-       "ipb-sitewide-help": "在 wiki 上的各個頁面以及其它貢獻行為。",
-       "ipb-partial-help": "特殊頁面或命名空間。",
+       "ipb-sitewide-help": "在維基上的所有頁面以及其它貢獻行為。",
+       "ipb-partial-help": "指定頁面或命名空間。",
        "ipb-pages-label": "頁面",
        "ipb-namespaces-label": "命名空間",
        "badipaddress": "無效的 IP 位址",
        "blocklist-userblocks": "隱藏帳號封鎖",
        "blocklist-tempblocks": "隱藏暫時封鎖",
        "blocklist-addressblocks": "隱藏單一 IP 封鎖",
+       "blocklist-type": "類型:",
+       "blocklist-type-opt-all": "所有",
+       "blocklist-type-opt-sitewide": "全站範圍",
+       "blocklist-type-opt-partial": "部分",
        "blocklist-rangeblocks": "隱藏 IP 範圍封鎖",
        "blocklist-timestamp": "日期時間",
        "blocklist-target": "目標",
        "blocklist-editing-page": "頁面",
        "blocklist-editing-ns": "命名空間",
        "ipblocklist-empty": "封鎖清單為空。",
-       "ipblocklist-no-results": "請求的 IP 位址或使用者名稱尚未被封鎖。",
+       "ipblocklist-no-results": "未找出符合所請求 IP 位址或使用者名稱的封鎖。",
        "blocklink": "封鎖",
        "unblocklink": "解除封鎖",
        "change-blocklink": "變更封鎖",
+       "empty-username": "(沒有使用者名稱)",
        "contribslink": "貢獻",
        "emaillink": "傳送電子郵件",
        "autoblocker": "您的 IP 位址因最近被 [[User:$1|$1]] 使用過而被自動封鎖。\n封鎖 $1 的原因為 \"$2\"",
        "allmessagesdefault": "預設的訊息文字",
        "allmessagescurrent": "目前的訊息文字",
        "allmessagestext": "此處列出所有在 MediaWiki 命名空間中系統訊息。\n若您想參與官方的 MediaWiki 在地化,請參考 [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki 在地化] 與 [https://translatewiki.net translatewiki.net]。",
-       "allmessagesnotsupportedDB": "已停用 <strong>$wgUseDatabaseMessages</strong> 設定,無法使用此頁面。",
+       "allmessages-not-supported-database": "已停用 <strong>$wgUseDatabaseMessages</strong> 設定,無法使用此頁面。",
        "allmessages-filter-legend": "篩選",
        "allmessages-filter": "依修改狀況搜尋:",
        "allmessages-filter-unmodified": "未修改",
        "print.css": "/* 此處的 CSS 會影響列印輸出 */",
        "noscript.css": "/* 此 CSS 會影響沒有啟用 JavaScript 的使用者 */",
        "group-autoconfirmed.css": "/* 此 CSS 會影響自動確認的使用者 */",
+       "group-user.css": "/* 置於此處的CSS只會影響已註冊使用者 */",
        "group-bot.css": "/* 此 CSS 會影響機器人 */",
        "group-sysop.css": "/* 這裡的 CSS 會影響管理員 */",
        "group-bureaucrat.css": "/* 此 CSS 會影響行政員 */",
        "common.json": "/* 在此的任一 JavaScript 會為全部使用者在所有頁面裡載入。 */",
        "common.js": "/* 此 JavaScript 會用於使用者載入的每一個頁面。 */",
+       "group-autoconfirmed.js": "/* 這裡的任何JavaScript只會為自動確認的使用者載入 */",
+       "group-user.js": "/* 這裡的任何JavaScript只會為已註冊使用者載入 */",
+       "group-bot.js": "/* 這裡的任何JavaScript只會為機器人載入 */",
        "group-sysop.js": "/* 這裡的 JavaScript 會影響管理員 */",
+       "group-bureaucrat.js": "/* 這裡的任何JavaScript只會為行政員載入 */",
        "anonymous": "{{SITENAME}} 的匿名{{PLURAL:$1|使用者}}",
        "siteuser": "{{SITENAME}}使用者 $1",
        "anonuser": "{{SITENAME}} 匿名使用者 $1",
        "spam_blanking": "所有修訂均包含 $1 連結,清空中",
        "spam_deleting": "所有修訂均包含 $1 連結,刪除中",
        "simpleantispam-label": "防垃圾訊息檢查用。\n請 <strong>勿</strong> 填寫此欄位!",
-       "pageinfo-title": "\"$1\" 的資訊",
+       "pageinfo-title": "「$1」的資訊",
        "pageinfo-not-current": "抱歉,無法提供先前修訂的資訊。",
        "pageinfo-header-basic": "基本資訊",
        "pageinfo-header-edits": "編輯歷史",
        "confirm-unwatch-top": "從您的監視清單中移除此頁面?",
        "confirm-rollback-button": "確定",
        "confirm-rollback-top": "還原編輯到此頁面?",
+       "confirm-rollback-bottom": "此操作會立即回退對於此頁面的所選更改。",
        "confirm-mcrrestore-title": "還原修訂",
        "confirm-mcrundo-title": "還原變更",
        "mcrundofailed": "還原失敗",
        "version-libraries-description": "描述",
        "version-libraries-authors": "作者",
        "redirect": "依檔案、使用者、頁面、修訂或日誌 ID 來重新導向",
-       "redirect-summary": "此特殊頁面可用來重新導向至檔案 (指定檔案名稱)、頁面 (指定修訂 ID 或頁面 ID)、使用者頁面 (指定使用者 ID)、或者日誌項目 (指定日誌 ID)。用法:[[{{#Special:Redirect}}/file/Example.jpg]]、[[{{#Special:Redirect}}/page/64308]]、[[{{#Special:Redirect}}/revision/328429]]、[[{{#Special:Redirect}}/user/101]] 或 [[{{#Special:Redirect}}/logid/186]]。",
+       "redirect-summary": "此特殊頁面可用來重新導向至檔案(指定檔案名稱)、頁面(指定修訂 ID 或頁面 ID)、使用者頁面(指定使用者 ID)、或者日誌項目(指定日誌 ID)。用法:[[{{#Special:Redirect}}/file/Example.jpg]]、[[{{#Special:Redirect}}/page/64308]]、[[{{#Special:Redirect}}/revision/328429]]、[[{{#Special:Redirect}}/user/101]] 或 [[{{#Special:Redirect}}/logid/186]]。",
        "redirect-submit": "執行",
        "redirect-lookup": "查詢:",
        "redirect-value": "值:",
        "logentry-partialblock-block": "$1{{GENDER:$2|已封鎖}}{{GENDER:$4|$3}}對於$7的編輯為期限至 $5 $6",
        "logentry-partialblock-reblock": "$1{{GENDER:$2|已變更}}在$7的{{GENDER:$4|$3}}禁止編輯封鎖設定為期限至 $5 $6",
        "logentry-non-editing-block-block": "$1{{GENDER:$2|已封鎖}}{{GENDER:$4|$3}}的指定編輯操作至期限$5 $6",
-       "logentry-non-editing-block-reblock": "$1{{GENDER:$2|已變更}}{{GENDER:$4|$3}}的指定禁止編輯操作之封鎖設定為期限至$5 $6",
+       "logentry-non-editing-block-reblock": "$1{{GENDER:$2|已變更}}{{GENDER:$4|$3}}的指定非編輯操作之封鎖設定,到期時間為$5 $6",
        "logentry-suppress-block": "$1 {{GENDER:$2|已封鎖}} {{GENDER:$4|$3}} 期限為 $5 $6",
        "logentry-suppress-reblock": "$1 {{GENDER:$2|已變更}} {{GENDER:$4|$3}} 的封鎖設定期限為 $5 $6",
        "logentry-import-upload": "$1 已由檔案上傳{{GENDER:$2|匯入}} $3",
        "log-action-filter-managetags-delete": "標籤刪除",
        "log-action-filter-managetags-activate": "標籤啟動",
        "log-action-filter-managetags-deactivate": "標籤取消啟動",
-       "log-action-filter-move-move": "移動不覆寫重新導向",
+       "log-action-filter-move-move": "移動不覆寫重新導向",
        "log-action-filter-move-move_redir": "移動覆寫重新導向",
        "log-action-filter-newusers-create": "由匿名使用者建立",
        "log-action-filter-newusers-create2": "由註冊使用者建立",
        "passwordpolicies-policyflag-forcechange": "必須在登入時更改",
        "passwordpolicies-policyflag-suggestchangeonlogin": "建議在登入時更改",
        "easydeflate-invaliddeflate": "提供的內容未被正常的壓縮",
-       "unprotected-js": "基於安全因素,JavaScript 不能從未保護的頁面來載入。建立 JavaScript 請僅在 MediaWiki 的:命名空間或使用者子頁面"
+       "unprotected-js": "基於安全因素,JavaScript 不能從未保護的頁面來載入。請僅在 MediaWiki:命名空間或使用者子頁面中建立 JavaScript。",
+       "userlogout-continue": "若您想要登出請[$1 繼續前至登出頁面]。",
+       "userlogout-sessionerror": "出於 session 錯誤造成登出失敗。請[$1 重試]。"
 }
index 4cdf3ae..fcf42ea 100644 (file)
        "wlshowhidebots": "機械人",
        "blanknamespace": "(主要)",
        "blockip": "封鎖{{GENDER:$1|用戶}}",
+       "empty-username": "沒有用戶名",
        "contribslink": "貢獻",
        "blocklogtext": "這是用戶的封禁與解禁操作的日誌記錄。\n自動封禁的 IP 位址不予包含。\n請參考 [[Special:BlockList|封禁清單]] 以檢視目前的封禁。",
        "tooltip-pt-login": "我們建議您登入,但這並非必要",
index 4edce3d..eeec665 100644 (file)
@@ -290,7 +290,7 @@ $magicWords = [
        'defaultsort'             => [ 1, 'পূর্বনির্ধারিত_বাছাই', 'পূর্বনির্ধারিতবাছাই', 'DEFAULTSORT:', 'DEFAULTSORTKEY:', 'DEFAULTCATEGORYSORT:' ],
        'filepath'                => [ 0, 'ফাইলের_পথ:', 'ফাইলেরপথ:', 'FILEPATH:' ],
        'tag'                     => [ 0, 'ট্যাগ', 'tag' ],
-       'hiddencat'               => [ 1, '__লà§\81à¦\95ায়িতবিষয়শà§\8dরà§\87ণà§\80__', '__লà§\81à¦\95à§\8dà¦\95ায়িতবিষয়শ্রেণী__', '__HIDDENCAT__' ],
+       'hiddencat'               => [ 1, '__লà§\81à¦\95ানà§\8b_বিষয়শà§\8dরà§\87ণà§\80__', '__লà§\81à¦\95ানà§\8bবিষয়শà§\8dরà§\87ণà§\80__', '__লà§\81à¦\95ায়িতবিষয়শà§\8dরà§\87ণà§\80__', '__লà§\81à¦\95à§\8dà¦\95ায়িতবিষয়শà§\8dরà§\87ণà§\80__', '__লà§\81à¦\95à§\8dà¦\95ায়িত_বিষয়শ্রেণী__', '__HIDDENCAT__' ],
        'pagesincategory'         => [ 1, 'বিষয়শ্রেণীতেপাতা', 'বিষয়শ্রেণীতেপৃষ্ঠা', 'বিষয়শ্রেণীতে_পাতা', 'বিষয়শ্রেণীতে_পৃষ্ঠা', 'PAGESINCATEGORY', 'PAGESINCAT' ],
        'pagesize'                => [ 1, 'পাতার_আকার', 'পাতারআকার', 'পৃষ্ঠার_আকার', 'পৃষ্ঠারআকার', 'PAGESIZE' ],
        'index'                   => [ 1, '__নির্ঘণ্ট__', '__INDEX__' ],
index 6646122..c14d052 100644 (file)
@@ -54,6 +54,7 @@ $specialPageAliases = [
        'Ancientpages'              => [ 'Nejstarší_stránky', 'Staré_stránky', 'Stare_stranky' ],
        'ApiHelp'                   => [ 'Nápověda_k_API' ],
        'ApiSandbox'                => [ 'API_pískoviště' ],
+       'AutoblockList'             => [ 'Seznam_automatických_blokování' ],
        'Badtitle'                  => [ 'Neplatný_název' ],
        'Blankpage'                 => [ 'Prázdná_stránka' ],
        'Block'                     => [ 'Blokování', 'Blokovani', 'Blokovat_uživatele', 'Blokovat_IP', 'Blokovat_uzivatele' ],
@@ -62,6 +63,7 @@ $specialPageAliases = [
        'BrokenRedirects'           => [ 'Přerušená_přesměrování', 'Prerusena_presmerovani' ],
        'Categories'                => [ 'Kategorie' ],
        'ChangeContentModel'        => [ 'Změnit_model_obsahu_stránky' ],
+       'ChangeCredentials'         => [ 'Změna_přihlašovacích_údajů' ],
        'ChangeEmail'               => [ 'Změna_emailu', 'Zmena_emailu' ],
        'ChangePassword'            => [ 'Změna_hesla', 'Zmena_hesla' ],
        'ComparePages'              => [ 'Porovnání_stránek', 'PorovnáníStránek', 'Porovnani_stranek', 'PorovnaniStranek' ],
@@ -101,6 +103,7 @@ $specialPageAliases = [
        'MIMEsearch'                => [ 'Hledání_podle_MIME', 'Hledani_podle_MIME', 'Hledat_podle_MIME_typu' ],
        'Mostcategories'            => [ 'Stránky_s_nejvíce_kategoriemi', 'Stranky_s_nejvice_kategoriemi', 'Stránky_s_nejvyšším_počtem_kategorií' ],
        'Mostimages'                => [ 'Nejpoužívanější_soubory', 'Nejpouzivanejsi_soubory' ],
+       'Mostinterwikis'            => [ 'Stránky_s_největším_počtem_mezijazykových_odkazů', 'Nejvíce_mezijazykových_odkazů' ],
        'Mostlinked'                => [ 'Nejodkazovanější_stránky', 'Nejodkazovanejsi_stranky' ],
        'Mostlinkedcategories'      => [ 'Nejpoužívanější_kategorie', 'Nejpouzivanejsi_kategorie' ],
        'Mostlinkedtemplates'       => [ 'Nejpoužívanější_šablony', 'Nejpouzivanejsi_sablony' ],
@@ -111,9 +114,10 @@ $specialPageAliases = [
        'Mypage'                    => [ 'Moje_stránka', 'Moje_stranka', 'Má_stránka' ],
        'Mytalk'                    => [ 'Moje_diskuse', 'Má_diskuse' ],
        'Myuploads'                 => [ 'Moje_soubory', 'Mé_soubory' ],
-       'Newimages'                 => [ 'Nové_obrázky', 'Galerie_nových_obrázků', 'Nove_obrazky' ],
+       'Newimages'                 => [ 'Nové_soubory', 'Nové_obrázky', 'Galerie_nových_obrázků', 'Nove_obrazky' ],
        'Newpages'                  => [ 'Nové_stránky', 'Nove_stranky', 'Nejnovější_stránky', 'Nejnovejsi_stranky' ],
        'PagesWithProp'             => [ 'Stránky_s_vlastností', 'Stránky_s_vlastnostmi' ],
+       'PasswordPolicies'          => [ 'Pravidla_pro_heslo' ],
        'PasswordReset'             => [ 'Reset_hesla', 'Resetovat_heslo', 'Obnova_hesla', 'Obnovit_heslo' ],
        'PermanentLink'             => [ 'Trvalý_odkaz' ],
        'Preferences'               => [ 'Nastavení', 'Nastaveni' ],
@@ -127,6 +131,8 @@ $specialPageAliases = [
        'Recentchanges'             => [ 'Poslední_změny', 'Posledni_zmeny' ],
        'Recentchangeslinked'       => [ 'Související_změny', 'Souvisejici_zmeny' ],
        'Redirect'                  => [ 'Přesměrování', 'Přesměrovat' ],
+       'RemoveCredentials'         => [ 'Odstranění_přihlašovacích_údajů' ],
+       'ResetTokens'               => [ 'Reinicializace_klíčů' ],
        'Revisiondelete'            => [ 'Smazat_revizi' ],
        'Search'                    => [ 'Hledání', 'Hledani' ],
        'Shortpages'                => [ 'Nejkratší_stránky', 'Nejkratsi_stranky' ],
index f325641..d0115ea 100644 (file)
@@ -400,6 +400,7 @@ $specialPageAliases = [
        'Badtitle'                  => [ 'Badtitle' ],
        'Blankpage'                 => [ 'BlankPage' ],
        'Block'                     => [ 'Block', 'BlockIP', 'BlockUser' ],
+       'BlockList'                 => [ 'BlockList', 'ListBlocks', 'IPBlockList' ],
        'Booksources'               => [ 'BookSources' ],
        'BotPasswords'              => [ 'BotPasswords' ],
        'BrokenRedirects'           => [ 'BrokenRedirects' ],
@@ -428,7 +429,6 @@ $specialPageAliases = [
        'Import'                    => [ 'Import' ],
        'Invalidateemail'           => [ 'InvalidateEmail' ],
        'JavaScriptTest'            => [ 'JavaScriptTest' ],
-       'BlockList'                 => [ 'BlockList', 'ListBlocks', 'IPBlockList' ],
        'LinkSearch'                => [ 'LinkSearch' ],
        'LinkAccounts'              => [ 'LinkAccounts' ],
        'Listadmins'                => [ 'ListAdmins' ],
@@ -438,7 +438,7 @@ $specialPageAliases = [
        'Listgrants'                => [ 'ListGrants' ],
        'Listredirects'             => [ 'ListRedirects' ],
        'ListDuplicatedFiles'       => [ 'ListDuplicatedFiles', 'ListFileDuplicates' ],
-       'Listusers'                 => [ 'ListUsers', 'UserList' ],
+       'Listusers'                 => [ 'ListUsers', 'UserList', 'Users' ],
        'Lockdb'                    => [ 'LockDB' ],
        'Log'                       => [ 'Log', 'Logs' ],
        'Lonelypages'               => [ 'LonelyPages', 'OrphanedPages' ],
index 5488b9a..2b103be 100644 (file)
@@ -1,5 +1,5 @@
 <?php
-/** Javanese (Basa Jawa)
+/** Javanese (Jawa)
  *
  * To improve a translation please visit https://translatewiki.net
  *
index 855e014..4de60f3 100644 (file)
 
 $rtl = true;
 
+$namespaceNames = [
+       NS_MEDIA            => 'ߟߊߛߋߢߊߥߙߍ',
+       NS_SPECIAL          => 'ߞߙߍߞߙߍߣߍ߲',
+       NS_TALK             => 'ߢߊߝߐߞߣߍ',
+       NS_USER             => 'ߟߊߓߊ߯ߙߟߊ',
+       NS_USER_TALK        => 'ߟߊߓߊ߯ߙߟߊ ߟߊ߫ ߢߊߝߐߞߣߍ',
+       NS_PROJECT_TALK     => '$1 ߢߊߝߐߞߣߍ',
+       NS_FILE             => 'ߞߐߕߐ߮',
+       NS_FILE_TALK        => 'ߞߐߕߐ߮ ߢߊߝߐߞߣߍ',
+       NS_MEDIAWIKI        => 'ߡߘߌߦߊߥߞߌ',
+       NS_MEDIAWIKI_TALK   => 'ߡߘߌߦߊߥߞߌ ߢߊߝߐߞߣߍ',
+       NS_TEMPLATE         => 'ߞߙߊߞߏ',
+       NS_TEMPLATE_TALK    => 'ߞߙߊߞߏ ߢߊߝߐߞߣߍ',
+       NS_HELP             => 'ߡߊ߬ߘߍ߬ߡߍ߲߬ߠߌ߲',
+       NS_HELP_TALK        => 'ߡߊ߬ߘߍ߬ߡߍ߲߬ߠߌ߲ ߢߊߝߐߞߣߍ',
+       NS_CATEGORY         => 'ߦߌߟߡߊ',
+       NS_CATEGORY_TALK    => 'ߦߌߟߡߊ ߢߊߝߐߞߣߍ',
+];
+
 $digitTransformTable = [
        '0' => '߀', # U+07C0
        '1' => '߁', # U+07C1
index 4859719..11547f4 100644 (file)
@@ -134,6 +134,14 @@ $magicWords = [
        'img_link'                  => [ '1', 'liŋka=$1', 'link=$1' ],
 ];
 
+$defaultDateFormat = 'mdy';
+
+$dateFormats = [
+       'mdy time' => 'G.i',
+       'mdy date' => 'xg j "b." Y',
+       'mdy both' => 'xg j "b." Y "dii." G.i',
+];
+
 $separatorTransformTable = [ ',' => "\u{00A0}", '.' => ',' ];
 
 $linkTrail = '/^(:?[a-zàáâçčʒǯđðéèêëǧǥȟíìîïıǩŋñóòôõßšŧúùûýÿüžþæøåäö]+)(.*)$/sDu';
index 847a13d..446d214 100644 (file)
@@ -22,6 +22,7 @@
  * @author Pitr2311
  * @author Ragimiri
  * @author Reedy
+ * @author Robertvazan
  * @author Rudko
  * @author Sp5uhe
  * @author Sudo77(new)
@@ -30,6 +31,7 @@
  * @author Urhixidur
  * @author Valasek
  * @author Wizzard
+ * @author Zoranzoki21
  * @author לערי ריינהארט
  */
 
@@ -40,19 +42,28 @@ $specialPageAliases = [
        'Allmessages'               => [ 'VšetkySprávy' ],
        'Allpages'                  => [ 'VšetkyStránky' ],
        'Ancientpages'              => [ 'StaréStránky' ],
+       'ApiSandbox'                => [ 'APIPieskovisko' ],
+       'AutoblockList'             => [ 'AutomatickéBlokovania' ],
        'Blankpage'                 => [ 'PrázdnaStránka' ],
        'Block'                     => [ 'Blokovanie' ],
        'Booksources'               => [ 'KnižnéZdroje' ],
+       'BotPasswords'              => [ 'HesláPreBotov' ],
        'BrokenRedirects'           => [ 'PokazenéPresmerovania' ],
        'Categories'                => [ 'Kategórie' ],
+       'ChangeCredentials'         => [ 'ZmenaPrihlasovacíchÚdajov' ],
+       'ChangeEmail'               => [ 'ZmenaEmailu' ],
        'ChangePassword'            => [ 'ZmenaHesla' ],
+       'ComparePages'              => [ 'PorovnaťStránky' ],
        'Confirmemail'              => [ 'PotvrdiťEmail' ],
        'Contributions'             => [ 'Príspevky' ],
        'CreateAccount'             => [ 'VytvorenieÚčtu' ],
        'Deadendpages'              => [ 'StránkyBezOdkazov' ],
        'DeletedContributions'      => [ 'ZmazanéPríspevky' ],
+       'Diff'                      => [ 'Rozdiel' ],
        'DoubleRedirects'           => [ 'DvojitéPresmerovania' ],
        'Emailuser'                 => [ 'EmailPoužívateľovi' ],
+       'ExpandTemplates'           => [ 'SubstituovaťŠablóny' ],
+       'Export'                    => [ 'ExportovaťStránky' ],
        'Fewestrevisions'           => [ 'NajmenejRevízií' ],
        'FileDuplicateSearch'       => [ 'HľadanieDuplicitnýchSúborov' ],
        'Filepath'                  => [ 'CestaKSúboru' ],
@@ -61,7 +72,9 @@ $specialPageAliases = [
        'LinkSearch'                => [ 'HľadanieOdkazov' ],
        'Listadmins'                => [ 'ZoznamSprávcov' ],
        'Listbots'                  => [ 'ZoznamBotov' ],
+       'ListDuplicatedFiles'       => [ 'ZoznamDuplicitnýchSúborov' ],
        'Listfiles'                 => [ 'ZoznamSúborov' ],
+       'Listgrants'                => [ 'SkupinyOprávnení' ],
        'Listgrouprights'           => [ 'ZoznamSkupinovýchPráv' ],
        'Listredirects'             => [ 'ZoznamPresmerovaní' ],
        'Listusers'                 => [ 'ZoznamPoužívateľov' ],
@@ -69,10 +82,12 @@ $specialPageAliases = [
        'Log'                       => [ 'Záznamy' ],
        'Lonelypages'               => [ 'OsirotenéStránky' ],
        'Longpages'                 => [ 'DlhéStránky' ],
+       'MediaStatistics'           => [ 'ŠtatistikaSúborov' ],
        'MergeHistory'              => [ 'HistóriaZlúčení' ],
        'MIMEsearch'                => [ 'HľadanieMIME' ],
        'Mostcategories'            => [ 'NajviacKategórií' ],
        'Mostimages'                => [ 'NajodkazovanejšieSúbory' ],
+       'MostInterwikis'            => [ 'NajviacInterwiki' ],
        'Mostlinked'                => [ 'NajodkazovanejšieStránky' ],
        'Mostlinkedcategories'      => [ 'NajodkazovanejšieKategórie' ],
        'Mostlinkedtemplates'       => [ 'NajodkazovanejšieŠablóny' ],
@@ -83,20 +98,30 @@ $specialPageAliases = [
        'Mytalk'                    => [ 'MojaDiskusia' ],
        'Newimages'                 => [ 'NovéSúbory' ],
        'Newpages'                  => [ 'NovéStránky' ],
+       'PagesWithProp'             => [ 'StránkySVlastnosťou' ],
+       'PasswordPolicies'          => [ 'PravidláPreHeslá' ],
+       'PasswordReset'             => [ 'ObnovaHesla' ],
+       'PermanentLink'             => [ 'TrvalýOdkaz' ],
        'Preferences'               => [ 'Nastavenia' ],
-       'Prefixindex'               => [ 'IndexPredpon' ],
+       'Prefixindex'               => [ 'StránkyZačínajúceNa', 'IndexPredpon' ],
        'Protectedpages'            => [ 'ZamknutéStránky' ],
        'Protectedtitles'           => [ 'ZamknutéNázvy' ],
+       'RandomInCategory'          => [ 'NáhodnáVKategórii' ],
        'Randompage'                => [ 'Náhodná', 'NáhodnáStránka' ],
        'Randomredirect'            => [ 'NáhodnéPresmerovanie' ],
+       'Randomrootpage'            => [ 'NáhodnáKoreňováStránka' ],
        'Recentchanges'             => [ 'PoslednéÚpravy' ],
        'Recentchangeslinked'       => [ 'SúvisiacePoslednéÚpravy' ],
+       'Redirect'                  => [ 'Presmerovanie' ],
+       'RemoveCredentials'         => [ 'OdstráneniePrihlasovacíchÚdajov' ],
+       'ResetTokens'               => [ 'ObnovaKľúčov' ],
        'Revisiondelete'            => [ 'ZmazaťRevíziu' ],
        'Search'                    => [ 'Hľadanie' ],
        'Shortpages'                => [ 'KrátkeStránky' ],
        'Specialpages'              => [ 'ŠpeciálneStránky' ],
        'Statistics'                => [ 'Štatistika' ],
        'Tags'                      => [ 'Značky' ],
+       'TrackingCategories'        => [ 'SledovacieKategórie' ],
        'Uncategorizedcategories'   => [ 'NekategorizovanéKategórie' ],
        'Uncategorizedimages'       => [ 'NekategorizovanéSúbory' ],
        'Uncategorizedpages'        => [ 'NekategorizovanéStránky' ],
index 5b32f91..2d73cd2 100644 (file)
@@ -96,29 +96,30 @@ $specialPageAliases = [
        'Activeusers'               => [ 'АктивниКорисници', 'Активни_корисници' ],
        'Allmessages'               => [ 'СвеПоруке', 'Све_поруке' ],
        'AllMyUploads'              => [ 'СваМојаОтпремања', 'СвеМојеДатотеке' ],
-       'Allpages'                  => [ 'Све_странице' ],
+       'Allpages'                  => [ 'СвеСтранице', 'Све_странице' ],
+       'ApiHelp'                   => [ 'API_помоћ' ],
        'ApiSandbox'                => [ 'API_песак', 'АПИ_песак' ],
        'Ancientpages'              => [ 'НајстаријеСтранице', 'НајстаријиЧланци' ],
        'AutoblockList'             => [ 'СписакАутоблокова', 'Аутоблокови' ],
-       'Badtitle'                  => [ 'Лош_наслов' ],
+       'Badtitle'                  => [ 'ЛошНаслов', 'Лош_наслов' ],
        'Blankpage'                 => [ 'ПразнаСтраница' ],
        'Block'                     => [ 'Блокирај', 'БлокирајИП', 'БлокирајКорисника' ],
        'Booksources'               => [ 'КњижевниИзвори', 'ШтампаниИзвори' ],
        'BotPasswords'              => [ 'ЛозинкеБотова' ],
-       'BrokenRedirects'           => [ 'Покварена_преусмерења', 'Неисправна_преусмерења' ],
+       'BrokenRedirects'           => [ 'ПокваренаПреусмерења', 'Покварена_преусмерења', 'Неисправна_преусмерења' ],
        'Categories'                => [ 'Категорије' ],
        'ChangeContentModel'        => [ 'ПромениМоделСадржаја', 'ИзмениМоделСадржаја' ],
        'ChangeCredentials'         => [ 'ПромениАкредитиве' ],
-       'ChangeEmail'               => [ 'ПромениИмејлАдресу' ],
+       'ChangeEmail'               => [ 'ПромениИмејл', 'ПромениИмејлАдресу' ],
        'ChangePassword'            => [ 'ПромениЛозинку' ],
-       'ComparePages'              => [ 'Упореди_странице' ],
-       'Confirmemail'              => [ 'ПотврдиЕ-пошту', 'Потврда_е-поште' ],
+       'ComparePages'              => [ 'УпоредиСтранице', 'Упореди_странице' ],
+       'Confirmemail'              => [ 'Ð\9fоÑ\82вÑ\80диÐ\98меÑ\98л', 'Ð\9fоÑ\82вÑ\80диÐ\95-поÑ\88Ñ\82Ñ\83', 'Ð\9fоÑ\82вÑ\80да_е-поÑ\88Ñ\82е' ],
        'Contributions'             => [ 'Доприноси', 'Прилози' ],
        'CreateAccount'             => [ 'ОтвориНалог', 'Отвори_налог' ],
        'Deadendpages'              => [ 'Ћорсокаци', 'СтраницеКојеНеВодеНикуда', 'СлепеСтранице' ],
        'DeletedContributions'      => [ 'ОбрисаниДоприноси' ],
        'Diff'                      => [ 'Разлике' ],
-       'DoubleRedirects'           => [ 'Двострука_преусмерења' ],
+       'DoubleRedirects'           => [ 'ДвострукаПреусмерења', 'Двострука_преусмерења' ],
        'EditTags'                  => [ 'УредиОзнаке' ],
        'EditWatchlist'             => [ 'УредиСписакНадгледања' ],
        'Emailuser'                 => [ 'ПошаљиИмејлКориснику' ],
@@ -126,12 +127,12 @@ $specialPageAliases = [
        'Export'                    => [ 'Извези' ],
        'Fewestrevisions'           => [ 'НајмањеИзмена', 'ЧланциСаНајмањеРевизија' ],
        'FileDuplicateSearch'       => [ 'ПретрагаДупликатаДатотека' ],
-       'Filepath'                  => [ 'Путања_датотеке' ],
+       'Filepath'                  => [ 'ПутањаДатотеке', 'Путања_датотеке' ],
        'GoToInterwiki'             => [ 'ПосетиМеђувики' ],
        'Import'                    => [ 'Увези' ],
        'Invalidateemail'           => [ 'ПоништиИмејл' ],
        'JavaScriptTest'            => [ 'ТестирањеЈаваскрипта' ],
-       'BlockList'                 => [ 'СписакБлокираних', 'ПописБлокираних' ],
+       'BlockList'                 => [ 'СпиÑ\81акÐ\91локада', 'СпиÑ\81акÐ\91локиÑ\80аниÑ\85', 'Ð\9fопиÑ\81Ð\91локиÑ\80аниÑ\85' ],
        'LinkSearch'                => [ 'ПретрагаВеза' ],
        'LinkAccounts'              => [ 'ПовежиНалоге' ],
        'Listadmins'                => [ 'СписакАдминистратора', 'ПописАдминистратора', 'Списак_администратора' ],
@@ -142,28 +143,28 @@ $specialPageAliases = [
        'Listredirects'             => [ 'СписакПреусмерења', 'Списак_преусмерења' ],
        'ListDuplicatedFiles'       => [ 'СписакДупликата' ],
        'Listusers'                 => [ 'СписакКорисника', 'КорисничкиСписак', 'Списак_корисника', 'Кориснички_списак' ],
-       'Lockdb'                    => [ 'ЗакључајБазу', 'Закључај_базу' ],
-       'Log'                       => [ 'Извештај', 'Извештаји' ],
+       'Lockdb'                    => [ 'ЗакључајБазуПодатака', 'ЗакључајБазу', 'Закључај_базу' ],
+       'Log'                       => [ 'Ð\94невник', 'Ð\98звеÑ\88Ñ\82аÑ\98', 'Ð\98звеÑ\88Ñ\82аÑ\98и' ],
        'Lonelypages'               => [ 'Сирочићи' ],
-       'Longpages'                 => [ 'ДугачкеСтране' ],
+       'Longpages'                 => [ 'Ð\94Ñ\83гаÑ\87кеСÑ\82Ñ\80аниÑ\86е', 'Ð\94Ñ\83гаÑ\87кеСÑ\82Ñ\80ане' ],
        'MediaStatistics'           => [ 'СтатистикеМедија' ],
        'MergeHistory'              => [ 'СпојиИсторију', 'Споји_историју' ],
        'MIMEsearch'                => [ 'MIME_претрага' ],
        'Mostcategories'            => [ 'НајвишеКатегорија', 'ЧланциСаНајвишеКатегорија' ],
        'Mostimages'                => [ 'НајповезанијеДатотеке', 'НајповезанијеСлике' ],
        'Mostinterwikis'            => [ 'НајвишеМеђувикија' ],
-       'Mostlinked'                => [ 'НајповезанијеСтране' ],
+       'Mostlinked'                => [ 'Ð\9dаÑ\98повезаниÑ\98еСÑ\82Ñ\80аниÑ\86е', 'Ð\9dаÑ\98повезаниÑ\98еСÑ\82Ñ\80ане' ],
        'Mostlinkedcategories'      => [ 'НајповезанијеКатегорије' ],
        'Mostlinkedtemplates'       => [ 'НајповезанијиШаблони' ],
-       'Mostrevisions'             => [ 'НајвишеРевизија', 'ЧланциСаНајвишеРевизија' ],
-       'Movepage'                  => [ 'Премести', 'Преусмери', 'Премести_страницу' ],
+       'Mostrevisions'             => [ 'Ð\9dаÑ\98виÑ\88еÐ\98змена', 'Ð\9dаÑ\98виÑ\88еРевизиÑ\98а', 'ЧланÑ\86иСаÐ\9dаÑ\98виÑ\88еРевизиÑ\98а' ],
+       'Movepage'                  => [ 'ПреместиСтраницу', 'Премести', 'Преусмери', 'Премести_страницу' ],
        'Mycontributions'           => [ 'МојиДоприноси', 'Моји_доприноси', 'Моји_прилози' ],
-       'MyLanguage'                => [ 'Мој_језик' ],
+       'MyLanguage'                => [ 'МојЈезик', 'Мој_језик' ],
        'Mypage'                    => [ 'МојаСтраница', 'Моја_страница' ],
        'Mytalk'                    => [ 'МојРазговор', 'Мој_разговор' ],
-       'Myuploads'                 => [ 'Моја_слања' ],
+       'Myuploads'                 => [ 'МојаОтпремања', 'Моја_слања' ],
        'Newimages'                 => [ 'НовеДатотеке', 'НовиФајлови', 'НовеСлике' ],
-       'Newpages'                  => [ 'НовеСтране' ],
+       'Newpages'                  => [ 'Ð\9dовеСÑ\82Ñ\80аниÑ\86е', 'Ð\9dовеСÑ\82Ñ\80ане' ],
        'PagesWithProp'             => [ 'СтраницеСаСвојством' ],
        'PageData'                  => [ 'ПодациСтранице' ],
        'PageLanguage'              => [ 'ЈезикСтранице' ],
@@ -174,20 +175,20 @@ $specialPageAliases = [
        'Prefixindex'               => [ 'СтраницеСаПрефиксом' ],
        'Protectedpages'            => [ 'ЗаштићенеСтранице', 'Заштићене_странице' ],
        'Protectedtitles'           => [ 'ЗаштићениНаслови', 'Заштићени_наслови' ],
-       'Randompage'                => [ 'СлучајнаСтрана', 'Насумична_страница' ],
-       'RandomInCategory'          => [ 'Случајна_страна_у_категорији' ],
+       'Randompage'                => [ 'СлÑ\83Ñ\87аÑ\98наСÑ\82Ñ\80аниÑ\86а', 'СлÑ\83Ñ\87аÑ\98наСÑ\82Ñ\80ана', 'Ð\9dаÑ\81Ñ\83миÑ\87на_Ñ\81Ñ\82Ñ\80аниÑ\86а' ],
+       'RandomInCategory'          => [ 'СлÑ\83Ñ\87аÑ\98на_Ñ\81Ñ\82Ñ\80аниÑ\86а_Ñ\83_каÑ\82егоÑ\80иÑ\98и', 'СлÑ\83Ñ\87аÑ\98на_Ñ\81Ñ\82Ñ\80ана_Ñ\83_каÑ\82егоÑ\80иÑ\98и' ],
        'Randomredirect'            => [ 'СлучајноПреусмерење' ],
-       'Randomrootpage'            => [ 'СлучајнаОсновнаСтрана' ],
+       'Randomrootpage'            => [ 'СлÑ\83Ñ\87аÑ\98наÐ\9eÑ\81новнаСÑ\82Ñ\80аниÑ\86а', 'СлÑ\83Ñ\87аÑ\98наÐ\9eÑ\81новнаСÑ\82Ñ\80ана' ],
        'Recentchanges'             => [ 'СкорашњеИзмене', 'Скорашње_измене' ],
        'Recentchangeslinked'       => [ 'СроднеИзмене' ],
        'Redirect'                  => [ 'Преусмерење' ],
        'RemoveCredentials'         => [ 'УклониАкредитиве' ],
        'ResetTokens'               => [ 'РесетујЖетоне' ],
-       'Revisiondelete'            => [ 'УклањањеИзмене' ],
+       'Revisiondelete'            => [ 'Ð\91Ñ\80иÑ\81аÑ\9aеÐ\98змене', 'УклаÑ\9aаÑ\9aеÐ\98змене' ],
        'RunJobs'                   => [ 'ИзвршиПослове' ],
        'Search'                    => [ 'Претражи' ],
        'Shortpages'                => [ 'КраткеСтранице', 'КраткиЧланци' ],
-       'Specialpages'              => [ 'ПосебнеСтране', 'СпецијалнеСтране', 'Посебне_странице', 'Специјалне_странице' ],
+       'Specialpages'              => [ 'Ð\9fоÑ\81ебнеСÑ\82Ñ\80аниÑ\86е', 'Ð\9fоÑ\81ебнеСÑ\82Ñ\80ане', 'СпеÑ\86иÑ\98алнеСÑ\82Ñ\80ане', 'Ð\9fоÑ\81ебне_Ñ\81Ñ\82Ñ\80аниÑ\86е', 'СпеÑ\86иÑ\98алне_Ñ\81Ñ\82Ñ\80аниÑ\86е' ],
        'Statistics'                => [ 'Статистике' ],
        'Tags'                      => [ 'Ознаке' ],
        'TrackingCategories'        => [ 'КатегоријеЗаПраћење' ],
@@ -197,25 +198,25 @@ $specialPageAliases = [
        'Uncategorizedpages'        => [ 'НекатегорисанеСтранице', 'ЧланциБезКатегорија', 'Чланци_без_категорија' ],
        'Uncategorizedtemplates'    => [ 'НекатегорисаниШаблони', 'ШаблониБезКатегорија' ],
        'Undelete'                  => [ 'Врати' ],
-       'UnlinkAccounts'            => [ 'УклониПовезивањеНалога' ],
-       'Unlockdb'                  => [ 'ОткључајБазу', 'Откључај_базу' ],
+       'UnlinkAccounts'            => [ 'Ð\9eдвежиÐ\9dалоге', 'УклониÐ\9fовезиваÑ\9aеÐ\9dалога' ],
+       'Unlockdb'                  => [ 'ОткључајБазуПодатака', 'ОткључајБазу', 'Откључај_базу' ],
        'Unusedcategories'          => [ 'НеискоришћенеКатегорије' ],
        'Unusedimages'              => [ 'НеискоришћенеДатотеке', 'НеискоришћенеСлике' ],
        'Unusedtemplates'           => [ 'НеискоришћениШаблони' ],
        'Unwatchedpages'            => [ 'НенадгледанеСтранице' ],
-       'Upload'                    => [ 'Пошаљи' ],
+       'Upload'                    => [ 'Ð\9eÑ\82пÑ\80еми', 'Ð\9fоÑ\88аÑ\99и' ],
        'UploadStash'               => [ 'Складиште' ],
-       'Userlogin'                 => [ 'Корисничка_пријава' ],
-       'Userlogout'                => [ 'Корисничка_одјава' ],
+       'Userlogin'                 => [ 'КорисничкаПријава', 'Корисничка_пријава' ],
+       'Userlogout'                => [ 'КорисничкаОдјава', 'Корисничка_одјава' ],
        'Userrights'                => [ 'КорисничкаПрава' ],
        'Version'                   => [ 'Верзија', 'Издање' ],
        'Wantedcategories'          => [ 'ТраженеКатегорије' ],
        'Wantedfiles'               => [ 'ТраженеДатотеке', 'ТраженеСлике' ],
-       'Wantedpages'               => [ 'ТраженеСтране' ],
+       'Wantedpages'               => [ 'ТÑ\80аженеСÑ\82Ñ\80аниÑ\86е', 'ТÑ\80аженеСÑ\82Ñ\80ане' ],
        'Wantedtemplates'           => [ 'ТражениШаблони' ],
        'Watchlist'                 => [ 'СписакНадгледања', 'Списак_надгледања' ],
        'Whatlinkshere'             => [ 'ШтаВодиОвде', 'Шта_је_повезано_овде' ],
-       'Withoutinterwiki'          => [ 'Без_међувикија' ],
+       'Withoutinterwiki'          => [ 'БезМеђувикија', 'Без_међувикија' ],
 ];
 
 $datePreferences = [
diff --git a/maintenance/7zip.inc b/maintenance/7zip.inc
deleted file mode 100644 (file)
index 9c1093b..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-<?php
-/**
- * 7z stream wrapper
- *
- * Copyright © 2005 Brion Vibber <brion@pobox.com>
- * https://www.mediawiki.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Maintenance
- */
-
-/**
- * Stream wrapper around 7za filter program.
- * Required since we can't pass an open file resource to XMLReader->open()
- * which is used for the text prefetch.
- *
- * @ingroup Maintenance
- */
-class SevenZipStream {
-       protected $stream;
-
-       private function stripPath( $path ) {
-               $prefix = 'mediawiki.compress.7z://';
-
-               return substr( $path, strlen( $prefix ) );
-       }
-
-       function stream_open( $path, $mode, $options, &$opened_path ) {
-               if ( $mode[0] == 'r' ) {
-                       $options = 'e -bd -so';
-               } elseif ( $mode[0] == 'w' ) {
-                       $options = 'a -bd -si';
-               } else {
-                       return false;
-               }
-               $arg = wfEscapeShellArg( $this->stripPath( $path ) );
-               $command = "7za $options $arg";
-               if ( !wfIsWindows() ) {
-                       // Suppress the stupid messages on stderr
-                       $command .= ' 2>/dev/null';
-               }
-               $this->stream = popen( $command, $mode[0] ); // popen() doesn't like two-letter modes
-               return ( $this->stream !== false );
-       }
-
-       function url_stat( $path, $flags ) {
-               return stat( $this->stripPath( $path ) );
-       }
-
-       // This is all so lame; there should be a default class we can extend
-
-       function stream_close() {
-               return fclose( $this->stream );
-       }
-
-       function stream_flush() {
-               return fflush( $this->stream );
-       }
-
-       function stream_read( $count ) {
-               return fread( $this->stream, $count );
-       }
-
-       function stream_write( $data ) {
-               return fwrite( $this->stream, $data );
-       }
-
-       function stream_tell() {
-               return ftell( $this->stream );
-       }
-
-       function stream_eof() {
-               return feof( $this->stream );
-       }
-
-       function stream_seek( $offset, $whence ) {
-               return fseek( $this->stream, $offset, $whence );
-       }
-}
-
-stream_wrapper_register( 'mediawiki.compress.7z', SevenZipStream::class );
index ad748f3..c88a1a0 100644 (file)
@@ -42,6 +42,13 @@ define( 'DO_MAINTENANCE', RUN_MAINTENANCE_IF_MAIN ); // original name, harmless
 
 $maintClass = false;
 
+// Some extensions rely on MW_INSTALL_PATH to find core files to include. Setting it here helps them
+// if they're included by a core script (like DatabaseUpdater) after Maintenance.php has already
+// been run.
+if ( strval( getenv( 'MW_INSTALL_PATH' ) ) === '' ) {
+       putenv( 'MW_INSTALL_PATH=' . realpath( __DIR__ . '/..' ) );
+}
+
 use Wikimedia\Rdbms\IDatabase;
 use MediaWiki\Logger\LoggerFactory;
 use MediaWiki\MediaWikiServices;
@@ -54,6 +61,18 @@ use Wikimedia\Rdbms\IMaintainableDatabase;
  * is the execute() method. See docs/maintenance.txt for more info
  * and a quick demo of how to use it.
  *
+ * Terminology:
+ *   params: registry of named values that may be passed to the script
+ *   arg list: registry of positional values that may be passed to the script
+ *   options: passed param values
+ *   args: passed positional values
+ *
+ * In the command:
+ *   mwscript somescript.php --foo=bar baz
+ * foo is a param
+ * bar is the option value of the option for param foo
+ * baz is the arg value at index 0 in the arg list
+ *
  * @since 1.16
  * @ingroup Maintenance
  */
@@ -69,13 +88,13 @@ abstract class Maintenance {
        // Const for getStdin()
        const STDIN_ALL = 'all';
 
-       // This is the desired params
+       // Array of desired/allowed params
        protected $mParams = [];
 
        // Array of mapping short parameters to long ones
        protected $mShortParamsMap = [];
 
-       // Array of desired args
+       // Array of desired/allowed args
        protected $mArgList = [];
 
        // This is the list of options that were actually passed
@@ -159,11 +178,8 @@ abstract class Maintenance {
         * their own constructors
         */
        public function __construct() {
-               // Setup $IP, using MW_INSTALL_PATH if it exists
                global $IP;
-               $IP = strval( getenv( 'MW_INSTALL_PATH' ) ) !== ''
-                       ? getenv( 'MW_INSTALL_PATH' )
-                       : realpath( __DIR__ . '/..' );
+               $IP = getenv( 'MW_INSTALL_PATH' );
 
                $this->addDefaultParams();
                register_shutdown_function( [ $this, 'outputChanneled' ], false );
@@ -324,6 +340,10 @@ abstract class Maintenance {
         * @return bool
         */
        protected function hasArg( $argId = 0 ) {
+               if ( func_num_args() === 0 ) {
+                       wfDeprecated( __METHOD__ . ' without an $argId', '1.33' );
+               }
+
                return isset( $this->mArgs[$argId] );
        }
 
@@ -334,6 +354,10 @@ abstract class Maintenance {
         * @return mixed
         */
        protected function getArg( $argId = 0, $default = null ) {
+               if ( func_num_args() === 0 ) {
+                       wfDeprecated( __METHOD__ . ' without an $argId', '1.33' );
+               }
+
                return $this->hasArg( $argId ) ? $this->mArgs[$argId] : $default;
        }
 
@@ -697,7 +721,7 @@ abstract class Maintenance {
                }
 
                /**
-                * @var $child Maintenance
+                * @var Maintenance $child
                 */
                $child = new $maintClass();
                $child->loadParamsAndArgs( $this->mSelf, $this->mOptions, $this->mArgs );
@@ -738,7 +762,6 @@ abstract class Maintenance {
                }
 
                $this->loadParamsAndArgs();
-               $this->maybeHelp();
 
                # Set the memory limit
                # Note we need to set it again later in cache LocalSettings changed it
@@ -758,8 +781,6 @@ abstract class Maintenance {
                while ( ob_get_level() > 0 ) {
                        ob_end_flush();
                }
-
-               $this->validateParamsAndArgs();
        }
 
        /**
@@ -862,14 +883,7 @@ abstract class Maintenance {
                                        $this->setParam( $options, $option, $param );
                                } else {
                                        $bits = explode( '=', $option, 2 );
-                                       if ( count( $bits ) > 1 ) {
-                                               $option = $bits[0];
-                                               $param = $bits[1];
-                                       } else {
-                                               $param = 1;
-                                       }
-
-                                       $this->setParam( $options, $option, $param );
+                                       $this->setParam( $options, $bits[0], $bits[1] ?? 1 );
                                }
                        } elseif ( $arg == '-' ) {
                                # Lonely "-", often used to indicate stdin or stdout.
@@ -979,7 +993,7 @@ abstract class Maintenance {
        /**
         * Run some validation checks on the params, etc
         */
-       protected function validateParamsAndArgs() {
+       public function validateParamsAndArgs() {
                $die = false;
                # Check to make sure we've got all the required options
                foreach ( $this->mParams as $opt => $info ) {
@@ -1005,9 +1019,7 @@ abstract class Maintenance {
                        }
                }
 
-               if ( $die ) {
-                       $this->maybeHelp( true );
-               }
+               $this->maybeHelp( $die );
        }
 
        /**
@@ -1183,7 +1195,7 @@ abstract class Maintenance {
 
                        if ( $wgDBservers ) {
                                /**
-                                * @var $wgDBservers array
+                                * @var array $wgDBservers
                                 */
                                foreach ( $wgDBservers as $i => $server ) {
                                        $wgDBservers[$i]['user'] = $wgDBuser;
@@ -1252,11 +1264,8 @@ abstract class Maintenance {
                }
                if ( isset( $this->mOptions['wiki'] ) ) {
                        $bits = explode( '-', $this->mOptions['wiki'], 2 );
-                       if ( count( $bits ) == 1 ) {
-                               $bits[] = '';
-                       }
                        define( 'MW_DB', $bits[0] );
-                       define( 'MW_PREFIX', $bits[1] );
+                       define( 'MW_PREFIX', $bits[1] ?? '' );
                } elseif ( isset( $this->mOptions['server'] ) ) {
                        // Provide the option for site admins to detect and configure
                        // multiple wikis based on server names. This offers --server
@@ -1445,7 +1454,7 @@ abstract class Maintenance {
                        'user',
                        'page_restrictions'
                ];
-               $db->lockTables( $read, $write, __CLASS__ . '::' . __METHOD__ );
+               $db->lockTables( $read, $write, __CLASS__ . '-searchIndexLock' );
        }
 
        /**
@@ -1453,7 +1462,7 @@ abstract class Maintenance {
         * @param IMaintainableDatabase &$db
         */
        private function unlockSearchindex( $db ) {
-               $db->unlockTables( __CLASS__ . '::' . __METHOD__ );
+               $db->unlockTables( __CLASS__ . '-searchIndexLock' );
        }
 
        /**
@@ -1610,10 +1619,10 @@ abstract class Maintenance {
                $bash = ExecutableFinder::findInDefaultPaths( 'bash' );
                if ( !wfIsWindows() && $bash ) {
                        $retval = false;
-                       $encPrompt = wfEscapeShellArg( $prompt );
+                       $encPrompt = Shell::escape( $prompt );
                        $command = "read -er -p $encPrompt && echo \"\$REPLY\"";
-                       $encCommand = wfEscapeShellArg( $command );
-                       $line = wfShellExec( "$bash -c $encCommand", $retval, [], [ 'walltime' => 0 ] );
+                       $encCommand = Shell::escape( $command );
+                       $line = Shell::escape( "$bash -c $encCommand", $retval, [], [ 'walltime' => 0 ] );
 
                        if ( $retval == 0 ) {
                                return $line;
diff --git a/maintenance/archives/patch-job-params-mediumblob.sql b/maintenance/archives/patch-job-params-mediumblob.sql
new file mode 100644 (file)
index 0000000..19fe0b6
--- /dev/null
@@ -0,0 +1,2 @@
+ALTER TABLE /*$wgDBprefix*/job
+MODIFY COLUMN job_params mediumblob NOT NULL;
index d53d2ea..be633ed 100644 (file)
@@ -28,7 +28,7 @@ CREATE TABLE /*$wgDBprefix*/brokenlinks (
   -- Key to the page_id of the page containing the link.
   bl_from int unsigned NOT NULL default '0',
 
-  -- Text of the target page title ("namesapce:title").
+  -- Text of the target page title ("namespace:title").
   -- Unfortunately this doesn't split the namespace index
   -- key and therefore can't easily be joined to anything.
   bl_to varchar(255) binary NOT NULL default '',
index 5e1feb7..b7d584a 100644 (file)
@@ -24,6 +24,8 @@
  * @author  Platonides
  */
 
+use MediaWiki\MediaWikiServices;
+
 require_once __DIR__ . '/Benchmarker.php';
 
 /**
@@ -45,7 +47,8 @@ class BenchHttpHttps extends Benchmarker {
        }
 
        private function doRequest( $proto ) {
-               Http::get( "$proto://localhost/", [], __METHOD__ );
+               MediaWikiServices::getInstance()->getHttpRequestFactory()->
+                       get( "$proto://localhost/", [], __METHOD__ );
        }
 
        // bench function 1
index c42fcd9..a3a4974 100644 (file)
@@ -75,7 +75,7 @@ class BenchmarkParse extends Maintenance {
                // Set as a member variable to avoid function calls when we're timing the parse
                $this->linkCache = MediaWikiServices::getInstance()->getLinkCache();
 
-               $title = Title::newFromText( $this->getArg() );
+               $title = Title::newFromText( $this->getArg( 0 ) );
                if ( !$title ) {
                        $this->error( "Invalid title" );
                        exit( 1 );
index 1b49f0e..20be9fd 100644 (file)
@@ -55,7 +55,10 @@ class CleanupCaps extends TableCleanup {
 
                $this->namespace = intval( $this->getOption( 'namespace', 0 ) );
 
-               if ( MWNamespace::isCapitalized( $this->namespace ) ) {
+               if (
+                       MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               isCapitalized( $this->namespace )
+               ) {
                        $this->output( "Will be moving pages to first letter capitalized titles" );
                        $callback = 'processRowToUppercase';
                } else {
index abae4f4..eb45cfc 100644 (file)
@@ -121,8 +121,7 @@ TEXT
         * @param array $tableParams A child array of self::$tables
         */
        protected function cleanupTable( $tableParams ) {
-               $table = $tableParams[0];
-               $prefix = $tableParams[1];
+               list( $table, $prefix ) = $tableParams;
                $idField = $tableParams['idField'] ?? "{$prefix}_id";
                $nsField = $tableParams['nsField'] ?? "{$prefix}_namespace";
                $titleField = $tableParams['titleField'] ?? "{$prefix}_title";
index 17d2e18..e1ea247 100644 (file)
@@ -52,7 +52,7 @@ class CleanupSpam extends Maintenance {
                // Hack: Grant bot rights so we don't flood RecentChanges
                $wgUser->addGroup( 'bot' );
 
-               $spec = $this->getArg();
+               $spec = $this->getArg( 0 );
 
                $protConds = [];
                foreach ( [ 'http://', 'https://' ] as $prot ) {
@@ -68,7 +68,7 @@ class CleanupSpam extends Maintenance {
                        $this->output( "Finding spam on " . count( $wgLocalDatabases ) . " wikis\n" );
                        $found = false;
                        foreach ( $wgLocalDatabases as $wikiID ) {
-                               /** @var $dbr Database */
+                               /** @var Database $dbr */
                                $dbr = $this->getDB( DB_REPLICA, [], $wikiID );
 
                                foreach ( $protConds as $conds ) {
@@ -97,7 +97,7 @@ class CleanupSpam extends Maintenance {
                        // Clean up spam on this wiki
 
                        $count = 0;
-                       /** @var $dbr Database */
+                       /** @var Database $dbr */
                        $dbr = $this->getDB( DB_REPLICA );
                        foreach ( $protConds as $prot => $conds ) {
                                $res = $dbr->select(
index 7f0e340..cad6122 100644 (file)
@@ -152,7 +152,7 @@ class TitleCleanup extends TableCleanup {
 
                        # Namespace which no longer exists. Put the page in the main namespace
                        # since we don't have any idea of the old namespace name. See T70501.
-                       if ( !MWNamespace::exists( $ns ) ) {
+                       if ( !MediaWikiServices::getInstance()->getNamespaceInfo()->exists( $ns ) ) {
                                $ns = 0;
                        }
 
index 61d1e5d..f7fd9d5 100644 (file)
@@ -166,13 +166,13 @@ class CleanupUsersWithNoId extends LoggedUpdateMaintenance {
 
                                $id = 0;
                                if ( $this->assign ) {
-                                       $id = (int)User::idFromName( $name );
+                                       $id = User::idFromName( $name );
                                        if ( !$id ) {
                                                // See if any extension wants to create it.
                                                if ( !isset( $this->triedCreations[$name] ) ) {
                                                        $this->triedCreations[$name] = true;
                                                        if ( !Hooks::run( 'ImportHandleUnknownUser', [ $name ] ) ) {
-                                                               $id = (int)User::idFromName( $name, User::READ_LATEST );
+                                                               $id = User::idFromName( $name, User::READ_LATEST );
                                                        }
                                                }
                                        }
index af60eaa..59820a5 100644 (file)
@@ -126,7 +126,6 @@ class ConvertLinks extends Maintenance {
                $res = $dbw->query( "SELECT COUNT(*) AS count FROM $links" );
                $row = $dbw->fetchObject( $res );
                $numRows = $row->count;
-               $dbw->freeResult( $res );
 
                if ( $numRows == 0 ) {
                        $this->output( "Updating schema (no rows to convert)...\n" );
@@ -168,7 +167,6 @@ class ConvertLinks extends Maintenance {
                                        }
                                }
                        }
-                       $dbw->freeResult( $res );
                        $dbw->bufferResults( true );
                        $this->output( "Finished loading IDs.\n\n" );
                        $this->performanceLog(
@@ -214,7 +212,6 @@ class ConvertLinks extends Maintenance {
                                                $numBadLinks++;
                                        }
                                }
-                               $dbw->freeResult( $res );
                                # $this->output( "rowOffset: $rowOffset\ttuplesAdded: "
                                #       . "$tuplesAdded\tnumBadLinks: $numBadLinks\n" );
                                if ( $tuplesAdded != 0 ) {
index fe3bea0..4f9e488 100644 (file)
@@ -69,8 +69,8 @@ class DeleteBatch extends Maintenance {
                }
                $wgUser = $user;
 
-               if ( $this->hasArg() ) {
-                       $file = fopen( $this->getArg(), 'r' );
+               if ( $this->hasArg( 0 ) ) {
+                       $file = fopen( $this->getArg( 0 ), 'r' );
                } else {
                        $file = $this->getStdin();
                }
index 9917a4f..d767df0 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 /**
  * Router for the php cli-server built-in webserver.
- * https://secure.php.net/manual/en/features.commandline.webserver.php
+ * https://www.php.net/manual/en/features.commandline.webserver.php
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -25,73 +25,59 @@ if ( PHP_SAPI != 'cli-server' ) {
        die( "This script can only be run by php's cli-server sapi." );
 }
 
-ini_set( 'display_errors', 1 );
-error_reporting( E_ALL );
-
-if ( isset( $_SERVER["SCRIPT_FILENAME"] ) ) {
-       # Known resource, sometimes a script sometimes a file
-       $file = $_SERVER["SCRIPT_FILENAME"];
-} elseif ( isset( $_SERVER["SCRIPT_NAME"] ) ) {
-       # Usually unknown, document root relative rather than absolute
-       # Happens with some cases like /wiki/File:Image.png
-       if ( is_readable( $_SERVER['DOCUMENT_ROOT'] . $_SERVER["SCRIPT_NAME"] ) ) {
-               # Just in case this actually IS a file, set it here
-               $file = $_SERVER['DOCUMENT_ROOT'] . $_SERVER["SCRIPT_NAME"];
-       } else {
-               # Otherwise let's pretend that this is supposed to go to index.php
-               $file = $_SERVER['DOCUMENT_ROOT'] . '/index.php';
-       }
-} else {
-       # Meh, we'll just give up
+if ( !isset( $_SERVER['SCRIPT_FILENAME'] ) ) {
+       // Let built-in server handle error.
        return false;
 }
 
-# And now do handling for that $file
-
+// The SCRIPT_FILENAME can be one of three things:
+// 1. Absolute path to a file in the docroot associated with the
+//    path of the current request URL. PHP does this for any file path
+//    where it finds a matching file on disk. For both PHP files, and for
+//    static files.
+// 2. Relative path to router.php (this file), for any unknown URL path
+//    that ends in ".php" or another extension that PHP would execute.
+// 3. Absolute path to {docroot}/index.php, for any other unknown path.
+//    Effectively treating it as a 404 handler.
+$file = $_SERVER['SCRIPT_FILENAME'];
 if ( !is_readable( $file ) ) {
-       # Let the server throw the error if it doesn't exist
+       // Let built-in server handle error.
        return false;
 }
+
 $ext = pathinfo( $file, PATHINFO_EXTENSION );
-if ( $ext == 'php' || $ext == 'php5' ) {
+if ( $ext == 'php' ) {
+       // Let built-in server handle script inclusion.
        return false;
-}
-$mime = false;
-// Borrow mime type file from MimeAnalyzer
-$lines = explode( "\n", file_get_contents( "includes/libs/mime/mime.types" ) );
-foreach ( $lines as $line ) {
-       $exts = explode( " ", $line );
-       $mime = array_shift( $exts );
-       if ( in_array( $ext, $exts ) ) {
-               break; # this is the right value for $mime
-       }
-       $mime = false;
-}
-if ( !$mime ) {
-       $basename = basename( $file );
-       if ( $basename == strtoupper( $basename ) ) {
-               # IF it's something like README serve it as text
-               $mime = "text/plain";
+} else {
+       // Serve static file with appropiate Content-Type headers.
+       // The built-in server for PHP 7.0+ supports most files already
+       // (contrary to PHP 5.2, which was supported when router.php was created).
+       // But it still doesn't support as many MIME types as MediaWiki (e.g. ".json")
+
+       // Fallback
+       $mime = 'text/plain';
+       // Borrow from MimeAnalyzer
+       $lines = explode( "\n", file_get_contents( "includes/libs/mime/mime.types" ) );
+       foreach ( $lines as $line ) {
+               $exts = explode( ' ', $line );
+               $type = array_shift( $exts );
+               if ( in_array( $ext, $exts ) ) {
+                       $mime = $type;
+                       break;
+               }
        }
-}
-if ( $mime ) {
-       # Use custom handling to serve files with a known MIME type
-       # This way we can serve things like .svg files that the built-in
-       # PHP webserver doesn't understand.
-       # ;) Nicely enough we just happen to bundle a mime.types file
-       $f = fopen( $file, 'rb' );
+
        if ( preg_match( '#^text/#', $mime ) ) {
-               # Text should have a charset=UTF-8 (php's webserver does this too)
+               // Text should have a charset=UTF-8 (PHP's webserver does this too)
                header( "Content-Type: $mime; charset=UTF-8" );
        } else {
                header( "Content-Type: $mime" );
        }
        header( "Content-Length: " . filesize( $file ) );
        // Stream that out to the browser
+       $f = fopen( $file, 'rb' );
        fpassthru( $f );
 
        return true;
 }
-
-# Let the php server handle things on its own otherwise
-return false;
index 1e3d410..cc5e6e5 100755 (executable)
@@ -14,7 +14,7 @@ fi
 
 VER=5.6.32
 TAR="php-$VER.tar.gz"
-PHPURL="https://secure.php.net/get/$TAR/from/this/mirror"
+PHPURL="https://www.php.net/get/$TAR/from/this/mirror"
 
 cd "$DEV"
 
index fc17a3d..45457f5 100644 (file)
@@ -2425,7 +2425,6 @@ mkdir
 mms
 mobile
 mobileformat
-mobilelanding
 mobileview
 modified
 modifiedarticleprotection
index 1f1a4c7..94ae95d 100644 (file)
@@ -61,6 +61,7 @@ if ( !defined( 'MW_CONFIG_CALLBACK' ) && !defined( 'MW_CONFIG_FILE' ) ) {
 
 // Custom setup for Maintenance entry point
 if ( !defined( 'MW_SETUP_CALLBACK' ) ) {
+
        function wfMaintenanceSetup() {
                // phpcs:ignore MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
                global $maintenance, $wgLocalisationCacheConf, $wgCacheDirectory;
@@ -75,6 +76,7 @@ if ( !defined( 'MW_SETUP_CALLBACK' ) ) {
 
                $maintenance->finalSetup();
        }
+
        define( 'MW_SETUP_CALLBACK', 'wfMaintenanceSetup' );
 }
 
@@ -90,6 +92,8 @@ $maintenance->checkRequiredExtensions();
 // This avoids having long running scripts just OOM and lose all the updates.
 $maintenance->setAgentAndTriggers();
 
+$maintenance->validateParamsAndArgs();
+
 // Do the work
 $success = $maintenance->execute();
 
index b942302..938a6d1 100644 (file)
@@ -65,6 +65,7 @@ TEXT
                $this->addOption( 'stub', 'Don\'t perform old_text lookups; for 2-pass dump' );
                $this->addOption( 'uploads', 'Include upload records without files' );
                $this->addOption( 'include-files', 'Include files within the XML stream' );
+               $this->addOption( 'namespaces', 'Limit to this comma-separated list of namespace numbers' );
 
                if ( $args ) {
                        $this->loadWithArgv( $args );
@@ -131,6 +132,11 @@ TEXT
                $this->dumpUploads = $this->hasOption( 'uploads' );
                $this->dumpUploadFileContents = $this->hasOption( 'include-files' );
                $this->orderRevs = $this->hasOption( 'orderrevs' );
+               if ( $this->hasOption( 'namespaces' ) ) {
+                       $this->limitNamespaces = explode( ',', $this->getOption( 'namespaces' ) );
+               } else {
+                       $this->limitNamespaces = null;
+               }
        }
 }
 
index 0479a91..a80ac7e 100644 (file)
  * @file
  * @ingroup Maintenance
  */
-
-require_once __DIR__ . '/includes/BackupDumper.php';
-require_once __DIR__ . '/7zip.inc';
-require_once __DIR__ . '/../includes/export/WikiExporter.php';
-
-use MediaWiki\MediaWikiServices;
-use MediaWiki\Storage\BlobAccessException;
-use MediaWiki\Storage\BlobStore;
-use MediaWiki\Storage\SqlBlobStore;
-use Wikimedia\Rdbms\IMaintainableDatabase;
-
-/**
- * @ingroup Maintenance
- */
-class TextPassDumper extends BackupDumper {
-       /** @var BaseDump */
-       public $prefetch = null;
-       /** @var string|bool */
-       private $thisPage;
-       /** @var string|bool */
-       private $thisRev;
-
-       // when we spend more than maxTimeAllowed seconds on this run, we continue
-       // processing until we write out the next complete page, then save output file(s),
-       // rename it/them and open new one(s)
-       public $maxTimeAllowed = 0; // 0 = no limit
-
-       protected $input = "php://stdin";
-       protected $history = WikiExporter::FULL;
-       protected $fetchCount = 0;
-       protected $prefetchCount = 0;
-       protected $prefetchCountLast = 0;
-       protected $fetchCountLast = 0;
-
-       protected $maxFailures = 5;
-       protected $maxConsecutiveFailedTextRetrievals = 200;
-       protected $failureTimeout = 5; // Seconds to sleep after db failure
-
-       protected $bufferSize = 524288; // In bytes. Maximum size to read from the stub in on go.
-
-       protected $php = "php";
-       protected $spawn = false;
-
-       /**
-        * @var bool|resource
-        */
-       protected $spawnProc = false;
-
-       /**
-        * @var bool|resource
-        */
-       protected $spawnWrite = false;
-
-       /**
-        * @var bool|resource
-        */
-       protected $spawnRead = false;
-
-       /**
-        * @var bool|resource
-        */
-       protected $spawnErr = false;
-
-       /**
-        * @var bool|XmlDumpWriter
-        */
-       protected $xmlwriterobj = false;
-
-       protected $timeExceeded = false;
-       protected $firstPageWritten = false;
-       protected $lastPageWritten = false;
-       protected $checkpointJustWritten = false;
-       protected $checkpointFiles = [];
-
-       /**
-        * @var IMaintainableDatabase
-        */
-       protected $db;
-
-       /**
-        * @param array|null $args For backward compatibility
-        */
-       function __construct( $args = null ) {
-               parent::__construct();
-
-               $this->addDescription( <<<TEXT
-This script postprocesses XML dumps from dumpBackup.php to add
-page text which was stubbed out (using --stub).
-
-XML input is accepted on stdin.
-XML output is sent to stdout; progress reports are sent to stderr.
-TEXT
-               );
-               $this->stderr = fopen( "php://stderr", "wt" );
-
-               $this->addOption( 'stub', 'To load a compressed stub dump instead of stdin. ' .
-                       'Specify as --stub=<type>:<file>.', false, true );
-               $this->addOption( 'prefetch', 'Use a prior dump file as a text source, to savepressure on the ' .
-                       'database. (Requires the XMLReader extension). Specify as --prefetch=<type>:<file>',
-                       false, true );
-               $this->addOption( 'maxtime', 'Write out checkpoint file after this many minutes (writing' .
-                       'out complete page, closing xml file properly, and opening new one' .
-                       'with header).  This option requires the checkpointfile option.', false, true );
-               $this->addOption( 'checkpointfile', 'Use this string for checkpoint filenames,substituting ' .
-                       'first pageid written for the first %s (required) and the last pageid written for the ' .
-                       'second %s if it exists.', false, true, false, true ); // This can be specified multiple times
-               $this->addOption( 'quiet', 'Don\'t dump status reports to stderr.' );
-               $this->addOption( 'full', 'Dump all revisions of every page' );
-               $this->addOption( 'current', 'Base ETA on number of pages in database instead of all revisions' );
-               $this->addOption( 'spawn', 'Spawn a subprocess for loading text records' );
-               $this->addOption( 'buffersize', 'Buffer size in bytes to use for reading the stub. ' .
-                       '(Default: 512KB, Minimum: 4KB)', false, true );
-
-               if ( $args ) {
-                       $this->loadWithArgv( $args );
-                       $this->processOptions();
-               }
-       }
-
-       /**
-        * @return BlobStore
-        */
-       private function getBlobStore() {
-               return MediaWikiServices::getInstance()->getBlobStore();
-       }
-
-       function execute() {
-               $this->processOptions();
-               $this->dump( true );
-       }
-
-       function processOptions() {
-               parent::processOptions();
-
-               if ( $this->hasOption( 'buffersize' ) ) {
-                       $this->bufferSize = max( intval( $this->getOption( 'buffersize' ) ), 4 * 1024 );
-               }
-
-               if ( $this->hasOption( 'prefetch' ) ) {
-                       $url = $this->processFileOpt( $this->getOption( 'prefetch' ) );
-                       $this->prefetch = new BaseDump( $url );
-               }
-
-               if ( $this->hasOption( 'stub' ) ) {
-                       $this->input = $this->processFileOpt( $this->getOption( 'stub' ) );
-               }
-
-               if ( $this->hasOption( 'maxtime' ) ) {
-                       $this->maxTimeAllowed = intval( $this->getOption( 'maxtime' ) ) * 60;
-               }
-
-               if ( $this->hasOption( 'checkpointfile' ) ) {
-                       $this->checkpointFiles = $this->getOption( 'checkpointfile' );
-               }
-
-               if ( $this->hasOption( 'current' ) ) {
-                       $this->history = WikiExporter::CURRENT;
-               }
-
-               if ( $this->hasOption( 'full' ) ) {
-                       $this->history = WikiExporter::FULL;
-               }
-
-               if ( $this->hasOption( 'spawn' ) ) {
-                       $this->spawn = true;
-                       $val = $this->getOption( 'spawn' );
-                       if ( $val !== 1 ) {
-                               $this->php = $val;
-                       }
-               }
-       }
-
-       /**
-        * Drop the database connection $this->db and try to get a new one.
-        *
-        * This function tries to get a /different/ connection if this is
-        * possible. Hence, (if this is possible) it switches to a different
-        * failover upon each call.
-        *
-        * This function resets $this->lb and closes all connections on it.
-        *
-        * @throws MWException
-        */
-       function rotateDb() {
-               // Cleaning up old connections
-               if ( isset( $this->lb ) ) {
-                       $this->lb->closeAll();
-                       unset( $this->lb );
-               }
-
-               if ( $this->forcedDb !== null ) {
-                       $this->db = $this->forcedDb;
-
-                       return;
-               }
-
-               if ( isset( $this->db ) && $this->db->isOpen() ) {
-                       throw new MWException( 'DB is set and has not been closed by the Load Balancer' );
-               }
-
-               unset( $this->db );
-
-               // Trying to set up new connection.
-               // We do /not/ retry upon failure, but delegate to encapsulating logic, to avoid
-               // individually retrying at different layers of code.
-
-               try {
-                       $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
-                       $this->lb = $lbFactory->newMainLB();
-               } catch ( Exception $e ) {
-                       throw new MWException( __METHOD__
-                               . " rotating DB failed to obtain new load balancer (" . $e->getMessage() . ")" );
-               }
-
-               try {
-                       $this->db = $this->lb->getConnection( DB_REPLICA, 'dump' );
-               } catch ( Exception $e ) {
-                       throw new MWException( __METHOD__
-                               . " rotating DB failed to obtain new database (" . $e->getMessage() . ")" );
-               }
-       }
-
-       function initProgress( $history = WikiExporter::FULL ) {
-               parent::initProgress();
-               $this->timeOfCheckpoint = $this->startTime;
-       }
-
-       function dump( $history, $text = WikiExporter::TEXT ) {
-               // Notice messages will foul up your XML output even if they're
-               // relatively harmless.
-               if ( ini_get( 'display_errors' ) ) {
-                       ini_set( 'display_errors', 'stderr' );
-               }
-
-               $this->initProgress( $this->history );
-
-               // We are trying to get an initial database connection to avoid that the
-               // first try of this request's first call to getText fails. However, if
-               // obtaining a good DB connection fails it's not a serious issue, as
-               // getText does retry upon failure and can start without having a working
-               // DB connection.
-               try {
-                       $this->rotateDb();
-               } catch ( Exception $e ) {
-                       // We do not even count this as failure. Just let eventual
-                       // watchdogs know.
-                       $this->progress( "Getting initial DB connection failed (" .
-                               $e->getMessage() . ")" );
-               }
-
-               $this->egress = new ExportProgressFilter( $this->sink, $this );
-
-               // it would be nice to do it in the constructor, oh well. need egress set
-               $this->finalOptionCheck();
-
-               // we only want this so we know how to close a stream :-P
-               $this->xmlwriterobj = new XmlDumpWriter();
-
-               $input = fopen( $this->input, "rt" );
-               $this->readDump( $input );
-
-               if ( $this->spawnProc ) {
-                       $this->closeSpawn();
-               }
-
-               $this->report( true );
-       }
-
-       function processFileOpt( $opt ) {
-               $split = explode( ':', $opt, 2 );
-               $val = $split[0];
-               $param = '';
-               if ( count( $split ) === 2 ) {
-                       $param = $split[1];
-               }
-               $fileURIs = explode( ';', $param );
-               foreach ( $fileURIs as $URI ) {
-                       switch ( $val ) {
-                               case "file":
-                                       $newURI = $URI;
-                                       break;
-                               case "gzip":
-                                       $newURI = "compress.zlib://$URI";
-                                       break;
-                               case "bzip2":
-                                       $newURI = "compress.bzip2://$URI";
-                                       break;
-                               case "7zip":
-                                       $newURI = "mediawiki.compress.7z://$URI";
-                                       break;
-                               default:
-                                       $newURI = $URI;
-                       }
-                       $newFileURIs[] = $newURI;
-               }
-               $val = implode( ';', $newFileURIs );
-
-               return $val;
-       }
-
-       /**
-        * Overridden to include prefetch ratio if enabled.
-        */
-       function showReport() {
-               if ( !$this->prefetch ) {
-                       parent::showReport();
-
-                       return;
-               }
-
-               if ( $this->reporting ) {
-                       $now = wfTimestamp( TS_DB );
-                       $nowts = microtime( true );
-                       $deltaAll = $nowts - $this->startTime;
-                       $deltaPart = $nowts - $this->lastTime;
-                       $this->pageCountPart = $this->pageCount - $this->pageCountLast;
-                       $this->revCountPart = $this->revCount - $this->revCountLast;
-
-                       if ( $deltaAll ) {
-                               $portion = $this->revCount / $this->maxCount;
-                               $eta = $this->startTime + $deltaAll / $portion;
-                               $etats = wfTimestamp( TS_DB, intval( $eta ) );
-                               if ( $this->fetchCount ) {
-                                       $fetchRate = 100.0 * $this->prefetchCount / $this->fetchCount;
-                               } else {
-                                       $fetchRate = '-';
-                               }
-                               $pageRate = $this->pageCount / $deltaAll;
-                               $revRate = $this->revCount / $deltaAll;
-                       } else {
-                               $pageRate = '-';
-                               $revRate = '-';
-                               $etats = '-';
-                               $fetchRate = '-';
-                       }
-                       if ( $deltaPart ) {
-                               if ( $this->fetchCountLast ) {
-                                       $fetchRatePart = 100.0 * $this->prefetchCountLast / $this->fetchCountLast;
-                               } else {
-                                       $fetchRatePart = '-';
-                               }
-                               $pageRatePart = $this->pageCountPart / $deltaPart;
-                               $revRatePart = $this->revCountPart / $deltaPart;
-                       } else {
-                               $fetchRatePart = '-';
-                               $pageRatePart = '-';
-                               $revRatePart = '-';
-                       }
-                       $this->progress( sprintf(
-                               "%s: %s (ID %d) %d pages (%0.1f|%0.1f/sec all|curr), "
-                                       . "%d revs (%0.1f|%0.1f/sec all|curr), %0.1f%%|%0.1f%% "
-                                       . "prefetched (all|curr), ETA %s [max %d]",
-                               $now, wfWikiID(), $this->ID, $this->pageCount, $pageRate,
-                               $pageRatePart, $this->revCount, $revRate, $revRatePart,
-                               $fetchRate, $fetchRatePart, $etats, $this->maxCount
-                       ) );
-                       $this->lastTime = $nowts;
-                       $this->revCountLast = $this->revCount;
-                       $this->prefetchCountLast = $this->prefetchCount;
-                       $this->fetchCountLast = $this->fetchCount;
-               }
-       }
-
-       function setTimeExceeded() {
-               $this->timeExceeded = true;
-       }
-
-       function checkIfTimeExceeded() {
-               if ( $this->maxTimeAllowed
-                       && ( $this->lastTime - $this->timeOfCheckpoint > $this->maxTimeAllowed )
-               ) {
-                       return true;
-               }
-
-               return false;
-       }
-
-       function finalOptionCheck() {
-               if ( ( $this->checkpointFiles && !$this->maxTimeAllowed )
-                       || ( $this->maxTimeAllowed && !$this->checkpointFiles )
-               ) {
-                       throw new MWException( "Options checkpointfile and maxtime must be specified together.\n" );
-               }
-               foreach ( $this->checkpointFiles as $checkpointFile ) {
-                       $count = substr_count( $checkpointFile, "%s" );
-                       if ( $count != 2 ) {
-                               throw new MWException( "Option checkpointfile must contain two '%s' "
-                                       . "for substitution of first and last pageids, count is $count instead, "
-                                       . "file is $checkpointFile.\n" );
-                       }
-               }
-
-               if ( $this->checkpointFiles ) {
-                       $filenameList = (array)$this->egress->getFilenames();
-                       if ( count( $filenameList ) != count( $this->checkpointFiles ) ) {
-                               throw new MWException( "One checkpointfile must be specified "
-                                       . "for each output option, if maxtime is used.\n" );
-                       }
-               }
-       }
-
-       /**
-        * @throws MWException Failure to parse XML input
-        * @param string $input
-        * @return bool
-        */
-       function readDump( $input ) {
-               $this->buffer = "";
-               $this->openElement = false;
-               $this->atStart = true;
-               $this->state = "";
-               $this->lastName = "";
-               $this->thisPage = 0;
-               $this->thisRev = 0;
-               $this->thisRevModel = null;
-               $this->thisRevFormat = null;
-
-               $parser = xml_parser_create( "UTF-8" );
-               xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, false );
-
-               xml_set_element_handler(
-                       $parser,
-                       [ $this, 'startElement' ],
-                       [ $this, 'endElement' ]
-               );
-               xml_set_character_data_handler( $parser, [ $this, 'characterData' ] );
-
-               $offset = 0; // for context extraction on error reporting
-               do {
-                       if ( $this->checkIfTimeExceeded() ) {
-                               $this->setTimeExceeded();
-                       }
-                       $chunk = fread( $input, $this->bufferSize );
-                       if ( !xml_parse( $parser, $chunk, feof( $input ) ) ) {
-                               wfDebug( "TextDumpPass::readDump encountered XML parsing error\n" );
-
-                               $byte = xml_get_current_byte_index( $parser );
-                               $msg = wfMessage( 'xml-error-string',
-                                       'XML import parse failure',
-                                       xml_get_current_line_number( $parser ),
-                                       xml_get_current_column_number( $parser ),
-                                       $byte . ( is_null( $chunk ) ? null : ( '; "' . substr( $chunk, $byte - $offset, 16 ) . '"' ) ),
-                                       xml_error_string( xml_get_error_code( $parser ) ) )->escaped();
-
-                               xml_parser_free( $parser );
-
-                               throw new MWException( $msg );
-                       }
-                       $offset += strlen( $chunk );
-               } while ( $chunk !== false && !feof( $input ) );
-               if ( $this->maxTimeAllowed ) {
-                       $filenameList = (array)$this->egress->getFilenames();
-                       // we wrote some stuff after last checkpoint that needs renamed
-                       if ( file_exists( $filenameList[0] ) ) {
-                               $newFilenames = [];
-                               # we might have just written the header and footer and had no
-                               # pages or revisions written... perhaps they were all deleted
-                               # there's no pageID 0 so we use that. the caller is responsible
-                               # for deciding what to do with a file containing only the
-                               # siteinfo information and the mw tags.
-                               if ( !$this->firstPageWritten ) {
-                                       $firstPageID = str_pad( 0, 9, "0", STR_PAD_LEFT );
-                                       $lastPageID = str_pad( 0, 9, "0", STR_PAD_LEFT );
-                               } else {
-                                       $firstPageID = str_pad( $this->firstPageWritten, 9, "0", STR_PAD_LEFT );
-                                       $lastPageID = str_pad( $this->lastPageWritten, 9, "0", STR_PAD_LEFT );
-                               }
-
-                               $filenameCount = count( $filenameList );
-                               for ( $i = 0; $i < $filenameCount; $i++ ) {
-                                       $checkpointNameFilledIn = sprintf( $this->checkpointFiles[$i], $firstPageID, $lastPageID );
-                                       $fileinfo = pathinfo( $filenameList[$i] );
-                                       $newFilenames[] = $fileinfo['dirname'] . '/' . $checkpointNameFilledIn;
-                               }
-                               $this->egress->closeAndRename( $newFilenames );
-                       }
-               }
-               xml_parser_free( $parser );
-
-               return true;
-       }
-
-       /**
-        * Applies applicable export transformations to $text.
-        *
-        * @param string $text
-        * @param string $model
-        * @param string|null $format
-        *
-        * @return string
-        */
-       private function exportTransform( $text, $model, $format = null ) {
-               try {
-                       $handler = ContentHandler::getForModelID( $model );
-                       $text = $handler->exportTransform( $text, $format );
-               }
-               catch ( MWException $ex ) {
-                       $this->progress(
-                               "Unable to apply export transformation for content model '$model': " .
-                               $ex->getMessage()
-                       );
-               }
-
-               return $text;
-       }
-
-       /**
-        * Tries to load revision text.
-        * Export transformations are applied if the content model is given or can be
-        * determined from the database.
-        *
-        * Upon errors, retries (Up to $this->maxFailures tries each call).
-        * If still no good revision could be found even after this retrying, "" is returned.
-        * If no good revision text could be returned for
-        * $this->maxConsecutiveFailedTextRetrievals consecutive calls to getText, MWException
-        * is thrown.
-        *
-        * @param int|string $id Content address, or text row ID.
-        * @param string|bool|null $model The content model used to determine
-        *  applicable export transformations.
-        *  If $model is null, it will be determined from the database.
-        * @param string|null $format The content format used when applying export transformations.
-        *
-        * @throws MWException
-        * @return string The revision text for $id, or ""
-        */
-       function getText( $id, $model = null, $format = null ) {
-               global $wgContentHandlerUseDB;
-
-               $prefetchNotTried = true; // Whether or not we already tried to get the text via prefetch.
-               $text = false; // The candidate for a good text. false if no proper value.
-               $failures = 0; // The number of times, this invocation of getText already failed.
-
-               // The number of times getText failed without yielding a good text in between.
-               static $consecutiveFailedTextRetrievals = 0;
-
-               $this->fetchCount++;
-
-               // To allow to simply return on success and do not have to worry about book keeping,
-               // we assume, this fetch works (possible after some retries). Nevertheless, we koop
-               // the old value, so we can restore it, if problems occur (See after the while loop).
-               $oldConsecutiveFailedTextRetrievals = $consecutiveFailedTextRetrievals;
-               $consecutiveFailedTextRetrievals = 0;
-
-               if ( $model === null && $wgContentHandlerUseDB ) {
-                       // TODO: MCR: use content table
-                       $row = $this->db->selectRow(
-                               'revision',
-                               [ 'rev_content_model', 'rev_content_format' ],
-                               [ 'rev_id' => $this->thisRev ],
-                               __METHOD__
-                       );
-
-                       if ( $row ) {
-                               $model = $row->rev_content_model;
-                               $format = $row->rev_content_format;
-                       }
-               }
-
-               if ( $model === null || $model === '' ) {
-                       $model = false;
-               }
-
-               while ( $failures < $this->maxFailures ) {
-                       // As soon as we found a good text for the $id, we will return immediately.
-                       // Hence, if we make it past the try catch block, we know that we did not
-                       // find a good text.
-
-                       try {
-                               // Step 1: Get some text (or reuse from previous iteratuon if checking
-                               //         for plausibility failed)
-
-                               // Trying to get prefetch, if it has not been tried before
-                               if ( $text === false && isset( $this->prefetch ) && $prefetchNotTried ) {
-                                       $prefetchNotTried = false;
-                                       $tryIsPrefetch = true;
-                                       $text = $this->prefetch->prefetch( (int)$this->thisPage, (int)$this->thisRev );
-
-                                       if ( $text === null ) {
-                                               $text = false;
-                                       }
-
-                                       if ( is_string( $text ) && $model !== false ) {
-                                               // Apply export transformation to text coming from an old dump.
-                                               // The purpose of this transformation is to convert up from legacy
-                                               // formats, which may still be used in the older dump that is used
-                                               // for pre-fetching. Applying the transformation again should not
-                                               // interfere with content that is already in the correct form.
-                                               $text = $this->exportTransform( $text, $model, $format );
-                                       }
-                               }
-
-                               if ( $text === false ) {
-                                       // Fallback to asking the database
-                                       $tryIsPrefetch = false;
-                                       if ( $this->spawn ) {
-                                               $text = $this->getTextSpawned( $id );
-                                       } else {
-                                               $text = $this->getTextDb( $id );
-                                       }
-
-                                       if ( $text !== false && $model !== false ) {
-                                               // Apply export transformation to text coming from the database.
-                                               // Prefetched text should already have transformations applied.
-                                               $text = $this->exportTransform( $text, $model, $format );
-                                       }
-
-                                       // No more checks for texts from DB for now.
-                                       // If we received something that is not false,
-                                       // We treat it as good text, regardless of whether it actually is or is not
-                                       if ( $text !== false ) {
-                                               return $text;
-                                       }
-                               }
-
-                               if ( $text === false ) {
-                                       throw new MWException( "Generic error while obtaining text for id " . $id );
-                               }
-
-                               // We received a good candidate for the text of $id via some method
-
-                               // Step 2: Checking for plausibility and return the text if it is
-                               //         plausible
-                               $revID = intval( $this->thisRev );
-                               if ( !isset( $this->db ) ) {
-                                       throw new MWException( "No database available" );
-                               }
-
-                               if ( $model !== CONTENT_MODEL_WIKITEXT ) {
-                                       $revLength = strlen( $text );
-                               } else {
-                                       $revLength = $this->db->selectField( 'revision', 'rev_len', [ 'rev_id' => $revID ] );
-                               }
-
-                               if ( strlen( $text ) == $revLength ) {
-                                       if ( $tryIsPrefetch ) {
-                                               $this->prefetchCount++;
-                                       }
-
-                                       return $text;
-                               }
-
-                               $text = false;
-                               throw new MWException( "Received text is unplausible for id " . $id );
-                       } catch ( Exception $e ) {
-                               $msg = "getting/checking text " . $id . " failed (" . $e->getMessage() . ")";
-                               if ( $failures + 1 < $this->maxFailures ) {
-                                       $msg .= " (Will retry " . ( $this->maxFailures - $failures - 1 ) . " more times)";
-                               }
-                               $this->progress( $msg );
-                       }
-
-                       // Something went wrong; we did not a text that was plausible :(
-                       $failures++;
-
-                       // A failure in a prefetch hit does not warrant resetting db connection etc.
-                       if ( !$tryIsPrefetch ) {
-                               // After backing off for some time, we try to reboot the whole process as
-                               // much as possible to not carry over failures from one part to the other
-                               // parts
-                               sleep( $this->failureTimeout );
-                               try {
-                                       $this->rotateDb();
-                                       if ( $this->spawn ) {
-                                               $this->closeSpawn();
-                                               $this->openSpawn();
-                                       }
-                               } catch ( Exception $e ) {
-                                       $this->progress( "Rebooting getText infrastructure failed (" . $e->getMessage() . ")" .
-                                               " Trying to continue anyways" );
-                               }
-                       }
-               }
-
-               // Retirieving a good text for $id failed (at least) maxFailures times.
-               // We abort for this $id.
-
-               // Restoring the consecutive failures, and maybe aborting, if the dump
-               // is too broken.
-               $consecutiveFailedTextRetrievals = $oldConsecutiveFailedTextRetrievals + 1;
-               if ( $consecutiveFailedTextRetrievals > $this->maxConsecutiveFailedTextRetrievals ) {
-                       throw new MWException( "Graceful storage failure" );
-               }
-
-               return "";
-       }
-
-       /**
-        * Loads the serialized content from storage.
-        *
-        * @param int|string $id Content address, or text row ID.
-        * @return bool|string
-        */
-       private function getTextDb( $id ) {
-               $store = $this->getBlobStore();
-               $address = ( is_int( $id ) || strpos( $id, ':' ) === false )
-                       ? SqlBlobStore::makeAddressFromTextId( (int)$id )
-                       : $id;
-
-               try {
-                       $text = $store->getBlob( $address );
-
-                       $stripped = str_replace( "\r", "", $text );
-                       $normalized = MediaWikiServices::getInstance()->getContentLanguage()
-                               ->normalize( $stripped );
-
-                       return $normalized;
-               } catch ( BlobAccessException $ex ) {
-                       // XXX: log a warning?
-                       return false;
-               }
-       }
-
-       /**
-        * @param int|string $id Content address, or text row ID.
-        * @return bool|string
-        */
-       private function getTextSpawned( $id ) {
-               Wikimedia\suppressWarnings();
-               if ( !$this->spawnProc ) {
-                       // First time?
-                       $this->openSpawn();
-               }
-               $text = $this->getTextSpawnedOnce( $id );
-               Wikimedia\restoreWarnings();
-
-               return $text;
-       }
-
-       function openSpawn() {
-               global $IP;
-
-               if ( file_exists( "$IP/../multiversion/MWScript.php" ) ) {
-                       $cmd = implode( " ",
-                               array_map( 'wfEscapeShellArg',
-                                       [
-                                               $this->php,
-                                               "$IP/../multiversion/MWScript.php",
-                                               "fetchText.php",
-                                               '--wiki', wfWikiID() ] ) );
-               } else {
-                       $cmd = implode( " ",
-                               array_map( 'wfEscapeShellArg',
-                                       [
-                                               $this->php,
-                                               "$IP/maintenance/fetchText.php",
-                                               '--wiki', wfWikiID() ] ) );
-               }
-               $spec = [
-                       0 => [ "pipe", "r" ],
-                       1 => [ "pipe", "w" ],
-                       2 => [ "file", "/dev/null", "a" ] ];
-               $pipes = [];
-
-               $this->progress( "Spawning database subprocess: $cmd" );
-               $this->spawnProc = proc_open( $cmd, $spec, $pipes );
-               if ( !$this->spawnProc ) {
-                       $this->progress( "Subprocess spawn failed." );
-
-                       return false;
-               }
-               list(
-                       $this->spawnWrite, // -> stdin
-                       $this->spawnRead, // <- stdout
-               ) = $pipes;
-
-               return true;
-       }
-
-       private function closeSpawn() {
-               Wikimedia\suppressWarnings();
-               if ( $this->spawnRead ) {
-                       fclose( $this->spawnRead );
-               }
-               $this->spawnRead = false;
-               if ( $this->spawnWrite ) {
-                       fclose( $this->spawnWrite );
-               }
-               $this->spawnWrite = false;
-               if ( $this->spawnErr ) {
-                       fclose( $this->spawnErr );
-               }
-               $this->spawnErr = false;
-               if ( $this->spawnProc ) {
-                       pclose( $this->spawnProc );
-               }
-               $this->spawnProc = false;
-               Wikimedia\restoreWarnings();
-       }
-
-       /**
-        * @param int|string $id Content address, or text row ID.
-        * @return bool|string
-        */
-       private function getTextSpawnedOnce( $id ) {
-               $ok = fwrite( $this->spawnWrite, "$id\n" );
-               // $this->progress( ">> $id" );
-               if ( !$ok ) {
-                       return false;
-               }
-
-               $ok = fflush( $this->spawnWrite );
-               // $this->progress( ">> [flush]" );
-               if ( !$ok ) {
-                       return false;
-               }
-
-               // check that the text id they are sending is the one we asked for
-               // this avoids out of sync revision text errors we have encountered in the past
-               $newAddress = fgets( $this->spawnRead );
-               if ( $newAddress === false ) {
-                       return false;
-               }
-               if ( strpos( $newAddress, ':' ) === false ) {
-                       $newId = intval( $newAddress );
-                       if ( $newId === false ) {
-                               return false;
-                       }
-               } else {
-                       try {
-                               $newAddressFields = SqlBlobStore::splitBlobAddress( $newAddress );
-                               $newId = $newAddressFields[ 1 ];
-                       } catch ( InvalidArgumentException $ex ) {
-                               return false;
-                       }
-               }
-               if ( $id != intval( $newId ) ) {
-                       return false;
-               }
-
-               $len = fgets( $this->spawnRead );
-               // $this->progress( "<< " . trim( $len ) );
-               if ( $len === false ) {
-                       return false;
-               }
-
-               $nbytes = intval( $len );
-               // actual error, not zero-length text
-               if ( $nbytes < 0 ) {
-                       return false;
-               }
-
-               $text = "";
-
-               // Subprocess may not send everything at once, we have to loop.
-               while ( $nbytes > strlen( $text ) ) {
-                       $buffer = fread( $this->spawnRead, $nbytes - strlen( $text ) );
-                       if ( $buffer === false ) {
-                               break;
-                       }
-                       $text .= $buffer;
-               }
-
-               $gotbytes = strlen( $text );
-               if ( $gotbytes != $nbytes ) {
-                       $this->progress( "Expected $nbytes bytes from database subprocess, got $gotbytes " );
-
-                       return false;
-               }
-
-               // Do normalization in the dump thread...
-               $stripped = str_replace( "\r", "", $text );
-               $normalized = MediaWikiServices::getInstance()->getContentLanguage()->
-                       normalize( $stripped );
-
-               return $normalized;
-       }
-
-       function startElement( $parser, $name, $attribs ) {
-               $this->checkpointJustWritten = false;
-
-               $this->clearOpenElement( null );
-               $this->lastName = $name;
-
-               if ( $name == 'revision' ) {
-                       $this->state = $name;
-                       $this->egress->writeOpenPage( null, $this->buffer );
-                       $this->buffer = "";
-               } elseif ( $name == 'page' ) {
-                       $this->state = $name;
-                       if ( $this->atStart ) {
-                               $this->egress->writeOpenStream( $this->buffer );
-                               $this->buffer = "";
-                               $this->atStart = false;
-                       }
-               }
-
-               if ( $name == "text" && isset( $attribs['id'] ) ) {
-                       $id = $attribs['id'];
-                       $model = trim( $this->thisRevModel );
-                       $format = trim( $this->thisRevFormat );
-
-                       $model = $model === '' ? null : $model;
-                       $format = $format === '' ? null : $format;
-
-                       $text = $this->getText( $id, $model, $format );
-                       $this->openElement = [ $name, [ 'xml:space' => 'preserve' ] ];
-                       if ( strlen( $text ) > 0 ) {
-                               $this->characterData( $parser, $text );
-                       }
-               } else {
-                       $this->openElement = [ $name, $attribs ];
-               }
-       }
-
-       function endElement( $parser, $name ) {
-               $this->checkpointJustWritten = false;
-
-               if ( $this->openElement ) {
-                       $this->clearOpenElement( "" );
-               } else {
-                       $this->buffer .= "</$name>";
-               }
-
-               if ( $name == 'revision' ) {
-                       $this->egress->writeRevision( null, $this->buffer );
-                       $this->buffer = "";
-                       $this->thisRev = "";
-                       $this->thisRevModel = null;
-                       $this->thisRevFormat = null;
-               } elseif ( $name == 'page' ) {
-                       if ( !$this->firstPageWritten ) {
-                               $this->firstPageWritten = trim( $this->thisPage );
-                       }
-                       $this->lastPageWritten = trim( $this->thisPage );
-                       if ( $this->timeExceeded ) {
-                               $this->egress->writeClosePage( $this->buffer );
-                               // nasty hack, we can't just write the chardata after the
-                               // page tag, it will include leading blanks from the next line
-                               $this->egress->sink->write( "\n" );
-
-                               $this->buffer = $this->xmlwriterobj->closeStream();
-                               $this->egress->writeCloseStream( $this->buffer );
-
-                               $this->buffer = "";
-                               $this->thisPage = "";
-                               // this could be more than one file if we had more than one output arg
-
-                               $filenameList = (array)$this->egress->getFilenames();
-                               $newFilenames = [];
-                               $firstPageID = str_pad( $this->firstPageWritten, 9, "0", STR_PAD_LEFT );
-                               $lastPageID = str_pad( $this->lastPageWritten, 9, "0", STR_PAD_LEFT );
-                               $filenamesCount = count( $filenameList );
-                               for ( $i = 0; $i < $filenamesCount; $i++ ) {
-                                       $checkpointNameFilledIn = sprintf( $this->checkpointFiles[$i], $firstPageID, $lastPageID );
-                                       $fileinfo = pathinfo( $filenameList[$i] );
-                                       $newFilenames[] = $fileinfo['dirname'] . '/' . $checkpointNameFilledIn;
-                               }
-                               $this->egress->closeRenameAndReopen( $newFilenames );
-                               $this->buffer = $this->xmlwriterobj->openStream();
-                               $this->timeExceeded = false;
-                               $this->timeOfCheckpoint = $this->lastTime;
-                               $this->firstPageWritten = false;
-                               $this->checkpointJustWritten = true;
-                       } else {
-                               $this->egress->writeClosePage( $this->buffer );
-                               $this->buffer = "";
-                               $this->thisPage = "";
-                       }
-               } elseif ( $name == 'mediawiki' ) {
-                       $this->egress->writeCloseStream( $this->buffer );
-                       $this->buffer = "";
-               }
-       }
-
-       function characterData( $parser, $data ) {
-               $this->clearOpenElement( null );
-               if ( $this->lastName == "id" ) {
-                       if ( $this->state == "revision" ) {
-                               $this->thisRev .= $data;
-                       } elseif ( $this->state == "page" ) {
-                               $this->thisPage .= $data;
-                       }
-               } elseif ( $this->lastName == "model" ) {
-                       $this->thisRevModel .= $data;
-               } elseif ( $this->lastName == "format" ) {
-                       $this->thisRevFormat .= $data;
-               }
-
-               // have to skip the newline left over from closepagetag line of
-               // end of checkpoint files. nasty hack!!
-               if ( $this->checkpointJustWritten ) {
-                       if ( $data[0] == "\n" ) {
-                               $data = substr( $data, 1 );
-                       }
-                       $this->checkpointJustWritten = false;
-               }
-               $this->buffer .= htmlspecialchars( $data );
-       }
-
-       function clearOpenElement( $style ) {
-               if ( $this->openElement ) {
-                       $this->buffer .= Xml::element( $this->openElement[0], $this->openElement[1], $style );
-                       $this->openElement = false;
-               }
-       }
-}
+require_once __DIR__ . '/includes/TextPassDumper.php';
 
 $maintClass = TextPassDumper::class;
 require_once RUN_MAINTENANCE_IF_MAIN;
index d4a7bef..3609cf2 100644 (file)
@@ -71,7 +71,7 @@ class EditCLI extends Maintenance {
                        $wgUser->addToDatabase();
                }
 
-               $title = Title::newFromText( $this->getArg() );
+               $title = Title::newFromText( $this->getArg( 0 ) );
                if ( !$title ) {
                        $this->fatalError( "Invalid title" );
                }
index 900752f..b57db8f 100644 (file)
@@ -34,6 +34,8 @@
  * @author Antoine Musso <hashar at free dot fr>
  */
 
+use MediaWiki\MediaWikiServices;
+
 require_once __DIR__ . '/Maintenance.php';
 
 /**
@@ -216,7 +218,7 @@ class FindHooks extends Maintenance {
 
                $retval = [];
                while ( true ) {
-                       $json = Http::get(
+                       $json = MediaWikiServices::getInstance()->getHttpRequestFactory()->get(
                                wfAppendQuery( 'https://www.mediawiki.org/w/api.php', $params ),
                                [],
                                __METHOD__
index 57e04e0..e81e197 100644 (file)
@@ -117,7 +117,7 @@ class FindOrphanedFiles extends Maintenance {
                                                $oiWheres ? $dbr->makeList( $oiWheres, LIST_OR ) : '1=0'
                                        )
                                ],
-                               true // UNION ALL (performance)
+                               $dbr::UNION_ALL
                        ),
                        __METHOD__
                );
index dc1de4f..7d43f21 100644 (file)
@@ -230,7 +230,7 @@ class GenerateSitemap extends Maintenance {
                // Custom priorities
                if ( $wgSitemapNamespacesPriorities !== false ) {
                        /**
-                        * @var $wgSitemapNamespacesPriorities array
+                        * @var array $wgSitemapNamespacesPriorities
                         */
                        foreach ( $wgSitemapNamespacesPriorities as $namespace => $priority ) {
                                $float = floatval( $priority );
@@ -290,7 +290,7 @@ class GenerateSitemap extends Maintenance {
         * @return string
         */
        function guessPriority( $namespace ) {
-               return MWNamespace::isSubject( $namespace )
+               return MediaWikiServices::getInstance()->getNamespaceInfo()->isSubject( $namespace )
                        ? $this->priorities[self::GS_MAIN]
                        : $this->priorities[self::GS_TALK];
        }
index de6e87a..f56729c 100644 (file)
@@ -56,7 +56,7 @@ class GetConfiguration extends Maintenance {
                $this->addOption( 'format', implode( ', ', self::$outFormats ), false, true );
        }
 
-       protected function validateParamsAndArgs() {
+       public function validateParamsAndArgs() {
                $error_out = false;
 
                # Get the format and make sure it is set to a valid default value
index a8a0c71..9502cdc 100644 (file)
@@ -1,5 +1,7 @@
 <?php
 
+use MediaWiki\Shell\Shell;
+
 require __DIR__ . '/../Maintenance.php';
 
 class HHVMMakeRepo extends Maintenance {
@@ -103,7 +105,7 @@ class HHVMMakeRepo extends Maintenance {
 
                $hhvm = $this->getOption( 'hhvm', 'hhvm' );
                $verbose = $this->getOption( 'verbose', 3 );
-               $cmd = wfEscapeShellArg(
+               $cmd = Shell::escape(
                        $hhvm,
                        '--hphp',
                        '--target', 'hhbc',
index d84e02f..e1deb4c 100755 (executable)
@@ -1,6 +1,8 @@
 #!/usr/bin/hhvm -f
 <?php
 
+use MediaWiki\Shell\Shell;
+
 require __DIR__ . '/../Maintenance.php';
 
 class RunHipHopServer extends Maintenance {
@@ -12,8 +14,8 @@ class RunHipHopServer extends Maintenance {
                global $IP;
 
                passthru(
-                       'cd ' . wfEscapeShellArg( $IP ) . " && " .
-                       wfEscapeShellArg(
+                       'cd ' . Shell::escape( $IP ) . " && " .
+                       Shell::escape(
                                'hhvm',
                                '-c', __DIR__."/server.conf",
                                '--mode=server',
index 7c20748..c2c5ccf 100644 (file)
@@ -112,8 +112,8 @@ TEXT
                        $this->setNsfilter( explode( '|', $this->getOption( 'namespaces' ) ) );
                }
 
-               if ( $this->hasArg() ) {
-                       $this->importFromFile( $this->getArg() );
+               if ( $this->hasArg( 0 ) ) {
+                       $this->importFromFile( $this->getArg( 0 ) );
                } else {
                        $this->importFromStdin();
                }
index 1728695..f27ea2f 100644 (file)
@@ -211,7 +211,8 @@ class ImportImages extends Maintenance {
 
                                if ( $checkUserBlock && ( ( $processed % $checkUserBlock ) == 0 ) ) {
                                        $user->clearInstanceCache( 'name' ); // reload from DB!
-                                       if ( $user->isBlocked() ) {
+                                       // @TODO Use PermissionManager::isBlockedFrom() instead.
+                                       if ( $user->getBlock() ) {
                                                $this->output( $user->getName() . " was blocked! Aborting.\n" );
                                                break;
                                        }
index e60e776..1d4b496 100644 (file)
@@ -21,6 +21,8 @@
  * @ingroup Maintenance
  */
 
+use MediaWiki\MediaWikiServices;
+
 require_once __DIR__ . '/Maintenance.php';
 
 /**
@@ -64,7 +66,8 @@ class ImportSiteScripts extends Maintenance {
                        $url = wfAppendQuery( $baseUrl, [
                                'action' => 'raw',
                                'title' => "MediaWiki:{$page}" ] );
-                       $text = Http::get( $url, [], __METHOD__ );
+                       $text = MediaWikiServices::getInstance()->getHttpRequestFactory()->
+                               get( $url, [], __METHOD__ );
 
                        $wikiPage = WikiPage::factory( $title );
                        $content = ContentHandler::makeContent( $text, $wikiPage->getTitle() );
@@ -86,7 +89,8 @@ class ImportSiteScripts extends Maintenance {
 
                while ( true ) {
                        $url = wfAppendQuery( $baseUrl, $data );
-                       $strResult = Http::get( $url, [], __METHOD__ );
+                       $strResult = MediaWikiServices::getInstance()->getHttpRequestFactory()->
+                               get( $url, [], __METHOD__ );
                        $result = FormatJson::decode( $strResult, true );
 
                        $page = null;
index 45786d8..0118c94 100644 (file)
@@ -26,6 +26,7 @@
  */
 
 require_once __DIR__ . '/../Maintenance.php';
+require_once __DIR__ . '/../../includes/export/WikiExporter.php';
 
 use MediaWiki\MediaWikiServices;
 use Wikimedia\Rdbms\LoadBalancer;
@@ -47,10 +48,12 @@ abstract class BackupDumper extends Maintenance {
        public $dumpUploads = false;
        public $dumpUploadFileContents = false;
        public $orderRevs = false;
+       public $limitNamespaces = [];
 
        protected $reportingInterval = 100;
        protected $pageCount = 0;
        protected $revCount = 0;
+       protected $schemaVersion = null; // use default
        protected $server = null; // use default
        protected $sink = null; // Output filters
        protected $lastTime = 0;
@@ -86,6 +89,7 @@ abstract class BackupDumper extends Maintenance {
                $this->registerOutput( 'gzip', DumpGZipOutput::class );
                $this->registerOutput( 'bzip2', DumpBZip2Output::class );
                $this->registerOutput( 'dbzip2', DumpDBZip2Output::class );
+               $this->registerOutput( 'lbzip2', DumpLBZip2Output::class );
                $this->registerOutput( '7zip', Dump7ZipOutput::class );
 
                $this->registerFilter( 'latest', DumpLatestFilter::class );
@@ -96,11 +100,13 @@ abstract class BackupDumper extends Maintenance {
                $this->addOption( 'plugin', 'Load a dump plugin class. Specify as <class>[:<file>].',
                        false, true, false, true );
                $this->addOption( 'output', 'Begin a filtered output stream; Specify as <type>:<file>. ' .
-                       '<type>s: file, gzip, bzip2, 7zip, dbzip2', false, true, false, true );
+                       '<type>s: file, gzip, bzip2, 7zip, dbzip2, lbzip2', false, true, false, true );
                $this->addOption( 'filter', 'Add a filter on an output branch. Specify as ' .
                        '<type>[:<options>]. <types>s: latest, notalk, namespace', false, true, false, true );
                $this->addOption( 'report', 'Report position and speed after every n pages processed. ' .
                        'Default: 100.', false, true );
+               $this->addOption( 'schema-version', 'Schema version to use for output. ' .
+                       'Default: ' . WikiExporter::schemaVersion(), false, true );
                $this->addOption( 'server', 'Force reading from MySQL server', false, true );
                $this->addOption( '7ziplevel', '7zip compression level for all 7zip outputs. Used for ' .
                        '-mx option to 7za command.', false, true );
@@ -155,10 +161,11 @@ abstract class BackupDumper extends Maintenance {
                $sink = null;
                $sinks = [];
 
+               $this->schemaVersion = WikiExporter::schemaVersion();
+
                $options = $this->orderedOptions;
                foreach ( $options as $arg ) {
-                       $opt = $arg[0];
-                       $param = $arg[1];
+                       list( $opt, $param ) = $arg;
 
                        switch ( $opt ) {
                                case 'plugin':
@@ -215,6 +222,15 @@ abstract class BackupDumper extends Maintenance {
                                        unset( $sink );
                                        $sink = $filter;
 
+                                       break;
+                               case 'schema-version':
+                                       if ( !in_array( $param, XmlDumpWriter::$supportedSchemas ) ) {
+                                               $this->fatalError(
+                                                       "Unsupported schema version $param. Supported versions: " .
+                                                       implode( ', ', XmlDumpWriter::$supportedSchemas )
+                                               );
+                                       }
+                                       $this->schemaVersion = $param;
                                        break;
                        }
                }
@@ -249,7 +265,8 @@ abstract class BackupDumper extends Maintenance {
                $this->initProgress( $history );
 
                $db = $this->backupDb();
-               $exporter = new WikiExporter( $db, $history, $text );
+               $exporter = new WikiExporter( $db, $history, $text, $this->limitNamespaces );
+               $exporter->setSchemaVersion( $this->schemaVersion );
                $exporter->dumpUploads = $this->dumpUploads;
                $exporter->dumpUploadFileContents = $this->dumpUploadFileContents;
 
index ef8756f..aff6758 100644 (file)
@@ -32,9 +32,13 @@ require_once __DIR__ . '/../Maintenance.php';
  * @ingroup Maintenance
  */
 class MigrateActors extends LoggedUpdateMaintenance {
+
+       protected $tables = null;
+
        public function __construct() {
                parent::__construct();
                $this->addDescription( 'Migrates actors from pre-1.31 columns to the \'actor\' table' );
+               $this->addOption( 'tables', 'List of tables to process, comma-separated', false, true );
                $this->setBatchSize( 100 );
        }
 
@@ -42,6 +46,10 @@ class MigrateActors extends LoggedUpdateMaintenance {
                return __CLASS__;
        }
 
+       protected function doTable( $table ) {
+               return $this->tables === null || in_array( $table, $this->tables, true );
+       }
+
        protected function doDBUpdates() {
                global $wgActorTableSchemaMigrationStage;
 
@@ -52,28 +60,51 @@ class MigrateActors extends LoggedUpdateMaintenance {
                        return false;
                }
 
-               $this->output( "Creating actor entries for all registered users\n" );
-               $end = 0;
-               $dbw = $this->getDB( DB_MASTER );
-               $max = $dbw->selectField( 'user', 'MAX(user_id)', '', __METHOD__ );
-               $count = 0;
-               while ( $end < $max ) {
-                       $start = $end + 1;
-                       $end = min( $start + $this->mBatchSize, $max );
-                       $this->output( "... $start - $end\n" );
-                       $dbw->insertSelect(
-                               'actor',
-                               'user',
-                               [ 'actor_user' => 'user_id', 'actor_name' => 'user_name' ],
-                               [ "user_id >= $start", "user_id <= $end" ],
+               $tables = $this->getOption( 'tables' );
+               if ( $tables !== null ) {
+                       $this->tables = explode( ',', $tables );
+               }
+
+               if ( $this->doTable( 'user' ) ) {
+                       $this->output( "Creating actor entries for all registered users\n" );
+                       $end = 0;
+                       $dbw = $this->getDB( DB_MASTER );
+                       $max = $dbw->selectField( 'user', 'MAX(user_id)', '', __METHOD__ );
+                       $count = 0;
+                       while ( $end < $max ) {
+                               $start = $end + 1;
+                               $end = min( $start + $this->mBatchSize, $max );
+                               $this->output( "... $start - $end\n" );
+                               $dbw->insertSelect(
+                                       'actor',
+                                       'user',
+                                       [ 'actor_user' => 'user_id', 'actor_name' => 'user_name' ],
+                                       [ "user_id >= $start", "user_id <= $end" ],
+                                       __METHOD__,
+                                       [ 'IGNORE' ],
+                                       [ 'ORDER BY' => [ 'user_id' ] ]
+                               );
+                               $count += $dbw->affectedRows();
+                               wfWaitForSlaves();
+                       }
+                       $this->output( "Completed actor creation, added $count new actor(s)\n" );
+               } else {
+                       $this->output( "Checking that actors exist for all registered users\n" );
+                       $dbr = $this->getDB( DB_REPLICA, [ 'vslow' ] );
+                       $anyMissing = $dbr->selectField(
+                               [ 'user', 'actor' ],
+                               '1',
+                               [ 'actor_id' => null ],
                                __METHOD__,
-                               [ 'IGNORE' ],
-                               [ 'ORDER BY' => [ 'user_id' ] ]
+                               [ 'LIMIT 1' ],
+                               [ 'actor' => [ 'LEFT JOIN', 'actor_user = user_id' ] ]
                        );
-                       $count += $dbw->affectedRows();
-                       wfWaitForSlaves();
+                       if ( $anyMissing ) {
+                               $this->error( 'Some users lack actors; run without --tables or include `user` in --tables.' );
+                               return false;
+                       }
+                       $this->output( "Ok, continuing.\n" );
                }
-               $this->output( "Completed actor creation, added $count new actor(s)\n" );
 
                $errors = 0;
                $errors += $this->migrateToTemp(
@@ -229,6 +260,11 @@ class MigrateActors extends LoggedUpdateMaintenance {
         * @return int Number of errors
         */
        protected function migrate( $table, $primaryKey, $userField, $nameField, $actorField ) {
+               if ( !$this->doTable( $table ) ) {
+                       $this->output( "Skipping $table, not included in --tables\n" );
+                       return 0;
+               }
+
                $complainedAboutUsers = [];
 
                $primaryKey = (array)$primaryKey;
@@ -325,6 +361,11 @@ class MigrateActors extends LoggedUpdateMaintenance {
        protected function migrateToTemp(
                $table, $primaryKey, $extra, $userField, $nameField, $newPrimaryKey, $actorField
        ) {
+               if ( !$this->doTable( $table ) ) {
+                       $this->output( "Skipping $table, not included in --tables\n" );
+                       return 0;
+               }
+
                $complainedAboutUsers = [];
 
                $newTable = $table . '_actor_temp';
@@ -413,6 +454,11 @@ class MigrateActors extends LoggedUpdateMaintenance {
         * @return int Number of errors
         */
        protected function migrateLogSearch() {
+               if ( !$this->doTable( 'log_search' ) ) {
+                       $this->output( "Skipping log_search, not included in --tables\n" );
+                       return 0;
+               }
+
                $complainedAboutUsers = [];
 
                $primaryKey = [ 'ls_value', 'ls_log_id' ];
@@ -424,6 +470,25 @@ class MigrateActors extends LoggedUpdateMaintenance {
                $countActors = 0;
                $countErrors = 0;
 
+               $anyBad = $dbw->selectField(
+                       'log_search',
+                       1,
+                       [ 'ls_field' => 'target_author_actor', 'ls_value' => '' ],
+                       __METHOD__,
+                       [ 'LIMIT' => 1 ]
+               );
+               if ( $anyBad ) {
+                       $this->output( "... Deleting bogus rows due to T215525\n" );
+                       $dbw->delete(
+                               'log_search',
+                               [ 'ls_field' => 'target_author_actor', 'ls_value' => '' ],
+                               __METHOD__
+                       );
+                       $ct = $dbw->affectedRows();
+                       $this->output( "... Deleted $ct bogus row(s) from T215525\n" );
+                       wfWaitForSlaves();
+               }
+
                $next = '1=1';
                while ( true ) {
                        // Fetch the rows needing update
@@ -439,7 +504,7 @@ class MigrateActors extends LoggedUpdateMaintenance {
                                        'ORDER BY' => $primaryKey,
                                        'LIMIT' => $this->mBatchSize,
                                ],
-                               [ 'actor' => [ 'LEFT JOIN', 'ls_value = ' . $dbw->buildStringCast( 'actor_user' ) ] ]
+                               [ 'actor' => [ 'LEFT JOIN', 'actor_user = ' . $dbw->buildIntegerCast( 'ls_value' ) ] ]
                        );
                        if ( !$res->numRows() ) {
                                break;
diff --git a/maintenance/includes/SevenZipStream.php b/maintenance/includes/SevenZipStream.php
new file mode 100644 (file)
index 0000000..6a763f2
--- /dev/null
@@ -0,0 +1,98 @@
+<?php
+/**
+ * 7z stream wrapper
+ *
+ * Copyright © 2005 Brion Vibber <brion@pobox.com>
+ * https://www.mediawiki.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+use MediaWiki\Shell\Shell;
+
+/**
+ * Stream wrapper around 7za filter program.
+ * Required since we can't pass an open file resource to XMLReader->open()
+ * which is used for the text prefetch.
+ *
+ * @ingroup Maintenance
+ */
+class SevenZipStream {
+       protected $stream;
+
+       private function stripPath( $path ) {
+               $prefix = 'mediawiki.compress.7z://';
+
+               return substr( $path, strlen( $prefix ) );
+       }
+
+       function stream_open( $path, $mode, $options, &$opened_path ) {
+               if ( $mode[0] == 'r' ) {
+                       $options = 'e -bd -so';
+               } elseif ( $mode[0] == 'w' ) {
+                       $options = 'a -bd -si';
+               } else {
+                       return false;
+               }
+               $arg = Shell::escape( $this->stripPath( $path ) );
+               $command = "7za $options $arg";
+               if ( !wfIsWindows() ) {
+                       // Suppress the stupid messages on stderr
+                       $command .= ' 2>/dev/null';
+               }
+               $this->stream = popen( $command, $mode[0] ); // popen() doesn't like two-letter modes
+               return ( $this->stream !== false );
+       }
+
+       function url_stat( $path, $flags ) {
+               return stat( $this->stripPath( $path ) );
+       }
+
+       // This is all so lame; there should be a default class we can extend
+
+       function stream_close() {
+               return fclose( $this->stream );
+       }
+
+       function stream_flush() {
+               return fflush( $this->stream );
+       }
+
+       function stream_read( $count ) {
+               return fread( $this->stream, $count );
+       }
+
+       function stream_write( $data ) {
+               return fwrite( $this->stream, $data );
+       }
+
+       function stream_tell() {
+               return ftell( $this->stream );
+       }
+
+       function stream_eof() {
+               return feof( $this->stream );
+       }
+
+       function stream_seek( $offset, $whence ) {
+               return fseek( $this->stream, $offset, $whence );
+       }
+}
+
+stream_wrapper_register( 'mediawiki.compress.7z', SevenZipStream::class );
diff --git a/maintenance/includes/TextPassDumper.php b/maintenance/includes/TextPassDumper.php
new file mode 100644 (file)
index 0000000..eaed7ed
--- /dev/null
@@ -0,0 +1,1025 @@
+<?php
+/**
+ * BackupDumper that postprocesses XML dumps from dumpBackup.php to add page text
+ *
+ * Copyright (C) 2005 Brion Vibber <brion@pobox.com>
+ * https://www.mediawiki.org/
+ *
+ * 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 Dump
+ * @ingroup Maintenance
+ */
+
+require_once __DIR__ . '/BackupDumper.php';
+require_once __DIR__ . '/SevenZipStream.php';
+require_once __DIR__ . '/../../includes/export/WikiExporter.php';
+
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Shell\Shell;
+use MediaWiki\Storage\BlobAccessException;
+use MediaWiki\Storage\SqlBlobStore;
+use Wikimedia\Rdbms\IMaintainableDatabase;
+
+/**
+ * @ingroup Maintenance
+ */
+class TextPassDumper extends BackupDumper {
+       /** @var BaseDump */
+       public $prefetch = null;
+       /** @var string|bool */
+       private $thisPage;
+       /** @var string|bool */
+       private $thisRev;
+
+       // when we spend more than maxTimeAllowed seconds on this run, we continue
+       // processing until we write out the next complete page, then save output file(s),
+       // rename it/them and open new one(s)
+       public $maxTimeAllowed = 0; // 0 = no limit
+
+       protected $input = "php://stdin";
+       protected $history = WikiExporter::FULL;
+       protected $fetchCount = 0;
+       protected $prefetchCount = 0;
+       protected $prefetchCountLast = 0;
+       protected $fetchCountLast = 0;
+
+       protected $maxFailures = 5;
+       protected $maxConsecutiveFailedTextRetrievals = 200;
+       protected $failureTimeout = 5; // Seconds to sleep after db failure
+
+       protected $bufferSize = 524288; // In bytes. Maximum size to read from the stub in on go.
+
+       protected $php = "php";
+       protected $spawn = false;
+
+       /**
+        * @var bool|resource
+        */
+       protected $spawnProc = false;
+
+       /**
+        * @var bool|resource
+        */
+       protected $spawnWrite = false;
+
+       /**
+        * @var bool|resource
+        */
+       protected $spawnRead = false;
+
+       /**
+        * @var bool|resource
+        */
+       protected $spawnErr = false;
+
+       /**
+        * @var bool|XmlDumpWriter
+        */
+       protected $xmlwriterobj = false;
+
+       protected $timeExceeded = false;
+       protected $firstPageWritten = false;
+       protected $lastPageWritten = false;
+       protected $checkpointJustWritten = false;
+       protected $checkpointFiles = [];
+
+       /**
+        * @var IMaintainableDatabase
+        */
+       protected $db;
+
+       /**
+        * @param array|null $args For backward compatibility
+        */
+       function __construct( $args = null ) {
+               parent::__construct();
+
+               $this->addDescription( <<<TEXT
+This script postprocesses XML dumps from dumpBackup.php to add
+page text which was stubbed out (using --stub).
+
+XML input is accepted on stdin.
+XML output is sent to stdout; progress reports are sent to stderr.
+TEXT
+               );
+               $this->stderr = fopen( "php://stderr", "wt" );
+
+               $this->addOption( 'stub', 'To load a compressed stub dump instead of stdin. ' .
+                       'Specify as --stub=<type>:<file>.', false, true );
+               $this->addOption( 'prefetch', 'Use a prior dump file as a text source, to savepressure on the ' .
+                       'database. (Requires the XMLReader extension). Specify as --prefetch=<type>:<file>',
+                       false, true );
+               $this->addOption( 'maxtime', 'Write out checkpoint file after this many minutes (writing' .
+                       'out complete page, closing xml file properly, and opening new one' .
+                       'with header).  This option requires the checkpointfile option.', false, true );
+               $this->addOption( 'checkpointfile', 'Use this string for checkpoint filenames,substituting ' .
+                       'first pageid written for the first %s (required) and the last pageid written for the ' .
+                       'second %s if it exists.', false, true, false, true ); // This can be specified multiple times
+               $this->addOption( 'quiet', 'Don\'t dump status reports to stderr.' );
+               $this->addOption( 'full', 'Dump all revisions of every page' );
+               $this->addOption( 'current', 'Base ETA on number of pages in database instead of all revisions' );
+               $this->addOption( 'spawn', 'Spawn a subprocess for loading text records, optionally specify ' .
+                       'php[,mwscript] paths' );
+               $this->addOption( 'buffersize', 'Buffer size in bytes to use for reading the stub. ' .
+                       '(Default: 512KB, Minimum: 4KB)', false, true );
+
+               if ( $args ) {
+                       $this->loadWithArgv( $args );
+                       $this->processOptions();
+               }
+       }
+
+       /**
+        * @return SqlBlobStore
+        */
+       private function getBlobStore() {
+               return MediaWikiServices::getInstance()->getBlobStore();
+       }
+
+       function execute() {
+               $this->processOptions();
+               $this->dump( true );
+       }
+
+       function processOptions() {
+               parent::processOptions();
+
+               if ( $this->hasOption( 'buffersize' ) ) {
+                       $this->bufferSize = max( intval( $this->getOption( 'buffersize' ) ), 4 * 1024 );
+               }
+
+               if ( $this->hasOption( 'prefetch' ) ) {
+                       $url = $this->processFileOpt( $this->getOption( 'prefetch' ) );
+                       $this->prefetch = new BaseDump( $url );
+               }
+
+               if ( $this->hasOption( 'stub' ) ) {
+                       $this->input = $this->processFileOpt( $this->getOption( 'stub' ) );
+               }
+
+               if ( $this->hasOption( 'maxtime' ) ) {
+                       $this->maxTimeAllowed = intval( $this->getOption( 'maxtime' ) ) * 60;
+               }
+
+               if ( $this->hasOption( 'checkpointfile' ) ) {
+                       $this->checkpointFiles = $this->getOption( 'checkpointfile' );
+               }
+
+               if ( $this->hasOption( 'current' ) ) {
+                       $this->history = WikiExporter::CURRENT;
+               }
+
+               if ( $this->hasOption( 'full' ) ) {
+                       $this->history = WikiExporter::FULL;
+               }
+
+               if ( $this->hasOption( 'spawn' ) ) {
+                       $this->spawn = true;
+                       $val = $this->getOption( 'spawn' );
+                       if ( $val !== 1 ) {
+                               $this->php = explode( ',', $val, 2 );
+                       }
+               }
+       }
+
+       /**
+        * Drop the database connection $this->db and try to get a new one.
+        *
+        * This function tries to get a /different/ connection if this is
+        * possible. Hence, (if this is possible) it switches to a different
+        * failover upon each call.
+        *
+        * This function resets $this->lb and closes all connections on it.
+        *
+        * @throws MWException
+        */
+       function rotateDb() {
+               // Cleaning up old connections
+               if ( isset( $this->lb ) ) {
+                       $this->lb->closeAll();
+                       unset( $this->lb );
+               }
+
+               if ( $this->forcedDb !== null ) {
+                       $this->db = $this->forcedDb;
+
+                       return;
+               }
+
+               if ( isset( $this->db ) && $this->db->isOpen() ) {
+                       throw new MWException( 'DB is set and has not been closed by the Load Balancer' );
+               }
+
+               unset( $this->db );
+
+               // Trying to set up new connection.
+               // We do /not/ retry upon failure, but delegate to encapsulating logic, to avoid
+               // individually retrying at different layers of code.
+
+               try {
+                       $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+                       $this->lb = $lbFactory->newMainLB();
+               } catch ( Exception $e ) {
+                       throw new MWException( __METHOD__
+                               . " rotating DB failed to obtain new load balancer (" . $e->getMessage() . ")" );
+               }
+
+               try {
+                       $this->db = $this->lb->getConnection( DB_REPLICA, 'dump' );
+               } catch ( Exception $e ) {
+                       throw new MWException( __METHOD__
+                               . " rotating DB failed to obtain new database (" . $e->getMessage() . ")" );
+               }
+       }
+
+       function initProgress( $history = WikiExporter::FULL ) {
+               parent::initProgress();
+               $this->timeOfCheckpoint = $this->startTime;
+       }
+
+       function dump( $history, $text = WikiExporter::TEXT ) {
+               // Notice messages will foul up your XML output even if they're
+               // relatively harmless.
+               if ( ini_get( 'display_errors' ) ) {
+                       ini_set( 'display_errors', 'stderr' );
+               }
+
+               $this->initProgress( $this->history );
+
+               // We are trying to get an initial database connection to avoid that the
+               // first try of this request's first call to getText fails. However, if
+               // obtaining a good DB connection fails it's not a serious issue, as
+               // getText does retry upon failure and can start without having a working
+               // DB connection.
+               try {
+                       $this->rotateDb();
+               } catch ( Exception $e ) {
+                       // We do not even count this as failure. Just let eventual
+                       // watchdogs know.
+                       $this->progress( "Getting initial DB connection failed (" .
+                               $e->getMessage() . ")" );
+               }
+
+               $this->egress = new ExportProgressFilter( $this->sink, $this );
+
+               // it would be nice to do it in the constructor, oh well. need egress set
+               $this->finalOptionCheck();
+
+               // we only want this so we know how to close a stream :-P
+               $this->xmlwriterobj = new XmlDumpWriter();
+
+               $input = fopen( $this->input, "rt" );
+               $this->readDump( $input );
+
+               if ( $this->spawnProc ) {
+                       $this->closeSpawn();
+               }
+
+               $this->report( true );
+       }
+
+       function processFileOpt( $opt ) {
+               $split = explode( ':', $opt, 2 );
+               $val = $split[0];
+               $param = '';
+               if ( count( $split ) === 2 ) {
+                       $param = $split[1];
+               }
+               $fileURIs = explode( ';', $param );
+               foreach ( $fileURIs as $URI ) {
+                       switch ( $val ) {
+                               case "file":
+                                       $newURI = $URI;
+                                       break;
+                               case "gzip":
+                                       $newURI = "compress.zlib://$URI";
+                                       break;
+                               case "bzip2":
+                                       $newURI = "compress.bzip2://$URI";
+                                       break;
+                               case "7zip":
+                                       $newURI = "mediawiki.compress.7z://$URI";
+                                       break;
+                               default:
+                                       $newURI = $URI;
+                       }
+                       $newFileURIs[] = $newURI;
+               }
+               $val = implode( ';', $newFileURIs );
+
+               return $val;
+       }
+
+       /**
+        * Overridden to include prefetch ratio if enabled.
+        */
+       function showReport() {
+               if ( !$this->prefetch ) {
+                       parent::showReport();
+
+                       return;
+               }
+
+               if ( $this->reporting ) {
+                       $now = wfTimestamp( TS_DB );
+                       $nowts = microtime( true );
+                       $deltaAll = $nowts - $this->startTime;
+                       $deltaPart = $nowts - $this->lastTime;
+                       $this->pageCountPart = $this->pageCount - $this->pageCountLast;
+                       $this->revCountPart = $this->revCount - $this->revCountLast;
+
+                       if ( $deltaAll ) {
+                               $portion = $this->revCount / $this->maxCount;
+                               $eta = $this->startTime + $deltaAll / $portion;
+                               $etats = wfTimestamp( TS_DB, intval( $eta ) );
+                               if ( $this->fetchCount ) {
+                                       $fetchRate = 100.0 * $this->prefetchCount / $this->fetchCount;
+                               } else {
+                                       $fetchRate = '-';
+                               }
+                               $pageRate = $this->pageCount / $deltaAll;
+                               $revRate = $this->revCount / $deltaAll;
+                       } else {
+                               $pageRate = '-';
+                               $revRate = '-';
+                               $etats = '-';
+                               $fetchRate = '-';
+                       }
+                       if ( $deltaPart ) {
+                               if ( $this->fetchCountLast ) {
+                                       $fetchRatePart = 100.0 * $this->prefetchCountLast / $this->fetchCountLast;
+                               } else {
+                                       $fetchRatePart = '-';
+                               }
+                               $pageRatePart = $this->pageCountPart / $deltaPart;
+                               $revRatePart = $this->revCountPart / $deltaPart;
+                       } else {
+                               $fetchRatePart = '-';
+                               $pageRatePart = '-';
+                               $revRatePart = '-';
+                       }
+                       $this->progress( sprintf(
+                               "%s: %s (ID %d) %d pages (%0.1f|%0.1f/sec all|curr), "
+                                       . "%d revs (%0.1f|%0.1f/sec all|curr), %0.1f%%|%0.1f%% "
+                                       . "prefetched (all|curr), ETA %s [max %d]",
+                               $now, wfWikiID(), $this->ID, $this->pageCount, $pageRate,
+                               $pageRatePart, $this->revCount, $revRate, $revRatePart,
+                               $fetchRate, $fetchRatePart, $etats, $this->maxCount
+                       ) );
+                       $this->lastTime = $nowts;
+                       $this->revCountLast = $this->revCount;
+                       $this->prefetchCountLast = $this->prefetchCount;
+                       $this->fetchCountLast = $this->fetchCount;
+               }
+       }
+
+       function setTimeExceeded() {
+               $this->timeExceeded = true;
+       }
+
+       function checkIfTimeExceeded() {
+               if ( $this->maxTimeAllowed
+                       && ( $this->lastTime - $this->timeOfCheckpoint > $this->maxTimeAllowed )
+               ) {
+                       return true;
+               }
+
+               return false;
+       }
+
+       function finalOptionCheck() {
+               if ( ( $this->checkpointFiles && !$this->maxTimeAllowed )
+                       || ( $this->maxTimeAllowed && !$this->checkpointFiles )
+               ) {
+                       throw new MWException( "Options checkpointfile and maxtime must be specified together.\n" );
+               }
+               foreach ( $this->checkpointFiles as $checkpointFile ) {
+                       $count = substr_count( $checkpointFile, "%s" );
+                       if ( $count != 2 ) {
+                               throw new MWException( "Option checkpointfile must contain two '%s' "
+                                       . "for substitution of first and last pageids, count is $count instead, "
+                                       . "file is $checkpointFile.\n" );
+                       }
+               }
+
+               if ( $this->checkpointFiles ) {
+                       $filenameList = (array)$this->egress->getFilenames();
+                       if ( count( $filenameList ) != count( $this->checkpointFiles ) ) {
+                               throw new MWException( "One checkpointfile must be specified "
+                                       . "for each output option, if maxtime is used.\n" );
+                       }
+               }
+       }
+
+       /**
+        * @throws MWException Failure to parse XML input
+        * @param string $input
+        * @return bool
+        */
+       function readDump( $input ) {
+               $this->buffer = "";
+               $this->openElement = false;
+               $this->atStart = true;
+               $this->state = "";
+               $this->lastName = "";
+               $this->thisPage = 0;
+               $this->thisRev = 0;
+               $this->thisRevModel = null;
+               $this->thisRevFormat = null;
+
+               $parser = xml_parser_create( "UTF-8" );
+               xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, false );
+
+               xml_set_element_handler(
+                       $parser,
+                       [ $this, 'startElement' ],
+                       [ $this, 'endElement' ]
+               );
+               xml_set_character_data_handler( $parser, [ $this, 'characterData' ] );
+
+               $offset = 0; // for context extraction on error reporting
+               do {
+                       if ( $this->checkIfTimeExceeded() ) {
+                               $this->setTimeExceeded();
+                       }
+                       $chunk = fread( $input, $this->bufferSize );
+                       if ( !xml_parse( $parser, $chunk, feof( $input ) ) ) {
+                               wfDebug( "TextDumpPass::readDump encountered XML parsing error\n" );
+
+                               $byte = xml_get_current_byte_index( $parser );
+                               $msg = wfMessage( 'xml-error-string',
+                                       'XML import parse failure',
+                                       xml_get_current_line_number( $parser ),
+                                       xml_get_current_column_number( $parser ),
+                                       $byte . ( is_null( $chunk ) ? null : ( '; "' . substr( $chunk, $byte - $offset, 16 ) . '"' ) ),
+                                       xml_error_string( xml_get_error_code( $parser ) ) )->escaped();
+
+                               xml_parser_free( $parser );
+
+                               throw new MWException( $msg );
+                       }
+                       $offset += strlen( $chunk );
+               } while ( $chunk !== false && !feof( $input ) );
+               if ( $this->maxTimeAllowed ) {
+                       $filenameList = (array)$this->egress->getFilenames();
+                       // we wrote some stuff after last checkpoint that needs renamed
+                       if ( file_exists( $filenameList[0] ) ) {
+                               $newFilenames = [];
+                               # we might have just written the header and footer and had no
+                               # pages or revisions written... perhaps they were all deleted
+                               # there's no pageID 0 so we use that. the caller is responsible
+                               # for deciding what to do with a file containing only the
+                               # siteinfo information and the mw tags.
+                               if ( !$this->firstPageWritten ) {
+                                       $firstPageID = str_pad( 0, 9, "0", STR_PAD_LEFT );
+                                       $lastPageID = str_pad( 0, 9, "0", STR_PAD_LEFT );
+                               } else {
+                                       $firstPageID = str_pad( $this->firstPageWritten, 9, "0", STR_PAD_LEFT );
+                                       $lastPageID = str_pad( $this->lastPageWritten, 9, "0", STR_PAD_LEFT );
+                               }
+
+                               $filenameCount = count( $filenameList );
+                               for ( $i = 0; $i < $filenameCount; $i++ ) {
+                                       $checkpointNameFilledIn = sprintf( $this->checkpointFiles[$i], $firstPageID, $lastPageID );
+                                       $fileinfo = pathinfo( $filenameList[$i] );
+                                       $newFilenames[] = $fileinfo['dirname'] . '/' . $checkpointNameFilledIn;
+                               }
+                               $this->egress->closeAndRename( $newFilenames );
+                       }
+               }
+               xml_parser_free( $parser );
+
+               return true;
+       }
+
+       /**
+        * Applies applicable export transformations to $text.
+        *
+        * @param string $text
+        * @param string $model
+        * @param string|null $format
+        *
+        * @return string
+        */
+       private function exportTransform( $text, $model, $format = null ) {
+               try {
+                       $handler = ContentHandler::getForModelID( $model );
+                       $text = $handler->exportTransform( $text, $format );
+               }
+               catch ( MWException $ex ) {
+                       $this->progress(
+                               "Unable to apply export transformation for content model '$model': " .
+                               $ex->getMessage()
+                       );
+               }
+
+               return $text;
+       }
+
+       /**
+        * Tries to load revision text.
+        * Export transformations are applied if the content model is given or can be
+        * determined from the database.
+        *
+        * Upon errors, retries (Up to $this->maxFailures tries each call).
+        * If still no good revision could be found even after this retrying, "" is returned.
+        * If no good revision text could be returned for
+        * $this->maxConsecutiveFailedTextRetrievals consecutive calls to getText, MWException
+        * is thrown.
+        *
+        * @param int|string $id Content address, or text row ID.
+        * @param string|bool|null $model The content model used to determine
+        *  applicable export transformations.
+        *  If $model is null, it will be determined from the database.
+        * @param string|null $format The content format used when applying export transformations.
+        *
+        * @throws MWException
+        * @return string The revision text for $id, or ""
+        */
+       function getText( $id, $model = null, $format = null ) {
+               global $wgContentHandlerUseDB;
+
+               $prefetchNotTried = true; // Whether or not we already tried to get the text via prefetch.
+               $text = false; // The candidate for a good text. false if no proper value.
+               $failures = 0; // The number of times, this invocation of getText already failed.
+
+               // The number of times getText failed without yielding a good text in between.
+               static $consecutiveFailedTextRetrievals = 0;
+
+               $this->fetchCount++;
+
+               // To allow to simply return on success and do not have to worry about book keeping,
+               // we assume, this fetch works (possible after some retries). Nevertheless, we koop
+               // the old value, so we can restore it, if problems occur (See after the while loop).
+               $oldConsecutiveFailedTextRetrievals = $consecutiveFailedTextRetrievals;
+               $consecutiveFailedTextRetrievals = 0;
+
+               if ( $model === null && $wgContentHandlerUseDB ) {
+                       // TODO: MCR: use content table
+                       $row = $this->db->selectRow(
+                               'revision',
+                               [ 'rev_content_model', 'rev_content_format' ],
+                               [ 'rev_id' => $this->thisRev ],
+                               __METHOD__
+                       );
+
+                       if ( $row ) {
+                               $model = $row->rev_content_model;
+                               $format = $row->rev_content_format;
+                       }
+               }
+
+               if ( $model === null || $model === '' ) {
+                       $model = false;
+               }
+
+               while ( $failures < $this->maxFailures ) {
+                       // As soon as we found a good text for the $id, we will return immediately.
+                       // Hence, if we make it past the try catch block, we know that we did not
+                       // find a good text.
+
+                       try {
+                               // Step 1: Get some text (or reuse from previous iteratuon if checking
+                               //         for plausibility failed)
+
+                               // Trying to get prefetch, if it has not been tried before
+                               if ( $text === false && isset( $this->prefetch ) && $prefetchNotTried ) {
+                                       $prefetchNotTried = false;
+                                       $tryIsPrefetch = true;
+                                       $text = $this->prefetch->prefetch( (int)$this->thisPage, (int)$this->thisRev );
+
+                                       if ( $text === null ) {
+                                               $text = false;
+                                       }
+
+                                       if ( is_string( $text ) && $model !== false ) {
+                                               // Apply export transformation to text coming from an old dump.
+                                               // The purpose of this transformation is to convert up from legacy
+                                               // formats, which may still be used in the older dump that is used
+                                               // for pre-fetching. Applying the transformation again should not
+                                               // interfere with content that is already in the correct form.
+                                               $text = $this->exportTransform( $text, $model, $format );
+                                       }
+                               }
+
+                               if ( $text === false ) {
+                                       // Fallback to asking the database
+                                       $tryIsPrefetch = false;
+                                       if ( $this->spawn ) {
+                                               $text = $this->getTextSpawned( $id );
+                                       } else {
+                                               $text = $this->getTextDb( $id );
+                                       }
+
+                                       if ( $text !== false && $model !== false ) {
+                                               // Apply export transformation to text coming from the database.
+                                               // Prefetched text should already have transformations applied.
+                                               $text = $this->exportTransform( $text, $model, $format );
+                                       }
+
+                                       // No more checks for texts from DB for now.
+                                       // If we received something that is not false,
+                                       // We treat it as good text, regardless of whether it actually is or is not
+                                       if ( $text !== false ) {
+                                               return $text;
+                                       }
+                               }
+
+                               if ( $text === false ) {
+                                       throw new MWException( "Generic error while obtaining text for id " . $id );
+                               }
+
+                               // We received a good candidate for the text of $id via some method
+
+                               // Step 2: Checking for plausibility and return the text if it is
+                               //         plausible
+                               $revID = intval( $this->thisRev );
+                               if ( !isset( $this->db ) ) {
+                                       throw new MWException( "No database available" );
+                               }
+
+                               if ( $model !== CONTENT_MODEL_WIKITEXT ) {
+                                       $revLength = strlen( $text );
+                               } else {
+                                       $revLength = $this->db->selectField( 'revision', 'rev_len', [ 'rev_id' => $revID ] );
+                               }
+
+                               if ( strlen( $text ) == $revLength ) {
+                                       if ( $tryIsPrefetch ) {
+                                               $this->prefetchCount++;
+                                       }
+
+                                       return $text;
+                               }
+
+                               $text = false;
+                               throw new MWException( "Received text is unplausible for id " . $id );
+                       } catch ( Exception $e ) {
+                               $msg = "getting/checking text " . $id . " failed (" . $e->getMessage() . ")";
+                               if ( $failures + 1 < $this->maxFailures ) {
+                                       $msg .= " (Will retry " . ( $this->maxFailures - $failures - 1 ) . " more times)";
+                               }
+                               $this->progress( $msg );
+                       }
+
+                       // Something went wrong; we did not a text that was plausible :(
+                       $failures++;
+
+                       // A failure in a prefetch hit does not warrant resetting db connection etc.
+                       if ( !$tryIsPrefetch ) {
+                               // After backing off for some time, we try to reboot the whole process as
+                               // much as possible to not carry over failures from one part to the other
+                               // parts
+                               sleep( $this->failureTimeout );
+                               try {
+                                       $this->rotateDb();
+                                       if ( $this->spawn ) {
+                                               $this->closeSpawn();
+                                               $this->openSpawn();
+                                       }
+                               } catch ( Exception $e ) {
+                                       $this->progress( "Rebooting getText infrastructure failed (" . $e->getMessage() . ")" .
+                                               " Trying to continue anyways" );
+                               }
+                       }
+               }
+
+               // Retirieving a good text for $id failed (at least) maxFailures times.
+               // We abort for this $id.
+
+               // Restoring the consecutive failures, and maybe aborting, if the dump
+               // is too broken.
+               $consecutiveFailedTextRetrievals = $oldConsecutiveFailedTextRetrievals + 1;
+               if ( $consecutiveFailedTextRetrievals > $this->maxConsecutiveFailedTextRetrievals ) {
+                       throw new MWException( "Graceful storage failure" );
+               }
+
+               return "";
+       }
+
+       /**
+        * Loads the serialized content from storage.
+        *
+        * @param int|string $id Content address, or text row ID.
+        * @return bool|string
+        */
+       private function getTextDb( $id ) {
+               $store = $this->getBlobStore();
+               $address = ( is_int( $id ) || strpos( $id, ':' ) === false )
+                       ? SqlBlobStore::makeAddressFromTextId( (int)$id )
+                       : $id;
+
+               try {
+                       $text = $store->getBlob( $address );
+
+                       $stripped = str_replace( "\r", "", $text );
+                       $normalized = MediaWikiServices::getInstance()->getContentLanguage()
+                               ->normalize( $stripped );
+
+                       return $normalized;
+               } catch ( BlobAccessException $ex ) {
+                       // XXX: log a warning?
+                       return false;
+               }
+       }
+
+       /**
+        * @param int|string $address Content address, or text row ID.
+        * @return bool|string
+        */
+       private function getTextSpawned( $address ) {
+               Wikimedia\suppressWarnings();
+               if ( !$this->spawnProc ) {
+                       // First time?
+                       $this->openSpawn();
+               }
+               $text = $this->getTextSpawnedOnce( $address );
+               Wikimedia\restoreWarnings();
+
+               return $text;
+       }
+
+       function openSpawn() {
+               global $IP;
+
+               if ( count( $this->php ) == 2 ) {
+                       $mwscriptpath = $this->php[1];
+               } else {
+                       $mwscriptpath = "$IP/../multiversion/MWScript.php";
+               }
+               if ( file_exists( $mwscriptpath ) ) {
+                       $cmd = implode( " ",
+                               array_map( [ Shell::class, 'escape' ],
+                                       [
+                                               $this->php[0],
+                                               $mwscriptpath,
+                                               "fetchText.php",
+                                               '--wiki', wfWikiID() ] ) );
+               } else {
+                       $cmd = implode( " ",
+                               array_map( [ Shell::class, 'escape' ],
+                                       [
+                                               $this->php[0],
+                                               "$IP/maintenance/fetchText.php",
+                                               '--wiki', wfWikiID() ] ) );
+               }
+               $spec = [
+                       0 => [ "pipe", "r" ],
+                       1 => [ "pipe", "w" ],
+                       2 => [ "file", "/dev/null", "a" ] ];
+               $pipes = [];
+
+               $this->progress( "Spawning database subprocess: $cmd" );
+               $this->spawnProc = proc_open( $cmd, $spec, $pipes );
+               if ( !$this->spawnProc ) {
+                       $this->progress( "Subprocess spawn failed." );
+
+                       return false;
+               }
+               list(
+                       $this->spawnWrite, // -> stdin
+                       $this->spawnRead, // <- stdout
+               ) = $pipes;
+
+               return true;
+       }
+
+       private function closeSpawn() {
+               Wikimedia\suppressWarnings();
+               if ( $this->spawnRead ) {
+                       fclose( $this->spawnRead );
+               }
+               $this->spawnRead = false;
+               if ( $this->spawnWrite ) {
+                       fclose( $this->spawnWrite );
+               }
+               $this->spawnWrite = false;
+               if ( $this->spawnErr ) {
+                       fclose( $this->spawnErr );
+               }
+               $this->spawnErr = false;
+               if ( $this->spawnProc ) {
+                       pclose( $this->spawnProc );
+               }
+               $this->spawnProc = false;
+               Wikimedia\restoreWarnings();
+       }
+
+       /**
+        * @param int|string $address Content address, or text row ID.
+        * @return bool|string
+        */
+       private function getTextSpawnedOnce( $address ) {
+               if ( is_int( $address ) || intval( $address ) ) {
+                       $address = SqlBlobStore::makeAddressFromTextId( (int)$address );
+               }
+
+               $ok = fwrite( $this->spawnWrite, "$address\n" );
+               // $this->progress( ">> $id" );
+               if ( !$ok ) {
+                       return false;
+               }
+
+               $ok = fflush( $this->spawnWrite );
+               // $this->progress( ">> [flush]" );
+               if ( !$ok ) {
+                       return false;
+               }
+
+               // check that the text address they are sending is the one we asked for
+               // this avoids out of sync revision text errors we have encountered in the past
+               $newAddress = fgets( $this->spawnRead );
+               if ( $newAddress === false ) {
+                       return false;
+               }
+               $newAddress = trim( $newAddress );
+               if ( strpos( $newAddress, ':' ) === false ) {
+                       $newAddress = SqlBlobStore::makeAddressFromTextId( intval( $newAddress ) );
+               }
+
+               if ( $newAddress !== $address ) {
+                       return false;
+               }
+
+               $len = fgets( $this->spawnRead );
+               // $this->progress( "<< " . trim( $len ) );
+               if ( $len === false ) {
+                       return false;
+               }
+
+               $nbytes = intval( $len );
+               // actual error, not zero-length text
+               if ( $nbytes < 0 ) {
+                       return false;
+               }
+
+               $text = "";
+
+               // Subprocess may not send everything at once, we have to loop.
+               while ( $nbytes > strlen( $text ) ) {
+                       $buffer = fread( $this->spawnRead, $nbytes - strlen( $text ) );
+                       if ( $buffer === false ) {
+                               break;
+                       }
+                       $text .= $buffer;
+               }
+
+               $gotbytes = strlen( $text );
+               if ( $gotbytes != $nbytes ) {
+                       $this->progress( "Expected $nbytes bytes from database subprocess, got $gotbytes " );
+
+                       return false;
+               }
+
+               // Do normalization in the dump thread...
+               $stripped = str_replace( "\r", "", $text );
+               $normalized = MediaWikiServices::getInstance()->getContentLanguage()->
+                       normalize( $stripped );
+
+               return $normalized;
+       }
+
+       function startElement( $parser, $name, $attribs ) {
+               $this->checkpointJustWritten = false;
+
+               $this->clearOpenElement( null );
+               $this->lastName = $name;
+
+               if ( $name == 'revision' ) {
+                       $this->state = $name;
+                       $this->egress->writeOpenPage( null, $this->buffer );
+                       $this->buffer = "";
+               } elseif ( $name == 'page' ) {
+                       $this->state = $name;
+                       if ( $this->atStart ) {
+                               $this->egress->writeOpenStream( $this->buffer );
+                               $this->buffer = "";
+                               $this->atStart = false;
+                       }
+               }
+
+               if ( $name == "text" && isset( $attribs['id'] ) ) {
+                       $id = $attribs['id'];
+                       $model = trim( $this->thisRevModel );
+                       $format = trim( $this->thisRevFormat );
+
+                       $model = $model === '' ? null : $model;
+                       $format = $format === '' ? null : $format;
+
+                       $text = $this->getText( $id, $model, $format );
+                       $this->openElement = [ $name, [ 'xml:space' => 'preserve' ] ];
+                       if ( strlen( $text ) > 0 ) {
+                               $this->characterData( $parser, $text );
+                       }
+               } else {
+                       $this->openElement = [ $name, $attribs ];
+               }
+       }
+
+       function endElement( $parser, $name ) {
+               $this->checkpointJustWritten = false;
+
+               if ( $this->openElement ) {
+                       $this->clearOpenElement( "" );
+               } else {
+                       $this->buffer .= "</$name>";
+               }
+
+               if ( $name == 'revision' ) {
+                       $this->egress->writeRevision( null, $this->buffer );
+                       $this->buffer = "";
+                       $this->thisRev = "";
+                       $this->thisRevModel = null;
+                       $this->thisRevFormat = null;
+               } elseif ( $name == 'page' ) {
+                       if ( !$this->firstPageWritten ) {
+                               $this->firstPageWritten = trim( $this->thisPage );
+                       }
+                       $this->lastPageWritten = trim( $this->thisPage );
+                       if ( $this->timeExceeded ) {
+                               $this->egress->writeClosePage( $this->buffer );
+                               // nasty hack, we can't just write the chardata after the
+                               // page tag, it will include leading blanks from the next line
+                               $this->egress->sink->write( "\n" );
+
+                               $this->buffer = $this->xmlwriterobj->closeStream();
+                               $this->egress->writeCloseStream( $this->buffer );
+
+                               $this->buffer = "";
+                               $this->thisPage = "";
+                               // this could be more than one file if we had more than one output arg
+
+                               $filenameList = (array)$this->egress->getFilenames();
+                               $newFilenames = [];
+                               $firstPageID = str_pad( $this->firstPageWritten, 9, "0", STR_PAD_LEFT );
+                               $lastPageID = str_pad( $this->lastPageWritten, 9, "0", STR_PAD_LEFT );
+                               $filenamesCount = count( $filenameList );
+                               for ( $i = 0; $i < $filenamesCount; $i++ ) {
+                                       $checkpointNameFilledIn = sprintf( $this->checkpointFiles[$i], $firstPageID, $lastPageID );
+                                       $fileinfo = pathinfo( $filenameList[$i] );
+                                       $newFilenames[] = $fileinfo['dirname'] . '/' . $checkpointNameFilledIn;
+                               }
+                               $this->egress->closeRenameAndReopen( $newFilenames );
+                               $this->buffer = $this->xmlwriterobj->openStream();
+                               $this->timeExceeded = false;
+                               $this->timeOfCheckpoint = $this->lastTime;
+                               $this->firstPageWritten = false;
+                               $this->checkpointJustWritten = true;
+                       } else {
+                               $this->egress->writeClosePage( $this->buffer );
+                               $this->buffer = "";
+                               $this->thisPage = "";
+                       }
+               } elseif ( $name == 'mediawiki' ) {
+                       $this->egress->writeCloseStream( $this->buffer );
+                       $this->buffer = "";
+               }
+       }
+
+       function characterData( $parser, $data ) {
+               $this->clearOpenElement( null );
+               if ( $this->lastName == "id" ) {
+                       if ( $this->state == "revision" ) {
+                               $this->thisRev .= $data;
+                       } elseif ( $this->state == "page" ) {
+                               $this->thisPage .= $data;
+                       }
+               } elseif ( $this->lastName == "model" ) {
+                       $this->thisRevModel .= $data;
+               } elseif ( $this->lastName == "format" ) {
+                       $this->thisRevFormat .= $data;
+               }
+
+               // have to skip the newline left over from closepagetag line of
+               // end of checkpoint files. nasty hack!!
+               if ( $this->checkpointJustWritten ) {
+                       if ( $data[0] == "\n" ) {
+                               $data = substr( $data, 1 );
+                       }
+                       $this->checkpointJustWritten = false;
+               }
+               $this->buffer .= htmlspecialchars( $data );
+       }
+
+       function clearOpenElement( $style ) {
+               if ( $this->openElement ) {
+                       $this->buffer .= Xml::element( $this->openElement[0], $this->openElement[1], $style );
+                       $this->openElement = false;
+               }
+       }
+}
index 3395458..1dd1909 100644 (file)
@@ -129,6 +129,11 @@ class CommandLineInstaller extends Maintenance {
                        $installer->execute();
                        $installer->writeConfigurationFile( $this->getOption( 'confpath', $IP ) );
                }
+               $installer->showMessage(
+                       'config-install-success',
+                       $installer->getVar( 'wgServer' ),
+                       $installer->getVar( 'wgScriptPath' )
+               );
        }
 
        private function setDbPassOption() {
index 661ec98..aa5077d 100644 (file)
@@ -38,7 +38,7 @@ class JSParseHelper extends Maintenance {
        }
 
        public function execute() {
-               if ( $this->hasArg() ) {
+               if ( $this->hasArg( 0 ) ) {
                        $files = $this->mArgs;
                } else {
                        $this->maybeHelp( true ); // @todo fixme this is a lame API :)
index f43d75f..5843f67 100644 (file)
@@ -23,6 +23,8 @@
 
 require_once __DIR__ . '/../Maintenance.php';
 
+use Wikimedia\StaticArrayWriter;
+
 /**
  * Generate first letter data files for Collation.php
  *
index 336495a..e689f7c 100644 (file)
@@ -23,6 +23,8 @@
 
 require_once __DIR__ . '/../Maintenance.php';
 
+use Wikimedia\StaticArrayWriter;
+
 /**
  * Generates the normalizer data file for Arabic.
  *
index 1b8ea09..5f865ce 100644 (file)
@@ -23,6 +23,8 @@
 
 require_once __DIR__ . '/../Maintenance.php';
 
+use Wikimedia\StaticArrayWriter;
+
 /**
  * Generates the normalizer data file for Malayalam.
  *
diff --git a/maintenance/language/generateUcfirstOverrides.php b/maintenance/language/generateUcfirstOverrides.php
new file mode 100644 (file)
index 0000000..458231c
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+/**
+ * Generate a php file containg an array of
+ *   utf8_lowercase => utf8_uppercase
+ * overrides. Takes as input two json files generated with generateUpperCharTable.php
+ * as input.
+ *
+ * Example run:
+ * # this will prepare a file to use to make hhvm's Language::ucfirst work like php7's
+ *
+ * $ php7.2 maintenance/language/generateUpperCharTable.php --outfile php7.2.json
+ * $ hhvm --php maintenance/language/generateUpperCharTable.php --outfile hhvm.json
+ * $ hhvm maintenance/language/generateUcfirstOverrides.php \
+ *       --override hhvm.json --with php7.2.json --outfile test.php
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup MaintenanceLanguage
+ */
+
+require_once __DIR__ . '/../Maintenance.php';
+
+class GenerateUcfirstOverrides extends Maintenance {
+
+       public function __construct() {
+               parent::__construct();
+               $this->addDescription(
+                       'Generates a php source file containing a definition for mb_strtoupper overrides' );
+               $this->addOption( 'outfile', 'Output file', true, true, 'o' );
+               $this->addOption( 'override', 'Char table we want to override', true, true );
+               $this->addOption( 'with', 'Char table we want to obtain', true, true );
+       }
+
+       public function execute() {
+               $outfile = $this->getOption( 'outfile' );
+               $from = $this->loadJson( $this->getOption( 'override' ) );
+               $to = $this->loadJson( $this->getOption( 'with' ) );
+               $overrides = [];
+
+               foreach ( $from as $lc => $uc ) {
+                       $ref = $to[$lc] ?? null;
+                       if ( $ref !== null && $ref !== $uc ) {
+                               $overrides[$lc] = $ref;
+                       }
+               }
+               $writer = new StaticArrayWriter();
+               file_put_contents(
+                       $outfile,
+                       $writer->create( $overrides, 'File created by generateUcfirstOverrides.php' )
+               );
+       }
+
+       private function loadJson( $filename ) {
+               $data = file_get_contents( $filename );
+               if ( $data === false ) {
+                       $msg = sprintf( "Could not load data from file '%s'\n", $filename );
+                       $this->fatalError( $msg );
+               }
+               $json = json_decode( $data, true );
+               if ( $json === null ) {
+                       $msg = sprintf( "Invalid json in the data file %s\n", $filename );
+                       $this->fatalError( $msg, 2 );
+               }
+               return $json;
+       }
+}
+
+$maintClass = GenerateUcfirstOverrides::class;
+require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/language/generateUpperCharTable.php b/maintenance/language/generateUpperCharTable.php
new file mode 100644 (file)
index 0000000..c8393bf
--- /dev/null
@@ -0,0 +1,53 @@
+<?php
+/**
+ * Generate a json file containing an array of
+ *   utf8_lowercase => utf8_uppercase
+ * for all of the utf-8 range. This provides the input for generateUcfirstOverrides.php
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup MaintenanceLanguage
+ */
+
+require_once __DIR__ . '/../Maintenance.php';
+
+class GenerateUpperCharTable extends Maintenance {
+
+       public function __construct() {
+               parent::__construct();
+               $this->addDescription( 'Generates the lowercase => uppercase json table' );
+               $this->addOption( 'outfile', 'Output file', true, true, 'o' );
+       }
+
+       public function execute() {
+               $outfile = $this->getOption( 'outfile', 'upperchar.json' );
+               $toUpperTable = [];
+               for ( $i = 0; $i <= 0x10ffff; $i++ ) {
+                       // skip all surrogate codepoints or json_encode would fail.
+                       if ( $i >= 0xd800 && $i <= 0xdfff ) {
+                               continue;
+                       }
+                       $char = UtfNormal\Utils::codepointToUtf8( $i );
+                       $upper = mb_strtoupper( $char );
+                       $toUpperTable[$char] = $upper;
+               }
+               file_put_contents( $outfile, json_encode( $toUpperTable ) );
+       }
+}
+
+$maintClass = GenerateUpperCharTable::class;
+require_once RUN_MAINTENANCE_IF_MAIN;
index cb85a53..7a5e93e 100644 (file)
@@ -242,6 +242,7 @@ U+09FCE鿎|U+040EE䃮|
 U+09FCF鿏|U+04951䥑|
 U+09FD2鿒|U+09FD3鿓|
 U+09FD4鿔|U+093B6鎶|
+U+22016𢀖|U+05DE0巠|
 U+235CB𣗋|U+06B13欓|
 U+23C97𣲗|U+06E4B湋|
 U+23C98𣲘|U+06F55潕|
index 6c34e0b..1613b83 100644 (file)
@@ -26,6 +26,8 @@
 名份 名分
 職份 职分
 份外 分外
+份外,      份外,
+份外卖      份外卖
 份內 分内
 部份 部分
 知識份子   知识分子
 臨著稱      临著称
 臨著者      临著者
 臨著述      临著述
-麗著 丽着
-麗著書      丽著书
-麗著作      丽著作
-麗著名      丽著名
-麗著錄      丽著录
-麗著稱      丽著称
-麗著者      丽著者
-麗著述      丽著述
 樂著 乐着
 樂著書      乐著书
 樂著作      乐著作
 樂著稱      乐著称
 樂著者      乐著者
 樂著述      乐著述
+樂著《      乐著《
 乘著 乘着
 乘著書      乘著书
 乘著作      乘著作
 亮著称      亮著称
 亮著者      亮著者
 亮著述      亮著述
+亮著《      亮著《
 仗著 仗着
 仗著書      仗著书
 仗著作      仗著作
 信著称      信著称
 信著者      信著者
 信著述      信著述
+信著《      信著《
 候著 候着
 候著書      候著书
 候著作      候著作
 光著称      光著称
 光著者      光著者
 光著述      光著述
+光著《      光著《
 關著 关着
 關著書      关著书
 關著作      关著作
 印著稱      印著称
 印著者      印著者
 印著述      印著述
+印著《      印著《
 壓著 压着
 壓著書      压著书
 壓著作      压著作
 定著称      定著称
 定著者      定著者
 定著述      定著述
+定著《      定著《
 對著 对着
 對著書      对著书
 對著作      对著作
 展著稱      展著称
 展著者      展著者
 展著述      展著述
+展著《      展著《
 帶著 带着
 帶著書      带著书
 帶著作      带著作
 心著称      心著称
 心著者      心著者
 心著述      心著述
+心著《      心著《
 忍著 忍着
 忍著書      忍著书
 忍著作      忍著作
 懷著稱      怀著称
 懷著者      怀著者
 懷著述      怀著述
+懷著《      怀著《
 急著 急着
 急著書      急著书
 急著作      急著作
 夢著稱      梦著称
 夢著者      梦著者
 夢著述      梦著述
+夢著《      梦著《
 梳著 梳着
 梳著作      梳著作
 梳著名      梳著名
 憑著者      凭著者
 三十六著   三十六着
 走為上著   走为上着
+機率 几率
+乙個 一个
+乙隻 一只
+乙份 一份
 記憶體      内存
 乙太網      以太网
 點陣圖      位图
@@ -2551,11 +2559,11 @@ IP位址        IP地址
 空中巴士   空中客车
 電視劇集   电视剧
 狂牛症      疯牛病
+瘋牛症      疯牛病
 結他 吉他
 了結他      了结他
 連結他      连结他
 鏈結 链接
-已開發國家        发达国家
 太空飛行員        宇航员
 太空衣      宇航服
 外部連結   外部链接
@@ -2715,3 +2723,5 @@ A型肝炎        甲型肝炎
 道瓊 道琼斯
 聖佐治      圣乔治
 格瑞那丁   格林纳丁斯
+普立茲獎   普利策奖
+富比士      福布斯
index 93acb33..4bc445b 100644 (file)
 來著 來着
 樂著 樂着
 努力著      努力着
-麗著 麗着
 連著 連着
 戀著 戀着
 涼著 涼着
 定著称      定著稱
 定著錄      定著錄
 定著書      定著書
+定著《      定著《
 動著作      動著作
 動著者      動著者
 動著名      動著名
 光著称      光著稱
 光著錄      光著錄
 光著書      光著書
+光著《      光著《
 跪著作      跪著作
 跪著者      跪著者
 跪著名      跪著名
 懷著稱      懷著稱
 懷著錄      懷著錄
 懷著書      懷著書
+懷著《      懷著《
 晃著作      晃著作
 晃著者      晃著者
 晃著名      晃著名
 樂著稱      樂著稱
 樂著錄      樂著錄
 樂著書      樂著書
+樂著《      樂著《
 努力著作   努力著作
 努力著者   努力著者
 努力著名   努力著名
 努力著称   努力著稱
 努力著錄   努力著錄
 努力著書   努力著書
-麗著作      麗著作
-麗著者      麗著者
-麗著名      麗著名
-麗著述      麗著述
-麗著稱      麗著稱
-麗著錄      麗著錄
-麗著書      麗著書
 連著作      連著作
 連著者      連著者
 連著名      連著名
 亮著称      亮著稱
 亮著錄      亮著錄
 亮著書      亮著書
+亮著《      亮著《
 臨著作      臨著作
 臨著者      臨著者
 臨著名      臨著名
 夢著稱      夢著稱
 夢著錄      夢著錄
 夢著書      夢著書
+夢著《      夢著《
 蒙著作      蒙著作
 蒙著者      蒙著者
 蒙著名      蒙著名
 心著称      心著稱
 心著錄      心著錄
 心著書      心著書
+心著《      心著《
 信著作      信著作
 信著者      信著者
 信著名      信著名
 信著称      信著稱
 信著錄      信著錄
 信著書      信著書
+信著《      信著《
 行著作      行著作
 行著者      行著者
 行著名      行著名
 印著稱      印著稱
 印著錄      印著錄
 印著書      印著書
+印著《      印著《
 應著作      應著作
 應著者      應著者
 應著名      應著名
 展著稱      展著稱
 展著錄      展著錄
 展著書      展著書
+展著《      展著《
 站著作      站著作
 站著者      站著者
 站著名      站著名
 厄瓜多尔   厄瓜多爾
 厄瓜多爾   厄瓜多爾
 厄瓜多      厄瓜多爾
+百慕大      百慕達
 厄利垂亞   厄立特里亞
 吉布地      吉布堤
 哥斯大黎加        哥斯達黎加
@@ -3078,3 +3081,7 @@ IP地址  IP位址
 圣乔治      聖佐治
 聖喬治      聖佐治
 格瑞那丁   格林納丁斯
+空中客车   空中巴士
+疯牛病      瘋牛症
+狂牛症      瘋牛症
+普利策奖   普立茲獎
index aacec98..4adbbcf 100644 (file)
 情蒐 情搜
 蘋果 苹果
 蘋婆 苹婆
+鄭蘋如      郑苹如
 於之莹      於之莹
 陆徵祥      陆徵祥
 瞭臺 瞭台
index dd8e5d0..bf24176 100644 (file)
 着眼于      著眼於
 桃金娘      桃金孃
 粘膜 黏膜
+几率 機率
 缺省 預設
 以太网      乙太網
 光盘 光碟
 唐纳德·特朗普   唐納·川普
 當勞·特朗普      唐納·川普
 當奴·特朗普      唐納·川普
-æ¦\82ç\8e\87 æ©\9fç\8e\87
\96¯牛症      狂牛症
+ç\96¯ç\89\9bç\97\85      ç\8b\82ç\89\9bç\97\87
\98\8b牛症      狂牛症
 甲肝 A肝
 甲型肝炎   A型肝炎
 乙肝 B肝
@@ -661,7 +662,6 @@ IP地址    IP位址
 獨立國家聯合體  獨立國家國協
 东南亚国家联盟  東南亞國家協會
 東南亞國家聯盟  東南亞國家協會
-发达国家   已開發國家
 哥特式      哥德式
 落車 下車
 上落客      上下客
@@ -821,3 +821,5 @@ IP地址    IP位址
 聖佐治      聖喬治
 格林纳丁斯        格瑞那丁
 格林納丁斯        格瑞那丁
+空中客车   空中巴士
+普利策奖   普立茲獎
index a3565b8..871f1ef 100644 (file)
@@ -91,8 +91,6 @@
 古語云      古語云
 經有云      經有云
 語有云      語有云
-采納 採納
-風采 風采
 于樂 于樂
 于軍 于軍
 于堅 于堅
 于國治      于國治
 于楓 于楓
 黎吉雲      黎吉雲
-于飛 于飛
+鳳凰于飛   鳳凰于飛
 鄉愿 鄉愿
 愿樸 愿樸
 謹愿 謹愿
 苹果 蘋果
 苹果干      蘋果乾
 苹婆 蘋婆
+郑苹如      鄭蘋如
 昵称 暱稱
 單于 單于
 鮮于 鮮于
 單向 單向
 轉向 轉向 #分詞用
 十出頭      十出頭
+更钟情      更鍾情
+更钟爱      更鍾愛
+更钟意      更鍾意
index 8d09901..5ff1d63 100644 (file)
@@ -206,6 +206,7 @@ U+05DBD嶽|U+05CB3岳|
 U+05DD6巖|U+05CA9岩|
 U+05DD7巗|U+05CA9岩|
 U+05DD8巘|U+2AA58𪩘|
+U+05DE0巠|U+22016𢀖|
 U+05DF5巵|U+0536E卮|
 U+05E00帀|U+0531D匝|
 U+05E0B帋|U+07EB8纸|
index 24d8a42..4a480ab 100644 (file)
 採運
 採風
 採血
+採編
 花不要採
 官地為寀
 寮寀
 標籤
 書籤
 發籤
-粉籤子
 路籤
-更籤
-好籤
 火籤
 籤幐
 籤押
 照入籤
-制籤
 抽公籤
 瑤籤
 藥籤
 巴而朮
 朮虎高
 耶律朮烈
+朮忽
 髼鬆
 皮鬆
 濛鬆雨
 石英鐘錶
 鐘律
 看鐘
-看錶
-看表面
 鐵鐘
 鐘不敲不響
 對準鐘
 科斗
 斗牛星
 斗法會
+抓斗
 小几
 尸利
 尸祿
 裏白 #植物常用名
 烏蘇里 #分詞用
 夸脫
-風采
 代碼表
 編碼表
 字碼表
 葉叶琹
 胡子昂
 胡子嬰
-包括
 特别致
 分别致
 韶山沖
 于氏
 于娜
 于娟
-于山
 于帥
 于慧
 于振
 于靖
 于勒
 于格
-于飛
+鳳凰于飛
 于仁泰
 于會泳
 于偉國
 李志喜
 于欣
 于少保
-于海
-於海洋
-於海邊
-於海上
-於海拔
-於海平面
-於山東
-於山西
 于凌辰
 于魁智
 于鬯
 於震前
 於震後
 於震中
-由於 #分詞用
 固定制
 划船
 划不來
diff --git a/maintenance/manageForeignResources.php b/maintenance/manageForeignResources.php
new file mode 100644 (file)
index 0000000..54554b8
--- /dev/null
@@ -0,0 +1,86 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+require_once __DIR__ . '/Maintenance.php';
+
+/**
+ * Manage foreign resources registered with ResourceLoader.
+ *
+ * @ingroup Maintenance
+ * @since 1.32
+ */
+class ManageForeignResources extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->addDescription( <<<TEXT
+Manage foreign resources registered with ResourceLoader.
+
+This helps developers with downloading, verifying, and updating local copies of upstream
+libraries registered as ResourceLoader modules. See resources/lib/foreign-resources.yaml.
+
+Use the "update" action to download urls specified in foreign-resources.yaml, and unpack
+them to the resources directory. This will also verify them against the integrity hashes.
+
+Use the "verify" action to verify the files currently in the resources directory match
+what "update" would replace them with. This is effectively a dry-run and will not change
+any module resources on disk.
+
+Use the "make-sri" action to compute an integrity hash for upstreams that do not publish
+one themselves. Add or update the urls foreign-resources.yaml as needed, but omit (or
+leave empty) the "integrity" key. Then, run the "make-sri" action for the module and
+copy the integrity into the file. Then, you can use "verify" or "update" normally.
+TEXT
+               );
+               $this->addArg( 'action', 'One of "update", "verify" or "make-sri"', true );
+               $this->addArg( 'module', 'Name of a single module (Default: all)', false );
+               $this->addOption( 'verbose', 'Be verbose', false, false, 'v' );
+       }
+
+       /**
+        * @return bool
+        * @throws Exception
+        */
+       public function execute() {
+               global $IP;
+               $frm = new ForeignResourceManager(
+                        "{$IP}/resources/lib/foreign-resources.yaml",
+                        "{$IP}/resources/lib",
+                       function ( $text ) {
+                               $this->output( $text );
+                       },
+                       function ( $text ) {
+                               $this->error( $text );
+                       },
+                       function ( $text ) {
+                               if ( $this->hasOption( 'verbose' ) ) {
+                                       $this->output( $text );
+                               }
+                       }
+               );
+
+               $action = $this->getArg( 0 );
+               $module = $this->getArg( 1, 'all' );
+               return $frm->run( $action, $module );
+       }
+}
+
+$maintClass = ManageForeignResources::class;
+require_once RUN_MAINTENANCE_IF_MAIN;
index c976bd7..98f0eb9 100644 (file)
@@ -50,8 +50,8 @@ class McTest extends Maintenance {
                                $this->fatalError( "MediaWiki isn't configured with a cache named '$cache'" );
                        }
                        $servers = $wgObjectCaches[$cache]['servers'];
-               } elseif ( $this->hasArg() ) {
-                       $servers = [ $this->getArg() ];
+               } elseif ( $this->hasArg( 0 ) ) {
+                       $servers = [ $this->getArg( 0 ) ];
                } elseif ( $wgMainCacheType === CACHE_MEMCACHED ) {
                        global $wgMemCachedServers;
                        $servers = $wgMemCachedServers;
diff --git a/maintenance/mediawiki.Title/generateJsToUpperCaseList.js b/maintenance/mediawiki.Title/generateJsToUpperCaseList.js
new file mode 100644 (file)
index 0000000..0104ec2
--- /dev/null
@@ -0,0 +1,9 @@
+/* eslint-env node, es6 */
+var i, chars = [];
+
+for ( i = 0; i <= 0x10ffff; i++ ) {
+       // eslint-disable-next-line no-restricted-properties
+       chars.push( String.fromCodePoint( i ).toUpperCase() );
+}
+// eslint-disable-next-line no-console
+console.log( JSON.stringify( chars ) );
diff --git a/maintenance/mediawiki.Title/generatePhpCharToUpperMappings.php b/maintenance/mediawiki.Title/generatePhpCharToUpperMappings.php
new file mode 100755 (executable)
index 0000000..5dd9432
--- /dev/null
@@ -0,0 +1,87 @@
+<?php
+
+/**
+ * Update list of upper case differences between JS and PHP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+use MediaWiki\Shell\Shell;
+
+require_once __DIR__ . '/../Maintenance.php';
+
+/**
+ * Update list of upper case differences between JS and PHP
+ *
+ * @ingroup Maintenance
+ * @since 1.33
+ */
+class GeneratePhpCharToUpperMappings extends Maintenance {
+
+       public function __construct() {
+               parent::__construct();
+               $this->addDescription( 'Update list of upper case differences between JS and PHP.' );
+       }
+
+       public function execute() {
+               global $wgContLang, $IP;
+
+               $data = [];
+
+               $result = Shell::command(
+                               [ 'node', $IP . '/maintenance/mediawiki.Title/generateJsToUpperCaseList.js' ]
+                       )
+                       // Node allocates lots of memory
+                       ->limits( [ 'memory' => 1024 * 1024 ] )
+                       ->execute();
+
+               if ( $result->getExitcode() !== 0 ) {
+                       $this->output( $result->getStderr() );
+                       return;
+               }
+
+               $jsUpperChars = json_decode( $result->getStdout() );
+
+               for ( $i = 0; $i <= 0x10ffff; $i++ ) {
+                       if ( $i >= 0xd800 && $i <= 0xdfff ) {
+                               // Skip surrogate pairs
+                               continue;
+                       }
+                       $char = \UtfNormal\Utils::codepointToUtf8( $i );
+                       $phpUpper = $wgContLang->ucfirst( $char );
+                       $jsUpper = $jsUpperChars[$i];
+                       if ( $jsUpper !== $phpUpper ) {
+                               $data[$char] = $phpUpper;
+                       }
+               }
+
+               $mappingJson = str_replace( '    ', "\t",
+                       json_encode( $data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE )
+               ) . "\n";
+               $outputPath = '/resources/src/mediawiki.Title/phpCharToUpper.json';
+               $file = fopen( $IP . $outputPath, 'w' );
+               fwrite( $file, $mappingJson );
+
+               $this->output( count( $data ) . " differences found.\n" );
+               $this->output( "Written to $outputPath\n" );
+       }
+}
+
+$maintClass = GeneratePhpCharToUpperMappings::class;
+require_once RUN_MAINTENANCE_IF_MAIN;
index 9c20c67..47828e6 100644 (file)
@@ -65,8 +65,8 @@ class MoveBatch extends Maintenance {
                $reason = $this->getOption( 'r', '' );
                $interval = $this->getOption( 'i', 0 );
                $noredirects = $this->hasOption( 'noredirects' );
-               if ( $this->hasArg() ) {
-                       $file = fopen( $this->getArg(), 'r' );
+               if ( $this->hasArg( 0 ) ) {
+                       $file = fopen( $this->getArg( 0 ), 'r' );
                } else {
                        $file = $this->getStdin();
                }
index 2d6a0be..791b360 100644 (file)
@@ -33,6 +33,8 @@
  * @version first release
  */
 
+use MediaWiki\Shell\Shell;
+
 require_once __DIR__ . '/Maintenance.php';
 
 /**
@@ -88,7 +90,7 @@ class MWDocGen extends Maintenance {
 
                // Do not use wfShellWikiCmd, because mwdoc-filter.php is not
                // a Maintenance script.
-               $this->inputFilter = wfEscapeShellArg( [
+               $this->inputFilter = Shell::escape( [
                        $wgPhpCli,
                        $IP . '/maintenance/mwdoc-filter.php'
                ] );
index 34a6cb6..c1e403c 100644 (file)
@@ -137,9 +137,7 @@ class MysqlMaintenance extends Maintenance {
                } elseif ( substr_count( $realServer, ':' ) == 1 ) {
                        // If we have a colon and something that's not a port number
                        // inside the hostname, assume it's the socket location
-                       $hostAndSocket = explode( ':', $realServer, 2 );
-                       $realServer = $hostAndSocket[0];
-                       $socket = $hostAndSocket[1];
+                       list( $realServer, $socket ) = explode( ':', $realServer, 2 );
                }
 
                if ( $dbName === false ) {
index 075d6f2..3c73306 100644 (file)
@@ -117,7 +117,10 @@ class NamespaceDupes extends Maintenance {
                }
 
                // Now pull in all canonical and alias namespaces...
-               foreach ( MWNamespace::getCanonicalNamespaces() as $ns => $name ) {
+               foreach (
+                       MediaWikiServices::getInstance()->getNamespaceInfo()->getCanonicalNamespaces()
+                       as $ns => $name
+               ) {
                        // This includes $wgExtraNamespaces
                        if ( $name !== '' ) {
                                $spaces[$name] = $ns;
@@ -429,7 +432,10 @@ class NamespaceDupes extends Maintenance {
         * @return ResultWrapper
         */
        private function getTargetList( $ns, $name, $options ) {
-               if ( $options['move-talk'] && MWNamespace::isSubject( $ns ) ) {
+               if (
+                       $options['move-talk'] &&
+                       MediaWikiServices::getInstance()->getNamespaceInfo()->isSubject( $ns )
+               ) {
                        $checkNamespaces = [ NS_MAIN, NS_TALK ];
                } else {
                        $checkNamespaces = NS_MAIN;
@@ -465,9 +471,10 @@ class NamespaceDupes extends Maintenance {
                        $dbk = "$name-" . $dbk;
                }
                $destNS = $ns;
-               if ( $sourceNs == NS_TALK && MWNamespace::isSubject( $ns ) ) {
+               $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
+               if ( $sourceNs == NS_TALK && $nsInfo->isSubject( $ns ) ) {
                        // This is an associated talk page moved with the --move-talk feature.
-                       $destNS = MWNamespace::getTalk( $destNS );
+                       $destNS = $nsInfo->getTalk( $destNS );
                }
                $newTitle = Title::makeTitleSafe( $destNS, $dbk );
                if ( !$newTitle || !$newTitle->canExist() ) {
index baead94..ba0fe5d 100644 (file)
@@ -39,7 +39,7 @@ class NukePage extends Maintenance {
        }
 
        public function execute() {
-               $name = $this->getArg();
+               $name = $this->getArg( 0 );
                $delete = $this->hasOption( 'delete' );
 
                $dbw = $this->getDB( DB_MASTER );
index 10d37de..6a5654f 100644 (file)
@@ -32,7 +32,7 @@ class PageExists extends Maintenance {
        }
 
        public function execute() {
-               $titleArg = $this->getArg();
+               $titleArg = $this->getArg( 0 );
                $title = Title::newFromText( $titleArg );
                $pageExists = $title && $title->exists();
 
index ec2eff4..96fcebf 100644 (file)
@@ -110,7 +110,7 @@ class PopulateArchiveRevId extends LoggedUpdateMaintenance {
                $ok = false;
                while ( !$ok ) {
                        try {
-                               $dbw->doAtomicSection( __METHOD__, function ( $dbw, $fname ) {
+                               $dbw->doAtomicSection( __METHOD__, function ( IDatabase $dbw, $fname ) {
                                        $dbw->insert( 'revision', self::$dummyRev, $fname );
                                        $id = $dbw->insertId();
                                        $toDelete[] = $id;
@@ -147,7 +147,7 @@ class PopulateArchiveRevId extends LoggedUpdateMaintenance {
                        self::$dummyRev = self::makeDummyRevisionRow( $dbw );
                }
 
-               $updates = $dbw->doAtomicSection( __METHOD__, function ( $dbw, $fname ) use ( $arIds ) {
+               $updates = $dbw->doAtomicSection( __METHOD__, function ( IDatabase $dbw, $fname ) use ( $arIds ) {
                        // Create new rev_ids by inserting dummy rows into revision and then deleting them.
                        $dbw->insert( 'revision', array_fill( 0, count( $arIds ), self::$dummyRev ), $fname );
                        $revIds = $dbw->selectFieldValues(
index 212a20d..a71abb6 100644 (file)
@@ -21,6 +21,8 @@
  * @ingroup Maintenance
  */
 
+use MediaWiki\Shell\Shell;
+
 require_once __DIR__ . '/Maintenance.php';
 
 /**
@@ -107,9 +109,9 @@ class PopulateImageSha1 extends LoggedUpdateMaintenance {
                        // in the pipe buffer. This can improve performance by up to a
                        // factor of 2.
                        global $wgDBuser, $wgDBserver, $wgDBpassword, $wgDBname;
-                       $cmd = 'mysql -u' . wfEscapeShellArg( $wgDBuser ) .
-                               ' -h' . wfEscapeShellArg( $wgDBserver ) .
-                               ' -p' . wfEscapeShellArg( $wgDBpassword, $wgDBname );
+                       $cmd = 'mysql -u' . Shell::escape( $wgDBuser ) .
+                               ' -h' . Shell::escape( $wgDBserver ) .
+                               ' -p' . Shell::escape( $wgDBpassword, $wgDBname );
                        $this->output( "Using pipe method\n" );
                        $pipe = popen( $cmd, 'w' );
                }
index acc66c5..a654a1f 100644 (file)
@@ -86,7 +86,7 @@ TEXT
                        $url = rtrim( $this->source, '?' ) . '?' . $url;
                }
 
-               $json = Http::get( $url );
+               $json = MediaWikiServices::getInstance()->getHttpRequestFactory()->get( $url );
                $data = json_decode( $json, true );
 
                if ( is_array( $data ) ) {
index 1ba7054..591fbd4 100644 (file)
@@ -93,6 +93,7 @@ class PopulatePPSortKey extends LoggedUpdateMaintenance {
                }
 
                $this->output( "Populating page_props.pp_sortkey complete.\n" );
+               return true;
        }
 
        protected function getUpdateKey() {
index 75904d0..a62e019 100644 (file)
@@ -58,7 +58,7 @@ class PreprocessDump extends DumpIterator {
        }
 
        public function checkOptions() {
-               global $wgParser, $wgParserConf, $wgPreprocessorCacheThreshold;
+               global $wgParserConf, $wgPreprocessorCacheThreshold;
 
                if ( !$this->hasOption( 'cache' ) ) {
                        $wgPreprocessorCacheThreshold = false;
@@ -72,7 +72,7 @@ class PreprocessDump extends DumpIterator {
                        $name = Preprocessor_DOM::class;
                }
 
-               $wgParser->firstCallInit();
+               MediaWikiServices::getInstance()->getParser()->firstCallInit();
                $this->mPreprocessor = new $name( $this );
        }
 
index d5d27ad..e57e977 100644 (file)
@@ -195,7 +195,7 @@ class PPFuzzTest {
        }
 
        function execute() {
-               global $wgParser, $wgUser;
+               global $wgUser;
 
                $wgUser = new PPFuzzUser;
                $wgUser->mName = 'Fuzz';
@@ -206,7 +206,7 @@ class PPFuzzTest {
                $options->setTemplateCallback( [ $this, 'templateHook' ] );
                $options->setTimestamp( wfTimestampNow() );
                $this->output = call_user_func(
-                       [ $wgParser, $this->entryPoint ],
+                       [ MediaWikiServices::getInstance()->getParser(), $this->entryPoint ],
                        $this->mainText,
                        $this->title,
                        $options
@@ -239,7 +239,7 @@ class PPFuzzTest {
 class PPFuzzUser extends User {
        public $ppfz_test, $mDataLoaded;
 
-       function load() {
+       function load( $flags = null ) {
                if ( $this->mDataLoaded ) {
                        return;
                }
index e2c1a8b..1603ab0 100644 (file)
@@ -62,7 +62,7 @@ class Protect extends Maintenance {
                        $this->fatalError( "Invalid username" );
                }
 
-               $t = Title::newFromText( $this->getArg() );
+               $t = Title::newFromText( $this->getArg( 0 ) );
                if ( !$t ) {
                        $this->fatalError( "Invalid title" );
                }
index 0ef2a99..81fb5e3 100644 (file)
@@ -170,23 +170,31 @@ class PurgeChangedPages extends Maintenance {
         */
        protected function pageableSortedRows( ResultWrapper $res, $column, $limit ) {
                $rows = iterator_to_array( $res, false );
-               $count = count( $rows );
-               if ( !$count ) {
-                       return [ [], null ]; // nothing to do
-               } elseif ( $count < $limit ) {
-                       return [ $rows, $rows[$count - 1]->$column ]; // no more rows left
+
+               // Nothing to do
+               if ( !$rows ) {
+                       return [ [], null ];
+               }
+
+               $lastValue = end( $rows )->$column;
+               if ( count( $rows ) < $limit ) {
+                       return [ $rows, $lastValue ];
                }
-               $lastValue = $rows[$count - 1]->$column; // should be the highest
-               for ( $i = $count - 1; $i >= 0; --$i ) {
-                       if ( $rows[$i]->$column === $lastValue ) {
-                               unset( $rows[$i] );
-                       } else {
+
+               for ( $i = count( $rows ) - 1; $i >= 0; --$i ) {
+                       if ( $rows[$i]->$column !== $lastValue ) {
                                break;
                        }
+
+                       unset( $rows[$i] );
+               }
+
+               // No more rows left
+               if ( !$rows ) {
+                       return [ [], null ];
                }
-               $lastValueLeft = count( $rows ) ? $rows[count( $rows ) - 1]->$column : null;
 
-               return [ $rows, $lastValueLeft ];
+               return [ $rows, end( $rows )->$column ];
        }
 }
 
index cf398ff..2cdf418 100644 (file)
@@ -21,6 +21,8 @@
  * @ingroup Maintenance
  */
 
+use MediaWiki\MediaWikiServices;
+
 require_once __DIR__ . '/Maintenance.php';
 
 /**
@@ -102,7 +104,8 @@ class RebuildFileCache extends Maintenance {
                        // Get the pages
                        $res = $dbr->select( 'page',
                                [ 'page_namespace', 'page_title', 'page_id' ],
-                               [ 'page_namespace' => MWNamespace::getContentNamespaces(),
+                               [ 'page_namespace' => MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                       getContentNamespaces(),
                                        "page_id BETWEEN " . (int)$blockStart . " AND " . (int)$blockEnd ],
                                __METHOD__,
                                [ 'ORDER BY' => 'page_id ASC', 'USE INDEX' => 'PRIMARY' ]
index ec68ef2..bee8d69 100644 (file)
@@ -21,6 +21,7 @@ class RemoveInvalidEmails extends Maintenance {
                $this->addOption( 'commit', 'Whether to actually update the database', false, false );
                $this->setBatchSize( 500 );
        }
+
        public function execute() {
                $this->commit = $this->hasOption( 'commit' );
                $dbr = $this->getDB( DB_REPLICA );
diff --git a/maintenance/resources/foreign-resources.yaml b/maintenance/resources/foreign-resources.yaml
deleted file mode 100644 (file)
index 37768cc..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-### Format of this file
-#
-# The top-level keys are directory names (under resources/lib/).
-# They should match module names (as registered in Resources.php), but there are exceptions.
-# Each top-level key holds a resource descriptor that must have one of
-# the following `type` values:
-#
-# - `tar`: For tarball archive (may be gzip-compressed).
-# - `file: For a plain file.
-# - `multi-file`: For multiple plain files.
-#
-### Type tar
-#
-# The `src` and `integrity` keys are required.
-#
-# * `src`: Full URL to the remote resource.
-# * `integrity`: Cryptographic hash (integrity metadata format per <https://www.w3.org/TR/SRI/>).
-# * `dest`: An object mapping paths to files or directory from the remote resource to a destination
-#    in the module directory. The value of key in dest may be omitted, which will extract the key
-#    directly to the module directory.
-#
-### Type file
-#
-# The `src` and `integrity` keys are required.
-#
-# * `src`: Full URL to the remote resource.
-# * `integrity`: Cryptographic hash (integrity metadata format per <https://www.w3.org/TR/SRI/>).
-# * `dest`: The name of the file in the module directory. Default: Basename of URL.
-#
-### Type multi-file
-#
-# The `files` key is required.
-#
-# * `files`: An object mapping destination paths to an object containing `src` and `integrity`
-#    keys.
-
-CLDRPluralRuleParser:
-  type: file
-  src: https://raw.githubusercontent.com/santhoshtr/CLDRPluralRuleParser/0dda851/src/CLDRPluralRuleParser.js
-  integrity: sha384-M4taeYYG2+9Ob1/La16iO+zlRRmBV5lBR3xUKkQT6kfkJ0aLbCi6yc0RYI1BDzdh
-
-easy-deflate:
-  type: multi-file
-  files:
-    deflate.js:
-      src: https://raw.githubusercontent.com/edg2s/Easy-Deflate/7a6056e5302f6f385ff2efa60afda45b4ad81e51/deflate.js
-      integrity: sha384-sHnZLDSWMUhA2w9ygkzCK8YFvoh/fQKY6lXMbvmrYzjuNURiLB0DZFCDNMpGyZ77
-    easydeflate.js:
-      src: https://raw.githubusercontent.com/edg2s/Easy-Deflate/7a6056e5302f6f385ff2efa60afda45b4ad81e51/easydeflate.js
-      integrity: sha384-EwPfP2RMkDPa1HkzQsXgzTsy1KEjcIzQPA1HDS/JPHjvEMvVUsCxWwm1oXql/jk2
-    inflate.js:
-      src: https://raw.githubusercontent.com/edg2s/Easy-Deflate/7a6056e5302f6f385ff2efa60afda45b4ad81e51/inflate.js
-      integrity: sha384-hMg44Hw424mUYvmzKl0JT4J8UU/1YYhTiGRtR0YX/MXNLK9qWTK0d62FBCDGxmxw
-    README.md:
-      src: https://raw.githubusercontent.com/edg2s/Easy-Deflate/7a6056e5302f6f385ff2efa60afda45b4ad81e51/README.md
-      integrity: sha384-6kwcfCLivvqXBZy2ATyya+mTVWLk3eaQyBdC6tbpBtkygnBrM2SNkq3jz/l7IkvP
-
-html5shiv:
-  type: file
-  src: https://raw.githubusercontent.com/aFarkas/html5shiv/3.7.3/src/html5shiv.js
-  integrity: sha384-RPXhaTf22QktT8KTwZ6bUz/C+7CnccaIw5W/y/t0FW5WSDGj3wc3YtRIJC0w47in
-
-jquery:
-  type: file
-  src: https://code.jquery.com/jquery-3.3.1.js
-  # Integrity from link modals https://code.jquery.com/jquery/
-  integrity: sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60=
-  dest: jquery.js
-
-jquery.client:
-  type: tar
-  src: https://registry.npmjs.org/jquery-client/-/jquery-client-2.0.2.tgz
-  integrity: sha256-8c8nBbBykHEMc4I7ksdKJvvw/P7WkaC2X46RTPdz/pw=
-  dest:
-    package/AUTHORS.txt:
-    package/jquery.client.js:
-    package/LICENSE-MIT:
-    package/README.md:
-
-jquery.cookie:
-  type: multi-file
-  files:
-    jquery.cookie.js:
-      src: https://raw.githubusercontent.com/carhartl/jquery-cookie/v1.3.1/jquery.cookie.js
-      integrity: sha384-Xxq63E9KDgzUJ6WPNPqVeOtRIwZyx6y9DzEwY2u6LYKSnWrjSoGtWSKmTindYBf2
-    MIT-LICENSE.txt:
-      src: https://raw.githubusercontent.com/carhartl/jquery-cookie/v1.3.1/MIT-LICENSE.txt
-      integrity: sha384-zYsGf3KJ7S0AhOICjcoh0kkn7aGZlzYUXXX5xz8dwR9KjLMM+/JPR2g/jVOGGeId
-    CHANGELOG.md:
-      src: https://raw.githubusercontent.com/carhartl/jquery-cookie/v1.3.1/CHANGELOG.md
-      integrity: sha384-SQOHhLc7PHxHDQpGE/zv9XfXKL0A7OBu8kuyVDnHVp+zSoWyRw4xUJ+LSm5ql4kS
-
-moment:
-  type: tar
-  src: https://codeload.github.com/moment/moment/tar.gz/2.24.0
-  integrity: sha384-2/I9rfqkN8AAgh5wOXXphuo827uV7lMmOodrCfIvqC6W6JKKiDGOwd+lE3e8R0yz
-  dest:
-    moment-2.24.0/moment.js:
-    moment-2.24.0/CHANGELOG.md:
-    moment-2.24.0/README.md:
-    moment-2.24.0/LICENSE:
-    moment-2.24.0/locale/*.js: locale
-
-mustache:
-  type: multi-file
-  files:
-    mustache.js:
-      src: https://raw.githubusercontent.com/janl/mustache.js/v1.0.0/mustache.js
-      integrity: sha384-k2UYqmzoiq/qgIzZvcYBxbXQW4YdPAsXDOTkHTGb9TCZ9sjCkyT4TlaUN0wQRkql
-    LICENSE:
-      src: https://raw.githubusercontent.com/janl/mustache.js/v1.0.0/LICENSE
-      integrity: sha384-MYVwXwula9+YkyXexOJVZ0v0DaVvG22uX57mNq5Di+7u8OH9EG9q3yuXkp1Iehiq
-
-oojs:
-  type: tar
-  src: https://registry.npmjs.org/oojs/-/oojs-2.2.2.tgz
-  integrity: sha256-ebgQW2EGrSkBCnDJBGqDpsBDjA3PMN/M8U5DyLHt9mw=
-  dest:
-    package/dist/oojs.jquery.js:
-    package/AUTHORS.txt:
-    package/LICENSE-MIT:
-    package/README.md:
-
-oojs-router:
-  type: tar
-  src: https://registry.npmjs.org/oojs-router/-/oojs-router-0.2.0.tgz
-  integrity: sha384-VngYqdQ3vTDMXbm4e4FUZCCGos7fB0Jkr9V+kBL5MElprK1h0yQZOzBNnMHtSJS/
-  dest:
-    package/dist/oojs-router.js:
-    package/LICENSE:
-    package/AUTHORS.txt:
-    package/History.md:
-
-ooui:
-  type: tar
-  src: https://registry.npmjs.org/oojs-ui/-/oojs-ui-0.31.0.tgz
-  integrity: sha384-kmMOvTjLZbr0Nd1iiV61KSDevnZffuY0jpr7Wjoo61HrJY53b9SacjQqebcNzTEK
-  dest:
-    # Main stuff
-    package/dist/oojs-ui-core.js{,.map.json}:
-    package/dist/oojs-ui-core-{wikimediaui,apex}.css:
-    package/dist/oojs-ui-widgets.js{,.map.json}:
-    package/dist/oojs-ui-widgets-{wikimediaui,apex}.css:
-    package/dist/oojs-ui-toolbars.js{,.map.json}:
-    package/dist/oojs-ui-toolbars-{wikimediaui,apex}.css:
-    package/dist/oojs-ui-windows.js{,.map.json}:
-    package/dist/oojs-ui-windows-{wikimediaui,apex}.css:
-    package/dist/oojs-ui-{wikimediaui,apex}.js{,.map.json}:
-    package/dist/i18n:
-    package/dist/images:
-    # WikimediaUI theme
-    package/dist/themes/wikimediaui/images/icons/*.{svg,png}: themes/wikimediaui/images/icons
-    package/dist/themes/wikimediaui/images/indicators/*.{svg,png}: themes/wikimediaui/images/indicators
-    package/dist/themes/wikimediaui/images/textures/*.{gif,svg}: themes/wikimediaui/images/textures
-    package/src/themes/wikimediaui/*.json: themes/wikimediaui
-    package/dist/wikimedia-ui-base.less:
-    # Apex theme (icons, indicators, and textures)
-    package/src/themes/apex/*.json: themes/apex
-    # Misc stuff
-    package/dist/AUTHORS.txt:
-    package/dist/History.md:
-    package/dist/LICENSE-MIT:
-    package/dist/README.md:
-
-qunitjs:
-  type: multi-file
-  # Integrity from link modals at https://code.jquery.com/qunit/
-  files:
-    qunit.js:
-      src: http://code.jquery.com/qunit/qunit-2.9.1.js
-      integrity: sha256-eNccBdxd8zReziWcVjEsPeyJDi3LKMYnzMXyDv8bzsU=
-    qunit.css:
-      src: https://code.jquery.com/qunit/qunit-2.9.1.css
-      integrity: sha256-SSS7o92V7wzcIFg3qnJL9mc4msePaT4klbxtuSGvVVo=
-
-sinonjs:
-  type: file
-  src: https://sinonjs.org/releases/sinon-1.17.7.js
-  integrity: sha384-wR63Jwy75KqwBfzCmXd6gYws6uj3qV/XMAybzXrkEYGYG3AQ58ZWwr1fVpkHa5e8
-  dest: sinon.js
diff --git a/maintenance/resources/manageForeignResources.php b/maintenance/resources/manageForeignResources.php
deleted file mode 100644 (file)
index 6de82c0..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Maintenance
- */
-
-require_once __DIR__ . '/../Maintenance.php';
-
-/**
- * Manage foreign resources registered with ResourceLoader.
- *
- * @ingroup Maintenance
- * @since 1.32
- */
-class ManageForeignResources extends Maintenance {
-       public function __construct() {
-               parent::__construct();
-               $this->addDescription( <<<TEXT
-Manage foreign resources registered with ResourceLoader.
-
-This helps developers to download, verify and update local copies of upstream
-libraries registered as ResourceLoader modules. See also foreign-resources.yaml.
-
-For sources that don't publish an integrity hash, omit "integrity" (or leave empty)
-and run the "make-sri" action to compute the missing hashes.
-
-This script runs in dry-run mode by default. Use --update to actually change,
-remove, or add files to resources/lib/.
-TEXT
-               );
-               $this->addArg( 'action', 'One of "update", "verify" or "make-sri"', true );
-               $this->addArg( 'module', 'Name of a single module (Default: all)', false );
-               $this->addOption( 'verbose', 'Be verbose', false, false, 'v' );
-       }
-
-       /**
-        * @return bool
-        * @throws Exception
-        */
-       public function execute() {
-               global $IP;
-               $frm = new ForeignResourceManager(
-                        __DIR__ . '/foreign-resources.yaml',
-                        "{$IP}/resources/lib",
-                       function ( $text ) {
-                               $this->output( $text );
-                       },
-                       function ( $text ) {
-                               $this->error( $text );
-                       },
-                       function ( $text ) {
-                               if ( $this->hasOption( 'verbose' ) ) {
-                                       $this->output( $text );
-                               }
-                       }
-               );
-
-               $action = $this->getArg( 0 );
-               $module = $this->getArg( 1, 'all' );
-               return $frm->run( $action, $module );
-       }
-}
-
-$maintClass = ManageForeignResources::class;
-require_once RUN_MAINTENANCE_IF_MAIN;
index 9f5f1af..9354e4f 100644 (file)
  * @ingroup Maintenance
  */
 
+if ( !defined( 'MEDIAWIKI' ) ) {
+       // So extensions (and other code) can check whether they're running in job mode.
+       // This is not defined if this script is included from installer/updater or phpunit.
+       define( 'MEDIAWIKI_JOB_RUNNER', true );
+}
+
 require_once __DIR__ . '/Maintenance.php';
 
 use MediaWiki\Logger\LoggerFactory;
 
-// So extensions (and other code) can check whether they're running in job mode
-define( 'MEDIAWIKI_JOB_RUNNER', true );
-
 /**
  * Maintenance script that runs pending jobs.
  *
@@ -100,7 +103,7 @@ class RunJobs extends Maintenance {
                                $response['reached'] === 'memory-limit'
                        ) {
                                // If job queue is empty, output it
-                               if ( $response['jobs'] === [] ) {
+                               if ( !$outputJSON && $response['jobs'] === [] ) {
                                        $this->output( "Job queue is empty.\n" );
                                }
                                break;
index a95789d..173d741 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 use MediaWiki\MediaWikiServices;
+use MediaWiki\Shell\Shell;
 
 if ( !defined( 'MEDIAWIKI' ) ) {
        $optionsWithoutArgs = [ 'fix' ];
@@ -55,6 +56,8 @@ class CheckStorage {
        ];
 
        function check( $fix = false, $xml = '' ) {
+               global $wgMultiContentRevisionSchemaMigrationStage;
+
                $dbr = wfGetDB( DB_REPLICA );
                if ( $fix ) {
                        print "Checking, will fix errors if possible...\n";
@@ -78,33 +81,59 @@ class CheckStorage {
                        $chunkEnd = $chunkStart + $chunkSize - 1;
                        // print "$chunkStart of $maxRevId\n";
 
-                       // Fetch revision rows
                        $this->oldIdMap = [];
                        $dbr->ping();
-                       $res = $dbr->select( 'revision', [ 'rev_id', 'rev_text_id' ],
-                               [ "rev_id BETWEEN $chunkStart AND $chunkEnd" ], __METHOD__ );
-                       foreach ( $res as $row ) {
-                               $this->oldIdMap[$row->rev_id] = $row->rev_text_id;
+
+                       // Fetch revision rows
+                       if ( $wgMultiContentRevisionSchemaMigrationStage & SCHEMA_COMPAT_READ_OLD ) {
+                               $res = $dbr->select( 'revision', [ 'rev_id', 'rev_text_id' ],
+                                       [ "rev_id BETWEEN $chunkStart AND $chunkEnd" ], __METHOD__ );
+                               foreach ( $res as $row ) {
+                                       if ( !isset( $this->oldIdMap[ $row->rev_text_id ] ) ) {
+                                               $this->oldIdMap[ $row->rev_text_id ] = [ $row->rev_id ];
+                                       } elseif ( !in_array( $row->rev_id, $this->oldIdMap[ $row->rev_text_id ] ) ) {
+                                               $this->oldIdMap[ $row->rev_text_id ][] = $row->rev_id;
+                                       }
+                               }
+                       } else {
+                               $res = $dbr->select(
+                                       [ 'slots', 'content' ],
+                                       [ 'slot_revision_id', 'content_address' ],
+                                       [ "slot_revision_id BETWEEN $chunkStart AND $chunkEnd" ],
+                                       __METHOD__,
+                                       [],
+                                       [ 'content' => [ 'INNER JOIN', [ 'content_id = slot_content_id' ] ] ]
+                               );
+                               $blobStore = MediaWikiServices::getInstance()->getBlobStore();
+                               foreach ( $res as $row ) {
+                                       $textId = $blobStore->getTextIdFromAddress( $row->content_address );
+                                       if ( $textId ) {
+                                               if ( !isset( $this->oldIdMap[$textId] ) ) {
+                                                       $this->oldIdMap[ $textId ] = [ $row->slot_revision_id ];
+                                               } elseif ( !in_array( $row->slot_revision_id, $this->oldIdMap[$textId] ) ) {
+                                                       $this->oldIdMap[ $textId ][] = $row->slot_revision_id;
+                                               }
+                                       }
+                               }
                        }
-                       $dbr->freeResult( $res );
 
                        if ( !count( $this->oldIdMap ) ) {
                                continue;
                        }
 
                        // Fetch old_flags
-                       $missingTextRows = array_flip( $this->oldIdMap );
+                       $missingTextRows = $this->oldIdMap;
                        $externalRevs = [];
                        $objectRevs = [];
                        $res = $dbr->select(
                                'text',
                                [ 'old_id', 'old_flags' ],
-                               [ 'old_id' => $this->oldIdMap ],
+                               [ 'old_id' => array_keys( $this->oldIdMap ) ],
                                __METHOD__
                        );
                        foreach ( $res as $row ) {
                                /**
-                                * @var $flags int
+                                * @var int $flags
                                 */
                                $flags = $row->old_flags;
                                $id = $row->old_id;
@@ -147,10 +176,9 @@ class CheckStorage {
                                        $this->addError( 'unfixable', "Error: invalid flags field \"$flags\"", $id );
                                }
                        }
-                       $dbr->freeResult( $res );
 
                        // Output errors for any missing text rows
-                       foreach ( $missingTextRows as $oldId => $revId ) {
+                       foreach ( $missingTextRows as $oldId => $revIds ) {
                                $this->addError( 'restore revision', "Error: missing text row", $oldId );
                        }
 
@@ -187,7 +215,6 @@ class CheckStorage {
                                                $externalNormalBlobs[$cluster][$id][] = $row->old_id;
                                        }
                                }
-                               $dbr->freeResult( $res );
                        }
 
                        // Check external concat blobs for the right header
@@ -210,7 +237,6 @@ class CheckStorage {
                                        foreach ( $res as $row ) {
                                                unset( $xBlobIds[$row->blob_id] );
                                        }
-                                       $extDb->freeResult( $res );
                                        // Print errors for missing blobs rows
                                        foreach ( $xBlobIds as $blobId => $oldId ) {
                                                $this->addError(
@@ -279,7 +305,6 @@ class CheckStorage {
                                                        $this->addError( 'unfixable', "Error: unrecognised object class \"$className\"", $oldId );
                                        }
                                }
-                               $dbr->freeResult( $res );
                        }
 
                        // Check local concat blob validity
@@ -333,7 +358,6 @@ class CheckStorage {
 
                                        unset( $concatBlobs[$row->old_id] );
                                }
-                               $dbr->freeResult( $res );
                        }
 
                        // Check targets of unresolved stubs
@@ -376,13 +400,13 @@ class CheckStorage {
                if ( is_array( $ids ) ) {
                        $revIds = [];
                        foreach ( $ids as $id ) {
-                               $revIds = array_merge( $revIds, array_keys( $this->oldIdMap, $id ) );
+                               $revIds = array_unique( array_merge( $revIds, $this->oldIdMap[$id] ) );
                        }
                        print "$msg in text rows " . implode( ', ', $ids ) .
                                ", revisions " . implode( ', ', $revIds ) . "\n";
                } else {
                        $id = $ids;
-                       $revIds = array_keys( $this->oldIdMap, $id );
+                       $revIds = $this->oldIdMap[$id];
                        if ( count( $revIds ) == 1 ) {
                                print "$msg in old_id $id, rev_id {$revIds[0]}\n";
                        } else {
@@ -421,7 +445,6 @@ class CheckStorage {
                                }
                                unset( $oldIds[$row->blob_id] );
                        }
-                       $extDb->freeResult( $res );
 
                        // Print errors for missing blobs rows
                        foreach ( $oldIds as $blobId => $oldIds2 ) {
@@ -458,7 +481,7 @@ class CheckStorage {
                echo "Filtering XML dump...\n";
                $exitStatus = 0;
                passthru( 'mwdumper ' .
-                       wfEscapeShellArg(
+                       Shell::escape(
                                "--output=file:$filteredXmlFileName",
                                "--filter=revlist:$revFileName",
                                $xml
index 8a1069e..d3e9ce2 100644 (file)
@@ -40,6 +40,8 @@
  * @file
  * @ingroup Maintenance ExternalStorage
  */
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Revision\SlotRecord;
 
 require_once __DIR__ . '/../Maintenance.php';
 
@@ -49,16 +51,6 @@ require_once __DIR__ . '/../Maintenance.php';
  * @ingroup Maintenance ExternalStorage
  */
 class CompressOld extends Maintenance {
-       /**
-        * Option to load each revision individually.
-        */
-       const LS_INDIVIDUAL = 0;
-
-       /**
-        * Option to load revisions in chunks.
-        */
-       const LS_CHUNKED = 1;
-
        public function __construct() {
                parent::__construct();
                $this->addDescription( 'Compress the text of a wiki' );
@@ -104,7 +96,7 @@ class CompressOld extends Maintenance {
                global $wgDBname;
                if ( !function_exists( "gzdeflate" ) ) {
                        $this->fatalError( "You must enable zlib support in PHP to compress old revisions!\n" .
-                               "Please see https://secure.php.net/manual/en/ref.zlib.php\n" );
+                               "Please see https://www.php.net/manual/en/ref.zlib.php\n" );
                }
 
                $type = $this->getOption( 'type', 'concat' );
@@ -233,7 +225,7 @@ class CompressOld extends Maintenance {
        private function compressWithConcat( $startId, $maxChunkSize, $beginDate,
                $endDate, $extdb = "", $maxPageId = false
        ) {
-               $loadStyle = self::LS_CHUNKED;
+               global $wgMultiContentRevisionSchemaMigrationStage;
 
                $dbr = $this->getDB( DB_REPLICA );
                $dbw = $this->getDB( DB_MASTER );
@@ -288,17 +280,25 @@ class CompressOld extends Maintenance {
                        }
                        $conds[] = "rev_timestamp<'" . $endDate . "'";
                }
-               if ( $loadStyle == self::LS_CHUNKED ) {
+
+               if ( $wgMultiContentRevisionSchemaMigrationStage & SCHEMA_COMPAT_READ_OLD ) {
                        $tables = [ 'revision', 'text' ];
-                       $fields = [ 'rev_id', 'rev_text_id', 'old_flags', 'old_text' ];
                        $conds[] = 'rev_text_id=old_id';
-                       $revLoadOptions = 'FOR UPDATE';
                } else {
-                       $tables = [ 'revision' ];
-                       $fields = [ 'rev_id', 'rev_text_id' ];
-                       $revLoadOptions = [];
+                       $slotRoleStore = MediaWikiServices::getInstance()->getSlotRoleStore();
+                       $tables = [ 'revision', 'slots', 'content', 'text' ];
+                       $conds = array_merge( [
+                               'rev_id=slot_revision_id',
+                               'slot_role_id=' . $slotRoleStore->getId( SlotRecord::MAIN ),
+                               'content_id=slot_content_id',
+                               'SUBSTRING(content_address, 1, 3)=' . $dbr->addQuotes( 'tt:' ),
+                               'SUBSTRING(content_address, 4)=old_id',
+                       ], $conds );
                }
 
+               $fields = [ 'rev_id', 'old_id', 'old_flags', 'old_text' ];
+               $revLoadOptions = 'FOR UPDATE';
+
                # Don't work with current revisions
                # Don't lock the page table for update either -- TS 2006-04-04
                # $tables[] = 'page';
@@ -359,24 +359,14 @@ class CompressOld extends Maintenance {
                                $stubs = [];
                                $this->beginTransaction( $dbw, __METHOD__ );
                                $usedChunk = false;
-                               $primaryOldid = $revs[$i]->rev_text_id;
+                               $primaryOldid = $revs[$i]->old_id;
 
                                # Get the text of each revision and add it to the object
                                for ( $j = 0; $j < $thisChunkSize && $chunk->isHappy(); $j++ ) {
-                                       $oldid = $revs[$i + $j]->rev_text_id;
+                                       $oldid = $revs[$i + $j]->old_id;
 
                                        # Get text
-                                       if ( $loadStyle == self::LS_INDIVIDUAL ) {
-                                               $textRow = $dbw->selectRow( 'text',
-                                                       [ 'old_flags', 'old_text' ],
-                                                       [ 'old_id' => $oldid ],
-                                                       __METHOD__,
-                                                       'FOR UPDATE'
-                                               );
-                                               $text = Revision::getRevisionText( $textRow );
-                                       } else {
-                                               $text = Revision::getRevisionText( $revs[$i + $j] );
-                                       }
+                                       $text = Revision::getRevisionText( $revs[$i + $j] );
 
                                        if ( $text === false ) {
                                                $this->error( "\nError, unable to get text in old_id $oldid" );
@@ -444,13 +434,13 @@ class CompressOld extends Maintenance {
                                                # Store the stub objects
                                                for ( $j = 1; $j < $thisChunkSize; $j++ ) {
                                                        # Skip if not compressing and don't overwrite the first revision
-                                                       if ( $stubs[$j] !== false && $revs[$i + $j]->rev_text_id != $primaryOldid ) {
+                                                       if ( $stubs[$j] !== false && $revs[$i + $j]->old_id != $primaryOldid ) {
                                                                $dbw->update( 'text',
                                                                        [ /* SET */
                                                                                'old_text' => serialize( $stubs[$j] ),
                                                                                'old_flags' => 'object,utf-8',
                                                                        ], [ /* WHERE */
-                                                                               'old_id' => $revs[$i + $j]->rev_text_id
+                                                                               'old_id' => $revs[$i + $j]->old_id
                                                                        ]
                                                                );
                                                        }
index b00db20..7d9883e 100644 (file)
@@ -39,7 +39,7 @@ class DumpRev extends Maintenance {
        }
 
        public function execute() {
-               $id = (int)$this->getArg();
+               $id = (int)$this->getArg( 0 );
 
                $lookup = MediaWikiServices::getInstance()->getRevisionLookup();
                $rev = $lookup->getRevisionById( $id );
index 7f36442..f17b00c 100644 (file)
@@ -24,6 +24,7 @@
 
 use MediaWiki\Logger\LegacyLogger;
 use MediaWiki\MediaWikiServices;
+use MediaWiki\Shell\Shell;
 use Wikimedia\Rdbms\IDatabase;
 
 $optionsWithArgs = RecompressTracked::getOptionsWithArgs();
@@ -215,19 +216,19 @@ class RecompressTracked {
         * writing are all slow.
         */
        function startReplicaProcs() {
-               $cmd = 'php ' . wfEscapeShellArg( __FILE__ );
+               $cmd = 'php ' . Shell::escape( __FILE__ );
                foreach ( self::$cmdLineOptionMap as $cmdOption => $classOption ) {
                        if ( $cmdOption == 'replica-id' ) {
                                continue;
                        } elseif ( in_array( $cmdOption, self::$optionsWithArgs ) && isset( $this->$classOption ) ) {
-                               $cmd .= " --$cmdOption " . wfEscapeShellArg( $this->$classOption );
+                               $cmd .= " --$cmdOption " . Shell::escape( $this->$classOption );
                        } elseif ( $this->$classOption ) {
                                $cmd .= " --$cmdOption";
                        }
                }
                $cmd .= ' --child' .
-                       ' --wiki ' . wfEscapeShellArg( wfWikiID() ) .
-                       ' ' . wfEscapeShellArg( ...$this->destClusters );
+                       ' --wiki ' . Shell::escape( wfWikiID() ) .
+                       ' ' . Shell::escape( ...$this->destClusters );
 
                $this->replicaPipes = $this->replicaProcs = [];
                for ( $i = 0; $i < $this->numProcs; $i++ ) {
@@ -271,10 +272,11 @@ class RecompressTracked {
         * Dispatch a command to the next available replica DB.
         * This may block until a replica DB finishes its work and becomes available.
         */
-       function dispatch( /*...*/ ) {
-               $args = func_get_args();
+       function dispatch( ...$args ) {
                $pipes = $this->replicaPipes;
-               $numPipes = stream_select( $x = [], $pipes, $y = [], 3600 );
+               $x = [];
+               $y = [];
+               $numPipes = stream_select( $x, $pipes, $y, 3600 );
                if ( !$numPipes ) {
                        $this->critical( "Error waiting to write to replica DBs. Aborting" );
                        exit( 1 );
index 7cac728..fa5364d 100644 (file)
@@ -47,8 +47,8 @@ if ( isset( $options['limit'] ) ) {
 }
 $type = $options['type'] ?? ConcatenatedGzipHistoryBlob::class;
 
-$dbr = $this->getDB( DB_REPLICA );
-$revQuery = Revision::getQueryInfo( [ 'page', 'text' ] );
+$dbr = wfGetDB( DB_REPLICA );
+$revQuery = Revision::getQueryInfo( [ 'page' ] );
 $res = $dbr->select(
        $revQuery['tables'],
        $revQuery['fields'],
index 2dd48ca..385ae6a 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 use MediaWiki\MediaWikiServices;
+use MediaWiki\Revision\SlotRecord;
 use Wikimedia\Rdbms\DBConnectionError;
 
 require __DIR__ . '/../commandLine.inc';
@@ -130,6 +131,8 @@ class TrackBlobs {
         *  Scan the revision table for rows stored in the specified clusters
         */
        function trackRevisions() {
+               global $wgMultiContentRevisionSchemaMigrationStage;
+
                $dbw = wfGetDB( DB_MASTER );
                $dbr = wfGetDB( DB_REPLICA );
 
@@ -141,20 +144,40 @@ class TrackBlobs {
 
                echo "Finding revisions...\n";
 
+               $fields = [ 'rev_id', 'rev_page', 'old_id', 'old_flags', 'old_text' ];
+               $options = [
+                       'ORDER BY' => 'rev_id',
+                       'LIMIT' => $this->batchSize
+               ];
+               $conds = [
+                       $textClause,
+                       'old_flags ' . $dbr->buildLike( $dbr->anyString(), 'external', $dbr->anyString() ),
+               ];
+               if ( $wgMultiContentRevisionSchemaMigrationStage & SCHEMA_COMPAT_READ_OLD ) {
+                       $tables = [ 'revision', 'text' ];
+                       $conds = array_merge( [
+                               'rev_text_id=old_id',
+                       ], $conds );
+               } else {
+                       $slotRoleStore = MediaWikiServices::getInstance()->getSlotRoleStore();
+                       $tables = [ 'revision', 'slots', 'content', 'text' ];
+                       $conds = array_merge( [
+                               'rev_id=slot_revision_id',
+                               'slot_role_id=' . $slotRoleStore->getId( SlotRecord::MAIN ),
+                               'content_id=slot_content_id',
+                               'SUBSTRING(content_address, 1, 3)=' . $dbr->addQuotes( 'tt:' ),
+                               'SUBSTRING(content_address, 4)=old_id',
+                       ], $conds );
+               }
+
                while ( true ) {
-                       $res = $dbr->select( [ 'revision', 'text' ],
-                               [ 'rev_id', 'rev_page', 'old_id', 'old_flags', 'old_text' ],
-                               [
+                       $res = $dbr->select( $tables,
+                               $fields,
+                               array_merge( [
                                        'rev_id > ' . $dbr->addQuotes( $startId ),
-                                       'rev_text_id=old_id',
-                                       $textClause,
-                                       'old_flags ' . $dbr->buildLike( $dbr->anyString(), 'external', $dbr->anyString() ),
-                               ],
+                               ], $conds ),
                                __METHOD__,
-                               [
-                                       'ORDER BY' => 'rev_id',
-                                       'LIMIT' => $this->batchSize
-                               ]
+                               $options
                        );
                        if ( !$res->numRows() ) {
                                break;
index dac222f..0739666 100644 (file)
@@ -1683,7 +1683,7 @@ CREATE TABLE /*_*/job (
 
   -- Any other parameters to the command
   -- Stored as a PHP serialized array, or an empty string if there are no parameters
-  job_params blob NOT NULL,
+  job_params mediumblob NOT NULL,
 
   -- Random, non-unique, number used for job acquisition (for lock concurrency)
   job_random integer unsigned NOT NULL default 0,
index e9b2abd..144518e 100644 (file)
@@ -37,7 +37,7 @@ class Undelete extends Maintenance {
 
                $user = $this->getOption( 'user', false );
                $reason = $this->getOption( 'reason', '' );
-               $pageName = $this->getArg();
+               $pageName = $this->getArg( 0 );
 
                $title = Title::newFromText( $pageName );
                if ( !$title ) {
index 2a1feb4..b6c7ae4 100755 (executable)
@@ -64,7 +64,7 @@ class UpdateMediaWiki extends Maintenance {
        function compatChecks() {
                $minimumPcreVersion = Installer::MINIMUM_PCRE_VERSION;
 
-               list( $pcreVersion ) = explode( ' ', PCRE_VERSION, 2 );
+               $pcreVersion = explode( ' ', PCRE_VERSION, 2 )[0];
                if ( version_compare( $pcreVersion, $minimumPcreVersion, '<' ) ) {
                        $this->fatalError(
                                "PCRE $minimumPcreVersion or later is required.\n" .
@@ -242,6 +242,24 @@ class UpdateMediaWiki extends Maintenance {
                        'manualRecache' => false,
                ];
        }
+
+       public function validateParamsAndArgs() {
+               // Allow extensions to add additional params.
+               $params = [];
+               Hooks::run( 'MaintenanceUpdateAddParams', [ &$params ] );
+               foreach ( $params as $name => $param ) {
+                       $this->addOption(
+                               $name,
+                               $param['desc'],
+                               $param['require'] ?? false,
+                               $param['withArg'] ?? false,
+                               $param['shortName'] ?? false,
+                               $param['multiOccurrence'] ?? false
+                       );
+               }
+
+               parent::validateParamsAndArgs();
+       }
 }
 
 $maintClass = UpdateMediaWiki::class;
index ab40e48..ebace75 100644 (file)
@@ -26,6 +26,7 @@
 
 require_once __DIR__ . '/Maintenance.php';
 
+use MediaWiki\MediaWikiServices;
 use Wikimedia\Rdbms\IDatabase;
 
 /**
@@ -186,7 +187,8 @@ TEXT
                                }
                                # cl_type will be wrong for lots of pages if cl_collation is 0,
                                # so let's update it while we're here.
-                               $type = MWNamespace::getCategoryLinkType( $title->getNamespace() );
+                               $type = MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                       getCategoryLinkType( $title->getNamespace() );
                                $newSortKey = $collation->getSortKey(
                                        $title->getCategorySortkey( $prefix ) );
                                if ( $verboseStats ) {
index 0d6cfa2..a704d61 100644 (file)
@@ -11,6 +11,7 @@ class ValidateRegistrationFile extends Maintenance {
                        true
                );
        }
+
        public function execute() {
                $validator = new ExtensionJsonValidator( function ( $msg ) {
                        $this->fatalError( $msg );
index 24b5007..671369a 100644 (file)
@@ -36,7 +36,7 @@ class ViewCLI extends Maintenance {
        }
 
        public function execute() {
-               $title = Title::newFromText( $this->getArg() );
+               $title = Title::newFromText( $this->getArg( 0 ) );
                if ( !$title ) {
                        $this->fatalError( "Invalid title" );
                }
index ef9e46e..00046d3 100644 (file)
@@ -114,7 +114,7 @@ class WrapOldPasswords extends Maintenance {
 
                        // Clear memcached so old passwords are wiped out
                        foreach ( $updateUsers as $user ) {
-                               $user->clearSharedCache();
+                               $user->clearSharedCache( 'refresh' );
                        }
                } while ( $res->numRows() );
        }
index 511cd03..81cb92d 100644 (file)
@@ -2,6 +2,8 @@
  * Copy of CC standard stylesheet, plus tweaks for iframe usage
  */
 
+/* stylelint-disable selector-class-pattern */
+
 body {
        margin: 0;
        background: #eee;
index 1b2574d..8b3b39e 100644 (file)
@@ -1,3 +1,5 @@
+/* stylelint-disable selector-class-pattern */
+
 .env-check {
        font-size: 90%;
        margin: 1em 0 1em 2.5em;
index df3f6e5..b625c96 100644 (file)
@@ -63,7 +63,7 @@ function wfInstallerMain() {
                $session = array();
        }
 
-       if ( $request->getVal( 'uselang' ) !== null ) {
+       if ( $request->getCheck( 'uselang' ) ) {
                $langCode = $request->getVal( 'uselang' );
        } elseif ( isset( $session['settings']['_UserLang'] ) ) {
                $langCode = $session['settings']['_UserLang'];
index 6bcc98a..2556d5f 100644 (file)
     "selenium-test": "wdio ./tests/selenium/wdio.conf.js"
   },
   "devDependencies": {
-    "eslint-config-wikimedia": "0.11.0",
-    "grunt": "1.0.3",
-    "grunt-banana-checker": "0.6.0",
+    "eslint-config-wikimedia": "0.12.0",
+    "grunt": "1.0.4",
+    "grunt-banana-checker": "0.7.0",
     "grunt-contrib-copy": "1.0.0",
     "grunt-contrib-watch": "1.1.0",
     "grunt-eslint": "21.0.0",
-    "grunt-jsonlint": "1.1.0",
     "grunt-karma": "3.0.0",
     "grunt-stylelint": "0.10.1",
     "grunt-svgmin": "5.0.0",
+    "jpeg-js": "0.3.5",
     "karma": "3.1.4",
     "karma-chrome-launcher": "2.2.0",
     "karma-firefox-launcher": "1.1.0",
index d000972..dccdd38 100644 (file)
@@ -412,6 +412,7 @@ $filter = $_REQUEST['filter'] ?? '';
        $queries = [];
        $sqltotal = 0.0;
 
+       /** @var profile_point|false $last */
        $last = false;
        foreach ( $res as $o ) {
                $next = new profile_point( $o->pf_name, $o->pf_count, $o->pf_time, $o->pf_memory );
@@ -435,7 +436,7 @@ $filter = $_REQUEST['filter'] ?? '';
                }
        }
 
-       $s = new profile_point( 'SQL Queries', 0, $sqltotal, 0, 0 );
+       $s = new profile_point( 'SQL Queries', 0, $sqltotal, 0 );
        foreach ( $queries as $q ) {
                $s->add_child( $q );
        }
index 86bca6c..4c359ee 100644 (file)
@@ -27,12 +27,6 @@ if ( !defined( 'MEDIAWIKI' ) ) {
 global $wgResourceBasePath;
 
 return [
-
-       /**
-        * Special modules who have their own classes
-        */
-       'startup' => [ 'class' => ResourceLoaderStartUpModule::class ],
-
        // Scripts managed by the local wiki (stored in the MediaWiki namespace)
        'site' => [ 'class' => ResourceLoaderSiteModule::class ],
        'site.styles' => [ 'class' => ResourceLoaderSiteStylesModule::class ],
@@ -175,10 +169,6 @@ return [
                'messages' => [ 'brackets', 'word-separator' ],
                'targets' => [ 'mobile', 'desktop' ],
        ],
-       'jquery.async' => [
-               'scripts' => 'resources/lib/jquery.async.js',
-               'deprecated' => true,
-       ],
        'jquery.byteLength' => [
                'scripts' => 'resources/src/jquery/jquery.byteLength.js',
                'deprecated' => 'Use "mediawiki.String" instead.',
@@ -223,10 +213,10 @@ return [
                'targets' => [ 'desktop', 'mobile' ],
        ],
        'jquery.form' => [
-               'scripts' => 'resources/lib/jquery.form.js',
+               'scripts' => 'resources/lib/jquery.form/jquery.form.js',
        ],
        'jquery.fullscreen' => [
-               'scripts' => 'resources/lib/jquery.fullscreen.js',
+               'scripts' => 'resources/lib/jquery.fullscreen/jquery.fullscreen.js',
        ],
        'jquery.getAttrs' => [
                'scripts' => 'resources/src/jquery/jquery.getAttrs.js',
@@ -240,7 +230,7 @@ return [
                'targets' => [ 'desktop', 'mobile' ],
        ],
        'jquery.hoverIntent' => [
-               'scripts' => 'resources/lib/jquery.hoverIntent.js',
+               'scripts' => 'resources/lib/jquery.hoverIntent/jquery.hoverIntent.js',
        ],
        'jquery.i18n' => [
                'scripts' => [
@@ -294,12 +284,12 @@ return [
        ],
        'jquery.spinner' => [
                'scripts' => 'resources/src/jquery.spinner/spinner.js',
-               'styles' => 'resources/src/jquery.spinner/spinner.css',
+               'styles' => 'resources/src/jquery.spinner/spinner.less',
                'targets' => [ 'desktop', 'mobile' ],
        ],
        'jquery.jStorage' => [
                'deprecated' => 'Please use "mediawiki.storage" instead.',
-               'scripts' => 'resources/lib/jquery.jStorage.js',
+               'scripts' => 'resources/lib/jquery.jStorage/jstorage.js',
        ],
        'jquery.suggestions' => [
                'targets' => [ 'desktop', 'mobile' ],
@@ -332,7 +322,7 @@ return [
        'jquery.throttle-debounce' => [
                'deprecated' => 'Please use OO.ui.throttle/debounce instead. See '
                        . 'https://phabricator.wikimedia.org/T213426',
-               'scripts' => 'resources/lib/jquery.ba-throttle-debounce.js',
+               'scripts' => 'resources/lib/jquery.throttle-debounce/jquery.ba-throttle-debounce.js',
                'targets' => [ 'desktop', 'mobile' ],
        ],
 
@@ -591,18 +581,6 @@ return [
                ],
                'group' => 'jquery.ui',
        ],
-       'jquery.ui.spinner' => [
-               'scripts' => 'resources/lib/jquery.ui/jquery.ui.spinner.js',
-               'dependencies' => [
-                       'jquery.ui.core',
-                       'jquery.ui.widget',
-                       'jquery.ui.button',
-               ],
-               'skinStyles' => [
-                       'default' => 'resources/lib/jquery.ui/themes/smoothness/jquery.ui.spinner.css',
-               ],
-               'group' => 'jquery.ui',
-       ],
        'jquery.ui.tabs' => [
                'scripts' => 'resources/lib/jquery.ui/jquery.ui.tabs.js',
                'dependencies' => [
@@ -884,6 +862,7 @@ return [
        ],
        'mediawiki.content.json' => [
                'styles' => 'resources/src/mediawiki.content.json.less',
+               'targets' => [ 'desktop', 'mobile' ],
        ],
        'mediawiki.confirmCloseWindow' => [
                'scripts' => [
@@ -1135,9 +1114,11 @@ return [
                'targets' => [ 'desktop', 'mobile' ],
        ],
        'mediawiki.Title' => [
-               'scripts' => [
-                       'resources/src/mediawiki.Title/Title.js',
-                       'resources/src/mediawiki.Title/phpCharToUpper.js',
+               'localBasePath' => "$IP/resources/src/mediawiki.Title",
+               'remoteBasePath' => "$wgResourceBasePath/resources/src/mediawiki.Title",
+               'packageFiles' => [
+                       'Title.js',
+                       'phpCharToUpper.json'
                ],
                'dependencies' => [
                        'mediawiki.String',
@@ -1335,9 +1316,11 @@ return [
                'targets' => [ 'desktop', 'mobile' ],
        ],
        'mediawiki.checkboxtoggle' => [
+               'targets' => [ 'desktop', 'mobile' ],
                'scripts' => 'resources/src/mediawiki.checkboxtoggle.js',
        ],
        'mediawiki.checkboxtoggle.styles' => [
+               'targets' => [ 'desktop', 'mobile' ],
                'styles' => 'resources/src/mediawiki.checkboxtoggle.styles.css',
        ],
        'mediawiki.cookie' => [
@@ -1449,11 +1432,16 @@ return [
                ],
        ],
        'mediawiki.action.history' => [
+               'dependencies' => [ 'jquery.makeCollapsible' ],
                'scripts' => 'resources/src/mediawiki.action/mediawiki.action.history.js',
                'styles' => 'resources/src/mediawiki.action/mediawiki.action.history.css',
+               'targets' => [ 'desktop', 'mobile' ]
        ],
        'mediawiki.action.history.styles' => [
-               'styles' => 'resources/src/mediawiki.action/mediawiki.action.history.styles.css',
+               'skinStyles' => [
+                       'default' => 'resources/src/mediawiki.action/mediawiki.action.history.styles.less',
+               ],
+               'targets' => [ 'desktop', 'mobile' ],
        ],
        'mediawiki.action.view.dblClickEdit' => [
                'scripts' => 'resources/src/mediawiki.action/mediawiki.action.view.dblClickEdit.js',
@@ -1505,6 +1493,7 @@ return [
                'scripts' => 'resources/src/mediawiki.action/mediawiki.action.view.rightClickEdit.js',
        ],
        'mediawiki.action.edit.editWarning' => [
+               'targets' => [ 'desktop', 'mobile' ],
                'scripts' => 'resources/src/mediawiki.action/mediawiki.action.edit.editWarning.js',
                'dependencies' => [
                        'jquery.textSelection',
@@ -1690,7 +1679,7 @@ return [
        ],
        'mediawiki.page.gallery.styles' => [
                'styles' => [
-                       'resources/src/mediawiki.page.gallery.styles/gallery.css',
+                       'resources/src/mediawiki.page.gallery.styles/gallery.less',
                        'resources/src/mediawiki.page.gallery.styles/print.css' => [ 'media' => 'print' ],
                ],
                'targets' => [ 'desktop', 'mobile' ],
@@ -1715,8 +1704,14 @@ return [
                'dependencies' => [
                        'jquery.accessKeyLabel',
                        'jquery.checkboxShiftClick',
+                       'mediawiki.notify',
+                       'mediawiki.api'
                ],
                'targets' => [ 'desktop', 'mobile' ],
+               'messages' => [
+                       'logout-failed',
+                       'logging-out-notify'
+               ]
        ],
        'mediawiki.page.startup' => [
                'scripts' => 'resources/src/mediawiki.page.startup.js',
@@ -1763,17 +1758,15 @@ return [
                        'removedwatchtext-talk',
                ],
        ],
-       'mediawiki.page.rollback' => [
-               'scripts' => 'resources/src/mediawiki.page.rollback.js',
+       'mediawiki.page.rollback.confirmation' => [
+               'scripts' => 'resources/src/mediawiki.rollback.confirmation.js',
                'dependencies' => [
-                       'mediawiki.api',
-                       'mediawiki.notify',
-                       'mediawiki.util',
-                       'jquery.spinner',
+                       'jquery.confirmable'
                ],
                'messages' => [
-                       'rollbackfailed',
-                       'actioncomplete',
+                       'rollback-confirmation-confirm',
+                       'rollback-confirmation-yes',
+                       'rollback-confirmation-no',
                ],
        ],
        'mediawiki.page.image.pagination' => [
@@ -1787,14 +1780,16 @@ return [
        /* MediaWiki Special pages */
 
        'mediawiki.rcfilters.filters.base.styles' => [
-               'styles' => [
-                       'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less',
+               'skinStyles' => [
+                       'default' => 'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less',
                ],
        ],
        'mediawiki.rcfilters.highlightCircles.seenunseen.styles' => [
-               'styles' => [
-                       'resources/src/mediawiki.rcfilters/' .
-                       'styles/mw.rcfilters.ui.ChangesListWrapperWidget.highlightCircles.seenunseen.less',
+               'skinStyles' => [
+                       'default' => [
+                               'resources/src/mediawiki.rcfilters/' .
+                               'styles/mw.rcfilters.ui.ChangesListWrapperWidget.highlightCircles.seenunseen.less',
+                       ],
                ],
        ],
        'mediawiki.rcfilters.filters.dm' => [
@@ -2012,8 +2007,8 @@ return [
                        'parentheses-end',
                        'pipe-separator'
                ],
-               'styles' => [
-                       'resources/src/mediawiki.interface.helpers.styles.less',
+               'skinStyles' => [
+                       'default' => 'resources/src/mediawiki.interface.helpers.styles.less',
                ],
                'targets' => [
                        'desktop', 'mobile'
@@ -2109,7 +2104,15 @@ return [
                ],
        ],
        'mediawiki.special.block' => [
-               'scripts' => 'resources/src/mediawiki.special.block.js',
+               'localBasePath' => "$IP/resources/src",
+               'remoteBasePath' => "$wgResourceBasePath/resources/src",
+               'packageFiles' => [
+                       'mediawiki.special.block.js',
+                       [ 'name' => 'config.json', 'config' => [
+                               'EnablePartialBlocks',
+                               'BlockAllowsUTEdit',
+                       ] ],
+               ],
                'dependencies' => [
                        'oojs-ui-core',
                        'oojs-ui.styles.icons-editing-core',
@@ -2125,6 +2128,10 @@ return [
                ],
                'targets' => [ 'desktop', 'mobile' ],
        ],
+       'mediawiki.special.blocklist' => [
+               'styles' => 'resources/src/mediawiki.special/blocklist.less',
+               'targets' => [ 'desktop', 'mobile' ],
+       ],
        'mediawiki.special.changecredentials.js' => [
                'scripts' => 'resources/src/mediawiki.special.changecredentials.js',
                'dependencies' => [
@@ -2135,7 +2142,10 @@ return [
        ],
        'mediawiki.special.changeslist' => [
                'styles' => [
-                       'resources/src/mediawiki.special.changeslist.less',
+                       'resources/src/mediawiki.special.changeslist/changeslist.less'
+               ],
+               'skinStyles' => [
+                       'default' => 'resources/src/mediawiki.special.changeslist/default.less',
                ],
                'targets' => [ 'desktop', 'mobile' ],
        ],
@@ -2508,6 +2518,7 @@ return [
                        'oojs-ui-widgets',
                        'mediawiki.widgets.styles',
                        // TitleInputWidget
+                       'oojs-ui.styles.icons-content',
                        'mediawiki.Title',
                        'mediawiki.api',
                        'mediawiki.String',
diff --git a/resources/lib/foreign-resources.yaml b/resources/lib/foreign-resources.yaml
new file mode 100644 (file)
index 0000000..4609c04
--- /dev/null
@@ -0,0 +1,275 @@
+# ## Format of this file
+#
+# The top-level keys in this file correspond with directories under resources/lib/.
+# These in turn are registered as module bundles in Resources.php.
+#
+# ## How to install an foreign resource
+#
+# 1. Add or update the url(s) for the upstream module to this YAML file.
+#
+#    Look at other modules for examples. To install a module from npm,
+#    we use the tarball distribution from npmjs.org. This is the same as what
+#    the npm CLI uses. For example, to install jquery-client@9.2.0, use:
+#    <https://registry.npmjs.org/jquery-client/-/jquery-client-9.2.0.tgz>.
+#
+# 2. If the upstream maintainers publish an integrity hash, set that as well.
+#    Otherwise, use manageForeignResources.php to compute the integrity hash.
+#
+#    Run `php manageForeignResources.php make-sri "my module name"`
+#
+#    This will download the specified file(s) and print their integrity hashes,
+#    already formatted in YAML, ready for copying to this file.
+#
+# 3. Last but not least, decide where files go.
+#
+#    If you specified a direct url to JavaScript or CSS file, this step is
+#    optional. See the corresponding documentation section below for more
+#    information and examples for "dest" keys. Once you've set any "dest" keys,
+#    run `php manageForeignResources.php update "my module name"`.
+#
+# ## Package formats
+#
+# Each top-level key must use one of these types:
+#
+# - `file`: For a plain file.
+# - `multi-file`: For multiple plain files.
+# - `tar`: For a tarball archive (may be compressed).
+#
+# ### The "file" type
+#
+# * `src`: Full URL to the remote resource.
+# * `integrity`: Cryptographic hash (integrity metadata format per <https://www.w3.org/TR/SRI/>).
+# * `dest`: [optional] The file name to use in the module directory. Default: Basename of URL.
+#
+# For example, the following would produce resources/lib/mymodule/x.js:
+#
+#     mymodule:
+#       type: file
+#       src: https://mymodule.example/1.2.3/x.js
+#       integrity: sha384-Je+NE+saisQuoi
+#
+# ### The "multi-file" type
+#
+# * `files`: An object mapping destination paths to `src` and `integrity` keys.
+#
+# For example:
+#
+#     mymodule:
+#       type: multi-file
+#       files:
+#         x.js:
+#           src: https://mymodule.example/1.2.3/x.js
+#           integrity: sha384-Je+NE+saisQuoi
+#         x.css:
+#           src: https://mymodule.example/1.2.3/x.css
+#           integrity: sha384-Je+NE+saisQuoi
+#
+# ### The "tar" type
+#
+# * `src`: Full URL to the remote resource.
+# * `integrity`: Cryptographic hash (integrity metadata format per <https://www.w3.org/TR/SRI/>).
+# * `dest`: [optional] The default is to extract all files from the package.
+#    To only extract some of the files or directories, use "dest" to specify
+#    files, directories, and/or glob patterns. You can use a site like https://unpkg.com/
+#    to easily inspect an npm package, like <https://unpkg.com/jquery-client@2.0.2/>.
+#
+# For example:
+#
+#     mymodule:
+#       type: tar
+#       src: https://registry.npmjs.org/jquery-client/-/jquery-client-9.2.0.tgz
+#       integrity: sha384-Je+NE+saisQuoi
+#       dest:
+#         package/dist/x.js:
+#         package/dist/i18n:
+#         package/dist/style/*.css:
+#
+# The would extract the "x.js" file, the "i18n" directory (recursive),
+# and any "*.css" files from the "style" directory.
+#
+
+CLDRPluralRuleParser:
+  type: file
+  src: https://raw.githubusercontent.com/santhoshtr/CLDRPluralRuleParser/0dda851/src/CLDRPluralRuleParser.js
+  integrity: sha384-M4taeYYG2+9Ob1/La16iO+zlRRmBV5lBR3xUKkQT6kfkJ0aLbCi6yc0RYI1BDzdh
+
+easy-deflate:
+  type: multi-file
+  files:
+    deflate.js:
+      src: https://raw.githubusercontent.com/edg2s/Easy-Deflate/7a6056e5302f6f385ff2efa60afda45b4ad81e51/deflate.js
+      integrity: sha384-sHnZLDSWMUhA2w9ygkzCK8YFvoh/fQKY6lXMbvmrYzjuNURiLB0DZFCDNMpGyZ77
+    easydeflate.js:
+      src: https://raw.githubusercontent.com/edg2s/Easy-Deflate/7a6056e5302f6f385ff2efa60afda45b4ad81e51/easydeflate.js
+      integrity: sha384-EwPfP2RMkDPa1HkzQsXgzTsy1KEjcIzQPA1HDS/JPHjvEMvVUsCxWwm1oXql/jk2
+    inflate.js:
+      src: https://raw.githubusercontent.com/edg2s/Easy-Deflate/7a6056e5302f6f385ff2efa60afda45b4ad81e51/inflate.js
+      integrity: sha384-hMg44Hw424mUYvmzKl0JT4J8UU/1YYhTiGRtR0YX/MXNLK9qWTK0d62FBCDGxmxw
+    README.md:
+      src: https://raw.githubusercontent.com/edg2s/Easy-Deflate/7a6056e5302f6f385ff2efa60afda45b4ad81e51/README.md
+      integrity: sha384-6kwcfCLivvqXBZy2ATyya+mTVWLk3eaQyBdC6tbpBtkygnBrM2SNkq3jz/l7IkvP
+
+html5shiv:
+  type: file
+  src: https://raw.githubusercontent.com/aFarkas/html5shiv/3.7.3/src/html5shiv.js
+  integrity: sha384-RPXhaTf22QktT8KTwZ6bUz/C+7CnccaIw5W/y/t0FW5WSDGj3wc3YtRIJC0w47in
+
+jquery:
+  type: file
+  src: https://code.jquery.com/jquery-3.3.1.js
+  # Integrity from link modals https://code.jquery.com/jquery/
+  integrity: sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60=
+  dest: jquery.js
+
+# TODO: jquery.chosen
+
+jquery.client:
+  type: tar
+  src: https://registry.npmjs.org/jquery-client/-/jquery-client-2.0.2.tgz
+  integrity: sha256-8c8nBbBykHEMc4I7ksdKJvvw/P7WkaC2X46RTPdz/pw=
+  dest:
+    package/AUTHORS.txt:
+    package/jquery.client.js:
+    package/LICENSE-MIT:
+    package/README.md:
+
+jquery.cookie:
+  type: multi-file
+  files:
+    jquery.cookie.js:
+      src: https://raw.githubusercontent.com/carhartl/jquery-cookie/v1.3.1/jquery.cookie.js
+      integrity: sha384-Xxq63E9KDgzUJ6WPNPqVeOtRIwZyx6y9DzEwY2u6LYKSnWrjSoGtWSKmTindYBf2
+    MIT-LICENSE.txt:
+      src: https://raw.githubusercontent.com/carhartl/jquery-cookie/v1.3.1/MIT-LICENSE.txt
+      integrity: sha384-zYsGf3KJ7S0AhOICjcoh0kkn7aGZlzYUXXX5xz8dwR9KjLMM+/JPR2g/jVOGGeId
+    CHANGELOG.md:
+      src: https://raw.githubusercontent.com/carhartl/jquery-cookie/v1.3.1/CHANGELOG.md
+      integrity: sha384-SQOHhLc7PHxHDQpGE/zv9XfXKL0A7OBu8kuyVDnHVp+zSoWyRw4xUJ+LSm5ql4kS
+
+jquery.form:
+  type: file
+  src: https://raw.githubusercontent.com/jquery-form/form/ff80d9ddf4/jquery.form.js
+  integrity: sha384-h4G2CrcSbixzMvrrK259cNBYaL/vS1D4+KdUN9NJDzQnTU1bQ6Avluget+Id13M7
+
+jquery.fullscreen:
+  type: file
+  src: https://raw.githubusercontent.com/theopolisme/jquery-fullscreen/v2.1.0/jquery.fullscreen.js
+  integrity: sha384-G4KPs2d99tgcsyUnJ3eeZ1r2hEKDwZfc4+/xowL/LIemq2VVwEE8HpVAWt4WYNLR
+
+jquery.hoverIntent:
+  type: file
+  src: https://raw.githubusercontent.com/briancherne/jquery-hoverIntent/823603fdac/jquery.hoverIntent.js
+  integrity: sha384-lca0haN0hqFGGh2aYUhtAgX9dhVHfQnTADH4svDeM6gcXnL7aFGeAi1NYwipDMyS
+
+jquery.i18n:
+  type: tar
+  src: https://codeload.github.com/wikimedia/jquery.i18n/tar.gz/v1.0.5
+  integrity: sha384-bkmmKC2byOVjTg4di3o6sSISU49JwXynV9gNGH2zl4U9nh8vZJiauiIvoWgvhwsK
+  dest:
+    jquery.i18n-1.0.5/CODE_OF_CONDUCT.md:
+    jquery.i18n-1.0.5/CREDITS:
+    jquery.i18n-1.0.5/GPL-LICENSE:
+    jquery.i18n-1.0.5/MIT-LICENSE:
+    jquery.i18n-1.0.5/README.md:
+    jquery.i18n-1.0.5/src:
+
+jquery.jStorage:
+  type: file
+  src: https://raw.githubusercontent.com/andris9/jStorage/v0.4.12/jstorage.js
+  integrity: sha384-geMeN8k803kPp6cqRL4VNfuSM1L8DcbKRk0St/KHJzxgpX9S0y9FA6HxA/JgucrJ
+
+jquery.throttle-debounce:
+  type: file
+  src: https://raw.githubusercontent.com/cowboy/jquery-throttle-debounce/v1.1/jquery.ba-throttle-debounce.js
+  integrity: sha384-ULOy4DbAghrCqRcrTJLXOY9e4gDpWh0BeEf6xMSL0VtNudXWggcb6AmrVrl4KDAP
+
+# TODO: jquery.ui (!)
+
+moment:
+  type: tar
+  src: https://codeload.github.com/moment/moment/tar.gz/2.24.0
+  integrity: sha384-2/I9rfqkN8AAgh5wOXXphuo827uV7lMmOodrCfIvqC6W6JKKiDGOwd+lE3e8R0yz
+  dest:
+    moment-2.24.0/moment.js:
+    moment-2.24.0/CHANGELOG.md:
+    moment-2.24.0/README.md:
+    moment-2.24.0/LICENSE:
+    moment-2.24.0/locale/*.js: locale
+
+mustache:
+  type: multi-file
+  files:
+    mustache.js:
+      src: https://raw.githubusercontent.com/janl/mustache.js/v3.0.1/mustache.js
+      integrity: sha384-YjAj6Nll7fkEWzxTlE9o3NWC9qdZt1Upat6Afjib9eLs8lTODpSKEBHeXq8o/VUH
+    LICENSE:
+      src: https://raw.githubusercontent.com/janl/mustache.js/v3.0.1/LICENSE
+      integrity: sha384-j2EDj6YtCRgFvYDtzo6pXzbskIj/K1Yg65BL0j3/L6UIHxbMtRMJwC/W+XoYx0FZ
+
+oojs:
+  type: tar
+  src: https://registry.npmjs.org/oojs/-/oojs-2.2.2.tgz
+  integrity: sha256-ebgQW2EGrSkBCnDJBGqDpsBDjA3PMN/M8U5DyLHt9mw=
+  dest:
+    package/dist/oojs.jquery.js:
+    package/AUTHORS.txt:
+    package/LICENSE-MIT:
+    package/README.md:
+
+oojs-router:
+  type: tar
+  src: https://registry.npmjs.org/oojs-router/-/oojs-router-0.2.0.tgz
+  integrity: sha384-VngYqdQ3vTDMXbm4e4FUZCCGos7fB0Jkr9V+kBL5MElprK1h0yQZOzBNnMHtSJS/
+  dest:
+    package/dist/oojs-router.js:
+    package/LICENSE:
+    package/AUTHORS.txt:
+    package/History.md:
+
+ooui:
+  type: tar
+  src: https://registry.npmjs.org/oojs-ui/-/oojs-ui-0.31.6.tgz
+  integrity: sha384-zixZ5PrOMXEo9x3/Y6++IJGbOPYEUpDjCjCsXhiPVKyEBvySFtlceFKM2HJvi9mz
+  dest:
+    # Main stuff
+    package/dist/oojs-ui-core.js{,.map.json}:
+    package/dist/oojs-ui-core-{wikimediaui,apex}.css:
+    package/dist/oojs-ui-widgets.js{,.map.json}:
+    package/dist/oojs-ui-widgets-{wikimediaui,apex}.css:
+    package/dist/oojs-ui-toolbars.js{,.map.json}:
+    package/dist/oojs-ui-toolbars-{wikimediaui,apex}.css:
+    package/dist/oojs-ui-windows.js{,.map.json}:
+    package/dist/oojs-ui-windows-{wikimediaui,apex}.css:
+    package/dist/oojs-ui-{wikimediaui,apex}.js{,.map.json}:
+    package/dist/i18n:
+    package/dist/images:
+    # WikimediaUI theme
+    package/dist/themes/wikimediaui/images/icons/*.{svg,png}: themes/wikimediaui/images/icons
+    package/dist/themes/wikimediaui/images/indicators/*.{svg,png}: themes/wikimediaui/images/indicators
+    package/dist/themes/wikimediaui/images/textures/*.{gif,svg}: themes/wikimediaui/images/textures
+    package/dist/themes/wikimediaui/*.json: themes/wikimediaui
+    package/dist/wikimedia-ui-base.less:
+    # Apex theme (icons, indicators, and textures)
+    package/dist/themes/apex/*.json: themes/apex
+    # Misc stuff
+    package/dist/AUTHORS.txt:
+    package/dist/History.md:
+    package/dist/LICENSE-MIT:
+    package/dist/README.md:
+
+qunitjs:
+  type: multi-file
+  # Integrity from link modals at https://code.jquery.com/qunit/
+  files:
+    qunit.js:
+      src: http://code.jquery.com/qunit/qunit-2.9.1.js
+      integrity: sha256-eNccBdxd8zReziWcVjEsPeyJDi3LKMYnzMXyDv8bzsU=
+    qunit.css:
+      src: https://code.jquery.com/qunit/qunit-2.9.1.css
+      integrity: sha256-SSS7o92V7wzcIFg3qnJL9mc4msePaT4klbxtuSGvVVo=
+
+sinonjs:
+  type: file
+  src: https://sinonjs.org/releases/sinon-1.17.7.js
+  integrity: sha384-wR63Jwy75KqwBfzCmXd6gYws6uj3qV/XMAybzXrkEYGYG3AQ58ZWwr1fVpkHa5e8
+  dest: sinon.js
diff --git a/resources/lib/jquery.async.js b/resources/lib/jquery.async.js
deleted file mode 100644 (file)
index 2161f6b..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * jQuery Asynchronous Plugin 1.0
- *
- * Copyright (c) 2008 Vincent Robert (genezys.net)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
- *
- */
-(function($){
-
-// opts.delay : (default 10) delay between async call in ms
-// opts.bulk : (default 500) delay during which the loop can continue synchronously without yielding the CPU
-// opts.test : (default true) function to test in the while test part
-// opts.loop : (default empty) function to call in the while loop part
-// opts.end : (default empty) function to call at the end of the while loop
-$.whileAsync = function(opts) {
-       var delay = Math.abs(opts.delay) || 10,
-               bulk = isNaN(opts.bulk) ? 500 : Math.abs(opts.bulk),
-               test = opts.test || function(){ return true; },
-               loop = opts.loop || function(){},
-               end = opts.end || function(){};
-       
-       (function(){
-
-               var t = false,
-                       begin = new Date();
-                       
-               while( t = test() ) {
-                       loop();
-                       if( bulk === 0 || (new Date() - begin) > bulk ) {
-                               break;
-                       }
-               }
-               if( t ) {
-                       setTimeout(arguments.callee, delay);
-               }
-               else {
-                       end();
-               }
-               
-       })();
-};
-
-// opts.delay : (default 10) delay between async call in ms
-// opts.bulk : (default 500) delay during which the loop can continue synchronously without yielding the CPU
-// opts.loop : (default empty) function to call in the each loop part, signature: function(index, value) this = value
-// opts.end : (default empty) function to call at the end of the each loop
-$.eachAsync = function(array, opts) {
-       var     i = 0,
-               l = array.length,
-               loop = opts.loop || function(){};
-       
-       $.whileAsync(
-               $.extend(opts, {
-                       test: function() { return i < l; },
-                       loop: function() {
-                               var val = array[i];
-                               return loop.call(val, i++, val);
-                       }
-               })
-       );
-};
-
-$.fn.eachAsync = function(opts) {
-       $.eachAsync(this, opts);
-       return this;
-}
-
-})(jQuery);
\ No newline at end of file
diff --git a/resources/lib/jquery.ba-throttle-debounce.js b/resources/lib/jquery.ba-throttle-debounce.js
deleted file mode 100644 (file)
index fa30bdf..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-/*!
- * jQuery throttle / debounce - v1.1 - 3/7/2010
- * http://benalman.com/projects/jquery-throttle-debounce-plugin/
- * 
- * Copyright (c) 2010 "Cowboy" Ben Alman
- * Dual licensed under the MIT and GPL licenses.
- * http://benalman.com/about/license/
- */
-
-// Script: jQuery throttle / debounce: Sometimes, less is more!
-//
-// *Version: 1.1, Last updated: 3/7/2010*
-// 
-// Project Home - http://benalman.com/projects/jquery-throttle-debounce-plugin/
-// GitHub       - http://github.com/cowboy/jquery-throttle-debounce/
-// Source       - http://github.com/cowboy/jquery-throttle-debounce/raw/master/jquery.ba-throttle-debounce.js
-// (Minified)   - http://github.com/cowboy/jquery-throttle-debounce/raw/master/jquery.ba-throttle-debounce.min.js (0.7kb)
-// 
-// About: License
-// 
-// Copyright (c) 2010 "Cowboy" Ben Alman,
-// Dual licensed under the MIT and GPL licenses.
-// http://benalman.com/about/license/
-// 
-// About: Examples
-// 
-// These working examples, complete with fully commented code, illustrate a few
-// ways in which this plugin can be used.
-// 
-// Throttle - http://benalman.com/code/projects/jquery-throttle-debounce/examples/throttle/
-// Debounce - http://benalman.com/code/projects/jquery-throttle-debounce/examples/debounce/
-// 
-// About: Support and Testing
-// 
-// Information about what version or versions of jQuery this plugin has been
-// tested with, what browsers it has been tested in, and where the unit tests
-// reside (so you can test it yourself).
-// 
-// jQuery Versions - none, 1.3.2, 1.4.2
-// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.6, Safari 3-4, Chrome 4-5, Opera 9.6-10.1.
-// Unit Tests      - http://benalman.com/code/projects/jquery-throttle-debounce/unit/
-// 
-// About: Release History
-// 
-// 1.1 - (3/7/2010) Fixed a bug in <jQuery.throttle> where trailing callbacks
-//       executed later than they should. Reworked a fair amount of internal
-//       logic as well.
-// 1.0 - (3/6/2010) Initial release as a stand-alone project. Migrated over
-//       from jquery-misc repo v0.4 to jquery-throttle repo v1.0, added the
-//       no_trailing throttle parameter and debounce functionality.
-// 
-// Topic: Note for non-jQuery users
-// 
-// jQuery isn't actually required for this plugin, because nothing internal
-// uses any jQuery methods or properties. jQuery is just used as a namespace
-// under which these methods can exist.
-// 
-// Since jQuery isn't actually required for this plugin, if jQuery doesn't exist
-// when this plugin is loaded, the method described below will be created in
-// the `Cowboy` namespace. Usage will be exactly the same, but instead of
-// $.method() or jQuery.method(), you'll need to use Cowboy.method().
-
-(function(window,undefined){
-  '$:nomunge'; // Used by YUI compressor.
-  
-  // Since jQuery really isn't required for this plugin, use `jQuery` as the
-  // namespace only if it already exists, otherwise use the `Cowboy` namespace,
-  // creating it if necessary.
-  var $ = window.jQuery || window.Cowboy || ( window.Cowboy = {} ),
-    
-    // Internal method reference.
-    jq_throttle;
-  
-  // Method: jQuery.throttle
-  // 
-  // Throttle execution of a function. Especially useful for rate limiting
-  // execution of handlers on events like resize and scroll. If you want to
-  // rate-limit execution of a function to a single time, see the
-  // <jQuery.debounce> method.
-  // 
-  // In this visualization, | is a throttled-function call and X is the actual
-  // callback execution:
-  // 
-  // > Throttled with `no_trailing` specified as false or unspecified:
-  // > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
-  // > X    X    X    X    X    X        X    X    X    X    X    X
-  // > 
-  // > Throttled with `no_trailing` specified as true:
-  // > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
-  // > X    X    X    X    X             X    X    X    X    X
-  // 
-  // Usage:
-  // 
-  // > var throttled = jQuery.throttle( delay, [ no_trailing, ] callback );
-  // > 
-  // > jQuery('selector').bind( 'someevent', throttled );
-  // > jQuery('selector').unbind( 'someevent', throttled );
-  // 
-  // This also works in jQuery 1.4+:
-  // 
-  // > jQuery('selector').bind( 'someevent', jQuery.throttle( delay, [ no_trailing, ] callback ) );
-  // > jQuery('selector').unbind( 'someevent', callback );
-  // 
-  // Arguments:
-  // 
-  //  delay - (Number) A zero-or-greater delay in milliseconds. For event
-  //    callbacks, values around 100 or 250 (or even higher) are most useful.
-  //  no_trailing - (Boolean) Optional, defaults to false. If no_trailing is
-  //    true, callback will only execute every `delay` milliseconds while the
-  //    throttled-function is being called. If no_trailing is false or
-  //    unspecified, callback will be executed one final time after the last
-  //    throttled-function call. (After the throttled-function has not been
-  //    called for `delay` milliseconds, the internal counter is reset)
-  //  callback - (Function) A function to be executed after delay milliseconds.
-  //    The `this` context and all arguments are passed through, as-is, to
-  //    `callback` when the throttled-function is executed.
-  // 
-  // Returns:
-  // 
-  //  (Function) A new, throttled, function.
-  
-  $.throttle = jq_throttle = function( delay, no_trailing, callback, debounce_mode ) {
-    // After wrapper has stopped being called, this timeout ensures that
-    // `callback` is executed at the proper times in `throttle` and `end`
-    // debounce modes.
-    var timeout_id,
-      
-      // Keep track of the last time `callback` was executed.
-      last_exec = 0;
-    
-    // `no_trailing` defaults to falsy.
-    if ( typeof no_trailing !== 'boolean' ) {
-      debounce_mode = callback;
-      callback = no_trailing;
-      no_trailing = undefined;
-    }
-    
-    // The `wrapper` function encapsulates all of the throttling / debouncing
-    // functionality and when executed will limit the rate at which `callback`
-    // is executed.
-    function wrapper() {
-      var that = this,
-        elapsed = +new Date() - last_exec,
-        args = arguments;
-      
-      // Execute `callback` and update the `last_exec` timestamp.
-      function exec() {
-        last_exec = +new Date();
-        callback.apply( that, args );
-      };
-      
-      // If `debounce_mode` is true (at_begin) this is used to clear the flag
-      // to allow future `callback` executions.
-      function clear() {
-        timeout_id = undefined;
-      };
-      
-      if ( debounce_mode && !timeout_id ) {
-        // Since `wrapper` is being called for the first time and
-        // `debounce_mode` is true (at_begin), execute `callback`.
-        exec();
-      }
-      
-      // Clear any existing timeout.
-      timeout_id && clearTimeout( timeout_id );
-      
-      if ( debounce_mode === undefined && elapsed > delay ) {
-        // In throttle mode, if `delay` time has been exceeded, execute
-        // `callback`.
-        exec();
-        
-      } else if ( no_trailing !== true ) {
-        // In trailing throttle mode, since `delay` time has not been
-        // exceeded, schedule `callback` to execute `delay` ms after most
-        // recent execution.
-        // 
-        // If `debounce_mode` is true (at_begin), schedule `clear` to execute
-        // after `delay` ms.
-        // 
-        // If `debounce_mode` is false (at end), schedule `callback` to
-        // execute after `delay` ms.
-        timeout_id = setTimeout( debounce_mode ? clear : exec, debounce_mode === undefined ? delay - elapsed : delay );
-      }
-    };
-    
-    // Set the guid of `wrapper` function to the same of original callback, so
-    // it can be removed in jQuery 1.4+ .unbind or .die by using the original
-    // callback as a reference.
-    if ( $.guid ) {
-      wrapper.guid = callback.guid = callback.guid || $.guid++;
-    }
-    
-    // Return the wrapper function.
-    return wrapper;
-  };
-  
-  // Method: jQuery.debounce
-  // 
-  // Debounce execution of a function. Debouncing, unlike throttling,
-  // guarantees that a function is only executed a single time, either at the
-  // very beginning of a series of calls, or at the very end. If you want to
-  // simply rate-limit execution of a function, see the <jQuery.throttle>
-  // method.
-  // 
-  // In this visualization, | is a debounced-function call and X is the actual
-  // callback execution:
-  // 
-  // > Debounced with `at_begin` specified as false or unspecified:
-  // > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
-  // >                          X                                 X
-  // > 
-  // > Debounced with `at_begin` specified as true:
-  // > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
-  // > X                                 X
-  // 
-  // Usage:
-  // 
-  // > var debounced = jQuery.debounce( delay, [ at_begin, ] callback );
-  // > 
-  // > jQuery('selector').bind( 'someevent', debounced );
-  // > jQuery('selector').unbind( 'someevent', debounced );
-  // 
-  // This also works in jQuery 1.4+:
-  // 
-  // > jQuery('selector').bind( 'someevent', jQuery.debounce( delay, [ at_begin, ] callback ) );
-  // > jQuery('selector').unbind( 'someevent', callback );
-  // 
-  // Arguments:
-  // 
-  //  delay - (Number) A zero-or-greater delay in milliseconds. For event
-  //    callbacks, values around 100 or 250 (or even higher) are most useful.
-  //  at_begin - (Boolean) Optional, defaults to false. If at_begin is false or
-  //    unspecified, callback will only be executed `delay` milliseconds after
-  //    the last debounced-function call. If at_begin is true, callback will be
-  //    executed only at the first debounced-function call. (After the
-  //    throttled-function has not been called for `delay` milliseconds, the
-  //    internal counter is reset)
-  //  callback - (Function) A function to be executed after delay milliseconds.
-  //    The `this` context and all arguments are passed through, as-is, to
-  //    `callback` when the debounced-function is executed.
-  // 
-  // Returns:
-  // 
-  //  (Function) A new, debounced, function.
-  
-  $.debounce = function( delay, at_begin, callback ) {
-    return callback === undefined
-      ? jq_throttle( delay, at_begin, false )
-      : jq_throttle( delay, callback, at_begin !== false );
-  };
-  
-})(this);
diff --git a/resources/lib/jquery.form.js b/resources/lib/jquery.form.js
deleted file mode 100644 (file)
index 13e9a55..0000000
+++ /dev/null
@@ -1,1089 +0,0 @@
-/*!
- * jQuery Form Plugin
- * version: 3.14 (30-JUL-2012)
- * @requires jQuery v1.3.2 or later
- *
- * Examples and documentation at: http://malsup.com/jquery/form/
- * Project repository: https://github.com/malsup/form
- * Dual licensed under the MIT and GPL licenses:
- *    http://malsup.github.com/mit-license.txt
- *    http://malsup.github.com/gpl-license-v2.txt
- */
-/*global ActiveXObject alert */
-;(function($) {
-"use strict";
-
-/*
-    Usage Note:
-    -----------
-    Do not use both ajaxSubmit and ajaxForm on the same form.  These
-    functions are mutually exclusive.  Use ajaxSubmit if you want
-    to bind your own submit handler to the form.  For example,
-
-    $(document).ready(function() {
-        $('#myForm').on('submit', function(e) {
-            e.preventDefault(); // <-- important
-            $(this).ajaxSubmit({
-                target: '#output'
-            });
-        });
-    });
-
-    Use ajaxForm when you want the plugin to manage all the event binding
-    for you.  For example,
-
-    $(document).ready(function() {
-        $('#myForm').ajaxForm({
-            target: '#output'
-        });
-    });
-    
-    You can also use ajaxForm with delegation (requires jQuery v1.7+), so the
-    form does not have to exist when you invoke ajaxForm:
-
-    $('#myForm').ajaxForm({
-        delegation: true,
-        target: '#output'
-    });
-    
-    When using ajaxForm, the ajaxSubmit function will be invoked for you
-    at the appropriate time.
-*/
-
-/**
- * Feature detection
- */
-var feature = {};
-feature.fileapi = $("<input type='file'/>").get(0).files !== undefined;
-feature.formdata = window.FormData !== undefined;
-
-/**
- * ajaxSubmit() provides a mechanism for immediately submitting
- * an HTML form using AJAX.
- */
-$.fn.ajaxSubmit = function(options) {
-    /*jshint scripturl:true */
-
-    // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
-    if (!this.length) {
-        log('ajaxSubmit: skipping submit process - no element selected');
-        return this;
-    }
-    
-    var method, action, url, $form = this;
-
-    if (typeof options == 'function') {
-        options = { success: options };
-    }
-
-    method = this.attr('method');
-    action = this.attr('action');
-    url = (typeof action === 'string') ? $.trim(action) : '';
-    url = url || window.location.href || '';
-    if (url) {
-        // clean url (don't include hash vaue)
-        url = (url.match(/^([^#]+)/)||[])[1];
-    }
-
-    options = $.extend(true, {
-        url:  url,
-        success: $.ajaxSettings.success,
-        type: method || 'GET',
-        iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
-    }, options);
-
-    // hook for manipulating the form data before it is extracted;
-    // convenient for use with rich editors like tinyMCE or FCKEditor
-    var veto = {};
-    this.trigger('form-pre-serialize', [this, options, veto]);
-    if (veto.veto) {
-        log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
-        return this;
-    }
-
-    // provide opportunity to alter form data before it is serialized
-    if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
-        log('ajaxSubmit: submit aborted via beforeSerialize callback');
-        return this;
-    }
-
-    var traditional = options.traditional;
-    if ( traditional === undefined ) {
-        traditional = $.ajaxSettings.traditional;
-    }
-    
-    var elements = [];
-    var qx, a = this.formToArray(options.semantic, elements);
-    if (options.data) {
-        options.extraData = options.data;
-        qx = $.param(options.data, traditional);
-    }
-
-    // give pre-submit callback an opportunity to abort the submit
-    if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
-        log('ajaxSubmit: submit aborted via beforeSubmit callback');
-        return this;
-    }
-
-    // fire vetoable 'validate' event
-    this.trigger('form-submit-validate', [a, this, options, veto]);
-    if (veto.veto) {
-        log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
-        return this;
-    }
-
-    var q = $.param(a, traditional);
-    if (qx) {
-        q = ( q ? (q + '&' + qx) : qx );
-    }    
-    if (options.type.toUpperCase() == 'GET') {
-        options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
-        options.data = null;  // data is null for 'get'
-    }
-    else {
-        options.data = q; // data is the query string for 'post'
-    }
-
-    var callbacks = [];
-    if (options.resetForm) {
-        callbacks.push(function() { $form.resetForm(); });
-    }
-    if (options.clearForm) {
-        callbacks.push(function() { $form.clearForm(options.includeHidden); });
-    }
-
-    // perform a load on the target only if dataType is not provided
-    if (!options.dataType && options.target) {
-        var oldSuccess = options.success || function(){};
-        callbacks.push(function(data) {
-            var fn = options.replaceTarget ? 'replaceWith' : 'html';
-            $(options.target)[fn](data).each(oldSuccess, arguments);
-        });
-    }
-    else if (options.success) {
-        callbacks.push(options.success);
-    }
-
-    options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
-        var context = options.context || this ;    // jQuery 1.4+ supports scope context 
-        for (var i=0, max=callbacks.length; i < max; i++) {
-            callbacks[i].apply(context, [data, status, xhr || $form, $form]);
-        }
-    };
-
-    // are there files to upload?
-    var fileInputs = $('input:file:enabled[value]', this); // [value] (issue #113)
-    var hasFileInputs = fileInputs.length > 0;
-    var mp = 'multipart/form-data';
-    var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
-
-    var fileAPI = feature.fileapi && feature.formdata;
-    log("fileAPI :" + fileAPI);
-    var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI;
-
-    // options.iframe allows user to force iframe mode
-    // 06-NOV-09: now defaulting to iframe mode if file input is detected
-    if (options.iframe !== false && (options.iframe || shouldUseFrame)) {
-        // hack to fix Safari hang (thanks to Tim Molendijk for this)
-        // see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
-        if (options.closeKeepAlive) {
-            $.get(options.closeKeepAlive, function() {
-                fileUploadIframe(a);
-            });
-        }
-          else {
-            fileUploadIframe(a);
-          }
-    }
-    else if ((hasFileInputs || multipart) && fileAPI) {
-        fileUploadXhr(a);
-    }
-    else {
-        $.ajax(options);
-    }
-
-    // clear element array
-    for (var k=0; k < elements.length; k++)
-        elements[k] = null;
-
-    // fire 'notify' event
-    this.trigger('form-submit-notify', [this, options]);
-    return this;
-
-     // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz)
-    function fileUploadXhr(a) {
-        var formdata = new FormData();
-
-        for (var i=0; i < a.length; i++) {
-            formdata.append(a[i].name, a[i].value);
-        }
-
-        if (options.extraData) {
-            for (var p in options.extraData)
-                if (options.extraData.hasOwnProperty(p))
-                    formdata.append(p, options.extraData[p]);
-        }
-
-        options.data = null;
-
-        var s = $.extend(true, {}, $.ajaxSettings, options, {
-            contentType: false,
-            processData: false,
-            cache: false,
-            type: 'POST'
-        });
-        
-        if (options.uploadProgress) {
-            // workaround because jqXHR does not expose upload property
-            s.xhr = function() {
-                var xhr = jQuery.ajaxSettings.xhr();
-                if (xhr.upload) {
-                    xhr.upload.onprogress = function(event) {
-                        var percent = 0;
-                        var position = event.loaded || event.position; /*event.position is deprecated*/
-                        var total = event.total;
-                        if (event.lengthComputable) {
-                            percent = Math.ceil(position / total * 100);
-                        }
-                        options.uploadProgress(event, position, total, percent);
-                    };
-                }
-                return xhr;
-            };
-        }
-
-        s.data = null;
-            var beforeSend = s.beforeSend;
-            s.beforeSend = function(xhr, o) {
-                o.data = formdata;
-                if(beforeSend)
-                    beforeSend.call(this, xhr, o);
-        };
-        $.ajax(s);
-    }
-
-    // private function for handling file uploads (hat tip to YAHOO!)
-    function fileUploadIframe(a) {
-        var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;
-        var useProp = !!$.fn.prop;
-
-        if ($(':input[name=submit],:input[id=submit]', form).length) {
-            // if there is an input with a name or id of 'submit' then we won't be
-            // able to invoke the submit fn on the form (at least not x-browser)
-            alert('Error: Form elements must not have name or id of "submit".');
-            return;
-        }
-        
-        if (a) {
-            // ensure that every serialized input is still enabled
-            for (i=0; i < elements.length; i++) {
-                el = $(elements[i]);
-                if ( useProp )
-                    el.prop('disabled', false);
-                else
-                    el.removeAttr('disabled');
-            }
-        }
-
-        s = $.extend(true, {}, $.ajaxSettings, options);
-        s.context = s.context || s;
-        id = 'jqFormIO' + (new Date().getTime());
-        if (s.iframeTarget) {
-            $io = $(s.iframeTarget);
-            n = $io.attr('name');
-            if (!n)
-                 $io.attr('name', id);
-            else
-                id = n;
-        }
-        else {
-            $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />');
-            $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
-        }
-        io = $io[0];
-
-
-        xhr = { // mock object
-            aborted: 0,
-            responseText: null,
-            responseXML: null,
-            status: 0,
-            statusText: 'n/a',
-            getAllResponseHeaders: function() {},
-            getResponseHeader: function() {},
-            setRequestHeader: function() {},
-            abort: function(status) {
-                var e = (status === 'timeout' ? 'timeout' : 'aborted');
-                log('aborting upload... ' + e);
-                this.aborted = 1;
-                // #214
-                if (io.contentWindow.document.execCommand) {
-                    try { // #214
-                        io.contentWindow.document.execCommand('Stop');
-                    } catch(ignore) {}
-                }
-                $io.attr('src', s.iframeSrc); // abort op in progress
-                xhr.error = e;
-                if (s.error)
-                    s.error.call(s.context, xhr, e, status);
-                if (g)
-                    $.event.trigger("ajaxError", [xhr, s, e]);
-                if (s.complete)
-                    s.complete.call(s.context, xhr, e);
-            }
-        };
-
-        g = s.global;
-        // trigger ajax global events so that activity/block indicators work like normal
-        if (g && 0 === $.active++) {
-            $.event.trigger("ajaxStart");
-        }
-        if (g) {
-            $.event.trigger("ajaxSend", [xhr, s]);
-        }
-
-        if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
-            if (s.global) {
-                $.active--;
-            }
-            return;
-        }
-        if (xhr.aborted) {
-            return;
-        }
-
-        // add submitting element to data if we know it
-        sub = form.clk;
-        if (sub) {
-            n = sub.name;
-            if (n && !sub.disabled) {
-                s.extraData = s.extraData || {};
-                s.extraData[n] = sub.value;
-                if (sub.type == "image") {
-                    s.extraData[n+'.x'] = form.clk_x;
-                    s.extraData[n+'.y'] = form.clk_y;
-                }
-            }
-        }
-        
-        var CLIENT_TIMEOUT_ABORT = 1;
-        var SERVER_ABORT = 2;
-
-        function getDoc(frame) {
-            var doc = frame.contentWindow ? frame.contentWindow.document : frame.contentDocument ? frame.contentDocument : frame.document;
-            return doc;
-        }
-        
-        // Rails CSRF hack (thanks to Yvan Barthelemy)
-        var csrf_token = $('meta[name=csrf-token]').attr('content');
-        var csrf_param = $('meta[name=csrf-param]').attr('content');
-        if (csrf_param && csrf_token) {
-            s.extraData = s.extraData || {};
-            s.extraData[csrf_param] = csrf_token;
-        }
-
-        // take a breath so that pending repaints get some cpu time before the upload starts
-        function doSubmit() {
-            // make sure form attrs are set
-            var t = $form.attr('target'), a = $form.attr('action');
-
-            // update form attrs in IE friendly way
-            form.setAttribute('target',id);
-            if (!method) {
-                form.setAttribute('method', 'POST');
-            }
-            if (a != s.url) {
-                form.setAttribute('action', s.url);
-            }
-
-            // ie borks in some cases when setting encoding
-            if (! s.skipEncodingOverride && (!method || /post/i.test(method))) {
-                $form.attr({
-                    encoding: 'multipart/form-data',
-                    enctype:  'multipart/form-data'
-                });
-            }
-
-            // support timout
-            if (s.timeout) {
-                timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout);
-            }
-            
-            // look for server aborts
-            function checkState() {
-                try {
-                    var state = getDoc(io).readyState;
-                    log('state = ' + state);
-                    if (state && state.toLowerCase() == 'uninitialized')
-                        setTimeout(checkState,50);
-                }
-                catch(e) {
-                    log('Server abort: ' , e, ' (', e.name, ')');
-                    cb(SERVER_ABORT);
-                    if (timeoutHandle)
-                        clearTimeout(timeoutHandle);
-                    timeoutHandle = undefined;
-                }
-            }
-
-            // add "extra" data to form if provided in options
-            var extraInputs = [];
-            try {
-                if (s.extraData) {
-                    for (var n in s.extraData) {
-                        if (s.extraData.hasOwnProperty(n)) {
-                           // if using the $.param format that allows for multiple values with the same name
-                           if($.isPlainObject(s.extraData[n]) && s.extraData[n].hasOwnProperty('name') && s.extraData[n].hasOwnProperty('value')) {
-                               extraInputs.push(
-                               $('<input type="hidden" name="'+s.extraData[n].name+'">').attr('value',s.extraData[n].value)
-                                   .appendTo(form)[0]);
-                           } else {
-                               extraInputs.push(
-                               $('<input type="hidden" name="'+n+'">').attr('value',s.extraData[n])
-                                   .appendTo(form)[0]);
-                           }
-                        }
-                    }
-                }
-
-                if (!s.iframeTarget) {
-                    // add iframe to doc and submit the form
-                    $io.appendTo('body');
-                    if (io.attachEvent)
-                        io.attachEvent('onload', cb);
-                    else
-                        io.addEventListener('load', cb, false);
-                }
-                setTimeout(checkState,15);
-                form.submit();
-            }
-            finally {
-                // reset attrs and remove "extra" input elements
-                form.setAttribute('action',a);
-                if(t) {
-                    form.setAttribute('target', t);
-                } else {
-                    $form.removeAttr('target');
-                }
-                $(extraInputs).remove();
-            }
-        }
-
-        if (s.forceSync) {
-            doSubmit();
-        }
-        else {
-            setTimeout(doSubmit, 10); // this lets dom updates render
-        }
-
-        var data, doc, domCheckCount = 50, callbackProcessed;
-
-        function cb(e) {
-            if (xhr.aborted || callbackProcessed) {
-                return;
-            }
-            try {
-                doc = getDoc(io);
-            }
-            catch(ex) {
-                log('cannot access response document: ', ex);
-                e = SERVER_ABORT;
-            }
-            if (e === CLIENT_TIMEOUT_ABORT && xhr) {
-                xhr.abort('timeout');
-                return;
-            }
-            else if (e == SERVER_ABORT && xhr) {
-                xhr.abort('server abort');
-                return;
-            }
-
-            if (!doc || doc.location.href == s.iframeSrc) {
-                // response not received yet
-                if (!timedOut)
-                    return;
-            }
-            if (io.detachEvent)
-                io.detachEvent('onload', cb);
-            else    
-                io.removeEventListener('load', cb, false);
-
-            var status = 'success', errMsg;
-            try {
-                if (timedOut) {
-                    throw 'timeout';
-                }
-
-                var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
-                log('isXml='+isXml);
-                if (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) {
-                    if (--domCheckCount) {
-                        // in some browsers (Opera) the iframe DOM is not always traversable when
-                        // the onload callback fires, so we loop a bit to accommodate
-                        log('requeing onLoad callback, DOM not available');
-                        setTimeout(cb, 250);
-                        return;
-                    }
-                    // let this fall through because server response could be an empty document
-                    //log('Could not access iframe DOM after mutiple tries.');
-                    //throw 'DOMException: not available';
-                }
-
-                //log('response detected');
-                var docRoot = doc.body ? doc.body : doc.documentElement;
-                xhr.responseText = docRoot ? docRoot.innerHTML : null;
-                xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
-                if (isXml)
-                    s.dataType = 'xml';
-                xhr.getResponseHeader = function(header){
-                    var headers = {'content-type': s.dataType};
-                    return headers[header];
-                };
-                // support for XHR 'status' & 'statusText' emulation :
-                if (docRoot) {
-                    xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status;
-                    xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText;
-                }
-
-                var dt = (s.dataType || '').toLowerCase();
-                var scr = /(json|script|text)/.test(dt);
-                if (scr || s.textarea) {
-                    // see if user embedded response in textarea
-                    var ta = doc.getElementsByTagName('textarea')[0];
-                    if (ta) {
-                        xhr.responseText = ta.value;
-                        // support for XHR 'status' & 'statusText' emulation :
-                        xhr.status = Number( ta.getAttribute('status') ) || xhr.status;
-                        xhr.statusText = ta.getAttribute('statusText') || xhr.statusText;
-                    }
-                    else if (scr) {
-                        // account for browsers injecting pre around json response
-                        var pre = doc.getElementsByTagName('pre')[0];
-                        var b = doc.getElementsByTagName('body')[0];
-                        if (pre) {
-                            xhr.responseText = pre.textContent ? pre.textContent : pre.innerText;
-                        }
-                        else if (b) {
-                            xhr.responseText = b.textContent ? b.textContent : b.innerText;
-                        }
-                    }
-                }
-                else if (dt == 'xml' && !xhr.responseXML && xhr.responseText) {
-                    xhr.responseXML = toXml(xhr.responseText);
-                }
-
-                try {
-                    data = httpData(xhr, dt, s);
-                }
-                catch (e) {
-                    status = 'parsererror';
-                    xhr.error = errMsg = (e || status);
-                }
-            }
-            catch (e) {
-                log('error caught: ',e);
-                status = 'error';
-                xhr.error = errMsg = (e || status);
-            }
-
-            if (xhr.aborted) {
-                log('upload aborted');
-                status = null;
-            }
-
-            if (xhr.status) { // we've set xhr.status
-                status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error';
-            }
-
-            // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
-            if (status === 'success') {
-                if (s.success)
-                    s.success.call(s.context, data, 'success', xhr);
-                if (g)
-                    $.event.trigger("ajaxSuccess", [xhr, s]);
-            }
-            else if (status) {
-                if (errMsg === undefined)
-                    errMsg = xhr.statusText;
-                if (s.error)
-                    s.error.call(s.context, xhr, status, errMsg);
-                if (g)
-                    $.event.trigger("ajaxError", [xhr, s, errMsg]);
-            }
-
-            if (g)
-                $.event.trigger("ajaxComplete", [xhr, s]);
-
-            if (g && ! --$.active) {
-                $.event.trigger("ajaxStop");
-            }
-
-            if (s.complete)
-                s.complete.call(s.context, xhr, status);
-
-            callbackProcessed = true;
-            if (s.timeout)
-                clearTimeout(timeoutHandle);
-
-            // clean up
-            setTimeout(function() {
-                if (!s.iframeTarget)
-                    $io.remove();
-                xhr.responseXML = null;
-            }, 100);
-        }
-
-        var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
-            if (window.ActiveXObject) {
-                doc = new ActiveXObject('Microsoft.XMLDOM');
-                doc.async = 'false';
-                doc.loadXML(s);
-            }
-            else {
-                doc = (new DOMParser()).parseFromString(s, 'text/xml');
-            }
-            return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
-        };
-        var parseJSON = $.parseJSON || function(s) {
-            /*jslint evil:true */
-            return window['eval']('(' + s + ')');
-        };
-
-        var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
-
-            var ct = xhr.getResponseHeader('content-type') || '',
-                xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
-                data = xml ? xhr.responseXML : xhr.responseText;
-
-            if (xml && data.documentElement.nodeName === 'parsererror') {
-                if ($.error)
-                    $.error('parsererror');
-            }
-            if (s && s.dataFilter) {
-                data = s.dataFilter(data, type);
-            }
-            if (typeof data === 'string') {
-                if (type === 'json' || !type && ct.indexOf('json') >= 0) {
-                    data = parseJSON(data);
-                } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
-                    $.globalEval(data);
-                }
-            }
-            return data;
-        };
-    }
-};
-
-/**
- * ajaxForm() provides a mechanism for fully automating form submission.
- *
- * The advantages of using this method instead of ajaxSubmit() are:
- *
- * 1: This method will include coordinates for <input type="image" /> elements (if the element
- *    is used to submit the form).
- * 2. This method will include the submit element's name/value data (for the element that was
- *    used to submit the form).
- * 3. This method binds the submit() method to the form for you.
- *
- * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely
- * passes the options argument along after properly binding events for submit elements and
- * the form itself.
- */
-$.fn.ajaxForm = function(options) {
-    options = options || {};
-    options.delegation = options.delegation && $.isFunction($.fn.on);
-    
-    // in jQuery 1.3+ we can fix mistakes with the ready state
-    if (!options.delegation && this.length === 0) {
-        var o = { s: this.selector, c: this.context };
-        if (!$.isReady && o.s) {
-            log('DOM not ready, queuing ajaxForm');
-            $(function() {
-                $(o.s,o.c).ajaxForm(options);
-            });
-            return this;
-        }
-        // is your DOM ready?  http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
-        log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
-        return this;
-    }
-
-    if ( options.delegation ) {
-        $(document)
-            .off('submit.form-plugin', this.selector, doAjaxSubmit)
-            .off('click.form-plugin', this.selector, captureSubmittingElement)
-            .on('submit.form-plugin', this.selector, options, doAjaxSubmit)
-            .on('click.form-plugin', this.selector, options, captureSubmittingElement);
-        return this;
-    }
-
-    return this.ajaxFormUnbind()
-        .bind('submit.form-plugin', options, doAjaxSubmit)
-        .bind('click.form-plugin', options, captureSubmittingElement);
-};
-
-// private event handlers    
-function doAjaxSubmit(e) {
-    /*jshint validthis:true */
-    var options = e.data;
-    if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
-        e.preventDefault();
-        $(this).ajaxSubmit(options);
-    }
-}
-    
-function captureSubmittingElement(e) {
-    /*jshint validthis:true */
-    var target = e.target;
-    var $el = $(target);
-    if (!($el.is(":submit,input:image"))) {
-        // is this a child element of the submit el?  (ex: a span within a button)
-        var t = $el.closest(':submit');
-        if (t.length === 0) {
-            return;
-        }
-        target = t[0];
-    }
-    var form = this;
-    form.clk = target;
-    if (target.type == 'image') {
-        if (e.offsetX !== undefined) {
-            form.clk_x = e.offsetX;
-            form.clk_y = e.offsetY;
-        } else if (typeof $.fn.offset == 'function') {
-            var offset = $el.offset();
-            form.clk_x = e.pageX - offset.left;
-            form.clk_y = e.pageY - offset.top;
-        } else {
-            form.clk_x = e.pageX - target.offsetLeft;
-            form.clk_y = e.pageY - target.offsetTop;
-        }
-    }
-    // clear form vars
-    setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
-}
-
-
-// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
-$.fn.ajaxFormUnbind = function() {
-    return this.unbind('submit.form-plugin click.form-plugin');
-};
-
-/**
- * formToArray() gathers form element data into an array of objects that can
- * be passed to any of the following ajax functions: $.get, $.post, or load.
- * Each object in the array has both a 'name' and 'value' property.  An example of
- * an array for a simple login form might be:
- *
- * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
- *
- * It is this array that is passed to pre-submit callback functions provided to the
- * ajaxSubmit() and ajaxForm() methods.
- */
-$.fn.formToArray = function(semantic, elements) {
-    var a = [];
-    if (this.length === 0) {
-        return a;
-    }
-
-    var form = this[0];
-    var els = semantic ? form.getElementsByTagName('*') : form.elements;
-    if (!els) {
-        return a;
-    }
-
-    var i,j,n,v,el,max,jmax;
-    for(i=0, max=els.length; i < max; i++) {
-        el = els[i];
-        n = el.name;
-        if (!n) {
-            continue;
-        }
-
-        if (semantic && form.clk && el.type == "image") {
-            // handle image inputs on the fly when semantic == true
-            if(!el.disabled && form.clk == el) {
-                a.push({name: n, value: $(el).val(), type: el.type });
-                a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
-            }
-            continue;
-        }
-
-        v = $.fieldValue(el, true);
-        if (v && v.constructor == Array) {
-            if (elements) 
-                elements.push(el);
-            for(j=0, jmax=v.length; j < jmax; j++) {
-                a.push({name: n, value: v[j]});
-            }
-        }
-        else if (feature.fileapi && el.type == 'file' && !el.disabled) {
-            if (elements) 
-                elements.push(el);
-            var files = el.files;
-            if (files.length) {
-                for (j=0; j < files.length; j++) {
-                    a.push({name: n, value: files[j], type: el.type});
-                }
-            }
-            else {
-                // #180
-                a.push({ name: n, value: '', type: el.type });
-            }
-        }
-        else if (v !== null && typeof v != 'undefined') {
-            if (elements) 
-                elements.push(el);
-            a.push({name: n, value: v, type: el.type, required: el.required});
-        }
-    }
-
-    if (!semantic && form.clk) {
-        // input type=='image' are not found in elements array! handle it here
-        var $input = $(form.clk), input = $input[0];
-        n = input.name;
-        if (n && !input.disabled && input.type == 'image') {
-            a.push({name: n, value: $input.val()});
-            a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
-        }
-    }
-    return a;
-};
-
-/**
- * Serializes form data into a 'submittable' string. This method will return a string
- * in the format: name1=value1&amp;name2=value2
- */
-$.fn.formSerialize = function(semantic) {
-    //hand off to jQuery.param for proper encoding
-    return $.param(this.formToArray(semantic));
-};
-
-/**
- * Serializes all field elements in the jQuery object into a query string.
- * This method will return a string in the format: name1=value1&amp;name2=value2
- */
-$.fn.fieldSerialize = function(successful) {
-    var a = [];
-    this.each(function() {
-        var n = this.name;
-        if (!n) {
-            return;
-        }
-        var v = $.fieldValue(this, successful);
-        if (v && v.constructor == Array) {
-            for (var i=0,max=v.length; i < max; i++) {
-                a.push({name: n, value: v[i]});
-            }
-        }
-        else if (v !== null && typeof v != 'undefined') {
-            a.push({name: this.name, value: v});
-        }
-    });
-    //hand off to jQuery.param for proper encoding
-    return $.param(a);
-};
-
-/**
- * Returns the value(s) of the element in the matched set.  For example, consider the following form:
- *
- *  <form><fieldset>
- *      <input name="A" type="text" />
- *      <input name="A" type="text" />
- *      <input name="B" type="checkbox" value="B1" />
- *      <input name="B" type="checkbox" value="B2"/>
- *      <input name="C" type="radio" value="C1" />
- *      <input name="C" type="radio" value="C2" />
- *  </fieldset></form>
- *
- *  var v = $(':text').fieldValue();
- *  // if no values are entered into the text inputs
- *  v == ['','']
- *  // if values entered into the text inputs are 'foo' and 'bar'
- *  v == ['foo','bar']
- *
- *  var v = $(':checkbox').fieldValue();
- *  // if neither checkbox is checked
- *  v === undefined
- *  // if both checkboxes are checked
- *  v == ['B1', 'B2']
- *
- *  var v = $(':radio').fieldValue();
- *  // if neither radio is checked
- *  v === undefined
- *  // if first radio is checked
- *  v == ['C1']
- *
- * The successful argument controls whether or not the field element must be 'successful'
- * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
- * The default value of the successful argument is true.  If this value is false the value(s)
- * for each element is returned.
- *
- * Note: This method *always* returns an array.  If no valid value can be determined the
- *    array will be empty, otherwise it will contain one or more values.
- */
-$.fn.fieldValue = function(successful) {
-    for (var val=[], i=0, max=this.length; i < max; i++) {
-        var el = this[i];
-        var v = $.fieldValue(el, successful);
-        if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
-            continue;
-        }
-        if (v.constructor == Array)
-            $.merge(val, v);
-        else
-            val.push(v);
-    }
-    return val;
-};
-
-/**
- * Returns the value of the field element.
- */
-$.fieldValue = function(el, successful) {
-    var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
-    if (successful === undefined) {
-        successful = true;
-    }
-
-    if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
-        (t == 'checkbox' || t == 'radio') && !el.checked ||
-        (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
-        tag == 'select' && el.selectedIndex == -1)) {
-            return null;
-    }
-
-    if (tag == 'select') {
-        var index = el.selectedIndex;
-        if (index < 0) {
-            return null;
-        }
-        var a = [], ops = el.options;
-        var one = (t == 'select-one');
-        var max = (one ? index+1 : ops.length);
-        for(var i=(one ? index : 0); i < max; i++) {
-            var op = ops[i];
-            if (op.selected) {
-                var v = op.value;
-                if (!v) { // extra pain for IE...
-                    v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
-                }
-                if (one) {
-                    return v;
-                }
-                a.push(v);
-            }
-        }
-        return a;
-    }
-    return $(el).val();
-};
-
-/**
- * Clears the form data.  Takes the following actions on the form's input fields:
- *  - input text fields will have their 'value' property set to the empty string
- *  - select elements will have their 'selectedIndex' property set to -1
- *  - checkbox and radio inputs will have their 'checked' property set to false
- *  - inputs of type submit, button, reset, and hidden will *not* be effected
- *  - button elements will *not* be effected
- */
-$.fn.clearForm = function(includeHidden) {
-    return this.each(function() {
-        $('input,select,textarea', this).clearFields(includeHidden);
-    });
-};
-
-/**
- * Clears the selected form elements.
- */
-$.fn.clearFields = $.fn.clearInputs = function(includeHidden) {
-    var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list
-    return this.each(function() {
-        var t = this.type, tag = this.tagName.toLowerCase();
-        if (re.test(t) || tag == 'textarea') {
-            this.value = '';
-        }
-        else if (t == 'checkbox' || t == 'radio') {
-            this.checked = false;
-        }
-        else if (tag == 'select') {
-            this.selectedIndex = -1;
-        }
-        else if (includeHidden) {
-            // includeHidden can be the value true, or it can be a selector string
-            // indicating a special test; for example:
-            //  $('#myForm').clearForm('.special:hidden')
-            // the above would clean hidden inputs that have the class of 'special'
-            if ( (includeHidden === true && /hidden/.test(t)) ||
-                 (typeof includeHidden == 'string' && $(this).is(includeHidden)) )
-                this.value = '';
-        }
-    });
-};
-
-/**
- * Resets the form data.  Causes all form elements to be reset to their original value.
- */
-$.fn.resetForm = function() {
-    return this.each(function() {
-        // guard against an input with the name of 'reset'
-        // note that IE reports the reset function as an 'object'
-        if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
-            this.reset();
-        }
-    });
-};
-
-/**
- * Enables or disables any matching elements.
- */
-$.fn.enable = function(b) {
-    if (b === undefined) {
-        b = true;
-    }
-    return this.each(function() {
-        this.disabled = !b;
-    });
-};
-
-/**
- * Checks/unchecks any matching checkboxes or radio buttons and
- * selects/deselects and matching option elements.
- */
-$.fn.selected = function(select) {
-    if (select === undefined) {
-        select = true;
-    }
-    return this.each(function() {
-        var t = this.type;
-        if (t == 'checkbox' || t == 'radio') {
-            this.checked = select;
-        }
-        else if (this.tagName.toLowerCase() == 'option') {
-            var $sel = $(this).parent('select');
-            if (select && $sel[0] && $sel[0].type == 'select-one') {
-                // deselect all other options
-                $sel.find('option').selected(false);
-            }
-            this.selected = select;
-        }
-    });
-};
-
-// expose debug var
-$.fn.ajaxSubmit.debug = false;
-
-// helper fn for console logging
-function log() {
-    if (!$.fn.ajaxSubmit.debug) 
-        return;
-    var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
-    if (window.console && window.console.log) {
-        window.console.log(msg);
-    }
-    else if (window.opera && window.opera.postError) {
-        window.opera.postError(msg);
-    }
-}
-
-})(jQuery);
diff --git a/resources/lib/jquery.form/jquery.form.js b/resources/lib/jquery.form/jquery.form.js
new file mode 100644 (file)
index 0000000..13e9a55
--- /dev/null
@@ -0,0 +1,1089 @@
+/*!
+ * jQuery Form Plugin
+ * version: 3.14 (30-JUL-2012)
+ * @requires jQuery v1.3.2 or later
+ *
+ * Examples and documentation at: http://malsup.com/jquery/form/
+ * Project repository: https://github.com/malsup/form
+ * Dual licensed under the MIT and GPL licenses:
+ *    http://malsup.github.com/mit-license.txt
+ *    http://malsup.github.com/gpl-license-v2.txt
+ */
+/*global ActiveXObject alert */
+;(function($) {
+"use strict";
+
+/*
+    Usage Note:
+    -----------
+    Do not use both ajaxSubmit and ajaxForm on the same form.  These
+    functions are mutually exclusive.  Use ajaxSubmit if you want
+    to bind your own submit handler to the form.  For example,
+
+    $(document).ready(function() {
+        $('#myForm').on('submit', function(e) {
+            e.preventDefault(); // <-- important
+            $(this).ajaxSubmit({
+                target: '#output'
+            });
+        });
+    });
+
+    Use ajaxForm when you want the plugin to manage all the event binding
+    for you.  For example,
+
+    $(document).ready(function() {
+        $('#myForm').ajaxForm({
+            target: '#output'
+        });
+    });
+    
+    You can also use ajaxForm with delegation (requires jQuery v1.7+), so the
+    form does not have to exist when you invoke ajaxForm:
+
+    $('#myForm').ajaxForm({
+        delegation: true,
+        target: '#output'
+    });
+    
+    When using ajaxForm, the ajaxSubmit function will be invoked for you
+    at the appropriate time.
+*/
+
+/**
+ * Feature detection
+ */
+var feature = {};
+feature.fileapi = $("<input type='file'/>").get(0).files !== undefined;
+feature.formdata = window.FormData !== undefined;
+
+/**
+ * ajaxSubmit() provides a mechanism for immediately submitting
+ * an HTML form using AJAX.
+ */
+$.fn.ajaxSubmit = function(options) {
+    /*jshint scripturl:true */
+
+    // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
+    if (!this.length) {
+        log('ajaxSubmit: skipping submit process - no element selected');
+        return this;
+    }
+    
+    var method, action, url, $form = this;
+
+    if (typeof options == 'function') {
+        options = { success: options };
+    }
+
+    method = this.attr('method');
+    action = this.attr('action');
+    url = (typeof action === 'string') ? $.trim(action) : '';
+    url = url || window.location.href || '';
+    if (url) {
+        // clean url (don't include hash vaue)
+        url = (url.match(/^([^#]+)/)||[])[1];
+    }
+
+    options = $.extend(true, {
+        url:  url,
+        success: $.ajaxSettings.success,
+        type: method || 'GET',
+        iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
+    }, options);
+
+    // hook for manipulating the form data before it is extracted;
+    // convenient for use with rich editors like tinyMCE or FCKEditor
+    var veto = {};
+    this.trigger('form-pre-serialize', [this, options, veto]);
+    if (veto.veto) {
+        log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
+        return this;
+    }
+
+    // provide opportunity to alter form data before it is serialized
+    if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
+        log('ajaxSubmit: submit aborted via beforeSerialize callback');
+        return this;
+    }
+
+    var traditional = options.traditional;
+    if ( traditional === undefined ) {
+        traditional = $.ajaxSettings.traditional;
+    }
+    
+    var elements = [];
+    var qx, a = this.formToArray(options.semantic, elements);
+    if (options.data) {
+        options.extraData = options.data;
+        qx = $.param(options.data, traditional);
+    }
+
+    // give pre-submit callback an opportunity to abort the submit
+    if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
+        log('ajaxSubmit: submit aborted via beforeSubmit callback');
+        return this;
+    }
+
+    // fire vetoable 'validate' event
+    this.trigger('form-submit-validate', [a, this, options, veto]);
+    if (veto.veto) {
+        log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
+        return this;
+    }
+
+    var q = $.param(a, traditional);
+    if (qx) {
+        q = ( q ? (q + '&' + qx) : qx );
+    }    
+    if (options.type.toUpperCase() == 'GET') {
+        options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
+        options.data = null;  // data is null for 'get'
+    }
+    else {
+        options.data = q; // data is the query string for 'post'
+    }
+
+    var callbacks = [];
+    if (options.resetForm) {
+        callbacks.push(function() { $form.resetForm(); });
+    }
+    if (options.clearForm) {
+        callbacks.push(function() { $form.clearForm(options.includeHidden); });
+    }
+
+    // perform a load on the target only if dataType is not provided
+    if (!options.dataType && options.target) {
+        var oldSuccess = options.success || function(){};
+        callbacks.push(function(data) {
+            var fn = options.replaceTarget ? 'replaceWith' : 'html';
+            $(options.target)[fn](data).each(oldSuccess, arguments);
+        });
+    }
+    else if (options.success) {
+        callbacks.push(options.success);
+    }
+
+    options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
+        var context = options.context || this ;    // jQuery 1.4+ supports scope context 
+        for (var i=0, max=callbacks.length; i < max; i++) {
+            callbacks[i].apply(context, [data, status, xhr || $form, $form]);
+        }
+    };
+
+    // are there files to upload?
+    var fileInputs = $('input:file:enabled[value]', this); // [value] (issue #113)
+    var hasFileInputs = fileInputs.length > 0;
+    var mp = 'multipart/form-data';
+    var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
+
+    var fileAPI = feature.fileapi && feature.formdata;
+    log("fileAPI :" + fileAPI);
+    var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI;
+
+    // options.iframe allows user to force iframe mode
+    // 06-NOV-09: now defaulting to iframe mode if file input is detected
+    if (options.iframe !== false && (options.iframe || shouldUseFrame)) {
+        // hack to fix Safari hang (thanks to Tim Molendijk for this)
+        // see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
+        if (options.closeKeepAlive) {
+            $.get(options.closeKeepAlive, function() {
+                fileUploadIframe(a);
+            });
+        }
+          else {
+            fileUploadIframe(a);
+          }
+    }
+    else if ((hasFileInputs || multipart) && fileAPI) {
+        fileUploadXhr(a);
+    }
+    else {
+        $.ajax(options);
+    }
+
+    // clear element array
+    for (var k=0; k < elements.length; k++)
+        elements[k] = null;
+
+    // fire 'notify' event
+    this.trigger('form-submit-notify', [this, options]);
+    return this;
+
+     // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz)
+    function fileUploadXhr(a) {
+        var formdata = new FormData();
+
+        for (var i=0; i < a.length; i++) {
+            formdata.append(a[i].name, a[i].value);
+        }
+
+        if (options.extraData) {
+            for (var p in options.extraData)
+                if (options.extraData.hasOwnProperty(p))
+                    formdata.append(p, options.extraData[p]);
+        }
+
+        options.data = null;
+
+        var s = $.extend(true, {}, $.ajaxSettings, options, {
+            contentType: false,
+            processData: false,
+            cache: false,
+            type: 'POST'
+        });
+        
+        if (options.uploadProgress) {
+            // workaround because jqXHR does not expose upload property
+            s.xhr = function() {
+                var xhr = jQuery.ajaxSettings.xhr();
+                if (xhr.upload) {
+                    xhr.upload.onprogress = function(event) {
+                        var percent = 0;
+                        var position = event.loaded || event.position; /*event.position is deprecated*/
+                        var total = event.total;
+                        if (event.lengthComputable) {
+                            percent = Math.ceil(position / total * 100);
+                        }
+                        options.uploadProgress(event, position, total, percent);
+                    };
+                }
+                return xhr;
+            };
+        }
+
+        s.data = null;
+            var beforeSend = s.beforeSend;
+            s.beforeSend = function(xhr, o) {
+                o.data = formdata;
+                if(beforeSend)
+                    beforeSend.call(this, xhr, o);
+        };
+        $.ajax(s);
+    }
+
+    // private function for handling file uploads (hat tip to YAHOO!)
+    function fileUploadIframe(a) {
+        var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;
+        var useProp = !!$.fn.prop;
+
+        if ($(':input[name=submit],:input[id=submit]', form).length) {
+            // if there is an input with a name or id of 'submit' then we won't be
+            // able to invoke the submit fn on the form (at least not x-browser)
+            alert('Error: Form elements must not have name or id of "submit".');
+            return;
+        }
+        
+        if (a) {
+            // ensure that every serialized input is still enabled
+            for (i=0; i < elements.length; i++) {
+                el = $(elements[i]);
+                if ( useProp )
+                    el.prop('disabled', false);
+                else
+                    el.removeAttr('disabled');
+            }
+        }
+
+        s = $.extend(true, {}, $.ajaxSettings, options);
+        s.context = s.context || s;
+        id = 'jqFormIO' + (new Date().getTime());
+        if (s.iframeTarget) {
+            $io = $(s.iframeTarget);
+            n = $io.attr('name');
+            if (!n)
+                 $io.attr('name', id);
+            else
+                id = n;
+        }
+        else {
+            $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />');
+            $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
+        }
+        io = $io[0];
+
+
+        xhr = { // mock object
+            aborted: 0,
+            responseText: null,
+            responseXML: null,
+            status: 0,
+            statusText: 'n/a',
+            getAllResponseHeaders: function() {},
+            getResponseHeader: function() {},
+            setRequestHeader: function() {},
+            abort: function(status) {
+                var e = (status === 'timeout' ? 'timeout' : 'aborted');
+                log('aborting upload... ' + e);
+                this.aborted = 1;
+                // #214
+                if (io.contentWindow.document.execCommand) {
+                    try { // #214
+                        io.contentWindow.document.execCommand('Stop');
+                    } catch(ignore) {}
+                }
+                $io.attr('src', s.iframeSrc); // abort op in progress
+                xhr.error = e;
+                if (s.error)
+                    s.error.call(s.context, xhr, e, status);
+                if (g)
+                    $.event.trigger("ajaxError", [xhr, s, e]);
+                if (s.complete)
+                    s.complete.call(s.context, xhr, e);
+            }
+        };
+
+        g = s.global;
+        // trigger ajax global events so that activity/block indicators work like normal
+        if (g && 0 === $.active++) {
+            $.event.trigger("ajaxStart");
+        }
+        if (g) {
+            $.event.trigger("ajaxSend", [xhr, s]);
+        }
+
+        if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
+            if (s.global) {
+                $.active--;
+            }
+            return;
+        }
+        if (xhr.aborted) {
+            return;
+        }
+
+        // add submitting element to data if we know it
+        sub = form.clk;
+        if (sub) {
+            n = sub.name;
+            if (n && !sub.disabled) {
+                s.extraData = s.extraData || {};
+                s.extraData[n] = sub.value;
+                if (sub.type == "image") {
+                    s.extraData[n+'.x'] = form.clk_x;
+                    s.extraData[n+'.y'] = form.clk_y;
+                }
+            }
+        }
+        
+        var CLIENT_TIMEOUT_ABORT = 1;
+        var SERVER_ABORT = 2;
+
+        function getDoc(frame) {
+            var doc = frame.contentWindow ? frame.contentWindow.document : frame.contentDocument ? frame.contentDocument : frame.document;
+            return doc;
+        }
+        
+        // Rails CSRF hack (thanks to Yvan Barthelemy)
+        var csrf_token = $('meta[name=csrf-token]').attr('content');
+        var csrf_param = $('meta[name=csrf-param]').attr('content');
+        if (csrf_param && csrf_token) {
+            s.extraData = s.extraData || {};
+            s.extraData[csrf_param] = csrf_token;
+        }
+
+        // take a breath so that pending repaints get some cpu time before the upload starts
+        function doSubmit() {
+            // make sure form attrs are set
+            var t = $form.attr('target'), a = $form.attr('action');
+
+            // update form attrs in IE friendly way
+            form.setAttribute('target',id);
+            if (!method) {
+                form.setAttribute('method', 'POST');
+            }
+            if (a != s.url) {
+                form.setAttribute('action', s.url);
+            }
+
+            // ie borks in some cases when setting encoding
+            if (! s.skipEncodingOverride && (!method || /post/i.test(method))) {
+                $form.attr({
+                    encoding: 'multipart/form-data',
+                    enctype:  'multipart/form-data'
+                });
+            }
+
+            // support timout
+            if (s.timeout) {
+                timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout);
+            }
+            
+            // look for server aborts
+            function checkState() {
+                try {
+                    var state = getDoc(io).readyState;
+                    log('state = ' + state);
+                    if (state && state.toLowerCase() == 'uninitialized')
+                        setTimeout(checkState,50);
+                }
+                catch(e) {
+                    log('Server abort: ' , e, ' (', e.name, ')');
+                    cb(SERVER_ABORT);
+                    if (timeoutHandle)
+                        clearTimeout(timeoutHandle);
+                    timeoutHandle = undefined;
+                }
+            }
+
+            // add "extra" data to form if provided in options
+            var extraInputs = [];
+            try {
+                if (s.extraData) {
+                    for (var n in s.extraData) {
+                        if (s.extraData.hasOwnProperty(n)) {
+                           // if using the $.param format that allows for multiple values with the same name
+                           if($.isPlainObject(s.extraData[n]) && s.extraData[n].hasOwnProperty('name') && s.extraData[n].hasOwnProperty('value')) {
+                               extraInputs.push(
+                               $('<input type="hidden" name="'+s.extraData[n].name+'">').attr('value',s.extraData[n].value)
+                                   .appendTo(form)[0]);
+                           } else {
+                               extraInputs.push(
+                               $('<input type="hidden" name="'+n+'">').attr('value',s.extraData[n])
+                                   .appendTo(form)[0]);
+                           }
+                        }
+                    }
+                }
+
+                if (!s.iframeTarget) {
+                    // add iframe to doc and submit the form
+                    $io.appendTo('body');
+                    if (io.attachEvent)
+                        io.attachEvent('onload', cb);
+                    else
+                        io.addEventListener('load', cb, false);
+                }
+                setTimeout(checkState,15);
+                form.submit();
+            }
+            finally {
+                // reset attrs and remove "extra" input elements
+                form.setAttribute('action',a);
+                if(t) {
+                    form.setAttribute('target', t);
+                } else {
+                    $form.removeAttr('target');
+                }
+                $(extraInputs).remove();
+            }
+        }
+
+        if (s.forceSync) {
+            doSubmit();
+        }
+        else {
+            setTimeout(doSubmit, 10); // this lets dom updates render
+        }
+
+        var data, doc, domCheckCount = 50, callbackProcessed;
+
+        function cb(e) {
+            if (xhr.aborted || callbackProcessed) {
+                return;
+            }
+            try {
+                doc = getDoc(io);
+            }
+            catch(ex) {
+                log('cannot access response document: ', ex);
+                e = SERVER_ABORT;
+            }
+            if (e === CLIENT_TIMEOUT_ABORT && xhr) {
+                xhr.abort('timeout');
+                return;
+            }
+            else if (e == SERVER_ABORT && xhr) {
+                xhr.abort('server abort');
+                return;
+            }
+
+            if (!doc || doc.location.href == s.iframeSrc) {
+                // response not received yet
+                if (!timedOut)
+                    return;
+            }
+            if (io.detachEvent)
+                io.detachEvent('onload', cb);
+            else    
+                io.removeEventListener('load', cb, false);
+
+            var status = 'success', errMsg;
+            try {
+                if (timedOut) {
+                    throw 'timeout';
+                }
+
+                var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
+                log('isXml='+isXml);
+                if (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) {
+                    if (--domCheckCount) {
+                        // in some browsers (Opera) the iframe DOM is not always traversable when
+                        // the onload callback fires, so we loop a bit to accommodate
+                        log('requeing onLoad callback, DOM not available');
+                        setTimeout(cb, 250);
+                        return;
+                    }
+                    // let this fall through because server response could be an empty document
+                    //log('Could not access iframe DOM after mutiple tries.');
+                    //throw 'DOMException: not available';
+                }
+
+                //log('response detected');
+                var docRoot = doc.body ? doc.body : doc.documentElement;
+                xhr.responseText = docRoot ? docRoot.innerHTML : null;
+                xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
+                if (isXml)
+                    s.dataType = 'xml';
+                xhr.getResponseHeader = function(header){
+                    var headers = {'content-type': s.dataType};
+                    return headers[header];
+                };
+                // support for XHR 'status' & 'statusText' emulation :
+                if (docRoot) {
+                    xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status;
+                    xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText;
+                }
+
+                var dt = (s.dataType || '').toLowerCase();
+                var scr = /(json|script|text)/.test(dt);
+                if (scr || s.textarea) {
+                    // see if user embedded response in textarea
+                    var ta = doc.getElementsByTagName('textarea')[0];
+                    if (ta) {
+                        xhr.responseText = ta.value;
+                        // support for XHR 'status' & 'statusText' emulation :
+                        xhr.status = Number( ta.getAttribute('status') ) || xhr.status;
+                        xhr.statusText = ta.getAttribute('statusText') || xhr.statusText;
+                    }
+                    else if (scr) {
+                        // account for browsers injecting pre around json response
+                        var pre = doc.getElementsByTagName('pre')[0];
+                        var b = doc.getElementsByTagName('body')[0];
+                        if (pre) {
+                            xhr.responseText = pre.textContent ? pre.textContent : pre.innerText;
+                        }
+                        else if (b) {
+                            xhr.responseText = b.textContent ? b.textContent : b.innerText;
+                        }
+                    }
+                }
+                else if (dt == 'xml' && !xhr.responseXML && xhr.responseText) {
+                    xhr.responseXML = toXml(xhr.responseText);
+                }
+
+                try {
+                    data = httpData(xhr, dt, s);
+                }
+                catch (e) {
+                    status = 'parsererror';
+                    xhr.error = errMsg = (e || status);
+                }
+            }
+            catch (e) {
+                log('error caught: ',e);
+                status = 'error';
+                xhr.error = errMsg = (e || status);
+            }
+
+            if (xhr.aborted) {
+                log('upload aborted');
+                status = null;
+            }
+
+            if (xhr.status) { // we've set xhr.status
+                status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error';
+            }
+
+            // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
+            if (status === 'success') {
+                if (s.success)
+                    s.success.call(s.context, data, 'success', xhr);
+                if (g)
+                    $.event.trigger("ajaxSuccess", [xhr, s]);
+            }
+            else if (status) {
+                if (errMsg === undefined)
+                    errMsg = xhr.statusText;
+                if (s.error)
+                    s.error.call(s.context, xhr, status, errMsg);
+                if (g)
+                    $.event.trigger("ajaxError", [xhr, s, errMsg]);
+            }
+
+            if (g)
+                $.event.trigger("ajaxComplete", [xhr, s]);
+
+            if (g && ! --$.active) {
+                $.event.trigger("ajaxStop");
+            }
+
+            if (s.complete)
+                s.complete.call(s.context, xhr, status);
+
+            callbackProcessed = true;
+            if (s.timeout)
+                clearTimeout(timeoutHandle);
+
+            // clean up
+            setTimeout(function() {
+                if (!s.iframeTarget)
+                    $io.remove();
+                xhr.responseXML = null;
+            }, 100);
+        }
+
+        var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
+            if (window.ActiveXObject) {
+                doc = new ActiveXObject('Microsoft.XMLDOM');
+                doc.async = 'false';
+                doc.loadXML(s);
+            }
+            else {
+                doc = (new DOMParser()).parseFromString(s, 'text/xml');
+            }
+            return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
+        };
+        var parseJSON = $.parseJSON || function(s) {
+            /*jslint evil:true */
+            return window['eval']('(' + s + ')');
+        };
+
+        var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
+
+            var ct = xhr.getResponseHeader('content-type') || '',
+                xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
+                data = xml ? xhr.responseXML : xhr.responseText;
+
+            if (xml && data.documentElement.nodeName === 'parsererror') {
+                if ($.error)
+                    $.error('parsererror');
+            }
+            if (s && s.dataFilter) {
+                data = s.dataFilter(data, type);
+            }
+            if (typeof data === 'string') {
+                if (type === 'json' || !type && ct.indexOf('json') >= 0) {
+                    data = parseJSON(data);
+                } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
+                    $.globalEval(data);
+                }
+            }
+            return data;
+        };
+    }
+};
+
+/**
+ * ajaxForm() provides a mechanism for fully automating form submission.
+ *
+ * The advantages of using this method instead of ajaxSubmit() are:
+ *
+ * 1: This method will include coordinates for <input type="image" /> elements (if the element
+ *    is used to submit the form).
+ * 2. This method will include the submit element's name/value data (for the element that was
+ *    used to submit the form).
+ * 3. This method binds the submit() method to the form for you.
+ *
+ * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely
+ * passes the options argument along after properly binding events for submit elements and
+ * the form itself.
+ */
+$.fn.ajaxForm = function(options) {
+    options = options || {};
+    options.delegation = options.delegation && $.isFunction($.fn.on);
+    
+    // in jQuery 1.3+ we can fix mistakes with the ready state
+    if (!options.delegation && this.length === 0) {
+        var o = { s: this.selector, c: this.context };
+        if (!$.isReady && o.s) {
+            log('DOM not ready, queuing ajaxForm');
+            $(function() {
+                $(o.s,o.c).ajaxForm(options);
+            });
+            return this;
+        }
+        // is your DOM ready?  http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
+        log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
+        return this;
+    }
+
+    if ( options.delegation ) {
+        $(document)
+            .off('submit.form-plugin', this.selector, doAjaxSubmit)
+            .off('click.form-plugin', this.selector, captureSubmittingElement)
+            .on('submit.form-plugin', this.selector, options, doAjaxSubmit)
+            .on('click.form-plugin', this.selector, options, captureSubmittingElement);
+        return this;
+    }
+
+    return this.ajaxFormUnbind()
+        .bind('submit.form-plugin', options, doAjaxSubmit)
+        .bind('click.form-plugin', options, captureSubmittingElement);
+};
+
+// private event handlers    
+function doAjaxSubmit(e) {
+    /*jshint validthis:true */
+    var options = e.data;
+    if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
+        e.preventDefault();
+        $(this).ajaxSubmit(options);
+    }
+}
+    
+function captureSubmittingElement(e) {
+    /*jshint validthis:true */
+    var target = e.target;
+    var $el = $(target);
+    if (!($el.is(":submit,input:image"))) {
+        // is this a child element of the submit el?  (ex: a span within a button)
+        var t = $el.closest(':submit');
+        if (t.length === 0) {
+            return;
+        }
+        target = t[0];
+    }
+    var form = this;
+    form.clk = target;
+    if (target.type == 'image') {
+        if (e.offsetX !== undefined) {
+            form.clk_x = e.offsetX;
+            form.clk_y = e.offsetY;
+        } else if (typeof $.fn.offset == 'function') {
+            var offset = $el.offset();
+            form.clk_x = e.pageX - offset.left;
+            form.clk_y = e.pageY - offset.top;
+        } else {
+            form.clk_x = e.pageX - target.offsetLeft;
+            form.clk_y = e.pageY - target.offsetTop;
+        }
+    }
+    // clear form vars
+    setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
+}
+
+
+// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
+$.fn.ajaxFormUnbind = function() {
+    return this.unbind('submit.form-plugin click.form-plugin');
+};
+
+/**
+ * formToArray() gathers form element data into an array of objects that can
+ * be passed to any of the following ajax functions: $.get, $.post, or load.
+ * Each object in the array has both a 'name' and 'value' property.  An example of
+ * an array for a simple login form might be:
+ *
+ * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
+ *
+ * It is this array that is passed to pre-submit callback functions provided to the
+ * ajaxSubmit() and ajaxForm() methods.
+ */
+$.fn.formToArray = function(semantic, elements) {
+    var a = [];
+    if (this.length === 0) {
+        return a;
+    }
+
+    var form = this[0];
+    var els = semantic ? form.getElementsByTagName('*') : form.elements;
+    if (!els) {
+        return a;
+    }
+
+    var i,j,n,v,el,max,jmax;
+    for(i=0, max=els.length; i < max; i++) {
+        el = els[i];
+        n = el.name;
+        if (!n) {
+            continue;
+        }
+
+        if (semantic && form.clk && el.type == "image") {
+            // handle image inputs on the fly when semantic == true
+            if(!el.disabled && form.clk == el) {
+                a.push({name: n, value: $(el).val(), type: el.type });
+                a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
+            }
+            continue;
+        }
+
+        v = $.fieldValue(el, true);
+        if (v && v.constructor == Array) {
+            if (elements) 
+                elements.push(el);
+            for(j=0, jmax=v.length; j < jmax; j++) {
+                a.push({name: n, value: v[j]});
+            }
+        }
+        else if (feature.fileapi && el.type == 'file' && !el.disabled) {
+            if (elements) 
+                elements.push(el);
+            var files = el.files;
+            if (files.length) {
+                for (j=0; j < files.length; j++) {
+                    a.push({name: n, value: files[j], type: el.type});
+                }
+            }
+            else {
+                // #180
+                a.push({ name: n, value: '', type: el.type });
+            }
+        }
+        else if (v !== null && typeof v != 'undefined') {
+            if (elements) 
+                elements.push(el);
+            a.push({name: n, value: v, type: el.type, required: el.required});
+        }
+    }
+
+    if (!semantic && form.clk) {
+        // input type=='image' are not found in elements array! handle it here
+        var $input = $(form.clk), input = $input[0];
+        n = input.name;
+        if (n && !input.disabled && input.type == 'image') {
+            a.push({name: n, value: $input.val()});
+            a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
+        }
+    }
+    return a;
+};
+
+/**
+ * Serializes form data into a 'submittable' string. This method will return a string
+ * in the format: name1=value1&amp;name2=value2
+ */
+$.fn.formSerialize = function(semantic) {
+    //hand off to jQuery.param for proper encoding
+    return $.param(this.formToArray(semantic));
+};
+
+/**
+ * Serializes all field elements in the jQuery object into a query string.
+ * This method will return a string in the format: name1=value1&amp;name2=value2
+ */
+$.fn.fieldSerialize = function(successful) {
+    var a = [];
+    this.each(function() {
+        var n = this.name;
+        if (!n) {
+            return;
+        }
+        var v = $.fieldValue(this, successful);
+        if (v && v.constructor == Array) {
+            for (var i=0,max=v.length; i < max; i++) {
+                a.push({name: n, value: v[i]});
+            }
+        }
+        else if (v !== null && typeof v != 'undefined') {
+            a.push({name: this.name, value: v});
+        }
+    });
+    //hand off to jQuery.param for proper encoding
+    return $.param(a);
+};
+
+/**
+ * Returns the value(s) of the element in the matched set.  For example, consider the following form:
+ *
+ *  <form><fieldset>
+ *      <input name="A" type="text" />
+ *      <input name="A" type="text" />
+ *      <input name="B" type="checkbox" value="B1" />
+ *      <input name="B" type="checkbox" value="B2"/>
+ *      <input name="C" type="radio" value="C1" />
+ *      <input name="C" type="radio" value="C2" />
+ *  </fieldset></form>
+ *
+ *  var v = $(':text').fieldValue();
+ *  // if no values are entered into the text inputs
+ *  v == ['','']
+ *  // if values entered into the text inputs are 'foo' and 'bar'
+ *  v == ['foo','bar']
+ *
+ *  var v = $(':checkbox').fieldValue();
+ *  // if neither checkbox is checked
+ *  v === undefined
+ *  // if both checkboxes are checked
+ *  v == ['B1', 'B2']
+ *
+ *  var v = $(':radio').fieldValue();
+ *  // if neither radio is checked
+ *  v === undefined
+ *  // if first radio is checked
+ *  v == ['C1']
+ *
+ * The successful argument controls whether or not the field element must be 'successful'
+ * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
+ * The default value of the successful argument is true.  If this value is false the value(s)
+ * for each element is returned.
+ *
+ * Note: This method *always* returns an array.  If no valid value can be determined the
+ *    array will be empty, otherwise it will contain one or more values.
+ */
+$.fn.fieldValue = function(successful) {
+    for (var val=[], i=0, max=this.length; i < max; i++) {
+        var el = this[i];
+        var v = $.fieldValue(el, successful);
+        if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
+            continue;
+        }
+        if (v.constructor == Array)
+            $.merge(val, v);
+        else
+            val.push(v);
+    }
+    return val;
+};
+
+/**
+ * Returns the value of the field element.
+ */
+$.fieldValue = function(el, successful) {
+    var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
+    if (successful === undefined) {
+        successful = true;
+    }
+
+    if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
+        (t == 'checkbox' || t == 'radio') && !el.checked ||
+        (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
+        tag == 'select' && el.selectedIndex == -1)) {
+            return null;
+    }
+
+    if (tag == 'select') {
+        var index = el.selectedIndex;
+        if (index < 0) {
+            return null;
+        }
+        var a = [], ops = el.options;
+        var one = (t == 'select-one');
+        var max = (one ? index+1 : ops.length);
+        for(var i=(one ? index : 0); i < max; i++) {
+            var op = ops[i];
+            if (op.selected) {
+                var v = op.value;
+                if (!v) { // extra pain for IE...
+                    v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
+                }
+                if (one) {
+                    return v;
+                }
+                a.push(v);
+            }
+        }
+        return a;
+    }
+    return $(el).val();
+};
+
+/**
+ * Clears the form data.  Takes the following actions on the form's input fields:
+ *  - input text fields will have their 'value' property set to the empty string
+ *  - select elements will have their 'selectedIndex' property set to -1
+ *  - checkbox and radio inputs will have their 'checked' property set to false
+ *  - inputs of type submit, button, reset, and hidden will *not* be effected
+ *  - button elements will *not* be effected
+ */
+$.fn.clearForm = function(includeHidden) {
+    return this.each(function() {
+        $('input,select,textarea', this).clearFields(includeHidden);
+    });
+};
+
+/**
+ * Clears the selected form elements.
+ */
+$.fn.clearFields = $.fn.clearInputs = function(includeHidden) {
+    var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list
+    return this.each(function() {
+        var t = this.type, tag = this.tagName.toLowerCase();
+        if (re.test(t) || tag == 'textarea') {
+            this.value = '';
+        }
+        else if (t == 'checkbox' || t == 'radio') {
+            this.checked = false;
+        }
+        else if (tag == 'select') {
+            this.selectedIndex = -1;
+        }
+        else if (includeHidden) {
+            // includeHidden can be the value true, or it can be a selector string
+            // indicating a special test; for example:
+            //  $('#myForm').clearForm('.special:hidden')
+            // the above would clean hidden inputs that have the class of 'special'
+            if ( (includeHidden === true && /hidden/.test(t)) ||
+                 (typeof includeHidden == 'string' && $(this).is(includeHidden)) )
+                this.value = '';
+        }
+    });
+};
+
+/**
+ * Resets the form data.  Causes all form elements to be reset to their original value.
+ */
+$.fn.resetForm = function() {
+    return this.each(function() {
+        // guard against an input with the name of 'reset'
+        // note that IE reports the reset function as an 'object'
+        if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
+            this.reset();
+        }
+    });
+};
+
+/**
+ * Enables or disables any matching elements.
+ */
+$.fn.enable = function(b) {
+    if (b === undefined) {
+        b = true;
+    }
+    return this.each(function() {
+        this.disabled = !b;
+    });
+};
+
+/**
+ * Checks/unchecks any matching checkboxes or radio buttons and
+ * selects/deselects and matching option elements.
+ */
+$.fn.selected = function(select) {
+    if (select === undefined) {
+        select = true;
+    }
+    return this.each(function() {
+        var t = this.type;
+        if (t == 'checkbox' || t == 'radio') {
+            this.checked = select;
+        }
+        else if (this.tagName.toLowerCase() == 'option') {
+            var $sel = $(this).parent('select');
+            if (select && $sel[0] && $sel[0].type == 'select-one') {
+                // deselect all other options
+                $sel.find('option').selected(false);
+            }
+            this.selected = select;
+        }
+    });
+};
+
+// expose debug var
+$.fn.ajaxSubmit.debug = false;
+
+// helper fn for console logging
+function log() {
+    if (!$.fn.ajaxSubmit.debug) 
+        return;
+    var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
+    if (window.console && window.console.log) {
+        window.console.log(msg);
+    }
+    else if (window.opera && window.opera.postError) {
+        window.opera.postError(msg);
+    }
+}
+
+})(jQuery);
diff --git a/resources/lib/jquery.fullscreen.js b/resources/lib/jquery.fullscreen.js
deleted file mode 100644 (file)
index 30e4484..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-/**
- * jQuery fullscreen plugin v2.0.0-git (9f8f97d127)
- * https://github.com/theopolisme/jquery-fullscreen
- *
- * Copyright (c) 2013 Theopolisme <theopolismewiki@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.
- */
-( function ( $ ) {
-       var setupFullscreen,
-               fsClass = 'jq-fullscreened';
-
-       /**
-        * On fullscreenchange, trigger a jq-fullscreen-change event
-        * The event is given an object, which contains the fullscreened DOM element (element), if any
-        * and a boolean value (fullscreen) indicating if we've entered or exited fullscreen mode
-        * Also remove the 'fullscreened' class from elements that are no longer fullscreen
-        */
-       function handleFullscreenChange () {
-               var fullscreenElement = document.fullscreenElement ||
-                       document.mozFullScreenElement ||
-                       document.webkitFullscreenElement ||
-                       document.msFullscreenElement;
-
-               if ( !fullscreenElement ) {
-                       $( '.' + fsClass ).data( 'isFullscreened', false ).removeClass( fsClass );
-               }
-
-               $( document ).trigger( $.Event( 'jq-fullscreen-change', { element: fullscreenElement, fullscreen: !!fullscreenElement } ) );
-       }
-
-       /**
-        * Enters full screen with the "this" element in focus.
-        * Check the .data( 'isFullscreened' ) of the return value to check
-        * success or failure, if you're into that sort of thing.
-        * @chainable
-        * @return {jQuery}
-        */
-       function enterFullscreen () {
-               var element = this.get(0),
-                       $element = this.first();
-               if ( element ) {
-                       if ( element.requestFullscreen ) {
-                               element.requestFullscreen();
-                       } else if ( element.mozRequestFullScreen ) {
-                               element.mozRequestFullScreen();
-                       } else if ( element.webkitRequestFullscreen ) {
-                               element.webkitRequestFullscreen();
-                       } else if ( element.msRequestFullscreen ) {
-                               element.msRequestFullscreen();
-                       } else {
-                               // Unable to make fullscreen
-                               $element.data( 'isFullscreened', false );
-                               return this;
-                       }
-                       // Add the fullscreen class and data attribute to `element`
-                       $element.addClass( fsClass ).data( 'isFullscreened', true );
-                       return this;
-               } else {
-                       $element.data( 'isFullscreened', false );
-                       return this;
-               }
-       }
-
-       /**
-        * Brings the "this" element out of fullscreen.
-        * Check the .data( 'isFullscreened' ) of the return value to check
-        * success or failure, if you're into that sort of thing.
-        * @chainable
-        * @return {jQuery}
-        */
-       function exitFullscreen () {
-               var fullscreenElement = ( document.fullscreenElement ||
-                               document.mozFullScreenElement ||
-                               document.webkitFullscreenElement ||
-                               document.msFullscreenElement );
-
-               // Ensure that we only exit fullscreen if exitFullscreen() is being called on the same element that is currently fullscreen
-               if ( fullscreenElement && this.get(0) === fullscreenElement ) {
-                       if ( document.exitFullscreen ) {
-                               document.exitFullscreen();
-                       } else if ( document.mozCancelFullScreen ) {
-                               document.mozCancelFullScreen();
-                       } else if ( document.webkitCancelFullScreen ) {
-                               document.webkitCancelFullScreen();
-                       } else if ( document.msExitFullscreen ) {
-                               document.msExitFullscreen();
-                       } else {
-                               // Unable to cancel fullscreen mode
-                               return this;
-                       }
-                       // We don't need to remove the fullscreen class here,
-                       // because it will be removed in handleFullscreenChange.
-                       // But we should change the data on the element so the
-                       // caller can check for success.
-                       this.first().data( 'isFullscreened', false );
-               }
-
-               return this;
-       }
-
-       /**
-        * Set up fullscreen handling and install necessary event handlers.
-        * Return false if fullscreen is not supported.
-        */
-       setupFullscreen = function () {
-               if ( $.support.fullscreen ) {
-                       // When the fullscreen mode is changed, trigger the
-                       // fullscreen events (and when exiting,
-                       // also remove the fullscreen class)
-                       $( document ).on( 'fullscreenchange webkitfullscreenchange mozfullscreenchange MSFullscreenChange', handleFullscreenChange);
-                       // Convenience wrapper so that one only needs to listen for
-                       // 'fullscreenerror', not all of the prefixed versions
-                       $( document ).on( 'webkitfullscreenerror mozfullscreenerror MSFullscreenError', function () {
-                               $( document ).trigger( $.Event( 'fullscreenerror' ) );
-                       } );
-                       // Fullscreen has been set up, so always return true
-                       setupFullscreen = function () { return true; };
-                       return true;
-               } else {
-                       // Always return false from now on, since fullscreen is not supported
-                       setupFullscreen = function () { return false; };
-                       return false;
-               }
-       };
-
-       /**
-        * Set up fullscreen handling if necessary, then make the first element
-        * matching the given selector fullscreen
-        * @chainable
-        * @return {jQuery}
-        */
-       $.fn.enterFullscreen = function () {
-               if ( setupFullscreen() ) {
-                       $.fn.enterFullscreen = enterFullscreen;
-                       return this.enterFullscreen();
-               } else {
-                       $.fn.enterFullscreen = function () { return this; };
-                       return this;
-               }
-       };
-
-       /**
-        * Set up fullscreen handling if necessary, then cancel fullscreen mode
-        * for the first element matching the given selector.
-        * @chainable
-        * @return {jQuery}
-        */
-       $.fn.exitFullscreen = function () {
-               if ( setupFullscreen() ) {
-                       $.fn.exitFullscreen = exitFullscreen;
-                       return this.exitFullscreen();
-               } else {
-                       $.fn.exitFullscreen = function () { return this; };
-                       return this;
-               }
-       };
-
-       $.support.fullscreen = document.fullscreenEnabled ||
-               document.webkitFullscreenEnabled ||
-               document.mozFullScreenEnabled ||
-               document.msFullscreenEnabled;
-}( jQuery ) );
diff --git a/resources/lib/jquery.fullscreen/jquery.fullscreen.js b/resources/lib/jquery.fullscreen/jquery.fullscreen.js
new file mode 100644 (file)
index 0000000..2702cee
--- /dev/null
@@ -0,0 +1,175 @@
+/**
+ * jQuery fullscreen plugin
+ * https://github.com/theopolisme/jquery-fullscreen
+ *
+ * Copyright (c) 2013 Theopolisme <theopolismewiki@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.
+ */
+( function ( $ ) {
+       var setupFullscreen,
+               fsClass = 'jq-fullscreened';
+
+       /**
+        * On fullscreenchange, trigger a jq-fullscreen-change event
+        * The event is given an object, which contains the fullscreened DOM element (element), if any
+        * and a boolean value (fullscreen) indicating if we've entered or exited fullscreen mode
+        * Also remove the 'fullscreened' class from elements that are no longer fullscreen
+        */
+       function handleFullscreenChange () {
+               var fullscreenElement = document.fullscreenElement ||
+                       document.mozFullScreenElement ||
+                       document.webkitFullscreenElement ||
+                       document.msFullscreenElement;
+
+               if ( !fullscreenElement ) {
+                       $( '.' + fsClass ).data( 'isFullscreened', false ).removeClass( fsClass );
+               }
+
+               $( document ).trigger( $.Event( 'jq-fullscreen-change', { element: fullscreenElement, fullscreen: !!fullscreenElement } ) );
+       }
+
+       /**
+        * Enters full screen with the "this" element in focus.
+        * Check the .data( 'isFullscreened' ) of the return value to check
+        * success or failure, if you're into that sort of thing.
+        * @chainable
+        * @return {jQuery}
+        */
+       function enterFullscreen () {
+               var element = this.get(0),
+                       $element = this.first();
+               if ( element ) {
+                       if ( element.requestFullscreen ) {
+                               element.requestFullscreen();
+                       } else if ( element.mozRequestFullScreen ) {
+                               element.mozRequestFullScreen();
+                       } else if ( element.webkitRequestFullscreen ) {
+                               element.webkitRequestFullscreen();
+                       } else if ( element.msRequestFullscreen ) {
+                               element.msRequestFullscreen();
+                       } else {
+                               // Unable to make fullscreen
+                               $element.data( 'isFullscreened', false );
+                               return this;
+                       }
+                       // Add the fullscreen class and data attribute to `element`
+                       $element.addClass( fsClass ).data( 'isFullscreened', true );
+                       return this;
+               } else {
+                       $element.data( 'isFullscreened', false );
+                       return this;
+               }
+       }
+
+       /**
+        * Brings the "this" element out of fullscreen.
+        * Check the .data( 'isFullscreened' ) of the return value to check
+        * success or failure, if you're into that sort of thing.
+        * @chainable
+        * @return {jQuery}
+        */
+       function exitFullscreen () {
+               var fullscreenElement = ( document.fullscreenElement ||
+                               document.mozFullScreenElement ||
+                               document.webkitFullscreenElement ||
+                               document.msFullscreenElement );
+
+               // Ensure that we only exit fullscreen if exitFullscreen() is being called on the same element that is currently fullscreen
+               if ( fullscreenElement && this.get(0) === fullscreenElement ) {
+                       if ( document.exitFullscreen ) {
+                               document.exitFullscreen();
+                       } else if ( document.mozCancelFullScreen ) {
+                               document.mozCancelFullScreen();
+                       } else if ( document.webkitCancelFullScreen ) {
+                               document.webkitCancelFullScreen();
+                       } else if ( document.msExitFullscreen ) {
+                               document.msExitFullscreen();
+                       } else {
+                               // Unable to cancel fullscreen mode
+                               return this;
+                       }
+                       // We don't need to remove the fullscreen class here,
+                       // because it will be removed in handleFullscreenChange.
+                       // But we should change the data on the element so the
+                       // caller can check for success.
+                       this.first().data( 'isFullscreened', false );
+               }
+
+               return this;
+       }
+
+       /**
+        * Set up fullscreen handling and install necessary event handlers.
+        * Return false if fullscreen is not supported.
+        */
+       setupFullscreen = function () {
+               if ( $.support.fullscreen ) {
+                       // When the fullscreen mode is changed, trigger the
+                       // fullscreen events (and when exiting,
+                       // also remove the fullscreen class)
+                       $( document ).on( 'fullscreenchange webkitfullscreenchange mozfullscreenchange MSFullscreenChange', handleFullscreenChange);
+                       // Convenience wrapper so that one only needs to listen for
+                       // 'fullscreenerror', not all of the prefixed versions
+                       $( document ).on( 'webkitfullscreenerror mozfullscreenerror MSFullscreenError', function () {
+                               $( document ).trigger( $.Event( 'fullscreenerror' ) );
+                       } );
+                       // Fullscreen has been set up, so always return true
+                       setupFullscreen = function () { return true; };
+                       return true;
+               } else {
+                       // Always return false from now on, since fullscreen is not supported
+                       setupFullscreen = function () { return false; };
+                       return false;
+               }
+       };
+
+       /**
+        * Set up fullscreen handling if necessary, then make the first element
+        * matching the given selector fullscreen
+        * @chainable
+        * @return {jQuery}
+        */
+       $.fn.enterFullscreen = function () {
+               if ( setupFullscreen() ) {
+                       $.fn.enterFullscreen = enterFullscreen;
+                       return this.enterFullscreen();
+               } else {
+                       $.fn.enterFullscreen = function () { return this; };
+                       return this;
+               }
+       };
+
+       /**
+        * Set up fullscreen handling if necessary, then cancel fullscreen mode
+        * for the first element matching the given selector.
+        * @chainable
+        * @return {jQuery}
+        */
+       $.fn.exitFullscreen = function () {
+               if ( setupFullscreen() ) {
+                       $.fn.exitFullscreen = exitFullscreen;
+                       return this.exitFullscreen();
+               } else {
+                       $.fn.exitFullscreen = function () { return this; };
+                       return this;
+               }
+       };
+
+       $.support.fullscreen = document.fullscreenEnabled ||
+               document.webkitFullscreenEnabled ||
+               document.mozFullScreenEnabled ||
+               document.msFullscreenEnabled;
+}( jQuery ) );
diff --git a/resources/lib/jquery.hoverIntent.js b/resources/lib/jquery.hoverIntent.js
deleted file mode 100644 (file)
index adf948d..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/**
-* hoverIntent is similar to jQuery's built-in "hover" function except that
-* instead of firing the onMouseOver event immediately, hoverIntent checks
-* to see if the user's mouse has slowed down (beneath the sensitivity
-* threshold) before firing the onMouseOver event.
-* 
-* hoverIntent r5 // 2007.03.27 // jQuery 1.1.2+
-* <http://cherne.net/brian/resources/jquery.hoverIntent.html>
-* 
-* hoverIntent is currently available for use in all personal or commercial 
-* projects under both MIT and GPL licenses. This means that you can choose 
-* the license that best suits your project, and use it accordingly.
-* 
-* // basic usage (just like .hover) receives onMouseOver and onMouseOut functions
-* $("ul li").hoverIntent( showNav , hideNav );
-* 
-* // advanced usage receives configuration object only
-* $("ul li").hoverIntent({
-*      sensitivity: 7, // number = sensitivity threshold (must be 1 or higher)
-*      interval: 100,   // number = milliseconds of polling interval
-*      over: showNav,  // function = onMouseOver callback (required)
-*      timeout: 0,   // number = milliseconds delay before onMouseOut function call
-*      out: hideNav    // function = onMouseOut callback (required)
-* });
-* 
-* @param  f  onMouseOver function || An object with configuration options
-* @param  g  onMouseOut function  || Nothing (use configuration options object)
-* @author    Brian Cherne <brian@cherne.net>
-*/
-(function($) {
-       $.fn.hoverIntent = function(f,g) {
-               // default configuration options
-               var cfg = {
-                       sensitivity: 7,
-                       interval: 100,
-                       timeout: 0
-               };
-               // override configuration options with user supplied object
-               cfg = $.extend(cfg, g ? { over: f, out: g } : f );
-
-               // instantiate variables
-               // cX, cY = current X and Y position of mouse, updated by mousemove event
-               // pX, pY = previous X and Y position of mouse, set by mouseover and polling interval
-               var cX, cY, pX, pY;
-
-               // A private function for getting mouse position
-               var track = function(ev) {
-                       cX = ev.pageX;
-                       cY = ev.pageY;
-               };
-
-               // A private function for comparing current and previous mouse position
-               var compare = function(ev,ob) {
-                       ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
-                       // compare mouse positions to see if they've crossed the threshold
-                       if ( ( Math.abs(pX-cX) + Math.abs(pY-cY) ) < cfg.sensitivity ) {
-                               $(ob).unbind("mousemove",track);
-                               // set hoverIntent state to true (so mouseOut can be called)
-                               ob.hoverIntent_s = 1;
-                               return cfg.over.apply(ob,[ev]);
-                       } else {
-                               // set previous coordinates for next time
-                               pX = cX; pY = cY;
-                               // use self-calling timeout, guarantees intervals are spaced out properly (avoids JavaScript timer bugs)
-                               ob.hoverIntent_t = setTimeout( function(){compare(ev, ob);} , cfg.interval );
-                       }
-               };
-
-               // A private function for delaying the mouseOut function
-               var delay = function(ev,ob) {
-                       ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
-                       ob.hoverIntent_s = 0;
-                       return cfg.out.apply(ob,[ev]);
-               };
-
-               // A private function for handling mouse 'hovering'
-               var handleHover = function(e) {
-                       // next three lines copied from jQuery.hover, ignore children onMouseOver/onMouseOut
-                       var p = (e.type == "mouseover" ? e.fromElement : e.toElement) || e.relatedTarget;
-                       while ( p && p != this ) { try { p = p.parentNode; } catch(e) { p = this; } }
-                       if ( p == this ) { return false; }
-
-                       // copy objects to be passed into t (required for event object to be passed in IE)
-                       var ev = $.extend({},e);
-                       var ob = this;
-
-                       // cancel hoverIntent timer if it exists
-                       if (ob.hoverIntent_t) { ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); }
-
-                       // else e.type == "onmouseover"
-                       if (e.type == "mouseover") {
-                               // set "previous" X and Y position based on initial entry point
-                               pX = ev.pageX; pY = ev.pageY;
-                               // update "current" X and Y position based on mousemove
-                               $(ob).bind("mousemove",track);
-                               // start polling interval (self-calling timeout) to compare mouse coordinates over time
-                               if (ob.hoverIntent_s != 1) { ob.hoverIntent_t = setTimeout( function(){compare(ev,ob);} , cfg.interval );}
-
-                       // else e.type == "onmouseout"
-                       } else {
-                               // unbind expensive mousemove event
-                               $(ob).unbind("mousemove",track);
-                               // if hoverIntent state is true, then call the mouseOut function after the specified delay
-                               if (ob.hoverIntent_s == 1) { ob.hoverIntent_t = setTimeout( function(){delay(ev,ob);} , cfg.timeout );}
-                       }
-               };
-
-               // bind the function to the two event listeners
-               return this.mouseover(handleHover).mouseout(handleHover);
-       };
-})(jQuery);
\ No newline at end of file
diff --git a/resources/lib/jquery.hoverIntent/jquery.hoverIntent.js b/resources/lib/jquery.hoverIntent/jquery.hoverIntent.js
new file mode 100644 (file)
index 0000000..bd11442
--- /dev/null
@@ -0,0 +1,111 @@
+/**
+* hoverIntent is similar to jQuery's built-in "hover" function except that
+* instead of firing the onMouseOver event immediately, hoverIntent checks
+* to see if the user's mouse has slowed down (beneath the sensitivity
+* threshold) before firing the onMouseOver event.
+* 
+* hoverIntent r5 // 2007.03.27 // jQuery 1.1.2+
+* <http://cherne.net/brian/resources/jquery.hoverIntent.html>
+* 
+* hoverIntent is currently available for use in all personal or commercial 
+* projects under both MIT and GPL licenses. This means that you can choose 
+* the license that best suits your project, and use it accordingly.
+* 
+* // basic usage (just like .hover) receives onMouseOver and onMouseOut functions
+* $("ul li").hoverIntent( showNav , hideNav );
+* 
+* // advanced usage receives configuration object only
+* $("ul li").hoverIntent({
+*      sensitivity: 7, // number = sensitivity threshold (must be 1 or higher)
+*      interval: 100,   // number = milliseconds of polling interval
+*      over: showNav,  // function = onMouseOver callback (required)
+*      timeout: 0,   // number = milliseconds delay before onMouseOut function call
+*      out: hideNav    // function = onMouseOut callback (required)
+* });
+* 
+* @param  f  onMouseOver function || An object with configuration options
+* @param  g  onMouseOut function  || Nothing (use configuration options object)
+* @author    Brian Cherne <brian@cherne.net>
+*/
+(function($) {
+       $.fn.hoverIntent = function(f,g) {
+               // default configuration options
+               var cfg = {
+                       sensitivity: 7,
+                       interval: 100,
+                       timeout: 0
+               };
+               // override configuration options with user supplied object
+               cfg = $.extend(cfg, g ? { over: f, out: g } : f );
+
+               // instantiate variables
+               // cX, cY = current X and Y position of mouse, updated by mousemove event
+               // pX, pY = previous X and Y position of mouse, set by mouseover and polling interval
+               var cX, cY, pX, pY;
+
+               // A private function for getting mouse position
+               var track = function(ev) {
+                       cX = ev.pageX;
+                       cY = ev.pageY;
+               };
+
+               // A private function for comparing current and previous mouse position
+               var compare = function(ev,ob) {
+                       ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
+                       // compare mouse positions to see if they've crossed the threshold
+                       if ( ( Math.abs(pX-cX) + Math.abs(pY-cY) ) < cfg.sensitivity ) {
+                               $(ob).unbind("mousemove",track);
+                               // set hoverIntent state to true (so mouseOut can be called)
+                               ob.hoverIntent_s = 1;
+                               return cfg.over.apply(ob,[ev]);
+                       } else {
+                               // set previous coordinates for next time
+                               pX = cX; pY = cY;
+                               // use self-calling timeout, guarantees intervals are spaced out properly (avoids JavaScript timer bugs)
+                               ob.hoverIntent_t = setTimeout( function(){compare(ev, ob);} , cfg.interval );
+                       }
+               };
+
+               // A private function for delaying the mouseOut function
+               var delay = function(ev,ob) {
+                       ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
+                       ob.hoverIntent_s = 0;
+                       return cfg.out.apply(ob,[ev]);
+               };
+
+               // A private function for handling mouse 'hovering'
+               var handleHover = function(e) {
+                       // next three lines copied from jQuery.hover, ignore children onMouseOver/onMouseOut
+                       var p = (e.type == "mouseover" ? e.fromElement : e.toElement) || e.relatedTarget;
+                       while ( p && p != this ) { try { p = p.parentNode; } catch(e) { p = this; } }
+                       if ( p == this ) { return false; }
+
+                       // copy objects to be passed into t (required for event object to be passed in IE)
+                       var ev = jQuery.extend({},e);
+                       var ob = this;
+
+                       // cancel hoverIntent timer if it exists
+                       if (ob.hoverIntent_t) { ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); }
+
+                       // else e.type == "onmouseover"
+                       if (e.type == "mouseover") {
+                               // set "previous" X and Y position based on initial entry point
+                               pX = ev.pageX; pY = ev.pageY;
+                               // update "current" X and Y position based on mousemove
+                               $(ob).bind("mousemove",track);
+                               // start polling interval (self-calling timeout) to compare mouse coordinates over time
+                               if (ob.hoverIntent_s != 1) { ob.hoverIntent_t = setTimeout( function(){compare(ev,ob);} , cfg.interval );}
+
+                       // else e.type == "onmouseout"
+                       } else {
+                               // unbind expensive mousemove event
+                               $(ob).unbind("mousemove",track);
+                               // if hoverIntent state is true, then call the mouseOut function after the specified delay
+                               if (ob.hoverIntent_s == 1) { ob.hoverIntent_t = setTimeout( function(){delay(ev,ob);} , cfg.timeout );}
+                       }
+               };
+
+               // bind the function to the two event listeners
+               return this.mouseover(handleHover).mouseout(handleHover);
+       };
+})(jQuery);
\ No newline at end of file
diff --git a/resources/lib/jquery.jStorage.js b/resources/lib/jquery.jStorage.js
deleted file mode 100644 (file)
index 45e19ac..0000000
+++ /dev/null
@@ -1,996 +0,0 @@
-/*
- * ----------------------------- JSTORAGE -------------------------------------
- * Simple local storage wrapper to save data on the browser side, supporting
- * all major browsers - IE6+, Firefox2+, Safari4+, Chrome4+ and Opera 10.5+
- *
- * Author: Andris Reinman, andris.reinman@gmail.com
- * Project homepage: www.jstorage.info
- *
- * Licensed under Unlicense:
- *
- * This is free and unencumbered software released into the public domain.
- *
- * Anyone is free to copy, modify, publish, use, compile, sell, or
- * distribute this software, either in source code form or as a compiled
- * binary, for any purpose, commercial or non-commercial, and by any
- * means.
- *
- * In jurisdictions that recognize copyright laws, the author or authors
- * of this software dedicate any and all copyright interest in the
- * software to the public domain. We make this dedication for the benefit
- * of the public at large and to the detriment of our heirs and
- * successors. We intend this dedication to be an overt act of
- * relinquishment in perpetuity of all present and future rights to this
- * software under copyright law.
- *
- * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * For more information, please refer to <http://unlicense.org/>
- */
-
-/* global ActiveXObject: false */
-/* jshint browser: true */
-
-(function() {
-    'use strict';
-
-    var
-    /* jStorage version */
-        JSTORAGE_VERSION = '0.4.12',
-
-        /* detect a dollar object or create one if not found */
-        $ = window.jQuery || window.$ || (window.$ = {}),
-
-        /* check for a JSON handling support */
-        JSON = {
-            parse: window.JSON && (window.JSON.parse || window.JSON.decode) ||
-                String.prototype.evalJSON && function(str) {
-                    return String(str).evalJSON();
-            } ||
-                $.parseJSON ||
-                $.evalJSON,
-            stringify: Object.toJSON ||
-                window.JSON && (window.JSON.stringify || window.JSON.encode) ||
-                $.toJSON
-        };
-
-    // Break if no JSON support was found
-    if (typeof JSON.parse !== 'function' || typeof JSON.stringify !== 'function') {
-        throw new Error('No JSON support found, include //cdnjs.cloudflare.com/ajax/libs/json2/20110223/json2.js to page');
-    }
-
-    var
-    /* This is the object, that holds the cached values */
-        _storage = {
-            __jstorage_meta: {
-                CRC32: {}
-            }
-        },
-
-        /* Actual browser storage (localStorage or globalStorage['domain']) */
-        _storage_service = {
-            jStorage: '{}'
-        },
-
-        /* DOM element for older IE versions, holds userData behavior */
-        _storage_elm = null,
-
-        /* How much space does the storage take */
-        _storage_size = 0,
-
-        /* which backend is currently used */
-        _backend = false,
-
-        /* onchange observers */
-        _observers = {},
-
-        /* timeout to wait after onchange event */
-        _observer_timeout = false,
-
-        /* last update time */
-        _observer_update = 0,
-
-        /* pubsub observers */
-        _pubsub_observers = {},
-
-        /* skip published items older than current timestamp */
-        _pubsub_last = +new Date(),
-
-        /* Next check for TTL */
-        _ttl_timeout,
-
-        /**
-         * XML encoding and decoding as XML nodes can't be JSON'ized
-         * XML nodes are encoded and decoded if the node is the value to be saved
-         * but not if it's as a property of another object
-         * Eg. -
-         *   $.jStorage.set('key', xmlNode);        // IS OK
-         *   $.jStorage.set('key', {xml: xmlNode}); // NOT OK
-         */
-        _XMLService = {
-
-            /**
-             * Validates a XML node to be XML
-             * based on jQuery.isXML function
-             */
-            isXML: function(elm) {
-                var documentElement = (elm ? elm.ownerDocument || elm : 0).documentElement;
-                return documentElement ? documentElement.nodeName !== 'HTML' : false;
-            },
-
-            /**
-             * Encodes a XML node to string
-             * based on http://www.mercurytide.co.uk/news/article/issues-when-working-ajax/
-             */
-            encode: function(xmlNode) {
-                if (!this.isXML(xmlNode)) {
-                    return false;
-                }
-                try { // Mozilla, Webkit, Opera
-                    return new XMLSerializer().serializeToString(xmlNode);
-                } catch (E1) {
-                    try { // IE
-                        return xmlNode.xml;
-                    } catch (E2) {}
-                }
-                return false;
-            },
-
-            /**
-             * Decodes a XML node from string
-             * loosely based on http://outwestmedia.com/jquery-plugins/xmldom/
-             */
-            decode: function(xmlString) {
-                var dom_parser = ('DOMParser' in window && (new DOMParser()).parseFromString) ||
-                    (window.ActiveXObject && function(_xmlString) {
-                        var xml_doc = new ActiveXObject('Microsoft.XMLDOM');
-                        xml_doc.async = 'false';
-                        xml_doc.loadXML(_xmlString);
-                        return xml_doc;
-                    }),
-                    resultXML;
-                if (!dom_parser) {
-                    return false;
-                }
-                resultXML = dom_parser.call('DOMParser' in window && (new DOMParser()) || window, xmlString, 'text/xml');
-                return this.isXML(resultXML) ? resultXML : false;
-            }
-        };
-
-
-    ////////////////////////// PRIVATE METHODS ////////////////////////
-
-    /**
-     * Initialization function. Detects if the browser supports DOM Storage
-     * or userData behavior and behaves accordingly.
-     */
-    function _init() {
-        /* Check if browser supports localStorage */
-        var localStorageReallyWorks = false;
-        if ('localStorage' in window) {
-            try {
-                window.localStorage.setItem('_tmptest', 'tmpval');
-                localStorageReallyWorks = true;
-                window.localStorage.removeItem('_tmptest');
-            } catch (BogusQuotaExceededErrorOnIos5) {
-                // Thanks be to iOS5 Private Browsing mode which throws
-                // QUOTA_EXCEEDED_ERRROR DOM Exception 22.
-            }
-        }
-
-        if (localStorageReallyWorks) {
-            try {
-                if (window.localStorage) {
-                    _storage_service = window.localStorage;
-                    _backend = 'localStorage';
-                    _observer_update = _storage_service.jStorage_update;
-                }
-            } catch (E3) { /* Firefox fails when touching localStorage and cookies are disabled */ }
-        }
-        /* Check if browser supports globalStorage */
-        else if ('globalStorage' in window) {
-            try {
-                if (window.globalStorage) {
-                    if (window.location.hostname == 'localhost') {
-                        _storage_service = window.globalStorage['localhost.localdomain'];
-                    } else {
-                        _storage_service = window.globalStorage[window.location.hostname];
-                    }
-                    _backend = 'globalStorage';
-                    _observer_update = _storage_service.jStorage_update;
-                }
-            } catch (E4) { /* Firefox fails when touching localStorage and cookies are disabled */ }
-        }
-        /* Check if browser supports userData behavior */
-        else {
-            _storage_elm = document.createElement('link');
-            if (_storage_elm.addBehavior) {
-
-                /* Use a DOM element to act as userData storage */
-                _storage_elm.style.behavior = 'url(#default#userData)';
-
-                /* userData element needs to be inserted into the DOM! */
-                document.getElementsByTagName('head')[0].appendChild(_storage_elm);
-
-                try {
-                    _storage_elm.load('jStorage');
-                } catch (E) {
-                    // try to reset cache
-                    _storage_elm.setAttribute('jStorage', '{}');
-                    _storage_elm.save('jStorage');
-                    _storage_elm.load('jStorage');
-                }
-
-                var data = '{}';
-                try {
-                    data = _storage_elm.getAttribute('jStorage');
-                } catch (E5) {}
-
-                try {
-                    _observer_update = _storage_elm.getAttribute('jStorage_update');
-                } catch (E6) {}
-
-                _storage_service.jStorage = data;
-                _backend = 'userDataBehavior';
-            } else {
-                _storage_elm = null;
-                return;
-            }
-        }
-
-        // Load data from storage
-        _load_storage();
-
-        // remove dead keys
-        _handleTTL();
-
-        // start listening for changes
-        _setupObserver();
-
-        // initialize publish-subscribe service
-        _handlePubSub();
-
-        // handle cached navigation
-        if ('addEventListener' in window) {
-            window.addEventListener('pageshow', function(event) {
-                if (event.persisted) {
-                    _storageObserver();
-                }
-            }, false);
-        }
-    }
-
-    /**
-     * Reload data from storage when needed
-     */
-    function _reloadData() {
-        var data = '{}';
-
-        if (_backend == 'userDataBehavior') {
-            _storage_elm.load('jStorage');
-
-            try {
-                data = _storage_elm.getAttribute('jStorage');
-            } catch (E5) {}
-
-            try {
-                _observer_update = _storage_elm.getAttribute('jStorage_update');
-            } catch (E6) {}
-
-            _storage_service.jStorage = data;
-        }
-
-        _load_storage();
-
-        // remove dead keys
-        _handleTTL();
-
-        _handlePubSub();
-    }
-
-    /**
-     * Sets up a storage change observer
-     */
-    function _setupObserver() {
-        if (_backend == 'localStorage' || _backend == 'globalStorage') {
-            if ('addEventListener' in window) {
-                window.addEventListener('storage', _storageObserver, false);
-            } else {
-                document.attachEvent('onstorage', _storageObserver);
-            }
-        } else if (_backend == 'userDataBehavior') {
-            setInterval(_storageObserver, 1000);
-        }
-    }
-
-    /**
-     * Fired on any kind of data change, needs to check if anything has
-     * really been changed
-     */
-    function _storageObserver() {
-        var updateTime;
-        // cumulate change notifications with timeout
-        clearTimeout(_observer_timeout);
-        _observer_timeout = setTimeout(function() {
-
-            if (_backend == 'localStorage' || _backend == 'globalStorage') {
-                updateTime = _storage_service.jStorage_update;
-            } else if (_backend == 'userDataBehavior') {
-                _storage_elm.load('jStorage');
-                try {
-                    updateTime = _storage_elm.getAttribute('jStorage_update');
-                } catch (E5) {}
-            }
-
-            if (updateTime && updateTime != _observer_update) {
-                _observer_update = updateTime;
-                _checkUpdatedKeys();
-            }
-
-        }, 25);
-    }
-
-    /**
-     * Reloads the data and checks if any keys are changed
-     */
-    function _checkUpdatedKeys() {
-        var oldCrc32List = JSON.parse(JSON.stringify(_storage.__jstorage_meta.CRC32)),
-            newCrc32List;
-
-        _reloadData();
-        newCrc32List = JSON.parse(JSON.stringify(_storage.__jstorage_meta.CRC32));
-
-        var key,
-            updated = [],
-            removed = [];
-
-        for (key in oldCrc32List) {
-            if (oldCrc32List.hasOwnProperty(key)) {
-                if (!newCrc32List[key]) {
-                    removed.push(key);
-                    continue;
-                }
-                if (oldCrc32List[key] != newCrc32List[key] && String(oldCrc32List[key]).substr(0, 2) == '2.') {
-                    updated.push(key);
-                }
-            }
-        }
-
-        for (key in newCrc32List) {
-            if (newCrc32List.hasOwnProperty(key)) {
-                if (!oldCrc32List[key]) {
-                    updated.push(key);
-                }
-            }
-        }
-
-        _fireObservers(updated, 'updated');
-        _fireObservers(removed, 'deleted');
-    }
-
-    /**
-     * Fires observers for updated keys
-     *
-     * @param {Array|String} keys Array of key names or a key
-     * @param {String} action What happened with the value (updated, deleted, flushed)
-     */
-    function _fireObservers(keys, action) {
-        keys = [].concat(keys || []);
-
-        var i, j, len, jlen;
-
-        if (action == 'flushed') {
-            keys = [];
-            for (var key in _observers) {
-                if (_observers.hasOwnProperty(key)) {
-                    keys.push(key);
-                }
-            }
-            action = 'deleted';
-        }
-        for (i = 0, len = keys.length; i < len; i++) {
-            if (_observers[keys[i]]) {
-                for (j = 0, jlen = _observers[keys[i]].length; j < jlen; j++) {
-                    _observers[keys[i]][j](keys[i], action);
-                }
-            }
-            if (_observers['*']) {
-                for (j = 0, jlen = _observers['*'].length; j < jlen; j++) {
-                    _observers['*'][j](keys[i], action);
-                }
-            }
-        }
-    }
-
-    /**
-     * Publishes key change to listeners
-     */
-    function _publishChange() {
-        var updateTime = (+new Date()).toString();
-
-        if (_backend == 'localStorage' || _backend == 'globalStorage') {
-            try {
-                _storage_service.jStorage_update = updateTime;
-            } catch (E8) {
-                // safari private mode has been enabled after the jStorage initialization
-                _backend = false;
-            }
-        } else if (_backend == 'userDataBehavior') {
-            _storage_elm.setAttribute('jStorage_update', updateTime);
-            _storage_elm.save('jStorage');
-        }
-
-        _storageObserver();
-    }
-
-    /**
-     * Loads the data from the storage based on the supported mechanism
-     */
-    function _load_storage() {
-        /* if jStorage string is retrieved, then decode it */
-        if (_storage_service.jStorage) {
-            try {
-                _storage = JSON.parse(String(_storage_service.jStorage));
-            } catch (E6) {
-                _storage_service.jStorage = '{}';
-            }
-        } else {
-            _storage_service.jStorage = '{}';
-        }
-        _storage_size = _storage_service.jStorage ? String(_storage_service.jStorage).length : 0;
-
-        if (!_storage.__jstorage_meta) {
-            _storage.__jstorage_meta = {};
-        }
-        if (!_storage.__jstorage_meta.CRC32) {
-            _storage.__jstorage_meta.CRC32 = {};
-        }
-    }
-
-    /**
-     * This functions provides the 'save' mechanism to store the jStorage object
-     */
-    function _save() {
-        _dropOldEvents(); // remove expired events
-        try {
-            _storage_service.jStorage = JSON.stringify(_storage);
-            // If userData is used as the storage engine, additional
-            if (_storage_elm) {
-                _storage_elm.setAttribute('jStorage', _storage_service.jStorage);
-                _storage_elm.save('jStorage');
-            }
-            _storage_size = _storage_service.jStorage ? String(_storage_service.jStorage).length : 0;
-        } catch (E7) { /* probably cache is full, nothing is saved this way*/ }
-    }
-
-    /**
-     * Function checks if a key is set and is string or numberic
-     *
-     * @param {String} key Key name
-     */
-    function _checkKey(key) {
-        if (typeof key != 'string' && typeof key != 'number') {
-            throw new TypeError('Key name must be string or numeric');
-        }
-        if (key == '__jstorage_meta') {
-            throw new TypeError('Reserved key name');
-        }
-        return true;
-    }
-
-    /**
-     * Removes expired keys
-     */
-    function _handleTTL() {
-        var curtime, i, TTL, CRC32, nextExpire = Infinity,
-            changed = false,
-            deleted = [];
-
-        clearTimeout(_ttl_timeout);
-
-        if (!_storage.__jstorage_meta || typeof _storage.__jstorage_meta.TTL != 'object') {
-            // nothing to do here
-            return;
-        }
-
-        curtime = +new Date();
-        TTL = _storage.__jstorage_meta.TTL;
-
-        CRC32 = _storage.__jstorage_meta.CRC32;
-        for (i in TTL) {
-            if (TTL.hasOwnProperty(i)) {
-                if (TTL[i] <= curtime) {
-                    delete TTL[i];
-                    delete CRC32[i];
-                    delete _storage[i];
-                    changed = true;
-                    deleted.push(i);
-                } else if (TTL[i] < nextExpire) {
-                    nextExpire = TTL[i];
-                }
-            }
-        }
-
-        // set next check
-        if (nextExpire != Infinity) {
-            _ttl_timeout = setTimeout(_handleTTL, Math.min(nextExpire - curtime, 0x7FFFFFFF));
-        }
-
-        // save changes
-        if (changed) {
-            _save();
-            _publishChange();
-            _fireObservers(deleted, 'deleted');
-        }
-    }
-
-    /**
-     * Checks if there's any events on hold to be fired to listeners
-     */
-    function _handlePubSub() {
-        var i, len;
-        if (!_storage.__jstorage_meta.PubSub) {
-            return;
-        }
-        var pubelm,
-            _pubsubCurrent = _pubsub_last,
-            needFired = [];
-
-        for (i = len = _storage.__jstorage_meta.PubSub.length - 1; i >= 0; i--) {
-            pubelm = _storage.__jstorage_meta.PubSub[i];
-            if (pubelm[0] > _pubsub_last) {
-                _pubsubCurrent = pubelm[0];
-                needFired.unshift(pubelm);
-            }
-        }
-
-        for (i = needFired.length - 1; i >= 0; i--) {
-            _fireSubscribers(needFired[i][1], needFired[i][2]);
-        }
-
-        _pubsub_last = _pubsubCurrent;
-    }
-
-    /**
-     * Fires all subscriber listeners for a pubsub channel
-     *
-     * @param {String} channel Channel name
-     * @param {Mixed} payload Payload data to deliver
-     */
-    function _fireSubscribers(channel, payload) {
-        if (_pubsub_observers[channel]) {
-            for (var i = 0, len = _pubsub_observers[channel].length; i < len; i++) {
-                // send immutable data that can't be modified by listeners
-                try {
-                    _pubsub_observers[channel][i](channel, JSON.parse(JSON.stringify(payload)));
-                } catch (E) {}
-            }
-        }
-    }
-
-    /**
-     * Remove old events from the publish stream (at least 2sec old)
-     */
-    function _dropOldEvents() {
-        if (!_storage.__jstorage_meta.PubSub) {
-            return;
-        }
-
-        var retire = +new Date() - 2000;
-
-        for (var i = 0, len = _storage.__jstorage_meta.PubSub.length; i < len; i++) {
-            if (_storage.__jstorage_meta.PubSub[i][0] <= retire) {
-                // deleteCount is needed for IE6
-                _storage.__jstorage_meta.PubSub.splice(i, _storage.__jstorage_meta.PubSub.length - i);
-                break;
-            }
-        }
-
-        if (!_storage.__jstorage_meta.PubSub.length) {
-            delete _storage.__jstorage_meta.PubSub;
-        }
-
-    }
-
-    /**
-     * Publish payload to a channel
-     *
-     * @param {String} channel Channel name
-     * @param {Mixed} payload Payload to send to the subscribers
-     */
-    function _publish(channel, payload) {
-        if (!_storage.__jstorage_meta) {
-            _storage.__jstorage_meta = {};
-        }
-        if (!_storage.__jstorage_meta.PubSub) {
-            _storage.__jstorage_meta.PubSub = [];
-        }
-
-        _storage.__jstorage_meta.PubSub.unshift([+new Date(), channel, payload]);
-
-        _save();
-        _publishChange();
-    }
-
-
-    /**
-     * JS Implementation of MurmurHash2
-     *
-     *  SOURCE: https://github.com/garycourt/murmurhash-js (MIT licensed)
-     *
-     * @author <a href='mailto:gary.court@gmail.com'>Gary Court</a>
-     * @see http://github.com/garycourt/murmurhash-js
-     * @author <a href='mailto:aappleby@gmail.com'>Austin Appleby</a>
-     * @see http://sites.google.com/site/murmurhash/
-     *
-     * @param {string} str ASCII only
-     * @param {number} seed Positive integer only
-     * @return {number} 32-bit positive integer hash
-     */
-
-    function murmurhash2_32_gc(str, seed) {
-        var
-            l = str.length,
-            h = seed ^ l,
-            i = 0,
-            k;
-
-        while (l >= 4) {
-            k =
-                ((str.charCodeAt(i) & 0xff)) |
-                ((str.charCodeAt(++i) & 0xff) << 8) |
-                ((str.charCodeAt(++i) & 0xff) << 16) |
-                ((str.charCodeAt(++i) & 0xff) << 24);
-
-            k = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16));
-            k ^= k >>> 24;
-            k = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16));
-
-            h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16)) ^ k;
-
-            l -= 4;
-            ++i;
-        }
-
-        switch (l) {
-            case 3:
-                h ^= (str.charCodeAt(i + 2) & 0xff) << 16;
-                /* falls through */
-            case 2:
-                h ^= (str.charCodeAt(i + 1) & 0xff) << 8;
-                /* falls through */
-            case 1:
-                h ^= (str.charCodeAt(i) & 0xff);
-                h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));
-        }
-
-        h ^= h >>> 13;
-        h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));
-        h ^= h >>> 15;
-
-        return h >>> 0;
-    }
-
-    ////////////////////////// PUBLIC INTERFACE /////////////////////////
-
-    $.jStorage = {
-        /* Version number */
-        version: JSTORAGE_VERSION,
-
-        /**
-         * Sets a key's value.
-         *
-         * @param {String} key Key to set. If this value is not set or not
-         *              a string an exception is raised.
-         * @param {Mixed} value Value to set. This can be any value that is JSON
-         *              compatible (Numbers, Strings, Objects etc.).
-         * @param {Object} [options] - possible options to use
-         * @param {Number} [options.TTL] - optional TTL value, in milliseconds
-         * @return {Mixed} the used value
-         */
-        set: function(key, value, options) {
-            _checkKey(key);
-
-            options = options || {};
-
-            // undefined values are deleted automatically
-            if (typeof value == 'undefined') {
-                this.deleteKey(key);
-                return value;
-            }
-
-            if (_XMLService.isXML(value)) {
-                value = {
-                    _is_xml: true,
-                    xml: _XMLService.encode(value)
-                };
-            } else if (typeof value == 'function') {
-                return undefined; // functions can't be saved!
-            } else if (value && typeof value == 'object') {
-                // clone the object before saving to _storage tree
-                value = JSON.parse(JSON.stringify(value));
-            }
-
-            _storage[key] = value;
-
-            _storage.__jstorage_meta.CRC32[key] = '2.' + murmurhash2_32_gc(JSON.stringify(value), 0x9747b28c);
-
-            this.setTTL(key, options.TTL || 0); // also handles saving and _publishChange
-
-            _fireObservers(key, 'updated');
-            return value;
-        },
-
-        /**
-         * Looks up a key in cache
-         *
-         * @param {String} key - Key to look up.
-         * @param {mixed} def - Default value to return, if key didn't exist.
-         * @return {Mixed} the key value, default value or null
-         */
-        get: function(key, def) {
-            _checkKey(key);
-            if (key in _storage) {
-                if (_storage[key] && typeof _storage[key] == 'object' && _storage[key]._is_xml) {
-                    return _XMLService.decode(_storage[key].xml);
-                } else {
-                    return _storage[key];
-                }
-            }
-            return typeof(def) == 'undefined' ? null : def;
-        },
-
-        /**
-         * Deletes a key from cache.
-         *
-         * @param {String} key - Key to delete.
-         * @return {Boolean} true if key existed or false if it didn't
-         */
-        deleteKey: function(key) {
-            _checkKey(key);
-            if (key in _storage) {
-                delete _storage[key];
-                // remove from TTL list
-                if (typeof _storage.__jstorage_meta.TTL == 'object' &&
-                    key in _storage.__jstorage_meta.TTL) {
-                    delete _storage.__jstorage_meta.TTL[key];
-                }
-
-                delete _storage.__jstorage_meta.CRC32[key];
-
-                _save();
-                _publishChange();
-                _fireObservers(key, 'deleted');
-                return true;
-            }
-            return false;
-        },
-
-        /**
-         * Sets a TTL for a key, or remove it if ttl value is 0 or below
-         *
-         * @param {String} key - key to set the TTL for
-         * @param {Number} ttl - TTL timeout in milliseconds
-         * @return {Boolean} true if key existed or false if it didn't
-         */
-        setTTL: function(key, ttl) {
-            var curtime = +new Date();
-            _checkKey(key);
-            ttl = Number(ttl) || 0;
-            if (key in _storage) {
-
-                if (!_storage.__jstorage_meta.TTL) {
-                    _storage.__jstorage_meta.TTL = {};
-                }
-
-                // Set TTL value for the key
-                if (ttl > 0) {
-                    _storage.__jstorage_meta.TTL[key] = curtime + ttl;
-                } else {
-                    delete _storage.__jstorage_meta.TTL[key];
-                }
-
-                _save();
-
-                _handleTTL();
-
-                _publishChange();
-                return true;
-            }
-            return false;
-        },
-
-        /**
-         * Gets remaining TTL (in milliseconds) for a key or 0 when no TTL has been set
-         *
-         * @param {String} key Key to check
-         * @return {Number} Remaining TTL in milliseconds
-         */
-        getTTL: function(key) {
-            var curtime = +new Date(),
-                ttl;
-            _checkKey(key);
-            if (key in _storage && _storage.__jstorage_meta.TTL && _storage.__jstorage_meta.TTL[key]) {
-                ttl = _storage.__jstorage_meta.TTL[key] - curtime;
-                return ttl || 0;
-            }
-            return 0;
-        },
-
-        /**
-         * Deletes everything in cache.
-         *
-         * @return {Boolean} Always true
-         */
-        flush: function() {
-            _storage = {
-                __jstorage_meta: {
-                    CRC32: {}
-                }
-            };
-            _save();
-            _publishChange();
-            _fireObservers(null, 'flushed');
-            return true;
-        },
-
-        /**
-         * Returns a read-only copy of _storage
-         *
-         * @return {Object} Read-only copy of _storage
-         */
-        storageObj: function() {
-            function F() {}
-            F.prototype = _storage;
-            return new F();
-        },
-
-        /**
-         * Returns an index of all used keys as an array
-         * ['key1', 'key2',..'keyN']
-         *
-         * @return {Array} Used keys
-         */
-        index: function() {
-            var index = [],
-                i;
-            for (i in _storage) {
-                if (_storage.hasOwnProperty(i) && i != '__jstorage_meta') {
-                    index.push(i);
-                }
-            }
-            return index;
-        },
-
-        /**
-         * How much space in bytes does the storage take?
-         *
-         * @return {Number} Storage size in chars (not the same as in bytes,
-         *                  since some chars may take several bytes)
-         */
-        storageSize: function() {
-            return _storage_size;
-        },
-
-        /**
-         * Which backend is currently in use?
-         *
-         * @return {String} Backend name
-         */
-        currentBackend: function() {
-            return _backend;
-        },
-
-        /**
-         * Test if storage is available
-         *
-         * @return {Boolean} True if storage can be used
-         */
-        storageAvailable: function() {
-            return !!_backend;
-        },
-
-        /**
-         * Register change listeners
-         *
-         * @param {String} key Key name
-         * @param {Function} callback Function to run when the key changes
-         */
-        listenKeyChange: function(key, callback) {
-            _checkKey(key);
-            if (!_observers[key]) {
-                _observers[key] = [];
-            }
-            _observers[key].push(callback);
-        },
-
-        /**
-         * Remove change listeners
-         *
-         * @param {String} key Key name to unregister listeners against
-         * @param {Function} [callback] If set, unregister the callback, if not - unregister all
-         */
-        stopListening: function(key, callback) {
-            _checkKey(key);
-
-            if (!_observers[key]) {
-                return;
-            }
-
-            if (!callback) {
-                delete _observers[key];
-                return;
-            }
-
-            for (var i = _observers[key].length - 1; i >= 0; i--) {
-                if (_observers[key][i] == callback) {
-                    _observers[key].splice(i, 1);
-                }
-            }
-        },
-
-        /**
-         * Subscribe to a Publish/Subscribe event stream
-         *
-         * @param {String} channel Channel name
-         * @param {Function} callback Function to run when the something is published to the channel
-         */
-        subscribe: function(channel, callback) {
-            channel = (channel || '').toString();
-            if (!channel) {
-                throw new TypeError('Channel not defined');
-            }
-            if (!_pubsub_observers[channel]) {
-                _pubsub_observers[channel] = [];
-            }
-            _pubsub_observers[channel].push(callback);
-        },
-
-        /**
-         * Publish data to an event stream
-         *
-         * @param {String} channel Channel name
-         * @param {Mixed} payload Payload to deliver
-         */
-        publish: function(channel, payload) {
-            channel = (channel || '').toString();
-            if (!channel) {
-                throw new TypeError('Channel not defined');
-            }
-
-            _publish(channel, payload);
-        },
-
-        /**
-         * Reloads the data from browser storage
-         */
-        reInit: function() {
-            _reloadData();
-        },
-
-        /**
-         * Removes reference from global objects and saves it as jStorage
-         *
-         * @param {Boolean} option if needed to save object as simple 'jStorage' in windows context
-         */
-        noConflict: function(saveInGlobal) {
-            delete window.$.jStorage;
-
-            if (saveInGlobal) {
-                window.jStorage = this;
-            }
-
-            return this;
-        }
-    };
-
-    // Initialize jStorage
-    _init();
-
-})();
diff --git a/resources/lib/jquery.jStorage/jstorage.js b/resources/lib/jquery.jStorage/jstorage.js
new file mode 100644 (file)
index 0000000..1ac8fcc
--- /dev/null
@@ -0,0 +1,996 @@
+/*
+ * ----------------------------- JSTORAGE -------------------------------------
+ * Simple local storage wrapper to save data on the browser side, supporting
+ * all major browsers - IE6+, Firefox2+, Safari4+, Chrome4+ and Opera 10.5+
+ *
+ * Author: Andris Reinman, andris.reinman@gmail.com
+ * Project homepage: www.jstorage.info
+ *
+ * Licensed under Unlicense:
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org/>
+ */
+
+/* global ActiveXObject: false */
+/* jshint browser: true */
+
+(function() {
+    'use strict';
+
+    var
+    /* jStorage version */
+        JSTORAGE_VERSION = '0.4.12',
+
+        /* detect a dollar object or create one if not found */
+        $ = window.jQuery || window.$ || (window.$ = {}),
+
+        /* check for a JSON handling support */
+        JSON = {
+            parse: window.JSON && (window.JSON.parse || window.JSON.decode) ||
+                String.prototype.evalJSON && function(str) {
+                    return String(str).evalJSON();
+            } ||
+                $.parseJSON ||
+                $.evalJSON,
+            stringify: Object.toJSON ||
+                window.JSON && (window.JSON.stringify || window.JSON.encode) ||
+                $.toJSON
+        };
+
+    // Break if no JSON support was found
+    if (typeof JSON.parse !== 'function' || typeof JSON.stringify !== 'function') {
+        throw new Error('No JSON support found, include //cdnjs.cloudflare.com/ajax/libs/json2/20110223/json2.js to page');
+    }
+
+    var
+    /* This is the object, that holds the cached values */
+        _storage = {
+            __jstorage_meta: {
+                CRC32: {}
+            }
+        },
+
+        /* Actual browser storage (localStorage or globalStorage['domain']) */
+        _storage_service = {
+            jStorage: '{}'
+        },
+
+        /* DOM element for older IE versions, holds userData behavior */
+        _storage_elm = null,
+
+        /* How much space does the storage take */
+        _storage_size = 0,
+
+        /* which backend is currently used */
+        _backend = false,
+
+        /* onchange observers */
+        _observers = {},
+
+        /* timeout to wait after onchange event */
+        _observer_timeout = false,
+
+        /* last update time */
+        _observer_update = 0,
+
+        /* pubsub observers */
+        _pubsub_observers = {},
+
+        /* skip published items older than current timestamp */
+        _pubsub_last = +new Date(),
+
+        /* Next check for TTL */
+        _ttl_timeout,
+
+        /**
+         * XML encoding and decoding as XML nodes can't be JSON'ized
+         * XML nodes are encoded and decoded if the node is the value to be saved
+         * but not if it's as a property of another object
+         * Eg. -
+         *   $.jStorage.set('key', xmlNode);        // IS OK
+         *   $.jStorage.set('key', {xml: xmlNode}); // NOT OK
+         */
+        _XMLService = {
+
+            /**
+             * Validates a XML node to be XML
+             * based on jQuery.isXML function
+             */
+            isXML: function(elm) {
+                var documentElement = (elm ? elm.ownerDocument || elm : 0).documentElement;
+                return documentElement ? documentElement.nodeName !== 'HTML' : false;
+            },
+
+            /**
+             * Encodes a XML node to string
+             * based on http://www.mercurytide.co.uk/news/article/issues-when-working-ajax/
+             */
+            encode: function(xmlNode) {
+                if (!this.isXML(xmlNode)) {
+                    return false;
+                }
+                try { // Mozilla, Webkit, Opera
+                    return new XMLSerializer().serializeToString(xmlNode);
+                } catch (E1) {
+                    try { // IE
+                        return xmlNode.xml;
+                    } catch (E2) {}
+                }
+                return false;
+            },
+
+            /**
+             * Decodes a XML node from string
+             * loosely based on http://outwestmedia.com/jquery-plugins/xmldom/
+             */
+            decode: function(xmlString) {
+                var dom_parser = ('DOMParser' in window && (new DOMParser()).parseFromString) ||
+                    (window.ActiveXObject && function(_xmlString) {
+                        var xml_doc = new ActiveXObject('Microsoft.XMLDOM');
+                        xml_doc.async = 'false';
+                        xml_doc.loadXML(_xmlString);
+                        return xml_doc;
+                    }),
+                    resultXML;
+                if (!dom_parser) {
+                    return false;
+                }
+                resultXML = dom_parser.call('DOMParser' in window && (new DOMParser()) || window, xmlString, 'text/xml');
+                return this.isXML(resultXML) ? resultXML : false;
+            }
+        };
+
+
+    ////////////////////////// PRIVATE METHODS ////////////////////////
+
+    /**
+     * Initialization function. Detects if the browser supports DOM Storage
+     * or userData behavior and behaves accordingly.
+     */
+    function _init() {
+        /* Check if browser supports localStorage */
+        var localStorageReallyWorks = false;
+        if ('localStorage' in window) {
+            try {
+                window.localStorage.setItem('_tmptest', 'tmpval');
+                localStorageReallyWorks = true;
+                window.localStorage.removeItem('_tmptest');
+            } catch (BogusQuotaExceededErrorOnIos5) {
+                // Thanks be to iOS5 Private Browsing mode which throws
+                // QUOTA_EXCEEDED_ERRROR DOM Exception 22.
+            }
+        }
+
+        if (localStorageReallyWorks) {
+            try {
+                if (window.localStorage) {
+                    _storage_service = window.localStorage;
+                    _backend = 'localStorage';
+                    _observer_update = _storage_service.jStorage_update;
+                }
+            } catch (E3) { /* Firefox fails when touching localStorage and cookies are disabled */ }
+        }
+        /* Check if browser supports globalStorage */
+        else if ('globalStorage' in window) {
+            try {
+                if (window.globalStorage) {
+                    if (window.location.hostname == 'localhost') {
+                        _storage_service = window.globalStorage['localhost.localdomain'];
+                    } else {
+                        _storage_service = window.globalStorage[window.location.hostname];
+                    }
+                    _backend = 'globalStorage';
+                    _observer_update = _storage_service.jStorage_update;
+                }
+            } catch (E4) { /* Firefox fails when touching localStorage and cookies are disabled */ }
+        }
+        /* Check if browser supports userData behavior */
+        else {
+            _storage_elm = document.createElement('link');
+            if (_storage_elm.addBehavior) {
+
+                /* Use a DOM element to act as userData storage */
+                _storage_elm.style.behavior = 'url(#default#userData)';
+
+                /* userData element needs to be inserted into the DOM! */
+                document.getElementsByTagName('head')[0].appendChild(_storage_elm);
+
+                try {
+                    _storage_elm.load('jStorage');
+                } catch (E) {
+                    // try to reset cache
+                    _storage_elm.setAttribute('jStorage', '{}');
+                    _storage_elm.save('jStorage');
+                    _storage_elm.load('jStorage');
+                }
+
+                var data = '{}';
+                try {
+                    data = _storage_elm.getAttribute('jStorage');
+                } catch (E5) {}
+
+                try {
+                    _observer_update = _storage_elm.getAttribute('jStorage_update');
+                } catch (E6) {}
+
+                _storage_service.jStorage = data;
+                _backend = 'userDataBehavior';
+            } else {
+                _storage_elm = null;
+                return;
+            }
+        }
+
+        // Load data from storage
+        _load_storage();
+
+        // remove dead keys
+        _handleTTL();
+
+        // start listening for changes
+        _setupObserver();
+
+        // initialize publish-subscribe service
+        _handlePubSub();
+
+        // handle cached navigation
+        if ('addEventListener' in window) {
+            window.addEventListener('pageshow', function(event) {
+                if (event.persisted) {
+                    _storageObserver();
+                }
+            }, false);
+        }
+    }
+
+    /**
+     * Reload data from storage when needed
+     */
+    function _reloadData() {
+        var data = '{}';
+
+        if (_backend == 'userDataBehavior') {
+            _storage_elm.load('jStorage');
+
+            try {
+                data = _storage_elm.getAttribute('jStorage');
+            } catch (E5) {}
+
+            try {
+                _observer_update = _storage_elm.getAttribute('jStorage_update');
+            } catch (E6) {}
+
+            _storage_service.jStorage = data;
+        }
+
+        _load_storage();
+
+        // remove dead keys
+        _handleTTL();
+
+        _handlePubSub();
+    }
+
+    /**
+     * Sets up a storage change observer
+     */
+    function _setupObserver() {
+        if (_backend == 'localStorage' || _backend == 'globalStorage') {
+            if ('addEventListener' in window) {
+                window.addEventListener('storage', _storageObserver, false);
+            } else {
+                document.attachEvent('onstorage', _storageObserver);
+            }
+        } else if (_backend == 'userDataBehavior') {
+            setInterval(_storageObserver, 1000);
+        }
+    }
+
+    /**
+     * Fired on any kind of data change, needs to check if anything has
+     * really been changed
+     */
+    function _storageObserver() {
+        var updateTime;
+        // cumulate change notifications with timeout
+        clearTimeout(_observer_timeout);
+        _observer_timeout = setTimeout(function() {
+
+            if (_backend == 'localStorage' || _backend == 'globalStorage') {
+                updateTime = _storage_service.jStorage_update;
+            } else if (_backend == 'userDataBehavior') {
+                _storage_elm.load('jStorage');
+                try {
+                    updateTime = _storage_elm.getAttribute('jStorage_update');
+                } catch (E5) {}
+            }
+
+            if (updateTime && updateTime != _observer_update) {
+                _observer_update = updateTime;
+                _checkUpdatedKeys();
+            }
+
+        }, 25);
+    }
+
+    /**
+     * Reloads the data and checks if any keys are changed
+     */
+    function _checkUpdatedKeys() {
+        var oldCrc32List = JSON.parse(JSON.stringify(_storage.__jstorage_meta.CRC32)),
+            newCrc32List;
+
+        _reloadData();
+        newCrc32List = JSON.parse(JSON.stringify(_storage.__jstorage_meta.CRC32));
+
+        var key,
+            updated = [],
+            removed = [];
+
+        for (key in oldCrc32List) {
+            if (oldCrc32List.hasOwnProperty(key)) {
+                if (!newCrc32List[key]) {
+                    removed.push(key);
+                    continue;
+                }
+                if (oldCrc32List[key] != newCrc32List[key] && String(oldCrc32List[key]).substr(0, 2) == '2.') {
+                    updated.push(key);
+                }
+            }
+        }
+
+        for (key in newCrc32List) {
+            if (newCrc32List.hasOwnProperty(key)) {
+                if (!oldCrc32List[key]) {
+                    updated.push(key);
+                }
+            }
+        }
+
+        _fireObservers(updated, 'updated');
+        _fireObservers(removed, 'deleted');
+    }
+
+    /**
+     * Fires observers for updated keys
+     *
+     * @param {Array|String} keys Array of key names or a key
+     * @param {String} action What happened with the value (updated, deleted, flushed)
+     */
+    function _fireObservers(keys, action) {
+        keys = [].concat(keys || []);
+
+        var i, j, len, jlen;
+
+        if (action == 'flushed') {
+            keys = [];
+            for (var key in _observers) {
+                if (_observers.hasOwnProperty(key)) {
+                    keys.push(key);
+                }
+            }
+            action = 'deleted';
+        }
+        for (i = 0, len = keys.length; i < len; i++) {
+            if (_observers[keys[i]]) {
+                for (j = 0, jlen = _observers[keys[i]].length; j < jlen; j++) {
+                    _observers[keys[i]][j](keys[i], action);
+                }
+            }
+            if (_observers['*']) {
+                for (j = 0, jlen = _observers['*'].length; j < jlen; j++) {
+                    _observers['*'][j](keys[i], action);
+                }
+            }
+        }
+    }
+
+    /**
+     * Publishes key change to listeners
+     */
+    function _publishChange() {
+        var updateTime = (+new Date()).toString();
+
+        if (_backend == 'localStorage' || _backend == 'globalStorage') {
+            try {
+                _storage_service.jStorage_update = updateTime;
+            } catch (E8) {
+                // safari private mode has been enabled after the jStorage initialization
+                _backend = false;
+            }
+        } else if (_backend == 'userDataBehavior') {
+            _storage_elm.setAttribute('jStorage_update', updateTime);
+            _storage_elm.save('jStorage');
+        }
+
+        _storageObserver();
+    }
+
+    /**
+     * Loads the data from the storage based on the supported mechanism
+     */
+    function _load_storage() {
+        /* if jStorage string is retrieved, then decode it */
+        if (_storage_service.jStorage) {
+            try {
+                _storage = JSON.parse(String(_storage_service.jStorage));
+            } catch (E6) {
+                _storage_service.jStorage = '{}';
+            }
+        } else {
+            _storage_service.jStorage = '{}';
+        }
+        _storage_size = _storage_service.jStorage ? String(_storage_service.jStorage).length : 0;
+
+        if (!_storage.__jstorage_meta) {
+            _storage.__jstorage_meta = {};
+        }
+        if (!_storage.__jstorage_meta.CRC32) {
+            _storage.__jstorage_meta.CRC32 = {};
+        }
+    }
+
+    /**
+     * This functions provides the 'save' mechanism to store the jStorage object
+     */
+    function _save() {
+        _dropOldEvents(); // remove expired events
+        try {
+            _storage_service.jStorage = JSON.stringify(_storage);
+            // If userData is used as the storage engine, additional
+            if (_storage_elm) {
+                _storage_elm.setAttribute('jStorage', _storage_service.jStorage);
+                _storage_elm.save('jStorage');
+            }
+            _storage_size = _storage_service.jStorage ? String(_storage_service.jStorage).length : 0;
+        } catch (E7) { /* probably cache is full, nothing is saved this way*/ }
+    }
+
+    /**
+     * Function checks if a key is set and is string or numberic
+     *
+     * @param {String} key Key name
+     */
+    function _checkKey(key) {
+        if (typeof key != 'string' && typeof key != 'number') {
+            throw new TypeError('Key name must be string or numeric');
+        }
+        if (key == '__jstorage_meta') {
+            throw new TypeError('Reserved key name');
+        }
+        return true;
+    }
+
+    /**
+     * Removes expired keys
+     */
+    function _handleTTL() {
+        var curtime, i, TTL, CRC32, nextExpire = Infinity,
+            changed = false,
+            deleted = [];
+
+        clearTimeout(_ttl_timeout);
+
+        if (!_storage.__jstorage_meta || typeof _storage.__jstorage_meta.TTL != 'object') {
+            // nothing to do here
+            return;
+        }
+
+        curtime = +new Date();
+        TTL = _storage.__jstorage_meta.TTL;
+
+        CRC32 = _storage.__jstorage_meta.CRC32;
+        for (i in TTL) {
+            if (TTL.hasOwnProperty(i)) {
+                if (TTL[i] <= curtime) {
+                    delete TTL[i];
+                    delete CRC32[i];
+                    delete _storage[i];
+                    changed = true;
+                    deleted.push(i);
+                } else if (TTL[i] < nextExpire) {
+                    nextExpire = TTL[i];
+                }
+            }
+        }
+
+        // set next check
+        if (nextExpire != Infinity) {
+            _ttl_timeout = setTimeout(_handleTTL, Math.min(nextExpire - curtime, 0x7FFFFFFF));
+        }
+
+        // save changes
+        if (changed) {
+            _save();
+            _publishChange();
+            _fireObservers(deleted, 'deleted');
+        }
+    }
+
+    /**
+     * Checks if there's any events on hold to be fired to listeners
+     */
+    function _handlePubSub() {
+        var i, len;
+        if (!_storage.__jstorage_meta.PubSub) {
+            return;
+        }
+        var pubelm,
+            _pubsubCurrent = _pubsub_last,
+            needFired = [];
+
+        for (i = len = _storage.__jstorage_meta.PubSub.length - 1; i >= 0; i--) {
+            pubelm = _storage.__jstorage_meta.PubSub[i];
+            if (pubelm[0] > _pubsub_last) {
+                _pubsubCurrent = pubelm[0];
+                needFired.unshift(pubelm);
+            }
+        }
+
+        for (i = needFired.length - 1; i >= 0; i--) {
+            _fireSubscribers(needFired[i][1], needFired[i][2]);
+        }
+
+        _pubsub_last = _pubsubCurrent;
+    }
+
+    /**
+     * Fires all subscriber listeners for a pubsub channel
+     *
+     * @param {String} channel Channel name
+     * @param {Mixed} payload Payload data to deliver
+     */
+    function _fireSubscribers(channel, payload) {
+        if (_pubsub_observers[channel]) {
+            for (var i = 0, len = _pubsub_observers[channel].length; i < len; i++) {
+                // send immutable data that can't be modified by listeners
+                try {
+                    _pubsub_observers[channel][i](channel, JSON.parse(JSON.stringify(payload)));
+                } catch (E) {}
+            }
+        }
+    }
+
+    /**
+     * Remove old events from the publish stream (at least 2sec old)
+     */
+    function _dropOldEvents() {
+        if (!_storage.__jstorage_meta.PubSub) {
+            return;
+        }
+
+        var retire = +new Date() - 2000;
+
+        for (var i = 0, len = _storage.__jstorage_meta.PubSub.length; i < len; i++) {
+            if (_storage.__jstorage_meta.PubSub[i][0] <= retire) {
+                // deleteCount is needed for IE6
+                _storage.__jstorage_meta.PubSub.splice(i, _storage.__jstorage_meta.PubSub.length - i);
+                break;
+            }
+        }
+
+        if (!_storage.__jstorage_meta.PubSub.length) {
+            delete _storage.__jstorage_meta.PubSub;
+        }
+
+    }
+
+    /**
+     * Publish payload to a channel
+     *
+     * @param {String} channel Channel name
+     * @param {Mixed} payload Payload to send to the subscribers
+     */
+    function _publish(channel, payload) {
+        if (!_storage.__jstorage_meta) {
+            _storage.__jstorage_meta = {};
+        }
+        if (!_storage.__jstorage_meta.PubSub) {
+            _storage.__jstorage_meta.PubSub = [];
+        }
+
+        _storage.__jstorage_meta.PubSub.unshift([+new Date(), channel, payload]);
+
+        _save();
+        _publishChange();
+    }
+
+
+    /**
+     * JS Implementation of MurmurHash2
+     *
+     *  SOURCE: https://github.com/garycourt/murmurhash-js (MIT licensed)
+     *
+     * @author <a href='mailto:gary.court@gmail.com'>Gary Court</a>
+     * @see http://github.com/garycourt/murmurhash-js
+     * @author <a href='mailto:aappleby@gmail.com'>Austin Appleby</a>
+     * @see http://sites.google.com/site/murmurhash/
+     *
+     * @param {string} str ASCII only
+     * @param {number} seed Positive integer only
+     * @return {number} 32-bit positive integer hash
+     */
+
+    function murmurhash2_32_gc(str, seed) {
+        var
+            l = str.length,
+            h = seed ^ l,
+            i = 0,
+            k;
+
+        while (l >= 4) {
+            k =
+                ((str.charCodeAt(i) & 0xff)) |
+                ((str.charCodeAt(++i) & 0xff) << 8) |
+                ((str.charCodeAt(++i) & 0xff) << 16) |
+                ((str.charCodeAt(++i) & 0xff) << 24);
+
+            k = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16));
+            k ^= k >>> 24;
+            k = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16));
+
+            h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16)) ^ k;
+
+            l -= 4;
+            ++i;
+        }
+
+        switch (l) {
+            case 3:
+                h ^= (str.charCodeAt(i + 2) & 0xff) << 16;
+                /* falls through */
+            case 2:
+                h ^= (str.charCodeAt(i + 1) & 0xff) << 8;
+                /* falls through */
+            case 1:
+                h ^= (str.charCodeAt(i) & 0xff);
+                h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));
+        }
+
+        h ^= h >>> 13;
+        h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));
+        h ^= h >>> 15;
+
+        return h >>> 0;
+    }
+
+    ////////////////////////// PUBLIC INTERFACE /////////////////////////
+
+    $.jStorage = {
+        /* Version number */
+        version: JSTORAGE_VERSION,
+
+        /**
+         * Sets a key's value.
+         *
+         * @param {String} key Key to set. If this value is not set or not
+         *              a string an exception is raised.
+         * @param {Mixed} value Value to set. This can be any value that is JSON
+         *              compatible (Numbers, Strings, Objects etc.).
+         * @param {Object} [options] - possible options to use
+         * @param {Number} [options.TTL] - optional TTL value, in milliseconds
+         * @return {Mixed} the used value
+         */
+        set: function(key, value, options) {
+            _checkKey(key);
+
+            options = options || {};
+
+            // undefined values are deleted automatically
+            if (typeof value == 'undefined') {
+                this.deleteKey(key);
+                return value;
+            }
+
+            if (_XMLService.isXML(value)) {
+                value = {
+                    _is_xml: true,
+                    xml: _XMLService.encode(value)
+                };
+            } else if (typeof value == 'function') {
+                return undefined; // functions can't be saved!
+            } else if (value && typeof value == 'object') {
+                // clone the object before saving to _storage tree
+                value = JSON.parse(JSON.stringify(value));
+            }
+
+            _storage[key] = value;
+
+            _storage.__jstorage_meta.CRC32[key] = '2.' + murmurhash2_32_gc(JSON.stringify(value), 0x9747b28c);
+
+            this.setTTL(key, options.TTL || 0); // also handles saving and _publishChange
+
+            _fireObservers(key, 'updated');
+            return value;
+        },
+
+        /**
+         * Looks up a key in cache
+         *
+         * @param {String} key - Key to look up.
+         * @param {mixed} def - Default value to return, if key didn't exist.
+         * @return {Mixed} the key value, default value or null
+         */
+        get: function(key, def) {
+            _checkKey(key);
+            if (key in _storage) {
+                if (_storage[key] && typeof _storage[key] == 'object' && _storage[key]._is_xml) {
+                    return _XMLService.decode(_storage[key].xml);
+                } else {
+                    return _storage[key];
+                }
+            }
+            return typeof(def) == 'undefined' ? null : def;
+        },
+
+        /**
+         * Deletes a key from cache.
+         *
+         * @param {String} key - Key to delete.
+         * @return {Boolean} true if key existed or false if it didn't
+         */
+        deleteKey: function(key) {
+            _checkKey(key);
+            if (key in _storage) {
+                delete _storage[key];
+                // remove from TTL list
+                if (typeof _storage.__jstorage_meta.TTL == 'object' &&
+                    key in _storage.__jstorage_meta.TTL) {
+                    delete _storage.__jstorage_meta.TTL[key];
+                }
+
+                delete _storage.__jstorage_meta.CRC32[key];
+
+                _save();
+                _publishChange();
+                _fireObservers(key, 'deleted');
+                return true;
+            }
+            return false;
+        },
+
+        /**
+         * Sets a TTL for a key, or remove it if ttl value is 0 or below
+         *
+         * @param {String} key - key to set the TTL for
+         * @param {Number} ttl - TTL timeout in milliseconds
+         * @return {Boolean} true if key existed or false if it didn't
+         */
+        setTTL: function(key, ttl) {
+            var curtime = +new Date();
+            _checkKey(key);
+            ttl = Number(ttl) || 0;
+            if (key in _storage) {
+
+                if (!_storage.__jstorage_meta.TTL) {
+                    _storage.__jstorage_meta.TTL = {};
+                }
+
+                // Set TTL value for the key
+                if (ttl > 0) {
+                    _storage.__jstorage_meta.TTL[key] = curtime + ttl;
+                } else {
+                    delete _storage.__jstorage_meta.TTL[key];
+                }
+
+                _save();
+
+                _handleTTL();
+
+                _publishChange();
+                return true;
+            }
+            return false;
+        },
+
+        /**
+         * Gets remaining TTL (in milliseconds) for a key or 0 when no TTL has been set
+         *
+         * @param {String} key Key to check
+         * @return {Number} Remaining TTL in milliseconds
+         */
+        getTTL: function(key) {
+            var curtime = +new Date(),
+                ttl;
+            _checkKey(key);
+            if (key in _storage && _storage.__jstorage_meta.TTL && _storage.__jstorage_meta.TTL[key]) {
+                ttl = _storage.__jstorage_meta.TTL[key] - curtime;
+                return ttl || 0;
+            }
+            return 0;
+        },
+
+        /**
+         * Deletes everything in cache.
+         *
+         * @return {Boolean} Always true
+         */
+        flush: function() {
+            _storage = {
+                __jstorage_meta: {
+                    CRC32: {}
+                }
+            };
+            _save();
+            _publishChange();
+            _fireObservers(null, 'flushed');
+            return true;
+        },
+
+        /**
+         * Returns a read-only copy of _storage
+         *
+         * @return {Object} Read-only copy of _storage
+         */
+        storageObj: function() {
+            function F() {}
+            F.prototype = _storage;
+            return new F();
+        },
+
+        /**
+         * Returns an index of all used keys as an array
+         * ['key1', 'key2',..'keyN']
+         *
+         * @return {Array} Used keys
+         */
+        index: function() {
+            var index = [],
+                i;
+            for (i in _storage) {
+                if (_storage.hasOwnProperty(i) && i != '__jstorage_meta') {
+                    index.push(i);
+                }
+            }
+            return index;
+        },
+
+        /**
+         * How much space in bytes does the storage take?
+         *
+         * @return {Number} Storage size in chars (not the same as in bytes,
+         *                  since some chars may take several bytes)
+         */
+        storageSize: function() {
+            return _storage_size;
+        },
+
+        /**
+         * Which backend is currently in use?
+         *
+         * @return {String} Backend name
+         */
+        currentBackend: function() {
+            return _backend;
+        },
+
+        /**
+         * Test if storage is available
+         *
+         * @return {Boolean} True if storage can be used
+         */
+        storageAvailable: function() {
+            return !!_backend;
+        },
+
+        /**
+         * Register change listeners
+         *
+         * @param {String} key Key name
+         * @param {Function} callback Function to run when the key changes
+         */
+        listenKeyChange: function(key, callback) {
+            _checkKey(key);
+            if (!_observers[key]) {
+                _observers[key] = [];
+            }
+            _observers[key].push(callback);
+        },
+
+        /**
+         * Remove change listeners
+         *
+         * @param {String} key Key name to unregister listeners against
+         * @param {Function} [callback] If set, unregister the callback, if not - unregister all
+         */
+        stopListening: function(key, callback) {
+            _checkKey(key);
+
+            if (!_observers[key]) {
+                return;
+            }
+
+            if (!callback) {
+                delete _observers[key];
+                return;
+            }
+
+            for (var i = _observers[key].length - 1; i >= 0; i--) {
+                if (_observers[key][i] == callback) {
+                    _observers[key].splice(i, 1);
+                }
+            }
+        },
+
+        /**
+         * Subscribe to a Publish/Subscribe event stream
+         *
+         * @param {String} channel Channel name
+         * @param {Function} callback Function to run when the something is published to the channel
+         */
+        subscribe: function(channel, callback) {
+            channel = (channel || '').toString();
+            if (!channel) {
+                throw new TypeError('Channel not defined');
+            }
+            if (!_pubsub_observers[channel]) {
+                _pubsub_observers[channel] = [];
+            }
+            _pubsub_observers[channel].push(callback);
+        },
+
+        /**
+         * Publish data to an event stream
+         *
+         * @param {String} channel Channel name
+         * @param {Mixed} payload Payload to deliver
+         */
+        publish: function(channel, payload) {
+            channel = (channel || '').toString();
+            if (!channel) {
+                throw new TypeError('Channel not defined');
+            }
+
+            _publish(channel, payload);
+        },
+
+        /**
+         * Reloads the data from browser storage
+         */
+        reInit: function() {
+            _reloadData();
+        },
+
+        /**
+         * Removes reference from global objects and saves it as jStorage
+         *
+         * @param {Boolean} option if needed to save object as simple 'jStorage' in windows context
+         */
+        noConflict: function(saveInGlobal) {
+            delete window.$.jStorage;
+
+            if (saveInGlobal) {
+                window.jStorage = this;
+            }
+
+            return this;
+        }
+    };
+
+    // Initialize jStorage
+    _init();
+
+})();
\ No newline at end of file
diff --git a/resources/lib/jquery.throttle-debounce/jquery.ba-throttle-debounce.js b/resources/lib/jquery.throttle-debounce/jquery.ba-throttle-debounce.js
new file mode 100644 (file)
index 0000000..fa30bdf
--- /dev/null
@@ -0,0 +1,252 @@
+/*!
+ * jQuery throttle / debounce - v1.1 - 3/7/2010
+ * http://benalman.com/projects/jquery-throttle-debounce-plugin/
+ * 
+ * Copyright (c) 2010 "Cowboy" Ben Alman
+ * Dual licensed under the MIT and GPL licenses.
+ * http://benalman.com/about/license/
+ */
+
+// Script: jQuery throttle / debounce: Sometimes, less is more!
+//
+// *Version: 1.1, Last updated: 3/7/2010*
+// 
+// Project Home - http://benalman.com/projects/jquery-throttle-debounce-plugin/
+// GitHub       - http://github.com/cowboy/jquery-throttle-debounce/
+// Source       - http://github.com/cowboy/jquery-throttle-debounce/raw/master/jquery.ba-throttle-debounce.js
+// (Minified)   - http://github.com/cowboy/jquery-throttle-debounce/raw/master/jquery.ba-throttle-debounce.min.js (0.7kb)
+// 
+// About: License
+// 
+// Copyright (c) 2010 "Cowboy" Ben Alman,
+// Dual licensed under the MIT and GPL licenses.
+// http://benalman.com/about/license/
+// 
+// About: Examples
+// 
+// These working examples, complete with fully commented code, illustrate a few
+// ways in which this plugin can be used.
+// 
+// Throttle - http://benalman.com/code/projects/jquery-throttle-debounce/examples/throttle/
+// Debounce - http://benalman.com/code/projects/jquery-throttle-debounce/examples/debounce/
+// 
+// About: Support and Testing
+// 
+// Information about what version or versions of jQuery this plugin has been
+// tested with, what browsers it has been tested in, and where the unit tests
+// reside (so you can test it yourself).
+// 
+// jQuery Versions - none, 1.3.2, 1.4.2
+// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.6, Safari 3-4, Chrome 4-5, Opera 9.6-10.1.
+// Unit Tests      - http://benalman.com/code/projects/jquery-throttle-debounce/unit/
+// 
+// About: Release History
+// 
+// 1.1 - (3/7/2010) Fixed a bug in <jQuery.throttle> where trailing callbacks
+//       executed later than they should. Reworked a fair amount of internal
+//       logic as well.
+// 1.0 - (3/6/2010) Initial release as a stand-alone project. Migrated over
+//       from jquery-misc repo v0.4 to jquery-throttle repo v1.0, added the
+//       no_trailing throttle parameter and debounce functionality.
+// 
+// Topic: Note for non-jQuery users
+// 
+// jQuery isn't actually required for this plugin, because nothing internal
+// uses any jQuery methods or properties. jQuery is just used as a namespace
+// under which these methods can exist.
+// 
+// Since jQuery isn't actually required for this plugin, if jQuery doesn't exist
+// when this plugin is loaded, the method described below will be created in
+// the `Cowboy` namespace. Usage will be exactly the same, but instead of
+// $.method() or jQuery.method(), you'll need to use Cowboy.method().
+
+(function(window,undefined){
+  '$:nomunge'; // Used by YUI compressor.
+  
+  // Since jQuery really isn't required for this plugin, use `jQuery` as the
+  // namespace only if it already exists, otherwise use the `Cowboy` namespace,
+  // creating it if necessary.
+  var $ = window.jQuery || window.Cowboy || ( window.Cowboy = {} ),
+    
+    // Internal method reference.
+    jq_throttle;
+  
+  // Method: jQuery.throttle
+  // 
+  // Throttle execution of a function. Especially useful for rate limiting
+  // execution of handlers on events like resize and scroll. If you want to
+  // rate-limit execution of a function to a single time, see the
+  // <jQuery.debounce> method.
+  // 
+  // In this visualization, | is a throttled-function call and X is the actual
+  // callback execution:
+  // 
+  // > Throttled with `no_trailing` specified as false or unspecified:
+  // > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
+  // > X    X    X    X    X    X        X    X    X    X    X    X
+  // > 
+  // > Throttled with `no_trailing` specified as true:
+  // > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
+  // > X    X    X    X    X             X    X    X    X    X
+  // 
+  // Usage:
+  // 
+  // > var throttled = jQuery.throttle( delay, [ no_trailing, ] callback );
+  // > 
+  // > jQuery('selector').bind( 'someevent', throttled );
+  // > jQuery('selector').unbind( 'someevent', throttled );
+  // 
+  // This also works in jQuery 1.4+:
+  // 
+  // > jQuery('selector').bind( 'someevent', jQuery.throttle( delay, [ no_trailing, ] callback ) );
+  // > jQuery('selector').unbind( 'someevent', callback );
+  // 
+  // Arguments:
+  // 
+  //  delay - (Number) A zero-or-greater delay in milliseconds. For event
+  //    callbacks, values around 100 or 250 (or even higher) are most useful.
+  //  no_trailing - (Boolean) Optional, defaults to false. If no_trailing is
+  //    true, callback will only execute every `delay` milliseconds while the
+  //    throttled-function is being called. If no_trailing is false or
+  //    unspecified, callback will be executed one final time after the last
+  //    throttled-function call. (After the throttled-function has not been
+  //    called for `delay` milliseconds, the internal counter is reset)
+  //  callback - (Function) A function to be executed after delay milliseconds.
+  //    The `this` context and all arguments are passed through, as-is, to
+  //    `callback` when the throttled-function is executed.
+  // 
+  // Returns:
+  // 
+  //  (Function) A new, throttled, function.
+  
+  $.throttle = jq_throttle = function( delay, no_trailing, callback, debounce_mode ) {
+    // After wrapper has stopped being called, this timeout ensures that
+    // `callback` is executed at the proper times in `throttle` and `end`
+    // debounce modes.
+    var timeout_id,
+      
+      // Keep track of the last time `callback` was executed.
+      last_exec = 0;
+    
+    // `no_trailing` defaults to falsy.
+    if ( typeof no_trailing !== 'boolean' ) {
+      debounce_mode = callback;
+      callback = no_trailing;
+      no_trailing = undefined;
+    }
+    
+    // The `wrapper` function encapsulates all of the throttling / debouncing
+    // functionality and when executed will limit the rate at which `callback`
+    // is executed.
+    function wrapper() {
+      var that = this,
+        elapsed = +new Date() - last_exec,
+        args = arguments;
+      
+      // Execute `callback` and update the `last_exec` timestamp.
+      function exec() {
+        last_exec = +new Date();
+        callback.apply( that, args );
+      };
+      
+      // If `debounce_mode` is true (at_begin) this is used to clear the flag
+      // to allow future `callback` executions.
+      function clear() {
+        timeout_id = undefined;
+      };
+      
+      if ( debounce_mode && !timeout_id ) {
+        // Since `wrapper` is being called for the first time and
+        // `debounce_mode` is true (at_begin), execute `callback`.
+        exec();
+      }
+      
+      // Clear any existing timeout.
+      timeout_id && clearTimeout( timeout_id );
+      
+      if ( debounce_mode === undefined && elapsed > delay ) {
+        // In throttle mode, if `delay` time has been exceeded, execute
+        // `callback`.
+        exec();
+        
+      } else if ( no_trailing !== true ) {
+        // In trailing throttle mode, since `delay` time has not been
+        // exceeded, schedule `callback` to execute `delay` ms after most
+        // recent execution.
+        // 
+        // If `debounce_mode` is true (at_begin), schedule `clear` to execute
+        // after `delay` ms.
+        // 
+        // If `debounce_mode` is false (at end), schedule `callback` to
+        // execute after `delay` ms.
+        timeout_id = setTimeout( debounce_mode ? clear : exec, debounce_mode === undefined ? delay - elapsed : delay );
+      }
+    };
+    
+    // Set the guid of `wrapper` function to the same of original callback, so
+    // it can be removed in jQuery 1.4+ .unbind or .die by using the original
+    // callback as a reference.
+    if ( $.guid ) {
+      wrapper.guid = callback.guid = callback.guid || $.guid++;
+    }
+    
+    // Return the wrapper function.
+    return wrapper;
+  };
+  
+  // Method: jQuery.debounce
+  // 
+  // Debounce execution of a function. Debouncing, unlike throttling,
+  // guarantees that a function is only executed a single time, either at the
+  // very beginning of a series of calls, or at the very end. If you want to
+  // simply rate-limit execution of a function, see the <jQuery.throttle>
+  // method.
+  // 
+  // In this visualization, | is a debounced-function call and X is the actual
+  // callback execution:
+  // 
+  // > Debounced with `at_begin` specified as false or unspecified:
+  // > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
+  // >                          X                                 X
+  // > 
+  // > Debounced with `at_begin` specified as true:
+  // > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
+  // > X                                 X
+  // 
+  // Usage:
+  // 
+  // > var debounced = jQuery.debounce( delay, [ at_begin, ] callback );
+  // > 
+  // > jQuery('selector').bind( 'someevent', debounced );
+  // > jQuery('selector').unbind( 'someevent', debounced );
+  // 
+  // This also works in jQuery 1.4+:
+  // 
+  // > jQuery('selector').bind( 'someevent', jQuery.debounce( delay, [ at_begin, ] callback ) );
+  // > jQuery('selector').unbind( 'someevent', callback );
+  // 
+  // Arguments:
+  // 
+  //  delay - (Number) A zero-or-greater delay in milliseconds. For event
+  //    callbacks, values around 100 or 250 (or even higher) are most useful.
+  //  at_begin - (Boolean) Optional, defaults to false. If at_begin is false or
+  //    unspecified, callback will only be executed `delay` milliseconds after
+  //    the last debounced-function call. If at_begin is true, callback will be
+  //    executed only at the first debounced-function call. (After the
+  //    throttled-function has not been called for `delay` milliseconds, the
+  //    internal counter is reset)
+  //  callback - (Function) A function to be executed after delay milliseconds.
+  //    The `this` context and all arguments are passed through, as-is, to
+  //    `callback` when the debounced-function is executed.
+  // 
+  // Returns:
+  // 
+  //  (Function) A new, debounced, function.
+  
+  $.debounce = function( delay, at_begin, callback ) {
+    return callback === undefined
+      ? jq_throttle( delay, at_begin, false )
+      : jq_throttle( delay, callback, at_begin !== false );
+  };
+  
+})(this);
diff --git a/resources/lib/jquery.ui/jquery.ui.spinner.js b/resources/lib/jquery.ui/jquery.ui.spinner.js
deleted file mode 100644 (file)
index 98dc9df..0000000
+++ /dev/null
@@ -1,478 +0,0 @@
-/*!
- * jQuery UI Spinner 1.9.2
- * http://jqueryui.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- *
- * http://api.jqueryui.com/spinner/
- *
- * Depends:
- *  jquery.ui.core.js
- *  jquery.ui.widget.js
- *  jquery.ui.button.js
- */
-(function( $ ) {
-
-function modifier( fn ) {
-       return function() {
-               var previous = this.element.val();
-               fn.apply( this, arguments );
-               this._refresh();
-               if ( previous !== this.element.val() ) {
-                       this._trigger( "change" );
-               }
-       };
-}
-
-$.widget( "ui.spinner", {
-       version: "1.9.2",
-       defaultElement: "<input>",
-       widgetEventPrefix: "spin",
-       options: {
-               culture: null,
-               icons: {
-                       down: "ui-icon-triangle-1-s",
-                       up: "ui-icon-triangle-1-n"
-               },
-               incremental: true,
-               max: null,
-               min: null,
-               numberFormat: null,
-               page: 10,
-               step: 1,
-
-               change: null,
-               spin: null,
-               start: null,
-               stop: null
-       },
-
-       _create: function() {
-               // handle string values that need to be parsed
-               this._setOption( "max", this.options.max );
-               this._setOption( "min", this.options.min );
-               this._setOption( "step", this.options.step );
-
-               // format the value, but don't constrain
-               this._value( this.element.val(), true );
-
-               this._draw();
-               this._on( this._events );
-               this._refresh();
-
-               // turning off autocomplete prevents the browser from remembering the
-               // value when navigating through history, so we re-enable autocomplete
-               // if the page is unloaded before the widget is destroyed. #7790
-               this._on( this.window, {
-                       beforeunload: function() {
-                               this.element.removeAttr( "autocomplete" );
-                       }
-               });
-       },
-
-       _getCreateOptions: function() {
-               var options = {},
-                       element = this.element;
-
-               $.each( [ "min", "max", "step" ], function( i, option ) {
-                       var value = element.attr( option );
-                       if ( value !== undefined && value.length ) {
-                               options[ option ] = value;
-                       }
-               });
-
-               return options;
-       },
-
-       _events: {
-               keydown: function( event ) {
-                       if ( this._start( event ) && this._keydown( event ) ) {
-                               event.preventDefault();
-                       }
-               },
-               keyup: "_stop",
-               focus: function() {
-                       this.previous = this.element.val();
-               },
-               blur: function( event ) {
-                       if ( this.cancelBlur ) {
-                               delete this.cancelBlur;
-                               return;
-                       }
-
-                       this._refresh();
-                       if ( this.previous !== this.element.val() ) {
-                               this._trigger( "change", event );
-                       }
-               },
-               mousewheel: function( event, delta ) {
-                       if ( !delta ) {
-                               return;
-                       }
-                       if ( !this.spinning && !this._start( event ) ) {
-                               return false;
-                       }
-
-                       this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
-                       clearTimeout( this.mousewheelTimer );
-                       this.mousewheelTimer = this._delay(function() {
-                               if ( this.spinning ) {
-                                       this._stop( event );
-                               }
-                       }, 100 );
-                       event.preventDefault();
-               },
-               "mousedown .ui-spinner-button": function( event ) {
-                       var previous;
-
-                       // We never want the buttons to have focus; whenever the user is
-                       // interacting with the spinner, the focus should be on the input.
-                       // If the input is focused then this.previous is properly set from
-                       // when the input first received focus. If the input is not focused
-                       // then we need to set this.previous based on the value before spinning.
-                       previous = this.element[0] === this.document[0].activeElement ?
-                               this.previous : this.element.val();
-                       function checkFocus() {
-                               var isActive = this.element[0] === this.document[0].activeElement;
-                               if ( !isActive ) {
-                                       this.element.focus();
-                                       this.previous = previous;
-                                       // support: IE
-                                       // IE sets focus asynchronously, so we need to check if focus
-                                       // moved off of the input because the user clicked on the button.
-                                       this._delay(function() {
-                                               this.previous = previous;
-                                       });
-                               }
-                       }
-
-                       // ensure focus is on (or stays on) the text field
-                       event.preventDefault();
-                       checkFocus.call( this );
-
-                       // support: IE
-                       // IE doesn't prevent moving focus even with event.preventDefault()
-                       // so we set a flag to know when we should ignore the blur event
-                       // and check (again) if focus moved off of the input.
-                       this.cancelBlur = true;
-                       this._delay(function() {
-                               delete this.cancelBlur;
-                               checkFocus.call( this );
-                       });
-
-                       if ( this._start( event ) === false ) {
-                               return;
-                       }
-
-                       this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
-               },
-               "mouseup .ui-spinner-button": "_stop",
-               "mouseenter .ui-spinner-button": function( event ) {
-                       // button will add ui-state-active if mouse was down while mouseleave and kept down
-                       if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
-                               return;
-                       }
-
-                       if ( this._start( event ) === false ) {
-                               return false;
-                       }
-                       this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
-               },
-               // TODO: do we really want to consider this a stop?
-               // shouldn't we just stop the repeater and wait until mouseup before
-               // we trigger the stop event?
-               "mouseleave .ui-spinner-button": "_stop"
-       },
-
-       _draw: function() {
-               var uiSpinner = this.uiSpinner = this.element
-                       .addClass( "ui-spinner-input" )
-                       .attr( "autocomplete", "off" )
-                       .wrap( this._uiSpinnerHtml() )
-                       .parent()
-                               // add buttons
-                               .append( this._buttonHtml() );
-
-               this.element.attr( "role", "spinbutton" );
-
-               // button bindings
-               this.buttons = uiSpinner.find( ".ui-spinner-button" )
-                       .attr( "tabIndex", -1 )
-                       .button()
-                       .removeClass( "ui-corner-all" );
-
-               // IE 6 doesn't understand height: 50% for the buttons
-               // unless the wrapper has an explicit height
-               if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
-                               uiSpinner.height() > 0 ) {
-                       uiSpinner.height( uiSpinner.height() );
-               }
-
-               // disable spinner if element was already disabled
-               if ( this.options.disabled ) {
-                       this.disable();
-               }
-       },
-
-       _keydown: function( event ) {
-               var options = this.options,
-                       keyCode = $.ui.keyCode;
-
-               switch ( event.keyCode ) {
-               case keyCode.UP:
-                       this._repeat( null, 1, event );
-                       return true;
-               case keyCode.DOWN:
-                       this._repeat( null, -1, event );
-                       return true;
-               case keyCode.PAGE_UP:
-                       this._repeat( null, options.page, event );
-                       return true;
-               case keyCode.PAGE_DOWN:
-                       this._repeat( null, -options.page, event );
-                       return true;
-               }
-
-               return false;
-       },
-
-       _uiSpinnerHtml: function() {
-               return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
-       },
-
-       _buttonHtml: function() {
-               return "" +
-                       "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
-                               "<span class='ui-icon " + this.options.icons.up + "'>&#9650;</span>" +
-                       "</a>" +
-                       "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
-                               "<span class='ui-icon " + this.options.icons.down + "'>&#9660;</span>" +
-                       "</a>";
-       },
-
-       _start: function( event ) {
-               if ( !this.spinning && this._trigger( "start", event ) === false ) {
-                       return false;
-               }
-
-               if ( !this.counter ) {
-                       this.counter = 1;
-               }
-               this.spinning = true;
-               return true;
-       },
-
-       _repeat: function( i, steps, event ) {
-               i = i || 500;
-
-               clearTimeout( this.timer );
-               this.timer = this._delay(function() {
-                       this._repeat( 40, steps, event );
-               }, i );
-
-               this._spin( steps * this.options.step, event );
-       },
-
-       _spin: function( step, event ) {
-               var value = this.value() || 0;
-
-               if ( !this.counter ) {
-                       this.counter = 1;
-               }
-
-               value = this._adjustValue( value + step * this._increment( this.counter ) );
-
-               if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
-                       this._value( value );
-                       this.counter++;
-               }
-       },
-
-       _increment: function( i ) {
-               var incremental = this.options.incremental;
-
-               if ( incremental ) {
-                       return $.isFunction( incremental ) ?
-                               incremental( i ) :
-                               Math.floor( i*i*i/50000 - i*i/500 + 17*i/200 + 1 );
-               }
-
-               return 1;
-       },
-
-       _precision: function() {
-               var precision = this._precisionOf( this.options.step );
-               if ( this.options.min !== null ) {
-                       precision = Math.max( precision, this._precisionOf( this.options.min ) );
-               }
-               return precision;
-       },
-
-       _precisionOf: function( num ) {
-               var str = num.toString(),
-                       decimal = str.indexOf( "." );
-               return decimal === -1 ? 0 : str.length - decimal - 1;
-       },
-
-       _adjustValue: function( value ) {
-               var base, aboveMin,
-                       options = this.options;
-
-               // make sure we're at a valid step
-               // - find out where we are relative to the base (min or 0)
-               base = options.min !== null ? options.min : 0;
-               aboveMin = value - base;
-               // - round to the nearest step
-               aboveMin = Math.round(aboveMin / options.step) * options.step;
-               // - rounding is based on 0, so adjust back to our base
-               value = base + aboveMin;
-
-               // fix precision from bad JS floating point math
-               value = parseFloat( value.toFixed( this._precision() ) );
-
-               // clamp the value
-               if ( options.max !== null && value > options.max) {
-                       return options.max;
-               }
-               if ( options.min !== null && value < options.min ) {
-                       return options.min;
-               }
-
-               return value;
-       },
-
-       _stop: function( event ) {
-               if ( !this.spinning ) {
-                       return;
-               }
-
-               clearTimeout( this.timer );
-               clearTimeout( this.mousewheelTimer );
-               this.counter = 0;
-               this.spinning = false;
-               this._trigger( "stop", event );
-       },
-
-       _setOption: function( key, value ) {
-               if ( key === "culture" || key === "numberFormat" ) {
-                       var prevValue = this._parse( this.element.val() );
-                       this.options[ key ] = value;
-                       this.element.val( this._format( prevValue ) );
-                       return;
-               }
-
-               if ( key === "max" || key === "min" || key === "step" ) {
-                       if ( typeof value === "string" ) {
-                               value = this._parse( value );
-                       }
-               }
-
-               this._super( key, value );
-
-               if ( key === "disabled" ) {
-                       if ( value ) {
-                               this.element.prop( "disabled", true );
-                               this.buttons.button( "disable" );
-                       } else {
-                               this.element.prop( "disabled", false );
-                               this.buttons.button( "enable" );
-                       }
-               }
-       },
-
-       _setOptions: modifier(function( options ) {
-               this._super( options );
-               this._value( this.element.val() );
-       }),
-
-       _parse: function( val ) {
-               if ( typeof val === "string" && val !== "" ) {
-                       val = window.Globalize && this.options.numberFormat ?
-                               Globalize.parseFloat( val, 10, this.options.culture ) : +val;
-               }
-               return val === "" || isNaN( val ) ? null : val;
-       },
-
-       _format: function( value ) {
-               if ( value === "" ) {
-                       return "";
-               }
-               return window.Globalize && this.options.numberFormat ?
-                       Globalize.format( value, this.options.numberFormat, this.options.culture ) :
-                       value;
-       },
-
-       _refresh: function() {
-               this.element.attr({
-                       "aria-valuemin": this.options.min,
-                       "aria-valuemax": this.options.max,
-                       // TODO: what should we do with values that can't be parsed?
-                       "aria-valuenow": this._parse( this.element.val() )
-               });
-       },
-
-       // update the value without triggering change
-       _value: function( value, allowAny ) {
-               var parsed;
-               if ( value !== "" ) {
-                       parsed = this._parse( value );
-                       if ( parsed !== null ) {
-                               if ( !allowAny ) {
-                                       parsed = this._adjustValue( parsed );
-                               }
-                               value = this._format( parsed );
-                       }
-               }
-               this.element.val( value );
-               this._refresh();
-       },
-
-       _destroy: function() {
-               this.element
-                       .removeClass( "ui-spinner-input" )
-                       .prop( "disabled", false )
-                       .removeAttr( "autocomplete" )
-                       .removeAttr( "role" )
-                       .removeAttr( "aria-valuemin" )
-                       .removeAttr( "aria-valuemax" )
-                       .removeAttr( "aria-valuenow" );
-               this.uiSpinner.replaceWith( this.element );
-       },
-
-       stepUp: modifier(function( steps ) {
-               this._stepUp( steps );
-       }),
-       _stepUp: function( steps ) {
-               this._spin( (steps || 1) * this.options.step );
-       },
-
-       stepDown: modifier(function( steps ) {
-               this._stepDown( steps );
-       }),
-       _stepDown: function( steps ) {
-               this._spin( (steps || 1) * -this.options.step );
-       },
-
-       pageUp: modifier(function( pages ) {
-               this._stepUp( (pages || 1) * this.options.page );
-       }),
-
-       pageDown: modifier(function( pages ) {
-               this._stepDown( (pages || 1) * this.options.page );
-       }),
-
-       value: function( newVal ) {
-               if ( !arguments.length ) {
-                       return this._parse( this.element.val() );
-               }
-               modifier( this._value ).call( this, newVal );
-       },
-
-       widget: function() {
-               return this.uiSpinner;
-       }
-});
-
-}( jQuery ) );
diff --git a/resources/lib/jquery.ui/themes/smoothness/jquery.ui.spinner.css b/resources/lib/jquery.ui/themes/smoothness/jquery.ui.spinner.css
deleted file mode 100644 (file)
index e89b720..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*!
- * jQuery UI Spinner 1.9.2
- * http://jqueryui.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Spinner#theming
- */
-.ui-spinner { position:relative; display: inline-block; overflow: hidden; padding: 0; vertical-align: middle; }
-.ui-spinner-input { border: none; background: none; padding: 0; margin: .2em 0; vertical-align: middle; margin-left: .4em; margin-right: 22px; }
-.ui-spinner-button { width: 16px; height: 50%; font-size: .5em; padding: 0; margin: 0; text-align: center; position: absolute; cursor: default; display: block; overflow: hidden; right: 0; }
-.ui-spinner a.ui-spinner-button { border-top: none; border-bottom: none; border-right: none; } /* more specificity required here to overide default borders */
-.ui-spinner .ui-icon { position: absolute; margin-top: -8px; top: 50%; left: 0; } /* vertical centre icon */
-.ui-spinner-up { top: 0; }
-.ui-spinner-down { bottom: 0; }
-
-/* TR overrides */
-.ui-spinner .ui-icon-triangle-1-s {
-       /* need to fix icons sprite */
-       background-position:-65px -16px;
-}
index aa1b831..4df7d1a 100644 (file)
@@ -2,6 +2,7 @@ The MIT License
 
 Copyright (c) 2009 Chris Wanstrath (Ruby)
 Copyright (c) 2010-2014 Jan Lehnardt (JavaScript)
+Copyright (c) 2010-2015 The mustache.js community
 
 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 
index c7ffbef..8ec1b44 100644 (file)
@@ -3,54 +3,86 @@
  * http://github.com/janl/mustache.js
  */
 
-/*global define: false*/
+/*global define: false Mustache: true*/
 
-(function (global, factory) {
-  if (typeof exports === "object" && exports) {
+(function defineMustache (global, factory) {
+  if (typeof exports === 'object' && exports && typeof exports.nodeName !== 'string') {
     factory(exports); // CommonJS
-  } else if (typeof define === "function" && define.amd) {
+  } else if (typeof define === 'function' && define.amd) {
     define(['exports'], factory); // AMD
   } else {
-    factory(global.Mustache = {}); // <script>
+    global.Mustache = {};
+    factory(global.Mustache); // script, wsh, asp
   }
-}(this, function (mustache) {
+}(this, function mustacheFactory (mustache) {
 
-  var Object_toString = Object.prototype.toString;
-  var isArray = Array.isArray || function (object) {
-    return Object_toString.call(object) === '[object Array]';
+  var objectToString = Object.prototype.toString;
+  var isArray = Array.isArray || function isArrayPolyfill (object) {
+    return objectToString.call(object) === '[object Array]';
   };
 
-  function isFunction(object) {
+  function isFunction (object) {
     return typeof object === 'function';
   }
 
-  function escapeRegExp(string) {
-    return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
+  /**
+   * More correct typeof string handling array
+   * which normally returns typeof 'object'
+   */
+  function typeStr (obj) {
+    return isArray(obj) ? 'array' : typeof obj;
+  }
+
+  function escapeRegExp (string) {
+    return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
+  }
+
+  /**
+   * Null safe way of checking whether or not an object,
+   * including its prototype, has a given property
+   */
+  function hasProperty (obj, propName) {
+    return obj != null && typeof obj === 'object' && (propName in obj);
+  }
+
+  /**
+   * Safe way of detecting whether or not the given thing is a primitive and
+   * whether it has the given property
+   */
+  function primitiveHasOwnProperty (primitive, propName) {  
+    return (
+      primitive != null
+      && typeof primitive !== 'object'
+      && primitive.hasOwnProperty
+      && primitive.hasOwnProperty(propName)
+    );
   }
 
   // Workaround for https://issues.apache.org/jira/browse/COUCHDB-577
   // See https://github.com/janl/mustache.js/issues/189
-  var RegExp_test = RegExp.prototype.test;
-  function testRegExp(re, string) {
-    return RegExp_test.call(re, string);
+  var regExpTest = RegExp.prototype.test;
+  function testRegExp (re, string) {
+    return regExpTest.call(re, string);
   }
 
   var nonSpaceRe = /\S/;
-  function isWhitespace(string) {
+  function isWhitespace (string) {
     return !testRegExp(nonSpaceRe, string);
   }
 
   var entityMap = {
-    "&": "&amp;",
-    "<": "&lt;",
-    ">": "&gt;",
+    '&': '&amp;',
+    '<': '&lt;',
+    '>': '&gt;',
     '"': '&quot;',
     "'": '&#39;',
-    "/": '&#x2F;'
+    '/': '&#x2F;',
+    '`': '&#x60;',
+    '=': '&#x3D;'
   };
 
-  function escapeHtml(string) {
-    return String(string).replace(/[&<>"'\/]/g, function (s) {
+  function escapeHtml (string) {
+    return String(string).replace(/[&<>"'`=\/]/g, function fromEntityMap (s) {
       return entityMap[s];
     });
   }
    * array of tokens in the subtree and 2) the index in the original template at
    * which the closing tag for that section begins.
    */
-  function parseTemplate(template, tags) {
+  function parseTemplate (template, tags) {
     if (!template)
       return [];
 
 
     // Strips all whitespace tokens array for the current line
     // if there was a {{#tag}} on it and otherwise only space.
-    function stripSpace() {
+    function stripSpace () {
       if (hasTag && !nonSpace) {
         while (spaces.length)
           delete tokens[spaces.pop()];
     }
 
     var openingTagRe, closingTagRe, closingCurlyRe;
-    function compileTags(tags) {
-      if (typeof tags === 'string')
-        tags = tags.split(spaceRe, 2);
+    function compileTags (tagsToCompile) {
+      if (typeof tagsToCompile === 'string')
+        tagsToCompile = tagsToCompile.split(spaceRe, 2);
 
-      if (!isArray(tags) || tags.length !== 2)
-        throw new Error('Invalid tags: ' + tags);
+      if (!isArray(tagsToCompile) || tagsToCompile.length !== 2)
+        throw new Error('Invalid tags: ' + tagsToCompile);
 
-      openingTagRe = new RegExp(escapeRegExp(tags[0]) + '\\s*');
-      closingTagRe = new RegExp('\\s*' + escapeRegExp(tags[1]));
-      closingCurlyRe = new RegExp('\\s*' + escapeRegExp('}' + tags[1]));
+      openingTagRe = new RegExp(escapeRegExp(tagsToCompile[0]) + '\\s*');
+      closingTagRe = new RegExp('\\s*' + escapeRegExp(tagsToCompile[1]));
+      closingCurlyRe = new RegExp('\\s*' + escapeRegExp('}' + tagsToCompile[1]));
     }
 
     compileTags(tags || mustache.tags);
    * Combines the values of consecutive text tokens in the given `tokens` array
    * to a single token.
    */
-  function squashTokens(tokens) {
+  function squashTokens (tokens) {
     var squashedTokens = [];
 
     var token, lastToken;
    * all tokens that appear in that section and 2) the index in the original
    * template that represents the end of that section.
    */
-  function nestTokens(tokens) {
+  function nestTokens (tokens) {
     var nestedTokens = [];
     var collector = nestedTokens;
     var sections = [];
       token = tokens[i];
 
       switch (token[0]) {
-      case '#':
-      case '^':
-        collector.push(token);
-        sections.push(token);
-        collector = token[4] = [];
-        break;
-      case '/':
-        section = sections.pop();
-        section[5] = token[2];
-        collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens;
-        break;
-      default:
-        collector.push(token);
+        case '#':
+        case '^':
+          collector.push(token);
+          sections.push(token);
+          collector = token[4] = [];
+          break;
+        case '/':
+          section = sections.pop();
+          section[5] = token[2];
+          collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens;
+          break;
+        default:
+          collector.push(token);
       }
     }
 
    * A simple string scanner that is used by the template parser to find
    * tokens in template strings.
    */
-  function Scanner(string) {
+  function Scanner (string) {
     this.string = string;
     this.tail = string;
     this.pos = 0;
   /**
    * Returns `true` if the tail is empty (end of string).
    */
-  Scanner.prototype.eos = function () {
-    return this.tail === "";
+  Scanner.prototype.eos = function eos () {
+    return this.tail === '';
   };
 
   /**
    * Tries to match the given regular expression at the current position.
    * Returns the matched text if it can match, the empty string otherwise.
    */
-  Scanner.prototype.scan = function (re) {
+  Scanner.prototype.scan = function scan (re) {
     var match = this.tail.match(re);
 
     if (!match || match.index !== 0)
    * Skips all text until the given regular expression can be matched. Returns
    * the skipped string, which is the entire tail if no match can be made.
    */
-  Scanner.prototype.scanUntil = function (re) {
+  Scanner.prototype.scanUntil = function scanUntil (re) {
     var index = this.tail.search(re), match;
 
     switch (index) {
-    case -1:
-      match = this.tail;
-      this.tail = "";
-      break;
-    case 0:
-      match = "";
-      break;
-    default:
-      match = this.tail.substring(0, index);
-      this.tail = this.tail.substring(index);
+      case -1:
+        match = this.tail;
+        this.tail = '';
+        break;
+      case 0:
+        match = '';
+        break;
+      default:
+        match = this.tail.substring(0, index);
+        this.tail = this.tail.substring(index);
     }
 
     this.pos += match.length;
    * Represents a rendering context by wrapping a view object and
    * maintaining a reference to the parent context.
    */
-  function Context(view, parentContext) {
-    this.view = view == null ? {} : view;
+  function Context (view, parentContext) {
+    this.view = view;
     this.cache = { '.': this.view };
     this.parent = parentContext;
   }
    * Creates a new context using the given view with this context
    * as the parent.
    */
-  Context.prototype.push = function (view) {
+  Context.prototype.push = function push (view) {
     return new Context(view, this);
   };
 
    * Returns the value of the given name in this context, traversing
    * up the context hierarchy if the value is absent in this context's view.
    */
-  Context.prototype.lookup = function (name) {
+  Context.prototype.lookup = function lookup (name) {
     var cache = this.cache;
 
     var value;
-    if (name in cache) {
+    if (cache.hasOwnProperty(name)) {
       value = cache[name];
     } else {
-      var context = this, names, index;
+      var context = this, intermediateValue, names, index, lookupHit = false;
 
       while (context) {
         if (name.indexOf('.') > 0) {
-          value = context.view;
+          intermediateValue = context.view;
           names = name.split('.');
           index = 0;
 
-          while (value != null && index < names.length)
-            value = value[names[index++]];
-        } else if (typeof context.view == 'object') {
-          value = context.view[name];
+          /**
+           * Using the dot notion path in `name`, we descend through the
+           * nested objects.
+           *
+           * To be certain that the lookup has been successful, we have to
+           * check if the last object in the path actually has the property
+           * we are looking for. We store the result in `lookupHit`.
+           *
+           * This is specially necessary for when the value has been set to
+           * `undefined` and we want to avoid looking up parent contexts.
+           *
+           * In the case where dot notation is used, we consider the lookup
+           * to be successful even if the last "object" in the path is
+           * not actually an object but a primitive (e.g., a string, or an
+           * integer), because it is sometimes useful to access a property
+           * of an autoboxed primitive, such as the length of a string.
+           **/
+          while (intermediateValue != null && index < names.length) {
+            if (index === names.length - 1)
+              lookupHit = (
+                hasProperty(intermediateValue, names[index]) 
+                || primitiveHasOwnProperty(intermediateValue, names[index])
+              );
+
+            intermediateValue = intermediateValue[names[index++]];
+          }
+        } else {
+          intermediateValue = context.view[name];
+
+          /**
+           * Only checking against `hasProperty`, which always returns `false` if
+           * `context.view` is not an object. Deliberately omitting the check
+           * against `primitiveHasOwnProperty` if dot notation is not used.
+           *
+           * Consider this example:
+           * ```
+           * Mustache.render("The length of a football field is {{#length}}{{length}}{{/length}}.", {length: "100 yards"})
+           * ```
+           *
+           * If we were to check also against `primitiveHasOwnProperty`, as we do
+           * in the dot notation case, then render call would return:
+           *
+           * "The length of a football field is 9."
+           *
+           * rather than the expected:
+           *
+           * "The length of a football field is 100 yards."
+           **/
+          lookupHit = hasProperty(context.view, name);
         }
 
-        if (value != null)
+        if (lookupHit) {
+          value = intermediateValue;
           break;
+        }
 
         context = context.parent;
       }
    * string, given a context. It also maintains a cache of templates to
    * avoid the need to parse the same template twice.
    */
-  function Writer() {
+  function Writer () {
     this.cache = {};
   }
 
   /**
    * Clears all cached templates in this writer.
    */
-  Writer.prototype.clearCache = function () {
+  Writer.prototype.clearCache = function clearCache () {
     this.cache = {};
   };
 
   /**
-   * Parses and caches the given `template` and returns the array of tokens
+   * Parses and caches the given `template` according to the given `tags` or
+   * `mustache.tags` if `tags` is omitted,  and returns the array of tokens
    * that is generated from the parse.
    */
-  Writer.prototype.parse = function (template, tags) {
+  Writer.prototype.parse = function parse (template, tags) {
     var cache = this.cache;
-    var tokens = cache[template];
+    var cacheKey = template + ':' + (tags || mustache.tags).join(':');
+    var tokens = cache[cacheKey];
 
     if (tokens == null)
-      tokens = cache[template] = parseTemplate(template, tags);
+      tokens = cache[cacheKey] = parseTemplate(template, tags);
 
     return tokens;
   };
    * names and templates of partials that are used in the template. It may
    * also be a function that is used to load partial templates on the fly
    * that takes a single argument: the name of the partial.
+   *
+   * If the optional `tags` argument is given here it must be an array with two
+   * string values: the opening and closing tags used in the template (e.g.
+   * [ "<%", "%>" ]). The default is to mustache.tags.
    */
-  Writer.prototype.render = function (template, view, partials) {
-    var tokens = this.parse(template);
+  Writer.prototype.render = function render (template, view, partials, tags) {
+    var tokens = this.parse(template, tags);
     var context = (view instanceof Context) ? view : new Context(view);
-    return this.renderTokens(tokens, context, partials, template);
+    return this.renderTokens(tokens, context, partials, template, tags);
   };
 
   /**
    * If the template doesn't use higher-order sections, this argument may
    * be omitted.
    */
-  Writer.prototype.renderTokens = function (tokens, context, partials, originalTemplate) {
+  Writer.prototype.renderTokens = function renderTokens (tokens, context, partials, originalTemplate, tags) {
     var buffer = '';
 
-    // This function is used to render an arbitrary template
-    // in the current context by higher-order sections.
-    var self = this;
-    function subRender(template) {
-      return self.render(template, context, partials);
-    }
-
-    var token, value;
+    var token, symbol, value;
     for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
+      value = undefined;
       token = tokens[i];
+      symbol = token[0];
 
-      switch (token[0]) {
-      case '#':
-        value = context.lookup(token[1]);
+      if (symbol === '#') value = this.renderSection(token, context, partials, originalTemplate);
+      else if (symbol === '^') value = this.renderInverted(token, context, partials, originalTemplate);
+      else if (symbol === '>') value = this.renderPartial(token, context, partials, tags);
+      else if (symbol === '&') value = this.unescapedValue(token, context);
+      else if (symbol === 'name') value = this.escapedValue(token, context);
+      else if (symbol === 'text') value = this.rawValue(token);
 
-        if (!value)
-          continue;
+      if (value !== undefined)
+        buffer += value;
+    }
 
-        if (isArray(value)) {
-          for (var j = 0, valueLength = value.length; j < valueLength; ++j) {
-            buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate);
-          }
-        } else if (typeof value === 'object' || typeof value === 'string') {
-          buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate);
-        } else if (isFunction(value)) {
-          if (typeof originalTemplate !== 'string')
-            throw new Error('Cannot use higher-order sections without the original template');
+    return buffer;
+  };
 
-          // Extract the portion of the original template that the section contains.
-          value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender);
+  Writer.prototype.renderSection = function renderSection (token, context, partials, originalTemplate) {
+    var self = this;
+    var buffer = '';
+    var value = context.lookup(token[1]);
 
-          if (value != null)
-            buffer += value;
-        } else {
-          buffer += this.renderTokens(token[4], context, partials, originalTemplate);
-        }
+    // This function is used to render an arbitrary template
+    // in the current context by higher-order sections.
+    function subRender (template) {
+      return self.render(template, context, partials);
+    }
 
-        break;
-      case '^':
-        value = context.lookup(token[1]);
+    if (!value) return;
 
-        // Use JavaScript's definition of falsy. Include empty arrays.
-        // See https://github.com/janl/mustache.js/issues/186
-        if (!value || (isArray(value) && value.length === 0))
-          buffer += this.renderTokens(token[4], context, partials, originalTemplate);
+    if (isArray(value)) {
+      for (var j = 0, valueLength = value.length; j < valueLength; ++j) {
+        buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate);
+      }
+    } else if (typeof value === 'object' || typeof value === 'string' || typeof value === 'number') {
+      buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate);
+    } else if (isFunction(value)) {
+      if (typeof originalTemplate !== 'string')
+        throw new Error('Cannot use higher-order sections without the original template');
 
-        break;
-      case '>':
-        if (!partials)
-          continue;
+      // Extract the portion of the original template that the section contains.
+      value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender);
 
-        value = isFunction(partials) ? partials(token[1]) : partials[token[1]];
+      if (value != null)
+        buffer += value;
+    } else {
+      buffer += this.renderTokens(token[4], context, partials, originalTemplate);
+    }
+    return buffer;
+  };
 
-        if (value != null)
-          buffer += this.renderTokens(this.parse(value), context, partials, value);
+  Writer.prototype.renderInverted = function renderInverted (token, context, partials, originalTemplate) {
+    var value = context.lookup(token[1]);
 
-        break;
-      case '&':
-        value = context.lookup(token[1]);
+    // Use JavaScript's definition of falsy. Include empty arrays.
+    // See https://github.com/janl/mustache.js/issues/186
+    if (!value || (isArray(value) && value.length === 0))
+      return this.renderTokens(token[4], context, partials, originalTemplate);
+  };
 
-        if (value != null)
-          buffer += value;
+  Writer.prototype.renderPartial = function renderPartial (token, context, partials, tags) {
+    if (!partials) return;
 
-        break;
-      case 'name':
-        value = context.lookup(token[1]);
+    var value = isFunction(partials) ? partials(token[1]) : partials[token[1]];
+    if (value != null)
+      return this.renderTokens(this.parse(value, tags), context, partials, value);
+  };
 
-        if (value != null)
-          buffer += mustache.escape(value);
+  Writer.prototype.unescapedValue = function unescapedValue (token, context) {
+    var value = context.lookup(token[1]);
+    if (value != null)
+      return value;
+  };
 
-        break;
-      case 'text':
-        buffer += token[1];
-        break;
-      }
-    }
+  Writer.prototype.escapedValue = function escapedValue (token, context) {
+    var value = context.lookup(token[1]);
+    if (value != null)
+      return mustache.escape(value);
+  };
 
-    return buffer;
+  Writer.prototype.rawValue = function rawValue (token) {
+    return token[1];
   };
 
-  mustache.name = "mustache.js";
-  mustache.version = "1.0.0";
-  mustache.tags = [ "{{", "}}" ];
+  mustache.name = 'mustache.js';
+  mustache.version = '3.0.1';
+  mustache.tags = [ '{{', '}}' ];
 
   // All high-level mustache.* functions use this writer.
   var defaultWriter = new Writer();
   /**
    * Clears all cached templates in the default writer.
    */
-  mustache.clearCache = function () {
+  mustache.clearCache = function clearCache () {
     return defaultWriter.clearCache();
   };
 
    * array of tokens it contains. Doing this ahead of time avoids the need to
    * parse templates on the fly as they are rendered.
    */
-  mustache.parse = function (template, tags) {
+  mustache.parse = function parse (template, tags) {
     return defaultWriter.parse(template, tags);
   };
 
   /**
    * Renders the `template` with the given `view` and `partials` using the
-   * default writer.
+   * default writer. If the optional `tags` argument is given here it must be an
+   * array with two string values: the opening and closing tags used in the
+   * template (e.g. [ "<%", "%>" ]). The default is to mustache.tags.
    */
-  mustache.render = function (template, view, partials) {
-    return defaultWriter.render(template, view, partials);
+  mustache.render = function render (template, view, partials, tags) {
+    if (typeof template !== 'string') {
+      throw new TypeError('Invalid template! Template should be a "string" ' +
+                          'but "' + typeStr(template) + '" was given as the first ' +
+                          'argument for mustache#render(template, view, partials)');
+    }
+
+    return defaultWriter.render(template, view, partials, tags);
   };
 
-  // This is here for backwards compatibility with 0.4.x.
-  mustache.to_html = function (template, view, partials, send) {
+  // This is here for backwards compatibility with 0.4.x.,
+  /*eslint-disable */ // eslint wants camel cased function name
+  mustache.to_html = function to_html (template, view, partials, send) {
+    /*eslint-enable*/
+
     var result = mustache.render(template, view, partials);
 
     if (isFunction(send)) {
   mustache.Context = Context;
   mustache.Writer = Writer;
 
+  return mustache;
 }));
index 9ade84c..91604ab 100644 (file)
@@ -1,4 +1,142 @@
 # OOUI Release History
+## v0.31.6 / 2019-05-07
+### Styles
+* FieldLayout: Use 'error' icon for error messages (Volker E.)
+* FieldLayout, FieldsetLayout: Remove bad `z-index` override for help popup (Bartosz Dziewoński)
+* MenuSelectWidget: Amend value to reflect one option's height (Volker E.)
+* PopupTool: Fix popup `z-index` override (Bartosz Dziewoński)
+* icons: Add 'articleDisambiguation*' and 'articleNotFound*' (Volker E.)
+
+### Code
+* WikimediaUI theme: Fix regression of too short menu items (Volker E.)
+* build: Upgrade eslint-config-wikimedia 0.12.0, drop grunt-jsonlint (James D. Forrester)
+
+
+## v0.31.5 / 2019-04-24
+### Features
+* MenuSelectWidget: Fix highlight on re-display (Lucas Werkmeister)
+* NumberInputWidget: Disable event listeners when disabled or readOnly (Ed Sanders)
+
+### Styles
+* PopupWidget: Fix stacking context problems caused by `filter: drop-shadow` (Bartosz Dziewoński)
+
+### Code
+* docs: {undefined/boolean} -> {undefined|boolean} (Ed Sanders)
+* icons: Re-crush with 'svgmin' build task (Volker E.)
+
+
+## v0.31.4 / 2019-04-16
+### Features
+* Element: Make `scrollIntoView()` more flexible (Ed Sanders)
+* NumberInputWidget: Disable buttons when read-only (Ed Sanders)
+* RequestManager: Add `showPendingRequest` option (Ed Sanders)
+* Toolbar: Support flagged buttons (Ed Sanders)
+
+### Styles
+* CheckboxInputWidget: Fix styling of indeterminate with focus/hover/active (Ed Sanders)
+* CheckboxMultioptionWidget: Remove full width (Thalia Chan)
+* PopupWidget: Progressively enhance to use `filter: drop-shadow()` (Volker E.)
+* RadioOptionWidget: Remove full-width radio buttons to bring consistency with checkboxes (David Barratt)
+* WikimediaUI theme: Fix popup callout border color (Ed Sanders)
+* WikimediaUI theme: Fix PHP Checkbox- & RadioInputWidget native appearance (Volker E.)
+
+### Code
+* Fix `'inherit'` value passed to toolbar mixin (Ed Sanders)
+* MenuSelect-/SelectWidget: Fix eslint `max-len` warnings (Volker E.)
+* NumberInputWidget: Remove duplicate documentation (Ed Sanders)
+* OptionWidget: Fix copy-paste from LabelElement (Bartosz Dziewoński)
+* icons: Point Wikimedia icon in Apex theme to correct file (Stephen Niedzielski)
+* testsuitegenerator: Do not generate duplicate tests if config options are duplicated (Bartosz Dziewoński)
+
+
+## v0.31.3 / 2019-04-03
+### Features
+* SelectFileInputWidget: Support multiple files (Ed Sanders)
+* WikimediaUI theme: Allow inverted icons to appear anywhere (Roan Kattouw)
+
+### Styles
+* CheckboxMultiselect- & RadioselectInputWidget: Fix infusion reflow (Volker E.)
+* DropdownInputWidget: Make WikimediaUI version useable for non-JS users (Volker E.)
+* WikimediaUI theme: Increase and unify widget `line-height` (Volker E.)
+* WikimediaUI theme: Reduce accessory icon's opacity in non-focussed state (Volker E.)
+* WikimediaUI theme: Unify inlined FieldLayout padding (Volker E.)
+* icons: Add 'error' icon to 'alerts' pack (Volker E.)
+* icons: Amend 'helpNotice' filename (Volker E.)
+* icons: Make 'error' octagon regular (Ed Sanders)
+
+### Code
+* SelectFile(Input)Widget: Remove addInput and inline setupInput (Ed Sanders)
+* SelectFileInputWidget: Make 'title' behaviour consistent (Ed Sanders)
+* build: Bump non-qunit devDependencies to latest where possible (Volker E.)
+* build: Do not duplicate localisation messages and their docs in JS code (Bartosz Dziewoński)
+* build: Have 'quick-build' use 'build-code' to include messages (Ed Sanders)
+* build: Remove unnecessary 'enable-source-maps' task (Bartosz Dziewoński)
+* build: We distribute icon/indicator/texture manifests, too (James D. Forrester)
+* demos: Add Vietnamese labels (Volker E.)
+* demos: Add `title` to LTR/RTL ButtonWidgets (Volker E.)
+* demos: Re-order PHP TextInput demo to align with the JS demo (Volker E.)
+* docs: Fix syntax errors in MenuLayout (Huji Lee)
+
+
+## v0.31.2 / 2019-03-26
+### Features
+* CheckboxInputWidget: Add support for indeterminate state (Ed Sanders & Bartosz Dziewoński)
+
+### Code
+* DropdownInputWidget: Fix typo in Apex border styles (Ed Sanders)
+* SelectFileInputWidget: Apply IE11 scrolling fix (Ed Sanders)
+* TextInputWidget: Remove proprietary vendor UI extensions (Volker E.)
+* PHP: Tag: Use strict comparison for `array_search` (Ed Sanders)
+* icons: Identical optimization to both newspaper-ltr… and …rtl.svg icons (Thiemo Kreuz)
+* icons: Make use of the auto-closing feature in SVG `<path>`s (Thiemo Kreuz)
+* icons: Remove non-standard offset from web.svg icon (Thiemo Kreuz)
+* demo: Match PHP toolbar to JS (Ed Sanders)
+* build: Update package-lock.json (Ed Sanders)
+* build: Upgrade js-yaml sub-dependency from 3.12.1 to 3.13.0 for DoS fix (James D. Forrester)
+* packages: Massively trim down which files are in npm and composer packages (James D. Forrester)
+
+
+## v0.31.1 / 2019-03-21
+### Deprecations
+* [DEPRECATING CHANGE] core: Remove unused Date.now fallback (Timo Tijhof)
+* [DEPRECATING CHANGE] textures: Deprecate 'pending.gif' (Volker E.)
+* [DEPRECATING CHANGE] textures: Deprecate unused 'transparency' (Volker E.)
+
+### Features
+* MenuTagMultiselectWidget: `hideOnChoose` should be set to false (Moriel Schottlender)
+* MenuTagMultiselectWidget: `highlightOnFilter` only if not `allowArbitrary` (Moriel Schottlender)
+* MenuTagMultiselectWidget: Fix highlight and scrolling to item behavior (Moriel Schottlender)
+* SearchInputWidget: Use click handler for indicator (Ed Sanders)
+* SelectWidget: Allow multiselect mode, add to MenuTagMultiselectWidget (Moriel Schottlender)
+* SelectFileWidget: Support a button-only mode (Ed Sanders)
+* SelectFileWidget: Suppress misleading browser default tooltips (Bartosz Dziewoński)
+* SelectFileInputWidget: Create as a super-class of SelectFileWidget (Ed Sanders)
+* SelectFileInputWidget: Allow button config to be passed (Ed Sanders)
+* TagMultiselectWidget: Edit by item label, not data (Moriel Schottlender)
+
+### Styles
+* Separate SelectFileWidget and SelectFileInputWidget styles (Ed Sanders)
+* themes: Provide `background` needed for PendingElement on inputs (Volker E.)
+* themes: Replace 'pending.gif' with CSS animation (Volker E.)
+* icons: Manually rewrite paths of tableMove….svg icons (Thiemo Kreuz)
+* icons: Recreate settings.svg icon with shorter syntax (Thiemo Kreuz)
+* icons: Remove invisible parts from web.svg icon (Thiemo Kreuz)
+* icons: Remove unused dotted borders from imageLayout….svg icons (Thiemo Kreuz)
+* icons: Use rounded <rect> elements to optimize some SVG icons (Thiemo Kreuz)
+
+### Code
+* MenuSectionOptionWidget: Avoid select events (Gabriel Birke)
+* SelectFileInputWidget: Rewrite as an ActionFieldLayout (Ed Sanders)
+* testsuitegenerator: Reduce PHP test count by 40% (Ed Sanders)
+* testsuitegenerator: Reduce some code duplication (Bartosz Dziewoński)
+* testsuitegenerator: Use normal methods more instead of lambdas (Bartosz Dziewoński)
+* docs: Clarify some types in documentation (Bartosz Dziewoński)
+* docs: Fix missing `;` and typos in documentation examples (Volker E.)
+* demos: Make demo toolbar narrower (Ed Sanders)
+* build: Specify library entry (Stephen Niedzielski)
+* Grunt: Add a quick-build-code task for JS-only quick builds (Ed Sanders)
+
+
 ## v0.31.0 / 2019-03-13
 ### Breaking changes
 * [BREAKING CHANGE] Remove FlaggedElement from InputWidget (Ed Sanders)
index e6e4463..ae6171d 100644 (file)
@@ -31,6 +31,7 @@
        "ooui-dialog-process-dismiss": "رد",
        "ooui-dialog-process-retry": "دوباره امتحان کنید",
        "ooui-dialog-process-continue": "ادامه",
+       "ooui-combobox-button-label": "پایین‌رونده برای جعبهٔ پایین‌رونده",
        "ooui-selectfile-button-select": "یک فایل انتخاب کنید",
        "ooui-selectfile-not-supported": "انتخاب پرونده پشتیبانی نمی‌شود",
        "ooui-selectfile-placeholder": "هیچ پرونده‌ای انتخاب نشده است",
index 22174f7..291ecd3 100644 (file)
@@ -22,6 +22,7 @@
        "ooui-dialog-process-dismiss": "Agochar",
        "ooui-dialog-process-retry": "Inténteo de novo",
        "ooui-dialog-process-continue": "Continuar",
+       "ooui-combobox-button-label": "Lista despregable para caixa combinada",
        "ooui-selectfile-button-select": "Seleccionar un ficheiro",
        "ooui-selectfile-not-supported": "Non está soportada a selección de ficheiros",
        "ooui-selectfile-placeholder": "Non se seleccionou ningún ficheiro",
index 598fee3..7b94a9f 100644 (file)
@@ -5,7 +5,8 @@
                        "Xelgen",
                        "Դավիթ Սարոյան",
                        "Vahe Gharakhanyan",
-                       "Kareyac"
+                       "Kareyac",
+                       "GeoO"
                ]
        },
        "ooui-outline-control-move-down": "Իջեցնել ներքև",
@@ -24,5 +25,5 @@
        "ooui-selectfile-button-select": "Ընտրել նիշք",
        "ooui-selectfile-not-supported": "Ֆայլի ընտրությունը չի պաշտպանվում",
        "ooui-selectfile-placeholder": "Ֆայլն ընտրված չէ",
-       "ooui-selectfile-dragdrop-placeholder": "Õ\96Õ¡ÕµÕ¬Õ¨ Õ£Ö\81Õ¥Õ¬ Õ¡ÕµÕ½Õ¿Õ¥"
+       "ooui-selectfile-dragdrop-placeholder": "Õ\96Õ¡ÕµÕ¬Õ¨ Õ¢Õ¥Ö\80Õ¥Õ¬ Õ¡ÕµÕ½Õ¿Õ¥Õ²"
 }
index 4264be5..2ae08bb 100644 (file)
@@ -9,7 +9,7 @@
                ]
        },
        "ooui-outline-control-move-down": "Lih barang mangisor",
-       "ooui-outline-control-move-up": "Lih barang mandhuwur",
+       "ooui-outline-control-move-up": "Lih barangé munggah",
        "ooui-outline-control-remove": "Buwang barang",
        "ooui-toolbar-more": "Liyané",
        "ooui-toolgroup-expand": "Liyané",
index de8c5bb..fec09a1 100644 (file)
@@ -25,6 +25,7 @@
        "ooui-dialog-process-dismiss": "Lukk",
        "ooui-dialog-process-retry": "Prøv igjen",
        "ooui-dialog-process-continue": "Fortsett",
+       "ooui-combobox-button-label": "Rullegardinliste for komboboks",
        "ooui-selectfile-button-select": "Velg en fil",
        "ooui-selectfile-not-supported": "Filvalg er ikke støttet",
        "ooui-selectfile-placeholder": "Ingen fil er valgt",
index 8847ef2..623deda 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOUI v0.31.0
+ * OOUI v0.31.6
  * https://www.mediawiki.org/wiki/OOUI
  *
  * Copyright 2011–2019 OOUI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2019-03-14T00:52:20Z
+ * Date: 2019-05-08T10:08:36Z
  */
 ( function ( OO ) {
 
index c298481..dab2e33 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOUI v0.31.0
+ * OOUI v0.31.6
  * https://www.mediawiki.org/wiki/OOUI
  *
  * Copyright 2011–2019 OOUI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2019-03-14T00:52:27Z
+ * Date: 2019-05-08T10:08:44Z
  */
 .oo-ui-element-hidden {
   display: none !important;
 }
 
 .oo-ui-pendingElement-pending {
-  background-image: /* @embed */ url(themes/wikimediaui/images/textures/pending.gif);
+  background-color: #ddd;
+  background-image: -webkit-linear-gradient(135deg, #fff 25%, transparent 25%, transparent 50%, #fff 50%, #fff 75%, transparent 75%, transparent);
+  background-image: -moz-linear-gradient(135deg, #fff 25%, transparent 25%, transparent 50%, #fff 50%, #fff 75%, transparent 75%, transparent);
+  background-image: linear-gradient(135deg, #fff 25%, transparent 25%, transparent 50%, #fff 50%, #fff 75%, transparent 75%, transparent);
+  background-size: 1.5625em 1.5625em;
+  -webkit-animation: oo-ui-pendingElement-stripes 650ms linear infinite;
+  -moz-animation: oo-ui-pendingElement-stripes 650ms linear infinite;
+  animation: oo-ui-pendingElement-stripes 650ms linear infinite;
+}
+@-webkit-keyframes oo-ui-pendingElement-stripes {
+  0% {
+    background-position: -1.5625em 0;
+  }
+  100% {
+    background-position: 0 0;
+  }
+}
+@-moz-keyframes oo-ui-pendingElement-stripes {
+  0% {
+    background-position: -1.5625em 0;
+  }
+  100% {
+    background-position: 0 0;
+  }
+}
+@keyframes oo-ui-pendingElement-stripes {
+  0% {
+    background-position: -1.5625em 0;
+  }
+  100% {
+    background-position: 0 0;
+  }
 }
 
 
 .oo-ui-fieldLayout .oo-ui-fieldLayout-help {
   float: right;
 }
-.oo-ui-fieldLayout .oo-ui-fieldLayout-help > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
-  z-index: 1;
-}
 .oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-help,
 .oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-help {
   margin-right: 0;
@@ -549,9 +577,6 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
 .oo-ui-fieldsetLayout .oo-ui-fieldsetLayout-help {
   float: right;
 }
-.oo-ui-fieldsetLayout .oo-ui-fieldsetLayout-help > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
-  z-index: 1;
-}
 .oo-ui-fieldsetLayout .oo-ui-fieldsetLayout-header {
   max-width: 50em;
 }
@@ -696,7 +721,6 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
 
 .oo-ui-radioOptionWidget {
   display: table;
-  width: 100%;
   padding: 0.3125em 0;
 }
 .oo-ui-radioOptionWidget .oo-ui-radioInputWidget,
@@ -831,15 +855,14 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
 
 .oo-ui-popupWidget {
   position: absolute;
+  z-index: 1;
 }
 .oo-ui-popupWidget-popup {
   position: relative;
   overflow: hidden;
-  z-index: 1;
 }
 .oo-ui-popupWidget-anchor {
   display: none;
-  z-index: 1;
 }
 .oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor {
   display: block;
@@ -909,6 +932,14 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
   border-radius: 3px;
   box-shadow: 0 0.15em 0.5em 0 rgba(0, 0, 0, 0.2);
 }
+@supports ( filter: drop-shadow( 0 0 0 ) ) {
+  .oo-ui-popupWidget {
+    filter: drop-shadow(0 0.15em 0.5em rgba(0, 0, 0, 0.2));
+  }
+  .oo-ui-popupWidget-popup {
+    box-shadow: none;
+  }
+}
 .oo-ui-popupWidget-anchored-top {
   margin-top: 6px;
 }
@@ -918,7 +949,7 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
 .oo-ui-popupWidget-anchored-top .oo-ui-popupWidget-anchor:before {
   bottom: -7px;
   left: -6px;
-  border-bottom-color: #aaa;
+  border-bottom-color: #a8a8a8;
   border-width: 7px;
 }
 .oo-ui-popupWidget-anchored-top .oo-ui-popupWidget-anchor:after {
@@ -1041,6 +1072,9 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
 .oo-ui-checkboxMultiselectInputWidget .oo-ui-fieldLayout .oo-ui-fieldLayout-body {
   padding: 0.3125em 0;
 }
+.oo-ui-checkboxMultiselectInputWidget .oo-ui-fieldLayout .oo-ui-labelElement-label {
+  line-height: 1.5;
+}
 
 .oo-ui-dropdownInputWidget {
   position: relative;
@@ -1073,7 +1107,7 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
   padding: 0.5em;
   font-size: inherit;
   font-family: inherit;
-  border: #ccc;
+  border: 1px solid #ccc;
   border-radius: 3px;
 }
 .oo-ui-dropdownInputWidget option {
@@ -1106,6 +1140,9 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
 .oo-ui-radioSelectInputWidget .oo-ui-fieldLayout .oo-ui-fieldLayout-body {
   padding: 0.3125em 0;
 }
+.oo-ui-radioSelectInputWidget .oo-ui-fieldLayout .oo-ui-labelElement-label {
+  line-height: 1.5;
+}
 
 .oo-ui-textInputWidget {
   position: relative;
@@ -1117,32 +1154,30 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
   max-width: 50em;
 }
 .oo-ui-textInputWidget .oo-ui-inputWidget-input {
+  -webkit-appearance: none;
   display: block;
   width: 100%;
   -webkit-box-sizing: border-box;
   -moz-box-sizing: border-box;
   box-sizing: border-box;
 }
+.oo-ui-textInputWidget input {
+  -moz-appearance: textfield;
+}
+.oo-ui-textInputWidget input::-ms-clear {
+  display: none;
+}
 .oo-ui-textInputWidget textarea {
   overflow: auto;
 }
 .oo-ui-textInputWidget textarea.oo-ui-textInputWidget-autosized {
   resize: none;
 }
-.oo-ui-textInputWidget [type='number'] {
-  -moz-appearance: textfield;
-}
 .oo-ui-textInputWidget [type='number']::-webkit-outer-spin-button,
 .oo-ui-textInputWidget [type='number']::-webkit-inner-spin-button {
   -webkit-appearance: none;
   margin: 0;
 }
-.oo-ui-textInputWidget [type='search'] {
-  -webkit-appearance: none;
-}
-.oo-ui-textInputWidget [type='search']::-ms-clear {
-  display: none;
-}
 .oo-ui-textInputWidget [type='search']::-webkit-search-decoration,
 .oo-ui-textInputWidget [type='search']::-webkit-search-cancel-button {
   display: none;
@@ -1204,7 +1239,7 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
   line-height: 1.275;
 }
 .oo-ui-textInputWidget .oo-ui-pendingElement-pending {
-  background-color: transparent;
+  background-color: #ddd;
 }
 .oo-ui-textInputWidget.oo-ui-iconElement > .oo-ui-iconElement-icon,
 .oo-ui-textInputWidget.oo-ui-indicatorElement > .oo-ui-indicatorElement-indicator {
@@ -1297,7 +1332,7 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
   box-shadow: 0 0.15em 1em 0 rgba(0, 0, 0, 0.2);
 }
 .oo-ui-menuSelectWidget.oo-ui-clippableElement-clippable {
-  min-height: 2.6em;
+  min-height: 2.286em;
 }
 .oo-ui-menuSelectWidget-invisible {
   display: none;
@@ -1523,7 +1558,6 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
 
 .oo-ui-checkboxMultioptionWidget {
   display: table;
-  width: 100%;
   padding: 0.3125em 0;
 }
 .oo-ui-checkboxMultioptionWidget .oo-ui-checkboxInputWidget,
@@ -1659,6 +1693,68 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
   border-left-width: 0;
 }
 
+.oo-ui-selectFileInputWidget {
+  width: 100%;
+  max-width: 50em;
+  margin-right: 0.5em;
+}
+.oo-ui-selectFileInputWidget-selectButton > .oo-ui-buttonElement-button {
+  position: relative;
+  overflow: hidden;
+}
+.oo-ui-selectFileInputWidget-selectButton > .oo-ui-buttonElement-button > [type='file'] {
+  position: absolute;
+  top: 0;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  width: 100%;
+  height: 100%;
+  opacity: 0;
+  z-index: 1;
+  cursor: pointer;
+  padding-top: 100px;
+}
+.oo-ui-selectFileInputWidget-selectButton.oo-ui-widget-disabled > .oo-ui-buttonElement-button > [type='file'] {
+  display: none;
+}
+.oo-ui-selectFileInputWidget-info > .oo-ui-inputWidget-input {
+  pointer-events: none;
+}
+.oo-ui-selectFileInputWidget-label {
+  position: absolute;
+  top: 0;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  text-overflow: ellipsis;
+}
+.oo-ui-selectFileInputWidget-clearButton {
+  position: absolute;
+  z-index: 2;
+}
+.oo-ui-selectFileInputWidget-empty .oo-ui-selectFileInputWidget-clearButton {
+  display: none;
+}
+.oo-ui-selectFileInputWidget-empty.oo-ui-widget-enabled .oo-ui-selectFileInputWidget-label {
+  cursor: default;
+}
+.oo-ui-selectFileInputWidget:last-child {
+  margin-right: 0;
+}
+.oo-ui-selectFileInputWidget-label {
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+  left: 0.5em;
+  right: 2.175em;
+  line-height: 2.3em;
+  margin: 0;
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+}
+
 .oo-ui-defaultOverlay {
   position: absolute;
   top: 0;
index 6766494..b2e0483 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOUI v0.31.0
+ * OOUI v0.31.6
  * https://www.mediawiki.org/wiki/OOUI
  *
  * Copyright 2011–2019 OOUI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2019-03-14T00:52:27Z
+ * Date: 2019-05-08T10:08:44Z
  */
 .oo-ui-element-hidden {
   display: none !important;
@@ -65,7 +65,7 @@
 }
 .oo-ui-buttonElement.oo-ui-labelElement > input.oo-ui-buttonElement-button,
 .oo-ui-buttonElement.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
-  line-height: 1;
+  line-height: 1.28571429em;
 }
 .oo-ui-buttonElement.oo-ui-labelElement.oo-ui-indicatorElement > .oo-ui-buttonElement-button {
   padding-right: 2.28571429em;
   border-color: transparent;
   border-style: solid;
   border-width: 1px;
-  padding: 0.57142857em 0.14285714em;
+  padding: 0.42857143em 0.14285714em;
 }
 .oo-ui-buttonElement-frameless.oo-ui-labelElement.oo-ui-iconElement > .oo-ui-buttonElement-button {
   padding-left: 2.14285714em;
 }
 .oo-ui-buttonElement-frameless.oo-ui-indicatorElement.oo-ui-labelElement > .oo-ui-buttonElement-button {
   padding-left: 0.14285714em;
-  padding-top: 0.57142857em;
+  padding-top: 0.42857143em;
 }
 .oo-ui-buttonElement-frameless.oo-ui-indicatorElement.oo-ui-iconElement.oo-ui-labelElement > .oo-ui-buttonElement-button {
   padding-left: 2.14285714em;
   padding-right: 2.28571429em;
 }
 .oo-ui-buttonElement-framed.oo-ui-labelElement > .oo-ui-buttonElement-button {
-  padding-top: 0.57142857em;
-  padding-bottom: 0.57142857em;
+  padding-top: 0.42857143em;
+  padding-bottom: 0.42857143em;
 }
 .oo-ui-buttonElement-framed.oo-ui-widget-disabled > .oo-ui-buttonElement-button {
   background-color: #c8ccd1;
 }
 
 .oo-ui-pendingElement-pending {
-  background-image: /* @embed */ url(themes/wikimediaui/images/textures/pending.gif);
+  background-color: #eaecf0;
+  background-image: -webkit-linear-gradient(135deg, #fff 25%, transparent 25%, transparent 50%, #fff 50%, #fff 75%, transparent 75%, transparent);
+  background-image: -moz-linear-gradient(135deg, #fff 25%, transparent 25%, transparent 50%, #fff 50%, #fff 75%, transparent 75%, transparent);
+  background-image: linear-gradient(135deg, #fff 25%, transparent 25%, transparent 50%, #fff 50%, #fff 75%, transparent 75%, transparent);
+  background-size: 1.42857143em 1.42857143em;
+  -webkit-animation: oo-ui-pendingElement-stripes 650ms linear infinite;
+  -moz-animation: oo-ui-pendingElement-stripes 650ms linear infinite;
+  animation: oo-ui-pendingElement-stripes 650ms linear infinite;
+}
+@-webkit-keyframes oo-ui-pendingElement-stripes {
+  0% {
+    background-position: -1.42857143em 0;
+  }
+  100% {
+    background-position: 0 0;
+  }
+}
+@-moz-keyframes oo-ui-pendingElement-stripes {
+  0% {
+    background-position: -1.42857143em 0;
+  }
+  100% {
+    background-position: 0 0;
+  }
+}
+@keyframes oo-ui-pendingElement-stripes {
+  0% {
+    background-position: -1.42857143em 0;
+  }
+  100% {
+    background-position: 0 0;
+  }
 }
 
 
 .oo-ui-fieldLayout .oo-ui-fieldLayout-help {
   float: right;
 }
-.oo-ui-fieldLayout .oo-ui-fieldLayout-help > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
-  z-index: 1;
-}
 .oo-ui-fieldLayout.oo-ui-labelElement,
 .oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline {
   margin-top: 0.85714286em;
 .oo-ui-fieldLayout.oo-ui-labelElement.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-header {
   padding-top: 0;
   padding-bottom: 0;
-  padding-left: 0.57142857em;
+  padding-left: 0.42857143em;
 }
 .oo-ui-fieldLayout .oo-ui-fieldLayout-help {
   margin-right: 0;
@@ -683,9 +711,6 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
 .oo-ui-fieldsetLayout .oo-ui-fieldsetLayout-help {
   float: right;
 }
-.oo-ui-fieldsetLayout .oo-ui-fieldsetLayout-help > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
-  z-index: 1;
-}
 .oo-ui-fieldsetLayout .oo-ui-fieldsetLayout-header {
   max-width: 50em;
 }
@@ -805,7 +830,7 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
 }
 
 .oo-ui-decoratedOptionWidget {
-  padding: 0.57142857em 0.85714286em;
+  padding: 0.5em 0.85714286em;
   line-height: 1;
 }
 .oo-ui-decoratedOptionWidget.oo-ui-iconElement {
@@ -815,7 +840,7 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
   left: 0.78571429em;
 }
 .oo-ui-decoratedOptionWidget .oo-ui-labelElement-label {
-  line-height: 1.14285714em;
+  line-height: 1.28571429em;
 }
 .oo-ui-decoratedOptionWidget.oo-ui-indicatorElement {
   padding-right: 2.28571429em;
@@ -848,7 +873,6 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
 
 .oo-ui-radioOptionWidget {
   display: table;
-  width: 100%;
   padding: 0.28571429em 0;
 }
 .oo-ui-radioOptionWidget .oo-ui-radioInputWidget,
@@ -862,6 +886,9 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
 .oo-ui-radioOptionWidget.oo-ui-labelElement > .oo-ui-labelElement-label {
   white-space: normal;
 }
+.oo-ui-radioOptionWidget:first-child {
+  margin-top: -0.28571429em;
+}
 .oo-ui-radioOptionWidget.oo-ui-labelElement .oo-ui-labelElement-label {
   padding-left: 0.42857143em;
 }
@@ -984,15 +1011,14 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
 
 .oo-ui-popupWidget {
   position: absolute;
+  z-index: 1;
 }
 .oo-ui-popupWidget-popup {
   position: relative;
   overflow: hidden;
-  z-index: 1;
 }
 .oo-ui-popupWidget-anchor {
   display: none;
-  z-index: 1;
 }
 .oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor {
   display: block;
@@ -1062,6 +1088,14 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
   border-radius: 2px;
   box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.25);
 }
+@supports ( filter: drop-shadow( 0 0 0 ) ) {
+  .oo-ui-popupWidget {
+    filter: drop-shadow(0 2px 1px rgba(0, 0, 0, 0.3));
+  }
+  .oo-ui-popupWidget-popup {
+    box-shadow: none;
+  }
+}
 .oo-ui-popupWidget-anchored-top {
   margin-top: 9px;
 }
@@ -1071,7 +1105,7 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
 .oo-ui-popupWidget-anchored-top .oo-ui-popupWidget-anchor:before {
   bottom: -10px;
   left: -9px;
-  border-bottom-color: #a2a9b1;
+  border-bottom-color: #7b8590;
   border-width: 10px;
 }
 .oo-ui-popupWidget-anchored-top .oo-ui-popupWidget-anchor:after {
@@ -1140,8 +1174,8 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
   transition: width 100ms, height 100ms, left 100ms;
 }
 .oo-ui-popupWidget-head > .oo-ui-labelElement-label {
-  margin: 0.64285714em 2.64285714em 0.57142857em 0.85714286em;
-  line-height: 1;
+  margin: 0.64285714em 2.64285714em 0.42857143em 0.85714286em;
+  line-height: 1.28571429em;
 }
 .oo-ui-popupWidget-head > .oo-ui-buttonWidget {
   right: 0;
@@ -1153,13 +1187,13 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
   line-height: 1.42857143em;
 }
 .oo-ui-popupWidget-body-padded {
-  margin: 0.64285714em 0.85714286em 0.57142857em;
+  margin: 0.64285714em 0.85714286em 0.42857143em;
 }
 .oo-ui-popupWidget-body-padded > :first-child {
   margin-top: 0;
 }
 .oo-ui-popupWidget-footer {
-  margin: 0.64285714em 0.85714286em 0.57142857em;
+  margin: 0.64285714em 0.85714286em 0.42857143em;
 }
 
 .oo-ui-popupButtonWidget {
@@ -1214,12 +1248,26 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
   left: 0;
   width: 1.42857143em;
   height: 1.42857143em;
-  border: 1px solid #72777d;
+  border-color: #72777d;
+  border-style: solid;
   border-radius: 2px;
+  border-width: 0;
+}
+:root .oo-ui-checkboxInputWidget [type='checkbox'] + span {
+  border-width: 1px;
 }
-.oo-ui-checkboxInputWidget [type='checkbox']:checked + span {
+.oo-ui-checkboxInputWidget [type='checkbox']:checked:not( :indeterminate ) + span {
   background-size: 1em 1em;
 }
+.oo-ui-checkboxInputWidget [type='checkbox']:indeterminate + span:before {
+  content: ' ';
+  position: absolute;
+  top: 0.57142857em;
+  bottom: 0.57142857em;
+  left: 0.21428571em;
+  right: 0.21428571em;
+  background-color: #fff;
+}
 .oo-ui-checkboxInputWidget [type='checkbox']:disabled + span {
   background-color: #c8ccd1;
   border-color: #c8ccd1;
@@ -1245,27 +1293,35 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
   border-color: #2a4b8d;
   box-shadow: inset 0 0 0 1px #2a4b8d;
 }
-.oo-ui-checkboxInputWidget.oo-ui-widget-enabled [type='checkbox']:checked + span {
+.oo-ui-checkboxInputWidget.oo-ui-widget-enabled [type='checkbox']:checked + span,
+.oo-ui-checkboxInputWidget.oo-ui-widget-enabled [type='checkbox']:indeterminate + span {
   background-color: #36c;
   border-color: #36c;
 }
-.oo-ui-checkboxInputWidget.oo-ui-widget-enabled [type='checkbox']:checked:focus + span {
+.oo-ui-checkboxInputWidget.oo-ui-widget-enabled [type='checkbox']:checked:focus + span,
+.oo-ui-checkboxInputWidget.oo-ui-widget-enabled [type='checkbox']:indeterminate:focus + span {
   background-color: #36c;
   border-color: #36c;
   box-shadow: inset 0 0 0 1px #36c, inset 0 0 0 2px #fff;
 }
-.oo-ui-checkboxInputWidget.oo-ui-widget-enabled [type='checkbox']:checked:hover + span {
+.oo-ui-checkboxInputWidget.oo-ui-widget-enabled [type='checkbox']:checked:hover + span,
+.oo-ui-checkboxInputWidget.oo-ui-widget-enabled [type='checkbox']:indeterminate:hover + span {
   background-color: #447ff5;
   border-color: #447ff5;
 }
-.oo-ui-checkboxInputWidget.oo-ui-widget-enabled [type='checkbox']:checked:active + span {
+.oo-ui-checkboxInputWidget.oo-ui-widget-enabled [type='checkbox']:checked:active + span,
+.oo-ui-checkboxInputWidget.oo-ui-widget-enabled [type='checkbox']:indeterminate:active + span {
   background-color: #2a4b8d;
   border-color: #2a4b8d;
   box-shadow: inset 0 0 0 1px #2a4b8d;
 }
 
 .oo-ui-checkboxMultiselectInputWidget .oo-ui-fieldLayout {
-  margin-top: 0.28571429em;
+  margin-top: 0;
+  padding: 0.28571429em 0;
+}
+.oo-ui-checkboxMultiselectInputWidget .oo-ui-fieldLayout:first-child {
+  margin-top: -0.28571429em;
 }
 
 .oo-ui-dropdownInputWidget {
@@ -1293,20 +1349,18 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
 .oo-ui-dropdownInputWidget.oo-ui-widget-enabled select {
   cursor: pointer;
 }
-.oo-ui-dropdownInputWidget-php {
-  border-right: 1px solid #a2a9b1;
-  border-radius: 2px;
-  overflow-x: hidden;
-}
 .oo-ui-dropdownInputWidget select {
   -webkit-appearance: none;
   -moz-appearance: none;
+  background-color: transparent;
+  background-position: right 0.85714286em center;
   -webkit-box-sizing: border-box;
   -moz-box-sizing: border-box;
   box-sizing: border-box;
+  height: 2.28571429em;
   border: 1px solid #a2a9b1;
   border-radius: 2px;
-  padding: 0.57142857em 0.85714286em;
+  padding: 0.42857143em 0.85714286em;
   font-size: inherit;
   font-family: inherit;
   vertical-align: middle;
@@ -1314,27 +1368,35 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
 .oo-ui-dropdownInputWidget select::-ms-expand {
   display: none;
 }
-.oo-ui-dropdownInputWidget select:not( [no-ie] ) {
-  background-position: right 1.75em center;
-  width: calc( 100% + 1em );
-  height: 2.28571429em;
-  padding: 0 0 0 0.85714286em;
+@media screen and (min-width: 0 \0 ) {
+  .oo-ui-dropdownInputWidget select select {
+    background-image: none\9;
+    padding: 5px\9;
+  }
 }
 .oo-ui-dropdownInputWidget option {
+  background-color: transparent;
   font-size: inherit;
   font-family: inherit;
   height: 1.5em;
-  padding: 0.57142857em 0.85714286em;
+  padding: 0.42857143em 0.85714286em;
 }
-.oo-ui-dropdownInputWidget.oo-ui-widget-enabled select {
+.oo-ui-dropdownInputWidget.oo-ui-widget-enabled {
   background-color: #f8f9fa;
+  -webkit-transition: background-color 100ms;
+  -moz-transition: background-color 100ms;
+  transition: background-color 100ms;
+}
+.oo-ui-dropdownInputWidget.oo-ui-widget-enabled:hover {
+  background-color: #fff;
+}
+.oo-ui-dropdownInputWidget.oo-ui-widget-enabled select {
   color: #222;
-  -webkit-transition: background-color 100ms, border-color 100ms, box-shadow 100ms;
-  -moz-transition: background-color 100ms, border-color 100ms, box-shadow 100ms;
-  transition: background-color 100ms, border-color 100ms, box-shadow 100ms;
+  -webkit-transition: border-color 100ms, box-shadow 100ms;
+  -moz-transition: border-color 100ms, box-shadow 100ms;
+  transition: border-color 100ms, box-shadow 100ms;
 }
 .oo-ui-dropdownInputWidget.oo-ui-widget-enabled select:hover {
-  background-color: #fff;
   color: #444;
   border-color: #a2a9b1;
 }
@@ -1347,8 +1409,10 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
   outline: 0;
   box-shadow: inset 0 0 0 1px #36c;
 }
-.oo-ui-dropdownInputWidget.oo-ui-widget-disabled select {
+.oo-ui-dropdownInputWidget.oo-ui-widget-disabled {
   background-color: #eaecf0;
+}
+.oo-ui-dropdownInputWidget.oo-ui-widget-disabled select {
   color: #72777d;
   border-color: #c8ccd1;
 }
@@ -1382,8 +1446,13 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
   box-sizing: border-box;
   width: 1.42857143em;
   height: 1.42857143em;
-  border: 1px solid #72777d;
+  border-color: #72777d;
+  border-style: solid;
   border-radius: 100%;
+  border-width: 0;
+}
+:root .oo-ui-radioInputWidget [type='radio'] + span {
+  border-width: 1px;
 }
 .oo-ui-radioInputWidget [type='radio'] + span:before {
   content: ' ';
@@ -1441,7 +1510,11 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
 }
 
 .oo-ui-radioSelectInputWidget .oo-ui-fieldLayout {
-  margin-top: 0.28571429em;
+  margin-top: 0;
+  padding: 0.28571429em 0;
+}
+.oo-ui-radioSelectInputWidget .oo-ui-fieldLayout:first-child {
+  margin-top: -0.28571429em;
 }
 
 .oo-ui-textInputWidget {
@@ -1454,32 +1527,30 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
   max-width: 50em;
 }
 .oo-ui-textInputWidget .oo-ui-inputWidget-input {
+  -webkit-appearance: none;
   display: block;
   width: 100%;
   -webkit-box-sizing: border-box;
   -moz-box-sizing: border-box;
   box-sizing: border-box;
 }
+.oo-ui-textInputWidget input {
+  -moz-appearance: textfield;
+}
+.oo-ui-textInputWidget input::-ms-clear {
+  display: none;
+}
 .oo-ui-textInputWidget textarea {
   overflow: auto;
 }
 .oo-ui-textInputWidget textarea.oo-ui-textInputWidget-autosized {
   resize: none;
 }
-.oo-ui-textInputWidget [type='number'] {
-  -moz-appearance: textfield;
-}
 .oo-ui-textInputWidget [type='number']::-webkit-outer-spin-button,
 .oo-ui-textInputWidget [type='number']::-webkit-inner-spin-button {
   -webkit-appearance: none;
   margin: 0;
 }
-.oo-ui-textInputWidget [type='search'] {
-  -webkit-appearance: none;
-}
-.oo-ui-textInputWidget [type='search']::-ms-clear {
-  display: none;
-}
 .oo-ui-textInputWidget [type='search']::-webkit-search-decoration,
 .oo-ui-textInputWidget [type='search']::-webkit-search-cancel-button {
   display: none;
@@ -1522,25 +1593,21 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
   user-select: none;
 }
 .oo-ui-textInputWidget .oo-ui-inputWidget-input {
-  -webkit-appearance: none;
   background-color: #fff;
   color: #000;
   margin: 0;
   border: 1px solid #a2a9b1;
   border-radius: 2px;
-  padding: 0.57142857em 0.57142857em;
+  padding: 0.42857143em 0.57142857em;
   font-size: inherit;
   font-family: inherit;
+  line-height: 1.28571429em;
 }
 .oo-ui-textInputWidget input {
   height: 2.28571429em;
-  line-height: 1;
-}
-.oo-ui-textInputWidget textarea {
-  line-height: 1.286;
 }
 .oo-ui-textInputWidget .oo-ui-pendingElement-pending {
-  background-color: transparent;
+  background-color: #eaecf0;
 }
 .oo-ui-textInputWidget.oo-ui-iconElement .oo-ui-inputWidget-input {
   padding-left: 2.64285714em;
@@ -1554,8 +1621,8 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
 .oo-ui-textInputWidget > .oo-ui-labelElement-label {
   color: #72777d;
   margin-top: 1px;
-  padding: 0.57142857em 0.85714286em 0.57142857em 0.57142857em;
-  line-height: 1;
+  padding: 0.42857143em 0.85714286em 0.42857143em 0.57142857em;
+  line-height: 1.28571429em;
 }
 .oo-ui-textInputWidget.oo-ui-indicatorElement .oo-ui-inputWidget-input {
   padding-right: 2em;
@@ -1626,7 +1693,9 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
     outline-color: #d33;
   }
 }
-.oo-ui-textInputWidget.oo-ui-widget-enabled > .oo-ui-iconElement-icon,
+.oo-ui-textInputWidget.oo-ui-widget-enabled > .oo-ui-iconElement-icon {
+  opacity: 0.67;
+}
 .oo-ui-textInputWidget.oo-ui-widget-enabled > .oo-ui-indicatorElement-indicator {
   opacity: 0.87;
 }
@@ -1668,7 +1737,7 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
   box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.25);
 }
 .oo-ui-menuSelectWidget.oo-ui-clippableElement-clippable {
-  min-height: 2.6em;
+  min-height: 2.286em;
 }
 .oo-ui-menuSelectWidget-invisible {
   display: none;
@@ -1701,7 +1770,7 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
 
 .oo-ui-menuSectionOptionWidget {
   color: #72777d;
-  padding: 0.57142857em 0.85714286em 0.28571429em;
+  padding: 0.42857143em 0.85714286em 0.28571429em;
   font-weight: bold;
 }
 .oo-ui-menuSectionOptionWidget.oo-ui-widget-enabled {
@@ -1760,7 +1829,7 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
   min-height: 2.28571429em;
   border: 1px solid #a2a9b1;
   border-radius: 2px;
-  padding: 0.57142857em 0.85714286em;
+  padding: 0.42857143em 0.85714286em;
   line-height: 1;
 }
 .oo-ui-dropdownWidget-handle .oo-ui-iconElement-icon {
@@ -1770,7 +1839,7 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
   right: 0.78571429em;
 }
 .oo-ui-dropdownWidget-handle .oo-ui-labelElement-label {
-  line-height: 1;
+  line-height: 1.28571429em;
 }
 .oo-ui-dropdownWidget.oo-ui-iconElement .oo-ui-dropdownWidget-handle {
   padding-left: 2.64285714em;
@@ -1937,7 +2006,6 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
 
 .oo-ui-checkboxMultioptionWidget {
   display: table;
-  width: 100%;
   padding: 0.28571429em 0;
 }
 .oo-ui-checkboxMultioptionWidget .oo-ui-checkboxInputWidget,
@@ -1951,6 +2019,9 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
 .oo-ui-checkboxMultioptionWidget.oo-ui-labelElement > .oo-ui-labelElement-label {
   white-space: normal;
 }
+.oo-ui-checkboxMultioptionWidget:first-child {
+  margin-top: -0.28571429em;
+}
 .oo-ui-checkboxMultioptionWidget.oo-ui-labelElement .oo-ui-labelElement-label {
   padding-left: 0.42857143em;
 }
@@ -2083,6 +2154,70 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
   opacity: 1;
 }
 
+.oo-ui-selectFileInputWidget {
+  width: 100%;
+  max-width: 50em;
+  margin-right: 0.5em;
+}
+.oo-ui-selectFileInputWidget-selectButton > .oo-ui-buttonElement-button {
+  position: relative;
+  overflow: hidden;
+}
+.oo-ui-selectFileInputWidget-selectButton > .oo-ui-buttonElement-button > [type='file'] {
+  position: absolute;
+  top: 0;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  width: 100%;
+  height: 100%;
+  opacity: 0;
+  z-index: 1;
+  cursor: pointer;
+  padding-top: 100px;
+}
+.oo-ui-selectFileInputWidget-selectButton.oo-ui-widget-disabled > .oo-ui-buttonElement-button > [type='file'] {
+  display: none;
+}
+.oo-ui-selectFileInputWidget-info > .oo-ui-inputWidget-input {
+  pointer-events: none;
+}
+.oo-ui-selectFileInputWidget-label {
+  position: absolute;
+  top: 0;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  text-overflow: ellipsis;
+}
+.oo-ui-selectFileInputWidget-clearButton {
+  position: absolute;
+  z-index: 2;
+}
+.oo-ui-selectFileInputWidget-empty .oo-ui-selectFileInputWidget-clearButton {
+  display: none;
+}
+.oo-ui-selectFileInputWidget-empty.oo-ui-widget-enabled .oo-ui-selectFileInputWidget-label {
+  cursor: default;
+}
+.oo-ui-selectFileInputWidget:last-child {
+  margin-right: 0;
+}
+.oo-ui-selectFileInputWidget-label {
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+  display: block;
+  right: 2.85714286em;
+  padding-top: 0.42857143em;
+  padding-left: 0.57142857em;
+  padding-bottom: 0.42857143em;
+  white-space: nowrap;
+}
+.oo-ui-selectFileInputWidget.oo-ui-labelElement .oo-ui-selectFileInputWidget-label {
+  line-height: 1.28571429em;
+}
+
 .oo-ui-defaultOverlay {
   position: absolute;
   top: 0;
index c32844c..a51ba74 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOUI v0.31.0
+ * OOUI v0.31.6
  * https://www.mediawiki.org/wiki/OOUI
  *
  * Copyright 2011–2019 OOUI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2019-03-14T00:52:20Z
+ * Date: 2019-05-08T10:08:36Z
  */
 ( function ( OO ) {
 
@@ -295,7 +295,7 @@ OO.ui.throttle = function ( func, wait ) {
                previous = 0,
                run = function () {
                        timeout = null;
-                       previous = OO.ui.now();
+                       previous = Date.now();
                        func.apply( context, args );
                };
        return function () {
@@ -304,7 +304,7 @@ OO.ui.throttle = function ( func, wait ) {
                // period. If it's less, run the function immediately. If it's more,
                // set a timeout for the remaining time -- but don't replace an
                // existing timeout, since that'd indefinitely prolong the wait.
-               var remaining = wait - ( OO.ui.now() - previous );
+               var remaining = wait - ( Date.now() - previous );
                context = this;
                args = arguments;
                if ( remaining <= 0 ) {
@@ -323,10 +323,12 @@ OO.ui.throttle = function ( func, wait ) {
 /**
  * A (possibly faster) way to get the current timestamp as an integer.
  *
+ * @deprecated Since 0.31.1; use `Date.now()` instead.
  * @return {number} Current timestamp, in milliseconds since the Unix epoch
  */
-OO.ui.now = Date.now || function () {
-       return new Date().getTime();
+OO.ui.now = function () {
+       OO.ui.warnDeprecation( 'OO.ui.now() is deprecated, use Date.now() instead' );
+       return Date.now();
 };
 
 /**
@@ -345,124 +347,74 @@ OO.ui.infuse = function ( idOrNode, config ) {
        return OO.ui.Element.static.infuse( idOrNode, config );
 };
 
-( function () {
-       /**
-        * Message store for the default implementation of OO.ui.msg.
-        *
-        * Environments that provide a localization system should not use this, but should override
-        * OO.ui.msg altogether.
-        *
-        * @private
-        */
-       var messages = {
-               // Tool tip for a button that moves items in a list down one place
-               'ooui-outline-control-move-down': 'Move item down',
-               // Tool tip for a button that moves items in a list up one place
-               'ooui-outline-control-move-up': 'Move item up',
-               // Tool tip for a button that removes items from a list
-               'ooui-outline-control-remove': 'Remove item',
-               // Label for the toolbar group that contains a list of all other available tools
-               'ooui-toolbar-more': 'More',
-               // Label for the fake tool that expands the full list of tools in a toolbar group
-               'ooui-toolgroup-expand': 'More',
-               // Label for the fake tool that collapses the full list of tools in a toolbar group
-               'ooui-toolgroup-collapse': 'Fewer',
-               // Default label for the tooltip for the button that removes a tag item
-               'ooui-item-remove': 'Remove',
-               // Default label for the accept button of a confirmation dialog
-               'ooui-dialog-message-accept': 'OK',
-               // Default label for the reject button of a confirmation dialog
-               'ooui-dialog-message-reject': 'Cancel',
-               // Title for process dialog error description
-               'ooui-dialog-process-error': 'Something went wrong',
-               // Label for process dialog dismiss error button, visible when describing errors
-               'ooui-dialog-process-dismiss': 'Dismiss',
-               // Label for process dialog retry action button, visible when describing only recoverable
-               // errors
-               'ooui-dialog-process-retry': 'Try again',
-               // Label for process dialog retry action button, visible when describing only warnings
-               'ooui-dialog-process-continue': 'Continue',
-               // Label for button in combobox input that triggers its dropdown
-               'ooui-combobox-button-label': 'Dropdown for combobox',
-               // Label for the file selection widget's select file button
-               'ooui-selectfile-button-select': 'Select a file',
-               // Label for the file selection widget if file selection is not supported
-               'ooui-selectfile-not-supported': 'File selection is not supported',
-               // Label for the file selection widget when no file is currently selected
-               'ooui-selectfile-placeholder': 'No file is selected',
-               // Label for the file selection widget's drop target
-               'ooui-selectfile-dragdrop-placeholder': 'Drop file here',
-               // Label for the help icon attached to a form field
-               'ooui-field-help': 'Help'
-       };
-
-       /**
-        * Get a localized message.
-        *
-        * After the message key, message parameters may optionally be passed. In the default
-        * implementation, any occurrences of $1 are replaced with the first parameter, $2 with the
-        * second parameter, etc.
-        * Alternative implementations of OO.ui.msg may use any substitution system they like, as long
-        * as they support unnamed, ordered message parameters.
-        *
-        * In environments that provide a localization system, this function should be overridden to
-        * return the message translated in the user's language. The default implementation always
-        * returns English messages. An example of doing this with
-        * [jQuery.i18n](https://github.com/wikimedia/jquery.i18n) follows.
-        *
-        *     @example
-        *     var i, iLen, button,
-        *         messagePath = 'oojs-ui/dist/i18n/',
-        *         languages = [ $.i18n().locale, 'ur', 'en' ],
-        *         languageMap = {};
-        *
-        *     for ( i = 0, iLen = languages.length; i < iLen; i++ ) {
-        *         languageMap[ languages[ i ] ] = messagePath + languages[ i ].toLowerCase() + '.json';
-        *     }
-        *
-        *     $.i18n().load( languageMap ).done( function() {
-        *         // Replace the built-in `msg` only once we've loaded the internationalization.
-        *         // OOUI uses `OO.ui.deferMsg` for all initially-loaded messages. So long as
-        *         // you put off creating any widgets until this promise is complete, no English
-        *         // will be displayed.
-        *         OO.ui.msg = $.i18n;
-        *
-        *         // A button displaying "OK" in the default locale
-        *         button = new OO.ui.ButtonWidget( {
-        *             label: OO.ui.msg( 'ooui-dialog-message-accept' ),
-        *             icon: 'check'
-        *         } );
-        *         $( document.body ).append( button.$element );
-        *
-        *         // A button displaying "OK" in Urdu
-        *         $.i18n().locale = 'ur';
-        *         button = new OO.ui.ButtonWidget( {
-        *             label: OO.ui.msg( 'ooui-dialog-message-accept' ),
-        *             icon: 'check'
-        *         } );
-        *         $( document.body ).append( button.$element );
-        *     } );
-        *
-        * @param {string} key Message key
-        * @param {...Mixed} [params] Message parameters
-        * @return {string} Translated message with parameters substituted
-        */
-       OO.ui.msg = function ( key ) {
-               var message = messages[ key ],
-                       params = Array.prototype.slice.call( arguments, 1 );
-               if ( typeof message === 'string' ) {
-                       // Perform $1 substitution
-                       message = message.replace( /\$(\d+)/g, function ( unused, n ) {
-                               var i = parseInt( n, 10 );
-                               return params[ i - 1 ] !== undefined ? params[ i - 1 ] : '$' + n;
-                       } );
-               } else {
-                       // Return placeholder if message not found
-                       message = '[' + key + ']';
-               }
-               return message;
-       };
-}() );
+/**
+ * Get a localized message.
+ *
+ * After the message key, message parameters may optionally be passed. In the default
+ * implementation, any occurrences of $1 are replaced with the first parameter, $2 with the
+ * second parameter, etc.
+ * Alternative implementations of OO.ui.msg may use any substitution system they like, as long
+ * as they support unnamed, ordered message parameters.
+ *
+ * In environments that provide a localization system, this function should be overridden to
+ * return the message translated in the user's language. The default implementation always
+ * returns English messages. An example of doing this with
+ * [jQuery.i18n](https://github.com/wikimedia/jquery.i18n) follows.
+ *
+ *     @example
+ *     var i, iLen, button,
+ *         messagePath = 'oojs-ui/dist/i18n/',
+ *         languages = [ $.i18n().locale, 'ur', 'en' ],
+ *         languageMap = {};
+ *
+ *     for ( i = 0, iLen = languages.length; i < iLen; i++ ) {
+ *         languageMap[ languages[ i ] ] = messagePath + languages[ i ].toLowerCase() + '.json';
+ *     }
+ *
+ *     $.i18n().load( languageMap ).done( function() {
+ *         // Replace the built-in `msg` only once we've loaded the internationalization.
+ *         // OOUI uses `OO.ui.deferMsg` for all initially-loaded messages. So long as
+ *         // you put off creating any widgets until this promise is complete, no English
+ *         // will be displayed.
+ *         OO.ui.msg = $.i18n;
+ *
+ *         // A button displaying "OK" in the default locale
+ *         button = new OO.ui.ButtonWidget( {
+ *             label: OO.ui.msg( 'ooui-dialog-message-accept' ),
+ *             icon: 'check'
+ *         } );
+ *         $( document.body ).append( button.$element );
+ *
+ *         // A button displaying "OK" in Urdu
+ *         $.i18n().locale = 'ur';
+ *         button = new OO.ui.ButtonWidget( {
+ *             label: OO.ui.msg( 'ooui-dialog-message-accept' ),
+ *             icon: 'check'
+ *         } );
+ *         $( document.body ).append( button.$element );
+ *     } );
+ *
+ * @param {string} key Message key
+ * @param {...Mixed} [params] Message parameters
+ * @return {string} Translated message with parameters substituted
+ */
+OO.ui.msg = function ( key ) {
+       // `OO.ui.msg.messages` is defined in code generated during the build process
+       var messages = OO.ui.msg.messages,
+               message = messages[ key ],
+               params = Array.prototype.slice.call( arguments, 1 );
+       if ( typeof message === 'string' ) {
+               // Perform $1 substitution
+               message = message.replace( /\$(\d+)/g, function ( unused, n ) {
+                       var i = parseInt( n, 10 );
+                       return params[ i - 1 ] !== undefined ? params[ i - 1 ] : '$' + n;
+               } );
+       } else {
+               // Return placeholder if message not found
+               message = '[' + key + ']';
+       }
+       return message;
+};
 
 /**
  * Package a message and arguments for deferred resolution.
@@ -581,6 +533,36 @@ OO.ui.getDefaultOverlay = function () {
        return OO.ui.$defaultOverlay;
 };
 
+/**
+ * Message store for the default implementation of OO.ui.msg.
+ *
+ * Environments that provide a localization system should not use this, but should override
+ * OO.ui.msg altogether.
+ *
+ * @private
+ */
+OO.ui.msg.messages = {
+       "ooui-outline-control-move-down": "Move item down",
+       "ooui-outline-control-move-up": "Move item up",
+       "ooui-outline-control-remove": "Remove item",
+       "ooui-toolbar-more": "More",
+       "ooui-toolgroup-expand": "More",
+       "ooui-toolgroup-collapse": "Fewer",
+       "ooui-item-remove": "Remove",
+       "ooui-dialog-message-accept": "OK",
+       "ooui-dialog-message-reject": "Cancel",
+       "ooui-dialog-process-error": "Something went wrong",
+       "ooui-dialog-process-dismiss": "Dismiss",
+       "ooui-dialog-process-retry": "Try again",
+       "ooui-dialog-process-continue": "Continue",
+       "ooui-combobox-button-label": "Dropdown for combobox",
+       "ooui-selectfile-button-select": "Select a file",
+       "ooui-selectfile-not-supported": "File selection is not supported",
+       "ooui-selectfile-placeholder": "No file is selected",
+       "ooui-selectfile-dragdrop-placeholder": "Drop file here",
+       "ooui-field-help": "Help"
+};
+
 /*!
  * Mixin namespace.
  */
@@ -1301,75 +1283,107 @@ OO.ui.Element.static.getClosestScrollableContainer = function ( el, dimension )
  * Scroll element into view.
  *
  * @static
- * @param {HTMLElement} el Element to scroll into view
+ * @param {HTMLElement|Object} elOrPosition Element to scroll into view
  * @param {Object} [config] Configuration options
+ * @param {string} [config.animate=true] Animate to the new scroll offset.
  * @param {string} [config.duration='fast'] jQuery animation duration value
  * @param {string} [config.direction] Scroll in only one direction, e.g. 'x' or 'y', omit
  *  to scroll in both directions
+ * @param {Object} [config.padding] Additional padding on the container to scroll past.
+ *  Object containing any of 'top', 'bottom', 'left', or 'right' as numbers.
+ * @param {Object} [config.scrollContainer] Scroll container. Defaults to
+ *  getClosestScrollableContainer of the element.
  * @return {jQuery.Promise} Promise which resolves when the scroll is complete
  */
-OO.ui.Element.static.scrollIntoView = function ( el, config ) {
-       var position, animations, container, $container, elementDimensions, containerDimensions,
-               $window,
+OO.ui.Element.static.scrollIntoView = function ( elOrPosition, config ) {
+       var position, animations, container, $container, elementPosition, containerDimensions,
+               $window, padding, animate, method,
                deferred = $.Deferred();
 
        // Configuration initialization
        config = config || {};
 
+       padding = $.extend( {
+               top: 0,
+               bottom: 0,
+               left: 0,
+               right: 0
+       }, config.padding );
+
+       animate = config.animate !== false;
+
        animations = {};
-       container = this.getClosestScrollableContainer( el, config.direction );
+       elementPosition = elOrPosition instanceof HTMLElement ?
+               this.getDimensions( elOrPosition ).rect :
+               elOrPosition;
+       container = config.scrollContainer || (
+               elOrPosition instanceof HTMLElement ?
+                       this.getClosestScrollableContainer( elOrPosition, config.direction ) :
+                       // No scrollContainer or element
+                       this.getClosestScrollableContainer( document.body )
+       );
        $container = $( container );
-       elementDimensions = this.getDimensions( el );
        containerDimensions = this.getDimensions( container );
-       $window = $( this.getWindow( el ) );
+       $window = $( this.getWindow( container ) );
 
        // Compute the element's position relative to the container
        if ( $container.is( 'html, body' ) ) {
                // If the scrollable container is the root, this is easy
                position = {
-                       top: elementDimensions.rect.top,
-                       bottom: $window.innerHeight() - elementDimensions.rect.bottom,
-                       left: elementDimensions.rect.left,
-                       right: $window.innerWidth() - elementDimensions.rect.right
+                       top: elementPosition.top,
+                       bottom: $window.innerHeight() - elementPosition.bottom,
+                       left: elementPosition.left,
+                       right: $window.innerWidth() - elementPosition.right
                };
        } else {
                // Otherwise, we have to subtract el's coordinates from container's coordinates
                position = {
-                       top: elementDimensions.rect.top -
+                       top: elementPosition.top -
                                ( containerDimensions.rect.top + containerDimensions.borders.top ),
                        bottom: containerDimensions.rect.bottom - containerDimensions.borders.bottom -
-                               containerDimensions.scrollbar.bottom - elementDimensions.rect.bottom,
-                       left: elementDimensions.rect.left -
+                               containerDimensions.scrollbar.bottom - elementPosition.bottom,
+                       left: elementPosition.left -
                                ( containerDimensions.rect.left + containerDimensions.borders.left ),
                        right: containerDimensions.rect.right - containerDimensions.borders.right -
-                               containerDimensions.scrollbar.right - elementDimensions.rect.right
+                               containerDimensions.scrollbar.right - elementPosition.right
                };
        }
 
        if ( !config.direction || config.direction === 'y' ) {
-               if ( position.top < 0 ) {
-                       animations.scrollTop = containerDimensions.scroll.top + position.top;
-               } else if ( position.top > 0 && position.bottom < 0 ) {
+               if ( position.top < padding.top ) {
+                       animations.scrollTop = containerDimensions.scroll.top + position.top - padding.top;
+               } else if ( position.bottom < padding.bottom ) {
                        animations.scrollTop = containerDimensions.scroll.top +
-                               Math.min( position.top, -position.bottom );
+                               // Scroll the bottom into view, but not at the expense
+                               // of scrolling the top out of view
+                               Math.min( position.top - padding.top, -position.bottom + padding.bottom );
                }
        }
        if ( !config.direction || config.direction === 'x' ) {
-               if ( position.left < 0 ) {
-                       animations.scrollLeft = containerDimensions.scroll.left + position.left;
-               } else if ( position.left > 0 && position.right < 0 ) {
+               if ( position.left < padding.left ) {
+                       animations.scrollLeft = containerDimensions.scroll.left + position.left - padding.left;
+               } else if ( position.right < padding.right ) {
                        animations.scrollLeft = containerDimensions.scroll.left +
-                               Math.min( position.left, -position.right );
+                               // Scroll the right into view, but not at the expense
+                               // of scrolling the left out of view
+                               Math.min( position.left - padding.left, -position.right + padding.right );
                }
        }
        if ( !$.isEmptyObject( animations ) ) {
-               // eslint-disable-next-line no-jquery/no-animate
-               $container.stop( true ).animate( animations, config.duration === undefined ?
-                       'fast' : config.duration );
-               $container.queue( function ( next ) {
+               if ( animate ) {
+                       // eslint-disable-next-line no-jquery/no-animate
+                       $container.stop( true ).animate( animations, config.duration === undefined ? 'fast' : config.duration );
+                       $container.queue( function ( next ) {
+                               deferred.resolve();
+                               next();
+                       } );
+               } else {
+                       $container.stop( true );
+                       for ( method in animations ) {
+                               $container[ method ]( animations[ method ] );
+                       }
                        deferred.resolve();
-                       next();
-               } );
+               }
        } else {
                deferred.resolve();
        }
@@ -2118,7 +2132,7 @@ OO.ui.mixin.TabIndexedElement.prototype.getInputId = function () {
 OO.ui.mixin.TabIndexedElement.prototype.isLabelableNode = function ( $node ) {
        var
                labelableTags = [ 'button', 'meter', 'output', 'progress', 'select', 'textarea' ],
-               tagName = $node.prop( 'tagName' ).toLowerCase();
+               tagName = ( $node.prop( 'tagName' ) || '' ).toLowerCase();
 
        if ( tagName === 'input' && $node.attr( 'type' ) !== 'hidden' ) {
                return true;
@@ -2271,7 +2285,7 @@ OO.ui.mixin.ButtonElement.prototype.setButtonElement = function ( $button ) {
  *
  * @protected
  * @param {jQuery.Event} e Mouse down event
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.mixin.ButtonElement.prototype.onMouseDown = function ( e ) {
        if ( this.isDisabled() || e.which !== OO.ui.MouseButtons.LEFT ) {
@@ -2308,7 +2322,7 @@ OO.ui.mixin.ButtonElement.prototype.onDocumentMouseUp = function ( e ) {
  * @protected
  * @param {jQuery.Event} e Mouse click event
  * @fires click
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.mixin.ButtonElement.prototype.onClick = function ( e ) {
        if ( !this.isDisabled() && e.which === OO.ui.MouseButtons.LEFT ) {
@@ -2355,7 +2369,7 @@ OO.ui.mixin.ButtonElement.prototype.onDocumentKeyUp = function ( e ) {
  * @protected
  * @param {jQuery.Event} e Key press event
  * @fires click
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.mixin.ButtonElement.prototype.onKeyPress = function ( e ) {
        if ( !this.isDisabled() && ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER ) ) {
@@ -3250,10 +3264,14 @@ OO.ui.mixin.FlaggedElement = function OoUiMixinFlaggedElement( config ) {
        this.$flagged = null;
 
        // Initialization
-       this.setFlags( config.flags );
+       this.setFlags( config.flags || this.constructor.static.flags );
        this.setFlaggedElement( config.$flagged || this.$element );
 };
 
+/* Setup */
+
+OO.initClass( OO.ui.mixin.FlaggedElement );
+
 /* Events */
 
 /**
@@ -3266,6 +3284,17 @@ OO.ui.mixin.FlaggedElement = function OoUiMixinFlaggedElement( config ) {
  * that the flag was added, `false` that the flag was removed.
  */
 
+/* Static Properties */
+
+/**
+ * Initial value to pass to setFlags if no value is provided in config.
+ *
+ * @static
+ * @inheritable
+ * @property {string|string[]|Object.<string, boolean>}
+ */
+OO.ui.mixin.FlaggedElement.static.flags = null;
+
 /* Methods */
 
 /**
@@ -3456,6 +3485,9 @@ OO.initClass( OO.ui.mixin.TitledElement );
  * The title text, a function that returns text, or `null` for no title. The value of the static
  * property is overridden if the #title config option is used.
  *
+ * If the element has a default title (e.g. `<input type=file>`), `null` will allow that title to be
+ * shown. Use empty string to suppress it.
+ *
  * @static
  * @inheritable
  * @property {string|Function|null}
@@ -3480,9 +3512,7 @@ OO.ui.mixin.TitledElement.prototype.setTitledElement = function ( $titled ) {
        }
 
        this.$titled = $titled;
-       if ( this.title ) {
-               this.updateTitle();
-       }
+       this.updateTitle();
 };
 
 /**
@@ -3495,7 +3525,7 @@ OO.ui.mixin.TitledElement.prototype.setTitledElement = function ( $titled ) {
  */
 OO.ui.mixin.TitledElement.prototype.setTitle = function ( title ) {
        title = typeof title === 'function' ? OO.ui.resolveMsg( title ) : title;
-       title = ( typeof title === 'string' && title.length ) ? title : null;
+       title = typeof title === 'string' ? title : null;
 
        if ( this.title !== title ) {
                this.title = title;
@@ -6420,6 +6450,7 @@ OO.ui.OptionWidget.prototype.getMatchText = function () {
  *  Options are created with {@link OO.ui.OptionWidget OptionWidget} classes. See
  *  the [OOUI documentation on MediaWiki] [2] for examples.
  *  [2]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options
+ * @cfg {boolean} [multiselect] Allow for multiple selections
  */
 OO.ui.SelectWidget = function OoUiSelectWidget( config ) {
        // Configuration initialization
@@ -6436,6 +6467,7 @@ OO.ui.SelectWidget = function OoUiSelectWidget( config ) {
        // Properties
        this.pressed = false;
        this.selecting = null;
+       this.multiselect = !!config.multiselect;
        this.onDocumentMouseUpHandler = this.onDocumentMouseUp.bind( this );
        this.onDocumentMouseMoveHandler = this.onDocumentMouseMove.bind( this );
        this.onDocumentKeyDownHandler = this.onDocumentKeyDown.bind( this );
@@ -6496,13 +6528,16 @@ OO.mixinClass( OO.ui.SelectWidget, OO.ui.mixin.GroupWidget );
  * A `select` event is emitted when the selection is modified programmatically with the #selectItem
  * method.
  *
- * @param {OO.ui.OptionWidget|null} item Selected item
+ * @param {OO.ui.OptionWidget[]|OO.ui.OptionWidget|null} items Currently selected items
  */
 
 /**
  * @event choose
+ *
  * A `choose` event is emitted when an item is chosen with the #chooseItem method.
+ *
  * @param {OO.ui.OptionWidget} item Chosen item
+ * @param {boolean} selected Item is selected
  */
 
 /**
@@ -6592,7 +6627,7 @@ OO.ui.SelectWidget.prototype.onFocus = function ( event ) {
  *
  * @private
  * @param {jQuery.Event} e Mouse down event
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.SelectWidget.prototype.onMouseDown = function ( e ) {
        var item;
@@ -6615,7 +6650,7 @@ OO.ui.SelectWidget.prototype.onMouseDown = function ( e ) {
  *
  * @private
  * @param {MouseEvent} e Mouse up event
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.SelectWidget.prototype.onDocumentMouseUp = function ( e ) {
        var item;
@@ -6662,7 +6697,7 @@ OO.ui.SelectWidget.prototype.onDocumentMouseMove = function ( e ) {
  *
  * @private
  * @param {jQuery.Event} e Mouse over event
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.SelectWidget.prototype.onMouseOver = function ( e ) {
        var item;
@@ -6681,7 +6716,7 @@ OO.ui.SelectWidget.prototype.onMouseOver = function ( e ) {
  *
  * @private
  * @param {jQuery.Event} e Mouse over event
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.SelectWidget.prototype.onMouseLeave = function () {
        if ( !this.isDisabled() ) {
@@ -6699,12 +6734,13 @@ OO.ui.SelectWidget.prototype.onMouseLeave = function () {
 OO.ui.SelectWidget.prototype.onDocumentKeyDown = function ( e ) {
        var nextItem,
                handled = false,
-               currentItem = this.findHighlightedItem() || this.findSelectedItem();
+               currentItem = this.findHighlightedItem(),
+               firstItem = this.getItems()[ 0 ];
 
        if ( !this.isDisabled() && this.isVisible() ) {
                switch ( e.keyCode ) {
                        case OO.ui.Keys.ENTER:
-                               if ( currentItem && currentItem.constructor.static.highlightable ) {
+                               if ( currentItem ) {
                                        // Was only highlighted, now let's select it. No-op if already selected.
                                        this.chooseItem( currentItem );
                                        handled = true;
@@ -6713,18 +6749,20 @@ OO.ui.SelectWidget.prototype.onDocumentKeyDown = function ( e ) {
                        case OO.ui.Keys.UP:
                        case OO.ui.Keys.LEFT:
                                this.clearKeyPressBuffer();
-                               nextItem = this.findRelativeSelectableItem( currentItem, -1 );
+                               nextItem = currentItem ?
+                                       this.findRelativeSelectableItem( currentItem, -1 ) : firstItem;
                                handled = true;
                                break;
                        case OO.ui.Keys.DOWN:
                        case OO.ui.Keys.RIGHT:
                                this.clearKeyPressBuffer();
-                               nextItem = this.findRelativeSelectableItem( currentItem, 1 );
+                               nextItem = currentItem ?
+                                       this.findRelativeSelectableItem( currentItem, 1 ) : firstItem;
                                handled = true;
                                break;
                        case OO.ui.Keys.ESCAPE:
                        case OO.ui.Keys.TAB:
-                               if ( currentItem && currentItem.constructor.static.highlightable ) {
+                               if ( currentItem ) {
                                        currentItem.setHighlighted( false );
                                }
                                this.unbindDocumentKeyDownListener();
@@ -6803,7 +6841,7 @@ OO.ui.SelectWidget.prototype.clearKeyPressBuffer = function () {
  *
  * @protected
  * @param {KeyboardEvent} e Key press event
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.SelectWidget.prototype.onDocumentKeyPress = function ( e ) {
        var c, filter, item;
@@ -6944,20 +6982,36 @@ OO.ui.SelectWidget.prototype.findTargetItem = function ( e ) {
        return $option.data( 'oo-ui-optionWidget' ) || null;
 };
 
+/**
+ * Find all selected items, if there are any. If the widget allows for multiselect
+ * it will return an array of selected options. If the widget doesn't allow for
+ * multiselect, it will return the selected option or null if no item is selected.
+ *
+ * @return {OO.ui.OptionWidget[]|OO.ui.OptionWidget|null} If the widget is multiselect
+ *  then return an array of selected items (or empty array),
+ *  if the widget is not multiselect, return a single selected item, or `null`
+ *  if no item is selected
+ */
+OO.ui.SelectWidget.prototype.findSelectedItems = function () {
+       var selected = this.items.filter( function ( item ) {
+               return item.isSelected();
+       } );
+
+       return this.multiselect ?
+               selected :
+               selected[ 0 ] || null;
+};
+
 /**
  * Find selected item.
  *
- * @return {OO.ui.OptionWidget|null} Selected item, `null` if no item is selected
+ * @return {OO.ui.OptionWidget[]|OO.ui.OptionWidget|null} If the widget is multiselect
+ *  then return an array of selected items (or empty array),
+ *  if the widget is not multiselect, return a single selected item, or `null`
+ *  if no item is selected
  */
 OO.ui.SelectWidget.prototype.findSelectedItem = function () {
-       var i, len;
-
-       for ( i = 0, len = this.items.length; i < len; i++ ) {
-               if ( this.items[ i ].isSelected() ) {
-                       return this.items[ i ];
-               }
-       }
-       return null;
+       return this.findSelectedItems();
 };
 
 /**
@@ -7104,6 +7158,30 @@ OO.ui.SelectWidget.prototype.selectItemByData = function ( data ) {
        return this.selectItem( itemFromData );
 };
 
+/**
+ * Programmatically unselect an option by its reference. If the widget
+ * allows for multiple selections, there may be other items still selected;
+ * otherwise, no items will be selected.
+ * If no item is given, all selected items will be unselected.
+ *
+ * @param {OO.ui.OptionWidget} [item] Item to unselect
+ * @fires select
+ * @chainable
+ * @return {OO.ui.Widget} The widget, for chaining
+ */
+OO.ui.SelectWidget.prototype.unselectItem = function ( item ) {
+       if ( item ) {
+               item.setSelected( false );
+       } else {
+               this.items.forEach( function ( item ) {
+                       item.setSelected( false );
+               } );
+       }
+
+       this.emit( 'select', this.findSelectedItems() );
+       return this;
+};
+
 /**
  * Programmatically select an option by its reference. If the `item` parameter is omitted,
  * all options will be deselected.
@@ -7117,14 +7195,20 @@ OO.ui.SelectWidget.prototype.selectItem = function ( item ) {
        var i, len, selected,
                changed = false;
 
-       for ( i = 0, len = this.items.length; i < len; i++ ) {
-               selected = this.items[ i ] === item;
-               if ( this.items[ i ].isSelected() !== selected ) {
-                       this.items[ i ].setSelected( selected );
-                       changed = true;
+       if ( this.multiselect && item ) {
+               // Select the item directly
+               item.setSelected( true );
+       } else {
+               for ( i = 0, len = this.items.length; i < len; i++ ) {
+                       selected = this.items[ i ] === item;
+                       if ( this.items[ i ].isSelected() !== selected ) {
+                               this.items[ i ].setSelected( selected );
+                               changed = true;
+                       }
                }
        }
        if ( changed ) {
+               // TODO: When should a non-highlightable element be selected?
                if ( item && !item.constructor.static.highlightable ) {
                        if ( item ) {
                                this.$focusOwner.attr( 'aria-activedescendant', item.getElementId() );
@@ -7132,7 +7216,7 @@ OO.ui.SelectWidget.prototype.selectItem = function ( item ) {
                                this.$focusOwner.removeAttr( 'aria-activedescendant' );
                        }
                }
-               this.emit( 'select', item );
+               this.emit( 'select', this.findSelectedItems() );
        }
 
        return this;
@@ -7185,8 +7269,13 @@ OO.ui.SelectWidget.prototype.pressItem = function ( item ) {
  */
 OO.ui.SelectWidget.prototype.chooseItem = function ( item ) {
        if ( item ) {
-               this.selectItem( item );
-               this.emit( 'choose', item );
+               if ( this.multiselect && item.isSelected() ) {
+                       this.unselectItem( item );
+               } else {
+                       this.selectItem( item );
+               }
+
+               this.emit( 'choose', item, item.isSelected() );
        }
 
        return this;
@@ -7470,6 +7559,7 @@ OO.ui.MenuSectionOptionWidget = function OoUiMenuSectionOptionWidget( config ) {
        this.$element
                .addClass( 'oo-ui-menuSectionOptionWidget' )
                .removeAttr( 'role aria-selected' );
+       this.selected = false;
 };
 
 /* Setup */
@@ -7654,7 +7744,7 @@ OO.ui.MenuSelectWidget.prototype.onDocumentKeyDown = function ( e ) {
                                break;
                        case OO.ui.Keys.ESCAPE:
                        case OO.ui.Keys.TAB:
-                               if ( currentItem ) {
+                               if ( currentItem && !this.multiselect ) {
                                        currentItem.setHighlighted( false );
                                }
                                this.toggle( false );
@@ -7711,10 +7801,6 @@ OO.ui.MenuSelectWidget.prototype.updateItemVisibility = function () {
                        section.toggle( showAll || !sectionEmpty );
                }
 
-               if ( anyVisible && this.items.length && !exactMatch ) {
-                       this.scrollItemIntoView( this.items[ 0 ] );
-               }
-
                if ( !anyVisible ) {
                        this.highlightItem( null );
                }
@@ -7871,7 +7957,7 @@ OO.ui.MenuSelectWidget.prototype.clearItems = function () {
  * @inheritdoc
  */
 OO.ui.MenuSelectWidget.prototype.toggle = function ( visible ) {
-       var change, originalHeight, flippedHeight;
+       var change, originalHeight, flippedHeight, selectedItem;
 
        visible = ( visible === undefined ? !this.visible : !!visible ) && !!this.items.length;
        change = visible !== this.isVisible();
@@ -7936,9 +8022,13 @@ OO.ui.MenuSelectWidget.prototype.toggle = function ( visible ) {
 
                        this.$focusOwner.attr( 'aria-expanded', 'true' );
 
-                       if ( this.findSelectedItem() ) {
-                               this.$focusOwner.attr( 'aria-activedescendant', this.findSelectedItem().getElementId() );
-                               this.findSelectedItem().scrollElementIntoView( { duration: 0 } );
+                       selectedItem = this.findSelectedItem();
+                       if ( !this.multiselect && selectedItem ) {
+                               // TODO: Verify if this is even needed; This is already done on highlight changes
+                               // in SelectWidget#highlightItem, so we should just need to highlight the item
+                               // we need to highlight here and not bother with attr or checking selections.
+                               this.$focusOwner.attr( 'aria-activedescendant', selectedItem.getElementId() );
+                               selectedItem.scrollElementIntoView( { duration: 0 } );
                        }
 
                        // Auto-hide
@@ -7955,12 +8045,20 @@ OO.ui.MenuSelectWidget.prototype.toggle = function ( visible ) {
                        this.getElementDocument().removeEventListener( 'mousedown', this.onDocumentMouseDownHandler, true );
                        this.togglePositioning( false );
                        this.toggleClipping( false );
+                       this.lastHighlightedItem = null;
                }
        }
 
        return this;
 };
 
+/**
+ * Scroll to the top of the menu
+ */
+OO.ui.MenuSelectWidget.prototype.scrollToTop = function () {
+       this.$element.scrollTop( 0 );
+};
+
 /**
  * DropdownWidgets are not menus themselves, rather they contain a menu of options created with
  * OO.ui.MenuOptionWidget. The DropdownWidget takes care of opening and displaying the menu so that
@@ -8135,7 +8233,7 @@ OO.ui.DropdownWidget.prototype.onMenuToggle = function ( isVisible ) {
  *
  * @private
  * @param {jQuery.Event} e Mouse click event
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.DropdownWidget.prototype.onClick = function ( e ) {
        if ( !this.isDisabled() && e.which === OO.ui.MouseButtons.LEFT ) {
@@ -8149,7 +8247,7 @@ OO.ui.DropdownWidget.prototype.onClick = function ( e ) {
  *
  * @private
  * @param {jQuery.Event} e Key down event
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.DropdownWidget.prototype.onKeyDown = function ( e ) {
        if (
@@ -9400,6 +9498,7 @@ OO.ui.ButtonInputWidget.prototype.getInputId = function () {
  * @param {Object} [config] Configuration options
  * @cfg {boolean} [selected=false] Select the checkbox initially. By default, the checkbox is
  *  not selected.
+ * @cfg {boolean} [indeterminate=false] Whether the checkbox is in the indeterminate state.
  */
 OO.ui.CheckboxInputWidget = function OoUiCheckboxInputWidget( config ) {
        // Configuration initialization
@@ -9420,12 +9519,24 @@ OO.ui.CheckboxInputWidget = function OoUiCheckboxInputWidget( config ) {
                // Required for pretty styling in WikimediaUI theme
                .append( this.checkIcon.$element );
        this.setSelected( config.selected !== undefined ? config.selected : false );
+       this.setIndeterminate( config.indeterminate !== undefined ? config.indeterminate : false );
 };
 
 /* Setup */
 
 OO.inheritClass( OO.ui.CheckboxInputWidget, OO.ui.InputWidget );
 
+/* Events */
+
+/**
+ * @event change
+ *
+ * A change event is emitted when the state of the input changes.
+ *
+ * @param {boolean} selected
+ * @param {boolean} indeterminate
+ */
+
 /* Static Properties */
 
 /**
@@ -9464,6 +9575,7 @@ OO.ui.CheckboxInputWidget.prototype.onEdit = function () {
                // Allow the stack to clear so the value will be updated
                setTimeout( function () {
                        widget.setSelected( widget.$input.prop( 'checked' ) );
+                       widget.setIndeterminate( widget.$input.prop( 'indeterminate' ) );
                } );
        }
 };
@@ -9471,16 +9583,20 @@ OO.ui.CheckboxInputWidget.prototype.onEdit = function () {
 /**
  * Set selection state of this checkbox.
  *
- * @param {boolean} state `true` for selected
+ * @param {boolean} state Selected state
+ * @param {boolean} internal Used for internal calls to suppress events
  * @chainable
- * @return {OO.ui.Widget} The widget, for chaining
+ * @return {OO.ui.CheckboxInputWidget} The widget, for chaining
  */
-OO.ui.CheckboxInputWidget.prototype.setSelected = function ( state ) {
+OO.ui.CheckboxInputWidget.prototype.setSelected = function ( state, internal ) {
        state = !!state;
        if ( this.selected !== state ) {
                this.selected = state;
                this.$input.prop( 'checked', this.selected );
-               this.emit( 'change', this.selected );
+               if ( !internal ) {
+                       this.setIndeterminate( false, true );
+                       this.emit( 'change', this.selected, this.indeterminate );
+               }
        }
        // The first time that the selection state is set (probably while constructing the widget),
        // remember it in defaultSelected. This property can be later used to check whether
@@ -9507,6 +9623,42 @@ OO.ui.CheckboxInputWidget.prototype.isSelected = function () {
        return this.selected;
 };
 
+/**
+ * Set indeterminate state of this checkbox.
+ *
+ * @param {boolean} state Indeterminate state
+ * @param {boolean} internal Used for internal calls to suppress events
+ * @chainable
+ * @return {OO.ui.CheckboxInputWidget} The widget, for chaining
+ */
+OO.ui.CheckboxInputWidget.prototype.setIndeterminate = function ( state, internal ) {
+       state = !!state;
+       if ( this.indeterminate !== state ) {
+               this.indeterminate = state;
+               this.$input.prop( 'indeterminate', this.indeterminate );
+               if ( !internal ) {
+                       this.setSelected( false, true );
+                       this.emit( 'change', this.selected, this.indeterminate );
+               }
+       }
+       return this;
+};
+
+/**
+ * Check if this checkbox is selected.
+ *
+ * @return {boolean} Checkbox is selected
+ */
+OO.ui.CheckboxInputWidget.prototype.isIndeterminate = function () {
+       // Resynchronize our internal data with DOM data. Other scripts executing on the page can modify
+       // it, and we won't know unless they're kind enough to trigger a 'change' event.
+       var indeterminate = this.$input.prop( 'indeterminate' );
+       if ( this.indeterminate !== indeterminate ) {
+               this.setIndeterminate( indeterminate );
+       }
+       return this.indeterminate;
+};
+
 /**
  * @inheritdoc
  */
@@ -10396,7 +10548,7 @@ OO.ui.CheckboxMultiselectInputWidget.prototype.focus = function () {
  *     // A TextInputWidget.
  *     var textInput = new OO.ui.TextInputWidget( {
  *         value: 'Text input'
- *     } )
+ *     } );
  *     $( document.body ).append( textInput.$element );
  *
  * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs
@@ -10545,7 +10697,7 @@ OO.ui.TextInputWidget.static.validationPatterns = {
  *
  * @private
  * @param {jQuery.Event} e Mouse down event
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.TextInputWidget.prototype.onIconMouseDown = function ( e ) {
        if ( e.which === OO.ui.MouseButtons.LEFT ) {
@@ -10559,7 +10711,7 @@ OO.ui.TextInputWidget.prototype.onIconMouseDown = function ( e ) {
  *
  * @private
  * @param {jQuery.Event} e Mouse down event
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.TextInputWidget.prototype.onIndicatorMouseDown = function ( e ) {
        if ( e.which === OO.ui.MouseButtons.LEFT ) {
@@ -11116,6 +11268,7 @@ OO.ui.SearchInputWidget = function OoUiSearchInputWidget( config ) {
        this.connect( this, {
                change: 'onChange'
        } );
+       this.$indicator.on( 'click', this.onIndicatorClick.bind( this ) );
 
        // Initialization
        this.updateSearchIndicator();
@@ -11139,9 +11292,12 @@ OO.ui.SearchInputWidget.prototype.getSaneType = function () {
 };
 
 /**
- * @inheritdoc
+ * Handle click events on the indicator
+ *
+ * @param {jQuery.Event} e Click event
+ * @return {boolean}
  */
-OO.ui.SearchInputWidget.prototype.onIndicatorMouseDown = function ( e ) {
+OO.ui.SearchInputWidget.prototype.onIndicatorClick = function ( e ) {
        if ( e.which === OO.ui.MouseButtons.LEFT ) {
                // Clear the text field
                this.setValue( '' );
@@ -11204,8 +11360,8 @@ OO.ui.SearchInputWidget.prototype.setReadOnly = function ( state ) {
  *     // A MultilineTextInputWidget.
  *     var multilineTextInput = new OO.ui.MultilineTextInputWidget( {
  *         value: 'Text input on multiple lines'
- *     } )
- *     $( 'body' ).append( multilineTextInput.$element );
+ *     } );
+ *     $( document.body ).append( multilineTextInput.$element );
  *
  * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs#MultilineTextInputWidget
  *
@@ -11914,7 +12070,7 @@ OO.ui.FieldLayout.prototype.makeMessage = function ( kind, text ) {
        var $listItem, $icon, message;
        $listItem = $( '<li>' );
        if ( kind === 'error' ) {
-               $icon = new OO.ui.IconWidget( { icon: 'alert', flags: [ 'error' ] } ).$element;
+               $icon = new OO.ui.IconWidget( { icon: 'error', flags: [ 'error' ] } ).$element;
                $listItem.attr( 'role', 'alert' );
        } else if ( kind === 'warning' ) {
                $icon = new OO.ui.IconWidget( { icon: 'alert', flags: [ 'warning' ] } ).$element;
@@ -12359,21 +12515,21 @@ OO.ui.FieldsetLayout.static.tagName = 'fieldset';
  * [2]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs
  *
  *     @example
- *     // Example of a form layout that wraps a fieldset layout
+ *     // Example of a form layout that wraps a fieldset layout.
  *     var input1 = new OO.ui.TextInputWidget( {
- *         placeholder: 'Username'
- *     } );
- *     var input2 = new OO.ui.TextInputWidget( {
- *         placeholder: 'Password',
- *         type: 'password'
- *     } );
- *     var submit = new OO.ui.ButtonInputWidget( {
- *         label: 'Submit'
- *     } );
+ *             placeholder: 'Username'
+ *         } ),
+ *         input2 = new OO.ui.TextInputWidget( {
+ *             placeholder: 'Password',
+ *             type: 'password'
+ *         } ),
+ *         submit = new OO.ui.ButtonInputWidget( {
+ *             label: 'Submit'
+ *         } ),
+ *         fieldset = new OO.ui.FieldsetLayout( {
+ *             label: 'A form layout'
+ *         } );
  *
- *     var fieldset = new OO.ui.FieldsetLayout( {
- *         label: 'A form layout'
- *     } );
  *     fieldset.addItems( [
  *         new OO.ui.FieldLayout( input1, {
  *             label: 'Username',
@@ -12564,7 +12720,7 @@ OO.ui.PanelLayout.prototype.focus = function () {
  * Note that inline elements, such as OO.ui.ButtonWidgets, do not need this wrapper.
  *
  *     @example
- *     // HorizontalLayout with a text input and a label
+ *     // HorizontalLayout with a text input and a label.
  *     var layout = new OO.ui.HorizontalLayout( {
  *       items: [
  *         new OO.ui.LabelWidget( { label: 'Label' } ),
@@ -12896,12 +13052,16 @@ OO.ui.NumberInputWidget.prototype.onButtonClick = function ( dir ) {
  *
  * @private
  * @param {jQuery.Event} event
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.NumberInputWidget.prototype.onWheel = function ( event ) {
        var delta = 0;
 
-       if ( !this.isDisabled() && this.$input.is( ':focus' ) ) {
+       if ( this.isDisabled() || this.isReadOnly() ) {
+               return;
+       }
+
+       if ( this.$input.is( ':focus' ) ) {
                // Standard 'wheel' event
                if ( event.originalEvent.deltaMode !== undefined ) {
                        this.sawWheelEvent = true;
@@ -12939,40 +13099,326 @@ OO.ui.NumberInputWidget.prototype.onWheel = function ( event ) {
  *
  * @private
  * @param {jQuery.Event} e Key down event
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.NumberInputWidget.prototype.onKeyDown = function ( e ) {
-       if ( !this.isDisabled() ) {
-               switch ( e.which ) {
-                       case OO.ui.Keys.UP:
-                               this.adjustValue( this.buttonStep );
-                               return false;
-                       case OO.ui.Keys.DOWN:
-                               this.adjustValue( -this.buttonStep );
-                               return false;
-                       case OO.ui.Keys.PAGEUP:
-                               this.adjustValue( this.pageStep );
-                               return false;
-                       case OO.ui.Keys.PAGEDOWN:
-                               this.adjustValue( -this.pageStep );
-                               return false;
-               }
+       if ( this.isDisabled() || this.isReadOnly() ) {
+               return;
+       }
+
+       switch ( e.which ) {
+               case OO.ui.Keys.UP:
+                       this.adjustValue( this.buttonStep );
+                       return false;
+               case OO.ui.Keys.DOWN:
+                       this.adjustValue( -this.buttonStep );
+                       return false;
+               case OO.ui.Keys.PAGEUP:
+                       this.adjustValue( this.pageStep );
+                       return false;
+               case OO.ui.Keys.PAGEDOWN:
+                       this.adjustValue( -this.pageStep );
+                       return false;
        }
 };
 
+/**
+ * Update the disabled state of the controls
+ *
+ * @chainable
+ * @protected
+ * @return {OO.ui.NumberInputWidget} The widget, for chaining
+ */
+OO.ui.NumberInputWidget.prototype.updateControlsDisabled = function () {
+       var disabled = this.isDisabled() || this.isReadOnly();
+       if ( this.minusButton ) {
+               this.minusButton.setDisabled( disabled );
+       }
+       if ( this.plusButton ) {
+               this.plusButton.setDisabled( disabled );
+       }
+       return this;
+};
+
 /**
  * @inheritdoc
  */
 OO.ui.NumberInputWidget.prototype.setDisabled = function ( disabled ) {
        // Parent method
        OO.ui.NumberInputWidget.parent.prototype.setDisabled.call( this, disabled );
+       this.updateControlsDisabled();
+       return this;
+};
 
-       if ( this.minusButton ) {
-               this.minusButton.setDisabled( this.isDisabled() );
+/**
+ * @inheritdoc
+ */
+OO.ui.NumberInputWidget.prototype.setReadOnly = function () {
+       // Parent method
+       OO.ui.NumberInputWidget.parent.prototype.setReadOnly.apply( this, arguments );
+       this.updateControlsDisabled();
+       return this;
+};
+
+/**
+ * SelectFileInputWidgets allow for selecting files, using <input type="file">. These
+ * widgets can be configured with {@link OO.ui.mixin.IconElement icons}, {@link
+ * OO.ui.mixin.IndicatorElement indicators} and {@link OO.ui.mixin.TitledElement titles}.
+ * Please see the [OOUI documentation on MediaWiki] [1] for more information and examples.
+ *
+ * SelectFileInputWidgets must be used in HTML forms, as getValue only returns the filename.
+ *
+ *     @example
+ *     // A file select input widget.
+ *     var selectFile = new OO.ui.SelectFileInputWidget();
+ *     $( document.body ).append( selectFile.$element );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets
+ *
+ * @class
+ * @extends OO.ui.InputWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {string[]|null} [accept=null] MIME types to accept. null accepts all types.
+ * @cfg {boolean} [multiple=false] Allow multiple files to be selected.
+ * @cfg {string} [placeholder] Text to display when no file is selected.
+ * @cfg {Object} [button] Config to pass to select file button.
+ * @cfg {string} [icon] Icon to show next to file info
+ */
+OO.ui.SelectFileInputWidget = function OoUiSelectFileInputWidget( config ) {
+       var widget = this;
+
+       config = config || {};
+
+       // Construct buttons before parent method is called (calling setDisabled)
+       this.selectButton = new OO.ui.ButtonWidget( $.extend( {
+               $element: $( '<label>' ),
+               classes: [ 'oo-ui-selectFileInputWidget-selectButton' ],
+               label: OO.ui.msg( 'ooui-selectfile-button-select' )
+       }, config.button ) );
+
+       // Configuration initialization
+       config = $.extend( {
+               accept: null,
+               placeholder: OO.ui.msg( 'ooui-selectfile-placeholder' ),
+               $tabIndexed: this.selectButton.$tabIndexed
+       }, config );
+
+       this.info = new OO.ui.SearchInputWidget( {
+               classes: [ 'oo-ui-selectFileInputWidget-info' ],
+               placeholder: config.placeholder,
+               // Pass an empty collection so that .focus() always does nothing
+               $tabIndexed: $( [] )
+       } ).setIcon( config.icon );
+       // Set tabindex manually on $input as $tabIndexed has been overridden
+       this.info.$input.attr( 'tabindex', -1 );
+
+       // Parent constructor
+       OO.ui.SelectFileInputWidget.parent.call( this, config );
+
+       // Properties
+       this.currentFiles = this.filterFiles( this.$input[ 0 ].files || [] );
+       if ( Array.isArray( config.accept ) ) {
+               this.accept = config.accept;
+       } else {
+               this.accept = null;
        }
-       if ( this.plusButton ) {
-               this.plusButton.setDisabled( this.isDisabled() );
+       this.multiple = !!config.multiple;
+
+       // Events
+       this.info.connect( this, { change: 'onInfoChange' } );
+       this.selectButton.$button.on( {
+               keypress: this.onKeyPress.bind( this )
+       } );
+       this.$input.on( {
+               change: this.onFileSelected.bind( this ),
+               // Support: IE11
+               // In IE 11, focussing a file input (by clicking on it) displays a text cursor and scrolls
+               // the cursor into view (in this case, it scrolls the button, which has 'overflow: hidden').
+               // Since this messes with our custom styling (the file input has large dimensions and this
+               // causes the label to scroll out of view), scroll the button back to top. (T192131)
+               focus: function () {
+                       widget.$input.parent().prop( 'scrollTop', 0 );
+               }
+       } );
+       this.connect( this, { change: 'updateUI' } );
+
+       this.fieldLayout = new OO.ui.ActionFieldLayout( this.info, this.selectButton, { align: 'top' } );
+
+       this.$input
+               .attr( {
+                       type: 'file',
+                       // this.selectButton is tabindexed
+                       tabindex: -1,
+                       // Infused input may have previously by
+                       // TabIndexed, so remove aria-disabled attr.
+                       'aria-disabled': null
+               } );
+
+       if ( this.accept ) {
+               this.$input.attr( 'accept', this.accept.join( ', ' ) );
+       }
+       if ( this.multiple ) {
+               this.$input.attr( 'multiple', '' );
+       }
+       this.selectButton.$button.append( this.$input );
+
+       this.$element
+               .addClass( 'oo-ui-selectFileInputWidget' )
+               .append( this.fieldLayout.$element );
+
+       this.updateUI();
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.SelectFileInputWidget, OO.ui.InputWidget );
+
+/* Static properties */
+
+// Set empty title so that browser default tooltips like "No file chosen" don't appear.
+// On SelectFileWidget this tooltip will often be incorrect, so create a consistent
+// experience on SelectFileInputWidget.
+OO.ui.SelectFileInputWidget.static.title = '';
+
+/* Methods */
+
+/**
+ * Get the filename of the currently selected file.
+ *
+ * @return {string} Filename
+ */
+OO.ui.SelectFileInputWidget.prototype.getFilename = function () {
+       if ( this.currentFiles.length ) {
+               return this.currentFiles.map( function ( file ) {
+                       return file.name;
+               } ).join( ', ' );
+       } else {
+               // Try to strip leading fakepath.
+               return this.getValue().split( '\\' ).pop();
+       }
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.SelectFileInputWidget.prototype.setValue = function ( value ) {
+       if ( value === undefined ) {
+               // Called during init, don't replace value if just infusing.
+               return;
        }
+       if ( value ) {
+               // We need to update this.value, but without trying to modify
+               // the DOM value, which would throw an exception.
+               if ( this.value !== value ) {
+                       this.value = value;
+                       this.emit( 'change', this.value );
+               }
+       } else {
+               this.currentFiles = [];
+               // Parent method
+               OO.ui.SelectFileInputWidget.super.prototype.setValue.call( this, '' );
+       }
+};
+
+/**
+ * Handle file selection from the input.
+ *
+ * @protected
+ * @param {jQuery.Event} e
+ */
+OO.ui.SelectFileInputWidget.prototype.onFileSelected = function ( e ) {
+       this.currentFiles = this.filterFiles( e.target.files || [] );
+};
+
+/**
+ * Update the user interface when a file is selected or unselected.
+ *
+ * @protected
+ */
+OO.ui.SelectFileInputWidget.prototype.updateUI = function () {
+       this.info.setValue( this.getFilename() );
+};
+
+/**
+ * Determine if we should accept this file.
+ *
+ * @private
+ * @param {FileList|File[]} files Files to filter
+ * @return {File[]} Filter files
+ */
+OO.ui.SelectFileInputWidget.prototype.filterFiles = function ( files ) {
+       var accept = this.accept;
+
+       function mimeAllowed( file ) {
+               var i, mimeTest,
+                       mimeType = file.type;
+
+               if ( !accept || !mimeType ) {
+                       return true;
+               }
+
+               for ( i = 0; i < accept.length; i++ ) {
+                       mimeTest = accept[ i ];
+                       if ( mimeTest === mimeType ) {
+                               return true;
+                       } else if ( mimeTest.substr( -2 ) === '/*' ) {
+                               mimeTest = mimeTest.substr( 0, mimeTest.length - 1 );
+                               if ( mimeType.substr( 0, mimeTest.length ) === mimeTest ) {
+                                       return true;
+                               }
+                       }
+               }
+               return false;
+       }
+
+       return Array.prototype.filter.call( files, mimeAllowed );
+};
+
+/**
+ * Handle info input change events
+ *
+ * The info widget can only be changed by the user
+ * with the clear button.
+ *
+ * @private
+ * @param {string} value
+ */
+OO.ui.SelectFileInputWidget.prototype.onInfoChange = function ( value ) {
+       if ( value === '' ) {
+               this.setValue( null );
+       }
+};
+
+/**
+ * Handle key press events.
+ *
+ * @private
+ * @param {jQuery.Event} e Key press event
+ * @return {undefined|boolean} False to prevent default if event is handled
+ */
+OO.ui.SelectFileInputWidget.prototype.onKeyPress = function ( e ) {
+       if ( !this.isDisabled() && this.$input &&
+               ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER )
+       ) {
+               // Emit a click to open the file selector.
+               this.$input.trigger( 'click' );
+               // Taking focus from the selectButton means keyUp isn't fired, so fire it manually.
+               this.selectButton.onDocumentKeyUp( e );
+               return false;
+       }
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.SelectFileInputWidget.prototype.setDisabled = function ( disabled ) {
+       // Parent method
+       OO.ui.SelectFileInputWidget.parent.prototype.setDisabled.call( this, disabled );
+
+       this.selectButton.setDisabled( disabled );
+       this.info.setDisabled( disabled );
 
        return this;
 };
index 85e9554..ebcc9c8 100644 (file)
@@ -1 +1 @@
-{"version":3,"sources":["../src/intro.js.txt","../src/core.js","../src/mixin.js","../src/Element.js","../src/HtmlSnippet.js","../src/Layout.js","../src/Widget.js","../src/Theme.js","../src/mixins/TabIndexedElement.js","../src/mixins/ButtonElement.js","../src/mixins/GroupElement.js","../src/mixins/LabelElement.js","../src/mixins/IconElement.js","../src/mixins/IndicatorElement.js","../src/mixins/FlaggedElement.js","../src/mixins/TitledElement.js","../src/mixins/AccessKeyedElement.js","../src/widgets/ButtonWidget.js","../src/widgets/ButtonGroupWidget.js","../src/widgets/IconWidget.js","../src/widgets/IndicatorWidget.js","../src/widgets/LabelWidget.js","../src/mixins/PendingElement.js","../src/mixins/FloatableElement.js","../src/mixins/ClippableElement.js","../src/widgets/PopupWidget.js","../src/mixins/PopupElement.js","../src/widgets/PopupButtonWidget.js","../src/mixins/GroupWidget.js","../src/mixins/ItemWidget.js","../src/widgets/OptionWidget.js","../src/widgets/SelectWidget.js","../src/widgets/DecoratedOptionWidget.js","../src/widgets/MenuOptionWidget.js","../src/widgets/MenuSectionOptionWidget.js","../src/widgets/MenuSelectWidget.js","../src/widgets/DropdownWidget.js","../src/widgets/RadioOptionWidget.js","../src/widgets/RadioSelectWidget.js","../src/widgets/MultioptionWidget.js","../src/widgets/MultiselectWidget.js","../src/widgets/CheckboxMultioptionWidget.js","../src/widgets/CheckboxMultiselectWidget.js","../src/widgets/ProgressBarWidget.js","../src/widgets/InputWidget.js","../src/widgets/HiddenInputWidget.js","../src/widgets/ButtonInputWidget.js","../src/widgets/CheckboxInputWidget.js","../src/widgets/DropdownInputWidget.js","../src/widgets/RadioInputWidget.js","../src/widgets/RadioSelectInputWidget.js","../src/widgets/CheckboxMultiselectInputWidget.js","../src/widgets/TextInputWidget.js","../src/widgets/SearchInputWidget.js","../src/widgets/MultilineTextInputWidget.js","../src/widgets/ComboBoxInputWidget.js","../src/layouts/FieldLayout.js","../src/layouts/ActionFieldLayout.js","../src/layouts/FieldsetLayout.js","../src/layouts/FormLayout.js","../src/layouts/PanelLayout.js","../src/layouts/HorizontalLayout.js","../src/widgets/NumberInputWidget.js","../src/outro.js.txt"],"names":[],"mappings":"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","file":"oojs-ui-core.js","sourcesContent":["( function ( OO ) {\n\n'use strict';\n","/**\n * Namespace for all classes, static methods and static properties.\n *\n * @class\n * @singleton\n */\nOO.ui = {};\n\nOO.ui.bind = $.proxy;\n\n/**\n * @property {Object}\n */\nOO.ui.Keys = {\n\tUNDEFINED: 0,\n\tBACKSPACE: 8,\n\tDELETE: 46,\n\tLEFT: 37,\n\tRIGHT: 39,\n\tUP: 38,\n\tDOWN: 40,\n\tENTER: 13,\n\tEND: 35,\n\tHOME: 36,\n\tTAB: 9,\n\tPAGEUP: 33,\n\tPAGEDOWN: 34,\n\tESCAPE: 27,\n\tSHIFT: 16,\n\tSPACE: 32\n};\n\n/**\n * Constants for MouseEvent.which\n *\n * @property {Object}\n */\nOO.ui.MouseButtons = {\n\tLEFT: 1,\n\tMIDDLE: 2,\n\tRIGHT: 3\n};\n\n/**\n * @property {number}\n * @private\n */\nOO.ui.elementId = 0;\n\n/**\n * Generate a unique ID for element\n *\n * @return {string} ID\n */\nOO.ui.generateElementId = function () {\n\tOO.ui.elementId++;\n\treturn 'ooui-' + OO.ui.elementId;\n};\n\n/**\n * Check if an element is focusable.\n * Inspired by :focusable in jQueryUI v1.11.4 - 2015-04-14\n *\n * @param {jQuery} $element Element to test\n * @return {boolean} Element is focusable\n */\nOO.ui.isFocusableElement = function ( $element ) {\n\tvar nodeName,\n\t\telement = $element[ 0 ];\n\n\t// Anything disabled is not focusable\n\tif ( element.disabled ) {\n\t\treturn false;\n\t}\n\n\t// Check if the element is visible\n\tif ( !(\n\t\t// This is quicker than calling $element.is( ':visible' )\n\t\t$.expr.pseudos.visible( element ) &&\n\t\t// Check that all parents are visible\n\t\t!$element.parents().addBack().filter( function () {\n\t\t\treturn $.css( this, 'visibility' ) === 'hidden';\n\t\t} ).length\n\t) ) {\n\t\treturn false;\n\t}\n\n\t// Check if the element is ContentEditable, which is the string 'true'\n\tif ( element.contentEditable === 'true' ) {\n\t\treturn true;\n\t}\n\n\t// Anything with a non-negative numeric tabIndex is focusable.\n\t// Use .prop to avoid browser bugs\n\tif ( $element.prop( 'tabIndex' ) >= 0 ) {\n\t\treturn true;\n\t}\n\n\t// Some element types are naturally focusable\n\t// (indexOf is much faster than regex in Chrome and about the\n\t// same in FF: https://jsperf.com/regex-vs-indexof-array2)\n\tnodeName = element.nodeName.toLowerCase();\n\tif ( [ 'input', 'select', 'textarea', 'button', 'object' ].indexOf( nodeName ) !== -1 ) {\n\t\treturn true;\n\t}\n\n\t// Links and areas are focusable if they have an href\n\tif ( ( nodeName === 'a' || nodeName === 'area' ) && $element.attr( 'href' ) !== undefined ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n};\n\n/**\n * Find a focusable child.\n *\n * @param {jQuery} $container Container to search in\n * @param {boolean} [backwards] Search backwards\n * @return {jQuery} Focusable child, or an empty jQuery object if none found\n */\nOO.ui.findFocusable = function ( $container, backwards ) {\n\tvar $focusable = $( [] ),\n\t\t// $focusableCandidates is a superset of things that\n\t\t// could get matched by isFocusableElement\n\t\t$focusableCandidates = $container\n\t\t\t.find( 'input, select, textarea, button, object, a, area, [contenteditable], [tabindex]' );\n\n\tif ( backwards ) {\n\t\t$focusableCandidates = Array.prototype.reverse.call( $focusableCandidates );\n\t}\n\n\t$focusableCandidates.each( function () {\n\t\tvar $this = $( this );\n\t\tif ( OO.ui.isFocusableElement( $this ) ) {\n\t\t\t$focusable = $this;\n\t\t\treturn false;\n\t\t}\n\t} );\n\treturn $focusable;\n};\n\n/**\n * Get the user's language and any fallback languages.\n *\n * These language codes are used to localize user interface elements in the user's language.\n *\n * In environments that provide a localization system, this function should be overridden to\n * return the user's language(s). The default implementation returns English (en) only.\n *\n * @return {string[]} Language codes, in descending order of priority\n */\nOO.ui.getUserLanguages = function () {\n\treturn [ 'en' ];\n};\n\n/**\n * Get a value in an object keyed by language code.\n *\n * @param {Object.<string,Mixed>} obj Object keyed by language code\n * @param {string|null} [lang] Language code, if omitted or null defaults to any user language\n * @param {string} [fallback] Fallback code, used if no matching language can be found\n * @return {Mixed} Local value\n */\nOO.ui.getLocalValue = function ( obj, lang, fallback ) {\n\tvar i, len, langs;\n\n\t// Requested language\n\tif ( obj[ lang ] ) {\n\t\treturn obj[ lang ];\n\t}\n\t// Known user language\n\tlangs = OO.ui.getUserLanguages();\n\tfor ( i = 0, len = langs.length; i < len; i++ ) {\n\t\tlang = langs[ i ];\n\t\tif ( obj[ lang ] ) {\n\t\t\treturn obj[ lang ];\n\t\t}\n\t}\n\t// Fallback language\n\tif ( obj[ fallback ] ) {\n\t\treturn obj[ fallback ];\n\t}\n\t// First existing language\n\tfor ( lang in obj ) {\n\t\treturn obj[ lang ];\n\t}\n\n\treturn undefined;\n};\n\n/**\n * Check if a node is contained within another node.\n *\n * Similar to jQuery#contains except a list of containers can be supplied\n * and a boolean argument allows you to include the container in the match list\n *\n * @param {HTMLElement|HTMLElement[]} containers Container node(s) to search in\n * @param {HTMLElement} contained Node to find\n * @param {boolean} [matchContainers] Include the container(s) in the list of nodes to match,\n *  otherwise only match descendants\n * @return {boolean} The node is in the list of target nodes\n */\nOO.ui.contains = function ( containers, contained, matchContainers ) {\n\tvar i;\n\tif ( !Array.isArray( containers ) ) {\n\t\tcontainers = [ containers ];\n\t}\n\tfor ( i = containers.length - 1; i >= 0; i-- ) {\n\t\tif (\n\t\t\t( matchContainers && contained === containers[ i ] ) ||\n\t\t\t$.contains( containers[ i ], contained )\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n};\n\n/**\n * Return a function, that, as long as it continues to be invoked, will not\n * be triggered. The function will be called after it stops being called for\n * N milliseconds. If `immediate` is passed, trigger the function on the\n * leading edge, instead of the trailing.\n *\n * Ported from: http://underscorejs.org/underscore.js\n *\n * @param {Function} func Function to debounce\n * @param {number} [wait=0] Wait period in milliseconds\n * @param {boolean} [immediate] Trigger on leading edge\n * @return {Function} Debounced function\n */\nOO.ui.debounce = function ( func, wait, immediate ) {\n\tvar timeout;\n\treturn function () {\n\t\tvar context = this,\n\t\t\targs = arguments,\n\t\t\tlater = function () {\n\t\t\t\ttimeout = null;\n\t\t\t\tif ( !immediate ) {\n\t\t\t\t\tfunc.apply( context, args );\n\t\t\t\t}\n\t\t\t};\n\t\tif ( immediate && !timeout ) {\n\t\t\tfunc.apply( context, args );\n\t\t}\n\t\tif ( !timeout || wait ) {\n\t\t\tclearTimeout( timeout );\n\t\t\ttimeout = setTimeout( later, wait );\n\t\t}\n\t};\n};\n\n/**\n * Puts a console warning with provided message.\n *\n * @param {string} message Message\n */\nOO.ui.warnDeprecation = function ( message ) {\n\tif ( OO.getProp( window, 'console', 'warn' ) !== undefined ) {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn( message );\n\t}\n};\n\n/**\n * Returns a function, that, when invoked, will only be triggered at most once\n * during a given window of time. If called again during that window, it will\n * wait until the window ends and then trigger itself again.\n *\n * As it's not knowable to the caller whether the function will actually run\n * when the wrapper is called, return values from the function are entirely\n * discarded.\n *\n * @param {Function} func Function to throttle\n * @param {number} wait Throttle window length, in milliseconds\n * @return {Function} Throttled function\n */\nOO.ui.throttle = function ( func, wait ) {\n\tvar context, args, timeout,\n\t\tprevious = 0,\n\t\trun = function () {\n\t\t\ttimeout = null;\n\t\t\tprevious = OO.ui.now();\n\t\t\tfunc.apply( context, args );\n\t\t};\n\treturn function () {\n\t\t// Check how long it's been since the last time the function was\n\t\t// called, and whether it's more or less than the requested throttle\n\t\t// period. If it's less, run the function immediately. If it's more,\n\t\t// set a timeout for the remaining time -- but don't replace an\n\t\t// existing timeout, since that'd indefinitely prolong the wait.\n\t\tvar remaining = wait - ( OO.ui.now() - previous );\n\t\tcontext = this;\n\t\targs = arguments;\n\t\tif ( remaining <= 0 ) {\n\t\t\t// Note: unless wait was ridiculously large, this means we'll\n\t\t\t// automatically run the first time the function was called in a\n\t\t\t// given period. (If you provide a wait period larger than the\n\t\t\t// current Unix timestamp, you *deserve* unexpected behavior.)\n\t\t\tclearTimeout( timeout );\n\t\t\trun();\n\t\t} else if ( !timeout ) {\n\t\t\ttimeout = setTimeout( run, remaining );\n\t\t}\n\t};\n};\n\n/**\n * A (possibly faster) way to get the current timestamp as an integer.\n *\n * @return {number} Current timestamp, in milliseconds since the Unix epoch\n */\nOO.ui.now = Date.now || function () {\n\treturn new Date().getTime();\n};\n\n/**\n * Reconstitute a JavaScript object corresponding to a widget created by\n * the PHP implementation.\n *\n * This is an alias for `OO.ui.Element.static.infuse()`.\n *\n * @param {string|HTMLElement|jQuery} idOrNode\n *   A DOM id (if a string) or node for the widget to infuse.\n * @param {Object} [config] Configuration options\n * @return {OO.ui.Element}\n *   The `OO.ui.Element` corresponding to this (infusable) document node.\n */\nOO.ui.infuse = function ( idOrNode, config ) {\n\treturn OO.ui.Element.static.infuse( idOrNode, config );\n};\n\n( function () {\n\t/**\n\t * Message store for the default implementation of OO.ui.msg.\n\t *\n\t * Environments that provide a localization system should not use this, but should override\n\t * OO.ui.msg altogether.\n\t *\n\t * @private\n\t */\n\tvar messages = {\n\t\t// Tool tip for a button that moves items in a list down one place\n\t\t'ooui-outline-control-move-down': 'Move item down',\n\t\t// Tool tip for a button that moves items in a list up one place\n\t\t'ooui-outline-control-move-up': 'Move item up',\n\t\t// Tool tip for a button that removes items from a list\n\t\t'ooui-outline-control-remove': 'Remove item',\n\t\t// Label for the toolbar group that contains a list of all other available tools\n\t\t'ooui-toolbar-more': 'More',\n\t\t// Label for the fake tool that expands the full list of tools in a toolbar group\n\t\t'ooui-toolgroup-expand': 'More',\n\t\t// Label for the fake tool that collapses the full list of tools in a toolbar group\n\t\t'ooui-toolgroup-collapse': 'Fewer',\n\t\t// Default label for the tooltip for the button that removes a tag item\n\t\t'ooui-item-remove': 'Remove',\n\t\t// Default label for the accept button of a confirmation dialog\n\t\t'ooui-dialog-message-accept': 'OK',\n\t\t// Default label for the reject button of a confirmation dialog\n\t\t'ooui-dialog-message-reject': 'Cancel',\n\t\t// Title for process dialog error description\n\t\t'ooui-dialog-process-error': 'Something went wrong',\n\t\t// Label for process dialog dismiss error button, visible when describing errors\n\t\t'ooui-dialog-process-dismiss': 'Dismiss',\n\t\t// Label for process dialog retry action button, visible when describing only recoverable\n\t\t// errors\n\t\t'ooui-dialog-process-retry': 'Try again',\n\t\t// Label for process dialog retry action button, visible when describing only warnings\n\t\t'ooui-dialog-process-continue': 'Continue',\n\t\t// Label for button in combobox input that triggers its dropdown\n\t\t'ooui-combobox-button-label': 'Dropdown for combobox',\n\t\t// Label for the file selection widget's select file button\n\t\t'ooui-selectfile-button-select': 'Select a file',\n\t\t// Label for the file selection widget if file selection is not supported\n\t\t'ooui-selectfile-not-supported': 'File selection is not supported',\n\t\t// Label for the file selection widget when no file is currently selected\n\t\t'ooui-selectfile-placeholder': 'No file is selected',\n\t\t// Label for the file selection widget's drop target\n\t\t'ooui-selectfile-dragdrop-placeholder': 'Drop file here',\n\t\t// Label for the help icon attached to a form field\n\t\t'ooui-field-help': 'Help'\n\t};\n\n\t/**\n\t * Get a localized message.\n\t *\n\t * After the message key, message parameters may optionally be passed. In the default\n\t * implementation, any occurrences of $1 are replaced with the first parameter, $2 with the\n\t * second parameter, etc.\n\t * Alternative implementations of OO.ui.msg may use any substitution system they like, as long\n\t * as they support unnamed, ordered message parameters.\n\t *\n\t * In environments that provide a localization system, this function should be overridden to\n\t * return the message translated in the user's language. The default implementation always\n\t * returns English messages. An example of doing this with\n\t * [jQuery.i18n](https://github.com/wikimedia/jquery.i18n) follows.\n\t *\n\t *     @example\n\t *     var i, iLen, button,\n\t *         messagePath = 'oojs-ui/dist/i18n/',\n\t *         languages = [ $.i18n().locale, 'ur', 'en' ],\n\t *         languageMap = {};\n\t *\n\t *     for ( i = 0, iLen = languages.length; i < iLen; i++ ) {\n\t *         languageMap[ languages[ i ] ] = messagePath + languages[ i ].toLowerCase() + '.json';\n\t *     }\n\t *\n\t *     $.i18n().load( languageMap ).done( function() {\n\t *         // Replace the built-in `msg` only once we've loaded the internationalization.\n\t *         // OOUI uses `OO.ui.deferMsg` for all initially-loaded messages. So long as\n\t *         // you put off creating any widgets until this promise is complete, no English\n\t *         // will be displayed.\n\t *         OO.ui.msg = $.i18n;\n\t *\n\t *         // A button displaying \"OK\" in the default locale\n\t *         button = new OO.ui.ButtonWidget( {\n\t *             label: OO.ui.msg( 'ooui-dialog-message-accept' ),\n\t *             icon: 'check'\n\t *         } );\n\t *         $( document.body ).append( button.$element );\n\t *\n\t *         // A button displaying \"OK\" in Urdu\n\t *         $.i18n().locale = 'ur';\n\t *         button = new OO.ui.ButtonWidget( {\n\t *             label: OO.ui.msg( 'ooui-dialog-message-accept' ),\n\t *             icon: 'check'\n\t *         } );\n\t *         $( document.body ).append( button.$element );\n\t *     } );\n\t *\n\t * @param {string} key Message key\n\t * @param {...Mixed} [params] Message parameters\n\t * @return {string} Translated message with parameters substituted\n\t */\n\tOO.ui.msg = function ( key ) {\n\t\tvar message = messages[ key ],\n\t\t\tparams = Array.prototype.slice.call( arguments, 1 );\n\t\tif ( typeof message === 'string' ) {\n\t\t\t// Perform $1 substitution\n\t\t\tmessage = message.replace( /\\$(\\d+)/g, function ( unused, n ) {\n\t\t\t\tvar i = parseInt( n, 10 );\n\t\t\t\treturn params[ i - 1 ] !== undefined ? params[ i - 1 ] : '$' + n;\n\t\t\t} );\n\t\t} else {\n\t\t\t// Return placeholder if message not found\n\t\t\tmessage = '[' + key + ']';\n\t\t}\n\t\treturn message;\n\t};\n}() );\n\n/**\n * Package a message and arguments for deferred resolution.\n *\n * Use this when you are statically specifying a message and the message may not yet be present.\n *\n * @param {string} key Message key\n * @param {...Mixed} [params] Message parameters\n * @return {Function} Function that returns the resolved message when executed\n */\nOO.ui.deferMsg = function () {\n\tvar args = arguments;\n\treturn function () {\n\t\treturn OO.ui.msg.apply( OO.ui, args );\n\t};\n};\n\n/**\n * Resolve a message.\n *\n * If the message is a function it will be executed, otherwise it will pass through directly.\n *\n * @param {Function|string} msg Deferred message, or message text\n * @return {string} Resolved message\n */\nOO.ui.resolveMsg = function ( msg ) {\n\tif ( typeof msg === 'function' ) {\n\t\treturn msg();\n\t}\n\treturn msg;\n};\n\n/**\n * @param {string} url\n * @return {boolean}\n */\nOO.ui.isSafeUrl = function ( url ) {\n\t// Keep this function in sync with php/Tag.php\n\tvar i, protocolWhitelist;\n\n\tfunction stringStartsWith( haystack, needle ) {\n\t\treturn haystack.substr( 0, needle.length ) === needle;\n\t}\n\n\tprotocolWhitelist = [\n\t\t'bitcoin', 'ftp', 'ftps', 'geo', 'git', 'gopher', 'http', 'https', 'irc', 'ircs',\n\t\t'magnet', 'mailto', 'mms', 'news', 'nntp', 'redis', 'sftp', 'sip', 'sips', 'sms', 'ssh',\n\t\t'svn', 'tel', 'telnet', 'urn', 'worldwind', 'xmpp'\n\t];\n\n\tif ( url === '' ) {\n\t\treturn true;\n\t}\n\n\tfor ( i = 0; i < protocolWhitelist.length; i++ ) {\n\t\tif ( stringStartsWith( url, protocolWhitelist[ i ] + ':' ) ) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t// This matches '//' too\n\tif ( stringStartsWith( url, '/' ) || stringStartsWith( url, './' ) ) {\n\t\treturn true;\n\t}\n\tif ( stringStartsWith( url, '?' ) || stringStartsWith( url, '#' ) ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n};\n\n/**\n * Check if the user has a 'mobile' device.\n *\n * For our purposes this means the user is primarily using an\n * on-screen keyboard, touch input instead of a mouse and may\n * have a physically small display.\n *\n * It is left up to implementors to decide how to compute this\n * so the default implementation always returns false.\n *\n * @return {boolean} User is on a mobile device\n */\nOO.ui.isMobile = function () {\n\treturn false;\n};\n\n/**\n * Get the additional spacing that should be taken into account when displaying elements that are\n * clipped to the viewport, e.g. dropdown menus and popups. This is meant to be overridden to avoid\n * such menus overlapping any fixed headers/toolbars/navigation used by the site.\n *\n * @return {Object} Object with the properties 'top', 'right', 'bottom', 'left', each representing\n *  the extra spacing from that edge of viewport (in pixels)\n */\nOO.ui.getViewportSpacing = function () {\n\treturn {\n\t\ttop: 0,\n\t\tright: 0,\n\t\tbottom: 0,\n\t\tleft: 0\n\t};\n};\n\n/**\n * Get the default overlay, which is used by various widgets when they are passed `$overlay: true`.\n * See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.\n *\n * @return {jQuery} Default overlay node\n */\nOO.ui.getDefaultOverlay = function () {\n\tif ( !OO.ui.$defaultOverlay ) {\n\t\tOO.ui.$defaultOverlay = $( '<div>' ).addClass( 'oo-ui-defaultOverlay' );\n\t\t$( document.body ).append( OO.ui.$defaultOverlay );\n\t}\n\treturn OO.ui.$defaultOverlay;\n};\n","/*!\n * Mixin namespace.\n */\n\n/**\n * Namespace for OOUI mixins.\n *\n * Mixins are named according to the type of object they are intended to\n * be mixed in to.  For example, OO.ui.mixin.GroupElement is intended to be\n * mixed in to an instance of OO.ui.Element, and OO.ui.mixin.GroupWidget\n * is intended to be mixed in to an instance of OO.ui.Widget.\n *\n * @class\n * @singleton\n */\nOO.ui.mixin = {};\n","/**\n * Each Element represents a rendering in the DOM—a button or an icon, for example, or anything\n * that is visible to a user. Unlike {@link OO.ui.Widget widgets}, plain elements usually do not\n * have events connected to them and can't be interacted with.\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {string[]} [classes] The names of the CSS classes to apply to the element. CSS styles are\n *  added to the top level (e.g., the outermost div) of the element. See the\n *  [OOUI documentation on MediaWiki][2] for an example.\n *  [2]: https://www.mediawiki.org/wiki/OOUI/Widgets/Buttons_and_Switches#cssExample\n * @cfg {string} [id] The HTML id attribute used in the rendered tag.\n * @cfg {string} [text] Text to insert\n * @cfg {Array} [content] An array of content elements to append (after #text).\n *  Strings will be html-escaped; use an OO.ui.HtmlSnippet to append raw HTML.\n *  Instances of OO.ui.Element will have their $element appended.\n * @cfg {jQuery} [$content] Content elements to append (after #text).\n * @cfg {jQuery} [$element] Wrapper element. Defaults to a new element with #getTagName.\n * @cfg {Mixed} [data] Custom data of any type or combination of types (e.g., string, number,\n *  array, object).\n *  Data can also be specified with the #setData method.\n */\nOO.ui.Element = function OoUiElement( config ) {\n\tif ( OO.ui.isDemo ) {\n\t\tthis.initialConfig = config;\n\t}\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.$ = function () {\n\t\tOO.ui.warnDeprecation( 'this.$ is deprecated, use global $ instead' );\n\t\treturn $.apply( this, arguments );\n\t};\n\tthis.elementId = null;\n\tthis.visible = true;\n\tthis.data = config.data;\n\tthis.$element = config.$element ||\n\t\t$( document.createElement( this.getTagName() ) );\n\tthis.elementGroup = null;\n\n\t// Initialization\n\tif ( Array.isArray( config.classes ) ) {\n\t\tthis.$element.addClass( config.classes );\n\t}\n\tif ( config.id ) {\n\t\tthis.setElementId( config.id );\n\t}\n\tif ( config.text ) {\n\t\tthis.$element.text( config.text );\n\t}\n\tif ( config.content ) {\n\t\t// The `content` property treats plain strings as text; use an\n\t\t// HtmlSnippet to append HTML content.  `OO.ui.Element`s get their\n\t\t// appropriate $element appended.\n\t\tthis.$element.append( config.content.map( function ( v ) {\n\t\t\tif ( typeof v === 'string' ) {\n\t\t\t\t// Escape string so it is properly represented in HTML.\n\t\t\t\t// Don't create empty text nodes for empty strings.\n\t\t\t\treturn v ? document.createTextNode( v ) : undefined;\n\t\t\t} else if ( v instanceof OO.ui.HtmlSnippet ) {\n\t\t\t\t// Bypass escaping.\n\t\t\t\treturn v.toString();\n\t\t\t} else if ( v instanceof OO.ui.Element ) {\n\t\t\t\treturn v.$element;\n\t\t\t}\n\t\t\treturn v;\n\t\t} ) );\n\t}\n\tif ( config.$content ) {\n\t\t// The `$content` property treats plain strings as HTML.\n\t\tthis.$element.append( config.$content );\n\t}\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.Element );\n\n/* Static Properties */\n\n/**\n * The name of the HTML tag used by the element.\n *\n * The static value may be ignored if the #getTagName method is overridden.\n *\n * @static\n * @inheritable\n * @property {string}\n */\nOO.ui.Element.static.tagName = 'div';\n\n/* Static Methods */\n\n/**\n * Reconstitute a JavaScript object corresponding to a widget created\n * by the PHP implementation.\n *\n * @param {string|HTMLElement|jQuery} idOrNode\n *   A DOM id (if a string) or node for the widget to infuse.\n * @param {Object} [config] Configuration options\n * @return {OO.ui.Element}\n *   The `OO.ui.Element` corresponding to this (infusable) document node.\n *   For `Tag` objects emitted on the HTML side (used occasionally for content)\n *   the value returned is a newly-created Element wrapping around the existing\n *   DOM node.\n */\nOO.ui.Element.static.infuse = function ( idOrNode, config ) {\n\tvar obj = OO.ui.Element.static.unsafeInfuse( idOrNode, config, false );\n\n\tif ( typeof idOrNode === 'string' ) {\n\t\t// IDs deprecated since 0.29.7\n\t\tOO.ui.warnDeprecation(\n\t\t\t'Passing a string ID to infuse is deprecated. Use an HTMLElement or jQuery collection instead.'\n\t\t);\n\t}\n\t// Verify that the type matches up.\n\t// FIXME: uncomment after T89721 is fixed, see T90929.\n\t/*\n\tif ( !( obj instanceof this['class'] ) ) {\n\t\tthrow new Error( 'Infusion type mismatch!' );\n\t}\n\t*/\n\treturn obj;\n};\n\n/**\n * Implementation helper for `infuse`; skips the type check and has an\n * extra property so that only the top-level invocation touches the DOM.\n *\n * @private\n * @param {string|HTMLElement|jQuery} idOrNode\n * @param {Object} [config] Configuration options\n * @param {jQuery.Promise} [domPromise] A promise that will be resolved\n *     when the top-level widget of this infusion is inserted into DOM,\n *     replacing the original node; only used internally.\n * @return {OO.ui.Element}\n */\nOO.ui.Element.static.unsafeInfuse = function ( idOrNode, config, domPromise ) {\n\t// look for a cached result of a previous infusion.\n\tvar id, $elem, error, data, cls, parts, parent, obj, top, state, infusedChildren;\n\tif ( typeof idOrNode === 'string' ) {\n\t\tid = idOrNode;\n\t\t$elem = $( document.getElementById( id ) );\n\t} else {\n\t\t$elem = $( idOrNode );\n\t\tid = $elem.attr( 'id' );\n\t}\n\tif ( !$elem.length ) {\n\t\tif ( typeof idOrNode === 'string' ) {\n\t\t\terror = 'Widget not found: ' + idOrNode;\n\t\t} else if ( idOrNode && idOrNode.selector ) {\n\t\t\terror = 'Widget not found: ' + idOrNode.selector;\n\t\t} else {\n\t\t\terror = 'Widget not found';\n\t\t}\n\t\tthrow new Error( error );\n\t}\n\tif ( $elem[ 0 ].oouiInfused ) {\n\t\t$elem = $elem[ 0 ].oouiInfused;\n\t}\n\tdata = $elem.data( 'ooui-infused' );\n\tif ( data ) {\n\t\t// cached!\n\t\tif ( data === true ) {\n\t\t\tthrow new Error( 'Circular dependency! ' + id );\n\t\t}\n\t\tif ( domPromise ) {\n\t\t\t// Pick up dynamic state, like focus, value of form inputs, scroll position, etc.\n\t\t\tstate = data.constructor.static.gatherPreInfuseState( $elem, data );\n\t\t\t// Restore dynamic state after the new element is re-inserted into DOM under\n\t\t\t// infused parent.\n\t\t\tdomPromise.done( data.restorePreInfuseState.bind( data, state ) );\n\t\t\tinfusedChildren = $elem.data( 'ooui-infused-children' );\n\t\t\tif ( infusedChildren && infusedChildren.length ) {\n\t\t\t\tinfusedChildren.forEach( function ( data ) {\n\t\t\t\t\tvar state = data.constructor.static.gatherPreInfuseState( $elem, data );\n\t\t\t\t\tdomPromise.done( data.restorePreInfuseState.bind( data, state ) );\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\treturn data;\n\t}\n\tdata = $elem.attr( 'data-ooui' );\n\tif ( !data ) {\n\t\tthrow new Error( 'No infusion data found: ' + id );\n\t}\n\ttry {\n\t\tdata = JSON.parse( data );\n\t} catch ( _ ) {\n\t\tdata = null;\n\t}\n\tif ( !( data && data._ ) ) {\n\t\tthrow new Error( 'No valid infusion data found: ' + id );\n\t}\n\tif ( data._ === 'Tag' ) {\n\t\t// Special case: this is a raw Tag; wrap existing node, don't rebuild.\n\t\treturn new OO.ui.Element( $.extend( {}, config, { $element: $elem } ) );\n\t}\n\tparts = data._.split( '.' );\n\tcls = OO.getProp.apply( OO, [ window ].concat( parts ) );\n\tif ( cls === undefined ) {\n\t\tthrow new Error( 'Unknown widget type: id: ' + id + ', class: ' + data._ );\n\t}\n\n\t// Verify that we're creating an OO.ui.Element instance\n\tparent = cls.parent;\n\n\twhile ( parent !== undefined ) {\n\t\tif ( parent === OO.ui.Element ) {\n\t\t\t// Safe\n\t\t\tbreak;\n\t\t}\n\n\t\tparent = parent.parent;\n\t}\n\n\tif ( parent !== OO.ui.Element ) {\n\t\tthrow new Error( 'Unknown widget type: id: ' + id + ', class: ' + data._ );\n\t}\n\n\tif ( !domPromise ) {\n\t\ttop = $.Deferred();\n\t\tdomPromise = top.promise();\n\t}\n\t$elem.data( 'ooui-infused', true ); // prevent loops\n\tdata.id = id; // implicit\n\tinfusedChildren = [];\n\tdata = OO.copy( data, null, function deserialize( value ) {\n\t\tvar infused;\n\t\tif ( OO.isPlainObject( value ) ) {\n\t\t\tif ( value.tag ) {\n\t\t\t\tinfused = OO.ui.Element.static.unsafeInfuse( value.tag, config, domPromise );\n\t\t\t\tinfusedChildren.push( infused );\n\t\t\t\t// Flatten the structure\n\t\t\t\tinfusedChildren.push.apply(\n\t\t\t\t\tinfusedChildren,\n\t\t\t\t\tinfused.$element.data( 'ooui-infused-children' ) || []\n\t\t\t\t);\n\t\t\t\tinfused.$element.removeData( 'ooui-infused-children' );\n\t\t\t\treturn infused;\n\t\t\t}\n\t\t\tif ( value.html !== undefined ) {\n\t\t\t\treturn new OO.ui.HtmlSnippet( value.html );\n\t\t\t}\n\t\t}\n\t} );\n\t// allow widgets to reuse parts of the DOM\n\tdata = cls.static.reusePreInfuseDOM( $elem[ 0 ], data );\n\t// pick up dynamic state, like focus, value of form inputs, scroll position, etc.\n\tstate = cls.static.gatherPreInfuseState( $elem[ 0 ], data );\n\t// rebuild widget\n\t// eslint-disable-next-line new-cap\n\tobj = new cls( $.extend( {}, config, data ) );\n\t// If anyone is holding a reference to the old DOM element,\n\t// let's allow them to OO.ui.infuse() it and do what they expect, see T105828.\n\t// Do not use jQuery.data(), as using it on detached nodes leaks memory in 1.x line by design.\n\t$elem[ 0 ].oouiInfused = obj.$element;\n\t// now replace old DOM with this new DOM.\n\tif ( top ) {\n\t\t// An efficient constructor might be able to reuse the entire DOM tree of the original\n\t\t// element, so only mutate the DOM if we need to.\n\t\tif ( $elem[ 0 ] !== obj.$element[ 0 ] ) {\n\t\t\t$elem.replaceWith( obj.$element );\n\t\t}\n\t\ttop.resolve();\n\t}\n\tobj.$element.data( 'ooui-infused', obj );\n\tobj.$element.data( 'ooui-infused-children', infusedChildren );\n\t// set the 'data-ooui' attribute so we can identify infused widgets\n\tobj.$element.attr( 'data-ooui', '' );\n\t// restore dynamic state after the new element is inserted into DOM\n\tdomPromise.done( obj.restorePreInfuseState.bind( obj, state ) );\n\treturn obj;\n};\n\n/**\n * Pick out parts of `node`'s DOM to be reused when infusing a widget.\n *\n * This method **must not** make any changes to the DOM, only find interesting pieces and add them\n * to `config` (which should then be returned). Actual DOM juggling should then be done by the\n * constructor, which will be given the enhanced config.\n *\n * @protected\n * @param {HTMLElement} node\n * @param {Object} config\n * @return {Object}\n */\nOO.ui.Element.static.reusePreInfuseDOM = function ( node, config ) {\n\treturn config;\n};\n\n/**\n * Gather the dynamic state (focus, value of form inputs, scroll position, etc.) of an HTML DOM\n * node (and its children) that represent an Element of the same class and the given configuration,\n * generated by the PHP implementation.\n *\n * This method is called just before `node` is detached from the DOM. The return value of this\n * function will be passed to #restorePreInfuseState after the newly created widget's #$element\n * is inserted into DOM to replace `node`.\n *\n * @protected\n * @param {HTMLElement} node\n * @param {Object} config\n * @return {Object}\n */\nOO.ui.Element.static.gatherPreInfuseState = function () {\n\treturn {};\n};\n\n/**\n * Get a jQuery function within a specific document.\n *\n * @static\n * @param {jQuery|HTMLElement|HTMLDocument|Window} context Context to bind the function to\n * @param {jQuery} [$iframe] HTML iframe element that contains the document, omit if document is\n *   not in an iframe\n * @return {Function} Bound jQuery function\n */\nOO.ui.Element.static.getJQuery = function ( context, $iframe ) {\n\tfunction wrapper( selector ) {\n\t\treturn $( selector, wrapper.context );\n\t}\n\n\twrapper.context = this.getDocument( context );\n\n\tif ( $iframe ) {\n\t\twrapper.$iframe = $iframe;\n\t}\n\n\treturn wrapper;\n};\n\n/**\n * Get the document of an element.\n *\n * @static\n * @param {jQuery|HTMLElement|HTMLDocument|Window} obj Object to get the document for\n * @return {HTMLDocument|null} Document object\n */\nOO.ui.Element.static.getDocument = function ( obj ) {\n\t// jQuery - selections created \"offscreen\" won't have a context, so .context isn't reliable\n\treturn ( obj[ 0 ] && obj[ 0 ].ownerDocument ) ||\n\t\t// Empty jQuery selections might have a context\n\t\tobj.context ||\n\t\t// HTMLElement\n\t\tobj.ownerDocument ||\n\t\t// Window\n\t\tobj.document ||\n\t\t// HTMLDocument\n\t\t( obj.nodeType === Node.DOCUMENT_NODE && obj ) ||\n\t\tnull;\n};\n\n/**\n * Get the window of an element or document.\n *\n * @static\n * @param {jQuery|HTMLElement|HTMLDocument|Window} obj Context to get the window for\n * @return {Window} Window object\n */\nOO.ui.Element.static.getWindow = function ( obj ) {\n\tvar doc = this.getDocument( obj );\n\treturn doc.defaultView;\n};\n\n/**\n * Get the direction of an element or document.\n *\n * @static\n * @param {jQuery|HTMLElement|HTMLDocument|Window} obj Context to get the direction for\n * @return {string} Text direction, either 'ltr' or 'rtl'\n */\nOO.ui.Element.static.getDir = function ( obj ) {\n\tvar isDoc, isWin;\n\n\tif ( obj instanceof $ ) {\n\t\tobj = obj[ 0 ];\n\t}\n\tisDoc = obj.nodeType === Node.DOCUMENT_NODE;\n\tisWin = obj.document !== undefined;\n\tif ( isDoc || isWin ) {\n\t\tif ( isWin ) {\n\t\t\tobj = obj.document;\n\t\t}\n\t\tobj = obj.body;\n\t}\n\treturn $( obj ).css( 'direction' );\n};\n\n/**\n * Get the offset between two frames.\n *\n * TODO: Make this function not use recursion.\n *\n * @static\n * @param {Window} from Window of the child frame\n * @param {Window} [to=window] Window of the parent frame\n * @param {Object} [offset] Offset to start with, used internally\n * @return {Object} Offset object, containing left and top properties\n */\nOO.ui.Element.static.getFrameOffset = function ( from, to, offset ) {\n\tvar i, len, frames, frame, rect;\n\n\tif ( !to ) {\n\t\tto = window;\n\t}\n\tif ( !offset ) {\n\t\toffset = { top: 0, left: 0 };\n\t}\n\tif ( from.parent === from ) {\n\t\treturn offset;\n\t}\n\n\t// Get iframe element\n\tframes = from.parent.document.getElementsByTagName( 'iframe' );\n\tfor ( i = 0, len = frames.length; i < len; i++ ) {\n\t\tif ( frames[ i ].contentWindow === from ) {\n\t\t\tframe = frames[ i ];\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Recursively accumulate offset values\n\tif ( frame ) {\n\t\trect = frame.getBoundingClientRect();\n\t\toffset.left += rect.left;\n\t\toffset.top += rect.top;\n\t\tif ( from !== to ) {\n\t\t\tthis.getFrameOffset( from.parent, offset );\n\t\t}\n\t}\n\treturn offset;\n};\n\n/**\n * Get the offset between two elements.\n *\n * The two elements may be in a different frame, but in that case the frame $element is in must\n * be contained in the frame $anchor is in.\n *\n * @static\n * @param {jQuery} $element Element whose position to get\n * @param {jQuery} $anchor Element to get $element's position relative to\n * @return {Object} Translated position coordinates, containing top and left properties\n */\nOO.ui.Element.static.getRelativePosition = function ( $element, $anchor ) {\n\tvar iframe, iframePos,\n\t\tpos = $element.offset(),\n\t\tanchorPos = $anchor.offset(),\n\t\telementDocument = this.getDocument( $element ),\n\t\tanchorDocument = this.getDocument( $anchor );\n\n\t// If $element isn't in the same document as $anchor, traverse up\n\twhile ( elementDocument !== anchorDocument ) {\n\t\tiframe = elementDocument.defaultView.frameElement;\n\t\tif ( !iframe ) {\n\t\t\tthrow new Error( '$element frame is not contained in $anchor frame' );\n\t\t}\n\t\tiframePos = $( iframe ).offset();\n\t\tpos.left += iframePos.left;\n\t\tpos.top += iframePos.top;\n\t\telementDocument = iframe.ownerDocument;\n\t}\n\tpos.left -= anchorPos.left;\n\tpos.top -= anchorPos.top;\n\treturn pos;\n};\n\n/**\n * Get element border sizes.\n *\n * @static\n * @param {HTMLElement} el Element to measure\n * @return {Object} Dimensions object with `top`, `left`, `bottom` and `right` properties\n */\nOO.ui.Element.static.getBorders = function ( el ) {\n\tvar doc = el.ownerDocument,\n\t\twin = doc.defaultView,\n\t\tstyle = win.getComputedStyle( el, null ),\n\t\t$el = $( el ),\n\t\ttop = parseFloat( style ? style.borderTopWidth : $el.css( 'borderTopWidth' ) ) || 0,\n\t\tleft = parseFloat( style ? style.borderLeftWidth : $el.css( 'borderLeftWidth' ) ) || 0,\n\t\tbottom = parseFloat( style ? style.borderBottomWidth : $el.css( 'borderBottomWidth' ) ) || 0,\n\t\tright = parseFloat( style ? style.borderRightWidth : $el.css( 'borderRightWidth' ) ) || 0;\n\n\treturn {\n\t\ttop: top,\n\t\tleft: left,\n\t\tbottom: bottom,\n\t\tright: right\n\t};\n};\n\n/**\n * Get dimensions of an element or window.\n *\n * @static\n * @param {HTMLElement|Window} el Element to measure\n * @return {Object} Dimensions object with `borders`, `scroll`, `scrollbar` and `rect` properties\n */\nOO.ui.Element.static.getDimensions = function ( el ) {\n\tvar $el, $win,\n\t\tdoc = el.ownerDocument || el.document,\n\t\twin = doc.defaultView;\n\n\tif ( win === el || el === doc.documentElement ) {\n\t\t$win = $( win );\n\t\treturn {\n\t\t\tborders: { top: 0, left: 0, bottom: 0, right: 0 },\n\t\t\tscroll: {\n\t\t\t\ttop: $win.scrollTop(),\n\t\t\t\tleft: $win.scrollLeft()\n\t\t\t},\n\t\t\tscrollbar: { right: 0, bottom: 0 },\n\t\t\trect: {\n\t\t\t\ttop: 0,\n\t\t\t\tleft: 0,\n\t\t\t\tbottom: $win.innerHeight(),\n\t\t\t\tright: $win.innerWidth()\n\t\t\t}\n\t\t};\n\t} else {\n\t\t$el = $( el );\n\t\treturn {\n\t\t\tborders: this.getBorders( el ),\n\t\t\tscroll: {\n\t\t\t\ttop: $el.scrollTop(),\n\t\t\t\tleft: $el.scrollLeft()\n\t\t\t},\n\t\t\tscrollbar: {\n\t\t\t\tright: $el.innerWidth() - el.clientWidth,\n\t\t\t\tbottom: $el.innerHeight() - el.clientHeight\n\t\t\t},\n\t\t\trect: el.getBoundingClientRect()\n\t\t};\n\t}\n};\n\n/**\n * Get the number of pixels that an element's content is scrolled to the left.\n *\n * Adapted from <https://github.com/othree/jquery.rtl-scroll-type>.\n * Original code copyright 2012 Wei-Ko Kao, licensed under the MIT License.\n *\n * This function smooths out browser inconsistencies (nicely described in the README at\n * <https://github.com/othree/jquery.rtl-scroll-type>) and produces a result consistent\n * with Firefox's 'scrollLeft', which seems the sanest.\n *\n * @static\n * @method\n * @param {HTMLElement|Window} el Element to measure\n * @return {number} Scroll position from the left.\n *  If the element's direction is LTR, this is a positive number between `0` (initial scroll\n *  position) and `el.scrollWidth - el.clientWidth` (furthest possible scroll position).\n *  If the element's direction is RTL, this is a negative number between `0` (initial scroll\n *  position) and `-el.scrollWidth + el.clientWidth` (furthest possible scroll position).\n */\nOO.ui.Element.static.getScrollLeft = ( function () {\n\tvar rtlScrollType = null;\n\n\tfunction test() {\n\t\tvar $definer = $( '<div>' ).attr( {\n\t\t\t\tdir: 'rtl',\n\t\t\t\tstyle: 'font-size: 14px; width: 4px; height: 1px; position: absolute; top: -1000px; overflow: scroll;'\n\t\t\t} ).text( 'ABCD' ),\n\t\t\tdefiner = $definer[ 0 ];\n\n\t\t$definer.appendTo( 'body' );\n\t\tif ( definer.scrollLeft > 0 ) {\n\t\t\t// Safari, Chrome\n\t\t\trtlScrollType = 'default';\n\t\t} else {\n\t\t\tdefiner.scrollLeft = 1;\n\t\t\tif ( definer.scrollLeft === 0 ) {\n\t\t\t\t// Firefox, old Opera\n\t\t\t\trtlScrollType = 'negative';\n\t\t\t} else {\n\t\t\t\t// Internet Explorer, Edge\n\t\t\t\trtlScrollType = 'reverse';\n\t\t\t}\n\t\t}\n\t\t$definer.remove();\n\t}\n\n\treturn function getScrollLeft( el ) {\n\t\tvar isRoot = el.window === el ||\n\t\t\t\tel === el.ownerDocument.body ||\n\t\t\t\tel === el.ownerDocument.documentElement,\n\t\t\tscrollLeft = isRoot ? $( window ).scrollLeft() : el.scrollLeft,\n\t\t\t// All browsers use the correct scroll type ('negative') on the root, so don't\n\t\t\t// do any fixups when looking at the root element\n\t\t\tdirection = isRoot ? 'ltr' : $( el ).css( 'direction' );\n\n\t\tif ( direction === 'rtl' ) {\n\t\t\tif ( rtlScrollType === null ) {\n\t\t\t\ttest();\n\t\t\t}\n\t\t\tif ( rtlScrollType === 'reverse' ) {\n\t\t\t\tscrollLeft = -scrollLeft;\n\t\t\t} else if ( rtlScrollType === 'default' ) {\n\t\t\t\tscrollLeft = scrollLeft - el.scrollWidth + el.clientWidth;\n\t\t\t}\n\t\t}\n\n\t\treturn scrollLeft;\n\t};\n}() );\n\n/**\n * Get the root scrollable element of given element's document.\n *\n * On Blink-based browsers (Chrome etc.), `document.documentElement` can't be used to get or set\n * the scrollTop property; instead we have to use `document.body`. Changing and testing the value\n * lets us use 'body' or 'documentElement' based on what is working.\n *\n * https://code.google.com/p/chromium/issues/detail?id=303131\n *\n * @static\n * @param {HTMLElement} el Element to find root scrollable parent for\n * @return {HTMLElement} Scrollable parent, `document.body` or `document.documentElement`\n *     depending on browser\n */\nOO.ui.Element.static.getRootScrollableElement = function ( el ) {\n\tvar scrollTop, body;\n\n\tif ( OO.ui.scrollableElement === undefined ) {\n\t\tbody = el.ownerDocument.body;\n\t\tscrollTop = body.scrollTop;\n\t\tbody.scrollTop = 1;\n\n\t\t// In some browsers (observed in Chrome 56 on Linux Mint 18.1),\n\t\t// body.scrollTop doesn't become exactly 1, but a fractional value like 0.76\n\t\tif ( Math.round( body.scrollTop ) === 1 ) {\n\t\t\tbody.scrollTop = scrollTop;\n\t\t\tOO.ui.scrollableElement = 'body';\n\t\t} else {\n\t\t\tOO.ui.scrollableElement = 'documentElement';\n\t\t}\n\t}\n\n\treturn el.ownerDocument[ OO.ui.scrollableElement ];\n};\n\n/**\n * Get closest scrollable container.\n *\n * Traverses up until either a scrollable element or the root is reached, in which case the root\n * scrollable element will be returned (see #getRootScrollableElement).\n *\n * @static\n * @param {HTMLElement} el Element to find scrollable container for\n * @param {string} [dimension] Dimension of scrolling to look for; `x`, `y` or omit for either\n * @return {HTMLElement} Closest scrollable container\n */\nOO.ui.Element.static.getClosestScrollableContainer = function ( el, dimension ) {\n\tvar i, val,\n\t\t// Browsers do not correctly return the computed value of 'overflow' when 'overflow-x' and\n\t\t// 'overflow-y' have different values, so we need to check the separate properties.\n\t\tprops = [ 'overflow-x', 'overflow-y' ],\n\t\t$parent = $( el ).parent();\n\n\tif ( dimension === 'x' || dimension === 'y' ) {\n\t\tprops = [ 'overflow-' + dimension ];\n\t}\n\n\t// Special case for the document root (which doesn't really have any scrollable container,\n\t// since it is the ultimate scrollable container, but this is probably saner than null or\n\t// exception).\n\tif ( $( el ).is( 'html, body' ) ) {\n\t\treturn this.getRootScrollableElement( el );\n\t}\n\n\twhile ( $parent.length ) {\n\t\tif ( $parent[ 0 ] === this.getRootScrollableElement( el ) ) {\n\t\t\treturn $parent[ 0 ];\n\t\t}\n\t\ti = props.length;\n\t\twhile ( i-- ) {\n\t\t\tval = $parent.css( props[ i ] );\n\t\t\t// We assume that elements with 'overflow' (in any direction) set to 'hidden' will\n\t\t\t// never be scrolled in that direction, but they can actually be scrolled\n\t\t\t// programatically. The user can unintentionally perform a scroll in such case even if\n\t\t\t// the application doesn't scroll programatically, e.g. when jumping to an anchor, or\n\t\t\t// when using built-in find functionality.\n\t\t\t// This could cause funny issues...\n\t\t\tif ( val === 'auto' || val === 'scroll' ) {\n\t\t\t\treturn $parent[ 0 ];\n\t\t\t}\n\t\t}\n\t\t$parent = $parent.parent();\n\t}\n\t// The element is unattached... return something mostly sane\n\treturn this.getRootScrollableElement( el );\n};\n\n/**\n * Scroll element into view.\n *\n * @static\n * @param {HTMLElement} el Element to scroll into view\n * @param {Object} [config] Configuration options\n * @param {string} [config.duration='fast'] jQuery animation duration value\n * @param {string} [config.direction] Scroll in only one direction, e.g. 'x' or 'y', omit\n *  to scroll in both directions\n * @return {jQuery.Promise} Promise which resolves when the scroll is complete\n */\nOO.ui.Element.static.scrollIntoView = function ( el, config ) {\n\tvar position, animations, container, $container, elementDimensions, containerDimensions,\n\t\t$window,\n\t\tdeferred = $.Deferred();\n\n\t// Configuration initialization\n\tconfig = config || {};\n\n\tanimations = {};\n\tcontainer = this.getClosestScrollableContainer( el, config.direction );\n\t$container = $( container );\n\telementDimensions = this.getDimensions( el );\n\tcontainerDimensions = this.getDimensions( container );\n\t$window = $( this.getWindow( el ) );\n\n\t// Compute the element's position relative to the container\n\tif ( $container.is( 'html, body' ) ) {\n\t\t// If the scrollable container is the root, this is easy\n\t\tposition = {\n\t\t\ttop: elementDimensions.rect.top,\n\t\t\tbottom: $window.innerHeight() - elementDimensions.rect.bottom,\n\t\t\tleft: elementDimensions.rect.left,\n\t\t\tright: $window.innerWidth() - elementDimensions.rect.right\n\t\t};\n\t} else {\n\t\t// Otherwise, we have to subtract el's coordinates from container's coordinates\n\t\tposition = {\n\t\t\ttop: elementDimensions.rect.top -\n\t\t\t\t( containerDimensions.rect.top + containerDimensions.borders.top ),\n\t\t\tbottom: containerDimensions.rect.bottom - containerDimensions.borders.bottom -\n\t\t\t\tcontainerDimensions.scrollbar.bottom - elementDimensions.rect.bottom,\n\t\t\tleft: elementDimensions.rect.left -\n\t\t\t\t( containerDimensions.rect.left + containerDimensions.borders.left ),\n\t\t\tright: containerDimensions.rect.right - containerDimensions.borders.right -\n\t\t\t\tcontainerDimensions.scrollbar.right - elementDimensions.rect.right\n\t\t};\n\t}\n\n\tif ( !config.direction || config.direction === 'y' ) {\n\t\tif ( position.top < 0 ) {\n\t\t\tanimations.scrollTop = containerDimensions.scroll.top + position.top;\n\t\t} else if ( position.top > 0 && position.bottom < 0 ) {\n\t\t\tanimations.scrollTop = containerDimensions.scroll.top +\n\t\t\t\tMath.min( position.top, -position.bottom );\n\t\t}\n\t}\n\tif ( !config.direction || config.direction === 'x' ) {\n\t\tif ( position.left < 0 ) {\n\t\t\tanimations.scrollLeft = containerDimensions.scroll.left + position.left;\n\t\t} else if ( position.left > 0 && position.right < 0 ) {\n\t\t\tanimations.scrollLeft = containerDimensions.scroll.left +\n\t\t\t\tMath.min( position.left, -position.right );\n\t\t}\n\t}\n\tif ( !$.isEmptyObject( animations ) ) {\n\t\t// eslint-disable-next-line no-jquery/no-animate\n\t\t$container.stop( true ).animate( animations, config.duration === undefined ?\n\t\t\t'fast' : config.duration );\n\t\t$container.queue( function ( next ) {\n\t\t\tdeferred.resolve();\n\t\t\tnext();\n\t\t} );\n\t} else {\n\t\tdeferred.resolve();\n\t}\n\treturn deferred.promise();\n};\n\n/**\n * Force the browser to reconsider whether it really needs to render scrollbars inside the element\n * and reserve space for them, because it probably doesn't.\n *\n * Workaround primarily for <https://code.google.com/p/chromium/issues/detail?id=387290>, but also\n * similar bugs in other browsers. \"Just\" forcing a reflow is not sufficient in all cases, we need\n * to first actually detach (or hide, but detaching is simpler) all children, *then* force a\n * reflow, and then reattach (or show) them back.\n *\n * @static\n * @param {HTMLElement} el Element to reconsider the scrollbars on\n */\nOO.ui.Element.static.reconsiderScrollbars = function ( el ) {\n\tvar i, len, scrollLeft, scrollTop, nodes = [];\n\t// Save scroll position\n\tscrollLeft = el.scrollLeft;\n\tscrollTop = el.scrollTop;\n\t// Detach all children\n\twhile ( el.firstChild ) {\n\t\tnodes.push( el.firstChild );\n\t\tel.removeChild( el.firstChild );\n\t}\n\t// Force reflow\n\t// eslint-disable-next-line no-void\n\tvoid el.offsetHeight;\n\t// Reattach all children\n\tfor ( i = 0, len = nodes.length; i < len; i++ ) {\n\t\tel.appendChild( nodes[ i ] );\n\t}\n\t// Restore scroll position (no-op if scrollbars disappeared)\n\tel.scrollLeft = scrollLeft;\n\tel.scrollTop = scrollTop;\n};\n\n/* Methods */\n\n/**\n * Toggle visibility of an element.\n *\n * @param {boolean} [show] Make element visible, omit to toggle visibility\n * @fires visible\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.Element.prototype.toggle = function ( show ) {\n\tshow = show === undefined ? !this.visible : !!show;\n\n\tif ( show !== this.isVisible() ) {\n\t\tthis.visible = show;\n\t\tthis.$element.toggleClass( 'oo-ui-element-hidden', !this.visible );\n\t\tthis.emit( 'toggle', show );\n\t}\n\n\treturn this;\n};\n\n/**\n * Check if element is visible.\n *\n * @return {boolean} element is visible\n */\nOO.ui.Element.prototype.isVisible = function () {\n\treturn this.visible;\n};\n\n/**\n * Get element data.\n *\n * @return {Mixed} Element data\n */\nOO.ui.Element.prototype.getData = function () {\n\treturn this.data;\n};\n\n/**\n * Set element data.\n *\n * @param {Mixed} data Element data\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.Element.prototype.setData = function ( data ) {\n\tthis.data = data;\n\treturn this;\n};\n\n/**\n * Set the element has an 'id' attribute.\n *\n * @param {string} id\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.Element.prototype.setElementId = function ( id ) {\n\tthis.elementId = id;\n\tthis.$element.attr( 'id', id );\n\treturn this;\n};\n\n/**\n * Ensure that the element has an 'id' attribute, setting it to an unique value if it's missing,\n * and return its value.\n *\n * @return {string}\n */\nOO.ui.Element.prototype.getElementId = function () {\n\tif ( this.elementId === null ) {\n\t\tthis.setElementId( OO.ui.generateElementId() );\n\t}\n\treturn this.elementId;\n};\n\n/**\n * Check if element supports one or more methods.\n *\n * @param {string|string[]} methods Method or list of methods to check\n * @return {boolean} All methods are supported\n */\nOO.ui.Element.prototype.supports = function ( methods ) {\n\tvar i, len,\n\t\tsupport = 0;\n\n\tmethods = Array.isArray( methods ) ? methods : [ methods ];\n\tfor ( i = 0, len = methods.length; i < len; i++ ) {\n\t\tif ( typeof this[ methods[ i ] ] === 'function' ) {\n\t\t\tsupport++;\n\t\t}\n\t}\n\n\treturn methods.length === support;\n};\n\n/**\n * Update the theme-provided classes.\n *\n * @localdoc This is called in element mixins and widget classes any time state changes.\n *   Updating is debounced, minimizing overhead of changing multiple attributes and\n *   guaranteeing that theme updates do not occur within an element's constructor\n */\nOO.ui.Element.prototype.updateThemeClasses = function () {\n\tOO.ui.theme.queueUpdateElementClasses( this );\n};\n\n/**\n * Get the HTML tag name.\n *\n * Override this method to base the result on instance information.\n *\n * @return {string} HTML tag name\n */\nOO.ui.Element.prototype.getTagName = function () {\n\treturn this.constructor.static.tagName;\n};\n\n/**\n * Check if the element is attached to the DOM\n *\n * @return {boolean} The element is attached to the DOM\n */\nOO.ui.Element.prototype.isElementAttached = function () {\n\treturn $.contains( this.getElementDocument(), this.$element[ 0 ] );\n};\n\n/**\n * Get the DOM document.\n *\n * @return {HTMLDocument} Document object\n */\nOO.ui.Element.prototype.getElementDocument = function () {\n\t// Don't cache this in other ways either because subclasses could can change this.$element\n\treturn OO.ui.Element.static.getDocument( this.$element );\n};\n\n/**\n * Get the DOM window.\n *\n * @return {Window} Window object\n */\nOO.ui.Element.prototype.getElementWindow = function () {\n\treturn OO.ui.Element.static.getWindow( this.$element );\n};\n\n/**\n * Get closest scrollable container.\n *\n * @return {HTMLElement} Closest scrollable container\n */\nOO.ui.Element.prototype.getClosestScrollableElementContainer = function () {\n\treturn OO.ui.Element.static.getClosestScrollableContainer( this.$element[ 0 ] );\n};\n\n/**\n * Get group element is in.\n *\n * @return {OO.ui.mixin.GroupElement|null} Group element, null if none\n */\nOO.ui.Element.prototype.getElementGroup = function () {\n\treturn this.elementGroup;\n};\n\n/**\n * Set group element is in.\n *\n * @param {OO.ui.mixin.GroupElement|null} group Group element, null if none\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.Element.prototype.setElementGroup = function ( group ) {\n\tthis.elementGroup = group;\n\treturn this;\n};\n\n/**\n * Scroll element into view.\n *\n * @param {Object} [config] Configuration options\n * @return {jQuery.Promise} Promise which resolves when the scroll is complete\n */\nOO.ui.Element.prototype.scrollElementIntoView = function ( config ) {\n\tif (\n\t\t!this.isElementAttached() ||\n\t\t!this.isVisible() ||\n\t\t( this.getElementGroup() && !this.getElementGroup().isVisible() )\n\t) {\n\t\treturn $.Deferred().resolve();\n\t}\n\treturn OO.ui.Element.static.scrollIntoView( this.$element[ 0 ], config );\n};\n\n/**\n * Restore the pre-infusion dynamic state for this widget.\n *\n * This method is called after #$element has been inserted into DOM. The parameter is the return\n * value of #gatherPreInfuseState.\n *\n * @protected\n * @param {Object} state\n */\nOO.ui.Element.prototype.restorePreInfuseState = function () {\n};\n","/**\n * Wraps an HTML snippet for use with configuration values which default\n * to strings.  This bypasses the default html-escaping done to string\n * values.\n *\n * @class\n *\n * @constructor\n * @param {string} [content] HTML content\n */\nOO.ui.HtmlSnippet = function OoUiHtmlSnippet( content ) {\n\t// Properties\n\tthis.content = content;\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.HtmlSnippet );\n\n/* Methods */\n\n/**\n * Render into HTML.\n *\n * @return {string} Unchanged HTML snippet.\n */\nOO.ui.HtmlSnippet.prototype.toString = function () {\n\treturn this.content;\n};\n","/**\n * Layouts are containers for elements and are used to arrange other widgets of arbitrary type in\n * a way that is centrally controlled and can be updated dynamically. Layouts can be, and usually\n * are, combined.\n * See {@link OO.ui.FieldsetLayout FieldsetLayout}, {@link OO.ui.FieldLayout FieldLayout},\n * {@link OO.ui.FormLayout FormLayout}, {@link OO.ui.PanelLayout PanelLayout},\n * {@link OO.ui.StackLayout StackLayout}, {@link OO.ui.PageLayout PageLayout},\n * {@link OO.ui.HorizontalLayout HorizontalLayout}, and {@link OO.ui.BookletLayout BookletLayout}\n * for more information and examples.\n *\n * @abstract\n * @class\n * @extends OO.ui.Element\n * @mixins OO.EventEmitter\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.Layout = function OoUiLayout( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.Layout.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.EventEmitter.call( this );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-layout' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.Layout, OO.ui.Element );\nOO.mixinClass( OO.ui.Layout, OO.EventEmitter );\n\n/* Methods */\n\n/**\n * Reset scroll offsets\n *\n * @chainable\n * @return {OO.ui.Layout} The layout, for chaining\n */\nOO.ui.Layout.prototype.resetScroll = function () {\n\tthis.$element[ 0 ].scrollTop = 0;\n\t// TODO: Reset scrollLeft in an RTL-aware manner, see OO.ui.Element.static.getScrollLeft.\n\n\treturn this;\n};\n","/**\n * Widgets are compositions of one or more OOUI elements that users can both view\n * and interact with. All widgets can be configured and modified via a standard API,\n * and their state can change dynamically according to a model.\n *\n * @abstract\n * @class\n * @extends OO.ui.Element\n * @mixins OO.EventEmitter\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [disabled=false] Disable the widget. Disabled widgets cannot be used and their\n *  appearance reflects this state.\n */\nOO.ui.Widget = function OoUiWidget( config ) {\n\t// Initialize config\n\tconfig = $.extend( { disabled: false }, config );\n\n\t// Parent constructor\n\tOO.ui.Widget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.EventEmitter.call( this );\n\n\t// Properties\n\tthis.disabled = null;\n\tthis.wasDisabled = null;\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-widget' );\n\tthis.setDisabled( !!config.disabled );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.Widget, OO.ui.Element );\nOO.mixinClass( OO.ui.Widget, OO.EventEmitter );\n\n/* Events */\n\n/**\n * @event disable\n *\n * A 'disable' event is emitted when the disabled state of the widget changes\n * (i.e. on disable **and** enable).\n *\n * @param {boolean} disabled Widget is disabled\n */\n\n/**\n * @event toggle\n *\n * A 'toggle' event is emitted when the visibility of the widget changes.\n *\n * @param {boolean} visible Widget is visible\n */\n\n/* Methods */\n\n/**\n * Check if the widget is disabled.\n *\n * @return {boolean} Widget is disabled\n */\nOO.ui.Widget.prototype.isDisabled = function () {\n\treturn this.disabled;\n};\n\n/**\n * Set the 'disabled' state of the widget.\n *\n * When a widget is disabled, it cannot be used and its appearance is updated to reflect this state.\n *\n * @param {boolean} disabled Disable widget\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.Widget.prototype.setDisabled = function ( disabled ) {\n\tvar isDisabled;\n\n\tthis.disabled = !!disabled;\n\tisDisabled = this.isDisabled();\n\tif ( isDisabled !== this.wasDisabled ) {\n\t\tthis.$element.toggleClass( 'oo-ui-widget-disabled', isDisabled );\n\t\tthis.$element.toggleClass( 'oo-ui-widget-enabled', !isDisabled );\n\t\tthis.$element.attr( 'aria-disabled', isDisabled.toString() );\n\t\tthis.emit( 'disable', isDisabled );\n\t\tthis.updateThemeClasses();\n\t}\n\tthis.wasDisabled = isDisabled;\n\n\treturn this;\n};\n\n/**\n * Update the disabled state, in case of changes in parent widget.\n *\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.Widget.prototype.updateDisabled = function () {\n\tthis.setDisabled( this.disabled );\n\treturn this;\n};\n\n/**\n * Get an ID of a labelable node which is part of this widget, if any, to be used for `<label for>`\n * value.\n *\n * If this function returns null, the widget should have a meaningful #simulateLabelClick method\n * instead.\n *\n * @return {string|null} The ID of the labelable element\n */\nOO.ui.Widget.prototype.getInputId = function () {\n\treturn null;\n};\n\n/**\n * Simulate the behavior of clicking on a label (a HTML `<label>` element) bound to this input.\n * HTML only allows `<label>` to act on specific \"labelable\" elements; complex widgets might need to\n * override this method to provide intuitive, accessible behavior.\n *\n * By default, this does nothing. OO.ui.mixin.TabIndexedElement overrides it for focusable widgets.\n * Individual widgets may override it too.\n *\n * This method is called by OO.ui.LabelWidget and OO.ui.FieldLayout. It should not be called\n * directly.\n */\nOO.ui.Widget.prototype.simulateLabelClick = function () {\n};\n","/**\n * Theme logic.\n *\n * @abstract\n * @class\n *\n * @constructor\n */\nOO.ui.Theme = function OoUiTheme() {\n\tthis.elementClassesQueue = [];\n\tthis.debouncedUpdateQueuedElementClasses = OO.ui.debounce( this.updateQueuedElementClasses );\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.Theme );\n\n/* Methods */\n\n/**\n * Get a list of classes to be applied to a widget.\n *\n * The 'on' and 'off' lists combined MUST contain keys for all classes the theme adds or removes,\n * otherwise state transitions will not work properly.\n *\n * @param {OO.ui.Element} element Element for which to get classes\n * @return {Object.<string,string[]>} Categorized class names with `on` and `off` lists\n */\nOO.ui.Theme.prototype.getElementClasses = function () {\n\treturn { on: [], off: [] };\n};\n\n/**\n * Update CSS classes provided by the theme.\n *\n * For elements with theme logic hooks, this should be called any time there's a state change.\n *\n * @param {OO.ui.Element} element Element for which to update classes\n */\nOO.ui.Theme.prototype.updateElementClasses = function ( element ) {\n\tvar $elements = $( [] ),\n\t\tclasses = this.getElementClasses( element );\n\n\tif ( element.$icon ) {\n\t\t$elements = $elements.add( element.$icon );\n\t}\n\tif ( element.$indicator ) {\n\t\t$elements = $elements.add( element.$indicator );\n\t}\n\n\t$elements\n\t\t.removeClass( classes.off )\n\t\t.addClass( classes.on );\n};\n\n/**\n * @private\n */\nOO.ui.Theme.prototype.updateQueuedElementClasses = function () {\n\tvar i;\n\tfor ( i = 0; i < this.elementClassesQueue.length; i++ ) {\n\t\tthis.updateElementClasses( this.elementClassesQueue[ i ] );\n\t}\n\t// Clear the queue\n\tthis.elementClassesQueue = [];\n};\n\n/**\n * Queue #updateElementClasses to be called for this element.\n *\n * @localdoc QUnit tests override this method to directly call #queueUpdateElementClasses,\n *   to make them synchronous.\n *\n * @param {OO.ui.Element} element Element for which to update classes\n */\nOO.ui.Theme.prototype.queueUpdateElementClasses = function ( element ) {\n\t// Keep items in the queue unique. Use lastIndexOf to start checking from the end because that's\n\t// the most common case (this method is often called repeatedly for the same element).\n\tif ( this.elementClassesQueue.lastIndexOf( element ) !== -1 ) {\n\t\treturn;\n\t}\n\tthis.elementClassesQueue.push( element );\n\tthis.debouncedUpdateQueuedElementClasses();\n};\n\n/**\n * Get the transition duration in milliseconds for dialogs opening/closing\n *\n * The dialog should be fully rendered this many milliseconds after the\n * ready process has executed.\n *\n * @return {number} Transition duration in milliseconds\n */\nOO.ui.Theme.prototype.getDialogTransitionDuration = function () {\n\treturn 0;\n};\n","/**\n * The TabIndexedElement class is an attribute mixin used to add additional functionality to an\n * element created by another class. The mixin provides a ‘tabIndex’ property, which specifies the\n * order in which users will navigate through the focusable elements via the Tab key.\n *\n *     @example\n *     // TabIndexedElement is mixed into the ButtonWidget class\n *     // to provide a tabIndex property.\n *     var button1 = new OO.ui.ButtonWidget( {\n *             label: 'fourth',\n *             tabIndex: 4\n *         } ),\n *         button2 = new OO.ui.ButtonWidget( {\n *             label: 'second',\n *             tabIndex: 2\n *         } ),\n *         button3 = new OO.ui.ButtonWidget( {\n *             label: 'third',\n *             tabIndex: 3\n *         } ),\n *         button4 = new OO.ui.ButtonWidget( {\n *             label: 'first',\n *             tabIndex: 1\n *         } );\n *     $( document.body ).append(\n *         button1.$element,\n *         button2.$element,\n *         button3.$element,\n *         button4.$element\n *      );\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$tabIndexed] The element that should use the tabindex functionality. By default,\n *  the functionality is applied to the element created by the class ($element). If a different\n *  element is specified, the tabindex functionality will be applied to it instead.\n * @cfg {string|number|null} [tabIndex=0] Number that specifies the element’s position in the\n *  tab-navigation order (e.g., 1 for the first focusable element). Use 0 to use the default\n *  navigation order; use -1 to remove the element from the tab-navigation flow.\n */\nOO.ui.mixin.TabIndexedElement = function OoUiMixinTabIndexedElement( config ) {\n\t// Configuration initialization\n\tconfig = $.extend( { tabIndex: 0 }, config );\n\n\t// Properties\n\tthis.$tabIndexed = null;\n\tthis.tabIndex = null;\n\n\t// Events\n\tthis.connect( this, {\n\t\tdisable: 'onTabIndexedElementDisable'\n\t} );\n\n\t// Initialization\n\tthis.setTabIndex( config.tabIndex );\n\tthis.setTabIndexedElement( config.$tabIndexed || this.$element );\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.mixin.TabIndexedElement );\n\n/* Methods */\n\n/**\n * Set the element that should use the tabindex functionality.\n *\n * This method is used to retarget a tabindex mixin so that its functionality applies\n * to the specified element. If an element is currently using the functionality, the mixin’s\n * effect on that element is removed before the new element is set up.\n *\n * @param {jQuery} $tabIndexed Element that should use the tabindex functionality\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.TabIndexedElement.prototype.setTabIndexedElement = function ( $tabIndexed ) {\n\tvar tabIndex = this.tabIndex;\n\t// Remove attributes from old $tabIndexed\n\tthis.setTabIndex( null );\n\t// Force update of new $tabIndexed\n\tthis.$tabIndexed = $tabIndexed;\n\tthis.tabIndex = tabIndex;\n\treturn this.updateTabIndex();\n};\n\n/**\n * Set the value of the tabindex.\n *\n * @param {string|number|null} tabIndex Tabindex value, or `null` for no tabindex\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.TabIndexedElement.prototype.setTabIndex = function ( tabIndex ) {\n\ttabIndex = /^-?\\d+$/.test( tabIndex ) ? Number( tabIndex ) : null;\n\n\tif ( this.tabIndex !== tabIndex ) {\n\t\tthis.tabIndex = tabIndex;\n\t\tthis.updateTabIndex();\n\t}\n\n\treturn this;\n};\n\n/**\n * Update the `tabindex` attribute, in case of changes to tab index or\n * disabled state.\n *\n * @private\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.TabIndexedElement.prototype.updateTabIndex = function () {\n\tif ( this.$tabIndexed ) {\n\t\tif ( this.tabIndex !== null ) {\n\t\t\t// Do not index over disabled elements\n\t\t\tthis.$tabIndexed.attr( {\n\t\t\t\ttabindex: this.isDisabled() ? -1 : this.tabIndex,\n\t\t\t\t// Support: ChromeVox and NVDA\n\t\t\t\t// These do not seem to inherit aria-disabled from parent elements\n\t\t\t\t'aria-disabled': this.isDisabled().toString()\n\t\t\t} );\n\t\t} else {\n\t\t\tthis.$tabIndexed.removeAttr( 'tabindex aria-disabled' );\n\t\t}\n\t}\n\treturn this;\n};\n\n/**\n * Handle disable events.\n *\n * @private\n * @param {boolean} disabled Element is disabled\n */\nOO.ui.mixin.TabIndexedElement.prototype.onTabIndexedElementDisable = function () {\n\tthis.updateTabIndex();\n};\n\n/**\n * Get the value of the tabindex.\n *\n * @return {number|null} Tabindex value\n */\nOO.ui.mixin.TabIndexedElement.prototype.getTabIndex = function () {\n\treturn this.tabIndex;\n};\n\n/**\n * Get an ID of a focusable element of this widget, if any, to be used for `<label for>` value.\n *\n * If the element already has an ID then that is returned, otherwise unique ID is\n * generated, set on the element, and returned.\n *\n * @return {string|null} The ID of the focusable element\n */\nOO.ui.mixin.TabIndexedElement.prototype.getInputId = function () {\n\tvar id;\n\n\tif ( !this.$tabIndexed ) {\n\t\treturn null;\n\t}\n\tif ( !this.isLabelableNode( this.$tabIndexed ) ) {\n\t\treturn null;\n\t}\n\n\tid = this.$tabIndexed.attr( 'id' );\n\tif ( id === undefined ) {\n\t\tid = OO.ui.generateElementId();\n\t\tthis.$tabIndexed.attr( 'id', id );\n\t}\n\n\treturn id;\n};\n\n/**\n * Whether the node is 'labelable' according to the HTML spec\n * (i.e., whether it can be interacted with through a `<label for=\"…\">`).\n * See: <https://html.spec.whatwg.org/multipage/forms.html#category-label>.\n *\n * @private\n * @param {jQuery} $node\n * @return {boolean}\n */\nOO.ui.mixin.TabIndexedElement.prototype.isLabelableNode = function ( $node ) {\n\tvar\n\t\tlabelableTags = [ 'button', 'meter', 'output', 'progress', 'select', 'textarea' ],\n\t\ttagName = $node.prop( 'tagName' ).toLowerCase();\n\n\tif ( tagName === 'input' && $node.attr( 'type' ) !== 'hidden' ) {\n\t\treturn true;\n\t}\n\tif ( labelableTags.indexOf( tagName ) !== -1 ) {\n\t\treturn true;\n\t}\n\treturn false;\n};\n\n/**\n * Focus this element.\n *\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.TabIndexedElement.prototype.focus = function () {\n\tif ( !this.isDisabled() ) {\n\t\tthis.$tabIndexed.trigger( 'focus' );\n\t}\n\treturn this;\n};\n\n/**\n * Blur this element.\n *\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.TabIndexedElement.prototype.blur = function () {\n\tthis.$tabIndexed.trigger( 'blur' );\n\treturn this;\n};\n\n/**\n * @inheritdoc OO.ui.Widget\n */\nOO.ui.mixin.TabIndexedElement.prototype.simulateLabelClick = function () {\n\tthis.focus();\n};\n","/**\n * ButtonElement is often mixed into other classes to generate a button, which is a clickable\n * interface element that can be configured with access keys for keyboard interaction.\n * See the [OOUI documentation on MediaWiki] [1] for examples.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Buttons_and_Switches#Buttons\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$button] The button element created by the class.\n *  If this configuration is omitted, the button element will use a generated `<a>`.\n * @cfg {boolean} [framed=true] Render the button with a frame\n */\nOO.ui.mixin.ButtonElement = function OoUiMixinButtonElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.$button = null;\n\tthis.framed = null;\n\tthis.active = config.active !== undefined && config.active;\n\tthis.onDocumentMouseUpHandler = this.onDocumentMouseUp.bind( this );\n\tthis.onMouseDownHandler = this.onMouseDown.bind( this );\n\tthis.onDocumentKeyUpHandler = this.onDocumentKeyUp.bind( this );\n\tthis.onKeyDownHandler = this.onKeyDown.bind( this );\n\tthis.onClickHandler = this.onClick.bind( this );\n\tthis.onKeyPressHandler = this.onKeyPress.bind( this );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-buttonElement' );\n\tthis.toggleFramed( config.framed === undefined || config.framed );\n\tthis.setButtonElement( config.$button || $( '<a>' ) );\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.mixin.ButtonElement );\n\n/* Static Properties */\n\n/**\n * Cancel mouse down events.\n *\n * This property is usually set to `true` to prevent the focus from changing when the button is\n * clicked.\n * Classes such as {@link OO.ui.mixin.DraggableElement DraggableElement} and\n * {@link OO.ui.ButtonOptionWidget ButtonOptionWidget} use a value of `false` so that dragging\n * behavior is possible and mousedown events can be handled by a parent widget.\n *\n * @static\n * @inheritable\n * @property {boolean}\n */\nOO.ui.mixin.ButtonElement.static.cancelButtonMouseDownEvents = true;\n\n/* Events */\n\n/**\n * A 'click' event is emitted when the button element is clicked.\n *\n * @event click\n */\n\n/* Methods */\n\n/**\n * Set the button element.\n *\n * This method is used to retarget a button mixin so that its functionality applies to\n * the specified button element instead of the one created by the class. If a button element\n * is already set, the method will remove the mixin’s effect on that element.\n *\n * @param {jQuery} $button Element to use as button\n */\nOO.ui.mixin.ButtonElement.prototype.setButtonElement = function ( $button ) {\n\tif ( this.$button ) {\n\t\tthis.$button\n\t\t\t.removeClass( 'oo-ui-buttonElement-button' )\n\t\t\t.removeAttr( 'role accesskey' )\n\t\t\t.off( {\n\t\t\t\tmousedown: this.onMouseDownHandler,\n\t\t\t\tkeydown: this.onKeyDownHandler,\n\t\t\t\tclick: this.onClickHandler,\n\t\t\t\tkeypress: this.onKeyPressHandler\n\t\t\t} );\n\t}\n\n\tthis.$button = $button\n\t\t.addClass( 'oo-ui-buttonElement-button' )\n\t\t.on( {\n\t\t\tmousedown: this.onMouseDownHandler,\n\t\t\tkeydown: this.onKeyDownHandler,\n\t\t\tclick: this.onClickHandler,\n\t\t\tkeypress: this.onKeyPressHandler\n\t\t} );\n\n\t// Add `role=\"button\"` on `<a>` elements, where it's needed\n\t// `toUpperCase()` is added for XHTML documents\n\tif ( this.$button.prop( 'tagName' ).toUpperCase() === 'A' ) {\n\t\tthis.$button.attr( 'role', 'button' );\n\t}\n};\n\n/**\n * Handles mouse down events.\n *\n * @protected\n * @param {jQuery.Event} e Mouse down event\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.mixin.ButtonElement.prototype.onMouseDown = function ( e ) {\n\tif ( this.isDisabled() || e.which !== OO.ui.MouseButtons.LEFT ) {\n\t\treturn;\n\t}\n\tthis.$element.addClass( 'oo-ui-buttonElement-pressed' );\n\t// Run the mouseup handler no matter where the mouse is when the button is let go, so we can\n\t// reliably remove the pressed class\n\tthis.getElementDocument().addEventListener( 'mouseup', this.onDocumentMouseUpHandler, true );\n\t// Prevent change of focus unless specifically configured otherwise\n\tif ( this.constructor.static.cancelButtonMouseDownEvents ) {\n\t\treturn false;\n\t}\n};\n\n/**\n * Handles document mouse up events.\n *\n * @protected\n * @param {MouseEvent} e Mouse up event\n */\nOO.ui.mixin.ButtonElement.prototype.onDocumentMouseUp = function ( e ) {\n\tif ( this.isDisabled() || e.which !== OO.ui.MouseButtons.LEFT ) {\n\t\treturn;\n\t}\n\tthis.$element.removeClass( 'oo-ui-buttonElement-pressed' );\n\t// Stop listening for mouseup, since we only needed this once\n\tthis.getElementDocument().removeEventListener( 'mouseup', this.onDocumentMouseUpHandler, true );\n};\n\n/**\n * Handles mouse click events.\n *\n * @protected\n * @param {jQuery.Event} e Mouse click event\n * @fires click\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.mixin.ButtonElement.prototype.onClick = function ( e ) {\n\tif ( !this.isDisabled() && e.which === OO.ui.MouseButtons.LEFT ) {\n\t\tif ( this.emit( 'click' ) ) {\n\t\t\treturn false;\n\t\t}\n\t}\n};\n\n/**\n * Handles key down events.\n *\n * @protected\n * @param {jQuery.Event} e Key down event\n */\nOO.ui.mixin.ButtonElement.prototype.onKeyDown = function ( e ) {\n\tif ( this.isDisabled() || ( e.which !== OO.ui.Keys.SPACE && e.which !== OO.ui.Keys.ENTER ) ) {\n\t\treturn;\n\t}\n\tthis.$element.addClass( 'oo-ui-buttonElement-pressed' );\n\t// Run the keyup handler no matter where the key is when the button is let go, so we can\n\t// reliably remove the pressed class\n\tthis.getElementDocument().addEventListener( 'keyup', this.onDocumentKeyUpHandler, true );\n};\n\n/**\n * Handles document key up events.\n *\n * @protected\n * @param {KeyboardEvent} e Key up event\n */\nOO.ui.mixin.ButtonElement.prototype.onDocumentKeyUp = function ( e ) {\n\tif ( this.isDisabled() || ( e.which !== OO.ui.Keys.SPACE && e.which !== OO.ui.Keys.ENTER ) ) {\n\t\treturn;\n\t}\n\tthis.$element.removeClass( 'oo-ui-buttonElement-pressed' );\n\t// Stop listening for keyup, since we only needed this once\n\tthis.getElementDocument().removeEventListener( 'keyup', this.onDocumentKeyUpHandler, true );\n};\n\n/**\n * Handles key press events.\n *\n * @protected\n * @param {jQuery.Event} e Key press event\n * @fires click\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.mixin.ButtonElement.prototype.onKeyPress = function ( e ) {\n\tif ( !this.isDisabled() && ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER ) ) {\n\t\tif ( this.emit( 'click' ) ) {\n\t\t\treturn false;\n\t\t}\n\t}\n};\n\n/**\n * Check if button has a frame.\n *\n * @return {boolean} Button is framed\n */\nOO.ui.mixin.ButtonElement.prototype.isFramed = function () {\n\treturn this.framed;\n};\n\n/**\n * Render the button with or without a frame. Omit the `framed` parameter to toggle the button frame\n * on and off.\n *\n * @param {boolean} [framed] Make button framed, omit to toggle\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.ButtonElement.prototype.toggleFramed = function ( framed ) {\n\tframed = framed === undefined ? !this.framed : !!framed;\n\tif ( framed !== this.framed ) {\n\t\tthis.framed = framed;\n\t\tthis.$element\n\t\t\t.toggleClass( 'oo-ui-buttonElement-frameless', !framed )\n\t\t\t.toggleClass( 'oo-ui-buttonElement-framed', framed );\n\t\tthis.updateThemeClasses();\n\t}\n\n\treturn this;\n};\n\n/**\n * Set the button's active state.\n *\n * The active state can be set on:\n *\n *  - {@link OO.ui.ButtonOptionWidget ButtonOptionWidget} when it is selected\n *  - {@link OO.ui.ToggleButtonWidget ToggleButtonWidget} when it is toggle on\n *  - {@link OO.ui.ButtonWidget ButtonWidget} when clicking the button would only refresh the page\n *\n * @protected\n * @param {boolean} value Make button active\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.ButtonElement.prototype.setActive = function ( value ) {\n\tthis.active = !!value;\n\tthis.$element.toggleClass( 'oo-ui-buttonElement-active', this.active );\n\tthis.updateThemeClasses();\n\treturn this;\n};\n\n/**\n * Check if the button is active\n *\n * @protected\n * @return {boolean} The button is active\n */\nOO.ui.mixin.ButtonElement.prototype.isActive = function () {\n\treturn this.active;\n};\n","/**\n * Any OOUI widget that contains other widgets (such as {@link OO.ui.ButtonWidget buttons} or\n * {@link OO.ui.OptionWidget options}) mixes in GroupElement. Adding, removing, and clearing\n * items from the group is done through the interface the class provides.\n * For more information, please see the [OOUI documentation on MediaWiki] [1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Elements/Groups\n *\n * @abstract\n * @mixins OO.EmitterList\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$group] The container element created by the class. If this configuration\n *  is omitted, the group element will use a generated `<div>`.\n */\nOO.ui.mixin.GroupElement = function OoUiMixinGroupElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Mixin constructors\n\tOO.EmitterList.call( this, config );\n\n\t// Properties\n\tthis.$group = null;\n\n\t// Initialization\n\tthis.setGroupElement( config.$group || $( '<div>' ) );\n};\n\n/* Setup */\n\nOO.mixinClass( OO.ui.mixin.GroupElement, OO.EmitterList );\n\n/* Events */\n\n/**\n * @event change\n *\n * A change event is emitted when the set of selected items changes.\n *\n * @param {OO.ui.Element[]} items Items currently in the group\n */\n\n/* Methods */\n\n/**\n * Set the group element.\n *\n * If an element is already set, items will be moved to the new element.\n *\n * @param {jQuery} $group Element to use as group\n */\nOO.ui.mixin.GroupElement.prototype.setGroupElement = function ( $group ) {\n\tvar i, len;\n\n\tthis.$group = $group;\n\tfor ( i = 0, len = this.items.length; i < len; i++ ) {\n\t\tthis.$group.append( this.items[ i ].$element );\n\t}\n};\n\n/**\n * Find an item by its data.\n *\n * Only the first item with matching data will be returned. To return all matching items,\n * use the #findItemsFromData method.\n *\n * @param {Object} data Item data to search for\n * @return {OO.ui.Element|null} Item with equivalent data, `null` if none exists\n */\nOO.ui.mixin.GroupElement.prototype.findItemFromData = function ( data ) {\n\tvar i, len, item,\n\t\thash = OO.getHash( data );\n\n\tfor ( i = 0, len = this.items.length; i < len; i++ ) {\n\t\titem = this.items[ i ];\n\t\tif ( hash === OO.getHash( item.getData() ) ) {\n\t\t\treturn item;\n\t\t}\n\t}\n\n\treturn null;\n};\n\n/**\n * Find items by their data.\n *\n * All items with matching data will be returned. To return only the first match, use the\n * #findItemFromData method instead.\n *\n * @param {Object} data Item data to search for\n * @return {OO.ui.Element[]} Items with equivalent data\n */\nOO.ui.mixin.GroupElement.prototype.findItemsFromData = function ( data ) {\n\tvar i, len, item,\n\t\thash = OO.getHash( data ),\n\t\titems = [];\n\n\tfor ( i = 0, len = this.items.length; i < len; i++ ) {\n\t\titem = this.items[ i ];\n\t\tif ( hash === OO.getHash( item.getData() ) ) {\n\t\t\titems.push( item );\n\t\t}\n\t}\n\n\treturn items;\n};\n\n/**\n * Add items to the group.\n *\n * Items will be added to the end of the group array unless the optional `index` parameter\n * specifies a different insertion point. Adding an existing item will move it to the end of the\n * array or the point specified by the `index`.\n *\n * @param {OO.ui.Element[]} items An array of items to add to the group\n * @param {number} [index] Index of the insertion point\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.GroupElement.prototype.addItems = function ( items, index ) {\n\n\tif ( items.length === 0 ) {\n\t\treturn this;\n\t}\n\n\t// Mixin method\n\tOO.EmitterList.prototype.addItems.call( this, items, index );\n\n\tthis.emit( 'change', this.getItems() );\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.mixin.GroupElement.prototype.moveItem = function ( items, newIndex ) {\n\t// insertItemElements expects this.items to not have been modified yet, so call before the mixin\n\tthis.insertItemElements( items, newIndex );\n\n\t// Mixin method\n\tnewIndex = OO.EmitterList.prototype.moveItem.call( this, items, newIndex );\n\n\treturn newIndex;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.mixin.GroupElement.prototype.insertItem = function ( item, index ) {\n\titem.setElementGroup( this );\n\tthis.insertItemElements( item, index );\n\n\t// Mixin method\n\tindex = OO.EmitterList.prototype.insertItem.call( this, item, index );\n\n\treturn index;\n};\n\n/**\n * Insert elements into the group\n *\n * @private\n * @param {OO.ui.Element} itemWidget Item to insert\n * @param {number} index Insertion index\n */\nOO.ui.mixin.GroupElement.prototype.insertItemElements = function ( itemWidget, index ) {\n\tif ( index === undefined || index < 0 || index >= this.items.length ) {\n\t\tthis.$group.append( itemWidget.$element );\n\t} else if ( index === 0 ) {\n\t\tthis.$group.prepend( itemWidget.$element );\n\t} else {\n\t\tthis.items[ index ].$element.before( itemWidget.$element );\n\t}\n};\n\n/**\n * Remove the specified items from a group.\n *\n * Removed items are detached (not removed) from the DOM so that they may be reused.\n * To remove all items from a group, you may wish to use the #clearItems method instead.\n *\n * @param {OO.ui.Element[]} items An array of items to remove\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.GroupElement.prototype.removeItems = function ( items ) {\n\tvar i, len, item, index;\n\n\tif ( items.length === 0 ) {\n\t\treturn this;\n\t}\n\n\t// Remove specific items elements\n\tfor ( i = 0, len = items.length; i < len; i++ ) {\n\t\titem = items[ i ];\n\t\tindex = this.items.indexOf( item );\n\t\tif ( index !== -1 ) {\n\t\t\titem.setElementGroup( null );\n\t\t\titem.$element.detach();\n\t\t}\n\t}\n\n\t// Mixin method\n\tOO.EmitterList.prototype.removeItems.call( this, items );\n\n\tthis.emit( 'change', this.getItems() );\n\treturn this;\n};\n\n/**\n * Clear all items from the group.\n *\n * Cleared items are detached from the DOM, not removed, so that they may be reused.\n * To remove only a subset of items from a group, use the #removeItems method.\n *\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.GroupElement.prototype.clearItems = function () {\n\tvar i, len;\n\n\t// Remove all item elements\n\tfor ( i = 0, len = this.items.length; i < len; i++ ) {\n\t\tthis.items[ i ].setElementGroup( null );\n\t\tthis.items[ i ].$element.detach();\n\t}\n\n\t// Mixin method\n\tOO.EmitterList.prototype.clearItems.call( this );\n\n\tthis.emit( 'change', this.getItems() );\n\treturn this;\n};\n","/**\n * LabelElement is often mixed into other classes to generate a label, which\n * helps identify the function of an interface element.\n * See the [OOUI documentation on MediaWiki] [1] for more information.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Icons,_Indicators,_and_Labels#Labels\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$label] The label element created by the class. If this\n *  configuration is omitted, the label element will use a generated `<span>`.\n * @cfg {jQuery|string|Function|OO.ui.HtmlSnippet} [label] The label text. The label can be\n *  specified as a plaintext string, a jQuery selection of elements, or a function that will\n *  produce a string in the future. See the [OOUI documentation on MediaWiki] [2] for examples.\n *  [2]: https://www.mediawiki.org/wiki/OOUI/Widgets/Icons,_Indicators,_and_Labels#Labels\n * @cfg {boolean} [invisibleLabel] Whether the label should be visually hidden (but still\n *  accessible to screen-readers).\n */\nOO.ui.mixin.LabelElement = function OoUiMixinLabelElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.$label = null;\n\tthis.label = null;\n\tthis.invisibleLabel = null;\n\n\t// Initialization\n\tthis.setLabel( config.label || this.constructor.static.label );\n\tthis.setLabelElement( config.$label || $( '<span>' ) );\n\tthis.setInvisibleLabel( config.invisibleLabel );\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.mixin.LabelElement );\n\n/* Events */\n\n/**\n * @event labelChange\n * @param {string} value\n */\n\n/* Static Properties */\n\n/**\n * The label text. The label can be specified as a plaintext string, a function that will\n * produce a string in the future, or `null` for no label. The static value will\n * be overridden if a label is specified with the #label config option.\n *\n * @static\n * @inheritable\n * @property {string|Function|null}\n */\nOO.ui.mixin.LabelElement.static.label = null;\n\n/* Static methods */\n\n/**\n * Highlight the first occurrence of the query in the given text\n *\n * @param {string} text Text\n * @param {string} query Query to find\n * @param {Function} [compare] Optional string comparator, e.g. Intl.Collator().compare\n * @return {jQuery} Text with the first match of the query\n *  sub-string wrapped in highlighted span\n */\nOO.ui.mixin.LabelElement.static.highlightQuery = function ( text, query, compare ) {\n\tvar i, tLen, qLen,\n\t\toffset = -1,\n\t\t$result = $( '<span>' );\n\n\tif ( compare ) {\n\t\ttLen = text.length;\n\t\tqLen = query.length;\n\t\tfor ( i = 0; offset === -1 && i <= tLen - qLen; i++ ) {\n\t\t\tif ( compare( query, text.slice( i, i + qLen ) ) === 0 ) {\n\t\t\t\toffset = i;\n\t\t\t}\n\t\t}\n\t} else {\n\t\toffset = text.toLowerCase().indexOf( query.toLowerCase() );\n\t}\n\n\tif ( !query.length || offset === -1 ) {\n\t\t$result.text( text );\n\t} else {\n\t\t$result.append(\n\t\t\tdocument.createTextNode( text.slice( 0, offset ) ),\n\t\t\t$( '<span>' )\n\t\t\t\t.addClass( 'oo-ui-labelElement-label-highlight' )\n\t\t\t\t.text( text.slice( offset, offset + query.length ) ),\n\t\t\tdocument.createTextNode( text.slice( offset + query.length ) )\n\t\t);\n\t}\n\treturn $result.contents();\n};\n\n/* Methods */\n\n/**\n * Set the label element.\n *\n * If an element is already set, it will be cleaned up before setting up the new element.\n *\n * @param {jQuery} $label Element to use as label\n */\nOO.ui.mixin.LabelElement.prototype.setLabelElement = function ( $label ) {\n\tif ( this.$label ) {\n\t\tthis.$label.removeClass( 'oo-ui-labelElement-label' ).empty();\n\t}\n\n\tthis.$label = $label.addClass( 'oo-ui-labelElement-label' );\n\tthis.setLabelContent( this.label );\n};\n\n/**\n * Set the label.\n *\n * An empty string will result in the label being hidden. A string containing only whitespace will\n * be converted to a single `&nbsp;`.\n *\n * @param {jQuery|string|OO.ui.HtmlSnippet|Function|null} label Label nodes; text; a function that\n *  returns nodes or text; or null for no label\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.LabelElement.prototype.setLabel = function ( label ) {\n\tlabel = typeof label === 'function' ? OO.ui.resolveMsg( label ) : label;\n\tlabel = ( ( typeof label === 'string' || label instanceof $ ) && label.length ) || ( label instanceof OO.ui.HtmlSnippet && label.toString().length ) ? label : null;\n\n\tif ( this.label !== label ) {\n\t\tif ( this.$label ) {\n\t\t\tthis.setLabelContent( label );\n\t\t}\n\t\tthis.label = label;\n\t\tthis.emit( 'labelChange' );\n\t}\n\n\tthis.$element.toggleClass( 'oo-ui-labelElement', !!this.label && !this.invisibleLabel );\n\n\treturn this;\n};\n\n/**\n * Set whether the label should be visually hidden (but still accessible to screen-readers).\n *\n * @param {boolean} invisibleLabel\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.LabelElement.prototype.setInvisibleLabel = function ( invisibleLabel ) {\n\tinvisibleLabel = !!invisibleLabel;\n\n\tif ( this.invisibleLabel !== invisibleLabel ) {\n\t\tthis.invisibleLabel = invisibleLabel;\n\t\tthis.emit( 'labelChange' );\n\t}\n\n\tthis.$label.toggleClass( 'oo-ui-labelElement-invisible', this.invisibleLabel );\n\t// Pretend that there is no label, a lot of CSS has been written with this assumption\n\tthis.$element.toggleClass( 'oo-ui-labelElement', !!this.label && !this.invisibleLabel );\n\n\treturn this;\n};\n\n/**\n * Set the label as plain text with a highlighted query\n *\n * @param {string} text Text label to set\n * @param {string} query Substring of text to highlight\n * @param {Function} [compare] Optional string comparator, e.g. Intl.Collator().compare\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.LabelElement.prototype.setHighlightedQuery = function ( text, query, compare ) {\n\treturn this.setLabel( this.constructor.static.highlightQuery( text, query, compare ) );\n};\n\n/**\n * Get the label.\n *\n * @return {jQuery|string|Function|null} Label nodes; text; a function that returns nodes or\n *  text; or null for no label\n */\nOO.ui.mixin.LabelElement.prototype.getLabel = function () {\n\treturn this.label;\n};\n\n/**\n * Set the content of the label.\n *\n * Do not call this method until after the label element has been set by #setLabelElement.\n *\n * @private\n * @param {jQuery|string|Function|null} label Label nodes; text; a function that returns nodes or\n *  text; or null for no label\n */\nOO.ui.mixin.LabelElement.prototype.setLabelContent = function ( label ) {\n\tif ( typeof label === 'string' ) {\n\t\tif ( label.match( /^\\s*$/ ) ) {\n\t\t\t// Convert whitespace only string to a single non-breaking space\n\t\t\tthis.$label.html( '&nbsp;' );\n\t\t} else {\n\t\t\tthis.$label.text( label );\n\t\t}\n\t} else if ( label instanceof OO.ui.HtmlSnippet ) {\n\t\tthis.$label.html( label.toString() );\n\t} else if ( label instanceof $ ) {\n\t\tthis.$label.empty().append( label );\n\t} else {\n\t\tthis.$label.empty();\n\t}\n};\n","/**\n * IconElement is often mixed into other classes to generate an icon.\n * Icons are graphics, about the size of normal text. They are used to aid the user\n * in locating a control or to convey information in a space-efficient way. See the\n * [OOUI documentation on MediaWiki] [1] for a list of icons\n * included in the library.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Icons,_Indicators,_and_Labels#Icons\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$icon] The icon element created by the class. If this configuration is omitted,\n *  the icon element will use a generated `<span>`. To use a different HTML tag, or to specify that\n *  the icon element be set to an existing icon instead of the one generated by this class, set a\n *  value using a jQuery selection. For example:\n *\n *      // Use a <div> tag instead of a <span>\n *     $icon: $( '<div>' )\n *     // Use an existing icon element instead of the one generated by the class\n *     $icon: this.$element\n *     // Use an icon element from a child widget\n *     $icon: this.childwidget.$element\n * @cfg {Object|string} [icon=''] The symbolic name of the icon (e.g., ‘remove’ or ‘menu’), or a\n *  map of symbolic names. A map is used for i18n purposes and contains a `default` icon\n *  name and additional names keyed by language code. The `default` name is used when no icon is\n *  keyed by the user's language.\n *\n *  Example of an i18n map:\n *\n *     { default: 'bold-a', en: 'bold-b', de: 'bold-f' }\n *  See the [OOUI documentation on MediaWiki] [2] for a list of icons included in the library.\n * [2]: https://www.mediawiki.org/wiki/OOUI/Widgets/Icons,_Indicators,_and_Labels#Icons\n */\nOO.ui.mixin.IconElement = function OoUiMixinIconElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.$icon = null;\n\tthis.icon = null;\n\n\t// Initialization\n\tthis.setIcon( config.icon || this.constructor.static.icon );\n\tthis.setIconElement( config.$icon || $( '<span>' ) );\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.mixin.IconElement );\n\n/* Static Properties */\n\n/**\n * The symbolic name of the icon (e.g., ‘remove’ or ‘menu’), or a map of symbolic names. A map\n * is used for i18n purposes and contains a `default` icon name and additional names keyed by\n * language code. The `default` name is used when no icon is keyed by the user's language.\n *\n * Example of an i18n map:\n *\n *     { default: 'bold-a', en: 'bold-b', de: 'bold-f' }\n *\n * Note: the static property will be overridden if the #icon configuration is used.\n *\n * @static\n * @inheritable\n * @property {Object|string}\n */\nOO.ui.mixin.IconElement.static.icon = null;\n\n/**\n * The icon title, displayed when users move the mouse over the icon. The value can be text, a\n * function that returns title text, or `null` for no title.\n *\n * The static property will be overridden if the #iconTitle configuration is used.\n *\n * @static\n * @inheritable\n * @property {string|Function|null}\n */\nOO.ui.mixin.IconElement.static.iconTitle = null;\n\n/* Methods */\n\n/**\n * Set the icon element. This method is used to retarget an icon mixin so that its functionality\n * applies to the specified icon element instead of the one created by the class. If an icon\n * element is already set, the mixin’s effect on that element is removed. Generated CSS classes\n * and mixin methods will no longer affect the element.\n *\n * @param {jQuery} $icon Element to use as icon\n */\nOO.ui.mixin.IconElement.prototype.setIconElement = function ( $icon ) {\n\tif ( this.$icon ) {\n\t\tthis.$icon\n\t\t\t.removeClass( 'oo-ui-iconElement-icon oo-ui-icon-' + this.icon )\n\t\t\t.removeAttr( 'title' );\n\t}\n\n\tthis.$icon = $icon\n\t\t.addClass( 'oo-ui-iconElement-icon' )\n\t\t.toggleClass( 'oo-ui-iconElement-noIcon', !this.icon )\n\t\t.toggleClass( 'oo-ui-icon-' + this.icon, !!this.icon );\n\tif ( this.iconTitle !== null ) {\n\t\tthis.$icon.attr( 'title', this.iconTitle );\n\t}\n\n\tthis.updateThemeClasses();\n};\n\n/**\n * Set icon by symbolic name (e.g., ‘remove’ or ‘menu’). Use `null` to remove an icon.\n * The icon parameter can also be set to a map of icon names. See the #icon config setting\n * for an example.\n *\n * @param {Object|string|null} icon A symbolic icon name, a {@link #icon map of icon names} keyed\n *  by language code, or `null` to remove the icon.\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.IconElement.prototype.setIcon = function ( icon ) {\n\ticon = OO.isPlainObject( icon ) ? OO.ui.getLocalValue( icon, null, 'default' ) : icon;\n\ticon = typeof icon === 'string' && icon.trim().length ? icon.trim() : null;\n\n\tif ( this.icon !== icon ) {\n\t\tif ( this.$icon ) {\n\t\t\tif ( this.icon !== null ) {\n\t\t\t\tthis.$icon.removeClass( 'oo-ui-icon-' + this.icon );\n\t\t\t}\n\t\t\tif ( icon !== null ) {\n\t\t\t\tthis.$icon.addClass( 'oo-ui-icon-' + icon );\n\t\t\t}\n\t\t}\n\t\tthis.icon = icon;\n\t}\n\n\tthis.$element.toggleClass( 'oo-ui-iconElement', !!this.icon );\n\tif ( this.$icon ) {\n\t\tthis.$icon.toggleClass( 'oo-ui-iconElement-noIcon', !this.icon );\n\t}\n\tthis.updateThemeClasses();\n\n\treturn this;\n};\n\n/**\n * Get the symbolic name of the icon.\n *\n * @return {string} Icon name\n */\nOO.ui.mixin.IconElement.prototype.getIcon = function () {\n\treturn this.icon;\n};\n\n/**\n * Get the icon title. The title text is displayed when a user moves the mouse over the icon.\n *\n * @return {string} Icon title text\n * @deprecated\n */\nOO.ui.mixin.IconElement.prototype.getIconTitle = function () {\n\treturn this.iconTitle;\n};\n","/**\n * IndicatorElement is often mixed into other classes to generate an indicator.\n * Indicators are small graphics that are generally used in two ways:\n *\n * - To draw attention to the status of an item. For example, an indicator might be\n *   used to show that an item in a list has errors that need to be resolved.\n * - To clarify the function of a control that acts in an exceptional way (a button\n *   that opens a menu instead of performing an action directly, for example).\n *\n * For a list of indicators included in the library, please see the\n * [OOUI documentation on MediaWiki] [1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Icons,_Indicators,_and_Labels#Indicators\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$indicator] The indicator element created by the class. If this\n *  configuration is omitted, the indicator element will use a generated `<span>`.\n * @cfg {string} [indicator] Symbolic name of the indicator (e.g., ‘clear’ or ‘down’).\n *  See the [OOUI documentation on MediaWiki][2] for a list of indicators included\n *  in the library.\n * [2]: https://www.mediawiki.org/wiki/OOUI/Widgets/Icons,_Indicators,_and_Labels#Indicators\n */\nOO.ui.mixin.IndicatorElement = function OoUiMixinIndicatorElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.$indicator = null;\n\tthis.indicator = null;\n\n\t// Initialization\n\tthis.setIndicator( config.indicator || this.constructor.static.indicator );\n\tthis.setIndicatorElement( config.$indicator || $( '<span>' ) );\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.mixin.IndicatorElement );\n\n/* Static Properties */\n\n/**\n * Symbolic name of the indicator (e.g., ‘clear’ or  ‘down’).\n * The static property will be overridden if the #indicator configuration is used.\n *\n * @static\n * @inheritable\n * @property {string|null}\n */\nOO.ui.mixin.IndicatorElement.static.indicator = null;\n\n/**\n * A text string used as the indicator title, a function that returns title text, or `null`\n * for no title. The static property will be overridden if the #indicatorTitle configuration is\n * used.\n *\n * @static\n * @inheritable\n * @property {string|Function|null}\n */\nOO.ui.mixin.IndicatorElement.static.indicatorTitle = null;\n\n/* Methods */\n\n/**\n * Set the indicator element.\n *\n * If an element is already set, it will be cleaned up before setting up the new element.\n *\n * @param {jQuery} $indicator Element to use as indicator\n */\nOO.ui.mixin.IndicatorElement.prototype.setIndicatorElement = function ( $indicator ) {\n\tif ( this.$indicator ) {\n\t\tthis.$indicator\n\t\t\t.removeClass( 'oo-ui-indicatorElement-indicator oo-ui-indicator-' + this.indicator )\n\t\t\t.removeAttr( 'title' );\n\t}\n\n\tthis.$indicator = $indicator\n\t\t.addClass( 'oo-ui-indicatorElement-indicator' )\n\t\t.toggleClass( 'oo-ui-indicatorElement-noIndicator', !this.indicator )\n\t\t.toggleClass( 'oo-ui-indicator-' + this.indicator, !!this.indicator );\n\tif ( this.indicatorTitle !== null ) {\n\t\tthis.$indicator.attr( 'title', this.indicatorTitle );\n\t}\n\n\tthis.updateThemeClasses();\n};\n\n/**\n * Set the indicator by its symbolic name: ‘clear’, ‘down’, ‘required’, ‘search’, ‘up’. Use `null`\n * to remove the indicator.\n *\n * @param {string|null} indicator Symbolic name of indicator, or `null` for no indicator\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.IndicatorElement.prototype.setIndicator = function ( indicator ) {\n\tindicator = typeof indicator === 'string' && indicator.length ? indicator.trim() : null;\n\n\tif ( this.indicator !== indicator ) {\n\t\tif ( this.$indicator ) {\n\t\t\tif ( this.indicator !== null ) {\n\t\t\t\tthis.$indicator.removeClass( 'oo-ui-indicator-' + this.indicator );\n\t\t\t}\n\t\t\tif ( indicator !== null ) {\n\t\t\t\tthis.$indicator.addClass( 'oo-ui-indicator-' + indicator );\n\t\t\t}\n\t\t}\n\t\tthis.indicator = indicator;\n\t}\n\n\tthis.$element.toggleClass( 'oo-ui-indicatorElement', !!this.indicator );\n\tif ( this.$indicator ) {\n\t\tthis.$indicator.toggleClass( 'oo-ui-indicatorElement-noIndicator', !this.indicator );\n\t}\n\tthis.updateThemeClasses();\n\n\treturn this;\n};\n\n/**\n * Get the symbolic name of the indicator (e.g., ‘clear’ or  ‘down’).\n *\n * @return {string} Symbolic name of indicator\n */\nOO.ui.mixin.IndicatorElement.prototype.getIndicator = function () {\n\treturn this.indicator;\n};\n\n/**\n * Get the indicator title.\n *\n * The title is displayed when a user moves the mouse over the indicator.\n *\n * @return {string} Indicator title text\n * @deprecated\n */\nOO.ui.mixin.IndicatorElement.prototype.getIndicatorTitle = function () {\n\treturn this.indicatorTitle;\n};\n","/**\n * The FlaggedElement class is an attribute mixin, meaning that it is used to add\n * additional functionality to an element created by another class. The class provides\n * a ‘flags’ property assigned the name (or an array of names) of styling flags,\n * which are used to customize the look and feel of a widget to better describe its\n * importance and functionality.\n *\n * The library currently contains the following styling flags for general use:\n *\n * - **progressive**: Progressive styling is applied to convey that the widget will move the user\n *   forward in a process.\n * - **destructive**: Destructive styling is applied to convey that the widget will remove\n *   something.\n *\n * The flags affect the appearance of the buttons:\n *\n *     @example\n *     // FlaggedElement is mixed into ButtonWidget to provide styling flags\n *     var button1 = new OO.ui.ButtonWidget( {\n *             label: 'Progressive',\n *             flags: 'progressive'\n *         } ),\n *         button2 = new OO.ui.ButtonWidget( {\n *             label: 'Destructive',\n *             flags: 'destructive'\n *         } );\n *     $( document.body ).append( button1.$element, button2.$element );\n *\n * {@link OO.ui.ActionWidget ActionWidgets}, which are a special kind of button that execute an\n * action, use these flags: **primary** and **safe**.\n * Please see the [OOUI documentation on MediaWiki] [1] for more information.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Elements/Flagged\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {string|string[]} [flags] The name or names of the flags (e.g., 'progressive' or 'primary')\n *  to apply.\n *  Please see the [OOUI documentation on MediaWiki] [2] for more information about available flags.\n *  [2]: https://www.mediawiki.org/wiki/OOUI/Elements/Flagged\n * @cfg {jQuery} [$flagged] The flagged element. By default,\n *  the flagged functionality is applied to the element created by the class ($element).\n *  If a different element is specified, the flagged functionality will be applied to it instead.\n */\nOO.ui.mixin.FlaggedElement = function OoUiMixinFlaggedElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.flags = {};\n\tthis.$flagged = null;\n\n\t// Initialization\n\tthis.setFlags( config.flags );\n\tthis.setFlaggedElement( config.$flagged || this.$element );\n};\n\n/* Events */\n\n/**\n * @event flag\n * A flag event is emitted when the #clearFlags or #setFlags methods are used. The `changes`\n * parameter contains the name of each modified flag and indicates whether it was\n * added or removed.\n *\n * @param {Object.<string,boolean>} changes Object keyed by flag name. A Boolean `true` indicates\n * that the flag was added, `false` that the flag was removed.\n */\n\n/* Methods */\n\n/**\n * Set the flagged element.\n *\n * This method is used to retarget a flagged mixin so that its functionality applies to the\n * specified element.\n * If an element is already set, the method will remove the mixin’s effect on that element.\n *\n * @param {jQuery} $flagged Element that should be flagged\n */\nOO.ui.mixin.FlaggedElement.prototype.setFlaggedElement = function ( $flagged ) {\n\tvar classNames = Object.keys( this.flags ).map( function ( flag ) {\n\t\treturn 'oo-ui-flaggedElement-' + flag;\n\t} );\n\n\tif ( this.$flagged ) {\n\t\tthis.$flagged.removeClass( classNames );\n\t}\n\n\tthis.$flagged = $flagged.addClass( classNames );\n};\n\n/**\n * Check if the specified flag is set.\n *\n * @param {string} flag Name of flag\n * @return {boolean} The flag is set\n */\nOO.ui.mixin.FlaggedElement.prototype.hasFlag = function ( flag ) {\n\t// This may be called before the constructor, thus before this.flags is set\n\treturn this.flags && ( flag in this.flags );\n};\n\n/**\n * Get the names of all flags set.\n *\n * @return {string[]} Flag names\n */\nOO.ui.mixin.FlaggedElement.prototype.getFlags = function () {\n\t// This may be called before the constructor, thus before this.flags is set\n\treturn Object.keys( this.flags || {} );\n};\n\n/**\n * Clear all flags.\n *\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n * @fires flag\n */\nOO.ui.mixin.FlaggedElement.prototype.clearFlags = function () {\n\tvar flag, className,\n\t\tchanges = {},\n\t\tremove = [],\n\t\tclassPrefix = 'oo-ui-flaggedElement-';\n\n\tfor ( flag in this.flags ) {\n\t\tclassName = classPrefix + flag;\n\t\tchanges[ flag ] = false;\n\t\tdelete this.flags[ flag ];\n\t\tremove.push( className );\n\t}\n\n\tif ( this.$flagged ) {\n\t\tthis.$flagged.removeClass( remove );\n\t}\n\n\tthis.updateThemeClasses();\n\tthis.emit( 'flag', changes );\n\n\treturn this;\n};\n\n/**\n * Add one or more flags.\n *\n * @param {string|string[]|Object.<string, boolean>} flags A flag name, an array of flag names,\n *  or an object keyed by flag name with a boolean value that indicates whether the flag should\n *  be added (`true`) or removed (`false`).\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n * @fires flag\n */\nOO.ui.mixin.FlaggedElement.prototype.setFlags = function ( flags ) {\n\tvar i, len, flag, className,\n\t\tchanges = {},\n\t\tadd = [],\n\t\tremove = [],\n\t\tclassPrefix = 'oo-ui-flaggedElement-';\n\n\tif ( typeof flags === 'string' ) {\n\t\tclassName = classPrefix + flags;\n\t\t// Set\n\t\tif ( !this.flags[ flags ] ) {\n\t\t\tthis.flags[ flags ] = true;\n\t\t\tadd.push( className );\n\t\t}\n\t} else if ( Array.isArray( flags ) ) {\n\t\tfor ( i = 0, len = flags.length; i < len; i++ ) {\n\t\t\tflag = flags[ i ];\n\t\t\tclassName = classPrefix + flag;\n\t\t\t// Set\n\t\t\tif ( !this.flags[ flag ] ) {\n\t\t\t\tchanges[ flag ] = true;\n\t\t\t\tthis.flags[ flag ] = true;\n\t\t\t\tadd.push( className );\n\t\t\t}\n\t\t}\n\t} else if ( OO.isPlainObject( flags ) ) {\n\t\tfor ( flag in flags ) {\n\t\t\tclassName = classPrefix + flag;\n\t\t\tif ( flags[ flag ] ) {\n\t\t\t\t// Set\n\t\t\t\tif ( !this.flags[ flag ] ) {\n\t\t\t\t\tchanges[ flag ] = true;\n\t\t\t\t\tthis.flags[ flag ] = true;\n\t\t\t\t\tadd.push( className );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Remove\n\t\t\t\tif ( this.flags[ flag ] ) {\n\t\t\t\t\tchanges[ flag ] = false;\n\t\t\t\t\tdelete this.flags[ flag ];\n\t\t\t\t\tremove.push( className );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( this.$flagged ) {\n\t\tthis.$flagged\n\t\t\t.addClass( add )\n\t\t\t.removeClass( remove );\n\t}\n\n\tthis.updateThemeClasses();\n\tthis.emit( 'flag', changes );\n\n\treturn this;\n};\n","/**\n * TitledElement is mixed into other classes to provide a `title` attribute.\n * Titles are rendered by the browser and are made visible when the user moves\n * the mouse over the element. Titles are not visible on touch devices.\n *\n *     @example\n *     // TitledElement provides a `title` attribute to the\n *     // ButtonWidget class.\n *     var button = new OO.ui.ButtonWidget( {\n *         label: 'Button with Title',\n *         title: 'I am a button'\n *     } );\n *     $( document.body ).append( button.$element );\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$titled] The element to which the `title` attribute is applied.\n *  If this config is omitted, the title functionality is applied to $element, the\n *  element created by the class.\n * @cfg {string|Function} [title] The title text or a function that returns text. If\n *  this config is omitted, the value of the {@link #static-title static title} property is used.\n */\nOO.ui.mixin.TitledElement = function OoUiMixinTitledElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.$titled = null;\n\tthis.title = null;\n\n\t// Initialization\n\tthis.setTitle( config.title !== undefined ? config.title : this.constructor.static.title );\n\tthis.setTitledElement( config.$titled || this.$element );\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.mixin.TitledElement );\n\n/* Static Properties */\n\n/**\n * The title text, a function that returns text, or `null` for no title. The value of the static\n * property is overridden if the #title config option is used.\n *\n * @static\n * @inheritable\n * @property {string|Function|null}\n */\nOO.ui.mixin.TitledElement.static.title = null;\n\n/* Methods */\n\n/**\n * Set the titled element.\n *\n * This method is used to retarget a TitledElement mixin so that its functionality applies to the\n * specified element.\n * If an element is already set, the mixin’s effect on that element is removed before the new\n * element is set up.\n *\n * @param {jQuery} $titled Element that should use the 'titled' functionality\n */\nOO.ui.mixin.TitledElement.prototype.setTitledElement = function ( $titled ) {\n\tif ( this.$titled ) {\n\t\tthis.$titled.removeAttr( 'title' );\n\t}\n\n\tthis.$titled = $titled;\n\tif ( this.title ) {\n\t\tthis.updateTitle();\n\t}\n};\n\n/**\n * Set title.\n *\n * @param {string|Function|null} title Title text, a function that returns text, or `null`\n *  for no title\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.TitledElement.prototype.setTitle = function ( title ) {\n\ttitle = typeof title === 'function' ? OO.ui.resolveMsg( title ) : title;\n\ttitle = ( typeof title === 'string' && title.length ) ? title : null;\n\n\tif ( this.title !== title ) {\n\t\tthis.title = title;\n\t\tthis.updateTitle();\n\t}\n\n\treturn this;\n};\n\n/**\n * Update the title attribute, in case of changes to title or accessKey.\n *\n * @protected\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.TitledElement.prototype.updateTitle = function () {\n\tvar title = this.getTitle();\n\tif ( this.$titled ) {\n\t\tif ( title !== null ) {\n\t\t\t// Only if this is an AccessKeyedElement\n\t\t\tif ( this.formatTitleWithAccessKey ) {\n\t\t\t\ttitle = this.formatTitleWithAccessKey( title );\n\t\t\t}\n\t\t\tthis.$titled.attr( 'title', title );\n\t\t} else {\n\t\t\tthis.$titled.removeAttr( 'title' );\n\t\t}\n\t}\n\treturn this;\n};\n\n/**\n * Get title.\n *\n * @return {string} Title string\n */\nOO.ui.mixin.TitledElement.prototype.getTitle = function () {\n\treturn this.title;\n};\n","/**\n * AccessKeyedElement is mixed into other classes to provide an `accesskey` HTML attribute.\n * Access keys allow an user to go to a specific element by using\n * a shortcut combination of a browser specific keys + the key\n * set to the field.\n *\n *     @example\n *     // AccessKeyedElement provides an `accesskey` attribute to the\n *     // ButtonWidget class.\n *     var button = new OO.ui.ButtonWidget( {\n *         label: 'Button with access key',\n *         accessKey: 'k'\n *     } );\n *     $( document.body ).append( button.$element );\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$accessKeyed] The element to which the `accesskey` attribute is applied.\n *  If this config is omitted, the access key functionality is applied to $element, the\n *  element created by the class.\n * @cfg {string|Function} [accessKey] The key or a function that returns the key. If\n *  this config is omitted, no access key will be added.\n */\nOO.ui.mixin.AccessKeyedElement = function OoUiMixinAccessKeyedElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.$accessKeyed = null;\n\tthis.accessKey = null;\n\n\t// Initialization\n\tthis.setAccessKey( config.accessKey || null );\n\tthis.setAccessKeyedElement( config.$accessKeyed || this.$element );\n\n\t// If this is also a TitledElement and it initialized before we did, we may have\n\t// to update the title with the access key\n\tif ( this.updateTitle ) {\n\t\tthis.updateTitle();\n\t}\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.mixin.AccessKeyedElement );\n\n/* Static Properties */\n\n/**\n * The access key, a function that returns a key, or `null` for no access key.\n *\n * @static\n * @inheritable\n * @property {string|Function|null}\n */\nOO.ui.mixin.AccessKeyedElement.static.accessKey = null;\n\n/* Methods */\n\n/**\n * Set the access keyed element.\n *\n * This method is used to retarget a AccessKeyedElement mixin so that its functionality applies to\n * the specified element.\n * If an element is already set, the mixin's effect on that element is removed before the new\n * element is set up.\n *\n * @param {jQuery} $accessKeyed Element that should use the 'access keyed' functionality\n */\nOO.ui.mixin.AccessKeyedElement.prototype.setAccessKeyedElement = function ( $accessKeyed ) {\n\tif ( this.$accessKeyed ) {\n\t\tthis.$accessKeyed.removeAttr( 'accesskey' );\n\t}\n\n\tthis.$accessKeyed = $accessKeyed;\n\tif ( this.accessKey ) {\n\t\tthis.$accessKeyed.attr( 'accesskey', this.accessKey );\n\t}\n};\n\n/**\n * Set access key.\n *\n * @param {string|Function|null} accessKey Key, a function that returns a key, or `null` for no\n *  access key\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.AccessKeyedElement.prototype.setAccessKey = function ( accessKey ) {\n\taccessKey = typeof accessKey === 'string' ? OO.ui.resolveMsg( accessKey ) : null;\n\n\tif ( this.accessKey !== accessKey ) {\n\t\tif ( this.$accessKeyed ) {\n\t\t\tif ( accessKey !== null ) {\n\t\t\t\tthis.$accessKeyed.attr( 'accesskey', accessKey );\n\t\t\t} else {\n\t\t\t\tthis.$accessKeyed.removeAttr( 'accesskey' );\n\t\t\t}\n\t\t}\n\t\tthis.accessKey = accessKey;\n\n\t\t// Only if this is a TitledElement\n\t\tif ( this.updateTitle ) {\n\t\t\tthis.updateTitle();\n\t\t}\n\t}\n\n\treturn this;\n};\n\n/**\n * Get access key.\n *\n * @return {string} accessKey string\n */\nOO.ui.mixin.AccessKeyedElement.prototype.getAccessKey = function () {\n\treturn this.accessKey;\n};\n\n/**\n * Add information about the access key to the element's tooltip label.\n * (This is only public for hacky usage in FieldLayout.)\n *\n * @param {string} title Tooltip label for `title` attribute\n * @return {string}\n */\nOO.ui.mixin.AccessKeyedElement.prototype.formatTitleWithAccessKey = function ( title ) {\n\tvar accessKey;\n\n\tif ( !this.$accessKeyed ) {\n\t\t// Not initialized yet; the constructor will call updateTitle() which will rerun this\n\t\t// function.\n\t\treturn title;\n\t}\n\t// Use jquery.accessKeyLabel if available to show modifiers, otherwise just display the\n\t// single key.\n\tif ( $.fn.updateTooltipAccessKeys && $.fn.updateTooltipAccessKeys.getAccessKeyLabel ) {\n\t\taccessKey = $.fn.updateTooltipAccessKeys.getAccessKeyLabel( this.$accessKeyed[ 0 ] );\n\t} else {\n\t\taccessKey = this.getAccessKey();\n\t}\n\tif ( accessKey ) {\n\t\ttitle += ' [' + accessKey + ']';\n\t}\n\treturn title;\n};\n","/**\n * ButtonWidget is a generic widget for buttons. A wide variety of looks,\n * feels, and functionality can be customized via the class’s configuration options\n * and methods. Please see the [OOUI documentation on MediaWiki] [1] for more information\n * and examples.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Buttons_and_Switches\n *\n *     @example\n *     // A button widget.\n *     var button = new OO.ui.ButtonWidget( {\n *         label: 'Button with Icon',\n *         icon: 'trash',\n *         title: 'Remove'\n *     } );\n *     $( document.body ).append( button.$element );\n *\n * NOTE: HTML form buttons should use the OO.ui.ButtonInputWidget class.\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.ButtonElement\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.IndicatorElement\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.TitledElement\n * @mixins OO.ui.mixin.FlaggedElement\n * @mixins OO.ui.mixin.TabIndexedElement\n * @mixins OO.ui.mixin.AccessKeyedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [active=false] Whether button should be shown as active\n * @cfg {string} [href] Hyperlink to visit when the button is clicked.\n * @cfg {string} [target] The frame or window in which to open the hyperlink.\n * @cfg {boolean} [noFollow] Search engine traversal hint (default: true)\n */\nOO.ui.ButtonWidget = function OoUiButtonWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.ButtonWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.ButtonElement.call( this, config );\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.IndicatorElement.call( this, config );\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.TitledElement.call( this, $.extend( {\n\t\t$titled: this.$button\n\t}, config ) );\n\tOO.ui.mixin.FlaggedElement.call( this, config );\n\tOO.ui.mixin.TabIndexedElement.call( this, $.extend( {\n\t\t$tabIndexed: this.$button\n\t}, config ) );\n\tOO.ui.mixin.AccessKeyedElement.call( this, $.extend( {\n\t\t$accessKeyed: this.$button\n\t}, config ) );\n\n\t// Properties\n\tthis.href = null;\n\tthis.target = null;\n\tthis.noFollow = false;\n\n\t// Events\n\tthis.connect( this, {\n\t\tdisable: 'onDisable'\n\t} );\n\n\t// Initialization\n\tthis.$button.append( this.$icon, this.$label, this.$indicator );\n\tthis.$element\n\t\t.addClass( 'oo-ui-buttonWidget' )\n\t\t.append( this.$button );\n\tthis.setActive( config.active );\n\tthis.setHref( config.href );\n\tthis.setTarget( config.target );\n\tthis.setNoFollow( config.noFollow );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ButtonWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.ButtonElement );\nOO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.IndicatorElement );\nOO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.TitledElement );\nOO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.FlaggedElement );\nOO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.TabIndexedElement );\nOO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.AccessKeyedElement );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.ButtonWidget.static.cancelButtonMouseDownEvents = false;\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.ButtonWidget.static.tagName = 'span';\n\n/* Methods */\n\n/**\n * Get hyperlink location.\n *\n * @return {string} Hyperlink location\n */\nOO.ui.ButtonWidget.prototype.getHref = function () {\n\treturn this.href;\n};\n\n/**\n * Get hyperlink target.\n *\n * @return {string} Hyperlink target\n */\nOO.ui.ButtonWidget.prototype.getTarget = function () {\n\treturn this.target;\n};\n\n/**\n * Get search engine traversal hint.\n *\n * @return {boolean} Whether search engines should avoid traversing this hyperlink\n */\nOO.ui.ButtonWidget.prototype.getNoFollow = function () {\n\treturn this.noFollow;\n};\n\n/**\n * Set hyperlink location.\n *\n * @param {string|null} href Hyperlink location, null to remove\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.ButtonWidget.prototype.setHref = function ( href ) {\n\thref = typeof href === 'string' ? href : null;\n\tif ( href !== null && !OO.ui.isSafeUrl( href ) ) {\n\t\thref = './' + href;\n\t}\n\n\tif ( href !== this.href ) {\n\t\tthis.href = href;\n\t\tthis.updateHref();\n\t}\n\n\treturn this;\n};\n\n/**\n * Update the `href` attribute, in case of changes to href or\n * disabled state.\n *\n * @private\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.ButtonWidget.prototype.updateHref = function () {\n\tif ( this.href !== null && !this.isDisabled() ) {\n\t\tthis.$button.attr( 'href', this.href );\n\t} else {\n\t\tthis.$button.removeAttr( 'href' );\n\t}\n\n\treturn this;\n};\n\n/**\n * Handle disable events.\n *\n * @private\n * @param {boolean} disabled Element is disabled\n */\nOO.ui.ButtonWidget.prototype.onDisable = function () {\n\tthis.updateHref();\n};\n\n/**\n * Set hyperlink target.\n *\n * @param {string|null} target Hyperlink target, null to remove\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.ButtonWidget.prototype.setTarget = function ( target ) {\n\ttarget = typeof target === 'string' ? target : null;\n\n\tif ( target !== this.target ) {\n\t\tthis.target = target;\n\t\tif ( target !== null ) {\n\t\t\tthis.$button.attr( 'target', target );\n\t\t} else {\n\t\t\tthis.$button.removeAttr( 'target' );\n\t\t}\n\t}\n\n\treturn this;\n};\n\n/**\n * Set search engine traversal hint.\n *\n * @param {boolean} noFollow True if search engines should avoid traversing this hyperlink\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.ButtonWidget.prototype.setNoFollow = function ( noFollow ) {\n\tnoFollow = typeof noFollow === 'boolean' ? noFollow : true;\n\n\tif ( noFollow !== this.noFollow ) {\n\t\tthis.noFollow = noFollow;\n\t\tif ( noFollow ) {\n\t\t\tthis.$button.attr( 'rel', 'nofollow' );\n\t\t} else {\n\t\t\tthis.$button.removeAttr( 'rel' );\n\t\t}\n\t}\n\n\treturn this;\n};\n\n// Override method visibility hints from ButtonElement\n/**\n * @method setActive\n * @inheritdoc\n */\n/**\n * @method isActive\n * @inheritdoc\n */\n","/**\n * A ButtonGroupWidget groups related buttons and is used together with OO.ui.ButtonWidget and\n * its subclasses. Each button in a group is addressed by a unique reference. Buttons can be added,\n * removed, and cleared from the group.\n *\n *     @example\n *     // A ButtonGroupWidget with two buttons.\n *     var button1 = new OO.ui.PopupButtonWidget( {\n *             label: 'Select a category',\n *             icon: 'menu',\n *             popup: {\n *                 $content: $( '<p>List of categories…</p>' ),\n *                 padded: true,\n *                 align: 'left'\n *             }\n *         } ),\n *         button2 = new OO.ui.ButtonWidget( {\n *             label: 'Add item'\n *         } ),\n *         buttonGroup = new OO.ui.ButtonGroupWidget( {\n *             items: [ button1, button2 ]\n *         } );\n *     $( document.body ).append( buttonGroup.$element );\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.GroupElement\n * @mixins OO.ui.mixin.TitledElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {OO.ui.ButtonWidget[]} [items] Buttons to add\n */\nOO.ui.ButtonGroupWidget = function OoUiButtonGroupWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.ButtonGroupWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.GroupElement.call( this, $.extend( {\n\t\t$group: this.$element\n\t}, config ) );\n\tOO.ui.mixin.TitledElement.call( this, config );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-buttonGroupWidget' );\n\tif ( Array.isArray( config.items ) ) {\n\t\tthis.addItems( config.items );\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ButtonGroupWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.ButtonGroupWidget, OO.ui.mixin.GroupElement );\nOO.mixinClass( OO.ui.ButtonGroupWidget, OO.ui.mixin.TitledElement );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.ButtonGroupWidget.static.tagName = 'span';\n\n/* Methods */\n\n/**\n * Focus the widget\n *\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.ButtonGroupWidget.prototype.focus = function () {\n\tif ( !this.isDisabled() ) {\n\t\tif ( this.items[ 0 ] ) {\n\t\t\tthis.items[ 0 ].focus();\n\t\t}\n\t}\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.ButtonGroupWidget.prototype.simulateLabelClick = function () {\n\tthis.focus();\n};\n","/**\n * IconWidget is a generic widget for {@link OO.ui.mixin.IconElement icons}.\n * In general, IconWidgets should be used with OO.ui.LabelWidget, which creates a label that\n * identifies the icon’s function. See the [OOUI documentation on MediaWiki] [1]\n * for a list of icons included in the library.\n *\n *     @example\n *     // An IconWidget with a label via LabelWidget.\n *     var myIcon = new OO.ui.IconWidget( {\n *             icon: 'help',\n *             title: 'Help'\n *          } ),\n *          // Create a label.\n *          iconLabel = new OO.ui.LabelWidget( {\n *              label: 'Help'\n *          } );\n *      $( document.body ).append( myIcon.$element, iconLabel.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Icons,_Indicators,_and_Labels#Icons\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.TitledElement\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.FlaggedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.IconWidget = function OoUiIconWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.IconWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.IconElement.call( this, $.extend( {\n\t\t$icon: this.$element\n\t}, config ) );\n\tOO.ui.mixin.TitledElement.call( this, $.extend( {\n\t\t$titled: this.$element\n\t}, config ) );\n\tOO.ui.mixin.LabelElement.call( this, $.extend( {\n\t\t$label: this.$element,\n\t\tinvisibleLabel: true\n\t}, config ) );\n\tOO.ui.mixin.FlaggedElement.call( this, $.extend( {\n\t\t$flagged: this.$element\n\t}, config ) );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-iconWidget' );\n\t// Remove class added by LabelElement initialization. It causes unexpected CSS to apply when\n\t// nested in other widgets, because this widget used to not mix in LabelElement.\n\tthis.$element.removeClass( 'oo-ui-labelElement-label' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.IconWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.IconWidget, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.IconWidget, OO.ui.mixin.TitledElement );\nOO.mixinClass( OO.ui.IconWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.IconWidget, OO.ui.mixin.FlaggedElement );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.IconWidget.static.tagName = 'span';\n","/**\n * IndicatorWidgets create indicators, which are small graphics that are generally used to draw\n * attention to the status of an item or to clarify the function within a control. For a list of\n * indicators included in the library, please see the [OOUI documentation on MediaWiki][1].\n *\n *     @example\n *     // An indicator widget.\n *     var indicator1 = new OO.ui.IndicatorWidget( {\n *             indicator: 'required'\n *         } ),\n *         // Create a fieldset layout to add a label.\n *         fieldset = new OO.ui.FieldsetLayout();\n *     fieldset.addItems( [\n *         new OO.ui.FieldLayout( indicator1, {\n *             label: 'A required indicator:'\n *         } )\n *     ] );\n *     $( document.body ).append( fieldset.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Icons,_Indicators,_and_Labels#Indicators\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.IndicatorElement\n * @mixins OO.ui.mixin.TitledElement\n * @mixins OO.ui.mixin.LabelElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.IndicatorWidget = function OoUiIndicatorWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.IndicatorWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.IndicatorElement.call( this, $.extend( {\n\t\t$indicator: this.$element\n\t}, config ) );\n\tOO.ui.mixin.TitledElement.call( this, $.extend( {\n\t\t$titled: this.$element\n\t}, config ) );\n\tOO.ui.mixin.LabelElement.call( this, $.extend( {\n\t\t$label: this.$element,\n\t\tinvisibleLabel: true\n\t}, config ) );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-indicatorWidget' );\n\t// Remove class added by LabelElement initialization. It causes unexpected CSS to apply when\n\t// nested in other widgets, because this widget used to not mix in LabelElement.\n\tthis.$element.removeClass( 'oo-ui-labelElement-label' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.IndicatorWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.IndicatorWidget, OO.ui.mixin.IndicatorElement );\nOO.mixinClass( OO.ui.IndicatorWidget, OO.ui.mixin.TitledElement );\nOO.mixinClass( OO.ui.IndicatorWidget, OO.ui.mixin.LabelElement );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.IndicatorWidget.static.tagName = 'span';\n","/**\n * LabelWidgets help identify the function of interface elements. Each LabelWidget can\n * be configured with a `label` option that is set to a string, a label node, or a function:\n *\n * - String: a plaintext string\n * - jQuery selection: a jQuery selection, used for anything other than a plaintext label, e.g., a\n *   label that includes a link or special styling, such as a gray color or additional\n *   graphical elements.\n * - Function: a function that will produce a string in the future. Functions are used\n *   in cases where the value of the label is not currently defined.\n *\n * In addition, the LabelWidget can be associated with an {@link OO.ui.InputWidget input widget},\n * which will come into focus when the label is clicked.\n *\n *     @example\n *     // Two LabelWidgets.\n *     var label1 = new OO.ui.LabelWidget( {\n *             label: 'plaintext label'\n *         } ),\n *         label2 = new OO.ui.LabelWidget( {\n *             label: $( '<a>' ).attr( 'href', 'default.html' ).text( 'jQuery label' )\n *         } ),\n *         // Create a fieldset layout with fields for each example.\n *         fieldset = new OO.ui.FieldsetLayout();\n *     fieldset.addItems( [\n *         new OO.ui.FieldLayout( label1 ),\n *         new OO.ui.FieldLayout( label2 )\n *     ] );\n *     $( document.body ).append( fieldset.$element );\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.TitledElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {OO.ui.InputWidget} [input] {@link OO.ui.InputWidget Input widget} that uses the label.\n *  Clicking the label will focus the specified input field.\n */\nOO.ui.LabelWidget = function OoUiLabelWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.LabelWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.LabelElement.call( this, $.extend( {\n\t\t$label: this.$element\n\t}, config ) );\n\tOO.ui.mixin.TitledElement.call( this, config );\n\n\t// Properties\n\tthis.input = config.input;\n\n\t// Initialization\n\tif ( this.input ) {\n\t\tif ( this.input.getInputId() ) {\n\t\t\tthis.$element.attr( 'for', this.input.getInputId() );\n\t\t} else {\n\t\t\tthis.$label.on( 'click', function () {\n\t\t\t\tthis.input.simulateLabelClick();\n\t\t\t}.bind( this ) );\n\t\t}\n\t}\n\tthis.$element.addClass( 'oo-ui-labelWidget' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.LabelWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.LabelWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.LabelWidget, OO.ui.mixin.TitledElement );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.LabelWidget.static.tagName = 'label';\n","/**\n * PendingElement is a mixin that is used to create elements that notify users that something is\n * happening and that they should wait before proceeding. The pending state is visually represented\n * with a pending texture that appears in the head of a pending\n * {@link OO.ui.ProcessDialog process dialog} or in the input field of a\n * {@link OO.ui.TextInputWidget text input widget}.\n *\n * Currently, {@link OO.ui.ActionWidget Action widgets}, which mix in this class, can also be marked\n * as pending, but only when used in {@link OO.ui.MessageDialog message dialogs}. The behavior is\n * not currently supported for action widgets used in process dialogs.\n *\n *     @example\n *     function MessageDialog( config ) {\n *         MessageDialog.parent.call( this, config );\n *     }\n *     OO.inheritClass( MessageDialog, OO.ui.MessageDialog );\n *\n *     MessageDialog.static.name = 'myMessageDialog';\n *     MessageDialog.static.actions = [\n *         { action: 'save', label: 'Done', flags: 'primary' },\n *         { label: 'Cancel', flags: 'safe' }\n *     ];\n *\n *     MessageDialog.prototype.initialize = function () {\n *         MessageDialog.parent.prototype.initialize.apply( this, arguments );\n *         this.content = new OO.ui.PanelLayout( { padded: true } );\n *         this.content.$element.append( '<p>Click the \\'Done\\' action widget to see its pending ' +\n *             'state. Note that action widgets can be marked pending in message dialogs but not ' +\n *             'process dialogs.</p>' );\n *         this.$body.append( this.content.$element );\n *     };\n *     MessageDialog.prototype.getBodyHeight = function () {\n *         return 100;\n *     }\n *     MessageDialog.prototype.getActionProcess = function ( action ) {\n *         var dialog = this;\n *         if ( action === 'save' ) {\n *             dialog.getActions().get({actions: 'save'})[0].pushPending();\n *             return new OO.ui.Process()\n *             .next( 1000 )\n *             .next( function () {\n *                 dialog.getActions().get({actions: 'save'})[0].popPending();\n *             } );\n *         }\n *         return MessageDialog.parent.prototype.getActionProcess.call( this, action );\n *     };\n *\n *     var windowManager = new OO.ui.WindowManager();\n *     $( document.body ).append( windowManager.$element );\n *\n *     var dialog = new MessageDialog();\n *     windowManager.addWindows( [ dialog ] );\n *     windowManager.openWindow( dialog );\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$pending] Element to mark as pending, defaults to this.$element\n */\nOO.ui.mixin.PendingElement = function OoUiMixinPendingElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.pending = 0;\n\tthis.$pending = null;\n\n\t// Initialisation\n\tthis.setPendingElement( config.$pending || this.$element );\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.mixin.PendingElement );\n\n/* Methods */\n\n/**\n * Set the pending element (and clean up any existing one).\n *\n * @param {jQuery} $pending The element to set to pending.\n */\nOO.ui.mixin.PendingElement.prototype.setPendingElement = function ( $pending ) {\n\tif ( this.$pending ) {\n\t\tthis.$pending.removeClass( 'oo-ui-pendingElement-pending' );\n\t}\n\n\tthis.$pending = $pending;\n\tif ( this.pending > 0 ) {\n\t\tthis.$pending.addClass( 'oo-ui-pendingElement-pending' );\n\t}\n};\n\n/**\n * Check if an element is pending.\n *\n * @return {boolean} Element is pending\n */\nOO.ui.mixin.PendingElement.prototype.isPending = function () {\n\treturn !!this.pending;\n};\n\n/**\n * Increase the pending counter. The pending state will remain active until the counter is zero\n * (i.e., the number of calls to #pushPending and #popPending is the same).\n *\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.PendingElement.prototype.pushPending = function () {\n\tif ( this.pending === 0 ) {\n\t\tthis.$pending.addClass( 'oo-ui-pendingElement-pending' );\n\t\tthis.updateThemeClasses();\n\t}\n\tthis.pending++;\n\n\treturn this;\n};\n\n/**\n * Decrease the pending counter. The pending state will remain active until the counter is zero\n * (i.e., the number of calls to #pushPending and #popPending is the same).\n *\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.PendingElement.prototype.popPending = function () {\n\tif ( this.pending === 1 ) {\n\t\tthis.$pending.removeClass( 'oo-ui-pendingElement-pending' );\n\t\tthis.updateThemeClasses();\n\t}\n\tthis.pending = Math.max( 0, this.pending - 1 );\n\n\treturn this;\n};\n","/**\n * Element that will stick adjacent to a specified container, even when it is inserted elsewhere\n * in the document (for example, in an OO.ui.Window's $overlay).\n *\n * The elements's position is automatically calculated and maintained when window is resized or the\n * page is scrolled. If you reposition the container manually, you have to call #position to make\n * sure the element is still placed correctly.\n *\n * As positioning is only possible when both the element and the container are attached to the DOM\n * and visible, it's only done after you call #togglePositioning. You might want to do this inside\n * the #toggle method to display a floating popup, for example.\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$floatable] Node to position, assigned to #$floatable, omit to use #$element\n * @cfg {jQuery} [$floatableContainer] Node to position adjacent to\n * @cfg {string} [verticalPosition='below'] Where to position $floatable vertically:\n *  'below': Directly below $floatableContainer, aligning f's top edge with fC's bottom edge\n *  'above': Directly above $floatableContainer, aligning f's bottom edge with fC's top edge\n *  'top': Align the top edge with $floatableContainer's top edge\n *  'bottom': Align the bottom edge with $floatableContainer's bottom edge\n *  'center': Vertically align the center with $floatableContainer's center\n * @cfg {string} [horizontalPosition='start'] Where to position $floatable horizontally:\n *  'before': Directly before $floatableContainer, aligning f's end edge with fC's start edge\n *  'after': Directly after $floatableContainer, aligning f's start edge with fC's end edge\n *  'start': Align the start (left in LTR, right in RTL) edge with $floatableContainer's start edge\n *  'end': Align the end (right in LTR, left in RTL) edge with $floatableContainer's end edge\n *  'center': Horizontally align the center with $floatableContainer's center\n * @cfg {boolean} [hideWhenOutOfView=true] Whether to hide the floatable element if the container\n *  is out of view\n */\nOO.ui.mixin.FloatableElement = function OoUiMixinFloatableElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.$floatable = null;\n\tthis.$floatableContainer = null;\n\tthis.$floatableWindow = null;\n\tthis.$floatableClosestScrollable = null;\n\tthis.floatableOutOfView = false;\n\tthis.onFloatableScrollHandler = this.position.bind( this );\n\tthis.onFloatableWindowResizeHandler = this.position.bind( this );\n\n\t// Initialization\n\tthis.setFloatableContainer( config.$floatableContainer );\n\tthis.setFloatableElement( config.$floatable || this.$element );\n\tthis.setVerticalPosition( config.verticalPosition || 'below' );\n\tthis.setHorizontalPosition( config.horizontalPosition || 'start' );\n\tthis.hideWhenOutOfView = config.hideWhenOutOfView === undefined ?\n\t\ttrue : !!config.hideWhenOutOfView;\n};\n\n/* Methods */\n\n/**\n * Set floatable element.\n *\n * If an element is already set, it will be cleaned up before setting up the new element.\n *\n * @param {jQuery} $floatable Element to make floatable\n */\nOO.ui.mixin.FloatableElement.prototype.setFloatableElement = function ( $floatable ) {\n\tif ( this.$floatable ) {\n\t\tthis.$floatable.removeClass( 'oo-ui-floatableElement-floatable' );\n\t\tthis.$floatable.css( { left: '', top: '' } );\n\t}\n\n\tthis.$floatable = $floatable.addClass( 'oo-ui-floatableElement-floatable' );\n\tthis.position();\n};\n\n/**\n * Set floatable container.\n *\n * The element will be positioned relative to the specified container.\n *\n * @param {jQuery|null} $floatableContainer Container to keep visible, or null to unset\n */\nOO.ui.mixin.FloatableElement.prototype.setFloatableContainer = function ( $floatableContainer ) {\n\tthis.$floatableContainer = $floatableContainer;\n\tif ( this.$floatable ) {\n\t\tthis.position();\n\t}\n};\n\n/**\n * Change how the element is positioned vertically.\n *\n * @param {string} position 'below', 'above', 'top', 'bottom' or 'center'\n */\nOO.ui.mixin.FloatableElement.prototype.setVerticalPosition = function ( position ) {\n\tif ( [ 'below', 'above', 'top', 'bottom', 'center' ].indexOf( position ) === -1 ) {\n\t\tthrow new Error( 'Invalid value for vertical position: ' + position );\n\t}\n\tif ( this.verticalPosition !== position ) {\n\t\tthis.verticalPosition = position;\n\t\tif ( this.$floatable ) {\n\t\t\tthis.position();\n\t\t}\n\t}\n};\n\n/**\n * Change how the element is positioned horizontally.\n *\n * @param {string} position 'before', 'after', 'start', 'end' or 'center'\n */\nOO.ui.mixin.FloatableElement.prototype.setHorizontalPosition = function ( position ) {\n\tif ( [ 'before', 'after', 'start', 'end', 'center' ].indexOf( position ) === -1 ) {\n\t\tthrow new Error( 'Invalid value for horizontal position: ' + position );\n\t}\n\tif ( this.horizontalPosition !== position ) {\n\t\tthis.horizontalPosition = position;\n\t\tif ( this.$floatable ) {\n\t\t\tthis.position();\n\t\t}\n\t}\n};\n\n/**\n * Toggle positioning.\n *\n * Do not turn positioning on until after the element is attached to the DOM and visible.\n *\n * @param {boolean} [positioning] Enable positioning, omit to toggle\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.FloatableElement.prototype.togglePositioning = function ( positioning ) {\n\tvar closestScrollableOfContainer;\n\n\tif ( !this.$floatable || !this.$floatableContainer ) {\n\t\treturn this;\n\t}\n\n\tpositioning = positioning === undefined ? !this.positioning : !!positioning;\n\n\tif ( positioning && !this.warnedUnattached && !this.isElementAttached() ) {\n\t\tOO.ui.warnDeprecation( 'FloatableElement#togglePositioning: Before calling this method, the element must be attached to the DOM.' );\n\t\tthis.warnedUnattached = true;\n\t}\n\n\tif ( this.positioning !== positioning ) {\n\t\tthis.positioning = positioning;\n\n\t\tclosestScrollableOfContainer = OO.ui.Element.static.getClosestScrollableContainer(\n\t\t\tthis.$floatableContainer[ 0 ]\n\t\t);\n\t\t// If the scrollable is the root, we have to listen to scroll events\n\t\t// on the window because of browser inconsistencies.\n\t\tif ( $( closestScrollableOfContainer ).is( 'html, body' ) ) {\n\t\t\tclosestScrollableOfContainer = OO.ui.Element.static.getWindow(\n\t\t\t\tclosestScrollableOfContainer\n\t\t\t);\n\t\t}\n\n\t\tif ( positioning ) {\n\t\t\tthis.$floatableWindow = $( this.getElementWindow() );\n\t\t\tthis.$floatableWindow.on( 'resize', this.onFloatableWindowResizeHandler );\n\n\t\t\tthis.$floatableClosestScrollable = $( closestScrollableOfContainer );\n\t\t\tthis.$floatableClosestScrollable.on( 'scroll', this.onFloatableScrollHandler );\n\n\t\t\t// Initial position after visible\n\t\t\tthis.position();\n\t\t} else {\n\t\t\tif ( this.$floatableWindow ) {\n\t\t\t\tthis.$floatableWindow.off( 'resize', this.onFloatableWindowResizeHandler );\n\t\t\t\tthis.$floatableWindow = null;\n\t\t\t}\n\n\t\t\tif ( this.$floatableClosestScrollable ) {\n\t\t\t\tthis.$floatableClosestScrollable.off( 'scroll', this.onFloatableScrollHandler );\n\t\t\t\tthis.$floatableClosestScrollable = null;\n\t\t\t}\n\n\t\t\tthis.$floatable.css( { left: '', right: '', top: '' } );\n\t\t}\n\t}\n\n\treturn this;\n};\n\n/**\n * Check whether the bottom edge of the given element is within the viewport of the given\n * container.\n *\n * @private\n * @param {jQuery} $element\n * @param {jQuery} $container\n * @return {boolean}\n */\nOO.ui.mixin.FloatableElement.prototype.isElementInViewport = function ( $element, $container ) {\n\tvar elemRect, contRect, topEdgeInBounds, bottomEdgeInBounds, leftEdgeInBounds,\n\t\trightEdgeInBounds, startEdgeInBounds, endEdgeInBounds, viewportSpacing,\n\t\tdirection = $element.css( 'direction' );\n\n\telemRect = $element[ 0 ].getBoundingClientRect();\n\tif ( $container[ 0 ] === window ) {\n\t\tviewportSpacing = OO.ui.getViewportSpacing();\n\t\tcontRect = {\n\t\t\ttop: 0,\n\t\t\tleft: 0,\n\t\t\tright: document.documentElement.clientWidth,\n\t\t\tbottom: document.documentElement.clientHeight\n\t\t};\n\t\tcontRect.top += viewportSpacing.top;\n\t\tcontRect.left += viewportSpacing.left;\n\t\tcontRect.right -= viewportSpacing.right;\n\t\tcontRect.bottom -= viewportSpacing.bottom;\n\t} else {\n\t\tcontRect = $container[ 0 ].getBoundingClientRect();\n\t}\n\n\ttopEdgeInBounds = elemRect.top >= contRect.top && elemRect.top <= contRect.bottom;\n\tbottomEdgeInBounds = elemRect.bottom >= contRect.top && elemRect.bottom <= contRect.bottom;\n\tleftEdgeInBounds = elemRect.left >= contRect.left && elemRect.left <= contRect.right;\n\trightEdgeInBounds = elemRect.right >= contRect.left && elemRect.right <= contRect.right;\n\tif ( direction === 'rtl' ) {\n\t\tstartEdgeInBounds = rightEdgeInBounds;\n\t\tendEdgeInBounds = leftEdgeInBounds;\n\t} else {\n\t\tstartEdgeInBounds = leftEdgeInBounds;\n\t\tendEdgeInBounds = rightEdgeInBounds;\n\t}\n\n\tif ( this.verticalPosition === 'below' && !bottomEdgeInBounds ) {\n\t\treturn false;\n\t}\n\tif ( this.verticalPosition === 'above' && !topEdgeInBounds ) {\n\t\treturn false;\n\t}\n\tif ( this.horizontalPosition === 'before' && !startEdgeInBounds ) {\n\t\treturn false;\n\t}\n\tif ( this.horizontalPosition === 'after' && !endEdgeInBounds ) {\n\t\treturn false;\n\t}\n\n\t// The other positioning values are all about being inside the container,\n\t// so in those cases all we care about is that any part of the container is visible.\n\treturn elemRect.top <= contRect.bottom && elemRect.bottom >= contRect.top &&\n\t\telemRect.left <= contRect.right && elemRect.right >= contRect.left;\n};\n\n/**\n * Check if the floatable is hidden to the user because it was offscreen.\n *\n * @return {boolean} Floatable is out of view\n */\nOO.ui.mixin.FloatableElement.prototype.isFloatableOutOfView = function () {\n\treturn this.floatableOutOfView;\n};\n\n/**\n * Position the floatable below its container.\n *\n * This should only be done when both of them are attached to the DOM and visible.\n *\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.FloatableElement.prototype.position = function () {\n\tif ( !this.positioning ) {\n\t\treturn this;\n\t}\n\n\tif ( !(\n\t\t// To continue, some things need to be true:\n\t\t// The element must actually be in the DOM\n\t\tthis.isElementAttached() && (\n\t\t\t// The closest scrollable is the current window\n\t\t\tthis.$floatableClosestScrollable[ 0 ] === this.getElementWindow() ||\n\t\t\t// OR is an element in the element's DOM\n\t\t\t$.contains( this.getElementDocument(), this.$floatableClosestScrollable[ 0 ] )\n\t\t)\n\t) ) {\n\t\t// Abort early if important parts of the widget are no longer attached to the DOM\n\t\treturn this;\n\t}\n\n\tthis.floatableOutOfView = this.hideWhenOutOfView &&\n\t\t!this.isElementInViewport( this.$floatableContainer, this.$floatableClosestScrollable );\n\tif ( this.floatableOutOfView ) {\n\t\tthis.$floatable.addClass( 'oo-ui-element-hidden' );\n\t\treturn this;\n\t} else {\n\t\tthis.$floatable.removeClass( 'oo-ui-element-hidden' );\n\t}\n\n\tthis.$floatable.css( this.computePosition() );\n\n\t// We updated the position, so re-evaluate the clipping state.\n\t// (ClippableElement does not listen to 'scroll' events on $floatableContainer's parent, and so\n\t// will not notice the need to update itself.)\n\t// TODO: This is terrible, we shouldn't need to know about ClippableElement at all here.\n\t// Why does it not listen to the right events in the right places?\n\tif ( this.clip ) {\n\t\tthis.clip();\n\t}\n\n\treturn this;\n};\n\n/**\n * Compute how #$floatable should be positioned based on the position of #$floatableContainer\n * and the positioning settings. This is a helper for #position that shouldn't be called directly,\n * but may be overridden by subclasses if they want to change or add to the positioning logic.\n *\n * @return {Object} New position to apply with .css(). Keys are 'top', 'left', 'bottom' and 'right'.\n */\nOO.ui.mixin.FloatableElement.prototype.computePosition = function () {\n\tvar isBody, scrollableX, scrollableY, containerPos,\n\t\thorizScrollbarHeight, vertScrollbarWidth, scrollTop, scrollLeft,\n\t\tnewPos = { top: '', left: '', bottom: '', right: '' },\n\t\tdirection = this.$floatableContainer.css( 'direction' ),\n\t\t$offsetParent = this.$floatable.offsetParent();\n\n\tif ( $offsetParent.is( 'html' ) ) {\n\t\t// The innerHeight/Width and clientHeight/Width calculations don't work well on the\n\t\t// <html> element, but they do work on the <body>\n\t\t$offsetParent = $( $offsetParent[ 0 ].ownerDocument.body );\n\t}\n\tisBody = $offsetParent.is( 'body' );\n\tscrollableX = $offsetParent.css( 'overflow-x' ) === 'scroll' ||\n\t\t$offsetParent.css( 'overflow-x' ) === 'auto';\n\tscrollableY = $offsetParent.css( 'overflow-y' ) === 'scroll' ||\n\t\t$offsetParent.css( 'overflow-y' ) === 'auto';\n\n\tvertScrollbarWidth = $offsetParent.innerWidth() - $offsetParent.prop( 'clientWidth' );\n\thorizScrollbarHeight = $offsetParent.innerHeight() - $offsetParent.prop( 'clientHeight' );\n\t// We don't need to compute and add scrollTop and scrollLeft if the scrollable container\n\t// is the body, or if it isn't scrollable\n\tscrollTop = scrollableY && !isBody ?\n\t\t$offsetParent.scrollTop() : 0;\n\tscrollLeft = scrollableX && !isBody ?\n\t\tOO.ui.Element.static.getScrollLeft( $offsetParent[ 0 ] ) : 0;\n\n\t// Avoid passing the <body> to getRelativePosition(), because it won't return what we expect\n\t// if the <body> has a margin\n\tcontainerPos = isBody ?\n\t\tthis.$floatableContainer.offset() :\n\t\tOO.ui.Element.static.getRelativePosition( this.$floatableContainer, $offsetParent );\n\tcontainerPos.bottom = containerPos.top + this.$floatableContainer.outerHeight();\n\tcontainerPos.right = containerPos.left + this.$floatableContainer.outerWidth();\n\tcontainerPos.start = direction === 'rtl' ? containerPos.right : containerPos.left;\n\tcontainerPos.end = direction === 'rtl' ? containerPos.left : containerPos.right;\n\n\tif ( this.verticalPosition === 'below' ) {\n\t\tnewPos.top = containerPos.bottom;\n\t} else if ( this.verticalPosition === 'above' ) {\n\t\tnewPos.bottom = $offsetParent.outerHeight() - containerPos.top;\n\t} else if ( this.verticalPosition === 'top' ) {\n\t\tnewPos.top = containerPos.top;\n\t} else if ( this.verticalPosition === 'bottom' ) {\n\t\tnewPos.bottom = $offsetParent.outerHeight() - containerPos.bottom;\n\t} else if ( this.verticalPosition === 'center' ) {\n\t\tnewPos.top = containerPos.top +\n\t\t\t( this.$floatableContainer.height() - this.$floatable.height() ) / 2;\n\t}\n\n\tif ( this.horizontalPosition === 'before' ) {\n\t\tnewPos.end = containerPos.start;\n\t} else if ( this.horizontalPosition === 'after' ) {\n\t\tnewPos.start = containerPos.end;\n\t} else if ( this.horizontalPosition === 'start' ) {\n\t\tnewPos.start = containerPos.start;\n\t} else if ( this.horizontalPosition === 'end' ) {\n\t\tnewPos.end = containerPos.end;\n\t} else if ( this.horizontalPosition === 'center' ) {\n\t\tnewPos.left = containerPos.left +\n\t\t\t( this.$floatableContainer.width() - this.$floatable.width() ) / 2;\n\t}\n\n\tif ( newPos.start !== undefined ) {\n\t\tif ( direction === 'rtl' ) {\n\t\t\tnewPos.right = ( isBody ? $( $offsetParent[ 0 ].ownerDocument.documentElement ) :\n\t\t\t\t$offsetParent ).outerWidth() - newPos.start;\n\t\t} else {\n\t\t\tnewPos.left = newPos.start;\n\t\t}\n\t\tdelete newPos.start;\n\t}\n\tif ( newPos.end !== undefined ) {\n\t\tif ( direction === 'rtl' ) {\n\t\t\tnewPos.left = newPos.end;\n\t\t} else {\n\t\t\tnewPos.right = ( isBody ? $( $offsetParent[ 0 ].ownerDocument.documentElement ) :\n\t\t\t\t$offsetParent ).outerWidth() - newPos.end;\n\t\t}\n\t\tdelete newPos.end;\n\t}\n\n\t// Account for scroll position\n\tif ( newPos.top !== '' ) {\n\t\tnewPos.top += scrollTop;\n\t}\n\tif ( newPos.bottom !== '' ) {\n\t\tnewPos.bottom -= scrollTop;\n\t}\n\tif ( newPos.left !== '' ) {\n\t\tnewPos.left += scrollLeft;\n\t}\n\tif ( newPos.right !== '' ) {\n\t\tnewPos.right -= scrollLeft;\n\t}\n\n\t// Account for scrollbar gutter\n\tif ( newPos.bottom !== '' ) {\n\t\tnewPos.bottom -= horizScrollbarHeight;\n\t}\n\tif ( direction === 'rtl' ) {\n\t\tif ( newPos.left !== '' ) {\n\t\t\tnewPos.left -= vertScrollbarWidth;\n\t\t}\n\t} else {\n\t\tif ( newPos.right !== '' ) {\n\t\t\tnewPos.right -= vertScrollbarWidth;\n\t\t}\n\t}\n\n\treturn newPos;\n};\n","/**\n * Element that can be automatically clipped to visible boundaries.\n *\n * Whenever the element's natural height changes, you have to call\n * {@link OO.ui.mixin.ClippableElement#clip} to make sure it's still\n * clipping correctly.\n *\n * The dimensions of #$clippableContainer will be compared to the boundaries of the\n * nearest scrollable container. If #$clippableContainer is too tall and/or too wide,\n * then #$clippable will be given a fixed reduced height and/or width and will be made\n * scrollable. By default, #$clippable and #$clippableContainer are the same element,\n * but you can build a static footer by setting #$clippableContainer to an element that contains\n * #$clippable and the footer.\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$clippable] Node to clip, assigned to #$clippable, omit to use #$element\n * @cfg {jQuery} [$clippableContainer] Node to keep visible, assigned to #$clippableContainer,\n *   omit to use #$clippable\n */\nOO.ui.mixin.ClippableElement = function OoUiMixinClippableElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.$clippable = null;\n\tthis.$clippableContainer = null;\n\tthis.clipping = false;\n\tthis.clippedHorizontally = false;\n\tthis.clippedVertically = false;\n\tthis.$clippableScrollableContainer = null;\n\tthis.$clippableScroller = null;\n\tthis.$clippableWindow = null;\n\tthis.idealWidth = null;\n\tthis.idealHeight = null;\n\tthis.onClippableScrollHandler = this.clip.bind( this );\n\tthis.onClippableWindowResizeHandler = this.clip.bind( this );\n\n\t// Initialization\n\tif ( config.$clippableContainer ) {\n\t\tthis.setClippableContainer( config.$clippableContainer );\n\t}\n\tthis.setClippableElement( config.$clippable || this.$element );\n};\n\n/* Methods */\n\n/**\n * Set clippable element.\n *\n * If an element is already set, it will be cleaned up before setting up the new element.\n *\n * @param {jQuery} $clippable Element to make clippable\n */\nOO.ui.mixin.ClippableElement.prototype.setClippableElement = function ( $clippable ) {\n\tif ( this.$clippable ) {\n\t\tthis.$clippable.removeClass( 'oo-ui-clippableElement-clippable' );\n\t\tthis.$clippable.css( { width: '', height: '', overflowX: '', overflowY: '' } );\n\t\tOO.ui.Element.static.reconsiderScrollbars( this.$clippable[ 0 ] );\n\t}\n\n\tthis.$clippable = $clippable.addClass( 'oo-ui-clippableElement-clippable' );\n\tthis.clip();\n};\n\n/**\n * Set clippable container.\n *\n * This is the container that will be measured when deciding whether to clip. When clipping,\n * #$clippable will be resized in order to keep the clippable container fully visible.\n *\n * If the clippable container is unset, #$clippable will be used.\n *\n * @param {jQuery|null} $clippableContainer Container to keep visible, or null to unset\n */\nOO.ui.mixin.ClippableElement.prototype.setClippableContainer = function ( $clippableContainer ) {\n\tthis.$clippableContainer = $clippableContainer;\n\tif ( this.$clippable ) {\n\t\tthis.clip();\n\t}\n};\n\n/**\n * Toggle clipping.\n *\n * Do not turn clipping on until after the element is attached to the DOM and visible.\n *\n * @param {boolean} [clipping] Enable clipping, omit to toggle\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.ClippableElement.prototype.toggleClipping = function ( clipping ) {\n\tclipping = clipping === undefined ? !this.clipping : !!clipping;\n\n\tif ( clipping && !this.warnedUnattached && !this.isElementAttached() ) {\n\t\tOO.ui.warnDeprecation( 'ClippableElement#toggleClipping: Before calling this method, the element must be attached to the DOM.' );\n\t\tthis.warnedUnattached = true;\n\t}\n\n\tif ( this.clipping !== clipping ) {\n\t\tthis.clipping = clipping;\n\t\tif ( clipping ) {\n\t\t\tthis.$clippableScrollableContainer = $( this.getClosestScrollableElementContainer() );\n\t\t\t// If the clippable container is the root, we have to listen to scroll events and check\n\t\t\t// jQuery.scrollTop on the window because of browser inconsistencies\n\t\t\tthis.$clippableScroller = this.$clippableScrollableContainer.is( 'html, body' ) ?\n\t\t\t\t$( OO.ui.Element.static.getWindow( this.$clippableScrollableContainer ) ) :\n\t\t\t\tthis.$clippableScrollableContainer;\n\t\t\tthis.$clippableScroller.on( 'scroll', this.onClippableScrollHandler );\n\t\t\tthis.$clippableWindow = $( this.getElementWindow() )\n\t\t\t\t.on( 'resize', this.onClippableWindowResizeHandler );\n\t\t\t// Initial clip after visible\n\t\t\tthis.clip();\n\t\t} else {\n\t\t\tthis.$clippable.css( {\n\t\t\t\twidth: '',\n\t\t\t\theight: '',\n\t\t\t\tmaxWidth: '',\n\t\t\t\tmaxHeight: '',\n\t\t\t\toverflowX: '',\n\t\t\t\toverflowY: ''\n\t\t\t} );\n\t\t\tOO.ui.Element.static.reconsiderScrollbars( this.$clippable[ 0 ] );\n\n\t\t\tthis.$clippableScrollableContainer = null;\n\t\t\tthis.$clippableScroller.off( 'scroll', this.onClippableScrollHandler );\n\t\t\tthis.$clippableScroller = null;\n\t\t\tthis.$clippableWindow.off( 'resize', this.onClippableWindowResizeHandler );\n\t\t\tthis.$clippableWindow = null;\n\t\t}\n\t}\n\n\treturn this;\n};\n\n/**\n * Check if the element will be clipped to fit the visible area of the nearest scrollable container.\n *\n * @return {boolean} Element will be clipped to the visible area\n */\nOO.ui.mixin.ClippableElement.prototype.isClipping = function () {\n\treturn this.clipping;\n};\n\n/**\n * Check if the bottom or right of the element is being clipped by the nearest scrollable container.\n *\n * @return {boolean} Part of the element is being clipped\n */\nOO.ui.mixin.ClippableElement.prototype.isClipped = function () {\n\treturn this.clippedHorizontally || this.clippedVertically;\n};\n\n/**\n * Check if the right of the element is being clipped by the nearest scrollable container.\n *\n * @return {boolean} Part of the element is being clipped\n */\nOO.ui.mixin.ClippableElement.prototype.isClippedHorizontally = function () {\n\treturn this.clippedHorizontally;\n};\n\n/**\n * Check if the bottom of the element is being clipped by the nearest scrollable container.\n *\n * @return {boolean} Part of the element is being clipped\n */\nOO.ui.mixin.ClippableElement.prototype.isClippedVertically = function () {\n\treturn this.clippedVertically;\n};\n\n/**\n * Set the ideal size. These are the dimensions #$clippable will have when it's not being clipped.\n *\n * @param {number|string} [width] Width as a number of pixels or CSS string with unit suffix\n * @param {number|string} [height] Height as a number of pixels or CSS string with unit suffix\n */\nOO.ui.mixin.ClippableElement.prototype.setIdealSize = function ( width, height ) {\n\tthis.idealWidth = width;\n\tthis.idealHeight = height;\n\n\tif ( !this.clipping ) {\n\t\t// Update dimensions\n\t\tthis.$clippable.css( { width: width, height: height } );\n\t}\n\t// While clipping, idealWidth and idealHeight are not considered\n};\n\n/**\n * Return the side of the clippable on which it is \"anchored\" (aligned to something else).\n * ClippableElement will clip the opposite side when reducing element's width.\n *\n * Classes that mix in ClippableElement should override this to return 'right' if their\n * clippable is absolutely positioned and using 'right: Npx' (and not using 'left').\n * If your class also mixes in FloatableElement, this is handled automatically.\n *\n * (This can't be guessed from the actual CSS because the computed values for 'left'/'right' are\n * always in pixels, even if they were unset or set to 'auto'.)\n *\n * When in doubt, 'left' (or 'right' in RTL) is a sane fallback.\n *\n * @return {string} 'left' or 'right'\n */\nOO.ui.mixin.ClippableElement.prototype.getHorizontalAnchorEdge = function () {\n\tif ( this.computePosition && this.positioning && this.computePosition().right !== '' ) {\n\t\treturn 'right';\n\t}\n\treturn 'left';\n};\n\n/**\n * Return the side of the clippable on which it is \"anchored\" (aligned to something else).\n * ClippableElement will clip the opposite side when reducing element's width.\n *\n * Classes that mix in ClippableElement should override this to return 'bottom' if their\n * clippable is absolutely positioned and using 'bottom: Npx' (and not using 'top').\n * If your class also mixes in FloatableElement, this is handled automatically.\n *\n * (This can't be guessed from the actual CSS because the computed values for 'left'/'right' are\n * always in pixels, even if they were unset or set to 'auto'.)\n *\n * When in doubt, 'top' is a sane fallback.\n *\n * @return {string} 'top' or 'bottom'\n */\nOO.ui.mixin.ClippableElement.prototype.getVerticalAnchorEdge = function () {\n\tif ( this.computePosition && this.positioning && this.computePosition().bottom !== '' ) {\n\t\treturn 'bottom';\n\t}\n\treturn 'top';\n};\n\n/**\n * Clip element to visible boundaries and allow scrolling when needed. You should call this method\n * when the element's natural height changes.\n *\n * Element will be clipped the bottom or right of the element is within 10px of the edge of, or\n * overlapped by, the visible area of the nearest scrollable container.\n *\n * Because calling clip() when the natural height changes isn't always possible, we also set\n * max-height when the element isn't being clipped. This means that if the element tries to grow\n * beyond the edge, something reasonable will happen before clip() is called.\n *\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.ClippableElement.prototype.clip = function () {\n\tvar extraHeight, extraWidth, viewportSpacing,\n\t\tdesiredWidth, desiredHeight, allotedWidth, allotedHeight,\n\t\tnaturalWidth, naturalHeight, clipWidth, clipHeight,\n\t\t$item, itemRect, $viewport, viewportRect, availableRect,\n\t\tdirection, vertScrollbarWidth, horizScrollbarHeight,\n\t\t// Extra tolerance so that the sloppy code below doesn't result in results that are off\n\t\t// by one or two pixels. (And also so that we have space to display drop shadows.)\n\t\t// Chosen by fair dice roll.\n\t\tbuffer = 7;\n\n\tif ( !this.clipping ) {\n\t\t// this.$clippableScrollableContainer and this.$clippableWindow are null, so the below\n\t\t// will fail\n\t\treturn this;\n\t}\n\n\tfunction rectIntersection( a, b ) {\n\t\tvar out = {};\n\t\tout.top = Math.max( a.top, b.top );\n\t\tout.left = Math.max( a.left, b.left );\n\t\tout.bottom = Math.min( a.bottom, b.bottom );\n\t\tout.right = Math.min( a.right, b.right );\n\t\treturn out;\n\t}\n\n\tviewportSpacing = OO.ui.getViewportSpacing();\n\n\tif ( this.$clippableScrollableContainer.is( 'html, body' ) ) {\n\t\t$viewport = $( this.$clippableScrollableContainer[ 0 ].ownerDocument.body );\n\t\t// Dimensions of the browser window, rather than the element!\n\t\tviewportRect = {\n\t\t\ttop: 0,\n\t\t\tleft: 0,\n\t\t\tright: document.documentElement.clientWidth,\n\t\t\tbottom: document.documentElement.clientHeight\n\t\t};\n\t\tviewportRect.top += viewportSpacing.top;\n\t\tviewportRect.left += viewportSpacing.left;\n\t\tviewportRect.right -= viewportSpacing.right;\n\t\tviewportRect.bottom -= viewportSpacing.bottom;\n\t} else {\n\t\t$viewport = this.$clippableScrollableContainer;\n\t\tviewportRect = $viewport[ 0 ].getBoundingClientRect();\n\t\t// Convert into a plain object\n\t\tviewportRect = $.extend( {}, viewportRect );\n\t}\n\n\t// Account for scrollbar gutter\n\tdirection = $viewport.css( 'direction' );\n\tvertScrollbarWidth = $viewport.innerWidth() - $viewport.prop( 'clientWidth' );\n\thorizScrollbarHeight = $viewport.innerHeight() - $viewport.prop( 'clientHeight' );\n\tviewportRect.bottom -= horizScrollbarHeight;\n\tif ( direction === 'rtl' ) {\n\t\tviewportRect.left += vertScrollbarWidth;\n\t} else {\n\t\tviewportRect.right -= vertScrollbarWidth;\n\t}\n\n\t// Add arbitrary tolerance\n\tviewportRect.top += buffer;\n\tviewportRect.left += buffer;\n\tviewportRect.right -= buffer;\n\tviewportRect.bottom -= buffer;\n\n\t$item = this.$clippableContainer || this.$clippable;\n\n\textraHeight = $item.outerHeight() - this.$clippable.outerHeight();\n\textraWidth = $item.outerWidth() - this.$clippable.outerWidth();\n\n\titemRect = $item[ 0 ].getBoundingClientRect();\n\t// Convert into a plain object\n\titemRect = $.extend( {}, itemRect );\n\n\t// Item might already be clipped, so we can't just use its dimensions (in case we might need to\n\t// make it larger than before). Extend the rectangle to the maximum size we are allowed to take.\n\tif ( this.getHorizontalAnchorEdge() === 'right' ) {\n\t\titemRect.left = viewportRect.left;\n\t} else {\n\t\titemRect.right = viewportRect.right;\n\t}\n\tif ( this.getVerticalAnchorEdge() === 'bottom' ) {\n\t\titemRect.top = viewportRect.top;\n\t} else {\n\t\titemRect.bottom = viewportRect.bottom;\n\t}\n\n\tavailableRect = rectIntersection( viewportRect, itemRect );\n\n\tdesiredWidth = Math.max( 0, availableRect.right - availableRect.left );\n\tdesiredHeight = Math.max( 0, availableRect.bottom - availableRect.top );\n\t// It should never be desirable to exceed the dimensions of the browser viewport... right?\n\tdesiredWidth = Math.min( desiredWidth,\n\t\tdocument.documentElement.clientWidth - viewportSpacing.left - viewportSpacing.right );\n\tdesiredHeight = Math.min( desiredHeight,\n\t\tdocument.documentElement.clientHeight - viewportSpacing.top - viewportSpacing.right );\n\tallotedWidth = Math.ceil( desiredWidth - extraWidth );\n\tallotedHeight = Math.ceil( desiredHeight - extraHeight );\n\tnaturalWidth = this.$clippable.prop( 'scrollWidth' );\n\tnaturalHeight = this.$clippable.prop( 'scrollHeight' );\n\tclipWidth = allotedWidth < naturalWidth;\n\tclipHeight = allotedHeight < naturalHeight;\n\n\tif ( clipWidth ) {\n\t\t// The order matters here. If overflow is not set first, Chrome displays bogus scrollbars.\n\t\t// See T157672.\n\t\t// Forcing a reflow is a smaller workaround than calling reconsiderScrollbars() for\n\t\t// this case.\n\t\tthis.$clippable.css( 'overflowX', 'scroll' );\n\t\t// eslint-disable-next-line no-void\n\t\tvoid this.$clippable[ 0 ].offsetHeight; // Force reflow\n\t\tthis.$clippable.css( {\n\t\t\twidth: Math.max( 0, allotedWidth ),\n\t\t\tmaxWidth: ''\n\t\t} );\n\t} else {\n\t\tthis.$clippable.css( {\n\t\t\toverflowX: '',\n\t\t\twidth: this.idealWidth || '',\n\t\t\tmaxWidth: Math.max( 0, allotedWidth )\n\t\t} );\n\t}\n\tif ( clipHeight ) {\n\t\t// The order matters here. If overflow is not set first, Chrome displays bogus scrollbars.\n\t\t// See T157672.\n\t\t// Forcing a reflow is a smaller workaround than calling reconsiderScrollbars() for\n\t\t// this case.\n\t\tthis.$clippable.css( 'overflowY', 'scroll' );\n\t\t// eslint-disable-next-line no-void\n\t\tvoid this.$clippable[ 0 ].offsetHeight; // Force reflow\n\t\tthis.$clippable.css( {\n\t\t\theight: Math.max( 0, allotedHeight ),\n\t\t\tmaxHeight: ''\n\t\t} );\n\t} else {\n\t\tthis.$clippable.css( {\n\t\t\toverflowY: '',\n\t\t\theight: this.idealHeight || '',\n\t\t\tmaxHeight: Math.max( 0, allotedHeight )\n\t\t} );\n\t}\n\n\t// If we stopped clipping in at least one of the dimensions\n\tif ( ( this.clippedHorizontally && !clipWidth ) || ( this.clippedVertically && !clipHeight ) ) {\n\t\tOO.ui.Element.static.reconsiderScrollbars( this.$clippable[ 0 ] );\n\t}\n\n\tthis.clippedHorizontally = clipWidth;\n\tthis.clippedVertically = clipHeight;\n\n\treturn this;\n};\n","/**\n * PopupWidget is a container for content. The popup is overlaid and positioned absolutely.\n * By default, each popup has an anchor that points toward its origin.\n * Please see the [OOUI documentation on MediaWiki.org] [1] for more information and examples.\n *\n * Unlike most widgets, PopupWidget is initially hidden and must be shown by calling #toggle.\n *\n *     @example\n *     // A PopupWidget.\n *     var popup = new OO.ui.PopupWidget( {\n *         $content: $( '<p>Hi there!</p>' ),\n *         padded: true,\n *         width: 300\n *     } );\n *\n *     $( document.body ).append( popup.$element );\n *     // To display the popup, toggle the visibility to 'true'.\n *     popup.toggle( true );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Popups\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.ClippableElement\n * @mixins OO.ui.mixin.FloatableElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {number|null} [width=320] Width of popup in pixels. Pass `null` to use automatic width.\n * @cfg {number|null} [height=null] Height of popup in pixels. Pass `null` to use automatic height.\n * @cfg {boolean} [anchor=true] Show anchor pointing to origin of popup\n * @cfg {string} [position='below'] Where to position the popup relative to $floatableContainer\n *  'above': Put popup above $floatableContainer; anchor points down to the horizontal center\n *    of $floatableContainer\n *  'below': Put popup below $floatableContainer; anchor points up to the horizontal center\n *    of $floatableContainer\n *  'before': Put popup to the left (LTR) / right (RTL) of $floatableContainer; anchor points\n *    endwards (right/left) to the vertical center of $floatableContainer\n *  'after': Put popup to the right (LTR) / left (RTL) of $floatableContainer; anchor points\n *    startwards (left/right) to the vertical center of $floatableContainer\n * @cfg {string} [align='center'] How to align the popup to $floatableContainer\n *  'forwards': If position is above/below, move the popup as far endwards (right in LTR, left in\n *    RTL) as possible while still keeping the anchor within the popup; if position is before/after,\n *    move the popup as far downwards as possible.\n *  'backwards': If position is above/below, move the popup as far startwards (left in LTR, right in\n *    RTL) as possible while still keeping the anchor within the popup; if position is before/after,\n *     move the popup as far upwards as possible.\n *  'center': Horizontally (if position is above/below) or vertically (before/after) align the\n *     center of the popup with the center of $floatableContainer.\n * 'force-left': Alias for 'forwards' in LTR and 'backwards' in RTL\n * 'force-right': Alias for 'backwards' in RTL and 'forwards' in LTR\n * @cfg {boolean} [autoFlip=true] Whether to automatically switch the popup's position between\n *  'above' and 'below', or between 'before' and 'after', if there is not enough space in the\n *  desired direction to display the popup without clipping\n * @cfg {jQuery} [$container] Constrain the popup to the boundaries of the specified container.\n *  See the [OOUI docs on MediaWiki][3] for an example.\n *  [3]: https://www.mediawiki.org/wiki/OOUI/Widgets/Popups#containerExample\n * @cfg {number} [containerPadding=10] Padding between the popup and its container, specified as a\n *  number of pixels.\n * @cfg {jQuery} [$content] Content to append to the popup's body\n * @cfg {jQuery} [$footer] Content to append to the popup's footer\n * @cfg {boolean} [autoClose=false] Automatically close the popup when it loses focus.\n * @cfg {jQuery} [$autoCloseIgnore] Elements that will not close the popup when clicked.\n *  This config option is only relevant if #autoClose is set to `true`. See the\n *  [OOUI documentation on MediaWiki][2] for an example.\n *  [2]: https://www.mediawiki.org/wiki/OOUI/Widgets/Popups#autocloseExample\n * @cfg {boolean} [head=false] Show a popup header that contains a #label (if specified) and close\n *  button.\n * @cfg {boolean} [padded=false] Add padding to the popup's body\n */\nOO.ui.PopupWidget = function OoUiPopupWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.PopupWidget.parent.call( this, config );\n\n\t// Properties (must be set before ClippableElement constructor call)\n\tthis.$body = $( '<div>' );\n\tthis.$popup = $( '<div>' );\n\n\t// Mixin constructors\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.ClippableElement.call( this, $.extend( {\n\t\t$clippable: this.$body,\n\t\t$clippableContainer: this.$popup\n\t}, config ) );\n\tOO.ui.mixin.FloatableElement.call( this, config );\n\n\t// Properties\n\tthis.$anchor = $( '<div>' );\n\t// If undefined, will be computed lazily in computePosition()\n\tthis.$container = config.$container;\n\tthis.containerPadding = config.containerPadding !== undefined ? config.containerPadding : 10;\n\tthis.autoClose = !!config.autoClose;\n\tthis.transitionTimeout = null;\n\tthis.anchored = false;\n\tthis.onDocumentMouseDownHandler = this.onDocumentMouseDown.bind( this );\n\tthis.onDocumentKeyDownHandler = this.onDocumentKeyDown.bind( this );\n\n\t// Initialization\n\tthis.setSize( config.width, config.height );\n\tthis.toggleAnchor( config.anchor === undefined || config.anchor );\n\tthis.setAlignment( config.align || 'center' );\n\tthis.setPosition( config.position || 'below' );\n\tthis.setAutoFlip( config.autoFlip === undefined || config.autoFlip );\n\tthis.setAutoCloseIgnore( config.$autoCloseIgnore );\n\tthis.$body.addClass( 'oo-ui-popupWidget-body' );\n\tthis.$anchor.addClass( 'oo-ui-popupWidget-anchor' );\n\tthis.$popup\n\t\t.addClass( 'oo-ui-popupWidget-popup' )\n\t\t.append( this.$body );\n\tthis.$element\n\t\t.addClass( 'oo-ui-popupWidget' )\n\t\t.append( this.$popup, this.$anchor );\n\t// Move content, which was added to #$element by OO.ui.Widget, to the body\n\t// FIXME This is gross, we should use '$body' or something for the config\n\tif ( config.$content instanceof $ ) {\n\t\tthis.$body.append( config.$content );\n\t}\n\n\tif ( config.padded ) {\n\t\tthis.$body.addClass( 'oo-ui-popupWidget-body-padded' );\n\t}\n\n\tif ( config.head ) {\n\t\tthis.closeButton = new OO.ui.ButtonWidget( {\n\t\t\tframed: false,\n\t\t\ticon: 'close'\n\t\t} );\n\t\tthis.closeButton.connect( this, {\n\t\t\tclick: 'onCloseButtonClick'\n\t\t} );\n\t\tthis.$head = $( '<div>' )\n\t\t\t.addClass( 'oo-ui-popupWidget-head' )\n\t\t\t.append( this.$label, this.closeButton.$element );\n\t\tthis.$popup.prepend( this.$head );\n\t}\n\n\tif ( config.$footer ) {\n\t\tthis.$footer = $( '<div>' )\n\t\t\t.addClass( 'oo-ui-popupWidget-footer' )\n\t\t\t.append( config.$footer );\n\t\tthis.$popup.append( this.$footer );\n\t}\n\n\t// Initially hidden - using #toggle may cause errors if subclasses override toggle with methods\n\t// that reference properties not initialized at that time of parent class construction\n\t// TODO: Find a better way to handle post-constructor setup\n\tthis.visible = false;\n\tthis.$element.addClass( 'oo-ui-element-hidden' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.PopupWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.PopupWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.PopupWidget, OO.ui.mixin.ClippableElement );\nOO.mixinClass( OO.ui.PopupWidget, OO.ui.mixin.FloatableElement );\n\n/* Events */\n\n/**\n * @event ready\n *\n * The popup is ready: it is visible and has been positioned and clipped.\n */\n\n/* Methods */\n\n/**\n * Handles document mouse down events.\n *\n * @private\n * @param {MouseEvent} e Mouse down event\n */\nOO.ui.PopupWidget.prototype.onDocumentMouseDown = function ( e ) {\n\tif (\n\t\tthis.isVisible() &&\n\t\t!OO.ui.contains( this.$element.add( this.$autoCloseIgnore ).get(), e.target, true )\n\t) {\n\t\tthis.toggle( false );\n\t}\n};\n\n/**\n * Bind document mouse down listener.\n *\n * @private\n */\nOO.ui.PopupWidget.prototype.bindDocumentMouseDownListener = function () {\n\t// Capture clicks outside popup\n\tthis.getElementDocument().addEventListener( 'mousedown', this.onDocumentMouseDownHandler, true );\n\t// We add 'click' event because iOS safari needs to respond to this event.\n\t// We can't use 'touchstart' (as is usually the equivalent to 'mousedown') because\n\t// then it will trigger when scrolling. While iOS Safari has some reported behavior\n\t// of occasionally not emitting 'click' properly, that event seems to be the standard\n\t// that it should be emitting, so we add it to this and will operate the event handler\n\t// on whichever of these events was triggered first\n\tthis.getElementDocument().addEventListener( 'click', this.onDocumentMouseDownHandler, true );\n};\n\n/**\n * Handles close button click events.\n *\n * @private\n */\nOO.ui.PopupWidget.prototype.onCloseButtonClick = function () {\n\tif ( this.isVisible() ) {\n\t\tthis.toggle( false );\n\t}\n};\n\n/**\n * Unbind document mouse down listener.\n *\n * @private\n */\nOO.ui.PopupWidget.prototype.unbindDocumentMouseDownListener = function () {\n\tthis.getElementDocument().removeEventListener( 'mousedown', this.onDocumentMouseDownHandler, true );\n\tthis.getElementDocument().removeEventListener( 'click', this.onDocumentMouseDownHandler, true );\n};\n\n/**\n * Handles document key down events.\n *\n * @private\n * @param {KeyboardEvent} e Key down event\n */\nOO.ui.PopupWidget.prototype.onDocumentKeyDown = function ( e ) {\n\tif (\n\t\te.which === OO.ui.Keys.ESCAPE &&\n\t\tthis.isVisible()\n\t) {\n\t\tthis.toggle( false );\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t}\n};\n\n/**\n * Bind document key down listener.\n *\n * @private\n */\nOO.ui.PopupWidget.prototype.bindDocumentKeyDownListener = function () {\n\tthis.getElementDocument().addEventListener( 'keydown', this.onDocumentKeyDownHandler, true );\n};\n\n/**\n * Unbind document key down listener.\n *\n * @private\n */\nOO.ui.PopupWidget.prototype.unbindDocumentKeyDownListener = function () {\n\tthis.getElementDocument().removeEventListener( 'keydown', this.onDocumentKeyDownHandler, true );\n};\n\n/**\n * Show, hide, or toggle the visibility of the anchor.\n *\n * @param {boolean} [show] Show anchor, omit to toggle\n */\nOO.ui.PopupWidget.prototype.toggleAnchor = function ( show ) {\n\tshow = show === undefined ? !this.anchored : !!show;\n\n\tif ( this.anchored !== show ) {\n\t\tif ( show ) {\n\t\t\tthis.$element.addClass( 'oo-ui-popupWidget-anchored' );\n\t\t\tthis.$element.addClass( 'oo-ui-popupWidget-anchored-' + this.anchorEdge );\n\t\t} else {\n\t\t\tthis.$element.removeClass( 'oo-ui-popupWidget-anchored' );\n\t\t\tthis.$element.removeClass( 'oo-ui-popupWidget-anchored-' + this.anchorEdge );\n\t\t}\n\t\tthis.anchored = show;\n\t}\n};\n\n/**\n * Change which edge the anchor appears on.\n *\n * @param {string} edge 'top', 'bottom', 'start' or 'end'\n */\nOO.ui.PopupWidget.prototype.setAnchorEdge = function ( edge ) {\n\tif ( [ 'top', 'bottom', 'start', 'end' ].indexOf( edge ) === -1 ) {\n\t\tthrow new Error( 'Invalid value for edge: ' + edge );\n\t}\n\tif ( this.anchorEdge !== null ) {\n\t\tthis.$element.removeClass( 'oo-ui-popupWidget-anchored-' + this.anchorEdge );\n\t}\n\tthis.anchorEdge = edge;\n\tif ( this.anchored ) {\n\t\tthis.$element.addClass( 'oo-ui-popupWidget-anchored-' + edge );\n\t}\n};\n\n/**\n * Check if the anchor is visible.\n *\n * @return {boolean} Anchor is visible\n */\nOO.ui.PopupWidget.prototype.hasAnchor = function () {\n\treturn this.anchored;\n};\n\n/**\n * Toggle visibility of the popup. The popup is initially hidden and must be shown by calling\n * `.toggle( true )` after its #$element is attached to the DOM.\n *\n * Do not show the popup while it is not attached to the DOM. The calculations required to display\n * it in the right place and with the right dimensions only work correctly while it is attached.\n * Side-effects may include broken interface and exceptions being thrown. This wasn't always\n * strictly enforced, so currently it only generates a warning in the browser console.\n *\n * @fires ready\n * @inheritdoc\n */\nOO.ui.PopupWidget.prototype.toggle = function ( show ) {\n\tvar change, normalHeight, oppositeHeight, normalWidth, oppositeWidth;\n\tshow = show === undefined ? !this.isVisible() : !!show;\n\n\tchange = show !== this.isVisible();\n\n\tif ( show && !this.warnedUnattached && !this.isElementAttached() ) {\n\t\tOO.ui.warnDeprecation( 'PopupWidget#toggle: Before calling this method, the popup must be attached to the DOM.' );\n\t\tthis.warnedUnattached = true;\n\t}\n\tif ( show && !this.$floatableContainer && this.isElementAttached() ) {\n\t\t// Fall back to the parent node if the floatableContainer is not set\n\t\tthis.setFloatableContainer( this.$element.parent() );\n\t}\n\n\tif ( change && show && this.autoFlip ) {\n\t\t// Reset auto-flipping before showing the popup again. It's possible we no longer need to\n\t\t// flip (e.g. if the user scrolled).\n\t\tthis.isAutoFlipped = false;\n\t}\n\n\t// Parent method\n\tOO.ui.PopupWidget.parent.prototype.toggle.call( this, show );\n\n\tif ( change ) {\n\t\tthis.togglePositioning( show && !!this.$floatableContainer );\n\n\t\tif ( show ) {\n\t\t\tif ( this.autoClose ) {\n\t\t\t\tthis.bindDocumentMouseDownListener();\n\t\t\t\tthis.bindDocumentKeyDownListener();\n\t\t\t}\n\t\t\tthis.updateDimensions();\n\t\t\tthis.toggleClipping( true );\n\n\t\t\tif ( this.autoFlip ) {\n\t\t\t\tif ( this.popupPosition === 'above' || this.popupPosition === 'below' ) {\n\t\t\t\t\tif ( this.isClippedVertically() || this.isFloatableOutOfView() ) {\n\t\t\t\t\t\t// If opening the popup in the normal direction causes it to be clipped,\n\t\t\t\t\t\t// open in the opposite one instead\n\t\t\t\t\t\tnormalHeight = this.$element.height();\n\t\t\t\t\t\tthis.isAutoFlipped = !this.isAutoFlipped;\n\t\t\t\t\t\tthis.position();\n\t\t\t\t\t\tif ( this.isClippedVertically() || this.isFloatableOutOfView() ) {\n\t\t\t\t\t\t\t// If that also causes it to be clipped, open in whichever direction\n\t\t\t\t\t\t\t// we have more space\n\t\t\t\t\t\t\toppositeHeight = this.$element.height();\n\t\t\t\t\t\t\tif ( oppositeHeight < normalHeight ) {\n\t\t\t\t\t\t\t\tthis.isAutoFlipped = !this.isAutoFlipped;\n\t\t\t\t\t\t\t\tthis.position();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif ( this.popupPosition === 'before' || this.popupPosition === 'after' ) {\n\t\t\t\t\tif ( this.isClippedHorizontally() || this.isFloatableOutOfView() ) {\n\t\t\t\t\t\t// If opening the popup in the normal direction causes it to be clipped,\n\t\t\t\t\t\t// open in the opposite one instead\n\t\t\t\t\t\tnormalWidth = this.$element.width();\n\t\t\t\t\t\tthis.isAutoFlipped = !this.isAutoFlipped;\n\t\t\t\t\t\t// Due to T180173 horizontally clipped PopupWidgets have messed up\n\t\t\t\t\t\t// dimensions, which causes positioning to be off. Toggle clipping back and\n\t\t\t\t\t\t// forth to work around.\n\t\t\t\t\t\tthis.toggleClipping( false );\n\t\t\t\t\t\tthis.position();\n\t\t\t\t\t\tthis.toggleClipping( true );\n\t\t\t\t\t\tif ( this.isClippedHorizontally() || this.isFloatableOutOfView() ) {\n\t\t\t\t\t\t\t// If that also causes it to be clipped, open in whichever direction\n\t\t\t\t\t\t\t// we have more space\n\t\t\t\t\t\t\toppositeWidth = this.$element.width();\n\t\t\t\t\t\t\tif ( oppositeWidth < normalWidth ) {\n\t\t\t\t\t\t\t\tthis.isAutoFlipped = !this.isAutoFlipped;\n\t\t\t\t\t\t\t\t// Due to T180173, horizontally clipped PopupWidgets have messed up\n\t\t\t\t\t\t\t\t// dimensions, which causes positioning to be off. Toggle clipping\n\t\t\t\t\t\t\t\t// back and forth to work around.\n\t\t\t\t\t\t\t\tthis.toggleClipping( false );\n\t\t\t\t\t\t\t\tthis.position();\n\t\t\t\t\t\t\t\tthis.toggleClipping( true );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.emit( 'ready' );\n\t\t} else {\n\t\t\tthis.toggleClipping( false );\n\t\t\tif ( this.autoClose ) {\n\t\t\t\tthis.unbindDocumentMouseDownListener();\n\t\t\t\tthis.unbindDocumentKeyDownListener();\n\t\t\t}\n\t\t}\n\t}\n\n\treturn this;\n};\n\n/**\n * Set the size of the popup.\n *\n * Changing the size may also change the popup's position depending on the alignment.\n *\n * @param {number|null} [width=320] Width in pixels. Pass `null` to use automatic width.\n * @param {number|null} [height=null] Height in pixels. Pass `null` to use automatic height.\n * @param {boolean} [transition=false] Use a smooth transition\n * @chainable\n */\nOO.ui.PopupWidget.prototype.setSize = function ( width, height, transition ) {\n\tthis.width = width !== undefined ? width : 320;\n\tthis.height = height !== undefined ? height : null;\n\tif ( this.isVisible() ) {\n\t\tthis.updateDimensions( transition );\n\t}\n};\n\n/**\n * Update the size and position.\n *\n * Only use this to keep the popup properly anchored. Use #setSize to change the size, and this will\n * be called automatically.\n *\n * @param {boolean} [transition=false] Use a smooth transition\n * @chainable\n */\nOO.ui.PopupWidget.prototype.updateDimensions = function ( transition ) {\n\tvar widget = this;\n\n\t// Prevent transition from being interrupted\n\tclearTimeout( this.transitionTimeout );\n\tif ( transition ) {\n\t\t// Enable transition\n\t\tthis.$element.addClass( 'oo-ui-popupWidget-transitioning' );\n\t}\n\n\tthis.position();\n\n\tif ( transition ) {\n\t\t// Prevent transitioning after transition is complete\n\t\tthis.transitionTimeout = setTimeout( function () {\n\t\t\twidget.$element.removeClass( 'oo-ui-popupWidget-transitioning' );\n\t\t}, 200 );\n\t} else {\n\t\t// Prevent transitioning immediately\n\t\tthis.$element.removeClass( 'oo-ui-popupWidget-transitioning' );\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.PopupWidget.prototype.computePosition = function () {\n\tvar direction, align, vertical, start, end, near, far, sizeProp, popupSize, anchorSize,\n\t\tanchorPos, anchorOffset, anchorMargin, parentPosition, positionProp, positionAdjustment,\n\t\tfloatablePos, offsetParentPos, containerPos, popupPosition, viewportSpacing,\n\t\tpopupPos = {},\n\t\tanchorCss = { left: '', right: '', top: '', bottom: '' },\n\t\tpopupPositionOppositeMap = {\n\t\t\tabove: 'below',\n\t\t\tbelow: 'above',\n\t\t\tbefore: 'after',\n\t\t\tafter: 'before'\n\t\t},\n\t\talignMap = {\n\t\t\tltr: {\n\t\t\t\t'force-left': 'backwards',\n\t\t\t\t'force-right': 'forwards'\n\t\t\t},\n\t\t\trtl: {\n\t\t\t\t'force-left': 'forwards',\n\t\t\t\t'force-right': 'backwards'\n\t\t\t}\n\t\t},\n\t\tanchorEdgeMap = {\n\t\t\tabove: 'bottom',\n\t\t\tbelow: 'top',\n\t\t\tbefore: 'end',\n\t\t\tafter: 'start'\n\t\t},\n\t\thPosMap = {\n\t\t\tforwards: 'start',\n\t\t\tcenter: 'center',\n\t\t\tbackwards: this.anchored ? 'before' : 'end'\n\t\t},\n\t\tvPosMap = {\n\t\t\tforwards: 'top',\n\t\t\tcenter: 'center',\n\t\t\tbackwards: 'bottom'\n\t\t};\n\n\tif ( !this.$container ) {\n\t\t// Lazy-initialize $container if not specified in constructor\n\t\tthis.$container = $( this.getClosestScrollableElementContainer() );\n\t}\n\tdirection = this.$container.css( 'direction' );\n\n\t// Set height and width before we do anything else, since it might cause our measurements\n\t// to change (e.g. due to scrollbars appearing or disappearing), and it also affects centering\n\tthis.$popup.css( {\n\t\twidth: this.width !== null ? this.width : 'auto',\n\t\theight: this.height !== null ? this.height : 'auto'\n\t} );\n\n\talign = alignMap[ direction ][ this.align ] || this.align;\n\tpopupPosition = this.popupPosition;\n\tif ( this.isAutoFlipped ) {\n\t\tpopupPosition = popupPositionOppositeMap[ popupPosition ];\n\t}\n\n\t// If the popup is positioned before or after, then the anchor positioning is vertical,\n\t// otherwise horizontal\n\tvertical = popupPosition === 'before' || popupPosition === 'after';\n\tstart = vertical ? 'top' : ( direction === 'rtl' ? 'right' : 'left' );\n\tend = vertical ? 'bottom' : ( direction === 'rtl' ? 'left' : 'right' );\n\tnear = vertical ? 'top' : 'left';\n\tfar = vertical ? 'bottom' : 'right';\n\tsizeProp = vertical ? 'Height' : 'Width';\n\tpopupSize = vertical ?\n\t\t( this.height || this.$popup.height() ) :\n\t\t( this.width || this.$popup.width() );\n\n\tthis.setAnchorEdge( anchorEdgeMap[ popupPosition ] );\n\tthis.horizontalPosition = vertical ? popupPosition : hPosMap[ align ];\n\tthis.verticalPosition = vertical ? vPosMap[ align ] : popupPosition;\n\n\t// Parent method\n\tparentPosition = OO.ui.mixin.FloatableElement.prototype.computePosition.call( this );\n\t// Find out which property FloatableElement used for positioning, and adjust that value\n\tpositionProp = vertical ?\n\t\t( parentPosition.top !== '' ? 'top' : 'bottom' ) :\n\t\t( parentPosition.left !== '' ? 'left' : 'right' );\n\n\t// Figure out where the near and far edges of the popup and $floatableContainer are\n\tfloatablePos = this.$floatableContainer.offset();\n\tfloatablePos[ far ] = floatablePos[ near ] + this.$floatableContainer[ 'outer' + sizeProp ]();\n\t// Measure where the offsetParent is and compute our position based on that and parentPosition\n\toffsetParentPos = this.$element.offsetParent()[ 0 ] === document.documentElement ?\n\t\t{ top: 0, left: 0 } :\n\t\tthis.$element.offsetParent().offset();\n\n\tif ( positionProp === near ) {\n\t\tpopupPos[ near ] = offsetParentPos[ near ] + parentPosition[ near ];\n\t\tpopupPos[ far ] = popupPos[ near ] + popupSize;\n\t} else {\n\t\tpopupPos[ far ] = offsetParentPos[ near ] +\n\t\t\tthis.$element.offsetParent()[ 'inner' + sizeProp ]() - parentPosition[ far ];\n\t\tpopupPos[ near ] = popupPos[ far ] - popupSize;\n\t}\n\n\tif ( this.anchored ) {\n\t\t// Position the anchor (which is positioned relative to the popup) to point to\n\t\t// $floatableContainer\n\t\tanchorPos = ( floatablePos[ start ] + floatablePos[ end ] ) / 2;\n\t\tanchorOffset = ( start === far ? -1 : 1 ) * ( anchorPos - popupPos[ start ] );\n\n\t\t// If the anchor is less than 2*anchorSize from either edge, move the popup to make more\n\t\t// space this.$anchor.width()/height() returns 0 because of the CSS trickery we use, so use\n\t\t// scrollWidth/Height\n\t\tanchorSize = this.$anchor[ 0 ][ 'scroll' + sizeProp ];\n\t\tanchorMargin = parseFloat( this.$anchor.css( 'margin-' + start ) );\n\t\tif ( anchorOffset + anchorMargin < 2 * anchorSize ) {\n\t\t\t// Not enough space for the anchor on the start side; pull the popup startwards\n\t\t\tpositionAdjustment = ( positionProp === start ? -1 : 1 ) *\n\t\t\t\t( 2 * anchorSize - ( anchorOffset + anchorMargin ) );\n\t\t} else if ( anchorOffset + anchorMargin > popupSize - 2 * anchorSize ) {\n\t\t\t// Not enough space for the anchor on the end side; pull the popup endwards\n\t\t\tpositionAdjustment = ( positionProp === end ? -1 : 1 ) *\n\t\t\t\t( anchorOffset + anchorMargin - ( popupSize - 2 * anchorSize ) );\n\t\t} else {\n\t\t\tpositionAdjustment = 0;\n\t\t}\n\t} else {\n\t\tpositionAdjustment = 0;\n\t}\n\n\t// Check if the popup will go beyond the edge of this.$container\n\tcontainerPos = this.$container[ 0 ] === document.documentElement ?\n\t\t{ top: 0, left: 0 } :\n\t\tthis.$container.offset();\n\tcontainerPos[ far ] = containerPos[ near ] + this.$container[ 'inner' + sizeProp ]();\n\tif ( this.$container[ 0 ] === document.documentElement ) {\n\t\tviewportSpacing = OO.ui.getViewportSpacing();\n\t\tcontainerPos[ near ] += viewportSpacing[ near ];\n\t\tcontainerPos[ far ] -= viewportSpacing[ far ];\n\t}\n\t// Take into account how much the popup will move because of the adjustments we're going to make\n\tpopupPos[ near ] += ( positionProp === near ? 1 : -1 ) * positionAdjustment;\n\tpopupPos[ far ] += ( positionProp === near ? 1 : -1 ) * positionAdjustment;\n\tif ( containerPos[ near ] + this.containerPadding > popupPos[ near ] ) {\n\t\t// Popup goes beyond the near (left/top) edge, move it to the right/bottom\n\t\tpositionAdjustment += ( positionProp === near ? 1 : -1 ) *\n\t\t\t( containerPos[ near ] + this.containerPadding - popupPos[ near ] );\n\t} else if ( containerPos[ far ] - this.containerPadding < popupPos[ far ] ) {\n\t\t// Popup goes beyond the far (right/bottom) edge, move it to the left/top\n\t\tpositionAdjustment += ( positionProp === far ? 1 : -1 ) *\n\t\t\t( popupPos[ far ] - ( containerPos[ far ] - this.containerPadding ) );\n\t}\n\n\tif ( this.anchored ) {\n\t\t// Adjust anchorOffset for positionAdjustment\n\t\tanchorOffset += ( positionProp === start ? -1 : 1 ) * positionAdjustment;\n\n\t\t// Position the anchor\n\t\tanchorCss[ start ] = anchorOffset;\n\t\tthis.$anchor.css( anchorCss );\n\t}\n\n\t// Move the popup if needed\n\tparentPosition[ positionProp ] += positionAdjustment;\n\n\treturn parentPosition;\n};\n\n/**\n * Set popup alignment\n *\n * @param {string} [align=center] Alignment of the popup, `center`, `force-left`, `force-right`,\n *  `backwards` or `forwards`.\n */\nOO.ui.PopupWidget.prototype.setAlignment = function ( align ) {\n\t// Validate alignment\n\tif ( [ 'force-left', 'force-right', 'backwards', 'forwards', 'center' ].indexOf( align ) > -1 ) {\n\t\tthis.align = align;\n\t} else {\n\t\tthis.align = 'center';\n\t}\n\tthis.position();\n};\n\n/**\n * Get popup alignment\n *\n * @return {string} Alignment of the popup, `center`, `force-left`, `force-right`,\n *  `backwards` or `forwards`.\n */\nOO.ui.PopupWidget.prototype.getAlignment = function () {\n\treturn this.align;\n};\n\n/**\n * Change the positioning of the popup.\n *\n * @param {string} position 'above', 'below', 'before' or 'after'\n */\nOO.ui.PopupWidget.prototype.setPosition = function ( position ) {\n\tif ( [ 'above', 'below', 'before', 'after' ].indexOf( position ) === -1 ) {\n\t\tposition = 'below';\n\t}\n\tthis.popupPosition = position;\n\tthis.position();\n};\n\n/**\n * Get popup positioning.\n *\n * @return {string} 'above', 'below', 'before' or 'after'\n */\nOO.ui.PopupWidget.prototype.getPosition = function () {\n\treturn this.popupPosition;\n};\n\n/**\n * Set popup auto-flipping.\n *\n * @param {boolean} autoFlip Whether to automatically switch the popup's position between\n *  'above' and 'below', or between 'before' and 'after', if there is not enough space in the\n *  desired direction to display the popup without clipping\n */\nOO.ui.PopupWidget.prototype.setAutoFlip = function ( autoFlip ) {\n\tautoFlip = !!autoFlip;\n\n\tif ( this.autoFlip !== autoFlip ) {\n\t\tthis.autoFlip = autoFlip;\n\t}\n};\n\n/**\n * Set which elements will not close the popup when clicked.\n *\n * For auto-closing popups, clicks on these elements will not cause the popup to auto-close.\n *\n * @param {jQuery} $autoCloseIgnore Elements to ignore for auto-closing\n */\nOO.ui.PopupWidget.prototype.setAutoCloseIgnore = function ( $autoCloseIgnore ) {\n\tthis.$autoCloseIgnore = $autoCloseIgnore;\n};\n\n/**\n * Get an ID of the body element, this can be used as the\n * `aria-describedby` attribute for an input field.\n *\n * @return {string} The ID of the body element\n */\nOO.ui.PopupWidget.prototype.getBodyId = function () {\n\tvar id = this.$body.attr( 'id' );\n\tif ( id === undefined ) {\n\t\tid = OO.ui.generateElementId();\n\t\tthis.$body.attr( 'id', id );\n\t}\n\treturn id;\n};\n","/**\n * PopupElement is mixed into other classes to generate a {@link OO.ui.PopupWidget popup widget}.\n * A popup is a container for content. It is overlaid and positioned absolutely. By default, each\n * popup has an anchor, which is an arrow-like protrusion that points toward the popup’s origin.\n * See {@link OO.ui.PopupWidget PopupWidget} for an example.\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {Object} [popup] Configuration to pass to popup\n * @cfg {boolean} [popup.autoClose=true] Popup auto-closes when it loses focus\n */\nOO.ui.mixin.PopupElement = function OoUiMixinPopupElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.popup = new OO.ui.PopupWidget( $.extend(\n\t\t{\n\t\t\tautoClose: true,\n\t\t\t$floatableContainer: this.$element\n\t\t},\n\t\tconfig.popup,\n\t\t{\n\t\t\t$autoCloseIgnore: this.$element.add( config.popup && config.popup.$autoCloseIgnore )\n\t\t}\n\t) );\n};\n\n/* Methods */\n\n/**\n * Get popup.\n *\n * @return {OO.ui.PopupWidget} Popup widget\n */\nOO.ui.mixin.PopupElement.prototype.getPopup = function () {\n\treturn this.popup;\n};\n","/**\n * PopupButtonWidgets toggle the visibility of a contained {@link OO.ui.PopupWidget PopupWidget},\n * which is used to display additional information or options.\n *\n *     @example\n *     // A PopupButtonWidget.\n *     var popupButton = new OO.ui.PopupButtonWidget( {\n *         label: 'Popup button with options',\n *         icon: 'menu',\n *         popup: {\n *             $content: $( '<p>Additional options here.</p>' ),\n *             padded: true,\n *             align: 'force-left'\n *         }\n *     } );\n *     // Append the button to the DOM.\n *     $( document.body ).append( popupButton.$element );\n *\n * @class\n * @extends OO.ui.ButtonWidget\n * @mixins OO.ui.mixin.PopupElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$overlay] Render the popup into a separate layer. This configuration is useful\n *  in cases where the expanded popup is larger than its containing `<div>`. The specified overlay\n *  layer is usually on top of the containing `<div>` and has a larger area. By default, the popup\n *  uses relative positioning.\n *  See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.\n */\nOO.ui.PopupButtonWidget = function OoUiPopupButtonWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.PopupButtonWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.PopupElement.call( this, config );\n\n\t// Properties\n\tthis.$overlay = ( config.$overlay === true ?\n\t\tOO.ui.getDefaultOverlay() : config.$overlay ) || this.$element;\n\n\t// Events\n\tthis.connect( this, {\n\t\tclick: 'onAction'\n\t} );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-popupButtonWidget' );\n\tthis.popup.$element\n\t\t.addClass( 'oo-ui-popupButtonWidget-popup' )\n\t\t.toggleClass( 'oo-ui-popupButtonWidget-framed-popup', this.isFramed() )\n\t\t.toggleClass( 'oo-ui-popupButtonWidget-frameless-popup', !this.isFramed() );\n\tthis.$overlay.append( this.popup.$element );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.PopupButtonWidget, OO.ui.ButtonWidget );\nOO.mixinClass( OO.ui.PopupButtonWidget, OO.ui.mixin.PopupElement );\n\n/* Methods */\n\n/**\n * Handle the button action being triggered.\n *\n * @private\n */\nOO.ui.PopupButtonWidget.prototype.onAction = function () {\n\tthis.popup.toggle();\n};\n","/**\n * Mixin for OO.ui.Widget subclasses to provide OO.ui.mixin.GroupElement.\n *\n * Use together with OO.ui.mixin.ItemWidget to make disabled state inheritable.\n *\n * @private\n * @abstract\n * @class\n * @mixins OO.ui.mixin.GroupElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.mixin.GroupWidget = function OoUiMixinGroupWidget( config ) {\n\t// Mixin constructors\n\tOO.ui.mixin.GroupElement.call( this, config );\n};\n\n/* Setup */\n\nOO.mixinClass( OO.ui.mixin.GroupWidget, OO.ui.mixin.GroupElement );\n\n/* Methods */\n\n/**\n * Set the disabled state of the widget.\n *\n * This will also update the disabled state of child widgets.\n *\n * @param {boolean} disabled Disable widget\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.mixin.GroupWidget.prototype.setDisabled = function ( disabled ) {\n\tvar i, len;\n\n\t// Parent method\n\t// Note: Calling #setDisabled this way assumes this is mixed into an OO.ui.Widget\n\tOO.ui.Widget.prototype.setDisabled.call( this, disabled );\n\n\t// During construction, #setDisabled is called before the OO.ui.mixin.GroupElement constructor\n\tif ( this.items ) {\n\t\tfor ( i = 0, len = this.items.length; i < len; i++ ) {\n\t\t\tthis.items[ i ].updateDisabled();\n\t\t}\n\t}\n\n\treturn this;\n};\n","/**\n * Mixin for widgets used as items in widgets that mix in OO.ui.mixin.GroupWidget.\n *\n * Item widgets have a reference to a OO.ui.mixin.GroupWidget while they are attached to the group.\n * This allows bidirectional communication.\n *\n * Use together with OO.ui.mixin.GroupWidget to make disabled state inheritable.\n *\n * @private\n * @abstract\n * @class\n *\n * @constructor\n */\nOO.ui.mixin.ItemWidget = function OoUiMixinItemWidget() {\n\t//\n};\n\n/* Methods */\n\n/**\n * Check if widget is disabled.\n *\n * Checks parent if present, making disabled state inheritable.\n *\n * @return {boolean} Widget is disabled\n */\nOO.ui.mixin.ItemWidget.prototype.isDisabled = function () {\n\treturn this.disabled ||\n\t\t( this.elementGroup instanceof OO.ui.Widget && this.elementGroup.isDisabled() );\n};\n\n/**\n * Set group element is in.\n *\n * @param {OO.ui.mixin.GroupElement|null} group Group element, null if none\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.mixin.ItemWidget.prototype.setElementGroup = function ( group ) {\n\t// Parent method\n\t// Note: Calling #setElementGroup this way assumes this is mixed into an OO.ui.Element\n\tOO.ui.Element.prototype.setElementGroup.call( this, group );\n\n\t// Initialize item disabled states\n\tthis.updateDisabled();\n\n\treturn this;\n};\n","/**\n * OptionWidgets are special elements that can be selected and configured with data. The\n * data is often unique for each option, but it does not have to be. OptionWidgets are used\n * with OO.ui.SelectWidget to create a selection of mutually exclusive options. For more information\n * and examples, please see the [OOUI documentation on MediaWiki][1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.ItemWidget\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.FlaggedElement\n * @mixins OO.ui.mixin.AccessKeyedElement\n * @mixins OO.ui.mixin.TitledElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.OptionWidget = function OoUiOptionWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.OptionWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.ItemWidget.call( this );\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.FlaggedElement.call( this, config );\n\tOO.ui.mixin.AccessKeyedElement.call( this, config );\n\tOO.ui.mixin.TitledElement.call( this, config );\n\n\t// Properties\n\tthis.highlighted = false;\n\tthis.pressed = false;\n\tthis.setSelected( !!config.selected );\n\n\t// Initialization\n\tthis.$element\n\t\t.data( 'oo-ui-optionWidget', this )\n\t\t// Allow programmatic focussing (and by access key), but not tabbing\n\t\t.attr( 'tabindex', '-1' )\n\t\t.attr( 'role', 'option' )\n\t\t.addClass( 'oo-ui-optionWidget' )\n\t\t.append( this.$label );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.OptionWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.ItemWidget );\nOO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.FlaggedElement );\nOO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.AccessKeyedElement );\nOO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.TitledElement );\n\n/* Static Properties */\n\n/**\n * Whether this option can be selected. See #setSelected.\n *\n * @static\n * @inheritable\n * @property {boolean}\n */\nOO.ui.OptionWidget.static.selectable = true;\n\n/**\n * Whether this option can be highlighted. See #setHighlighted.\n *\n * @static\n * @inheritable\n * @property {boolean}\n */\nOO.ui.OptionWidget.static.highlightable = true;\n\n/**\n * Whether this option can be pressed. See #setPressed.\n *\n * @static\n * @inheritable\n * @property {boolean}\n */\nOO.ui.OptionWidget.static.pressable = true;\n\n/**\n * Whether this option will be scrolled into view when it is selected.\n *\n * @static\n * @inheritable\n * @property {boolean}\n */\nOO.ui.OptionWidget.static.scrollIntoViewOnSelect = false;\n\n/* Methods */\n\n/**\n * Check if the option can be selected.\n *\n * @return {boolean} Item is selectable\n */\nOO.ui.OptionWidget.prototype.isSelectable = function () {\n\treturn this.constructor.static.selectable && !this.disabled && this.isVisible();\n};\n\n/**\n * Check if the option can be highlighted. A highlight indicates that the option\n * may be selected when a user presses Enter key or clicks. Disabled items cannot\n * be highlighted.\n *\n * @return {boolean} Item is highlightable\n */\nOO.ui.OptionWidget.prototype.isHighlightable = function () {\n\treturn this.constructor.static.highlightable && !this.disabled && this.isVisible();\n};\n\n/**\n * Check if the option can be pressed. The pressed state occurs when a user mouses\n * down on an item, but has not yet let go of the mouse.\n *\n * @return {boolean} Item is pressable\n */\nOO.ui.OptionWidget.prototype.isPressable = function () {\n\treturn this.constructor.static.pressable && !this.disabled && this.isVisible();\n};\n\n/**\n * Check if the option is selected.\n *\n * @return {boolean} Item is selected\n */\nOO.ui.OptionWidget.prototype.isSelected = function () {\n\treturn this.selected;\n};\n\n/**\n * Check if the option is highlighted. A highlight indicates that the\n * item may be selected when a user presses Enter key or clicks.\n *\n * @return {boolean} Item is highlighted\n */\nOO.ui.OptionWidget.prototype.isHighlighted = function () {\n\treturn this.highlighted;\n};\n\n/**\n * Check if the option is pressed. The pressed state occurs when a user mouses\n * down on an item, but has not yet let go of the mouse. The item may appear\n * selected, but it will not be selected until the user releases the mouse.\n *\n * @return {boolean} Item is pressed\n */\nOO.ui.OptionWidget.prototype.isPressed = function () {\n\treturn this.pressed;\n};\n\n/**\n * Set the option’s selected state. In general, all modifications to the selection\n * should be handled by the SelectWidget’s\n * {@link OO.ui.SelectWidget#selectItem selectItem( [item] )} method instead of this method.\n *\n * @param {boolean} [state=false] Select option\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.OptionWidget.prototype.setSelected = function ( state ) {\n\tif ( this.constructor.static.selectable ) {\n\t\tthis.selected = !!state;\n\t\tthis.$element\n\t\t\t.toggleClass( 'oo-ui-optionWidget-selected', state )\n\t\t\t.attr( 'aria-selected', state.toString() );\n\t\tif ( state && this.constructor.static.scrollIntoViewOnSelect ) {\n\t\t\tthis.scrollElementIntoView();\n\t\t}\n\t\tthis.updateThemeClasses();\n\t}\n\treturn this;\n};\n\n/**\n * Set the option’s highlighted state. In general, all programmatic\n * modifications to the highlight should be handled by the\n * SelectWidget’s {@link OO.ui.SelectWidget#highlightItem highlightItem( [item] )}\n * method instead of this method.\n *\n * @param {boolean} [state=false] Highlight option\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.OptionWidget.prototype.setHighlighted = function ( state ) {\n\tif ( this.constructor.static.highlightable ) {\n\t\tthis.highlighted = !!state;\n\t\tthis.$element.toggleClass( 'oo-ui-optionWidget-highlighted', state );\n\t\tthis.updateThemeClasses();\n\t}\n\treturn this;\n};\n\n/**\n * Set the option’s pressed state. In general, all\n * programmatic modifications to the pressed state should be handled by the\n * SelectWidget’s {@link OO.ui.SelectWidget#pressItem pressItem( [item] )}\n * method instead of this method.\n *\n * @param {boolean} [state=false] Press option\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.OptionWidget.prototype.setPressed = function ( state ) {\n\tif ( this.constructor.static.pressable ) {\n\t\tthis.pressed = !!state;\n\t\tthis.$element.toggleClass( 'oo-ui-optionWidget-pressed', state );\n\t\tthis.updateThemeClasses();\n\t}\n\treturn this;\n};\n\n/**\n * Get text to match search strings against.\n *\n * The default implementation returns the label text, but subclasses\n * can override this to provide more complex behavior.\n *\n * @return {string|boolean} String to match search string against\n */\nOO.ui.OptionWidget.prototype.getMatchText = function () {\n\tvar label = this.getLabel();\n\treturn typeof label === 'string' ? label : this.$label.text();\n};\n","/**\n * A SelectWidget is of a generic selection of options. The OOUI library contains several types of\n * select widgets, including {@link OO.ui.ButtonSelectWidget button selects},\n * {@link OO.ui.RadioSelectWidget radio selects}, and {@link OO.ui.MenuSelectWidget\n * menu selects}.\n *\n * This class should be used together with OO.ui.OptionWidget or OO.ui.DecoratedOptionWidget. For\n * more information, please see the [OOUI documentation on MediaWiki][1].\n *\n *     @example\n *     // A select widget with three options.\n *     var select = new OO.ui.SelectWidget( {\n *         items: [\n *             new OO.ui.OptionWidget( {\n *                 data: 'a',\n *                 label: 'Option One',\n *             } ),\n *             new OO.ui.OptionWidget( {\n *                 data: 'b',\n *                 label: 'Option Two',\n *             } ),\n *             new OO.ui.OptionWidget( {\n *                 data: 'c',\n *                 label: 'Option Three',\n *             } )\n *         ]\n *     } );\n *     $( document.body ).append( select.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options\n *\n * @abstract\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.GroupWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {OO.ui.OptionWidget[]} [items] An array of options to add to the select.\n *  Options are created with {@link OO.ui.OptionWidget OptionWidget} classes. See\n *  the [OOUI documentation on MediaWiki] [2] for examples.\n *  [2]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options\n */\nOO.ui.SelectWidget = function OoUiSelectWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.SelectWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.GroupWidget.call( this, $.extend( {\n\t\t$group: this.$element\n\t}, config ) );\n\n\t// Properties\n\tthis.pressed = false;\n\tthis.selecting = null;\n\tthis.onDocumentMouseUpHandler = this.onDocumentMouseUp.bind( this );\n\tthis.onDocumentMouseMoveHandler = this.onDocumentMouseMove.bind( this );\n\tthis.onDocumentKeyDownHandler = this.onDocumentKeyDown.bind( this );\n\tthis.onDocumentKeyPressHandler = this.onDocumentKeyPress.bind( this );\n\tthis.keyPressBuffer = '';\n\tthis.keyPressBufferTimer = null;\n\tthis.blockMouseOverEvents = 0;\n\n\t// Events\n\tthis.connect( this, {\n\t\ttoggle: 'onToggle'\n\t} );\n\tthis.$element.on( {\n\t\tfocusin: this.onFocus.bind( this ),\n\t\tmousedown: this.onMouseDown.bind( this ),\n\t\tmouseover: this.onMouseOver.bind( this ),\n\t\tmouseleave: this.onMouseLeave.bind( this )\n\t} );\n\n\t// Initialization\n\tthis.$element\n\t\t// -depressed is a deprecated alias of -unpressed\n\t\t.addClass( 'oo-ui-selectWidget oo-ui-selectWidget-unpressed oo-ui-selectWidget-depressed' )\n\t\t.attr( 'role', 'listbox' );\n\tthis.setFocusOwner( this.$element );\n\tif ( Array.isArray( config.items ) ) {\n\t\tthis.addItems( config.items );\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.SelectWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.SelectWidget, OO.ui.mixin.GroupWidget );\n\n/* Events */\n\n/**\n * @event highlight\n *\n * A `highlight` event is emitted when the highlight is changed with the #highlightItem method.\n *\n * @param {OO.ui.OptionWidget|null} item Highlighted item\n */\n\n/**\n * @event press\n *\n * A `press` event is emitted when the #pressItem method is used to programmatically modify the\n * pressed state of an option.\n *\n * @param {OO.ui.OptionWidget|null} item Pressed item\n */\n\n/**\n * @event select\n *\n * A `select` event is emitted when the selection is modified programmatically with the #selectItem\n * method.\n *\n * @param {OO.ui.OptionWidget|null} item Selected item\n */\n\n/**\n * @event choose\n * A `choose` event is emitted when an item is chosen with the #chooseItem method.\n * @param {OO.ui.OptionWidget} item Chosen item\n */\n\n/**\n * @event add\n *\n * An `add` event is emitted when options are added to the select with the #addItems method.\n *\n * @param {OO.ui.OptionWidget[]} items Added items\n * @param {number} index Index of insertion point\n */\n\n/**\n * @event remove\n *\n * A `remove` event is emitted when options are removed from the select with the #clearItems\n * or #removeItems methods.\n *\n * @param {OO.ui.OptionWidget[]} items Removed items\n */\n\n/* Static methods */\n\n/**\n * Normalize text for filter matching\n *\n * @param {string} text Text\n * @return {string} Normalized text\n */\nOO.ui.SelectWidget.static.normalizeForMatching = function ( text ) {\n\t// Replace trailing whitespace, normalize multiple spaces and make case insensitive\n\tvar normalized = text.trim().replace( /\\s+/, ' ' ).toLowerCase();\n\n\t// Normalize Unicode\n\t// eslint-disable-next-line no-restricted-properties\n\tif ( normalized.normalize ) {\n\t\t// eslint-disable-next-line no-restricted-properties\n\t\tnormalized = normalized.normalize();\n\t}\n\treturn normalized;\n};\n\n/* Methods */\n\n/**\n * Handle focus events\n *\n * @private\n * @param {jQuery.Event} event\n */\nOO.ui.SelectWidget.prototype.onFocus = function ( event ) {\n\tvar item;\n\tif ( event.target === this.$element[ 0 ] ) {\n\t\t// This widget was focussed, e.g. by the user tabbing to it.\n\t\t// The styles for focus state depend on one of the items being selected.\n\t\tif ( !this.findSelectedItem() ) {\n\t\t\titem = this.findFirstSelectableItem();\n\t\t}\n\t} else {\n\t\tif ( event.target.tabIndex === -1 ) {\n\t\t\t// One of the options got focussed (and the event bubbled up here).\n\t\t\t// They can't be tabbed to, but they can be activated using access keys.\n\t\t\t// OptionWidgets and focusable UI elements inside them have tabindex=\"-1\" set.\n\t\t\titem = this.findTargetItem( event );\n\t\t} else {\n\t\t\t// There is something actually user-focusable in one of the labels of the options, and\n\t\t\t// the user focussed it (e.g. by tabbing to it). Do nothing (especially, don't change\n\t\t\t// the focus).\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif ( item ) {\n\t\tif ( item.constructor.static.highlightable ) {\n\t\t\tthis.highlightItem( item );\n\t\t} else {\n\t\t\tthis.selectItem( item );\n\t\t}\n\t}\n\n\tif ( event.target !== this.$element[ 0 ] ) {\n\t\tthis.$focusOwner.trigger( 'focus' );\n\t}\n};\n\n/**\n * Handle mouse down events.\n *\n * @private\n * @param {jQuery.Event} e Mouse down event\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.SelectWidget.prototype.onMouseDown = function ( e ) {\n\tvar item;\n\n\tif ( !this.isDisabled() && e.which === OO.ui.MouseButtons.LEFT ) {\n\t\tthis.togglePressed( true );\n\t\titem = this.findTargetItem( e );\n\t\tif ( item && item.isSelectable() ) {\n\t\t\tthis.pressItem( item );\n\t\t\tthis.selecting = item;\n\t\t\tthis.getElementDocument().addEventListener( 'mouseup', this.onDocumentMouseUpHandler, true );\n\t\t\tthis.getElementDocument().addEventListener( 'mousemove', this.onDocumentMouseMoveHandler, true );\n\t\t}\n\t}\n\treturn false;\n};\n\n/**\n * Handle document mouse up events.\n *\n * @private\n * @param {MouseEvent} e Mouse up event\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.SelectWidget.prototype.onDocumentMouseUp = function ( e ) {\n\tvar item;\n\n\tthis.togglePressed( false );\n\tif ( !this.selecting ) {\n\t\titem = this.findTargetItem( e );\n\t\tif ( item && item.isSelectable() ) {\n\t\t\tthis.selecting = item;\n\t\t}\n\t}\n\tif ( !this.isDisabled() && e.which === OO.ui.MouseButtons.LEFT && this.selecting ) {\n\t\tthis.pressItem( null );\n\t\tthis.chooseItem( this.selecting );\n\t\tthis.selecting = null;\n\t}\n\n\tthis.getElementDocument().removeEventListener( 'mouseup', this.onDocumentMouseUpHandler, true );\n\tthis.getElementDocument().removeEventListener( 'mousemove', this.onDocumentMouseMoveHandler, true );\n\n\treturn false;\n};\n\n/**\n * Handle document mouse move events.\n *\n * @private\n * @param {MouseEvent} e Mouse move event\n */\nOO.ui.SelectWidget.prototype.onDocumentMouseMove = function ( e ) {\n\tvar item;\n\n\tif ( !this.isDisabled() && this.pressed ) {\n\t\titem = this.findTargetItem( e );\n\t\tif ( item && item !== this.selecting && item.isSelectable() ) {\n\t\t\tthis.pressItem( item );\n\t\t\tthis.selecting = item;\n\t\t}\n\t}\n};\n\n/**\n * Handle mouse over events.\n *\n * @private\n * @param {jQuery.Event} e Mouse over event\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.SelectWidget.prototype.onMouseOver = function ( e ) {\n\tvar item;\n\tif ( this.blockMouseOverEvents ) {\n\t\treturn;\n\t}\n\tif ( !this.isDisabled() ) {\n\t\titem = this.findTargetItem( e );\n\t\tthis.highlightItem( item && item.isHighlightable() ? item : null );\n\t}\n\treturn false;\n};\n\n/**\n * Handle mouse leave events.\n *\n * @private\n * @param {jQuery.Event} e Mouse over event\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.SelectWidget.prototype.onMouseLeave = function () {\n\tif ( !this.isDisabled() ) {\n\t\tthis.highlightItem( null );\n\t}\n\treturn false;\n};\n\n/**\n * Handle document key down events.\n *\n * @protected\n * @param {KeyboardEvent} e Key down event\n */\nOO.ui.SelectWidget.prototype.onDocumentKeyDown = function ( e ) {\n\tvar nextItem,\n\t\thandled = false,\n\t\tcurrentItem = this.findHighlightedItem() || this.findSelectedItem();\n\n\tif ( !this.isDisabled() && this.isVisible() ) {\n\t\tswitch ( e.keyCode ) {\n\t\t\tcase OO.ui.Keys.ENTER:\n\t\t\t\tif ( currentItem && currentItem.constructor.static.highlightable ) {\n\t\t\t\t\t// Was only highlighted, now let's select it. No-op if already selected.\n\t\t\t\t\tthis.chooseItem( currentItem );\n\t\t\t\t\thandled = true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase OO.ui.Keys.UP:\n\t\t\tcase OO.ui.Keys.LEFT:\n\t\t\t\tthis.clearKeyPressBuffer();\n\t\t\t\tnextItem = this.findRelativeSelectableItem( currentItem, -1 );\n\t\t\t\thandled = true;\n\t\t\t\tbreak;\n\t\t\tcase OO.ui.Keys.DOWN:\n\t\t\tcase OO.ui.Keys.RIGHT:\n\t\t\t\tthis.clearKeyPressBuffer();\n\t\t\t\tnextItem = this.findRelativeSelectableItem( currentItem, 1 );\n\t\t\t\thandled = true;\n\t\t\t\tbreak;\n\t\t\tcase OO.ui.Keys.ESCAPE:\n\t\t\tcase OO.ui.Keys.TAB:\n\t\t\t\tif ( currentItem && currentItem.constructor.static.highlightable ) {\n\t\t\t\t\tcurrentItem.setHighlighted( false );\n\t\t\t\t}\n\t\t\t\tthis.unbindDocumentKeyDownListener();\n\t\t\t\tthis.unbindDocumentKeyPressListener();\n\t\t\t\t// Don't prevent tabbing away / defocusing\n\t\t\t\thandled = false;\n\t\t\t\tbreak;\n\t\t}\n\n\t\tif ( nextItem ) {\n\t\t\tif ( nextItem.constructor.static.highlightable ) {\n\t\t\t\tthis.highlightItem( nextItem );\n\t\t\t} else {\n\t\t\t\tthis.chooseItem( nextItem );\n\t\t\t}\n\t\t\tthis.scrollItemIntoView( nextItem );\n\t\t}\n\n\t\tif ( handled ) {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t}\n\t}\n};\n\n/**\n * Bind document key down listener.\n *\n * @protected\n */\nOO.ui.SelectWidget.prototype.bindDocumentKeyDownListener = function () {\n\tthis.getElementDocument().addEventListener( 'keydown', this.onDocumentKeyDownHandler, true );\n};\n\n/**\n * Unbind document key down listener.\n *\n * @protected\n */\nOO.ui.SelectWidget.prototype.unbindDocumentKeyDownListener = function () {\n\tthis.getElementDocument().removeEventListener( 'keydown', this.onDocumentKeyDownHandler, true );\n};\n\n/**\n * Scroll item into view, preventing spurious mouse highlight actions from happening.\n *\n * @param {OO.ui.OptionWidget} item Item to scroll into view\n */\nOO.ui.SelectWidget.prototype.scrollItemIntoView = function ( item ) {\n\tvar widget = this;\n\t// Chromium's Blink engine will generate spurious 'mouseover' events during programmatic\n\t// scrolling and around 100-150 ms after it is finished.\n\tthis.blockMouseOverEvents++;\n\titem.scrollElementIntoView().done( function () {\n\t\tsetTimeout( function () {\n\t\t\twidget.blockMouseOverEvents--;\n\t\t}, 200 );\n\t} );\n};\n\n/**\n * Clear the key-press buffer\n *\n * @protected\n */\nOO.ui.SelectWidget.prototype.clearKeyPressBuffer = function () {\n\tif ( this.keyPressBufferTimer ) {\n\t\tclearTimeout( this.keyPressBufferTimer );\n\t\tthis.keyPressBufferTimer = null;\n\t}\n\tthis.keyPressBuffer = '';\n};\n\n/**\n * Handle key press events.\n *\n * @protected\n * @param {KeyboardEvent} e Key press event\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.SelectWidget.prototype.onDocumentKeyPress = function ( e ) {\n\tvar c, filter, item;\n\n\tif ( !e.charCode ) {\n\t\tif ( e.keyCode === OO.ui.Keys.BACKSPACE && this.keyPressBuffer !== '' ) {\n\t\t\tthis.keyPressBuffer = this.keyPressBuffer.substr( 0, this.keyPressBuffer.length - 1 );\n\t\t\treturn false;\n\t\t}\n\t\treturn;\n\t}\n\t// eslint-disable-next-line no-restricted-properties\n\tif ( String.fromCodePoint ) {\n\t\t// eslint-disable-next-line no-restricted-properties\n\t\tc = String.fromCodePoint( e.charCode );\n\t} else {\n\t\tc = String.fromCharCode( e.charCode );\n\t}\n\n\tif ( this.keyPressBufferTimer ) {\n\t\tclearTimeout( this.keyPressBufferTimer );\n\t}\n\tthis.keyPressBufferTimer = setTimeout( this.clearKeyPressBuffer.bind( this ), 1500 );\n\n\titem = this.findHighlightedItem() || this.findSelectedItem();\n\n\tif ( this.keyPressBuffer === c ) {\n\t\t// Common (if weird) special case: typing \"xxxx\" will cycle through all\n\t\t// the items beginning with \"x\".\n\t\tif ( item ) {\n\t\t\titem = this.findRelativeSelectableItem( item, 1 );\n\t\t}\n\t} else {\n\t\tthis.keyPressBuffer += c;\n\t}\n\n\tfilter = this.getItemMatcher( this.keyPressBuffer, false );\n\tif ( !item || !filter( item ) ) {\n\t\titem = this.findRelativeSelectableItem( item, 1, filter );\n\t}\n\tif ( item ) {\n\t\tif ( this.isVisible() && item.constructor.static.highlightable ) {\n\t\t\tthis.highlightItem( item );\n\t\t} else {\n\t\t\tthis.chooseItem( item );\n\t\t}\n\t\tthis.scrollItemIntoView( item );\n\t}\n\n\te.preventDefault();\n\te.stopPropagation();\n};\n\n/**\n * Get a matcher for the specific string\n *\n * @protected\n * @param {string} query String to match against items\n * @param {string} [mode='prefix'] Matching mode: 'substring', 'prefix', or 'exact'\n * @return {Function} function ( OO.ui.OptionWidget ) => boolean\n */\nOO.ui.SelectWidget.prototype.getItemMatcher = function ( query, mode ) {\n\tvar normalizeForMatching = this.constructor.static.normalizeForMatching,\n\t\tnormalizedQuery = normalizeForMatching( query );\n\n\t// Support deprecated exact=true argument\n\tif ( mode === true ) {\n\t\tmode = 'exact';\n\t}\n\n\treturn function ( item ) {\n\t\tvar matchText = normalizeForMatching( item.getMatchText() );\n\n\t\tif ( normalizedQuery === '' ) {\n\t\t\t// Empty string matches all, except if we are in 'exact'\n\t\t\t// mode, where it doesn't match at all\n\t\t\treturn mode !== 'exact';\n\t\t}\n\n\t\tswitch ( mode ) {\n\t\t\tcase 'exact':\n\t\t\t\treturn matchText === normalizedQuery;\n\t\t\tcase 'substring':\n\t\t\t\treturn matchText.indexOf( normalizedQuery ) !== -1;\n\t\t\t// 'prefix'\n\t\t\tdefault:\n\t\t\t\treturn matchText.indexOf( normalizedQuery ) === 0;\n\t\t}\n\t};\n};\n\n/**\n * Bind document key press listener.\n *\n * @protected\n */\nOO.ui.SelectWidget.prototype.bindDocumentKeyPressListener = function () {\n\tthis.getElementDocument().addEventListener( 'keypress', this.onDocumentKeyPressHandler, true );\n};\n\n/**\n * Unbind document key down listener.\n *\n * If you override this, be sure to call this.clearKeyPressBuffer() from your\n * implementation.\n *\n * @protected\n */\nOO.ui.SelectWidget.prototype.unbindDocumentKeyPressListener = function () {\n\tthis.getElementDocument().removeEventListener( 'keypress', this.onDocumentKeyPressHandler, true );\n\tthis.clearKeyPressBuffer();\n};\n\n/**\n * Visibility change handler\n *\n * @protected\n * @param {boolean} visible\n */\nOO.ui.SelectWidget.prototype.onToggle = function ( visible ) {\n\tif ( !visible ) {\n\t\tthis.clearKeyPressBuffer();\n\t}\n};\n\n/**\n * Get the closest item to a jQuery.Event.\n *\n * @private\n * @param {jQuery.Event} e\n * @return {OO.ui.OptionWidget|null} Outline item widget, `null` if none was found\n */\nOO.ui.SelectWidget.prototype.findTargetItem = function ( e ) {\n\tvar $option = $( e.target ).closest( '.oo-ui-optionWidget' );\n\tif ( !$option.closest( '.oo-ui-selectWidget' ).is( this.$element ) ) {\n\t\treturn null;\n\t}\n\treturn $option.data( 'oo-ui-optionWidget' ) || null;\n};\n\n/**\n * Find selected item.\n *\n * @return {OO.ui.OptionWidget|null} Selected item, `null` if no item is selected\n */\nOO.ui.SelectWidget.prototype.findSelectedItem = function () {\n\tvar i, len;\n\n\tfor ( i = 0, len = this.items.length; i < len; i++ ) {\n\t\tif ( this.items[ i ].isSelected() ) {\n\t\t\treturn this.items[ i ];\n\t\t}\n\t}\n\treturn null;\n};\n\n/**\n * Find highlighted item.\n *\n * @return {OO.ui.OptionWidget|null} Highlighted item, `null` if no item is highlighted\n */\nOO.ui.SelectWidget.prototype.findHighlightedItem = function () {\n\tvar i, len;\n\n\tfor ( i = 0, len = this.items.length; i < len; i++ ) {\n\t\tif ( this.items[ i ].isHighlighted() ) {\n\t\t\treturn this.items[ i ];\n\t\t}\n\t}\n\treturn null;\n};\n\n/**\n * Toggle pressed state.\n *\n * Press is a state that occurs when a user mouses down on an item, but\n * has not yet let go of the mouse. The item may appear selected, but it will not be selected\n * until the user releases the mouse.\n *\n * @param {boolean} pressed An option is being pressed\n */\nOO.ui.SelectWidget.prototype.togglePressed = function ( pressed ) {\n\tif ( pressed === undefined ) {\n\t\tpressed = !this.pressed;\n\t}\n\tif ( pressed !== this.pressed ) {\n\t\tthis.$element\n\t\t\t.toggleClass( 'oo-ui-selectWidget-pressed', pressed )\n\t\t\t// -depressed is a deprecated alias of -unpressed\n\t\t\t.toggleClass( 'oo-ui-selectWidget-unpressed oo-ui-selectWidget-depressed', !pressed );\n\t\tthis.pressed = pressed;\n\t}\n};\n\n/**\n * Highlight an option. If the `item` param is omitted, no options will be highlighted\n * and any existing highlight will be removed. The highlight is mutually exclusive.\n *\n * @param {OO.ui.OptionWidget} [item] Item to highlight, omit for no highlight\n * @fires highlight\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.SelectWidget.prototype.highlightItem = function ( item ) {\n\tvar i, len, highlighted,\n\t\tchanged = false;\n\n\tfor ( i = 0, len = this.items.length; i < len; i++ ) {\n\t\thighlighted = this.items[ i ] === item;\n\t\tif ( this.items[ i ].isHighlighted() !== highlighted ) {\n\t\t\tthis.items[ i ].setHighlighted( highlighted );\n\t\t\tchanged = true;\n\t\t}\n\t}\n\tif ( changed ) {\n\t\tif ( item ) {\n\t\t\tthis.$focusOwner.attr( 'aria-activedescendant', item.getElementId() );\n\t\t} else {\n\t\t\tthis.$focusOwner.removeAttr( 'aria-activedescendant' );\n\t\t}\n\t\tthis.emit( 'highlight', item );\n\t}\n\n\treturn this;\n};\n\n/**\n * Fetch an item by its label.\n *\n * @param {string} label Label of the item to select.\n * @param {boolean} [prefix=false] Allow a prefix match, if only a single item matches\n * @return {OO.ui.Element|null} Item with equivalent label, `null` if none exists\n */\nOO.ui.SelectWidget.prototype.getItemFromLabel = function ( label, prefix ) {\n\tvar i, item, found,\n\t\tlen = this.items.length,\n\t\tfilter = this.getItemMatcher( label, 'exact' );\n\n\tfor ( i = 0; i < len; i++ ) {\n\t\titem = this.items[ i ];\n\t\tif ( item instanceof OO.ui.OptionWidget && item.isSelectable() && filter( item ) ) {\n\t\t\treturn item;\n\t\t}\n\t}\n\n\tif ( prefix ) {\n\t\tfound = null;\n\t\tfilter = this.getItemMatcher( label, 'prefix' );\n\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\titem = this.items[ i ];\n\t\t\tif ( item instanceof OO.ui.OptionWidget && item.isSelectable() && filter( item ) ) {\n\t\t\t\tif ( found ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tfound = item;\n\t\t\t}\n\t\t}\n\t\tif ( found ) {\n\t\t\treturn found;\n\t\t}\n\t}\n\n\treturn null;\n};\n\n/**\n * Programmatically select an option by its label. If the item does not exist,\n * all options will be deselected.\n *\n * @param {string} [label] Label of the item to select.\n * @param {boolean} [prefix=false] Allow a prefix match, if only a single item matches\n * @fires select\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.SelectWidget.prototype.selectItemByLabel = function ( label, prefix ) {\n\tvar itemFromLabel = this.getItemFromLabel( label, !!prefix );\n\tif ( label === undefined || !itemFromLabel ) {\n\t\treturn this.selectItem();\n\t}\n\treturn this.selectItem( itemFromLabel );\n};\n\n/**\n * Programmatically select an option by its data. If the `data` parameter is omitted,\n * or if the item does not exist, all options will be deselected.\n *\n * @param {Object|string} [data] Value of the item to select, omit to deselect all\n * @fires select\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.SelectWidget.prototype.selectItemByData = function ( data ) {\n\tvar itemFromData = this.findItemFromData( data );\n\tif ( data === undefined || !itemFromData ) {\n\t\treturn this.selectItem();\n\t}\n\treturn this.selectItem( itemFromData );\n};\n\n/**\n * Programmatically select an option by its reference. If the `item` parameter is omitted,\n * all options will be deselected.\n *\n * @param {OO.ui.OptionWidget} [item] Item to select, omit to deselect all\n * @fires select\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n*/\nOO.ui.SelectWidget.prototype.selectItem = function ( item ) {\n\tvar i, len, selected,\n\t\tchanged = false;\n\n\tfor ( i = 0, len = this.items.length; i < len; i++ ) {\n\t\tselected = this.items[ i ] === item;\n\t\tif ( this.items[ i ].isSelected() !== selected ) {\n\t\t\tthis.items[ i ].setSelected( selected );\n\t\t\tchanged = true;\n\t\t}\n\t}\n\tif ( changed ) {\n\t\tif ( item && !item.constructor.static.highlightable ) {\n\t\t\tif ( item ) {\n\t\t\t\tthis.$focusOwner.attr( 'aria-activedescendant', item.getElementId() );\n\t\t\t} else {\n\t\t\t\tthis.$focusOwner.removeAttr( 'aria-activedescendant' );\n\t\t\t}\n\t\t}\n\t\tthis.emit( 'select', item );\n\t}\n\n\treturn this;\n};\n\n/**\n * Press an item.\n *\n * Press is a state that occurs when a user mouses down on an item, but has not\n * yet let go of the mouse. The item may appear selected, but it will not be selected until the user\n * releases the mouse.\n *\n * @param {OO.ui.OptionWidget} [item] Item to press, omit to depress all\n * @fires press\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.SelectWidget.prototype.pressItem = function ( item ) {\n\tvar i, len, pressed,\n\t\tchanged = false;\n\n\tfor ( i = 0, len = this.items.length; i < len; i++ ) {\n\t\tpressed = this.items[ i ] === item;\n\t\tif ( this.items[ i ].isPressed() !== pressed ) {\n\t\t\tthis.items[ i ].setPressed( pressed );\n\t\t\tchanged = true;\n\t\t}\n\t}\n\tif ( changed ) {\n\t\tthis.emit( 'press', item );\n\t}\n\n\treturn this;\n};\n\n/**\n * Choose an item.\n *\n * Note that ‘choose’ should never be modified programmatically. A user can choose\n * an option with the keyboard or mouse and it becomes selected. To select an item programmatically,\n * use the #selectItem method.\n *\n * This method is identical to #selectItem, but may vary in subclasses that take additional action\n * when users choose an item with the keyboard or mouse.\n *\n * @param {OO.ui.OptionWidget} item Item to choose\n * @fires choose\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.SelectWidget.prototype.chooseItem = function ( item ) {\n\tif ( item ) {\n\t\tthis.selectItem( item );\n\t\tthis.emit( 'choose', item );\n\t}\n\n\treturn this;\n};\n\n/**\n * Find an option by its position relative to the specified item (or to the start of the option\n * array, if item is `null`). The direction in which to search through the option array is specified\n * with a number: -1 for reverse (the default) or 1 for forward. The method will return an option,\n * or `null` if there are no options in the array.\n *\n * @param {OO.ui.OptionWidget|null} item Item to describe the start position, or `null` to start at\n *  the beginning of the array.\n * @param {number} direction Direction to move in: -1 to move backward, 1 to move forward\n * @param {Function} [filter] Only consider items for which this function returns\n *  true. Function takes an OO.ui.OptionWidget and returns a boolean.\n * @return {OO.ui.OptionWidget|null} Item at position, `null` if there are no items in the select\n */\nOO.ui.SelectWidget.prototype.findRelativeSelectableItem = function ( item, direction, filter ) {\n\tvar currentIndex, nextIndex, i,\n\t\tincrease = direction > 0 ? 1 : -1,\n\t\tlen = this.items.length;\n\n\tif ( item instanceof OO.ui.OptionWidget ) {\n\t\tcurrentIndex = this.items.indexOf( item );\n\t\tnextIndex = ( currentIndex + increase + len ) % len;\n\t} else {\n\t\t// If no item is selected and moving forward, start at the beginning.\n\t\t// If moving backward, start at the end.\n\t\tnextIndex = direction > 0 ? 0 : len - 1;\n\t}\n\n\tfor ( i = 0; i < len; i++ ) {\n\t\titem = this.items[ nextIndex ];\n\t\tif (\n\t\t\titem instanceof OO.ui.OptionWidget && item.isSelectable() &&\n\t\t\t( !filter || filter( item ) )\n\t\t) {\n\t\t\treturn item;\n\t\t}\n\t\tnextIndex = ( nextIndex + increase + len ) % len;\n\t}\n\treturn null;\n};\n\n/**\n * Find the next selectable item or `null` if there are no selectable items.\n * Disabled options and menu-section markers and breaks are not selectable.\n *\n * @return {OO.ui.OptionWidget|null} Item, `null` if there aren't any selectable items\n */\nOO.ui.SelectWidget.prototype.findFirstSelectableItem = function () {\n\treturn this.findRelativeSelectableItem( null, 1 );\n};\n\n/**\n * Add an array of options to the select. Optionally, an index number can be used to\n * specify an insertion point.\n *\n * @param {OO.ui.OptionWidget[]} items Items to add\n * @param {number} [index] Index to insert items after\n * @fires add\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.SelectWidget.prototype.addItems = function ( items, index ) {\n\t// Mixin method\n\tOO.ui.mixin.GroupWidget.prototype.addItems.call( this, items, index );\n\n\t// Always provide an index, even if it was omitted\n\tthis.emit( 'add', items, index === undefined ? this.items.length - items.length - 1 : index );\n\n\treturn this;\n};\n\n/**\n * Remove the specified array of options from the select. Options will be detached\n * from the DOM, not removed, so they can be reused later. To remove all options from\n * the select, you may wish to use the #clearItems method instead.\n *\n * @param {OO.ui.OptionWidget[]} items Items to remove\n * @fires remove\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.SelectWidget.prototype.removeItems = function ( items ) {\n\tvar i, len, item;\n\n\t// Deselect items being removed\n\tfor ( i = 0, len = items.length; i < len; i++ ) {\n\t\titem = items[ i ];\n\t\tif ( item.isSelected() ) {\n\t\t\tthis.selectItem( null );\n\t\t}\n\t}\n\n\t// Mixin method\n\tOO.ui.mixin.GroupWidget.prototype.removeItems.call( this, items );\n\n\tthis.emit( 'remove', items );\n\n\treturn this;\n};\n\n/**\n * Clear all options from the select. Options will be detached from the DOM, not removed,\n * so that they can be reused later. To remove a subset of options from the select, use\n * the #removeItems method.\n *\n * @fires remove\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.SelectWidget.prototype.clearItems = function () {\n\tvar items = this.items.slice();\n\n\t// Mixin method\n\tOO.ui.mixin.GroupWidget.prototype.clearItems.call( this );\n\n\t// Clear selection\n\tthis.selectItem( null );\n\n\tthis.emit( 'remove', items );\n\n\treturn this;\n};\n\n/**\n * Set the DOM element which has focus while the user is interacting with this SelectWidget.\n *\n * This is used to set `aria-activedescendant` and `aria-expanded` on it.\n *\n * @protected\n * @param {jQuery} $focusOwner\n */\nOO.ui.SelectWidget.prototype.setFocusOwner = function ( $focusOwner ) {\n\tthis.$focusOwner = $focusOwner;\n};\n","/**\n * DecoratedOptionWidgets are {@link OO.ui.OptionWidget options} that can be configured\n * with an {@link OO.ui.mixin.IconElement icon} and/or\n * {@link OO.ui.mixin.IndicatorElement indicator}.\n * This class is used with OO.ui.SelectWidget to create a selection of mutually exclusive\n * options. For more information about options and selects, please see the\n * [OOUI documentation on MediaWiki][1].\n *\n *     @example\n *     // Decorated options in a select widget.\n *     var select = new OO.ui.SelectWidget( {\n *         items: [\n *             new OO.ui.DecoratedOptionWidget( {\n *                 data: 'a',\n *                 label: 'Option with icon',\n *                 icon: 'help'\n *             } ),\n *             new OO.ui.DecoratedOptionWidget( {\n *                 data: 'b',\n *                 label: 'Option with indicator',\n *                 indicator: 'next'\n *             } )\n *         ]\n *     } );\n *     $( document.body ).append( select.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options\n *\n * @class\n * @extends OO.ui.OptionWidget\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.IndicatorElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.DecoratedOptionWidget = function OoUiDecoratedOptionWidget( config ) {\n\t// Parent constructor\n\tOO.ui.DecoratedOptionWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.IndicatorElement.call( this, config );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-decoratedOptionWidget' )\n\t\t.prepend( this.$icon )\n\t\t.append( this.$indicator );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.DecoratedOptionWidget, OO.ui.OptionWidget );\nOO.mixinClass( OO.ui.DecoratedOptionWidget, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.DecoratedOptionWidget, OO.ui.mixin.IndicatorElement );\n","/**\n * MenuOptionWidget is an option widget that looks like a menu item. The class is used with\n * OO.ui.MenuSelectWidget to create a menu of mutually exclusive options. Please see\n * the [OOUI documentation on MediaWiki] [1] for more information.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options#Menu_selects_and_options\n *\n * @class\n * @extends OO.ui.DecoratedOptionWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.MenuOptionWidget = function OoUiMenuOptionWidget( config ) {\n\t// Parent constructor\n\tOO.ui.MenuOptionWidget.parent.call( this, config );\n\n\t// Properties\n\tthis.checkIcon = new OO.ui.IconWidget( {\n\t\ticon: 'check',\n\t\tclasses: [ 'oo-ui-menuOptionWidget-checkIcon' ]\n\t} );\n\n\t// Initialization\n\tthis.$element\n\t\t.prepend( this.checkIcon.$element )\n\t\t.addClass( 'oo-ui-menuOptionWidget' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.MenuOptionWidget, OO.ui.DecoratedOptionWidget );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.MenuOptionWidget.static.scrollIntoViewOnSelect = true;\n","/**\n * MenuSectionOptionWidgets are used inside {@link OO.ui.MenuSelectWidget menu select widgets} to\n * group one or more related {@link OO.ui.MenuOptionWidget menu options}. MenuSectionOptionWidgets\n * cannot be highlighted or selected.\n *\n *     @example\n *     var dropdown = new OO.ui.DropdownWidget( {\n *         menu: {\n *             items: [\n *                 new OO.ui.MenuSectionOptionWidget( {\n *                     label: 'Dogs'\n *                 } ),\n *                 new OO.ui.MenuOptionWidget( {\n *                     data: 'corgi',\n *                     label: 'Welsh Corgi'\n *                 } ),\n *                 new OO.ui.MenuOptionWidget( {\n *                     data: 'poodle',\n *                     label: 'Standard Poodle'\n *                 } ),\n *                 new OO.ui.MenuSectionOptionWidget( {\n *                     label: 'Cats'\n *                 } ),\n *                 new OO.ui.MenuOptionWidget( {\n *                     data: 'lion',\n *                     label: 'Lion'\n *                 } )\n *             ]\n *         }\n *     } );\n *     $( document.body ).append( dropdown.$element );\n *\n * @class\n * @extends OO.ui.DecoratedOptionWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.MenuSectionOptionWidget = function OoUiMenuSectionOptionWidget( config ) {\n\t// Parent constructor\n\tOO.ui.MenuSectionOptionWidget.parent.call( this, config );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-menuSectionOptionWidget' )\n\t\t.removeAttr( 'role aria-selected' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.MenuSectionOptionWidget, OO.ui.DecoratedOptionWidget );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.MenuSectionOptionWidget.static.selectable = false;\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.MenuSectionOptionWidget.static.highlightable = false;\n","/**\n * MenuSelectWidget is a {@link OO.ui.SelectWidget select widget} that contains options and\n * is used together with OO.ui.MenuOptionWidget. It is designed be used as part of another widget.\n * See {@link OO.ui.DropdownWidget DropdownWidget},\n * {@link OO.ui.ComboBoxInputWidget ComboBoxInputWidget}, and\n * {@link OO.ui.mixin.LookupElement LookupElement} for examples of widgets that contain menus.\n * MenuSelectWidgets themselves are not instantiated directly, rather subclassed\n * and customized to be opened, closed, and displayed as needed.\n *\n * By default, menus are clipped to the visible viewport and are not visible when a user presses the\n * mouse outside the menu.\n *\n * Menus also have support for keyboard interaction:\n *\n * - Enter/Return key: choose and select a menu option\n * - Up-arrow key: highlight the previous menu option\n * - Down-arrow key: highlight the next menu option\n * - Escape key: hide the menu\n *\n * Unlike most widgets, MenuSelectWidget is initially hidden and must be shown by calling #toggle.\n *\n * Please see the [OOUI documentation on MediaWiki][1] for more information.\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options\n *\n * @class\n * @extends OO.ui.SelectWidget\n * @mixins OO.ui.mixin.ClippableElement\n * @mixins OO.ui.mixin.FloatableElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {OO.ui.TextInputWidget} [input] Text input used to implement option highlighting for menu\n *  items that match the text the user types. This config is used by\n *  {@link OO.ui.ComboBoxInputWidget ComboBoxInputWidget} and\n *  {@link OO.ui.mixin.LookupElement LookupElement}\n * @cfg {jQuery} [$input] Text input used to implement option highlighting for menu items that match\n *  the text the user types. This config is used by\n *  {@link OO.ui.TagMultiselectWidget TagMultiselectWidget}\n * @cfg {OO.ui.Widget} [widget] Widget associated with the menu's active state. If the user clicks\n *  the mouse anywhere on the page outside of this widget, the menu is hidden. For example, if\n *  there is a button that toggles the menu's visibility on click, the menu will be hidden then\n *  re-shown when the user clicks that button, unless the button (or its parent widget) is passed\n *  in here.\n * @cfg {boolean} [autoHide=true] Hide the menu when the mouse is pressed outside the menu.\n * @cfg {jQuery} [$autoCloseIgnore] If these elements are clicked, don't auto-hide the menu.\n * @cfg {boolean} [hideOnChoose=true] Hide the menu when the user chooses an option.\n * @cfg {boolean} [filterFromInput=false] Filter the displayed options from the input\n * @cfg {boolean} [highlightOnFilter] Highlight the first result when filtering\n * @cfg {string} [filterMode='prefix'] The mode by which the menu filters the results.\n *  Options are 'exact', 'prefix' or 'substring'. See `OO.ui.SelectWidget#getItemMatcher`\n * @param {number|string} [width] Width of the menu as a number of pixels or CSS string with unit\n *  suffix, used by {@link OO.ui.mixin.ClippableElement ClippableElement}\n */\nOO.ui.MenuSelectWidget = function OoUiMenuSelectWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.MenuSelectWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.ClippableElement.call( this, $.extend( { $clippable: this.$group }, config ) );\n\tOO.ui.mixin.FloatableElement.call( this, config );\n\n\t// Initial vertical positions other than 'center' will result in\n\t// the menu being flipped if there is not enough space in the container.\n\t// Store the original position so we know what to reset to.\n\tthis.originalVerticalPosition = this.verticalPosition;\n\n\t// Properties\n\tthis.autoHide = config.autoHide === undefined || !!config.autoHide;\n\tthis.hideOnChoose = config.hideOnChoose === undefined || !!config.hideOnChoose;\n\tthis.filterFromInput = !!config.filterFromInput;\n\tthis.$input = config.$input ? config.$input : config.input ? config.input.$input : null;\n\tthis.$widget = config.widget ? config.widget.$element : null;\n\tthis.$autoCloseIgnore = config.$autoCloseIgnore || $( [] );\n\tthis.onDocumentMouseDownHandler = this.onDocumentMouseDown.bind( this );\n\tthis.onInputEditHandler = OO.ui.debounce( this.updateItemVisibility.bind( this ), 100 );\n\tthis.highlightOnFilter = !!config.highlightOnFilter;\n\tthis.lastHighlightedItem = null;\n\tthis.width = config.width;\n\tthis.filterMode = config.filterMode;\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-menuSelectWidget' );\n\tif ( config.widget ) {\n\t\tthis.setFocusOwner( config.widget.$tabIndexed );\n\t}\n\n\t// Initially hidden - using #toggle may cause errors if subclasses override toggle with methods\n\t// that reference properties not initialized at that time of parent class construction\n\t// TODO: Find a better way to handle post-constructor setup\n\tthis.visible = false;\n\tthis.$element.addClass( 'oo-ui-element-hidden' );\n\tthis.$focusOwner.attr( 'aria-expanded', 'false' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.MenuSelectWidget, OO.ui.SelectWidget );\nOO.mixinClass( OO.ui.MenuSelectWidget, OO.ui.mixin.ClippableElement );\nOO.mixinClass( OO.ui.MenuSelectWidget, OO.ui.mixin.FloatableElement );\n\n/* Events */\n\n/**\n * @event ready\n *\n * The menu is ready: it is visible and has been positioned and clipped.\n */\n\n/* Static properties */\n\n/**\n * Positions to flip to if there isn't room in the container for the\n * menu in a specific direction.\n *\n * @property {Object.<string,string>}\n */\nOO.ui.MenuSelectWidget.static.flippedPositions = {\n\tbelow: 'above',\n\tabove: 'below',\n\ttop: 'bottom',\n\tbottom: 'top'\n};\n\n/* Methods */\n\n/**\n * Handles document mouse down events.\n *\n * @protected\n * @param {MouseEvent} e Mouse down event\n */\nOO.ui.MenuSelectWidget.prototype.onDocumentMouseDown = function ( e ) {\n\tif (\n\t\tthis.isVisible() &&\n\t\t!OO.ui.contains(\n\t\t\tthis.$element.add( this.$widget ).add( this.$autoCloseIgnore ).get(),\n\t\t\te.target,\n\t\t\ttrue\n\t\t)\n\t) {\n\t\tthis.toggle( false );\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuSelectWidget.prototype.onDocumentKeyDown = function ( e ) {\n\tvar currentItem = this.findHighlightedItem() || this.findSelectedItem();\n\n\tif ( !this.isDisabled() && this.isVisible() ) {\n\t\tswitch ( e.keyCode ) {\n\t\t\tcase OO.ui.Keys.LEFT:\n\t\t\tcase OO.ui.Keys.RIGHT:\n\t\t\t\t// Do nothing if a text field is associated, arrow keys will be handled natively\n\t\t\t\tif ( !this.$input ) {\n\t\t\t\t\tOO.ui.MenuSelectWidget.parent.prototype.onDocumentKeyDown.call( this, e );\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase OO.ui.Keys.ESCAPE:\n\t\t\tcase OO.ui.Keys.TAB:\n\t\t\t\tif ( currentItem ) {\n\t\t\t\t\tcurrentItem.setHighlighted( false );\n\t\t\t\t}\n\t\t\t\tthis.toggle( false );\n\t\t\t\t// Don't prevent tabbing away, prevent defocusing\n\t\t\t\tif ( e.keyCode === OO.ui.Keys.ESCAPE ) {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\te.stopPropagation();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tOO.ui.MenuSelectWidget.parent.prototype.onDocumentKeyDown.call( this, e );\n\t\t\t\treturn;\n\t\t}\n\t}\n};\n\n/**\n * Update menu item visibility and clipping after input changes (if filterFromInput is enabled)\n * or after items were added/removed (always).\n *\n * @protected\n */\nOO.ui.MenuSelectWidget.prototype.updateItemVisibility = function () {\n\tvar i, item, items, visible, section, sectionEmpty, filter, exactFilter,\n\t\tanyVisible = false,\n\t\tlen = this.items.length,\n\t\tshowAll = !this.isVisible(),\n\t\texactMatch = false;\n\n\tif ( this.$input && this.filterFromInput ) {\n\t\tfilter = showAll ? null : this.getItemMatcher( this.$input.val(), this.filterMode );\n\t\texactFilter = this.getItemMatcher( this.$input.val(), 'exact' );\n\t\t// Hide non-matching options, and also hide section headers if all options\n\t\t// in their section are hidden.\n\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\titem = this.items[ i ];\n\t\t\tif ( item instanceof OO.ui.MenuSectionOptionWidget ) {\n\t\t\t\tif ( section ) {\n\t\t\t\t\t// If the previous section was empty, hide its header\n\t\t\t\t\tsection.toggle( showAll || !sectionEmpty );\n\t\t\t\t}\n\t\t\t\tsection = item;\n\t\t\t\tsectionEmpty = true;\n\t\t\t} else if ( item instanceof OO.ui.OptionWidget ) {\n\t\t\t\tvisible = showAll || filter( item );\n\t\t\t\texactMatch = exactMatch || exactFilter( item );\n\t\t\t\tanyVisible = anyVisible || visible;\n\t\t\t\tsectionEmpty = sectionEmpty && !visible;\n\t\t\t\titem.toggle( visible );\n\t\t\t}\n\t\t}\n\t\t// Process the final section\n\t\tif ( section ) {\n\t\t\tsection.toggle( showAll || !sectionEmpty );\n\t\t}\n\n\t\tif ( anyVisible && this.items.length && !exactMatch ) {\n\t\t\tthis.scrollItemIntoView( this.items[ 0 ] );\n\t\t}\n\n\t\tif ( !anyVisible ) {\n\t\t\tthis.highlightItem( null );\n\t\t}\n\n\t\tthis.$element.toggleClass( 'oo-ui-menuSelectWidget-invisible', !anyVisible );\n\n\t\tif (\n\t\t\tthis.highlightOnFilter &&\n\t\t\t!( this.lastHighlightedItem && this.lastHighlightedItem.isVisible() )\n\t\t) {\n\t\t\t// Highlight the first item on the list\n\t\t\titem = null;\n\t\t\titems = this.getItems();\n\t\t\tfor ( i = 0; i < items.length; i++ ) {\n\t\t\t\tif ( items[ i ].isVisible() ) {\n\t\t\t\t\titem = items[ i ];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.highlightItem( item );\n\t\t\tthis.lastHighlightedItem = item;\n\t\t}\n\n\t}\n\n\t// Reevaluate clipping\n\tthis.clip();\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuSelectWidget.prototype.bindDocumentKeyDownListener = function () {\n\tif ( this.$input ) {\n\t\tthis.$input.on( 'keydown', this.onDocumentKeyDownHandler );\n\t} else {\n\t\tOO.ui.MenuSelectWidget.parent.prototype.bindDocumentKeyDownListener.call( this );\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuSelectWidget.prototype.unbindDocumentKeyDownListener = function () {\n\tif ( this.$input ) {\n\t\tthis.$input.off( 'keydown', this.onDocumentKeyDownHandler );\n\t} else {\n\t\tOO.ui.MenuSelectWidget.parent.prototype.unbindDocumentKeyDownListener.call( this );\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuSelectWidget.prototype.bindDocumentKeyPressListener = function () {\n\tif ( this.$input ) {\n\t\tif ( this.filterFromInput ) {\n\t\t\tthis.$input.on(\n\t\t\t\t'keydown mouseup cut paste change input select',\n\t\t\t\tthis.onInputEditHandler\n\t\t\t);\n\t\t\tthis.updateItemVisibility();\n\t\t}\n\t} else {\n\t\tOO.ui.MenuSelectWidget.parent.prototype.bindDocumentKeyPressListener.call( this );\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuSelectWidget.prototype.unbindDocumentKeyPressListener = function () {\n\tif ( this.$input ) {\n\t\tif ( this.filterFromInput ) {\n\t\t\tthis.$input.off(\n\t\t\t\t'keydown mouseup cut paste change input select',\n\t\t\t\tthis.onInputEditHandler\n\t\t\t);\n\t\t\tthis.updateItemVisibility();\n\t\t}\n\t} else {\n\t\tOO.ui.MenuSelectWidget.parent.prototype.unbindDocumentKeyPressListener.call( this );\n\t}\n};\n\n/**\n * Choose an item.\n *\n * When a user chooses an item, the menu is closed, unless the hideOnChoose config option is\n * set to false.\n *\n * Note that ‘choose’ should never be modified programmatically. A user can choose an option with\n * the keyboard or mouse and it becomes selected. To select an item programmatically,\n * use the #selectItem method.\n *\n * @param {OO.ui.OptionWidget} item Item to choose\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.MenuSelectWidget.prototype.chooseItem = function ( item ) {\n\tOO.ui.MenuSelectWidget.parent.prototype.chooseItem.call( this, item );\n\tif ( this.hideOnChoose ) {\n\t\tthis.toggle( false );\n\t}\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuSelectWidget.prototype.addItems = function ( items, index ) {\n\t// Parent method\n\tOO.ui.MenuSelectWidget.parent.prototype.addItems.call( this, items, index );\n\n\tthis.updateItemVisibility();\n\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuSelectWidget.prototype.removeItems = function ( items ) {\n\t// Parent method\n\tOO.ui.MenuSelectWidget.parent.prototype.removeItems.call( this, items );\n\n\tthis.updateItemVisibility();\n\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuSelectWidget.prototype.clearItems = function () {\n\t// Parent method\n\tOO.ui.MenuSelectWidget.parent.prototype.clearItems.call( this );\n\n\tthis.updateItemVisibility();\n\n\treturn this;\n};\n\n/**\n * Toggle visibility of the menu. The menu is initially hidden and must be shown by calling\n * `.toggle( true )` after its #$element is attached to the DOM.\n *\n * Do not show the menu while it is not attached to the DOM. The calculations required to display\n * it in the right place and with the right dimensions only work correctly while it is attached.\n * Side-effects may include broken interface and exceptions being thrown. This wasn't always\n * strictly enforced, so currently it only generates a warning in the browser console.\n *\n * @fires ready\n * @inheritdoc\n */\nOO.ui.MenuSelectWidget.prototype.toggle = function ( visible ) {\n\tvar change, originalHeight, flippedHeight;\n\n\tvisible = ( visible === undefined ? !this.visible : !!visible ) && !!this.items.length;\n\tchange = visible !== this.isVisible();\n\n\tif ( visible && !this.warnedUnattached && !this.isElementAttached() ) {\n\t\tOO.ui.warnDeprecation( 'MenuSelectWidget#toggle: Before calling this method, the menu must be attached to the DOM.' );\n\t\tthis.warnedUnattached = true;\n\t}\n\n\tif ( change && visible ) {\n\t\t// Reset position before showing the popup again. It's possible we no longer need to flip\n\t\t// (e.g. if the user scrolled).\n\t\tthis.setVerticalPosition( this.originalVerticalPosition );\n\t}\n\n\t// Parent method\n\tOO.ui.MenuSelectWidget.parent.prototype.toggle.call( this, visible );\n\n\tif ( change ) {\n\t\tif ( visible ) {\n\n\t\t\tif ( this.width ) {\n\t\t\t\tthis.setIdealSize( this.width );\n\t\t\t} else if ( this.$floatableContainer ) {\n\t\t\t\tthis.$clippable.css( 'width', 'auto' );\n\t\t\t\tthis.setIdealSize(\n\t\t\t\t\tthis.$floatableContainer[ 0 ].offsetWidth > this.$clippable[ 0 ].offsetWidth ?\n\t\t\t\t\t\t// Dropdown is smaller than handle so expand to width\n\t\t\t\t\t\tthis.$floatableContainer[ 0 ].offsetWidth :\n\t\t\t\t\t\t// Dropdown is larger than handle so auto size\n\t\t\t\t\t\t'auto'\n\t\t\t\t);\n\t\t\t\tthis.$clippable.css( 'width', '' );\n\t\t\t}\n\n\t\t\tthis.togglePositioning( !!this.$floatableContainer );\n\t\t\tthis.toggleClipping( true );\n\n\t\t\tthis.bindDocumentKeyDownListener();\n\t\t\tthis.bindDocumentKeyPressListener();\n\n\t\t\tif (\n\t\t\t\t( this.isClippedVertically() || this.isFloatableOutOfView() ) &&\n\t\t\t\tthis.originalVerticalPosition !== 'center'\n\t\t\t) {\n\t\t\t\t// If opening the menu in one direction causes it to be clipped, flip it\n\t\t\t\toriginalHeight = this.$element.height();\n\t\t\t\tthis.setVerticalPosition(\n\t\t\t\t\tthis.constructor.static.flippedPositions[ this.originalVerticalPosition ]\n\t\t\t\t);\n\t\t\t\tif ( this.isClippedVertically() || this.isFloatableOutOfView() ) {\n\t\t\t\t\t// If flipping also causes it to be clipped, open in whichever direction\n\t\t\t\t\t// we have more space\n\t\t\t\t\tflippedHeight = this.$element.height();\n\t\t\t\t\tif ( originalHeight > flippedHeight ) {\n\t\t\t\t\t\tthis.setVerticalPosition( this.originalVerticalPosition );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Note that we do not flip the menu's opening direction if the clipping changes\n\t\t\t// later (e.g. after the user scrolls), that seems like it would be annoying\n\n\t\t\tthis.$focusOwner.attr( 'aria-expanded', 'true' );\n\n\t\t\tif ( this.findSelectedItem() ) {\n\t\t\t\tthis.$focusOwner.attr( 'aria-activedescendant', this.findSelectedItem().getElementId() );\n\t\t\t\tthis.findSelectedItem().scrollElementIntoView( { duration: 0 } );\n\t\t\t}\n\n\t\t\t// Auto-hide\n\t\t\tif ( this.autoHide ) {\n\t\t\t\tthis.getElementDocument().addEventListener( 'mousedown', this.onDocumentMouseDownHandler, true );\n\t\t\t}\n\n\t\t\tthis.emit( 'ready' );\n\t\t} else {\n\t\t\tthis.$focusOwner.removeAttr( 'aria-activedescendant' );\n\t\t\tthis.unbindDocumentKeyDownListener();\n\t\t\tthis.unbindDocumentKeyPressListener();\n\t\t\tthis.$focusOwner.attr( 'aria-expanded', 'false' );\n\t\t\tthis.getElementDocument().removeEventListener( 'mousedown', this.onDocumentMouseDownHandler, true );\n\t\t\tthis.togglePositioning( false );\n\t\t\tthis.toggleClipping( false );\n\t\t}\n\t}\n\n\treturn this;\n};\n","/**\n * DropdownWidgets are not menus themselves, rather they contain a menu of options created with\n * OO.ui.MenuOptionWidget. The DropdownWidget takes care of opening and displaying the menu so that\n * users can interact with it.\n *\n * If you want to use this within an HTML form, such as a OO.ui.FormLayout, use\n * OO.ui.DropdownInputWidget instead.\n *\n *     @example\n *     // A DropdownWidget with a menu that contains three options.\n *     var dropDown = new OO.ui.DropdownWidget( {\n *         label: 'Dropdown menu: Select a menu option',\n *         menu: {\n *             items: [\n *                 new OO.ui.MenuOptionWidget( {\n *                     data: 'a',\n *                     label: 'First'\n *                 } ),\n *                 new OO.ui.MenuOptionWidget( {\n *                     data: 'b',\n *                     label: 'Second'\n *                 } ),\n *                 new OO.ui.MenuOptionWidget( {\n *                     data: 'c',\n *                     label: 'Third'\n *                 } )\n *             ]\n *         }\n *     } );\n *\n *     $( document.body ).append( dropDown.$element );\n *\n *     dropDown.getMenu().selectItemByData( 'b' );\n *\n *     dropDown.getMenu().findSelectedItem().getData(); // Returns 'b'.\n *\n * For more information, please see the [OOUI documentation on MediaWiki] [1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options#Menu_selects_and_options\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.IndicatorElement\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.TitledElement\n * @mixins OO.ui.mixin.TabIndexedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {Object} [menu] Configuration options to pass to\n *  {@link OO.ui.MenuSelectWidget menu select widget}.\n * @cfg {jQuery} [$overlay] Render the menu into a separate layer. This configuration is useful\n *  in cases where the expanded menu is larger than its containing `<div>`. The specified overlay\n *  layer is usually on top of the containing `<div>` and has a larger area. By default, the menu\n *  uses relative positioning.\n *  See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.\n */\nOO.ui.DropdownWidget = function OoUiDropdownWidget( config ) {\n\t// Configuration initialization\n\tconfig = $.extend( { indicator: 'down' }, config );\n\n\t// Parent constructor\n\tOO.ui.DropdownWidget.parent.call( this, config );\n\n\t// Properties (must be set before TabIndexedElement constructor call)\n\tthis.$handle = $( '<button>' );\n\tthis.$overlay = ( config.$overlay === true ?\n\t\tOO.ui.getDefaultOverlay() : config.$overlay ) || this.$element;\n\n\t// Mixin constructors\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.IndicatorElement.call( this, config );\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.TitledElement.call( this, $.extend( {\n\t\t$titled: this.$label\n\t}, config ) );\n\tOO.ui.mixin.TabIndexedElement.call( this, $.extend( {\n\t\t$tabIndexed: this.$handle\n\t}, config ) );\n\n\t// Properties\n\tthis.menu = new OO.ui.MenuSelectWidget( $.extend( {\n\t\twidget: this,\n\t\t$floatableContainer: this.$element\n\t}, config.menu ) );\n\n\t// Events\n\tthis.$handle.on( {\n\t\tclick: this.onClick.bind( this ),\n\t\tkeydown: this.onKeyDown.bind( this ),\n\t\t// Hack? Handle type-to-search when menu is not expanded and not handling its own events.\n\t\tkeypress: this.menu.onDocumentKeyPressHandler,\n\t\tblur: this.menu.clearKeyPressBuffer.bind( this.menu )\n\t} );\n\tthis.menu.connect( this, {\n\t\tselect: 'onMenuSelect',\n\t\ttoggle: 'onMenuToggle'\n\t} );\n\n\t// Initialization\n\tthis.$handle\n\t\t.addClass( 'oo-ui-dropdownWidget-handle' )\n\t\t.attr( {\n\t\t\ttype: 'button',\n\t\t\t'aria-owns': this.menu.getElementId(),\n\t\t\t'aria-haspopup': 'listbox'\n\t\t} )\n\t\t.append( this.$icon, this.$label, this.$indicator );\n\tthis.$element\n\t\t.addClass( 'oo-ui-dropdownWidget' )\n\t\t.append( this.$handle );\n\tthis.$overlay.append( this.menu.$element );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.DropdownWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.DropdownWidget, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.DropdownWidget, OO.ui.mixin.IndicatorElement );\nOO.mixinClass( OO.ui.DropdownWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.DropdownWidget, OO.ui.mixin.TitledElement );\nOO.mixinClass( OO.ui.DropdownWidget, OO.ui.mixin.TabIndexedElement );\n\n/* Methods */\n\n/**\n * Get the menu.\n *\n * @return {OO.ui.MenuSelectWidget} Menu of widget\n */\nOO.ui.DropdownWidget.prototype.getMenu = function () {\n\treturn this.menu;\n};\n\n/**\n * Handles menu select events.\n *\n * @private\n * @param {OO.ui.MenuOptionWidget} item Selected menu item\n */\nOO.ui.DropdownWidget.prototype.onMenuSelect = function ( item ) {\n\tvar selectedLabel;\n\n\tif ( !item ) {\n\t\tthis.setLabel( null );\n\t\treturn;\n\t}\n\n\tselectedLabel = item.getLabel();\n\n\t// If the label is a DOM element, clone it, because setLabel will append() it\n\tif ( selectedLabel instanceof $ ) {\n\t\tselectedLabel = selectedLabel.clone();\n\t}\n\n\tthis.setLabel( selectedLabel );\n};\n\n/**\n * Handle menu toggle events.\n *\n * @private\n * @param {boolean} isVisible Open state of the menu\n */\nOO.ui.DropdownWidget.prototype.onMenuToggle = function ( isVisible ) {\n\tthis.$element.toggleClass( 'oo-ui-dropdownWidget-open', isVisible );\n};\n\n/**\n * Handle mouse click events.\n *\n * @private\n * @param {jQuery.Event} e Mouse click event\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.DropdownWidget.prototype.onClick = function ( e ) {\n\tif ( !this.isDisabled() && e.which === OO.ui.MouseButtons.LEFT ) {\n\t\tthis.menu.toggle();\n\t}\n\treturn false;\n};\n\n/**\n * Handle key down events.\n *\n * @private\n * @param {jQuery.Event} e Key down event\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.DropdownWidget.prototype.onKeyDown = function ( e ) {\n\tif (\n\t\t!this.isDisabled() &&\n\t\t(\n\t\t\te.which === OO.ui.Keys.ENTER ||\n\t\t\t(\n\t\t\t\te.which === OO.ui.Keys.SPACE &&\n\t\t\t\t// Avoid conflicts with type-to-search, see SelectWidget#onKeyPress.\n\t\t\t\t// Space only closes the menu is the user is not typing to search.\n\t\t\t\tthis.menu.keyPressBuffer === ''\n\t\t\t) ||\n\t\t\t(\n\t\t\t\t!this.menu.isVisible() &&\n\t\t\t\t(\n\t\t\t\t\te.which === OO.ui.Keys.UP ||\n\t\t\t\t\te.which === OO.ui.Keys.DOWN\n\t\t\t\t)\n\t\t\t)\n\t\t)\n\t) {\n\t\tthis.menu.toggle();\n\t\treturn false;\n\t}\n};\n","/**\n * RadioOptionWidget is an option widget that looks like a radio button.\n * The class is used with OO.ui.RadioSelectWidget to create a selection of radio options.\n * Please see the [OOUI documentation on MediaWiki] [1] for more information.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options#Button_selects_and_option\n *\n * @class\n * @extends OO.ui.OptionWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.RadioOptionWidget = function OoUiRadioOptionWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties (must be done before parent constructor which calls #setDisabled)\n\tthis.radio = new OO.ui.RadioInputWidget( { value: config.data, tabIndex: -1 } );\n\n\t// Parent constructor\n\tOO.ui.RadioOptionWidget.parent.call( this, config );\n\n\t// Initialization\n\t// Remove implicit role, we're handling it ourselves\n\tthis.radio.$input.attr( 'role', 'presentation' );\n\tthis.$element\n\t\t.addClass( 'oo-ui-radioOptionWidget' )\n\t\t.attr( 'role', 'radio' )\n\t\t.attr( 'aria-checked', 'false' )\n\t\t.removeAttr( 'aria-selected' )\n\t\t.prepend( this.radio.$element );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.RadioOptionWidget, OO.ui.OptionWidget );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.RadioOptionWidget.static.highlightable = false;\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.RadioOptionWidget.static.scrollIntoViewOnSelect = true;\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.RadioOptionWidget.static.pressable = false;\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.RadioOptionWidget.static.tagName = 'label';\n\n/* Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioOptionWidget.prototype.setSelected = function ( state ) {\n\tOO.ui.RadioOptionWidget.parent.prototype.setSelected.call( this, state );\n\n\tthis.radio.setSelected( state );\n\tthis.$element\n\t\t.attr( 'aria-checked', state.toString() )\n\t\t.removeAttr( 'aria-selected' );\n\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioOptionWidget.prototype.setDisabled = function ( disabled ) {\n\tOO.ui.RadioOptionWidget.parent.prototype.setDisabled.call( this, disabled );\n\n\tthis.radio.setDisabled( this.isDisabled() );\n\n\treturn this;\n};\n","/**\n * RadioSelectWidget is a {@link OO.ui.SelectWidget select widget} that contains radio\n * options and is used together with OO.ui.RadioOptionWidget. The RadioSelectWidget provides\n * an interface for adding, removing and selecting options.\n * Please see the [OOUI documentation on MediaWiki][1] for more information.\n *\n * If you want to use this within an HTML form, such as a OO.ui.FormLayout, use\n * OO.ui.RadioSelectInputWidget instead.\n *\n *     @example\n *     // A RadioSelectWidget with RadioOptions.\n *     var option1 = new OO.ui.RadioOptionWidget( {\n *             data: 'a',\n *             label: 'Selected radio option'\n *         } ),\n *         option2 = new OO.ui.RadioOptionWidget( {\n *             data: 'b',\n *             label: 'Unselected radio option'\n *         } );\n *         radioSelect = new OO.ui.RadioSelectWidget( {\n *             items: [ option1, option2 ]\n *         } );\n *\n *     // Select 'option 1' using the RadioSelectWidget's selectItem() method.\n *     radioSelect.selectItem( option1 );\n *\n *     $( document.body ).append( radioSelect.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options\n\n *\n * @class\n * @extends OO.ui.SelectWidget\n * @mixins OO.ui.mixin.TabIndexedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.RadioSelectWidget = function OoUiRadioSelectWidget( config ) {\n\t// Parent constructor\n\tOO.ui.RadioSelectWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.TabIndexedElement.call( this, config );\n\n\t// Events\n\tthis.$element.on( {\n\t\tfocus: this.bindDocumentKeyDownListener.bind( this ),\n\t\tblur: this.unbindDocumentKeyDownListener.bind( this )\n\t} );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-radioSelectWidget' )\n\t\t.attr( 'role', 'radiogroup' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.RadioSelectWidget, OO.ui.SelectWidget );\nOO.mixinClass( OO.ui.RadioSelectWidget, OO.ui.mixin.TabIndexedElement );\n","/**\n * MultioptionWidgets are special elements that can be selected and configured with data. The\n * data is often unique for each option, but it does not have to be. MultioptionWidgets are used\n * with OO.ui.SelectWidget to create a selection of mutually exclusive options. For more information\n * and examples, please see the [OOUI documentation on MediaWiki][1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.ItemWidget\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.TitledElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [selected=false] Whether the option is initially selected\n */\nOO.ui.MultioptionWidget = function OoUiMultioptionWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.MultioptionWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.ItemWidget.call( this );\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.TitledElement.call( this, config );\n\n\t// Properties\n\tthis.selected = null;\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-multioptionWidget' )\n\t\t.append( this.$label );\n\tthis.setSelected( config.selected );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.MultioptionWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.MultioptionWidget, OO.ui.mixin.ItemWidget );\nOO.mixinClass( OO.ui.MultioptionWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.MultioptionWidget, OO.ui.mixin.TitledElement );\n\n/* Events */\n\n/**\n * @event change\n *\n * A change event is emitted when the selected state of the option changes.\n *\n * @param {boolean} selected Whether the option is now selected\n */\n\n/* Methods */\n\n/**\n * Check if the option is selected.\n *\n * @return {boolean} Item is selected\n */\nOO.ui.MultioptionWidget.prototype.isSelected = function () {\n\treturn this.selected;\n};\n\n/**\n * Set the option’s selected state. In general, all modifications to the selection\n * should be handled by the SelectWidget’s\n * {@link OO.ui.SelectWidget#selectItem selectItem( [item] )} method instead of this method.\n *\n * @param {boolean} [state=false] Select option\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.MultioptionWidget.prototype.setSelected = function ( state ) {\n\tstate = !!state;\n\tif ( this.selected !== state ) {\n\t\tthis.selected = state;\n\t\tthis.emit( 'change', state );\n\t\tthis.$element.toggleClass( 'oo-ui-multioptionWidget-selected', state );\n\t}\n\treturn this;\n};\n","/**\n * MultiselectWidget allows selecting multiple options from a list.\n *\n * For more information about menus and options, please see the [OOUI documentation\n * on MediaWiki][1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options#Menu_selects_and_options\n *\n * @class\n * @abstract\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.GroupWidget\n * @mixins OO.ui.mixin.TitledElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {OO.ui.MultioptionWidget[]} [items] An array of options to add to the multiselect.\n */\nOO.ui.MultiselectWidget = function OoUiMultiselectWidget( config ) {\n\t// Parent constructor\n\tOO.ui.MultiselectWidget.parent.call( this, config );\n\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Mixin constructors\n\tOO.ui.mixin.GroupWidget.call( this, config );\n\tOO.ui.mixin.TitledElement.call( this, config );\n\n\t// Events\n\tthis.aggregate( {\n\t\tchange: 'select'\n\t} );\n\t// This is mostly for compatibility with TagMultiselectWidget... normally, 'change' is emitted\n\t// by GroupElement only when items are added/removed\n\tthis.connect( this, {\n\t\tselect: [ 'emit', 'change' ]\n\t} );\n\n\t// Initialization\n\tif ( config.items ) {\n\t\tthis.addItems( config.items );\n\t}\n\tthis.$group.addClass( 'oo-ui-multiselectWidget-group' );\n\tthis.$element.addClass( 'oo-ui-multiselectWidget' )\n\t\t.append( this.$group );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.MultiselectWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.MultiselectWidget, OO.ui.mixin.GroupWidget );\nOO.mixinClass( OO.ui.MultiselectWidget, OO.ui.mixin.TitledElement );\n\n/* Events */\n\n/**\n * @event change\n *\n * A change event is emitted when the set of items changes, or an item is selected or deselected.\n */\n\n/**\n * @event select\n *\n * A select event is emitted when an item is selected or deselected.\n */\n\n/* Methods */\n\n/**\n * Find options that are selected.\n *\n * @return {OO.ui.MultioptionWidget[]} Selected options\n */\nOO.ui.MultiselectWidget.prototype.findSelectedItems = function () {\n\treturn this.items.filter( function ( item ) {\n\t\treturn item.isSelected();\n\t} );\n};\n\n/**\n * Find the data of options that are selected.\n *\n * @return {Object[]|string[]} Values of selected options\n */\nOO.ui.MultiselectWidget.prototype.findSelectedItemsData = function () {\n\treturn this.findSelectedItems().map( function ( item ) {\n\t\treturn item.data;\n\t} );\n};\n\n/**\n * Select options by reference. Options not mentioned in the `items` array will be deselected.\n *\n * @param {OO.ui.MultioptionWidget[]} items Items to select\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.MultiselectWidget.prototype.selectItems = function ( items ) {\n\tthis.items.forEach( function ( item ) {\n\t\tvar selected = items.indexOf( item ) !== -1;\n\t\titem.setSelected( selected );\n\t} );\n\treturn this;\n};\n\n/**\n * Select items by their data. Options not mentioned in the `datas` array will be deselected.\n *\n * @param {Object[]|string[]} datas Values of items to select\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.MultiselectWidget.prototype.selectItemsByData = function ( datas ) {\n\tvar items,\n\t\twidget = this;\n\titems = datas.map( function ( data ) {\n\t\treturn widget.findItemFromData( data );\n\t} );\n\tthis.selectItems( items );\n\treturn this;\n};\n","/**\n * CheckboxMultioptionWidget is an option widget that looks like a checkbox.\n * The class is used with OO.ui.CheckboxMultiselectWidget to create a selection of checkbox options.\n * Please see the [OOUI documentation on MediaWiki] [1] for more information.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options#Button_selects_and_option\n *\n * @class\n * @extends OO.ui.MultioptionWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.CheckboxMultioptionWidget = function OoUiCheckboxMultioptionWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties (must be done before parent constructor which calls #setDisabled)\n\tthis.checkbox = new OO.ui.CheckboxInputWidget();\n\n\t// Parent constructor\n\tOO.ui.CheckboxMultioptionWidget.parent.call( this, config );\n\n\t// Events\n\tthis.checkbox.on( 'change', this.onCheckboxChange.bind( this ) );\n\tthis.$element.on( 'keydown', this.onKeyDown.bind( this ) );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-checkboxMultioptionWidget' )\n\t\t.prepend( this.checkbox.$element );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.CheckboxMultioptionWidget, OO.ui.MultioptionWidget );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.CheckboxMultioptionWidget.static.tagName = 'label';\n\n/* Methods */\n\n/**\n * Handle checkbox selected state change.\n *\n * @private\n */\nOO.ui.CheckboxMultioptionWidget.prototype.onCheckboxChange = function () {\n\tthis.setSelected( this.checkbox.isSelected() );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxMultioptionWidget.prototype.setSelected = function ( state ) {\n\tOO.ui.CheckboxMultioptionWidget.parent.prototype.setSelected.call( this, state );\n\tthis.checkbox.setSelected( state );\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxMultioptionWidget.prototype.setDisabled = function ( disabled ) {\n\tOO.ui.CheckboxMultioptionWidget.parent.prototype.setDisabled.call( this, disabled );\n\tthis.checkbox.setDisabled( this.isDisabled() );\n\treturn this;\n};\n\n/**\n * Focus the widget.\n */\nOO.ui.CheckboxMultioptionWidget.prototype.focus = function () {\n\tthis.checkbox.focus();\n};\n\n/**\n * Handle key down events.\n *\n * @protected\n * @param {jQuery.Event} e\n */\nOO.ui.CheckboxMultioptionWidget.prototype.onKeyDown = function ( e ) {\n\tvar\n\t\telement = this.getElementGroup(),\n\t\tnextItem;\n\n\tif ( e.keyCode === OO.ui.Keys.LEFT || e.keyCode === OO.ui.Keys.UP ) {\n\t\tnextItem = element.getRelativeFocusableItem( this, -1 );\n\t} else if ( e.keyCode === OO.ui.Keys.RIGHT || e.keyCode === OO.ui.Keys.DOWN ) {\n\t\tnextItem = element.getRelativeFocusableItem( this, 1 );\n\t}\n\n\tif ( nextItem ) {\n\t\te.preventDefault();\n\t\tnextItem.focus();\n\t}\n};\n","/**\n * CheckboxMultiselectWidget is a {@link OO.ui.MultiselectWidget multiselect widget} that contains\n * checkboxes and is used together with OO.ui.CheckboxMultioptionWidget. The\n * CheckboxMultiselectWidget provides an interface for adding, removing and selecting options.\n * Please see the [OOUI documentation on MediaWiki][1] for more information.\n *\n * If you want to use this within an HTML form, such as a OO.ui.FormLayout, use\n * OO.ui.CheckboxMultiselectInputWidget instead.\n *\n *     @example\n *     // A CheckboxMultiselectWidget with CheckboxMultioptions.\n *     var option1 = new OO.ui.CheckboxMultioptionWidget( {\n *             data: 'a',\n *             selected: true,\n *             label: 'Selected checkbox'\n *         } ),\n *         option2 = new OO.ui.CheckboxMultioptionWidget( {\n *             data: 'b',\n *             label: 'Unselected checkbox'\n *         } ),\n *         multiselect = new OO.ui.CheckboxMultiselectWidget( {\n *             items: [ option1, option2 ]\n *         } );\n *     $( document.body ).append( multiselect.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options\n *\n * @class\n * @extends OO.ui.MultiselectWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.CheckboxMultiselectWidget = function OoUiCheckboxMultiselectWidget( config ) {\n\t// Parent constructor\n\tOO.ui.CheckboxMultiselectWidget.parent.call( this, config );\n\n\t// Properties\n\tthis.$lastClicked = null;\n\n\t// Events\n\tthis.$group.on( 'click', this.onClick.bind( this ) );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-checkboxMultiselectWidget' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.CheckboxMultiselectWidget, OO.ui.MultiselectWidget );\n\n/* Methods */\n\n/**\n * Get an option by its position relative to the specified item (or to the start of the\n * option array, if item is `null`). The direction in which to search through the option array\n * is specified with a number: -1 for reverse (the default) or 1 for forward. The method will\n * return an option, or `null` if there are no options in the array.\n *\n * @param {OO.ui.CheckboxMultioptionWidget|null} item Item to describe the start position, or\n *  `null` to start at the beginning of the array.\n * @param {number} direction Direction to move in: -1 to move backward, 1 to move forward\n * @return {OO.ui.CheckboxMultioptionWidget|null} Item at position, `null` if there are no items\n *  in the select.\n */\nOO.ui.CheckboxMultiselectWidget.prototype.getRelativeFocusableItem = function ( item, direction ) {\n\tvar currentIndex, nextIndex, i,\n\t\tincrease = direction > 0 ? 1 : -1,\n\t\tlen = this.items.length;\n\n\tif ( item ) {\n\t\tcurrentIndex = this.items.indexOf( item );\n\t\tnextIndex = ( currentIndex + increase + len ) % len;\n\t} else {\n\t\t// If no item is selected and moving forward, start at the beginning.\n\t\t// If moving backward, start at the end.\n\t\tnextIndex = direction > 0 ? 0 : len - 1;\n\t}\n\n\tfor ( i = 0; i < len; i++ ) {\n\t\titem = this.items[ nextIndex ];\n\t\tif ( item && !item.isDisabled() ) {\n\t\t\treturn item;\n\t\t}\n\t\tnextIndex = ( nextIndex + increase + len ) % len;\n\t}\n\treturn null;\n};\n\n/**\n * Handle click events on checkboxes.\n *\n * @param {jQuery.Event} e\n */\nOO.ui.CheckboxMultiselectWidget.prototype.onClick = function ( e ) {\n\tvar $options, lastClickedIndex, nowClickedIndex, i, direction, wasSelected, items,\n\t\t$lastClicked = this.$lastClicked,\n\t\t$nowClicked = $( e.target ).closest( '.oo-ui-checkboxMultioptionWidget' )\n\t\t\t.not( '.oo-ui-widget-disabled' );\n\n\t// Allow selecting multiple options at once by Shift-clicking them\n\tif ( $lastClicked && $nowClicked.length && e.shiftKey ) {\n\t\t$options = this.$group.find( '.oo-ui-checkboxMultioptionWidget' );\n\t\tlastClickedIndex = $options.index( $lastClicked );\n\t\tnowClickedIndex = $options.index( $nowClicked );\n\t\t// If it's the same item, either the user is being silly, or it's a fake event generated\n\t\t// by the browser. In either case we don't need custom handling.\n\t\tif ( nowClickedIndex !== lastClickedIndex ) {\n\t\t\titems = this.items;\n\t\t\twasSelected = items[ nowClickedIndex ].isSelected();\n\t\t\tdirection = nowClickedIndex > lastClickedIndex ? 1 : -1;\n\n\t\t\t// This depends on the DOM order of the items and the order of the .items array being\n\t\t\t// the same.\n\t\t\tfor ( i = lastClickedIndex; i !== nowClickedIndex; i += direction ) {\n\t\t\t\tif ( !items[ i ].isDisabled() ) {\n\t\t\t\t\titems[ i ].setSelected( !wasSelected );\n\t\t\t\t}\n\t\t\t}\n\t\t\t// For the now-clicked element, use immediate timeout to allow the browser to do its own\n\t\t\t// handling first, then set our value. The order in which events happen is different for\n\t\t\t// clicks on the <input> and on the <label> and there are additional fake clicks fired\n\t\t\t// for non-click actions that change the checkboxes.\n\t\t\te.preventDefault();\n\t\t\tsetTimeout( function () {\n\t\t\t\tif ( !items[ nowClickedIndex ].isDisabled() ) {\n\t\t\t\t\titems[ nowClickedIndex ].setSelected( !wasSelected );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t}\n\n\tif ( $nowClicked.length ) {\n\t\tthis.$lastClicked = $nowClicked;\n\t}\n};\n\n/**\n * Focus the widget\n *\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.CheckboxMultiselectWidget.prototype.focus = function () {\n\tvar item;\n\tif ( !this.isDisabled() ) {\n\t\titem = this.getRelativeFocusableItem( null, 1 );\n\t\tif ( item ) {\n\t\t\titem.focus();\n\t\t}\n\t}\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxMultiselectWidget.prototype.simulateLabelClick = function () {\n\tthis.focus();\n};\n","/**\n * Progress bars visually display the status of an operation, such as a download,\n * and can be either determinate or indeterminate:\n *\n * - **determinate** process bars show the percent of an operation that is complete.\n *\n * - **indeterminate** process bars use a visual display of motion to indicate that an operation\n *   is taking place. Because the extent of an indeterminate operation is unknown, the bar does\n *   not use percentages.\n *\n * The value of the `progress` configuration determines whether the bar is determinate\n * or indeterminate.\n *\n *     @example\n *     // Examples of determinate and indeterminate progress bars.\n *     var progressBar1 = new OO.ui.ProgressBarWidget( {\n *         progress: 33\n *     } );\n *     var progressBar2 = new OO.ui.ProgressBarWidget();\n *\n *     // Create a FieldsetLayout to layout progress bars.\n *     var fieldset = new OO.ui.FieldsetLayout;\n *     fieldset.addItems( [\n *         new OO.ui.FieldLayout( progressBar1, {\n *             label: 'Determinate',\n *             align: 'top'\n *         } ),\n *         new OO.ui.FieldLayout( progressBar2, {\n *             label: 'Indeterminate',\n *             align: 'top'\n *         } )\n *     ] );\n *     $( document.body ).append( fieldset.$element );\n *\n * @class\n * @extends OO.ui.Widget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {number|boolean} [progress=false] The type of progress bar (determinate or indeterminate).\n *  To create a determinate progress bar, specify a number that reflects the initial\n *  percent complete.\n *  By default, the progress bar is indeterminate.\n */\nOO.ui.ProgressBarWidget = function OoUiProgressBarWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.ProgressBarWidget.parent.call( this, config );\n\n\t// Properties\n\tthis.$bar = $( '<div>' );\n\tthis.progress = null;\n\n\t// Initialization\n\tthis.setProgress( config.progress !== undefined ? config.progress : false );\n\tthis.$bar.addClass( 'oo-ui-progressBarWidget-bar' );\n\tthis.$element\n\t\t.attr( {\n\t\t\trole: 'progressbar',\n\t\t\t'aria-valuemin': 0,\n\t\t\t'aria-valuemax': 100\n\t\t} )\n\t\t.addClass( 'oo-ui-progressBarWidget' )\n\t\t.append( this.$bar );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ProgressBarWidget, OO.ui.Widget );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.ProgressBarWidget.static.tagName = 'div';\n\n/* Methods */\n\n/**\n * Get the percent of the progress that has been completed. Indeterminate progresses will\n * return `false`.\n *\n * @return {number|boolean} Progress percent\n */\nOO.ui.ProgressBarWidget.prototype.getProgress = function () {\n\treturn this.progress;\n};\n\n/**\n * Set the percent of the process completed or `false` for an indeterminate process.\n *\n * @param {number|boolean} progress Progress percent or `false` for indeterminate\n */\nOO.ui.ProgressBarWidget.prototype.setProgress = function ( progress ) {\n\tthis.progress = progress;\n\n\tif ( progress !== false ) {\n\t\tthis.$bar.css( 'width', this.progress + '%' );\n\t\tthis.$element.attr( 'aria-valuenow', this.progress );\n\t} else {\n\t\tthis.$bar.css( 'width', '' );\n\t\tthis.$element.removeAttr( 'aria-valuenow' );\n\t}\n\tthis.$element.toggleClass( 'oo-ui-progressBarWidget-indeterminate', progress === false );\n};\n","/**\n * InputWidget is the base class for all input widgets, which\n * include {@link OO.ui.TextInputWidget text inputs}, {@link OO.ui.CheckboxInputWidget checkbox\n * inputs}, {@link OO.ui.RadioInputWidget radio inputs}, and\n * {@link OO.ui.ButtonInputWidget button inputs}.\n * See the [OOUI documentation on MediaWiki] [1] for more information and examples.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs\n *\n * @abstract\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.TabIndexedElement\n * @mixins OO.ui.mixin.TitledElement\n * @mixins OO.ui.mixin.AccessKeyedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {string} [name=''] The value of the input’s HTML `name` attribute.\n * @cfg {string} [value=''] The value of the input.\n * @cfg {string} [dir] The directionality of the input (ltr/rtl).\n * @cfg {string} [inputId] The value of the input’s HTML `id` attribute.\n * @cfg {Function} [inputFilter] The name of an input filter function. Input filters modify the\n *  value of an input before it is accepted.\n */\nOO.ui.InputWidget = function OoUiInputWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.InputWidget.parent.call( this, config );\n\n\t// Properties\n\t// See #reusePreInfuseDOM about config.$input\n\tthis.$input = config.$input || this.getInputElement( config );\n\tthis.value = '';\n\tthis.inputFilter = config.inputFilter;\n\n\t// Mixin constructors\n\tOO.ui.mixin.TabIndexedElement.call( this, $.extend( {\n\t\t$tabIndexed: this.$input\n\t}, config ) );\n\tOO.ui.mixin.TitledElement.call( this, $.extend( {\n\t\t$titled: this.$input\n\t}, config ) );\n\tOO.ui.mixin.AccessKeyedElement.call( this, $.extend( {\n\t\t$accessKeyed: this.$input\n\t}, config ) );\n\n\t// Events\n\tthis.$input.on( 'keydown mouseup cut paste change input select', this.onEdit.bind( this ) );\n\n\t// Initialization\n\tthis.$input\n\t\t.addClass( 'oo-ui-inputWidget-input' )\n\t\t.attr( 'name', config.name )\n\t\t.prop( 'disabled', this.isDisabled() );\n\tthis.$element\n\t\t.addClass( 'oo-ui-inputWidget' )\n\t\t.append( this.$input );\n\tthis.setValue( config.value );\n\tif ( config.dir ) {\n\t\tthis.setDir( config.dir );\n\t}\n\tif ( config.inputId !== undefined ) {\n\t\tthis.setInputId( config.inputId );\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.InputWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.InputWidget, OO.ui.mixin.TabIndexedElement );\nOO.mixinClass( OO.ui.InputWidget, OO.ui.mixin.TitledElement );\nOO.mixinClass( OO.ui.InputWidget, OO.ui.mixin.AccessKeyedElement );\n\n/* Static Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.InputWidget.static.reusePreInfuseDOM = function ( node, config ) {\n\tconfig = OO.ui.InputWidget.parent.static.reusePreInfuseDOM( node, config );\n\t// Reusing `$input` lets browsers preserve inputted values across page reloads, see T114134.\n\tconfig.$input = $( node ).find( '.oo-ui-inputWidget-input' );\n\treturn config;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.InputWidget.static.gatherPreInfuseState = function ( node, config ) {\n\tvar state = OO.ui.InputWidget.parent.static.gatherPreInfuseState( node, config );\n\tif ( config.$input && config.$input.length ) {\n\t\tstate.value = config.$input.val();\n\t\t// Might be better in TabIndexedElement, but it's awkward to do there because\n\t\t// mixins are awkward\n\t\tstate.focus = config.$input.is( ':focus' );\n\t}\n\treturn state;\n};\n\n/* Events */\n\n/**\n * @event change\n *\n * A change event is emitted when the value of the input changes.\n *\n * @param {string} value\n */\n\n/* Methods */\n\n/**\n * Get input element.\n *\n * Subclasses of OO.ui.InputWidget use the `config` parameter to produce different elements in\n * different circumstances. The element must have a `value` property (like form elements).\n *\n * @protected\n * @param {Object} config Configuration options\n * @return {jQuery} Input element\n */\nOO.ui.InputWidget.prototype.getInputElement = function () {\n\treturn $( '<input>' );\n};\n\n/**\n * Handle potentially value-changing events.\n *\n * @private\n * @param {jQuery.Event} e Key down, mouse up, cut, paste, change, input, or select event\n */\nOO.ui.InputWidget.prototype.onEdit = function () {\n\tvar widget = this;\n\tif ( !this.isDisabled() ) {\n\t\t// Allow the stack to clear so the value will be updated\n\t\tsetTimeout( function () {\n\t\t\twidget.setValue( widget.$input.val() );\n\t\t} );\n\t}\n};\n\n/**\n * Get the value of the input.\n *\n * @return {string} Input value\n */\nOO.ui.InputWidget.prototype.getValue = function () {\n\t// Resynchronize our internal data with DOM data. Other scripts executing on the page can modify\n\t// it, and we won't know unless they're kind enough to trigger a 'change' event.\n\tvar value = this.$input.val();\n\tif ( this.value !== value ) {\n\t\tthis.setValue( value );\n\t}\n\treturn this.value;\n};\n\n/**\n * Set the directionality of the input.\n *\n * @param {string} dir Text directionality: 'ltr', 'rtl' or 'auto'\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.InputWidget.prototype.setDir = function ( dir ) {\n\tthis.$input.prop( 'dir', dir );\n\treturn this;\n};\n\n/**\n * Set the value of the input.\n *\n * @param {string} value New value\n * @fires change\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.InputWidget.prototype.setValue = function ( value ) {\n\tvalue = this.cleanUpValue( value );\n\t// Update the DOM if it has changed. Note that with cleanUpValue, it\n\t// is possible for the DOM value to change without this.value changing.\n\tif ( this.$input.val() !== value ) {\n\t\tthis.$input.val( value );\n\t}\n\tif ( this.value !== value ) {\n\t\tthis.value = value;\n\t\tthis.emit( 'change', this.value );\n\t}\n\t// The first time that the value is set (probably while constructing the widget),\n\t// remember it in defaultValue. This property can be later used to check whether\n\t// the value of the input has been changed since it was created.\n\tif ( this.defaultValue === undefined ) {\n\t\tthis.defaultValue = this.value;\n\t\tthis.$input[ 0 ].defaultValue = this.defaultValue;\n\t}\n\treturn this;\n};\n\n/**\n * Clean up incoming value.\n *\n * Ensures value is a string, and converts undefined and null to empty string.\n *\n * @private\n * @param {string} value Original value\n * @return {string} Cleaned up value\n */\nOO.ui.InputWidget.prototype.cleanUpValue = function ( value ) {\n\tif ( value === undefined || value === null ) {\n\t\treturn '';\n\t} else if ( this.inputFilter ) {\n\t\treturn this.inputFilter( String( value ) );\n\t} else {\n\t\treturn String( value );\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.InputWidget.prototype.setDisabled = function ( state ) {\n\tOO.ui.InputWidget.parent.prototype.setDisabled.call( this, state );\n\tif ( this.$input ) {\n\t\tthis.$input.prop( 'disabled', this.isDisabled() );\n\t}\n\treturn this;\n};\n\n/**\n * Set the 'id' attribute of the `<input>` element.\n *\n * @param {string} id\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.InputWidget.prototype.setInputId = function ( id ) {\n\tthis.$input.attr( 'id', id );\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.InputWidget.prototype.restorePreInfuseState = function ( state ) {\n\tOO.ui.InputWidget.parent.prototype.restorePreInfuseState.call( this, state );\n\tif ( state.value !== undefined && state.value !== this.getValue() ) {\n\t\tthis.setValue( state.value );\n\t}\n\tif ( state.focus ) {\n\t\tthis.focus();\n\t}\n};\n","/**\n * Data widget intended for creating `<input type=\"hidden\">` inputs.\n *\n * @class\n * @extends OO.ui.Widget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {string} [value=''] The value of the input.\n * @cfg {string} [name=''] The value of the input’s HTML `name` attribute.\n */\nOO.ui.HiddenInputWidget = function OoUiHiddenInputWidget( config ) {\n\t// Configuration initialization\n\tconfig = $.extend( { value: '', name: '' }, config );\n\n\t// Parent constructor\n\tOO.ui.HiddenInputWidget.parent.call( this, config );\n\n\t// Initialization\n\tthis.$element.attr( {\n\t\ttype: 'hidden',\n\t\tvalue: config.value,\n\t\tname: config.name\n\t} );\n\tthis.$element.removeAttr( 'aria-disabled' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.HiddenInputWidget, OO.ui.Widget );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.HiddenInputWidget.static.tagName = 'input';\n","/**\n * ButtonInputWidget is used to submit HTML forms and is intended to be used within\n * a OO.ui.FormLayout. If you do not need the button to work with HTML forms, you probably\n * want to use OO.ui.ButtonWidget instead. Button input widgets can be rendered as either an\n * HTML `<button>` (the default) or an HTML `<input>` tags. See the\n * [OOUI documentation on MediaWiki] [1] for more information.\n *\n *     @example\n *     // A ButtonInputWidget rendered as an HTML button, the default.\n *     var button = new OO.ui.ButtonInputWidget( {\n *         label: 'Input button',\n *         icon: 'check',\n *         value: 'check'\n *     } );\n *     $( document.body ).append( button.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs#Button_inputs\n *\n * @class\n * @extends OO.ui.InputWidget\n * @mixins OO.ui.mixin.ButtonElement\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.IndicatorElement\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.FlaggedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {string} [type='button'] The value of the HTML `'type'` attribute:\n *  'button', 'submit' or 'reset'.\n * @cfg {boolean} [useInputTag=false] Use an `<input>` tag instead of a `<button>` tag, the default.\n *  Widgets configured to be an `<input>` do not support {@link #icon icons} and\n *  {@link #indicator indicators},\n *  non-plaintext {@link #label labels}, or {@link #value values}. In general, useInputTag should\n *  only be set to `true` when there’s need to support IE 6 in a form with multiple buttons.\n */\nOO.ui.ButtonInputWidget = function OoUiButtonInputWidget( config ) {\n\t// Configuration initialization\n\tconfig = $.extend( { type: 'button', useInputTag: false }, config );\n\n\t// See InputWidget#reusePreInfuseDOM about config.$input\n\tif ( config.$input ) {\n\t\tconfig.$input.empty();\n\t}\n\n\t// Properties (must be set before parent constructor, which calls #setValue)\n\tthis.useInputTag = config.useInputTag;\n\n\t// Parent constructor\n\tOO.ui.ButtonInputWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.ButtonElement.call( this, $.extend( {\n\t\t$button: this.$input\n\t}, config ) );\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.IndicatorElement.call( this, config );\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.FlaggedElement.call( this, config );\n\n\t// Initialization\n\tif ( !config.useInputTag ) {\n\t\tthis.$input.append( this.$icon, this.$label, this.$indicator );\n\t}\n\tthis.$element.addClass( 'oo-ui-buttonInputWidget' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ButtonInputWidget, OO.ui.InputWidget );\nOO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.mixin.ButtonElement );\nOO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.mixin.IndicatorElement );\nOO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.mixin.FlaggedElement );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.ButtonInputWidget.static.tagName = 'span';\n\n/* Methods */\n\n/**\n * @inheritdoc\n * @protected\n */\nOO.ui.ButtonInputWidget.prototype.getInputElement = function ( config ) {\n\tvar type;\n\ttype = [ 'button', 'submit', 'reset' ].indexOf( config.type ) !== -1 ? config.type : 'button';\n\treturn $( '<' + ( config.useInputTag ? 'input' : 'button' ) + ' type=\"' + type + '\">' );\n};\n\n/**\n * Set label value.\n *\n * If #useInputTag is `true`, the label is set as the `value` of the `<input>` tag.\n *\n * @param {jQuery|string|Function|null} label Label nodes, text, a function that returns nodes or\n *  text, or `null` for no label\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.ButtonInputWidget.prototype.setLabel = function ( label ) {\n\tif ( typeof label === 'function' ) {\n\t\tlabel = OO.ui.resolveMsg( label );\n\t}\n\n\tif ( this.useInputTag ) {\n\t\t// Discard non-plaintext labels\n\t\tif ( typeof label !== 'string' ) {\n\t\t\tlabel = '';\n\t\t}\n\n\t\tthis.$input.val( label );\n\t}\n\n\treturn OO.ui.mixin.LabelElement.prototype.setLabel.call( this, label );\n};\n\n/**\n * Set the value of the input.\n *\n * This method is disabled for button inputs configured as {@link #useInputTag <input> tags}, as\n * they do not support {@link #value values}.\n *\n * @param {string} value New value\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.ButtonInputWidget.prototype.setValue = function ( value ) {\n\tif ( !this.useInputTag ) {\n\t\tOO.ui.ButtonInputWidget.parent.prototype.setValue.call( this, value );\n\t}\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.ButtonInputWidget.prototype.getInputId = function () {\n\t// Disable generating `<label>` elements for buttons. One would very rarely need additional\n\t// label for a button, and it's already a big clickable target, and it causes\n\t// unexpected rendering.\n\treturn null;\n};\n","/**\n * CheckboxInputWidgets, like HTML checkboxes, can be selected and/or configured with a value.\n * Note that these {@link OO.ui.InputWidget input widgets} are best laid out\n * in {@link OO.ui.FieldLayout field layouts} that use the {@link OO.ui.FieldLayout#align inline}\n * alignment. For more information, please see the [OOUI documentation on MediaWiki][1].\n *\n * This widget can be used inside an HTML form, such as a OO.ui.FormLayout.\n *\n *     @example\n *     // An example of selected, unselected, and disabled checkbox inputs.\n *     var checkbox1 = new OO.ui.CheckboxInputWidget( {\n *             value: 'a',\n *              selected: true\n *         } ),\n *         checkbox2 = new OO.ui.CheckboxInputWidget( {\n *             value: 'b'\n *         } ),\n *         checkbox3 = new OO.ui.CheckboxInputWidget( {\n *             value:'c',\n *             disabled: true\n *         } ),\n *         // Create a fieldset layout with fields for each checkbox.\n *         fieldset = new OO.ui.FieldsetLayout( {\n *             label: 'Checkboxes'\n *         } );\n *     fieldset.addItems( [\n *         new OO.ui.FieldLayout( checkbox1, { label: 'Selected checkbox', align: 'inline' } ),\n *         new OO.ui.FieldLayout( checkbox2, { label: 'Unselected checkbox', align: 'inline' } ),\n *         new OO.ui.FieldLayout( checkbox3, { label: 'Disabled checkbox', align: 'inline' } ),\n *     ] );\n *     $( document.body ).append( fieldset.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs\n *\n * @class\n * @extends OO.ui.InputWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [selected=false] Select the checkbox initially. By default, the checkbox is\n *  not selected.\n */\nOO.ui.CheckboxInputWidget = function OoUiCheckboxInputWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.CheckboxInputWidget.parent.call( this, config );\n\n\t// Properties\n\tthis.checkIcon = new OO.ui.IconWidget( {\n\t\ticon: 'check',\n\t\tclasses: [ 'oo-ui-checkboxInputWidget-checkIcon' ]\n\t} );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-checkboxInputWidget' )\n\t\t// Required for pretty styling in WikimediaUI theme\n\t\t.append( this.checkIcon.$element );\n\tthis.setSelected( config.selected !== undefined ? config.selected : false );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.CheckboxInputWidget, OO.ui.InputWidget );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.CheckboxInputWidget.static.tagName = 'span';\n\n/* Static Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxInputWidget.static.gatherPreInfuseState = function ( node, config ) {\n\tvar state = OO.ui.CheckboxInputWidget.parent.static.gatherPreInfuseState( node, config );\n\tstate.checked = config.$input.prop( 'checked' );\n\treturn state;\n};\n\n/* Methods */\n\n/**\n * @inheritdoc\n * @protected\n */\nOO.ui.CheckboxInputWidget.prototype.getInputElement = function () {\n\treturn $( '<input>' ).attr( 'type', 'checkbox' );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxInputWidget.prototype.onEdit = function () {\n\tvar widget = this;\n\tif ( !this.isDisabled() ) {\n\t\t// Allow the stack to clear so the value will be updated\n\t\tsetTimeout( function () {\n\t\t\twidget.setSelected( widget.$input.prop( 'checked' ) );\n\t\t} );\n\t}\n};\n\n/**\n * Set selection state of this checkbox.\n *\n * @param {boolean} state `true` for selected\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.CheckboxInputWidget.prototype.setSelected = function ( state ) {\n\tstate = !!state;\n\tif ( this.selected !== state ) {\n\t\tthis.selected = state;\n\t\tthis.$input.prop( 'checked', this.selected );\n\t\tthis.emit( 'change', this.selected );\n\t}\n\t// The first time that the selection state is set (probably while constructing the widget),\n\t// remember it in defaultSelected. This property can be later used to check whether\n\t// the selection state of the input has been changed since it was created.\n\tif ( this.defaultSelected === undefined ) {\n\t\tthis.defaultSelected = this.selected;\n\t\tthis.$input[ 0 ].defaultChecked = this.defaultSelected;\n\t}\n\treturn this;\n};\n\n/**\n * Check if this checkbox is selected.\n *\n * @return {boolean} Checkbox is selected\n */\nOO.ui.CheckboxInputWidget.prototype.isSelected = function () {\n\t// Resynchronize our internal data with DOM data. Other scripts executing on the page can modify\n\t// it, and we won't know unless they're kind enough to trigger a 'change' event.\n\tvar selected = this.$input.prop( 'checked' );\n\tif ( this.selected !== selected ) {\n\t\tthis.setSelected( selected );\n\t}\n\treturn this.selected;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxInputWidget.prototype.simulateLabelClick = function () {\n\tif ( !this.isDisabled() ) {\n\t\tthis.$handle.trigger( 'click' );\n\t}\n\tthis.focus();\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxInputWidget.prototype.restorePreInfuseState = function ( state ) {\n\tOO.ui.CheckboxInputWidget.parent.prototype.restorePreInfuseState.call( this, state );\n\tif ( state.checked !== undefined && state.checked !== this.isSelected() ) {\n\t\tthis.setSelected( state.checked );\n\t}\n};\n","/**\n * DropdownInputWidget is a {@link OO.ui.DropdownWidget DropdownWidget} intended to be used\n * within an HTML form, such as a OO.ui.FormLayout. The selected value is synchronized with the\n * value of a hidden HTML `input` tag. Please see the [OOUI documentation on MediaWiki][1] for\n * more information about input widgets.\n *\n * A DropdownInputWidget always has a value (one of the options is always selected), unless there\n * are no options. If no `value` configuration option is provided, the first option is selected.\n * If you need a state representing no value (no option being selected), use a DropdownWidget.\n *\n * This and OO.ui.RadioSelectInputWidget support similar configuration options.\n *\n *     @example\n *     // A DropdownInputWidget with three options.\n *     var dropdownInput = new OO.ui.DropdownInputWidget( {\n *         options: [\n *             { data: 'a', label: 'First' },\n *             { data: 'b', label: 'Second', disabled: true },\n *             { optgroup: 'Group label' },\n *             { data: 'c', label: 'First sub-item)' }\n *         ]\n *     } );\n *     $( document.body ).append( dropdownInput.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs\n *\n * @class\n * @extends OO.ui.InputWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {Object[]} [options=[]] Array of menu options in the format described above.\n * @cfg {Object} [dropdown] Configuration options for {@link OO.ui.DropdownWidget DropdownWidget}\n * @cfg {jQuery} [$overlay] Render the menu into a separate layer. This configuration is useful\n *  in cases where the expanded menu is larger than its containing `<div>`. The specified overlay\n *  layer is usually on top of the containing `<div>` and has a larger area. By default, the menu\n *  uses relative positioning.\n *  See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.\n */\nOO.ui.DropdownInputWidget = function OoUiDropdownInputWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties (must be done before parent constructor which calls #setDisabled)\n\tthis.dropdownWidget = new OO.ui.DropdownWidget( $.extend(\n\t\t{\n\t\t\t$overlay: config.$overlay\n\t\t},\n\t\tconfig.dropdown\n\t) );\n\t// Set up the options before parent constructor, which uses them to validate config.value.\n\t// Use this instead of setOptions() because this.$input is not set up yet.\n\tthis.setOptionsData( config.options || [] );\n\n\t// Parent constructor\n\tOO.ui.DropdownInputWidget.parent.call( this, config );\n\n\t// Events\n\tthis.dropdownWidget.getMenu().connect( this, {\n\t\tselect: 'onMenuSelect'\n\t} );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-dropdownInputWidget' )\n\t\t.append( this.dropdownWidget.$element );\n\tthis.setTabIndexedElement( this.dropdownWidget.$tabIndexed );\n\tthis.setTitledElement( this.dropdownWidget.$handle );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.DropdownInputWidget, OO.ui.InputWidget );\n\n/* Methods */\n\n/**\n * @inheritdoc\n * @protected\n */\nOO.ui.DropdownInputWidget.prototype.getInputElement = function () {\n\treturn $( '<select>' );\n};\n\n/**\n * Handles menu select events.\n *\n * @private\n * @param {OO.ui.MenuOptionWidget|null} item Selected menu item\n */\nOO.ui.DropdownInputWidget.prototype.onMenuSelect = function ( item ) {\n\tthis.setValue( item ? item.getData() : '' );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.DropdownInputWidget.prototype.setValue = function ( value ) {\n\tvar selected;\n\tvalue = this.cleanUpValue( value );\n\t// Only allow setting values that are actually present in the dropdown\n\tselected = this.dropdownWidget.getMenu().findItemFromData( value ) ||\n\t\tthis.dropdownWidget.getMenu().findFirstSelectableItem();\n\tthis.dropdownWidget.getMenu().selectItem( selected );\n\tvalue = selected ? selected.getData() : '';\n\tOO.ui.DropdownInputWidget.parent.prototype.setValue.call( this, value );\n\tif ( this.optionsDirty ) {\n\t\t// We reached this from the constructor or from #setOptions.\n\t\t// We have to update the <select> element.\n\t\tthis.updateOptionsInterface();\n\t}\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.DropdownInputWidget.prototype.setDisabled = function ( state ) {\n\tthis.dropdownWidget.setDisabled( state );\n\tOO.ui.DropdownInputWidget.parent.prototype.setDisabled.call( this, state );\n\treturn this;\n};\n\n/**\n * Set the options available for this input.\n *\n * @param {Object[]} options Array of menu options in the format `{ data: …, label: … }`\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.DropdownInputWidget.prototype.setOptions = function ( options ) {\n\tvar value = this.getValue();\n\n\tthis.setOptionsData( options );\n\n\t// Re-set the value to update the visible interface (DropdownWidget and <select>).\n\t// In case the previous value is no longer an available option, select the first valid one.\n\tthis.setValue( value );\n\n\treturn this;\n};\n\n/**\n * Set the internal list of options, used e.g. by setValue() to see which options are allowed.\n *\n * This method may be called before the parent constructor, so various properties may not be\n * initialized yet.\n *\n * @param {Object[]} options Array of menu options (see #constructor for details).\n * @private\n */\nOO.ui.DropdownInputWidget.prototype.setOptionsData = function ( options ) {\n\tvar optionWidgets, optIndex, opt, previousOptgroup, optionWidget, optValue,\n\t\twidget = this;\n\n\tthis.optionsDirty = true;\n\n\t// Go through all the supplied option configs and create either\n\t// MenuSectionOption or MenuOption widgets from each.\n\toptionWidgets = [];\n\tfor ( optIndex = 0; optIndex < options.length; optIndex++ ) {\n\t\topt = options[ optIndex ];\n\n\t\tif ( opt.optgroup !== undefined ) {\n\t\t\t// Create a <optgroup> menu item.\n\t\t\toptionWidget = widget.createMenuSectionOptionWidget( opt.optgroup );\n\t\t\tpreviousOptgroup = optionWidget;\n\n\t\t} else {\n\t\t\t// Create a normal <option> menu item.\n\t\t\toptValue = widget.cleanUpValue( opt.data );\n\t\t\toptionWidget = widget.createMenuOptionWidget(\n\t\t\t\toptValue,\n\t\t\t\topt.label !== undefined ? opt.label : optValue\n\t\t\t);\n\t\t}\n\n\t\t// Disable the menu option if it is itself disabled or if its parent optgroup is disabled.\n\t\tif (\n\t\t\topt.disabled !== undefined ||\n\t\t\tpreviousOptgroup instanceof OO.ui.MenuSectionOptionWidget &&\n\t\t\tpreviousOptgroup.isDisabled()\n\t\t) {\n\t\t\toptionWidget.setDisabled( true );\n\t\t}\n\n\t\toptionWidgets.push( optionWidget );\n\t}\n\n\tthis.dropdownWidget.getMenu().clearItems().addItems( optionWidgets );\n};\n\n/**\n * Create a menu option widget.\n *\n * @protected\n * @param {string} data Item data\n * @param {string} label Item label\n * @return {OO.ui.MenuOptionWidget} Option widget\n */\nOO.ui.DropdownInputWidget.prototype.createMenuOptionWidget = function ( data, label ) {\n\treturn new OO.ui.MenuOptionWidget( {\n\t\tdata: data,\n\t\tlabel: label\n\t} );\n};\n\n/**\n * Create a menu section option widget.\n *\n * @protected\n * @param {string} label Section item label\n * @return {OO.ui.MenuSectionOptionWidget} Menu section option widget\n */\nOO.ui.DropdownInputWidget.prototype.createMenuSectionOptionWidget = function ( label ) {\n\treturn new OO.ui.MenuSectionOptionWidget( {\n\t\tlabel: label\n\t} );\n};\n\n/**\n * Update the user-visible interface to match the internal list of options and value.\n *\n * This method must only be called after the parent constructor.\n *\n * @private\n */\nOO.ui.DropdownInputWidget.prototype.updateOptionsInterface = function () {\n\tvar\n\t\t$optionsContainer = this.$input,\n\t\tdefaultValue = this.defaultValue,\n\t\twidget = this;\n\n\tthis.$input.empty();\n\n\tthis.dropdownWidget.getMenu().getItems().forEach( function ( optionWidget ) {\n\t\tvar $optionNode;\n\n\t\tif ( !( optionWidget instanceof OO.ui.MenuSectionOptionWidget ) ) {\n\t\t\t$optionNode = $( '<option>' )\n\t\t\t\t.attr( 'value', optionWidget.getData() )\n\t\t\t\t.text( optionWidget.getLabel() );\n\n\t\t\t// Remember original selection state. This property can be later used to check whether\n\t\t\t// the selection state of the input has been changed since it was created.\n\t\t\t$optionNode[ 0 ].defaultSelected = ( optionWidget.getData() === defaultValue );\n\n\t\t\t$optionsContainer.append( $optionNode );\n\t\t} else {\n\t\t\t$optionNode = $( '<optgroup>' )\n\t\t\t\t.attr( 'label', optionWidget.getLabel() );\n\t\t\twidget.$input.append( $optionNode );\n\t\t\t$optionsContainer = $optionNode;\n\t\t}\n\n\t\t// Disable the option or optgroup if required.\n\t\tif ( optionWidget.isDisabled() ) {\n\t\t\t$optionNode.prop( 'disabled', true );\n\t\t}\n\t} );\n\n\tthis.optionsDirty = false;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.DropdownInputWidget.prototype.focus = function () {\n\tthis.dropdownWidget.focus();\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.DropdownInputWidget.prototype.blur = function () {\n\tthis.dropdownWidget.blur();\n\treturn this;\n};\n","/**\n * RadioInputWidget creates a single radio button. Because radio buttons are usually used as a set,\n * in most cases you will want to use a {@link OO.ui.RadioSelectWidget radio select}\n * with {@link OO.ui.RadioOptionWidget radio options} instead of this class. For more information,\n * please see the [OOUI documentation on MediaWiki][1].\n *\n * This widget can be used inside an HTML form, such as a OO.ui.FormLayout.\n *\n *     @example\n *     // An example of selected, unselected, and disabled radio inputs\n *     var radio1 = new OO.ui.RadioInputWidget( {\n *         value: 'a',\n *         selected: true\n *     } );\n *     var radio2 = new OO.ui.RadioInputWidget( {\n *         value: 'b'\n *     } );\n *     var radio3 = new OO.ui.RadioInputWidget( {\n *         value: 'c',\n *         disabled: true\n *     } );\n *     // Create a fieldset layout with fields for each radio button.\n *     var fieldset = new OO.ui.FieldsetLayout( {\n *         label: 'Radio inputs'\n *     } );\n *     fieldset.addItems( [\n *         new OO.ui.FieldLayout( radio1, { label: 'Selected', align: 'inline' } ),\n *         new OO.ui.FieldLayout( radio2, { label: 'Unselected', align: 'inline' } ),\n *         new OO.ui.FieldLayout( radio3, { label: 'Disabled', align: 'inline' } ),\n *     ] );\n *     $( document.body ).append( fieldset.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs\n *\n * @class\n * @extends OO.ui.InputWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [selected=false] Select the radio button initially. By default, the radio button\n *  is not selected.\n */\nOO.ui.RadioInputWidget = function OoUiRadioInputWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.RadioInputWidget.parent.call( this, config );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-radioInputWidget' )\n\t\t// Required for pretty styling in WikimediaUI theme\n\t\t.append( $( '<span>' ) );\n\tthis.setSelected( config.selected !== undefined ? config.selected : false );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.RadioInputWidget, OO.ui.InputWidget );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.RadioInputWidget.static.tagName = 'span';\n\n/* Static Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioInputWidget.static.gatherPreInfuseState = function ( node, config ) {\n\tvar state = OO.ui.RadioInputWidget.parent.static.gatherPreInfuseState( node, config );\n\tstate.checked = config.$input.prop( 'checked' );\n\treturn state;\n};\n\n/* Methods */\n\n/**\n * @inheritdoc\n * @protected\n */\nOO.ui.RadioInputWidget.prototype.getInputElement = function () {\n\treturn $( '<input>' ).attr( 'type', 'radio' );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioInputWidget.prototype.onEdit = function () {\n\t// RadioInputWidget doesn't track its state.\n};\n\n/**\n * Set selection state of this radio button.\n *\n * @param {boolean} state `true` for selected\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.RadioInputWidget.prototype.setSelected = function ( state ) {\n\t// RadioInputWidget doesn't track its state.\n\tthis.$input.prop( 'checked', state );\n\t// The first time that the selection state is set (probably while constructing the widget),\n\t// remember it in defaultSelected. This property can be later used to check whether\n\t// the selection state of the input has been changed since it was created.\n\tif ( this.defaultSelected === undefined ) {\n\t\tthis.defaultSelected = state;\n\t\tthis.$input[ 0 ].defaultChecked = this.defaultSelected;\n\t}\n\treturn this;\n};\n\n/**\n * Check if this radio button is selected.\n *\n * @return {boolean} Radio is selected\n */\nOO.ui.RadioInputWidget.prototype.isSelected = function () {\n\treturn this.$input.prop( 'checked' );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioInputWidget.prototype.simulateLabelClick = function () {\n\tif ( !this.isDisabled() ) {\n\t\tthis.$input.trigger( 'click' );\n\t}\n\tthis.focus();\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioInputWidget.prototype.restorePreInfuseState = function ( state ) {\n\tOO.ui.RadioInputWidget.parent.prototype.restorePreInfuseState.call( this, state );\n\tif ( state.checked !== undefined && state.checked !== this.isSelected() ) {\n\t\tthis.setSelected( state.checked );\n\t}\n};\n","/**\n * RadioSelectInputWidget is a {@link OO.ui.RadioSelectWidget RadioSelectWidget} intended to be\n * used within an HTML form, such as a OO.ui.FormLayout. The selected value is synchronized with\n * the value of a hidden HTML `input` tag. Please see the [OOUI documentation on MediaWiki][1] for\n * more information about input widgets.\n *\n * This and OO.ui.DropdownInputWidget support similar configuration options.\n *\n *     @example\n *     // A RadioSelectInputWidget with three options\n *     var radioSelectInput = new OO.ui.RadioSelectInputWidget( {\n *         options: [\n *             { data: 'a', label: 'First' },\n *             { data: 'b', label: 'Second'},\n *             { data: 'c', label: 'Third' }\n *         ]\n *     } );\n *     $( document.body ).append( radioSelectInput.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs\n *\n * @class\n * @extends OO.ui.InputWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {Object[]} [options=[]] Array of menu options in the format `{ data: …, label: … }`\n */\nOO.ui.RadioSelectInputWidget = function OoUiRadioSelectInputWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties (must be done before parent constructor which calls #setDisabled)\n\tthis.radioSelectWidget = new OO.ui.RadioSelectWidget();\n\t// Set up the options before parent constructor, which uses them to validate config.value.\n\t// Use this instead of setOptions() because this.$input is not set up yet\n\tthis.setOptionsData( config.options || [] );\n\n\t// Parent constructor\n\tOO.ui.RadioSelectInputWidget.parent.call( this, config );\n\n\t// Events\n\tthis.radioSelectWidget.connect( this, {\n\t\tselect: 'onMenuSelect'\n\t} );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-radioSelectInputWidget' )\n\t\t.append( this.radioSelectWidget.$element );\n\tthis.setTabIndexedElement( this.radioSelectWidget.$tabIndexed );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.RadioSelectInputWidget, OO.ui.InputWidget );\n\n/* Static Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioSelectInputWidget.static.gatherPreInfuseState = function ( node, config ) {\n\tvar state = OO.ui.RadioSelectInputWidget.parent.static.gatherPreInfuseState( node, config );\n\tstate.value = $( node ).find( '.oo-ui-radioInputWidget .oo-ui-inputWidget-input:checked' ).val();\n\treturn state;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioSelectInputWidget.static.reusePreInfuseDOM = function ( node, config ) {\n\tconfig = OO.ui.RadioSelectInputWidget.parent.static.reusePreInfuseDOM( node, config );\n\t// Cannot reuse the `<input type=radio>` set\n\tdelete config.$input;\n\treturn config;\n};\n\n/* Methods */\n\n/**\n * @inheritdoc\n * @protected\n */\nOO.ui.RadioSelectInputWidget.prototype.getInputElement = function () {\n\t// Use this instead of <input type=\"hidden\">, because hidden inputs do not have separate\n\t// 'value' and 'defaultValue' properties, and InputWidget wants to handle 'defaultValue'.\n\treturn $( '<input>' ).addClass( 'oo-ui-element-hidden' );\n};\n\n/**\n * Handles menu select events.\n *\n * @private\n * @param {OO.ui.RadioOptionWidget} item Selected menu item\n */\nOO.ui.RadioSelectInputWidget.prototype.onMenuSelect = function ( item ) {\n\tthis.setValue( item.getData() );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioSelectInputWidget.prototype.setValue = function ( value ) {\n\tvar selected;\n\tvalue = this.cleanUpValue( value );\n\t// Only allow setting values that are actually present in the dropdown\n\tselected = this.radioSelectWidget.findItemFromData( value ) ||\n\t\tthis.radioSelectWidget.findFirstSelectableItem();\n\tthis.radioSelectWidget.selectItem( selected );\n\tvalue = selected ? selected.getData() : '';\n\tOO.ui.RadioSelectInputWidget.parent.prototype.setValue.call( this, value );\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioSelectInputWidget.prototype.setDisabled = function ( state ) {\n\tthis.radioSelectWidget.setDisabled( state );\n\tOO.ui.RadioSelectInputWidget.parent.prototype.setDisabled.call( this, state );\n\treturn this;\n};\n\n/**\n * Set the options available for this input.\n *\n * @param {Object[]} options Array of menu options in the format `{ data: …, label: … }`\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.RadioSelectInputWidget.prototype.setOptions = function ( options ) {\n\tvar value = this.getValue();\n\n\tthis.setOptionsData( options );\n\n\t// Re-set the value to update the visible interface (RadioSelectWidget).\n\t// In case the previous value is no longer an available option, select the first valid one.\n\tthis.setValue( value );\n\n\treturn this;\n};\n\n/**\n * Set the internal list of options, used e.g. by setValue() to see which options are allowed.\n *\n * This method may be called before the parent constructor, so various properties may not be\n * intialized yet.\n *\n * @param {Object[]} options Array of menu options in the format `{ data: …, label: … }`\n * @private\n */\nOO.ui.RadioSelectInputWidget.prototype.setOptionsData = function ( options ) {\n\tvar widget = this;\n\n\tthis.radioSelectWidget\n\t\t.clearItems()\n\t\t.addItems( options.map( function ( opt ) {\n\t\t\tvar optValue = widget.cleanUpValue( opt.data );\n\t\t\treturn new OO.ui.RadioOptionWidget( {\n\t\t\t\tdata: optValue,\n\t\t\t\tlabel: opt.label !== undefined ? opt.label : optValue\n\t\t\t} );\n\t\t} ) );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioSelectInputWidget.prototype.focus = function () {\n\tthis.radioSelectWidget.focus();\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioSelectInputWidget.prototype.blur = function () {\n\tthis.radioSelectWidget.blur();\n\treturn this;\n};\n","/**\n * CheckboxMultiselectInputWidget is a\n * {@link OO.ui.CheckboxMultiselectWidget CheckboxMultiselectWidget} intended to be used within a\n * HTML form, such as a OO.ui.FormLayout. The selected values are synchronized with the value of\n * HTML `<input type=checkbox>` tags. Please see the [OOUI documentation on MediaWiki][1] for\n * more information about input widgets.\n *\n *     @example\n *     // A CheckboxMultiselectInputWidget with three options.\n *     var multiselectInput = new OO.ui.CheckboxMultiselectInputWidget( {\n *         options: [\n *             { data: 'a', label: 'First' },\n *             { data: 'b', label: 'Second' },\n *             { data: 'c', label: 'Third' }\n *         ]\n *     } );\n *     $( document.body ).append( multiselectInput.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs\n *\n * @class\n * @extends OO.ui.InputWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {Object[]} [options=[]] Array of menu options in the format\n *  `{ data: …, label: …, disabled: … }`\n */\nOO.ui.CheckboxMultiselectInputWidget = function OoUiCheckboxMultiselectInputWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties (must be done before parent constructor which calls #setDisabled)\n\tthis.checkboxMultiselectWidget = new OO.ui.CheckboxMultiselectWidget();\n\t// Must be set before the #setOptionsData call below\n\tthis.inputName = config.name;\n\t// Set up the options before parent constructor, which uses them to validate config.value.\n\t// Use this instead of setOptions() because this.$input is not set up yet\n\tthis.setOptionsData( config.options || [] );\n\n\t// Parent constructor\n\tOO.ui.CheckboxMultiselectInputWidget.parent.call( this, config );\n\n\t// Events\n\tthis.checkboxMultiselectWidget.connect( this, {\n\t\tselect: 'onCheckboxesSelect'\n\t} );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-checkboxMultiselectInputWidget' )\n\t\t.append( this.checkboxMultiselectWidget.$element );\n\t// We don't use this.$input, but rather the CheckboxInputWidgets inside each option\n\tthis.$input.detach();\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.CheckboxMultiselectInputWidget, OO.ui.InputWidget );\n\n/* Static Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxMultiselectInputWidget.static.gatherPreInfuseState = function ( node, config ) {\n\tvar state = OO.ui.CheckboxMultiselectInputWidget.parent.static.gatherPreInfuseState(\n\t\tnode, config\n\t);\n\tstate.value = $( node ).find( '.oo-ui-checkboxInputWidget .oo-ui-inputWidget-input:checked' )\n\t\t.toArray().map( function ( el ) { return el.value; } );\n\treturn state;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxMultiselectInputWidget.static.reusePreInfuseDOM = function ( node, config ) {\n\tconfig = OO.ui.CheckboxMultiselectInputWidget.parent.static.reusePreInfuseDOM( node, config );\n\t// Cannot reuse the `<input type=checkbox>` set\n\tdelete config.$input;\n\treturn config;\n};\n\n/* Methods */\n\n/**\n * @inheritdoc\n * @protected\n */\nOO.ui.CheckboxMultiselectInputWidget.prototype.getInputElement = function () {\n\t// Actually unused\n\treturn $( '<unused>' );\n};\n\n/**\n * Handles CheckboxMultiselectWidget select events.\n *\n * @private\n */\nOO.ui.CheckboxMultiselectInputWidget.prototype.onCheckboxesSelect = function () {\n\tthis.setValue( this.checkboxMultiselectWidget.findSelectedItemsData() );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxMultiselectInputWidget.prototype.getValue = function () {\n\tvar value = this.$element.find( '.oo-ui-checkboxInputWidget .oo-ui-inputWidget-input:checked' )\n\t\t.toArray().map( function ( el ) { return el.value; } );\n\tif ( this.value !== value ) {\n\t\tthis.setValue( value );\n\t}\n\treturn this.value;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxMultiselectInputWidget.prototype.setValue = function ( value ) {\n\tvalue = this.cleanUpValue( value );\n\tthis.checkboxMultiselectWidget.selectItemsByData( value );\n\tOO.ui.CheckboxMultiselectInputWidget.parent.prototype.setValue.call( this, value );\n\tif ( this.optionsDirty ) {\n\t\t// We reached this from the constructor or from #setOptions.\n\t\t// We have to update the <select> element.\n\t\tthis.updateOptionsInterface();\n\t}\n\treturn this;\n};\n\n/**\n * Clean up incoming value.\n *\n * @param {string[]} value Original value\n * @return {string[]} Cleaned up value\n */\nOO.ui.CheckboxMultiselectInputWidget.prototype.cleanUpValue = function ( value ) {\n\tvar i, singleValue,\n\t\tcleanValue = [];\n\tif ( !Array.isArray( value ) ) {\n\t\treturn cleanValue;\n\t}\n\tfor ( i = 0; i < value.length; i++ ) {\n\t\tsingleValue = OO.ui.CheckboxMultiselectInputWidget.parent.prototype.cleanUpValue\n\t\t\t.call( this, value[ i ] );\n\t\t// Remove options that we don't have here\n\t\tif ( !this.checkboxMultiselectWidget.findItemFromData( singleValue ) ) {\n\t\t\tcontinue;\n\t\t}\n\t\tcleanValue.push( singleValue );\n\t}\n\treturn cleanValue;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxMultiselectInputWidget.prototype.setDisabled = function ( state ) {\n\tthis.checkboxMultiselectWidget.setDisabled( state );\n\tOO.ui.CheckboxMultiselectInputWidget.parent.prototype.setDisabled.call( this, state );\n\treturn this;\n};\n\n/**\n * Set the options available for this input.\n *\n * @param {Object[]} options Array of menu options in the format\n *  `{ data: …, label: …, disabled: … }`\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.CheckboxMultiselectInputWidget.prototype.setOptions = function ( options ) {\n\tvar value = this.getValue();\n\n\tthis.setOptionsData( options );\n\n\t// Re-set the value to update the visible interface (CheckboxMultiselectWidget).\n\t// This will also get rid of any stale options that we just removed.\n\tthis.setValue( value );\n\n\treturn this;\n};\n\n/**\n * Set the internal list of options, used e.g. by setValue() to see which options are allowed.\n *\n * This method may be called before the parent constructor, so various properties may not be\n * intialized yet.\n *\n * @param {Object[]} options Array of menu options in the format\n *  `{ data: …, label: … }`\n * @private\n */\nOO.ui.CheckboxMultiselectInputWidget.prototype.setOptionsData = function ( options ) {\n\tvar widget = this;\n\n\tthis.optionsDirty = true;\n\n\tthis.checkboxMultiselectWidget\n\t\t.clearItems()\n\t\t.addItems( options.map( function ( opt ) {\n\t\t\tvar optValue, item, optDisabled;\n\t\t\toptValue = OO.ui.CheckboxMultiselectInputWidget.parent.prototype.cleanUpValue\n\t\t\t\t.call( widget, opt.data );\n\t\t\toptDisabled = opt.disabled !== undefined ? opt.disabled : false;\n\t\t\titem = new OO.ui.CheckboxMultioptionWidget( {\n\t\t\t\tdata: optValue,\n\t\t\t\tlabel: opt.label !== undefined ? opt.label : optValue,\n\t\t\t\tdisabled: optDisabled\n\t\t\t} );\n\t\t\t// Set the 'name' and 'value' for form submission\n\t\t\titem.checkbox.$input.attr( 'name', widget.inputName );\n\t\t\titem.checkbox.setValue( optValue );\n\t\t\treturn item;\n\t\t} ) );\n};\n\n/**\n * Update the user-visible interface to match the internal list of options and value.\n *\n * This method must only be called after the parent constructor.\n *\n * @private\n */\nOO.ui.CheckboxMultiselectInputWidget.prototype.updateOptionsInterface = function () {\n\tvar defaultValue = this.defaultValue;\n\n\tthis.checkboxMultiselectWidget.getItems().forEach( function ( item ) {\n\t\t// Remember original selection state. This property can be later used to check whether\n\t\t// the selection state of the input has been changed since it was created.\n\t\tvar isDefault = defaultValue.indexOf( item.getData() ) !== -1;\n\t\titem.checkbox.defaultSelected = isDefault;\n\t\titem.checkbox.$input[ 0 ].defaultChecked = isDefault;\n\t} );\n\n\tthis.optionsDirty = false;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxMultiselectInputWidget.prototype.focus = function () {\n\tthis.checkboxMultiselectWidget.focus();\n\treturn this;\n};\n","/**\n * TextInputWidgets, like HTML text inputs, can be configured with options that customize the\n * size of the field as well as its presentation. In addition, these widgets can be configured\n * with {@link OO.ui.mixin.IconElement icons}, {@link OO.ui.mixin.IndicatorElement indicators}, an\n * optional validation-pattern (used to determine if an input value is valid or not) and an input\n * filter, which modifies incoming values rather than validating them.\n * Please see the [OOUI documentation on MediaWiki] [1] for more information and examples.\n *\n * This widget can be used inside an HTML form, such as a OO.ui.FormLayout.\n *\n *     @example\n *     // A TextInputWidget.\n *     var textInput = new OO.ui.TextInputWidget( {\n *         value: 'Text input'\n *     } )\n *     $( document.body ).append( textInput.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs\n *\n * @class\n * @extends OO.ui.InputWidget\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.IndicatorElement\n * @mixins OO.ui.mixin.PendingElement\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.FlaggedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {string} [type='text'] The value of the HTML `type` attribute: 'text', 'password'\n *  'email', 'url' or 'number'.\n * @cfg {string} [placeholder] Placeholder text\n * @cfg {boolean} [autofocus=false] Use an HTML `autofocus` attribute to\n *  instruct the browser to focus this widget.\n * @cfg {boolean} [readOnly=false] Prevent changes to the value of the text input.\n * @cfg {number} [maxLength] Maximum number of characters allowed in the input.\n *\n *  For unfortunate historical reasons, this counts the number of UTF-16 code units rather than\n *  Unicode codepoints, which means that codepoints outside the Basic Multilingual Plane (e.g.\n *  many emojis) count as 2 characters each.\n * @cfg {string} [labelPosition='after'] The position of the inline label relative to that of\n *  the value or placeholder text: `'before'` or `'after'`\n * @cfg {boolean} [required=false] Mark the field as required with `true`. Implies `indicator:\n *  'required'`. Note that `false` & setting `indicator: 'required' will result in no indicator\n *  shown.\n * @cfg {boolean} [autocomplete=true] Should the browser support autocomplete for this field\n * @cfg {boolean} [spellcheck] Should the browser support spellcheck for this field (`undefined`\n *  means leaving it up to the browser).\n * @cfg {RegExp|Function|string} [validate] Validation pattern: when string, a symbolic name of a\n *  pattern defined by the class: 'non-empty' (the value cannot be an empty string) or 'integer'\n *  (the value must contain only numbers); when RegExp, a regular expression that must match the\n *  value for it to be considered valid; when Function, a function receiving the value as parameter\n *  that must return true, or promise resolving to true, for it to be considered valid.\n */\nOO.ui.TextInputWidget = function OoUiTextInputWidget( config ) {\n\t// Configuration initialization\n\tconfig = $.extend( {\n\t\ttype: 'text',\n\t\tlabelPosition: 'after'\n\t}, config );\n\n\t// Parent constructor\n\tOO.ui.TextInputWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.IndicatorElement.call( this, config );\n\tOO.ui.mixin.PendingElement.call( this, $.extend( { $pending: this.$input }, config ) );\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.FlaggedElement.call( this, config );\n\n\t// Properties\n\tthis.type = this.getSaneType( config );\n\tthis.readOnly = false;\n\tthis.required = false;\n\tthis.validate = null;\n\tthis.scrollWidth = null;\n\n\tthis.setValidation( config.validate );\n\tthis.setLabelPosition( config.labelPosition );\n\n\t// Events\n\tthis.$input.on( {\n\t\tkeypress: this.onKeyPress.bind( this ),\n\t\tblur: this.onBlur.bind( this ),\n\t\tfocus: this.onFocus.bind( this )\n\t} );\n\tthis.$icon.on( 'mousedown', this.onIconMouseDown.bind( this ) );\n\tthis.$indicator.on( 'mousedown', this.onIndicatorMouseDown.bind( this ) );\n\tthis.on( 'labelChange', this.updatePosition.bind( this ) );\n\tthis.on( 'change', OO.ui.debounce( this.onDebouncedChange.bind( this ), 250 ) );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-textInputWidget oo-ui-textInputWidget-type-' + this.type )\n\t\t.append( this.$icon, this.$indicator );\n\tthis.setReadOnly( !!config.readOnly );\n\tthis.setRequired( !!config.required );\n\tif ( config.placeholder !== undefined ) {\n\t\tthis.$input.attr( 'placeholder', config.placeholder );\n\t}\n\tif ( config.maxLength !== undefined ) {\n\t\tthis.$input.attr( 'maxlength', config.maxLength );\n\t}\n\tif ( config.autofocus ) {\n\t\tthis.$input.attr( 'autofocus', 'autofocus' );\n\t}\n\tif ( config.autocomplete === false ) {\n\t\tthis.$input.attr( 'autocomplete', 'off' );\n\t\t// Turning off autocompletion also disables \"form caching\" when the user navigates to a\n\t\t// different page and then clicks \"Back\". Re-enable it when leaving.\n\t\t// Borrowed from jQuery UI.\n\t\t$( window ).on( {\n\t\t\tbeforeunload: function () {\n\t\t\t\tthis.$input.removeAttr( 'autocomplete' );\n\t\t\t}.bind( this ),\n\t\t\tpageshow: function () {\n\t\t\t\t// Browsers don't seem to actually fire this event on \"Back\", they instead just\n\t\t\t\t// reload the whole page... it shouldn't hurt, though.\n\t\t\t\tthis.$input.attr( 'autocomplete', 'off' );\n\t\t\t}.bind( this )\n\t\t} );\n\t}\n\tif ( config.spellcheck !== undefined ) {\n\t\tthis.$input.attr( 'spellcheck', config.spellcheck ? 'true' : 'false' );\n\t}\n\tif ( this.label ) {\n\t\tthis.isWaitingToBeAttached = true;\n\t\tthis.installParentChangeDetector();\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.TextInputWidget, OO.ui.InputWidget );\nOO.mixinClass( OO.ui.TextInputWidget, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.TextInputWidget, OO.ui.mixin.IndicatorElement );\nOO.mixinClass( OO.ui.TextInputWidget, OO.ui.mixin.PendingElement );\nOO.mixinClass( OO.ui.TextInputWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.TextInputWidget, OO.ui.mixin.FlaggedElement );\n\n/* Static Properties */\n\nOO.ui.TextInputWidget.static.validationPatterns = {\n\t'non-empty': /.+/,\n\tinteger: /^\\d+$/\n};\n\n/* Events */\n\n/**\n * An `enter` event is emitted when the user presses Enter key inside the text box.\n *\n * @event enter\n */\n\n/* Methods */\n\n/**\n * Handle icon mouse down events.\n *\n * @private\n * @param {jQuery.Event} e Mouse down event\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.TextInputWidget.prototype.onIconMouseDown = function ( e ) {\n\tif ( e.which === OO.ui.MouseButtons.LEFT ) {\n\t\tthis.focus();\n\t\treturn false;\n\t}\n};\n\n/**\n * Handle indicator mouse down events.\n *\n * @private\n * @param {jQuery.Event} e Mouse down event\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.TextInputWidget.prototype.onIndicatorMouseDown = function ( e ) {\n\tif ( e.which === OO.ui.MouseButtons.LEFT ) {\n\t\tthis.focus();\n\t\treturn false;\n\t}\n};\n\n/**\n * Handle key press events.\n *\n * @private\n * @param {jQuery.Event} e Key press event\n * @fires enter If Enter key is pressed\n */\nOO.ui.TextInputWidget.prototype.onKeyPress = function ( e ) {\n\tif ( e.which === OO.ui.Keys.ENTER ) {\n\t\tthis.emit( 'enter', e );\n\t}\n};\n\n/**\n * Handle blur events.\n *\n * @private\n * @param {jQuery.Event} e Blur event\n */\nOO.ui.TextInputWidget.prototype.onBlur = function () {\n\tthis.setValidityFlag();\n};\n\n/**\n * Handle focus events.\n *\n * @private\n * @param {jQuery.Event} e Focus event\n */\nOO.ui.TextInputWidget.prototype.onFocus = function () {\n\tif ( this.isWaitingToBeAttached ) {\n\t\t// If we've received focus, then we must be attached to the document, and if\n\t\t// isWaitingToBeAttached is still true, that means the handler never fired. Fire it now.\n\t\tthis.onElementAttach();\n\t}\n\tthis.setValidityFlag( true );\n};\n\n/**\n * Handle element attach events.\n *\n * @private\n * @param {jQuery.Event} e Element attach event\n */\nOO.ui.TextInputWidget.prototype.onElementAttach = function () {\n\tthis.isWaitingToBeAttached = false;\n\t// Any previously calculated size is now probably invalid if we reattached elsewhere\n\tthis.valCache = null;\n\tthis.positionLabel();\n};\n\n/**\n * Handle debounced change events.\n *\n * @param {string} value\n * @private\n */\nOO.ui.TextInputWidget.prototype.onDebouncedChange = function () {\n\tthis.setValidityFlag();\n};\n\n/**\n * Check if the input is {@link #readOnly read-only}.\n *\n * @return {boolean}\n */\nOO.ui.TextInputWidget.prototype.isReadOnly = function () {\n\treturn this.readOnly;\n};\n\n/**\n * Set the {@link #readOnly read-only} state of the input.\n *\n * @param {boolean} state Make input read-only\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TextInputWidget.prototype.setReadOnly = function ( state ) {\n\tthis.readOnly = !!state;\n\tthis.$input.prop( 'readOnly', this.readOnly );\n\treturn this;\n};\n\n/**\n * Check if the input is {@link #required required}.\n *\n * @return {boolean}\n */\nOO.ui.TextInputWidget.prototype.isRequired = function () {\n\treturn this.required;\n};\n\n/**\n * Set the {@link #required required} state of the input.\n *\n * @param {boolean} state Make input required\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TextInputWidget.prototype.setRequired = function ( state ) {\n\tthis.required = !!state;\n\tif ( this.required ) {\n\t\tthis.$input\n\t\t\t.prop( 'required', true )\n\t\t\t.attr( 'aria-required', 'true' );\n\t\tif ( this.getIndicator() === null ) {\n\t\t\tthis.setIndicator( 'required' );\n\t\t}\n\t} else {\n\t\tthis.$input\n\t\t\t.prop( 'required', false )\n\t\t\t.removeAttr( 'aria-required' );\n\t\tif ( this.getIndicator() === 'required' ) {\n\t\t\tthis.setIndicator( null );\n\t\t}\n\t}\n\treturn this;\n};\n\n/**\n * Support function for making #onElementAttach work across browsers.\n *\n * This whole function could be replaced with one line of code using the DOMNodeInsertedIntoDocument\n * event, but it's not supported by Firefox and allegedly deprecated, so we only use it as fallback.\n *\n * Due to MutationObserver performance woes, #onElementAttach is only somewhat reliably called the\n * first time that the element gets attached to the documented.\n */\nOO.ui.TextInputWidget.prototype.installParentChangeDetector = function () {\n\tvar mutationObserver, onRemove, topmostNode, fakeParentNode,\n\t\tMutationObserver = window.MutationObserver ||\n\t\t\twindow.WebKitMutationObserver ||\n\t\t\twindow.MozMutationObserver,\n\t\twidget = this;\n\n\tif ( MutationObserver ) {\n\t\t// The new way. If only it wasn't so ugly.\n\n\t\tif ( this.isElementAttached() ) {\n\t\t\t// Widget is attached already, do nothing. This breaks the functionality of this\n\t\t\t// function when the widget is detached and reattached. Alas, doing this correctly with\n\t\t\t// MutationObserver would require observation of the whole document, which would hurt\n\t\t\t// performance of other, more important code.\n\t\t\treturn;\n\t\t}\n\n\t\t// Find topmost node in the tree\n\t\ttopmostNode = this.$element[ 0 ];\n\t\twhile ( topmostNode.parentNode ) {\n\t\t\ttopmostNode = topmostNode.parentNode;\n\t\t}\n\n\t\t// We have no way to detect the $element being attached somewhere without observing the\n\t\t// entire DOM with subtree modifications, which would hurt performance. So we cheat: we hook\n\t\t// to the parent node of $element, and instead detect when $element is removed from it (and\n\t\t// thus probably attached somewhere else). If there is no parent, we create a \"fake\" one. If\n\t\t// it doesn't get attached, we end up back here and create the parent.\n\t\tmutationObserver = new MutationObserver( function ( mutations ) {\n\t\t\tvar i, j, removedNodes;\n\t\t\tfor ( i = 0; i < mutations.length; i++ ) {\n\t\t\t\tremovedNodes = mutations[ i ].removedNodes;\n\t\t\t\tfor ( j = 0; j < removedNodes.length; j++ ) {\n\t\t\t\t\tif ( removedNodes[ j ] === topmostNode ) {\n\t\t\t\t\t\tsetTimeout( onRemove, 0 );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\tonRemove = function () {\n\t\t\t// If the node was attached somewhere else, report it\n\t\t\tif ( widget.isElementAttached() ) {\n\t\t\t\twidget.onElementAttach();\n\t\t\t}\n\t\t\tmutationObserver.disconnect();\n\t\t\twidget.installParentChangeDetector();\n\t\t};\n\n\t\t// Create a fake parent and observe it\n\t\tfakeParentNode = $( '<div>' ).append( topmostNode )[ 0 ];\n\t\tmutationObserver.observe( fakeParentNode, { childList: true } );\n\t} else {\n\t\t// Using the DOMNodeInsertedIntoDocument event is much nicer and less magical, and works for\n\t\t// detachment and reattachment, but it's not supported by Firefox and allegedly deprecated.\n\t\tthis.$element.on( 'DOMNodeInsertedIntoDocument', this.onElementAttach.bind( this ) );\n\t}\n};\n\n/**\n * @inheritdoc\n * @protected\n */\nOO.ui.TextInputWidget.prototype.getInputElement = function ( config ) {\n\tif ( this.getSaneType( config ) === 'number' ) {\n\t\treturn $( '<input>' )\n\t\t\t.attr( 'step', 'any' )\n\t\t\t.attr( 'type', 'number' );\n\t} else {\n\t\treturn $( '<input>' ).attr( 'type', this.getSaneType( config ) );\n\t}\n};\n\n/**\n * Get sanitized value for 'type' for given config.\n *\n * @param {Object} config Configuration options\n * @return {string|null}\n * @protected\n */\nOO.ui.TextInputWidget.prototype.getSaneType = function ( config ) {\n\tvar allowedTypes = [\n\t\t'text',\n\t\t'password',\n\t\t'email',\n\t\t'url',\n\t\t'number'\n\t];\n\treturn allowedTypes.indexOf( config.type ) !== -1 ? config.type : 'text';\n};\n\n/**\n * Focus the input and select a specified range within the text.\n *\n * @param {number} from Select from offset\n * @param {number} [to] Select to offset, defaults to from\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TextInputWidget.prototype.selectRange = function ( from, to ) {\n\tvar isBackwards, start, end,\n\t\tinput = this.$input[ 0 ];\n\n\tto = to || from;\n\n\tisBackwards = to < from;\n\tstart = isBackwards ? to : from;\n\tend = isBackwards ? from : to;\n\n\tthis.focus();\n\n\ttry {\n\t\tinput.setSelectionRange( start, end, isBackwards ? 'backward' : 'forward' );\n\t} catch ( e ) {\n\t\t// IE throws an exception if you call setSelectionRange on a unattached DOM node.\n\t\t// Rather than expensively check if the input is attached every time, just check\n\t\t// if it was the cause of an error being thrown. If not, rethrow the error.\n\t\tif ( this.getElementDocument().body.contains( input ) ) {\n\t\t\tthrow e;\n\t\t}\n\t}\n\treturn this;\n};\n\n/**\n * Get an object describing the current selection range in a directional manner\n *\n * @return {Object} Object containing 'from' and 'to' offsets\n */\nOO.ui.TextInputWidget.prototype.getRange = function () {\n\tvar input = this.$input[ 0 ],\n\t\tstart = input.selectionStart,\n\t\tend = input.selectionEnd,\n\t\tisBackwards = input.selectionDirection === 'backward';\n\n\treturn {\n\t\tfrom: isBackwards ? end : start,\n\t\tto: isBackwards ? start : end\n\t};\n};\n\n/**\n * Get the length of the text input value.\n *\n * This could differ from the length of #getValue if the\n * value gets filtered\n *\n * @return {number} Input length\n */\nOO.ui.TextInputWidget.prototype.getInputLength = function () {\n\treturn this.$input[ 0 ].value.length;\n};\n\n/**\n * Focus the input and select the entire text.\n *\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TextInputWidget.prototype.select = function () {\n\treturn this.selectRange( 0, this.getInputLength() );\n};\n\n/**\n * Focus the input and move the cursor to the start.\n *\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TextInputWidget.prototype.moveCursorToStart = function () {\n\treturn this.selectRange( 0 );\n};\n\n/**\n * Focus the input and move the cursor to the end.\n *\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TextInputWidget.prototype.moveCursorToEnd = function () {\n\treturn this.selectRange( this.getInputLength() );\n};\n\n/**\n * Insert new content into the input.\n *\n * @param {string} content Content to be inserted\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TextInputWidget.prototype.insertContent = function ( content ) {\n\tvar start, end,\n\t\trange = this.getRange(),\n\t\tvalue = this.getValue();\n\n\tstart = Math.min( range.from, range.to );\n\tend = Math.max( range.from, range.to );\n\n\tthis.setValue( value.slice( 0, start ) + content + value.slice( end ) );\n\tthis.selectRange( start + content.length );\n\treturn this;\n};\n\n/**\n * Insert new content either side of a selection.\n *\n * @param {string} pre Content to be inserted before the selection\n * @param {string} post Content to be inserted after the selection\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TextInputWidget.prototype.encapsulateContent = function ( pre, post ) {\n\tvar start, end,\n\t\trange = this.getRange(),\n\t\toffset = pre.length;\n\n\tstart = Math.min( range.from, range.to );\n\tend = Math.max( range.from, range.to );\n\n\tthis.selectRange( start ).insertContent( pre );\n\tthis.selectRange( offset + end ).insertContent( post );\n\n\tthis.selectRange( offset + start, offset + end );\n\treturn this;\n};\n\n/**\n * Set the validation pattern.\n *\n * The validation pattern is either a regular expression, a function, or the symbolic name of a\n * pattern defined by the class: 'non-empty' (the value cannot be an empty string) or 'integer' (the\n * value must contain only numbers).\n *\n * @param {RegExp|Function|string|null} validate Regular expression, function, or the symbolic name\n *  of a pattern (either ‘integer’ or ‘non-empty’) defined by the class.\n */\nOO.ui.TextInputWidget.prototype.setValidation = function ( validate ) {\n\tif ( validate instanceof RegExp || validate instanceof Function ) {\n\t\tthis.validate = validate;\n\t} else {\n\t\tthis.validate = this.constructor.static.validationPatterns[ validate ] || /.*/;\n\t}\n};\n\n/**\n * Sets the 'invalid' flag appropriately.\n *\n * @param {boolean} [isValid] Optionally override validation result\n */\nOO.ui.TextInputWidget.prototype.setValidityFlag = function ( isValid ) {\n\tvar widget = this,\n\t\tsetFlag = function ( valid ) {\n\t\t\tif ( !valid ) {\n\t\t\t\twidget.$input.attr( 'aria-invalid', 'true' );\n\t\t\t} else {\n\t\t\t\twidget.$input.removeAttr( 'aria-invalid' );\n\t\t\t}\n\t\t\twidget.setFlags( { invalid: !valid } );\n\t\t};\n\n\tif ( isValid !== undefined ) {\n\t\tsetFlag( isValid );\n\t} else {\n\t\tthis.getValidity().then( function () {\n\t\t\tsetFlag( true );\n\t\t}, function () {\n\t\t\tsetFlag( false );\n\t\t} );\n\t}\n};\n\n/**\n * Get the validity of current value.\n *\n * This method returns a promise that resolves if the value is valid and rejects if\n * it isn't. Uses the {@link #validate validation pattern}  to check for validity.\n *\n * @return {jQuery.Promise} A promise that resolves if the value is valid, rejects if not.\n */\nOO.ui.TextInputWidget.prototype.getValidity = function () {\n\tvar result;\n\n\tfunction rejectOrResolve( valid ) {\n\t\tif ( valid ) {\n\t\t\treturn $.Deferred().resolve().promise();\n\t\t} else {\n\t\t\treturn $.Deferred().reject().promise();\n\t\t}\n\t}\n\n\t// Check browser validity and reject if it is invalid\n\tif (\n\t\tthis.$input[ 0 ].checkValidity !== undefined &&\n\t\tthis.$input[ 0 ].checkValidity() === false\n\t) {\n\t\treturn rejectOrResolve( false );\n\t}\n\n\t// Run our checks if the browser thinks the field is valid\n\tif ( this.validate instanceof Function ) {\n\t\tresult = this.validate( this.getValue() );\n\t\tif ( result && typeof result.promise === 'function' ) {\n\t\t\treturn result.promise().then( function ( valid ) {\n\t\t\t\treturn rejectOrResolve( valid );\n\t\t\t} );\n\t\t} else {\n\t\t\treturn rejectOrResolve( result );\n\t\t}\n\t} else {\n\t\treturn rejectOrResolve( this.getValue().match( this.validate ) );\n\t}\n};\n\n/**\n * Set the position of the inline label relative to that of the value: `‘before’` or `‘after’`.\n *\n * @param {string} labelPosition Label position, 'before' or 'after'\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TextInputWidget.prototype.setLabelPosition = function ( labelPosition ) {\n\tthis.labelPosition = labelPosition;\n\tif ( this.label ) {\n\t\t// If there is no label and we only change the position, #updatePosition is a no-op,\n\t\t// but it takes really a lot of work to do nothing.\n\t\tthis.updatePosition();\n\t}\n\treturn this;\n};\n\n/**\n * Update the position of the inline label.\n *\n * This method is called by #setLabelPosition, and can also be called on its own if\n * something causes the label to be mispositioned.\n *\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TextInputWidget.prototype.updatePosition = function () {\n\tvar after = this.labelPosition === 'after';\n\n\tthis.$element\n\t\t.toggleClass( 'oo-ui-textInputWidget-labelPosition-after', !!this.label && after )\n\t\t.toggleClass( 'oo-ui-textInputWidget-labelPosition-before', !!this.label && !after );\n\n\tthis.valCache = null;\n\tthis.scrollWidth = null;\n\tthis.positionLabel();\n\n\treturn this;\n};\n\n/**\n * Position the label by setting the correct padding on the input.\n *\n * @private\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TextInputWidget.prototype.positionLabel = function () {\n\tvar after, rtl, property, newCss;\n\n\tif ( this.isWaitingToBeAttached ) {\n\t\t// #onElementAttach will be called soon, which calls this method\n\t\treturn this;\n\t}\n\n\tnewCss = {\n\t\t'padding-right': '',\n\t\t'padding-left': ''\n\t};\n\n\tif ( this.label ) {\n\t\tthis.$element.append( this.$label );\n\t} else {\n\t\tthis.$label.detach();\n\t\t// Clear old values if present\n\t\tthis.$input.css( newCss );\n\t\treturn;\n\t}\n\n\tafter = this.labelPosition === 'after';\n\trtl = this.$element.css( 'direction' ) === 'rtl';\n\tproperty = after === rtl ? 'padding-left' : 'padding-right';\n\n\tnewCss[ property ] = this.$label.outerWidth( true ) + ( after ? this.scrollWidth : 0 );\n\t// We have to clear the padding on the other side, in case the element direction changed\n\tthis.$input.css( newCss );\n\n\treturn this;\n};\n","/**\n * SearchInputWidgets are TextInputWidgets with `type=\"search\"` assigned and feature a\n * {@link OO.ui.mixin.IconElement search icon} by default.\n * Please see the [OOUI documentation on MediaWiki] [1] for more information and examples.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs#SearchInputWidget\n *\n * @class\n * @extends OO.ui.TextInputWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.SearchInputWidget = function OoUiSearchInputWidget( config ) {\n\tconfig = $.extend( {\n\t\ticon: 'search'\n\t}, config );\n\n\t// Parent constructor\n\tOO.ui.SearchInputWidget.parent.call( this, config );\n\n\t// Events\n\tthis.connect( this, {\n\t\tchange: 'onChange'\n\t} );\n\n\t// Initialization\n\tthis.updateSearchIndicator();\n\tthis.connect( this, {\n\t\tdisable: 'onDisable'\n\t} );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.SearchInputWidget, OO.ui.TextInputWidget );\n\n/* Methods */\n\n/**\n * @inheritdoc\n * @protected\n */\nOO.ui.SearchInputWidget.prototype.getSaneType = function () {\n\treturn 'search';\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.SearchInputWidget.prototype.onIndicatorMouseDown = function ( e ) {\n\tif ( e.which === OO.ui.MouseButtons.LEFT ) {\n\t\t// Clear the text field\n\t\tthis.setValue( '' );\n\t\tthis.focus();\n\t\treturn false;\n\t}\n};\n\n/**\n * Update the 'clear' indicator displayed on type: 'search' text\n * fields, hiding it when the field is already empty or when it's not\n * editable.\n */\nOO.ui.SearchInputWidget.prototype.updateSearchIndicator = function () {\n\tif ( this.getValue() === '' || this.isDisabled() || this.isReadOnly() ) {\n\t\tthis.setIndicator( null );\n\t} else {\n\t\tthis.setIndicator( 'clear' );\n\t}\n};\n\n/**\n * Handle change events.\n *\n * @private\n */\nOO.ui.SearchInputWidget.prototype.onChange = function () {\n\tthis.updateSearchIndicator();\n};\n\n/**\n * Handle disable events.\n *\n * @param {boolean} disabled Element is disabled\n * @private\n */\nOO.ui.SearchInputWidget.prototype.onDisable = function () {\n\tthis.updateSearchIndicator();\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.SearchInputWidget.prototype.setReadOnly = function ( state ) {\n\tOO.ui.SearchInputWidget.parent.prototype.setReadOnly.call( this, state );\n\tthis.updateSearchIndicator();\n\treturn this;\n};\n","/**\n * MultilineTextInputWidgets, like HTML textareas, are featuring customization options to\n * configure number of rows visible. In addition, these widgets can be autosized to fit user\n * inputs and can show {@link OO.ui.mixin.IconElement icons} and\n * {@link OO.ui.mixin.IndicatorElement indicators}.\n * Please see the [OOUI documentation on MediaWiki] [1] for more information and examples.\n *\n * This widget can be used inside an HTML form, such as a OO.ui.FormLayout.\n *\n *     @example\n *     // A MultilineTextInputWidget.\n *     var multilineTextInput = new OO.ui.MultilineTextInputWidget( {\n *         value: 'Text input on multiple lines'\n *     } )\n *     $( 'body' ).append( multilineTextInput.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs#MultilineTextInputWidget\n *\n * @class\n * @extends OO.ui.TextInputWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {number} [rows] Number of visible lines in textarea. If used with `autosize`,\n *  specifies minimum number of rows to display.\n * @cfg {boolean} [autosize=false] Automatically resize the text input to fit its content.\n *  Use the #maxRows config to specify a maximum number of displayed rows.\n * @cfg {number} [maxRows] Maximum number of rows to display when #autosize is set to true.\n *  Defaults to the maximum of `10` and `2 * rows`, or `10` if `rows` isn't provided.\n */\nOO.ui.MultilineTextInputWidget = function OoUiMultilineTextInputWidget( config ) {\n\tconfig = $.extend( {\n\t\ttype: 'text'\n\t}, config );\n\t// Parent constructor\n\tOO.ui.MultilineTextInputWidget.parent.call( this, config );\n\n\t// Properties\n\tthis.autosize = !!config.autosize;\n\tthis.styleHeight = null;\n\tthis.minRows = config.rows !== undefined ? config.rows : '';\n\tthis.maxRows = config.maxRows || Math.max( 2 * ( this.minRows || 0 ), 10 );\n\n\t// Clone for resizing\n\tif ( this.autosize ) {\n\t\tthis.$clone = this.$input\n\t\t\t.clone()\n\t\t\t.removeAttr( 'id' )\n\t\t\t.removeAttr( 'name' )\n\t\t\t.insertAfter( this.$input )\n\t\t\t.attr( 'aria-hidden', 'true' )\n\t\t\t.addClass( 'oo-ui-element-hidden' );\n\t}\n\n\t// Events\n\tthis.connect( this, {\n\t\tchange: 'onChange'\n\t} );\n\n\t// Initialization\n\tif ( config.rows ) {\n\t\tthis.$input.attr( 'rows', config.rows );\n\t}\n\tif ( this.autosize ) {\n\t\tthis.$input.addClass( 'oo-ui-textInputWidget-autosized' );\n\t\tthis.isWaitingToBeAttached = true;\n\t\tthis.installParentChangeDetector();\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.MultilineTextInputWidget, OO.ui.TextInputWidget );\n\n/* Static Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.MultilineTextInputWidget.static.gatherPreInfuseState = function ( node, config ) {\n\tvar state = OO.ui.MultilineTextInputWidget.parent.static.gatherPreInfuseState( node, config );\n\tstate.scrollTop = config.$input.scrollTop();\n\treturn state;\n};\n\n/* Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.MultilineTextInputWidget.prototype.onElementAttach = function () {\n\tOO.ui.MultilineTextInputWidget.parent.prototype.onElementAttach.call( this );\n\tthis.adjustSize();\n};\n\n/**\n * Handle change events.\n *\n * @private\n */\nOO.ui.MultilineTextInputWidget.prototype.onChange = function () {\n\tthis.adjustSize();\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MultilineTextInputWidget.prototype.updatePosition = function () {\n\tOO.ui.MultilineTextInputWidget.parent.prototype.updatePosition.call( this );\n\tthis.adjustSize();\n};\n\n/**\n * @inheritdoc\n *\n * Modify to emit 'enter' on Ctrl/Meta+Enter, instead of plain Enter\n */\nOO.ui.MultilineTextInputWidget.prototype.onKeyPress = function ( e ) {\n\tif (\n\t\t( e.which === OO.ui.Keys.ENTER && ( e.ctrlKey || e.metaKey ) ) ||\n\t\t// Some platforms emit keycode 10 for Control+Enter keypress in a textarea\n\t\te.which === 10\n\t) {\n\t\tthis.emit( 'enter', e );\n\t}\n};\n\n/**\n * Automatically adjust the size of the text input.\n *\n * This only affects multiline inputs that are {@link #autosize autosized}.\n *\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n * @fires resize\n */\nOO.ui.MultilineTextInputWidget.prototype.adjustSize = function () {\n\tvar scrollHeight, innerHeight, outerHeight, maxInnerHeight, measurementError,\n\t\tidealHeight, newHeight, scrollWidth, property;\n\n\tif ( this.$input.val() !== this.valCache ) {\n\t\tif ( this.autosize ) {\n\t\t\tthis.$clone\n\t\t\t\t.val( this.$input.val() )\n\t\t\t\t.attr( 'rows', this.minRows )\n\t\t\t\t// Set inline height property to 0 to measure scroll height\n\t\t\t\t.css( 'height', 0 );\n\n\t\t\tthis.$clone.removeClass( 'oo-ui-element-hidden' );\n\n\t\t\tthis.valCache = this.$input.val();\n\n\t\t\tscrollHeight = this.$clone[ 0 ].scrollHeight;\n\n\t\t\t// Remove inline height property to measure natural heights\n\t\t\tthis.$clone.css( 'height', '' );\n\t\t\tinnerHeight = this.$clone.innerHeight();\n\t\t\touterHeight = this.$clone.outerHeight();\n\n\t\t\t// Measure max rows height\n\t\t\tthis.$clone\n\t\t\t\t.attr( 'rows', this.maxRows )\n\t\t\t\t.css( 'height', 'auto' )\n\t\t\t\t.val( '' );\n\t\t\tmaxInnerHeight = this.$clone.innerHeight();\n\n\t\t\t// Difference between reported innerHeight and scrollHeight with no scrollbars present.\n\t\t\t// This is sometimes non-zero on Blink-based browsers, depending on zoom level.\n\t\t\tmeasurementError = maxInnerHeight - this.$clone[ 0 ].scrollHeight;\n\t\t\tidealHeight = Math.min( maxInnerHeight, scrollHeight + measurementError );\n\n\t\t\tthis.$clone.addClass( 'oo-ui-element-hidden' );\n\n\t\t\t// Only apply inline height when expansion beyond natural height is needed\n\t\t\t// Use the difference between the inner and outer height as a buffer\n\t\t\tnewHeight = idealHeight > innerHeight ? idealHeight + ( outerHeight - innerHeight ) : '';\n\t\t\tif ( newHeight !== this.styleHeight ) {\n\t\t\t\tthis.$input.css( 'height', newHeight );\n\t\t\t\tthis.styleHeight = newHeight;\n\t\t\t\tthis.emit( 'resize' );\n\t\t\t}\n\t\t}\n\t\tscrollWidth = this.$input[ 0 ].offsetWidth - this.$input[ 0 ].clientWidth;\n\t\tif ( scrollWidth !== this.scrollWidth ) {\n\t\t\tproperty = this.$element.css( 'direction' ) === 'rtl' ? 'left' : 'right';\n\t\t\t// Reset\n\t\t\tthis.$label.css( { right: '', left: '' } );\n\t\t\tthis.$indicator.css( { right: '', left: '' } );\n\n\t\t\tif ( scrollWidth ) {\n\t\t\t\tthis.$indicator.css( property, scrollWidth );\n\t\t\t\tif ( this.labelPosition === 'after' ) {\n\t\t\t\t\tthis.$label.css( property, scrollWidth );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.scrollWidth = scrollWidth;\n\t\t\tthis.positionLabel();\n\t\t}\n\t}\n\treturn this;\n};\n\n/**\n * @inheritdoc\n * @protected\n */\nOO.ui.MultilineTextInputWidget.prototype.getInputElement = function () {\n\treturn $( '<textarea>' );\n};\n\n/**\n * Check if the input automatically adjusts its size.\n *\n * @return {boolean}\n */\nOO.ui.MultilineTextInputWidget.prototype.isAutosizing = function () {\n\treturn !!this.autosize;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MultilineTextInputWidget.prototype.restorePreInfuseState = function ( state ) {\n\tOO.ui.MultilineTextInputWidget.parent.prototype.restorePreInfuseState.call( this, state );\n\tif ( state.scrollTop !== undefined ) {\n\t\tthis.$input.scrollTop( state.scrollTop );\n\t}\n};\n","/**\n * ComboBoxInputWidgets combine a {@link OO.ui.TextInputWidget text input} (where a value\n * can be entered manually) and a {@link OO.ui.MenuSelectWidget menu of options} (from which\n * a value can be chosen instead). Users can choose options from the combo box in one of two ways:\n *\n * - by typing a value in the text input field. If the value exactly matches the value of a menu\n *   option, that option will appear to be selected.\n * - by choosing a value from the menu. The value of the chosen option will then appear in the text\n *   input field.\n *\n * After the user chooses an option, its `data` will be used as a new value for the widget.\n * A `label` also can be specified for each option: if given, it will be shown instead of the\n * `data` in the dropdown menu.\n *\n * This widget can be used inside an HTML form, such as a OO.ui.FormLayout.\n *\n * For more information about menus and options, please see the\n * [OOUI documentation on MediaWiki][1].\n *\n *     @example\n *     // A ComboBoxInputWidget.\n *     var comboBox = new OO.ui.ComboBoxInputWidget( {\n *         value: 'Option 1',\n *         options: [\n *             { data: 'Option 1' },\n *             { data: 'Option 2' },\n *             { data: 'Option 3' }\n *         ]\n *     } );\n *     $( document.body ).append( comboBox.$element );\n *\n *     @example\n *     // Example: A ComboBoxInputWidget with additional option labels.\n *     var comboBox = new OO.ui.ComboBoxInputWidget( {\n *         value: 'Option 1',\n *         options: [\n *             {\n *                 data: 'Option 1',\n *                 label: 'Option One'\n *             },\n *             {\n *                 data: 'Option 2',\n *                 label: 'Option Two'\n *             },\n *             {\n *                 data: 'Option 3',\n *                 label: 'Option Three'\n *             }\n *         ]\n *     } );\n *     $( document.body ).append( comboBox.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options#Menu_selects_and_options\n *\n * @class\n * @extends OO.ui.TextInputWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {Object[]} [options=[]] Array of menu options in the format `{ data: …, label: … }`\n * @cfg {Object} [menu] Configuration options to pass to the {@link OO.ui.MenuSelectWidget menu\n *  select widget}.\n * @cfg {jQuery} [$overlay] Render the menu into a separate layer. This configuration is useful\n *  in cases where the expanded menu is larger than its containing `<div>`. The specified overlay\n *  layer is usually on top of the containing `<div>` and has a larger area. By default, the menu\n *  uses relative positioning.\n *  See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.\n */\nOO.ui.ComboBoxInputWidget = function OoUiComboBoxInputWidget( config ) {\n\t// Configuration initialization\n\tconfig = $.extend( {\n\t\tautocomplete: false\n\t}, config );\n\n\t// ComboBoxInputWidget shouldn't support `multiline`\n\tconfig.multiline = false;\n\n\t// See InputWidget#reusePreInfuseDOM about `config.$input`\n\tif ( config.$input ) {\n\t\tconfig.$input.removeAttr( 'list' );\n\t}\n\n\t// Parent constructor\n\tOO.ui.ComboBoxInputWidget.parent.call( this, config );\n\n\t// Properties\n\tthis.$overlay = ( config.$overlay === true ?\n\t\tOO.ui.getDefaultOverlay() : config.$overlay ) || this.$element;\n\tthis.dropdownButton = new OO.ui.ButtonWidget( {\n\t\tclasses: [ 'oo-ui-comboBoxInputWidget-dropdownButton' ],\n\t\tlabel: OO.ui.msg( 'ooui-combobox-button-label' ),\n\t\tindicator: 'down',\n\t\tinvisibleLabel: true,\n\t\tdisabled: this.disabled\n\t} );\n\tthis.menu = new OO.ui.MenuSelectWidget( $.extend(\n\t\t{\n\t\t\twidget: this,\n\t\t\tinput: this,\n\t\t\t$floatableContainer: this.$element,\n\t\t\tdisabled: this.isDisabled()\n\t\t},\n\t\tconfig.menu\n\t) );\n\n\t// Events\n\tthis.connect( this, {\n\t\tchange: 'onInputChange',\n\t\tenter: 'onInputEnter'\n\t} );\n\tthis.dropdownButton.connect( this, {\n\t\tclick: 'onDropdownButtonClick'\n\t} );\n\tthis.menu.connect( this, {\n\t\tchoose: 'onMenuChoose',\n\t\tadd: 'onMenuItemsChange',\n\t\tremove: 'onMenuItemsChange',\n\t\ttoggle: 'onMenuToggle'\n\t} );\n\n\t// Initialization\n\tthis.$input.attr( {\n\t\trole: 'combobox',\n\t\t'aria-owns': this.menu.getElementId(),\n\t\t'aria-autocomplete': 'list'\n\t} );\n\tthis.dropdownButton.$button.attr( {\n\t\t'aria-controls': this.menu.getElementId()\n\t} );\n\t// Do not override options set via config.menu.items\n\tif ( config.options !== undefined ) {\n\t\tthis.setOptions( config.options );\n\t}\n\tthis.$field = $( '<div>' )\n\t\t.addClass( 'oo-ui-comboBoxInputWidget-field' )\n\t\t.append( this.$input, this.dropdownButton.$element );\n\tthis.$element\n\t\t.addClass( 'oo-ui-comboBoxInputWidget' )\n\t\t.append( this.$field );\n\tthis.$overlay.append( this.menu.$element );\n\tthis.onMenuItemsChange();\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ComboBoxInputWidget, OO.ui.TextInputWidget );\n\n/* Methods */\n\n/**\n * Get the combobox's menu.\n *\n * @return {OO.ui.MenuSelectWidget} Menu widget\n */\nOO.ui.ComboBoxInputWidget.prototype.getMenu = function () {\n\treturn this.menu;\n};\n\n/**\n * Get the combobox's text input widget.\n *\n * @return {OO.ui.TextInputWidget} Text input widget\n */\nOO.ui.ComboBoxInputWidget.prototype.getInput = function () {\n\treturn this;\n};\n\n/**\n * Handle input change events.\n *\n * @private\n * @param {string} value New value\n */\nOO.ui.ComboBoxInputWidget.prototype.onInputChange = function ( value ) {\n\tvar match = this.menu.findItemFromData( value );\n\n\tthis.menu.selectItem( match );\n\tif ( this.menu.findHighlightedItem() ) {\n\t\tthis.menu.highlightItem( match );\n\t}\n\n\tif ( !this.isDisabled() ) {\n\t\tthis.menu.toggle( true );\n\t}\n};\n\n/**\n * Handle input enter events.\n *\n * @private\n */\nOO.ui.ComboBoxInputWidget.prototype.onInputEnter = function () {\n\tif ( !this.isDisabled() ) {\n\t\tthis.menu.toggle( false );\n\t}\n};\n\n/**\n * Handle button click events.\n *\n * @private\n */\nOO.ui.ComboBoxInputWidget.prototype.onDropdownButtonClick = function () {\n\tthis.menu.toggle();\n\tthis.focus();\n};\n\n/**\n * Handle menu choose events.\n *\n * @private\n * @param {OO.ui.OptionWidget} item Chosen item\n */\nOO.ui.ComboBoxInputWidget.prototype.onMenuChoose = function ( item ) {\n\tthis.setValue( item.getData() );\n};\n\n/**\n * Handle menu item change events.\n *\n * @private\n */\nOO.ui.ComboBoxInputWidget.prototype.onMenuItemsChange = function () {\n\tvar match = this.menu.findItemFromData( this.getValue() );\n\tthis.menu.selectItem( match );\n\tif ( this.menu.findHighlightedItem() ) {\n\t\tthis.menu.highlightItem( match );\n\t}\n\tthis.$element.toggleClass( 'oo-ui-comboBoxInputWidget-empty', this.menu.isEmpty() );\n};\n\n/**\n * Handle menu toggle events.\n *\n * @private\n * @param {boolean} isVisible Open state of the menu\n */\nOO.ui.ComboBoxInputWidget.prototype.onMenuToggle = function ( isVisible ) {\n\tthis.$element.toggleClass( 'oo-ui-comboBoxInputWidget-open', isVisible );\n};\n\n/**\n * Update the disabled state of the controls\n *\n * @chainable\n * @protected\n * @return {OO.ui.ComboBoxInputWidget} The widget, for chaining\n */\nOO.ui.ComboBoxInputWidget.prototype.updateControlsDisabled = function () {\n\tvar disabled = this.isDisabled() || this.isReadOnly();\n\tif ( this.dropdownButton ) {\n\t\tthis.dropdownButton.setDisabled( disabled );\n\t}\n\tif ( this.menu ) {\n\t\tthis.menu.setDisabled( disabled );\n\t}\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.ComboBoxInputWidget.prototype.setDisabled = function () {\n\t// Parent method\n\tOO.ui.ComboBoxInputWidget.parent.prototype.setDisabled.apply( this, arguments );\n\tthis.updateControlsDisabled();\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.ComboBoxInputWidget.prototype.setReadOnly = function () {\n\t// Parent method\n\tOO.ui.ComboBoxInputWidget.parent.prototype.setReadOnly.apply( this, arguments );\n\tthis.updateControlsDisabled();\n\treturn this;\n};\n\n/**\n * Set the options available for this input.\n *\n * @param {Object[]} options Array of menu options in the format `{ data: …, label: … }`\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.ComboBoxInputWidget.prototype.setOptions = function ( options ) {\n\tthis.getMenu()\n\t\t.clearItems()\n\t\t.addItems( options.map( function ( opt ) {\n\t\t\treturn new OO.ui.MenuOptionWidget( {\n\t\t\t\tdata: opt.data,\n\t\t\t\tlabel: opt.label !== undefined ? opt.label : opt.data\n\t\t\t} );\n\t\t} ) );\n\n\treturn this;\n};\n","/**\n * FieldLayouts are used with OO.ui.FieldsetLayout. Each FieldLayout requires a field-widget,\n * which is a widget that is specified by reference before any optional configuration settings.\n *\n * Field layouts can be configured with help text and/or labels. Labels are aligned in one of\n * four ways:\n *\n * - **left**: The label is placed before the field-widget and aligned with the left margin.\n *   A left-alignment is used for forms with many fields.\n * - **right**: The label is placed before the field-widget and aligned to the right margin.\n *   A right-alignment is used for long but familiar forms which users tab through,\n *   verifying the current field with a quick glance at the label.\n * - **top**: The label is placed above the field-widget. A top-alignment is used for brief forms\n *   that users fill out from top to bottom.\n * - **inline**: The label is placed after the field-widget and aligned to the left.\n *   An inline-alignment is best used with checkboxes or radio buttons.\n *\n * Help text can either be:\n *\n * - accessed via a help icon that appears in the upper right corner of the rendered field layout,\n *   or\n * - shown as a subtle explanation below the label.\n *\n * If the help text is brief, or is essential to always expose it, set `helpInline` to `true`.\n * If it is long or not essential, leave `helpInline` to its default, `false`.\n *\n * Please see the [OOUI documentation on MediaWiki] [1] for examples and more information.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Layouts/Fields_and_Fieldsets\n *\n * @class\n * @extends OO.ui.Layout\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.TitledElement\n *\n * @constructor\n * @param {OO.ui.Widget} fieldWidget Field widget\n * @param {Object} [config] Configuration options\n * @cfg {string} [align='left'] Alignment of the label: 'left', 'right', 'top'\n *  or 'inline'\n * @cfg {Array} [errors] Error messages about the widget, which will be\n *  displayed below the widget.\n * @cfg {Array} [warnings] Warning messages about the widget, which will be\n *  displayed below the widget.\n * @cfg {Array} [successMessages] Success messages on user interactions with the widget,\n *  which will be displayed below the widget.\n *  The array may contain strings or OO.ui.HtmlSnippet instances.\n * @cfg {Array} [notices] Notices about the widget, which will be displayed\n *  below the widget.\n *  The array may contain strings or OO.ui.HtmlSnippet instances.\n *  These are more visible than `help` messages when `helpInline` is set, and so\n *  might be good for transient messages.\n * @cfg {string|OO.ui.HtmlSnippet} [help] Help text. When help text is specified\n *  and `helpInline` is `false`, a \"help\" icon will appear in the upper-right\n *  corner of the rendered field; clicking it will display the text in a popup.\n *  If `helpInline` is `true`, then a subtle description will be shown after the\n *  label.\n * @cfg {boolean} [helpInline=false] Whether or not the help should be inline,\n *  or shown when the \"help\" icon is clicked.\n * @cfg {jQuery} [$overlay] Passed to OO.ui.PopupButtonWidget for help popup, if\n * `help` is given.\n *  See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.\n *\n * @throws {Error} An error is thrown if no widget is specified\n */\nOO.ui.FieldLayout = function OoUiFieldLayout( fieldWidget, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( fieldWidget ) && config === undefined ) {\n\t\tconfig = fieldWidget;\n\t\tfieldWidget = config.fieldWidget;\n\t}\n\n\t// Make sure we have required constructor arguments\n\tif ( fieldWidget === undefined ) {\n\t\tthrow new Error( 'Widget not found' );\n\t}\n\n\t// Configuration initialization\n\tconfig = $.extend( { align: 'left', helpInline: false }, config );\n\n\t// Parent constructor\n\tOO.ui.FieldLayout.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.LabelElement.call( this, $.extend( {\n\t\t$label: $( '<label>' )\n\t}, config ) );\n\tOO.ui.mixin.TitledElement.call( this, $.extend( { $titled: this.$label }, config ) );\n\n\t// Properties\n\tthis.fieldWidget = fieldWidget;\n\tthis.errors = [];\n\tthis.warnings = [];\n\tthis.successMessages = [];\n\tthis.notices = [];\n\tthis.$field = this.isFieldInline() ? $( '<span>' ) : $( '<div>' );\n\tthis.$messages = $( '<ul>' );\n\tthis.$header = $( '<span>' );\n\tthis.$body = $( '<div>' );\n\tthis.align = null;\n\tthis.helpInline = config.helpInline;\n\n\t// Events\n\tthis.fieldWidget.connect( this, {\n\t\tdisable: 'onFieldDisable'\n\t} );\n\n\t// Initialization\n\tthis.$help = config.help ?\n\t\tthis.createHelpElement( config.help, config.$overlay ) :\n\t\t$( [] );\n\tif ( this.fieldWidget.getInputId() ) {\n\t\tthis.$label.attr( 'for', this.fieldWidget.getInputId() );\n\t\tif ( this.helpInline ) {\n\t\t\tthis.$help.attr( 'for', this.fieldWidget.getInputId() );\n\t\t}\n\t} else {\n\t\tthis.$label.on( 'click', function () {\n\t\t\tthis.fieldWidget.simulateLabelClick();\n\t\t}.bind( this ) );\n\t\tif ( this.helpInline ) {\n\t\t\tthis.$help.on( 'click', function () {\n\t\t\t\tthis.fieldWidget.simulateLabelClick();\n\t\t\t}.bind( this ) );\n\t\t}\n\t}\n\tthis.$element\n\t\t.addClass( 'oo-ui-fieldLayout' )\n\t\t.toggleClass( 'oo-ui-fieldLayout-disabled', this.fieldWidget.isDisabled() )\n\t\t.append( this.$body );\n\tthis.$body.addClass( 'oo-ui-fieldLayout-body' );\n\tthis.$header.addClass( 'oo-ui-fieldLayout-header' );\n\tthis.$messages.addClass( 'oo-ui-fieldLayout-messages' );\n\tthis.$field\n\t\t.addClass( 'oo-ui-fieldLayout-field' )\n\t\t.append( this.fieldWidget.$element );\n\n\tthis.setErrors( config.errors || [] );\n\tthis.setWarnings( config.warnings || [] );\n\tthis.setSuccess( config.successMessages || [] );\n\tthis.setNotices( config.notices || [] );\n\tthis.setAlignment( config.align );\n\t// Call this again to take into account the widget's accessKey\n\tthis.updateTitle();\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.FieldLayout, OO.ui.Layout );\nOO.mixinClass( OO.ui.FieldLayout, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.FieldLayout, OO.ui.mixin.TitledElement );\n\n/* Methods */\n\n/**\n * Handle field disable events.\n *\n * @private\n * @param {boolean} value Field is disabled\n */\nOO.ui.FieldLayout.prototype.onFieldDisable = function ( value ) {\n\tthis.$element.toggleClass( 'oo-ui-fieldLayout-disabled', value );\n};\n\n/**\n * Get the widget contained by the field.\n *\n * @return {OO.ui.Widget} Field widget\n */\nOO.ui.FieldLayout.prototype.getField = function () {\n\treturn this.fieldWidget;\n};\n\n/**\n * Return `true` if the given field widget can be used with `'inline'` alignment (see\n * #setAlignment). Return `false` if it can't or if this can't be determined.\n *\n * @return {boolean}\n */\nOO.ui.FieldLayout.prototype.isFieldInline = function () {\n\t// This is very simplistic, but should be good enough.\n\treturn this.getField().$element.prop( 'tagName' ).toLowerCase() === 'span';\n};\n\n/**\n * @protected\n * @param {string} kind 'error' or 'notice'\n * @param {string|OO.ui.HtmlSnippet} text\n * @return {jQuery}\n */\nOO.ui.FieldLayout.prototype.makeMessage = function ( kind, text ) {\n\tvar $listItem, $icon, message;\n\t$listItem = $( '<li>' );\n\tif ( kind === 'error' ) {\n\t\t$icon = new OO.ui.IconWidget( { icon: 'alert', flags: [ 'error' ] } ).$element;\n\t\t$listItem.attr( 'role', 'alert' );\n\t} else if ( kind === 'warning' ) {\n\t\t$icon = new OO.ui.IconWidget( { icon: 'alert', flags: [ 'warning' ] } ).$element;\n\t\t$listItem.attr( 'role', 'alert' );\n\t} else if ( kind === 'success' ) {\n\t\t$icon = new OO.ui.IconWidget( { icon: 'check', flags: [ 'success' ] } ).$element;\n\t} else if ( kind === 'notice' ) {\n\t\t$icon = new OO.ui.IconWidget( { icon: 'notice' } ).$element;\n\t} else {\n\t\t$icon = '';\n\t}\n\tmessage = new OO.ui.LabelWidget( { label: text } );\n\t$listItem\n\t\t.append( $icon, message.$element )\n\t\t.addClass( 'oo-ui-fieldLayout-messages-' + kind );\n\treturn $listItem;\n};\n\n/**\n * Set the field alignment mode.\n *\n * @private\n * @param {string} value Alignment mode, either 'left', 'right', 'top' or 'inline'\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.FieldLayout.prototype.setAlignment = function ( value ) {\n\tif ( value !== this.align ) {\n\t\t// Default to 'left'\n\t\tif ( [ 'left', 'right', 'top', 'inline' ].indexOf( value ) === -1 ) {\n\t\t\tvalue = 'left';\n\t\t}\n\t\t// Validate\n\t\tif ( value === 'inline' && !this.isFieldInline() ) {\n\t\t\tvalue = 'top';\n\t\t}\n\t\t// Reorder elements\n\n\t\tif ( this.helpInline ) {\n\t\t\tif ( value === 'top' ) {\n\t\t\t\tthis.$header.append( this.$label );\n\t\t\t\tthis.$body.append( this.$header, this.$field, this.$help );\n\t\t\t} else if ( value === 'inline' ) {\n\t\t\t\tthis.$header.append( this.$label, this.$help );\n\t\t\t\tthis.$body.append( this.$field, this.$header );\n\t\t\t} else {\n\t\t\t\tthis.$header.append( this.$label, this.$help );\n\t\t\t\tthis.$body.append( this.$header, this.$field );\n\t\t\t}\n\t\t} else {\n\t\t\tif ( value === 'top' ) {\n\t\t\t\tthis.$header.append( this.$help, this.$label );\n\t\t\t\tthis.$body.append( this.$header, this.$field );\n\t\t\t} else if ( value === 'inline' ) {\n\t\t\t\tthis.$header.append( this.$help, this.$label );\n\t\t\t\tthis.$body.append( this.$field, this.$header );\n\t\t\t} else {\n\t\t\t\tthis.$header.append( this.$label );\n\t\t\t\tthis.$body.append( this.$header, this.$help, this.$field );\n\t\t\t}\n\t\t}\n\t\t// Set classes. The following classes can be used here:\n\t\t// * oo-ui-fieldLayout-align-left\n\t\t// * oo-ui-fieldLayout-align-right\n\t\t// * oo-ui-fieldLayout-align-top\n\t\t// * oo-ui-fieldLayout-align-inline\n\t\tif ( this.align ) {\n\t\t\tthis.$element.removeClass( 'oo-ui-fieldLayout-align-' + this.align );\n\t\t}\n\t\tthis.$element.addClass( 'oo-ui-fieldLayout-align-' + value );\n\t\tthis.align = value;\n\t}\n\n\treturn this;\n};\n\n/**\n * Set the list of error messages.\n *\n * @param {Array} errors Error messages about the widget, which will be displayed below the widget.\n *  The array may contain strings or OO.ui.HtmlSnippet instances.\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.FieldLayout.prototype.setErrors = function ( errors ) {\n\tthis.errors = errors.slice();\n\tthis.updateMessages();\n\treturn this;\n};\n\n/**\n * Set the list of warning messages.\n *\n * @param {Array} warnings Warning messages about the widget, which will be displayed below\n *  the widget.\n *  The array may contain strings or OO.ui.HtmlSnippet instances.\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.FieldLayout.prototype.setWarnings = function ( warnings ) {\n\tthis.warnings = warnings.slice();\n\tthis.updateMessages();\n\treturn this;\n};\n\n/**\n * Set the list of success messages.\n *\n * @param {Array} successMessages Success messages about the widget, which will be displayed below\n *  the widget.\n *  The array may contain strings or OO.ui.HtmlSnippet instances.\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.FieldLayout.prototype.setSuccess = function ( successMessages ) {\n\tthis.successMessages = successMessages.slice();\n\tthis.updateMessages();\n\treturn this;\n};\n\n/**\n * Set the list of notice messages.\n *\n * @param {Array} notices Notices about the widget, which will be displayed below the widget.\n *  The array may contain strings or OO.ui.HtmlSnippet instances.\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.FieldLayout.prototype.setNotices = function ( notices ) {\n\tthis.notices = notices.slice();\n\tthis.updateMessages();\n\treturn this;\n};\n\n/**\n * Update the rendering of error, warning, success and notice messages.\n *\n * @private\n */\nOO.ui.FieldLayout.prototype.updateMessages = function () {\n\tvar i;\n\tthis.$messages.empty();\n\n\tif (\n\t\tthis.errors.length ||\n\t\tthis.warnings.length ||\n\t\tthis.successMessages.length ||\n\t\tthis.notices.length\n\t) {\n\t\tthis.$body.after( this.$messages );\n\t} else {\n\t\tthis.$messages.remove();\n\t\treturn;\n\t}\n\n\tfor ( i = 0; i < this.errors.length; i++ ) {\n\t\tthis.$messages.append( this.makeMessage( 'error', this.errors[ i ] ) );\n\t}\n\tfor ( i = 0; i < this.warnings.length; i++ ) {\n\t\tthis.$messages.append( this.makeMessage( 'warning', this.warnings[ i ] ) );\n\t}\n\tfor ( i = 0; i < this.successMessages.length; i++ ) {\n\t\tthis.$messages.append( this.makeMessage( 'success', this.successMessages[ i ] ) );\n\t}\n\tfor ( i = 0; i < this.notices.length; i++ ) {\n\t\tthis.$messages.append( this.makeMessage( 'notice', this.notices[ i ] ) );\n\t}\n};\n\n/**\n * Include information about the widget's accessKey in our title. TitledElement calls this method.\n * (This is a bit of a hack.)\n *\n * @protected\n * @param {string} title Tooltip label for 'title' attribute\n * @return {string}\n */\nOO.ui.FieldLayout.prototype.formatTitleWithAccessKey = function ( title ) {\n\tif ( this.fieldWidget && this.fieldWidget.formatTitleWithAccessKey ) {\n\t\treturn this.fieldWidget.formatTitleWithAccessKey( title );\n\t}\n\treturn title;\n};\n\n/**\n * Creates and returns the help element. Also sets the `aria-describedby`\n * attribute on the main element of the `fieldWidget`.\n *\n * @private\n * @param {string|OO.ui.HtmlSnippet} [help] Help text.\n * @param {jQuery} [$overlay] Passed to OO.ui.PopupButtonWidget for help popup.\n * @return {jQuery} The element that should become `this.$help`.\n */\nOO.ui.FieldLayout.prototype.createHelpElement = function ( help, $overlay ) {\n\tvar helpId, helpWidget;\n\n\tif ( this.helpInline ) {\n\t\thelpWidget = new OO.ui.LabelWidget( {\n\t\t\tlabel: help,\n\t\t\tclasses: [ 'oo-ui-inline-help' ]\n\t\t} );\n\n\t\thelpId = helpWidget.getElementId();\n\t} else {\n\t\thelpWidget = new OO.ui.PopupButtonWidget( {\n\t\t\t$overlay: $overlay,\n\t\t\tpopup: {\n\t\t\t\tpadded: true\n\t\t\t},\n\t\t\tclasses: [ 'oo-ui-fieldLayout-help' ],\n\t\t\tframed: false,\n\t\t\ticon: 'info',\n\t\t\tlabel: OO.ui.msg( 'ooui-field-help' ),\n\t\t\tinvisibleLabel: true\n\t\t} );\n\t\tif ( help instanceof OO.ui.HtmlSnippet ) {\n\t\t\thelpWidget.getPopup().$body.html( help.toString() );\n\t\t} else {\n\t\t\thelpWidget.getPopup().$body.text( help );\n\t\t}\n\n\t\thelpId = helpWidget.getPopup().getBodyId();\n\t}\n\n\t// Set the 'aria-describedby' attribute on the fieldWidget\n\t// Preference given to an input or a button\n\t(\n\t\tthis.fieldWidget.$input ||\n\t\tthis.fieldWidget.$button ||\n\t\tthis.fieldWidget.$element\n\t).attr( 'aria-describedby', helpId );\n\n\treturn helpWidget.$element;\n};\n","/**\n * ActionFieldLayouts are used with OO.ui.FieldsetLayout. The layout consists of a field-widget,\n * a button, and an optional label and/or help text. The field-widget (e.g., a\n * {@link OO.ui.TextInputWidget TextInputWidget}), is required and is specified before any optional\n * configuration settings.\n *\n * Labels can be aligned in one of four ways:\n *\n * - **left**: The label is placed before the field-widget and aligned with the left margin.\n *   A left-alignment is used for forms with many fields.\n * - **right**: The label is placed before the field-widget and aligned to the right margin.\n *   A right-alignment is used for long but familiar forms which users tab through,\n *   verifying the current field with a quick glance at the label.\n * - **top**: The label is placed above the field-widget. A top-alignment is used for brief forms\n *   that users fill out from top to bottom.\n * - **inline**: The label is placed after the field-widget and aligned to the left.\n *   An inline-alignment is best used with checkboxes or radio buttons.\n *\n * Help text is accessed via a help icon that appears in the upper right corner of the rendered\n * field layout when help text is specified.\n *\n *     @example\n *     // Example of an ActionFieldLayout\n *     var actionFieldLayout = new OO.ui.ActionFieldLayout(\n *         new OO.ui.TextInputWidget( {\n *             placeholder: 'Field widget'\n *         } ),\n *         new OO.ui.ButtonWidget( {\n *             label: 'Button'\n *         } ),\n *         {\n *             label: 'An ActionFieldLayout. This label is aligned top',\n *             align: 'top',\n *             help: 'This is help text'\n *         }\n *     );\n *\n *     $( document.body ).append( actionFieldLayout.$element );\n *\n * @class\n * @extends OO.ui.FieldLayout\n *\n * @constructor\n * @param {OO.ui.Widget} fieldWidget Field widget\n * @param {OO.ui.ButtonWidget} buttonWidget Button widget\n * @param {Object} config\n */\nOO.ui.ActionFieldLayout = function OoUiActionFieldLayout( fieldWidget, buttonWidget, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( fieldWidget ) && config === undefined ) {\n\t\tconfig = fieldWidget;\n\t\tfieldWidget = config.fieldWidget;\n\t\tbuttonWidget = config.buttonWidget;\n\t}\n\n\t// Parent constructor\n\tOO.ui.ActionFieldLayout.parent.call( this, fieldWidget, config );\n\n\t// Properties\n\tthis.buttonWidget = buttonWidget;\n\tthis.$button = $( '<span>' );\n\tthis.$input = this.isFieldInline() ? $( '<span>' ) : $( '<div>' );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-actionFieldLayout' );\n\tthis.$button\n\t\t.addClass( 'oo-ui-actionFieldLayout-button' )\n\t\t.append( this.buttonWidget.$element );\n\tthis.$input\n\t\t.addClass( 'oo-ui-actionFieldLayout-input' )\n\t\t.append( this.fieldWidget.$element );\n\tthis.$field.append( this.$input, this.$button );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ActionFieldLayout, OO.ui.FieldLayout );\n","/**\n * FieldsetLayouts are composed of one or more {@link OO.ui.FieldLayout FieldLayouts},\n * which each contain an individual widget and, optionally, a label. Each Fieldset can be\n * configured with a label as well. For more information and examples,\n * please see the [OOUI documentation on MediaWiki][1].\n *\n *     @example\n *     // Example of a fieldset layout\n *     var input1 = new OO.ui.TextInputWidget( {\n *         placeholder: 'A text input field'\n *     } );\n *\n *     var input2 = new OO.ui.TextInputWidget( {\n *         placeholder: 'A text input field'\n *     } );\n *\n *     var fieldset = new OO.ui.FieldsetLayout( {\n *         label: 'Example of a fieldset layout'\n *     } );\n *\n *     fieldset.addItems( [\n *         new OO.ui.FieldLayout( input1, {\n *             label: 'Field One'\n *         } ),\n *         new OO.ui.FieldLayout( input2, {\n *             label: 'Field Two'\n *         } )\n *     ] );\n *     $( document.body ).append( fieldset.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Layouts/Fields_and_Fieldsets\n *\n * @class\n * @extends OO.ui.Layout\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.GroupElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {OO.ui.FieldLayout[]} [items] An array of fields to add to the fieldset.\n *  See OO.ui.FieldLayout for more information about fields.\n * @cfg {string|OO.ui.HtmlSnippet} [help] Help text. When help text is specified, a \"help\" icon\n *  will appear in the upper-right corner of the rendered field; clicking it will display the text\n *  in a popup. For important messages, you are advised to use `notices`, as they are always shown.\n * @cfg {jQuery} [$overlay] Passed to OO.ui.PopupButtonWidget for help popup, if `help` is given.\n *  See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.\n */\nOO.ui.FieldsetLayout = function OoUiFieldsetLayout( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.FieldsetLayout.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.GroupElement.call( this, config );\n\n\t// Properties\n\tthis.$header = $( '<legend>' );\n\tif ( config.help ) {\n\t\tthis.popupButtonWidget = new OO.ui.PopupButtonWidget( {\n\t\t\t$overlay: config.$overlay,\n\t\t\tpopup: {\n\t\t\t\tpadded: true\n\t\t\t},\n\t\t\tclasses: [ 'oo-ui-fieldsetLayout-help' ],\n\t\t\tframed: false,\n\t\t\ticon: 'info',\n\t\t\tlabel: OO.ui.msg( 'ooui-field-help' ),\n\t\t\tinvisibleLabel: true\n\t\t} );\n\t\tif ( config.help instanceof OO.ui.HtmlSnippet ) {\n\t\t\tthis.popupButtonWidget.getPopup().$body.html( config.help.toString() );\n\t\t} else {\n\t\t\tthis.popupButtonWidget.getPopup().$body.text( config.help );\n\t\t}\n\t\tthis.$help = this.popupButtonWidget.$element;\n\t} else {\n\t\tthis.$help = $( [] );\n\t}\n\n\t// Initialization\n\tthis.$header\n\t\t.addClass( 'oo-ui-fieldsetLayout-header' )\n\t\t.append( this.$icon, this.$label, this.$help );\n\tthis.$group.addClass( 'oo-ui-fieldsetLayout-group' );\n\tthis.$element\n\t\t.addClass( 'oo-ui-fieldsetLayout' )\n\t\t.prepend( this.$header, this.$group );\n\tif ( Array.isArray( config.items ) ) {\n\t\tthis.addItems( config.items );\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.FieldsetLayout, OO.ui.Layout );\nOO.mixinClass( OO.ui.FieldsetLayout, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.FieldsetLayout, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.FieldsetLayout, OO.ui.mixin.GroupElement );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.FieldsetLayout.static.tagName = 'fieldset';\n","/**\n * FormLayouts are used to wrap {@link OO.ui.FieldsetLayout FieldsetLayouts} when you intend to use\n * browser-based form submission for the fields instead of handling them in JavaScript. Form layouts\n * can be configured with an HTML form action, an encoding type, and a method using the #action,\n * #enctype, and #method configs, respectively.\n * See the [OOUI documentation on MediaWiki] [1] for more information and examples.\n *\n * Only widgets from the {@link OO.ui.InputWidget InputWidget} family support form submission. It\n * includes standard form elements like {@link OO.ui.CheckboxInputWidget checkboxes}, {@link\n * OO.ui.RadioInputWidget radio buttons} and {@link OO.ui.TextInputWidget text fields}, as well as\n * some fancier controls. Some controls have both regular and InputWidget variants, for example\n * OO.ui.DropdownWidget and OO.ui.DropdownInputWidget – only the latter support form submission and\n * often have simplified APIs to match the capabilities of HTML forms.\n * See the [OOUI documentation on MediaWiki] [2] for more information about InputWidgets.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Layouts/Forms\n * [2]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs\n *\n *     @example\n *     // Example of a form layout that wraps a fieldset layout\n *     var input1 = new OO.ui.TextInputWidget( {\n *         placeholder: 'Username'\n *     } );\n *     var input2 = new OO.ui.TextInputWidget( {\n *         placeholder: 'Password',\n *         type: 'password'\n *     } );\n *     var submit = new OO.ui.ButtonInputWidget( {\n *         label: 'Submit'\n *     } );\n *\n *     var fieldset = new OO.ui.FieldsetLayout( {\n *         label: 'A form layout'\n *     } );\n *     fieldset.addItems( [\n *         new OO.ui.FieldLayout( input1, {\n *             label: 'Username',\n *             align: 'top'\n *         } ),\n *         new OO.ui.FieldLayout( input2, {\n *             label: 'Password',\n *             align: 'top'\n *         } ),\n *         new OO.ui.FieldLayout( submit )\n *     ] );\n *     var form = new OO.ui.FormLayout( {\n *         items: [ fieldset ],\n *         action: '/api/formhandler',\n *         method: 'get'\n *     } )\n *     $( document.body ).append( form.$element );\n *\n * @class\n * @extends OO.ui.Layout\n * @mixins OO.ui.mixin.GroupElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {string} [method] HTML form `method` attribute\n * @cfg {string} [action] HTML form `action` attribute\n * @cfg {string} [enctype] HTML form `enctype` attribute\n * @cfg {OO.ui.FieldsetLayout[]} [items] Fieldset layouts to add to the form layout.\n */\nOO.ui.FormLayout = function OoUiFormLayout( config ) {\n\tvar action;\n\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.FormLayout.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.GroupElement.call( this, $.extend( { $group: this.$element }, config ) );\n\n\t// Events\n\tthis.$element.on( 'submit', this.onFormSubmit.bind( this ) );\n\n\t// Make sure the action is safe\n\taction = config.action;\n\tif ( action !== undefined && !OO.ui.isSafeUrl( action ) ) {\n\t\taction = './' + action;\n\t}\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-formLayout' )\n\t\t.attr( {\n\t\t\tmethod: config.method,\n\t\t\taction: action,\n\t\t\tenctype: config.enctype\n\t\t} );\n\tif ( Array.isArray( config.items ) ) {\n\t\tthis.addItems( config.items );\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.FormLayout, OO.ui.Layout );\nOO.mixinClass( OO.ui.FormLayout, OO.ui.mixin.GroupElement );\n\n/* Events */\n\n/**\n * A 'submit' event is emitted when the form is submitted.\n *\n * @event submit\n */\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.FormLayout.static.tagName = 'form';\n\n/* Methods */\n\n/**\n * Handle form submit events.\n *\n * @private\n * @param {jQuery.Event} e Submit event\n * @fires submit\n * @return {OO.ui.FormLayout} The layout, for chaining\n */\nOO.ui.FormLayout.prototype.onFormSubmit = function () {\n\tif ( this.emit( 'submit' ) ) {\n\t\treturn false;\n\t}\n};\n","/**\n * PanelLayouts expand to cover the entire area of their parent. They can be configured with\n * scrolling, padding, and a frame, and are often used together with\n * {@link OO.ui.StackLayout StackLayouts}.\n *\n *     @example\n *     // Example of a panel layout\n *     var panel = new OO.ui.PanelLayout( {\n *         expanded: false,\n *         framed: true,\n *         padded: true,\n *         $content: $( '<p>A panel layout with padding and a frame.</p>' )\n *     } );\n *     $( document.body ).append( panel.$element );\n *\n * @class\n * @extends OO.ui.Layout\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [scrollable=false] Allow vertical scrolling\n * @cfg {boolean} [padded=false] Add padding between the content and the edges of the panel.\n * @cfg {boolean} [expanded=true] Expand the panel to fill the entire parent element.\n * @cfg {boolean} [framed=false] Render the panel with a frame to visually separate it from outside\n *  content.\n */\nOO.ui.PanelLayout = function OoUiPanelLayout( config ) {\n\t// Configuration initialization\n\tconfig = $.extend( {\n\t\tscrollable: false,\n\t\tpadded: false,\n\t\texpanded: true,\n\t\tframed: false\n\t}, config );\n\n\t// Parent constructor\n\tOO.ui.PanelLayout.parent.call( this, config );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-panelLayout' );\n\tif ( config.scrollable ) {\n\t\tthis.$element.addClass( 'oo-ui-panelLayout-scrollable' );\n\t}\n\tif ( config.padded ) {\n\t\tthis.$element.addClass( 'oo-ui-panelLayout-padded' );\n\t}\n\tif ( config.expanded ) {\n\t\tthis.$element.addClass( 'oo-ui-panelLayout-expanded' );\n\t}\n\tif ( config.framed ) {\n\t\tthis.$element.addClass( 'oo-ui-panelLayout-framed' );\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.PanelLayout, OO.ui.Layout );\n\n/* Static Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.PanelLayout.static.reusePreInfuseDOM = function ( node, config ) {\n\tconfig = OO.ui.PanelLayout.parent.static.reusePreInfuseDOM( node, config );\n\tif ( config.preserveContent !== false ) {\n\t\tconfig.$content = $( node ).contents();\n\t}\n\treturn config;\n};\n\n/* Methods */\n\n/**\n * Focus the panel layout\n *\n * The default implementation just focuses the first focusable element in the panel\n */\nOO.ui.PanelLayout.prototype.focus = function () {\n\tOO.ui.findFocusable( this.$element ).focus();\n};\n","/**\n * HorizontalLayout arranges its contents in a single line (using `display: inline-block` for its\n * items), with small margins between them. Convenient when you need to put a number of block-level\n * widgets on a single line next to each other.\n *\n * Note that inline elements, such as OO.ui.ButtonWidgets, do not need this wrapper.\n *\n *     @example\n *     // HorizontalLayout with a text input and a label\n *     var layout = new OO.ui.HorizontalLayout( {\n *       items: [\n *         new OO.ui.LabelWidget( { label: 'Label' } ),\n *         new OO.ui.TextInputWidget( { value: 'Text' } )\n *       ]\n *     } );\n *     $( document.body ).append( layout.$element );\n *\n * @class\n * @extends OO.ui.Layout\n * @mixins OO.ui.mixin.GroupElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {OO.ui.Widget[]|OO.ui.Layout[]} [items] Widgets or other layouts to add to the layout.\n */\nOO.ui.HorizontalLayout = function OoUiHorizontalLayout( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.HorizontalLayout.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.GroupElement.call( this, $.extend( { $group: this.$element }, config ) );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-horizontalLayout' );\n\tif ( Array.isArray( config.items ) ) {\n\t\tthis.addItems( config.items );\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.HorizontalLayout, OO.ui.Layout );\nOO.mixinClass( OO.ui.HorizontalLayout, OO.ui.mixin.GroupElement );\n","/**\n * NumberInputWidgets combine a {@link OO.ui.TextInputWidget text input} (where a value\n * can be entered manually) and two {@link OO.ui.ButtonWidget button widgets}\n * (to adjust the value in increments) to allow the user to enter a number.\n *\n *     @example\n *     // A NumberInputWidget.\n *     var numberInput = new OO.ui.NumberInputWidget( {\n *         label: 'NumberInputWidget',\n *         input: { value: 5 },\n *         min: 1,\n *         max: 10\n *     } );\n *     $( document.body ).append( numberInput.$element );\n *\n * @class\n * @extends OO.ui.TextInputWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {Object} [minusButton] Configuration options to pass to the\n *  {@link OO.ui.ButtonWidget decrementing button widget}.\n * @cfg {Object} [plusButton] Configuration options to pass to the\n *  {@link OO.ui.ButtonWidget incrementing button widget}.\n * @cfg {number} [min=-Infinity] Minimum allowed value\n * @cfg {number} [max=Infinity] Maximum allowed value\n * @cfg {number|null} [step] If specified, the field only accepts values that are multiples of this.\n * @cfg {number} [buttonStep=step||1] Delta when using the buttons or Up/Down arrow keys.\n *  Defaults to `step` if specified, otherwise `1`.\n * @cfg {number} [pageStep=10*buttonStep] Delta when using the Page-up/Page-down keys.\n *  Defaults to 10 times `buttonStep`.\n * @cfg {boolean} [showButtons=true] Whether to show the plus and minus buttons.\n */\nOO.ui.NumberInputWidget = function OoUiNumberInputWidget( config ) {\n\tvar $field = $( '<div>' ).addClass( 'oo-ui-numberInputWidget-field' );\n\n\t// Configuration initialization\n\tconfig = $.extend( {\n\t\tmin: -Infinity,\n\t\tmax: Infinity,\n\t\tshowButtons: true\n\t}, config );\n\n\t// For backward compatibility\n\t$.extend( config, config.input );\n\tthis.input = this;\n\n\t// Parent constructor\n\tOO.ui.NumberInputWidget.parent.call( this, $.extend( config, {\n\t\ttype: 'number'\n\t} ) );\n\n\tif ( config.showButtons ) {\n\t\tthis.minusButton = new OO.ui.ButtonWidget( $.extend(\n\t\t\t{\n\t\t\t\tdisabled: this.isDisabled(),\n\t\t\t\ttabIndex: -1,\n\t\t\t\tclasses: [ 'oo-ui-numberInputWidget-minusButton' ],\n\t\t\t\ticon: 'subtract'\n\t\t\t},\n\t\t\tconfig.minusButton\n\t\t) );\n\t\tthis.minusButton.$element.attr( 'aria-hidden', 'true' );\n\t\tthis.plusButton = new OO.ui.ButtonWidget( $.extend(\n\t\t\t{\n\t\t\t\tdisabled: this.isDisabled(),\n\t\t\t\ttabIndex: -1,\n\t\t\t\tclasses: [ 'oo-ui-numberInputWidget-plusButton' ],\n\t\t\t\ticon: 'add'\n\t\t\t},\n\t\t\tconfig.plusButton\n\t\t) );\n\t\tthis.plusButton.$element.attr( 'aria-hidden', 'true' );\n\t}\n\n\t// Events\n\tthis.$input.on( {\n\t\tkeydown: this.onKeyDown.bind( this ),\n\t\t'wheel mousewheel DOMMouseScroll': this.onWheel.bind( this )\n\t} );\n\tif ( config.showButtons ) {\n\t\tthis.plusButton.connect( this, {\n\t\t\tclick: [ 'onButtonClick', +1 ]\n\t\t} );\n\t\tthis.minusButton.connect( this, {\n\t\t\tclick: [ 'onButtonClick', -1 ]\n\t\t} );\n\t}\n\n\t// Build the field\n\t$field.append( this.$input );\n\tif ( config.showButtons ) {\n\t\t$field\n\t\t\t.prepend( this.minusButton.$element )\n\t\t\t.append( this.plusButton.$element );\n\t}\n\n\t// Initialization\n\tif ( config.allowInteger || config.isInteger ) {\n\t\t// Backward compatibility\n\t\tconfig.step = 1;\n\t}\n\tthis.setRange( config.min, config.max );\n\tthis.setStep( config.buttonStep, config.pageStep, config.step );\n\t// Set the validation method after we set step and range\n\t// so that it doesn't immediately call setValidityFlag\n\tthis.setValidation( this.validateNumber.bind( this ) );\n\n\tthis.$element\n\t\t.addClass( 'oo-ui-numberInputWidget' )\n\t\t.toggleClass( 'oo-ui-numberInputWidget-buttoned', config.showButtons )\n\t\t.append( $field );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.NumberInputWidget, OO.ui.TextInputWidget );\n\n/* Methods */\n\n// Backward compatibility\nOO.ui.NumberInputWidget.prototype.setAllowInteger = function ( flag ) {\n\tthis.setStep( flag ? 1 : null );\n};\n// Backward compatibility\nOO.ui.NumberInputWidget.prototype.setIsInteger = OO.ui.NumberInputWidget.prototype.setAllowInteger;\n\n// Backward compatibility\nOO.ui.NumberInputWidget.prototype.getAllowInteger = function () {\n\treturn this.step === 1;\n};\n// Backward compatibility\nOO.ui.NumberInputWidget.prototype.getIsInteger = OO.ui.NumberInputWidget.prototype.getAllowInteger;\n\n/**\n * Set the range of allowed values\n *\n * @param {number} min Minimum allowed value\n * @param {number} max Maximum allowed value\n */\nOO.ui.NumberInputWidget.prototype.setRange = function ( min, max ) {\n\tif ( min > max ) {\n\t\tthrow new Error( 'Minimum (' + min + ') must not be greater than maximum (' + max + ')' );\n\t}\n\tthis.min = min;\n\tthis.max = max;\n\tthis.$input.attr( 'min', this.min );\n\tthis.$input.attr( 'max', this.max );\n\tthis.setValidityFlag();\n};\n\n/**\n * Get the current range\n *\n * @return {number[]} Minimum and maximum values\n */\nOO.ui.NumberInputWidget.prototype.getRange = function () {\n\treturn [ this.min, this.max ];\n};\n\n/**\n * Set the stepping deltas\n *\n * @param {number} [buttonStep=step||1] Delta when using the buttons or up/down arrow keys.\n *  Defaults to `step` if specified, otherwise `1`.\n * @param {number} [pageStep=10*buttonStep] Delta when using the page-up/page-down keys.\n *  Defaults to 10 times `buttonStep`.\n * @param {number|null} [step] If specified, the field only accepts values that are multiples\n *  of this.\n */\nOO.ui.NumberInputWidget.prototype.setStep = function ( buttonStep, pageStep, step ) {\n\tif ( buttonStep === undefined ) {\n\t\tbuttonStep = step || 1;\n\t}\n\tif ( pageStep === undefined ) {\n\t\tpageStep = 10 * buttonStep;\n\t}\n\tif ( step !== null && step <= 0 ) {\n\t\tthrow new Error( 'Step value, if given, must be positive' );\n\t}\n\tif ( buttonStep <= 0 ) {\n\t\tthrow new Error( 'Button step value must be positive' );\n\t}\n\tif ( pageStep <= 0 ) {\n\t\tthrow new Error( 'Page step value must be positive' );\n\t}\n\tthis.step = step;\n\tthis.buttonStep = buttonStep;\n\tthis.pageStep = pageStep;\n\tthis.$input.attr( 'step', this.step || 'any' );\n\tthis.setValidityFlag();\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.NumberInputWidget.prototype.setValue = function ( value ) {\n\tif ( value === '' ) {\n\t\t// Some browsers allow a value in the input even if there isn't one reported by $input.val()\n\t\t// so here we make sure an 'empty' value is actually displayed as such.\n\t\tthis.$input.val( '' );\n\t}\n\treturn OO.ui.NumberInputWidget.parent.prototype.setValue.call( this, value );\n};\n\n/**\n * Get the current stepping values\n *\n * @return {number[]} Button step, page step, and validity step\n */\nOO.ui.NumberInputWidget.prototype.getStep = function () {\n\treturn [ this.buttonStep, this.pageStep, this.step ];\n};\n\n/**\n * Get the current value of the widget as a number\n *\n * @return {number} May be NaN, or an invalid number\n */\nOO.ui.NumberInputWidget.prototype.getNumericValue = function () {\n\treturn +this.getValue();\n};\n\n/**\n * Adjust the value of the widget\n *\n * @param {number} delta Adjustment amount\n */\nOO.ui.NumberInputWidget.prototype.adjustValue = function ( delta ) {\n\tvar n, v = this.getNumericValue();\n\n\tdelta = +delta;\n\tif ( isNaN( delta ) || !isFinite( delta ) ) {\n\t\tthrow new Error( 'Delta must be a finite number' );\n\t}\n\n\tif ( isNaN( v ) ) {\n\t\tn = 0;\n\t} else {\n\t\tn = v + delta;\n\t\tn = Math.max( Math.min( n, this.max ), this.min );\n\t\tif ( this.step ) {\n\t\t\tn = Math.round( n / this.step ) * this.step;\n\t\t}\n\t}\n\n\tif ( n !== v ) {\n\t\tthis.setValue( n );\n\t}\n};\n/**\n * Validate input\n *\n * @private\n * @param {string} value Field value\n * @return {boolean}\n */\nOO.ui.NumberInputWidget.prototype.validateNumber = function ( value ) {\n\tvar n = +value;\n\tif ( value === '' ) {\n\t\treturn !this.isRequired();\n\t}\n\n\tif ( isNaN( n ) || !isFinite( n ) ) {\n\t\treturn false;\n\t}\n\n\tif ( this.step && Math.floor( n / this.step ) !== n / this.step ) {\n\t\treturn false;\n\t}\n\n\tif ( n < this.min || n > this.max ) {\n\t\treturn false;\n\t}\n\n\treturn true;\n};\n\n/**\n * Handle mouse click events.\n *\n * @private\n * @param {number} dir +1 or -1\n */\nOO.ui.NumberInputWidget.prototype.onButtonClick = function ( dir ) {\n\tthis.adjustValue( dir * this.buttonStep );\n};\n\n/**\n * Handle mouse wheel events.\n *\n * @private\n * @param {jQuery.Event} event\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.NumberInputWidget.prototype.onWheel = function ( event ) {\n\tvar delta = 0;\n\n\tif ( !this.isDisabled() && this.$input.is( ':focus' ) ) {\n\t\t// Standard 'wheel' event\n\t\tif ( event.originalEvent.deltaMode !== undefined ) {\n\t\t\tthis.sawWheelEvent = true;\n\t\t}\n\t\tif ( event.originalEvent.deltaY ) {\n\t\t\tdelta = -event.originalEvent.deltaY;\n\t\t} else if ( event.originalEvent.deltaX ) {\n\t\t\tdelta = event.originalEvent.deltaX;\n\t\t}\n\n\t\t// Non-standard events\n\t\tif ( !this.sawWheelEvent ) {\n\t\t\tif ( event.originalEvent.wheelDeltaX ) {\n\t\t\t\tdelta = -event.originalEvent.wheelDeltaX;\n\t\t\t} else if ( event.originalEvent.wheelDeltaY ) {\n\t\t\t\tdelta = event.originalEvent.wheelDeltaY;\n\t\t\t} else if ( event.originalEvent.wheelDelta ) {\n\t\t\t\tdelta = event.originalEvent.wheelDelta;\n\t\t\t} else if ( event.originalEvent.detail ) {\n\t\t\t\tdelta = -event.originalEvent.detail;\n\t\t\t}\n\t\t}\n\n\t\tif ( delta ) {\n\t\t\tdelta = delta < 0 ? -1 : 1;\n\t\t\tthis.adjustValue( delta * this.buttonStep );\n\t\t}\n\n\t\treturn false;\n\t}\n};\n\n/**\n * Handle key down events.\n *\n * @private\n * @param {jQuery.Event} e Key down event\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.NumberInputWidget.prototype.onKeyDown = function ( e ) {\n\tif ( !this.isDisabled() ) {\n\t\tswitch ( e.which ) {\n\t\t\tcase OO.ui.Keys.UP:\n\t\t\t\tthis.adjustValue( this.buttonStep );\n\t\t\t\treturn false;\n\t\t\tcase OO.ui.Keys.DOWN:\n\t\t\t\tthis.adjustValue( -this.buttonStep );\n\t\t\t\treturn false;\n\t\t\tcase OO.ui.Keys.PAGEUP:\n\t\t\t\tthis.adjustValue( this.pageStep );\n\t\t\t\treturn false;\n\t\t\tcase OO.ui.Keys.PAGEDOWN:\n\t\t\t\tthis.adjustValue( -this.pageStep );\n\t\t\t\treturn false;\n\t\t}\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.NumberInputWidget.prototype.setDisabled = function ( disabled ) {\n\t// Parent method\n\tOO.ui.NumberInputWidget.parent.prototype.setDisabled.call( this, disabled );\n\n\tif ( this.minusButton ) {\n\t\tthis.minusButton.setDisabled( this.isDisabled() );\n\t}\n\tif ( this.plusButton ) {\n\t\tthis.plusButton.setDisabled( this.isDisabled() );\n\t}\n\n\treturn this;\n};\n","}( OO ) );\n"]}
\ No newline at end of file
+{"version":3,"sources":["../src/intro.js.txt","../src/core.js","tmp/src/core-messages.js","../src/mixin.js","../src/Element.js","../src/HtmlSnippet.js","../src/Layout.js","../src/Widget.js","../src/Theme.js","../src/mixins/TabIndexedElement.js","../src/mixins/ButtonElement.js","../src/mixins/GroupElement.js","../src/mixins/LabelElement.js","../src/mixins/IconElement.js","../src/mixins/IndicatorElement.js","../src/mixins/FlaggedElement.js","../src/mixins/TitledElement.js","../src/mixins/AccessKeyedElement.js","../src/widgets/ButtonWidget.js","../src/widgets/ButtonGroupWidget.js","../src/widgets/IconWidget.js","../src/widgets/IndicatorWidget.js","../src/widgets/LabelWidget.js","../src/mixins/PendingElement.js","../src/mixins/FloatableElement.js","../src/mixins/ClippableElement.js","../src/widgets/PopupWidget.js","../src/mixins/PopupElement.js","../src/widgets/PopupButtonWidget.js","../src/mixins/GroupWidget.js","../src/mixins/ItemWidget.js","../src/widgets/OptionWidget.js","../src/widgets/SelectWidget.js","../src/widgets/DecoratedOptionWidget.js","../src/widgets/MenuOptionWidget.js","../src/widgets/MenuSectionOptionWidget.js","../src/widgets/MenuSelectWidget.js","../src/widgets/DropdownWidget.js","../src/widgets/RadioOptionWidget.js","../src/widgets/RadioSelectWidget.js","../src/widgets/MultioptionWidget.js","../src/widgets/MultiselectWidget.js","../src/widgets/CheckboxMultioptionWidget.js","../src/widgets/CheckboxMultiselectWidget.js","../src/widgets/ProgressBarWidget.js","../src/widgets/InputWidget.js","../src/widgets/HiddenInputWidget.js","../src/widgets/ButtonInputWidget.js","../src/widgets/CheckboxInputWidget.js","../src/widgets/DropdownInputWidget.js","../src/widgets/RadioInputWidget.js","../src/widgets/RadioSelectInputWidget.js","../src/widgets/CheckboxMultiselectInputWidget.js","../src/widgets/TextInputWidget.js","../src/widgets/SearchInputWidget.js","../src/widgets/MultilineTextInputWidget.js","../src/widgets/ComboBoxInputWidget.js","../src/layouts/FieldLayout.js","../src/layouts/ActionFieldLayout.js","../src/layouts/FieldsetLayout.js","../src/layouts/FormLayout.js","../src/layouts/PanelLayout.js","../src/layouts/HorizontalLayout.js","../src/widgets/NumberInputWidget.js","../src/widgets/SelectFileInputWidget.js","../src/outro.js.txt"],"names":[],"mappings":"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","file":"oojs-ui-core.js","sourcesContent":["( function ( OO ) {\n\n'use strict';\n","/**\n * Namespace for all classes, static methods and static properties.\n *\n * @class\n * @singleton\n */\nOO.ui = {};\n\nOO.ui.bind = $.proxy;\n\n/**\n * @property {Object}\n */\nOO.ui.Keys = {\n\tUNDEFINED: 0,\n\tBACKSPACE: 8,\n\tDELETE: 46,\n\tLEFT: 37,\n\tRIGHT: 39,\n\tUP: 38,\n\tDOWN: 40,\n\tENTER: 13,\n\tEND: 35,\n\tHOME: 36,\n\tTAB: 9,\n\tPAGEUP: 33,\n\tPAGEDOWN: 34,\n\tESCAPE: 27,\n\tSHIFT: 16,\n\tSPACE: 32\n};\n\n/**\n * Constants for MouseEvent.which\n *\n * @property {Object}\n */\nOO.ui.MouseButtons = {\n\tLEFT: 1,\n\tMIDDLE: 2,\n\tRIGHT: 3\n};\n\n/**\n * @property {number}\n * @private\n */\nOO.ui.elementId = 0;\n\n/**\n * Generate a unique ID for element\n *\n * @return {string} ID\n */\nOO.ui.generateElementId = function () {\n\tOO.ui.elementId++;\n\treturn 'ooui-' + OO.ui.elementId;\n};\n\n/**\n * Check if an element is focusable.\n * Inspired by :focusable in jQueryUI v1.11.4 - 2015-04-14\n *\n * @param {jQuery} $element Element to test\n * @return {boolean} Element is focusable\n */\nOO.ui.isFocusableElement = function ( $element ) {\n\tvar nodeName,\n\t\telement = $element[ 0 ];\n\n\t// Anything disabled is not focusable\n\tif ( element.disabled ) {\n\t\treturn false;\n\t}\n\n\t// Check if the element is visible\n\tif ( !(\n\t\t// This is quicker than calling $element.is( ':visible' )\n\t\t$.expr.pseudos.visible( element ) &&\n\t\t// Check that all parents are visible\n\t\t!$element.parents().addBack().filter( function () {\n\t\t\treturn $.css( this, 'visibility' ) === 'hidden';\n\t\t} ).length\n\t) ) {\n\t\treturn false;\n\t}\n\n\t// Check if the element is ContentEditable, which is the string 'true'\n\tif ( element.contentEditable === 'true' ) {\n\t\treturn true;\n\t}\n\n\t// Anything with a non-negative numeric tabIndex is focusable.\n\t// Use .prop to avoid browser bugs\n\tif ( $element.prop( 'tabIndex' ) >= 0 ) {\n\t\treturn true;\n\t}\n\n\t// Some element types are naturally focusable\n\t// (indexOf is much faster than regex in Chrome and about the\n\t// same in FF: https://jsperf.com/regex-vs-indexof-array2)\n\tnodeName = element.nodeName.toLowerCase();\n\tif ( [ 'input', 'select', 'textarea', 'button', 'object' ].indexOf( nodeName ) !== -1 ) {\n\t\treturn true;\n\t}\n\n\t// Links and areas are focusable if they have an href\n\tif ( ( nodeName === 'a' || nodeName === 'area' ) && $element.attr( 'href' ) !== undefined ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n};\n\n/**\n * Find a focusable child.\n *\n * @param {jQuery} $container Container to search in\n * @param {boolean} [backwards] Search backwards\n * @return {jQuery} Focusable child, or an empty jQuery object if none found\n */\nOO.ui.findFocusable = function ( $container, backwards ) {\n\tvar $focusable = $( [] ),\n\t\t// $focusableCandidates is a superset of things that\n\t\t// could get matched by isFocusableElement\n\t\t$focusableCandidates = $container\n\t\t\t.find( 'input, select, textarea, button, object, a, area, [contenteditable], [tabindex]' );\n\n\tif ( backwards ) {\n\t\t$focusableCandidates = Array.prototype.reverse.call( $focusableCandidates );\n\t}\n\n\t$focusableCandidates.each( function () {\n\t\tvar $this = $( this );\n\t\tif ( OO.ui.isFocusableElement( $this ) ) {\n\t\t\t$focusable = $this;\n\t\t\treturn false;\n\t\t}\n\t} );\n\treturn $focusable;\n};\n\n/**\n * Get the user's language and any fallback languages.\n *\n * These language codes are used to localize user interface elements in the user's language.\n *\n * In environments that provide a localization system, this function should be overridden to\n * return the user's language(s). The default implementation returns English (en) only.\n *\n * @return {string[]} Language codes, in descending order of priority\n */\nOO.ui.getUserLanguages = function () {\n\treturn [ 'en' ];\n};\n\n/**\n * Get a value in an object keyed by language code.\n *\n * @param {Object.<string,Mixed>} obj Object keyed by language code\n * @param {string|null} [lang] Language code, if omitted or null defaults to any user language\n * @param {string} [fallback] Fallback code, used if no matching language can be found\n * @return {Mixed} Local value\n */\nOO.ui.getLocalValue = function ( obj, lang, fallback ) {\n\tvar i, len, langs;\n\n\t// Requested language\n\tif ( obj[ lang ] ) {\n\t\treturn obj[ lang ];\n\t}\n\t// Known user language\n\tlangs = OO.ui.getUserLanguages();\n\tfor ( i = 0, len = langs.length; i < len; i++ ) {\n\t\tlang = langs[ i ];\n\t\tif ( obj[ lang ] ) {\n\t\t\treturn obj[ lang ];\n\t\t}\n\t}\n\t// Fallback language\n\tif ( obj[ fallback ] ) {\n\t\treturn obj[ fallback ];\n\t}\n\t// First existing language\n\tfor ( lang in obj ) {\n\t\treturn obj[ lang ];\n\t}\n\n\treturn undefined;\n};\n\n/**\n * Check if a node is contained within another node.\n *\n * Similar to jQuery#contains except a list of containers can be supplied\n * and a boolean argument allows you to include the container in the match list\n *\n * @param {HTMLElement|HTMLElement[]} containers Container node(s) to search in\n * @param {HTMLElement} contained Node to find\n * @param {boolean} [matchContainers] Include the container(s) in the list of nodes to match,\n *  otherwise only match descendants\n * @return {boolean} The node is in the list of target nodes\n */\nOO.ui.contains = function ( containers, contained, matchContainers ) {\n\tvar i;\n\tif ( !Array.isArray( containers ) ) {\n\t\tcontainers = [ containers ];\n\t}\n\tfor ( i = containers.length - 1; i >= 0; i-- ) {\n\t\tif (\n\t\t\t( matchContainers && contained === containers[ i ] ) ||\n\t\t\t$.contains( containers[ i ], contained )\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n};\n\n/**\n * Return a function, that, as long as it continues to be invoked, will not\n * be triggered. The function will be called after it stops being called for\n * N milliseconds. If `immediate` is passed, trigger the function on the\n * leading edge, instead of the trailing.\n *\n * Ported from: http://underscorejs.org/underscore.js\n *\n * @param {Function} func Function to debounce\n * @param {number} [wait=0] Wait period in milliseconds\n * @param {boolean} [immediate] Trigger on leading edge\n * @return {Function} Debounced function\n */\nOO.ui.debounce = function ( func, wait, immediate ) {\n\tvar timeout;\n\treturn function () {\n\t\tvar context = this,\n\t\t\targs = arguments,\n\t\t\tlater = function () {\n\t\t\t\ttimeout = null;\n\t\t\t\tif ( !immediate ) {\n\t\t\t\t\tfunc.apply( context, args );\n\t\t\t\t}\n\t\t\t};\n\t\tif ( immediate && !timeout ) {\n\t\t\tfunc.apply( context, args );\n\t\t}\n\t\tif ( !timeout || wait ) {\n\t\t\tclearTimeout( timeout );\n\t\t\ttimeout = setTimeout( later, wait );\n\t\t}\n\t};\n};\n\n/**\n * Puts a console warning with provided message.\n *\n * @param {string} message Message\n */\nOO.ui.warnDeprecation = function ( message ) {\n\tif ( OO.getProp( window, 'console', 'warn' ) !== undefined ) {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn( message );\n\t}\n};\n\n/**\n * Returns a function, that, when invoked, will only be triggered at most once\n * during a given window of time. If called again during that window, it will\n * wait until the window ends and then trigger itself again.\n *\n * As it's not knowable to the caller whether the function will actually run\n * when the wrapper is called, return values from the function are entirely\n * discarded.\n *\n * @param {Function} func Function to throttle\n * @param {number} wait Throttle window length, in milliseconds\n * @return {Function} Throttled function\n */\nOO.ui.throttle = function ( func, wait ) {\n\tvar context, args, timeout,\n\t\tprevious = 0,\n\t\trun = function () {\n\t\t\ttimeout = null;\n\t\t\tprevious = Date.now();\n\t\t\tfunc.apply( context, args );\n\t\t};\n\treturn function () {\n\t\t// Check how long it's been since the last time the function was\n\t\t// called, and whether it's more or less than the requested throttle\n\t\t// period. If it's less, run the function immediately. If it's more,\n\t\t// set a timeout for the remaining time -- but don't replace an\n\t\t// existing timeout, since that'd indefinitely prolong the wait.\n\t\tvar remaining = wait - ( Date.now() - previous );\n\t\tcontext = this;\n\t\targs = arguments;\n\t\tif ( remaining <= 0 ) {\n\t\t\t// Note: unless wait was ridiculously large, this means we'll\n\t\t\t// automatically run the first time the function was called in a\n\t\t\t// given period. (If you provide a wait period larger than the\n\t\t\t// current Unix timestamp, you *deserve* unexpected behavior.)\n\t\t\tclearTimeout( timeout );\n\t\t\trun();\n\t\t} else if ( !timeout ) {\n\t\t\ttimeout = setTimeout( run, remaining );\n\t\t}\n\t};\n};\n\n/**\n * A (possibly faster) way to get the current timestamp as an integer.\n *\n * @deprecated Since 0.31.1; use `Date.now()` instead.\n * @return {number} Current timestamp, in milliseconds since the Unix epoch\n */\nOO.ui.now = function () {\n\tOO.ui.warnDeprecation( 'OO.ui.now() is deprecated, use Date.now() instead' );\n\treturn Date.now();\n};\n\n/**\n * Reconstitute a JavaScript object corresponding to a widget created by\n * the PHP implementation.\n *\n * This is an alias for `OO.ui.Element.static.infuse()`.\n *\n * @param {string|HTMLElement|jQuery} idOrNode\n *   A DOM id (if a string) or node for the widget to infuse.\n * @param {Object} [config] Configuration options\n * @return {OO.ui.Element}\n *   The `OO.ui.Element` corresponding to this (infusable) document node.\n */\nOO.ui.infuse = function ( idOrNode, config ) {\n\treturn OO.ui.Element.static.infuse( idOrNode, config );\n};\n\n/**\n * Get a localized message.\n *\n * After the message key, message parameters may optionally be passed. In the default\n * implementation, any occurrences of $1 are replaced with the first parameter, $2 with the\n * second parameter, etc.\n * Alternative implementations of OO.ui.msg may use any substitution system they like, as long\n * as they support unnamed, ordered message parameters.\n *\n * In environments that provide a localization system, this function should be overridden to\n * return the message translated in the user's language. The default implementation always\n * returns English messages. An example of doing this with\n * [jQuery.i18n](https://github.com/wikimedia/jquery.i18n) follows.\n *\n *     @example\n *     var i, iLen, button,\n *         messagePath = 'oojs-ui/dist/i18n/',\n *         languages = [ $.i18n().locale, 'ur', 'en' ],\n *         languageMap = {};\n *\n *     for ( i = 0, iLen = languages.length; i < iLen; i++ ) {\n *         languageMap[ languages[ i ] ] = messagePath + languages[ i ].toLowerCase() + '.json';\n *     }\n *\n *     $.i18n().load( languageMap ).done( function() {\n *         // Replace the built-in `msg` only once we've loaded the internationalization.\n *         // OOUI uses `OO.ui.deferMsg` for all initially-loaded messages. So long as\n *         // you put off creating any widgets until this promise is complete, no English\n *         // will be displayed.\n *         OO.ui.msg = $.i18n;\n *\n *         // A button displaying \"OK\" in the default locale\n *         button = new OO.ui.ButtonWidget( {\n *             label: OO.ui.msg( 'ooui-dialog-message-accept' ),\n *             icon: 'check'\n *         } );\n *         $( document.body ).append( button.$element );\n *\n *         // A button displaying \"OK\" in Urdu\n *         $.i18n().locale = 'ur';\n *         button = new OO.ui.ButtonWidget( {\n *             label: OO.ui.msg( 'ooui-dialog-message-accept' ),\n *             icon: 'check'\n *         } );\n *         $( document.body ).append( button.$element );\n *     } );\n *\n * @param {string} key Message key\n * @param {...Mixed} [params] Message parameters\n * @return {string} Translated message with parameters substituted\n */\nOO.ui.msg = function ( key ) {\n\t// `OO.ui.msg.messages` is defined in code generated during the build process\n\tvar messages = OO.ui.msg.messages,\n\t\tmessage = messages[ key ],\n\t\tparams = Array.prototype.slice.call( arguments, 1 );\n\tif ( typeof message === 'string' ) {\n\t\t// Perform $1 substitution\n\t\tmessage = message.replace( /\\$(\\d+)/g, function ( unused, n ) {\n\t\t\tvar i = parseInt( n, 10 );\n\t\t\treturn params[ i - 1 ] !== undefined ? params[ i - 1 ] : '$' + n;\n\t\t} );\n\t} else {\n\t\t// Return placeholder if message not found\n\t\tmessage = '[' + key + ']';\n\t}\n\treturn message;\n};\n\n/**\n * Package a message and arguments for deferred resolution.\n *\n * Use this when you are statically specifying a message and the message may not yet be present.\n *\n * @param {string} key Message key\n * @param {...Mixed} [params] Message parameters\n * @return {Function} Function that returns the resolved message when executed\n */\nOO.ui.deferMsg = function () {\n\tvar args = arguments;\n\treturn function () {\n\t\treturn OO.ui.msg.apply( OO.ui, args );\n\t};\n};\n\n/**\n * Resolve a message.\n *\n * If the message is a function it will be executed, otherwise it will pass through directly.\n *\n * @param {Function|string} msg Deferred message, or message text\n * @return {string} Resolved message\n */\nOO.ui.resolveMsg = function ( msg ) {\n\tif ( typeof msg === 'function' ) {\n\t\treturn msg();\n\t}\n\treturn msg;\n};\n\n/**\n * @param {string} url\n * @return {boolean}\n */\nOO.ui.isSafeUrl = function ( url ) {\n\t// Keep this function in sync with php/Tag.php\n\tvar i, protocolWhitelist;\n\n\tfunction stringStartsWith( haystack, needle ) {\n\t\treturn haystack.substr( 0, needle.length ) === needle;\n\t}\n\n\tprotocolWhitelist = [\n\t\t'bitcoin', 'ftp', 'ftps', 'geo', 'git', 'gopher', 'http', 'https', 'irc', 'ircs',\n\t\t'magnet', 'mailto', 'mms', 'news', 'nntp', 'redis', 'sftp', 'sip', 'sips', 'sms', 'ssh',\n\t\t'svn', 'tel', 'telnet', 'urn', 'worldwind', 'xmpp'\n\t];\n\n\tif ( url === '' ) {\n\t\treturn true;\n\t}\n\n\tfor ( i = 0; i < protocolWhitelist.length; i++ ) {\n\t\tif ( stringStartsWith( url, protocolWhitelist[ i ] + ':' ) ) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t// This matches '//' too\n\tif ( stringStartsWith( url, '/' ) || stringStartsWith( url, './' ) ) {\n\t\treturn true;\n\t}\n\tif ( stringStartsWith( url, '?' ) || stringStartsWith( url, '#' ) ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n};\n\n/**\n * Check if the user has a 'mobile' device.\n *\n * For our purposes this means the user is primarily using an\n * on-screen keyboard, touch input instead of a mouse and may\n * have a physically small display.\n *\n * It is left up to implementors to decide how to compute this\n * so the default implementation always returns false.\n *\n * @return {boolean} User is on a mobile device\n */\nOO.ui.isMobile = function () {\n\treturn false;\n};\n\n/**\n * Get the additional spacing that should be taken into account when displaying elements that are\n * clipped to the viewport, e.g. dropdown menus and popups. This is meant to be overridden to avoid\n * such menus overlapping any fixed headers/toolbars/navigation used by the site.\n *\n * @return {Object} Object with the properties 'top', 'right', 'bottom', 'left', each representing\n *  the extra spacing from that edge of viewport (in pixels)\n */\nOO.ui.getViewportSpacing = function () {\n\treturn {\n\t\ttop: 0,\n\t\tright: 0,\n\t\tbottom: 0,\n\t\tleft: 0\n\t};\n};\n\n/**\n * Get the default overlay, which is used by various widgets when they are passed `$overlay: true`.\n * See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.\n *\n * @return {jQuery} Default overlay node\n */\nOO.ui.getDefaultOverlay = function () {\n\tif ( !OO.ui.$defaultOverlay ) {\n\t\tOO.ui.$defaultOverlay = $( '<div>' ).addClass( 'oo-ui-defaultOverlay' );\n\t\t$( document.body ).append( OO.ui.$defaultOverlay );\n\t}\n\treturn OO.ui.$defaultOverlay;\n};\n","/**\n * Message store for the default implementation of OO.ui.msg.\n *\n * Environments that provide a localization system should not use this, but should override\n * OO.ui.msg altogether.\n *\n * @private\n */\nOO.ui.msg.messages = {\n\t\"ooui-outline-control-move-down\": \"Move item down\",\n\t\"ooui-outline-control-move-up\": \"Move item up\",\n\t\"ooui-outline-control-remove\": \"Remove item\",\n\t\"ooui-toolbar-more\": \"More\",\n\t\"ooui-toolgroup-expand\": \"More\",\n\t\"ooui-toolgroup-collapse\": \"Fewer\",\n\t\"ooui-item-remove\": \"Remove\",\n\t\"ooui-dialog-message-accept\": \"OK\",\n\t\"ooui-dialog-message-reject\": \"Cancel\",\n\t\"ooui-dialog-process-error\": \"Something went wrong\",\n\t\"ooui-dialog-process-dismiss\": \"Dismiss\",\n\t\"ooui-dialog-process-retry\": \"Try again\",\n\t\"ooui-dialog-process-continue\": \"Continue\",\n\t\"ooui-combobox-button-label\": \"Dropdown for combobox\",\n\t\"ooui-selectfile-button-select\": \"Select a file\",\n\t\"ooui-selectfile-not-supported\": \"File selection is not supported\",\n\t\"ooui-selectfile-placeholder\": \"No file is selected\",\n\t\"ooui-selectfile-dragdrop-placeholder\": \"Drop file here\",\n\t\"ooui-field-help\": \"Help\"\n};\n","/*!\n * Mixin namespace.\n */\n\n/**\n * Namespace for OOUI mixins.\n *\n * Mixins are named according to the type of object they are intended to\n * be mixed in to.  For example, OO.ui.mixin.GroupElement is intended to be\n * mixed in to an instance of OO.ui.Element, and OO.ui.mixin.GroupWidget\n * is intended to be mixed in to an instance of OO.ui.Widget.\n *\n * @class\n * @singleton\n */\nOO.ui.mixin = {};\n","/**\n * Each Element represents a rendering in the DOM—a button or an icon, for example, or anything\n * that is visible to a user. Unlike {@link OO.ui.Widget widgets}, plain elements usually do not\n * have events connected to them and can't be interacted with.\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {string[]} [classes] The names of the CSS classes to apply to the element. CSS styles are\n *  added to the top level (e.g., the outermost div) of the element. See the\n *  [OOUI documentation on MediaWiki][2] for an example.\n *  [2]: https://www.mediawiki.org/wiki/OOUI/Widgets/Buttons_and_Switches#cssExample\n * @cfg {string} [id] The HTML id attribute used in the rendered tag.\n * @cfg {string} [text] Text to insert\n * @cfg {Array} [content] An array of content elements to append (after #text).\n *  Strings will be html-escaped; use an OO.ui.HtmlSnippet to append raw HTML.\n *  Instances of OO.ui.Element will have their $element appended.\n * @cfg {jQuery} [$content] Content elements to append (after #text).\n * @cfg {jQuery} [$element] Wrapper element. Defaults to a new element with #getTagName.\n * @cfg {Mixed} [data] Custom data of any type or combination of types (e.g., string, number,\n *  array, object).\n *  Data can also be specified with the #setData method.\n */\nOO.ui.Element = function OoUiElement( config ) {\n\tif ( OO.ui.isDemo ) {\n\t\tthis.initialConfig = config;\n\t}\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.$ = function () {\n\t\tOO.ui.warnDeprecation( 'this.$ is deprecated, use global $ instead' );\n\t\treturn $.apply( this, arguments );\n\t};\n\tthis.elementId = null;\n\tthis.visible = true;\n\tthis.data = config.data;\n\tthis.$element = config.$element ||\n\t\t$( document.createElement( this.getTagName() ) );\n\tthis.elementGroup = null;\n\n\t// Initialization\n\tif ( Array.isArray( config.classes ) ) {\n\t\tthis.$element.addClass( config.classes );\n\t}\n\tif ( config.id ) {\n\t\tthis.setElementId( config.id );\n\t}\n\tif ( config.text ) {\n\t\tthis.$element.text( config.text );\n\t}\n\tif ( config.content ) {\n\t\t// The `content` property treats plain strings as text; use an\n\t\t// HtmlSnippet to append HTML content.  `OO.ui.Element`s get their\n\t\t// appropriate $element appended.\n\t\tthis.$element.append( config.content.map( function ( v ) {\n\t\t\tif ( typeof v === 'string' ) {\n\t\t\t\t// Escape string so it is properly represented in HTML.\n\t\t\t\t// Don't create empty text nodes for empty strings.\n\t\t\t\treturn v ? document.createTextNode( v ) : undefined;\n\t\t\t} else if ( v instanceof OO.ui.HtmlSnippet ) {\n\t\t\t\t// Bypass escaping.\n\t\t\t\treturn v.toString();\n\t\t\t} else if ( v instanceof OO.ui.Element ) {\n\t\t\t\treturn v.$element;\n\t\t\t}\n\t\t\treturn v;\n\t\t} ) );\n\t}\n\tif ( config.$content ) {\n\t\t// The `$content` property treats plain strings as HTML.\n\t\tthis.$element.append( config.$content );\n\t}\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.Element );\n\n/* Static Properties */\n\n/**\n * The name of the HTML tag used by the element.\n *\n * The static value may be ignored if the #getTagName method is overridden.\n *\n * @static\n * @inheritable\n * @property {string}\n */\nOO.ui.Element.static.tagName = 'div';\n\n/* Static Methods */\n\n/**\n * Reconstitute a JavaScript object corresponding to a widget created\n * by the PHP implementation.\n *\n * @param {string|HTMLElement|jQuery} idOrNode\n *   A DOM id (if a string) or node for the widget to infuse.\n * @param {Object} [config] Configuration options\n * @return {OO.ui.Element}\n *   The `OO.ui.Element` corresponding to this (infusable) document node.\n *   For `Tag` objects emitted on the HTML side (used occasionally for content)\n *   the value returned is a newly-created Element wrapping around the existing\n *   DOM node.\n */\nOO.ui.Element.static.infuse = function ( idOrNode, config ) {\n\tvar obj = OO.ui.Element.static.unsafeInfuse( idOrNode, config, false );\n\n\tif ( typeof idOrNode === 'string' ) {\n\t\t// IDs deprecated since 0.29.7\n\t\tOO.ui.warnDeprecation(\n\t\t\t'Passing a string ID to infuse is deprecated. Use an HTMLElement or jQuery collection instead.'\n\t\t);\n\t}\n\t// Verify that the type matches up.\n\t// FIXME: uncomment after T89721 is fixed, see T90929.\n\t/*\n\tif ( !( obj instanceof this['class'] ) ) {\n\t\tthrow new Error( 'Infusion type mismatch!' );\n\t}\n\t*/\n\treturn obj;\n};\n\n/**\n * Implementation helper for `infuse`; skips the type check and has an\n * extra property so that only the top-level invocation touches the DOM.\n *\n * @private\n * @param {string|HTMLElement|jQuery} idOrNode\n * @param {Object} [config] Configuration options\n * @param {jQuery.Promise} [domPromise] A promise that will be resolved\n *     when the top-level widget of this infusion is inserted into DOM,\n *     replacing the original node; only used internally.\n * @return {OO.ui.Element}\n */\nOO.ui.Element.static.unsafeInfuse = function ( idOrNode, config, domPromise ) {\n\t// look for a cached result of a previous infusion.\n\tvar id, $elem, error, data, cls, parts, parent, obj, top, state, infusedChildren;\n\tif ( typeof idOrNode === 'string' ) {\n\t\tid = idOrNode;\n\t\t$elem = $( document.getElementById( id ) );\n\t} else {\n\t\t$elem = $( idOrNode );\n\t\tid = $elem.attr( 'id' );\n\t}\n\tif ( !$elem.length ) {\n\t\tif ( typeof idOrNode === 'string' ) {\n\t\t\terror = 'Widget not found: ' + idOrNode;\n\t\t} else if ( idOrNode && idOrNode.selector ) {\n\t\t\terror = 'Widget not found: ' + idOrNode.selector;\n\t\t} else {\n\t\t\terror = 'Widget not found';\n\t\t}\n\t\tthrow new Error( error );\n\t}\n\tif ( $elem[ 0 ].oouiInfused ) {\n\t\t$elem = $elem[ 0 ].oouiInfused;\n\t}\n\tdata = $elem.data( 'ooui-infused' );\n\tif ( data ) {\n\t\t// cached!\n\t\tif ( data === true ) {\n\t\t\tthrow new Error( 'Circular dependency! ' + id );\n\t\t}\n\t\tif ( domPromise ) {\n\t\t\t// Pick up dynamic state, like focus, value of form inputs, scroll position, etc.\n\t\t\tstate = data.constructor.static.gatherPreInfuseState( $elem, data );\n\t\t\t// Restore dynamic state after the new element is re-inserted into DOM under\n\t\t\t// infused parent.\n\t\t\tdomPromise.done( data.restorePreInfuseState.bind( data, state ) );\n\t\t\tinfusedChildren = $elem.data( 'ooui-infused-children' );\n\t\t\tif ( infusedChildren && infusedChildren.length ) {\n\t\t\t\tinfusedChildren.forEach( function ( data ) {\n\t\t\t\t\tvar state = data.constructor.static.gatherPreInfuseState( $elem, data );\n\t\t\t\t\tdomPromise.done( data.restorePreInfuseState.bind( data, state ) );\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\treturn data;\n\t}\n\tdata = $elem.attr( 'data-ooui' );\n\tif ( !data ) {\n\t\tthrow new Error( 'No infusion data found: ' + id );\n\t}\n\ttry {\n\t\tdata = JSON.parse( data );\n\t} catch ( _ ) {\n\t\tdata = null;\n\t}\n\tif ( !( data && data._ ) ) {\n\t\tthrow new Error( 'No valid infusion data found: ' + id );\n\t}\n\tif ( data._ === 'Tag' ) {\n\t\t// Special case: this is a raw Tag; wrap existing node, don't rebuild.\n\t\treturn new OO.ui.Element( $.extend( {}, config, { $element: $elem } ) );\n\t}\n\tparts = data._.split( '.' );\n\tcls = OO.getProp.apply( OO, [ window ].concat( parts ) );\n\tif ( cls === undefined ) {\n\t\tthrow new Error( 'Unknown widget type: id: ' + id + ', class: ' + data._ );\n\t}\n\n\t// Verify that we're creating an OO.ui.Element instance\n\tparent = cls.parent;\n\n\twhile ( parent !== undefined ) {\n\t\tif ( parent === OO.ui.Element ) {\n\t\t\t// Safe\n\t\t\tbreak;\n\t\t}\n\n\t\tparent = parent.parent;\n\t}\n\n\tif ( parent !== OO.ui.Element ) {\n\t\tthrow new Error( 'Unknown widget type: id: ' + id + ', class: ' + data._ );\n\t}\n\n\tif ( !domPromise ) {\n\t\ttop = $.Deferred();\n\t\tdomPromise = top.promise();\n\t}\n\t$elem.data( 'ooui-infused', true ); // prevent loops\n\tdata.id = id; // implicit\n\tinfusedChildren = [];\n\tdata = OO.copy( data, null, function deserialize( value ) {\n\t\tvar infused;\n\t\tif ( OO.isPlainObject( value ) ) {\n\t\t\tif ( value.tag ) {\n\t\t\t\tinfused = OO.ui.Element.static.unsafeInfuse( value.tag, config, domPromise );\n\t\t\t\tinfusedChildren.push( infused );\n\t\t\t\t// Flatten the structure\n\t\t\t\tinfusedChildren.push.apply(\n\t\t\t\t\tinfusedChildren,\n\t\t\t\t\tinfused.$element.data( 'ooui-infused-children' ) || []\n\t\t\t\t);\n\t\t\t\tinfused.$element.removeData( 'ooui-infused-children' );\n\t\t\t\treturn infused;\n\t\t\t}\n\t\t\tif ( value.html !== undefined ) {\n\t\t\t\treturn new OO.ui.HtmlSnippet( value.html );\n\t\t\t}\n\t\t}\n\t} );\n\t// allow widgets to reuse parts of the DOM\n\tdata = cls.static.reusePreInfuseDOM( $elem[ 0 ], data );\n\t// pick up dynamic state, like focus, value of form inputs, scroll position, etc.\n\tstate = cls.static.gatherPreInfuseState( $elem[ 0 ], data );\n\t// rebuild widget\n\t// eslint-disable-next-line new-cap\n\tobj = new cls( $.extend( {}, config, data ) );\n\t// If anyone is holding a reference to the old DOM element,\n\t// let's allow them to OO.ui.infuse() it and do what they expect, see T105828.\n\t// Do not use jQuery.data(), as using it on detached nodes leaks memory in 1.x line by design.\n\t$elem[ 0 ].oouiInfused = obj.$element;\n\t// now replace old DOM with this new DOM.\n\tif ( top ) {\n\t\t// An efficient constructor might be able to reuse the entire DOM tree of the original\n\t\t// element, so only mutate the DOM if we need to.\n\t\tif ( $elem[ 0 ] !== obj.$element[ 0 ] ) {\n\t\t\t$elem.replaceWith( obj.$element );\n\t\t}\n\t\ttop.resolve();\n\t}\n\tobj.$element.data( 'ooui-infused', obj );\n\tobj.$element.data( 'ooui-infused-children', infusedChildren );\n\t// set the 'data-ooui' attribute so we can identify infused widgets\n\tobj.$element.attr( 'data-ooui', '' );\n\t// restore dynamic state after the new element is inserted into DOM\n\tdomPromise.done( obj.restorePreInfuseState.bind( obj, state ) );\n\treturn obj;\n};\n\n/**\n * Pick out parts of `node`'s DOM to be reused when infusing a widget.\n *\n * This method **must not** make any changes to the DOM, only find interesting pieces and add them\n * to `config` (which should then be returned). Actual DOM juggling should then be done by the\n * constructor, which will be given the enhanced config.\n *\n * @protected\n * @param {HTMLElement} node\n * @param {Object} config\n * @return {Object}\n */\nOO.ui.Element.static.reusePreInfuseDOM = function ( node, config ) {\n\treturn config;\n};\n\n/**\n * Gather the dynamic state (focus, value of form inputs, scroll position, etc.) of an HTML DOM\n * node (and its children) that represent an Element of the same class and the given configuration,\n * generated by the PHP implementation.\n *\n * This method is called just before `node` is detached from the DOM. The return value of this\n * function will be passed to #restorePreInfuseState after the newly created widget's #$element\n * is inserted into DOM to replace `node`.\n *\n * @protected\n * @param {HTMLElement} node\n * @param {Object} config\n * @return {Object}\n */\nOO.ui.Element.static.gatherPreInfuseState = function () {\n\treturn {};\n};\n\n/**\n * Get a jQuery function within a specific document.\n *\n * @static\n * @param {jQuery|HTMLElement|HTMLDocument|Window} context Context to bind the function to\n * @param {jQuery} [$iframe] HTML iframe element that contains the document, omit if document is\n *   not in an iframe\n * @return {Function} Bound jQuery function\n */\nOO.ui.Element.static.getJQuery = function ( context, $iframe ) {\n\tfunction wrapper( selector ) {\n\t\treturn $( selector, wrapper.context );\n\t}\n\n\twrapper.context = this.getDocument( context );\n\n\tif ( $iframe ) {\n\t\twrapper.$iframe = $iframe;\n\t}\n\n\treturn wrapper;\n};\n\n/**\n * Get the document of an element.\n *\n * @static\n * @param {jQuery|HTMLElement|HTMLDocument|Window} obj Object to get the document for\n * @return {HTMLDocument|null} Document object\n */\nOO.ui.Element.static.getDocument = function ( obj ) {\n\t// jQuery - selections created \"offscreen\" won't have a context, so .context isn't reliable\n\treturn ( obj[ 0 ] && obj[ 0 ].ownerDocument ) ||\n\t\t// Empty jQuery selections might have a context\n\t\tobj.context ||\n\t\t// HTMLElement\n\t\tobj.ownerDocument ||\n\t\t// Window\n\t\tobj.document ||\n\t\t// HTMLDocument\n\t\t( obj.nodeType === Node.DOCUMENT_NODE && obj ) ||\n\t\tnull;\n};\n\n/**\n * Get the window of an element or document.\n *\n * @static\n * @param {jQuery|HTMLElement|HTMLDocument|Window} obj Context to get the window for\n * @return {Window} Window object\n */\nOO.ui.Element.static.getWindow = function ( obj ) {\n\tvar doc = this.getDocument( obj );\n\treturn doc.defaultView;\n};\n\n/**\n * Get the direction of an element or document.\n *\n * @static\n * @param {jQuery|HTMLElement|HTMLDocument|Window} obj Context to get the direction for\n * @return {string} Text direction, either 'ltr' or 'rtl'\n */\nOO.ui.Element.static.getDir = function ( obj ) {\n\tvar isDoc, isWin;\n\n\tif ( obj instanceof $ ) {\n\t\tobj = obj[ 0 ];\n\t}\n\tisDoc = obj.nodeType === Node.DOCUMENT_NODE;\n\tisWin = obj.document !== undefined;\n\tif ( isDoc || isWin ) {\n\t\tif ( isWin ) {\n\t\t\tobj = obj.document;\n\t\t}\n\t\tobj = obj.body;\n\t}\n\treturn $( obj ).css( 'direction' );\n};\n\n/**\n * Get the offset between two frames.\n *\n * TODO: Make this function not use recursion.\n *\n * @static\n * @param {Window} from Window of the child frame\n * @param {Window} [to=window] Window of the parent frame\n * @param {Object} [offset] Offset to start with, used internally\n * @return {Object} Offset object, containing left and top properties\n */\nOO.ui.Element.static.getFrameOffset = function ( from, to, offset ) {\n\tvar i, len, frames, frame, rect;\n\n\tif ( !to ) {\n\t\tto = window;\n\t}\n\tif ( !offset ) {\n\t\toffset = { top: 0, left: 0 };\n\t}\n\tif ( from.parent === from ) {\n\t\treturn offset;\n\t}\n\n\t// Get iframe element\n\tframes = from.parent.document.getElementsByTagName( 'iframe' );\n\tfor ( i = 0, len = frames.length; i < len; i++ ) {\n\t\tif ( frames[ i ].contentWindow === from ) {\n\t\t\tframe = frames[ i ];\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Recursively accumulate offset values\n\tif ( frame ) {\n\t\trect = frame.getBoundingClientRect();\n\t\toffset.left += rect.left;\n\t\toffset.top += rect.top;\n\t\tif ( from !== to ) {\n\t\t\tthis.getFrameOffset( from.parent, offset );\n\t\t}\n\t}\n\treturn offset;\n};\n\n/**\n * Get the offset between two elements.\n *\n * The two elements may be in a different frame, but in that case the frame $element is in must\n * be contained in the frame $anchor is in.\n *\n * @static\n * @param {jQuery} $element Element whose position to get\n * @param {jQuery} $anchor Element to get $element's position relative to\n * @return {Object} Translated position coordinates, containing top and left properties\n */\nOO.ui.Element.static.getRelativePosition = function ( $element, $anchor ) {\n\tvar iframe, iframePos,\n\t\tpos = $element.offset(),\n\t\tanchorPos = $anchor.offset(),\n\t\telementDocument = this.getDocument( $element ),\n\t\tanchorDocument = this.getDocument( $anchor );\n\n\t// If $element isn't in the same document as $anchor, traverse up\n\twhile ( elementDocument !== anchorDocument ) {\n\t\tiframe = elementDocument.defaultView.frameElement;\n\t\tif ( !iframe ) {\n\t\t\tthrow new Error( '$element frame is not contained in $anchor frame' );\n\t\t}\n\t\tiframePos = $( iframe ).offset();\n\t\tpos.left += iframePos.left;\n\t\tpos.top += iframePos.top;\n\t\telementDocument = iframe.ownerDocument;\n\t}\n\tpos.left -= anchorPos.left;\n\tpos.top -= anchorPos.top;\n\treturn pos;\n};\n\n/**\n * Get element border sizes.\n *\n * @static\n * @param {HTMLElement} el Element to measure\n * @return {Object} Dimensions object with `top`, `left`, `bottom` and `right` properties\n */\nOO.ui.Element.static.getBorders = function ( el ) {\n\tvar doc = el.ownerDocument,\n\t\twin = doc.defaultView,\n\t\tstyle = win.getComputedStyle( el, null ),\n\t\t$el = $( el ),\n\t\ttop = parseFloat( style ? style.borderTopWidth : $el.css( 'borderTopWidth' ) ) || 0,\n\t\tleft = parseFloat( style ? style.borderLeftWidth : $el.css( 'borderLeftWidth' ) ) || 0,\n\t\tbottom = parseFloat( style ? style.borderBottomWidth : $el.css( 'borderBottomWidth' ) ) || 0,\n\t\tright = parseFloat( style ? style.borderRightWidth : $el.css( 'borderRightWidth' ) ) || 0;\n\n\treturn {\n\t\ttop: top,\n\t\tleft: left,\n\t\tbottom: bottom,\n\t\tright: right\n\t};\n};\n\n/**\n * Get dimensions of an element or window.\n *\n * @static\n * @param {HTMLElement|Window} el Element to measure\n * @return {Object} Dimensions object with `borders`, `scroll`, `scrollbar` and `rect` properties\n */\nOO.ui.Element.static.getDimensions = function ( el ) {\n\tvar $el, $win,\n\t\tdoc = el.ownerDocument || el.document,\n\t\twin = doc.defaultView;\n\n\tif ( win === el || el === doc.documentElement ) {\n\t\t$win = $( win );\n\t\treturn {\n\t\t\tborders: { top: 0, left: 0, bottom: 0, right: 0 },\n\t\t\tscroll: {\n\t\t\t\ttop: $win.scrollTop(),\n\t\t\t\tleft: $win.scrollLeft()\n\t\t\t},\n\t\t\tscrollbar: { right: 0, bottom: 0 },\n\t\t\trect: {\n\t\t\t\ttop: 0,\n\t\t\t\tleft: 0,\n\t\t\t\tbottom: $win.innerHeight(),\n\t\t\t\tright: $win.innerWidth()\n\t\t\t}\n\t\t};\n\t} else {\n\t\t$el = $( el );\n\t\treturn {\n\t\t\tborders: this.getBorders( el ),\n\t\t\tscroll: {\n\t\t\t\ttop: $el.scrollTop(),\n\t\t\t\tleft: $el.scrollLeft()\n\t\t\t},\n\t\t\tscrollbar: {\n\t\t\t\tright: $el.innerWidth() - el.clientWidth,\n\t\t\t\tbottom: $el.innerHeight() - el.clientHeight\n\t\t\t},\n\t\t\trect: el.getBoundingClientRect()\n\t\t};\n\t}\n};\n\n/**\n * Get the number of pixels that an element's content is scrolled to the left.\n *\n * Adapted from <https://github.com/othree/jquery.rtl-scroll-type>.\n * Original code copyright 2012 Wei-Ko Kao, licensed under the MIT License.\n *\n * This function smooths out browser inconsistencies (nicely described in the README at\n * <https://github.com/othree/jquery.rtl-scroll-type>) and produces a result consistent\n * with Firefox's 'scrollLeft', which seems the sanest.\n *\n * @static\n * @method\n * @param {HTMLElement|Window} el Element to measure\n * @return {number} Scroll position from the left.\n *  If the element's direction is LTR, this is a positive number between `0` (initial scroll\n *  position) and `el.scrollWidth - el.clientWidth` (furthest possible scroll position).\n *  If the element's direction is RTL, this is a negative number between `0` (initial scroll\n *  position) and `-el.scrollWidth + el.clientWidth` (furthest possible scroll position).\n */\nOO.ui.Element.static.getScrollLeft = ( function () {\n\tvar rtlScrollType = null;\n\n\tfunction test() {\n\t\tvar $definer = $( '<div>' ).attr( {\n\t\t\t\tdir: 'rtl',\n\t\t\t\tstyle: 'font-size: 14px; width: 4px; height: 1px; position: absolute; top: -1000px; overflow: scroll;'\n\t\t\t} ).text( 'ABCD' ),\n\t\t\tdefiner = $definer[ 0 ];\n\n\t\t$definer.appendTo( 'body' );\n\t\tif ( definer.scrollLeft > 0 ) {\n\t\t\t// Safari, Chrome\n\t\t\trtlScrollType = 'default';\n\t\t} else {\n\t\t\tdefiner.scrollLeft = 1;\n\t\t\tif ( definer.scrollLeft === 0 ) {\n\t\t\t\t// Firefox, old Opera\n\t\t\t\trtlScrollType = 'negative';\n\t\t\t} else {\n\t\t\t\t// Internet Explorer, Edge\n\t\t\t\trtlScrollType = 'reverse';\n\t\t\t}\n\t\t}\n\t\t$definer.remove();\n\t}\n\n\treturn function getScrollLeft( el ) {\n\t\tvar isRoot = el.window === el ||\n\t\t\t\tel === el.ownerDocument.body ||\n\t\t\t\tel === el.ownerDocument.documentElement,\n\t\t\tscrollLeft = isRoot ? $( window ).scrollLeft() : el.scrollLeft,\n\t\t\t// All browsers use the correct scroll type ('negative') on the root, so don't\n\t\t\t// do any fixups when looking at the root element\n\t\t\tdirection = isRoot ? 'ltr' : $( el ).css( 'direction' );\n\n\t\tif ( direction === 'rtl' ) {\n\t\t\tif ( rtlScrollType === null ) {\n\t\t\t\ttest();\n\t\t\t}\n\t\t\tif ( rtlScrollType === 'reverse' ) {\n\t\t\t\tscrollLeft = -scrollLeft;\n\t\t\t} else if ( rtlScrollType === 'default' ) {\n\t\t\t\tscrollLeft = scrollLeft - el.scrollWidth + el.clientWidth;\n\t\t\t}\n\t\t}\n\n\t\treturn scrollLeft;\n\t};\n}() );\n\n/**\n * Get the root scrollable element of given element's document.\n *\n * On Blink-based browsers (Chrome etc.), `document.documentElement` can't be used to get or set\n * the scrollTop property; instead we have to use `document.body`. Changing and testing the value\n * lets us use 'body' or 'documentElement' based on what is working.\n *\n * https://code.google.com/p/chromium/issues/detail?id=303131\n *\n * @static\n * @param {HTMLElement} el Element to find root scrollable parent for\n * @return {HTMLElement} Scrollable parent, `document.body` or `document.documentElement`\n *     depending on browser\n */\nOO.ui.Element.static.getRootScrollableElement = function ( el ) {\n\tvar scrollTop, body;\n\n\tif ( OO.ui.scrollableElement === undefined ) {\n\t\tbody = el.ownerDocument.body;\n\t\tscrollTop = body.scrollTop;\n\t\tbody.scrollTop = 1;\n\n\t\t// In some browsers (observed in Chrome 56 on Linux Mint 18.1),\n\t\t// body.scrollTop doesn't become exactly 1, but a fractional value like 0.76\n\t\tif ( Math.round( body.scrollTop ) === 1 ) {\n\t\t\tbody.scrollTop = scrollTop;\n\t\t\tOO.ui.scrollableElement = 'body';\n\t\t} else {\n\t\t\tOO.ui.scrollableElement = 'documentElement';\n\t\t}\n\t}\n\n\treturn el.ownerDocument[ OO.ui.scrollableElement ];\n};\n\n/**\n * Get closest scrollable container.\n *\n * Traverses up until either a scrollable element or the root is reached, in which case the root\n * scrollable element will be returned (see #getRootScrollableElement).\n *\n * @static\n * @param {HTMLElement} el Element to find scrollable container for\n * @param {string} [dimension] Dimension of scrolling to look for; `x`, `y` or omit for either\n * @return {HTMLElement} Closest scrollable container\n */\nOO.ui.Element.static.getClosestScrollableContainer = function ( el, dimension ) {\n\tvar i, val,\n\t\t// Browsers do not correctly return the computed value of 'overflow' when 'overflow-x' and\n\t\t// 'overflow-y' have different values, so we need to check the separate properties.\n\t\tprops = [ 'overflow-x', 'overflow-y' ],\n\t\t$parent = $( el ).parent();\n\n\tif ( dimension === 'x' || dimension === 'y' ) {\n\t\tprops = [ 'overflow-' + dimension ];\n\t}\n\n\t// Special case for the document root (which doesn't really have any scrollable container,\n\t// since it is the ultimate scrollable container, but this is probably saner than null or\n\t// exception).\n\tif ( $( el ).is( 'html, body' ) ) {\n\t\treturn this.getRootScrollableElement( el );\n\t}\n\n\twhile ( $parent.length ) {\n\t\tif ( $parent[ 0 ] === this.getRootScrollableElement( el ) ) {\n\t\t\treturn $parent[ 0 ];\n\t\t}\n\t\ti = props.length;\n\t\twhile ( i-- ) {\n\t\t\tval = $parent.css( props[ i ] );\n\t\t\t// We assume that elements with 'overflow' (in any direction) set to 'hidden' will\n\t\t\t// never be scrolled in that direction, but they can actually be scrolled\n\t\t\t// programatically. The user can unintentionally perform a scroll in such case even if\n\t\t\t// the application doesn't scroll programatically, e.g. when jumping to an anchor, or\n\t\t\t// when using built-in find functionality.\n\t\t\t// This could cause funny issues...\n\t\t\tif ( val === 'auto' || val === 'scroll' ) {\n\t\t\t\treturn $parent[ 0 ];\n\t\t\t}\n\t\t}\n\t\t$parent = $parent.parent();\n\t}\n\t// The element is unattached... return something mostly sane\n\treturn this.getRootScrollableElement( el );\n};\n\n/**\n * Scroll element into view.\n *\n * @static\n * @param {HTMLElement|Object} elOrPosition Element to scroll into view\n * @param {Object} [config] Configuration options\n * @param {string} [config.animate=true] Animate to the new scroll offset.\n * @param {string} [config.duration='fast'] jQuery animation duration value\n * @param {string} [config.direction] Scroll in only one direction, e.g. 'x' or 'y', omit\n *  to scroll in both directions\n * @param {Object} [config.padding] Additional padding on the container to scroll past.\n *  Object containing any of 'top', 'bottom', 'left', or 'right' as numbers.\n * @param {Object} [config.scrollContainer] Scroll container. Defaults to\n *  getClosestScrollableContainer of the element.\n * @return {jQuery.Promise} Promise which resolves when the scroll is complete\n */\nOO.ui.Element.static.scrollIntoView = function ( elOrPosition, config ) {\n\tvar position, animations, container, $container, elementPosition, containerDimensions,\n\t\t$window, padding, animate, method,\n\t\tdeferred = $.Deferred();\n\n\t// Configuration initialization\n\tconfig = config || {};\n\n\tpadding = $.extend( {\n\t\ttop: 0,\n\t\tbottom: 0,\n\t\tleft: 0,\n\t\tright: 0\n\t}, config.padding );\n\n\tanimate = config.animate !== false;\n\n\tanimations = {};\n\telementPosition = elOrPosition instanceof HTMLElement ?\n\t\tthis.getDimensions( elOrPosition ).rect :\n\t\telOrPosition;\n\tcontainer = config.scrollContainer || (\n\t\telOrPosition instanceof HTMLElement ?\n\t\t\tthis.getClosestScrollableContainer( elOrPosition, config.direction ) :\n\t\t\t// No scrollContainer or element\n\t\t\tthis.getClosestScrollableContainer( document.body )\n\t);\n\t$container = $( container );\n\tcontainerDimensions = this.getDimensions( container );\n\t$window = $( this.getWindow( container ) );\n\n\t// Compute the element's position relative to the container\n\tif ( $container.is( 'html, body' ) ) {\n\t\t// If the scrollable container is the root, this is easy\n\t\tposition = {\n\t\t\ttop: elementPosition.top,\n\t\t\tbottom: $window.innerHeight() - elementPosition.bottom,\n\t\t\tleft: elementPosition.left,\n\t\t\tright: $window.innerWidth() - elementPosition.right\n\t\t};\n\t} else {\n\t\t// Otherwise, we have to subtract el's coordinates from container's coordinates\n\t\tposition = {\n\t\t\ttop: elementPosition.top -\n\t\t\t\t( containerDimensions.rect.top + containerDimensions.borders.top ),\n\t\t\tbottom: containerDimensions.rect.bottom - containerDimensions.borders.bottom -\n\t\t\t\tcontainerDimensions.scrollbar.bottom - elementPosition.bottom,\n\t\t\tleft: elementPosition.left -\n\t\t\t\t( containerDimensions.rect.left + containerDimensions.borders.left ),\n\t\t\tright: containerDimensions.rect.right - containerDimensions.borders.right -\n\t\t\t\tcontainerDimensions.scrollbar.right - elementPosition.right\n\t\t};\n\t}\n\n\tif ( !config.direction || config.direction === 'y' ) {\n\t\tif ( position.top < padding.top ) {\n\t\t\tanimations.scrollTop = containerDimensions.scroll.top + position.top - padding.top;\n\t\t} else if ( position.bottom < padding.bottom ) {\n\t\t\tanimations.scrollTop = containerDimensions.scroll.top +\n\t\t\t\t// Scroll the bottom into view, but not at the expense\n\t\t\t\t// of scrolling the top out of view\n\t\t\t\tMath.min( position.top - padding.top, -position.bottom + padding.bottom );\n\t\t}\n\t}\n\tif ( !config.direction || config.direction === 'x' ) {\n\t\tif ( position.left < padding.left ) {\n\t\t\tanimations.scrollLeft = containerDimensions.scroll.left + position.left - padding.left;\n\t\t} else if ( position.right < padding.right ) {\n\t\t\tanimations.scrollLeft = containerDimensions.scroll.left +\n\t\t\t\t// Scroll the right into view, but not at the expense\n\t\t\t\t// of scrolling the left out of view\n\t\t\t\tMath.min( position.left - padding.left, -position.right + padding.right );\n\t\t}\n\t}\n\tif ( !$.isEmptyObject( animations ) ) {\n\t\tif ( animate ) {\n\t\t\t// eslint-disable-next-line no-jquery/no-animate\n\t\t\t$container.stop( true ).animate( animations, config.duration === undefined ? 'fast' : config.duration );\n\t\t\t$container.queue( function ( next ) {\n\t\t\t\tdeferred.resolve();\n\t\t\t\tnext();\n\t\t\t} );\n\t\t} else {\n\t\t\t$container.stop( true );\n\t\t\tfor ( method in animations ) {\n\t\t\t\t$container[ method ]( animations[ method ] );\n\t\t\t}\n\t\t\tdeferred.resolve();\n\t\t}\n\t} else {\n\t\tdeferred.resolve();\n\t}\n\treturn deferred.promise();\n};\n\n/**\n * Force the browser to reconsider whether it really needs to render scrollbars inside the element\n * and reserve space for them, because it probably doesn't.\n *\n * Workaround primarily for <https://code.google.com/p/chromium/issues/detail?id=387290>, but also\n * similar bugs in other browsers. \"Just\" forcing a reflow is not sufficient in all cases, we need\n * to first actually detach (or hide, but detaching is simpler) all children, *then* force a\n * reflow, and then reattach (or show) them back.\n *\n * @static\n * @param {HTMLElement} el Element to reconsider the scrollbars on\n */\nOO.ui.Element.static.reconsiderScrollbars = function ( el ) {\n\tvar i, len, scrollLeft, scrollTop, nodes = [];\n\t// Save scroll position\n\tscrollLeft = el.scrollLeft;\n\tscrollTop = el.scrollTop;\n\t// Detach all children\n\twhile ( el.firstChild ) {\n\t\tnodes.push( el.firstChild );\n\t\tel.removeChild( el.firstChild );\n\t}\n\t// Force reflow\n\t// eslint-disable-next-line no-void\n\tvoid el.offsetHeight;\n\t// Reattach all children\n\tfor ( i = 0, len = nodes.length; i < len; i++ ) {\n\t\tel.appendChild( nodes[ i ] );\n\t}\n\t// Restore scroll position (no-op if scrollbars disappeared)\n\tel.scrollLeft = scrollLeft;\n\tel.scrollTop = scrollTop;\n};\n\n/* Methods */\n\n/**\n * Toggle visibility of an element.\n *\n * @param {boolean} [show] Make element visible, omit to toggle visibility\n * @fires visible\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.Element.prototype.toggle = function ( show ) {\n\tshow = show === undefined ? !this.visible : !!show;\n\n\tif ( show !== this.isVisible() ) {\n\t\tthis.visible = show;\n\t\tthis.$element.toggleClass( 'oo-ui-element-hidden', !this.visible );\n\t\tthis.emit( 'toggle', show );\n\t}\n\n\treturn this;\n};\n\n/**\n * Check if element is visible.\n *\n * @return {boolean} element is visible\n */\nOO.ui.Element.prototype.isVisible = function () {\n\treturn this.visible;\n};\n\n/**\n * Get element data.\n *\n * @return {Mixed} Element data\n */\nOO.ui.Element.prototype.getData = function () {\n\treturn this.data;\n};\n\n/**\n * Set element data.\n *\n * @param {Mixed} data Element data\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.Element.prototype.setData = function ( data ) {\n\tthis.data = data;\n\treturn this;\n};\n\n/**\n * Set the element has an 'id' attribute.\n *\n * @param {string} id\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.Element.prototype.setElementId = function ( id ) {\n\tthis.elementId = id;\n\tthis.$element.attr( 'id', id );\n\treturn this;\n};\n\n/**\n * Ensure that the element has an 'id' attribute, setting it to an unique value if it's missing,\n * and return its value.\n *\n * @return {string}\n */\nOO.ui.Element.prototype.getElementId = function () {\n\tif ( this.elementId === null ) {\n\t\tthis.setElementId( OO.ui.generateElementId() );\n\t}\n\treturn this.elementId;\n};\n\n/**\n * Check if element supports one or more methods.\n *\n * @param {string|string[]} methods Method or list of methods to check\n * @return {boolean} All methods are supported\n */\nOO.ui.Element.prototype.supports = function ( methods ) {\n\tvar i, len,\n\t\tsupport = 0;\n\n\tmethods = Array.isArray( methods ) ? methods : [ methods ];\n\tfor ( i = 0, len = methods.length; i < len; i++ ) {\n\t\tif ( typeof this[ methods[ i ] ] === 'function' ) {\n\t\t\tsupport++;\n\t\t}\n\t}\n\n\treturn methods.length === support;\n};\n\n/**\n * Update the theme-provided classes.\n *\n * @localdoc This is called in element mixins and widget classes any time state changes.\n *   Updating is debounced, minimizing overhead of changing multiple attributes and\n *   guaranteeing that theme updates do not occur within an element's constructor\n */\nOO.ui.Element.prototype.updateThemeClasses = function () {\n\tOO.ui.theme.queueUpdateElementClasses( this );\n};\n\n/**\n * Get the HTML tag name.\n *\n * Override this method to base the result on instance information.\n *\n * @return {string} HTML tag name\n */\nOO.ui.Element.prototype.getTagName = function () {\n\treturn this.constructor.static.tagName;\n};\n\n/**\n * Check if the element is attached to the DOM\n *\n * @return {boolean} The element is attached to the DOM\n */\nOO.ui.Element.prototype.isElementAttached = function () {\n\treturn $.contains( this.getElementDocument(), this.$element[ 0 ] );\n};\n\n/**\n * Get the DOM document.\n *\n * @return {HTMLDocument} Document object\n */\nOO.ui.Element.prototype.getElementDocument = function () {\n\t// Don't cache this in other ways either because subclasses could can change this.$element\n\treturn OO.ui.Element.static.getDocument( this.$element );\n};\n\n/**\n * Get the DOM window.\n *\n * @return {Window} Window object\n */\nOO.ui.Element.prototype.getElementWindow = function () {\n\treturn OO.ui.Element.static.getWindow( this.$element );\n};\n\n/**\n * Get closest scrollable container.\n *\n * @return {HTMLElement} Closest scrollable container\n */\nOO.ui.Element.prototype.getClosestScrollableElementContainer = function () {\n\treturn OO.ui.Element.static.getClosestScrollableContainer( this.$element[ 0 ] );\n};\n\n/**\n * Get group element is in.\n *\n * @return {OO.ui.mixin.GroupElement|null} Group element, null if none\n */\nOO.ui.Element.prototype.getElementGroup = function () {\n\treturn this.elementGroup;\n};\n\n/**\n * Set group element is in.\n *\n * @param {OO.ui.mixin.GroupElement|null} group Group element, null if none\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.Element.prototype.setElementGroup = function ( group ) {\n\tthis.elementGroup = group;\n\treturn this;\n};\n\n/**\n * Scroll element into view.\n *\n * @param {Object} [config] Configuration options\n * @return {jQuery.Promise} Promise which resolves when the scroll is complete\n */\nOO.ui.Element.prototype.scrollElementIntoView = function ( config ) {\n\tif (\n\t\t!this.isElementAttached() ||\n\t\t!this.isVisible() ||\n\t\t( this.getElementGroup() && !this.getElementGroup().isVisible() )\n\t) {\n\t\treturn $.Deferred().resolve();\n\t}\n\treturn OO.ui.Element.static.scrollIntoView( this.$element[ 0 ], config );\n};\n\n/**\n * Restore the pre-infusion dynamic state for this widget.\n *\n * This method is called after #$element has been inserted into DOM. The parameter is the return\n * value of #gatherPreInfuseState.\n *\n * @protected\n * @param {Object} state\n */\nOO.ui.Element.prototype.restorePreInfuseState = function () {\n};\n","/**\n * Wraps an HTML snippet for use with configuration values which default\n * to strings.  This bypasses the default html-escaping done to string\n * values.\n *\n * @class\n *\n * @constructor\n * @param {string} [content] HTML content\n */\nOO.ui.HtmlSnippet = function OoUiHtmlSnippet( content ) {\n\t// Properties\n\tthis.content = content;\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.HtmlSnippet );\n\n/* Methods */\n\n/**\n * Render into HTML.\n *\n * @return {string} Unchanged HTML snippet.\n */\nOO.ui.HtmlSnippet.prototype.toString = function () {\n\treturn this.content;\n};\n","/**\n * Layouts are containers for elements and are used to arrange other widgets of arbitrary type in\n * a way that is centrally controlled and can be updated dynamically. Layouts can be, and usually\n * are, combined.\n * See {@link OO.ui.FieldsetLayout FieldsetLayout}, {@link OO.ui.FieldLayout FieldLayout},\n * {@link OO.ui.FormLayout FormLayout}, {@link OO.ui.PanelLayout PanelLayout},\n * {@link OO.ui.StackLayout StackLayout}, {@link OO.ui.PageLayout PageLayout},\n * {@link OO.ui.HorizontalLayout HorizontalLayout}, and {@link OO.ui.BookletLayout BookletLayout}\n * for more information and examples.\n *\n * @abstract\n * @class\n * @extends OO.ui.Element\n * @mixins OO.EventEmitter\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.Layout = function OoUiLayout( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.Layout.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.EventEmitter.call( this );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-layout' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.Layout, OO.ui.Element );\nOO.mixinClass( OO.ui.Layout, OO.EventEmitter );\n\n/* Methods */\n\n/**\n * Reset scroll offsets\n *\n * @chainable\n * @return {OO.ui.Layout} The layout, for chaining\n */\nOO.ui.Layout.prototype.resetScroll = function () {\n\tthis.$element[ 0 ].scrollTop = 0;\n\t// TODO: Reset scrollLeft in an RTL-aware manner, see OO.ui.Element.static.getScrollLeft.\n\n\treturn this;\n};\n","/**\n * Widgets are compositions of one or more OOUI elements that users can both view\n * and interact with. All widgets can be configured and modified via a standard API,\n * and their state can change dynamically according to a model.\n *\n * @abstract\n * @class\n * @extends OO.ui.Element\n * @mixins OO.EventEmitter\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [disabled=false] Disable the widget. Disabled widgets cannot be used and their\n *  appearance reflects this state.\n */\nOO.ui.Widget = function OoUiWidget( config ) {\n\t// Initialize config\n\tconfig = $.extend( { disabled: false }, config );\n\n\t// Parent constructor\n\tOO.ui.Widget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.EventEmitter.call( this );\n\n\t// Properties\n\tthis.disabled = null;\n\tthis.wasDisabled = null;\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-widget' );\n\tthis.setDisabled( !!config.disabled );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.Widget, OO.ui.Element );\nOO.mixinClass( OO.ui.Widget, OO.EventEmitter );\n\n/* Events */\n\n/**\n * @event disable\n *\n * A 'disable' event is emitted when the disabled state of the widget changes\n * (i.e. on disable **and** enable).\n *\n * @param {boolean} disabled Widget is disabled\n */\n\n/**\n * @event toggle\n *\n * A 'toggle' event is emitted when the visibility of the widget changes.\n *\n * @param {boolean} visible Widget is visible\n */\n\n/* Methods */\n\n/**\n * Check if the widget is disabled.\n *\n * @return {boolean} Widget is disabled\n */\nOO.ui.Widget.prototype.isDisabled = function () {\n\treturn this.disabled;\n};\n\n/**\n * Set the 'disabled' state of the widget.\n *\n * When a widget is disabled, it cannot be used and its appearance is updated to reflect this state.\n *\n * @param {boolean} disabled Disable widget\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.Widget.prototype.setDisabled = function ( disabled ) {\n\tvar isDisabled;\n\n\tthis.disabled = !!disabled;\n\tisDisabled = this.isDisabled();\n\tif ( isDisabled !== this.wasDisabled ) {\n\t\tthis.$element.toggleClass( 'oo-ui-widget-disabled', isDisabled );\n\t\tthis.$element.toggleClass( 'oo-ui-widget-enabled', !isDisabled );\n\t\tthis.$element.attr( 'aria-disabled', isDisabled.toString() );\n\t\tthis.emit( 'disable', isDisabled );\n\t\tthis.updateThemeClasses();\n\t}\n\tthis.wasDisabled = isDisabled;\n\n\treturn this;\n};\n\n/**\n * Update the disabled state, in case of changes in parent widget.\n *\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.Widget.prototype.updateDisabled = function () {\n\tthis.setDisabled( this.disabled );\n\treturn this;\n};\n\n/**\n * Get an ID of a labelable node which is part of this widget, if any, to be used for `<label for>`\n * value.\n *\n * If this function returns null, the widget should have a meaningful #simulateLabelClick method\n * instead.\n *\n * @return {string|null} The ID of the labelable element\n */\nOO.ui.Widget.prototype.getInputId = function () {\n\treturn null;\n};\n\n/**\n * Simulate the behavior of clicking on a label (a HTML `<label>` element) bound to this input.\n * HTML only allows `<label>` to act on specific \"labelable\" elements; complex widgets might need to\n * override this method to provide intuitive, accessible behavior.\n *\n * By default, this does nothing. OO.ui.mixin.TabIndexedElement overrides it for focusable widgets.\n * Individual widgets may override it too.\n *\n * This method is called by OO.ui.LabelWidget and OO.ui.FieldLayout. It should not be called\n * directly.\n */\nOO.ui.Widget.prototype.simulateLabelClick = function () {\n};\n","/**\n * Theme logic.\n *\n * @abstract\n * @class\n *\n * @constructor\n */\nOO.ui.Theme = function OoUiTheme() {\n\tthis.elementClassesQueue = [];\n\tthis.debouncedUpdateQueuedElementClasses = OO.ui.debounce( this.updateQueuedElementClasses );\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.Theme );\n\n/* Methods */\n\n/**\n * Get a list of classes to be applied to a widget.\n *\n * The 'on' and 'off' lists combined MUST contain keys for all classes the theme adds or removes,\n * otherwise state transitions will not work properly.\n *\n * @param {OO.ui.Element} element Element for which to get classes\n * @return {Object.<string,string[]>} Categorized class names with `on` and `off` lists\n */\nOO.ui.Theme.prototype.getElementClasses = function () {\n\treturn { on: [], off: [] };\n};\n\n/**\n * Update CSS classes provided by the theme.\n *\n * For elements with theme logic hooks, this should be called any time there's a state change.\n *\n * @param {OO.ui.Element} element Element for which to update classes\n */\nOO.ui.Theme.prototype.updateElementClasses = function ( element ) {\n\tvar $elements = $( [] ),\n\t\tclasses = this.getElementClasses( element );\n\n\tif ( element.$icon ) {\n\t\t$elements = $elements.add( element.$icon );\n\t}\n\tif ( element.$indicator ) {\n\t\t$elements = $elements.add( element.$indicator );\n\t}\n\n\t$elements\n\t\t.removeClass( classes.off )\n\t\t.addClass( classes.on );\n};\n\n/**\n * @private\n */\nOO.ui.Theme.prototype.updateQueuedElementClasses = function () {\n\tvar i;\n\tfor ( i = 0; i < this.elementClassesQueue.length; i++ ) {\n\t\tthis.updateElementClasses( this.elementClassesQueue[ i ] );\n\t}\n\t// Clear the queue\n\tthis.elementClassesQueue = [];\n};\n\n/**\n * Queue #updateElementClasses to be called for this element.\n *\n * @localdoc QUnit tests override this method to directly call #queueUpdateElementClasses,\n *   to make them synchronous.\n *\n * @param {OO.ui.Element} element Element for which to update classes\n */\nOO.ui.Theme.prototype.queueUpdateElementClasses = function ( element ) {\n\t// Keep items in the queue unique. Use lastIndexOf to start checking from the end because that's\n\t// the most common case (this method is often called repeatedly for the same element).\n\tif ( this.elementClassesQueue.lastIndexOf( element ) !== -1 ) {\n\t\treturn;\n\t}\n\tthis.elementClassesQueue.push( element );\n\tthis.debouncedUpdateQueuedElementClasses();\n};\n\n/**\n * Get the transition duration in milliseconds for dialogs opening/closing\n *\n * The dialog should be fully rendered this many milliseconds after the\n * ready process has executed.\n *\n * @return {number} Transition duration in milliseconds\n */\nOO.ui.Theme.prototype.getDialogTransitionDuration = function () {\n\treturn 0;\n};\n","/**\n * The TabIndexedElement class is an attribute mixin used to add additional functionality to an\n * element created by another class. The mixin provides a ‘tabIndex’ property, which specifies the\n * order in which users will navigate through the focusable elements via the Tab key.\n *\n *     @example\n *     // TabIndexedElement is mixed into the ButtonWidget class\n *     // to provide a tabIndex property.\n *     var button1 = new OO.ui.ButtonWidget( {\n *             label: 'fourth',\n *             tabIndex: 4\n *         } ),\n *         button2 = new OO.ui.ButtonWidget( {\n *             label: 'second',\n *             tabIndex: 2\n *         } ),\n *         button3 = new OO.ui.ButtonWidget( {\n *             label: 'third',\n *             tabIndex: 3\n *         } ),\n *         button4 = new OO.ui.ButtonWidget( {\n *             label: 'first',\n *             tabIndex: 1\n *         } );\n *     $( document.body ).append(\n *         button1.$element,\n *         button2.$element,\n *         button3.$element,\n *         button4.$element\n *      );\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$tabIndexed] The element that should use the tabindex functionality. By default,\n *  the functionality is applied to the element created by the class ($element). If a different\n *  element is specified, the tabindex functionality will be applied to it instead.\n * @cfg {string|number|null} [tabIndex=0] Number that specifies the element’s position in the\n *  tab-navigation order (e.g., 1 for the first focusable element). Use 0 to use the default\n *  navigation order; use -1 to remove the element from the tab-navigation flow.\n */\nOO.ui.mixin.TabIndexedElement = function OoUiMixinTabIndexedElement( config ) {\n\t// Configuration initialization\n\tconfig = $.extend( { tabIndex: 0 }, config );\n\n\t// Properties\n\tthis.$tabIndexed = null;\n\tthis.tabIndex = null;\n\n\t// Events\n\tthis.connect( this, {\n\t\tdisable: 'onTabIndexedElementDisable'\n\t} );\n\n\t// Initialization\n\tthis.setTabIndex( config.tabIndex );\n\tthis.setTabIndexedElement( config.$tabIndexed || this.$element );\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.mixin.TabIndexedElement );\n\n/* Methods */\n\n/**\n * Set the element that should use the tabindex functionality.\n *\n * This method is used to retarget a tabindex mixin so that its functionality applies\n * to the specified element. If an element is currently using the functionality, the mixin’s\n * effect on that element is removed before the new element is set up.\n *\n * @param {jQuery} $tabIndexed Element that should use the tabindex functionality\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.TabIndexedElement.prototype.setTabIndexedElement = function ( $tabIndexed ) {\n\tvar tabIndex = this.tabIndex;\n\t// Remove attributes from old $tabIndexed\n\tthis.setTabIndex( null );\n\t// Force update of new $tabIndexed\n\tthis.$tabIndexed = $tabIndexed;\n\tthis.tabIndex = tabIndex;\n\treturn this.updateTabIndex();\n};\n\n/**\n * Set the value of the tabindex.\n *\n * @param {string|number|null} tabIndex Tabindex value, or `null` for no tabindex\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.TabIndexedElement.prototype.setTabIndex = function ( tabIndex ) {\n\ttabIndex = /^-?\\d+$/.test( tabIndex ) ? Number( tabIndex ) : null;\n\n\tif ( this.tabIndex !== tabIndex ) {\n\t\tthis.tabIndex = tabIndex;\n\t\tthis.updateTabIndex();\n\t}\n\n\treturn this;\n};\n\n/**\n * Update the `tabindex` attribute, in case of changes to tab index or\n * disabled state.\n *\n * @private\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.TabIndexedElement.prototype.updateTabIndex = function () {\n\tif ( this.$tabIndexed ) {\n\t\tif ( this.tabIndex !== null ) {\n\t\t\t// Do not index over disabled elements\n\t\t\tthis.$tabIndexed.attr( {\n\t\t\t\ttabindex: this.isDisabled() ? -1 : this.tabIndex,\n\t\t\t\t// Support: ChromeVox and NVDA\n\t\t\t\t// These do not seem to inherit aria-disabled from parent elements\n\t\t\t\t'aria-disabled': this.isDisabled().toString()\n\t\t\t} );\n\t\t} else {\n\t\t\tthis.$tabIndexed.removeAttr( 'tabindex aria-disabled' );\n\t\t}\n\t}\n\treturn this;\n};\n\n/**\n * Handle disable events.\n *\n * @private\n * @param {boolean} disabled Element is disabled\n */\nOO.ui.mixin.TabIndexedElement.prototype.onTabIndexedElementDisable = function () {\n\tthis.updateTabIndex();\n};\n\n/**\n * Get the value of the tabindex.\n *\n * @return {number|null} Tabindex value\n */\nOO.ui.mixin.TabIndexedElement.prototype.getTabIndex = function () {\n\treturn this.tabIndex;\n};\n\n/**\n * Get an ID of a focusable element of this widget, if any, to be used for `<label for>` value.\n *\n * If the element already has an ID then that is returned, otherwise unique ID is\n * generated, set on the element, and returned.\n *\n * @return {string|null} The ID of the focusable element\n */\nOO.ui.mixin.TabIndexedElement.prototype.getInputId = function () {\n\tvar id;\n\n\tif ( !this.$tabIndexed ) {\n\t\treturn null;\n\t}\n\tif ( !this.isLabelableNode( this.$tabIndexed ) ) {\n\t\treturn null;\n\t}\n\n\tid = this.$tabIndexed.attr( 'id' );\n\tif ( id === undefined ) {\n\t\tid = OO.ui.generateElementId();\n\t\tthis.$tabIndexed.attr( 'id', id );\n\t}\n\n\treturn id;\n};\n\n/**\n * Whether the node is 'labelable' according to the HTML spec\n * (i.e., whether it can be interacted with through a `<label for=\"…\">`).\n * See: <https://html.spec.whatwg.org/multipage/forms.html#category-label>.\n *\n * @private\n * @param {jQuery} $node\n * @return {boolean}\n */\nOO.ui.mixin.TabIndexedElement.prototype.isLabelableNode = function ( $node ) {\n\tvar\n\t\tlabelableTags = [ 'button', 'meter', 'output', 'progress', 'select', 'textarea' ],\n\t\ttagName = ( $node.prop( 'tagName' ) || '' ).toLowerCase();\n\n\tif ( tagName === 'input' && $node.attr( 'type' ) !== 'hidden' ) {\n\t\treturn true;\n\t}\n\tif ( labelableTags.indexOf( tagName ) !== -1 ) {\n\t\treturn true;\n\t}\n\treturn false;\n};\n\n/**\n * Focus this element.\n *\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.TabIndexedElement.prototype.focus = function () {\n\tif ( !this.isDisabled() ) {\n\t\tthis.$tabIndexed.trigger( 'focus' );\n\t}\n\treturn this;\n};\n\n/**\n * Blur this element.\n *\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.TabIndexedElement.prototype.blur = function () {\n\tthis.$tabIndexed.trigger( 'blur' );\n\treturn this;\n};\n\n/**\n * @inheritdoc OO.ui.Widget\n */\nOO.ui.mixin.TabIndexedElement.prototype.simulateLabelClick = function () {\n\tthis.focus();\n};\n","/**\n * ButtonElement is often mixed into other classes to generate a button, which is a clickable\n * interface element that can be configured with access keys for keyboard interaction.\n * See the [OOUI documentation on MediaWiki] [1] for examples.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Buttons_and_Switches#Buttons\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$button] The button element created by the class.\n *  If this configuration is omitted, the button element will use a generated `<a>`.\n * @cfg {boolean} [framed=true] Render the button with a frame\n */\nOO.ui.mixin.ButtonElement = function OoUiMixinButtonElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.$button = null;\n\tthis.framed = null;\n\tthis.active = config.active !== undefined && config.active;\n\tthis.onDocumentMouseUpHandler = this.onDocumentMouseUp.bind( this );\n\tthis.onMouseDownHandler = this.onMouseDown.bind( this );\n\tthis.onDocumentKeyUpHandler = this.onDocumentKeyUp.bind( this );\n\tthis.onKeyDownHandler = this.onKeyDown.bind( this );\n\tthis.onClickHandler = this.onClick.bind( this );\n\tthis.onKeyPressHandler = this.onKeyPress.bind( this );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-buttonElement' );\n\tthis.toggleFramed( config.framed === undefined || config.framed );\n\tthis.setButtonElement( config.$button || $( '<a>' ) );\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.mixin.ButtonElement );\n\n/* Static Properties */\n\n/**\n * Cancel mouse down events.\n *\n * This property is usually set to `true` to prevent the focus from changing when the button is\n * clicked.\n * Classes such as {@link OO.ui.mixin.DraggableElement DraggableElement} and\n * {@link OO.ui.ButtonOptionWidget ButtonOptionWidget} use a value of `false` so that dragging\n * behavior is possible and mousedown events can be handled by a parent widget.\n *\n * @static\n * @inheritable\n * @property {boolean}\n */\nOO.ui.mixin.ButtonElement.static.cancelButtonMouseDownEvents = true;\n\n/* Events */\n\n/**\n * A 'click' event is emitted when the button element is clicked.\n *\n * @event click\n */\n\n/* Methods */\n\n/**\n * Set the button element.\n *\n * This method is used to retarget a button mixin so that its functionality applies to\n * the specified button element instead of the one created by the class. If a button element\n * is already set, the method will remove the mixin’s effect on that element.\n *\n * @param {jQuery} $button Element to use as button\n */\nOO.ui.mixin.ButtonElement.prototype.setButtonElement = function ( $button ) {\n\tif ( this.$button ) {\n\t\tthis.$button\n\t\t\t.removeClass( 'oo-ui-buttonElement-button' )\n\t\t\t.removeAttr( 'role accesskey' )\n\t\t\t.off( {\n\t\t\t\tmousedown: this.onMouseDownHandler,\n\t\t\t\tkeydown: this.onKeyDownHandler,\n\t\t\t\tclick: this.onClickHandler,\n\t\t\t\tkeypress: this.onKeyPressHandler\n\t\t\t} );\n\t}\n\n\tthis.$button = $button\n\t\t.addClass( 'oo-ui-buttonElement-button' )\n\t\t.on( {\n\t\t\tmousedown: this.onMouseDownHandler,\n\t\t\tkeydown: this.onKeyDownHandler,\n\t\t\tclick: this.onClickHandler,\n\t\t\tkeypress: this.onKeyPressHandler\n\t\t} );\n\n\t// Add `role=\"button\"` on `<a>` elements, where it's needed\n\t// `toUpperCase()` is added for XHTML documents\n\tif ( this.$button.prop( 'tagName' ).toUpperCase() === 'A' ) {\n\t\tthis.$button.attr( 'role', 'button' );\n\t}\n};\n\n/**\n * Handles mouse down events.\n *\n * @protected\n * @param {jQuery.Event} e Mouse down event\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.mixin.ButtonElement.prototype.onMouseDown = function ( e ) {\n\tif ( this.isDisabled() || e.which !== OO.ui.MouseButtons.LEFT ) {\n\t\treturn;\n\t}\n\tthis.$element.addClass( 'oo-ui-buttonElement-pressed' );\n\t// Run the mouseup handler no matter where the mouse is when the button is let go, so we can\n\t// reliably remove the pressed class\n\tthis.getElementDocument().addEventListener( 'mouseup', this.onDocumentMouseUpHandler, true );\n\t// Prevent change of focus unless specifically configured otherwise\n\tif ( this.constructor.static.cancelButtonMouseDownEvents ) {\n\t\treturn false;\n\t}\n};\n\n/**\n * Handles document mouse up events.\n *\n * @protected\n * @param {MouseEvent} e Mouse up event\n */\nOO.ui.mixin.ButtonElement.prototype.onDocumentMouseUp = function ( e ) {\n\tif ( this.isDisabled() || e.which !== OO.ui.MouseButtons.LEFT ) {\n\t\treturn;\n\t}\n\tthis.$element.removeClass( 'oo-ui-buttonElement-pressed' );\n\t// Stop listening for mouseup, since we only needed this once\n\tthis.getElementDocument().removeEventListener( 'mouseup', this.onDocumentMouseUpHandler, true );\n};\n\n/**\n * Handles mouse click events.\n *\n * @protected\n * @param {jQuery.Event} e Mouse click event\n * @fires click\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.mixin.ButtonElement.prototype.onClick = function ( e ) {\n\tif ( !this.isDisabled() && e.which === OO.ui.MouseButtons.LEFT ) {\n\t\tif ( this.emit( 'click' ) ) {\n\t\t\treturn false;\n\t\t}\n\t}\n};\n\n/**\n * Handles key down events.\n *\n * @protected\n * @param {jQuery.Event} e Key down event\n */\nOO.ui.mixin.ButtonElement.prototype.onKeyDown = function ( e ) {\n\tif ( this.isDisabled() || ( e.which !== OO.ui.Keys.SPACE && e.which !== OO.ui.Keys.ENTER ) ) {\n\t\treturn;\n\t}\n\tthis.$element.addClass( 'oo-ui-buttonElement-pressed' );\n\t// Run the keyup handler no matter where the key is when the button is let go, so we can\n\t// reliably remove the pressed class\n\tthis.getElementDocument().addEventListener( 'keyup', this.onDocumentKeyUpHandler, true );\n};\n\n/**\n * Handles document key up events.\n *\n * @protected\n * @param {KeyboardEvent} e Key up event\n */\nOO.ui.mixin.ButtonElement.prototype.onDocumentKeyUp = function ( e ) {\n\tif ( this.isDisabled() || ( e.which !== OO.ui.Keys.SPACE && e.which !== OO.ui.Keys.ENTER ) ) {\n\t\treturn;\n\t}\n\tthis.$element.removeClass( 'oo-ui-buttonElement-pressed' );\n\t// Stop listening for keyup, since we only needed this once\n\tthis.getElementDocument().removeEventListener( 'keyup', this.onDocumentKeyUpHandler, true );\n};\n\n/**\n * Handles key press events.\n *\n * @protected\n * @param {jQuery.Event} e Key press event\n * @fires click\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.mixin.ButtonElement.prototype.onKeyPress = function ( e ) {\n\tif ( !this.isDisabled() && ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER ) ) {\n\t\tif ( this.emit( 'click' ) ) {\n\t\t\treturn false;\n\t\t}\n\t}\n};\n\n/**\n * Check if button has a frame.\n *\n * @return {boolean} Button is framed\n */\nOO.ui.mixin.ButtonElement.prototype.isFramed = function () {\n\treturn this.framed;\n};\n\n/**\n * Render the button with or without a frame. Omit the `framed` parameter to toggle the button frame\n * on and off.\n *\n * @param {boolean} [framed] Make button framed, omit to toggle\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.ButtonElement.prototype.toggleFramed = function ( framed ) {\n\tframed = framed === undefined ? !this.framed : !!framed;\n\tif ( framed !== this.framed ) {\n\t\tthis.framed = framed;\n\t\tthis.$element\n\t\t\t.toggleClass( 'oo-ui-buttonElement-frameless', !framed )\n\t\t\t.toggleClass( 'oo-ui-buttonElement-framed', framed );\n\t\tthis.updateThemeClasses();\n\t}\n\n\treturn this;\n};\n\n/**\n * Set the button's active state.\n *\n * The active state can be set on:\n *\n *  - {@link OO.ui.ButtonOptionWidget ButtonOptionWidget} when it is selected\n *  - {@link OO.ui.ToggleButtonWidget ToggleButtonWidget} when it is toggle on\n *  - {@link OO.ui.ButtonWidget ButtonWidget} when clicking the button would only refresh the page\n *\n * @protected\n * @param {boolean} value Make button active\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.ButtonElement.prototype.setActive = function ( value ) {\n\tthis.active = !!value;\n\tthis.$element.toggleClass( 'oo-ui-buttonElement-active', this.active );\n\tthis.updateThemeClasses();\n\treturn this;\n};\n\n/**\n * Check if the button is active\n *\n * @protected\n * @return {boolean} The button is active\n */\nOO.ui.mixin.ButtonElement.prototype.isActive = function () {\n\treturn this.active;\n};\n","/**\n * Any OOUI widget that contains other widgets (such as {@link OO.ui.ButtonWidget buttons} or\n * {@link OO.ui.OptionWidget options}) mixes in GroupElement. Adding, removing, and clearing\n * items from the group is done through the interface the class provides.\n * For more information, please see the [OOUI documentation on MediaWiki] [1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Elements/Groups\n *\n * @abstract\n * @mixins OO.EmitterList\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$group] The container element created by the class. If this configuration\n *  is omitted, the group element will use a generated `<div>`.\n */\nOO.ui.mixin.GroupElement = function OoUiMixinGroupElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Mixin constructors\n\tOO.EmitterList.call( this, config );\n\n\t// Properties\n\tthis.$group = null;\n\n\t// Initialization\n\tthis.setGroupElement( config.$group || $( '<div>' ) );\n};\n\n/* Setup */\n\nOO.mixinClass( OO.ui.mixin.GroupElement, OO.EmitterList );\n\n/* Events */\n\n/**\n * @event change\n *\n * A change event is emitted when the set of selected items changes.\n *\n * @param {OO.ui.Element[]} items Items currently in the group\n */\n\n/* Methods */\n\n/**\n * Set the group element.\n *\n * If an element is already set, items will be moved to the new element.\n *\n * @param {jQuery} $group Element to use as group\n */\nOO.ui.mixin.GroupElement.prototype.setGroupElement = function ( $group ) {\n\tvar i, len;\n\n\tthis.$group = $group;\n\tfor ( i = 0, len = this.items.length; i < len; i++ ) {\n\t\tthis.$group.append( this.items[ i ].$element );\n\t}\n};\n\n/**\n * Find an item by its data.\n *\n * Only the first item with matching data will be returned. To return all matching items,\n * use the #findItemsFromData method.\n *\n * @param {Object} data Item data to search for\n * @return {OO.ui.Element|null} Item with equivalent data, `null` if none exists\n */\nOO.ui.mixin.GroupElement.prototype.findItemFromData = function ( data ) {\n\tvar i, len, item,\n\t\thash = OO.getHash( data );\n\n\tfor ( i = 0, len = this.items.length; i < len; i++ ) {\n\t\titem = this.items[ i ];\n\t\tif ( hash === OO.getHash( item.getData() ) ) {\n\t\t\treturn item;\n\t\t}\n\t}\n\n\treturn null;\n};\n\n/**\n * Find items by their data.\n *\n * All items with matching data will be returned. To return only the first match, use the\n * #findItemFromData method instead.\n *\n * @param {Object} data Item data to search for\n * @return {OO.ui.Element[]} Items with equivalent data\n */\nOO.ui.mixin.GroupElement.prototype.findItemsFromData = function ( data ) {\n\tvar i, len, item,\n\t\thash = OO.getHash( data ),\n\t\titems = [];\n\n\tfor ( i = 0, len = this.items.length; i < len; i++ ) {\n\t\titem = this.items[ i ];\n\t\tif ( hash === OO.getHash( item.getData() ) ) {\n\t\t\titems.push( item );\n\t\t}\n\t}\n\n\treturn items;\n};\n\n/**\n * Add items to the group.\n *\n * Items will be added to the end of the group array unless the optional `index` parameter\n * specifies a different insertion point. Adding an existing item will move it to the end of the\n * array or the point specified by the `index`.\n *\n * @param {OO.ui.Element[]} items An array of items to add to the group\n * @param {number} [index] Index of the insertion point\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.GroupElement.prototype.addItems = function ( items, index ) {\n\n\tif ( items.length === 0 ) {\n\t\treturn this;\n\t}\n\n\t// Mixin method\n\tOO.EmitterList.prototype.addItems.call( this, items, index );\n\n\tthis.emit( 'change', this.getItems() );\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.mixin.GroupElement.prototype.moveItem = function ( items, newIndex ) {\n\t// insertItemElements expects this.items to not have been modified yet, so call before the mixin\n\tthis.insertItemElements( items, newIndex );\n\n\t// Mixin method\n\tnewIndex = OO.EmitterList.prototype.moveItem.call( this, items, newIndex );\n\n\treturn newIndex;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.mixin.GroupElement.prototype.insertItem = function ( item, index ) {\n\titem.setElementGroup( this );\n\tthis.insertItemElements( item, index );\n\n\t// Mixin method\n\tindex = OO.EmitterList.prototype.insertItem.call( this, item, index );\n\n\treturn index;\n};\n\n/**\n * Insert elements into the group\n *\n * @private\n * @param {OO.ui.Element} itemWidget Item to insert\n * @param {number} index Insertion index\n */\nOO.ui.mixin.GroupElement.prototype.insertItemElements = function ( itemWidget, index ) {\n\tif ( index === undefined || index < 0 || index >= this.items.length ) {\n\t\tthis.$group.append( itemWidget.$element );\n\t} else if ( index === 0 ) {\n\t\tthis.$group.prepend( itemWidget.$element );\n\t} else {\n\t\tthis.items[ index ].$element.before( itemWidget.$element );\n\t}\n};\n\n/**\n * Remove the specified items from a group.\n *\n * Removed items are detached (not removed) from the DOM so that they may be reused.\n * To remove all items from a group, you may wish to use the #clearItems method instead.\n *\n * @param {OO.ui.Element[]} items An array of items to remove\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.GroupElement.prototype.removeItems = function ( items ) {\n\tvar i, len, item, index;\n\n\tif ( items.length === 0 ) {\n\t\treturn this;\n\t}\n\n\t// Remove specific items elements\n\tfor ( i = 0, len = items.length; i < len; i++ ) {\n\t\titem = items[ i ];\n\t\tindex = this.items.indexOf( item );\n\t\tif ( index !== -1 ) {\n\t\t\titem.setElementGroup( null );\n\t\t\titem.$element.detach();\n\t\t}\n\t}\n\n\t// Mixin method\n\tOO.EmitterList.prototype.removeItems.call( this, items );\n\n\tthis.emit( 'change', this.getItems() );\n\treturn this;\n};\n\n/**\n * Clear all items from the group.\n *\n * Cleared items are detached from the DOM, not removed, so that they may be reused.\n * To remove only a subset of items from a group, use the #removeItems method.\n *\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.GroupElement.prototype.clearItems = function () {\n\tvar i, len;\n\n\t// Remove all item elements\n\tfor ( i = 0, len = this.items.length; i < len; i++ ) {\n\t\tthis.items[ i ].setElementGroup( null );\n\t\tthis.items[ i ].$element.detach();\n\t}\n\n\t// Mixin method\n\tOO.EmitterList.prototype.clearItems.call( this );\n\n\tthis.emit( 'change', this.getItems() );\n\treturn this;\n};\n","/**\n * LabelElement is often mixed into other classes to generate a label, which\n * helps identify the function of an interface element.\n * See the [OOUI documentation on MediaWiki] [1] for more information.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Icons,_Indicators,_and_Labels#Labels\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$label] The label element created by the class. If this\n *  configuration is omitted, the label element will use a generated `<span>`.\n * @cfg {jQuery|string|Function|OO.ui.HtmlSnippet} [label] The label text. The label can be\n *  specified as a plaintext string, a jQuery selection of elements, or a function that will\n *  produce a string in the future. See the [OOUI documentation on MediaWiki] [2] for examples.\n *  [2]: https://www.mediawiki.org/wiki/OOUI/Widgets/Icons,_Indicators,_and_Labels#Labels\n * @cfg {boolean} [invisibleLabel] Whether the label should be visually hidden (but still\n *  accessible to screen-readers).\n */\nOO.ui.mixin.LabelElement = function OoUiMixinLabelElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.$label = null;\n\tthis.label = null;\n\tthis.invisibleLabel = null;\n\n\t// Initialization\n\tthis.setLabel( config.label || this.constructor.static.label );\n\tthis.setLabelElement( config.$label || $( '<span>' ) );\n\tthis.setInvisibleLabel( config.invisibleLabel );\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.mixin.LabelElement );\n\n/* Events */\n\n/**\n * @event labelChange\n * @param {string} value\n */\n\n/* Static Properties */\n\n/**\n * The label text. The label can be specified as a plaintext string, a function that will\n * produce a string in the future, or `null` for no label. The static value will\n * be overridden if a label is specified with the #label config option.\n *\n * @static\n * @inheritable\n * @property {string|Function|null}\n */\nOO.ui.mixin.LabelElement.static.label = null;\n\n/* Static methods */\n\n/**\n * Highlight the first occurrence of the query in the given text\n *\n * @param {string} text Text\n * @param {string} query Query to find\n * @param {Function} [compare] Optional string comparator, e.g. Intl.Collator().compare\n * @return {jQuery} Text with the first match of the query\n *  sub-string wrapped in highlighted span\n */\nOO.ui.mixin.LabelElement.static.highlightQuery = function ( text, query, compare ) {\n\tvar i, tLen, qLen,\n\t\toffset = -1,\n\t\t$result = $( '<span>' );\n\n\tif ( compare ) {\n\t\ttLen = text.length;\n\t\tqLen = query.length;\n\t\tfor ( i = 0; offset === -1 && i <= tLen - qLen; i++ ) {\n\t\t\tif ( compare( query, text.slice( i, i + qLen ) ) === 0 ) {\n\t\t\t\toffset = i;\n\t\t\t}\n\t\t}\n\t} else {\n\t\toffset = text.toLowerCase().indexOf( query.toLowerCase() );\n\t}\n\n\tif ( !query.length || offset === -1 ) {\n\t\t$result.text( text );\n\t} else {\n\t\t$result.append(\n\t\t\tdocument.createTextNode( text.slice( 0, offset ) ),\n\t\t\t$( '<span>' )\n\t\t\t\t.addClass( 'oo-ui-labelElement-label-highlight' )\n\t\t\t\t.text( text.slice( offset, offset + query.length ) ),\n\t\t\tdocument.createTextNode( text.slice( offset + query.length ) )\n\t\t);\n\t}\n\treturn $result.contents();\n};\n\n/* Methods */\n\n/**\n * Set the label element.\n *\n * If an element is already set, it will be cleaned up before setting up the new element.\n *\n * @param {jQuery} $label Element to use as label\n */\nOO.ui.mixin.LabelElement.prototype.setLabelElement = function ( $label ) {\n\tif ( this.$label ) {\n\t\tthis.$label.removeClass( 'oo-ui-labelElement-label' ).empty();\n\t}\n\n\tthis.$label = $label.addClass( 'oo-ui-labelElement-label' );\n\tthis.setLabelContent( this.label );\n};\n\n/**\n * Set the label.\n *\n * An empty string will result in the label being hidden. A string containing only whitespace will\n * be converted to a single `&nbsp;`.\n *\n * @param {jQuery|string|OO.ui.HtmlSnippet|Function|null} label Label nodes; text; a function that\n *  returns nodes or text; or null for no label\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.LabelElement.prototype.setLabel = function ( label ) {\n\tlabel = typeof label === 'function' ? OO.ui.resolveMsg( label ) : label;\n\tlabel = ( ( typeof label === 'string' || label instanceof $ ) && label.length ) || ( label instanceof OO.ui.HtmlSnippet && label.toString().length ) ? label : null;\n\n\tif ( this.label !== label ) {\n\t\tif ( this.$label ) {\n\t\t\tthis.setLabelContent( label );\n\t\t}\n\t\tthis.label = label;\n\t\tthis.emit( 'labelChange' );\n\t}\n\n\tthis.$element.toggleClass( 'oo-ui-labelElement', !!this.label && !this.invisibleLabel );\n\n\treturn this;\n};\n\n/**\n * Set whether the label should be visually hidden (but still accessible to screen-readers).\n *\n * @param {boolean} invisibleLabel\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.LabelElement.prototype.setInvisibleLabel = function ( invisibleLabel ) {\n\tinvisibleLabel = !!invisibleLabel;\n\n\tif ( this.invisibleLabel !== invisibleLabel ) {\n\t\tthis.invisibleLabel = invisibleLabel;\n\t\tthis.emit( 'labelChange' );\n\t}\n\n\tthis.$label.toggleClass( 'oo-ui-labelElement-invisible', this.invisibleLabel );\n\t// Pretend that there is no label, a lot of CSS has been written with this assumption\n\tthis.$element.toggleClass( 'oo-ui-labelElement', !!this.label && !this.invisibleLabel );\n\n\treturn this;\n};\n\n/**\n * Set the label as plain text with a highlighted query\n *\n * @param {string} text Text label to set\n * @param {string} query Substring of text to highlight\n * @param {Function} [compare] Optional string comparator, e.g. Intl.Collator().compare\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.LabelElement.prototype.setHighlightedQuery = function ( text, query, compare ) {\n\treturn this.setLabel( this.constructor.static.highlightQuery( text, query, compare ) );\n};\n\n/**\n * Get the label.\n *\n * @return {jQuery|string|Function|null} Label nodes; text; a function that returns nodes or\n *  text; or null for no label\n */\nOO.ui.mixin.LabelElement.prototype.getLabel = function () {\n\treturn this.label;\n};\n\n/**\n * Set the content of the label.\n *\n * Do not call this method until after the label element has been set by #setLabelElement.\n *\n * @private\n * @param {jQuery|string|Function|null} label Label nodes; text; a function that returns nodes or\n *  text; or null for no label\n */\nOO.ui.mixin.LabelElement.prototype.setLabelContent = function ( label ) {\n\tif ( typeof label === 'string' ) {\n\t\tif ( label.match( /^\\s*$/ ) ) {\n\t\t\t// Convert whitespace only string to a single non-breaking space\n\t\t\tthis.$label.html( '&nbsp;' );\n\t\t} else {\n\t\t\tthis.$label.text( label );\n\t\t}\n\t} else if ( label instanceof OO.ui.HtmlSnippet ) {\n\t\tthis.$label.html( label.toString() );\n\t} else if ( label instanceof $ ) {\n\t\tthis.$label.empty().append( label );\n\t} else {\n\t\tthis.$label.empty();\n\t}\n};\n","/**\n * IconElement is often mixed into other classes to generate an icon.\n * Icons are graphics, about the size of normal text. They are used to aid the user\n * in locating a control or to convey information in a space-efficient way. See the\n * [OOUI documentation on MediaWiki] [1] for a list of icons\n * included in the library.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Icons,_Indicators,_and_Labels#Icons\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$icon] The icon element created by the class. If this configuration is omitted,\n *  the icon element will use a generated `<span>`. To use a different HTML tag, or to specify that\n *  the icon element be set to an existing icon instead of the one generated by this class, set a\n *  value using a jQuery selection. For example:\n *\n *      // Use a <div> tag instead of a <span>\n *     $icon: $( '<div>' )\n *     // Use an existing icon element instead of the one generated by the class\n *     $icon: this.$element\n *     // Use an icon element from a child widget\n *     $icon: this.childwidget.$element\n * @cfg {Object|string} [icon=''] The symbolic name of the icon (e.g., ‘remove’ or ‘menu’), or a\n *  map of symbolic names. A map is used for i18n purposes and contains a `default` icon\n *  name and additional names keyed by language code. The `default` name is used when no icon is\n *  keyed by the user's language.\n *\n *  Example of an i18n map:\n *\n *     { default: 'bold-a', en: 'bold-b', de: 'bold-f' }\n *  See the [OOUI documentation on MediaWiki] [2] for a list of icons included in the library.\n * [2]: https://www.mediawiki.org/wiki/OOUI/Widgets/Icons,_Indicators,_and_Labels#Icons\n */\nOO.ui.mixin.IconElement = function OoUiMixinIconElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.$icon = null;\n\tthis.icon = null;\n\n\t// Initialization\n\tthis.setIcon( config.icon || this.constructor.static.icon );\n\tthis.setIconElement( config.$icon || $( '<span>' ) );\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.mixin.IconElement );\n\n/* Static Properties */\n\n/**\n * The symbolic name of the icon (e.g., ‘remove’ or ‘menu’), or a map of symbolic names. A map\n * is used for i18n purposes and contains a `default` icon name and additional names keyed by\n * language code. The `default` name is used when no icon is keyed by the user's language.\n *\n * Example of an i18n map:\n *\n *     { default: 'bold-a', en: 'bold-b', de: 'bold-f' }\n *\n * Note: the static property will be overridden if the #icon configuration is used.\n *\n * @static\n * @inheritable\n * @property {Object|string}\n */\nOO.ui.mixin.IconElement.static.icon = null;\n\n/**\n * The icon title, displayed when users move the mouse over the icon. The value can be text, a\n * function that returns title text, or `null` for no title.\n *\n * The static property will be overridden if the #iconTitle configuration is used.\n *\n * @static\n * @inheritable\n * @property {string|Function|null}\n */\nOO.ui.mixin.IconElement.static.iconTitle = null;\n\n/* Methods */\n\n/**\n * Set the icon element. This method is used to retarget an icon mixin so that its functionality\n * applies to the specified icon element instead of the one created by the class. If an icon\n * element is already set, the mixin’s effect on that element is removed. Generated CSS classes\n * and mixin methods will no longer affect the element.\n *\n * @param {jQuery} $icon Element to use as icon\n */\nOO.ui.mixin.IconElement.prototype.setIconElement = function ( $icon ) {\n\tif ( this.$icon ) {\n\t\tthis.$icon\n\t\t\t.removeClass( 'oo-ui-iconElement-icon oo-ui-icon-' + this.icon )\n\t\t\t.removeAttr( 'title' );\n\t}\n\n\tthis.$icon = $icon\n\t\t.addClass( 'oo-ui-iconElement-icon' )\n\t\t.toggleClass( 'oo-ui-iconElement-noIcon', !this.icon )\n\t\t.toggleClass( 'oo-ui-icon-' + this.icon, !!this.icon );\n\tif ( this.iconTitle !== null ) {\n\t\tthis.$icon.attr( 'title', this.iconTitle );\n\t}\n\n\tthis.updateThemeClasses();\n};\n\n/**\n * Set icon by symbolic name (e.g., ‘remove’ or ‘menu’). Use `null` to remove an icon.\n * The icon parameter can also be set to a map of icon names. See the #icon config setting\n * for an example.\n *\n * @param {Object|string|null} icon A symbolic icon name, a {@link #icon map of icon names} keyed\n *  by language code, or `null` to remove the icon.\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.IconElement.prototype.setIcon = function ( icon ) {\n\ticon = OO.isPlainObject( icon ) ? OO.ui.getLocalValue( icon, null, 'default' ) : icon;\n\ticon = typeof icon === 'string' && icon.trim().length ? icon.trim() : null;\n\n\tif ( this.icon !== icon ) {\n\t\tif ( this.$icon ) {\n\t\t\tif ( this.icon !== null ) {\n\t\t\t\tthis.$icon.removeClass( 'oo-ui-icon-' + this.icon );\n\t\t\t}\n\t\t\tif ( icon !== null ) {\n\t\t\t\tthis.$icon.addClass( 'oo-ui-icon-' + icon );\n\t\t\t}\n\t\t}\n\t\tthis.icon = icon;\n\t}\n\n\tthis.$element.toggleClass( 'oo-ui-iconElement', !!this.icon );\n\tif ( this.$icon ) {\n\t\tthis.$icon.toggleClass( 'oo-ui-iconElement-noIcon', !this.icon );\n\t}\n\tthis.updateThemeClasses();\n\n\treturn this;\n};\n\n/**\n * Get the symbolic name of the icon.\n *\n * @return {string} Icon name\n */\nOO.ui.mixin.IconElement.prototype.getIcon = function () {\n\treturn this.icon;\n};\n\n/**\n * Get the icon title. The title text is displayed when a user moves the mouse over the icon.\n *\n * @return {string} Icon title text\n * @deprecated\n */\nOO.ui.mixin.IconElement.prototype.getIconTitle = function () {\n\treturn this.iconTitle;\n};\n","/**\n * IndicatorElement is often mixed into other classes to generate an indicator.\n * Indicators are small graphics that are generally used in two ways:\n *\n * - To draw attention to the status of an item. For example, an indicator might be\n *   used to show that an item in a list has errors that need to be resolved.\n * - To clarify the function of a control that acts in an exceptional way (a button\n *   that opens a menu instead of performing an action directly, for example).\n *\n * For a list of indicators included in the library, please see the\n * [OOUI documentation on MediaWiki] [1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Icons,_Indicators,_and_Labels#Indicators\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$indicator] The indicator element created by the class. If this\n *  configuration is omitted, the indicator element will use a generated `<span>`.\n * @cfg {string} [indicator] Symbolic name of the indicator (e.g., ‘clear’ or ‘down’).\n *  See the [OOUI documentation on MediaWiki][2] for a list of indicators included\n *  in the library.\n * [2]: https://www.mediawiki.org/wiki/OOUI/Widgets/Icons,_Indicators,_and_Labels#Indicators\n */\nOO.ui.mixin.IndicatorElement = function OoUiMixinIndicatorElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.$indicator = null;\n\tthis.indicator = null;\n\n\t// Initialization\n\tthis.setIndicator( config.indicator || this.constructor.static.indicator );\n\tthis.setIndicatorElement( config.$indicator || $( '<span>' ) );\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.mixin.IndicatorElement );\n\n/* Static Properties */\n\n/**\n * Symbolic name of the indicator (e.g., ‘clear’ or  ‘down’).\n * The static property will be overridden if the #indicator configuration is used.\n *\n * @static\n * @inheritable\n * @property {string|null}\n */\nOO.ui.mixin.IndicatorElement.static.indicator = null;\n\n/**\n * A text string used as the indicator title, a function that returns title text, or `null`\n * for no title. The static property will be overridden if the #indicatorTitle configuration is\n * used.\n *\n * @static\n * @inheritable\n * @property {string|Function|null}\n */\nOO.ui.mixin.IndicatorElement.static.indicatorTitle = null;\n\n/* Methods */\n\n/**\n * Set the indicator element.\n *\n * If an element is already set, it will be cleaned up before setting up the new element.\n *\n * @param {jQuery} $indicator Element to use as indicator\n */\nOO.ui.mixin.IndicatorElement.prototype.setIndicatorElement = function ( $indicator ) {\n\tif ( this.$indicator ) {\n\t\tthis.$indicator\n\t\t\t.removeClass( 'oo-ui-indicatorElement-indicator oo-ui-indicator-' + this.indicator )\n\t\t\t.removeAttr( 'title' );\n\t}\n\n\tthis.$indicator = $indicator\n\t\t.addClass( 'oo-ui-indicatorElement-indicator' )\n\t\t.toggleClass( 'oo-ui-indicatorElement-noIndicator', !this.indicator )\n\t\t.toggleClass( 'oo-ui-indicator-' + this.indicator, !!this.indicator );\n\tif ( this.indicatorTitle !== null ) {\n\t\tthis.$indicator.attr( 'title', this.indicatorTitle );\n\t}\n\n\tthis.updateThemeClasses();\n};\n\n/**\n * Set the indicator by its symbolic name: ‘clear’, ‘down’, ‘required’, ‘search’, ‘up’. Use `null`\n * to remove the indicator.\n *\n * @param {string|null} indicator Symbolic name of indicator, or `null` for no indicator\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.IndicatorElement.prototype.setIndicator = function ( indicator ) {\n\tindicator = typeof indicator === 'string' && indicator.length ? indicator.trim() : null;\n\n\tif ( this.indicator !== indicator ) {\n\t\tif ( this.$indicator ) {\n\t\t\tif ( this.indicator !== null ) {\n\t\t\t\tthis.$indicator.removeClass( 'oo-ui-indicator-' + this.indicator );\n\t\t\t}\n\t\t\tif ( indicator !== null ) {\n\t\t\t\tthis.$indicator.addClass( 'oo-ui-indicator-' + indicator );\n\t\t\t}\n\t\t}\n\t\tthis.indicator = indicator;\n\t}\n\n\tthis.$element.toggleClass( 'oo-ui-indicatorElement', !!this.indicator );\n\tif ( this.$indicator ) {\n\t\tthis.$indicator.toggleClass( 'oo-ui-indicatorElement-noIndicator', !this.indicator );\n\t}\n\tthis.updateThemeClasses();\n\n\treturn this;\n};\n\n/**\n * Get the symbolic name of the indicator (e.g., ‘clear’ or  ‘down’).\n *\n * @return {string} Symbolic name of indicator\n */\nOO.ui.mixin.IndicatorElement.prototype.getIndicator = function () {\n\treturn this.indicator;\n};\n\n/**\n * Get the indicator title.\n *\n * The title is displayed when a user moves the mouse over the indicator.\n *\n * @return {string} Indicator title text\n * @deprecated\n */\nOO.ui.mixin.IndicatorElement.prototype.getIndicatorTitle = function () {\n\treturn this.indicatorTitle;\n};\n","/**\n * The FlaggedElement class is an attribute mixin, meaning that it is used to add\n * additional functionality to an element created by another class. The class provides\n * a ‘flags’ property assigned the name (or an array of names) of styling flags,\n * which are used to customize the look and feel of a widget to better describe its\n * importance and functionality.\n *\n * The library currently contains the following styling flags for general use:\n *\n * - **progressive**: Progressive styling is applied to convey that the widget will move the user\n *   forward in a process.\n * - **destructive**: Destructive styling is applied to convey that the widget will remove\n *   something.\n *\n * The flags affect the appearance of the buttons:\n *\n *     @example\n *     // FlaggedElement is mixed into ButtonWidget to provide styling flags\n *     var button1 = new OO.ui.ButtonWidget( {\n *             label: 'Progressive',\n *             flags: 'progressive'\n *         } ),\n *         button2 = new OO.ui.ButtonWidget( {\n *             label: 'Destructive',\n *             flags: 'destructive'\n *         } );\n *     $( document.body ).append( button1.$element, button2.$element );\n *\n * {@link OO.ui.ActionWidget ActionWidgets}, which are a special kind of button that execute an\n * action, use these flags: **primary** and **safe**.\n * Please see the [OOUI documentation on MediaWiki] [1] for more information.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Elements/Flagged\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {string|string[]} [flags] The name or names of the flags (e.g., 'progressive' or 'primary')\n *  to apply.\n *  Please see the [OOUI documentation on MediaWiki] [2] for more information about available flags.\n *  [2]: https://www.mediawiki.org/wiki/OOUI/Elements/Flagged\n * @cfg {jQuery} [$flagged] The flagged element. By default,\n *  the flagged functionality is applied to the element created by the class ($element).\n *  If a different element is specified, the flagged functionality will be applied to it instead.\n */\nOO.ui.mixin.FlaggedElement = function OoUiMixinFlaggedElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.flags = {};\n\tthis.$flagged = null;\n\n\t// Initialization\n\tthis.setFlags( config.flags || this.constructor.static.flags );\n\tthis.setFlaggedElement( config.$flagged || this.$element );\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.mixin.FlaggedElement );\n\n/* Events */\n\n/**\n * @event flag\n * A flag event is emitted when the #clearFlags or #setFlags methods are used. The `changes`\n * parameter contains the name of each modified flag and indicates whether it was\n * added or removed.\n *\n * @param {Object.<string,boolean>} changes Object keyed by flag name. A Boolean `true` indicates\n * that the flag was added, `false` that the flag was removed.\n */\n\n/* Static Properties */\n\n/**\n * Initial value to pass to setFlags if no value is provided in config.\n *\n * @static\n * @inheritable\n * @property {string|string[]|Object.<string, boolean>}\n */\nOO.ui.mixin.FlaggedElement.static.flags = null;\n\n/* Methods */\n\n/**\n * Set the flagged element.\n *\n * This method is used to retarget a flagged mixin so that its functionality applies to the\n * specified element.\n * If an element is already set, the method will remove the mixin’s effect on that element.\n *\n * @param {jQuery} $flagged Element that should be flagged\n */\nOO.ui.mixin.FlaggedElement.prototype.setFlaggedElement = function ( $flagged ) {\n\tvar classNames = Object.keys( this.flags ).map( function ( flag ) {\n\t\treturn 'oo-ui-flaggedElement-' + flag;\n\t} );\n\n\tif ( this.$flagged ) {\n\t\tthis.$flagged.removeClass( classNames );\n\t}\n\n\tthis.$flagged = $flagged.addClass( classNames );\n};\n\n/**\n * Check if the specified flag is set.\n *\n * @param {string} flag Name of flag\n * @return {boolean} The flag is set\n */\nOO.ui.mixin.FlaggedElement.prototype.hasFlag = function ( flag ) {\n\t// This may be called before the constructor, thus before this.flags is set\n\treturn this.flags && ( flag in this.flags );\n};\n\n/**\n * Get the names of all flags set.\n *\n * @return {string[]} Flag names\n */\nOO.ui.mixin.FlaggedElement.prototype.getFlags = function () {\n\t// This may be called before the constructor, thus before this.flags is set\n\treturn Object.keys( this.flags || {} );\n};\n\n/**\n * Clear all flags.\n *\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n * @fires flag\n */\nOO.ui.mixin.FlaggedElement.prototype.clearFlags = function () {\n\tvar flag, className,\n\t\tchanges = {},\n\t\tremove = [],\n\t\tclassPrefix = 'oo-ui-flaggedElement-';\n\n\tfor ( flag in this.flags ) {\n\t\tclassName = classPrefix + flag;\n\t\tchanges[ flag ] = false;\n\t\tdelete this.flags[ flag ];\n\t\tremove.push( className );\n\t}\n\n\tif ( this.$flagged ) {\n\t\tthis.$flagged.removeClass( remove );\n\t}\n\n\tthis.updateThemeClasses();\n\tthis.emit( 'flag', changes );\n\n\treturn this;\n};\n\n/**\n * Add one or more flags.\n *\n * @param {string|string[]|Object.<string, boolean>} flags A flag name, an array of flag names,\n *  or an object keyed by flag name with a boolean value that indicates whether the flag should\n *  be added (`true`) or removed (`false`).\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n * @fires flag\n */\nOO.ui.mixin.FlaggedElement.prototype.setFlags = function ( flags ) {\n\tvar i, len, flag, className,\n\t\tchanges = {},\n\t\tadd = [],\n\t\tremove = [],\n\t\tclassPrefix = 'oo-ui-flaggedElement-';\n\n\tif ( typeof flags === 'string' ) {\n\t\tclassName = classPrefix + flags;\n\t\t// Set\n\t\tif ( !this.flags[ flags ] ) {\n\t\t\tthis.flags[ flags ] = true;\n\t\t\tadd.push( className );\n\t\t}\n\t} else if ( Array.isArray( flags ) ) {\n\t\tfor ( i = 0, len = flags.length; i < len; i++ ) {\n\t\t\tflag = flags[ i ];\n\t\t\tclassName = classPrefix + flag;\n\t\t\t// Set\n\t\t\tif ( !this.flags[ flag ] ) {\n\t\t\t\tchanges[ flag ] = true;\n\t\t\t\tthis.flags[ flag ] = true;\n\t\t\t\tadd.push( className );\n\t\t\t}\n\t\t}\n\t} else if ( OO.isPlainObject( flags ) ) {\n\t\tfor ( flag in flags ) {\n\t\t\tclassName = classPrefix + flag;\n\t\t\tif ( flags[ flag ] ) {\n\t\t\t\t// Set\n\t\t\t\tif ( !this.flags[ flag ] ) {\n\t\t\t\t\tchanges[ flag ] = true;\n\t\t\t\t\tthis.flags[ flag ] = true;\n\t\t\t\t\tadd.push( className );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Remove\n\t\t\t\tif ( this.flags[ flag ] ) {\n\t\t\t\t\tchanges[ flag ] = false;\n\t\t\t\t\tdelete this.flags[ flag ];\n\t\t\t\t\tremove.push( className );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( this.$flagged ) {\n\t\tthis.$flagged\n\t\t\t.addClass( add )\n\t\t\t.removeClass( remove );\n\t}\n\n\tthis.updateThemeClasses();\n\tthis.emit( 'flag', changes );\n\n\treturn this;\n};\n","/**\n * TitledElement is mixed into other classes to provide a `title` attribute.\n * Titles are rendered by the browser and are made visible when the user moves\n * the mouse over the element. Titles are not visible on touch devices.\n *\n *     @example\n *     // TitledElement provides a `title` attribute to the\n *     // ButtonWidget class.\n *     var button = new OO.ui.ButtonWidget( {\n *         label: 'Button with Title',\n *         title: 'I am a button'\n *     } );\n *     $( document.body ).append( button.$element );\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$titled] The element to which the `title` attribute is applied.\n *  If this config is omitted, the title functionality is applied to $element, the\n *  element created by the class.\n * @cfg {string|Function} [title] The title text or a function that returns text. If\n *  this config is omitted, the value of the {@link #static-title static title} property is used.\n */\nOO.ui.mixin.TitledElement = function OoUiMixinTitledElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.$titled = null;\n\tthis.title = null;\n\n\t// Initialization\n\tthis.setTitle( config.title !== undefined ? config.title : this.constructor.static.title );\n\tthis.setTitledElement( config.$titled || this.$element );\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.mixin.TitledElement );\n\n/* Static Properties */\n\n/**\n * The title text, a function that returns text, or `null` for no title. The value of the static\n * property is overridden if the #title config option is used.\n *\n * If the element has a default title (e.g. `<input type=file>`), `null` will allow that title to be\n * shown. Use empty string to suppress it.\n *\n * @static\n * @inheritable\n * @property {string|Function|null}\n */\nOO.ui.mixin.TitledElement.static.title = null;\n\n/* Methods */\n\n/**\n * Set the titled element.\n *\n * This method is used to retarget a TitledElement mixin so that its functionality applies to the\n * specified element.\n * If an element is already set, the mixin’s effect on that element is removed before the new\n * element is set up.\n *\n * @param {jQuery} $titled Element that should use the 'titled' functionality\n */\nOO.ui.mixin.TitledElement.prototype.setTitledElement = function ( $titled ) {\n\tif ( this.$titled ) {\n\t\tthis.$titled.removeAttr( 'title' );\n\t}\n\n\tthis.$titled = $titled;\n\tthis.updateTitle();\n};\n\n/**\n * Set title.\n *\n * @param {string|Function|null} title Title text, a function that returns text, or `null`\n *  for no title\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.TitledElement.prototype.setTitle = function ( title ) {\n\ttitle = typeof title === 'function' ? OO.ui.resolveMsg( title ) : title;\n\ttitle = typeof title === 'string' ? title : null;\n\n\tif ( this.title !== title ) {\n\t\tthis.title = title;\n\t\tthis.updateTitle();\n\t}\n\n\treturn this;\n};\n\n/**\n * Update the title attribute, in case of changes to title or accessKey.\n *\n * @protected\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.TitledElement.prototype.updateTitle = function () {\n\tvar title = this.getTitle();\n\tif ( this.$titled ) {\n\t\tif ( title !== null ) {\n\t\t\t// Only if this is an AccessKeyedElement\n\t\t\tif ( this.formatTitleWithAccessKey ) {\n\t\t\t\ttitle = this.formatTitleWithAccessKey( title );\n\t\t\t}\n\t\t\tthis.$titled.attr( 'title', title );\n\t\t} else {\n\t\t\tthis.$titled.removeAttr( 'title' );\n\t\t}\n\t}\n\treturn this;\n};\n\n/**\n * Get title.\n *\n * @return {string} Title string\n */\nOO.ui.mixin.TitledElement.prototype.getTitle = function () {\n\treturn this.title;\n};\n","/**\n * AccessKeyedElement is mixed into other classes to provide an `accesskey` HTML attribute.\n * Access keys allow an user to go to a specific element by using\n * a shortcut combination of a browser specific keys + the key\n * set to the field.\n *\n *     @example\n *     // AccessKeyedElement provides an `accesskey` attribute to the\n *     // ButtonWidget class.\n *     var button = new OO.ui.ButtonWidget( {\n *         label: 'Button with access key',\n *         accessKey: 'k'\n *     } );\n *     $( document.body ).append( button.$element );\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$accessKeyed] The element to which the `accesskey` attribute is applied.\n *  If this config is omitted, the access key functionality is applied to $element, the\n *  element created by the class.\n * @cfg {string|Function} [accessKey] The key or a function that returns the key. If\n *  this config is omitted, no access key will be added.\n */\nOO.ui.mixin.AccessKeyedElement = function OoUiMixinAccessKeyedElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.$accessKeyed = null;\n\tthis.accessKey = null;\n\n\t// Initialization\n\tthis.setAccessKey( config.accessKey || null );\n\tthis.setAccessKeyedElement( config.$accessKeyed || this.$element );\n\n\t// If this is also a TitledElement and it initialized before we did, we may have\n\t// to update the title with the access key\n\tif ( this.updateTitle ) {\n\t\tthis.updateTitle();\n\t}\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.mixin.AccessKeyedElement );\n\n/* Static Properties */\n\n/**\n * The access key, a function that returns a key, or `null` for no access key.\n *\n * @static\n * @inheritable\n * @property {string|Function|null}\n */\nOO.ui.mixin.AccessKeyedElement.static.accessKey = null;\n\n/* Methods */\n\n/**\n * Set the access keyed element.\n *\n * This method is used to retarget a AccessKeyedElement mixin so that its functionality applies to\n * the specified element.\n * If an element is already set, the mixin's effect on that element is removed before the new\n * element is set up.\n *\n * @param {jQuery} $accessKeyed Element that should use the 'access keyed' functionality\n */\nOO.ui.mixin.AccessKeyedElement.prototype.setAccessKeyedElement = function ( $accessKeyed ) {\n\tif ( this.$accessKeyed ) {\n\t\tthis.$accessKeyed.removeAttr( 'accesskey' );\n\t}\n\n\tthis.$accessKeyed = $accessKeyed;\n\tif ( this.accessKey ) {\n\t\tthis.$accessKeyed.attr( 'accesskey', this.accessKey );\n\t}\n};\n\n/**\n * Set access key.\n *\n * @param {string|Function|null} accessKey Key, a function that returns a key, or `null` for no\n *  access key\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.AccessKeyedElement.prototype.setAccessKey = function ( accessKey ) {\n\taccessKey = typeof accessKey === 'string' ? OO.ui.resolveMsg( accessKey ) : null;\n\n\tif ( this.accessKey !== accessKey ) {\n\t\tif ( this.$accessKeyed ) {\n\t\t\tif ( accessKey !== null ) {\n\t\t\t\tthis.$accessKeyed.attr( 'accesskey', accessKey );\n\t\t\t} else {\n\t\t\t\tthis.$accessKeyed.removeAttr( 'accesskey' );\n\t\t\t}\n\t\t}\n\t\tthis.accessKey = accessKey;\n\n\t\t// Only if this is a TitledElement\n\t\tif ( this.updateTitle ) {\n\t\t\tthis.updateTitle();\n\t\t}\n\t}\n\n\treturn this;\n};\n\n/**\n * Get access key.\n *\n * @return {string} accessKey string\n */\nOO.ui.mixin.AccessKeyedElement.prototype.getAccessKey = function () {\n\treturn this.accessKey;\n};\n\n/**\n * Add information about the access key to the element's tooltip label.\n * (This is only public for hacky usage in FieldLayout.)\n *\n * @param {string} title Tooltip label for `title` attribute\n * @return {string}\n */\nOO.ui.mixin.AccessKeyedElement.prototype.formatTitleWithAccessKey = function ( title ) {\n\tvar accessKey;\n\n\tif ( !this.$accessKeyed ) {\n\t\t// Not initialized yet; the constructor will call updateTitle() which will rerun this\n\t\t// function.\n\t\treturn title;\n\t}\n\t// Use jquery.accessKeyLabel if available to show modifiers, otherwise just display the\n\t// single key.\n\tif ( $.fn.updateTooltipAccessKeys && $.fn.updateTooltipAccessKeys.getAccessKeyLabel ) {\n\t\taccessKey = $.fn.updateTooltipAccessKeys.getAccessKeyLabel( this.$accessKeyed[ 0 ] );\n\t} else {\n\t\taccessKey = this.getAccessKey();\n\t}\n\tif ( accessKey ) {\n\t\ttitle += ' [' + accessKey + ']';\n\t}\n\treturn title;\n};\n","/**\n * ButtonWidget is a generic widget for buttons. A wide variety of looks,\n * feels, and functionality can be customized via the class’s configuration options\n * and methods. Please see the [OOUI documentation on MediaWiki] [1] for more information\n * and examples.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Buttons_and_Switches\n *\n *     @example\n *     // A button widget.\n *     var button = new OO.ui.ButtonWidget( {\n *         label: 'Button with Icon',\n *         icon: 'trash',\n *         title: 'Remove'\n *     } );\n *     $( document.body ).append( button.$element );\n *\n * NOTE: HTML form buttons should use the OO.ui.ButtonInputWidget class.\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.ButtonElement\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.IndicatorElement\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.TitledElement\n * @mixins OO.ui.mixin.FlaggedElement\n * @mixins OO.ui.mixin.TabIndexedElement\n * @mixins OO.ui.mixin.AccessKeyedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [active=false] Whether button should be shown as active\n * @cfg {string} [href] Hyperlink to visit when the button is clicked.\n * @cfg {string} [target] The frame or window in which to open the hyperlink.\n * @cfg {boolean} [noFollow] Search engine traversal hint (default: true)\n */\nOO.ui.ButtonWidget = function OoUiButtonWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.ButtonWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.ButtonElement.call( this, config );\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.IndicatorElement.call( this, config );\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.TitledElement.call( this, $.extend( {\n\t\t$titled: this.$button\n\t}, config ) );\n\tOO.ui.mixin.FlaggedElement.call( this, config );\n\tOO.ui.mixin.TabIndexedElement.call( this, $.extend( {\n\t\t$tabIndexed: this.$button\n\t}, config ) );\n\tOO.ui.mixin.AccessKeyedElement.call( this, $.extend( {\n\t\t$accessKeyed: this.$button\n\t}, config ) );\n\n\t// Properties\n\tthis.href = null;\n\tthis.target = null;\n\tthis.noFollow = false;\n\n\t// Events\n\tthis.connect( this, {\n\t\tdisable: 'onDisable'\n\t} );\n\n\t// Initialization\n\tthis.$button.append( this.$icon, this.$label, this.$indicator );\n\tthis.$element\n\t\t.addClass( 'oo-ui-buttonWidget' )\n\t\t.append( this.$button );\n\tthis.setActive( config.active );\n\tthis.setHref( config.href );\n\tthis.setTarget( config.target );\n\tthis.setNoFollow( config.noFollow );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ButtonWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.ButtonElement );\nOO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.IndicatorElement );\nOO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.TitledElement );\nOO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.FlaggedElement );\nOO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.TabIndexedElement );\nOO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.AccessKeyedElement );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.ButtonWidget.static.cancelButtonMouseDownEvents = false;\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.ButtonWidget.static.tagName = 'span';\n\n/* Methods */\n\n/**\n * Get hyperlink location.\n *\n * @return {string} Hyperlink location\n */\nOO.ui.ButtonWidget.prototype.getHref = function () {\n\treturn this.href;\n};\n\n/**\n * Get hyperlink target.\n *\n * @return {string} Hyperlink target\n */\nOO.ui.ButtonWidget.prototype.getTarget = function () {\n\treturn this.target;\n};\n\n/**\n * Get search engine traversal hint.\n *\n * @return {boolean} Whether search engines should avoid traversing this hyperlink\n */\nOO.ui.ButtonWidget.prototype.getNoFollow = function () {\n\treturn this.noFollow;\n};\n\n/**\n * Set hyperlink location.\n *\n * @param {string|null} href Hyperlink location, null to remove\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.ButtonWidget.prototype.setHref = function ( href ) {\n\thref = typeof href === 'string' ? href : null;\n\tif ( href !== null && !OO.ui.isSafeUrl( href ) ) {\n\t\thref = './' + href;\n\t}\n\n\tif ( href !== this.href ) {\n\t\tthis.href = href;\n\t\tthis.updateHref();\n\t}\n\n\treturn this;\n};\n\n/**\n * Update the `href` attribute, in case of changes to href or\n * disabled state.\n *\n * @private\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.ButtonWidget.prototype.updateHref = function () {\n\tif ( this.href !== null && !this.isDisabled() ) {\n\t\tthis.$button.attr( 'href', this.href );\n\t} else {\n\t\tthis.$button.removeAttr( 'href' );\n\t}\n\n\treturn this;\n};\n\n/**\n * Handle disable events.\n *\n * @private\n * @param {boolean} disabled Element is disabled\n */\nOO.ui.ButtonWidget.prototype.onDisable = function () {\n\tthis.updateHref();\n};\n\n/**\n * Set hyperlink target.\n *\n * @param {string|null} target Hyperlink target, null to remove\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.ButtonWidget.prototype.setTarget = function ( target ) {\n\ttarget = typeof target === 'string' ? target : null;\n\n\tif ( target !== this.target ) {\n\t\tthis.target = target;\n\t\tif ( target !== null ) {\n\t\t\tthis.$button.attr( 'target', target );\n\t\t} else {\n\t\t\tthis.$button.removeAttr( 'target' );\n\t\t}\n\t}\n\n\treturn this;\n};\n\n/**\n * Set search engine traversal hint.\n *\n * @param {boolean} noFollow True if search engines should avoid traversing this hyperlink\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.ButtonWidget.prototype.setNoFollow = function ( noFollow ) {\n\tnoFollow = typeof noFollow === 'boolean' ? noFollow : true;\n\n\tif ( noFollow !== this.noFollow ) {\n\t\tthis.noFollow = noFollow;\n\t\tif ( noFollow ) {\n\t\t\tthis.$button.attr( 'rel', 'nofollow' );\n\t\t} else {\n\t\t\tthis.$button.removeAttr( 'rel' );\n\t\t}\n\t}\n\n\treturn this;\n};\n\n// Override method visibility hints from ButtonElement\n/**\n * @method setActive\n * @inheritdoc\n */\n/**\n * @method isActive\n * @inheritdoc\n */\n","/**\n * A ButtonGroupWidget groups related buttons and is used together with OO.ui.ButtonWidget and\n * its subclasses. Each button in a group is addressed by a unique reference. Buttons can be added,\n * removed, and cleared from the group.\n *\n *     @example\n *     // A ButtonGroupWidget with two buttons.\n *     var button1 = new OO.ui.PopupButtonWidget( {\n *             label: 'Select a category',\n *             icon: 'menu',\n *             popup: {\n *                 $content: $( '<p>List of categories…</p>' ),\n *                 padded: true,\n *                 align: 'left'\n *             }\n *         } ),\n *         button2 = new OO.ui.ButtonWidget( {\n *             label: 'Add item'\n *         } ),\n *         buttonGroup = new OO.ui.ButtonGroupWidget( {\n *             items: [ button1, button2 ]\n *         } );\n *     $( document.body ).append( buttonGroup.$element );\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.GroupElement\n * @mixins OO.ui.mixin.TitledElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {OO.ui.ButtonWidget[]} [items] Buttons to add\n */\nOO.ui.ButtonGroupWidget = function OoUiButtonGroupWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.ButtonGroupWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.GroupElement.call( this, $.extend( {\n\t\t$group: this.$element\n\t}, config ) );\n\tOO.ui.mixin.TitledElement.call( this, config );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-buttonGroupWidget' );\n\tif ( Array.isArray( config.items ) ) {\n\t\tthis.addItems( config.items );\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ButtonGroupWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.ButtonGroupWidget, OO.ui.mixin.GroupElement );\nOO.mixinClass( OO.ui.ButtonGroupWidget, OO.ui.mixin.TitledElement );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.ButtonGroupWidget.static.tagName = 'span';\n\n/* Methods */\n\n/**\n * Focus the widget\n *\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.ButtonGroupWidget.prototype.focus = function () {\n\tif ( !this.isDisabled() ) {\n\t\tif ( this.items[ 0 ] ) {\n\t\t\tthis.items[ 0 ].focus();\n\t\t}\n\t}\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.ButtonGroupWidget.prototype.simulateLabelClick = function () {\n\tthis.focus();\n};\n","/**\n * IconWidget is a generic widget for {@link OO.ui.mixin.IconElement icons}.\n * In general, IconWidgets should be used with OO.ui.LabelWidget, which creates a label that\n * identifies the icon’s function. See the [OOUI documentation on MediaWiki] [1]\n * for a list of icons included in the library.\n *\n *     @example\n *     // An IconWidget with a label via LabelWidget.\n *     var myIcon = new OO.ui.IconWidget( {\n *             icon: 'help',\n *             title: 'Help'\n *          } ),\n *          // Create a label.\n *          iconLabel = new OO.ui.LabelWidget( {\n *              label: 'Help'\n *          } );\n *      $( document.body ).append( myIcon.$element, iconLabel.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Icons,_Indicators,_and_Labels#Icons\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.TitledElement\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.FlaggedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.IconWidget = function OoUiIconWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.IconWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.IconElement.call( this, $.extend( {\n\t\t$icon: this.$element\n\t}, config ) );\n\tOO.ui.mixin.TitledElement.call( this, $.extend( {\n\t\t$titled: this.$element\n\t}, config ) );\n\tOO.ui.mixin.LabelElement.call( this, $.extend( {\n\t\t$label: this.$element,\n\t\tinvisibleLabel: true\n\t}, config ) );\n\tOO.ui.mixin.FlaggedElement.call( this, $.extend( {\n\t\t$flagged: this.$element\n\t}, config ) );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-iconWidget' );\n\t// Remove class added by LabelElement initialization. It causes unexpected CSS to apply when\n\t// nested in other widgets, because this widget used to not mix in LabelElement.\n\tthis.$element.removeClass( 'oo-ui-labelElement-label' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.IconWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.IconWidget, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.IconWidget, OO.ui.mixin.TitledElement );\nOO.mixinClass( OO.ui.IconWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.IconWidget, OO.ui.mixin.FlaggedElement );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.IconWidget.static.tagName = 'span';\n","/**\n * IndicatorWidgets create indicators, which are small graphics that are generally used to draw\n * attention to the status of an item or to clarify the function within a control. For a list of\n * indicators included in the library, please see the [OOUI documentation on MediaWiki][1].\n *\n *     @example\n *     // An indicator widget.\n *     var indicator1 = new OO.ui.IndicatorWidget( {\n *             indicator: 'required'\n *         } ),\n *         // Create a fieldset layout to add a label.\n *         fieldset = new OO.ui.FieldsetLayout();\n *     fieldset.addItems( [\n *         new OO.ui.FieldLayout( indicator1, {\n *             label: 'A required indicator:'\n *         } )\n *     ] );\n *     $( document.body ).append( fieldset.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Icons,_Indicators,_and_Labels#Indicators\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.IndicatorElement\n * @mixins OO.ui.mixin.TitledElement\n * @mixins OO.ui.mixin.LabelElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.IndicatorWidget = function OoUiIndicatorWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.IndicatorWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.IndicatorElement.call( this, $.extend( {\n\t\t$indicator: this.$element\n\t}, config ) );\n\tOO.ui.mixin.TitledElement.call( this, $.extend( {\n\t\t$titled: this.$element\n\t}, config ) );\n\tOO.ui.mixin.LabelElement.call( this, $.extend( {\n\t\t$label: this.$element,\n\t\tinvisibleLabel: true\n\t}, config ) );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-indicatorWidget' );\n\t// Remove class added by LabelElement initialization. It causes unexpected CSS to apply when\n\t// nested in other widgets, because this widget used to not mix in LabelElement.\n\tthis.$element.removeClass( 'oo-ui-labelElement-label' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.IndicatorWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.IndicatorWidget, OO.ui.mixin.IndicatorElement );\nOO.mixinClass( OO.ui.IndicatorWidget, OO.ui.mixin.TitledElement );\nOO.mixinClass( OO.ui.IndicatorWidget, OO.ui.mixin.LabelElement );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.IndicatorWidget.static.tagName = 'span';\n","/**\n * LabelWidgets help identify the function of interface elements. Each LabelWidget can\n * be configured with a `label` option that is set to a string, a label node, or a function:\n *\n * - String: a plaintext string\n * - jQuery selection: a jQuery selection, used for anything other than a plaintext label, e.g., a\n *   label that includes a link or special styling, such as a gray color or additional\n *   graphical elements.\n * - Function: a function that will produce a string in the future. Functions are used\n *   in cases where the value of the label is not currently defined.\n *\n * In addition, the LabelWidget can be associated with an {@link OO.ui.InputWidget input widget},\n * which will come into focus when the label is clicked.\n *\n *     @example\n *     // Two LabelWidgets.\n *     var label1 = new OO.ui.LabelWidget( {\n *             label: 'plaintext label'\n *         } ),\n *         label2 = new OO.ui.LabelWidget( {\n *             label: $( '<a>' ).attr( 'href', 'default.html' ).text( 'jQuery label' )\n *         } ),\n *         // Create a fieldset layout with fields for each example.\n *         fieldset = new OO.ui.FieldsetLayout();\n *     fieldset.addItems( [\n *         new OO.ui.FieldLayout( label1 ),\n *         new OO.ui.FieldLayout( label2 )\n *     ] );\n *     $( document.body ).append( fieldset.$element );\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.TitledElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {OO.ui.InputWidget} [input] {@link OO.ui.InputWidget Input widget} that uses the label.\n *  Clicking the label will focus the specified input field.\n */\nOO.ui.LabelWidget = function OoUiLabelWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.LabelWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.LabelElement.call( this, $.extend( {\n\t\t$label: this.$element\n\t}, config ) );\n\tOO.ui.mixin.TitledElement.call( this, config );\n\n\t// Properties\n\tthis.input = config.input;\n\n\t// Initialization\n\tif ( this.input ) {\n\t\tif ( this.input.getInputId() ) {\n\t\t\tthis.$element.attr( 'for', this.input.getInputId() );\n\t\t} else {\n\t\t\tthis.$label.on( 'click', function () {\n\t\t\t\tthis.input.simulateLabelClick();\n\t\t\t}.bind( this ) );\n\t\t}\n\t}\n\tthis.$element.addClass( 'oo-ui-labelWidget' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.LabelWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.LabelWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.LabelWidget, OO.ui.mixin.TitledElement );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.LabelWidget.static.tagName = 'label';\n","/**\n * PendingElement is a mixin that is used to create elements that notify users that something is\n * happening and that they should wait before proceeding. The pending state is visually represented\n * with a pending texture that appears in the head of a pending\n * {@link OO.ui.ProcessDialog process dialog} or in the input field of a\n * {@link OO.ui.TextInputWidget text input widget}.\n *\n * Currently, {@link OO.ui.ActionWidget Action widgets}, which mix in this class, can also be marked\n * as pending, but only when used in {@link OO.ui.MessageDialog message dialogs}. The behavior is\n * not currently supported for action widgets used in process dialogs.\n *\n *     @example\n *     function MessageDialog( config ) {\n *         MessageDialog.parent.call( this, config );\n *     }\n *     OO.inheritClass( MessageDialog, OO.ui.MessageDialog );\n *\n *     MessageDialog.static.name = 'myMessageDialog';\n *     MessageDialog.static.actions = [\n *         { action: 'save', label: 'Done', flags: 'primary' },\n *         { label: 'Cancel', flags: 'safe' }\n *     ];\n *\n *     MessageDialog.prototype.initialize = function () {\n *         MessageDialog.parent.prototype.initialize.apply( this, arguments );\n *         this.content = new OO.ui.PanelLayout( { padded: true } );\n *         this.content.$element.append( '<p>Click the \\'Done\\' action widget to see its pending ' +\n *             'state. Note that action widgets can be marked pending in message dialogs but not ' +\n *             'process dialogs.</p>' );\n *         this.$body.append( this.content.$element );\n *     };\n *     MessageDialog.prototype.getBodyHeight = function () {\n *         return 100;\n *     }\n *     MessageDialog.prototype.getActionProcess = function ( action ) {\n *         var dialog = this;\n *         if ( action === 'save' ) {\n *             dialog.getActions().get({actions: 'save'})[0].pushPending();\n *             return new OO.ui.Process()\n *             .next( 1000 )\n *             .next( function () {\n *                 dialog.getActions().get({actions: 'save'})[0].popPending();\n *             } );\n *         }\n *         return MessageDialog.parent.prototype.getActionProcess.call( this, action );\n *     };\n *\n *     var windowManager = new OO.ui.WindowManager();\n *     $( document.body ).append( windowManager.$element );\n *\n *     var dialog = new MessageDialog();\n *     windowManager.addWindows( [ dialog ] );\n *     windowManager.openWindow( dialog );\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$pending] Element to mark as pending, defaults to this.$element\n */\nOO.ui.mixin.PendingElement = function OoUiMixinPendingElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.pending = 0;\n\tthis.$pending = null;\n\n\t// Initialisation\n\tthis.setPendingElement( config.$pending || this.$element );\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.mixin.PendingElement );\n\n/* Methods */\n\n/**\n * Set the pending element (and clean up any existing one).\n *\n * @param {jQuery} $pending The element to set to pending.\n */\nOO.ui.mixin.PendingElement.prototype.setPendingElement = function ( $pending ) {\n\tif ( this.$pending ) {\n\t\tthis.$pending.removeClass( 'oo-ui-pendingElement-pending' );\n\t}\n\n\tthis.$pending = $pending;\n\tif ( this.pending > 0 ) {\n\t\tthis.$pending.addClass( 'oo-ui-pendingElement-pending' );\n\t}\n};\n\n/**\n * Check if an element is pending.\n *\n * @return {boolean} Element is pending\n */\nOO.ui.mixin.PendingElement.prototype.isPending = function () {\n\treturn !!this.pending;\n};\n\n/**\n * Increase the pending counter. The pending state will remain active until the counter is zero\n * (i.e., the number of calls to #pushPending and #popPending is the same).\n *\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.PendingElement.prototype.pushPending = function () {\n\tif ( this.pending === 0 ) {\n\t\tthis.$pending.addClass( 'oo-ui-pendingElement-pending' );\n\t\tthis.updateThemeClasses();\n\t}\n\tthis.pending++;\n\n\treturn this;\n};\n\n/**\n * Decrease the pending counter. The pending state will remain active until the counter is zero\n * (i.e., the number of calls to #pushPending and #popPending is the same).\n *\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.PendingElement.prototype.popPending = function () {\n\tif ( this.pending === 1 ) {\n\t\tthis.$pending.removeClass( 'oo-ui-pendingElement-pending' );\n\t\tthis.updateThemeClasses();\n\t}\n\tthis.pending = Math.max( 0, this.pending - 1 );\n\n\treturn this;\n};\n","/**\n * Element that will stick adjacent to a specified container, even when it is inserted elsewhere\n * in the document (for example, in an OO.ui.Window's $overlay).\n *\n * The elements's position is automatically calculated and maintained when window is resized or the\n * page is scrolled. If you reposition the container manually, you have to call #position to make\n * sure the element is still placed correctly.\n *\n * As positioning is only possible when both the element and the container are attached to the DOM\n * and visible, it's only done after you call #togglePositioning. You might want to do this inside\n * the #toggle method to display a floating popup, for example.\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$floatable] Node to position, assigned to #$floatable, omit to use #$element\n * @cfg {jQuery} [$floatableContainer] Node to position adjacent to\n * @cfg {string} [verticalPosition='below'] Where to position $floatable vertically:\n *  'below': Directly below $floatableContainer, aligning f's top edge with fC's bottom edge\n *  'above': Directly above $floatableContainer, aligning f's bottom edge with fC's top edge\n *  'top': Align the top edge with $floatableContainer's top edge\n *  'bottom': Align the bottom edge with $floatableContainer's bottom edge\n *  'center': Vertically align the center with $floatableContainer's center\n * @cfg {string} [horizontalPosition='start'] Where to position $floatable horizontally:\n *  'before': Directly before $floatableContainer, aligning f's end edge with fC's start edge\n *  'after': Directly after $floatableContainer, aligning f's start edge with fC's end edge\n *  'start': Align the start (left in LTR, right in RTL) edge with $floatableContainer's start edge\n *  'end': Align the end (right in LTR, left in RTL) edge with $floatableContainer's end edge\n *  'center': Horizontally align the center with $floatableContainer's center\n * @cfg {boolean} [hideWhenOutOfView=true] Whether to hide the floatable element if the container\n *  is out of view\n */\nOO.ui.mixin.FloatableElement = function OoUiMixinFloatableElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.$floatable = null;\n\tthis.$floatableContainer = null;\n\tthis.$floatableWindow = null;\n\tthis.$floatableClosestScrollable = null;\n\tthis.floatableOutOfView = false;\n\tthis.onFloatableScrollHandler = this.position.bind( this );\n\tthis.onFloatableWindowResizeHandler = this.position.bind( this );\n\n\t// Initialization\n\tthis.setFloatableContainer( config.$floatableContainer );\n\tthis.setFloatableElement( config.$floatable || this.$element );\n\tthis.setVerticalPosition( config.verticalPosition || 'below' );\n\tthis.setHorizontalPosition( config.horizontalPosition || 'start' );\n\tthis.hideWhenOutOfView = config.hideWhenOutOfView === undefined ?\n\t\ttrue : !!config.hideWhenOutOfView;\n};\n\n/* Methods */\n\n/**\n * Set floatable element.\n *\n * If an element is already set, it will be cleaned up before setting up the new element.\n *\n * @param {jQuery} $floatable Element to make floatable\n */\nOO.ui.mixin.FloatableElement.prototype.setFloatableElement = function ( $floatable ) {\n\tif ( this.$floatable ) {\n\t\tthis.$floatable.removeClass( 'oo-ui-floatableElement-floatable' );\n\t\tthis.$floatable.css( { left: '', top: '' } );\n\t}\n\n\tthis.$floatable = $floatable.addClass( 'oo-ui-floatableElement-floatable' );\n\tthis.position();\n};\n\n/**\n * Set floatable container.\n *\n * The element will be positioned relative to the specified container.\n *\n * @param {jQuery|null} $floatableContainer Container to keep visible, or null to unset\n */\nOO.ui.mixin.FloatableElement.prototype.setFloatableContainer = function ( $floatableContainer ) {\n\tthis.$floatableContainer = $floatableContainer;\n\tif ( this.$floatable ) {\n\t\tthis.position();\n\t}\n};\n\n/**\n * Change how the element is positioned vertically.\n *\n * @param {string} position 'below', 'above', 'top', 'bottom' or 'center'\n */\nOO.ui.mixin.FloatableElement.prototype.setVerticalPosition = function ( position ) {\n\tif ( [ 'below', 'above', 'top', 'bottom', 'center' ].indexOf( position ) === -1 ) {\n\t\tthrow new Error( 'Invalid value for vertical position: ' + position );\n\t}\n\tif ( this.verticalPosition !== position ) {\n\t\tthis.verticalPosition = position;\n\t\tif ( this.$floatable ) {\n\t\t\tthis.position();\n\t\t}\n\t}\n};\n\n/**\n * Change how the element is positioned horizontally.\n *\n * @param {string} position 'before', 'after', 'start', 'end' or 'center'\n */\nOO.ui.mixin.FloatableElement.prototype.setHorizontalPosition = function ( position ) {\n\tif ( [ 'before', 'after', 'start', 'end', 'center' ].indexOf( position ) === -1 ) {\n\t\tthrow new Error( 'Invalid value for horizontal position: ' + position );\n\t}\n\tif ( this.horizontalPosition !== position ) {\n\t\tthis.horizontalPosition = position;\n\t\tif ( this.$floatable ) {\n\t\t\tthis.position();\n\t\t}\n\t}\n};\n\n/**\n * Toggle positioning.\n *\n * Do not turn positioning on until after the element is attached to the DOM and visible.\n *\n * @param {boolean} [positioning] Enable positioning, omit to toggle\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.FloatableElement.prototype.togglePositioning = function ( positioning ) {\n\tvar closestScrollableOfContainer;\n\n\tif ( !this.$floatable || !this.$floatableContainer ) {\n\t\treturn this;\n\t}\n\n\tpositioning = positioning === undefined ? !this.positioning : !!positioning;\n\n\tif ( positioning && !this.warnedUnattached && !this.isElementAttached() ) {\n\t\tOO.ui.warnDeprecation( 'FloatableElement#togglePositioning: Before calling this method, the element must be attached to the DOM.' );\n\t\tthis.warnedUnattached = true;\n\t}\n\n\tif ( this.positioning !== positioning ) {\n\t\tthis.positioning = positioning;\n\n\t\tclosestScrollableOfContainer = OO.ui.Element.static.getClosestScrollableContainer(\n\t\t\tthis.$floatableContainer[ 0 ]\n\t\t);\n\t\t// If the scrollable is the root, we have to listen to scroll events\n\t\t// on the window because of browser inconsistencies.\n\t\tif ( $( closestScrollableOfContainer ).is( 'html, body' ) ) {\n\t\t\tclosestScrollableOfContainer = OO.ui.Element.static.getWindow(\n\t\t\t\tclosestScrollableOfContainer\n\t\t\t);\n\t\t}\n\n\t\tif ( positioning ) {\n\t\t\tthis.$floatableWindow = $( this.getElementWindow() );\n\t\t\tthis.$floatableWindow.on( 'resize', this.onFloatableWindowResizeHandler );\n\n\t\t\tthis.$floatableClosestScrollable = $( closestScrollableOfContainer );\n\t\t\tthis.$floatableClosestScrollable.on( 'scroll', this.onFloatableScrollHandler );\n\n\t\t\t// Initial position after visible\n\t\t\tthis.position();\n\t\t} else {\n\t\t\tif ( this.$floatableWindow ) {\n\t\t\t\tthis.$floatableWindow.off( 'resize', this.onFloatableWindowResizeHandler );\n\t\t\t\tthis.$floatableWindow = null;\n\t\t\t}\n\n\t\t\tif ( this.$floatableClosestScrollable ) {\n\t\t\t\tthis.$floatableClosestScrollable.off( 'scroll', this.onFloatableScrollHandler );\n\t\t\t\tthis.$floatableClosestScrollable = null;\n\t\t\t}\n\n\t\t\tthis.$floatable.css( { left: '', right: '', top: '' } );\n\t\t}\n\t}\n\n\treturn this;\n};\n\n/**\n * Check whether the bottom edge of the given element is within the viewport of the given\n * container.\n *\n * @private\n * @param {jQuery} $element\n * @param {jQuery} $container\n * @return {boolean}\n */\nOO.ui.mixin.FloatableElement.prototype.isElementInViewport = function ( $element, $container ) {\n\tvar elemRect, contRect, topEdgeInBounds, bottomEdgeInBounds, leftEdgeInBounds,\n\t\trightEdgeInBounds, startEdgeInBounds, endEdgeInBounds, viewportSpacing,\n\t\tdirection = $element.css( 'direction' );\n\n\telemRect = $element[ 0 ].getBoundingClientRect();\n\tif ( $container[ 0 ] === window ) {\n\t\tviewportSpacing = OO.ui.getViewportSpacing();\n\t\tcontRect = {\n\t\t\ttop: 0,\n\t\t\tleft: 0,\n\t\t\tright: document.documentElement.clientWidth,\n\t\t\tbottom: document.documentElement.clientHeight\n\t\t};\n\t\tcontRect.top += viewportSpacing.top;\n\t\tcontRect.left += viewportSpacing.left;\n\t\tcontRect.right -= viewportSpacing.right;\n\t\tcontRect.bottom -= viewportSpacing.bottom;\n\t} else {\n\t\tcontRect = $container[ 0 ].getBoundingClientRect();\n\t}\n\n\ttopEdgeInBounds = elemRect.top >= contRect.top && elemRect.top <= contRect.bottom;\n\tbottomEdgeInBounds = elemRect.bottom >= contRect.top && elemRect.bottom <= contRect.bottom;\n\tleftEdgeInBounds = elemRect.left >= contRect.left && elemRect.left <= contRect.right;\n\trightEdgeInBounds = elemRect.right >= contRect.left && elemRect.right <= contRect.right;\n\tif ( direction === 'rtl' ) {\n\t\tstartEdgeInBounds = rightEdgeInBounds;\n\t\tendEdgeInBounds = leftEdgeInBounds;\n\t} else {\n\t\tstartEdgeInBounds = leftEdgeInBounds;\n\t\tendEdgeInBounds = rightEdgeInBounds;\n\t}\n\n\tif ( this.verticalPosition === 'below' && !bottomEdgeInBounds ) {\n\t\treturn false;\n\t}\n\tif ( this.verticalPosition === 'above' && !topEdgeInBounds ) {\n\t\treturn false;\n\t}\n\tif ( this.horizontalPosition === 'before' && !startEdgeInBounds ) {\n\t\treturn false;\n\t}\n\tif ( this.horizontalPosition === 'after' && !endEdgeInBounds ) {\n\t\treturn false;\n\t}\n\n\t// The other positioning values are all about being inside the container,\n\t// so in those cases all we care about is that any part of the container is visible.\n\treturn elemRect.top <= contRect.bottom && elemRect.bottom >= contRect.top &&\n\t\telemRect.left <= contRect.right && elemRect.right >= contRect.left;\n};\n\n/**\n * Check if the floatable is hidden to the user because it was offscreen.\n *\n * @return {boolean} Floatable is out of view\n */\nOO.ui.mixin.FloatableElement.prototype.isFloatableOutOfView = function () {\n\treturn this.floatableOutOfView;\n};\n\n/**\n * Position the floatable below its container.\n *\n * This should only be done when both of them are attached to the DOM and visible.\n *\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.FloatableElement.prototype.position = function () {\n\tif ( !this.positioning ) {\n\t\treturn this;\n\t}\n\n\tif ( !(\n\t\t// To continue, some things need to be true:\n\t\t// The element must actually be in the DOM\n\t\tthis.isElementAttached() && (\n\t\t\t// The closest scrollable is the current window\n\t\t\tthis.$floatableClosestScrollable[ 0 ] === this.getElementWindow() ||\n\t\t\t// OR is an element in the element's DOM\n\t\t\t$.contains( this.getElementDocument(), this.$floatableClosestScrollable[ 0 ] )\n\t\t)\n\t) ) {\n\t\t// Abort early if important parts of the widget are no longer attached to the DOM\n\t\treturn this;\n\t}\n\n\tthis.floatableOutOfView = this.hideWhenOutOfView &&\n\t\t!this.isElementInViewport( this.$floatableContainer, this.$floatableClosestScrollable );\n\tif ( this.floatableOutOfView ) {\n\t\tthis.$floatable.addClass( 'oo-ui-element-hidden' );\n\t\treturn this;\n\t} else {\n\t\tthis.$floatable.removeClass( 'oo-ui-element-hidden' );\n\t}\n\n\tthis.$floatable.css( this.computePosition() );\n\n\t// We updated the position, so re-evaluate the clipping state.\n\t// (ClippableElement does not listen to 'scroll' events on $floatableContainer's parent, and so\n\t// will not notice the need to update itself.)\n\t// TODO: This is terrible, we shouldn't need to know about ClippableElement at all here.\n\t// Why does it not listen to the right events in the right places?\n\tif ( this.clip ) {\n\t\tthis.clip();\n\t}\n\n\treturn this;\n};\n\n/**\n * Compute how #$floatable should be positioned based on the position of #$floatableContainer\n * and the positioning settings. This is a helper for #position that shouldn't be called directly,\n * but may be overridden by subclasses if they want to change or add to the positioning logic.\n *\n * @return {Object} New position to apply with .css(). Keys are 'top', 'left', 'bottom' and 'right'.\n */\nOO.ui.mixin.FloatableElement.prototype.computePosition = function () {\n\tvar isBody, scrollableX, scrollableY, containerPos,\n\t\thorizScrollbarHeight, vertScrollbarWidth, scrollTop, scrollLeft,\n\t\tnewPos = { top: '', left: '', bottom: '', right: '' },\n\t\tdirection = this.$floatableContainer.css( 'direction' ),\n\t\t$offsetParent = this.$floatable.offsetParent();\n\n\tif ( $offsetParent.is( 'html' ) ) {\n\t\t// The innerHeight/Width and clientHeight/Width calculations don't work well on the\n\t\t// <html> element, but they do work on the <body>\n\t\t$offsetParent = $( $offsetParent[ 0 ].ownerDocument.body );\n\t}\n\tisBody = $offsetParent.is( 'body' );\n\tscrollableX = $offsetParent.css( 'overflow-x' ) === 'scroll' ||\n\t\t$offsetParent.css( 'overflow-x' ) === 'auto';\n\tscrollableY = $offsetParent.css( 'overflow-y' ) === 'scroll' ||\n\t\t$offsetParent.css( 'overflow-y' ) === 'auto';\n\n\tvertScrollbarWidth = $offsetParent.innerWidth() - $offsetParent.prop( 'clientWidth' );\n\thorizScrollbarHeight = $offsetParent.innerHeight() - $offsetParent.prop( 'clientHeight' );\n\t// We don't need to compute and add scrollTop and scrollLeft if the scrollable container\n\t// is the body, or if it isn't scrollable\n\tscrollTop = scrollableY && !isBody ?\n\t\t$offsetParent.scrollTop() : 0;\n\tscrollLeft = scrollableX && !isBody ?\n\t\tOO.ui.Element.static.getScrollLeft( $offsetParent[ 0 ] ) : 0;\n\n\t// Avoid passing the <body> to getRelativePosition(), because it won't return what we expect\n\t// if the <body> has a margin\n\tcontainerPos = isBody ?\n\t\tthis.$floatableContainer.offset() :\n\t\tOO.ui.Element.static.getRelativePosition( this.$floatableContainer, $offsetParent );\n\tcontainerPos.bottom = containerPos.top + this.$floatableContainer.outerHeight();\n\tcontainerPos.right = containerPos.left + this.$floatableContainer.outerWidth();\n\tcontainerPos.start = direction === 'rtl' ? containerPos.right : containerPos.left;\n\tcontainerPos.end = direction === 'rtl' ? containerPos.left : containerPos.right;\n\n\tif ( this.verticalPosition === 'below' ) {\n\t\tnewPos.top = containerPos.bottom;\n\t} else if ( this.verticalPosition === 'above' ) {\n\t\tnewPos.bottom = $offsetParent.outerHeight() - containerPos.top;\n\t} else if ( this.verticalPosition === 'top' ) {\n\t\tnewPos.top = containerPos.top;\n\t} else if ( this.verticalPosition === 'bottom' ) {\n\t\tnewPos.bottom = $offsetParent.outerHeight() - containerPos.bottom;\n\t} else if ( this.verticalPosition === 'center' ) {\n\t\tnewPos.top = containerPos.top +\n\t\t\t( this.$floatableContainer.height() - this.$floatable.height() ) / 2;\n\t}\n\n\tif ( this.horizontalPosition === 'before' ) {\n\t\tnewPos.end = containerPos.start;\n\t} else if ( this.horizontalPosition === 'after' ) {\n\t\tnewPos.start = containerPos.end;\n\t} else if ( this.horizontalPosition === 'start' ) {\n\t\tnewPos.start = containerPos.start;\n\t} else if ( this.horizontalPosition === 'end' ) {\n\t\tnewPos.end = containerPos.end;\n\t} else if ( this.horizontalPosition === 'center' ) {\n\t\tnewPos.left = containerPos.left +\n\t\t\t( this.$floatableContainer.width() - this.$floatable.width() ) / 2;\n\t}\n\n\tif ( newPos.start !== undefined ) {\n\t\tif ( direction === 'rtl' ) {\n\t\t\tnewPos.right = ( isBody ? $( $offsetParent[ 0 ].ownerDocument.documentElement ) :\n\t\t\t\t$offsetParent ).outerWidth() - newPos.start;\n\t\t} else {\n\t\t\tnewPos.left = newPos.start;\n\t\t}\n\t\tdelete newPos.start;\n\t}\n\tif ( newPos.end !== undefined ) {\n\t\tif ( direction === 'rtl' ) {\n\t\t\tnewPos.left = newPos.end;\n\t\t} else {\n\t\t\tnewPos.right = ( isBody ? $( $offsetParent[ 0 ].ownerDocument.documentElement ) :\n\t\t\t\t$offsetParent ).outerWidth() - newPos.end;\n\t\t}\n\t\tdelete newPos.end;\n\t}\n\n\t// Account for scroll position\n\tif ( newPos.top !== '' ) {\n\t\tnewPos.top += scrollTop;\n\t}\n\tif ( newPos.bottom !== '' ) {\n\t\tnewPos.bottom -= scrollTop;\n\t}\n\tif ( newPos.left !== '' ) {\n\t\tnewPos.left += scrollLeft;\n\t}\n\tif ( newPos.right !== '' ) {\n\t\tnewPos.right -= scrollLeft;\n\t}\n\n\t// Account for scrollbar gutter\n\tif ( newPos.bottom !== '' ) {\n\t\tnewPos.bottom -= horizScrollbarHeight;\n\t}\n\tif ( direction === 'rtl' ) {\n\t\tif ( newPos.left !== '' ) {\n\t\t\tnewPos.left -= vertScrollbarWidth;\n\t\t}\n\t} else {\n\t\tif ( newPos.right !== '' ) {\n\t\t\tnewPos.right -= vertScrollbarWidth;\n\t\t}\n\t}\n\n\treturn newPos;\n};\n","/**\n * Element that can be automatically clipped to visible boundaries.\n *\n * Whenever the element's natural height changes, you have to call\n * {@link OO.ui.mixin.ClippableElement#clip} to make sure it's still\n * clipping correctly.\n *\n * The dimensions of #$clippableContainer will be compared to the boundaries of the\n * nearest scrollable container. If #$clippableContainer is too tall and/or too wide,\n * then #$clippable will be given a fixed reduced height and/or width and will be made\n * scrollable. By default, #$clippable and #$clippableContainer are the same element,\n * but you can build a static footer by setting #$clippableContainer to an element that contains\n * #$clippable and the footer.\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$clippable] Node to clip, assigned to #$clippable, omit to use #$element\n * @cfg {jQuery} [$clippableContainer] Node to keep visible, assigned to #$clippableContainer,\n *   omit to use #$clippable\n */\nOO.ui.mixin.ClippableElement = function OoUiMixinClippableElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.$clippable = null;\n\tthis.$clippableContainer = null;\n\tthis.clipping = false;\n\tthis.clippedHorizontally = false;\n\tthis.clippedVertically = false;\n\tthis.$clippableScrollableContainer = null;\n\tthis.$clippableScroller = null;\n\tthis.$clippableWindow = null;\n\tthis.idealWidth = null;\n\tthis.idealHeight = null;\n\tthis.onClippableScrollHandler = this.clip.bind( this );\n\tthis.onClippableWindowResizeHandler = this.clip.bind( this );\n\n\t// Initialization\n\tif ( config.$clippableContainer ) {\n\t\tthis.setClippableContainer( config.$clippableContainer );\n\t}\n\tthis.setClippableElement( config.$clippable || this.$element );\n};\n\n/* Methods */\n\n/**\n * Set clippable element.\n *\n * If an element is already set, it will be cleaned up before setting up the new element.\n *\n * @param {jQuery} $clippable Element to make clippable\n */\nOO.ui.mixin.ClippableElement.prototype.setClippableElement = function ( $clippable ) {\n\tif ( this.$clippable ) {\n\t\tthis.$clippable.removeClass( 'oo-ui-clippableElement-clippable' );\n\t\tthis.$clippable.css( { width: '', height: '', overflowX: '', overflowY: '' } );\n\t\tOO.ui.Element.static.reconsiderScrollbars( this.$clippable[ 0 ] );\n\t}\n\n\tthis.$clippable = $clippable.addClass( 'oo-ui-clippableElement-clippable' );\n\tthis.clip();\n};\n\n/**\n * Set clippable container.\n *\n * This is the container that will be measured when deciding whether to clip. When clipping,\n * #$clippable will be resized in order to keep the clippable container fully visible.\n *\n * If the clippable container is unset, #$clippable will be used.\n *\n * @param {jQuery|null} $clippableContainer Container to keep visible, or null to unset\n */\nOO.ui.mixin.ClippableElement.prototype.setClippableContainer = function ( $clippableContainer ) {\n\tthis.$clippableContainer = $clippableContainer;\n\tif ( this.$clippable ) {\n\t\tthis.clip();\n\t}\n};\n\n/**\n * Toggle clipping.\n *\n * Do not turn clipping on until after the element is attached to the DOM and visible.\n *\n * @param {boolean} [clipping] Enable clipping, omit to toggle\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.ClippableElement.prototype.toggleClipping = function ( clipping ) {\n\tclipping = clipping === undefined ? !this.clipping : !!clipping;\n\n\tif ( clipping && !this.warnedUnattached && !this.isElementAttached() ) {\n\t\tOO.ui.warnDeprecation( 'ClippableElement#toggleClipping: Before calling this method, the element must be attached to the DOM.' );\n\t\tthis.warnedUnattached = true;\n\t}\n\n\tif ( this.clipping !== clipping ) {\n\t\tthis.clipping = clipping;\n\t\tif ( clipping ) {\n\t\t\tthis.$clippableScrollableContainer = $( this.getClosestScrollableElementContainer() );\n\t\t\t// If the clippable container is the root, we have to listen to scroll events and check\n\t\t\t// jQuery.scrollTop on the window because of browser inconsistencies\n\t\t\tthis.$clippableScroller = this.$clippableScrollableContainer.is( 'html, body' ) ?\n\t\t\t\t$( OO.ui.Element.static.getWindow( this.$clippableScrollableContainer ) ) :\n\t\t\t\tthis.$clippableScrollableContainer;\n\t\t\tthis.$clippableScroller.on( 'scroll', this.onClippableScrollHandler );\n\t\t\tthis.$clippableWindow = $( this.getElementWindow() )\n\t\t\t\t.on( 'resize', this.onClippableWindowResizeHandler );\n\t\t\t// Initial clip after visible\n\t\t\tthis.clip();\n\t\t} else {\n\t\t\tthis.$clippable.css( {\n\t\t\t\twidth: '',\n\t\t\t\theight: '',\n\t\t\t\tmaxWidth: '',\n\t\t\t\tmaxHeight: '',\n\t\t\t\toverflowX: '',\n\t\t\t\toverflowY: ''\n\t\t\t} );\n\t\t\tOO.ui.Element.static.reconsiderScrollbars( this.$clippable[ 0 ] );\n\n\t\t\tthis.$clippableScrollableContainer = null;\n\t\t\tthis.$clippableScroller.off( 'scroll', this.onClippableScrollHandler );\n\t\t\tthis.$clippableScroller = null;\n\t\t\tthis.$clippableWindow.off( 'resize', this.onClippableWindowResizeHandler );\n\t\t\tthis.$clippableWindow = null;\n\t\t}\n\t}\n\n\treturn this;\n};\n\n/**\n * Check if the element will be clipped to fit the visible area of the nearest scrollable container.\n *\n * @return {boolean} Element will be clipped to the visible area\n */\nOO.ui.mixin.ClippableElement.prototype.isClipping = function () {\n\treturn this.clipping;\n};\n\n/**\n * Check if the bottom or right of the element is being clipped by the nearest scrollable container.\n *\n * @return {boolean} Part of the element is being clipped\n */\nOO.ui.mixin.ClippableElement.prototype.isClipped = function () {\n\treturn this.clippedHorizontally || this.clippedVertically;\n};\n\n/**\n * Check if the right of the element is being clipped by the nearest scrollable container.\n *\n * @return {boolean} Part of the element is being clipped\n */\nOO.ui.mixin.ClippableElement.prototype.isClippedHorizontally = function () {\n\treturn this.clippedHorizontally;\n};\n\n/**\n * Check if the bottom of the element is being clipped by the nearest scrollable container.\n *\n * @return {boolean} Part of the element is being clipped\n */\nOO.ui.mixin.ClippableElement.prototype.isClippedVertically = function () {\n\treturn this.clippedVertically;\n};\n\n/**\n * Set the ideal size. These are the dimensions #$clippable will have when it's not being clipped.\n *\n * @param {number|string} [width] Width as a number of pixels or CSS string with unit suffix\n * @param {number|string} [height] Height as a number of pixels or CSS string with unit suffix\n */\nOO.ui.mixin.ClippableElement.prototype.setIdealSize = function ( width, height ) {\n\tthis.idealWidth = width;\n\tthis.idealHeight = height;\n\n\tif ( !this.clipping ) {\n\t\t// Update dimensions\n\t\tthis.$clippable.css( { width: width, height: height } );\n\t}\n\t// While clipping, idealWidth and idealHeight are not considered\n};\n\n/**\n * Return the side of the clippable on which it is \"anchored\" (aligned to something else).\n * ClippableElement will clip the opposite side when reducing element's width.\n *\n * Classes that mix in ClippableElement should override this to return 'right' if their\n * clippable is absolutely positioned and using 'right: Npx' (and not using 'left').\n * If your class also mixes in FloatableElement, this is handled automatically.\n *\n * (This can't be guessed from the actual CSS because the computed values for 'left'/'right' are\n * always in pixels, even if they were unset or set to 'auto'.)\n *\n * When in doubt, 'left' (or 'right' in RTL) is a sane fallback.\n *\n * @return {string} 'left' or 'right'\n */\nOO.ui.mixin.ClippableElement.prototype.getHorizontalAnchorEdge = function () {\n\tif ( this.computePosition && this.positioning && this.computePosition().right !== '' ) {\n\t\treturn 'right';\n\t}\n\treturn 'left';\n};\n\n/**\n * Return the side of the clippable on which it is \"anchored\" (aligned to something else).\n * ClippableElement will clip the opposite side when reducing element's width.\n *\n * Classes that mix in ClippableElement should override this to return 'bottom' if their\n * clippable is absolutely positioned and using 'bottom: Npx' (and not using 'top').\n * If your class also mixes in FloatableElement, this is handled automatically.\n *\n * (This can't be guessed from the actual CSS because the computed values for 'left'/'right' are\n * always in pixels, even if they were unset or set to 'auto'.)\n *\n * When in doubt, 'top' is a sane fallback.\n *\n * @return {string} 'top' or 'bottom'\n */\nOO.ui.mixin.ClippableElement.prototype.getVerticalAnchorEdge = function () {\n\tif ( this.computePosition && this.positioning && this.computePosition().bottom !== '' ) {\n\t\treturn 'bottom';\n\t}\n\treturn 'top';\n};\n\n/**\n * Clip element to visible boundaries and allow scrolling when needed. You should call this method\n * when the element's natural height changes.\n *\n * Element will be clipped the bottom or right of the element is within 10px of the edge of, or\n * overlapped by, the visible area of the nearest scrollable container.\n *\n * Because calling clip() when the natural height changes isn't always possible, we also set\n * max-height when the element isn't being clipped. This means that if the element tries to grow\n * beyond the edge, something reasonable will happen before clip() is called.\n *\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.ClippableElement.prototype.clip = function () {\n\tvar extraHeight, extraWidth, viewportSpacing,\n\t\tdesiredWidth, desiredHeight, allotedWidth, allotedHeight,\n\t\tnaturalWidth, naturalHeight, clipWidth, clipHeight,\n\t\t$item, itemRect, $viewport, viewportRect, availableRect,\n\t\tdirection, vertScrollbarWidth, horizScrollbarHeight,\n\t\t// Extra tolerance so that the sloppy code below doesn't result in results that are off\n\t\t// by one or two pixels. (And also so that we have space to display drop shadows.)\n\t\t// Chosen by fair dice roll.\n\t\tbuffer = 7;\n\n\tif ( !this.clipping ) {\n\t\t// this.$clippableScrollableContainer and this.$clippableWindow are null, so the below\n\t\t// will fail\n\t\treturn this;\n\t}\n\n\tfunction rectIntersection( a, b ) {\n\t\tvar out = {};\n\t\tout.top = Math.max( a.top, b.top );\n\t\tout.left = Math.max( a.left, b.left );\n\t\tout.bottom = Math.min( a.bottom, b.bottom );\n\t\tout.right = Math.min( a.right, b.right );\n\t\treturn out;\n\t}\n\n\tviewportSpacing = OO.ui.getViewportSpacing();\n\n\tif ( this.$clippableScrollableContainer.is( 'html, body' ) ) {\n\t\t$viewport = $( this.$clippableScrollableContainer[ 0 ].ownerDocument.body );\n\t\t// Dimensions of the browser window, rather than the element!\n\t\tviewportRect = {\n\t\t\ttop: 0,\n\t\t\tleft: 0,\n\t\t\tright: document.documentElement.clientWidth,\n\t\t\tbottom: document.documentElement.clientHeight\n\t\t};\n\t\tviewportRect.top += viewportSpacing.top;\n\t\tviewportRect.left += viewportSpacing.left;\n\t\tviewportRect.right -= viewportSpacing.right;\n\t\tviewportRect.bottom -= viewportSpacing.bottom;\n\t} else {\n\t\t$viewport = this.$clippableScrollableContainer;\n\t\tviewportRect = $viewport[ 0 ].getBoundingClientRect();\n\t\t// Convert into a plain object\n\t\tviewportRect = $.extend( {}, viewportRect );\n\t}\n\n\t// Account for scrollbar gutter\n\tdirection = $viewport.css( 'direction' );\n\tvertScrollbarWidth = $viewport.innerWidth() - $viewport.prop( 'clientWidth' );\n\thorizScrollbarHeight = $viewport.innerHeight() - $viewport.prop( 'clientHeight' );\n\tviewportRect.bottom -= horizScrollbarHeight;\n\tif ( direction === 'rtl' ) {\n\t\tviewportRect.left += vertScrollbarWidth;\n\t} else {\n\t\tviewportRect.right -= vertScrollbarWidth;\n\t}\n\n\t// Add arbitrary tolerance\n\tviewportRect.top += buffer;\n\tviewportRect.left += buffer;\n\tviewportRect.right -= buffer;\n\tviewportRect.bottom -= buffer;\n\n\t$item = this.$clippableContainer || this.$clippable;\n\n\textraHeight = $item.outerHeight() - this.$clippable.outerHeight();\n\textraWidth = $item.outerWidth() - this.$clippable.outerWidth();\n\n\titemRect = $item[ 0 ].getBoundingClientRect();\n\t// Convert into a plain object\n\titemRect = $.extend( {}, itemRect );\n\n\t// Item might already be clipped, so we can't just use its dimensions (in case we might need to\n\t// make it larger than before). Extend the rectangle to the maximum size we are allowed to take.\n\tif ( this.getHorizontalAnchorEdge() === 'right' ) {\n\t\titemRect.left = viewportRect.left;\n\t} else {\n\t\titemRect.right = viewportRect.right;\n\t}\n\tif ( this.getVerticalAnchorEdge() === 'bottom' ) {\n\t\titemRect.top = viewportRect.top;\n\t} else {\n\t\titemRect.bottom = viewportRect.bottom;\n\t}\n\n\tavailableRect = rectIntersection( viewportRect, itemRect );\n\n\tdesiredWidth = Math.max( 0, availableRect.right - availableRect.left );\n\tdesiredHeight = Math.max( 0, availableRect.bottom - availableRect.top );\n\t// It should never be desirable to exceed the dimensions of the browser viewport... right?\n\tdesiredWidth = Math.min( desiredWidth,\n\t\tdocument.documentElement.clientWidth - viewportSpacing.left - viewportSpacing.right );\n\tdesiredHeight = Math.min( desiredHeight,\n\t\tdocument.documentElement.clientHeight - viewportSpacing.top - viewportSpacing.right );\n\tallotedWidth = Math.ceil( desiredWidth - extraWidth );\n\tallotedHeight = Math.ceil( desiredHeight - extraHeight );\n\tnaturalWidth = this.$clippable.prop( 'scrollWidth' );\n\tnaturalHeight = this.$clippable.prop( 'scrollHeight' );\n\tclipWidth = allotedWidth < naturalWidth;\n\tclipHeight = allotedHeight < naturalHeight;\n\n\tif ( clipWidth ) {\n\t\t// The order matters here. If overflow is not set first, Chrome displays bogus scrollbars.\n\t\t// See T157672.\n\t\t// Forcing a reflow is a smaller workaround than calling reconsiderScrollbars() for\n\t\t// this case.\n\t\tthis.$clippable.css( 'overflowX', 'scroll' );\n\t\t// eslint-disable-next-line no-void\n\t\tvoid this.$clippable[ 0 ].offsetHeight; // Force reflow\n\t\tthis.$clippable.css( {\n\t\t\twidth: Math.max( 0, allotedWidth ),\n\t\t\tmaxWidth: ''\n\t\t} );\n\t} else {\n\t\tthis.$clippable.css( {\n\t\t\toverflowX: '',\n\t\t\twidth: this.idealWidth || '',\n\t\t\tmaxWidth: Math.max( 0, allotedWidth )\n\t\t} );\n\t}\n\tif ( clipHeight ) {\n\t\t// The order matters here. If overflow is not set first, Chrome displays bogus scrollbars.\n\t\t// See T157672.\n\t\t// Forcing a reflow is a smaller workaround than calling reconsiderScrollbars() for\n\t\t// this case.\n\t\tthis.$clippable.css( 'overflowY', 'scroll' );\n\t\t// eslint-disable-next-line no-void\n\t\tvoid this.$clippable[ 0 ].offsetHeight; // Force reflow\n\t\tthis.$clippable.css( {\n\t\t\theight: Math.max( 0, allotedHeight ),\n\t\t\tmaxHeight: ''\n\t\t} );\n\t} else {\n\t\tthis.$clippable.css( {\n\t\t\toverflowY: '',\n\t\t\theight: this.idealHeight || '',\n\t\t\tmaxHeight: Math.max( 0, allotedHeight )\n\t\t} );\n\t}\n\n\t// If we stopped clipping in at least one of the dimensions\n\tif ( ( this.clippedHorizontally && !clipWidth ) || ( this.clippedVertically && !clipHeight ) ) {\n\t\tOO.ui.Element.static.reconsiderScrollbars( this.$clippable[ 0 ] );\n\t}\n\n\tthis.clippedHorizontally = clipWidth;\n\tthis.clippedVertically = clipHeight;\n\n\treturn this;\n};\n","/**\n * PopupWidget is a container for content. The popup is overlaid and positioned absolutely.\n * By default, each popup has an anchor that points toward its origin.\n * Please see the [OOUI documentation on MediaWiki.org] [1] for more information and examples.\n *\n * Unlike most widgets, PopupWidget is initially hidden and must be shown by calling #toggle.\n *\n *     @example\n *     // A PopupWidget.\n *     var popup = new OO.ui.PopupWidget( {\n *         $content: $( '<p>Hi there!</p>' ),\n *         padded: true,\n *         width: 300\n *     } );\n *\n *     $( document.body ).append( popup.$element );\n *     // To display the popup, toggle the visibility to 'true'.\n *     popup.toggle( true );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Popups\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.ClippableElement\n * @mixins OO.ui.mixin.FloatableElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {number|null} [width=320] Width of popup in pixels. Pass `null` to use automatic width.\n * @cfg {number|null} [height=null] Height of popup in pixels. Pass `null` to use automatic height.\n * @cfg {boolean} [anchor=true] Show anchor pointing to origin of popup\n * @cfg {string} [position='below'] Where to position the popup relative to $floatableContainer\n *  'above': Put popup above $floatableContainer; anchor points down to the horizontal center\n *    of $floatableContainer\n *  'below': Put popup below $floatableContainer; anchor points up to the horizontal center\n *    of $floatableContainer\n *  'before': Put popup to the left (LTR) / right (RTL) of $floatableContainer; anchor points\n *    endwards (right/left) to the vertical center of $floatableContainer\n *  'after': Put popup to the right (LTR) / left (RTL) of $floatableContainer; anchor points\n *    startwards (left/right) to the vertical center of $floatableContainer\n * @cfg {string} [align='center'] How to align the popup to $floatableContainer\n *  'forwards': If position is above/below, move the popup as far endwards (right in LTR, left in\n *    RTL) as possible while still keeping the anchor within the popup; if position is before/after,\n *    move the popup as far downwards as possible.\n *  'backwards': If position is above/below, move the popup as far startwards (left in LTR, right in\n *    RTL) as possible while still keeping the anchor within the popup; if position is before/after,\n *     move the popup as far upwards as possible.\n *  'center': Horizontally (if position is above/below) or vertically (before/after) align the\n *     center of the popup with the center of $floatableContainer.\n * 'force-left': Alias for 'forwards' in LTR and 'backwards' in RTL\n * 'force-right': Alias for 'backwards' in RTL and 'forwards' in LTR\n * @cfg {boolean} [autoFlip=true] Whether to automatically switch the popup's position between\n *  'above' and 'below', or between 'before' and 'after', if there is not enough space in the\n *  desired direction to display the popup without clipping\n * @cfg {jQuery} [$container] Constrain the popup to the boundaries of the specified container.\n *  See the [OOUI docs on MediaWiki][3] for an example.\n *  [3]: https://www.mediawiki.org/wiki/OOUI/Widgets/Popups#containerExample\n * @cfg {number} [containerPadding=10] Padding between the popup and its container, specified as a\n *  number of pixels.\n * @cfg {jQuery} [$content] Content to append to the popup's body\n * @cfg {jQuery} [$footer] Content to append to the popup's footer\n * @cfg {boolean} [autoClose=false] Automatically close the popup when it loses focus.\n * @cfg {jQuery} [$autoCloseIgnore] Elements that will not close the popup when clicked.\n *  This config option is only relevant if #autoClose is set to `true`. See the\n *  [OOUI documentation on MediaWiki][2] for an example.\n *  [2]: https://www.mediawiki.org/wiki/OOUI/Widgets/Popups#autocloseExample\n * @cfg {boolean} [head=false] Show a popup header that contains a #label (if specified) and close\n *  button.\n * @cfg {boolean} [padded=false] Add padding to the popup's body\n */\nOO.ui.PopupWidget = function OoUiPopupWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.PopupWidget.parent.call( this, config );\n\n\t// Properties (must be set before ClippableElement constructor call)\n\tthis.$body = $( '<div>' );\n\tthis.$popup = $( '<div>' );\n\n\t// Mixin constructors\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.ClippableElement.call( this, $.extend( {\n\t\t$clippable: this.$body,\n\t\t$clippableContainer: this.$popup\n\t}, config ) );\n\tOO.ui.mixin.FloatableElement.call( this, config );\n\n\t// Properties\n\tthis.$anchor = $( '<div>' );\n\t// If undefined, will be computed lazily in computePosition()\n\tthis.$container = config.$container;\n\tthis.containerPadding = config.containerPadding !== undefined ? config.containerPadding : 10;\n\tthis.autoClose = !!config.autoClose;\n\tthis.transitionTimeout = null;\n\tthis.anchored = false;\n\tthis.onDocumentMouseDownHandler = this.onDocumentMouseDown.bind( this );\n\tthis.onDocumentKeyDownHandler = this.onDocumentKeyDown.bind( this );\n\n\t// Initialization\n\tthis.setSize( config.width, config.height );\n\tthis.toggleAnchor( config.anchor === undefined || config.anchor );\n\tthis.setAlignment( config.align || 'center' );\n\tthis.setPosition( config.position || 'below' );\n\tthis.setAutoFlip( config.autoFlip === undefined || config.autoFlip );\n\tthis.setAutoCloseIgnore( config.$autoCloseIgnore );\n\tthis.$body.addClass( 'oo-ui-popupWidget-body' );\n\tthis.$anchor.addClass( 'oo-ui-popupWidget-anchor' );\n\tthis.$popup\n\t\t.addClass( 'oo-ui-popupWidget-popup' )\n\t\t.append( this.$body );\n\tthis.$element\n\t\t.addClass( 'oo-ui-popupWidget' )\n\t\t.append( this.$popup, this.$anchor );\n\t// Move content, which was added to #$element by OO.ui.Widget, to the body\n\t// FIXME This is gross, we should use '$body' or something for the config\n\tif ( config.$content instanceof $ ) {\n\t\tthis.$body.append( config.$content );\n\t}\n\n\tif ( config.padded ) {\n\t\tthis.$body.addClass( 'oo-ui-popupWidget-body-padded' );\n\t}\n\n\tif ( config.head ) {\n\t\tthis.closeButton = new OO.ui.ButtonWidget( {\n\t\t\tframed: false,\n\t\t\ticon: 'close'\n\t\t} );\n\t\tthis.closeButton.connect( this, {\n\t\t\tclick: 'onCloseButtonClick'\n\t\t} );\n\t\tthis.$head = $( '<div>' )\n\t\t\t.addClass( 'oo-ui-popupWidget-head' )\n\t\t\t.append( this.$label, this.closeButton.$element );\n\t\tthis.$popup.prepend( this.$head );\n\t}\n\n\tif ( config.$footer ) {\n\t\tthis.$footer = $( '<div>' )\n\t\t\t.addClass( 'oo-ui-popupWidget-footer' )\n\t\t\t.append( config.$footer );\n\t\tthis.$popup.append( this.$footer );\n\t}\n\n\t// Initially hidden - using #toggle may cause errors if subclasses override toggle with methods\n\t// that reference properties not initialized at that time of parent class construction\n\t// TODO: Find a better way to handle post-constructor setup\n\tthis.visible = false;\n\tthis.$element.addClass( 'oo-ui-element-hidden' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.PopupWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.PopupWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.PopupWidget, OO.ui.mixin.ClippableElement );\nOO.mixinClass( OO.ui.PopupWidget, OO.ui.mixin.FloatableElement );\n\n/* Events */\n\n/**\n * @event ready\n *\n * The popup is ready: it is visible and has been positioned and clipped.\n */\n\n/* Methods */\n\n/**\n * Handles document mouse down events.\n *\n * @private\n * @param {MouseEvent} e Mouse down event\n */\nOO.ui.PopupWidget.prototype.onDocumentMouseDown = function ( e ) {\n\tif (\n\t\tthis.isVisible() &&\n\t\t!OO.ui.contains( this.$element.add( this.$autoCloseIgnore ).get(), e.target, true )\n\t) {\n\t\tthis.toggle( false );\n\t}\n};\n\n/**\n * Bind document mouse down listener.\n *\n * @private\n */\nOO.ui.PopupWidget.prototype.bindDocumentMouseDownListener = function () {\n\t// Capture clicks outside popup\n\tthis.getElementDocument().addEventListener( 'mousedown', this.onDocumentMouseDownHandler, true );\n\t// We add 'click' event because iOS safari needs to respond to this event.\n\t// We can't use 'touchstart' (as is usually the equivalent to 'mousedown') because\n\t// then it will trigger when scrolling. While iOS Safari has some reported behavior\n\t// of occasionally not emitting 'click' properly, that event seems to be the standard\n\t// that it should be emitting, so we add it to this and will operate the event handler\n\t// on whichever of these events was triggered first\n\tthis.getElementDocument().addEventListener( 'click', this.onDocumentMouseDownHandler, true );\n};\n\n/**\n * Handles close button click events.\n *\n * @private\n */\nOO.ui.PopupWidget.prototype.onCloseButtonClick = function () {\n\tif ( this.isVisible() ) {\n\t\tthis.toggle( false );\n\t}\n};\n\n/**\n * Unbind document mouse down listener.\n *\n * @private\n */\nOO.ui.PopupWidget.prototype.unbindDocumentMouseDownListener = function () {\n\tthis.getElementDocument().removeEventListener( 'mousedown', this.onDocumentMouseDownHandler, true );\n\tthis.getElementDocument().removeEventListener( 'click', this.onDocumentMouseDownHandler, true );\n};\n\n/**\n * Handles document key down events.\n *\n * @private\n * @param {KeyboardEvent} e Key down event\n */\nOO.ui.PopupWidget.prototype.onDocumentKeyDown = function ( e ) {\n\tif (\n\t\te.which === OO.ui.Keys.ESCAPE &&\n\t\tthis.isVisible()\n\t) {\n\t\tthis.toggle( false );\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t}\n};\n\n/**\n * Bind document key down listener.\n *\n * @private\n */\nOO.ui.PopupWidget.prototype.bindDocumentKeyDownListener = function () {\n\tthis.getElementDocument().addEventListener( 'keydown', this.onDocumentKeyDownHandler, true );\n};\n\n/**\n * Unbind document key down listener.\n *\n * @private\n */\nOO.ui.PopupWidget.prototype.unbindDocumentKeyDownListener = function () {\n\tthis.getElementDocument().removeEventListener( 'keydown', this.onDocumentKeyDownHandler, true );\n};\n\n/**\n * Show, hide, or toggle the visibility of the anchor.\n *\n * @param {boolean} [show] Show anchor, omit to toggle\n */\nOO.ui.PopupWidget.prototype.toggleAnchor = function ( show ) {\n\tshow = show === undefined ? !this.anchored : !!show;\n\n\tif ( this.anchored !== show ) {\n\t\tif ( show ) {\n\t\t\tthis.$element.addClass( 'oo-ui-popupWidget-anchored' );\n\t\t\tthis.$element.addClass( 'oo-ui-popupWidget-anchored-' + this.anchorEdge );\n\t\t} else {\n\t\t\tthis.$element.removeClass( 'oo-ui-popupWidget-anchored' );\n\t\t\tthis.$element.removeClass( 'oo-ui-popupWidget-anchored-' + this.anchorEdge );\n\t\t}\n\t\tthis.anchored = show;\n\t}\n};\n\n/**\n * Change which edge the anchor appears on.\n *\n * @param {string} edge 'top', 'bottom', 'start' or 'end'\n */\nOO.ui.PopupWidget.prototype.setAnchorEdge = function ( edge ) {\n\tif ( [ 'top', 'bottom', 'start', 'end' ].indexOf( edge ) === -1 ) {\n\t\tthrow new Error( 'Invalid value for edge: ' + edge );\n\t}\n\tif ( this.anchorEdge !== null ) {\n\t\tthis.$element.removeClass( 'oo-ui-popupWidget-anchored-' + this.anchorEdge );\n\t}\n\tthis.anchorEdge = edge;\n\tif ( this.anchored ) {\n\t\tthis.$element.addClass( 'oo-ui-popupWidget-anchored-' + edge );\n\t}\n};\n\n/**\n * Check if the anchor is visible.\n *\n * @return {boolean} Anchor is visible\n */\nOO.ui.PopupWidget.prototype.hasAnchor = function () {\n\treturn this.anchored;\n};\n\n/**\n * Toggle visibility of the popup. The popup is initially hidden and must be shown by calling\n * `.toggle( true )` after its #$element is attached to the DOM.\n *\n * Do not show the popup while it is not attached to the DOM. The calculations required to display\n * it in the right place and with the right dimensions only work correctly while it is attached.\n * Side-effects may include broken interface and exceptions being thrown. This wasn't always\n * strictly enforced, so currently it only generates a warning in the browser console.\n *\n * @fires ready\n * @inheritdoc\n */\nOO.ui.PopupWidget.prototype.toggle = function ( show ) {\n\tvar change, normalHeight, oppositeHeight, normalWidth, oppositeWidth;\n\tshow = show === undefined ? !this.isVisible() : !!show;\n\n\tchange = show !== this.isVisible();\n\n\tif ( show && !this.warnedUnattached && !this.isElementAttached() ) {\n\t\tOO.ui.warnDeprecation( 'PopupWidget#toggle: Before calling this method, the popup must be attached to the DOM.' );\n\t\tthis.warnedUnattached = true;\n\t}\n\tif ( show && !this.$floatableContainer && this.isElementAttached() ) {\n\t\t// Fall back to the parent node if the floatableContainer is not set\n\t\tthis.setFloatableContainer( this.$element.parent() );\n\t}\n\n\tif ( change && show && this.autoFlip ) {\n\t\t// Reset auto-flipping before showing the popup again. It's possible we no longer need to\n\t\t// flip (e.g. if the user scrolled).\n\t\tthis.isAutoFlipped = false;\n\t}\n\n\t// Parent method\n\tOO.ui.PopupWidget.parent.prototype.toggle.call( this, show );\n\n\tif ( change ) {\n\t\tthis.togglePositioning( show && !!this.$floatableContainer );\n\n\t\tif ( show ) {\n\t\t\tif ( this.autoClose ) {\n\t\t\t\tthis.bindDocumentMouseDownListener();\n\t\t\t\tthis.bindDocumentKeyDownListener();\n\t\t\t}\n\t\t\tthis.updateDimensions();\n\t\t\tthis.toggleClipping( true );\n\n\t\t\tif ( this.autoFlip ) {\n\t\t\t\tif ( this.popupPosition === 'above' || this.popupPosition === 'below' ) {\n\t\t\t\t\tif ( this.isClippedVertically() || this.isFloatableOutOfView() ) {\n\t\t\t\t\t\t// If opening the popup in the normal direction causes it to be clipped,\n\t\t\t\t\t\t// open in the opposite one instead\n\t\t\t\t\t\tnormalHeight = this.$element.height();\n\t\t\t\t\t\tthis.isAutoFlipped = !this.isAutoFlipped;\n\t\t\t\t\t\tthis.position();\n\t\t\t\t\t\tif ( this.isClippedVertically() || this.isFloatableOutOfView() ) {\n\t\t\t\t\t\t\t// If that also causes it to be clipped, open in whichever direction\n\t\t\t\t\t\t\t// we have more space\n\t\t\t\t\t\t\toppositeHeight = this.$element.height();\n\t\t\t\t\t\t\tif ( oppositeHeight < normalHeight ) {\n\t\t\t\t\t\t\t\tthis.isAutoFlipped = !this.isAutoFlipped;\n\t\t\t\t\t\t\t\tthis.position();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif ( this.popupPosition === 'before' || this.popupPosition === 'after' ) {\n\t\t\t\t\tif ( this.isClippedHorizontally() || this.isFloatableOutOfView() ) {\n\t\t\t\t\t\t// If opening the popup in the normal direction causes it to be clipped,\n\t\t\t\t\t\t// open in the opposite one instead\n\t\t\t\t\t\tnormalWidth = this.$element.width();\n\t\t\t\t\t\tthis.isAutoFlipped = !this.isAutoFlipped;\n\t\t\t\t\t\t// Due to T180173 horizontally clipped PopupWidgets have messed up\n\t\t\t\t\t\t// dimensions, which causes positioning to be off. Toggle clipping back and\n\t\t\t\t\t\t// forth to work around.\n\t\t\t\t\t\tthis.toggleClipping( false );\n\t\t\t\t\t\tthis.position();\n\t\t\t\t\t\tthis.toggleClipping( true );\n\t\t\t\t\t\tif ( this.isClippedHorizontally() || this.isFloatableOutOfView() ) {\n\t\t\t\t\t\t\t// If that also causes it to be clipped, open in whichever direction\n\t\t\t\t\t\t\t// we have more space\n\t\t\t\t\t\t\toppositeWidth = this.$element.width();\n\t\t\t\t\t\t\tif ( oppositeWidth < normalWidth ) {\n\t\t\t\t\t\t\t\tthis.isAutoFlipped = !this.isAutoFlipped;\n\t\t\t\t\t\t\t\t// Due to T180173, horizontally clipped PopupWidgets have messed up\n\t\t\t\t\t\t\t\t// dimensions, which causes positioning to be off. Toggle clipping\n\t\t\t\t\t\t\t\t// back and forth to work around.\n\t\t\t\t\t\t\t\tthis.toggleClipping( false );\n\t\t\t\t\t\t\t\tthis.position();\n\t\t\t\t\t\t\t\tthis.toggleClipping( true );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.emit( 'ready' );\n\t\t} else {\n\t\t\tthis.toggleClipping( false );\n\t\t\tif ( this.autoClose ) {\n\t\t\t\tthis.unbindDocumentMouseDownListener();\n\t\t\t\tthis.unbindDocumentKeyDownListener();\n\t\t\t}\n\t\t}\n\t}\n\n\treturn this;\n};\n\n/**\n * Set the size of the popup.\n *\n * Changing the size may also change the popup's position depending on the alignment.\n *\n * @param {number|null} [width=320] Width in pixels. Pass `null` to use automatic width.\n * @param {number|null} [height=null] Height in pixels. Pass `null` to use automatic height.\n * @param {boolean} [transition=false] Use a smooth transition\n * @chainable\n */\nOO.ui.PopupWidget.prototype.setSize = function ( width, height, transition ) {\n\tthis.width = width !== undefined ? width : 320;\n\tthis.height = height !== undefined ? height : null;\n\tif ( this.isVisible() ) {\n\t\tthis.updateDimensions( transition );\n\t}\n};\n\n/**\n * Update the size and position.\n *\n * Only use this to keep the popup properly anchored. Use #setSize to change the size, and this will\n * be called automatically.\n *\n * @param {boolean} [transition=false] Use a smooth transition\n * @chainable\n */\nOO.ui.PopupWidget.prototype.updateDimensions = function ( transition ) {\n\tvar widget = this;\n\n\t// Prevent transition from being interrupted\n\tclearTimeout( this.transitionTimeout );\n\tif ( transition ) {\n\t\t// Enable transition\n\t\tthis.$element.addClass( 'oo-ui-popupWidget-transitioning' );\n\t}\n\n\tthis.position();\n\n\tif ( transition ) {\n\t\t// Prevent transitioning after transition is complete\n\t\tthis.transitionTimeout = setTimeout( function () {\n\t\t\twidget.$element.removeClass( 'oo-ui-popupWidget-transitioning' );\n\t\t}, 200 );\n\t} else {\n\t\t// Prevent transitioning immediately\n\t\tthis.$element.removeClass( 'oo-ui-popupWidget-transitioning' );\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.PopupWidget.prototype.computePosition = function () {\n\tvar direction, align, vertical, start, end, near, far, sizeProp, popupSize, anchorSize,\n\t\tanchorPos, anchorOffset, anchorMargin, parentPosition, positionProp, positionAdjustment,\n\t\tfloatablePos, offsetParentPos, containerPos, popupPosition, viewportSpacing,\n\t\tpopupPos = {},\n\t\tanchorCss = { left: '', right: '', top: '', bottom: '' },\n\t\tpopupPositionOppositeMap = {\n\t\t\tabove: 'below',\n\t\t\tbelow: 'above',\n\t\t\tbefore: 'after',\n\t\t\tafter: 'before'\n\t\t},\n\t\talignMap = {\n\t\t\tltr: {\n\t\t\t\t'force-left': 'backwards',\n\t\t\t\t'force-right': 'forwards'\n\t\t\t},\n\t\t\trtl: {\n\t\t\t\t'force-left': 'forwards',\n\t\t\t\t'force-right': 'backwards'\n\t\t\t}\n\t\t},\n\t\tanchorEdgeMap = {\n\t\t\tabove: 'bottom',\n\t\t\tbelow: 'top',\n\t\t\tbefore: 'end',\n\t\t\tafter: 'start'\n\t\t},\n\t\thPosMap = {\n\t\t\tforwards: 'start',\n\t\t\tcenter: 'center',\n\t\t\tbackwards: this.anchored ? 'before' : 'end'\n\t\t},\n\t\tvPosMap = {\n\t\t\tforwards: 'top',\n\t\t\tcenter: 'center',\n\t\t\tbackwards: 'bottom'\n\t\t};\n\n\tif ( !this.$container ) {\n\t\t// Lazy-initialize $container if not specified in constructor\n\t\tthis.$container = $( this.getClosestScrollableElementContainer() );\n\t}\n\tdirection = this.$container.css( 'direction' );\n\n\t// Set height and width before we do anything else, since it might cause our measurements\n\t// to change (e.g. due to scrollbars appearing or disappearing), and it also affects centering\n\tthis.$popup.css( {\n\t\twidth: this.width !== null ? this.width : 'auto',\n\t\theight: this.height !== null ? this.height : 'auto'\n\t} );\n\n\talign = alignMap[ direction ][ this.align ] || this.align;\n\tpopupPosition = this.popupPosition;\n\tif ( this.isAutoFlipped ) {\n\t\tpopupPosition = popupPositionOppositeMap[ popupPosition ];\n\t}\n\n\t// If the popup is positioned before or after, then the anchor positioning is vertical,\n\t// otherwise horizontal\n\tvertical = popupPosition === 'before' || popupPosition === 'after';\n\tstart = vertical ? 'top' : ( direction === 'rtl' ? 'right' : 'left' );\n\tend = vertical ? 'bottom' : ( direction === 'rtl' ? 'left' : 'right' );\n\tnear = vertical ? 'top' : 'left';\n\tfar = vertical ? 'bottom' : 'right';\n\tsizeProp = vertical ? 'Height' : 'Width';\n\tpopupSize = vertical ?\n\t\t( this.height || this.$popup.height() ) :\n\t\t( this.width || this.$popup.width() );\n\n\tthis.setAnchorEdge( anchorEdgeMap[ popupPosition ] );\n\tthis.horizontalPosition = vertical ? popupPosition : hPosMap[ align ];\n\tthis.verticalPosition = vertical ? vPosMap[ align ] : popupPosition;\n\n\t// Parent method\n\tparentPosition = OO.ui.mixin.FloatableElement.prototype.computePosition.call( this );\n\t// Find out which property FloatableElement used for positioning, and adjust that value\n\tpositionProp = vertical ?\n\t\t( parentPosition.top !== '' ? 'top' : 'bottom' ) :\n\t\t( parentPosition.left !== '' ? 'left' : 'right' );\n\n\t// Figure out where the near and far edges of the popup and $floatableContainer are\n\tfloatablePos = this.$floatableContainer.offset();\n\tfloatablePos[ far ] = floatablePos[ near ] + this.$floatableContainer[ 'outer' + sizeProp ]();\n\t// Measure where the offsetParent is and compute our position based on that and parentPosition\n\toffsetParentPos = this.$element.offsetParent()[ 0 ] === document.documentElement ?\n\t\t{ top: 0, left: 0 } :\n\t\tthis.$element.offsetParent().offset();\n\n\tif ( positionProp === near ) {\n\t\tpopupPos[ near ] = offsetParentPos[ near ] + parentPosition[ near ];\n\t\tpopupPos[ far ] = popupPos[ near ] + popupSize;\n\t} else {\n\t\tpopupPos[ far ] = offsetParentPos[ near ] +\n\t\t\tthis.$element.offsetParent()[ 'inner' + sizeProp ]() - parentPosition[ far ];\n\t\tpopupPos[ near ] = popupPos[ far ] - popupSize;\n\t}\n\n\tif ( this.anchored ) {\n\t\t// Position the anchor (which is positioned relative to the popup) to point to\n\t\t// $floatableContainer\n\t\tanchorPos = ( floatablePos[ start ] + floatablePos[ end ] ) / 2;\n\t\tanchorOffset = ( start === far ? -1 : 1 ) * ( anchorPos - popupPos[ start ] );\n\n\t\t// If the anchor is less than 2*anchorSize from either edge, move the popup to make more\n\t\t// space this.$anchor.width()/height() returns 0 because of the CSS trickery we use, so use\n\t\t// scrollWidth/Height\n\t\tanchorSize = this.$anchor[ 0 ][ 'scroll' + sizeProp ];\n\t\tanchorMargin = parseFloat( this.$anchor.css( 'margin-' + start ) );\n\t\tif ( anchorOffset + anchorMargin < 2 * anchorSize ) {\n\t\t\t// Not enough space for the anchor on the start side; pull the popup startwards\n\t\t\tpositionAdjustment = ( positionProp === start ? -1 : 1 ) *\n\t\t\t\t( 2 * anchorSize - ( anchorOffset + anchorMargin ) );\n\t\t} else if ( anchorOffset + anchorMargin > popupSize - 2 * anchorSize ) {\n\t\t\t// Not enough space for the anchor on the end side; pull the popup endwards\n\t\t\tpositionAdjustment = ( positionProp === end ? -1 : 1 ) *\n\t\t\t\t( anchorOffset + anchorMargin - ( popupSize - 2 * anchorSize ) );\n\t\t} else {\n\t\t\tpositionAdjustment = 0;\n\t\t}\n\t} else {\n\t\tpositionAdjustment = 0;\n\t}\n\n\t// Check if the popup will go beyond the edge of this.$container\n\tcontainerPos = this.$container[ 0 ] === document.documentElement ?\n\t\t{ top: 0, left: 0 } :\n\t\tthis.$container.offset();\n\tcontainerPos[ far ] = containerPos[ near ] + this.$container[ 'inner' + sizeProp ]();\n\tif ( this.$container[ 0 ] === document.documentElement ) {\n\t\tviewportSpacing = OO.ui.getViewportSpacing();\n\t\tcontainerPos[ near ] += viewportSpacing[ near ];\n\t\tcontainerPos[ far ] -= viewportSpacing[ far ];\n\t}\n\t// Take into account how much the popup will move because of the adjustments we're going to make\n\tpopupPos[ near ] += ( positionProp === near ? 1 : -1 ) * positionAdjustment;\n\tpopupPos[ far ] += ( positionProp === near ? 1 : -1 ) * positionAdjustment;\n\tif ( containerPos[ near ] + this.containerPadding > popupPos[ near ] ) {\n\t\t// Popup goes beyond the near (left/top) edge, move it to the right/bottom\n\t\tpositionAdjustment += ( positionProp === near ? 1 : -1 ) *\n\t\t\t( containerPos[ near ] + this.containerPadding - popupPos[ near ] );\n\t} else if ( containerPos[ far ] - this.containerPadding < popupPos[ far ] ) {\n\t\t// Popup goes beyond the far (right/bottom) edge, move it to the left/top\n\t\tpositionAdjustment += ( positionProp === far ? 1 : -1 ) *\n\t\t\t( popupPos[ far ] - ( containerPos[ far ] - this.containerPadding ) );\n\t}\n\n\tif ( this.anchored ) {\n\t\t// Adjust anchorOffset for positionAdjustment\n\t\tanchorOffset += ( positionProp === start ? -1 : 1 ) * positionAdjustment;\n\n\t\t// Position the anchor\n\t\tanchorCss[ start ] = anchorOffset;\n\t\tthis.$anchor.css( anchorCss );\n\t}\n\n\t// Move the popup if needed\n\tparentPosition[ positionProp ] += positionAdjustment;\n\n\treturn parentPosition;\n};\n\n/**\n * Set popup alignment\n *\n * @param {string} [align=center] Alignment of the popup, `center`, `force-left`, `force-right`,\n *  `backwards` or `forwards`.\n */\nOO.ui.PopupWidget.prototype.setAlignment = function ( align ) {\n\t// Validate alignment\n\tif ( [ 'force-left', 'force-right', 'backwards', 'forwards', 'center' ].indexOf( align ) > -1 ) {\n\t\tthis.align = align;\n\t} else {\n\t\tthis.align = 'center';\n\t}\n\tthis.position();\n};\n\n/**\n * Get popup alignment\n *\n * @return {string} Alignment of the popup, `center`, `force-left`, `force-right`,\n *  `backwards` or `forwards`.\n */\nOO.ui.PopupWidget.prototype.getAlignment = function () {\n\treturn this.align;\n};\n\n/**\n * Change the positioning of the popup.\n *\n * @param {string} position 'above', 'below', 'before' or 'after'\n */\nOO.ui.PopupWidget.prototype.setPosition = function ( position ) {\n\tif ( [ 'above', 'below', 'before', 'after' ].indexOf( position ) === -1 ) {\n\t\tposition = 'below';\n\t}\n\tthis.popupPosition = position;\n\tthis.position();\n};\n\n/**\n * Get popup positioning.\n *\n * @return {string} 'above', 'below', 'before' or 'after'\n */\nOO.ui.PopupWidget.prototype.getPosition = function () {\n\treturn this.popupPosition;\n};\n\n/**\n * Set popup auto-flipping.\n *\n * @param {boolean} autoFlip Whether to automatically switch the popup's position between\n *  'above' and 'below', or between 'before' and 'after', if there is not enough space in the\n *  desired direction to display the popup without clipping\n */\nOO.ui.PopupWidget.prototype.setAutoFlip = function ( autoFlip ) {\n\tautoFlip = !!autoFlip;\n\n\tif ( this.autoFlip !== autoFlip ) {\n\t\tthis.autoFlip = autoFlip;\n\t}\n};\n\n/**\n * Set which elements will not close the popup when clicked.\n *\n * For auto-closing popups, clicks on these elements will not cause the popup to auto-close.\n *\n * @param {jQuery} $autoCloseIgnore Elements to ignore for auto-closing\n */\nOO.ui.PopupWidget.prototype.setAutoCloseIgnore = function ( $autoCloseIgnore ) {\n\tthis.$autoCloseIgnore = $autoCloseIgnore;\n};\n\n/**\n * Get an ID of the body element, this can be used as the\n * `aria-describedby` attribute for an input field.\n *\n * @return {string} The ID of the body element\n */\nOO.ui.PopupWidget.prototype.getBodyId = function () {\n\tvar id = this.$body.attr( 'id' );\n\tif ( id === undefined ) {\n\t\tid = OO.ui.generateElementId();\n\t\tthis.$body.attr( 'id', id );\n\t}\n\treturn id;\n};\n","/**\n * PopupElement is mixed into other classes to generate a {@link OO.ui.PopupWidget popup widget}.\n * A popup is a container for content. It is overlaid and positioned absolutely. By default, each\n * popup has an anchor, which is an arrow-like protrusion that points toward the popup’s origin.\n * See {@link OO.ui.PopupWidget PopupWidget} for an example.\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {Object} [popup] Configuration to pass to popup\n * @cfg {boolean} [popup.autoClose=true] Popup auto-closes when it loses focus\n */\nOO.ui.mixin.PopupElement = function OoUiMixinPopupElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties\n\tthis.popup = new OO.ui.PopupWidget( $.extend(\n\t\t{\n\t\t\tautoClose: true,\n\t\t\t$floatableContainer: this.$element\n\t\t},\n\t\tconfig.popup,\n\t\t{\n\t\t\t$autoCloseIgnore: this.$element.add( config.popup && config.popup.$autoCloseIgnore )\n\t\t}\n\t) );\n};\n\n/* Methods */\n\n/**\n * Get popup.\n *\n * @return {OO.ui.PopupWidget} Popup widget\n */\nOO.ui.mixin.PopupElement.prototype.getPopup = function () {\n\treturn this.popup;\n};\n","/**\n * PopupButtonWidgets toggle the visibility of a contained {@link OO.ui.PopupWidget PopupWidget},\n * which is used to display additional information or options.\n *\n *     @example\n *     // A PopupButtonWidget.\n *     var popupButton = new OO.ui.PopupButtonWidget( {\n *         label: 'Popup button with options',\n *         icon: 'menu',\n *         popup: {\n *             $content: $( '<p>Additional options here.</p>' ),\n *             padded: true,\n *             align: 'force-left'\n *         }\n *     } );\n *     // Append the button to the DOM.\n *     $( document.body ).append( popupButton.$element );\n *\n * @class\n * @extends OO.ui.ButtonWidget\n * @mixins OO.ui.mixin.PopupElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$overlay] Render the popup into a separate layer. This configuration is useful\n *  in cases where the expanded popup is larger than its containing `<div>`. The specified overlay\n *  layer is usually on top of the containing `<div>` and has a larger area. By default, the popup\n *  uses relative positioning.\n *  See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.\n */\nOO.ui.PopupButtonWidget = function OoUiPopupButtonWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.PopupButtonWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.PopupElement.call( this, config );\n\n\t// Properties\n\tthis.$overlay = ( config.$overlay === true ?\n\t\tOO.ui.getDefaultOverlay() : config.$overlay ) || this.$element;\n\n\t// Events\n\tthis.connect( this, {\n\t\tclick: 'onAction'\n\t} );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-popupButtonWidget' );\n\tthis.popup.$element\n\t\t.addClass( 'oo-ui-popupButtonWidget-popup' )\n\t\t.toggleClass( 'oo-ui-popupButtonWidget-framed-popup', this.isFramed() )\n\t\t.toggleClass( 'oo-ui-popupButtonWidget-frameless-popup', !this.isFramed() );\n\tthis.$overlay.append( this.popup.$element );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.PopupButtonWidget, OO.ui.ButtonWidget );\nOO.mixinClass( OO.ui.PopupButtonWidget, OO.ui.mixin.PopupElement );\n\n/* Methods */\n\n/**\n * Handle the button action being triggered.\n *\n * @private\n */\nOO.ui.PopupButtonWidget.prototype.onAction = function () {\n\tthis.popup.toggle();\n};\n","/**\n * Mixin for OO.ui.Widget subclasses to provide OO.ui.mixin.GroupElement.\n *\n * Use together with OO.ui.mixin.ItemWidget to make disabled state inheritable.\n *\n * @private\n * @abstract\n * @class\n * @mixins OO.ui.mixin.GroupElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.mixin.GroupWidget = function OoUiMixinGroupWidget( config ) {\n\t// Mixin constructors\n\tOO.ui.mixin.GroupElement.call( this, config );\n};\n\n/* Setup */\n\nOO.mixinClass( OO.ui.mixin.GroupWidget, OO.ui.mixin.GroupElement );\n\n/* Methods */\n\n/**\n * Set the disabled state of the widget.\n *\n * This will also update the disabled state of child widgets.\n *\n * @param {boolean} disabled Disable widget\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.mixin.GroupWidget.prototype.setDisabled = function ( disabled ) {\n\tvar i, len;\n\n\t// Parent method\n\t// Note: Calling #setDisabled this way assumes this is mixed into an OO.ui.Widget\n\tOO.ui.Widget.prototype.setDisabled.call( this, disabled );\n\n\t// During construction, #setDisabled is called before the OO.ui.mixin.GroupElement constructor\n\tif ( this.items ) {\n\t\tfor ( i = 0, len = this.items.length; i < len; i++ ) {\n\t\t\tthis.items[ i ].updateDisabled();\n\t\t}\n\t}\n\n\treturn this;\n};\n","/**\n * Mixin for widgets used as items in widgets that mix in OO.ui.mixin.GroupWidget.\n *\n * Item widgets have a reference to a OO.ui.mixin.GroupWidget while they are attached to the group.\n * This allows bidirectional communication.\n *\n * Use together with OO.ui.mixin.GroupWidget to make disabled state inheritable.\n *\n * @private\n * @abstract\n * @class\n *\n * @constructor\n */\nOO.ui.mixin.ItemWidget = function OoUiMixinItemWidget() {\n\t//\n};\n\n/* Methods */\n\n/**\n * Check if widget is disabled.\n *\n * Checks parent if present, making disabled state inheritable.\n *\n * @return {boolean} Widget is disabled\n */\nOO.ui.mixin.ItemWidget.prototype.isDisabled = function () {\n\treturn this.disabled ||\n\t\t( this.elementGroup instanceof OO.ui.Widget && this.elementGroup.isDisabled() );\n};\n\n/**\n * Set group element is in.\n *\n * @param {OO.ui.mixin.GroupElement|null} group Group element, null if none\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.mixin.ItemWidget.prototype.setElementGroup = function ( group ) {\n\t// Parent method\n\t// Note: Calling #setElementGroup this way assumes this is mixed into an OO.ui.Element\n\tOO.ui.Element.prototype.setElementGroup.call( this, group );\n\n\t// Initialize item disabled states\n\tthis.updateDisabled();\n\n\treturn this;\n};\n","/**\n * OptionWidgets are special elements that can be selected and configured with data. The\n * data is often unique for each option, but it does not have to be. OptionWidgets are used\n * with OO.ui.SelectWidget to create a selection of mutually exclusive options. For more information\n * and examples, please see the [OOUI documentation on MediaWiki][1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.ItemWidget\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.FlaggedElement\n * @mixins OO.ui.mixin.AccessKeyedElement\n * @mixins OO.ui.mixin.TitledElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.OptionWidget = function OoUiOptionWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.OptionWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.ItemWidget.call( this );\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.FlaggedElement.call( this, config );\n\tOO.ui.mixin.AccessKeyedElement.call( this, config );\n\tOO.ui.mixin.TitledElement.call( this, config );\n\n\t// Properties\n\tthis.highlighted = false;\n\tthis.pressed = false;\n\tthis.setSelected( !!config.selected );\n\n\t// Initialization\n\tthis.$element\n\t\t.data( 'oo-ui-optionWidget', this )\n\t\t// Allow programmatic focussing (and by access key), but not tabbing\n\t\t.attr( 'tabindex', '-1' )\n\t\t.attr( 'role', 'option' )\n\t\t.addClass( 'oo-ui-optionWidget' )\n\t\t.append( this.$label );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.OptionWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.ItemWidget );\nOO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.FlaggedElement );\nOO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.AccessKeyedElement );\nOO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.TitledElement );\n\n/* Static Properties */\n\n/**\n * Whether this option can be selected. See #setSelected.\n *\n * @static\n * @inheritable\n * @property {boolean}\n */\nOO.ui.OptionWidget.static.selectable = true;\n\n/**\n * Whether this option can be highlighted. See #setHighlighted.\n *\n * @static\n * @inheritable\n * @property {boolean}\n */\nOO.ui.OptionWidget.static.highlightable = true;\n\n/**\n * Whether this option can be pressed. See #setPressed.\n *\n * @static\n * @inheritable\n * @property {boolean}\n */\nOO.ui.OptionWidget.static.pressable = true;\n\n/**\n * Whether this option will be scrolled into view when it is selected.\n *\n * @static\n * @inheritable\n * @property {boolean}\n */\nOO.ui.OptionWidget.static.scrollIntoViewOnSelect = false;\n\n/* Methods */\n\n/**\n * Check if the option can be selected.\n *\n * @return {boolean} Item is selectable\n */\nOO.ui.OptionWidget.prototype.isSelectable = function () {\n\treturn this.constructor.static.selectable && !this.disabled && this.isVisible();\n};\n\n/**\n * Check if the option can be highlighted. A highlight indicates that the option\n * may be selected when a user presses Enter key or clicks. Disabled items cannot\n * be highlighted.\n *\n * @return {boolean} Item is highlightable\n */\nOO.ui.OptionWidget.prototype.isHighlightable = function () {\n\treturn this.constructor.static.highlightable && !this.disabled && this.isVisible();\n};\n\n/**\n * Check if the option can be pressed. The pressed state occurs when a user mouses\n * down on an item, but has not yet let go of the mouse.\n *\n * @return {boolean} Item is pressable\n */\nOO.ui.OptionWidget.prototype.isPressable = function () {\n\treturn this.constructor.static.pressable && !this.disabled && this.isVisible();\n};\n\n/**\n * Check if the option is selected.\n *\n * @return {boolean} Item is selected\n */\nOO.ui.OptionWidget.prototype.isSelected = function () {\n\treturn this.selected;\n};\n\n/**\n * Check if the option is highlighted. A highlight indicates that the\n * item may be selected when a user presses Enter key or clicks.\n *\n * @return {boolean} Item is highlighted\n */\nOO.ui.OptionWidget.prototype.isHighlighted = function () {\n\treturn this.highlighted;\n};\n\n/**\n * Check if the option is pressed. The pressed state occurs when a user mouses\n * down on an item, but has not yet let go of the mouse. The item may appear\n * selected, but it will not be selected until the user releases the mouse.\n *\n * @return {boolean} Item is pressed\n */\nOO.ui.OptionWidget.prototype.isPressed = function () {\n\treturn this.pressed;\n};\n\n/**\n * Set the option’s selected state. In general, all modifications to the selection\n * should be handled by the SelectWidget’s\n * {@link OO.ui.SelectWidget#selectItem selectItem( [item] )} method instead of this method.\n *\n * @param {boolean} [state=false] Select option\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.OptionWidget.prototype.setSelected = function ( state ) {\n\tif ( this.constructor.static.selectable ) {\n\t\tthis.selected = !!state;\n\t\tthis.$element\n\t\t\t.toggleClass( 'oo-ui-optionWidget-selected', state )\n\t\t\t.attr( 'aria-selected', state.toString() );\n\t\tif ( state && this.constructor.static.scrollIntoViewOnSelect ) {\n\t\t\tthis.scrollElementIntoView();\n\t\t}\n\t\tthis.updateThemeClasses();\n\t}\n\treturn this;\n};\n\n/**\n * Set the option’s highlighted state. In general, all programmatic\n * modifications to the highlight should be handled by the\n * SelectWidget’s {@link OO.ui.SelectWidget#highlightItem highlightItem( [item] )}\n * method instead of this method.\n *\n * @param {boolean} [state=false] Highlight option\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.OptionWidget.prototype.setHighlighted = function ( state ) {\n\tif ( this.constructor.static.highlightable ) {\n\t\tthis.highlighted = !!state;\n\t\tthis.$element.toggleClass( 'oo-ui-optionWidget-highlighted', state );\n\t\tthis.updateThemeClasses();\n\t}\n\treturn this;\n};\n\n/**\n * Set the option’s pressed state. In general, all\n * programmatic modifications to the pressed state should be handled by the\n * SelectWidget’s {@link OO.ui.SelectWidget#pressItem pressItem( [item] )}\n * method instead of this method.\n *\n * @param {boolean} [state=false] Press option\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.OptionWidget.prototype.setPressed = function ( state ) {\n\tif ( this.constructor.static.pressable ) {\n\t\tthis.pressed = !!state;\n\t\tthis.$element.toggleClass( 'oo-ui-optionWidget-pressed', state );\n\t\tthis.updateThemeClasses();\n\t}\n\treturn this;\n};\n\n/**\n * Get text to match search strings against.\n *\n * The default implementation returns the label text, but subclasses\n * can override this to provide more complex behavior.\n *\n * @return {string|boolean} String to match search string against\n */\nOO.ui.OptionWidget.prototype.getMatchText = function () {\n\tvar label = this.getLabel();\n\treturn typeof label === 'string' ? label : this.$label.text();\n};\n","/**\n * A SelectWidget is of a generic selection of options. The OOUI library contains several types of\n * select widgets, including {@link OO.ui.ButtonSelectWidget button selects},\n * {@link OO.ui.RadioSelectWidget radio selects}, and {@link OO.ui.MenuSelectWidget\n * menu selects}.\n *\n * This class should be used together with OO.ui.OptionWidget or OO.ui.DecoratedOptionWidget. For\n * more information, please see the [OOUI documentation on MediaWiki][1].\n *\n *     @example\n *     // A select widget with three options.\n *     var select = new OO.ui.SelectWidget( {\n *         items: [\n *             new OO.ui.OptionWidget( {\n *                 data: 'a',\n *                 label: 'Option One',\n *             } ),\n *             new OO.ui.OptionWidget( {\n *                 data: 'b',\n *                 label: 'Option Two',\n *             } ),\n *             new OO.ui.OptionWidget( {\n *                 data: 'c',\n *                 label: 'Option Three',\n *             } )\n *         ]\n *     } );\n *     $( document.body ).append( select.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options\n *\n * @abstract\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.GroupWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {OO.ui.OptionWidget[]} [items] An array of options to add to the select.\n *  Options are created with {@link OO.ui.OptionWidget OptionWidget} classes. See\n *  the [OOUI documentation on MediaWiki] [2] for examples.\n *  [2]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options\n * @cfg {boolean} [multiselect] Allow for multiple selections\n */\nOO.ui.SelectWidget = function OoUiSelectWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.SelectWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.GroupWidget.call( this, $.extend( {\n\t\t$group: this.$element\n\t}, config ) );\n\n\t// Properties\n\tthis.pressed = false;\n\tthis.selecting = null;\n\tthis.multiselect = !!config.multiselect;\n\tthis.onDocumentMouseUpHandler = this.onDocumentMouseUp.bind( this );\n\tthis.onDocumentMouseMoveHandler = this.onDocumentMouseMove.bind( this );\n\tthis.onDocumentKeyDownHandler = this.onDocumentKeyDown.bind( this );\n\tthis.onDocumentKeyPressHandler = this.onDocumentKeyPress.bind( this );\n\tthis.keyPressBuffer = '';\n\tthis.keyPressBufferTimer = null;\n\tthis.blockMouseOverEvents = 0;\n\n\t// Events\n\tthis.connect( this, {\n\t\ttoggle: 'onToggle'\n\t} );\n\tthis.$element.on( {\n\t\tfocusin: this.onFocus.bind( this ),\n\t\tmousedown: this.onMouseDown.bind( this ),\n\t\tmouseover: this.onMouseOver.bind( this ),\n\t\tmouseleave: this.onMouseLeave.bind( this )\n\t} );\n\n\t// Initialization\n\tthis.$element\n\t\t// -depressed is a deprecated alias of -unpressed\n\t\t.addClass( 'oo-ui-selectWidget oo-ui-selectWidget-unpressed oo-ui-selectWidget-depressed' )\n\t\t.attr( 'role', 'listbox' );\n\tthis.setFocusOwner( this.$element );\n\tif ( Array.isArray( config.items ) ) {\n\t\tthis.addItems( config.items );\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.SelectWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.SelectWidget, OO.ui.mixin.GroupWidget );\n\n/* Events */\n\n/**\n * @event highlight\n *\n * A `highlight` event is emitted when the highlight is changed with the #highlightItem method.\n *\n * @param {OO.ui.OptionWidget|null} item Highlighted item\n */\n\n/**\n * @event press\n *\n * A `press` event is emitted when the #pressItem method is used to programmatically modify the\n * pressed state of an option.\n *\n * @param {OO.ui.OptionWidget|null} item Pressed item\n */\n\n/**\n * @event select\n *\n * A `select` event is emitted when the selection is modified programmatically with the #selectItem\n * method.\n *\n * @param {OO.ui.OptionWidget[]|OO.ui.OptionWidget|null} items Currently selected items\n */\n\n/**\n * @event choose\n *\n * A `choose` event is emitted when an item is chosen with the #chooseItem method.\n *\n * @param {OO.ui.OptionWidget} item Chosen item\n * @param {boolean} selected Item is selected\n */\n\n/**\n * @event add\n *\n * An `add` event is emitted when options are added to the select with the #addItems method.\n *\n * @param {OO.ui.OptionWidget[]} items Added items\n * @param {number} index Index of insertion point\n */\n\n/**\n * @event remove\n *\n * A `remove` event is emitted when options are removed from the select with the #clearItems\n * or #removeItems methods.\n *\n * @param {OO.ui.OptionWidget[]} items Removed items\n */\n\n/* Static methods */\n\n/**\n * Normalize text for filter matching\n *\n * @param {string} text Text\n * @return {string} Normalized text\n */\nOO.ui.SelectWidget.static.normalizeForMatching = function ( text ) {\n\t// Replace trailing whitespace, normalize multiple spaces and make case insensitive\n\tvar normalized = text.trim().replace( /\\s+/, ' ' ).toLowerCase();\n\n\t// Normalize Unicode\n\t// eslint-disable-next-line no-restricted-properties\n\tif ( normalized.normalize ) {\n\t\t// eslint-disable-next-line no-restricted-properties\n\t\tnormalized = normalized.normalize();\n\t}\n\treturn normalized;\n};\n\n/* Methods */\n\n/**\n * Handle focus events\n *\n * @private\n * @param {jQuery.Event} event\n */\nOO.ui.SelectWidget.prototype.onFocus = function ( event ) {\n\tvar item;\n\tif ( event.target === this.$element[ 0 ] ) {\n\t\t// This widget was focussed, e.g. by the user tabbing to it.\n\t\t// The styles for focus state depend on one of the items being selected.\n\t\tif ( !this.findSelectedItem() ) {\n\t\t\titem = this.findFirstSelectableItem();\n\t\t}\n\t} else {\n\t\tif ( event.target.tabIndex === -1 ) {\n\t\t\t// One of the options got focussed (and the event bubbled up here).\n\t\t\t// They can't be tabbed to, but they can be activated using access keys.\n\t\t\t// OptionWidgets and focusable UI elements inside them have tabindex=\"-1\" set.\n\t\t\titem = this.findTargetItem( event );\n\t\t} else {\n\t\t\t// There is something actually user-focusable in one of the labels of the options, and\n\t\t\t// the user focussed it (e.g. by tabbing to it). Do nothing (especially, don't change\n\t\t\t// the focus).\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif ( item ) {\n\t\tif ( item.constructor.static.highlightable ) {\n\t\t\tthis.highlightItem( item );\n\t\t} else {\n\t\t\tthis.selectItem( item );\n\t\t}\n\t}\n\n\tif ( event.target !== this.$element[ 0 ] ) {\n\t\tthis.$focusOwner.trigger( 'focus' );\n\t}\n};\n\n/**\n * Handle mouse down events.\n *\n * @private\n * @param {jQuery.Event} e Mouse down event\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.SelectWidget.prototype.onMouseDown = function ( e ) {\n\tvar item;\n\n\tif ( !this.isDisabled() && e.which === OO.ui.MouseButtons.LEFT ) {\n\t\tthis.togglePressed( true );\n\t\titem = this.findTargetItem( e );\n\t\tif ( item && item.isSelectable() ) {\n\t\t\tthis.pressItem( item );\n\t\t\tthis.selecting = item;\n\t\t\tthis.getElementDocument().addEventListener( 'mouseup', this.onDocumentMouseUpHandler, true );\n\t\t\tthis.getElementDocument().addEventListener( 'mousemove', this.onDocumentMouseMoveHandler, true );\n\t\t}\n\t}\n\treturn false;\n};\n\n/**\n * Handle document mouse up events.\n *\n * @private\n * @param {MouseEvent} e Mouse up event\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.SelectWidget.prototype.onDocumentMouseUp = function ( e ) {\n\tvar item;\n\n\tthis.togglePressed( false );\n\tif ( !this.selecting ) {\n\t\titem = this.findTargetItem( e );\n\t\tif ( item && item.isSelectable() ) {\n\t\t\tthis.selecting = item;\n\t\t}\n\t}\n\tif ( !this.isDisabled() && e.which === OO.ui.MouseButtons.LEFT && this.selecting ) {\n\t\tthis.pressItem( null );\n\t\tthis.chooseItem( this.selecting );\n\t\tthis.selecting = null;\n\t}\n\n\tthis.getElementDocument().removeEventListener( 'mouseup', this.onDocumentMouseUpHandler, true );\n\tthis.getElementDocument().removeEventListener( 'mousemove', this.onDocumentMouseMoveHandler, true );\n\n\treturn false;\n};\n\n/**\n * Handle document mouse move events.\n *\n * @private\n * @param {MouseEvent} e Mouse move event\n */\nOO.ui.SelectWidget.prototype.onDocumentMouseMove = function ( e ) {\n\tvar item;\n\n\tif ( !this.isDisabled() && this.pressed ) {\n\t\titem = this.findTargetItem( e );\n\t\tif ( item && item !== this.selecting && item.isSelectable() ) {\n\t\t\tthis.pressItem( item );\n\t\t\tthis.selecting = item;\n\t\t}\n\t}\n};\n\n/**\n * Handle mouse over events.\n *\n * @private\n * @param {jQuery.Event} e Mouse over event\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.SelectWidget.prototype.onMouseOver = function ( e ) {\n\tvar item;\n\tif ( this.blockMouseOverEvents ) {\n\t\treturn;\n\t}\n\tif ( !this.isDisabled() ) {\n\t\titem = this.findTargetItem( e );\n\t\tthis.highlightItem( item && item.isHighlightable() ? item : null );\n\t}\n\treturn false;\n};\n\n/**\n * Handle mouse leave events.\n *\n * @private\n * @param {jQuery.Event} e Mouse over event\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.SelectWidget.prototype.onMouseLeave = function () {\n\tif ( !this.isDisabled() ) {\n\t\tthis.highlightItem( null );\n\t}\n\treturn false;\n};\n\n/**\n * Handle document key down events.\n *\n * @protected\n * @param {KeyboardEvent} e Key down event\n */\nOO.ui.SelectWidget.prototype.onDocumentKeyDown = function ( e ) {\n\tvar nextItem,\n\t\thandled = false,\n\t\tcurrentItem = this.findHighlightedItem(),\n\t\tfirstItem = this.getItems()[ 0 ];\n\n\tif ( !this.isDisabled() && this.isVisible() ) {\n\t\tswitch ( e.keyCode ) {\n\t\t\tcase OO.ui.Keys.ENTER:\n\t\t\t\tif ( currentItem ) {\n\t\t\t\t\t// Was only highlighted, now let's select it. No-op if already selected.\n\t\t\t\t\tthis.chooseItem( currentItem );\n\t\t\t\t\thandled = true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase OO.ui.Keys.UP:\n\t\t\tcase OO.ui.Keys.LEFT:\n\t\t\t\tthis.clearKeyPressBuffer();\n\t\t\t\tnextItem = currentItem ?\n\t\t\t\t\tthis.findRelativeSelectableItem( currentItem, -1 ) : firstItem;\n\t\t\t\thandled = true;\n\t\t\t\tbreak;\n\t\t\tcase OO.ui.Keys.DOWN:\n\t\t\tcase OO.ui.Keys.RIGHT:\n\t\t\t\tthis.clearKeyPressBuffer();\n\t\t\t\tnextItem = currentItem ?\n\t\t\t\t\tthis.findRelativeSelectableItem( currentItem, 1 ) : firstItem;\n\t\t\t\thandled = true;\n\t\t\t\tbreak;\n\t\t\tcase OO.ui.Keys.ESCAPE:\n\t\t\tcase OO.ui.Keys.TAB:\n\t\t\t\tif ( currentItem ) {\n\t\t\t\t\tcurrentItem.setHighlighted( false );\n\t\t\t\t}\n\t\t\t\tthis.unbindDocumentKeyDownListener();\n\t\t\t\tthis.unbindDocumentKeyPressListener();\n\t\t\t\t// Don't prevent tabbing away / defocusing\n\t\t\t\thandled = false;\n\t\t\t\tbreak;\n\t\t}\n\n\t\tif ( nextItem ) {\n\t\t\tif ( nextItem.constructor.static.highlightable ) {\n\t\t\t\tthis.highlightItem( nextItem );\n\t\t\t} else {\n\t\t\t\tthis.chooseItem( nextItem );\n\t\t\t}\n\t\t\tthis.scrollItemIntoView( nextItem );\n\t\t}\n\n\t\tif ( handled ) {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t}\n\t}\n};\n\n/**\n * Bind document key down listener.\n *\n * @protected\n */\nOO.ui.SelectWidget.prototype.bindDocumentKeyDownListener = function () {\n\tthis.getElementDocument().addEventListener( 'keydown', this.onDocumentKeyDownHandler, true );\n};\n\n/**\n * Unbind document key down listener.\n *\n * @protected\n */\nOO.ui.SelectWidget.prototype.unbindDocumentKeyDownListener = function () {\n\tthis.getElementDocument().removeEventListener( 'keydown', this.onDocumentKeyDownHandler, true );\n};\n\n/**\n * Scroll item into view, preventing spurious mouse highlight actions from happening.\n *\n * @param {OO.ui.OptionWidget} item Item to scroll into view\n */\nOO.ui.SelectWidget.prototype.scrollItemIntoView = function ( item ) {\n\tvar widget = this;\n\t// Chromium's Blink engine will generate spurious 'mouseover' events during programmatic\n\t// scrolling and around 100-150 ms after it is finished.\n\tthis.blockMouseOverEvents++;\n\titem.scrollElementIntoView().done( function () {\n\t\tsetTimeout( function () {\n\t\t\twidget.blockMouseOverEvents--;\n\t\t}, 200 );\n\t} );\n};\n\n/**\n * Clear the key-press buffer\n *\n * @protected\n */\nOO.ui.SelectWidget.prototype.clearKeyPressBuffer = function () {\n\tif ( this.keyPressBufferTimer ) {\n\t\tclearTimeout( this.keyPressBufferTimer );\n\t\tthis.keyPressBufferTimer = null;\n\t}\n\tthis.keyPressBuffer = '';\n};\n\n/**\n * Handle key press events.\n *\n * @protected\n * @param {KeyboardEvent} e Key press event\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.SelectWidget.prototype.onDocumentKeyPress = function ( e ) {\n\tvar c, filter, item;\n\n\tif ( !e.charCode ) {\n\t\tif ( e.keyCode === OO.ui.Keys.BACKSPACE && this.keyPressBuffer !== '' ) {\n\t\t\tthis.keyPressBuffer = this.keyPressBuffer.substr( 0, this.keyPressBuffer.length - 1 );\n\t\t\treturn false;\n\t\t}\n\t\treturn;\n\t}\n\t// eslint-disable-next-line no-restricted-properties\n\tif ( String.fromCodePoint ) {\n\t\t// eslint-disable-next-line no-restricted-properties\n\t\tc = String.fromCodePoint( e.charCode );\n\t} else {\n\t\tc = String.fromCharCode( e.charCode );\n\t}\n\n\tif ( this.keyPressBufferTimer ) {\n\t\tclearTimeout( this.keyPressBufferTimer );\n\t}\n\tthis.keyPressBufferTimer = setTimeout( this.clearKeyPressBuffer.bind( this ), 1500 );\n\n\titem = this.findHighlightedItem() || this.findSelectedItem();\n\n\tif ( this.keyPressBuffer === c ) {\n\t\t// Common (if weird) special case: typing \"xxxx\" will cycle through all\n\t\t// the items beginning with \"x\".\n\t\tif ( item ) {\n\t\t\titem = this.findRelativeSelectableItem( item, 1 );\n\t\t}\n\t} else {\n\t\tthis.keyPressBuffer += c;\n\t}\n\n\tfilter = this.getItemMatcher( this.keyPressBuffer, false );\n\tif ( !item || !filter( item ) ) {\n\t\titem = this.findRelativeSelectableItem( item, 1, filter );\n\t}\n\tif ( item ) {\n\t\tif ( this.isVisible() && item.constructor.static.highlightable ) {\n\t\t\tthis.highlightItem( item );\n\t\t} else {\n\t\t\tthis.chooseItem( item );\n\t\t}\n\t\tthis.scrollItemIntoView( item );\n\t}\n\n\te.preventDefault();\n\te.stopPropagation();\n};\n\n/**\n * Get a matcher for the specific string\n *\n * @protected\n * @param {string} query String to match against items\n * @param {string} [mode='prefix'] Matching mode: 'substring', 'prefix', or 'exact'\n * @return {Function} function ( OO.ui.OptionWidget ) => boolean\n */\nOO.ui.SelectWidget.prototype.getItemMatcher = function ( query, mode ) {\n\tvar normalizeForMatching = this.constructor.static.normalizeForMatching,\n\t\tnormalizedQuery = normalizeForMatching( query );\n\n\t// Support deprecated exact=true argument\n\tif ( mode === true ) {\n\t\tmode = 'exact';\n\t}\n\n\treturn function ( item ) {\n\t\tvar matchText = normalizeForMatching( item.getMatchText() );\n\n\t\tif ( normalizedQuery === '' ) {\n\t\t\t// Empty string matches all, except if we are in 'exact'\n\t\t\t// mode, where it doesn't match at all\n\t\t\treturn mode !== 'exact';\n\t\t}\n\n\t\tswitch ( mode ) {\n\t\t\tcase 'exact':\n\t\t\t\treturn matchText === normalizedQuery;\n\t\t\tcase 'substring':\n\t\t\t\treturn matchText.indexOf( normalizedQuery ) !== -1;\n\t\t\t// 'prefix'\n\t\t\tdefault:\n\t\t\t\treturn matchText.indexOf( normalizedQuery ) === 0;\n\t\t}\n\t};\n};\n\n/**\n * Bind document key press listener.\n *\n * @protected\n */\nOO.ui.SelectWidget.prototype.bindDocumentKeyPressListener = function () {\n\tthis.getElementDocument().addEventListener( 'keypress', this.onDocumentKeyPressHandler, true );\n};\n\n/**\n * Unbind document key down listener.\n *\n * If you override this, be sure to call this.clearKeyPressBuffer() from your\n * implementation.\n *\n * @protected\n */\nOO.ui.SelectWidget.prototype.unbindDocumentKeyPressListener = function () {\n\tthis.getElementDocument().removeEventListener( 'keypress', this.onDocumentKeyPressHandler, true );\n\tthis.clearKeyPressBuffer();\n};\n\n/**\n * Visibility change handler\n *\n * @protected\n * @param {boolean} visible\n */\nOO.ui.SelectWidget.prototype.onToggle = function ( visible ) {\n\tif ( !visible ) {\n\t\tthis.clearKeyPressBuffer();\n\t}\n};\n\n/**\n * Get the closest item to a jQuery.Event.\n *\n * @private\n * @param {jQuery.Event} e\n * @return {OO.ui.OptionWidget|null} Outline item widget, `null` if none was found\n */\nOO.ui.SelectWidget.prototype.findTargetItem = function ( e ) {\n\tvar $option = $( e.target ).closest( '.oo-ui-optionWidget' );\n\tif ( !$option.closest( '.oo-ui-selectWidget' ).is( this.$element ) ) {\n\t\treturn null;\n\t}\n\treturn $option.data( 'oo-ui-optionWidget' ) || null;\n};\n\n/**\n * Find all selected items, if there are any. If the widget allows for multiselect\n * it will return an array of selected options. If the widget doesn't allow for\n * multiselect, it will return the selected option or null if no item is selected.\n *\n * @return {OO.ui.OptionWidget[]|OO.ui.OptionWidget|null} If the widget is multiselect\n *  then return an array of selected items (or empty array),\n *  if the widget is not multiselect, return a single selected item, or `null`\n *  if no item is selected\n */\nOO.ui.SelectWidget.prototype.findSelectedItems = function () {\n\tvar selected = this.items.filter( function ( item ) {\n\t\treturn item.isSelected();\n\t} );\n\n\treturn this.multiselect ?\n\t\tselected :\n\t\tselected[ 0 ] || null;\n};\n\n/**\n * Find selected item.\n *\n * @return {OO.ui.OptionWidget[]|OO.ui.OptionWidget|null} If the widget is multiselect\n *  then return an array of selected items (or empty array),\n *  if the widget is not multiselect, return a single selected item, or `null`\n *  if no item is selected\n */\nOO.ui.SelectWidget.prototype.findSelectedItem = function () {\n\treturn this.findSelectedItems();\n};\n\n/**\n * Find highlighted item.\n *\n * @return {OO.ui.OptionWidget|null} Highlighted item, `null` if no item is highlighted\n */\nOO.ui.SelectWidget.prototype.findHighlightedItem = function () {\n\tvar i, len;\n\n\tfor ( i = 0, len = this.items.length; i < len; i++ ) {\n\t\tif ( this.items[ i ].isHighlighted() ) {\n\t\t\treturn this.items[ i ];\n\t\t}\n\t}\n\treturn null;\n};\n\n/**\n * Toggle pressed state.\n *\n * Press is a state that occurs when a user mouses down on an item, but\n * has not yet let go of the mouse. The item may appear selected, but it will not be selected\n * until the user releases the mouse.\n *\n * @param {boolean} pressed An option is being pressed\n */\nOO.ui.SelectWidget.prototype.togglePressed = function ( pressed ) {\n\tif ( pressed === undefined ) {\n\t\tpressed = !this.pressed;\n\t}\n\tif ( pressed !== this.pressed ) {\n\t\tthis.$element\n\t\t\t.toggleClass( 'oo-ui-selectWidget-pressed', pressed )\n\t\t\t// -depressed is a deprecated alias of -unpressed\n\t\t\t.toggleClass( 'oo-ui-selectWidget-unpressed oo-ui-selectWidget-depressed', !pressed );\n\t\tthis.pressed = pressed;\n\t}\n};\n\n/**\n * Highlight an option. If the `item` param is omitted, no options will be highlighted\n * and any existing highlight will be removed. The highlight is mutually exclusive.\n *\n * @param {OO.ui.OptionWidget} [item] Item to highlight, omit for no highlight\n * @fires highlight\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.SelectWidget.prototype.highlightItem = function ( item ) {\n\tvar i, len, highlighted,\n\t\tchanged = false;\n\n\tfor ( i = 0, len = this.items.length; i < len; i++ ) {\n\t\thighlighted = this.items[ i ] === item;\n\t\tif ( this.items[ i ].isHighlighted() !== highlighted ) {\n\t\t\tthis.items[ i ].setHighlighted( highlighted );\n\t\t\tchanged = true;\n\t\t}\n\t}\n\tif ( changed ) {\n\t\tif ( item ) {\n\t\t\tthis.$focusOwner.attr( 'aria-activedescendant', item.getElementId() );\n\t\t} else {\n\t\t\tthis.$focusOwner.removeAttr( 'aria-activedescendant' );\n\t\t}\n\t\tthis.emit( 'highlight', item );\n\t}\n\n\treturn this;\n};\n\n/**\n * Fetch an item by its label.\n *\n * @param {string} label Label of the item to select.\n * @param {boolean} [prefix=false] Allow a prefix match, if only a single item matches\n * @return {OO.ui.Element|null} Item with equivalent label, `null` if none exists\n */\nOO.ui.SelectWidget.prototype.getItemFromLabel = function ( label, prefix ) {\n\tvar i, item, found,\n\t\tlen = this.items.length,\n\t\tfilter = this.getItemMatcher( label, 'exact' );\n\n\tfor ( i = 0; i < len; i++ ) {\n\t\titem = this.items[ i ];\n\t\tif ( item instanceof OO.ui.OptionWidget && item.isSelectable() && filter( item ) ) {\n\t\t\treturn item;\n\t\t}\n\t}\n\n\tif ( prefix ) {\n\t\tfound = null;\n\t\tfilter = this.getItemMatcher( label, 'prefix' );\n\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\titem = this.items[ i ];\n\t\t\tif ( item instanceof OO.ui.OptionWidget && item.isSelectable() && filter( item ) ) {\n\t\t\t\tif ( found ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tfound = item;\n\t\t\t}\n\t\t}\n\t\tif ( found ) {\n\t\t\treturn found;\n\t\t}\n\t}\n\n\treturn null;\n};\n\n/**\n * Programmatically select an option by its label. If the item does not exist,\n * all options will be deselected.\n *\n * @param {string} [label] Label of the item to select.\n * @param {boolean} [prefix=false] Allow a prefix match, if only a single item matches\n * @fires select\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.SelectWidget.prototype.selectItemByLabel = function ( label, prefix ) {\n\tvar itemFromLabel = this.getItemFromLabel( label, !!prefix );\n\tif ( label === undefined || !itemFromLabel ) {\n\t\treturn this.selectItem();\n\t}\n\treturn this.selectItem( itemFromLabel );\n};\n\n/**\n * Programmatically select an option by its data. If the `data` parameter is omitted,\n * or if the item does not exist, all options will be deselected.\n *\n * @param {Object|string} [data] Value of the item to select, omit to deselect all\n * @fires select\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.SelectWidget.prototype.selectItemByData = function ( data ) {\n\tvar itemFromData = this.findItemFromData( data );\n\tif ( data === undefined || !itemFromData ) {\n\t\treturn this.selectItem();\n\t}\n\treturn this.selectItem( itemFromData );\n};\n\n/**\n * Programmatically unselect an option by its reference. If the widget\n * allows for multiple selections, there may be other items still selected;\n * otherwise, no items will be selected.\n * If no item is given, all selected items will be unselected.\n *\n * @param {OO.ui.OptionWidget} [item] Item to unselect\n * @fires select\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.SelectWidget.prototype.unselectItem = function ( item ) {\n\tif ( item ) {\n\t\titem.setSelected( false );\n\t} else {\n\t\tthis.items.forEach( function ( item ) {\n\t\t\titem.setSelected( false );\n\t\t} );\n\t}\n\n\tthis.emit( 'select', this.findSelectedItems() );\n\treturn this;\n};\n\n/**\n * Programmatically select an option by its reference. If the `item` parameter is omitted,\n * all options will be deselected.\n *\n * @param {OO.ui.OptionWidget} [item] Item to select, omit to deselect all\n * @fires select\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n*/\nOO.ui.SelectWidget.prototype.selectItem = function ( item ) {\n\tvar i, len, selected,\n\t\tchanged = false;\n\n\tif ( this.multiselect && item ) {\n\t\t// Select the item directly\n\t\titem.setSelected( true );\n\t} else {\n\t\tfor ( i = 0, len = this.items.length; i < len; i++ ) {\n\t\t\tselected = this.items[ i ] === item;\n\t\t\tif ( this.items[ i ].isSelected() !== selected ) {\n\t\t\t\tthis.items[ i ].setSelected( selected );\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\t}\n\tif ( changed ) {\n\t\t// TODO: When should a non-highlightable element be selected?\n\t\tif ( item && !item.constructor.static.highlightable ) {\n\t\t\tif ( item ) {\n\t\t\t\tthis.$focusOwner.attr( 'aria-activedescendant', item.getElementId() );\n\t\t\t} else {\n\t\t\t\tthis.$focusOwner.removeAttr( 'aria-activedescendant' );\n\t\t\t}\n\t\t}\n\t\tthis.emit( 'select', this.findSelectedItems() );\n\t}\n\n\treturn this;\n};\n\n/**\n * Press an item.\n *\n * Press is a state that occurs when a user mouses down on an item, but has not\n * yet let go of the mouse. The item may appear selected, but it will not be selected until the user\n * releases the mouse.\n *\n * @param {OO.ui.OptionWidget} [item] Item to press, omit to depress all\n * @fires press\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.SelectWidget.prototype.pressItem = function ( item ) {\n\tvar i, len, pressed,\n\t\tchanged = false;\n\n\tfor ( i = 0, len = this.items.length; i < len; i++ ) {\n\t\tpressed = this.items[ i ] === item;\n\t\tif ( this.items[ i ].isPressed() !== pressed ) {\n\t\t\tthis.items[ i ].setPressed( pressed );\n\t\t\tchanged = true;\n\t\t}\n\t}\n\tif ( changed ) {\n\t\tthis.emit( 'press', item );\n\t}\n\n\treturn this;\n};\n\n/**\n * Choose an item.\n *\n * Note that ‘choose’ should never be modified programmatically. A user can choose\n * an option with the keyboard or mouse and it becomes selected. To select an item programmatically,\n * use the #selectItem method.\n *\n * This method is identical to #selectItem, but may vary in subclasses that take additional action\n * when users choose an item with the keyboard or mouse.\n *\n * @param {OO.ui.OptionWidget} item Item to choose\n * @fires choose\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.SelectWidget.prototype.chooseItem = function ( item ) {\n\tif ( item ) {\n\t\tif ( this.multiselect && item.isSelected() ) {\n\t\t\tthis.unselectItem( item );\n\t\t} else {\n\t\t\tthis.selectItem( item );\n\t\t}\n\n\t\tthis.emit( 'choose', item, item.isSelected() );\n\t}\n\n\treturn this;\n};\n\n/**\n * Find an option by its position relative to the specified item (or to the start of the option\n * array, if item is `null`). The direction in which to search through the option array is specified\n * with a number: -1 for reverse (the default) or 1 for forward. The method will return an option,\n * or `null` if there are no options in the array.\n *\n * @param {OO.ui.OptionWidget|null} item Item to describe the start position, or `null` to start at\n *  the beginning of the array.\n * @param {number} direction Direction to move in: -1 to move backward, 1 to move forward\n * @param {Function} [filter] Only consider items for which this function returns\n *  true. Function takes an OO.ui.OptionWidget and returns a boolean.\n * @return {OO.ui.OptionWidget|null} Item at position, `null` if there are no items in the select\n */\nOO.ui.SelectWidget.prototype.findRelativeSelectableItem = function ( item, direction, filter ) {\n\tvar currentIndex, nextIndex, i,\n\t\tincrease = direction > 0 ? 1 : -1,\n\t\tlen = this.items.length;\n\n\tif ( item instanceof OO.ui.OptionWidget ) {\n\t\tcurrentIndex = this.items.indexOf( item );\n\t\tnextIndex = ( currentIndex + increase + len ) % len;\n\t} else {\n\t\t// If no item is selected and moving forward, start at the beginning.\n\t\t// If moving backward, start at the end.\n\t\tnextIndex = direction > 0 ? 0 : len - 1;\n\t}\n\n\tfor ( i = 0; i < len; i++ ) {\n\t\titem = this.items[ nextIndex ];\n\t\tif (\n\t\t\titem instanceof OO.ui.OptionWidget && item.isSelectable() &&\n\t\t\t( !filter || filter( item ) )\n\t\t) {\n\t\t\treturn item;\n\t\t}\n\t\tnextIndex = ( nextIndex + increase + len ) % len;\n\t}\n\treturn null;\n};\n\n/**\n * Find the next selectable item or `null` if there are no selectable items.\n * Disabled options and menu-section markers and breaks are not selectable.\n *\n * @return {OO.ui.OptionWidget|null} Item, `null` if there aren't any selectable items\n */\nOO.ui.SelectWidget.prototype.findFirstSelectableItem = function () {\n\treturn this.findRelativeSelectableItem( null, 1 );\n};\n\n/**\n * Add an array of options to the select. Optionally, an index number can be used to\n * specify an insertion point.\n *\n * @param {OO.ui.OptionWidget[]} items Items to add\n * @param {number} [index] Index to insert items after\n * @fires add\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.SelectWidget.prototype.addItems = function ( items, index ) {\n\t// Mixin method\n\tOO.ui.mixin.GroupWidget.prototype.addItems.call( this, items, index );\n\n\t// Always provide an index, even if it was omitted\n\tthis.emit( 'add', items, index === undefined ? this.items.length - items.length - 1 : index );\n\n\treturn this;\n};\n\n/**\n * Remove the specified array of options from the select. Options will be detached\n * from the DOM, not removed, so they can be reused later. To remove all options from\n * the select, you may wish to use the #clearItems method instead.\n *\n * @param {OO.ui.OptionWidget[]} items Items to remove\n * @fires remove\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.SelectWidget.prototype.removeItems = function ( items ) {\n\tvar i, len, item;\n\n\t// Deselect items being removed\n\tfor ( i = 0, len = items.length; i < len; i++ ) {\n\t\titem = items[ i ];\n\t\tif ( item.isSelected() ) {\n\t\t\tthis.selectItem( null );\n\t\t}\n\t}\n\n\t// Mixin method\n\tOO.ui.mixin.GroupWidget.prototype.removeItems.call( this, items );\n\n\tthis.emit( 'remove', items );\n\n\treturn this;\n};\n\n/**\n * Clear all options from the select. Options will be detached from the DOM, not removed,\n * so that they can be reused later. To remove a subset of options from the select, use\n * the #removeItems method.\n *\n * @fires remove\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.SelectWidget.prototype.clearItems = function () {\n\tvar items = this.items.slice();\n\n\t// Mixin method\n\tOO.ui.mixin.GroupWidget.prototype.clearItems.call( this );\n\n\t// Clear selection\n\tthis.selectItem( null );\n\n\tthis.emit( 'remove', items );\n\n\treturn this;\n};\n\n/**\n * Set the DOM element which has focus while the user is interacting with this SelectWidget.\n *\n * This is used to set `aria-activedescendant` and `aria-expanded` on it.\n *\n * @protected\n * @param {jQuery} $focusOwner\n */\nOO.ui.SelectWidget.prototype.setFocusOwner = function ( $focusOwner ) {\n\tthis.$focusOwner = $focusOwner;\n};\n","/**\n * DecoratedOptionWidgets are {@link OO.ui.OptionWidget options} that can be configured\n * with an {@link OO.ui.mixin.IconElement icon} and/or\n * {@link OO.ui.mixin.IndicatorElement indicator}.\n * This class is used with OO.ui.SelectWidget to create a selection of mutually exclusive\n * options. For more information about options and selects, please see the\n * [OOUI documentation on MediaWiki][1].\n *\n *     @example\n *     // Decorated options in a select widget.\n *     var select = new OO.ui.SelectWidget( {\n *         items: [\n *             new OO.ui.DecoratedOptionWidget( {\n *                 data: 'a',\n *                 label: 'Option with icon',\n *                 icon: 'help'\n *             } ),\n *             new OO.ui.DecoratedOptionWidget( {\n *                 data: 'b',\n *                 label: 'Option with indicator',\n *                 indicator: 'next'\n *             } )\n *         ]\n *     } );\n *     $( document.body ).append( select.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options\n *\n * @class\n * @extends OO.ui.OptionWidget\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.IndicatorElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.DecoratedOptionWidget = function OoUiDecoratedOptionWidget( config ) {\n\t// Parent constructor\n\tOO.ui.DecoratedOptionWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.IndicatorElement.call( this, config );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-decoratedOptionWidget' )\n\t\t.prepend( this.$icon )\n\t\t.append( this.$indicator );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.DecoratedOptionWidget, OO.ui.OptionWidget );\nOO.mixinClass( OO.ui.DecoratedOptionWidget, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.DecoratedOptionWidget, OO.ui.mixin.IndicatorElement );\n","/**\n * MenuOptionWidget is an option widget that looks like a menu item. The class is used with\n * OO.ui.MenuSelectWidget to create a menu of mutually exclusive options. Please see\n * the [OOUI documentation on MediaWiki] [1] for more information.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options#Menu_selects_and_options\n *\n * @class\n * @extends OO.ui.DecoratedOptionWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.MenuOptionWidget = function OoUiMenuOptionWidget( config ) {\n\t// Parent constructor\n\tOO.ui.MenuOptionWidget.parent.call( this, config );\n\n\t// Properties\n\tthis.checkIcon = new OO.ui.IconWidget( {\n\t\ticon: 'check',\n\t\tclasses: [ 'oo-ui-menuOptionWidget-checkIcon' ]\n\t} );\n\n\t// Initialization\n\tthis.$element\n\t\t.prepend( this.checkIcon.$element )\n\t\t.addClass( 'oo-ui-menuOptionWidget' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.MenuOptionWidget, OO.ui.DecoratedOptionWidget );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.MenuOptionWidget.static.scrollIntoViewOnSelect = true;\n","/**\n * MenuSectionOptionWidgets are used inside {@link OO.ui.MenuSelectWidget menu select widgets} to\n * group one or more related {@link OO.ui.MenuOptionWidget menu options}. MenuSectionOptionWidgets\n * cannot be highlighted or selected.\n *\n *     @example\n *     var dropdown = new OO.ui.DropdownWidget( {\n *         menu: {\n *             items: [\n *                 new OO.ui.MenuSectionOptionWidget( {\n *                     label: 'Dogs'\n *                 } ),\n *                 new OO.ui.MenuOptionWidget( {\n *                     data: 'corgi',\n *                     label: 'Welsh Corgi'\n *                 } ),\n *                 new OO.ui.MenuOptionWidget( {\n *                     data: 'poodle',\n *                     label: 'Standard Poodle'\n *                 } ),\n *                 new OO.ui.MenuSectionOptionWidget( {\n *                     label: 'Cats'\n *                 } ),\n *                 new OO.ui.MenuOptionWidget( {\n *                     data: 'lion',\n *                     label: 'Lion'\n *                 } )\n *             ]\n *         }\n *     } );\n *     $( document.body ).append( dropdown.$element );\n *\n * @class\n * @extends OO.ui.DecoratedOptionWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.MenuSectionOptionWidget = function OoUiMenuSectionOptionWidget( config ) {\n\t// Parent constructor\n\tOO.ui.MenuSectionOptionWidget.parent.call( this, config );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-menuSectionOptionWidget' )\n\t\t.removeAttr( 'role aria-selected' );\n\tthis.selected = false;\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.MenuSectionOptionWidget, OO.ui.DecoratedOptionWidget );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.MenuSectionOptionWidget.static.selectable = false;\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.MenuSectionOptionWidget.static.highlightable = false;\n","/**\n * MenuSelectWidget is a {@link OO.ui.SelectWidget select widget} that contains options and\n * is used together with OO.ui.MenuOptionWidget. It is designed be used as part of another widget.\n * See {@link OO.ui.DropdownWidget DropdownWidget},\n * {@link OO.ui.ComboBoxInputWidget ComboBoxInputWidget}, and\n * {@link OO.ui.mixin.LookupElement LookupElement} for examples of widgets that contain menus.\n * MenuSelectWidgets themselves are not instantiated directly, rather subclassed\n * and customized to be opened, closed, and displayed as needed.\n *\n * By default, menus are clipped to the visible viewport and are not visible when a user presses the\n * mouse outside the menu.\n *\n * Menus also have support for keyboard interaction:\n *\n * - Enter/Return key: choose and select a menu option\n * - Up-arrow key: highlight the previous menu option\n * - Down-arrow key: highlight the next menu option\n * - Escape key: hide the menu\n *\n * Unlike most widgets, MenuSelectWidget is initially hidden and must be shown by calling #toggle.\n *\n * Please see the [OOUI documentation on MediaWiki][1] for more information.\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options\n *\n * @class\n * @extends OO.ui.SelectWidget\n * @mixins OO.ui.mixin.ClippableElement\n * @mixins OO.ui.mixin.FloatableElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {OO.ui.TextInputWidget} [input] Text input used to implement option highlighting for menu\n *  items that match the text the user types. This config is used by\n *  {@link OO.ui.ComboBoxInputWidget ComboBoxInputWidget} and\n *  {@link OO.ui.mixin.LookupElement LookupElement}\n * @cfg {jQuery} [$input] Text input used to implement option highlighting for menu items that match\n *  the text the user types. This config is used by\n *  {@link OO.ui.TagMultiselectWidget TagMultiselectWidget}\n * @cfg {OO.ui.Widget} [widget] Widget associated with the menu's active state. If the user clicks\n *  the mouse anywhere on the page outside of this widget, the menu is hidden. For example, if\n *  there is a button that toggles the menu's visibility on click, the menu will be hidden then\n *  re-shown when the user clicks that button, unless the button (or its parent widget) is passed\n *  in here.\n * @cfg {boolean} [autoHide=true] Hide the menu when the mouse is pressed outside the menu.\n * @cfg {jQuery} [$autoCloseIgnore] If these elements are clicked, don't auto-hide the menu.\n * @cfg {boolean} [hideOnChoose=true] Hide the menu when the user chooses an option.\n * @cfg {boolean} [filterFromInput=false] Filter the displayed options from the input\n * @cfg {boolean} [highlightOnFilter] Highlight the first result when filtering\n * @cfg {string} [filterMode='prefix'] The mode by which the menu filters the results.\n *  Options are 'exact', 'prefix' or 'substring'. See `OO.ui.SelectWidget#getItemMatcher`\n * @param {number|string} [width] Width of the menu as a number of pixels or CSS string with unit\n *  suffix, used by {@link OO.ui.mixin.ClippableElement ClippableElement}\n */\nOO.ui.MenuSelectWidget = function OoUiMenuSelectWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.MenuSelectWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.ClippableElement.call( this, $.extend( { $clippable: this.$group }, config ) );\n\tOO.ui.mixin.FloatableElement.call( this, config );\n\n\t// Initial vertical positions other than 'center' will result in\n\t// the menu being flipped if there is not enough space in the container.\n\t// Store the original position so we know what to reset to.\n\tthis.originalVerticalPosition = this.verticalPosition;\n\n\t// Properties\n\tthis.autoHide = config.autoHide === undefined || !!config.autoHide;\n\tthis.hideOnChoose = config.hideOnChoose === undefined || !!config.hideOnChoose;\n\tthis.filterFromInput = !!config.filterFromInput;\n\tthis.$input = config.$input ? config.$input : config.input ? config.input.$input : null;\n\tthis.$widget = config.widget ? config.widget.$element : null;\n\tthis.$autoCloseIgnore = config.$autoCloseIgnore || $( [] );\n\tthis.onDocumentMouseDownHandler = this.onDocumentMouseDown.bind( this );\n\tthis.onInputEditHandler = OO.ui.debounce( this.updateItemVisibility.bind( this ), 100 );\n\tthis.highlightOnFilter = !!config.highlightOnFilter;\n\tthis.lastHighlightedItem = null;\n\tthis.width = config.width;\n\tthis.filterMode = config.filterMode;\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-menuSelectWidget' );\n\tif ( config.widget ) {\n\t\tthis.setFocusOwner( config.widget.$tabIndexed );\n\t}\n\n\t// Initially hidden - using #toggle may cause errors if subclasses override toggle with methods\n\t// that reference properties not initialized at that time of parent class construction\n\t// TODO: Find a better way to handle post-constructor setup\n\tthis.visible = false;\n\tthis.$element.addClass( 'oo-ui-element-hidden' );\n\tthis.$focusOwner.attr( 'aria-expanded', 'false' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.MenuSelectWidget, OO.ui.SelectWidget );\nOO.mixinClass( OO.ui.MenuSelectWidget, OO.ui.mixin.ClippableElement );\nOO.mixinClass( OO.ui.MenuSelectWidget, OO.ui.mixin.FloatableElement );\n\n/* Events */\n\n/**\n * @event ready\n *\n * The menu is ready: it is visible and has been positioned and clipped.\n */\n\n/* Static properties */\n\n/**\n * Positions to flip to if there isn't room in the container for the\n * menu in a specific direction.\n *\n * @property {Object.<string,string>}\n */\nOO.ui.MenuSelectWidget.static.flippedPositions = {\n\tbelow: 'above',\n\tabove: 'below',\n\ttop: 'bottom',\n\tbottom: 'top'\n};\n\n/* Methods */\n\n/**\n * Handles document mouse down events.\n *\n * @protected\n * @param {MouseEvent} e Mouse down event\n */\nOO.ui.MenuSelectWidget.prototype.onDocumentMouseDown = function ( e ) {\n\tif (\n\t\tthis.isVisible() &&\n\t\t!OO.ui.contains(\n\t\t\tthis.$element.add( this.$widget ).add( this.$autoCloseIgnore ).get(),\n\t\t\te.target,\n\t\t\ttrue\n\t\t)\n\t) {\n\t\tthis.toggle( false );\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuSelectWidget.prototype.onDocumentKeyDown = function ( e ) {\n\tvar currentItem = this.findHighlightedItem() || this.findSelectedItem();\n\n\tif ( !this.isDisabled() && this.isVisible() ) {\n\t\tswitch ( e.keyCode ) {\n\t\t\tcase OO.ui.Keys.LEFT:\n\t\t\tcase OO.ui.Keys.RIGHT:\n\t\t\t\t// Do nothing if a text field is associated, arrow keys will be handled natively\n\t\t\t\tif ( !this.$input ) {\n\t\t\t\t\tOO.ui.MenuSelectWidget.parent.prototype.onDocumentKeyDown.call( this, e );\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase OO.ui.Keys.ESCAPE:\n\t\t\tcase OO.ui.Keys.TAB:\n\t\t\t\tif ( currentItem && !this.multiselect ) {\n\t\t\t\t\tcurrentItem.setHighlighted( false );\n\t\t\t\t}\n\t\t\t\tthis.toggle( false );\n\t\t\t\t// Don't prevent tabbing away, prevent defocusing\n\t\t\t\tif ( e.keyCode === OO.ui.Keys.ESCAPE ) {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\te.stopPropagation();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tOO.ui.MenuSelectWidget.parent.prototype.onDocumentKeyDown.call( this, e );\n\t\t\t\treturn;\n\t\t}\n\t}\n};\n\n/**\n * Update menu item visibility and clipping after input changes (if filterFromInput is enabled)\n * or after items were added/removed (always).\n *\n * @protected\n */\nOO.ui.MenuSelectWidget.prototype.updateItemVisibility = function () {\n\tvar i, item, items, visible, section, sectionEmpty, filter, exactFilter,\n\t\tanyVisible = false,\n\t\tlen = this.items.length,\n\t\tshowAll = !this.isVisible(),\n\t\texactMatch = false;\n\n\tif ( this.$input && this.filterFromInput ) {\n\t\tfilter = showAll ? null : this.getItemMatcher( this.$input.val(), this.filterMode );\n\t\texactFilter = this.getItemMatcher( this.$input.val(), 'exact' );\n\t\t// Hide non-matching options, and also hide section headers if all options\n\t\t// in their section are hidden.\n\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\titem = this.items[ i ];\n\t\t\tif ( item instanceof OO.ui.MenuSectionOptionWidget ) {\n\t\t\t\tif ( section ) {\n\t\t\t\t\t// If the previous section was empty, hide its header\n\t\t\t\t\tsection.toggle( showAll || !sectionEmpty );\n\t\t\t\t}\n\t\t\t\tsection = item;\n\t\t\t\tsectionEmpty = true;\n\t\t\t} else if ( item instanceof OO.ui.OptionWidget ) {\n\t\t\t\tvisible = showAll || filter( item );\n\t\t\t\texactMatch = exactMatch || exactFilter( item );\n\t\t\t\tanyVisible = anyVisible || visible;\n\t\t\t\tsectionEmpty = sectionEmpty && !visible;\n\t\t\t\titem.toggle( visible );\n\t\t\t}\n\t\t}\n\t\t// Process the final section\n\t\tif ( section ) {\n\t\t\tsection.toggle( showAll || !sectionEmpty );\n\t\t}\n\n\t\tif ( !anyVisible ) {\n\t\t\tthis.highlightItem( null );\n\t\t}\n\n\t\tthis.$element.toggleClass( 'oo-ui-menuSelectWidget-invisible', !anyVisible );\n\n\t\tif (\n\t\t\tthis.highlightOnFilter &&\n\t\t\t!( this.lastHighlightedItem && this.lastHighlightedItem.isVisible() )\n\t\t) {\n\t\t\t// Highlight the first item on the list\n\t\t\titem = null;\n\t\t\titems = this.getItems();\n\t\t\tfor ( i = 0; i < items.length; i++ ) {\n\t\t\t\tif ( items[ i ].isVisible() ) {\n\t\t\t\t\titem = items[ i ];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.highlightItem( item );\n\t\t\tthis.lastHighlightedItem = item;\n\t\t}\n\n\t}\n\n\t// Reevaluate clipping\n\tthis.clip();\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuSelectWidget.prototype.bindDocumentKeyDownListener = function () {\n\tif ( this.$input ) {\n\t\tthis.$input.on( 'keydown', this.onDocumentKeyDownHandler );\n\t} else {\n\t\tOO.ui.MenuSelectWidget.parent.prototype.bindDocumentKeyDownListener.call( this );\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuSelectWidget.prototype.unbindDocumentKeyDownListener = function () {\n\tif ( this.$input ) {\n\t\tthis.$input.off( 'keydown', this.onDocumentKeyDownHandler );\n\t} else {\n\t\tOO.ui.MenuSelectWidget.parent.prototype.unbindDocumentKeyDownListener.call( this );\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuSelectWidget.prototype.bindDocumentKeyPressListener = function () {\n\tif ( this.$input ) {\n\t\tif ( this.filterFromInput ) {\n\t\t\tthis.$input.on(\n\t\t\t\t'keydown mouseup cut paste change input select',\n\t\t\t\tthis.onInputEditHandler\n\t\t\t);\n\t\t\tthis.updateItemVisibility();\n\t\t}\n\t} else {\n\t\tOO.ui.MenuSelectWidget.parent.prototype.bindDocumentKeyPressListener.call( this );\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuSelectWidget.prototype.unbindDocumentKeyPressListener = function () {\n\tif ( this.$input ) {\n\t\tif ( this.filterFromInput ) {\n\t\t\tthis.$input.off(\n\t\t\t\t'keydown mouseup cut paste change input select',\n\t\t\t\tthis.onInputEditHandler\n\t\t\t);\n\t\t\tthis.updateItemVisibility();\n\t\t}\n\t} else {\n\t\tOO.ui.MenuSelectWidget.parent.prototype.unbindDocumentKeyPressListener.call( this );\n\t}\n};\n\n/**\n * Choose an item.\n *\n * When a user chooses an item, the menu is closed, unless the hideOnChoose config option is\n * set to false.\n *\n * Note that ‘choose’ should never be modified programmatically. A user can choose an option with\n * the keyboard or mouse and it becomes selected. To select an item programmatically,\n * use the #selectItem method.\n *\n * @param {OO.ui.OptionWidget} item Item to choose\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.MenuSelectWidget.prototype.chooseItem = function ( item ) {\n\tOO.ui.MenuSelectWidget.parent.prototype.chooseItem.call( this, item );\n\tif ( this.hideOnChoose ) {\n\t\tthis.toggle( false );\n\t}\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuSelectWidget.prototype.addItems = function ( items, index ) {\n\t// Parent method\n\tOO.ui.MenuSelectWidget.parent.prototype.addItems.call( this, items, index );\n\n\tthis.updateItemVisibility();\n\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuSelectWidget.prototype.removeItems = function ( items ) {\n\t// Parent method\n\tOO.ui.MenuSelectWidget.parent.prototype.removeItems.call( this, items );\n\n\tthis.updateItemVisibility();\n\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuSelectWidget.prototype.clearItems = function () {\n\t// Parent method\n\tOO.ui.MenuSelectWidget.parent.prototype.clearItems.call( this );\n\n\tthis.updateItemVisibility();\n\n\treturn this;\n};\n\n/**\n * Toggle visibility of the menu. The menu is initially hidden and must be shown by calling\n * `.toggle( true )` after its #$element is attached to the DOM.\n *\n * Do not show the menu while it is not attached to the DOM. The calculations required to display\n * it in the right place and with the right dimensions only work correctly while it is attached.\n * Side-effects may include broken interface and exceptions being thrown. This wasn't always\n * strictly enforced, so currently it only generates a warning in the browser console.\n *\n * @fires ready\n * @inheritdoc\n */\nOO.ui.MenuSelectWidget.prototype.toggle = function ( visible ) {\n\tvar change, originalHeight, flippedHeight, selectedItem;\n\n\tvisible = ( visible === undefined ? !this.visible : !!visible ) && !!this.items.length;\n\tchange = visible !== this.isVisible();\n\n\tif ( visible && !this.warnedUnattached && !this.isElementAttached() ) {\n\t\tOO.ui.warnDeprecation( 'MenuSelectWidget#toggle: Before calling this method, the menu must be attached to the DOM.' );\n\t\tthis.warnedUnattached = true;\n\t}\n\n\tif ( change && visible ) {\n\t\t// Reset position before showing the popup again. It's possible we no longer need to flip\n\t\t// (e.g. if the user scrolled).\n\t\tthis.setVerticalPosition( this.originalVerticalPosition );\n\t}\n\n\t// Parent method\n\tOO.ui.MenuSelectWidget.parent.prototype.toggle.call( this, visible );\n\n\tif ( change ) {\n\t\tif ( visible ) {\n\n\t\t\tif ( this.width ) {\n\t\t\t\tthis.setIdealSize( this.width );\n\t\t\t} else if ( this.$floatableContainer ) {\n\t\t\t\tthis.$clippable.css( 'width', 'auto' );\n\t\t\t\tthis.setIdealSize(\n\t\t\t\t\tthis.$floatableContainer[ 0 ].offsetWidth > this.$clippable[ 0 ].offsetWidth ?\n\t\t\t\t\t\t// Dropdown is smaller than handle so expand to width\n\t\t\t\t\t\tthis.$floatableContainer[ 0 ].offsetWidth :\n\t\t\t\t\t\t// Dropdown is larger than handle so auto size\n\t\t\t\t\t\t'auto'\n\t\t\t\t);\n\t\t\t\tthis.$clippable.css( 'width', '' );\n\t\t\t}\n\n\t\t\tthis.togglePositioning( !!this.$floatableContainer );\n\t\t\tthis.toggleClipping( true );\n\n\t\t\tthis.bindDocumentKeyDownListener();\n\t\t\tthis.bindDocumentKeyPressListener();\n\n\t\t\tif (\n\t\t\t\t( this.isClippedVertically() || this.isFloatableOutOfView() ) &&\n\t\t\t\tthis.originalVerticalPosition !== 'center'\n\t\t\t) {\n\t\t\t\t// If opening the menu in one direction causes it to be clipped, flip it\n\t\t\t\toriginalHeight = this.$element.height();\n\t\t\t\tthis.setVerticalPosition(\n\t\t\t\t\tthis.constructor.static.flippedPositions[ this.originalVerticalPosition ]\n\t\t\t\t);\n\t\t\t\tif ( this.isClippedVertically() || this.isFloatableOutOfView() ) {\n\t\t\t\t\t// If flipping also causes it to be clipped, open in whichever direction\n\t\t\t\t\t// we have more space\n\t\t\t\t\tflippedHeight = this.$element.height();\n\t\t\t\t\tif ( originalHeight > flippedHeight ) {\n\t\t\t\t\t\tthis.setVerticalPosition( this.originalVerticalPosition );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Note that we do not flip the menu's opening direction if the clipping changes\n\t\t\t// later (e.g. after the user scrolls), that seems like it would be annoying\n\n\t\t\tthis.$focusOwner.attr( 'aria-expanded', 'true' );\n\n\t\t\tselectedItem = this.findSelectedItem();\n\t\t\tif ( !this.multiselect && selectedItem ) {\n\t\t\t\t// TODO: Verify if this is even needed; This is already done on highlight changes\n\t\t\t\t// in SelectWidget#highlightItem, so we should just need to highlight the item\n\t\t\t\t// we need to highlight here and not bother with attr or checking selections.\n\t\t\t\tthis.$focusOwner.attr( 'aria-activedescendant', selectedItem.getElementId() );\n\t\t\t\tselectedItem.scrollElementIntoView( { duration: 0 } );\n\t\t\t}\n\n\t\t\t// Auto-hide\n\t\t\tif ( this.autoHide ) {\n\t\t\t\tthis.getElementDocument().addEventListener( 'mousedown', this.onDocumentMouseDownHandler, true );\n\t\t\t}\n\n\t\t\tthis.emit( 'ready' );\n\t\t} else {\n\t\t\tthis.$focusOwner.removeAttr( 'aria-activedescendant' );\n\t\t\tthis.unbindDocumentKeyDownListener();\n\t\t\tthis.unbindDocumentKeyPressListener();\n\t\t\tthis.$focusOwner.attr( 'aria-expanded', 'false' );\n\t\t\tthis.getElementDocument().removeEventListener( 'mousedown', this.onDocumentMouseDownHandler, true );\n\t\t\tthis.togglePositioning( false );\n\t\t\tthis.toggleClipping( false );\n\t\t\tthis.lastHighlightedItem = null;\n\t\t}\n\t}\n\n\treturn this;\n};\n\n/**\n * Scroll to the top of the menu\n */\nOO.ui.MenuSelectWidget.prototype.scrollToTop = function () {\n\tthis.$element.scrollTop( 0 );\n};\n","/**\n * DropdownWidgets are not menus themselves, rather they contain a menu of options created with\n * OO.ui.MenuOptionWidget. The DropdownWidget takes care of opening and displaying the menu so that\n * users can interact with it.\n *\n * If you want to use this within an HTML form, such as a OO.ui.FormLayout, use\n * OO.ui.DropdownInputWidget instead.\n *\n *     @example\n *     // A DropdownWidget with a menu that contains three options.\n *     var dropDown = new OO.ui.DropdownWidget( {\n *         label: 'Dropdown menu: Select a menu option',\n *         menu: {\n *             items: [\n *                 new OO.ui.MenuOptionWidget( {\n *                     data: 'a',\n *                     label: 'First'\n *                 } ),\n *                 new OO.ui.MenuOptionWidget( {\n *                     data: 'b',\n *                     label: 'Second'\n *                 } ),\n *                 new OO.ui.MenuOptionWidget( {\n *                     data: 'c',\n *                     label: 'Third'\n *                 } )\n *             ]\n *         }\n *     } );\n *\n *     $( document.body ).append( dropDown.$element );\n *\n *     dropDown.getMenu().selectItemByData( 'b' );\n *\n *     dropDown.getMenu().findSelectedItem().getData(); // Returns 'b'.\n *\n * For more information, please see the [OOUI documentation on MediaWiki] [1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options#Menu_selects_and_options\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.IndicatorElement\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.TitledElement\n * @mixins OO.ui.mixin.TabIndexedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {Object} [menu] Configuration options to pass to\n *  {@link OO.ui.MenuSelectWidget menu select widget}.\n * @cfg {jQuery} [$overlay] Render the menu into a separate layer. This configuration is useful\n *  in cases where the expanded menu is larger than its containing `<div>`. The specified overlay\n *  layer is usually on top of the containing `<div>` and has a larger area. By default, the menu\n *  uses relative positioning.\n *  See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.\n */\nOO.ui.DropdownWidget = function OoUiDropdownWidget( config ) {\n\t// Configuration initialization\n\tconfig = $.extend( { indicator: 'down' }, config );\n\n\t// Parent constructor\n\tOO.ui.DropdownWidget.parent.call( this, config );\n\n\t// Properties (must be set before TabIndexedElement constructor call)\n\tthis.$handle = $( '<button>' );\n\tthis.$overlay = ( config.$overlay === true ?\n\t\tOO.ui.getDefaultOverlay() : config.$overlay ) || this.$element;\n\n\t// Mixin constructors\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.IndicatorElement.call( this, config );\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.TitledElement.call( this, $.extend( {\n\t\t$titled: this.$label\n\t}, config ) );\n\tOO.ui.mixin.TabIndexedElement.call( this, $.extend( {\n\t\t$tabIndexed: this.$handle\n\t}, config ) );\n\n\t// Properties\n\tthis.menu = new OO.ui.MenuSelectWidget( $.extend( {\n\t\twidget: this,\n\t\t$floatableContainer: this.$element\n\t}, config.menu ) );\n\n\t// Events\n\tthis.$handle.on( {\n\t\tclick: this.onClick.bind( this ),\n\t\tkeydown: this.onKeyDown.bind( this ),\n\t\t// Hack? Handle type-to-search when menu is not expanded and not handling its own events.\n\t\tkeypress: this.menu.onDocumentKeyPressHandler,\n\t\tblur: this.menu.clearKeyPressBuffer.bind( this.menu )\n\t} );\n\tthis.menu.connect( this, {\n\t\tselect: 'onMenuSelect',\n\t\ttoggle: 'onMenuToggle'\n\t} );\n\n\t// Initialization\n\tthis.$handle\n\t\t.addClass( 'oo-ui-dropdownWidget-handle' )\n\t\t.attr( {\n\t\t\ttype: 'button',\n\t\t\t'aria-owns': this.menu.getElementId(),\n\t\t\t'aria-haspopup': 'listbox'\n\t\t} )\n\t\t.append( this.$icon, this.$label, this.$indicator );\n\tthis.$element\n\t\t.addClass( 'oo-ui-dropdownWidget' )\n\t\t.append( this.$handle );\n\tthis.$overlay.append( this.menu.$element );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.DropdownWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.DropdownWidget, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.DropdownWidget, OO.ui.mixin.IndicatorElement );\nOO.mixinClass( OO.ui.DropdownWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.DropdownWidget, OO.ui.mixin.TitledElement );\nOO.mixinClass( OO.ui.DropdownWidget, OO.ui.mixin.TabIndexedElement );\n\n/* Methods */\n\n/**\n * Get the menu.\n *\n * @return {OO.ui.MenuSelectWidget} Menu of widget\n */\nOO.ui.DropdownWidget.prototype.getMenu = function () {\n\treturn this.menu;\n};\n\n/**\n * Handles menu select events.\n *\n * @private\n * @param {OO.ui.MenuOptionWidget} item Selected menu item\n */\nOO.ui.DropdownWidget.prototype.onMenuSelect = function ( item ) {\n\tvar selectedLabel;\n\n\tif ( !item ) {\n\t\tthis.setLabel( null );\n\t\treturn;\n\t}\n\n\tselectedLabel = item.getLabel();\n\n\t// If the label is a DOM element, clone it, because setLabel will append() it\n\tif ( selectedLabel instanceof $ ) {\n\t\tselectedLabel = selectedLabel.clone();\n\t}\n\n\tthis.setLabel( selectedLabel );\n};\n\n/**\n * Handle menu toggle events.\n *\n * @private\n * @param {boolean} isVisible Open state of the menu\n */\nOO.ui.DropdownWidget.prototype.onMenuToggle = function ( isVisible ) {\n\tthis.$element.toggleClass( 'oo-ui-dropdownWidget-open', isVisible );\n};\n\n/**\n * Handle mouse click events.\n *\n * @private\n * @param {jQuery.Event} e Mouse click event\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.DropdownWidget.prototype.onClick = function ( e ) {\n\tif ( !this.isDisabled() && e.which === OO.ui.MouseButtons.LEFT ) {\n\t\tthis.menu.toggle();\n\t}\n\treturn false;\n};\n\n/**\n * Handle key down events.\n *\n * @private\n * @param {jQuery.Event} e Key down event\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.DropdownWidget.prototype.onKeyDown = function ( e ) {\n\tif (\n\t\t!this.isDisabled() &&\n\t\t(\n\t\t\te.which === OO.ui.Keys.ENTER ||\n\t\t\t(\n\t\t\t\te.which === OO.ui.Keys.SPACE &&\n\t\t\t\t// Avoid conflicts with type-to-search, see SelectWidget#onKeyPress.\n\t\t\t\t// Space only closes the menu is the user is not typing to search.\n\t\t\t\tthis.menu.keyPressBuffer === ''\n\t\t\t) ||\n\t\t\t(\n\t\t\t\t!this.menu.isVisible() &&\n\t\t\t\t(\n\t\t\t\t\te.which === OO.ui.Keys.UP ||\n\t\t\t\t\te.which === OO.ui.Keys.DOWN\n\t\t\t\t)\n\t\t\t)\n\t\t)\n\t) {\n\t\tthis.menu.toggle();\n\t\treturn false;\n\t}\n};\n","/**\n * RadioOptionWidget is an option widget that looks like a radio button.\n * The class is used with OO.ui.RadioSelectWidget to create a selection of radio options.\n * Please see the [OOUI documentation on MediaWiki] [1] for more information.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options#Button_selects_and_option\n *\n * @class\n * @extends OO.ui.OptionWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.RadioOptionWidget = function OoUiRadioOptionWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties (must be done before parent constructor which calls #setDisabled)\n\tthis.radio = new OO.ui.RadioInputWidget( { value: config.data, tabIndex: -1 } );\n\n\t// Parent constructor\n\tOO.ui.RadioOptionWidget.parent.call( this, config );\n\n\t// Initialization\n\t// Remove implicit role, we're handling it ourselves\n\tthis.radio.$input.attr( 'role', 'presentation' );\n\tthis.$element\n\t\t.addClass( 'oo-ui-radioOptionWidget' )\n\t\t.attr( 'role', 'radio' )\n\t\t.attr( 'aria-checked', 'false' )\n\t\t.removeAttr( 'aria-selected' )\n\t\t.prepend( this.radio.$element );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.RadioOptionWidget, OO.ui.OptionWidget );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.RadioOptionWidget.static.highlightable = false;\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.RadioOptionWidget.static.scrollIntoViewOnSelect = true;\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.RadioOptionWidget.static.pressable = false;\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.RadioOptionWidget.static.tagName = 'label';\n\n/* Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioOptionWidget.prototype.setSelected = function ( state ) {\n\tOO.ui.RadioOptionWidget.parent.prototype.setSelected.call( this, state );\n\n\tthis.radio.setSelected( state );\n\tthis.$element\n\t\t.attr( 'aria-checked', state.toString() )\n\t\t.removeAttr( 'aria-selected' );\n\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioOptionWidget.prototype.setDisabled = function ( disabled ) {\n\tOO.ui.RadioOptionWidget.parent.prototype.setDisabled.call( this, disabled );\n\n\tthis.radio.setDisabled( this.isDisabled() );\n\n\treturn this;\n};\n","/**\n * RadioSelectWidget is a {@link OO.ui.SelectWidget select widget} that contains radio\n * options and is used together with OO.ui.RadioOptionWidget. The RadioSelectWidget provides\n * an interface for adding, removing and selecting options.\n * Please see the [OOUI documentation on MediaWiki][1] for more information.\n *\n * If you want to use this within an HTML form, such as a OO.ui.FormLayout, use\n * OO.ui.RadioSelectInputWidget instead.\n *\n *     @example\n *     // A RadioSelectWidget with RadioOptions.\n *     var option1 = new OO.ui.RadioOptionWidget( {\n *             data: 'a',\n *             label: 'Selected radio option'\n *         } ),\n *         option2 = new OO.ui.RadioOptionWidget( {\n *             data: 'b',\n *             label: 'Unselected radio option'\n *         } );\n *         radioSelect = new OO.ui.RadioSelectWidget( {\n *             items: [ option1, option2 ]\n *         } );\n *\n *     // Select 'option 1' using the RadioSelectWidget's selectItem() method.\n *     radioSelect.selectItem( option1 );\n *\n *     $( document.body ).append( radioSelect.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options\n\n *\n * @class\n * @extends OO.ui.SelectWidget\n * @mixins OO.ui.mixin.TabIndexedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.RadioSelectWidget = function OoUiRadioSelectWidget( config ) {\n\t// Parent constructor\n\tOO.ui.RadioSelectWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.TabIndexedElement.call( this, config );\n\n\t// Events\n\tthis.$element.on( {\n\t\tfocus: this.bindDocumentKeyDownListener.bind( this ),\n\t\tblur: this.unbindDocumentKeyDownListener.bind( this )\n\t} );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-radioSelectWidget' )\n\t\t.attr( 'role', 'radiogroup' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.RadioSelectWidget, OO.ui.SelectWidget );\nOO.mixinClass( OO.ui.RadioSelectWidget, OO.ui.mixin.TabIndexedElement );\n","/**\n * MultioptionWidgets are special elements that can be selected and configured with data. The\n * data is often unique for each option, but it does not have to be. MultioptionWidgets are used\n * with OO.ui.SelectWidget to create a selection of mutually exclusive options. For more information\n * and examples, please see the [OOUI documentation on MediaWiki][1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.ItemWidget\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.TitledElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [selected=false] Whether the option is initially selected\n */\nOO.ui.MultioptionWidget = function OoUiMultioptionWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.MultioptionWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.ItemWidget.call( this );\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.TitledElement.call( this, config );\n\n\t// Properties\n\tthis.selected = null;\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-multioptionWidget' )\n\t\t.append( this.$label );\n\tthis.setSelected( config.selected );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.MultioptionWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.MultioptionWidget, OO.ui.mixin.ItemWidget );\nOO.mixinClass( OO.ui.MultioptionWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.MultioptionWidget, OO.ui.mixin.TitledElement );\n\n/* Events */\n\n/**\n * @event change\n *\n * A change event is emitted when the selected state of the option changes.\n *\n * @param {boolean} selected Whether the option is now selected\n */\n\n/* Methods */\n\n/**\n * Check if the option is selected.\n *\n * @return {boolean} Item is selected\n */\nOO.ui.MultioptionWidget.prototype.isSelected = function () {\n\treturn this.selected;\n};\n\n/**\n * Set the option’s selected state. In general, all modifications to the selection\n * should be handled by the SelectWidget’s\n * {@link OO.ui.SelectWidget#selectItem selectItem( [item] )} method instead of this method.\n *\n * @param {boolean} [state=false] Select option\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.MultioptionWidget.prototype.setSelected = function ( state ) {\n\tstate = !!state;\n\tif ( this.selected !== state ) {\n\t\tthis.selected = state;\n\t\tthis.emit( 'change', state );\n\t\tthis.$element.toggleClass( 'oo-ui-multioptionWidget-selected', state );\n\t}\n\treturn this;\n};\n","/**\n * MultiselectWidget allows selecting multiple options from a list.\n *\n * For more information about menus and options, please see the [OOUI documentation\n * on MediaWiki][1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options#Menu_selects_and_options\n *\n * @class\n * @abstract\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.GroupWidget\n * @mixins OO.ui.mixin.TitledElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {OO.ui.MultioptionWidget[]} [items] An array of options to add to the multiselect.\n */\nOO.ui.MultiselectWidget = function OoUiMultiselectWidget( config ) {\n\t// Parent constructor\n\tOO.ui.MultiselectWidget.parent.call( this, config );\n\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Mixin constructors\n\tOO.ui.mixin.GroupWidget.call( this, config );\n\tOO.ui.mixin.TitledElement.call( this, config );\n\n\t// Events\n\tthis.aggregate( {\n\t\tchange: 'select'\n\t} );\n\t// This is mostly for compatibility with TagMultiselectWidget... normally, 'change' is emitted\n\t// by GroupElement only when items are added/removed\n\tthis.connect( this, {\n\t\tselect: [ 'emit', 'change' ]\n\t} );\n\n\t// Initialization\n\tif ( config.items ) {\n\t\tthis.addItems( config.items );\n\t}\n\tthis.$group.addClass( 'oo-ui-multiselectWidget-group' );\n\tthis.$element.addClass( 'oo-ui-multiselectWidget' )\n\t\t.append( this.$group );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.MultiselectWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.MultiselectWidget, OO.ui.mixin.GroupWidget );\nOO.mixinClass( OO.ui.MultiselectWidget, OO.ui.mixin.TitledElement );\n\n/* Events */\n\n/**\n * @event change\n *\n * A change event is emitted when the set of items changes, or an item is selected or deselected.\n */\n\n/**\n * @event select\n *\n * A select event is emitted when an item is selected or deselected.\n */\n\n/* Methods */\n\n/**\n * Find options that are selected.\n *\n * @return {OO.ui.MultioptionWidget[]} Selected options\n */\nOO.ui.MultiselectWidget.prototype.findSelectedItems = function () {\n\treturn this.items.filter( function ( item ) {\n\t\treturn item.isSelected();\n\t} );\n};\n\n/**\n * Find the data of options that are selected.\n *\n * @return {Object[]|string[]} Values of selected options\n */\nOO.ui.MultiselectWidget.prototype.findSelectedItemsData = function () {\n\treturn this.findSelectedItems().map( function ( item ) {\n\t\treturn item.data;\n\t} );\n};\n\n/**\n * Select options by reference. Options not mentioned in the `items` array will be deselected.\n *\n * @param {OO.ui.MultioptionWidget[]} items Items to select\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.MultiselectWidget.prototype.selectItems = function ( items ) {\n\tthis.items.forEach( function ( item ) {\n\t\tvar selected = items.indexOf( item ) !== -1;\n\t\titem.setSelected( selected );\n\t} );\n\treturn this;\n};\n\n/**\n * Select items by their data. Options not mentioned in the `datas` array will be deselected.\n *\n * @param {Object[]|string[]} datas Values of items to select\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.MultiselectWidget.prototype.selectItemsByData = function ( datas ) {\n\tvar items,\n\t\twidget = this;\n\titems = datas.map( function ( data ) {\n\t\treturn widget.findItemFromData( data );\n\t} );\n\tthis.selectItems( items );\n\treturn this;\n};\n","/**\n * CheckboxMultioptionWidget is an option widget that looks like a checkbox.\n * The class is used with OO.ui.CheckboxMultiselectWidget to create a selection of checkbox options.\n * Please see the [OOUI documentation on MediaWiki] [1] for more information.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options#Button_selects_and_option\n *\n * @class\n * @extends OO.ui.MultioptionWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.CheckboxMultioptionWidget = function OoUiCheckboxMultioptionWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties (must be done before parent constructor which calls #setDisabled)\n\tthis.checkbox = new OO.ui.CheckboxInputWidget();\n\n\t// Parent constructor\n\tOO.ui.CheckboxMultioptionWidget.parent.call( this, config );\n\n\t// Events\n\tthis.checkbox.on( 'change', this.onCheckboxChange.bind( this ) );\n\tthis.$element.on( 'keydown', this.onKeyDown.bind( this ) );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-checkboxMultioptionWidget' )\n\t\t.prepend( this.checkbox.$element );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.CheckboxMultioptionWidget, OO.ui.MultioptionWidget );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.CheckboxMultioptionWidget.static.tagName = 'label';\n\n/* Methods */\n\n/**\n * Handle checkbox selected state change.\n *\n * @private\n */\nOO.ui.CheckboxMultioptionWidget.prototype.onCheckboxChange = function () {\n\tthis.setSelected( this.checkbox.isSelected() );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxMultioptionWidget.prototype.setSelected = function ( state ) {\n\tOO.ui.CheckboxMultioptionWidget.parent.prototype.setSelected.call( this, state );\n\tthis.checkbox.setSelected( state );\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxMultioptionWidget.prototype.setDisabled = function ( disabled ) {\n\tOO.ui.CheckboxMultioptionWidget.parent.prototype.setDisabled.call( this, disabled );\n\tthis.checkbox.setDisabled( this.isDisabled() );\n\treturn this;\n};\n\n/**\n * Focus the widget.\n */\nOO.ui.CheckboxMultioptionWidget.prototype.focus = function () {\n\tthis.checkbox.focus();\n};\n\n/**\n * Handle key down events.\n *\n * @protected\n * @param {jQuery.Event} e\n */\nOO.ui.CheckboxMultioptionWidget.prototype.onKeyDown = function ( e ) {\n\tvar\n\t\telement = this.getElementGroup(),\n\t\tnextItem;\n\n\tif ( e.keyCode === OO.ui.Keys.LEFT || e.keyCode === OO.ui.Keys.UP ) {\n\t\tnextItem = element.getRelativeFocusableItem( this, -1 );\n\t} else if ( e.keyCode === OO.ui.Keys.RIGHT || e.keyCode === OO.ui.Keys.DOWN ) {\n\t\tnextItem = element.getRelativeFocusableItem( this, 1 );\n\t}\n\n\tif ( nextItem ) {\n\t\te.preventDefault();\n\t\tnextItem.focus();\n\t}\n};\n","/**\n * CheckboxMultiselectWidget is a {@link OO.ui.MultiselectWidget multiselect widget} that contains\n * checkboxes and is used together with OO.ui.CheckboxMultioptionWidget. The\n * CheckboxMultiselectWidget provides an interface for adding, removing and selecting options.\n * Please see the [OOUI documentation on MediaWiki][1] for more information.\n *\n * If you want to use this within an HTML form, such as a OO.ui.FormLayout, use\n * OO.ui.CheckboxMultiselectInputWidget instead.\n *\n *     @example\n *     // A CheckboxMultiselectWidget with CheckboxMultioptions.\n *     var option1 = new OO.ui.CheckboxMultioptionWidget( {\n *             data: 'a',\n *             selected: true,\n *             label: 'Selected checkbox'\n *         } ),\n *         option2 = new OO.ui.CheckboxMultioptionWidget( {\n *             data: 'b',\n *             label: 'Unselected checkbox'\n *         } ),\n *         multiselect = new OO.ui.CheckboxMultiselectWidget( {\n *             items: [ option1, option2 ]\n *         } );\n *     $( document.body ).append( multiselect.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options\n *\n * @class\n * @extends OO.ui.MultiselectWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.CheckboxMultiselectWidget = function OoUiCheckboxMultiselectWidget( config ) {\n\t// Parent constructor\n\tOO.ui.CheckboxMultiselectWidget.parent.call( this, config );\n\n\t// Properties\n\tthis.$lastClicked = null;\n\n\t// Events\n\tthis.$group.on( 'click', this.onClick.bind( this ) );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-checkboxMultiselectWidget' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.CheckboxMultiselectWidget, OO.ui.MultiselectWidget );\n\n/* Methods */\n\n/**\n * Get an option by its position relative to the specified item (or to the start of the\n * option array, if item is `null`). The direction in which to search through the option array\n * is specified with a number: -1 for reverse (the default) or 1 for forward. The method will\n * return an option, or `null` if there are no options in the array.\n *\n * @param {OO.ui.CheckboxMultioptionWidget|null} item Item to describe the start position, or\n *  `null` to start at the beginning of the array.\n * @param {number} direction Direction to move in: -1 to move backward, 1 to move forward\n * @return {OO.ui.CheckboxMultioptionWidget|null} Item at position, `null` if there are no items\n *  in the select.\n */\nOO.ui.CheckboxMultiselectWidget.prototype.getRelativeFocusableItem = function ( item, direction ) {\n\tvar currentIndex, nextIndex, i,\n\t\tincrease = direction > 0 ? 1 : -1,\n\t\tlen = this.items.length;\n\n\tif ( item ) {\n\t\tcurrentIndex = this.items.indexOf( item );\n\t\tnextIndex = ( currentIndex + increase + len ) % len;\n\t} else {\n\t\t// If no item is selected and moving forward, start at the beginning.\n\t\t// If moving backward, start at the end.\n\t\tnextIndex = direction > 0 ? 0 : len - 1;\n\t}\n\n\tfor ( i = 0; i < len; i++ ) {\n\t\titem = this.items[ nextIndex ];\n\t\tif ( item && !item.isDisabled() ) {\n\t\t\treturn item;\n\t\t}\n\t\tnextIndex = ( nextIndex + increase + len ) % len;\n\t}\n\treturn null;\n};\n\n/**\n * Handle click events on checkboxes.\n *\n * @param {jQuery.Event} e\n */\nOO.ui.CheckboxMultiselectWidget.prototype.onClick = function ( e ) {\n\tvar $options, lastClickedIndex, nowClickedIndex, i, direction, wasSelected, items,\n\t\t$lastClicked = this.$lastClicked,\n\t\t$nowClicked = $( e.target ).closest( '.oo-ui-checkboxMultioptionWidget' )\n\t\t\t.not( '.oo-ui-widget-disabled' );\n\n\t// Allow selecting multiple options at once by Shift-clicking them\n\tif ( $lastClicked && $nowClicked.length && e.shiftKey ) {\n\t\t$options = this.$group.find( '.oo-ui-checkboxMultioptionWidget' );\n\t\tlastClickedIndex = $options.index( $lastClicked );\n\t\tnowClickedIndex = $options.index( $nowClicked );\n\t\t// If it's the same item, either the user is being silly, or it's a fake event generated\n\t\t// by the browser. In either case we don't need custom handling.\n\t\tif ( nowClickedIndex !== lastClickedIndex ) {\n\t\t\titems = this.items;\n\t\t\twasSelected = items[ nowClickedIndex ].isSelected();\n\t\t\tdirection = nowClickedIndex > lastClickedIndex ? 1 : -1;\n\n\t\t\t// This depends on the DOM order of the items and the order of the .items array being\n\t\t\t// the same.\n\t\t\tfor ( i = lastClickedIndex; i !== nowClickedIndex; i += direction ) {\n\t\t\t\tif ( !items[ i ].isDisabled() ) {\n\t\t\t\t\titems[ i ].setSelected( !wasSelected );\n\t\t\t\t}\n\t\t\t}\n\t\t\t// For the now-clicked element, use immediate timeout to allow the browser to do its own\n\t\t\t// handling first, then set our value. The order in which events happen is different for\n\t\t\t// clicks on the <input> and on the <label> and there are additional fake clicks fired\n\t\t\t// for non-click actions that change the checkboxes.\n\t\t\te.preventDefault();\n\t\t\tsetTimeout( function () {\n\t\t\t\tif ( !items[ nowClickedIndex ].isDisabled() ) {\n\t\t\t\t\titems[ nowClickedIndex ].setSelected( !wasSelected );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t}\n\n\tif ( $nowClicked.length ) {\n\t\tthis.$lastClicked = $nowClicked;\n\t}\n};\n\n/**\n * Focus the widget\n *\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.CheckboxMultiselectWidget.prototype.focus = function () {\n\tvar item;\n\tif ( !this.isDisabled() ) {\n\t\titem = this.getRelativeFocusableItem( null, 1 );\n\t\tif ( item ) {\n\t\t\titem.focus();\n\t\t}\n\t}\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxMultiselectWidget.prototype.simulateLabelClick = function () {\n\tthis.focus();\n};\n","/**\n * Progress bars visually display the status of an operation, such as a download,\n * and can be either determinate or indeterminate:\n *\n * - **determinate** process bars show the percent of an operation that is complete.\n *\n * - **indeterminate** process bars use a visual display of motion to indicate that an operation\n *   is taking place. Because the extent of an indeterminate operation is unknown, the bar does\n *   not use percentages.\n *\n * The value of the `progress` configuration determines whether the bar is determinate\n * or indeterminate.\n *\n *     @example\n *     // Examples of determinate and indeterminate progress bars.\n *     var progressBar1 = new OO.ui.ProgressBarWidget( {\n *         progress: 33\n *     } );\n *     var progressBar2 = new OO.ui.ProgressBarWidget();\n *\n *     // Create a FieldsetLayout to layout progress bars.\n *     var fieldset = new OO.ui.FieldsetLayout;\n *     fieldset.addItems( [\n *         new OO.ui.FieldLayout( progressBar1, {\n *             label: 'Determinate',\n *             align: 'top'\n *         } ),\n *         new OO.ui.FieldLayout( progressBar2, {\n *             label: 'Indeterminate',\n *             align: 'top'\n *         } )\n *     ] );\n *     $( document.body ).append( fieldset.$element );\n *\n * @class\n * @extends OO.ui.Widget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {number|boolean} [progress=false] The type of progress bar (determinate or indeterminate).\n *  To create a determinate progress bar, specify a number that reflects the initial\n *  percent complete.\n *  By default, the progress bar is indeterminate.\n */\nOO.ui.ProgressBarWidget = function OoUiProgressBarWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.ProgressBarWidget.parent.call( this, config );\n\n\t// Properties\n\tthis.$bar = $( '<div>' );\n\tthis.progress = null;\n\n\t// Initialization\n\tthis.setProgress( config.progress !== undefined ? config.progress : false );\n\tthis.$bar.addClass( 'oo-ui-progressBarWidget-bar' );\n\tthis.$element\n\t\t.attr( {\n\t\t\trole: 'progressbar',\n\t\t\t'aria-valuemin': 0,\n\t\t\t'aria-valuemax': 100\n\t\t} )\n\t\t.addClass( 'oo-ui-progressBarWidget' )\n\t\t.append( this.$bar );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ProgressBarWidget, OO.ui.Widget );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.ProgressBarWidget.static.tagName = 'div';\n\n/* Methods */\n\n/**\n * Get the percent of the progress that has been completed. Indeterminate progresses will\n * return `false`.\n *\n * @return {number|boolean} Progress percent\n */\nOO.ui.ProgressBarWidget.prototype.getProgress = function () {\n\treturn this.progress;\n};\n\n/**\n * Set the percent of the process completed or `false` for an indeterminate process.\n *\n * @param {number|boolean} progress Progress percent or `false` for indeterminate\n */\nOO.ui.ProgressBarWidget.prototype.setProgress = function ( progress ) {\n\tthis.progress = progress;\n\n\tif ( progress !== false ) {\n\t\tthis.$bar.css( 'width', this.progress + '%' );\n\t\tthis.$element.attr( 'aria-valuenow', this.progress );\n\t} else {\n\t\tthis.$bar.css( 'width', '' );\n\t\tthis.$element.removeAttr( 'aria-valuenow' );\n\t}\n\tthis.$element.toggleClass( 'oo-ui-progressBarWidget-indeterminate', progress === false );\n};\n","/**\n * InputWidget is the base class for all input widgets, which\n * include {@link OO.ui.TextInputWidget text inputs}, {@link OO.ui.CheckboxInputWidget checkbox\n * inputs}, {@link OO.ui.RadioInputWidget radio inputs}, and\n * {@link OO.ui.ButtonInputWidget button inputs}.\n * See the [OOUI documentation on MediaWiki] [1] for more information and examples.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs\n *\n * @abstract\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.TabIndexedElement\n * @mixins OO.ui.mixin.TitledElement\n * @mixins OO.ui.mixin.AccessKeyedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {string} [name=''] The value of the input’s HTML `name` attribute.\n * @cfg {string} [value=''] The value of the input.\n * @cfg {string} [dir] The directionality of the input (ltr/rtl).\n * @cfg {string} [inputId] The value of the input’s HTML `id` attribute.\n * @cfg {Function} [inputFilter] The name of an input filter function. Input filters modify the\n *  value of an input before it is accepted.\n */\nOO.ui.InputWidget = function OoUiInputWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.InputWidget.parent.call( this, config );\n\n\t// Properties\n\t// See #reusePreInfuseDOM about config.$input\n\tthis.$input = config.$input || this.getInputElement( config );\n\tthis.value = '';\n\tthis.inputFilter = config.inputFilter;\n\n\t// Mixin constructors\n\tOO.ui.mixin.TabIndexedElement.call( this, $.extend( {\n\t\t$tabIndexed: this.$input\n\t}, config ) );\n\tOO.ui.mixin.TitledElement.call( this, $.extend( {\n\t\t$titled: this.$input\n\t}, config ) );\n\tOO.ui.mixin.AccessKeyedElement.call( this, $.extend( {\n\t\t$accessKeyed: this.$input\n\t}, config ) );\n\n\t// Events\n\tthis.$input.on( 'keydown mouseup cut paste change input select', this.onEdit.bind( this ) );\n\n\t// Initialization\n\tthis.$input\n\t\t.addClass( 'oo-ui-inputWidget-input' )\n\t\t.attr( 'name', config.name )\n\t\t.prop( 'disabled', this.isDisabled() );\n\tthis.$element\n\t\t.addClass( 'oo-ui-inputWidget' )\n\t\t.append( this.$input );\n\tthis.setValue( config.value );\n\tif ( config.dir ) {\n\t\tthis.setDir( config.dir );\n\t}\n\tif ( config.inputId !== undefined ) {\n\t\tthis.setInputId( config.inputId );\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.InputWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.InputWidget, OO.ui.mixin.TabIndexedElement );\nOO.mixinClass( OO.ui.InputWidget, OO.ui.mixin.TitledElement );\nOO.mixinClass( OO.ui.InputWidget, OO.ui.mixin.AccessKeyedElement );\n\n/* Static Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.InputWidget.static.reusePreInfuseDOM = function ( node, config ) {\n\tconfig = OO.ui.InputWidget.parent.static.reusePreInfuseDOM( node, config );\n\t// Reusing `$input` lets browsers preserve inputted values across page reloads, see T114134.\n\tconfig.$input = $( node ).find( '.oo-ui-inputWidget-input' );\n\treturn config;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.InputWidget.static.gatherPreInfuseState = function ( node, config ) {\n\tvar state = OO.ui.InputWidget.parent.static.gatherPreInfuseState( node, config );\n\tif ( config.$input && config.$input.length ) {\n\t\tstate.value = config.$input.val();\n\t\t// Might be better in TabIndexedElement, but it's awkward to do there because\n\t\t// mixins are awkward\n\t\tstate.focus = config.$input.is( ':focus' );\n\t}\n\treturn state;\n};\n\n/* Events */\n\n/**\n * @event change\n *\n * A change event is emitted when the value of the input changes.\n *\n * @param {string} value\n */\n\n/* Methods */\n\n/**\n * Get input element.\n *\n * Subclasses of OO.ui.InputWidget use the `config` parameter to produce different elements in\n * different circumstances. The element must have a `value` property (like form elements).\n *\n * @protected\n * @param {Object} config Configuration options\n * @return {jQuery} Input element\n */\nOO.ui.InputWidget.prototype.getInputElement = function () {\n\treturn $( '<input>' );\n};\n\n/**\n * Handle potentially value-changing events.\n *\n * @private\n * @param {jQuery.Event} e Key down, mouse up, cut, paste, change, input, or select event\n */\nOO.ui.InputWidget.prototype.onEdit = function () {\n\tvar widget = this;\n\tif ( !this.isDisabled() ) {\n\t\t// Allow the stack to clear so the value will be updated\n\t\tsetTimeout( function () {\n\t\t\twidget.setValue( widget.$input.val() );\n\t\t} );\n\t}\n};\n\n/**\n * Get the value of the input.\n *\n * @return {string} Input value\n */\nOO.ui.InputWidget.prototype.getValue = function () {\n\t// Resynchronize our internal data with DOM data. Other scripts executing on the page can modify\n\t// it, and we won't know unless they're kind enough to trigger a 'change' event.\n\tvar value = this.$input.val();\n\tif ( this.value !== value ) {\n\t\tthis.setValue( value );\n\t}\n\treturn this.value;\n};\n\n/**\n * Set the directionality of the input.\n *\n * @param {string} dir Text directionality: 'ltr', 'rtl' or 'auto'\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.InputWidget.prototype.setDir = function ( dir ) {\n\tthis.$input.prop( 'dir', dir );\n\treturn this;\n};\n\n/**\n * Set the value of the input.\n *\n * @param {string} value New value\n * @fires change\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.InputWidget.prototype.setValue = function ( value ) {\n\tvalue = this.cleanUpValue( value );\n\t// Update the DOM if it has changed. Note that with cleanUpValue, it\n\t// is possible for the DOM value to change without this.value changing.\n\tif ( this.$input.val() !== value ) {\n\t\tthis.$input.val( value );\n\t}\n\tif ( this.value !== value ) {\n\t\tthis.value = value;\n\t\tthis.emit( 'change', this.value );\n\t}\n\t// The first time that the value is set (probably while constructing the widget),\n\t// remember it in defaultValue. This property can be later used to check whether\n\t// the value of the input has been changed since it was created.\n\tif ( this.defaultValue === undefined ) {\n\t\tthis.defaultValue = this.value;\n\t\tthis.$input[ 0 ].defaultValue = this.defaultValue;\n\t}\n\treturn this;\n};\n\n/**\n * Clean up incoming value.\n *\n * Ensures value is a string, and converts undefined and null to empty string.\n *\n * @private\n * @param {string} value Original value\n * @return {string} Cleaned up value\n */\nOO.ui.InputWidget.prototype.cleanUpValue = function ( value ) {\n\tif ( value === undefined || value === null ) {\n\t\treturn '';\n\t} else if ( this.inputFilter ) {\n\t\treturn this.inputFilter( String( value ) );\n\t} else {\n\t\treturn String( value );\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.InputWidget.prototype.setDisabled = function ( state ) {\n\tOO.ui.InputWidget.parent.prototype.setDisabled.call( this, state );\n\tif ( this.$input ) {\n\t\tthis.$input.prop( 'disabled', this.isDisabled() );\n\t}\n\treturn this;\n};\n\n/**\n * Set the 'id' attribute of the `<input>` element.\n *\n * @param {string} id\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.InputWidget.prototype.setInputId = function ( id ) {\n\tthis.$input.attr( 'id', id );\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.InputWidget.prototype.restorePreInfuseState = function ( state ) {\n\tOO.ui.InputWidget.parent.prototype.restorePreInfuseState.call( this, state );\n\tif ( state.value !== undefined && state.value !== this.getValue() ) {\n\t\tthis.setValue( state.value );\n\t}\n\tif ( state.focus ) {\n\t\tthis.focus();\n\t}\n};\n","/**\n * Data widget intended for creating `<input type=\"hidden\">` inputs.\n *\n * @class\n * @extends OO.ui.Widget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {string} [value=''] The value of the input.\n * @cfg {string} [name=''] The value of the input’s HTML `name` attribute.\n */\nOO.ui.HiddenInputWidget = function OoUiHiddenInputWidget( config ) {\n\t// Configuration initialization\n\tconfig = $.extend( { value: '', name: '' }, config );\n\n\t// Parent constructor\n\tOO.ui.HiddenInputWidget.parent.call( this, config );\n\n\t// Initialization\n\tthis.$element.attr( {\n\t\ttype: 'hidden',\n\t\tvalue: config.value,\n\t\tname: config.name\n\t} );\n\tthis.$element.removeAttr( 'aria-disabled' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.HiddenInputWidget, OO.ui.Widget );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.HiddenInputWidget.static.tagName = 'input';\n","/**\n * ButtonInputWidget is used to submit HTML forms and is intended to be used within\n * a OO.ui.FormLayout. If you do not need the button to work with HTML forms, you probably\n * want to use OO.ui.ButtonWidget instead. Button input widgets can be rendered as either an\n * HTML `<button>` (the default) or an HTML `<input>` tags. See the\n * [OOUI documentation on MediaWiki] [1] for more information.\n *\n *     @example\n *     // A ButtonInputWidget rendered as an HTML button, the default.\n *     var button = new OO.ui.ButtonInputWidget( {\n *         label: 'Input button',\n *         icon: 'check',\n *         value: 'check'\n *     } );\n *     $( document.body ).append( button.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs#Button_inputs\n *\n * @class\n * @extends OO.ui.InputWidget\n * @mixins OO.ui.mixin.ButtonElement\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.IndicatorElement\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.FlaggedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {string} [type='button'] The value of the HTML `'type'` attribute:\n *  'button', 'submit' or 'reset'.\n * @cfg {boolean} [useInputTag=false] Use an `<input>` tag instead of a `<button>` tag, the default.\n *  Widgets configured to be an `<input>` do not support {@link #icon icons} and\n *  {@link #indicator indicators},\n *  non-plaintext {@link #label labels}, or {@link #value values}. In general, useInputTag should\n *  only be set to `true` when there’s need to support IE 6 in a form with multiple buttons.\n */\nOO.ui.ButtonInputWidget = function OoUiButtonInputWidget( config ) {\n\t// Configuration initialization\n\tconfig = $.extend( { type: 'button', useInputTag: false }, config );\n\n\t// See InputWidget#reusePreInfuseDOM about config.$input\n\tif ( config.$input ) {\n\t\tconfig.$input.empty();\n\t}\n\n\t// Properties (must be set before parent constructor, which calls #setValue)\n\tthis.useInputTag = config.useInputTag;\n\n\t// Parent constructor\n\tOO.ui.ButtonInputWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.ButtonElement.call( this, $.extend( {\n\t\t$button: this.$input\n\t}, config ) );\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.IndicatorElement.call( this, config );\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.FlaggedElement.call( this, config );\n\n\t// Initialization\n\tif ( !config.useInputTag ) {\n\t\tthis.$input.append( this.$icon, this.$label, this.$indicator );\n\t}\n\tthis.$element.addClass( 'oo-ui-buttonInputWidget' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ButtonInputWidget, OO.ui.InputWidget );\nOO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.mixin.ButtonElement );\nOO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.mixin.IndicatorElement );\nOO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.mixin.FlaggedElement );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.ButtonInputWidget.static.tagName = 'span';\n\n/* Methods */\n\n/**\n * @inheritdoc\n * @protected\n */\nOO.ui.ButtonInputWidget.prototype.getInputElement = function ( config ) {\n\tvar type;\n\ttype = [ 'button', 'submit', 'reset' ].indexOf( config.type ) !== -1 ? config.type : 'button';\n\treturn $( '<' + ( config.useInputTag ? 'input' : 'button' ) + ' type=\"' + type + '\">' );\n};\n\n/**\n * Set label value.\n *\n * If #useInputTag is `true`, the label is set as the `value` of the `<input>` tag.\n *\n * @param {jQuery|string|Function|null} label Label nodes, text, a function that returns nodes or\n *  text, or `null` for no label\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.ButtonInputWidget.prototype.setLabel = function ( label ) {\n\tif ( typeof label === 'function' ) {\n\t\tlabel = OO.ui.resolveMsg( label );\n\t}\n\n\tif ( this.useInputTag ) {\n\t\t// Discard non-plaintext labels\n\t\tif ( typeof label !== 'string' ) {\n\t\t\tlabel = '';\n\t\t}\n\n\t\tthis.$input.val( label );\n\t}\n\n\treturn OO.ui.mixin.LabelElement.prototype.setLabel.call( this, label );\n};\n\n/**\n * Set the value of the input.\n *\n * This method is disabled for button inputs configured as {@link #useInputTag <input> tags}, as\n * they do not support {@link #value values}.\n *\n * @param {string} value New value\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.ButtonInputWidget.prototype.setValue = function ( value ) {\n\tif ( !this.useInputTag ) {\n\t\tOO.ui.ButtonInputWidget.parent.prototype.setValue.call( this, value );\n\t}\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.ButtonInputWidget.prototype.getInputId = function () {\n\t// Disable generating `<label>` elements for buttons. One would very rarely need additional\n\t// label for a button, and it's already a big clickable target, and it causes\n\t// unexpected rendering.\n\treturn null;\n};\n","/**\n * CheckboxInputWidgets, like HTML checkboxes, can be selected and/or configured with a value.\n * Note that these {@link OO.ui.InputWidget input widgets} are best laid out\n * in {@link OO.ui.FieldLayout field layouts} that use the {@link OO.ui.FieldLayout#align inline}\n * alignment. For more information, please see the [OOUI documentation on MediaWiki][1].\n *\n * This widget can be used inside an HTML form, such as a OO.ui.FormLayout.\n *\n *     @example\n *     // An example of selected, unselected, and disabled checkbox inputs.\n *     var checkbox1 = new OO.ui.CheckboxInputWidget( {\n *             value: 'a',\n *              selected: true\n *         } ),\n *         checkbox2 = new OO.ui.CheckboxInputWidget( {\n *             value: 'b'\n *         } ),\n *         checkbox3 = new OO.ui.CheckboxInputWidget( {\n *             value:'c',\n *             disabled: true\n *         } ),\n *         // Create a fieldset layout with fields for each checkbox.\n *         fieldset = new OO.ui.FieldsetLayout( {\n *             label: 'Checkboxes'\n *         } );\n *     fieldset.addItems( [\n *         new OO.ui.FieldLayout( checkbox1, { label: 'Selected checkbox', align: 'inline' } ),\n *         new OO.ui.FieldLayout( checkbox2, { label: 'Unselected checkbox', align: 'inline' } ),\n *         new OO.ui.FieldLayout( checkbox3, { label: 'Disabled checkbox', align: 'inline' } ),\n *     ] );\n *     $( document.body ).append( fieldset.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs\n *\n * @class\n * @extends OO.ui.InputWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [selected=false] Select the checkbox initially. By default, the checkbox is\n *  not selected.\n * @cfg {boolean} [indeterminate=false] Whether the checkbox is in the indeterminate state.\n */\nOO.ui.CheckboxInputWidget = function OoUiCheckboxInputWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.CheckboxInputWidget.parent.call( this, config );\n\n\t// Properties\n\tthis.checkIcon = new OO.ui.IconWidget( {\n\t\ticon: 'check',\n\t\tclasses: [ 'oo-ui-checkboxInputWidget-checkIcon' ]\n\t} );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-checkboxInputWidget' )\n\t\t// Required for pretty styling in WikimediaUI theme\n\t\t.append( this.checkIcon.$element );\n\tthis.setSelected( config.selected !== undefined ? config.selected : false );\n\tthis.setIndeterminate( config.indeterminate !== undefined ? config.indeterminate : false );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.CheckboxInputWidget, OO.ui.InputWidget );\n\n/* Events */\n\n/**\n * @event change\n *\n * A change event is emitted when the state of the input changes.\n *\n * @param {boolean} selected\n * @param {boolean} indeterminate\n */\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.CheckboxInputWidget.static.tagName = 'span';\n\n/* Static Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxInputWidget.static.gatherPreInfuseState = function ( node, config ) {\n\tvar state = OO.ui.CheckboxInputWidget.parent.static.gatherPreInfuseState( node, config );\n\tstate.checked = config.$input.prop( 'checked' );\n\treturn state;\n};\n\n/* Methods */\n\n/**\n * @inheritdoc\n * @protected\n */\nOO.ui.CheckboxInputWidget.prototype.getInputElement = function () {\n\treturn $( '<input>' ).attr( 'type', 'checkbox' );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxInputWidget.prototype.onEdit = function () {\n\tvar widget = this;\n\tif ( !this.isDisabled() ) {\n\t\t// Allow the stack to clear so the value will be updated\n\t\tsetTimeout( function () {\n\t\t\twidget.setSelected( widget.$input.prop( 'checked' ) );\n\t\t\twidget.setIndeterminate( widget.$input.prop( 'indeterminate' ) );\n\t\t} );\n\t}\n};\n\n/**\n * Set selection state of this checkbox.\n *\n * @param {boolean} state Selected state\n * @param {boolean} internal Used for internal calls to suppress events\n * @chainable\n * @return {OO.ui.CheckboxInputWidget} The widget, for chaining\n */\nOO.ui.CheckboxInputWidget.prototype.setSelected = function ( state, internal ) {\n\tstate = !!state;\n\tif ( this.selected !== state ) {\n\t\tthis.selected = state;\n\t\tthis.$input.prop( 'checked', this.selected );\n\t\tif ( !internal ) {\n\t\t\tthis.setIndeterminate( false, true );\n\t\t\tthis.emit( 'change', this.selected, this.indeterminate );\n\t\t}\n\t}\n\t// The first time that the selection state is set (probably while constructing the widget),\n\t// remember it in defaultSelected. This property can be later used to check whether\n\t// the selection state of the input has been changed since it was created.\n\tif ( this.defaultSelected === undefined ) {\n\t\tthis.defaultSelected = this.selected;\n\t\tthis.$input[ 0 ].defaultChecked = this.defaultSelected;\n\t}\n\treturn this;\n};\n\n/**\n * Check if this checkbox is selected.\n *\n * @return {boolean} Checkbox is selected\n */\nOO.ui.CheckboxInputWidget.prototype.isSelected = function () {\n\t// Resynchronize our internal data with DOM data. Other scripts executing on the page can modify\n\t// it, and we won't know unless they're kind enough to trigger a 'change' event.\n\tvar selected = this.$input.prop( 'checked' );\n\tif ( this.selected !== selected ) {\n\t\tthis.setSelected( selected );\n\t}\n\treturn this.selected;\n};\n\n/**\n * Set indeterminate state of this checkbox.\n *\n * @param {boolean} state Indeterminate state\n * @param {boolean} internal Used for internal calls to suppress events\n * @chainable\n * @return {OO.ui.CheckboxInputWidget} The widget, for chaining\n */\nOO.ui.CheckboxInputWidget.prototype.setIndeterminate = function ( state, internal ) {\n\tstate = !!state;\n\tif ( this.indeterminate !== state ) {\n\t\tthis.indeterminate = state;\n\t\tthis.$input.prop( 'indeterminate', this.indeterminate );\n\t\tif ( !internal ) {\n\t\t\tthis.setSelected( false, true );\n\t\t\tthis.emit( 'change', this.selected, this.indeterminate );\n\t\t}\n\t}\n\treturn this;\n};\n\n/**\n * Check if this checkbox is selected.\n *\n * @return {boolean} Checkbox is selected\n */\nOO.ui.CheckboxInputWidget.prototype.isIndeterminate = function () {\n\t// Resynchronize our internal data with DOM data. Other scripts executing on the page can modify\n\t// it, and we won't know unless they're kind enough to trigger a 'change' event.\n\tvar indeterminate = this.$input.prop( 'indeterminate' );\n\tif ( this.indeterminate !== indeterminate ) {\n\t\tthis.setIndeterminate( indeterminate );\n\t}\n\treturn this.indeterminate;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxInputWidget.prototype.simulateLabelClick = function () {\n\tif ( !this.isDisabled() ) {\n\t\tthis.$handle.trigger( 'click' );\n\t}\n\tthis.focus();\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxInputWidget.prototype.restorePreInfuseState = function ( state ) {\n\tOO.ui.CheckboxInputWidget.parent.prototype.restorePreInfuseState.call( this, state );\n\tif ( state.checked !== undefined && state.checked !== this.isSelected() ) {\n\t\tthis.setSelected( state.checked );\n\t}\n};\n","/**\n * DropdownInputWidget is a {@link OO.ui.DropdownWidget DropdownWidget} intended to be used\n * within an HTML form, such as a OO.ui.FormLayout. The selected value is synchronized with the\n * value of a hidden HTML `input` tag. Please see the [OOUI documentation on MediaWiki][1] for\n * more information about input widgets.\n *\n * A DropdownInputWidget always has a value (one of the options is always selected), unless there\n * are no options. If no `value` configuration option is provided, the first option is selected.\n * If you need a state representing no value (no option being selected), use a DropdownWidget.\n *\n * This and OO.ui.RadioSelectInputWidget support similar configuration options.\n *\n *     @example\n *     // A DropdownInputWidget with three options.\n *     var dropdownInput = new OO.ui.DropdownInputWidget( {\n *         options: [\n *             { data: 'a', label: 'First' },\n *             { data: 'b', label: 'Second', disabled: true },\n *             { optgroup: 'Group label' },\n *             { data: 'c', label: 'First sub-item)' }\n *         ]\n *     } );\n *     $( document.body ).append( dropdownInput.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs\n *\n * @class\n * @extends OO.ui.InputWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {Object[]} [options=[]] Array of menu options in the format described above.\n * @cfg {Object} [dropdown] Configuration options for {@link OO.ui.DropdownWidget DropdownWidget}\n * @cfg {jQuery} [$overlay] Render the menu into a separate layer. This configuration is useful\n *  in cases where the expanded menu is larger than its containing `<div>`. The specified overlay\n *  layer is usually on top of the containing `<div>` and has a larger area. By default, the menu\n *  uses relative positioning.\n *  See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.\n */\nOO.ui.DropdownInputWidget = function OoUiDropdownInputWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties (must be done before parent constructor which calls #setDisabled)\n\tthis.dropdownWidget = new OO.ui.DropdownWidget( $.extend(\n\t\t{\n\t\t\t$overlay: config.$overlay\n\t\t},\n\t\tconfig.dropdown\n\t) );\n\t// Set up the options before parent constructor, which uses them to validate config.value.\n\t// Use this instead of setOptions() because this.$input is not set up yet.\n\tthis.setOptionsData( config.options || [] );\n\n\t// Parent constructor\n\tOO.ui.DropdownInputWidget.parent.call( this, config );\n\n\t// Events\n\tthis.dropdownWidget.getMenu().connect( this, {\n\t\tselect: 'onMenuSelect'\n\t} );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-dropdownInputWidget' )\n\t\t.append( this.dropdownWidget.$element );\n\tthis.setTabIndexedElement( this.dropdownWidget.$tabIndexed );\n\tthis.setTitledElement( this.dropdownWidget.$handle );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.DropdownInputWidget, OO.ui.InputWidget );\n\n/* Methods */\n\n/**\n * @inheritdoc\n * @protected\n */\nOO.ui.DropdownInputWidget.prototype.getInputElement = function () {\n\treturn $( '<select>' );\n};\n\n/**\n * Handles menu select events.\n *\n * @private\n * @param {OO.ui.MenuOptionWidget|null} item Selected menu item\n */\nOO.ui.DropdownInputWidget.prototype.onMenuSelect = function ( item ) {\n\tthis.setValue( item ? item.getData() : '' );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.DropdownInputWidget.prototype.setValue = function ( value ) {\n\tvar selected;\n\tvalue = this.cleanUpValue( value );\n\t// Only allow setting values that are actually present in the dropdown\n\tselected = this.dropdownWidget.getMenu().findItemFromData( value ) ||\n\t\tthis.dropdownWidget.getMenu().findFirstSelectableItem();\n\tthis.dropdownWidget.getMenu().selectItem( selected );\n\tvalue = selected ? selected.getData() : '';\n\tOO.ui.DropdownInputWidget.parent.prototype.setValue.call( this, value );\n\tif ( this.optionsDirty ) {\n\t\t// We reached this from the constructor or from #setOptions.\n\t\t// We have to update the <select> element.\n\t\tthis.updateOptionsInterface();\n\t}\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.DropdownInputWidget.prototype.setDisabled = function ( state ) {\n\tthis.dropdownWidget.setDisabled( state );\n\tOO.ui.DropdownInputWidget.parent.prototype.setDisabled.call( this, state );\n\treturn this;\n};\n\n/**\n * Set the options available for this input.\n *\n * @param {Object[]} options Array of menu options in the format `{ data: …, label: … }`\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.DropdownInputWidget.prototype.setOptions = function ( options ) {\n\tvar value = this.getValue();\n\n\tthis.setOptionsData( options );\n\n\t// Re-set the value to update the visible interface (DropdownWidget and <select>).\n\t// In case the previous value is no longer an available option, select the first valid one.\n\tthis.setValue( value );\n\n\treturn this;\n};\n\n/**\n * Set the internal list of options, used e.g. by setValue() to see which options are allowed.\n *\n * This method may be called before the parent constructor, so various properties may not be\n * initialized yet.\n *\n * @param {Object[]} options Array of menu options (see #constructor for details).\n * @private\n */\nOO.ui.DropdownInputWidget.prototype.setOptionsData = function ( options ) {\n\tvar optionWidgets, optIndex, opt, previousOptgroup, optionWidget, optValue,\n\t\twidget = this;\n\n\tthis.optionsDirty = true;\n\n\t// Go through all the supplied option configs and create either\n\t// MenuSectionOption or MenuOption widgets from each.\n\toptionWidgets = [];\n\tfor ( optIndex = 0; optIndex < options.length; optIndex++ ) {\n\t\topt = options[ optIndex ];\n\n\t\tif ( opt.optgroup !== undefined ) {\n\t\t\t// Create a <optgroup> menu item.\n\t\t\toptionWidget = widget.createMenuSectionOptionWidget( opt.optgroup );\n\t\t\tpreviousOptgroup = optionWidget;\n\n\t\t} else {\n\t\t\t// Create a normal <option> menu item.\n\t\t\toptValue = widget.cleanUpValue( opt.data );\n\t\t\toptionWidget = widget.createMenuOptionWidget(\n\t\t\t\toptValue,\n\t\t\t\topt.label !== undefined ? opt.label : optValue\n\t\t\t);\n\t\t}\n\n\t\t// Disable the menu option if it is itself disabled or if its parent optgroup is disabled.\n\t\tif (\n\t\t\topt.disabled !== undefined ||\n\t\t\tpreviousOptgroup instanceof OO.ui.MenuSectionOptionWidget &&\n\t\t\tpreviousOptgroup.isDisabled()\n\t\t) {\n\t\t\toptionWidget.setDisabled( true );\n\t\t}\n\n\t\toptionWidgets.push( optionWidget );\n\t}\n\n\tthis.dropdownWidget.getMenu().clearItems().addItems( optionWidgets );\n};\n\n/**\n * Create a menu option widget.\n *\n * @protected\n * @param {string} data Item data\n * @param {string} label Item label\n * @return {OO.ui.MenuOptionWidget} Option widget\n */\nOO.ui.DropdownInputWidget.prototype.createMenuOptionWidget = function ( data, label ) {\n\treturn new OO.ui.MenuOptionWidget( {\n\t\tdata: data,\n\t\tlabel: label\n\t} );\n};\n\n/**\n * Create a menu section option widget.\n *\n * @protected\n * @param {string} label Section item label\n * @return {OO.ui.MenuSectionOptionWidget} Menu section option widget\n */\nOO.ui.DropdownInputWidget.prototype.createMenuSectionOptionWidget = function ( label ) {\n\treturn new OO.ui.MenuSectionOptionWidget( {\n\t\tlabel: label\n\t} );\n};\n\n/**\n * Update the user-visible interface to match the internal list of options and value.\n *\n * This method must only be called after the parent constructor.\n *\n * @private\n */\nOO.ui.DropdownInputWidget.prototype.updateOptionsInterface = function () {\n\tvar\n\t\t$optionsContainer = this.$input,\n\t\tdefaultValue = this.defaultValue,\n\t\twidget = this;\n\n\tthis.$input.empty();\n\n\tthis.dropdownWidget.getMenu().getItems().forEach( function ( optionWidget ) {\n\t\tvar $optionNode;\n\n\t\tif ( !( optionWidget instanceof OO.ui.MenuSectionOptionWidget ) ) {\n\t\t\t$optionNode = $( '<option>' )\n\t\t\t\t.attr( 'value', optionWidget.getData() )\n\t\t\t\t.text( optionWidget.getLabel() );\n\n\t\t\t// Remember original selection state. This property can be later used to check whether\n\t\t\t// the selection state of the input has been changed since it was created.\n\t\t\t$optionNode[ 0 ].defaultSelected = ( optionWidget.getData() === defaultValue );\n\n\t\t\t$optionsContainer.append( $optionNode );\n\t\t} else {\n\t\t\t$optionNode = $( '<optgroup>' )\n\t\t\t\t.attr( 'label', optionWidget.getLabel() );\n\t\t\twidget.$input.append( $optionNode );\n\t\t\t$optionsContainer = $optionNode;\n\t\t}\n\n\t\t// Disable the option or optgroup if required.\n\t\tif ( optionWidget.isDisabled() ) {\n\t\t\t$optionNode.prop( 'disabled', true );\n\t\t}\n\t} );\n\n\tthis.optionsDirty = false;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.DropdownInputWidget.prototype.focus = function () {\n\tthis.dropdownWidget.focus();\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.DropdownInputWidget.prototype.blur = function () {\n\tthis.dropdownWidget.blur();\n\treturn this;\n};\n","/**\n * RadioInputWidget creates a single radio button. Because radio buttons are usually used as a set,\n * in most cases you will want to use a {@link OO.ui.RadioSelectWidget radio select}\n * with {@link OO.ui.RadioOptionWidget radio options} instead of this class. For more information,\n * please see the [OOUI documentation on MediaWiki][1].\n *\n * This widget can be used inside an HTML form, such as a OO.ui.FormLayout.\n *\n *     @example\n *     // An example of selected, unselected, and disabled radio inputs\n *     var radio1 = new OO.ui.RadioInputWidget( {\n *         value: 'a',\n *         selected: true\n *     } );\n *     var radio2 = new OO.ui.RadioInputWidget( {\n *         value: 'b'\n *     } );\n *     var radio3 = new OO.ui.RadioInputWidget( {\n *         value: 'c',\n *         disabled: true\n *     } );\n *     // Create a fieldset layout with fields for each radio button.\n *     var fieldset = new OO.ui.FieldsetLayout( {\n *         label: 'Radio inputs'\n *     } );\n *     fieldset.addItems( [\n *         new OO.ui.FieldLayout( radio1, { label: 'Selected', align: 'inline' } ),\n *         new OO.ui.FieldLayout( radio2, { label: 'Unselected', align: 'inline' } ),\n *         new OO.ui.FieldLayout( radio3, { label: 'Disabled', align: 'inline' } ),\n *     ] );\n *     $( document.body ).append( fieldset.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs\n *\n * @class\n * @extends OO.ui.InputWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [selected=false] Select the radio button initially. By default, the radio button\n *  is not selected.\n */\nOO.ui.RadioInputWidget = function OoUiRadioInputWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.RadioInputWidget.parent.call( this, config );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-radioInputWidget' )\n\t\t// Required for pretty styling in WikimediaUI theme\n\t\t.append( $( '<span>' ) );\n\tthis.setSelected( config.selected !== undefined ? config.selected : false );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.RadioInputWidget, OO.ui.InputWidget );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.RadioInputWidget.static.tagName = 'span';\n\n/* Static Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioInputWidget.static.gatherPreInfuseState = function ( node, config ) {\n\tvar state = OO.ui.RadioInputWidget.parent.static.gatherPreInfuseState( node, config );\n\tstate.checked = config.$input.prop( 'checked' );\n\treturn state;\n};\n\n/* Methods */\n\n/**\n * @inheritdoc\n * @protected\n */\nOO.ui.RadioInputWidget.prototype.getInputElement = function () {\n\treturn $( '<input>' ).attr( 'type', 'radio' );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioInputWidget.prototype.onEdit = function () {\n\t// RadioInputWidget doesn't track its state.\n};\n\n/**\n * Set selection state of this radio button.\n *\n * @param {boolean} state `true` for selected\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.RadioInputWidget.prototype.setSelected = function ( state ) {\n\t// RadioInputWidget doesn't track its state.\n\tthis.$input.prop( 'checked', state );\n\t// The first time that the selection state is set (probably while constructing the widget),\n\t// remember it in defaultSelected. This property can be later used to check whether\n\t// the selection state of the input has been changed since it was created.\n\tif ( this.defaultSelected === undefined ) {\n\t\tthis.defaultSelected = state;\n\t\tthis.$input[ 0 ].defaultChecked = this.defaultSelected;\n\t}\n\treturn this;\n};\n\n/**\n * Check if this radio button is selected.\n *\n * @return {boolean} Radio is selected\n */\nOO.ui.RadioInputWidget.prototype.isSelected = function () {\n\treturn this.$input.prop( 'checked' );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioInputWidget.prototype.simulateLabelClick = function () {\n\tif ( !this.isDisabled() ) {\n\t\tthis.$input.trigger( 'click' );\n\t}\n\tthis.focus();\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioInputWidget.prototype.restorePreInfuseState = function ( state ) {\n\tOO.ui.RadioInputWidget.parent.prototype.restorePreInfuseState.call( this, state );\n\tif ( state.checked !== undefined && state.checked !== this.isSelected() ) {\n\t\tthis.setSelected( state.checked );\n\t}\n};\n","/**\n * RadioSelectInputWidget is a {@link OO.ui.RadioSelectWidget RadioSelectWidget} intended to be\n * used within an HTML form, such as a OO.ui.FormLayout. The selected value is synchronized with\n * the value of a hidden HTML `input` tag. Please see the [OOUI documentation on MediaWiki][1] for\n * more information about input widgets.\n *\n * This and OO.ui.DropdownInputWidget support similar configuration options.\n *\n *     @example\n *     // A RadioSelectInputWidget with three options\n *     var radioSelectInput = new OO.ui.RadioSelectInputWidget( {\n *         options: [\n *             { data: 'a', label: 'First' },\n *             { data: 'b', label: 'Second'},\n *             { data: 'c', label: 'Third' }\n *         ]\n *     } );\n *     $( document.body ).append( radioSelectInput.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs\n *\n * @class\n * @extends OO.ui.InputWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {Object[]} [options=[]] Array of menu options in the format `{ data: …, label: … }`\n */\nOO.ui.RadioSelectInputWidget = function OoUiRadioSelectInputWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties (must be done before parent constructor which calls #setDisabled)\n\tthis.radioSelectWidget = new OO.ui.RadioSelectWidget();\n\t// Set up the options before parent constructor, which uses them to validate config.value.\n\t// Use this instead of setOptions() because this.$input is not set up yet\n\tthis.setOptionsData( config.options || [] );\n\n\t// Parent constructor\n\tOO.ui.RadioSelectInputWidget.parent.call( this, config );\n\n\t// Events\n\tthis.radioSelectWidget.connect( this, {\n\t\tselect: 'onMenuSelect'\n\t} );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-radioSelectInputWidget' )\n\t\t.append( this.radioSelectWidget.$element );\n\tthis.setTabIndexedElement( this.radioSelectWidget.$tabIndexed );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.RadioSelectInputWidget, OO.ui.InputWidget );\n\n/* Static Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioSelectInputWidget.static.gatherPreInfuseState = function ( node, config ) {\n\tvar state = OO.ui.RadioSelectInputWidget.parent.static.gatherPreInfuseState( node, config );\n\tstate.value = $( node ).find( '.oo-ui-radioInputWidget .oo-ui-inputWidget-input:checked' ).val();\n\treturn state;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioSelectInputWidget.static.reusePreInfuseDOM = function ( node, config ) {\n\tconfig = OO.ui.RadioSelectInputWidget.parent.static.reusePreInfuseDOM( node, config );\n\t// Cannot reuse the `<input type=radio>` set\n\tdelete config.$input;\n\treturn config;\n};\n\n/* Methods */\n\n/**\n * @inheritdoc\n * @protected\n */\nOO.ui.RadioSelectInputWidget.prototype.getInputElement = function () {\n\t// Use this instead of <input type=\"hidden\">, because hidden inputs do not have separate\n\t// 'value' and 'defaultValue' properties, and InputWidget wants to handle 'defaultValue'.\n\treturn $( '<input>' ).addClass( 'oo-ui-element-hidden' );\n};\n\n/**\n * Handles menu select events.\n *\n * @private\n * @param {OO.ui.RadioOptionWidget} item Selected menu item\n */\nOO.ui.RadioSelectInputWidget.prototype.onMenuSelect = function ( item ) {\n\tthis.setValue( item.getData() );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioSelectInputWidget.prototype.setValue = function ( value ) {\n\tvar selected;\n\tvalue = this.cleanUpValue( value );\n\t// Only allow setting values that are actually present in the dropdown\n\tselected = this.radioSelectWidget.findItemFromData( value ) ||\n\t\tthis.radioSelectWidget.findFirstSelectableItem();\n\tthis.radioSelectWidget.selectItem( selected );\n\tvalue = selected ? selected.getData() : '';\n\tOO.ui.RadioSelectInputWidget.parent.prototype.setValue.call( this, value );\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioSelectInputWidget.prototype.setDisabled = function ( state ) {\n\tthis.radioSelectWidget.setDisabled( state );\n\tOO.ui.RadioSelectInputWidget.parent.prototype.setDisabled.call( this, state );\n\treturn this;\n};\n\n/**\n * Set the options available for this input.\n *\n * @param {Object[]} options Array of menu options in the format `{ data: …, label: … }`\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.RadioSelectInputWidget.prototype.setOptions = function ( options ) {\n\tvar value = this.getValue();\n\n\tthis.setOptionsData( options );\n\n\t// Re-set the value to update the visible interface (RadioSelectWidget).\n\t// In case the previous value is no longer an available option, select the first valid one.\n\tthis.setValue( value );\n\n\treturn this;\n};\n\n/**\n * Set the internal list of options, used e.g. by setValue() to see which options are allowed.\n *\n * This method may be called before the parent constructor, so various properties may not be\n * intialized yet.\n *\n * @param {Object[]} options Array of menu options in the format `{ data: …, label: … }`\n * @private\n */\nOO.ui.RadioSelectInputWidget.prototype.setOptionsData = function ( options ) {\n\tvar widget = this;\n\n\tthis.radioSelectWidget\n\t\t.clearItems()\n\t\t.addItems( options.map( function ( opt ) {\n\t\t\tvar optValue = widget.cleanUpValue( opt.data );\n\t\t\treturn new OO.ui.RadioOptionWidget( {\n\t\t\t\tdata: optValue,\n\t\t\t\tlabel: opt.label !== undefined ? opt.label : optValue\n\t\t\t} );\n\t\t} ) );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioSelectInputWidget.prototype.focus = function () {\n\tthis.radioSelectWidget.focus();\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.RadioSelectInputWidget.prototype.blur = function () {\n\tthis.radioSelectWidget.blur();\n\treturn this;\n};\n","/**\n * CheckboxMultiselectInputWidget is a\n * {@link OO.ui.CheckboxMultiselectWidget CheckboxMultiselectWidget} intended to be used within a\n * HTML form, such as a OO.ui.FormLayout. The selected values are synchronized with the value of\n * HTML `<input type=checkbox>` tags. Please see the [OOUI documentation on MediaWiki][1] for\n * more information about input widgets.\n *\n *     @example\n *     // A CheckboxMultiselectInputWidget with three options.\n *     var multiselectInput = new OO.ui.CheckboxMultiselectInputWidget( {\n *         options: [\n *             { data: 'a', label: 'First' },\n *             { data: 'b', label: 'Second' },\n *             { data: 'c', label: 'Third' }\n *         ]\n *     } );\n *     $( document.body ).append( multiselectInput.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs\n *\n * @class\n * @extends OO.ui.InputWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {Object[]} [options=[]] Array of menu options in the format\n *  `{ data: …, label: …, disabled: … }`\n */\nOO.ui.CheckboxMultiselectInputWidget = function OoUiCheckboxMultiselectInputWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties (must be done before parent constructor which calls #setDisabled)\n\tthis.checkboxMultiselectWidget = new OO.ui.CheckboxMultiselectWidget();\n\t// Must be set before the #setOptionsData call below\n\tthis.inputName = config.name;\n\t// Set up the options before parent constructor, which uses them to validate config.value.\n\t// Use this instead of setOptions() because this.$input is not set up yet\n\tthis.setOptionsData( config.options || [] );\n\n\t// Parent constructor\n\tOO.ui.CheckboxMultiselectInputWidget.parent.call( this, config );\n\n\t// Events\n\tthis.checkboxMultiselectWidget.connect( this, {\n\t\tselect: 'onCheckboxesSelect'\n\t} );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-checkboxMultiselectInputWidget' )\n\t\t.append( this.checkboxMultiselectWidget.$element );\n\t// We don't use this.$input, but rather the CheckboxInputWidgets inside each option\n\tthis.$input.detach();\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.CheckboxMultiselectInputWidget, OO.ui.InputWidget );\n\n/* Static Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxMultiselectInputWidget.static.gatherPreInfuseState = function ( node, config ) {\n\tvar state = OO.ui.CheckboxMultiselectInputWidget.parent.static.gatherPreInfuseState(\n\t\tnode, config\n\t);\n\tstate.value = $( node ).find( '.oo-ui-checkboxInputWidget .oo-ui-inputWidget-input:checked' )\n\t\t.toArray().map( function ( el ) { return el.value; } );\n\treturn state;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxMultiselectInputWidget.static.reusePreInfuseDOM = function ( node, config ) {\n\tconfig = OO.ui.CheckboxMultiselectInputWidget.parent.static.reusePreInfuseDOM( node, config );\n\t// Cannot reuse the `<input type=checkbox>` set\n\tdelete config.$input;\n\treturn config;\n};\n\n/* Methods */\n\n/**\n * @inheritdoc\n * @protected\n */\nOO.ui.CheckboxMultiselectInputWidget.prototype.getInputElement = function () {\n\t// Actually unused\n\treturn $( '<unused>' );\n};\n\n/**\n * Handles CheckboxMultiselectWidget select events.\n *\n * @private\n */\nOO.ui.CheckboxMultiselectInputWidget.prototype.onCheckboxesSelect = function () {\n\tthis.setValue( this.checkboxMultiselectWidget.findSelectedItemsData() );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxMultiselectInputWidget.prototype.getValue = function () {\n\tvar value = this.$element.find( '.oo-ui-checkboxInputWidget .oo-ui-inputWidget-input:checked' )\n\t\t.toArray().map( function ( el ) { return el.value; } );\n\tif ( this.value !== value ) {\n\t\tthis.setValue( value );\n\t}\n\treturn this.value;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxMultiselectInputWidget.prototype.setValue = function ( value ) {\n\tvalue = this.cleanUpValue( value );\n\tthis.checkboxMultiselectWidget.selectItemsByData( value );\n\tOO.ui.CheckboxMultiselectInputWidget.parent.prototype.setValue.call( this, value );\n\tif ( this.optionsDirty ) {\n\t\t// We reached this from the constructor or from #setOptions.\n\t\t// We have to update the <select> element.\n\t\tthis.updateOptionsInterface();\n\t}\n\treturn this;\n};\n\n/**\n * Clean up incoming value.\n *\n * @param {string[]} value Original value\n * @return {string[]} Cleaned up value\n */\nOO.ui.CheckboxMultiselectInputWidget.prototype.cleanUpValue = function ( value ) {\n\tvar i, singleValue,\n\t\tcleanValue = [];\n\tif ( !Array.isArray( value ) ) {\n\t\treturn cleanValue;\n\t}\n\tfor ( i = 0; i < value.length; i++ ) {\n\t\tsingleValue = OO.ui.CheckboxMultiselectInputWidget.parent.prototype.cleanUpValue\n\t\t\t.call( this, value[ i ] );\n\t\t// Remove options that we don't have here\n\t\tif ( !this.checkboxMultiselectWidget.findItemFromData( singleValue ) ) {\n\t\t\tcontinue;\n\t\t}\n\t\tcleanValue.push( singleValue );\n\t}\n\treturn cleanValue;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxMultiselectInputWidget.prototype.setDisabled = function ( state ) {\n\tthis.checkboxMultiselectWidget.setDisabled( state );\n\tOO.ui.CheckboxMultiselectInputWidget.parent.prototype.setDisabled.call( this, state );\n\treturn this;\n};\n\n/**\n * Set the options available for this input.\n *\n * @param {Object[]} options Array of menu options in the format\n *  `{ data: …, label: …, disabled: … }`\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.CheckboxMultiselectInputWidget.prototype.setOptions = function ( options ) {\n\tvar value = this.getValue();\n\n\tthis.setOptionsData( options );\n\n\t// Re-set the value to update the visible interface (CheckboxMultiselectWidget).\n\t// This will also get rid of any stale options that we just removed.\n\tthis.setValue( value );\n\n\treturn this;\n};\n\n/**\n * Set the internal list of options, used e.g. by setValue() to see which options are allowed.\n *\n * This method may be called before the parent constructor, so various properties may not be\n * intialized yet.\n *\n * @param {Object[]} options Array of menu options in the format\n *  `{ data: …, label: … }`\n * @private\n */\nOO.ui.CheckboxMultiselectInputWidget.prototype.setOptionsData = function ( options ) {\n\tvar widget = this;\n\n\tthis.optionsDirty = true;\n\n\tthis.checkboxMultiselectWidget\n\t\t.clearItems()\n\t\t.addItems( options.map( function ( opt ) {\n\t\t\tvar optValue, item, optDisabled;\n\t\t\toptValue = OO.ui.CheckboxMultiselectInputWidget.parent.prototype.cleanUpValue\n\t\t\t\t.call( widget, opt.data );\n\t\t\toptDisabled = opt.disabled !== undefined ? opt.disabled : false;\n\t\t\titem = new OO.ui.CheckboxMultioptionWidget( {\n\t\t\t\tdata: optValue,\n\t\t\t\tlabel: opt.label !== undefined ? opt.label : optValue,\n\t\t\t\tdisabled: optDisabled\n\t\t\t} );\n\t\t\t// Set the 'name' and 'value' for form submission\n\t\t\titem.checkbox.$input.attr( 'name', widget.inputName );\n\t\t\titem.checkbox.setValue( optValue );\n\t\t\treturn item;\n\t\t} ) );\n};\n\n/**\n * Update the user-visible interface to match the internal list of options and value.\n *\n * This method must only be called after the parent constructor.\n *\n * @private\n */\nOO.ui.CheckboxMultiselectInputWidget.prototype.updateOptionsInterface = function () {\n\tvar defaultValue = this.defaultValue;\n\n\tthis.checkboxMultiselectWidget.getItems().forEach( function ( item ) {\n\t\t// Remember original selection state. This property can be later used to check whether\n\t\t// the selection state of the input has been changed since it was created.\n\t\tvar isDefault = defaultValue.indexOf( item.getData() ) !== -1;\n\t\titem.checkbox.defaultSelected = isDefault;\n\t\titem.checkbox.$input[ 0 ].defaultChecked = isDefault;\n\t} );\n\n\tthis.optionsDirty = false;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.CheckboxMultiselectInputWidget.prototype.focus = function () {\n\tthis.checkboxMultiselectWidget.focus();\n\treturn this;\n};\n","/**\n * TextInputWidgets, like HTML text inputs, can be configured with options that customize the\n * size of the field as well as its presentation. In addition, these widgets can be configured\n * with {@link OO.ui.mixin.IconElement icons}, {@link OO.ui.mixin.IndicatorElement indicators}, an\n * optional validation-pattern (used to determine if an input value is valid or not) and an input\n * filter, which modifies incoming values rather than validating them.\n * Please see the [OOUI documentation on MediaWiki] [1] for more information and examples.\n *\n * This widget can be used inside an HTML form, such as a OO.ui.FormLayout.\n *\n *     @example\n *     // A TextInputWidget.\n *     var textInput = new OO.ui.TextInputWidget( {\n *         value: 'Text input'\n *     } );\n *     $( document.body ).append( textInput.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs\n *\n * @class\n * @extends OO.ui.InputWidget\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.IndicatorElement\n * @mixins OO.ui.mixin.PendingElement\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.FlaggedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {string} [type='text'] The value of the HTML `type` attribute: 'text', 'password'\n *  'email', 'url' or 'number'.\n * @cfg {string} [placeholder] Placeholder text\n * @cfg {boolean} [autofocus=false] Use an HTML `autofocus` attribute to\n *  instruct the browser to focus this widget.\n * @cfg {boolean} [readOnly=false] Prevent changes to the value of the text input.\n * @cfg {number} [maxLength] Maximum number of characters allowed in the input.\n *\n *  For unfortunate historical reasons, this counts the number of UTF-16 code units rather than\n *  Unicode codepoints, which means that codepoints outside the Basic Multilingual Plane (e.g.\n *  many emojis) count as 2 characters each.\n * @cfg {string} [labelPosition='after'] The position of the inline label relative to that of\n *  the value or placeholder text: `'before'` or `'after'`\n * @cfg {boolean} [required=false] Mark the field as required with `true`. Implies `indicator:\n *  'required'`. Note that `false` & setting `indicator: 'required' will result in no indicator\n *  shown.\n * @cfg {boolean} [autocomplete=true] Should the browser support autocomplete for this field\n * @cfg {boolean} [spellcheck] Should the browser support spellcheck for this field (`undefined`\n *  means leaving it up to the browser).\n * @cfg {RegExp|Function|string} [validate] Validation pattern: when string, a symbolic name of a\n *  pattern defined by the class: 'non-empty' (the value cannot be an empty string) or 'integer'\n *  (the value must contain only numbers); when RegExp, a regular expression that must match the\n *  value for it to be considered valid; when Function, a function receiving the value as parameter\n *  that must return true, or promise resolving to true, for it to be considered valid.\n */\nOO.ui.TextInputWidget = function OoUiTextInputWidget( config ) {\n\t// Configuration initialization\n\tconfig = $.extend( {\n\t\ttype: 'text',\n\t\tlabelPosition: 'after'\n\t}, config );\n\n\t// Parent constructor\n\tOO.ui.TextInputWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.IndicatorElement.call( this, config );\n\tOO.ui.mixin.PendingElement.call( this, $.extend( { $pending: this.$input }, config ) );\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.FlaggedElement.call( this, config );\n\n\t// Properties\n\tthis.type = this.getSaneType( config );\n\tthis.readOnly = false;\n\tthis.required = false;\n\tthis.validate = null;\n\tthis.scrollWidth = null;\n\n\tthis.setValidation( config.validate );\n\tthis.setLabelPosition( config.labelPosition );\n\n\t// Events\n\tthis.$input.on( {\n\t\tkeypress: this.onKeyPress.bind( this ),\n\t\tblur: this.onBlur.bind( this ),\n\t\tfocus: this.onFocus.bind( this )\n\t} );\n\tthis.$icon.on( 'mousedown', this.onIconMouseDown.bind( this ) );\n\tthis.$indicator.on( 'mousedown', this.onIndicatorMouseDown.bind( this ) );\n\tthis.on( 'labelChange', this.updatePosition.bind( this ) );\n\tthis.on( 'change', OO.ui.debounce( this.onDebouncedChange.bind( this ), 250 ) );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-textInputWidget oo-ui-textInputWidget-type-' + this.type )\n\t\t.append( this.$icon, this.$indicator );\n\tthis.setReadOnly( !!config.readOnly );\n\tthis.setRequired( !!config.required );\n\tif ( config.placeholder !== undefined ) {\n\t\tthis.$input.attr( 'placeholder', config.placeholder );\n\t}\n\tif ( config.maxLength !== undefined ) {\n\t\tthis.$input.attr( 'maxlength', config.maxLength );\n\t}\n\tif ( config.autofocus ) {\n\t\tthis.$input.attr( 'autofocus', 'autofocus' );\n\t}\n\tif ( config.autocomplete === false ) {\n\t\tthis.$input.attr( 'autocomplete', 'off' );\n\t\t// Turning off autocompletion also disables \"form caching\" when the user navigates to a\n\t\t// different page and then clicks \"Back\". Re-enable it when leaving.\n\t\t// Borrowed from jQuery UI.\n\t\t$( window ).on( {\n\t\t\tbeforeunload: function () {\n\t\t\t\tthis.$input.removeAttr( 'autocomplete' );\n\t\t\t}.bind( this ),\n\t\t\tpageshow: function () {\n\t\t\t\t// Browsers don't seem to actually fire this event on \"Back\", they instead just\n\t\t\t\t// reload the whole page... it shouldn't hurt, though.\n\t\t\t\tthis.$input.attr( 'autocomplete', 'off' );\n\t\t\t}.bind( this )\n\t\t} );\n\t}\n\tif ( config.spellcheck !== undefined ) {\n\t\tthis.$input.attr( 'spellcheck', config.spellcheck ? 'true' : 'false' );\n\t}\n\tif ( this.label ) {\n\t\tthis.isWaitingToBeAttached = true;\n\t\tthis.installParentChangeDetector();\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.TextInputWidget, OO.ui.InputWidget );\nOO.mixinClass( OO.ui.TextInputWidget, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.TextInputWidget, OO.ui.mixin.IndicatorElement );\nOO.mixinClass( OO.ui.TextInputWidget, OO.ui.mixin.PendingElement );\nOO.mixinClass( OO.ui.TextInputWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.TextInputWidget, OO.ui.mixin.FlaggedElement );\n\n/* Static Properties */\n\nOO.ui.TextInputWidget.static.validationPatterns = {\n\t'non-empty': /.+/,\n\tinteger: /^\\d+$/\n};\n\n/* Events */\n\n/**\n * An `enter` event is emitted when the user presses Enter key inside the text box.\n *\n * @event enter\n */\n\n/* Methods */\n\n/**\n * Handle icon mouse down events.\n *\n * @private\n * @param {jQuery.Event} e Mouse down event\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.TextInputWidget.prototype.onIconMouseDown = function ( e ) {\n\tif ( e.which === OO.ui.MouseButtons.LEFT ) {\n\t\tthis.focus();\n\t\treturn false;\n\t}\n};\n\n/**\n * Handle indicator mouse down events.\n *\n * @private\n * @param {jQuery.Event} e Mouse down event\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.TextInputWidget.prototype.onIndicatorMouseDown = function ( e ) {\n\tif ( e.which === OO.ui.MouseButtons.LEFT ) {\n\t\tthis.focus();\n\t\treturn false;\n\t}\n};\n\n/**\n * Handle key press events.\n *\n * @private\n * @param {jQuery.Event} e Key press event\n * @fires enter If Enter key is pressed\n */\nOO.ui.TextInputWidget.prototype.onKeyPress = function ( e ) {\n\tif ( e.which === OO.ui.Keys.ENTER ) {\n\t\tthis.emit( 'enter', e );\n\t}\n};\n\n/**\n * Handle blur events.\n *\n * @private\n * @param {jQuery.Event} e Blur event\n */\nOO.ui.TextInputWidget.prototype.onBlur = function () {\n\tthis.setValidityFlag();\n};\n\n/**\n * Handle focus events.\n *\n * @private\n * @param {jQuery.Event} e Focus event\n */\nOO.ui.TextInputWidget.prototype.onFocus = function () {\n\tif ( this.isWaitingToBeAttached ) {\n\t\t// If we've received focus, then we must be attached to the document, and if\n\t\t// isWaitingToBeAttached is still true, that means the handler never fired. Fire it now.\n\t\tthis.onElementAttach();\n\t}\n\tthis.setValidityFlag( true );\n};\n\n/**\n * Handle element attach events.\n *\n * @private\n * @param {jQuery.Event} e Element attach event\n */\nOO.ui.TextInputWidget.prototype.onElementAttach = function () {\n\tthis.isWaitingToBeAttached = false;\n\t// Any previously calculated size is now probably invalid if we reattached elsewhere\n\tthis.valCache = null;\n\tthis.positionLabel();\n};\n\n/**\n * Handle debounced change events.\n *\n * @param {string} value\n * @private\n */\nOO.ui.TextInputWidget.prototype.onDebouncedChange = function () {\n\tthis.setValidityFlag();\n};\n\n/**\n * Check if the input is {@link #readOnly read-only}.\n *\n * @return {boolean}\n */\nOO.ui.TextInputWidget.prototype.isReadOnly = function () {\n\treturn this.readOnly;\n};\n\n/**\n * Set the {@link #readOnly read-only} state of the input.\n *\n * @param {boolean} state Make input read-only\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TextInputWidget.prototype.setReadOnly = function ( state ) {\n\tthis.readOnly = !!state;\n\tthis.$input.prop( 'readOnly', this.readOnly );\n\treturn this;\n};\n\n/**\n * Check if the input is {@link #required required}.\n *\n * @return {boolean}\n */\nOO.ui.TextInputWidget.prototype.isRequired = function () {\n\treturn this.required;\n};\n\n/**\n * Set the {@link #required required} state of the input.\n *\n * @param {boolean} state Make input required\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TextInputWidget.prototype.setRequired = function ( state ) {\n\tthis.required = !!state;\n\tif ( this.required ) {\n\t\tthis.$input\n\t\t\t.prop( 'required', true )\n\t\t\t.attr( 'aria-required', 'true' );\n\t\tif ( this.getIndicator() === null ) {\n\t\t\tthis.setIndicator( 'required' );\n\t\t}\n\t} else {\n\t\tthis.$input\n\t\t\t.prop( 'required', false )\n\t\t\t.removeAttr( 'aria-required' );\n\t\tif ( this.getIndicator() === 'required' ) {\n\t\t\tthis.setIndicator( null );\n\t\t}\n\t}\n\treturn this;\n};\n\n/**\n * Support function for making #onElementAttach work across browsers.\n *\n * This whole function could be replaced with one line of code using the DOMNodeInsertedIntoDocument\n * event, but it's not supported by Firefox and allegedly deprecated, so we only use it as fallback.\n *\n * Due to MutationObserver performance woes, #onElementAttach is only somewhat reliably called the\n * first time that the element gets attached to the documented.\n */\nOO.ui.TextInputWidget.prototype.installParentChangeDetector = function () {\n\tvar mutationObserver, onRemove, topmostNode, fakeParentNode,\n\t\tMutationObserver = window.MutationObserver ||\n\t\t\twindow.WebKitMutationObserver ||\n\t\t\twindow.MozMutationObserver,\n\t\twidget = this;\n\n\tif ( MutationObserver ) {\n\t\t// The new way. If only it wasn't so ugly.\n\n\t\tif ( this.isElementAttached() ) {\n\t\t\t// Widget is attached already, do nothing. This breaks the functionality of this\n\t\t\t// function when the widget is detached and reattached. Alas, doing this correctly with\n\t\t\t// MutationObserver would require observation of the whole document, which would hurt\n\t\t\t// performance of other, more important code.\n\t\t\treturn;\n\t\t}\n\n\t\t// Find topmost node in the tree\n\t\ttopmostNode = this.$element[ 0 ];\n\t\twhile ( topmostNode.parentNode ) {\n\t\t\ttopmostNode = topmostNode.parentNode;\n\t\t}\n\n\t\t// We have no way to detect the $element being attached somewhere without observing the\n\t\t// entire DOM with subtree modifications, which would hurt performance. So we cheat: we hook\n\t\t// to the parent node of $element, and instead detect when $element is removed from it (and\n\t\t// thus probably attached somewhere else). If there is no parent, we create a \"fake\" one. If\n\t\t// it doesn't get attached, we end up back here and create the parent.\n\t\tmutationObserver = new MutationObserver( function ( mutations ) {\n\t\t\tvar i, j, removedNodes;\n\t\t\tfor ( i = 0; i < mutations.length; i++ ) {\n\t\t\t\tremovedNodes = mutations[ i ].removedNodes;\n\t\t\t\tfor ( j = 0; j < removedNodes.length; j++ ) {\n\t\t\t\t\tif ( removedNodes[ j ] === topmostNode ) {\n\t\t\t\t\t\tsetTimeout( onRemove, 0 );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\tonRemove = function () {\n\t\t\t// If the node was attached somewhere else, report it\n\t\t\tif ( widget.isElementAttached() ) {\n\t\t\t\twidget.onElementAttach();\n\t\t\t}\n\t\t\tmutationObserver.disconnect();\n\t\t\twidget.installParentChangeDetector();\n\t\t};\n\n\t\t// Create a fake parent and observe it\n\t\tfakeParentNode = $( '<div>' ).append( topmostNode )[ 0 ];\n\t\tmutationObserver.observe( fakeParentNode, { childList: true } );\n\t} else {\n\t\t// Using the DOMNodeInsertedIntoDocument event is much nicer and less magical, and works for\n\t\t// detachment and reattachment, but it's not supported by Firefox and allegedly deprecated.\n\t\tthis.$element.on( 'DOMNodeInsertedIntoDocument', this.onElementAttach.bind( this ) );\n\t}\n};\n\n/**\n * @inheritdoc\n * @protected\n */\nOO.ui.TextInputWidget.prototype.getInputElement = function ( config ) {\n\tif ( this.getSaneType( config ) === 'number' ) {\n\t\treturn $( '<input>' )\n\t\t\t.attr( 'step', 'any' )\n\t\t\t.attr( 'type', 'number' );\n\t} else {\n\t\treturn $( '<input>' ).attr( 'type', this.getSaneType( config ) );\n\t}\n};\n\n/**\n * Get sanitized value for 'type' for given config.\n *\n * @param {Object} config Configuration options\n * @return {string|null}\n * @protected\n */\nOO.ui.TextInputWidget.prototype.getSaneType = function ( config ) {\n\tvar allowedTypes = [\n\t\t'text',\n\t\t'password',\n\t\t'email',\n\t\t'url',\n\t\t'number'\n\t];\n\treturn allowedTypes.indexOf( config.type ) !== -1 ? config.type : 'text';\n};\n\n/**\n * Focus the input and select a specified range within the text.\n *\n * @param {number} from Select from offset\n * @param {number} [to] Select to offset, defaults to from\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TextInputWidget.prototype.selectRange = function ( from, to ) {\n\tvar isBackwards, start, end,\n\t\tinput = this.$input[ 0 ];\n\n\tto = to || from;\n\n\tisBackwards = to < from;\n\tstart = isBackwards ? to : from;\n\tend = isBackwards ? from : to;\n\n\tthis.focus();\n\n\ttry {\n\t\tinput.setSelectionRange( start, end, isBackwards ? 'backward' : 'forward' );\n\t} catch ( e ) {\n\t\t// IE throws an exception if you call setSelectionRange on a unattached DOM node.\n\t\t// Rather than expensively check if the input is attached every time, just check\n\t\t// if it was the cause of an error being thrown. If not, rethrow the error.\n\t\tif ( this.getElementDocument().body.contains( input ) ) {\n\t\t\tthrow e;\n\t\t}\n\t}\n\treturn this;\n};\n\n/**\n * Get an object describing the current selection range in a directional manner\n *\n * @return {Object} Object containing 'from' and 'to' offsets\n */\nOO.ui.TextInputWidget.prototype.getRange = function () {\n\tvar input = this.$input[ 0 ],\n\t\tstart = input.selectionStart,\n\t\tend = input.selectionEnd,\n\t\tisBackwards = input.selectionDirection === 'backward';\n\n\treturn {\n\t\tfrom: isBackwards ? end : start,\n\t\tto: isBackwards ? start : end\n\t};\n};\n\n/**\n * Get the length of the text input value.\n *\n * This could differ from the length of #getValue if the\n * value gets filtered\n *\n * @return {number} Input length\n */\nOO.ui.TextInputWidget.prototype.getInputLength = function () {\n\treturn this.$input[ 0 ].value.length;\n};\n\n/**\n * Focus the input and select the entire text.\n *\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TextInputWidget.prototype.select = function () {\n\treturn this.selectRange( 0, this.getInputLength() );\n};\n\n/**\n * Focus the input and move the cursor to the start.\n *\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TextInputWidget.prototype.moveCursorToStart = function () {\n\treturn this.selectRange( 0 );\n};\n\n/**\n * Focus the input and move the cursor to the end.\n *\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TextInputWidget.prototype.moveCursorToEnd = function () {\n\treturn this.selectRange( this.getInputLength() );\n};\n\n/**\n * Insert new content into the input.\n *\n * @param {string} content Content to be inserted\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TextInputWidget.prototype.insertContent = function ( content ) {\n\tvar start, end,\n\t\trange = this.getRange(),\n\t\tvalue = this.getValue();\n\n\tstart = Math.min( range.from, range.to );\n\tend = Math.max( range.from, range.to );\n\n\tthis.setValue( value.slice( 0, start ) + content + value.slice( end ) );\n\tthis.selectRange( start + content.length );\n\treturn this;\n};\n\n/**\n * Insert new content either side of a selection.\n *\n * @param {string} pre Content to be inserted before the selection\n * @param {string} post Content to be inserted after the selection\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TextInputWidget.prototype.encapsulateContent = function ( pre, post ) {\n\tvar start, end,\n\t\trange = this.getRange(),\n\t\toffset = pre.length;\n\n\tstart = Math.min( range.from, range.to );\n\tend = Math.max( range.from, range.to );\n\n\tthis.selectRange( start ).insertContent( pre );\n\tthis.selectRange( offset + end ).insertContent( post );\n\n\tthis.selectRange( offset + start, offset + end );\n\treturn this;\n};\n\n/**\n * Set the validation pattern.\n *\n * The validation pattern is either a regular expression, a function, or the symbolic name of a\n * pattern defined by the class: 'non-empty' (the value cannot be an empty string) or 'integer' (the\n * value must contain only numbers).\n *\n * @param {RegExp|Function|string|null} validate Regular expression, function, or the symbolic name\n *  of a pattern (either ‘integer’ or ‘non-empty’) defined by the class.\n */\nOO.ui.TextInputWidget.prototype.setValidation = function ( validate ) {\n\tif ( validate instanceof RegExp || validate instanceof Function ) {\n\t\tthis.validate = validate;\n\t} else {\n\t\tthis.validate = this.constructor.static.validationPatterns[ validate ] || /.*/;\n\t}\n};\n\n/**\n * Sets the 'invalid' flag appropriately.\n *\n * @param {boolean} [isValid] Optionally override validation result\n */\nOO.ui.TextInputWidget.prototype.setValidityFlag = function ( isValid ) {\n\tvar widget = this,\n\t\tsetFlag = function ( valid ) {\n\t\t\tif ( !valid ) {\n\t\t\t\twidget.$input.attr( 'aria-invalid', 'true' );\n\t\t\t} else {\n\t\t\t\twidget.$input.removeAttr( 'aria-invalid' );\n\t\t\t}\n\t\t\twidget.setFlags( { invalid: !valid } );\n\t\t};\n\n\tif ( isValid !== undefined ) {\n\t\tsetFlag( isValid );\n\t} else {\n\t\tthis.getValidity().then( function () {\n\t\t\tsetFlag( true );\n\t\t}, function () {\n\t\t\tsetFlag( false );\n\t\t} );\n\t}\n};\n\n/**\n * Get the validity of current value.\n *\n * This method returns a promise that resolves if the value is valid and rejects if\n * it isn't. Uses the {@link #validate validation pattern}  to check for validity.\n *\n * @return {jQuery.Promise} A promise that resolves if the value is valid, rejects if not.\n */\nOO.ui.TextInputWidget.prototype.getValidity = function () {\n\tvar result;\n\n\tfunction rejectOrResolve( valid ) {\n\t\tif ( valid ) {\n\t\t\treturn $.Deferred().resolve().promise();\n\t\t} else {\n\t\t\treturn $.Deferred().reject().promise();\n\t\t}\n\t}\n\n\t// Check browser validity and reject if it is invalid\n\tif (\n\t\tthis.$input[ 0 ].checkValidity !== undefined &&\n\t\tthis.$input[ 0 ].checkValidity() === false\n\t) {\n\t\treturn rejectOrResolve( false );\n\t}\n\n\t// Run our checks if the browser thinks the field is valid\n\tif ( this.validate instanceof Function ) {\n\t\tresult = this.validate( this.getValue() );\n\t\tif ( result && typeof result.promise === 'function' ) {\n\t\t\treturn result.promise().then( function ( valid ) {\n\t\t\t\treturn rejectOrResolve( valid );\n\t\t\t} );\n\t\t} else {\n\t\t\treturn rejectOrResolve( result );\n\t\t}\n\t} else {\n\t\treturn rejectOrResolve( this.getValue().match( this.validate ) );\n\t}\n};\n\n/**\n * Set the position of the inline label relative to that of the value: `‘before’` or `‘after’`.\n *\n * @param {string} labelPosition Label position, 'before' or 'after'\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TextInputWidget.prototype.setLabelPosition = function ( labelPosition ) {\n\tthis.labelPosition = labelPosition;\n\tif ( this.label ) {\n\t\t// If there is no label and we only change the position, #updatePosition is a no-op,\n\t\t// but it takes really a lot of work to do nothing.\n\t\tthis.updatePosition();\n\t}\n\treturn this;\n};\n\n/**\n * Update the position of the inline label.\n *\n * This method is called by #setLabelPosition, and can also be called on its own if\n * something causes the label to be mispositioned.\n *\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TextInputWidget.prototype.updatePosition = function () {\n\tvar after = this.labelPosition === 'after';\n\n\tthis.$element\n\t\t.toggleClass( 'oo-ui-textInputWidget-labelPosition-after', !!this.label && after )\n\t\t.toggleClass( 'oo-ui-textInputWidget-labelPosition-before', !!this.label && !after );\n\n\tthis.valCache = null;\n\tthis.scrollWidth = null;\n\tthis.positionLabel();\n\n\treturn this;\n};\n\n/**\n * Position the label by setting the correct padding on the input.\n *\n * @private\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TextInputWidget.prototype.positionLabel = function () {\n\tvar after, rtl, property, newCss;\n\n\tif ( this.isWaitingToBeAttached ) {\n\t\t// #onElementAttach will be called soon, which calls this method\n\t\treturn this;\n\t}\n\n\tnewCss = {\n\t\t'padding-right': '',\n\t\t'padding-left': ''\n\t};\n\n\tif ( this.label ) {\n\t\tthis.$element.append( this.$label );\n\t} else {\n\t\tthis.$label.detach();\n\t\t// Clear old values if present\n\t\tthis.$input.css( newCss );\n\t\treturn;\n\t}\n\n\tafter = this.labelPosition === 'after';\n\trtl = this.$element.css( 'direction' ) === 'rtl';\n\tproperty = after === rtl ? 'padding-left' : 'padding-right';\n\n\tnewCss[ property ] = this.$label.outerWidth( true ) + ( after ? this.scrollWidth : 0 );\n\t// We have to clear the padding on the other side, in case the element direction changed\n\tthis.$input.css( newCss );\n\n\treturn this;\n};\n","/**\n * SearchInputWidgets are TextInputWidgets with `type=\"search\"` assigned and feature a\n * {@link OO.ui.mixin.IconElement search icon} by default.\n * Please see the [OOUI documentation on MediaWiki] [1] for more information and examples.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs#SearchInputWidget\n *\n * @class\n * @extends OO.ui.TextInputWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.SearchInputWidget = function OoUiSearchInputWidget( config ) {\n\tconfig = $.extend( {\n\t\ticon: 'search'\n\t}, config );\n\n\t// Parent constructor\n\tOO.ui.SearchInputWidget.parent.call( this, config );\n\n\t// Events\n\tthis.connect( this, {\n\t\tchange: 'onChange'\n\t} );\n\tthis.$indicator.on( 'click', this.onIndicatorClick.bind( this ) );\n\n\t// Initialization\n\tthis.updateSearchIndicator();\n\tthis.connect( this, {\n\t\tdisable: 'onDisable'\n\t} );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.SearchInputWidget, OO.ui.TextInputWidget );\n\n/* Methods */\n\n/**\n * @inheritdoc\n * @protected\n */\nOO.ui.SearchInputWidget.prototype.getSaneType = function () {\n\treturn 'search';\n};\n\n/**\n * Handle click events on the indicator\n *\n * @param {jQuery.Event} e Click event\n * @return {boolean}\n */\nOO.ui.SearchInputWidget.prototype.onIndicatorClick = function ( e ) {\n\tif ( e.which === OO.ui.MouseButtons.LEFT ) {\n\t\t// Clear the text field\n\t\tthis.setValue( '' );\n\t\tthis.focus();\n\t\treturn false;\n\t}\n};\n\n/**\n * Update the 'clear' indicator displayed on type: 'search' text\n * fields, hiding it when the field is already empty or when it's not\n * editable.\n */\nOO.ui.SearchInputWidget.prototype.updateSearchIndicator = function () {\n\tif ( this.getValue() === '' || this.isDisabled() || this.isReadOnly() ) {\n\t\tthis.setIndicator( null );\n\t} else {\n\t\tthis.setIndicator( 'clear' );\n\t}\n};\n\n/**\n * Handle change events.\n *\n * @private\n */\nOO.ui.SearchInputWidget.prototype.onChange = function () {\n\tthis.updateSearchIndicator();\n};\n\n/**\n * Handle disable events.\n *\n * @param {boolean} disabled Element is disabled\n * @private\n */\nOO.ui.SearchInputWidget.prototype.onDisable = function () {\n\tthis.updateSearchIndicator();\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.SearchInputWidget.prototype.setReadOnly = function ( state ) {\n\tOO.ui.SearchInputWidget.parent.prototype.setReadOnly.call( this, state );\n\tthis.updateSearchIndicator();\n\treturn this;\n};\n","/**\n * MultilineTextInputWidgets, like HTML textareas, are featuring customization options to\n * configure number of rows visible. In addition, these widgets can be autosized to fit user\n * inputs and can show {@link OO.ui.mixin.IconElement icons} and\n * {@link OO.ui.mixin.IndicatorElement indicators}.\n * Please see the [OOUI documentation on MediaWiki] [1] for more information and examples.\n *\n * This widget can be used inside an HTML form, such as a OO.ui.FormLayout.\n *\n *     @example\n *     // A MultilineTextInputWidget.\n *     var multilineTextInput = new OO.ui.MultilineTextInputWidget( {\n *         value: 'Text input on multiple lines'\n *     } );\n *     $( document.body ).append( multilineTextInput.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs#MultilineTextInputWidget\n *\n * @class\n * @extends OO.ui.TextInputWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {number} [rows] Number of visible lines in textarea. If used with `autosize`,\n *  specifies minimum number of rows to display.\n * @cfg {boolean} [autosize=false] Automatically resize the text input to fit its content.\n *  Use the #maxRows config to specify a maximum number of displayed rows.\n * @cfg {number} [maxRows] Maximum number of rows to display when #autosize is set to true.\n *  Defaults to the maximum of `10` and `2 * rows`, or `10` if `rows` isn't provided.\n */\nOO.ui.MultilineTextInputWidget = function OoUiMultilineTextInputWidget( config ) {\n\tconfig = $.extend( {\n\t\ttype: 'text'\n\t}, config );\n\t// Parent constructor\n\tOO.ui.MultilineTextInputWidget.parent.call( this, config );\n\n\t// Properties\n\tthis.autosize = !!config.autosize;\n\tthis.styleHeight = null;\n\tthis.minRows = config.rows !== undefined ? config.rows : '';\n\tthis.maxRows = config.maxRows || Math.max( 2 * ( this.minRows || 0 ), 10 );\n\n\t// Clone for resizing\n\tif ( this.autosize ) {\n\t\tthis.$clone = this.$input\n\t\t\t.clone()\n\t\t\t.removeAttr( 'id' )\n\t\t\t.removeAttr( 'name' )\n\t\t\t.insertAfter( this.$input )\n\t\t\t.attr( 'aria-hidden', 'true' )\n\t\t\t.addClass( 'oo-ui-element-hidden' );\n\t}\n\n\t// Events\n\tthis.connect( this, {\n\t\tchange: 'onChange'\n\t} );\n\n\t// Initialization\n\tif ( config.rows ) {\n\t\tthis.$input.attr( 'rows', config.rows );\n\t}\n\tif ( this.autosize ) {\n\t\tthis.$input.addClass( 'oo-ui-textInputWidget-autosized' );\n\t\tthis.isWaitingToBeAttached = true;\n\t\tthis.installParentChangeDetector();\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.MultilineTextInputWidget, OO.ui.TextInputWidget );\n\n/* Static Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.MultilineTextInputWidget.static.gatherPreInfuseState = function ( node, config ) {\n\tvar state = OO.ui.MultilineTextInputWidget.parent.static.gatherPreInfuseState( node, config );\n\tstate.scrollTop = config.$input.scrollTop();\n\treturn state;\n};\n\n/* Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.MultilineTextInputWidget.prototype.onElementAttach = function () {\n\tOO.ui.MultilineTextInputWidget.parent.prototype.onElementAttach.call( this );\n\tthis.adjustSize();\n};\n\n/**\n * Handle change events.\n *\n * @private\n */\nOO.ui.MultilineTextInputWidget.prototype.onChange = function () {\n\tthis.adjustSize();\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MultilineTextInputWidget.prototype.updatePosition = function () {\n\tOO.ui.MultilineTextInputWidget.parent.prototype.updatePosition.call( this );\n\tthis.adjustSize();\n};\n\n/**\n * @inheritdoc\n *\n * Modify to emit 'enter' on Ctrl/Meta+Enter, instead of plain Enter\n */\nOO.ui.MultilineTextInputWidget.prototype.onKeyPress = function ( e ) {\n\tif (\n\t\t( e.which === OO.ui.Keys.ENTER && ( e.ctrlKey || e.metaKey ) ) ||\n\t\t// Some platforms emit keycode 10 for Control+Enter keypress in a textarea\n\t\te.which === 10\n\t) {\n\t\tthis.emit( 'enter', e );\n\t}\n};\n\n/**\n * Automatically adjust the size of the text input.\n *\n * This only affects multiline inputs that are {@link #autosize autosized}.\n *\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n * @fires resize\n */\nOO.ui.MultilineTextInputWidget.prototype.adjustSize = function () {\n\tvar scrollHeight, innerHeight, outerHeight, maxInnerHeight, measurementError,\n\t\tidealHeight, newHeight, scrollWidth, property;\n\n\tif ( this.$input.val() !== this.valCache ) {\n\t\tif ( this.autosize ) {\n\t\t\tthis.$clone\n\t\t\t\t.val( this.$input.val() )\n\t\t\t\t.attr( 'rows', this.minRows )\n\t\t\t\t// Set inline height property to 0 to measure scroll height\n\t\t\t\t.css( 'height', 0 );\n\n\t\t\tthis.$clone.removeClass( 'oo-ui-element-hidden' );\n\n\t\t\tthis.valCache = this.$input.val();\n\n\t\t\tscrollHeight = this.$clone[ 0 ].scrollHeight;\n\n\t\t\t// Remove inline height property to measure natural heights\n\t\t\tthis.$clone.css( 'height', '' );\n\t\t\tinnerHeight = this.$clone.innerHeight();\n\t\t\touterHeight = this.$clone.outerHeight();\n\n\t\t\t// Measure max rows height\n\t\t\tthis.$clone\n\t\t\t\t.attr( 'rows', this.maxRows )\n\t\t\t\t.css( 'height', 'auto' )\n\t\t\t\t.val( '' );\n\t\t\tmaxInnerHeight = this.$clone.innerHeight();\n\n\t\t\t// Difference between reported innerHeight and scrollHeight with no scrollbars present.\n\t\t\t// This is sometimes non-zero on Blink-based browsers, depending on zoom level.\n\t\t\tmeasurementError = maxInnerHeight - this.$clone[ 0 ].scrollHeight;\n\t\t\tidealHeight = Math.min( maxInnerHeight, scrollHeight + measurementError );\n\n\t\t\tthis.$clone.addClass( 'oo-ui-element-hidden' );\n\n\t\t\t// Only apply inline height when expansion beyond natural height is needed\n\t\t\t// Use the difference between the inner and outer height as a buffer\n\t\t\tnewHeight = idealHeight > innerHeight ? idealHeight + ( outerHeight - innerHeight ) : '';\n\t\t\tif ( newHeight !== this.styleHeight ) {\n\t\t\t\tthis.$input.css( 'height', newHeight );\n\t\t\t\tthis.styleHeight = newHeight;\n\t\t\t\tthis.emit( 'resize' );\n\t\t\t}\n\t\t}\n\t\tscrollWidth = this.$input[ 0 ].offsetWidth - this.$input[ 0 ].clientWidth;\n\t\tif ( scrollWidth !== this.scrollWidth ) {\n\t\t\tproperty = this.$element.css( 'direction' ) === 'rtl' ? 'left' : 'right';\n\t\t\t// Reset\n\t\t\tthis.$label.css( { right: '', left: '' } );\n\t\t\tthis.$indicator.css( { right: '', left: '' } );\n\n\t\t\tif ( scrollWidth ) {\n\t\t\t\tthis.$indicator.css( property, scrollWidth );\n\t\t\t\tif ( this.labelPosition === 'after' ) {\n\t\t\t\t\tthis.$label.css( property, scrollWidth );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.scrollWidth = scrollWidth;\n\t\t\tthis.positionLabel();\n\t\t}\n\t}\n\treturn this;\n};\n\n/**\n * @inheritdoc\n * @protected\n */\nOO.ui.MultilineTextInputWidget.prototype.getInputElement = function () {\n\treturn $( '<textarea>' );\n};\n\n/**\n * Check if the input automatically adjusts its size.\n *\n * @return {boolean}\n */\nOO.ui.MultilineTextInputWidget.prototype.isAutosizing = function () {\n\treturn !!this.autosize;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MultilineTextInputWidget.prototype.restorePreInfuseState = function ( state ) {\n\tOO.ui.MultilineTextInputWidget.parent.prototype.restorePreInfuseState.call( this, state );\n\tif ( state.scrollTop !== undefined ) {\n\t\tthis.$input.scrollTop( state.scrollTop );\n\t}\n};\n","/**\n * ComboBoxInputWidgets combine a {@link OO.ui.TextInputWidget text input} (where a value\n * can be entered manually) and a {@link OO.ui.MenuSelectWidget menu of options} (from which\n * a value can be chosen instead). Users can choose options from the combo box in one of two ways:\n *\n * - by typing a value in the text input field. If the value exactly matches the value of a menu\n *   option, that option will appear to be selected.\n * - by choosing a value from the menu. The value of the chosen option will then appear in the text\n *   input field.\n *\n * After the user chooses an option, its `data` will be used as a new value for the widget.\n * A `label` also can be specified for each option: if given, it will be shown instead of the\n * `data` in the dropdown menu.\n *\n * This widget can be used inside an HTML form, such as a OO.ui.FormLayout.\n *\n * For more information about menus and options, please see the\n * [OOUI documentation on MediaWiki][1].\n *\n *     @example\n *     // A ComboBoxInputWidget.\n *     var comboBox = new OO.ui.ComboBoxInputWidget( {\n *         value: 'Option 1',\n *         options: [\n *             { data: 'Option 1' },\n *             { data: 'Option 2' },\n *             { data: 'Option 3' }\n *         ]\n *     } );\n *     $( document.body ).append( comboBox.$element );\n *\n *     @example\n *     // Example: A ComboBoxInputWidget with additional option labels.\n *     var comboBox = new OO.ui.ComboBoxInputWidget( {\n *         value: 'Option 1',\n *         options: [\n *             {\n *                 data: 'Option 1',\n *                 label: 'Option One'\n *             },\n *             {\n *                 data: 'Option 2',\n *                 label: 'Option Two'\n *             },\n *             {\n *                 data: 'Option 3',\n *                 label: 'Option Three'\n *             }\n *         ]\n *     } );\n *     $( document.body ).append( comboBox.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options#Menu_selects_and_options\n *\n * @class\n * @extends OO.ui.TextInputWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {Object[]} [options=[]] Array of menu options in the format `{ data: …, label: … }`\n * @cfg {Object} [menu] Configuration options to pass to the {@link OO.ui.MenuSelectWidget menu\n *  select widget}.\n * @cfg {jQuery} [$overlay] Render the menu into a separate layer. This configuration is useful\n *  in cases where the expanded menu is larger than its containing `<div>`. The specified overlay\n *  layer is usually on top of the containing `<div>` and has a larger area. By default, the menu\n *  uses relative positioning.\n *  See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.\n */\nOO.ui.ComboBoxInputWidget = function OoUiComboBoxInputWidget( config ) {\n\t// Configuration initialization\n\tconfig = $.extend( {\n\t\tautocomplete: false\n\t}, config );\n\n\t// ComboBoxInputWidget shouldn't support `multiline`\n\tconfig.multiline = false;\n\n\t// See InputWidget#reusePreInfuseDOM about `config.$input`\n\tif ( config.$input ) {\n\t\tconfig.$input.removeAttr( 'list' );\n\t}\n\n\t// Parent constructor\n\tOO.ui.ComboBoxInputWidget.parent.call( this, config );\n\n\t// Properties\n\tthis.$overlay = ( config.$overlay === true ?\n\t\tOO.ui.getDefaultOverlay() : config.$overlay ) || this.$element;\n\tthis.dropdownButton = new OO.ui.ButtonWidget( {\n\t\tclasses: [ 'oo-ui-comboBoxInputWidget-dropdownButton' ],\n\t\tlabel: OO.ui.msg( 'ooui-combobox-button-label' ),\n\t\tindicator: 'down',\n\t\tinvisibleLabel: true,\n\t\tdisabled: this.disabled\n\t} );\n\tthis.menu = new OO.ui.MenuSelectWidget( $.extend(\n\t\t{\n\t\t\twidget: this,\n\t\t\tinput: this,\n\t\t\t$floatableContainer: this.$element,\n\t\t\tdisabled: this.isDisabled()\n\t\t},\n\t\tconfig.menu\n\t) );\n\n\t// Events\n\tthis.connect( this, {\n\t\tchange: 'onInputChange',\n\t\tenter: 'onInputEnter'\n\t} );\n\tthis.dropdownButton.connect( this, {\n\t\tclick: 'onDropdownButtonClick'\n\t} );\n\tthis.menu.connect( this, {\n\t\tchoose: 'onMenuChoose',\n\t\tadd: 'onMenuItemsChange',\n\t\tremove: 'onMenuItemsChange',\n\t\ttoggle: 'onMenuToggle'\n\t} );\n\n\t// Initialization\n\tthis.$input.attr( {\n\t\trole: 'combobox',\n\t\t'aria-owns': this.menu.getElementId(),\n\t\t'aria-autocomplete': 'list'\n\t} );\n\tthis.dropdownButton.$button.attr( {\n\t\t'aria-controls': this.menu.getElementId()\n\t} );\n\t// Do not override options set via config.menu.items\n\tif ( config.options !== undefined ) {\n\t\tthis.setOptions( config.options );\n\t}\n\tthis.$field = $( '<div>' )\n\t\t.addClass( 'oo-ui-comboBoxInputWidget-field' )\n\t\t.append( this.$input, this.dropdownButton.$element );\n\tthis.$element\n\t\t.addClass( 'oo-ui-comboBoxInputWidget' )\n\t\t.append( this.$field );\n\tthis.$overlay.append( this.menu.$element );\n\tthis.onMenuItemsChange();\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ComboBoxInputWidget, OO.ui.TextInputWidget );\n\n/* Methods */\n\n/**\n * Get the combobox's menu.\n *\n * @return {OO.ui.MenuSelectWidget} Menu widget\n */\nOO.ui.ComboBoxInputWidget.prototype.getMenu = function () {\n\treturn this.menu;\n};\n\n/**\n * Get the combobox's text input widget.\n *\n * @return {OO.ui.TextInputWidget} Text input widget\n */\nOO.ui.ComboBoxInputWidget.prototype.getInput = function () {\n\treturn this;\n};\n\n/**\n * Handle input change events.\n *\n * @private\n * @param {string} value New value\n */\nOO.ui.ComboBoxInputWidget.prototype.onInputChange = function ( value ) {\n\tvar match = this.menu.findItemFromData( value );\n\n\tthis.menu.selectItem( match );\n\tif ( this.menu.findHighlightedItem() ) {\n\t\tthis.menu.highlightItem( match );\n\t}\n\n\tif ( !this.isDisabled() ) {\n\t\tthis.menu.toggle( true );\n\t}\n};\n\n/**\n * Handle input enter events.\n *\n * @private\n */\nOO.ui.ComboBoxInputWidget.prototype.onInputEnter = function () {\n\tif ( !this.isDisabled() ) {\n\t\tthis.menu.toggle( false );\n\t}\n};\n\n/**\n * Handle button click events.\n *\n * @private\n */\nOO.ui.ComboBoxInputWidget.prototype.onDropdownButtonClick = function () {\n\tthis.menu.toggle();\n\tthis.focus();\n};\n\n/**\n * Handle menu choose events.\n *\n * @private\n * @param {OO.ui.OptionWidget} item Chosen item\n */\nOO.ui.ComboBoxInputWidget.prototype.onMenuChoose = function ( item ) {\n\tthis.setValue( item.getData() );\n};\n\n/**\n * Handle menu item change events.\n *\n * @private\n */\nOO.ui.ComboBoxInputWidget.prototype.onMenuItemsChange = function () {\n\tvar match = this.menu.findItemFromData( this.getValue() );\n\tthis.menu.selectItem( match );\n\tif ( this.menu.findHighlightedItem() ) {\n\t\tthis.menu.highlightItem( match );\n\t}\n\tthis.$element.toggleClass( 'oo-ui-comboBoxInputWidget-empty', this.menu.isEmpty() );\n};\n\n/**\n * Handle menu toggle events.\n *\n * @private\n * @param {boolean} isVisible Open state of the menu\n */\nOO.ui.ComboBoxInputWidget.prototype.onMenuToggle = function ( isVisible ) {\n\tthis.$element.toggleClass( 'oo-ui-comboBoxInputWidget-open', isVisible );\n};\n\n/**\n * Update the disabled state of the controls\n *\n * @chainable\n * @protected\n * @return {OO.ui.ComboBoxInputWidget} The widget, for chaining\n */\nOO.ui.ComboBoxInputWidget.prototype.updateControlsDisabled = function () {\n\tvar disabled = this.isDisabled() || this.isReadOnly();\n\tif ( this.dropdownButton ) {\n\t\tthis.dropdownButton.setDisabled( disabled );\n\t}\n\tif ( this.menu ) {\n\t\tthis.menu.setDisabled( disabled );\n\t}\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.ComboBoxInputWidget.prototype.setDisabled = function () {\n\t// Parent method\n\tOO.ui.ComboBoxInputWidget.parent.prototype.setDisabled.apply( this, arguments );\n\tthis.updateControlsDisabled();\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.ComboBoxInputWidget.prototype.setReadOnly = function () {\n\t// Parent method\n\tOO.ui.ComboBoxInputWidget.parent.prototype.setReadOnly.apply( this, arguments );\n\tthis.updateControlsDisabled();\n\treturn this;\n};\n\n/**\n * Set the options available for this input.\n *\n * @param {Object[]} options Array of menu options in the format `{ data: …, label: … }`\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.ComboBoxInputWidget.prototype.setOptions = function ( options ) {\n\tthis.getMenu()\n\t\t.clearItems()\n\t\t.addItems( options.map( function ( opt ) {\n\t\t\treturn new OO.ui.MenuOptionWidget( {\n\t\t\t\tdata: opt.data,\n\t\t\t\tlabel: opt.label !== undefined ? opt.label : opt.data\n\t\t\t} );\n\t\t} ) );\n\n\treturn this;\n};\n","/**\n * FieldLayouts are used with OO.ui.FieldsetLayout. Each FieldLayout requires a field-widget,\n * which is a widget that is specified by reference before any optional configuration settings.\n *\n * Field layouts can be configured with help text and/or labels. Labels are aligned in one of\n * four ways:\n *\n * - **left**: The label is placed before the field-widget and aligned with the left margin.\n *   A left-alignment is used for forms with many fields.\n * - **right**: The label is placed before the field-widget and aligned to the right margin.\n *   A right-alignment is used for long but familiar forms which users tab through,\n *   verifying the current field with a quick glance at the label.\n * - **top**: The label is placed above the field-widget. A top-alignment is used for brief forms\n *   that users fill out from top to bottom.\n * - **inline**: The label is placed after the field-widget and aligned to the left.\n *   An inline-alignment is best used with checkboxes or radio buttons.\n *\n * Help text can either be:\n *\n * - accessed via a help icon that appears in the upper right corner of the rendered field layout,\n *   or\n * - shown as a subtle explanation below the label.\n *\n * If the help text is brief, or is essential to always expose it, set `helpInline` to `true`.\n * If it is long or not essential, leave `helpInline` to its default, `false`.\n *\n * Please see the [OOUI documentation on MediaWiki] [1] for examples and more information.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Layouts/Fields_and_Fieldsets\n *\n * @class\n * @extends OO.ui.Layout\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.TitledElement\n *\n * @constructor\n * @param {OO.ui.Widget} fieldWidget Field widget\n * @param {Object} [config] Configuration options\n * @cfg {string} [align='left'] Alignment of the label: 'left', 'right', 'top'\n *  or 'inline'\n * @cfg {Array} [errors] Error messages about the widget, which will be\n *  displayed below the widget.\n * @cfg {Array} [warnings] Warning messages about the widget, which will be\n *  displayed below the widget.\n * @cfg {Array} [successMessages] Success messages on user interactions with the widget,\n *  which will be displayed below the widget.\n *  The array may contain strings or OO.ui.HtmlSnippet instances.\n * @cfg {Array} [notices] Notices about the widget, which will be displayed\n *  below the widget.\n *  The array may contain strings or OO.ui.HtmlSnippet instances.\n *  These are more visible than `help` messages when `helpInline` is set, and so\n *  might be good for transient messages.\n * @cfg {string|OO.ui.HtmlSnippet} [help] Help text. When help text is specified\n *  and `helpInline` is `false`, a \"help\" icon will appear in the upper-right\n *  corner of the rendered field; clicking it will display the text in a popup.\n *  If `helpInline` is `true`, then a subtle description will be shown after the\n *  label.\n * @cfg {boolean} [helpInline=false] Whether or not the help should be inline,\n *  or shown when the \"help\" icon is clicked.\n * @cfg {jQuery} [$overlay] Passed to OO.ui.PopupButtonWidget for help popup, if\n * `help` is given.\n *  See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.\n *\n * @throws {Error} An error is thrown if no widget is specified\n */\nOO.ui.FieldLayout = function OoUiFieldLayout( fieldWidget, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( fieldWidget ) && config === undefined ) {\n\t\tconfig = fieldWidget;\n\t\tfieldWidget = config.fieldWidget;\n\t}\n\n\t// Make sure we have required constructor arguments\n\tif ( fieldWidget === undefined ) {\n\t\tthrow new Error( 'Widget not found' );\n\t}\n\n\t// Configuration initialization\n\tconfig = $.extend( { align: 'left', helpInline: false }, config );\n\n\t// Parent constructor\n\tOO.ui.FieldLayout.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.LabelElement.call( this, $.extend( {\n\t\t$label: $( '<label>' )\n\t}, config ) );\n\tOO.ui.mixin.TitledElement.call( this, $.extend( { $titled: this.$label }, config ) );\n\n\t// Properties\n\tthis.fieldWidget = fieldWidget;\n\tthis.errors = [];\n\tthis.warnings = [];\n\tthis.successMessages = [];\n\tthis.notices = [];\n\tthis.$field = this.isFieldInline() ? $( '<span>' ) : $( '<div>' );\n\tthis.$messages = $( '<ul>' );\n\tthis.$header = $( '<span>' );\n\tthis.$body = $( '<div>' );\n\tthis.align = null;\n\tthis.helpInline = config.helpInline;\n\n\t// Events\n\tthis.fieldWidget.connect( this, {\n\t\tdisable: 'onFieldDisable'\n\t} );\n\n\t// Initialization\n\tthis.$help = config.help ?\n\t\tthis.createHelpElement( config.help, config.$overlay ) :\n\t\t$( [] );\n\tif ( this.fieldWidget.getInputId() ) {\n\t\tthis.$label.attr( 'for', this.fieldWidget.getInputId() );\n\t\tif ( this.helpInline ) {\n\t\t\tthis.$help.attr( 'for', this.fieldWidget.getInputId() );\n\t\t}\n\t} else {\n\t\tthis.$label.on( 'click', function () {\n\t\t\tthis.fieldWidget.simulateLabelClick();\n\t\t}.bind( this ) );\n\t\tif ( this.helpInline ) {\n\t\t\tthis.$help.on( 'click', function () {\n\t\t\t\tthis.fieldWidget.simulateLabelClick();\n\t\t\t}.bind( this ) );\n\t\t}\n\t}\n\tthis.$element\n\t\t.addClass( 'oo-ui-fieldLayout' )\n\t\t.toggleClass( 'oo-ui-fieldLayout-disabled', this.fieldWidget.isDisabled() )\n\t\t.append( this.$body );\n\tthis.$body.addClass( 'oo-ui-fieldLayout-body' );\n\tthis.$header.addClass( 'oo-ui-fieldLayout-header' );\n\tthis.$messages.addClass( 'oo-ui-fieldLayout-messages' );\n\tthis.$field\n\t\t.addClass( 'oo-ui-fieldLayout-field' )\n\t\t.append( this.fieldWidget.$element );\n\n\tthis.setErrors( config.errors || [] );\n\tthis.setWarnings( config.warnings || [] );\n\tthis.setSuccess( config.successMessages || [] );\n\tthis.setNotices( config.notices || [] );\n\tthis.setAlignment( config.align );\n\t// Call this again to take into account the widget's accessKey\n\tthis.updateTitle();\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.FieldLayout, OO.ui.Layout );\nOO.mixinClass( OO.ui.FieldLayout, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.FieldLayout, OO.ui.mixin.TitledElement );\n\n/* Methods */\n\n/**\n * Handle field disable events.\n *\n * @private\n * @param {boolean} value Field is disabled\n */\nOO.ui.FieldLayout.prototype.onFieldDisable = function ( value ) {\n\tthis.$element.toggleClass( 'oo-ui-fieldLayout-disabled', value );\n};\n\n/**\n * Get the widget contained by the field.\n *\n * @return {OO.ui.Widget} Field widget\n */\nOO.ui.FieldLayout.prototype.getField = function () {\n\treturn this.fieldWidget;\n};\n\n/**\n * Return `true` if the given field widget can be used with `'inline'` alignment (see\n * #setAlignment). Return `false` if it can't or if this can't be determined.\n *\n * @return {boolean}\n */\nOO.ui.FieldLayout.prototype.isFieldInline = function () {\n\t// This is very simplistic, but should be good enough.\n\treturn this.getField().$element.prop( 'tagName' ).toLowerCase() === 'span';\n};\n\n/**\n * @protected\n * @param {string} kind 'error' or 'notice'\n * @param {string|OO.ui.HtmlSnippet} text\n * @return {jQuery}\n */\nOO.ui.FieldLayout.prototype.makeMessage = function ( kind, text ) {\n\tvar $listItem, $icon, message;\n\t$listItem = $( '<li>' );\n\tif ( kind === 'error' ) {\n\t\t$icon = new OO.ui.IconWidget( { icon: 'error', flags: [ 'error' ] } ).$element;\n\t\t$listItem.attr( 'role', 'alert' );\n\t} else if ( kind === 'warning' ) {\n\t\t$icon = new OO.ui.IconWidget( { icon: 'alert', flags: [ 'warning' ] } ).$element;\n\t\t$listItem.attr( 'role', 'alert' );\n\t} else if ( kind === 'success' ) {\n\t\t$icon = new OO.ui.IconWidget( { icon: 'check', flags: [ 'success' ] } ).$element;\n\t} else if ( kind === 'notice' ) {\n\t\t$icon = new OO.ui.IconWidget( { icon: 'notice' } ).$element;\n\t} else {\n\t\t$icon = '';\n\t}\n\tmessage = new OO.ui.LabelWidget( { label: text } );\n\t$listItem\n\t\t.append( $icon, message.$element )\n\t\t.addClass( 'oo-ui-fieldLayout-messages-' + kind );\n\treturn $listItem;\n};\n\n/**\n * Set the field alignment mode.\n *\n * @private\n * @param {string} value Alignment mode, either 'left', 'right', 'top' or 'inline'\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.FieldLayout.prototype.setAlignment = function ( value ) {\n\tif ( value !== this.align ) {\n\t\t// Default to 'left'\n\t\tif ( [ 'left', 'right', 'top', 'inline' ].indexOf( value ) === -1 ) {\n\t\t\tvalue = 'left';\n\t\t}\n\t\t// Validate\n\t\tif ( value === 'inline' && !this.isFieldInline() ) {\n\t\t\tvalue = 'top';\n\t\t}\n\t\t// Reorder elements\n\n\t\tif ( this.helpInline ) {\n\t\t\tif ( value === 'top' ) {\n\t\t\t\tthis.$header.append( this.$label );\n\t\t\t\tthis.$body.append( this.$header, this.$field, this.$help );\n\t\t\t} else if ( value === 'inline' ) {\n\t\t\t\tthis.$header.append( this.$label, this.$help );\n\t\t\t\tthis.$body.append( this.$field, this.$header );\n\t\t\t} else {\n\t\t\t\tthis.$header.append( this.$label, this.$help );\n\t\t\t\tthis.$body.append( this.$header, this.$field );\n\t\t\t}\n\t\t} else {\n\t\t\tif ( value === 'top' ) {\n\t\t\t\tthis.$header.append( this.$help, this.$label );\n\t\t\t\tthis.$body.append( this.$header, this.$field );\n\t\t\t} else if ( value === 'inline' ) {\n\t\t\t\tthis.$header.append( this.$help, this.$label );\n\t\t\t\tthis.$body.append( this.$field, this.$header );\n\t\t\t} else {\n\t\t\t\tthis.$header.append( this.$label );\n\t\t\t\tthis.$body.append( this.$header, this.$help, this.$field );\n\t\t\t}\n\t\t}\n\t\t// Set classes. The following classes can be used here:\n\t\t// * oo-ui-fieldLayout-align-left\n\t\t// * oo-ui-fieldLayout-align-right\n\t\t// * oo-ui-fieldLayout-align-top\n\t\t// * oo-ui-fieldLayout-align-inline\n\t\tif ( this.align ) {\n\t\t\tthis.$element.removeClass( 'oo-ui-fieldLayout-align-' + this.align );\n\t\t}\n\t\tthis.$element.addClass( 'oo-ui-fieldLayout-align-' + value );\n\t\tthis.align = value;\n\t}\n\n\treturn this;\n};\n\n/**\n * Set the list of error messages.\n *\n * @param {Array} errors Error messages about the widget, which will be displayed below the widget.\n *  The array may contain strings or OO.ui.HtmlSnippet instances.\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.FieldLayout.prototype.setErrors = function ( errors ) {\n\tthis.errors = errors.slice();\n\tthis.updateMessages();\n\treturn this;\n};\n\n/**\n * Set the list of warning messages.\n *\n * @param {Array} warnings Warning messages about the widget, which will be displayed below\n *  the widget.\n *  The array may contain strings or OO.ui.HtmlSnippet instances.\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.FieldLayout.prototype.setWarnings = function ( warnings ) {\n\tthis.warnings = warnings.slice();\n\tthis.updateMessages();\n\treturn this;\n};\n\n/**\n * Set the list of success messages.\n *\n * @param {Array} successMessages Success messages about the widget, which will be displayed below\n *  the widget.\n *  The array may contain strings or OO.ui.HtmlSnippet instances.\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.FieldLayout.prototype.setSuccess = function ( successMessages ) {\n\tthis.successMessages = successMessages.slice();\n\tthis.updateMessages();\n\treturn this;\n};\n\n/**\n * Set the list of notice messages.\n *\n * @param {Array} notices Notices about the widget, which will be displayed below the widget.\n *  The array may contain strings or OO.ui.HtmlSnippet instances.\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.FieldLayout.prototype.setNotices = function ( notices ) {\n\tthis.notices = notices.slice();\n\tthis.updateMessages();\n\treturn this;\n};\n\n/**\n * Update the rendering of error, warning, success and notice messages.\n *\n * @private\n */\nOO.ui.FieldLayout.prototype.updateMessages = function () {\n\tvar i;\n\tthis.$messages.empty();\n\n\tif (\n\t\tthis.errors.length ||\n\t\tthis.warnings.length ||\n\t\tthis.successMessages.length ||\n\t\tthis.notices.length\n\t) {\n\t\tthis.$body.after( this.$messages );\n\t} else {\n\t\tthis.$messages.remove();\n\t\treturn;\n\t}\n\n\tfor ( i = 0; i < this.errors.length; i++ ) {\n\t\tthis.$messages.append( this.makeMessage( 'error', this.errors[ i ] ) );\n\t}\n\tfor ( i = 0; i < this.warnings.length; i++ ) {\n\t\tthis.$messages.append( this.makeMessage( 'warning', this.warnings[ i ] ) );\n\t}\n\tfor ( i = 0; i < this.successMessages.length; i++ ) {\n\t\tthis.$messages.append( this.makeMessage( 'success', this.successMessages[ i ] ) );\n\t}\n\tfor ( i = 0; i < this.notices.length; i++ ) {\n\t\tthis.$messages.append( this.makeMessage( 'notice', this.notices[ i ] ) );\n\t}\n};\n\n/**\n * Include information about the widget's accessKey in our title. TitledElement calls this method.\n * (This is a bit of a hack.)\n *\n * @protected\n * @param {string} title Tooltip label for 'title' attribute\n * @return {string}\n */\nOO.ui.FieldLayout.prototype.formatTitleWithAccessKey = function ( title ) {\n\tif ( this.fieldWidget && this.fieldWidget.formatTitleWithAccessKey ) {\n\t\treturn this.fieldWidget.formatTitleWithAccessKey( title );\n\t}\n\treturn title;\n};\n\n/**\n * Creates and returns the help element. Also sets the `aria-describedby`\n * attribute on the main element of the `fieldWidget`.\n *\n * @private\n * @param {string|OO.ui.HtmlSnippet} [help] Help text.\n * @param {jQuery} [$overlay] Passed to OO.ui.PopupButtonWidget for help popup.\n * @return {jQuery} The element that should become `this.$help`.\n */\nOO.ui.FieldLayout.prototype.createHelpElement = function ( help, $overlay ) {\n\tvar helpId, helpWidget;\n\n\tif ( this.helpInline ) {\n\t\thelpWidget = new OO.ui.LabelWidget( {\n\t\t\tlabel: help,\n\t\t\tclasses: [ 'oo-ui-inline-help' ]\n\t\t} );\n\n\t\thelpId = helpWidget.getElementId();\n\t} else {\n\t\thelpWidget = new OO.ui.PopupButtonWidget( {\n\t\t\t$overlay: $overlay,\n\t\t\tpopup: {\n\t\t\t\tpadded: true\n\t\t\t},\n\t\t\tclasses: [ 'oo-ui-fieldLayout-help' ],\n\t\t\tframed: false,\n\t\t\ticon: 'info',\n\t\t\tlabel: OO.ui.msg( 'ooui-field-help' ),\n\t\t\tinvisibleLabel: true\n\t\t} );\n\t\tif ( help instanceof OO.ui.HtmlSnippet ) {\n\t\t\thelpWidget.getPopup().$body.html( help.toString() );\n\t\t} else {\n\t\t\thelpWidget.getPopup().$body.text( help );\n\t\t}\n\n\t\thelpId = helpWidget.getPopup().getBodyId();\n\t}\n\n\t// Set the 'aria-describedby' attribute on the fieldWidget\n\t// Preference given to an input or a button\n\t(\n\t\tthis.fieldWidget.$input ||\n\t\tthis.fieldWidget.$button ||\n\t\tthis.fieldWidget.$element\n\t).attr( 'aria-describedby', helpId );\n\n\treturn helpWidget.$element;\n};\n","/**\n * ActionFieldLayouts are used with OO.ui.FieldsetLayout. The layout consists of a field-widget,\n * a button, and an optional label and/or help text. The field-widget (e.g., a\n * {@link OO.ui.TextInputWidget TextInputWidget}), is required and is specified before any optional\n * configuration settings.\n *\n * Labels can be aligned in one of four ways:\n *\n * - **left**: The label is placed before the field-widget and aligned with the left margin.\n *   A left-alignment is used for forms with many fields.\n * - **right**: The label is placed before the field-widget and aligned to the right margin.\n *   A right-alignment is used for long but familiar forms which users tab through,\n *   verifying the current field with a quick glance at the label.\n * - **top**: The label is placed above the field-widget. A top-alignment is used for brief forms\n *   that users fill out from top to bottom.\n * - **inline**: The label is placed after the field-widget and aligned to the left.\n *   An inline-alignment is best used with checkboxes or radio buttons.\n *\n * Help text is accessed via a help icon that appears in the upper right corner of the rendered\n * field layout when help text is specified.\n *\n *     @example\n *     // Example of an ActionFieldLayout\n *     var actionFieldLayout = new OO.ui.ActionFieldLayout(\n *         new OO.ui.TextInputWidget( {\n *             placeholder: 'Field widget'\n *         } ),\n *         new OO.ui.ButtonWidget( {\n *             label: 'Button'\n *         } ),\n *         {\n *             label: 'An ActionFieldLayout. This label is aligned top',\n *             align: 'top',\n *             help: 'This is help text'\n *         }\n *     );\n *\n *     $( document.body ).append( actionFieldLayout.$element );\n *\n * @class\n * @extends OO.ui.FieldLayout\n *\n * @constructor\n * @param {OO.ui.Widget} fieldWidget Field widget\n * @param {OO.ui.ButtonWidget} buttonWidget Button widget\n * @param {Object} config\n */\nOO.ui.ActionFieldLayout = function OoUiActionFieldLayout( fieldWidget, buttonWidget, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( fieldWidget ) && config === undefined ) {\n\t\tconfig = fieldWidget;\n\t\tfieldWidget = config.fieldWidget;\n\t\tbuttonWidget = config.buttonWidget;\n\t}\n\n\t// Parent constructor\n\tOO.ui.ActionFieldLayout.parent.call( this, fieldWidget, config );\n\n\t// Properties\n\tthis.buttonWidget = buttonWidget;\n\tthis.$button = $( '<span>' );\n\tthis.$input = this.isFieldInline() ? $( '<span>' ) : $( '<div>' );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-actionFieldLayout' );\n\tthis.$button\n\t\t.addClass( 'oo-ui-actionFieldLayout-button' )\n\t\t.append( this.buttonWidget.$element );\n\tthis.$input\n\t\t.addClass( 'oo-ui-actionFieldLayout-input' )\n\t\t.append( this.fieldWidget.$element );\n\tthis.$field.append( this.$input, this.$button );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ActionFieldLayout, OO.ui.FieldLayout );\n","/**\n * FieldsetLayouts are composed of one or more {@link OO.ui.FieldLayout FieldLayouts},\n * which each contain an individual widget and, optionally, a label. Each Fieldset can be\n * configured with a label as well. For more information and examples,\n * please see the [OOUI documentation on MediaWiki][1].\n *\n *     @example\n *     // Example of a fieldset layout\n *     var input1 = new OO.ui.TextInputWidget( {\n *         placeholder: 'A text input field'\n *     } );\n *\n *     var input2 = new OO.ui.TextInputWidget( {\n *         placeholder: 'A text input field'\n *     } );\n *\n *     var fieldset = new OO.ui.FieldsetLayout( {\n *         label: 'Example of a fieldset layout'\n *     } );\n *\n *     fieldset.addItems( [\n *         new OO.ui.FieldLayout( input1, {\n *             label: 'Field One'\n *         } ),\n *         new OO.ui.FieldLayout( input2, {\n *             label: 'Field Two'\n *         } )\n *     ] );\n *     $( document.body ).append( fieldset.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Layouts/Fields_and_Fieldsets\n *\n * @class\n * @extends OO.ui.Layout\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.GroupElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {OO.ui.FieldLayout[]} [items] An array of fields to add to the fieldset.\n *  See OO.ui.FieldLayout for more information about fields.\n * @cfg {string|OO.ui.HtmlSnippet} [help] Help text. When help text is specified, a \"help\" icon\n *  will appear in the upper-right corner of the rendered field; clicking it will display the text\n *  in a popup. For important messages, you are advised to use `notices`, as they are always shown.\n * @cfg {jQuery} [$overlay] Passed to OO.ui.PopupButtonWidget for help popup, if `help` is given.\n *  See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.\n */\nOO.ui.FieldsetLayout = function OoUiFieldsetLayout( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.FieldsetLayout.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.GroupElement.call( this, config );\n\n\t// Properties\n\tthis.$header = $( '<legend>' );\n\tif ( config.help ) {\n\t\tthis.popupButtonWidget = new OO.ui.PopupButtonWidget( {\n\t\t\t$overlay: config.$overlay,\n\t\t\tpopup: {\n\t\t\t\tpadded: true\n\t\t\t},\n\t\t\tclasses: [ 'oo-ui-fieldsetLayout-help' ],\n\t\t\tframed: false,\n\t\t\ticon: 'info',\n\t\t\tlabel: OO.ui.msg( 'ooui-field-help' ),\n\t\t\tinvisibleLabel: true\n\t\t} );\n\t\tif ( config.help instanceof OO.ui.HtmlSnippet ) {\n\t\t\tthis.popupButtonWidget.getPopup().$body.html( config.help.toString() );\n\t\t} else {\n\t\t\tthis.popupButtonWidget.getPopup().$body.text( config.help );\n\t\t}\n\t\tthis.$help = this.popupButtonWidget.$element;\n\t} else {\n\t\tthis.$help = $( [] );\n\t}\n\n\t// Initialization\n\tthis.$header\n\t\t.addClass( 'oo-ui-fieldsetLayout-header' )\n\t\t.append( this.$icon, this.$label, this.$help );\n\tthis.$group.addClass( 'oo-ui-fieldsetLayout-group' );\n\tthis.$element\n\t\t.addClass( 'oo-ui-fieldsetLayout' )\n\t\t.prepend( this.$header, this.$group );\n\tif ( Array.isArray( config.items ) ) {\n\t\tthis.addItems( config.items );\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.FieldsetLayout, OO.ui.Layout );\nOO.mixinClass( OO.ui.FieldsetLayout, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.FieldsetLayout, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.FieldsetLayout, OO.ui.mixin.GroupElement );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.FieldsetLayout.static.tagName = 'fieldset';\n","/**\n * FormLayouts are used to wrap {@link OO.ui.FieldsetLayout FieldsetLayouts} when you intend to use\n * browser-based form submission for the fields instead of handling them in JavaScript. Form layouts\n * can be configured with an HTML form action, an encoding type, and a method using the #action,\n * #enctype, and #method configs, respectively.\n * See the [OOUI documentation on MediaWiki] [1] for more information and examples.\n *\n * Only widgets from the {@link OO.ui.InputWidget InputWidget} family support form submission. It\n * includes standard form elements like {@link OO.ui.CheckboxInputWidget checkboxes}, {@link\n * OO.ui.RadioInputWidget radio buttons} and {@link OO.ui.TextInputWidget text fields}, as well as\n * some fancier controls. Some controls have both regular and InputWidget variants, for example\n * OO.ui.DropdownWidget and OO.ui.DropdownInputWidget – only the latter support form submission and\n * often have simplified APIs to match the capabilities of HTML forms.\n * See the [OOUI documentation on MediaWiki] [2] for more information about InputWidgets.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Layouts/Forms\n * [2]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs\n *\n *     @example\n *     // Example of a form layout that wraps a fieldset layout.\n *     var input1 = new OO.ui.TextInputWidget( {\n *             placeholder: 'Username'\n *         } ),\n *         input2 = new OO.ui.TextInputWidget( {\n *             placeholder: 'Password',\n *             type: 'password'\n *         } ),\n *         submit = new OO.ui.ButtonInputWidget( {\n *             label: 'Submit'\n *         } ),\n *         fieldset = new OO.ui.FieldsetLayout( {\n *             label: 'A form layout'\n *         } );\n *\n *     fieldset.addItems( [\n *         new OO.ui.FieldLayout( input1, {\n *             label: 'Username',\n *             align: 'top'\n *         } ),\n *         new OO.ui.FieldLayout( input2, {\n *             label: 'Password',\n *             align: 'top'\n *         } ),\n *         new OO.ui.FieldLayout( submit )\n *     ] );\n *     var form = new OO.ui.FormLayout( {\n *         items: [ fieldset ],\n *         action: '/api/formhandler',\n *         method: 'get'\n *     } )\n *     $( document.body ).append( form.$element );\n *\n * @class\n * @extends OO.ui.Layout\n * @mixins OO.ui.mixin.GroupElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {string} [method] HTML form `method` attribute\n * @cfg {string} [action] HTML form `action` attribute\n * @cfg {string} [enctype] HTML form `enctype` attribute\n * @cfg {OO.ui.FieldsetLayout[]} [items] Fieldset layouts to add to the form layout.\n */\nOO.ui.FormLayout = function OoUiFormLayout( config ) {\n\tvar action;\n\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.FormLayout.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.GroupElement.call( this, $.extend( { $group: this.$element }, config ) );\n\n\t// Events\n\tthis.$element.on( 'submit', this.onFormSubmit.bind( this ) );\n\n\t// Make sure the action is safe\n\taction = config.action;\n\tif ( action !== undefined && !OO.ui.isSafeUrl( action ) ) {\n\t\taction = './' + action;\n\t}\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-formLayout' )\n\t\t.attr( {\n\t\t\tmethod: config.method,\n\t\t\taction: action,\n\t\t\tenctype: config.enctype\n\t\t} );\n\tif ( Array.isArray( config.items ) ) {\n\t\tthis.addItems( config.items );\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.FormLayout, OO.ui.Layout );\nOO.mixinClass( OO.ui.FormLayout, OO.ui.mixin.GroupElement );\n\n/* Events */\n\n/**\n * A 'submit' event is emitted when the form is submitted.\n *\n * @event submit\n */\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.FormLayout.static.tagName = 'form';\n\n/* Methods */\n\n/**\n * Handle form submit events.\n *\n * @private\n * @param {jQuery.Event} e Submit event\n * @fires submit\n * @return {OO.ui.FormLayout} The layout, for chaining\n */\nOO.ui.FormLayout.prototype.onFormSubmit = function () {\n\tif ( this.emit( 'submit' ) ) {\n\t\treturn false;\n\t}\n};\n","/**\n * PanelLayouts expand to cover the entire area of their parent. They can be configured with\n * scrolling, padding, and a frame, and are often used together with\n * {@link OO.ui.StackLayout StackLayouts}.\n *\n *     @example\n *     // Example of a panel layout\n *     var panel = new OO.ui.PanelLayout( {\n *         expanded: false,\n *         framed: true,\n *         padded: true,\n *         $content: $( '<p>A panel layout with padding and a frame.</p>' )\n *     } );\n *     $( document.body ).append( panel.$element );\n *\n * @class\n * @extends OO.ui.Layout\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [scrollable=false] Allow vertical scrolling\n * @cfg {boolean} [padded=false] Add padding between the content and the edges of the panel.\n * @cfg {boolean} [expanded=true] Expand the panel to fill the entire parent element.\n * @cfg {boolean} [framed=false] Render the panel with a frame to visually separate it from outside\n *  content.\n */\nOO.ui.PanelLayout = function OoUiPanelLayout( config ) {\n\t// Configuration initialization\n\tconfig = $.extend( {\n\t\tscrollable: false,\n\t\tpadded: false,\n\t\texpanded: true,\n\t\tframed: false\n\t}, config );\n\n\t// Parent constructor\n\tOO.ui.PanelLayout.parent.call( this, config );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-panelLayout' );\n\tif ( config.scrollable ) {\n\t\tthis.$element.addClass( 'oo-ui-panelLayout-scrollable' );\n\t}\n\tif ( config.padded ) {\n\t\tthis.$element.addClass( 'oo-ui-panelLayout-padded' );\n\t}\n\tif ( config.expanded ) {\n\t\tthis.$element.addClass( 'oo-ui-panelLayout-expanded' );\n\t}\n\tif ( config.framed ) {\n\t\tthis.$element.addClass( 'oo-ui-panelLayout-framed' );\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.PanelLayout, OO.ui.Layout );\n\n/* Static Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.PanelLayout.static.reusePreInfuseDOM = function ( node, config ) {\n\tconfig = OO.ui.PanelLayout.parent.static.reusePreInfuseDOM( node, config );\n\tif ( config.preserveContent !== false ) {\n\t\tconfig.$content = $( node ).contents();\n\t}\n\treturn config;\n};\n\n/* Methods */\n\n/**\n * Focus the panel layout\n *\n * The default implementation just focuses the first focusable element in the panel\n */\nOO.ui.PanelLayout.prototype.focus = function () {\n\tOO.ui.findFocusable( this.$element ).focus();\n};\n","/**\n * HorizontalLayout arranges its contents in a single line (using `display: inline-block` for its\n * items), with small margins between them. Convenient when you need to put a number of block-level\n * widgets on a single line next to each other.\n *\n * Note that inline elements, such as OO.ui.ButtonWidgets, do not need this wrapper.\n *\n *     @example\n *     // HorizontalLayout with a text input and a label.\n *     var layout = new OO.ui.HorizontalLayout( {\n *       items: [\n *         new OO.ui.LabelWidget( { label: 'Label' } ),\n *         new OO.ui.TextInputWidget( { value: 'Text' } )\n *       ]\n *     } );\n *     $( document.body ).append( layout.$element );\n *\n * @class\n * @extends OO.ui.Layout\n * @mixins OO.ui.mixin.GroupElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {OO.ui.Widget[]|OO.ui.Layout[]} [items] Widgets or other layouts to add to the layout.\n */\nOO.ui.HorizontalLayout = function OoUiHorizontalLayout( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.HorizontalLayout.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.GroupElement.call( this, $.extend( { $group: this.$element }, config ) );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-horizontalLayout' );\n\tif ( Array.isArray( config.items ) ) {\n\t\tthis.addItems( config.items );\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.HorizontalLayout, OO.ui.Layout );\nOO.mixinClass( OO.ui.HorizontalLayout, OO.ui.mixin.GroupElement );\n","/**\n * NumberInputWidgets combine a {@link OO.ui.TextInputWidget text input} (where a value\n * can be entered manually) and two {@link OO.ui.ButtonWidget button widgets}\n * (to adjust the value in increments) to allow the user to enter a number.\n *\n *     @example\n *     // A NumberInputWidget.\n *     var numberInput = new OO.ui.NumberInputWidget( {\n *         label: 'NumberInputWidget',\n *         input: { value: 5 },\n *         min: 1,\n *         max: 10\n *     } );\n *     $( document.body ).append( numberInput.$element );\n *\n * @class\n * @extends OO.ui.TextInputWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {Object} [minusButton] Configuration options to pass to the\n *  {@link OO.ui.ButtonWidget decrementing button widget}.\n * @cfg {Object} [plusButton] Configuration options to pass to the\n *  {@link OO.ui.ButtonWidget incrementing button widget}.\n * @cfg {number} [min=-Infinity] Minimum allowed value\n * @cfg {number} [max=Infinity] Maximum allowed value\n * @cfg {number|null} [step] If specified, the field only accepts values that are multiples of this.\n * @cfg {number} [buttonStep=step||1] Delta when using the buttons or Up/Down arrow keys.\n *  Defaults to `step` if specified, otherwise `1`.\n * @cfg {number} [pageStep=10*buttonStep] Delta when using the Page-up/Page-down keys.\n *  Defaults to 10 times `buttonStep`.\n * @cfg {boolean} [showButtons=true] Whether to show the plus and minus buttons.\n */\nOO.ui.NumberInputWidget = function OoUiNumberInputWidget( config ) {\n\tvar $field = $( '<div>' ).addClass( 'oo-ui-numberInputWidget-field' );\n\n\t// Configuration initialization\n\tconfig = $.extend( {\n\t\tmin: -Infinity,\n\t\tmax: Infinity,\n\t\tshowButtons: true\n\t}, config );\n\n\t// For backward compatibility\n\t$.extend( config, config.input );\n\tthis.input = this;\n\n\t// Parent constructor\n\tOO.ui.NumberInputWidget.parent.call( this, $.extend( config, {\n\t\ttype: 'number'\n\t} ) );\n\n\tif ( config.showButtons ) {\n\t\tthis.minusButton = new OO.ui.ButtonWidget( $.extend(\n\t\t\t{\n\t\t\t\tdisabled: this.isDisabled(),\n\t\t\t\ttabIndex: -1,\n\t\t\t\tclasses: [ 'oo-ui-numberInputWidget-minusButton' ],\n\t\t\t\ticon: 'subtract'\n\t\t\t},\n\t\t\tconfig.minusButton\n\t\t) );\n\t\tthis.minusButton.$element.attr( 'aria-hidden', 'true' );\n\t\tthis.plusButton = new OO.ui.ButtonWidget( $.extend(\n\t\t\t{\n\t\t\t\tdisabled: this.isDisabled(),\n\t\t\t\ttabIndex: -1,\n\t\t\t\tclasses: [ 'oo-ui-numberInputWidget-plusButton' ],\n\t\t\t\ticon: 'add'\n\t\t\t},\n\t\t\tconfig.plusButton\n\t\t) );\n\t\tthis.plusButton.$element.attr( 'aria-hidden', 'true' );\n\t}\n\n\t// Events\n\tthis.$input.on( {\n\t\tkeydown: this.onKeyDown.bind( this ),\n\t\t'wheel mousewheel DOMMouseScroll': this.onWheel.bind( this )\n\t} );\n\tif ( config.showButtons ) {\n\t\tthis.plusButton.connect( this, {\n\t\t\tclick: [ 'onButtonClick', +1 ]\n\t\t} );\n\t\tthis.minusButton.connect( this, {\n\t\t\tclick: [ 'onButtonClick', -1 ]\n\t\t} );\n\t}\n\n\t// Build the field\n\t$field.append( this.$input );\n\tif ( config.showButtons ) {\n\t\t$field\n\t\t\t.prepend( this.minusButton.$element )\n\t\t\t.append( this.plusButton.$element );\n\t}\n\n\t// Initialization\n\tif ( config.allowInteger || config.isInteger ) {\n\t\t// Backward compatibility\n\t\tconfig.step = 1;\n\t}\n\tthis.setRange( config.min, config.max );\n\tthis.setStep( config.buttonStep, config.pageStep, config.step );\n\t// Set the validation method after we set step and range\n\t// so that it doesn't immediately call setValidityFlag\n\tthis.setValidation( this.validateNumber.bind( this ) );\n\n\tthis.$element\n\t\t.addClass( 'oo-ui-numberInputWidget' )\n\t\t.toggleClass( 'oo-ui-numberInputWidget-buttoned', config.showButtons )\n\t\t.append( $field );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.NumberInputWidget, OO.ui.TextInputWidget );\n\n/* Methods */\n\n// Backward compatibility\nOO.ui.NumberInputWidget.prototype.setAllowInteger = function ( flag ) {\n\tthis.setStep( flag ? 1 : null );\n};\n// Backward compatibility\nOO.ui.NumberInputWidget.prototype.setIsInteger = OO.ui.NumberInputWidget.prototype.setAllowInteger;\n\n// Backward compatibility\nOO.ui.NumberInputWidget.prototype.getAllowInteger = function () {\n\treturn this.step === 1;\n};\n// Backward compatibility\nOO.ui.NumberInputWidget.prototype.getIsInteger = OO.ui.NumberInputWidget.prototype.getAllowInteger;\n\n/**\n * Set the range of allowed values\n *\n * @param {number} min Minimum allowed value\n * @param {number} max Maximum allowed value\n */\nOO.ui.NumberInputWidget.prototype.setRange = function ( min, max ) {\n\tif ( min > max ) {\n\t\tthrow new Error( 'Minimum (' + min + ') must not be greater than maximum (' + max + ')' );\n\t}\n\tthis.min = min;\n\tthis.max = max;\n\tthis.$input.attr( 'min', this.min );\n\tthis.$input.attr( 'max', this.max );\n\tthis.setValidityFlag();\n};\n\n/**\n * Get the current range\n *\n * @return {number[]} Minimum and maximum values\n */\nOO.ui.NumberInputWidget.prototype.getRange = function () {\n\treturn [ this.min, this.max ];\n};\n\n/**\n * Set the stepping deltas\n *\n * @param {number} [buttonStep=step||1] Delta when using the buttons or up/down arrow keys.\n *  Defaults to `step` if specified, otherwise `1`.\n * @param {number} [pageStep=10*buttonStep] Delta when using the page-up/page-down keys.\n *  Defaults to 10 times `buttonStep`.\n * @param {number|null} [step] If specified, the field only accepts values that are multiples\n *  of this.\n */\nOO.ui.NumberInputWidget.prototype.setStep = function ( buttonStep, pageStep, step ) {\n\tif ( buttonStep === undefined ) {\n\t\tbuttonStep = step || 1;\n\t}\n\tif ( pageStep === undefined ) {\n\t\tpageStep = 10 * buttonStep;\n\t}\n\tif ( step !== null && step <= 0 ) {\n\t\tthrow new Error( 'Step value, if given, must be positive' );\n\t}\n\tif ( buttonStep <= 0 ) {\n\t\tthrow new Error( 'Button step value must be positive' );\n\t}\n\tif ( pageStep <= 0 ) {\n\t\tthrow new Error( 'Page step value must be positive' );\n\t}\n\tthis.step = step;\n\tthis.buttonStep = buttonStep;\n\tthis.pageStep = pageStep;\n\tthis.$input.attr( 'step', this.step || 'any' );\n\tthis.setValidityFlag();\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.NumberInputWidget.prototype.setValue = function ( value ) {\n\tif ( value === '' ) {\n\t\t// Some browsers allow a value in the input even if there isn't one reported by $input.val()\n\t\t// so here we make sure an 'empty' value is actually displayed as such.\n\t\tthis.$input.val( '' );\n\t}\n\treturn OO.ui.NumberInputWidget.parent.prototype.setValue.call( this, value );\n};\n\n/**\n * Get the current stepping values\n *\n * @return {number[]} Button step, page step, and validity step\n */\nOO.ui.NumberInputWidget.prototype.getStep = function () {\n\treturn [ this.buttonStep, this.pageStep, this.step ];\n};\n\n/**\n * Get the current value of the widget as a number\n *\n * @return {number} May be NaN, or an invalid number\n */\nOO.ui.NumberInputWidget.prototype.getNumericValue = function () {\n\treturn +this.getValue();\n};\n\n/**\n * Adjust the value of the widget\n *\n * @param {number} delta Adjustment amount\n */\nOO.ui.NumberInputWidget.prototype.adjustValue = function ( delta ) {\n\tvar n, v = this.getNumericValue();\n\n\tdelta = +delta;\n\tif ( isNaN( delta ) || !isFinite( delta ) ) {\n\t\tthrow new Error( 'Delta must be a finite number' );\n\t}\n\n\tif ( isNaN( v ) ) {\n\t\tn = 0;\n\t} else {\n\t\tn = v + delta;\n\t\tn = Math.max( Math.min( n, this.max ), this.min );\n\t\tif ( this.step ) {\n\t\t\tn = Math.round( n / this.step ) * this.step;\n\t\t}\n\t}\n\n\tif ( n !== v ) {\n\t\tthis.setValue( n );\n\t}\n};\n/**\n * Validate input\n *\n * @private\n * @param {string} value Field value\n * @return {boolean}\n */\nOO.ui.NumberInputWidget.prototype.validateNumber = function ( value ) {\n\tvar n = +value;\n\tif ( value === '' ) {\n\t\treturn !this.isRequired();\n\t}\n\n\tif ( isNaN( n ) || !isFinite( n ) ) {\n\t\treturn false;\n\t}\n\n\tif ( this.step && Math.floor( n / this.step ) !== n / this.step ) {\n\t\treturn false;\n\t}\n\n\tif ( n < this.min || n > this.max ) {\n\t\treturn false;\n\t}\n\n\treturn true;\n};\n\n/**\n * Handle mouse click events.\n *\n * @private\n * @param {number} dir +1 or -1\n */\nOO.ui.NumberInputWidget.prototype.onButtonClick = function ( dir ) {\n\tthis.adjustValue( dir * this.buttonStep );\n};\n\n/**\n * Handle mouse wheel events.\n *\n * @private\n * @param {jQuery.Event} event\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.NumberInputWidget.prototype.onWheel = function ( event ) {\n\tvar delta = 0;\n\n\tif ( this.isDisabled() || this.isReadOnly() ) {\n\t\treturn;\n\t}\n\n\tif ( this.$input.is( ':focus' ) ) {\n\t\t// Standard 'wheel' event\n\t\tif ( event.originalEvent.deltaMode !== undefined ) {\n\t\t\tthis.sawWheelEvent = true;\n\t\t}\n\t\tif ( event.originalEvent.deltaY ) {\n\t\t\tdelta = -event.originalEvent.deltaY;\n\t\t} else if ( event.originalEvent.deltaX ) {\n\t\t\tdelta = event.originalEvent.deltaX;\n\t\t}\n\n\t\t// Non-standard events\n\t\tif ( !this.sawWheelEvent ) {\n\t\t\tif ( event.originalEvent.wheelDeltaX ) {\n\t\t\t\tdelta = -event.originalEvent.wheelDeltaX;\n\t\t\t} else if ( event.originalEvent.wheelDeltaY ) {\n\t\t\t\tdelta = event.originalEvent.wheelDeltaY;\n\t\t\t} else if ( event.originalEvent.wheelDelta ) {\n\t\t\t\tdelta = event.originalEvent.wheelDelta;\n\t\t\t} else if ( event.originalEvent.detail ) {\n\t\t\t\tdelta = -event.originalEvent.detail;\n\t\t\t}\n\t\t}\n\n\t\tif ( delta ) {\n\t\t\tdelta = delta < 0 ? -1 : 1;\n\t\t\tthis.adjustValue( delta * this.buttonStep );\n\t\t}\n\n\t\treturn false;\n\t}\n};\n\n/**\n * Handle key down events.\n *\n * @private\n * @param {jQuery.Event} e Key down event\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.NumberInputWidget.prototype.onKeyDown = function ( e ) {\n\tif ( this.isDisabled() || this.isReadOnly() ) {\n\t\treturn;\n\t}\n\n\tswitch ( e.which ) {\n\t\tcase OO.ui.Keys.UP:\n\t\t\tthis.adjustValue( this.buttonStep );\n\t\t\treturn false;\n\t\tcase OO.ui.Keys.DOWN:\n\t\t\tthis.adjustValue( -this.buttonStep );\n\t\t\treturn false;\n\t\tcase OO.ui.Keys.PAGEUP:\n\t\t\tthis.adjustValue( this.pageStep );\n\t\t\treturn false;\n\t\tcase OO.ui.Keys.PAGEDOWN:\n\t\t\tthis.adjustValue( -this.pageStep );\n\t\t\treturn false;\n\t}\n};\n\n/**\n * Update the disabled state of the controls\n *\n * @chainable\n * @protected\n * @return {OO.ui.NumberInputWidget} The widget, for chaining\n */\nOO.ui.NumberInputWidget.prototype.updateControlsDisabled = function () {\n\tvar disabled = this.isDisabled() || this.isReadOnly();\n\tif ( this.minusButton ) {\n\t\tthis.minusButton.setDisabled( disabled );\n\t}\n\tif ( this.plusButton ) {\n\t\tthis.plusButton.setDisabled( disabled );\n\t}\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.NumberInputWidget.prototype.setDisabled = function ( disabled ) {\n\t// Parent method\n\tOO.ui.NumberInputWidget.parent.prototype.setDisabled.call( this, disabled );\n\tthis.updateControlsDisabled();\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.NumberInputWidget.prototype.setReadOnly = function () {\n\t// Parent method\n\tOO.ui.NumberInputWidget.parent.prototype.setReadOnly.apply( this, arguments );\n\tthis.updateControlsDisabled();\n\treturn this;\n};\n","/**\n * SelectFileInputWidgets allow for selecting files, using <input type=\"file\">. These\n * widgets can be configured with {@link OO.ui.mixin.IconElement icons}, {@link\n * OO.ui.mixin.IndicatorElement indicators} and {@link OO.ui.mixin.TitledElement titles}.\n * Please see the [OOUI documentation on MediaWiki] [1] for more information and examples.\n *\n * SelectFileInputWidgets must be used in HTML forms, as getValue only returns the filename.\n *\n *     @example\n *     // A file select input widget.\n *     var selectFile = new OO.ui.SelectFileInputWidget();\n *     $( document.body ).append( selectFile.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets\n *\n * @class\n * @extends OO.ui.InputWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {string[]|null} [accept=null] MIME types to accept. null accepts all types.\n * @cfg {boolean} [multiple=false] Allow multiple files to be selected.\n * @cfg {string} [placeholder] Text to display when no file is selected.\n * @cfg {Object} [button] Config to pass to select file button.\n * @cfg {string} [icon] Icon to show next to file info\n */\nOO.ui.SelectFileInputWidget = function OoUiSelectFileInputWidget( config ) {\n\tvar widget = this;\n\n\tconfig = config || {};\n\n\t// Construct buttons before parent method is called (calling setDisabled)\n\tthis.selectButton = new OO.ui.ButtonWidget( $.extend( {\n\t\t$element: $( '<label>' ),\n\t\tclasses: [ 'oo-ui-selectFileInputWidget-selectButton' ],\n\t\tlabel: OO.ui.msg( 'ooui-selectfile-button-select' )\n\t}, config.button ) );\n\n\t// Configuration initialization\n\tconfig = $.extend( {\n\t\taccept: null,\n\t\tplaceholder: OO.ui.msg( 'ooui-selectfile-placeholder' ),\n\t\t$tabIndexed: this.selectButton.$tabIndexed\n\t}, config );\n\n\tthis.info = new OO.ui.SearchInputWidget( {\n\t\tclasses: [ 'oo-ui-selectFileInputWidget-info' ],\n\t\tplaceholder: config.placeholder,\n\t\t// Pass an empty collection so that .focus() always does nothing\n\t\t$tabIndexed: $( [] )\n\t} ).setIcon( config.icon );\n\t// Set tabindex manually on $input as $tabIndexed has been overridden\n\tthis.info.$input.attr( 'tabindex', -1 );\n\n\t// Parent constructor\n\tOO.ui.SelectFileInputWidget.parent.call( this, config );\n\n\t// Properties\n\tthis.currentFiles = this.filterFiles( this.$input[ 0 ].files || [] );\n\tif ( Array.isArray( config.accept ) ) {\n\t\tthis.accept = config.accept;\n\t} else {\n\t\tthis.accept = null;\n\t}\n\tthis.multiple = !!config.multiple;\n\n\t// Events\n\tthis.info.connect( this, { change: 'onInfoChange' } );\n\tthis.selectButton.$button.on( {\n\t\tkeypress: this.onKeyPress.bind( this )\n\t} );\n\tthis.$input.on( {\n\t\tchange: this.onFileSelected.bind( this ),\n\t\t// Support: IE11\n\t\t// In IE 11, focussing a file input (by clicking on it) displays a text cursor and scrolls\n\t\t// the cursor into view (in this case, it scrolls the button, which has 'overflow: hidden').\n\t\t// Since this messes with our custom styling (the file input has large dimensions and this\n\t\t// causes the label to scroll out of view), scroll the button back to top. (T192131)\n\t\tfocus: function () {\n\t\t\twidget.$input.parent().prop( 'scrollTop', 0 );\n\t\t}\n\t} );\n\tthis.connect( this, { change: 'updateUI' } );\n\n\tthis.fieldLayout = new OO.ui.ActionFieldLayout( this.info, this.selectButton, { align: 'top' } );\n\n\tthis.$input\n\t\t.attr( {\n\t\t\ttype: 'file',\n\t\t\t// this.selectButton is tabindexed\n\t\t\ttabindex: -1,\n\t\t\t// Infused input may have previously by\n\t\t\t// TabIndexed, so remove aria-disabled attr.\n\t\t\t'aria-disabled': null\n\t\t} );\n\n\tif ( this.accept ) {\n\t\tthis.$input.attr( 'accept', this.accept.join( ', ' ) );\n\t}\n\tif ( this.multiple ) {\n\t\tthis.$input.attr( 'multiple', '' );\n\t}\n\tthis.selectButton.$button.append( this.$input );\n\n\tthis.$element\n\t\t.addClass( 'oo-ui-selectFileInputWidget' )\n\t\t.append( this.fieldLayout.$element );\n\n\tthis.updateUI();\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.SelectFileInputWidget, OO.ui.InputWidget );\n\n/* Static properties */\n\n// Set empty title so that browser default tooltips like \"No file chosen\" don't appear.\n// On SelectFileWidget this tooltip will often be incorrect, so create a consistent\n// experience on SelectFileInputWidget.\nOO.ui.SelectFileInputWidget.static.title = '';\n\n/* Methods */\n\n/**\n * Get the filename of the currently selected file.\n *\n * @return {string} Filename\n */\nOO.ui.SelectFileInputWidget.prototype.getFilename = function () {\n\tif ( this.currentFiles.length ) {\n\t\treturn this.currentFiles.map( function ( file ) {\n\t\t\treturn file.name;\n\t\t} ).join( ', ' );\n\t} else {\n\t\t// Try to strip leading fakepath.\n\t\treturn this.getValue().split( '\\\\' ).pop();\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.SelectFileInputWidget.prototype.setValue = function ( value ) {\n\tif ( value === undefined ) {\n\t\t// Called during init, don't replace value if just infusing.\n\t\treturn;\n\t}\n\tif ( value ) {\n\t\t// We need to update this.value, but without trying to modify\n\t\t// the DOM value, which would throw an exception.\n\t\tif ( this.value !== value ) {\n\t\t\tthis.value = value;\n\t\t\tthis.emit( 'change', this.value );\n\t\t}\n\t} else {\n\t\tthis.currentFiles = [];\n\t\t// Parent method\n\t\tOO.ui.SelectFileInputWidget.super.prototype.setValue.call( this, '' );\n\t}\n};\n\n/**\n * Handle file selection from the input.\n *\n * @protected\n * @param {jQuery.Event} e\n */\nOO.ui.SelectFileInputWidget.prototype.onFileSelected = function ( e ) {\n\tthis.currentFiles = this.filterFiles( e.target.files || [] );\n};\n\n/**\n * Update the user interface when a file is selected or unselected.\n *\n * @protected\n */\nOO.ui.SelectFileInputWidget.prototype.updateUI = function () {\n\tthis.info.setValue( this.getFilename() );\n};\n\n/**\n * Determine if we should accept this file.\n *\n * @private\n * @param {FileList|File[]} files Files to filter\n * @return {File[]} Filter files\n */\nOO.ui.SelectFileInputWidget.prototype.filterFiles = function ( files ) {\n\tvar accept = this.accept;\n\n\tfunction mimeAllowed( file ) {\n\t\tvar i, mimeTest,\n\t\t\tmimeType = file.type;\n\n\t\tif ( !accept || !mimeType ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tfor ( i = 0; i < accept.length; i++ ) {\n\t\t\tmimeTest = accept[ i ];\n\t\t\tif ( mimeTest === mimeType ) {\n\t\t\t\treturn true;\n\t\t\t} else if ( mimeTest.substr( -2 ) === '/*' ) {\n\t\t\t\tmimeTest = mimeTest.substr( 0, mimeTest.length - 1 );\n\t\t\t\tif ( mimeType.substr( 0, mimeTest.length ) === mimeTest ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\treturn Array.prototype.filter.call( files, mimeAllowed );\n};\n\n/**\n * Handle info input change events\n *\n * The info widget can only be changed by the user\n * with the clear button.\n *\n * @private\n * @param {string} value\n */\nOO.ui.SelectFileInputWidget.prototype.onInfoChange = function ( value ) {\n\tif ( value === '' ) {\n\t\tthis.setValue( null );\n\t}\n};\n\n/**\n * Handle key press events.\n *\n * @private\n * @param {jQuery.Event} e Key press event\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.SelectFileInputWidget.prototype.onKeyPress = function ( e ) {\n\tif ( !this.isDisabled() && this.$input &&\n\t\t( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER )\n\t) {\n\t\t// Emit a click to open the file selector.\n\t\tthis.$input.trigger( 'click' );\n\t\t// Taking focus from the selectButton means keyUp isn't fired, so fire it manually.\n\t\tthis.selectButton.onDocumentKeyUp( e );\n\t\treturn false;\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.SelectFileInputWidget.prototype.setDisabled = function ( disabled ) {\n\t// Parent method\n\tOO.ui.SelectFileInputWidget.parent.prototype.setDisabled.call( this, disabled );\n\n\tthis.selectButton.setDisabled( disabled );\n\tthis.info.setDisabled( disabled );\n\n\treturn this;\n};\n","}( OO ) );\n"]}
\ No newline at end of file
index 5b0c7c8..c1d75f6 100644 (file)
@@ -1,19 +1,18 @@
 /*!
- * OOUI v0.31.0
+ * OOUI v0.31.6
  * https://www.mediawiki.org/wiki/OOUI
  *
  * Copyright 2011–2019 OOUI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2019-03-14T00:52:27Z
+ * Date: 2019-05-08T10:08:44Z
  */
 .oo-ui-tool > .oo-ui-tool-link > .oo-ui-tool-checkIcon {
   display: none;
 }
 
-.oo-ui-popupTool-popup .oo-ui-popupWidget-popup,
-.oo-ui-popupTool-popup .oo-ui-popupWidget-anchor {
+.oo-ui-popupTool-popup.oo-ui-popupWidget {
   z-index: 4;
 }
 
@@ -70,9 +69,6 @@
 .oo-ui-toolGroup.oo-ui-widget-enabled:hover {
   border-color: rgba(0, 0, 0, 0.1);
 }
-.oo-ui-toolGroup-tools.oo-ui-toolGroup-enabled-tools .oo-ui-tool-link .oo-ui-tool-title {
-  color: #000;
-}
 
 .oo-ui-barToolGroup-tools > .oo-ui-tool {
   display: inline-block;
 .oo-ui-barToolGroup-tools > .oo-ui-tool > .oo-ui-tool-link .oo-ui-tool-title {
   line-height: 2.1em;
 }
+.oo-ui-barToolGroup-tools > .oo-ui-tool:not( .oo-ui-tool-with-icon ) > .oo-ui-tool-link .oo-ui-iconElement-noIcon {
+  display: none;
+}
 .oo-ui-barToolGroup-tools.oo-ui-toolGroup-enabled-tools > .oo-ui-tool.oo-ui-widget-enabled:hover {
   border-color: rgba(0, 0, 0, 0.2);
 }
 .oo-ui-barToolGroup-tools.oo-ui-toolGroup-enabled-tools > .oo-ui-tool.oo-ui-widget-enabled:hover > .oo-ui-tool-link .oo-ui-iconElement-icon {
   opacity: 1;
 }
+.oo-ui-barToolGroup-tools.oo-ui-toolGroup-enabled-tools > .oo-ui-tool.oo-ui-flaggedElement-progressive {
+  background-color: #cde7f4;
+  background-image: -webkit-gradient(linear, right top, right bottom, color-stop(0, #eaf4fa), color-stop(100%, #b0d9ee));
+  background-image: -webkit-linear-gradient(top, #eaf4fa 0, #b0d9ee 100%);
+  background-image: -moz-linear-gradient(top, #eaf4fa 0, #b0d9ee 100%);
+  background-image: linear-gradient(to bottom, #eaf4fa 0, #b0d9ee 100%);
+  border: 1px solid #a6cee1;
+}
+.oo-ui-barToolGroup-tools.oo-ui-toolGroup-enabled-tools > .oo-ui-tool.oo-ui-flaggedElement-progressive:hover {
+  border-color: #9dc2d4;
+}
+.oo-ui-barToolGroup-tools.oo-ui-toolGroup-enabled-tools > .oo-ui-tool.oo-ui-flaggedElement-progressive.oo-ui-tool-active.oo-ui-widget-enabled {
+  background-color: #cde7f4;
+  background-image: -webkit-gradient(linear, right top, right bottom, color-stop(0, #b0d9ee), color-stop(100%, #eaf4fa));
+  background-image: -webkit-linear-gradient(top, #b0d9ee 0, #eaf4fa 100%);
+  background-image: -moz-linear-gradient(top, #b0d9ee 0, #eaf4fa 100%);
+  background-image: linear-gradient(to bottom, #b0d9ee 0, #eaf4fa 100%);
+  border: 1px solid #a6cee1;
+}
+.oo-ui-barToolGroup-tools.oo-ui-toolGroup-enabled-tools > .oo-ui-tool.oo-ui-flaggedElement-progressive > .oo-ui-tool-link {
+  padding: 0.3125em 0.6255em;
+}
+.oo-ui-barToolGroup-tools.oo-ui-toolGroup-enabled-tools > .oo-ui-tool.oo-ui-flaggedElement-destructive {
+  background-color: #ebebeb;
+  background-image: -webkit-gradient(linear, right top, right bottom, color-stop(0, #fafafa), color-stop(100%, #ddd));
+  background-image: -webkit-linear-gradient(top, #fafafa 0, #ddd 100%);
+  background-image: -moz-linear-gradient(top, #fafafa 0, #ddd 100%);
+  background-image: linear-gradient(to bottom, #fafafa 0, #ddd 100%);
+  border: 1px solid #ccc;
+}
+.oo-ui-barToolGroup-tools.oo-ui-toolGroup-enabled-tools > .oo-ui-tool.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled > .oo-ui-tool-link {
+  color: #d45353;
+}
+.oo-ui-barToolGroup-tools.oo-ui-toolGroup-enabled-tools > .oo-ui-tool.oo-ui-flaggedElement-destructive > .oo-ui-tool-link {
+  padding: 0.3125em 0.6255em;
+}
 .oo-ui-barToolGroup-tools.oo-ui-toolGroup-disabled-tools > .oo-ui-tool:focus {
   outline: 0;
 }
   border-bottom-right-radius: 0;
   box-shadow: inset 0 0.0875em 0.0875em 0 rgba(0, 0, 0, 0.07);
 }
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-progressive {
+  background-color: #cde7f4;
+  background-image: -webkit-gradient(linear, right top, right bottom, color-stop(0, #eaf4fa), color-stop(100%, #b0d9ee));
+  background-image: -webkit-linear-gradient(top, #eaf4fa 0, #b0d9ee 100%);
+  background-image: -moz-linear-gradient(top, #eaf4fa 0, #b0d9ee 100%);
+  background-image: linear-gradient(to bottom, #eaf4fa 0, #b0d9ee 100%);
+  border: 1px solid #a6cee1;
+}
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-progressive:hover {
+  border-color: #9dc2d4;
+}
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-progressive.oo-ui-popupToolGroup-active.oo-ui-widget-enabled {
+  background-color: #cde7f4;
+  background-image: -webkit-gradient(linear, right top, right bottom, color-stop(0, #b0d9ee), color-stop(100%, #eaf4fa));
+  background-image: -webkit-linear-gradient(top, #b0d9ee 0, #eaf4fa 100%);
+  background-image: -moz-linear-gradient(top, #b0d9ee 0, #eaf4fa 100%);
+  background-image: linear-gradient(to bottom, #b0d9ee 0, #eaf4fa 100%);
+  border: 1px solid #a6cee1;
+}
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-destructive {
+  background-color: #ebebeb;
+  background-image: -webkit-gradient(linear, right top, right bottom, color-stop(0, #fafafa), color-stop(100%, #ddd));
+  background-image: -webkit-linear-gradient(top, #fafafa 0, #ddd 100%);
+  background-image: -moz-linear-gradient(top, #fafafa 0, #ddd 100%);
+  background-image: linear-gradient(to bottom, #fafafa 0, #ddd 100%);
+  border: 1px solid #ccc;
+}
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled > .oo-ui-popupToolGroup-handle {
+  color: #d45353;
+}
 .oo-ui-popupToolGroup-tools {
   margin: -1px;
   border: 1px solid #ccc;
index e2d0e47..5fa780f 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOUI v0.31.0
+ * OOUI v0.31.6
  * https://www.mediawiki.org/wiki/OOUI
  *
  * Copyright 2011–2019 OOUI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2019-03-14T00:52:27Z
+ * Date: 2019-05-08T10:08:44Z
  */
 .oo-ui-tool {
   -webkit-box-sizing: border-box;
 .oo-ui-toolbar-narrow .oo-ui-tool .oo-ui-tool-link {
   padding-left: 2.85714286em;
 }
-.oo-ui-tool-with-label .oo-ui-tool-link {
-  padding: 1em 0.85714286em 1em 2.64285714em;
+.oo-ui-tool.oo-ui-tool-with-label .oo-ui-tool-link {
+  padding: 0.85714286em 0.85714286em 0.85714286em 0.85714286em;
+}
+.oo-ui-tool.oo-ui-tool-with-icon.oo-ui-tool-with-label .oo-ui-tool-link {
+  padding: 0.85714286em 0.85714286em 0.85714286em 2.64285714em;
 }
 .oo-ui-tool .oo-ui-iconElement-icon {
   display: block;
@@ -38,9 +41,9 @@
   left: 0.71428571em;
 }
 .oo-ui-tool .oo-ui-tool-title {
-  line-height: 1;
+  line-height: 1.28571429em;
 }
-.oo-ui-tool.oo-ui-widget-enabled {
+.oo-ui-tool.oo-ui-widget-enabled .oo-ui-tool-link {
   -webkit-transition: background-color 100ms;
   -moz-transition: background-color 100ms;
   transition: background-color 100ms;
 .oo-ui-tool.oo-ui-widget-enabled[class*='oo-ui-flaggedElement'] .oo-ui-iconElement-icon {
   opacity: 1;
 }
-.oo-ui-tool.oo-ui-widget-disabled .oo-ui-iconElement-icon {
-  opacity: 0.34;
+.oo-ui-tool.oo-ui-widget-enabled > .oo-ui-tool-link {
+  color: inherit;
+}
+.oo-ui-tool.oo-ui-widget-enabled > .oo-ui-tool-link:hover {
+  background-color: #eaecf0;
+}
+.oo-ui-tool.oo-ui-widget-enabled > .oo-ui-tool-link:active,
+.oo-ui-tool.oo-ui-widget-enabled > .oo-ui-tool-link:active:focus,
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-tool-active > .oo-ui-tool-link,
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-popupToolGroup-active > .oo-ui-tool-link {
+  background-color: #eff3fa;
+  color: #36c;
+  box-shadow: none;
+}
+.oo-ui-tool.oo-ui-widget-enabled > .oo-ui-tool-link:focus {
+  outline: 1px solid #36c;
+  box-shadow: inset 0 0 0 1px #36c;
+}
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-tool-link {
+  color: #36c;
+}
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-tool-link:hover {
+  background-color: #eaecf0;
+}
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-tool-link:active,
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-tool-link:active:focus,
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive.oo-ui-tool-active > .oo-ui-tool-link,
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive.oo-ui-popupToolGroup-active > .oo-ui-tool-link {
+  background-color: #eff3fa;
+  color: #2a4b8d;
+  box-shadow: none;
+}
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-tool-link:focus {
+  outline: 1px solid #36c;
+  box-shadow: inset 0 0 0 1px #36c;
+}
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-tool-link {
+  color: #d73333;
+}
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-tool-link:hover {
+  background-color: #eaecf0;
+}
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-tool-link:active,
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-tool-link:active:focus,
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive.oo-ui-tool-active > .oo-ui-tool-link,
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive.oo-ui-popupToolGroup-active > .oo-ui-tool-link {
+  background-color: #ffffff;
+  color: #b32424;
+  box-shadow: none;
+}
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-tool-link:focus {
+  outline: 1px solid #d33;
+  box-shadow: inset 0 0 0 1px #d33;
+}
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-tool-link {
+  color: #fff;
+  background-color: #36c;
+}
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-tool-link:hover {
+  background-color: #447ff5;
+}
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-tool-link:active,
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-tool-link:active:focus,
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-tool-active > .oo-ui-tool-link {
+  color: #fff;
+  background-color: #2a4b8d;
+  box-shadow: none;
+}
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-tool-link:focus {
+  outline: 1px solid #36c;
+  box-shadow: inset 0 0 0 1px #36c, inset 0 0 0 2px #fff;
+}
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-widget-disabled > .oo-ui-tool-link,
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-widget-disabled > .oo-ui-tool-link:active,
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-widget-disabled > .oo-ui-tool-link:active:focus {
+  background-color: #c8ccd1;
+  color: #fff;
+}
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-tool-link {
+  color: #fff;
+  background-color: #d33;
+}
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-tool-link:hover {
+  background-color: #ff4242;
+}
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-tool-link:active,
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-tool-link:active:focus,
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-tool-active > .oo-ui-tool-link {
+  color: #fff;
+  background-color: #b32424;
+  box-shadow: none;
+}
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-tool-link:focus {
+  outline: 1px solid #d33;
+  box-shadow: inset 0 0 0 1px #d33, inset 0 0 0 2px #fff;
+}
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-widget-disabled > .oo-ui-tool-link,
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-widget-disabled > .oo-ui-tool-link:active,
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-widget-disabled > .oo-ui-tool-link:active:focus {
+  background-color: #c8ccd1;
+  color: #fff;
+}
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-primary > .oo-ui-tool-link > .oo-ui-iconElement-icon,
+.oo-ui-tool.oo-ui-widget-enabled.oo-ui-flaggedElement-primary > .oo-ui-tool-link > .oo-ui-indicatorElement-indicator {
+  opacity: 1;
 }
 
-.oo-ui-popupTool-popup .oo-ui-popupWidget-popup,
-.oo-ui-popupTool-popup .oo-ui-popupWidget-anchor {
+.oo-ui-popupTool-popup.oo-ui-popupWidget {
   z-index: 4;
 }
 
 .oo-ui-toolbar-actions .oo-ui-toolGroup.oo-ui-barToolGroup {
   border-right-width: 0;
 }
-.oo-ui-toolGroup.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator,
-.oo-ui-toolGroup.oo-ui-widget-disabled .oo-ui-iconElement-icon {
+.oo-ui-toolGroup.oo-ui-widget-disabled:not( .oo-ui-flaggedElement-primary ) .oo-ui-indicatorElement-indicator,
+.oo-ui-toolGroup.oo-ui-widget-disabled:not( .oo-ui-flaggedElement-primary ) .oo-ui-iconElement-icon {
   opacity: 0.34 !important;
 }
 
 .oo-ui-barToolGroup-tools > .oo-ui-tool + .oo-ui-tool {
   margin-left: -2px;
 }
-.oo-ui-barToolGroup-tools.oo-ui-toolGroup-enabled-tools > .oo-ui-tool:not( .oo-ui-toolGroupTool ).oo-ui-widget-enabled:hover {
-  background-color: #eaecf0;
+.oo-ui-barToolGroup-tools.oo-ui-toolGroup-enabled-tools .oo-ui-tool.oo-ui-widget-disabled .oo-ui-iconElement-icon,
+.oo-ui-barToolGroup-tools.oo-ui-toolGroup-disabled-tools .oo-ui-tool .oo-ui-iconElement-icon {
+  opacity: 0.34;
 }
-.oo-ui-barToolGroup-tools.oo-ui-toolGroup-enabled-tools > .oo-ui-tool:not( .oo-ui-toolGroupTool ).oo-ui-widget-enabled > .oo-ui-tool-link .oo-ui-tool-title {
-  color: #222;
-  -webkit-transition: color 100ms;
-  -moz-transition: color 100ms;
-  transition: color 100ms;
+.oo-ui-barToolGroup-tools.oo-ui-toolGroup-enabled-tools .oo-ui-tool.oo-ui-widget-disabled.oo-ui-flaggedElement-primary > .oo-ui-tool-link,
+.oo-ui-barToolGroup-tools.oo-ui-toolGroup-disabled-tools .oo-ui-tool.oo-ui-flaggedElement-primary > .oo-ui-tool-link {
+  background-color: #c8ccd1;
+  border-color: #c8ccd1;
 }
-.oo-ui-barToolGroup-tools.oo-ui-toolGroup-enabled-tools > .oo-ui-tool:not( .oo-ui-toolGroupTool ).oo-ui-tool-active {
-  background-color: #eaf3ff;
+.oo-ui-barToolGroup-tools.oo-ui-toolGroup-enabled-tools .oo-ui-tool.oo-ui-widget-disabled.oo-ui-flaggedElement-primary > .oo-ui-tool-link .oo-ui-tool-title,
+.oo-ui-barToolGroup-tools.oo-ui-toolGroup-disabled-tools .oo-ui-tool.oo-ui-flaggedElement-primary > .oo-ui-tool-link .oo-ui-tool-title {
+  color: #fff;
 }
-.oo-ui-barToolGroup-tools.oo-ui-toolGroup-enabled-tools > .oo-ui-tool:not( .oo-ui-toolGroupTool ).oo-ui-tool-active:hover {
-  background-color: rgba(41, 98, 204, 0.1);
+.oo-ui-barToolGroup-tools.oo-ui-toolGroup-enabled-tools .oo-ui-tool.oo-ui-widget-disabled.oo-ui-flaggedElement-primary.oo-ui-tool-active > .oo-ui-tool-link,
+.oo-ui-barToolGroup-tools.oo-ui-toolGroup-disabled-tools .oo-ui-tool.oo-ui-flaggedElement-primary.oo-ui-tool-active > .oo-ui-tool-link {
+  background-color: #919fb9;
 }
-.oo-ui-barToolGroup-tools.oo-ui-toolGroup-enabled-tools > .oo-ui-tool:not( .oo-ui-toolGroupTool ).oo-ui-tool-active > .oo-ui-tool-link .oo-ui-tool-title {
-  color: #36c;
+.oo-ui-barToolGroup-tools.oo-ui-toolGroup-enabled-tools .oo-ui-tool.oo-ui-widget-disabled.oo-ui-flaggedElement-primary .oo-ui-iconElement-icon,
+.oo-ui-barToolGroup-tools.oo-ui-toolGroup-disabled-tools .oo-ui-tool.oo-ui-flaggedElement-primary .oo-ui-iconElement-icon {
+  opacity: 1;
 }
 .oo-ui-barToolGroup-tools.oo-ui-toolGroup-enabled-tools .oo-ui-tool.oo-ui-widget-disabled > .oo-ui-tool-link .oo-ui-tool-title,
 .oo-ui-barToolGroup-tools.oo-ui-toolGroup-disabled-tools .oo-ui-tool > .oo-ui-tool-link .oo-ui-tool-title {
   padding-left: 2.85714286em;
 }
 .oo-ui-popupToolGroup.oo-ui-labelElement .oo-ui-popupToolGroup-handle {
-  padding: 1em 0.85714286em;
+  padding: 0.85714286em 0.85714286em;
 }
 .oo-ui-popupToolGroup.oo-ui-labelElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
-  line-height: 1;
+  line-height: 1.28571429em;
 }
 .oo-ui-toolbar-narrow .oo-ui-popupToolGroup.oo-ui-labelElement .oo-ui-popupToolGroup-handle {
   padding-left: 0.71428571em;
   box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.25);
 }
 .oo-ui-popupToolGroup-tools .oo-ui-tool-link {
-  padding: 1em 0.85714286em;
+  padding: 0.85714286em 0.85714286em;
 }
 .oo-ui-toolbar-narrow .oo-ui-popupToolGroup-tools .oo-ui-tool-link {
   padding-left: 0.71428571em;
   padding-right: 0.71428571em;
 }
-.oo-ui-popupToolGroup-tools .oo-ui-tool-link .oo-ui-tool-title {
-  color: #222;
-}
 .oo-ui-popupToolGroup-tools .oo-ui-tool-link .oo-ui-tool-accel {
   color: #72777d;
-  line-height: 1;
+  line-height: 1.28571429em;
 }
 .oo-ui-popupToolGroup-tools .oo-ui-tool-link .oo-ui-tool-accel:not( :empty ) {
   padding-left: 1.28571429em;
   outline: 0;
   box-shadow: inset 0 0 0 2px #36c;
 }
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-progressive > .oo-ui-popupToolGroup-handle {
+  color: #36c;
+}
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-progressive > .oo-ui-popupToolGroup-handle:hover {
+  background-color: #fff;
+}
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-progressive > .oo-ui-popupToolGroup-handle:active,
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-progressive > .oo-ui-popupToolGroup-handle:active:focus,
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-progressive.oo-ui-tool-active > .oo-ui-popupToolGroup-handle,
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-progressive.oo-ui-popupToolGroup-active > .oo-ui-popupToolGroup-handle {
+  background-color: #eff3fa;
+  color: #2a4b8d;
+  box-shadow: none;
+}
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-progressive > .oo-ui-popupToolGroup-handle:focus {
+  outline: 1px solid #36c;
+  box-shadow: inset 0 0 0 1px #36c;
+}
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-destructive > .oo-ui-popupToolGroup-handle {
+  color: #d73333;
+}
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-destructive > .oo-ui-popupToolGroup-handle:hover {
+  background-color: #fff;
+}
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-destructive > .oo-ui-popupToolGroup-handle:active,
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-destructive > .oo-ui-popupToolGroup-handle:active:focus,
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-destructive.oo-ui-tool-active > .oo-ui-popupToolGroup-handle,
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-destructive.oo-ui-popupToolGroup-active > .oo-ui-popupToolGroup-handle {
+  background-color: #ffffff;
+  color: #b32424;
+  box-shadow: none;
+}
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-destructive > .oo-ui-popupToolGroup-handle:focus {
+  outline: 1px solid #d33;
+  box-shadow: inset 0 0 0 1px #d33;
+}
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-popupToolGroup-handle {
+  color: #fff;
+  background-color: #36c;
+}
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-popupToolGroup-handle:hover {
+  background-color: #447ff5;
+}
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-popupToolGroup-handle:active,
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-popupToolGroup-handle:active:focus,
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-tool-active > .oo-ui-popupToolGroup-handle {
+  color: #fff;
+  background-color: #2a4b8d;
+  box-shadow: none;
+}
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-popupToolGroup-handle:focus {
+  outline: 1px solid #36c;
+  box-shadow: inset 0 0 0 1px #36c, inset 0 0 0 2px #fff;
+}
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-widget-disabled > .oo-ui-popupToolGroup-handle,
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-widget-disabled > .oo-ui-popupToolGroup-handle:active,
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-widget-disabled > .oo-ui-popupToolGroup-handle:active:focus {
+  background-color: #c8ccd1;
+  color: #fff;
+}
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-popupToolGroup-handle {
+  color: #fff;
+  background-color: #d33;
+}
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-popupToolGroup-handle:hover {
+  background-color: #ff4242;
+}
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-popupToolGroup-handle:active,
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-popupToolGroup-handle:active:focus,
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-tool-active > .oo-ui-popupToolGroup-handle {
+  color: #fff;
+  background-color: #b32424;
+  box-shadow: none;
+}
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-popupToolGroup-handle:focus {
+  outline: 1px solid #d33;
+  box-shadow: inset 0 0 0 1px #d33, inset 0 0 0 2px #fff;
+}
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-widget-disabled > .oo-ui-popupToolGroup-handle,
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-widget-disabled > .oo-ui-popupToolGroup-handle:active,
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-widget-disabled > .oo-ui-popupToolGroup-handle:active:focus {
+  background-color: #c8ccd1;
+  color: #fff;
+}
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-primary > .oo-ui-popupToolGroup-handle > .oo-ui-iconElement-icon,
+.oo-ui-popupToolGroup.oo-ui-flaggedElement-primary > .oo-ui-popupToolGroup-handle > .oo-ui-indicatorElement-indicator {
+  opacity: 1;
+}
 
 .oo-ui-listToolGroup-tools .oo-ui-tool {
   display: block;
   box-shadow: inset 0 0 0 2px #36c, inset 0 0 0 3px #fff;
 }
 .oo-ui-toolbar-actions > .oo-ui-buttonElement.oo-ui-labelElement > .oo-ui-buttonElement-button {
-  padding-top: 1em;
-  padding-bottom: 1em;
+  padding-top: 0.85714286em;
+  padding-bottom: 0.85714286em;
 }
 .oo-ui-toolbar-actions > .oo-ui-buttonGroupWidget > .oo-ui-buttonElement > .oo-ui-buttonElement-button {
   border-radius: 0;
   border-width: 0 0 0 1px;
-  padding-top: 1em;
-  padding-bottom: 1em;
+  padding-top: 0.85714286em;
+  padding-bottom: 0.85714286em;
 }
 .oo-ui-toolbar-actions > .oo-ui-buttonGroupWidget > .oo-ui-popupToolGroup.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-popupToolGroup-handle {
   color: #fff;
   background-color: #36c;
-  border-color: #36c;
 }
 .oo-ui-toolbar-actions > .oo-ui-buttonGroupWidget > .oo-ui-popupToolGroup.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-popupToolGroup-handle:hover {
   background-color: #447ff5;
-  border-color: #447ff5;
 }
 .oo-ui-toolbar-actions > .oo-ui-buttonGroupWidget > .oo-ui-popupToolGroup.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-popupToolGroup-handle:active,
 .oo-ui-toolbar-actions > .oo-ui-buttonGroupWidget > .oo-ui-popupToolGroup.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-popupToolGroup-handle:active:focus,
-.oo-ui-toolbar-actions > .oo-ui-buttonGroupWidget > .oo-ui-popupToolGroup.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-buttonElement-pressed > .oo-ui-popupToolGroup-handle,
-.oo-ui-toolbar-actions > .oo-ui-buttonGroupWidget > .oo-ui-popupToolGroup.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-buttonElement-active > .oo-ui-popupToolGroup-handle,
-.oo-ui-toolbar-actions > .oo-ui-buttonGroupWidget > .oo-ui-popupToolGroup.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-popupToolGroup-active > .oo-ui-popupToolGroup-handle {
+.oo-ui-toolbar-actions > .oo-ui-buttonGroupWidget > .oo-ui-popupToolGroup.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-tool-active > .oo-ui-popupToolGroup-handle {
   color: #fff;
   background-color: #2a4b8d;
-  border-color: #2a4b8d;
   box-shadow: none;
 }
 .oo-ui-toolbar-actions > .oo-ui-buttonGroupWidget > .oo-ui-popupToolGroup.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-popupToolGroup-handle:focus {
-  border-color: #36c;
+  outline: 1px solid #36c;
   box-shadow: inset 0 0 0 1px #36c, inset 0 0 0 2px #fff;
 }
+.oo-ui-toolbar-actions > .oo-ui-buttonGroupWidget > .oo-ui-popupToolGroup.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-widget-disabled > .oo-ui-popupToolGroup-handle,
+.oo-ui-toolbar-actions > .oo-ui-buttonGroupWidget > .oo-ui-popupToolGroup.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-widget-disabled > .oo-ui-popupToolGroup-handle:active,
+.oo-ui-toolbar-actions > .oo-ui-buttonGroupWidget > .oo-ui-popupToolGroup.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-widget-disabled > .oo-ui-popupToolGroup-handle:active:focus {
+  background-color: #c8ccd1;
+  color: #fff;
+}
index 72e4bab..780d1fd 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOUI v0.31.0
+ * OOUI v0.31.6
  * https://www.mediawiki.org/wiki/OOUI
  *
  * Copyright 2011–2019 OOUI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2019-03-14T00:52:20Z
+ * Date: 2019-05-08T10:08:36Z
  */
 ( function ( OO ) {
 
@@ -405,7 +405,7 @@ OO.ui.Toolbar.prototype.getToolGroupFactory = function () {
  *
  * @private
  * @param {jQuery.Event} e Mouse down event
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.Toolbar.prototype.onPointerDown = function ( e ) {
        var $closestWidgetToEvent = $( e.target ).closest( '.oo-ui-widget' ),
@@ -934,6 +934,18 @@ OO.ui.Tool.prototype.updateTitle = function () {
        }
 };
 
+/**
+ * @inheritdoc OO.ui.mixin.IconElement
+ */
+OO.ui.Tool.prototype.setIcon = function ( icon ) {
+       // Mixin method
+       OO.ui.mixin.IconElement.prototype.setIcon.call( this, icon );
+
+       this.$element.toggleClass( 'oo-ui-tool-with-icon', !!this.icon );
+
+       return this;
+};
+
 /**
  * Destroy tool.
  *
@@ -1143,7 +1155,7 @@ OO.ui.ToolGroup.prototype.onDisable = function ( isDisabled ) {
  *
  * @protected
  * @param {jQuery.Event} e Mouse down or key down event
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.ToolGroup.prototype.onMouseKeyDown = function ( e ) {
        if (
@@ -2119,7 +2131,7 @@ OO.ui.PopupToolGroup.prototype.onMouseKeyDown = function ( e ) {
  *
  * @protected
  * @param {jQuery.Event} e Mouse up or key up event
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.PopupToolGroup.prototype.onHandleMouseKeyUp = function ( e ) {
        if (
@@ -2138,7 +2150,7 @@ OO.ui.PopupToolGroup.prototype.onHandleMouseKeyUp = function ( e ) {
  *
  * @protected
  * @param {jQuery.Event} e Mouse down or key down event
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.PopupToolGroup.prototype.onHandleMouseKeyDown = function ( e ) {
        var $focusable;
index 7146465..196301f 100644 (file)
@@ -1 +1 @@
-{"version":3,"sources":["../src/intro.js.txt","../src/Toolbar.js","../src/Tool.js","../src/ToolGroup.js","../src/ToolFactory.js","../src/ToolGroupFactory.js","../src/tools/PopupTool.js","../src/tools/ToolGroupTool.js","../src/toolgroups/BarToolGroup.js","../src/toolgroups/PopupToolGroup.js","../src/toolgroups/ListToolGroup.js","../src/toolgroups/MenuToolGroup.js","../src/outro.js.txt"],"names":[],"mappings":"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","file":"oojs-ui-toolbars.js","sourcesContent":["( function ( OO ) {\n\n'use strict';\n","/**\n * Toolbars are complex interface components that permit users to easily access a variety\n * of {@link OO.ui.Tool tools} (e.g., formatting commands) and actions, which are additional\n * commands that are part of the toolbar, but not configured as tools.\n *\n * Individual tools are customized and then registered with a\n * {@link OO.ui.ToolFactory tool factory}, which creates the tools on demand. Each tool has a\n * symbolic name (used when registering the tool), a title (e.g., ‘Insert image’), and an icon.\n *\n * Individual tools are organized in {@link OO.ui.ToolGroup toolgroups}, which can be\n * {@link OO.ui.MenuToolGroup menus} of tools, {@link OO.ui.ListToolGroup lists} of tools, or a\n * single {@link OO.ui.BarToolGroup bar} of tools. The arrangement and order of the toolgroups is\n * customized when the toolbar is set up. Tools can be presented in any order, but each can only\n * appear once in the toolbar.\n *\n * The toolbar can be synchronized with the state of the external \"application\", like a text\n * editor's editing area, marking tools as active/inactive (e.g. a 'bold' tool would be shown as\n * active when the text cursor was inside bolded text) or enabled/disabled (e.g. a table caption\n * tool would be disabled while the user is not editing a table). A state change is signalled by\n * emitting the {@link #event-updateState 'updateState' event}, which calls Tools'\n * {@link OO.ui.Tool#onUpdateState onUpdateState method}.\n *\n * The following is an example of a basic toolbar.\n *\n *     @example\n *     // Example of a toolbar\n *     // Create the toolbar\n *     var toolFactory = new OO.ui.ToolFactory();\n *     var toolGroupFactory = new OO.ui.ToolGroupFactory();\n *     var toolbar = new OO.ui.Toolbar( toolFactory, toolGroupFactory );\n *\n *     // We will be placing status text in this element when tools are used\n *     var $area = $( '<p>' ).text( 'Toolbar example' );\n *\n *     // Define the tools that we're going to place in our toolbar\n *\n *     // Create a class inheriting from OO.ui.Tool\n *     function SearchTool() {\n *         SearchTool.parent.apply( this, arguments );\n *     }\n *     OO.inheritClass( SearchTool, OO.ui.Tool );\n *     // Each tool must have a 'name' (used as an internal identifier, see later) and at least one\n *     // of 'icon' and 'title' (displayed icon and text).\n *     SearchTool.static.name = 'search';\n *     SearchTool.static.icon = 'search';\n *     SearchTool.static.title = 'Search...';\n *     // Defines the action that will happen when this tool is selected (clicked).\n *     SearchTool.prototype.onSelect = function () {\n *         $area.text( 'Search tool clicked!' );\n *         // Never display this tool as \"active\" (selected).\n *         this.setActive( false );\n *     };\n *     SearchTool.prototype.onUpdateState = function () {};\n *     // Make this tool available in our toolFactory and thus our toolbar\n *     toolFactory.register( SearchTool );\n *\n *     // Register two more tools, nothing interesting here\n *     function SettingsTool() {\n *         SettingsTool.parent.apply( this, arguments );\n *     }\n *     OO.inheritClass( SettingsTool, OO.ui.Tool );\n *     SettingsTool.static.name = 'settings';\n *     SettingsTool.static.icon = 'settings';\n *     SettingsTool.static.title = 'Change settings';\n *     SettingsTool.prototype.onSelect = function () {\n *         $area.text( 'Settings tool clicked!' );\n *         this.setActive( false );\n *     };\n *     SettingsTool.prototype.onUpdateState = function () {};\n *     toolFactory.register( SettingsTool );\n *\n *     // Register two more tools, nothing interesting here\n *     function StuffTool() {\n *         StuffTool.parent.apply( this, arguments );\n *     }\n *     OO.inheritClass( StuffTool, OO.ui.Tool );\n *     StuffTool.static.name = 'stuff';\n *     StuffTool.static.icon = 'ellipsis';\n *     StuffTool.static.title = 'More stuff';\n *     StuffTool.prototype.onSelect = function () {\n *         $area.text( 'More stuff tool clicked!' );\n *         this.setActive( false );\n *     };\n *     StuffTool.prototype.onUpdateState = function () {};\n *     toolFactory.register( StuffTool );\n *\n *     // This is a PopupTool. Rather than having a custom 'onSelect' action, it will display a\n *     // little popup window (a PopupWidget).\n *     function HelpTool( toolGroup, config ) {\n *         OO.ui.PopupTool.call( this, toolGroup, $.extend( { popup: {\n *             padded: true,\n *             label: 'Help',\n *             head: true\n *         } }, config ) );\n *         this.popup.$body.append( '<p>I am helpful!</p>' );\n *     }\n *     OO.inheritClass( HelpTool, OO.ui.PopupTool );\n *     HelpTool.static.name = 'help';\n *     HelpTool.static.icon = 'help';\n *     HelpTool.static.title = 'Help';\n *     toolFactory.register( HelpTool );\n *\n *     // Finally define which tools and in what order appear in the toolbar. Each tool may only be\n *     // used once (but not all defined tools must be used).\n *     toolbar.setup( [\n *         {\n *             // 'bar' tool groups display tools' icons only, side-by-side.\n *             type: 'bar',\n *             include: [ 'search', 'help' ]\n *         },\n *         {\n *             // 'list' tool groups display both the titles and icons, in a dropdown list.\n *             type: 'list',\n *             indicator: 'down',\n *             label: 'More',\n *             include: [ 'settings', 'stuff' ]\n *         }\n *         // Note how the tools themselves are toolgroup-agnostic - the same tool can be displayed\n *         // either in a 'list' or a 'bar'. There is a 'menu' tool group too, not showcased here,\n *         // since it's more complicated to use. (See the next example snippet on this page.)\n *     ] );\n *\n *     // Create some UI around the toolbar and place it in the document\n *     var frame = new OO.ui.PanelLayout( {\n *         expanded: false,\n *         framed: true\n *     } );\n *     var contentFrame = new OO.ui.PanelLayout( {\n *         expanded: false,\n *         padded: true\n *     } );\n *     frame.$element.append(\n *         toolbar.$element,\n *         contentFrame.$element.append( $area )\n *     );\n *     $( document.body ).append( frame.$element );\n *\n *     // Here is where the toolbar is actually built. This must be done after inserting it into the\n *     // document.\n *     toolbar.initialize();\n *     toolbar.emit( 'updateState' );\n *\n * The following example extends the previous one to illustrate 'menu' toolgroups and the usage of\n * {@link #event-updateState 'updateState' event}.\n *\n *     @example\n *     // Create the toolbar\n *     var toolFactory = new OO.ui.ToolFactory();\n *     var toolGroupFactory = new OO.ui.ToolGroupFactory();\n *     var toolbar = new OO.ui.Toolbar( toolFactory, toolGroupFactory );\n *\n *     // We will be placing status text in this element when tools are used\n *     var $area = $( '<p>' ).text( 'Toolbar example' );\n *\n *     // Define the tools that we're going to place in our toolbar\n *\n *     // Create a class inheriting from OO.ui.Tool\n *     function SearchTool() {\n *         SearchTool.parent.apply( this, arguments );\n *     }\n *     OO.inheritClass( SearchTool, OO.ui.Tool );\n *     // Each tool must have a 'name' (used as an internal identifier, see later) and at least one\n *     // of 'icon' and 'title' (displayed icon and text).\n *     SearchTool.static.name = 'search';\n *     SearchTool.static.icon = 'search';\n *     SearchTool.static.title = 'Search...';\n *     // Defines the action that will happen when this tool is selected (clicked).\n *     SearchTool.prototype.onSelect = function () {\n *         $area.text( 'Search tool clicked!' );\n *         // Never display this tool as \"active\" (selected).\n *         this.setActive( false );\n *     };\n *     SearchTool.prototype.onUpdateState = function () {};\n *     // Make this tool available in our toolFactory and thus our toolbar\n *     toolFactory.register( SearchTool );\n *\n *     // Register two more tools, nothing interesting here\n *     function SettingsTool() {\n *         SettingsTool.parent.apply( this, arguments );\n *         this.reallyActive = false;\n *     }\n *     OO.inheritClass( SettingsTool, OO.ui.Tool );\n *     SettingsTool.static.name = 'settings';\n *     SettingsTool.static.icon = 'settings';\n *     SettingsTool.static.title = 'Change settings';\n *     SettingsTool.prototype.onSelect = function () {\n *         $area.text( 'Settings tool clicked!' );\n *         // Toggle the active state on each click\n *         this.reallyActive = !this.reallyActive;\n *         this.setActive( this.reallyActive );\n *         // To update the menu label\n *         this.toolbar.emit( 'updateState' );\n *     };\n *     SettingsTool.prototype.onUpdateState = function () {};\n *     toolFactory.register( SettingsTool );\n *\n *     // Register two more tools, nothing interesting here\n *     function StuffTool() {\n *         StuffTool.parent.apply( this, arguments );\n *         this.reallyActive = false;\n *     }\n *     OO.inheritClass( StuffTool, OO.ui.Tool );\n *     StuffTool.static.name = 'stuff';\n *     StuffTool.static.icon = 'ellipsis';\n *     StuffTool.static.title = 'More stuff';\n *     StuffTool.prototype.onSelect = function () {\n *         $area.text( 'More stuff tool clicked!' );\n *         // Toggle the active state on each click\n *         this.reallyActive = !this.reallyActive;\n *         this.setActive( this.reallyActive );\n *         // To update the menu label\n *         this.toolbar.emit( 'updateState' );\n *     };\n *     StuffTool.prototype.onUpdateState = function () {};\n *     toolFactory.register( StuffTool );\n *\n *     // This is a PopupTool. Rather than having a custom 'onSelect' action, it will display a\n *     // little popup window (a PopupWidget). 'onUpdateState' is also already implemented.\n *     function HelpTool( toolGroup, config ) {\n *         OO.ui.PopupTool.call( this, toolGroup, $.extend( { popup: {\n *             padded: true,\n *             label: 'Help',\n *             head: true\n *         } }, config ) );\n *         this.popup.$body.append( '<p>I am helpful!</p>' );\n *     }\n *     OO.inheritClass( HelpTool, OO.ui.PopupTool );\n *     HelpTool.static.name = 'help';\n *     HelpTool.static.icon = 'help';\n *     HelpTool.static.title = 'Help';\n *     toolFactory.register( HelpTool );\n *\n *     // Finally define which tools and in what order appear in the toolbar. Each tool may only be\n *     // used once (but not all defined tools must be used).\n *     toolbar.setup( [\n *         {\n *             // 'bar' tool groups display tools' icons only, side-by-side.\n *             type: 'bar',\n *             include: [ 'search', 'help' ]\n *         },\n *         {\n *             // 'menu' tool groups display both the titles and icons, in a dropdown menu.\n *             // Menu label indicates which items are selected.\n *             type: 'menu',\n *             indicator: 'down',\n *             include: [ 'settings', 'stuff' ]\n *         }\n *     ] );\n *\n *     // Create some UI around the toolbar and place it in the document\n *     var frame = new OO.ui.PanelLayout( {\n *         expanded: false,\n *         framed: true\n *     } );\n *     var contentFrame = new OO.ui.PanelLayout( {\n *         expanded: false,\n *         padded: true\n *     } );\n *     frame.$element.append(\n *         toolbar.$element,\n *         contentFrame.$element.append( $area )\n *     );\n *     $( document.body ).append( frame.$element );\n *\n *     // Here is where the toolbar is actually built. This must be done after inserting it into the\n *     // document.\n *     toolbar.initialize();\n *     toolbar.emit( 'updateState' );\n *\n * @class\n * @extends OO.ui.Element\n * @mixins OO.EventEmitter\n * @mixins OO.ui.mixin.GroupElement\n *\n * @constructor\n * @param {OO.ui.ToolFactory} toolFactory Factory for creating tools\n * @param {OO.ui.ToolGroupFactory} toolGroupFactory Factory for creating toolgroups\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [actions] Add an actions section to the toolbar. Actions are commands that are\n *  included in the toolbar, but are not configured as tools. By default, actions are displayed on\n *  the right side of the toolbar.\n * @cfg {string} [position='top'] Whether the toolbar is positioned above ('top') or below\n *  ('bottom') content.\n * @cfg {jQuery} [$overlay] An overlay for the popup.\n *  See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.\n */\nOO.ui.Toolbar = function OoUiToolbar( toolFactory, toolGroupFactory, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( toolFactory ) && config === undefined ) {\n\t\tconfig = toolFactory;\n\t\ttoolFactory = config.toolFactory;\n\t\ttoolGroupFactory = config.toolGroupFactory;\n\t}\n\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.Toolbar.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.EventEmitter.call( this );\n\tOO.ui.mixin.GroupElement.call( this, config );\n\n\t// Properties\n\tthis.toolFactory = toolFactory;\n\tthis.toolGroupFactory = toolGroupFactory;\n\tthis.groupsByName = {};\n\tthis.activeToolGroups = 0;\n\tthis.tools = {};\n\tthis.position = config.position || 'top';\n\tthis.$bar = $( '<div>' );\n\tthis.$actions = $( '<div>' );\n\tthis.$popups = $( '<div>' );\n\tthis.initialized = false;\n\tthis.narrowThreshold = null;\n\tthis.onWindowResizeHandler = this.onWindowResize.bind( this );\n\tthis.$overlay = ( config.$overlay === true ? OO.ui.getDefaultOverlay() : config.$overlay ) ||\n\t\tthis.$element;\n\n\t// Events\n\tthis.$element\n\t\t.add( this.$bar ).add( this.$group ).add( this.$actions )\n\t\t.on( 'mousedown keydown', this.onPointerDown.bind( this ) );\n\n\t// Initialization\n\tthis.$group.addClass( 'oo-ui-toolbar-tools' );\n\tif ( config.actions ) {\n\t\tthis.$bar.append( this.$actions.addClass( 'oo-ui-toolbar-actions' ) );\n\t}\n\tthis.$popups.addClass( 'oo-ui-toolbar-popups' );\n\tthis.$bar\n\t\t.addClass( 'oo-ui-toolbar-bar' )\n\t\t.append( this.$group, '<div style=\"clear:both\"></div>' );\n\t// Possible classes: oo-ui-toolbar-position-top, oo-ui-toolbar-position-bottom\n\tthis.$element\n\t\t.addClass( 'oo-ui-toolbar oo-ui-toolbar-position-' + this.position )\n\t\t.append( this.$bar );\n\tthis.$overlay.append( this.$popups );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.Toolbar, OO.ui.Element );\nOO.mixinClass( OO.ui.Toolbar, OO.EventEmitter );\nOO.mixinClass( OO.ui.Toolbar, OO.ui.mixin.GroupElement );\n\n/* Events */\n\n/**\n * @event updateState\n *\n * An 'updateState' event must be emitted on the Toolbar (by calling\n * `toolbar.emit( 'updateState' )`) every time the state of the application using the toolbar\n * changes, and an update to the state of tools is required.\n *\n * @param {...Mixed} data Application-defined parameters\n */\n\n/**\n * @event active\n *\n * An 'active' event is emitted when the number of active toolgroups increases from 0, or\n * returns to 0.\n *\n * @param {boolean} There are active toolgroups in this toolbar\n */\n\n/* Methods */\n\n/**\n * Get the tool factory.\n *\n * @return {OO.ui.ToolFactory} Tool factory\n */\nOO.ui.Toolbar.prototype.getToolFactory = function () {\n\treturn this.toolFactory;\n};\n\n/**\n * Get the toolgroup factory.\n *\n * @return {OO.Factory} Toolgroup factory\n */\nOO.ui.Toolbar.prototype.getToolGroupFactory = function () {\n\treturn this.toolGroupFactory;\n};\n\n/**\n * Handles mouse down events.\n *\n * @private\n * @param {jQuery.Event} e Mouse down event\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.Toolbar.prototype.onPointerDown = function ( e ) {\n\tvar $closestWidgetToEvent = $( e.target ).closest( '.oo-ui-widget' ),\n\t\t$closestWidgetToToolbar = this.$element.closest( '.oo-ui-widget' );\n\tif (\n\t\t!$closestWidgetToEvent.length ||\n\t\t$closestWidgetToEvent[ 0 ] ===\n\t\t$closestWidgetToToolbar[ 0 ]\n\t) {\n\t\treturn false;\n\t}\n};\n\n/**\n * Handle window resize event.\n *\n * @private\n * @param {jQuery.Event} e Window resize event\n */\nOO.ui.Toolbar.prototype.onWindowResize = function () {\n\tthis.$element.add( this.$popups ).toggleClass(\n\t\t'oo-ui-toolbar-narrow',\n\t\tthis.$bar[ 0 ].clientWidth <= this.getNarrowThreshold()\n\t);\n};\n\n/**\n * Get the (lazily-computed) width threshold for applying the oo-ui-toolbar-narrow\n * class.\n *\n * @private\n * @return {number} Width threshold in pixels\n */\nOO.ui.Toolbar.prototype.getNarrowThreshold = function () {\n\tif ( this.narrowThreshold === null ) {\n\t\tthis.narrowThreshold = this.$group[ 0 ].offsetWidth + this.$actions[ 0 ].offsetWidth;\n\t}\n\treturn this.narrowThreshold;\n};\n\n/**\n * Sets up handles and preloads required information for the toolbar to work.\n * This must be called after it is attached to a visible document and before doing anything else.\n */\nOO.ui.Toolbar.prototype.initialize = function () {\n\tif ( !this.initialized ) {\n\t\tthis.initialized = true;\n\t\t$( this.getElementWindow() ).on( 'resize', this.onWindowResizeHandler );\n\t\tthis.onWindowResize();\n\t}\n};\n\n/**\n * Set up the toolbar.\n *\n * The toolbar is set up with a list of toolgroup configurations that specify the type of\n * toolgroup ({@link OO.ui.BarToolGroup bar}, {@link OO.ui.MenuToolGroup menu}, or\n * {@link OO.ui.ListToolGroup list}) to add and which tools to include, exclude, promote, or demote\n * within that toolgroup. Please see {@link OO.ui.ToolGroup toolgroups} for more information about\n * including tools in toolgroups.\n *\n * @param {Object.<string,Array>} groups List of toolgroup configurations\n * @param {string} [groups.name] Symbolic name for this toolgroup\n * @param {string} [groups.type] Toolgroup type, should exist in the toolgroup factory\n * @param {Array|string} [groups.include] Tools to include in the toolgroup\n * @param {Array|string} [groups.exclude] Tools to exclude from the toolgroup\n * @param {Array|string} [groups.promote] Tools to promote to the beginning of the toolgroup\n * @param {Array|string} [groups.demote] Tools to demote to the end of the toolgroup\n */\nOO.ui.Toolbar.prototype.setup = function ( groups ) {\n\tvar i, len, type, toolGroup, groupConfig,\n\t\titems = [],\n\t\tdefaultType = 'bar';\n\n\t// Cleanup previous groups\n\tthis.reset();\n\n\t// Build out new groups\n\tfor ( i = 0, len = groups.length; i < len; i++ ) {\n\t\tgroupConfig = groups[ i ];\n\t\tif ( groupConfig.include === '*' ) {\n\t\t\t// Apply defaults to catch-all groups\n\t\t\tif ( groupConfig.type === undefined ) {\n\t\t\t\tgroupConfig.type = 'list';\n\t\t\t}\n\t\t\tif ( groupConfig.label === undefined ) {\n\t\t\t\tgroupConfig.label = OO.ui.msg( 'ooui-toolbar-more' );\n\t\t\t}\n\t\t}\n\t\t// Check type has been registered\n\t\ttype = this.getToolGroupFactory().lookup( groupConfig.type ) ?\n\t\t\tgroupConfig.type : defaultType;\n\t\ttoolGroup = this.getToolGroupFactory().create( type, this, groupConfig );\n\t\titems.push( toolGroup );\n\t\tif ( groupConfig.name ) {\n\t\t\tthis.groupsByName[ groupConfig.name ] = toolGroup;\n\t\t} else {\n\t\t\t// Groups without name are deprecated\n\t\t\tOO.ui.warnDeprecation( 'Toolgroups must have a \\'name\\' property' );\n\t\t}\n\t\ttoolGroup.connect( this, {\n\t\t\tactive: 'onToolGroupActive'\n\t\t} );\n\t}\n\tthis.addItems( items );\n};\n\n/**\n * Handle active events from tool groups\n *\n * @param {boolean} active Tool group has become active, inactive if false\n * @fires active\n */\nOO.ui.Toolbar.prototype.onToolGroupActive = function ( active ) {\n\tif ( active ) {\n\t\tthis.activeToolGroups++;\n\t\tif ( this.activeToolGroups === 1 ) {\n\t\t\tthis.emit( 'active', true );\n\t\t}\n\t} else {\n\t\tthis.activeToolGroups--;\n\t\tif ( this.activeToolGroups === 0 ) {\n\t\t\tthis.emit( 'active', false );\n\t\t}\n\t}\n};\n\n/**\n * Get a toolgroup by name\n *\n * @param {string} name Group name\n * @return {OO.ui.ToolGroup|null} Tool group, or null if none found by that name\n */\nOO.ui.Toolbar.prototype.getToolGroupByName = function ( name ) {\n\treturn this.groupsByName[ name ] || null;\n};\n\n/**\n * Remove all tools and toolgroups from the toolbar.\n */\nOO.ui.Toolbar.prototype.reset = function () {\n\tvar i, len;\n\n\tthis.groupsByName = {};\n\tthis.tools = {};\n\tfor ( i = 0, len = this.items.length; i < len; i++ ) {\n\t\tthis.items[ i ].destroy();\n\t}\n\tthis.clearItems();\n};\n\n/**\n * Destroy the toolbar.\n *\n * Destroying the toolbar removes all event handlers and DOM elements that constitute the toolbar.\n * Call this method whenever you are done using a toolbar.\n */\nOO.ui.Toolbar.prototype.destroy = function () {\n\t$( this.getElementWindow() ).off( 'resize', this.onWindowResizeHandler );\n\tthis.reset();\n\tthis.$element.remove();\n};\n\n/**\n * Check if the tool is available.\n *\n * Available tools are ones that have not yet been added to the toolbar.\n *\n * @param {string} name Symbolic name of tool\n * @return {boolean} Tool is available\n */\nOO.ui.Toolbar.prototype.isToolAvailable = function ( name ) {\n\treturn !this.tools[ name ];\n};\n\n/**\n * Prevent tool from being used again.\n *\n * @param {OO.ui.Tool} tool Tool to reserve\n */\nOO.ui.Toolbar.prototype.reserveTool = function ( tool ) {\n\tthis.tools[ tool.getName() ] = tool;\n};\n\n/**\n * Allow tool to be used again.\n *\n * @param {OO.ui.Tool} tool Tool to release\n */\nOO.ui.Toolbar.prototype.releaseTool = function ( tool ) {\n\tdelete this.tools[ tool.getName() ];\n};\n\n/**\n * Get accelerator label for tool.\n *\n * The OOUI library does not contain an accelerator system, but this is the hook for one. To\n * use an accelerator system, subclass the toolbar and override this method, which is meant to\n * return a label that describes the accelerator keys for the tool passed (by symbolic name) to\n * the method.\n *\n * @param {string} name Symbolic name of tool\n * @return {string|undefined} Tool accelerator label if available\n */\nOO.ui.Toolbar.prototype.getToolAccelerator = function () {\n\treturn undefined;\n};\n","/**\n * Tools, together with {@link OO.ui.ToolGroup toolgroups}, constitute\n * {@link OO.ui.Toolbar toolbars}.\n * Each tool is configured with a static name, title, and icon and is customized with the command\n * to carry out when the tool is selected. Tools must also be registered with a\n * {@link OO.ui.ToolFactory tool factory}, which creates the tools on demand.\n *\n * Every Tool subclass must implement two methods:\n *\n * - {@link #onUpdateState}\n * - {@link #onSelect}\n *\n * Tools are added to toolgroups ({@link OO.ui.ListToolGroup ListToolGroup},\n * {@link OO.ui.BarToolGroup BarToolGroup}, or {@link OO.ui.MenuToolGroup MenuToolGroup}), which\n * determine how the tool is displayed in the toolbar. See {@link OO.ui.Toolbar toolbars} for an\n * example.\n *\n * For more information, please see the [OOUI documentation on MediaWiki][1].\n * [1]: https://www.mediawiki.org/wiki/OOUI/Toolbars\n *\n * @abstract\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.FlaggedElement\n * @mixins OO.ui.mixin.TabIndexedElement\n *\n * @constructor\n * @param {OO.ui.ToolGroup} toolGroup\n * @param {Object} [config] Configuration options\n * @cfg {string|Function} [title] Title text or a function that returns text. If this config is\n *  omitted, the value of the {@link #static-title static title} property is used.\n *\n *  The title is used in different ways depending on the type of toolgroup that contains the tool.\n *  The title is used as a tooltip if the tool is part of a {@link OO.ui.BarToolGroup bar}\n *  toolgroup, or as the label text if the tool is part of a {@link OO.ui.ListToolGroup list} or\n *  {@link OO.ui.MenuToolGroup menu} toolgroup.\n *\n *  For bar toolgroups, a description of the accelerator key is appended to the title if an\n *  accelerator key is associated with an action by the same name as the tool and accelerator\n *  functionality has been added to the application.\n *  To add accelerator key functionality, you must subclass OO.ui.Toolbar and override the\n *  {@link OO.ui.Toolbar#getToolAccelerator getToolAccelerator} method.\n */\nOO.ui.Tool = function OoUiTool( toolGroup, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( toolGroup ) && config === undefined ) {\n\t\tconfig = toolGroup;\n\t\ttoolGroup = config.toolGroup;\n\t}\n\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.Tool.parent.call( this, config );\n\n\t// Properties\n\tthis.toolGroup = toolGroup;\n\tthis.toolbar = this.toolGroup.getToolbar();\n\tthis.active = false;\n\tthis.$title = $( '<span>' );\n\tthis.$accel = $( '<span>' );\n\tthis.$link = $( '<a>' );\n\tthis.title = null;\n\tthis.checkIcon = new OO.ui.IconWidget( {\n\t\ticon: 'check',\n\t\tclasses: [ 'oo-ui-tool-checkIcon' ]\n\t} );\n\n\t// Mixin constructors\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.FlaggedElement.call( this, config );\n\tOO.ui.mixin.TabIndexedElement.call( this, $.extend( {\n\t\t$tabIndexed: this.$link\n\t}, config ) );\n\n\t// Events\n\tthis.toolbar.connect( this, {\n\t\tupdateState: 'onUpdateState'\n\t} );\n\n\t// Initialization\n\tthis.$title.addClass( 'oo-ui-tool-title' );\n\tthis.$accel\n\t\t.addClass( 'oo-ui-tool-accel' )\n\t\t.prop( {\n\t\t\t// This may need to be changed if the key names are ever localized,\n\t\t\t// but for now they are essentially written in English\n\t\t\tdir: 'ltr',\n\t\t\tlang: 'en'\n\t\t} );\n\tthis.$link\n\t\t.addClass( 'oo-ui-tool-link' )\n\t\t.append( this.checkIcon.$element, this.$icon, this.$title, this.$accel )\n\t\t.attr( 'role', 'button' );\n\tthis.$element\n\t\t.data( 'oo-ui-tool', this )\n\t\t.addClass( 'oo-ui-tool' )\n\t\t.addClass( 'oo-ui-tool-name-' +\n\t\t\tthis.constructor.static.name.replace( /^([^/]+)\\/([^/]+).*$/, '$1-$2' ) )\n\t\t.toggleClass( 'oo-ui-tool-with-label', this.constructor.static.displayBothIconAndLabel )\n\t\t.append( this.$link );\n\tthis.setTitle( config.title || this.constructor.static.title );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.Tool, OO.ui.Widget );\nOO.mixinClass( OO.ui.Tool, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.Tool, OO.ui.mixin.FlaggedElement );\nOO.mixinClass( OO.ui.Tool, OO.ui.mixin.TabIndexedElement );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.Tool.static.tagName = 'span';\n\n/**\n * Symbolic name of tool.\n *\n * The symbolic name is used internally to register the tool with a\n * {@link OO.ui.ToolFactory ToolFactory}. It can also be used when adding tools to toolgroups.\n *\n * @abstract\n * @static\n * @inheritable\n * @property {string}\n */\nOO.ui.Tool.static.name = '';\n\n/**\n * Symbolic name of the group.\n *\n * The group name is used to associate tools with each other so that they can be selected later by\n * a {@link OO.ui.ToolGroup toolgroup}.\n *\n * @abstract\n * @static\n * @inheritable\n * @property {string}\n */\nOO.ui.Tool.static.group = '';\n\n/**\n * Tool title text or a function that returns title text. The value of the static property is\n * overridden if the #title config option is used.\n *\n * @abstract\n * @static\n * @inheritable\n * @property {string|Function}\n */\nOO.ui.Tool.static.title = '';\n\n/**\n * Display both icon and label when the tool is used in a {@link OO.ui.BarToolGroup bar} toolgroup.\n * Normally only the icon is displayed, or only the label if no icon is given.\n *\n * @static\n * @inheritable\n * @property {boolean}\n */\nOO.ui.Tool.static.displayBothIconAndLabel = false;\n\n/**\n * Add tool to catch-all groups automatically.\n *\n * A catch-all group, which contains all tools that do not currently belong to a toolgroup,\n * can be included in a toolgroup using the wildcard selector, an asterisk (*).\n *\n * @static\n * @inheritable\n * @property {boolean}\n */\nOO.ui.Tool.static.autoAddToCatchall = true;\n\n/**\n * Add tool to named groups automatically.\n *\n * By default, tools that are configured with a static ‘group’ property are added\n * to that group and will be selected when the symbolic name of the group is specified (e.g., when\n * toolgroups include tools by group name).\n *\n * @static\n * @property {boolean}\n * @inheritable\n */\nOO.ui.Tool.static.autoAddToGroup = true;\n\n/**\n * Check if this tool is compatible with given data.\n *\n * This is a stub that can be overridden to provide support for filtering tools based on an\n * arbitrary piece of information  (e.g., where the cursor is in a document). The implementation\n * must also call this method so that the compatibility check can be performed.\n *\n * @static\n * @inheritable\n * @param {Mixed} data Data to check\n * @return {boolean} Tool can be used with data\n */\nOO.ui.Tool.static.isCompatibleWith = function () {\n\treturn false;\n};\n\n/* Methods */\n\n/**\n * Handle the toolbar state being updated. This method is called when the\n * {@link OO.ui.Toolbar#event-updateState 'updateState' event} is emitted on the\n * {@link OO.ui.Toolbar Toolbar} that uses this tool, and should set the state of this tool\n * depending on application state (usually by calling #setDisabled to enable or disable the tool,\n * or #setActive to mark is as currently in-use or not).\n *\n * This is an abstract method that must be overridden in a concrete subclass.\n *\n * @method\n * @protected\n * @abstract\n */\nOO.ui.Tool.prototype.onUpdateState = null;\n\n/**\n * Handle the tool being selected. This method is called when the user triggers this tool,\n * usually by clicking on its label/icon.\n *\n * This is an abstract method that must be overridden in a concrete subclass.\n *\n * @method\n * @protected\n * @abstract\n */\nOO.ui.Tool.prototype.onSelect = null;\n\n/**\n * Check if the tool is active.\n *\n * Tools become active when their #onSelect or #onUpdateState handlers change them to appear pressed\n * with the #setActive method. Additional CSS is applied to the tool to reflect the active state.\n *\n * @return {boolean} Tool is active\n */\nOO.ui.Tool.prototype.isActive = function () {\n\treturn this.active;\n};\n\n/**\n * Make the tool appear active or inactive.\n *\n * This method should be called within #onSelect or #onUpdateState event handlers to make the tool\n * appear pressed or not.\n *\n * @param {boolean} state Make tool appear active\n */\nOO.ui.Tool.prototype.setActive = function ( state ) {\n\tthis.active = !!state;\n\tthis.$element.toggleClass( 'oo-ui-tool-active', this.active );\n\tthis.updateThemeClasses();\n};\n\n/**\n * Set the tool #title.\n *\n * @param {string|Function} title Title text or a function that returns text\n * @chainable\n * @return {OO.ui.Tool} The tool, for chaining\n */\nOO.ui.Tool.prototype.setTitle = function ( title ) {\n\tthis.title = OO.ui.resolveMsg( title );\n\tthis.updateTitle();\n\treturn this;\n};\n\n/**\n * Get the tool #title.\n *\n * @return {string} Title text\n */\nOO.ui.Tool.prototype.getTitle = function () {\n\treturn this.title;\n};\n\n/**\n * Get the tool's symbolic name.\n *\n * @return {string} Symbolic name of tool\n */\nOO.ui.Tool.prototype.getName = function () {\n\treturn this.constructor.static.name;\n};\n\n/**\n * Update the title.\n */\nOO.ui.Tool.prototype.updateTitle = function () {\n\tvar titleTooltips = this.toolGroup.constructor.static.titleTooltips,\n\t\taccelTooltips = this.toolGroup.constructor.static.accelTooltips,\n\t\taccel = this.toolbar.getToolAccelerator( this.constructor.static.name ),\n\t\ttooltipParts = [];\n\n\tthis.$title.text( this.title );\n\tthis.$accel.text( accel );\n\n\tif ( titleTooltips && typeof this.title === 'string' && this.title.length ) {\n\t\ttooltipParts.push( this.title );\n\t}\n\tif ( accelTooltips && typeof accel === 'string' && accel.length ) {\n\t\ttooltipParts.push( accel );\n\t}\n\tif ( tooltipParts.length ) {\n\t\tthis.$link.attr( 'title', tooltipParts.join( ' ' ) );\n\t} else {\n\t\tthis.$link.removeAttr( 'title' );\n\t}\n};\n\n/**\n * Destroy tool.\n *\n * Destroying the tool removes all event handlers and the tool’s DOM elements.\n * Call this method whenever you are done using a tool.\n */\nOO.ui.Tool.prototype.destroy = function () {\n\tthis.toolbar.disconnect( this );\n\tthis.$element.remove();\n};\n","/**\n * ToolGroups are collections of {@link OO.ui.Tool tools} that are used in a\n * {@link OO.ui.Toolbar toolbar}.\n * The type of toolgroup ({@link OO.ui.ListToolGroup list}, {@link OO.ui.BarToolGroup bar}, or\n * {@link OO.ui.MenuToolGroup menu}) to which a tool belongs determines how the tool is arranged\n * and displayed in the toolbar. Toolgroups themselves are created on demand with a\n * {@link OO.ui.ToolGroupFactory toolgroup factory}.\n *\n * Toolgroups can contain individual tools, groups of tools, or all available tools, as specified\n * using the `include` config option. See OO.ui.ToolFactory#extract on documentation of the format.\n * The options `exclude`, `promote`, and `demote` support the same formats.\n *\n * See {@link OO.ui.Toolbar toolbars} for a full example. For more information about toolbars in\n * general, please see the [OOUI documentation on MediaWiki][1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Toolbars\n *\n * @abstract\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.GroupElement\n *\n * @constructor\n * @param {OO.ui.Toolbar} toolbar\n * @param {Object} [config] Configuration options\n * @cfg {Array|string} [include] List of tools to include in the toolgroup, see above.\n * @cfg {Array|string} [exclude] List of tools to exclude from the toolgroup, see above.\n * @cfg {Array|string} [promote] List of tools to promote to the beginning of the toolgroup,\n *  see above.\n * @cfg {Array|string} [demote] List of tools to demote to the end of the toolgroup, see above.\n *  This setting is particularly useful when tools have been added to the toolgroup\n *  en masse (e.g., via the catch-all selector).\n */\nOO.ui.ToolGroup = function OoUiToolGroup( toolbar, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( toolbar ) && config === undefined ) {\n\t\tconfig = toolbar;\n\t\ttoolbar = config.toolbar;\n\t}\n\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.ToolGroup.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.GroupElement.call( this, config );\n\n\t// Properties\n\tthis.toolbar = toolbar;\n\tthis.tools = {};\n\tthis.pressed = null;\n\tthis.autoDisabled = false;\n\tthis.include = config.include || [];\n\tthis.exclude = config.exclude || [];\n\tthis.promote = config.promote || [];\n\tthis.demote = config.demote || [];\n\tthis.onDocumentMouseKeyUpHandler = this.onDocumentMouseKeyUp.bind( this );\n\n\t// Events\n\tthis.$group.on( {\n\t\tmousedown: this.onMouseKeyDown.bind( this ),\n\t\tmouseup: this.onMouseKeyUp.bind( this ),\n\t\tkeydown: this.onMouseKeyDown.bind( this ),\n\t\tkeyup: this.onMouseKeyUp.bind( this ),\n\t\tfocus: this.onMouseOverFocus.bind( this ),\n\t\tblur: this.onMouseOutBlur.bind( this ),\n\t\tmouseover: this.onMouseOverFocus.bind( this ),\n\t\tmouseout: this.onMouseOutBlur.bind( this )\n\t} );\n\tthis.toolbar.getToolFactory().connect( this, {\n\t\tregister: 'onToolFactoryRegister'\n\t} );\n\tthis.aggregate( {\n\t\tdisable: 'itemDisable'\n\t} );\n\tthis.connect( this, {\n\t\titemDisable: 'updateDisabled',\n\t\tdisable: 'onDisable'\n\t} );\n\n\t// Initialization\n\tthis.$group.addClass( 'oo-ui-toolGroup-tools' );\n\tthis.$element\n\t\t.addClass( 'oo-ui-toolGroup' )\n\t\t.append( this.$group );\n\tthis.onDisable( this.isDisabled() );\n\tthis.populate();\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ToolGroup, OO.ui.Widget );\nOO.mixinClass( OO.ui.ToolGroup, OO.ui.mixin.GroupElement );\n\n/* Events */\n\n/**\n * @event update\n */\n\n/**\n * @event active\n *\n * An 'active' event is emitted when any popup is shown/hidden.\n *\n * @param {boolean} The popup is visible\n */\n\n/* Static Properties */\n\n/**\n * Show labels in tooltips.\n *\n * @static\n * @inheritable\n * @property {boolean}\n */\nOO.ui.ToolGroup.static.titleTooltips = false;\n\n/**\n * Show acceleration labels in tooltips.\n *\n * Note: The OOUI library does not include an accelerator system, but does contain\n * a hook for one. To use an accelerator system, subclass the {@link OO.ui.Toolbar toolbar} and\n * override the {@link OO.ui.Toolbar#getToolAccelerator getToolAccelerator} method, which is\n * meant to return a label that describes the accelerator keys for a given tool (e.g., Control+M\n * key combination).\n *\n * @static\n * @inheritable\n * @property {boolean}\n */\nOO.ui.ToolGroup.static.accelTooltips = false;\n\n/**\n * Automatically disable the toolgroup when all tools are disabled\n *\n * @static\n * @inheritable\n * @property {boolean}\n */\nOO.ui.ToolGroup.static.autoDisable = true;\n\n/**\n * @abstract\n * @static\n * @inheritable\n * @property {string}\n */\nOO.ui.ToolGroup.static.name = null;\n\n/* Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.ToolGroup.prototype.isDisabled = function () {\n\treturn this.autoDisabled ||\n\t\tOO.ui.ToolGroup.parent.prototype.isDisabled.apply( this, arguments );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.ToolGroup.prototype.updateDisabled = function () {\n\tvar i, item, allDisabled = true;\n\n\tif ( this.constructor.static.autoDisable ) {\n\t\tfor ( i = this.items.length - 1; i >= 0; i-- ) {\n\t\t\titem = this.items[ i ];\n\t\t\tif ( !item.isDisabled() ) {\n\t\t\t\tallDisabled = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tthis.autoDisabled = allDisabled;\n\t}\n\tOO.ui.ToolGroup.parent.prototype.updateDisabled.apply( this, arguments );\n};\n\n/**\n * Handle disable events.\n *\n * @protected\n * @param {boolean} isDisabled\n */\nOO.ui.ToolGroup.prototype.onDisable = function ( isDisabled ) {\n\tthis.$group.toggleClass( 'oo-ui-toolGroup-disabled-tools', isDisabled );\n\tthis.$group.toggleClass( 'oo-ui-toolGroup-enabled-tools', !isDisabled );\n};\n\n/**\n * Handle mouse down and key down events.\n *\n * @protected\n * @param {jQuery.Event} e Mouse down or key down event\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.ToolGroup.prototype.onMouseKeyDown = function ( e ) {\n\tif (\n\t\t!this.isDisabled() && (\n\t\t\te.which === OO.ui.MouseButtons.LEFT ||\n\t\t\te.which === OO.ui.Keys.SPACE ||\n\t\t\te.which === OO.ui.Keys.ENTER\n\t\t)\n\t) {\n\t\tthis.pressed = this.findTargetTool( e );\n\t\tif ( this.pressed ) {\n\t\t\tthis.pressed.setActive( true );\n\t\t\tthis.getElementDocument().addEventListener(\n\t\t\t\t'mouseup',\n\t\t\t\tthis.onDocumentMouseKeyUpHandler,\n\t\t\t\ttrue\n\t\t\t);\n\t\t\tthis.getElementDocument().addEventListener(\n\t\t\t\t'keyup',\n\t\t\t\tthis.onDocumentMouseKeyUpHandler,\n\t\t\t\ttrue\n\t\t\t);\n\t\t\treturn false;\n\t\t}\n\t}\n};\n\n/**\n * Handle document mouse up and key up events.\n *\n * @protected\n * @param {MouseEvent|KeyboardEvent} e Mouse up or key up event\n */\nOO.ui.ToolGroup.prototype.onDocumentMouseKeyUp = function ( e ) {\n\tthis.getElementDocument().removeEventListener(\n\t\t'mouseup',\n\t\tthis.onDocumentMouseKeyUpHandler,\n\t\ttrue\n\t);\n\tthis.getElementDocument().removeEventListener(\n\t\t'keyup',\n\t\tthis.onDocumentMouseKeyUpHandler,\n\t\ttrue\n\t);\n\t// onMouseKeyUp may be called a second time, depending on where the mouse is when the button is\n\t// released, but since `this.pressed` will no longer be true, the second call will be ignored.\n\tthis.onMouseKeyUp( e );\n};\n\n/**\n * Handle mouse up and key up events.\n *\n * @protected\n * @param {MouseEvent|KeyboardEvent} e Mouse up or key up event\n */\nOO.ui.ToolGroup.prototype.onMouseKeyUp = function ( e ) {\n\tvar tool = this.findTargetTool( e );\n\n\tif (\n\t\t!this.isDisabled() && this.pressed && this.pressed === tool && (\n\t\t\te.which === OO.ui.MouseButtons.LEFT ||\n\t\t\te.which === OO.ui.Keys.SPACE ||\n\t\t\te.which === OO.ui.Keys.ENTER\n\t\t)\n\t) {\n\t\tthis.pressed.onSelect();\n\t\tthis.pressed = null;\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t}\n\n\tthis.pressed = null;\n};\n\n/**\n * Handle mouse over and focus events.\n *\n * @protected\n * @param {jQuery.Event} e Mouse over or focus event\n */\nOO.ui.ToolGroup.prototype.onMouseOverFocus = function ( e ) {\n\tvar tool = this.findTargetTool( e );\n\n\tif ( this.pressed && this.pressed === tool ) {\n\t\tthis.pressed.setActive( true );\n\t}\n};\n\n/**\n * Handle mouse out and blur events.\n *\n * @protected\n * @param {jQuery.Event} e Mouse out or blur event\n */\nOO.ui.ToolGroup.prototype.onMouseOutBlur = function ( e ) {\n\tvar tool = this.findTargetTool( e );\n\n\tif ( this.pressed && this.pressed === tool ) {\n\t\tthis.pressed.setActive( false );\n\t}\n};\n\n/**\n * Get the closest tool to a jQuery.Event.\n *\n * Only tool links are considered, which prevents other elements in the tool such as popups from\n * triggering tool group interactions.\n *\n * @private\n * @param {jQuery.Event} e\n * @return {OO.ui.Tool|null} Tool, `null` if none was found\n */\nOO.ui.ToolGroup.prototype.findTargetTool = function ( e ) {\n\tvar tool,\n\t\t$item = $( e.target ).closest( '.oo-ui-tool-link' );\n\n\tif ( $item.length ) {\n\t\ttool = $item.parent().data( 'oo-ui-tool' );\n\t}\n\n\treturn tool && !tool.isDisabled() ? tool : null;\n};\n\n/**\n * Handle tool registry register events.\n *\n * If a tool is registered after the group is created, we must repopulate the list to account for:\n *\n * - a tool being added that may be included\n * - a tool already included being overridden\n *\n * @protected\n * @param {string} name Symbolic name of tool\n */\nOO.ui.ToolGroup.prototype.onToolFactoryRegister = function () {\n\tthis.populate();\n};\n\n/**\n * Get the toolbar that contains the toolgroup.\n *\n * @return {OO.ui.Toolbar} Toolbar that contains the toolgroup\n */\nOO.ui.ToolGroup.prototype.getToolbar = function () {\n\treturn this.toolbar;\n};\n\n/**\n * Add and remove tools based on configuration.\n */\nOO.ui.ToolGroup.prototype.populate = function () {\n\tvar i, len, name, tool,\n\t\ttoolFactory = this.toolbar.getToolFactory(),\n\t\tnames = {},\n\t\tadd = [],\n\t\tremove = [],\n\t\tlist = this.toolbar.getToolFactory().getTools(\n\t\t\tthis.include, this.exclude, this.promote, this.demote\n\t\t);\n\n\t// Build a list of needed tools\n\tfor ( i = 0, len = list.length; i < len; i++ ) {\n\t\tname = list[ i ];\n\t\tif (\n\t\t\t// Tool exists\n\t\t\ttoolFactory.lookup( name ) &&\n\t\t\t// Tool is available or is already in this group\n\t\t\t( this.toolbar.isToolAvailable( name ) || this.tools[ name ] )\n\t\t) {\n\t\t\t// Hack to prevent infinite recursion via ToolGroupTool. We need to reserve the tool\n\t\t\t// before creating it, but we can't call reserveTool() yet because we haven't created\n\t\t\t// the tool.\n\t\t\tthis.toolbar.tools[ name ] = true;\n\t\t\ttool = this.tools[ name ];\n\t\t\tif ( !tool ) {\n\t\t\t\t// Auto-initialize tools on first use\n\t\t\t\tthis.tools[ name ] = tool = toolFactory.create( name, this );\n\t\t\t\ttool.updateTitle();\n\t\t\t}\n\t\t\tthis.toolbar.reserveTool( tool );\n\t\t\tadd.push( tool );\n\t\t\tnames[ name ] = true;\n\t\t}\n\t}\n\t// Remove tools that are no longer needed\n\tfor ( name in this.tools ) {\n\t\tif ( !names[ name ] ) {\n\t\t\tthis.tools[ name ].destroy();\n\t\t\tthis.toolbar.releaseTool( this.tools[ name ] );\n\t\t\tremove.push( this.tools[ name ] );\n\t\t\tdelete this.tools[ name ];\n\t\t}\n\t}\n\tif ( remove.length ) {\n\t\tthis.removeItems( remove );\n\t}\n\t// Update emptiness state\n\tif ( add.length ) {\n\t\tthis.$element.removeClass( 'oo-ui-toolGroup-empty' );\n\t} else {\n\t\tthis.$element.addClass( 'oo-ui-toolGroup-empty' );\n\t}\n\t// Re-add tools (moving existing ones to new locations)\n\tthis.addItems( add );\n\t// Disabled state may depend on items\n\tthis.updateDisabled();\n};\n\n/**\n * Destroy toolgroup.\n */\nOO.ui.ToolGroup.prototype.destroy = function () {\n\tvar name;\n\n\tthis.clearItems();\n\tthis.toolbar.getToolFactory().disconnect( this );\n\tfor ( name in this.tools ) {\n\t\tthis.toolbar.releaseTool( this.tools[ name ] );\n\t\tthis.tools[ name ].disconnect( this ).destroy();\n\t\tdelete this.tools[ name ];\n\t}\n\tthis.$element.remove();\n};\n","/**\n * A ToolFactory creates tools on demand. All tools ({@link OO.ui.Tool Tools},\n * {@link OO.ui.PopupTool PopupTools}, and {@link OO.ui.ToolGroupTool ToolGroupTools}) must be\n * registered with a tool factory. Tools are registered by their symbolic name. See\n * {@link OO.ui.Toolbar toolbars} for an example.\n *\n * For more information about toolbars in general, please see the\n * [OOUI documentation on MediaWiki][1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Toolbars\n *\n * @class\n * @extends OO.Factory\n * @constructor\n */\nOO.ui.ToolFactory = function OoUiToolFactory() {\n\t// Parent constructor\n\tOO.ui.ToolFactory.parent.call( this );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ToolFactory, OO.Factory );\n\n/* Methods */\n\n/**\n * Get tools from the factory.\n *\n * @param {Array|string} [include] Included tools, see #extract for format\n * @param {Array|string} [exclude] Excluded tools, see #extract for format\n * @param {Array|string} [promote] Promoted tools, see #extract for format\n * @param {Array|string} [demote] Demoted tools, see #extract for format\n * @return {string[]} List of tools\n */\nOO.ui.ToolFactory.prototype.getTools = function ( include, exclude, promote, demote ) {\n\tvar i, len, included, promoted, demoted,\n\t\tauto = [],\n\t\tused = {};\n\n\t// Collect included and not excluded tools\n\tincluded = OO.simpleArrayDifference( this.extract( include ), this.extract( exclude ) );\n\n\t// Promotion\n\tpromoted = this.extract( promote, used );\n\tdemoted = this.extract( demote, used );\n\n\t// Auto\n\tfor ( i = 0, len = included.length; i < len; i++ ) {\n\t\tif ( !used[ included[ i ] ] ) {\n\t\t\tauto.push( included[ i ] );\n\t\t}\n\t}\n\n\treturn promoted.concat( auto ).concat( demoted );\n};\n\n/**\n * Get a flat list of names from a list of names or groups.\n *\n * Normally, `collection` is an array of tool specifications. Tools can be specified in the\n * following ways:\n *\n * - To include an individual tool, use the symbolic name: `{ name: 'tool-name' }` or `'tool-name'`.\n * - To include all tools in a group, use the group name: `{ group: 'group-name' }`. (To assign the\n *   tool to a group, use OO.ui.Tool.static.group.)\n *\n * Alternatively, to include all tools that are not yet assigned to any other toolgroup, use the\n * catch-all selector `'*'`.\n *\n * If `used` is passed, tool names that appear as properties in this object will be considered\n * already assigned, and will not be returned even if specified otherwise. The tool names extracted\n * by this function call will be added as new properties in the object.\n *\n * @private\n * @param {Array|string} collection List of tools, see above\n * @param {Object} [used] Object containing information about used tools, see above\n * @return {string[]} List of extracted tool names\n */\nOO.ui.ToolFactory.prototype.extract = function ( collection, used ) {\n\tvar i, len, item, name, tool,\n\t\tnames = [];\n\n\tcollection = !Array.isArray( collection ) ? [ collection ] : collection;\n\n\tfor ( i = 0, len = collection.length; i < len; i++ ) {\n\t\titem = collection[ i ];\n\t\tif ( item === '*' ) {\n\t\t\tfor ( name in this.registry ) {\n\t\t\t\ttool = this.registry[ name ];\n\t\t\t\tif (\n\t\t\t\t\t// Only add tools by group name when auto-add is enabled\n\t\t\t\t\ttool.static.autoAddToCatchall &&\n\t\t\t\t\t// Exclude already used tools\n\t\t\t\t\t( !used || !used[ name ] )\n\t\t\t\t) {\n\t\t\t\t\tnames.push( name );\n\t\t\t\t\tif ( used ) {\n\t\t\t\t\t\tused[ name ] = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// Allow plain strings as shorthand for named tools\n\t\t\tif ( typeof item === 'string' ) {\n\t\t\t\titem = { name: item };\n\t\t\t}\n\t\t\tif ( OO.isPlainObject( item ) ) {\n\t\t\t\tif ( item.group ) {\n\t\t\t\t\tfor ( name in this.registry ) {\n\t\t\t\t\t\ttool = this.registry[ name ];\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t// Include tools with matching group\n\t\t\t\t\t\t\ttool.static.group === item.group &&\n\t\t\t\t\t\t\t// Only add tools by group name when auto-add is enabled\n\t\t\t\t\t\t\ttool.static.autoAddToGroup &&\n\t\t\t\t\t\t\t// Exclude already used tools\n\t\t\t\t\t\t\t( !used || !used[ name ] )\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tnames.push( name );\n\t\t\t\t\t\t\tif ( used ) {\n\t\t\t\t\t\t\t\tused[ name ] = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t// Include tools with matching name and exclude already used tools\n\t\t\t\t} else if ( item.name && ( !used || !used[ item.name ] ) ) {\n\t\t\t\t\tnames.push( item.name );\n\t\t\t\t\tif ( used ) {\n\t\t\t\t\t\tused[ item.name ] = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn names;\n};\n","/**\n * ToolGroupFactories create {@link OO.ui.ToolGroup toolgroups} on demand. The toolgroup classes\n * must specify a symbolic name and be registered with the factory. The following classes are\n * registered by default:\n *\n * - {@link OO.ui.BarToolGroup BarToolGroups} (‘bar’)\n * - {@link OO.ui.MenuToolGroup MenuToolGroups} (‘menu’)\n * - {@link OO.ui.ListToolGroup ListToolGroups} (‘list’)\n *\n * See {@link OO.ui.Toolbar toolbars} for an example.\n *\n * For more information about toolbars in general, please see the\n * [OOUI documentation on MediaWiki][1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Toolbars\n *\n * @class\n * @extends OO.Factory\n * @constructor\n */\nOO.ui.ToolGroupFactory = function OoUiToolGroupFactory() {\n\tvar i, l, defaultClasses;\n\t// Parent constructor\n\tOO.Factory.call( this );\n\n\tdefaultClasses = this.constructor.static.getDefaultClasses();\n\n\t// Register default toolgroups\n\tfor ( i = 0, l = defaultClasses.length; i < l; i++ ) {\n\t\tthis.register( defaultClasses[ i ] );\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ToolGroupFactory, OO.Factory );\n\n/* Static Methods */\n\n/**\n * Get a default set of classes to be registered on construction.\n *\n * @return {Function[]} Default classes\n */\nOO.ui.ToolGroupFactory.static.getDefaultClasses = function () {\n\treturn [\n\t\tOO.ui.BarToolGroup,\n\t\tOO.ui.ListToolGroup,\n\t\tOO.ui.MenuToolGroup\n\t];\n};\n","/**\n * Popup tools open a popup window when they are selected from the {@link OO.ui.Toolbar toolbar}.\n * Each popup tool is configured with a static name, title, and icon, as well with as any popup\n * configurations. Unlike other tools, popup tools do not require that developers specify an\n * #onSelect or #onUpdateState method, as these methods have been implemented already.\n *\n *     // Example of a popup tool. When selected, a popup tool displays\n *     // a popup window.\n *     function HelpTool( toolGroup, config ) {\n *        OO.ui.PopupTool.call( this, toolGroup, $.extend( { popup: {\n *            padded: true,\n *            label: 'Help',\n *            head: true\n *        } }, config ) );\n *        this.popup.$body.append( '<p>I am helpful!</p>' );\n *     };\n *     OO.inheritClass( HelpTool, OO.ui.PopupTool );\n *     HelpTool.static.name = 'help';\n *     HelpTool.static.icon = 'help';\n *     HelpTool.static.title = 'Help';\n *     toolFactory.register( HelpTool );\n *\n * For an example of a toolbar that contains a popup tool, see {@link OO.ui.Toolbar toolbars}.\n * For more information about toolbars in general, please see the\n * [OOUI documentation on MediaWiki][1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Toolbars\n *\n * @abstract\n * @class\n * @extends OO.ui.Tool\n * @mixins OO.ui.mixin.PopupElement\n *\n * @constructor\n * @param {OO.ui.ToolGroup} toolGroup\n * @param {Object} [config] Configuration options\n */\nOO.ui.PopupTool = function OoUiPopupTool( toolGroup, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( toolGroup ) && config === undefined ) {\n\t\tconfig = toolGroup;\n\t\ttoolGroup = config.toolGroup;\n\t}\n\n\t// Parent constructor\n\tOO.ui.PopupTool.parent.call( this, toolGroup, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.PopupElement.call( this, config );\n\n\t// Events\n\tthis.popup.connect( this, {\n\t\ttoggle: 'onPopupToggle'\n\t} );\n\n\t// Initialization\n\tthis.popup.setAutoFlip( false );\n\tthis.popup.setPosition( toolGroup.getToolbar().position === 'bottom' ? 'above' : 'below' );\n\tthis.$element.addClass( 'oo-ui-popupTool' );\n\tthis.popup.$element.addClass( 'oo-ui-popupTool-popup' );\n\tthis.toolbar.$popups.append( this.popup.$element );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.PopupTool, OO.ui.Tool );\nOO.mixinClass( OO.ui.PopupTool, OO.ui.mixin.PopupElement );\n\n/* Methods */\n\n/**\n * Handle the tool being selected.\n *\n * @inheritdoc\n */\nOO.ui.PopupTool.prototype.onSelect = function () {\n\tif ( !this.isDisabled() ) {\n\t\tthis.popup.toggle();\n\t}\n\treturn false;\n};\n\n/**\n * Handle the toolbar state being updated.\n *\n * @inheritdoc\n */\nOO.ui.PopupTool.prototype.onUpdateState = function () {\n};\n\n/**\n * Handle popup visibility being toggled.\n *\n * @param {boolean} isVisible\n */\nOO.ui.PopupTool.prototype.onPopupToggle = function ( isVisible ) {\n\tthis.setActive( isVisible );\n\tthis.toolGroup.emit( 'active', isVisible );\n};\n","/**\n * A ToolGroupTool is a special sort of tool that can contain other {@link OO.ui.Tool tools}\n * and {@link OO.ui.ToolGroup toolgroups}. The ToolGroupTool was specifically designed to be used\n * inside a {@link OO.ui.BarToolGroup bar} toolgroup to provide access to additional tools from\n * the bar item. Included tools will be displayed in a dropdown {@link OO.ui.ListToolGroup list}\n * when the ToolGroupTool is selected.\n *\n *     // Example: ToolGroupTool with two nested tools, 'setting1' and 'setting2',\n *     // defined elsewhere.\n *\n *     function SettingsTool() {\n *         SettingsTool.parent.apply( this, arguments );\n *     };\n *     OO.inheritClass( SettingsTool, OO.ui.ToolGroupTool );\n *     SettingsTool.static.name = 'settings';\n *     SettingsTool.static.title = 'Change settings';\n *     SettingsTool.static.groupConfig = {\n *         icon: 'settings',\n *         label: 'ToolGroupTool',\n *         include: [  'setting1', 'setting2'  ]\n *     };\n *     toolFactory.register( SettingsTool );\n *\n * For more information, please see the [OOUI documentation on MediaWiki][1].\n *\n * Please note that this implementation is subject to change per [T74159] [2].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Toolbars#ToolGroupTool\n * [2]: https://phabricator.wikimedia.org/T74159\n *\n * @abstract\n * @class\n * @extends OO.ui.Tool\n *\n * @constructor\n * @param {OO.ui.ToolGroup} toolGroup\n * @param {Object} [config] Configuration options\n */\nOO.ui.ToolGroupTool = function OoUiToolGroupTool( toolGroup, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( toolGroup ) && config === undefined ) {\n\t\tconfig = toolGroup;\n\t\ttoolGroup = config.toolGroup;\n\t}\n\n\t// Parent constructor\n\tOO.ui.ToolGroupTool.parent.call( this, toolGroup, config );\n\n\t// Properties\n\tthis.innerToolGroup = this.createGroup( this.constructor.static.groupConfig );\n\n\t// Events\n\tthis.innerToolGroup.connect( this, {\n\t\tdisable: 'onToolGroupDisable',\n\t\t// Re-emit active events from the innerToolGroup on the parent toolGroup\n\t\tactive: this.toolGroup.emit.bind( this.toolGroup, 'active' )\n\t} );\n\n\t// Initialization\n\tthis.$link.remove();\n\tthis.$element\n\t\t.addClass( 'oo-ui-toolGroupTool' )\n\t\t.append( this.innerToolGroup.$element );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ToolGroupTool, OO.ui.Tool );\n\n/* Static Properties */\n\n/**\n * Toolgroup configuration.\n *\n * The toolgroup configuration consists of the tools to include, as well as an icon and label\n * to use for the bar item. Tools can be included by symbolic name, group, or with the\n * wildcard selector. Please see {@link OO.ui.ToolGroup toolgroup} for more information.\n *\n * @property {Object.<string,Array>}\n */\nOO.ui.ToolGroupTool.static.groupConfig = {};\n\n/* Methods */\n\n/**\n * Handle the tool being selected.\n *\n * @inheritdoc\n */\nOO.ui.ToolGroupTool.prototype.onSelect = function () {\n\tthis.innerToolGroup.setActive( !this.innerToolGroup.active );\n\treturn false;\n};\n\n/**\n * Synchronize disabledness state of the tool with the inner toolgroup.\n *\n * @private\n * @param {boolean} disabled Element is disabled\n */\nOO.ui.ToolGroupTool.prototype.onToolGroupDisable = function ( disabled ) {\n\tthis.setDisabled( disabled );\n};\n\n/**\n * Handle the toolbar state being updated.\n *\n * @inheritdoc\n */\nOO.ui.ToolGroupTool.prototype.onUpdateState = function () {\n\tthis.setActive( false );\n};\n\n/**\n * Build a {@link OO.ui.ToolGroup toolgroup} from the specified configuration.\n *\n * @param {Object.<string,Array>} group Toolgroup configuration. Please see\n *  {@link OO.ui.ToolGroup toolgroup} for more information.\n * @return {OO.ui.ListToolGroup}\n */\nOO.ui.ToolGroupTool.prototype.createGroup = function ( group ) {\n\tif ( group.include === '*' ) {\n\t\t// Apply defaults to catch-all groups\n\t\tif ( group.label === undefined ) {\n\t\t\tgroup.label = OO.ui.msg( 'ooui-toolbar-more' );\n\t\t}\n\t}\n\n\treturn this.toolbar.getToolGroupFactory().create( 'list', this.toolbar, group );\n};\n","/**\n * BarToolGroups are one of three types of {@link OO.ui.ToolGroup toolgroups} that are used to\n * create {@link OO.ui.Toolbar toolbars} (the other types of groups are\n * {@link OO.ui.MenuToolGroup MenuToolGroup} and {@link OO.ui.ListToolGroup ListToolGroup}).\n * The {@link OO.ui.Tool tools} in a BarToolGroup are displayed by icon in a single row. The\n * title of the tool is displayed when users move the mouse over the tool.\n *\n * BarToolGroups are created by a {@link OO.ui.ToolGroupFactory tool group factory} when the toolbar\n * is set up.\n *\n *     @example\n *     // Example of a BarToolGroup with two tools\n *     var toolFactory = new OO.ui.ToolFactory();\n *     var toolGroupFactory = new OO.ui.ToolGroupFactory();\n *     var toolbar = new OO.ui.Toolbar( toolFactory, toolGroupFactory );\n *\n *     // We will be placing status text in this element when tools are used\n *     var $area = $( '<p>' ).text( 'Example of a BarToolGroup with two tools.' );\n *\n *     // Define the tools that we're going to place in our toolbar\n *\n *     // Create a class inheriting from OO.ui.Tool\n *     function SearchTool() {\n *         SearchTool.parent.apply( this, arguments );\n *     }\n *     OO.inheritClass( SearchTool, OO.ui.Tool );\n *     // Each tool must have a 'name' (used as an internal identifier, see later) and at least one\n *     // of 'icon' and 'title' (displayed icon and text).\n *     SearchTool.static.name = 'search';\n *     SearchTool.static.icon = 'search';\n *     SearchTool.static.title = 'Search...';\n *     // Defines the action that will happen when this tool is selected (clicked).\n *     SearchTool.prototype.onSelect = function () {\n *         $area.text( 'Search tool clicked!' );\n *         // Never display this tool as \"active\" (selected).\n *         this.setActive( false );\n *     };\n *     SearchTool.prototype.onUpdateState = function () {};\n *     // Make this tool available in our toolFactory and thus our toolbar\n *     toolFactory.register( SearchTool );\n *\n *     // This is a PopupTool. Rather than having a custom 'onSelect' action, it will display a\n *     // little popup window (a PopupWidget).\n *     function HelpTool( toolGroup, config ) {\n *         OO.ui.PopupTool.call( this, toolGroup, $.extend( { popup: {\n *             padded: true,\n *             label: 'Help',\n *             head: true\n *         } }, config ) );\n *         this.popup.$body.append( '<p>I am helpful!</p>' );\n *     }\n *     OO.inheritClass( HelpTool, OO.ui.PopupTool );\n *     HelpTool.static.name = 'help';\n *     HelpTool.static.icon = 'help';\n *     HelpTool.static.title = 'Help';\n *     toolFactory.register( HelpTool );\n *\n *     // Finally define which tools and in what order appear in the toolbar. Each tool may only be\n *     // used once (but not all defined tools must be used).\n *     toolbar.setup( [\n *         {\n *             // 'bar' tool groups display tools by icon only\n *             type: 'bar',\n *             include: [ 'search', 'help' ]\n *         }\n *     ] );\n *\n *     // Create some UI around the toolbar and place it in the document\n *     var frame = new OO.ui.PanelLayout( {\n *         expanded: false,\n *         framed: true\n *     } );\n *     var contentFrame = new OO.ui.PanelLayout( {\n *         expanded: false,\n *         padded: true\n *     } );\n *     frame.$element.append(\n *         toolbar.$element,\n *         contentFrame.$element.append( $area )\n *     );\n *     $( document.body ).append( frame.$element );\n *\n *     // Here is where the toolbar is actually built. This must be done after inserting it into the\n *     // document.\n *     toolbar.initialize();\n *\n * For more information about how to add tools to a bar tool group, please see\n * {@link OO.ui.ToolGroup toolgroup}.\n * For more information about toolbars in general, please see the\n * [OOUI documentation on MediaWiki][1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Toolbars\n *\n * @class\n * @extends OO.ui.ToolGroup\n *\n * @constructor\n * @param {OO.ui.Toolbar} toolbar\n * @param {Object} [config] Configuration options\n */\nOO.ui.BarToolGroup = function OoUiBarToolGroup( toolbar, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( toolbar ) && config === undefined ) {\n\t\tconfig = toolbar;\n\t\ttoolbar = config.toolbar;\n\t}\n\n\t// Parent constructor\n\tOO.ui.BarToolGroup.parent.call( this, toolbar, config );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-barToolGroup' );\n\tthis.$group.addClass( 'oo-ui-barToolGroup-tools' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.BarToolGroup, OO.ui.ToolGroup );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.BarToolGroup.static.titleTooltips = true;\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.BarToolGroup.static.accelTooltips = true;\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.BarToolGroup.static.name = 'bar';\n","/**\n * PopupToolGroup is an abstract base class used by both {@link OO.ui.MenuToolGroup MenuToolGroup}\n * and {@link OO.ui.ListToolGroup ListToolGroup} to provide a popup (an overlaid menu or list of\n * tools with an optional icon and label). This class can be used for other base classes that\n * also use this functionality.\n *\n * @abstract\n * @class\n * @extends OO.ui.ToolGroup\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.IndicatorElement\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.TitledElement\n * @mixins OO.ui.mixin.FlaggedElement\n * @mixins OO.ui.mixin.ClippableElement\n * @mixins OO.ui.mixin.FloatableElement\n * @mixins OO.ui.mixin.TabIndexedElement\n *\n * @constructor\n * @param {OO.ui.Toolbar} toolbar\n * @param {Object} [config] Configuration options\n * @cfg {string} [header] Text to display at the top of the popup\n */\nOO.ui.PopupToolGroup = function OoUiPopupToolGroup( toolbar, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( toolbar ) && config === undefined ) {\n\t\tconfig = toolbar;\n\t\ttoolbar = config.toolbar;\n\t}\n\n\t// Configuration initialization\n\tconfig = $.extend( {\n\t\tindicator: config.indicator === undefined ?\n\t\t\t( toolbar.position === 'bottom' ? 'up' : 'down' ) : config.indicator\n\t}, config );\n\n\t// Parent constructor\n\tOO.ui.PopupToolGroup.parent.call( this, toolbar, config );\n\n\t// Properties\n\tthis.active = false;\n\tthis.dragging = false;\n\t// Don't conflict with parent method of the same name\n\tthis.onPopupDocumentMouseKeyUpHandler = this.onPopupDocumentMouseKeyUp.bind( this );\n\tthis.$handle = $( '<span>' );\n\n\t// Mixin constructors\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.IndicatorElement.call( this, config );\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.TitledElement.call( this, config );\n\tOO.ui.mixin.FlaggedElement.call( this, config );\n\tOO.ui.mixin.ClippableElement.call( this, $.extend( {\n\t\t$clippable: this.$group\n\t}, config ) );\n\tOO.ui.mixin.FloatableElement.call( this, $.extend( {\n\t\t$floatable: this.$group,\n\t\t$floatableContainer: this.$handle,\n\t\thideWhenOutOfView: false,\n\t\tverticalPosition: this.toolbar.position === 'bottom' ? 'above' : 'below'\n\t}, config ) );\n\tOO.ui.mixin.TabIndexedElement.call( this, $.extend( {\n\t\t$tabIndexed: this.$handle\n\t}, config ) );\n\n\t// Events\n\tthis.$handle.on( {\n\t\tkeydown: this.onHandleMouseKeyDown.bind( this ),\n\t\tkeyup: this.onHandleMouseKeyUp.bind( this ),\n\t\tmousedown: this.onHandleMouseKeyDown.bind( this ),\n\t\tmouseup: this.onHandleMouseKeyUp.bind( this )\n\t} );\n\n\t// Initialization\n\tthis.$handle\n\t\t.addClass( 'oo-ui-popupToolGroup-handle' )\n\t\t.attr( 'role', 'button' )\n\t\t.append( this.$icon, this.$label, this.$indicator );\n\t// If the pop-up should have a header, add it to the top of the toolGroup.\n\t// Note: If this feature is useful for other widgets, we could abstract it into an\n\t// OO.ui.HeaderedElement mixin constructor.\n\tif ( config.header !== undefined ) {\n\t\tthis.$group\n\t\t\t.prepend( $( '<span>' )\n\t\t\t\t.addClass( 'oo-ui-popupToolGroup-header' )\n\t\t\t\t.text( config.header )\n\t\t\t);\n\t}\n\tthis.$element\n\t\t.addClass( 'oo-ui-popupToolGroup' )\n\t\t.prepend( this.$handle );\n\tthis.$group.addClass( 'oo-ui-popupToolGroup-tools' );\n\tthis.toolbar.$popups.append( this.$group );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.PopupToolGroup, OO.ui.ToolGroup );\nOO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.IndicatorElement );\nOO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.TitledElement );\nOO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.FlaggedElement );\nOO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.ClippableElement );\nOO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.FloatableElement );\nOO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.TabIndexedElement );\n\n/* Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.PopupToolGroup.prototype.setDisabled = function () {\n\t// Parent method\n\tOO.ui.PopupToolGroup.parent.prototype.setDisabled.apply( this, arguments );\n\n\tif ( this.isDisabled() && this.isElementAttached() ) {\n\t\tthis.setActive( false );\n\t}\n};\n\n/**\n * Handle document mouse up and key up events.\n *\n * @protected\n * @param {MouseEvent|KeyboardEvent} e Mouse up or key up event\n */\nOO.ui.PopupToolGroup.prototype.onPopupDocumentMouseKeyUp = function ( e ) {\n\tvar $target = $( e.target );\n\t// Only deactivate when clicking outside the dropdown element\n\tif ( $target.closest( '.oo-ui-popupToolGroup' )[ 0 ] === this.$element[ 0 ] ) {\n\t\treturn;\n\t}\n\tif ( $target.closest( '.oo-ui-popupToolGroup-tools' )[ 0 ] === this.$group[ 0 ] ) {\n\t\treturn;\n\t}\n\tthis.setActive( false );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.PopupToolGroup.prototype.onMouseKeyUp = function ( e ) {\n\t// Only close toolgroup when a tool was actually selected\n\tif (\n\t\t!this.isDisabled() && this.pressed && this.pressed === this.findTargetTool( e ) && (\n\t\t\te.which === OO.ui.MouseButtons.LEFT ||\n\t\t\te.which === OO.ui.Keys.SPACE ||\n\t\t\te.which === OO.ui.Keys.ENTER\n\t\t)\n\t) {\n\t\tthis.setActive( false );\n\t}\n\treturn OO.ui.PopupToolGroup.parent.prototype.onMouseKeyUp.call( this, e );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.PopupToolGroup.prototype.onMouseKeyDown = function ( e ) {\n\tvar $focused, $firstFocusable, $lastFocusable;\n\t// Shift-Tab on the first tool in the group jumps to the handle.\n\t// Tab on the last tool in the group jumps to the next group.\n\tif ( !this.isDisabled() && e.which === OO.ui.Keys.TAB ) {\n\t\t// We can't use this.items because ListToolGroup inserts the extra fake\n\t\t// expand/collapse tool.\n\t\t$focused = $( document.activeElement );\n\t\t$firstFocusable = OO.ui.findFocusable( this.$group );\n\t\tif ( $focused[ 0 ] === $firstFocusable[ 0 ] && e.shiftKey ) {\n\t\t\tthis.$handle.trigger( 'focus' );\n\t\t\treturn false;\n\t\t}\n\t\t$lastFocusable = OO.ui.findFocusable( this.$group, true );\n\t\tif ( $focused[ 0 ] === $lastFocusable[ 0 ] && !e.shiftKey ) {\n\t\t\t// Focus this group's handle and let the browser's tab handling happen\n\t\t\t// (no 'return false').\n\t\t\t// This way we don't have to fiddle with other ToolGroups' business, or worry what to do\n\t\t\t// if the next group is not a PopupToolGroup or doesn't exist at all.\n\t\t\tthis.$handle.trigger( 'focus' );\n\t\t\t// Close the popup so that we don't move back inside it (if this is the last group).\n\t\t\tthis.setActive( false );\n\t\t}\n\t}\n\treturn OO.ui.PopupToolGroup.parent.prototype.onMouseKeyDown.call( this, e );\n};\n\n/**\n * Handle mouse up and key up events.\n *\n * @protected\n * @param {jQuery.Event} e Mouse up or key up event\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.PopupToolGroup.prototype.onHandleMouseKeyUp = function ( e ) {\n\tif (\n\t\t!this.isDisabled() && (\n\t\t\te.which === OO.ui.MouseButtons.LEFT ||\n\t\t\te.which === OO.ui.Keys.SPACE ||\n\t\t\te.which === OO.ui.Keys.ENTER\n\t\t)\n\t) {\n\t\treturn false;\n\t}\n};\n\n/**\n * Handle mouse down and key down events.\n *\n * @protected\n * @param {jQuery.Event} e Mouse down or key down event\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.PopupToolGroup.prototype.onHandleMouseKeyDown = function ( e ) {\n\tvar $focusable;\n\tif ( !this.isDisabled() ) {\n\t\t// Tab on the handle jumps to the first tool in the group (if the popup is open).\n\t\tif ( e.which === OO.ui.Keys.TAB && !e.shiftKey ) {\n\t\t\t$focusable = OO.ui.findFocusable( this.$group );\n\t\t\tif ( $focusable.length ) {\n\t\t\t\t$focusable.trigger( 'focus' );\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\tif (\n\t\t\te.which === OO.ui.MouseButtons.LEFT ||\n\t\t\te.which === OO.ui.Keys.SPACE ||\n\t\t\te.which === OO.ui.Keys.ENTER\n\t\t) {\n\t\t\tthis.setActive( !this.active );\n\t\t\treturn false;\n\t\t}\n\t}\n};\n\n/**\n * Check if the tool group is active.\n *\n * @return {boolean} Tool group is active\n */\nOO.ui.PopupToolGroup.prototype.isActive = function () {\n\treturn this.active;\n};\n\n/**\n * Switch into 'active' mode.\n *\n * When active, the popup is visible. A mouseup event anywhere in the document will trigger\n * deactivation.\n *\n * @param {boolean} value The active state to set\n * @fires active\n */\nOO.ui.PopupToolGroup.prototype.setActive = function ( value ) {\n\tvar containerWidth, containerLeft;\n\tvalue = !!value;\n\tif ( this.active !== value ) {\n\t\tthis.active = value;\n\t\tif ( value ) {\n\t\t\tthis.getElementDocument().addEventListener(\n\t\t\t\t'mouseup',\n\t\t\t\tthis.onPopupDocumentMouseKeyUpHandler,\n\t\t\t\ttrue\n\t\t\t);\n\t\t\tthis.getElementDocument().addEventListener(\n\t\t\t\t'keyup',\n\t\t\t\tthis.onPopupDocumentMouseKeyUpHandler,\n\t\t\t\ttrue\n\t\t\t);\n\n\t\t\tthis.$clippable.css( 'left', '' );\n\t\t\tthis.$element.addClass( 'oo-ui-popupToolGroup-active' );\n\t\t\tthis.$group.addClass( 'oo-ui-popupToolGroup-active-tools' );\n\t\t\tthis.togglePositioning( true );\n\t\t\tthis.toggleClipping( true );\n\n\t\t\t// Try anchoring the popup to the left first\n\t\t\tthis.setHorizontalPosition( 'start' );\n\n\t\t\tif ( this.isClippedHorizontally() || this.isFloatableOutOfView() ) {\n\t\t\t\t// Anchoring to the left caused the popup to clip, so anchor it to the\n\t\t\t\t// right instead.\n\t\t\t\tthis.setHorizontalPosition( 'end' );\n\t\t\t}\n\t\t\tif ( this.isClippedHorizontally() || this.isFloatableOutOfView() ) {\n\t\t\t\t// Anchoring to the right also caused the popup to clip, so just make it fill the\n\t\t\t\t// container.\n\t\t\t\tcontainerWidth = this.$clippableScrollableContainer.width();\n\t\t\t\tcontainerLeft = this.$clippableScrollableContainer[ 0 ] ===\n\t\t\t\t\tdocument.documentElement ?\n\t\t\t\t\t0 :\n\t\t\t\t\tthis.$clippableScrollableContainer.offset().left;\n\n\t\t\t\tthis.toggleClipping( false );\n\t\t\t\tthis.setHorizontalPosition( 'start' );\n\n\t\t\t\tthis.$clippable.css( {\n\t\t\t\t\t'margin-left': -( this.$element.offset().left - containerLeft ),\n\t\t\t\t\twidth: containerWidth\n\t\t\t\t} );\n\t\t\t}\n\t\t} else {\n\t\t\tthis.getElementDocument().removeEventListener(\n\t\t\t\t'mouseup',\n\t\t\t\tthis.onPopupDocumentMouseKeyUpHandler,\n\t\t\t\ttrue\n\t\t\t);\n\t\t\tthis.getElementDocument().removeEventListener(\n\t\t\t\t'keyup',\n\t\t\t\tthis.onPopupDocumentMouseKeyUpHandler,\n\t\t\t\ttrue\n\t\t\t);\n\t\t\tthis.$element.removeClass( 'oo-ui-popupToolGroup-active' );\n\t\t\tthis.$group.removeClass( 'oo-ui-popupToolGroup-active-tools' );\n\t\t\tthis.togglePositioning( false );\n\t\t\tthis.toggleClipping( false );\n\t\t}\n\t\tthis.emit( 'active', this.active );\n\t\tthis.updateThemeClasses();\n\t}\n};\n","/**\n * ListToolGroups are one of three types of {@link OO.ui.ToolGroup toolgroups} that are used to\n * create {@link OO.ui.Toolbar toolbars} (the other types of groups are\n * {@link OO.ui.MenuToolGroup MenuToolGroup} and {@link OO.ui.BarToolGroup BarToolGroup}).\n * The {@link OO.ui.Tool tools} in a ListToolGroup are displayed by label in a dropdown menu.\n * The title of the tool is used as the label text. The menu itself can be configured with a label,\n * icon, indicator, header, and title.\n *\n * ListToolGroups can be configured to be expanded and collapsed. Collapsed lists will have a\n * ‘More’ option that users can select to see the full list of tools. If a collapsed toolgroup is\n * expanded, a ‘Fewer’ option permits users to collapse the list again.\n *\n * ListToolGroups are created by a {@link OO.ui.ToolGroupFactory toolgroup factory} when the\n * toolbar is set up. The factory requires the ListToolGroup's symbolic name, 'list', which is\n * specified along with the other configurations. For more information about how to add tools to a\n * ListToolGroup, please see {@link OO.ui.ToolGroup toolgroup}.\n *\n *     @example\n *     // Example of a ListToolGroup\n *     var toolFactory = new OO.ui.ToolFactory();\n *     var toolGroupFactory = new OO.ui.ToolGroupFactory();\n *     var toolbar = new OO.ui.Toolbar( toolFactory, toolGroupFactory );\n *\n *     // Configure and register two tools\n *     function SettingsTool() {\n *         SettingsTool.parent.apply( this, arguments );\n *     }\n *     OO.inheritClass( SettingsTool, OO.ui.Tool );\n *     SettingsTool.static.name = 'settings';\n *     SettingsTool.static.icon = 'settings';\n *     SettingsTool.static.title = 'Change settings';\n *     SettingsTool.prototype.onSelect = function () {\n *         this.setActive( false );\n *     };\n *     SettingsTool.prototype.onUpdateState = function () {};\n *     toolFactory.register( SettingsTool );\n *     // Register two more tools, nothing interesting here\n *     function StuffTool() {\n *         StuffTool.parent.apply( this, arguments );\n *     }\n *     OO.inheritClass( StuffTool, OO.ui.Tool );\n *     StuffTool.static.name = 'stuff';\n *     StuffTool.static.icon = 'search';\n *     StuffTool.static.title = 'Change the world';\n *     StuffTool.prototype.onSelect = function () {\n *         this.setActive( false );\n *     };\n *     StuffTool.prototype.onUpdateState = function () {};\n *     toolFactory.register( StuffTool );\n *     toolbar.setup( [\n *         {\n *             // Configurations for list toolgroup.\n *             type: 'list',\n *             label: 'ListToolGroup',\n *             icon: 'ellipsis',\n *             title: 'This is the title, displayed when user moves the mouse over the list ' +\n *                 'toolgroup',\n *             header: 'This is the header',\n *             include: [ 'settings', 'stuff' ],\n *             allowCollapse: ['stuff']\n *         }\n *     ] );\n *\n *     // Create some UI around the toolbar and place it in the document\n *     var frame = new OO.ui.PanelLayout( {\n *         expanded: false,\n *         framed: true\n *     } );\n *     frame.$element.append(\n *         toolbar.$element\n *     );\n *     $( document.body ).append( frame.$element );\n *     // Build the toolbar. This must be done after the toolbar has been appended to the document.\n *     toolbar.initialize();\n *\n * For more information about toolbars in general, please see the\n * [OOUI documentation on MediaWiki][1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Toolbars\n *\n * @class\n * @extends OO.ui.PopupToolGroup\n *\n * @constructor\n * @param {OO.ui.Toolbar} toolbar\n * @param {Object} [config] Configuration options\n * @cfg {Array} [allowCollapse] Allow the specified tools to be collapsed. By default, collapsible\n *  tools will only be displayed if users click the ‘More’ option displayed at the bottom of the\n *  list. If the list is expanded, a ‘Fewer’ option permits users to collapse the list again.\n *  Any tools that are included in the toolgroup, but are not designated as collapsible, will always\n *  be displayed.\n *  To open a collapsible list in its expanded state, set #expanded to 'true'.\n * @cfg {Array} [forceExpand] Expand the specified tools. All other tools will be designated as\n *  collapsible. Unless #expanded is set to true, the collapsible tools will be collapsed when the\n *  list is first opened.\n * @cfg {boolean} [expanded=false] Expand collapsible tools. This config is only relevant if tools\n *  have been designated as collapsible. When expanded is set to true, all tools in the group will\n *  be displayed when the list is first opened. Users can collapse the list with a ‘Fewer’ option at\n *  the bottom.\n */\nOO.ui.ListToolGroup = function OoUiListToolGroup( toolbar, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( toolbar ) && config === undefined ) {\n\t\tconfig = toolbar;\n\t\ttoolbar = config.toolbar;\n\t}\n\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties (must be set before parent constructor, which calls #populate)\n\tthis.allowCollapse = config.allowCollapse;\n\tthis.forceExpand = config.forceExpand;\n\tthis.expanded = config.expanded !== undefined ? config.expanded : false;\n\tthis.collapsibleTools = [];\n\n\t// Parent constructor\n\tOO.ui.ListToolGroup.parent.call( this, toolbar, config );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-listToolGroup' );\n\tthis.$group.addClass( 'oo-ui-listToolGroup-tools' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ListToolGroup, OO.ui.PopupToolGroup );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.ListToolGroup.static.name = 'list';\n\n/* Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.ListToolGroup.prototype.populate = function () {\n\tvar i, len, allowCollapse = [];\n\n\tOO.ui.ListToolGroup.parent.prototype.populate.call( this );\n\n\t// Update the list of collapsible tools\n\tif ( this.allowCollapse !== undefined ) {\n\t\tallowCollapse = this.allowCollapse;\n\t} else if ( this.forceExpand !== undefined ) {\n\t\tallowCollapse = OO.simpleArrayDifference( Object.keys( this.tools ), this.forceExpand );\n\t}\n\n\tthis.collapsibleTools = [];\n\tfor ( i = 0, len = allowCollapse.length; i < len; i++ ) {\n\t\tif ( this.tools[ allowCollapse[ i ] ] !== undefined ) {\n\t\t\tthis.collapsibleTools.push( this.tools[ allowCollapse[ i ] ] );\n\t\t}\n\t}\n\n\t// Keep at the end, even when tools are added\n\tthis.$group.append( this.getExpandCollapseTool().$element );\n\n\tthis.getExpandCollapseTool().toggle( this.collapsibleTools.length !== 0 );\n\tthis.updateCollapsibleState();\n};\n\n/**\n * Get the expand/collapse tool for this group\n *\n * @return {OO.ui.Tool} Expand collapse tool\n */\nOO.ui.ListToolGroup.prototype.getExpandCollapseTool = function () {\n\tvar ExpandCollapseTool;\n\tif ( this.expandCollapseTool === undefined ) {\n\t\tExpandCollapseTool = function () {\n\t\t\tExpandCollapseTool.parent.apply( this, arguments );\n\t\t};\n\n\t\tOO.inheritClass( ExpandCollapseTool, OO.ui.Tool );\n\n\t\tExpandCollapseTool.prototype.onSelect = function () {\n\t\t\tthis.toolGroup.expanded = !this.toolGroup.expanded;\n\t\t\tthis.toolGroup.updateCollapsibleState();\n\t\t\tthis.setActive( false );\n\t\t};\n\t\tExpandCollapseTool.prototype.onUpdateState = function () {\n\t\t\t// Do nothing. Tool interface requires an implementation of this function.\n\t\t};\n\n\t\tExpandCollapseTool.static.name = 'more-fewer';\n\n\t\tthis.expandCollapseTool = new ExpandCollapseTool( this );\n\t}\n\treturn this.expandCollapseTool;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.ListToolGroup.prototype.onMouseKeyUp = function ( e ) {\n\t// Do not close the popup when the user wants to show more/fewer tools\n\tif (\n\t\t$( e.target ).closest( '.oo-ui-tool-name-more-fewer' ).length && (\n\t\t\te.which === OO.ui.MouseButtons.LEFT ||\n\t\t\te.which === OO.ui.Keys.SPACE ||\n\t\t\te.which === OO.ui.Keys.ENTER\n\t\t)\n\t) {\n\t\t// HACK: Prevent the popup list from being hidden. Skip the PopupToolGroup implementation\n\t\t// (which hides the popup list when a tool is selected) and call ToolGroup's implementation\n\t\t// directly.\n\t\treturn OO.ui.ListToolGroup.parent.parent.prototype.onMouseKeyUp.call( this, e );\n\t} else {\n\t\treturn OO.ui.ListToolGroup.parent.prototype.onMouseKeyUp.call( this, e );\n\t}\n};\n\nOO.ui.ListToolGroup.prototype.updateCollapsibleState = function () {\n\tvar i, icon, len;\n\n\tif ( this.toolbar.position !== 'bottom' ) {\n\t\ticon = this.expanded ? 'collapse' : 'expand';\n\t} else {\n\t\ticon = this.expanded ? 'expand' : 'collapse';\n\t}\n\n\tthis.getExpandCollapseTool()\n\t\t.setIcon( icon )\n\t\t.setTitle( OO.ui.msg( this.expanded ? 'ooui-toolgroup-collapse' : 'ooui-toolgroup-expand' ) );\n\n\tfor ( i = 0, len = this.collapsibleTools.length; i < len; i++ ) {\n\t\tthis.collapsibleTools[ i ].toggle( this.expanded );\n\t}\n\n\t// Re-evaluate clipping, because our height has changed\n\tthis.clip();\n};\n","/**\n * MenuToolGroups are one of three types of {@link OO.ui.ToolGroup toolgroups} that are used to\n * create {@link OO.ui.Toolbar toolbars} (the other types of groups are\n * {@link OO.ui.BarToolGroup BarToolGroup} and {@link OO.ui.ListToolGroup ListToolGroup}).\n * MenuToolGroups contain selectable {@link OO.ui.Tool tools}, which are displayed by label in a\n * dropdown menu. The tool's title is used as the label text, and the menu label is updated to\n * reflect which tool or tools are currently selected. If no tools are selected, the menu label\n * is empty. The menu can be configured with an indicator, icon, title, and/or header.\n *\n * MenuToolGroups are created by a {@link OO.ui.ToolGroupFactory tool group factory} when the\n * toolbar is set up.\n *\n *     @example\n *     // Example of a MenuToolGroup\n *     var toolFactory = new OO.ui.ToolFactory();\n *     var toolGroupFactory = new OO.ui.ToolGroupFactory();\n *     var toolbar = new OO.ui.Toolbar( toolFactory, toolGroupFactory );\n *\n *     // We will be placing status text in this element when tools are used\n *     var $area = $( '<p>' ).text( 'An example of a MenuToolGroup. Select a tool from the '\n *         + 'dropdown menu.' );\n *\n *     // Define the tools that we're going to place in our toolbar\n *\n *     function SettingsTool() {\n *         SettingsTool.parent.apply( this, arguments );\n *         this.reallyActive = false;\n *     }\n *     OO.inheritClass( SettingsTool, OO.ui.Tool );\n *     SettingsTool.static.name = 'settings';\n *     SettingsTool.static.icon = 'settings';\n *     SettingsTool.static.title = 'Change settings';\n *     SettingsTool.prototype.onSelect = function () {\n *         $area.text( 'Settings tool clicked!' );\n *         // Toggle the active state on each click\n *         this.reallyActive = !this.reallyActive;\n *         this.setActive( this.reallyActive );\n *         // To update the menu label\n *         this.toolbar.emit( 'updateState' );\n *     };\n *     SettingsTool.prototype.onUpdateState = function () {};\n *     toolFactory.register( SettingsTool );\n *\n *     function StuffTool() {\n *         StuffTool.parent.apply( this, arguments );\n *         this.reallyActive = false;\n *     }\n *     OO.inheritClass( StuffTool, OO.ui.Tool );\n *     StuffTool.static.name = 'stuff';\n *     StuffTool.static.icon = 'ellipsis';\n *     StuffTool.static.title = 'More stuff';\n *     StuffTool.prototype.onSelect = function () {\n *         $area.text( 'More stuff tool clicked!' );\n *         // Toggle the active state on each click\n *         this.reallyActive = !this.reallyActive;\n *         this.setActive( this.reallyActive );\n *         // To update the menu label\n *         this.toolbar.emit( 'updateState' );\n *     };\n *     StuffTool.prototype.onUpdateState = function () {};\n *     toolFactory.register( StuffTool );\n *\n *     // Finally define which tools and in what order appear in the toolbar. Each tool may only be\n *     // used once (but not all defined tools must be used).\n *     toolbar.setup( [\n *         {\n *             type: 'menu',\n *             header: 'This is the (optional) header',\n *             title: 'This is the (optional) title',\n *             include: [ 'settings', 'stuff' ]\n *         }\n *     ] );\n *\n *     // Create some UI around the toolbar and place it in the document\n *     var frame = new OO.ui.PanelLayout( {\n *         expanded: false,\n *         framed: true\n *     } );\n *     var contentFrame = new OO.ui.PanelLayout( {\n *         expanded: false,\n *         padded: true\n *     } );\n *     frame.$element.append(\n *         toolbar.$element,\n *         contentFrame.$element.append( $area )\n *     );\n *     $( document.body ).append( frame.$element );\n *\n *     // Here is where the toolbar is actually built. This must be done after inserting it into the\n *     // document.\n *     toolbar.initialize();\n *     toolbar.emit( 'updateState' );\n *\n * For more information about how to add tools to a MenuToolGroup, please see\n * {@link OO.ui.ToolGroup toolgroup}.\n * For more information about toolbars in general, please see the\n * [OOUI documentation on MediaWiki] [1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Toolbars\n *\n * @class\n * @extends OO.ui.PopupToolGroup\n *\n * @constructor\n * @param {OO.ui.Toolbar} toolbar\n * @param {Object} [config] Configuration options\n */\nOO.ui.MenuToolGroup = function OoUiMenuToolGroup( toolbar, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( toolbar ) && config === undefined ) {\n\t\tconfig = toolbar;\n\t\ttoolbar = config.toolbar;\n\t}\n\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.MenuToolGroup.parent.call( this, toolbar, config );\n\n\t// Events\n\tthis.toolbar.connect( this, {\n\t\tupdateState: 'onUpdateState'\n\t} );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-menuToolGroup' );\n\tthis.$group.addClass( 'oo-ui-menuToolGroup-tools' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.MenuToolGroup, OO.ui.PopupToolGroup );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.MenuToolGroup.static.name = 'menu';\n\n/* Methods */\n\n/**\n * Handle the toolbar state being updated.\n *\n * When the state changes, the title of each active item in the menu will be joined together and\n * used as a label for the group. The label will be empty if none of the items are active.\n *\n * @private\n */\nOO.ui.MenuToolGroup.prototype.onUpdateState = function () {\n\tvar name,\n\t\tlabelTexts = [];\n\n\tfor ( name in this.tools ) {\n\t\tif ( this.tools[ name ].isActive() ) {\n\t\t\tlabelTexts.push( this.tools[ name ].getTitle() );\n\t\t}\n\t}\n\n\tthis.setLabel( labelTexts.join( ', ' ) || ' ' );\n};\n","}( OO ) );\n"]}
\ No newline at end of file
+{"version":3,"sources":["../src/intro.js.txt","../src/Toolbar.js","../src/Tool.js","../src/ToolGroup.js","../src/ToolFactory.js","../src/ToolGroupFactory.js","../src/tools/PopupTool.js","../src/tools/ToolGroupTool.js","../src/toolgroups/BarToolGroup.js","../src/toolgroups/PopupToolGroup.js","../src/toolgroups/ListToolGroup.js","../src/toolgroups/MenuToolGroup.js","../src/outro.js.txt"],"names":[],"mappings":"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","file":"oojs-ui-toolbars.js","sourcesContent":["( function ( OO ) {\n\n'use strict';\n","/**\n * Toolbars are complex interface components that permit users to easily access a variety\n * of {@link OO.ui.Tool tools} (e.g., formatting commands) and actions, which are additional\n * commands that are part of the toolbar, but not configured as tools.\n *\n * Individual tools are customized and then registered with a\n * {@link OO.ui.ToolFactory tool factory}, which creates the tools on demand. Each tool has a\n * symbolic name (used when registering the tool), a title (e.g., ‘Insert image’), and an icon.\n *\n * Individual tools are organized in {@link OO.ui.ToolGroup toolgroups}, which can be\n * {@link OO.ui.MenuToolGroup menus} of tools, {@link OO.ui.ListToolGroup lists} of tools, or a\n * single {@link OO.ui.BarToolGroup bar} of tools. The arrangement and order of the toolgroups is\n * customized when the toolbar is set up. Tools can be presented in any order, but each can only\n * appear once in the toolbar.\n *\n * The toolbar can be synchronized with the state of the external \"application\", like a text\n * editor's editing area, marking tools as active/inactive (e.g. a 'bold' tool would be shown as\n * active when the text cursor was inside bolded text) or enabled/disabled (e.g. a table caption\n * tool would be disabled while the user is not editing a table). A state change is signalled by\n * emitting the {@link #event-updateState 'updateState' event}, which calls Tools'\n * {@link OO.ui.Tool#onUpdateState onUpdateState method}.\n *\n * The following is an example of a basic toolbar.\n *\n *     @example\n *     // Example of a toolbar\n *     // Create the toolbar\n *     var toolFactory = new OO.ui.ToolFactory();\n *     var toolGroupFactory = new OO.ui.ToolGroupFactory();\n *     var toolbar = new OO.ui.Toolbar( toolFactory, toolGroupFactory );\n *\n *     // We will be placing status text in this element when tools are used\n *     var $area = $( '<p>' ).text( 'Toolbar example' );\n *\n *     // Define the tools that we're going to place in our toolbar\n *\n *     // Create a class inheriting from OO.ui.Tool\n *     function SearchTool() {\n *         SearchTool.parent.apply( this, arguments );\n *     }\n *     OO.inheritClass( SearchTool, OO.ui.Tool );\n *     // Each tool must have a 'name' (used as an internal identifier, see later) and at least one\n *     // of 'icon' and 'title' (displayed icon and text).\n *     SearchTool.static.name = 'search';\n *     SearchTool.static.icon = 'search';\n *     SearchTool.static.title = 'Search...';\n *     // Defines the action that will happen when this tool is selected (clicked).\n *     SearchTool.prototype.onSelect = function () {\n *         $area.text( 'Search tool clicked!' );\n *         // Never display this tool as \"active\" (selected).\n *         this.setActive( false );\n *     };\n *     SearchTool.prototype.onUpdateState = function () {};\n *     // Make this tool available in our toolFactory and thus our toolbar\n *     toolFactory.register( SearchTool );\n *\n *     // Register two more tools, nothing interesting here\n *     function SettingsTool() {\n *         SettingsTool.parent.apply( this, arguments );\n *     }\n *     OO.inheritClass( SettingsTool, OO.ui.Tool );\n *     SettingsTool.static.name = 'settings';\n *     SettingsTool.static.icon = 'settings';\n *     SettingsTool.static.title = 'Change settings';\n *     SettingsTool.prototype.onSelect = function () {\n *         $area.text( 'Settings tool clicked!' );\n *         this.setActive( false );\n *     };\n *     SettingsTool.prototype.onUpdateState = function () {};\n *     toolFactory.register( SettingsTool );\n *\n *     // Register two more tools, nothing interesting here\n *     function StuffTool() {\n *         StuffTool.parent.apply( this, arguments );\n *     }\n *     OO.inheritClass( StuffTool, OO.ui.Tool );\n *     StuffTool.static.name = 'stuff';\n *     StuffTool.static.icon = 'ellipsis';\n *     StuffTool.static.title = 'More stuff';\n *     StuffTool.prototype.onSelect = function () {\n *         $area.text( 'More stuff tool clicked!' );\n *         this.setActive( false );\n *     };\n *     StuffTool.prototype.onUpdateState = function () {};\n *     toolFactory.register( StuffTool );\n *\n *     // This is a PopupTool. Rather than having a custom 'onSelect' action, it will display a\n *     // little popup window (a PopupWidget).\n *     function HelpTool( toolGroup, config ) {\n *         OO.ui.PopupTool.call( this, toolGroup, $.extend( { popup: {\n *             padded: true,\n *             label: 'Help',\n *             head: true\n *         } }, config ) );\n *         this.popup.$body.append( '<p>I am helpful!</p>' );\n *     }\n *     OO.inheritClass( HelpTool, OO.ui.PopupTool );\n *     HelpTool.static.name = 'help';\n *     HelpTool.static.icon = 'help';\n *     HelpTool.static.title = 'Help';\n *     toolFactory.register( HelpTool );\n *\n *     // Finally define which tools and in what order appear in the toolbar. Each tool may only be\n *     // used once (but not all defined tools must be used).\n *     toolbar.setup( [\n *         {\n *             // 'bar' tool groups display tools' icons only, side-by-side.\n *             type: 'bar',\n *             include: [ 'search', 'help' ]\n *         },\n *         {\n *             // 'list' tool groups display both the titles and icons, in a dropdown list.\n *             type: 'list',\n *             indicator: 'down',\n *             label: 'More',\n *             include: [ 'settings', 'stuff' ]\n *         }\n *         // Note how the tools themselves are toolgroup-agnostic - the same tool can be displayed\n *         // either in a 'list' or a 'bar'. There is a 'menu' tool group too, not showcased here,\n *         // since it's more complicated to use. (See the next example snippet on this page.)\n *     ] );\n *\n *     // Create some UI around the toolbar and place it in the document\n *     var frame = new OO.ui.PanelLayout( {\n *         expanded: false,\n *         framed: true\n *     } );\n *     var contentFrame = new OO.ui.PanelLayout( {\n *         expanded: false,\n *         padded: true\n *     } );\n *     frame.$element.append(\n *         toolbar.$element,\n *         contentFrame.$element.append( $area )\n *     );\n *     $( document.body ).append( frame.$element );\n *\n *     // Here is where the toolbar is actually built. This must be done after inserting it into the\n *     // document.\n *     toolbar.initialize();\n *     toolbar.emit( 'updateState' );\n *\n * The following example extends the previous one to illustrate 'menu' toolgroups and the usage of\n * {@link #event-updateState 'updateState' event}.\n *\n *     @example\n *     // Create the toolbar\n *     var toolFactory = new OO.ui.ToolFactory();\n *     var toolGroupFactory = new OO.ui.ToolGroupFactory();\n *     var toolbar = new OO.ui.Toolbar( toolFactory, toolGroupFactory );\n *\n *     // We will be placing status text in this element when tools are used\n *     var $area = $( '<p>' ).text( 'Toolbar example' );\n *\n *     // Define the tools that we're going to place in our toolbar\n *\n *     // Create a class inheriting from OO.ui.Tool\n *     function SearchTool() {\n *         SearchTool.parent.apply( this, arguments );\n *     }\n *     OO.inheritClass( SearchTool, OO.ui.Tool );\n *     // Each tool must have a 'name' (used as an internal identifier, see later) and at least one\n *     // of 'icon' and 'title' (displayed icon and text).\n *     SearchTool.static.name = 'search';\n *     SearchTool.static.icon = 'search';\n *     SearchTool.static.title = 'Search...';\n *     // Defines the action that will happen when this tool is selected (clicked).\n *     SearchTool.prototype.onSelect = function () {\n *         $area.text( 'Search tool clicked!' );\n *         // Never display this tool as \"active\" (selected).\n *         this.setActive( false );\n *     };\n *     SearchTool.prototype.onUpdateState = function () {};\n *     // Make this tool available in our toolFactory and thus our toolbar\n *     toolFactory.register( SearchTool );\n *\n *     // Register two more tools, nothing interesting here\n *     function SettingsTool() {\n *         SettingsTool.parent.apply( this, arguments );\n *         this.reallyActive = false;\n *     }\n *     OO.inheritClass( SettingsTool, OO.ui.Tool );\n *     SettingsTool.static.name = 'settings';\n *     SettingsTool.static.icon = 'settings';\n *     SettingsTool.static.title = 'Change settings';\n *     SettingsTool.prototype.onSelect = function () {\n *         $area.text( 'Settings tool clicked!' );\n *         // Toggle the active state on each click\n *         this.reallyActive = !this.reallyActive;\n *         this.setActive( this.reallyActive );\n *         // To update the menu label\n *         this.toolbar.emit( 'updateState' );\n *     };\n *     SettingsTool.prototype.onUpdateState = function () {};\n *     toolFactory.register( SettingsTool );\n *\n *     // Register two more tools, nothing interesting here\n *     function StuffTool() {\n *         StuffTool.parent.apply( this, arguments );\n *         this.reallyActive = false;\n *     }\n *     OO.inheritClass( StuffTool, OO.ui.Tool );\n *     StuffTool.static.name = 'stuff';\n *     StuffTool.static.icon = 'ellipsis';\n *     StuffTool.static.title = 'More stuff';\n *     StuffTool.prototype.onSelect = function () {\n *         $area.text( 'More stuff tool clicked!' );\n *         // Toggle the active state on each click\n *         this.reallyActive = !this.reallyActive;\n *         this.setActive( this.reallyActive );\n *         // To update the menu label\n *         this.toolbar.emit( 'updateState' );\n *     };\n *     StuffTool.prototype.onUpdateState = function () {};\n *     toolFactory.register( StuffTool );\n *\n *     // This is a PopupTool. Rather than having a custom 'onSelect' action, it will display a\n *     // little popup window (a PopupWidget). 'onUpdateState' is also already implemented.\n *     function HelpTool( toolGroup, config ) {\n *         OO.ui.PopupTool.call( this, toolGroup, $.extend( { popup: {\n *             padded: true,\n *             label: 'Help',\n *             head: true\n *         } }, config ) );\n *         this.popup.$body.append( '<p>I am helpful!</p>' );\n *     }\n *     OO.inheritClass( HelpTool, OO.ui.PopupTool );\n *     HelpTool.static.name = 'help';\n *     HelpTool.static.icon = 'help';\n *     HelpTool.static.title = 'Help';\n *     toolFactory.register( HelpTool );\n *\n *     // Finally define which tools and in what order appear in the toolbar. Each tool may only be\n *     // used once (but not all defined tools must be used).\n *     toolbar.setup( [\n *         {\n *             // 'bar' tool groups display tools' icons only, side-by-side.\n *             type: 'bar',\n *             include: [ 'search', 'help' ]\n *         },\n *         {\n *             // 'menu' tool groups display both the titles and icons, in a dropdown menu.\n *             // Menu label indicates which items are selected.\n *             type: 'menu',\n *             indicator: 'down',\n *             include: [ 'settings', 'stuff' ]\n *         }\n *     ] );\n *\n *     // Create some UI around the toolbar and place it in the document\n *     var frame = new OO.ui.PanelLayout( {\n *         expanded: false,\n *         framed: true\n *     } );\n *     var contentFrame = new OO.ui.PanelLayout( {\n *         expanded: false,\n *         padded: true\n *     } );\n *     frame.$element.append(\n *         toolbar.$element,\n *         contentFrame.$element.append( $area )\n *     );\n *     $( document.body ).append( frame.$element );\n *\n *     // Here is where the toolbar is actually built. This must be done after inserting it into the\n *     // document.\n *     toolbar.initialize();\n *     toolbar.emit( 'updateState' );\n *\n * @class\n * @extends OO.ui.Element\n * @mixins OO.EventEmitter\n * @mixins OO.ui.mixin.GroupElement\n *\n * @constructor\n * @param {OO.ui.ToolFactory} toolFactory Factory for creating tools\n * @param {OO.ui.ToolGroupFactory} toolGroupFactory Factory for creating toolgroups\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [actions] Add an actions section to the toolbar. Actions are commands that are\n *  included in the toolbar, but are not configured as tools. By default, actions are displayed on\n *  the right side of the toolbar.\n * @cfg {string} [position='top'] Whether the toolbar is positioned above ('top') or below\n *  ('bottom') content.\n * @cfg {jQuery} [$overlay] An overlay for the popup.\n *  See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.\n */\nOO.ui.Toolbar = function OoUiToolbar( toolFactory, toolGroupFactory, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( toolFactory ) && config === undefined ) {\n\t\tconfig = toolFactory;\n\t\ttoolFactory = config.toolFactory;\n\t\ttoolGroupFactory = config.toolGroupFactory;\n\t}\n\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.Toolbar.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.EventEmitter.call( this );\n\tOO.ui.mixin.GroupElement.call( this, config );\n\n\t// Properties\n\tthis.toolFactory = toolFactory;\n\tthis.toolGroupFactory = toolGroupFactory;\n\tthis.groupsByName = {};\n\tthis.activeToolGroups = 0;\n\tthis.tools = {};\n\tthis.position = config.position || 'top';\n\tthis.$bar = $( '<div>' );\n\tthis.$actions = $( '<div>' );\n\tthis.$popups = $( '<div>' );\n\tthis.initialized = false;\n\tthis.narrowThreshold = null;\n\tthis.onWindowResizeHandler = this.onWindowResize.bind( this );\n\tthis.$overlay = ( config.$overlay === true ? OO.ui.getDefaultOverlay() : config.$overlay ) ||\n\t\tthis.$element;\n\n\t// Events\n\tthis.$element\n\t\t.add( this.$bar ).add( this.$group ).add( this.$actions )\n\t\t.on( 'mousedown keydown', this.onPointerDown.bind( this ) );\n\n\t// Initialization\n\tthis.$group.addClass( 'oo-ui-toolbar-tools' );\n\tif ( config.actions ) {\n\t\tthis.$bar.append( this.$actions.addClass( 'oo-ui-toolbar-actions' ) );\n\t}\n\tthis.$popups.addClass( 'oo-ui-toolbar-popups' );\n\tthis.$bar\n\t\t.addClass( 'oo-ui-toolbar-bar' )\n\t\t.append( this.$group, '<div style=\"clear:both\"></div>' );\n\t// Possible classes: oo-ui-toolbar-position-top, oo-ui-toolbar-position-bottom\n\tthis.$element\n\t\t.addClass( 'oo-ui-toolbar oo-ui-toolbar-position-' + this.position )\n\t\t.append( this.$bar );\n\tthis.$overlay.append( this.$popups );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.Toolbar, OO.ui.Element );\nOO.mixinClass( OO.ui.Toolbar, OO.EventEmitter );\nOO.mixinClass( OO.ui.Toolbar, OO.ui.mixin.GroupElement );\n\n/* Events */\n\n/**\n * @event updateState\n *\n * An 'updateState' event must be emitted on the Toolbar (by calling\n * `toolbar.emit( 'updateState' )`) every time the state of the application using the toolbar\n * changes, and an update to the state of tools is required.\n *\n * @param {...Mixed} data Application-defined parameters\n */\n\n/**\n * @event active\n *\n * An 'active' event is emitted when the number of active toolgroups increases from 0, or\n * returns to 0.\n *\n * @param {boolean} There are active toolgroups in this toolbar\n */\n\n/* Methods */\n\n/**\n * Get the tool factory.\n *\n * @return {OO.ui.ToolFactory} Tool factory\n */\nOO.ui.Toolbar.prototype.getToolFactory = function () {\n\treturn this.toolFactory;\n};\n\n/**\n * Get the toolgroup factory.\n *\n * @return {OO.Factory} Toolgroup factory\n */\nOO.ui.Toolbar.prototype.getToolGroupFactory = function () {\n\treturn this.toolGroupFactory;\n};\n\n/**\n * Handles mouse down events.\n *\n * @private\n * @param {jQuery.Event} e Mouse down event\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.Toolbar.prototype.onPointerDown = function ( e ) {\n\tvar $closestWidgetToEvent = $( e.target ).closest( '.oo-ui-widget' ),\n\t\t$closestWidgetToToolbar = this.$element.closest( '.oo-ui-widget' );\n\tif (\n\t\t!$closestWidgetToEvent.length ||\n\t\t$closestWidgetToEvent[ 0 ] ===\n\t\t$closestWidgetToToolbar[ 0 ]\n\t) {\n\t\treturn false;\n\t}\n};\n\n/**\n * Handle window resize event.\n *\n * @private\n * @param {jQuery.Event} e Window resize event\n */\nOO.ui.Toolbar.prototype.onWindowResize = function () {\n\tthis.$element.add( this.$popups ).toggleClass(\n\t\t'oo-ui-toolbar-narrow',\n\t\tthis.$bar[ 0 ].clientWidth <= this.getNarrowThreshold()\n\t);\n};\n\n/**\n * Get the (lazily-computed) width threshold for applying the oo-ui-toolbar-narrow\n * class.\n *\n * @private\n * @return {number} Width threshold in pixels\n */\nOO.ui.Toolbar.prototype.getNarrowThreshold = function () {\n\tif ( this.narrowThreshold === null ) {\n\t\tthis.narrowThreshold = this.$group[ 0 ].offsetWidth + this.$actions[ 0 ].offsetWidth;\n\t}\n\treturn this.narrowThreshold;\n};\n\n/**\n * Sets up handles and preloads required information for the toolbar to work.\n * This must be called after it is attached to a visible document and before doing anything else.\n */\nOO.ui.Toolbar.prototype.initialize = function () {\n\tif ( !this.initialized ) {\n\t\tthis.initialized = true;\n\t\t$( this.getElementWindow() ).on( 'resize', this.onWindowResizeHandler );\n\t\tthis.onWindowResize();\n\t}\n};\n\n/**\n * Set up the toolbar.\n *\n * The toolbar is set up with a list of toolgroup configurations that specify the type of\n * toolgroup ({@link OO.ui.BarToolGroup bar}, {@link OO.ui.MenuToolGroup menu}, or\n * {@link OO.ui.ListToolGroup list}) to add and which tools to include, exclude, promote, or demote\n * within that toolgroup. Please see {@link OO.ui.ToolGroup toolgroups} for more information about\n * including tools in toolgroups.\n *\n * @param {Object.<string,Array>} groups List of toolgroup configurations\n * @param {string} [groups.name] Symbolic name for this toolgroup\n * @param {string} [groups.type] Toolgroup type, should exist in the toolgroup factory\n * @param {Array|string} [groups.include] Tools to include in the toolgroup\n * @param {Array|string} [groups.exclude] Tools to exclude from the toolgroup\n * @param {Array|string} [groups.promote] Tools to promote to the beginning of the toolgroup\n * @param {Array|string} [groups.demote] Tools to demote to the end of the toolgroup\n */\nOO.ui.Toolbar.prototype.setup = function ( groups ) {\n\tvar i, len, type, toolGroup, groupConfig,\n\t\titems = [],\n\t\tdefaultType = 'bar';\n\n\t// Cleanup previous groups\n\tthis.reset();\n\n\t// Build out new groups\n\tfor ( i = 0, len = groups.length; i < len; i++ ) {\n\t\tgroupConfig = groups[ i ];\n\t\tif ( groupConfig.include === '*' ) {\n\t\t\t// Apply defaults to catch-all groups\n\t\t\tif ( groupConfig.type === undefined ) {\n\t\t\t\tgroupConfig.type = 'list';\n\t\t\t}\n\t\t\tif ( groupConfig.label === undefined ) {\n\t\t\t\tgroupConfig.label = OO.ui.msg( 'ooui-toolbar-more' );\n\t\t\t}\n\t\t}\n\t\t// Check type has been registered\n\t\ttype = this.getToolGroupFactory().lookup( groupConfig.type ) ?\n\t\t\tgroupConfig.type : defaultType;\n\t\ttoolGroup = this.getToolGroupFactory().create( type, this, groupConfig );\n\t\titems.push( toolGroup );\n\t\tif ( groupConfig.name ) {\n\t\t\tthis.groupsByName[ groupConfig.name ] = toolGroup;\n\t\t} else {\n\t\t\t// Groups without name are deprecated\n\t\t\tOO.ui.warnDeprecation( 'Toolgroups must have a \\'name\\' property' );\n\t\t}\n\t\ttoolGroup.connect( this, {\n\t\t\tactive: 'onToolGroupActive'\n\t\t} );\n\t}\n\tthis.addItems( items );\n};\n\n/**\n * Handle active events from tool groups\n *\n * @param {boolean} active Tool group has become active, inactive if false\n * @fires active\n */\nOO.ui.Toolbar.prototype.onToolGroupActive = function ( active ) {\n\tif ( active ) {\n\t\tthis.activeToolGroups++;\n\t\tif ( this.activeToolGroups === 1 ) {\n\t\t\tthis.emit( 'active', true );\n\t\t}\n\t} else {\n\t\tthis.activeToolGroups--;\n\t\tif ( this.activeToolGroups === 0 ) {\n\t\t\tthis.emit( 'active', false );\n\t\t}\n\t}\n};\n\n/**\n * Get a toolgroup by name\n *\n * @param {string} name Group name\n * @return {OO.ui.ToolGroup|null} Tool group, or null if none found by that name\n */\nOO.ui.Toolbar.prototype.getToolGroupByName = function ( name ) {\n\treturn this.groupsByName[ name ] || null;\n};\n\n/**\n * Remove all tools and toolgroups from the toolbar.\n */\nOO.ui.Toolbar.prototype.reset = function () {\n\tvar i, len;\n\n\tthis.groupsByName = {};\n\tthis.tools = {};\n\tfor ( i = 0, len = this.items.length; i < len; i++ ) {\n\t\tthis.items[ i ].destroy();\n\t}\n\tthis.clearItems();\n};\n\n/**\n * Destroy the toolbar.\n *\n * Destroying the toolbar removes all event handlers and DOM elements that constitute the toolbar.\n * Call this method whenever you are done using a toolbar.\n */\nOO.ui.Toolbar.prototype.destroy = function () {\n\t$( this.getElementWindow() ).off( 'resize', this.onWindowResizeHandler );\n\tthis.reset();\n\tthis.$element.remove();\n};\n\n/**\n * Check if the tool is available.\n *\n * Available tools are ones that have not yet been added to the toolbar.\n *\n * @param {string} name Symbolic name of tool\n * @return {boolean} Tool is available\n */\nOO.ui.Toolbar.prototype.isToolAvailable = function ( name ) {\n\treturn !this.tools[ name ];\n};\n\n/**\n * Prevent tool from being used again.\n *\n * @param {OO.ui.Tool} tool Tool to reserve\n */\nOO.ui.Toolbar.prototype.reserveTool = function ( tool ) {\n\tthis.tools[ tool.getName() ] = tool;\n};\n\n/**\n * Allow tool to be used again.\n *\n * @param {OO.ui.Tool} tool Tool to release\n */\nOO.ui.Toolbar.prototype.releaseTool = function ( tool ) {\n\tdelete this.tools[ tool.getName() ];\n};\n\n/**\n * Get accelerator label for tool.\n *\n * The OOUI library does not contain an accelerator system, but this is the hook for one. To\n * use an accelerator system, subclass the toolbar and override this method, which is meant to\n * return a label that describes the accelerator keys for the tool passed (by symbolic name) to\n * the method.\n *\n * @param {string} name Symbolic name of tool\n * @return {string|undefined} Tool accelerator label if available\n */\nOO.ui.Toolbar.prototype.getToolAccelerator = function () {\n\treturn undefined;\n};\n","/**\n * Tools, together with {@link OO.ui.ToolGroup toolgroups}, constitute\n * {@link OO.ui.Toolbar toolbars}.\n * Each tool is configured with a static name, title, and icon and is customized with the command\n * to carry out when the tool is selected. Tools must also be registered with a\n * {@link OO.ui.ToolFactory tool factory}, which creates the tools on demand.\n *\n * Every Tool subclass must implement two methods:\n *\n * - {@link #onUpdateState}\n * - {@link #onSelect}\n *\n * Tools are added to toolgroups ({@link OO.ui.ListToolGroup ListToolGroup},\n * {@link OO.ui.BarToolGroup BarToolGroup}, or {@link OO.ui.MenuToolGroup MenuToolGroup}), which\n * determine how the tool is displayed in the toolbar. See {@link OO.ui.Toolbar toolbars} for an\n * example.\n *\n * For more information, please see the [OOUI documentation on MediaWiki][1].\n * [1]: https://www.mediawiki.org/wiki/OOUI/Toolbars\n *\n * @abstract\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.FlaggedElement\n * @mixins OO.ui.mixin.TabIndexedElement\n *\n * @constructor\n * @param {OO.ui.ToolGroup} toolGroup\n * @param {Object} [config] Configuration options\n * @cfg {string|Function} [title] Title text or a function that returns text. If this config is\n *  omitted, the value of the {@link #static-title static title} property is used.\n *\n *  The title is used in different ways depending on the type of toolgroup that contains the tool.\n *  The title is used as a tooltip if the tool is part of a {@link OO.ui.BarToolGroup bar}\n *  toolgroup, or as the label text if the tool is part of a {@link OO.ui.ListToolGroup list} or\n *  {@link OO.ui.MenuToolGroup menu} toolgroup.\n *\n *  For bar toolgroups, a description of the accelerator key is appended to the title if an\n *  accelerator key is associated with an action by the same name as the tool and accelerator\n *  functionality has been added to the application.\n *  To add accelerator key functionality, you must subclass OO.ui.Toolbar and override the\n *  {@link OO.ui.Toolbar#getToolAccelerator getToolAccelerator} method.\n */\nOO.ui.Tool = function OoUiTool( toolGroup, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( toolGroup ) && config === undefined ) {\n\t\tconfig = toolGroup;\n\t\ttoolGroup = config.toolGroup;\n\t}\n\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.Tool.parent.call( this, config );\n\n\t// Properties\n\tthis.toolGroup = toolGroup;\n\tthis.toolbar = this.toolGroup.getToolbar();\n\tthis.active = false;\n\tthis.$title = $( '<span>' );\n\tthis.$accel = $( '<span>' );\n\tthis.$link = $( '<a>' );\n\tthis.title = null;\n\tthis.checkIcon = new OO.ui.IconWidget( {\n\t\ticon: 'check',\n\t\tclasses: [ 'oo-ui-tool-checkIcon' ]\n\t} );\n\n\t// Mixin constructors\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.FlaggedElement.call( this, config );\n\tOO.ui.mixin.TabIndexedElement.call( this, $.extend( {\n\t\t$tabIndexed: this.$link\n\t}, config ) );\n\n\t// Events\n\tthis.toolbar.connect( this, {\n\t\tupdateState: 'onUpdateState'\n\t} );\n\n\t// Initialization\n\tthis.$title.addClass( 'oo-ui-tool-title' );\n\tthis.$accel\n\t\t.addClass( 'oo-ui-tool-accel' )\n\t\t.prop( {\n\t\t\t// This may need to be changed if the key names are ever localized,\n\t\t\t// but for now they are essentially written in English\n\t\t\tdir: 'ltr',\n\t\t\tlang: 'en'\n\t\t} );\n\tthis.$link\n\t\t.addClass( 'oo-ui-tool-link' )\n\t\t.append( this.checkIcon.$element, this.$icon, this.$title, this.$accel )\n\t\t.attr( 'role', 'button' );\n\tthis.$element\n\t\t.data( 'oo-ui-tool', this )\n\t\t.addClass( 'oo-ui-tool' )\n\t\t.addClass( 'oo-ui-tool-name-' +\n\t\t\tthis.constructor.static.name.replace( /^([^/]+)\\/([^/]+).*$/, '$1-$2' ) )\n\t\t.toggleClass( 'oo-ui-tool-with-label', this.constructor.static.displayBothIconAndLabel )\n\t\t.append( this.$link );\n\tthis.setTitle( config.title || this.constructor.static.title );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.Tool, OO.ui.Widget );\nOO.mixinClass( OO.ui.Tool, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.Tool, OO.ui.mixin.FlaggedElement );\nOO.mixinClass( OO.ui.Tool, OO.ui.mixin.TabIndexedElement );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.Tool.static.tagName = 'span';\n\n/**\n * Symbolic name of tool.\n *\n * The symbolic name is used internally to register the tool with a\n * {@link OO.ui.ToolFactory ToolFactory}. It can also be used when adding tools to toolgroups.\n *\n * @abstract\n * @static\n * @inheritable\n * @property {string}\n */\nOO.ui.Tool.static.name = '';\n\n/**\n * Symbolic name of the group.\n *\n * The group name is used to associate tools with each other so that they can be selected later by\n * a {@link OO.ui.ToolGroup toolgroup}.\n *\n * @abstract\n * @static\n * @inheritable\n * @property {string}\n */\nOO.ui.Tool.static.group = '';\n\n/**\n * Tool title text or a function that returns title text. The value of the static property is\n * overridden if the #title config option is used.\n *\n * @abstract\n * @static\n * @inheritable\n * @property {string|Function}\n */\nOO.ui.Tool.static.title = '';\n\n/**\n * Display both icon and label when the tool is used in a {@link OO.ui.BarToolGroup bar} toolgroup.\n * Normally only the icon is displayed, or only the label if no icon is given.\n *\n * @static\n * @inheritable\n * @property {boolean}\n */\nOO.ui.Tool.static.displayBothIconAndLabel = false;\n\n/**\n * Add tool to catch-all groups automatically.\n *\n * A catch-all group, which contains all tools that do not currently belong to a toolgroup,\n * can be included in a toolgroup using the wildcard selector, an asterisk (*).\n *\n * @static\n * @inheritable\n * @property {boolean}\n */\nOO.ui.Tool.static.autoAddToCatchall = true;\n\n/**\n * Add tool to named groups automatically.\n *\n * By default, tools that are configured with a static ‘group’ property are added\n * to that group and will be selected when the symbolic name of the group is specified (e.g., when\n * toolgroups include tools by group name).\n *\n * @static\n * @property {boolean}\n * @inheritable\n */\nOO.ui.Tool.static.autoAddToGroup = true;\n\n/**\n * Check if this tool is compatible with given data.\n *\n * This is a stub that can be overridden to provide support for filtering tools based on an\n * arbitrary piece of information  (e.g., where the cursor is in a document). The implementation\n * must also call this method so that the compatibility check can be performed.\n *\n * @static\n * @inheritable\n * @param {Mixed} data Data to check\n * @return {boolean} Tool can be used with data\n */\nOO.ui.Tool.static.isCompatibleWith = function () {\n\treturn false;\n};\n\n/* Methods */\n\n/**\n * Handle the toolbar state being updated. This method is called when the\n * {@link OO.ui.Toolbar#event-updateState 'updateState' event} is emitted on the\n * {@link OO.ui.Toolbar Toolbar} that uses this tool, and should set the state of this tool\n * depending on application state (usually by calling #setDisabled to enable or disable the tool,\n * or #setActive to mark is as currently in-use or not).\n *\n * This is an abstract method that must be overridden in a concrete subclass.\n *\n * @method\n * @protected\n * @abstract\n */\nOO.ui.Tool.prototype.onUpdateState = null;\n\n/**\n * Handle the tool being selected. This method is called when the user triggers this tool,\n * usually by clicking on its label/icon.\n *\n * This is an abstract method that must be overridden in a concrete subclass.\n *\n * @method\n * @protected\n * @abstract\n */\nOO.ui.Tool.prototype.onSelect = null;\n\n/**\n * Check if the tool is active.\n *\n * Tools become active when their #onSelect or #onUpdateState handlers change them to appear pressed\n * with the #setActive method. Additional CSS is applied to the tool to reflect the active state.\n *\n * @return {boolean} Tool is active\n */\nOO.ui.Tool.prototype.isActive = function () {\n\treturn this.active;\n};\n\n/**\n * Make the tool appear active or inactive.\n *\n * This method should be called within #onSelect or #onUpdateState event handlers to make the tool\n * appear pressed or not.\n *\n * @param {boolean} state Make tool appear active\n */\nOO.ui.Tool.prototype.setActive = function ( state ) {\n\tthis.active = !!state;\n\tthis.$element.toggleClass( 'oo-ui-tool-active', this.active );\n\tthis.updateThemeClasses();\n};\n\n/**\n * Set the tool #title.\n *\n * @param {string|Function} title Title text or a function that returns text\n * @chainable\n * @return {OO.ui.Tool} The tool, for chaining\n */\nOO.ui.Tool.prototype.setTitle = function ( title ) {\n\tthis.title = OO.ui.resolveMsg( title );\n\tthis.updateTitle();\n\treturn this;\n};\n\n/**\n * Get the tool #title.\n *\n * @return {string} Title text\n */\nOO.ui.Tool.prototype.getTitle = function () {\n\treturn this.title;\n};\n\n/**\n * Get the tool's symbolic name.\n *\n * @return {string} Symbolic name of tool\n */\nOO.ui.Tool.prototype.getName = function () {\n\treturn this.constructor.static.name;\n};\n\n/**\n * Update the title.\n */\nOO.ui.Tool.prototype.updateTitle = function () {\n\tvar titleTooltips = this.toolGroup.constructor.static.titleTooltips,\n\t\taccelTooltips = this.toolGroup.constructor.static.accelTooltips,\n\t\taccel = this.toolbar.getToolAccelerator( this.constructor.static.name ),\n\t\ttooltipParts = [];\n\n\tthis.$title.text( this.title );\n\tthis.$accel.text( accel );\n\n\tif ( titleTooltips && typeof this.title === 'string' && this.title.length ) {\n\t\ttooltipParts.push( this.title );\n\t}\n\tif ( accelTooltips && typeof accel === 'string' && accel.length ) {\n\t\ttooltipParts.push( accel );\n\t}\n\tif ( tooltipParts.length ) {\n\t\tthis.$link.attr( 'title', tooltipParts.join( ' ' ) );\n\t} else {\n\t\tthis.$link.removeAttr( 'title' );\n\t}\n};\n\n/**\n * @inheritdoc OO.ui.mixin.IconElement\n */\nOO.ui.Tool.prototype.setIcon = function ( icon ) {\n\t// Mixin method\n\tOO.ui.mixin.IconElement.prototype.setIcon.call( this, icon );\n\n\tthis.$element.toggleClass( 'oo-ui-tool-with-icon', !!this.icon );\n\n\treturn this;\n};\n\n/**\n * Destroy tool.\n *\n * Destroying the tool removes all event handlers and the tool’s DOM elements.\n * Call this method whenever you are done using a tool.\n */\nOO.ui.Tool.prototype.destroy = function () {\n\tthis.toolbar.disconnect( this );\n\tthis.$element.remove();\n};\n","/**\n * ToolGroups are collections of {@link OO.ui.Tool tools} that are used in a\n * {@link OO.ui.Toolbar toolbar}.\n * The type of toolgroup ({@link OO.ui.ListToolGroup list}, {@link OO.ui.BarToolGroup bar}, or\n * {@link OO.ui.MenuToolGroup menu}) to which a tool belongs determines how the tool is arranged\n * and displayed in the toolbar. Toolgroups themselves are created on demand with a\n * {@link OO.ui.ToolGroupFactory toolgroup factory}.\n *\n * Toolgroups can contain individual tools, groups of tools, or all available tools, as specified\n * using the `include` config option. See OO.ui.ToolFactory#extract on documentation of the format.\n * The options `exclude`, `promote`, and `demote` support the same formats.\n *\n * See {@link OO.ui.Toolbar toolbars} for a full example. For more information about toolbars in\n * general, please see the [OOUI documentation on MediaWiki][1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Toolbars\n *\n * @abstract\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.GroupElement\n *\n * @constructor\n * @param {OO.ui.Toolbar} toolbar\n * @param {Object} [config] Configuration options\n * @cfg {Array|string} [include] List of tools to include in the toolgroup, see above.\n * @cfg {Array|string} [exclude] List of tools to exclude from the toolgroup, see above.\n * @cfg {Array|string} [promote] List of tools to promote to the beginning of the toolgroup,\n *  see above.\n * @cfg {Array|string} [demote] List of tools to demote to the end of the toolgroup, see above.\n *  This setting is particularly useful when tools have been added to the toolgroup\n *  en masse (e.g., via the catch-all selector).\n */\nOO.ui.ToolGroup = function OoUiToolGroup( toolbar, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( toolbar ) && config === undefined ) {\n\t\tconfig = toolbar;\n\t\ttoolbar = config.toolbar;\n\t}\n\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.ToolGroup.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.GroupElement.call( this, config );\n\n\t// Properties\n\tthis.toolbar = toolbar;\n\tthis.tools = {};\n\tthis.pressed = null;\n\tthis.autoDisabled = false;\n\tthis.include = config.include || [];\n\tthis.exclude = config.exclude || [];\n\tthis.promote = config.promote || [];\n\tthis.demote = config.demote || [];\n\tthis.onDocumentMouseKeyUpHandler = this.onDocumentMouseKeyUp.bind( this );\n\n\t// Events\n\tthis.$group.on( {\n\t\tmousedown: this.onMouseKeyDown.bind( this ),\n\t\tmouseup: this.onMouseKeyUp.bind( this ),\n\t\tkeydown: this.onMouseKeyDown.bind( this ),\n\t\tkeyup: this.onMouseKeyUp.bind( this ),\n\t\tfocus: this.onMouseOverFocus.bind( this ),\n\t\tblur: this.onMouseOutBlur.bind( this ),\n\t\tmouseover: this.onMouseOverFocus.bind( this ),\n\t\tmouseout: this.onMouseOutBlur.bind( this )\n\t} );\n\tthis.toolbar.getToolFactory().connect( this, {\n\t\tregister: 'onToolFactoryRegister'\n\t} );\n\tthis.aggregate( {\n\t\tdisable: 'itemDisable'\n\t} );\n\tthis.connect( this, {\n\t\titemDisable: 'updateDisabled',\n\t\tdisable: 'onDisable'\n\t} );\n\n\t// Initialization\n\tthis.$group.addClass( 'oo-ui-toolGroup-tools' );\n\tthis.$element\n\t\t.addClass( 'oo-ui-toolGroup' )\n\t\t.append( this.$group );\n\tthis.onDisable( this.isDisabled() );\n\tthis.populate();\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ToolGroup, OO.ui.Widget );\nOO.mixinClass( OO.ui.ToolGroup, OO.ui.mixin.GroupElement );\n\n/* Events */\n\n/**\n * @event update\n */\n\n/**\n * @event active\n *\n * An 'active' event is emitted when any popup is shown/hidden.\n *\n * @param {boolean} The popup is visible\n */\n\n/* Static Properties */\n\n/**\n * Show labels in tooltips.\n *\n * @static\n * @inheritable\n * @property {boolean}\n */\nOO.ui.ToolGroup.static.titleTooltips = false;\n\n/**\n * Show acceleration labels in tooltips.\n *\n * Note: The OOUI library does not include an accelerator system, but does contain\n * a hook for one. To use an accelerator system, subclass the {@link OO.ui.Toolbar toolbar} and\n * override the {@link OO.ui.Toolbar#getToolAccelerator getToolAccelerator} method, which is\n * meant to return a label that describes the accelerator keys for a given tool (e.g., Control+M\n * key combination).\n *\n * @static\n * @inheritable\n * @property {boolean}\n */\nOO.ui.ToolGroup.static.accelTooltips = false;\n\n/**\n * Automatically disable the toolgroup when all tools are disabled\n *\n * @static\n * @inheritable\n * @property {boolean}\n */\nOO.ui.ToolGroup.static.autoDisable = true;\n\n/**\n * @abstract\n * @static\n * @inheritable\n * @property {string}\n */\nOO.ui.ToolGroup.static.name = null;\n\n/* Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.ToolGroup.prototype.isDisabled = function () {\n\treturn this.autoDisabled ||\n\t\tOO.ui.ToolGroup.parent.prototype.isDisabled.apply( this, arguments );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.ToolGroup.prototype.updateDisabled = function () {\n\tvar i, item, allDisabled = true;\n\n\tif ( this.constructor.static.autoDisable ) {\n\t\tfor ( i = this.items.length - 1; i >= 0; i-- ) {\n\t\t\titem = this.items[ i ];\n\t\t\tif ( !item.isDisabled() ) {\n\t\t\t\tallDisabled = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tthis.autoDisabled = allDisabled;\n\t}\n\tOO.ui.ToolGroup.parent.prototype.updateDisabled.apply( this, arguments );\n};\n\n/**\n * Handle disable events.\n *\n * @protected\n * @param {boolean} isDisabled\n */\nOO.ui.ToolGroup.prototype.onDisable = function ( isDisabled ) {\n\tthis.$group.toggleClass( 'oo-ui-toolGroup-disabled-tools', isDisabled );\n\tthis.$group.toggleClass( 'oo-ui-toolGroup-enabled-tools', !isDisabled );\n};\n\n/**\n * Handle mouse down and key down events.\n *\n * @protected\n * @param {jQuery.Event} e Mouse down or key down event\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.ToolGroup.prototype.onMouseKeyDown = function ( e ) {\n\tif (\n\t\t!this.isDisabled() && (\n\t\t\te.which === OO.ui.MouseButtons.LEFT ||\n\t\t\te.which === OO.ui.Keys.SPACE ||\n\t\t\te.which === OO.ui.Keys.ENTER\n\t\t)\n\t) {\n\t\tthis.pressed = this.findTargetTool( e );\n\t\tif ( this.pressed ) {\n\t\t\tthis.pressed.setActive( true );\n\t\t\tthis.getElementDocument().addEventListener(\n\t\t\t\t'mouseup',\n\t\t\t\tthis.onDocumentMouseKeyUpHandler,\n\t\t\t\ttrue\n\t\t\t);\n\t\t\tthis.getElementDocument().addEventListener(\n\t\t\t\t'keyup',\n\t\t\t\tthis.onDocumentMouseKeyUpHandler,\n\t\t\t\ttrue\n\t\t\t);\n\t\t\treturn false;\n\t\t}\n\t}\n};\n\n/**\n * Handle document mouse up and key up events.\n *\n * @protected\n * @param {MouseEvent|KeyboardEvent} e Mouse up or key up event\n */\nOO.ui.ToolGroup.prototype.onDocumentMouseKeyUp = function ( e ) {\n\tthis.getElementDocument().removeEventListener(\n\t\t'mouseup',\n\t\tthis.onDocumentMouseKeyUpHandler,\n\t\ttrue\n\t);\n\tthis.getElementDocument().removeEventListener(\n\t\t'keyup',\n\t\tthis.onDocumentMouseKeyUpHandler,\n\t\ttrue\n\t);\n\t// onMouseKeyUp may be called a second time, depending on where the mouse is when the button is\n\t// released, but since `this.pressed` will no longer be true, the second call will be ignored.\n\tthis.onMouseKeyUp( e );\n};\n\n/**\n * Handle mouse up and key up events.\n *\n * @protected\n * @param {MouseEvent|KeyboardEvent} e Mouse up or key up event\n */\nOO.ui.ToolGroup.prototype.onMouseKeyUp = function ( e ) {\n\tvar tool = this.findTargetTool( e );\n\n\tif (\n\t\t!this.isDisabled() && this.pressed && this.pressed === tool && (\n\t\t\te.which === OO.ui.MouseButtons.LEFT ||\n\t\t\te.which === OO.ui.Keys.SPACE ||\n\t\t\te.which === OO.ui.Keys.ENTER\n\t\t)\n\t) {\n\t\tthis.pressed.onSelect();\n\t\tthis.pressed = null;\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t}\n\n\tthis.pressed = null;\n};\n\n/**\n * Handle mouse over and focus events.\n *\n * @protected\n * @param {jQuery.Event} e Mouse over or focus event\n */\nOO.ui.ToolGroup.prototype.onMouseOverFocus = function ( e ) {\n\tvar tool = this.findTargetTool( e );\n\n\tif ( this.pressed && this.pressed === tool ) {\n\t\tthis.pressed.setActive( true );\n\t}\n};\n\n/**\n * Handle mouse out and blur events.\n *\n * @protected\n * @param {jQuery.Event} e Mouse out or blur event\n */\nOO.ui.ToolGroup.prototype.onMouseOutBlur = function ( e ) {\n\tvar tool = this.findTargetTool( e );\n\n\tif ( this.pressed && this.pressed === tool ) {\n\t\tthis.pressed.setActive( false );\n\t}\n};\n\n/**\n * Get the closest tool to a jQuery.Event.\n *\n * Only tool links are considered, which prevents other elements in the tool such as popups from\n * triggering tool group interactions.\n *\n * @private\n * @param {jQuery.Event} e\n * @return {OO.ui.Tool|null} Tool, `null` if none was found\n */\nOO.ui.ToolGroup.prototype.findTargetTool = function ( e ) {\n\tvar tool,\n\t\t$item = $( e.target ).closest( '.oo-ui-tool-link' );\n\n\tif ( $item.length ) {\n\t\ttool = $item.parent().data( 'oo-ui-tool' );\n\t}\n\n\treturn tool && !tool.isDisabled() ? tool : null;\n};\n\n/**\n * Handle tool registry register events.\n *\n * If a tool is registered after the group is created, we must repopulate the list to account for:\n *\n * - a tool being added that may be included\n * - a tool already included being overridden\n *\n * @protected\n * @param {string} name Symbolic name of tool\n */\nOO.ui.ToolGroup.prototype.onToolFactoryRegister = function () {\n\tthis.populate();\n};\n\n/**\n * Get the toolbar that contains the toolgroup.\n *\n * @return {OO.ui.Toolbar} Toolbar that contains the toolgroup\n */\nOO.ui.ToolGroup.prototype.getToolbar = function () {\n\treturn this.toolbar;\n};\n\n/**\n * Add and remove tools based on configuration.\n */\nOO.ui.ToolGroup.prototype.populate = function () {\n\tvar i, len, name, tool,\n\t\ttoolFactory = this.toolbar.getToolFactory(),\n\t\tnames = {},\n\t\tadd = [],\n\t\tremove = [],\n\t\tlist = this.toolbar.getToolFactory().getTools(\n\t\t\tthis.include, this.exclude, this.promote, this.demote\n\t\t);\n\n\t// Build a list of needed tools\n\tfor ( i = 0, len = list.length; i < len; i++ ) {\n\t\tname = list[ i ];\n\t\tif (\n\t\t\t// Tool exists\n\t\t\ttoolFactory.lookup( name ) &&\n\t\t\t// Tool is available or is already in this group\n\t\t\t( this.toolbar.isToolAvailable( name ) || this.tools[ name ] )\n\t\t) {\n\t\t\t// Hack to prevent infinite recursion via ToolGroupTool. We need to reserve the tool\n\t\t\t// before creating it, but we can't call reserveTool() yet because we haven't created\n\t\t\t// the tool.\n\t\t\tthis.toolbar.tools[ name ] = true;\n\t\t\ttool = this.tools[ name ];\n\t\t\tif ( !tool ) {\n\t\t\t\t// Auto-initialize tools on first use\n\t\t\t\tthis.tools[ name ] = tool = toolFactory.create( name, this );\n\t\t\t\ttool.updateTitle();\n\t\t\t}\n\t\t\tthis.toolbar.reserveTool( tool );\n\t\t\tadd.push( tool );\n\t\t\tnames[ name ] = true;\n\t\t}\n\t}\n\t// Remove tools that are no longer needed\n\tfor ( name in this.tools ) {\n\t\tif ( !names[ name ] ) {\n\t\t\tthis.tools[ name ].destroy();\n\t\t\tthis.toolbar.releaseTool( this.tools[ name ] );\n\t\t\tremove.push( this.tools[ name ] );\n\t\t\tdelete this.tools[ name ];\n\t\t}\n\t}\n\tif ( remove.length ) {\n\t\tthis.removeItems( remove );\n\t}\n\t// Update emptiness state\n\tif ( add.length ) {\n\t\tthis.$element.removeClass( 'oo-ui-toolGroup-empty' );\n\t} else {\n\t\tthis.$element.addClass( 'oo-ui-toolGroup-empty' );\n\t}\n\t// Re-add tools (moving existing ones to new locations)\n\tthis.addItems( add );\n\t// Disabled state may depend on items\n\tthis.updateDisabled();\n};\n\n/**\n * Destroy toolgroup.\n */\nOO.ui.ToolGroup.prototype.destroy = function () {\n\tvar name;\n\n\tthis.clearItems();\n\tthis.toolbar.getToolFactory().disconnect( this );\n\tfor ( name in this.tools ) {\n\t\tthis.toolbar.releaseTool( this.tools[ name ] );\n\t\tthis.tools[ name ].disconnect( this ).destroy();\n\t\tdelete this.tools[ name ];\n\t}\n\tthis.$element.remove();\n};\n","/**\n * A ToolFactory creates tools on demand. All tools ({@link OO.ui.Tool Tools},\n * {@link OO.ui.PopupTool PopupTools}, and {@link OO.ui.ToolGroupTool ToolGroupTools}) must be\n * registered with a tool factory. Tools are registered by their symbolic name. See\n * {@link OO.ui.Toolbar toolbars} for an example.\n *\n * For more information about toolbars in general, please see the\n * [OOUI documentation on MediaWiki][1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Toolbars\n *\n * @class\n * @extends OO.Factory\n * @constructor\n */\nOO.ui.ToolFactory = function OoUiToolFactory() {\n\t// Parent constructor\n\tOO.ui.ToolFactory.parent.call( this );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ToolFactory, OO.Factory );\n\n/* Methods */\n\n/**\n * Get tools from the factory.\n *\n * @param {Array|string} [include] Included tools, see #extract for format\n * @param {Array|string} [exclude] Excluded tools, see #extract for format\n * @param {Array|string} [promote] Promoted tools, see #extract for format\n * @param {Array|string} [demote] Demoted tools, see #extract for format\n * @return {string[]} List of tools\n */\nOO.ui.ToolFactory.prototype.getTools = function ( include, exclude, promote, demote ) {\n\tvar i, len, included, promoted, demoted,\n\t\tauto = [],\n\t\tused = {};\n\n\t// Collect included and not excluded tools\n\tincluded = OO.simpleArrayDifference( this.extract( include ), this.extract( exclude ) );\n\n\t// Promotion\n\tpromoted = this.extract( promote, used );\n\tdemoted = this.extract( demote, used );\n\n\t// Auto\n\tfor ( i = 0, len = included.length; i < len; i++ ) {\n\t\tif ( !used[ included[ i ] ] ) {\n\t\t\tauto.push( included[ i ] );\n\t\t}\n\t}\n\n\treturn promoted.concat( auto ).concat( demoted );\n};\n\n/**\n * Get a flat list of names from a list of names or groups.\n *\n * Normally, `collection` is an array of tool specifications. Tools can be specified in the\n * following ways:\n *\n * - To include an individual tool, use the symbolic name: `{ name: 'tool-name' }` or `'tool-name'`.\n * - To include all tools in a group, use the group name: `{ group: 'group-name' }`. (To assign the\n *   tool to a group, use OO.ui.Tool.static.group.)\n *\n * Alternatively, to include all tools that are not yet assigned to any other toolgroup, use the\n * catch-all selector `'*'`.\n *\n * If `used` is passed, tool names that appear as properties in this object will be considered\n * already assigned, and will not be returned even if specified otherwise. The tool names extracted\n * by this function call will be added as new properties in the object.\n *\n * @private\n * @param {Array|string} collection List of tools, see above\n * @param {Object} [used] Object containing information about used tools, see above\n * @return {string[]} List of extracted tool names\n */\nOO.ui.ToolFactory.prototype.extract = function ( collection, used ) {\n\tvar i, len, item, name, tool,\n\t\tnames = [];\n\n\tcollection = !Array.isArray( collection ) ? [ collection ] : collection;\n\n\tfor ( i = 0, len = collection.length; i < len; i++ ) {\n\t\titem = collection[ i ];\n\t\tif ( item === '*' ) {\n\t\t\tfor ( name in this.registry ) {\n\t\t\t\ttool = this.registry[ name ];\n\t\t\t\tif (\n\t\t\t\t\t// Only add tools by group name when auto-add is enabled\n\t\t\t\t\ttool.static.autoAddToCatchall &&\n\t\t\t\t\t// Exclude already used tools\n\t\t\t\t\t( !used || !used[ name ] )\n\t\t\t\t) {\n\t\t\t\t\tnames.push( name );\n\t\t\t\t\tif ( used ) {\n\t\t\t\t\t\tused[ name ] = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// Allow plain strings as shorthand for named tools\n\t\t\tif ( typeof item === 'string' ) {\n\t\t\t\titem = { name: item };\n\t\t\t}\n\t\t\tif ( OO.isPlainObject( item ) ) {\n\t\t\t\tif ( item.group ) {\n\t\t\t\t\tfor ( name in this.registry ) {\n\t\t\t\t\t\ttool = this.registry[ name ];\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t// Include tools with matching group\n\t\t\t\t\t\t\ttool.static.group === item.group &&\n\t\t\t\t\t\t\t// Only add tools by group name when auto-add is enabled\n\t\t\t\t\t\t\ttool.static.autoAddToGroup &&\n\t\t\t\t\t\t\t// Exclude already used tools\n\t\t\t\t\t\t\t( !used || !used[ name ] )\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tnames.push( name );\n\t\t\t\t\t\t\tif ( used ) {\n\t\t\t\t\t\t\t\tused[ name ] = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t// Include tools with matching name and exclude already used tools\n\t\t\t\t} else if ( item.name && ( !used || !used[ item.name ] ) ) {\n\t\t\t\t\tnames.push( item.name );\n\t\t\t\t\tif ( used ) {\n\t\t\t\t\t\tused[ item.name ] = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn names;\n};\n","/**\n * ToolGroupFactories create {@link OO.ui.ToolGroup toolgroups} on demand. The toolgroup classes\n * must specify a symbolic name and be registered with the factory. The following classes are\n * registered by default:\n *\n * - {@link OO.ui.BarToolGroup BarToolGroups} (‘bar’)\n * - {@link OO.ui.MenuToolGroup MenuToolGroups} (‘menu’)\n * - {@link OO.ui.ListToolGroup ListToolGroups} (‘list’)\n *\n * See {@link OO.ui.Toolbar toolbars} for an example.\n *\n * For more information about toolbars in general, please see the\n * [OOUI documentation on MediaWiki][1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Toolbars\n *\n * @class\n * @extends OO.Factory\n * @constructor\n */\nOO.ui.ToolGroupFactory = function OoUiToolGroupFactory() {\n\tvar i, l, defaultClasses;\n\t// Parent constructor\n\tOO.Factory.call( this );\n\n\tdefaultClasses = this.constructor.static.getDefaultClasses();\n\n\t// Register default toolgroups\n\tfor ( i = 0, l = defaultClasses.length; i < l; i++ ) {\n\t\tthis.register( defaultClasses[ i ] );\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ToolGroupFactory, OO.Factory );\n\n/* Static Methods */\n\n/**\n * Get a default set of classes to be registered on construction.\n *\n * @return {Function[]} Default classes\n */\nOO.ui.ToolGroupFactory.static.getDefaultClasses = function () {\n\treturn [\n\t\tOO.ui.BarToolGroup,\n\t\tOO.ui.ListToolGroup,\n\t\tOO.ui.MenuToolGroup\n\t];\n};\n","/**\n * Popup tools open a popup window when they are selected from the {@link OO.ui.Toolbar toolbar}.\n * Each popup tool is configured with a static name, title, and icon, as well with as any popup\n * configurations. Unlike other tools, popup tools do not require that developers specify an\n * #onSelect or #onUpdateState method, as these methods have been implemented already.\n *\n *     // Example of a popup tool. When selected, a popup tool displays\n *     // a popup window.\n *     function HelpTool( toolGroup, config ) {\n *        OO.ui.PopupTool.call( this, toolGroup, $.extend( { popup: {\n *            padded: true,\n *            label: 'Help',\n *            head: true\n *        } }, config ) );\n *        this.popup.$body.append( '<p>I am helpful!</p>' );\n *     };\n *     OO.inheritClass( HelpTool, OO.ui.PopupTool );\n *     HelpTool.static.name = 'help';\n *     HelpTool.static.icon = 'help';\n *     HelpTool.static.title = 'Help';\n *     toolFactory.register( HelpTool );\n *\n * For an example of a toolbar that contains a popup tool, see {@link OO.ui.Toolbar toolbars}.\n * For more information about toolbars in general, please see the\n * [OOUI documentation on MediaWiki][1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Toolbars\n *\n * @abstract\n * @class\n * @extends OO.ui.Tool\n * @mixins OO.ui.mixin.PopupElement\n *\n * @constructor\n * @param {OO.ui.ToolGroup} toolGroup\n * @param {Object} [config] Configuration options\n */\nOO.ui.PopupTool = function OoUiPopupTool( toolGroup, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( toolGroup ) && config === undefined ) {\n\t\tconfig = toolGroup;\n\t\ttoolGroup = config.toolGroup;\n\t}\n\n\t// Parent constructor\n\tOO.ui.PopupTool.parent.call( this, toolGroup, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.PopupElement.call( this, config );\n\n\t// Events\n\tthis.popup.connect( this, {\n\t\ttoggle: 'onPopupToggle'\n\t} );\n\n\t// Initialization\n\tthis.popup.setAutoFlip( false );\n\tthis.popup.setPosition( toolGroup.getToolbar().position === 'bottom' ? 'above' : 'below' );\n\tthis.$element.addClass( 'oo-ui-popupTool' );\n\tthis.popup.$element.addClass( 'oo-ui-popupTool-popup' );\n\tthis.toolbar.$popups.append( this.popup.$element );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.PopupTool, OO.ui.Tool );\nOO.mixinClass( OO.ui.PopupTool, OO.ui.mixin.PopupElement );\n\n/* Methods */\n\n/**\n * Handle the tool being selected.\n *\n * @inheritdoc\n */\nOO.ui.PopupTool.prototype.onSelect = function () {\n\tif ( !this.isDisabled() ) {\n\t\tthis.popup.toggle();\n\t}\n\treturn false;\n};\n\n/**\n * Handle the toolbar state being updated.\n *\n * @inheritdoc\n */\nOO.ui.PopupTool.prototype.onUpdateState = function () {\n};\n\n/**\n * Handle popup visibility being toggled.\n *\n * @param {boolean} isVisible\n */\nOO.ui.PopupTool.prototype.onPopupToggle = function ( isVisible ) {\n\tthis.setActive( isVisible );\n\tthis.toolGroup.emit( 'active', isVisible );\n};\n","/**\n * A ToolGroupTool is a special sort of tool that can contain other {@link OO.ui.Tool tools}\n * and {@link OO.ui.ToolGroup toolgroups}. The ToolGroupTool was specifically designed to be used\n * inside a {@link OO.ui.BarToolGroup bar} toolgroup to provide access to additional tools from\n * the bar item. Included tools will be displayed in a dropdown {@link OO.ui.ListToolGroup list}\n * when the ToolGroupTool is selected.\n *\n *     // Example: ToolGroupTool with two nested tools, 'setting1' and 'setting2',\n *     // defined elsewhere.\n *\n *     function SettingsTool() {\n *         SettingsTool.parent.apply( this, arguments );\n *     };\n *     OO.inheritClass( SettingsTool, OO.ui.ToolGroupTool );\n *     SettingsTool.static.name = 'settings';\n *     SettingsTool.static.title = 'Change settings';\n *     SettingsTool.static.groupConfig = {\n *         icon: 'settings',\n *         label: 'ToolGroupTool',\n *         include: [  'setting1', 'setting2'  ]\n *     };\n *     toolFactory.register( SettingsTool );\n *\n * For more information, please see the [OOUI documentation on MediaWiki][1].\n *\n * Please note that this implementation is subject to change per [T74159] [2].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Toolbars#ToolGroupTool\n * [2]: https://phabricator.wikimedia.org/T74159\n *\n * @abstract\n * @class\n * @extends OO.ui.Tool\n *\n * @constructor\n * @param {OO.ui.ToolGroup} toolGroup\n * @param {Object} [config] Configuration options\n */\nOO.ui.ToolGroupTool = function OoUiToolGroupTool( toolGroup, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( toolGroup ) && config === undefined ) {\n\t\tconfig = toolGroup;\n\t\ttoolGroup = config.toolGroup;\n\t}\n\n\t// Parent constructor\n\tOO.ui.ToolGroupTool.parent.call( this, toolGroup, config );\n\n\t// Properties\n\tthis.innerToolGroup = this.createGroup( this.constructor.static.groupConfig );\n\n\t// Events\n\tthis.innerToolGroup.connect( this, {\n\t\tdisable: 'onToolGroupDisable',\n\t\t// Re-emit active events from the innerToolGroup on the parent toolGroup\n\t\tactive: this.toolGroup.emit.bind( this.toolGroup, 'active' )\n\t} );\n\n\t// Initialization\n\tthis.$link.remove();\n\tthis.$element\n\t\t.addClass( 'oo-ui-toolGroupTool' )\n\t\t.append( this.innerToolGroup.$element );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ToolGroupTool, OO.ui.Tool );\n\n/* Static Properties */\n\n/**\n * Toolgroup configuration.\n *\n * The toolgroup configuration consists of the tools to include, as well as an icon and label\n * to use for the bar item. Tools can be included by symbolic name, group, or with the\n * wildcard selector. Please see {@link OO.ui.ToolGroup toolgroup} for more information.\n *\n * @property {Object.<string,Array>}\n */\nOO.ui.ToolGroupTool.static.groupConfig = {};\n\n/* Methods */\n\n/**\n * Handle the tool being selected.\n *\n * @inheritdoc\n */\nOO.ui.ToolGroupTool.prototype.onSelect = function () {\n\tthis.innerToolGroup.setActive( !this.innerToolGroup.active );\n\treturn false;\n};\n\n/**\n * Synchronize disabledness state of the tool with the inner toolgroup.\n *\n * @private\n * @param {boolean} disabled Element is disabled\n */\nOO.ui.ToolGroupTool.prototype.onToolGroupDisable = function ( disabled ) {\n\tthis.setDisabled( disabled );\n};\n\n/**\n * Handle the toolbar state being updated.\n *\n * @inheritdoc\n */\nOO.ui.ToolGroupTool.prototype.onUpdateState = function () {\n\tthis.setActive( false );\n};\n\n/**\n * Build a {@link OO.ui.ToolGroup toolgroup} from the specified configuration.\n *\n * @param {Object.<string,Array>} group Toolgroup configuration. Please see\n *  {@link OO.ui.ToolGroup toolgroup} for more information.\n * @return {OO.ui.ListToolGroup}\n */\nOO.ui.ToolGroupTool.prototype.createGroup = function ( group ) {\n\tif ( group.include === '*' ) {\n\t\t// Apply defaults to catch-all groups\n\t\tif ( group.label === undefined ) {\n\t\t\tgroup.label = OO.ui.msg( 'ooui-toolbar-more' );\n\t\t}\n\t}\n\n\treturn this.toolbar.getToolGroupFactory().create( 'list', this.toolbar, group );\n};\n","/**\n * BarToolGroups are one of three types of {@link OO.ui.ToolGroup toolgroups} that are used to\n * create {@link OO.ui.Toolbar toolbars} (the other types of groups are\n * {@link OO.ui.MenuToolGroup MenuToolGroup} and {@link OO.ui.ListToolGroup ListToolGroup}).\n * The {@link OO.ui.Tool tools} in a BarToolGroup are displayed by icon in a single row. The\n * title of the tool is displayed when users move the mouse over the tool.\n *\n * BarToolGroups are created by a {@link OO.ui.ToolGroupFactory tool group factory} when the toolbar\n * is set up.\n *\n *     @example\n *     // Example of a BarToolGroup with two tools\n *     var toolFactory = new OO.ui.ToolFactory();\n *     var toolGroupFactory = new OO.ui.ToolGroupFactory();\n *     var toolbar = new OO.ui.Toolbar( toolFactory, toolGroupFactory );\n *\n *     // We will be placing status text in this element when tools are used\n *     var $area = $( '<p>' ).text( 'Example of a BarToolGroup with two tools.' );\n *\n *     // Define the tools that we're going to place in our toolbar\n *\n *     // Create a class inheriting from OO.ui.Tool\n *     function SearchTool() {\n *         SearchTool.parent.apply( this, arguments );\n *     }\n *     OO.inheritClass( SearchTool, OO.ui.Tool );\n *     // Each tool must have a 'name' (used as an internal identifier, see later) and at least one\n *     // of 'icon' and 'title' (displayed icon and text).\n *     SearchTool.static.name = 'search';\n *     SearchTool.static.icon = 'search';\n *     SearchTool.static.title = 'Search...';\n *     // Defines the action that will happen when this tool is selected (clicked).\n *     SearchTool.prototype.onSelect = function () {\n *         $area.text( 'Search tool clicked!' );\n *         // Never display this tool as \"active\" (selected).\n *         this.setActive( false );\n *     };\n *     SearchTool.prototype.onUpdateState = function () {};\n *     // Make this tool available in our toolFactory and thus our toolbar\n *     toolFactory.register( SearchTool );\n *\n *     // This is a PopupTool. Rather than having a custom 'onSelect' action, it will display a\n *     // little popup window (a PopupWidget).\n *     function HelpTool( toolGroup, config ) {\n *         OO.ui.PopupTool.call( this, toolGroup, $.extend( { popup: {\n *             padded: true,\n *             label: 'Help',\n *             head: true\n *         } }, config ) );\n *         this.popup.$body.append( '<p>I am helpful!</p>' );\n *     }\n *     OO.inheritClass( HelpTool, OO.ui.PopupTool );\n *     HelpTool.static.name = 'help';\n *     HelpTool.static.icon = 'help';\n *     HelpTool.static.title = 'Help';\n *     toolFactory.register( HelpTool );\n *\n *     // Finally define which tools and in what order appear in the toolbar. Each tool may only be\n *     // used once (but not all defined tools must be used).\n *     toolbar.setup( [\n *         {\n *             // 'bar' tool groups display tools by icon only\n *             type: 'bar',\n *             include: [ 'search', 'help' ]\n *         }\n *     ] );\n *\n *     // Create some UI around the toolbar and place it in the document\n *     var frame = new OO.ui.PanelLayout( {\n *         expanded: false,\n *         framed: true\n *     } );\n *     var contentFrame = new OO.ui.PanelLayout( {\n *         expanded: false,\n *         padded: true\n *     } );\n *     frame.$element.append(\n *         toolbar.$element,\n *         contentFrame.$element.append( $area )\n *     );\n *     $( document.body ).append( frame.$element );\n *\n *     // Here is where the toolbar is actually built. This must be done after inserting it into the\n *     // document.\n *     toolbar.initialize();\n *\n * For more information about how to add tools to a bar tool group, please see\n * {@link OO.ui.ToolGroup toolgroup}.\n * For more information about toolbars in general, please see the\n * [OOUI documentation on MediaWiki][1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Toolbars\n *\n * @class\n * @extends OO.ui.ToolGroup\n *\n * @constructor\n * @param {OO.ui.Toolbar} toolbar\n * @param {Object} [config] Configuration options\n */\nOO.ui.BarToolGroup = function OoUiBarToolGroup( toolbar, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( toolbar ) && config === undefined ) {\n\t\tconfig = toolbar;\n\t\ttoolbar = config.toolbar;\n\t}\n\n\t// Parent constructor\n\tOO.ui.BarToolGroup.parent.call( this, toolbar, config );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-barToolGroup' );\n\tthis.$group.addClass( 'oo-ui-barToolGroup-tools' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.BarToolGroup, OO.ui.ToolGroup );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.BarToolGroup.static.titleTooltips = true;\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.BarToolGroup.static.accelTooltips = true;\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.BarToolGroup.static.name = 'bar';\n","/**\n * PopupToolGroup is an abstract base class used by both {@link OO.ui.MenuToolGroup MenuToolGroup}\n * and {@link OO.ui.ListToolGroup ListToolGroup} to provide a popup (an overlaid menu or list of\n * tools with an optional icon and label). This class can be used for other base classes that\n * also use this functionality.\n *\n * @abstract\n * @class\n * @extends OO.ui.ToolGroup\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.IndicatorElement\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.TitledElement\n * @mixins OO.ui.mixin.FlaggedElement\n * @mixins OO.ui.mixin.ClippableElement\n * @mixins OO.ui.mixin.FloatableElement\n * @mixins OO.ui.mixin.TabIndexedElement\n *\n * @constructor\n * @param {OO.ui.Toolbar} toolbar\n * @param {Object} [config] Configuration options\n * @cfg {string} [header] Text to display at the top of the popup\n */\nOO.ui.PopupToolGroup = function OoUiPopupToolGroup( toolbar, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( toolbar ) && config === undefined ) {\n\t\tconfig = toolbar;\n\t\ttoolbar = config.toolbar;\n\t}\n\n\t// Configuration initialization\n\tconfig = $.extend( {\n\t\tindicator: config.indicator === undefined ?\n\t\t\t( toolbar.position === 'bottom' ? 'up' : 'down' ) : config.indicator\n\t}, config );\n\n\t// Parent constructor\n\tOO.ui.PopupToolGroup.parent.call( this, toolbar, config );\n\n\t// Properties\n\tthis.active = false;\n\tthis.dragging = false;\n\t// Don't conflict with parent method of the same name\n\tthis.onPopupDocumentMouseKeyUpHandler = this.onPopupDocumentMouseKeyUp.bind( this );\n\tthis.$handle = $( '<span>' );\n\n\t// Mixin constructors\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.IndicatorElement.call( this, config );\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.TitledElement.call( this, config );\n\tOO.ui.mixin.FlaggedElement.call( this, config );\n\tOO.ui.mixin.ClippableElement.call( this, $.extend( {\n\t\t$clippable: this.$group\n\t}, config ) );\n\tOO.ui.mixin.FloatableElement.call( this, $.extend( {\n\t\t$floatable: this.$group,\n\t\t$floatableContainer: this.$handle,\n\t\thideWhenOutOfView: false,\n\t\tverticalPosition: this.toolbar.position === 'bottom' ? 'above' : 'below'\n\t}, config ) );\n\tOO.ui.mixin.TabIndexedElement.call( this, $.extend( {\n\t\t$tabIndexed: this.$handle\n\t}, config ) );\n\n\t// Events\n\tthis.$handle.on( {\n\t\tkeydown: this.onHandleMouseKeyDown.bind( this ),\n\t\tkeyup: this.onHandleMouseKeyUp.bind( this ),\n\t\tmousedown: this.onHandleMouseKeyDown.bind( this ),\n\t\tmouseup: this.onHandleMouseKeyUp.bind( this )\n\t} );\n\n\t// Initialization\n\tthis.$handle\n\t\t.addClass( 'oo-ui-popupToolGroup-handle' )\n\t\t.attr( 'role', 'button' )\n\t\t.append( this.$icon, this.$label, this.$indicator );\n\t// If the pop-up should have a header, add it to the top of the toolGroup.\n\t// Note: If this feature is useful for other widgets, we could abstract it into an\n\t// OO.ui.HeaderedElement mixin constructor.\n\tif ( config.header !== undefined ) {\n\t\tthis.$group\n\t\t\t.prepend( $( '<span>' )\n\t\t\t\t.addClass( 'oo-ui-popupToolGroup-header' )\n\t\t\t\t.text( config.header )\n\t\t\t);\n\t}\n\tthis.$element\n\t\t.addClass( 'oo-ui-popupToolGroup' )\n\t\t.prepend( this.$handle );\n\tthis.$group.addClass( 'oo-ui-popupToolGroup-tools' );\n\tthis.toolbar.$popups.append( this.$group );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.PopupToolGroup, OO.ui.ToolGroup );\nOO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.IndicatorElement );\nOO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.TitledElement );\nOO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.FlaggedElement );\nOO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.ClippableElement );\nOO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.FloatableElement );\nOO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.TabIndexedElement );\n\n/* Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.PopupToolGroup.prototype.setDisabled = function () {\n\t// Parent method\n\tOO.ui.PopupToolGroup.parent.prototype.setDisabled.apply( this, arguments );\n\n\tif ( this.isDisabled() && this.isElementAttached() ) {\n\t\tthis.setActive( false );\n\t}\n};\n\n/**\n * Handle document mouse up and key up events.\n *\n * @protected\n * @param {MouseEvent|KeyboardEvent} e Mouse up or key up event\n */\nOO.ui.PopupToolGroup.prototype.onPopupDocumentMouseKeyUp = function ( e ) {\n\tvar $target = $( e.target );\n\t// Only deactivate when clicking outside the dropdown element\n\tif ( $target.closest( '.oo-ui-popupToolGroup' )[ 0 ] === this.$element[ 0 ] ) {\n\t\treturn;\n\t}\n\tif ( $target.closest( '.oo-ui-popupToolGroup-tools' )[ 0 ] === this.$group[ 0 ] ) {\n\t\treturn;\n\t}\n\tthis.setActive( false );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.PopupToolGroup.prototype.onMouseKeyUp = function ( e ) {\n\t// Only close toolgroup when a tool was actually selected\n\tif (\n\t\t!this.isDisabled() && this.pressed && this.pressed === this.findTargetTool( e ) && (\n\t\t\te.which === OO.ui.MouseButtons.LEFT ||\n\t\t\te.which === OO.ui.Keys.SPACE ||\n\t\t\te.which === OO.ui.Keys.ENTER\n\t\t)\n\t) {\n\t\tthis.setActive( false );\n\t}\n\treturn OO.ui.PopupToolGroup.parent.prototype.onMouseKeyUp.call( this, e );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.PopupToolGroup.prototype.onMouseKeyDown = function ( e ) {\n\tvar $focused, $firstFocusable, $lastFocusable;\n\t// Shift-Tab on the first tool in the group jumps to the handle.\n\t// Tab on the last tool in the group jumps to the next group.\n\tif ( !this.isDisabled() && e.which === OO.ui.Keys.TAB ) {\n\t\t// We can't use this.items because ListToolGroup inserts the extra fake\n\t\t// expand/collapse tool.\n\t\t$focused = $( document.activeElement );\n\t\t$firstFocusable = OO.ui.findFocusable( this.$group );\n\t\tif ( $focused[ 0 ] === $firstFocusable[ 0 ] && e.shiftKey ) {\n\t\t\tthis.$handle.trigger( 'focus' );\n\t\t\treturn false;\n\t\t}\n\t\t$lastFocusable = OO.ui.findFocusable( this.$group, true );\n\t\tif ( $focused[ 0 ] === $lastFocusable[ 0 ] && !e.shiftKey ) {\n\t\t\t// Focus this group's handle and let the browser's tab handling happen\n\t\t\t// (no 'return false').\n\t\t\t// This way we don't have to fiddle with other ToolGroups' business, or worry what to do\n\t\t\t// if the next group is not a PopupToolGroup or doesn't exist at all.\n\t\t\tthis.$handle.trigger( 'focus' );\n\t\t\t// Close the popup so that we don't move back inside it (if this is the last group).\n\t\t\tthis.setActive( false );\n\t\t}\n\t}\n\treturn OO.ui.PopupToolGroup.parent.prototype.onMouseKeyDown.call( this, e );\n};\n\n/**\n * Handle mouse up and key up events.\n *\n * @protected\n * @param {jQuery.Event} e Mouse up or key up event\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.PopupToolGroup.prototype.onHandleMouseKeyUp = function ( e ) {\n\tif (\n\t\t!this.isDisabled() && (\n\t\t\te.which === OO.ui.MouseButtons.LEFT ||\n\t\t\te.which === OO.ui.Keys.SPACE ||\n\t\t\te.which === OO.ui.Keys.ENTER\n\t\t)\n\t) {\n\t\treturn false;\n\t}\n};\n\n/**\n * Handle mouse down and key down events.\n *\n * @protected\n * @param {jQuery.Event} e Mouse down or key down event\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.PopupToolGroup.prototype.onHandleMouseKeyDown = function ( e ) {\n\tvar $focusable;\n\tif ( !this.isDisabled() ) {\n\t\t// Tab on the handle jumps to the first tool in the group (if the popup is open).\n\t\tif ( e.which === OO.ui.Keys.TAB && !e.shiftKey ) {\n\t\t\t$focusable = OO.ui.findFocusable( this.$group );\n\t\t\tif ( $focusable.length ) {\n\t\t\t\t$focusable.trigger( 'focus' );\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\tif (\n\t\t\te.which === OO.ui.MouseButtons.LEFT ||\n\t\t\te.which === OO.ui.Keys.SPACE ||\n\t\t\te.which === OO.ui.Keys.ENTER\n\t\t) {\n\t\t\tthis.setActive( !this.active );\n\t\t\treturn false;\n\t\t}\n\t}\n};\n\n/**\n * Check if the tool group is active.\n *\n * @return {boolean} Tool group is active\n */\nOO.ui.PopupToolGroup.prototype.isActive = function () {\n\treturn this.active;\n};\n\n/**\n * Switch into 'active' mode.\n *\n * When active, the popup is visible. A mouseup event anywhere in the document will trigger\n * deactivation.\n *\n * @param {boolean} value The active state to set\n * @fires active\n */\nOO.ui.PopupToolGroup.prototype.setActive = function ( value ) {\n\tvar containerWidth, containerLeft;\n\tvalue = !!value;\n\tif ( this.active !== value ) {\n\t\tthis.active = value;\n\t\tif ( value ) {\n\t\t\tthis.getElementDocument().addEventListener(\n\t\t\t\t'mouseup',\n\t\t\t\tthis.onPopupDocumentMouseKeyUpHandler,\n\t\t\t\ttrue\n\t\t\t);\n\t\t\tthis.getElementDocument().addEventListener(\n\t\t\t\t'keyup',\n\t\t\t\tthis.onPopupDocumentMouseKeyUpHandler,\n\t\t\t\ttrue\n\t\t\t);\n\n\t\t\tthis.$clippable.css( 'left', '' );\n\t\t\tthis.$element.addClass( 'oo-ui-popupToolGroup-active' );\n\t\t\tthis.$group.addClass( 'oo-ui-popupToolGroup-active-tools' );\n\t\t\tthis.togglePositioning( true );\n\t\t\tthis.toggleClipping( true );\n\n\t\t\t// Try anchoring the popup to the left first\n\t\t\tthis.setHorizontalPosition( 'start' );\n\n\t\t\tif ( this.isClippedHorizontally() || this.isFloatableOutOfView() ) {\n\t\t\t\t// Anchoring to the left caused the popup to clip, so anchor it to the\n\t\t\t\t// right instead.\n\t\t\t\tthis.setHorizontalPosition( 'end' );\n\t\t\t}\n\t\t\tif ( this.isClippedHorizontally() || this.isFloatableOutOfView() ) {\n\t\t\t\t// Anchoring to the right also caused the popup to clip, so just make it fill the\n\t\t\t\t// container.\n\t\t\t\tcontainerWidth = this.$clippableScrollableContainer.width();\n\t\t\t\tcontainerLeft = this.$clippableScrollableContainer[ 0 ] ===\n\t\t\t\t\tdocument.documentElement ?\n\t\t\t\t\t0 :\n\t\t\t\t\tthis.$clippableScrollableContainer.offset().left;\n\n\t\t\t\tthis.toggleClipping( false );\n\t\t\t\tthis.setHorizontalPosition( 'start' );\n\n\t\t\t\tthis.$clippable.css( {\n\t\t\t\t\t'margin-left': -( this.$element.offset().left - containerLeft ),\n\t\t\t\t\twidth: containerWidth\n\t\t\t\t} );\n\t\t\t}\n\t\t} else {\n\t\t\tthis.getElementDocument().removeEventListener(\n\t\t\t\t'mouseup',\n\t\t\t\tthis.onPopupDocumentMouseKeyUpHandler,\n\t\t\t\ttrue\n\t\t\t);\n\t\t\tthis.getElementDocument().removeEventListener(\n\t\t\t\t'keyup',\n\t\t\t\tthis.onPopupDocumentMouseKeyUpHandler,\n\t\t\t\ttrue\n\t\t\t);\n\t\t\tthis.$element.removeClass( 'oo-ui-popupToolGroup-active' );\n\t\t\tthis.$group.removeClass( 'oo-ui-popupToolGroup-active-tools' );\n\t\t\tthis.togglePositioning( false );\n\t\t\tthis.toggleClipping( false );\n\t\t}\n\t\tthis.emit( 'active', this.active );\n\t\tthis.updateThemeClasses();\n\t}\n};\n","/**\n * ListToolGroups are one of three types of {@link OO.ui.ToolGroup toolgroups} that are used to\n * create {@link OO.ui.Toolbar toolbars} (the other types of groups are\n * {@link OO.ui.MenuToolGroup MenuToolGroup} and {@link OO.ui.BarToolGroup BarToolGroup}).\n * The {@link OO.ui.Tool tools} in a ListToolGroup are displayed by label in a dropdown menu.\n * The title of the tool is used as the label text. The menu itself can be configured with a label,\n * icon, indicator, header, and title.\n *\n * ListToolGroups can be configured to be expanded and collapsed. Collapsed lists will have a\n * ‘More’ option that users can select to see the full list of tools. If a collapsed toolgroup is\n * expanded, a ‘Fewer’ option permits users to collapse the list again.\n *\n * ListToolGroups are created by a {@link OO.ui.ToolGroupFactory toolgroup factory} when the\n * toolbar is set up. The factory requires the ListToolGroup's symbolic name, 'list', which is\n * specified along with the other configurations. For more information about how to add tools to a\n * ListToolGroup, please see {@link OO.ui.ToolGroup toolgroup}.\n *\n *     @example\n *     // Example of a ListToolGroup\n *     var toolFactory = new OO.ui.ToolFactory();\n *     var toolGroupFactory = new OO.ui.ToolGroupFactory();\n *     var toolbar = new OO.ui.Toolbar( toolFactory, toolGroupFactory );\n *\n *     // Configure and register two tools\n *     function SettingsTool() {\n *         SettingsTool.parent.apply( this, arguments );\n *     }\n *     OO.inheritClass( SettingsTool, OO.ui.Tool );\n *     SettingsTool.static.name = 'settings';\n *     SettingsTool.static.icon = 'settings';\n *     SettingsTool.static.title = 'Change settings';\n *     SettingsTool.prototype.onSelect = function () {\n *         this.setActive( false );\n *     };\n *     SettingsTool.prototype.onUpdateState = function () {};\n *     toolFactory.register( SettingsTool );\n *     // Register two more tools, nothing interesting here\n *     function StuffTool() {\n *         StuffTool.parent.apply( this, arguments );\n *     }\n *     OO.inheritClass( StuffTool, OO.ui.Tool );\n *     StuffTool.static.name = 'stuff';\n *     StuffTool.static.icon = 'search';\n *     StuffTool.static.title = 'Change the world';\n *     StuffTool.prototype.onSelect = function () {\n *         this.setActive( false );\n *     };\n *     StuffTool.prototype.onUpdateState = function () {};\n *     toolFactory.register( StuffTool );\n *     toolbar.setup( [\n *         {\n *             // Configurations for list toolgroup.\n *             type: 'list',\n *             label: 'ListToolGroup',\n *             icon: 'ellipsis',\n *             title: 'This is the title, displayed when user moves the mouse over the list ' +\n *                 'toolgroup',\n *             header: 'This is the header',\n *             include: [ 'settings', 'stuff' ],\n *             allowCollapse: ['stuff']\n *         }\n *     ] );\n *\n *     // Create some UI around the toolbar and place it in the document\n *     var frame = new OO.ui.PanelLayout( {\n *         expanded: false,\n *         framed: true\n *     } );\n *     frame.$element.append(\n *         toolbar.$element\n *     );\n *     $( document.body ).append( frame.$element );\n *     // Build the toolbar. This must be done after the toolbar has been appended to the document.\n *     toolbar.initialize();\n *\n * For more information about toolbars in general, please see the\n * [OOUI documentation on MediaWiki][1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Toolbars\n *\n * @class\n * @extends OO.ui.PopupToolGroup\n *\n * @constructor\n * @param {OO.ui.Toolbar} toolbar\n * @param {Object} [config] Configuration options\n * @cfg {Array} [allowCollapse] Allow the specified tools to be collapsed. By default, collapsible\n *  tools will only be displayed if users click the ‘More’ option displayed at the bottom of the\n *  list. If the list is expanded, a ‘Fewer’ option permits users to collapse the list again.\n *  Any tools that are included in the toolgroup, but are not designated as collapsible, will always\n *  be displayed.\n *  To open a collapsible list in its expanded state, set #expanded to 'true'.\n * @cfg {Array} [forceExpand] Expand the specified tools. All other tools will be designated as\n *  collapsible. Unless #expanded is set to true, the collapsible tools will be collapsed when the\n *  list is first opened.\n * @cfg {boolean} [expanded=false] Expand collapsible tools. This config is only relevant if tools\n *  have been designated as collapsible. When expanded is set to true, all tools in the group will\n *  be displayed when the list is first opened. Users can collapse the list with a ‘Fewer’ option at\n *  the bottom.\n */\nOO.ui.ListToolGroup = function OoUiListToolGroup( toolbar, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( toolbar ) && config === undefined ) {\n\t\tconfig = toolbar;\n\t\ttoolbar = config.toolbar;\n\t}\n\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Properties (must be set before parent constructor, which calls #populate)\n\tthis.allowCollapse = config.allowCollapse;\n\tthis.forceExpand = config.forceExpand;\n\tthis.expanded = config.expanded !== undefined ? config.expanded : false;\n\tthis.collapsibleTools = [];\n\n\t// Parent constructor\n\tOO.ui.ListToolGroup.parent.call( this, toolbar, config );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-listToolGroup' );\n\tthis.$group.addClass( 'oo-ui-listToolGroup-tools' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ListToolGroup, OO.ui.PopupToolGroup );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.ListToolGroup.static.name = 'list';\n\n/* Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.ListToolGroup.prototype.populate = function () {\n\tvar i, len, allowCollapse = [];\n\n\tOO.ui.ListToolGroup.parent.prototype.populate.call( this );\n\n\t// Update the list of collapsible tools\n\tif ( this.allowCollapse !== undefined ) {\n\t\tallowCollapse = this.allowCollapse;\n\t} else if ( this.forceExpand !== undefined ) {\n\t\tallowCollapse = OO.simpleArrayDifference( Object.keys( this.tools ), this.forceExpand );\n\t}\n\n\tthis.collapsibleTools = [];\n\tfor ( i = 0, len = allowCollapse.length; i < len; i++ ) {\n\t\tif ( this.tools[ allowCollapse[ i ] ] !== undefined ) {\n\t\t\tthis.collapsibleTools.push( this.tools[ allowCollapse[ i ] ] );\n\t\t}\n\t}\n\n\t// Keep at the end, even when tools are added\n\tthis.$group.append( this.getExpandCollapseTool().$element );\n\n\tthis.getExpandCollapseTool().toggle( this.collapsibleTools.length !== 0 );\n\tthis.updateCollapsibleState();\n};\n\n/**\n * Get the expand/collapse tool for this group\n *\n * @return {OO.ui.Tool} Expand collapse tool\n */\nOO.ui.ListToolGroup.prototype.getExpandCollapseTool = function () {\n\tvar ExpandCollapseTool;\n\tif ( this.expandCollapseTool === undefined ) {\n\t\tExpandCollapseTool = function () {\n\t\t\tExpandCollapseTool.parent.apply( this, arguments );\n\t\t};\n\n\t\tOO.inheritClass( ExpandCollapseTool, OO.ui.Tool );\n\n\t\tExpandCollapseTool.prototype.onSelect = function () {\n\t\t\tthis.toolGroup.expanded = !this.toolGroup.expanded;\n\t\t\tthis.toolGroup.updateCollapsibleState();\n\t\t\tthis.setActive( false );\n\t\t};\n\t\tExpandCollapseTool.prototype.onUpdateState = function () {\n\t\t\t// Do nothing. Tool interface requires an implementation of this function.\n\t\t};\n\n\t\tExpandCollapseTool.static.name = 'more-fewer';\n\n\t\tthis.expandCollapseTool = new ExpandCollapseTool( this );\n\t}\n\treturn this.expandCollapseTool;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.ListToolGroup.prototype.onMouseKeyUp = function ( e ) {\n\t// Do not close the popup when the user wants to show more/fewer tools\n\tif (\n\t\t$( e.target ).closest( '.oo-ui-tool-name-more-fewer' ).length && (\n\t\t\te.which === OO.ui.MouseButtons.LEFT ||\n\t\t\te.which === OO.ui.Keys.SPACE ||\n\t\t\te.which === OO.ui.Keys.ENTER\n\t\t)\n\t) {\n\t\t// HACK: Prevent the popup list from being hidden. Skip the PopupToolGroup implementation\n\t\t// (which hides the popup list when a tool is selected) and call ToolGroup's implementation\n\t\t// directly.\n\t\treturn OO.ui.ListToolGroup.parent.parent.prototype.onMouseKeyUp.call( this, e );\n\t} else {\n\t\treturn OO.ui.ListToolGroup.parent.prototype.onMouseKeyUp.call( this, e );\n\t}\n};\n\nOO.ui.ListToolGroup.prototype.updateCollapsibleState = function () {\n\tvar i, icon, len;\n\n\tif ( this.toolbar.position !== 'bottom' ) {\n\t\ticon = this.expanded ? 'collapse' : 'expand';\n\t} else {\n\t\ticon = this.expanded ? 'expand' : 'collapse';\n\t}\n\n\tthis.getExpandCollapseTool()\n\t\t.setIcon( icon )\n\t\t.setTitle( OO.ui.msg( this.expanded ? 'ooui-toolgroup-collapse' : 'ooui-toolgroup-expand' ) );\n\n\tfor ( i = 0, len = this.collapsibleTools.length; i < len; i++ ) {\n\t\tthis.collapsibleTools[ i ].toggle( this.expanded );\n\t}\n\n\t// Re-evaluate clipping, because our height has changed\n\tthis.clip();\n};\n","/**\n * MenuToolGroups are one of three types of {@link OO.ui.ToolGroup toolgroups} that are used to\n * create {@link OO.ui.Toolbar toolbars} (the other types of groups are\n * {@link OO.ui.BarToolGroup BarToolGroup} and {@link OO.ui.ListToolGroup ListToolGroup}).\n * MenuToolGroups contain selectable {@link OO.ui.Tool tools}, which are displayed by label in a\n * dropdown menu. The tool's title is used as the label text, and the menu label is updated to\n * reflect which tool or tools are currently selected. If no tools are selected, the menu label\n * is empty. The menu can be configured with an indicator, icon, title, and/or header.\n *\n * MenuToolGroups are created by a {@link OO.ui.ToolGroupFactory tool group factory} when the\n * toolbar is set up.\n *\n *     @example\n *     // Example of a MenuToolGroup\n *     var toolFactory = new OO.ui.ToolFactory();\n *     var toolGroupFactory = new OO.ui.ToolGroupFactory();\n *     var toolbar = new OO.ui.Toolbar( toolFactory, toolGroupFactory );\n *\n *     // We will be placing status text in this element when tools are used\n *     var $area = $( '<p>' ).text( 'An example of a MenuToolGroup. Select a tool from the '\n *         + 'dropdown menu.' );\n *\n *     // Define the tools that we're going to place in our toolbar\n *\n *     function SettingsTool() {\n *         SettingsTool.parent.apply( this, arguments );\n *         this.reallyActive = false;\n *     }\n *     OO.inheritClass( SettingsTool, OO.ui.Tool );\n *     SettingsTool.static.name = 'settings';\n *     SettingsTool.static.icon = 'settings';\n *     SettingsTool.static.title = 'Change settings';\n *     SettingsTool.prototype.onSelect = function () {\n *         $area.text( 'Settings tool clicked!' );\n *         // Toggle the active state on each click\n *         this.reallyActive = !this.reallyActive;\n *         this.setActive( this.reallyActive );\n *         // To update the menu label\n *         this.toolbar.emit( 'updateState' );\n *     };\n *     SettingsTool.prototype.onUpdateState = function () {};\n *     toolFactory.register( SettingsTool );\n *\n *     function StuffTool() {\n *         StuffTool.parent.apply( this, arguments );\n *         this.reallyActive = false;\n *     }\n *     OO.inheritClass( StuffTool, OO.ui.Tool );\n *     StuffTool.static.name = 'stuff';\n *     StuffTool.static.icon = 'ellipsis';\n *     StuffTool.static.title = 'More stuff';\n *     StuffTool.prototype.onSelect = function () {\n *         $area.text( 'More stuff tool clicked!' );\n *         // Toggle the active state on each click\n *         this.reallyActive = !this.reallyActive;\n *         this.setActive( this.reallyActive );\n *         // To update the menu label\n *         this.toolbar.emit( 'updateState' );\n *     };\n *     StuffTool.prototype.onUpdateState = function () {};\n *     toolFactory.register( StuffTool );\n *\n *     // Finally define which tools and in what order appear in the toolbar. Each tool may only be\n *     // used once (but not all defined tools must be used).\n *     toolbar.setup( [\n *         {\n *             type: 'menu',\n *             header: 'This is the (optional) header',\n *             title: 'This is the (optional) title',\n *             include: [ 'settings', 'stuff' ]\n *         }\n *     ] );\n *\n *     // Create some UI around the toolbar and place it in the document\n *     var frame = new OO.ui.PanelLayout( {\n *         expanded: false,\n *         framed: true\n *     } );\n *     var contentFrame = new OO.ui.PanelLayout( {\n *         expanded: false,\n *         padded: true\n *     } );\n *     frame.$element.append(\n *         toolbar.$element,\n *         contentFrame.$element.append( $area )\n *     );\n *     $( document.body ).append( frame.$element );\n *\n *     // Here is where the toolbar is actually built. This must be done after inserting it into the\n *     // document.\n *     toolbar.initialize();\n *     toolbar.emit( 'updateState' );\n *\n * For more information about how to add tools to a MenuToolGroup, please see\n * {@link OO.ui.ToolGroup toolgroup}.\n * For more information about toolbars in general, please see the\n * [OOUI documentation on MediaWiki] [1].\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Toolbars\n *\n * @class\n * @extends OO.ui.PopupToolGroup\n *\n * @constructor\n * @param {OO.ui.Toolbar} toolbar\n * @param {Object} [config] Configuration options\n */\nOO.ui.MenuToolGroup = function OoUiMenuToolGroup( toolbar, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( toolbar ) && config === undefined ) {\n\t\tconfig = toolbar;\n\t\ttoolbar = config.toolbar;\n\t}\n\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.MenuToolGroup.parent.call( this, toolbar, config );\n\n\t// Events\n\tthis.toolbar.connect( this, {\n\t\tupdateState: 'onUpdateState'\n\t} );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-menuToolGroup' );\n\tthis.$group.addClass( 'oo-ui-menuToolGroup-tools' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.MenuToolGroup, OO.ui.PopupToolGroup );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.MenuToolGroup.static.name = 'menu';\n\n/* Methods */\n\n/**\n * Handle the toolbar state being updated.\n *\n * When the state changes, the title of each active item in the menu will be joined together and\n * used as a label for the group. The label will be empty if none of the items are active.\n *\n * @private\n */\nOO.ui.MenuToolGroup.prototype.onUpdateState = function () {\n\tvar name,\n\t\tlabelTexts = [];\n\n\tfor ( name in this.tools ) {\n\t\tif ( this.tools[ name ].isActive() ) {\n\t\t\tlabelTexts.push( this.tools[ name ].getTitle() );\n\t\t}\n\t}\n\n\tthis.setLabel( labelTexts.join( ', ' ) || ' ' );\n};\n","}( OO ) );\n"]}
\ No newline at end of file
index 5a6d6fe..fb86ec6 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOUI v0.31.0
+ * OOUI v0.31.6
  * https://www.mediawiki.org/wiki/OOUI
  *
  * Copyright 2011–2019 OOUI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2019-03-14T00:52:27Z
+ * Date: 2019-05-08T10:08:44Z
  */
 .oo-ui-draggableElement-handle:not( .oo-ui-draggableElement-undraggable ).oo-ui-widget {
   cursor: move;
   margin-left: -2px;
 }
 
-.oo-ui-selectFileWidget {
-  display: inline-block;
-  vertical-align: middle;
-  width: 100%;
-  max-width: 50em;
-  margin-right: 0.5em;
-}
-.oo-ui-selectFileWidget-selectButton {
-  display: table-cell;
-}
-.oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
-  position: relative;
-  overflow: hidden;
-}
-.oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button > [type='file'] {
-  position: absolute;
-  top: 0;
-  bottom: 0;
-  left: 0;
-  right: 0;
-  width: 100%;
-  height: 100%;
-  opacity: 0;
-  z-index: 1;
-  cursor: pointer;
-  padding-top: 100px;
-}
-.oo-ui-selectFileWidget-selectButton.oo-ui-widget-disabled > .oo-ui-buttonElement-button > [type='file'] {
-  display: none;
-}
-.oo-ui-selectFileWidget-info {
-  width: 100%;
-  display: table-cell;
-  vertical-align: middle;
-  position: relative;
-  overflow: hidden;
-  -webkit-box-sizing: border-box;
-  -moz-box-sizing: border-box;
-  box-sizing: border-box;
-}
-.oo-ui-widget-disabled .oo-ui-selectFileWidget-info {
-  cursor: default;
-  -webkit-touch-callout: none;
-  -webkit-user-select: none;
-  -moz-user-select: none;
-  -ms-user-select: none;
-  user-select: none;
-}
-.oo-ui-selectFileWidget-label {
-  position: absolute;
-  top: 0;
-  bottom: 0;
-  left: 0;
-  right: 0;
-  text-overflow: ellipsis;
-}
-.oo-ui-selectFileWidget-clearButton {
-  position: absolute;
-  z-index: 2;
-}
 .oo-ui-selectFileWidget-dropTarget {
   position: relative;
   cursor: default;
   height: 8.815em;
 }
 .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel,
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileInputWidget-selectButton {
   display: none;
 }
 .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail {
   background-repeat: no-repeat;
   background-size: contain;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail.oo-ui-pendingElement-pending {
-  background-repeat: repeat;
-  background-size: auto;
-}
 .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail > .oo-ui-selectFileWidget-noThumbnail-icon {
   opacity: 0.4;
   height: 7.815em;
   width: 7.815em;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
+.oo-ui-selectFileWidget-dropTarget .oo-ui-pendingElement-pending {
+  background-repeat: repeat;
+}
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileInputWidget-info {
   display: block;
   height: 100%;
   width: auto;
   margin-left: 8.815em;
+  margin-right: 0;
+}
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileInputWidget-info > .oo-ui-inputWidget-input {
   border: 0;
+  box-shadow: none;
+  background: transparent;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-label {
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileInputWidget-label {
   display: block;
   position: relative;
   top: inherit;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-fileName {
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileInputWidget-fileName {
   display: block;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail,
-.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
-  display: none;
-}
-.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
-  display: block;
-  margin: 2.2em 1em 1em;
-}
-.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget.oo-ui-selectFileInputWidget-empty.oo-ui-selectFileWidget-dropTarget {
   text-align: center;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info,
-.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
-  margin: 0;
-}
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-clearButton,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-clearButton {
+.oo-ui-selectFileWidget.oo-ui-selectFileInputWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail,
+.oo-ui-selectFileWidget.oo-ui-selectFileInputWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileInputWidget-info {
   display: none;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-widget-enabled .oo-ui-selectFileWidget-label {
-  cursor: default;
+.oo-ui-selectFileWidget.oo-ui-selectFileInputWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileInputWidget-selectButton {
+  display: block;
+  margin: 2.2em 1em 1em;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-widget-enabled .oo-ui-selectFileWidget-dropLabel {
+.oo-ui-selectFileWidget.oo-ui-selectFileInputWidget-empty.oo-ui-widget-enabled .oo-ui-selectFileWidget-dropLabel {
   display: block;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget.oo-ui-selectFileInputWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget {
   -webkit-touch-callout: none;
   -webkit-user-select: none;
   -moz-user-select: none;
   -ms-user-select: none;
   user-select: none;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button,
-.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button {
+.oo-ui-selectFileWidget.oo-ui-selectFileInputWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget.oo-ui-selectFileInputWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button {
   cursor: no-drop;
 }
-.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
-  height: auto;
-}
-.oo-ui-selectFileWidget:last-child {
-  margin-right: 0;
-}
-.oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
-  border-radius: 0 3px 3px 0;
-}
-.oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button .oo-ui-iconElement-icon,
-.oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button .oo-ui-indicatorElement-indicator {
-  display: none;
-}
-.oo-ui-selectFileWidget-info {
-  height: 2.4em;
-  background-color: #fff;
-  border: 1px solid #ccc;
-  border-width: 1px 0 1px 1px;
-  border-radius: 3px 0 0 3px;
-}
-.oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator,
-.oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon {
-  position: absolute;
-  top: 0;
-  height: 100%;
-}
-.oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon {
-  left: 0.3em;
-}
-.oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator {
-  right: 0.775em;
-}
-.oo-ui-selectFileWidget-label {
-  -webkit-box-sizing: border-box;
-  -moz-box-sizing: border-box;
-  box-sizing: border-box;
-  left: 0.5em;
-  right: 2.175em;
-  line-height: 2.3em;
-  margin: 0;
-  overflow: hidden;
-  white-space: nowrap;
-  text-overflow: ellipsis;
-}
-.oo-ui-selectFileWidget-clearButton {
-  top: 0;
-  right: 0;
-  height: 2.34375em;
-  margin: 0;
-}
-.oo-ui-selectFileWidget-clearButton.oo-ui-iconElement .oo-ui-buttonElement-button {
-  height: 2.34375em;
-  padding: 0;
-}
-.oo-ui-selectFileWidget-clearButton.oo-ui-iconElement .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
-  background-size: 12px 12px;
-  height: 2.34375em;
-  margin-top: 0;
-  margin-bottom: 0;
-}
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-label {
-  color: #ccc;
-}
-.oo-ui-selectFileWidget.oo-ui-iconElement .oo-ui-selectFileWidget-label {
-  left: 2.475em;
-}
-.oo-ui-selectFileWidget.oo-ui-indicatorElement .oo-ui-selectFileWidget-label {
-  right: 4.2625em;
-}
-.oo-ui-selectFileWidget.oo-ui-indicatorElement .oo-ui-selectFileWidget-clearButton {
-  right: 2.0875em;
-}
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-label,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-label {
-  right: 0.5em;
-}
-.oo-ui-selectFileWidget-empty.oo-ui-indicatorElement .oo-ui-selectFileWidget-label,
-.oo-ui-selectFileWidget-notsupported.oo-ui-indicatorElement .oo-ui-selectFileWidget-label,
-.oo-ui-selectFileWidget-empty.oo-ui-indicatorElement .oo-ui-selectFileWidget-label,
-.oo-ui-selectFileWidget-notsupported.oo-ui-indicatorElement .oo-ui-selectFileWidget-label {
-  right: 2em;
-}
-.oo-ui-selectFileWidget-supported.oo-ui-widget-enabled.oo-ui-selectFileWidget-canDrop.oo-ui-selectFileWidget-dropTarget {
-  background-color: #e1f3ff;
-}
-.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-label {
-  padding: 1em;
-}
 .oo-ui-selectFileWidget-dropTarget {
   background-color: #fff;
   border: 1px solid #aaa;
   border-radius: 3px;
   vertical-align: middle;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
-  border-radius: 3px;
-}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-label {
-  line-height: 1.4;
-  overflow: inherit;
-  white-space: normal;
-}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-fileName {
-  padding-top: 0.5em;
-  padding-right: 2.375em;
+.oo-ui-selectFileWidget-dropTarget.oo-ui-selectFileInputWidget-empty {
+  border-style: dashed;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-clearButton {
-  right: 0.5em;
+.oo-ui-selectFileWidget-dropTarget .oo-ui-pendingElement-pending {
+  background-size: 1.5625em 1.5625em;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget {
-  border-style: dashed;
+.oo-ui-selectFileWidget.oo-ui-widget-enabled.oo-ui-selectFileWidget-canDrop.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget.oo-ui-widget-enabled.oo-ui-selectFileWidget-canDrop .oo-ui-selectFileInputWidget-info > .oo-ui-inputWidget-input {
+  background-color: #e1f3ff;
 }
 .oo-ui-selectFileWidget.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget.oo-ui-selectFileInputWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget {
   background-color: #f3f3f3;
   color: #ccc;
   border-color: #ddd;
   text-shadow: 0 1px 1px #fff;
 }
-.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info,
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-info,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-info {
-  background-color: #f3f3f3;
-  color: #ccc;
-  border-color: #ddd;
-  text-shadow: 0 1px 1px #fff;
-}
-.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon,
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon,
-.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator,
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator {
-  opacity: 0.2;
-}
 
 
 .oo-ui-outlineOptionWidget {
index 8c693f5..a72b39c 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOUI v0.31.0
+ * OOUI v0.31.6
  * https://www.mediawiki.org/wiki/OOUI
  *
  * Copyright 2011–2019 OOUI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2019-03-14T00:52:27Z
+ * Date: 2019-05-08T10:08:44Z
  */
 .oo-ui-draggableElement-handle:not( .oo-ui-draggableElement-undraggable ).oo-ui-widget {
   cursor: move;
   background-color: #fff;
 }
 
-.oo-ui-selectFileWidget {
-  display: inline-block;
-  vertical-align: middle;
-  width: 100%;
-  max-width: 50em;
-  margin-right: 0.5em;
-}
-.oo-ui-selectFileWidget-selectButton {
-  display: table-cell;
-}
-.oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
-  position: relative;
-  overflow: hidden;
-}
-.oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button > [type='file'] {
-  position: absolute;
-  top: 0;
-  bottom: 0;
-  left: 0;
-  right: 0;
-  width: 100%;
-  height: 100%;
-  opacity: 0;
-  z-index: 1;
-  cursor: pointer;
-  padding-top: 100px;
-}
-.oo-ui-selectFileWidget-selectButton.oo-ui-widget-disabled > .oo-ui-buttonElement-button > [type='file'] {
-  display: none;
-}
-.oo-ui-selectFileWidget-info {
-  width: 100%;
-  display: table-cell;
-  vertical-align: middle;
-  position: relative;
-  overflow: hidden;
-  -webkit-box-sizing: border-box;
-  -moz-box-sizing: border-box;
-  box-sizing: border-box;
-}
-.oo-ui-widget-disabled .oo-ui-selectFileWidget-info {
-  cursor: default;
-  -webkit-touch-callout: none;
-  -webkit-user-select: none;
-  -moz-user-select: none;
-  -ms-user-select: none;
-  user-select: none;
-}
-.oo-ui-selectFileWidget-label {
-  position: absolute;
-  top: 0;
-  bottom: 0;
-  left: 0;
-  right: 0;
-  text-overflow: ellipsis;
-}
-.oo-ui-selectFileWidget-clearButton {
-  position: absolute;
-  z-index: 2;
-}
 .oo-ui-selectFileWidget-dropTarget {
   position: relative;
   cursor: default;
   height: 8.815em;
 }
 .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel,
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileInputWidget-selectButton {
   display: none;
 }
 .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail {
   background-repeat: no-repeat;
   background-size: contain;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail.oo-ui-pendingElement-pending {
-  background-repeat: repeat;
-  background-size: auto;
-}
 .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail > .oo-ui-selectFileWidget-noThumbnail-icon {
   opacity: 0.4;
   height: 7.815em;
   width: 7.815em;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
+.oo-ui-selectFileWidget-dropTarget .oo-ui-pendingElement-pending {
+  background-repeat: repeat;
+}
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileInputWidget-info {
   display: block;
   height: 100%;
   width: auto;
   margin-left: 8.815em;
+  margin-right: 0;
+}
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileInputWidget-info > .oo-ui-inputWidget-input {
   border: 0;
+  box-shadow: none;
+  background: transparent;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-label {
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileInputWidget-label {
   display: block;
   position: relative;
   top: inherit;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-fileName {
-  display: block;
-}
-.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail,
-.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
-  display: none;
-}
-.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileInputWidget-fileName {
   display: block;
-  margin: 2.2em 1em 1em;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget.oo-ui-selectFileInputWidget-empty.oo-ui-selectFileWidget-dropTarget {
   text-align: center;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info,
-.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
-  margin: 0;
-}
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-clearButton,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-clearButton {
+.oo-ui-selectFileWidget.oo-ui-selectFileInputWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail,
+.oo-ui-selectFileWidget.oo-ui-selectFileInputWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileInputWidget-info {
   display: none;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-widget-enabled .oo-ui-selectFileWidget-label {
-  cursor: default;
+.oo-ui-selectFileWidget.oo-ui-selectFileInputWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileInputWidget-selectButton {
+  display: block;
+  margin: 2.2em 1em 1em;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-widget-enabled .oo-ui-selectFileWidget-dropLabel {
+.oo-ui-selectFileWidget.oo-ui-selectFileInputWidget-empty.oo-ui-widget-enabled .oo-ui-selectFileWidget-dropLabel {
   display: block;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget.oo-ui-selectFileInputWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget {
   -webkit-touch-callout: none;
   -webkit-user-select: none;
   -moz-user-select: none;
   -ms-user-select: none;
   user-select: none;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button,
-.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button {
+.oo-ui-selectFileWidget.oo-ui-selectFileInputWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget.oo-ui-selectFileInputWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button {
   cursor: no-drop;
 }
-.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
-  height: auto;
-}
-.oo-ui-selectFileWidget:last-child {
-  margin-right: 0;
-}
-.oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
-  border-radius: 0 2px 2px 0;
-}
-.oo-ui-selectFileWidget-info {
-  background-color: #fff;
-  border: 1px solid #a2a9b1;
-  border-radius: 2px 0 0 2px;
-  border-right-width: 0;
-}
-.oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon {
-  top: -1px;
-  left: 0.57142857em;
-  min-height: 2.28571429em;
-  margin-left: -1px;
-}
-.oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator {
-  top: -1px;
-  right: 0.85714286em;
-  min-height: 2.28571429em;
-}
-.oo-ui-selectFileWidget-label {
-  -webkit-box-sizing: border-box;
-  -moz-box-sizing: border-box;
-  box-sizing: border-box;
-  display: block;
-  right: 2.85714286em;
-  padding-top: 0.57142857em;
-  padding-left: 0.57142857em;
-  padding-bottom: 0.57142857em;
-  white-space: nowrap;
-}
-.oo-ui-selectFileWidget.oo-ui-labelElement .oo-ui-selectFileWidget-label {
-  line-height: 1;
-}
-.oo-ui-selectFileWidget-fileName {
-  display: block;
-  overflow: hidden;
-  text-overflow: ellipsis;
-}
-.oo-ui-selectFileWidget-clearButton {
-  top: 0;
-  right: 0;
-  margin-right: 0;
-  padding-left: 0;
-}
-.oo-ui-selectFileWidget-clearButton > .oo-ui-buttonElement-button {
-  padding-top: 2em;
-}
-.oo-ui-selectFileWidget-clearButton .oo-ui-iconElement-icon {
-  background-position: center center;
-  background-size: 12px 12px;
-  height: 2em;
-}
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-label {
-  color: #72777d;
-}
-.oo-ui-selectFileWidget.oo-ui-iconElement .oo-ui-selectFileWidget-label {
-  left: 2.64285714em;
-}
-.oo-ui-selectFileWidget.oo-ui-indicatorElement .oo-ui-selectFileWidget-label {
-  right: 4.57142857em;
-  padding-left: 0;
-}
-.oo-ui-selectFileWidget.oo-ui-indicatorElement .oo-ui-selectFileWidget-clearButton {
-  right: 2.28571429em;
-}
-.oo-ui-selectFileWidget-empty.oo-ui-indicatorElement .oo-ui-selectFileWidget-label,
-.oo-ui-selectFileWidget-notsupported.oo-ui-indicatorElement .oo-ui-selectFileWidget-label {
-  right: 2em;
-}
 .oo-ui-selectFileWidget-dropTarget {
   background-color: #fff;
   border: 1px solid #a2a9b1;
   vertical-align: middle;
   overflow: hidden;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
-  border-radius: 2px;
-}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-label {
-  overflow: inherit;
-  white-space: normal;
-}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-fileName {
-  padding-right: 2.64285714em;
+.oo-ui-selectFileWidget-dropTarget.oo-ui-selectFileInputWidget-empty {
+  border-style: dashed;
 }
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-clearButton {
-  top: 0;
+.oo-ui-selectFileWidget-dropTarget .oo-ui-pendingElement-pending {
+  background-size: 1.42857143em 1.42857143em;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-widget-enabled.oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget.oo-ui-widget-enabled.oo-ui-selectFileWidget-dropTarget {
   background-color: #fff;
-  border-style: dashed;
   -webkit-transition: background-color 250ms, color 250ms, border-color 250ms;
   -moz-transition: background-color 250ms, color 250ms, border-color 250ms;
   transition: background-color 250ms, color 250ms, border-color 250ms;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-widget-enabled.oo-ui-selectFileWidget-dropTarget:hover {
+.oo-ui-selectFileWidget.oo-ui-widget-enabled.oo-ui-selectFileWidget-dropTarget:hover {
   border-color: #72777d;
 }
-.oo-ui-selectFileWidget-supported.oo-ui-widget-enabled.oo-ui-selectFileWidget-canDrop.oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget.oo-ui-widget-enabled .oo-ui-selectFileInputWidget-info > .oo-ui-inputWidget-input {
+  -webkit-transition: background-color 250ms, color 250ms;
+  -moz-transition: background-color 250ms, color 250ms;
+  transition: background-color 250ms, color 250ms;
+}
+.oo-ui-selectFileWidget.oo-ui-widget-enabled.oo-ui-selectFileWidget-canDrop.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget.oo-ui-widget-enabled.oo-ui-selectFileWidget-canDrop .oo-ui-selectFileInputWidget-info > .oo-ui-inputWidget-input {
   background-color: #eaf3ff;
   color: #36c;
 }
-.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info,
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-info {
-  background-color: #eaecf0;
-  color: #72777d;
-  border-color: #c8ccd1;
-  text-shadow: 0 1px 1px #fff;
-}
-.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon,
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon {
-  opacity: 0.51;
-}
-.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator,
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator {
-  opacity: 0.15;
-}
 .oo-ui-selectFileWidget.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget {
-  background-color: #eaecf0;
-  border-color: #c8ccd1;
-}
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-info {
-  background-color: #eaecf0;
-  color: #222;
-  border-color: #c8ccd1;
-}
-.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget.oo-ui-selectFileInputWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget {
   background-color: #eaecf0;
   border-color: #c8ccd1;
 }
-.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-label {
-  padding: 1em 0.85714286em;
-}
-.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropLabel {
-  display: none;
-}
 
 .oo-ui-outlineSelectWidget {
   height: 100%;
   -moz-user-select: none;
   -ms-user-select: none;
   user-select: none;
-  padding: 1em 0.85714286em;
+  padding: 0.85714286em 0.85714286em;
   -webkit-transition: background-color 100ms, color 100ms;
   -moz-transition: background-color 100ms, color 100ms;
   transition: background-color 100ms, color 100ms;
 }
 .oo-ui-tabOptionWidget .oo-ui-labelElement-label {
   border-bottom: 2px solid transparent;
-  padding: 0.57142857em 0.35714286em 0.42857143em;
-  line-height: 1;
+  padding: 0.42857143em 0.35714286em 0.28571429em;
+  line-height: 1.28571429em;
   -webkit-transition: border-color 100ms;
   -moz-transition: border-color 100ms;
   transition: border-color 100ms;
   box-sizing: border-box;
   height: 2.14285714em;
   border: 0;
-  padding: 0.57142857em 0 0.57142857em 0.57142857em;
+  padding: 0.42857143em 0 0.42857143em 0.57142857em;
   font-family: inherit;
   font-size: inherit;
-  line-height: 1;
+  line-height: 1.28571429em;
   vertical-align: top;
 }
 .oo-ui-tagMultiselectWidget-handle > .oo-ui-tagMultiselectWidget-content > input::-webkit-input-placeholder {
index e062642..82ff501 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOUI v0.31.0
+ * OOUI v0.31.6
  * https://www.mediawiki.org/wiki/OOUI
  *
  * Copyright 2011–2019 OOUI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2019-03-14T00:52:20Z
+ * Date: 2019-05-08T10:08:36Z
  */
 ( function ( OO ) {
 
@@ -494,11 +494,15 @@ OO.ui.mixin.DraggableGroupElement.prototype.getDragItem = function () {
  * @abstract
  *
  * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {boolean} [showPendingRequest=true] Show pending state while request data is being fetched.
+ *  Requires widget to have also mixed in {@link OO.ui.mixin.PendingElement}.
  */
-OO.ui.mixin.RequestManager = function OoUiMixinRequestManager() {
+OO.ui.mixin.RequestManager = function OoUiMixinRequestManager( config ) {
        this.requestCache = {};
        this.requestQuery = null;
        this.requestRequest = null;
+       this.showPendingRequest = !!this.pushPending && config.showPendingRequest !== false;
 };
 
 /* Setup */
@@ -522,7 +526,7 @@ OO.ui.mixin.RequestManager.prototype.getRequestData = function () {
        if ( Object.prototype.hasOwnProperty.call( this.requestCache, value ) ) {
                deferred.resolve( this.requestCache[ value ] );
        } else {
-               if ( this.pushPending ) {
+               if ( this.showPendingRequest ) {
                        this.pushPending();
                }
                this.requestQuery = value;
@@ -535,7 +539,7 @@ OO.ui.mixin.RequestManager.prototype.getRequestData = function () {
                                // being aborted, or at least eventually. It would be nice if we could popPending()
                                // at abort time, but only if we knew that we hadn't already called popPending()
                                // for that request.
-                               if ( widget.popPending ) {
+                               if ( widget.showPendingRequest ) {
                                        widget.popPending();
                                }
                        } )
@@ -1635,14 +1639,14 @@ OO.ui.StackLayout.prototype.updateHiddenState = function ( items, selectedItem )
  *         contentPanel: contentPanel
  *     } );
  *     menuLayout.$menu.append(
- *         menuPanel.$element.append( '<b>Menu panel</b>', select.$element );
+ *         menuPanel.$element.append( '<b>Menu panel</b>', select.$element )
  *     );
  *     menuLayout.$content.append(
  *         contentPanel.$element.append(
  *             '<b>Content panel</b>',
  *             '<p>Note that the menu is positioned relative to the content panel: ' +
  *             'top, bottom, after, before.</p>'
- *          );
+ *          )
  *     );
  *     $( document.body ).append( menuLayout.$element );
  *
@@ -3209,7 +3213,7 @@ OO.mixinClass( OO.ui.ToggleSwitchWidget, OO.ui.mixin.TabIndexedElement );
  *
  * @private
  * @param {jQuery.Event} e Mouse click event
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.ToggleSwitchWidget.prototype.onClick = function ( e ) {
        if ( !this.isDisabled() && e.which === OO.ui.MouseButtons.LEFT ) {
@@ -3223,7 +3227,7 @@ OO.ui.ToggleSwitchWidget.prototype.onClick = function ( e ) {
  *
  * @private
  * @param {jQuery.Event} e Key press event
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.ToggleSwitchWidget.prototype.onKeyPress = function ( e ) {
        if ( !this.isDisabled() && ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER ) ) {
@@ -4519,7 +4523,7 @@ OO.ui.TagMultiselectWidget.prototype.onTagSelect = function ( item ) {
                        this.addTagFromInput();
                }
                // 1. Get the label of the tag into the input
-               this.input.setValue( item.getData() );
+               this.input.setValue( item.getLabel() );
                // 2. Remove the tag
                this.removeItems( [ item ] );
                // 3. Focus the input
@@ -5187,23 +5191,30 @@ OO.ui.PopupTagMultiselectWidget.prototype.addTagByPopupValue = function ( data,
  * @cfg {Object[]} [options=[]] Array of menu options in the format `{ data: …, label: … }`
  */
 OO.ui.MenuTagMultiselectWidget = function OoUiMenuTagMultiselectWidget( config ) {
+       var $autoCloseIgnore = $( [] );
        config = config || {};
 
        // Parent constructor
        OO.ui.MenuTagMultiselectWidget.parent.call( this, config );
 
+       $autoCloseIgnore = $autoCloseIgnore.add( this.$group );
+       if ( this.hasInput ) {
+               $autoCloseIgnore = $autoCloseIgnore.add( this.input.$element );
+       }
+
        this.$overlay = ( config.$overlay === true ?
                OO.ui.getDefaultOverlay() : config.$overlay ) || this.$element;
        this.clearInputOnChoose = config.clearInputOnChoose === undefined ||
                !!config.clearInputOnChoose;
        this.menu = this.createMenuWidget( $.extend( {
                widget: this,
+               hideOnChoose: false,
                input: this.hasInput ? this.input : null,
                $input: this.hasInput ? this.input.$input : null,
                filterFromInput: !!this.hasInput,
-               highlightOnFilter: true,
-               $autoCloseIgnore: this.hasInput ?
-                       this.input.$element : $( [] ),
+               highlightOnFilter: !this.allowArbitrary,
+               multiselect: true,
+               $autoCloseIgnore: $autoCloseIgnore,
                $floatableContainer: this.hasInput && this.inputPosition === 'outline' ?
                        this.input.$element : this.$element,
                $overlay: this.$overlay,
@@ -5262,16 +5273,6 @@ OO.ui.MenuTagMultiselectWidget.prototype.onInputFocus = function () {
        this.menu.toggle( true );
 };
 
-/**
- * @inheritdoc
- */
-OO.ui.MenuTagMultiselectWidget.prototype.onInputBlur = function () {
-       // Parent method
-       OO.ui.MenuTagMultiselectWidget.parent.prototype.onInputBlur.call( this );
-
-       this.menu.toggle( false );
-};
-
 /**
  * Respond to input change event
  */
@@ -5280,16 +5281,23 @@ OO.ui.MenuTagMultiselectWidget.prototype.onInputChange = function () {
 };
 
 /**
- * Respond to menu choose event
+ * Respond to menu choose event, which is intentional by the user.
  *
- * @param {OO.ui.OptionWidget} menuItem Chosen menu item
+ * @param {OO.ui.OptionWidget} menuItem Selected menu items
+ * @param {boolean} selected Item is selected
  */
-OO.ui.MenuTagMultiselectWidget.prototype.onMenuChoose = function ( menuItem ) {
+OO.ui.MenuTagMultiselectWidget.prototype.onMenuChoose = function ( menuItem, selected ) {
        if ( this.hasInput && this.clearInputOnChoose ) {
                this.input.setValue( '' );
        }
-       // Add tag
-       this.addTag( menuItem.getData(), menuItem.getLabel() );
+
+       if ( selected && !this.findItemFromData( menuItem.getData() ) ) {
+               // The menu item is selected, add it to the tags
+               this.addTag( menuItem.getData(), menuItem.getLabel() );
+       } else {
+               // The menu item was unselected, remove the tag
+               this.removeTagByData( menuItem.getData() );
+       }
 };
 
 /**
@@ -5299,8 +5307,8 @@ OO.ui.MenuTagMultiselectWidget.prototype.onMenuChoose = function ( menuItem ) {
  */
 OO.ui.MenuTagMultiselectWidget.prototype.onMenuToggle = function ( isVisible ) {
        if ( !isVisible ) {
-               this.menu.selectItem( null );
                this.menu.highlightItem( null );
+               this.menu.scrollToTop();
        }
        setTimeout( function () {
                // Remove MenuSelectWidget's generic focus owner ARIA attribute
@@ -5325,16 +5333,75 @@ OO.ui.MenuTagMultiselectWidget.prototype.onTagSelect = function ( tagItem ) {
                        this.input.setValue( '' );
                }
 
-               // Select the menu item
-               this.menu.selectItem( menuItem );
-
                this.focus();
+
+               // Highlight the menu item
+               this.menu.highlightItem( menuItem );
+               this.menu.scrollItemIntoView( menuItem );
+
        } else {
                // Use the default
                OO.ui.MenuTagMultiselectWidget.parent.prototype.onTagSelect.call( this, tagItem );
        }
 };
 
+/**
+ * @inheritdoc
+ */
+OO.ui.MenuTagMultiselectWidget.prototype.removeItems = function ( items ) {
+       var widget = this;
+
+       // Parent
+       OO.ui.MenuTagMultiselectWidget.parent.prototype.removeItems.call( this, items );
+
+       items.forEach( function ( tagItem ) {
+               var menuItem = widget.menu.findItemFromData( tagItem.getData() );
+               if ( menuItem ) {
+                       // Synchronize the menu selection - unselect the removed tag
+                       widget.menu.unselectItem( menuItem );
+               }
+       } );
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.MenuTagMultiselectWidget.prototype.setValue = function ( valueObject ) {
+       valueObject = Array.isArray( valueObject ) ? valueObject : [ valueObject ];
+
+       // We override this method from the parent, to make sure we are adding proper
+       // menu items, and are accounting for cases where we have this widget with
+       // a menu but also 'allowArbitrary'
+       if ( !this.menu ) {
+               return;
+       }
+
+       this.clearItems();
+       valueObject.forEach( function ( obj ) {
+               var data, label, menuItem;
+
+               if ( typeof obj === 'string' ) {
+                       data = label = obj;
+               } else {
+                       data = obj.data;
+                       label = obj.label;
+               }
+
+               // Check if the item is in the menu
+               menuItem = this.menu.getItemFromLabel( label ) || this.menu.findItemFromData( data );
+               if ( menuItem ) {
+                       // Menu item found, add the menu item
+                       this.addTag( menuItem.getData(), menuItem.getLabel() );
+                       // Make sure that item is also selected
+                       this.menu.selectItem( menuItem );
+               } else if ( this.allowArbitrary ) {
+                       // If the item isn't in the menu, only add it if we
+                       // allow for arbitrary values
+                       this.addTag( data, label );
+               }
+       }.bind( this ) );
+};
+
 /**
  * @inheritdoc
  */
@@ -5355,12 +5422,17 @@ OO.ui.MenuTagMultiselectWidget.prototype.setDisabled = function ( isDisabled ) {
  * @chainable
  */
 OO.ui.MenuTagMultiselectWidget.prototype.initializeMenuSelection = function () {
-       if ( !this.menu.findSelectedItem() ) {
-               this.menu.highlightItem(
-                       this.allowArbitrary ?
-                               null :
-                               this.menu.findFirstSelectableItem()
-               );
+       var highlightedItem;
+       this.menu.highlightItem(
+               this.allowArbitrary ?
+                       null :
+                       this.menu.findFirstSelectableItem()
+       );
+
+       highlightedItem = this.menu.findHighlightedItem();
+       // Scroll to the highlighted item, if it exists
+       if ( highlightedItem ) {
+               this.menu.scrollItemIntoView( highlightedItem );
        }
 };
 
@@ -5477,6 +5549,9 @@ OO.ui.MenuTagMultiselectWidget.prototype.getAllowedValues = function () {
  * OO.ui.mixin.IndicatorElement indicators} and {@link OO.ui.mixin.TitledElement titles}.
  * Please see the [OOUI documentation on MediaWiki] [1] for more information and examples.
  *
+ * Although SelectFileWidget inherits from SelectFileInputWidget, it does not
+ * behave as an InputWidget, and can't be used in HTML forms.
+ *
  *     @example
  *     // A file select widget.
  *     var selectFile = new OO.ui.SelectFileWidget();
@@ -5485,92 +5560,55 @@ OO.ui.MenuTagMultiselectWidget.prototype.getAllowedValues = function () {
  * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets
  *
  * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.mixin.IconElement
- * @mixins OO.ui.mixin.IndicatorElement
+ * @extends OO.ui.SelectFileInputWidget
  * @mixins OO.ui.mixin.PendingElement
- * @mixins OO.ui.mixin.TabIndexedElement
- * @mixins OO.ui.mixin.LabelElement
- * @mixins OO.ui.mixin.TitledElement
  *
  * @constructor
  * @param {Object} [config] Configuration options
- * @cfg {string[]|null} [accept=null] MIME types to accept. null accepts all types.
- * @cfg {string} [placeholder] Text to display when no file is selected.
  * @cfg {string} [notsupported] Text to display when file support is missing in the browser.
  * @cfg {boolean} [droppable=true] Whether to accept files by drag and drop.
+ * @cfg {boolean} [buttonOnly=false] Show only the select file button, no info field. Requires
+ *  showDropTarget to be false.
  * @cfg {boolean} [showDropTarget=false] Whether to show a drop target. Requires droppable to be
- *  true.
+ *  true. Not yet supported in multiple file mode.
  * @cfg {number} [thumbnailSizeLimit=20] File size limit in MiB above which to not try and show a
  *  preview (for performance).
  */
 OO.ui.SelectFileWidget = function OoUiSelectFileWidget( config ) {
-       var dragHandler;
-
-       this.selectButton = new OO.ui.ButtonWidget( {
-               $element: $( '<label>' ),
-               classes: [ 'oo-ui-selectFileWidget-selectButton' ],
-               label: OO.ui.msg( 'ooui-selectfile-button-select' )
-       } );
+       var dragHandler, droppable,
+               isSupported = this.constructor.static.isSupported();
 
        // Configuration initialization
        config = $.extend( {
-               accept: null,
-               placeholder: OO.ui.msg( 'ooui-selectfile-placeholder' ),
                notsupported: OO.ui.msg( 'ooui-selectfile-not-supported' ),
                droppable: true,
+               buttonOnly: false,
                showDropTarget: false,
-               thumbnailSizeLimit: 20,
-               $tabIndexed: this.selectButton.$tabIndexed
+               thumbnailSizeLimit: 20
        }, config );
 
+       if ( !isSupported ) {
+               config.disabled = true;
+       }
+
        // Parent constructor
        OO.ui.SelectFileWidget.parent.call( this, config );
 
        // Mixin constructors
-       OO.ui.mixin.IconElement.call( this, config );
-       OO.ui.mixin.IndicatorElement.call( this, config );
-       OO.ui.mixin.PendingElement.call( this, $.extend( {
-               $pending: this.$info
-       }, config ) );
-       OO.ui.mixin.TabIndexedElement.call( this, $.extend( {
-               $tabIndexed: this.selectButton.$tabIndexed
-       }, config ) );
-       OO.ui.mixin.LabelElement.call( this, config );
-       OO.ui.mixin.TitledElement.call( this, config );
+       OO.ui.mixin.PendingElement.call( this );
 
-       // Properties
-       this.$info = $( '<span>' );
-       this.showDropTarget = config.droppable && config.showDropTarget;
-       this.thumbnailSizeLimit = config.thumbnailSizeLimit;
-       this.isSupported = this.constructor.static.isSupported();
-       this.currentFile = null;
-       if ( Array.isArray( config.accept ) ) {
-               this.accept = config.accept;
-       } else {
-               this.accept = null;
+       if ( !isSupported ) {
+               this.info.setValue( config.notsupported );
        }
-       this.placeholder = config.placeholder;
-       this.notsupported = config.notsupported;
-       this.onFileSelectedHandler = this.onFileSelected.bind( this );
-
-       this.selectButton.setDisabled( this.disabled || !this.isSupported );
 
-       this.clearButton = new OO.ui.ButtonWidget( {
-               classes: [ 'oo-ui-selectFileWidget-clearButton' ],
-               framed: false,
-               icon: 'clear',
-               disabled: this.disabled
-       } );
+       // Properties
+       droppable = config.droppable && isSupported;
+       // TODO: Support drop target when multiple is set
+       this.showDropTarget = droppable && config.showDropTarget && !this.multiple;
+       this.thumbnailSizeLimit = config.thumbnailSizeLimit;
 
        // Events
-       this.selectButton.$button.on( {
-               keypress: this.onKeyPress.bind( this )
-       } );
-       this.clearButton.connect( this, {
-               click: 'onClearClick'
-       } );
-       if ( config.droppable ) {
+       if ( droppable ) {
                dragHandler = this.onDragEnterOrOver.bind( this );
                this.$element.on( {
                        dragenter: dragHandler,
@@ -5581,46 +5619,45 @@ OO.ui.SelectFileWidget = function OoUiSelectFileWidget( config ) {
        }
 
        // Initialization
-       this.addInput();
-       this.$label.addClass( 'oo-ui-selectFileWidget-label' );
-       this.$info
-               .addClass( 'oo-ui-selectFileWidget-info' )
-               .append( this.$icon, this.$label, this.clearButton.$element, this.$indicator );
-
        if ( this.showDropTarget ) {
                this.selectButton.setIcon( 'upload' );
                this.$thumbnail = $( '<div>' ).addClass( 'oo-ui-selectFileWidget-thumbnail' );
                this.setPendingElement( this.$thumbnail );
                this.$element
-                       .addClass( 'oo-ui-selectFileWidget-dropTarget oo-ui-selectFileWidget' )
+                       .addClass( 'oo-ui-selectFileWidget-dropTarget' )
                        .on( {
                                click: this.onDropTargetClick.bind( this )
                        } )
                        .append(
                                this.$thumbnail,
-                               this.$info,
+                               this.info.$element,
                                this.selectButton.$element,
                                $( '<span>' )
                                        .addClass( 'oo-ui-selectFileWidget-dropLabel' )
                                        .text( OO.ui.msg( 'ooui-selectfile-dragdrop-placeholder' ) )
                        );
-       } else {
-               this.$element
-                       .addClass( 'oo-ui-selectFileWidget' )
-                       .append( this.$info, this.selectButton.$element );
+               this.fieldLayout.$element.remove();
+       } else if ( config.buttonOnly ) {
+               this.$element.append( this.selectButton.$element );
+               this.fieldLayout.$element.remove();
        }
+
+       this.$input
+               .on( 'click', function ( e ) {
+                       // Prevents dropTarget to get clicked which calls
+                       // a click on this input
+                       e.stopPropagation();
+               } );
+
+       this.$element.addClass( 'oo-ui-selectFileWidget' );
+
        this.updateUI();
 };
 
 /* Setup */
 
-OO.inheritClass( OO.ui.SelectFileWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.SelectFileWidget, OO.ui.mixin.IconElement );
-OO.mixinClass( OO.ui.SelectFileWidget, OO.ui.mixin.IndicatorElement );
+OO.inheritClass( OO.ui.SelectFileWidget, OO.ui.SelectFileInputWidget );
 OO.mixinClass( OO.ui.SelectFileWidget, OO.ui.mixin.PendingElement );
-OO.mixinClass( OO.ui.SelectFileWidget, OO.ui.mixin.TabIndexedElement );
-OO.mixinClass( OO.ui.SelectFileWidget, OO.ui.mixin.LabelElement );
-OO.mixinClass( OO.ui.SelectFileWidget, OO.ui.mixin.TitledElement );
 
 /* Static Properties */
 
@@ -5656,92 +5693,110 @@ OO.ui.SelectFileWidget.static.isSupportedCache = null;
 /**
  * Get the current value of the field
  *
- * @return {File|null}
+ * For single file widgets returns a File or null.
+ * For multiple file widgets returns a list of Files.
+ *
+ * @return {File|File[]|null}
  */
 OO.ui.SelectFileWidget.prototype.getValue = function () {
-       return this.currentFile;
+       return this.multiple ? this.currentFiles : this.currentFiles[ 0 ];
 };
 
 /**
  * Set the current value of the field
  *
- * @param {File|null} file File to select
+ * @param {File[]|null} files Files to select
  */
-OO.ui.SelectFileWidget.prototype.setValue = function ( file ) {
-       if ( this.currentFile !== file ) {
-               this.currentFile = file;
-               this.updateUI();
-               this.emit( 'change', this.currentFile );
+OO.ui.SelectFileWidget.prototype.setValue = function ( files ) {
+       if ( files && !this.multiple ) {
+               files = files.slice( 0, 1 );
+       }
+
+       function comparableFile( file ) {
+               // Use extend to convert to plain objects so they can be compared.
+               return $.extend( {}, file );
+       }
+
+       if ( !OO.compare(
+               files && files.map( comparableFile ),
+               this.currentFiles && this.currentFiles.map( comparableFile )
+       ) ) {
+               this.currentFiles = files || [];
+               this.emit( 'change', this.currentFiles );
        }
 };
 
 /**
- * Update the user interface when a file is selected or unselected
- *
- * @protected
+ * @inheritdoc
+ */
+OO.ui.SelectFileWidget.prototype.getFilename = function () {
+       return this.currentFiles.map( function ( file ) {
+               return file.name;
+       } ).join( ', ' );
+};
+
+/**
+ * Disable InputWidget#onEdit listener, onFileSelected is used instead.
+ * @inheritdoc
+ */
+OO.ui.SelectFileWidget.prototype.onEdit = function () {};
+
+/**
+ * @inheritdoc
  */
 OO.ui.SelectFileWidget.prototype.updateUI = function () {
-       var $label;
-       if ( !this.isSupported ) {
-               this.$element.addClass( 'oo-ui-selectFileWidget-notsupported' );
-               this.$element.removeClass( 'oo-ui-selectFileWidget-empty' );
-               this.setLabel( this.notsupported );
+       // Too early, or not supported
+       if ( !this.selectButton || !this.constructor.static.isSupported() ) {
+               return;
+       }
+
+       // Parent method
+       OO.ui.SelectFileWidget.super.prototype.updateUI.call( this );
+
+       if ( this.currentFiles.length ) {
+               this.$element.removeClass( 'oo-ui-selectFileInputWidget-empty' );
+
+               if ( this.showDropTarget ) {
+                       this.pushPending();
+                       this.loadAndGetImageUrl( this.currentFiles[ 0 ] ).done( function ( url ) {
+                               this.$thumbnail.css( 'background-image', 'url( ' + url + ' )' );
+                       }.bind( this ) ).fail( function () {
+                               this.$thumbnail.append(
+                                       new OO.ui.IconWidget( {
+                                               icon: 'attachment',
+                                               classes: [ 'oo-ui-selectFileWidget-noThumbnail-icon' ]
+                                       } ).$element
+                               );
+                       }.bind( this ) ).always( function () {
+                               this.popPending();
+                       }.bind( this ) );
+                       this.$element.off( 'click' );
+               }
        } else {
-               this.$element.addClass( 'oo-ui-selectFileWidget-supported' );
-               if ( this.currentFile ) {
-                       this.$element.removeClass( 'oo-ui-selectFileWidget-empty' );
-                       $label = $( [] );
-                       $label = $label.add(
-                               $( '<span>' )
-                                       .addClass( 'oo-ui-selectFileWidget-fileName' )
-                                       .text( this.currentFile.name )
-                       );
-                       this.setLabel( $label );
-
-                       if ( this.showDropTarget ) {
-                               this.pushPending();
-                               this.loadAndGetImageUrl().done( function ( url ) {
-                                       this.$thumbnail.css( 'background-image', 'url( ' + url + ' )' );
-                               }.bind( this ) ).fail( function () {
-                                       this.$thumbnail.append(
-                                               new OO.ui.IconWidget( {
-                                                       icon: 'attachment',
-                                                       classes: [ 'oo-ui-selectFileWidget-noThumbnail-icon' ]
-                                               } ).$element
-                                       );
-                               }.bind( this ) ).always( function () {
-                                       this.popPending();
-                               }.bind( this ) );
-                               this.$element.off( 'click' );
-                       }
-               } else {
-                       if ( this.showDropTarget ) {
-                               this.$element.off( 'click' );
-                               this.$element.on( {
-                                       click: this.onDropTargetClick.bind( this )
-                               } );
-                               this.$thumbnail
-                                       .empty()
-                                       .css( 'background-image', '' );
-                       }
-                       this.$element.addClass( 'oo-ui-selectFileWidget-empty' );
-                       this.setLabel( this.placeholder );
+               if ( this.showDropTarget ) {
+                       this.$element.off( 'click' );
+                       this.$element.on( {
+                               click: this.onDropTargetClick.bind( this )
+                       } );
+                       this.$thumbnail
+                               .empty()
+                               .css( 'background-image', '' );
                }
+               this.$element.addClass( 'oo-ui-selectFileInputWidget-empty' );
        }
 };
 
 /**
  * If the selected file is an image, get its URL and load it.
  *
+ * @param {File} file File
  * @return {jQuery.Promise} Promise resolves with the image URL after it has loaded
  */
-OO.ui.SelectFileWidget.prototype.loadAndGetImageUrl = function () {
+OO.ui.SelectFileWidget.prototype.loadAndGetImageUrl = function ( file ) {
        var deferred = $.Deferred(),
-               file = this.currentFile,
                reader = new FileReader();
 
        if (
-               file &&
                ( OO.getProp( file, 'type' ) || '' ).indexOf( 'image/' ) === 0 &&
                file.size < this.thumbnailSizeLimit * 1024 * 1024
        ) {
@@ -5769,107 +5824,23 @@ OO.ui.SelectFileWidget.prototype.loadAndGetImageUrl = function () {
 };
 
 /**
- * Add the input to the widget
- *
- * @private
- */
-OO.ui.SelectFileWidget.prototype.addInput = function () {
-       if ( this.$input ) {
-               this.$input.remove();
-       }
-
-       if ( !this.isSupported ) {
-               this.$input = null;
-               return;
-       }
-
-       this.$input = $( '<input>' ).attr( 'type', 'file' );
-       this.$input.on( 'change', this.onFileSelectedHandler );
-       this.$input.on( 'click', function ( e ) {
-               // Prevents dropTarget to get clicked which calls
-               // a click on this input
-               e.stopPropagation();
-       } );
-       this.$input.attr( {
-               tabindex: -1
-       } );
-       if ( this.accept ) {
-               this.$input.attr( 'accept', this.accept.join( ', ' ) );
-       }
-       this.selectButton.$button.append( this.$input );
-};
-
-/**
- * Determine if we should accept this file
- *
- * @private
- * @param {string} mimeType File MIME type
- * @return {boolean}
- */
-OO.ui.SelectFileWidget.prototype.isAllowedType = function ( mimeType ) {
-       var i, mimeTest;
-
-       if ( !this.accept || !mimeType ) {
-               return true;
-       }
-
-       for ( i = 0; i < this.accept.length; i++ ) {
-               mimeTest = this.accept[ i ];
-               if ( mimeTest === mimeType ) {
-                       return true;
-               } else if ( mimeTest.substr( -2 ) === '/*' ) {
-                       mimeTest = mimeTest.substr( 0, mimeTest.length - 1 );
-                       if ( mimeType.substr( 0, mimeTest.length ) === mimeTest ) {
-                               return true;
-                       }
-               }
-       }
-
-       return false;
-};
-
-/**
- * Handle file selection from the input
- *
- * @private
- * @param {jQuery.Event} e
+ * @inheritdoc
  */
 OO.ui.SelectFileWidget.prototype.onFileSelected = function ( e ) {
-       var file = OO.getProp( e.target, 'files', 0 ) || null;
+       var files;
 
-       if ( file && !this.isAllowedType( file.type ) ) {
-               file = null;
+       if ( this.inputClearing ) {
+               return;
        }
 
-       this.setValue( file );
-       this.addInput();
-};
+       files = this.filterFiles( e.target.files || [] );
 
-/**
- * Handle clear button click events.
- *
- * @private
- * @return {undefined/boolean} False to prevent default if event is handled
- */
-OO.ui.SelectFileWidget.prototype.onClearClick = function () {
-       this.setValue( null );
-       return false;
-};
+       // After a file is selected clear the native widget to avoid confusion
+       this.inputClearing = true;
+       this.$input[ 0 ].value = '';
+       this.inputClearing = false;
 
-/**
- * Handle key press events.
- *
- * @private
- * @param {jQuery.Event} e Key press event
- * @return {undefined/boolean} False to prevent default if event is handled
- */
-OO.ui.SelectFileWidget.prototype.onKeyPress = function ( e ) {
-       if ( this.isSupported && !this.isDisabled() && this.$input &&
-               ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER )
-       ) {
-               this.$input.trigger( 'click' );
-               return false;
-       }
+       this.setValue( files );
 };
 
 /**
@@ -5877,10 +5848,10 @@ OO.ui.SelectFileWidget.prototype.onKeyPress = function ( e ) {
  *
  * @private
  * @param {jQuery.Event} e Key press event
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.SelectFileWidget.prototype.onDropTargetClick = function () {
-       if ( this.isSupported && !this.isDisabled() && this.$input ) {
+       if ( !this.isDisabled() && this.$input ) {
                this.$input.trigger( 'click' );
                return false;
        }
@@ -5891,17 +5862,17 @@ OO.ui.SelectFileWidget.prototype.onDropTargetClick = function () {
  *
  * @private
  * @param {jQuery.Event} e Drag event
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.SelectFileWidget.prototype.onDragEnterOrOver = function ( e ) {
-       var itemOrFile,
-               droppableFile = false,
+       var itemsOrFiles,
+               hasDroppableFile = false,
                dt = e.originalEvent.dataTransfer;
 
        e.preventDefault();
        e.stopPropagation();
 
-       if ( this.isDisabled() || !this.isSupported ) {
+       if ( this.isDisabled() ) {
                this.$element.removeClass( 'oo-ui-selectFileWidget-canDrop' );
                dt.dropEffect = 'none';
                return false;
@@ -5909,21 +5880,21 @@ OO.ui.SelectFileWidget.prototype.onDragEnterOrOver = function ( e ) {
 
        // DataTransferItem and File both have a type property, but in Chrome files
        // have no information at this point.
-       itemOrFile = OO.getProp( dt, 'items', 0 ) || OO.getProp( dt, 'files', 0 );
-       if ( itemOrFile ) {
-               if ( this.isAllowedType( itemOrFile.type ) ) {
-                       droppableFile = true;
+       itemsOrFiles = dt.items || dt.files;
+       if ( itemsOrFiles && itemsOrFiles.length ) {
+               if ( this.filterFiles( itemsOrFiles ).length ) {
+                       hasDroppableFile = true;
                }
        // dt.types is Array-like, but not an Array
        } else if ( Array.prototype.indexOf.call( OO.getProp( dt, 'types' ) || [], 'Files' ) !== -1 ) {
                // File information is not available at this point for security so just assume
                // it is acceptable for now.
                // https://bugzilla.mozilla.org/show_bug.cgi?id=640534
-               droppableFile = true;
+               hasDroppableFile = true;
        }
 
-       this.$element.toggleClass( 'oo-ui-selectFileWidget-canDrop', droppableFile );
-       if ( !droppableFile ) {
+       this.$element.toggleClass( 'oo-ui-selectFileWidget-canDrop', hasDroppableFile );
+       if ( !hasDroppableFile ) {
                dt.dropEffect = 'none';
        }
 
@@ -5945,27 +5916,22 @@ OO.ui.SelectFileWidget.prototype.onDragLeave = function () {
  *
  * @private
  * @param {jQuery.Event} e Drop event
- * @return {undefined/boolean} False to prevent default if event is handled
+ * @return {undefined|boolean} False to prevent default if event is handled
  */
 OO.ui.SelectFileWidget.prototype.onDrop = function ( e ) {
-       var file = null,
+       var files,
                dt = e.originalEvent.dataTransfer;
 
        e.preventDefault();
        e.stopPropagation();
        this.$element.removeClass( 'oo-ui-selectFileWidget-canDrop' );
 
-       if ( this.isDisabled() || !this.isSupported ) {
+       if ( this.isDisabled() ) {
                return false;
        }
 
-       file = OO.getProp( dt, 'files', 0 );
-       if ( file && !this.isAllowedType( file.type ) ) {
-               file = null;
-       }
-       if ( file ) {
-               this.setValue( file );
-       }
+       files = this.filterFiles( dt.files || [] );
+       this.setValue( files );
 
        return false;
 };
@@ -5974,14 +5940,10 @@ OO.ui.SelectFileWidget.prototype.onDrop = function ( e ) {
  * @inheritdoc
  */
 OO.ui.SelectFileWidget.prototype.setDisabled = function ( disabled ) {
+       disabled = disabled || !this.constructor.static.isSupported();
+
+       // Parent method
        OO.ui.SelectFileWidget.parent.prototype.setDisabled.call( this, disabled );
-       if ( this.selectButton ) {
-               this.selectButton.setDisabled( disabled );
-       }
-       if ( this.clearButton ) {
-               this.clearButton.setDisabled( disabled );
-       }
-       return this;
 };
 
 /**
index b3687a7..91236ac 100644 (file)
@@ -1 +1 @@
-{"version":3,"sources":["../src/intro.js.txt","../src/mixins/DraggableElement.js","../src/mixins/DraggableGroupElement.js","../src/mixins/RequestManager.js","../src/mixins/LookupElement.js","../src/layouts/TabPanelLayout.js","../src/layouts/PageLayout.js","../src/layouts/StackLayout.js","../src/layouts/MenuLayout.js","../src/layouts/BookletLayout.js","../src/layouts/IndexLayout.js","../src/widgets/ToggleWidget.js","../src/widgets/ToggleButtonWidget.js","../src/widgets/ToggleSwitchWidget.js","../src/widgets/OutlineControlsWidget.js","../src/widgets/OutlineOptionWidget.js","../src/widgets/OutlineSelectWidget.js","../src/widgets/ButtonOptionWidget.js","../src/widgets/ButtonSelectWidget.js","../src/widgets/TabOptionWidget.js","../src/widgets/TabSelectWidget.js","../src/widgets/TagItemWidget.js","../src/widgets/TagMultiselectWidget.js","../src/widgets/PopupTagMultiselectWidget.js","../src/widgets/MenuTagMultiselectWidget.js","../src/widgets/SelectFileWidget.js","../src/widgets/SearchWidget.js","../src/outro.js.txt"],"names":[],"mappings":";;;;;;;;;;AAAA,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACnB;AACA,CAAC,GAAG,CAAC,MAAM,EAAE;;ACFb,GAAG;AACH,CAAC,CAAC,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO;AAChF,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI;AACnF,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG;AACxF,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC;AAC1B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO;AACjD,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE;AAC9F,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,OAAO;AACrB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,eAAe;AAC5F,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC,KAAK,CAAC,OAAO;AAC1F,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK;AACnB,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC7E,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG;AACvB;AACA,CAAC,EAAE,CAAC,UAAU;AACd,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACnB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC;AAChD,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3B;AACA,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM;AACzB,CAAC,IAAI,EAAE,OAAO;AACd,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC;AACvC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACR,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAChD,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAC5C,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAC1C,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AACxC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACjC,EAAE,CAAC,CAAC,EAAE;AACN,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,EAAE;AAC1D,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,EAAE;AACpF,EAAE;AACF;AACA,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE;AAC7C;AACA,EAAE,CAAC,MAAM,CAAC,EAAE;AACZ;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS;AACnB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC;AACjF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI;AAChG,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC;AACd,CAAC,EAAE;AACH;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO;AACjB,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACjF,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC;AACvC,CAAC,EAAE;AACH;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;AACd,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM;AACzF,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;AACvB,CAAC,EAAE;AACH;AACA,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE;AACvB;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa;AACxC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,2BAA2B,CAAC,CAAC,CAAC,KAAK,CAAC;AACxE;AACA,EAAE,CAAC,OAAO,CAAC,EAAE;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC7C,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC;AACjE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,UAAU;AACpE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS;AACnB,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACnF,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;AAC3E;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACxC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC;AAC/B;AACA,EAAE,IAAI,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;AACpF;AACA,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI;AACvE,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI;AACzE,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM;AAChC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;AACpD,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC5C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,UAAU;AACzD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAClE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;AACvB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC;AAC9B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK;AACrC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;AAC7B,EAAE,MAAM,CAAC;AACT,CAAC,CAAC;AACF;AACA,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;AACrB,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI;AACzE,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC7C,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM;AACnD,EAAE,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE;AACtD,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC;AAC9B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK;AACrC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS;AACpD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS;AACnB,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACpB,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC;AAC9C;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;AACpD,EAAE,MAAM,CAAC,KAAK,CAAC;AACf,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM;AACtB,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;AAClC,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;AACrC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,OAAO;AACpB,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;AACnE,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC;AAC7C,CAAC,GAAG,CAAC,CAAC;AACN,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE;AAC1E,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAClB,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;AACxD,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK;AACxE,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,EAAE;AAC1D,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK;AAClE,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC1B,EAAE,OAAO,EAAE,OAAO;AAClB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC;AACjD,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC,EAAE;AACrD,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK;AACd,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE;AAChC,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;AAC5B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO;AACjB,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAChE,CAAC,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC,EAAE;AACnE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE;AACxB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACrB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK;AACrC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC,CAAC,CAAC,cAAc,GAAG;AACpB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE;AACxB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI;AAC1D,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC;AACrC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK;AACrC,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpE,CAAC,CAAC,CAAC,cAAc,GAAG;AACpB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;AAClB,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACnE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK;AACnC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AACrB,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,EAAE;AACvC,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;AAClB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK;AAC9B,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC/D,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACnB,EAAE;;ACzNF,GAAG;AACH,CAAC,CAAC,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;AAC3E,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;AAC1F,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC;AACvD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AACnC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO;AACjD,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,WAAW;AAC5F,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG;AACzE,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;AACjG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC;AAChF,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,eAAe;AAC5F,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,8BAA8B,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACvF,CAAC,EAAE,CAAC,aAAa,CAAC,cAAc;AAChC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG;AACvB;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAC/C;AACA,CAAC,EAAE,CAAC,UAAU;AACd,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;AACrD,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AACtB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG;AACpB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AACjB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AACxB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC;AAC7E;AACA,CAAC,EAAE,CAAC,MAAM;AACV,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;AAClB,EAAE,SAAS,CAAC,CAAC,CAAC,aAAa,EAAE;AAC7B,EAAE,OAAO,CAAC,CAAC,CAAC,WAAW,EAAE;AACzB,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC;AAClB,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACtB,EAAE,aAAa,CAAC,CAAC,CAAC,eAAe,EAAE;AACnC,EAAE,QAAQ,CAAC,CAAC,CAAC,mBAAmB,EAAE;AAClC,EAAE,WAAW,CAAC,CAAC,CAAC,mBAAmB,CAAC;AACpC,CAAC,CAAC,CAAC,EAAE;AACL;AACA,CAAC,EAAE,CAAC,UAAU;AACd,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;AAChC,CAAC,CAAC;AACF,CAAC,IAAI,EAAE,OAAO;AACd,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,CAAC,CAAC;AAC5C,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,EAAE;AAC9F,EAAE;AACF;AACA,EAAE,CAAC,KAAK,CAAC,EAAE;AACX,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE;AAC7E;AACA,EAAE,CAAC,MAAM,CAAC,EAAE;AACZ;AACA,GAAG;AACH,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;AACnE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;AACd,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI;AAC1D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI;AACpD,CAAC,EAAE;AACH;AACA,GAAG;AACH,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC9C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO;AACjB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI;AAC5D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI;AACpD,CAAC,EAAE;AACH;AACA,GAAG;AACH,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC;AAC9C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS;AACnB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS;AACnD,CAAC,EAAE;AACH;AACA,EAAE,CAAC,OAAO,CAAC,EAAE;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC7C,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC;AACjE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,UAAU;AACpE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS;AACnB,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACxF,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;AAC3E;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACxC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC;AAC/B;AACA,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO;AACjD,EAAE,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC9C,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;AAC1C,EAAE,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AACnB;AACA,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK;AACf,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;AAC3C,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM;AAC3C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,UAAU;AACzD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACvE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;AACvB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK;AACnC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI;AAC1D,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjF,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;AAC7B,EAAE,MAAM,CAAC;AACT,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ;AAC3E,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC;AACzC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG;AACtC,CAAC,IAAI,CAAC,aAAa,GAAG;AACtB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3C,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM;AACrE,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;AACtD,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AAC9C,CAAC,CAAC;AACF,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE;AAC1B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK;AAC3C,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACzE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AACZ;AACA,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM;AAChC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5D,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;AACrC,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW;AAC7E,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI;AAC1D,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,QAAQ;AACpD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC/E,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,aAAa,CAAC;AAChC,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG;AAC5B;AACA,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS;AACnE,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI;AACjD,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACd,EAAE,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE;AAC7C,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK;AACtF,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9E,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AACxC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,WAAW,CAAC,EAAE;AACnD,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,WAAW,CAAC,EAAE;AAC3D,EAAE,CAAC;AACH,EAAE,IAAI,CAAC,aAAa,GAAG;AACvB,CAAC,CAAC;AACF,CAAC,IAAI,CAAC,aAAa,GAAG;AACtB,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,WAAW;AACvC,CAAC,MAAM,CAAC,KAAK,CAAC;AACd,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK;AAC5B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK;AACzC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO;AACjB,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC;AAC5B,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG;AAC5B,EAAE,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG;AAClC;AACA,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI;AAClD,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;AAChF;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AAChE,EAAE,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAClE;AACA,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1B,GAAG,IAAI,EAAE,KAAK,CAAC,QAAQ,GAAG,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE;AACvE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACV,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE;AACxC,EAAE,CAAC;AACH,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK;AAClC,EAAE,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACvC,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAClD,EAAE,EAAE;AACJ,EAAE,IAAI,CAAC,aAAa,GAAG;AACvB,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,EAAE;AACzC,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO;AACnB,CAAC,CAAC,CAAC,cAAc,GAAG;AACpB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK;AACjC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI;AAC5D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK;AACrC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACnF,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE;AACrC,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI;AACrB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI;AAC1D,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC7E,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAChC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AACvB,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AAC/D,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC,EAAE;AACnE,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI;AACjC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACzE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACvB,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AACvB,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE;AAClC,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC,EAAE;AACtE,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC;AAChD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;AAClG,CAAC,CAAC,EAAE,KAAK,CAAC,OAAO;AACjB,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACvE,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;AACtB,EAAE;;AC7PF,GAAG;AACH,CAAC,CAAC,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;AACjG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE;AACjD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,uBAAuB,EAAE,CAAC,CAAC;AACjE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG;AACxB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1B,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5B,EAAE;AACF;AACA,EAAE,CAAC,KAAK,CAAC,EAAE;AACX;AACA,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE;AAC3C;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC;AAC7C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ;AACnG,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI;AAC5F,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;AAC3E,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACnE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACnB,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,GAAG;AACjC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,GAAG;AAC1B,EAAE,UAAU,CAAC;AACb;AACA,CAAC,IAAI,CAAC,YAAY,GAAG;AACrB,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1E,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AACjD,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACT,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC3B,GAAG,IAAI,CAAC,WAAW,GAAG;AACtB,EAAE,CAAC;AACH,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC;AAC5B,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,GAAG;AACvD,EAAE,UAAU;AACZ,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACzB,IAAI,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,SAAS;AACvE,IAAI,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;AAC9C,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK;AACjF,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE;AACvF,IAAI,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE;AACpF,IAAI,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;AACxB,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC9B,KAAK,MAAM,CAAC,UAAU,GAAG;AACzB,IAAI,CAAC;AACL,GAAG,CAAC,CAAC,CAAC;AACN,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACjC,IAAI,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE;AACtF,IAAI,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU;AACpC,IAAI,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AACjD,KAAK,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;AAChC,KAAK,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC;AAClC,KAAK,MAAM,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,MAAM,CAAC,+BAA+B,CAAC,CAAC,QAAQ,CAAC,EAAE;AACzD,KAAK,QAAQ,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AACtD,IAAI,CAAC;AACL,GAAG,CAAC,CAAC,CAAC;AACN,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACvB,IAAI,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE;AACnF,IAAI,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU;AACpC,IAAI,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AACjD,KAAK,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;AAChC,KAAK,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC;AAClC,KAAK,QAAQ,CAAC,MAAM,GAAG;AACvB,IAAI,CAAC;AACL,GAAG,CAAC,CAAC,EAAE;AACP,CAAC,CAAC;AACF,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,GAAG;AAC3B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC;AAC/C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACjE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC;AACtC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACpB,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM;AACpE,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO;AAC1C,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7B,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3B,EAAE,UAAU,CAAC,KAAK,GAAG;AACrB,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;AAC5B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM;AACV,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI;AACpC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5D;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;AACvD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM;AACV,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,MAAM;AACzF,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AACvD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK;AAChG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM;AACV,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM;AAC/C,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI;AACrC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,+BAA+B,CAAC,CAAC,CAAC,IAAI,CAAC;;AC7H5E,GAAG;AACH,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,SAAS;AAC3F,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AAC9F,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI;AAC5F,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK;AACjG,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;AACxC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG;AACvF,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG;AAClF,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC;AAC1E,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC;AAC1C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,GAAG,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO;AAC9F,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc;AACrC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO;AACjD,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;AAC1F,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE;AAChE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ;AAC9F,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC;AAClC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;AACxD,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;AACrD,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,yBAAyB,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;AAC9F,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC;AACxB,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC;AAC7F,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW;AAC7F,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,aAAa;AACjG,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC;AACX,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACvE,CAAC,EAAE,CAAC,aAAa,CAAC,cAAc;AAChC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;AACvD;AACA,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACjD;AACA,CAAC,EAAE,CAAC,UAAU;AACd,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC7C,EAAE,EAAE,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC;AACjE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAC1D,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC;AACf,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC;AACd,EAAE,CAAC,kBAAkB,CAAC,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO;AACzD,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AACpB;AACA,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAC,MAAM,CAAC,yBAAyB,CAAC,EAAE,CAAC,KAAK,CAAC;AAC5E;AACA,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC;AAC9B,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,KAAK,CAAC;AACjC,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC;AACvD;AACA,CAAC,EAAE,CAAC,MAAM;AACV,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;AAClB,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAC9C,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAC5C,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACrD,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACtB,EAAE,MAAM,CAAC,CAAC,CAAC,mBAAmB,CAAC;AAC/B,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACjC,EAAE,MAAM,CAAC,CAAC,CAAC,kBAAkB,EAAE;AAC/B,EAAE,MAAM,CAAC,CAAC,CAAC,sBAAsB,CAAC;AAClC,CAAC,CAAC,CAAC,EAAE;AACL;AACA,CAAC,EAAE,CAAC,cAAc;AAClB,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;AACpB,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE;AACnB,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,GAAG;AAC9C,EAAE,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC;AAC7B,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE;AACjD,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,EAAE;AACjE,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,EAAE;AAClD,EAAE;AACF;AACA,EAAE,CAAC,KAAK,CAAC,EAAE;AACX;AACA,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE;AACvE;AACA,EAAE,CAAC,OAAO,CAAC,EAAE;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC;AAC5B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK;AAC5C,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACtE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC;AAChC,CAAC,IAAI,CAAC,kBAAkB,GAAG;AAC3B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;AAC3B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK;AAC3C,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACrE,CAAC,IAAI,CAAC,eAAe,GAAG;AACxB,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,KAAK,CAAC;AACjC,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;AACjC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK;AACjD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC1E,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AACxD,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC;AACxF,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS;AAC9E,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC;AAC5D,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;AACjE,EAAE,IAAI,CAAC,kBAAkB,GAAG;AAC5B,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;AAC7B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK;AACxC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACvE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;AACjC,EAAE,IAAI,CAAC,kBAAkB,GAAG;AAC5B,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC;AAC7C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC;AACnE,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC/E,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAClB,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;AAC1E,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,eAAe,GAAG,CAAC,OAAO;AACvE,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE;AAC3E,EAAE,IAAI,CAAC,kBAAkB,GAAG;AAC5B,EAAE,IAAI,CAAC,UAAU,CAAC,UAAU,GAAG;AAC/B,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC;AACnG,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI;AACrD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAChF,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE;AACjC,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;AACnB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC;AACnC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACjE,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;AACxB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC;AAChC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;AAC3E,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO;AAC5C,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAChF,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC;AACnC,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,QAAQ;AACpD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAClE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;AACpC,EAAE,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE;AACjC,CAAC,CAAC;AACF,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;AAC3D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,QAAQ;AACpD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACnE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE;AACjC,CAAC,IAAI,CAAC,kBAAkB,GAAG;AAC3B,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,GAAG;AAC9B,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/E,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;AACxD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC;AACtF,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,QAAQ;AACpD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACtE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACnB,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG;AAC1B;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;AACnD,EAAE,MAAM,CAAC;AACT,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC;AACrF,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACzD,EAAE,IAAI,CAAC,eAAe,GAAG;AACzB,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK;AAC/E,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC3C,EAAE,IAAI,CAAC,kBAAkB,EAAE;AAC3B,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,IAAI,MAAM,CAAC,UAAU,CAAC,UAAU,GAAG;AACnC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACzB,KAAK,MAAM,CAAC,UAAU;AACtB,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC;AACxB,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE;AACtB,KAAK,MAAM,CAAC,6BAA6B,GAAG;AAC5C,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ,KAAK,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE;AACvC,IAAI,CAAC;AACL,GAAG,CAAC,CAAC,CAAC;AACN,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACvB,IAAI,MAAM,CAAC,UAAU,CAAC,UAAU,GAAG;AACnC,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE;AACtC,GAAG,CAAC,CAAC,EAAE;AACP,CAAC,CAAC;AACF;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC;AAClE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACjF,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,wBAAwB,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9E,EAAE,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,uBAAuB,EAAE,CAAC,EAAE;AAC7E,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC;AAC/C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE;AACnG,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO;AAClG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;AAC1D,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACtE,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACvD,EAAE,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC,IAAI,CAAC,EAAE;AACnD,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AAClB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC;AACtD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACtE,CAAC,IAAI,CAAC,YAAY,GAAG;AACrB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;AAC9D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM;AACV,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,MAAM;AACzF,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5D;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,gBAAgB,CAAC;AACnE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK;AAChG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM;AACV,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM;AAC/C,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI;AACrC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,8BAA8B,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1E;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;AAChF,CAAC,CAAC,CAAC,CAAC,8BAA8B,CAAC;AACnC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM;AACV,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK;AAC3D,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,GAAG,CAAC,IAAI,CAAC,KAAK;AAChD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,4BAA4B,CAAC,CAAC,CAAC,IAAI,CAAC;AACxE;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AACzC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC;AAC3D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI;AACjD,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,QAAQ;AACpD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACzE,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM;AACjB,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe;AAC3F,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE;AACpE;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC;AACjG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC9C,EAAE,IAAI,CAAC,eAAe,GAAG;AACzB,CAAC,CAAC;AACF;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc;AACzC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACnE,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,GAAG;AACxB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc;AACzC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC9D,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,GAAG;AAChC,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc;AACzC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,+BAA+B,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC7F,CAAC,MAAM,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC,QAAQ,CAAC,EAAE;AACxD,EAAE;;AChXF,GAAG;AACH,CAAC,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI;AACpG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC;AAC3F,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG;AAC9F,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;AACtC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC;AACpG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG;AAC5F,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC;AACxD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW;AAC7B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK;AACzD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO;AACjD,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG;AACpF,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACpE,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM;AAChE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC1D,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAChB,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,aAAa,CAAC,cAAc;AAChC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;AACnD;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAClD;AACA,CAAC,EAAE,CAAC,UAAU;AACd,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAClB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;AAC3B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACrB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;AACrB;AACA,CAAC,EAAE,CAAC,cAAc;AAClB,CAAC,IAAI,EAAE,OAAO;AACd,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC;AACrC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE;AAC9B,EAAE;AACF;AACA,EAAE,CAAC,KAAK,CAAC,EAAE;AACX;AACA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE;AAC3D;AACA,EAAE,CAAC,MAAM,CAAC,EAAE;AACZ;AACA,GAAG;AACH,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI;AAChG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/F,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM;AAC9C,CAAC,EAAE;AACH;AACA,EAAE,CAAC,OAAO,CAAC,EAAE;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC;AAC1C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK;AAC9C,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACtD,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;AAClB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC;AAChC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE;AACnG,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACnG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC;AACxC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM;AACxC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACvD,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;AACpB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;AAChB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG;AACzE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG;AAC1F,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC;AACxB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM;AACzD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACzD,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;AACrB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;AAC7B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;AAChE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjG,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AACpD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK;AAC/E,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AAC1D,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC;AAChC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACjB,EAAE,IAAI,CAAC,YAAY,GAAG;AACtB,CAAC,CAAC;AACF,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;AACvB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK;AACjG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG;AACvF,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC;AAClC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE;AACrE,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AAC1D,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC3D,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,EAAE;AACtE;AACA,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,EAAE;AACpE;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpB,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AACtC,CAAC,CAAC;AACF,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC;AAC3C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI;AACpG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AAChG,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC;AACpG,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM;AAC9C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;AACnB;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAChC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;AACvB,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;AAC1E,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;AACrC,CAAC,CAAC;AACF,EAAE;;ACzJF,GAAG;AACH,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI;AAC/F,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ;AAC3D,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AAC3F,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;AAC/E,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,GAAG;AACnG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG;AAClF,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC;AAC1F,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW;AAC7B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI;AACpD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO;AACjD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC5D,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM;AAChE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC1D,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAChB,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,aAAa,CAAC,cAAc;AAChC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;AACnD;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAC9C;AACA,CAAC,EAAE,CAAC,UAAU;AACd,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAClB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;AACrB;AACA,CAAC,EAAE,CAAC,cAAc;AAClB,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE;AAC9C,EAAE;AACF;AACA,EAAE,CAAC,KAAK,CAAC,EAAE;AACX;AACA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE;AACvD;AACA,EAAE,CAAC,MAAM,CAAC,EAAE;AACZ;AACA,GAAG;AACH,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;AAC/F,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACnF,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM;AACzC,CAAC,EAAE;AACH;AACA,EAAE,CAAC,OAAO,CAAC,EAAE;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;AACrC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI;AACzC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAClD,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;AAClB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;AAC3B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE;AAClG,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO;AACjG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC;AACpC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM;AACnC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACnD,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;AACpB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC;AACpB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO;AAC9E,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG;AAC9F,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,MAAM,CAAC;AAC5B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM;AACjE,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACzD,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC;AACzB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC;AACjC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;AACzE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK;AAClG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AACnE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK;AAC3F,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AACtD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC;AACxC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACrB,EAAE,IAAI,CAAC,gBAAgB,GAAG;AAC1B,CAAC,CAAC;AACF,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC;AAC3B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE;AACnG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE;AAC7F,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC;AACnD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE;AACjF,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AACtD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC3D,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC;AACtC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI;AACjG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM;AACjG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;AAC1F,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM;AACzC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC5D,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;AACnB;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAChC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;AACvB,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE;AACjE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;AACrC,CAAC,CAAC;AACF,EAAE;;AC9IF,GAAG;AACH,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG;AACjG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;AAC3F,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE;AACpF,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,CAAC,OAAO;AACf,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,YAAY;AACjF,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;AAC7C,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC;AACnB,CAAC,CAAC,aAAa,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;AACvC,CAAC,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE;AACrD,CAAC,CAAC,iBAAiB,MAAM,CAAC,CAAC,IAAI,CAAC;AAChC,CAAC,CAAC,iBAAiB,MAAM,CAAC,CAAC,IAAI;AAC/B,CAAC,CAAC,aAAa,CAAC,CAAC,EAAE;AACnB,CAAC,CAAC,aAAa,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;AACvC,CAAC,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE;AACrD,CAAC,CAAC,iBAAiB,MAAM,CAAC,CAAC,IAAI,CAAC;AAChC,CAAC,CAAC,iBAAiB,MAAM,CAAC,CAAC,IAAI;AAC/B,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,SAAS,EAAE;AACb,CAAC,CAAC,SAAS,UAAU,CAAC,CAAC,IAAI;AAC3B,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;AACX,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW;AAC7B,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AACnC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO;AACjD,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK;AACnG,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3B,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1E,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC,EAAE,CAAC,aAAa,CAAC,cAAc;AAChC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,IAAI;AACjE,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC;AAC/C,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;AAChF;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAC/C;AACA,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AACtF;AACA,CAAC,EAAE,CAAC,UAAU;AACd,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;AACvC;AACA,CAAC,EAAE,CAAC,cAAc;AAClB,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE;AAC/C,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACzB,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,EAAE;AAC3D,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;AAClF,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;AAChC,CAAC,CAAC;AACF,EAAE;AACF;AACA,EAAE,CAAC,KAAK,CAAC,EAAE;AACX;AACA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE;AACxD,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE;AAC7D;AACA,EAAE,CAAC,MAAM,CAAC,EAAE;AACZ;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,WAAW,CAAC,OAAO,EAAE;AAClG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG;AACb,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK;AAC/E,CAAC,EAAE;AACH;AACA,GAAG;AACH,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI;AACjF,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC;AACzD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,iBAAiB;AAC3B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AACvE,CAAC,EAAE;AACH;AACA,EAAE,CAAC,OAAO,CAAC,EAAE;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO;AAC/C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AAC1B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,iBAAiB;AAC3B,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACpD,CAAC,GAAG,CAAC,WAAW,CAAC;AACjB,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1B,EAAE,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;AACxD,EAAE,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC;AAC1B,EAAE,aAAa,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,qBAAqB,GAAG;AAC7D;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3E,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;AACpD,EAAE,MAAM,CAAC;AACT,CAAC,CAAC;AACF;AACA,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC3B,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,qBAAqB,GAAG;AACpD,CAAC,CAAC;AACF;AACA,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC7B,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE;AAC7B,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC;AAC5E,CAAC,CAAC;AACF;AACA,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;AAC3C;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAChD,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI;AACpC,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC9B,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/C,IAAI,KAAK,CAAC;AACV,GAAG,CAAC;AACJ,EAAE,CAAC;AACH,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACvD,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI;AAClC,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/C,IAAI,KAAK,CAAC;AACV,GAAG,CAAC;AACJ,EAAE,CAAC;AACH,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACnC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;AAC3D,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC;AACzB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC;AAC9B,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC1D,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC;AACzB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC;AAC1B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,MAAM;AACpC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG;AACb,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC5D,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;AACjC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC3B,EAAE,MAAM,CAAC;AACT,CAAC,CAAC;AACF;AACA,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE;AAC1B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;AACzC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS;AAChG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;AAClG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AAC/D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG;AAC9C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK;AACvD,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AACvD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU;AACzB,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;AACnD;AACA,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE;AACxE;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC3C,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC7B,CAAC,CAAC;AACF;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG;AACnG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC;AAC9D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM;AACjD,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AACvD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG;AACb,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9D,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE;AACpE;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClD,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC5B,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACnC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACV,GAAG,IAAI,CAAC,gBAAgB,GAAG;AAC3B,EAAE,CAAC;AACH,CAAC,CAAC;AACF;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI;AACpG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC;AACnD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AACvD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG;AACb,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACtD,CAAC,IAAI,CAAC,gBAAgB,GAAG;AACzB,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAC5D;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC;AAC5B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;AAC9D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI;AAC3C,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AACvD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG;AACb,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACzD,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACnC,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE;AAC7C;AACA,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3B,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE;AAC5B,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACV,GAAG,IAAI,CAAC,gBAAgB,GAAG;AAC3B,EAAE,CAAC;AACH,CAAC,CAAC;AACF;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,UAAU;AACxE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACvD,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACzB,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM;AAClB,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AACrE,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK;AACpB,CAAC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9C,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE;AACjE,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO;AACnD,EAAE,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE;AACvD,EAAE,KAAK,CAAC,WAAW,GAAG;AACtB,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACjB,GAAG,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE;AACrD,EAAE,CAAC;AACH,CAAC,CAAC,CAAC,EAAE;AACL;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC;AACrE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;AAC3D,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC;AACzD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI;AACvD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI;AAC7D,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AAClF,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AACZ;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC1B,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACnD,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxD,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE;AAC3D,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACtD,GAAG,CAAC;AACJ,EAAE,CAAC;AACH,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACvB,GAAG,YAAY,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE;AAC/D,GAAG,YAAY,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE;AACrD,EAAE,CAAC;AACH,CAAC,CAAC;AACF,EAAE;;ACjTF,GAAG;AACH,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU;AACnG,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG;AAC9F,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC;AACpE,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,CAAC,OAAO;AACf,CAAC,CAAC,KAAK,GAAG,CAAC,UAAU,CAAC;AACtB,CAAC,CAAC,SAAS,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;AAC/C,CAAC,CAAC,aAAa,MAAM,CAAC,CAAC,IAAI,CAAC;AAC5B,CAAC,CAAC,aAAa,QAAQ,CAAC,CAAC,IAAI,CAAC;AAC9B,CAAC,CAAC,aAAa,UAAU,CAAC,CAAC,IAAI;AAC/B,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AACf,CAAC,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;AAClD,CAAC,CAAC,aAAa,MAAM,CAAC,CAAC,IAAI,CAAC;AAC5B,CAAC,CAAC,aAAa,QAAQ,CAAC,CAAC,IAAI,CAAC;AAC9B,CAAC,CAAC,aAAa,UAAU,CAAC,CAAC,IAAI;AAC/B,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AACf,CAAC,CAAC,SAAS,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;AAC7C,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC;AACvB,CAAC,CAAC,iBAAiB,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;AAC5C,CAAC,CAAC,qBAAqB,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE;AACtC,CAAC,CAAC,qBAAqB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;AACtC,CAAC,CAAC,iBAAiB,CAAC,CAAC,EAAE;AACvB,CAAC,CAAC,iBAAiB,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;AAC5C,CAAC,CAAC,qBAAqB,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE;AACrC,CAAC,CAAC,qBAAqB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AACrC,CAAC,CAAC,iBAAiB,CAAC,CAAC,EAAE;AACvB,CAAC,CAAC,iBAAiB,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;AAC5C,CAAC,CAAC,qBAAqB,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE;AACnC,CAAC,CAAC,qBAAqB,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;AACnC,CAAC,CAAC,iBAAiB,CAAC,CAAC,EAAE;AACvB,CAAC,CAAC,iBAAiB,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;AAC5C,CAAC,CAAC,qBAAqB,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE;AACtC,CAAC,CAAC,qBAAqB,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;AACtC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC;AACtB,CAAC,CAAC,cAAc,CAAC;AACjB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC,CAAC,YAAY,UAAU,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE;AAC3D,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AACf,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;AAC3C,CAAC,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE;AAC3B,CAAC,CAAC,SAAS,SAAS,CAAC,CAAC,SAAS,CAAC;AAChC,CAAC,CAAC,SAAS,YAAY,CAAC,CAAC,YAAY;AACrC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;AACX,CAAC,CAAC,KAAK,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC;AAC/B,CAAC,CAAC,SAAS,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE;AAC7E,CAAC,CAAC,KAAK,EAAE;AACT,CAAC,CAAC,KAAK,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC;AAClC,CAAC,CAAC,SAAS,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC;AACxC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,GAAG;AACtC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACtF,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE;AAChD,CAAC,CAAC,UAAU,EAAE;AACd,CAAC,CAAC,KAAK,EAAE;AACT,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,UAAU,EAAE,OAAO,CAAC,EAAE;AACxD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO;AAC/F,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG;AACjG,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS;AACpG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC;AAClB,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,KAAK,CAAC;AACxB,CAAC,CAAC,SAAS,MAAM,CAAC,CAAC,KAAK,CAAC;AACzB,CAAC,CAAC,KAAK,CAAC;AACR,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;AAClC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC;AACtB,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,KAAK,CAAC;AACvB,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,KAAK,CAAC;AACxB,CAAC,CAAC,SAAS,MAAM,CAAC,CAAC,KAAK,CAAC;AACzB,CAAC,CAAC,KAAK,CAAC;AACR,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM;AACxB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO;AACjD,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK;AAClD,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,KAAK;AACxD,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;AACtF,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI;AAC3C,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC;AAC/F,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACtD,CAAC,EAAE,CAAC,aAAa,CAAC,cAAc;AAChC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AACrB,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC;AACjB,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC;AACjB,EAAE,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC;AACxB,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;AACb;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAC9C;AACA,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AACvB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1B,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;AACnC,CAAC,GAAG;AACJ,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI;AACjB,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC;AACtB,EAAE,EAAE;AACJ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE;AAC3B,CAAC,GAAG;AACJ,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI;AACpB,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC;AACtB,EAAE,EAAE;AACJ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE;AAC9B;AACA,CAAC,EAAE,CAAC,cAAc;AAClB,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE;AAChD,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,EAAE;AACtD,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE;AAC9C,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACzB,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,EAAE;AACxD,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACT,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE;AACtD,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC1B,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE;AACxC,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AAC7B,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE;AAC9C,CAAC,CAAC;AACF,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE;AAC7C,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE;AACpC,EAAE;AACF;AACA,EAAE,CAAC,KAAK,CAAC,EAAE;AACX;AACA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;AAClD;AACA,EAAE,CAAC,OAAO,CAAC,EAAE;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;AACf,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM;AACtD,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AACtD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC/D,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC;AACjE;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACpC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC3B,EAAE,IAAI,EAAE,OAAO;AACf,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC7D,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;AAC/D,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACrE,CAAC,CAAC;AACF;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AAC3B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACpC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACxD,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;AACtB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;AACrB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC;AACzF,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AACtD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACpE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3E,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE;AACtB,CAAC,CAAC;AACF;AACA,CAAC,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE;AACtE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC9B,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACvE,EAAE,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE;AACpD,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACT,EAAE,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE;AACpD,CAAC,CAAC;AACF,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE;AAC1D;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;AACrB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ;AACjC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC1D,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC;AAC1B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;AACtB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK;AAClD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AAC5B,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE;AAC9C,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC;AACzB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK;AACxD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACxE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC;AAClC,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,EAAE;AACpD,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;AACxB,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACzD,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AACvB,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG;AACpB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC;AAC3B,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC5D,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1B,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,GAAG;AACvB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM;AAClE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACtD,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACxB,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,GAAG;AAC/B,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AAC3B,EAAE,IAAI,CAAC,YAAY,CAAC,WAAW,GAAG;AAClC,CAAC,CAAC;AACF;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;;AC1PF,GAAG;AACH,CAAC,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;AAC1E,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ;AACpF,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;AAClF,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;AACtF,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG;AACtF,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI;AAC7E,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC;AACvF,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,CAAC,OAAO;AACf,CAAC,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC;AACnE,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,QAAQ,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC,CAAC,SAAS,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAC3D,CAAC,CAAC,SAAS,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACpG,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,EAAE;AAC7B,CAAC,CAAC,KAAK,CAAC;AACR,CAAC,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE;AAC1D,CAAC,CAAC,KAAK,aAAa,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC/D,CAAC,CAAC,SAAS,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE;AACnD,CAAC,CAAC,KAAK,EAAE;AACT,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,QAAQ,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC,CAAC,SAAS,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAC3D,CAAC,CAAC,SAAS,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE;AACxD,CAAC,CAAC,KAAK,CAAC;AACR,CAAC,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE;AAC1D,CAAC,CAAC,KAAK,aAAa,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC/D,CAAC,CAAC,SAAS,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE;AACnD,CAAC,CAAC,KAAK,EAAE;AACT,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AAC9C,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AAC9C,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC;AAC/C,CAAC,CAAC,SAAS,QAAQ,CAAC,CAAC,IAAI;AACzB,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;AACX,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AAC5C,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU;AAC5B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO;AACjD,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO;AACtE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;AAC1F,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC;AAClC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG;AAChG,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC;AACzB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC;AAC3F,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC5D,CAAC,EAAE,CAAC,aAAa,CAAC,cAAc;AAChC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG;AACvB;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACjD;AACA,CAAC,EAAE,CAAC,UAAU;AACd,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG;AACjB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC;AAC1B,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;AAC5C,EAAE,UAAU,CAAC,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;AAClC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ;AACzB,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;AAC1C,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC;AACvE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC;AAC7B,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;AACnC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACvB,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;AACpC,EAAE,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC;AACpC,EAAE,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,GAAG;AAC7D,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;AAC9C,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;AAC3B,GAAG,UAAU,CAAC,CAAC,IAAI;AACnB,EAAE,CAAC,CAAC,EAAE;AACN,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE;AACzC,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7B,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACxB,GAAG,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC;AAChE,IAAI,IAAI,CAAC,mBAAmB;AAC5B,GAAG,EAAE;AACL,EAAE,CAAC;AACH,CAAC,CAAC;AACF,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;AAClC;AACA,CAAC,EAAE,CAAC,MAAM;AACV,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAClC,EAAE,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC;AACzB,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACvB,EAAE,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3C,GAAG,MAAM,CAAC,CAAC,CAAC,2BAA2B,CAAC;AACxC,EAAE,CAAC,CAAC,EAAE;AACN,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;AACzB,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACnC,GAAG,iBAAiB,CAAC,CAAC,CAAC,8BAA8B,CAAC;AACtD,EAAE,CAAC,CAAC,EAAE;AACN,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACxB,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI;AACtD,EAAE,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AAClF,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,cAAc;AAClB,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE;AACjD,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,EAAE;AACzE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACvB,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO;AAC5B,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC;AAClD,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,mBAAmB,EAAE,OAAO,CAAC,EAAE;AAChD,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACxB,GAAG,IAAI,CAAC,YAAY,EAAE,OAAO;AAC7B,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC5D,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,qBAAqB,EAAE,OAAO,CAAC,EAAE;AACnD,EAAE,CAAC;AACH,CAAC,CAAC;AACF,EAAE;AACF;AACA,EAAE,CAAC,KAAK,CAAC,EAAE;AACX;AACA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE;AACzD;AACA,EAAE,CAAC,MAAM,CAAC,EAAE;AACZ;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG;AACtF,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AAClB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG;AACb,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI;AAC9C,CAAC,EAAE;AACH;AACA,GAAG;AACH,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;AAC1F,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG;AACb,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK;AAC/C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AAClD,CAAC,EAAE;AACH;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,EAAE;AAC5E,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;AACjD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK;AAClD,CAAC,EAAE;AACH;AACA,EAAE,CAAC,OAAO,CAAC,EAAE;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;AAC7B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK;AACxC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;AACnB;AACA,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM;AACpD,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE;AACxD,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC7B,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO;AACzE,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AAC7F,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE;AACxB,GAAG,KAAK,CAAC;AACT,EAAE,CAAC;AACH,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW;AACvD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE;AACnE,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO;AACjB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AACrE,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,8BAA8B,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClF,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;AACzE,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;AAC5C,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AACvB,CAAC,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE;AAC7D,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;AACxB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;AAClC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK;AACpF,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5B,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,OAAO;AAC3C,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACf,EAAE,MAAM,CAAC;AACT,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK;AAC3E,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACxD,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB,GAAG;AACzC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACT,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG;AACnC,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC;AACxD,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC;AACjD,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAChE,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC7B,GAAG,MAAM,CAAC,KAAK,GAAG;AAClB,EAAE,CAAC,CAAC,EAAE;AACN,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC;AAC7C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC;AACtE,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;AAClF,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE;AAC1D,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC9D,CAAC,GAAG,CAAC,IAAI,CAAC;AACV,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,GAAG;AACtC;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE;AAC5B,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACT,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,cAAc,GAAG;AAC3C,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAChC,EAAE,IAAI,CAAC,yBAAyB,GAAG;AACnC,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,cAAc,GAAG;AAC3C,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACf,EAAE,MAAM,CAAC;AACT,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI;AAC/D,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,kBAAkB,GAAG,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9F,EAAE,IAAI,CAAC,KAAK,GAAG;AACf,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK;AACjE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AACT,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACjE,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE,KAAK,GAAG;AAC1D,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;AACvC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI;AACtD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,2BAA2B,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC/E,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACd,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE;AACjC,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC;AACnC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO;AAC3C,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACxD,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;AACtB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;AACzC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ;AACxC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACxD,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;AACtB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;AAC1C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO;AACvC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC9D,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC;AAC7C,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;AAC5B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK;AACrE,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AACzD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACpB;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACvB,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;AAC5D,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7B,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE;AAC1B,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAChC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;AAC/E,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;AACnF,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE;AAC/B,GAAG,UAAU,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC5B,IAAI,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACpF,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,2BAA2B,EAAE,CAAC,EAAE;AAClD,EAAE,CAAC;AACH,CAAC,CAAC;AACF;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC;AAC/C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK;AAClE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI;AACrE,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACnE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC;AACvB,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,GAAG;AACtC,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE;AAChC;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtB,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC5B,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC5B,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK;AAC5C,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACxB,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,QAAQ,GAAG;AAClF,GAAG,EAAE,CAAC,CAAC;AACP,IAAI,IAAI,CAAC,EAAE;AACX,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE;AACpF,GAAG,CAAC,CAAC,CAAC;AACN,IAAI,MAAM,CAAC,IAAI,CAAC;AAChB,GAAG,CAAC;AACJ,GAAG,EAAE,CAAC,CAAC;AACP,IAAI,IAAI,CAAC,EAAE;AACX,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE;AACpF,GAAG,CAAC,CAAC,CAAC;AACN,IAAI,MAAM,CAAC,IAAI,CAAC;AAChB,GAAG,CAAC;AACJ,EAAE,CAAC;AACH,CAAC,CAAC;AACF,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;AAC7B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;AAC1B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE;AACjE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ;AAClG,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACxD,CAAC,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC;AACjC,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;AACnC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE;AACjE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;AAC1E,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAChE,CAAC,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC;AACnC,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC;AACnC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI;AAC7C,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK;AACtD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC3D,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE;AAC3B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC;AACxB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK;AAC9D,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC5D,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,GAAG;AACtC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAChD,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC;AAC7C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI;AAC1D,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAChE,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC;AAC7B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM;AAClC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;AACzF,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;AACxD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG;AACjD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK;AACrD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG;AACb,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AACzD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC;AAC5C,EAAE,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,GAAG;AACjD,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG;AACd,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG;AACb;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK;AAChC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAClD,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;AACpB,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG;AACxB;AACA,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK;AACjC,GAAG,YAAY,CAAC,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AACjE,GAAG,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC3D,IAAI,KAAK,GAAG;AACZ,GAAG,CAAC;AACJ,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AACrC,EAAE,CAAC;AACH,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACvB,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,EAAE;AAC7B,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK;AACjB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAClD,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;AACpB,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG;AACxB,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACtC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACxB,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AAC1D,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,EAAE;AAC/B,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AACtB,EAAE,CAAC;AACH,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACvC,EAAE,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE;AACpD,EAAE,IAAI,CAAC,yBAAyB,GAAG;AACnC,CAAC,CAAC;AACF,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE;AAClC;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;AACtD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC;AAC5F,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM;AAChE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AACzD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;AACxB,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG;AACb;AACA,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAClD,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;AACpB,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG;AACxB,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE;AAC5B,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACxB,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AACnE,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,EAAE;AAC/B,EAAE,CAAC;AACH,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACvC,EAAE,IAAI,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AAChD,EAAE,IAAI,CAAC,yBAAyB,GAAG;AACnC,CAAC,CAAC;AACF,CAAC,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AACvC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE;AAC9B;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;AAC3C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC;AAClF,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AACzD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACxD,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AACZ,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,GAAG;AACtC;AACA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG;AACjB,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7B,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACvB,EAAE,IAAI,CAAC,mBAAmB,CAAC,UAAU,GAAG;AACxC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACnD,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,IAAI,CAAC,EAAE;AACrC,EAAE,CAAC;AACH,CAAC,CAAC;AACF,CAAC,IAAI,CAAC,WAAW,CAAC,UAAU,GAAG;AAC/B;AACA,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE;AAC9B;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC;AACzC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG;AACb,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI;AAC7C,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC3D,CAAC,GAAG,CAAC,YAAY,CAAC;AAClB,EAAE,CAAC,OAAO,CAAC;AACX,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE;AAC5B,EAAE,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE;AAC5E;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AACvC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACxB,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,GAAG;AAC9D,GAAG,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC3D,IAAI,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE;AACtD,GAAG,CAAC;AACJ,EAAE,CAAC;AACH,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACf,GAAG,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACxB,IAAI,YAAY,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,EAAE;AACpC,IAAI,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;AAC9E,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE;AACtF,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI;AACtF,IAAI,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACnF,IAAI,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;AAClB,IAAI,EAAE,CAAC,CAAC;AACR,KAAK,IAAI,CAAC,SAAS,CAAC,EAAE;AACtB,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,EAAE;AACzB,KAAK,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE;AACnC,KAAK,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;AACtD,IAAI,CAAC,CAAC,CAAC;AACP,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE;AACvD,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC7B,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,GAAG;AAC3B,KAAK,CAAC;AACN,IAAI,CAAC;AACL,GAAG,CAAC;AACJ,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/B,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE;AAC1B,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE;AACpC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACxD,IAAI,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI;AACtF,IAAI,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK;AAClF,IAAI,EAAE,CAAC,IAAI,CAAC;AACZ,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE;AACtD,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC5B,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,GAAG;AAC1B,IAAI,CAAC;AACL,GAAG,CAAC;AACJ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE;AAC5B,EAAE,CAAC;AACH,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;AAC1F,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACzD,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM;AACjB,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAC/D;AACA,CAAC,EAAE,CAAC,CAAC;AACL,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE;AAClB,EAAE,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE;AAChC,EAAE,IAAI,CAAC,mBAAmB,CAAC,uBAAuB,EAAE;AACpD,CAAC,CAAC,CAAC,CAAC;AACJ,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AACxB,EAAE,IAAI,CAAC,mBAAmB,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,uBAAuB,EAAE,CAAC,EAAE;AAC5F,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;AACzB,CAAC,CAAC;AACF,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;AACpC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AACzD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACvE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,CAAC;AACtD,EAAE,IAAI,CAAC,mBAAmB,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,uBAAuB,EAAE,CAAC,EAAE;AAC5F,CAAC,CAAC;AACF;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;;ACvmBF,GAAG;AACH,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;AACjF,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM;AAChG,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACjG,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS;AACnG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC;AAClD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AAC9F,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,CAAC,OAAO;AACf,CAAC,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC;AACrE,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,QAAQ,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACnD,CAAC,CAAC,SAAS,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAC/D,CAAC,CAAC,SAAS,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE;AAC5D,CAAC,CAAC,KAAK,CAAC;AACR,CAAC,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,EAAE;AAClE,CAAC,CAAC,KAAK,iBAAiB,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC/D,CAAC,CAAC,SAAS,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE;AACpD,CAAC,CAAC,KAAK,EAAE;AACT,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AACtD,CAAC,CAAC,SAAS,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE;AACrF,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE;AAC9D,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,GAAG;AAC3C,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;AACtD,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE;AACnD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU;AAC5B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO;AACjD,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC;AACzE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO;AAC3E,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AAC/F,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC;AAClC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC,EAAE,CAAC,aAAa,CAAC,cAAc;AAChC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE;AAC1D;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAC/C;AACA,CAAC,EAAE,CAAC,UAAU;AACd,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC;AACjC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS;AACpD,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG;AACzC;AACA,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC;AAC1B,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;AACjE,EAAE,UAAU,CAAC,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;AAClC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ;AACzB,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;AAC1C,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC;AACvE;AACA,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,eAAe;AAC7D,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,GAAG;AAC9E,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;AAC3D,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ;AACzB,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;AACpC;AACA,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE;AACzB;AACA,CAAC,EAAE,CAAC,MAAM;AACV,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAClC,EAAE,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC;AACzB,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACtC,EAAE,MAAM,CAAC,CAAC,CAAC,uBAAuB,CAAC;AACnC,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACxB,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC;AACvD,EAAE,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AAClF,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,cAAc;AAClB,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE;AAC/C,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,EAAE;AACvE,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO;AACvB,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC3C,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,eAAe,EAAE,OAAO,CAAC,EAAE;AAC3C;AACA,CAAC,IAAI,CAAC,6BAA6B,GAAG;AACtC,EAAE;AACF;AACA,EAAE,CAAC,KAAK,CAAC,EAAE;AACX;AACA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE;AACvD;AACA,EAAE,CAAC,MAAM,CAAC,EAAE;AACZ;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG;AAC/F,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;AAChB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG;AACb,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK;AAC3D,CAAC,EAAE;AACH;AACA,GAAG;AACH,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;AACjG,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG;AACb,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM;AAC5D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AACvD,CAAC,EAAE;AACH;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,EAAE;AACrF,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;AACnD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM;AAC9D,CAAC,EAAE;AACH;AACA,EAAE,CAAC,OAAO,CAAC,EAAE;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;AAC7B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK;AACzC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;AACnB;AACA,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM;AACzD,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,EAAE;AAC5D,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACjC,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO;AACxF,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC/D,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;AACzC,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE;AAC5B,GAAG,KAAK,CAAC;AACT,EAAE,CAAC;AACH,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;AAClC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK;AACvF,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,OAAO;AAC3C,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACnB,EAAE,MAAM,CAAC;AACT,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK;AACvD,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;AAC7C,EAAE,IAAI,CAAC,KAAK,GAAG;AACf,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;AAClD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC;AAChF,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;AACvF,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE;AAC1D,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC5D,CAAC,GAAG,CAAC,QAAQ,CAAC;AACd,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,GAAG;AACtC;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE;AAChC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACT,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,cAAc,GAAG;AAC/C,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACnB,EAAE,IAAI,CAAC,6BAA6B,GAAG;AACvC,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,cAAc,GAAG;AAC/C,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACnB,EAAE,MAAM,CAAC;AACT,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI;AAC/D,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC;AACtB,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE;AACzB,EAAE,IAAI,CAAC,kBAAkB,GAAG,aAAa,CAAC;AAC1C,EAAE,IAAI;AACN,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACN,EAAE,QAAQ,CAAC,KAAK,GAAG;AACnB,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK;AAC/D,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AACT,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC/D,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE,KAAK,GAAG;AAC1D,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;AACnC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI;AACtD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACzE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACd,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE;AACrC,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACxD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK;AAC/E,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS;AACzE,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACxE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC;AACvB,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,GAAG;AAC1C,EAAE,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,EAAE;AACxC;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtB,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAChC,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAChC,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK;AACjD,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,QAAQ,GAAG;AACjF,EAAE,EAAE,CAAC,CAAC;AACN,GAAG,IAAI,CAAC,EAAE;AACV,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE;AAC/E,EAAE,CAAC,CAAC,CAAC;AACL,GAAG,MAAM,CAAC,IAAI,CAAC;AACf,EAAE,CAAC;AACH,EAAE,EAAE,CAAC,CAAC;AACN,GAAG,IAAI,CAAC,EAAE;AACV,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE;AAC/E,EAAE,CAAC,CAAC,CAAC;AACL,GAAG,MAAM,CAAC,IAAI,CAAC;AACf,EAAE,CAAC;AACH,CAAC,CAAC;AACF,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;AAC7B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;AACvB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,MAAM;AAC9C,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACnD,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC;AAC7B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC;AACxC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK;AAClD,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK;AAC/D,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC7D,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE;AAC/B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;AAC7B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK;AACvE,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC9D,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,GAAG;AAC1C,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACpD,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;AAClD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK;AAC/D,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAClE,CAAC,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC;AACjC,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;AACtC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM;AAChG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACrE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG;AAC9D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK;AACrD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG;AACb,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AACzD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC1E,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC;AAChD,EAAE,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,GAAG;AACrD,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG;AACd,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG;AACb;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK;AACrC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACtD,EAAE,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE;AAC5B,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,GAAG;AAC5B;AACA,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK;AACjC,GAAG,YAAY,CAAC,CAAC,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AACzE,GAAG,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC3D,IAAI,KAAK,GAAG;AACZ,GAAG,CAAC;AACJ,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AACzC,EAAE,CAAC;AACH,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACvB,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,EAAE;AACjC,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM;AACtB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACtD,EAAE,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE;AAC5B,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,GAAG;AAC5B,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AAClD,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AACrD,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE;AAC9B,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AACrB,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACtB,EAAE,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE;AAChD,EAAE,IAAI,CAAC,6BAA6B,GAAG;AACvC,CAAC,CAAC;AACF,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,EAAE;AAC/C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,EAAE;AACtC;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;AACzD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC;AACnG,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM;AAC7E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AACzD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC;AAC5B,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG;AACb;AACA,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACtD,EAAE,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE;AAC5B,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,GAAG;AAC5B,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE;AAChC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AAC9D,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE;AAC9B,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACtB,EAAE,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AAC5C,EAAE,IAAI,CAAC,6BAA6B,GAAG;AACvC,CAAC,CAAC;AACF,CAAC,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,EAAE;AAC3C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE;AAClC;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;AAC9C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC;AACzF,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AACzD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC1D,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AACZ,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,GAAG;AAC1C;AACA,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG;AACrB,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC;AACjC,CAAC,IAAI,CAAC,eAAe,CAAC,UAAU,GAAG;AACnC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACtD,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE;AACpC,CAAC,CAAC;AACF,CAAC,IAAI,CAAC,WAAW,CAAC,UAAU,GAAG;AAC/B;AACA,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE;AAClC;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC;AAC9C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG;AACb,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK;AAClD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC7D,CAAC,GAAG,CAAC,YAAY,CAAC;AAClB,EAAE,CAAC,OAAO,CAAC;AACX,EAAE,gBAAgB,CAAC;AACnB,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE;AACpC;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;AAC3C,EAAE,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,GAAG;AAC/C,EAAE,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,gBAAgB,GAAG;AACzD,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC1D,GAAG,IAAI,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE;AACjD,EAAE,CAAC;AACH,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACnB,GAAG,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;AAC5B,IAAI,gBAAgB,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,EAAE;AACxC,IAAI,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;AACnF,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,IAAI;AACrF,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC;AACvF,IAAI,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI;AACvF,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;AACxB,IAAI,EAAE,CAAC,CAAC;AACR,KAAK,IAAI,CAAC,SAAS,CAAC,EAAE;AACtB,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,EAAE;AACzB,KAAK,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE;AACnC,KAAK,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;AAC1D,IAAI,CAAC,CAAC,CAAC;AACP,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE;AAC3D,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC7B,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,GAAG;AAC3B,KAAK,CAAC;AACN,IAAI,CAAC;AACL,GAAG,CAAC;AACJ,GAAG,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC;AACnC,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE;AAC9B,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,EAAE;AACxC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;AAC5D,IAAI,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM;AACtF,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK;AACvF,IAAI,EAAE,CAAC,IAAI,CAAC;AACZ,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE;AAC1D,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC5B,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,GAAG;AAC1B,IAAI,CAAC;AACL,GAAG,CAAC;AACJ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE;AAChC,EAAE,CAAC;AACH,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;AACzC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AACzD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACzE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,CAAC;AAClD,EAAE,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,uBAAuB,EAAE,CAAC,EAAE;AACpF,CAAC,CAAC;AACF;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;;ACndF,GAAG;AACH,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AAC1E,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC;AACjF,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,QAAQ;AACZ,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM;AACxB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa;AACpC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO;AACjD,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AAClE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;AACjD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC1D,CAAC,EAAE,CAAC,aAAa,CAAC,cAAc;AAChC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG;AACvB;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAChD;AACA,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW;AACrB,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAChD;AACA,CAAC,EAAE,CAAC,UAAU;AACd,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACnB;AACA,CAAC,EAAE,CAAC,cAAc;AAClB,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE;AAChD,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE;AACjC,EAAE;AACF;AACA,EAAE,CAAC,KAAK,CAAC,EAAE;AACX;AACA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;AACpD,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE;AAC/D;AACA,EAAE,CAAC,MAAM,CAAC,EAAE;AACZ;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AACxE,CAAC,EAAE;AACH;AACA,EAAE,CAAC,OAAO,CAAC,EAAE;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;AACjD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AACnD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACrD,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACnB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE;AACnE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AACjD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AAClD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC5D,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;AACjB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AACrB,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE;AAC/B,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE;AAC9D,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE;AAChE,CAAC,CAAC;AACF,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;;AC3EF,GAAG;AACH,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;AACvF,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;AACtF,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,EAAE;AACzD,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,UAAU,EAAE;AACnD,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,KAAK,EAAE;AAC9F,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG;AAC1D,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC;AACjE,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,CAAC,OAAO;AACf,CAAC,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC;AACrD,CAAC,CAAC,KAAK,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC;AAC1D,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC;AACzC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AACf,CAAC,CAAC,SAAS,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC;AAC1D,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE;AACzC,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,IAAI;AAC1B,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AACf,CAAC,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC;AACxC,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC,aAAa,EAAE,OAAO,CAAC,EAAE;AACnF,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,GAAG,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAC,cAAc;AACvF,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY;AAC9B,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa;AACpC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW;AAClC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB;AACvC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AACnC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc;AACrC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB;AACxC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO;AACjD,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG;AAClE,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;AACxD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC,EAAE,CAAC,aAAa,CAAC,cAAc;AAChC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG;AACvB;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACtD;AACA,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAClD,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM;AACrB,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AACf,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAC9C,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACnD,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAC/C,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACjD,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AACtD,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,MAAM;AAC3B,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AACf;AACA,CAAC,EAAE,CAAC,MAAM;AACV,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACtB,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AACnB,CAAC,CAAC,CAAC,EAAE;AACL;AACA,CAAC,EAAE,CAAC,cAAc;AAClB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE;AACjE,CAAC,IAAI,EAAE,OAAO;AACd,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC;AACzC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE;AAC1B,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE;AACvC,EAAE;AACF;AACA,EAAE,CAAC,KAAK,CAAC,EAAE;AACX;AACA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE;AAChE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE;AACrE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE;AACnE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE;AACxE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE;AACpE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE;AACtE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,EAAE;AACzE;AACA,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE;AACvB;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,MAAM;AACV,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;AACjD;AACA,EAAE,CAAC,OAAO,CAAC,EAAE;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC;AAC5C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC3D,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AAC9B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;AACjB,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,aAAa,CAAC,WAAW;AAC7E,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;AACvB,GAAG,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,EAAE;AACzD,EAAE,CAAC;AACH,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,EAAE;AAC1B,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM;AACjB,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE;AACxE;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC5E,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;AACtB,EAAE,IAAI,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE;AAC5C,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE;AAC5E,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,EAAE;AAC5D,EAAE;;AC9HF,GAAG;AACH,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO;AAC7F,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,WAAW;AAC9F,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC;AACjD,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,CAAC,OAAO;AACf,CAAC,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC;AACzD,CAAC,CAAC,KAAK,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,GAAG;AAC1D,CAAC,CAAC,SAAS,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC;AAC1D,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,IAAI;AAC1B,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AACf,CAAC,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC;AACnE,CAAC,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC;AACjD,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;AACvC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AACf,CAAC,CAAC,KAAK,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC3B,CAAC,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;AAClD,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE;AAC5B,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;AAC3B,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AACf,CAAC,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;AAClD,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;AAC3B,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;AAC3B,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AACd,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;AACX,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE;AACtD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY;AAC9B,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB;AACxC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO;AACjD,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AACzE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;AAC3D,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACtD;AACA,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACpD;AACA,CAAC,EAAE,CAAC,UAAU;AACd,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AACvB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AACvB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;AACtB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE;AAC5B,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE;AAC5B;AACA,CAAC,EAAE,CAAC,MAAM;AACV,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AACpB,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AACnC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC,CAAC,CAAC,EAAE;AACL;AACA,CAAC,EAAE,CAAC,cAAc;AAClB,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,EAAE;AACxD,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,EAAE;AACxD,CAAC,IAAI,EAAE,OAAO;AACd,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC;AACzC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC7B,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE;AACpC,EAAE;AACF;AACA,EAAE,CAAC,KAAK,CAAC,EAAE;AACX;AACA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE;AAChE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,EAAE;AACzE;AACA,EAAE,CAAC,OAAO,CAAC,EAAE;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC;AAC7B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK;AAC5C,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO;AAC3E,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7D,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACnE,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AAC/B,CAAC,CAAC;AACF,CAAC,MAAM,CAAC,KAAK,CAAC;AACd,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;AAC3B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK;AAC1C,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO;AAC3E,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChG,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AAC/B,EAAE,MAAM,CAAC,KAAK,CAAC;AACf,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE;AACxE,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,EAAE;AAC7D,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACrE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5B,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AAC/B,CAAC,CAAC;AACF,CAAC,IAAI,CAAC,KAAK,GAAG;AACd,EAAE;;ACrHF,GAAG;AACH,CAAC,CAAC,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;AACpD,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE;AAC3D,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC;AAClG,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,OAAO,IAAI;AACzF,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM;AACxB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AACnC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO;AAChE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO;AACjD,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ;AAC7C,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK;AAClE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,KAAK;AACxE,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACrF,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM;AAChE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC7D,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;AACnB,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;AAC3B,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,aAAa,CAAC,cAAc;AAChC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG;AACvB;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACzD;AACA,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAC/C;AACA,CAAC,EAAE,CAAC,UAAU;AACd,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;AACxB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE;AAC7B,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;AAC1C,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC;AAChB,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE;AACnB,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;AACpD,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;AAC5C,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC;AAChB,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE;AACjB,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACtD,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;AAC9C,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC;AAChB,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE;AAChB,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;AACnD,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE;AAC/C;AACA,CAAC,EAAE,CAAC,MAAM;AACV,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACzB,EAAE,MAAM,CAAC,CAAC,CAAC,eAAe,EAAE;AAC5B,EAAE,GAAG,CAAC,CAAC,CAAC,eAAe,EAAE;AACzB,EAAE,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC;AAC3B,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/B,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/B,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACjC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9B,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACnC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAC7B,CAAC,CAAC,CAAC,EAAE;AACL;AACA,CAAC,EAAE,CAAC,cAAc;AAClB,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,CAAC,EAAE;AACzD,CAAC,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,EAAE;AAC7D,CAAC,IAAI,EAAE,MAAM;AACb,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC,CAAC;AACnD,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,EAAE;AAC1F,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE;AAC/D,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AAC7C,EAAE;AACF;AACA,EAAE,CAAC,KAAK,CAAC,EAAE;AACX;AACA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;AAC7D,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE;AACvE;AACA,EAAE,CAAC,MAAM,CAAC,EAAE;AACZ;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;AACd,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI;AAClD,CAAC,EAAE;AACH;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,EAAE;AACH;AACA,EAAE,CAAC,OAAO,CAAC,EAAE;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC;AACjB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ;AAC7C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK;AAC/D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,KAAK;AACrE,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC7E,CAAC,GAAG,CAAC,OAAO,CAAC;AACb;AACA,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACpC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC7C,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE;AACtD,EAAE,CAAC;AACH,CAAC,CAAC;AACF;AACA,CAAC,IAAI,CAAC,eAAe,GAAG;AACxB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;AAChC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACrE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,WAAW,CAAC;AACvC,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,GAAG;AAClC,EAAE,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,GAAG;AACjD,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,GAAG;AAC5E,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,YAAY,CAAC,WAAW,GAAG;AAClF;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACjB,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACT,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;AACrB,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACvB,GAAG,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;AAClC,IAAI,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9B,IAAI,KAAK,CAAC;AACV,GAAG,CAAC;AACJ,EAAE,CAAC;AACH,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AACV,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACjB,GAAG,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;AAClC,IAAI,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;AAC7B,IAAI,KAAK,CAAC;AACV,GAAG,CAAC;AACJ,EAAE,CAAC;AACH,CAAC,CAAC;AACF,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE;AACxE,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE;AACzE,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE;AAC7C,EAAE;;ACrJF,GAAG;AACH,CAAC,CAAC,CAAC,mBAAmB,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,mBAAmB,EAAE;AAC9F,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,OAAO;AACnG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,aAAa,CAAC;AACvF,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC;AAClB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB;AACvC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO;AACjD,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,KAAK;AAC1C,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI;AACnD,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,OAAO,CAAC,QAAQ,EAAE;AACzD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,CAAC,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACxE,CAAC,EAAE,CAAC,aAAa,CAAC,cAAc;AAChC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG;AACvB;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACvD;AACA,CAAC,EAAE,CAAC,UAAU;AACd,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAChB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC;AACjC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC;AACrC;AACA,CAAC,EAAE,CAAC,cAAc;AAClB,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,CAAC,EAAE;AACvD,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;AAC/B,EAAE;AACF;AACA,EAAE,CAAC,KAAK,CAAC,EAAE;AACX;AACA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,EAAE;AAC1E;AACA,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE;AACvB;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,MAAM;AACV,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC;AACtD;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,MAAM;AACV,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/D;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,MAAM;AACV,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC;AACrB,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,KAAK,GAAG;AACjF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,MAAM;AACV,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC;AACrB,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C;AACA,EAAE,CAAC,OAAO,CAAC,EAAE;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;AAC5B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,OAAO,CAAC,QAAQ,EAAE;AAC9E,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACpC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC7D,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;AACrB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC;AAC9B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,OAAO,CAAC,QAAQ,EAAE;AAChF,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS;AACtC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC/D,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;AACvB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC;AACzB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,KAAK;AACrC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC5D,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACnB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACrE,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3E,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC;AAClB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,OAAO,CAAC,QAAQ,EAAE;AAC9E,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AAC3C,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AAClD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACvE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC;AAC1B,CAAC,IAAI,CAAC,kBAAkB,GAAG;AAC3B,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC;AACpB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,OAAO,CAAC,QAAQ,EAAE;AAChF,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS;AAC/C,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AAClD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC3E,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC;AAC9B,CAAC,IAAI,CAAC,kBAAkB,GAAG;AAC3B,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE;AAC5E,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC;AACzB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC;AAC7E,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AAClD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC;AAC7C,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC;AAClD,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AACb;AACA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAChB,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3B,GAAG,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC5C,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACV,GAAG,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC/C,EAAE,CAAC;AACH,CAAC,CAAC;AACF,CAAC,IAAI,CAAC,kBAAkB,GAAG;AAC3B;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;;ACvKF,GAAG;AACH,CAAC,CAAC,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ;AACzD,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,OAAO,CAAC,OAAO,CAAC;AACpD,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,OAAO,CAAC,QAAQ,CAAC;AACjG,CAAC,CAAC,CAAC,MAAM,CAAC;AACV,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,OAAO,IAAI;AACzF,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY;AAC9B,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB;AACxC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO;AACjD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,CAAC,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACxE,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACvD;AACA,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACpD;AACA,CAAC,EAAE,CAAC,MAAM;AACV,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AACpB,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AACvD,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,6BAA6B,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACvD,CAAC,CAAC,CAAC,EAAE;AACL;AACA,CAAC,EAAE,CAAC,cAAc;AAClB,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,CAAC,EAAE;AACvD,EAAE;AACF;AACA,EAAE,CAAC,KAAK,CAAC,EAAE;AACX;AACA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE;AACjE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,EAAE;;ACnC1E,GAAG;AACH,CAAC,CAAC,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI;AAChG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AACzD,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG;AAC7F,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC;AAC9D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,GAAG,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,0BAA0B;AAClG,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY;AAC9B,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa;AACpC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW;AAClC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB;AACvC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO;AACjD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC,EAAE,CAAC,aAAa,CAAC,cAAc;AAChC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG;AACvB;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACtD;AACA,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAChD,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAC9C,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACnD;AACA,CAAC,EAAE,CAAC,cAAc;AAClB,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE;AACtD,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE;AACjE,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE;AACtC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE;AACvC,EAAE;AACF;AACA,EAAE,CAAC,KAAK,CAAC,EAAE;AACX;AACA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE;AAChE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE;AACrE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE;AACnE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE;AACxE;AACA,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE;AACvB;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM;AACpG,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM;AACV,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,MAAM,CAAC,2BAA2B,CAAC,CAAC,CAAC,KAAK,CAAC;AACpE;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,MAAM;AACV,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC;AACtD;AACA,EAAE,CAAC,OAAO,CAAC,EAAE;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACrE,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3E;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC5C,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,EAAE;AAC1B,CAAC,CAAC;AACF;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;;ACxEF,GAAG;AACH,CAAC,CAAC,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ;AACjF,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI;AAC3C,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG;AAC7E,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG;AAC/E,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC;AAClE,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,CAAC,OAAO;AACf,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,mBAAmB,CAAC;AACvE,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC;AACpD,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,CAAC,CAAC;AACvB,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE;AACjC,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;AACvC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AACf,CAAC,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC;AACpD,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,CAAC,CAAC;AACvB,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE;AACjC,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;AACvC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AACf,CAAC,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC;AACpD,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,CAAC,CAAC;AACvB,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE;AACjC,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;AACvC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AACf,CAAC,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC;AACzD,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC;AACnD,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AACf,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,YAAY,EAAE,OAAO,CAAC,EAAE;AAC1D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,GAAG,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,mBAAmB;AACvE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY;AAC9B,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB;AACxC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO;AACjD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACtD;AACA,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACpD;AACA,CAAC,EAAE,CAAC,MAAM;AACV,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AACpB,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AACvD,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,6BAA6B,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACvD,CAAC,CAAC,CAAC,EAAE;AACL;AACA,CAAC,EAAE,CAAC,cAAc;AAClB,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE;AACtD,EAAE;AACF;AACA,EAAE,CAAC,KAAK,CAAC,EAAE;AACX;AACA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE;AAChE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,EAAE;;AC1DzE,GAAG;AACH,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,eAAe,EAAE;AACjF,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,OAAO;AAC/F,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC;AAC5F,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC;AAClB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY;AAC9B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO;AACjD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC,EAAE,CAAC,aAAa,CAAC,cAAc;AAChC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG;AACvB;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACnD;AACA,CAAC,EAAE,CAAC,cAAc;AAClB,CAAC,IAAI,EAAE,OAAO;AACd,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC;AACtC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AACzB,EAAE;AACF;AACA,EAAE,CAAC,KAAK,CAAC,EAAE;AACX;AACA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE;AAC7D;AACA,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE;AACvB;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,MAAM;AACV,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC;;ACpCnD,GAAG;AACH,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC;AACpF,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,IAAI;AACrF,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY;AAC9B,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB;AACxC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO;AACjD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACnD;AACA,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACpD;AACA,CAAC,EAAE,CAAC,MAAM;AACV,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AACpB,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AACvD,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,6BAA6B,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACvD,CAAC,CAAC,CAAC,EAAE;AACL;AACA,CAAC,EAAE,CAAC,cAAc;AAClB,CAAC,IAAI,EAAE,OAAO;AACd,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC;AACtC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE;AAC7B,EAAE;AACF;AACA,EAAE,CAAC,KAAK,CAAC,EAAE;AACX;AACA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE;AAC7D,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,EAAE;;AClCtE,GAAG;AACH,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB;AACrE,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC;AACvD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM;AACxB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU;AACjC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AACnC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc;AACrC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB;AACxC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB;AACvC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,MAAM;AAChD,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK;AAC5C,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;AAC/D,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC;AACxD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC5D,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG;AACvB;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACjD;AACA,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AACrC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAC/C,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACjD,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACpD,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACnD;AACA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC;AACjE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC;AAC7B;AACA,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;AAC7C,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC;AAChB,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE;AAChB,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AACf,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AACxC,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE;AACnD;AACA,CAAC,EAAE,CAAC,MAAM;AACV,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAClC,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;AACjB,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,EAAE,OAAO;AACd,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC1C,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC/C,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG;AAClE,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;AACjE,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI;AACjE,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK;AACpE,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;AACnE,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE;AAC7E,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC;AACnC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,GAAG,CAAC,CAAC,CAAC,EAAE;AAC9D;AACA,CAAC,EAAE,CAAC,cAAc;AAClB,CAAC,IAAI,EAAE,OAAO;AACd,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC;AACpC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE;AACpD,EAAE;AACF;AACA,EAAE,CAAC,cAAc,CAAC,EAAE;AACpB;AACA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;AACrD,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE;AAC7D,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE;AAC/D,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE;AACjE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,EAAE;AACpE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE;AACnE;AACA,EAAE,CAAC,MAAM,CAAC,EAAE;AACZ;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI;AAC5C,CAAC,EAAE;AACH;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ;AAClB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS;AAC5E,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI;AAC9C,CAAC,EAAE;AACH;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM;AAC9D,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;AAChD,CAAC,EAAE;AACH;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK;AACzC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO;AAC5B,CAAC,EAAE;AACH;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK;AACzC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO;AAC/B,CAAC,EAAE;AACH;AACA,EAAE,CAAC,OAAO,CAAC,EAAE;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO;AACvD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK;AACxC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK;AACf,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ;AAClD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC7D,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;AACrD;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AACrB,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC3B,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AAC1C,EAAE,CAAC;AACH;AACA,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/E,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG;AAC9C,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS;AAC/B,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AACvC,EAAE,CAAC;AACH,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AACvE;AACA,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE;AACvC,CAAC,CAAC;AACF,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK;AAClC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AACpB,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACrD,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACnB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;AACvE,EAAE,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE;AAC/K,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM;AACjB,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE;AACtE,CAAC,EAAE,CAAC,CAAC;AACL,EAAE,CAAC,KAAK,CAAC,EAAE;AACX,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AACzD,EAAE,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE;AAC9C,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE;AACpB,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE;AAClC,CAAC,CAAC,CAAC,CAAC;AACJ,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG;AACvD,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG;AACxD,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK;AACtB,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE;AACjC,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC1B,EAAE,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AACxC,CAAC,CAAC;AACF;AACA,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI;AAC7B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ;AAC/D,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI;AAC9D,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI;AAC1D,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC;AACtD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACpD,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/C,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE;AACxB,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AACvC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ;AAClB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK;AACzC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS;AAC1D,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1D,CAAC,GAAG,CAAC,QAAQ,CAAC;AACd;AACA,CAAC,EAAE,CAAC,CAAC;AACL,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE;AACvB,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE;AACpB,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC3E,CAAC,CAAC,CAAC,CAAC;AACJ,EAAE,IAAI,CAAC,MAAM,GAAG;AAChB,EAAE,MAAM,CAAC,KAAK,CAAC;AACf,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC/C,EAAE,IAAI,CAAC,MAAM,GAAG;AAChB,EAAE,MAAM,CAAC,KAAK,CAAC;AACf,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACZ,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;AAClC,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK;AAChC,CAAC,CAAC,CAAC,CAAC;AACJ,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACjE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;AACf,IAAI,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE;AACrB,IAAI,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACtB,GAAG,EAAE;AACL,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACV,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;AACf,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE;AACtB,IAAI,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AACrB,GAAG,EAAE;AACL,EAAE,CAAC;AACH;AACA,EAAE,IAAI,CAAC,IAAI,CAAC;AACZ,GAAG,CAAC,QAAQ,EAAE;AACd,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAClC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK;AAClC,EAAE,EAAE;AACJ,EAAE,MAAM,CAAC,KAAK,CAAC;AACf,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI;AACnB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACpD,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5B,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE;AACxB,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI;AACnC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK;AACzC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK;AACf,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;AACrD;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AACrB;AACA,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AAC5C;AACA,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AACnC,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK;AAClC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK;AAClC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACrD,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACnB,EAAE;;AClRF,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE;AACxD,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM;AACjG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;AACpC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,wBAAwB,CAAC;AACpG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,yBAAyB,CAAC,yBAAyB,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,eAAe;AAChG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC;AAC5C,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,CAAC,OAAO;AACf,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,oBAAoB,CAAC;AACjC,CAAC,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAC;AACrD,CAAC,CAAC,SAAS,aAAa,CAAC,CAAC,CAAC,OAAO,EAAE;AACpC,CAAC,CAAC,SAAS,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;AACjE,CAAC,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACnC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;AACX,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE;AACpD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM;AACxB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW;AAClC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB;AAC5C,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB;AACvC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW;AAClC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB;AACxC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc;AACrC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa;AACpC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM;AAC9C,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM;AACnE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI;AACrF,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AAC5E,CAAC,CAAC,EAAE,oBAAoB,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;AACzC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,EAAE,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;AAC9E,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE;AACxE,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;AACrD,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;AACpD,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ;AAC7B,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI;AACjF,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;AAC7E,CAAC,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;AAC5B,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK;AAC1E,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC;AACnB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK;AAC3E,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE;AACtE,CAAC,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG;AACpE,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI;AACxE,CAAC,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;AAChB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC;AAChF,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG;AAChF,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;AAClF,CAAC,CAAC,EAAE,KAAK,CAAC;AACV,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK;AACtE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC;AACxE,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI;AACxE,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC;AAC5B,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAC,QAAQ,CAAC,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC1E,CAAC,GAAG,CAAC,WAAW,CAAC;AACjB,EAAE,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,qBAAqB,CAAC,EAAE,CAAC,UAAU,CAAC;AACnD,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAChB,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAAC,EAAE;AAC/E;AACA,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG;AACvB;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACxD;AACA,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAC9C,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACnD,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAC9C,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACpD,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACjD,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACxD,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAChD;AACA,CAAC,IAAI,CAAC,eAAe,CAAC;AACtB,EAAE,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AACxC,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,eAAe;AAClC,CAAC,EAAE;AACH;AACA,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;AACrB,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtF,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE;AACnC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,aAAa,CAAC;AACzF,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;AAC/C,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,eAAe,CAAC;AACjD,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,GAAG;AACjD,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC,MAAM,CAAC,uBAAuB,CAAC;AAC/D,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE;AAC/C,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;AACjC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACpB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACnB;AACA,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC,EAAE;AAC/E,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;AAC5B,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC;AAClD,EAAE,CAAC,MAAM,CAAC;AACV,GAAG,IAAI,EAAE,SAAS,CAAC;AACnB,GAAG,IAAI,EAAE,IAAI,CAAC;AACd,GAAG,IAAI,EAAE,OAAO;AAChB,IAAI,CAAC,MAAM,CAAC;AACZ,KAAK,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/D,IAAI,CAAC;AACL,EAAE,EAAE;AACJ;AACA,CAAC,EAAE,CAAC,MAAM;AACV,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;AAClB,EAAE,MAAM,CAAC,CAAC,CAAC,UAAU,EAAE;AACvB,EAAE,QAAQ,CAAC,CAAC,CAAC,YAAY,EAAE;AAC3B,EAAE,MAAM,CAAC,CAAC,CAAC,UAAU,EAAE;AACvB,EAAE,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACpB,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACtB,EAAE,UAAU,CAAC,CAAC,CAAC,WAAW,EAAE;AAC5B,EAAE,UAAU,CAAC,CAAC,CAAC,WAAW,EAAE;AAC5B,EAAE,SAAS,CAAC,CAAC,CAAC,UAAU,EAAE;AAC1B,EAAE,YAAY,CAAC,CAAC,CAAC,aAAa,EAAE;AAChC,EAAE,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC;AACxB,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;AACnB,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AAC1C,CAAC,CAAC,CAAC,EAAE;AACL;AACA,CAAC,EAAE,CAAC,UAAU;AACd,CAAC,IAAI,EAAE,OAAO;AACd,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAC;AAC3C,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE;AAC1B;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACvB,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC7B,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC;AACnC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACV,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AACtD,IAAI,WAAW,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC;AACpC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC;AACnD,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AACvB,EAAE,CAAC;AACH,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE;AAC9C;AACA,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;AACjB,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AACzC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AACvC,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE;AACpF,IAAI,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AACxD,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAC7C,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AAC9C,EAAE,EAAE;AACJ;AACA,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE;AACtC,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE;AAClE;AACA,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3C,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM;AAC9C,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG;AACjD,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI;AAC/C,GAAG,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE;AACrD,GAAG,IAAI,EAAE,OAAO;AAChB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC,CAAC;AACtD,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE;AACnC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACV,GAAG,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC,EAAE;AAClE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG;AACxD,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM;AAClD,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,SAAS;AACpD,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU;AACpD,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC;AAChD,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;AACpD,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI;AAChD,GAAG,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,GAAG;AACpD,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG;AAChD,GAAG,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE;AAC7C,EAAE,CAAC;AACH,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACT,EAAE,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE;AACpC,CAAC,CAAC;AACF;AACA,CAAC,IAAI,CAAC,oBAAoB,CAAC;AAC3B,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;AACjB,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AACtB,GAAG,CAAC,QAAQ;AACZ,CAAC,EAAE;AACH;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACzB,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE;AACnC,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,UAAU;AAC5D,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ;AACpB,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACnB,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC1B,GAAG,MAAM,CAAC,eAAe,GAAG;AAC5B,EAAE,CAAC;AACH,CAAC,CAAC,CAAC,EAAE;AACL,EAAE;AACF;AACA,EAAE,CAAC,cAAc,CAAC,EAAE;AACpB;AACA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;AAC5D,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE;AACrE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,EAAE;AAC/E,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE;AAC1E,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE;AACrE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,EAAE;AAC3E,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE;AACxE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE;AACvE;AACA,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE;AACvB;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC;AAC3B,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI;AAC7C,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI;AAC7C,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK;AAC5B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC;AACpB,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AAC1F;AACA,EAAE,CAAC,OAAO,CAAC,EAAE;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;AAC5B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK;AAC3C,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ;AAC9C,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnE,CAAC,EAAE,CAAC,CAAC;AACL,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE;AACvB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9D,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI;AACrC,CAAC,CAAC,CAAC,CAAC;AACJ,EAAE,IAAI,CAAC,KAAK,GAAG;AACf,EAAE,MAAM,CAAC,KAAK,CAAC;AACf,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;AAC3B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK;AAC1C,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ;AAChD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvE,CAAC,GAAG,CAAC,cAAc,CAAC;AACpB,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;AACvC;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5B,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACvC,GAAG,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE;AACxD,EAAE,CAAC;AACH;AACA,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC;AACtC,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;AACrD,EAAE,MAAM,CAAC,cAAc,CAAC;AACxB,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;AAC1B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK;AACzC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AACpB,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC;AACzB,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAChB,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;AACvC,EAAE,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAClD,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,GAAG;AAC5C,IAAI,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,GAAG;AAC5D;AACA,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7E,IAAI,MAAM,CAAC,KAAK,CAAC;AACjB,GAAG,CAAC;AACJ;AACA,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7D,IAAI,MAAM,CAAC,KAAK,CAAC;AACjB,GAAG,CAAC;AACJ;AACA,GAAG,MAAM,CAAC,IAAI,CAAC;AACf,EAAE,EAAE;AACJ;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5B,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG;AACxD,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC7C,GAAG,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE;AAClD,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACjD,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE;AAClC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACb,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;AACnC,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK;AACjC,EAAE,CAAC,CAAC,CAAC;AACL,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAClE,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC;AAChB,KAAK,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE;AACtB,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACvB,IAAI,EAAE;AACN,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;AACX,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC;AAChB,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE;AACvB,KAAK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AACtB,IAAI,EAAE;AACN,GAAG,CAAC;AACJ,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC9C,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;AACnC;AACA,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,qBAAqB,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjE,IAAI,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,EAAE;AAC1D,GAAG,CAAC;AACJ,EAAE,CAAC;AACH,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK;AAC/B,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACjE,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,EAAE;AAC9D,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ;AAClB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE;AAC1B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK;AAC9B,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAChE,CAAC,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,EAAE;AACjE;AACA,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK;AAC1D,CAAC,IAAI,CAAC,eAAe,GAAG;AACxB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE;AAC1F,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;AACrC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI;AACnE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO;AAC1B,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ;AAChD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACjE,CAAC,IAAI,CAAC,eAAe,GAAG;AACxB,CAAC,MAAM,CAAC,KAAK,CAAC;AACd,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;AACrC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI;AACnE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO;AAC1B,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ;AAChD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACrF,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;AACjB;AACA,CAAC,EAAE,CAAC,CAAC;AACL,EAAE,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE;AACpC,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;AACjC,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE;AACjB,CAAC,CAAC,CAAC,CAAC;AACJ,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI;AACzB,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG;AAC1B,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACnC;AACA,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;AAChD,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AAChC,GAAG,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;AACpD,GAAG,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC;AACvD,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACxB,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE;AAC3C,GAAG,CAAC;AACJ,EAAE,CAAC;AACH;AACA,EAAE,MAAM,CAAC,KAAK,CAAC;AACf,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK;AACtD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;AACrC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAClE,CAAC,IAAI,CAAC,UAAU,GAAG;AACnB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ;AACrF,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;AACvB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,eAAe;AACvB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;AACrC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS;AAC7E,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI;AACnE,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO;AAC3B,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC/E,CAAC,EAAE,CAAC,CAAC;AACL,EAAE,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE;AACpC,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE;AACpB,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC;AAC3B,CAAC,CAAC,CAAC,CAAC;AACJ,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI;AACtB,EAAE,IAAI,CAAC,eAAe,GAAG,KAAK,GAAG;AACjC,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK;AAC/B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI;AAClD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;AAChE,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;AAChC,GAAG,IAAI,CAAC,eAAe,GAAG;AAC1B,EAAE,CAAC;AACH,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK;AAC/C,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE;AACxC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG;AACtB,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AAC/B,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK;AACvB,EAAE,IAAI,CAAC,KAAK,GAAG;AACf,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM;AACrC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI;AAClD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACrE,CAAC,GAAG,CAAC,CAAC,CAAC;AACP,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG;AAC1B;AACA,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK;AAC5C,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACvC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;AACvD,GAAG,KAAK,CAAC;AACT,EAAE,CAAC;AACH,CAAC,CAAC;AACF,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;AAC1B,EAAE;AACF,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC;AACxE,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACjE,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,GAAG;AACxC;AACA,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ;AAClB,CAAC,IAAI,CAAC,WAAW,CAAC;AAClB,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,EAAE;AACzB,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC7C,CAAC,EAAE;AACH;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACvB,EAAE,IAAI,CAAC,eAAe,GAAG;AACzB,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACxB,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK;AACrB,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE;AAC7B,EAAE,CAAC;AACH,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3C,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK;AAC7D,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK;AAC9D,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;AACtF,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE;AAC3C,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACV,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK;AACzB,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,YAAY,CAAC,EAAE;AAC1E,EAAE,CAAC;AACH,CAAC,CAAC;AACF,CAAC,IAAI,CAAC,qBAAqB,GAAG;AAC9B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC5E,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM;AACjB,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,EAAE;AAClF;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACrC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACtB,GAAG,IAAI,CAAC,eAAe,GAAG;AAC1B,EAAE,CAAC;AACH,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,EAAE;AACjE,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpB,EAAE,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC9C,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE;AACpC,EAAE,CAAC,CAAC,EAAE;AACN,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK;AAC9B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG;AAChD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE;AACxC,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG;AACvC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG;AAChD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;AAC7E,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACnF,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE;AACtC;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAClC,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG;AACnC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACvE,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI;AAC5E,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI;AAChB,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG;AACvC,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK;AAC3B,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACpE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG;AACjC,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,EAAE;AACtC;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACd,EAAE,MAAM,CAAC;AACT,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC;AACjD,EAAE,IAAI,CAAC,UAAU,GAAG;AACpB,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE;AACrB,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK;AAClB,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC/D,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE;AAC3B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ;AAC9D,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;AAC3B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK;AAC9C,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS;AACvC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC1E,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE;AACxC,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK;AACrD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK;AAC9C,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO;AACrC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACxE,CAAC,EAAE,CAAC,CAAC;AACL,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE;AAC1B,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC,CAAC,CAAC,CAAC;AACJ,EAAE,MAAM,CAAC,KAAK,CAAC;AACf,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AAC7B,EAAE,MAAM,CAAC,IAAI,CAAC;AACd,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM;AAC7B,CAAC,EAAE,CAAC,CAAC;AACL,EAAE,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpD,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;AACzB,EAAE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC,CAAC;AACJ,EAAE,MAAM,CAAC,IAAI,CAAC;AACd,CAAC,CAAC;AACF;AACA,CAAC,MAAM,CAAC,KAAK,CAAC;AACd,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI;AAC9B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM;AACzC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACrE,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC;AAC3B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI;AACzC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK;AAC3C,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC3E,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpD,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE;AACnC,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK;AAChD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK;AAChE,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC7D,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE;AACvB,EAAE,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC9B,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,GAAG;AACzB,EAAE,CAAC,CAAC,CAAC;AACL,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC3B,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,GAAG;AACzB,EAAE,CAAC,CAAC,EAAE;AACN,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC;AACzC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI;AACvF,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;AAClE,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI;AACjE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC;AACrC,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC;AAC1D,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AACtC,CAAC,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;AAC7D,CAAC,CAAC,EAAE,CAAC;AACL,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE;AAC1C,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AACzC,CAAC,CAAC,EAAE,CAAC;AACL,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;AAC9D,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC;AAC1D,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC1E,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE;AAC5E;AACA,CAAC,IAAI,CAAC,UAAU,GAAG;AACnB,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACxC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAClC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE;AACtB,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACV,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AACtC,EAAE,CAAC;AACH,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AAClB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI;AAC9B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI;AACvC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,GAAG;AAClE,CAAC,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC;AACzD,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY;AAChD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxE,CAAC,GAAG,CAAC,aAAa,CAAC;AACnB,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,EAAE;AACvC;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5E,EAAE,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE;AAC1D,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,EAAE;AACvC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE;AACrC,EAAE,MAAM,CAAC,IAAI,CAAC;AACd,CAAC,CAAC;AACF;AACA,CAAC,MAAM,CAAC,KAAK,CAAC;AACd,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAChE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AACrE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG;AAC5B,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACjE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;AACzB,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;AACtC,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;AACnC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI;AACvC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC1E,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE;AAC1C;AACA,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AAC9B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;AACrF,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;AACjC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;AACxC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC;AAChC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACrF,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC;AACvB;AACA,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AAChE,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG;AACvE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG;AACpE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;AACnB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI;AAC/C,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC;AACpD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE;AAC5C;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;AACzB,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI;AAC1D,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACxB,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACrB,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACV,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI;AACvB,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;AAC1B,EAAE,CAAC;AACH,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACT,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACrC,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG;AACrE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AAClB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI;AAC/C,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC;AACxD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC1E,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE;AAC5C;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC7C,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzB,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACxB,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACrB,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACV,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI;AAC1B,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9C,EAAE,CAAC;AACH,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACT,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACrC,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC;AACjF,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI;AAC1E,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;AAClF,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;AAC5E,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACpE,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC,YAAY,CAAC,CAAC,SAAS,CAAC;AACjE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/D,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;AACnD,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;AAChE,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/B,GAAG,MAAM,CAAC;AACV,EAAE,CAAC;AACH,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AAC1C,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,GAAG;AAC5C,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE;AAC1D;AACA,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE;AAC5D,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa;AAC9D,EAAE,EAAE,CAAC,CAAC;AACN,GAAG,IAAI,CAAC,2BAA2B,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE;AACpD,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;AAClC,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS;AACxD,EAAE,CAAC,CAAC,CAAC;AACL,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE;AAClE,GAAG,IAAI,CAAC,2BAA2B,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC;AACzE,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE;AAC7B;AACA,EAAE,CAAC;AACH;AACA,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI;AAC/D,EAAE,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;AAC1B,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC;AACtC,GAAG,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG;AACjD,GAAG,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACvD,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,2BAA2B;AACxC,EAAE,EAAE;AACJ,EAAE,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG;AAC3C;AACA,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACtC,GAAG,IAAI,CAAC,qBAAqB,GAAG;AAChC,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,YAAY;AACvD,GAAG,MAAM,CAAC;AACV,EAAE,CAAC;AACH;AACA,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjC,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,GAAG;AAC1C,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACV,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACpC,IAAI,IAAI,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;AACrF,IAAI,CAAC,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC;AAC9B,EAAE,CAAC;AACH;AACA,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG;AAC5F,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;AAC/C,EAAE,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC;AAClB,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACnC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI;AACpE,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/C,EAAE,CAAC;AACH,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;AACrD,EAAE,IAAI,CAAC,qBAAqB,GAAG;AAC/B,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACT,EAAE,IAAI,CAAC,qBAAqB,GAAG;AAC/B,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;AACjD,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM;AAClE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,KAAK;AACjE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI;AACjE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AACT,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC1E,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,GAAG;AACrC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAChC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;AACvB,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE;AACxB,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK;AAClD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AACpC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAClE,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClD,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,GAAG;AACxB,CAAC,CAAC,CAAC,EAAE;AACL,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI;AACnC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK;AACzC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK;AACf,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACvE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;AACrD;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9B,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AACrB;AACA,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AAC5C;AACA,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AACnC,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AAC5C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;AACpC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC5D,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACnB,EAAE;;ACl4BF,GAAG;AACH,CAAC,CAAC,CAAC,yBAAyB,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC;AAC/F,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM;AAChG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;AACnB,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,CAAC,OAAO;AACf,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,yBAAyB,CAAC;AACtC,CAAC,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,yBAAyB,GAAG;AAC1D,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE;AACpD,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,yBAAyB,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC;AACtE,CAAC,CAAC,KAAK,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,GAAG;AACpD,CAAC,CAAC,SAAS,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,yBAAyB,CAAC,CAAC,CAAC;AAC1D,CAAC,CAAC,YAAY,UAAU,CAAC,CAAC,UAAU,CAAC;AACrC,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC;AACtB,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,OAAO;AAC9C,CAAC,CAAC,YAAY,CAAC;AACf,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE;AACf,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE;AACpD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB;AACtC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AACnC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM;AAC9C,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC;AACrD,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE;AAChE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK;AAC5D,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;AACtF,CAAC,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG;AAC5E,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AAChC,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,yBAAyB,CAAC,CAAC,CAAC,QAAQ,CAAC,6BAA6B,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACpF,CAAC,GAAG,CAAC,YAAY,CAAC;AAClB,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE;AAChC;AACA,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG;AACvB;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,yBAAyB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAC/D,EAAE,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC;AACvB,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AACf;AACA,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC7C,EAAE,EAAE,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC;AACjE;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACvB,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK;AACzD,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK;AAC5D,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG;AACvD,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ;AACtD,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,GAAG;AAC7C;AACA,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC;AAC1C,EAAE,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,EAAE,OAAO,CAAC;AACvD,EAAE,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACpC;AACA,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,yBAAyB,CAAC,YAAY,CAAC,CAAC,EAAE;AAC3E,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,eAAe;AACpD,CAAC,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC;AAC9C,CAAC,aAAa,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACvD,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC;AAC3D;AACA,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK;AACpC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,EAAE;AAC5C;AACA,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAC/C;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACvB,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AAC9E,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO;AACzB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;AACrC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACzB,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAClC,GAAG,KAAK,CAAC,CAAC,CAAC,iBAAiB,CAAC;AAC7B,EAAE,CAAC,CAAC,EAAE;AACN,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,MAAM;AACV,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AACrE,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5B,EAAE,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC;AACzB,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AAC3D;AACA,CAAC,EAAE,CAAC,UAAU;AACd,CAAC,IAAI,EAAE,OAAO;AACd,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AAChC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,yBAAyB,CAAC,CAAC,EAAE;AACjD;AACA,CAAC,EAAE,CAAC,WAAW,CAAC,OAAO;AACvB,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,wBAAwB,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE;AAC7H,EAAE;AACF;AACA,EAAE,CAAC,cAAc,CAAC,EAAE;AACpB;AACA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,yBAAyB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,EAAE;AAC/E,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,yBAAyB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE;AAC3E;AACA,EAAE,CAAC,OAAO,CAAC,EAAE;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC;AACvB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,yBAAyB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACjE,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE;AAC3B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK;AAChC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO;AAC9C,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,yBAAyB,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAClF,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACtC,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK,GAAG;AAC1B,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK;AACrC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,yBAAyB,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC3E,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACzB,EAAE,IAAI,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC,EAAE;AACxD,EAAE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE;AACjC,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,yBAAyB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC3E,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AAC/C,EAAE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE;AAC7C,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AAC/B;AACA,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE;AAC5B,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK,GAAG;AAC1B,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACT,EAAE,EAAE,CAAC,MAAM;AACX,EAAE,EAAE,CAAC,EAAE,CAAC,yBAAyB,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAClF,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;AAChC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI;AACzE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACvE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;AACtB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI;AACzC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;AAChF,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,yBAAyB,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACzF,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE;AAC5B,EAAE;;ACpKF,GAAG;AACH,CAAC,CAAC,CAAC,wBAAwB,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC;AAC9F,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;AAChD,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,CAAC,OAAO;AACf,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,wBAAwB,CAAC;AAC3C,CAAC,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,CAAC,CAAC;AACzD,CAAC,CAAC,SAAS,aAAa,CAAC,CAAC,CAAC,OAAO,EAAE;AACpC,CAAC,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC;AACrB,CAAC,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AAClE,CAAC,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;AACrD,CAAC,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;AACrD,CAAC,CAAC,SAAS,EAAE;AACb,CAAC,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC7C,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;AACX,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE;AACpD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB;AACtC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,MAAM;AAChD,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM;AACnG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM;AAChE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;AACpD,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE;AAChE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;AAC3F,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,CAAC,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAClF,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG;AACvB;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAC5D;AACA,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC7C,EAAE,EAAE,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC;AACjE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE;AACrE,EAAE,EAAE,MAAM,CAAC,kBAAkB,CAAC;AAC9B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAC/C,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC;AACf,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3C,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACnD,EAAE,eAAe,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC;AACnC,EAAE,iBAAiB,CAAC,CAAC,IAAI,CAAC;AAC1B,EAAE,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACnC,GAAG,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AACjC,EAAE,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC1E,GAAG,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC;AACvC,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC;AAC1B,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE;AAC7B,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AACpB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AACzC;AACA,CAAC,EAAE,CAAC,MAAM;AACV,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3B,EAAE,MAAM,CAAC,CAAC,CAAC,YAAY,EAAE;AACzB,EAAE,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC;AACxB,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACvB,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC7B,GAAG,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC;AAC1B,EAAE,CAAC,CAAC,EAAE;AACN,CAAC,CAAC;AACF,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACtB,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;AACpB,CAAC,CAAC,CAAC,EAAE;AACL;AACA,CAAC,EAAE,CAAC,cAAc;AAClB,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE;AAC5C,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,CAAC,EAAE;AAC5D,CAAC,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS;AAChE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;AAClF,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE;AACrD,CAAC,EAAE,CAAC,oBAAoB,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;AAC1F,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC,UAAU,CAAC;AAC/F,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACzB,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE;AACnC,CAAC,CAAC;AACF,EAAE;AACF;AACA,EAAE,CAAC,cAAc,CAAC,EAAE;AACpB;AACA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,EAAE;AAC9E;AACA,EAAE,CAAC,OAAO,CAAC,EAAE;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK;AAC1B,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACjE,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI;AACvB,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG;AACtB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACrE,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM;AACjB,CAAC,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAC3E;AACA,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE;AAC1B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACpE,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM;AACjB,CAAC,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAC1E;AACA,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK;AAChC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACtE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE;AAC1B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK;AAC/B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI;AACxD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC/E,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;AAClD,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE;AAC5B,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG;AACX,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,EAAE;AACxD,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC;AAC/D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;AACjD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAChF,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACpB,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE;AAC/B,EAAE,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,EAAE;AAClC,CAAC,CAAC;AACF,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC1B,EAAE,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS;AACjE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;AACnF,EAAE,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE;AACtD,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AAClB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC7E,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,EAAE;AAChE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AAC9B,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ;AAC5E,EAAE,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AAC1E,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,GAAG;AACzE,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;AACpC;AACA,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM;AACxF,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AACrD,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE;AAC7B,EAAE,CAAC;AACH;AACA,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI;AACzB,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,EAAE;AACnC;AACA,EAAE,IAAI,CAAC,KAAK,GAAG;AACf,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACT,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;AACpB,EAAE,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE;AACpF,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAChF,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM;AACjB,CAAC,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,EAAE;AACtF;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACnB,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW;AAC1E,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,UAAU,CAAC,EAAE;AACtC,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC;AAClE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAChF,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,CAAC;AACvC,EAAE,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC;AAC1B,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC;AACxB,IAAI,IAAI,CAAC,CAAC;AACV,IAAI,IAAI,CAAC,IAAI,CAAC,uBAAuB,EAAE;AACvC,EAAE,EAAE;AACJ,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACxE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG;AACjC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK;AACtC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI;AACjD,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,GAAG,CAAC,EAAE;AAC9E,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;AACrC,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,EAAE;AACvC;AACA,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI;AACtD,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK;AACvC;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACd,EAAE,MAAM,CAAC;AACT,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC;AACjD,EAAE,IAAI,CAAC,UAAU,GAAG;AACpB,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACf,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE;AACxC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACV,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE;AACtB,EAAE,CAAC;AACH,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI;AACrE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC;AACjC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,GAAG,CAAC,OAAO,CAAC,OAAO;AACrD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC5E,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC5D,EAAE,MAAM,CAAC,QAAQ,CAAC,SAAS,GAAG;AAC9B,CAAC,CAAC,CAAC,EAAE;AACL,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI;AACxE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI;AACzE,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC;AACpD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,OAAO;AACnD,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,MAAM;AAC/C,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACrF,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,UAAU,CAAC,EAAE;AACjD,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI;AAC1B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO;AACxD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAChF,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACnB,EAAE,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC7C,GAAG,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;AACzE,EAAE,CAAC,CAAC,EAAE;AACN;AACA,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE;AAC7B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;AAC/B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;AACjC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK;AACrC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI;AAC5C,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,MAAM;AAC7C,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC;AACrC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC;AACb,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC;AACvB,EAAE,IAAI,CAAC,CAAC,IAAI;AACZ,CAAC,CAAC,CAAC,EAAE;AACL,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI;AACf,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,IAAI;AACxC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAChE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;AAClB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI;AAC9B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM;AACzC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,wBAAwB,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACzE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG;AACpB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACnB,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;AAC3F,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC/D,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,GAAG;AAC7B,EAAE,CAAC,CAAC,EAAE;AACN,CAAC,CAAC;AACF,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE;AAC/C,EAAE;;ACvTF,GAAG;AACH,CAAC,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK;AAC/E,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,EAAE,IAAI;AAC/E,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,EAAE;AACzF,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC1F,CAAC,CAAC;AACF,CAAC,CAAC,KAAK,CAAC,OAAO;AACf,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;AAC/B,CAAC,CAAC,KAAK,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,GAAG;AACrD,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,UAAU,EAAE,OAAO,CAAC,EAAE;AACxD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,GAAG,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO;AACnD,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM;AACxB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW;AAClC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB;AACvC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc;AACrC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB;AACxC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AACnC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa;AACpC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO;AACjD,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;AACnF,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC;AACxE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC;AAC5F,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;AAC5E,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE;AAChG,CAAC,CAAC,EAAE,IAAI,CAAC;AACT,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACjG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE;AAC9B,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC,GAAG,CAAC,WAAW,CAAC;AACjB;AACA,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;AAC9C,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;AAC3B,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC,EAAE;AACrD,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;AACrD,CAAC,CAAC,CAAC,EAAE;AACL;AACA,CAAC,EAAE,CAAC,aAAa,CAAC,cAAc;AAChC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AACrB,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC;AACf,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,EAAE;AAC1D,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE;AAC7D,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC;AAClB,EAAE,cAAc,CAAC,CAAC,KAAK,CAAC;AACxB,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC;AACzB,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,UAAU;AAC5C,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;AACb;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACpD;AACA,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAC9C,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AACnD,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AACnD,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,IAAI;AACtB,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AACf,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AACtD,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,UAAU;AAC5C,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;AACf,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAC/C,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAChD;AACA,CAAC,EAAE,CAAC,UAAU;AACd,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE;AAC5B,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;AACjE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC;AACrD,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,WAAW,GAAG;AAC1D,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC;AAC9B,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACT,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACrB,CAAC,CAAC;AACF,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC;AACvC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC;AACzC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAC/D;AACA,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;AACrE;AACA,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;AAC7C,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC,EAAE;AACpD,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC;AAChB,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE;AAChB,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ;AACzB,CAAC,CAAC,CAAC,EAAE;AACL;AACA,CAAC,EAAE,CAAC,MAAM;AACV,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;AAChC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAClC,EAAE,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC;AACvB,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC1B,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AACpD,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AACrB,GAAG,SAAS,CAAC,CAAC,WAAW,CAAC;AAC1B,GAAG,QAAQ,CAAC,CAAC,WAAW,CAAC;AACzB,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE;AAC5C,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACjC,EAAE,CAAC,CAAC,EAAE;AACN,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,cAAc;AAClB,CAAC,IAAI,CAAC,QAAQ,GAAG;AACjB,CAAC,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,EAAE;AACxD,CAAC,IAAI,EAAE,IAAI;AACX,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5C,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE;AACjF;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AAC7B,EAAE,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE;AACxC,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,EAAE;AAChF,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE;AAC5C,EAAE,IAAI,EAAE,OAAO;AACf,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAC1E,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;AACT,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AAC9C,GAAG,CAAC,CAAC,CAAC;AACN,GAAG,CAAC,MAAM,CAAC;AACX,IAAI,IAAI,EAAE,SAAS,CAAC;AACpB,IAAI,IAAI,EAAE,IAAI,CAAC;AACf,IAAI,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC;AAC/B,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;AACjB,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC;AACpD,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;AACjE,GAAG,EAAE;AACL,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACT,EAAE,IAAI,EAAE,OAAO;AACf,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC;AACxC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,EAAE;AACrD,CAAC,CAAC;AACF,CAAC,IAAI,CAAC,QAAQ,GAAG;AACjB,EAAE;AACF;AACA,EAAE,CAAC,KAAK,CAAC,EAAE;AACX;AACA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;AACxD,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE;AACjE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE;AACtE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE;AACpE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,EAAE;AACvE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE;AAClE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE;AACnE;AACA,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE;AACvB;AACA,GAAG;AACH,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS;AACpC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM;AACV,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AACpB,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACzD,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;AACZ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACjD,EAAE,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;AACnF,CAAC,CAAC;AACF,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,MAAM,CAAC,gBAAgB,CAAC;AACvD,EAAE;AACF;AACA,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC;AACtD;AACA,EAAE,CAAC,MAAM,CAAC,EAAE;AACZ;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;AAChB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;AACzE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK;AACrC,CAAC,EAAE;AACH;AACA,EAAE,CAAC,OAAO,CAAC,EAAE;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK;AACrC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;AACtB,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACzD,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC;AACzB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK;AACrC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM;AACzC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC/D,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACnC,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1B,EAAE,IAAI,CAAC,QAAQ,GAAG;AAClB,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;AAC1C,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU;AAClE,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,SAAS;AACb,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACzD,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;AACZ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC3B,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC,EAAE;AAClE,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,EAAE;AAC9D,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE;AACrC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACT,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,EAAE;AAC/D,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC3B,GAAG,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,EAAE;AAC/D,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AACpB,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;AACvB,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;AACjB,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC;AACnD,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;AACnC,GAAG,EAAE;AACL,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE;AAC3B;AACA,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AAC/B,IAAI,IAAI,CAAC,WAAW,GAAG;AACvB,IAAI,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACtD,KAAK,IAAI,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;AACrE,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACxC,KAAK,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC;AAC5B,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;AAC7B,OAAO,IAAI,CAAC,CAAC,CAAC,UAAU,EAAE;AAC1B,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;AAC7D,MAAM,CAAC,CAAC,GAAG,OAAO;AAClB,KAAK,EAAE;AACP,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC1C,KAAK,IAAI,CAAC,UAAU,GAAG;AACvB,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AACrB,IAAI,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;AACjC,GAAG,CAAC;AACJ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACV,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AAC/B,IAAI,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;AACjC,IAAI,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AACvB,KAAK,KAAK,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AAC/C,IAAI,CAAC,CAAC,EAAE;AACR,IAAI,IAAI,EAAE,SAAS;AACnB,KAAK,CAAC,KAAK,EAAE;AACb,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE;AACpC,GAAG,CAAC;AACJ,GAAG,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,EAAE;AAC5D,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;AACrC,EAAE,CAAC;AACH,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;AAC7D,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AACnF,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACnE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,GAAG;AAC7B,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;AAC1B,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,GAAG;AAC5B;AACA,CAAC,EAAE,CAAC,CAAC;AACL,EAAE,IAAI,CAAC,EAAE;AACT,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;AACnE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;AACnD,CAAC,CAAC,CAAC,CAAC;AACJ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACtC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;AAC7C,GAAG,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC9C,IAAI,EAAE,CAAC,CAAC;AACR,KAAK,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;AAC9B,KAAK,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;AAC/B,KAAK,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK;AAC3B,IAAI,CAAC,CAAC,CAAC;AACP,KAAK,QAAQ,CAAC,MAAM,GAAG;AACvB,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AACZ,KAAK,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE;AAC7C,IAAI,CAAC;AACL,GAAG,CAAC,CAAC,EAAE;AACP,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;AACjC,EAAE,EAAE;AACJ,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,EAAE;AAC/B,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACT,EAAE,QAAQ,CAAC,MAAM,GAAG;AACpB,CAAC,CAAC;AACF;AACA,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,GAAG;AAC3B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM;AAC9B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACzD,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;AACrB,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,GAAG;AACvB,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC3B,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACrB,EAAE,MAAM,CAAC;AACT,CAAC,CAAC;AACF;AACA,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;AACrD,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,EAAE;AACxD,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1C,EAAE,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK;AACnD,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK;AAC1B,EAAE,CAAC,CAAC,eAAe,GAAG;AACtB,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;AACpB,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;AACd,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACrB,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACzD,CAAC,CAAC;AACF,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE;AACjD,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI;AAC1C,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;AAC1C,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;AACpB,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACxE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AACjB;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACnC,EAAE,MAAM,CAAC,IAAI,CAAC;AACd,CAAC,CAAC;AACF;AACA,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC7C,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9B,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAChC,GAAG,MAAM,CAAC,IAAI,CAAC;AACf,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAChD,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACxD,GAAG,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC9D,IAAI,MAAM,CAAC,IAAI,CAAC;AAChB,GAAG,CAAC;AACJ,EAAE,CAAC;AACH,CAAC,CAAC;AACF;AACA,CAAC,MAAM,CAAC,KAAK,CAAC;AACd,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK;AACvC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AAC1B,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC;AACvD;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClD,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACd,CAAC,CAAC;AACF;AACA,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE;AACvB,CAAC,IAAI,CAAC,QAAQ,GAAG;AACjB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;AACpC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO;AAC3E,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC7D,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE;AACvB,CAAC,MAAM,CAAC,KAAK,CAAC;AACd,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;AAC3B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK;AAC1C,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO;AAC3E,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9D,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE;AAC9D,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAClE,CAAC,CAAC,CAAC,CAAC;AACJ,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;AACjC,EAAE,MAAM,CAAC,KAAK,CAAC;AACf,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;AACnC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK;AAC1C,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO;AAC3E,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAClE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;AAC/D,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;AACjC,EAAE,MAAM,CAAC,KAAK,CAAC;AACf,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM;AACpC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK;AACrC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO;AAC3E,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrE,CAAC,GAAG,CAAC,UAAU,CAAC;AAChB,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC;AACxB,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC;AACpC;AACA,CAAC,CAAC,CAAC,cAAc,GAAG;AACpB,CAAC,CAAC,CAAC,eAAe,GAAG;AACrB;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAChD,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,EAAE;AAChE,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;AACzB,EAAE,MAAM,CAAC,KAAK,CAAC;AACf,CAAC,CAAC;AACF;AACA,CAAC,EAAE,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK;AAC5E,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;AACtC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE;AAC3E,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AACpB,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,GAAG,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC;AACxB,EAAE,CAAC;AACH,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK;AAC5C,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChG,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM;AAChF,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC;AAC9B,EAAE,EAAE,CAAC,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM;AACxD,EAAE,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC;AACvB,CAAC,CAAC;AACF;AACA,CAAC,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,aAAa,CAAC,EAAE;AAC9E,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AACxB,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;AACzB,CAAC,CAAC;AACF;AACA,CAAC,MAAM,CAAC,KAAK,CAAC;AACd,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM;AAC3B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK;AACrC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC5D,CAAC,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,EAAE;AAC/D,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM;AACrB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK;AACrC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO;AAC3E,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1D,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACjB,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC;AACpC;AACA,CAAC,CAAC,CAAC,cAAc,GAAG;AACpB,CAAC,CAAC,CAAC,eAAe,GAAG;AACrB,CAAC,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,EAAE;AAC/D;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAChD,EAAE,MAAM,CAAC,KAAK,CAAC;AACf,CAAC,CAAC;AACF;AACA,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE;AACrC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClD,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACd,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACd,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE;AACxB,CAAC,CAAC;AACF;AACA,CAAC,MAAM,CAAC,KAAK,CAAC;AACd,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,CAAC,UAAU;AACd,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE;AAC5E,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AAC3B,EAAE,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,EAAE;AAC5C,CAAC,CAAC;AACF,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAC1B,EAAE,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,EAAE;AAC3C,CAAC,CAAC;AACF,CAAC,MAAM,CAAC,IAAI,CAAC;AACb,EAAE;;AC/fF,GAAG;AACH,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE;AAC1E,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC;AACrE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;AAC9C,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO;AAChG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AAC7F,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC;AACrC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;AAC5F,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,GAAG;AAChG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC;AACtC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,GAAG,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,iBAAiB,CAAC,IAAI,CAAC,MAAM;AACrF,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,KAAK;AACT,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM;AACxB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,WAAW;AACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,OAAO;AACjD,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK;AACtE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK;AAC5C,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC1D,CAAC,EAAE,CAAC,aAAa,CAAC,cAAc;AAChC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG;AACvB;AACA,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;AACtB,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE;AAChD;AACA,CAAC,EAAE,CAAC,UAAU;AACd,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC;AAC1C,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE;AACjB,EAAE,WAAW,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC;AAClC,EAAE,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK;AACrB,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,GAAG;AACzC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE;AAC5B,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE;AAC9B;AACA,CAAC,EAAE,CAAC,MAAM;AACV,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5B,EAAE,MAAM,CAAC,CAAC,CAAC,aAAa,EAAE;AAC1B,EAAE,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC;AACvB,CAAC,CAAC,CAAC,EAAE;AACL,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;AACrE;AACA,CAAC,EAAE,CAAC,cAAc;AAClB,CAAC,IAAI,EAAE,KAAK;AACZ,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;AACzC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE;AACjC,CAAC,IAAI,EAAE,OAAO;AACd,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;AAC3C,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE;AACnC,CAAC,IAAI,EAAE,OAAO;AACd,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;AACnC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE;AACxC,EAAE;AACF;AACA,EAAE,CAAC,KAAK,CAAC,EAAE;AACX;AACA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;AACpD;AACA,EAAE,CAAC,OAAO,CAAC,EAAE;AACb;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;AAChC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK;AACzC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9D,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,QAAQ,CAAC;AAC/B,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;AACjF;AACA,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACb,EAAE,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,mBAAmB,GAAG;AACvD,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AAC3B,GAAG,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,GAAG;AACrD,EAAE,CAAC;AACH,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,EAAE;AAC7E,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,QAAQ,CAAC,EAAE;AACzC,EAAE,QAAQ,CAAC,qBAAqB,GAAG;AACnC,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;AACtC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;AACtF,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK;AAClC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC1D,CAAC,EAAE,CAAC,KAAK;AACT,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,GAAG;AAC3B,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;AACzC,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC;AAC5B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,OAAO;AACX,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK;AAClC,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACzD,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,mBAAmB,GAAG;AAC1D,CAAC,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AACzB,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,eAAe,CAAC,EAAE;AAC7C,CAAC,CAAC;AACF,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;AACvB,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,KAAK;AAC9C,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACrD,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACnB,EAAE;AACF;AACA,GAAG;AACH,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;AAC/B,CAAC,CAAC;AACF,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO;AACtD,CAAC,EAAE;AACH,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACvD,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;AACrB,EAAE;;ACjIF,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE","file":"oojs-ui-widgets.js","sourcesContent":["( function ( OO ) {\n\n'use strict';\n","/**\n * DraggableElement is a mixin class used to create elements that can be clicked\n * and dragged by a mouse to a new position within a group. This class must be used\n * in conjunction with OO.ui.mixin.DraggableGroupElement, which provides a container for\n * the draggable elements.\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$handle] The part of the element which can be used for dragging, defaults to\n *  the whole element\n * @cfg {boolean} [draggable] The items are draggable. This can change with #toggleDraggable\n *  but the draggable state should be called from the DraggableGroupElement, which updates\n *  the whole group\n */\nOO.ui.mixin.DraggableElement = function OoUiMixinDraggableElement( config ) {\n\tconfig = config || {};\n\n\t// Properties\n\tthis.index = null;\n\tthis.$handle = config.$handle || this.$element;\n\tthis.wasHandleUsed = null;\n\n\t// Initialize and events\n\tthis.$element\n\t\t.addClass( 'oo-ui-draggableElement' )\n\t\t.on( {\n\t\t\tmousedown: this.onDragMouseDown.bind( this ),\n\t\t\tdragstart: this.onDragStart.bind( this ),\n\t\t\tdragover: this.onDragOver.bind( this ),\n\t\t\tdragend: this.onDragEnd.bind( this ),\n\t\t\tdrop: this.onDrop.bind( this )\n\t\t} );\n\tthis.$handle.addClass( 'oo-ui-draggableElement-handle' );\n\tthis.toggleDraggable( config.draggable === undefined ? true : !!config.draggable );\n};\n\nOO.initClass( OO.ui.mixin.DraggableElement );\n\n/* Events */\n\n/**\n * @event dragstart\n *\n * A dragstart event is emitted when the user clicks and begins dragging an item.\n * @param {OO.ui.mixin.DraggableElement} item The item the user has clicked and is dragging with\n *  the mouse.\n */\n\n/**\n * @event dragend\n * A dragend event is emitted when the user drags an item and releases the mouse,\n * thus terminating the drag operation.\n */\n\n/**\n * @event drop\n * A drop event is emitted when the user drags an item and then releases the mouse button\n * over a valid target.\n */\n\n/* Static Properties */\n\n/**\n * @inheritdoc OO.ui.mixin.ButtonElement\n */\nOO.ui.mixin.DraggableElement.static.cancelButtonMouseDownEvents = false;\n\n/* Methods */\n\n/**\n * Change the draggable state of this widget.\n * This allows users to temporarily halt the dragging operations.\n *\n * @param {boolean} isDraggable Widget supports draggable operations\n * @fires draggable\n */\nOO.ui.mixin.DraggableElement.prototype.toggleDraggable = function ( isDraggable ) {\n\tisDraggable = isDraggable !== undefined ? !!isDraggable : !this.draggable;\n\n\tif ( this.draggable !== isDraggable ) {\n\t\tthis.draggable = isDraggable;\n\n\t\tthis.$handle.toggleClass( 'oo-ui-draggableElement-undraggable', !this.draggable );\n\n\t\t// We make the entire element draggable, not just the handle, so that\n\t\t// the whole element appears to move. wasHandleUsed prevents drags from\n\t\t// starting outside the handle\n\t\tthis.$element.prop( 'draggable', this.draggable );\n\t}\n};\n\n/**\n * Check the draggable state of this widget.\n *\n * @return {boolean} Widget supports draggable operations\n */\nOO.ui.mixin.DraggableElement.prototype.isDraggable = function () {\n\treturn this.draggable;\n};\n\n/**\n * Respond to mousedown event.\n *\n * @private\n * @param {jQuery.Event} e Drag event\n */\nOO.ui.mixin.DraggableElement.prototype.onDragMouseDown = function ( e ) {\n\tif ( !this.isDraggable() ) {\n\t\treturn;\n\t}\n\n\tthis.wasHandleUsed =\n\t\t// Optimization: if the handle is the whole element this is always true\n\t\tthis.$handle[ 0 ] === this.$element[ 0 ] ||\n\t\t// Check the mousedown occurred inside the handle\n\t\tOO.ui.contains( this.$handle[ 0 ], e.target, true );\n};\n\n/**\n * Respond to dragstart event.\n *\n * @private\n * @param {jQuery.Event} e Drag event\n * @return {boolean} False if the event is cancelled\n * @fires dragstart\n */\nOO.ui.mixin.DraggableElement.prototype.onDragStart = function ( e ) {\n\tvar element = this,\n\t\tdataTransfer = e.originalEvent.dataTransfer;\n\n\tif ( !this.wasHandleUsed || !this.isDraggable() ) {\n\t\treturn false;\n\t}\n\n\t// Define drop effect\n\tdataTransfer.dropEffect = 'none';\n\tdataTransfer.effectAllowed = 'move';\n\t// Support: Firefox\n\t// We must set up a dataTransfer data property or Firefox seems to\n\t// ignore the fact the element is draggable.\n\ttry {\n\t\tdataTransfer.setData( 'application-x/OOUI-draggable', this.getIndex() );\n\t} catch ( err ) {\n\t\t// The above is only for Firefox. Move on if it fails.\n\t}\n\t// Briefly add a 'clone' class to style the browser's native drag image\n\tthis.$element.addClass( 'oo-ui-draggableElement-clone' );\n\t// Add placeholder class after the browser has rendered the clone\n\tsetTimeout( function () {\n\t\telement.$element\n\t\t\t.removeClass( 'oo-ui-draggableElement-clone' )\n\t\t\t.addClass( 'oo-ui-draggableElement-placeholder' );\n\t} );\n\t// Emit event\n\tthis.emit( 'dragstart', this );\n\treturn true;\n};\n\n/**\n * Respond to dragend event.\n *\n * @private\n * @fires dragend\n */\nOO.ui.mixin.DraggableElement.prototype.onDragEnd = function () {\n\tthis.$element.removeClass( 'oo-ui-draggableElement-placeholder' );\n\tthis.emit( 'dragend' );\n};\n\n/**\n * Handle drop event.\n *\n * @private\n * @param {jQuery.Event} e Drop event\n * @fires drop\n */\nOO.ui.mixin.DraggableElement.prototype.onDrop = function ( e ) {\n\te.preventDefault();\n\tthis.emit( 'drop', e );\n};\n\n/**\n * In order for drag/drop to work, the dragover event must\n * return false and stop propogation.\n *\n * @param {jQuery.Event} e Drag event\n * @private\n */\nOO.ui.mixin.DraggableElement.prototype.onDragOver = function ( e ) {\n\te.preventDefault();\n};\n\n/**\n * Set item index.\n * Store it in the DOM so we can access from the widget drag event.\n *\n * @private\n * @param {number} index Item index\n */\nOO.ui.mixin.DraggableElement.prototype.setIndex = function ( index ) {\n\tif ( this.index !== index ) {\n\t\tthis.index = index;\n\t\tthis.$element.data( 'index', index );\n\t}\n};\n\n/**\n * Get item index.\n *\n * @private\n * @return {number} Item index\n */\nOO.ui.mixin.DraggableElement.prototype.getIndex = function () {\n\treturn this.index;\n};\n","/**\n * DraggableGroupElement is a mixin class used to create a group element to\n * contain draggable elements, which are items that can be clicked and dragged by a mouse.\n * The class is used with OO.ui.mixin.DraggableElement.\n *\n * @abstract\n * @class\n * @mixins OO.ui.mixin.GroupElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {string} [orientation] Item orientation: 'horizontal' or 'vertical'. The orientation\n *  should match the layout of the items. Items displayed in a single row\n *  or in several rows should use horizontal orientation. The vertical orientation should only be\n *  used when the items are displayed in a single column. Defaults to 'vertical'\n * @cfg {boolean} [draggable] The items are draggable. This can change with #toggleDraggable\n */\nOO.ui.mixin.DraggableGroupElement = function OoUiMixinDraggableGroupElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.mixin.GroupElement.call( this, config );\n\n\t// Properties\n\tthis.orientation = config.orientation || 'vertical';\n\tthis.dragItem = null;\n\tthis.itemKeys = {};\n\tthis.dir = null;\n\tthis.itemsOrder = null;\n\tthis.draggable = config.draggable === undefined ? true : !!config.draggable;\n\n\t// Events\n\tthis.aggregate( {\n\t\tdragstart: 'itemDragStart',\n\t\tdragend: 'itemDragEnd',\n\t\tdrop: 'itemDrop'\n\t} );\n\tthis.connect( this, {\n\t\titemDragStart: 'onItemDragStart',\n\t\titemDrop: 'onItemDropOrDragEnd',\n\t\titemDragEnd: 'onItemDropOrDragEnd'\n\t} );\n\n\t// Initialize\n\tif ( Array.isArray( config.items ) ) {\n\t\tthis.addItems( config.items );\n\t}\n\tthis.$element\n\t\t.addClass( 'oo-ui-draggableGroupElement' )\n\t\t.toggleClass( 'oo-ui-draggableGroupElement-horizontal', this.orientation === 'horizontal' );\n};\n\n/* Setup */\nOO.mixinClass( OO.ui.mixin.DraggableGroupElement, OO.ui.mixin.GroupElement );\n\n/* Events */\n\n/**\n * An item has been dragged to a new position, but not yet dropped.\n *\n * @event drag\n * @param {OO.ui.mixin.DraggableElement} item Dragged item\n * @param {number} [newIndex] New index for the item\n */\n\n/**\n * An item has been dropped at a new position.\n *\n * @event reorder\n * @param {OO.ui.mixin.DraggableElement} item Reordered item\n * @param {number} [newIndex] New index for the item\n */\n\n/**\n * Draggable state of this widget has changed.\n *\n * @event draggable\n * @param {boolean} [draggable] Widget is draggable\n */\n\n/* Methods */\n\n/**\n * Change the draggable state of this widget.\n * This allows users to temporarily halt the dragging operations.\n *\n * @param {boolean} isDraggable Widget supports draggable operations\n * @fires draggable\n */\nOO.ui.mixin.DraggableGroupElement.prototype.toggleDraggable = function ( isDraggable ) {\n\tisDraggable = isDraggable !== undefined ? !!isDraggable : !this.draggable;\n\n\tif ( this.draggable !== isDraggable ) {\n\t\tthis.draggable = isDraggable;\n\n\t\t// Tell the items their draggable state changed\n\t\tthis.getItems().forEach( function ( item ) {\n\t\t\titem.toggleDraggable( this.draggable );\n\t\t}.bind( this ) );\n\n\t\t// Emit event\n\t\tthis.emit( 'draggable', this.draggable );\n\t}\n};\n\n/**\n * Check the draggable state of this widget\n *\n * @return {boolean} Widget supports draggable operations\n */\nOO.ui.mixin.DraggableGroupElement.prototype.isDraggable = function () {\n\treturn this.draggable;\n};\n\n/**\n * Respond to item drag start event\n *\n * @private\n * @param {OO.ui.mixin.DraggableElement} item Dragged item\n */\nOO.ui.mixin.DraggableGroupElement.prototype.onItemDragStart = function ( item ) {\n\tif ( !this.isDraggable() ) {\n\t\treturn;\n\t}\n\t// Make a shallow copy of this.items so we can re-order it during previews\n\t// without affecting the original array.\n\tthis.itemsOrder = this.items.slice();\n\tthis.updateIndexes();\n\tif ( this.orientation === 'horizontal' ) {\n\t\t// Calculate and cache directionality on drag start - it's a little\n\t\t// expensive and it shouldn't change while dragging.\n\t\tthis.dir = this.$element.css( 'direction' );\n\t}\n\tthis.setDragItem( item );\n};\n\n/**\n * Update the index properties of the items\n */\nOO.ui.mixin.DraggableGroupElement.prototype.updateIndexes = function () {\n\tvar i, len;\n\n\t// Map the index of each object\n\tfor ( i = 0, len = this.itemsOrder.length; i < len; i++ ) {\n\t\tthis.itemsOrder[ i ].setIndex( i );\n\t}\n};\n\n/**\n * Handle drop or dragend event and switch the order of the items accordingly\n *\n * @private\n * @param {OO.ui.mixin.DraggableElement} item Dropped item\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.DraggableGroupElement.prototype.onItemDropOrDragEnd = function () {\n\tvar targetIndex, originalIndex,\n\t\titem = this.getDragItem();\n\n\t// TODO: Figure out a way to configure a list of legally droppable\n\t// elements even if they are not yet in the list\n\tif ( item ) {\n\t\toriginalIndex = this.items.indexOf( item );\n\t\t// If the item has moved forward, add one to the index to account for the left shift\n\t\ttargetIndex = item.getIndex() + ( item.getIndex() > originalIndex ? 1 : 0 );\n\t\tif ( targetIndex !== originalIndex ) {\n\t\t\tthis.reorder( this.getDragItem(), targetIndex );\n\t\t\tthis.emit( 'reorder', this.getDragItem(), targetIndex );\n\t\t}\n\t\tthis.updateIndexes();\n\t}\n\tthis.unsetDragItem();\n\t// Return false to prevent propogation\n\treturn false;\n};\n\n/**\n * Respond to dragover event\n *\n * @private\n * @param {jQuery.Event} e Dragover event\n * @fires reorder\n */\nOO.ui.mixin.DraggableGroupElement.prototype.onDragOver = function ( e ) {\n\tvar overIndex, targetIndex,\n\t\titem = this.getDragItem(),\n\t\tdragItemIndex = item.getIndex();\n\n\t// Get the OptionWidget item we are dragging over\n\toverIndex = $( e.target ).closest( '.oo-ui-draggableElement' ).data( 'index' );\n\n\tif ( overIndex !== undefined && overIndex !== dragItemIndex ) {\n\t\ttargetIndex = overIndex + ( overIndex > dragItemIndex ? 1 : 0 );\n\n\t\tif ( targetIndex > 0 ) {\n\t\t\tthis.$group.children().eq( targetIndex - 1 ).after( item.$element );\n\t\t} else {\n\t\t\tthis.$group.prepend( item.$element );\n\t\t}\n\t\t// Move item in itemsOrder array\n\t\tthis.itemsOrder.splice( overIndex, 0,\n\t\t\tthis.itemsOrder.splice( dragItemIndex, 1 )[ 0 ]\n\t\t);\n\t\tthis.updateIndexes();\n\t\tthis.emit( 'drag', item, targetIndex );\n\t}\n\t// Prevent default\n\te.preventDefault();\n};\n\n/**\n * Reorder the items in the group\n *\n * @param {OO.ui.mixin.DraggableElement} item Reordered item\n * @param {number} newIndex New index\n */\nOO.ui.mixin.DraggableGroupElement.prototype.reorder = function ( item, newIndex ) {\n\tthis.addItems( [ item ], newIndex );\n};\n\n/**\n * Set a dragged item\n *\n * @param {OO.ui.mixin.DraggableElement} item Dragged item\n */\nOO.ui.mixin.DraggableGroupElement.prototype.setDragItem = function ( item ) {\n\tif ( this.dragItem !== item ) {\n\t\tthis.dragItem = item;\n\t\tthis.$element.on( 'dragover', this.onDragOver.bind( this ) );\n\t\tthis.$element.addClass( 'oo-ui-draggableGroupElement-dragging' );\n\t}\n};\n\n/**\n * Unset the current dragged item\n */\nOO.ui.mixin.DraggableGroupElement.prototype.unsetDragItem = function () {\n\tif ( this.dragItem ) {\n\t\tthis.dragItem = null;\n\t\tthis.$element.off( 'dragover' );\n\t\tthis.$element.removeClass( 'oo-ui-draggableGroupElement-dragging' );\n\t}\n};\n\n/**\n * Get the item that is currently being dragged.\n *\n * @return {OO.ui.mixin.DraggableElement|null} The currently dragged item, or `null` if no item is\n *  being dragged\n */\nOO.ui.mixin.DraggableGroupElement.prototype.getDragItem = function () {\n\treturn this.dragItem;\n};\n","/**\n * RequestManager is a mixin that manages the lifecycle of a promise-backed request for a widget,\n * such as the {@link OO.ui.mixin.LookupElement}.\n *\n * @class\n * @abstract\n *\n * @constructor\n */\nOO.ui.mixin.RequestManager = function OoUiMixinRequestManager() {\n\tthis.requestCache = {};\n\tthis.requestQuery = null;\n\tthis.requestRequest = null;\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.mixin.RequestManager );\n\n/**\n * Get request results for the current query.\n *\n * @return {jQuery.Promise} Promise object which will be passed response data as the first argument\n *  of the done event. If the request was aborted to make way for a subsequent request, this\n *  promise may not be rejected, depending on what jQuery feels like doing.\n */\nOO.ui.mixin.RequestManager.prototype.getRequestData = function () {\n\tvar widget = this,\n\t\tvalue = this.getRequestQuery(),\n\t\tdeferred = $.Deferred(),\n\t\tourRequest;\n\n\tthis.abortRequest();\n\tif ( Object.prototype.hasOwnProperty.call( this.requestCache, value ) ) {\n\t\tdeferred.resolve( this.requestCache[ value ] );\n\t} else {\n\t\tif ( this.pushPending ) {\n\t\t\tthis.pushPending();\n\t\t}\n\t\tthis.requestQuery = value;\n\t\tourRequest = this.requestRequest = this.getRequest();\n\t\tourRequest\n\t\t\t.always( function () {\n\t\t\t\t// We need to pop pending even if this is an old request, otherwise\n\t\t\t\t// the widget will remain pending forever.\n\t\t\t\t// TODO: this assumes that an aborted request will fail or succeed soon after\n\t\t\t\t// being aborted, or at least eventually. It would be nice if we could popPending()\n\t\t\t\t// at abort time, but only if we knew that we hadn't already called popPending()\n\t\t\t\t// for that request.\n\t\t\t\tif ( widget.popPending ) {\n\t\t\t\t\twidget.popPending();\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.done( function ( response ) {\n\t\t\t\t// If this is an old request (and aborting it somehow caused it to still succeed),\n\t\t\t\t// ignore its success completely\n\t\t\t\tif ( ourRequest === widget.requestRequest ) {\n\t\t\t\t\twidget.requestQuery = null;\n\t\t\t\t\twidget.requestRequest = null;\n\t\t\t\t\twidget.requestCache[ value ] =\n\t\t\t\t\t\twidget.getRequestCacheDataFromResponse( response );\n\t\t\t\t\tdeferred.resolve( widget.requestCache[ value ] );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.fail( function () {\n\t\t\t\t// If this is an old request (or a request failing because it's being aborted),\n\t\t\t\t// ignore its failure completely\n\t\t\t\tif ( ourRequest === widget.requestRequest ) {\n\t\t\t\t\twidget.requestQuery = null;\n\t\t\t\t\twidget.requestRequest = null;\n\t\t\t\t\tdeferred.reject();\n\t\t\t\t}\n\t\t\t} );\n\t}\n\treturn deferred.promise();\n};\n\n/**\n * Abort the currently pending request, if any.\n *\n * @private\n */\nOO.ui.mixin.RequestManager.prototype.abortRequest = function () {\n\tvar oldRequest = this.requestRequest;\n\tif ( oldRequest ) {\n\t\t// First unset this.requestRequest to the fail handler will notice\n\t\t// that the request is no longer current\n\t\tthis.requestRequest = null;\n\t\tthis.requestQuery = null;\n\t\toldRequest.abort();\n\t}\n};\n\n/**\n * Get the query to be made.\n *\n * @protected\n * @method\n * @abstract\n * @return {string} query to be used\n */\nOO.ui.mixin.RequestManager.prototype.getRequestQuery = null;\n\n/**\n * Get a new request object of the current query value.\n *\n * @protected\n * @method\n * @abstract\n * @return {jQuery.Promise} jQuery AJAX object, or promise object with an .abort() method\n */\nOO.ui.mixin.RequestManager.prototype.getRequest = null;\n\n/**\n * Pre-process data returned by the request from #getRequest.\n *\n * The return value of this function will be cached, and any further queries for the given value\n * will use the cache rather than doing API requests.\n *\n * @protected\n * @method\n * @abstract\n * @param {Mixed} response Response from server\n * @return {Mixed} Cached result data\n */\nOO.ui.mixin.RequestManager.prototype.getRequestCacheDataFromResponse = null;\n","/**\n * LookupElement is a mixin that creates a {@link OO.ui.MenuSelectWidget menu} of suggested\n * values for a {@link OO.ui.TextInputWidget text input widget}. Suggested values are based on\n * the characters the user types into the text input field and, in general, the menu is only\n * displayed when the user types. If a suggested value is chosen from the lookup menu, that value\n * becomes the value of the input field.\n *\n * Note that a new menu of suggested items is displayed when a value is chosen from the\n * lookup menu. If this is not the desired behavior, disable lookup menus with the\n * #setLookupsDisabled method, then set the value, then re-enable lookups.\n *\n * See the [OOUI demos][1] for an example.\n *\n * [1]: https://doc.wikimedia.org/oojs-ui/master/demos/#LookupElement-try-inputting-an-integer\n *\n * @class\n * @abstract\n * @mixins OO.ui.mixin.RequestManager\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$overlay] Overlay for the lookup menu; defaults to relative positioning.\n *  See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.\n * @cfg {jQuery} [$container=this.$element] The container element. The lookup menu is rendered\n *  beneath the specified element.\n * @cfg {Object} [menu] Configuration options to pass to\n *  {@link OO.ui.MenuSelectWidget menu select widget}\n * @cfg {boolean} [allowSuggestionsWhenEmpty=false] Request and display a lookup menu when the\n *  text input is empty.\n *  By default, the lookup menu is not generated and displayed until the user begins to type.\n * @cfg {boolean} [highlightFirst=true] Whether the first lookup result should be highlighted\n *  (so, that the user can take it over into the input with simply pressing return) automatically\n *  or not.\n */\nOO.ui.mixin.LookupElement = function OoUiMixinLookupElement( config ) {\n\t// Configuration initialization\n\tconfig = $.extend( { highlightFirst: true }, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.RequestManager.call( this, config );\n\n\t// Properties\n\tthis.$overlay = ( config.$overlay === true ?\n\t\tOO.ui.getDefaultOverlay() : config.$overlay ) || this.$element;\n\tthis.lookupMenu = new OO.ui.MenuSelectWidget( $.extend( {\n\t\twidget: this,\n\t\tinput: this,\n\t\t$floatableContainer: config.$container || this.$element\n\t}, config.menu ) );\n\n\tthis.allowSuggestionsWhenEmpty = config.allowSuggestionsWhenEmpty || false;\n\n\tthis.lookupsDisabled = false;\n\tthis.lookupInputFocused = false;\n\tthis.lookupHighlightFirstItem = config.highlightFirst;\n\n\t// Events\n\tthis.$input.on( {\n\t\tfocus: this.onLookupInputFocus.bind( this ),\n\t\tblur: this.onLookupInputBlur.bind( this ),\n\t\tmousedown: this.onLookupInputMouseDown.bind( this )\n\t} );\n\tthis.connect( this, {\n\t\tchange: 'onLookupInputChange'\n\t} );\n\tthis.lookupMenu.connect( this, {\n\t\ttoggle: 'onLookupMenuToggle',\n\t\tchoose: 'onLookupMenuItemChoose'\n\t} );\n\n\t// Initialization\n\tthis.$input.attr( {\n\t\trole: 'combobox',\n\t\t'aria-owns': this.lookupMenu.getElementId(),\n\t\t'aria-autocomplete': 'list'\n\t} );\n\tthis.$element.addClass( 'oo-ui-lookupElement' );\n\tthis.lookupMenu.$element.addClass( 'oo-ui-lookupElement-menu' );\n\tthis.$overlay.append( this.lookupMenu.$element );\n};\n\n/* Setup */\n\nOO.mixinClass( OO.ui.mixin.LookupElement, OO.ui.mixin.RequestManager );\n\n/* Methods */\n\n/**\n * Handle input focus event.\n *\n * @protected\n * @param {jQuery.Event} e Input focus event\n */\nOO.ui.mixin.LookupElement.prototype.onLookupInputFocus = function () {\n\tthis.lookupInputFocused = true;\n\tthis.populateLookupMenu();\n};\n\n/**\n * Handle input blur event.\n *\n * @protected\n * @param {jQuery.Event} e Input blur event\n */\nOO.ui.mixin.LookupElement.prototype.onLookupInputBlur = function () {\n\tthis.closeLookupMenu();\n\tthis.lookupInputFocused = false;\n};\n\n/**\n * Handle input mouse down event.\n *\n * @protected\n * @param {jQuery.Event} e Input mouse down event\n */\nOO.ui.mixin.LookupElement.prototype.onLookupInputMouseDown = function () {\n\t// Only open the menu if the input was already focused.\n\t// This way we allow the user to open the menu again after closing it with Escape (esc)\n\t// by clicking in the input. Opening (and populating) the menu when initially\n\t// clicking into the input is handled by the focus handler.\n\tif ( this.lookupInputFocused && !this.lookupMenu.isVisible() ) {\n\t\tthis.populateLookupMenu();\n\t}\n};\n\n/**\n * Handle input change event.\n *\n * @protected\n * @param {string} value New input value\n */\nOO.ui.mixin.LookupElement.prototype.onLookupInputChange = function () {\n\tif ( this.lookupInputFocused ) {\n\t\tthis.populateLookupMenu();\n\t}\n};\n\n/**\n * Handle the lookup menu being shown/hidden.\n *\n * @protected\n * @param {boolean} visible Whether the lookup menu is now visible.\n */\nOO.ui.mixin.LookupElement.prototype.onLookupMenuToggle = function ( visible ) {\n\tif ( !visible ) {\n\t\t// When the menu is hidden, abort any active request and clear the menu.\n\t\t// This has to be done here in addition to closeLookupMenu(), because\n\t\t// MenuSelectWidget will close itself when the user presses Escape (esc).\n\t\tthis.abortLookupRequest();\n\t\tthis.lookupMenu.clearItems();\n\t}\n};\n\n/**\n * Handle menu item 'choose' event, updating the text input value to the value of the clicked item.\n *\n * @protected\n * @param {OO.ui.MenuOptionWidget} item Selected item\n */\nOO.ui.mixin.LookupElement.prototype.onLookupMenuItemChoose = function ( item ) {\n\tthis.setValue( item.getData() );\n};\n\n/**\n * Get lookup menu.\n *\n * @private\n * @return {OO.ui.MenuSelectWidget}\n */\nOO.ui.mixin.LookupElement.prototype.getLookupMenu = function () {\n\treturn this.lookupMenu;\n};\n\n/**\n * Disable or re-enable lookups.\n *\n * When lookups are disabled, calls to #populateLookupMenu will be ignored.\n *\n * @param {boolean} disabled Disable lookups\n */\nOO.ui.mixin.LookupElement.prototype.setLookupsDisabled = function ( disabled ) {\n\tthis.lookupsDisabled = !!disabled;\n};\n\n/**\n * Open the menu. If there are no entries in the menu, this does nothing.\n *\n * @private\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.LookupElement.prototype.openLookupMenu = function () {\n\tif ( !this.lookupMenu.isEmpty() ) {\n\t\tthis.lookupMenu.toggle( true );\n\t}\n\treturn this;\n};\n\n/**\n * Close the menu, empty it, and abort any pending request.\n *\n * @private\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.LookupElement.prototype.closeLookupMenu = function () {\n\tthis.lookupMenu.toggle( false );\n\tthis.abortLookupRequest();\n\tthis.lookupMenu.clearItems();\n\treturn this;\n};\n\n/**\n * Request menu items based on the input's current value, and when they arrive,\n * populate the menu with these items and show the menu.\n *\n * If lookups have been disabled with #setLookupsDisabled, this function does nothing.\n *\n * @private\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.LookupElement.prototype.populateLookupMenu = function () {\n\tvar widget = this,\n\t\tvalue = this.getValue();\n\n\tif ( this.lookupsDisabled || this.isReadOnly() ) {\n\t\treturn;\n\t}\n\n\t// If the input is empty, clear the menu, unless suggestions when empty are allowed.\n\tif ( !this.allowSuggestionsWhenEmpty && value === '' ) {\n\t\tthis.closeLookupMenu();\n\t// Skip population if there is already a request pending for the current value\n\t} else if ( value !== this.lookupQuery ) {\n\t\tthis.getLookupMenuItems()\n\t\t\t.done( function ( items ) {\n\t\t\t\twidget.lookupMenu.clearItems();\n\t\t\t\tif ( items.length ) {\n\t\t\t\t\twidget.lookupMenu\n\t\t\t\t\t\t.addItems( items )\n\t\t\t\t\t\t.toggle( true );\n\t\t\t\t\twidget.initializeLookupMenuSelection();\n\t\t\t\t} else {\n\t\t\t\t\twidget.lookupMenu.toggle( false );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.fail( function () {\n\t\t\t\twidget.lookupMenu.clearItems();\n\t\t\t\twidget.lookupMenu.toggle( false );\n\t\t\t} );\n\t}\n\n\treturn this;\n};\n\n/**\n * Highlight the first selectable item in the menu, if configured.\n *\n * @private\n * @chainable\n */\nOO.ui.mixin.LookupElement.prototype.initializeLookupMenuSelection = function () {\n\tif ( this.lookupHighlightFirstItem && !this.lookupMenu.findSelectedItem() ) {\n\t\tthis.lookupMenu.highlightItem( this.lookupMenu.findFirstSelectableItem() );\n\t}\n};\n\n/**\n * Get lookup menu items for the current query.\n *\n * @private\n * @return {jQuery.Promise} Promise object which will be passed menu items as the first argument of\n *   the done event. If the request was aborted to make way for a subsequent request, this promise\n *   will not be rejected: it will remain pending forever.\n */\nOO.ui.mixin.LookupElement.prototype.getLookupMenuItems = function () {\n\treturn this.getRequestData().then( function ( data ) {\n\t\treturn this.getLookupMenuOptionsFromData( data );\n\t}.bind( this ) );\n};\n\n/**\n * Abort the currently pending lookup request, if any.\n *\n * @private\n */\nOO.ui.mixin.LookupElement.prototype.abortLookupRequest = function () {\n\tthis.abortRequest();\n};\n\n/**\n * Get a new request object of the current lookup query value.\n *\n * @protected\n * @method\n * @abstract\n * @return {jQuery.Promise} jQuery AJAX object, or promise object with an .abort() method\n */\nOO.ui.mixin.LookupElement.prototype.getLookupRequest = null;\n\n/**\n * Pre-process data returned by the request from #getLookupRequest.\n *\n * The return value of this function will be cached, and any further queries for the given value\n * will use the cache rather than doing API requests.\n *\n * @protected\n * @method\n * @abstract\n * @param {Mixed} response Response from server\n * @return {Mixed} Cached result data\n */\nOO.ui.mixin.LookupElement.prototype.getLookupCacheDataFromResponse = null;\n\n/**\n * Get a list of menu option widgets from the (possibly cached) data returned by\n * #getLookupCacheDataFromResponse.\n *\n * @protected\n * @method\n * @abstract\n * @param {Mixed} data Cached result data, usually an array\n * @return {OO.ui.MenuOptionWidget[]} Menu items\n */\nOO.ui.mixin.LookupElement.prototype.getLookupMenuOptionsFromData = null;\n\n/**\n * Set the read-only state of the widget.\n *\n * This will also disable/enable the lookups functionality.\n *\n * @param {boolean} readOnly Make input read-only\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.LookupElement.prototype.setReadOnly = function ( readOnly ) {\n\t// Parent method\n\t// Note: Calling #setReadOnly this way assumes this is mixed into an OO.ui.TextInputWidget\n\tOO.ui.TextInputWidget.prototype.setReadOnly.call( this, readOnly );\n\n\t// During construction, #setReadOnly is called before the OO.ui.mixin.LookupElement constructor.\n\tif ( this.isReadOnly() && this.lookupMenu ) {\n\t\tthis.closeLookupMenu();\n\t}\n\n\treturn this;\n};\n\n/**\n * @inheritdoc OO.ui.mixin.RequestManager\n */\nOO.ui.mixin.LookupElement.prototype.getRequestQuery = function () {\n\treturn this.getValue();\n};\n\n/**\n * @inheritdoc OO.ui.mixin.RequestManager\n */\nOO.ui.mixin.LookupElement.prototype.getRequest = function () {\n\treturn this.getLookupRequest();\n};\n\n/**\n * @inheritdoc OO.ui.mixin.RequestManager\n */\nOO.ui.mixin.LookupElement.prototype.getRequestCacheDataFromResponse = function ( response ) {\n\treturn this.getLookupCacheDataFromResponse( response );\n};\n","/**\n * TabPanelLayouts are used within {@link OO.ui.IndexLayout index layouts} to create tab panels that\n * users can select and display from the index's optional {@link OO.ui.TabSelectWidget tab}\n * navigation. TabPanels are usually not instantiated directly, rather extended to include the\n * required content and functionality.\n *\n * Each tab panel must have a unique symbolic name, which is passed to the constructor. In addition,\n * the tab panel's tab item is customized (with a label) using the #setupTabItem method. See\n * {@link OO.ui.IndexLayout IndexLayout} for an example.\n *\n * @class\n * @extends OO.ui.PanelLayout\n *\n * @constructor\n * @param {string} name Unique symbolic name of tab panel\n * @param {Object} [config] Configuration options\n * @cfg {jQuery|string|Function|OO.ui.HtmlSnippet} [label] Label for tab panel's tab\n */\nOO.ui.TabPanelLayout = function OoUiTabPanelLayout( name, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( name ) && config === undefined ) {\n\t\tconfig = name;\n\t\tname = config.name;\n\t}\n\n\t// Configuration initialization\n\tconfig = $.extend( { scrollable: true }, config );\n\n\t// Parent constructor\n\tOO.ui.TabPanelLayout.parent.call( this, config );\n\n\t// Properties\n\tthis.name = name;\n\tthis.label = config.label;\n\tthis.tabItem = null;\n\tthis.active = false;\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-tabPanelLayout' )\n\t\t.attr( 'role', 'tabpanel' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.TabPanelLayout, OO.ui.PanelLayout );\n\n/* Events */\n\n/**\n * An 'active' event is emitted when the tab panel becomes active. Tab panels become active when\n * they are shown in a index layout that is configured to display only one tab panel at a time.\n *\n * @event active\n * @param {boolean} active Tab panel is active\n */\n\n/* Methods */\n\n/**\n * Get the symbolic name of the tab panel.\n *\n * @return {string} Symbolic name of tab panel\n */\nOO.ui.TabPanelLayout.prototype.getName = function () {\n\treturn this.name;\n};\n\n/**\n * Check if tab panel is active.\n *\n * Tab panels become active when they are shown in a {@link OO.ui.IndexLayout index layout} that is\n * configured to display only one tab panel at a time. Additional CSS is applied to the tab panel's\n * tab item to reflect the active state.\n *\n * @return {boolean} Tab panel is active\n */\nOO.ui.TabPanelLayout.prototype.isActive = function () {\n\treturn this.active;\n};\n\n/**\n * Get tab item.\n *\n * The tab item allows users to access the tab panel from the index's tab\n * navigation. The tab item itself can be customized (with a label, level, etc.) using the\n * #setupTabItem method.\n *\n * @return {OO.ui.TabOptionWidget|null} Tab option widget\n */\nOO.ui.TabPanelLayout.prototype.getTabItem = function () {\n\treturn this.tabItem;\n};\n\n/**\n * Set or unset the tab item.\n *\n * Specify a {@link OO.ui.TabOptionWidget tab option} to set it,\n * or `null` to clear the tab item. To customize the tab item itself (e.g., to set a label or tab\n * level), use #setupTabItem instead of this method.\n *\n * @param {OO.ui.TabOptionWidget|null} tabItem Tab option widget, null to clear\n * @chainable\n * @return {OO.ui.TabPanelLayout} The layout, for chaining\n */\nOO.ui.TabPanelLayout.prototype.setTabItem = function ( tabItem ) {\n\tthis.tabItem = tabItem || null;\n\tif ( tabItem ) {\n\t\tthis.setupTabItem();\n\t}\n\treturn this;\n};\n\n/**\n * Set up the tab item.\n *\n * Use this method to customize the tab item (e.g., to add a label or tab level). To set or unset\n * the tab item itself (with a {@link OO.ui.TabOptionWidget tab option} or `null`), use\n * the #setTabItem method instead.\n *\n * @param {OO.ui.TabOptionWidget} tabItem Tab option widget to set up\n * @chainable\n * @return {OO.ui.TabPanelLayout} The layout, for chaining\n */\nOO.ui.TabPanelLayout.prototype.setupTabItem = function () {\n\tthis.$element.attr( 'aria-labelledby', this.tabItem.getElementId() );\n\n\tthis.tabItem.$element.attr( 'aria-controls', this.getElementId() );\n\n\tif ( this.label ) {\n\t\tthis.tabItem.setLabel( this.label );\n\t}\n\treturn this;\n};\n\n/**\n * Set the tab panel to its 'active' state.\n *\n * Tab panels become active when they are shown in a index layout that is configured to display only\n * one tab panel at a time. Additional CSS is applied to the tab item to reflect the tab panel's\n * active state. Outside of the index context, setting the active state on a tab panel does nothing.\n *\n * @param {boolean} active Tab panel is active\n * @fires active\n */\nOO.ui.TabPanelLayout.prototype.setActive = function ( active ) {\n\tactive = !!active;\n\n\tif ( active !== this.active ) {\n\t\tthis.active = active;\n\t\tthis.$element.toggleClass( 'oo-ui-tabPanelLayout-active', this.active );\n\t\tthis.emit( 'active', this.active );\n\t}\n};\n","/**\n * PageLayouts are used within {@link OO.ui.BookletLayout booklet layouts} to create pages that\n * users can select and display from the booklet's optional\n * {@link OO.ui.OutlineSelectWidget outline} navigation. Pages are usually not instantiated\n * directly, rather extended to include the required content and functionality.\n *\n * Each page must have a unique symbolic name, which is passed to the constructor. In addition, the\n * page's outline item is customized (with a label, outline level, etc.) using the\n * #setupOutlineItem method. See {@link OO.ui.BookletLayout BookletLayout} for an example.\n *\n * @class\n * @extends OO.ui.PanelLayout\n *\n * @constructor\n * @param {string} name Unique symbolic name of page\n * @param {Object} [config] Configuration options\n */\nOO.ui.PageLayout = function OoUiPageLayout( name, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( name ) && config === undefined ) {\n\t\tconfig = name;\n\t\tname = config.name;\n\t}\n\n\t// Configuration initialization\n\tconfig = $.extend( { scrollable: true }, config );\n\n\t// Parent constructor\n\tOO.ui.PageLayout.parent.call( this, config );\n\n\t// Properties\n\tthis.name = name;\n\tthis.outlineItem = null;\n\tthis.active = false;\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-pageLayout' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.PageLayout, OO.ui.PanelLayout );\n\n/* Events */\n\n/**\n * An 'active' event is emitted when the page becomes active. Pages become active when they are\n * shown in a booklet layout that is configured to display only one page at a time.\n *\n * @event active\n * @param {boolean} active Page is active\n */\n\n/* Methods */\n\n/**\n * Get the symbolic name of the page.\n *\n * @return {string} Symbolic name of page\n */\nOO.ui.PageLayout.prototype.getName = function () {\n\treturn this.name;\n};\n\n/**\n * Check if page is active.\n *\n * Pages become active when they are shown in a {@link OO.ui.BookletLayout booklet layout} that is\n * configured to display only one page at a time. Additional CSS is applied to the page's outline\n * item to reflect the active state.\n *\n * @return {boolean} Page is active\n */\nOO.ui.PageLayout.prototype.isActive = function () {\n\treturn this.active;\n};\n\n/**\n * Get outline item.\n *\n * The outline item allows users to access the page from the booklet's outline\n * navigation. The outline item itself can be customized (with a label, level, etc.) using the\n * #setupOutlineItem method.\n *\n * @return {OO.ui.OutlineOptionWidget|null} Outline option widget\n */\nOO.ui.PageLayout.prototype.getOutlineItem = function () {\n\treturn this.outlineItem;\n};\n\n/**\n * Set or unset the outline item.\n *\n * Specify an {@link OO.ui.OutlineOptionWidget outline option} to set it,\n * or `null` to clear the outline item. To customize the outline item itself (e.g., to set a label\n * or outline level), use #setupOutlineItem instead of this method.\n *\n * @param {OO.ui.OutlineOptionWidget|null} outlineItem Outline option widget, null to clear\n * @chainable\n * @return {OO.ui.PageLayout} The layout, for chaining\n */\nOO.ui.PageLayout.prototype.setOutlineItem = function ( outlineItem ) {\n\tthis.outlineItem = outlineItem || null;\n\tif ( outlineItem ) {\n\t\tthis.setupOutlineItem();\n\t}\n\treturn this;\n};\n\n/**\n * Set up the outline item.\n *\n * Use this method to customize the outline item (e.g., to add a label or outline level). To set or\n * unset the outline item itself (with an {@link OO.ui.OutlineOptionWidget outline option} or\n * `null`), use the #setOutlineItem method instead.\n *\n * @param {OO.ui.OutlineOptionWidget} outlineItem Outline option widget to set up\n * @chainable\n * @return {OO.ui.PageLayout} The layout, for chaining\n */\nOO.ui.PageLayout.prototype.setupOutlineItem = function () {\n\treturn this;\n};\n\n/**\n * Set the page to its 'active' state.\n *\n * Pages become active when they are shown in a booklet layout that is configured to display only\n * one page at a time. Additional CSS is applied to the outline item to reflect the page's active\n * state. Outside of the booklet context, setting the active state on a page does nothing.\n *\n * @param {boolean} active Page is active\n * @fires active\n */\nOO.ui.PageLayout.prototype.setActive = function ( active ) {\n\tactive = !!active;\n\n\tif ( active !== this.active ) {\n\t\tthis.active = active;\n\t\tthis.$element.toggleClass( 'oo-ui-pageLayout-active', active );\n\t\tthis.emit( 'active', this.active );\n\t}\n};\n","/**\n * StackLayouts contain a series of {@link OO.ui.PanelLayout panel layouts}. By default, only one\n * panel is displayed at a time, though the stack layout can also be configured to show all\n * contained panels, one after another, by setting the #continuous option to 'true'.\n *\n *     @example\n *     // A stack layout with two panels, configured to be displayed continuously\n *     var myStack = new OO.ui.StackLayout( {\n *         items: [\n *             new OO.ui.PanelLayout( {\n *                 $content: $( '<p>Panel One</p>' ),\n *                 padded: true,\n *                 framed: true\n *             } ),\n *             new OO.ui.PanelLayout( {\n *                 $content: $( '<p>Panel Two</p>' ),\n *                 padded: true,\n *                 framed: true\n *             } )\n *         ],\n *         continuous: true\n *     } );\n *     $( document.body ).append( myStack.$element );\n *\n * @class\n * @extends OO.ui.PanelLayout\n * @mixins OO.ui.mixin.GroupElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [continuous=false] Show all panels, one after another. By default, only one panel\n *  is displayed at a time.\n * @cfg {OO.ui.Layout[]} [items] Panel layouts to add to the stack layout.\n */\nOO.ui.StackLayout = function OoUiStackLayout( config ) {\n\t// Configuration initialization\n\t// Make the layout scrollable in continuous mode, otherwise each\n\t// panel is responsible for its own scrolling.\n\tconfig = $.extend( { scrollable: !!( config && config.continuous ) }, config );\n\n\t// Parent constructor\n\tOO.ui.StackLayout.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.GroupElement.call( this, $.extend( { $group: this.$element }, config ) );\n\n\t// Properties\n\tthis.currentItem = null;\n\tthis.continuous = !!config.continuous;\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-stackLayout' );\n\tif ( this.continuous ) {\n\t\tthis.$element.addClass( 'oo-ui-stackLayout-continuous' );\n\t\tthis.$element.on( 'scroll', OO.ui.debounce( this.onScroll.bind( this ), 250 ) );\n\t}\n\tif ( Array.isArray( config.items ) ) {\n\t\tthis.addItems( config.items );\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.StackLayout, OO.ui.PanelLayout );\nOO.mixinClass( OO.ui.StackLayout, OO.ui.mixin.GroupElement );\n\n/* Events */\n\n/**\n * A 'set' event is emitted when panels are {@link #addItems added}, {@link #removeItems removed},\n * {@link #clearItems cleared} or {@link #setItem displayed}.\n *\n * @event set\n * @param {OO.ui.Layout|null} item Current panel or `null` if no panel is shown\n */\n\n/**\n * When used in continuous mode, this event is emitted when the user scrolls down\n * far enough such that currentItem is no longer visible.\n *\n * @event visibleItemChange\n * @param {OO.ui.PanelLayout} panel The next visible item in the layout\n */\n\n/* Methods */\n\n/**\n * Handle scroll events from the layout element\n *\n * @param {jQuery.Event} e\n * @fires visibleItemChange\n */\nOO.ui.StackLayout.prototype.onScroll = function () {\n\tvar currentRect,\n\t\tlen = this.items.length,\n\t\tcurrentIndex = this.items.indexOf( this.currentItem ),\n\t\tnewIndex = currentIndex,\n\t\tcontainerRect = this.$element[ 0 ].getBoundingClientRect();\n\n\tif ( !containerRect || ( !containerRect.top && !containerRect.bottom ) ) {\n\t\t// Can't get bounding rect, possibly not attached.\n\t\treturn;\n\t}\n\n\tfunction getRect( item ) {\n\t\treturn item.$element[ 0 ].getBoundingClientRect();\n\t}\n\n\tfunction isVisible( item ) {\n\t\tvar rect = getRect( item );\n\t\treturn rect.bottom > containerRect.top && rect.top < containerRect.bottom;\n\t}\n\n\tcurrentRect = getRect( this.currentItem );\n\n\tif ( currentRect.bottom < containerRect.top ) {\n\t\t// Scrolled down past current item\n\t\twhile ( ++newIndex < len ) {\n\t\t\tif ( isVisible( this.items[ newIndex ] ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t} else if ( currentRect.top > containerRect.bottom ) {\n\t\t// Scrolled up past current item\n\t\twhile ( --newIndex >= 0 ) {\n\t\t\tif ( isVisible( this.items[ newIndex ] ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( newIndex !== currentIndex ) {\n\t\tthis.emit( 'visibleItemChange', this.items[ newIndex ] );\n\t}\n};\n\n/**\n * Get the current panel.\n *\n * @return {OO.ui.Layout|null}\n */\nOO.ui.StackLayout.prototype.getCurrentItem = function () {\n\treturn this.currentItem;\n};\n\n/**\n * Unset the current item.\n *\n * @private\n * @param {OO.ui.StackLayout} layout\n * @fires set\n */\nOO.ui.StackLayout.prototype.unsetCurrentItem = function () {\n\tvar prevItem = this.currentItem;\n\tif ( prevItem === null ) {\n\t\treturn;\n\t}\n\n\tthis.currentItem = null;\n\tthis.emit( 'set', null );\n};\n\n/**\n * Add panel layouts to the stack layout.\n *\n * Panels will be added to the end of the stack layout array unless the optional index parameter\n * specifies a different insertion point. Adding a panel that is already in the stack will move it\n * to the end of the array or the point specified by the index.\n *\n * @param {OO.ui.Layout[]} items Panels to add\n * @param {number} [index] Index of the insertion point\n * @chainable\n * @return {OO.ui.StackLayout} The layout, for chaining\n */\nOO.ui.StackLayout.prototype.addItems = function ( items, index ) {\n\t// Update the visibility\n\tthis.updateHiddenState( items, this.currentItem );\n\n\t// Mixin method\n\tOO.ui.mixin.GroupElement.prototype.addItems.call( this, items, index );\n\n\tif ( !this.currentItem && items.length ) {\n\t\tthis.setItem( items[ 0 ] );\n\t}\n\n\treturn this;\n};\n\n/**\n * Remove the specified panels from the stack layout.\n *\n * Removed panels are detached from the DOM, not removed, so that they may be reused. To remove all\n * panels, you may wish to use the #clearItems method instead.\n *\n * @param {OO.ui.Layout[]} items Panels to remove\n * @chainable\n * @return {OO.ui.StackLayout} The layout, for chaining\n * @fires set\n */\nOO.ui.StackLayout.prototype.removeItems = function ( items ) {\n\t// Mixin method\n\tOO.ui.mixin.GroupElement.prototype.removeItems.call( this, items );\n\n\tif ( items.indexOf( this.currentItem ) !== -1 ) {\n\t\tif ( this.items.length ) {\n\t\t\tthis.setItem( this.items[ 0 ] );\n\t\t} else {\n\t\t\tthis.unsetCurrentItem();\n\t\t}\n\t}\n\n\treturn this;\n};\n\n/**\n * Clear all panels from the stack layout.\n *\n * Cleared panels are detached from the DOM, not removed, so that they may be reused. To remove only\n * a subset of panels, use the #removeItems method.\n *\n * @chainable\n * @return {OO.ui.StackLayout} The layout, for chaining\n * @fires set\n */\nOO.ui.StackLayout.prototype.clearItems = function () {\n\tthis.unsetCurrentItem();\n\tOO.ui.mixin.GroupElement.prototype.clearItems.call( this );\n\n\treturn this;\n};\n\n/**\n * Show the specified panel.\n *\n * If another panel is currently displayed, it will be hidden.\n *\n * @param {OO.ui.Layout} item Panel to show\n * @chainable\n * @return {OO.ui.StackLayout} The layout, for chaining\n * @fires set\n */\nOO.ui.StackLayout.prototype.setItem = function ( item ) {\n\tif ( item !== this.currentItem ) {\n\t\tthis.updateHiddenState( this.items, item );\n\n\t\tif ( this.items.indexOf( item ) !== -1 ) {\n\t\t\tthis.currentItem = item;\n\t\t\tthis.emit( 'set', item );\n\t\t} else {\n\t\t\tthis.unsetCurrentItem();\n\t\t}\n\t}\n\n\treturn this;\n};\n\n/**\n * Reset the scroll offset of all panels, or the container if continuous\n *\n * @inheritdoc\n */\nOO.ui.StackLayout.prototype.resetScroll = function () {\n\tif ( this.continuous ) {\n\t\t// Parent method\n\t\treturn OO.ui.StackLayout.parent.prototype.resetScroll.call( this );\n\t}\n\t// Reset each panel\n\tthis.getItems().forEach( function ( panel ) {\n\t\tvar hidden = panel.$element.hasClass( 'oo-ui-element-hidden' );\n\t\t// Scroll can only be reset when panel is visible\n\t\tpanel.$element.removeClass( 'oo-ui-element-hidden' );\n\t\tpanel.resetScroll();\n\t\tif ( hidden ) {\n\t\t\tpanel.$element.addClass( 'oo-ui-element-hidden' );\n\t\t}\n\t} );\n\n\treturn this;\n};\n\n/**\n * Update the visibility of all items in case of non-continuous view.\n *\n * Ensure all items are hidden except for the selected one.\n * This method does nothing when the stack is continuous.\n *\n * @private\n * @param {OO.ui.Layout[]} items Item list iterate over\n * @param {OO.ui.Layout} [selectedItem] Selected item to show\n */\nOO.ui.StackLayout.prototype.updateHiddenState = function ( items, selectedItem ) {\n\tvar i, len;\n\n\tif ( !this.continuous ) {\n\t\tfor ( i = 0, len = items.length; i < len; i++ ) {\n\t\t\tif ( !selectedItem || selectedItem !== items[ i ] ) {\n\t\t\t\titems[ i ].$element.addClass( 'oo-ui-element-hidden' );\n\t\t\t\titems[ i ].$element.attr( 'aria-hidden', 'true' );\n\t\t\t}\n\t\t}\n\t\tif ( selectedItem ) {\n\t\t\tselectedItem.$element.removeClass( 'oo-ui-element-hidden' );\n\t\t\tselectedItem.$element.removeAttr( 'aria-hidden' );\n\t\t}\n\t}\n};\n","/**\n * MenuLayouts combine a menu and a content {@link OO.ui.PanelLayout panel}. The menu is positioned\n * relative to the content (after, before, top, or bottom) and its size is customized with the\n * #menuSize config. The content area will fill all remaining space.\n *\n *     @example\n *     var menuLayout,\n *         menuPanel = new OO.ui.PanelLayout( {\n *             padded: true,\n *             expanded: true,\n *             scrollable: true\n *         } ),\n *         contentPanel = new OO.ui.PanelLayout( {\n *             padded: true,\n *             expanded: true,\n *             scrollable: true\n *         } ),\n *         select = new OO.ui.SelectWidget( {\n *             items: [\n *                 new OO.ui.OptionWidget( {\n *                     data: 'before',\n *                     label: 'Before'\n *                 } ),\n *                 new OO.ui.OptionWidget( {\n *                     data: 'after',\n *                     label: 'After'\n *                 } ),\n *                 new OO.ui.OptionWidget( {\n *                     data: 'top',\n *                     label: 'Top'\n *                 } ),\n *                 new OO.ui.OptionWidget( {\n *                     data: 'bottom',\n *                     label: 'Bottom'\n *                 } )\n *              ]\n *         } ).on( 'select', function ( item ) {\n *            menuLayout.setMenuPosition( item.getData() );\n *         } );\n *\n *     menuLayout = new OO.ui.MenuLayout( {\n *         position: 'top',\n *         menuPanel: menuPanel,\n *         contentPanel: contentPanel\n *     } );\n *     menuLayout.$menu.append(\n *         menuPanel.$element.append( '<b>Menu panel</b>', select.$element );\n *     );\n *     menuLayout.$content.append(\n *         contentPanel.$element.append(\n *             '<b>Content panel</b>',\n *             '<p>Note that the menu is positioned relative to the content panel: ' +\n *             'top, bottom, after, before.</p>'\n *          );\n *     );\n *     $( document.body ).append( menuLayout.$element );\n *\n * If menu size needs to be overridden, it can be accomplished using CSS similar to the snippet\n * below. MenuLayout's CSS will override the appropriate values with 'auto' or '0' to display the\n * menu correctly. If `menuPosition` is known beforehand, CSS rules corresponding to other positions\n * may be omitted.\n *\n *     .oo-ui-menuLayout-menu {\n *         width: 200px;\n *         height: 200px;\n *     }\n *\n *     .oo-ui-menuLayout-content {\n *         top: 200px;\n *         left: 200px;\n *         right: 200px;\n *         bottom: 200px;\n *     }\n *\n * @class\n * @extends OO.ui.Layout\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {OO.ui.PanelLayout} [menuPanel] Menu panel\n * @cfg {OO.ui.PanelLayout} [contentPanel] Content panel\n * @cfg {boolean} [expanded=true] Expand the layout to fill the entire parent element.\n * @cfg {boolean} [showMenu=true] Show menu\n * @cfg {string} [menuPosition='before'] Position of menu: `top`, `after`, `bottom` or `before`\n */\nOO.ui.MenuLayout = function OoUiMenuLayout( config ) {\n\t// Configuration initialization\n\tconfig = $.extend( {\n\t\texpanded: true,\n\t\tshowMenu: true,\n\t\tmenuPosition: 'before'\n\t}, config );\n\n\t// Parent constructor\n\tOO.ui.MenuLayout.parent.call( this, config );\n\n\tthis.menuPanel = null;\n\tthis.contentPanel = null;\n\tthis.expanded = !!config.expanded;\n\t/**\n\t * Menu DOM node\n\t *\n\t * @property {jQuery}\n\t */\n\tthis.$menu = $( '<div>' );\n\t/**\n\t * Content DOM node\n\t *\n\t * @property {jQuery}\n\t */\n\tthis.$content = $( '<div>' );\n\n\t// Initialization\n\tthis.$menu.addClass( 'oo-ui-menuLayout-menu' );\n\tthis.$content.addClass( 'oo-ui-menuLayout-content' );\n\tthis.$element.addClass( 'oo-ui-menuLayout' );\n\tif ( config.expanded ) {\n\t\tthis.$element.addClass( 'oo-ui-menuLayout-expanded' );\n\t} else {\n\t\tthis.$element.addClass( 'oo-ui-menuLayout-static' );\n\t}\n\tif ( config.menuPanel ) {\n\t\tthis.setMenuPanel( config.menuPanel );\n\t}\n\tif ( config.contentPanel ) {\n\t\tthis.setContentPanel( config.contentPanel );\n\t}\n\tthis.setMenuPosition( config.menuPosition );\n\tthis.toggleMenu( config.showMenu );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.MenuLayout, OO.ui.Layout );\n\n/* Methods */\n\n/**\n * Toggle menu.\n *\n * @param {boolean} showMenu Show menu, omit to toggle\n * @chainable\n * @return {OO.ui.MenuLayout} The layout, for chaining\n */\nOO.ui.MenuLayout.prototype.toggleMenu = function ( showMenu ) {\n\tshowMenu = showMenu === undefined ? !this.showMenu : !!showMenu;\n\n\tif ( this.showMenu !== showMenu ) {\n\t\tthis.showMenu = showMenu;\n\t\tthis.$element\n\t\t\t.toggleClass( 'oo-ui-menuLayout-showMenu', this.showMenu )\n\t\t\t.toggleClass( 'oo-ui-menuLayout-hideMenu', !this.showMenu );\n\t\tthis.$menu.attr( 'aria-hidden', this.showMenu ? 'false' : 'true' );\n\t}\n\n\treturn this;\n};\n\n/**\n * Check if menu is visible\n *\n * @return {boolean} Menu is visible\n */\nOO.ui.MenuLayout.prototype.isMenuVisible = function () {\n\treturn this.showMenu;\n};\n\n/**\n * Set menu position.\n *\n * @param {string} position Position of menu, either `top`, `after`, `bottom` or `before`\n * @chainable\n * @return {OO.ui.MenuLayout} The layout, for chaining\n */\nOO.ui.MenuLayout.prototype.setMenuPosition = function ( position ) {\n\tif ( [ 'top', 'bottom', 'before', 'after' ].indexOf( position ) === -1 ) {\n\t\tposition = 'before';\n\t}\n\n\tthis.$element.removeClass( 'oo-ui-menuLayout-' + this.menuPosition );\n\tthis.menuPosition = position;\n\tif ( this.menuPosition === 'top' || this.menuPosition === 'before' ) {\n\t\tthis.$element.append( this.$menu, this.$content );\n\t} else {\n\t\tthis.$element.append( this.$content, this.$menu );\n\t}\n\tthis.$element.addClass( 'oo-ui-menuLayout-' + position );\n\n\treturn this;\n};\n\n/**\n * Get menu position.\n *\n * @return {string} Menu position\n */\nOO.ui.MenuLayout.prototype.getMenuPosition = function () {\n\treturn this.menuPosition;\n};\n\n/**\n * Set the menu panel.\n *\n * @param {OO.ui.PanelLayout} menuPanel Menu panel\n */\nOO.ui.MenuLayout.prototype.setMenuPanel = function ( menuPanel ) {\n\tthis.menuPanel = menuPanel;\n\tthis.$menu.append( this.menuPanel.$element );\n};\n\n/**\n * Set the content panel.\n *\n * @param {OO.ui.PanelLayout} contentPanel Content panel\n */\nOO.ui.MenuLayout.prototype.setContentPanel = function ( contentPanel ) {\n\tthis.contentPanel = contentPanel;\n\tthis.$content.append( this.contentPanel.$element );\n};\n\n/**\n * Clear the menu panel.\n */\nOO.ui.MenuLayout.prototype.clearMenuPanel = function () {\n\tthis.menuPanel = null;\n\tthis.$menu.empty();\n};\n\n/**\n * Clear the content panel.\n */\nOO.ui.MenuLayout.prototype.clearContentPanel = function () {\n\tthis.contentPanel = null;\n\tthis.$content.empty();\n};\n\n/**\n * Reset the scroll offset of all panels and the tab select widget\n *\n * @inheritdoc\n */\nOO.ui.MenuLayout.prototype.resetScroll = function () {\n\tif ( this.menuPanel ) {\n\t\tthis.menuPanel.resetScroll();\n\t}\n\tif ( this.contentPanel ) {\n\t\tthis.contentPanel.resetScroll();\n\t}\n\n\treturn this;\n};\n","/**\n * BookletLayouts contain {@link OO.ui.PageLayout page layouts} as well as\n * an {@link OO.ui.OutlineSelectWidget outline} that allows users to easily navigate\n * through the pages and select which one to display. By default, only one page is\n * displayed at a time and the outline is hidden. When a user navigates to a new page,\n * the booklet layout automatically focuses on the first focusable element, unless the\n * default setting is changed. Optionally, booklets can be configured to show\n * {@link OO.ui.OutlineControlsWidget controls} for adding, moving, and removing items.\n *\n *     @example\n *     // Example of a BookletLayout that contains two PageLayouts.\n *\n *     function PageOneLayout( name, config ) {\n *         PageOneLayout.parent.call( this, name, config );\n *         this.$element.append( '<p>First page</p><p>(This booklet has an outline, displayed on ' +\n *         'the left)</p>' );\n *     }\n *     OO.inheritClass( PageOneLayout, OO.ui.PageLayout );\n *     PageOneLayout.prototype.setupOutlineItem = function () {\n *         this.outlineItem.setLabel( 'Page One' );\n *     };\n *\n *     function PageTwoLayout( name, config ) {\n *         PageTwoLayout.parent.call( this, name, config );\n *         this.$element.append( '<p>Second page</p>' );\n *     }\n *     OO.inheritClass( PageTwoLayout, OO.ui.PageLayout );\n *     PageTwoLayout.prototype.setupOutlineItem = function () {\n *         this.outlineItem.setLabel( 'Page Two' );\n *     };\n *\n *     var page1 = new PageOneLayout( 'one' ),\n *         page2 = new PageTwoLayout( 'two' );\n *\n *     var booklet = new OO.ui.BookletLayout( {\n *         outlined: true\n *     } );\n *\n *     booklet.addPages( [ page1, page2 ] );\n *     $( document.body ).append( booklet.$element );\n *\n * @class\n * @extends OO.ui.MenuLayout\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [continuous=false] Show all pages, one after another\n * @cfg {boolean} [autoFocus=true] Focus on the first focusable element when a new page is\n *  displayed. Disabled on mobile.\n * @cfg {boolean} [outlined=false] Show the outline. The outline is used to navigate through the\n *  pages of the booklet.\n * @cfg {boolean} [editable=false] Show controls for adding, removing and reordering pages.\n */\nOO.ui.BookletLayout = function OoUiBookletLayout( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.BookletLayout.parent.call( this, config );\n\n\t// Properties\n\tthis.currentPageName = null;\n\tthis.pages = {};\n\tthis.ignoreFocus = false;\n\tthis.stackLayout = new OO.ui.StackLayout( {\n\t\tcontinuous: !!config.continuous,\n\t\texpanded: this.expanded\n\t} );\n\tthis.setContentPanel( this.stackLayout );\n\tthis.autoFocus = config.autoFocus === undefined || !!config.autoFocus;\n\tthis.outlineVisible = false;\n\tthis.outlined = !!config.outlined;\n\tif ( this.outlined ) {\n\t\tthis.editable = !!config.editable;\n\t\tthis.outlineControlsWidget = null;\n\t\tthis.outlineSelectWidget = new OO.ui.OutlineSelectWidget();\n\t\tthis.outlinePanel = new OO.ui.PanelLayout( {\n\t\t\texpanded: this.expanded,\n\t\t\tscrollable: true\n\t\t} );\n\t\tthis.setMenuPanel( this.outlinePanel );\n\t\tthis.outlineVisible = true;\n\t\tif ( this.editable ) {\n\t\t\tthis.outlineControlsWidget = new OO.ui.OutlineControlsWidget(\n\t\t\t\tthis.outlineSelectWidget\n\t\t\t);\n\t\t}\n\t}\n\tthis.toggleMenu( this.outlined );\n\n\t// Events\n\tthis.stackLayout.connect( this, {\n\t\tset: 'onStackLayoutSet'\n\t} );\n\tif ( this.outlined ) {\n\t\tthis.outlineSelectWidget.connect( this, {\n\t\t\tselect: 'onOutlineSelectWidgetSelect'\n\t\t} );\n\t\tthis.scrolling = false;\n\t\tthis.stackLayout.connect( this, {\n\t\t\tvisibleItemChange: 'onStackLayoutVisibleItemChange'\n\t\t} );\n\t}\n\tif ( this.autoFocus ) {\n\t\t// Event 'focus' does not bubble, but 'focusin' does\n\t\tthis.stackLayout.$element.on( 'focusin', this.onStackLayoutFocus.bind( this ) );\n\t}\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-bookletLayout' );\n\tthis.stackLayout.$element.addClass( 'oo-ui-bookletLayout-stackLayout' );\n\tif ( this.outlined ) {\n\t\tthis.outlinePanel.$element\n\t\t\t.addClass( 'oo-ui-bookletLayout-outlinePanel' )\n\t\t\t.append( this.outlineSelectWidget.$element );\n\t\tif ( this.editable ) {\n\t\t\tthis.outlinePanel.$element\n\t\t\t\t.addClass( 'oo-ui-bookletLayout-outlinePanel-editable' )\n\t\t\t\t.append( this.outlineControlsWidget.$element );\n\t\t}\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.BookletLayout, OO.ui.MenuLayout );\n\n/* Events */\n\n/**\n * A 'set' event is emitted when a page is {@link #setPage set} to be displayed by the\n * booklet layout.\n * @event set\n * @param {OO.ui.PageLayout} page Current page\n */\n\n/**\n * An 'add' event is emitted when pages are {@link #addPages added} to the booklet layout.\n *\n * @event add\n * @param {OO.ui.PageLayout[]} page Added pages\n * @param {number} index Index pages were added at\n */\n\n/**\n * A 'remove' event is emitted when pages are {@link #clearPages cleared} or\n * {@link #removePages removed} from the booklet.\n *\n * @event remove\n * @param {OO.ui.PageLayout[]} pages Removed pages\n */\n\n/* Methods */\n\n/**\n * Handle stack layout focus.\n *\n * @private\n * @param {jQuery.Event} e Focusin event\n */\nOO.ui.BookletLayout.prototype.onStackLayoutFocus = function ( e ) {\n\tvar name, $target;\n\n\t// Find the page that an element was focused within\n\t$target = $( e.target ).closest( '.oo-ui-pageLayout' );\n\tfor ( name in this.pages ) {\n\t\t// Check for page match, exclude current page to find only page changes\n\t\tif ( this.pages[ name ].$element[ 0 ] === $target[ 0 ] && name !== this.currentPageName ) {\n\t\t\tthis.setPage( name );\n\t\t\tbreak;\n\t\t}\n\t}\n};\n\n/**\n * Handle visibleItemChange events from the stackLayout\n *\n * The next visible page is set as the current page by selecting it\n * in the outline\n *\n * @param {OO.ui.PageLayout} page The next visible page in the layout\n */\nOO.ui.BookletLayout.prototype.onStackLayoutVisibleItemChange = function ( page ) {\n\t// Set a flag to so that the resulting call to #onStackLayoutSet doesn't\n\t// try and scroll the item into view again.\n\tthis.scrolling = true;\n\tthis.outlineSelectWidget.selectItemByData( page.getName() );\n\tthis.scrolling = false;\n};\n\n/**\n * Handle stack layout set events.\n *\n * @private\n * @param {OO.ui.PanelLayout|null} page The page panel that is now the current panel\n */\nOO.ui.BookletLayout.prototype.onStackLayoutSet = function ( page ) {\n\tvar promise, layout = this;\n\t// If everything is unselected, do nothing\n\tif ( !page ) {\n\t\treturn;\n\t}\n\t// For continuous BookletLayouts, scroll the selected page into view first\n\tif ( this.stackLayout.continuous && !this.scrolling ) {\n\t\tpromise = page.scrollElementIntoView();\n\t} else {\n\t\tpromise = $.Deferred().resolve();\n\t}\n\t// Focus the first element on the newly selected panel.\n\t// Don't focus if the page was set by scrolling.\n\tif ( this.autoFocus && !OO.ui.isMobile() && !this.scrolling ) {\n\t\tpromise.done( function () {\n\t\t\tlayout.focus();\n\t\t} );\n\t}\n};\n\n/**\n * Focus the first input in the current page.\n *\n * If no page is selected, the first selectable page will be selected.\n * If the focus is already in an element on the current page, nothing will happen.\n *\n * @param {number} [itemIndex] A specific item to focus on\n */\nOO.ui.BookletLayout.prototype.focus = function ( itemIndex ) {\n\tvar page,\n\t\titems = this.stackLayout.getItems();\n\n\tif ( itemIndex !== undefined && items[ itemIndex ] ) {\n\t\tpage = items[ itemIndex ];\n\t} else {\n\t\tpage = this.stackLayout.getCurrentItem();\n\t}\n\n\tif ( !page && this.outlined ) {\n\t\tthis.selectFirstSelectablePage();\n\t\tpage = this.stackLayout.getCurrentItem();\n\t}\n\tif ( !page ) {\n\t\treturn;\n\t}\n\t// Only change the focus if is not already in the current page\n\tif ( !OO.ui.contains( page.$element[ 0 ], this.getElementDocument().activeElement, true ) ) {\n\t\tpage.focus();\n\t}\n};\n\n/**\n * Find the first focusable input in the booklet layout and focus\n * on it.\n */\nOO.ui.BookletLayout.prototype.focusFirstFocusable = function () {\n\tOO.ui.findFocusable( this.stackLayout.$element ).focus();\n};\n\n/**\n * Handle outline widget select events.\n *\n * @private\n * @param {OO.ui.OptionWidget|null} item Selected item\n */\nOO.ui.BookletLayout.prototype.onOutlineSelectWidgetSelect = function ( item ) {\n\tif ( item ) {\n\t\tthis.setPage( item.getData() );\n\t}\n};\n\n/**\n * Check if booklet has an outline.\n *\n * @return {boolean} Booklet has an outline\n */\nOO.ui.BookletLayout.prototype.isOutlined = function () {\n\treturn this.outlined;\n};\n\n/**\n * Check if booklet has editing controls.\n *\n * @return {boolean} Booklet is editable\n */\nOO.ui.BookletLayout.prototype.isEditable = function () {\n\treturn this.editable;\n};\n\n/**\n * Check if booklet has a visible outline.\n *\n * @return {boolean} Outline is visible\n */\nOO.ui.BookletLayout.prototype.isOutlineVisible = function () {\n\treturn this.outlined && this.outlineVisible;\n};\n\n/**\n * Hide or show the outline.\n *\n * @param {boolean} [show] Show outline, omit to invert current state\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.BookletLayout.prototype.toggleOutline = function ( show ) {\n\tvar booklet = this;\n\n\tif ( this.outlined ) {\n\t\tshow = show === undefined ? !this.outlineVisible : !!show;\n\t\tthis.outlineVisible = show;\n\t\tthis.toggleMenu( show );\n\t\tif ( show && this.editable ) {\n\t\t\t// HACK: Kill dumb scrollbars when the sidebar stops animating, see T161798.\n\t\t\t// Only necessary when outline controls are present, delay matches transition on\n\t\t\t// `.oo-ui-menuLayout-menu`.\n\t\t\tsetTimeout( function () {\n\t\t\t\tOO.ui.Element.static.reconsiderScrollbars( booklet.outlinePanel.$element[ 0 ] );\n\t\t\t}, OO.ui.theme.getDialogTransitionDuration() );\n\t\t}\n\t}\n\n\treturn this;\n};\n\n/**\n * Find the page closest to the specified page.\n *\n * @param {OO.ui.PageLayout} page Page to use as a reference point\n * @return {OO.ui.PageLayout|null} Page closest to the specified page\n */\nOO.ui.BookletLayout.prototype.findClosestPage = function ( page ) {\n\tvar next, prev, level,\n\t\tpages = this.stackLayout.getItems(),\n\t\tindex = pages.indexOf( page );\n\n\tif ( index !== -1 ) {\n\t\tnext = pages[ index + 1 ];\n\t\tprev = pages[ index - 1 ];\n\t\t// Prefer adjacent pages at the same level\n\t\tif ( this.outlined ) {\n\t\t\tlevel = this.outlineSelectWidget.findItemFromData( page.getName() ).getLevel();\n\t\t\tif (\n\t\t\t\tprev &&\n\t\t\t\tlevel === this.outlineSelectWidget.findItemFromData( prev.getName() ).getLevel()\n\t\t\t) {\n\t\t\t\treturn prev;\n\t\t\t}\n\t\t\tif (\n\t\t\t\tnext &&\n\t\t\t\tlevel === this.outlineSelectWidget.findItemFromData( next.getName() ).getLevel()\n\t\t\t) {\n\t\t\t\treturn next;\n\t\t\t}\n\t\t}\n\t}\n\treturn prev || next || null;\n};\n\n/**\n * Get the outline widget.\n *\n * If the booklet is not outlined, the method will return `null`.\n *\n * @return {OO.ui.OutlineSelectWidget|null} Outline widget, or null if the booklet is not outlined\n */\nOO.ui.BookletLayout.prototype.getOutline = function () {\n\treturn this.outlineSelectWidget;\n};\n\n/**\n * Get the outline controls widget.\n *\n * If the outline is not editable, the method will return `null`.\n *\n * @return {OO.ui.OutlineControlsWidget|null} The outline controls widget.\n */\nOO.ui.BookletLayout.prototype.getOutlineControls = function () {\n\treturn this.outlineControlsWidget;\n};\n\n/**\n * Get a page by its symbolic name.\n *\n * @param {string} name Symbolic name of page\n * @return {OO.ui.PageLayout|undefined} Page, if found\n */\nOO.ui.BookletLayout.prototype.getPage = function ( name ) {\n\treturn this.pages[ name ];\n};\n\n/**\n * Get the current page.\n *\n * @return {OO.ui.PageLayout|undefined} Current page, if found\n */\nOO.ui.BookletLayout.prototype.getCurrentPage = function () {\n\tvar name = this.getCurrentPageName();\n\treturn name ? this.getPage( name ) : undefined;\n};\n\n/**\n * Get the symbolic name of the current page.\n *\n * @return {string|null} Symbolic name of the current page\n */\nOO.ui.BookletLayout.prototype.getCurrentPageName = function () {\n\treturn this.currentPageName;\n};\n\n/**\n * Add pages to the booklet layout\n *\n * When pages are added with the same names as existing pages, the existing pages will be\n * automatically removed before the new pages are added.\n *\n * @param {OO.ui.PageLayout[]} pages Pages to add\n * @param {number} index Index of the insertion point\n * @fires add\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.BookletLayout.prototype.addPages = function ( pages, index ) {\n\tvar i, len, name, page, item, currentIndex,\n\t\tstackLayoutPages = this.stackLayout.getItems(),\n\t\tremove = [],\n\t\titems = [];\n\n\t// Remove pages with same names\n\tfor ( i = 0, len = pages.length; i < len; i++ ) {\n\t\tpage = pages[ i ];\n\t\tname = page.getName();\n\n\t\tif ( Object.prototype.hasOwnProperty.call( this.pages, name ) ) {\n\t\t\t// Correct the insertion index\n\t\t\tcurrentIndex = stackLayoutPages.indexOf( this.pages[ name ] );\n\t\t\tif ( currentIndex !== -1 && currentIndex + 1 < index ) {\n\t\t\t\tindex--;\n\t\t\t}\n\t\t\tremove.push( this.pages[ name ] );\n\t\t}\n\t}\n\tif ( remove.length ) {\n\t\tthis.removePages( remove );\n\t}\n\n\t// Add new pages\n\tfor ( i = 0, len = pages.length; i < len; i++ ) {\n\t\tpage = pages[ i ];\n\t\tname = page.getName();\n\t\tthis.pages[ page.getName() ] = page;\n\t\tif ( this.outlined ) {\n\t\t\titem = new OO.ui.OutlineOptionWidget( { data: name } );\n\t\t\tpage.setOutlineItem( item );\n\t\t\titems.push( item );\n\t\t}\n\t}\n\n\tif ( this.outlined && items.length ) {\n\t\tthis.outlineSelectWidget.addItems( items, index );\n\t\tthis.selectFirstSelectablePage();\n\t}\n\tthis.stackLayout.addItems( pages, index );\n\tthis.emit( 'add', pages, index );\n\n\treturn this;\n};\n\n/**\n * Remove the specified pages from the booklet layout.\n *\n * To remove all pages from the booklet, you may wish to use the #clearPages method instead.\n *\n * @param {OO.ui.PageLayout[]} pages An array of pages to remove\n * @fires remove\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.BookletLayout.prototype.removePages = function ( pages ) {\n\tvar i, len, name, page,\n\t\titems = [];\n\n\tfor ( i = 0, len = pages.length; i < len; i++ ) {\n\t\tpage = pages[ i ];\n\t\tname = page.getName();\n\t\tdelete this.pages[ name ];\n\t\tif ( this.outlined ) {\n\t\t\titems.push( this.outlineSelectWidget.findItemFromData( name ) );\n\t\t\tpage.setOutlineItem( null );\n\t\t}\n\t}\n\tif ( this.outlined && items.length ) {\n\t\tthis.outlineSelectWidget.removeItems( items );\n\t\tthis.selectFirstSelectablePage();\n\t}\n\tthis.stackLayout.removeItems( pages );\n\tthis.emit( 'remove', pages );\n\n\treturn this;\n};\n\n/**\n * Clear all pages from the booklet layout.\n *\n * To remove only a subset of pages from the booklet, use the #removePages method.\n *\n * @fires remove\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.BookletLayout.prototype.clearPages = function () {\n\tvar i, len,\n\t\tpages = this.stackLayout.getItems();\n\n\tthis.pages = {};\n\tthis.currentPageName = null;\n\tif ( this.outlined ) {\n\t\tthis.outlineSelectWidget.clearItems();\n\t\tfor ( i = 0, len = pages.length; i < len; i++ ) {\n\t\t\tpages[ i ].setOutlineItem( null );\n\t\t}\n\t}\n\tthis.stackLayout.clearItems();\n\n\tthis.emit( 'remove', pages );\n\n\treturn this;\n};\n\n/**\n * Set the current page by symbolic name.\n *\n * @fires set\n * @param {string} name Symbolic name of page\n */\nOO.ui.BookletLayout.prototype.setPage = function ( name ) {\n\tvar selectedItem,\n\t\t$focused,\n\t\tpage = this.pages[ name ],\n\t\tpreviousPage = this.currentPageName && this.pages[ this.currentPageName ];\n\n\tif ( name !== this.currentPageName ) {\n\t\tif ( this.outlined ) {\n\t\t\tselectedItem = this.outlineSelectWidget.findSelectedItem();\n\t\t\tif ( selectedItem && selectedItem.getData() !== name ) {\n\t\t\t\tthis.outlineSelectWidget.selectItemByData( name );\n\t\t\t}\n\t\t}\n\t\tif ( page ) {\n\t\t\tif ( previousPage ) {\n\t\t\t\tpreviousPage.setActive( false );\n\t\t\t\t// Blur anything focused if the next page doesn't have anything focusable.\n\t\t\t\t// This is not needed if the next page has something focusable (because once it is\n\t\t\t\t// focused this blur happens automatically). If the layout is non-continuous, this\n\t\t\t\t// check is meaningless because the next page is not visible yet and thus can't\n\t\t\t\t// hold focus.\n\t\t\t\tif (\n\t\t\t\t\tthis.autoFocus &&\n\t\t\t\t\t!OO.ui.isMobile() &&\n\t\t\t\t\tthis.stackLayout.continuous &&\n\t\t\t\t\tOO.ui.findFocusable( page.$element ).length !== 0\n\t\t\t\t) {\n\t\t\t\t\t$focused = previousPage.$element.find( ':focus' );\n\t\t\t\t\tif ( $focused.length ) {\n\t\t\t\t\t\t$focused[ 0 ].blur();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.currentPageName = name;\n\t\t\tpage.setActive( true );\n\t\t\tthis.stackLayout.setItem( page );\n\t\t\tif ( !this.stackLayout.continuous && previousPage ) {\n\t\t\t\t// This should not be necessary, since any inputs on the previous page should have\n\t\t\t\t// been blurred when it was hidden, but browsers are not very consistent about\n\t\t\t\t// this.\n\t\t\t\t$focused = previousPage.$element.find( ':focus' );\n\t\t\t\tif ( $focused.length ) {\n\t\t\t\t\t$focused[ 0 ].blur();\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.emit( 'set', page );\n\t\t}\n\t}\n};\n\n/**\n * For outlined-continuous booklets, also reset the outlineSelectWidget to the first item.\n *\n * @inheritdoc\n */\nOO.ui.BookletLayout.prototype.resetScroll = function () {\n\t// Parent method\n\tOO.ui.BookletLayout.parent.prototype.resetScroll.call( this );\n\n\tif (\n\t\tthis.outlined &&\n\t\tthis.stackLayout.continuous &&\n\t\tthis.outlineSelectWidget.findFirstSelectableItem()\n\t) {\n\t\tthis.scrolling = true;\n\t\tthis.outlineSelectWidget.selectItem( this.outlineSelectWidget.findFirstSelectableItem() );\n\t\tthis.scrolling = false;\n\t}\n\treturn this;\n};\n\n/**\n * Select the first selectable page.\n *\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.BookletLayout.prototype.selectFirstSelectablePage = function () {\n\tif ( !this.outlineSelectWidget.findSelectedItem() ) {\n\t\tthis.outlineSelectWidget.selectItem( this.outlineSelectWidget.findFirstSelectableItem() );\n\t}\n\n\treturn this;\n};\n","/**\n * IndexLayouts contain {@link OO.ui.TabPanelLayout tab panel layouts} as well as\n * {@link OO.ui.TabSelectWidget tabs} that allow users to easily navigate through the tab panels\n * and select which one to display. By default, only one tab panel is displayed at a time. When a\n * user navigates to a new tab panel, the index layout automatically focuses on the first focusable\n * element, unless the default setting is changed.\n *\n * TODO: This class is similar to BookletLayout, we may want to refactor to reduce duplication\n *\n *     @example\n *     // Example of a IndexLayout that contains two TabPanelLayouts.\n *\n *     function TabPanelOneLayout( name, config ) {\n *         TabPanelOneLayout.parent.call( this, name, config );\n *         this.$element.append( '<p>First tab panel</p>' );\n *     }\n *     OO.inheritClass( TabPanelOneLayout, OO.ui.TabPanelLayout );\n *     TabPanelOneLayout.prototype.setupTabItem = function () {\n *         this.tabItem.setLabel( 'Tab panel one' );\n *     };\n *\n *     var tabPanel1 = new TabPanelOneLayout( 'one' ),\n *         tabPanel2 = new OO.ui.TabPanelLayout( 'two', { label: 'Tab panel two' } );\n *\n *     tabPanel2.$element.append( '<p>Second tab panel</p>' );\n *\n *     var index = new OO.ui.IndexLayout();\n *\n *     index.addTabPanels( [ tabPanel1, tabPanel2 ] );\n *     $( document.body ).append( index.$element );\n *\n * @class\n * @extends OO.ui.MenuLayout\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {OO.ui.StackLayout} [contentPanel] Content stack (see MenuLayout)\n * @cfg {boolean} [continuous=false] Show all tab panels, one after another\n * @cfg {boolean} [autoFocus=true] Focus on the first focusable element when a new tab panel is\n *  displayed. Disabled on mobile.\n */\nOO.ui.IndexLayout = function OoUiIndexLayout( config ) {\n\t// Configuration initialization\n\tconfig = $.extend( {}, config, { menuPosition: 'top' } );\n\n\t// Parent constructor\n\tOO.ui.IndexLayout.parent.call( this, config );\n\n\t// Properties\n\tthis.currentTabPanelName = null;\n\t// Allow infused widgets to pass existing tabPanels\n\tthis.tabPanels = config.tabPanels || {};\n\n\tthis.ignoreFocus = false;\n\tthis.stackLayout = this.contentPanel || new OO.ui.StackLayout( {\n\t\tcontinuous: !!config.continuous,\n\t\texpanded: this.expanded\n\t} );\n\tthis.setContentPanel( this.stackLayout );\n\tthis.autoFocus = config.autoFocus === undefined || !!config.autoFocus;\n\n\t// Allow infused widgets to pass an existing tabSelectWidget\n\tthis.tabSelectWidget = config.tabSelectWidget || new OO.ui.TabSelectWidget();\n\tthis.tabPanel = this.menuPanel || new OO.ui.PanelLayout( {\n\t\texpanded: this.expanded\n\t} );\n\tthis.setMenuPanel( this.tabPanel );\n\n\tthis.toggleMenu( true );\n\n\t// Events\n\tthis.stackLayout.connect( this, {\n\t\tset: 'onStackLayoutSet'\n\t} );\n\tthis.tabSelectWidget.connect( this, {\n\t\tselect: 'onTabSelectWidgetSelect'\n\t} );\n\tif ( this.autoFocus ) {\n\t\t// Event 'focus' does not bubble, but 'focusin' does.\n\t\tthis.stackLayout.$element.on( 'focusin', this.onStackLayoutFocus.bind( this ) );\n\t}\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-indexLayout' );\n\tthis.stackLayout.$element.addClass( 'oo-ui-indexLayout-stackLayout' );\n\tthis.tabPanel.$element\n\t\t.addClass( 'oo-ui-indexLayout-tabPanel' )\n\t\t.append( this.tabSelectWidget.$element );\n\n\tthis.selectFirstSelectableTabPanel();\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.IndexLayout, OO.ui.MenuLayout );\n\n/* Events */\n\n/**\n * A 'set' event is emitted when a tab panel is {@link #setTabPanel set} to be displayed by the\n * index layout.\n *\n * @event set\n * @param {OO.ui.TabPanelLayout} tabPanel Current tab panel\n */\n\n/**\n * An 'add' event is emitted when tab panels are {@link #addTabPanels added} to the index layout.\n *\n * @event add\n * @param {OO.ui.TabPanelLayout[]} tabPanel Added tab panels\n * @param {number} index Index tab panels were added at\n */\n\n/**\n * A 'remove' event is emitted when tab panels are {@link #clearTabPanels cleared} or\n * {@link #removeTabPanels removed} from the index.\n *\n * @event remove\n * @param {OO.ui.TabPanelLayout[]} tabPanel Removed tab panels\n */\n\n/* Methods */\n\n/**\n * Handle stack layout focus.\n *\n * @private\n * @param {jQuery.Event} e Focusing event\n */\nOO.ui.IndexLayout.prototype.onStackLayoutFocus = function ( e ) {\n\tvar name, $target;\n\n\t// Find the tab panel that an element was focused within\n\t$target = $( e.target ).closest( '.oo-ui-tabPanelLayout' );\n\tfor ( name in this.tabPanels ) {\n\t\t// Check for tab panel match, exclude current tab panel to find only tab panel changes\n\t\tif ( this.tabPanels[ name ].$element[ 0 ] === $target[ 0 ] &&\n\t\t\t\tname !== this.currentTabPanelName ) {\n\t\t\tthis.setTabPanel( name );\n\t\t\tbreak;\n\t\t}\n\t}\n};\n\n/**\n * Handle stack layout set events.\n *\n * @private\n * @param {OO.ui.PanelLayout|null} tabPanel The tab panel that is now the current panel\n */\nOO.ui.IndexLayout.prototype.onStackLayoutSet = function ( tabPanel ) {\n\t// If everything is unselected, do nothing\n\tif ( !tabPanel ) {\n\t\treturn;\n\t}\n\t// Focus the first element on the newly selected panel\n\tif ( this.autoFocus && !OO.ui.isMobile() ) {\n\t\tthis.focus();\n\t}\n};\n\n/**\n * Focus the first input in the current tab panel.\n *\n * If no tab panel is selected, the first selectable tab panel will be selected.\n * If the focus is already in an element on the current tab panel, nothing will happen.\n *\n * @param {number} [itemIndex] A specific item to focus on\n */\nOO.ui.IndexLayout.prototype.focus = function ( itemIndex ) {\n\tvar tabPanel,\n\t\titems = this.stackLayout.getItems();\n\n\tif ( itemIndex !== undefined && items[ itemIndex ] ) {\n\t\ttabPanel = items[ itemIndex ];\n\t} else {\n\t\ttabPanel = this.stackLayout.getCurrentItem();\n\t}\n\n\tif ( !tabPanel ) {\n\t\tthis.selectFirstSelectableTabPanel();\n\t\ttabPanel = this.stackLayout.getCurrentItem();\n\t}\n\tif ( !tabPanel ) {\n\t\treturn;\n\t}\n\t// Only change the focus if is not already in the current page\n\tif ( !OO.ui.contains(\n\t\ttabPanel.$element[ 0 ],\n\t\tthis.getElementDocument().activeElement,\n\t\ttrue\n\t) ) {\n\t\ttabPanel.focus();\n\t}\n};\n\n/**\n * Find the first focusable input in the index layout and focus\n * on it.\n */\nOO.ui.IndexLayout.prototype.focusFirstFocusable = function () {\n\tOO.ui.findFocusable( this.stackLayout.$element ).focus();\n};\n\n/**\n * Handle tab widget select events.\n *\n * @private\n * @param {OO.ui.OptionWidget|null} item Selected item\n */\nOO.ui.IndexLayout.prototype.onTabSelectWidgetSelect = function ( item ) {\n\tif ( item ) {\n\t\tthis.setTabPanel( item.getData() );\n\t}\n};\n\n/**\n * Get the tab panel closest to the specified tab panel.\n *\n * @param {OO.ui.TabPanelLayout} tabPanel Tab panel to use as a reference point\n * @return {OO.ui.TabPanelLayout|null} Tab panel closest to the specified\n */\nOO.ui.IndexLayout.prototype.getClosestTabPanel = function ( tabPanel ) {\n\tvar next, prev, level,\n\t\ttabPanels = this.stackLayout.getItems(),\n\t\tindex = tabPanels.indexOf( tabPanel );\n\n\tif ( index !== -1 ) {\n\t\tnext = tabPanels[ index + 1 ];\n\t\tprev = tabPanels[ index - 1 ];\n\t\t// Prefer adjacent tab panels at the same level\n\t\tlevel = this.tabSelectWidget.findItemFromData( tabPanel.getName() ).getLevel();\n\t\tif (\n\t\t\tprev &&\n\t\t\tlevel === this.tabSelectWidget.findItemFromData( prev.getName() ).getLevel()\n\t\t) {\n\t\t\treturn prev;\n\t\t}\n\t\tif (\n\t\t\tnext &&\n\t\t\tlevel === this.tabSelectWidget.findItemFromData( next.getName() ).getLevel()\n\t\t) {\n\t\t\treturn next;\n\t\t}\n\t}\n\treturn prev || next || null;\n};\n\n/**\n * Get the tabs widget.\n *\n * @return {OO.ui.TabSelectWidget} Tabs widget\n */\nOO.ui.IndexLayout.prototype.getTabs = function () {\n\treturn this.tabSelectWidget;\n};\n\n/**\n * Get a tab panel by its symbolic name.\n *\n * @param {string} name Symbolic name of tab panel\n * @return {OO.ui.TabPanelLayout|undefined} Tab panel, if found\n */\nOO.ui.IndexLayout.prototype.getTabPanel = function ( name ) {\n\treturn this.tabPanels[ name ];\n};\n\n/**\n * Get the current tab panel.\n *\n * @return {OO.ui.TabPanelLayout|undefined} Current tab panel, if found\n */\nOO.ui.IndexLayout.prototype.getCurrentTabPanel = function () {\n\tvar name = this.getCurrentTabPanelName();\n\treturn name ? this.getTabPanel( name ) : undefined;\n};\n\n/**\n * Get the symbolic name of the current tab panel.\n *\n * @return {string|null} Symbolic name of the current tab panel\n */\nOO.ui.IndexLayout.prototype.getCurrentTabPanelName = function () {\n\treturn this.currentTabPanelName;\n};\n\n/**\n * Add tab panels to the index layout.\n *\n * When tab panels are added with the same names as existing tab panels, the existing tab panels\n * will be automatically removed before the new tab panels are added.\n *\n * @param {OO.ui.TabPanelLayout[]} tabPanels Tab panels to add\n * @param {number} index Index of the insertion point\n * @fires add\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.IndexLayout.prototype.addTabPanels = function ( tabPanels, index ) {\n\tvar i, len, name, tabPanel, item, currentIndex,\n\t\tstackLayoutTabPanels = this.stackLayout.getItems(),\n\t\tremove = [],\n\t\titems = [];\n\n\t// Remove tab panels with same names\n\tfor ( i = 0, len = tabPanels.length; i < len; i++ ) {\n\t\ttabPanel = tabPanels[ i ];\n\t\tname = tabPanel.getName();\n\n\t\tif ( Object.prototype.hasOwnProperty.call( this.tabPanels, name ) ) {\n\t\t\t// Correct the insertion index\n\t\t\tcurrentIndex = stackLayoutTabPanels.indexOf( this.tabPanels[ name ] );\n\t\t\tif ( currentIndex !== -1 && currentIndex + 1 < index ) {\n\t\t\t\tindex--;\n\t\t\t}\n\t\t\tremove.push( this.tabPanels[ name ] );\n\t\t}\n\t}\n\tif ( remove.length ) {\n\t\tthis.removeTabPanels( remove );\n\t}\n\n\t// Add new tab panels\n\tfor ( i = 0, len = tabPanels.length; i < len; i++ ) {\n\t\ttabPanel = tabPanels[ i ];\n\t\tname = tabPanel.getName();\n\t\tthis.tabPanels[ tabPanel.getName() ] = tabPanel;\n\t\titem = new OO.ui.TabOptionWidget( { data: name } );\n\t\ttabPanel.setTabItem( item );\n\t\titems.push( item );\n\t}\n\n\tif ( items.length ) {\n\t\tthis.tabSelectWidget.addItems( items, index );\n\t\tthis.selectFirstSelectableTabPanel();\n\t}\n\tthis.stackLayout.addItems( tabPanels, index );\n\tthis.emit( 'add', tabPanels, index );\n\n\treturn this;\n};\n\n/**\n * Remove the specified tab panels from the index layout.\n *\n * To remove all tab panels from the index, you may wish to use the #clearTabPanels method instead.\n *\n * @param {OO.ui.TabPanelLayout[]} tabPanels An array of tab panels to remove\n * @fires remove\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.IndexLayout.prototype.removeTabPanels = function ( tabPanels ) {\n\tvar i, len, name, tabPanel,\n\t\titems = [];\n\n\tfor ( i = 0, len = tabPanels.length; i < len; i++ ) {\n\t\ttabPanel = tabPanels[ i ];\n\t\tname = tabPanel.getName();\n\t\tdelete this.tabPanels[ name ];\n\t\titems.push( this.tabSelectWidget.findItemFromData( name ) );\n\t\ttabPanel.setTabItem( null );\n\t}\n\tif ( items.length ) {\n\t\tthis.tabSelectWidget.removeItems( items );\n\t\tthis.selectFirstSelectableTabPanel();\n\t}\n\tthis.stackLayout.removeItems( tabPanels );\n\tthis.emit( 'remove', tabPanels );\n\n\treturn this;\n};\n\n/**\n * Clear all tab panels from the index layout.\n *\n * To remove only a subset of tab panels from the index, use the #removeTabPanels method.\n *\n * @fires remove\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.IndexLayout.prototype.clearTabPanels = function () {\n\tvar i, len,\n\t\ttabPanels = this.stackLayout.getItems();\n\n\tthis.tabPanels = {};\n\tthis.currentTabPanelName = null;\n\tthis.tabSelectWidget.clearItems();\n\tfor ( i = 0, len = tabPanels.length; i < len; i++ ) {\n\t\ttabPanels[ i ].setTabItem( null );\n\t}\n\tthis.stackLayout.clearItems();\n\n\tthis.emit( 'remove', tabPanels );\n\n\treturn this;\n};\n\n/**\n * Set the current tab panel by symbolic name.\n *\n * @fires set\n * @param {string} name Symbolic name of tab panel\n */\nOO.ui.IndexLayout.prototype.setTabPanel = function ( name ) {\n\tvar selectedItem,\n\t\t$focused,\n\t\tpreviousTabPanel,\n\t\ttabPanel = this.tabPanels[ name ];\n\n\tif ( name !== this.currentTabPanelName ) {\n\t\tpreviousTabPanel = this.getCurrentTabPanel();\n\t\tselectedItem = this.tabSelectWidget.findSelectedItem();\n\t\tif ( selectedItem && selectedItem.getData() !== name ) {\n\t\t\tthis.tabSelectWidget.selectItemByData( name );\n\t\t}\n\t\tif ( tabPanel ) {\n\t\t\tif ( previousTabPanel ) {\n\t\t\t\tpreviousTabPanel.setActive( false );\n\t\t\t\t// Blur anything focused if the next tab panel doesn't have anything focusable.\n\t\t\t\t// This is not needed if the next tab panel has something focusable (because once\n\t\t\t\t// it is focused this blur happens automatically). If the layout is non-continuous,\n\t\t\t\t// this check is meaningless because the next tab panel is not visible yet and thus\n\t\t\t\t// can't hold focus.\n\t\t\t\tif (\n\t\t\t\t\tthis.autoFocus &&\n\t\t\t\t\t!OO.ui.isMobile() &&\n\t\t\t\t\tthis.stackLayout.continuous &&\n\t\t\t\t\tOO.ui.findFocusable( tabPanel.$element ).length !== 0\n\t\t\t\t) {\n\t\t\t\t\t$focused = previousTabPanel.$element.find( ':focus' );\n\t\t\t\t\tif ( $focused.length ) {\n\t\t\t\t\t\t$focused[ 0 ].blur();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.currentTabPanelName = name;\n\t\t\ttabPanel.setActive( true );\n\t\t\tthis.stackLayout.setItem( tabPanel );\n\t\t\tif ( !this.stackLayout.continuous && previousTabPanel ) {\n\t\t\t\t// This should not be necessary, since any inputs on the previous tab panel should\n\t\t\t\t// have been blurred when it was hidden, but browsers are not very consistent about\n\t\t\t\t// this.\n\t\t\t\t$focused = previousTabPanel.$element.find( ':focus' );\n\t\t\t\tif ( $focused.length ) {\n\t\t\t\t\t$focused[ 0 ].blur();\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.emit( 'set', tabPanel );\n\t\t}\n\t}\n};\n\n/**\n * Select the first selectable tab panel.\n *\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.IndexLayout.prototype.selectFirstSelectableTabPanel = function () {\n\tif ( !this.tabSelectWidget.findSelectedItem() ) {\n\t\tthis.tabSelectWidget.selectItem( this.tabSelectWidget.findFirstSelectableItem() );\n\t}\n\n\treturn this;\n};\n","/**\n * ToggleWidget implements basic behavior of widgets with an on/off state.\n * Please see OO.ui.ToggleButtonWidget and OO.ui.ToggleSwitchWidget for examples.\n *\n * @abstract\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.TitledElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [value=false] The toggle’s initial on/off state.\n *  By default, the toggle is in the 'off' state.\n */\nOO.ui.ToggleWidget = function OoUiToggleWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.ToggleWidget.parent.call( this, config );\n\n\t// Mixin constructor\n\tOO.ui.mixin.TitledElement.call( this, config );\n\n\t// Properties\n\tthis.value = null;\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-toggleWidget' );\n\tthis.setValue( !!config.value );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ToggleWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.ToggleWidget, OO.ui.mixin.TitledElement );\n\n/* Events */\n\n/**\n * @event change\n *\n * A change event is emitted when the on/off state of the toggle changes.\n *\n * @param {boolean} value Value representing the new state of the toggle\n */\n\n/* Methods */\n\n/**\n * Get the value representing the toggle’s state.\n *\n * @return {boolean} The on/off state of the toggle\n */\nOO.ui.ToggleWidget.prototype.getValue = function () {\n\treturn this.value;\n};\n\n/**\n * Set the state of the toggle: `true` for 'on', `false` for 'off'.\n *\n * @param {boolean} value The state of the toggle\n * @fires change\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.ToggleWidget.prototype.setValue = function ( value ) {\n\tvalue = !!value;\n\tif ( this.value !== value ) {\n\t\tthis.value = value;\n\t\tthis.emit( 'change', value );\n\t\tthis.$element.toggleClass( 'oo-ui-toggleWidget-on', value );\n\t\tthis.$element.toggleClass( 'oo-ui-toggleWidget-off', !value );\n\t}\n\treturn this;\n};\n","/**\n * ToggleButtons are buttons that have a state (‘on’ or ‘off’) that is represented by a\n * Boolean value. Like other {@link OO.ui.ButtonWidget buttons}, toggle buttons can be\n * configured with {@link OO.ui.mixin.IconElement icons},\n * {@link OO.ui.mixin.IndicatorElement indicators},\n * {@link OO.ui.mixin.TitledElement titles}, {@link OO.ui.mixin.FlaggedElement styling flags},\n * and {@link OO.ui.mixin.LabelElement labels}. Please see\n * the [OOUI documentation][1] on MediaWiki for more information.\n *\n *     @example\n *     // Toggle buttons in the 'off' and 'on' state.\n *     var toggleButton1 = new OO.ui.ToggleButtonWidget( {\n *             label: 'Toggle Button off'\n *         } ),\n *         toggleButton2 = new OO.ui.ToggleButtonWidget( {\n *             label: 'Toggle Button on',\n *             value: true\n *         } );\n *     // Append the buttons to the DOM.\n *     $( document.body ).append( toggleButton1.$element, toggleButton2.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Buttons_and_Switches#Toggle_buttons\n *\n * @class\n * @extends OO.ui.ToggleWidget\n * @mixins OO.ui.mixin.ButtonElement\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.IndicatorElement\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.FlaggedElement\n * @mixins OO.ui.mixin.TabIndexedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [value=false] The toggle button’s initial on/off\n *  state. By default, the button is in the 'off' state.\n */\nOO.ui.ToggleButtonWidget = function OoUiToggleButtonWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.ToggleButtonWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.ButtonElement.call( this, $.extend( {\n\t\tactive: this.active\n\t}, config ) );\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.IndicatorElement.call( this, config );\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.FlaggedElement.call( this, config );\n\tOO.ui.mixin.TabIndexedElement.call( this, $.extend( {\n\t\t$tabIndexed: this.$button\n\t}, config ) );\n\n\t// Events\n\tthis.connect( this, {\n\t\tclick: 'onAction'\n\t} );\n\n\t// Initialization\n\tthis.$button.append( this.$icon, this.$label, this.$indicator );\n\tthis.$element\n\t\t.addClass( 'oo-ui-toggleButtonWidget' )\n\t\t.append( this.$button );\n\tthis.setTitledElement( this.$button );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ToggleButtonWidget, OO.ui.ToggleWidget );\nOO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.mixin.ButtonElement );\nOO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.mixin.IndicatorElement );\nOO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.mixin.FlaggedElement );\nOO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.mixin.TabIndexedElement );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.ToggleButtonWidget.static.tagName = 'span';\n\n/* Methods */\n\n/**\n * Handle the button action being triggered.\n *\n * @private\n */\nOO.ui.ToggleButtonWidget.prototype.onAction = function () {\n\tthis.setValue( !this.value );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.ToggleButtonWidget.prototype.setValue = function ( value ) {\n\tvalue = !!value;\n\tif ( value !== this.value ) {\n\t\t// Might be called from parent constructor before ButtonElement constructor\n\t\tif ( this.$button ) {\n\t\t\tthis.$button.attr( 'aria-pressed', value.toString() );\n\t\t}\n\t\tthis.setActive( value );\n\t}\n\n\t// Parent method\n\tOO.ui.ToggleButtonWidget.parent.prototype.setValue.call( this, value );\n\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.ToggleButtonWidget.prototype.setButtonElement = function ( $button ) {\n\tif ( this.$button ) {\n\t\tthis.$button.removeAttr( 'aria-pressed' );\n\t}\n\tOO.ui.mixin.ButtonElement.prototype.setButtonElement.call( this, $button );\n\tthis.$button.attr( 'aria-pressed', this.value.toString() );\n};\n","/**\n * ToggleSwitches are switches that slide on and off. Their state is represented by a Boolean\n * value (`true` for ‘on’, and `false` otherwise, the default). The ‘off’ state is represented\n * visually by a slider in the leftmost position.\n *\n *     @example\n *     // Toggle switches in the 'off' and 'on' position.\n *     var toggleSwitch1 = new OO.ui.ToggleSwitchWidget(),\n *         toggleSwitch2 = new OO.ui.ToggleSwitchWidget( {\n *             value: true\n *         } );\n *         // Create a FieldsetLayout to layout and label switches.\n *         fieldset = new OO.ui.FieldsetLayout( {\n *             label: 'Toggle switches'\n *         } );\n *     fieldset.addItems( [\n *         new OO.ui.FieldLayout( toggleSwitch1, {\n *             label: 'Off',\n *             align: 'top'\n *         } ),\n *         new OO.ui.FieldLayout( toggleSwitch2, {\n *             label: 'On',\n *             align: 'top'\n *         } )\n *     ] );\n *     $( document.body ).append( fieldset.$element );\n *\n * @class\n * @extends OO.ui.ToggleWidget\n * @mixins OO.ui.mixin.TabIndexedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [value=false] The toggle switch’s initial on/off state.\n *  By default, the toggle switch is in the 'off' position.\n */\nOO.ui.ToggleSwitchWidget = function OoUiToggleSwitchWidget( config ) {\n\t// Parent constructor\n\tOO.ui.ToggleSwitchWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.TabIndexedElement.call( this, config );\n\n\t// Properties\n\tthis.dragging = false;\n\tthis.dragStart = null;\n\tthis.sliding = false;\n\tthis.$glow = $( '<span>' );\n\tthis.$grip = $( '<span>' );\n\n\t// Events\n\tthis.$element.on( {\n\t\tclick: this.onClick.bind( this ),\n\t\tkeypress: this.onKeyPress.bind( this )\n\t} );\n\n\t// Initialization\n\tthis.$glow.addClass( 'oo-ui-toggleSwitchWidget-glow' );\n\tthis.$grip.addClass( 'oo-ui-toggleSwitchWidget-grip' );\n\tthis.$element\n\t\t.addClass( 'oo-ui-toggleSwitchWidget' )\n\t\t.attr( 'role', 'checkbox' )\n\t\t.append( this.$glow, this.$grip );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ToggleSwitchWidget, OO.ui.ToggleWidget );\nOO.mixinClass( OO.ui.ToggleSwitchWidget, OO.ui.mixin.TabIndexedElement );\n\n/* Methods */\n\n/**\n * Handle mouse click events.\n *\n * @private\n * @param {jQuery.Event} e Mouse click event\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.ToggleSwitchWidget.prototype.onClick = function ( e ) {\n\tif ( !this.isDisabled() && e.which === OO.ui.MouseButtons.LEFT ) {\n\t\tthis.setValue( !this.value );\n\t}\n\treturn false;\n};\n\n/**\n * Handle key press events.\n *\n * @private\n * @param {jQuery.Event} e Key press event\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.ToggleSwitchWidget.prototype.onKeyPress = function ( e ) {\n\tif ( !this.isDisabled() && ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER ) ) {\n\t\tthis.setValue( !this.value );\n\t\treturn false;\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.ToggleSwitchWidget.prototype.setValue = function ( value ) {\n\tOO.ui.ToggleSwitchWidget.parent.prototype.setValue.call( this, value );\n\tthis.$element.attr( 'aria-checked', this.value.toString() );\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.ToggleSwitchWidget.prototype.simulateLabelClick = function () {\n\tif ( !this.isDisabled() ) {\n\t\tthis.setValue( !this.value );\n\t}\n\tthis.focus();\n};\n","/**\n * OutlineControlsWidget is a set of controls for an\n * {@link OO.ui.OutlineSelectWidget outline select widget}.\n * Controls include moving items up and down, removing items, and adding different kinds of items.\n *\n * **Currently, this class is only used by {@link OO.ui.BookletLayout booklet layouts}.**\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.GroupElement\n *\n * @constructor\n * @param {OO.ui.OutlineSelectWidget} outline Outline to control\n * @param {Object} [config] Configuration options\n * @cfg {Object} [abilities] List of abilties\n * @cfg {boolean} [abilities.move=true] Allow moving movable items\n * @cfg {boolean} [abilities.remove=true] Allow removing removable items\n */\nOO.ui.OutlineControlsWidget = function OoUiOutlineControlsWidget( outline, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( outline ) && config === undefined ) {\n\t\tconfig = outline;\n\t\toutline = config.outline;\n\t}\n\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.OutlineControlsWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.GroupElement.call( this, config );\n\n\t// Properties\n\tthis.outline = outline;\n\tthis.$movers = $( '<div>' );\n\tthis.upButton = new OO.ui.ButtonWidget( {\n\t\tframed: false,\n\t\ticon: 'collapse',\n\t\ttitle: OO.ui.msg( 'ooui-outline-control-move-up' )\n\t} );\n\tthis.downButton = new OO.ui.ButtonWidget( {\n\t\tframed: false,\n\t\ticon: 'expand',\n\t\ttitle: OO.ui.msg( 'ooui-outline-control-move-down' )\n\t} );\n\tthis.removeButton = new OO.ui.ButtonWidget( {\n\t\tframed: false,\n\t\ticon: 'trash',\n\t\ttitle: OO.ui.msg( 'ooui-outline-control-remove' )\n\t} );\n\tthis.abilities = { move: true, remove: true };\n\n\t// Events\n\toutline.connect( this, {\n\t\tselect: 'onOutlineChange',\n\t\tadd: 'onOutlineChange',\n\t\tremove: 'onOutlineChange'\n\t} );\n\tthis.upButton.connect( this, {\n\t\tclick: [ 'emit', 'move', -1 ]\n\t} );\n\tthis.downButton.connect( this, {\n\t\tclick: [ 'emit', 'move', 1 ]\n\t} );\n\tthis.removeButton.connect( this, {\n\t\tclick: [ 'emit', 'remove' ]\n\t} );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-outlineControlsWidget' );\n\tthis.$group.addClass( 'oo-ui-outlineControlsWidget-items' );\n\tthis.$movers\n\t\t.addClass( 'oo-ui-outlineControlsWidget-movers' )\n\t\t.append( this.removeButton.$element, this.upButton.$element, this.downButton.$element );\n\tthis.$element.append( this.$icon, this.$group, this.$movers );\n\tthis.setAbilities( config.abilities || {} );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.OutlineControlsWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.OutlineControlsWidget, OO.ui.mixin.GroupElement );\n\n/* Events */\n\n/**\n * @event move\n * @param {number} places Number of places to move\n */\n\n/**\n * @event remove\n */\n\n/* Methods */\n\n/**\n * Set abilities.\n *\n * @param {Object} abilities List of abilties\n * @param {boolean} [abilities.move] Allow moving movable items\n * @param {boolean} [abilities.remove] Allow removing removable items\n */\nOO.ui.OutlineControlsWidget.prototype.setAbilities = function ( abilities ) {\n\tvar ability;\n\n\tfor ( ability in this.abilities ) {\n\t\tif ( abilities[ ability ] !== undefined ) {\n\t\t\tthis.abilities[ ability ] = !!abilities[ ability ];\n\t\t}\n\t}\n\n\tthis.onOutlineChange();\n};\n\n/**\n * Handle outline change events.\n *\n * @private\n */\nOO.ui.OutlineControlsWidget.prototype.onOutlineChange = function () {\n\tvar i, len, firstMovable, lastMovable,\n\t\titems = this.outline.getItems(),\n\t\tselectedItem = this.outline.findSelectedItem(),\n\t\tmovable = this.abilities.move && selectedItem && selectedItem.isMovable(),\n\t\tremovable = this.abilities.remove && selectedItem && selectedItem.isRemovable();\n\n\tif ( movable ) {\n\t\ti = -1;\n\t\tlen = items.length;\n\t\twhile ( ++i < len ) {\n\t\t\tif ( items[ i ].isMovable() ) {\n\t\t\t\tfirstMovable = items[ i ];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\ti = len;\n\t\twhile ( i-- ) {\n\t\t\tif ( items[ i ].isMovable() ) {\n\t\t\t\tlastMovable = items[ i ];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\tthis.upButton.setDisabled( !movable || selectedItem === firstMovable );\n\tthis.downButton.setDisabled( !movable || selectedItem === lastMovable );\n\tthis.removeButton.setDisabled( !removable );\n};\n","/**\n * OutlineOptionWidget is an item in an {@link OO.ui.OutlineSelectWidget OutlineSelectWidget}.\n *\n * Currently, this class is only used by {@link OO.ui.BookletLayout booklet layouts}, which contain\n * {@link OO.ui.PageLayout page layouts}. See {@link OO.ui.BookletLayout BookletLayout}\n * for an example.\n *\n * @class\n * @extends OO.ui.DecoratedOptionWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {number} [level] Indentation level\n * @cfg {boolean} [movable] Allow modification from\n *  {@link OO.ui.OutlineControlsWidget outline controls}.\n */\nOO.ui.OutlineOptionWidget = function OoUiOutlineOptionWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.OutlineOptionWidget.parent.call( this, config );\n\n\t// Properties\n\tthis.level = 0;\n\tthis.movable = !!config.movable;\n\tthis.removable = !!config.removable;\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-outlineOptionWidget' );\n\tthis.setLevel( config.level );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.OutlineOptionWidget, OO.ui.DecoratedOptionWidget );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.OutlineOptionWidget.static.highlightable = true;\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.OutlineOptionWidget.static.scrollIntoViewOnSelect = true;\n\n/**\n * @static\n * @inheritable\n * @property {string}\n */\nOO.ui.OutlineOptionWidget.static.levelClass = 'oo-ui-outlineOptionWidget-level-';\n\n/**\n * @static\n * @inheritable\n * @property {number}\n */\nOO.ui.OutlineOptionWidget.static.levels = 3;\n\n/* Methods */\n\n/**\n * Check if item is movable.\n *\n * Movability is used by {@link OO.ui.OutlineControlsWidget outline controls}.\n *\n * @return {boolean} Item is movable\n */\nOO.ui.OutlineOptionWidget.prototype.isMovable = function () {\n\treturn this.movable;\n};\n\n/**\n * Check if item is removable.\n *\n * Removability is used by {@link OO.ui.OutlineControlsWidget outline controls}.\n *\n * @return {boolean} Item is removable\n */\nOO.ui.OutlineOptionWidget.prototype.isRemovable = function () {\n\treturn this.removable;\n};\n\n/**\n * Get indentation level.\n *\n * @return {number} Indentation level\n */\nOO.ui.OutlineOptionWidget.prototype.getLevel = function () {\n\treturn this.level;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.OutlineOptionWidget.prototype.setPressed = function ( state ) {\n\tOO.ui.OutlineOptionWidget.parent.prototype.setPressed.call( this, state );\n\treturn this;\n};\n\n/**\n * Set movability.\n *\n * Movability is used by {@link OO.ui.OutlineControlsWidget outline controls}.\n *\n * @param {boolean} movable Item is movable\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.OutlineOptionWidget.prototype.setMovable = function ( movable ) {\n\tthis.movable = !!movable;\n\tthis.updateThemeClasses();\n\treturn this;\n};\n\n/**\n * Set removability.\n *\n * Removability is used by {@link OO.ui.OutlineControlsWidget outline controls}.\n *\n * @param {boolean} removable Item is removable\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.OutlineOptionWidget.prototype.setRemovable = function ( removable ) {\n\tthis.removable = !!removable;\n\tthis.updateThemeClasses();\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.OutlineOptionWidget.prototype.setSelected = function ( state ) {\n\tOO.ui.OutlineOptionWidget.parent.prototype.setSelected.call( this, state );\n\treturn this;\n};\n\n/**\n * Set indentation level.\n *\n * @param {number} [level=0] Indentation level, in the range of [0,#maxLevel]\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.OutlineOptionWidget.prototype.setLevel = function ( level ) {\n\tvar levels = this.constructor.static.levels,\n\t\tlevelClass = this.constructor.static.levelClass,\n\t\ti = levels;\n\n\tthis.level = level ? Math.max( 0, Math.min( levels - 1, level ) ) : 0;\n\twhile ( i-- ) {\n\t\tif ( this.level === i ) {\n\t\t\tthis.$element.addClass( levelClass + i );\n\t\t} else {\n\t\t\tthis.$element.removeClass( levelClass + i );\n\t\t}\n\t}\n\tthis.updateThemeClasses();\n\n\treturn this;\n};\n","/**\n * OutlineSelectWidget is a structured list that contains\n * {@link OO.ui.OutlineOptionWidget outline options}\n * A set of controls can be provided with an {@link OO.ui.OutlineControlsWidget outline controls}\n * widget.\n *\n * **Currently, this class is only used by {@link OO.ui.BookletLayout booklet layouts}.**\n *\n * @class\n * @extends OO.ui.SelectWidget\n * @mixins OO.ui.mixin.TabIndexedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.OutlineSelectWidget = function OoUiOutlineSelectWidget( config ) {\n\t// Parent constructor\n\tOO.ui.OutlineSelectWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.TabIndexedElement.call( this, config );\n\n\t// Events\n\tthis.$element.on( {\n\t\tfocus: this.bindDocumentKeyDownListener.bind( this ),\n\t\tblur: this.unbindDocumentKeyDownListener.bind( this )\n\t} );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-outlineSelectWidget' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.OutlineSelectWidget, OO.ui.SelectWidget );\nOO.mixinClass( OO.ui.OutlineSelectWidget, OO.ui.mixin.TabIndexedElement );\n","/**\n * ButtonOptionWidget is a special type of {@link OO.ui.mixin.ButtonElement button element} that\n * can be selected and configured with data. The class is\n * used with OO.ui.ButtonSelectWidget to create a selection of button options. Please see the\n * [OOUI documentation on MediaWiki] [1] for more information.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options#Button_selects_and_options\n *\n * @class\n * @extends OO.ui.OptionWidget\n * @mixins OO.ui.mixin.ButtonElement\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.IndicatorElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.ButtonOptionWidget = function OoUiButtonOptionWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.ButtonOptionWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.ButtonElement.call( this, config );\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.IndicatorElement.call( this, config );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-buttonOptionWidget' );\n\tthis.$button.append( this.$icon, this.$label, this.$indicator );\n\tthis.$element.append( this.$button );\n\tthis.setTitledElement( this.$button );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ButtonOptionWidget, OO.ui.OptionWidget );\nOO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.mixin.ButtonElement );\nOO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.mixin.IndicatorElement );\n\n/* Static Properties */\n\n/**\n * Allow button mouse down events to pass through so they can be handled by the parent select widget\n *\n * @static\n * @inheritdoc\n */\nOO.ui.ButtonOptionWidget.static.cancelButtonMouseDownEvents = false;\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.ButtonOptionWidget.static.highlightable = false;\n\n/* Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.ButtonOptionWidget.prototype.setSelected = function ( state ) {\n\tOO.ui.ButtonOptionWidget.parent.prototype.setSelected.call( this, state );\n\n\tif ( this.constructor.static.selectable ) {\n\t\tthis.setActive( state );\n\t}\n\n\treturn this;\n};\n","/**\n * ButtonSelectWidget is a {@link OO.ui.SelectWidget select widget} that contains\n * button options and is used together with\n * OO.ui.ButtonOptionWidget. The ButtonSelectWidget provides an interface for\n * highlighting, choosing, and selecting mutually exclusive options. Please see\n * the [OOUI documentation on MediaWiki] [1] for more information.\n *\n *     @example\n *     // A ButtonSelectWidget that contains three ButtonOptionWidgets.\n *     var option1 = new OO.ui.ButtonOptionWidget( {\n *             data: 1,\n *             label: 'Option 1',\n *             title: 'Button option 1'\n *         } ),\n *         option2 = new OO.ui.ButtonOptionWidget( {\n *             data: 2,\n *             label: 'Option 2',\n *             title: 'Button option 2'\n *         } ),\n *         option3 = new OO.ui.ButtonOptionWidget( {\n *             data: 3,\n *             label: 'Option 3',\n *             title: 'Button option 3'\n *         } ),\n *         buttonSelect = new OO.ui.ButtonSelectWidget( {\n *             items: [ option1, option2, option3 ]\n *         } );\n *     $( document.body ).append( buttonSelect.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options\n *\n * @class\n * @extends OO.ui.SelectWidget\n * @mixins OO.ui.mixin.TabIndexedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.ButtonSelectWidget = function OoUiButtonSelectWidget( config ) {\n\t// Parent constructor\n\tOO.ui.ButtonSelectWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.TabIndexedElement.call( this, config );\n\n\t// Events\n\tthis.$element.on( {\n\t\tfocus: this.bindDocumentKeyDownListener.bind( this ),\n\t\tblur: this.unbindDocumentKeyDownListener.bind( this )\n\t} );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-buttonSelectWidget' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ButtonSelectWidget, OO.ui.SelectWidget );\nOO.mixinClass( OO.ui.ButtonSelectWidget, OO.ui.mixin.TabIndexedElement );\n","/**\n * TabOptionWidget is an item in a {@link OO.ui.TabSelectWidget TabSelectWidget}.\n *\n * Currently, this class is only used by {@link OO.ui.IndexLayout index layouts}, which contain\n * {@link OO.ui.TabPanelLayout tab panel layouts}. See {@link OO.ui.IndexLayout IndexLayout}\n * for an example.\n *\n * @class\n * @extends OO.ui.OptionWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.TabOptionWidget = function OoUiTabOptionWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.TabOptionWidget.parent.call( this, config );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-tabOptionWidget' )\n\t\t.attr( 'role', 'tab' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.TabOptionWidget, OO.ui.OptionWidget );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.TabOptionWidget.static.highlightable = false;\n","/**\n * TabSelectWidget is a list that contains {@link OO.ui.TabOptionWidget tab options}\n *\n * **Currently, this class is only used by {@link OO.ui.IndexLayout index layouts}.**\n *\n * @class\n * @extends OO.ui.SelectWidget\n * @mixins OO.ui.mixin.TabIndexedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.TabSelectWidget = function OoUiTabSelectWidget( config ) {\n\t// Parent constructor\n\tOO.ui.TabSelectWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.TabIndexedElement.call( this, config );\n\n\t// Events\n\tthis.$element.on( {\n\t\tfocus: this.bindDocumentKeyDownListener.bind( this ),\n\t\tblur: this.unbindDocumentKeyDownListener.bind( this )\n\t} );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-tabSelectWidget' )\n\t\t.attr( 'role', 'tablist' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.TabSelectWidget, OO.ui.SelectWidget );\nOO.mixinClass( OO.ui.TabSelectWidget, OO.ui.mixin.TabIndexedElement );\n","/**\n * TagItemWidgets are used within a {@link OO.ui.TagMultiselectWidget\n * TagMultiselectWidget} to display the selected items.\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.ItemWidget\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.FlaggedElement\n * @mixins OO.ui.mixin.TabIndexedElement\n * @mixins OO.ui.mixin.DraggableElement\n *\n * @constructor\n * @param {Object} [config] Configuration object\n * @cfg {boolean} [valid=true] Item is valid\n * @cfg {boolean} [fixed] Item is fixed. This means the item is\n *  always included in the values and cannot be removed.\n */\nOO.ui.TagItemWidget = function OoUiTagItemWidget( config ) {\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.TagItemWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.ItemWidget.call( this );\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.FlaggedElement.call( this, config );\n\tOO.ui.mixin.TabIndexedElement.call( this, config );\n\tOO.ui.mixin.DraggableElement.call( this, config );\n\n\tthis.valid = config.valid === undefined ? true : !!config.valid;\n\tthis.fixed = !!config.fixed;\n\n\tthis.closeButton = new OO.ui.ButtonWidget( {\n\t\tframed: false,\n\t\ticon: 'close',\n\t\ttabIndex: -1,\n\t\ttitle: OO.ui.msg( 'ooui-item-remove' )\n\t} );\n\tthis.closeButton.setDisabled( this.isDisabled() );\n\n\t// Events\n\tthis.closeButton.connect( this, {\n\t\tclick: 'remove'\n\t} );\n\tthis.$element\n\t\t.on( 'click', this.select.bind( this ) )\n\t\t.on( 'keydown', this.onKeyDown.bind( this ) )\n\t\t// Prevent propagation of mousedown; the tag item \"lives\" in the\n\t\t// clickable area of the TagMultiselectWidget, which listens to\n\t\t// mousedown to open the menu or popup. We want to prevent that\n\t\t// for clicks specifically on the tag itself, so the actions taken\n\t\t// are more deliberate. When the tag is clicked, it will emit the\n\t\t// selection event (similar to how #OO.ui.MultioptionWidget emits 'change')\n\t\t// and can be handled separately.\n\t\t.on( 'mousedown', function ( e ) { e.stopPropagation(); } );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-tagItemWidget' )\n\t\t.append( this.$label, this.closeButton.$element );\n};\n\n/* Initialization */\n\nOO.inheritClass( OO.ui.TagItemWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.TagItemWidget, OO.ui.mixin.ItemWidget );\nOO.mixinClass( OO.ui.TagItemWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.TagItemWidget, OO.ui.mixin.FlaggedElement );\nOO.mixinClass( OO.ui.TagItemWidget, OO.ui.mixin.TabIndexedElement );\nOO.mixinClass( OO.ui.TagItemWidget, OO.ui.mixin.DraggableElement );\n\n/* Events */\n\n/**\n * @event remove\n *\n * A remove action was performed on the item\n */\n\n/**\n * @event navigate\n * @param {string} direction Direction of the movement, forward or backwards\n *\n * A navigate action was performed on the item\n */\n\n/**\n * @event select\n *\n * The tag widget was selected. This can occur when the widget\n * is either clicked or enter was pressed on it.\n */\n\n/**\n * @event valid\n * @param {boolean} isValid Item is valid\n *\n * Item validity has changed\n */\n\n/**\n * @event fixed\n * @param {boolean} isFixed Item is fixed\n *\n * Item fixed state has changed\n */\n\n/* Methods */\n\n/**\n * Set this item as fixed, meaning it cannot be removed\n *\n * @param {string} [state] Item is fixed\n * @fires fixed\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TagItemWidget.prototype.setFixed = function ( state ) {\n\tstate = state === undefined ? !this.fixed : !!state;\n\n\tif ( this.fixed !== state ) {\n\t\tthis.fixed = state;\n\t\tif ( this.closeButton ) {\n\t\t\tthis.closeButton.toggle( !this.fixed );\n\t\t}\n\n\t\tif ( !this.fixed && this.elementGroup && !this.elementGroup.isDraggable() ) {\n\t\t\t// Only enable the state of the item if the\n\t\t\t// entire group is draggable\n\t\t\tthis.toggleDraggable( !this.fixed );\n\t\t}\n\t\tthis.$element.toggleClass( 'oo-ui-tagItemWidget-fixed', this.fixed );\n\n\t\tthis.emit( 'fixed', this.isFixed() );\n\t}\n\treturn this;\n};\n\n/**\n * Check whether the item is fixed\n * @return {boolean}\n */\nOO.ui.TagItemWidget.prototype.isFixed = function () {\n\treturn this.fixed;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.TagItemWidget.prototype.setDisabled = function ( state ) {\n\tif ( state && this.elementGroup && !this.elementGroup.isDisabled() ) {\n\t\tOO.ui.warnDeprecation( 'TagItemWidget#setDisabled: Disabling individual items is deprecated and will result in inconsistent behavior. Use #setFixed instead. See T193571.' );\n\t}\n\t// Parent method\n\tOO.ui.TagItemWidget.parent.prototype.setDisabled.call( this, state );\n\tif (\n\t\t!state &&\n\t\t// Verify we have a group, and that the widget is ready\n\t\tthis.toggleDraggable && this.elementGroup &&\n\t\t!this.isFixed() &&\n\t\t!this.elementGroup.isDraggable()\n\t) {\n\t\t// Only enable the draggable state of the item if the\n\t\t// entire group is draggable to begin with, and if the\n\t\t// item is not fixed\n\t\tthis.toggleDraggable( !state );\n\t}\n\n\tif ( this.closeButton ) {\n\t\tthis.closeButton.setDisabled( state );\n\t}\n\n\treturn this;\n};\n\n/**\n * Handle removal of the item\n *\n * This is mainly for extensibility concerns, so other children\n * of this class can change the behavior if they need to. This\n * is called by both clicking the 'remove' button but also\n * on keypress, which is harder to override if needed.\n *\n * @fires remove\n */\nOO.ui.TagItemWidget.prototype.remove = function () {\n\tif ( !this.isDisabled() && !this.isFixed() ) {\n\t\tthis.emit( 'remove' );\n\t}\n};\n\n/**\n * Handle a keydown event on the widget\n *\n * @fires navigate\n * @fires remove\n * @param {jQuery.Event} e Key down event\n * @return {boolean|undefined} false to stop the operation\n */\nOO.ui.TagItemWidget.prototype.onKeyDown = function ( e ) {\n\tvar movement;\n\n\tif (\n\t\t!this.isDisabled() &&\n\t\t!this.isFixed() &&\n\t\t( e.keyCode === OO.ui.Keys.BACKSPACE || e.keyCode === OO.ui.Keys.DELETE )\n\t) {\n\t\tthis.remove();\n\t\treturn false;\n\t} else if ( e.keyCode === OO.ui.Keys.ENTER ) {\n\t\tthis.select();\n\t\treturn false;\n\t} else if (\n\t\te.keyCode === OO.ui.Keys.LEFT ||\n\t\te.keyCode === OO.ui.Keys.RIGHT\n\t) {\n\t\tif ( OO.ui.Element.static.getDir( this.$element ) === 'rtl' ) {\n\t\t\tmovement = {\n\t\t\t\tleft: 'forwards',\n\t\t\t\tright: 'backwards'\n\t\t\t};\n\t\t} else {\n\t\t\tmovement = {\n\t\t\t\tleft: 'backwards',\n\t\t\t\tright: 'forwards'\n\t\t\t};\n\t\t}\n\n\t\tthis.emit(\n\t\t\t'navigate',\n\t\t\te.keyCode === OO.ui.Keys.LEFT ?\n\t\t\t\tmovement.left : movement.right\n\t\t);\n\t\treturn false;\n\t}\n};\n\n/**\n * Select this item\n *\n * @fires select\n */\nOO.ui.TagItemWidget.prototype.select = function () {\n\tif ( !this.isDisabled() ) {\n\t\tthis.emit( 'select' );\n\t}\n};\n\n/**\n * Set the valid state of this item\n *\n * @param {boolean} [valid] Item is valid\n * @fires valid\n */\nOO.ui.TagItemWidget.prototype.toggleValid = function ( valid ) {\n\tvalid = valid === undefined ? !this.valid : !!valid;\n\n\tif ( this.valid !== valid ) {\n\t\tthis.valid = valid;\n\n\t\tthis.setFlags( { invalid: !this.valid } );\n\n\t\tthis.emit( 'valid', this.valid );\n\t}\n};\n\n/**\n * Check whether the item is valid\n *\n * @return {boolean} Item is valid\n */\nOO.ui.TagItemWidget.prototype.isValid = function () {\n\treturn this.valid;\n};\n","/**\n * A basic tag multiselect widget, similar in concept to\n * {@link OO.ui.ComboBoxInputWidget combo box widget} that allows the user to add multiple values\n * that are displayed in a tag area.\n *\n * This widget is a base widget; see {@link OO.ui.MenuTagMultiselectWidget MenuTagMultiselectWidget}\n * and {@link OO.ui.PopupTagMultiselectWidget PopupTagMultiselectWidget} for the implementations\n * that use a menu and a popup respectively.\n *\n *     @example\n *     // A TagMultiselectWidget.\n *     var widget = new OO.ui.TagMultiselectWidget( {\n *         inputPosition: 'outline',\n *         allowedValues: [ 'Option 1', 'Option 2', 'Option 3' ],\n *         selected: [ 'Option 1' ]\n *     } );\n *     $( document.body ).append( widget.$element );\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.GroupWidget\n * @mixins OO.ui.mixin.DraggableGroupElement\n * @mixins OO.ui.mixin.IndicatorElement\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.TabIndexedElement\n * @mixins OO.ui.mixin.FlaggedElement\n * @mixins OO.ui.mixin.TitledElement\n *\n * @constructor\n * @param {Object} config Configuration object\n * @cfg {Object} [input] Configuration options for the input widget\n * @cfg {OO.ui.InputWidget} [inputWidget] An optional input widget. If given, it will\n *  replace the input widget used in the TagMultiselectWidget. If not given,\n *  TagMultiselectWidget creates its own.\n * @cfg {boolean} [inputPosition='inline'] Position of the input. Options are:\n *  - inline: The input is invisible, but exists inside the tag list, so\n *    the user types into the tag groups to add tags.\n *  - outline: The input is underneath the tag area.\n *  - none: No input supplied\n * @cfg {boolean} [allowEditTags=true] Allow editing of the tags by clicking them\n * @cfg {boolean} [allowArbitrary=false] Allow data items to be added even if\n *  not present in the menu.\n * @cfg {Object[]} [allowedValues] An array representing the allowed items\n *  by their datas.\n * @cfg {boolean} [allowDuplicates=false] Allow duplicate items to be added\n * @cfg {boolean} [allowDisplayInvalidTags=false] Allow the display of\n *  invalid tags. These tags will display with an invalid state, and\n *  the widget as a whole will have an invalid state if any invalid tags\n *  are present.\n * @cfg {number} [tagLimit] An optional limit on the number of selected options.\n *  If 'tagLimit' is set and is reached, the input is disabled, not allowing any\n *  additions. If 'tagLimit' is unset or is 0, an unlimited number of items can be\n *  added.\n * @cfg {boolean} [allowReordering=true] Allow reordering of the items\n * @cfg {Object[]|String[]} [selected] A set of selected tags. If given,\n *  these will appear in the tag list on initialization, as long as they\n *  pass the validity tests.\n */\nOO.ui.TagMultiselectWidget = function OoUiTagMultiselectWidget( config ) {\n\tvar inputEvents,\n\t\trAF = window.requestAnimationFrame || setTimeout,\n\t\twidget = this,\n\t\t$tabFocus = $( '<span>' ).addClass( 'oo-ui-tagMultiselectWidget-focusTrap' );\n\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.TagMultiselectWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.GroupWidget.call( this, config );\n\tOO.ui.mixin.IndicatorElement.call( this, config );\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.TabIndexedElement.call( this, config );\n\tOO.ui.mixin.FlaggedElement.call( this, config );\n\tOO.ui.mixin.DraggableGroupElement.call( this, config );\n\tOO.ui.mixin.TitledElement.call( this, config );\n\n\tthis.toggleDraggable(\n\t\tconfig.allowReordering === undefined ?\n\t\t\ttrue : !!config.allowReordering\n\t);\n\n\tthis.inputPosition =\n\t\tthis.constructor.static.allowedInputPositions.indexOf( config.inputPosition ) > -1 ?\n\t\t\tconfig.inputPosition : 'inline';\n\tthis.allowEditTags = config.allowEditTags === undefined ? true : !!config.allowEditTags;\n\tthis.allowArbitrary = !!config.allowArbitrary;\n\tthis.allowDuplicates = !!config.allowDuplicates;\n\tthis.allowedValues = config.allowedValues || [];\n\tthis.allowDisplayInvalidTags = config.allowDisplayInvalidTags;\n\tthis.hasInput = this.inputPosition !== 'none';\n\tthis.tagLimit = config.tagLimit;\n\tthis.height = null;\n\tthis.valid = true;\n\n\tthis.$content = $( '<div>' ).addClass( 'oo-ui-tagMultiselectWidget-content' );\n\tthis.$handle = $( '<div>' )\n\t\t.addClass( 'oo-ui-tagMultiselectWidget-handle' )\n\t\t.append(\n\t\t\tthis.$indicator,\n\t\t\tthis.$icon,\n\t\t\tthis.$content\n\t\t\t\t.append(\n\t\t\t\t\tthis.$group.addClass( 'oo-ui-tagMultiselectWidget-group' )\n\t\t\t\t)\n\t\t);\n\n\t// Events\n\tthis.aggregate( {\n\t\tremove: 'itemRemove',\n\t\tnavigate: 'itemNavigate',\n\t\tselect: 'itemSelect',\n\t\tfixed: 'itemFixed'\n\t} );\n\tthis.connect( this, {\n\t\titemRemove: 'onTagRemove',\n\t\titemSelect: 'onTagSelect',\n\t\titemFixed: 'onTagFixed',\n\t\titemNavigate: 'onTagNavigate',\n\t\tchange: 'onChangeTags'\n\t} );\n\tthis.$handle.on( {\n\t\tmousedown: this.onMouseDown.bind( this )\n\t} );\n\n\t// Initialize\n\tthis.$element\n\t\t.addClass( 'oo-ui-tagMultiselectWidget' )\n\t\t.append( this.$handle );\n\n\tif ( this.hasInput ) {\n\t\tif ( config.inputWidget ) {\n\t\t\tthis.input = config.inputWidget;\n\t\t} else {\n\t\t\tthis.input = new OO.ui.TextInputWidget( $.extend( {\n\t\t\t\tplaceholder: config.placeholder,\n\t\t\t\tclasses: [ 'oo-ui-tagMultiselectWidget-input' ]\n\t\t\t}, config.input ) );\n\t\t}\n\t\tthis.input.setDisabled( this.isDisabled() );\n\n\t\tinputEvents = {\n\t\t\tfocus: this.onInputFocus.bind( this ),\n\t\t\tblur: this.onInputBlur.bind( this ),\n\t\t\t'propertychange change click mouseup keydown keyup input cut paste select focus':\n\t\t\t\tOO.ui.debounce( this.updateInputSize.bind( this ) ),\n\t\t\tkeydown: this.onInputKeyDown.bind( this ),\n\t\t\tkeypress: this.onInputKeyPress.bind( this )\n\t\t};\n\n\t\tthis.input.$input.on( inputEvents );\n\t\tthis.inputPlaceholder = this.input.$input.attr( 'placeholder' );\n\n\t\tif ( this.inputPosition === 'outline' ) {\n\t\t\t// Override max-height for the input widget\n\t\t\t// in the case the widget is outline so it can\n\t\t\t// stretch all the way if the widget is wide\n\t\t\tthis.input.$element.css( 'max-width', 'inherit' );\n\t\t\tthis.$element\n\t\t\t\t.addClass( 'oo-ui-tagMultiselectWidget-outlined' )\n\t\t\t\t.append( this.input.$element );\n\t\t} else {\n\t\t\tthis.$element.addClass( 'oo-ui-tagMultiselectWidget-inlined' );\n\t\t\t// HACK: When the widget is using 'inline' input, the\n\t\t\t// behavior needs to only use the $input itself\n\t\t\t// so we style and size it accordingly (otherwise\n\t\t\t// the styling and sizing can get very convoluted\n\t\t\t// when the wrapping divs and other elements)\n\t\t\t// We are taking advantage of still being able to\n\t\t\t// call the widget itself for operations like\n\t\t\t// .getValue() and setDisabled() and .focus() but\n\t\t\t// having only the $input attached to the DOM\n\t\t\tthis.$content.append( this.input.$input );\n\t\t}\n\t} else {\n\t\tthis.$content.append( $tabFocus );\n\t}\n\n\tthis.setTabIndexedElement(\n\t\tthis.hasInput ?\n\t\t\tthis.input.$input :\n\t\t\t$tabFocus\n\t);\n\n\tif ( config.selected ) {\n\t\tthis.setValue( config.selected );\n\t}\n\n\t// HACK: Input size needs to be calculated after everything\n\t// else is rendered\n\trAF( function () {\n\t\tif ( widget.hasInput ) {\n\t\t\twidget.updateInputSize();\n\t\t}\n\t} );\n};\n\n/* Initialization */\n\nOO.inheritClass( OO.ui.TagMultiselectWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.TagMultiselectWidget, OO.ui.mixin.GroupWidget );\nOO.mixinClass( OO.ui.TagMultiselectWidget, OO.ui.mixin.DraggableGroupElement );\nOO.mixinClass( OO.ui.TagMultiselectWidget, OO.ui.mixin.IndicatorElement );\nOO.mixinClass( OO.ui.TagMultiselectWidget, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.TagMultiselectWidget, OO.ui.mixin.TabIndexedElement );\nOO.mixinClass( OO.ui.TagMultiselectWidget, OO.ui.mixin.FlaggedElement );\nOO.mixinClass( OO.ui.TagMultiselectWidget, OO.ui.mixin.TitledElement );\n\n/* Static properties */\n\n/**\n * Allowed input positions.\n * - inline: The input is inside the tag list\n * - outline: The input is under the tag list\n * - none: There is no input\n *\n * @property {Array}\n */\nOO.ui.TagMultiselectWidget.static.allowedInputPositions = [ 'inline', 'outline', 'none' ];\n\n/* Methods */\n\n/**\n * Handle mouse down events.\n *\n * @private\n * @param {jQuery.Event} e Mouse down event\n * @return {boolean} False to prevent defaults\n */\nOO.ui.TagMultiselectWidget.prototype.onMouseDown = function ( e ) {\n\tif (\n\t\t!this.isDisabled() &&\n\t\t( !this.hasInput || e.target !== this.input.$input[ 0 ] ) &&\n\t\te.which === OO.ui.MouseButtons.LEFT\n\t) {\n\t\tthis.focus();\n\t\treturn false;\n\t}\n};\n\n/**\n * Handle key press events.\n *\n * @private\n * @param {jQuery.Event} e Key press event\n * @return {boolean} Whether to prevent defaults\n */\nOO.ui.TagMultiselectWidget.prototype.onInputKeyPress = function ( e ) {\n\tvar stopOrContinue,\n\t\twithMetaKey = e.metaKey || e.ctrlKey;\n\n\tif ( !this.isDisabled() ) {\n\t\tif ( e.which === OO.ui.Keys.ENTER ) {\n\t\t\tstopOrContinue = this.doInputEnter( e, withMetaKey );\n\t\t}\n\n\t\t// Make sure the input gets resized.\n\t\tsetTimeout( this.updateInputSize.bind( this ), 0 );\n\t\treturn stopOrContinue;\n\t}\n};\n\n/**\n * Handle key down events.\n *\n * @private\n * @param {jQuery.Event} e Key down event\n * @return {boolean}\n */\nOO.ui.TagMultiselectWidget.prototype.onInputKeyDown = function ( e ) {\n\tvar movement, direction,\n\t\twidget = this,\n\t\twithMetaKey = e.metaKey || e.ctrlKey,\n\t\tisMovementInsideInput = function ( direction ) {\n\t\t\tvar inputRange = widget.input.getRange(),\n\t\t\t\tinputValue = widget.hasInput && widget.input.getValue();\n\n\t\t\tif ( direction === 'forwards' && inputRange.to > inputValue.length - 1 ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif ( direction === 'backwards' && inputRange.from <= 0 ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t};\n\n\tif ( !this.isDisabled() ) {\n\t\t// 'keypress' event is not triggered for Backspace key\n\t\tif ( e.keyCode === OO.ui.Keys.BACKSPACE ) {\n\t\t\treturn this.doInputBackspace( e, withMetaKey );\n\t\t} else if ( e.keyCode === OO.ui.Keys.ESCAPE ) {\n\t\t\treturn this.doInputEscape( e );\n\t\t} else if (\n\t\t\te.keyCode === OO.ui.Keys.LEFT ||\n\t\t\te.keyCode === OO.ui.Keys.RIGHT\n\t\t) {\n\t\t\tif ( OO.ui.Element.static.getDir( this.$element ) === 'rtl' ) {\n\t\t\t\tmovement = {\n\t\t\t\t\tleft: 'forwards',\n\t\t\t\t\tright: 'backwards'\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\tmovement = {\n\t\t\t\t\tleft: 'backwards',\n\t\t\t\t\tright: 'forwards'\n\t\t\t\t};\n\t\t\t}\n\t\t\tdirection = e.keyCode === OO.ui.Keys.LEFT ?\n\t\t\t\tmovement.left : movement.right;\n\n\t\t\tif ( !this.hasInput || !isMovementInsideInput( direction ) ) {\n\t\t\t\treturn this.doInputArrow( e, direction, withMetaKey );\n\t\t\t}\n\t\t}\n\t}\n};\n\n/**\n * Respond to input focus event\n */\nOO.ui.TagMultiselectWidget.prototype.onInputFocus = function () {\n\tthis.$element.addClass( 'oo-ui-tagMultiselectWidget-focus' );\n\t// Reset validity\n\tthis.toggleValid( true );\n};\n\n/**\n * Respond to input blur event\n */\nOO.ui.TagMultiselectWidget.prototype.onInputBlur = function () {\n\tthis.$element.removeClass( 'oo-ui-tagMultiselectWidget-focus' );\n\n\t// Set the widget as invalid if there's text in the input\n\tthis.addTagFromInput();\n\tthis.toggleValid( this.checkValidity() && ( !this.hasInput || !this.input.getValue() ) );\n};\n\n/**\n * Perform an action after the Enter key on the input\n *\n * @param {jQuery.Event} e Event data\n * @param {boolean} [withMetaKey] Whether this key was pressed with\n * a meta key like Control\n * @return {boolean} Whether to prevent defaults\n */\nOO.ui.TagMultiselectWidget.prototype.doInputEnter = function () {\n\tthis.addTagFromInput();\n\treturn false;\n};\n\n/**\n * Perform an action responding to the Enter key on the input\n *\n * @param {jQuery.Event} e Event data\n * @param {boolean} [withMetaKey] Whether this key was pressed with\n * a meta key like Control\n * @return {boolean} Whether to prevent defaults\n */\nOO.ui.TagMultiselectWidget.prototype.doInputBackspace = function ( e, withMetaKey ) {\n\tvar items, item;\n\n\tif (\n\t\tthis.inputPosition === 'inline' &&\n\t\tthis.input.getValue() === '' &&\n\t\t!this.isEmpty()\n\t) {\n\t\t// Delete the last item\n\t\titems = this.getItems();\n\t\titem = items[ items.length - 1 ];\n\n\t\tif ( !item.isDisabled() && !item.isFixed() ) {\n\t\t\tthis.removeItems( [ item ] );\n\t\t\t// If Ctrl/Cmd was pressed, delete item entirely.\n\t\t\t// Otherwise put it into the text field for editing.\n\t\t\tif ( !withMetaKey ) {\n\t\t\t\tthis.input.setValue( item.getLabel() );\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n};\n\n/**\n * Perform an action after the Escape key on the input\n *\n * @param {jQuery.Event} e Event data\n */\nOO.ui.TagMultiselectWidget.prototype.doInputEscape = function () {\n\tthis.clearInput();\n};\n\n/**\n * Perform an action after the Left/Right arrow key on the input, select the previous\n * item from the input.\n * See #getPreviousItem\n *\n * @param {jQuery.Event} e Event data\n * @param {string} direction Direction of the movement; forwards or backwards\n * @param {boolean} [withMetaKey] Whether this key was pressed with\n *  a meta key like Control\n */\nOO.ui.TagMultiselectWidget.prototype.doInputArrow = function ( e, direction ) {\n\tif (\n\t\tthis.inputPosition === 'inline' &&\n\t\t!this.isEmpty() &&\n\t\tdirection === 'backwards'\n\t) {\n\t\t// Get previous item\n\t\tthis.getPreviousItem().focus();\n\t}\n};\n\n/**\n * Respond to item select event\n *\n * @param {OO.ui.TagItemWidget} item Selected item\n */\nOO.ui.TagMultiselectWidget.prototype.onTagSelect = function ( item ) {\n\tif ( this.hasInput && this.allowEditTags && !item.isFixed() ) {\n\t\tif ( this.input.getValue() ) {\n\t\t\tthis.addTagFromInput();\n\t\t}\n\t\t// 1. Get the label of the tag into the input\n\t\tthis.input.setValue( item.getData() );\n\t\t// 2. Remove the tag\n\t\tthis.removeItems( [ item ] );\n\t\t// 3. Focus the input\n\t\tthis.focus();\n\t}\n};\n\n/**\n * Respond to item fixed state change\n *\n * @param {OO.ui.TagItemWidget} item Selected item\n */\nOO.ui.TagMultiselectWidget.prototype.onTagFixed = function ( item ) {\n\tvar i,\n\t\titems = this.getItems();\n\n\t// Move item to the end of the static items\n\tfor ( i = 0; i < items.length; i++ ) {\n\t\tif ( items[ i ] !== item && !items[ i ].isFixed() ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\tthis.addItems( item, i );\n};\n/**\n * Respond to change event, where items were added, removed, or cleared.\n */\nOO.ui.TagMultiselectWidget.prototype.onChangeTags = function () {\n\tvar isUnderLimit = this.isUnderLimit();\n\n\t// Reset validity\n\tthis.toggleValid(\n\t\tthis.checkValidity() &&\n\t\t!( this.hasInput && this.input.getValue() )\n\t);\n\n\tif ( this.hasInput ) {\n\t\tthis.updateInputSize();\n\t\tif ( !isUnderLimit ) {\n\t\t\t// Clear the input\n\t\t\tthis.input.setValue( '' );\n\t\t}\n\t\tif ( this.inputPosition === 'outline' ) {\n\t\t\t// Show/clear the placeholder and enable/disable the input\n\t\t\t// based on whether we are/aren't under the specified limit\n\t\t\tthis.input.$input.attr( 'placeholder', isUnderLimit ? this.inputPlaceholder : '' );\n\t\t\tthis.input.setDisabled( !isUnderLimit );\n\t\t} else {\n\t\t\t// Show/hide the input\n\t\t\tthis.input.$input.toggleClass( 'oo-ui-element-hidden', !isUnderLimit );\n\t\t}\n\t}\n\tthis.updateIfHeightChanged();\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.TagMultiselectWidget.prototype.setDisabled = function ( isDisabled ) {\n\t// Parent method\n\tOO.ui.TagMultiselectWidget.parent.prototype.setDisabled.call( this, isDisabled );\n\n\tif ( this.hasInput && this.input ) {\n\t\tif ( !isDisabled ) {\n\t\t\tthis.updateInputSize();\n\t\t}\n\t\tthis.input.setDisabled( !!isDisabled && !this.isUnderLimit() );\n\t}\n\n\tif ( this.items ) {\n\t\tthis.getItems().forEach( function ( item ) {\n\t\t\titem.setDisabled( !!isDisabled );\n\t\t} );\n\t}\n};\n\n/**\n * Respond to tag remove event\n * @param {OO.ui.TagItemWidget} item Removed tag\n */\nOO.ui.TagMultiselectWidget.prototype.onTagRemove = function ( item ) {\n\tthis.removeTagByData( item.getData() );\n};\n\n/**\n * Respond to navigate event on the tag\n *\n * @param {OO.ui.TagItemWidget} item Removed tag\n * @param {string} direction Direction of movement; 'forwards' or 'backwards'\n */\nOO.ui.TagMultiselectWidget.prototype.onTagNavigate = function ( item, direction ) {\n\tvar firstItem = this.getItems()[ 0 ];\n\n\tif ( direction === 'forwards' ) {\n\t\tthis.getNextItem( item ).focus();\n\t} else if ( !this.inputPosition === 'inline' || item !== firstItem ) {\n\t\t// If the widget has an inline input, we want to stop at the starting edge\n\t\t// of the tags\n\t\tthis.getPreviousItem( item ).focus();\n\t}\n};\n\n/**\n * Add tag from input value\n */\nOO.ui.TagMultiselectWidget.prototype.addTagFromInput = function () {\n\tvar val = this.input.getValue(),\n\t\tisValid = this.isAllowedData( val );\n\n\tif ( !val ) {\n\t\treturn;\n\t}\n\n\tif ( isValid || this.allowDisplayInvalidTags ) {\n\t\tthis.clearInput();\n\t\tthis.addTag( val );\n\t}\n};\n\n/**\n * Clear the input\n */\nOO.ui.TagMultiselectWidget.prototype.clearInput = function () {\n\tthis.input.setValue( '' );\n};\n\n/**\n * Check whether the given value is a duplicate of an existing\n * tag already in the list.\n *\n * @param {string|Object} data Requested value\n * @return {boolean} Value is duplicate\n */\nOO.ui.TagMultiselectWidget.prototype.isDuplicateData = function ( data ) {\n\treturn !!this.findItemFromData( data );\n};\n\n/**\n * Check whether a given value is allowed to be added\n *\n * @param {string|Object} data Requested value\n * @return {boolean} Value is allowed\n */\nOO.ui.TagMultiselectWidget.prototype.isAllowedData = function ( data ) {\n\tif (\n\t\t!this.allowDuplicates &&\n\t\tthis.isDuplicateData( data )\n\t) {\n\t\treturn false;\n\t}\n\n\tif ( this.allowArbitrary ) {\n\t\treturn true;\n\t}\n\n\t// Check with allowed values\n\tif (\n\t\tthis.getAllowedValues().some( function ( value ) {\n\t\t\treturn data === value;\n\t\t} )\n\t) {\n\t\treturn true;\n\t}\n\n\treturn false;\n};\n\n/**\n * Get the allowed values list\n *\n * @return {string[]} Allowed data values\n */\nOO.ui.TagMultiselectWidget.prototype.getAllowedValues = function () {\n\treturn this.allowedValues;\n};\n\n/**\n * Add a value to the allowed values list\n *\n * @param {string} value Allowed data value\n */\nOO.ui.TagMultiselectWidget.prototype.addAllowedValue = function ( value ) {\n\tif ( this.allowedValues.indexOf( value ) === -1 ) {\n\t\tthis.allowedValues.push( value );\n\t}\n};\n\n/**\n * Get the datas of the currently selected items\n *\n * @return {string[]|Object[]} Datas of currently selected items\n */\nOO.ui.TagMultiselectWidget.prototype.getValue = function () {\n\treturn this.getItems()\n\t\t.filter( function ( item ) {\n\t\t\treturn item.isValid();\n\t\t} )\n\t\t.map( function ( item ) {\n\t\t\treturn item.getData();\n\t\t} );\n};\n\n/**\n * Set the value of this widget by datas.\n *\n * @param {string|string[]|Object|Object[]} valueObject An object representing the data\n *  and label of the value. If the widget allows arbitrary values,\n *  the items will be added as-is. Otherwise, the data value will\n *  be checked against allowedValues.\n *  This object must contain at least a data key. Example:\n *  { data: 'foo', label: 'Foo item' }\n *  For multiple items, use an array of objects. For example:\n *  [\n *     { data: 'foo', label: 'Foo item' },\n *     { data: 'bar', label: 'Bar item' }\n *  ]\n *  Value can also be added with plaintext array, for example:\n *  [ 'foo', 'bar', 'bla' ] or a single string, like 'foo'\n */\nOO.ui.TagMultiselectWidget.prototype.setValue = function ( valueObject ) {\n\tvalueObject = Array.isArray( valueObject ) ? valueObject : [ valueObject ];\n\n\tthis.clearItems();\n\tvalueObject.forEach( function ( obj ) {\n\t\tif ( typeof obj === 'string' ) {\n\t\t\tthis.addTag( obj );\n\t\t} else {\n\t\t\tthis.addTag( obj.data, obj.label );\n\t\t}\n\t}.bind( this ) );\n};\n\n/**\n * Add tag to the display area\n *\n * @param {string|Object} data Tag data\n * @param {string} [label] Tag label. If no label is provided, the\n *  stringified version of the data will be used instead.\n * @return {boolean} Item was added successfully\n */\nOO.ui.TagMultiselectWidget.prototype.addTag = function ( data, label ) {\n\tvar newItemWidget,\n\t\tisValid = this.isAllowedData( data );\n\n\tif ( this.isUnderLimit() && ( isValid || this.allowDisplayInvalidTags ) ) {\n\t\tnewItemWidget = this.createTagItemWidget( data, label );\n\t\tnewItemWidget.toggleValid( isValid );\n\t\tthis.addItems( [ newItemWidget ] );\n\t\treturn true;\n\t}\n\n\treturn false;\n};\n\n/**\n * Check whether the number of current tags is within the limit.\n *\n * @return {boolean} True if current tag count is within the limit or\n *  if 'tagLimit' is not set\n */\nOO.ui.TagMultiselectWidget.prototype.isUnderLimit = function () {\n\treturn !this.tagLimit ||\n\t\tthis.getItemCount() < this.tagLimit;\n};\n\n/**\n * Remove tag by its data property.\n *\n * @param {string|Object} data Tag data\n */\nOO.ui.TagMultiselectWidget.prototype.removeTagByData = function ( data ) {\n\tvar item = this.findItemFromData( data );\n\n\tthis.removeItems( [ item ] );\n};\n\n/**\n * Construct a OO.ui.TagItemWidget (or a subclass thereof) from given label and data.\n *\n * @protected\n * @param {string} data Item data\n * @param {string} label The label text.\n * @return {OO.ui.TagItemWidget}\n */\nOO.ui.TagMultiselectWidget.prototype.createTagItemWidget = function ( data, label ) {\n\tlabel = label || data;\n\n\treturn new OO.ui.TagItemWidget( { data: data, label: label } );\n};\n\n/**\n * Given an item, returns the item after it. If the item is already the\n * last item, return `this.input`. If no item is passed, returns the\n * very first item.\n *\n * @protected\n * @param {OO.ui.TagItemWidget} [item] Tag item\n * @return {OO.ui.Widget} The next widget available.\n */\nOO.ui.TagMultiselectWidget.prototype.getNextItem = function ( item ) {\n\tvar itemIndex = this.items.indexOf( item );\n\n\tif ( item === undefined || itemIndex === -1 ) {\n\t\treturn this.items[ 0 ];\n\t}\n\n\tif ( itemIndex === this.items.length - 1 ) { // Last item\n\t\tif ( this.hasInput ) {\n\t\t\treturn this.input;\n\t\t} else {\n\t\t\t// Return first item\n\t\t\treturn this.items[ 0 ];\n\t\t}\n\t} else {\n\t\treturn this.items[ itemIndex + 1 ];\n\t}\n};\n\n/**\n * Given an item, returns the item before it. If the item is already the\n * first item, return `this.input`. If no item is passed, returns the\n * very last item.\n *\n * @protected\n * @param {OO.ui.TagItemWidget} [item] Tag item\n * @return {OO.ui.Widget} The previous widget available.\n */\nOO.ui.TagMultiselectWidget.prototype.getPreviousItem = function ( item ) {\n\tvar itemIndex = this.items.indexOf( item );\n\n\tif ( item === undefined || itemIndex === -1 ) {\n\t\treturn this.items[ this.items.length - 1 ];\n\t}\n\n\tif ( itemIndex === 0 ) {\n\t\tif ( this.hasInput ) {\n\t\t\treturn this.input;\n\t\t} else {\n\t\t\t// Return the last item\n\t\t\treturn this.items[ this.items.length - 1 ];\n\t\t}\n\t} else {\n\t\treturn this.items[ itemIndex - 1 ];\n\t}\n};\n\n/**\n * Update the dimensions of the text input field to encompass all available area.\n * This is especially relevant for when the input is at the edge of a line\n * and should get smaller. The usual operation (as an inline-block with min-width)\n * does not work in that case, pushing the input downwards to the next line.\n *\n * @private\n */\nOO.ui.TagMultiselectWidget.prototype.updateInputSize = function () {\n\tvar $lastItem, direction, contentWidth, currentWidth, bestWidth;\n\tif ( this.inputPosition === 'inline' && !this.isDisabled() ) {\n\t\tif ( this.input.$input[ 0 ].scrollWidth === 0 ) {\n\t\t\t// Input appears to be attached but not visible.\n\t\t\t// Don't attempt to adjust its size, because our measurements\n\t\t\t// are going to fail anyway.\n\t\t\treturn;\n\t\t}\n\t\tthis.input.$input.css( 'width', '1em' );\n\t\t$lastItem = this.$group.children().last();\n\t\tdirection = OO.ui.Element.static.getDir( this.$handle );\n\n\t\t// Get the width of the input with the placeholder text as\n\t\t// the value and save it so that we don't keep recalculating\n\t\tif (\n\t\t\tthis.contentWidthWithPlaceholder === undefined &&\n\t\t\tthis.input.getValue() === '' &&\n\t\t\tthis.input.$input.attr( 'placeholder' ) !== undefined\n\t\t) {\n\t\t\tthis.input.setValue( this.input.$input.attr( 'placeholder' ) );\n\t\t\tthis.contentWidthWithPlaceholder = this.input.$input[ 0 ].scrollWidth;\n\t\t\tthis.input.setValue( '' );\n\n\t\t}\n\n\t\t// Always keep the input wide enough for the placeholder text\n\t\tcontentWidth = Math.max(\n\t\t\tthis.input.$input[ 0 ].scrollWidth,\n\t\t\t// undefined arguments in Math.max lead to NaN\n\t\t\t( this.contentWidthWithPlaceholder === undefined ) ?\n\t\t\t\t0 : this.contentWidthWithPlaceholder\n\t\t);\n\t\tcurrentWidth = this.input.$input.width();\n\n\t\tif ( contentWidth < currentWidth ) {\n\t\t\tthis.updateIfHeightChanged();\n\t\t\t// All is fine, don't perform expensive calculations\n\t\t\treturn;\n\t\t}\n\n\t\tif ( $lastItem.length === 0 ) {\n\t\t\tbestWidth = this.$content.innerWidth();\n\t\t} else {\n\t\t\tbestWidth = direction === 'ltr' ?\n\t\t\t\tthis.$content.innerWidth() - $lastItem.position().left - $lastItem.outerWidth() :\n\t\t\t\t$lastItem.position().left;\n\t\t}\n\n\t\t// Some safety margin for sanity, because I *really* don't feel like finding out where the\n\t\t// few pixels this is off by are coming from.\n\t\tbestWidth -= 13;\n\t\tif ( contentWidth > bestWidth ) {\n\t\t\t// This will result in the input getting shifted to the next line\n\t\t\tbestWidth = this.$content.innerWidth() - 13;\n\t\t}\n\t\tthis.input.$input.width( Math.floor( bestWidth ) );\n\t\tthis.updateIfHeightChanged();\n\t} else {\n\t\tthis.updateIfHeightChanged();\n\t}\n};\n\n/**\n * Determine if widget height changed, and if so,\n * emit the resize event. This is useful for when there are either\n * menus or popups attached to the bottom of the widget, to allow\n * them to change their positioning in case the widget moved down\n * or up.\n *\n * @private\n */\nOO.ui.TagMultiselectWidget.prototype.updateIfHeightChanged = function () {\n\tvar height = this.$element.height();\n\tif ( height !== this.height ) {\n\t\tthis.height = height;\n\t\tthis.emit( 'resize' );\n\t}\n};\n\n/**\n * Check whether all items in the widget are valid\n *\n * @return {boolean} Widget is valid\n */\nOO.ui.TagMultiselectWidget.prototype.checkValidity = function () {\n\treturn this.getItems().every( function ( item ) {\n\t\treturn item.isValid();\n\t} );\n};\n\n/**\n * Set the valid state of this item\n *\n * @param {boolean} [valid] Item is valid\n * @fires valid\n */\nOO.ui.TagMultiselectWidget.prototype.toggleValid = function ( valid ) {\n\tvalid = valid === undefined ? !this.valid : !!valid;\n\n\tif ( this.valid !== valid ) {\n\t\tthis.valid = valid;\n\n\t\tthis.setFlags( { invalid: !this.valid } );\n\n\t\tthis.emit( 'valid', this.valid );\n\t}\n};\n\n/**\n * Get the current valid state of the widget\n *\n * @return {boolean} Widget is valid\n */\nOO.ui.TagMultiselectWidget.prototype.isValid = function () {\n\treturn this.valid;\n};\n","/**\n * PopupTagMultiselectWidget is a {@link OO.ui.TagMultiselectWidget OO.ui.TagMultiselectWidget}\n * intended to use a popup. The popup can be configured to have a default input to insert values\n * into the widget.\n *\n *     @example\n *     // A PopupTagMultiselectWidget.\n *     var widget = new OO.ui.PopupTagMultiselectWidget();\n *     $( document.body ).append( widget.$element );\n *\n *     // Example: A PopupTagMultiselectWidget with an external popup.\n *     var popupInput = new OO.ui.TextInputWidget(),\n *         widget = new OO.ui.PopupTagMultiselectWidget( {\n *            popupInput: popupInput,\n *            popup: {\n *               $content: popupInput.$element\n *            }\n *         } );\n *     $( document.body ).append( widget.$element );\n *\n * @class\n * @extends OO.ui.TagMultiselectWidget\n * @mixins OO.ui.mixin.PopupElement\n *\n * @param {Object} config Configuration object\n * @cfg {jQuery} [$overlay] An overlay for the popup.\n *  See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.\n * @cfg {Object} [popup] Configuration options for the popup\n * @cfg {OO.ui.InputWidget} [popupInput] An input widget inside the popup that will be\n *  focused when the popup is opened and will be used as replacement for the\n *  general input in the widget.\n * @deprecated\n */\nOO.ui.PopupTagMultiselectWidget = function OoUiPopupTagMultiselectWidget( config ) {\n\tvar defaultInput,\n\t\tdefaultConfig = { popup: {} };\n\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.PopupTagMultiselectWidget.parent.call( this, $.extend( {\n\t\tinputPosition: 'none'\n\t}, config ) );\n\n\tthis.$overlay = ( config.$overlay === true ?\n\t\tOO.ui.getDefaultOverlay() : config.$overlay ) || this.$element;\n\n\tif ( !config.popup ) {\n\t\t// For the default base implementation, we give a popup\n\t\t// with an input widget inside it. For any other use cases\n\t\t// the popup needs to be populated externally and the\n\t\t// event handled to add tags separately and manually\n\t\tdefaultInput = new OO.ui.TextInputWidget();\n\n\t\tdefaultConfig.popupInput = defaultInput;\n\t\tdefaultConfig.popup.$content = defaultInput.$element;\n\t\tdefaultConfig.popup.padded = true;\n\n\t\tthis.$element.addClass( 'oo-ui-popupTagMultiselectWidget-defaultPopup' );\n\t}\n\n\t// Add overlay, and add that to the autoCloseIgnore\n\tdefaultConfig.popup.$overlay = this.$overlay;\n\tdefaultConfig.popup.$autoCloseIgnore = this.hasInput ?\n\t\tthis.input.$element.add( this.$overlay ) : this.$overlay;\n\n\t// Allow extending any of the above\n\tconfig = $.extend( defaultConfig, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.PopupElement.call( this, config );\n\n\tif ( this.hasInput ) {\n\t\tthis.input.$input.on( 'focus', this.popup.toggle.bind( this.popup, true ) );\n\t}\n\n\t// Configuration options\n\tthis.popupInput = config.popupInput;\n\tif ( this.popupInput ) {\n\t\tthis.popupInput.connect( this, {\n\t\t\tenter: 'onPopupInputEnter'\n\t\t} );\n\t}\n\n\t// Events\n\tthis.on( 'resize', this.popup.updateDimensions.bind( this.popup ) );\n\tthis.popup.connect( this, {\n\t\ttoggle: 'onPopupToggle'\n\t} );\n\tthis.$tabIndexed.on( 'focus', this.onFocus.bind( this ) );\n\n\t// Initialize\n\tthis.$element\n\t\t.append( this.popup.$element )\n\t\t.addClass( 'oo-ui-popupTagMultiselectWidget' );\n\n\t// Deprecation warning\n\tOO.ui.warnDeprecation( 'PopupTagMultiselectWidget: Deprecated widget. Use MenuTagMultiselectWidget instead. See T208821.' );\n};\n\n/* Initialization */\n\nOO.inheritClass( OO.ui.PopupTagMultiselectWidget, OO.ui.TagMultiselectWidget );\nOO.mixinClass( OO.ui.PopupTagMultiselectWidget, OO.ui.mixin.PopupElement );\n\n/* Methods */\n\n/**\n * Focus event handler.\n *\n * @private\n */\nOO.ui.PopupTagMultiselectWidget.prototype.onFocus = function () {\n\tthis.popup.toggle( true );\n};\n\n/**\n * Respond to popup toggle event\n *\n * @param {boolean} isVisible Popup is visible\n */\nOO.ui.PopupTagMultiselectWidget.prototype.onPopupToggle = function ( isVisible ) {\n\tif ( isVisible && this.popupInput ) {\n\t\tthis.popupInput.focus();\n\t}\n};\n\n/**\n * Respond to popup input enter event\n */\nOO.ui.PopupTagMultiselectWidget.prototype.onPopupInputEnter = function () {\n\tif ( this.popupInput ) {\n\t\tthis.addTagByPopupValue( this.popupInput.getValue() );\n\t\tthis.popupInput.setValue( '' );\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.PopupTagMultiselectWidget.prototype.onTagSelect = function ( item ) {\n\tif ( this.popupInput && this.allowEditTags ) {\n\t\tthis.popupInput.setValue( item.getData() );\n\t\tthis.removeItems( [ item ] );\n\n\t\tthis.popup.toggle( true );\n\t\tthis.popupInput.focus();\n\t} else {\n\t\t// Parent\n\t\tOO.ui.PopupTagMultiselectWidget.parent.prototype.onTagSelect.call( this, item );\n\t}\n};\n\n/**\n * Add a tag by the popup value.\n * Whatever is responsible for setting the value in the popup should call\n * this method to add a tag, or use the regular methods like #addTag or\n * #setValue directly.\n *\n * @param {string} data The value of item\n * @param {string} [label] The label of the tag. If not given, the data is used.\n */\nOO.ui.PopupTagMultiselectWidget.prototype.addTagByPopupValue = function ( data, label ) {\n\tthis.addTag( data, label );\n};\n","/**\n * MenuTagMultiselectWidget is a {@link OO.ui.TagMultiselectWidget OO.ui.TagMultiselectWidget}\n * intended to use a menu of selectable options.\n *\n *     @example\n *     // A basic MenuTagMultiselectWidget.\n *     var widget = new OO.ui.MenuTagMultiselectWidget( {\n *         inputPosition: 'outline',\n *         options: [\n *            { data: 'option1', label: 'Option 1', icon: 'tag' },\n *            { data: 'option2', label: 'Option 2' },\n *            { data: 'option3', label: 'Option 3' },\n *         ],\n *         selected: [ 'option1', 'option2' ]\n *     } );\n *     $( document.body ).append( widget.$element );\n *\n * @class\n * @extends OO.ui.TagMultiselectWidget\n *\n * @constructor\n * @param {Object} [config] Configuration object\n * @cfg {boolean} [clearInputOnChoose=true] Clear the text input value when a menu option is chosen\n * @cfg {Object} [menu] Configuration object for the menu widget\n * @cfg {jQuery} [$overlay] An overlay for the menu.\n *  See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.\n * @cfg {Object[]} [options=[]] Array of menu options in the format `{ data: …, label: … }`\n */\nOO.ui.MenuTagMultiselectWidget = function OoUiMenuTagMultiselectWidget( config ) {\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.MenuTagMultiselectWidget.parent.call( this, config );\n\n\tthis.$overlay = ( config.$overlay === true ?\n\t\tOO.ui.getDefaultOverlay() : config.$overlay ) || this.$element;\n\tthis.clearInputOnChoose = config.clearInputOnChoose === undefined ||\n\t\t!!config.clearInputOnChoose;\n\tthis.menu = this.createMenuWidget( $.extend( {\n\t\twidget: this,\n\t\tinput: this.hasInput ? this.input : null,\n\t\t$input: this.hasInput ? this.input.$input : null,\n\t\tfilterFromInput: !!this.hasInput,\n\t\thighlightOnFilter: true,\n\t\t$autoCloseIgnore: this.hasInput ?\n\t\t\tthis.input.$element : $( [] ),\n\t\t$floatableContainer: this.hasInput && this.inputPosition === 'outline' ?\n\t\t\tthis.input.$element : this.$element,\n\t\t$overlay: this.$overlay,\n\t\tdisabled: this.isDisabled()\n\t}, config.menu ) );\n\tthis.addOptions( config.options || [] );\n\n\t// Events\n\tthis.menu.connect( this, {\n\t\tchoose: 'onMenuChoose',\n\t\ttoggle: 'onMenuToggle'\n\t} );\n\tif ( this.hasInput ) {\n\t\tthis.input.connect( this, {\n\t\t\tchange: 'onInputChange'\n\t\t} );\n\t}\n\tthis.connect( this, {\n\t\tresize: 'onResize'\n\t} );\n\n\t// Initialization\n\tthis.$overlay.append( this.menu.$element );\n\tthis.$element.addClass( 'oo-ui-menuTagMultiselectWidget' );\n\t// Remove MenuSelectWidget's generic focus owner ARIA attribute\n\t// TODO: Should this widget have a `role` that is compatible with this attribute?\n\tthis.menu.$focusOwner.removeAttr( 'aria-expanded' );\n\t// TagMultiselectWidget already does this, but it doesn't work right because this.menu is\n\t// not yet set up while the parent constructor runs, and #getAllowedValues rejects everything.\n\tif ( config.selected ) {\n\t\tthis.setValue( config.selected );\n\t}\n};\n\n/* Initialization */\n\nOO.inheritClass( OO.ui.MenuTagMultiselectWidget, OO.ui.TagMultiselectWidget );\n\n/* Methods */\n\n/**\n * Respond to resize event\n */\nOO.ui.MenuTagMultiselectWidget.prototype.onResize = function () {\n\t// Reposition the menu\n\tthis.menu.position();\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuTagMultiselectWidget.prototype.onInputFocus = function () {\n\t// Parent method\n\tOO.ui.MenuTagMultiselectWidget.parent.prototype.onInputFocus.call( this );\n\n\tthis.menu.toggle( true );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuTagMultiselectWidget.prototype.onInputBlur = function () {\n\t// Parent method\n\tOO.ui.MenuTagMultiselectWidget.parent.prototype.onInputBlur.call( this );\n\n\tthis.menu.toggle( false );\n};\n\n/**\n * Respond to input change event\n */\nOO.ui.MenuTagMultiselectWidget.prototype.onInputChange = function () {\n\tthis.menu.toggle( true );\n};\n\n/**\n * Respond to menu choose event\n *\n * @param {OO.ui.OptionWidget} menuItem Chosen menu item\n */\nOO.ui.MenuTagMultiselectWidget.prototype.onMenuChoose = function ( menuItem ) {\n\tif ( this.hasInput && this.clearInputOnChoose ) {\n\t\tthis.input.setValue( '' );\n\t}\n\t// Add tag\n\tthis.addTag( menuItem.getData(), menuItem.getLabel() );\n};\n\n/**\n * Respond to menu toggle event. Reset item highlights on hide.\n *\n * @param {boolean} isVisible The menu is visible\n */\nOO.ui.MenuTagMultiselectWidget.prototype.onMenuToggle = function ( isVisible ) {\n\tif ( !isVisible ) {\n\t\tthis.menu.selectItem( null );\n\t\tthis.menu.highlightItem( null );\n\t}\n\tsetTimeout( function () {\n\t\t// Remove MenuSelectWidget's generic focus owner ARIA attribute\n\t\t// TODO: Should this widget have a `role` that is compatible with this attribute?\n\t\tthis.menu.$focusOwner.removeAttr( 'aria-expanded' );\n\t}.bind( this ) );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuTagMultiselectWidget.prototype.onTagSelect = function ( tagItem ) {\n\tvar menuItem = this.menu.findItemFromData( tagItem.getData() );\n\tif ( !this.allowArbitrary ) {\n\t\t// Override the base behavior from TagMultiselectWidget; the base behavior\n\t\t// in TagMultiselectWidget is to remove the tag to edit it in the input,\n\t\t// but in our case, we want to utilize the menu selection behavior, and\n\t\t// definitely not remove the item.\n\n\t\t// If there is an input that is used for filtering, erase the value so we don't filter\n\t\tif ( this.hasInput && this.menu.filterFromInput ) {\n\t\t\tthis.input.setValue( '' );\n\t\t}\n\n\t\t// Select the menu item\n\t\tthis.menu.selectItem( menuItem );\n\n\t\tthis.focus();\n\t} else {\n\t\t// Use the default\n\t\tOO.ui.MenuTagMultiselectWidget.parent.prototype.onTagSelect.call( this, tagItem );\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuTagMultiselectWidget.prototype.setDisabled = function ( isDisabled ) {\n\t// Parent method\n\tOO.ui.MenuTagMultiselectWidget.parent.prototype.setDisabled.call( this, isDisabled );\n\n\tif ( this.menu ) {\n\t\t// Protect against calling setDisabled() before the menu was initialized\n\t\tthis.menu.setDisabled( isDisabled );\n\t}\n};\n\n/**\n * Highlight the first selectable item in the menu, if configured.\n *\n * @private\n * @chainable\n */\nOO.ui.MenuTagMultiselectWidget.prototype.initializeMenuSelection = function () {\n\tif ( !this.menu.findSelectedItem() ) {\n\t\tthis.menu.highlightItem(\n\t\t\tthis.allowArbitrary ?\n\t\t\t\tnull :\n\t\t\t\tthis.menu.findFirstSelectableItem()\n\t\t);\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuTagMultiselectWidget.prototype.addTagFromInput = function () {\n\tvar val = this.input.getValue(),\n\t\t// Look for a highlighted item first\n\t\t// Then look for the element that fits the data\n\t\titem = this.menu.findHighlightedItem() || this.menu.findItemFromData( val ),\n\t\tdata = item ? item.getData() : val,\n\t\tisValid = this.isAllowedData( data );\n\n\t// Override the parent method so we add from the menu\n\t// rather than directly from the input\n\n\tif ( !val ) {\n\t\treturn;\n\t}\n\n\tif ( isValid || this.allowDisplayInvalidTags ) {\n\t\tthis.clearInput();\n\t\tif ( item ) {\n\t\t\tthis.addTag( data, item.getLabel() );\n\t\t} else {\n\t\t\tthis.addTag( val );\n\t\t}\n\t}\n};\n\n/**\n * Return the visible items in the menu. This is mainly used for when\n * the menu is filtering results.\n *\n * @return {OO.ui.MenuOptionWidget[]} Visible results\n */\nOO.ui.MenuTagMultiselectWidget.prototype.getMenuVisibleItems = function () {\n\treturn this.menu.getItems().filter( function ( menuItem ) {\n\t\treturn menuItem.isVisible();\n\t} );\n};\n\n/**\n * Create the menu for this widget. This is in a separate method so that\n * child classes can override this without polluting the constructor with\n * unnecessary extra objects that will be overidden.\n *\n * @param {Object} menuConfig Configuration options\n * @return {OO.ui.MenuSelectWidget} Menu widget\n */\nOO.ui.MenuTagMultiselectWidget.prototype.createMenuWidget = function ( menuConfig ) {\n\treturn new OO.ui.MenuSelectWidget( menuConfig );\n};\n\n/**\n * Add options to the menu\n *\n * @param {Object[]} menuOptions Object defining options\n */\nOO.ui.MenuTagMultiselectWidget.prototype.addOptions = function ( menuOptions ) {\n\tvar widget = this,\n\t\titems = menuOptions.map( function ( obj ) {\n\t\t\treturn widget.createMenuOptionWidget( obj.data, obj.label, obj.icon );\n\t\t} );\n\n\tthis.menu.addItems( items );\n};\n\n/**\n * Create a menu option widget.\n *\n * @param {string} data Item data\n * @param {string} [label] Item label\n * @param {string} [icon] Symbolic icon name\n * @return {OO.ui.OptionWidget} Option widget\n */\nOO.ui.MenuTagMultiselectWidget.prototype.createMenuOptionWidget = function ( data, label, icon ) {\n\treturn new OO.ui.MenuOptionWidget( {\n\t\tdata: data,\n\t\tlabel: label || data,\n\t\ticon: icon\n\t} );\n};\n\n/**\n * Get the menu\n *\n * @return {OO.ui.MenuSelectWidget} Menu\n */\nOO.ui.MenuTagMultiselectWidget.prototype.getMenu = function () {\n\treturn this.menu;\n};\n\n/**\n * Get the allowed values list\n *\n * @return {string[]} Allowed data values\n */\nOO.ui.MenuTagMultiselectWidget.prototype.getAllowedValues = function () {\n\tvar menuDatas = [];\n\tif ( this.menu ) {\n\t\t// If the parent constructor is calling us, we're not ready yet, this.menu is not set up.\n\t\tmenuDatas = this.menu.getItems().map( function ( menuItem ) {\n\t\t\treturn menuItem.getData();\n\t\t} );\n\t}\n\treturn this.allowedValues.concat( menuDatas );\n};\n","/**\n * SelectFileWidgets allow for selecting files, using the HTML5 File API. These\n * widgets can be configured with {@link OO.ui.mixin.IconElement icons}, {@link\n * OO.ui.mixin.IndicatorElement indicators} and {@link OO.ui.mixin.TitledElement titles}.\n * Please see the [OOUI documentation on MediaWiki] [1] for more information and examples.\n *\n *     @example\n *     // A file select widget.\n *     var selectFile = new OO.ui.SelectFileWidget();\n *     $( document.body ).append( selectFile.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.IndicatorElement\n * @mixins OO.ui.mixin.PendingElement\n * @mixins OO.ui.mixin.TabIndexedElement\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.TitledElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {string[]|null} [accept=null] MIME types to accept. null accepts all types.\n * @cfg {string} [placeholder] Text to display when no file is selected.\n * @cfg {string} [notsupported] Text to display when file support is missing in the browser.\n * @cfg {boolean} [droppable=true] Whether to accept files by drag and drop.\n * @cfg {boolean} [showDropTarget=false] Whether to show a drop target. Requires droppable to be\n *  true.\n * @cfg {number} [thumbnailSizeLimit=20] File size limit in MiB above which to not try and show a\n *  preview (for performance).\n */\nOO.ui.SelectFileWidget = function OoUiSelectFileWidget( config ) {\n\tvar dragHandler;\n\n\tthis.selectButton = new OO.ui.ButtonWidget( {\n\t\t$element: $( '<label>' ),\n\t\tclasses: [ 'oo-ui-selectFileWidget-selectButton' ],\n\t\tlabel: OO.ui.msg( 'ooui-selectfile-button-select' )\n\t} );\n\n\t// Configuration initialization\n\tconfig = $.extend( {\n\t\taccept: null,\n\t\tplaceholder: OO.ui.msg( 'ooui-selectfile-placeholder' ),\n\t\tnotsupported: OO.ui.msg( 'ooui-selectfile-not-supported' ),\n\t\tdroppable: true,\n\t\tshowDropTarget: false,\n\t\tthumbnailSizeLimit: 20,\n\t\t$tabIndexed: this.selectButton.$tabIndexed\n\t}, config );\n\n\t// Parent constructor\n\tOO.ui.SelectFileWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.IndicatorElement.call( this, config );\n\tOO.ui.mixin.PendingElement.call( this, $.extend( {\n\t\t$pending: this.$info\n\t}, config ) );\n\tOO.ui.mixin.TabIndexedElement.call( this, $.extend( {\n\t\t$tabIndexed: this.selectButton.$tabIndexed\n\t}, config ) );\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.TitledElement.call( this, config );\n\n\t// Properties\n\tthis.$info = $( '<span>' );\n\tthis.showDropTarget = config.droppable && config.showDropTarget;\n\tthis.thumbnailSizeLimit = config.thumbnailSizeLimit;\n\tthis.isSupported = this.constructor.static.isSupported();\n\tthis.currentFile = null;\n\tif ( Array.isArray( config.accept ) ) {\n\t\tthis.accept = config.accept;\n\t} else {\n\t\tthis.accept = null;\n\t}\n\tthis.placeholder = config.placeholder;\n\tthis.notsupported = config.notsupported;\n\tthis.onFileSelectedHandler = this.onFileSelected.bind( this );\n\n\tthis.selectButton.setDisabled( this.disabled || !this.isSupported );\n\n\tthis.clearButton = new OO.ui.ButtonWidget( {\n\t\tclasses: [ 'oo-ui-selectFileWidget-clearButton' ],\n\t\tframed: false,\n\t\ticon: 'clear',\n\t\tdisabled: this.disabled\n\t} );\n\n\t// Events\n\tthis.selectButton.$button.on( {\n\t\tkeypress: this.onKeyPress.bind( this )\n\t} );\n\tthis.clearButton.connect( this, {\n\t\tclick: 'onClearClick'\n\t} );\n\tif ( config.droppable ) {\n\t\tdragHandler = this.onDragEnterOrOver.bind( this );\n\t\tthis.$element.on( {\n\t\t\tdragenter: dragHandler,\n\t\t\tdragover: dragHandler,\n\t\t\tdragleave: this.onDragLeave.bind( this ),\n\t\t\tdrop: this.onDrop.bind( this )\n\t\t} );\n\t}\n\n\t// Initialization\n\tthis.addInput();\n\tthis.$label.addClass( 'oo-ui-selectFileWidget-label' );\n\tthis.$info\n\t\t.addClass( 'oo-ui-selectFileWidget-info' )\n\t\t.append( this.$icon, this.$label, this.clearButton.$element, this.$indicator );\n\n\tif ( this.showDropTarget ) {\n\t\tthis.selectButton.setIcon( 'upload' );\n\t\tthis.$thumbnail = $( '<div>' ).addClass( 'oo-ui-selectFileWidget-thumbnail' );\n\t\tthis.setPendingElement( this.$thumbnail );\n\t\tthis.$element\n\t\t\t.addClass( 'oo-ui-selectFileWidget-dropTarget oo-ui-selectFileWidget' )\n\t\t\t.on( {\n\t\t\t\tclick: this.onDropTargetClick.bind( this )\n\t\t\t} )\n\t\t\t.append(\n\t\t\t\tthis.$thumbnail,\n\t\t\t\tthis.$info,\n\t\t\t\tthis.selectButton.$element,\n\t\t\t\t$( '<span>' )\n\t\t\t\t\t.addClass( 'oo-ui-selectFileWidget-dropLabel' )\n\t\t\t\t\t.text( OO.ui.msg( 'ooui-selectfile-dragdrop-placeholder' ) )\n\t\t\t);\n\t} else {\n\t\tthis.$element\n\t\t\t.addClass( 'oo-ui-selectFileWidget' )\n\t\t\t.append( this.$info, this.selectButton.$element );\n\t}\n\tthis.updateUI();\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.SelectFileWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.SelectFileWidget, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.SelectFileWidget, OO.ui.mixin.IndicatorElement );\nOO.mixinClass( OO.ui.SelectFileWidget, OO.ui.mixin.PendingElement );\nOO.mixinClass( OO.ui.SelectFileWidget, OO.ui.mixin.TabIndexedElement );\nOO.mixinClass( OO.ui.SelectFileWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.SelectFileWidget, OO.ui.mixin.TitledElement );\n\n/* Static Properties */\n\n/**\n * Check if this widget is supported\n *\n * @static\n * @return {boolean}\n */\nOO.ui.SelectFileWidget.static.isSupported = function () {\n\tvar $input;\n\tif ( OO.ui.SelectFileWidget.static.isSupportedCache === null ) {\n\t\t$input = $( '<input>' ).attr( 'type', 'file' );\n\t\tOO.ui.SelectFileWidget.static.isSupportedCache = $input[ 0 ].files !== undefined;\n\t}\n\treturn OO.ui.SelectFileWidget.static.isSupportedCache;\n};\n\nOO.ui.SelectFileWidget.static.isSupportedCache = null;\n\n/* Events */\n\n/**\n * @event change\n *\n * A change event is emitted when the on/off state of the toggle changes.\n *\n * @param {File|null} value New value\n */\n\n/* Methods */\n\n/**\n * Get the current value of the field\n *\n * @return {File|null}\n */\nOO.ui.SelectFileWidget.prototype.getValue = function () {\n\treturn this.currentFile;\n};\n\n/**\n * Set the current value of the field\n *\n * @param {File|null} file File to select\n */\nOO.ui.SelectFileWidget.prototype.setValue = function ( file ) {\n\tif ( this.currentFile !== file ) {\n\t\tthis.currentFile = file;\n\t\tthis.updateUI();\n\t\tthis.emit( 'change', this.currentFile );\n\t}\n};\n\n/**\n * Update the user interface when a file is selected or unselected\n *\n * @protected\n */\nOO.ui.SelectFileWidget.prototype.updateUI = function () {\n\tvar $label;\n\tif ( !this.isSupported ) {\n\t\tthis.$element.addClass( 'oo-ui-selectFileWidget-notsupported' );\n\t\tthis.$element.removeClass( 'oo-ui-selectFileWidget-empty' );\n\t\tthis.setLabel( this.notsupported );\n\t} else {\n\t\tthis.$element.addClass( 'oo-ui-selectFileWidget-supported' );\n\t\tif ( this.currentFile ) {\n\t\t\tthis.$element.removeClass( 'oo-ui-selectFileWidget-empty' );\n\t\t\t$label = $( [] );\n\t\t\t$label = $label.add(\n\t\t\t\t$( '<span>' )\n\t\t\t\t\t.addClass( 'oo-ui-selectFileWidget-fileName' )\n\t\t\t\t\t.text( this.currentFile.name )\n\t\t\t);\n\t\t\tthis.setLabel( $label );\n\n\t\t\tif ( this.showDropTarget ) {\n\t\t\t\tthis.pushPending();\n\t\t\t\tthis.loadAndGetImageUrl().done( function ( url ) {\n\t\t\t\t\tthis.$thumbnail.css( 'background-image', 'url( ' + url + ' )' );\n\t\t\t\t}.bind( this ) ).fail( function () {\n\t\t\t\t\tthis.$thumbnail.append(\n\t\t\t\t\t\tnew OO.ui.IconWidget( {\n\t\t\t\t\t\t\ticon: 'attachment',\n\t\t\t\t\t\t\tclasses: [ 'oo-ui-selectFileWidget-noThumbnail-icon' ]\n\t\t\t\t\t\t} ).$element\n\t\t\t\t\t);\n\t\t\t\t}.bind( this ) ).always( function () {\n\t\t\t\t\tthis.popPending();\n\t\t\t\t}.bind( this ) );\n\t\t\t\tthis.$element.off( 'click' );\n\t\t\t}\n\t\t} else {\n\t\t\tif ( this.showDropTarget ) {\n\t\t\t\tthis.$element.off( 'click' );\n\t\t\t\tthis.$element.on( {\n\t\t\t\t\tclick: this.onDropTargetClick.bind( this )\n\t\t\t\t} );\n\t\t\t\tthis.$thumbnail\n\t\t\t\t\t.empty()\n\t\t\t\t\t.css( 'background-image', '' );\n\t\t\t}\n\t\t\tthis.$element.addClass( 'oo-ui-selectFileWidget-empty' );\n\t\t\tthis.setLabel( this.placeholder );\n\t\t}\n\t}\n};\n\n/**\n * If the selected file is an image, get its URL and load it.\n *\n * @return {jQuery.Promise} Promise resolves with the image URL after it has loaded\n */\nOO.ui.SelectFileWidget.prototype.loadAndGetImageUrl = function () {\n\tvar deferred = $.Deferred(),\n\t\tfile = this.currentFile,\n\t\treader = new FileReader();\n\n\tif (\n\t\tfile &&\n\t\t( OO.getProp( file, 'type' ) || '' ).indexOf( 'image/' ) === 0 &&\n\t\tfile.size < this.thumbnailSizeLimit * 1024 * 1024\n\t) {\n\t\treader.onload = function ( event ) {\n\t\t\tvar img = document.createElement( 'img' );\n\t\t\timg.addEventListener( 'load', function () {\n\t\t\t\tif (\n\t\t\t\t\timg.naturalWidth === 0 ||\n\t\t\t\t\timg.naturalHeight === 0 ||\n\t\t\t\t\timg.complete === false\n\t\t\t\t) {\n\t\t\t\t\tdeferred.reject();\n\t\t\t\t} else {\n\t\t\t\t\tdeferred.resolve( event.target.result );\n\t\t\t\t}\n\t\t\t} );\n\t\t\timg.src = event.target.result;\n\t\t};\n\t\treader.readAsDataURL( file );\n\t} else {\n\t\tdeferred.reject();\n\t}\n\n\treturn deferred.promise();\n};\n\n/**\n * Add the input to the widget\n *\n * @private\n */\nOO.ui.SelectFileWidget.prototype.addInput = function () {\n\tif ( this.$input ) {\n\t\tthis.$input.remove();\n\t}\n\n\tif ( !this.isSupported ) {\n\t\tthis.$input = null;\n\t\treturn;\n\t}\n\n\tthis.$input = $( '<input>' ).attr( 'type', 'file' );\n\tthis.$input.on( 'change', this.onFileSelectedHandler );\n\tthis.$input.on( 'click', function ( e ) {\n\t\t// Prevents dropTarget to get clicked which calls\n\t\t// a click on this input\n\t\te.stopPropagation();\n\t} );\n\tthis.$input.attr( {\n\t\ttabindex: -1\n\t} );\n\tif ( this.accept ) {\n\t\tthis.$input.attr( 'accept', this.accept.join( ', ' ) );\n\t}\n\tthis.selectButton.$button.append( this.$input );\n};\n\n/**\n * Determine if we should accept this file\n *\n * @private\n * @param {string} mimeType File MIME type\n * @return {boolean}\n */\nOO.ui.SelectFileWidget.prototype.isAllowedType = function ( mimeType ) {\n\tvar i, mimeTest;\n\n\tif ( !this.accept || !mimeType ) {\n\t\treturn true;\n\t}\n\n\tfor ( i = 0; i < this.accept.length; i++ ) {\n\t\tmimeTest = this.accept[ i ];\n\t\tif ( mimeTest === mimeType ) {\n\t\t\treturn true;\n\t\t} else if ( mimeTest.substr( -2 ) === '/*' ) {\n\t\t\tmimeTest = mimeTest.substr( 0, mimeTest.length - 1 );\n\t\t\tif ( mimeType.substr( 0, mimeTest.length ) === mimeTest ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false;\n};\n\n/**\n * Handle file selection from the input\n *\n * @private\n * @param {jQuery.Event} e\n */\nOO.ui.SelectFileWidget.prototype.onFileSelected = function ( e ) {\n\tvar file = OO.getProp( e.target, 'files', 0 ) || null;\n\n\tif ( file && !this.isAllowedType( file.type ) ) {\n\t\tfile = null;\n\t}\n\n\tthis.setValue( file );\n\tthis.addInput();\n};\n\n/**\n * Handle clear button click events.\n *\n * @private\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.SelectFileWidget.prototype.onClearClick = function () {\n\tthis.setValue( null );\n\treturn false;\n};\n\n/**\n * Handle key press events.\n *\n * @private\n * @param {jQuery.Event} e Key press event\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.SelectFileWidget.prototype.onKeyPress = function ( e ) {\n\tif ( this.isSupported && !this.isDisabled() && this.$input &&\n\t\t( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER )\n\t) {\n\t\tthis.$input.trigger( 'click' );\n\t\treturn false;\n\t}\n};\n\n/**\n * Handle drop target click events.\n *\n * @private\n * @param {jQuery.Event} e Key press event\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.SelectFileWidget.prototype.onDropTargetClick = function () {\n\tif ( this.isSupported && !this.isDisabled() && this.$input ) {\n\t\tthis.$input.trigger( 'click' );\n\t\treturn false;\n\t}\n};\n\n/**\n * Handle drag enter and over events\n *\n * @private\n * @param {jQuery.Event} e Drag event\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.SelectFileWidget.prototype.onDragEnterOrOver = function ( e ) {\n\tvar itemOrFile,\n\t\tdroppableFile = false,\n\t\tdt = e.originalEvent.dataTransfer;\n\n\te.preventDefault();\n\te.stopPropagation();\n\n\tif ( this.isDisabled() || !this.isSupported ) {\n\t\tthis.$element.removeClass( 'oo-ui-selectFileWidget-canDrop' );\n\t\tdt.dropEffect = 'none';\n\t\treturn false;\n\t}\n\n\t// DataTransferItem and File both have a type property, but in Chrome files\n\t// have no information at this point.\n\titemOrFile = OO.getProp( dt, 'items', 0 ) || OO.getProp( dt, 'files', 0 );\n\tif ( itemOrFile ) {\n\t\tif ( this.isAllowedType( itemOrFile.type ) ) {\n\t\t\tdroppableFile = true;\n\t\t}\n\t// dt.types is Array-like, but not an Array\n\t} else if ( Array.prototype.indexOf.call( OO.getProp( dt, 'types' ) || [], 'Files' ) !== -1 ) {\n\t\t// File information is not available at this point for security so just assume\n\t\t// it is acceptable for now.\n\t\t// https://bugzilla.mozilla.org/show_bug.cgi?id=640534\n\t\tdroppableFile = true;\n\t}\n\n\tthis.$element.toggleClass( 'oo-ui-selectFileWidget-canDrop', droppableFile );\n\tif ( !droppableFile ) {\n\t\tdt.dropEffect = 'none';\n\t}\n\n\treturn false;\n};\n\n/**\n * Handle drag leave events\n *\n * @private\n * @param {jQuery.Event} e Drag event\n */\nOO.ui.SelectFileWidget.prototype.onDragLeave = function () {\n\tthis.$element.removeClass( 'oo-ui-selectFileWidget-canDrop' );\n};\n\n/**\n * Handle drop events\n *\n * @private\n * @param {jQuery.Event} e Drop event\n * @return {undefined/boolean} False to prevent default if event is handled\n */\nOO.ui.SelectFileWidget.prototype.onDrop = function ( e ) {\n\tvar file = null,\n\t\tdt = e.originalEvent.dataTransfer;\n\n\te.preventDefault();\n\te.stopPropagation();\n\tthis.$element.removeClass( 'oo-ui-selectFileWidget-canDrop' );\n\n\tif ( this.isDisabled() || !this.isSupported ) {\n\t\treturn false;\n\t}\n\n\tfile = OO.getProp( dt, 'files', 0 );\n\tif ( file && !this.isAllowedType( file.type ) ) {\n\t\tfile = null;\n\t}\n\tif ( file ) {\n\t\tthis.setValue( file );\n\t}\n\n\treturn false;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.SelectFileWidget.prototype.setDisabled = function ( disabled ) {\n\tOO.ui.SelectFileWidget.parent.prototype.setDisabled.call( this, disabled );\n\tif ( this.selectButton ) {\n\t\tthis.selectButton.setDisabled( disabled );\n\t}\n\tif ( this.clearButton ) {\n\t\tthis.clearButton.setDisabled( disabled );\n\t}\n\treturn this;\n};\n","/**\n * SearchWidgets combine a {@link OO.ui.TextInputWidget text input field},\n * where users can type a search query, and a menu of search results,\n * which is displayed beneath the query field.\n * Unlike {@link OO.ui.mixin.LookupElement lookup menus}, search result menus are always visible\n * to the user. Users can choose an item from the menu or type a query into the text field to\n * search for a matching result item.\n * In general, search widgets are used inside a separate {@link OO.ui.Dialog dialog} window.\n *\n * Each time the query is changed, the search result menu is cleared and repopulated. Please see\n * the [OOUI demos][1] for an example.\n *\n * [1]: https://doc.wikimedia.org/oojs-ui/master/demos/#SearchInputWidget-type-search\n *\n * @class\n * @extends OO.ui.Widget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {string|jQuery} [placeholder] Placeholder text for query input\n * @cfg {string} [value] Initial query value\n */\nOO.ui.SearchWidget = function OoUiSearchWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.SearchWidget.parent.call( this, config );\n\n\t// Properties\n\tthis.query = new OO.ui.TextInputWidget( {\n\t\ticon: 'search',\n\t\tplaceholder: config.placeholder,\n\t\tvalue: config.value\n\t} );\n\tthis.results = new OO.ui.SelectWidget();\n\tthis.$query = $( '<div>' );\n\tthis.$results = $( '<div>' );\n\n\t// Events\n\tthis.query.connect( this, {\n\t\tchange: 'onQueryChange',\n\t\tenter: 'onQueryEnter'\n\t} );\n\tthis.query.$input.on( 'keydown', this.onQueryKeydown.bind( this ) );\n\n\t// Initialization\n\tthis.$query\n\t\t.addClass( 'oo-ui-searchWidget-query' )\n\t\t.append( this.query.$element );\n\tthis.$results\n\t\t.addClass( 'oo-ui-searchWidget-results' )\n\t\t.append( this.results.$element );\n\tthis.$element\n\t\t.addClass( 'oo-ui-searchWidget' )\n\t\t.append( this.$results, this.$query );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.SearchWidget, OO.ui.Widget );\n\n/* Methods */\n\n/**\n * Handle query key down events.\n *\n * @private\n * @param {jQuery.Event} e Key down event\n */\nOO.ui.SearchWidget.prototype.onQueryKeydown = function ( e ) {\n\tvar highlightedItem, nextItem,\n\t\tdir = e.which === OO.ui.Keys.DOWN ? 1 : ( e.which === OO.ui.Keys.UP ? -1 : 0 );\n\n\tif ( dir ) {\n\t\thighlightedItem = this.results.findHighlightedItem();\n\t\tif ( !highlightedItem ) {\n\t\t\thighlightedItem = this.results.findSelectedItem();\n\t\t}\n\t\tnextItem = this.results.findRelativeSelectableItem( highlightedItem, dir );\n\t\tthis.results.highlightItem( nextItem );\n\t\tnextItem.scrollElementIntoView();\n\t}\n};\n\n/**\n * Handle select widget select events.\n *\n * Clears existing results. Subclasses should repopulate items according to new query.\n *\n * @private\n * @param {string} value New value\n */\nOO.ui.SearchWidget.prototype.onQueryChange = function () {\n\t// Reset\n\tthis.results.clearItems();\n};\n\n/**\n * Handle select widget enter key events.\n *\n * Chooses highlighted item.\n *\n * @private\n * @param {string} value New value\n */\nOO.ui.SearchWidget.prototype.onQueryEnter = function () {\n\tvar highlightedItem = this.results.findHighlightedItem();\n\tif ( highlightedItem ) {\n\t\tthis.results.chooseItem( highlightedItem );\n\t}\n};\n\n/**\n * Get the query input.\n *\n * @return {OO.ui.TextInputWidget} Query input\n */\nOO.ui.SearchWidget.prototype.getQuery = function () {\n\treturn this.query;\n};\n\n/**\n * Get the search results menu.\n *\n * @return {OO.ui.SelectWidget} Menu of search results\n */\nOO.ui.SearchWidget.prototype.getResults = function () {\n\treturn this.results;\n};\n","}( OO ) );\n"]}
\ No newline at end of file
+{"version":3,"sources":["../src/intro.js.txt","../src/mixins/DraggableElement.js","../src/mixins/DraggableGroupElement.js","../src/mixins/RequestManager.js","../src/mixins/LookupElement.js","../src/layouts/TabPanelLayout.js","../src/layouts/PageLayout.js","../src/layouts/StackLayout.js","../src/layouts/MenuLayout.js","../src/layouts/BookletLayout.js","../src/layouts/IndexLayout.js","../src/widgets/ToggleWidget.js","../src/widgets/ToggleButtonWidget.js","../src/widgets/ToggleSwitchWidget.js","../src/widgets/OutlineControlsWidget.js","../src/widgets/OutlineOptionWidget.js","../src/widgets/OutlineSelectWidget.js","../src/widgets/ButtonOptionWidget.js","../src/widgets/ButtonSelectWidget.js","../src/widgets/TabOptionWidget.js","../src/widgets/TabSelectWidget.js","../src/widgets/TagItemWidget.js","../src/widgets/TagMultiselectWidget.js","../src/widgets/PopupTagMultiselectWidget.js","../src/widgets/MenuTagMultiselectWidget.js","../src/widgets/SelectFileWidget.js","../src/widgets/SearchWidget.js","../src/outro.js.txt"],"names":[],"mappings":"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","file":"oojs-ui-widgets.js","sourcesContent":["( function ( OO ) {\n\n'use strict';\n","/**\n * DraggableElement is a mixin class used to create elements that can be clicked\n * and dragged by a mouse to a new position within a group. This class must be used\n * in conjunction with OO.ui.mixin.DraggableGroupElement, which provides a container for\n * the draggable elements.\n *\n * @abstract\n * @class\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$handle] The part of the element which can be used for dragging, defaults to\n *  the whole element\n * @cfg {boolean} [draggable] The items are draggable. This can change with #toggleDraggable\n *  but the draggable state should be called from the DraggableGroupElement, which updates\n *  the whole group\n */\nOO.ui.mixin.DraggableElement = function OoUiMixinDraggableElement( config ) {\n\tconfig = config || {};\n\n\t// Properties\n\tthis.index = null;\n\tthis.$handle = config.$handle || this.$element;\n\tthis.wasHandleUsed = null;\n\n\t// Initialize and events\n\tthis.$element\n\t\t.addClass( 'oo-ui-draggableElement' )\n\t\t.on( {\n\t\t\tmousedown: this.onDragMouseDown.bind( this ),\n\t\t\tdragstart: this.onDragStart.bind( this ),\n\t\t\tdragover: this.onDragOver.bind( this ),\n\t\t\tdragend: this.onDragEnd.bind( this ),\n\t\t\tdrop: this.onDrop.bind( this )\n\t\t} );\n\tthis.$handle.addClass( 'oo-ui-draggableElement-handle' );\n\tthis.toggleDraggable( config.draggable === undefined ? true : !!config.draggable );\n};\n\nOO.initClass( OO.ui.mixin.DraggableElement );\n\n/* Events */\n\n/**\n * @event dragstart\n *\n * A dragstart event is emitted when the user clicks and begins dragging an item.\n * @param {OO.ui.mixin.DraggableElement} item The item the user has clicked and is dragging with\n *  the mouse.\n */\n\n/**\n * @event dragend\n * A dragend event is emitted when the user drags an item and releases the mouse,\n * thus terminating the drag operation.\n */\n\n/**\n * @event drop\n * A drop event is emitted when the user drags an item and then releases the mouse button\n * over a valid target.\n */\n\n/* Static Properties */\n\n/**\n * @inheritdoc OO.ui.mixin.ButtonElement\n */\nOO.ui.mixin.DraggableElement.static.cancelButtonMouseDownEvents = false;\n\n/* Methods */\n\n/**\n * Change the draggable state of this widget.\n * This allows users to temporarily halt the dragging operations.\n *\n * @param {boolean} isDraggable Widget supports draggable operations\n * @fires draggable\n */\nOO.ui.mixin.DraggableElement.prototype.toggleDraggable = function ( isDraggable ) {\n\tisDraggable = isDraggable !== undefined ? !!isDraggable : !this.draggable;\n\n\tif ( this.draggable !== isDraggable ) {\n\t\tthis.draggable = isDraggable;\n\n\t\tthis.$handle.toggleClass( 'oo-ui-draggableElement-undraggable', !this.draggable );\n\n\t\t// We make the entire element draggable, not just the handle, so that\n\t\t// the whole element appears to move. wasHandleUsed prevents drags from\n\t\t// starting outside the handle\n\t\tthis.$element.prop( 'draggable', this.draggable );\n\t}\n};\n\n/**\n * Check the draggable state of this widget.\n *\n * @return {boolean} Widget supports draggable operations\n */\nOO.ui.mixin.DraggableElement.prototype.isDraggable = function () {\n\treturn this.draggable;\n};\n\n/**\n * Respond to mousedown event.\n *\n * @private\n * @param {jQuery.Event} e Drag event\n */\nOO.ui.mixin.DraggableElement.prototype.onDragMouseDown = function ( e ) {\n\tif ( !this.isDraggable() ) {\n\t\treturn;\n\t}\n\n\tthis.wasHandleUsed =\n\t\t// Optimization: if the handle is the whole element this is always true\n\t\tthis.$handle[ 0 ] === this.$element[ 0 ] ||\n\t\t// Check the mousedown occurred inside the handle\n\t\tOO.ui.contains( this.$handle[ 0 ], e.target, true );\n};\n\n/**\n * Respond to dragstart event.\n *\n * @private\n * @param {jQuery.Event} e Drag event\n * @return {boolean} False if the event is cancelled\n * @fires dragstart\n */\nOO.ui.mixin.DraggableElement.prototype.onDragStart = function ( e ) {\n\tvar element = this,\n\t\tdataTransfer = e.originalEvent.dataTransfer;\n\n\tif ( !this.wasHandleUsed || !this.isDraggable() ) {\n\t\treturn false;\n\t}\n\n\t// Define drop effect\n\tdataTransfer.dropEffect = 'none';\n\tdataTransfer.effectAllowed = 'move';\n\t// Support: Firefox\n\t// We must set up a dataTransfer data property or Firefox seems to\n\t// ignore the fact the element is draggable.\n\ttry {\n\t\tdataTransfer.setData( 'application-x/OOUI-draggable', this.getIndex() );\n\t} catch ( err ) {\n\t\t// The above is only for Firefox. Move on if it fails.\n\t}\n\t// Briefly add a 'clone' class to style the browser's native drag image\n\tthis.$element.addClass( 'oo-ui-draggableElement-clone' );\n\t// Add placeholder class after the browser has rendered the clone\n\tsetTimeout( function () {\n\t\telement.$element\n\t\t\t.removeClass( 'oo-ui-draggableElement-clone' )\n\t\t\t.addClass( 'oo-ui-draggableElement-placeholder' );\n\t} );\n\t// Emit event\n\tthis.emit( 'dragstart', this );\n\treturn true;\n};\n\n/**\n * Respond to dragend event.\n *\n * @private\n * @fires dragend\n */\nOO.ui.mixin.DraggableElement.prototype.onDragEnd = function () {\n\tthis.$element.removeClass( 'oo-ui-draggableElement-placeholder' );\n\tthis.emit( 'dragend' );\n};\n\n/**\n * Handle drop event.\n *\n * @private\n * @param {jQuery.Event} e Drop event\n * @fires drop\n */\nOO.ui.mixin.DraggableElement.prototype.onDrop = function ( e ) {\n\te.preventDefault();\n\tthis.emit( 'drop', e );\n};\n\n/**\n * In order for drag/drop to work, the dragover event must\n * return false and stop propogation.\n *\n * @param {jQuery.Event} e Drag event\n * @private\n */\nOO.ui.mixin.DraggableElement.prototype.onDragOver = function ( e ) {\n\te.preventDefault();\n};\n\n/**\n * Set item index.\n * Store it in the DOM so we can access from the widget drag event.\n *\n * @private\n * @param {number} index Item index\n */\nOO.ui.mixin.DraggableElement.prototype.setIndex = function ( index ) {\n\tif ( this.index !== index ) {\n\t\tthis.index = index;\n\t\tthis.$element.data( 'index', index );\n\t}\n};\n\n/**\n * Get item index.\n *\n * @private\n * @return {number} Item index\n */\nOO.ui.mixin.DraggableElement.prototype.getIndex = function () {\n\treturn this.index;\n};\n","/**\n * DraggableGroupElement is a mixin class used to create a group element to\n * contain draggable elements, which are items that can be clicked and dragged by a mouse.\n * The class is used with OO.ui.mixin.DraggableElement.\n *\n * @abstract\n * @class\n * @mixins OO.ui.mixin.GroupElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {string} [orientation] Item orientation: 'horizontal' or 'vertical'. The orientation\n *  should match the layout of the items. Items displayed in a single row\n *  or in several rows should use horizontal orientation. The vertical orientation should only be\n *  used when the items are displayed in a single column. Defaults to 'vertical'\n * @cfg {boolean} [draggable] The items are draggable. This can change with #toggleDraggable\n */\nOO.ui.mixin.DraggableGroupElement = function OoUiMixinDraggableGroupElement( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.mixin.GroupElement.call( this, config );\n\n\t// Properties\n\tthis.orientation = config.orientation || 'vertical';\n\tthis.dragItem = null;\n\tthis.itemKeys = {};\n\tthis.dir = null;\n\tthis.itemsOrder = null;\n\tthis.draggable = config.draggable === undefined ? true : !!config.draggable;\n\n\t// Events\n\tthis.aggregate( {\n\t\tdragstart: 'itemDragStart',\n\t\tdragend: 'itemDragEnd',\n\t\tdrop: 'itemDrop'\n\t} );\n\tthis.connect( this, {\n\t\titemDragStart: 'onItemDragStart',\n\t\titemDrop: 'onItemDropOrDragEnd',\n\t\titemDragEnd: 'onItemDropOrDragEnd'\n\t} );\n\n\t// Initialize\n\tif ( Array.isArray( config.items ) ) {\n\t\tthis.addItems( config.items );\n\t}\n\tthis.$element\n\t\t.addClass( 'oo-ui-draggableGroupElement' )\n\t\t.toggleClass( 'oo-ui-draggableGroupElement-horizontal', this.orientation === 'horizontal' );\n};\n\n/* Setup */\nOO.mixinClass( OO.ui.mixin.DraggableGroupElement, OO.ui.mixin.GroupElement );\n\n/* Events */\n\n/**\n * An item has been dragged to a new position, but not yet dropped.\n *\n * @event drag\n * @param {OO.ui.mixin.DraggableElement} item Dragged item\n * @param {number} [newIndex] New index for the item\n */\n\n/**\n * An item has been dropped at a new position.\n *\n * @event reorder\n * @param {OO.ui.mixin.DraggableElement} item Reordered item\n * @param {number} [newIndex] New index for the item\n */\n\n/**\n * Draggable state of this widget has changed.\n *\n * @event draggable\n * @param {boolean} [draggable] Widget is draggable\n */\n\n/* Methods */\n\n/**\n * Change the draggable state of this widget.\n * This allows users to temporarily halt the dragging operations.\n *\n * @param {boolean} isDraggable Widget supports draggable operations\n * @fires draggable\n */\nOO.ui.mixin.DraggableGroupElement.prototype.toggleDraggable = function ( isDraggable ) {\n\tisDraggable = isDraggable !== undefined ? !!isDraggable : !this.draggable;\n\n\tif ( this.draggable !== isDraggable ) {\n\t\tthis.draggable = isDraggable;\n\n\t\t// Tell the items their draggable state changed\n\t\tthis.getItems().forEach( function ( item ) {\n\t\t\titem.toggleDraggable( this.draggable );\n\t\t}.bind( this ) );\n\n\t\t// Emit event\n\t\tthis.emit( 'draggable', this.draggable );\n\t}\n};\n\n/**\n * Check the draggable state of this widget\n *\n * @return {boolean} Widget supports draggable operations\n */\nOO.ui.mixin.DraggableGroupElement.prototype.isDraggable = function () {\n\treturn this.draggable;\n};\n\n/**\n * Respond to item drag start event\n *\n * @private\n * @param {OO.ui.mixin.DraggableElement} item Dragged item\n */\nOO.ui.mixin.DraggableGroupElement.prototype.onItemDragStart = function ( item ) {\n\tif ( !this.isDraggable() ) {\n\t\treturn;\n\t}\n\t// Make a shallow copy of this.items so we can re-order it during previews\n\t// without affecting the original array.\n\tthis.itemsOrder = this.items.slice();\n\tthis.updateIndexes();\n\tif ( this.orientation === 'horizontal' ) {\n\t\t// Calculate and cache directionality on drag start - it's a little\n\t\t// expensive and it shouldn't change while dragging.\n\t\tthis.dir = this.$element.css( 'direction' );\n\t}\n\tthis.setDragItem( item );\n};\n\n/**\n * Update the index properties of the items\n */\nOO.ui.mixin.DraggableGroupElement.prototype.updateIndexes = function () {\n\tvar i, len;\n\n\t// Map the index of each object\n\tfor ( i = 0, len = this.itemsOrder.length; i < len; i++ ) {\n\t\tthis.itemsOrder[ i ].setIndex( i );\n\t}\n};\n\n/**\n * Handle drop or dragend event and switch the order of the items accordingly\n *\n * @private\n * @param {OO.ui.mixin.DraggableElement} item Dropped item\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.DraggableGroupElement.prototype.onItemDropOrDragEnd = function () {\n\tvar targetIndex, originalIndex,\n\t\titem = this.getDragItem();\n\n\t// TODO: Figure out a way to configure a list of legally droppable\n\t// elements even if they are not yet in the list\n\tif ( item ) {\n\t\toriginalIndex = this.items.indexOf( item );\n\t\t// If the item has moved forward, add one to the index to account for the left shift\n\t\ttargetIndex = item.getIndex() + ( item.getIndex() > originalIndex ? 1 : 0 );\n\t\tif ( targetIndex !== originalIndex ) {\n\t\t\tthis.reorder( this.getDragItem(), targetIndex );\n\t\t\tthis.emit( 'reorder', this.getDragItem(), targetIndex );\n\t\t}\n\t\tthis.updateIndexes();\n\t}\n\tthis.unsetDragItem();\n\t// Return false to prevent propogation\n\treturn false;\n};\n\n/**\n * Respond to dragover event\n *\n * @private\n * @param {jQuery.Event} e Dragover event\n * @fires reorder\n */\nOO.ui.mixin.DraggableGroupElement.prototype.onDragOver = function ( e ) {\n\tvar overIndex, targetIndex,\n\t\titem = this.getDragItem(),\n\t\tdragItemIndex = item.getIndex();\n\n\t// Get the OptionWidget item we are dragging over\n\toverIndex = $( e.target ).closest( '.oo-ui-draggableElement' ).data( 'index' );\n\n\tif ( overIndex !== undefined && overIndex !== dragItemIndex ) {\n\t\ttargetIndex = overIndex + ( overIndex > dragItemIndex ? 1 : 0 );\n\n\t\tif ( targetIndex > 0 ) {\n\t\t\tthis.$group.children().eq( targetIndex - 1 ).after( item.$element );\n\t\t} else {\n\t\t\tthis.$group.prepend( item.$element );\n\t\t}\n\t\t// Move item in itemsOrder array\n\t\tthis.itemsOrder.splice( overIndex, 0,\n\t\t\tthis.itemsOrder.splice( dragItemIndex, 1 )[ 0 ]\n\t\t);\n\t\tthis.updateIndexes();\n\t\tthis.emit( 'drag', item, targetIndex );\n\t}\n\t// Prevent default\n\te.preventDefault();\n};\n\n/**\n * Reorder the items in the group\n *\n * @param {OO.ui.mixin.DraggableElement} item Reordered item\n * @param {number} newIndex New index\n */\nOO.ui.mixin.DraggableGroupElement.prototype.reorder = function ( item, newIndex ) {\n\tthis.addItems( [ item ], newIndex );\n};\n\n/**\n * Set a dragged item\n *\n * @param {OO.ui.mixin.DraggableElement} item Dragged item\n */\nOO.ui.mixin.DraggableGroupElement.prototype.setDragItem = function ( item ) {\n\tif ( this.dragItem !== item ) {\n\t\tthis.dragItem = item;\n\t\tthis.$element.on( 'dragover', this.onDragOver.bind( this ) );\n\t\tthis.$element.addClass( 'oo-ui-draggableGroupElement-dragging' );\n\t}\n};\n\n/**\n * Unset the current dragged item\n */\nOO.ui.mixin.DraggableGroupElement.prototype.unsetDragItem = function () {\n\tif ( this.dragItem ) {\n\t\tthis.dragItem = null;\n\t\tthis.$element.off( 'dragover' );\n\t\tthis.$element.removeClass( 'oo-ui-draggableGroupElement-dragging' );\n\t}\n};\n\n/**\n * Get the item that is currently being dragged.\n *\n * @return {OO.ui.mixin.DraggableElement|null} The currently dragged item, or `null` if no item is\n *  being dragged\n */\nOO.ui.mixin.DraggableGroupElement.prototype.getDragItem = function () {\n\treturn this.dragItem;\n};\n","/**\n * RequestManager is a mixin that manages the lifecycle of a promise-backed request for a widget,\n * such as the {@link OO.ui.mixin.LookupElement}.\n *\n * @class\n * @abstract\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [showPendingRequest=true] Show pending state while request data is being fetched.\n *  Requires widget to have also mixed in {@link OO.ui.mixin.PendingElement}.\n */\nOO.ui.mixin.RequestManager = function OoUiMixinRequestManager( config ) {\n\tthis.requestCache = {};\n\tthis.requestQuery = null;\n\tthis.requestRequest = null;\n\tthis.showPendingRequest = !!this.pushPending && config.showPendingRequest !== false;\n};\n\n/* Setup */\n\nOO.initClass( OO.ui.mixin.RequestManager );\n\n/**\n * Get request results for the current query.\n *\n * @return {jQuery.Promise} Promise object which will be passed response data as the first argument\n *  of the done event. If the request was aborted to make way for a subsequent request, this\n *  promise may not be rejected, depending on what jQuery feels like doing.\n */\nOO.ui.mixin.RequestManager.prototype.getRequestData = function () {\n\tvar widget = this,\n\t\tvalue = this.getRequestQuery(),\n\t\tdeferred = $.Deferred(),\n\t\tourRequest;\n\n\tthis.abortRequest();\n\tif ( Object.prototype.hasOwnProperty.call( this.requestCache, value ) ) {\n\t\tdeferred.resolve( this.requestCache[ value ] );\n\t} else {\n\t\tif ( this.showPendingRequest ) {\n\t\t\tthis.pushPending();\n\t\t}\n\t\tthis.requestQuery = value;\n\t\tourRequest = this.requestRequest = this.getRequest();\n\t\tourRequest\n\t\t\t.always( function () {\n\t\t\t\t// We need to pop pending even if this is an old request, otherwise\n\t\t\t\t// the widget will remain pending forever.\n\t\t\t\t// TODO: this assumes that an aborted request will fail or succeed soon after\n\t\t\t\t// being aborted, or at least eventually. It would be nice if we could popPending()\n\t\t\t\t// at abort time, but only if we knew that we hadn't already called popPending()\n\t\t\t\t// for that request.\n\t\t\t\tif ( widget.showPendingRequest ) {\n\t\t\t\t\twidget.popPending();\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.done( function ( response ) {\n\t\t\t\t// If this is an old request (and aborting it somehow caused it to still succeed),\n\t\t\t\t// ignore its success completely\n\t\t\t\tif ( ourRequest === widget.requestRequest ) {\n\t\t\t\t\twidget.requestQuery = null;\n\t\t\t\t\twidget.requestRequest = null;\n\t\t\t\t\twidget.requestCache[ value ] =\n\t\t\t\t\t\twidget.getRequestCacheDataFromResponse( response );\n\t\t\t\t\tdeferred.resolve( widget.requestCache[ value ] );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.fail( function () {\n\t\t\t\t// If this is an old request (or a request failing because it's being aborted),\n\t\t\t\t// ignore its failure completely\n\t\t\t\tif ( ourRequest === widget.requestRequest ) {\n\t\t\t\t\twidget.requestQuery = null;\n\t\t\t\t\twidget.requestRequest = null;\n\t\t\t\t\tdeferred.reject();\n\t\t\t\t}\n\t\t\t} );\n\t}\n\treturn deferred.promise();\n};\n\n/**\n * Abort the currently pending request, if any.\n *\n * @private\n */\nOO.ui.mixin.RequestManager.prototype.abortRequest = function () {\n\tvar oldRequest = this.requestRequest;\n\tif ( oldRequest ) {\n\t\t// First unset this.requestRequest to the fail handler will notice\n\t\t// that the request is no longer current\n\t\tthis.requestRequest = null;\n\t\tthis.requestQuery = null;\n\t\toldRequest.abort();\n\t}\n};\n\n/**\n * Get the query to be made.\n *\n * @protected\n * @method\n * @abstract\n * @return {string} query to be used\n */\nOO.ui.mixin.RequestManager.prototype.getRequestQuery = null;\n\n/**\n * Get a new request object of the current query value.\n *\n * @protected\n * @method\n * @abstract\n * @return {jQuery.Promise} jQuery AJAX object, or promise object with an .abort() method\n */\nOO.ui.mixin.RequestManager.prototype.getRequest = null;\n\n/**\n * Pre-process data returned by the request from #getRequest.\n *\n * The return value of this function will be cached, and any further queries for the given value\n * will use the cache rather than doing API requests.\n *\n * @protected\n * @method\n * @abstract\n * @param {Mixed} response Response from server\n * @return {Mixed} Cached result data\n */\nOO.ui.mixin.RequestManager.prototype.getRequestCacheDataFromResponse = null;\n","/**\n * LookupElement is a mixin that creates a {@link OO.ui.MenuSelectWidget menu} of suggested\n * values for a {@link OO.ui.TextInputWidget text input widget}. Suggested values are based on\n * the characters the user types into the text input field and, in general, the menu is only\n * displayed when the user types. If a suggested value is chosen from the lookup menu, that value\n * becomes the value of the input field.\n *\n * Note that a new menu of suggested items is displayed when a value is chosen from the\n * lookup menu. If this is not the desired behavior, disable lookup menus with the\n * #setLookupsDisabled method, then set the value, then re-enable lookups.\n *\n * See the [OOUI demos][1] for an example.\n *\n * [1]: https://doc.wikimedia.org/oojs-ui/master/demos/#LookupElement-try-inputting-an-integer\n *\n * @class\n * @abstract\n * @mixins OO.ui.mixin.RequestManager\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {jQuery} [$overlay] Overlay for the lookup menu; defaults to relative positioning.\n *  See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.\n * @cfg {jQuery} [$container=this.$element] The container element. The lookup menu is rendered\n *  beneath the specified element.\n * @cfg {Object} [menu] Configuration options to pass to\n *  {@link OO.ui.MenuSelectWidget menu select widget}\n * @cfg {boolean} [allowSuggestionsWhenEmpty=false] Request and display a lookup menu when the\n *  text input is empty.\n *  By default, the lookup menu is not generated and displayed until the user begins to type.\n * @cfg {boolean} [highlightFirst=true] Whether the first lookup result should be highlighted\n *  (so, that the user can take it over into the input with simply pressing return) automatically\n *  or not.\n */\nOO.ui.mixin.LookupElement = function OoUiMixinLookupElement( config ) {\n\t// Configuration initialization\n\tconfig = $.extend( { highlightFirst: true }, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.RequestManager.call( this, config );\n\n\t// Properties\n\tthis.$overlay = ( config.$overlay === true ?\n\t\tOO.ui.getDefaultOverlay() : config.$overlay ) || this.$element;\n\tthis.lookupMenu = new OO.ui.MenuSelectWidget( $.extend( {\n\t\twidget: this,\n\t\tinput: this,\n\t\t$floatableContainer: config.$container || this.$element\n\t}, config.menu ) );\n\n\tthis.allowSuggestionsWhenEmpty = config.allowSuggestionsWhenEmpty || false;\n\n\tthis.lookupsDisabled = false;\n\tthis.lookupInputFocused = false;\n\tthis.lookupHighlightFirstItem = config.highlightFirst;\n\n\t// Events\n\tthis.$input.on( {\n\t\tfocus: this.onLookupInputFocus.bind( this ),\n\t\tblur: this.onLookupInputBlur.bind( this ),\n\t\tmousedown: this.onLookupInputMouseDown.bind( this )\n\t} );\n\tthis.connect( this, {\n\t\tchange: 'onLookupInputChange'\n\t} );\n\tthis.lookupMenu.connect( this, {\n\t\ttoggle: 'onLookupMenuToggle',\n\t\tchoose: 'onLookupMenuItemChoose'\n\t} );\n\n\t// Initialization\n\tthis.$input.attr( {\n\t\trole: 'combobox',\n\t\t'aria-owns': this.lookupMenu.getElementId(),\n\t\t'aria-autocomplete': 'list'\n\t} );\n\tthis.$element.addClass( 'oo-ui-lookupElement' );\n\tthis.lookupMenu.$element.addClass( 'oo-ui-lookupElement-menu' );\n\tthis.$overlay.append( this.lookupMenu.$element );\n};\n\n/* Setup */\n\nOO.mixinClass( OO.ui.mixin.LookupElement, OO.ui.mixin.RequestManager );\n\n/* Methods */\n\n/**\n * Handle input focus event.\n *\n * @protected\n * @param {jQuery.Event} e Input focus event\n */\nOO.ui.mixin.LookupElement.prototype.onLookupInputFocus = function () {\n\tthis.lookupInputFocused = true;\n\tthis.populateLookupMenu();\n};\n\n/**\n * Handle input blur event.\n *\n * @protected\n * @param {jQuery.Event} e Input blur event\n */\nOO.ui.mixin.LookupElement.prototype.onLookupInputBlur = function () {\n\tthis.closeLookupMenu();\n\tthis.lookupInputFocused = false;\n};\n\n/**\n * Handle input mouse down event.\n *\n * @protected\n * @param {jQuery.Event} e Input mouse down event\n */\nOO.ui.mixin.LookupElement.prototype.onLookupInputMouseDown = function () {\n\t// Only open the menu if the input was already focused.\n\t// This way we allow the user to open the menu again after closing it with Escape (esc)\n\t// by clicking in the input. Opening (and populating) the menu when initially\n\t// clicking into the input is handled by the focus handler.\n\tif ( this.lookupInputFocused && !this.lookupMenu.isVisible() ) {\n\t\tthis.populateLookupMenu();\n\t}\n};\n\n/**\n * Handle input change event.\n *\n * @protected\n * @param {string} value New input value\n */\nOO.ui.mixin.LookupElement.prototype.onLookupInputChange = function () {\n\tif ( this.lookupInputFocused ) {\n\t\tthis.populateLookupMenu();\n\t}\n};\n\n/**\n * Handle the lookup menu being shown/hidden.\n *\n * @protected\n * @param {boolean} visible Whether the lookup menu is now visible.\n */\nOO.ui.mixin.LookupElement.prototype.onLookupMenuToggle = function ( visible ) {\n\tif ( !visible ) {\n\t\t// When the menu is hidden, abort any active request and clear the menu.\n\t\t// This has to be done here in addition to closeLookupMenu(), because\n\t\t// MenuSelectWidget will close itself when the user presses Escape (esc).\n\t\tthis.abortLookupRequest();\n\t\tthis.lookupMenu.clearItems();\n\t}\n};\n\n/**\n * Handle menu item 'choose' event, updating the text input value to the value of the clicked item.\n *\n * @protected\n * @param {OO.ui.MenuOptionWidget} item Selected item\n */\nOO.ui.mixin.LookupElement.prototype.onLookupMenuItemChoose = function ( item ) {\n\tthis.setValue( item.getData() );\n};\n\n/**\n * Get lookup menu.\n *\n * @private\n * @return {OO.ui.MenuSelectWidget}\n */\nOO.ui.mixin.LookupElement.prototype.getLookupMenu = function () {\n\treturn this.lookupMenu;\n};\n\n/**\n * Disable or re-enable lookups.\n *\n * When lookups are disabled, calls to #populateLookupMenu will be ignored.\n *\n * @param {boolean} disabled Disable lookups\n */\nOO.ui.mixin.LookupElement.prototype.setLookupsDisabled = function ( disabled ) {\n\tthis.lookupsDisabled = !!disabled;\n};\n\n/**\n * Open the menu. If there are no entries in the menu, this does nothing.\n *\n * @private\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.LookupElement.prototype.openLookupMenu = function () {\n\tif ( !this.lookupMenu.isEmpty() ) {\n\t\tthis.lookupMenu.toggle( true );\n\t}\n\treturn this;\n};\n\n/**\n * Close the menu, empty it, and abort any pending request.\n *\n * @private\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.LookupElement.prototype.closeLookupMenu = function () {\n\tthis.lookupMenu.toggle( false );\n\tthis.abortLookupRequest();\n\tthis.lookupMenu.clearItems();\n\treturn this;\n};\n\n/**\n * Request menu items based on the input's current value, and when they arrive,\n * populate the menu with these items and show the menu.\n *\n * If lookups have been disabled with #setLookupsDisabled, this function does nothing.\n *\n * @private\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.LookupElement.prototype.populateLookupMenu = function () {\n\tvar widget = this,\n\t\tvalue = this.getValue();\n\n\tif ( this.lookupsDisabled || this.isReadOnly() ) {\n\t\treturn;\n\t}\n\n\t// If the input is empty, clear the menu, unless suggestions when empty are allowed.\n\tif ( !this.allowSuggestionsWhenEmpty && value === '' ) {\n\t\tthis.closeLookupMenu();\n\t// Skip population if there is already a request pending for the current value\n\t} else if ( value !== this.lookupQuery ) {\n\t\tthis.getLookupMenuItems()\n\t\t\t.done( function ( items ) {\n\t\t\t\twidget.lookupMenu.clearItems();\n\t\t\t\tif ( items.length ) {\n\t\t\t\t\twidget.lookupMenu\n\t\t\t\t\t\t.addItems( items )\n\t\t\t\t\t\t.toggle( true );\n\t\t\t\t\twidget.initializeLookupMenuSelection();\n\t\t\t\t} else {\n\t\t\t\t\twidget.lookupMenu.toggle( false );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.fail( function () {\n\t\t\t\twidget.lookupMenu.clearItems();\n\t\t\t\twidget.lookupMenu.toggle( false );\n\t\t\t} );\n\t}\n\n\treturn this;\n};\n\n/**\n * Highlight the first selectable item in the menu, if configured.\n *\n * @private\n * @chainable\n */\nOO.ui.mixin.LookupElement.prototype.initializeLookupMenuSelection = function () {\n\tif ( this.lookupHighlightFirstItem && !this.lookupMenu.findSelectedItem() ) {\n\t\tthis.lookupMenu.highlightItem( this.lookupMenu.findFirstSelectableItem() );\n\t}\n};\n\n/**\n * Get lookup menu items for the current query.\n *\n * @private\n * @return {jQuery.Promise} Promise object which will be passed menu items as the first argument of\n *   the done event. If the request was aborted to make way for a subsequent request, this promise\n *   will not be rejected: it will remain pending forever.\n */\nOO.ui.mixin.LookupElement.prototype.getLookupMenuItems = function () {\n\treturn this.getRequestData().then( function ( data ) {\n\t\treturn this.getLookupMenuOptionsFromData( data );\n\t}.bind( this ) );\n};\n\n/**\n * Abort the currently pending lookup request, if any.\n *\n * @private\n */\nOO.ui.mixin.LookupElement.prototype.abortLookupRequest = function () {\n\tthis.abortRequest();\n};\n\n/**\n * Get a new request object of the current lookup query value.\n *\n * @protected\n * @method\n * @abstract\n * @return {jQuery.Promise} jQuery AJAX object, or promise object with an .abort() method\n */\nOO.ui.mixin.LookupElement.prototype.getLookupRequest = null;\n\n/**\n * Pre-process data returned by the request from #getLookupRequest.\n *\n * The return value of this function will be cached, and any further queries for the given value\n * will use the cache rather than doing API requests.\n *\n * @protected\n * @method\n * @abstract\n * @param {Mixed} response Response from server\n * @return {Mixed} Cached result data\n */\nOO.ui.mixin.LookupElement.prototype.getLookupCacheDataFromResponse = null;\n\n/**\n * Get a list of menu option widgets from the (possibly cached) data returned by\n * #getLookupCacheDataFromResponse.\n *\n * @protected\n * @method\n * @abstract\n * @param {Mixed} data Cached result data, usually an array\n * @return {OO.ui.MenuOptionWidget[]} Menu items\n */\nOO.ui.mixin.LookupElement.prototype.getLookupMenuOptionsFromData = null;\n\n/**\n * Set the read-only state of the widget.\n *\n * This will also disable/enable the lookups functionality.\n *\n * @param {boolean} readOnly Make input read-only\n * @chainable\n * @return {OO.ui.Element} The element, for chaining\n */\nOO.ui.mixin.LookupElement.prototype.setReadOnly = function ( readOnly ) {\n\t// Parent method\n\t// Note: Calling #setReadOnly this way assumes this is mixed into an OO.ui.TextInputWidget\n\tOO.ui.TextInputWidget.prototype.setReadOnly.call( this, readOnly );\n\n\t// During construction, #setReadOnly is called before the OO.ui.mixin.LookupElement constructor.\n\tif ( this.isReadOnly() && this.lookupMenu ) {\n\t\tthis.closeLookupMenu();\n\t}\n\n\treturn this;\n};\n\n/**\n * @inheritdoc OO.ui.mixin.RequestManager\n */\nOO.ui.mixin.LookupElement.prototype.getRequestQuery = function () {\n\treturn this.getValue();\n};\n\n/**\n * @inheritdoc OO.ui.mixin.RequestManager\n */\nOO.ui.mixin.LookupElement.prototype.getRequest = function () {\n\treturn this.getLookupRequest();\n};\n\n/**\n * @inheritdoc OO.ui.mixin.RequestManager\n */\nOO.ui.mixin.LookupElement.prototype.getRequestCacheDataFromResponse = function ( response ) {\n\treturn this.getLookupCacheDataFromResponse( response );\n};\n","/**\n * TabPanelLayouts are used within {@link OO.ui.IndexLayout index layouts} to create tab panels that\n * users can select and display from the index's optional {@link OO.ui.TabSelectWidget tab}\n * navigation. TabPanels are usually not instantiated directly, rather extended to include the\n * required content and functionality.\n *\n * Each tab panel must have a unique symbolic name, which is passed to the constructor. In addition,\n * the tab panel's tab item is customized (with a label) using the #setupTabItem method. See\n * {@link OO.ui.IndexLayout IndexLayout} for an example.\n *\n * @class\n * @extends OO.ui.PanelLayout\n *\n * @constructor\n * @param {string} name Unique symbolic name of tab panel\n * @param {Object} [config] Configuration options\n * @cfg {jQuery|string|Function|OO.ui.HtmlSnippet} [label] Label for tab panel's tab\n */\nOO.ui.TabPanelLayout = function OoUiTabPanelLayout( name, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( name ) && config === undefined ) {\n\t\tconfig = name;\n\t\tname = config.name;\n\t}\n\n\t// Configuration initialization\n\tconfig = $.extend( { scrollable: true }, config );\n\n\t// Parent constructor\n\tOO.ui.TabPanelLayout.parent.call( this, config );\n\n\t// Properties\n\tthis.name = name;\n\tthis.label = config.label;\n\tthis.tabItem = null;\n\tthis.active = false;\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-tabPanelLayout' )\n\t\t.attr( 'role', 'tabpanel' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.TabPanelLayout, OO.ui.PanelLayout );\n\n/* Events */\n\n/**\n * An 'active' event is emitted when the tab panel becomes active. Tab panels become active when\n * they are shown in a index layout that is configured to display only one tab panel at a time.\n *\n * @event active\n * @param {boolean} active Tab panel is active\n */\n\n/* Methods */\n\n/**\n * Get the symbolic name of the tab panel.\n *\n * @return {string} Symbolic name of tab panel\n */\nOO.ui.TabPanelLayout.prototype.getName = function () {\n\treturn this.name;\n};\n\n/**\n * Check if tab panel is active.\n *\n * Tab panels become active when they are shown in a {@link OO.ui.IndexLayout index layout} that is\n * configured to display only one tab panel at a time. Additional CSS is applied to the tab panel's\n * tab item to reflect the active state.\n *\n * @return {boolean} Tab panel is active\n */\nOO.ui.TabPanelLayout.prototype.isActive = function () {\n\treturn this.active;\n};\n\n/**\n * Get tab item.\n *\n * The tab item allows users to access the tab panel from the index's tab\n * navigation. The tab item itself can be customized (with a label, level, etc.) using the\n * #setupTabItem method.\n *\n * @return {OO.ui.TabOptionWidget|null} Tab option widget\n */\nOO.ui.TabPanelLayout.prototype.getTabItem = function () {\n\treturn this.tabItem;\n};\n\n/**\n * Set or unset the tab item.\n *\n * Specify a {@link OO.ui.TabOptionWidget tab option} to set it,\n * or `null` to clear the tab item. To customize the tab item itself (e.g., to set a label or tab\n * level), use #setupTabItem instead of this method.\n *\n * @param {OO.ui.TabOptionWidget|null} tabItem Tab option widget, null to clear\n * @chainable\n * @return {OO.ui.TabPanelLayout} The layout, for chaining\n */\nOO.ui.TabPanelLayout.prototype.setTabItem = function ( tabItem ) {\n\tthis.tabItem = tabItem || null;\n\tif ( tabItem ) {\n\t\tthis.setupTabItem();\n\t}\n\treturn this;\n};\n\n/**\n * Set up the tab item.\n *\n * Use this method to customize the tab item (e.g., to add a label or tab level). To set or unset\n * the tab item itself (with a {@link OO.ui.TabOptionWidget tab option} or `null`), use\n * the #setTabItem method instead.\n *\n * @param {OO.ui.TabOptionWidget} tabItem Tab option widget to set up\n * @chainable\n * @return {OO.ui.TabPanelLayout} The layout, for chaining\n */\nOO.ui.TabPanelLayout.prototype.setupTabItem = function () {\n\tthis.$element.attr( 'aria-labelledby', this.tabItem.getElementId() );\n\n\tthis.tabItem.$element.attr( 'aria-controls', this.getElementId() );\n\n\tif ( this.label ) {\n\t\tthis.tabItem.setLabel( this.label );\n\t}\n\treturn this;\n};\n\n/**\n * Set the tab panel to its 'active' state.\n *\n * Tab panels become active when they are shown in a index layout that is configured to display only\n * one tab panel at a time. Additional CSS is applied to the tab item to reflect the tab panel's\n * active state. Outside of the index context, setting the active state on a tab panel does nothing.\n *\n * @param {boolean} active Tab panel is active\n * @fires active\n */\nOO.ui.TabPanelLayout.prototype.setActive = function ( active ) {\n\tactive = !!active;\n\n\tif ( active !== this.active ) {\n\t\tthis.active = active;\n\t\tthis.$element.toggleClass( 'oo-ui-tabPanelLayout-active', this.active );\n\t\tthis.emit( 'active', this.active );\n\t}\n};\n","/**\n * PageLayouts are used within {@link OO.ui.BookletLayout booklet layouts} to create pages that\n * users can select and display from the booklet's optional\n * {@link OO.ui.OutlineSelectWidget outline} navigation. Pages are usually not instantiated\n * directly, rather extended to include the required content and functionality.\n *\n * Each page must have a unique symbolic name, which is passed to the constructor. In addition, the\n * page's outline item is customized (with a label, outline level, etc.) using the\n * #setupOutlineItem method. See {@link OO.ui.BookletLayout BookletLayout} for an example.\n *\n * @class\n * @extends OO.ui.PanelLayout\n *\n * @constructor\n * @param {string} name Unique symbolic name of page\n * @param {Object} [config] Configuration options\n */\nOO.ui.PageLayout = function OoUiPageLayout( name, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( name ) && config === undefined ) {\n\t\tconfig = name;\n\t\tname = config.name;\n\t}\n\n\t// Configuration initialization\n\tconfig = $.extend( { scrollable: true }, config );\n\n\t// Parent constructor\n\tOO.ui.PageLayout.parent.call( this, config );\n\n\t// Properties\n\tthis.name = name;\n\tthis.outlineItem = null;\n\tthis.active = false;\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-pageLayout' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.PageLayout, OO.ui.PanelLayout );\n\n/* Events */\n\n/**\n * An 'active' event is emitted when the page becomes active. Pages become active when they are\n * shown in a booklet layout that is configured to display only one page at a time.\n *\n * @event active\n * @param {boolean} active Page is active\n */\n\n/* Methods */\n\n/**\n * Get the symbolic name of the page.\n *\n * @return {string} Symbolic name of page\n */\nOO.ui.PageLayout.prototype.getName = function () {\n\treturn this.name;\n};\n\n/**\n * Check if page is active.\n *\n * Pages become active when they are shown in a {@link OO.ui.BookletLayout booklet layout} that is\n * configured to display only one page at a time. Additional CSS is applied to the page's outline\n * item to reflect the active state.\n *\n * @return {boolean} Page is active\n */\nOO.ui.PageLayout.prototype.isActive = function () {\n\treturn this.active;\n};\n\n/**\n * Get outline item.\n *\n * The outline item allows users to access the page from the booklet's outline\n * navigation. The outline item itself can be customized (with a label, level, etc.) using the\n * #setupOutlineItem method.\n *\n * @return {OO.ui.OutlineOptionWidget|null} Outline option widget\n */\nOO.ui.PageLayout.prototype.getOutlineItem = function () {\n\treturn this.outlineItem;\n};\n\n/**\n * Set or unset the outline item.\n *\n * Specify an {@link OO.ui.OutlineOptionWidget outline option} to set it,\n * or `null` to clear the outline item. To customize the outline item itself (e.g., to set a label\n * or outline level), use #setupOutlineItem instead of this method.\n *\n * @param {OO.ui.OutlineOptionWidget|null} outlineItem Outline option widget, null to clear\n * @chainable\n * @return {OO.ui.PageLayout} The layout, for chaining\n */\nOO.ui.PageLayout.prototype.setOutlineItem = function ( outlineItem ) {\n\tthis.outlineItem = outlineItem || null;\n\tif ( outlineItem ) {\n\t\tthis.setupOutlineItem();\n\t}\n\treturn this;\n};\n\n/**\n * Set up the outline item.\n *\n * Use this method to customize the outline item (e.g., to add a label or outline level). To set or\n * unset the outline item itself (with an {@link OO.ui.OutlineOptionWidget outline option} or\n * `null`), use the #setOutlineItem method instead.\n *\n * @param {OO.ui.OutlineOptionWidget} outlineItem Outline option widget to set up\n * @chainable\n * @return {OO.ui.PageLayout} The layout, for chaining\n */\nOO.ui.PageLayout.prototype.setupOutlineItem = function () {\n\treturn this;\n};\n\n/**\n * Set the page to its 'active' state.\n *\n * Pages become active when they are shown in a booklet layout that is configured to display only\n * one page at a time. Additional CSS is applied to the outline item to reflect the page's active\n * state. Outside of the booklet context, setting the active state on a page does nothing.\n *\n * @param {boolean} active Page is active\n * @fires active\n */\nOO.ui.PageLayout.prototype.setActive = function ( active ) {\n\tactive = !!active;\n\n\tif ( active !== this.active ) {\n\t\tthis.active = active;\n\t\tthis.$element.toggleClass( 'oo-ui-pageLayout-active', active );\n\t\tthis.emit( 'active', this.active );\n\t}\n};\n","/**\n * StackLayouts contain a series of {@link OO.ui.PanelLayout panel layouts}. By default, only one\n * panel is displayed at a time, though the stack layout can also be configured to show all\n * contained panels, one after another, by setting the #continuous option to 'true'.\n *\n *     @example\n *     // A stack layout with two panels, configured to be displayed continuously\n *     var myStack = new OO.ui.StackLayout( {\n *         items: [\n *             new OO.ui.PanelLayout( {\n *                 $content: $( '<p>Panel One</p>' ),\n *                 padded: true,\n *                 framed: true\n *             } ),\n *             new OO.ui.PanelLayout( {\n *                 $content: $( '<p>Panel Two</p>' ),\n *                 padded: true,\n *                 framed: true\n *             } )\n *         ],\n *         continuous: true\n *     } );\n *     $( document.body ).append( myStack.$element );\n *\n * @class\n * @extends OO.ui.PanelLayout\n * @mixins OO.ui.mixin.GroupElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [continuous=false] Show all panels, one after another. By default, only one panel\n *  is displayed at a time.\n * @cfg {OO.ui.Layout[]} [items] Panel layouts to add to the stack layout.\n */\nOO.ui.StackLayout = function OoUiStackLayout( config ) {\n\t// Configuration initialization\n\t// Make the layout scrollable in continuous mode, otherwise each\n\t// panel is responsible for its own scrolling.\n\tconfig = $.extend( { scrollable: !!( config && config.continuous ) }, config );\n\n\t// Parent constructor\n\tOO.ui.StackLayout.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.GroupElement.call( this, $.extend( { $group: this.$element }, config ) );\n\n\t// Properties\n\tthis.currentItem = null;\n\tthis.continuous = !!config.continuous;\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-stackLayout' );\n\tif ( this.continuous ) {\n\t\tthis.$element.addClass( 'oo-ui-stackLayout-continuous' );\n\t\tthis.$element.on( 'scroll', OO.ui.debounce( this.onScroll.bind( this ), 250 ) );\n\t}\n\tif ( Array.isArray( config.items ) ) {\n\t\tthis.addItems( config.items );\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.StackLayout, OO.ui.PanelLayout );\nOO.mixinClass( OO.ui.StackLayout, OO.ui.mixin.GroupElement );\n\n/* Events */\n\n/**\n * A 'set' event is emitted when panels are {@link #addItems added}, {@link #removeItems removed},\n * {@link #clearItems cleared} or {@link #setItem displayed}.\n *\n * @event set\n * @param {OO.ui.Layout|null} item Current panel or `null` if no panel is shown\n */\n\n/**\n * When used in continuous mode, this event is emitted when the user scrolls down\n * far enough such that currentItem is no longer visible.\n *\n * @event visibleItemChange\n * @param {OO.ui.PanelLayout} panel The next visible item in the layout\n */\n\n/* Methods */\n\n/**\n * Handle scroll events from the layout element\n *\n * @param {jQuery.Event} e\n * @fires visibleItemChange\n */\nOO.ui.StackLayout.prototype.onScroll = function () {\n\tvar currentRect,\n\t\tlen = this.items.length,\n\t\tcurrentIndex = this.items.indexOf( this.currentItem ),\n\t\tnewIndex = currentIndex,\n\t\tcontainerRect = this.$element[ 0 ].getBoundingClientRect();\n\n\tif ( !containerRect || ( !containerRect.top && !containerRect.bottom ) ) {\n\t\t// Can't get bounding rect, possibly not attached.\n\t\treturn;\n\t}\n\n\tfunction getRect( item ) {\n\t\treturn item.$element[ 0 ].getBoundingClientRect();\n\t}\n\n\tfunction isVisible( item ) {\n\t\tvar rect = getRect( item );\n\t\treturn rect.bottom > containerRect.top && rect.top < containerRect.bottom;\n\t}\n\n\tcurrentRect = getRect( this.currentItem );\n\n\tif ( currentRect.bottom < containerRect.top ) {\n\t\t// Scrolled down past current item\n\t\twhile ( ++newIndex < len ) {\n\t\t\tif ( isVisible( this.items[ newIndex ] ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t} else if ( currentRect.top > containerRect.bottom ) {\n\t\t// Scrolled up past current item\n\t\twhile ( --newIndex >= 0 ) {\n\t\t\tif ( isVisible( this.items[ newIndex ] ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( newIndex !== currentIndex ) {\n\t\tthis.emit( 'visibleItemChange', this.items[ newIndex ] );\n\t}\n};\n\n/**\n * Get the current panel.\n *\n * @return {OO.ui.Layout|null}\n */\nOO.ui.StackLayout.prototype.getCurrentItem = function () {\n\treturn this.currentItem;\n};\n\n/**\n * Unset the current item.\n *\n * @private\n * @param {OO.ui.StackLayout} layout\n * @fires set\n */\nOO.ui.StackLayout.prototype.unsetCurrentItem = function () {\n\tvar prevItem = this.currentItem;\n\tif ( prevItem === null ) {\n\t\treturn;\n\t}\n\n\tthis.currentItem = null;\n\tthis.emit( 'set', null );\n};\n\n/**\n * Add panel layouts to the stack layout.\n *\n * Panels will be added to the end of the stack layout array unless the optional index parameter\n * specifies a different insertion point. Adding a panel that is already in the stack will move it\n * to the end of the array or the point specified by the index.\n *\n * @param {OO.ui.Layout[]} items Panels to add\n * @param {number} [index] Index of the insertion point\n * @chainable\n * @return {OO.ui.StackLayout} The layout, for chaining\n */\nOO.ui.StackLayout.prototype.addItems = function ( items, index ) {\n\t// Update the visibility\n\tthis.updateHiddenState( items, this.currentItem );\n\n\t// Mixin method\n\tOO.ui.mixin.GroupElement.prototype.addItems.call( this, items, index );\n\n\tif ( !this.currentItem && items.length ) {\n\t\tthis.setItem( items[ 0 ] );\n\t}\n\n\treturn this;\n};\n\n/**\n * Remove the specified panels from the stack layout.\n *\n * Removed panels are detached from the DOM, not removed, so that they may be reused. To remove all\n * panels, you may wish to use the #clearItems method instead.\n *\n * @param {OO.ui.Layout[]} items Panels to remove\n * @chainable\n * @return {OO.ui.StackLayout} The layout, for chaining\n * @fires set\n */\nOO.ui.StackLayout.prototype.removeItems = function ( items ) {\n\t// Mixin method\n\tOO.ui.mixin.GroupElement.prototype.removeItems.call( this, items );\n\n\tif ( items.indexOf( this.currentItem ) !== -1 ) {\n\t\tif ( this.items.length ) {\n\t\t\tthis.setItem( this.items[ 0 ] );\n\t\t} else {\n\t\t\tthis.unsetCurrentItem();\n\t\t}\n\t}\n\n\treturn this;\n};\n\n/**\n * Clear all panels from the stack layout.\n *\n * Cleared panels are detached from the DOM, not removed, so that they may be reused. To remove only\n * a subset of panels, use the #removeItems method.\n *\n * @chainable\n * @return {OO.ui.StackLayout} The layout, for chaining\n * @fires set\n */\nOO.ui.StackLayout.prototype.clearItems = function () {\n\tthis.unsetCurrentItem();\n\tOO.ui.mixin.GroupElement.prototype.clearItems.call( this );\n\n\treturn this;\n};\n\n/**\n * Show the specified panel.\n *\n * If another panel is currently displayed, it will be hidden.\n *\n * @param {OO.ui.Layout} item Panel to show\n * @chainable\n * @return {OO.ui.StackLayout} The layout, for chaining\n * @fires set\n */\nOO.ui.StackLayout.prototype.setItem = function ( item ) {\n\tif ( item !== this.currentItem ) {\n\t\tthis.updateHiddenState( this.items, item );\n\n\t\tif ( this.items.indexOf( item ) !== -1 ) {\n\t\t\tthis.currentItem = item;\n\t\t\tthis.emit( 'set', item );\n\t\t} else {\n\t\t\tthis.unsetCurrentItem();\n\t\t}\n\t}\n\n\treturn this;\n};\n\n/**\n * Reset the scroll offset of all panels, or the container if continuous\n *\n * @inheritdoc\n */\nOO.ui.StackLayout.prototype.resetScroll = function () {\n\tif ( this.continuous ) {\n\t\t// Parent method\n\t\treturn OO.ui.StackLayout.parent.prototype.resetScroll.call( this );\n\t}\n\t// Reset each panel\n\tthis.getItems().forEach( function ( panel ) {\n\t\tvar hidden = panel.$element.hasClass( 'oo-ui-element-hidden' );\n\t\t// Scroll can only be reset when panel is visible\n\t\tpanel.$element.removeClass( 'oo-ui-element-hidden' );\n\t\tpanel.resetScroll();\n\t\tif ( hidden ) {\n\t\t\tpanel.$element.addClass( 'oo-ui-element-hidden' );\n\t\t}\n\t} );\n\n\treturn this;\n};\n\n/**\n * Update the visibility of all items in case of non-continuous view.\n *\n * Ensure all items are hidden except for the selected one.\n * This method does nothing when the stack is continuous.\n *\n * @private\n * @param {OO.ui.Layout[]} items Item list iterate over\n * @param {OO.ui.Layout} [selectedItem] Selected item to show\n */\nOO.ui.StackLayout.prototype.updateHiddenState = function ( items, selectedItem ) {\n\tvar i, len;\n\n\tif ( !this.continuous ) {\n\t\tfor ( i = 0, len = items.length; i < len; i++ ) {\n\t\t\tif ( !selectedItem || selectedItem !== items[ i ] ) {\n\t\t\t\titems[ i ].$element.addClass( 'oo-ui-element-hidden' );\n\t\t\t\titems[ i ].$element.attr( 'aria-hidden', 'true' );\n\t\t\t}\n\t\t}\n\t\tif ( selectedItem ) {\n\t\t\tselectedItem.$element.removeClass( 'oo-ui-element-hidden' );\n\t\t\tselectedItem.$element.removeAttr( 'aria-hidden' );\n\t\t}\n\t}\n};\n","/**\n * MenuLayouts combine a menu and a content {@link OO.ui.PanelLayout panel}. The menu is positioned\n * relative to the content (after, before, top, or bottom) and its size is customized with the\n * #menuSize config. The content area will fill all remaining space.\n *\n *     @example\n *     var menuLayout,\n *         menuPanel = new OO.ui.PanelLayout( {\n *             padded: true,\n *             expanded: true,\n *             scrollable: true\n *         } ),\n *         contentPanel = new OO.ui.PanelLayout( {\n *             padded: true,\n *             expanded: true,\n *             scrollable: true\n *         } ),\n *         select = new OO.ui.SelectWidget( {\n *             items: [\n *                 new OO.ui.OptionWidget( {\n *                     data: 'before',\n *                     label: 'Before'\n *                 } ),\n *                 new OO.ui.OptionWidget( {\n *                     data: 'after',\n *                     label: 'After'\n *                 } ),\n *                 new OO.ui.OptionWidget( {\n *                     data: 'top',\n *                     label: 'Top'\n *                 } ),\n *                 new OO.ui.OptionWidget( {\n *                     data: 'bottom',\n *                     label: 'Bottom'\n *                 } )\n *              ]\n *         } ).on( 'select', function ( item ) {\n *            menuLayout.setMenuPosition( item.getData() );\n *         } );\n *\n *     menuLayout = new OO.ui.MenuLayout( {\n *         position: 'top',\n *         menuPanel: menuPanel,\n *         contentPanel: contentPanel\n *     } );\n *     menuLayout.$menu.append(\n *         menuPanel.$element.append( '<b>Menu panel</b>', select.$element )\n *     );\n *     menuLayout.$content.append(\n *         contentPanel.$element.append(\n *             '<b>Content panel</b>',\n *             '<p>Note that the menu is positioned relative to the content panel: ' +\n *             'top, bottom, after, before.</p>'\n *          )\n *     );\n *     $( document.body ).append( menuLayout.$element );\n *\n * If menu size needs to be overridden, it can be accomplished using CSS similar to the snippet\n * below. MenuLayout's CSS will override the appropriate values with 'auto' or '0' to display the\n * menu correctly. If `menuPosition` is known beforehand, CSS rules corresponding to other positions\n * may be omitted.\n *\n *     .oo-ui-menuLayout-menu {\n *         width: 200px;\n *         height: 200px;\n *     }\n *\n *     .oo-ui-menuLayout-content {\n *         top: 200px;\n *         left: 200px;\n *         right: 200px;\n *         bottom: 200px;\n *     }\n *\n * @class\n * @extends OO.ui.Layout\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {OO.ui.PanelLayout} [menuPanel] Menu panel\n * @cfg {OO.ui.PanelLayout} [contentPanel] Content panel\n * @cfg {boolean} [expanded=true] Expand the layout to fill the entire parent element.\n * @cfg {boolean} [showMenu=true] Show menu\n * @cfg {string} [menuPosition='before'] Position of menu: `top`, `after`, `bottom` or `before`\n */\nOO.ui.MenuLayout = function OoUiMenuLayout( config ) {\n\t// Configuration initialization\n\tconfig = $.extend( {\n\t\texpanded: true,\n\t\tshowMenu: true,\n\t\tmenuPosition: 'before'\n\t}, config );\n\n\t// Parent constructor\n\tOO.ui.MenuLayout.parent.call( this, config );\n\n\tthis.menuPanel = null;\n\tthis.contentPanel = null;\n\tthis.expanded = !!config.expanded;\n\t/**\n\t * Menu DOM node\n\t *\n\t * @property {jQuery}\n\t */\n\tthis.$menu = $( '<div>' );\n\t/**\n\t * Content DOM node\n\t *\n\t * @property {jQuery}\n\t */\n\tthis.$content = $( '<div>' );\n\n\t// Initialization\n\tthis.$menu.addClass( 'oo-ui-menuLayout-menu' );\n\tthis.$content.addClass( 'oo-ui-menuLayout-content' );\n\tthis.$element.addClass( 'oo-ui-menuLayout' );\n\tif ( config.expanded ) {\n\t\tthis.$element.addClass( 'oo-ui-menuLayout-expanded' );\n\t} else {\n\t\tthis.$element.addClass( 'oo-ui-menuLayout-static' );\n\t}\n\tif ( config.menuPanel ) {\n\t\tthis.setMenuPanel( config.menuPanel );\n\t}\n\tif ( config.contentPanel ) {\n\t\tthis.setContentPanel( config.contentPanel );\n\t}\n\tthis.setMenuPosition( config.menuPosition );\n\tthis.toggleMenu( config.showMenu );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.MenuLayout, OO.ui.Layout );\n\n/* Methods */\n\n/**\n * Toggle menu.\n *\n * @param {boolean} showMenu Show menu, omit to toggle\n * @chainable\n * @return {OO.ui.MenuLayout} The layout, for chaining\n */\nOO.ui.MenuLayout.prototype.toggleMenu = function ( showMenu ) {\n\tshowMenu = showMenu === undefined ? !this.showMenu : !!showMenu;\n\n\tif ( this.showMenu !== showMenu ) {\n\t\tthis.showMenu = showMenu;\n\t\tthis.$element\n\t\t\t.toggleClass( 'oo-ui-menuLayout-showMenu', this.showMenu )\n\t\t\t.toggleClass( 'oo-ui-menuLayout-hideMenu', !this.showMenu );\n\t\tthis.$menu.attr( 'aria-hidden', this.showMenu ? 'false' : 'true' );\n\t}\n\n\treturn this;\n};\n\n/**\n * Check if menu is visible\n *\n * @return {boolean} Menu is visible\n */\nOO.ui.MenuLayout.prototype.isMenuVisible = function () {\n\treturn this.showMenu;\n};\n\n/**\n * Set menu position.\n *\n * @param {string} position Position of menu, either `top`, `after`, `bottom` or `before`\n * @chainable\n * @return {OO.ui.MenuLayout} The layout, for chaining\n */\nOO.ui.MenuLayout.prototype.setMenuPosition = function ( position ) {\n\tif ( [ 'top', 'bottom', 'before', 'after' ].indexOf( position ) === -1 ) {\n\t\tposition = 'before';\n\t}\n\n\tthis.$element.removeClass( 'oo-ui-menuLayout-' + this.menuPosition );\n\tthis.menuPosition = position;\n\tif ( this.menuPosition === 'top' || this.menuPosition === 'before' ) {\n\t\tthis.$element.append( this.$menu, this.$content );\n\t} else {\n\t\tthis.$element.append( this.$content, this.$menu );\n\t}\n\tthis.$element.addClass( 'oo-ui-menuLayout-' + position );\n\n\treturn this;\n};\n\n/**\n * Get menu position.\n *\n * @return {string} Menu position\n */\nOO.ui.MenuLayout.prototype.getMenuPosition = function () {\n\treturn this.menuPosition;\n};\n\n/**\n * Set the menu panel.\n *\n * @param {OO.ui.PanelLayout} menuPanel Menu panel\n */\nOO.ui.MenuLayout.prototype.setMenuPanel = function ( menuPanel ) {\n\tthis.menuPanel = menuPanel;\n\tthis.$menu.append( this.menuPanel.$element );\n};\n\n/**\n * Set the content panel.\n *\n * @param {OO.ui.PanelLayout} contentPanel Content panel\n */\nOO.ui.MenuLayout.prototype.setContentPanel = function ( contentPanel ) {\n\tthis.contentPanel = contentPanel;\n\tthis.$content.append( this.contentPanel.$element );\n};\n\n/**\n * Clear the menu panel.\n */\nOO.ui.MenuLayout.prototype.clearMenuPanel = function () {\n\tthis.menuPanel = null;\n\tthis.$menu.empty();\n};\n\n/**\n * Clear the content panel.\n */\nOO.ui.MenuLayout.prototype.clearContentPanel = function () {\n\tthis.contentPanel = null;\n\tthis.$content.empty();\n};\n\n/**\n * Reset the scroll offset of all panels and the tab select widget\n *\n * @inheritdoc\n */\nOO.ui.MenuLayout.prototype.resetScroll = function () {\n\tif ( this.menuPanel ) {\n\t\tthis.menuPanel.resetScroll();\n\t}\n\tif ( this.contentPanel ) {\n\t\tthis.contentPanel.resetScroll();\n\t}\n\n\treturn this;\n};\n","/**\n * BookletLayouts contain {@link OO.ui.PageLayout page layouts} as well as\n * an {@link OO.ui.OutlineSelectWidget outline} that allows users to easily navigate\n * through the pages and select which one to display. By default, only one page is\n * displayed at a time and the outline is hidden. When a user navigates to a new page,\n * the booklet layout automatically focuses on the first focusable element, unless the\n * default setting is changed. Optionally, booklets can be configured to show\n * {@link OO.ui.OutlineControlsWidget controls} for adding, moving, and removing items.\n *\n *     @example\n *     // Example of a BookletLayout that contains two PageLayouts.\n *\n *     function PageOneLayout( name, config ) {\n *         PageOneLayout.parent.call( this, name, config );\n *         this.$element.append( '<p>First page</p><p>(This booklet has an outline, displayed on ' +\n *         'the left)</p>' );\n *     }\n *     OO.inheritClass( PageOneLayout, OO.ui.PageLayout );\n *     PageOneLayout.prototype.setupOutlineItem = function () {\n *         this.outlineItem.setLabel( 'Page One' );\n *     };\n *\n *     function PageTwoLayout( name, config ) {\n *         PageTwoLayout.parent.call( this, name, config );\n *         this.$element.append( '<p>Second page</p>' );\n *     }\n *     OO.inheritClass( PageTwoLayout, OO.ui.PageLayout );\n *     PageTwoLayout.prototype.setupOutlineItem = function () {\n *         this.outlineItem.setLabel( 'Page Two' );\n *     };\n *\n *     var page1 = new PageOneLayout( 'one' ),\n *         page2 = new PageTwoLayout( 'two' );\n *\n *     var booklet = new OO.ui.BookletLayout( {\n *         outlined: true\n *     } );\n *\n *     booklet.addPages( [ page1, page2 ] );\n *     $( document.body ).append( booklet.$element );\n *\n * @class\n * @extends OO.ui.MenuLayout\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [continuous=false] Show all pages, one after another\n * @cfg {boolean} [autoFocus=true] Focus on the first focusable element when a new page is\n *  displayed. Disabled on mobile.\n * @cfg {boolean} [outlined=false] Show the outline. The outline is used to navigate through the\n *  pages of the booklet.\n * @cfg {boolean} [editable=false] Show controls for adding, removing and reordering pages.\n */\nOO.ui.BookletLayout = function OoUiBookletLayout( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.BookletLayout.parent.call( this, config );\n\n\t// Properties\n\tthis.currentPageName = null;\n\tthis.pages = {};\n\tthis.ignoreFocus = false;\n\tthis.stackLayout = new OO.ui.StackLayout( {\n\t\tcontinuous: !!config.continuous,\n\t\texpanded: this.expanded\n\t} );\n\tthis.setContentPanel( this.stackLayout );\n\tthis.autoFocus = config.autoFocus === undefined || !!config.autoFocus;\n\tthis.outlineVisible = false;\n\tthis.outlined = !!config.outlined;\n\tif ( this.outlined ) {\n\t\tthis.editable = !!config.editable;\n\t\tthis.outlineControlsWidget = null;\n\t\tthis.outlineSelectWidget = new OO.ui.OutlineSelectWidget();\n\t\tthis.outlinePanel = new OO.ui.PanelLayout( {\n\t\t\texpanded: this.expanded,\n\t\t\tscrollable: true\n\t\t} );\n\t\tthis.setMenuPanel( this.outlinePanel );\n\t\tthis.outlineVisible = true;\n\t\tif ( this.editable ) {\n\t\t\tthis.outlineControlsWidget = new OO.ui.OutlineControlsWidget(\n\t\t\t\tthis.outlineSelectWidget\n\t\t\t);\n\t\t}\n\t}\n\tthis.toggleMenu( this.outlined );\n\n\t// Events\n\tthis.stackLayout.connect( this, {\n\t\tset: 'onStackLayoutSet'\n\t} );\n\tif ( this.outlined ) {\n\t\tthis.outlineSelectWidget.connect( this, {\n\t\t\tselect: 'onOutlineSelectWidgetSelect'\n\t\t} );\n\t\tthis.scrolling = false;\n\t\tthis.stackLayout.connect( this, {\n\t\t\tvisibleItemChange: 'onStackLayoutVisibleItemChange'\n\t\t} );\n\t}\n\tif ( this.autoFocus ) {\n\t\t// Event 'focus' does not bubble, but 'focusin' does\n\t\tthis.stackLayout.$element.on( 'focusin', this.onStackLayoutFocus.bind( this ) );\n\t}\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-bookletLayout' );\n\tthis.stackLayout.$element.addClass( 'oo-ui-bookletLayout-stackLayout' );\n\tif ( this.outlined ) {\n\t\tthis.outlinePanel.$element\n\t\t\t.addClass( 'oo-ui-bookletLayout-outlinePanel' )\n\t\t\t.append( this.outlineSelectWidget.$element );\n\t\tif ( this.editable ) {\n\t\t\tthis.outlinePanel.$element\n\t\t\t\t.addClass( 'oo-ui-bookletLayout-outlinePanel-editable' )\n\t\t\t\t.append( this.outlineControlsWidget.$element );\n\t\t}\n\t}\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.BookletLayout, OO.ui.MenuLayout );\n\n/* Events */\n\n/**\n * A 'set' event is emitted when a page is {@link #setPage set} to be displayed by the\n * booklet layout.\n * @event set\n * @param {OO.ui.PageLayout} page Current page\n */\n\n/**\n * An 'add' event is emitted when pages are {@link #addPages added} to the booklet layout.\n *\n * @event add\n * @param {OO.ui.PageLayout[]} page Added pages\n * @param {number} index Index pages were added at\n */\n\n/**\n * A 'remove' event is emitted when pages are {@link #clearPages cleared} or\n * {@link #removePages removed} from the booklet.\n *\n * @event remove\n * @param {OO.ui.PageLayout[]} pages Removed pages\n */\n\n/* Methods */\n\n/**\n * Handle stack layout focus.\n *\n * @private\n * @param {jQuery.Event} e Focusin event\n */\nOO.ui.BookletLayout.prototype.onStackLayoutFocus = function ( e ) {\n\tvar name, $target;\n\n\t// Find the page that an element was focused within\n\t$target = $( e.target ).closest( '.oo-ui-pageLayout' );\n\tfor ( name in this.pages ) {\n\t\t// Check for page match, exclude current page to find only page changes\n\t\tif ( this.pages[ name ].$element[ 0 ] === $target[ 0 ] && name !== this.currentPageName ) {\n\t\t\tthis.setPage( name );\n\t\t\tbreak;\n\t\t}\n\t}\n};\n\n/**\n * Handle visibleItemChange events from the stackLayout\n *\n * The next visible page is set as the current page by selecting it\n * in the outline\n *\n * @param {OO.ui.PageLayout} page The next visible page in the layout\n */\nOO.ui.BookletLayout.prototype.onStackLayoutVisibleItemChange = function ( page ) {\n\t// Set a flag to so that the resulting call to #onStackLayoutSet doesn't\n\t// try and scroll the item into view again.\n\tthis.scrolling = true;\n\tthis.outlineSelectWidget.selectItemByData( page.getName() );\n\tthis.scrolling = false;\n};\n\n/**\n * Handle stack layout set events.\n *\n * @private\n * @param {OO.ui.PanelLayout|null} page The page panel that is now the current panel\n */\nOO.ui.BookletLayout.prototype.onStackLayoutSet = function ( page ) {\n\tvar promise, layout = this;\n\t// If everything is unselected, do nothing\n\tif ( !page ) {\n\t\treturn;\n\t}\n\t// For continuous BookletLayouts, scroll the selected page into view first\n\tif ( this.stackLayout.continuous && !this.scrolling ) {\n\t\tpromise = page.scrollElementIntoView();\n\t} else {\n\t\tpromise = $.Deferred().resolve();\n\t}\n\t// Focus the first element on the newly selected panel.\n\t// Don't focus if the page was set by scrolling.\n\tif ( this.autoFocus && !OO.ui.isMobile() && !this.scrolling ) {\n\t\tpromise.done( function () {\n\t\t\tlayout.focus();\n\t\t} );\n\t}\n};\n\n/**\n * Focus the first input in the current page.\n *\n * If no page is selected, the first selectable page will be selected.\n * If the focus is already in an element on the current page, nothing will happen.\n *\n * @param {number} [itemIndex] A specific item to focus on\n */\nOO.ui.BookletLayout.prototype.focus = function ( itemIndex ) {\n\tvar page,\n\t\titems = this.stackLayout.getItems();\n\n\tif ( itemIndex !== undefined && items[ itemIndex ] ) {\n\t\tpage = items[ itemIndex ];\n\t} else {\n\t\tpage = this.stackLayout.getCurrentItem();\n\t}\n\n\tif ( !page && this.outlined ) {\n\t\tthis.selectFirstSelectablePage();\n\t\tpage = this.stackLayout.getCurrentItem();\n\t}\n\tif ( !page ) {\n\t\treturn;\n\t}\n\t// Only change the focus if is not already in the current page\n\tif ( !OO.ui.contains( page.$element[ 0 ], this.getElementDocument().activeElement, true ) ) {\n\t\tpage.focus();\n\t}\n};\n\n/**\n * Find the first focusable input in the booklet layout and focus\n * on it.\n */\nOO.ui.BookletLayout.prototype.focusFirstFocusable = function () {\n\tOO.ui.findFocusable( this.stackLayout.$element ).focus();\n};\n\n/**\n * Handle outline widget select events.\n *\n * @private\n * @param {OO.ui.OptionWidget|null} item Selected item\n */\nOO.ui.BookletLayout.prototype.onOutlineSelectWidgetSelect = function ( item ) {\n\tif ( item ) {\n\t\tthis.setPage( item.getData() );\n\t}\n};\n\n/**\n * Check if booklet has an outline.\n *\n * @return {boolean} Booklet has an outline\n */\nOO.ui.BookletLayout.prototype.isOutlined = function () {\n\treturn this.outlined;\n};\n\n/**\n * Check if booklet has editing controls.\n *\n * @return {boolean} Booklet is editable\n */\nOO.ui.BookletLayout.prototype.isEditable = function () {\n\treturn this.editable;\n};\n\n/**\n * Check if booklet has a visible outline.\n *\n * @return {boolean} Outline is visible\n */\nOO.ui.BookletLayout.prototype.isOutlineVisible = function () {\n\treturn this.outlined && this.outlineVisible;\n};\n\n/**\n * Hide or show the outline.\n *\n * @param {boolean} [show] Show outline, omit to invert current state\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.BookletLayout.prototype.toggleOutline = function ( show ) {\n\tvar booklet = this;\n\n\tif ( this.outlined ) {\n\t\tshow = show === undefined ? !this.outlineVisible : !!show;\n\t\tthis.outlineVisible = show;\n\t\tthis.toggleMenu( show );\n\t\tif ( show && this.editable ) {\n\t\t\t// HACK: Kill dumb scrollbars when the sidebar stops animating, see T161798.\n\t\t\t// Only necessary when outline controls are present, delay matches transition on\n\t\t\t// `.oo-ui-menuLayout-menu`.\n\t\t\tsetTimeout( function () {\n\t\t\t\tOO.ui.Element.static.reconsiderScrollbars( booklet.outlinePanel.$element[ 0 ] );\n\t\t\t}, OO.ui.theme.getDialogTransitionDuration() );\n\t\t}\n\t}\n\n\treturn this;\n};\n\n/**\n * Find the page closest to the specified page.\n *\n * @param {OO.ui.PageLayout} page Page to use as a reference point\n * @return {OO.ui.PageLayout|null} Page closest to the specified page\n */\nOO.ui.BookletLayout.prototype.findClosestPage = function ( page ) {\n\tvar next, prev, level,\n\t\tpages = this.stackLayout.getItems(),\n\t\tindex = pages.indexOf( page );\n\n\tif ( index !== -1 ) {\n\t\tnext = pages[ index + 1 ];\n\t\tprev = pages[ index - 1 ];\n\t\t// Prefer adjacent pages at the same level\n\t\tif ( this.outlined ) {\n\t\t\tlevel = this.outlineSelectWidget.findItemFromData( page.getName() ).getLevel();\n\t\t\tif (\n\t\t\t\tprev &&\n\t\t\t\tlevel === this.outlineSelectWidget.findItemFromData( prev.getName() ).getLevel()\n\t\t\t) {\n\t\t\t\treturn prev;\n\t\t\t}\n\t\t\tif (\n\t\t\t\tnext &&\n\t\t\t\tlevel === this.outlineSelectWidget.findItemFromData( next.getName() ).getLevel()\n\t\t\t) {\n\t\t\t\treturn next;\n\t\t\t}\n\t\t}\n\t}\n\treturn prev || next || null;\n};\n\n/**\n * Get the outline widget.\n *\n * If the booklet is not outlined, the method will return `null`.\n *\n * @return {OO.ui.OutlineSelectWidget|null} Outline widget, or null if the booklet is not outlined\n */\nOO.ui.BookletLayout.prototype.getOutline = function () {\n\treturn this.outlineSelectWidget;\n};\n\n/**\n * Get the outline controls widget.\n *\n * If the outline is not editable, the method will return `null`.\n *\n * @return {OO.ui.OutlineControlsWidget|null} The outline controls widget.\n */\nOO.ui.BookletLayout.prototype.getOutlineControls = function () {\n\treturn this.outlineControlsWidget;\n};\n\n/**\n * Get a page by its symbolic name.\n *\n * @param {string} name Symbolic name of page\n * @return {OO.ui.PageLayout|undefined} Page, if found\n */\nOO.ui.BookletLayout.prototype.getPage = function ( name ) {\n\treturn this.pages[ name ];\n};\n\n/**\n * Get the current page.\n *\n * @return {OO.ui.PageLayout|undefined} Current page, if found\n */\nOO.ui.BookletLayout.prototype.getCurrentPage = function () {\n\tvar name = this.getCurrentPageName();\n\treturn name ? this.getPage( name ) : undefined;\n};\n\n/**\n * Get the symbolic name of the current page.\n *\n * @return {string|null} Symbolic name of the current page\n */\nOO.ui.BookletLayout.prototype.getCurrentPageName = function () {\n\treturn this.currentPageName;\n};\n\n/**\n * Add pages to the booklet layout\n *\n * When pages are added with the same names as existing pages, the existing pages will be\n * automatically removed before the new pages are added.\n *\n * @param {OO.ui.PageLayout[]} pages Pages to add\n * @param {number} index Index of the insertion point\n * @fires add\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.BookletLayout.prototype.addPages = function ( pages, index ) {\n\tvar i, len, name, page, item, currentIndex,\n\t\tstackLayoutPages = this.stackLayout.getItems(),\n\t\tremove = [],\n\t\titems = [];\n\n\t// Remove pages with same names\n\tfor ( i = 0, len = pages.length; i < len; i++ ) {\n\t\tpage = pages[ i ];\n\t\tname = page.getName();\n\n\t\tif ( Object.prototype.hasOwnProperty.call( this.pages, name ) ) {\n\t\t\t// Correct the insertion index\n\t\t\tcurrentIndex = stackLayoutPages.indexOf( this.pages[ name ] );\n\t\t\tif ( currentIndex !== -1 && currentIndex + 1 < index ) {\n\t\t\t\tindex--;\n\t\t\t}\n\t\t\tremove.push( this.pages[ name ] );\n\t\t}\n\t}\n\tif ( remove.length ) {\n\t\tthis.removePages( remove );\n\t}\n\n\t// Add new pages\n\tfor ( i = 0, len = pages.length; i < len; i++ ) {\n\t\tpage = pages[ i ];\n\t\tname = page.getName();\n\t\tthis.pages[ page.getName() ] = page;\n\t\tif ( this.outlined ) {\n\t\t\titem = new OO.ui.OutlineOptionWidget( { data: name } );\n\t\t\tpage.setOutlineItem( item );\n\t\t\titems.push( item );\n\t\t}\n\t}\n\n\tif ( this.outlined && items.length ) {\n\t\tthis.outlineSelectWidget.addItems( items, index );\n\t\tthis.selectFirstSelectablePage();\n\t}\n\tthis.stackLayout.addItems( pages, index );\n\tthis.emit( 'add', pages, index );\n\n\treturn this;\n};\n\n/**\n * Remove the specified pages from the booklet layout.\n *\n * To remove all pages from the booklet, you may wish to use the #clearPages method instead.\n *\n * @param {OO.ui.PageLayout[]} pages An array of pages to remove\n * @fires remove\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.BookletLayout.prototype.removePages = function ( pages ) {\n\tvar i, len, name, page,\n\t\titems = [];\n\n\tfor ( i = 0, len = pages.length; i < len; i++ ) {\n\t\tpage = pages[ i ];\n\t\tname = page.getName();\n\t\tdelete this.pages[ name ];\n\t\tif ( this.outlined ) {\n\t\t\titems.push( this.outlineSelectWidget.findItemFromData( name ) );\n\t\t\tpage.setOutlineItem( null );\n\t\t}\n\t}\n\tif ( this.outlined && items.length ) {\n\t\tthis.outlineSelectWidget.removeItems( items );\n\t\tthis.selectFirstSelectablePage();\n\t}\n\tthis.stackLayout.removeItems( pages );\n\tthis.emit( 'remove', pages );\n\n\treturn this;\n};\n\n/**\n * Clear all pages from the booklet layout.\n *\n * To remove only a subset of pages from the booklet, use the #removePages method.\n *\n * @fires remove\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.BookletLayout.prototype.clearPages = function () {\n\tvar i, len,\n\t\tpages = this.stackLayout.getItems();\n\n\tthis.pages = {};\n\tthis.currentPageName = null;\n\tif ( this.outlined ) {\n\t\tthis.outlineSelectWidget.clearItems();\n\t\tfor ( i = 0, len = pages.length; i < len; i++ ) {\n\t\t\tpages[ i ].setOutlineItem( null );\n\t\t}\n\t}\n\tthis.stackLayout.clearItems();\n\n\tthis.emit( 'remove', pages );\n\n\treturn this;\n};\n\n/**\n * Set the current page by symbolic name.\n *\n * @fires set\n * @param {string} name Symbolic name of page\n */\nOO.ui.BookletLayout.prototype.setPage = function ( name ) {\n\tvar selectedItem,\n\t\t$focused,\n\t\tpage = this.pages[ name ],\n\t\tpreviousPage = this.currentPageName && this.pages[ this.currentPageName ];\n\n\tif ( name !== this.currentPageName ) {\n\t\tif ( this.outlined ) {\n\t\t\tselectedItem = this.outlineSelectWidget.findSelectedItem();\n\t\t\tif ( selectedItem && selectedItem.getData() !== name ) {\n\t\t\t\tthis.outlineSelectWidget.selectItemByData( name );\n\t\t\t}\n\t\t}\n\t\tif ( page ) {\n\t\t\tif ( previousPage ) {\n\t\t\t\tpreviousPage.setActive( false );\n\t\t\t\t// Blur anything focused if the next page doesn't have anything focusable.\n\t\t\t\t// This is not needed if the next page has something focusable (because once it is\n\t\t\t\t// focused this blur happens automatically). If the layout is non-continuous, this\n\t\t\t\t// check is meaningless because the next page is not visible yet and thus can't\n\t\t\t\t// hold focus.\n\t\t\t\tif (\n\t\t\t\t\tthis.autoFocus &&\n\t\t\t\t\t!OO.ui.isMobile() &&\n\t\t\t\t\tthis.stackLayout.continuous &&\n\t\t\t\t\tOO.ui.findFocusable( page.$element ).length !== 0\n\t\t\t\t) {\n\t\t\t\t\t$focused = previousPage.$element.find( ':focus' );\n\t\t\t\t\tif ( $focused.length ) {\n\t\t\t\t\t\t$focused[ 0 ].blur();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.currentPageName = name;\n\t\t\tpage.setActive( true );\n\t\t\tthis.stackLayout.setItem( page );\n\t\t\tif ( !this.stackLayout.continuous && previousPage ) {\n\t\t\t\t// This should not be necessary, since any inputs on the previous page should have\n\t\t\t\t// been blurred when it was hidden, but browsers are not very consistent about\n\t\t\t\t// this.\n\t\t\t\t$focused = previousPage.$element.find( ':focus' );\n\t\t\t\tif ( $focused.length ) {\n\t\t\t\t\t$focused[ 0 ].blur();\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.emit( 'set', page );\n\t\t}\n\t}\n};\n\n/**\n * For outlined-continuous booklets, also reset the outlineSelectWidget to the first item.\n *\n * @inheritdoc\n */\nOO.ui.BookletLayout.prototype.resetScroll = function () {\n\t// Parent method\n\tOO.ui.BookletLayout.parent.prototype.resetScroll.call( this );\n\n\tif (\n\t\tthis.outlined &&\n\t\tthis.stackLayout.continuous &&\n\t\tthis.outlineSelectWidget.findFirstSelectableItem()\n\t) {\n\t\tthis.scrolling = true;\n\t\tthis.outlineSelectWidget.selectItem( this.outlineSelectWidget.findFirstSelectableItem() );\n\t\tthis.scrolling = false;\n\t}\n\treturn this;\n};\n\n/**\n * Select the first selectable page.\n *\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.BookletLayout.prototype.selectFirstSelectablePage = function () {\n\tif ( !this.outlineSelectWidget.findSelectedItem() ) {\n\t\tthis.outlineSelectWidget.selectItem( this.outlineSelectWidget.findFirstSelectableItem() );\n\t}\n\n\treturn this;\n};\n","/**\n * IndexLayouts contain {@link OO.ui.TabPanelLayout tab panel layouts} as well as\n * {@link OO.ui.TabSelectWidget tabs} that allow users to easily navigate through the tab panels\n * and select which one to display. By default, only one tab panel is displayed at a time. When a\n * user navigates to a new tab panel, the index layout automatically focuses on the first focusable\n * element, unless the default setting is changed.\n *\n * TODO: This class is similar to BookletLayout, we may want to refactor to reduce duplication\n *\n *     @example\n *     // Example of a IndexLayout that contains two TabPanelLayouts.\n *\n *     function TabPanelOneLayout( name, config ) {\n *         TabPanelOneLayout.parent.call( this, name, config );\n *         this.$element.append( '<p>First tab panel</p>' );\n *     }\n *     OO.inheritClass( TabPanelOneLayout, OO.ui.TabPanelLayout );\n *     TabPanelOneLayout.prototype.setupTabItem = function () {\n *         this.tabItem.setLabel( 'Tab panel one' );\n *     };\n *\n *     var tabPanel1 = new TabPanelOneLayout( 'one' ),\n *         tabPanel2 = new OO.ui.TabPanelLayout( 'two', { label: 'Tab panel two' } );\n *\n *     tabPanel2.$element.append( '<p>Second tab panel</p>' );\n *\n *     var index = new OO.ui.IndexLayout();\n *\n *     index.addTabPanels( [ tabPanel1, tabPanel2 ] );\n *     $( document.body ).append( index.$element );\n *\n * @class\n * @extends OO.ui.MenuLayout\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {OO.ui.StackLayout} [contentPanel] Content stack (see MenuLayout)\n * @cfg {boolean} [continuous=false] Show all tab panels, one after another\n * @cfg {boolean} [autoFocus=true] Focus on the first focusable element when a new tab panel is\n *  displayed. Disabled on mobile.\n */\nOO.ui.IndexLayout = function OoUiIndexLayout( config ) {\n\t// Configuration initialization\n\tconfig = $.extend( {}, config, { menuPosition: 'top' } );\n\n\t// Parent constructor\n\tOO.ui.IndexLayout.parent.call( this, config );\n\n\t// Properties\n\tthis.currentTabPanelName = null;\n\t// Allow infused widgets to pass existing tabPanels\n\tthis.tabPanels = config.tabPanels || {};\n\n\tthis.ignoreFocus = false;\n\tthis.stackLayout = this.contentPanel || new OO.ui.StackLayout( {\n\t\tcontinuous: !!config.continuous,\n\t\texpanded: this.expanded\n\t} );\n\tthis.setContentPanel( this.stackLayout );\n\tthis.autoFocus = config.autoFocus === undefined || !!config.autoFocus;\n\n\t// Allow infused widgets to pass an existing tabSelectWidget\n\tthis.tabSelectWidget = config.tabSelectWidget || new OO.ui.TabSelectWidget();\n\tthis.tabPanel = this.menuPanel || new OO.ui.PanelLayout( {\n\t\texpanded: this.expanded\n\t} );\n\tthis.setMenuPanel( this.tabPanel );\n\n\tthis.toggleMenu( true );\n\n\t// Events\n\tthis.stackLayout.connect( this, {\n\t\tset: 'onStackLayoutSet'\n\t} );\n\tthis.tabSelectWidget.connect( this, {\n\t\tselect: 'onTabSelectWidgetSelect'\n\t} );\n\tif ( this.autoFocus ) {\n\t\t// Event 'focus' does not bubble, but 'focusin' does.\n\t\tthis.stackLayout.$element.on( 'focusin', this.onStackLayoutFocus.bind( this ) );\n\t}\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-indexLayout' );\n\tthis.stackLayout.$element.addClass( 'oo-ui-indexLayout-stackLayout' );\n\tthis.tabPanel.$element\n\t\t.addClass( 'oo-ui-indexLayout-tabPanel' )\n\t\t.append( this.tabSelectWidget.$element );\n\n\tthis.selectFirstSelectableTabPanel();\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.IndexLayout, OO.ui.MenuLayout );\n\n/* Events */\n\n/**\n * A 'set' event is emitted when a tab panel is {@link #setTabPanel set} to be displayed by the\n * index layout.\n *\n * @event set\n * @param {OO.ui.TabPanelLayout} tabPanel Current tab panel\n */\n\n/**\n * An 'add' event is emitted when tab panels are {@link #addTabPanels added} to the index layout.\n *\n * @event add\n * @param {OO.ui.TabPanelLayout[]} tabPanel Added tab panels\n * @param {number} index Index tab panels were added at\n */\n\n/**\n * A 'remove' event is emitted when tab panels are {@link #clearTabPanels cleared} or\n * {@link #removeTabPanels removed} from the index.\n *\n * @event remove\n * @param {OO.ui.TabPanelLayout[]} tabPanel Removed tab panels\n */\n\n/* Methods */\n\n/**\n * Handle stack layout focus.\n *\n * @private\n * @param {jQuery.Event} e Focusing event\n */\nOO.ui.IndexLayout.prototype.onStackLayoutFocus = function ( e ) {\n\tvar name, $target;\n\n\t// Find the tab panel that an element was focused within\n\t$target = $( e.target ).closest( '.oo-ui-tabPanelLayout' );\n\tfor ( name in this.tabPanels ) {\n\t\t// Check for tab panel match, exclude current tab panel to find only tab panel changes\n\t\tif ( this.tabPanels[ name ].$element[ 0 ] === $target[ 0 ] &&\n\t\t\t\tname !== this.currentTabPanelName ) {\n\t\t\tthis.setTabPanel( name );\n\t\t\tbreak;\n\t\t}\n\t}\n};\n\n/**\n * Handle stack layout set events.\n *\n * @private\n * @param {OO.ui.PanelLayout|null} tabPanel The tab panel that is now the current panel\n */\nOO.ui.IndexLayout.prototype.onStackLayoutSet = function ( tabPanel ) {\n\t// If everything is unselected, do nothing\n\tif ( !tabPanel ) {\n\t\treturn;\n\t}\n\t// Focus the first element on the newly selected panel\n\tif ( this.autoFocus && !OO.ui.isMobile() ) {\n\t\tthis.focus();\n\t}\n};\n\n/**\n * Focus the first input in the current tab panel.\n *\n * If no tab panel is selected, the first selectable tab panel will be selected.\n * If the focus is already in an element on the current tab panel, nothing will happen.\n *\n * @param {number} [itemIndex] A specific item to focus on\n */\nOO.ui.IndexLayout.prototype.focus = function ( itemIndex ) {\n\tvar tabPanel,\n\t\titems = this.stackLayout.getItems();\n\n\tif ( itemIndex !== undefined && items[ itemIndex ] ) {\n\t\ttabPanel = items[ itemIndex ];\n\t} else {\n\t\ttabPanel = this.stackLayout.getCurrentItem();\n\t}\n\n\tif ( !tabPanel ) {\n\t\tthis.selectFirstSelectableTabPanel();\n\t\ttabPanel = this.stackLayout.getCurrentItem();\n\t}\n\tif ( !tabPanel ) {\n\t\treturn;\n\t}\n\t// Only change the focus if is not already in the current page\n\tif ( !OO.ui.contains(\n\t\ttabPanel.$element[ 0 ],\n\t\tthis.getElementDocument().activeElement,\n\t\ttrue\n\t) ) {\n\t\ttabPanel.focus();\n\t}\n};\n\n/**\n * Find the first focusable input in the index layout and focus\n * on it.\n */\nOO.ui.IndexLayout.prototype.focusFirstFocusable = function () {\n\tOO.ui.findFocusable( this.stackLayout.$element ).focus();\n};\n\n/**\n * Handle tab widget select events.\n *\n * @private\n * @param {OO.ui.OptionWidget|null} item Selected item\n */\nOO.ui.IndexLayout.prototype.onTabSelectWidgetSelect = function ( item ) {\n\tif ( item ) {\n\t\tthis.setTabPanel( item.getData() );\n\t}\n};\n\n/**\n * Get the tab panel closest to the specified tab panel.\n *\n * @param {OO.ui.TabPanelLayout} tabPanel Tab panel to use as a reference point\n * @return {OO.ui.TabPanelLayout|null} Tab panel closest to the specified\n */\nOO.ui.IndexLayout.prototype.getClosestTabPanel = function ( tabPanel ) {\n\tvar next, prev, level,\n\t\ttabPanels = this.stackLayout.getItems(),\n\t\tindex = tabPanels.indexOf( tabPanel );\n\n\tif ( index !== -1 ) {\n\t\tnext = tabPanels[ index + 1 ];\n\t\tprev = tabPanels[ index - 1 ];\n\t\t// Prefer adjacent tab panels at the same level\n\t\tlevel = this.tabSelectWidget.findItemFromData( tabPanel.getName() ).getLevel();\n\t\tif (\n\t\t\tprev &&\n\t\t\tlevel === this.tabSelectWidget.findItemFromData( prev.getName() ).getLevel()\n\t\t) {\n\t\t\treturn prev;\n\t\t}\n\t\tif (\n\t\t\tnext &&\n\t\t\tlevel === this.tabSelectWidget.findItemFromData( next.getName() ).getLevel()\n\t\t) {\n\t\t\treturn next;\n\t\t}\n\t}\n\treturn prev || next || null;\n};\n\n/**\n * Get the tabs widget.\n *\n * @return {OO.ui.TabSelectWidget} Tabs widget\n */\nOO.ui.IndexLayout.prototype.getTabs = function () {\n\treturn this.tabSelectWidget;\n};\n\n/**\n * Get a tab panel by its symbolic name.\n *\n * @param {string} name Symbolic name of tab panel\n * @return {OO.ui.TabPanelLayout|undefined} Tab panel, if found\n */\nOO.ui.IndexLayout.prototype.getTabPanel = function ( name ) {\n\treturn this.tabPanels[ name ];\n};\n\n/**\n * Get the current tab panel.\n *\n * @return {OO.ui.TabPanelLayout|undefined} Current tab panel, if found\n */\nOO.ui.IndexLayout.prototype.getCurrentTabPanel = function () {\n\tvar name = this.getCurrentTabPanelName();\n\treturn name ? this.getTabPanel( name ) : undefined;\n};\n\n/**\n * Get the symbolic name of the current tab panel.\n *\n * @return {string|null} Symbolic name of the current tab panel\n */\nOO.ui.IndexLayout.prototype.getCurrentTabPanelName = function () {\n\treturn this.currentTabPanelName;\n};\n\n/**\n * Add tab panels to the index layout.\n *\n * When tab panels are added with the same names as existing tab panels, the existing tab panels\n * will be automatically removed before the new tab panels are added.\n *\n * @param {OO.ui.TabPanelLayout[]} tabPanels Tab panels to add\n * @param {number} index Index of the insertion point\n * @fires add\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.IndexLayout.prototype.addTabPanels = function ( tabPanels, index ) {\n\tvar i, len, name, tabPanel, item, currentIndex,\n\t\tstackLayoutTabPanels = this.stackLayout.getItems(),\n\t\tremove = [],\n\t\titems = [];\n\n\t// Remove tab panels with same names\n\tfor ( i = 0, len = tabPanels.length; i < len; i++ ) {\n\t\ttabPanel = tabPanels[ i ];\n\t\tname = tabPanel.getName();\n\n\t\tif ( Object.prototype.hasOwnProperty.call( this.tabPanels, name ) ) {\n\t\t\t// Correct the insertion index\n\t\t\tcurrentIndex = stackLayoutTabPanels.indexOf( this.tabPanels[ name ] );\n\t\t\tif ( currentIndex !== -1 && currentIndex + 1 < index ) {\n\t\t\t\tindex--;\n\t\t\t}\n\t\t\tremove.push( this.tabPanels[ name ] );\n\t\t}\n\t}\n\tif ( remove.length ) {\n\t\tthis.removeTabPanels( remove );\n\t}\n\n\t// Add new tab panels\n\tfor ( i = 0, len = tabPanels.length; i < len; i++ ) {\n\t\ttabPanel = tabPanels[ i ];\n\t\tname = tabPanel.getName();\n\t\tthis.tabPanels[ tabPanel.getName() ] = tabPanel;\n\t\titem = new OO.ui.TabOptionWidget( { data: name } );\n\t\ttabPanel.setTabItem( item );\n\t\titems.push( item );\n\t}\n\n\tif ( items.length ) {\n\t\tthis.tabSelectWidget.addItems( items, index );\n\t\tthis.selectFirstSelectableTabPanel();\n\t}\n\tthis.stackLayout.addItems( tabPanels, index );\n\tthis.emit( 'add', tabPanels, index );\n\n\treturn this;\n};\n\n/**\n * Remove the specified tab panels from the index layout.\n *\n * To remove all tab panels from the index, you may wish to use the #clearTabPanels method instead.\n *\n * @param {OO.ui.TabPanelLayout[]} tabPanels An array of tab panels to remove\n * @fires remove\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.IndexLayout.prototype.removeTabPanels = function ( tabPanels ) {\n\tvar i, len, name, tabPanel,\n\t\titems = [];\n\n\tfor ( i = 0, len = tabPanels.length; i < len; i++ ) {\n\t\ttabPanel = tabPanels[ i ];\n\t\tname = tabPanel.getName();\n\t\tdelete this.tabPanels[ name ];\n\t\titems.push( this.tabSelectWidget.findItemFromData( name ) );\n\t\ttabPanel.setTabItem( null );\n\t}\n\tif ( items.length ) {\n\t\tthis.tabSelectWidget.removeItems( items );\n\t\tthis.selectFirstSelectableTabPanel();\n\t}\n\tthis.stackLayout.removeItems( tabPanels );\n\tthis.emit( 'remove', tabPanels );\n\n\treturn this;\n};\n\n/**\n * Clear all tab panels from the index layout.\n *\n * To remove only a subset of tab panels from the index, use the #removeTabPanels method.\n *\n * @fires remove\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.IndexLayout.prototype.clearTabPanels = function () {\n\tvar i, len,\n\t\ttabPanels = this.stackLayout.getItems();\n\n\tthis.tabPanels = {};\n\tthis.currentTabPanelName = null;\n\tthis.tabSelectWidget.clearItems();\n\tfor ( i = 0, len = tabPanels.length; i < len; i++ ) {\n\t\ttabPanels[ i ].setTabItem( null );\n\t}\n\tthis.stackLayout.clearItems();\n\n\tthis.emit( 'remove', tabPanels );\n\n\treturn this;\n};\n\n/**\n * Set the current tab panel by symbolic name.\n *\n * @fires set\n * @param {string} name Symbolic name of tab panel\n */\nOO.ui.IndexLayout.prototype.setTabPanel = function ( name ) {\n\tvar selectedItem,\n\t\t$focused,\n\t\tpreviousTabPanel,\n\t\ttabPanel = this.tabPanels[ name ];\n\n\tif ( name !== this.currentTabPanelName ) {\n\t\tpreviousTabPanel = this.getCurrentTabPanel();\n\t\tselectedItem = this.tabSelectWidget.findSelectedItem();\n\t\tif ( selectedItem && selectedItem.getData() !== name ) {\n\t\t\tthis.tabSelectWidget.selectItemByData( name );\n\t\t}\n\t\tif ( tabPanel ) {\n\t\t\tif ( previousTabPanel ) {\n\t\t\t\tpreviousTabPanel.setActive( false );\n\t\t\t\t// Blur anything focused if the next tab panel doesn't have anything focusable.\n\t\t\t\t// This is not needed if the next tab panel has something focusable (because once\n\t\t\t\t// it is focused this blur happens automatically). If the layout is non-continuous,\n\t\t\t\t// this check is meaningless because the next tab panel is not visible yet and thus\n\t\t\t\t// can't hold focus.\n\t\t\t\tif (\n\t\t\t\t\tthis.autoFocus &&\n\t\t\t\t\t!OO.ui.isMobile() &&\n\t\t\t\t\tthis.stackLayout.continuous &&\n\t\t\t\t\tOO.ui.findFocusable( tabPanel.$element ).length !== 0\n\t\t\t\t) {\n\t\t\t\t\t$focused = previousTabPanel.$element.find( ':focus' );\n\t\t\t\t\tif ( $focused.length ) {\n\t\t\t\t\t\t$focused[ 0 ].blur();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.currentTabPanelName = name;\n\t\t\ttabPanel.setActive( true );\n\t\t\tthis.stackLayout.setItem( tabPanel );\n\t\t\tif ( !this.stackLayout.continuous && previousTabPanel ) {\n\t\t\t\t// This should not be necessary, since any inputs on the previous tab panel should\n\t\t\t\t// have been blurred when it was hidden, but browsers are not very consistent about\n\t\t\t\t// this.\n\t\t\t\t$focused = previousTabPanel.$element.find( ':focus' );\n\t\t\t\tif ( $focused.length ) {\n\t\t\t\t\t$focused[ 0 ].blur();\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.emit( 'set', tabPanel );\n\t\t}\n\t}\n};\n\n/**\n * Select the first selectable tab panel.\n *\n * @chainable\n * @return {OO.ui.BookletLayout} The layout, for chaining\n */\nOO.ui.IndexLayout.prototype.selectFirstSelectableTabPanel = function () {\n\tif ( !this.tabSelectWidget.findSelectedItem() ) {\n\t\tthis.tabSelectWidget.selectItem( this.tabSelectWidget.findFirstSelectableItem() );\n\t}\n\n\treturn this;\n};\n","/**\n * ToggleWidget implements basic behavior of widgets with an on/off state.\n * Please see OO.ui.ToggleButtonWidget and OO.ui.ToggleSwitchWidget for examples.\n *\n * @abstract\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.TitledElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [value=false] The toggle’s initial on/off state.\n *  By default, the toggle is in the 'off' state.\n */\nOO.ui.ToggleWidget = function OoUiToggleWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.ToggleWidget.parent.call( this, config );\n\n\t// Mixin constructor\n\tOO.ui.mixin.TitledElement.call( this, config );\n\n\t// Properties\n\tthis.value = null;\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-toggleWidget' );\n\tthis.setValue( !!config.value );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ToggleWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.ToggleWidget, OO.ui.mixin.TitledElement );\n\n/* Events */\n\n/**\n * @event change\n *\n * A change event is emitted when the on/off state of the toggle changes.\n *\n * @param {boolean} value Value representing the new state of the toggle\n */\n\n/* Methods */\n\n/**\n * Get the value representing the toggle’s state.\n *\n * @return {boolean} The on/off state of the toggle\n */\nOO.ui.ToggleWidget.prototype.getValue = function () {\n\treturn this.value;\n};\n\n/**\n * Set the state of the toggle: `true` for 'on', `false` for 'off'.\n *\n * @param {boolean} value The state of the toggle\n * @fires change\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.ToggleWidget.prototype.setValue = function ( value ) {\n\tvalue = !!value;\n\tif ( this.value !== value ) {\n\t\tthis.value = value;\n\t\tthis.emit( 'change', value );\n\t\tthis.$element.toggleClass( 'oo-ui-toggleWidget-on', value );\n\t\tthis.$element.toggleClass( 'oo-ui-toggleWidget-off', !value );\n\t}\n\treturn this;\n};\n","/**\n * ToggleButtons are buttons that have a state (‘on’ or ‘off’) that is represented by a\n * Boolean value. Like other {@link OO.ui.ButtonWidget buttons}, toggle buttons can be\n * configured with {@link OO.ui.mixin.IconElement icons},\n * {@link OO.ui.mixin.IndicatorElement indicators},\n * {@link OO.ui.mixin.TitledElement titles}, {@link OO.ui.mixin.FlaggedElement styling flags},\n * and {@link OO.ui.mixin.LabelElement labels}. Please see\n * the [OOUI documentation][1] on MediaWiki for more information.\n *\n *     @example\n *     // Toggle buttons in the 'off' and 'on' state.\n *     var toggleButton1 = new OO.ui.ToggleButtonWidget( {\n *             label: 'Toggle Button off'\n *         } ),\n *         toggleButton2 = new OO.ui.ToggleButtonWidget( {\n *             label: 'Toggle Button on',\n *             value: true\n *         } );\n *     // Append the buttons to the DOM.\n *     $( document.body ).append( toggleButton1.$element, toggleButton2.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Buttons_and_Switches#Toggle_buttons\n *\n * @class\n * @extends OO.ui.ToggleWidget\n * @mixins OO.ui.mixin.ButtonElement\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.IndicatorElement\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.FlaggedElement\n * @mixins OO.ui.mixin.TabIndexedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [value=false] The toggle button’s initial on/off\n *  state. By default, the button is in the 'off' state.\n */\nOO.ui.ToggleButtonWidget = function OoUiToggleButtonWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.ToggleButtonWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.ButtonElement.call( this, $.extend( {\n\t\tactive: this.active\n\t}, config ) );\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.IndicatorElement.call( this, config );\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.FlaggedElement.call( this, config );\n\tOO.ui.mixin.TabIndexedElement.call( this, $.extend( {\n\t\t$tabIndexed: this.$button\n\t}, config ) );\n\n\t// Events\n\tthis.connect( this, {\n\t\tclick: 'onAction'\n\t} );\n\n\t// Initialization\n\tthis.$button.append( this.$icon, this.$label, this.$indicator );\n\tthis.$element\n\t\t.addClass( 'oo-ui-toggleButtonWidget' )\n\t\t.append( this.$button );\n\tthis.setTitledElement( this.$button );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ToggleButtonWidget, OO.ui.ToggleWidget );\nOO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.mixin.ButtonElement );\nOO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.mixin.IndicatorElement );\nOO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.mixin.FlaggedElement );\nOO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.mixin.TabIndexedElement );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.ToggleButtonWidget.static.tagName = 'span';\n\n/* Methods */\n\n/**\n * Handle the button action being triggered.\n *\n * @private\n */\nOO.ui.ToggleButtonWidget.prototype.onAction = function () {\n\tthis.setValue( !this.value );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.ToggleButtonWidget.prototype.setValue = function ( value ) {\n\tvalue = !!value;\n\tif ( value !== this.value ) {\n\t\t// Might be called from parent constructor before ButtonElement constructor\n\t\tif ( this.$button ) {\n\t\t\tthis.$button.attr( 'aria-pressed', value.toString() );\n\t\t}\n\t\tthis.setActive( value );\n\t}\n\n\t// Parent method\n\tOO.ui.ToggleButtonWidget.parent.prototype.setValue.call( this, value );\n\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.ToggleButtonWidget.prototype.setButtonElement = function ( $button ) {\n\tif ( this.$button ) {\n\t\tthis.$button.removeAttr( 'aria-pressed' );\n\t}\n\tOO.ui.mixin.ButtonElement.prototype.setButtonElement.call( this, $button );\n\tthis.$button.attr( 'aria-pressed', this.value.toString() );\n};\n","/**\n * ToggleSwitches are switches that slide on and off. Their state is represented by a Boolean\n * value (`true` for ‘on’, and `false` otherwise, the default). The ‘off’ state is represented\n * visually by a slider in the leftmost position.\n *\n *     @example\n *     // Toggle switches in the 'off' and 'on' position.\n *     var toggleSwitch1 = new OO.ui.ToggleSwitchWidget(),\n *         toggleSwitch2 = new OO.ui.ToggleSwitchWidget( {\n *             value: true\n *         } );\n *         // Create a FieldsetLayout to layout and label switches.\n *         fieldset = new OO.ui.FieldsetLayout( {\n *             label: 'Toggle switches'\n *         } );\n *     fieldset.addItems( [\n *         new OO.ui.FieldLayout( toggleSwitch1, {\n *             label: 'Off',\n *             align: 'top'\n *         } ),\n *         new OO.ui.FieldLayout( toggleSwitch2, {\n *             label: 'On',\n *             align: 'top'\n *         } )\n *     ] );\n *     $( document.body ).append( fieldset.$element );\n *\n * @class\n * @extends OO.ui.ToggleWidget\n * @mixins OO.ui.mixin.TabIndexedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {boolean} [value=false] The toggle switch’s initial on/off state.\n *  By default, the toggle switch is in the 'off' position.\n */\nOO.ui.ToggleSwitchWidget = function OoUiToggleSwitchWidget( config ) {\n\t// Parent constructor\n\tOO.ui.ToggleSwitchWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.TabIndexedElement.call( this, config );\n\n\t// Properties\n\tthis.dragging = false;\n\tthis.dragStart = null;\n\tthis.sliding = false;\n\tthis.$glow = $( '<span>' );\n\tthis.$grip = $( '<span>' );\n\n\t// Events\n\tthis.$element.on( {\n\t\tclick: this.onClick.bind( this ),\n\t\tkeypress: this.onKeyPress.bind( this )\n\t} );\n\n\t// Initialization\n\tthis.$glow.addClass( 'oo-ui-toggleSwitchWidget-glow' );\n\tthis.$grip.addClass( 'oo-ui-toggleSwitchWidget-grip' );\n\tthis.$element\n\t\t.addClass( 'oo-ui-toggleSwitchWidget' )\n\t\t.attr( 'role', 'checkbox' )\n\t\t.append( this.$glow, this.$grip );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ToggleSwitchWidget, OO.ui.ToggleWidget );\nOO.mixinClass( OO.ui.ToggleSwitchWidget, OO.ui.mixin.TabIndexedElement );\n\n/* Methods */\n\n/**\n * Handle mouse click events.\n *\n * @private\n * @param {jQuery.Event} e Mouse click event\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.ToggleSwitchWidget.prototype.onClick = function ( e ) {\n\tif ( !this.isDisabled() && e.which === OO.ui.MouseButtons.LEFT ) {\n\t\tthis.setValue( !this.value );\n\t}\n\treturn false;\n};\n\n/**\n * Handle key press events.\n *\n * @private\n * @param {jQuery.Event} e Key press event\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.ToggleSwitchWidget.prototype.onKeyPress = function ( e ) {\n\tif ( !this.isDisabled() && ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER ) ) {\n\t\tthis.setValue( !this.value );\n\t\treturn false;\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.ToggleSwitchWidget.prototype.setValue = function ( value ) {\n\tOO.ui.ToggleSwitchWidget.parent.prototype.setValue.call( this, value );\n\tthis.$element.attr( 'aria-checked', this.value.toString() );\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.ToggleSwitchWidget.prototype.simulateLabelClick = function () {\n\tif ( !this.isDisabled() ) {\n\t\tthis.setValue( !this.value );\n\t}\n\tthis.focus();\n};\n","/**\n * OutlineControlsWidget is a set of controls for an\n * {@link OO.ui.OutlineSelectWidget outline select widget}.\n * Controls include moving items up and down, removing items, and adding different kinds of items.\n *\n * **Currently, this class is only used by {@link OO.ui.BookletLayout booklet layouts}.**\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.GroupElement\n *\n * @constructor\n * @param {OO.ui.OutlineSelectWidget} outline Outline to control\n * @param {Object} [config] Configuration options\n * @cfg {Object} [abilities] List of abilties\n * @cfg {boolean} [abilities.move=true] Allow moving movable items\n * @cfg {boolean} [abilities.remove=true] Allow removing removable items\n */\nOO.ui.OutlineControlsWidget = function OoUiOutlineControlsWidget( outline, config ) {\n\t// Allow passing positional parameters inside the config object\n\tif ( OO.isPlainObject( outline ) && config === undefined ) {\n\t\tconfig = outline;\n\t\toutline = config.outline;\n\t}\n\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.OutlineControlsWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.GroupElement.call( this, config );\n\n\t// Properties\n\tthis.outline = outline;\n\tthis.$movers = $( '<div>' );\n\tthis.upButton = new OO.ui.ButtonWidget( {\n\t\tframed: false,\n\t\ticon: 'collapse',\n\t\ttitle: OO.ui.msg( 'ooui-outline-control-move-up' )\n\t} );\n\tthis.downButton = new OO.ui.ButtonWidget( {\n\t\tframed: false,\n\t\ticon: 'expand',\n\t\ttitle: OO.ui.msg( 'ooui-outline-control-move-down' )\n\t} );\n\tthis.removeButton = new OO.ui.ButtonWidget( {\n\t\tframed: false,\n\t\ticon: 'trash',\n\t\ttitle: OO.ui.msg( 'ooui-outline-control-remove' )\n\t} );\n\tthis.abilities = { move: true, remove: true };\n\n\t// Events\n\toutline.connect( this, {\n\t\tselect: 'onOutlineChange',\n\t\tadd: 'onOutlineChange',\n\t\tremove: 'onOutlineChange'\n\t} );\n\tthis.upButton.connect( this, {\n\t\tclick: [ 'emit', 'move', -1 ]\n\t} );\n\tthis.downButton.connect( this, {\n\t\tclick: [ 'emit', 'move', 1 ]\n\t} );\n\tthis.removeButton.connect( this, {\n\t\tclick: [ 'emit', 'remove' ]\n\t} );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-outlineControlsWidget' );\n\tthis.$group.addClass( 'oo-ui-outlineControlsWidget-items' );\n\tthis.$movers\n\t\t.addClass( 'oo-ui-outlineControlsWidget-movers' )\n\t\t.append( this.removeButton.$element, this.upButton.$element, this.downButton.$element );\n\tthis.$element.append( this.$icon, this.$group, this.$movers );\n\tthis.setAbilities( config.abilities || {} );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.OutlineControlsWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.OutlineControlsWidget, OO.ui.mixin.GroupElement );\n\n/* Events */\n\n/**\n * @event move\n * @param {number} places Number of places to move\n */\n\n/**\n * @event remove\n */\n\n/* Methods */\n\n/**\n * Set abilities.\n *\n * @param {Object} abilities List of abilties\n * @param {boolean} [abilities.move] Allow moving movable items\n * @param {boolean} [abilities.remove] Allow removing removable items\n */\nOO.ui.OutlineControlsWidget.prototype.setAbilities = function ( abilities ) {\n\tvar ability;\n\n\tfor ( ability in this.abilities ) {\n\t\tif ( abilities[ ability ] !== undefined ) {\n\t\t\tthis.abilities[ ability ] = !!abilities[ ability ];\n\t\t}\n\t}\n\n\tthis.onOutlineChange();\n};\n\n/**\n * Handle outline change events.\n *\n * @private\n */\nOO.ui.OutlineControlsWidget.prototype.onOutlineChange = function () {\n\tvar i, len, firstMovable, lastMovable,\n\t\titems = this.outline.getItems(),\n\t\tselectedItem = this.outline.findSelectedItem(),\n\t\tmovable = this.abilities.move && selectedItem && selectedItem.isMovable(),\n\t\tremovable = this.abilities.remove && selectedItem && selectedItem.isRemovable();\n\n\tif ( movable ) {\n\t\ti = -1;\n\t\tlen = items.length;\n\t\twhile ( ++i < len ) {\n\t\t\tif ( items[ i ].isMovable() ) {\n\t\t\t\tfirstMovable = items[ i ];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\ti = len;\n\t\twhile ( i-- ) {\n\t\t\tif ( items[ i ].isMovable() ) {\n\t\t\t\tlastMovable = items[ i ];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\tthis.upButton.setDisabled( !movable || selectedItem === firstMovable );\n\tthis.downButton.setDisabled( !movable || selectedItem === lastMovable );\n\tthis.removeButton.setDisabled( !removable );\n};\n","/**\n * OutlineOptionWidget is an item in an {@link OO.ui.OutlineSelectWidget OutlineSelectWidget}.\n *\n * Currently, this class is only used by {@link OO.ui.BookletLayout booklet layouts}, which contain\n * {@link OO.ui.PageLayout page layouts}. See {@link OO.ui.BookletLayout BookletLayout}\n * for an example.\n *\n * @class\n * @extends OO.ui.DecoratedOptionWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {number} [level] Indentation level\n * @cfg {boolean} [movable] Allow modification from\n *  {@link OO.ui.OutlineControlsWidget outline controls}.\n */\nOO.ui.OutlineOptionWidget = function OoUiOutlineOptionWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.OutlineOptionWidget.parent.call( this, config );\n\n\t// Properties\n\tthis.level = 0;\n\tthis.movable = !!config.movable;\n\tthis.removable = !!config.removable;\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-outlineOptionWidget' );\n\tthis.setLevel( config.level );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.OutlineOptionWidget, OO.ui.DecoratedOptionWidget );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.OutlineOptionWidget.static.highlightable = true;\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.OutlineOptionWidget.static.scrollIntoViewOnSelect = true;\n\n/**\n * @static\n * @inheritable\n * @property {string}\n */\nOO.ui.OutlineOptionWidget.static.levelClass = 'oo-ui-outlineOptionWidget-level-';\n\n/**\n * @static\n * @inheritable\n * @property {number}\n */\nOO.ui.OutlineOptionWidget.static.levels = 3;\n\n/* Methods */\n\n/**\n * Check if item is movable.\n *\n * Movability is used by {@link OO.ui.OutlineControlsWidget outline controls}.\n *\n * @return {boolean} Item is movable\n */\nOO.ui.OutlineOptionWidget.prototype.isMovable = function () {\n\treturn this.movable;\n};\n\n/**\n * Check if item is removable.\n *\n * Removability is used by {@link OO.ui.OutlineControlsWidget outline controls}.\n *\n * @return {boolean} Item is removable\n */\nOO.ui.OutlineOptionWidget.prototype.isRemovable = function () {\n\treturn this.removable;\n};\n\n/**\n * Get indentation level.\n *\n * @return {number} Indentation level\n */\nOO.ui.OutlineOptionWidget.prototype.getLevel = function () {\n\treturn this.level;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.OutlineOptionWidget.prototype.setPressed = function ( state ) {\n\tOO.ui.OutlineOptionWidget.parent.prototype.setPressed.call( this, state );\n\treturn this;\n};\n\n/**\n * Set movability.\n *\n * Movability is used by {@link OO.ui.OutlineControlsWidget outline controls}.\n *\n * @param {boolean} movable Item is movable\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.OutlineOptionWidget.prototype.setMovable = function ( movable ) {\n\tthis.movable = !!movable;\n\tthis.updateThemeClasses();\n\treturn this;\n};\n\n/**\n * Set removability.\n *\n * Removability is used by {@link OO.ui.OutlineControlsWidget outline controls}.\n *\n * @param {boolean} removable Item is removable\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.OutlineOptionWidget.prototype.setRemovable = function ( removable ) {\n\tthis.removable = !!removable;\n\tthis.updateThemeClasses();\n\treturn this;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.OutlineOptionWidget.prototype.setSelected = function ( state ) {\n\tOO.ui.OutlineOptionWidget.parent.prototype.setSelected.call( this, state );\n\treturn this;\n};\n\n/**\n * Set indentation level.\n *\n * @param {number} [level=0] Indentation level, in the range of [0,#maxLevel]\n * @chainable\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.OutlineOptionWidget.prototype.setLevel = function ( level ) {\n\tvar levels = this.constructor.static.levels,\n\t\tlevelClass = this.constructor.static.levelClass,\n\t\ti = levels;\n\n\tthis.level = level ? Math.max( 0, Math.min( levels - 1, level ) ) : 0;\n\twhile ( i-- ) {\n\t\tif ( this.level === i ) {\n\t\t\tthis.$element.addClass( levelClass + i );\n\t\t} else {\n\t\t\tthis.$element.removeClass( levelClass + i );\n\t\t}\n\t}\n\tthis.updateThemeClasses();\n\n\treturn this;\n};\n","/**\n * OutlineSelectWidget is a structured list that contains\n * {@link OO.ui.OutlineOptionWidget outline options}\n * A set of controls can be provided with an {@link OO.ui.OutlineControlsWidget outline controls}\n * widget.\n *\n * **Currently, this class is only used by {@link OO.ui.BookletLayout booklet layouts}.**\n *\n * @class\n * @extends OO.ui.SelectWidget\n * @mixins OO.ui.mixin.TabIndexedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.OutlineSelectWidget = function OoUiOutlineSelectWidget( config ) {\n\t// Parent constructor\n\tOO.ui.OutlineSelectWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.TabIndexedElement.call( this, config );\n\n\t// Events\n\tthis.$element.on( {\n\t\tfocus: this.bindDocumentKeyDownListener.bind( this ),\n\t\tblur: this.unbindDocumentKeyDownListener.bind( this )\n\t} );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-outlineSelectWidget' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.OutlineSelectWidget, OO.ui.SelectWidget );\nOO.mixinClass( OO.ui.OutlineSelectWidget, OO.ui.mixin.TabIndexedElement );\n","/**\n * ButtonOptionWidget is a special type of {@link OO.ui.mixin.ButtonElement button element} that\n * can be selected and configured with data. The class is\n * used with OO.ui.ButtonSelectWidget to create a selection of button options. Please see the\n * [OOUI documentation on MediaWiki] [1] for more information.\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options#Button_selects_and_options\n *\n * @class\n * @extends OO.ui.OptionWidget\n * @mixins OO.ui.mixin.ButtonElement\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.IndicatorElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.ButtonOptionWidget = function OoUiButtonOptionWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.ButtonOptionWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.ButtonElement.call( this, config );\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.IndicatorElement.call( this, config );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-buttonOptionWidget' );\n\tthis.$button.append( this.$icon, this.$label, this.$indicator );\n\tthis.$element.append( this.$button );\n\tthis.setTitledElement( this.$button );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ButtonOptionWidget, OO.ui.OptionWidget );\nOO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.mixin.ButtonElement );\nOO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.mixin.IndicatorElement );\n\n/* Static Properties */\n\n/**\n * Allow button mouse down events to pass through so they can be handled by the parent select widget\n *\n * @static\n * @inheritdoc\n */\nOO.ui.ButtonOptionWidget.static.cancelButtonMouseDownEvents = false;\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.ButtonOptionWidget.static.highlightable = false;\n\n/* Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.ButtonOptionWidget.prototype.setSelected = function ( state ) {\n\tOO.ui.ButtonOptionWidget.parent.prototype.setSelected.call( this, state );\n\n\tif ( this.constructor.static.selectable ) {\n\t\tthis.setActive( state );\n\t}\n\n\treturn this;\n};\n","/**\n * ButtonSelectWidget is a {@link OO.ui.SelectWidget select widget} that contains\n * button options and is used together with\n * OO.ui.ButtonOptionWidget. The ButtonSelectWidget provides an interface for\n * highlighting, choosing, and selecting mutually exclusive options. Please see\n * the [OOUI documentation on MediaWiki] [1] for more information.\n *\n *     @example\n *     // A ButtonSelectWidget that contains three ButtonOptionWidgets.\n *     var option1 = new OO.ui.ButtonOptionWidget( {\n *             data: 1,\n *             label: 'Option 1',\n *             title: 'Button option 1'\n *         } ),\n *         option2 = new OO.ui.ButtonOptionWidget( {\n *             data: 2,\n *             label: 'Option 2',\n *             title: 'Button option 2'\n *         } ),\n *         option3 = new OO.ui.ButtonOptionWidget( {\n *             data: 3,\n *             label: 'Option 3',\n *             title: 'Button option 3'\n *         } ),\n *         buttonSelect = new OO.ui.ButtonSelectWidget( {\n *             items: [ option1, option2, option3 ]\n *         } );\n *     $( document.body ).append( buttonSelect.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options\n *\n * @class\n * @extends OO.ui.SelectWidget\n * @mixins OO.ui.mixin.TabIndexedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.ButtonSelectWidget = function OoUiButtonSelectWidget( config ) {\n\t// Parent constructor\n\tOO.ui.ButtonSelectWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.TabIndexedElement.call( this, config );\n\n\t// Events\n\tthis.$element.on( {\n\t\tfocus: this.bindDocumentKeyDownListener.bind( this ),\n\t\tblur: this.unbindDocumentKeyDownListener.bind( this )\n\t} );\n\n\t// Initialization\n\tthis.$element.addClass( 'oo-ui-buttonSelectWidget' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.ButtonSelectWidget, OO.ui.SelectWidget );\nOO.mixinClass( OO.ui.ButtonSelectWidget, OO.ui.mixin.TabIndexedElement );\n","/**\n * TabOptionWidget is an item in a {@link OO.ui.TabSelectWidget TabSelectWidget}.\n *\n * Currently, this class is only used by {@link OO.ui.IndexLayout index layouts}, which contain\n * {@link OO.ui.TabPanelLayout tab panel layouts}. See {@link OO.ui.IndexLayout IndexLayout}\n * for an example.\n *\n * @class\n * @extends OO.ui.OptionWidget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.TabOptionWidget = function OoUiTabOptionWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.TabOptionWidget.parent.call( this, config );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-tabOptionWidget' )\n\t\t.attr( 'role', 'tab' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.TabOptionWidget, OO.ui.OptionWidget );\n\n/* Static Properties */\n\n/**\n * @static\n * @inheritdoc\n */\nOO.ui.TabOptionWidget.static.highlightable = false;\n","/**\n * TabSelectWidget is a list that contains {@link OO.ui.TabOptionWidget tab options}\n *\n * **Currently, this class is only used by {@link OO.ui.IndexLayout index layouts}.**\n *\n * @class\n * @extends OO.ui.SelectWidget\n * @mixins OO.ui.mixin.TabIndexedElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n */\nOO.ui.TabSelectWidget = function OoUiTabSelectWidget( config ) {\n\t// Parent constructor\n\tOO.ui.TabSelectWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.TabIndexedElement.call( this, config );\n\n\t// Events\n\tthis.$element.on( {\n\t\tfocus: this.bindDocumentKeyDownListener.bind( this ),\n\t\tblur: this.unbindDocumentKeyDownListener.bind( this )\n\t} );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-tabSelectWidget' )\n\t\t.attr( 'role', 'tablist' );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.TabSelectWidget, OO.ui.SelectWidget );\nOO.mixinClass( OO.ui.TabSelectWidget, OO.ui.mixin.TabIndexedElement );\n","/**\n * TagItemWidgets are used within a {@link OO.ui.TagMultiselectWidget\n * TagMultiselectWidget} to display the selected items.\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.ItemWidget\n * @mixins OO.ui.mixin.LabelElement\n * @mixins OO.ui.mixin.FlaggedElement\n * @mixins OO.ui.mixin.TabIndexedElement\n * @mixins OO.ui.mixin.DraggableElement\n *\n * @constructor\n * @param {Object} [config] Configuration object\n * @cfg {boolean} [valid=true] Item is valid\n * @cfg {boolean} [fixed] Item is fixed. This means the item is\n *  always included in the values and cannot be removed.\n */\nOO.ui.TagItemWidget = function OoUiTagItemWidget( config ) {\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.TagItemWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.ItemWidget.call( this );\n\tOO.ui.mixin.LabelElement.call( this, config );\n\tOO.ui.mixin.FlaggedElement.call( this, config );\n\tOO.ui.mixin.TabIndexedElement.call( this, config );\n\tOO.ui.mixin.DraggableElement.call( this, config );\n\n\tthis.valid = config.valid === undefined ? true : !!config.valid;\n\tthis.fixed = !!config.fixed;\n\n\tthis.closeButton = new OO.ui.ButtonWidget( {\n\t\tframed: false,\n\t\ticon: 'close',\n\t\ttabIndex: -1,\n\t\ttitle: OO.ui.msg( 'ooui-item-remove' )\n\t} );\n\tthis.closeButton.setDisabled( this.isDisabled() );\n\n\t// Events\n\tthis.closeButton.connect( this, {\n\t\tclick: 'remove'\n\t} );\n\tthis.$element\n\t\t.on( 'click', this.select.bind( this ) )\n\t\t.on( 'keydown', this.onKeyDown.bind( this ) )\n\t\t// Prevent propagation of mousedown; the tag item \"lives\" in the\n\t\t// clickable area of the TagMultiselectWidget, which listens to\n\t\t// mousedown to open the menu or popup. We want to prevent that\n\t\t// for clicks specifically on the tag itself, so the actions taken\n\t\t// are more deliberate. When the tag is clicked, it will emit the\n\t\t// selection event (similar to how #OO.ui.MultioptionWidget emits 'change')\n\t\t// and can be handled separately.\n\t\t.on( 'mousedown', function ( e ) { e.stopPropagation(); } );\n\n\t// Initialization\n\tthis.$element\n\t\t.addClass( 'oo-ui-tagItemWidget' )\n\t\t.append( this.$label, this.closeButton.$element );\n};\n\n/* Initialization */\n\nOO.inheritClass( OO.ui.TagItemWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.TagItemWidget, OO.ui.mixin.ItemWidget );\nOO.mixinClass( OO.ui.TagItemWidget, OO.ui.mixin.LabelElement );\nOO.mixinClass( OO.ui.TagItemWidget, OO.ui.mixin.FlaggedElement );\nOO.mixinClass( OO.ui.TagItemWidget, OO.ui.mixin.TabIndexedElement );\nOO.mixinClass( OO.ui.TagItemWidget, OO.ui.mixin.DraggableElement );\n\n/* Events */\n\n/**\n * @event remove\n *\n * A remove action was performed on the item\n */\n\n/**\n * @event navigate\n * @param {string} direction Direction of the movement, forward or backwards\n *\n * A navigate action was performed on the item\n */\n\n/**\n * @event select\n *\n * The tag widget was selected. This can occur when the widget\n * is either clicked or enter was pressed on it.\n */\n\n/**\n * @event valid\n * @param {boolean} isValid Item is valid\n *\n * Item validity has changed\n */\n\n/**\n * @event fixed\n * @param {boolean} isFixed Item is fixed\n *\n * Item fixed state has changed\n */\n\n/* Methods */\n\n/**\n * Set this item as fixed, meaning it cannot be removed\n *\n * @param {string} [state] Item is fixed\n * @fires fixed\n * @return {OO.ui.Widget} The widget, for chaining\n */\nOO.ui.TagItemWidget.prototype.setFixed = function ( state ) {\n\tstate = state === undefined ? !this.fixed : !!state;\n\n\tif ( this.fixed !== state ) {\n\t\tthis.fixed = state;\n\t\tif ( this.closeButton ) {\n\t\t\tthis.closeButton.toggle( !this.fixed );\n\t\t}\n\n\t\tif ( !this.fixed && this.elementGroup && !this.elementGroup.isDraggable() ) {\n\t\t\t// Only enable the state of the item if the\n\t\t\t// entire group is draggable\n\t\t\tthis.toggleDraggable( !this.fixed );\n\t\t}\n\t\tthis.$element.toggleClass( 'oo-ui-tagItemWidget-fixed', this.fixed );\n\n\t\tthis.emit( 'fixed', this.isFixed() );\n\t}\n\treturn this;\n};\n\n/**\n * Check whether the item is fixed\n * @return {boolean}\n */\nOO.ui.TagItemWidget.prototype.isFixed = function () {\n\treturn this.fixed;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.TagItemWidget.prototype.setDisabled = function ( state ) {\n\tif ( state && this.elementGroup && !this.elementGroup.isDisabled() ) {\n\t\tOO.ui.warnDeprecation( 'TagItemWidget#setDisabled: Disabling individual items is deprecated and will result in inconsistent behavior. Use #setFixed instead. See T193571.' );\n\t}\n\t// Parent method\n\tOO.ui.TagItemWidget.parent.prototype.setDisabled.call( this, state );\n\tif (\n\t\t!state &&\n\t\t// Verify we have a group, and that the widget is ready\n\t\tthis.toggleDraggable && this.elementGroup &&\n\t\t!this.isFixed() &&\n\t\t!this.elementGroup.isDraggable()\n\t) {\n\t\t// Only enable the draggable state of the item if the\n\t\t// entire group is draggable to begin with, and if the\n\t\t// item is not fixed\n\t\tthis.toggleDraggable( !state );\n\t}\n\n\tif ( this.closeButton ) {\n\t\tthis.closeButton.setDisabled( state );\n\t}\n\n\treturn this;\n};\n\n/**\n * Handle removal of the item\n *\n * This is mainly for extensibility concerns, so other children\n * of this class can change the behavior if they need to. This\n * is called by both clicking the 'remove' button but also\n * on keypress, which is harder to override if needed.\n *\n * @fires remove\n */\nOO.ui.TagItemWidget.prototype.remove = function () {\n\tif ( !this.isDisabled() && !this.isFixed() ) {\n\t\tthis.emit( 'remove' );\n\t}\n};\n\n/**\n * Handle a keydown event on the widget\n *\n * @fires navigate\n * @fires remove\n * @param {jQuery.Event} e Key down event\n * @return {boolean|undefined} false to stop the operation\n */\nOO.ui.TagItemWidget.prototype.onKeyDown = function ( e ) {\n\tvar movement;\n\n\tif (\n\t\t!this.isDisabled() &&\n\t\t!this.isFixed() &&\n\t\t( e.keyCode === OO.ui.Keys.BACKSPACE || e.keyCode === OO.ui.Keys.DELETE )\n\t) {\n\t\tthis.remove();\n\t\treturn false;\n\t} else if ( e.keyCode === OO.ui.Keys.ENTER ) {\n\t\tthis.select();\n\t\treturn false;\n\t} else if (\n\t\te.keyCode === OO.ui.Keys.LEFT ||\n\t\te.keyCode === OO.ui.Keys.RIGHT\n\t) {\n\t\tif ( OO.ui.Element.static.getDir( this.$element ) === 'rtl' ) {\n\t\t\tmovement = {\n\t\t\t\tleft: 'forwards',\n\t\t\t\tright: 'backwards'\n\t\t\t};\n\t\t} else {\n\t\t\tmovement = {\n\t\t\t\tleft: 'backwards',\n\t\t\t\tright: 'forwards'\n\t\t\t};\n\t\t}\n\n\t\tthis.emit(\n\t\t\t'navigate',\n\t\t\te.keyCode === OO.ui.Keys.LEFT ?\n\t\t\t\tmovement.left : movement.right\n\t\t);\n\t\treturn false;\n\t}\n};\n\n/**\n * Select this item\n *\n * @fires select\n */\nOO.ui.TagItemWidget.prototype.select = function () {\n\tif ( !this.isDisabled() ) {\n\t\tthis.emit( 'select' );\n\t}\n};\n\n/**\n * Set the valid state of this item\n *\n * @param {boolean} [valid] Item is valid\n * @fires valid\n */\nOO.ui.TagItemWidget.prototype.toggleValid = function ( valid ) {\n\tvalid = valid === undefined ? !this.valid : !!valid;\n\n\tif ( this.valid !== valid ) {\n\t\tthis.valid = valid;\n\n\t\tthis.setFlags( { invalid: !this.valid } );\n\n\t\tthis.emit( 'valid', this.valid );\n\t}\n};\n\n/**\n * Check whether the item is valid\n *\n * @return {boolean} Item is valid\n */\nOO.ui.TagItemWidget.prototype.isValid = function () {\n\treturn this.valid;\n};\n","/**\n * A basic tag multiselect widget, similar in concept to\n * {@link OO.ui.ComboBoxInputWidget combo box widget} that allows the user to add multiple values\n * that are displayed in a tag area.\n *\n * This widget is a base widget; see {@link OO.ui.MenuTagMultiselectWidget MenuTagMultiselectWidget}\n * and {@link OO.ui.PopupTagMultiselectWidget PopupTagMultiselectWidget} for the implementations\n * that use a menu and a popup respectively.\n *\n *     @example\n *     // A TagMultiselectWidget.\n *     var widget = new OO.ui.TagMultiselectWidget( {\n *         inputPosition: 'outline',\n *         allowedValues: [ 'Option 1', 'Option 2', 'Option 3' ],\n *         selected: [ 'Option 1' ]\n *     } );\n *     $( document.body ).append( widget.$element );\n *\n * @class\n * @extends OO.ui.Widget\n * @mixins OO.ui.mixin.GroupWidget\n * @mixins OO.ui.mixin.DraggableGroupElement\n * @mixins OO.ui.mixin.IndicatorElement\n * @mixins OO.ui.mixin.IconElement\n * @mixins OO.ui.mixin.TabIndexedElement\n * @mixins OO.ui.mixin.FlaggedElement\n * @mixins OO.ui.mixin.TitledElement\n *\n * @constructor\n * @param {Object} config Configuration object\n * @cfg {Object} [input] Configuration options for the input widget\n * @cfg {OO.ui.InputWidget} [inputWidget] An optional input widget. If given, it will\n *  replace the input widget used in the TagMultiselectWidget. If not given,\n *  TagMultiselectWidget creates its own.\n * @cfg {boolean} [inputPosition='inline'] Position of the input. Options are:\n *  - inline: The input is invisible, but exists inside the tag list, so\n *    the user types into the tag groups to add tags.\n *  - outline: The input is underneath the tag area.\n *  - none: No input supplied\n * @cfg {boolean} [allowEditTags=true] Allow editing of the tags by clicking them\n * @cfg {boolean} [allowArbitrary=false] Allow data items to be added even if\n *  not present in the menu.\n * @cfg {Object[]} [allowedValues] An array representing the allowed items\n *  by their datas.\n * @cfg {boolean} [allowDuplicates=false] Allow duplicate items to be added\n * @cfg {boolean} [allowDisplayInvalidTags=false] Allow the display of\n *  invalid tags. These tags will display with an invalid state, and\n *  the widget as a whole will have an invalid state if any invalid tags\n *  are present.\n * @cfg {number} [tagLimit] An optional limit on the number of selected options.\n *  If 'tagLimit' is set and is reached, the input is disabled, not allowing any\n *  additions. If 'tagLimit' is unset or is 0, an unlimited number of items can be\n *  added.\n * @cfg {boolean} [allowReordering=true] Allow reordering of the items\n * @cfg {Object[]|String[]} [selected] A set of selected tags. If given,\n *  these will appear in the tag list on initialization, as long as they\n *  pass the validity tests.\n */\nOO.ui.TagMultiselectWidget = function OoUiTagMultiselectWidget( config ) {\n\tvar inputEvents,\n\t\trAF = window.requestAnimationFrame || setTimeout,\n\t\twidget = this,\n\t\t$tabFocus = $( '<span>' ).addClass( 'oo-ui-tagMultiselectWidget-focusTrap' );\n\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.TagMultiselectWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.GroupWidget.call( this, config );\n\tOO.ui.mixin.IndicatorElement.call( this, config );\n\tOO.ui.mixin.IconElement.call( this, config );\n\tOO.ui.mixin.TabIndexedElement.call( this, config );\n\tOO.ui.mixin.FlaggedElement.call( this, config );\n\tOO.ui.mixin.DraggableGroupElement.call( this, config );\n\tOO.ui.mixin.TitledElement.call( this, config );\n\n\tthis.toggleDraggable(\n\t\tconfig.allowReordering === undefined ?\n\t\t\ttrue : !!config.allowReordering\n\t);\n\n\tthis.inputPosition =\n\t\tthis.constructor.static.allowedInputPositions.indexOf( config.inputPosition ) > -1 ?\n\t\t\tconfig.inputPosition : 'inline';\n\tthis.allowEditTags = config.allowEditTags === undefined ? true : !!config.allowEditTags;\n\tthis.allowArbitrary = !!config.allowArbitrary;\n\tthis.allowDuplicates = !!config.allowDuplicates;\n\tthis.allowedValues = config.allowedValues || [];\n\tthis.allowDisplayInvalidTags = config.allowDisplayInvalidTags;\n\tthis.hasInput = this.inputPosition !== 'none';\n\tthis.tagLimit = config.tagLimit;\n\tthis.height = null;\n\tthis.valid = true;\n\n\tthis.$content = $( '<div>' ).addClass( 'oo-ui-tagMultiselectWidget-content' );\n\tthis.$handle = $( '<div>' )\n\t\t.addClass( 'oo-ui-tagMultiselectWidget-handle' )\n\t\t.append(\n\t\t\tthis.$indicator,\n\t\t\tthis.$icon,\n\t\t\tthis.$content\n\t\t\t\t.append(\n\t\t\t\t\tthis.$group.addClass( 'oo-ui-tagMultiselectWidget-group' )\n\t\t\t\t)\n\t\t);\n\n\t// Events\n\tthis.aggregate( {\n\t\tremove: 'itemRemove',\n\t\tnavigate: 'itemNavigate',\n\t\tselect: 'itemSelect',\n\t\tfixed: 'itemFixed'\n\t} );\n\tthis.connect( this, {\n\t\titemRemove: 'onTagRemove',\n\t\titemSelect: 'onTagSelect',\n\t\titemFixed: 'onTagFixed',\n\t\titemNavigate: 'onTagNavigate',\n\t\tchange: 'onChangeTags'\n\t} );\n\tthis.$handle.on( {\n\t\tmousedown: this.onMouseDown.bind( this )\n\t} );\n\n\t// Initialize\n\tthis.$element\n\t\t.addClass( 'oo-ui-tagMultiselectWidget' )\n\t\t.append( this.$handle );\n\n\tif ( this.hasInput ) {\n\t\tif ( config.inputWidget ) {\n\t\t\tthis.input = config.inputWidget;\n\t\t} else {\n\t\t\tthis.input = new OO.ui.TextInputWidget( $.extend( {\n\t\t\t\tplaceholder: config.placeholder,\n\t\t\t\tclasses: [ 'oo-ui-tagMultiselectWidget-input' ]\n\t\t\t}, config.input ) );\n\t\t}\n\t\tthis.input.setDisabled( this.isDisabled() );\n\n\t\tinputEvents = {\n\t\t\tfocus: this.onInputFocus.bind( this ),\n\t\t\tblur: this.onInputBlur.bind( this ),\n\t\t\t'propertychange change click mouseup keydown keyup input cut paste select focus':\n\t\t\t\tOO.ui.debounce( this.updateInputSize.bind( this ) ),\n\t\t\tkeydown: this.onInputKeyDown.bind( this ),\n\t\t\tkeypress: this.onInputKeyPress.bind( this )\n\t\t};\n\n\t\tthis.input.$input.on( inputEvents );\n\t\tthis.inputPlaceholder = this.input.$input.attr( 'placeholder' );\n\n\t\tif ( this.inputPosition === 'outline' ) {\n\t\t\t// Override max-height for the input widget\n\t\t\t// in the case the widget is outline so it can\n\t\t\t// stretch all the way if the widget is wide\n\t\t\tthis.input.$element.css( 'max-width', 'inherit' );\n\t\t\tthis.$element\n\t\t\t\t.addClass( 'oo-ui-tagMultiselectWidget-outlined' )\n\t\t\t\t.append( this.input.$element );\n\t\t} else {\n\t\t\tthis.$element.addClass( 'oo-ui-tagMultiselectWidget-inlined' );\n\t\t\t// HACK: When the widget is using 'inline' input, the\n\t\t\t// behavior needs to only use the $input itself\n\t\t\t// so we style and size it accordingly (otherwise\n\t\t\t// the styling and sizing can get very convoluted\n\t\t\t// when the wrapping divs and other elements)\n\t\t\t// We are taking advantage of still being able to\n\t\t\t// call the widget itself for operations like\n\t\t\t// .getValue() and setDisabled() and .focus() but\n\t\t\t// having only the $input attached to the DOM\n\t\t\tthis.$content.append( this.input.$input );\n\t\t}\n\t} else {\n\t\tthis.$content.append( $tabFocus );\n\t}\n\n\tthis.setTabIndexedElement(\n\t\tthis.hasInput ?\n\t\t\tthis.input.$input :\n\t\t\t$tabFocus\n\t);\n\n\tif ( config.selected ) {\n\t\tthis.setValue( config.selected );\n\t}\n\n\t// HACK: Input size needs to be calculated after everything\n\t// else is rendered\n\trAF( function () {\n\t\tif ( widget.hasInput ) {\n\t\t\twidget.updateInputSize();\n\t\t}\n\t} );\n};\n\n/* Initialization */\n\nOO.inheritClass( OO.ui.TagMultiselectWidget, OO.ui.Widget );\nOO.mixinClass( OO.ui.TagMultiselectWidget, OO.ui.mixin.GroupWidget );\nOO.mixinClass( OO.ui.TagMultiselectWidget, OO.ui.mixin.DraggableGroupElement );\nOO.mixinClass( OO.ui.TagMultiselectWidget, OO.ui.mixin.IndicatorElement );\nOO.mixinClass( OO.ui.TagMultiselectWidget, OO.ui.mixin.IconElement );\nOO.mixinClass( OO.ui.TagMultiselectWidget, OO.ui.mixin.TabIndexedElement );\nOO.mixinClass( OO.ui.TagMultiselectWidget, OO.ui.mixin.FlaggedElement );\nOO.mixinClass( OO.ui.TagMultiselectWidget, OO.ui.mixin.TitledElement );\n\n/* Static properties */\n\n/**\n * Allowed input positions.\n * - inline: The input is inside the tag list\n * - outline: The input is under the tag list\n * - none: There is no input\n *\n * @property {Array}\n */\nOO.ui.TagMultiselectWidget.static.allowedInputPositions = [ 'inline', 'outline', 'none' ];\n\n/* Methods */\n\n/**\n * Handle mouse down events.\n *\n * @private\n * @param {jQuery.Event} e Mouse down event\n * @return {boolean} False to prevent defaults\n */\nOO.ui.TagMultiselectWidget.prototype.onMouseDown = function ( e ) {\n\tif (\n\t\t!this.isDisabled() &&\n\t\t( !this.hasInput || e.target !== this.input.$input[ 0 ] ) &&\n\t\te.which === OO.ui.MouseButtons.LEFT\n\t) {\n\t\tthis.focus();\n\t\treturn false;\n\t}\n};\n\n/**\n * Handle key press events.\n *\n * @private\n * @param {jQuery.Event} e Key press event\n * @return {boolean} Whether to prevent defaults\n */\nOO.ui.TagMultiselectWidget.prototype.onInputKeyPress = function ( e ) {\n\tvar stopOrContinue,\n\t\twithMetaKey = e.metaKey || e.ctrlKey;\n\n\tif ( !this.isDisabled() ) {\n\t\tif ( e.which === OO.ui.Keys.ENTER ) {\n\t\t\tstopOrContinue = this.doInputEnter( e, withMetaKey );\n\t\t}\n\n\t\t// Make sure the input gets resized.\n\t\tsetTimeout( this.updateInputSize.bind( this ), 0 );\n\t\treturn stopOrContinue;\n\t}\n};\n\n/**\n * Handle key down events.\n *\n * @private\n * @param {jQuery.Event} e Key down event\n * @return {boolean}\n */\nOO.ui.TagMultiselectWidget.prototype.onInputKeyDown = function ( e ) {\n\tvar movement, direction,\n\t\twidget = this,\n\t\twithMetaKey = e.metaKey || e.ctrlKey,\n\t\tisMovementInsideInput = function ( direction ) {\n\t\t\tvar inputRange = widget.input.getRange(),\n\t\t\t\tinputValue = widget.hasInput && widget.input.getValue();\n\n\t\t\tif ( direction === 'forwards' && inputRange.to > inputValue.length - 1 ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif ( direction === 'backwards' && inputRange.from <= 0 ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t};\n\n\tif ( !this.isDisabled() ) {\n\t\t// 'keypress' event is not triggered for Backspace key\n\t\tif ( e.keyCode === OO.ui.Keys.BACKSPACE ) {\n\t\t\treturn this.doInputBackspace( e, withMetaKey );\n\t\t} else if ( e.keyCode === OO.ui.Keys.ESCAPE ) {\n\t\t\treturn this.doInputEscape( e );\n\t\t} else if (\n\t\t\te.keyCode === OO.ui.Keys.LEFT ||\n\t\t\te.keyCode === OO.ui.Keys.RIGHT\n\t\t) {\n\t\t\tif ( OO.ui.Element.static.getDir( this.$element ) === 'rtl' ) {\n\t\t\t\tmovement = {\n\t\t\t\t\tleft: 'forwards',\n\t\t\t\t\tright: 'backwards'\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\tmovement = {\n\t\t\t\t\tleft: 'backwards',\n\t\t\t\t\tright: 'forwards'\n\t\t\t\t};\n\t\t\t}\n\t\t\tdirection = e.keyCode === OO.ui.Keys.LEFT ?\n\t\t\t\tmovement.left : movement.right;\n\n\t\t\tif ( !this.hasInput || !isMovementInsideInput( direction ) ) {\n\t\t\t\treturn this.doInputArrow( e, direction, withMetaKey );\n\t\t\t}\n\t\t}\n\t}\n};\n\n/**\n * Respond to input focus event\n */\nOO.ui.TagMultiselectWidget.prototype.onInputFocus = function () {\n\tthis.$element.addClass( 'oo-ui-tagMultiselectWidget-focus' );\n\t// Reset validity\n\tthis.toggleValid( true );\n};\n\n/**\n * Respond to input blur event\n */\nOO.ui.TagMultiselectWidget.prototype.onInputBlur = function () {\n\tthis.$element.removeClass( 'oo-ui-tagMultiselectWidget-focus' );\n\n\t// Set the widget as invalid if there's text in the input\n\tthis.addTagFromInput();\n\tthis.toggleValid( this.checkValidity() && ( !this.hasInput || !this.input.getValue() ) );\n};\n\n/**\n * Perform an action after the Enter key on the input\n *\n * @param {jQuery.Event} e Event data\n * @param {boolean} [withMetaKey] Whether this key was pressed with\n * a meta key like Control\n * @return {boolean} Whether to prevent defaults\n */\nOO.ui.TagMultiselectWidget.prototype.doInputEnter = function () {\n\tthis.addTagFromInput();\n\treturn false;\n};\n\n/**\n * Perform an action responding to the Enter key on the input\n *\n * @param {jQuery.Event} e Event data\n * @param {boolean} [withMetaKey] Whether this key was pressed with\n * a meta key like Control\n * @return {boolean} Whether to prevent defaults\n */\nOO.ui.TagMultiselectWidget.prototype.doInputBackspace = function ( e, withMetaKey ) {\n\tvar items, item;\n\n\tif (\n\t\tthis.inputPosition === 'inline' &&\n\t\tthis.input.getValue() === '' &&\n\t\t!this.isEmpty()\n\t) {\n\t\t// Delete the last item\n\t\titems = this.getItems();\n\t\titem = items[ items.length - 1 ];\n\n\t\tif ( !item.isDisabled() && !item.isFixed() ) {\n\t\t\tthis.removeItems( [ item ] );\n\t\t\t// If Ctrl/Cmd was pressed, delete item entirely.\n\t\t\t// Otherwise put it into the text field for editing.\n\t\t\tif ( !withMetaKey ) {\n\t\t\t\tthis.input.setValue( item.getLabel() );\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n};\n\n/**\n * Perform an action after the Escape key on the input\n *\n * @param {jQuery.Event} e Event data\n */\nOO.ui.TagMultiselectWidget.prototype.doInputEscape = function () {\n\tthis.clearInput();\n};\n\n/**\n * Perform an action after the Left/Right arrow key on the input, select the previous\n * item from the input.\n * See #getPreviousItem\n *\n * @param {jQuery.Event} e Event data\n * @param {string} direction Direction of the movement; forwards or backwards\n * @param {boolean} [withMetaKey] Whether this key was pressed with\n *  a meta key like Control\n */\nOO.ui.TagMultiselectWidget.prototype.doInputArrow = function ( e, direction ) {\n\tif (\n\t\tthis.inputPosition === 'inline' &&\n\t\t!this.isEmpty() &&\n\t\tdirection === 'backwards'\n\t) {\n\t\t// Get previous item\n\t\tthis.getPreviousItem().focus();\n\t}\n};\n\n/**\n * Respond to item select event\n *\n * @param {OO.ui.TagItemWidget} item Selected item\n */\nOO.ui.TagMultiselectWidget.prototype.onTagSelect = function ( item ) {\n\tif ( this.hasInput && this.allowEditTags && !item.isFixed() ) {\n\t\tif ( this.input.getValue() ) {\n\t\t\tthis.addTagFromInput();\n\t\t}\n\t\t// 1. Get the label of the tag into the input\n\t\tthis.input.setValue( item.getLabel() );\n\t\t// 2. Remove the tag\n\t\tthis.removeItems( [ item ] );\n\t\t// 3. Focus the input\n\t\tthis.focus();\n\t}\n};\n\n/**\n * Respond to item fixed state change\n *\n * @param {OO.ui.TagItemWidget} item Selected item\n */\nOO.ui.TagMultiselectWidget.prototype.onTagFixed = function ( item ) {\n\tvar i,\n\t\titems = this.getItems();\n\n\t// Move item to the end of the static items\n\tfor ( i = 0; i < items.length; i++ ) {\n\t\tif ( items[ i ] !== item && !items[ i ].isFixed() ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\tthis.addItems( item, i );\n};\n/**\n * Respond to change event, where items were added, removed, or cleared.\n */\nOO.ui.TagMultiselectWidget.prototype.onChangeTags = function () {\n\tvar isUnderLimit = this.isUnderLimit();\n\n\t// Reset validity\n\tthis.toggleValid(\n\t\tthis.checkValidity() &&\n\t\t!( this.hasInput && this.input.getValue() )\n\t);\n\n\tif ( this.hasInput ) {\n\t\tthis.updateInputSize();\n\t\tif ( !isUnderLimit ) {\n\t\t\t// Clear the input\n\t\t\tthis.input.setValue( '' );\n\t\t}\n\t\tif ( this.inputPosition === 'outline' ) {\n\t\t\t// Show/clear the placeholder and enable/disable the input\n\t\t\t// based on whether we are/aren't under the specified limit\n\t\t\tthis.input.$input.attr( 'placeholder', isUnderLimit ? this.inputPlaceholder : '' );\n\t\t\tthis.input.setDisabled( !isUnderLimit );\n\t\t} else {\n\t\t\t// Show/hide the input\n\t\t\tthis.input.$input.toggleClass( 'oo-ui-element-hidden', !isUnderLimit );\n\t\t}\n\t}\n\tthis.updateIfHeightChanged();\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.TagMultiselectWidget.prototype.setDisabled = function ( isDisabled ) {\n\t// Parent method\n\tOO.ui.TagMultiselectWidget.parent.prototype.setDisabled.call( this, isDisabled );\n\n\tif ( this.hasInput && this.input ) {\n\t\tif ( !isDisabled ) {\n\t\t\tthis.updateInputSize();\n\t\t}\n\t\tthis.input.setDisabled( !!isDisabled && !this.isUnderLimit() );\n\t}\n\n\tif ( this.items ) {\n\t\tthis.getItems().forEach( function ( item ) {\n\t\t\titem.setDisabled( !!isDisabled );\n\t\t} );\n\t}\n};\n\n/**\n * Respond to tag remove event\n * @param {OO.ui.TagItemWidget} item Removed tag\n */\nOO.ui.TagMultiselectWidget.prototype.onTagRemove = function ( item ) {\n\tthis.removeTagByData( item.getData() );\n};\n\n/**\n * Respond to navigate event on the tag\n *\n * @param {OO.ui.TagItemWidget} item Removed tag\n * @param {string} direction Direction of movement; 'forwards' or 'backwards'\n */\nOO.ui.TagMultiselectWidget.prototype.onTagNavigate = function ( item, direction ) {\n\tvar firstItem = this.getItems()[ 0 ];\n\n\tif ( direction === 'forwards' ) {\n\t\tthis.getNextItem( item ).focus();\n\t} else if ( !this.inputPosition === 'inline' || item !== firstItem ) {\n\t\t// If the widget has an inline input, we want to stop at the starting edge\n\t\t// of the tags\n\t\tthis.getPreviousItem( item ).focus();\n\t}\n};\n\n/**\n * Add tag from input value\n */\nOO.ui.TagMultiselectWidget.prototype.addTagFromInput = function () {\n\tvar val = this.input.getValue(),\n\t\tisValid = this.isAllowedData( val );\n\n\tif ( !val ) {\n\t\treturn;\n\t}\n\n\tif ( isValid || this.allowDisplayInvalidTags ) {\n\t\tthis.clearInput();\n\t\tthis.addTag( val );\n\t}\n};\n\n/**\n * Clear the input\n */\nOO.ui.TagMultiselectWidget.prototype.clearInput = function () {\n\tthis.input.setValue( '' );\n};\n\n/**\n * Check whether the given value is a duplicate of an existing\n * tag already in the list.\n *\n * @param {string|Object} data Requested value\n * @return {boolean} Value is duplicate\n */\nOO.ui.TagMultiselectWidget.prototype.isDuplicateData = function ( data ) {\n\treturn !!this.findItemFromData( data );\n};\n\n/**\n * Check whether a given value is allowed to be added\n *\n * @param {string|Object} data Requested value\n * @return {boolean} Value is allowed\n */\nOO.ui.TagMultiselectWidget.prototype.isAllowedData = function ( data ) {\n\tif (\n\t\t!this.allowDuplicates &&\n\t\tthis.isDuplicateData( data )\n\t) {\n\t\treturn false;\n\t}\n\n\tif ( this.allowArbitrary ) {\n\t\treturn true;\n\t}\n\n\t// Check with allowed values\n\tif (\n\t\tthis.getAllowedValues().some( function ( value ) {\n\t\t\treturn data === value;\n\t\t} )\n\t) {\n\t\treturn true;\n\t}\n\n\treturn false;\n};\n\n/**\n * Get the allowed values list\n *\n * @return {string[]} Allowed data values\n */\nOO.ui.TagMultiselectWidget.prototype.getAllowedValues = function () {\n\treturn this.allowedValues;\n};\n\n/**\n * Add a value to the allowed values list\n *\n * @param {string} value Allowed data value\n */\nOO.ui.TagMultiselectWidget.prototype.addAllowedValue = function ( value ) {\n\tif ( this.allowedValues.indexOf( value ) === -1 ) {\n\t\tthis.allowedValues.push( value );\n\t}\n};\n\n/**\n * Get the datas of the currently selected items\n *\n * @return {string[]|Object[]} Datas of currently selected items\n */\nOO.ui.TagMultiselectWidget.prototype.getValue = function () {\n\treturn this.getItems()\n\t\t.filter( function ( item ) {\n\t\t\treturn item.isValid();\n\t\t} )\n\t\t.map( function ( item ) {\n\t\t\treturn item.getData();\n\t\t} );\n};\n\n/**\n * Set the value of this widget by datas.\n *\n * @param {string|string[]|Object|Object[]} valueObject An object representing the data\n *  and label of the value. If the widget allows arbitrary values,\n *  the items will be added as-is. Otherwise, the data value will\n *  be checked against allowedValues.\n *  This object must contain at least a data key. Example:\n *  { data: 'foo', label: 'Foo item' }\n *  For multiple items, use an array of objects. For example:\n *  [\n *     { data: 'foo', label: 'Foo item' },\n *     { data: 'bar', label: 'Bar item' }\n *  ]\n *  Value can also be added with plaintext array, for example:\n *  [ 'foo', 'bar', 'bla' ] or a single string, like 'foo'\n */\nOO.ui.TagMultiselectWidget.prototype.setValue = function ( valueObject ) {\n\tvalueObject = Array.isArray( valueObject ) ? valueObject : [ valueObject ];\n\n\tthis.clearItems();\n\tvalueObject.forEach( function ( obj ) {\n\t\tif ( typeof obj === 'string' ) {\n\t\t\tthis.addTag( obj );\n\t\t} else {\n\t\t\tthis.addTag( obj.data, obj.label );\n\t\t}\n\t}.bind( this ) );\n};\n\n/**\n * Add tag to the display area\n *\n * @param {string|Object} data Tag data\n * @param {string} [label] Tag label. If no label is provided, the\n *  stringified version of the data will be used instead.\n * @return {boolean} Item was added successfully\n */\nOO.ui.TagMultiselectWidget.prototype.addTag = function ( data, label ) {\n\tvar newItemWidget,\n\t\tisValid = this.isAllowedData( data );\n\n\tif ( this.isUnderLimit() && ( isValid || this.allowDisplayInvalidTags ) ) {\n\t\tnewItemWidget = this.createTagItemWidget( data, label );\n\t\tnewItemWidget.toggleValid( isValid );\n\t\tthis.addItems( [ newItemWidget ] );\n\t\treturn true;\n\t}\n\n\treturn false;\n};\n\n/**\n * Check whether the number of current tags is within the limit.\n *\n * @return {boolean} True if current tag count is within the limit or\n *  if 'tagLimit' is not set\n */\nOO.ui.TagMultiselectWidget.prototype.isUnderLimit = function () {\n\treturn !this.tagLimit ||\n\t\tthis.getItemCount() < this.tagLimit;\n};\n\n/**\n * Remove tag by its data property.\n *\n * @param {string|Object} data Tag data\n */\nOO.ui.TagMultiselectWidget.prototype.removeTagByData = function ( data ) {\n\tvar item = this.findItemFromData( data );\n\n\tthis.removeItems( [ item ] );\n};\n\n/**\n * Construct a OO.ui.TagItemWidget (or a subclass thereof) from given label and data.\n *\n * @protected\n * @param {string} data Item data\n * @param {string} label The label text.\n * @return {OO.ui.TagItemWidget}\n */\nOO.ui.TagMultiselectWidget.prototype.createTagItemWidget = function ( data, label ) {\n\tlabel = label || data;\n\n\treturn new OO.ui.TagItemWidget( { data: data, label: label } );\n};\n\n/**\n * Given an item, returns the item after it. If the item is already the\n * last item, return `this.input`. If no item is passed, returns the\n * very first item.\n *\n * @protected\n * @param {OO.ui.TagItemWidget} [item] Tag item\n * @return {OO.ui.Widget} The next widget available.\n */\nOO.ui.TagMultiselectWidget.prototype.getNextItem = function ( item ) {\n\tvar itemIndex = this.items.indexOf( item );\n\n\tif ( item === undefined || itemIndex === -1 ) {\n\t\treturn this.items[ 0 ];\n\t}\n\n\tif ( itemIndex === this.items.length - 1 ) { // Last item\n\t\tif ( this.hasInput ) {\n\t\t\treturn this.input;\n\t\t} else {\n\t\t\t// Return first item\n\t\t\treturn this.items[ 0 ];\n\t\t}\n\t} else {\n\t\treturn this.items[ itemIndex + 1 ];\n\t}\n};\n\n/**\n * Given an item, returns the item before it. If the item is already the\n * first item, return `this.input`. If no item is passed, returns the\n * very last item.\n *\n * @protected\n * @param {OO.ui.TagItemWidget} [item] Tag item\n * @return {OO.ui.Widget} The previous widget available.\n */\nOO.ui.TagMultiselectWidget.prototype.getPreviousItem = function ( item ) {\n\tvar itemIndex = this.items.indexOf( item );\n\n\tif ( item === undefined || itemIndex === -1 ) {\n\t\treturn this.items[ this.items.length - 1 ];\n\t}\n\n\tif ( itemIndex === 0 ) {\n\t\tif ( this.hasInput ) {\n\t\t\treturn this.input;\n\t\t} else {\n\t\t\t// Return the last item\n\t\t\treturn this.items[ this.items.length - 1 ];\n\t\t}\n\t} else {\n\t\treturn this.items[ itemIndex - 1 ];\n\t}\n};\n\n/**\n * Update the dimensions of the text input field to encompass all available area.\n * This is especially relevant for when the input is at the edge of a line\n * and should get smaller. The usual operation (as an inline-block with min-width)\n * does not work in that case, pushing the input downwards to the next line.\n *\n * @private\n */\nOO.ui.TagMultiselectWidget.prototype.updateInputSize = function () {\n\tvar $lastItem, direction, contentWidth, currentWidth, bestWidth;\n\tif ( this.inputPosition === 'inline' && !this.isDisabled() ) {\n\t\tif ( this.input.$input[ 0 ].scrollWidth === 0 ) {\n\t\t\t// Input appears to be attached but not visible.\n\t\t\t// Don't attempt to adjust its size, because our measurements\n\t\t\t// are going to fail anyway.\n\t\t\treturn;\n\t\t}\n\t\tthis.input.$input.css( 'width', '1em' );\n\t\t$lastItem = this.$group.children().last();\n\t\tdirection = OO.ui.Element.static.getDir( this.$handle );\n\n\t\t// Get the width of the input with the placeholder text as\n\t\t// the value and save it so that we don't keep recalculating\n\t\tif (\n\t\t\tthis.contentWidthWithPlaceholder === undefined &&\n\t\t\tthis.input.getValue() === '' &&\n\t\t\tthis.input.$input.attr( 'placeholder' ) !== undefined\n\t\t) {\n\t\t\tthis.input.setValue( this.input.$input.attr( 'placeholder' ) );\n\t\t\tthis.contentWidthWithPlaceholder = this.input.$input[ 0 ].scrollWidth;\n\t\t\tthis.input.setValue( '' );\n\n\t\t}\n\n\t\t// Always keep the input wide enough for the placeholder text\n\t\tcontentWidth = Math.max(\n\t\t\tthis.input.$input[ 0 ].scrollWidth,\n\t\t\t// undefined arguments in Math.max lead to NaN\n\t\t\t( this.contentWidthWithPlaceholder === undefined ) ?\n\t\t\t\t0 : this.contentWidthWithPlaceholder\n\t\t);\n\t\tcurrentWidth = this.input.$input.width();\n\n\t\tif ( contentWidth < currentWidth ) {\n\t\t\tthis.updateIfHeightChanged();\n\t\t\t// All is fine, don't perform expensive calculations\n\t\t\treturn;\n\t\t}\n\n\t\tif ( $lastItem.length === 0 ) {\n\t\t\tbestWidth = this.$content.innerWidth();\n\t\t} else {\n\t\t\tbestWidth = direction === 'ltr' ?\n\t\t\t\tthis.$content.innerWidth() - $lastItem.position().left - $lastItem.outerWidth() :\n\t\t\t\t$lastItem.position().left;\n\t\t}\n\n\t\t// Some safety margin for sanity, because I *really* don't feel like finding out where the\n\t\t// few pixels this is off by are coming from.\n\t\tbestWidth -= 13;\n\t\tif ( contentWidth > bestWidth ) {\n\t\t\t// This will result in the input getting shifted to the next line\n\t\t\tbestWidth = this.$content.innerWidth() - 13;\n\t\t}\n\t\tthis.input.$input.width( Math.floor( bestWidth ) );\n\t\tthis.updateIfHeightChanged();\n\t} else {\n\t\tthis.updateIfHeightChanged();\n\t}\n};\n\n/**\n * Determine if widget height changed, and if so,\n * emit the resize event. This is useful for when there are either\n * menus or popups attached to the bottom of the widget, to allow\n * them to change their positioning in case the widget moved down\n * or up.\n *\n * @private\n */\nOO.ui.TagMultiselectWidget.prototype.updateIfHeightChanged = function () {\n\tvar height = this.$element.height();\n\tif ( height !== this.height ) {\n\t\tthis.height = height;\n\t\tthis.emit( 'resize' );\n\t}\n};\n\n/**\n * Check whether all items in the widget are valid\n *\n * @return {boolean} Widget is valid\n */\nOO.ui.TagMultiselectWidget.prototype.checkValidity = function () {\n\treturn this.getItems().every( function ( item ) {\n\t\treturn item.isValid();\n\t} );\n};\n\n/**\n * Set the valid state of this item\n *\n * @param {boolean} [valid] Item is valid\n * @fires valid\n */\nOO.ui.TagMultiselectWidget.prototype.toggleValid = function ( valid ) {\n\tvalid = valid === undefined ? !this.valid : !!valid;\n\n\tif ( this.valid !== valid ) {\n\t\tthis.valid = valid;\n\n\t\tthis.setFlags( { invalid: !this.valid } );\n\n\t\tthis.emit( 'valid', this.valid );\n\t}\n};\n\n/**\n * Get the current valid state of the widget\n *\n * @return {boolean} Widget is valid\n */\nOO.ui.TagMultiselectWidget.prototype.isValid = function () {\n\treturn this.valid;\n};\n","/**\n * PopupTagMultiselectWidget is a {@link OO.ui.TagMultiselectWidget OO.ui.TagMultiselectWidget}\n * intended to use a popup. The popup can be configured to have a default input to insert values\n * into the widget.\n *\n *     @example\n *     // A PopupTagMultiselectWidget.\n *     var widget = new OO.ui.PopupTagMultiselectWidget();\n *     $( document.body ).append( widget.$element );\n *\n *     // Example: A PopupTagMultiselectWidget with an external popup.\n *     var popupInput = new OO.ui.TextInputWidget(),\n *         widget = new OO.ui.PopupTagMultiselectWidget( {\n *            popupInput: popupInput,\n *            popup: {\n *               $content: popupInput.$element\n *            }\n *         } );\n *     $( document.body ).append( widget.$element );\n *\n * @class\n * @extends OO.ui.TagMultiselectWidget\n * @mixins OO.ui.mixin.PopupElement\n *\n * @param {Object} config Configuration object\n * @cfg {jQuery} [$overlay] An overlay for the popup.\n *  See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.\n * @cfg {Object} [popup] Configuration options for the popup\n * @cfg {OO.ui.InputWidget} [popupInput] An input widget inside the popup that will be\n *  focused when the popup is opened and will be used as replacement for the\n *  general input in the widget.\n * @deprecated\n */\nOO.ui.PopupTagMultiselectWidget = function OoUiPopupTagMultiselectWidget( config ) {\n\tvar defaultInput,\n\t\tdefaultConfig = { popup: {} };\n\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.PopupTagMultiselectWidget.parent.call( this, $.extend( {\n\t\tinputPosition: 'none'\n\t}, config ) );\n\n\tthis.$overlay = ( config.$overlay === true ?\n\t\tOO.ui.getDefaultOverlay() : config.$overlay ) || this.$element;\n\n\tif ( !config.popup ) {\n\t\t// For the default base implementation, we give a popup\n\t\t// with an input widget inside it. For any other use cases\n\t\t// the popup needs to be populated externally and the\n\t\t// event handled to add tags separately and manually\n\t\tdefaultInput = new OO.ui.TextInputWidget();\n\n\t\tdefaultConfig.popupInput = defaultInput;\n\t\tdefaultConfig.popup.$content = defaultInput.$element;\n\t\tdefaultConfig.popup.padded = true;\n\n\t\tthis.$element.addClass( 'oo-ui-popupTagMultiselectWidget-defaultPopup' );\n\t}\n\n\t// Add overlay, and add that to the autoCloseIgnore\n\tdefaultConfig.popup.$overlay = this.$overlay;\n\tdefaultConfig.popup.$autoCloseIgnore = this.hasInput ?\n\t\tthis.input.$element.add( this.$overlay ) : this.$overlay;\n\n\t// Allow extending any of the above\n\tconfig = $.extend( defaultConfig, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.PopupElement.call( this, config );\n\n\tif ( this.hasInput ) {\n\t\tthis.input.$input.on( 'focus', this.popup.toggle.bind( this.popup, true ) );\n\t}\n\n\t// Configuration options\n\tthis.popupInput = config.popupInput;\n\tif ( this.popupInput ) {\n\t\tthis.popupInput.connect( this, {\n\t\t\tenter: 'onPopupInputEnter'\n\t\t} );\n\t}\n\n\t// Events\n\tthis.on( 'resize', this.popup.updateDimensions.bind( this.popup ) );\n\tthis.popup.connect( this, {\n\t\ttoggle: 'onPopupToggle'\n\t} );\n\tthis.$tabIndexed.on( 'focus', this.onFocus.bind( this ) );\n\n\t// Initialize\n\tthis.$element\n\t\t.append( this.popup.$element )\n\t\t.addClass( 'oo-ui-popupTagMultiselectWidget' );\n\n\t// Deprecation warning\n\tOO.ui.warnDeprecation( 'PopupTagMultiselectWidget: Deprecated widget. Use MenuTagMultiselectWidget instead. See T208821.' );\n};\n\n/* Initialization */\n\nOO.inheritClass( OO.ui.PopupTagMultiselectWidget, OO.ui.TagMultiselectWidget );\nOO.mixinClass( OO.ui.PopupTagMultiselectWidget, OO.ui.mixin.PopupElement );\n\n/* Methods */\n\n/**\n * Focus event handler.\n *\n * @private\n */\nOO.ui.PopupTagMultiselectWidget.prototype.onFocus = function () {\n\tthis.popup.toggle( true );\n};\n\n/**\n * Respond to popup toggle event\n *\n * @param {boolean} isVisible Popup is visible\n */\nOO.ui.PopupTagMultiselectWidget.prototype.onPopupToggle = function ( isVisible ) {\n\tif ( isVisible && this.popupInput ) {\n\t\tthis.popupInput.focus();\n\t}\n};\n\n/**\n * Respond to popup input enter event\n */\nOO.ui.PopupTagMultiselectWidget.prototype.onPopupInputEnter = function () {\n\tif ( this.popupInput ) {\n\t\tthis.addTagByPopupValue( this.popupInput.getValue() );\n\t\tthis.popupInput.setValue( '' );\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.PopupTagMultiselectWidget.prototype.onTagSelect = function ( item ) {\n\tif ( this.popupInput && this.allowEditTags ) {\n\t\tthis.popupInput.setValue( item.getData() );\n\t\tthis.removeItems( [ item ] );\n\n\t\tthis.popup.toggle( true );\n\t\tthis.popupInput.focus();\n\t} else {\n\t\t// Parent\n\t\tOO.ui.PopupTagMultiselectWidget.parent.prototype.onTagSelect.call( this, item );\n\t}\n};\n\n/**\n * Add a tag by the popup value.\n * Whatever is responsible for setting the value in the popup should call\n * this method to add a tag, or use the regular methods like #addTag or\n * #setValue directly.\n *\n * @param {string} data The value of item\n * @param {string} [label] The label of the tag. If not given, the data is used.\n */\nOO.ui.PopupTagMultiselectWidget.prototype.addTagByPopupValue = function ( data, label ) {\n\tthis.addTag( data, label );\n};\n","/**\n * MenuTagMultiselectWidget is a {@link OO.ui.TagMultiselectWidget OO.ui.TagMultiselectWidget}\n * intended to use a menu of selectable options.\n *\n *     @example\n *     // A basic MenuTagMultiselectWidget.\n *     var widget = new OO.ui.MenuTagMultiselectWidget( {\n *         inputPosition: 'outline',\n *         options: [\n *            { data: 'option1', label: 'Option 1', icon: 'tag' },\n *            { data: 'option2', label: 'Option 2' },\n *            { data: 'option3', label: 'Option 3' },\n *         ],\n *         selected: [ 'option1', 'option2' ]\n *     } );\n *     $( document.body ).append( widget.$element );\n *\n * @class\n * @extends OO.ui.TagMultiselectWidget\n *\n * @constructor\n * @param {Object} [config] Configuration object\n * @cfg {boolean} [clearInputOnChoose=true] Clear the text input value when a menu option is chosen\n * @cfg {Object} [menu] Configuration object for the menu widget\n * @cfg {jQuery} [$overlay] An overlay for the menu.\n *  See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.\n * @cfg {Object[]} [options=[]] Array of menu options in the format `{ data: …, label: … }`\n */\nOO.ui.MenuTagMultiselectWidget = function OoUiMenuTagMultiselectWidget( config ) {\n\tvar $autoCloseIgnore = $( [] );\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.MenuTagMultiselectWidget.parent.call( this, config );\n\n\t$autoCloseIgnore = $autoCloseIgnore.add( this.$group );\n\tif ( this.hasInput ) {\n\t\t$autoCloseIgnore = $autoCloseIgnore.add( this.input.$element );\n\t}\n\n\tthis.$overlay = ( config.$overlay === true ?\n\t\tOO.ui.getDefaultOverlay() : config.$overlay ) || this.$element;\n\tthis.clearInputOnChoose = config.clearInputOnChoose === undefined ||\n\t\t!!config.clearInputOnChoose;\n\tthis.menu = this.createMenuWidget( $.extend( {\n\t\twidget: this,\n\t\thideOnChoose: false,\n\t\tinput: this.hasInput ? this.input : null,\n\t\t$input: this.hasInput ? this.input.$input : null,\n\t\tfilterFromInput: !!this.hasInput,\n\t\thighlightOnFilter: !this.allowArbitrary,\n\t\tmultiselect: true,\n\t\t$autoCloseIgnore: $autoCloseIgnore,\n\t\t$floatableContainer: this.hasInput && this.inputPosition === 'outline' ?\n\t\t\tthis.input.$element : this.$element,\n\t\t$overlay: this.$overlay,\n\t\tdisabled: this.isDisabled()\n\t}, config.menu ) );\n\tthis.addOptions( config.options || [] );\n\n\t// Events\n\tthis.menu.connect( this, {\n\t\tchoose: 'onMenuChoose',\n\t\ttoggle: 'onMenuToggle'\n\t} );\n\tif ( this.hasInput ) {\n\t\tthis.input.connect( this, {\n\t\t\tchange: 'onInputChange'\n\t\t} );\n\t}\n\tthis.connect( this, {\n\t\tresize: 'onResize'\n\t} );\n\n\t// Initialization\n\tthis.$overlay.append( this.menu.$element );\n\tthis.$element.addClass( 'oo-ui-menuTagMultiselectWidget' );\n\t// Remove MenuSelectWidget's generic focus owner ARIA attribute\n\t// TODO: Should this widget have a `role` that is compatible with this attribute?\n\tthis.menu.$focusOwner.removeAttr( 'aria-expanded' );\n\t// TagMultiselectWidget already does this, but it doesn't work right because this.menu is\n\t// not yet set up while the parent constructor runs, and #getAllowedValues rejects everything.\n\tif ( config.selected ) {\n\t\tthis.setValue( config.selected );\n\t}\n};\n\n/* Initialization */\n\nOO.inheritClass( OO.ui.MenuTagMultiselectWidget, OO.ui.TagMultiselectWidget );\n\n/* Methods */\n\n/**\n * Respond to resize event\n */\nOO.ui.MenuTagMultiselectWidget.prototype.onResize = function () {\n\t// Reposition the menu\n\tthis.menu.position();\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuTagMultiselectWidget.prototype.onInputFocus = function () {\n\t// Parent method\n\tOO.ui.MenuTagMultiselectWidget.parent.prototype.onInputFocus.call( this );\n\n\tthis.menu.toggle( true );\n};\n\n/**\n * Respond to input change event\n */\nOO.ui.MenuTagMultiselectWidget.prototype.onInputChange = function () {\n\tthis.menu.toggle( true );\n};\n\n/**\n * Respond to menu choose event, which is intentional by the user.\n *\n * @param {OO.ui.OptionWidget} menuItem Selected menu items\n * @param {boolean} selected Item is selected\n */\nOO.ui.MenuTagMultiselectWidget.prototype.onMenuChoose = function ( menuItem, selected ) {\n\tif ( this.hasInput && this.clearInputOnChoose ) {\n\t\tthis.input.setValue( '' );\n\t}\n\n\tif ( selected && !this.findItemFromData( menuItem.getData() ) ) {\n\t\t// The menu item is selected, add it to the tags\n\t\tthis.addTag( menuItem.getData(), menuItem.getLabel() );\n\t} else {\n\t\t// The menu item was unselected, remove the tag\n\t\tthis.removeTagByData( menuItem.getData() );\n\t}\n};\n\n/**\n * Respond to menu toggle event. Reset item highlights on hide.\n *\n * @param {boolean} isVisible The menu is visible\n */\nOO.ui.MenuTagMultiselectWidget.prototype.onMenuToggle = function ( isVisible ) {\n\tif ( !isVisible ) {\n\t\tthis.menu.highlightItem( null );\n\t\tthis.menu.scrollToTop();\n\t}\n\tsetTimeout( function () {\n\t\t// Remove MenuSelectWidget's generic focus owner ARIA attribute\n\t\t// TODO: Should this widget have a `role` that is compatible with this attribute?\n\t\tthis.menu.$focusOwner.removeAttr( 'aria-expanded' );\n\t}.bind( this ) );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuTagMultiselectWidget.prototype.onTagSelect = function ( tagItem ) {\n\tvar menuItem = this.menu.findItemFromData( tagItem.getData() );\n\tif ( !this.allowArbitrary ) {\n\t\t// Override the base behavior from TagMultiselectWidget; the base behavior\n\t\t// in TagMultiselectWidget is to remove the tag to edit it in the input,\n\t\t// but in our case, we want to utilize the menu selection behavior, and\n\t\t// definitely not remove the item.\n\n\t\t// If there is an input that is used for filtering, erase the value so we don't filter\n\t\tif ( this.hasInput && this.menu.filterFromInput ) {\n\t\t\tthis.input.setValue( '' );\n\t\t}\n\n\t\tthis.focus();\n\n\t\t// Highlight the menu item\n\t\tthis.menu.highlightItem( menuItem );\n\t\tthis.menu.scrollItemIntoView( menuItem );\n\n\t} else {\n\t\t// Use the default\n\t\tOO.ui.MenuTagMultiselectWidget.parent.prototype.onTagSelect.call( this, tagItem );\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuTagMultiselectWidget.prototype.removeItems = function ( items ) {\n\tvar widget = this;\n\n\t// Parent\n\tOO.ui.MenuTagMultiselectWidget.parent.prototype.removeItems.call( this, items );\n\n\titems.forEach( function ( tagItem ) {\n\t\tvar menuItem = widget.menu.findItemFromData( tagItem.getData() );\n\t\tif ( menuItem ) {\n\t\t\t// Synchronize the menu selection - unselect the removed tag\n\t\t\twidget.menu.unselectItem( menuItem );\n\t\t}\n\t} );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuTagMultiselectWidget.prototype.setValue = function ( valueObject ) {\n\tvalueObject = Array.isArray( valueObject ) ? valueObject : [ valueObject ];\n\n\t// We override this method from the parent, to make sure we are adding proper\n\t// menu items, and are accounting for cases where we have this widget with\n\t// a menu but also 'allowArbitrary'\n\tif ( !this.menu ) {\n\t\treturn;\n\t}\n\n\tthis.clearItems();\n\tvalueObject.forEach( function ( obj ) {\n\t\tvar data, label, menuItem;\n\n\t\tif ( typeof obj === 'string' ) {\n\t\t\tdata = label = obj;\n\t\t} else {\n\t\t\tdata = obj.data;\n\t\t\tlabel = obj.label;\n\t\t}\n\n\t\t// Check if the item is in the menu\n\t\tmenuItem = this.menu.getItemFromLabel( label ) || this.menu.findItemFromData( data );\n\t\tif ( menuItem ) {\n\t\t\t// Menu item found, add the menu item\n\t\t\tthis.addTag( menuItem.getData(), menuItem.getLabel() );\n\t\t\t// Make sure that item is also selected\n\t\t\tthis.menu.selectItem( menuItem );\n\t\t} else if ( this.allowArbitrary ) {\n\t\t\t// If the item isn't in the menu, only add it if we\n\t\t\t// allow for arbitrary values\n\t\t\tthis.addTag( data, label );\n\t\t}\n\t}.bind( this ) );\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuTagMultiselectWidget.prototype.setDisabled = function ( isDisabled ) {\n\t// Parent method\n\tOO.ui.MenuTagMultiselectWidget.parent.prototype.setDisabled.call( this, isDisabled );\n\n\tif ( this.menu ) {\n\t\t// Protect against calling setDisabled() before the menu was initialized\n\t\tthis.menu.setDisabled( isDisabled );\n\t}\n};\n\n/**\n * Highlight the first selectable item in the menu, if configured.\n *\n * @private\n * @chainable\n */\nOO.ui.MenuTagMultiselectWidget.prototype.initializeMenuSelection = function () {\n\tvar highlightedItem;\n\tthis.menu.highlightItem(\n\t\tthis.allowArbitrary ?\n\t\t\tnull :\n\t\t\tthis.menu.findFirstSelectableItem()\n\t);\n\n\thighlightedItem = this.menu.findHighlightedItem();\n\t// Scroll to the highlighted item, if it exists\n\tif ( highlightedItem ) {\n\t\tthis.menu.scrollItemIntoView( highlightedItem );\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.MenuTagMultiselectWidget.prototype.addTagFromInput = function () {\n\tvar val = this.input.getValue(),\n\t\t// Look for a highlighted item first\n\t\t// Then look for the element that fits the data\n\t\titem = this.menu.findHighlightedItem() || this.menu.findItemFromData( val ),\n\t\tdata = item ? item.getData() : val,\n\t\tisValid = this.isAllowedData( data );\n\n\t// Override the parent method so we add from the menu\n\t// rather than directly from the input\n\n\tif ( !val ) {\n\t\treturn;\n\t}\n\n\tif ( isValid || this.allowDisplayInvalidTags ) {\n\t\tthis.clearInput();\n\t\tif ( item ) {\n\t\t\tthis.addTag( data, item.getLabel() );\n\t\t} else {\n\t\t\tthis.addTag( val );\n\t\t}\n\t}\n};\n\n/**\n * Return the visible items in the menu. This is mainly used for when\n * the menu is filtering results.\n *\n * @return {OO.ui.MenuOptionWidget[]} Visible results\n */\nOO.ui.MenuTagMultiselectWidget.prototype.getMenuVisibleItems = function () {\n\treturn this.menu.getItems().filter( function ( menuItem ) {\n\t\treturn menuItem.isVisible();\n\t} );\n};\n\n/**\n * Create the menu for this widget. This is in a separate method so that\n * child classes can override this without polluting the constructor with\n * unnecessary extra objects that will be overidden.\n *\n * @param {Object} menuConfig Configuration options\n * @return {OO.ui.MenuSelectWidget} Menu widget\n */\nOO.ui.MenuTagMultiselectWidget.prototype.createMenuWidget = function ( menuConfig ) {\n\treturn new OO.ui.MenuSelectWidget( menuConfig );\n};\n\n/**\n * Add options to the menu\n *\n * @param {Object[]} menuOptions Object defining options\n */\nOO.ui.MenuTagMultiselectWidget.prototype.addOptions = function ( menuOptions ) {\n\tvar widget = this,\n\t\titems = menuOptions.map( function ( obj ) {\n\t\t\treturn widget.createMenuOptionWidget( obj.data, obj.label, obj.icon );\n\t\t} );\n\n\tthis.menu.addItems( items );\n};\n\n/**\n * Create a menu option widget.\n *\n * @param {string} data Item data\n * @param {string} [label] Item label\n * @param {string} [icon] Symbolic icon name\n * @return {OO.ui.OptionWidget} Option widget\n */\nOO.ui.MenuTagMultiselectWidget.prototype.createMenuOptionWidget = function ( data, label, icon ) {\n\treturn new OO.ui.MenuOptionWidget( {\n\t\tdata: data,\n\t\tlabel: label || data,\n\t\ticon: icon\n\t} );\n};\n\n/**\n * Get the menu\n *\n * @return {OO.ui.MenuSelectWidget} Menu\n */\nOO.ui.MenuTagMultiselectWidget.prototype.getMenu = function () {\n\treturn this.menu;\n};\n\n/**\n * Get the allowed values list\n *\n * @return {string[]} Allowed data values\n */\nOO.ui.MenuTagMultiselectWidget.prototype.getAllowedValues = function () {\n\tvar menuDatas = [];\n\tif ( this.menu ) {\n\t\t// If the parent constructor is calling us, we're not ready yet, this.menu is not set up.\n\t\tmenuDatas = this.menu.getItems().map( function ( menuItem ) {\n\t\t\treturn menuItem.getData();\n\t\t} );\n\t}\n\treturn this.allowedValues.concat( menuDatas );\n};\n","/**\n * SelectFileWidgets allow for selecting files, using the HTML5 File API. These\n * widgets can be configured with {@link OO.ui.mixin.IconElement icons}, {@link\n * OO.ui.mixin.IndicatorElement indicators} and {@link OO.ui.mixin.TitledElement titles}.\n * Please see the [OOUI documentation on MediaWiki] [1] for more information and examples.\n *\n * Although SelectFileWidget inherits from SelectFileInputWidget, it does not\n * behave as an InputWidget, and can't be used in HTML forms.\n *\n *     @example\n *     // A file select widget.\n *     var selectFile = new OO.ui.SelectFileWidget();\n *     $( document.body ).append( selectFile.$element );\n *\n * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets\n *\n * @class\n * @extends OO.ui.SelectFileInputWidget\n * @mixins OO.ui.mixin.PendingElement\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {string} [notsupported] Text to display when file support is missing in the browser.\n * @cfg {boolean} [droppable=true] Whether to accept files by drag and drop.\n * @cfg {boolean} [buttonOnly=false] Show only the select file button, no info field. Requires\n *  showDropTarget to be false.\n * @cfg {boolean} [showDropTarget=false] Whether to show a drop target. Requires droppable to be\n *  true. Not yet supported in multiple file mode.\n * @cfg {number} [thumbnailSizeLimit=20] File size limit in MiB above which to not try and show a\n *  preview (for performance).\n */\nOO.ui.SelectFileWidget = function OoUiSelectFileWidget( config ) {\n\tvar dragHandler, droppable,\n\t\tisSupported = this.constructor.static.isSupported();\n\n\t// Configuration initialization\n\tconfig = $.extend( {\n\t\tnotsupported: OO.ui.msg( 'ooui-selectfile-not-supported' ),\n\t\tdroppable: true,\n\t\tbuttonOnly: false,\n\t\tshowDropTarget: false,\n\t\tthumbnailSizeLimit: 20\n\t}, config );\n\n\tif ( !isSupported ) {\n\t\tconfig.disabled = true;\n\t}\n\n\t// Parent constructor\n\tOO.ui.SelectFileWidget.parent.call( this, config );\n\n\t// Mixin constructors\n\tOO.ui.mixin.PendingElement.call( this );\n\n\tif ( !isSupported ) {\n\t\tthis.info.setValue( config.notsupported );\n\t}\n\n\t// Properties\n\tdroppable = config.droppable && isSupported;\n\t// TODO: Support drop target when multiple is set\n\tthis.showDropTarget = droppable && config.showDropTarget && !this.multiple;\n\tthis.thumbnailSizeLimit = config.thumbnailSizeLimit;\n\n\t// Events\n\tif ( droppable ) {\n\t\tdragHandler = this.onDragEnterOrOver.bind( this );\n\t\tthis.$element.on( {\n\t\t\tdragenter: dragHandler,\n\t\t\tdragover: dragHandler,\n\t\t\tdragleave: this.onDragLeave.bind( this ),\n\t\t\tdrop: this.onDrop.bind( this )\n\t\t} );\n\t}\n\n\t// Initialization\n\tif ( this.showDropTarget ) {\n\t\tthis.selectButton.setIcon( 'upload' );\n\t\tthis.$thumbnail = $( '<div>' ).addClass( 'oo-ui-selectFileWidget-thumbnail' );\n\t\tthis.setPendingElement( this.$thumbnail );\n\t\tthis.$element\n\t\t\t.addClass( 'oo-ui-selectFileWidget-dropTarget' )\n\t\t\t.on( {\n\t\t\t\tclick: this.onDropTargetClick.bind( this )\n\t\t\t} )\n\t\t\t.append(\n\t\t\t\tthis.$thumbnail,\n\t\t\t\tthis.info.$element,\n\t\t\t\tthis.selectButton.$element,\n\t\t\t\t$( '<span>' )\n\t\t\t\t\t.addClass( 'oo-ui-selectFileWidget-dropLabel' )\n\t\t\t\t\t.text( OO.ui.msg( 'ooui-selectfile-dragdrop-placeholder' ) )\n\t\t\t);\n\t\tthis.fieldLayout.$element.remove();\n\t} else if ( config.buttonOnly ) {\n\t\tthis.$element.append( this.selectButton.$element );\n\t\tthis.fieldLayout.$element.remove();\n\t}\n\n\tthis.$input\n\t\t.on( 'click', function ( e ) {\n\t\t\t// Prevents dropTarget to get clicked which calls\n\t\t\t// a click on this input\n\t\t\te.stopPropagation();\n\t\t} );\n\n\tthis.$element.addClass( 'oo-ui-selectFileWidget' );\n\n\tthis.updateUI();\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.SelectFileWidget, OO.ui.SelectFileInputWidget );\nOO.mixinClass( OO.ui.SelectFileWidget, OO.ui.mixin.PendingElement );\n\n/* Static Properties */\n\n/**\n * Check if this widget is supported\n *\n * @static\n * @return {boolean}\n */\nOO.ui.SelectFileWidget.static.isSupported = function () {\n\tvar $input;\n\tif ( OO.ui.SelectFileWidget.static.isSupportedCache === null ) {\n\t\t$input = $( '<input>' ).attr( 'type', 'file' );\n\t\tOO.ui.SelectFileWidget.static.isSupportedCache = $input[ 0 ].files !== undefined;\n\t}\n\treturn OO.ui.SelectFileWidget.static.isSupportedCache;\n};\n\nOO.ui.SelectFileWidget.static.isSupportedCache = null;\n\n/* Events */\n\n/**\n * @event change\n *\n * A change event is emitted when the on/off state of the toggle changes.\n *\n * @param {File|null} value New value\n */\n\n/* Methods */\n\n/**\n * Get the current value of the field\n *\n * For single file widgets returns a File or null.\n * For multiple file widgets returns a list of Files.\n *\n * @return {File|File[]|null}\n */\nOO.ui.SelectFileWidget.prototype.getValue = function () {\n\treturn this.multiple ? this.currentFiles : this.currentFiles[ 0 ];\n};\n\n/**\n * Set the current value of the field\n *\n * @param {File[]|null} files Files to select\n */\nOO.ui.SelectFileWidget.prototype.setValue = function ( files ) {\n\tif ( files && !this.multiple ) {\n\t\tfiles = files.slice( 0, 1 );\n\t}\n\n\tfunction comparableFile( file ) {\n\t\t// Use extend to convert to plain objects so they can be compared.\n\t\treturn $.extend( {}, file );\n\t}\n\n\tif ( !OO.compare(\n\t\tfiles && files.map( comparableFile ),\n\t\tthis.currentFiles && this.currentFiles.map( comparableFile )\n\t) ) {\n\t\tthis.currentFiles = files || [];\n\t\tthis.emit( 'change', this.currentFiles );\n\t}\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.SelectFileWidget.prototype.getFilename = function () {\n\treturn this.currentFiles.map( function ( file ) {\n\t\treturn file.name;\n\t} ).join( ', ' );\n};\n\n/**\n * Disable InputWidget#onEdit listener, onFileSelected is used instead.\n * @inheritdoc\n */\nOO.ui.SelectFileWidget.prototype.onEdit = function () {};\n\n/**\n * @inheritdoc\n */\nOO.ui.SelectFileWidget.prototype.updateUI = function () {\n\t// Too early, or not supported\n\tif ( !this.selectButton || !this.constructor.static.isSupported() ) {\n\t\treturn;\n\t}\n\n\t// Parent method\n\tOO.ui.SelectFileWidget.super.prototype.updateUI.call( this );\n\n\tif ( this.currentFiles.length ) {\n\t\tthis.$element.removeClass( 'oo-ui-selectFileInputWidget-empty' );\n\n\t\tif ( this.showDropTarget ) {\n\t\t\tthis.pushPending();\n\t\t\tthis.loadAndGetImageUrl( this.currentFiles[ 0 ] ).done( function ( url ) {\n\t\t\t\tthis.$thumbnail.css( 'background-image', 'url( ' + url + ' )' );\n\t\t\t}.bind( this ) ).fail( function () {\n\t\t\t\tthis.$thumbnail.append(\n\t\t\t\t\tnew OO.ui.IconWidget( {\n\t\t\t\t\t\ticon: 'attachment',\n\t\t\t\t\t\tclasses: [ 'oo-ui-selectFileWidget-noThumbnail-icon' ]\n\t\t\t\t\t} ).$element\n\t\t\t\t);\n\t\t\t}.bind( this ) ).always( function () {\n\t\t\t\tthis.popPending();\n\t\t\t}.bind( this ) );\n\t\t\tthis.$element.off( 'click' );\n\t\t}\n\t} else {\n\t\tif ( this.showDropTarget ) {\n\t\t\tthis.$element.off( 'click' );\n\t\t\tthis.$element.on( {\n\t\t\t\tclick: this.onDropTargetClick.bind( this )\n\t\t\t} );\n\t\t\tthis.$thumbnail\n\t\t\t\t.empty()\n\t\t\t\t.css( 'background-image', '' );\n\t\t}\n\t\tthis.$element.addClass( 'oo-ui-selectFileInputWidget-empty' );\n\t}\n};\n\n/**\n * If the selected file is an image, get its URL and load it.\n *\n * @param {File} file File\n * @return {jQuery.Promise} Promise resolves with the image URL after it has loaded\n */\nOO.ui.SelectFileWidget.prototype.loadAndGetImageUrl = function ( file ) {\n\tvar deferred = $.Deferred(),\n\t\treader = new FileReader();\n\n\tif (\n\t\t( OO.getProp( file, 'type' ) || '' ).indexOf( 'image/' ) === 0 &&\n\t\tfile.size < this.thumbnailSizeLimit * 1024 * 1024\n\t) {\n\t\treader.onload = function ( event ) {\n\t\t\tvar img = document.createElement( 'img' );\n\t\t\timg.addEventListener( 'load', function () {\n\t\t\t\tif (\n\t\t\t\t\timg.naturalWidth === 0 ||\n\t\t\t\t\timg.naturalHeight === 0 ||\n\t\t\t\t\timg.complete === false\n\t\t\t\t) {\n\t\t\t\t\tdeferred.reject();\n\t\t\t\t} else {\n\t\t\t\t\tdeferred.resolve( event.target.result );\n\t\t\t\t}\n\t\t\t} );\n\t\t\timg.src = event.target.result;\n\t\t};\n\t\treader.readAsDataURL( file );\n\t} else {\n\t\tdeferred.reject();\n\t}\n\n\treturn deferred.promise();\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.SelectFileWidget.prototype.onFileSelected = function ( e ) {\n\tvar files;\n\n\tif ( this.inputClearing ) {\n\t\treturn;\n\t}\n\n\tfiles = this.filterFiles( e.target.files || [] );\n\n\t// After a file is selected clear the native widget to avoid confusion\n\tthis.inputClearing = true;\n\tthis.$input[ 0 ].value = '';\n\tthis.inputClearing = false;\n\n\tthis.setValue( files );\n};\n\n/**\n * Handle drop target click events.\n *\n * @private\n * @param {jQuery.Event} e Key press event\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.SelectFileWidget.prototype.onDropTargetClick = function () {\n\tif ( !this.isDisabled() && this.$input ) {\n\t\tthis.$input.trigger( 'click' );\n\t\treturn false;\n\t}\n};\n\n/**\n * Handle drag enter and over events\n *\n * @private\n * @param {jQuery.Event} e Drag event\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.SelectFileWidget.prototype.onDragEnterOrOver = function ( e ) {\n\tvar itemsOrFiles,\n\t\thasDroppableFile = false,\n\t\tdt = e.originalEvent.dataTransfer;\n\n\te.preventDefault();\n\te.stopPropagation();\n\n\tif ( this.isDisabled() ) {\n\t\tthis.$element.removeClass( 'oo-ui-selectFileWidget-canDrop' );\n\t\tdt.dropEffect = 'none';\n\t\treturn false;\n\t}\n\n\t// DataTransferItem and File both have a type property, but in Chrome files\n\t// have no information at this point.\n\titemsOrFiles = dt.items || dt.files;\n\tif ( itemsOrFiles && itemsOrFiles.length ) {\n\t\tif ( this.filterFiles( itemsOrFiles ).length ) {\n\t\t\thasDroppableFile = true;\n\t\t}\n\t// dt.types is Array-like, but not an Array\n\t} else if ( Array.prototype.indexOf.call( OO.getProp( dt, 'types' ) || [], 'Files' ) !== -1 ) {\n\t\t// File information is not available at this point for security so just assume\n\t\t// it is acceptable for now.\n\t\t// https://bugzilla.mozilla.org/show_bug.cgi?id=640534\n\t\thasDroppableFile = true;\n\t}\n\n\tthis.$element.toggleClass( 'oo-ui-selectFileWidget-canDrop', hasDroppableFile );\n\tif ( !hasDroppableFile ) {\n\t\tdt.dropEffect = 'none';\n\t}\n\n\treturn false;\n};\n\n/**\n * Handle drag leave events\n *\n * @private\n * @param {jQuery.Event} e Drag event\n */\nOO.ui.SelectFileWidget.prototype.onDragLeave = function () {\n\tthis.$element.removeClass( 'oo-ui-selectFileWidget-canDrop' );\n};\n\n/**\n * Handle drop events\n *\n * @private\n * @param {jQuery.Event} e Drop event\n * @return {undefined|boolean} False to prevent default if event is handled\n */\nOO.ui.SelectFileWidget.prototype.onDrop = function ( e ) {\n\tvar files,\n\t\tdt = e.originalEvent.dataTransfer;\n\n\te.preventDefault();\n\te.stopPropagation();\n\tthis.$element.removeClass( 'oo-ui-selectFileWidget-canDrop' );\n\n\tif ( this.isDisabled() ) {\n\t\treturn false;\n\t}\n\n\tfiles = this.filterFiles( dt.files || [] );\n\tthis.setValue( files );\n\n\treturn false;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.SelectFileWidget.prototype.setDisabled = function ( disabled ) {\n\tdisabled = disabled || !this.constructor.static.isSupported();\n\n\t// Parent method\n\tOO.ui.SelectFileWidget.parent.prototype.setDisabled.call( this, disabled );\n};\n","/**\n * SearchWidgets combine a {@link OO.ui.TextInputWidget text input field},\n * where users can type a search query, and a menu of search results,\n * which is displayed beneath the query field.\n * Unlike {@link OO.ui.mixin.LookupElement lookup menus}, search result menus are always visible\n * to the user. Users can choose an item from the menu or type a query into the text field to\n * search for a matching result item.\n * In general, search widgets are used inside a separate {@link OO.ui.Dialog dialog} window.\n *\n * Each time the query is changed, the search result menu is cleared and repopulated. Please see\n * the [OOUI demos][1] for an example.\n *\n * [1]: https://doc.wikimedia.org/oojs-ui/master/demos/#SearchInputWidget-type-search\n *\n * @class\n * @extends OO.ui.Widget\n *\n * @constructor\n * @param {Object} [config] Configuration options\n * @cfg {string|jQuery} [placeholder] Placeholder text for query input\n * @cfg {string} [value] Initial query value\n */\nOO.ui.SearchWidget = function OoUiSearchWidget( config ) {\n\t// Configuration initialization\n\tconfig = config || {};\n\n\t// Parent constructor\n\tOO.ui.SearchWidget.parent.call( this, config );\n\n\t// Properties\n\tthis.query = new OO.ui.TextInputWidget( {\n\t\ticon: 'search',\n\t\tplaceholder: config.placeholder,\n\t\tvalue: config.value\n\t} );\n\tthis.results = new OO.ui.SelectWidget();\n\tthis.$query = $( '<div>' );\n\tthis.$results = $( '<div>' );\n\n\t// Events\n\tthis.query.connect( this, {\n\t\tchange: 'onQueryChange',\n\t\tenter: 'onQueryEnter'\n\t} );\n\tthis.query.$input.on( 'keydown', this.onQueryKeydown.bind( this ) );\n\n\t// Initialization\n\tthis.$query\n\t\t.addClass( 'oo-ui-searchWidget-query' )\n\t\t.append( this.query.$element );\n\tthis.$results\n\t\t.addClass( 'oo-ui-searchWidget-results' )\n\t\t.append( this.results.$element );\n\tthis.$element\n\t\t.addClass( 'oo-ui-searchWidget' )\n\t\t.append( this.$results, this.$query );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.SearchWidget, OO.ui.Widget );\n\n/* Methods */\n\n/**\n * Handle query key down events.\n *\n * @private\n * @param {jQuery.Event} e Key down event\n */\nOO.ui.SearchWidget.prototype.onQueryKeydown = function ( e ) {\n\tvar highlightedItem, nextItem,\n\t\tdir = e.which === OO.ui.Keys.DOWN ? 1 : ( e.which === OO.ui.Keys.UP ? -1 : 0 );\n\n\tif ( dir ) {\n\t\thighlightedItem = this.results.findHighlightedItem();\n\t\tif ( !highlightedItem ) {\n\t\t\thighlightedItem = this.results.findSelectedItem();\n\t\t}\n\t\tnextItem = this.results.findRelativeSelectableItem( highlightedItem, dir );\n\t\tthis.results.highlightItem( nextItem );\n\t\tnextItem.scrollElementIntoView();\n\t}\n};\n\n/**\n * Handle select widget select events.\n *\n * Clears existing results. Subclasses should repopulate items according to new query.\n *\n * @private\n * @param {string} value New value\n */\nOO.ui.SearchWidget.prototype.onQueryChange = function () {\n\t// Reset\n\tthis.results.clearItems();\n};\n\n/**\n * Handle select widget enter key events.\n *\n * Chooses highlighted item.\n *\n * @private\n * @param {string} value New value\n */\nOO.ui.SearchWidget.prototype.onQueryEnter = function () {\n\tvar highlightedItem = this.results.findHighlightedItem();\n\tif ( highlightedItem ) {\n\t\tthis.results.chooseItem( highlightedItem );\n\t}\n};\n\n/**\n * Get the query input.\n *\n * @return {OO.ui.TextInputWidget} Query input\n */\nOO.ui.SearchWidget.prototype.getQuery = function () {\n\treturn this.query;\n};\n\n/**\n * Get the search results menu.\n *\n * @return {OO.ui.SelectWidget} Menu of search results\n */\nOO.ui.SearchWidget.prototype.getResults = function () {\n\treturn this.results;\n};\n","}( OO ) );\n"]}
\ No newline at end of file
index f120abd..5d0db6a 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOUI v0.31.0
+ * OOUI v0.31.6
  * https://www.mediawiki.org/wiki/OOUI
  *
  * Copyright 2011–2019 OOUI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2019-03-14T00:52:20Z
+ * Date: 2019-05-08T10:08:36Z
  */
 ( function ( OO ) {
 
@@ -68,7 +68,7 @@ OO.ui.WikimediaUITheme.prototype.getElementClasses = function ( element ) {
                ) {
                        // … use white icon / indicator, regardless of other flags
                        variants.invert = true;
-               } else if ( !isFramed && element.isDisabled() ) {
+               } else if ( !isFramed && element.isDisabled() && !element.hasFlag( 'invert' ) ) {
                        // Frameless disabled button, always use black icon / indicator regardless of
                        // other flags.
                        variants.invert = false;
@@ -92,6 +92,7 @@ OO.ui.WikimediaUITheme.prototype.getElementClasses = function ( element ) {
                                );
 
                        variants.destructive = element.hasFlag( 'destructive' );
+                       variants.invert = element.hasFlag( 'invert' );
                        variants.error = element.hasFlag( 'error' );
                        variants.warning = element.hasFlag( 'warning' );
                        variants.success = element.hasFlag( 'success' );
index a6aa959..13f570e 100644 (file)
@@ -1 +1 @@
-{"version":3,"sources":["../src/intro.js.txt","../src/themes/wikimediaui/WikimediaUITheme.js","../src/outro.js.txt"],"names":[],"mappings":"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","file":"oojs-ui-wikimediaui.js","sourcesContent":["( function ( OO ) {\n\n'use strict';\n","/**\n * @class\n * @extends OO.ui.Theme\n *\n * @constructor\n */\nOO.ui.WikimediaUITheme = function OoUiWikimediaUITheme() {\n\t// Parent constructor\n\tOO.ui.WikimediaUITheme.parent.call( this );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.WikimediaUITheme, OO.ui.Theme );\n\n/* Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.WikimediaUITheme.prototype.getElementClasses = function ( element ) {\n\t// Parent method\n\tvar variant, isFramed, isActive, isToolOrGroup,\n\t\tvariants = {\n\t\t\tinvert: false,\n\t\t\tprogressive: false,\n\t\t\tdestructive: false,\n\t\t\terror: false,\n\t\t\twarning: false,\n\t\t\tsuccess: false\n\t\t},\n\t\t// Parent method\n\t\tclasses = OO.ui.WikimediaUITheme.parent.prototype.getElementClasses.call( this, element );\n\n\tif (\n\t\telement instanceof OO.ui.IconWidget &&\n\t\telement.$element.hasClass( 'oo-ui-checkboxInputWidget-checkIcon' )\n\t) {\n\t\t// Icon on CheckboxInputWidget\n\t\tvariants.invert = true;\n\t} else if ( element.supports( [ 'hasFlag' ] ) ) {\n\t\tisFramed = element.supports( [ 'isFramed' ] ) && element.isFramed();\n\t\tisActive = element.supports( [ 'isActive' ] ) && element.isActive();\n\t\tisToolOrGroup =\n\t\t\t// Check if the class exists, as classes that are not in the 'core' module may\n\t\t\t// not be loaded.\n\t\t\t( OO.ui.Tool && element instanceof OO.ui.Tool ) ||\n\t\t\t( OO.ui.ToolGroup && element instanceof OO.ui.ToolGroup );\n\t\tif (\n\t\t\t// Button with a dark background.\n\t\t\tisFramed && ( isActive || element.isDisabled() || element.hasFlag( 'primary' ) ) ||\n\t\t\t// Toolbar with a dark background.\n\t\t\tisToolOrGroup && element.hasFlag( 'primary' )\n\t\t) {\n\t\t\t// … use white icon / indicator, regardless of other flags\n\t\t\tvariants.invert = true;\n\t\t} else if ( !isFramed && element.isDisabled() ) {\n\t\t\t// Frameless disabled button, always use black icon / indicator regardless of\n\t\t\t// other flags.\n\t\t\tvariants.invert = false;\n\t\t} else if ( !element.isDisabled() ) {\n\t\t\t// Any other kind of button, use the right colored icon / indicator if available.\n\t\t\tvariants.progressive = element.hasFlag( 'progressive' ) ||\n\t\t\t\t// Active tools/toolgroups\n\t\t\t\t( isToolOrGroup && isActive ) ||\n\t\t\t\t// Pressed or selected outline/menu option widgets\n\t\t\t\t(\n\t\t\t\t\t(\n\t\t\t\t\t\telement instanceof OO.ui.MenuOptionWidget ||\n\t\t\t\t\t\t// Check if the class exists, as classes that are not in the 'core' module\n\t\t\t\t\t\t// may not be loaded.\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\tOO.ui.OutlineOptionWidget &&\n\t\t\t\t\t\t\telement instanceof OO.ui.OutlineOptionWidget\n\t\t\t\t\t\t)\n\t\t\t\t\t) &&\n\t\t\t\t\t( element.isPressed() || element.isSelected() )\n\t\t\t\t);\n\n\t\t\tvariants.destructive = element.hasFlag( 'destructive' );\n\t\t\tvariants.error = element.hasFlag( 'error' );\n\t\t\tvariants.warning = element.hasFlag( 'warning' );\n\t\t\tvariants.success = element.hasFlag( 'success' );\n\t\t}\n\t}\n\n\tfor ( variant in variants ) {\n\t\tclasses[ variants[ variant ] ? 'on' : 'off' ].push( 'oo-ui-image-' + variant );\n\t}\n\n\treturn classes;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.WikimediaUITheme.prototype.getDialogTransitionDuration = function () {\n\treturn 250;\n};\n\n/* Instantiation */\n\nOO.ui.theme = new OO.ui.WikimediaUITheme();\n","}( OO ) );\n"]}
\ No newline at end of file
+{"version":3,"sources":["../src/intro.js.txt","../src/themes/wikimediaui/WikimediaUITheme.js","../src/outro.js.txt"],"names":[],"mappings":"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","file":"oojs-ui-wikimediaui.js","sourcesContent":["( function ( OO ) {\n\n'use strict';\n","/**\n * @class\n * @extends OO.ui.Theme\n *\n * @constructor\n */\nOO.ui.WikimediaUITheme = function OoUiWikimediaUITheme() {\n\t// Parent constructor\n\tOO.ui.WikimediaUITheme.parent.call( this );\n};\n\n/* Setup */\n\nOO.inheritClass( OO.ui.WikimediaUITheme, OO.ui.Theme );\n\n/* Methods */\n\n/**\n * @inheritdoc\n */\nOO.ui.WikimediaUITheme.prototype.getElementClasses = function ( element ) {\n\t// Parent method\n\tvar variant, isFramed, isActive, isToolOrGroup,\n\t\tvariants = {\n\t\t\tinvert: false,\n\t\t\tprogressive: false,\n\t\t\tdestructive: false,\n\t\t\terror: false,\n\t\t\twarning: false,\n\t\t\tsuccess: false\n\t\t},\n\t\t// Parent method\n\t\tclasses = OO.ui.WikimediaUITheme.parent.prototype.getElementClasses.call( this, element );\n\n\tif (\n\t\telement instanceof OO.ui.IconWidget &&\n\t\telement.$element.hasClass( 'oo-ui-checkboxInputWidget-checkIcon' )\n\t) {\n\t\t// Icon on CheckboxInputWidget\n\t\tvariants.invert = true;\n\t} else if ( element.supports( [ 'hasFlag' ] ) ) {\n\t\tisFramed = element.supports( [ 'isFramed' ] ) && element.isFramed();\n\t\tisActive = element.supports( [ 'isActive' ] ) && element.isActive();\n\t\tisToolOrGroup =\n\t\t\t// Check if the class exists, as classes that are not in the 'core' module may\n\t\t\t// not be loaded.\n\t\t\t( OO.ui.Tool && element instanceof OO.ui.Tool ) ||\n\t\t\t( OO.ui.ToolGroup && element instanceof OO.ui.ToolGroup );\n\t\tif (\n\t\t\t// Button with a dark background.\n\t\t\tisFramed && ( isActive || element.isDisabled() || element.hasFlag( 'primary' ) ) ||\n\t\t\t// Toolbar with a dark background.\n\t\t\tisToolOrGroup && element.hasFlag( 'primary' )\n\t\t) {\n\t\t\t// … use white icon / indicator, regardless of other flags\n\t\t\tvariants.invert = true;\n\t\t} else if ( !isFramed && element.isDisabled() && !element.hasFlag( 'invert' ) ) {\n\t\t\t// Frameless disabled button, always use black icon / indicator regardless of\n\t\t\t// other flags.\n\t\t\tvariants.invert = false;\n\t\t} else if ( !element.isDisabled() ) {\n\t\t\t// Any other kind of button, use the right colored icon / indicator if available.\n\t\t\tvariants.progressive = element.hasFlag( 'progressive' ) ||\n\t\t\t\t// Active tools/toolgroups\n\t\t\t\t( isToolOrGroup && isActive ) ||\n\t\t\t\t// Pressed or selected outline/menu option widgets\n\t\t\t\t(\n\t\t\t\t\t(\n\t\t\t\t\t\telement instanceof OO.ui.MenuOptionWidget ||\n\t\t\t\t\t\t// Check if the class exists, as classes that are not in the 'core' module\n\t\t\t\t\t\t// may not be loaded.\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\tOO.ui.OutlineOptionWidget &&\n\t\t\t\t\t\t\telement instanceof OO.ui.OutlineOptionWidget\n\t\t\t\t\t\t)\n\t\t\t\t\t) &&\n\t\t\t\t\t( element.isPressed() || element.isSelected() )\n\t\t\t\t);\n\n\t\t\tvariants.destructive = element.hasFlag( 'destructive' );\n\t\t\tvariants.invert = element.hasFlag( 'invert' );\n\t\t\tvariants.error = element.hasFlag( 'error' );\n\t\t\tvariants.warning = element.hasFlag( 'warning' );\n\t\t\tvariants.success = element.hasFlag( 'success' );\n\t\t}\n\t}\n\n\tfor ( variant in variants ) {\n\t\tclasses[ variants[ variant ] ? 'on' : 'off' ].push( 'oo-ui-image-' + variant );\n\t}\n\n\treturn classes;\n};\n\n/**\n * @inheritdoc\n */\nOO.ui.WikimediaUITheme.prototype.getDialogTransitionDuration = function () {\n\treturn 250;\n};\n\n/* Instantiation */\n\nOO.ui.theme = new OO.ui.WikimediaUITheme();\n","}( OO ) );\n"]}
\ No newline at end of file
index 1b3557f..6798d1d 100644 (file)
@@ -1,16 +1,13 @@
 /*!
- * OOUI v0.31.0
+ * OOUI v0.31.6
  * https://www.mediawiki.org/wiki/OOUI
  *
  * Copyright 2011–2019 OOUI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2019-03-14T00:52:27Z
+ * Date: 2019-05-08T10:08:44Z
  */
-.oo-ui-actionWidget.oo-ui-pendingElement-pending {
-  background-image: /* @embed */ url(themes/wikimediaui/images/textures/pending.gif);
-}
 
 .oo-ui-window {
   background-color: transparent;
index 57c0da9..ec2bd97 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOUI v0.31.0
+ * OOUI v0.31.6
  * https://www.mediawiki.org/wiki/OOUI
  *
  * Copyright 2011–2019 OOUI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2019-03-14T00:52:27Z
+ * Date: 2019-05-08T10:08:44Z
  */
 
 .oo-ui-window {
index 25c99a4..7693135 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOUI v0.31.0
+ * OOUI v0.31.6
  * https://www.mediawiki.org/wiki/OOUI
  *
  * Copyright 2011–2019 OOUI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2019-03-14T00:52:20Z
+ * Date: 2019-05-08T10:08:36Z
  */
 ( function ( OO ) {
 
index 74cb6f9..8e440cb 100644 (file)
@@ -8,6 +8,9 @@
                "bell": {
                        "file": "../wikimediaui/images/icons/bell.svg"
                },
+               "error": {
+                       "file": "../wikimediaui/images/icons/error.svg"
+               },
                "message": {
                        "file": "../wikimediaui/images/icons/message.svg"
                },
index b1608c3..64d6bac 100644 (file)
                },
                "helpNotice": {
                        "file": {
-                               "ltr": "../wikimediaui/images/icons/helpOutlined-ltr.svg",
-                               "rtl": "../wikimediaui/images/icons/helpOutlined-rtl.svg",
+                               "ltr": "../wikimediaui/images/icons/helpNotice-ltr.svg",
+                               "rtl": "../wikimediaui/images/icons/helpNotice-rtl.svg",
                                "lang": {
-                                       "he,yi": "../wikimediaui/images/icons/helpOutlined-ltr.svg"
+                                       "he,yi": "../wikimediaui/images/icons/helpNotice-ltr.svg"
                                }
                        }
                },
index 7cb8856..2280cf0 100644 (file)
@@ -9,7 +9,7 @@
                        "file": "../wikimediaui/images/icons/logo-Wikidata.svg"
                },
                "logoWikimedia": {
-                       "file": "../wikimediaui/images/icons/logo-Wikidata.svg"
+                       "file": "../wikimediaui/images/icons/logo-Wikimedia.svg"
                },
                "logoWikimediaCommons": {
                        "file": "../wikimediaui/images/icons/logo-Wikimedia-Commons.svg"
index 82dedb6..b4999e2 100644 (file)
@@ -2,7 +2,13 @@
        "prefix": "oo-ui-texture",
        "intro": "@import '../../../../src/styles/common';",
        "images": {
-               "pending": { "file": "../wikimediaui/images/textures/pending.gif" },
-               "transparency": { "file": "../wikimediaui/images/textures/transparency.svg" }
+               "pending": {
+                       "file": "../wikimediaui/images/textures/pending.gif",
+                       "deprecated": "Deprecated since v0.31.1."
+               },
+               "transparency": {
+                       "file": "../wikimediaui/images/textures/transparency.svg",
+                       "deprecated": "Deprecated since v0.31.1."
+               }
        }
 }
index 2e9cb9c..2b315c8 100644 (file)
                "alert": {
                        "file": "images/icons/alert.svg",
                        "variants": [
-                               "error",
                                "warning"
                        ]
                },
                "bell": {
                        "file": "images/icons/bell.svg"
                },
+               "error": {
+                       "file": "images/icons/error.svg",
+                       "variants": [
+                               "error"
+                       ]
+               },
                "message": {
                        "file": "images/icons/message.svg"
                },
index b7570fe..ccffb60 100644 (file)
                "articleCheck": {
                        "file": "images/icons/articleCheck.svg"
                },
+               "articleDisambiguation": {
+                       "file": {
+                               "ltr": "images/icons/articleDisambiguation-ltr.svg",
+                               "rtl": "images/icons/articleDisambiguation-rtl.svg"
+                       }
+               },
+               "articleNotFound": {
+                       "file": {
+                               "ltr": "images/icons/articleNotFound-ltr.svg",
+                               "rtl": "images/icons/articleNotFound-rtl.svg",
+                               "lang": {
+                                       "he,yi": "images/icons/articleNotFound-ltr.svg"
+                               }
+                       }
+               },
                "articleSearch": {
                        "file": "images/icons/articleSearch.svg"
                },
index 7ff6399..b460429 100644 (file)
                },
                "helpNotice": {
                        "file": {
-                               "ltr": "images/icons/helpOutlined-ltr.svg",
-                               "rtl": "images/icons/helpOutlined-rtl.svg",
+                               "ltr": "images/icons/helpNotice-ltr.svg",
+                               "rtl": "images/icons/helpNotice-rtl.svg",
                                "lang": {
-                                       "he,yi": "images/icons/helpOutlined-ltr.svg"
+                                       "he,yi": "images/icons/helpNotice-ltr.svg"
                                }
                        }
                },
index 56526d2..5794445 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add</title><path fill="#fff" d="M16 9h-5V4H9v5H4v2h5v5h2v-5h5V9z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add</title><path fill="#fff" d="M11 9V4H9v5H4v2h5v5h2v-5h5V9z"/></svg>
\ No newline at end of file
index 4c84858..5e9adad 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add</title><path fill="#36c" d="M16 9h-5V4H9v5H4v2h5v5h2v-5h5V9z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add</title><path fill="#36c" d="M11 9V4H9v5H4v2h5v5h2v-5h5V9z"/></svg>
\ No newline at end of file
index 9ba48c9..c3b2f55 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add</title><path d="M16 9h-5V4H9v5H4v2h5v5h2v-5h5V9z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add</title><path d="M11 9V4H9v5H4v2h5v5h2v-5h5V9z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/alert-error.png b/resources/lib/ooui/themes/wikimediaui/images/icons/alert-error.png
deleted file mode 100644 (file)
index 075500e..0000000
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/alert-error.png and /dev/null differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/alert-error.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/alert-error.svg
deleted file mode 100644 (file)
index 36f9125..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>alert</title><path fill="#d33" d="M19.64 16.36L11.53 2.3A1.85 1.85 0 0 0 10 1.21 1.85 1.85 0 0 0 8.48 2.3L.36 16.36C-.48 17.81.21 19 1.88 19h16.24c1.67 0 2.36-1.19 1.52-2.64zM11 16H9v-2h2zm0-4H9V6h2z"/></svg>
\ No newline at end of file
index bc4b616..f1f94f9 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>alert</title><path fill="#fff" d="M19.64 16.36L11.53 2.3A1.85 1.85 0 0 0 10 1.21 1.85 1.85 0 0 0 8.48 2.3L.36 16.36C-.48 17.81.21 19 1.88 19h16.24c1.67 0 2.36-1.19 1.52-2.64zM11 16H9v-2h2zm0-4H9V6h2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>alert</title><path fill="#fff" d="M11.53 2.3A1.85 1.85 0 0 0 10 1.21 1.85 1.85 0 0 0 8.48 2.3L.36 16.36C-.48 17.81.21 19 1.88 19h16.24c1.67 0 2.36-1.19 1.52-2.64zM11 16H9v-2h2zm0-4H9V6h2z"/></svg>
\ No newline at end of file
index 4407349..7451848 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>alert</title><path fill="#36c" d="M19.64 16.36L11.53 2.3A1.85 1.85 0 0 0 10 1.21 1.85 1.85 0 0 0 8.48 2.3L.36 16.36C-.48 17.81.21 19 1.88 19h16.24c1.67 0 2.36-1.19 1.52-2.64zM11 16H9v-2h2zm0-4H9V6h2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>alert</title><path fill="#36c" d="M11.53 2.3A1.85 1.85 0 0 0 10 1.21 1.85 1.85 0 0 0 8.48 2.3L.36 16.36C-.48 17.81.21 19 1.88 19h16.24c1.67 0 2.36-1.19 1.52-2.64zM11 16H9v-2h2zm0-4H9V6h2z"/></svg>
\ No newline at end of file
index 9e8b4db..b49c48e 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>alert</title><path fill="#fc3" d="M19.64 16.36L11.53 2.3A1.85 1.85 0 0 0 10 1.21 1.85 1.85 0 0 0 8.48 2.3L.36 16.36C-.48 17.81.21 19 1.88 19h16.24c1.67 0 2.36-1.19 1.52-2.64zM11 16H9v-2h2zm0-4H9V6h2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>alert</title><path fill="#fc3" d="M11.53 2.3A1.85 1.85 0 0 0 10 1.21 1.85 1.85 0 0 0 8.48 2.3L.36 16.36C-.48 17.81.21 19 1.88 19h16.24c1.67 0 2.36-1.19 1.52-2.64zM11 16H9v-2h2zm0-4H9V6h2z"/></svg>
\ No newline at end of file
index d5db1ed..b21dbc0 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>alert</title><path d="M19.64 16.36L11.53 2.3A1.85 1.85 0 0 0 10 1.21 1.85 1.85 0 0 0 8.48 2.3L.36 16.36C-.48 17.81.21 19 1.88 19h16.24c1.67 0 2.36-1.19 1.52-2.64zM11 16H9v-2h2zm0-4H9V6h2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>alert</title><path d="M11.53 2.3A1.85 1.85 0 0 0 10 1.21 1.85 1.85 0 0 0 8.48 2.3L.36 16.36C-.48 17.81.21 19 1.88 19h16.24c1.67 0 2.36-1.19 1.52-2.64zM11 16H9v-2h2zm0-4H9V6h2z"/></svg>
\ No newline at end of file
index c58e800..e76b455 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>next</title><path fill="#fff" d="M10 2L8.59 3.42 14.17 9H2v2h12.17l-5.58 5.59L10 18l8-8-8-8z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>next</title><path fill="#fff" d="M8.59 3.42L14.17 9H2v2h12.17l-5.58 5.59L10 18l8-8-8-8z"/></svg>
\ No newline at end of file
index a0c8843..db462b8 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>next</title><path fill="#36c" d="M10 2L8.59 3.42 14.17 9H2v2h12.17l-5.58 5.59L10 18l8-8-8-8z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>next</title><path fill="#36c" d="M8.59 3.42L14.17 9H2v2h12.17l-5.58 5.59L10 18l8-8-8-8z"/></svg>
\ No newline at end of file
index a9f9745..8eb80f1 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>next</title><path d="M10 2L8.59 3.42 14.17 9H2v2h12.17l-5.58 5.59L10 18l8-8-8-8z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>next</title><path d="M8.59 3.42L14.17 9H2v2h12.17l-5.58 5.59L10 18l8-8-8-8z"/></svg>
\ No newline at end of file
index 0c5952c..746a91d 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>previous</title><path fill="#fff" d="M18 9H5.83l5.58-5.58L10 2l-8 8 8 8 1.41-1.41L5.83 11H18V9z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>previous</title><path fill="#fff" d="M5.83 9l5.58-5.58L10 2l-8 8 8 8 1.41-1.41L5.83 11H18V9z"/></svg>
\ No newline at end of file
index efa9e50..91e9b68 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>previous</title><path fill="#36c" d="M18 9H5.83l5.58-5.58L10 2l-8 8 8 8 1.41-1.41L5.83 11H18V9z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>previous</title><path fill="#36c" d="M5.83 9l5.58-5.58L10 2l-8 8 8 8 1.41-1.41L5.83 11H18V9z"/></svg>
\ No newline at end of file
index d95b511..5f0c082 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>previous</title><path d="M18 9H5.83l5.58-5.58L10 2l-8 8 8 8 1.41-1.41L5.83 11H18V9z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>previous</title><path d="M5.83 9l5.58-5.58L10 2l-8 8 8 8 1.41-1.41L5.83 11H18V9z"/></svg>
\ No newline at end of file
index 36ca5e3..290967a 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article</title><path fill="#fff" d="M15 1H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zM5 4h5v1H5zm0 2h5v1H5zm0 2h5v1H5zm10 7H5v-1h10zm0-2H5v-1h10zm0-2H5v-1h10zm0-2h-4V4h4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article</title><path fill="#fff" d="M5 1a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm0 3h5v1H5zm0 2h5v1H5zm0 2h5v1H5zm10 7H5v-1h10zm0-2H5v-1h10zm0-2H5v-1h10zm0-2h-4V4h4z"/></svg>
\ No newline at end of file
index 76c8d03..1a3049c 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article</title><path fill="#36c" d="M15 1H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zM5 4h5v1H5zm0 2h5v1H5zm0 2h5v1H5zm10 7H5v-1h10zm0-2H5v-1h10zm0-2H5v-1h10zm0-2h-4V4h4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article</title><path fill="#36c" d="M5 1a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm0 3h5v1H5zm0 2h5v1H5zm0 2h5v1H5zm10 7H5v-1h10zm0-2H5v-1h10zm0-2H5v-1h10zm0-2h-4V4h4z"/></svg>
\ No newline at end of file
index e370aee..a983fe0 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article</title><path d="M15 1H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zM5 4h5v1H5zm0 2h5v1H5zm0 2h5v1H5zm10 7H5v-1h10zm0-2H5v-1h10zm0-2H5v-1h10zm0-2h-4V4h4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article</title><path d="M5 1a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm0 3h5v1H5zm0 2h5v1H5zm0 2h5v1H5zm10 7H5v-1h10zm0-2H5v-1h10zm0-2H5v-1h10zm0-2h-4V4h4z"/></svg>
\ No newline at end of file
index d565d97..c62ac1c 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article</title><path fill="#fff" d="M3 3v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2zm12 2h-5V4h5zm0 2h-5V6h5zm0 2h-5V8h5zM5 14h10v1H5zm0-2h10v1H5zm0-2h10v1H5zm0-6h4v5H5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article</title><path fill="#fff" d="M3 17a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2zM15 5h-5V4h5zm0 2h-5V6h5zm0 2h-5V8h5zM5 14h10v1H5zm0-2h10v1H5zm0-2h10v1H5zm0-6h4v5H5z"/></svg>
\ No newline at end of file
index 0062f6b..f312c60 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article</title><path fill="#36c" d="M3 3v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2zm12 2h-5V4h5zm0 2h-5V6h5zm0 2h-5V8h5zM5 14h10v1H5zm0-2h10v1H5zm0-2h10v1H5zm0-6h4v5H5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article</title><path fill="#36c" d="M3 17a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2zM15 5h-5V4h5zm0 2h-5V6h5zm0 2h-5V8h5zM5 14h10v1H5zm0-2h10v1H5zm0-2h10v1H5zm0-6h4v5H5z"/></svg>
\ No newline at end of file
index 1ef6e18..6b97553 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article</title><path d="M3 3v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2zm12 2h-5V4h5zm0 2h-5V6h5zm0 2h-5V8h5zM5 14h10v1H5zm0-2h10v1H5zm0-2h10v1H5zm0-6h4v5H5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article</title><path d="M3 17a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2zM15 5h-5V4h5zm0 2h-5V6h5zm0 2h-5V8h5zM5 14h10v1H5zm0-2h10v1H5zm0-2h10v1H5zm0-6h4v5H5z"/></svg>
\ No newline at end of file
index 086fb1d..b83ed2b 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add article</title><path fill="#fff" d="M15 1H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm0 10h-4v4H9v-4H5V9h4V5h2v4h4v2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add article</title><path fill="#fff" d="M5 1c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm10 10h-4v4H9v-4H5V9h4V5h2v4h4z"/></svg>
\ No newline at end of file
index e4e8923..c25c622 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add article</title><path fill="#36c" d="M15 1H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm0 10h-4v4H9v-4H5V9h4V5h2v4h4v2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add article</title><path fill="#36c" d="M5 1c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm10 10h-4v4H9v-4H5V9h4V5h2v4h4z"/></svg>
\ No newline at end of file
index 191a2ff..a9ad603 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add article</title><path d="M15 1H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm0 10h-4v4H9v-4H5V9h4V5h2v4h4v2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add article</title><path d="M5 1c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm10 10h-4v4H9v-4H5V9h4V5h2v4h4z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-ltr-invert.png b/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-ltr-invert.png
new file mode 100644 (file)
index 0000000..0d01921
Binary files /dev/null and b/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-ltr-invert.png differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-ltr-invert.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-ltr-invert.svg
new file mode 100644 (file)
index 0000000..935aac8
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article disambiguation</title><path fill="#fff" d="M5 1c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2H5zm6.002 3h4v4l-1.281-1.281L10.44 10l3.28 3.281L15.003 12v4h-4l1.313-1.313L8.595 11H5.003V9h3.594l3.687-3.719L11.003 4z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-ltr-progressive.png b/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-ltr-progressive.png
new file mode 100644 (file)
index 0000000..91994d5
Binary files /dev/null and b/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-ltr-progressive.png differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-ltr-progressive.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-ltr-progressive.svg
new file mode 100644 (file)
index 0000000..8f1a041
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article disambiguation</title><path fill="#36c" d="M5 1c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2H5zm6.002 3h4v4l-1.281-1.281L10.44 10l3.28 3.281L15.003 12v4h-4l1.313-1.313L8.595 11H5.003V9h3.594l3.687-3.719L11.003 4z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-ltr.png b/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-ltr.png
new file mode 100644 (file)
index 0000000..3165d14
Binary files /dev/null and b/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-ltr.png differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-ltr.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-ltr.svg
new file mode 100644 (file)
index 0000000..ac65ae8
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article disambiguation</title><path d="M5 1c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2H5zm6.002 3h4v4l-1.281-1.281L10.44 10l3.28 3.281L15.003 12v4h-4l1.313-1.313L8.595 11H5.003V9h3.594l3.687-3.719L11.003 4z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-rtl-invert.png b/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-rtl-invert.png
new file mode 100644 (file)
index 0000000..f98f983
Binary files /dev/null and b/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-rtl-invert.png differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-rtl-invert.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-rtl-invert.svg
new file mode 100644 (file)
index 0000000..e7b521a
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article disambiguation</title><path fill="#fff" d="M15 1c1.1 0 2 .9 2 2v14c0 1.1-.9 2-2 2H5c-1.1 0-2-.9-2-2V3c0-1.1.9-2 2-2zM8.998 4h-4v4l1.281-1.281L9.56 10l-3.28 3.281L4.997 12v4h4l-1.312-1.313L11.404 11h3.594V9h-3.594L7.717 5.281z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-rtl-progressive.png b/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-rtl-progressive.png
new file mode 100644 (file)
index 0000000..a399c12
Binary files /dev/null and b/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-rtl-progressive.png differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-rtl-progressive.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-rtl-progressive.svg
new file mode 100644 (file)
index 0000000..33ed25b
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article disambiguation</title><path fill="#36c" d="M15 1c1.1 0 2 .9 2 2v14c0 1.1-.9 2-2 2H5c-1.1 0-2-.9-2-2V3c0-1.1.9-2 2-2zM8.998 4h-4v4l1.281-1.281L9.56 10l-3.28 3.281L4.997 12v4h4l-1.312-1.313L11.404 11h3.594V9h-3.594L7.717 5.281z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-rtl.png b/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-rtl.png
new file mode 100644 (file)
index 0000000..44241fb
Binary files /dev/null and b/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-rtl.png differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-rtl.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/articleDisambiguation-rtl.svg
new file mode 100644 (file)
index 0000000..1f4ff98
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article disambiguation</title><path d="M15 1c1.1 0 2 .9 2 2v14c0 1.1-.9 2-2 2H5c-1.1 0-2-.9-2-2V3c0-1.1.9-2 2-2zM8.998 4h-4v4l1.281-1.281L9.56 10l-3.28 3.281L4.997 12v4h4l-1.312-1.313L11.404 11h3.594V9h-3.594L7.717 5.281z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-ltr-invert.png b/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-ltr-invert.png
new file mode 100644 (file)
index 0000000..07528c9
Binary files /dev/null and b/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-ltr-invert.png differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-ltr-invert.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-ltr-invert.svg
new file mode 100644 (file)
index 0000000..6ae5070
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>article not found</title><path d="M5 1c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2H5zm4.98 4.201c.385 0 .744.06 1.079.174.33.114.623.282.869.5s.443.487.586.814c.143.323.215.692.215 1.1a3.19 3.19 0 0 1-.106.783h.004a2.144 2.144 0 0 1-.25.563c-.104.16-.226.3-.361.424l-.403.363-.437.396c-.134.127-.25.273-.354.428a1.84 1.84 0 0 0-.232.555c-.054.215-.08.475-.08.785H9.15c0-.378.017-.696.057-.955.036-.26.099-.49.184-.69a2.21 2.21 0 0 1 .308-.52c.12-.15.268-.294.434-.439l.385-.332a2.24 2.24 0 0 0 .328-.34 1.53 1.53 0 0 0 .226-.42 1.67 1.67 0 0 0 .08-.55c0-.256-.044-.48-.133-.66a1.397 1.397 0 0 0-.322-.442 1.35 1.35 0 0 0-.402-.246 1.17 1.17 0 0 0-.375-.078c-.52 0-.905.175-1.15.522-.248.345-.374.808-.374 1.388H6.963c0-.468.066-.894.205-1.28a2.641 2.641 0 0 1 1.56-1.62c.37-.15.79-.223 1.252-.223zm-1.023 7.772h1.688v1.6H8.957v-1.6z"/></g></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-ltr-progressive.png b/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-ltr-progressive.png
new file mode 100644 (file)
index 0000000..d2d2460
Binary files /dev/null and b/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-ltr-progressive.png differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-ltr-progressive.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-ltr-progressive.svg
new file mode 100644 (file)
index 0000000..73e6a1a
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>article not found</title><path d="M5 1c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2H5zm4.98 4.201c.385 0 .744.06 1.079.174.33.114.623.282.869.5s.443.487.586.814c.143.323.215.692.215 1.1a3.19 3.19 0 0 1-.106.783h.004a2.144 2.144 0 0 1-.25.563c-.104.16-.226.3-.361.424l-.403.363-.437.396c-.134.127-.25.273-.354.428a1.84 1.84 0 0 0-.232.555c-.054.215-.08.475-.08.785H9.15c0-.378.017-.696.057-.955.036-.26.099-.49.184-.69a2.21 2.21 0 0 1 .308-.52c.12-.15.268-.294.434-.439l.385-.332a2.24 2.24 0 0 0 .328-.34 1.53 1.53 0 0 0 .226-.42 1.67 1.67 0 0 0 .08-.55c0-.256-.044-.48-.133-.66a1.397 1.397 0 0 0-.322-.442 1.35 1.35 0 0 0-.402-.246 1.17 1.17 0 0 0-.375-.078c-.52 0-.905.175-1.15.522-.248.345-.374.808-.374 1.388H6.963c0-.468.066-.894.205-1.28a2.641 2.641 0 0 1 1.56-1.62c.37-.15.79-.223 1.252-.223zm-1.023 7.772h1.688v1.6H8.957v-1.6z"/></g></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-ltr.png b/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-ltr.png
new file mode 100644 (file)
index 0000000..860c443
Binary files /dev/null and b/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-ltr.png differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-ltr.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-ltr.svg
new file mode 100644 (file)
index 0000000..29f1127
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article not found</title><path d="M5 1c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2H5zm4.98 4.201c.385 0 .744.06 1.079.174.33.114.623.282.869.5s.443.487.586.814c.143.323.215.692.215 1.1a3.19 3.19 0 0 1-.106.783h.004a2.144 2.144 0 0 1-.25.563c-.104.16-.226.3-.361.424l-.403.363-.437.396c-.134.127-.25.273-.354.428a1.84 1.84 0 0 0-.232.555c-.054.215-.08.475-.08.785H9.15c0-.378.017-.696.057-.955.036-.26.099-.49.184-.69a2.21 2.21 0 0 1 .308-.52c.12-.15.268-.294.434-.439l.385-.332a2.24 2.24 0 0 0 .328-.34 1.53 1.53 0 0 0 .226-.42 1.67 1.67 0 0 0 .08-.55c0-.256-.044-.48-.133-.66a1.397 1.397 0 0 0-.322-.442 1.35 1.35 0 0 0-.402-.246 1.17 1.17 0 0 0-.375-.078c-.52 0-.905.175-1.15.522-.248.345-.374.808-.374 1.388H6.963c0-.468.066-.894.205-1.28a2.641 2.641 0 0 1 1.56-1.62c.37-.15.79-.223 1.252-.223zm-1.023 7.772h1.688v1.6H8.957v-1.6z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-rtl-invert.png b/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-rtl-invert.png
new file mode 100644 (file)
index 0000000..05691e5
Binary files /dev/null and b/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-rtl-invert.png differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-rtl-invert.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-rtl-invert.svg
new file mode 100644 (file)
index 0000000..e1d4e0c
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article not found</title><path fill="#fff" d="M15 1c1.1 0 2 .9 2 2v14c0 1.1-.9 2-2 2H5c-1.1 0-2-.9-2-2V3c0-1.1.9-2 2-2zm-4.98 4.201c-.385 0-.744.06-1.079.174-.33.114-.623.282-.869.5s-.443.487-.586.814a2.697 2.697 0 0 0-.215 1.1c.01.306.042.564.106.783h-.004a2.144 2.144 0 0 0 .25.563c.104.16.226.3.361.424l.403.363.437.396c.134.127.25.273.354.428.103.16.18.346.232.555.054.215.08.475.08.785h1.36a6.45 6.45 0 0 0-.057-.955 2.708 2.708 0 0 0-.184-.69 2.21 2.21 0 0 0-.308-.52 3.506 3.506 0 0 0-.434-.439l-.385-.332a2.24 2.24 0 0 1-.328-.34 1.53 1.53 0 0 1-.226-.42 1.67 1.67 0 0 1-.08-.55c0-.256.044-.48.133-.66a1.397 1.397 0 0 1 .322-.442 1.35 1.35 0 0 1 .402-.246 1.17 1.17 0 0 1 .375-.078c.52 0 .906.175 1.15.522.248.345.374.808.374 1.388h1.433c0-.468-.066-.894-.205-1.28a2.641 2.641 0 0 0-1.56-1.62c-.37-.15-.79-.223-1.252-.223zm1.023 7.772H9.355v1.6h1.688z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-rtl-progressive.png b/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-rtl-progressive.png
new file mode 100644 (file)
index 0000000..9ab4cf4
Binary files /dev/null and b/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-rtl-progressive.png differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-rtl-progressive.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-rtl-progressive.svg
new file mode 100644 (file)
index 0000000..966d365
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article not found</title><path fill="#36c" d="M15 1c1.1 0 2 .9 2 2v14c0 1.1-.9 2-2 2H5c-1.1 0-2-.9-2-2V3c0-1.1.9-2 2-2zm-4.98 4.201c-.385 0-.744.06-1.079.174-.33.114-.623.282-.869.5s-.443.487-.586.814a2.697 2.697 0 0 0-.215 1.1c.01.306.042.564.106.783h-.004a2.144 2.144 0 0 0 .25.563c.104.16.226.3.361.424l.403.363.437.396c.134.127.25.273.354.428.103.16.18.346.232.555.054.215.08.475.08.785h1.36a6.45 6.45 0 0 0-.057-.955 2.708 2.708 0 0 0-.184-.69 2.21 2.21 0 0 0-.308-.52 3.506 3.506 0 0 0-.434-.439l-.385-.332a2.24 2.24 0 0 1-.328-.34 1.53 1.53 0 0 1-.226-.42 1.67 1.67 0 0 1-.08-.55c0-.256.044-.48.133-.66a1.397 1.397 0 0 1 .322-.442 1.35 1.35 0 0 1 .402-.246 1.17 1.17 0 0 1 .375-.078c.52 0 .906.175 1.15.522.248.345.374.808.374 1.388h1.433c0-.468-.066-.894-.205-1.28a2.641 2.641 0 0 0-1.56-1.62c-.37-.15-.79-.223-1.252-.223zm1.023 7.772H9.355v1.6h1.688z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-rtl.png b/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-rtl.png
new file mode 100644 (file)
index 0000000..d52a078
Binary files /dev/null and b/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-rtl.png differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-rtl.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/articleNotFound-rtl.svg
new file mode 100644 (file)
index 0000000..45dcd19
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article not found</title><path d="M15 1c1.1 0 2 .9 2 2v14c0 1.1-.9 2-2 2H5c-1.1 0-2-.9-2-2V3c0-1.1.9-2 2-2zm-4.98 4.201c-.385 0-.744.06-1.079.174-.33.114-.623.282-.869.5s-.443.487-.586.814a2.697 2.697 0 0 0-.215 1.1c.01.306.042.564.106.783h-.004a2.144 2.144 0 0 0 .25.563c.104.16.226.3.361.424l.403.363.437.396c.134.127.25.273.354.428.103.16.18.346.232.555.054.215.08.475.08.785h1.36a6.45 6.45 0 0 0-.057-.955 2.708 2.708 0 0 0-.184-.69 2.21 2.21 0 0 0-.308-.52 3.506 3.506 0 0 0-.434-.439l-.385-.332a2.24 2.24 0 0 1-.328-.34 1.53 1.53 0 0 1-.226-.42 1.67 1.67 0 0 1-.08-.55c0-.256.044-.48.133-.66a1.397 1.397 0 0 1 .322-.442 1.35 1.35 0 0 1 .402-.246 1.17 1.17 0 0 1 .375-.078c.52 0 .906.175 1.15.522.248.345.374.808.374 1.388h1.433c0-.468-.066-.894-.205-1.28a2.641 2.641 0 0 0-1.56-1.62c-.37-.15-.79-.223-1.252-.223zm1.023 7.772H9.355v1.6h1.688z"/></svg>
\ No newline at end of file
index d30485e..0a838b0 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article redirect</title><path fill="#fff" d="M15 1H5a2 2 0 0 0-2 2v1c0 5 2 8 7 8V9l5 4-5 4v-3c-3.18 0-5.51-.85-7-2.68V17a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article redirect</title><path fill="#fff" d="M5 1a2 2 0 0 0-2 2v1c0 5 2 8 7 8V9l5 4-5 4v-3c-3.18 0-5.51-.85-7-2.68V17a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
index 3075f61..14e438f 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article redirect</title><path fill="#36c" d="M15 1H5a2 2 0 0 0-2 2v1c0 5 2 8 7 8V9l5 4-5 4v-3c-3.18 0-5.51-.85-7-2.68V17a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article redirect</title><path fill="#36c" d="M5 1a2 2 0 0 0-2 2v1c0 5 2 8 7 8V9l5 4-5 4v-3c-3.18 0-5.51-.85-7-2.68V17a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
index 3ec9a9c..666dac2 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article redirect</title><path d="M15 1H5a2 2 0 0 0-2 2v1c0 5 2 8 7 8V9l5 4-5 4v-3c-3.18 0-5.51-.85-7-2.68V17a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article redirect</title><path d="M5 1a2 2 0 0 0-2 2v1c0 5 2 8 7 8V9l5 4-5 4v-3c-3.18 0-5.51-.85-7-2.68V17a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
index c74f93b..13cd649 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article redirect</title><path fill="#fff" d="M3 3v14c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2v-5.7c-1.5 1.8-3.8 2.7-7 2.7v3l-5-4 5-4v3c5 0 7-3 7-8V3c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article redirect</title><path fill="#fff" d="M3 17c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2v-5.7c-1.5 1.8-3.8 2.7-7 2.7v3l-5-4 5-4v3c5 0 7-3 7-8V3c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2z"/></svg>
\ No newline at end of file
index aec619b..162dec3 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article redirect</title><path fill="#36c" d="M3 3v14c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2v-5.7c-1.5 1.8-3.8 2.7-7 2.7v3l-5-4 5-4v3c5 0 7-3 7-8V3c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article redirect</title><path fill="#36c" d="M3 17c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2v-5.7c-1.5 1.8-3.8 2.7-7 2.7v3l-5-4 5-4v3c5 0 7-3 7-8V3c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2z"/></svg>
\ No newline at end of file
index feb8ee7..b5c5064 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article redirect</title><path d="M3 3v14c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2v-5.7c-1.5 1.8-3.8 2.7-7 2.7v3l-5-4 5-4v3c5 0 7-3 7-8V3c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>article redirect</title><path d="M3 17c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2v-5.7c-1.5 1.8-3.8 2.7-7 2.7v3l-5-4 5-4v3c5 0 7-3 7-8V3c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2z"/></svg>
\ No newline at end of file
index 8e0800e..3a02aa1 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>articles</title><g fill="#fff"><path d="M16 0H5v2h11v14h2V2a2 2 0 0 0-2-2z"/><path d="M4 20h9a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2zM9 5h4v5H9zM4 5h4v1H4zm0 2h4v1H4zm0 2h4v1H4zm0 2h9v1H4zm0 2h9v1H4zm0 2h9v1H4z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>articles</title><g fill="#fff"><path d="M5 0v2h11v14h2V2a2 2 0 0 0-2-2z"/><path d="M13 20a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2zM9 5h4v5H9zM4 5h4v1H4zm0 2h4v1H4zm0 2h4v1H4zm0 2h9v1H4zm0 2h9v1H4zm0 2h9v1H4z"/></g></svg>
\ No newline at end of file
index 383d905..9475ce8 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>articles</title><g fill="#36c"><path d="M16 0H5v2h11v14h2V2a2 2 0 0 0-2-2z"/><path d="M4 20h9a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2zM9 5h4v5H9zM4 5h4v1H4zm0 2h4v1H4zm0 2h4v1H4zm0 2h9v1H4zm0 2h9v1H4zm0 2h9v1H4z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>articles</title><g fill="#36c"><path d="M5 0v2h11v14h2V2a2 2 0 0 0-2-2z"/><path d="M13 20a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2zM9 5h4v5H9zM4 5h4v1H4zm0 2h4v1H4zm0 2h4v1H4zm0 2h9v1H4zm0 2h9v1H4zm0 2h9v1H4z"/></g></svg>
\ No newline at end of file
index a3b0833..8de6f28 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>articles</title><path d="M16 0H5v2h11v14h2V2a2 2 0 0 0-2-2z"/><path d="M4 20h9a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2zM9 5h4v5H9zM4 5h4v1H4zm0 2h4v1H4zm0 2h4v1H4zm0 2h9v1H4zm0 2h9v1H4zm0 2h9v1H4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>articles</title><path d="M5 0v2h11v14h2V2a2 2 0 0 0-2-2z"/><path d="M13 20a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2zM9 5h4v5H9zM4 5h4v1H4zm0 2h4v1H4zm0 2h4v1H4zm0 2h9v1H4zm0 2h9v1H4zm0 2h9v1H4z"/></svg>
\ No newline at end of file
index 24f6eb0..edbd240 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>articles</title><g fill="#fff"><path d="M4 0h11v2H4v14H2V2a2 2 0 0 1 2-2z"/><path d="M18 18V5a2 2 0 0 0-2-2H7a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2zm-7-8H7V5h4zm5-4h-4V5h4zm0 2h-4V7h4zm0 2h-4V9h4zm0 2H7v-1h9zm0 2H7v-1h9zm0 2H7v-1h9z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>articles</title><g fill="#fff"><path d="M15 0v2H4v14H2V2a2 2 0 0 1 2-2z"/><path d="M18 5a2 2 0 0 0-2-2H7a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2zm-7 5H7V5h4zm5-4h-4V5h4zm0 2h-4V7h4zm0 2h-4V9h4zm0 2H7v-1h9zm0 2H7v-1h9zm0 2H7v-1h9z"/></g></svg>
\ No newline at end of file
index 81c3a48..ca72eab 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>articles</title><g fill="#36c"><path d="M4 0h11v2H4v14H2V2a2 2 0 0 1 2-2z"/><path d="M18 18V5a2 2 0 0 0-2-2H7a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2zm-7-8H7V5h4zm5-4h-4V5h4zm0 2h-4V7h4zm0 2h-4V9h4zm0 2H7v-1h9zm0 2H7v-1h9zm0 2H7v-1h9z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>articles</title><g fill="#36c"><path d="M15 0v2H4v14H2V2a2 2 0 0 1 2-2z"/><path d="M18 5a2 2 0 0 0-2-2H7a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2zm-7 5H7V5h4zm5-4h-4V5h4zm0 2h-4V7h4zm0 2h-4V9h4zm0 2H7v-1h9zm0 2H7v-1h9zm0 2H7v-1h9z"/></g></svg>
\ No newline at end of file
index 522e646..2983357 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>articles</title><path d="M4 0h11v2H4v14H2V2a2 2 0 0 1 2-2z"/><path d="M18 18V5a2 2 0 0 0-2-2H7a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2zm-7-8H7V5h4zm5-4h-4V5h4zm0 2h-4V7h4zm0 2h-4V9h4zm0 2H7v-1h9zm0 2H7v-1h9zm0 2H7v-1h9z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>articles</title><path d="M15 0v2H4v14H2V2a2 2 0 0 1 2-2z"/><path d="M18 5a2 2 0 0 0-2-2H7a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2zm-7 5H7V5h4zm5-4h-4V5h4zm0 2h-4V7h4zm0 2h-4V9h4zm0 2H7v-1h9zm0 2H7v-1h9zm0 2H7v-1h9z"/></svg>
\ No newline at end of file
index 224433e..28c5ae3 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/beaker-invert.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/beaker-invert.png differ
index ab0fbe3..107ffa8 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>beaker</title><path fill="#fff" d="M18.86 17.49L13 7.61V3h1V1H6v2h1v4.61l-5.86 9.88A1 1 0 0 0 2 19h16a1 1 0 0 0 .86-1.51zm-10-9.09A1 1 0 0 0 9 7.89V3h2v4.89a1 1 0 0 0 .14.51l2.14 3.6H6.72z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>beaker</title><path fill="#fff" d="M13 7.61V3h1V1H6v2h1v4.61l-5.86 9.88A1 1 0 0 0 2 19h16a1 1 0 0 0 .86-1.51zm-4.2.88a1 1 0 0 0 .2-.6V3h2v4.89a1 1 0 0 0 .14.51l2.14 3.6H6.72z"/></svg>
\ No newline at end of file
index 2d2ed6f..4bde9bf 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/beaker-progressive.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/beaker-progressive.png differ
index 80d57a1..0ef3edf 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>beaker</title><path fill="#36c" d="M18.86 17.49L13 7.61V3h1V1H6v2h1v4.61l-5.86 9.88A1 1 0 0 0 2 19h16a1 1 0 0 0 .86-1.51zm-10-9.09A1 1 0 0 0 9 7.89V3h2v4.89a1 1 0 0 0 .14.51l2.14 3.6H6.72z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>beaker</title><path fill="#36c" d="M13 7.61V3h1V1H6v2h1v4.61l-5.86 9.88A1 1 0 0 0 2 19h16a1 1 0 0 0 .86-1.51zm-4.2.88a1 1 0 0 0 .2-.6V3h2v4.89a1 1 0 0 0 .14.51l2.14 3.6H6.72z"/></svg>
\ No newline at end of file
index decef02..dcc30c2 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/beaker.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/beaker.png differ
index dadaac3..6796523 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>beaker</title><path d="M18.86 17.49L13 7.61V3h1V1H6v2h1v4.61l-5.86 9.88A1 1 0 0 0 2 19h16a1 1 0 0 0 .86-1.51zm-10-9.09A1 1 0 0 0 9 7.89V3h2v4.89a1 1 0 0 0 .14.51l2.14 3.6H6.72z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>beaker</title><path d="M13 7.61V3h1V1H6v2h1v4.61l-5.86 9.88A1 1 0 0 0 2 19h16a1 1 0 0 0 .86-1.51zm-4.2.88a1 1 0 0 0 .2-.6V3h2v4.89a1 1 0 0 0 .14.51l2.14 3.6H6.72z"/></svg>
\ No newline at end of file
index e9f5745..2761894 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bigger</title><path fill="#fff" d="M14 18h-1.57a.66.66 0 0 1-.44-.13.87.87 0 0 1-.25-.34l-1-2.77H5.3l-1 2.77a.83.83 0 0 1-.24.32.65.65 0 0 1-.44.15H2L7 5.47h2zm-3.85-4.7L8.42 8.72A12.66 12.66 0 0 1 8 7.37q-.1.41-.21.75t-.21.6L5.85 13.3zM15 2l3 4h-6l3-4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bigger</title><path fill="#fff" d="M14 18h-1.57a.66.66 0 0 1-.44-.13.87.87 0 0 1-.25-.34l-1-2.77H5.3l-1 2.77a.83.83 0 0 1-.24.32.65.65 0 0 1-.44.15H2L7 5.47h2zm-3.85-4.7L8.42 8.72A12.66 12.66 0 0 1 8 7.37q-.1.41-.21.75t-.21.6L5.85 13.3zM15 2l3 4h-6z"/></svg>
\ No newline at end of file
index f03fab7..ac61d07 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bigger</title><path fill="#36c" d="M14 18h-1.57a.66.66 0 0 1-.44-.13.87.87 0 0 1-.25-.34l-1-2.77H5.3l-1 2.77a.83.83 0 0 1-.24.32.65.65 0 0 1-.44.15H2L7 5.47h2zm-3.85-4.7L8.42 8.72A12.66 12.66 0 0 1 8 7.37q-.1.41-.21.75t-.21.6L5.85 13.3zM15 2l3 4h-6l3-4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bigger</title><path fill="#36c" d="M14 18h-1.57a.66.66 0 0 1-.44-.13.87.87 0 0 1-.25-.34l-1-2.77H5.3l-1 2.77a.83.83 0 0 1-.24.32.65.65 0 0 1-.44.15H2L7 5.47h2zm-3.85-4.7L8.42 8.72A12.66 12.66 0 0 1 8 7.37q-.1.41-.21.75t-.21.6L5.85 13.3zM15 2l3 4h-6z"/></svg>
\ No newline at end of file
index 19400ae..0831060 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bigger</title><path d="M14 18h-1.57a.66.66 0 0 1-.44-.13.87.87 0 0 1-.25-.34l-1-2.77H5.3l-1 2.77a.83.83 0 0 1-.24.32.65.65 0 0 1-.44.15H2L7 5.47h2zm-3.85-4.7L8.42 8.72A12.66 12.66 0 0 1 8 7.37q-.1.41-.21.75t-.21.6L5.85 13.3zM15 2l3 4h-6l3-4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bigger</title><path d="M14 18h-1.57a.66.66 0 0 1-.44-.13.87.87 0 0 1-.25-.34l-1-2.77H5.3l-1 2.77a.83.83 0 0 1-.24.32.65.65 0 0 1-.44.15H2L7 5.47h2zm-3.85-4.7L8.42 8.72A12.66 12.66 0 0 1 8 7.37q-.1.41-.21.75t-.21.6L5.85 13.3zM15 2l3 4h-6z"/></svg>
\ No newline at end of file
index e1b29e4..5f15b5c 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>bold</title><path d="M5 17V3h3v12h7v2"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>bold</title><path d="M5 17V3h3v12h7v2z"/></g></svg>
\ No newline at end of file
index 862f225..286435a 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>bold</title><path d="M5 17V3h3v12h7v2"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>bold</title><path d="M5 17V3h3v12h7v2z"/></g></svg>
\ No newline at end of file
index 4007c81..ee3a0a8 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bold</title><path d="M5 17V3h3v12h7v2"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bold</title><path d="M5 17V3h3v12h7v2z"/></svg>
\ No newline at end of file
index 41001c8..9c3aaa2 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>bold</title><path d="M4 17V3h3l6 9.333V3h3v14h-3L7 7.667V17H4"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>bold</title><path d="M4 3h3l6 9.333V3h3v14h-3L7 7.667V17H4z"/></g></svg>
\ No newline at end of file
index 7823bd7..c990385 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>bold</title><path d="M4 17V3h3l6 9.333V3h3v14h-3L7 7.667V17H4"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>bold</title><path d="M4 3h3l6 9.333V3h3v14h-3L7 7.667V17H4z"/></g></svg>
\ No newline at end of file
index c10c55e..4e76bc3 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bold</title><path d="M4 17V3h3l6 9.333V3h3v14h-3L7 7.667V17H4"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bold</title><path d="M4 3h3l6 9.333V3h3v14h-3L7 7.667V17H4z"/></svg>
\ No newline at end of file
index 9bc0ea5..d88776a 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>bold</title><path d="M8.25 17L3 3h3.5l3.5 9.333L13.5 3H17l-5.25 14"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>bold</title><path d="M3 3h3.5l3.5 9.333L13.5 3H17l-5.25 14h-3.5z"/></g></svg>
\ No newline at end of file
index 881bb06..354465e 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>bold</title><path d="M8.25 17L3 3h3.5l3.5 9.333L13.5 3H17l-5.25 14"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>bold</title><path d="M3 3h3.5l3.5 9.333L13.5 3H17l-5.25 14h-3.5z"/></g></svg>
\ No newline at end of file
index 0283db1..3e1eab8 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bold</title><path d="M8.25 17L3 3h3.5l3.5 9.333L13.5 3H17l-5.25 14"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bold</title><path d="M3 3h3.5l3.5 9.333L13.5 3H17l-5.25 14h-3.5z"/></svg>
\ No newline at end of file
index d10dfb1..be0ccbb 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bookmark</title><path fill="#fff" d="M15 1H5a2 2 0 0 0-2 2v16l7-5 7 5V3a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bookmark</title><path fill="#fff" d="M5 1a2 2 0 0 0-2 2v16l7-5 7 5V3a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
index d79220f..8b60b1f 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bookmark</title><path fill="#36c" d="M15 1H5a2 2 0 0 0-2 2v16l7-5 7 5V3a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bookmark</title><path fill="#36c" d="M5 1a2 2 0 0 0-2 2v16l7-5 7 5V3a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
index d5d0797..27d6c45 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bookmark</title><path d="M15 1H5a2 2 0 0 0-2 2v16l7-5 7 5V3a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bookmark</title><path d="M5 1a2 2 0 0 0-2 2v16l7-5 7 5V3a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
index 62ad078..7b78416 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bookmark outlined</title><path fill="#fff" d="M15 1H5a2 2 0 0 0-2 2v16l7-5 7 5V3a2 2 0 0 0-2-2zm0 14.25l-5-3.5-5 3.5V3h10z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bookmark outlined</title><path fill="#fff" d="M5 1a2 2 0 0 0-2 2v16l7-5 7 5V3a2 2 0 0 0-2-2zm10 14.25l-5-3.5-5 3.5V3h10z"/></svg>
\ No newline at end of file
index ba60c95..0e31efa 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bookmark outlined</title><path fill="#36c" d="M15 1H5a2 2 0 0 0-2 2v16l7-5 7 5V3a2 2 0 0 0-2-2zm0 14.25l-5-3.5-5 3.5V3h10z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bookmark outlined</title><path fill="#36c" d="M5 1a2 2 0 0 0-2 2v16l7-5 7 5V3a2 2 0 0 0-2-2zm10 14.25l-5-3.5-5 3.5V3h10z"/></svg>
\ No newline at end of file
index 04d8d28..6431f72 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bookmark outlined</title><path d="M15 1H5a2 2 0 0 0-2 2v16l7-5 7 5V3a2 2 0 0 0-2-2zm0 14.25l-5-3.5-5 3.5V3h10z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bookmark outlined</title><path d="M5 1a2 2 0 0 0-2 2v16l7-5 7 5V3a2 2 0 0 0-2-2zm10 14.25l-5-3.5-5 3.5V3h10z"/></svg>
\ No newline at end of file
index 19357ac..12db77e 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>browser</title><path fill="#fff" d="M18 2H2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zM4 3.5A1.5 1.5 0 1 1 2.5 5 1.5 1.5 0 0 1 4 3.5zM18 16H2V8h16z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>browser</title><path fill="#fff" d="M2 2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm2 1.5A1.5 1.5 0 1 1 2.5 5 1.5 1.5 0 0 1 4 3.5zM18 16H2V8h16z"/></svg>
\ No newline at end of file
index 1d7228f..7206f6f 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>browser</title><path fill="#36c" d="M18 2H2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zM4 3.5A1.5 1.5 0 1 1 2.5 5 1.5 1.5 0 0 1 4 3.5zM18 16H2V8h16z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>browser</title><path fill="#36c" d="M2 2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm2 1.5A1.5 1.5 0 1 1 2.5 5 1.5 1.5 0 0 1 4 3.5zM18 16H2V8h16z"/></svg>
\ No newline at end of file
index c496ab7..a74b5f3 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>browser</title><path d="M18 2H2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zM4 3.5A1.5 1.5 0 1 1 2.5 5 1.5 1.5 0 0 1 4 3.5zM18 16H2V8h16z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>browser</title><path d="M2 2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm2 1.5A1.5 1.5 0 1 1 2.5 5 1.5 1.5 0 0 1 4 3.5zM18 16H2V8h16z"/></svg>
\ No newline at end of file
index 4691bd6..a15b911 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>browser</title><path fill="#fff" d="M0 4v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2H2C.9 2 0 2.9 0 4zm17.5 1c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5.7-1.5 1.5-1.5 1.5.7 1.5 1.5zM2 8h16v8H2V8z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>browser</title><path fill="#fff" d="M0 16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2H2C.9 2 0 2.9 0 4zM17.5 5c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5.7-1.5 1.5-1.5 1.5.7 1.5 1.5zM2 8h16v8H2z"/></svg>
\ No newline at end of file
index dc5417c..1730c98 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>browser</title><path fill="#36c" d="M0 4v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2H2C.9 2 0 2.9 0 4zm17.5 1c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5.7-1.5 1.5-1.5 1.5.7 1.5 1.5zM2 8h16v8H2V8z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>browser</title><path fill="#36c" d="M0 16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2H2C.9 2 0 2.9 0 4zM17.5 5c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5.7-1.5 1.5-1.5 1.5.7 1.5 1.5zM2 8h16v8H2z"/></svg>
\ No newline at end of file
index 738d05c..3108da6 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>browser</title><path d="M0 4v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2H2C.9 2 0 2.9 0 4zm17.5 1c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5.7-1.5 1.5-1.5 1.5.7 1.5 1.5zM2 8h16v8H2V8z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>browser</title><path d="M0 16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2H2C.9 2 0 2.9 0 4zM17.5 5c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5.7-1.5 1.5-1.5 1.5.7 1.5 1.5zM2 8h16v8H2z"/></svg>
\ No newline at end of file
index 4c88b00..20c7da0 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>calendar</title><path fill="#fff" d="M18 3h-3V1h-2v2H7V1H5v2H2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zm0 14H2V8h16zm-2-6h-4v4h4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>calendar</title><path fill="#fff" d="M15 3V1h-2v2H7V1H5v2H2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zm3 14H2V8h16zm-2-6h-4v4h4z"/></svg>
\ No newline at end of file
index 0e20e6a..8102a8b 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>calendar</title><path fill="#36c" d="M18 3h-3V1h-2v2H7V1H5v2H2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zm0 14H2V8h16zm-2-6h-4v4h4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>calendar</title><path fill="#36c" d="M15 3V1h-2v2H7V1H5v2H2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zm3 14H2V8h16zm-2-6h-4v4h4z"/></svg>
\ No newline at end of file
index a818b0b..5733191 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>calendar</title><path d="M18 3h-3V1h-2v2H7V1H5v2H2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zm0 14H2V8h16zm-2-6h-4v4h4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>calendar</title><path d="M15 3V1h-2v2H7V1H5v2H2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zm3 14H2V8h16zm-2-6h-4v4h4z"/></svg>
\ No newline at end of file
index e5167ad..a4e1e21 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>chart</title><g fill="#fff"><path d="M3 17V3H1v16h18v-2H3z"/><path d="M18 5l-7 6-3-2-4 4v3h14V5z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>chart</title><g fill="#fff"><path d="M3 3H1v16h18v-2H3z"/><path d="M11 11L8 9l-4 4v3h14V5z"/></g></svg>
\ No newline at end of file
index 9233478..787de0c 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>chart</title><g fill="#36c"><path d="M3 17V3H1v16h18v-2H3z"/><path d="M18 5l-7 6-3-2-4 4v3h14V5z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>chart</title><g fill="#36c"><path d="M3 3H1v16h18v-2H3z"/><path d="M11 11L8 9l-4 4v3h14V5z"/></g></svg>
\ No newline at end of file
index a979a4c..58a2a13 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>chart</title><path d="M3 17V3H1v16h18v-2H3z"/><path d="M18 5l-7 6-3-2-4 4v3h14V5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>chart</title><path d="M3 3H1v16h18v-2H3z"/><path d="M11 11L8 9l-4 4v3h14V5z"/></svg>
\ No newline at end of file
index 0414d6b..e03f6f0 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>check</title><path fill="#d33" d="M7 14.17L2.83 10l-1.41 1.41L7 17 19 5l-1.41-1.42L7 14.17z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>check</title><path fill="#d33" d="M7 14.17L2.83 10l-1.41 1.41L7 17 19 5l-1.41-1.42z"/></svg>
\ No newline at end of file
index 8ae3020..847cebc 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>check</title><path fill="#fff" d="M7 14.17L2.83 10l-1.41 1.41L7 17 19 5l-1.41-1.42L7 14.17z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>check</title><path fill="#fff" d="M7 14.17L2.83 10l-1.41 1.41L7 17 19 5l-1.41-1.42z"/></svg>
\ No newline at end of file
index 73dbdf1..3ab6190 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>check</title><path fill="#36c" d="M7 14.17L2.83 10l-1.41 1.41L7 17 19 5l-1.41-1.42L7 14.17z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>check</title><path fill="#36c" d="M7 14.17L2.83 10l-1.41 1.41L7 17 19 5l-1.41-1.42z"/></svg>
\ No newline at end of file
index ef190d4..f361b93 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>check</title><path fill="#14866d" d="M7 14.17L2.83 10l-1.41 1.41L7 17 19 5l-1.41-1.42L7 14.17z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>check</title><path fill="#14866d" d="M7 14.17L2.83 10l-1.41 1.41L7 17 19 5l-1.41-1.42z"/></svg>
\ No newline at end of file
index 77ff858..62a0337 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>check</title><path d="M7 14.17L2.83 10l-1.41 1.41L7 17 19 5l-1.41-1.42L7 14.17z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>check</title><path d="M7 14.17L2.83 10l-1.41 1.41L7 17 19 5l-1.41-1.42z"/></svg>
\ No newline at end of file
index d5dc113..dfd4579 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>check all</title><path fill="#fff" d="M4.07 16.49L.29 12.71l1.42-1.42 2.22 2.22 8.3-10.14 1.54 1.26-9.7 11.86zM12 10h5v2h-5zm-3 4h5v2H9zm6-8h5v2h-5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>check all</title><path fill="#fff" d="M.29 12.71l1.42-1.42 2.22 2.22 8.3-10.14 1.54 1.26-9.7 11.86zM12 10h5v2h-5zm-3 4h5v2H9zm6-8h5v2h-5z"/></svg>
\ No newline at end of file
index 92bdbaf..1df0d4f 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>check all</title><path fill="#36c" d="M4.07 16.49L.29 12.71l1.42-1.42 2.22 2.22 8.3-10.14 1.54 1.26-9.7 11.86zM12 10h5v2h-5zm-3 4h5v2H9zm6-8h5v2h-5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>check all</title><path fill="#36c" d="M.29 12.71l1.42-1.42 2.22 2.22 8.3-10.14 1.54 1.26-9.7 11.86zM12 10h5v2h-5zm-3 4h5v2H9zm6-8h5v2h-5z"/></svg>
\ No newline at end of file
index de8ee4b..6fe1464 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>check all</title><path d="M4.07 16.49L.29 12.71l1.42-1.42 2.22 2.22 8.3-10.14 1.54 1.26-9.7 11.86zM12 10h5v2h-5zm-3 4h5v2H9zm6-8h5v2h-5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>check all</title><path d="M.29 12.71l1.42-1.42 2.22 2.22 8.3-10.14 1.54 1.26-9.7 11.86zM12 10h5v2h-5zm-3 4h5v2H9zm6-8h5v2h-5z"/></svg>
\ No newline at end of file
index fbf35c3..603d4c3 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>collapse</title><path fill="#fff" d="M1 13.75l1.5 1.5 7.5-7.5 7.5 7.5 1.5-1.5-9-9-9 9z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>collapse</title><path fill="#fff" d="M2.5 15.25l7.5-7.5 7.5 7.5 1.5-1.5-9-9-9 9z"/></svg>
\ No newline at end of file
index 2109697..0855d79 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>collapse</title><path fill="#36c" d="M1 13.75l1.5 1.5 7.5-7.5 7.5 7.5 1.5-1.5-9-9-9 9z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>collapse</title><path fill="#36c" d="M2.5 15.25l7.5-7.5 7.5 7.5 1.5-1.5-9-9-9 9z"/></svg>
\ No newline at end of file
index 580736c..c49bfe5 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>collapse</title><path d="M1 13.75l1.5 1.5 7.5-7.5 7.5 7.5 1.5-1.5-9-9-9 9z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>collapse</title><path d="M2.5 15.25l7.5-7.5 7.5 7.5 1.5-1.5-9-9-9 9z"/></svg>
\ No newline at end of file
index 7c7b3a2..5c19b63 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>die</title><path fill="#fff" d="M17 1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zM5 17a2 2 0 1 1 2-2 2 2 0 0 1-2 2zM5 7a2 2 0 1 1 2-2 2 2 0 0 1-2 2zm5 5a2 2 0 1 1 2-2 2 2 0 0 1-2 2zm5 5a2 2 0 1 1 2-2 2 2 0 0 1-2 2zm0-10a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>die</title><path fill="#fff" d="M3 1a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm2 16a2 2 0 1 1 2-2 2 2 0 0 1-2 2zM5 7a2 2 0 1 1 2-2 2 2 0 0 1-2 2zm5 5a2 2 0 1 1 2-2 2 2 0 0 1-2 2zm5 5a2 2 0 1 1 2-2 2 2 0 0 1-2 2zm0-10a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
index 681cbfc..549c40a 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>die</title><path fill="#36c" d="M17 1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zM5 17a2 2 0 1 1 2-2 2 2 0 0 1-2 2zM5 7a2 2 0 1 1 2-2 2 2 0 0 1-2 2zm5 5a2 2 0 1 1 2-2 2 2 0 0 1-2 2zm5 5a2 2 0 1 1 2-2 2 2 0 0 1-2 2zm0-10a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>die</title><path fill="#36c" d="M3 1a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm2 16a2 2 0 1 1 2-2 2 2 0 0 1-2 2zM5 7a2 2 0 1 1 2-2 2 2 0 0 1-2 2zm5 5a2 2 0 1 1 2-2 2 2 0 0 1-2 2zm5 5a2 2 0 1 1 2-2 2 2 0 0 1-2 2zm0-10a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
index 9fc0b03..8fec5b2 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>die</title><path d="M17 1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zM5 17a2 2 0 1 1 2-2 2 2 0 0 1-2 2zM5 7a2 2 0 1 1 2-2 2 2 0 0 1-2 2zm5 5a2 2 0 1 1 2-2 2 2 0 0 1-2 2zm5 5a2 2 0 1 1 2-2 2 2 0 0 1-2 2zm0-10a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>die</title><path d="M3 1a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm2 16a2 2 0 1 1 2-2 2 2 0 0 1-2 2zM5 7a2 2 0 1 1 2-2 2 2 0 0 1-2 2zm5 5a2 2 0 1 1 2-2 2 2 0 0 1-2 2zm5 5a2 2 0 1 1 2-2 2 2 0 0 1-2 2zm0-10a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
index 57b6f84..d974665 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>down triangle</title><path fill="#fff" d="M10 15L2 5h16l-8 10z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>down triangle</title><path fill="#fff" d="M10 15L2 5h16z"/></svg>
\ No newline at end of file
index 152cbb7..db8ce20 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>down triangle</title><path fill="#36c" d="M10 15L2 5h16l-8 10z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>down triangle</title><path fill="#36c" d="M10 15L2 5h16z"/></svg>
\ No newline at end of file
index 852ea6b..3b512ab 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>down triangle</title><path d="M10 15L2 5h16l-8 10z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>down triangle</title><path d="M10 15L2 5h16z"/></svg>
\ No newline at end of file
index 130b84c..28d279c 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>download</title><g fill="#fff"><path d="M17 12v5H3v-5H1v5a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5z"/><path d="M10 15l5-6h-4V1H9v8H5l5 6z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>download</title><g fill="#fff"><path d="M17 12v5H3v-5H1v5a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5z"/><path d="M15 9h-4V1H9v8H5l5 6z"/></g></svg>
\ No newline at end of file
index 3551d9b..01aa1ad 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>download</title><g fill="#36c"><path d="M17 12v5H3v-5H1v5a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5z"/><path d="M10 15l5-6h-4V1H9v8H5l5 6z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>download</title><g fill="#36c"><path d="M17 12v5H3v-5H1v5a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5z"/><path d="M15 9h-4V1H9v8H5l5 6z"/></g></svg>
\ No newline at end of file
index 9023c6a..f3c94d4 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>download</title><path d="M17 12v5H3v-5H1v5a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5z"/><path d="M10 15l5-6h-4V1H9v8H5l5 6z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>download</title><path d="M17 12v5H3v-5H1v5a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5z"/><path d="M15 9h-4V1H9v8H5l5 6z"/></svg>
\ No newline at end of file
index 31503f0..2f4352f 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>draggable</title><path fill="#fff" d="M2 11h16v2H2zm0-4h16v2H2zm8 11l3-3H7l3 3zm0-16L7 5h6l-3-3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>draggable</title><path fill="#fff" d="M2 11h16v2H2zm0-4h16v2H2zm11 8H7l3 3zM7 5h6l-3-3z"/></svg>
\ No newline at end of file
index 34bd4d7..9c57fe3 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>draggable</title><path fill="#36c" d="M2 11h16v2H2zm0-4h16v2H2zm8 11l3-3H7l3 3zm0-16L7 5h6l-3-3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>draggable</title><path fill="#36c" d="M2 11h16v2H2zm0-4h16v2H2zm11 8H7l3 3zM7 5h6l-3-3z"/></svg>
\ No newline at end of file
index 9b4ca86..c6e128a 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>draggable</title><path d="M2 11h16v2H2zm0-4h16v2H2zm8 11l3-3H7l3 3zm0-16L7 5h6l-3-3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>draggable</title><path d="M2 11h16v2H2zm0-4h16v2H2zm11 8H7l3 3zM7 5h6l-3-3z"/></svg>
\ No newline at end of file
index 6117de9..4b87a48 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>edit</title><path fill="#fff" d="M16.77 8l1.94-2a1 1 0 0 0 0-1.41l-3.34-3.3a1 1 0 0 0-1.41 0L12 3.23zm-5.81-3.71L1 14.25V19h4.75l9.96-9.96-4.75-4.75z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>edit</title><path fill="#fff" d="M16.77 8l1.94-2a1 1 0 0 0 0-1.41l-3.34-3.3a1 1 0 0 0-1.41 0L12 3.23zM1 14.25V19h4.75l9.96-9.96-4.75-4.75z"/></svg>
\ No newline at end of file
index 21aa633..c14305e 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>edit</title><path fill="#36c" d="M16.77 8l1.94-2a1 1 0 0 0 0-1.41l-3.34-3.3a1 1 0 0 0-1.41 0L12 3.23zm-5.81-3.71L1 14.25V19h4.75l9.96-9.96-4.75-4.75z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>edit</title><path fill="#36c" d="M16.77 8l1.94-2a1 1 0 0 0 0-1.41l-3.34-3.3a1 1 0 0 0-1.41 0L12 3.23zM1 14.25V19h4.75l9.96-9.96-4.75-4.75z"/></svg>
\ No newline at end of file
index cc29f6e..a6f305f 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>edit</title><path d="M16.77 8l1.94-2a1 1 0 0 0 0-1.41l-3.34-3.3a1 1 0 0 0-1.41 0L12 3.23zm-5.81-3.71L1 14.25V19h4.75l9.96-9.96-4.75-4.75z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>edit</title><path d="M16.77 8l1.94-2a1 1 0 0 0 0-1.41l-3.34-3.3a1 1 0 0 0-1.41 0L12 3.23zM1 14.25V19h4.75l9.96-9.96-4.75-4.75z"/></svg>
\ No newline at end of file
index 0c3b396..86e9198 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo edit</title><path fill="#fff" d="M8.81 6.44L1 14.25V19h4.75l8.33-8.33-5.27-4.23zm5.05-3.58H13V0L8 4l5 4V5h.86c2.29 0 4 1.43 4 4.29H20a6.51 6.51 0 0 0-6.14-6.43z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo edit</title><path fill="#fff" d="M1 14.25V19h4.75l8.33-8.33-5.27-4.23zM13 2.86V0L8 4l5 4V5h.86c2.29 0 4 1.43 4 4.29H20a6.51 6.51 0 0 0-6.14-6.43z"/></svg>
\ No newline at end of file
index b18e215..396b656 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo edit</title><path fill="#36c" d="M8.81 6.44L1 14.25V19h4.75l8.33-8.33-5.27-4.23zm5.05-3.58H13V0L8 4l5 4V5h.86c2.29 0 4 1.43 4 4.29H20a6.51 6.51 0 0 0-6.14-6.43z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo edit</title><path fill="#36c" d="M1 14.25V19h4.75l8.33-8.33-5.27-4.23zM13 2.86V0L8 4l5 4V5h.86c2.29 0 4 1.43 4 4.29H20a6.51 6.51 0 0 0-6.14-6.43z"/></svg>
\ No newline at end of file
index 1e52a45..ec86e2e 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo edit</title><path d="M8.81 6.44L1 14.25V19h4.75l8.33-8.33-5.27-4.23zm5.05-3.58H13V0L8 4l5 4V5h.86c2.29 0 4 1.43 4 4.29H20a6.51 6.51 0 0 0-6.14-6.43z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo edit</title><path d="M1 14.25V19h4.75l8.33-8.33-5.27-4.23zM13 2.86V0L8 4l5 4V5h.86c2.29 0 4 1.43 4 4.29H20a6.51 6.51 0 0 0-6.14-6.43z"/></svg>
\ No newline at end of file
index 0fb064d..e25470a 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo edit</title><g fill="#fff"><path d="M10.81 7.44L3 15.25V20h4.75l8.33-8.33-5.27-4.23z"/><path d="M12.14 2.86H13V0l5 4-5 4V5h-.86c-2.28 0-4 1.43-4 4.29H6a6.51 6.51 0 0 1 6.14-6.43z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo edit</title><g fill="#fff"><path d="M3 15.25V20h4.75l8.33-8.33-5.27-4.23z"/><path d="M13 2.86V0l5 4-5 4V5h-.86c-2.28 0-4 1.43-4 4.29H6a6.51 6.51 0 0 1 6.14-6.43z"/></g></svg>
\ No newline at end of file
index 9da6a88..c65bd8a 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo edit</title><g fill="#36c"><path d="M10.81 7.44L3 15.25V20h4.75l8.33-8.33-5.27-4.23z"/><path d="M12.14 2.86H13V0l5 4-5 4V5h-.86c-2.28 0-4 1.43-4 4.29H6a6.51 6.51 0 0 1 6.14-6.43z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo edit</title><g fill="#36c"><path d="M3 15.25V20h4.75l8.33-8.33-5.27-4.23z"/><path d="M13 2.86V0l5 4-5 4V5h-.86c-2.28 0-4 1.43-4 4.29H6a6.51 6.51 0 0 1 6.14-6.43z"/></g></svg>
\ No newline at end of file
index 5a6859b..67d75bd 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo edit</title><path d="M10.81 7.44L3 15.25V20h4.75l8.33-8.33-5.27-4.23z"/><path d="M12.14 2.86H13V0l5 4-5 4V5h-.86c-2.28 0-4 1.43-4 4.29H6a6.51 6.51 0 0 1 6.14-6.43z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo edit</title><path d="M3 15.25V20h4.75l8.33-8.33-5.27-4.23z"/><path d="M13 2.86V0l5 4-5 4V5h-.86c-2.28 0-4 1.43-4 4.29H6a6.51 6.51 0 0 1 6.14-6.43z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/error-error.png b/resources/lib/ooui/themes/wikimediaui/images/icons/error-error.png
new file mode 100644 (file)
index 0000000..a1d3353
Binary files /dev/null and b/resources/lib/ooui/themes/wikimediaui/images/icons/error-error.png differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/error-error.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/error-error.svg
new file mode 100644 (file)
index 0000000..3a2db43
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>error</title><path fill="#d33" d="M13.728 1H6.272L1 6.272v7.456L6.272 19h7.456L19 13.728V6.272zM11 15H9v-2h2zm0-4H9V5h2z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/error-invert.png b/resources/lib/ooui/themes/wikimediaui/images/icons/error-invert.png
new file mode 100644 (file)
index 0000000..40502b3
Binary files /dev/null and b/resources/lib/ooui/themes/wikimediaui/images/icons/error-invert.png differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/error-invert.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/error-invert.svg
new file mode 100644 (file)
index 0000000..bf7cf7e
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>error</title><path fill="#fff" d="M13.728 1H6.272L1 6.272v7.456L6.272 19h7.456L19 13.728V6.272zM11 15H9v-2h2zm0-4H9V5h2z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/error-progressive.png b/resources/lib/ooui/themes/wikimediaui/images/icons/error-progressive.png
new file mode 100644 (file)
index 0000000..ee87517
Binary files /dev/null and b/resources/lib/ooui/themes/wikimediaui/images/icons/error-progressive.png differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/error-progressive.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/error-progressive.svg
new file mode 100644 (file)
index 0000000..2072f16
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>error</title><path fill="#36c" d="M13.728 1H6.272L1 6.272v7.456L6.272 19h7.456L19 13.728V6.272zM11 15H9v-2h2zm0-4H9V5h2z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/error.png b/resources/lib/ooui/themes/wikimediaui/images/icons/error.png
new file mode 100644 (file)
index 0000000..0d575fb
Binary files /dev/null and b/resources/lib/ooui/themes/wikimediaui/images/icons/error.png differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/error.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/error.svg
new file mode 100644 (file)
index 0000000..69f4d9b
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>error</title><path d="M13.728 1H6.272L1 6.272v7.456L6.272 19h7.456L19 13.728V6.272zM11 15H9v-2h2zm0-4H9V5h2z"/></svg>
\ No newline at end of file
index eaa617b..8c2085a 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>exit fullscreen</title><path fill="#fff" d="M7 7V1H5v4H1v2h6zM5 19h2v-6H1v2h4v4zm10-4h4v-2h-6v6h2v-4zm0-8h4V5h-4V1h-2v6h2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>exit fullscreen</title><path fill="#fff" d="M7 7V1H5v4H1v2zM5 19h2v-6H1v2h4zm10-4h4v-2h-6v6h2zm0-8h4V5h-4V1h-2v6z"/></svg>
\ No newline at end of file
index e8744a6..426f673 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>exit fullscreen</title><path fill="#36c" d="M7 7V1H5v4H1v2h6zM5 19h2v-6H1v2h4v4zm10-4h4v-2h-6v6h2v-4zm0-8h4V5h-4V1h-2v6h2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>exit fullscreen</title><path fill="#36c" d="M7 7V1H5v4H1v2zM5 19h2v-6H1v2h4zm10-4h4v-2h-6v6h2zm0-8h4V5h-4V1h-2v6z"/></svg>
\ No newline at end of file
index 6822a68..2c79c28 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>exit fullscreen</title><path d="M7 7V1H5v4H1v2h6zM5 19h2v-6H1v2h4v4zm10-4h4v-2h-6v6h2v-4zm0-8h4V5h-4V1h-2v6h2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>exit fullscreen</title><path d="M7 7V1H5v4H1v2zM5 19h2v-6H1v2h4zm10-4h4v-2h-6v6h2zm0-8h4V5h-4V1h-2v6z"/></svg>
\ No newline at end of file
index 58d85fa..04b3108 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>expand</title><path fill="#fff" d="M19 6.25l-1.5-1.5-7.5 7.5-7.5-7.5L1 6.25l9 9 9-9z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>expand</title><path fill="#fff" d="M17.5 4.75l-7.5 7.5-7.5-7.5L1 6.25l9 9 9-9z"/></svg>
\ No newline at end of file
index ff08194..84744af 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>expand</title><path fill="#36c" d="M19 6.25l-1.5-1.5-7.5 7.5-7.5-7.5L1 6.25l9 9 9-9z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>expand</title><path fill="#36c" d="M17.5 4.75l-7.5 7.5-7.5-7.5L1 6.25l9 9 9-9z"/></svg>
\ No newline at end of file
index 94bc7c1..eec9c6a 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>expand</title><path d="M19 6.25l-1.5-1.5-7.5 7.5-7.5-7.5L1 6.25l9 9 9-9z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>expand</title><path d="M17.5 4.75l-7.5 7.5-7.5-7.5L1 6.25l9 9 9-9z"/></svg>
\ No newline at end of file
index 1491d94..c013939 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/eyeClosed-invert.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/eyeClosed-invert.png differ
index 5a5611d..6f54e9f 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>eye closed</title><g fill="#fff"><path d="M9.91 7.51l2.58 2.43A2.5 2.5 0 0 0 10 7.5z"/><path d="M8.2 5.9a4.38 4.38 0 0 1 1.8-.4 4.5 4.5 0 0 1 4.5 4.5 4.34 4.34 0 0 1-.29 1.55L17 14.14A14 14 0 0 0 20 10s-3-7-10-7a9.63 9.63 0 0 0-4 .85zm7.67 9.15L13 12.36l-1-.91-3.56-3.39L7 6.69 4.71 4.55 2 2 1 3l2.55 2.4A13.89 13.89 0 0 0 0 10s3 7 10 7a9.67 9.67 0 0 0 4.64-1.16L18 19l1-1-3.13-2.95zM10 14.5A4.5 4.5 0 0 1 5.5 10a4.45 4.45 0 0 1 .6-2.2l1.53 1.44a2.47 2.47 0 0 0-.13.76 2.49 2.49 0 0 0 3.41 2.32l1.54 1.45a4.47 4.47 0 0 1-2.45.73z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>eye closed</title><g fill="#fff"><path d="M12.49 9.94A2.5 2.5 0 0 0 10 7.5z"/><path d="M8.2 5.9a4.38 4.38 0 0 1 1.8-.4 4.5 4.5 0 0 1 4.5 4.5 4.34 4.34 0 0 1-.29 1.55L17 14.14A14 14 0 0 0 20 10s-3-7-10-7a9.63 9.63 0 0 0-4 .85zM2 2L1 3l2.55 2.4A13.89 13.89 0 0 0 0 10s3 7 10 7a9.67 9.67 0 0 0 4.64-1.16L18 19l1-1zm8 12.5A4.5 4.5 0 0 1 5.5 10a4.45 4.45 0 0 1 .6-2.2l1.53 1.44a2.47 2.47 0 0 0-.13.76 2.49 2.49 0 0 0 3.41 2.32l1.54 1.45a4.47 4.47 0 0 1-2.45.73z"/></g></svg>
\ No newline at end of file
index 5c6759a..2495104 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/eyeClosed-progressive.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/eyeClosed-progressive.png differ
index 6e2fa34..6a9a76d 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>eye closed</title><g fill="#36c"><path d="M9.91 7.51l2.58 2.43A2.5 2.5 0 0 0 10 7.5z"/><path d="M8.2 5.9a4.38 4.38 0 0 1 1.8-.4 4.5 4.5 0 0 1 4.5 4.5 4.34 4.34 0 0 1-.29 1.55L17 14.14A14 14 0 0 0 20 10s-3-7-10-7a9.63 9.63 0 0 0-4 .85zm7.67 9.15L13 12.36l-1-.91-3.56-3.39L7 6.69 4.71 4.55 2 2 1 3l2.55 2.4A13.89 13.89 0 0 0 0 10s3 7 10 7a9.67 9.67 0 0 0 4.64-1.16L18 19l1-1-3.13-2.95zM10 14.5A4.5 4.5 0 0 1 5.5 10a4.45 4.45 0 0 1 .6-2.2l1.53 1.44a2.47 2.47 0 0 0-.13.76 2.49 2.49 0 0 0 3.41 2.32l1.54 1.45a4.47 4.47 0 0 1-2.45.73z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>eye closed</title><g fill="#36c"><path d="M12.49 9.94A2.5 2.5 0 0 0 10 7.5z"/><path d="M8.2 5.9a4.38 4.38 0 0 1 1.8-.4 4.5 4.5 0 0 1 4.5 4.5 4.34 4.34 0 0 1-.29 1.55L17 14.14A14 14 0 0 0 20 10s-3-7-10-7a9.63 9.63 0 0 0-4 .85zM2 2L1 3l2.55 2.4A13.89 13.89 0 0 0 0 10s3 7 10 7a9.67 9.67 0 0 0 4.64-1.16L18 19l1-1zm8 12.5A4.5 4.5 0 0 1 5.5 10a4.45 4.45 0 0 1 .6-2.2l1.53 1.44a2.47 2.47 0 0 0-.13.76 2.49 2.49 0 0 0 3.41 2.32l1.54 1.45a4.47 4.47 0 0 1-2.45.73z"/></g></svg>
\ No newline at end of file
index 772e209..6eacf5a 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/eyeClosed.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/eyeClosed.png differ
index f1df4ac..f5c53f5 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>eye closed</title><path d="M9.91 7.51l2.58 2.43A2.5 2.5 0 0 0 10 7.5z"/><path d="M8.2 5.9a4.38 4.38 0 0 1 1.8-.4 4.5 4.5 0 0 1 4.5 4.5 4.34 4.34 0 0 1-.29 1.55L17 14.14A14 14 0 0 0 20 10s-3-7-10-7a9.63 9.63 0 0 0-4 .85zm7.67 9.15L13 12.36l-1-.91-3.56-3.39L7 6.69 4.71 4.55 2 2 1 3l2.55 2.4A13.89 13.89 0 0 0 0 10s3 7 10 7a9.67 9.67 0 0 0 4.64-1.16L18 19l1-1-3.13-2.95zM10 14.5A4.5 4.5 0 0 1 5.5 10a4.45 4.45 0 0 1 .6-2.2l1.53 1.44a2.47 2.47 0 0 0-.13.76 2.49 2.49 0 0 0 3.41 2.32l1.54 1.45a4.47 4.47 0 0 1-2.45.73z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>eye closed</title><path d="M12.49 9.94A2.5 2.5 0 0 0 10 7.5z"/><path d="M8.2 5.9a4.38 4.38 0 0 1 1.8-.4 4.5 4.5 0 0 1 4.5 4.5 4.34 4.34 0 0 1-.29 1.55L17 14.14A14 14 0 0 0 20 10s-3-7-10-7a9.63 9.63 0 0 0-4 .85zM2 2L1 3l2.55 2.4A13.89 13.89 0 0 0 0 10s3 7 10 7a9.67 9.67 0 0 0 4.64-1.16L18 19l1-1zm8 12.5A4.5 4.5 0 0 1 5.5 10a4.45 4.45 0 0 1 .6-2.2l1.53 1.44a2.47 2.47 0 0 0-.13.76 2.49 2.49 0 0 0 3.41 2.32l1.54 1.45a4.47 4.47 0 0 1-2.45.73z"/></svg>
\ No newline at end of file
index 6fd541f..80924b2 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>feedback</title><g fill="#fff"><path d="M1 3l17 4c.6.7 1 1.6 1 2.5 0 .9-.4 1.8-1 2.5L1 16V3z"/><rect width="4" height="8" x="12" y="9" rx="2"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>feedback</title><g fill="#fff"><path d="M18 7c.6.7 1 1.6 1 2.5 0 .9-.4 1.8-1 2.5L1 16V3z"/><rect width="4" height="8" x="12" y="9" rx="2"/></g></svg>
\ No newline at end of file
index 2fe0560..7fed87d 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>feedback</title><g fill="#36c"><path d="M1 3l17 4c.6.7 1 1.6 1 2.5 0 .9-.4 1.8-1 2.5L1 16V3z"/><rect width="4" height="8" x="12" y="9" rx="2"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>feedback</title><g fill="#36c"><path d="M18 7c.6.7 1 1.6 1 2.5 0 .9-.4 1.8-1 2.5L1 16V3z"/><rect width="4" height="8" x="12" y="9" rx="2"/></g></svg>
\ No newline at end of file
index d404874..7a0c7e0 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>feedback</title><path d="M1 3l17 4c.6.7 1 1.6 1 2.5 0 .9-.4 1.8-1 2.5L1 16V3z"/><rect width="4" height="8" x="12" y="9" rx="2"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>feedback</title><path d="M18 7c.6.7 1 1.6 1 2.5 0 .9-.4 1.8-1 2.5L1 16V3z"/><rect width="4" height="8" x="12" y="9" rx="2"/></svg>
\ No newline at end of file
index e7fa1a9..a19df35 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>flag</title><path fill="#fff" d="M17 6L3 1v18h2v-6.87L17 6z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>flag</title><path fill="#fff" d="M17 6L3 1v18h2v-6.87z"/></svg>
\ No newline at end of file
index dd98fc6..2e1a8c1 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>flag</title><path fill="#36c" d="M17 6L3 1v18h2v-6.87L17 6z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>flag</title><path fill="#36c" d="M17 6L3 1v18h2v-6.87z"/></svg>
\ No newline at end of file
index d19bed5..e900492 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>flag</title><path d="M17 6L3 1v18h2v-6.87L17 6z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>flag</title><path d="M17 6L3 1v18h2v-6.87z"/></svg>
\ No newline at end of file
index dc80534..bbcc880 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>flag</title><path fill="#fff" d="M3 6l14-5v18h-2v-6.87L3 6z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>flag</title><path fill="#fff" d="M3 6l14-5v18h-2v-6.87z"/></svg>
\ No newline at end of file
index 4497644..53dd777 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>flag</title><path fill="#36c" d="M3 6l14-5v18h-2v-6.87L3 6z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>flag</title><path fill="#36c" d="M3 6l14-5v18h-2v-6.87z"/></svg>
\ No newline at end of file
index a58bb92..9851df4 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>flag</title><path d="M3 6l14-5v18h-2v-6.87L3 6z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>flag</title><path d="M3 6l14-5v18h-2v-6.87z"/></svg>
\ No newline at end of file
index 4974680..a8417e4 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-ltr-invert.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-ltr-invert.png differ
index b98beb1..2f851c9 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>folder placeholder</title><path fill="#fff" d="M8 2H2C.9 2 0 2.9 0 4v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2h-8L8 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>folder placeholder</title><g fill="#fff"><path d="M8 2H2a2 2 0 0 0-2 2v2h12z"/><rect width="20" height="14" y="4" rx="2"/></g></svg>
\ No newline at end of file
index b963fe8..a9ee109 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-ltr-progressive.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-ltr-progressive.png differ
index 8c89d06..a5a6dab 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>folder placeholder</title><path fill="#36c" d="M8 2H2C.9 2 0 2.9 0 4v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2h-8L8 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>folder placeholder</title><g fill="#36c"><path d="M8 2H2a2 2 0 0 0-2 2v2h12z"/><rect width="20" height="14" y="4" rx="2"/></g></svg>
\ No newline at end of file
index aa92b98..58178a5 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-ltr.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-ltr.png differ
index 6ebe28e..5bea197 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>folder placeholder</title><path d="M8 2H2C.9 2 0 2.9 0 4v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2h-8L8 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>folder placeholder</title><path d="M8 2H2a2 2 0 0 0-2 2v2h12z"/><rect width="20" height="14" y="4" rx="2"/></svg>
\ No newline at end of file
index a886573..6af8060 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-rtl-invert.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-rtl-invert.png differ
index 5887d6d..3a1bbad 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>folder placeholder</title><path fill="#fff" d="M10 4H2C.9 4 0 4.9 0 6v10c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2h-6l-2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>folder placeholder</title><g fill="#fff"><path d="M8 6h12V4a2 2 0 0 0-2-2h-6z"/><rect width="20" height="14" y="4" rx="2"/></g></svg>
\ No newline at end of file
index 7667dc5..6003746 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-rtl-progressive.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-rtl-progressive.png differ
index 3634463..59a2928 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>folder placeholder</title><path fill="#36c" d="M10 4H2C.9 4 0 4.9 0 6v10c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2h-6l-2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>folder placeholder</title><g fill="#36c"><path d="M8 6h12V4a2 2 0 0 0-2-2h-6z"/><rect width="20" height="14" y="4" rx="2"/></g></svg>
\ No newline at end of file
index c5cfd2b..e74c0f1 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-rtl.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/folderPlaceholder-rtl.png differ
index f92ef93..fceff11 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>folder placeholder</title><path d="M10 4H2C.9 4 0 4.9 0 6v10c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2h-6l-2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>folder placeholder</title><path d="M8 6h12V4a2 2 0 0 0-2-2h-6z"/><rect width="20" height="14" y="4" rx="2"/></svg>
\ No newline at end of file
index d1d2cc1..966f1d2 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>fullscreen</title><path fill="#fff" d="M1 1v6h2V3h4V1H1zm2 12H1v6h6v-2H3v-4zm14 4h-4v2h6v-6h-2v4zm0-16h-4v2h4v4h2V1h-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>fullscreen</title><path fill="#fff" d="M1 1v6h2V3h4V1zm2 12H1v6h6v-2H3zm14 4h-4v2h6v-6h-2zm0-16h-4v2h4v4h2V1z"/></svg>
\ No newline at end of file
index 68331db..3bc2142 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>fullscreen</title><path fill="#36c" d="M1 1v6h2V3h4V1H1zm2 12H1v6h6v-2H3v-4zm14 4h-4v2h6v-6h-2v4zm0-16h-4v2h4v4h2V1h-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>fullscreen</title><path fill="#36c" d="M1 1v6h2V3h4V1zm2 12H1v6h6v-2H3zm14 4h-4v2h6v-6h-2zm0-16h-4v2h4v4h2V1z"/></svg>
\ No newline at end of file
index ebb18a1..5981f5e 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>fullscreen</title><path d="M1 1v6h2V3h4V1H1zm2 12H1v6h6v-2H3v-4zm14 4h-4v2h6v-6h-2v4zm0-16h-4v2h4v4h2V1h-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>fullscreen</title><path d="M1 1v6h2V3h4V1zm2 12H1v6h6v-2H3zm14 4h-4v2h6v-6h-2zm0-16h-4v2h4v4h2V1z"/></svg>
\ No newline at end of file
index c14f604..7cf23e0 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>funnel</title><g fill="#fff"><path d="M10 13L1 1h18l-9 12z"/><path d="M12 9H8v8l4 2V9z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>funnel</title><g fill="#fff"><path d="M10 13L1 1h18z"/><path d="M8 9v8l4 2V9z"/></g></svg>
\ No newline at end of file
index ec81fff..c2085da 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>funnel</title><g fill="#36c"><path d="M10 13L1 1h18l-9 12z"/><path d="M12 9H8v8l4 2V9z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>funnel</title><g fill="#36c"><path d="M10 13L1 1h18z"/><path d="M8 9v8l4 2V9z"/></g></svg>
\ No newline at end of file
index 52008ae..c0bbada 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>funnel</title><path d="M10 13L1 1h18l-9 12z"/><path d="M12 9H8v8l4 2V9z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>funnel</title><path d="M10 13L1 1h18z"/><path d="M8 9v8l4 2V9z"/></svg>
\ No newline at end of file
index aad5b35..e41c235 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>half bright</title><path fill="#fff" d="M.1 9.6L3 12.5V17h4.2l2.9 2.9L13 17h4v-4.5l2.9-2.9L17 6.7V3h-3.9L10.2.1 7.2 3H3v3.7L.1 9.6zm3.9 0c.1-3.3 2.7-5.9 6-6v12c-3.3-.1-5.9-2.7-6-6z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>half bright</title><path fill="#fff" d="M.1 9.6L3 12.5V17h4.2l2.9 2.9L13 17h4v-4.5l2.9-2.9L17 6.7V3h-3.9L10.2.1 7.2 3H3v3.7zm3.9 0c.1-3.3 2.7-5.9 6-6v12c-3.3-.1-5.9-2.7-6-6z"/></svg>
\ No newline at end of file
index 4d676aa..ef1a55b 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>half bright</title><path fill="#36c" d="M.1 9.6L3 12.5V17h4.2l2.9 2.9L13 17h4v-4.5l2.9-2.9L17 6.7V3h-3.9L10.2.1 7.2 3H3v3.7L.1 9.6zm3.9 0c.1-3.3 2.7-5.9 6-6v12c-3.3-.1-5.9-2.7-6-6z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>half bright</title><path fill="#36c" d="M.1 9.6L3 12.5V17h4.2l2.9 2.9L13 17h4v-4.5l2.9-2.9L17 6.7V3h-3.9L10.2.1 7.2 3H3v3.7zm3.9 0c.1-3.3 2.7-5.9 6-6v12c-3.3-.1-5.9-2.7-6-6z"/></svg>
\ No newline at end of file
index 59a010a..4664802 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>half bright</title><path d="M.1 9.6L3 12.5V17h4.2l2.9 2.9L13 17h4v-4.5l2.9-2.9L17 6.7V3h-3.9L10.2.1 7.2 3H3v3.7L.1 9.6zm3.9 0c.1-3.3 2.7-5.9 6-6v12c-3.3-.1-5.9-2.7-6-6z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>half bright</title><path d="M.1 9.6L3 12.5V17h4.2l2.9 2.9L13 17h4v-4.5l2.9-2.9L17 6.7V3h-3.9L10.2.1 7.2 3H3v3.7zm3.9 0c.1-3.3 2.7-5.9 6-6v12c-3.3-.1-5.9-2.7-6-6z"/></svg>
\ No newline at end of file
index 2ab3c41..d6e6c47 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>half star</title><path fill="#fff" d="M5.4 12.5l-1.6 7 6.2-3.7 6.2 3.7-1.6-7L20 7h-7L10 .5 7 7H0l5.4 5.5zm.8 3.7l1-4.3-3.7-3.4h4.6L10 4.6v9.3l-3.8 2.3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>half star</title><path fill="#fff" d="M5.4 12.5l-1.6 7 6.2-3.7 6.2 3.7-1.6-7L20 7h-7L10 .5 7 7H0zm.8 3.7l1-4.3-3.7-3.4h4.6L10 4.6v9.3z"/></svg>
\ No newline at end of file
index 2c535a9..d5227a8 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>half star</title><path fill="#36c" d="M5.4 12.5l-1.6 7 6.2-3.7 6.2 3.7-1.6-7L20 7h-7L10 .5 7 7H0l5.4 5.5zm.8 3.7l1-4.3-3.7-3.4h4.6L10 4.6v9.3l-3.8 2.3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>half star</title><path fill="#36c" d="M5.4 12.5l-1.6 7 6.2-3.7 6.2 3.7-1.6-7L20 7h-7L10 .5 7 7H0zm.8 3.7l1-4.3-3.7-3.4h4.6L10 4.6v9.3z"/></svg>
\ No newline at end of file
index d6bdfbb..2e87ef3 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>half star</title><path d="M5.4 12.5l-1.6 7 6.2-3.7 6.2 3.7-1.6-7L20 7h-7L10 .5 7 7H0l5.4 5.5zm.8 3.7l1-4.3-3.7-3.4h4.6L10 4.6v9.3l-3.8 2.3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>half star</title><path d="M5.4 12.5l-1.6 7 6.2-3.7 6.2 3.7-1.6-7L20 7h-7L10 .5 7 7H0zm.8 3.7l1-4.3-3.7-3.4h4.6L10 4.6v9.3z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-ltr-invert.png b/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-ltr-invert.png
new file mode 100644 (file)
index 0000000..d1ec002
Binary files /dev/null and b/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-ltr-invert.png differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-ltr-invert.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-ltr-invert.svg
new file mode 100644 (file)
index 0000000..a350188
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>help</title><path d="M10 0a10 10 0 1 0 10 10A10 10 0 0 0 10 0zm1 16H9v-2h2zm2.71-7.6a2.64 2.64 0 0 1-.33.74 3.16 3.16 0 0 1-.48.55l-.54.48c-.21.18-.41.35-.58.52a2.54 2.54 0 0 0-.47.56A2.3 2.3 0 0 0 11 12a3.79 3.79 0 0 0-.11 1H9.08a8.9 8.9 0 0 1 .07-1.25 3.28 3.28 0 0 1 .25-.9 2.79 2.79 0 0 1 .41-.67 4 4 0 0 1 .58-.58c.17-.16.34-.3.51-.44a3 3 0 0 0 .43-.44 1.83 1.83 0 0 0 .3-.55 2 2 0 0 0 .11-.72 2.06 2.06 0 0 0-.17-.86 1.71 1.71 0 0 0-1-.9 1.7 1.7 0 0 0-.5-.1 1.77 1.77 0 0 0-1.53.68 3 3 0 0 0-.5 1.82H6.16a4.74 4.74 0 0 1 .28-1.68 3.56 3.56 0 0 1 .8-1.29 3.88 3.88 0 0 1 1.28-.83A4.59 4.59 0 0 1 10.18 4a4.44 4.44 0 0 1 1.44.23 3.51 3.51 0 0 1 1.15.65 3.08 3.08 0 0 1 .78 1.06 3.54 3.54 0 0 1 .29 1.45 3.39 3.39 0 0 1-.13 1.01z"/></g></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-ltr-progressive.png b/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-ltr-progressive.png
new file mode 100644 (file)
index 0000000..eaa1be9
Binary files /dev/null and b/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-ltr-progressive.png differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-ltr-progressive.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-ltr-progressive.svg
new file mode 100644 (file)
index 0000000..73fe34c
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>help</title><path d="M10 0a10 10 0 1 0 10 10A10 10 0 0 0 10 0zm1 16H9v-2h2zm2.71-7.6a2.64 2.64 0 0 1-.33.74 3.16 3.16 0 0 1-.48.55l-.54.48c-.21.18-.41.35-.58.52a2.54 2.54 0 0 0-.47.56A2.3 2.3 0 0 0 11 12a3.79 3.79 0 0 0-.11 1H9.08a8.9 8.9 0 0 1 .07-1.25 3.28 3.28 0 0 1 .25-.9 2.79 2.79 0 0 1 .41-.67 4 4 0 0 1 .58-.58c.17-.16.34-.3.51-.44a3 3 0 0 0 .43-.44 1.83 1.83 0 0 0 .3-.55 2 2 0 0 0 .11-.72 2.06 2.06 0 0 0-.17-.86 1.71 1.71 0 0 0-1-.9 1.7 1.7 0 0 0-.5-.1 1.77 1.77 0 0 0-1.53.68 3 3 0 0 0-.5 1.82H6.16a4.74 4.74 0 0 1 .28-1.68 3.56 3.56 0 0 1 .8-1.29 3.88 3.88 0 0 1 1.28-.83A4.59 4.59 0 0 1 10.18 4a4.44 4.44 0 0 1 1.44.23 3.51 3.51 0 0 1 1.15.65 3.08 3.08 0 0 1 .78 1.06 3.54 3.54 0 0 1 .29 1.45 3.39 3.39 0 0 1-.13 1.01z"/></g></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-ltr.png b/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-ltr.png
new file mode 100644 (file)
index 0000000..3ac0da5
Binary files /dev/null and b/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-ltr.png differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-ltr.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-ltr.svg
new file mode 100644 (file)
index 0000000..807cb84
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>help</title><path d="M10 0a10 10 0 1 0 10 10A10 10 0 0 0 10 0zm1 16H9v-2h2zm2.71-7.6a2.64 2.64 0 0 1-.33.74 3.16 3.16 0 0 1-.48.55l-.54.48c-.21.18-.41.35-.58.52a2.54 2.54 0 0 0-.47.56A2.3 2.3 0 0 0 11 12a3.79 3.79 0 0 0-.11 1H9.08a8.9 8.9 0 0 1 .07-1.25 3.28 3.28 0 0 1 .25-.9 2.79 2.79 0 0 1 .41-.67 4 4 0 0 1 .58-.58c.17-.16.34-.3.51-.44a3 3 0 0 0 .43-.44 1.83 1.83 0 0 0 .3-.55 2 2 0 0 0 .11-.72 2.06 2.06 0 0 0-.17-.86 1.71 1.71 0 0 0-1-.9 1.7 1.7 0 0 0-.5-.1 1.77 1.77 0 0 0-1.53.68 3 3 0 0 0-.5 1.82H6.16a4.74 4.74 0 0 1 .28-1.68 3.56 3.56 0 0 1 .8-1.29 3.88 3.88 0 0 1 1.28-.83A4.59 4.59 0 0 1 10.18 4a4.44 4.44 0 0 1 1.44.23 3.51 3.51 0 0 1 1.15.65 3.08 3.08 0 0 1 .78 1.06 3.54 3.54 0 0 1 .29 1.45 3.39 3.39 0 0 1-.13 1.01z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-rtl-invert.png b/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-rtl-invert.png
new file mode 100644 (file)
index 0000000..2459a4c
Binary files /dev/null and b/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-rtl-invert.png differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-rtl-invert.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-rtl-invert.svg
new file mode 100644 (file)
index 0000000..9f79d18
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>help</title><path fill="#fff" d="M0 10A10 10 0 1 0 10 0 10 10 0 0 0 0 10zm9 4h2v2H9zM6.16 7.39a3.54 3.54 0 0 1 .29-1.45 3.08 3.08 0 0 1 .78-1.06 3.51 3.51 0 0 1 1.15-.65A4.44 4.44 0 0 1 9.82 4a4.59 4.59 0 0 1 1.66.29 3.88 3.88 0 0 1 1.28.83 3.56 3.56 0 0 1 .8 1.29 4.74 4.74 0 0 1 .28 1.68h-1.91a3 3 0 0 0-.5-1.82 1.77 1.77 0 0 0-1.53-.68 1.7 1.7 0 0 0-.5.1 1.71 1.71 0 0 0-1 .9 2.06 2.06 0 0 0-.17.86 2 2 0 0 0 .11.72 1.83 1.83 0 0 0 .3.55 3 3 0 0 0 .43.44c.17.14.34.28.51.44a4 4 0 0 1 .58.58 2.79 2.79 0 0 1 .41.67 3.28 3.28 0 0 1 .25.9 8.9 8.9 0 0 1 .1 1.25H9.11A3.79 3.79 0 0 0 9 12a2.3 2.3 0 0 0-.31-.73 2.54 2.54 0 0 0-.47-.56c-.17-.17-.37-.34-.58-.52l-.54-.5a3.16 3.16 0 0 1-.48-.55 2.64 2.64 0 0 1-.33-.74 3.39 3.39 0 0 1-.13-1.01z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-rtl-progressive.png b/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-rtl-progressive.png
new file mode 100644 (file)
index 0000000..e1dc9f7
Binary files /dev/null and b/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-rtl-progressive.png differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-rtl-progressive.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-rtl-progressive.svg
new file mode 100644 (file)
index 0000000..f71e0be
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>help</title><path fill="#36c" d="M0 10A10 10 0 1 0 10 0 10 10 0 0 0 0 10zm9 4h2v2H9zM6.16 7.39a3.54 3.54 0 0 1 .29-1.45 3.08 3.08 0 0 1 .78-1.06 3.51 3.51 0 0 1 1.15-.65A4.44 4.44 0 0 1 9.82 4a4.59 4.59 0 0 1 1.66.29 3.88 3.88 0 0 1 1.28.83 3.56 3.56 0 0 1 .8 1.29 4.74 4.74 0 0 1 .28 1.68h-1.91a3 3 0 0 0-.5-1.82 1.77 1.77 0 0 0-1.53-.68 1.7 1.7 0 0 0-.5.1 1.71 1.71 0 0 0-1 .9 2.06 2.06 0 0 0-.17.86 2 2 0 0 0 .11.72 1.83 1.83 0 0 0 .3.55 3 3 0 0 0 .43.44c.17.14.34.28.51.44a4 4 0 0 1 .58.58 2.79 2.79 0 0 1 .41.67 3.28 3.28 0 0 1 .25.9 8.9 8.9 0 0 1 .1 1.25H9.11A3.79 3.79 0 0 0 9 12a2.3 2.3 0 0 0-.31-.73 2.54 2.54 0 0 0-.47-.56c-.17-.17-.37-.34-.58-.52l-.54-.5a3.16 3.16 0 0 1-.48-.55 2.64 2.64 0 0 1-.33-.74 3.39 3.39 0 0 1-.13-1.01z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-rtl.png b/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-rtl.png
new file mode 100644 (file)
index 0000000..e60b61a
Binary files /dev/null and b/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-rtl.png differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-rtl.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/helpNotice-rtl.svg
new file mode 100644 (file)
index 0000000..7e400cb
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>help</title><path d="M0 10A10 10 0 1 0 10 0 10 10 0 0 0 0 10zm9 4h2v2H9zM6.16 7.39a3.54 3.54 0 0 1 .29-1.45 3.08 3.08 0 0 1 .78-1.06 3.51 3.51 0 0 1 1.15-.65A4.44 4.44 0 0 1 9.82 4a4.59 4.59 0 0 1 1.66.29 3.88 3.88 0 0 1 1.28.83 3.56 3.56 0 0 1 .8 1.29 4.74 4.74 0 0 1 .28 1.68h-1.91a3 3 0 0 0-.5-1.82 1.77 1.77 0 0 0-1.53-.68 1.7 1.7 0 0 0-.5.1 1.71 1.71 0 0 0-1 .9 2.06 2.06 0 0 0-.17.86 2 2 0 0 0 .11.72 1.83 1.83 0 0 0 .3.55 3 3 0 0 0 .43.44c.17.14.34.28.51.44a4 4 0 0 1 .58.58 2.79 2.79 0 0 1 .41.67 3.28 3.28 0 0 1 .25.9 8.9 8.9 0 0 1 .1 1.25H9.11A3.79 3.79 0 0 0 9 12a2.3 2.3 0 0 0-.31-.73 2.54 2.54 0 0 0-.47-.56c-.17-.17-.37-.34-.58-.52l-.54-.5a3.16 3.16 0 0 1-.48-.55 2.64 2.64 0 0 1-.33-.74 3.39 3.39 0 0 1-.13-1.01z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-ltr-invert.png b/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-ltr-invert.png
deleted file mode 100644 (file)
index d1ec002..0000000
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-ltr-invert.png and /dev/null differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-ltr-invert.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-ltr-invert.svg
deleted file mode 100644 (file)
index a350188..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>help</title><path d="M10 0a10 10 0 1 0 10 10A10 10 0 0 0 10 0zm1 16H9v-2h2zm2.71-7.6a2.64 2.64 0 0 1-.33.74 3.16 3.16 0 0 1-.48.55l-.54.48c-.21.18-.41.35-.58.52a2.54 2.54 0 0 0-.47.56A2.3 2.3 0 0 0 11 12a3.79 3.79 0 0 0-.11 1H9.08a8.9 8.9 0 0 1 .07-1.25 3.28 3.28 0 0 1 .25-.9 2.79 2.79 0 0 1 .41-.67 4 4 0 0 1 .58-.58c.17-.16.34-.3.51-.44a3 3 0 0 0 .43-.44 1.83 1.83 0 0 0 .3-.55 2 2 0 0 0 .11-.72 2.06 2.06 0 0 0-.17-.86 1.71 1.71 0 0 0-1-.9 1.7 1.7 0 0 0-.5-.1 1.77 1.77 0 0 0-1.53.68 3 3 0 0 0-.5 1.82H6.16a4.74 4.74 0 0 1 .28-1.68 3.56 3.56 0 0 1 .8-1.29 3.88 3.88 0 0 1 1.28-.83A4.59 4.59 0 0 1 10.18 4a4.44 4.44 0 0 1 1.44.23 3.51 3.51 0 0 1 1.15.65 3.08 3.08 0 0 1 .78 1.06 3.54 3.54 0 0 1 .29 1.45 3.39 3.39 0 0 1-.13 1.01z"/></g></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-ltr-progressive.png b/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-ltr-progressive.png
deleted file mode 100644 (file)
index eaa1be9..0000000
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-ltr-progressive.png and /dev/null differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-ltr-progressive.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-ltr-progressive.svg
deleted file mode 100644 (file)
index 73fe34c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>help</title><path d="M10 0a10 10 0 1 0 10 10A10 10 0 0 0 10 0zm1 16H9v-2h2zm2.71-7.6a2.64 2.64 0 0 1-.33.74 3.16 3.16 0 0 1-.48.55l-.54.48c-.21.18-.41.35-.58.52a2.54 2.54 0 0 0-.47.56A2.3 2.3 0 0 0 11 12a3.79 3.79 0 0 0-.11 1H9.08a8.9 8.9 0 0 1 .07-1.25 3.28 3.28 0 0 1 .25-.9 2.79 2.79 0 0 1 .41-.67 4 4 0 0 1 .58-.58c.17-.16.34-.3.51-.44a3 3 0 0 0 .43-.44 1.83 1.83 0 0 0 .3-.55 2 2 0 0 0 .11-.72 2.06 2.06 0 0 0-.17-.86 1.71 1.71 0 0 0-1-.9 1.7 1.7 0 0 0-.5-.1 1.77 1.77 0 0 0-1.53.68 3 3 0 0 0-.5 1.82H6.16a4.74 4.74 0 0 1 .28-1.68 3.56 3.56 0 0 1 .8-1.29 3.88 3.88 0 0 1 1.28-.83A4.59 4.59 0 0 1 10.18 4a4.44 4.44 0 0 1 1.44.23 3.51 3.51 0 0 1 1.15.65 3.08 3.08 0 0 1 .78 1.06 3.54 3.54 0 0 1 .29 1.45 3.39 3.39 0 0 1-.13 1.01z"/></g></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-ltr.png b/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-ltr.png
deleted file mode 100644 (file)
index 3ac0da5..0000000
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-ltr.png and /dev/null differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-ltr.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-ltr.svg
deleted file mode 100644 (file)
index 807cb84..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>help</title><path d="M10 0a10 10 0 1 0 10 10A10 10 0 0 0 10 0zm1 16H9v-2h2zm2.71-7.6a2.64 2.64 0 0 1-.33.74 3.16 3.16 0 0 1-.48.55l-.54.48c-.21.18-.41.35-.58.52a2.54 2.54 0 0 0-.47.56A2.3 2.3 0 0 0 11 12a3.79 3.79 0 0 0-.11 1H9.08a8.9 8.9 0 0 1 .07-1.25 3.28 3.28 0 0 1 .25-.9 2.79 2.79 0 0 1 .41-.67 4 4 0 0 1 .58-.58c.17-.16.34-.3.51-.44a3 3 0 0 0 .43-.44 1.83 1.83 0 0 0 .3-.55 2 2 0 0 0 .11-.72 2.06 2.06 0 0 0-.17-.86 1.71 1.71 0 0 0-1-.9 1.7 1.7 0 0 0-.5-.1 1.77 1.77 0 0 0-1.53.68 3 3 0 0 0-.5 1.82H6.16a4.74 4.74 0 0 1 .28-1.68 3.56 3.56 0 0 1 .8-1.29 3.88 3.88 0 0 1 1.28-.83A4.59 4.59 0 0 1 10.18 4a4.44 4.44 0 0 1 1.44.23 3.51 3.51 0 0 1 1.15.65 3.08 3.08 0 0 1 .78 1.06 3.54 3.54 0 0 1 .29 1.45 3.39 3.39 0 0 1-.13 1.01z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-rtl-invert.png b/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-rtl-invert.png
deleted file mode 100644 (file)
index 2459a4c..0000000
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-rtl-invert.png and /dev/null differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-rtl-invert.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-rtl-invert.svg
deleted file mode 100644 (file)
index 9f79d18..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>help</title><path fill="#fff" d="M0 10A10 10 0 1 0 10 0 10 10 0 0 0 0 10zm9 4h2v2H9zM6.16 7.39a3.54 3.54 0 0 1 .29-1.45 3.08 3.08 0 0 1 .78-1.06 3.51 3.51 0 0 1 1.15-.65A4.44 4.44 0 0 1 9.82 4a4.59 4.59 0 0 1 1.66.29 3.88 3.88 0 0 1 1.28.83 3.56 3.56 0 0 1 .8 1.29 4.74 4.74 0 0 1 .28 1.68h-1.91a3 3 0 0 0-.5-1.82 1.77 1.77 0 0 0-1.53-.68 1.7 1.7 0 0 0-.5.1 1.71 1.71 0 0 0-1 .9 2.06 2.06 0 0 0-.17.86 2 2 0 0 0 .11.72 1.83 1.83 0 0 0 .3.55 3 3 0 0 0 .43.44c.17.14.34.28.51.44a4 4 0 0 1 .58.58 2.79 2.79 0 0 1 .41.67 3.28 3.28 0 0 1 .25.9 8.9 8.9 0 0 1 .1 1.25H9.11A3.79 3.79 0 0 0 9 12a2.3 2.3 0 0 0-.31-.73 2.54 2.54 0 0 0-.47-.56c-.17-.17-.37-.34-.58-.52l-.54-.5a3.16 3.16 0 0 1-.48-.55 2.64 2.64 0 0 1-.33-.74 3.39 3.39 0 0 1-.13-1.01z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-rtl-progressive.png b/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-rtl-progressive.png
deleted file mode 100644 (file)
index e1dc9f7..0000000
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-rtl-progressive.png and /dev/null differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-rtl-progressive.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-rtl-progressive.svg
deleted file mode 100644 (file)
index f71e0be..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>help</title><path fill="#36c" d="M0 10A10 10 0 1 0 10 0 10 10 0 0 0 0 10zm9 4h2v2H9zM6.16 7.39a3.54 3.54 0 0 1 .29-1.45 3.08 3.08 0 0 1 .78-1.06 3.51 3.51 0 0 1 1.15-.65A4.44 4.44 0 0 1 9.82 4a4.59 4.59 0 0 1 1.66.29 3.88 3.88 0 0 1 1.28.83 3.56 3.56 0 0 1 .8 1.29 4.74 4.74 0 0 1 .28 1.68h-1.91a3 3 0 0 0-.5-1.82 1.77 1.77 0 0 0-1.53-.68 1.7 1.7 0 0 0-.5.1 1.71 1.71 0 0 0-1 .9 2.06 2.06 0 0 0-.17.86 2 2 0 0 0 .11.72 1.83 1.83 0 0 0 .3.55 3 3 0 0 0 .43.44c.17.14.34.28.51.44a4 4 0 0 1 .58.58 2.79 2.79 0 0 1 .41.67 3.28 3.28 0 0 1 .25.9 8.9 8.9 0 0 1 .1 1.25H9.11A3.79 3.79 0 0 0 9 12a2.3 2.3 0 0 0-.31-.73 2.54 2.54 0 0 0-.47-.56c-.17-.17-.37-.34-.58-.52l-.54-.5a3.16 3.16 0 0 1-.48-.55 2.64 2.64 0 0 1-.33-.74 3.39 3.39 0 0 1-.13-1.01z"/></svg>
\ No newline at end of file
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-rtl.png b/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-rtl.png
deleted file mode 100644 (file)
index e60b61a..0000000
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-rtl.png and /dev/null differ
diff --git a/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-rtl.svg b/resources/lib/ooui/themes/wikimediaui/images/icons/helpOutlined-rtl.svg
deleted file mode 100644 (file)
index 7e400cb..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>help</title><path d="M0 10A10 10 0 1 0 10 0 10 10 0 0 0 0 10zm9 4h2v2H9zM6.16 7.39a3.54 3.54 0 0 1 .29-1.45 3.08 3.08 0 0 1 .78-1.06 3.51 3.51 0 0 1 1.15-.65A4.44 4.44 0 0 1 9.82 4a4.59 4.59 0 0 1 1.66.29 3.88 3.88 0 0 1 1.28.83 3.56 3.56 0 0 1 .8 1.29 4.74 4.74 0 0 1 .28 1.68h-1.91a3 3 0 0 0-.5-1.82 1.77 1.77 0 0 0-1.53-.68 1.7 1.7 0 0 0-.5.1 1.71 1.71 0 0 0-1 .9 2.06 2.06 0 0 0-.17.86 2 2 0 0 0 .11.72 1.83 1.83 0 0 0 .3.55 3 3 0 0 0 .43.44c.17.14.34.28.51.44a4 4 0 0 1 .58.58 2.79 2.79 0 0 1 .41.67 3.28 3.28 0 0 1 .25.9 8.9 8.9 0 0 1 .1 1.25H9.11A3.79 3.79 0 0 0 9 12a2.3 2.3 0 0 0-.31-.73 2.54 2.54 0 0 0-.47-.56c-.17-.17-.37-.34-.58-.52l-.54-.5a3.16 3.16 0 0 1-.48-.55 2.64 2.64 0 0 1-.33-.74 3.39 3.39 0 0 1-.13-1.01z"/></svg>
\ No newline at end of file
index eade031..874d401 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>highlight</title><path fill="#fff" d="M18.73 5.86l-3.59-3.59a1 1 0 0 0-1.41 0l-10 10a1 1 0 0 0 0 1.41L4 14l-3 4h5l1-1 .29.29a1 1 0 0 0 1.41 0l10-10a1 1 0 0 0 .03-1.43zM7 15l-2-2 9-9 2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>highlight</title><path fill="#fff" d="M15.14 2.27a1 1 0 0 0-1.41 0l-10 10a1 1 0 0 0 0 1.41L4 14l-3 4h5l1-1 .29.29a1 1 0 0 0 1.41 0l10-10a1 1 0 0 0 .03-1.43zM7 15l-2-2 9-9 2 2z"/></svg>
\ No newline at end of file
index 57f0199..94d6bcc 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>highlight</title><path fill="#36c" d="M18.73 5.86l-3.59-3.59a1 1 0 0 0-1.41 0l-10 10a1 1 0 0 0 0 1.41L4 14l-3 4h5l1-1 .29.29a1 1 0 0 0 1.41 0l10-10a1 1 0 0 0 .03-1.43zM7 15l-2-2 9-9 2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>highlight</title><path fill="#36c" d="M15.14 2.27a1 1 0 0 0-1.41 0l-10 10a1 1 0 0 0 0 1.41L4 14l-3 4h5l1-1 .29.29a1 1 0 0 0 1.41 0l10-10a1 1 0 0 0 .03-1.43zM7 15l-2-2 9-9 2 2z"/></svg>
\ No newline at end of file
index 17774d2..331785d 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>highlight</title><path d="M18.73 5.86l-3.59-3.59a1 1 0 0 0-1.41 0l-10 10a1 1 0 0 0 0 1.41L4 14l-3 4h5l1-1 .29.29a1 1 0 0 0 1.41 0l10-10a1 1 0 0 0 .03-1.43zM7 15l-2-2 9-9 2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>highlight</title><path d="M15.14 2.27a1 1 0 0 0-1.41 0l-10 10a1 1 0 0 0 0 1.41L4 14l-3 4h5l1-1 .29.29a1 1 0 0 0 1.41 0l10-10a1 1 0 0 0 .03-1.43zM7 15l-2-2 9-9 2 2z"/></svg>
\ No newline at end of file
index 7728c43..b8d4522 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>history</title><g fill="#fff"><path d="M9 6v5h.06l2.48 2.47 1.41-1.41L11 10.11V6H9z"/><path d="M10 1a9 9 0 0 0-7.85 13.35L.5 16H6v-5.5l-2.38 2.38A7 7 0 1 1 10 17v2a9 9 0 0 0 0-18z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>history</title><g fill="#fff"><path d="M9 6v5h.06l2.48 2.47 1.41-1.41L11 10.11V6z"/><path d="M10 1a9 9 0 0 0-7.85 13.35L.5 16H6v-5.5l-2.38 2.38A7 7 0 1 1 10 17v2a9 9 0 0 0 0-18z"/></g></svg>
\ No newline at end of file
index 576e55f..9bbe3bd 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>history</title><g fill="#36c"><path d="M9 6v5h.06l2.48 2.47 1.41-1.41L11 10.11V6H9z"/><path d="M10 1a9 9 0 0 0-7.85 13.35L.5 16H6v-5.5l-2.38 2.38A7 7 0 1 1 10 17v2a9 9 0 0 0 0-18z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>history</title><g fill="#36c"><path d="M9 6v5h.06l2.48 2.47 1.41-1.41L11 10.11V6z"/><path d="M10 1a9 9 0 0 0-7.85 13.35L.5 16H6v-5.5l-2.38 2.38A7 7 0 1 1 10 17v2a9 9 0 0 0 0-18z"/></g></svg>
\ No newline at end of file
index 48a8b29..c2844cf 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>history</title><path d="M9 6v5h.06l2.48 2.47 1.41-1.41L11 10.11V6H9z"/><path d="M10 1a9 9 0 0 0-7.85 13.35L.5 16H6v-5.5l-2.38 2.38A7 7 0 1 1 10 17v2a9 9 0 0 0 0-18z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>history</title><path d="M9 6v5h.06l2.48 2.47 1.41-1.41L11 10.11V6z"/><path d="M10 1a9 9 0 0 0-7.85 13.35L.5 16H6v-5.5l-2.38 2.38A7 7 0 1 1 10 17v2a9 9 0 0 0 0-18z"/></svg>
\ No newline at end of file
index edc3401..1d3fc52 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image</title><path fill="#fff" d="M18 2H2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zM1.83 15l4.09-5.25 2.92 3.51L12.92 8l5.25 7z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image</title><path fill="#fff" d="M2 2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm-.17 13l4.09-5.25 2.92 3.51L12.92 8l5.25 7z"/></svg>
\ No newline at end of file
index 40d8f4e..b004eff 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image</title><path fill="#36c" d="M18 2H2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zM1.83 15l4.09-5.25 2.92 3.51L12.92 8l5.25 7z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image</title><path fill="#36c" d="M2 2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm-.17 13l4.09-5.25 2.92 3.51L12.92 8l5.25 7z"/></svg>
\ No newline at end of file
index 32f2476..a33fab2 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image</title><path d="M18 2H2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zM1.83 15l4.09-5.25 2.92 3.51L12.92 8l5.25 7z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image</title><path d="M2 2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm-.17 13l4.09-5.25 2.92 3.51L12.92 8l5.25 7z"/></svg>
\ No newline at end of file
index a9d0f21..7467e6c 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add image</title><g fill="#fff"><path d="M16 17H2l3.5-4.5 2.5 3 3.5-4.5.5.67V8H8V6H2a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-6h-5.75z"/><path d="M16 4V0h-2v4h-4v2h4v4h2V6h4V4h-4z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add image</title><g fill="#fff"><path d="M16 17H2l3.5-4.5 2.5 3 3.5-4.5.5.67V8H8V6H2a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-6h-5.75z"/><path d="M16 4V0h-2v4h-4v2h4v4h2V6h4V4z"/></g></svg>
\ No newline at end of file
index 06015ed..9ecbb76 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add image</title><g fill="#36c"><path d="M16 17H2l3.5-4.5 2.5 3 3.5-4.5.5.67V8H8V6H2a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-6h-5.75z"/><path d="M16 4V0h-2v4h-4v2h4v4h2V6h4V4h-4z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add image</title><g fill="#36c"><path d="M16 17H2l3.5-4.5 2.5 3 3.5-4.5.5.67V8H8V6H2a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-6h-5.75z"/><path d="M16 4V0h-2v4h-4v2h4v4h2V6h4V4z"/></g></svg>
\ No newline at end of file
index 7a3bf7a..6f764dc 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add image</title><path d="M16 17H2l3.5-4.5 2.5 3 3.5-4.5.5.67V8H8V6H2a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-6h-5.75z"/><path d="M16 4V0h-2v4h-4v2h4v4h2V6h4V4h-4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add image</title><path d="M16 17H2l3.5-4.5 2.5 3 3.5-4.5.5.67V8H8V6H2a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-6h-5.75z"/><path d="M16 4V0h-2v4h-4v2h4v4h2V6h4V4z"/></svg>
\ No newline at end of file
index 4ade668..2dda10d 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add image</title><path fill="#fff" d="M18 6h-6v2H8v4H2v6a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2zM3.83 17l3.55-4.5 2.52 3 3.55-4.5L18 17zM4 10h2V6h4V4H6V0H4v4H0v2h4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add image</title><path fill="#fff" d="M16v2H8v4H2v6a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2zM3.83 17l3.55-4.5 2.52 3 3.55-4.5L18 17zM4 10h2V6h4V4H6V0H4v4H0v2h4z"/></svg>
\ No newline at end of file
index a9fd6a8..d83a180 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add image</title><path fill="#36c" d="M18 6h-6v2H8v4H2v6a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2zM3.83 17l3.55-4.5 2.52 3 3.55-4.5L18 17zM4 10h2V6h4V4H6V0H4v4H0v2h4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add image</title><path fill="#36c" d="M16v2H8v4H2v6a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2zM3.83 17l3.55-4.5 2.52 3 3.55-4.5L18 17zM4 10h2V6h4V4H6V0H4v4H0v2h4z"/></svg>
\ No newline at end of file
index a7ded5c..ee49dff 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add image</title><path d="M18 6h-6v2H8v4H2v6a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2zM3.83 17l3.55-4.5 2.52 3 3.55-4.5L18 17zM4 10h2V6h4V4H6V0H4v4H0v2h4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add image</title><path d="M16v2H8v4H2v6a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2zM3.83 17l3.55-4.5 2.52 3 3.55-4.5L18 17zM4 10h2V6h4V4H6V0H4v4H0v2h4z"/></svg>
\ No newline at end of file
index 1a8b459..e145fcc 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>broken image</title><g fill="#fff"><path d="M16.67 9.47L20 12.13v4.09A2 2 0 0 1 17.78 18H2.22A2 2 0 0 1 0 16.22v-5.86L3.33 13l4.45-3.53L12.22 13z"/><path d="M20 3.78v5.86L16.67 7l-4.44 3.56L7.78 7l-4.45 3.53L0 7.87V3.78A2 2 0 0 1 2.22 2h15.56A2 2 0 0 1 20 3.78z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>broken image</title><g fill="#fff"><path d="M16.67 9.47L20 12.13v4.09A2 2 0 0 1 17.78 18H2.22A2 2 0 0 1 0 16.22v-5.86L3.33 13l4.45-3.53L12.22 13z"/><path d="M20 9.64L16.67 7l-4.44 3.56L7.78 7l-4.45 3.53L0 7.87V3.78A2 2 0 0 1 2.22 2h15.56A2 2 0 0 1 20 3.78z"/></g></svg>
\ No newline at end of file
index d67fee5..2590e29 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>broken image</title><g fill="#36c"><path d="M16.67 9.47L20 12.13v4.09A2 2 0 0 1 17.78 18H2.22A2 2 0 0 1 0 16.22v-5.86L3.33 13l4.45-3.53L12.22 13z"/><path d="M20 3.78v5.86L16.67 7l-4.44 3.56L7.78 7l-4.45 3.53L0 7.87V3.78A2 2 0 0 1 2.22 2h15.56A2 2 0 0 1 20 3.78z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>broken image</title><g fill="#36c"><path d="M16.67 9.47L20 12.13v4.09A2 2 0 0 1 17.78 18H2.22A2 2 0 0 1 0 16.22v-5.86L3.33 13l4.45-3.53L12.22 13z"/><path d="M20 9.64L16.67 7l-4.44 3.56L7.78 7l-4.45 3.53L0 7.87V3.78A2 2 0 0 1 2.22 2h15.56A2 2 0 0 1 20 3.78z"/></g></svg>
\ No newline at end of file
index bae885b..83ea4bf 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>broken image</title><path d="M16.67 9.47L20 12.13v4.09A2 2 0 0 1 17.78 18H2.22A2 2 0 0 1 0 16.22v-5.86L3.33 13l4.45-3.53L12.22 13z"/><path d="M20 3.78v5.86L16.67 7l-4.44 3.56L7.78 7l-4.45 3.53L0 7.87V3.78A2 2 0 0 1 2.22 2h15.56A2 2 0 0 1 20 3.78z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>broken image</title><path d="M16.67 9.47L20 12.13v4.09A2 2 0 0 1 17.78 18H2.22A2 2 0 0 1 0 16.22v-5.86L3.33 13l4.45-3.53L12.22 13z"/><path d="M20 9.64L16.67 7l-4.44 3.56L7.78 7l-4.45 3.53L0 7.87V3.78A2 2 0 0 1 2.22 2h15.56A2 2 0 0 1 20 3.78z"/></svg>
\ No newline at end of file
index 9e737c0..5d4b87b 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image gallery</title><path fill="#fff" d="M17 5H3a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2zM3 16l3.5-4.5 2.5 3 3.5-4.5 4.5 6zM4 2h12a2 2 0 0 1 2 2H2a2 2 0 0 1 2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image gallery</title><path fill="#fff" d="M3 5a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2zm0 11l3.5-4.5 2.5 3 3.5-4.5 4.5 6zM16 2a2 2 0 0 1 2 2H2a2 2 0 0 1 2-2z"/></svg>
\ No newline at end of file
index bd6684a..f35a09e 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image gallery</title><path fill="#36c" d="M17 5H3a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2zM3 16l3.5-4.5 2.5 3 3.5-4.5 4.5 6zM4 2h12a2 2 0 0 1 2 2H2a2 2 0 0 1 2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image gallery</title><path fill="#36c" d="M3 5a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2zm0 11l3.5-4.5 2.5 3 3.5-4.5 4.5 6zM16 2a2 2 0 0 1 2 2H2a2 2 0 0 1 2-2z"/></svg>
\ No newline at end of file
index 29f9faa..8116eda 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image gallery</title><path d="M17 5H3a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2zM3 16l3.5-4.5 2.5 3 3.5-4.5 4.5 6zM4 2h12a2 2 0 0 1 2 2H2a2 2 0 0 1 2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image gallery</title><path d="M3 5a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2zm0 11l3.5-4.5 2.5 3 3.5-4.5 4.5 6zM16 2a2 2 0 0 1 2 2H2a2 2 0 0 1 2-2z"/></svg>
\ No newline at end of file
index 1c8b878..9698785 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout basic</title><g fill="#fff"><path d="M20-.5h-.5V0h.5v-.5zm-2.5 0H17V0h.5v-.5zM15-.5h-.5V0h.5v-.5zm-2.5 0H12V0h.5v-.5zM10-.5h-.5V0h.5v-.5zm-2.5 0H7V0h.5v-.5zM5-.5h-.5V0H5v-.5zm-2.5 0H2V0h.5v-.5zM0 0h-.5v.5H0V0zm0 2.5h-.5V3H0v-.5zM0 5h-.5v.5H0V5zm0 2.5h-.5V8H0v-.5zM0 10h-.5v.5H0V10zm0 2.5h-.5v.5H0v-.5zM0 15h-.5v.5H0V15zm0 2.5h-.5v.5H0v-.5zM.5 20H0v.5h.5V20zM3 20h-.5v.5H3V20zm2.5 0H5v.5h.5V20zM8 20h-.5v.5H8V20zm2.5 0H10v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5 0H15v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5-.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V17zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V12zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V7zm0-2.5H20V5h.5v-.5zm0-2.5H20v.5h.5V2zM1 3v14h18V3zm17 13H2V4h16z"/><path d="M8.58 14h.81l3.11-4 3 4H17l-4.5-6L9 12.51 6.5 9.5 3 14h1.56l1.94-2.5L8.58 14z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout basic</title><g fill="#fff"><path d="M1 3v14h18V3zm17 13H2V4h16z"/><path d="M8.58 14h.81l3.11-4 3 4H17l-4.5-6L9 12.51 6.5 9.5 3 14h1.56l1.94-2.5z"/></g></svg>
\ No newline at end of file
index d2dae40..97ec295 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout basic</title><g fill="#36c"><path d="M20-.5h-.5V0h.5v-.5zm-2.5 0H17V0h.5v-.5zM15-.5h-.5V0h.5v-.5zm-2.5 0H12V0h.5v-.5zM10-.5h-.5V0h.5v-.5zm-2.5 0H7V0h.5v-.5zM5-.5h-.5V0H5v-.5zm-2.5 0H2V0h.5v-.5zM0 0h-.5v.5H0V0zm0 2.5h-.5V3H0v-.5zM0 5h-.5v.5H0V5zm0 2.5h-.5V8H0v-.5zM0 10h-.5v.5H0V10zm0 2.5h-.5v.5H0v-.5zM0 15h-.5v.5H0V15zm0 2.5h-.5v.5H0v-.5zM.5 20H0v.5h.5V20zM3 20h-.5v.5H3V20zm2.5 0H5v.5h.5V20zM8 20h-.5v.5H8V20zm2.5 0H10v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5 0H15v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5-.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V17zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V12zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V7zm0-2.5H20V5h.5v-.5zm0-2.5H20v.5h.5V2zM1 3v14h18V3zm17 13H2V4h16z"/><path d="M8.58 14h.81l3.11-4 3 4H17l-4.5-6L9 12.51 6.5 9.5 3 14h1.56l1.94-2.5L8.58 14z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout basic</title><g fill="#36c"><path d="M1 3v14h18V3zm17 13H2V4h16z"/><path d="M8.58 14h.81l3.11-4 3 4H17l-4.5-6L9 12.51 6.5 9.5 3 14h1.56l1.94-2.5z"/></g></svg>
\ No newline at end of file
index c577084..3f85f6b 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout basic</title><path d="M20-.5h-.5V0h.5v-.5zm-2.5 0H17V0h.5v-.5zM15-.5h-.5V0h.5v-.5zm-2.5 0H12V0h.5v-.5zM10-.5h-.5V0h.5v-.5zm-2.5 0H7V0h.5v-.5zM5-.5h-.5V0H5v-.5zm-2.5 0H2V0h.5v-.5zM0 0h-.5v.5H0V0zm0 2.5h-.5V3H0v-.5zM0 5h-.5v.5H0V5zm0 2.5h-.5V8H0v-.5zM0 10h-.5v.5H0V10zm0 2.5h-.5v.5H0v-.5zM0 15h-.5v.5H0V15zm0 2.5h-.5v.5H0v-.5zM.5 20H0v.5h.5V20zM3 20h-.5v.5H3V20zm2.5 0H5v.5h.5V20zM8 20h-.5v.5H8V20zm2.5 0H10v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5 0H15v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5-.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V17zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V12zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V7zm0-2.5H20V5h.5v-.5zm0-2.5H20v.5h.5V2zM1 3v14h18V3zm17 13H2V4h16z"/><path d="M8.58 14h.81l3.11-4 3 4H17l-4.5-6L9 12.51 6.5 9.5 3 14h1.56l1.94-2.5L8.58 14z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout basic</title><path d="M1 3v14h18V3zm17 13H2V4h16z"/><path d="M8.58 14h.81l3.11-4 3 4H17l-4.5-6L9 12.51 6.5 9.5 3 14h1.56l1.94-2.5z"/></svg>
\ No newline at end of file
index f8e154f..0590320 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout frame</title><g fill="#fff"><path d="M20-.5h-.5V0h.5v-.5zm-2.5 0H17V0h.5v-.5zM15-.5h-.5V0h.5v-.5zm-2.5 0H12V0h.5v-.5zM10-.5h-.5V0h.5v-.5zm-2.5 0H7V0h.5v-.5zM5-.5h-.5V0H5v-.5zm-2.5 0H2V0h.5v-.5zM0 0h-.5v.5H0V0zm0 2.5h-.5V3H0v-.5zM0 5h-.5v.5H0V5zm0 2.5h-.5V8H0v-.5zM0 10h-.5v.5H0V10zm0 2.5h-.5v.5H0v-.5zM0 15h-.5v.5H0V15zm0 2.5h-.5v.5H0v-.5zM.5 20H0v.5h.5V20zM3 20h-.5v.5H3V20zm2.5 0H5v.5h.5V20zM8 20h-.5v.5H8V20zm2.5 0H10v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5 0H15v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5-.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V17zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V12zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V7zm0-2.5H20V5h.5v-.5zm0-2.5H20v.5h.5V2zM17 2H3a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 15H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1z"/><path d="M15.25 4H4.75A1.8 1.8 0 0 0 3 5.85v8.31A1.8 1.8 0 0 0 4.75 16h10.5A1.8 1.8 0 0 0 17 14.15v-8.3A1.8 1.8 0 0 0 15.25 4zM5 13l2.5-3 2 2L12 9l3 4z"/><path d="M17 6H3V4h14zm0 10H3v-2h14z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout frame</title><g fill="#fff"><path d="M3 2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 15a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1z"/><path d="M17 4H3v12h14zM5 13l2.5-3 2 2L12 9l3 4z"/></g></svg>
\ No newline at end of file
index bd1e7b0..93ff30c 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout frame</title><g fill="#36c"><path d="M20-.5h-.5V0h.5v-.5zm-2.5 0H17V0h.5v-.5zM15-.5h-.5V0h.5v-.5zm-2.5 0H12V0h.5v-.5zM10-.5h-.5V0h.5v-.5zm-2.5 0H7V0h.5v-.5zM5-.5h-.5V0H5v-.5zm-2.5 0H2V0h.5v-.5zM0 0h-.5v.5H0V0zm0 2.5h-.5V3H0v-.5zM0 5h-.5v.5H0V5zm0 2.5h-.5V8H0v-.5zM0 10h-.5v.5H0V10zm0 2.5h-.5v.5H0v-.5zM0 15h-.5v.5H0V15zm0 2.5h-.5v.5H0v-.5zM.5 20H0v.5h.5V20zM3 20h-.5v.5H3V20zm2.5 0H5v.5h.5V20zM8 20h-.5v.5H8V20zm2.5 0H10v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5 0H15v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5-.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V17zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V12zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V7zm0-2.5H20V5h.5v-.5zm0-2.5H20v.5h.5V2zM17 2H3a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 15H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1z"/><path d="M15.25 4H4.75A1.8 1.8 0 0 0 3 5.85v8.31A1.8 1.8 0 0 0 4.75 16h10.5A1.8 1.8 0 0 0 17 14.15v-8.3A1.8 1.8 0 0 0 15.25 4zM5 13l2.5-3 2 2L12 9l3 4z"/><path d="M17 6H3V4h14zm0 10H3v-2h14z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout frame</title><g fill="#36c"><path d="M3 2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 15a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1z"/><path d="M17 4H3v12h14zM5 13l2.5-3 2 2L12 9l3 4z"/></g></svg>
\ No newline at end of file
index 83eeb1e..47f7d95 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout frame</title><path d="M20-.5h-.5V0h.5v-.5zm-2.5 0H17V0h.5v-.5zM15-.5h-.5V0h.5v-.5zm-2.5 0H12V0h.5v-.5zM10-.5h-.5V0h.5v-.5zm-2.5 0H7V0h.5v-.5zM5-.5h-.5V0H5v-.5zm-2.5 0H2V0h.5v-.5zM0 0h-.5v.5H0V0zm0 2.5h-.5V3H0v-.5zM0 5h-.5v.5H0V5zm0 2.5h-.5V8H0v-.5zM0 10h-.5v.5H0V10zm0 2.5h-.5v.5H0v-.5zM0 15h-.5v.5H0V15zm0 2.5h-.5v.5H0v-.5zM.5 20H0v.5h.5V20zM3 20h-.5v.5H3V20zm2.5 0H5v.5h.5V20zM8 20h-.5v.5H8V20zm2.5 0H10v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5 0H15v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5-.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V17zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V12zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V7zm0-2.5H20V5h.5v-.5zm0-2.5H20v.5h.5V2zM17 2H3a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 15H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1z"/><path d="M15.25 4H4.75A1.8 1.8 0 0 0 3 5.85v8.31A1.8 1.8 0 0 0 4.75 16h10.5A1.8 1.8 0 0 0 17 14.15v-8.3A1.8 1.8 0 0 0 15.25 4zM5 13l2.5-3 2 2L12 9l3 4z"/><path d="M17 6H3V4h14zm0 10H3v-2h14z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout frame</title><path d="M3 2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 15a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1z"/><path d="M17 4H3v12h14zM5 13l2.5-3 2 2L12 9l3 4z"/></svg>
\ No newline at end of file
index 2e0a17a..32179fe 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout frameless</title><g fill="#fff"><path d="M20-.5h-.5V0h.5v-.5zm-2.5 0H17V0h.5v-.5zM15-.5h-.5V0h.5v-.5zm-2.5 0H12V0h.5v-.5zM10-.5h-.5V0h.5v-.5zm-2.5 0H7V0h.5v-.5zM5-.5h-.5V0H5v-.5zm-2.5 0H2V0h.5v-.5zM0 0h-.5v.5H0V0zm0 2.5h-.5V3H0v-.5zM0 5h-.5v.5H0V5zm0 2.5h-.5V8H0v-.5zM0 10h-.5v.5H0V10zm0 2.5h-.5v.5H0v-.5zM0 15h-.5v.5H0V15zm0 2.5h-.5v.5H0v-.5zM.5 20H0v.5h.5V20zM3 20h-.5v.5H3V20zm2.5 0H5v.5h.5V20zM8 20h-.5v.5H8V20zm2.5 0H10v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5 0H15v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5-.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V17zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V12zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V7zm0-2.5H20V5h.5v-.5zm0-2.5H20v.5h.5V2zM17 3H3a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zM3 14l3.5-4.5 2.5 3L12.5 8l4.5 6z"/><path d="M19 5H1V3h18zm0 12H1v-2h18z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout frameless</title><g fill="#fff"><path d="M19 3H1v14h18zM3 14l3.5-4.5 2.5 3L12.5 8l4.5 6z"/><path d="M19 5H1V3h18zm0 12H1v-2h18z"/></g></svg>
\ No newline at end of file
index 19afa05..239b85a 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout frameless</title><g fill="#36c"><path d="M20-.5h-.5V0h.5v-.5zm-2.5 0H17V0h.5v-.5zM15-.5h-.5V0h.5v-.5zm-2.5 0H12V0h.5v-.5zM10-.5h-.5V0h.5v-.5zm-2.5 0H7V0h.5v-.5zM5-.5h-.5V0H5v-.5zm-2.5 0H2V0h.5v-.5zM0 0h-.5v.5H0V0zm0 2.5h-.5V3H0v-.5zM0 5h-.5v.5H0V5zm0 2.5h-.5V8H0v-.5zM0 10h-.5v.5H0V10zm0 2.5h-.5v.5H0v-.5zM0 15h-.5v.5H0V15zm0 2.5h-.5v.5H0v-.5zM.5 20H0v.5h.5V20zM3 20h-.5v.5H3V20zm2.5 0H5v.5h.5V20zM8 20h-.5v.5H8V20zm2.5 0H10v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5 0H15v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5-.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V17zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V12zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V7zm0-2.5H20V5h.5v-.5zm0-2.5H20v.5h.5V2zM17 3H3a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zM3 14l3.5-4.5 2.5 3L12.5 8l4.5 6z"/><path d="M19 5H1V3h18zm0 12H1v-2h18z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout frameless</title><g fill="#36c"><path d="M19 3H1v14h18zM3 14l3.5-4.5 2.5 3L12.5 8l4.5 6z"/><path d="M19 5H1V3h18zm0 12H1v-2h18z"/></g></svg>
\ No newline at end of file
index 68cfb5e..1753774 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout frameless</title><path d="M20-.5h-.5V0h.5v-.5zm-2.5 0H17V0h.5v-.5zM15-.5h-.5V0h.5v-.5zm-2.5 0H12V0h.5v-.5zM10-.5h-.5V0h.5v-.5zm-2.5 0H7V0h.5v-.5zM5-.5h-.5V0H5v-.5zm-2.5 0H2V0h.5v-.5zM0 0h-.5v.5H0V0zm0 2.5h-.5V3H0v-.5zM0 5h-.5v.5H0V5zm0 2.5h-.5V8H0v-.5zM0 10h-.5v.5H0V10zm0 2.5h-.5v.5H0v-.5zM0 15h-.5v.5H0V15zm0 2.5h-.5v.5H0v-.5zM.5 20H0v.5h.5V20zM3 20h-.5v.5H3V20zm2.5 0H5v.5h.5V20zM8 20h-.5v.5H8V20zm2.5 0H10v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5 0H15v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5-.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V17zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V12zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V7zm0-2.5H20V5h.5v-.5zm0-2.5H20v.5h.5V2zM17 3H3a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zM3 14l3.5-4.5 2.5 3L12.5 8l4.5 6z"/><path d="M19 5H1V3h18zm0 12H1v-2h18z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout frameless</title><path d="M19 3H1v14h18zM3 14l3.5-4.5 2.5 3L12.5 8l4.5 6z"/><path d="M19 5H1V3h18zm0 12H1v-2h18z"/></svg>
\ No newline at end of file
index 81d6a11..328f497 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout thumbnail</title><g fill="#fff"><path d="M20-.5h-.5V0h.5v-.5zm-2.5 0H17V0h.5v-.5zM15-.5h-.5V0h.5v-.5zm-2.5 0H12V0h.5v-.5zM10-.5h-.5V0h.5v-.5zm-2.5 0H7V0h.5v-.5zM5-.5h-.5V0H5v-.5zm-2.5 0H2V0h.5v-.5zM0 0h-.5v.5H0V0zm0 2.5h-.5V3H0v-.5zM0 5h-.5v.5H0V5zm0 2.5h-.5V8H0v-.5zM0 10h-.5v.5H0V10zm0 2.5h-.5v.5H0v-.5zM0 15h-.5v.5H0V15zm0 2.5h-.5v.5H0v-.5zM.5 20H0v.5h.5V20zM3 20h-.5v.5H3V20zm2.5 0H5v.5h.5V20zM8 20h-.5v.5H8V20zm2.5 0H10v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5 0H15v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5-.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V17zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V12zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V7zm0-2.5H20V5h.5v-.5zm0-2.5H20v.5h.5V2zM17 2H3a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 15H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1z"/><path d="M15.25 4H4.75A1.8 1.8 0 0 0 3 5.85v6.31A1.8 1.8 0 0 0 4.75 14h10.5A1.8 1.8 0 0 0 17 12.15v-6.3A1.8 1.8 0 0 0 15.25 4zM5 12l2.5-3 2 2L12 8l3 4zm-1 3h12v1H4z"/><path d="M17 6H3V4h14zm0 8H3v-2h14z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout thumbnail</title><g fill="#fff"><path d="M3 2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 15a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1z"/><path d="M17 4H3v10h14zM5 12l2.5-3 2 2L12 8l3 4zm-1 3h12v1H4z"/></g></svg>
\ No newline at end of file
index 7154bef..4dc5e29 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout thumbnail</title><g fill="#36c"><path d="M20-.5h-.5V0h.5v-.5zm-2.5 0H17V0h.5v-.5zM15-.5h-.5V0h.5v-.5zm-2.5 0H12V0h.5v-.5zM10-.5h-.5V0h.5v-.5zm-2.5 0H7V0h.5v-.5zM5-.5h-.5V0H5v-.5zm-2.5 0H2V0h.5v-.5zM0 0h-.5v.5H0V0zm0 2.5h-.5V3H0v-.5zM0 5h-.5v.5H0V5zm0 2.5h-.5V8H0v-.5zM0 10h-.5v.5H0V10zm0 2.5h-.5v.5H0v-.5zM0 15h-.5v.5H0V15zm0 2.5h-.5v.5H0v-.5zM.5 20H0v.5h.5V20zM3 20h-.5v.5H3V20zm2.5 0H5v.5h.5V20zM8 20h-.5v.5H8V20zm2.5 0H10v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5 0H15v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5-.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V17zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V12zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V7zm0-2.5H20V5h.5v-.5zm0-2.5H20v.5h.5V2zM17 2H3a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 15H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1z"/><path d="M15.25 4H4.75A1.8 1.8 0 0 0 3 5.85v6.31A1.8 1.8 0 0 0 4.75 14h10.5A1.8 1.8 0 0 0 17 12.15v-6.3A1.8 1.8 0 0 0 15.25 4zM5 12l2.5-3 2 2L12 8l3 4zm-1 3h12v1H4z"/><path d="M17 6H3V4h14zm0 8H3v-2h14z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout thumbnail</title><g fill="#36c"><path d="M3 2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 15a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1z"/><path d="M17 4H3v10h14zM5 12l2.5-3 2 2L12 8l3 4zm-1 3h12v1H4z"/></g></svg>
\ No newline at end of file
index 145d580..6902b1a 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout thumbnail</title><path d="M20-.5h-.5V0h.5v-.5zm-2.5 0H17V0h.5v-.5zM15-.5h-.5V0h.5v-.5zm-2.5 0H12V0h.5v-.5zM10-.5h-.5V0h.5v-.5zm-2.5 0H7V0h.5v-.5zM5-.5h-.5V0H5v-.5zm-2.5 0H2V0h.5v-.5zM0 0h-.5v.5H0V0zm0 2.5h-.5V3H0v-.5zM0 5h-.5v.5H0V5zm0 2.5h-.5V8H0v-.5zM0 10h-.5v.5H0V10zm0 2.5h-.5v.5H0v-.5zM0 15h-.5v.5H0V15zm0 2.5h-.5v.5H0v-.5zM.5 20H0v.5h.5V20zM3 20h-.5v.5H3V20zm2.5 0H5v.5h.5V20zM8 20h-.5v.5H8V20zm2.5 0H10v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5 0H15v.5h.5V20zm2.5 0h-.5v.5h.5V20zm2.5-.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V17zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V12zm0-2.5H20v.5h.5v-.5zm0-2.5H20v.5h.5V7zm0-2.5H20V5h.5v-.5zm0-2.5H20v.5h.5V2zM17 2H3a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 15H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1z"/><path d="M15.25 4H4.75A1.8 1.8 0 0 0 3 5.85v6.31A1.8 1.8 0 0 0 4.75 14h10.5A1.8 1.8 0 0 0 17 12.15v-6.3A1.8 1.8 0 0 0 15.25 4zM5 12l2.5-3 2 2L12 8l3 4zm-1 3h12v1H4z"/><path d="M17 6H3V4h14zm0 8H3v-2h14z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image layout thumbnail</title><path d="M3 2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 15a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1z"/><path d="M17 4H3v10h14zM5 12l2.5-3 2 2L12 8l3 4zm-1 3h12v1H4z"/></svg>
\ No newline at end of file
index 96b7e3e..23aa9fb 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image locked</title><path fill="#fff" d="M8 9V5a1 1 0 0 0-1-1h-.5V2.5A2.45 2.45 0 0 0 4 0a2.45 2.45 0 0 0-2.5 2.5V4H1a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1zM4 8a1 1 0 1 1 1-1 1 1 0 0 1-1 1zm1.5-4h-3V2.75C2.5 2 2.5 1 4 1s1.5 1 1.5 1.75zM18 6h-8v4a2 2 0 0 1-2 2H2v6a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2zM4 17l3.54-4.5 2.53 3 3.54-4.5 4.56 6z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image locked</title><path fill="#fff" d="M8 5a1 1 0 0 0-1-1h-.5V2.5A2.45 2.45 0 0 0 4 0a2.45 2.45 0 0 0-2.5 2.5V4H1a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1zM4 8a1 1 0 1 1 1-1 1 1 0 0 1-1 1zm1.5-4h-3V2.75C2.5 2 2.5 1 4 1s1.5 1 1.5 1.75zM10 6v4a2 2 0 0 1-2 2H2v6a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2zM4 17l3.54-4.5 2.53 3 3.54-4.5 4.56 6z"/></svg>
\ No newline at end of file
index 057bfc7..92a7fff 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image locked</title><path fill="#36c" d="M8 9V5a1 1 0 0 0-1-1h-.5V2.5A2.45 2.45 0 0 0 4 0a2.45 2.45 0 0 0-2.5 2.5V4H1a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1zM4 8a1 1 0 1 1 1-1 1 1 0 0 1-1 1zm1.5-4h-3V2.75C2.5 2 2.5 1 4 1s1.5 1 1.5 1.75zM18 6h-8v4a2 2 0 0 1-2 2H2v6a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2zM4 17l3.54-4.5 2.53 3 3.54-4.5 4.56 6z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image locked</title><path fill="#36c" d="M8 5a1 1 0 0 0-1-1h-.5V2.5A2.45 2.45 0 0 0 4 0a2.45 2.45 0 0 0-2.5 2.5V4H1a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1zM4 8a1 1 0 1 1 1-1 1 1 0 0 1-1 1zm1.5-4h-3V2.75C2.5 2 2.5 1 4 1s1.5 1 1.5 1.75zM10 6v4a2 2 0 0 1-2 2H2v6a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2zM4 17l3.54-4.5 2.53 3 3.54-4.5 4.56 6z"/></svg>
\ No newline at end of file
index 7898ea4..8961ca2 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image locked</title><path d="M8 9V5a1 1 0 0 0-1-1h-.5V2.5A2.45 2.45 0 0 0 4 0a2.45 2.45 0 0 0-2.5 2.5V4H1a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1zM4 8a1 1 0 1 1 1-1 1 1 0 0 1-1 1zm1.5-4h-3V2.75C2.5 2 2.5 1 4 1s1.5 1 1.5 1.75zM18 6h-8v4a2 2 0 0 1-2 2H2v6a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2zM4 17l3.54-4.5 2.53 3 3.54-4.5 4.56 6z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>image locked</title><path d="M8 5a1 1 0 0 0-1-1h-.5V2.5A2.45 2.45 0 0 0 4 0a2.45 2.45 0 0 0-2.5 2.5V4H1a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1zM4 8a1 1 0 1 1 1-1 1 1 0 0 1-1 1zm1.5-4h-3V2.75C2.5 2 2.5 1 4 1s1.5 1 1.5 1.75zM10 6v4a2 2 0 0 1-2 2H2v6a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2zM4 17l3.54-4.5 2.53 3 3.54-4.5 4.56 6z"/></svg>
\ No newline at end of file
index f8f15ca..3fc928e 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>indent</title><path fill="#fff" d="M1 16h18v2H1zm8-9h10v2H9zm0 4h10v2H9zM1 2h18v2H1zm5 8l-5 4V6l5 4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>indent</title><path fill="#fff" d="M1 16h18v2H1zm8-9h10v2H9zm0 4h10v2H9zM1 2h18v2H1zm5 8l-5 4V6z"/></svg>
\ No newline at end of file
index 4cd14a2..da5d250 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>indent</title><path fill="#36c" d="M1 16h18v2H1zm8-9h10v2H9zm0 4h10v2H9zM1 2h18v2H1zm5 8l-5 4V6l5 4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>indent</title><path fill="#36c" d="M1 16h18v2H1zm8-9h10v2H9zm0 4h10v2H9zM1 2h18v2H1zm5 8l-5 4V6z"/></svg>
\ No newline at end of file
index 18ab051..52447bc 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>indent</title><path d="M1 16h18v2H1zm8-9h10v2H9zm0 4h10v2H9zM1 2h18v2H1zm5 8l-5 4V6l5 4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>indent</title><path d="M1 16h18v2H1zm8-9h10v2H9zm0 4h10v2H9zM1 2h18v2H1zm5 8l-5 4V6z"/></svg>
\ No newline at end of file
index ad22cfb..0c33951 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>italic</title><path d="M3.583 17L6.47 3h9.947l-.33 1.595H7.983l-.875 4.238h7.105l-.327 1.595H6.78l-1.027 4.985h8.68L14.104 17H3.584"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>italic</title><path d="M3.583 17L6.47 3h9.947l-.33 1.595H7.983l-.875 4.238h7.105l-.327 1.595H6.78l-1.027 4.985h8.68L14.104 17z"/></g></svg>
\ No newline at end of file
index cf35ec2..be8f8b4 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>italic</title><path d="M3.583 17L6.47 3h9.947l-.33 1.595H7.983l-.875 4.238h7.105l-.327 1.595H6.78l-1.027 4.985h8.68L14.104 17H3.584"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>italic</title><path d="M3.583 17L6.47 3h9.947l-.33 1.595H7.983l-.875 4.238h7.105l-.327 1.595H6.78l-1.027 4.985h8.68L14.104 17z"/></g></svg>
\ No newline at end of file
index 9946b38..e7dd4c4 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>italic</title><path d="M3.583 17L6.47 3h9.947l-.33 1.595H7.983l-.875 4.238h7.105l-.327 1.595H6.78l-1.027 4.985h8.68L14.104 17H3.584"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>italic</title><path d="M3.583 17L6.47 3h9.947l-.33 1.595H7.983l-.875 4.238h7.105l-.327 1.595H6.78l-1.027 4.985h8.68L14.104 17z"/></svg>
\ No newline at end of file
index 8a91ec2..1af5437 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>journal</title><path fill="#fff" d="M2 1.5v17A1.5 1.5 0 0 0 3.5 20H5V0H3.5A1.5 1.5 0 0 0 2 1.5zM16 0H6v20h10a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm-3 8H8V7h5zm3-2H8V5h8z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>journal</title><path fill="#fff" d="M2 18.5A1.5 1.5 0 0 0 3.5 20H5V0H3.5A1.5 1.5 0 0 0 2 1.5zM6 0v20h10a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm7 8H8V7h5zm3-2H8V5h8z"/></svg>
\ No newline at end of file
index 8850d02..aee51bc 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>journal</title><path fill="#36c" d="M2 1.5v17A1.5 1.5 0 0 0 3.5 20H5V0H3.5A1.5 1.5 0 0 0 2 1.5zM16 0H6v20h10a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm-3 8H8V7h5zm3-2H8V5h8z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>journal</title><path fill="#36c" d="M2 18.5A1.5 1.5 0 0 0 3.5 20H5V0H3.5A1.5 1.5 0 0 0 2 1.5zM6 0v20h10a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm7 8H8V7h5zm3-2H8V5h8z"/></svg>
\ No newline at end of file
index 70e7c36..bba4760 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>journal</title><path d="M2 1.5v17A1.5 1.5 0 0 0 3.5 20H5V0H3.5A1.5 1.5 0 0 0 2 1.5zM16 0H6v20h10a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm-3 8H8V7h5zm3-2H8V5h8z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>journal</title><path d="M2 18.5A1.5 1.5 0 0 0 3.5 20H5V0H3.5A1.5 1.5 0 0 0 2 1.5zM6 0v20h10a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm7 8H8V7h5zm3-2H8V5h8z"/></svg>
\ No newline at end of file
index c845f3e..473739d 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>journal</title><path fill="#fff" d="M16.5 0H15v20h1.5c.8 0 1.5-.7 1.5-1.5v-17c0-.8-.7-1.5-1.5-1.5zM2 2v16c0 1.1.9 2 2 2h10V0H4C2.9 0 2 .9 2 2zm5 5h5v1H7V7zM4 5h8v1H4V5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>journal</title><path fill="#fff" d="M15 0v20h1.5c.8 0 1.5-.7 1.5-1.5v-17c0-.8-.7-1.5-1.5-1.5zM2 18c0 1.1.9 2 2 2h10V0H4C2.9 0 2 .9 2 2zM4 5h8v1H4zm3 2h5v1H7z"/></svg>
\ No newline at end of file
index 076915c..d4b7e32 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>journal</title><path fill="#36c" d="M16.5 0H15v20h1.5c.8 0 1.5-.7 1.5-1.5v-17c0-.8-.7-1.5-1.5-1.5zM2 2v16c0 1.1.9 2 2 2h10V0H4C2.9 0 2 .9 2 2zm5 5h5v1H7V7zM4 5h8v1H4V5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>journal</title><path fill="#36c" d="M15 0v20h1.5c.8 0 1.5-.7 1.5-1.5v-17c0-.8-.7-1.5-1.5-1.5zM2 18c0 1.1.9 2 2 2h10V0H4C2.9 0 2 .9 2 2zM4 5h8v1H4zm3 2h5v1H7z"/></svg>
\ No newline at end of file
index e032c26..258df36 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>journal</title><path d="M16.5 0H15v20h1.5c.8 0 1.5-.7 1.5-1.5v-17c0-.8-.7-1.5-1.5-1.5zM2 2v16c0 1.1.9 2 2 2h10V0H4C2.9 0 2 .9 2 2zm5 5h5v1H7V7zM4 5h8v1H4V5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>journal</title><path d="M15 0v20h1.5c.8 0 1.5-.7 1.5-1.5v-17c0-.8-.7-1.5-1.5-1.5zM2 18c0 1.1.9 2 2 2h10V0H4C2.9 0 2 .9 2 2zM4 5h8v1H4zm3 2h5v1H7z"/></svg>
\ No newline at end of file
index eb07935..3cc1b1b 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>keyboard</title><path fill="#fff" d="M0 5v10a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2H2a2 2 0 0 0-2 2zm9 1h2v2H9zm0 3h2v2H9zM6 6h2v2H6zm0 3h2v2H6zm-1 5H3v-2h2zm0-3H3V9h2zm0-3H3V6h2zm9 6H6v-2h8zm0-3h-2V9h2zm0-3h-2V6h2zm3 6h-2v-2h2zm0-3h-2V9h2zm0-3h-2V6h2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>keyboard</title><path fill="#fff" d="M0 15a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2H2a2 2 0 0 0-2 2zm9-9h2v2H9zm0 3h2v2H9zM6 6h2v2H6zm0 3h2v2H6zm-1 5H3v-2h2zm0-3H3V9h2zm0-3H3V6h2zm9 6H6v-2h8zm0-3h-2V9h2zm0-3h-2V6h2zm3 6h-2v-2h2zm0-3h-2V9h2zm0-3h-2V6h2z"/></svg>
\ No newline at end of file
index 8a72746..14f7a37 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>keyboard</title><path fill="#36c" d="M0 5v10a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2H2a2 2 0 0 0-2 2zm9 1h2v2H9zm0 3h2v2H9zM6 6h2v2H6zm0 3h2v2H6zm-1 5H3v-2h2zm0-3H3V9h2zm0-3H3V6h2zm9 6H6v-2h8zm0-3h-2V9h2zm0-3h-2V6h2zm3 6h-2v-2h2zm0-3h-2V9h2zm0-3h-2V6h2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>keyboard</title><path fill="#36c" d="M0 15a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2H2a2 2 0 0 0-2 2zm9-9h2v2H9zm0 3h2v2H9zM6 6h2v2H6zm0 3h2v2H6zm-1 5H3v-2h2zm0-3H3V9h2zm0-3H3V6h2zm9 6H6v-2h8zm0-3h-2V9h2zm0-3h-2V6h2zm3 6h-2v-2h2zm0-3h-2V9h2zm0-3h-2V6h2z"/></svg>
\ No newline at end of file
index fa60a80..f499141 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>keyboard</title><path d="M0 5v10a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2H2a2 2 0 0 0-2 2zm9 1h2v2H9zm0 3h2v2H9zM6 6h2v2H6zm0 3h2v2H6zm-1 5H3v-2h2zm0-3H3V9h2zm0-3H3V6h2zm9 6H6v-2h8zm0-3h-2V9h2zm0-3h-2V6h2zm3 6h-2v-2h2zm0-3h-2V9h2zm0-3h-2V6h2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>keyboard</title><path d="M0 15a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2H2a2 2 0 0 0-2 2zm9-9h2v2H9zm0 3h2v2H9zM6 6h2v2H6zm0 3h2v2H6zm-1 5H3v-2h2zm0-3H3V9h2zm0-3H3V6h2zm9 6H6v-2h8zm0-3h-2V9h2zm0-3h-2V6h2zm3 6h-2v-2h2zm0-3h-2V9h2zm0-3h-2V6h2z"/></svg>
\ No newline at end of file
index 3033beb..f2dd0fe 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>layout</title><g fill="#fff"><path d="M8 12V1H1v18h18v-7H8z"/><path d="M11 1v8h8V1zm6 6h-4V3h4z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>layout</title><g fill="#fff"><path d="M8 12V1H1v18h18v-7z"/><path d="M11 1v8h8V1zm6 6h-4V3h4z"/></g></svg>
\ No newline at end of file
index 0736564..7721244 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>layout</title><g fill="#36c"><path d="M8 12V1H1v18h18v-7H8z"/><path d="M11 1v8h8V1zm6 6h-4V3h4z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>layout</title><g fill="#36c"><path d="M8 12V1H1v18h18v-7z"/><path d="M11 1v8h8V1zm6 6h-4V3h4z"/></g></svg>
\ No newline at end of file
index 791076d..e32139e 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>layout</title><path d="M8 12V1H1v18h18v-7H8z"/><path d="M11 1v8h8V1zm6 6h-4V3h4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>layout</title><path d="M8 12V1H1v18h18v-7z"/><path d="M11 1v8h8V1zm6 6h-4V3h4z"/></svg>
\ No newline at end of file
index 2d0048b..fd61819 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>layout</title><g fill="#fff"><path d="M1 12v7h18V1h-7v11z"/><path d="M1 1v8h8V1H1zm2 2h4v4H3V3z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>layout</title><g fill="#fff"><path d="M1 12v7h18V1h-7v11z"/><path d="M1 1v8h8V1zm2 2h4v4H3z"/></g></svg>
\ No newline at end of file
index 82c1626..aa4de11 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>layout</title><g fill="#36c"><path d="M1 12v7h18V1h-7v11z"/><path d="M1 1v8h8V1H1zm2 2h4v4H3V3z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>layout</title><g fill="#36c"><path d="M1 12v7h18V1h-7v11z"/><path d="M1 1v8h8V1zm2 2h4v4H3z"/></g></svg>
\ No newline at end of file
index 133945c..07e51de 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>layout</title><path d="M1 12v7h18V1h-7v11z"/><path d="M1 1v8h8V1H1zm2 2h4v4H3V3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>layout</title><path d="M1 12v7h18V1h-7v11z"/><path d="M1 1v8h8V1zm2 2h4v4H3z"/></svg>
\ No newline at end of file
index 3dc2985..af616f9 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>external link</title><g fill="#fff"><path d="M17 17H3V3h5V1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5h-2z"/><path d="M19 1h-8l3.29 3.29-5.73 5.73 1.42 1.42 5.73-5.73L19 9V1z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>external link</title><g fill="#fff"><path d="M17 17H3V3h5V1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5h-2z"/><path d="M11 1l3.29 3.29-5.73 5.73 1.42 1.42 5.73-5.73L19 9V1z"/></g></svg>
\ No newline at end of file
index e9f1f30..fe8552d 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>external link</title><g fill="#36c"><path d="M17 17H3V3h5V1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5h-2z"/><path d="M19 1h-8l3.29 3.29-5.73 5.73 1.42 1.42 5.73-5.73L19 9V1z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>external link</title><g fill="#36c"><path d="M17 17H3V3h5V1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5h-2z"/><path d="M11 1l3.29 3.29-5.73 5.73 1.42 1.42 5.73-5.73L19 9V1z"/></g></svg>
\ No newline at end of file
index c6648f4..5259462 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>external link</title><path d="M17 17H3V3h5V1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5h-2z"/><path d="M19 1h-8l3.29 3.29-5.73 5.73 1.42 1.42 5.73-5.73L19 9V1z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>external link</title><path d="M17 17H3V3h5V1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5h-2z"/><path d="M11 1l3.29 3.29-5.73 5.73 1.42 1.42 5.73-5.73L19 9V1z"/></svg>
\ No newline at end of file
index 7b56588..3777796 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>external link</title><g fill="#fff"><path d="M3 12H1v5c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2h-5v2h5v14H3v-5z"/><path d="M1 9l3.3-3.3 5.7 5.7 1.4-1.4-5.7-5.7L9 1H1z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>external link</title><g fill="#fff"><path d="M3 12H1v5c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2h-5v2h5v14H3z"/><path d="M1 9l3.3-3.3 5.7 5.7 1.4-1.4-5.7-5.7L9 1H1z"/></g></svg>
\ No newline at end of file
index c6d8fdf..3af3291 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>external link</title><g fill="#36c"><path d="M3 12H1v5c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2h-5v2h5v14H3v-5z"/><path d="M1 9l3.3-3.3 5.7 5.7 1.4-1.4-5.7-5.7L9 1H1z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>external link</title><g fill="#36c"><path d="M3 12H1v5c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2h-5v2h5v14H3z"/><path d="M1 9l3.3-3.3 5.7 5.7 1.4-1.4-5.7-5.7L9 1H1z"/></g></svg>
\ No newline at end of file
index cf2d5d2..7bf3b43 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>external link</title><path d="M3 12H1v5c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2h-5v2h5v14H3v-5z"/><path d="M1 9l3.3-3.3 5.7 5.7 1.4-1.4-5.7-5.7L9 1H1z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>external link</title><path d="M3 12H1v5c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2h-5v2h5v14H3z"/><path d="M1 9l3.3-3.3 5.7 5.7 1.4-1.4-5.7-5.7L9 1H1z"/></svg>
\ No newline at end of file
index 266b6e2..5540c3d 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>numbered list</title><path fill="#fff" d="M7 15h12v2H7zm0-6h12v2H7zm0-6h12v2H7zM2 6h1V1H1v1h1v4zm-1 9h2v1H2v1h1v1H1v1h3v-5H1v1zm2.5-7H1v1h2v1H1.5a.5.5 0 0 0-.5.5V13h3v-1H2v-1h1.5a.5.5 0 0 0 .5-.5v-2a.5.5 0 0 0-.5-.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>numbered list</title><path fill="#fff" d="M7 15h12v2H7zm0-6h12v2H7zm0-6h12v2H7zM2 6h1V1H1v1h1zm1 9v1H2v1h1v1H1v1h3v-5H1v1zM1 8v1h2v1H1.5a.5.5 0 0 0-.5.5V13h3v-1H2v-1h1.5a.5.5 0 0 0 .5-.5v-2a.5.5 0 0 0-.5-.5z"/></svg>
\ No newline at end of file
index d5edc7d..89bfe22 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>numbered list</title><path fill="#36c" d="M7 15h12v2H7zm0-6h12v2H7zm0-6h12v2H7zM2 6h1V1H1v1h1v4zm-1 9h2v1H2v1h1v1H1v1h3v-5H1v1zm2.5-7H1v1h2v1H1.5a.5.5 0 0 0-.5.5V13h3v-1H2v-1h1.5a.5.5 0 0 0 .5-.5v-2a.5.5 0 0 0-.5-.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>numbered list</title><path fill="#36c" d="M7 15h12v2H7zm0-6h12v2H7zm0-6h12v2H7zM2 6h1V1H1v1h1zm1 9v1H2v1h1v1H1v1h3v-5H1v1zM1 8v1h2v1H1.5a.5.5 0 0 0-.5.5V13h3v-1H2v-1h1.5a.5.5 0 0 0 .5-.5v-2a.5.5 0 0 0-.5-.5z"/></svg>
\ No newline at end of file
index 44c67d2..63c5ad2 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>numbered list</title><path d="M7 15h12v2H7zm0-6h12v2H7zm0-6h12v2H7zM2 6h1V1H1v1h1v4zm-1 9h2v1H2v1h1v1H1v1h3v-5H1v1zm2.5-7H1v1h2v1H1.5a.5.5 0 0 0-.5.5V13h3v-1H2v-1h1.5a.5.5 0 0 0 .5-.5v-2a.5.5 0 0 0-.5-.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>numbered list</title><path d="M7 15h12v2H7zm0-6h12v2H7zm0-6h12v2H7zM2 6h1V1H1v1h1zm1 9v1H2v1h1v1H1v1h3v-5H1v1zM1 8v1h2v1H1.5a.5.5 0 0 0-.5.5V13h3v-1H2v-1h1.5a.5.5 0 0 0 .5-.5v-2a.5.5 0 0 0-.5-.5z"/></svg>
\ No newline at end of file
index 8dc921f..9a2a040 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>numbered list</title><path fill="#fff" d="M2 15h11v2H2zm0-6h11v2H2zm0-6h11v2H2zm15-2h-1v1h1v4h1V1zm-2 12v1h2v1h-1v1h1v1h-2v1h3v-5zm2.5-6H15v1h2v1h-1.5c-.3 0-.5.2-.5.5V12h3v-1h-2v-1h1.5c.3 0 .5-.2.5-.5v-2c0-.3-.2-.5-.5-.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>numbered list</title><path fill="#fff" d="M2 15h11v2H2zm0-6h11v2H2zm0-6h11v2H2zm15-2h-1v1h1v4h1V1zm-2 12v1h2v1h-1v1h1v1h-2v1h3v-5zm0-6v1h2v1h-1.5c-.3 0-.5.2-.5.5V12h3v-1h-2v-1h1.5c.3 0 .5-.2.5-.5v-2c0-.3-.2-.5-.5-.5z"/></svg>
\ No newline at end of file
index 15c6e87..bdb0c37 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>numbered list</title><path fill="#36c" d="M2 15h11v2H2zm0-6h11v2H2zm0-6h11v2H2zm15-2h-1v1h1v4h1V1zm-2 12v1h2v1h-1v1h1v1h-2v1h3v-5zm2.5-6H15v1h2v1h-1.5c-.3 0-.5.2-.5.5V12h3v-1h-2v-1h1.5c.3 0 .5-.2.5-.5v-2c0-.3-.2-.5-.5-.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>numbered list</title><path fill="#36c" d="M2 15h11v2H2zm0-6h11v2H2zm0-6h11v2H2zm15-2h-1v1h1v4h1V1zm-2 12v1h2v1h-1v1h1v1h-2v1h3v-5zm0-6v1h2v1h-1.5c-.3 0-.5.2-.5.5V12h3v-1h-2v-1h1.5c.3 0 .5-.2.5-.5v-2c0-.3-.2-.5-.5-.5z"/></svg>
\ No newline at end of file
index 4d97d39..986e212 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>numbered list</title><path d="M2 15h11v2H2zm0-6h11v2H2zm0-6h11v2H2zm15-2h-1v1h1v4h1V1zm-2 12v1h2v1h-1v1h1v1h-2v1h3v-5zm2.5-6H15v1h2v1h-1.5c-.3 0-.5.2-.5.5V12h3v-1h-2v-1h1.5c.3 0 .5-.2.5-.5v-2c0-.3-.2-.5-.5-.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>numbered list</title><path d="M2 15h11v2H2zm0-6h11v2H2zm0-6h11v2H2zm15-2h-1v1h1v4h1V1zm-2 12v1h2v1h-1v1h1v1h-2v1h3v-5zm0-6v1h2v1h-1.5c-.3 0-.5.2-.5.5V12h3v-1h-2v-1h1.5c.3 0 .5-.2.5-.5v-2c0-.3-.2-.5-.5-.5z"/></svg>
\ No newline at end of file
index 976da4a..fdd9ad7 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>log out</title><g fill="#fff"><path d="M3 3h8V1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h8v-2H3z"/><path d="M19 10l-6-5v4H5v2h8v4l6-5z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>log out</title><g fill="#fff"><path d="M3 3h8V1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h8v-2H3z"/><path d="M15v4H5v2h8v4l6-5z"/></g></svg>
\ No newline at end of file
index 8500617..c630231 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>log out</title><g fill="#36c"><path d="M3 3h8V1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h8v-2H3z"/><path d="M19 10l-6-5v4H5v2h8v4l6-5z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>log out</title><g fill="#36c"><path d="M3 3h8V1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h8v-2H3z"/><path d="M15v4H5v2h8v4l6-5z"/></g></svg>
\ No newline at end of file
index d071225..3a7a533 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>log out</title><path d="M3 3h8V1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h8v-2H3z"/><path d="M19 10l-6-5v4H5v2h8v4l6-5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>log out</title><path d="M3 3h8V1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h8v-2H3z"/><path d="M15v4H5v2h8v4l6-5z"/></svg>
\ No newline at end of file
index bca7d74..a665569 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>log out</title><g fill="#fff"><path d="M17 17H9v2h8c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2H9v2h8v14z"/><path d="M7 15v-4h8V9H7V5l-6 5z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>log out</title><g fill="#fff"><path d="M17 17H9v2h8c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2H9v2h8z"/><path d="M7 15v-4h8V9H7V5l-6 5z"/></g></svg>
\ No newline at end of file
index a8ac02f..80bf1dd 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>log out</title><g fill="#36c"><path d="M17 17H9v2h8c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2H9v2h8v14z"/><path d="M7 15v-4h8V9H7V5l-6 5z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>log out</title><g fill="#36c"><path d="M17 17H9v2h8c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2H9v2h8z"/><path d="M7 15v-4h8V9H7V5l-6 5z"/></g></svg>
\ No newline at end of file
index cb11921..5261d66 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>log out</title><path d="M17 17H9v2h8c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2H9v2h8v14z"/><path d="M7 15v-4h8V9H7V5l-6 5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>log out</title><path d="M17 17H9v2h8c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2H9v2h8z"/><path d="M7 15v-4h8V9H7V5l-6 5z"/></svg>
\ No newline at end of file
index b4317eb..6123f57 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>map trail</title><g fill="#fff"><path d="M20 6l-1-1-1.5 1.5L16 5l-1 1 1.5 1.5L15 9l1 1 1.5-1.5L19 10l1-1-1.5-1.5L20 6zm-9 8.5A3.54 3.54 0 0 1 7.5 18a3.5 3.5 0 0 1 0-7 3.54 3.54 0 0 1 3.5 3.5z"/><circle cx="7" cy="3" r="2"/><circle cx="13" cy="7" r="1"/><circle cx="10" cy="6" r="1"/><circle cx="3" cy="3" r="1"/><circle cx="1" cy="6" r="1"/><circle cx="1" cy="9" r="1"/><circle cx="3" cy="12" r="1"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>map trail</title><g fill="#fff"><path d="M20 6l-1-1-1.5 1.5L16 5l-1 1 1.5 1.5L15 9l1 1 1.5-1.5L19 10l1-1-1.5-1.5z"/><circle cx="7.5" cy="14.5" r="3.5"/><circle cx="7" cy="3" r="2"/><circle cx="13" cy="7" r="1"/><circle cx="10" cy="6" r="1"/><circle cx="3" cy="3" r="1"/><circle cx="1" cy="6" r="1"/><circle cx="1" cy="9" r="1"/><circle cx="3" cy="12" r="1"/></g></svg>
\ No newline at end of file
index 29c0b7f..c7bd4db 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>map trail</title><g fill="#36c"><path d="M20 6l-1-1-1.5 1.5L16 5l-1 1 1.5 1.5L15 9l1 1 1.5-1.5L19 10l1-1-1.5-1.5L20 6zm-9 8.5A3.54 3.54 0 0 1 7.5 18a3.5 3.5 0 0 1 0-7 3.54 3.54 0 0 1 3.5 3.5z"/><circle cx="7" cy="3" r="2"/><circle cx="13" cy="7" r="1"/><circle cx="10" cy="6" r="1"/><circle cx="3" cy="3" r="1"/><circle cx="1" cy="6" r="1"/><circle cx="1" cy="9" r="1"/><circle cx="3" cy="12" r="1"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>map trail</title><g fill="#36c"><path d="M20 6l-1-1-1.5 1.5L16 5l-1 1 1.5 1.5L15 9l1 1 1.5-1.5L19 10l1-1-1.5-1.5z"/><circle cx="7.5" cy="14.5" r="3.5"/><circle cx="7" cy="3" r="2"/><circle cx="13" cy="7" r="1"/><circle cx="10" cy="6" r="1"/><circle cx="3" cy="3" r="1"/><circle cx="1" cy="6" r="1"/><circle cx="1" cy="9" r="1"/><circle cx="3" cy="12" r="1"/></g></svg>
\ No newline at end of file
index 3c4726b..9fffe9b 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>map trail</title><path d="M20 6l-1-1-1.5 1.5L16 5l-1 1 1.5 1.5L15 9l1 1 1.5-1.5L19 10l1-1-1.5-1.5L20 6zm-9 8.5A3.54 3.54 0 0 1 7.5 18a3.5 3.5 0 0 1 0-7 3.54 3.54 0 0 1 3.5 3.5z"/><circle cx="7" cy="3" r="2"/><circle cx="13" cy="7" r="1"/><circle cx="10" cy="6" r="1"/><circle cx="3" cy="3" r="1"/><circle cx="1" cy="6" r="1"/><circle cx="1" cy="9" r="1"/><circle cx="3" cy="12" r="1"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>map trail</title><path d="M20 6l-1-1-1.5 1.5L16 5l-1 1 1.5 1.5L15 9l1 1 1.5-1.5L19 10l1-1-1.5-1.5z"/><circle cx="7.5" cy="14.5" r="3.5"/><circle cx="7" cy="3" r="2"/><circle cx="13" cy="7" r="1"/><circle cx="10" cy="6" r="1"/><circle cx="3" cy="3" r="1"/><circle cx="1" cy="6" r="1"/><circle cx="1" cy="9" r="1"/><circle cx="3" cy="12" r="1"/></svg>
\ No newline at end of file
index 4a0f3fb..0669bfa 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>markup</title><path fill="#fff" d="M6.5 3.5l-5 5L0 10l1.5 1.5 5 5L8 15l-5-5 5-5-1.5-1.5zm12 5l-5-5L12 5l5 5-5 5 1.5 1.5 5-5L20 10l-1.5-1.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>markup</title><path fill="#fff" d="M6.5 3.5L0 10l1.5 1.5 5 5L8 15l-5-5 5-5zm7 0L12 5l5 5-5 5 1.5 1.5L20 10z"/></svg>
\ No newline at end of file
index 3195886..f2100c6 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>markup</title><path fill="#36c" d="M6.5 3.5l-5 5L0 10l1.5 1.5 5 5L8 15l-5-5 5-5-1.5-1.5zm12 5l-5-5L12 5l5 5-5 5 1.5 1.5 5-5L20 10l-1.5-1.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>markup</title><path fill="#36c" d="M6.5 3.5L0 10l1.5 1.5 5 5L8 15l-5-5 5-5zm7 0L12 5l5 5-5 5 1.5 1.5L20 10z"/></svg>
\ No newline at end of file
index 8a6e84a..032d63c 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>markup</title><path d="M6.5 3.5l-5 5L0 10l1.5 1.5 5 5L8 15l-5-5 5-5-1.5-1.5zm12 5l-5-5L12 5l5 5-5 5 1.5 1.5 5-5L20 10l-1.5-1.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>markup</title><path d="M6.5 3.5L0 10l1.5 1.5 5 5L8 15l-5-5 5-5zm7 0L12 5l5 5-5 5 1.5 1.5L20 10z"/></svg>
\ No newline at end of file
index e6320d4..0b7a5d2 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula</title><path fill="#fff" d="M14 2H4l5 8-5 8h12v-4h-2v2H8.25L12 10 8.25 4H14v2h2V2h-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula</title><path fill="#fff" d="M14 2H4l5 8-5 8h12v-4h-2v2H8.25L12 10 8.25 4H14v2h2V2z"/></svg>
\ No newline at end of file
index 62dde43..6b5114d 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula</title><path fill="#36c" d="M14 2H4l5 8-5 8h12v-4h-2v2H8.25L12 10 8.25 4H14v2h2V2h-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula</title><path fill="#36c" d="M14 2H4l5 8-5 8h12v-4h-2v2H8.25L12 10 8.25 4H14v2h2V2z"/></svg>
\ No newline at end of file
index c7ef385..23c519a 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula</title><path d="M14 2H4l5 8-5 8h12v-4h-2v2H8.25L12 10 8.25 4H14v2h2V2h-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula</title><path d="M14 2H4l5 8-5 8h12v-4h-2v2H8.25L12 10 8.25 4H14v2h2V2z"/></svg>
\ No newline at end of file
index bcdd566..b6bab67 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula displayed block</title><path fill="#fff" d="M13 5H5l3 5-3 5h10v-3h-2v1H9.2l1.8-3-1.8-3H13v1h2V5h-2zM2 1h16v2H2zm0 16h16v2H2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula displayed block</title><path fill="#fff" d="M13 5H5l3 5-3 5h10v-3h-2v1H9.2l1.8-3-1.8-3H13v1h2V5zM2 1h16v2H2zm0 16h16v2H2z"/></svg>
\ No newline at end of file
index 696e026..1eaa33e 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula displayed block</title><path fill="#36c" d="M13 5H5l3 5-3 5h10v-3h-2v1H9.2l1.8-3-1.8-3H13v1h2V5h-2zM2 1h16v2H2zm0 16h16v2H2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula displayed block</title><path fill="#36c" d="M13 5H5l3 5-3 5h10v-3h-2v1H9.2l1.8-3-1.8-3H13v1h2V5zM2 1h16v2H2zm0 16h16v2H2z"/></svg>
\ No newline at end of file
index 5bf6084..0413075 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula displayed block</title><path d="M13 5H5l3 5-3 5h10v-3h-2v1H9.2l1.8-3-1.8-3H13v1h2V5h-2zM2 1h16v2H2zm0 16h16v2H2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula displayed block</title><path d="M13 5H5l3 5-3 5h10v-3h-2v1H9.2l1.8-3-1.8-3H13v1h2V5zM2 1h16v2H2zm0 16h16v2H2z"/></svg>
\ No newline at end of file
index 6f01e5a..6938ddd 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula displayed default</title><path fill="#fff" d="M12 5H4l3 5-3 5h10v-3h-2v1H8.2l1.8-3-1.8-3H12v1h2V5h-2zM1 9h3v2H1zm15 0h3v2h-3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula displayed default</title><path fill="#fff" d="M12 5H4l3 5-3 5h10v-3h-2v1H8.2l1.8-3-1.8-3H12v1h2V5zM1 9h3v2H1zm15 0h3v2h-3z"/></svg>
\ No newline at end of file
index d090c5c..6257edf 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula displayed default</title><path fill="#36c" d="M12 5H4l3 5-3 5h10v-3h-2v1H8.2l1.8-3-1.8-3H12v1h2V5h-2zM1 9h3v2H1zm15 0h3v2h-3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula displayed default</title><path fill="#36c" d="M12 5H4l3 5-3 5h10v-3h-2v1H8.2l1.8-3-1.8-3H12v1h2V5zM1 9h3v2H1zm15 0h3v2h-3z"/></svg>
\ No newline at end of file
index 4ca06cd..f514457 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula displayed default</title><path d="M12 5H4l3 5-3 5h10v-3h-2v1H8.2l1.8-3-1.8-3H12v1h2V5h-2zM1 9h3v2H1zm15 0h3v2h-3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula displayed default</title><path d="M12 5H4l3 5-3 5h10v-3h-2v1H8.2l1.8-3-1.8-3H12v1h2V5zM1 9h3v2H1zm15 0h3v2h-3z"/></svg>
\ No newline at end of file
index 1018e46..7473b05 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula displayed inline</title><path fill="#fff" d="M4 13H0V7h4v6zm12-6h4v6h-4zm-3-1H6l3 4-3 4h8v-3h-2v1H9.5l1.5-2-1.5-2H12v1h2V6h-1z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula displayed inline</title><path fill="#fff" d="M4 13H0V7h4zm12-6h4v6h-4zM6 6l3 4-3 4h8v-3h-2v1H9.5l1.5-2-1.5-2H12v1h2V6z"/></svg>
\ No newline at end of file
index 4b941e1..cd1da2a 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula displayed inline</title><path fill="#36c" d="M4 13H0V7h4v6zm12-6h4v6h-4zm-3-1H6l3 4-3 4h8v-3h-2v1H9.5l1.5-2-1.5-2H12v1h2V6h-1z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula displayed inline</title><path fill="#36c" d="M4 13H0V7h4zm12-6h4v6h-4zM6 6l3 4-3 4h8v-3h-2v1H9.5l1.5-2-1.5-2H12v1h2V6z"/></svg>
\ No newline at end of file
index d189571..96ad25c 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula displayed inline</title><path d="M4 13H0V7h4v6zm12-6h4v6h-4zm-3-1H6l3 4-3 4h8v-3h-2v1H9.5l1.5-2-1.5-2H12v1h2V6h-1z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>mathematics formula displayed inline</title><path d="M4 13H0V7h4zm12-6h4v6h-4zM6 6l3 4-3 4h8v-3h-2v1H9.5l1.5-2-1.5-2H12v1h2V6z"/></svg>
\ No newline at end of file
index 0fc1a12..d730b17 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>message</title><g fill="#fff"><path d="M0 8v8a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8l-10 4z"/><path d="M18 2H2a2 2 0 0 0-2 2v2l10 4 10-4V4a2 2 0 0 0-2-2z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>message</title><g fill="#fff"><path d="M0 8v8a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8l-10 4z"/><path d="M2a2 2 0 0 0-2 2v2l10 4 10-4V4a2 2 0 0 0-2-2z"/></g></svg>
\ No newline at end of file
index fe012fc..fc659bf 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>message</title><g fill="#36c"><path d="M0 8v8a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8l-10 4z"/><path d="M18 2H2a2 2 0 0 0-2 2v2l10 4 10-4V4a2 2 0 0 0-2-2z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>message</title><g fill="#36c"><path d="M0 8v8a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8l-10 4z"/><path d="M2a2 2 0 0 0-2 2v2l10 4 10-4V4a2 2 0 0 0-2-2z"/></g></svg>
\ No newline at end of file
index 0b9691c..1918658 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>message</title><path d="M0 8v8a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8l-10 4z"/><path d="M18 2H2a2 2 0 0 0-2 2v2l10 4 10-4V4a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>message</title><path d="M0 8v8a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8l-10 4z"/><path d="M2a2 2 0 0 0-2 2v2l10 4 10-4V4a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
index 9342df1..99bf518 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>move</title><path fill="#fff" d="M19 10l-4-3v2h-4V5h2l-3-4-3 4h2v4H5V7l-4 3 4 3v-2h4v4H7l3 4 3-4h-2v-4h4v2l4-3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>move</title><path fill="#fff" d="M19 10l-4-3v2h-4V5h2l-3-4-3 4h2v4H5V7l-4 3 4 3v-2h4v4H7l3 4 3-4h-2v-4h4v2z"/></svg>
\ No newline at end of file
index a8b62a3..37dd588 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>move</title><path fill="#36c" d="M19 10l-4-3v2h-4V5h2l-3-4-3 4h2v4H5V7l-4 3 4 3v-2h4v4H7l3 4 3-4h-2v-4h4v2l4-3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>move</title><path fill="#36c" d="M19 10l-4-3v2h-4V5h2l-3-4-3 4h2v4H5V7l-4 3 4 3v-2h4v4H7l3 4 3-4h-2v-4h4v2z"/></svg>
\ No newline at end of file
index 03975f8..e01347d 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>move</title><path d="M19 10l-4-3v2h-4V5h2l-3-4-3 4h2v4H5V7l-4 3 4 3v-2h4v4H7l3 4 3-4h-2v-4h4v2l4-3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>move</title><path d="M19 10l-4-3v2h-4V5h2l-3-4-3 4h2v4H5V7l-4 3 4 3v-2h4v4H7l3 4 3-4h-2v-4h4v2z"/></svg>
\ No newline at end of file
index 1f02679..d6342fc 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>first</title><path fill="#fff" d="M3 1h2v18H3zm13.5 1.5L15 1l-9 9 9 9 1.5-1.5L9 10l7.5-7.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>first</title><path fill="#fff" d="M3 1h2v18H3zm13.5 1.5L15 1l-9 9 9 9 1.5-1.5L9 10z"/></svg>
\ No newline at end of file
index dd8eec5..3e1c680 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>first</title><path fill="#36c" d="M3 1h2v18H3zm13.5 1.5L15 1l-9 9 9 9 1.5-1.5L9 10l7.5-7.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>first</title><path fill="#36c" d="M3 1h2v18H3zm13.5 1.5L15 1l-9 9 9 9 1.5-1.5L9 10z"/></svg>
\ No newline at end of file
index d7d116e..aa0b1fc 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>first</title><path d="M3 1h2v18H3zm13.5 1.5L15 1l-9 9 9 9 1.5-1.5L9 10l7.5-7.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>first</title><path d="M3 1h2v18H3zm13.5 1.5L15 1l-9 9 9 9 1.5-1.5L9 10z"/></svg>
\ No newline at end of file
index 6984974..0eaab17 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>first</title><path fill="#fff" d="M15 1h2v18h-2zM3.5 2.5L11 10l-7.5 7.5L5 19l9-9-9-9-1.5 1.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>first</title><path fill="#fff" d="M15 1h2v18h-2zM3.5 2.5L11 10l-7.5 7.5L5 19l9-9-9-9z"/></svg>
\ No newline at end of file
index 1cf9152..7c7821a 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>first</title><path fill="#36c" d="M15 1h2v18h-2zM3.5 2.5L11 10l-7.5 7.5L5 19l9-9-9-9-1.5 1.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>first</title><path fill="#36c" d="M15 1h2v18h-2zM3.5 2.5L11 10l-7.5 7.5L5 19l9-9-9-9z"/></svg>
\ No newline at end of file
index 88dfe2c..02e2d18 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>first</title><path d="M15 1h2v18h-2zM3.5 2.5L11 10l-7.5 7.5L5 19l9-9-9-9-1.5 1.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>first</title><path d="M15 1h2v18h-2zM3.5 2.5L11 10l-7.5 7.5L5 19l9-9-9-9z"/></svg>
\ No newline at end of file
index bc636d8..7463141 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>last</title><path fill="#fff" d="M15 1h2v18h-2zM3.5 2.5L11 10l-7.5 7.5L5 19l9-9-9-9-1.5 1.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>last</title><path fill="#fff" d="M15 1h2v18h-2zM3.5 2.5L11 10l-7.5 7.5L5 19l9-9-9-9z"/></svg>
\ No newline at end of file
index f5c3892..63aab84 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>last</title><path fill="#36c" d="M15 1h2v18h-2zM3.5 2.5L11 10l-7.5 7.5L5 19l9-9-9-9-1.5 1.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>last</title><path fill="#36c" d="M15 1h2v18h-2zM3.5 2.5L11 10l-7.5 7.5L5 19l9-9-9-9z"/></svg>
\ No newline at end of file
index cb0a473..326f655 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>last</title><path d="M15 1h2v18h-2zM3.5 2.5L11 10l-7.5 7.5L5 19l9-9-9-9-1.5 1.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>last</title><path d="M15 1h2v18h-2zM3.5 2.5L11 10l-7.5 7.5L5 19l9-9-9-9z"/></svg>
\ No newline at end of file
index 1f02679..d6342fc 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>first</title><path fill="#fff" d="M3 1h2v18H3zm13.5 1.5L15 1l-9 9 9 9 1.5-1.5L9 10l7.5-7.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>first</title><path fill="#fff" d="M3 1h2v18H3zm13.5 1.5L15 1l-9 9 9 9 1.5-1.5L9 10z"/></svg>
\ No newline at end of file
index dd8eec5..3e1c680 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>first</title><path fill="#36c" d="M3 1h2v18H3zm13.5 1.5L15 1l-9 9 9 9 1.5-1.5L9 10l7.5-7.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>first</title><path fill="#36c" d="M3 1h2v18H3zm13.5 1.5L15 1l-9 9 9 9 1.5-1.5L9 10z"/></svg>
\ No newline at end of file
index d7d116e..aa0b1fc 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>first</title><path d="M3 1h2v18H3zm13.5 1.5L15 1l-9 9 9 9 1.5-1.5L9 10l7.5-7.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>first</title><path d="M3 1h2v18H3zm13.5 1.5L15 1l-9 9 9 9 1.5-1.5L9 10z"/></svg>
\ No newline at end of file
index 39f14b2..dcc968d 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>new window</title><g fill="#fff"><path d="M17 17H3V3h5V1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5h-2z"/><path d="M19 1h-8l3.29 3.29-5.73 5.73 1.42 1.42 5.73-5.73L19 9V1z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>new window</title><g fill="#fff"><path d="M17 17H3V3h5V1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5h-2z"/><path d="M11 1l3.29 3.29-5.73 5.73 1.42 1.42 5.73-5.73L19 9V1z"/></g></svg>
\ No newline at end of file
index 1ff23cb..dc72dc2 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>new window</title><g fill="#36c"><path d="M17 17H3V3h5V1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5h-2z"/><path d="M19 1h-8l3.29 3.29-5.73 5.73 1.42 1.42 5.73-5.73L19 9V1z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>new window</title><g fill="#36c"><path d="M17 17H3V3h5V1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5h-2z"/><path d="M11 1l3.29 3.29-5.73 5.73 1.42 1.42 5.73-5.73L19 9V1z"/></g></svg>
\ No newline at end of file
index af0056a..2a6e8de 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>new window</title><path d="M17 17H3V3h5V1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5h-2z"/><path d="M19 1h-8l3.29 3.29-5.73 5.73 1.42 1.42 5.73-5.73L19 9V1z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>new window</title><path d="M17 17H3V3h5V1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5h-2z"/><path d="M11 1l3.29 3.29-5.73 5.73 1.42 1.42 5.73-5.73L19 9V1z"/></svg>
\ No newline at end of file
index bf03df3..946f9fb 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>new window</title><g fill="#fff"><path d="M3 12H1v5c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2h-5v2h5v14H3v-5z"/><path d="M1 9l3.3-3.3 5.7 5.7 1.4-1.4-5.7-5.7L9 1H1z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>new window</title><g fill="#fff"><path d="M3 12H1v5c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2h-5v2h5v14H3z"/><path d="M1 9l3.3-3.3 5.7 5.7 1.4-1.4-5.7-5.7L9 1H1z"/></g></svg>
\ No newline at end of file
index effb557..3b53f6b 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>new window</title><g fill="#36c"><path d="M3 12H1v5c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2h-5v2h5v14H3v-5z"/><path d="M1 9l3.3-3.3 5.7 5.7 1.4-1.4-5.7-5.7L9 1H1z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>new window</title><g fill="#36c"><path d="M3 12H1v5c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2h-5v2h5v14H3z"/><path d="M1 9l3.3-3.3 5.7 5.7 1.4-1.4-5.7-5.7L9 1H1z"/></g></svg>
\ No newline at end of file
index 6d98eec..9003288 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>new window</title><path d="M3 12H1v5c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2h-5v2h5v14H3v-5z"/><path d="M1 9l3.3-3.3 5.7 5.7 1.4-1.4-5.7-5.7L9 1H1z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>new window</title><path d="M3 12H1v5c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2h-5v2h5v14H3z"/><path d="M1 9l3.3-3.3 5.7 5.7 1.4-1.4-5.7-5.7L9 1H1z"/></svg>
\ No newline at end of file
index b045271..7958ab8 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>newline</title><path fill="#fff" d="M17 4v6H7V6l-6 5 6 5v-4h12V4h-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>newline</title><path fill="#fff" d="M17 4v6H7V6l-6 5 6 5v-4h12V4z"/></svg>
\ No newline at end of file
index fce413a..228a43d 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>newline</title><path fill="#36c" d="M17 4v6H7V6l-6 5 6 5v-4h12V4h-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>newline</title><path fill="#36c" d="M17 4v6H7V6l-6 5 6 5v-4h12V4z"/></svg>
\ No newline at end of file
index 98affee..dcd0883 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>newline</title><path d="M17 4v6H7V6l-6 5 6 5v-4h12V4h-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>newline</title><path d="M17 4v6H7V6l-6 5 6 5v-4h12V4z"/></svg>
\ No newline at end of file
index de0088b..15a4f68 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>newspaper</title><path fill="#fff" d="M18 2H5a2 2 0 0 0-2 2v12a1 1 0 0 1-1-1V5h-.5A1.5 1.5 0 0 0 0 6.5v10A1.5 1.5 0 0 0 1.5 18H18a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm-6 13H6v-1h6zm0-2H6v-1h6zm0-2H6v-1h6zm5 4h-4v-5h4zm0-7H6V4h11z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>newspaper</title><path fill="#fff" d="M5 2a2 2 0 0 0-2 2v12a1 1 0 0 1-1-1V5h-.5A1.5 1.5 0 0 0 0 6.5v10A1.5 1.5 0 0 0 1.5 18H18a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm1 2h11v4H6zm0 6h6v1H6zm0 2h6v1H6zm0 2h6v1H6zm7-4h4v5h-4z"/></svg>
\ No newline at end of file
index 35e6344..9057bbb 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>newspaper</title><path fill="#36c" d="M18 2H5a2 2 0 0 0-2 2v12a1 1 0 0 1-1-1V5h-.5A1.5 1.5 0 0 0 0 6.5v10A1.5 1.5 0 0 0 1.5 18H18a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm-6 13H6v-1h6zm0-2H6v-1h6zm0-2H6v-1h6zm5 4h-4v-5h4zm0-7H6V4h11z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>newspaper</title><path fill="#36c" d="M5 2a2 2 0 0 0-2 2v12a1 1 0 0 1-1-1V5h-.5A1.5 1.5 0 0 0 0 6.5v10A1.5 1.5 0 0 0 1.5 18H18a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm1 2h11v4H6zm0 6h6v1H6zm0 2h6v1H6zm0 2h6v1H6zm7-4h4v5h-4z"/></svg>
\ No newline at end of file
index 439ea96..fdc92e4 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>newspaper</title><path d="M18 2H5a2 2 0 0 0-2 2v12a1 1 0 0 1-1-1V5h-.5A1.5 1.5 0 0 0 0 6.5v10A1.5 1.5 0 0 0 1.5 18H18a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm-6 13H6v-1h6zm0-2H6v-1h6zm0-2H6v-1h6zm5 4h-4v-5h4zm0-7H6V4h11z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>newspaper</title><path d="M5 2a2 2 0 0 0-2 2v12a1 1 0 0 1-1-1V5h-.5A1.5 1.5 0 0 0 0 6.5v10A1.5 1.5 0 0 0 1.5 18H18a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm1 2h11v4H6zm0 6h6v1H6zm0 2h6v1H6zm0 2h6v1H6zm7-4h4v5h-4z"/></svg>
\ No newline at end of file
index 609a027..6a8bab7 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>newspaper</title><path fill="#fff" d="M0 4v12c0 1.1.9 2 2 2h16.5c.8 0 1.5-.7 1.5-1.5v-10c0-.8-.7-1.5-1.5-1.5H18v10c0 .6-.4 1-1 1V4c0-1.1-.9-2-2-2H2C.9 2 0 2.9 0 4zm8 10h6v1H8v-1zm0-2h6v1H8v-1zm0-2h6v1H8v-1zm-5 0h4v5H3v-5zm0-6h11v4H3V4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>newspaper</title><path fill="#fff" d="M0 16c0 1.1.9 2 2 2h16.5c.8 0 1.5-.7 1.5-1.5v-10c0-.8-.7-1.5-1.5-1.5H18v10c0 .6-.4 1-1 1V4c0-1.1-.9-2-2-2H2C.9 2 0 2.9 0 4zM3 4h11v4H3zm0 6h4v5H3zm5 0h6v1H8zm0 2h6v1H8zm0 2h6v1H8z"/></svg>
\ No newline at end of file
index bda8a99..2c8eba4 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>newspaper</title><path fill="#36c" d="M0 4v12c0 1.1.9 2 2 2h16.5c.8 0 1.5-.7 1.5-1.5v-10c0-.8-.7-1.5-1.5-1.5H18v10c0 .6-.4 1-1 1V4c0-1.1-.9-2-2-2H2C.9 2 0 2.9 0 4zm8 10h6v1H8v-1zm0-2h6v1H8v-1zm0-2h6v1H8v-1zm-5 0h4v5H3v-5zm0-6h11v4H3V4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>newspaper</title><path fill="#36c" d="M0 16c0 1.1.9 2 2 2h16.5c.8 0 1.5-.7 1.5-1.5v-10c0-.8-.7-1.5-1.5-1.5H18v10c0 .6-.4 1-1 1V4c0-1.1-.9-2-2-2H2C.9 2 0 2.9 0 4zM3 4h11v4H3zm0 6h4v5H3zm5 0h6v1H8zm0 2h6v1H8zm0 2h6v1H8z"/></svg>
\ No newline at end of file
index 76a8535..815dcc6 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>newspaper</title><path d="M0 4v12c0 1.1.9 2 2 2h16.5c.8 0 1.5-.7 1.5-1.5v-10c0-.8-.7-1.5-1.5-1.5H18v10c0 .6-.4 1-1 1V4c0-1.1-.9-2-2-2H2C.9 2 0 2.9 0 4zm8 10h6v1H8v-1zm0-2h6v1H8v-1zm0-2h6v1H8v-1zm-5 0h4v5H3v-5zm0-6h11v4H3V4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>newspaper</title><path d="M0 16c0 1.1.9 2 2 2h16.5c.8 0 1.5-.7 1.5-1.5v-10c0-.8-.7-1.5-1.5-1.5H18v10c0 .6-.4 1-1 1V4c0-1.1-.9-2-2-2H2C.9 2 0 2.9 0 4zM3 4h11v4H3zm0 6h4v5H3zm5 0h6v1H8zm0 2h6v1H8zm0 2h6v1H8z"/></svg>
\ No newline at end of file
index eb2f017..d58b406 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>no WikiText</title><path fill="#fff" d="M16 3v2h1v10l2 2V3zM9 5V3H5l2 2zM1 1L0 2l1 1v14h3v-2H3V5l2 2v10h4v-2H7V9l6 6h-2v2h4l3 3 1-1-3-3zm12 10l2 2V3h-4v2h2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>no WikiText</title><path fill="#fff" d="M16 3v2h1v10l2 2V3zM9 5V3H5l2 2zM1 1L0 2l1 1v14h3v-2H3V5l2 2v10h4v-2H7V9l6 6h-2v2h4l3 3 1-1zm12 10l2 2V3h-4v2h2z"/></svg>
\ No newline at end of file
index dff68df..9486955 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>no WikiText</title><path fill="#36c" d="M16 3v2h1v10l2 2V3zM9 5V3H5l2 2zM1 1L0 2l1 1v14h3v-2H3V5l2 2v10h4v-2H7V9l6 6h-2v2h4l3 3 1-1-3-3zm12 10l2 2V3h-4v2h2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>no WikiText</title><path fill="#36c" d="M16 3v2h1v10l2 2V3zM9 5V3H5l2 2zM1 1L0 2l1 1v14h3v-2H3V5l2 2v10h4v-2H7V9l6 6h-2v2h4l3 3 1-1zm12 10l2 2V3h-4v2h2z"/></svg>
\ No newline at end of file
index b32048f..cb98c78 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>no WikiText</title><path d="M16 3v2h1v10l2 2V3zM9 5V3H5l2 2zM1 1L0 2l1 1v14h3v-2H3V5l2 2v10h4v-2H7V9l6 6h-2v2h4l3 3 1-1-3-3zm12 10l2 2V3h-4v2h2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>no WikiText</title><path d="M16 3v2h1v10l2 2V3zM9 5V3H5l2 2zM1 1L0 2l1 1v14h3v-2H3V5l2 2v10h4v-2H7V9l6 6h-2v2h4l3 3 1-1zm12 10l2 2V3h-4v2h2z"/></svg>
\ No newline at end of file
index 81b90f6..0d48fb6 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>ongoing conversation</title><path fill="#fff" d="M18 0H2a2 2 0 0 0-2 2v18l4-4h14a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zM5 9.06a1.39 1.39 0 1 1 1.37-1.39A1.39 1.39 0 0 1 5 9.06zm5.16 0a1.39 1.39 0 1 1 1.39-1.39 1.39 1.39 0 0 1-1.42 1.39zm5.16 0a1.39 1.39 0 1 1 1.39-1.39 1.39 1.39 0 0 1-1.42 1.39z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>ongoing conversation</title><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v18l4-4h14a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm3 9.06a1.39 1.39 0 1 1 1.37-1.39A1.39 1.39 0 0 1 5 9.06zm5.16 0a1.39 1.39 0 1 1 1.39-1.39 1.39 1.39 0 0 1-1.42 1.39zm5.16 0a1.39 1.39 0 1 1 1.39-1.39 1.39 1.39 0 0 1-1.42 1.39z"/></svg>
\ No newline at end of file
index c4318b1..bad6547 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>ongoing conversation</title><path fill="#36c" d="M18 0H2a2 2 0 0 0-2 2v18l4-4h14a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zM5 9.06a1.39 1.39 0 1 1 1.37-1.39A1.39 1.39 0 0 1 5 9.06zm5.16 0a1.39 1.39 0 1 1 1.39-1.39 1.39 1.39 0 0 1-1.42 1.39zm5.16 0a1.39 1.39 0 1 1 1.39-1.39 1.39 1.39 0 0 1-1.42 1.39z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>ongoing conversation</title><path fill="#36c" d="M2 0a2 2 0 0 0-2 2v18l4-4h14a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm3 9.06a1.39 1.39 0 1 1 1.37-1.39A1.39 1.39 0 0 1 5 9.06zm5.16 0a1.39 1.39 0 1 1 1.39-1.39 1.39 1.39 0 0 1-1.42 1.39zm5.16 0a1.39 1.39 0 1 1 1.39-1.39 1.39 1.39 0 0 1-1.42 1.39z"/></svg>
\ No newline at end of file
index c4bc4da..b02924a 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>ongoing conversation</title><path d="M18 0H2a2 2 0 0 0-2 2v18l4-4h14a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zM5 9.06a1.39 1.39 0 1 1 1.37-1.39A1.39 1.39 0 0 1 5 9.06zm5.16 0a1.39 1.39 0 1 1 1.39-1.39 1.39 1.39 0 0 1-1.42 1.39zm5.16 0a1.39 1.39 0 1 1 1.39-1.39 1.39 1.39 0 0 1-1.42 1.39z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>ongoing conversation</title><path d="M2 0a2 2 0 0 0-2 2v18l4-4h14a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm3 9.06a1.39 1.39 0 1 1 1.37-1.39A1.39 1.39 0 0 1 5 9.06zm5.16 0a1.39 1.39 0 1 1 1.39-1.39 1.39 1.39 0 0 1-1.42 1.39zm5.16 0a1.39 1.39 0 1 1 1.39-1.39 1.39 1.39 0 0 1-1.42 1.39z"/></svg>
\ No newline at end of file
index 30fe996..7f0ccd0 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>ongoing conversation</title><path fill="#fff" d="M0 2v12c0 1.1.9 2 2 2h14l4 4V2c0-1.1-.9-2-2-2H2C.9 0 0 .9 0 2zm13.6 5.7c0-.8.6-1.4 1.4-1.4.8 0 1.4.6 1.4 1.4s-.6 1.4-1.4 1.4c-.8-.1-1.4-.7-1.4-1.4zM9.9 9.1s-.1 0 0 0c-.8 0-1.4-.6-1.4-1.4 0-.8.6-1.4 1.4-1.4.8 0 1.4.6 1.4 1.4s-.7 1.4-1.4 1.4zm-5.2 0c-.8 0-1.4-.6-1.4-1.4 0-.8.6-1.4 1.4-1.4.8 0 1.4.6 1.4 1.4 0 .7-.7 1.4-1.4 1.4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>ongoing conversation</title><path fill="#fff" d="M0 14c0 1.1.9 2 2 2h14l4 4V2c0-1.1-.9-2-2-2H2C.9 0 0 .9 0 2zm13.6-6.3c0-.8.6-1.4 1.4-1.4.8 0 1.4.6 1.4 1.4s-.6 1.4-1.4 1.4c-.8-.1-1.4-.7-1.4-1.4zM9.9 9.1s-.1 0 0 0c-.8 0-1.4-.6-1.4-1.4 0-.8.6-1.4 1.4-1.4.8 0 1.4.6 1.4 1.4s-.7 1.4-1.4 1.4zm-5.2 0c-.8 0-1.4-.6-1.4-1.4 0-.8.6-1.4 1.4-1.4.8 0 1.4.6 1.4 1.4 0 .7-.7 1.4-1.4 1.4z"/></svg>
\ No newline at end of file
index 5e50d81..0fa6cf2 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>ongoing conversation</title><path fill="#36c" d="M0 2v12c0 1.1.9 2 2 2h14l4 4V2c0-1.1-.9-2-2-2H2C.9 0 0 .9 0 2zm13.6 5.7c0-.8.6-1.4 1.4-1.4.8 0 1.4.6 1.4 1.4s-.6 1.4-1.4 1.4c-.8-.1-1.4-.7-1.4-1.4zM9.9 9.1s-.1 0 0 0c-.8 0-1.4-.6-1.4-1.4 0-.8.6-1.4 1.4-1.4.8 0 1.4.6 1.4 1.4s-.7 1.4-1.4 1.4zm-5.2 0c-.8 0-1.4-.6-1.4-1.4 0-.8.6-1.4 1.4-1.4.8 0 1.4.6 1.4 1.4 0 .7-.7 1.4-1.4 1.4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>ongoing conversation</title><path fill="#36c" d="M0 14c0 1.1.9 2 2 2h14l4 4V2c0-1.1-.9-2-2-2H2C.9 0 0 .9 0 2zm13.6-6.3c0-.8.6-1.4 1.4-1.4.8 0 1.4.6 1.4 1.4s-.6 1.4-1.4 1.4c-.8-.1-1.4-.7-1.4-1.4zM9.9 9.1s-.1 0 0 0c-.8 0-1.4-.6-1.4-1.4 0-.8.6-1.4 1.4-1.4.8 0 1.4.6 1.4 1.4s-.7 1.4-1.4 1.4zm-5.2 0c-.8 0-1.4-.6-1.4-1.4 0-.8.6-1.4 1.4-1.4.8 0 1.4.6 1.4 1.4 0 .7-.7 1.4-1.4 1.4z"/></svg>
\ No newline at end of file
index 707353f..4130e12 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>ongoing conversation</title><path d="M0 2v12c0 1.1.9 2 2 2h14l4 4V2c0-1.1-.9-2-2-2H2C.9 0 0 .9 0 2zm13.6 5.7c0-.8.6-1.4 1.4-1.4.8 0 1.4.6 1.4 1.4s-.6 1.4-1.4 1.4c-.8-.1-1.4-.7-1.4-1.4zM9.9 9.1s-.1 0 0 0c-.8 0-1.4-.6-1.4-1.4 0-.8.6-1.4 1.4-1.4.8 0 1.4.6 1.4 1.4s-.7 1.4-1.4 1.4zm-5.2 0c-.8 0-1.4-.6-1.4-1.4 0-.8.6-1.4 1.4-1.4.8 0 1.4.6 1.4 1.4 0 .7-.7 1.4-1.4 1.4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>ongoing conversation</title><path d="M0 14c0 1.1.9 2 2 2h14l4 4V2c0-1.1-.9-2-2-2H2C.9 0 0 .9 0 2zm13.6-6.3c0-.8.6-1.4 1.4-1.4.8 0 1.4.6 1.4 1.4s-.6 1.4-1.4 1.4c-.8-.1-1.4-.7-1.4-1.4zM9.9 9.1s-.1 0 0 0c-.8 0-1.4-.6-1.4-1.4 0-.8.6-1.4 1.4-1.4.8 0 1.4.6 1.4 1.4s-.7 1.4-1.4 1.4zm-5.2 0c-.8 0-1.4-.6-1.4-1.4 0-.8.6-1.4 1.4-1.4.8 0 1.4.6 1.4 1.4 0 .7-.7 1.4-1.4 1.4z"/></svg>
\ No newline at end of file
index 3d0b9a9..ebfe91d 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>outdent</title><path fill="#fff" d="M1 16h18v2H1zm8-9h10v2H9zm0 4h10v2H9zM1 2h18v2H1zm0 8l5 4V6l-5 4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>outdent</title><path fill="#fff" d="M1 16h18v2H1zm8-9h10v2H9zm0 4h10v2H9zM1 2h18v2H1zm0 8l5 4V6z"/></svg>
\ No newline at end of file
index b7bc829..13e2b1d 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>outdent</title><path fill="#36c" d="M1 16h18v2H1zm8-9h10v2H9zm0 4h10v2H9zM1 2h18v2H1zm0 8l5 4V6l-5 4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>outdent</title><path fill="#36c" d="M1 16h18v2H1zm8-9h10v2H9zm0 4h10v2H9zM1 2h18v2H1zm0 8l5 4V6z"/></svg>
\ No newline at end of file
index 8abc234..eef683e 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>outdent</title><path d="M1 16h18v2H1zm8-9h10v2H9zm0 4h10v2H9zM1 2h18v2H1zm0 8l5 4V6l-5 4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>outdent</title><path d="M1 16h18v2H1zm8-9h10v2H9zm0 4h10v2H9zM1 2h18v2H1zm0 8l5 4V6z"/></svg>
\ No newline at end of file
index 99a9fd6..3c54aba 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>outline</title><path fill="#fff" d="M1 12h18v7H1zM11 1v8h8V1h-8zm2 2h4v4h-4V3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>outline</title><path fill="#fff" d="M1 12h18v7H1zM11 1v8h8V1zm2 2h4v4h-4z"/></svg>
\ No newline at end of file
index 638405f..f63caa8 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>outline</title><path fill="#36c" d="M1 12h18v7H1zM11 1v8h8V1h-8zm2 2h4v4h-4V3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>outline</title><path fill="#36c" d="M1 12h18v7H1zM11 1v8h8V1zm2 2h4v4h-4z"/></svg>
\ No newline at end of file
index 2340bcd..5993fe2 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>outline</title><path d="M1 12h18v7H1zM11 1v8h8V1h-8zm2 2h4v4h-4V3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>outline</title><path d="M1 12h18v7H1zM11 1v8h8V1zm2 2h4v4h-4z"/></svg>
\ No newline at end of file
index d29be30..47c622f 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>play</title><path fill="#fff" d="M16.75 10.83L4.55 19A1 1 0 0 1 3 18.13V1.87A1 1 0 0 1 4.55 1l12.2 8.13a1 1 0 0 1 0 1.7z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>play</title><path fill="#fff" d="M4.55 19A1 1 0 0 1 3 18.13V1.87A1 1 0 0 1 4.55 1l12.2 8.13a1 1 0 0 1 0 1.7z"/></svg>
\ No newline at end of file
index 79090c5..9568f53 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>play</title><path fill="#36c" d="M16.75 10.83L4.55 19A1 1 0 0 1 3 18.13V1.87A1 1 0 0 1 4.55 1l12.2 8.13a1 1 0 0 1 0 1.7z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>play</title><path fill="#36c" d="M4.55 19A1 1 0 0 1 3 18.13V1.87A1 1 0 0 1 4.55 1l12.2 8.13a1 1 0 0 1 0 1.7z"/></svg>
\ No newline at end of file
index a04ff2a..30e7698 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>play</title><path d="M16.75 10.83L4.55 19A1 1 0 0 1 3 18.13V1.87A1 1 0 0 1 4.55 1l12.2 8.13a1 1 0 0 1 0 1.7z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>play</title><path d="M4.55 19A1 1 0 0 1 3 18.13V1.87A1 1 0 0 1 4.55 1l12.2 8.13a1 1 0 0 1 0 1.7z"/></svg>
\ No newline at end of file
index c8ef32c..69cb48d 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>printer</title><path fill="#fff" d="M5 1h10v4H5zm12 5H3a2 2 0 0 0-2 2v7h4v4h10v-4h4V8a2 2 0 0 0-2-2zm-3 12H6v-6h8zm2-8a1 1 0 1 1 1-1 1 1 0 0 1-1 1z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>printer</title><path fill="#fff" d="M5 1h10v4H5zM3 6a2 2 0 0 0-2 2v7h4v4h10v-4h4V8a2 2 0 0 0-2-2zm11 12H6v-6h8zm2-8a1 1 0 1 1 1-1 1 1 0 0 1-1 1z"/></svg>
\ No newline at end of file
index cf32cea..e96b9b6 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>printer</title><path fill="#36c" d="M5 1h10v4H5zm12 5H3a2 2 0 0 0-2 2v7h4v4h10v-4h4V8a2 2 0 0 0-2-2zm-3 12H6v-6h8zm2-8a1 1 0 1 1 1-1 1 1 0 0 1-1 1z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>printer</title><path fill="#36c" d="M5 1h10v4H5zM3 6a2 2 0 0 0-2 2v7h4v4h10v-4h4V8a2 2 0 0 0-2-2zm11 12H6v-6h8zm2-8a1 1 0 1 1 1-1 1 1 0 0 1-1 1z"/></svg>
\ No newline at end of file
index 98ebf1e..8d0d99f 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>printer</title><path d="M5 1h10v4H5zm12 5H3a2 2 0 0 0-2 2v7h4v4h10v-4h4V8a2 2 0 0 0-2-2zm-3 12H6v-6h8zm2-8a1 1 0 1 1 1-1 1 1 0 0 1-1 1z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>printer</title><path d="M5 1h10v4H5zM3 6a2 2 0 0 0-2 2v7h4v4h10v-4h4V8a2 2 0 0 0-2-2zm11 12H6v-6h8zm2-8a1 1 0 1 1 1-1 1 1 0 0 1-1 1z"/></svg>
\ No newline at end of file
index b97d0d6..a6a6d79 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>push pin</title><path fill="#fff" d="M14 8h-1V2a2 2 0 0 0 2-2H5a2 2 0 0 0 2 2v6H6a2 2 0 0 0-2 2v1h5v5l1 4 1-4v-5h5v-1a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>push pin</title><path fill="#fff" d="M13 8V2a2 2 0 0 0 2-2H5a2 2 0 0 0 2 2v6H6a2 2 0 0 0-2 2v1h5v5l1 4 1-4v-5h5v-1a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
index 06af606..9ba35bf 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>push pin</title><path fill="#36c" d="M14 8h-1V2a2 2 0 0 0 2-2H5a2 2 0 0 0 2 2v6H6a2 2 0 0 0-2 2v1h5v5l1 4 1-4v-5h5v-1a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>push pin</title><path fill="#36c" d="M13 8V2a2 2 0 0 0 2-2H5a2 2 0 0 0 2 2v6H6a2 2 0 0 0-2 2v1h5v5l1 4 1-4v-5h5v-1a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
index 37d0292..8b72199 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>push pin</title><path d="M14 8h-1V2a2 2 0 0 0 2-2H5a2 2 0 0 0 2 2v6H6a2 2 0 0 0-2 2v1h5v5l1 4 1-4v-5h5v-1a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>push pin</title><path d="M13 8V2a2 2 0 0 0 2-2H5a2 2 0 0 0 2 2v6H6a2 2 0 0 0-2 2v1h5v5l1 4 1-4v-5h5v-1a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
index 03c637c..f106ede 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>quotes</title><path fill="#fff" d="M15 9h-4v7h7V9c0-2.2-1.8-5-4-5h-2l1 2s2 0 2 3zM2 9v7h7V9c0-2.2-1.8-5-4-5H3l1 2s2 0 2 3H2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>quotes</title><path fill="#fff" d="M11 9v7h7V9c0-2.2-1.8-5-4-5h-2l1 2s2 0 2 3zM2 9v7h7V9c0-2.2-1.8-5-4-5H3l1 2s2 0 2 3z"/></svg>
\ No newline at end of file
index 63a7ce7..eb32248 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>quotes</title><path fill="#36c" d="M15 9h-4v7h7V9c0-2.2-1.8-5-4-5h-2l1 2s2 0 2 3zM2 9v7h7V9c0-2.2-1.8-5-4-5H3l1 2s2 0 2 3H2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>quotes</title><path fill="#36c" d="M11 9v7h7V9c0-2.2-1.8-5-4-5h-2l1 2s2 0 2 3zM2 9v7h7V9c0-2.2-1.8-5-4-5H3l1 2s2 0 2 3z"/></svg>
\ No newline at end of file
index 9741d1d..5605328 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>quotes</title><path d="M15 9h-4v7h7V9c0-2.2-1.8-5-4-5h-2l1 2s2 0 2 3zM2 9v7h7V9c0-2.2-1.8-5-4-5H3l1 2s2 0 2 3H2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>quotes</title><path d="M11 9v7h7V9c0-2.2-1.8-5-4-5h-2l1 2s2 0 2 3zM2 9v7h7V9c0-2.2-1.8-5-4-5H3l1 2s2 0 2 3z"/></svg>
\ No newline at end of file
index 5e09475..a036d29 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>redo</title><path fill="#fff" d="M19 8.5L12 3v11l7-5.5zM12 7v3h-1c-4 0-7 2-7 6v1H1v-1c0-6 5-9 10-9z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>redo</title><path fill="#fff" d="M19 8.5L12 3v11zM12 7v3h-1c-4 0-7 2-7 6v1H1v-1c0-6 5-9 10-9z"/></svg>
\ No newline at end of file
index ef12c25..dacd10a 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>redo</title><path fill="#36c" d="M19 8.5L12 3v11l7-5.5zM12 7v3h-1c-4 0-7 2-7 6v1H1v-1c0-6 5-9 10-9z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>redo</title><path fill="#36c" d="M19 8.5L12 3v11zM12 7v3h-1c-4 0-7 2-7 6v1H1v-1c0-6 5-9 10-9z"/></svg>
\ No newline at end of file
index 3543eea..97c3a3b 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>redo</title><path d="M19 8.5L12 3v11l7-5.5zM12 7v3h-1c-4 0-7 2-7 6v1H1v-1c0-6 5-9 10-9z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>redo</title><path d="M19 8.5L12 3v11zM12 7v3h-1c-4 0-7 2-7 6v1H1v-1c0-6 5-9 10-9z"/></svg>
\ No newline at end of file
index 00569fb..a079784 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>redo</title><path fill="#fff" d="M1 8.5L8 3v11L1 8.5zM8 7v3h1c4 0 7 2 7 6v1h3v-1c0-6-5-9-10-9z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>redo</title><path fill="#fff" d="M1 8.5L8 3v11zM8 7v3h1c4 0 7 2 7 6v1h3v-1c0-6-5-9-10-9z"/></svg>
\ No newline at end of file
index 45a654b..85e4d0a 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>redo</title><path fill="#36c" d="M1 8.5L8 3v11L1 8.5zM8 7v3h1c4 0 7 2 7 6v1h3v-1c0-6-5-9-10-9z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>redo</title><path fill="#36c" d="M1 8.5L8 3v11zM8 7v3h1c4 0 7 2 7 6v1h3v-1c0-6-5-9-10-9z"/></svg>
\ No newline at end of file
index cd8c70d..dc627cf 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>redo</title><path d="M1 8.5L8 3v11L1 8.5zM8 7v3h1c4 0 7 2 7 6v1h3v-1c0-6-5-9-10-9z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>redo</title><path d="M1 8.5L8 3v11zM8 7v3h1c4 0 7 2 7 6v1h3v-1c0-6-5-9-10-9z"/></svg>
\ No newline at end of file
index b0b6bd1..3915527 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>reference</title><path fill="#fff" d="M15 1v9l-2.78-2.78L9.44 10V1H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>reference</title><path fill="#fff" d="M15 10l-2.78-2.78L9.44 10V1H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
index a854dd0..0542626 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>reference</title><path fill="#36c" d="M15 1v9l-2.78-2.78L9.44 10V1H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>reference</title><path fill="#36c" d="M15 10l-2.78-2.78L9.44 10V1H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
index 6aab8f5..ef7c1b9 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>reference</title><path d="M15 1v9l-2.78-2.78L9.44 10V1H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>reference</title><path d="M15 10l-2.78-2.78L9.44 10V1H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
index b743725..ed0aa35 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>existing reference</title><g fill="#fff"><path d="M16 0v9l-2.8-2.8L10.4 9V0H7C5.9 0 5 .9 5 2v13c0 1.1.9 2 2 2h9c1.1 0 2-.9 2-2V2c0-1.1-.9-2-2-2z"/><path d="M4 4H2v14c0 1.1.9 2 2 2h11v-2H4z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>existing reference</title><g fill="#fff"><path d="M16 9l-2.8-2.8L10.4 9V0H7C5.9 0 5 .9 5 2v13c0 1.1.9 2 2 2h9c1.1 0 2-.9 2-2V2c0-1.1-.9-2-2-2z"/><path d="M4 4H2v14c0 1.1.9 2 2 2h11v-2H4z"/></g></svg>
\ No newline at end of file
index d07dbcc..7898e43 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>existing reference</title><g fill="#36c"><path d="M16 0v9l-2.8-2.8L10.4 9V0H7C5.9 0 5 .9 5 2v13c0 1.1.9 2 2 2h9c1.1 0 2-.9 2-2V2c0-1.1-.9-2-2-2z"/><path d="M4 4H2v14c0 1.1.9 2 2 2h11v-2H4z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>existing reference</title><g fill="#36c"><path d="M16 9l-2.8-2.8L10.4 9V0H7C5.9 0 5 .9 5 2v13c0 1.1.9 2 2 2h9c1.1 0 2-.9 2-2V2c0-1.1-.9-2-2-2z"/><path d="M4 4H2v14c0 1.1.9 2 2 2h11v-2H4z"/></g></svg>
\ No newline at end of file
index 5f7908a..e1e68cf 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>existing reference</title><path d="M16 0v9l-2.8-2.8L10.4 9V0H7C5.9 0 5 .9 5 2v13c0 1.1.9 2 2 2h9c1.1 0 2-.9 2-2V2c0-1.1-.9-2-2-2z"/><path d="M4 4H2v14c0 1.1.9 2 2 2h11v-2H4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>existing reference</title><path d="M16 9l-2.8-2.8L10.4 9V0H7C5.9 0 5 .9 5 2v13c0 1.1.9 2 2 2h9c1.1 0 2-.9 2-2V2c0-1.1-.9-2-2-2z"/><path d="M4 4H2v14c0 1.1.9 2 2 2h11v-2H4z"/></svg>
\ No newline at end of file
index 66eacb4..111056f 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>existing reference</title><g fill="#fff"><path d="M2 2v13c0 1.1.9 2 2 2h9c1.1 0 2-.9 2-2V2c0-1.1-.9-2-2-2v9l-2.8-2.8L7.4 9V0H4C2.4 0 2 1.6 2 2z"/><path d="M16 18H5v2h11c1.1 0 2-.9 2-2V4h-2z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>existing reference</title><g fill="#fff"><path d="M2 15c0 1.1.9 2 2 2h9c1.1 0 2-.9 2-2V2c0-1.1-.9-2-2-2v9l-2.8-2.8L7.4 9V0H4C2.4 0 2 1.6 2 2z"/><path d="M16 18H5v2h11c1.1 0 2-.9 2-2V4h-2z"/></g></svg>
\ No newline at end of file
index a2fe7a6..5a5d9d4 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>existing reference</title><g fill="#36c"><path d="M2 2v13c0 1.1.9 2 2 2h9c1.1 0 2-.9 2-2V2c0-1.1-.9-2-2-2v9l-2.8-2.8L7.4 9V0H4C2.4 0 2 1.6 2 2z"/><path d="M16 18H5v2h11c1.1 0 2-.9 2-2V4h-2z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>existing reference</title><g fill="#36c"><path d="M2 15c0 1.1.9 2 2 2h9c1.1 0 2-.9 2-2V2c0-1.1-.9-2-2-2v9l-2.8-2.8L7.4 9V0H4C2.4 0 2 1.6 2 2z"/><path d="M16 18H5v2h11c1.1 0 2-.9 2-2V4h-2z"/></g></svg>
\ No newline at end of file
index 808fd89..fcff3a9 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>existing reference</title><path d="M2 2v13c0 1.1.9 2 2 2h9c1.1 0 2-.9 2-2V2c0-1.1-.9-2-2-2v9l-2.8-2.8L7.4 9V0H4C2.4 0 2 1.6 2 2z"/><path d="M16 18H5v2h11c1.1 0 2-.9 2-2V4h-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>existing reference</title><path d="M2 15c0 1.1.9 2 2 2h9c1.1 0 2-.9 2-2V2c0-1.1-.9-2-2-2v9l-2.8-2.8L7.4 9V0H4C2.4 0 2 1.6 2 2z"/><path d="M16 18H5v2h11c1.1 0 2-.9 2-2V4h-2z"/></svg>
\ No newline at end of file
index 7d6fcac..cc2b27b 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>robot</title><path fill="#fff" d="M10.5 5h6.505C18.107 5 19 5.896 19 6.997V14h-7v2h5.005c1.102 0 1.995.888 1.995 2v2H1v-2c0-1.105.893-2 1.995-2H8v-2H1V6.997C1 5.894 1.893 5 2.995 5H9.5V2.915a1.5 1.5 0 1 1 1 0V5zm-4 6a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zm7 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>robot</title><path fill="#fff" d="M10.5 5h6.505C18.107 5 19 5.896 19 6.997V14h-7v2h5.005c1.102 0 1.995.888 1.995 2v2H1v-2c0-1.105.893-2 1.995-2H8v-2H1V6.997C1 5.894 1.893 5 2.995 5H9.5V2.915a1.5 1.5 0 1 1 1 0zm-4 6a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zm7 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z"/></svg>
\ No newline at end of file
index bef3c8a..20bc085 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>robot</title><path fill="#36c" d="M10.5 5h6.505C18.107 5 19 5.896 19 6.997V14h-7v2h5.005c1.102 0 1.995.888 1.995 2v2H1v-2c0-1.105.893-2 1.995-2H8v-2H1V6.997C1 5.894 1.893 5 2.995 5H9.5V2.915a1.5 1.5 0 1 1 1 0V5zm-4 6a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zm7 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>robot</title><path fill="#36c" d="M10.5 5h6.505C18.107 5 19 5.896 19 6.997V14h-7v2h5.005c1.102 0 1.995.888 1.995 2v2H1v-2c0-1.105.893-2 1.995-2H8v-2H1V6.997C1 5.894 1.893 5 2.995 5H9.5V2.915a1.5 1.5 0 1 1 1 0zm-4 6a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zm7 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z"/></svg>
\ No newline at end of file
index 6f1072b..498d3a3 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>robot</title><path d="M10.5 5h6.505C18.107 5 19 5.896 19 6.997V14h-7v2h5.005c1.102 0 1.995.888 1.995 2v2H1v-2c0-1.105.893-2 1.995-2H8v-2H1V6.997C1 5.894 1.893 5 2.995 5H9.5V2.915a1.5 1.5 0 1 1 1 0V5zm-4 6a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zm7 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>robot</title><path d="M10.5 5h6.505C18.107 5 19 5.896 19 6.997V14h-7v2h5.005c1.102 0 1.995.888 1.995 2v2H1v-2c0-1.105.893-2 1.995-2H8v-2H1V6.997C1 5.894 1.893 5 2.995 5H9.5V2.915a1.5 1.5 0 1 1 1 0zm-4 6a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zm7 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z"/></svg>
\ No newline at end of file
index 3cf5964..26d83fd 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/settings-invert.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/settings-invert.png differ
index 3fea1b9..18d7c79 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>settings</title><g fill="#fff"><path d="M10 2.5a7.5 7.5 0 1 0 7.5 7.5A7.5 7.5 0 0 0 10 2.5zm0 11a3.5 3.5 0 1 1 3.5-3.5 3.5 3.5 0 0 1-3.5 3.5z"/><path d="M12 3.29L11.5 0h-3L8 3.29a7 7 0 0 1 4 0zM8 16.71L8.5 20h3l.5-3.29a7 7 0 0 1-4 0zm8.16-10.04l2-2.68L16 1.87l-2.68 2a7 7 0 0 1 2.83 2.83zM3.84 13.33L1.87 16 4 18.13l2.68-2a7 7 0 0 1-2.83-2.83zM16.71 12l3.29-.5v-3L16.71 8a7 7 0 0 1 0 4zM3.29 8L0 8.5v3l3.29.5a7 7 0 0 1 0-4zm10.04 8.16l2.68 2L18.13 16l-2-2.68a7 7 0 0 1-2.83 2.83zM6.67 3.84L4 1.87 1.87 4l2 2.68a7 7 0 0 1 2.8-2.84z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>settings</title><g fill="#fff"><path d="M10 2.5a7.5 7.5 0 1 0 7.5 7.5A7.5 7.5 0 0 0 10 2.5zm0 11a3.5 3.5 0 1 1 3.5-3.5 3.5 3.5 0 0 1-3.5 3.5z"/><path d="M12.5 6.5l-1-6.5h-3l-1 6.5m0 7l1 6.5h3l1-6.5m1-1l6.5-1v-3l-6.5-1m-7 0L0 8.5v3l6.5 1m7.743-3.207l3.889-5.303-2.122-2.122-5.303 3.89m-4.95 4.95L1.868 16.01l2.122 2.122 5.303-3.89m0-8.485L3.99 1.868 1.868 3.99l3.89 5.303m4.95 4.95l5.302 3.889 2.122-2.122-3.89-5.303"/></g></svg>
\ No newline at end of file
index 9619646..933f8ce 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/settings-progressive.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/settings-progressive.png differ
index 50ce6a2..6ba9245 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>settings</title><g fill="#36c"><path d="M10 2.5a7.5 7.5 0 1 0 7.5 7.5A7.5 7.5 0 0 0 10 2.5zm0 11a3.5 3.5 0 1 1 3.5-3.5 3.5 3.5 0 0 1-3.5 3.5z"/><path d="M12 3.29L11.5 0h-3L8 3.29a7 7 0 0 1 4 0zM8 16.71L8.5 20h3l.5-3.29a7 7 0 0 1-4 0zm8.16-10.04l2-2.68L16 1.87l-2.68 2a7 7 0 0 1 2.83 2.83zM3.84 13.33L1.87 16 4 18.13l2.68-2a7 7 0 0 1-2.83-2.83zM16.71 12l3.29-.5v-3L16.71 8a7 7 0 0 1 0 4zM3.29 8L0 8.5v3l3.29.5a7 7 0 0 1 0-4zm10.04 8.16l2.68 2L18.13 16l-2-2.68a7 7 0 0 1-2.83 2.83zM6.67 3.84L4 1.87 1.87 4l2 2.68a7 7 0 0 1 2.8-2.84z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>settings</title><g fill="#36c"><path d="M10 2.5a7.5 7.5 0 1 0 7.5 7.5A7.5 7.5 0 0 0 10 2.5zm0 11a3.5 3.5 0 1 1 3.5-3.5 3.5 3.5 0 0 1-3.5 3.5z"/><path d="M12.5 6.5l-1-6.5h-3l-1 6.5m0 7l1 6.5h3l1-6.5m1-1l6.5-1v-3l-6.5-1m-7 0L0 8.5v3l6.5 1m7.743-3.207l3.889-5.303-2.122-2.122-5.303 3.89m-4.95 4.95L1.868 16.01l2.122 2.122 5.303-3.89m0-8.485L3.99 1.868 1.868 3.99l3.89 5.303m4.95 4.95l5.302 3.889 2.122-2.122-3.89-5.303"/></g></svg>
\ No newline at end of file
index 97e2bc9..8c8e16a 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/settings.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/settings.png differ
index bdc37cf..c58f812 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>settings</title><path d="M10 2.5a7.5 7.5 0 1 0 7.5 7.5A7.5 7.5 0 0 0 10 2.5zm0 11a3.5 3.5 0 1 1 3.5-3.5 3.5 3.5 0 0 1-3.5 3.5z"/><path d="M12 3.29L11.5 0h-3L8 3.29a7 7 0 0 1 4 0zM8 16.71L8.5 20h3l.5-3.29a7 7 0 0 1-4 0zm8.16-10.04l2-2.68L16 1.87l-2.68 2a7 7 0 0 1 2.83 2.83zM3.84 13.33L1.87 16 4 18.13l2.68-2a7 7 0 0 1-2.83-2.83zM16.71 12l3.29-.5v-3L16.71 8a7 7 0 0 1 0 4zM3.29 8L0 8.5v3l3.29.5a7 7 0 0 1 0-4zm10.04 8.16l2.68 2L18.13 16l-2-2.68a7 7 0 0 1-2.83 2.83zM6.67 3.84L4 1.87 1.87 4l2 2.68a7 7 0 0 1 2.8-2.84z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>settings</title><path d="M10 2.5a7.5 7.5 0 1 0 7.5 7.5A7.5 7.5 0 0 0 10 2.5zm0 11a3.5 3.5 0 1 1 3.5-3.5 3.5 3.5 0 0 1-3.5 3.5z"/><path d="M12.5 6.5l-1-6.5h-3l-1 6.5m0 7l1 6.5h3l1-6.5m1-1l6.5-1v-3l-6.5-1m-7 0L0 8.5v3l6.5 1m7.743-3.207l3.889-5.303-2.122-2.122-5.303 3.89m-4.95 4.95L1.868 16.01l2.122 2.122 5.303-3.89m0-8.485L3.99 1.868 1.868 3.99l3.89 5.303m4.95 4.95l5.302 3.889 2.122-2.122-3.89-5.303"/></svg>
\ No newline at end of file
index ef33db2..f615042 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>smaller</title><path fill="#fff" d="M12 16h-1.05a.44.44 0 0 1-.29-.09.58.58 0 0 1-.17-.22l-.7-1.84H6.2l-.7 1.84a.56.56 0 0 1-.16.21.43.43 0 0 1-.29.1H4l3.31-8.35h1.38zm-2.57-3.13L8.28 9.82a8.5 8.5 0 0 1-.28-.9q-.06.27-.14.5l-.14.4-1.15 3zM15 6l3-4h-6l3 4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>smaller</title><path fill="#fff" d="M12 16h-1.05a.44.44 0 0 1-.29-.09.58.58 0 0 1-.17-.22l-.7-1.84H6.2l-.7 1.84a.56.56 0 0 1-.16.21.43.43 0 0 1-.29.1H4l3.31-8.35h1.38zm-2.57-3.13L8.28 9.82a8.5 8.5 0 0 1-.28-.9q-.06.27-.14.5l-.14.4-1.15 3zM15 6l3-4h-6z"/></svg>
\ No newline at end of file
index ee35f8f..0ced2c0 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>smaller</title><path fill="#36c" d="M12 16h-1.05a.44.44 0 0 1-.29-.09.58.58 0 0 1-.17-.22l-.7-1.84H6.2l-.7 1.84a.56.56 0 0 1-.16.21.43.43 0 0 1-.29.1H4l3.31-8.35h1.38zm-2.57-3.13L8.28 9.82a8.5 8.5 0 0 1-.28-.9q-.06.27-.14.5l-.14.4-1.15 3zM15 6l3-4h-6l3 4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>smaller</title><path fill="#36c" d="M12 16h-1.05a.44.44 0 0 1-.29-.09.58.58 0 0 1-.17-.22l-.7-1.84H6.2l-.7 1.84a.56.56 0 0 1-.16.21.43.43 0 0 1-.29.1H4l3.31-8.35h1.38zm-2.57-3.13L8.28 9.82a8.5 8.5 0 0 1-.28-.9q-.06.27-.14.5l-.14.4-1.15 3zM15 6l3-4h-6z"/></svg>
\ No newline at end of file
index e498829..94203dc 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>smaller</title><path d="M12 16h-1.05a.44.44 0 0 1-.29-.09.58.58 0 0 1-.17-.22l-.7-1.84H6.2l-.7 1.84a.56.56 0 0 1-.16.21.43.43 0 0 1-.29.1H4l3.31-8.35h1.38zm-2.57-3.13L8.28 9.82a8.5 8.5 0 0 1-.28-.9q-.06.27-.14.5l-.14.4-1.15 3zM15 6l3-4h-6l3 4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>smaller</title><path d="M12 16h-1.05a.44.44 0 0 1-.29-.09.58.58 0 0 1-.17-.22l-.7-1.84H6.2l-.7 1.84a.56.56 0 0 1-.16.21.43.43 0 0 1-.29.1H4l3.31-8.35h1.38zm-2.57-3.13L8.28 9.82a8.5 8.5 0 0 1-.28-.9q-.06.27-.14.5l-.14.4-1.15 3zM15 6l3-4h-6z"/></svg>
\ No newline at end of file
index b7cbf41..aa7d64b 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-ltr-invert.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-ltr-invert.png differ
index 74204f1..585a5de 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubble</title><path fill="#fff" d="M18 0H2a2 2 0 0 0-2 2v18l4-4h14a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubble</title><g fill="#fff"><path d="M6 14H0v6z"/><rect width="20" height="16" rx="2"/></g></svg>
\ No newline at end of file
index 9b60865..2e2bb83 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-ltr-progressive.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-ltr-progressive.png differ
index ad6c192..d608028 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubble</title><path fill="#36c" d="M18 0H2a2 2 0 0 0-2 2v18l4-4h14a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubble</title><g fill="#36c"><path d="M6 14H0v6z"/><rect width="20" height="16" rx="2"/></g></svg>
\ No newline at end of file
index ffa7c74..5cbcb90 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-ltr.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-ltr.png differ
index 0b55276..750767a 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubble</title><path d="M18 0H2a2 2 0 0 0-2 2v18l4-4h14a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubble</title><path d="M6 14H0v6z"/><rect width="20" height="16" rx="2"/></svg>
\ No newline at end of file
index 54312a5..ec5232c 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-rtl-invert.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-rtl-invert.png differ
index 590a316..c171c5f 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubble</title><path fill="#fff" d="M0 2v12c0 1.1.9 2 2 2h14l4 4V2c0-1.1-.9-2-2-2H2C.9 0 0 .9 0 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubble</title><g fill="#fff"><path d="M14 14h6v6z"/><rect width="20" height="16" rx="2"/></g></svg>
\ No newline at end of file
index c5019da..e1c4cbf 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-rtl-progressive.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-rtl-progressive.png differ
index 4a29ccf..133358f 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubble</title><path fill="#36c" d="M0 2v12c0 1.1.9 2 2 2h14l4 4V2c0-1.1-.9-2-2-2H2C.9 0 0 .9 0 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubble</title><g fill="#36c"><path d="M14 14h6v6z"/><rect width="20" height="16" rx="2"/></g></svg>
\ No newline at end of file
index 18d20de..c16b560 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-rtl.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubble-rtl.png differ
index eae7171..c3f3095 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubble</title><path d="M0 2v12c0 1.1.9 2 2 2h14l4 4V2c0-1.1-.9-2-2-2H2C.9 0 0 .9 0 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubble</title><path d="M14 14h6v6z"/><rect width="20" height="16" rx="2"/></svg>
\ No newline at end of file
index 58f9c0b..102881c 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add speech bubble</title><path fill="#fff" d="M17 1H3a2 2 0 0 0-2 2v16l4-4h12a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm-2 8h-4v4H9V9H5V7h4V3h2v4h4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add speech bubble</title><path fill="#fff" d="M3 1a2 2 0 0 0-2 2v16l4-4h12a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm12 8h-4v4H9V9H5V7h4V3h2v4h4z"/></svg>
\ No newline at end of file
index 1d7e3ab..4c22e79 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add speech bubble</title><path fill="#36c" d="M17 1H3a2 2 0 0 0-2 2v16l4-4h12a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm-2 8h-4v4H9V9H5V7h4V3h2v4h4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add speech bubble</title><path fill="#36c" d="M3 1a2 2 0 0 0-2 2v16l4-4h12a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm12 8h-4v4H9V9H5V7h4V3h2v4h4z"/></svg>
\ No newline at end of file
index ed3dc5a..67351e6 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add speech bubble</title><path d="M17 1H3a2 2 0 0 0-2 2v16l4-4h12a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm-2 8h-4v4H9V9H5V7h4V3h2v4h4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add speech bubble</title><path d="M3 1a2 2 0 0 0-2 2v16l4-4h12a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm12 8h-4v4H9V9H5V7h4V3h2v4h4z"/></svg>
\ No newline at end of file
index de48255..3755f4f 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add speech bubble</title><path fill="#fff" d="M1 3v10c0 1.1.9 2 2 2h12l4 4V3c0-1.1-.9-2-2-2H3c-1.1 0-2 .9-2 2zm4 4h4V3h2v4h4v2h-4v4H9V9H5V7z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add speech bubble</title><path fill="#fff" d="M1 3v10c0 1.1.9 2 2 2h12l4 4V3c0-1.1-.9-2-2-2H3c-1.1 0-2 .9-2 2zm4 4h4V3h2v4h4v2h-4v4H9V9H5z"/></svg>
\ No newline at end of file
index db6c3bd..358222b 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add speech bubble</title><path fill="#36c" d="M1 3v10c0 1.1.9 2 2 2h12l4 4V3c0-1.1-.9-2-2-2H3c-1.1 0-2 .9-2 2zm4 4h4V3h2v4h4v2h-4v4H9V9H5V7z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add speech bubble</title><path fill="#36c" d="M1 3v10c0 1.1.9 2 2 2h12l4 4V3c0-1.1-.9-2-2-2H3c-1.1 0-2 .9-2 2zm4 4h4V3h2v4h4v2h-4v4H9V9H5z"/></svg>
\ No newline at end of file
index ac5a8f7..3c6aad2 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add speech bubble</title><path d="M1 3v10c0 1.1.9 2 2 2h12l4 4V3c0-1.1-.9-2-2-2H3c-1.1 0-2 .9-2 2zm4 4h4V3h2v4h4v2h-4v4H9V9H5V7z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add speech bubble</title><path d="M1 3v10c0 1.1.9 2 2 2h12l4 4V3c0-1.1-.9-2-2-2H3c-1.1 0-2 .9-2 2zm4 4h4V3h2v4h4v2h-4v4H9V9H5z"/></svg>
\ No newline at end of file
index 71e8147..a0cb357 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-ltr-invert.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-ltr-invert.png differ
index 3008518..197c0ac 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubbles</title><g fill="#fff"><path d="M18 4h-1v7a2 2 0 0 1-2 2H4v1a2 2 0 0 0 2 2h10l4 4V6a2 2 0 0 0-2-2z"/><path d="M14 0H2a2 2 0 0 0-2 2v14l4-4h10a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubbles</title><g fill="#fff"><path d="M17 4v7a2 2 0 0 1-2 2H4v1a2 2 0 0 0 2 2h10l4 4V6a2 2 0 0 0-2-2zM6 10H0v6z"/><rect width="16" height="12" rx="2"/></g></svg>
\ No newline at end of file
index 3a8911c..1424b22 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-ltr-progressive.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-ltr-progressive.png differ
index 53e111f..5d02383 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubbles</title><g fill="#36c"><path d="M18 4h-1v7a2 2 0 0 1-2 2H4v1a2 2 0 0 0 2 2h10l4 4V6a2 2 0 0 0-2-2z"/><path d="M14 0H2a2 2 0 0 0-2 2v14l4-4h10a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubbles</title><g fill="#36c"><path d="M17 4v7a2 2 0 0 1-2 2H4v1a2 2 0 0 0 2 2h10l4 4V6a2 2 0 0 0-2-2zM6 10H0v6z"/><rect width="16" height="12" rx="2"/></g></svg>
\ No newline at end of file
index 7461cef..09f6008 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-ltr.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-ltr.png differ
index eb1a817..d738920 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubbles</title><path d="M18 4h-1v7a2 2 0 0 1-2 2H4v1a2 2 0 0 0 2 2h10l4 4V6a2 2 0 0 0-2-2z"/><path d="M14 0H2a2 2 0 0 0-2 2v14l4-4h10a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubbles</title><path d="M17 4v7a2 2 0 0 1-2 2H4v1a2 2 0 0 0 2 2h10l4 4V6a2 2 0 0 0-2-2zM6 10H0v6z"/><rect width="16" height="12" rx="2"/></svg>
\ No newline at end of file
index 15e6fd1..39ccc22 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-rtl-invert.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-rtl-invert.png differ
index 954fde0..ceb9e2f 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubbles</title><g fill="#fff"><path d="M0 6v14l4-4h10c1.1 0 2-.9 2-2v-1H5c-1.1 0-2-.9-2-2V4H2C.9 4 0 4.9 0 6z"/><path d="M4 2v8c0 1.1.9 2 2 2h10l4 4V2c0-1.1-.9-2-2-2H6C4.9 0 4 .9 4 2z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubbles</title><g fill="#fff"><path d="M0 20l4-4h10c1.1 0 2-.9 2-2v-1H5c-1.1 0-2-.9-2-2V4H2C.9 4 0 4.9 0 6zm14-10h6v6z"/><rect width="16" height="12" x="4" rx="2"/></g></svg>
\ No newline at end of file
index de49d4a..2013f44 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-rtl-progressive.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-rtl-progressive.png differ
index 6fbd55c..d36b28d 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubbles</title><g fill="#36c"><path d="M0 6v14l4-4h10c1.1 0 2-.9 2-2v-1H5c-1.1 0-2-.9-2-2V4H2C.9 4 0 4.9 0 6z"/><path d="M4 2v8c0 1.1.9 2 2 2h10l4 4V2c0-1.1-.9-2-2-2H6C4.9 0 4 .9 4 2z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubbles</title><g fill="#36c"><path d="M0 20l4-4h10c1.1 0 2-.9 2-2v-1H5c-1.1 0-2-.9-2-2V4H2C.9 4 0 4.9 0 6zm14-10h6v6z"/><rect width="16" height="12" x="4" rx="2"/></g></svg>
\ No newline at end of file
index ad8958a..c5951df 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-rtl.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/speechBubbles-rtl.png differ
index a816817..32d7302 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubbles</title><path d="M0 6v14l4-4h10c1.1 0 2-.9 2-2v-1H5c-1.1 0-2-.9-2-2V4H2C.9 4 0 4.9 0 6z"/><path d="M4 2v8c0 1.1.9 2 2 2h10l4 4V2c0-1.1-.9-2-2-2H6C4.9 0 4 .9 4 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>speech bubbles</title><path d="M0 20l4-4h10c1.1 0 2-.9 2-2v-1H5c-1.1 0-2-.9-2-2V4H2C.9 4 0 4.9 0 6zm14-10h6v6z"/><rect width="16" height="12" x="4" rx="2"/></svg>
\ No newline at end of file
index 1e09d18..aa145c8 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>strikethrough</title><path fill="#fff" d="M8.285 2L5.928 8H8.59L10 3.979 11.41 8h2.662l-2.357-6h-3.43zM1 10v2h3.357L2 18h3.06l1.622-4.566h6.636L14.94 18H18l-2.357-6H19v-2H1z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>strikethrough</title><path fill="#fff" d="M5.928 8H8.59L10 3.979 11.41 8h2.662l-2.357-6h-3.43zM1 10v2h3.357L2 18h3.06l1.622-4.566h6.636L14.94 18H18l-2.357-6H19v-2z"/></svg>
\ No newline at end of file
index bb9cf1a..f13286d 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>strikethrough</title><path fill="#36c" d="M8.285 2L5.928 8H8.59L10 3.979 11.41 8h2.662l-2.357-6h-3.43zM1 10v2h3.357L2 18h3.06l1.622-4.566h6.636L14.94 18H18l-2.357-6H19v-2H1z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>strikethrough</title><path fill="#36c" d="M5.928 8H8.59L10 3.979 11.41 8h2.662l-2.357-6h-3.43zM1 10v2h3.357L2 18h3.06l1.622-4.566h6.636L14.94 18H18l-2.357-6H19v-2z"/></svg>
\ No newline at end of file
index f9f5d04..acf4205 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>strikethrough</title><path d="M8.285 2L5.928 8H8.59L10 3.979 11.41 8h2.662l-2.357-6h-3.43zM1 10v2h3.357L2 18h3.06l1.622-4.566h6.636L14.94 18H18l-2.357-6H19v-2H1z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>strikethrough</title><path d="M5.928 8H8.59L10 3.979 11.41 8h2.662l-2.357-6h-3.43zM1 10v2h3.357L2 18h3.06l1.622-4.566h6.636L14.94 18H18l-2.357-6H19v-2z"/></svg>
\ No newline at end of file
index 7ec7023..416943d 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>strikethrough</title><path d="M3.334 2l4.004 6h2.29L5.634 2h-2.3zm11.033 0l-3.969 6h2.264l4.004-6h-2.299zM1 10v2h7.926v6h2.148v-6H19v-2H1z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><title>strikethrough</title><path d="M7.338 8h2.29L5.634 2h-2.3zm3.06 0h2.264l4.004-6h-2.299zM1 10v2h7.926v6h2.148v-6H19v-2z"/></g></svg>
\ No newline at end of file
index f3707a8..6e84c3a 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>strikethrough</title><path d="M3.334 2l4.004 6h2.29L5.634 2h-2.3zm11.033 0l-3.969 6h2.264l4.004-6h-2.299zM1 10v2h7.926v6h2.148v-6H19v-2H1z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><g fill="#36c"><title>strikethrough</title><path d="M7.338 8h2.29L5.634 2h-2.3zm3.06 0h2.264l4.004-6h-2.299zM1 10v2h7.926v6h2.148v-6H19v-2z"/></g></svg>
\ No newline at end of file
index 045f04f..e5e76f2 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>strikethrough</title><path d="M3.334 2l4.004 6h2.29L5.634 2h-2.3zm11.033 0l-3.969 6h2.264l4.004-6h-2.299zM1 10v2h7.926v6h2.148v-6H19v-2H1z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>strikethrough</title><path d="M7.338 8h2.29L5.634 2h-2.3zm3.06 0h2.264l4.004-6h-2.299zM1 10v2h7.926v6h2.148v-6H19v-2z"/></svg>
\ No newline at end of file
index 37577c7..40aeb2d 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>subscript</title><path fill="#fff" d="M10.5 9.7L6.5 4h2.3c.3 0 .5.2.6.4l2.3 3.5c.1.2.3.5.3.7l2.8-4.2c.1-.1.1-.2.2-.3.1-.1.3-.1.4-.1h2.4l-4 5.8L18 16h-2.3c-.2 0-.3 0-.4-.1l-.3-.3-2.5-3.8c-.1-.2-.2-.4-.3-.7l-2.8 4.4-.3.3c0 .2-.2.2-.4.2H6.3l4.2-6.3zM3 12.5v6c0 .3-.2.5-.5.5H2v1h.5c.4 0 .7-.1 1-.4.3.2.6.4 1 .4H5v-1h-.5c-.3 0-.5-.2-.5-.5v-6c0-.3.2-.5.5-.5H5v-1h-.5c-.4 0-.7.1-1 .4-.3-.2-.6-.4-1-.4H2v1h.5c.3 0 .5.2.5.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>subscript</title><path fill="#fff" d="M10.5 9.7L6.5 4h2.3c.3 0 .5.2.6.4l2.3 3.5c.1.2.3.5.3.7l2.8-4.2c.1-.1.1-.2.2-.3.1-.1.3-.1.4-.1h2.4l-4 5.8L18 16h-2.3c-.2 0-.3 0-.4-.1l-.3-.3-2.5-3.8c-.1-.2-.2-.4-.3-.7l-2.8 4.4-.3.3c0 .2-.2.2-.4.2H6.3zM3 18.5c0 .3-.2.5-.5.5H2v1h.5c.4 0 .7-.1 1-.4.3.2.6.4 1 .4H5v-1h-.5c-.3 0-.5-.2-.5-.5v-6c0-.3.2-.5.5-.5H5v-1h-.5c-.4 0-.7.1-1 .4-.3-.2-.6-.4-1-.4H2v1h.5c.3 0 .5.2.5.5z"/></svg>
\ No newline at end of file
index 1d52184..de4fe27 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>subscript</title><path fill="#36c" d="M10.5 9.7L6.5 4h2.3c.3 0 .5.2.6.4l2.3 3.5c.1.2.3.5.3.7l2.8-4.2c.1-.1.1-.2.2-.3.1-.1.3-.1.4-.1h2.4l-4 5.8L18 16h-2.3c-.2 0-.3 0-.4-.1l-.3-.3-2.5-3.8c-.1-.2-.2-.4-.3-.7l-2.8 4.4-.3.3c0 .2-.2.2-.4.2H6.3l4.2-6.3zM3 12.5v6c0 .3-.2.5-.5.5H2v1h.5c.4 0 .7-.1 1-.4.3.2.6.4 1 .4H5v-1h-.5c-.3 0-.5-.2-.5-.5v-6c0-.3.2-.5.5-.5H5v-1h-.5c-.4 0-.7.1-1 .4-.3-.2-.6-.4-1-.4H2v1h.5c.3 0 .5.2.5.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>subscript</title><path fill="#36c" d="M10.5 9.7L6.5 4h2.3c.3 0 .5.2.6.4l2.3 3.5c.1.2.3.5.3.7l2.8-4.2c.1-.1.1-.2.2-.3.1-.1.3-.1.4-.1h2.4l-4 5.8L18 16h-2.3c-.2 0-.3 0-.4-.1l-.3-.3-2.5-3.8c-.1-.2-.2-.4-.3-.7l-2.8 4.4-.3.3c0 .2-.2.2-.4.2H6.3zM3 18.5c0 .3-.2.5-.5.5H2v1h.5c.4 0 .7-.1 1-.4.3.2.6.4 1 .4H5v-1h-.5c-.3 0-.5-.2-.5-.5v-6c0-.3.2-.5.5-.5H5v-1h-.5c-.4 0-.7.1-1 .4-.3-.2-.6-.4-1-.4H2v1h.5c.3 0 .5.2.5.5z"/></svg>
\ No newline at end of file
index 80a1468..80e9319 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>subscript</title><path d="M10.5 9.7L6.5 4h2.3c.3 0 .5.2.6.4l2.3 3.5c.1.2.3.5.3.7l2.8-4.2c.1-.1.1-.2.2-.3.1-.1.3-.1.4-.1h2.4l-4 5.8L18 16h-2.3c-.2 0-.3 0-.4-.1l-.3-.3-2.5-3.8c-.1-.2-.2-.4-.3-.7l-2.8 4.4-.3.3c0 .2-.2.2-.4.2H6.3l4.2-6.3zM3 12.5v6c0 .3-.2.5-.5.5H2v1h.5c.4 0 .7-.1 1-.4.3.2.6.4 1 .4H5v-1h-.5c-.3 0-.5-.2-.5-.5v-6c0-.3.2-.5.5-.5H5v-1h-.5c-.4 0-.7.1-1 .4-.3-.2-.6-.4-1-.4H2v1h.5c.3 0 .5.2.5.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>subscript</title><path d="M10.5 9.7L6.5 4h2.3c.3 0 .5.2.6.4l2.3 3.5c.1.2.3.5.3.7l2.8-4.2c.1-.1.1-.2.2-.3.1-.1.3-.1.4-.1h2.4l-4 5.8L18 16h-2.3c-.2 0-.3 0-.4-.1l-.3-.3-2.5-3.8c-.1-.2-.2-.4-.3-.7l-2.8 4.4-.3.3c0 .2-.2.2-.4.2H6.3zM3 18.5c0 .3-.2.5-.5.5H2v1h.5c.4 0 .7-.1 1-.4.3.2.6.4 1 .4H5v-1h-.5c-.3 0-.5-.2-.5-.5v-6c0-.3.2-.5.5-.5H5v-1h-.5c-.4 0-.7.1-1 .4-.3-.2-.6-.4-1-.4H2v1h.5c.3 0 .5.2.5.5z"/></svg>
\ No newline at end of file
index b0006cf..473ef32 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>superscript</title><path fill="#fff" d="M17.5 1h.5V0h-.5a1.49 1.49 0 0 0-1 .39 1.49 1.49 0 0 0-1-.39H15v1h.5a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-.5.5H15v1h.5a1.49 1.49 0 0 0 1-.39 1.49 1.49 0 0 0 1 .39h.5V8h-.5a.5.5 0 0 1-.5-.5v-6a.5.5 0 0 1 .5-.5zm-3.82 15h-2.42a.67.67 0 0 1-.46-.15 1.33 1.33 0 0 1-.28-.34l-2.77-4.44a2.65 2.65 0 0 1-.28.69L5 15.51a2.22 2.22 0 0 1-.29.34.58.58 0 0 1-.42.15H2l4.15-6.19L2.17 4h2.42a.81.81 0 0 1 .41.09.8.8 0 0 1 .24.26L8 8.59a2.71 2.71 0 0 1 .33-.74L10.6 4.4a.69.69 0 0 1 .6-.4h2.32l-4 5.71z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>superscript</title><path fill="#fff" d="M18 1V0h-.5a1.49 1.49 0 0 0-1 .39 1.49 1.49 0 0 0-1-.39H15v1h.5a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-.5.5H15v1h.5a1.49 1.49 0 0 0 1-.39 1.49 1.49 0 0 0 1 .39h.5V8h-.5a.5.5 0 0 1-.5-.5v-6a.5.5 0 0 1 .5-.5zm-4.32 15h-2.42a.67.67 0 0 1-.46-.15 1.33 1.33 0 0 1-.28-.34l-2.77-4.44a2.65 2.65 0 0 1-.28.69L5 15.51a2.22 2.22 0 0 1-.29.34.58.58 0 0 1-.42.15H2l4.15-6.19L2.17 4h2.42a.81.81 0 0 1 .41.09.8.8 0 0 1 .24.26L8 8.59a2.71 2.71 0 0 1 .33-.74L10.6 4.4a.69.69 0 0 1 .6-.4h2.32l-4 5.71z"/></svg>
\ No newline at end of file
index 095bd6a..4e31a3d 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>superscript</title><path fill="#36c" d="M17.5 1h.5V0h-.5a1.49 1.49 0 0 0-1 .39 1.49 1.49 0 0 0-1-.39H15v1h.5a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-.5.5H15v1h.5a1.49 1.49 0 0 0 1-.39 1.49 1.49 0 0 0 1 .39h.5V8h-.5a.5.5 0 0 1-.5-.5v-6a.5.5 0 0 1 .5-.5zm-3.82 15h-2.42a.67.67 0 0 1-.46-.15 1.33 1.33 0 0 1-.28-.34l-2.77-4.44a2.65 2.65 0 0 1-.28.69L5 15.51a2.22 2.22 0 0 1-.29.34.58.58 0 0 1-.42.15H2l4.15-6.19L2.17 4h2.42a.81.81 0 0 1 .41.09.8.8 0 0 1 .24.26L8 8.59a2.71 2.71 0 0 1 .33-.74L10.6 4.4a.69.69 0 0 1 .6-.4h2.32l-4 5.71z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>superscript</title><path fill="#36c" d="M18 1V0h-.5a1.49 1.49 0 0 0-1 .39 1.49 1.49 0 0 0-1-.39H15v1h.5a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-.5.5H15v1h.5a1.49 1.49 0 0 0 1-.39 1.49 1.49 0 0 0 1 .39h.5V8h-.5a.5.5 0 0 1-.5-.5v-6a.5.5 0 0 1 .5-.5zm-4.32 15h-2.42a.67.67 0 0 1-.46-.15 1.33 1.33 0 0 1-.28-.34l-2.77-4.44a2.65 2.65 0 0 1-.28.69L5 15.51a2.22 2.22 0 0 1-.29.34.58.58 0 0 1-.42.15H2l4.15-6.19L2.17 4h2.42a.81.81 0 0 1 .41.09.8.8 0 0 1 .24.26L8 8.59a2.71 2.71 0 0 1 .33-.74L10.6 4.4a.69.69 0 0 1 .6-.4h2.32l-4 5.71z"/></svg>
\ No newline at end of file
index ef58222..79c1317 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>superscript</title><path d="M17.5 1h.5V0h-.5a1.49 1.49 0 0 0-1 .39 1.49 1.49 0 0 0-1-.39H15v1h.5a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-.5.5H15v1h.5a1.49 1.49 0 0 0 1-.39 1.49 1.49 0 0 0 1 .39h.5V8h-.5a.5.5 0 0 1-.5-.5v-6a.5.5 0 0 1 .5-.5zm-3.82 15h-2.42a.67.67 0 0 1-.46-.15 1.33 1.33 0 0 1-.28-.34l-2.77-4.44a2.65 2.65 0 0 1-.28.69L5 15.51a2.22 2.22 0 0 1-.29.34.58.58 0 0 1-.42.15H2l4.15-6.19L2.17 4h2.42a.81.81 0 0 1 .41.09.8.8 0 0 1 .24.26L8 8.59a2.71 2.71 0 0 1 .33-.74L10.6 4.4a.69.69 0 0 1 .6-.4h2.32l-4 5.71z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>superscript</title><path d="M18 1V0h-.5a1.49 1.49 0 0 0-1 .39 1.49 1.49 0 0 0-1-.39H15v1h.5a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-.5.5H15v1h.5a1.49 1.49 0 0 0 1-.39 1.49 1.49 0 0 0 1 .39h.5V8h-.5a.5.5 0 0 1-.5-.5v-6a.5.5 0 0 1 .5-.5zm-4.32 15h-2.42a.67.67 0 0 1-.46-.15 1.33 1.33 0 0 1-.28-.34l-2.77-4.44a2.65 2.65 0 0 1-.28.69L5 15.51a2.22 2.22 0 0 1-.29.34.58.58 0 0 1-.42.15H2l4.15-6.19L2.17 4h2.42a.81.81 0 0 1 .41.09.8.8 0 0 1 .24.26L8 8.59a2.71 2.71 0 0 1 .33-.74L10.6 4.4a.69.69 0 0 1 .6-.4h2.32l-4 5.71z"/></svg>
\ No newline at end of file
index 051d732..16c0a06 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>superscript</title><path fill="#fff" d="M3 1.5v6c0 .3-.2.5-.5.5H2v1h.5c.4 0 .7-.1 1-.4.3.3.6.4 1 .4H5V8h-.5c-.3 0-.5-.2-.5-.5v-6c0-.3.2-.5.5-.5H5V0h-.5c-.4 0-.7.1-1 .4-.3-.3-.6-.4-1-.4H2v1h.5c.3 0 .5.2.5.5zm7.5 8.2L6.5 4h2.3c.3 0 .5.2.6.4l2.3 3.5c.1.2.3.5.3.7l2.8-4.2c.1-.1.1-.2.2-.3.1-.1.3-.1.4-.1h2.4l-4 5.8L18 16h-2.3c-.2 0-.3 0-.4-.1l-.3-.3-2.5-3.8c-.1-.2-.2-.4-.3-.7l-2.8 4.4-.3.3c0 .2-.2.2-.4.2H6.3l4.2-6.3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>superscript</title><path fill="#fff" d="M3 7.5c0 .3-.2.5-.5.5H2v1h.5c.4 0 .7-.1 1-.4.3.3.6.4 1 .4H5V8h-.5c-.3 0-.5-.2-.5-.5v-6c0-.3.2-.5.5-.5H5V0h-.5c-.4 0-.7.1-1 .4-.3-.3-.6-.4-1-.4H2v1h.5c.3 0 .5.2.5.5zm7.5 2.2L6.5 4h2.3c.3 0 .5.2.6.4l2.3 3.5c.1.2.3.5.3.7l2.8-4.2c.1-.1.1-.2.2-.3.1-.1.3-.1.4-.1h2.4l-4 5.8L18 16h-2.3c-.2 0-.3 0-.4-.1l-.3-.3-2.5-3.8c-.1-.2-.2-.4-.3-.7l-2.8 4.4-.3.3c0 .2-.2.2-.4.2H6.3z"/></svg>
\ No newline at end of file
index e31ba3e..9f396a1 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>superscript</title><path fill="#36c" d="M3 1.5v6c0 .3-.2.5-.5.5H2v1h.5c.4 0 .7-.1 1-.4.3.3.6.4 1 .4H5V8h-.5c-.3 0-.5-.2-.5-.5v-6c0-.3.2-.5.5-.5H5V0h-.5c-.4 0-.7.1-1 .4-.3-.3-.6-.4-1-.4H2v1h.5c.3 0 .5.2.5.5zm7.5 8.2L6.5 4h2.3c.3 0 .5.2.6.4l2.3 3.5c.1.2.3.5.3.7l2.8-4.2c.1-.1.1-.2.2-.3.1-.1.3-.1.4-.1h2.4l-4 5.8L18 16h-2.3c-.2 0-.3 0-.4-.1l-.3-.3-2.5-3.8c-.1-.2-.2-.4-.3-.7l-2.8 4.4-.3.3c0 .2-.2.2-.4.2H6.3l4.2-6.3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>superscript</title><path fill="#36c" d="M3 7.5c0 .3-.2.5-.5.5H2v1h.5c.4 0 .7-.1 1-.4.3.3.6.4 1 .4H5V8h-.5c-.3 0-.5-.2-.5-.5v-6c0-.3.2-.5.5-.5H5V0h-.5c-.4 0-.7.1-1 .4-.3-.3-.6-.4-1-.4H2v1h.5c.3 0 .5.2.5.5zm7.5 2.2L6.5 4h2.3c.3 0 .5.2.6.4l2.3 3.5c.1.2.3.5.3.7l2.8-4.2c.1-.1.1-.2.2-.3.1-.1.3-.1.4-.1h2.4l-4 5.8L18 16h-2.3c-.2 0-.3 0-.4-.1l-.3-.3-2.5-3.8c-.1-.2-.2-.4-.3-.7l-2.8 4.4-.3.3c0 .2-.2.2-.4.2H6.3z"/></svg>
\ No newline at end of file
index 51659b9..14ed9be 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>superscript</title><path d="M3 1.5v6c0 .3-.2.5-.5.5H2v1h.5c.4 0 .7-.1 1-.4.3.3.6.4 1 .4H5V8h-.5c-.3 0-.5-.2-.5-.5v-6c0-.3.2-.5.5-.5H5V0h-.5c-.4 0-.7.1-1 .4-.3-.3-.6-.4-1-.4H2v1h.5c.3 0 .5.2.5.5zm7.5 8.2L6.5 4h2.3c.3 0 .5.2.6.4l2.3 3.5c.1.2.3.5.3.7l2.8-4.2c.1-.1.1-.2.2-.3.1-.1.3-.1.4-.1h2.4l-4 5.8L18 16h-2.3c-.2 0-.3 0-.4-.1l-.3-.3-2.5-3.8c-.1-.2-.2-.4-.3-.7l-2.8 4.4-.3.3c0 .2-.2.2-.4.2H6.3l4.2-6.3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>superscript</title><path d="M3 7.5c0 .3-.2.5-.5.5H2v1h.5c.4 0 .7-.1 1-.4.3.3.6.4 1 .4H5V8h-.5c-.3 0-.5-.2-.5-.5v-6c0-.3.2-.5.5-.5H5V0h-.5c-.4 0-.7.1-1 .4-.3-.3-.6-.4-1-.4H2v1h.5c.3 0 .5.2.5.5zm7.5 2.2L6.5 4h2.3c.3 0 .5.2.6.4l2.3 3.5c.1.2.3.5.3.7l2.8-4.2c.1-.1.1-.2.2-.3.1-.1.3-.1.4-.1h2.4l-4 5.8L18 16h-2.3c-.2 0-.3 0-.4-.1l-.3-.3-2.5-3.8c-.1-.2-.2-.4-.3-.7l-2.8 4.4-.3.3c0 .2-.2.2-.4.2H6.3z"/></svg>
\ No newline at end of file
index 17e2023..85eaef1 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/table-invert.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/table-invert.png differ
index 831ab0b..886b78b 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table</title><path fill="#fff" d="M19.66 2.88a2 2 0 0 0-.54-.54A2 2 0 0 0 18 2H2a2 2 0 0 0-1.12.34 2 2 0 0 0-.54.54A2 2 0 0 0 0 4v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-.34-1.12zM2 6h7v4H2zm0 10v-4h7v4zm16 0h-7v-4h7zm0-6h-7V6h7z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table</title><path fill="#fff" d="M2 2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 4h7v4H2zm0 10v-4h7v4zm16 0h-7v-4h7zm0-6h-7V6h7z"/></svg>
\ No newline at end of file
index 897b9d3..75bb3ac 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/table-progressive.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/table-progressive.png differ
index 6654f6b..3b22056 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table</title><path fill="#36c" d="M19.66 2.88a2 2 0 0 0-.54-.54A2 2 0 0 0 18 2H2a2 2 0 0 0-1.12.34 2 2 0 0 0-.54.54A2 2 0 0 0 0 4v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-.34-1.12zM2 6h7v4H2zm0 10v-4h7v4zm16 0h-7v-4h7zm0-6h-7V6h7z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table</title><path fill="#36c" d="M2 2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 4h7v4H2zm0 10v-4h7v4zm16 0h-7v-4h7zm0-6h-7V6h7z"/></svg>
\ No newline at end of file
index 7c1ccb1..cd5f4d7 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/table.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/table.png differ
index 37caa1e..1b7c1c0 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table</title><path d="M19.66 2.88a2 2 0 0 0-.54-.54A2 2 0 0 0 18 2H2a2 2 0 0 0-1.12.34 2 2 0 0 0-.54.54A2 2 0 0 0 0 4v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-.34-1.12zM2 6h7v4H2zm0 10v-4h7v4zm16 0h-7v-4h7zm0-6h-7V6h7z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table</title><path d="M2 2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 4h7v4H2zm0 10v-4h7v4zm16 0h-7v-4h7zm0-6h-7V6h7z"/></svg>
\ No newline at end of file
index 613ec45..5119dec 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table add column after</title><path fill="#fff" d="M0 3v14h8v1h12V2H8v1H0zm10 6h3V6h2v3h3v2h-3v3h-2v-3h-3zM6 5h2v10H6zM2 5h2v10H2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table add column after</title><path fill="#fff" d="M0 3v14h8v1h12V2H8v1zm10 6h3V6h2v3h3v2h-3v3h-2v-3h-3zM6 5h2v10H6zM2 5h2v10H2z"/></svg>
\ No newline at end of file
index 8058717..03aa11e 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table add column after</title><path fill="#36c" d="M0 3v14h8v1h12V2H8v1H0zm10 6h3V6h2v3h3v2h-3v3h-2v-3h-3zM6 5h2v10H6zM2 5h2v10H2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table add column after</title><path fill="#36c" d="M0 3v14h8v1h12V2H8v1zm10 6h3V6h2v3h3v2h-3v3h-2v-3h-3zM6 5h2v10H6zM2 5h2v10H2z"/></svg>
\ No newline at end of file
index 7215082..8c57e81 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table add column after</title><path d="M0 3v14h8v1h12V2H8v1H0zm10 6h3V6h2v3h3v2h-3v3h-2v-3h-3zM6 5h2v10H6zM2 5h2v10H2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table add column after</title><path d="M0 3v14h8v1h12V2H8v1zm10 6h3V6h2v3h3v2h-3v3h-2v-3h-3zM6 5h2v10H6zM2 5h2v10H2z"/></svg>
\ No newline at end of file
index f3d6c4f..1188d92 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table add row after</title><path fill="#fff" d="M17 0H3v8H2v12h16V8h-1V0zm-6 10v3h3v2h-3v3H9v-3H6v-2h3v-3zm4-4v2H5V6zm0-4v2H5V2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table add row after</title><path fill="#fff" d="M3 0v8H2v12h16V8h-1V0zm8 10v3h3v2h-3v3H9v-3H6v-2h3v-3zm4-4v2H5V6zm0-4v2H5V2z"/></svg>
\ No newline at end of file
index e80330b..594d4fe 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table add row after</title><path fill="#36c" d="M17 0H3v8H2v12h16V8h-1V0zm-6 10v3h3v2h-3v3H9v-3H6v-2h3v-3zm4-4v2H5V6zm0-4v2H5V2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table add row after</title><path fill="#36c" d="M3 0v8H2v12h16V8h-1V0zm8 10v3h3v2h-3v3H9v-3H6v-2h3v-3zm4-4v2H5V6zm0-4v2H5V2z"/></svg>
\ No newline at end of file
index bb00198..2aa1bda 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table add row after</title><path d="M17 0H3v8H2v12h16V8h-1V0zm-6 10v3h3v2h-3v3H9v-3H6v-2h3v-3zm4-4v2H5V6zm0-4v2H5V2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table add row after</title><path d="M3 0v8H2v12h16V8h-1V0zm8 10v3h3v2h-3v3H9v-3H6v-2h3v-3zm4-4v2H5V6zm0-4v2H5V2z"/></svg>
\ No newline at end of file
index a8bad65..3d20cd8 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table add row before</title><path fill="#fff" d="M3 20h14v-8h1V0H2v12h1v8zm6-10V7H6V5h3V2h2v3h3v2h-3v3zm-4 4v-2h10v2zm0 4v-2h10v2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table add row before</title><path fill="#fff" d="M17 20v-8h1V0H2v12h1v8zM9 10V7H6V5h3V2h2v3h3v2h-3v3zm-4 4v-2h10v2zm0 4v-2h10v2z"/></svg>
\ No newline at end of file
index facc564..200791c 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table add row before</title><path fill="#36c" d="M3 20h14v-8h1V0H2v12h1v8zm6-10V7H6V5h3V2h2v3h3v2h-3v3zm-4 4v-2h10v2zm0 4v-2h10v2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table add row before</title><path fill="#36c" d="M17 20v-8h1V0H2v12h1v8zM9 10V7H6V5h3V2h2v3h3v2h-3v3zm-4 4v-2h10v2zm0 4v-2h10v2z"/></svg>
\ No newline at end of file
index 22ade23..b9ab81d 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table add row before</title><path d="M3 20h14v-8h1V0H2v12h1v8zm6-10V7H6V5h3V2h2v3h3v2h-3v3zm-4 4v-2h10v2zm0 4v-2h10v2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table add row before</title><path d="M17 20v-8h1V0H2v12h1v8zM9 10V7H6V5h3V2h2v3h3v2h-3v3zm-4 4v-2h10v2zm0 4v-2h10v2z"/></svg>
\ No newline at end of file
index 18bfa35..f59b37b 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table caption</title><path fill="#fff" d="M18 8H2a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6a2 2 0 0 0-2-2zM2 10h7v2H2zm0 6v-2h7v2zm16 0h-7v-2h7zm0-4h-7v-2h7zM2 2h16v4H2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table caption</title><path fill="#fff" d="M2 8a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6a2 2 0 0 0-2-2zm0 2h7v2H2zm0 6v-2h7v2zm16 0h-7v-2h7zm0-4h-7v-2h7zM2 2h16v4H2z"/></svg>
\ No newline at end of file
index 5b6dedc..2c4fca0 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table caption</title><path fill="#36c" d="M18 8H2a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6a2 2 0 0 0-2-2zM2 10h7v2H2zm0 6v-2h7v2zm16 0h-7v-2h7zm0-4h-7v-2h7zM2 2h16v4H2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table caption</title><path fill="#36c" d="M2 8a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6a2 2 0 0 0-2-2zm0 2h7v2H2zm0 6v-2h7v2zm16 0h-7v-2h7zm0-4h-7v-2h7zM2 2h16v4H2z"/></svg>
\ No newline at end of file
index bd04d3d..fec5086 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table caption</title><path d="M18 8H2a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6a2 2 0 0 0-2-2zM2 10h7v2H2zm0 6v-2h7v2zm16 0h-7v-2h7zm0-4h-7v-2h7zM2 2h16v4H2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table caption</title><path d="M2 8a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6a2 2 0 0 0-2-2zm0 2h7v2H2zm0 6v-2h7v2zm16 0h-7v-2h7zm0-4h-7v-2h7zM2 2h16v4H2z"/></svg>
\ No newline at end of file
index 6d0ecbc..96ecc43 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20"><title>merge cells</title><g fill="#fff"><path id="a" d="M4 11v3l5-4-5-4v3H0v2h4zm-2 5v-3H0v5h8v-2H2zM0 2v5h2V4h6V2H0z"/><use transform="matrix(-1 0 0 1 20 0)" xlink:href="#a"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20"><title>merge cells</title><g fill="#fff"><path id="a" d="M9 10L4 6v3H0v2h4v3zm-7 3H0v5h8v-2H2zM0 2v5h2V4h6V2z"/><use transform="matrix(-1 0 0 1 20 0)" xlink:href="#a"/></g></svg>
\ No newline at end of file
index 25d4af9..f12a2b4 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20"><title>merge cells</title><g fill="#36c"><path id="a" d="M4 11v3l5-4-5-4v3H0v2h4zm-2 5v-3H0v5h8v-2H2zM0 2v5h2V4h6V2H0z"/><use transform="matrix(-1 0 0 1 20 0)" xlink:href="#a"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20"><title>merge cells</title><g fill="#36c"><path id="a" d="M9 10L4 6v3H0v2h4v3zm-7 3H0v5h8v-2H2zM0 2v5h2V4h6V2z"/><use transform="matrix(-1 0 0 1 20 0)" xlink:href="#a"/></g></svg>
\ No newline at end of file
index 9969973..53549c7 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20"><title>merge cells</title><path id="a" d="M4 11v3l5-4-5-4v3H0v2h4zm-2 5v-3H0v5h8v-2H2zM0 2v5h2V4h6V2H0z"/><use transform="matrix(-1 0 0 1 20 0)" xlink:href="#a"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20"><title>merge cells</title><path id="a" d="M9 10L4 6v3H0v2h4v3zm-7 3H0v5h8v-2H2zM0 2v5h2V4h6V2z"/><use transform="matrix(-1 0 0 1 20 0)" xlink:href="#a"/></svg>
\ No newline at end of file
index 34ba5eb..a668a7a 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move column after</title><g fill="#fff"><path d="M11 11v3l5-4-5-4v3H6v2h5z"/><path d="M18 2h-8v2h8v12h-8v2h10V2h-2zM2 18h5v-2H5V4h2V2H0v16h2z"/><path d="M8 12H5v6h5v-6H8zM5 2v6h5V2H5z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move column after</title><g fill="#fff"><path d="M16 10l-5-4v3H6v2h5v3z"/><path d="M0 2h20v16H0zm5 6v4h5v4h8V4h-8v4z"/></g></svg>
\ No newline at end of file
index 61c0be4..9f41077 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move column after</title><g fill="#36c"><path d="M11 11v3l5-4-5-4v3H6v2h5z"/><path d="M18 2h-8v2h8v12h-8v2h10V2h-2zM2 18h5v-2H5V4h2V2H0v16h2z"/><path d="M8 12H5v6h5v-6H8zM5 2v6h5V2H5z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move column after</title><g fill="#36c"><path d="M16 10l-5-4v3H6v2h5v3z"/><path d="M0 2h20v16H0zm5 6v4h5v4h8V4h-8v4z"/></g></svg>
\ No newline at end of file
index 5669189..8e873da 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move column after</title><path d="M11 11v3l5-4-5-4v3H6v2h5z"/><path d="M18 2h-8v2h8v12h-8v2h10V2h-2zM2 18h5v-2H5V4h2V2H0v16h2z"/><path d="M8 12H5v6h5v-6H8zM5 2v6h5V2H5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move column after</title><path d="M16 10l-5-4v3H6v2h5v3z"/><path d="M0 2h20v16H0zm5 6v4h5v4h8V4h-8v4z"/></svg>
\ No newline at end of file
index 07c1437..ca5dc6f 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move column before</title><g fill="#fff"><path d="M9 11v3l-5-4 5-4v3h5v2H9z"/><path d="M2 2h8v2H2v12h8v2H0V2h2zm16 16h-5v-2h2V4h-2V2h7v16h-2z"/><path d="M12 12h3v6h-5v-6h2zm3-10v6h-5V2h5z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move column before</title><g fill="#fff"><path d="M4 10l5-4v3h5v2H9v3z"/><path d="M0 2v16h20V2zm2 2h8v4h5v4h-5v4H2z"/></g></svg>
\ No newline at end of file
index 364fa23..a9129a2 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move column before</title><g fill="#36c"><path d="M9 11v3l-5-4 5-4v3h5v2H9z"/><path d="M2 2h8v2H2v12h8v2H0V2h2zm16 16h-5v-2h2V4h-2V2h7v16h-2z"/><path d="M12 12h3v6h-5v-6h2zm3-10v6h-5V2h5z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move column before</title><g fill="#36c"><path d="M4 10l5-4v3h5v2H9v3z"/><path d="M0 2v16h20V2zm2 2h8v4h5v4h-5v4H2z"/></g></svg>
\ No newline at end of file
index 8a216bf..adc3c03 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move column before</title><path d="M9 11v3l-5-4 5-4v3h5v2H9z"/><path d="M2 2h8v2H2v12h8v2H0V2h2zm16 16h-5v-2h2V4h-2V2h7v16h-2z"/><path d="M12 12h3v6h-5v-6h2zm3-10v6h-5V2h5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move column before</title><path d="M4 10l5-4v3h5v2H9v3z"/><path d="M0 2v16h20V2zm2 2h8v4h5v4h-5v4H2z"/></svg>
\ No newline at end of file
index 00e21df..4abd889 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move row after</title><g fill="#fff"><path d="M11 11h3l-4 5-4-5h3V6h2v5z"/><path d="M2 18v-8h2v8h12v-8h2v10H2v-2zM18 2v5h-2V5H4v2H2V0h16v2z"/><path d="M12 8V5h6v5h-6V8zM2 5h6v5H2V5z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move row after</title><g fill="#fff"><path d="M10 16l-4-5h3V6h2v5h3z"/><path d="M2 0v20h16V0zm2 10h4V5h4v5h4v8H4z"/></g></svg>
\ No newline at end of file
index 0579966..79d28d9 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move row after</title><g fill="#36c"><path d="M11 11h3l-4 5-4-5h3V6h2v5z"/><path d="M2 18v-8h2v8h12v-8h2v10H2v-2zM18 2v5h-2V5H4v2H2V0h16v2z"/><path d="M12 8V5h6v5h-6V8zM2 5h6v5H2V5z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move row after</title><g fill="#36c"><path d="M10 16l-4-5h3V6h2v5h3z"/><path d="M2 0v20h16V0zm2 10h4V5h4v5h4v8H4z"/></g></svg>
\ No newline at end of file
index 82691a9..e9d6ef0 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move row after</title><path d="M11 11h3l-4 5-4-5h3V6h2v5z"/><path d="M2 18v-8h2v8h12v-8h2v10H2v-2zM18 2v5h-2V5H4v2H2V0h16v2z"/><path d="M12 8V5h6v5h-6V8zM2 5h6v5H2V5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move row after</title><path d="M10 16l-4-5h3V6h2v5h3z"/><path d="M2 0v20h16V0zm2 10h4V5h4v5h4v8H4z"/></svg>
\ No newline at end of file
index cb8899c..ea39632 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move row before</title><g fill="#fff"><path d="M9 9H6l4-5 4 5h-3v5H9V9z"/><path d="M18 2v8h-2V2H4v8H2V0h16v2zM2 18v-5h2v2h12v-2h2v7H2v-2z"/><path d="M8 12v3H2v-5h6v2zm10 3h-6v-5h6v5z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move row before</title><g fill="#fff"><path d="M9 9H6l4-5 4 5h-3v5H9z"/><path d="M2 0h16v20H2zm2 2v8h4v5h4v-5h4V2z"/></g></svg>
\ No newline at end of file
index 099f9db..2eaede1 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move row before</title><g fill="#36c"><path d="M9 9H6l4-5 4 5h-3v5H9V9z"/><path d="M18 2v8h-2V2H4v8H2V0h16v2zM2 18v-5h2v2h12v-2h2v7H2v-2z"/><path d="M8 12v3H2v-5h6v2zm10 3h-6v-5h6v5z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move row before</title><g fill="#36c"><path d="M9 9H6l4-5 4 5h-3v5H9z"/><path d="M2 0h16v20H2zm2 2v8h4v5h4v-5h4V2z"/></g></svg>
\ No newline at end of file
index 316dd56..7753c6e 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move row before</title><path d="M9 9H6l4-5 4 5h-3v5H9V9z"/><path d="M18 2v8h-2V2H4v8H2V0h16v2zM2 18v-5h2v2h12v-2h2v7H2v-2z"/><path d="M8 12v3H2v-5h6v2zm10 3h-6v-5h6v5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>table move row before</title><path d="M9 9H6l4-5 4 5h-3v5H9z"/><path d="M2 0h16v20H2zm2 2v8h4v5h4v-5h4V2z"/></svg>
\ No newline at end of file
index c812ede..67fd674 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path fill="#d33" d="M18.72 11L9 1.28A1 1 0 0 0 8.35 1H2a1 1 0 0 0-1 1v6.35a1 1 0 0 0 .28.65L11 18.72a1 1 0 0 0 1.37 0l6.38-6.38a1 1 0 0 0-.03-1.34zM5 7a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path fill="#d33" d="M9 1.28A1 1 0 0 0 8.35 1H2a1 1 0 0 0-1 1v6.35a1 1 0 0 0 .28.65L11 18.72a1 1 0 0 0 1.37 0l6.38-6.38a1 1 0 0 0-.03-1.34zM5 7a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
index c812ede..67fd674 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path fill="#d33" d="M18.72 11L9 1.28A1 1 0 0 0 8.35 1H2a1 1 0 0 0-1 1v6.35a1 1 0 0 0 .28.65L11 18.72a1 1 0 0 0 1.37 0l6.38-6.38a1 1 0 0 0-.03-1.34zM5 7a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path fill="#d33" d="M9 1.28A1 1 0 0 0 8.35 1H2a1 1 0 0 0-1 1v6.35a1 1 0 0 0 .28.65L11 18.72a1 1 0 0 0 1.37 0l6.38-6.38a1 1 0 0 0-.03-1.34zM5 7a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
index af677b2..e78e8d8 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path fill="#fff" d="M18.72 11L9 1.28A1 1 0 0 0 8.35 1H2a1 1 0 0 0-1 1v6.35a1 1 0 0 0 .28.65L11 18.72a1 1 0 0 0 1.37 0l6.38-6.38a1 1 0 0 0-.03-1.34zM5 7a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path fill="#fff" d="M9 1.28A1 1 0 0 0 8.35 1H2a1 1 0 0 0-1 1v6.35a1 1 0 0 0 .28.65L11 18.72a1 1 0 0 0 1.37 0l6.38-6.38a1 1 0 0 0-.03-1.34zM5 7a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
index ce714af..6cf532e 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path fill="#36c" d="M18.72 11L9 1.28A1 1 0 0 0 8.35 1H2a1 1 0 0 0-1 1v6.35a1 1 0 0 0 .28.65L11 18.72a1 1 0 0 0 1.37 0l6.38-6.38a1 1 0 0 0-.03-1.34zM5 7a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path fill="#36c" d="M9 1.28A1 1 0 0 0 8.35 1H2a1 1 0 0 0-1 1v6.35a1 1 0 0 0 .28.65L11 18.72a1 1 0 0 0 1.37 0l6.38-6.38a1 1 0 0 0-.03-1.34zM5 7a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
index 83f4ac2..ddc2764 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path fill="#fc3" d="M18.72 11L9 1.28A1 1 0 0 0 8.35 1H2a1 1 0 0 0-1 1v6.35a1 1 0 0 0 .28.65L11 18.72a1 1 0 0 0 1.37 0l6.38-6.38a1 1 0 0 0-.03-1.34zM5 7a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path fill="#fc3" d="M9 1.28A1 1 0 0 0 8.35 1H2a1 1 0 0 0-1 1v6.35a1 1 0 0 0 .28.65L11 18.72a1 1 0 0 0 1.37 0l6.38-6.38a1 1 0 0 0-.03-1.34zM5 7a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
index 0740438..f094226 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path d="M18.72 11L9 1.28A1 1 0 0 0 8.35 1H2a1 1 0 0 0-1 1v6.35a1 1 0 0 0 .28.65L11 18.72a1 1 0 0 0 1.37 0l6.38-6.38a1 1 0 0 0-.03-1.34zM5 7a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path d="M9 1.28A1 1 0 0 0 8.35 1H2a1 1 0 0 0-1 1v6.35a1 1 0 0 0 .28.65L11 18.72a1 1 0 0 0 1.37 0l6.38-6.38a1 1 0 0 0-.03-1.34zM5 7a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
index 3a6134a..145a398 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path fill="#d33" d="M1.2 12.3l6.4 6.4c.4.4 1 .4 1.4 0L18.7 9c.2-.2.3-.4.3-.6V2c0-.6-.4-1-1-1h-6.4c-.2 0-.5.1-.6.3L1.3 11c-.4.4-.4 1-.1 1.3zM13 5c0-1.1.9-2 2-2s2 .9 2 2-.9 2-2 2-2-.9-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path fill="#d33" d="M7.6 18.7c.4.4 1 .4 1.4 0L18.7 9c.2-.2.3-.4.3-.6V2c0-.6-.4-1-1-1h-6.4c-.2 0-.5.1-.6.3L1.3 11c-.4.4-.4 1-.1 1.3zM13 5c0-1.1.9-2 2-2s2 .9 2 2-.9 2-2 2-2-.9-2-2z"/></svg>
\ No newline at end of file
index 3a6134a..145a398 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path fill="#d33" d="M1.2 12.3l6.4 6.4c.4.4 1 .4 1.4 0L18.7 9c.2-.2.3-.4.3-.6V2c0-.6-.4-1-1-1h-6.4c-.2 0-.5.1-.6.3L1.3 11c-.4.4-.4 1-.1 1.3zM13 5c0-1.1.9-2 2-2s2 .9 2 2-.9 2-2 2-2-.9-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path fill="#d33" d="M7.6 18.7c.4.4 1 .4 1.4 0L18.7 9c.2-.2.3-.4.3-.6V2c0-.6-.4-1-1-1h-6.4c-.2 0-.5.1-.6.3L1.3 11c-.4.4-.4 1-.1 1.3zM13 5c0-1.1.9-2 2-2s2 .9 2 2-.9 2-2 2-2-.9-2-2z"/></svg>
\ No newline at end of file
index 1e65d63..c694b71 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path fill="#fff" d="M1.2 12.3l6.4 6.4c.4.4 1 .4 1.4 0L18.7 9c.2-.2.3-.4.3-.6V2c0-.6-.4-1-1-1h-6.4c-.2 0-.5.1-.6.3L1.3 11c-.4.4-.4 1-.1 1.3zM13 5c0-1.1.9-2 2-2s2 .9 2 2-.9 2-2 2-2-.9-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path fill="#fff" d="M7.6 18.7c.4.4 1 .4 1.4 0L18.7 9c.2-.2.3-.4.3-.6V2c0-.6-.4-1-1-1h-6.4c-.2 0-.5.1-.6.3L1.3 11c-.4.4-.4 1-.1 1.3zM13 5c0-1.1.9-2 2-2s2 .9 2 2-.9 2-2 2-2-.9-2-2z"/></svg>
\ No newline at end of file
index c859d06..658571f 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path fill="#36c" d="M1.2 12.3l6.4 6.4c.4.4 1 .4 1.4 0L18.7 9c.2-.2.3-.4.3-.6V2c0-.6-.4-1-1-1h-6.4c-.2 0-.5.1-.6.3L1.3 11c-.4.4-.4 1-.1 1.3zM13 5c0-1.1.9-2 2-2s2 .9 2 2-.9 2-2 2-2-.9-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path fill="#36c" d="M7.6 18.7c.4.4 1 .4 1.4 0L18.7 9c.2-.2.3-.4.3-.6V2c0-.6-.4-1-1-1h-6.4c-.2 0-.5.1-.6.3L1.3 11c-.4.4-.4 1-.1 1.3zM13 5c0-1.1.9-2 2-2s2 .9 2 2-.9 2-2 2-2-.9-2-2z"/></svg>
\ No newline at end of file
index a9dfbbf..1ce8505 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path fill="#fc3" d="M1.2 12.3l6.4 6.4c.4.4 1 .4 1.4 0L18.7 9c.2-.2.3-.4.3-.6V2c0-.6-.4-1-1-1h-6.4c-.2 0-.5.1-.6.3L1.3 11c-.4.4-.4 1-.1 1.3zM13 5c0-1.1.9-2 2-2s2 .9 2 2-.9 2-2 2-2-.9-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path fill="#fc3" d="M7.6 18.7c.4.4 1 .4 1.4 0L18.7 9c.2-.2.3-.4.3-.6V2c0-.6-.4-1-1-1h-6.4c-.2 0-.5.1-.6.3L1.3 11c-.4.4-.4 1-.1 1.3zM13 5c0-1.1.9-2 2-2s2 .9 2 2-.9 2-2 2-2-.9-2-2z"/></svg>
\ No newline at end of file
index d7b75e8..af3b9f9 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path d="M1.2 12.3l6.4 6.4c.4.4 1 .4 1.4 0L18.7 9c.2-.2.3-.4.3-.6V2c0-.6-.4-1-1-1h-6.4c-.2 0-.5.1-.6.3L1.3 11c-.4.4-.4 1-.1 1.3zM13 5c0-1.1.9-2 2-2s2 .9 2 2-.9 2-2 2-2-.9-2-2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tag</title><path d="M7.6 18.7c.4.4 1 .4 1.4 0L18.7 9c.2-.2.3-.4.3-.6V2c0-.6-.4-1-1-1h-6.4c-.2 0-.5.1-.6.3L1.3 11c-.4.4-.4 1-.1 1.3zM13 5c0-1.1.9-2 2-2s2 .9 2 2-.9 2-2 2-2-.9-2-2z"/></svg>
\ No newline at end of file
index 808e2ea..7cce295 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add template</title><g fill="#fff"><path d="M20 5h-4V1h-2v4h-4v2h4v4h2V7h4V5z"/><path d="M16 17H0V5h8v2H2v8h12v-2h2v4z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add template</title><g fill="#fff"><path d="M16 5V1h-2v4h-4v2h4v4h2V7h4V5z"/><path d="M0 17V5h8v2H2v8h12v-2h2v4z"/></g></svg>
\ No newline at end of file
index 9d7d6c9..99c2400 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add template</title><g fill="#36c"><path d="M20 5h-4V1h-2v4h-4v2h4v4h2V7h4V5z"/><path d="M16 17H0V5h8v2H2v8h12v-2h2v4z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add template</title><g fill="#36c"><path d="M16 5V1h-2v4h-4v2h4v4h2V7h4V5z"/><path d="M0 17V5h8v2H2v8h12v-2h2v4z"/></g></svg>
\ No newline at end of file
index 895ba0b..5723129 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add template</title><path d="M20 5h-4V1h-2v4h-4v2h4v4h2V7h4V5z"/><path d="M16 17H0V5h8v2H2v8h12v-2h2v4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>add template</title><path d="M16 5V1h-2v4h-4v2h4v4h2V7h4V5z"/><path d="M0 17V5h8v2H2v8h12v-2h2v4z"/></svg>
\ No newline at end of file
index 24042cb..bed0cd8 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>text direction left-to-right</title><path fill="#fff" d="M13 11v4l6-5-6-5v4H6v2h7zM4.5 2H6V1H4.5a1.49 1.49 0 0 0-1 .39 1.49 1.49 0 0 0-1-.39H1v1h1.5a.5.5 0 0 1 .5.5v15a.5.5 0 0 1-.5.5H1v1h1.5a1.49 1.49 0 0 0 1-.39 1.49 1.49 0 0 0 1 .39H6v-1H4.5a.5.5 0 0 1-.5-.5v-15a.5.5 0 0 1 .5-.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>text direction left-to-right</title><path fill="#fff" d="M19 10l-6-5v4H6v2h7v4zM6 2V1H4.5a1.49 1.49 0 0 0-1 .39 1.49 1.49 0 0 0-1-.39H1v1h1.5a.5.5 0 0 1 .5.5v15a.5.5 0 0 1-.5.5H1v1h1.5a1.49 1.49 0 0 0 1-.39 1.49 1.49 0 0 0 1 .39H6v-1H4.5a.5.5 0 0 1-.5-.5v-15a.5.5 0 0 1 .5-.5z"/></svg>
\ No newline at end of file
index 8cdc020..cc0e9bd 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>text direction left-to-right</title><path fill="#36c" d="M13 11v4l6-5-6-5v4H6v2h7zM4.5 2H6V1H4.5a1.49 1.49 0 0 0-1 .39 1.49 1.49 0 0 0-1-.39H1v1h1.5a.5.5 0 0 1 .5.5v15a.5.5 0 0 1-.5.5H1v1h1.5a1.49 1.49 0 0 0 1-.39 1.49 1.49 0 0 0 1 .39H6v-1H4.5a.5.5 0 0 1-.5-.5v-15a.5.5 0 0 1 .5-.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>text direction left-to-right</title><path fill="#36c" d="M19 10l-6-5v4H6v2h7v4zM6 2V1H4.5a1.49 1.49 0 0 0-1 .39 1.49 1.49 0 0 0-1-.39H1v1h1.5a.5.5 0 0 1 .5.5v15a.5.5 0 0 1-.5.5H1v1h1.5a1.49 1.49 0 0 0 1-.39 1.49 1.49 0 0 0 1 .39H6v-1H4.5a.5.5 0 0 1-.5-.5v-15a.5.5 0 0 1 .5-.5z"/></svg>
\ No newline at end of file
index 5eab5bc..5b521ed 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>text direction left-to-right</title><path d="M13 11v4l6-5-6-5v4H6v2h7zM4.5 2H6V1H4.5a1.49 1.49 0 0 0-1 .39 1.49 1.49 0 0 0-1-.39H1v1h1.5a.5.5 0 0 1 .5.5v15a.5.5 0 0 1-.5.5H1v1h1.5a1.49 1.49 0 0 0 1-.39 1.49 1.49 0 0 0 1 .39H6v-1H4.5a.5.5 0 0 1-.5-.5v-15a.5.5 0 0 1 .5-.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>text direction left-to-right</title><path d="M19 10l-6-5v4H6v2h7v4zM6 2V1H4.5a1.49 1.49 0 0 0-1 .39 1.49 1.49 0 0 0-1-.39H1v1h1.5a.5.5 0 0 1 .5.5v15a.5.5 0 0 1-.5.5H1v1h1.5a1.49 1.49 0 0 0 1-.39 1.49 1.49 0 0 0 1 .39H6v-1H4.5a.5.5 0 0 1-.5-.5v-15a.5.5 0 0 1 .5-.5z"/></svg>
\ No newline at end of file
index 9f04cb8..f486d78 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>text direction right-to-left</title><path fill="#fff" d="M7 11v4l-6-5 6-5v4h7v2H7zm8.5-9H14V1h1.5a1.49 1.49 0 0 1 1 .39 1.49 1.49 0 0 1 1-.39H19v1h-1.5a.5.5 0 0 0-.5.5v15a.5.5 0 0 0 .5.5H19v1h-1.5a1.49 1.49 0 0 1-1-.39 1.49 1.49 0 0 1-1 .39H14v-1h1.5a.5.5 0 0 0 .5-.5v-15a.5.5 0 0 0-.5-.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>text direction right-to-left</title><path fill="#fff" d="M1 10l6-5v4h7v2H7v4zm13-8V1h1.5a1.49 1.49 0 0 1 1 .39 1.49 1.49 0 0 1 1-.39H19v1h-1.5a.5.5 0 0 0-.5.5v15a.5.5 0 0 0 .5.5H19v1h-1.5a1.49 1.49 0 0 1-1-.39 1.49 1.49 0 0 1-1 .39H14v-1h1.5a.5.5 0 0 0 .5-.5v-15a.5.5 0 0 0-.5-.5z"/></svg>
\ No newline at end of file
index 012edce..e3750f1 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>text direction right-to-left</title><path fill="#36c" d="M7 11v4l-6-5 6-5v4h7v2H7zm8.5-9H14V1h1.5a1.49 1.49 0 0 1 1 .39 1.49 1.49 0 0 1 1-.39H19v1h-1.5a.5.5 0 0 0-.5.5v15a.5.5 0 0 0 .5.5H19v1h-1.5a1.49 1.49 0 0 1-1-.39 1.49 1.49 0 0 1-1 .39H14v-1h1.5a.5.5 0 0 0 .5-.5v-15a.5.5 0 0 0-.5-.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>text direction right-to-left</title><path fill="#36c" d="M1 10l6-5v4h7v2H7v4zm13-8V1h1.5a1.49 1.49 0 0 1 1 .39 1.49 1.49 0 0 1 1-.39H19v1h-1.5a.5.5 0 0 0-.5.5v15a.5.5 0 0 0 .5.5H19v1h-1.5a1.49 1.49 0 0 1-1-.39 1.49 1.49 0 0 1-1 .39H14v-1h1.5a.5.5 0 0 0 .5-.5v-15a.5.5 0 0 0-.5-.5z"/></svg>
\ No newline at end of file
index dc570fd..8a50d48 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>text direction right-to-left</title><path d="M7 11v4l-6-5 6-5v4h7v2H7zm8.5-9H14V1h1.5a1.49 1.49 0 0 1 1 .39 1.49 1.49 0 0 1 1-.39H19v1h-1.5a.5.5 0 0 0-.5.5v15a.5.5 0 0 0 .5.5H19v1h-1.5a1.49 1.49 0 0 1-1-.39 1.49 1.49 0 0 1-1 .39H14v-1h1.5a.5.5 0 0 0 .5-.5v-15a.5.5 0 0 0-.5-.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>text direction right-to-left</title><path d="M1 10l6-5v4h7v2H7v4zm13-8V1h1.5a1.49 1.49 0 0 1 1 .39 1.49 1.49 0 0 1 1-.39H19v1h-1.5a.5.5 0 0 0-.5.5v15a.5.5 0 0 0 .5.5H19v1h-1.5a1.49 1.49 0 0 1-1-.39 1.49 1.49 0 0 1-1 .39H14v-1h1.5a.5.5 0 0 0 .5-.5v-15a.5.5 0 0 0-.5-.5z"/></svg>
\ No newline at end of file
index 7c748c5..ec1642f 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tray</title><path fill="#fff" d="M17 1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm0 12h-4l-1 2H8l-1-2H3V3h14z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tray</title><path fill="#fff" d="M3 1a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm14 12h-4l-1 2H8l-1-2H3V3h14z"/></svg>
\ No newline at end of file
index 21229ba..9ee3e48 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tray</title><path fill="#36c" d="M17 1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm0 12h-4l-1 2H8l-1-2H3V3h14z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tray</title><path fill="#36c" d="M3 1a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm14 12h-4l-1 2H8l-1-2H3V3h14z"/></svg>
\ No newline at end of file
index 4b74cd1..cb360f5 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tray</title><path d="M17 1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm0 12h-4l-1 2H8l-1-2H3V3h14z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>tray</title><path d="M3 1a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm14 12h-4l-1 2H8l-1-2H3V3h14z"/></svg>
\ No newline at end of file
index e0d79ba..9dac17a 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>unblock</title><path fill="#fff" d="M16.94 15.72L12.22 11l-2-2-5.94-5.94L1.22 0 0 1.22l3.06 3.06a9 9 0 0 0 12.66 12.66L18.78 20 20 18.78zM5 11V9h2.78l2 2zm5-10a9 9 0 0 0-4.26 1.08L12.66 9H15v2h-.34l3.26 3.26A9 9 0 0 0 10 1z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>unblock</title><path fill="#fff" d="M1.22 0L0 1.22l3.06 3.06a9 9 0 0 0 12.66 12.66L18.78 20 20 18.78zM5 11V9h2.78l2 2zm5-10a9 9 0 0 0-4.26 1.08L12.66 9H15v2h-.34l3.26 3.26A9 9 0 0 0 10 1z"/></svg>
\ No newline at end of file
index 007b1ea..3ffa2f5 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>unblock</title><path fill="#36c" d="M16.94 15.72L12.22 11l-2-2-5.94-5.94L1.22 0 0 1.22l3.06 3.06a9 9 0 0 0 12.66 12.66L18.78 20 20 18.78zM5 11V9h2.78l2 2zm5-10a9 9 0 0 0-4.26 1.08L12.66 9H15v2h-.34l3.26 3.26A9 9 0 0 0 10 1z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>unblock</title><path fill="#36c" d="M1.22 0L0 1.22l3.06 3.06a9 9 0 0 0 12.66 12.66L18.78 20 20 18.78zM5 11V9h2.78l2 2zm5-10a9 9 0 0 0-4.26 1.08L12.66 9H15v2h-.34l3.26 3.26A9 9 0 0 0 10 1z"/></svg>
\ No newline at end of file
index f75bf9a..72778fe 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>unblock</title><path d="M16.94 15.72L12.22 11l-2-2-5.94-5.94L1.22 0 0 1.22l3.06 3.06a9 9 0 0 0 12.66 12.66L18.78 20 20 18.78zM5 11V9h2.78l2 2zm5-10a9 9 0 0 0-4.26 1.08L12.66 9H15v2h-.34l3.26 3.26A9 9 0 0 0 10 1z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>unblock</title><path d="M1.22 0L0 1.22l3.06 3.06a9 9 0 0 0 12.66 12.66L18.78 20 20 18.78zM5 11V9h2.78l2 2zm5-10a9 9 0 0 0-4.26 1.08L12.66 9H15v2h-.34l3.26 3.26A9 9 0 0 0 10 1z"/></svg>
\ No newline at end of file
index 827170e..47ec5f8 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/unFlag-ltr-invert.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/unFlag-ltr-invert.png differ
index d11d4d4..ae1a8b0 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>un-flag</title><path fill="#fff" d="M12.14 8.48L17 6 5.58 1.92l.16.16 6.4 6.4zm-1.61.82L3 1.78 1.22 0 0 1.22l3 3V19h2v-6.87l3.91-2L18.78 20 20 18.78 10.53 9.3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>un-flag</title><path fill="#fff" d="M12.14 8.48L17 6 5.58 1.92zM1.22 0L0 1.22l3 3V19h2v-6.87l3.91-2L18.78 20 20 18.78z"/></svg>
\ No newline at end of file
index 3de43ad..6ff759a 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/unFlag-ltr-progressive.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/unFlag-ltr-progressive.png differ
index 9c967fb..61e78a3 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>un-flag</title><path fill="#36c" d="M12.14 8.48L17 6 5.58 1.92l.16.16 6.4 6.4zm-1.61.82L3 1.78 1.22 0 0 1.22l3 3V19h2v-6.87l3.91-2L18.78 20 20 18.78 10.53 9.3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>un-flag</title><path fill="#36c" d="M12.14 8.48L17 6 5.58 1.92zM1.22 0L0 1.22l3 3V19h2v-6.87l3.91-2L18.78 20 20 18.78z"/></svg>
\ No newline at end of file
index 5f730b4..97008f8 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/unFlag-ltr.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/unFlag-ltr.png differ
index fd3be33..47054e0 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>un-flag</title><path d="M12.14 8.48L17 6 5.58 1.92l.16.16 6.4 6.4zm-1.61.82L3 1.78 1.22 0 0 1.22l3 3V19h2v-6.87l3.91-2L18.78 20 20 18.78 10.53 9.3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>un-flag</title><path d="M12.14 8.48L17 6 5.58 1.92zM1.22 0L0 1.22l3 3V19h2v-6.87l3.91-2L18.78 20 20 18.78z"/></svg>
\ No newline at end of file
index 92dba5c..93a7aa0 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>un-lock</title><path fill="#d33" d="M16.07 8H15V5s0-5-5-5a4.63 4.63 0 0 0-4.88 4h2C7.31 2.93 8 2 10 2c3 0 3 2 3 3.5V8H3.93A1.93 1.93 0 0 0 2 9.93v8.15A1.93 1.93 0 0 0 3.93 20h12.14A1.93 1.93 0 0 0 18 18.07V9.93A1.93 1.93 0 0 0 16.07 8zM10 16a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>un-lock</title><path fill="#d33" d="M15 8V5s0-5-5-5a4.63 4.63 0 0 0-4.88 4h2C7.31 2.93 8 2 10 2c3 0 3 2 3 3.5V8H3.93A1.93 1.93 0 0 0 2 9.93v8.15A1.93 1.93 0 0 0 3.93 20h12.14A1.93 1.93 0 0 0 18 18.07V9.93A1.93 1.93 0 0 0 16.07 8zm-5 8a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
index 685746f..ef4482b 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>un-lock</title><path fill="#fff" d="M16.07 8H15V5s0-5-5-5a4.63 4.63 0 0 0-4.88 4h2C7.31 2.93 8 2 10 2c3 0 3 2 3 3.5V8H3.93A1.93 1.93 0 0 0 2 9.93v8.15A1.93 1.93 0 0 0 3.93 20h12.14A1.93 1.93 0 0 0 18 18.07V9.93A1.93 1.93 0 0 0 16.07 8zM10 16a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>un-lock</title><path fill="#fff" d="M15 8V5s0-5-5-5a4.63 4.63 0 0 0-4.88 4h2C7.31 2.93 8 2 10 2c3 0 3 2 3 3.5V8H3.93A1.93 1.93 0 0 0 2 9.93v8.15A1.93 1.93 0 0 0 3.93 20h12.14A1.93 1.93 0 0 0 18 18.07V9.93A1.93 1.93 0 0 0 16.07 8zm-5 8a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
index 541701f..756a7e0 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>un-lock</title><path fill="#36c" d="M16.07 8H15V5s0-5-5-5a4.63 4.63 0 0 0-4.88 4h2C7.31 2.93 8 2 10 2c3 0 3 2 3 3.5V8H3.93A1.93 1.93 0 0 0 2 9.93v8.15A1.93 1.93 0 0 0 3.93 20h12.14A1.93 1.93 0 0 0 18 18.07V9.93A1.93 1.93 0 0 0 16.07 8zM10 16a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>un-lock</title><path fill="#36c" d="M15 8V5s0-5-5-5a4.63 4.63 0 0 0-4.88 4h2C7.31 2.93 8 2 10 2c3 0 3 2 3 3.5V8H3.93A1.93 1.93 0 0 0 2 9.93v8.15A1.93 1.93 0 0 0 3.93 20h12.14A1.93 1.93 0 0 0 18 18.07V9.93A1.93 1.93 0 0 0 16.07 8zm-5 8a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
index 94892e2..fd1db92 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>un-lock</title><path d="M16.07 8H15V5s0-5-5-5a4.63 4.63 0 0 0-4.88 4h2C7.31 2.93 8 2 10 2c3 0 3 2 3 3.5V8H3.93A1.93 1.93 0 0 0 2 9.93v8.15A1.93 1.93 0 0 0 3.93 20h12.14A1.93 1.93 0 0 0 18 18.07V9.93A1.93 1.93 0 0 0 16.07 8zM10 16a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>un-lock</title><path d="M15 8V5s0-5-5-5a4.63 4.63 0 0 0-4.88 4h2C7.31 2.93 8 2 10 2c3 0 3 2 3 3.5V8H3.93A1.93 1.93 0 0 0 2 9.93v8.15A1.93 1.93 0 0 0 3.93 20h12.14A1.93 1.93 0 0 0 18 18.07V9.93A1.93 1.93 0 0 0 16.07 8zm-5 8a2 2 0 1 1 2-2 2 2 0 0 1-2 2z"/></svg>
\ No newline at end of file
index b2b29ab..d9c1cba 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/unTrash-invert.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/unTrash-invert.png differ
index d6bc046..3aadb9b 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undelete</title><path fill="#fff" d="M16 14.78L6.22 5l-1-1-2-2-2-2L0 1.22l4 4V17a2 2 0 0 0 2 2h8a2 2 0 0 0 2-1.8l2.8 2.8 1.2-1.22zM17 4V2h-3.5l-1-1h-5l-1 1h-.84l2 2H17zm-1 1H8.66L16 12.34V5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undelete</title><path fill="#fff" d="M1.22 0L0 1.22l4 4V17a2 2 0 0 0 2 2h8a2 2 0 0 0 2-1.8l2.8 2.8 1.2-1.22zM17 4V2h-3.5l-1-1h-5l-1 1h-.84l2 2zM8.66 5H16v7.34z"/></svg>
\ No newline at end of file
index 853f8db..4b94456 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/unTrash-progressive.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/unTrash-progressive.png differ
index 36adbcb..c80deb6 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undelete</title><path fill="#36c" d="M16 14.78L6.22 5l-1-1-2-2-2-2L0 1.22l4 4V17a2 2 0 0 0 2 2h8a2 2 0 0 0 2-1.8l2.8 2.8 1.2-1.22zM17 4V2h-3.5l-1-1h-5l-1 1h-.84l2 2H17zm-1 1H8.66L16 12.34V5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undelete</title><path fill="#36c" d="M1.22 0L0 1.22l4 4V17a2 2 0 0 0 2 2h8a2 2 0 0 0 2-1.8l2.8 2.8 1.2-1.22zM17 4V2h-3.5l-1-1h-5l-1 1h-.84l2 2zM8.66 5H16v7.34z"/></svg>
\ No newline at end of file
index 8a59d2d..ae731f4 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/unTrash.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/unTrash.png differ
index 156e125..b5c8eb3 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undelete</title><path d="M16 14.78L6.22 5l-1-1-2-2-2-2L0 1.22l4 4V17a2 2 0 0 0 2 2h8a2 2 0 0 0 2-1.8l2.8 2.8 1.2-1.22zM17 4V2h-3.5l-1-1h-5l-1 1h-.84l2 2H17zm-1 1H8.66L16 12.34V5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undelete</title><path d="M1.22 0L0 1.22l4 4V17a2 2 0 0 0 2 2h8a2 2 0 0 0 2-1.8l2.8 2.8 1.2-1.22zM17 4V2h-3.5l-1-1h-5l-1 1h-.84l2 2zM8.66 5H16v7.34z"/></svg>
\ No newline at end of file
index b84a8cf..31ad6fc 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo</title><path fill="#fff" d="M8 3L1 8.5 8 14v-4h1c4 0 7 2 7 6v1h3v-1c0-6-5-9-10-9H8V3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo</title><path fill="#fff" d="M1 8.5L8 14v-4h1c4 0 7 2 7 6v1h3v-1c0-6-5-9-10-9H8V3z"/></svg>
\ No newline at end of file
index a6e9292..a99589c 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo</title><path fill="#36c" d="M8 3L1 8.5 8 14v-4h1c4 0 7 2 7 6v1h3v-1c0-6-5-9-10-9H8V3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo</title><path fill="#36c" d="M1 8.5L8 14v-4h1c4 0 7 2 7 6v1h3v-1c0-6-5-9-10-9H8V3z"/></svg>
\ No newline at end of file
index d9c1991..8d05848 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo</title><path d="M8 3L1 8.5 8 14v-4h1c4 0 7 2 7 6v1h3v-1c0-6-5-9-10-9H8V3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo</title><path d="M1 8.5L8 14v-4h1c4 0 7 2 7 6v1h3v-1c0-6-5-9-10-9H8V3z"/></svg>
\ No newline at end of file
index 7c0db1d..88e2ec5 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo</title><path fill="#fff" d="M12 3v4h-1C6 7 1 10 1 16v1h3v-1c0-4 3-6 7-6h1v4l7-5.5L12 3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo</title><path fill="#fff" d="M12 3v4h-1C6 7 1 10 1 16v1h3v-1c0-4 3-6 7-6h1v4l7-5.5z"/></svg>
\ No newline at end of file
index db98918..47fab52 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo</title><path fill="#36c" d="M12 3v4h-1C6 7 1 10 1 16v1h3v-1c0-4 3-6 7-6h1v4l7-5.5L12 3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo</title><path fill="#36c" d="M12 3v4h-1C6 7 1 10 1 16v1h3v-1c0-4 3-6 7-6h1v4l7-5.5z"/></svg>
\ No newline at end of file
index 45b0869..b04df7c 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo</title><path d="M12 3v4h-1C6 7 1 10 1 16v1h3v-1c0-4 3-6 7-6h1v4l7-5.5L12 3z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>undo</title><path d="M12 3v4h-1C6 7 1 10 1 16v1h3v-1c0-4 3-6 7-6h1v4l7-5.5z"/></svg>
\ No newline at end of file
index 5bdd2be..9d36592 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>triangle upwards</title><path fill="#fff" d="M10 5l8 10H2l8-10z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>triangle upwards</title><path fill="#fff" d="M10 5l8 10H2z"/></svg>
\ No newline at end of file
index a22e88b..e94f9fc 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>triangle upwards</title><path fill="#36c" d="M10 5l8 10H2l8-10z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>triangle upwards</title><path fill="#36c" d="M10 5l8 10H2z"/></svg>
\ No newline at end of file
index 90a88b2..a39fb75 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>triangle upwards</title><path d="M10 5l8 10H2l8-10z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>triangle upwards</title><path d="M10 5l8 10H2z"/></svg>
\ No newline at end of file
index d30ee5f..9102c8b 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>upload</title><g fill="#fff"><path d="M17 12v5H3v-5H1v5a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5z"/><path d="M15 7l-5-6-5 6h4v8h2V7h4z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>upload</title><g fill="#fff"><path d="M17 12v5H3v-5H1v5a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5z"/><path d="M10 1L5 7h4v8h2V7h4z"/></g></svg>
\ No newline at end of file
index b1128bd..48f23b7 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>upload</title><g fill="#36c"><path d="M17 12v5H3v-5H1v5a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5z"/><path d="M15 7l-5-6-5 6h4v8h2V7h4z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>upload</title><g fill="#36c"><path d="M17 12v5H3v-5H1v5a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5z"/><path d="M10 1L5 7h4v8h2V7h4z"/></g></svg>
\ No newline at end of file
index e50fc79..3133d6c 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>upload</title><path d="M17 12v5H3v-5H1v5a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5z"/><path d="M15 7l-5-6-5 6h4v8h2V7h4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>upload</title><path d="M17 12v5H3v-5H1v5a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5z"/><path d="M10 1L5 7h4v8h2V7h4z"/></svg>
\ No newline at end of file
index e4e70d1..7a73136 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>anonynmous user</title><g fill="#fff"><path d="M15 2H5L4 8h12l-1-6zM0 10s2 1 10 1 10-1 10-1l-4-2H4zm8 4h4v1H8z"/><circle cx="6" cy="15" r="3"/><circle cx="14" cy="15" r="3"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>anonynmous user</title><g fill="#fff"><path d="M15 2H5L4 8h12zM0 10s2 1 10 1 10-1 10-1l-4-2H4zm8 4h4v1H8z"/><circle cx="6" cy="15" r="3"/><circle cx="14" cy="15" r="3"/></g></svg>
\ No newline at end of file
index cd40859..6c4fa41 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>anonynmous user</title><g fill="#36c"><path d="M15 2H5L4 8h12l-1-6zM0 10s2 1 10 1 10-1 10-1l-4-2H4zm8 4h4v1H8z"/><circle cx="6" cy="15" r="3"/><circle cx="14" cy="15" r="3"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>anonynmous user</title><g fill="#36c"><path d="M15 2H5L4 8h12zM0 10s2 1 10 1 10-1 10-1l-4-2H4zm8 4h4v1H8z"/><circle cx="6" cy="15" r="3"/><circle cx="14" cy="15" r="3"/></g></svg>
\ No newline at end of file
index 8070f92..4992c77 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>anonynmous user</title><path d="M15 2H5L4 8h12l-1-6zM0 10s2 1 10 1 10-1 10-1l-4-2H4zm8 4h4v1H8z"/><circle cx="6" cy="15" r="3"/><circle cx="14" cy="15" r="3"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>anonynmous user</title><path d="M15 2H5L4 8h12zM0 10s2 1 10 1 10-1 10-1l-4-2H4zm8 4h4v1H8z"/><circle cx="6" cy="15" r="3"/><circle cx="14" cy="15" r="3"/></svg>
\ No newline at end of file
index 3010c5e..38bffb3 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>view details</title><path fill="#fff" d="M12 8H3V6h9v2zm0-3H1V3h11v2zm1-2h6v6h-6zm-1 13H3v-2h9v2zm0-3H1v-2h11v2zm1-2h6v6h-6z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>view details</title><path fill="#fff" d="M3 8V6h9v2zm9-3H1V3h11zm1-2h6v6h-6zm-1 13H3v-2h9zm0-3H1v-2h11zm1-2h6v6h-6z"/></svg>
\ No newline at end of file
index 37baa8e..54dc977 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>view details</title><path fill="#36c" d="M12 8H3V6h9v2zm0-3H1V3h11v2zm1-2h6v6h-6zm-1 13H3v-2h9v2zm0-3H1v-2h11v2zm1-2h6v6h-6z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>view details</title><path fill="#36c" d="M3 8V6h9v2zm9-3H1V3h11zm1-2h6v6h-6zm-1 13H3v-2h9zm0-3H1v-2h11zm1-2h6v6h-6z"/></svg>
\ No newline at end of file
index bcae7e0..49ad890 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>view details</title><path d="M12 8H3V6h9v2zm0-3H1V3h11v2zm1-2h6v6h-6zm-1 13H3v-2h9v2zm0-3H1v-2h11v2zm1-2h6v6h-6z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>view details</title><path d="M3 8V6h9v2zm9-3H1V3h11zm1-2h6v6h-6zm-1 13H3v-2h9zm0-3H1v-2h11zm1-2h6v6h-6z"/></svg>
\ No newline at end of file
index ecfe07f..09f408c 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/web-invert.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/web-invert.png differ
index 3dbc824..bc33d11 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="2 2 20 20"><title>web</title><g fill="#fff"><path d="M22.78 18.46L21 16V4H3v12l-1.757 2.463a.974.974 0 0 0-.157 1.043c.157.347.533.494.914.494h20c.382 0 .783-.148.94-.496a.976.976 0 0 0-.16-1.044zM4 18l1-2V6h14v10l1 2H4z"/><path d="M7 16h10V8H7v8zm2-2v-3h6v3H9z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>web</title><g fill="#fff"><path d="M19 14V2H1v12l-1 1.4V18h20v-2.6zM3 14V4h14v10l1 2H2z"/><path d="M5 14h10V6H5zm2-5h6v3H7z"/></g></svg>
\ No newline at end of file
index 430f06c..0bb1bed 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/web-progressive.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/web-progressive.png differ
index 8f0c103..f566113 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="2 2 20 20"><title>web</title><g fill="#36c"><path d="M22.78 18.46L21 16V4H3v12l-1.757 2.463a.974.974 0 0 0-.157 1.043c.157.347.533.494.914.494h20c.382 0 .783-.148.94-.496a.976.976 0 0 0-.16-1.044zM4 18l1-2V6h14v10l1 2H4z"/><path d="M7 16h10V8H7v8zm2-2v-3h6v3H9z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>web</title><g fill="#36c"><path d="M19 14V2H1v12l-1 1.4V18h20v-2.6zM3 14V4h14v10l1 2H2z"/><path d="M5 14h10V6H5zm2-5h6v3H7z"/></g></svg>
\ No newline at end of file
index 2371e22..e2cb0e3 100644 (file)
Binary files a/resources/lib/ooui/themes/wikimediaui/images/icons/web.png and b/resources/lib/ooui/themes/wikimediaui/images/icons/web.png differ
index a2c5402..9ad5056 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="2 2 20 20"><title>web</title><path d="M22.78 18.46L21 16V4H3v12l-1.757 2.463a.974.974 0 0 0-.157 1.043c.157.347.533.494.914.494h20c.382 0 .783-.148.94-.496a.976.976 0 0 0-.16-1.044zM4 18l1-2V6h14v10l1 2H4z"/><path d="M7 16h10V8H7v8zm2-2v-3h6v3H9z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>web</title><path d="M19 14V2H1v12l-1 1.4V18h20v-2.6zM3 14V4h14v10l1 2H2z"/><path d="M5 14h10V6H5zm2-5h6v3H7z"/></svg>
\ No newline at end of file
index f39b1c9..1a89ede 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>Wikitext</title><path fill="#fff" d="M1 3v14h3v-2H3V5h1V3H1zm4 0v14h4v-2H7V5h2V3H5zm12 0h-1v2h1v10h-1v2h3V3h-2zm-6 0v2h2v10h-2v2h4V3h-4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>Wikitext</title><path fill="#fff" d="M1 3v14h3v-2H3V5h1V3zm4 0v14h4v-2H7V5h2V3zm11 0v2h1v10h-1v2h3V3zm-5 0v2h2v10h-2v2h4V3z"/></svg>
\ No newline at end of file
index 5bf99f2..579ad04 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>Wikitext</title><path fill="#36c" d="M1 3v14h3v-2H3V5h1V3H1zm4 0v14h4v-2H7V5h2V3H5zm12 0h-1v2h1v10h-1v2h3V3h-2zm-6 0v2h2v10h-2v2h4V3h-4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>Wikitext</title><path fill="#36c" d="M1 3v14h3v-2H3V5h1V3zm4 0v14h4v-2H7V5h2V3zm11 0v2h1v10h-1v2h3V3zm-5 0v2h2v10h-2v2h4V3z"/></svg>
\ No newline at end of file
index 612805e..3e9b08d 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>Wikitext</title><path d="M1 3v14h3v-2H3V5h1V3H1zm4 0v14h4v-2H7V5h2V3H5zm12 0h-1v2h1v10h-1v2h3V3h-2zm-6 0v2h2v10h-2v2h4V3h-4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>Wikitext</title><path d="M1 3v14h3v-2H3V5h1V3zm4 0v14h4v-2H7V5h2V3zm11 0v2h1v10h-1v2h3V3zm-5 0v2h2v10h-2v2h4V3z"/></svg>
\ No newline at end of file
index a867897..39d2c8c 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>window</title><g fill="#fff"><path d="M18 2H2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 14H2V4h16z"/><path d="M4 6h12v2H4z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>window</title><g fill="#fff"><path d="M2 2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 2h16v12H2z"/><path d="M4 6h12v2H4z"/></g></svg>
\ No newline at end of file
index 6923d4b..f4745c5 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>window</title><g fill="#36c"><path d="M18 2H2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 14H2V4h16z"/><path d="M4 6h12v2H4z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>window</title><g fill="#36c"><path d="M2 2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 2h16v12H2z"/><path d="M4 6h12v2H4z"/></g></svg>
\ No newline at end of file
index 879dfba..ef76d55 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>window</title><path d="M18 2H2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 14H2V4h16z"/><path d="M4 6h12v2H4z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>window</title><path d="M2 2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm0 2h16v12H2z"/><path d="M4 6h12v2H4z"/></svg>
\ No newline at end of file
index ce56928..d4f8199 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>zoom in</title><g fill="#fff"><path d="M19 17l-5.15-5.15a7 7 0 1 0-2 2L17 19zM3.5 8A4.5 4.5 0 1 1 8 12.5 4.49 4.49 0 0 1 3.5 8z"/><path d="M11 7.25H8.75V5h-1.5v2.25H5v1.5h2.25V11h1.5V8.75H11v-1.5z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>zoom in</title><g fill="#fff"><path d="M19 17l-5.15-5.15a7 7 0 1 0-2 2L17 19zM3.5 8A4.5 4.5 0 1 1 8 12.5 4.49 4.49 0 0 1 3.5 8z"/><path d="M11 7.25H8.75V5h-1.5v2.25H5v1.5h2.25V11h1.5V8.75H11z"/></g></svg>
\ No newline at end of file
index 8288b28..25695b9 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>zoom in</title><g fill="#36c"><path d="M19 17l-5.15-5.15a7 7 0 1 0-2 2L17 19zM3.5 8A4.5 4.5 0 1 1 8 12.5 4.49 4.49 0 0 1 3.5 8z"/><path d="M11 7.25H8.75V5h-1.5v2.25H5v1.5h2.25V11h1.5V8.75H11v-1.5z"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>zoom in</title><g fill="#36c"><path d="M19 17l-5.15-5.15a7 7 0 1 0-2 2L17 19zM3.5 8A4.5 4.5 0 1 1 8 12.5 4.49 4.49 0 0 1 3.5 8z"/><path d="M11 7.25H8.75V5h-1.5v2.25H5v1.5h2.25V11h1.5V8.75H11z"/></g></svg>
\ No newline at end of file
index 6638012..673f753 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>zoom in</title><path d="M19 17l-5.15-5.15a7 7 0 1 0-2 2L17 19zM3.5 8A4.5 4.5 0 1 1 8 12.5 4.49 4.49 0 0 1 3.5 8z"/><path d="M11 7.25H8.75V5h-1.5v2.25H5v1.5h2.25V11h1.5V8.75H11v-1.5z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>zoom in</title><path d="M19 17l-5.15-5.15a7 7 0 1 0-2 2L17 19zM3.5 8A4.5 4.5 0 1 1 8 12.5 4.49 4.49 0 0 1 3.5 8z"/><path d="M11 7.25H8.75V5h-1.5v2.25H5v1.5h2.25V11h1.5V8.75H11z"/></svg>
\ No newline at end of file
index 96414b5..91a0fcd 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><title>down</title><path fill="#fff" d="M11.05 3.996l-.965-1.053-4.035 3.86-3.947-3.86L1.05 3.996l5 5 5-5"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><title>down</title><path fill="#fff" d="M10.085 2.943L6.05 6.803l-3.947-3.86L1.05 3.996l5 5 5-5z"/></svg>
\ No newline at end of file
index dbb5298..cbc28e5 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><title>down</title><path d="M11.05 3.996l-.965-1.053-4.035 3.86-3.947-3.86L1.05 3.996l5 5 5-5"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><title>down</title><path d="M10.085 2.943L6.05 6.803l-3.947-3.86L1.05 3.996l5 5 5-5z"/></svg>
\ No newline at end of file
index 78d875c..1f354a2 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><title>up</title><path fill="#fff" d="M11 7.974l-.965 1.052L6 5.168 2.053 9.026 1 7.974l5-5 5 5"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><title>up</title><path fill="#fff" d="M10.035 9.026L6 5.168 2.053 9.026 1 7.974l5-5 5 5z"/></svg>
\ No newline at end of file
index a8ec388..e541e23 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><title>up</title><path d="M11 7.974l-.965 1.052L6 5.168 2.053 9.026 1 7.974l5-5 5 5"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><title>up</title><path d="M10.035 9.026L6 5.168 2.053 9.026 1 7.974l5-5 5 5z"/></svg>
\ No newline at end of file
index 8a733cd..0559ca7 100644 (file)
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path fill="#c8ccd1" d="M0 0h16v16H0z"/><path fill="#fff" d="M8 0h8v8H8zM0 8h8v8H0z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path fill="#c8ccd1" d="M0 0h16v16H0z"/><path fill="#fff" d="M8 0h8v8H0v8h8z"/></svg>
\ No newline at end of file
index e90730a..146cebe 100644 (file)
@@ -2,7 +2,13 @@
        "prefix": "oo-ui-texture",
        "intro": "@import '../../../../src/styles/common';",
        "images": {
-               "pending": { "file": "images/textures/pending.gif" },
-               "transparency": { "file": "images/textures/transparency.svg" }
+               "pending": {
+                       "file": "images/textures/pending.gif",
+                       "deprecated": "Deprecated since v0.31.1."
+               },
+               "transparency": {
+                       "file": "images/textures/transparency.svg",
+                       "deprecated": "Deprecated since v0.31.1."
+               }
        }
 }
diff --git a/resources/src/jquery.spinner/images/spinner-large.gif b/resources/src/jquery.spinner/images/spinner-large.gif
deleted file mode 100644 (file)
index 72203fd..0000000
Binary files a/resources/src/jquery.spinner/images/spinner-large.gif and /dev/null differ
diff --git a/resources/src/jquery.spinner/images/spinner.gif b/resources/src/jquery.spinner/images/spinner.gif
deleted file mode 100644 (file)
index 6146be4..0000000
Binary files a/resources/src/jquery.spinner/images/spinner.gif and /dev/null differ
diff --git a/resources/src/jquery.spinner/spinner.css b/resources/src/jquery.spinner/spinner.css
deleted file mode 100644 (file)
index 9c819a6..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-.mw-spinner {
-       background-color: transparent;
-       background-position: center center;
-       background-repeat: no-repeat;
-}
-
-.mw-spinner-small {
-       /* @embed */
-       background-image: url( images/spinner.gif );
-       height: 20px;
-       width: 20px;
-       /* Avoid issues with .mw-spinner-block when floated without width. */
-       min-width: 20px;
-}
-
-.mw-spinner-large {
-       /* @embed */
-       background-image: url( images/spinner-large.gif );
-       height: 32px;
-       width: 32px;
-       /* Avoid issues with .mw-spinner-block when floated without width. */
-       min-width: 32px;
-}
-
-.mw-spinner-block {
-       display: block;
-       /* This overrides width from .mw-spinner-large / .mw-spinner-small,
-        * This is where the min-width kicks in.
-        */
-       width: 100%;
-}
-
-.mw-spinner-inline {
-       display: inline-block;
-       vertical-align: middle;
-}
index 5dfbab7..8cccedb 100644 (file)
@@ -59,7 +59,7 @@
                 * @return {jQuery}
                 */
                createSpinner: function ( opts ) {
-                       var $spinner;
+                       var i, $spinner, $container;
 
                        if ( typeof opts === 'string' ) {
                                opts = {
                                $spinner.attr( 'id', 'mw-spinner-' + opts.id );
                        }
 
-                       $spinner.addClass( opts.size === 'large' ? 'mw-spinner-large' : 'mw-spinner-small' );
-                       $spinner.addClass( opts.type === 'block' ? 'mw-spinner-block' : 'mw-spinner-inline' );
+                       $spinner
+                               .addClass( opts.size === 'large' ? 'mw-spinner-large' : 'mw-spinner-small' )
+                               .addClass( opts.type === 'block' ? 'mw-spinner-block' : 'mw-spinner-inline' );
+
+                       $container = $( '<div>' ).addClass( 'mw-spinner-container' ).appendTo( $spinner );
+                       for ( i = 0; i < 12; i++ ) {
+                               $container.append( $( '<div>' ) );
+                       }
 
                        return $spinner;
                },
diff --git a/resources/src/jquery.spinner/spinner.less b/resources/src/jquery.spinner/spinner.less
new file mode 100644 (file)
index 0000000..596858e
--- /dev/null
@@ -0,0 +1,143 @@
+.mw-spinner {
+       position: relative;
+
+       > .mw-spinner-container {
+               transform-origin: 0 0;
+       }
+}
+
+@mw-spinner-small-size: 20px;
+@mw-spinner-large-size: 32px;
+
+.mw-spinner-small {
+       width: @mw-spinner-small-size;
+       height: @mw-spinner-small-size;
+
+       > .mw-spinner-container {
+               transform: scale( unit( @mw-spinner-small-size / 64 ) );
+       }
+}
+
+.mw-spinner-large {
+       width: @mw-spinner-large-size;
+       height: @mw-spinner-large-size;
+
+       > .mw-spinner-container {
+               transform: scale( unit( @mw-spinner-large-size / 64 ) );
+       }
+}
+
+.mw-spinner-block {
+       display: block;
+       width: 100%;
+       text-align: center;
+
+       > .mw-spinner-container {
+               display: inline-block;
+               vertical-align: top;
+       }
+
+       &.mw-spinner-small > .mw-spinner-container {
+               min-width: @mw-spinner-small-size;
+       }
+
+       &.mw-spinner-large > .mw-spinner-container {
+               min-width: @mw-spinner-large-size;
+       }
+}
+
+.mw-spinner-inline {
+       display: inline-block;
+       vertical-align: middle;
+}
+
+/**
+ * CSS loading spinner adapted from loadingio, CC0
+ * https://github.com/loadingio/css-spinner/
+ */
+.mw-spinner-container > div {
+       transform-origin: 32px 32px;
+       animation: mw-spinner 1.2s linear infinite;
+}
+
+.mw-spinner-container > div:after {
+       content: ' ';
+       display: block;
+       position: absolute;
+       top: 3px;
+       left: 29px;
+       width: 5px;
+       height: 14px;
+       border-radius: 20%;
+       background: #000;
+}
+
+.mw-spinner-container > div:nth-child( 1 ) {
+       transform: rotate( 0deg );
+       animation-delay: -1.1s;
+}
+
+.mw-spinner-container > div:nth-child( 2 ) {
+       transform: rotate( 30deg );
+       animation-delay: -1s;
+}
+
+.mw-spinner-container > div:nth-child( 3 ) {
+       transform: rotate( 60deg );
+       animation-delay: -0.9s;
+}
+
+.mw-spinner-container > div:nth-child( 4 ) {
+       transform: rotate( 90deg );
+       animation-delay: -0.8s;
+}
+
+.mw-spinner-container > div:nth-child( 5 ) {
+       transform: rotate( 120deg );
+       animation-delay: -0.7s;
+}
+
+.mw-spinner-container > div:nth-child( 6 ) {
+       transform: rotate( 150deg );
+       animation-delay: -0.6s;
+}
+
+.mw-spinner-container > div:nth-child( 7 ) {
+       transform: rotate( 180deg );
+       animation-delay: -0.5s;
+}
+
+.mw-spinner-container > div:nth-child( 8 ) {
+       transform: rotate( 210deg );
+       animation-delay: -0.4s;
+}
+
+.mw-spinner-container > div:nth-child( 9 ) {
+       transform: rotate( 240deg );
+       animation-delay: -0.3s;
+}
+
+.mw-spinner-container > div:nth-child( 10 ) {
+       transform: rotate( 270deg );
+       animation-delay: -0.2s;
+}
+
+.mw-spinner-container > div:nth-child( 11 ) {
+       transform: rotate( 300deg );
+       animation-delay: -0.1s;
+}
+
+.mw-spinner-container > div:nth-child( 12 ) {
+       transform: rotate( 330deg );
+       animation-delay: 0s;
+}
+
+@keyframes mw-spinner {
+       0% {
+               opacity: 1;
+       }
+
+       100% {
+               opacity: 0;
+       }
+}
index 589ae23..b926454 100644 (file)
@@ -1,5 +1,7 @@
 @import 'mediawiki.mixins';
 
+/* stylelint-disable selector-class-pattern */
+
 /* Table Sorting */
 
 // Reserve space for table sortable controls
index ea60702..c239a8f 100644 (file)
@@ -1,3 +1,5 @@
+/* stylelint-disable selector-class-pattern */
+
 .tipsy {
        padding: 5px;
        position: absolute;
index 78c4c04..ac68b7a 100644 (file)
@@ -1,3 +1,5 @@
+/* stylelint-disable selector-class-pattern */
+
 .jquery-confirmable-button {
        /* Automatically flipped */
        margin-left: 1ex;
index 028b4b9..08bb601 100644 (file)
@@ -36,6 +36,7 @@
         *     the first parameter and 'yes' or 'no' as the second.
         * @param {Function} [options.handler] Callback to fire when the action is confirmed (user clicks
         *     the 'Yes' button).
+        * @param {string} [options.delegate] Optional selector used for jQuery event delegation
         * @param {string} [options.i18n] Text to use for interface elements.
         * @param {string} [options.i18n.space] Word separator to place between the three text messages.
         * @param {string} [options.i18n.confirm] Text to use for the confirmation question.
        $.fn.confirmable = function ( options ) {
                options = $.extend( true, {}, $.fn.confirmable.defaultOptions, options || {} );
 
-               return this.on( options.events, function ( e ) {
-                       var $element, $text, $buttonYes, $buttonNo, $wrapper, $interface, $elementClone,
-                               interfaceWidth, elementWidth, rtl, positionOffscreen, positionRestore, sideMargin;
+               if ( options.delegate === null ) {
+                       return this.on( options.events, function ( e ) {
+                               $.fn.confirmable.handler( e, options );
+                       } );
+               }
 
-                       $element = $( this );
+               return this.on( options.events, options.delegate, function ( e ) {
+                       $.fn.confirmable.handler( e, options );
+               } );
+       };
 
-                       if ( $element.data( 'jquery-confirmable-button' ) ) {
-                               // We're running on a clone of this element that represents the 'Yes' or 'No' button.
-                               // (This should never happen for the 'No' case unless calling code does bad things.)
-                               return;
-                       }
+       $.fn.confirmable.handler = function ( event, options ) {
+               var $element, $text, $buttonYes, $buttonNo, $wrapper, $interface, $elementClone,
+                       interfaceWidth, elementWidth, rtl, positionOffscreen, positionRestore, sideMargin;
 
-                       // Only prevent native event handling. Stopping other JavaScript event handlers
-                       // is impossible because they might have already run (we have no control over the order).
-                       e.preventDefault();
+               $element = $( event.target );
 
-                       rtl = $element.css( 'direction' ) === 'rtl';
-                       if ( rtl ) {
-                               positionOffscreen = { position: 'absolute', right: '-9999px' };
-                               positionRestore = { position: '', right: '' };
-                               sideMargin = 'marginRight';
-                       } else {
-                               positionOffscreen = { position: 'absolute', left: '-9999px' };
-                               positionRestore = { position: '', left: '' };
-                               sideMargin = 'marginLeft';
-                       }
+               if ( $element.data( 'jquery-confirmable-button' ) ) {
+                       // We're running on a clone of this element that represents the 'Yes' or 'No' button.
+                       // (This should never happen for the 'No' case unless calling code does bad things.)
+                       return;
+               }
 
-                       if ( $element.hasClass( 'jquery-confirmable-element' ) ) {
-                               $wrapper = $element.closest( '.jquery-confirmable-wrapper' );
-                               $interface = $wrapper.find( '.jquery-confirmable-interface' );
-                               $text = $interface.find( '.jquery-confirmable-text' );
-                               $buttonYes = $interface.find( '.jquery-confirmable-button-yes' );
-                               $buttonNo = $interface.find( '.jquery-confirmable-button-no' );
+               // Only prevent native event handling. Stopping other JavaScript event handlers
+               // is impossible because they might have already run (we have no control over the order).
+               event.preventDefault();
+
+               rtl = $element.css( 'direction' ) === 'rtl';
+               if ( rtl ) {
+                       positionOffscreen = { position: 'absolute', right: '-9999px' };
+                       positionRestore = { position: '', right: '' };
+                       sideMargin = 'marginRight';
+               } else {
+                       positionOffscreen = { position: 'absolute', left: '-9999px' };
+                       positionRestore = { position: '', left: '' };
+                       sideMargin = 'marginLeft';
+               }
 
-                               interfaceWidth = $interface.data( 'jquery-confirmable-width' );
-                               elementWidth = $element.data( 'jquery-confirmable-width' );
+               if ( $element.hasClass( 'jquery-confirmable-element' ) ) {
+                       $wrapper = $element.closest( '.jquery-confirmable-wrapper' );
+                       $interface = $wrapper.find( '.jquery-confirmable-interface' );
+                       $text = $interface.find( '.jquery-confirmable-text' );
+                       $buttonYes = $interface.find( '.jquery-confirmable-button-yes' );
+                       $buttonNo = $interface.find( '.jquery-confirmable-button-no' );
+
+                       interfaceWidth = $interface.data( 'jquery-confirmable-width' );
+                       elementWidth = $element.data( 'jquery-confirmable-width' );
+               } else {
+                       $elementClone = $element.clone( true );
+                       $element.addClass( 'jquery-confirmable-element' );
+
+                       elementWidth = $element.width();
+                       $element.data( 'jquery-confirmable-width', elementWidth );
+
+                       $wrapper = $( '<span>' )
+                               .addClass( 'jquery-confirmable-wrapper' );
+                       $element.wrap( $wrapper );
+
+                       // Build the mini-dialog
+                       $text = $( '<span>' )
+                               .addClass( 'jquery-confirmable-text' )
+                               .text( options.i18n.confirm );
+
+                       // Clone original element along with event handlers to easily replicate its behavior.
+                       // We could fiddle with .trigger() etc., but that is troublesome especially since
+                       // Safari doesn't implement .click() on <a> links and jQuery follows suit.
+                       $buttonYes = $elementClone.clone( true )
+                               .addClass( 'jquery-confirmable-button jquery-confirmable-button-yes' )
+                               .data( 'jquery-confirmable-button', true )
+                               .text( options.i18n.yes );
+                       if ( options.handler ) {
+                               $buttonYes.on( options.events, options.handler );
+                       }
+                       if ( options.i18n.yesTitle ) {
+                               $buttonYes.attr( 'title', options.i18n.yesTitle );
+                       }
+                       $buttonYes = options.buttonCallback( $buttonYes, 'yes' );
+
+                       // Clone it without any events and prevent default action to represent the 'No' button.
+                       $buttonNo = $elementClone.clone( false )
+                               .addClass( 'jquery-confirmable-button jquery-confirmable-button-no' )
+                               .data( 'jquery-confirmable-button', true )
+                               .text( options.i18n.no )
+                               .on( options.events, function ( e ) {
+                                       $element.css( sideMargin, 0 );
+                                       $interface.css( 'width', 0 );
+                                       e.preventDefault();
+                               } );
+                       if ( options.i18n.noTitle ) {
+                               $buttonNo.attr( 'title', options.i18n.noTitle );
                        } else {
-                               $elementClone = $element.clone( true );
-                               $element.addClass( 'jquery-confirmable-element' );
-
-                               elementWidth = $element.width();
-                               $element.data( 'jquery-confirmable-width', elementWidth );
-
-                               $wrapper = $( '<span>' )
-                                       .addClass( 'jquery-confirmable-wrapper' );
-                               $element.wrap( $wrapper );
-
-                               // Build the mini-dialog
-                               $text = $( '<span>' )
-                                       .addClass( 'jquery-confirmable-text' )
-                                       .text( options.i18n.confirm );
-
-                               // Clone original element along with event handlers to easily replicate its behavior.
-                               // We could fiddle with .trigger() etc., but that is troublesome especially since
-                               // Safari doesn't implement .click() on <a> links and jQuery follows suit.
-                               $buttonYes = $elementClone.clone( true )
-                                       .addClass( 'jquery-confirmable-button jquery-confirmable-button-yes' )
-                                       .data( 'jquery-confirmable-button', true )
-                                       .text( options.i18n.yes );
-                               if ( options.handler ) {
-                                       $buttonYes.on( options.events, options.handler );
-                               }
-                               if ( options.i18n.yesTitle ) {
-                                       $buttonYes.attr( 'title', options.i18n.yesTitle );
-                               }
-                               $buttonYes = options.buttonCallback( $buttonYes, 'yes' );
-
-                               // Clone it without any events and prevent default action to represent the 'No' button.
-                               $buttonNo = $elementClone.clone( false )
-                                       .addClass( 'jquery-confirmable-button jquery-confirmable-button-no' )
-                                       .data( 'jquery-confirmable-button', true )
-                                       .text( options.i18n.no )
-                                       .on( options.events, function ( e ) {
-                                               $element.css( sideMargin, 0 );
-                                               $interface.css( 'width', 0 );
-                                               e.preventDefault();
-                                       } );
-                               if ( options.i18n.noTitle ) {
-                                       $buttonNo.attr( 'title', options.i18n.noTitle );
-                               } else {
-                                       $buttonNo.removeAttr( 'title' );
-                               }
-                               $buttonNo = options.buttonCallback( $buttonNo, 'no' );
-
-                               // Prevent memory leaks
-                               $elementClone.remove();
-
-                               $interface = $( '<span>' )
-                                       .addClass( 'jquery-confirmable-interface' )
-                                       .append( $text, options.i18n.space, $buttonYes, options.i18n.space, $buttonNo );
-                               $interface = options.wrapperCallback( $interface );
-
-                               // Render offscreen to measure real width
-                               $interface.css( positionOffscreen );
-                               // Insert it in the correct place while we're at it
-                               $element.after( $interface );
-                               interfaceWidth = $interface.width();
-                               $interface.data( 'jquery-confirmable-width', interfaceWidth );
-                               $interface.css( positionRestore );
-
-                               // Hide to animate the transition later
-                               $interface.css( 'width', 0 );
+                               $buttonNo.removeAttr( 'title' );
                        }
+                       $buttonNo = options.buttonCallback( $buttonNo, 'no' );
+
+                       // Prevent memory leaks
+                       $elementClone.remove();
+
+                       $interface = $( '<span>' )
+                               .addClass( 'jquery-confirmable-interface' )
+                               .append( $text, options.i18n.space, $buttonYes, options.i18n.space, $buttonNo );
+                       $interface = options.wrapperCallback( $interface );
+
+                       // Render offscreen to measure real width
+                       $interface.css( positionOffscreen );
+                       // Insert it in the correct place while we're at it
+                       $element.after( $interface );
+                       interfaceWidth = $interface.width();
+                       $interface.data( 'jquery-confirmable-width', interfaceWidth );
+                       $interface.css( positionRestore );
+
+                       // Hide to animate the transition later
+                       $interface.css( 'width', 0 );
+               }
 
-                       // Hide element, show interface. This triggers both transitions.
-                       // In a timeout to trigger the 'width' transition.
-                       setTimeout( function () {
-                               $element.css( sideMargin, -elementWidth );
-                               $interface.css( 'width', interfaceWidth );
-                       }, 1 );
-               } );
+               // Hide element, show interface. This triggers both transitions.
+               // In a timeout to trigger the 'width' transition.
+               setTimeout( function () {
+                       $element.css( sideMargin, -elementWidth );
+                       $interface.css( 'width', interfaceWidth );
+               }, 1 );
        };
 
        /**
                wrapperCallback: identity,
                buttonCallback: identity,
                handler: null,
+               delegate: null,
                i18n: {
                        space: ' ',
                        confirm: 'Are you sure?',
index 26f8f9b..0e3394b 100644 (file)
@@ -31,7 +31,7 @@
         * function, if none, pass empty string.
         * @param {string} newVal New value that may have to be trimmed down.
         * @param {number} byteLimit Number of bytes the value may be in size.
-        * @param {Function} [filterFn] See jQuery#byteLimit.
+        * @param {Function} [filterFunction] See jQuery#byteLimit.
         * @return {Object}
         * @return {string} return.newVal
         * @return {boolean} return.trimmed
        mw.log.deprecate( $, 'trimByteLength', trimByteLength,
                'Use require( \'mediawiki.String\' ).trimByteLength instead.', '$.trimByteLength' );
 
-       function lengthLimit( trimFn, limit, filterFn ) {
+       function lengthLimit( trimFn, limit, filterFunction ) {
                var allowNativeMaxlength = trimFn === trimByteLength;
 
                // If the first argument is the function,
-               // set filterFn to the first argument's value and ignore the second argument.
+               // set filterFunction to the first argument's value and ignore the second argument.
                if ( typeof limit === 'function' ) {
-                       filterFn = limit;
+                       filterFunction = limit;
                        limit = undefined;
                // Either way, verify it is a function so we don't have to call
                // isFunction again after this.
-               } else if ( !filterFn || typeof filterFn !== 'function' ) {
-                       filterFn = undefined;
+               } else if ( !filterFunction || typeof filterFunction !== 'function' ) {
+                       filterFunction = undefined;
                }
 
                // The following is specific to each element in the collection.
                                return;
                        }
 
-                       if ( filterFn ) {
+                       if ( filterFunction ) {
                                // Save function for reference
-                               $el.data( 'lengthLimit.callback', filterFn );
+                               $el.data( 'lengthLimit.callback', filterFunction );
                        }
 
                        // Remove old event handlers (if there are any)
                        $el.off( '.lengthLimit' );
 
-                       if ( filterFn || !allowNativeMaxlength ) {
+                       if ( filterFunction || !allowNativeMaxlength ) {
                                // Disable the native maxLength (if there is any), because it interferes
                                // with the (differently calculated) character/byte limit.
                                // Aside from being differently calculated,
                                        prevSafeVal,
                                        this.value,
                                        elLimit,
-                                       filterFn
+                                       filterFunction
                                );
 
                                // Only set value property if it was trimmed, because whenever the
         *
         * @param {number} [limit] Limit to enforce, fallsback to maxLength-attribute,
         *  called with fetched value as argument.
-        * @param {Function} [filterFn] Function to call on the string before assessing the length.
+        * @param {Function} [filterFunction] Function to call on the string before assessing the length.
         * @return {jQuery}
         * @chainable
         */
-       $.fn.byteLimit = function ( limit, filterFn ) {
-               return lengthLimit.call( this, trimByteLength, limit, filterFn );
+       $.fn.byteLimit = function ( limit, filterFunction ) {
+               return lengthLimit.call( this, trimByteLength, limit, filterFunction );
        };
 
        /**
         *
         * @param {number} [limit] Limit to enforce, fallsback to maxLength-attribute,
         *  called with fetched value as argument.
-        * @param {Function} [filterFn] Function to call on the string before assessing the length.
+        * @param {Function} [filterFunction] Function to call on the string before assessing the length.
         * @return {jQuery}
         * @chainable
         */
-       $.fn.codePointLimit = function ( limit, filterFn ) {
-               return lengthLimit.call( this, trimCodePointLength, limit, filterFn );
+       $.fn.codePointLimit = function ( limit, filterFunction ) {
+               return lengthLimit.call( this, trimCodePointLength, limit, filterFunction );
        };
 
        /**
index ec96cb6..0f922c9 100644 (file)
@@ -124,6 +124,12 @@ li,
        }
 }
 
+fieldset.mw-collapsible .mw-collapsible-toggle {
+       position: absolute;
+       right: 0;
+       z-index: 1;
+}
+
 // special treatment for list items to match above
 // !important necessary to override overly-specific float left and right above.
 ol.mw-collapsible:not( @{exclude} ):before,
index 825c7ca..7c6d032 100644 (file)
@@ -1,5 +1,7 @@
 /* suggestions plugin */
 
+/* stylelint-disable selector-class-pattern */
+
 .suggestions {
        overflow: hidden;
        position: absolute;
index d9a094c..a585cf3 100644 (file)
                configure: function ( context, property, value ) {
                        var newCSS,
                                $result, $results, $spanForWidth, childrenWidth,
+                               regionIsFixed, regionPosition,
                                i, expWidth, maxWidth, text;
 
                        // Validate creation using fallback values
                                                        // Rebuild the suggestions list
                                                        context.data.$container.show();
                                                        // Update the size and position of the list
+                                                       regionIsFixed = ( function () {
+                                                               var $el = context.config.$region;
+                                                               do {
+                                                                       if ( $el.css( 'position' ) === 'fixed' ) {
+                                                                               return true;
+                                                                       }
+                                                                       $el = $( $el[ 0 ].offsetParent );
+                                                               } while ( $el.length );
+                                                               return false;
+                                                       }() );
+                                                       regionPosition = regionIsFixed ?
+                                                               context.config.$region[ 0 ].getBoundingClientRect() :
+                                                               context.config.$region.offset();
                                                        newCSS = {
-                                                               top: context.config.$region.offset().top + context.config.$region.outerHeight(),
+                                                               position: regionIsFixed ? 'fixed' : 'absolute',
+                                                               top: regionPosition.top + context.config.$region.outerHeight(),
                                                                bottom: 'auto',
                                                                width: context.config.$region.outerWidth(),
                                                                height: 'auto'
                                                                                        expandFrom = 'start';
                                                                                } else {
                                                                                        // Calculate the center points of the input and document
-                                                                                       regionCenter = $region.offset().left + regionWidth / 2;
+                                                                                       regionCenter = regionPosition.left + regionWidth / 2;
                                                                                        docCenter = docWidth / 2;
                                                                                        if ( Math.abs( regionCenter - docCenter ) < ( 0.10 * docCenter ) ) {
                                                                                                // If the input's center is within 10% of the document center
 
                                                        if ( context.config.expandFrom === 'left' ) {
                                                                // Expand from left
-                                                               newCSS.left = context.config.$region.offset().left;
+                                                               newCSS.left = regionPosition.left;
                                                                newCSS.right = 'auto';
                                                        } else {
                                                                // Expand from right
                                                                newCSS.left = 'auto';
-                                                               newCSS.right = $( 'body' ).width() - ( context.config.$region.offset().left + context.config.$region.outerWidth() );
+                                                               newCSS.right = $( 'body' ).width() - ( regionPosition.left + context.config.$region.outerWidth() );
                                                        }
 
                                                        context.data.$container.css( newCSS );
index 5d9bef0..5960f93 100644 (file)
         * function, if none, pass empty string.
         * @param {string} newVal New value that may have to be trimmed down.
         * @param {number} byteLimit Number of bytes the value may be in size.
-        * @param {Function} [filterFn] Function to call on the string before assessing the length.
+        * @param {Function} [filterFunction] Function to call on the string before assessing the length.
         * @return {Object}
         * @return {string} return.newVal
         * @return {boolean} return.trimmed
         */
-       function trimByteLength( safeVal, newVal, byteLimit, filterFn ) {
+       function trimByteLength( safeVal, newVal, byteLimit, filterFunction ) {
                var lengthFn;
-               if ( filterFn ) {
+               if ( filterFunction ) {
                        lengthFn = function ( val ) {
-                               return byteLength( filterFn( val ) );
+                               return byteLength( filterFunction( val ) );
                        };
                } else {
                        lengthFn = byteLength;
         * function, if none, pass empty string.
         * @param {string} newVal New value that may have to be trimmed down.
         * @param {number} codePointLimit Number of characters the value may be in size.
-        * @param {Function} [filterFn] Function to call on the string before assessing the length.
+        * @param {Function} [filterFunction] Function to call on the string before assessing the length.
         * @return {Object}
         * @return {string} return.newVal
         * @return {boolean} return.trimmed
         */
-       function trimCodePointLength( safeVal, newVal, codePointLimit, filterFn ) {
+       function trimCodePointLength( safeVal, newVal, codePointLimit, filterFunction ) {
                var lengthFn;
-               if ( filterFn ) {
+               if ( filterFunction ) {
                        lengthFn = function ( val ) {
-                               return codePointLength( filterFn( val ) );
+                               return codePointLength( filterFunction( val ) );
                        };
                } else {
                        lengthFn = codePointLength;
diff --git a/resources/src/mediawiki.Title/.eslintrc.json b/resources/src/mediawiki.Title/.eslintrc.json
new file mode 100644 (file)
index 0000000..ad8dbb3
--- /dev/null
@@ -0,0 +1,5 @@
+{
+       "parserOptions": {
+               "sourceType": "module"
+       }
+}
index 6bb3bce..900dab2 100644 (file)
 /*!
  * @author Neil Kandalgaonkar, 2010
- * @author Timo Tijhof
  * @since 1.18
  */
 
-( function () {
-       /**
-        * Parse titles into an object structure. Note that when using the constructor
-        * directly, passing invalid titles will result in an exception. Use #newFromText to use the
-        * logic directly and get null for invalid titles which is easier to work with.
-        *
-        * Note that in the constructor and #newFromText method, `namespace` is the **default** namespace
-        * only, and can be overridden by a namespace prefix in `title`. If you do not want this behavior,
-        * use #makeTitle. Compare:
-        *
-        *     new mw.Title( 'Foo', NS_TEMPLATE ).getPrefixedText();                  // => 'Template:Foo'
-        *     mw.Title.newFromText( 'Foo', NS_TEMPLATE ).getPrefixedText();          // => 'Template:Foo'
-        *     mw.Title.makeTitle( NS_TEMPLATE, 'Foo' ).getPrefixedText();            // => 'Template:Foo'
-        *
-        *     new mw.Title( 'Category:Foo', NS_TEMPLATE ).getPrefixedText();         // => 'Category:Foo'
-        *     mw.Title.newFromText( 'Category:Foo', NS_TEMPLATE ).getPrefixedText(); // => 'Category:Foo'
-        *     mw.Title.makeTitle( NS_TEMPLATE, 'Category:Foo' ).getPrefixedText();   // => 'Template:Category:Foo'
-        *
-        *     new mw.Title( 'Template:Foo', NS_TEMPLATE ).getPrefixedText();         // => 'Template:Foo'
-        *     mw.Title.newFromText( 'Template:Foo', NS_TEMPLATE ).getPrefixedText(); // => 'Template:Foo'
-        *     mw.Title.makeTitle( NS_TEMPLATE, 'Template:Foo' ).getPrefixedText();   // => 'Template:Template:Foo'
-        *
-        * @class mw.Title
-        */
-
-       /* Private members */
-
-       var
-               mwString = require( 'mediawiki.String' ),
-
-               namespaceIds = mw.config.get( 'wgNamespaceIds' ),
-
-               /**
-                * @private
-                * @static
-                * @property NS_MAIN
-                */
-               NS_MAIN = namespaceIds[ '' ],
-
-               /**
-                * @private
-                * @static
-                * @property NS_TALK
-                */
-               NS_TALK = namespaceIds.talk,
-
-               /**
-                * @private
-                * @static
-                * @property NS_SPECIAL
-                */
-               NS_SPECIAL = namespaceIds.special,
-
-               /**
-                * @private
-                * @static
-                * @property NS_MEDIA
-                */
-               NS_MEDIA = namespaceIds.media,
-
-               /**
-                * @private
-                * @static
-                * @property NS_FILE
-                */
-               NS_FILE = namespaceIds.file,
-
-               /**
-                * @private
-                * @static
-                * @property FILENAME_MAX_BYTES
-                */
-               FILENAME_MAX_BYTES = 240,
-
-               /**
-                * @private
-                * @static
-                * @property TITLE_MAX_BYTES
-                */
-               TITLE_MAX_BYTES = 255,
-
-               /**
-                * Get the namespace id from a namespace name (either from the localized, canonical or alias
-                * name).
-                *
-                * Example: On a German wiki this would return 6 for any of 'File', 'Datei', 'Image' or
-                * even 'Bild'.
-                *
-                * @private
-                * @static
-                * @method getNsIdByName
-                * @param {string} ns Namespace name (case insensitive, leading/trailing space ignored)
-                * @return {number|boolean} Namespace id or boolean false
-                */
-               getNsIdByName = function ( ns ) {
-                       var id;
-
-                       // Don't cast non-strings to strings, because null or undefined should not result in
-                       // returning the id of a potential namespace called "Null:" (e.g. on null.example.org/wiki)
-                       // Also, toLowerCase throws exception on null/undefined, because it is a String method.
-                       if ( typeof ns !== 'string' ) {
-                               return false;
-                       }
-                       // TODO: Should just use local var namespaceIds here but it
-                       // breaks test which modify the config
-                       id = mw.config.get( 'wgNamespaceIds' )[ ns.toLowerCase() ];
-                       if ( id === undefined ) {
-                               return false;
-                       }
-                       return id;
-               },
-
-               /**
-                * @private
-                * @method getNamespacePrefix_
-                * @param {number} namespace
-                * @return {string}
-                */
-               getNamespacePrefix = function ( namespace ) {
-                       return namespace === NS_MAIN ?
-                               '' :
-                               ( mw.config.get( 'wgFormattedNamespaces' )[ namespace ].replace( / /g, '_' ) + ':' );
-               },
-
-               rUnderscoreTrim = /^_+|_+$/g,
-
-               rSplit = /^(.+?)_*:_*(.*)$/,
-
-               // See MediaWikiTitleCodec.php#getTitleInvalidRegex
-               rInvalid = new RegExp(
-                       '[^' + mw.config.get( 'wgLegalTitleChars' ) + ']' +
-                       // URL percent encoding sequences interfere with the ability
-                       // to round-trip titles -- you can't link to them consistently.
-                       '|%[0-9A-Fa-f]{2}' +
-                       // XML/HTML character references produce similar issues.
-                       '|&[A-Za-z0-9\u0080-\uFFFF]+;' +
-                       '|&#[0-9]+;' +
-                       '|&#x[0-9A-Fa-f]+;'
-               ),
-
-               // From MediaWikiTitleCodec::splitTitleString() in PHP
-               // Note that this is not equivalent to /\s/, e.g. underscore is included, tab is not included.
-               rWhitespace = /[ _\u00A0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]+/g,
-
-               // From MediaWikiTitleCodec::splitTitleString() in PHP
-               rUnicodeBidi = /[\u200E\u200F\u202A-\u202E]/g,
-
-               /**
-                * Slightly modified from Flinfo. Credit goes to Lupo and Flominator.
-                * @private
-                * @static
-                * @property sanitationRules
-                */
-               sanitationRules = [
-                       // "signature"
-                       {
-                               pattern: /~{3}/g,
-                               replace: '',
-                               generalRule: true
-                       },
-                       // control characters
-                       {
-                               // eslint-disable-next-line no-control-regex
-                               pattern: /[\x00-\x1f\x7f]/g,
-                               replace: '',
-                               generalRule: true
-                       },
-                       // URL encoding (possibly)
-                       {
-                               pattern: /%([0-9A-Fa-f]{2})/g,
-                               replace: '% $1',
-                               generalRule: true
-                       },
-                       // HTML-character-entities
-                       {
-                               pattern: /&(([A-Za-z0-9\x80-\xff]+|#[0-9]+|#x[0-9A-Fa-f]+);)/g,
-                               replace: '& $1',
-                               generalRule: true
-                       },
-                       // slash, colon (not supported by file systems like NTFS/Windows, Mac OS 9 [:], ext4 [/])
-                       {
-                               pattern: new RegExp( '[' + mw.config.get( 'wgIllegalFileChars', '' ) + ']', 'g' ),
-                               replace: '-',
-                               fileRule: true
-                       },
-                       // brackets, greater than
-                       {
-                               pattern: /[}\]>]/g,
-                               replace: ')',
-                               generalRule: true
-                       },
-                       // brackets, lower than
-                       {
-                               pattern: /[{[<]/g,
-                               replace: '(',
-                               generalRule: true
-                       },
-                       // everything that wasn't covered yet
-                       {
-                               pattern: new RegExp( rInvalid.source, 'g' ),
-                               replace: '-',
-                               generalRule: true
-                       },
-                       // directory structures
-                       {
-                               pattern: /^(\.|\.\.|\.\/.*|\.\.\/.*|.*\/\.\/.*|.*\/\.\.\/.*|.*\/\.|.*\/\.\.)$/g,
-                               replace: '',
-                               generalRule: true
-                       }
-               ],
-
-               /**
-                * Internal helper for #constructor and #newFromText.
-                *
-                * Based on Title.php#secureAndSplit
-                *
-                * @private
-                * @static
-                * @method parse
-                * @param {string} title
-                * @param {number} [defaultNamespace=NS_MAIN]
-                * @return {Object|boolean}
-                */
-               parse = function ( title, defaultNamespace ) {
-                       var namespace, m, id, i, fragment, ext;
-
-                       namespace = defaultNamespace === undefined ? NS_MAIN : defaultNamespace;
-
-                       title = title
-                               // Strip Unicode bidi override characters
-                               .replace( rUnicodeBidi, '' )
-                               // Normalise whitespace to underscores and remove duplicates
-                               .replace( rWhitespace, '_' )
-                               // Trim underscores
-                               .replace( rUnderscoreTrim, '' );
-
-                       // Process initial colon
-                       if ( title !== '' && title[ 0 ] === ':' ) {
-                               // Initial colon means main namespace instead of specified default
-                               namespace = NS_MAIN;
-                               title = title
-                                       // Strip colon
-                                       .slice( 1 )
-                                       // Trim underscores
-                                       .replace( rUnderscoreTrim, '' );
-                       }
-
-                       if ( title === '' ) {
-                               return false;
-                       }
-
-                       // Process namespace prefix (if any)
-                       m = title.match( rSplit );
-                       if ( m ) {
-                               id = getNsIdByName( m[ 1 ] );
-                               if ( id !== false ) {
-                                       // Ordinary namespace
-                                       namespace = id;
-                                       title = m[ 2 ];
-
-                                       // For Talk:X pages, make sure X has no "namespace" prefix
-                                       if ( namespace === NS_TALK && ( m = title.match( rSplit ) ) ) {
-                                               // Disallow titles like Talk:File:x (subject should roundtrip: talk:file:x -> file:x -> file_talk:x)
-                                               if ( getNsIdByName( m[ 1 ] ) !== false ) {
-                                                       return false;
-                                               }
-                                       }
-                               }
-                       }
-
-                       // Process fragment
-                       i = title.indexOf( '#' );
-                       if ( i === -1 ) {
-                               fragment = null;
-                       } else {
-                               fragment = title
-                                       // Get segment starting after the hash
-                                       .slice( i + 1 )
-                                       // Convert to text
-                                       // NB: Must not be trimmed ("Example#_foo" is not the same as "Example#foo")
-                                       .replace( /_/g, ' ' );
-
-                               title = title
-                                       // Strip hash
-                                       .slice( 0, i )
-                                       // Trim underscores, again (strips "_" from "bar" in "Foo_bar_#quux")
-                                       .replace( rUnderscoreTrim, '' );
-                       }
-
-                       // Reject illegal characters
-                       if ( title.match( rInvalid ) ) {
-                               return false;
-                       }
-
-                       // Disallow titles that browsers or servers might resolve as directory navigation
-                       if (
-                               title.indexOf( '.' ) !== -1 && (
-                                       title === '.' || title === '..' ||
-                                       title.indexOf( './' ) === 0 ||
-                                       title.indexOf( '../' ) === 0 ||
-                                       title.indexOf( '/./' ) !== -1 ||
-                                       title.indexOf( '/../' ) !== -1 ||
-                                       title.slice( -2 ) === '/.' ||
-                                       title.slice( -3 ) === '/..'
-                               )
-                       ) {
-                               return false;
-                       }
-
-                       // Disallow magic tilde sequence
-                       if ( title.indexOf( '~~~' ) !== -1 ) {
-                               return false;
-                       }
-
-                       // Disallow titles exceeding the TITLE_MAX_BYTES byte size limit (size of underlying database field)
-                       // Except for special pages, e.g. [[Special:Block/Long name]]
-                       // Note: The PHP implementation also asserts that even in NS_SPECIAL, the title should
-                       // be less than 512 bytes.
-                       if ( namespace !== NS_SPECIAL && mwString.byteLength( title ) > TITLE_MAX_BYTES ) {
-                               return false;
-                       }
+/**
+ * Parse titles into an object structure. Note that when using the constructor
+ * directly, passing invalid titles will result in an exception. Use #newFromText to use the
+ * logic directly and get null for invalid titles which is easier to work with.
+ *
+ * Note that in the constructor and #newFromText method, `namespace` is the **default** namespace
+ * only, and can be overridden by a namespace prefix in `title`. If you do not want this behavior,
+ * use #makeTitle. Compare:
+ *
+ *     new mw.Title( 'Foo', NS_TEMPLATE ).getPrefixedText();                  // => 'Template:Foo'
+ *     mw.Title.newFromText( 'Foo', NS_TEMPLATE ).getPrefixedText();          // => 'Template:Foo'
+ *     mw.Title.makeTitle( NS_TEMPLATE, 'Foo' ).getPrefixedText();            // => 'Template:Foo'
+ *
+ *     new mw.Title( 'Category:Foo', NS_TEMPLATE ).getPrefixedText();         // => 'Category:Foo'
+ *     mw.Title.newFromText( 'Category:Foo', NS_TEMPLATE ).getPrefixedText(); // => 'Category:Foo'
+ *     mw.Title.makeTitle( NS_TEMPLATE, 'Category:Foo' ).getPrefixedText();   // => 'Template:Category:Foo'
+ *
+ *     new mw.Title( 'Template:Foo', NS_TEMPLATE ).getPrefixedText();         // => 'Template:Foo'
+ *     mw.Title.newFromText( 'Template:Foo', NS_TEMPLATE ).getPrefixedText(); // => 'Template:Foo'
+ *     mw.Title.makeTitle( NS_TEMPLATE, 'Template:Foo' ).getPrefixedText();   // => 'Template:Template:Foo'
+ *
+ * @class mw.Title
+ */
 
-                       // Can't make a link to a namespace alone.
-                       if ( title === '' && namespace !== NS_MAIN ) {
-                               return false;
-                       }
+/* Private members */
 
-                       // Any remaining initial :s are illegal.
-                       if ( title[ 0 ] === ':' ) {
-                               return false;
-                       }
+var
+       mwString = require( 'mediawiki.String' ),
 
-                       // For backwards-compatibility with old mw.Title, we separate the extension from the
-                       // rest of the title.
-                       i = title.lastIndexOf( '.' );
-                       if ( i === -1 || title.length <= i + 1 ) {
-                               // Extensions are the non-empty segment after the last dot
-                               ext = null;
-                       } else {
-                               ext = title.slice( i + 1 );
-                               title = title.slice( 0, i );
-                       }
+       toUpperMapping = require( './phpCharToUpper.json' ),
 
-                       return {
-                               namespace: namespace,
-                               title: title,
-                               ext: ext,
-                               fragment: fragment
-                       };
-               },
+       namespaceIds = mw.config.get( 'wgNamespaceIds' ),
 
-               /**
-                * Convert db-key to readable text.
-                *
-                * @private
-                * @static
-                * @method text
-                * @param {string} s
-                * @return {string}
-                */
-               text = function ( s ) {
-                       return s.replace( /_/g, ' ' );
-               },
+       /**
+        * @private
+        * @static
+        * @property NS_MAIN
+        */
+       NS_MAIN = namespaceIds[ '' ],
 
-               /**
-                * Sanitizes a string based on a rule set and a filter
-                *
-                * @private
-                * @static
-                * @method sanitize
-                * @param {string} s
-                * @param {Array} filter
-                * @return {string}
-                */
-               sanitize = function ( s, filter ) {
-                       var i, ruleLength, rule, m, filterLength,
-                               rules = sanitationRules;
-
-                       for ( i = 0, ruleLength = rules.length; i < ruleLength; ++i ) {
-                               rule = rules[ i ];
-                               for ( m = 0, filterLength = filter.length; m < filterLength; ++m ) {
-                                       if ( rule[ filter[ m ] ] ) {
-                                               s = s.replace( rule.pattern, rule.replace );
-                                       }
-                               }
-                       }
-                       return s;
-               },
+       /**
+        * @private
+        * @static
+        * @property NS_TALK
+        */
+       NS_TALK = namespaceIds.talk,
 
-               /**
-                * Cuts a string to a specific byte length, assuming UTF-8
-                * or less, if the last character is a multi-byte one
-                *
-                * @private
-                * @static
-                * @method trimToByteLength
-                * @param {string} s
-                * @param {number} length
-                * @return {string}
-                */
-               trimToByteLength = function ( s, length ) {
-                       return mwString.trimByteLength( '', s, length ).newVal;
-               },
+       /**
+        * @private
+        * @static
+        * @property NS_SPECIAL
+        */
+       NS_SPECIAL = namespaceIds.special,
 
-               /**
-                * Cuts a file name to a specific byte length
-                *
-                * @private
-                * @static
-                * @method trimFileNameToByteLength
-                * @param {string} name without extension
-                * @param {string} extension file extension
-                * @return {string} The full name, including extension
-                */
-               trimFileNameToByteLength = function ( name, extension ) {
-                       // There is a special byte limit for file names and ... remember the dot
-                       return trimToByteLength( name, FILENAME_MAX_BYTES - extension.length - 1 ) + '.' + extension;
-               };
+       /**
+        * @private
+        * @static
+        * @property NS_MEDIA
+        */
+       NS_MEDIA = namespaceIds.media,
 
        /**
-        * @method constructor
-        * @param {string} title Title of the page. If no second argument given,
-        *  this will be searched for a namespace
-        * @param {number} [namespace=NS_MAIN] If given, will used as default namespace for the given title
-        * @throws {Error} When the title is invalid
+        * @private
+        * @static
+        * @property NS_FILE
         */
-       function Title( title, namespace ) {
-               var parsed = parse( title, namespace );
-               if ( !parsed ) {
-                       throw new Error( 'Unable to parse title' );
-               }
+       NS_FILE = namespaceIds.file,
 
-               this.namespace = parsed.namespace;
-               this.title = parsed.title;
-               this.ext = parsed.ext;
-               this.fragment = parsed.fragment;
-       }
+       /**
+        * @private
+        * @static
+        * @property FILENAME_MAX_BYTES
+        */
+       FILENAME_MAX_BYTES = 240,
 
-       /* Static members */
+       /**
+        * @private
+        * @static
+        * @property TITLE_MAX_BYTES
+        */
+       TITLE_MAX_BYTES = 255,
 
        /**
-        * Constructor for Title objects with a null return instead of an exception for invalid titles.
+        * Get the namespace id from a namespace name (either from the localized, canonical or alias
+        * name).
         *
-        * Note that `namespace` is the **default** namespace only, and can be overridden by a namespace
-        * prefix in `title`. If you do not want this behavior, use #makeTitle. See #constructor for
-        * details.
+        * Example: On a German wiki this would return 6 for any of 'File', 'Datei', 'Image' or
+        * even 'Bild'.
         *
+        * @private
         * @static
-        * @param {string} title
-        * @param {number} [namespace=NS_MAIN] Default namespace
-        * @return {mw.Title|null} A valid Title object or null if the title is invalid
+        * @method getNsIdByName
+        * @param {string} ns Namespace name (case insensitive, leading/trailing space ignored)
+        * @return {number|boolean} Namespace id or boolean false
         */
-       Title.newFromText = function ( title, namespace ) {
-               var t, parsed = parse( title, namespace );
-               if ( !parsed ) {
-                       return null;
+       getNsIdByName = function ( ns ) {
+               var id;
+
+               // Don't cast non-strings to strings, because null or undefined should not result in
+               // returning the id of a potential namespace called "Null:" (e.g. on null.example.org/wiki)
+               // Also, toLowerCase throws exception on null/undefined, because it is a String method.
+               if ( typeof ns !== 'string' ) {
+                       return false;
                }
+               // TODO: Should just use local var namespaceIds here but it
+               // breaks test which modify the config
+               id = mw.config.get( 'wgNamespaceIds' )[ ns.toLowerCase() ];
+               if ( id === undefined ) {
+                       return false;
+               }
+               return id;
+       },
 
-               t = Object.create( Title.prototype );
-               t.namespace = parsed.namespace;
-               t.title = parsed.title;
-               t.ext = parsed.ext;
-               t.fragment = parsed.fragment;
-
-               return t;
-       };
+       /**
+        * @private
+        * @method getNamespacePrefix_
+        * @param {number} namespace
+        * @return {string}
+        */
+       getNamespacePrefix = function ( namespace ) {
+               return namespace === NS_MAIN ?
+                       '' :
+                       ( mw.config.get( 'wgFormattedNamespaces' )[ namespace ].replace( / /g, '_' ) + ':' );
+       },
+
+       rUnderscoreTrim = /^_+|_+$/g,
+
+       rSplit = /^(.+?)_*:_*(.*)$/,
+
+       // See MediaWikiTitleCodec.php#getTitleInvalidRegex
+       rInvalid = new RegExp(
+               '[^' + mw.config.get( 'wgLegalTitleChars' ) + ']' +
+               // URL percent encoding sequences interfere with the ability
+               // to round-trip titles -- you can't link to them consistently.
+               '|%[0-9A-Fa-f]{2}' +
+               // XML/HTML character references produce similar issues.
+               '|&[A-Za-z0-9\u0080-\uFFFF]+;' +
+               '|&#[0-9]+;' +
+               '|&#x[0-9A-Fa-f]+;'
+       ),
+
+       // From MediaWikiTitleCodec::splitTitleString() in PHP
+       // Note that this is not equivalent to /\s/, e.g. underscore is included, tab is not included.
+       rWhitespace = /[ _\u00A0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]+/g,
+
+       // From MediaWikiTitleCodec::splitTitleString() in PHP
+       rUnicodeBidi = /[\u200E\u200F\u202A-\u202E]/g,
 
        /**
-        * Constructor for Title objects with predefined namespace.
-        *
-        * Unlike #newFromText or #constructor, this function doesn't allow the given `namespace` to be
-        * overridden by a namespace prefix in `title`. See #constructor for details about this behavior.
-        *
-        * The single exception to this is when `namespace` is 0, indicating the main namespace. The
-        * function behaves like #newFromText in that case.
-        *
+        * Slightly modified from Flinfo. Credit goes to Lupo and Flominator.
+        * @private
         * @static
-        * @param {number} namespace Namespace to use for the title
-        * @param {string} title
-        * @return {mw.Title|null} A valid Title object or null if the title is invalid
+        * @property sanitationRules
         */
-       Title.makeTitle = function ( namespace, title ) {
-               return mw.Title.newFromText( getNamespacePrefix( namespace ) + title );
-       };
+       sanitationRules = [
+               // "signature"
+               {
+                       pattern: /~{3}/g,
+                       replace: '',
+                       generalRule: true
+               },
+               // control characters
+               {
+                       // eslint-disable-next-line no-control-regex
+                       pattern: /[\x00-\x1f\x7f]/g,
+                       replace: '',
+                       generalRule: true
+               },
+               // URL encoding (possibly)
+               {
+                       pattern: /%([0-9A-Fa-f]{2})/g,
+                       replace: '% $1',
+                       generalRule: true
+               },
+               // HTML-character-entities
+               {
+                       pattern: /&(([A-Za-z0-9\x80-\xff]+|#[0-9]+|#x[0-9A-Fa-f]+);)/g,
+                       replace: '& $1',
+                       generalRule: true
+               },
+               // slash, colon (not supported by file systems like NTFS/Windows, Mac OS 9 [:], ext4 [/])
+               {
+                       pattern: new RegExp( '[' + mw.config.get( 'wgIllegalFileChars', '' ) + ']', 'g' ),
+                       replace: '-',
+                       fileRule: true
+               },
+               // brackets, greater than
+               {
+                       pattern: /[}\]>]/g,
+                       replace: ')',
+                       generalRule: true
+               },
+               // brackets, lower than
+               {
+                       pattern: /[{[<]/g,
+                       replace: '(',
+                       generalRule: true
+               },
+               // everything that wasn't covered yet
+               {
+                       pattern: new RegExp( rInvalid.source, 'g' ),
+                       replace: '-',
+                       generalRule: true
+               },
+               // directory structures
+               {
+                       pattern: /^(\.|\.\.|\.\/.*|\.\.\/.*|.*\/\.\/.*|.*\/\.\.\/.*|.*\/\.|.*\/\.\.)$/g,
+                       replace: '',
+                       generalRule: true
+               }
+       ],
 
        /**
-        * Constructor for Title objects from user input altering that input to
-        * produce a title that MediaWiki will accept as legal
+        * Internal helper for #constructor and #newFromText.
+        *
+        * Based on Title.php#secureAndSplit
         *
+        * @private
         * @static
+        * @method parse
         * @param {string} title
-        * @param {number|Object} [defaultNamespaceOrOptions=NS_MAIN]
-        *  If given, will used as default namespace for the given title.
-        *  This method can also be called with two arguments, in which case
-        *  this becomes options (see below).
-        * @param {Object} [options] additional options
-        * @param {boolean} [options.forUploading=true]
-        *  Makes sure that a file is uploadable under the title returned.
-        *  There are pages in the file namespace under which file upload is impossible.
-        *  Automatically assumed if the title is created in the Media namespace.
-        * @return {mw.Title|null} A valid Title object or null if the input cannot be turned into a valid title
+        * @param {number} [defaultNamespace=NS_MAIN]
+        * @return {Object|boolean}
         */
-       Title.newFromUserInput = function ( title, defaultNamespaceOrOptions, options ) {
-               var namespace, m, id, ext, parts,
-                       defaultNamespace;
-
-               // defaultNamespace is optional; check whether options moves up
-               if ( arguments.length < 3 && typeof defaultNamespace === 'object' ) {
-                       options = defaultNamespaceOrOptions;
-               } else {
-                       defaultNamespace = defaultNamespaceOrOptions;
-               }
-
-               // merge options into defaults
-               options = $.extend( {
-                       forUploading: true
-               }, options );
+       parse = function ( title, defaultNamespace ) {
+               var namespace, m, id, i, fragment, ext;
 
                namespace = defaultNamespace === undefined ? NS_MAIN : defaultNamespace;
 
-               // Normalise additional whitespace
-               title = title.replace( /\s/g, ' ' ).trim();
+               title = title
+                       // Strip Unicode bidi override characters
+                       .replace( rUnicodeBidi, '' )
+                       // Normalise whitespace to underscores and remove duplicates
+                       .replace( rWhitespace, '_' )
+                       // Trim underscores
+                       .replace( rUnderscoreTrim, '' );
 
                // Process initial colon
                if ( title !== '' && title[ 0 ] === ':' ) {
                        namespace = NS_MAIN;
                        title = title
                                // Strip colon
-                               .substr( 1 )
+                               .slice( 1 )
                                // Trim underscores
                                .replace( rUnderscoreTrim, '' );
                }
 
+               if ( title === '' ) {
+                       return false;
+               }
+
                // Process namespace prefix (if any)
                m = title.match( rSplit );
                if ( m ) {
                                // Ordinary namespace
                                namespace = id;
                                title = m[ 2 ];
+
+                               // For Talk:X pages, make sure X has no "namespace" prefix
+                               if ( namespace === NS_TALK && ( m = title.match( rSplit ) ) ) {
+                                       // Disallow titles like Talk:File:x (subject should roundtrip: talk:file:x -> file:x -> file_talk:x)
+                                       if ( getNsIdByName( m[ 1 ] ) !== false ) {
+                                               return false;
+                                       }
+                               }
                        }
                }
 
-               if (
-                       namespace === NS_MEDIA ||
-                       ( options.forUploading && ( namespace === NS_FILE ) )
-               ) {
-
-                       title = sanitize( title, [ 'generalRule', 'fileRule' ] );
+               // Process fragment
+               i = title.indexOf( '#' );
+               if ( i === -1 ) {
+                       fragment = null;
+               } else {
+                       fragment = title
+                               // Get segment starting after the hash
+                               .slice( i + 1 )
+                               // Convert to text
+                               // NB: Must not be trimmed ("Example#_foo" is not the same as "Example#foo")
+                               .replace( /_/g, ' ' );
 
-                       // Operate on the file extension
-                       // Although it is possible having spaces between the name and the ".ext" this isn't nice for
-                       // operating systems hiding file extensions -> strip them later on
-                       parts = title.split( '.' );
+                       title = title
+                               // Strip hash
+                               .slice( 0, i )
+                               // Trim underscores, again (strips "_" from "bar" in "Foo_bar_#quux")
+                               .replace( rUnderscoreTrim, '' );
+               }
 
-                       if ( parts.length > 1 ) {
+               // Reject illegal characters
+               if ( title.match( rInvalid ) ) {
+                       return false;
+               }
 
-                               // Get the last part, which is supposed to be the file extension
-                               ext = parts.pop();
+               // Disallow titles that browsers or servers might resolve as directory navigation
+               if (
+                       title.indexOf( '.' ) !== -1 && (
+                               title === '.' || title === '..' ||
+                               title.indexOf( './' ) === 0 ||
+                               title.indexOf( '../' ) === 0 ||
+                               title.indexOf( '/./' ) !== -1 ||
+                               title.indexOf( '/../' ) !== -1 ||
+                               title.slice( -2 ) === '/.' ||
+                               title.slice( -3 ) === '/..'
+                       )
+               ) {
+                       return false;
+               }
 
-                               // Remove whitespace of the name part (that W/O extension)
-                               title = parts.join( '.' ).trim();
+               // Disallow magic tilde sequence
+               if ( title.indexOf( '~~~' ) !== -1 ) {
+                       return false;
+               }
 
-                               // Cut, if too long and append file extension
-                               title = trimFileNameToByteLength( title, ext );
+               // Disallow titles exceeding the TITLE_MAX_BYTES byte size limit (size of underlying database field)
+               // Except for special pages, e.g. [[Special:Block/Long name]]
+               // Note: The PHP implementation also asserts that even in NS_SPECIAL, the title should
+               // be less than 512 bytes.
+               if ( namespace !== NS_SPECIAL && mwString.byteLength( title ) > TITLE_MAX_BYTES ) {
+                       return false;
+               }
 
-                       } else {
+               // Can't make a link to a namespace alone.
+               if ( title === '' && namespace !== NS_MAIN ) {
+                       return false;
+               }
 
-                               // Missing file extension
-                               title = parts.join( '.' ).trim();
+               // Any remaining initial :s are illegal.
+               if ( title[ 0 ] === ':' ) {
+                       return false;
+               }
 
-                               // Name has no file extension and a fallback wasn't provided either
-                               return null;
-                       }
+               // For backwards-compatibility with old mw.Title, we separate the extension from the
+               // rest of the title.
+               i = title.lastIndexOf( '.' );
+               if ( i === -1 || title.length <= i + 1 ) {
+                       // Extensions are the non-empty segment after the last dot
+                       ext = null;
                } else {
-
-                       title = sanitize( title, [ 'generalRule' ] );
-
-                       // Cut titles exceeding the TITLE_MAX_BYTES byte size limit
-                       // (size of underlying database field)
-                       if ( namespace !== NS_SPECIAL ) {
-                               title = trimToByteLength( title, TITLE_MAX_BYTES );
-                       }
+                       ext = title.slice( i + 1 );
+                       title = title.slice( 0, i );
                }
 
-               // Any remaining initial :s are illegal.
-               title = title.replace( /^:+/, '' );
-
-               return Title.newFromText( title, namespace );
-       };
+               return {
+                       namespace: namespace,
+                       title: title,
+                       ext: ext,
+                       fragment: fragment
+               };
+       },
 
        /**
-        * Sanitizes a file name as supplied by the user, originating in the user's file system
-        * so it is most likely a valid MediaWiki title and file name after processing.
-        * Returns null on fatal errors.
+        * Convert db-key to readable text.
         *
+        * @private
         * @static
-        * @param {string} uncleanName The unclean file name including file extension but
-        *   without namespace
-        * @return {mw.Title|null} A valid Title object or null if the title is invalid
+        * @method text
+        * @param {string} s
+        * @return {string}
         */
-       Title.newFromFileName = function ( uncleanName ) {
+       text = function ( s ) {
+               return s.replace( /_/g, ' ' );
+       },
 
-               return Title.newFromUserInput( 'File:' + uncleanName, {
-                       forUploading: true
-               } );
-       };
+       /**
+        * Sanitizes a string based on a rule set and a filter
+        *
+        * @private
+        * @static
+        * @method sanitize
+        * @param {string} s
+        * @param {Array} filter
+        * @return {string}
+        */
+       sanitize = function ( s, filter ) {
+               var i, ruleLength, rule, m, filterLength,
+                       rules = sanitationRules;
+
+               for ( i = 0, ruleLength = rules.length; i < ruleLength; ++i ) {
+                       rule = rules[ i ];
+                       for ( m = 0, filterLength = filter.length; m < filterLength; ++m ) {
+                               if ( rule[ filter[ m ] ] ) {
+                                       s = s.replace( rule.pattern, rule.replace );
+                               }
+                       }
+               }
+               return s;
+       },
 
        /**
-        * Get the file title from an image element
+        * Cuts a string to a specific byte length, assuming UTF-8
+        * or less, if the last character is a multi-byte one
         *
-        *     var title = mw.Title.newFromImg( $( 'img:first' ) );
+        * @private
+        * @static
+        * @method trimToByteLength
+        * @param {string} s
+        * @param {number} length
+        * @return {string}
+        */
+       trimToByteLength = function ( s, length ) {
+               return mwString.trimByteLength( '', s, length ).newVal;
+       },
+
+       /**
+        * Cuts a file name to a specific byte length
         *
+        * @private
         * @static
-        * @param {HTMLElement|jQuery} img The image to use as a base
-        * @return {mw.Title|null} The file title or null if unsuccessful
+        * @method trimFileNameToByteLength
+        * @param {string} name without extension
+        * @param {string} extension file extension
+        * @return {string} The full name, including extension
         */
-       Title.newFromImg = function ( img ) {
-               var matches, i, regex, src, decodedSrc,
+       trimFileNameToByteLength = function ( name, extension ) {
+               // There is a special byte limit for file names and ... remember the dot
+               return trimToByteLength( name, FILENAME_MAX_BYTES - extension.length - 1 ) + '.' + extension;
+       };
+
+/**
+ * @method constructor
+ * @param {string} title Title of the page. If no second argument given,
+ *  this will be searched for a namespace
+ * @param {number} [namespace=NS_MAIN] If given, will used as default namespace for the given title
+ * @throws {Error} When the title is invalid
+ */
+function Title( title, namespace ) {
+       var parsed = parse( title, namespace );
+       if ( !parsed ) {
+               throw new Error( 'Unable to parse title' );
+       }
+
+       this.namespace = parsed.namespace;
+       this.title = parsed.title;
+       this.ext = parsed.ext;
+       this.fragment = parsed.fragment;
+}
+
+/* Static members */
+
+/**
+ * Constructor for Title objects with a null return instead of an exception for invalid titles.
+ *
+ * Note that `namespace` is the **default** namespace only, and can be overridden by a namespace
+ * prefix in `title`. If you do not want this behavior, use #makeTitle. See #constructor for
+ * details.
+ *
+ * @static
+ * @param {string} title
+ * @param {number} [namespace=NS_MAIN] Default namespace
+ * @return {mw.Title|null} A valid Title object or null if the title is invalid
+ */
+Title.newFromText = function ( title, namespace ) {
+       var t, parsed = parse( title, namespace );
+       if ( !parsed ) {
+               return null;
+       }
+
+       t = Object.create( Title.prototype );
+       t.namespace = parsed.namespace;
+       t.title = parsed.title;
+       t.ext = parsed.ext;
+       t.fragment = parsed.fragment;
+
+       return t;
+};
+
+/**
+ * Constructor for Title objects with predefined namespace.
+ *
+ * Unlike #newFromText or #constructor, this function doesn't allow the given `namespace` to be
+ * overridden by a namespace prefix in `title`. See #constructor for details about this behavior.
+ *
+ * The single exception to this is when `namespace` is 0, indicating the main namespace. The
+ * function behaves like #newFromText in that case.
+ *
+ * @static
+ * @param {number} namespace Namespace to use for the title
+ * @param {string} title
+ * @return {mw.Title|null} A valid Title object or null if the title is invalid
+ */
+Title.makeTitle = function ( namespace, title ) {
+       return mw.Title.newFromText( getNamespacePrefix( namespace ) + title );
+};
+
+/**
+ * Constructor for Title objects from user input altering that input to
+ * produce a title that MediaWiki will accept as legal
+ *
+ * @static
+ * @param {string} title
+ * @param {number|Object} [defaultNamespaceOrOptions=NS_MAIN]
+ *  If given, will used as default namespace for the given title.
+ *  This method can also be called with two arguments, in which case
+ *  this becomes options (see below).
+ * @param {Object} [options] additional options
+ * @param {boolean} [options.forUploading=true]
+ *  Makes sure that a file is uploadable under the title returned.
+ *  There are pages in the file namespace under which file upload is impossible.
+ *  Automatically assumed if the title is created in the Media namespace.
+ * @return {mw.Title|null} A valid Title object or null if the input cannot be turned into a valid title
+ */
+Title.newFromUserInput = function ( title, defaultNamespaceOrOptions, options ) {
+       var namespace, m, id, ext, parts,
+               defaultNamespace;
+
+       // defaultNamespace is optional; check whether options moves up
+       if ( arguments.length < 3 && typeof defaultNamespace === 'object' ) {
+               options = defaultNamespaceOrOptions;
+       } else {
+               defaultNamespace = defaultNamespaceOrOptions;
+       }
+
+       // merge options into defaults
+       options = $.extend( {
+               forUploading: true
+       }, options );
+
+       namespace = defaultNamespace === undefined ? NS_MAIN : defaultNamespace;
+
+       // Normalise additional whitespace
+       title = title.replace( /\s/g, ' ' ).trim();
+
+       // Process initial colon
+       if ( title !== '' && title[ 0 ] === ':' ) {
+               // Initial colon means main namespace instead of specified default
+               namespace = NS_MAIN;
+               title = title
+                       // Strip colon
+                       .substr( 1 )
+                       // Trim underscores
+                       .replace( rUnderscoreTrim, '' );
+       }
+
+       // Process namespace prefix (if any)
+       m = title.match( rSplit );
+       if ( m ) {
+               id = getNsIdByName( m[ 1 ] );
+               if ( id !== false ) {
+                       // Ordinary namespace
+                       namespace = id;
+                       title = m[ 2 ];
+               }
+       }
+
+       if (
+               namespace === NS_MEDIA ||
+               ( options.forUploading && ( namespace === NS_FILE ) )
+       ) {
 
-                       // thumb.php-generated thumbnails
-                       thumbPhpRegex = /thumb\.php/,
-                       regexes = [
-                               // Thumbnails
-                               /\/[a-f0-9]\/[a-f0-9]{2}\/([^\s/]+)\/[^\s/]+-[^\s/]*$/,
+               title = sanitize( title, [ 'generalRule', 'fileRule' ] );
 
-                               // Full size images
-                               /\/[a-f0-9]\/[a-f0-9]{2}\/([^\s/]+)$/,
+               // Operate on the file extension
+               // Although it is possible having spaces between the name and the ".ext" this isn't nice for
+               // operating systems hiding file extensions -> strip them later on
+               parts = title.split( '.' );
 
-                               // Thumbnails in non-hashed upload directories
-                               /\/([^\s/]+)\/[^\s/]+-(?:\1|thumbnail)[^\s/]*$/,
+               if ( parts.length > 1 ) {
 
-                               // Full-size images in non-hashed upload directories
-                               /\/([^\s/]+)$/
-                       ],
+                       // Get the last part, which is supposed to be the file extension
+                       ext = parts.pop();
 
-                       recount = regexes.length;
+                       // Remove whitespace of the name part (that W/O extension)
+                       title = parts.join( '.' ).trim();
 
-               src = img.jquery ? img[ 0 ].src : img.src;
+                       // Cut, if too long and append file extension
+                       title = trimFileNameToByteLength( title, ext );
 
-               matches = src.match( thumbPhpRegex );
+               } else {
 
-               if ( matches ) {
-                       return mw.Title.newFromText( 'File:' + mw.util.getParamValue( 'f', src ) );
+                       // Missing file extension
+                       title = parts.join( '.' ).trim();
+
+                       // Name has no file extension and a fallback wasn't provided either
+                       return null;
                }
+       } else {
 
-               decodedSrc = decodeURIComponent( src );
+               title = sanitize( title, [ 'generalRule' ] );
 
-               for ( i = 0; i < recount; i++ ) {
-                       regex = regexes[ i ];
-                       matches = decodedSrc.match( regex );
+               // Cut titles exceeding the TITLE_MAX_BYTES byte size limit
+               // (size of underlying database field)
+               if ( namespace !== NS_SPECIAL ) {
+                       title = trimToByteLength( title, TITLE_MAX_BYTES );
+               }
+       }
 
-                       if ( matches && matches[ 1 ] ) {
-                               return mw.Title.newFromText( 'File:' + matches[ 1 ] );
-                       }
+       // Any remaining initial :s are illegal.
+       title = title.replace( /^:+/, '' );
+
+       return Title.newFromText( title, namespace );
+};
+
+/**
+ * Sanitizes a file name as supplied by the user, originating in the user's file system
+ * so it is most likely a valid MediaWiki title and file name after processing.
+ * Returns null on fatal errors.
+ *
+ * @static
+ * @param {string} uncleanName The unclean file name including file extension but
+ *   without namespace
+ * @return {mw.Title|null} A valid Title object or null if the title is invalid
+ */
+Title.newFromFileName = function ( uncleanName ) {
+
+       return Title.newFromUserInput( 'File:' + uncleanName, {
+               forUploading: true
+       } );
+};
+
+/**
+ * Get the file title from an image element
+ *
+ *     var title = mw.Title.newFromImg( $( 'img:first' ) );
+ *
+ * @static
+ * @param {HTMLElement|jQuery} img The image to use as a base
+ * @return {mw.Title|null} The file title or null if unsuccessful
+ */
+Title.newFromImg = function ( img ) {
+       var matches, i, regex, src, decodedSrc,
+
+               // thumb.php-generated thumbnails
+               thumbPhpRegex = /thumb\.php/,
+               regexes = [
+                       // Thumbnails
+                       /\/[a-f0-9]\/[a-f0-9]{2}\/([^\s/]+)\/[^\s/]+-[^\s/]*$/,
+
+                       // Full size images
+                       /\/[a-f0-9]\/[a-f0-9]{2}\/([^\s/]+)$/,
+
+                       // Thumbnails in non-hashed upload directories
+                       /\/([^\s/]+)\/[^\s/]+-(?:\1|thumbnail)[^\s/]*$/,
+
+                       // Full-size images in non-hashed upload directories
+                       /\/([^\s/]+)$/
+               ],
+
+               recount = regexes.length;
+
+       src = img.jquery ? img[ 0 ].src : img.src;
+
+       matches = src.match( thumbPhpRegex );
+
+       if ( matches ) {
+               return mw.Title.newFromText( 'File:' + mw.util.getParamValue( 'f', src ) );
+       }
+
+       decodedSrc = decodeURIComponent( src );
+
+       for ( i = 0; i < recount; i++ ) {
+               regex = regexes[ i ];
+               matches = decodedSrc.match( regex );
+
+               if ( matches && matches[ 1 ] ) {
+                       return mw.Title.newFromText( 'File:' + matches[ 1 ] );
                }
+       }
+
+       return null;
+};
+
+/**
+ * Check if a given namespace is a talk namespace
+ *
+ * See MWNamespace::isTalk in PHP
+ *
+ * @param {number} namespaceId Namespace ID
+ * @return {boolean} Namespace is a talk namespace
+ */
+Title.isTalkNamespace = function ( namespaceId ) {
+       return !!( namespaceId > NS_MAIN && namespaceId % 2 );
+};
+
+/**
+ * Check if signature buttons should be shown in a given namespace
+ *
+ * See MWNamespace::wantSignatures in PHP
+ *
+ * @param {number} namespaceId Namespace ID
+ * @return {boolean} Namespace is a signature namespace
+ */
+Title.wantSignaturesNamespace = function ( namespaceId ) {
+       return Title.isTalkNamespace( namespaceId ) ||
+               mw.config.get( 'wgExtraSignatureNamespaces' ).indexOf( namespaceId ) !== -1;
+};
+
+/**
+ * Whether this title exists on the wiki.
+ *
+ * @static
+ * @param {string|mw.Title} title prefixed db-key name (string) or instance of Title
+ * @return {boolean|null} Boolean if the information is available, otherwise null
+ * @throws {Error} If title is not a string or mw.Title
+ */
+Title.exists = function ( title ) {
+       var match,
+               obj = Title.exist.pages;
+
+       if ( typeof title === 'string' ) {
+               match = obj[ title ];
+       } else if ( title instanceof Title ) {
+               match = obj[ title.toString() ];
+       } else {
+               throw new Error( 'mw.Title.exists: title must be a string or an instance of Title' );
+       }
 
+       if ( typeof match !== 'boolean' ) {
                return null;
-       };
+       }
+
+       return match;
+};
+
+/**
+ * Store page existence
+ *
+ * @static
+ * @property {Object} exist
+ * @property {Object} exist.pages Keyed by title. Boolean true value indicates page does exist.
+ *
+ * @property {Function} exist.set The setter function.
+ *
+ *  Example to declare existing titles:
+ *
+ *     Title.exist.set( ['User:John_Doe', ...] );
+ *
+ *  Example to declare titles nonexistent:
+ *
+ *     Title.exist.set( ['File:Foo_bar.jpg', ...], false );
+ *
+ * @property {string|Array} exist.set.titles Title(s) in strict prefixedDb title form
+ * @property {boolean} [exist.set.state=true] State of the given titles
+ * @return {boolean}
+ */
+Title.exist = {
+       pages: {},
+
+       set: function ( titles, state ) {
+               var i, len,
+                       pages = this.pages;
+
+               titles = Array.isArray( titles ) ? titles : [ titles ];
+               state = state === undefined ? true : !!state;
+
+               for ( i = 0, len = titles.length; i < len; i++ ) {
+                       pages[ titles[ i ] ] = state;
+               }
+               return true;
+       }
+};
+
+/**
+ * Normalize a file extension to the common form, making it lowercase and checking some synonyms,
+ * and ensure it's clean. Extensions with non-alphanumeric characters will be discarded.
+ * Keep in sync with File::normalizeExtension() in PHP.
+ *
+ * @param {string} extension File extension (without the leading dot)
+ * @return {string} File extension in canonical form
+ */
+Title.normalizeExtension = function ( extension ) {
+       var
+               lower = extension.toLowerCase(),
+               squish = {
+                       htm: 'html',
+                       jpeg: 'jpg',
+                       mpeg: 'mpg',
+                       tiff: 'tif',
+                       ogv: 'ogg'
+               };
+       if ( Object.prototype.hasOwnProperty.call( squish, lower ) ) {
+               return squish[ lower ];
+       } else if ( /^[0-9a-z]+$/.test( lower ) ) {
+               return lower;
+       } else {
+               return '';
+       }
+};
+
+/**
+ * PHP's strtoupper differs from String.toUpperCase in a number of cases (T147646).
+ *
+ * @param {string} chr Unicode character
+ * @return {string} Unicode character, in upper case, according to the same rules as in PHP
+ */
+Title.phpCharToUpper = function ( chr ) {
+       var mapped = toUpperMapping[ chr ];
+       return mapped || chr.toUpperCase();
+};
+
+/* Public members */
+
+Title.prototype = {
+       constructor: Title,
 
        /**
-        * Check if a given namespace is a talk namespace
+        * Get the namespace number
         *
-        * See MWNamespace::isTalk in PHP
+        * Example: 6 for "File:Example_image.svg".
         *
-        * @param {number} namespaceId Namespace ID
-        * @return {boolean} Namespace is a talk namespace
+        * @return {number}
         */
-       Title.isTalkNamespace = function ( namespaceId ) {
-               return !!( namespaceId > NS_MAIN && namespaceId % 2 );
-       };
+       getNamespaceId: function () {
+               return this.namespace;
+       },
 
        /**
-        * Check if signature buttons should be shown in a given namespace
+        * Get the namespace prefix (in the content language)
         *
-        * See MWNamespace::wantSignatures in PHP
+        * Example: "File:" for "File:Example_image.svg".
+        * In #NS_MAIN this is '', otherwise namespace name plus ':'
         *
-        * @param {number} namespaceId Namespace ID
-        * @return {boolean} Namespace is a signature namespace
+        * @return {string}
         */
-       Title.wantSignaturesNamespace = function ( namespaceId ) {
-               return Title.isTalkNamespace( namespaceId ) ||
-                       mw.config.get( 'wgExtraSignatureNamespaces' ).indexOf( namespaceId ) !== -1;
-       };
+       getNamespacePrefix: function () {
+               return getNamespacePrefix( this.namespace );
+       },
 
        /**
-        * Whether this title exists on the wiki.
+        * Get the page name without extension or namespace prefix
         *
-        * @static
-        * @param {string|mw.Title} title prefixed db-key name (string) or instance of Title
-        * @return {boolean|null} Boolean if the information is available, otherwise null
-        * @throws {Error} If title is not a string or mw.Title
+        * Example: "Example_image" for "File:Example_image.svg".
+        *
+        * For the page title (full page name without namespace prefix), see #getMain.
+        *
+        * @return {string}
         */
-       Title.exists = function ( title ) {
-               var match,
-                       obj = Title.exist.pages;
-
-               if ( typeof title === 'string' ) {
-                       match = obj[ title ];
-               } else if ( title instanceof Title ) {
-                       match = obj[ title.toString() ];
-               } else {
-                       throw new Error( 'mw.Title.exists: title must be a string or an instance of Title' );
-               }
-
-               if ( typeof match !== 'boolean' ) {
-                       return null;
+       getName: function () {
+               if (
+                       mw.config.get( 'wgCaseSensitiveNamespaces' ).indexOf( this.namespace ) !== -1 ||
+                       !this.title.length
+               ) {
+                       return this.title;
                }
-
-               return match;
-       };
+               return mw.Title.phpCharToUpper( this.title[ 0 ] ) + this.title.slice( 1 );
+       },
 
        /**
-        * Store page existence
+        * Get the page name (transformed by #text)
         *
-        * @static
-        * @property {Object} exist
-        * @property {Object} exist.pages Keyed by title. Boolean true value indicates page does exist.
+        * Example: "Example image" for "File:Example_image.svg".
         *
-        * @property {Function} exist.set The setter function.
+        * For the page title (full page name without namespace prefix), see #getMainText.
         *
-        *  Example to declare existing titles:
+        * @return {string}
+        */
+       getNameText: function () {
+               return text( this.getName() );
+       },
+
+       /**
+        * Get the extension of the page name (if any)
         *
-        *     Title.exist.set( ['User:John_Doe', ...] );
+        * @return {string|null} Name extension or null if there is none
+        */
+       getExtension: function () {
+               return this.ext;
+       },
+
+       /**
+        * Shortcut for appendable string to form the main page name.
         *
-        *  Example to declare titles nonexistent:
+        * Returns a string like ".json", or "" if no extension.
         *
-        *     Title.exist.set( ['File:Foo_bar.jpg', ...], false );
+        * @return {string}
+        */
+       getDotExtension: function () {
+               return this.ext === null ? '' : '.' + this.ext;
+       },
+
+       /**
+        * Get the main page name
+        *
+        * Example: "Example_image.svg" for "File:Example_image.svg".
         *
-        * @property {string|Array} exist.set.titles Title(s) in strict prefixedDb title form
-        * @property {boolean} [exist.set.state=true] State of the given titles
-        * @return {boolean}
+        * @return {string}
         */
-       Title.exist = {
-               pages: {},
+       getMain: function () {
+               return this.getName() + this.getDotExtension();
+       },
 
-               set: function ( titles, state ) {
-                       var i, len,
-                               pages = this.pages;
+       /**
+        * Get the main page name (transformed by #text)
+        *
+        * Example: "Example image.svg" for "File:Example_image.svg".
+        *
+        * @return {string}
+        */
+       getMainText: function () {
+               return text( this.getMain() );
+       },
 
-                       titles = Array.isArray( titles ) ? titles : [ titles ];
-                       state = state === undefined ? true : !!state;
+       /**
+        * Get the full page name
+        *
+        * Example: "File:Example_image.svg".
+        * Most useful for API calls, anything that must identify the "title".
+        *
+        * @return {string}
+        */
+       getPrefixedDb: function () {
+               return this.getNamespacePrefix() + this.getMain();
+       },
 
-                       for ( i = 0, len = titles.length; i < len; i++ ) {
-                               pages[ titles[ i ] ] = state;
-                       }
-                       return true;
-               }
-       };
+       /**
+        * Get the full page name (transformed by #text)
+        *
+        * Example: "File:Example image.svg" for "File:Example_image.svg".
+        *
+        * @return {string}
+        */
+       getPrefixedText: function () {
+               return text( this.getPrefixedDb() );
+       },
 
        /**
-        * Normalize a file extension to the common form, making it lowercase and checking some synonyms,
-        * and ensure it's clean. Extensions with non-alphanumeric characters will be discarded.
-        * Keep in sync with File::normalizeExtension() in PHP.
+        * Get the page name relative to a namespace
+        *
+        * Example:
         *
-        * @param {string} extension File extension (without the leading dot)
-        * @return {string} File extension in canonical form
+        * - "Foo:Bar" relative to the Foo namespace becomes "Bar".
+        * - "Bar" relative to any non-main namespace becomes ":Bar".
+        * - "Foo:Bar" relative to any namespace other than Foo stays "Foo:Bar".
+        *
+        * @param {number} namespace The namespace to be relative to
+        * @return {string}
         */
-       Title.normalizeExtension = function ( extension ) {
-               var
-                       lower = extension.toLowerCase(),
-                       squish = {
-                               htm: 'html',
-                               jpeg: 'jpg',
-                               mpeg: 'mpg',
-                               tiff: 'tif',
-                               ogv: 'ogg'
-                       };
-               if ( Object.prototype.hasOwnProperty.call( squish, lower ) ) {
-                       return squish[ lower ];
-               } else if ( /^[0-9a-z]+$/.test( lower ) ) {
-                       return lower;
+       getRelativeText: function ( namespace ) {
+               if ( this.getNamespaceId() === namespace ) {
+                       return this.getMainText();
+               } else if ( this.getNamespaceId() === NS_MAIN ) {
+                       return ':' + this.getPrefixedText();
                } else {
-                       return '';
+                       return this.getPrefixedText();
                }
-       };
-
-       /* Public members */
-
-       Title.prototype = {
-               constructor: Title,
-
-               /**
-                * Get the namespace number
-                *
-                * Example: 6 for "File:Example_image.svg".
-                *
-                * @return {number}
-                */
-               getNamespaceId: function () {
-                       return this.namespace;
-               },
-
-               /**
-                * Get the namespace prefix (in the content language)
-                *
-                * Example: "File:" for "File:Example_image.svg".
-                * In #NS_MAIN this is '', otherwise namespace name plus ':'
-                *
-                * @return {string}
-                */
-               getNamespacePrefix: function () {
-                       return getNamespacePrefix( this.namespace );
-               },
-
-               /**
-                * Get the page name without extension or namespace prefix
-                *
-                * Example: "Example_image" for "File:Example_image.svg".
-                *
-                * For the page title (full page name without namespace prefix), see #getMain.
-                *
-                * @return {string}
-                */
-               getName: function () {
-                       if (
-                               mw.config.get( 'wgCaseSensitiveNamespaces' ).indexOf( this.namespace ) !== -1 ||
-                               !this.title.length
-                       ) {
-                               return this.title;
-                       }
-                       // PHP's strtoupper differs from String.toUpperCase in a number of cases
-                       // Bug: T147646
-                       return mw.Title.phpCharToUpper( this.title[ 0 ] ) + this.title.slice( 1 );
-               },
-
-               /**
-                * Get the page name (transformed by #text)
-                *
-                * Example: "Example image" for "File:Example_image.svg".
-                *
-                * For the page title (full page name without namespace prefix), see #getMainText.
-                *
-                * @return {string}
-                */
-               getNameText: function () {
-                       return text( this.getName() );
-               },
-
-               /**
-                * Get the extension of the page name (if any)
-                *
-                * @return {string|null} Name extension or null if there is none
-                */
-               getExtension: function () {
-                       return this.ext;
-               },
-
-               /**
-                * Shortcut for appendable string to form the main page name.
-                *
-                * Returns a string like ".json", or "" if no extension.
-                *
-                * @return {string}
-                */
-               getDotExtension: function () {
-                       return this.ext === null ? '' : '.' + this.ext;
-               },
-
-               /**
-                * Get the main page name
-                *
-                * Example: "Example_image.svg" for "File:Example_image.svg".
-                *
-                * @return {string}
-                */
-               getMain: function () {
-                       return this.getName() + this.getDotExtension();
-               },
-
-               /**
-                * Get the main page name (transformed by #text)
-                *
-                * Example: "Example image.svg" for "File:Example_image.svg".
-                *
-                * @return {string}
-                */
-               getMainText: function () {
-                       return text( this.getMain() );
-               },
-
-               /**
-                * Get the full page name
-                *
-                * Example: "File:Example_image.svg".
-                * Most useful for API calls, anything that must identify the "title".
-                *
-                * @return {string}
-                */
-               getPrefixedDb: function () {
-                       return this.getNamespacePrefix() + this.getMain();
-               },
-
-               /**
-                * Get the full page name (transformed by #text)
-                *
-                * Example: "File:Example image.svg" for "File:Example_image.svg".
-                *
-                * @return {string}
-                */
-               getPrefixedText: function () {
-                       return text( this.getPrefixedDb() );
-               },
-
-               /**
-                * Get the page name relative to a namespace
-                *
-                * Example:
-                *
-                * - "Foo:Bar" relative to the Foo namespace becomes "Bar".
-                * - "Bar" relative to any non-main namespace becomes ":Bar".
-                * - "Foo:Bar" relative to any namespace other than Foo stays "Foo:Bar".
-                *
-                * @param {number} namespace The namespace to be relative to
-                * @return {string}
-                */
-               getRelativeText: function ( namespace ) {
-                       if ( this.getNamespaceId() === namespace ) {
-                               return this.getMainText();
-                       } else if ( this.getNamespaceId() === NS_MAIN ) {
-                               return ':' + this.getPrefixedText();
-                       } else {
-                               return this.getPrefixedText();
-                       }
-               },
-
-               /**
-                * Get the fragment (if any).
-                *
-                * Note that this method (by design) does not include the hash character and
-                * the value is not url encoded.
-                *
-                * @return {string|null}
-                */
-               getFragment: function () {
-                       return this.fragment;
-               },
-
-               /**
-                * Get the URL to this title
-                *
-                * @see mw.util#getUrl
-                * @param {Object} [params] A mapping of query parameter names to values,
-                *     e.g. `{ action: 'edit' }`.
-                * @return {string}
-                */
-               getUrl: function ( params ) {
-                       var fragment = this.getFragment();
-                       if ( fragment ) {
-                               return mw.util.getUrl( this.toString() + '#' + fragment, params );
-                       } else {
-                               return mw.util.getUrl( this.toString(), params );
-                       }
-               },
-
-               /**
-                * Check if the title is in a talk namespace
-                *
-                * @return {boolean} The title is in a talk namespace
-                */
-               isTalkPage: function () {
-                       return Title.isTalkNamespace( this.getNamespaceId() );
-               },
+       },
 
-               /**
-                * Get the title for the associated talk page
-                *
-                * @return {mw.Title|null} The title for the associated talk page, null if not available
-                */
-               getTalkPage: function () {
-                       if ( !this.canHaveTalkPage() ) {
-                               return null;
-                       }
-                       return this.isTalkPage() ?
-                               this :
-                               Title.makeTitle( this.getNamespaceId() + 1, this.getMainText() );
-               },
+       /**
+        * Get the fragment (if any).
+        *
+        * Note that this method (by design) does not include the hash character and
+        * the value is not url encoded.
+        *
+        * @return {string|null}
+        */
+       getFragment: function () {
+               return this.fragment;
+       },
 
-               /**
-                * Get the title for the subject page of a talk page
-                *
-                * @return {mw.Title|null} The title for the subject page of a talk page, null if not available
-                */
-               getSubjectPage: function () {
-                       return this.isTalkPage() ?
-                               Title.makeTitle( this.getNamespaceId() - 1, this.getMainText() ) :
-                               this;
-               },
+       /**
+        * Get the URL to this title
+        *
+        * @see mw.util#getUrl
+        * @param {Object} [params] A mapping of query parameter names to values,
+        *     e.g. `{ action: 'edit' }`.
+        * @return {string}
+        */
+       getUrl: function ( params ) {
+               var fragment = this.getFragment();
+               if ( fragment ) {
+                       return mw.util.getUrl( this.toString() + '#' + fragment, params );
+               } else {
+                       return mw.util.getUrl( this.toString(), params );
+               }
+       },
 
-               /**
-                * Check the the title can have an associated talk page
-                *
-                * @return {boolean} The title can have an associated talk page
-                */
-               canHaveTalkPage: function () {
-                       return this.getNamespaceId() >= NS_MAIN;
-               },
+       /**
+        * Check if the title is in a talk namespace
+        *
+        * @return {boolean} The title is in a talk namespace
+        */
+       isTalkPage: function () {
+               return Title.isTalkNamespace( this.getNamespaceId() );
+       },
 
-               /**
-                * Whether this title exists on the wiki.
-                *
-                * @see #static-method-exists
-                * @return {boolean|null} Boolean if the information is available, otherwise null
-                */
-               exists: function () {
-                       return Title.exists( this );
+       /**
+        * Get the title for the associated talk page
+        *
+        * @return {mw.Title|null} The title for the associated talk page, null if not available
+        */
+       getTalkPage: function () {
+               if ( !this.canHaveTalkPage() ) {
+                       return null;
                }
-       };
+               return this.isTalkPage() ?
+                       this :
+                       Title.makeTitle( this.getNamespaceId() + 1, this.getMainText() );
+       },
 
        /**
-        * @alias #getPrefixedDb
-        * @method
+        * Get the title for the subject page of a talk page
+        *
+        * @return {mw.Title|null} The title for the subject page of a talk page, null if not available
         */
-       Title.prototype.toString = Title.prototype.getPrefixedDb;
+       getSubjectPage: function () {
+               return this.isTalkPage() ?
+                       Title.makeTitle( this.getNamespaceId() - 1, this.getMainText() ) :
+                       this;
+       },
 
        /**
-        * @alias #getPrefixedText
-        * @method
+        * Check the the title can have an associated talk page
+        *
+        * @return {boolean} The title can have an associated talk page
         */
-       Title.prototype.toText = Title.prototype.getPrefixedText;
+       canHaveTalkPage: function () {
+               return this.getNamespaceId() >= NS_MAIN;
+       },
 
-       // Expose
-       mw.Title = Title;
+       /**
+        * Whether this title exists on the wiki.
+        *
+        * @see #static-method-exists
+        * @return {boolean|null} Boolean if the information is available, otherwise null
+        */
+       exists: function () {
+               return Title.exists( this );
+       }
+};
+
+/**
+ * @alias #getPrefixedDb
+ * @method
+ */
+Title.prototype.toString = Title.prototype.getPrefixedDb;
+
+/**
+ * @alias #getPrefixedText
+ * @method
+ */
+Title.prototype.toText = Title.prototype.getPrefixedText;
 
-}() );
+// Expose
+mw.Title = Title;
diff --git a/resources/src/mediawiki.Title/phpCharToUpper.js b/resources/src/mediawiki.Title/phpCharToUpper.js
deleted file mode 100644 (file)
index ed700f0..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-// This file can't be parsed by JSDuck due to <https://github.com/tenderlove/rkelly/issues/35>.
-// (It is excluded in jsduck.json.)
-// ESLint suggests unquoting some object keys, which would render the file unparseable by Opera 12.
-/* eslint-disable quote-props */
-( function () {
-       var toUpperMapping = {
-               'ß': 'ß',
-               'ʼn': 'ʼn',
-               'Dž': 'Dž',
-               'dž': 'Dž',
-               'Lj': 'Lj',
-               'lj': 'Lj',
-               'Nj': 'Nj',
-               'nj': 'Nj',
-               'ǰ': 'ǰ',
-               'Dz': 'Dz',
-               'dz': 'Dz',
-               'ʝ': 'Ʝ',
-               'ͅ': 'ͅ',
-               'ΐ': 'ΐ',
-               'ΰ': 'ΰ',
-               'և': 'և',
-               'ᏸ': 'Ᏸ',
-               'ᏹ': 'Ᏹ',
-               'ᏺ': 'Ᏺ',
-               'ᏻ': 'Ᏻ',
-               'ᏼ': 'Ᏼ',
-               'ᏽ': 'Ᏽ',
-               'ẖ': 'ẖ',
-               'ẗ': 'ẗ',
-               'ẘ': 'ẘ',
-               'ẙ': 'ẙ',
-               'ẚ': 'ẚ',
-               'ὐ': 'ὐ',
-               'ὒ': 'ὒ',
-               'ὔ': 'ὔ',
-               'ὖ': 'ὖ',
-               'ᾀ': 'ᾈ',
-               'ᾁ': 'ᾉ',
-               'ᾂ': 'ᾊ',
-               'ᾃ': 'ᾋ',
-               'ᾄ': 'ᾌ',
-               'ᾅ': 'ᾍ',
-               'ᾆ': 'ᾎ',
-               'ᾇ': 'ᾏ',
-               'ᾈ': 'ᾈ',
-               'ᾉ': 'ᾉ',
-               'ᾊ': 'ᾊ',
-               'ᾋ': 'ᾋ',
-               'ᾌ': 'ᾌ',
-               'ᾍ': 'ᾍ',
-               'ᾎ': 'ᾎ',
-               'ᾏ': 'ᾏ',
-               'ᾐ': 'ᾘ',
-               'ᾑ': 'ᾙ',
-               'ᾒ': 'ᾚ',
-               'ᾓ': 'ᾛ',
-               'ᾔ': 'ᾜ',
-               'ᾕ': 'ᾝ',
-               'ᾖ': 'ᾞ',
-               'ᾗ': 'ᾟ',
-               'ᾘ': 'ᾘ',
-               'ᾙ': 'ᾙ',
-               'ᾚ': 'ᾚ',
-               'ᾛ': 'ᾛ',
-               'ᾜ': 'ᾜ',
-               'ᾝ': 'ᾝ',
-               'ᾞ': 'ᾞ',
-               'ᾟ': 'ᾟ',
-               'ᾠ': 'ᾨ',
-               'ᾡ': 'ᾩ',
-               'ᾢ': 'ᾪ',
-               'ᾣ': 'ᾫ',
-               'ᾤ': 'ᾬ',
-               'ᾥ': 'ᾭ',
-               'ᾦ': 'ᾮ',
-               'ᾧ': 'ᾯ',
-               'ᾨ': 'ᾨ',
-               'ᾩ': 'ᾩ',
-               'ᾪ': 'ᾪ',
-               'ᾫ': 'ᾫ',
-               'ᾬ': 'ᾬ',
-               'ᾭ': 'ᾭ',
-               'ᾮ': 'ᾮ',
-               'ᾯ': 'ᾯ',
-               'ᾲ': 'ᾲ',
-               'ᾳ': 'ᾼ',
-               'ᾴ': 'ᾴ',
-               'ᾶ': 'ᾶ',
-               'ᾷ': 'ᾷ',
-               'ᾼ': 'ᾼ',
-               'ῂ': 'ῂ',
-               'ῃ': 'ῌ',
-               'ῄ': 'ῄ',
-               'ῆ': 'ῆ',
-               'ῇ': 'ῇ',
-               'ῌ': 'ῌ',
-               'ῒ': 'ῒ',
-               'ΐ': 'ΐ',
-               'ῖ': 'ῖ',
-               'ῗ': 'ῗ',
-               'ῢ': 'ῢ',
-               'ΰ': 'ΰ',
-               'ῤ': 'ῤ',
-               'ῦ': 'ῦ',
-               'ῧ': 'ῧ',
-               'ῲ': 'ῲ',
-               'ῳ': 'ῼ',
-               'ῴ': 'ῴ',
-               'ῶ': 'ῶ',
-               'ῷ': 'ῷ',
-               'ῼ': 'ῼ',
-               'ⅰ': 'ⅰ',
-               'ⅱ': 'ⅱ',
-               'ⅲ': 'ⅲ',
-               'ⅳ': 'ⅳ',
-               'ⅴ': 'ⅴ',
-               'ⅵ': 'ⅵ',
-               'ⅶ': 'ⅶ',
-               'ⅷ': 'ⅷ',
-               'ⅸ': 'ⅸ',
-               'ⅹ': 'ⅹ',
-               'ⅺ': 'ⅺ',
-               'ⅻ': 'ⅻ',
-               'ⅼ': 'ⅼ',
-               'ⅽ': 'ⅽ',
-               'ⅾ': 'ⅾ',
-               'ⅿ': 'ⅿ',
-               'ⓐ': 'ⓐ',
-               'ⓑ': 'ⓑ',
-               'ⓒ': 'ⓒ',
-               'ⓓ': 'ⓓ',
-               'ⓔ': 'ⓔ',
-               'ⓕ': 'ⓕ',
-               'ⓖ': 'ⓖ',
-               'ⓗ': 'ⓗ',
-               'ⓘ': 'ⓘ',
-               'ⓙ': 'ⓙ',
-               'ⓚ': 'ⓚ',
-               'ⓛ': 'ⓛ',
-               'ⓜ': 'ⓜ',
-               'ⓝ': 'ⓝ',
-               'ⓞ': 'ⓞ',
-               'ⓟ': 'ⓟ',
-               'ⓠ': 'ⓠ',
-               'ⓡ': 'ⓡ',
-               'ⓢ': 'ⓢ',
-               'ⓣ': 'ⓣ',
-               'ⓤ': 'ⓤ',
-               'ⓥ': 'ⓥ',
-               'ⓦ': 'ⓦ',
-               'ⓧ': 'ⓧ',
-               'ⓨ': 'ⓨ',
-               'ⓩ': 'ⓩ',
-               'ꞵ': 'Ꞵ',
-               'ꞷ': 'Ꞷ',
-               'ꭓ': 'Ꭓ',
-               'ꭰ': 'Ꭰ',
-               'ꭱ': 'Ꭱ',
-               'ꭲ': 'Ꭲ',
-               'ꭳ': 'Ꭳ',
-               'ꭴ': 'Ꭴ',
-               'ꭵ': 'Ꭵ',
-               'ꭶ': 'Ꭶ',
-               'ꭷ': 'Ꭷ',
-               'ꭸ': 'Ꭸ',
-               'ꭹ': 'Ꭹ',
-               'ꭺ': 'Ꭺ',
-               'ꭻ': 'Ꭻ',
-               'ꭼ': 'Ꭼ',
-               'ꭽ': 'Ꭽ',
-               'ꭾ': 'Ꭾ',
-               'ꭿ': 'Ꭿ',
-               'ꮀ': 'Ꮀ',
-               'ꮁ': 'Ꮁ',
-               'ꮂ': 'Ꮂ',
-               'ꮃ': 'Ꮃ',
-               'ꮄ': 'Ꮄ',
-               'ꮅ': 'Ꮅ',
-               'ꮆ': 'Ꮆ',
-               'ꮇ': 'Ꮇ',
-               'ꮈ': 'Ꮈ',
-               'ꮉ': 'Ꮉ',
-               'ꮊ': 'Ꮊ',
-               'ꮋ': 'Ꮋ',
-               'ꮌ': 'Ꮌ',
-               'ꮍ': 'Ꮍ',
-               'ꮎ': 'Ꮎ',
-               'ꮏ': 'Ꮏ',
-               'ꮐ': 'Ꮐ',
-               'ꮑ': 'Ꮑ',
-               'ꮒ': 'Ꮒ',
-               'ꮓ': 'Ꮓ',
-               'ꮔ': 'Ꮔ',
-               'ꮕ': 'Ꮕ',
-               'ꮖ': 'Ꮖ',
-               'ꮗ': 'Ꮗ',
-               'ꮘ': 'Ꮘ',
-               'ꮙ': 'Ꮙ',
-               'ꮚ': 'Ꮚ',
-               'ꮛ': 'Ꮛ',
-               'ꮜ': 'Ꮜ',
-               'ꮝ': 'Ꮝ',
-               'ꮞ': 'Ꮞ',
-               'ꮟ': 'Ꮟ',
-               'ꮠ': 'Ꮠ',
-               'ꮡ': 'Ꮡ',
-               'ꮢ': 'Ꮢ',
-               'ꮣ': 'Ꮣ',
-               'ꮤ': 'Ꮤ',
-               'ꮥ': 'Ꮥ',
-               'ꮦ': 'Ꮦ',
-               'ꮧ': 'Ꮧ',
-               'ꮨ': 'Ꮨ',
-               'ꮩ': 'Ꮩ',
-               'ꮪ': 'Ꮪ',
-               'ꮫ': 'Ꮫ',
-               'ꮬ': 'Ꮬ',
-               'ꮭ': 'Ꮭ',
-               'ꮮ': 'Ꮮ',
-               'ꮯ': 'Ꮯ',
-               'ꮰ': 'Ꮰ',
-               'ꮱ': 'Ꮱ',
-               'ꮲ': 'Ꮲ',
-               'ꮳ': 'Ꮳ',
-               'ꮴ': 'Ꮴ',
-               'ꮵ': 'Ꮵ',
-               'ꮶ': 'Ꮶ',
-               'ꮷ': 'Ꮷ',
-               'ꮸ': 'Ꮸ',
-               'ꮹ': 'Ꮹ',
-               'ꮺ': 'Ꮺ',
-               'ꮻ': 'Ꮻ',
-               'ꮼ': 'Ꮼ',
-               'ꮽ': 'Ꮽ',
-               'ꮾ': 'Ꮾ',
-               'ꮿ': 'Ꮿ',
-               'ff': 'ff',
-               'fi': 'fi',
-               'fl': 'fl',
-               'ffi': 'ffi',
-               'ffl': 'ffl',
-               'ſt': 'ſt',
-               'st': 'st',
-               'ﬓ': 'ﬓ',
-               'ﬔ': 'ﬔ',
-               'ﬕ': 'ﬕ',
-               'ﬖ': 'ﬖ',
-               'ﬗ': 'ﬗ'
-       };
-       mw.Title.phpCharToUpper = function ( chr ) {
-               var mapped = toUpperMapping[ chr ];
-               return mapped || chr.toUpperCase();
-       };
-}() );
diff --git a/resources/src/mediawiki.Title/phpCharToUpper.json b/resources/src/mediawiki.Title/phpCharToUpper.json
new file mode 100644 (file)
index 0000000..b0887fa
--- /dev/null
@@ -0,0 +1,245 @@
+{
+       "ß": "ß",
+       "ʼn": "ʼn",
+       "Dž": "Dž",
+       "dž": "Dž",
+       "Lj": "Lj",
+       "lj": "Lj",
+       "Nj": "Nj",
+       "nj": "Nj",
+       "ǰ": "ǰ",
+       "Dz": "Dz",
+       "dz": "Dz",
+       "ʝ": "Ʝ",
+       "ͅ": "ͅ",
+       "ΐ": "ΐ",
+       "ΰ": "ΰ",
+       "և": "և",
+       "ᏸ": "Ᏸ",
+       "ᏹ": "Ᏹ",
+       "ᏺ": "Ᏺ",
+       "ᏻ": "Ᏻ",
+       "ᏼ": "Ᏼ",
+       "ᏽ": "Ᏽ",
+       "ẖ": "ẖ",
+       "ẗ": "ẗ",
+       "ẘ": "ẘ",
+       "ẙ": "ẙ",
+       "ẚ": "ẚ",
+       "ὐ": "ὐ",
+       "ὒ": "ὒ",
+       "ὔ": "ὔ",
+       "ὖ": "ὖ",
+       "ᾀ": "ᾈ",
+       "ᾁ": "ᾉ",
+       "ᾂ": "ᾊ",
+       "ᾃ": "ᾋ",
+       "ᾄ": "ᾌ",
+       "ᾅ": "ᾍ",
+       "ᾆ": "ᾎ",
+       "ᾇ": "ᾏ",
+       "ᾈ": "ᾈ",
+       "ᾉ": "ᾉ",
+       "ᾊ": "ᾊ",
+       "ᾋ": "ᾋ",
+       "ᾌ": "ᾌ",
+       "ᾍ": "ᾍ",
+       "ᾎ": "ᾎ",
+       "ᾏ": "ᾏ",
+       "ᾐ": "ᾘ",
+       "ᾑ": "ᾙ",
+       "ᾒ": "ᾚ",
+       "ᾓ": "ᾛ",
+       "ᾔ": "ᾜ",
+       "ᾕ": "ᾝ",
+       "ᾖ": "ᾞ",
+       "ᾗ": "ᾟ",
+       "ᾘ": "ᾘ",
+       "ᾙ": "ᾙ",
+       "ᾚ": "ᾚ",
+       "ᾛ": "ᾛ",
+       "ᾜ": "ᾜ",
+       "ᾝ": "ᾝ",
+       "ᾞ": "ᾞ",
+       "ᾟ": "ᾟ",
+       "ᾠ": "ᾨ",
+       "ᾡ": "ᾩ",
+       "ᾢ": "ᾪ",
+       "ᾣ": "ᾫ",
+       "ᾤ": "ᾬ",
+       "ᾥ": "ᾭ",
+       "ᾦ": "ᾮ",
+       "ᾧ": "ᾯ",
+       "ᾨ": "ᾨ",
+       "ᾩ": "ᾩ",
+       "ᾪ": "ᾪ",
+       "ᾫ": "ᾫ",
+       "ᾬ": "ᾬ",
+       "ᾭ": "ᾭ",
+       "ᾮ": "ᾮ",
+       "ᾯ": "ᾯ",
+       "ᾲ": "ᾲ",
+       "ᾳ": "ᾼ",
+       "ᾴ": "ᾴ",
+       "ᾶ": "ᾶ",
+       "ᾷ": "ᾷ",
+       "ᾼ": "ᾼ",
+       "ῂ": "ῂ",
+       "ῃ": "ῌ",
+       "ῄ": "ῄ",
+       "ῆ": "ῆ",
+       "ῇ": "ῇ",
+       "ῌ": "ῌ",
+       "ῒ": "ῒ",
+       "ΐ": "ΐ",
+       "ῖ": "ῖ",
+       "ῗ": "ῗ",
+       "ῢ": "ῢ",
+       "ΰ": "ΰ",
+       "ῤ": "ῤ",
+       "ῦ": "ῦ",
+       "ῧ": "ῧ",
+       "ῲ": "ῲ",
+       "ῳ": "ῼ",
+       "ῴ": "ῴ",
+       "ῶ": "ῶ",
+       "ῷ": "ῷ",
+       "ῼ": "ῼ",
+       "ⅰ": "ⅰ",
+       "ⅱ": "ⅱ",
+       "ⅲ": "ⅲ",
+       "ⅳ": "ⅳ",
+       "ⅴ": "ⅴ",
+       "ⅵ": "ⅵ",
+       "ⅶ": "ⅶ",
+       "ⅷ": "ⅷ",
+       "ⅸ": "ⅸ",
+       "ⅹ": "ⅹ",
+       "ⅺ": "ⅺ",
+       "ⅻ": "ⅻ",
+       "ⅼ": "ⅼ",
+       "ⅽ": "ⅽ",
+       "ⅾ": "ⅾ",
+       "ⅿ": "ⅿ",
+       "ⓐ": "ⓐ",
+       "ⓑ": "ⓑ",
+       "ⓒ": "ⓒ",
+       "ⓓ": "ⓓ",
+       "ⓔ": "ⓔ",
+       "ⓕ": "ⓕ",
+       "ⓖ": "ⓖ",
+       "ⓗ": "ⓗ",
+       "ⓘ": "ⓘ",
+       "ⓙ": "ⓙ",
+       "ⓚ": "ⓚ",
+       "ⓛ": "ⓛ",
+       "ⓜ": "ⓜ",
+       "ⓝ": "ⓝ",
+       "ⓞ": "ⓞ",
+       "ⓟ": "ⓟ",
+       "ⓠ": "ⓠ",
+       "ⓡ": "ⓡ",
+       "ⓢ": "ⓢ",
+       "ⓣ": "ⓣ",
+       "ⓤ": "ⓤ",
+       "ⓥ": "ⓥ",
+       "ⓦ": "ⓦ",
+       "ⓧ": "ⓧ",
+       "ⓨ": "ⓨ",
+       "ⓩ": "ⓩ",
+       "ꞵ": "Ꞵ",
+       "ꞷ": "Ꞷ",
+       "ꭓ": "Ꭓ",
+       "ꭰ": "Ꭰ",
+       "ꭱ": "Ꭱ",
+       "ꭲ": "Ꭲ",
+       "ꭳ": "Ꭳ",
+       "ꭴ": "Ꭴ",
+       "ꭵ": "Ꭵ",
+       "ꭶ": "Ꭶ",
+       "ꭷ": "Ꭷ",
+       "ꭸ": "Ꭸ",
+       "ꭹ": "Ꭹ",
+       "ꭺ": "Ꭺ",
+       "ꭻ": "Ꭻ",
+       "ꭼ": "Ꭼ",
+       "ꭽ": "Ꭽ",
+       "ꭾ": "Ꭾ",
+       "ꭿ": "Ꭿ",
+       "ꮀ": "Ꮀ",
+       "ꮁ": "Ꮁ",
+       "ꮂ": "Ꮂ",
+       "ꮃ": "Ꮃ",
+       "ꮄ": "Ꮄ",
+       "ꮅ": "Ꮅ",
+       "ꮆ": "Ꮆ",
+       "ꮇ": "Ꮇ",
+       "ꮈ": "Ꮈ",
+       "ꮉ": "Ꮉ",
+       "ꮊ": "Ꮊ",
+       "ꮋ": "Ꮋ",
+       "ꮌ": "Ꮌ",
+       "ꮍ": "Ꮍ",
+       "ꮎ": "Ꮎ",
+       "ꮏ": "Ꮏ",
+       "ꮐ": "Ꮐ",
+       "ꮑ": "Ꮑ",
+       "ꮒ": "Ꮒ",
+       "ꮓ": "Ꮓ",
+       "ꮔ": "Ꮔ",
+       "ꮕ": "Ꮕ",
+       "ꮖ": "Ꮖ",
+       "ꮗ": "Ꮗ",
+       "ꮘ": "Ꮘ",
+       "ꮙ": "Ꮙ",
+       "ꮚ": "Ꮚ",
+       "ꮛ": "Ꮛ",
+       "ꮜ": "Ꮜ",
+       "ꮝ": "Ꮝ",
+       "ꮞ": "Ꮞ",
+       "ꮟ": "Ꮟ",
+       "ꮠ": "Ꮠ",
+       "ꮡ": "Ꮡ",
+       "ꮢ": "Ꮢ",
+       "ꮣ": "Ꮣ",
+       "ꮤ": "Ꮤ",
+       "ꮥ": "Ꮥ",
+       "ꮦ": "Ꮦ",
+       "ꮧ": "Ꮧ",
+       "ꮨ": "Ꮨ",
+       "ꮩ": "Ꮩ",
+       "ꮪ": "Ꮪ",
+       "ꮫ": "Ꮫ",
+       "ꮬ": "Ꮬ",
+       "ꮭ": "Ꮭ",
+       "ꮮ": "Ꮮ",
+       "ꮯ": "Ꮯ",
+       "ꮰ": "Ꮰ",
+       "ꮱ": "Ꮱ",
+       "ꮲ": "Ꮲ",
+       "ꮳ": "Ꮳ",
+       "ꮴ": "Ꮴ",
+       "ꮵ": "Ꮵ",
+       "ꮶ": "Ꮶ",
+       "ꮷ": "Ꮷ",
+       "ꮸ": "Ꮸ",
+       "ꮹ": "Ꮹ",
+       "ꮺ": "Ꮺ",
+       "ꮻ": "Ꮻ",
+       "ꮼ": "Ꮼ",
+       "ꮽ": "Ꮽ",
+       "ꮾ": "Ꮾ",
+       "ꮿ": "Ꮿ",
+       "ff": "ff",
+       "fi": "fi",
+       "fl": "fl",
+       "ffi": "ffi",
+       "ffl": "ffl",
+       "ſt": "ſt",
+       "st": "st",
+       "ﬓ": "ﬓ",
+       "ﬔ": "ﬔ",
+       "ﬕ": "ﬕ",
+       "ﬖ": "ﬖ",
+       "ﬗ": "ﬗ"
+}
index 7996ea4..a0505cc 100644 (file)
@@ -8,7 +8,7 @@
                        summaryByteLimit = mw.config.get( 'wgCommentByteLimit' ),
                        reasonList = OO.ui.infuse( $( '#wpDeleteReasonList' ).closest( '.oo-ui-widget' ) ),
                        reason = OO.ui.infuse( $( '#wpReason' ).closest( '.oo-ui-widget' ) ),
-                       filterFn = function ( input ) {
+                       filterFunction = function ( input ) {
                                // Should be built the same as in SpecialRevisionDelete::submit()
                                var comment = reasonList.getValue();
                                if ( comment === 'other' ) {
@@ -22,9 +22,9 @@
 
                // Limit to bytes or UTF-8 codepoints, depending on MediaWiki's configuration
                if ( summaryCodePointLimit ) {
-                       reason.$input.codePointLimit( summaryCodePointLimit, filterFn );
+                       reason.$input.codePointLimit( summaryCodePointLimit, filterFunction );
                } else if ( summaryByteLimit ) {
-                       reason.$input.byteLimit( summaryByteLimit, filterFn );
+                       reason.$input.byteLimit( summaryByteLimit, filterFunction );
                }
        } );
 
index a7228ed..f125748 100644 (file)
@@ -8,7 +8,7 @@
                        summaryByteLimit = mw.config.get( 'wgCommentByteLimit' ),
                        reasonList = OO.ui.infuse( $( '#wpDeleteReasonList' ).closest( '.oo-ui-widget' ) ),
                        reason = OO.ui.infuse( $( '#wpReason' ).closest( '.oo-ui-widget' ) ),
-                       filterFn = function ( input ) {
+                       filterFunction = function ( input ) {
                                // Should be built the same as in Article::delete()
                                var comment = reasonList.getValue();
                                if ( comment === 'other' ) {
@@ -22,9 +22,9 @@
 
                // Limit to bytes or UTF-8 codepoints, depending on MediaWiki's configuration
                if ( summaryCodePointLimit ) {
-                       reason.$input.codePointLimit( summaryCodePointLimit, filterFn );
+                       reason.$input.codePointLimit( summaryCodePointLimit, filterFunction );
                } else if ( summaryByteLimit ) {
-                       reason.$input.byteLimit( summaryByteLimit, filterFn );
+                       reason.$input.byteLimit( summaryByteLimit, filterFunction );
                }
        } );
 }() );
index b5a9665..b8c3a44 100644 (file)
@@ -12,6 +12,7 @@
 
 /* Show/hide animation is incorrect if the table has a margin set. Extra
  * ".wikitable" is needed in the selector for CSS specificity. */
+/* stylelint-disable-next-line selector-class-pattern */
 .wikitable.preview-limit-report {
        margin: 0;
 }
index 1367426..fc806c6 100644 (file)
@@ -2,6 +2,8 @@
  * Styles for elements of the editing form.
  */
 
+/* stylelint-disable selector-class-pattern */
+
 /*
  * Add a bit of margin space between the preview and the toolbar.
  * This replaces the ugly <p><br /></p> we used to insert into the page source
index 520917a..5425990 100644 (file)
@@ -1,3 +1,5 @@
+/* stylelint-disable selector-class-pattern */
+
 /* Styles for the JavaScript enhancements of the history page */
 
 #pagehistory li.before input[ name='oldid' ],
diff --git a/resources/src/mediawiki.action/mediawiki.action.history.styles.css b/resources/src/mediawiki.action/mediawiki.action.history.styles.css
deleted file mode 100644 (file)
index 257f153..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* Basic styles for the history page */
-
-#pagehistory .history-user {
-       margin-left: 0.4em;
-       margin-right: 0.2em;
-}
-
-#pagehistory li {
-       border: 1px solid #fff;
-}
-
-#pagehistory li.selected {
-       background-color: #f8f9fa;
-       color: #222;
-       border: 1px dashed #a2a9b1;
-}
-
-.mw-history-revisionactions {
-       float: right;
-}
-
-.updatedmarker {
-       background-color: #b7f430;
-}
diff --git a/resources/src/mediawiki.action/mediawiki.action.history.styles.less b/resources/src/mediawiki.action/mediawiki.action.history.styles.less
new file mode 100644 (file)
index 0000000..cf63ff8
--- /dev/null
@@ -0,0 +1,28 @@
+/**
+ * Basic styles for the edit revision history page 'HistoryAction.php'
+ */
+
+/* stylelint-disable selector-class-pattern */
+
+#pagehistory .history-user {
+       margin-left: 0.4em;
+       margin-right: 0.2em;
+}
+
+#pagehistory li {
+       padding: 1px;
+}
+
+#pagehistory li.selected {
+       background-color: #f8f9fa;
+       color: #222;
+       outline: 1px dashed #a2a9b1;
+}
+
+.mw-history-revisionactions {
+       float: right;
+}
+
+.updatedmarker {
+       background-color: #b7f430;
+}
index abdee12..274b3d3 100644 (file)
@@ -16,6 +16,7 @@
        }
 }
 
+/* stylelint-disable-next-line selector-class-pattern */
 .redirect-in-category {
        font-style: italic;
 }
index b643d76..b8d4e70 100644 (file)
@@ -2,6 +2,8 @@
  * File description page
  */
 
+/* stylelint-disable selector-class-pattern */
+
 .mw-filepage-resolutioninfo {
        font-size: smaller;
 }
index f21b111..dad3238 100644 (file)
@@ -13,6 +13,7 @@
 }
 
 @media print {
+       /* stylelint-disable-next-line selector-class-pattern */
        .mw_metadata .mw-metadata-show-hide-extended {
                display: none;
        }
index b61349b..393846d 100644 (file)
                                )
                        );
                } );
-
-               // Initial collapsed state
-               // (For back-compat with cached HTML from before ImagePage.php
-               // did this by default)
-               $tables.addClass( 'collapsed' );
        } );
-
 }() );
index 46976d4..c40b1c3 100644 (file)
@@ -1,5 +1,7 @@
 @import 'mediawiki.mixins';
 
+/* stylelint-disable selector-class-pattern */
+
 .postedit-container {
        margin: 0 auto;
        position: fixed;
index dccbacc..b5eaf8e 100644 (file)
@@ -2,6 +2,8 @@
  * Display neat icons on redirect pages.
  */
 
+/* stylelint-disable selector-class-pattern */
+
 /* Hide, but keep accessible for screen-readers. */
 .redirectMsg p {
        overflow: hidden;
index 42b0771..447b936 100644 (file)
                        if ( mw.Title && content instanceof mw.Title ) {
                                // Parse existing page
                                config.page = content.getPrefixedDb();
+                               apiPromise = this.get( config );
                        } else {
                                // Parse wikitext from input
                                config.text = String( content );
+                               apiPromise = this.post( config );
                        }
 
-                       apiPromise = this.get( config );
-
                        return apiPromise
                                .then( function ( data ) {
                                        return data.parse.text;
index de0688a..fe21f07 100644 (file)
                                        }
 
                                        // If the call flat out failed, we may want to try again...
-                                       retry = api.uploadChunk.bind( this, file, data, start, end, filekey, retries - 1 );
+                                       retry = api.uploadChunk.bind( api, file, data, start, end, filekey, retries - 1 );
                                        return api.retry( code, result, retry );
                                },
                                function ( fraction ) {
                                        return finishUpload;
                                },
                                function ( errorCode, result ) {
-                                       if ( result && result.upload && result.upload.filekey ) {
-                                               // Ignore any warnings if 'filekey' was returned, that's all we care about
+                                       if ( result && result.upload && result.upload.result === 'Success' && result.upload.filekey ) {
+                                               // Catch handler is also called in case of warnings (e.g. 'duplicate')
+                                               // We don't really care about those warnings, as long as the upload got stashed...
                                                filekey = result.upload.filekey;
                                                return $.Deferred().resolve( finishUpload );
                                        }
index 7528fdb..d1f32ab 100644 (file)
@@ -1,3 +1,5 @@
+/* stylelint-disable selector-class-pattern */
+
 .apihelp-header {
        clear: both;
        margin-bottom: 0.1em;
index 99e4569..3e921f4 100644 (file)
@@ -1,3 +1,5 @@
+/* stylelint-disable selector-class-pattern */
+
 .mw-special-ApiHelp h1.firstHeading {
        display: none;
 }
index 9016c7c..00a74fe 100644 (file)
                 * @return {string} Parsed message
                 */
                parser: function () {
-                       var text;
-                       if ( mw.config.get( 'wgUserLanguage' ) === 'qqx' ) {
+                       var text = this.map.get( this.key );
+                       if (
+                               mw.config.get( 'wgUserLanguage' ) === 'qqx' &&
+                               ( !text || text === '(' + this.key + ')' )
+                       ) {
                                text = '(' + this.key + '$*)';
-                       } else {
-                               text = this.map.get( this.key );
                        }
                        return mw.format.apply( null, [ text ].concat( this.parameters ) );
                },
index e084ab8..8f4fccc 100644 (file)
@@ -18,7 +18,7 @@
        padding: 0.5em 1em;
 }
 
-.mw-json .value,
+.mw-json-value,
 .mw-json-single-value {
        background-color: #dcfae3;
        font-family: monospace, monospace;
        background-color: #fff;
        font-weight: normal;
 }
-
-.mw-json caption {
-       /* For stylistic reasons, suppress the caption of the outermost table */
-       display: none;
-}
-
-.mw-json table caption {
-       color: #72777d;
-       display: inline-block;
-       font-size: 10px;
-       font-style: italic;
-       margin-bottom: 0.5em;
-       text-align: left;
-}
diff --git a/resources/src/mediawiki.cookie/.eslintrc.json b/resources/src/mediawiki.cookie/.eslintrc.json
new file mode 100644 (file)
index 0000000..ad8dbb3
--- /dev/null
@@ -0,0 +1,5 @@
+{
+       "parserOptions": {
+               "sourceType": "module"
+       }
+}
index 61379ae..b04b57a 100644 (file)
-( function () {
-       'use strict';
+'use strict';
 
-       var config = require( './config.json' ),
-               defaults = {
-                       prefix: config.prefix,
-                       domain: config.domain,
-                       path: config.path,
-                       expires: config.expires,
-                       secure: false
-               };
+var config = require( './config.json' ),
+       defaults = {
+               prefix: config.prefix,
+               domain: config.domain,
+               path: config.path,
+               expires: config.expires,
+               secure: false
+       };
+
+/**
+ * Manage cookies in a way that is syntactically and functionally similar
+ * to the `WebRequest#getCookie` and `WebResponse#setcookie` methods in PHP.
+ *
+ * @author Sam Smith <samsmith@wikimedia.org>
+ * @author Matthew Flaschen <mflaschen@wikimedia.org>
+ *
+ * @class mw.cookie
+ * @singleton
+ */
+mw.cookie = {
 
        /**
-        * Manage cookies in a way that is syntactically and functionally similar
-        * to the `WebRequest#getCookie` and `WebResponse#setcookie` methods in PHP.
+        * Set or delete a cookie.
         *
-        * @author Sam Smith <samsmith@wikimedia.org>
-        * @author Matthew Flaschen <mflaschen@wikimedia.org>
+        * **Note:** If explicitly passing `null` or `undefined` for an options key,
+        * that will override the default. This is natural in JavaScript, but noted
+        * here because it is contrary to MediaWiki's `WebResponse#setcookie()` method
+        * in PHP.
         *
-        * @class mw.cookie
-        * @singleton
+        * @param {string} key
+        * @param {string|null} value Value of cookie. If `value` is `null` then this method will
+        *   instead remove a cookie by name of `key`.
+        * @param {Object|Date|number} [options] Options object, or expiry date
+        * @param {Date|number|null} [options.expires=wgCookieExpiration] The expiry date of the cookie,
+        *  or lifetime in seconds. If `options.expires` is null or 0, then a session cookie is set.
+        * @param {string} [options.prefix=wgCookiePrefix] The prefix of the key
+        * @param {string} [options.domain=wgCookieDomain] The domain attribute of the cookie
+        * @param {string} [options.path=wgCookiePath] The path attribute of the cookie
+        * @param {boolean} [options.secure=false] Whether or not to include the secure attribute.
+        *   (Does **not** use the wgCookieSecure configuration variable)
         */
-       mw.cookie = {
+       set: function ( key, value, options ) {
+               var date;
 
-               /**
-                * Set or delete a cookie.
-                *
-                * **Note:** If explicitly passing `null` or `undefined` for an options key,
-                * that will override the default. This is natural in JavaScript, but noted
-                * here because it is contrary to MediaWiki's `WebResponse#setcookie()` method
-                * in PHP.
-                *
-                * @param {string} key
-                * @param {string|null} value Value of cookie. If `value` is `null` then this method will
-                *   instead remove a cookie by name of `key`.
-                * @param {Object|Date|number} [options] Options object, or expiry date
-                * @param {Date|number|null} [options.expires=wgCookieExpiration] The expiry date of the cookie,
-                *  or lifetime in seconds. If `options.expires` is null or 0, then a session cookie is set.
-                * @param {string} [options.prefix=wgCookiePrefix] The prefix of the key
-                * @param {string} [options.domain=wgCookieDomain] The domain attribute of the cookie
-                * @param {string} [options.path=wgCookiePath] The path attribute of the cookie
-                * @param {boolean} [options.secure=false] Whether or not to include the secure attribute.
-                *   (Does **not** use the wgCookieSecure configuration variable)
-                */
-               set: function ( key, value, options ) {
-                       var date;
+               // The 'options' parameter may be a shortcut for the expiry.
+               if ( arguments.length > 2 && ( !options || options instanceof Date || typeof options === 'number' ) ) {
+                       options = { expires: options };
+               }
+               // Apply defaults
+               options = $.extend( {}, defaults, options );
 
-                       // The 'options' parameter may be a shortcut for the expiry.
-                       if ( arguments.length > 2 && ( !options || options instanceof Date || typeof options === 'number' ) ) {
-                               options = { expires: options };
-                       }
-                       // Apply defaults
-                       options = $.extend( {}, defaults, options );
+               // Handle prefix
+               key = options.prefix + key;
+               // Don't pass invalid option to $.cookie
+               delete options.prefix;
 
-                       // Handle prefix
-                       key = options.prefix + key;
-                       // Don't pass invalid option to $.cookie
-                       delete options.prefix;
+               if ( !options.expires ) {
+                       // Session cookie (null or zero)
+                       // Normalize to absent (undefined) for $.cookie.
+                       delete options.expires;
+               } else if ( typeof options.expires === 'number' ) {
+                       // Lifetime in seconds
+                       date = new Date();
+                       date.setTime( Number( date ) + ( options.expires * 1000 ) );
+                       options.expires = date;
+               }
 
-                       if ( !options.expires ) {
-                               // Session cookie (null or zero)
-                               // Normalize to absent (undefined) for $.cookie.
-                               delete options.expires;
-                       } else if ( typeof options.expires === 'number' ) {
-                               // Lifetime in seconds
-                               date = new Date();
-                               date.setTime( Number( date ) + ( options.expires * 1000 ) );
-                               options.expires = date;
-                       }
+               if ( value !== null ) {
+                       value = String( value );
+               }
 
-                       if ( value !== null ) {
-                               value = String( value );
-                       }
+               $.cookie( key, value, options );
+       },
 
-                       $.cookie( key, value, options );
-               },
+       /**
+        * Get the value of a cookie.
+        *
+        * @param {string} key
+        * @param {string} [prefix=wgCookiePrefix] The prefix of the key. If `prefix` is
+        *   `undefined` or `null`, then `wgCookiePrefix` is used
+        * @param {Mixed} [defaultValue=null]
+        * @return {string|null|Mixed} If the cookie exists, then the value of the
+        *   cookie, otherwise `defaultValue`
+        */
+       get: function ( key, prefix, defaultValue ) {
+               var result;
 
-               /**
-                * Get the value of a cookie.
-                *
-                * @param {string} key
-                * @param {string} [prefix=wgCookiePrefix] The prefix of the key. If `prefix` is
-                *   `undefined` or `null`, then `wgCookiePrefix` is used
-                * @param {Mixed} [defaultValue=null]
-                * @return {string|null|Mixed} If the cookie exists, then the value of the
-                *   cookie, otherwise `defaultValue`
-                */
-               get: function ( key, prefix, defaultValue ) {
-                       var result;
+               if ( prefix === undefined || prefix === null ) {
+                       prefix = defaults.prefix;
+               }
 
-                       if ( prefix === undefined || prefix === null ) {
-                               prefix = defaults.prefix;
-                       }
+               // Was defaultValue omitted?
+               if ( arguments.length < 3 ) {
+                       defaultValue = null;
+               }
 
-                       // Was defaultValue omitted?
-                       if ( arguments.length < 3 ) {
-                               defaultValue = null;
-                       }
+               result = $.cookie( prefix + key );
 
-                       result = $.cookie( prefix + key );
+               return result !== null ? result : defaultValue;
+       }
+};
 
-                       return result !== null ? result : defaultValue;
+if ( window.QUnit ) {
+       module.exports = {
+               setDefaults: function ( value ) {
+                       var prev = defaults;
+                       defaults = value;
+                       return prev;
                }
        };
-
-       if ( window.QUnit ) {
-               module.exports = {
-                       setDefaults: function ( value ) {
-                               var prev = defaults;
-                               defaults = value;
-                               return prev;
-                       }
-               };
-       }
-}() );
+}
index 86bc44a..a8c7264 100644 (file)
                        }
 
                        bitDiv( 'mwversion' )
-                               .append( $( '<a>' ).attr( 'href', '//www.mediawiki.org/' ).text( 'MediaWiki' ) )
+                               .append( $( '<a>' ).attr( 'href', 'https://www.mediawiki.org/' ).text( 'MediaWiki' ) )
                                .append( document.createTextNode( ': ' + this.data.mwVersion + ' ' ) )
                                .append( gitInfo );
 
index a56e459..272e7e0 100644 (file)
                        border-bottom: 1px solid #eee;
                        word-wrap: break-word;
 
+                       /* stylelint-disable-next-line selector-class-pattern */
                        &.nr {
                                text-align: right;
                        }
 
+                       /* stylelint-disable-next-line selector-class-pattern */
                        span.stats {
                                color: #727272;
                        }
@@ -78,6 +80,7 @@
                cursor: pointer;
        }
 
+       /* stylelint-disable-next-line selector-class-pattern */
        &.current {
                background-color: #dedede;
        }
index 2053843..6382ac8 100644 (file)
@@ -2,6 +2,8 @@
  * Diff rendering
  */
 
+/* stylelint-disable selector-class-pattern */
+
 .diff {
        border: 0;
        border-spacing: 4px;
index 76b5c9b..159e7ae 100644 (file)
@@ -1,3 +1,4 @@
+/* stylelint-disable selector-class-pattern */
 /*!
  * Diff rendering
  */
index 92e1d04..c2d4835 100644 (file)
@@ -1,13 +1,3 @@
-.feedback-spinner {
-       display: inline-block;
-       zoom: 1;
-       *display: inline; /* IE7 and below */ /* stylelint-disable declaration-block-no-duplicate-properties */
-       /* @embed */
-       background: url( images/spinner.gif );
-       width: 18px;
-       height: 18px;
-}
-
 .mw-feedbackDialog-welcome-message,
 .mw-feedbackDialog-feedback-terms {
        line-height: 1.4;
index 5b73e7c..306d93a 100644 (file)
                        padded: true
                } );
 
-               this.$spinner = $( '<div>' )
-                       .addClass( 'feedback-spinner' );
-
                // Feedback form
                this.feedbackMessageLabel = new OO.ui.LabelWidget( {
                        classes: [ 'mw-feedbackDialog-welcome-message' ]
                                this.messagePosterPromise = settings.messagePosterPromise;
                                this.setBugReportLink( settings.bugsTaskSubmissionLink );
                                this.feedbackPageTitle = settings.title;
-                               this.feedbackPageName = settings.title.getNameText();
+                               this.feedbackPageName = settings.title.getMainText();
 
                                // Useragent checkbox
                                if ( settings.useragentCheckbox.show ) {
diff --git a/resources/src/mediawiki.feedback/images/spinner.gif b/resources/src/mediawiki.feedback/images/spinner.gif
deleted file mode 100644 (file)
index aed0ea4..0000000
Binary files a/resources/src/mediawiki.feedback/images/spinner.gif and /dev/null differ
index 37808d5..13d0ba1 100644 (file)
@@ -1,5 +1,6 @@
 /* Styles for links to RSS/Atom feeds in sidebar */
 
+/* stylelint-disable-next-line selector-class-pattern */
 a.feedlink {
        /* SVG support using a transparent gradient to guarantee cross-browser
         * compatibility (browsers able to understand gradient syntax support also SVG).
index bf9634f..a608437 100644 (file)
@@ -1,5 +1,7 @@
 @import 'mediawiki.ui/variables';
 
+/* stylelint-disable selector-class-pattern */
+
 // Increase the area of the button, so that the user can move the mouse cursor
 // to the popup without the popup disappearing. (T157544)
 .mediawiki-filewarning-anchor {
index 4eed90a..dd50106 100644 (file)
@@ -1,11 +1,11 @@
 @import 'mediawiki.mixins';
 
 #mw-indicator-mw-helplink a {
-       .background-image-svg('images/help.svg', 'images/help.png');
-       background-repeat: no-repeat;
+       .background-image-svg('images/helpNotice.svg', 'images/helpNotice.png');
        background-position: left center;
-       padding-left: 28px;
+       background-repeat: no-repeat;
        display: inline-block;
-       height: 24px;
-       line-height: 24px;
+       height: 20px;
+       padding-left: 25px;
+       line-height: 20px;
 }
diff --git a/resources/src/mediawiki.helplink/images/help.png b/resources/src/mediawiki.helplink/images/help.png
deleted file mode 100644 (file)
index 301e23b..0000000
Binary files a/resources/src/mediawiki.helplink/images/help.png and /dev/null differ
diff --git a/resources/src/mediawiki.helplink/images/help.svg b/resources/src/mediawiki.helplink/images/help.svg
deleted file mode 100644 (file)
index 4fc6a0c..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
-       <path d="M12.001 2.085a9.914 9.914 0 0 0-9.916 9.916c0 5.476 4.438 9.914 9.916 9.914a9.913 9.913 0 0 0 9.914-9.914c0-5.478-4.438-9.916-9.914-9.916zm.001 18a8.083 8.083 0 1 1 0-16.167 8.083 8.083 0 0 1 0 16.167z"/>
-       <path d="M11.766 6.688c-2.5 0-3.219 2.188-3.219 2.188l1.411.854s.298-.791.901-1.229c.516-.375 1.625-.625 2.219.125.701.885-.17 1.587-1.078 2.719C11.047 12.531 11 15 11 15h1.969s.135-2.318 1.041-3.381c.603-.707 1.443-1.338 1.443-2.494s-1.187-2.437-3.687-2.437zM11 16h2v2h-2z"/>
-</svg>
diff --git a/resources/src/mediawiki.helplink/images/helpNotice.png b/resources/src/mediawiki.helplink/images/helpNotice.png
new file mode 100644 (file)
index 0000000..ef1d713
Binary files /dev/null and b/resources/src/mediawiki.helplink/images/helpNotice.png differ
diff --git a/resources/src/mediawiki.helplink/images/helpNotice.svg b/resources/src/mediawiki.helplink/images/helpNotice.svg
new file mode 100644 (file)
index 0000000..8f0c3dc
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
+       <title>
+               help
+       </title>
+       <path d="M10 0a10 10 0 1 0 10 10A10 10 0 0 0 10 0zm1 16H9v-2h2zm2.71-7.6a2.64 2.64 0 0 1-.33.74 3.16 3.16 0 0 1-.48.55l-.54.48c-.21.18-.41.35-.58.52a2.54 2.54 0 0 0-.47.56A2.3 2.3 0 0 0 11 12a3.79 3.79 0 0 0-.11 1H9.08a8.9 8.9 0 0 1 .07-1.25 3.28 3.28 0 0 1 .25-.9 2.79 2.79 0 0 1 .41-.67 4 4 0 0 1 .58-.58c.17-.16.34-.3.51-.44a3 3 0 0 0 .43-.44 1.83 1.83 0 0 0 .3-.55 2 2 0 0 0 .11-.72 2.06 2.06 0 0 0-.17-.86 1.71 1.71 0 0 0-1-.9 1.7 1.7 0 0 0-.5-.1 1.77 1.77 0 0 0-1.53.68 3 3 0 0 0-.5 1.82H6.16a4.74 4.74 0 0 1 .28-1.68 3.56 3.56 0 0 1 .8-1.29 3.88 3.88 0 0 1 1.28-.83A4.59 4.59 0 0 1 10.18 4a4.44 4.44 0 0 1 1.44.23 3.51 3.51 0 0 1 1.15.65 3.08 3.08 0 0 1 .78 1.06 3.54 3.54 0 0 1 .29 1.45 3.39 3.39 0 0 1-.13 1.01z"/>
+</svg>
index e25a92f..d9612a8 100644 (file)
@@ -2,6 +2,9 @@
  * Stylesheet for mediawiki.hlist module
  * @author [[User:Edokter]]
  */
+
+/* stylelint-disable selector-class-pattern */
+
 /* Generate interpuncts */
 .hlist dt:after {
        content: ':';
index d7071e4..5bc6a68 100644 (file)
@@ -1,3 +1,4 @@
+/* stylelint-disable-next-line selector-class-pattern */
 .hlist {
        dl,
        ol,
index ecf728b..470d826 100644 (file)
@@ -1,5 +1,7 @@
 @import 'mediawiki.mixins';
 
+/* stylelint-disable selector-class-pattern */
+
 // OOUIHTMLForm styles
 @ooui-font-size-browser: 16; // assumed browser default of `16px`
 @ooui-font-size-base: 0.875em; // equals `14px` at browser default of `16px`
 @ooui-padding-vertical: 4 / @ooui-font-size-browser / @ooui-font-size-base; // equals `0.285714em`≈`4px`
 
 .mw-htmlform-ooui-wrapper.oo-ui-panelLayout-padded {
+       // Reducing `padding-top`, as the heading's `line-height` provides similar distance.
        padding: @ooui-spacing-medium @ooui-spacing-large @ooui-spacing-large;
+
+       // Trigger only when collapsible & JS is available via `.mw-collapsed`.
+       .client-js & .oo-ui-fieldsetLayout.mw-collapsed .oo-ui-fieldsetLayout-header {
+               // Negative margin to match the reduced distance on the top caused by the previous rule.
+               margin-bottom: -( @ooui-spacing-large - @ooui-spacing-medium );
+
+               .oo-ui-labelElement-label {
+                       margin-bottom: 0;
+               }
+       }
 }
 
 .mw-htmlform-ooui {
index cfabab6..a0e9f15 100644 (file)
@@ -8,6 +8,7 @@
        content: '. .';
 }
 
+/* stylelint-disable-next-line selector-class-pattern */
 .comment--without-parentheses,
 .mw-changeslist-links,
 .mw-diff-bytes,
diff --git a/resources/src/mediawiki.jqueryMsg/.eslintrc.json b/resources/src/mediawiki.jqueryMsg/.eslintrc.json
new file mode 100644 (file)
index 0000000..ad8dbb3
--- /dev/null
@@ -0,0 +1,5 @@
+{
+       "parserOptions": {
+               "sourceType": "module"
+       }
+}
index 3b89a74..e0c9833 100644 (file)
 * @author neilk@wikimedia.org
 * @author mflaschen@wikimedia.org
 */
-( function () {
-       /**
-        * @class mw.jqueryMsg
-        * @singleton
-        */
-
-       var oldParser,
-               slice = Array.prototype.slice,
-               parserDefaults = {
-                       // Magic words and their expansions. Server-side data is added to this below.
-                       magic: {
-                               PAGENAME: mw.config.get( 'wgPageName' ),
-                               PAGENAMEE: mw.util.wikiUrlencode( mw.config.get( 'wgPageName' ) )
-                       },
-                       // Whitelist for allowed HTML elements in wikitext.
-                       // Self-closing tags are not currently supported.
-                       // Filled in with server-side data below
-                       allowedHtmlElements: [],
-                       // Key tag name, value allowed attributes for that tag.
-                       // See Sanitizer::setupAttributeWhitelist
-                       allowedHtmlCommonAttributes: [
-                               // HTML
-                               'id',
-                               'class',
-                               'style',
-                               'lang',
-                               'dir',
-                               'title',
-
-                               // WAI-ARIA
-                               'role'
-                       ],
-
-                       // Attributes allowed for specific elements.
-                       // Key is element name in lower case
-                       // Value is array of allowed attributes for that element
-                       allowedHtmlAttributesByElement: {},
-                       messages: mw.messages,
-                       language: mw.language,
-
-                       // Same meaning as in mediawiki.js.
-                       //
-                       // Only 'text', 'parse', and 'escaped' are supported, and the
-                       // actual escaping for 'escaped' is done by other code (generally
-                       // through mediawiki.js).
-                       //
-                       // However, note that this default only
-                       // applies to direct calls to jqueryMsg. The default for mediawiki.js itself
-                       // is 'text', including when it uses jqueryMsg.
-                       format: 'parse'
-               };
 
-       // Add in server-side data (allowedHtmlElements and magic words)
-       $.extend( true, parserDefaults, require( './parserDefaults.json' ) );
+/**
+ * @class mw.jqueryMsg
+ * @singleton
+ */
+
+var oldParser,
+       slice = Array.prototype.slice,
+       parserDefaults = {
+               // Magic words and their expansions. Server-side data is added to this below.
+               magic: {
+                       PAGENAME: mw.config.get( 'wgPageName' ),
+                       PAGENAMEE: mw.util.wikiUrlencode( mw.config.get( 'wgPageName' ) )
+               },
+               // Whitelist for allowed HTML elements in wikitext.
+               // Self-closing tags are not currently supported.
+               // Filled in with server-side data below
+               allowedHtmlElements: [],
+               // Key tag name, value allowed attributes for that tag.
+               // See Sanitizer::setupAttributeWhitelist
+               allowedHtmlCommonAttributes: [
+                       // HTML
+                       'id',
+                       'class',
+                       'style',
+                       'lang',
+                       'dir',
+                       'title',
+
+                       // WAI-ARIA
+                       'role'
+               ],
+
+               // Attributes allowed for specific elements.
+               // Key is element name in lower case
+               // Value is array of allowed attributes for that element
+               allowedHtmlAttributesByElement: {},
+               messages: mw.messages,
+               language: mw.language,
+
+               // Same meaning as in mediawiki.js.
+               //
+               // Only 'text', 'parse', and 'escaped' are supported, and the
+               // actual escaping for 'escaped' is done by other code (generally
+               // through mediawiki.js).
+               //
+               // However, note that this default only
+               // applies to direct calls to jqueryMsg. The default for mediawiki.js itself
+               // is 'text', including when it uses jqueryMsg.
+               format: 'parse'
+       };
 
-       /**
-        * Wrapper around jQuery append that converts all non-objects to TextNode so append will not
-        * convert what it detects as an htmlString to an element.
-        *
-        * If our own HtmlEmitter jQuery object is given, its children will be unwrapped and appended to
-        * new parent.
-        *
-        * Object elements of children (jQuery, HTMLElement, TextNode, etc.) will be left as is.
-        *
-        * @private
-        * @param {jQuery} $parent Parent node wrapped by jQuery
-        * @param {Object|string|Array} children What to append, with the same possible types as jQuery
-        * @return {jQuery} $parent
-        */
-       function appendWithoutParsing( $parent, children ) {
-               var i, len;
+// Add in server-side data (allowedHtmlElements and magic words)
+$.extend( true, parserDefaults, require( './parserDefaults.json' ) );
+
+/**
+ * Wrapper around jQuery append that converts all non-objects to TextNode so append will not
+ * convert what it detects as an htmlString to an element.
+ *
+ * If our own HtmlEmitter jQuery object is given, its children will be unwrapped and appended to
+ * new parent.
+ *
+ * Object elements of children (jQuery, HTMLElement, TextNode, etc.) will be left as is.
+ *
+ * @private
+ * @param {jQuery} $parent Parent node wrapped by jQuery
+ * @param {Object|string|Array} children What to append, with the same possible types as jQuery
+ * @return {jQuery} $parent
+ */
+function appendWithoutParsing( $parent, children ) {
+       var i, len;
+
+       if ( !Array.isArray( children ) ) {
+               children = [ children ];
+       }
 
-               if ( !Array.isArray( children ) ) {
-                       children = [ children ];
+       for ( i = 0, len = children.length; i < len; i++ ) {
+               if ( typeof children[ i ] !== 'object' ) {
+                       children[ i ] = document.createTextNode( children[ i ] );
                }
-
-               for ( i = 0, len = children.length; i < len; i++ ) {
-                       if ( typeof children[ i ] !== 'object' ) {
-                               children[ i ] = document.createTextNode( children[ i ] );
-                       }
-                       if ( children[ i ] instanceof $ && children[ i ].hasClass( 'mediaWiki_htmlEmitter' ) ) {
-                               children[ i ] = children[ i ].contents();
-                       }
+               if ( children[ i ] instanceof $ && children[ i ].hasClass( 'mediaWiki_htmlEmitter' ) ) {
+                       children[ i ] = children[ i ].contents();
                }
-
-               return $parent.append( children );
        }
 
-       /**
-        * Decodes the main HTML entities, those encoded by mw.html.escape.
-        *
-        * @private
-        * @param {string} encoded Encoded string
-        * @return {string} String with those entities decoded
-        */
-       function decodePrimaryHtmlEntities( encoded ) {
-               return encoded
-                       .replace( /&#039;/g, '\'' )
-                       .replace( /&quot;/g, '"' )
-                       .replace( /&lt;/g, '<' )
-                       .replace( /&gt;/g, '>' )
-                       .replace( /&amp;/g, '&' );
+       return $parent.append( children );
+}
+
+/**
+ * Decodes the main HTML entities, those encoded by mw.html.escape.
+ *
+ * @private
+ * @param {string} encoded Encoded string
+ * @return {string} String with those entities decoded
+ */
+function decodePrimaryHtmlEntities( encoded ) {
+       return encoded
+               .replace( /&#039;/g, '\'' )
+               .replace( /&quot;/g, '"' )
+               .replace( /&lt;/g, '<' )
+               .replace( /&gt;/g, '>' )
+               .replace( /&amp;/g, '&' );
+}
+
+/**
+ * Turn input into a string.
+ *
+ * @private
+ * @param {string|jQuery} input
+ * @return {string} Textual value of input
+ */
+function textify( input ) {
+       if ( input instanceof $ ) {
+               input = input.text();
        }
-
-       /**
-        * Turn input into a string.
-        *
-        * @private
-        * @param {string|jQuery} input
-        * @return {string} Textual value of input
-        */
-       function textify( input ) {
-               if ( input instanceof $ ) {
-                       input = input.text();
+       return String( input );
+}
+
+/**
+ * Given parser options, return a function that parses a key and replacements, returning jQuery object
+ *
+ * Try to parse a key and optional replacements, returning a jQuery object that may be a tree of jQuery nodes.
+ * If there was an error parsing, return the key and the error message (wrapped in jQuery). This should put the error right into
+ * the interface, without causing the page to halt script execution, and it hopefully should be clearer how to fix it.
+ *
+ * @private
+ * @param {Object} options Parser options
+ * @return {Function}
+ * @return {Array} return.args First element is the key, replacements may be in array in 2nd element, or remaining elements.
+ * @return {jQuery} return.return
+ */
+function getFailableParserFn( options ) {
+       return function ( args ) {
+               var fallback,
+                       parser = new mw.jqueryMsg.Parser( options ),
+                       key = args[ 0 ],
+                       argsArray = Array.isArray( args[ 1 ] ) ? args[ 1 ] : slice.call( args, 1 );
+               try {
+                       return parser.parse( key, argsArray );
+               } catch ( e ) {
+                       fallback = parser.settings.messages.get( key );
+                       mw.log.warn( 'mediawiki.jqueryMsg: ' + key + ': ' + e.message );
+                       mw.track( 'mediawiki.jqueryMsg.error', {
+                               messageKey: key,
+                               errorMessage: e.message
+                       } );
+                       return $( '<span>' ).text( fallback );
                }
-               return String( input );
+       };
+}
+
+mw.jqueryMsg = {};
+
+/**
+ * Initialize parser defaults.
+ *
+ * ResourceLoaderJqueryMsgModule calls this to provide default values from
+ * Sanitizer.php for allowed HTML elements. To override this data for individual
+ * parsers, pass the relevant options to mw.jqueryMsg.Parser.
+ *
+ * @private
+ * @param {Object} data New data to extend parser defaults with
+ * @param {boolean} [deep=false] Whether the extend is done recursively (deep)
+ */
+mw.jqueryMsg.setParserDefaults = function ( data, deep ) {
+       if ( deep ) {
+               $.extend( true, parserDefaults, data );
+       } else {
+               $.extend( parserDefaults, data );
        }
-
-       /**
-        * Given parser options, return a function that parses a key and replacements, returning jQuery object
-        *
-        * Try to parse a key and optional replacements, returning a jQuery object that may be a tree of jQuery nodes.
-        * If there was an error parsing, return the key and the error message (wrapped in jQuery). This should put the error right into
-        * the interface, without causing the page to halt script execution, and it hopefully should be clearer how to fix it.
-        *
-        * @private
-        * @param {Object} options Parser options
-        * @return {Function}
-        * @return {Array} return.args First element is the key, replacements may be in array in 2nd element, or remaining elements.
-        * @return {jQuery} return.return
-        */
-       function getFailableParserFn( options ) {
-               return function ( args ) {
-                       var fallback,
-                               parser = new mw.jqueryMsg.Parser( options ),
-                               key = args[ 0 ],
-                               argsArray = Array.isArray( args[ 1 ] ) ? args[ 1 ] : slice.call( args, 1 );
-                       try {
-                               return parser.parse( key, argsArray );
-                       } catch ( e ) {
-                               fallback = parser.settings.messages.get( key );
-                               mw.log.warn( 'mediawiki.jqueryMsg: ' + key + ': ' + e.message );
-                               mw.track( 'mediawiki.jqueryMsg.error', {
-                                       messageKey: key,
-                                       errorMessage: e.message
-                               } );
-                               return $( '<span>' ).text( fallback );
-                       }
-               };
+};
+
+/**
+ * Get current parser defaults.
+ *
+ * Primarily used for the unit test. Returns a copy.
+ *
+ * @private
+ * @return {Object}
+ */
+mw.jqueryMsg.getParserDefaults = function () {
+       return $.extend( {}, parserDefaults );
+};
+
+/**
+ * Returns a function suitable for static use, to construct strings from a message key (and optional replacements).
+ *
+ * Example:
+ *
+ *       var format = mediaWiki.jqueryMsg.getMessageFunction( options );
+ *       $( '#example' ).text( format( 'hello-user', username ) );
+ *
+ * Tthis returns only strings, so it destroys any bindings. If you want to preserve bindings, use the
+ * jQuery plugin version instead. This was originally created to ease migration from `window.gM()`,
+ * from a time when the parser used by `mw.message` was not extendable.
+ *
+ * N.B. replacements are variadic arguments or an array in second parameter. In other words:
+ *    somefunction( a, b, c, d )
+ * is equivalent to
+ *    somefunction( a, [b, c, d] )
+ *
+ * @param {Object} options parser options
+ * @return {Function} Function The message formatter
+ * @return {string} return.key Message key.
+ * @return {Array|Mixed} return.replacements Optional variable replacements (variadically or an array).
+ * @return {string} return.return Rendered HTML.
+ */
+mw.jqueryMsg.getMessageFunction = function ( options ) {
+       var failableParserFn, format;
+
+       if ( options && options.format !== undefined ) {
+               format = options.format;
+       } else {
+               format = parserDefaults.format;
        }
 
-       mw.jqueryMsg = {};
-
-       /**
-        * Initialize parser defaults.
-        *
-        * ResourceLoaderJqueryMsgModule calls this to provide default values from
-        * Sanitizer.php for allowed HTML elements. To override this data for individual
-        * parsers, pass the relevant options to mw.jqueryMsg.Parser.
-        *
-        * @private
-        * @param {Object} data New data to extend parser defaults with
-        * @param {boolean} [deep=false] Whether the extend is done recursively (deep)
-        */
-       mw.jqueryMsg.setParserDefaults = function ( data, deep ) {
-               if ( deep ) {
-                       $.extend( true, parserDefaults, data );
+       return function () {
+               var failableResult;
+               if ( !failableParserFn ) {
+                       failableParserFn = getFailableParserFn( options );
+               }
+               failableResult = failableParserFn( arguments );
+               if ( format === 'text' || format === 'escaped' ) {
+                       return failableResult.text();
                } else {
-                       $.extend( parserDefaults, data );
+                       return failableResult.html();
                }
        };
-
-       /**
-        * Get current parser defaults.
-        *
-        * Primarily used for the unit test. Returns a copy.
-        *
-        * @private
-        * @return {Object}
-        */
-       mw.jqueryMsg.getParserDefaults = function () {
-               return $.extend( {}, parserDefaults );
+};
+
+/**
+ * Returns a jQuery plugin which parses the message in the message key, doing replacements optionally, and appends the nodes to
+ * the current selector. Bindings to passed-in jquery elements are preserved. Functions become click handlers for [$1 linktext] links.
+ * e.g.
+ *
+ *        $.fn.msg = mediaWiki.jqueryMsg.getPlugin( options );
+ *        var $userlink = $( '<a>' ).click( function () { alert( "hello!!" ) } );
+ *        $( 'p#headline' ).msg( 'hello-user', $userlink );
+ *
+ * N.B. replacements are variadic arguments or an array in second parameter. In other words:
+ *    somefunction( a, b, c, d )
+ * is equivalent to
+ *    somefunction( a, [b, c, d] )
+ *
+ * We append to 'this', which in a jQuery plugin context will be the selected elements.
+ *
+ * @param {Object} options Parser options
+ * @return {Function} Function suitable for assigning to jQuery plugin, such as jQuery#msg
+ * @return {string} return.key Message key.
+ * @return {Array|Mixed} return.replacements Optional variable replacements (variadically or an array).
+ * @return {jQuery} return.return
+ */
+mw.jqueryMsg.getPlugin = function ( options ) {
+       var failableParserFn;
+
+       return function () {
+               var $target;
+               if ( !failableParserFn ) {
+                       failableParserFn = getFailableParserFn( options );
+               }
+               $target = this.empty();
+               appendWithoutParsing( $target, failableParserFn( arguments ) );
+               return $target;
        };
-
+};
+
+/**
+ * The parser itself.
+ * Describes an object, whose primary duty is to .parse() message keys.
+ *
+ * @class
+ * @private
+ * @param {Object} options
+ */
+mw.jqueryMsg.Parser = function ( options ) {
+       this.settings = $.extend( {}, parserDefaults, options );
+       this.settings.onlyCurlyBraceTransform = ( this.settings.format === 'text' || this.settings.format === 'escaped' );
+       this.astCache = {};
+
+       this.emitter = new mw.jqueryMsg.HtmlEmitter( this.settings.language, this.settings.magic );
+};
+// Backwards-compatible alias
+// @deprecated since 1.31
+mw.jqueryMsg.parser = mw.jqueryMsg.Parser;
+
+mw.jqueryMsg.Parser.prototype = {
        /**
-        * Returns a function suitable for static use, to construct strings from a message key (and optional replacements).
-        *
-        * Example:
-        *
-        *       var format = mediaWiki.jqueryMsg.getMessageFunction( options );
-        *       $( '#example' ).text( format( 'hello-user', username ) );
-        *
-        * Tthis returns only strings, so it destroys any bindings. If you want to preserve bindings, use the
-        * jQuery plugin version instead. This was originally created to ease migration from `window.gM()`,
-        * from a time when the parser used by `mw.message` was not extendable.
+        * Where the magic happens.
+        * Parses a message from the key, and swaps in replacements as necessary, wraps in jQuery
+        * If an error is thrown, returns original key, and logs the error
         *
-        * N.B. replacements are variadic arguments or an array in second parameter. In other words:
-        *    somefunction( a, b, c, d )
-        * is equivalent to
-        *    somefunction( a, [b, c, d] )
-        *
-        * @param {Object} options parser options
-        * @return {Function} Function The message formatter
-        * @return {string} return.key Message key.
-        * @return {Array|Mixed} return.replacements Optional variable replacements (variadically or an array).
-        * @return {string} return.return Rendered HTML.
+        * @param {string} key Message key.
+        * @param {Array} replacements Variable replacements for $1, $2... $n
+        * @return {jQuery}
         */
-       mw.jqueryMsg.getMessageFunction = function ( options ) {
-               var failableParserFn, format;
-
-               if ( options && options.format !== undefined ) {
-                       format = options.format;
-               } else {
-                       format = parserDefaults.format;
-               }
-
-               return function () {
-                       var failableResult;
-                       if ( !failableParserFn ) {
-                               failableParserFn = getFailableParserFn( options );
-                       }
-                       failableResult = failableParserFn( arguments );
-                       if ( format === 'text' || format === 'escaped' ) {
-                               return failableResult.text();
-                       } else {
-                               return failableResult.html();
-                       }
-               };
-       };
+       parse: function ( key, replacements ) {
+               var ast = this.getAst( key, replacements );
+               return this.emitter.emit( ast, replacements );
+       },
 
        /**
-        * Returns a jQuery plugin which parses the message in the message key, doing replacements optionally, and appends the nodes to
-        * the current selector. Bindings to passed-in jquery elements are preserved. Functions become click handlers for [$1 linktext] links.
-        * e.g.
-        *
-        *        $.fn.msg = mediaWiki.jqueryMsg.getPlugin( options );
-        *        var $userlink = $( '<a>' ).click( function () { alert( "hello!!" ) } );
-        *        $( 'p#headline' ).msg( 'hello-user', $userlink );
-        *
-        * N.B. replacements are variadic arguments or an array in second parameter. In other words:
-        *    somefunction( a, b, c, d )
-        * is equivalent to
-        *    somefunction( a, [b, c, d] )
-        *
-        * We append to 'this', which in a jQuery plugin context will be the selected elements.
+        * Fetch the message string associated with a key, return parsed structure. Memoized.
+        * Note that we pass '⧼' + key + '⧽' back for a missing message here.
         *
-        * @param {Object} options Parser options
-        * @return {Function} Function suitable for assigning to jQuery plugin, such as jQuery#msg
-        * @return {string} return.key Message key.
-        * @return {Array|Mixed} return.replacements Optional variable replacements (variadically or an array).
-        * @return {jQuery} return.return
+        * @param {string} key
+        * @param {Array} replacements Variable replacements for $1, $2... $n
+        * @return {string|Array} string of '⧼key⧽' if message missing, simple string if possible, array of arrays if needs parsing
         */
-       mw.jqueryMsg.getPlugin = function ( options ) {
-               var failableParserFn;
-
-               return function () {
-                       var $target;
-                       if ( !failableParserFn ) {
-                               failableParserFn = getFailableParserFn( options );
+       getAst: function ( key, replacements ) {
+               var wikiText;
+
+               if ( !Object.prototype.hasOwnProperty.call( this.astCache, key ) ) {
+                       wikiText = this.settings.messages.get( key );
+                       if (
+                               mw.config.get( 'wgUserLanguage' ) === 'qqx' &&
+                               ( !wikiText || wikiText === '(' + key + ')' )
+                       ) {
+                               wikiText = '(' + key + '$*)';
+                       } else if ( typeof wikiText !== 'string' ) {
+                               wikiText = '⧼' + key + '⧽';
                        }
-                       $target = this.empty();
-                       appendWithoutParsing( $target, failableParserFn( arguments ) );
-                       return $target;
-               };
-       };
+                       wikiText = mw.internalDoTransformFormatForQqx( wikiText, replacements );
+                       this.astCache[ key ] = this.wikiTextToAst( wikiText );
+               }
+               return this.astCache[ key ];
+       },
 
        /**
-        * The parser itself.
-        * Describes an object, whose primary duty is to .parse() message keys.
+        * Parses the input wikiText into an abstract syntax tree, essentially an s-expression.
         *
-        * @class
-        * @private
-        * @param {Object} options
+        * CAVEAT: This does not parse all wikitext. It could be more efficient, but it's pretty good already.
+        * n.b. We want to move this functionality to the server. Nothing here is required to be on the client.
+        *
+        * @param {string} input Message string wikitext
+        * @throws Error
+        * @return {Mixed} abstract syntax tree
         */
-       mw.jqueryMsg.Parser = function ( options ) {
-               this.settings = $.extend( {}, parserDefaults, options );
-               this.settings.onlyCurlyBraceTransform = ( this.settings.format === 'text' || this.settings.format === 'escaped' );
-               this.astCache = {};
-
-               this.emitter = new mw.jqueryMsg.HtmlEmitter( this.settings.language, this.settings.magic );
-       };
-       // Backwards-compatible alias
-       // @deprecated since 1.31
-       mw.jqueryMsg.parser = mw.jqueryMsg.Parser;
+       wikiTextToAst: function ( input ) {
+               var pos,
+                       regularLiteral, regularLiteralWithoutBar, regularLiteralWithoutSpace, regularLiteralWithSquareBrackets,
+                       doubleQuote, singleQuote, backslash, anyCharacter, asciiAlphabetLiteral,
+                       escapedOrLiteralWithoutSpace, escapedOrLiteralWithoutBar, escapedOrRegularLiteral,
+                       whitespace, dollar, digits, htmlDoubleQuoteAttributeValue, htmlSingleQuoteAttributeValue,
+                       htmlAttributeEquals, openHtmlStartTag, optionalForwardSlash, openHtmlEndTag, closeHtmlTag,
+                       openExtlink, closeExtlink, wikilinkContents, openWikilink, closeWikilink, templateName, pipe, colon,
+                       templateContents, openTemplate, closeTemplate,
+                       nonWhitespaceExpression, paramExpression, expression, curlyBraceTransformExpression, result,
+                       settings = this.settings,
+                       concat = Array.prototype.concat;
+
+               // Indicates current position in input as we parse through it.
+               // Shared among all parsing functions below.
+               pos = 0;
+
+               // =========================================================
+               // parsing combinators - could be a library on its own
+               // =========================================================
 
-       mw.jqueryMsg.Parser.prototype = {
                /**
-                * Where the magic happens.
-                * Parses a message from the key, and swaps in replacements as necessary, wraps in jQuery
-                * If an error is thrown, returns original key, and logs the error
+                * Try parsers until one works, if none work return null
                 *
-                * @param {string} key Message key.
-                * @param {Array} replacements Variable replacements for $1, $2... $n
-                * @return {jQuery}
+                * @private
+                * @param {Function[]} ps
+                * @return {string|null}
                 */
-               parse: function ( key, replacements ) {
-                       var ast = this.getAst( key, replacements );
-                       return this.emitter.emit( ast, replacements );
-               },
+               function choice( ps ) {
+                       return function () {
+                               var i, result;
+                               for ( i = 0; i < ps.length; i++ ) {
+                                       result = ps[ i ]();
+                                       if ( result !== null ) {
+                                               return result;
+                                       }
+                               }
+                               return null;
+                       };
+               }
 
                /**
-                * Fetch the message string associated with a key, return parsed structure. Memoized.
-                * Note that we pass '⧼' + key + '⧽' back for a missing message here.
+                * Try several ps in a row, all must succeed or return null.
+                * This is the only eager one.
                 *
-                * @param {string} key
-                * @param {Array} replacements Variable replacements for $1, $2... $n
-                * @return {string|Array} string of '⧼key⧽' if message missing, simple string if possible, array of arrays if needs parsing
+                * @private
+                * @param {Function[]} ps
+                * @return {string|null}
                 */
-               getAst: function ( key, replacements ) {
-                       var wikiText;
-
-                       if ( !Object.prototype.hasOwnProperty.call( this.astCache, key ) ) {
-                               if ( mw.config.get( 'wgUserLanguage' ) === 'qqx' ) {
-                                       wikiText = '(' + key + '$*)';
-                               } else {
-                                       wikiText = this.settings.messages.get( key );
-                                       if ( typeof wikiText !== 'string' ) {
-                                               wikiText = '⧼' + key + '⧽';
-                                       }
+               function sequence( ps ) {
+                       var i, res,
+                               originalPos = pos,
+                               result = [];
+                       for ( i = 0; i < ps.length; i++ ) {
+                               res = ps[ i ]();
+                               if ( res === null ) {
+                                       pos = originalPos;
+                                       return null;
                                }
-                               wikiText = mw.internalDoTransformFormatForQqx( wikiText, replacements );
-                               this.astCache[ key ] = this.wikiTextToAst( wikiText );
+                               result.push( res );
                        }
-                       return this.astCache[ key ];
-               },
+                       return result;
+               }
 
                /**
-                * Parses the input wikiText into an abstract syntax tree, essentially an s-expression.
-                *
-                * CAVEAT: This does not parse all wikitext. It could be more efficient, but it's pretty good already.
-                * n.b. We want to move this functionality to the server. Nothing here is required to be on the client.
+                * Run the same parser over and over until it fails.
+                * Must succeed a minimum of n times or return null.
                 *
-                * @param {string} input Message string wikitext
-                * @throws Error
-                * @return {Mixed} abstract syntax tree
+                * @private
+                * @param {number} n
+                * @param {Function} p
+                * @return {string|null}
                 */
-               wikiTextToAst: function ( input ) {
-                       var pos,
-                               regularLiteral, regularLiteralWithoutBar, regularLiteralWithoutSpace, regularLiteralWithSquareBrackets,
-                               doubleQuote, singleQuote, backslash, anyCharacter, asciiAlphabetLiteral,
-                               escapedOrLiteralWithoutSpace, escapedOrLiteralWithoutBar, escapedOrRegularLiteral,
-                               whitespace, dollar, digits, htmlDoubleQuoteAttributeValue, htmlSingleQuoteAttributeValue,
-                               htmlAttributeEquals, openHtmlStartTag, optionalForwardSlash, openHtmlEndTag, closeHtmlTag,
-                               openExtlink, closeExtlink, wikilinkContents, openWikilink, closeWikilink, templateName, pipe, colon,
-                               templateContents, openTemplate, closeTemplate,
-                               nonWhitespaceExpression, paramExpression, expression, curlyBraceTransformExpression, result,
-                               settings = this.settings,
-                               concat = Array.prototype.concat;
-
-                       // Indicates current position in input as we parse through it.
-                       // Shared among all parsing functions below.
-                       pos = 0;
-
-                       // =========================================================
-                       // parsing combinators - could be a library on its own
-                       // =========================================================
-
-                       /**
-                        * Try parsers until one works, if none work return null
-                        *
-                        * @private
-                        * @param {Function[]} ps
-                        * @return {string|null}
-                        */
-                       function choice( ps ) {
-                               return function () {
-                                       var i, result;
-                                       for ( i = 0; i < ps.length; i++ ) {
-                                               result = ps[ i ]();
-                                               if ( result !== null ) {
-                                                       return result;
-                                               }
-                                       }
+               function nOrMore( n, p ) {
+                       return function () {
+                               var originalPos = pos,
+                                       result = [],
+                                       parsed = p();
+                               while ( parsed !== null ) {
+                                       result.push( parsed );
+                                       parsed = p();
+                               }
+                               if ( result.length < n ) {
+                                       pos = originalPos;
                                        return null;
-                               };
-                       }
-
-                       /**
-                        * Try several ps in a row, all must succeed or return null.
-                        * This is the only eager one.
-                        *
-                        * @private
-                        * @param {Function[]} ps
-                        * @return {string|null}
-                        */
-                       function sequence( ps ) {
-                               var i, res,
-                                       originalPos = pos,
-                                       result = [];
-                               for ( i = 0; i < ps.length; i++ ) {
-                                       res = ps[ i ]();
-                                       if ( res === null ) {
-                                               pos = originalPos;
-                                               return null;
-                                       }
-                                       result.push( res );
                                }
                                return result;
-                       }
-
-                       /**
-                        * Run the same parser over and over until it fails.
-                        * Must succeed a minimum of n times or return null.
-                        *
-                        * @private
-                        * @param {number} n
-                        * @param {Function} p
-                        * @return {string|null}
-                        */
-                       function nOrMore( n, p ) {
-                               return function () {
-                                       var originalPos = pos,
-                                               result = [],
-                                               parsed = p();
-                                       while ( parsed !== null ) {
-                                               result.push( parsed );
-                                               parsed = p();
-                                       }
-                                       if ( result.length < n ) {
-                                               pos = originalPos;
-                                               return null;
-                                       }
-                                       return result;
-                               };
-                       }
+                       };
+               }
 
-                       /**
-                        * There is a general pattern -- parse a thing, if that worked, apply transform, otherwise return null.
-                        *
-                        * TODO: But using this as a combinator seems to cause problems when combined with #nOrMore().
-                        * May be some scoping issue
-                        *
-                        * @private
-                        * @param {Function} p
-                        * @param {Function} fn
-                        * @return {string|null}
-                        */
-                       function transform( p, fn ) {
-                               return function () {
-                                       var result = p();
-                                       return result === null ? null : fn( result );
-                               };
-                       }
+               /**
+                * There is a general pattern -- parse a thing, if that worked, apply transform, otherwise return null.
+                *
+                * TODO: But using this as a combinator seems to cause problems when combined with #nOrMore().
+                * May be some scoping issue
+                *
+                * @private
+                * @param {Function} p
+                * @param {Function} fn
+                * @return {string|null}
+                */
+               function transform( p, fn ) {
+                       return function () {
+                               var result = p();
+                               return result === null ? null : fn( result );
+                       };
+               }
 
-                       /**
-                        * Just make parsers out of simpler JS builtin types
-                        *
-                        * @private
-                        * @param {string} s
-                        * @return {Function}
-                        * @return {string} return.return
-                        */
-                       function makeStringParser( s ) {
-                               var len = s.length;
-                               return function () {
-                                       var result = null;
-                                       if ( input.substr( pos, len ) === s ) {
-                                               result = s;
-                                               pos += len;
-                                       }
-                                       return result;
-                               };
-                       }
+               /**
+                * Just make parsers out of simpler JS builtin types
+                *
+                * @private
+                * @param {string} s
+                * @return {Function}
+                * @return {string} return.return
+                */
+               function makeStringParser( s ) {
+                       var len = s.length;
+                       return function () {
+                               var result = null;
+                               if ( input.substr( pos, len ) === s ) {
+                                       result = s;
+                                       pos += len;
+                               }
+                               return result;
+                       };
+               }
 
-                       /**
-                        * Makes a regex parser, given a RegExp object.
-                        * The regex being passed in should start with a ^ to anchor it to the start
-                        * of the string.
-                        *
-                        * @private
-                        * @param {RegExp} regex anchored regex
-                        * @return {Function} function to parse input based on the regex
-                        */
-                       function makeRegexParser( regex ) {
-                               return function () {
-                                       var matches = input.slice( pos ).match( regex );
-                                       if ( matches === null ) {
-                                               return null;
-                                       }
-                                       pos += matches[ 0 ].length;
-                                       return matches[ 0 ];
-                               };
-                       }
+               /**
+                * Makes a regex parser, given a RegExp object.
+                * The regex being passed in should start with a ^ to anchor it to the start
+                * of the string.
+                *
+                * @private
+                * @param {RegExp} regex anchored regex
+                * @return {Function} function to parse input based on the regex
+                */
+               function makeRegexParser( regex ) {
+                       return function () {
+                               var matches = input.slice( pos ).match( regex );
+                               if ( matches === null ) {
+                                       return null;
+                               }
+                               pos += matches[ 0 ].length;
+                               return matches[ 0 ];
+                       };
+               }
 
-                       // ===================================================================
-                       // General patterns above this line -- wikitext specific parsers below
-                       // ===================================================================
-
-                       // Parsing functions follow. All parsing functions work like this:
-                       // They don't accept any arguments.
-                       // Instead, they just operate non destructively on the string 'input'
-                       // As they can consume parts of the string, they advance the shared variable pos,
-                       // and return tokens (or whatever else they want to return).
-                       // some things are defined as closures and other things as ordinary functions
-                       // converting everything to a closure makes it a lot harder to debug... errors pop up
-                       // but some debuggers can't tell you exactly where they come from. Also the mutually
-                       // recursive functions seem not to work in all browsers then. (Tested IE6-7, Opera, Safari, FF)
-                       // This may be because, to save code, memoization was removed
-
-                       /* eslint-disable no-useless-escape */
-                       regularLiteral = makeRegexParser( /^[^{}\[\]$<\\]/ );
-                       regularLiteralWithoutBar = makeRegexParser( /^[^{}\[\]$\\|]/ );
-                       regularLiteralWithoutSpace = makeRegexParser( /^[^{}\[\]$\s]/ );
-                       regularLiteralWithSquareBrackets = makeRegexParser( /^[^{}$\\]/ );
-                       /* eslint-enable no-useless-escape */
-
-                       backslash = makeStringParser( '\\' );
-                       doubleQuote = makeStringParser( '"' );
-                       singleQuote = makeStringParser( '\'' );
-                       anyCharacter = makeRegexParser( /^./ );
-
-                       openHtmlStartTag = makeStringParser( '<' );
-                       optionalForwardSlash = makeRegexParser( /^\/?/ );
-                       openHtmlEndTag = makeStringParser( '</' );
-                       htmlAttributeEquals = makeRegexParser( /^\s*=\s*/ );
-                       closeHtmlTag = makeRegexParser( /^\s*>/ );
-
-                       function escapedLiteral() {
-                               var result = sequence( [
-                                       backslash,
-                                       anyCharacter
-                               ] );
-                               return result === null ? null : result[ 1 ];
-                       }
-                       escapedOrLiteralWithoutSpace = choice( [
-                               escapedLiteral,
-                               regularLiteralWithoutSpace
-                       ] );
-                       escapedOrLiteralWithoutBar = choice( [
-                               escapedLiteral,
-                               regularLiteralWithoutBar
-                       ] );
-                       escapedOrRegularLiteral = choice( [
-                               escapedLiteral,
-                               regularLiteral
+               // ===================================================================
+               // General patterns above this line -- wikitext specific parsers below
+               // ===================================================================
+
+               // Parsing functions follow. All parsing functions work like this:
+               // They don't accept any arguments.
+               // Instead, they just operate non destructively on the string 'input'
+               // As they can consume parts of the string, they advance the shared variable pos,
+               // and return tokens (or whatever else they want to return).
+               // some things are defined as closures and other things as ordinary functions
+               // converting everything to a closure makes it a lot harder to debug... errors pop up
+               // but some debuggers can't tell you exactly where they come from. Also the mutually
+               // recursive functions seem not to work in all browsers then. (Tested IE6-7, Opera, Safari, FF)
+               // This may be because, to save code, memoization was removed
+
+               /* eslint-disable no-useless-escape */
+               regularLiteral = makeRegexParser( /^[^{}\[\]$<\\]/ );
+               regularLiteralWithoutBar = makeRegexParser( /^[^{}\[\]$\\|]/ );
+               regularLiteralWithoutSpace = makeRegexParser( /^[^{}\[\]$\s]/ );
+               regularLiteralWithSquareBrackets = makeRegexParser( /^[^{}$\\]/ );
+               /* eslint-enable no-useless-escape */
+
+               backslash = makeStringParser( '\\' );
+               doubleQuote = makeStringParser( '"' );
+               singleQuote = makeStringParser( '\'' );
+               anyCharacter = makeRegexParser( /^./ );
+
+               openHtmlStartTag = makeStringParser( '<' );
+               optionalForwardSlash = makeRegexParser( /^\/?/ );
+               openHtmlEndTag = makeStringParser( '</' );
+               htmlAttributeEquals = makeRegexParser( /^\s*=\s*/ );
+               closeHtmlTag = makeRegexParser( /^\s*>/ );
+
+               function escapedLiteral() {
+                       var result = sequence( [
+                               backslash,
+                               anyCharacter
                        ] );
-                       // Used to define "literals" without spaces, in space-delimited situations
-                       function literalWithoutSpace() {
-                               var result = nOrMore( 1, escapedOrLiteralWithoutSpace )();
-                               return result === null ? null : result.join( '' );
-                       }
-                       // Used to define "literals" within template parameters. The pipe character is the parameter delimeter, so by default
-                       // it is not a literal in the parameter
-                       function literalWithoutBar() {
-                               var result = nOrMore( 1, escapedOrLiteralWithoutBar )();
-                               return result === null ? null : result.join( '' );
-                       }
+                       return result === null ? null : result[ 1 ];
+               }
+               escapedOrLiteralWithoutSpace = choice( [
+                       escapedLiteral,
+                       regularLiteralWithoutSpace
+               ] );
+               escapedOrLiteralWithoutBar = choice( [
+                       escapedLiteral,
+                       regularLiteralWithoutBar
+               ] );
+               escapedOrRegularLiteral = choice( [
+                       escapedLiteral,
+                       regularLiteral
+               ] );
+               // Used to define "literals" without spaces, in space-delimited situations
+               function literalWithoutSpace() {
+                       var result = nOrMore( 1, escapedOrLiteralWithoutSpace )();
+                       return result === null ? null : result.join( '' );
+               }
+               // Used to define "literals" within template parameters. The pipe character is the parameter delimeter, so by default
+               // it is not a literal in the parameter
+               function literalWithoutBar() {
+                       var result = nOrMore( 1, escapedOrLiteralWithoutBar )();
+                       return result === null ? null : result.join( '' );
+               }
 
-                       function literal() {
-                               var result = nOrMore( 1, escapedOrRegularLiteral )();
-                               return result === null ? null : result.join( '' );
-                       }
+               function literal() {
+                       var result = nOrMore( 1, escapedOrRegularLiteral )();
+                       return result === null ? null : result.join( '' );
+               }
 
-                       function curlyBraceTransformExpressionLiteral() {
-                               var result = nOrMore( 1, regularLiteralWithSquareBrackets )();
-                               return result === null ? null : result.join( '' );
-                       }
+               function curlyBraceTransformExpressionLiteral() {
+                       var result = nOrMore( 1, regularLiteralWithSquareBrackets )();
+                       return result === null ? null : result.join( '' );
+               }
 
-                       asciiAlphabetLiteral = makeRegexParser( /^[A-Za-z]+/ );
-                       htmlDoubleQuoteAttributeValue = makeRegexParser( /^[^"]*/ );
-                       htmlSingleQuoteAttributeValue = makeRegexParser( /^[^']*/ );
+               asciiAlphabetLiteral = makeRegexParser( /^[A-Za-z]+/ );
+               htmlDoubleQuoteAttributeValue = makeRegexParser( /^[^"]*/ );
+               htmlSingleQuoteAttributeValue = makeRegexParser( /^[^']*/ );
 
-                       whitespace = makeRegexParser( /^\s+/ );
-                       dollar = makeStringParser( '$' );
-                       digits = makeRegexParser( /^\d+/ );
+               whitespace = makeRegexParser( /^\s+/ );
+               dollar = makeStringParser( '$' );
+               digits = makeRegexParser( /^\d+/ );
 
-                       function replacement() {
-                               var result = sequence( [
-                                       dollar,
-                                       digits
-                               ] );
-                               if ( result === null ) {
-                                       return null;
-                               }
-                               return [ 'REPLACE', parseInt( result[ 1 ], 10 ) - 1 ];
-                       }
-                       openExtlink = makeStringParser( '[' );
-                       closeExtlink = makeStringParser( ']' );
-                       // this extlink MUST have inner contents, e.g. [foo] not allowed; [foo bar] [foo <i>bar</i>], etc. are allowed
-                       function extlink() {
-                               var result, parsedResult, target;
-                               result = null;
-                               parsedResult = sequence( [
-                                       openExtlink,
-                                       nOrMore( 1, nonWhitespaceExpression ),
-                                       whitespace,
-                                       nOrMore( 1, expression ),
-                                       closeExtlink
-                               ] );
-                               if ( parsedResult !== null ) {
-                                       // When the entire link target is a single parameter, we can't use CONCAT, as we allow
-                                       // passing fancy parameters (like a whole jQuery object or a function) to use for the
-                                       // link. Check only if it's a single match, since we can either do CONCAT or not for
-                                       // singles with the same effect.
-                                       target = parsedResult[ 1 ].length === 1 ?
-                                               parsedResult[ 1 ][ 0 ] :
-                                               [ 'CONCAT' ].concat( parsedResult[ 1 ] );
-                                       result = [
-                                               'EXTLINK',
-                                               target,
-                                               [ 'CONCAT' ].concat( parsedResult[ 3 ] )
-                                       ];
-                               }
-                               return result;
-                       }
-                       openWikilink = makeStringParser( '[[' );
-                       closeWikilink = makeStringParser( ']]' );
-                       pipe = makeStringParser( '|' );
-
-                       function template() {
-                               var result = sequence( [
-                                       openTemplate,
-                                       templateContents,
-                                       closeTemplate
-                               ] );
-                               return result === null ? null : result[ 1 ];
+               function replacement() {
+                       var result = sequence( [
+                               dollar,
+                               digits
+                       ] );
+                       if ( result === null ) {
+                               return null;
                        }
-
-                       function pipedWikilink() {
-                               var result = sequence( [
-                                       nOrMore( 1, paramExpression ),
-                                       pipe,
-                                       nOrMore( 1, expression )
-                               ] );
-                               return result === null ? null : [
-                                       [ 'CONCAT' ].concat( result[ 0 ] ),
-                                       [ 'CONCAT' ].concat( result[ 2 ] )
+                       return [ 'REPLACE', parseInt( result[ 1 ], 10 ) - 1 ];
+               }
+               openExtlink = makeStringParser( '[' );
+               closeExtlink = makeStringParser( ']' );
+               // this extlink MUST have inner contents, e.g. [foo] not allowed; [foo bar] [foo <i>bar</i>], etc. are allowed
+               function extlink() {
+                       var result, parsedResult, target;
+                       result = null;
+                       parsedResult = sequence( [
+                               openExtlink,
+                               nOrMore( 1, nonWhitespaceExpression ),
+                               whitespace,
+                               nOrMore( 1, expression ),
+                               closeExtlink
+                       ] );
+                       if ( parsedResult !== null ) {
+                               // When the entire link target is a single parameter, we can't use CONCAT, as we allow
+                               // passing fancy parameters (like a whole jQuery object or a function) to use for the
+                               // link. Check only if it's a single match, since we can either do CONCAT or not for
+                               // singles with the same effect.
+                               target = parsedResult[ 1 ].length === 1 ?
+                                       parsedResult[ 1 ][ 0 ] :
+                                       [ 'CONCAT' ].concat( parsedResult[ 1 ] );
+                               result = [
+                                       'EXTLINK',
+                                       target,
+                                       [ 'CONCAT' ].concat( parsedResult[ 3 ] )
                                ];
                        }
+                       return result;
+               }
+               openWikilink = makeStringParser( '[[' );
+               closeWikilink = makeStringParser( ']]' );
+               pipe = makeStringParser( '|' );
+
+               function template() {
+                       var result = sequence( [
+                               openTemplate,
+                               templateContents,
+                               closeTemplate
+                       ] );
+                       return result === null ? null : result[ 1 ];
+               }
 
-                       function unpipedWikilink() {
-                               var result = sequence( [
-                                       nOrMore( 1, paramExpression )
-                               ] );
-                               return result === null ? null : [
-                                       [ 'CONCAT' ].concat( result[ 0 ] )
-                               ];
-                       }
+               function pipedWikilink() {
+                       var result = sequence( [
+                               nOrMore( 1, paramExpression ),
+                               pipe,
+                               nOrMore( 1, expression )
+                       ] );
+                       return result === null ? null : [
+                               [ 'CONCAT' ].concat( result[ 0 ] ),
+                               [ 'CONCAT' ].concat( result[ 2 ] )
+                       ];
+               }
 
-                       wikilinkContents = choice( [
-                               pipedWikilink,
-                               unpipedWikilink
+               function unpipedWikilink() {
+                       var result = sequence( [
+                               nOrMore( 1, paramExpression )
                        ] );
+                       return result === null ? null : [
+                               [ 'CONCAT' ].concat( result[ 0 ] )
+                       ];
+               }
 
-                       function wikilink() {
-                               var result, parsedResult, parsedLinkContents;
-                               result = null;
+               wikilinkContents = choice( [
+                       pipedWikilink,
+                       unpipedWikilink
+               ] );
 
-                               parsedResult = sequence( [
-                                       openWikilink,
-                                       wikilinkContents,
-                                       closeWikilink
-                               ] );
-                               if ( parsedResult !== null ) {
-                                       parsedLinkContents = parsedResult[ 1 ];
-                                       result = [ 'WIKILINK' ].concat( parsedLinkContents );
-                               }
-                               return result;
-                       }
+               function wikilink() {
+                       var result, parsedResult, parsedLinkContents;
+                       result = null;
 
-                       // TODO: Support data- if appropriate
-                       function doubleQuotedHtmlAttributeValue() {
-                               var parsedResult = sequence( [
-                                       doubleQuote,
-                                       htmlDoubleQuoteAttributeValue,
-                                       doubleQuote
-                               ] );
-                               return parsedResult === null ? null : parsedResult[ 1 ];
+                       parsedResult = sequence( [
+                               openWikilink,
+                               wikilinkContents,
+                               closeWikilink
+                       ] );
+                       if ( parsedResult !== null ) {
+                               parsedLinkContents = parsedResult[ 1 ];
+                               result = [ 'WIKILINK' ].concat( parsedLinkContents );
                        }
+                       return result;
+               }
 
-                       function singleQuotedHtmlAttributeValue() {
-                               var parsedResult = sequence( [
-                                       singleQuote,
-                                       htmlSingleQuoteAttributeValue,
-                                       singleQuote
-                               ] );
-                               return parsedResult === null ? null : parsedResult[ 1 ];
-                       }
+               // TODO: Support data- if appropriate
+               function doubleQuotedHtmlAttributeValue() {
+                       var parsedResult = sequence( [
+                               doubleQuote,
+                               htmlDoubleQuoteAttributeValue,
+                               doubleQuote
+                       ] );
+                       return parsedResult === null ? null : parsedResult[ 1 ];
+               }
 
-                       function htmlAttribute() {
-                               var parsedResult = sequence( [
-                                       whitespace,
-                                       asciiAlphabetLiteral,
-                                       htmlAttributeEquals,
-                                       choice( [
-                                               doubleQuotedHtmlAttributeValue,
-                                               singleQuotedHtmlAttributeValue
-                                       ] )
-                               ] );
-                               return parsedResult === null ? null : [ parsedResult[ 1 ], parsedResult[ 3 ] ];
-                       }
+               function singleQuotedHtmlAttributeValue() {
+                       var parsedResult = sequence( [
+                               singleQuote,
+                               htmlSingleQuoteAttributeValue,
+                               singleQuote
+                       ] );
+                       return parsedResult === null ? null : parsedResult[ 1 ];
+               }
 
-                       /**
-                        * Checks if HTML is allowed
-                        *
-                        * @param {string} startTagName HTML start tag name
-                        * @param {string} endTagName HTML start tag name
-                        * @param {Object} attributes array of consecutive key value pairs,
-                        *  with index 2 * n being a name and 2 * n + 1 the associated value
-                        * @return {boolean} true if this is HTML is allowed, false otherwise
-                        */
-                       function isAllowedHtml( startTagName, endTagName, attributes ) {
-                               var i, len, attributeName;
-
-                               startTagName = startTagName.toLowerCase();
-                               endTagName = endTagName.toLowerCase();
-                               if ( startTagName !== endTagName || settings.allowedHtmlElements.indexOf( startTagName ) === -1 ) {
-                                       return false;
-                               }
+               function htmlAttribute() {
+                       var parsedResult = sequence( [
+                               whitespace,
+                               asciiAlphabetLiteral,
+                               htmlAttributeEquals,
+                               choice( [
+                                       doubleQuotedHtmlAttributeValue,
+                                       singleQuotedHtmlAttributeValue
+                               ] )
+                       ] );
+                       return parsedResult === null ? null : [ parsedResult[ 1 ], parsedResult[ 3 ] ];
+               }
 
-                               for ( i = 0, len = attributes.length; i < len; i += 2 ) {
-                                       attributeName = attributes[ i ];
-                                       if ( settings.allowedHtmlCommonAttributes.indexOf( attributeName ) === -1 &&
-                                               ( settings.allowedHtmlAttributesByElement[ startTagName ] || [] ).indexOf( attributeName ) === -1 ) {
-                                               return false;
-                                       }
-                               }
+               /**
+                * Checks if HTML is allowed
+                *
+                * @param {string} startTagName HTML start tag name
+                * @param {string} endTagName HTML start tag name
+                * @param {Object} attributes array of consecutive key value pairs,
+                *  with index 2 * n being a name and 2 * n + 1 the associated value
+                * @return {boolean} true if this is HTML is allowed, false otherwise
+                */
+               function isAllowedHtml( startTagName, endTagName, attributes ) {
+                       var i, len, attributeName;
 
-                               return true;
+                       startTagName = startTagName.toLowerCase();
+                       endTagName = endTagName.toLowerCase();
+                       if ( startTagName !== endTagName || settings.allowedHtmlElements.indexOf( startTagName ) === -1 ) {
+                               return false;
                        }
 
-                       function htmlAttributes() {
-                               var parsedResult = nOrMore( 0, htmlAttribute )();
-                               // Un-nest attributes array due to structure of jQueryMsg operations (see emit).
-                               return concat.apply( [ 'HTMLATTRIBUTES' ], parsedResult );
+                       for ( i = 0, len = attributes.length; i < len; i += 2 ) {
+                               attributeName = attributes[ i ];
+                               if ( settings.allowedHtmlCommonAttributes.indexOf( attributeName ) === -1 &&
+                                       ( settings.allowedHtmlAttributesByElement[ startTagName ] || [] ).indexOf( attributeName ) === -1 ) {
+                                       return false;
+                               }
                        }
 
-                       // Subset of allowed HTML markup.
-                       // Most elements and many attributes allowed on the server are not supported yet.
-                       function html() {
-                               var parsedOpenTagResult, parsedHtmlContents, parsedCloseTagResult,
-                                       wrappedAttributes, attributes, startTagName, endTagName, startOpenTagPos,
-                                       startCloseTagPos, endOpenTagPos, endCloseTagPos,
-                                       result = null;
-
-                               // Break into three sequence calls.  That should allow accurate reconstruction of the original HTML, and requiring an exact tag name match.
-                               // 1. open through closeHtmlTag
-                               // 2. expression
-                               // 3. openHtmlEnd through close
-                               // This will allow recording the positions to reconstruct if HTML is to be treated as text.
-
-                               startOpenTagPos = pos;
-                               parsedOpenTagResult = sequence( [
-                                       openHtmlStartTag,
-                                       asciiAlphabetLiteral,
-                                       htmlAttributes,
-                                       optionalForwardSlash,
-                                       closeHtmlTag
-                               ] );
+                       return true;
+               }
 
-                               if ( parsedOpenTagResult === null ) {
-                                       return null;
-                               }
+               function htmlAttributes() {
+                       var parsedResult = nOrMore( 0, htmlAttribute )();
+                       // Un-nest attributes array due to structure of jQueryMsg operations (see emit).
+                       return concat.apply( [ 'HTMLATTRIBUTES' ], parsedResult );
+               }
 
-                               endOpenTagPos = pos;
-                               startTagName = parsedOpenTagResult[ 1 ];
+               // Subset of allowed HTML markup.
+               // Most elements and many attributes allowed on the server are not supported yet.
+               function html() {
+                       var parsedOpenTagResult, parsedHtmlContents, parsedCloseTagResult,
+                               wrappedAttributes, attributes, startTagName, endTagName, startOpenTagPos,
+                               startCloseTagPos, endOpenTagPos, endCloseTagPos,
+                               result = null;
 
-                               parsedHtmlContents = nOrMore( 0, expression )();
+                       // Break into three sequence calls.  That should allow accurate reconstruction of the original HTML, and requiring an exact tag name match.
+                       // 1. open through closeHtmlTag
+                       // 2. expression
+                       // 3. openHtmlEnd through close
+                       // This will allow recording the positions to reconstruct if HTML is to be treated as text.
+
+                       startOpenTagPos = pos;
+                       parsedOpenTagResult = sequence( [
+                               openHtmlStartTag,
+                               asciiAlphabetLiteral,
+                               htmlAttributes,
+                               optionalForwardSlash,
+                               closeHtmlTag
+                       ] );
 
-                               startCloseTagPos = pos;
-                               parsedCloseTagResult = sequence( [
-                                       openHtmlEndTag,
-                                       asciiAlphabetLiteral,
-                                       closeHtmlTag
-                               ] );
+                       if ( parsedOpenTagResult === null ) {
+                               return null;
+                       }
 
-                               if ( parsedCloseTagResult === null ) {
-                                       // Closing tag failed.  Return the start tag and contents.
-                                       return [ 'CONCAT', input.slice( startOpenTagPos, endOpenTagPos ) ]
-                                               .concat( parsedHtmlContents );
-                               }
+                       endOpenTagPos = pos;
+                       startTagName = parsedOpenTagResult[ 1 ];
 
-                               endCloseTagPos = pos;
-                               endTagName = parsedCloseTagResult[ 1 ];
-                               wrappedAttributes = parsedOpenTagResult[ 2 ];
-                               attributes = wrappedAttributes.slice( 1 );
-                               if ( isAllowedHtml( startTagName, endTagName, attributes ) ) {
-                                       result = [ 'HTMLELEMENT', startTagName, wrappedAttributes ]
-                                               .concat( parsedHtmlContents );
-                               } else {
-                                       // HTML is not allowed, so contents will remain how
-                                       // it was, while HTML markup at this level will be
-                                       // treated as text
-                                       // E.g. assuming script tags are not allowed:
-                                       //
-                                       // <script>[[Foo|bar]]</script>
-                                       //
-                                       // results in '&lt;script&gt;' and '&lt;/script&gt;'
-                                       // (not treated as an HTML tag), surrounding a fully
-                                       // parsed HTML link.
-                                       //
-                                       // Concatenate everything from the tag, flattening the contents.
-                                       result = [ 'CONCAT', input.slice( startOpenTagPos, endOpenTagPos ) ]
-                                               .concat( parsedHtmlContents, input.slice( startCloseTagPos, endCloseTagPos ) );
-                               }
+                       parsedHtmlContents = nOrMore( 0, expression )();
 
-                               return result;
+                       startCloseTagPos = pos;
+                       parsedCloseTagResult = sequence( [
+                               openHtmlEndTag,
+                               asciiAlphabetLiteral,
+                               closeHtmlTag
+                       ] );
+
+                       if ( parsedCloseTagResult === null ) {
+                               // Closing tag failed.  Return the start tag and contents.
+                               return [ 'CONCAT', input.slice( startOpenTagPos, endOpenTagPos ) ]
+                                       .concat( parsedHtmlContents );
                        }
 
-                       // <nowiki>...</nowiki> tag. The tags are stripped and the contents are returned unparsed.
-                       function nowiki() {
-                               var parsedResult, plainText,
-                                       result = null;
+                       endCloseTagPos = pos;
+                       endTagName = parsedCloseTagResult[ 1 ];
+                       wrappedAttributes = parsedOpenTagResult[ 2 ];
+                       attributes = wrappedAttributes.slice( 1 );
+                       if ( isAllowedHtml( startTagName, endTagName, attributes ) ) {
+                               result = [ 'HTMLELEMENT', startTagName, wrappedAttributes ]
+                                       .concat( parsedHtmlContents );
+                       } else {
+                               // HTML is not allowed, so contents will remain how
+                               // it was, while HTML markup at this level will be
+                               // treated as text
+                               // E.g. assuming script tags are not allowed:
+                               //
+                               // <script>[[Foo|bar]]</script>
+                               //
+                               // results in '&lt;script&gt;' and '&lt;/script&gt;'
+                               // (not treated as an HTML tag), surrounding a fully
+                               // parsed HTML link.
+                               //
+                               // Concatenate everything from the tag, flattening the contents.
+                               result = [ 'CONCAT', input.slice( startOpenTagPos, endOpenTagPos ) ]
+                                       .concat( parsedHtmlContents, input.slice( startCloseTagPos, endCloseTagPos ) );
+                       }
 
-                               parsedResult = sequence( [
-                                       makeStringParser( '<nowiki>' ),
-                                       // We use a greedy non-backtracking parser, so we must ensure here that we don't take too much
-                                       makeRegexParser( /^.*?(?=<\/nowiki>)/ ),
-                                       makeStringParser( '</nowiki>' )
-                               ] );
-                               if ( parsedResult !== null ) {
-                                       plainText = parsedResult[ 1 ];
-                                       result = [ 'CONCAT' ].concat( plainText );
-                               }
+                       return result;
+               }
 
-                               return result;
+               // <nowiki>...</nowiki> tag. The tags are stripped and the contents are returned unparsed.
+               function nowiki() {
+                       var parsedResult, plainText,
+                               result = null;
+
+                       parsedResult = sequence( [
+                               makeStringParser( '<nowiki>' ),
+                               // We use a greedy non-backtracking parser, so we must ensure here that we don't take too much
+                               makeRegexParser( /^.*?(?=<\/nowiki>)/ ),
+                               makeStringParser( '</nowiki>' )
+                       ] );
+                       if ( parsedResult !== null ) {
+                               plainText = parsedResult[ 1 ];
+                               result = [ 'CONCAT' ].concat( plainText );
                        }
 
-                       templateName = transform(
-                               // see $wgLegalTitleChars
-                               // not allowing : due to the need to catch "PLURAL:$1"
-                               makeRegexParser( /^[ !"$&'()*,./0-9;=?@A-Z^_`a-z~\x80-\xFF+-]+/ ),
-                               function ( result ) { return result.toString(); }
-                       );
-                       function templateParam() {
-                               var expr, result;
-                               result = sequence( [
-                                       pipe,
-                                       nOrMore( 0, paramExpression )
-                               ] );
-                               if ( result === null ) {
-                                       return null;
-                               }
-                               expr = result[ 1 ];
-                               // use a CONCAT operator if there are multiple nodes, otherwise return the first node, raw.
-                               return expr.length > 1 ? [ 'CONCAT' ].concat( expr ) : expr[ 0 ];
+                       return result;
+               }
+
+               templateName = transform(
+                       // see $wgLegalTitleChars
+                       // not allowing : due to the need to catch "PLURAL:$1"
+                       makeRegexParser( /^[ !"$&'()*,./0-9;=?@A-Z^_`a-z~\x80-\xFF+-]+/ ),
+                       function ( result ) { return result.toString(); }
+               );
+               function templateParam() {
+                       var expr, result;
+                       result = sequence( [
+                               pipe,
+                               nOrMore( 0, paramExpression )
+                       ] );
+                       if ( result === null ) {
+                               return null;
                        }
+                       expr = result[ 1 ];
+                       // use a CONCAT operator if there are multiple nodes, otherwise return the first node, raw.
+                       return expr.length > 1 ? [ 'CONCAT' ].concat( expr ) : expr[ 0 ];
+               }
 
-                       function templateWithReplacement() {
-                               var result = sequence( [
-                                       templateName,
-                                       colon,
-                                       replacement
+               function templateWithReplacement() {
+                       var result = sequence( [
+                               templateName,
+                               colon,
+                               replacement
+                       ] );
+                       return result === null ? null : [ result[ 0 ], result[ 2 ] ];
+               }
+               function templateWithOutReplacement() {
+                       var result = sequence( [
+                               templateName,
+                               colon,
+                               paramExpression
+                       ] );
+                       return result === null ? null : [ result[ 0 ], result[ 2 ] ];
+               }
+               function templateWithOutFirstParameter() {
+                       var result = sequence( [
+                               templateName,
+                               colon
+                       ] );
+                       return result === null ? null : [ result[ 0 ], '' ];
+               }
+               colon = makeStringParser( ':' );
+               templateContents = choice( [
+                       function () {
+                               var res = sequence( [
+                                       // templates can have placeholders for dynamic replacement eg: {{PLURAL:$1|one car|$1 cars}}
+                                       // or no placeholders eg: {{GRAMMAR:genitive|{{SITENAME}}}
+                                       choice( [ templateWithReplacement, templateWithOutReplacement, templateWithOutFirstParameter ] ),
+                                       nOrMore( 0, templateParam )
                                ] );
-                               return result === null ? null : [ result[ 0 ], result[ 2 ] ];
-                       }
-                       function templateWithOutReplacement() {
-                               var result = sequence( [
+                               return res === null ? null : res[ 0 ].concat( res[ 1 ] );
+                       },
+                       function () {
+                               var res = sequence( [
                                        templateName,
-                                       colon,
-                                       paramExpression
+                                       nOrMore( 0, templateParam )
                                ] );
-                               return result === null ? null : [ result[ 0 ], result[ 2 ] ];
+                               if ( res === null ) {
+                                       return null;
+                               }
+                               return [ res[ 0 ] ].concat( res[ 1 ] );
                        }
-                       function templateWithOutFirstParameter() {
-                               var result = sequence( [
-                                       templateName,
-                                       colon
-                               ] );
-                               return result === null ? null : [ result[ 0 ], '' ];
+               ] );
+               openTemplate = makeStringParser( '{{' );
+               closeTemplate = makeStringParser( '}}' );
+               nonWhitespaceExpression = choice( [
+                       template,
+                       wikilink,
+                       extlink,
+                       replacement,
+                       literalWithoutSpace
+               ] );
+               paramExpression = choice( [
+                       template,
+                       wikilink,
+                       extlink,
+                       replacement,
+                       literalWithoutBar
+               ] );
+
+               expression = choice( [
+                       template,
+                       wikilink,
+                       extlink,
+                       replacement,
+                       nowiki,
+                       html,
+                       literal
+               ] );
+
+               // Used when only {{-transformation is wanted, for 'text'
+               // or 'escaped' formats
+               curlyBraceTransformExpression = choice( [
+                       template,
+                       replacement,
+                       curlyBraceTransformExpressionLiteral
+               ] );
+
+               /**
+                * Starts the parse
+                *
+                * @param {Function} rootExpression Root parse function
+                * @return {Array|null}
+                */
+               function start( rootExpression ) {
+                       var result = nOrMore( 0, rootExpression )();
+                       if ( result === null ) {
+                               return null;
                        }
-                       colon = makeStringParser( ':' );
-                       templateContents = choice( [
-                               function () {
-                                       var res = sequence( [
-                                               // templates can have placeholders for dynamic replacement eg: {{PLURAL:$1|one car|$1 cars}}
-                                               // or no placeholders eg: {{GRAMMAR:genitive|{{SITENAME}}}
-                                               choice( [ templateWithReplacement, templateWithOutReplacement, templateWithOutFirstParameter ] ),
-                                               nOrMore( 0, templateParam )
-                                       ] );
-                                       return res === null ? null : res[ 0 ].concat( res[ 1 ] );
-                               },
-                               function () {
-                                       var res = sequence( [
-                                               templateName,
-                                               nOrMore( 0, templateParam )
-                                       ] );
-                                       if ( res === null ) {
-                                               return null;
-                                       }
-                                       return [ res[ 0 ] ].concat( res[ 1 ] );
-                               }
-                       ] );
-                       openTemplate = makeStringParser( '{{' );
-                       closeTemplate = makeStringParser( '}}' );
-                       nonWhitespaceExpression = choice( [
-                               template,
-                               wikilink,
-                               extlink,
-                               replacement,
-                               literalWithoutSpace
-                       ] );
-                       paramExpression = choice( [
-                               template,
-                               wikilink,
-                               extlink,
-                               replacement,
-                               literalWithoutBar
-                       ] );
+                       return [ 'CONCAT' ].concat( result );
+               }
+               // everything above this point is supposed to be stateless/static, but
+               // I am deferring the work of turning it into prototypes & objects. It's quite fast enough
+               // finally let's do some actual work...
 
-                       expression = choice( [
-                               template,
-                               wikilink,
-                               extlink,
-                               replacement,
-                               nowiki,
-                               html,
-                               literal
-                       ] );
+               result = start( this.settings.onlyCurlyBraceTransform ? curlyBraceTransformExpression : expression );
 
-                       // Used when only {{-transformation is wanted, for 'text'
-                       // or 'escaped' formats
-                       curlyBraceTransformExpression = choice( [
-                               template,
-                               replacement,
-                               curlyBraceTransformExpressionLiteral
-                       ] );
+               /*
+                * For success, the p must have gotten to the end of the input
+                * and returned a non-null.
+                * n.b. This is part of language infrastructure, so we do not throw an internationalizable message.
+                */
+               if ( result === null || pos !== input.length ) {
+                       throw new Error( 'Parse error at position ' + pos.toString() + ' in input: ' + input );
+               }
+               return result;
+       }
 
-                       /**
-                        * Starts the parse
-                        *
-                        * @param {Function} rootExpression Root parse function
-                        * @return {Array|null}
-                        */
-                       function start( rootExpression ) {
-                               var result = nOrMore( 0, rootExpression )();
-                               if ( result === null ) {
-                                       return null;
+};
+
+/**
+ * Class that primarily exists to emit HTML from parser ASTs.
+ *
+ * @private
+ * @class
+ * @param {Object} language
+ * @param {Object} magic
+ */
+mw.jqueryMsg.HtmlEmitter = function ( language, magic ) {
+       var jmsg = this;
+       this.language = language;
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( magic, function ( key, val ) {
+               jmsg[ key.toLowerCase() ] = function () {
+                       return val;
+               };
+       } );
+
+       /**
+        * (We put this method definition here, and not in prototype, to make sure it's not overwritten by any magic.)
+        * Walk entire node structure, applying replacements and template functions when appropriate
+        *
+        * @param {Mixed} node Abstract syntax tree (top node or subnode)
+        * @param {Array} replacements for $1, $2, ... $n
+        * @return {Mixed} single-string node or array of nodes suitable for jQuery appending
+        */
+       this.emit = function ( node, replacements ) {
+               var ret, subnodes, operation,
+                       jmsg = this;
+               switch ( typeof node ) {
+                       case 'string':
+                       case 'number':
+                               ret = node;
+                               break;
+                       // typeof returns object for arrays
+                       case 'object':
+                               // node is an array of nodes
+                               // eslint-disable-next-line no-jquery/no-map-util
+                               subnodes = $.map( node.slice( 1 ), function ( n ) {
+                                       return jmsg.emit( n, replacements );
+                               } );
+                               operation = node[ 0 ].toLowerCase();
+                               if ( typeof jmsg[ operation ] === 'function' ) {
+                                       ret = jmsg[ operation ]( subnodes, replacements );
+                               } else {
+                                       throw new Error( 'Unknown operation "' + operation + '"' );
                                }
-                               return [ 'CONCAT' ].concat( result );
-                       }
-                       // everything above this point is supposed to be stateless/static, but
-                       // I am deferring the work of turning it into prototypes & objects. It's quite fast enough
-                       // finally let's do some actual work...
-
-                       result = start( this.settings.onlyCurlyBraceTransform ? curlyBraceTransformExpression : expression );
-
-                       /*
-                        * For success, the p must have gotten to the end of the input
-                        * and returned a non-null.
-                        * n.b. This is part of language infrastructure, so we do not throw an internationalizable message.
-                        */
-                       if ( result === null || pos !== input.length ) {
-                               throw new Error( 'Parse error at position ' + pos.toString() + ' in input: ' + input );
-                       }
-                       return result;
+                               break;
+                       case 'undefined':
+                               // Parsing the empty string (as an entire expression, or as a paramExpression in a template) results in undefined
+                               // Perhaps a more clever parser can detect this, and return the empty string? Or is that useful information?
+                               // The logical thing is probably to return the empty string here when we encounter undefined.
+                               ret = '';
+                               break;
+                       default:
+                               throw new Error( 'Unexpected type in AST: ' + typeof node );
                }
-
+               return ret;
        };
-
+};
+
+// For everything in input that follows double-open-curly braces, there should be an equivalent parser
+// function. For instance {{PLURAL ... }} will be processed by 'plural'.
+// If you have 'magic words' then configure the parser to have them upon creation.
+//
+// An emitter method takes the parent node, the array of subnodes and the array of replacements (the values that $1, $2... should translate to).
+// Note: all such functions must be pure, with the exception of referring to other pure functions via this.language (convertPlural and so on)
+mw.jqueryMsg.HtmlEmitter.prototype = {
        /**
-        * Class that primarily exists to emit HTML from parser ASTs.
+        * Parsing has been applied depth-first we can assume that all nodes here are single nodes
+        * Must return a single node to parents -- a jQuery with synthetic span
+        * However, unwrap any other synthetic spans in our children and pass them upwards
         *
-        * @private
-        * @class
-        * @param {Object} language
-        * @param {Object} magic
+        * @param {Mixed[]} nodes Some single nodes, some arrays of nodes
+        * @return {jQuery}
         */
-       mw.jqueryMsg.HtmlEmitter = function ( language, magic ) {
-               var jmsg = this;
-               this.language = language;
+       concat: function ( nodes ) {
+               var $span = $( '<span>' ).addClass( 'mediaWiki_htmlEmitter' );
                // eslint-disable-next-line no-jquery/no-each-util
-               $.each( magic, function ( key, val ) {
-                       jmsg[ key.toLowerCase() ] = function () {
-                               return val;
-                       };
+               $.each( nodes, function ( i, node ) {
+                       // Let jQuery append nodes, arrays of nodes and jQuery objects
+                       // other things (strings, numbers, ..) are appended as text nodes (not as HTML strings)
+                       appendWithoutParsing( $span, node );
                } );
+               return $span;
+       },
 
-               /**
-                * (We put this method definition here, and not in prototype, to make sure it's not overwritten by any magic.)
-                * Walk entire node structure, applying replacements and template functions when appropriate
-                *
-                * @param {Mixed} node Abstract syntax tree (top node or subnode)
-                * @param {Array} replacements for $1, $2, ... $n
-                * @return {Mixed} single-string node or array of nodes suitable for jQuery appending
-                */
-               this.emit = function ( node, replacements ) {
-                       var ret, subnodes, operation,
-                               jmsg = this;
-                       switch ( typeof node ) {
-                               case 'string':
-                               case 'number':
-                                       ret = node;
-                                       break;
-                               // typeof returns object for arrays
-                               case 'object':
-                                       // node is an array of nodes
-                                       // eslint-disable-next-line no-jquery/no-map-util
-                                       subnodes = $.map( node.slice( 1 ), function ( n ) {
-                                               return jmsg.emit( n, replacements );
-                                       } );
-                                       operation = node[ 0 ].toLowerCase();
-                                       if ( typeof jmsg[ operation ] === 'function' ) {
-                                               ret = jmsg[ operation ]( subnodes, replacements );
-                                       } else {
-                                               throw new Error( 'Unknown operation "' + operation + '"' );
-                                       }
-                                       break;
-                               case 'undefined':
-                                       // Parsing the empty string (as an entire expression, or as a paramExpression in a template) results in undefined
-                                       // Perhaps a more clever parser can detect this, and return the empty string? Or is that useful information?
-                                       // The logical thing is probably to return the empty string here when we encounter undefined.
-                                       ret = '';
-                                       break;
-                               default:
-                                       throw new Error( 'Unexpected type in AST: ' + typeof node );
-                       }
-                       return ret;
-               };
-       };
-
-       // For everything in input that follows double-open-curly braces, there should be an equivalent parser
-       // function. For instance {{PLURAL ... }} will be processed by 'plural'.
-       // If you have 'magic words' then configure the parser to have them upon creation.
-       //
-       // An emitter method takes the parent node, the array of subnodes and the array of replacements (the values that $1, $2... should translate to).
-       // Note: all such functions must be pure, with the exception of referring to other pure functions via this.language (convertPlural and so on)
-       mw.jqueryMsg.HtmlEmitter.prototype = {
-               /**
-                * Parsing has been applied depth-first we can assume that all nodes here are single nodes
-                * Must return a single node to parents -- a jQuery with synthetic span
-                * However, unwrap any other synthetic spans in our children and pass them upwards
-                *
-                * @param {Mixed[]} nodes Some single nodes, some arrays of nodes
-                * @return {jQuery}
-                */
-               concat: function ( nodes ) {
-                       var $span = $( '<span>' ).addClass( 'mediaWiki_htmlEmitter' );
-                       // eslint-disable-next-line no-jquery/no-each-util
-                       $.each( nodes, function ( i, node ) {
-                               // Let jQuery append nodes, arrays of nodes and jQuery objects
-                               // other things (strings, numbers, ..) are appended as text nodes (not as HTML strings)
-                               appendWithoutParsing( $span, node );
-                       } );
-                       return $span;
-               },
+       /**
+        * Return escaped replacement of correct index, or string if unavailable.
+        * Note that we expect the parsed parameter to be zero-based. i.e. $1 should have become [ 0 ].
+        * if the specified parameter is not found return the same string
+        * (e.g. "$99" -> parameter 98 -> not found -> return "$99" )
+        *
+        * TODO: Throw error if nodes.length > 1 ?
+        *
+        * @param {Array} nodes List of one element, integer, n >= 0
+        * @param {Array} replacements List of at least n strings
+        * @return {string|jQuery} replacement
+        */
+       replace: function ( nodes, replacements ) {
+               var index = parseInt( nodes[ 0 ], 10 );
 
-               /**
-                * Return escaped replacement of correct index, or string if unavailable.
-                * Note that we expect the parsed parameter to be zero-based. i.e. $1 should have become [ 0 ].
-                * if the specified parameter is not found return the same string
-                * (e.g. "$99" -> parameter 98 -> not found -> return "$99" )
-                *
-                * TODO: Throw error if nodes.length > 1 ?
-                *
-                * @param {Array} nodes List of one element, integer, n >= 0
-                * @param {Array} replacements List of at least n strings
-                * @return {string|jQuery} replacement
-                */
-               replace: function ( nodes, replacements ) {
-                       var index = parseInt( nodes[ 0 ], 10 );
+               if ( index < replacements.length ) {
+                       return replacements[ index ];
+               } else {
+                       // index not found, fallback to displaying variable
+                       return '$' + ( index + 1 );
+               }
+       },
 
-                       if ( index < replacements.length ) {
-                               return replacements[ index ];
-                       } else {
-                               // index not found, fallback to displaying variable
-                               return '$' + ( index + 1 );
-                       }
-               },
+       /**
+        * Transform wiki-link
+        *
+        * TODO:
+        * It only handles basic cases, either no pipe, or a pipe with an explicit
+        * anchor.
+        *
+        * It does not attempt to handle features like the pipe trick.
+        * However, the pipe trick should usually not be present in wikitext retrieved
+        * from the server, since the replacement is done at save time.
+        * It may, though, if the wikitext appears in extension-controlled content.
+        *
+        * @param {string[]} nodes
+        * @return {jQuery}
+        */
+       wikilink: function ( nodes ) {
+               var page, anchor, url, $el;
+
+               page = textify( nodes[ 0 ] );
+               // Strip leading ':', which is used to suppress special behavior in wikitext links,
+               // e.g. [[:Category:Foo]] or [[:File:Foo.jpg]]
+               if ( page.charAt( 0 ) === ':' ) {
+                       page = page.slice( 1 );
+               }
+               url = mw.util.getUrl( page );
 
-               /**
-                * Transform wiki-link
-                *
-                * TODO:
-                * It only handles basic cases, either no pipe, or a pipe with an explicit
-                * anchor.
-                *
-                * It does not attempt to handle features like the pipe trick.
-                * However, the pipe trick should usually not be present in wikitext retrieved
-                * from the server, since the replacement is done at save time.
-                * It may, though, if the wikitext appears in extension-controlled content.
-                *
-                * @param {string[]} nodes
-                * @return {jQuery}
-                */
-               wikilink: function ( nodes ) {
-                       var page, anchor, url, $el;
-
-                       page = textify( nodes[ 0 ] );
-                       // Strip leading ':', which is used to suppress special behavior in wikitext links,
-                       // e.g. [[:Category:Foo]] or [[:File:Foo.jpg]]
-                       if ( page.charAt( 0 ) === ':' ) {
-                               page = page.slice( 1 );
-                       }
-                       url = mw.util.getUrl( page );
+               if ( nodes.length === 1 ) {
+                       // [[Some Page]] or [[Namespace:Some Page]]
+                       anchor = page;
+               } else {
+                       // [[Some Page|anchor text]] or [[Namespace:Some Page|anchor]]
+                       anchor = nodes[ 1 ];
+               }
 
-                       if ( nodes.length === 1 ) {
-                               // [[Some Page]] or [[Namespace:Some Page]]
-                               anchor = page;
-                       } else {
-                               // [[Some Page|anchor text]] or [[Namespace:Some Page|anchor]]
-                               anchor = nodes[ 1 ];
-                       }
+               $el = $( '<a>' ).attr( {
+                       title: page,
+                       href: url
+               } );
+               return appendWithoutParsing( $el, anchor );
+       },
 
-                       $el = $( '<a>' ).attr( {
-                               title: page,
-                               href: url
-                       } );
-                       return appendWithoutParsing( $el, anchor );
-               },
+       /**
+        * Converts array of HTML element key value pairs to object
+        *
+        * @param {Array} nodes Array of consecutive key value pairs, with index 2 * n being a
+        *  name and 2 * n + 1 the associated value
+        * @return {Object} Object mapping attribute name to attribute value
+        */
+       htmlattributes: function ( nodes ) {
+               var i, len, mapping = {};
+               for ( i = 0, len = nodes.length; i < len; i += 2 ) {
+                       mapping[ nodes[ i ] ] = decodePrimaryHtmlEntities( nodes[ i + 1 ] );
+               }
+               return mapping;
+       },
 
-               /**
-                * Converts array of HTML element key value pairs to object
-                *
-                * @param {Array} nodes Array of consecutive key value pairs, with index 2 * n being a
-                *  name and 2 * n + 1 the associated value
-                * @return {Object} Object mapping attribute name to attribute value
-                */
-               htmlattributes: function ( nodes ) {
-                       var i, len, mapping = {};
-                       for ( i = 0, len = nodes.length; i < len; i += 2 ) {
-                               mapping[ nodes[ i ] ] = decodePrimaryHtmlEntities( nodes[ i + 1 ] );
-                       }
-                       return mapping;
-               },
+       /**
+        * Handles an (already-validated) HTML element.
+        *
+        * @param {Array} nodes Nodes to process when creating element
+        * @return {jQuery}
+        */
+       htmlelement: function ( nodes ) {
+               var tagName, attributes, contents, $element;
 
-               /**
-                * Handles an (already-validated) HTML element.
-                *
-                * @param {Array} nodes Nodes to process when creating element
-                * @return {jQuery}
-                */
-               htmlelement: function ( nodes ) {
-                       var tagName, attributes, contents, $element;
-
-                       tagName = nodes.shift();
-                       attributes = nodes.shift();
-                       contents = nodes;
-                       $element = $( document.createElement( tagName ) ).attr( attributes );
-                       return appendWithoutParsing( $element, contents );
-               },
+               tagName = nodes.shift();
+               attributes = nodes.shift();
+               contents = nodes;
+               $element = $( document.createElement( tagName ) ).attr( attributes );
+               return appendWithoutParsing( $element, contents );
+       },
 
-               /**
-                * Transform parsed structure into external link.
-                *
-                * The "href" can be:
-                * - a jQuery object, treat it as "enclosing" the link text.
-                * - a function, treat it as the click handler.
-                * - a string, or our HtmlEmitter jQuery object, treat it as a URI after stringifying.
-                *
-                * TODO: throw an error if nodes.length > 2 ?
-                *
-                * @param {Array} nodes List of two elements, {jQuery|Function|String} and {string}
-                * @return {jQuery}
-                */
-               extlink: function ( nodes ) {
-                       var $el,
-                               arg = nodes[ 0 ],
-                               contents = nodes[ 1 ];
-                       if ( arg instanceof $ && !arg.hasClass( 'mediaWiki_htmlEmitter' ) ) {
-                               $el = arg;
+       /**
+        * Transform parsed structure into external link.
+        *
+        * The "href" can be:
+        * - a jQuery object, treat it as "enclosing" the link text.
+        * - a function, treat it as the click handler.
+        * - a string, or our HtmlEmitter jQuery object, treat it as a URI after stringifying.
+        *
+        * TODO: throw an error if nodes.length > 2 ?
+        *
+        * @param {Array} nodes List of two elements, {jQuery|Function|String} and {string}
+        * @return {jQuery}
+        */
+       extlink: function ( nodes ) {
+               var $el,
+                       arg = nodes[ 0 ],
+                       contents = nodes[ 1 ];
+               if ( arg instanceof $ && !arg.hasClass( 'mediaWiki_htmlEmitter' ) ) {
+                       $el = arg;
+               } else {
+                       $el = $( '<a>' );
+                       if ( typeof arg === 'function' ) {
+                               $el.attr( {
+                                       role: 'button',
+                                       tabindex: 0
+                               } ).on( 'click keypress', function ( e ) {
+                                       if (
+                                               e.type === 'click' ||
+                                               e.type === 'keypress' && e.which === 13
+                                       ) {
+                                               arg.call( this, e );
+                                       }
+                               } );
                        } else {
-                               $el = $( '<a>' );
-                               if ( typeof arg === 'function' ) {
-                                       $el.attr( {
-                                               role: 'button',
-                                               tabindex: 0
-                                       } ).on( 'click keypress', function ( e ) {
-                                               if (
-                                                       e.type === 'click' ||
-                                                       e.type === 'keypress' && e.which === 13
-                                               ) {
-                                                       arg.call( this, e );
-                                               }
-                                       } );
-                               } else {
-                                       $el.attr( 'href', textify( arg ) );
-                               }
+                               $el.attr( 'href', textify( arg ) );
                        }
-                       return appendWithoutParsing( $el.empty(), contents );
-               },
-
-               /**
-                * Transform parsed structure into pluralization
-                * n.b. The first node may be a non-integer (for instance, a string representing an Arabic number).
-                * So convert it back with the current language's convertNumber.
-                *
-                * @param {Array} nodes List of nodes, [ {string|number}, {string}, {string} ... ]
-                * @return {string|jQuery} selected pluralized form according to current language
-                */
-               plural: function ( nodes ) {
-                       var forms, firstChild, firstChildText, explicitPluralFormNumber, formIndex, form, count,
-                               explicitPluralForms = {};
+               }
+               return appendWithoutParsing( $el.empty(), contents );
+       },
 
-                       count = parseFloat( this.language.convertNumber( textify( nodes[ 0 ] ), true ) );
-                       forms = nodes.slice( 1 );
-                       for ( formIndex = 0; formIndex < forms.length; formIndex++ ) {
-                               form = forms[ formIndex ];
-
-                               if ( form instanceof $ && form.hasClass( 'mediaWiki_htmlEmitter' ) ) {
-                                       // This is a nested node, may be an explicit plural form like 5=[$2 linktext]
-                                       firstChild = form.contents().get( 0 );
-                                       if ( firstChild && firstChild.nodeType === Node.TEXT_NODE ) {
-                                               firstChildText = firstChild.textContent;
-                                               if ( /^\d+=/.test( firstChildText ) ) {
-                                                       explicitPluralFormNumber = parseInt( firstChildText.split( /=/ )[ 0 ], 10 );
-                                                       // Use the digit part as key and rest of first text node and
-                                                       // rest of child nodes as value.
-                                                       firstChild.textContent = firstChildText.slice( firstChildText.indexOf( '=' ) + 1 );
-                                                       explicitPluralForms[ explicitPluralFormNumber ] = form;
-                                                       forms[ formIndex ] = undefined;
-                                               }
+       /**
+        * Transform parsed structure into pluralization
+        * n.b. The first node may be a non-integer (for instance, a string representing an Arabic number).
+        * So convert it back with the current language's convertNumber.
+        *
+        * @param {Array} nodes List of nodes, [ {string|number}, {string}, {string} ... ]
+        * @return {string|jQuery} selected pluralized form according to current language
+        */
+       plural: function ( nodes ) {
+               var forms, firstChild, firstChildText, explicitPluralFormNumber, formIndex, form, count,
+                       explicitPluralForms = {};
+
+               count = parseFloat( this.language.convertNumber( textify( nodes[ 0 ] ), true ) );
+               forms = nodes.slice( 1 );
+               for ( formIndex = 0; formIndex < forms.length; formIndex++ ) {
+                       form = forms[ formIndex ];
+
+                       if ( form instanceof $ && form.hasClass( 'mediaWiki_htmlEmitter' ) ) {
+                               // This is a nested node, may be an explicit plural form like 5=[$2 linktext]
+                               firstChild = form.contents().get( 0 );
+                               if ( firstChild && firstChild.nodeType === Node.TEXT_NODE ) {
+                                       firstChildText = firstChild.textContent;
+                                       if ( /^\d+=/.test( firstChildText ) ) {
+                                               explicitPluralFormNumber = parseInt( firstChildText.split( /=/ )[ 0 ], 10 );
+                                               // Use the digit part as key and rest of first text node and
+                                               // rest of child nodes as value.
+                                               firstChild.textContent = firstChildText.slice( firstChildText.indexOf( '=' ) + 1 );
+                                               explicitPluralForms[ explicitPluralFormNumber ] = form;
+                                               forms[ formIndex ] = undefined;
                                        }
-                               } else if ( /^\d+=/.test( form ) ) {
-                                       // Simple explicit plural forms like 12=a dozen
-                                       explicitPluralFormNumber = parseInt( form.split( /=/ )[ 0 ], 10 );
-                                       explicitPluralForms[ explicitPluralFormNumber ] = form.slice( form.indexOf( '=' ) + 1 );
-                                       forms[ formIndex ] = undefined;
                                }
+                       } else if ( /^\d+=/.test( form ) ) {
+                               // Simple explicit plural forms like 12=a dozen
+                               explicitPluralFormNumber = parseInt( form.split( /=/ )[ 0 ], 10 );
+                               explicitPluralForms[ explicitPluralFormNumber ] = form.slice( form.indexOf( '=' ) + 1 );
+                               forms[ formIndex ] = undefined;
                        }
+               }
 
-                       // Remove explicit plural forms from the forms. They were set undefined in the above loop.
-                       // eslint-disable-next-line no-jquery/no-map-util
-                       forms = $.map( forms, function ( form ) {
-                               return form;
-                       } );
-
-                       return this.language.convertPlural( count, forms, explicitPluralForms );
-               },
-
-               /**
-                * Transform parsed structure according to gender.
-                *
-                * Usage: {{gender:[ mw.user object | '' | 'male' | 'female' | 'unknown' ] | masculine form | feminine form | neutral form}}.
-                *
-                * The first node must be one of:
-                * - the mw.user object (or a compatible one)
-                * - an empty string - indicating the current user, same effect as passing the mw.user object
-                * - a gender string ('male', 'female' or 'unknown')
-                *
-                * @param {Array} nodes List of nodes, [ {string|mw.user}, {string}, {string}, {string} ]
-                * @return {string|jQuery} Selected gender form according to current language
-                */
-               gender: function ( nodes ) {
-                       var gender,
-                               maybeUser = nodes[ 0 ],
-                               forms = nodes.slice( 1 );
-
-                       if ( maybeUser === '' ) {
-                               maybeUser = mw.user;
-                       }
-
-                       // If we are passed a mw.user-like object, check their gender.
-                       // Otherwise, assume the gender string itself was passed .
-                       if ( maybeUser && maybeUser.options instanceof mw.Map ) {
-                               gender = maybeUser.options.get( 'gender' );
-                       } else {
-                               gender = textify( maybeUser );
-                       }
-
-                       return this.language.gender( gender, forms );
-               },
+               // Remove explicit plural forms from the forms. They were set undefined in the above loop.
+               // eslint-disable-next-line no-jquery/no-map-util
+               forms = $.map( forms, function ( form ) {
+                       return form;
+               } );
 
-               /**
-                * Transform parsed structure into grammar conversion.
-                * Invoked by putting `{{grammar:form|word}}` in a message
-                *
-                * @param {Array} nodes List of nodes [{Grammar case eg: genitive}, {string word}]
-                * @return {string|jQuery} selected grammatical form according to current language
-                */
-               grammar: function ( nodes ) {
-                       var form = nodes[ 0 ],
-                               word = nodes[ 1 ];
-                       // These could be jQuery objects (passed as message parameters),
-                       // in which case we can't transform them (like rawParams() in PHP).
-                       if ( typeof form === 'string' && typeof word === 'string' ) {
-                               return this.language.convertGrammar( word, form );
-                       }
-                       return word;
-               },
+               return this.language.convertPlural( count, forms, explicitPluralForms );
+       },
 
-               /**
-                * Tranform parsed structure into a int: (interface language) message include
-                * Invoked by putting `{{int:othermessage}}` into a message
-                *
-                * TODO Syntax in the included message is not parsed, this seems like a bug?
-                *
-                * @param {Array} nodes List of nodes
-                * @return {string} Other message
-                */
-               int: function ( nodes ) {
-                       var msg = textify( nodes[ 0 ] );
-                       return mw.jqueryMsg.getMessageFunction()( msg.charAt( 0 ).toLowerCase() + msg.slice( 1 ) );
-               },
+       /**
+        * Transform parsed structure according to gender.
+        *
+        * Usage: {{gender:[ mw.user object | '' | 'male' | 'female' | 'unknown' ] | masculine form | feminine form | neutral form}}.
+        *
+        * The first node must be one of:
+        * - the mw.user object (or a compatible one)
+        * - an empty string - indicating the current user, same effect as passing the mw.user object
+        * - a gender string ('male', 'female' or 'unknown')
+        *
+        * @param {Array} nodes List of nodes, [ {string|mw.user}, {string}, {string}, {string} ]
+        * @return {string|jQuery} Selected gender form according to current language
+        */
+       gender: function ( nodes ) {
+               var gender,
+                       maybeUser = nodes[ 0 ],
+                       forms = nodes.slice( 1 );
 
-               /**
-                * Get localized namespace name from canonical name or namespace number.
-                * Invoked by putting `{{ns:foo}}` into a message
-                *
-                * @param {Array} nodes List of nodes
-                * @return {string} Localized namespace name
-                */
-               ns: function ( nodes ) {
-                       var ns = textify( nodes[ 0 ] ).trim();
-                       if ( !/^\d+$/.test( ns ) ) {
-                               ns = mw.config.get( 'wgNamespaceIds' )[ ns.replace( / /g, '_' ).toLowerCase() ];
-                       }
-                       ns = mw.config.get( 'wgFormattedNamespaces' )[ ns ];
-                       return ns || '';
-               },
+               if ( maybeUser === '' ) {
+                       maybeUser = mw.user;
+               }
 
-               /**
-                * Takes an unformatted number (arab, no group separators and . as decimal separator)
-                * and outputs it in the localized digit script and formatted with decimal
-                * separator, according to the current language.
-                *
-                * @param {Array} nodes List of nodes
-                * @return {number|string|jQuery} Formatted number
-                */
-               formatnum: function ( nodes ) {
-                       var isInteger = !!nodes[ 1 ] && nodes[ 1 ] === 'R',
-                               number = nodes[ 0 ];
-
-                       // These could be jQuery objects (passed as message parameters),
-                       // in which case we can't transform them (like rawParams() in PHP).
-                       if ( typeof number === 'string' || typeof number === 'number' ) {
-                               return this.language.convertNumber( number, isInteger );
-                       }
-                       return number;
-               },
+               // If we are passed a mw.user-like object, check their gender.
+               // Otherwise, assume the gender string itself was passed .
+               if ( maybeUser && maybeUser.options instanceof mw.Map ) {
+                       gender = maybeUser.options.get( 'gender' );
+               } else {
+                       gender = textify( maybeUser );
+               }
 
-               /**
-                * Lowercase text
-                *
-                * @param {Array} nodes List of nodes
-                * @return {string} The given text, all in lowercase
-                */
-               lc: function ( nodes ) {
-                       return textify( nodes[ 0 ] ).toLowerCase();
-               },
+               return this.language.gender( gender, forms );
+       },
 
-               /**
-                * Uppercase text
-                *
-                * @param {Array} nodes List of nodes
-                * @return {string} The given text, all in uppercase
-                */
-               uc: function ( nodes ) {
-                       return textify( nodes[ 0 ] ).toUpperCase();
-               },
+       /**
+        * Transform parsed structure into grammar conversion.
+        * Invoked by putting `{{grammar:form|word}}` in a message
+        *
+        * @param {Array} nodes List of nodes [{Grammar case eg: genitive}, {string word}]
+        * @return {string|jQuery} selected grammatical form according to current language
+        */
+       grammar: function ( nodes ) {
+               var form = nodes[ 0 ],
+                       word = nodes[ 1 ];
+               // These could be jQuery objects (passed as message parameters),
+               // in which case we can't transform them (like rawParams() in PHP).
+               if ( typeof form === 'string' && typeof word === 'string' ) {
+                       return this.language.convertGrammar( word, form );
+               }
+               return word;
+       },
 
-               /**
-                * Lowercase first letter of input, leaving the rest unchanged
-                *
-                * @param {Array} nodes List of nodes
-                * @return {string} The given text, with the first character in lowercase
-                */
-               lcfirst: function ( nodes ) {
-                       var text = textify( nodes[ 0 ] );
-                       return text.charAt( 0 ).toLowerCase() + text.slice( 1 );
-               },
+       /**
+        * Tranform parsed structure into a int: (interface language) message include
+        * Invoked by putting `{{int:othermessage}}` into a message
+        *
+        * TODO Syntax in the included message is not parsed, this seems like a bug?
+        *
+        * @param {Array} nodes List of nodes
+        * @return {string} Other message
+        */
+       int: function ( nodes ) {
+               var msg = textify( nodes[ 0 ] );
+               return mw.jqueryMsg.getMessageFunction()( msg.charAt( 0 ).toLowerCase() + msg.slice( 1 ) );
+       },
 
-               /**
-                * Uppercase first letter of input, leaving the rest unchanged
-                *
-                * @param {Array} nodes List of nodes
-                * @return {string} The given text, with the first character in uppercase
-                */
-               ucfirst: function ( nodes ) {
-                       var text = textify( nodes[ 0 ] );
-                       return text.charAt( 0 ).toUpperCase() + text.slice( 1 );
+       /**
+        * Get localized namespace name from canonical name or namespace number.
+        * Invoked by putting `{{ns:foo}}` into a message
+        *
+        * @param {Array} nodes List of nodes
+        * @return {string} Localized namespace name
+        */
+       ns: function ( nodes ) {
+               var ns = textify( nodes[ 0 ] ).trim();
+               if ( !/^\d+$/.test( ns ) ) {
+                       ns = mw.config.get( 'wgNamespaceIds' )[ ns.replace( / /g, '_' ).toLowerCase() ];
                }
-       };
+               ns = mw.config.get( 'wgFormattedNamespaces' )[ ns ];
+               return ns || '';
+       },
 
        /**
-        * @method
-        * @member jQuery
-        * @see mw.jqueryMsg#getPlugin
+        * Takes an unformatted number (arab, no group separators and . as decimal separator)
+        * and outputs it in the localized digit script and formatted with decimal
+        * separator, according to the current language.
+        *
+        * @param {Array} nodes List of nodes
+        * @return {number|string|jQuery} Formatted number
         */
-       $.fn.msg = mw.jqueryMsg.getPlugin();
-
-       // Replace the default message parser with jqueryMsg
-       oldParser = mw.Message.prototype.parser;
-       mw.Message.prototype.parser = function () {
-               // Fall back to mw.msg's simple parser where possible
-               if (
-                       // Plain text output always uses the simple parser
-                       this.format === 'plain' ||
-                       (
-                               // jqueryMsg parser is needed for messages containing wikitext
-                               !/\{\{|[<>[&]/.test( this.map.get( this.key ) ) &&
-                               // jqueryMsg parser is needed when jQuery objects or DOM nodes are passed in as parameters
-                               !this.parameters.some( function ( param ) {
-                                       return param instanceof $ || ( param && param.nodeType !== undefined );
-                               } )
-                       )
-               ) {
-                       return oldParser.apply( this );
+       formatnum: function ( nodes ) {
+               var isInteger = !!nodes[ 1 ] && nodes[ 1 ] === 'R',
+                       number = nodes[ 0 ];
+
+               // These could be jQuery objects (passed as message parameters),
+               // in which case we can't transform them (like rawParams() in PHP).
+               if ( typeof number === 'string' || typeof number === 'number' ) {
+                       return this.language.convertNumber( number, isInteger );
                }
+               return number;
+       },
 
-               if ( !Object.prototype.hasOwnProperty.call( this.map, this.format ) ) {
-                       this.map[ this.format ] = mw.jqueryMsg.getMessageFunction( {
-                               messages: this.map,
-                               // For format 'escaped', escaping part is handled by mediawiki.js
-                               format: this.format
-                       } );
-               }
-               return this.map[ this.format ]( this.key, this.parameters );
-       };
+       /**
+        * Lowercase text
+        *
+        * @param {Array} nodes List of nodes
+        * @return {string} The given text, all in lowercase
+        */
+       lc: function ( nodes ) {
+               return textify( nodes[ 0 ] ).toLowerCase();
+       },
 
        /**
-        * Parse the message to DOM nodes, rather than HTML string like #parse.
+        * Uppercase text
         *
-        * This method is only available when jqueryMsg is loaded.
+        * @param {Array} nodes List of nodes
+        * @return {string} The given text, all in uppercase
+        */
+       uc: function ( nodes ) {
+               return textify( nodes[ 0 ] ).toUpperCase();
+       },
+
+       /**
+        * Lowercase first letter of input, leaving the rest unchanged
         *
-        * @since 1.27
-        * @method parseDom
-        * @member mw.Message
-        * @return {jQuery}
+        * @param {Array} nodes List of nodes
+        * @return {string} The given text, with the first character in lowercase
         */
-       mw.Message.prototype.parseDom = ( function () {
-               var $wrapper = $( '<div>' );
-               return function () {
-                       return $wrapper.msg( this.key, this.parameters ).contents().detach();
-               };
-       }() );
+       lcfirst: function ( nodes ) {
+               var text = textify( nodes[ 0 ] );
+               return text.charAt( 0 ).toLowerCase() + text.slice( 1 );
+       },
+
+       /**
+        * Uppercase first letter of input, leaving the rest unchanged
+        *
+        * @param {Array} nodes List of nodes
+        * @return {string} The given text, with the first character in uppercase
+        */
+       ucfirst: function ( nodes ) {
+               var text = textify( nodes[ 0 ] );
+               return text.charAt( 0 ).toUpperCase() + text.slice( 1 );
+       }
+};
+
+/**
+ * @method
+ * @member jQuery
+ * @see mw.jqueryMsg#getPlugin
+ */
+$.fn.msg = mw.jqueryMsg.getPlugin();
+
+// Replace the default message parser with jqueryMsg
+oldParser = mw.Message.prototype.parser;
+mw.Message.prototype.parser = function () {
+       // Fall back to mw.msg's simple parser where possible
+       if (
+               // Plain text output always uses the simple parser
+               this.format === 'plain' ||
+               (
+                       // jqueryMsg parser is needed for messages containing wikitext
+                       !/\{\{|[<>[&]/.test( this.map.get( this.key ) ) &&
+                       // jqueryMsg parser is needed when jQuery objects or DOM nodes are passed in as parameters
+                       !this.parameters.some( function ( param ) {
+                               return param instanceof $ || ( param && param.nodeType !== undefined );
+                       } )
+               )
+       ) {
+               return oldParser.apply( this );
+       }
 
+       if ( !Object.prototype.hasOwnProperty.call( this.map, this.format ) ) {
+               this.map[ this.format ] = mw.jqueryMsg.getMessageFunction( {
+                       messages: this.map,
+                       // For format 'escaped', escaping part is handled by mediawiki.js
+                       format: this.format
+               } );
+       }
+       return this.map[ this.format ]( this.key, this.parameters );
+};
+
+/**
+ * Parse the message to DOM nodes, rather than HTML string like #parse.
+ *
+ * This method is only available when jqueryMsg is loaded.
+ *
+ * @since 1.27
+ * @method parseDom
+ * @member mw.Message
+ * @return {jQuery}
+ */
+mw.Message.prototype.parseDom = ( function () {
+       var $wrapper = $( '<div>' );
+       return function () {
+               return $wrapper.msg( this.key, this.parameters ).contents().detach();
+       };
 }() );
index c21b254..e58e677 100644 (file)
@@ -6,6 +6,8 @@
  * Copyright Alexander Limi
  */
 
+/* stylelint-disable selector-class-pattern */
+
 /**
  * Hide all the elements irrelevant for printing
  * Skins however can and should override.
index caaebad..4d67cae 100644 (file)
@@ -4,6 +4,8 @@
  * CologneBlue, the old pre-Monobook skins
  */
 
+/* stylelint-disable selector-class-pattern */
+
 /* For clarity, explicitly state some recommendations from
  * https://www.w3.org/TR/CSS21/sample.html to make sure the editsection links scale right
  */
@@ -280,21 +282,6 @@ span.comment {
        color: #c00;
 }
 
-.editExternally {
-       border: 1px solid #808080;
-       background: #fff;
-       padding: 3px;
-       margin-top: 0.5em;
-       float: left;
-       font-size: small;
-       text-align: center;
-}
-
-.editExternallyHelp {
-       font-style: italic;
-       color: #808080;
-}
-
 li span.deleted {
        text-decoration: line-through;
        color: #888;
index 1d0e335..6988576 100644 (file)
 ( function () {
-       var ProtectionForm,
-               config = require( './config.json' ),
+       var config = require( './config.json' ),
                reasonCodePointLimit = mw.config.get( 'wgCommentCodePointLimit' ),
                reasonByteLimit = mw.config.get( 'wgCommentByteLimit' );
 
-       ProtectionForm = window.ProtectionForm = {
-               /**
-                * Set up the protection chaining interface (i.e. "unlock move permissions" checkbox)
-                * on the protection form
-                *
-                * @return {boolean}
-                */
-               init: function () {
-                       var $cell = $( '<td>' ),
-                               $row = $( '<tr>' ).append( $cell );
-
-                       if ( !$( '#mwProtectSet' ).length ) {
+       /**
+        * Get a list of all protection selectors on the page
+        *
+        * @return {jQuery}
+        */
+       function getLevelSelectors() {
+               return $( 'select[id ^= mwProtect-level-]' );
+       }
+
+       /**
+        * Get a list of all expiry inputs on the page
+        *
+        * @return {jQuery}
+        */
+       function getExpiryInputs() {
+               return $( 'input[id ^= mwProtect-][id $= -expires]' );
+       }
+
+       /**
+        * Get a list of all expiry selector lists on the page
+        *
+        * @return {jQuery}
+        */
+       function getExpirySelectors() {
+               return $( 'select[id ^= mwProtectExpirySelection-]' );
+       }
+
+       /**
+        * Enable/disable protection selectors and expiry inputs
+        *
+        * @param {boolean} val Enable?
+        */
+       function toggleUnchainedInputs( val ) {
+               var setDisabled = function () {
+                       this.disabled = !val;
+               };
+               getLevelSelectors().slice( 1 ).each( setDisabled );
+               getExpiryInputs().slice( 1 ).each( setDisabled );
+               getExpirySelectors().slice( 1 ).each( setDisabled );
+       }
+
+       /**
+        * Checks if a certain protection level is cascadeable.
+        *
+        * @param {string} level
+        * @return {boolean}
+        */
+       function isCascadeableLevel( level ) {
+               return config.CascadingRestrictionLevels.indexOf( level ) !== -1;
+       }
+
+       /**
+        * Sets the disabled attribute on the cascade checkbox depending on the current selected levels
+        */
+       function updateCascadeCheckbox() {
+               getLevelSelectors().each( function () {
+                       if ( !isCascadeableLevel( $( this ).val() ) ) {
+                               $( '#mwProtect-cascade' ).prop( { checked: false, disabled: true } );
                                return false;
+                       } else {
+                               $( '#mwProtect-cascade' ).prop( 'disabled', false );
                        }
+               } );
+       }
+
+       /**
+        * Returns true if the named attribute in all objects in the given array are matching
+        *
+        * @param {Object[]} objects
+        * @param {string} attrName
+        * @return {boolean}
+        */
+       function matchAttribute( objects, attrName ) {
+               // eslint-disable-next-line no-jquery/no-map-util
+               return $.map( objects, function ( object ) {
+                       return object[ attrName ];
+               } ).filter( function ( item, index, a ) {
+                       return index === a.indexOf( item );
+               } ).length === 1;
+       }
+
+       /**
+        * Are all actions protected at the same level, with the same expiry time?
+        *
+        * @return {boolean}
+        */
+       function areAllTypesMatching() {
+               return matchAttribute( getLevelSelectors(), 'selectedIndex' ) &&
+                       matchAttribute( getExpirySelectors(), 'selectedIndex' ) &&
+                       matchAttribute( getExpiryInputs(), 'value' );
+       }
+
+       /**
+        * Is protection chaining off?
+        *
+        * @return {boolean}
+        */
+       function isUnchained() {
+               var element = document.getElementById( 'mwProtectUnchained' );
+               return element ?
+                       element.checked :
+                       true; // No control, so we need to let the user set both levels
+       }
+
+       /**
+        * Find the highest protection level in any selector
+        *
+        * @return {number}
+        */
+       function getMaxLevel() {
+               return Math.max.apply( Math, getLevelSelectors().map( function () {
+                       return this.selectedIndex;
+               } ) );
+       }
+
+       /**
+        * Protect all actions at the specified level
+        *
+        * @param {number} index Protection level
+        */
+       function setAllSelectors( index ) {
+               getLevelSelectors().prop( 'selectedIndex', index );
+       }
+
+       /**
+        * When protection levels are locked together, update the rest
+        * when one action's level changes
+        *
+        * @param {Event} event Level selector that changed
+        */
+       function updateLevels( event ) {
+               if ( !isUnchained() ) {
+                       setAllSelectors( event.target.selectedIndex );
+               }
+               updateCascadeCheckbox();
+       }
+
+       /**
+        * When protection levels are locked together, update the
+        * expiries when one changes
+        *
+        * @param {Event} event Expiry input that changed
+        */
+       function updateExpiry( event ) {
+               if ( !isUnchained() ) {
+                       getExpiryInputs().val( event.target.value );
+               }
+               if ( isUnchained() ) {
+                       $( '#' + event.target.id.replace( /^mwProtect-(\w+)-expires$/, 'mwProtectExpirySelection-$1' ) ).val( 'othertime' );
+               } else {
+                       getExpirySelectors().val( 'othertime' );
+               }
+       }
+
+       /**
+        * When protection levels are locked together, update the
+        * expiry lists when one changes and clear the custom inputs
+        *
+        * @param {Event} event Expiry selector that changed
+        */
+       function updateExpiryList( event ) {
+               if ( !isUnchained() ) {
+                       getExpirySelectors().val( event.target.value );
+                       getExpiryInputs().val( '' );
+               }
+       }
+
+       /**
+        * Update chain status and enable/disable various bits of the UI
+        * when the user changes the "unlock move permissions" checkbox
+        */
+       function onChainClick() {
+               toggleUnchainedInputs( isUnchained() );
+               if ( !isUnchained() ) {
+                       setAllSelectors( getMaxLevel() );
+               }
+               updateCascadeCheckbox();
+       }
+
+       /**
+        * Set up the protection chaining interface (i.e. "unlock move permissions" checkbox)
+        * on the protection form
+        */
+       function init() {
+               var $cell = $( '<td>' ),
+                       $row = $( '<tr>' ).append( $cell );
+
+               if ( !$( '#mwProtectSet' ).length ) {
+                       return;
+               }
 
-                       $( 'form#mw-Protect-Form' ).on( 'submit', this.toggleUnchainedInputs.bind( ProtectionForm, true ) );
-                       this.getExpirySelectors().each( function () {
-                               $( this ).on( 'change', ProtectionForm.updateExpiryList.bind( ProtectionForm, this ) );
-                       } );
-                       this.getExpiryInputs().each( function () {
-                               $( this ).on( 'keyup change', ProtectionForm.updateExpiry.bind( ProtectionForm, this ) );
-                       } );
-                       this.getLevelSelectors().each( function () {
-                               $( this ).on( 'change', ProtectionForm.updateLevels.bind( ProtectionForm, this ) );
-                       } );
-
-                       $( '#mwProtectSet > tbody > tr:first' ).after( $row );
-
-                       // If there is only one protection type, there is nothing to chain
-                       if ( $( '[id ^= mw-protect-table-]' ).length > 1 ) {
-                               $cell.append(
-                                       $( '<input>' )
-                                               .attr( { id: 'mwProtectUnchained', type: 'checkbox' } )
-                                               .on( 'click', this.onChainClick.bind( this ) )
-                                               .prop( 'checked', !this.areAllTypesMatching() ),
-                                       document.createTextNode( ' ' ),
-                                       $( '<label>' )
-                                               .attr( 'for', 'mwProtectUnchained' )
-                                               .text( mw.msg( 'protect-unchain-permissions' ) )
-                               );
-
-                               this.toggleUnchainedInputs( !this.areAllTypesMatching() );
-                       }
-
-                       // Arbitrary 75 to leave some space for the autogenerated null edit's summary
-                       if ( reasonCodePointLimit ) {
-                               $( '#mwProtect-reason' ).codePointLimit( reasonCodePointLimit - 75 );
-                       } else if ( reasonByteLimit ) {
-                               $( '#mwProtect-reason' ).byteLimit( reasonByteLimit - 75 );
-                       }
+               $( 'form#mw-Protect-Form' ).on( 'submit', toggleUnchainedInputs.bind( this, true ) );
+               getExpirySelectors().on( 'change', updateExpiryList );
+               getExpiryInputs().on( 'input change', updateExpiry );
+               getLevelSelectors().on( 'change', updateLevels );
+
+               $( '#mwProtectSet > tbody > tr:first' ).after( $row );
+
+               // If there is only one protection type, there is nothing to chain
+               if ( $( '[id ^= mw-protect-table-]' ).length > 1 ) {
+                       $cell.append(
+                               $( '<input>' )
+                                       .attr( { id: 'mwProtectUnchained', type: 'checkbox' } )
+                                       .on( 'click', onChainClick )
+                                       .prop( 'checked', !areAllTypesMatching() ),
+                               document.createTextNode( ' ' ),
+                               $( '<label>' )
+                                       .attr( 'for', 'mwProtectUnchained' )
+                                       .text( mw.msg( 'protect-unchain-permissions' ) )
+                       );
+
+                       toggleUnchainedInputs( !areAllTypesMatching() );
+               }
 
-                       this.updateCascadeCheckbox();
-                       return true;
-               },
-
-               /**
-                * Sets the disabled attribute on the cascade checkbox depending on the current selected levels
-                */
-               updateCascadeCheckbox: function () {
-                       this.getLevelSelectors().each( function () {
-                               if ( !ProtectionForm.isCascadeableLevel( $( this ).val() ) ) {
-                                       $( '#mwProtect-cascade' ).prop( { checked: false, disabled: true } );
-                                       return false;
-                               } else {
-                                       $( '#mwProtect-cascade' ).prop( 'disabled', false );
-                               }
-                       } );
-               },
-
-               /**
-                * Checks if a certain protection level is cascadeable.
-                *
-                * @param {string} level
-                * @return {boolean}
-                */
-               isCascadeableLevel: function ( level ) {
-                       return config.CascadingRestrictionLevels.indexOf( level ) !== -1;
-               },
-
-               /**
-                * When protection levels are locked together, update the rest
-                * when one action's level changes
-                *
-                * @param {Element} source Level selector that changed
-                */
-               updateLevels: function ( source ) {
-                       if ( !this.isUnchained() ) {
-                               this.setAllSelectors( source.selectedIndex );
-                       }
-                       this.updateCascadeCheckbox();
-               },
-
-               /**
-                * When protection levels are locked together, update the
-                * expiries when one changes
-                *
-                * @param {Element} source expiry input that changed
-                */
-
-               updateExpiry: function ( source ) {
-                       if ( !this.isUnchained() ) {
-                               this.getExpiryInputs().each( function () {
-                                       this.value = source.value;
-                               } );
-                       }
-                       if ( this.isUnchained() ) {
-                               $( '#' + source.id.replace( /^mwProtect-(\w+)-expires$/, 'mwProtectExpirySelection-$1' ) ).val( 'othertime' );
-                       } else {
-                               this.getExpirySelectors().each( function () {
-                                       this.value = 'othertime';
-                               } );
-                       }
-               },
-
-               /**
-                * When protection levels are locked together, update the
-                * expiry lists when one changes and clear the custom inputs
-                *
-                * @param {Element} source Expiry selector that changed
-                */
-               updateExpiryList: function ( source ) {
-                       if ( !this.isUnchained() ) {
-                               this.getExpirySelectors().each( function () {
-                                       this.value = source.value;
-                               } );
-                               this.getExpiryInputs().each( function () {
-                                       this.value = '';
-                               } );
-                       }
-               },
-
-               /**
-                * Update chain status and enable/disable various bits of the UI
-                * when the user changes the "unlock move permissions" checkbox
-                */
-               onChainClick: function () {
-                       this.toggleUnchainedInputs( this.isUnchained() );
-                       if ( !this.isUnchained() ) {
-                               this.setAllSelectors( this.getMaxLevel() );
-                       }
-                       this.updateCascadeCheckbox();
-               },
-
-               /**
-                * Returns true if the named attribute in all objects in the given array are matching
-                *
-                * @param {Object[]} objects
-                * @param {string} attrName
-                * @return {boolean}
-                */
-               matchAttribute: function ( objects, attrName ) {
-                       // eslint-disable-next-line no-jquery/no-map-util
-                       return $.map( objects, function ( object ) {
-                               return object[ attrName ];
-                       } ).filter( function ( item, index, a ) {
-                               return index === a.indexOf( item );
-                       } ).length === 1;
-               },
-
-               /**
-                * Are all actions protected at the same level, with the same expiry time?
-                *
-                * @return {boolean}
-                */
-               areAllTypesMatching: function () {
-                       return this.matchAttribute( this.getLevelSelectors(), 'selectedIndex' ) &&
-                               this.matchAttribute( this.getExpirySelectors(), 'selectedIndex' ) &&
-                               this.matchAttribute( this.getExpiryInputs(), 'value' );
-               },
-
-               /**
-                * Is protection chaining off?
-                *
-                * @return {boolean}
-                */
-               isUnchained: function () {
-                       var element = document.getElementById( 'mwProtectUnchained' );
-                       return element ?
-                               element.checked :
-                               true; // No control, so we need to let the user set both levels
-               },
-
-               /**
-                * Find the highest protection level in any selector
-                *
-                * @return {number}
-                */
-               getMaxLevel: function () {
-                       return Math.max.apply( Math, this.getLevelSelectors().map( function () {
-                               return this.selectedIndex;
-                       } ) );
-               },
-
-               /**
-                * Protect all actions at the specified level
-                *
-                * @param {number} index Protection level
-                */
-               setAllSelectors: function ( index ) {
-                       this.getLevelSelectors().each( function () {
-                               this.selectedIndex = index;
-                       } );
-               },
-
-               /**
-                * Get a list of all protection selectors on the page
-                *
-                * @return {jQuery}
-                */
-               getLevelSelectors: function () {
-                       return $( 'select[id ^= mwProtect-level-]' );
-               },
-
-               /**
-                * Get a list of all expiry inputs on the page
-                *
-                * @return {jQuery}
-                */
-               getExpiryInputs: function () {
-                       return $( 'input[id ^= mwProtect-][id $= -expires]' );
-               },
-
-               /**
-                * Get a list of all expiry selector lists on the page
-                *
-                * @return {jQuery}
-                */
-               getExpirySelectors: function () {
-                       return $( 'select[id ^= mwProtectExpirySelection-]' );
-               },
-
-               /**
-                * Enable/disable protection selectors and expiry inputs
-                *
-                * @param {boolean} val Enable?
-                */
-               toggleUnchainedInputs: function ( val ) {
-                       var setDisabled = function () {
-                               this.disabled = !val;
-                       };
-                       this.getLevelSelectors().slice( 1 ).each( setDisabled );
-                       this.getExpiryInputs().slice( 1 ).each( setDisabled );
-                       this.getExpirySelectors().slice( 1 ).each( setDisabled );
+               // Arbitrary 75 to leave some space for the autogenerated null edit's summary
+               if ( reasonCodePointLimit ) {
+                       $( '#mwProtect-reason' ).codePointLimit( reasonCodePointLimit - 75 );
+               } else if ( reasonByteLimit ) {
+                       $( '#mwProtect-reason' ).byteLimit( reasonByteLimit - 75 );
                }
-       };
 
-       $( ProtectionForm.init.bind( ProtectionForm ) );
+               updateCascadeCheckbox();
+       }
+
+       $( init );
 
 }() );
index 5f20cf9..bebc172 100644 (file)
@@ -9,6 +9,8 @@
  * blocking CSS common to all pages.
  */
 
+/* stylelint-disable selector-class-pattern */
+
 /* GENERAL CLASSES FOR DIRECTIONALITY SUPPORT */
 
 /**
@@ -462,7 +464,7 @@ a.new {
 }
 
 .mw-datatable th {
-       background-color: #ddf;
+       background-color: #eaeeff;
 }
 
 .mw-datatable td {
@@ -596,13 +598,11 @@ ol:lang( kk-arab ) li,
 ol:lang( lrc ) li,
 ol:lang( luz ) li,
 ol:lang( mzn ) li {
-       list-style-type: -moz-persian;
        list-style-type: persian;
 }
 
 ol:lang( ckb ) li,
 ol:lang( sdh ) li {
-       list-style-type: -moz-arabic-indic;
        list-style-type: arabic-indic;
 }
 
@@ -610,18 +610,15 @@ ol:lang( hi ) li,
 ol:lang( mai ) li,
 ol:lang( mr ) li,
 ol:lang( ne ) li {
-       list-style-type: -moz-devanagari;
        list-style-type: devanagari;
 }
 
 ol:lang( as ) li,
 ol:lang( bn ) li {
-       list-style-type: -moz-bengali;
        list-style-type: bengali;
 }
 
 ol:lang( or ) li {
-       list-style-type: -moz-oriya;
        list-style-type: oriya;
 }
 
index fe5647f..4684ea2 100644 (file)
        background-image: e( '/* @embed */' ) url( @url );
 }
 
-// Deprecated in MW 1.27
-.background-size( @width, @height ) {
-       // Vendor prefix is added to support Android 2
-       -webkit-background-size: @width @height;
-       background-size: @width @height;
-}
-
 .vertical-gradient( @startColor: gray, @endColor: white, @startPos: 0, @endPos: 100% ) {
        background-color: @endColor;
        background-image: -webkit-linear-gradient( top, @startColor @startPos, @endColor @endPos ); // Safari 5.1+, Chrome 10+
        list-style-image: e( '/* @embed */' ) url( @url );
 }
 
-.list-style-image-svg( @svg, @fallback ) {
-       list-style-image: e( '/* @embed */' ) url( @svg );
-       /* Fallback to PNG bullet for IE 8 and below using CSS hack */
-       list-style-image: e( '/* @embed */' ) url( @fallback ) e( '\9' );
-}
-
 .hyphens( @value: auto ) {
        & when ( @value = auto ) {
                // Legacy `word-wrap`; IE 6-11, Edge 12+, Firefox 3.5+, Chrome 4+, Safari 3.1+,
diff --git a/resources/src/mediawiki.less/mediawiki.ui/mixins.buttons.less b/resources/src/mediawiki.less/mediawiki.ui/mixins.buttons.less
new file mode 100644 (file)
index 0000000..360ae79
--- /dev/null
@@ -0,0 +1,132 @@
+// Mediawiki.ui button mixins for MediaWiki (deprecated)
+//
+// Helper mixins used to create button styles. This file is importable
+// by all LESS files via `@import 'mediawiki.ui/mixins.buttons';`.
+
+/* stylelint-disable selector-class-pattern */
+
+// Default button mixin.
+.mw-ui-button() {
+       // Container layout
+       display: inline-block;
+       .box-sizing( border-box );
+       min-width: 4em;
+       max-width: 28.75em; // equivalent to 460px, @see T95367
+       margin: 0;
+       padding: 0.57142857em 0.9375em; // equivalent to `8px 12px`
+       border: @border-width-base @border-style-base @border-color-base;
+       border-radius: @borderRadius;
+       cursor: pointer;
+       // Ensure that buttons and inputs are nicely aligned when they have differing heights
+       vertical-align: middle;
+       // Inherit the font rather than apply user agent stylesheet (T72072)
+       font-family: inherit;
+       font-size: 1em;
+       font-weight: bold;
+       line-height: 1;
+       text-align: center;
+       // Disable weird iOS styling
+       -webkit-appearance: none;
+       // IE 6 & 7 hack
+       // https://stackoverflow.com/a/5838575/365238
+       *display: inline; /* stylelint-disable-line declaration-block-no-duplicate-properties */
+       zoom: 1;
+}
+
+// Mixin for button interaction states.
+.mw-ui-button-states() {
+       // Make sure that `color` isn't inheriting from user-agent styles
+       &:visited {
+               color: @colorButtonText;
+       }
+
+       &:hover {
+               background-color: @background-color-base;
+               color: @colorGray4;
+               border-color: @colorGray10;
+       }
+
+       &:focus {
+               background-color: @background-color-base;
+               // Make sure that `color` isn't inheriting from user-agent styles
+               color: @colorButtonText;
+               border-color: @colorProgressive;
+               box-shadow: inset 0 0 0 1px @colorProgressive, inset 0 0 0 2px @background-color-base;
+               outline-width: 0;
+
+               // Remove the inner border and padding in Firefox.
+               &::-moz-focus-inner {
+                       border-color: transparent;
+                       padding: 0;
+               }
+       }
+
+       &:active,
+       &.is-on {
+               background-color: @colorGray12;
+               color: @colorGray1;
+               border-color: @colorGray7;
+               box-shadow: none;
+       }
+
+       &:disabled {
+               background-color: @colorGray12;
+               color: @colorBaseInverted;
+               border-color: @colorGray12;
+               cursor: default;
+
+               // Make sure disabled buttons don't have hover and active states
+               &:hover,
+               &:active {
+                       background-color: @colorGray12;
+                       color: @colorBaseInverted;
+                       box-shadow: none;
+                       border-color: @colorGray12;
+               }
+       }
+
+       // `:not()` is used exclusively for `transition`s as both are not supported by IE < 9
+       &:not( :disabled ) {
+               .transition( ~'background-color 100ms, color 100ms, border-color 100ms, box-shadow 100ms' );
+       }
+}
+
+// Primary buttons mixin.
+.mw-ui-button-colors-primary( @bgColor, @highlightColor, @activeColor ) {
+       background-color: @bgColor;
+       color: #fff;
+       // border of the same color as background so that light background and
+       // dark background buttons are the same height and width
+       border: 1px solid @bgColor;
+
+       &:hover {
+               background-color: @highlightColor;
+               border-color: @highlightColor;
+       }
+
+       &:focus {
+               box-shadow: inset 0 0 0 1px @bgColor, inset 0 0 0 2px #fff;
+       }
+
+       &:active,
+       &.is-on {
+               background-color: @activeColor;
+               border-color: @activeColor;
+               box-shadow: none;
+       }
+
+       &:disabled {
+               background-color: @colorGray12;
+               color: #fff;
+               border-color: @colorGray12;
+
+               // Make sure disabled buttons don't have hover and active states
+               &:hover,
+               &:active {
+                       background-color: @colorGray12;
+                       color: #fff;
+                       border-color: @colorGray12;
+                       box-shadow: none;
+               }
+       }
+}
index 17caa9e..4ea1999 100644 (file)
@@ -19,9 +19,6 @@
                this.$galleryBox = this.$gallery.find( '.gallerybox' );
                this.$currentImage = null;
                this.imageInfoCache = {};
-               if ( this.$gallery.parent().attr( 'id' ) !== 'mw-content-text' ) {
-                       this.$container = this.$gallery.parent();
-               }
 
                // Initialize
                this.drawCarousel();
         * @property {jQuery} $img The `<img>` element that'll display the current image.
         */
 
-       /**
-        * @property {jQuery} $imgLink The `<a>` element that links to the image's File page.
-        */
-
        /**
         * @property {jQuery} $imgCaption The `<p>` element that holds the image caption.
         */
         * @property {jQuery} $currentImage The `<li>` element of the current image.
         */
 
-       /**
-        * @property {jQuery} $container If the gallery contained in an element that is
-        *   not the main content element, then it stores that element.
-        */
-
        /**
         * @property {Object} imageInfoCache A key value pair of thumbnail URLs and image info.
         */
         * Draws the carousel and the interface around it.
         */
        mw.GallerySlideshow.prototype.drawCarousel = function () {
-               var next, prev, toggle, interfaceElements, carouselStack;
+               var nextButton, prevButton, toggleButton, interfaceElements, carouselStack;
 
                this.$carousel = $( '<li>' ).addClass( 'gallerycarousel' );
 
                // Buttons for the interface
-               prev = new OO.ui.ButtonWidget( {
+               prevButton = new OO.ui.ButtonWidget( {
                        framed: false,
                        icon: 'previous'
-               } ).on( 'click', this.prevImage.bind( this ) );
+               } ).connect( this, { click: 'prevImage' } );
 
-               next = new OO.ui.ButtonWidget( {
+               nextButton = new OO.ui.ButtonWidget( {
                        framed: false,
                        icon: 'next'
-               } ).on( 'click', this.nextImage.bind( this ) );
+               } ).connect( this, { click: 'nextImage' } );
 
-               toggle = new OO.ui.ButtonWidget( {
+               toggleButton = new OO.ui.ButtonWidget( {
                        framed: false,
                        icon: 'imageGallery',
                        title: mw.msg( 'gallery-slideshow-toggle' )
-               } ).on( 'click', this.toggleThumbnails.bind( this ) );
+               } ).connect( this, { click: 'toggleThumbnails' } );
 
                interfaceElements = new OO.ui.PanelLayout( {
                        expanded: false,
                        classes: [ 'mw-gallery-slideshow-buttons' ],
                        $content: $( '<div>' ).append(
-                               prev.$element,
-                               toggle.$element,
-                               next.$element
+                               prevButton.$element,
+                               toggleButton.$element,
+                               nextButton.$element
                        )
                } );
                this.$interface = interfaceElements.$element;
 
                // Containers for the current image, caption etc.
-               this.$img = $( '<img>' );
-               this.$imgLink = $( '<a>' ).append( this.$img );
                this.$imgCaption = $( '<p>' ).attr( 'class', 'mw-gallery-slideshow-caption' );
                this.$imgContainer = $( '<div>' )
-                       .attr( 'class', 'mw-gallery-slideshow-img-container' )
-                       .append( this.$imgLink );
+                       .attr( 'class', 'mw-gallery-slideshow-img-container' );
 
                carouselStack = new OO.ui.StackLayout( {
                        continuous: true,
         * size.
         */
        mw.GallerySlideshow.prototype.setSizeRequirement = function () {
-               var w, h;
-
-               if ( this.$container !== undefined ) {
-                       w = this.$container.width() * 0.9;
-                       h = ( this.$container.height() - this.getChromeHeight() ) * 0.9;
-               } else {
-                       w = this.$imgContainer.width();
+               var w = this.$imgContainer.width(),
                        h = Math.min( $( window ).height() * ( 3 / 4 ), this.$imgContainer.width() ) - this.getChromeHeight();
-               }
 
                // Only update and flush the cache if the size changed
                if ( w !== this.imageWidth || h !== this.imageHeight ) {
         * @return {number} Height
         */
        mw.GallerySlideshow.prototype.getChromeHeight = function () {
-               return this.$interface.outerHeight() + this.$galleryCaption.outerHeight();
+               return this.$interface.outerHeight() + ( this.$galleryCaption.outerHeight() || 0 );
        };
 
        /**
         * Sets the height and width of {@link #$img} based on the
         * proportion of the image and the values generated by
         * {@link #setSizeRequirement}.
-        *
-        * @return {boolean} Whether or not the image was sized.
         */
        mw.GallerySlideshow.prototype.setImageSize = function () {
                if ( this.$img === undefined || this.$thumbnail === undefined ) {
-                       return false;
+                       return;
                }
 
                // Reset height and width
                                info.thumbwidth < this.$img.width() ||
                                info.thumbheight < this.$img.height()
                        ) {
-                               this.$img.attr( 'width', info.thumbwidth + 'px' );
-                               this.$img.attr( 'height', info.thumbheight + 'px' );
+                               this.$img.attr( {
+                                       width: info.thumbwidth + 'px',
+                                       height: info.thumbheight + 'px'
+                               } );
                        }
                }.bind( this ) );
-
-               return true;
        };
 
        /**
         * Displays the image set as {@link #$currentImage} in the carousel.
         */
        mw.GallerySlideshow.prototype.showCurrentImage = function () {
-               var imageLi = this.getCurrentImage(),
-                       caption = imageLi.find( '.gallerytext' );
+               var $thumbnail, $imgLink,
+                       $imageLi = this.getCurrentImage(),
+                       $caption = $imageLi.find( '.gallerytext' );
 
                // The order of the following is important for size calculations
                // 1. Highlight current thumbnail
                this.$gallery
                        .find( '.gallerybox.slideshow-current' )
                        .removeClass( 'slideshow-current' );
-               imageLi.addClass( 'slideshow-current' );
+               $imageLi.addClass( 'slideshow-current' );
+
+               this.$thumbnail = $imageLi.find( 'img' );
+               if ( this.$thumbnail.length ) {
+                       // 2. Create and show thumbnail
+                       this.$img = $( '<img>' ).attr( {
+                               src: this.$thumbnail.attr( 'src' ),
+                               alt: this.$thumbnail.attr( 'alt' )
+                       } );
+                       // 'image' class required for detection by MultimediaViewer
+                       $imgLink = $( '<a>' ).addClass( 'image' )
+                               .attr( 'href', $imageLi.find( 'a' ).eq( 0 ).attr( 'href' ) )
+                               .append( this.$img );
 
-               // 2. Show thumbnail
-               this.$thumbnail = imageLi.find( 'img' );
-               this.$img.attr( 'src', this.$thumbnail.attr( 'src' ) );
-               this.$img.attr( 'alt', this.$thumbnail.attr( 'alt' ) );
-               this.$imgLink.attr( 'href', imageLi.find( 'a' ).eq( 0 ).attr( 'href' ) );
+                       this.$imgContainer.empty().append( $imgLink );
+               } else {
+                       // 2b. No image found (e.g. file doesn't exist)
+                       this.$imgContainer.text( $imageLi.find( '.thumb' ).text() );
+               }
 
                // 3. Copy caption
                this.$imgCaption
                        .empty()
-                       .append( caption.clone() );
+                       .append( $caption.clone() );
+
+               if ( !this.$thumbnail.length ) {
+                       return;
+               }
 
                // 4. Stretch thumbnail to correct size
                this.setImageSize();
 
+               $thumbnail = this.$thumbnail;
                // 5. Load image at the required size
-               this.loadImage( this.$thumbnail ).done( function ( info, $img ) {
+               this.loadImage( this.$thumbnail ).done( function ( info ) {
                        // Show this image to the user only if its still the current one
-                       if ( this.$thumbnail.attr( 'src' ) === $img.attr( 'src' ) ) {
+                       if ( this.$thumbnail.attr( 'src' ) === $thumbnail.attr( 'src' ) ) {
                                this.$img.attr( 'src', info.thumburl );
                                this.setImageSize();
+                               mw.hook( 'wikipage.content' ).fire( this.$imgContainer );
 
-                               // Keep the next image ready
+                               // Pre-fetch the next image
                                this.loadImage( this.getNextImage().find( 'img' ) );
                        }
+               }.bind( this ) ).fail( function () {
+                       // Image didn't load
+                       var title = mw.Title.newFromImg( this.$img );
+                       this.$imgContainer.text( title ? title.getMainText() : '' );
                }.bind( this ) );
        };
 
        /**
         * Loads the full image given the `<img>` element of the thumbnail.
         *
-        * @param {Object} $img
+        * @param {jQuery} $img
         * @return {jQuery.Promise} Resolves with the images URL and original
-        *   element once the image has loaded.
+        *  element once the image has loaded.
         */
        mw.GallerySlideshow.prototype.loadImage = function ( $img ) {
                var img, d = $.Deferred();
                        img = new Image();
                        img.src = info.thumburl;
                        img.onload = function () {
-                               d.resolve( info, $img );
+                               d.resolve( info );
                        };
                        img.onerror = function () {
                                d.reject();
diff --git a/resources/src/mediawiki.page.gallery.styles/gallery.css b/resources/src/mediawiki.page.gallery.styles/gallery.css
deleted file mode 100644 (file)
index 6a331b6..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/* Galleries */
-/* These display attributes look nonsensical, but are needed to support IE and FF2 */
-/* Don't forget to update gallery.print.css */
-li.gallerybox {
-       vertical-align: top;
-       display: -moz-inline-box;
-       display: inline-block;
-}
-
-ul.gallery,
-li.gallerybox {
-       zoom: 1;
-       *display: inline;
-}
-
-ul.gallery {
-       margin: 2px;
-       padding: 2px;
-       display: block;
-}
-
-li.gallerycaption {
-       font-weight: bold;
-       text-align: center;
-       display: block;
-       word-wrap: break-word;
-}
-
-li.gallerybox div.thumb {
-       text-align: center;
-       margin: 2px;
-}
-
-li.gallerybox div.thumb img {
-       display: block;
-       margin: 0 auto;
-}
-
-div.gallerytext {
-       overflow: hidden;
-       font-size: 94%;
-       padding: 2px 4px;
-       word-wrap: break-word;
-}
-
-.galleryfilename {
-       display: block;
-}
-
-.galleryfilename-truncate {
-       white-space: nowrap;
-       overflow: hidden;
-       text-overflow: ellipsis;
-}
-
-/* new gallery stuff */
-ul.mw-gallery-nolines li.gallerybox div.thumb {
-       background-color: transparent;
-       border: 0;
-}
-
-ul.mw-gallery-nolines li.gallerybox div.gallerytext {
-       text-align: center;
-}
-
-/* height constrained gallery */
-
-ul.mw-gallery-packed li.gallerybox div.thumb,
-ul.mw-gallery-packed-overlay li.gallerybox div.thumb,
-ul.mw-gallery-packed-hover li.gallerybox div.thumb {
-       background-color: transparent;
-       border: 0;
-}
-
-ul.mw-gallery-packed li.gallerybox div.thumb img,
-ul.mw-gallery-packed-overlay li.gallerybox div.thumb img,
-ul.mw-gallery-packed-hover li.gallerybox div.thumb img {
-       margin: 0 auto;
-}
-
-ul.mw-gallery-packed-hover li.gallerybox,
-ul.mw-gallery-packed-overlay li.gallerybox {
-       position: relative;
-}
-
-ul.mw-gallery-packed-hover div.gallerytextwrapper {
-       overflow: hidden;
-       height: 0;
-}
-
-ul.mw-gallery-packed-hover li.gallerybox:hover div.gallerytextwrapper,
-ul.mw-gallery-packed-overlay li.gallerybox div.gallerytextwrapper,
-ul.mw-gallery-packed-hover li.gallerybox.mw-gallery-focused div.gallerytextwrapper {
-       position: absolute;
-       background: #fff;
-       background: rgba( 255, 255, 255, 0.8 );
-       padding: 5px 10px;
-       bottom: 0;
-       left: 0; /* Needed for IE */
-       height: auto;
-       max-height: 40%;
-       overflow: hidden;
-       font-weight: bold;
-       margin: 2px; /* correspond to style on div.thumb */
-}
-
-ul.mw-gallery-packed-hover li.gallerybox:hover div.gallerytextwrapper p,
-ul.mw-gallery-packed-overlay li.gallerybox div.gallerytextwrapper p,
-ul.mw-gallery-packed-hover li.gallerybox.mw-gallery-focused div.gallerytextwrapper p {
-       text-overflow: ellipsis;
-       white-space: nowrap;
-       overflow: hidden;
-}
-
-ul.mw-gallery-packed-hover li.gallerybox div.gallerytextwrapper:hover,
-ul.mw-gallery-packed-overlay li.gallerybox div.gallerytextwrapper:hover,
-ul.mw-gallery-packed-hover li.gallerybox.mw-gallery-focused div.gallerytextwrapper:hover {
-       overflow: visible;
-       max-height: none;
-}
-
-ul.mw-gallery-packed-hover li.gallerybox div.gallerytextwrapper:hover p,
-ul.mw-gallery-packed-overlay li.gallerybox div.gallerytextwrapper:hover p,
-ul.mw-gallery-packed-hover li.gallerybox.mw-gallery-focused div.gallerytextwrapper:hover p {
-       text-overflow: clip;
-       white-space: normal;
-       overflow: visible;
-}
-
-ul.mw-gallery-packed-hover,
-ul.mw-gallery-packed-overlay,
-ul.mw-gallery-packed {
-       text-align: center;
-}
-
-/* Slideshow */
-ul.gallery.mw-gallery-slideshow {
-       display: block;
-       margin: 4em 0;
-}
-
-ul.gallery.mw-gallery-slideshow .gallerycaption {
-       font-size: 1.3em;
-       margin: 0;
-}
-
-ul.gallery.mw-gallery-slideshow .gallerycarousel.mw-gallery-slideshow-thumbnails-toggled {
-       margin-bottom: 1.3em;
-}
-
-ul.gallery.mw-gallery-slideshow .mw-gallery-slideshow-buttons {
-       opacity: 0.5;
-       padding: 1.3em 0;
-}
-
-ul.gallery.mw-gallery-slideshow .mw-gallery-slideshow-buttons .oo-ui-buttonElement {
-       margin: 0 2em;
-}
-
-.mw-gallery-slideshow li.gallerybox.slideshow-current {
-       background: #efefef;
-}
-
-.mw-gallery-slideshow .gallerybox > div {
-       max-width: 120px;
-}
-
-ul.mw-gallery-slideshow li.gallerybox div.thumb {
-       border: 0;
-       background: transparent;
-}
-
-ul.mw-gallery-slideshow li.gallerycarousel {
-       display: block;
-       text-align: center;
-}
-
-.mw-gallery-slideshow-img-container a {
-       display: block;
-}
-
-@media screen {
-       /* Background and border colors are defined separately for print mode */
-       li.gallerybox div.thumb {
-               border: 1px solid #c8ccd1;
-               background-color: #f8f9fa;
-       }
-}
diff --git a/resources/src/mediawiki.page.gallery.styles/gallery.less b/resources/src/mediawiki.page.gallery.styles/gallery.less
new file mode 100644 (file)
index 0000000..61bf5c3
--- /dev/null
@@ -0,0 +1,196 @@
+/* stylelint-disable selector-class-pattern */
+
+/* Galleries */
+/* These display attributes look nonsensical, but are needed to support IE and FF2 */
+/* Don't forget to update gallery.print.css */
+
+ul.gallery {
+       margin: 2px;
+       padding: 2px;
+       display: block;
+}
+
+li.gallerycaption {
+       font-weight: bold;
+       text-align: center;
+       display: block;
+       word-wrap: break-word;
+}
+
+li.gallerybox {
+       vertical-align: top;
+       display: -moz-inline-box;
+       display: inline-block;
+
+       div.thumb {
+               text-align: center;
+               margin: 2px;
+
+               img {
+                       display: block;
+                       margin: 0 auto;
+               }
+       }
+}
+
+ul.gallery,
+li.gallerybox {
+       zoom: 1;
+       *display: inline;
+}
+
+div.gallerytext {
+       overflow: hidden;
+       font-size: 94%;
+       padding: 2px 4px;
+       word-wrap: break-word;
+}
+
+.galleryfilename {
+       display: block;
+
+       &-truncate {
+               white-space: nowrap;
+               overflow: hidden;
+               text-overflow: ellipsis;
+       }
+}
+
+/* new gallery stuff */
+ul.mw-gallery-nolines li.gallerybox {
+       div.thumb {
+               background-color: transparent;
+               border: 0;
+       }
+
+       div.gallerytext {
+               text-align: center;
+       }
+}
+
+/* height constrained gallery */
+
+ul.mw-gallery-packed,
+ul.mw-gallery-packed-overlay,
+ul.mw-gallery-packed-hover {
+       text-align: center;
+
+       li.gallerybox div.thumb {
+               background-color: transparent;
+               border: 0;
+
+               img {
+                       margin: 0 auto;
+               }
+       }
+}
+
+ul.mw-gallery-packed-hover,
+ul.mw-gallery-packed-overlay {
+       li.gallerybox {
+               position: relative;
+       }
+}
+
+ul.mw-gallery-packed-hover div.gallerytextwrapper {
+       overflow: hidden;
+       height: 0;
+}
+
+ul.mw-gallery-packed-hover li.gallerybox:hover div.gallerytextwrapper,
+ul.mw-gallery-packed-overlay li.gallerybox div.gallerytextwrapper,
+ul.mw-gallery-packed-hover li.gallerybox.mw-gallery-focused div.gallerytextwrapper {
+       position: absolute;
+       background: #fff;
+       background: rgba( 255, 255, 255, 0.8 );
+       padding: 5px 10px;
+       bottom: 0;
+       left: 0; /* Needed for IE */
+       height: auto;
+       max-height: 40%;
+       overflow: hidden;
+       font-weight: bold;
+       margin: 2px; /* correspond to style on div.thumb */
+
+       p {
+               text-overflow: ellipsis;
+               white-space: nowrap;
+               overflow: hidden;
+       }
+
+       &:hover {
+               overflow: visible;
+               max-height: none;
+
+               p {
+                       text-overflow: clip;
+                       white-space: normal;
+                       overflow: visible;
+               }
+       }
+}
+
+/* Slideshow */
+ul.gallery.mw-gallery-slideshow {
+       display: block;
+       margin: 4em 0;
+
+       .gallerycaption {
+               font-size: 1.3em;
+               margin: 0;
+       }
+
+       .gallerycarousel {
+               display: block;
+               text-align: center;
+
+               &.mw-gallery-slideshow-thumbnails-toggled {
+                       margin-bottom: 1.3em;
+               }
+       }
+
+       .mw-gallery-slideshow-buttons {
+               opacity: 0.5;
+               padding: 1.3em 0;
+               white-space: nowrap;
+
+               .oo-ui-buttonElement {
+                       margin: 0 2em;
+
+                       &:first-child {
+                               margin-left: 0;
+                       }
+
+                       &:last-child {
+                               margin-right: 0;
+                       }
+               }
+       }
+
+       .gallerybox {
+               &.slideshow-current {
+                       background: #efefef;
+               }
+
+               > div {
+                       max-width: 120px;
+               }
+
+               div.thumb {
+                       border: 0;
+                       background: transparent;
+               }
+       }
+}
+
+.mw-gallery-slideshow-img-container a {
+       display: block;
+}
+
+@media screen {
+       /* Background and border colors are defined separately for print mode */
+       li.gallerybox div.thumb {
+               border: 1px solid #c8ccd1;
+               background-color: #f8f9fa;
+       }
+}
index f7a3f0d..2b596ab 100644 (file)
@@ -1,3 +1,4 @@
+/* stylelint-disable selector-class-pattern */
 li.gallerybox {
        vertical-align: top;
        display: inline-block;
index 12009d1..630e3a6 100644 (file)
                        window.print();
                        e.preventDefault();
                } );
+
+               // Turn logout to a POST action
+               $( '#pt-logout a' ).on( 'click', function ( e ) {
+                       var api = new mw.Api(), returnUrl;
+                       returnUrl = $( '#pt-logout a' ).attr( 'href' );
+                       mw.notify(
+                               mw.message( 'logging-out-notify' ),
+                               { tag: 'logout', autoHide: false }
+                       );
+                       api.postWithToken( 'csrf', {
+                               action: 'logout'
+                       } ).done( function () {
+                               // Horrible hack until deprecation of logoutToken in GET is done
+                               returnUrl = returnUrl.replace( /logoutToken=.+?($|&)/g, 'logoutToken=%2B%5C' );
+                               window.location = returnUrl;
+                       } ).fail( function ( e ) {
+                               mw.notify(
+                                       mw.message( 'logout-failed', e ),
+                                       { type: 'error', tag: 'logout', autoHide: false }
+                               );
+                       } );
+                       e.preventDefault();
+               } );
        } );
 
 }() );
diff --git a/resources/src/mediawiki.page.rollback.js b/resources/src/mediawiki.page.rollback.js
deleted file mode 100644 (file)
index 2896f40..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*!
- * Enhance rollback links by using asynchronous API requests,
- * rather than navigating to an action page.
- *
- * @since 1.28
- * @author Timo Tijhof
- */
-( function () {
-
-       $( function () {
-               $( '.mw-rollback-link' ).on( 'click', 'a[data-mw="interface"]', function ( e ) {
-                       var api, $spinner,
-                               $link = $( this ),
-                               url = this.href,
-                               page = mw.util.getParamValue( 'title', url ),
-                               user = mw.util.getParamValue( 'from', url );
-
-                       if ( !page || user === null ) {
-                               // Let native browsing handle the link
-                               return true;
-                       }
-
-                       // Preload the notification module for mw.notify
-                       mw.loader.load( 'mediawiki.notification' );
-
-                       // Remove event handler so that next click (re-try) uses server action
-                       $( e.delegateTarget ).off( 'click' );
-
-                       // Hide the link and create a spinner to show it inside the brackets.
-                       $spinner = $.createSpinner( { size: 'small', type: 'inline' } );
-                       $link.hide().after( $spinner );
-
-                       // @todo: data.messageHtml is no more. Convert to using errorformat=html.
-                       api = new mw.Api();
-                       api.rollback( page, user )
-                               .then( function ( data ) {
-                                       mw.notify( $.parseHTML( data.messageHtml ), {
-                                               title: mw.msg( 'actioncomplete' )
-                                       } );
-
-                                       // Remove link container and the subsequent text node containing " | ".
-                                       if ( e.delegateTarget.nextSibling && e.delegateTarget.nextSibling.nodeType === Node.TEXT_NODE ) {
-                                               $( e.delegateTarget.nextSibling ).remove();
-                                       }
-                                       $( e.delegateTarget ).remove();
-                               }, function ( errorCode, data ) {
-                                       var message = data && data.error && data.error.messageHtml ?
-                                                       $.parseHTML( data.error.messageHtml ) :
-                                                       mw.msg( 'rollbackfailed' ),
-                                               type = errorCode === 'alreadyrolled' ? 'warn' : 'error';
-
-                                       mw.notify( message, {
-                                               type: type,
-                                               title: mw.msg( 'rollbackfailed' ),
-                                               autoHide: false
-                                       } );
-
-                                       // Restore the link (enables user to try again)
-                                       $spinner.remove();
-                                       $link.show();
-                               } );
-
-                       e.preventDefault();
-               } );
-       } );
-
-}() );
index 1cccb88..4c82192 100644 (file)
@@ -3,6 +3,8 @@
  * in MediaWiki (used e.g. on Special:ListFiles).
  */
 
+/* stylelint-disable selector-class-pattern */
+
 @import 'mediawiki.mixins';
 
 // TablePager uses `.mw-datatable` and is loaded in the right order by RL
diff --git a/resources/src/mediawiki.rcfilters/.eslintrc.json b/resources/src/mediawiki.rcfilters/.eslintrc.json
new file mode 100644 (file)
index 0000000..ad8dbb3
--- /dev/null
@@ -0,0 +1,5 @@
+{
+       "parserOptions": {
+               "sourceType": "module"
+       }
+}
index ce5d407..97b73ae 100644 (file)
-( function () {
-
-       var byteLength = require( 'mediawiki.String' ).byteLength,
-               UriProcessor = require( './UriProcessor.js' ),
-               Controller;
-
-       /* eslint no-underscore-dangle: "off" */
-       /**
-        * Controller for the filters in Recent Changes
-        * @class mw.rcfilters.Controller
-        *
-        * @constructor
-        * @param {mw.rcfilters.dm.FiltersViewModel} filtersModel Filters view model
-        * @param {mw.rcfilters.dm.ChangesListViewModel} changesListModel Changes list view model
-        * @param {mw.rcfilters.dm.SavedQueriesModel} savedQueriesModel Saved queries model
-        * @param {Object} config Additional configuration
-        * @cfg {string} savedQueriesPreferenceName Where to save the saved queries
-        * @cfg {string} daysPreferenceName Preference name for the days filter
-        * @cfg {string} limitPreferenceName Preference name for the limit filter
-        * @cfg {string} collapsedPreferenceName Preference name for collapsing and showing
-        *  the active filters area
-        * @cfg {boolean} [normalizeTarget] Dictates whether or not to go through the
-        *  title normalization to separate title subpage/parts into the target= url
-        *  parameter
-        */
-       Controller = function MwRcfiltersController( filtersModel, changesListModel, savedQueriesModel, config ) {
-               this.filtersModel = filtersModel;
-               this.changesListModel = changesListModel;
-               this.savedQueriesModel = savedQueriesModel;
-               this.savedQueriesPreferenceName = config.savedQueriesPreferenceName;
-               this.daysPreferenceName = config.daysPreferenceName;
-               this.limitPreferenceName = config.limitPreferenceName;
-               this.collapsedPreferenceName = config.collapsedPreferenceName;
-               this.normalizeTarget = !!config.normalizeTarget;
-
-               this.pollingRate = require( './config.json' ).StructuredChangeFiltersLiveUpdatePollingRate;
-
-               this.requestCounter = {};
-               this.baseFilterState = {};
-               this.uriProcessor = null;
-               this.initialized = false;
-               this.wereSavedQueriesSaved = false;
-
-               this.prevLoggedItems = [];
-
-               this.FILTER_CHANGE = 'filterChange';
-               this.SHOW_NEW_CHANGES = 'showNewChanges';
-               this.LIVE_UPDATE = 'liveUpdate';
-       };
-
-       /* Initialization */
-       OO.initClass( Controller );
-
-       /**
-        * Initialize the filter and parameter states
-        *
-        * @param {Array} filterStructure Filter definition and structure for the model
-        * @param {Object} [namespaceStructure] Namespace definition
-        * @param {Object} [tagList] Tag definition
-        * @param {Object} [conditionalViews] Conditional view definition
-        */
-       Controller.prototype.initialize = function ( filterStructure, namespaceStructure, tagList, conditionalViews ) {
-               var parsedSavedQueries, pieces,
-                       displayConfig = mw.config.get( 'StructuredChangeFiltersDisplayConfig' ),
-                       defaultSavedQueryExists = mw.config.get( 'wgStructuredChangeFiltersDefaultSavedQueryExists' ),
-                       controller = this,
-                       views = $.extend( true, {}, conditionalViews ),
-                       items = [],
-                       uri = new mw.Uri();
-
-               // Prepare views
-               if ( namespaceStructure ) {
-                       items = [];
-                       // eslint-disable-next-line no-jquery/no-each-util
-                       $.each( namespaceStructure, function ( namespaceID, label ) {
-                               // Build and clean up the individual namespace items definition
-                               items.push( {
-                                       name: namespaceID,
-                                       label: label || mw.msg( 'blanknamespace' ),
-                                       description: '',
-                                       identifiers: [
-                                               mw.Title.isTalkNamespace( namespaceID ) ?
-                                                       'talk' : 'subject'
-                                       ],
-                                       cssClass: 'mw-changeslist-ns-' + namespaceID
-                               } );
+var byteLength = require( 'mediawiki.String' ).byteLength,
+       UriProcessor = require( './UriProcessor.js' ),
+       Controller;
+
+/* eslint no-underscore-dangle: "off" */
+/**
+ * Controller for the filters in Recent Changes
+ * @class mw.rcfilters.Controller
+ *
+ * @constructor
+ * @param {mw.rcfilters.dm.FiltersViewModel} filtersModel Filters view model
+ * @param {mw.rcfilters.dm.ChangesListViewModel} changesListModel Changes list view model
+ * @param {mw.rcfilters.dm.SavedQueriesModel} savedQueriesModel Saved queries model
+ * @param {Object} config Additional configuration
+ * @cfg {string} savedQueriesPreferenceName Where to save the saved queries
+ * @cfg {string} daysPreferenceName Preference name for the days filter
+ * @cfg {string} limitPreferenceName Preference name for the limit filter
+ * @cfg {string} collapsedPreferenceName Preference name for collapsing and showing
+ *  the active filters area
+ * @cfg {boolean} [normalizeTarget] Dictates whether or not to go through the
+ *  title normalization to separate title subpage/parts into the target= url
+ *  parameter
+ */
+Controller = function MwRcfiltersController( filtersModel, changesListModel, savedQueriesModel, config ) {
+       this.filtersModel = filtersModel;
+       this.changesListModel = changesListModel;
+       this.savedQueriesModel = savedQueriesModel;
+       this.savedQueriesPreferenceName = config.savedQueriesPreferenceName;
+       this.daysPreferenceName = config.daysPreferenceName;
+       this.limitPreferenceName = config.limitPreferenceName;
+       this.collapsedPreferenceName = config.collapsedPreferenceName;
+       this.normalizeTarget = !!config.normalizeTarget;
+
+       this.pollingRate = require( './config.json' ).StructuredChangeFiltersLiveUpdatePollingRate;
+
+       this.requestCounter = {};
+       this.uriProcessor = null;
+       this.initialized = false;
+       this.wereSavedQueriesSaved = false;
+
+       this.prevLoggedItems = [];
+
+       this.FILTER_CHANGE = 'filterChange';
+       this.SHOW_NEW_CHANGES = 'showNewChanges';
+       this.LIVE_UPDATE = 'liveUpdate';
+};
+
+/* Initialization */
+OO.initClass( Controller );
+
+/**
+ * Initialize the filter and parameter states
+ *
+ * @param {Array} filterStructure Filter definition and structure for the model
+ * @param {Object} [namespaceStructure] Namespace definition
+ * @param {Object} [tagList] Tag definition
+ * @param {Object} [conditionalViews] Conditional view definition
+ */
+Controller.prototype.initialize = function ( filterStructure, namespaceStructure, tagList, conditionalViews ) {
+       var parsedSavedQueries, pieces,
+               displayConfig = mw.config.get( 'StructuredChangeFiltersDisplayConfig' ),
+               defaultSavedQueryExists = mw.config.get( 'wgStructuredChangeFiltersDefaultSavedQueryExists' ),
+               controller = this,
+               views = $.extend( true, {}, conditionalViews ),
+               items = [],
+               uri = new mw.Uri();
+
+       // Prepare views
+       if ( namespaceStructure ) {
+               items = [];
+               // eslint-disable-next-line no-jquery/no-each-util
+               $.each( namespaceStructure, function ( namespaceID, label ) {
+                       // Build and clean up the individual namespace items definition
+                       items.push( {
+                               name: namespaceID,
+                               label: label || mw.msg( 'blanknamespace' ),
+                               description: '',
+                               identifiers: [
+                                       mw.Title.isTalkNamespace( namespaceID ) ?
+                                               'talk' : 'subject'
+                               ],
+                               cssClass: 'mw-changeslist-ns-' + namespaceID
                        } );
+               } );
 
-                       views.namespaces = {
+               views.namespaces = {
+                       title: mw.msg( 'namespaces' ),
+                       trigger: ':',
+                       groups: [ {
+                               // Group definition (single group)
+                               name: 'namespace', // parameter name is singular
+                               type: 'string_options',
                                title: mw.msg( 'namespaces' ),
-                               trigger: ':',
-                               groups: [ {
-                                       // Group definition (single group)
-                                       name: 'namespace', // parameter name is singular
-                                       type: 'string_options',
-                                       title: mw.msg( 'namespaces' ),
-                                       labelPrefixKey: { default: 'rcfilters-tag-prefix-namespace', inverted: 'rcfilters-tag-prefix-namespace-inverted' },
-                                       separator: ';',
-                                       fullCoverage: true,
-                                       filters: items
-                               } ]
-                       };
-                       views.invert = {
-                               groups: [
-                                       {
-                                               name: 'invertGroup',
-                                               type: 'boolean',
-                                               hidden: true,
-                                               filters: [ {
-                                                       name: 'invert',
-                                                       default: '0'
-                                               } ]
-                                       } ]
-                       };
-               }
-               if ( tagList ) {
-                       views.tags = {
-                               title: mw.msg( 'rcfilters-view-tags' ),
-                               trigger: '#',
-                               groups: [ {
-                                       // Group definition (single group)
-                                       name: 'tagfilter', // Parameter name
-                                       type: 'string_options',
-                                       title: 'rcfilters-view-tags', // Message key
-                                       labelPrefixKey: 'rcfilters-tag-prefix-tags',
-                                       separator: '|',
-                                       fullCoverage: false,
-                                       filters: tagList
-                               } ]
-                       };
-               }
-
-               // Add parameter range operations
-               views.range = {
-                       groups: [
-                               {
-                                       name: 'limit',
-                                       type: 'single_option',
-                                       title: '', // Because it's a hidden group, this title actually appears nowhere
-                                       hidden: true,
-                                       allowArbitrary: true,
-                                       // FIXME: $.isNumeric is deprecated
-                                       validate: $.isNumeric,
-                                       range: {
-                                               min: 0, // The server normalizes negative numbers to 0 results
-                                               max: 1000
-                                       },
-                                       sortFunc: function ( a, b ) { return Number( a.name ) - Number( b.name ); },
-                                       default: mw.user.options.get( this.limitPreferenceName, displayConfig.limitDefault ),
-                                       sticky: true,
-                                       filters: displayConfig.limitArray.map( function ( num ) {
-                                               return controller._createFilterDataFromNumber( num, num );
-                                       } )
-                               },
-                               {
-                                       name: 'days',
-                                       type: 'single_option',
-                                       title: '', // Because it's a hidden group, this title actually appears nowhere
-                                       hidden: true,
-                                       allowArbitrary: true,
-                                       // FIXME: $.isNumeric is deprecated
-                                       validate: $.isNumeric,
-                                       range: {
-                                               min: 0,
-                                               max: displayConfig.maxDays
-                                       },
-                                       sortFunc: function ( a, b ) { return Number( a.name ) - Number( b.name ); },
-                                       numToLabelFunc: function ( i ) {
-                                               return Number( i ) < 1 ?
-                                                       ( Number( i ) * 24 ).toFixed( 2 ) :
-                                                       Number( i );
-                                       },
-                                       default: mw.user.options.get( this.daysPreferenceName, displayConfig.daysDefault ),
-                                       sticky: true,
-                                       filters: [
-                                               // Hours (1, 2, 6, 12)
-                                               0.04166, 0.0833, 0.25, 0.5
-                                       // Days
-                                       ].concat( displayConfig.daysArray )
-                                               .map( function ( num ) {
-                                                       return controller._createFilterDataFromNumber(
-                                                               num,
-                                                               // Convert fractions of days to number of hours for the labels
-                                                               num < 1 ? Math.round( num * 24 ) : num
-                                                       );
-                                               } )
-                               }
-                       ]
+                               labelPrefixKey: { default: 'rcfilters-tag-prefix-namespace', inverted: 'rcfilters-tag-prefix-namespace-inverted' },
+                               separator: ';',
+                               fullCoverage: true,
+                               filters: items
+                       } ]
                };
-
-               views.display = {
+               views.invert = {
                        groups: [
                                {
-                                       name: 'display',
+                                       name: 'invertGroup',
                                        type: 'boolean',
-                                       title: '', // Because it's a hidden group, this title actually appears nowhere
                                        hidden: true,
-                                       sticky: true,
-                                       filters: [
-                                               {
-                                                       name: 'enhanced',
-                                                       default: String( mw.user.options.get( 'usenewrc', 0 ) )
-                                               }
-                                       ]
-                               }
-                       ]
+                                       filters: [ {
+                                               name: 'invert',
+                                               default: '0'
+                                       } ]
+                               } ]
                };
-
-               // Before we do anything, we need to see if we require additional items in the
-               // groups that have 'AllowArbitrary'. For the moment, those are only single_option
-               // groups; if we ever expand it, this might need further generalization:
-               // eslint-disable-next-line no-jquery/no-each-util
-               $.each( views, function ( viewName, viewData ) {
-                       viewData.groups.forEach( function ( groupData ) {
-                               var extraValues = [];
-                               if ( groupData.allowArbitrary ) {
-                                       // If the value in the URI isn't in the group, add it
-                                       if ( uri.query[ groupData.name ] !== undefined ) {
-                                               extraValues.push( uri.query[ groupData.name ] );
-                                       }
-                                       // If the default value isn't in the group, add it
-                                       if ( groupData.default !== undefined ) {
-                                               extraValues.push( String( groupData.default ) );
-                                       }
-                                       controller.addNumberValuesToGroup( groupData, extraValues );
-                               }
-                       } );
-               } );
-
-               // Initialize the model
-               this.filtersModel.initializeFilters( filterStructure, views );
-
-               this.uriProcessor = new UriProcessor(
-                       this.filtersModel,
-                       { normalizeTarget: this.normalizeTarget }
-               );
-
-               if ( !mw.user.isAnon() ) {
-                       try {
-                               parsedSavedQueries = JSON.parse( mw.user.options.get( this.savedQueriesPreferenceName ) || '{}' );
-                       } catch ( err ) {
-                               parsedSavedQueries = {};
-                       }
-
-                       // Initialize saved queries
-                       this.savedQueriesModel.initialize( parsedSavedQueries );
-                       if ( this.savedQueriesModel.isConverted() ) {
-                               // Since we know we converted, we're going to re-save
-                               // the queries so they are now migrated to the new format
-                               this._saveSavedQueries();
-                       }
-               }
-
-               if ( defaultSavedQueryExists ) {
-                       // This came from the server, meaning that we have a default
-                       // saved query, but the server could not load it, probably because
-                       // it was pre-conversion to the new format.
-                       // We need to load this query again
-                       this.applySavedQuery( this.savedQueriesModel.getDefault() );
-               } else {
-                       // There are either recognized parameters in the URL
-                       // or there are none, but there is also no default
-                       // saved query (so defaults are from the backend)
-                       // We want to update the state but not fetch results
-                       // again
-                       this.updateStateFromUrl( false );
-
-                       pieces = this._extractChangesListInfo( $( '#mw-content-text' ) );
-
-                       // Update the changes list with the existing data
-                       // so it gets processed
-                       this.changesListModel.update(
-                               pieces.changes,
-                               pieces.fieldset,
-                               pieces.noResultsDetails,
-                               true // We're using existing DOM elements
-                       );
-               }
-
-               this.initialized = true;
-               this.switchView( 'default' );
-
-               if ( this.pollingRate ) {
-                       this._scheduleLiveUpdate();
-               }
-       };
-
-       /**
-        * Check if the controller has finished initializing.
-        * @return {boolean} Controller is initialized
-        */
-       Controller.prototype.isInitialized = function () {
-               return this.initialized;
-       };
-
-       /**
-        * Extracts information from the changes list DOM
-        *
-        * @param {jQuery} $root Root DOM to find children from
-        * @param {boolean} [statusCode] Server response status code
-        * @return {Object} Information about changes list
-        * @return {Object|string} return.changes Changes list, or 'NO_RESULTS' if there are no results
-        *   (either normally or as an error)
-        * @return {string} [return.noResultsDetails] 'NO_RESULTS_NORMAL' for a normal 0-result set,
-        *   'NO_RESULTS_TIMEOUT' for no results due to a timeout, or omitted for more than 0 results
-        * @return {jQuery} return.fieldset Fieldset
-        */
-       Controller.prototype._extractChangesListInfo = function ( $root, statusCode ) {
-               var info,
-                       $changesListContents = $root.find( '.mw-changeslist' ).first().contents(),
-                       areResults = !!$changesListContents.length,
-                       checkForLogout = !areResults && statusCode === 200;
-
-               // We check if user logged out on different tab/browser or the session has expired.
-               // 205 status code returned from the server, which indicates that we need to reload the page
-               // is not usable on WL page, because we get redirected to login page, which gives 200 OK
-               // status code (if everything else goes well).
-               // Bug: T177717
-               if ( checkForLogout && !!$root.find( '#wpName1' ).length ) {
-                       location.reload( false );
-                       return;
-               }
-
-               info = {
-                       changes: $changesListContents.length ? $changesListContents : 'NO_RESULTS',
-                       fieldset: $root.find( 'fieldset.cloptions' ).first()
+       }
+       if ( tagList ) {
+               views.tags = {
+                       title: mw.msg( 'rcfilters-view-tags' ),
+                       trigger: '#',
+                       groups: [ {
+                               // Group definition (single group)
+                               name: 'tagfilter', // Parameter name
+                               type: 'string_options',
+                               title: 'rcfilters-view-tags', // Message key
+                               labelPrefixKey: 'rcfilters-tag-prefix-tags',
+                               separator: '|',
+                               fullCoverage: false,
+                               filters: tagList
+                       } ]
                };
+       }
 
-               if ( !areResults ) {
-                       if ( $root.find( '.mw-changeslist-timeout' ).length ) {
-                               info.noResultsDetails = 'NO_RESULTS_TIMEOUT';
-                       } else if ( $root.find( '.mw-changeslist-notargetpage' ).length ) {
-                               info.noResultsDetails = 'NO_RESULTS_NO_TARGET_PAGE';
-                       } else if ( $root.find( '.mw-changeslist-invalidtargetpage' ).length ) {
-                               info.noResultsDetails = 'NO_RESULTS_INVALID_TARGET_PAGE';
-                       } else {
-                               info.noResultsDetails = 'NO_RESULTS_NORMAL';
+       // Add parameter range operations
+       views.range = {
+               groups: [
+                       {
+                               name: 'limit',
+                               type: 'single_option',
+                               title: '', // Because it's a hidden group, this title actually appears nowhere
+                               hidden: true,
+                               allowArbitrary: true,
+                               // FIXME: $.isNumeric is deprecated
+                               validate: $.isNumeric,
+                               range: {
+                                       min: 0, // The server normalizes negative numbers to 0 results
+                                       max: 1000
+                               },
+                               sortFunc: function ( a, b ) { return Number( a.name ) - Number( b.name ); },
+                               default: mw.user.options.get( this.limitPreferenceName, displayConfig.limitDefault ),
+                               sticky: true,
+                               filters: displayConfig.limitArray.map( function ( num ) {
+                                       return controller._createFilterDataFromNumber( num, num );
+                               } )
+                       },
+                       {
+                               name: 'days',
+                               type: 'single_option',
+                               title: '', // Because it's a hidden group, this title actually appears nowhere
+                               hidden: true,
+                               allowArbitrary: true,
+                               // FIXME: $.isNumeric is deprecated
+                               validate: $.isNumeric,
+                               range: {
+                                       min: 0,
+                                       max: displayConfig.maxDays
+                               },
+                               sortFunc: function ( a, b ) { return Number( a.name ) - Number( b.name ); },
+                               numToLabelFunc: function ( i ) {
+                                       return Number( i ) < 1 ?
+                                               ( Number( i ) * 24 ).toFixed( 2 ) :
+                                               Number( i );
+                               },
+                               default: mw.user.options.get( this.daysPreferenceName, displayConfig.daysDefault ),
+                               sticky: true,
+                               filters: [
+                                       // Hours (1, 2, 6, 12)
+                                       0.04166, 0.0833, 0.25, 0.5
+                               // Days
+                               ].concat( displayConfig.daysArray )
+                                       .map( function ( num ) {
+                                               return controller._createFilterDataFromNumber(
+                                                       num,
+                                                       // Convert fractions of days to number of hours for the labels
+                                                       num < 1 ? Math.round( num * 24 ) : num
+                                               );
+                                       } )
                        }
-               }
-
-               return info;
+               ]
        };
 
-       /**
-        * Create filter data from a number, for the filters that are numerical value
-        *
-        * @param {number} num Number
-        * @param {number} numForDisplay Number for the label
-        * @return {Object} Filter data
-        */
-       Controller.prototype._createFilterDataFromNumber = function ( num, numForDisplay ) {
-               return {
-                       name: String( num ),
-                       label: mw.language.convertNumber( numForDisplay )
-               };
+       views.display = {
+               groups: [
+                       {
+                               name: 'display',
+                               type: 'boolean',
+                               title: '', // Because it's a hidden group, this title actually appears nowhere
+                               hidden: true,
+                               sticky: true,
+                               filters: [
+                                       {
+                                               name: 'enhanced',
+                                               default: String( mw.user.options.get( 'usenewrc', 0 ) )
+                                       }
+                               ]
+                       }
+               ]
        };
 
-       /**
-        * Add an arbitrary values to groups that allow arbitrary values
-        *
-        * @param {Object} groupData Group data
-        * @param {string|string[]} arbitraryValues An array of arbitrary values to add to the group
-        */
-       Controller.prototype.addNumberValuesToGroup = function ( groupData, arbitraryValues ) {
-               var controller = this,
-                       normalizeWithinRange = function ( range, val ) {
-                               if ( val < range.min ) {
-                                       return range.min; // Min
-                               } else if ( val >= range.max ) {
-                                       return range.max; // Max
+       // Before we do anything, we need to see if we require additional items in the
+       // groups that have 'AllowArbitrary'. For the moment, those are only single_option
+       // groups; if we ever expand it, this might need further generalization:
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( views, function ( viewName, viewData ) {
+               viewData.groups.forEach( function ( groupData ) {
+                       var extraValues = [];
+                       if ( groupData.allowArbitrary ) {
+                               // If the value in the URI isn't in the group, add it
+                               if ( uri.query[ groupData.name ] !== undefined ) {
+                                       extraValues.push( uri.query[ groupData.name ] );
                                }
-                               return val;
-                       };
-
-               arbitraryValues = Array.isArray( arbitraryValues ) ? arbitraryValues : [ arbitraryValues ];
-
-               // Normalize the arbitrary values and the default value for a range
-               if ( groupData.range ) {
-                       arbitraryValues = arbitraryValues.map( function ( val ) {
-                               return normalizeWithinRange( groupData.range, val );
-                       } );
-
-                       // Normalize the default, since that's user defined
-                       if ( groupData.default !== undefined ) {
-                               groupData.default = String( normalizeWithinRange( groupData.range, groupData.default ) );
-                       }
-               }
-
-               // This is only true for single_option group
-               // We assume these are the only groups that will allow for
-               // arbitrary, since it doesn't make any sense for the other
-               // groups.
-               arbitraryValues.forEach( function ( val ) {
-                       if (
-                               // If the group allows for arbitrary data
-                               groupData.allowArbitrary &&
-                               // and it is single_option (or string_options, but we
-                               // don't have cases of those yet, nor do we plan to)
-                               groupData.type === 'single_option' &&
-                               // and, if there is a validate method and it passes on
-                               // the data
-                               ( !groupData.validate || groupData.validate( val ) ) &&
-                               // but if that value isn't already in the definition
-                               groupData.filters
-                                       .map( function ( filterData ) {
-                                               return String( filterData.name );
-                                       } )
-                                       .indexOf( String( val ) ) === -1
-                       ) {
-                               // Add the filter information
-                               groupData.filters.push( controller._createFilterDataFromNumber(
-                                       val,
-                                       groupData.numToLabelFunc ?
-                                               groupData.numToLabelFunc( val ) :
-                                               val
-                               ) );
-
-                               // If there's a sort function set up, re-sort the values
-                               if ( groupData.sortFunc ) {
-                                       groupData.filters.sort( groupData.sortFunc );
+                               // If the default value isn't in the group, add it
+                               if ( groupData.default !== undefined ) {
+                                       extraValues.push( String( groupData.default ) );
                                }
+                               controller.addNumberValuesToGroup( groupData, extraValues );
                        }
                } );
-       };
+       } );
 
-       /**
-        * Reset to default filters
-        */
-       Controller.prototype.resetToDefaults = function () {
-               var params = this._getDefaultParams();
-               if ( this.applyParamChange( params ) ) {
-                       // Only update the changes list if there was a change to actual filters
-                       this.updateChangesList();
-               } else {
-                       this.uriProcessor.updateURL( params );
-               }
-       };
-
-       /**
-        * Check whether the default values of the filters are all false.
-        *
-        * @return {boolean} Defaults are all false
-        */
-       Controller.prototype.areDefaultsEmpty = function () {
-               return $.isEmptyObject( this._getDefaultParams() );
-       };
+       // Initialize the model
+       this.filtersModel.initializeFilters( filterStructure, views );
 
-       /**
-        * Empty all selected filters
-        */
-       Controller.prototype.emptyFilters = function () {
-               var highlightedFilterNames = this.filtersModel.getHighlightedItems()
-                       .map( function ( filterItem ) { return { name: filterItem.getName() }; } );
+       this.uriProcessor = new UriProcessor(
+               this.filtersModel,
+               { normalizeTarget: this.normalizeTarget }
+       );
 
-               if ( this.applyParamChange( {} ) ) {
-                       // Only update the changes list if there was a change to actual filters
-                       this.updateChangesList();
-               } else {
-                       this.uriProcessor.updateURL();
+       if ( !mw.user.isAnon() ) {
+               try {
+                       parsedSavedQueries = JSON.parse( mw.user.options.get( this.savedQueriesPreferenceName ) || '{}' );
+               } catch ( err ) {
+                       parsedSavedQueries = {};
                }
 
-               if ( highlightedFilterNames ) {
-                       this._trackHighlight( 'clearAll', highlightedFilterNames );
+               // Initialize saved queries
+               this.savedQueriesModel.initialize( parsedSavedQueries );
+               if ( this.savedQueriesModel.isConverted() ) {
+                       // Since we know we converted, we're going to re-save
+                       // the queries so they are now migrated to the new format
+                       this._saveSavedQueries();
                }
+       }
+
+       if ( defaultSavedQueryExists ) {
+               // This came from the server, meaning that we have a default
+               // saved query, but the server could not load it, probably because
+               // it was pre-conversion to the new format.
+               // We need to load this query again
+               this.applySavedQuery( this.savedQueriesModel.getDefault() );
+       } else {
+               // There are either recognized parameters in the URL
+               // or there are none, but there is also no default
+               // saved query (so defaults are from the backend)
+               // We want to update the state but not fetch results
+               // again
+               this.updateStateFromUrl( false );
+
+               pieces = this._extractChangesListInfo( $( '#mw-content-text' ) );
+
+               // Update the changes list with the existing data
+               // so it gets processed
+               this.changesListModel.update(
+                       pieces.changes,
+                       pieces.fieldset,
+                       pieces.noResultsDetails,
+                       true // We're using existing DOM elements
+               );
+       }
+
+       this.initialized = true;
+       this.switchView( 'default' );
+
+       if ( this.pollingRate ) {
+               this._scheduleLiveUpdate();
+       }
+};
+
+/**
+ * Check if the controller has finished initializing.
+ * @return {boolean} Controller is initialized
+ */
+Controller.prototype.isInitialized = function () {
+       return this.initialized;
+};
+
+/**
+ * Extracts information from the changes list DOM
+ *
+ * @param {jQuery} $root Root DOM to find children from
+ * @param {boolean} [statusCode] Server response status code
+ * @return {Object} Information about changes list
+ * @return {Object|string} return.changes Changes list, or 'NO_RESULTS' if there are no results
+ *   (either normally or as an error)
+ * @return {string} [return.noResultsDetails] 'NO_RESULTS_NORMAL' for a normal 0-result set,
+ *   'NO_RESULTS_TIMEOUT' for no results due to a timeout, or omitted for more than 0 results
+ * @return {jQuery} return.fieldset Fieldset
+ */
+Controller.prototype._extractChangesListInfo = function ( $root, statusCode ) {
+       var info,
+               $changesListContents = $root.find( '.mw-changeslist' ).first().contents(),
+               areResults = !!$changesListContents.length,
+               checkForLogout = !areResults && statusCode === 200;
+
+       // We check if user logged out on different tab/browser or the session has expired.
+       // 205 status code returned from the server, which indicates that we need to reload the page
+       // is not usable on WL page, because we get redirected to login page, which gives 200 OK
+       // status code (if everything else goes well).
+       // Bug: T177717
+       if ( checkForLogout && !!$root.find( '#wpName1' ).length ) {
+               location.reload( false );
+               return;
+       }
+
+       info = {
+               changes: $changesListContents.length ? $changesListContents : 'NO_RESULTS',
+               fieldset: $root.find( 'fieldset.cloptions' ).first()
        };
 
-       /**
-        * Update the selected state of a filter
-        *
-        * @param {string} filterName Filter name
-        * @param {boolean} [isSelected] Filter selected state
-        */
-       Controller.prototype.toggleFilterSelect = function ( filterName, isSelected ) {
-               var filterItem = this.filtersModel.getItemByName( filterName );
-
-               if ( !filterItem ) {
-                       // If no filter was found, break
-                       return;
-               }
-
-               isSelected = isSelected === undefined ? !filterItem.isSelected() : isSelected;
-
-               if ( filterItem.isSelected() !== isSelected ) {
-                       this.filtersModel.toggleFilterSelected( filterName, isSelected );
-
-                       this.updateChangesList();
-
-                       // Check filter interactions
-                       this.filtersModel.reassessFilterInteractions( filterItem );
+       if ( !areResults ) {
+               if ( $root.find( '.mw-changeslist-timeout' ).length ) {
+                       info.noResultsDetails = 'NO_RESULTS_TIMEOUT';
+               } else if ( $root.find( '.mw-changeslist-notargetpage' ).length ) {
+                       info.noResultsDetails = 'NO_RESULTS_NO_TARGET_PAGE';
+               } else if ( $root.find( '.mw-changeslist-invalidtargetpage' ).length ) {
+                       info.noResultsDetails = 'NO_RESULTS_INVALID_TARGET_PAGE';
+               } else {
+                       info.noResultsDetails = 'NO_RESULTS_NORMAL';
                }
+       }
+
+       return info;
+};
+
+/**
+ * Create filter data from a number, for the filters that are numerical value
+ *
+ * @param {number} num Number
+ * @param {number} numForDisplay Number for the label
+ * @return {Object} Filter data
+ */
+Controller.prototype._createFilterDataFromNumber = function ( num, numForDisplay ) {
+       return {
+               name: String( num ),
+               label: mw.language.convertNumber( numForDisplay )
        };
-
-       /**
-        * Clear both highlight and selection of a filter
-        *
-        * @param {string} filterName Name of the filter item
-        */
-       Controller.prototype.clearFilter = function ( filterName ) {
-               var filterItem = this.filtersModel.getItemByName( filterName ),
-                       isHighlighted = filterItem.isHighlighted(),
-                       isSelected = filterItem.isSelected();
-
-               if ( isSelected || isHighlighted ) {
-                       this.filtersModel.clearHighlightColor( filterName );
-                       this.filtersModel.toggleFilterSelected( filterName, false );
-
-                       if ( isSelected ) {
-                               // Only update the changes list if the filter changed
-                               // its selection state. If it only changed its highlight
-                               // then don't reload
-                               this.updateChangesList();
+};
+
+/**
+ * Add an arbitrary values to groups that allow arbitrary values
+ *
+ * @param {Object} groupData Group data
+ * @param {string|string[]} arbitraryValues An array of arbitrary values to add to the group
+ */
+Controller.prototype.addNumberValuesToGroup = function ( groupData, arbitraryValues ) {
+       var controller = this,
+               normalizeWithinRange = function ( range, val ) {
+                       if ( val < range.min ) {
+                               return range.min; // Min
+                       } else if ( val >= range.max ) {
+                               return range.max; // Max
                        }
+                       return val;
+               };
 
-                       this.filtersModel.reassessFilterInteractions( filterItem );
-
-                       // Log filter grouping
-                       this.trackFilterGroupings( 'removefilter' );
-               }
-
-               if ( isHighlighted ) {
-                       this._trackHighlight( 'clear', filterName );
-               }
-       };
+       arbitraryValues = Array.isArray( arbitraryValues ) ? arbitraryValues : [ arbitraryValues ];
 
-       /**
-        * Toggle the highlight feature on and off
-        */
-       Controller.prototype.toggleHighlight = function () {
-               this.filtersModel.toggleHighlight();
-               this.uriProcessor.updateURL();
+       // Normalize the arbitrary values and the default value for a range
+       if ( groupData.range ) {
+               arbitraryValues = arbitraryValues.map( function ( val ) {
+                       return normalizeWithinRange( groupData.range, val );
+               } );
 
-               if ( this.filtersModel.isHighlightEnabled() ) {
-                       mw.hook( 'RcFilters.highlight.enable' ).fire();
+               // Normalize the default, since that's user defined
+               if ( groupData.default !== undefined ) {
+                       groupData.default = String( normalizeWithinRange( groupData.range, groupData.default ) );
                }
-       };
+       }
 
-       /**
-        * Toggle the namespaces inverted feature on and off
-        */
-       Controller.prototype.toggleInvertedNamespaces = function () {
-               this.filtersModel.toggleInvertedNamespaces();
+       // This is only true for single_option group
+       // We assume these are the only groups that will allow for
+       // arbitrary, since it doesn't make any sense for the other
+       // groups.
+       arbitraryValues.forEach( function ( val ) {
                if (
-                       this.filtersModel.getFiltersByView( 'namespaces' ).filter(
-                               function ( filterItem ) { return filterItem.isSelected(); }
-                       ).length
+                       // If the group allows for arbitrary data
+                       groupData.allowArbitrary &&
+                       // and it is single_option (or string_options, but we
+                       // don't have cases of those yet, nor do we plan to)
+                       groupData.type === 'single_option' &&
+                       // and, if there is a validate method and it passes on
+                       // the data
+                       ( !groupData.validate || groupData.validate( val ) ) &&
+                       // but if that value isn't already in the definition
+                       groupData.filters
+                               .map( function ( filterData ) {
+                                       return String( filterData.name );
+                               } )
+                               .indexOf( String( val ) ) === -1
                ) {
-                       // Only re-fetch results if there are namespace items that are actually selected
-                       this.updateChangesList();
-               } else {
-                       this.uriProcessor.updateURL();
-               }
-       };
-
-       /**
-        * Set the value of the 'showlinkedto' parameter
-        * @param {boolean} value
-        */
-       Controller.prototype.setShowLinkedTo = function ( value ) {
-               var targetItem = this.filtersModel.getGroup( 'page' ).getItemByParamName( 'target' ),
-                       showLinkedToItem = this.filtersModel.getGroup( 'toOrFrom' ).getItemByParamName( 'showlinkedto' );
-
-               this.filtersModel.toggleFilterSelected( showLinkedToItem.getName(), value );
-               this.uriProcessor.updateURL();
-               // reload the results only when target is set
-               if ( targetItem.getValue() ) {
-                       this.updateChangesList();
+                       // Add the filter information
+                       groupData.filters.push( controller._createFilterDataFromNumber(
+                               val,
+                               groupData.numToLabelFunc ?
+                                       groupData.numToLabelFunc( val ) :
+                                       val
+                       ) );
+
+                       // If there's a sort function set up, re-sort the values
+                       if ( groupData.sortFunc ) {
+                               groupData.filters.sort( groupData.sortFunc );
+                       }
                }
-       };
-
-       /**
-        * Set the target page
-        * @param {string} page
       */
-       Controller.prototype.setTargetPage = function ( page ) {
-               var targetItem = this.filtersModel.getGroup( 'page' ).getItemByParamName( 'target' );
-               targetItem.setValue( page );
-               this.uriProcessor.updateURL();
+       } );
+};
+
+/**
+ * Reset to default filters
+ */
+Controller.prototype.resetToDefaults = function () {
+       var params = this._getDefaultParams();
+       if ( this.applyParamChange( params ) ) {
+               // Only update the changes list if there was a change to actual filters
                this.updateChangesList();
-       };
-
-       /**
-        * Set the highlight color for a filter item
-        *
-        * @param {string} filterName Name of the filter item
-        * @param {string} color Selected color
-        */
-       Controller.prototype.setHighlightColor = function ( filterName, color ) {
-               this.filtersModel.setHighlightColor( filterName, color );
-               this.uriProcessor.updateURL();
-               this._trackHighlight( 'set', { name: filterName, color: color } );
-       };
-
-       /**
-        * Clear highlight for a filter item
-        *
-        * @param {string} filterName Name of the filter item
-        */
-       Controller.prototype.clearHighlightColor = function ( filterName ) {
-               this.filtersModel.clearHighlightColor( filterName );
+       } else {
+               this.uriProcessor.updateURL( params );
+       }
+};
+
+/**
+ * Check whether the default values of the filters are all false.
+ *
+ * @return {boolean} Defaults are all false
+ */
+Controller.prototype.areDefaultsEmpty = function () {
+       return $.isEmptyObject( this._getDefaultParams() );
+};
+
+/**
+ * Empty all selected filters
+ */
+Controller.prototype.emptyFilters = function () {
+       var highlightedFilterNames = this.filtersModel.getHighlightedItems()
+               .map( function ( filterItem ) { return { name: filterItem.getName() }; } );
+
+       if ( this.applyParamChange( {} ) ) {
+               // Only update the changes list if there was a change to actual filters
+               this.updateChangesList();
+       } else {
                this.uriProcessor.updateURL();
-               this._trackHighlight( 'clear', filterName );
-       };
+       }
 
-       /**
-        * Enable or disable live updates.
-        * @param {boolean} enable True to enable, false to disable
-        */
-       Controller.prototype.toggleLiveUpdate = function ( enable ) {
-               this.changesListModel.toggleLiveUpdate( enable );
-               if ( this.changesListModel.getLiveUpdate() && this.changesListModel.getNewChangesExist() ) {
-                       this.updateChangesList( null, this.LIVE_UPDATE );
-               }
-       };
+       if ( highlightedFilterNames ) {
+               this._trackHighlight( 'clearAll', highlightedFilterNames );
+       }
+};
 
-       /**
-        * Set a timeout for the next live update.
-        * @private
-        */
-       Controller.prototype._scheduleLiveUpdate = function () {
-               setTimeout( this._doLiveUpdate.bind( this ), this.pollingRate * 1000 );
-       };
+/**
+ * Update the selected state of a filter
+ *
+ * @param {string} filterName Filter name
+ * @param {boolean} [isSelected] Filter selected state
+ */
+Controller.prototype.toggleFilterSelect = function ( filterName, isSelected ) {
+       var filterItem = this.filtersModel.getItemByName( filterName );
 
-       /**
-        * Perform a live update.
-        * @private
-        */
-       Controller.prototype._doLiveUpdate = function () {
-               if ( !this._shouldCheckForNewChanges() ) {
-                       // skip this turn and check back later
-                       this._scheduleLiveUpdate();
-                       return;
-               }
+       if ( !filterItem ) {
+               // If no filter was found, break
+               return;
+       }
 
-               this._checkForNewChanges()
-                       .then( function ( statusCode ) {
-                               // no result is 204 with the 'peek' param
-                               // logged out is 205
-                               var newChanges = statusCode === 200;
+       isSelected = isSelected === undefined ? !filterItem.isSelected() : isSelected;
 
-                               if ( !this._shouldCheckForNewChanges() ) {
-                                       // by the time the response is received,
-                                       // it may not be appropriate anymore
-                                       return;
-                               }
+       if ( filterItem.isSelected() !== isSelected ) {
+               this.filtersModel.toggleFilterSelected( filterName, isSelected );
 
-                               // 205 is the status code returned from server when user's logged in/out
-                               // status is not matching while fetching live update changes.
-                               // This works only on Recent Changes page. For WL, look _extractChangesListInfo.
-                               // Bug: T177717
-                               if ( statusCode === 205 ) {
-                                       location.reload( false );
-                                       return;
-                               }
-
-                               if ( newChanges ) {
-                                       if ( this.changesListModel.getLiveUpdate() ) {
-                                               return this.updateChangesList( null, this.LIVE_UPDATE );
-                                       } else {
-                                               this.changesListModel.setNewChangesExist( true );
-                                       }
-                               }
-                       }.bind( this ) )
-                       .always( this._scheduleLiveUpdate.bind( this ) );
-       };
-
-       /**
-        * @return {boolean} It's appropriate to check for new changes now
-        * @private
-        */
-       Controller.prototype._shouldCheckForNewChanges = function () {
-               return !document.hidden &&
-                       !this.filtersModel.hasConflict() &&
-                       !this.changesListModel.getNewChangesExist() &&
-                       !this.updatingChangesList &&
-                       this.changesListModel.getNextFrom();
-       };
-
-       /**
-        * Check if new changes, newer than those currently shown, are available
-        *
-        * @return {jQuery.Promise} Promise object that resolves with a bool
-        *   specifying if there are new changes or not
-        *
-        * @private
-        */
-       Controller.prototype._checkForNewChanges = function () {
-               var params = {
-                       limit: 1,
-                       peek: 1, // bypasses ChangesList specific UI
-                       from: this.changesListModel.getNextFrom(),
-                       isAnon: mw.user.isAnon()
-               };
-               return this._queryChangesList( 'liveUpdate', params ).then(
-                       function ( data ) {
-                               return data.status;
-                       }
-               );
-       };
-
-       /**
-        * Show the new changes
-        *
-        * @return {jQuery.Promise} Promise object that resolves after
-        * fetching and showing the new changes
-        */
-       Controller.prototype.showNewChanges = function () {
-               return this.updateChangesList( null, this.SHOW_NEW_CHANGES );
-       };
-
-       /**
-        * Save the current model state as a saved query
-        *
-        * @param {string} [label] Label of the saved query
-        * @param {boolean} [setAsDefault=false] This query should be set as the default
-        */
-       Controller.prototype.saveCurrentQuery = function ( label, setAsDefault ) {
-               // Add item
-               this.savedQueriesModel.addNewQuery(
-                       label || mw.msg( 'rcfilters-savedqueries-defaultlabel' ),
-                       this.filtersModel.getCurrentParameterState( true ),
-                       setAsDefault
-               );
-
-               // Save item
-               this._saveSavedQueries();
-       };
-
-       /**
-        * Remove a saved query
-        *
-        * @param {string} queryID Query id
-        */
-       Controller.prototype.removeSavedQuery = function ( queryID ) {
-               this.savedQueriesModel.removeQuery( queryID );
-
-               this._saveSavedQueries();
-       };
-
-       /**
-        * Rename a saved query
-        *
-        * @param {string} queryID Query id
-        * @param {string} newLabel New label for the query
-        */
-       Controller.prototype.renameSavedQuery = function ( queryID, newLabel ) {
-               var queryItem = this.savedQueriesModel.getItemByID( queryID );
-
-               if ( queryItem ) {
-                       queryItem.updateLabel( newLabel );
-               }
-               this._saveSavedQueries();
-       };
-
-       /**
-        * Set a saved query as default
-        *
-        * @param {string} queryID Query Id. If null is given, default
-        *  query is reset.
-        */
-       Controller.prototype.setDefaultSavedQuery = function ( queryID ) {
-               this.savedQueriesModel.setDefault( queryID );
-               this._saveSavedQueries();
-       };
-
-       /**
-        * Load a saved query
-        *
-        * @param {string} queryID Query id
-        */
-       Controller.prototype.applySavedQuery = function ( queryID ) {
-               var currentMatchingQuery,
-                       params = this.savedQueriesModel.getItemParams( queryID );
-
-               currentMatchingQuery = this.findQueryMatchingCurrentState();
+               this.updateChangesList();
 
-               if (
-                       currentMatchingQuery &&
-                       currentMatchingQuery.getID() === queryID
-               ) {
-                       // If the query we want to load is the one that is already
-                       // loaded, don't reload it
-                       return;
-               }
+               // Check filter interactions
+               this.filtersModel.reassessFilterInteractions( filterItem );
+       }
+};
+
+/**
+ * Clear both highlight and selection of a filter
+ *
+ * @param {string} filterName Name of the filter item
+ */
+Controller.prototype.clearFilter = function ( filterName ) {
+       var filterItem = this.filtersModel.getItemByName( filterName ),
+               isHighlighted = filterItem.isHighlighted(),
+               isSelected = filterItem.isSelected();
+
+       if ( isSelected || isHighlighted ) {
+               this.filtersModel.clearHighlightColor( filterName );
+               this.filtersModel.toggleFilterSelected( filterName, false );
 
-               if ( this.applyParamChange( params ) ) {
-                       // Update changes list only if there was a difference in filter selection
+               if ( isSelected ) {
+                       // Only update the changes list if the filter changed
+                       // its selection state. If it only changed its highlight
+                       // then don't reload
                        this.updateChangesList();
-               } else {
-                       this.uriProcessor.updateURL( params );
-               }
-
-               // Log filter grouping
-               this.trackFilterGroupings( 'savedfilters' );
-       };
-
-       /**
-        * Check whether the current filter and highlight state exists
-        * in the saved queries model.
-        *
-        * @return {mw.rcfilters.dm.SavedQueryItemModel} Matching item model
-        */
-       Controller.prototype.findQueryMatchingCurrentState = function () {
-               return this.savedQueriesModel.findMatchingQuery(
-                       this.filtersModel.getCurrentParameterState( true )
-               );
-       };
-
-       /**
-        * Save the current state of the saved queries model with all
-        * query item representation in the user settings.
-        */
-       Controller.prototype._saveSavedQueries = function () {
-               var stringified, oldPrefValue,
-                       backupPrefName = this.savedQueriesPreferenceName + '-versionbackup',
-                       state = this.savedQueriesModel.getState();
-
-               // Stringify state
-               stringified = JSON.stringify( state );
-
-               if ( byteLength( stringified ) > 65535 ) {
-                       // Sanity check, since the preference can only hold that.
-                       return;
                }
 
-               if ( !this.wereSavedQueriesSaved && this.savedQueriesModel.isConverted() ) {
-                       // The queries were converted from the previous version
-                       // Keep the old string in the [prefname]-versionbackup
-                       oldPrefValue = mw.user.options.get( this.savedQueriesPreferenceName );
+               this.filtersModel.reassessFilterInteractions( filterItem );
 
-                       // Save the old preference in the backup preference
-                       new mw.Api().saveOption( backupPrefName, oldPrefValue );
-                       // Update the preference for this session
-                       mw.user.options.set( backupPrefName, oldPrefValue );
-               }
-
-               // Save the preference
-               new mw.Api().saveOption( this.savedQueriesPreferenceName, stringified );
-               // Update the preference for this session
-               mw.user.options.set( this.savedQueriesPreferenceName, stringified );
-
-               // Tag as already saved so we don't do this again
-               this.wereSavedQueriesSaved = true;
-       };
-
-       /**
-        * Update sticky preferences with current model state
-        */
-       Controller.prototype.updateStickyPreferences = function () {
-               // Update default sticky values with selected, whether they came from
-               // the initial defaults or from the URL value that is being normalized
-               this.updateDaysDefault( this.filtersModel.getGroup( 'days' ).findSelectedItems()[ 0 ].getParamName() );
-               this.updateLimitDefault( this.filtersModel.getGroup( 'limit' ).findSelectedItems()[ 0 ].getParamName() );
-
-               // TODO: Make these automatic by having the model go over sticky
-               // items and update their default values automatically
-       };
-
-       /**
-        * Update the limit default value
-        *
-        * @param {number} newValue New value
-        */
-       Controller.prototype.updateLimitDefault = function ( newValue ) {
-               this.updateNumericPreference( this.limitPreferenceName, newValue );
-       };
-
-       /**
-        * Update the days default value
-        *
-        * @param {number} newValue New value
-        */
-       Controller.prototype.updateDaysDefault = function ( newValue ) {
-               this.updateNumericPreference( this.daysPreferenceName, newValue );
-       };
-
-       /**
-        * Update the group by page default value
-        *
-        * @param {boolean} newValue New value
-        */
-       Controller.prototype.updateGroupByPageDefault = function ( newValue ) {
-               this.updateNumericPreference( 'usenewrc', Number( newValue ) );
-       };
-
-       /**
-        * Update the collapsed state value
-        *
-        * @param {boolean} isCollapsed Filter area is collapsed
-        */
-       Controller.prototype.updateCollapsedState = function ( isCollapsed ) {
-               this.updateNumericPreference( this.collapsedPreferenceName, Number( isCollapsed ) );
-       };
-
-       /**
-        * Update a numeric preference with a new value
-        *
-        * @param {string} prefName Preference name
-        * @param {number|string} newValue New value
-        */
-       Controller.prototype.updateNumericPreference = function ( prefName, newValue ) {
-               // FIXME: $.isNumeric is deprecated
-               // eslint-disable-next-line no-jquery/no-is-numeric
-               if ( !$.isNumeric( newValue ) ) {
-                       return;
-               }
-
-               newValue = Number( newValue );
-
-               if ( mw.user.options.get( prefName ) !== newValue ) {
-                       // Save the preference
-                       new mw.Api().saveOption( prefName, newValue );
-                       // Update the preference for this session
-                       mw.user.options.set( prefName, newValue );
-               }
-       };
+               // Log filter grouping
+               this.trackFilterGroupings( 'removefilter' );
+       }
 
-       /**
-        * Synchronize the URL with the current state of the filters
-        * without adding an history entry.
-        */
-       Controller.prototype.replaceUrl = function () {
+       if ( isHighlighted ) {
+               this._trackHighlight( 'clear', filterName );
+       }
+};
+
+/**
+ * Toggle the highlight feature on and off
+ */
+Controller.prototype.toggleHighlight = function () {
+       this.filtersModel.toggleHighlight();
+       this.uriProcessor.updateURL();
+
+       if ( this.filtersModel.isHighlightEnabled() ) {
+               mw.hook( 'RcFilters.highlight.enable' ).fire();
+       }
+};
+
+/**
+ * Toggle the namespaces inverted feature on and off
+ */
+Controller.prototype.toggleInvertedNamespaces = function () {
+       this.filtersModel.toggleInvertedNamespaces();
+       if (
+               this.filtersModel.getFiltersByView( 'namespaces' ).filter(
+                       function ( filterItem ) { return filterItem.isSelected(); }
+               ).length
+       ) {
+               // Only re-fetch results if there are namespace items that are actually selected
+               this.updateChangesList();
+       } else {
                this.uriProcessor.updateURL();
-       };
-
-       /**
-        * Update filter state (selection and highlighting) based
-        * on current URL values.
-        *
-        * @param {boolean} [fetchChangesList=true] Fetch new results into the changes
-        *  list based on the updated model.
-        */
-       Controller.prototype.updateStateFromUrl = function ( fetchChangesList ) {
-               fetchChangesList = fetchChangesList === undefined ? true : !!fetchChangesList;
-
-               this.uriProcessor.updateModelBasedOnQuery();
-
-               // Update the sticky preferences, in case we received a value
-               // from the URL
-               this.updateStickyPreferences();
+       }
+};
+
+/**
+ * Set the value of the 'showlinkedto' parameter
+ * @param {boolean} value
+ */
+Controller.prototype.setShowLinkedTo = function ( value ) {
+       var targetItem = this.filtersModel.getGroup( 'page' ).getItemByParamName( 'target' ),
+               showLinkedToItem = this.filtersModel.getGroup( 'toOrFrom' ).getItemByParamName( 'showlinkedto' );
+
+       this.filtersModel.toggleFilterSelected( showLinkedToItem.getName(), value );
+       this.uriProcessor.updateURL();
+       // reload the results only when target is set
+       if ( targetItem.getValue() ) {
+               this.updateChangesList();
+       }
+};
+
+/**
+ * Set the target page
+ * @param {string} page
+ */
+Controller.prototype.setTargetPage = function ( page ) {
+       var targetItem = this.filtersModel.getGroup( 'page' ).getItemByParamName( 'target' );
+       targetItem.setValue( page );
+       this.uriProcessor.updateURL();
+       this.updateChangesList();
+};
+
+/**
+ * Set the highlight color for a filter item
+ *
+ * @param {string} filterName Name of the filter item
+ * @param {string} color Selected color
+ */
+Controller.prototype.setHighlightColor = function ( filterName, color ) {
+       this.filtersModel.setHighlightColor( filterName, color );
+       this.uriProcessor.updateURL();
+       this._trackHighlight( 'set', { name: filterName, color: color } );
+};
+
+/**
+ * Clear highlight for a filter item
+ *
+ * @param {string} filterName Name of the filter item
+ */
+Controller.prototype.clearHighlightColor = function ( filterName ) {
+       this.filtersModel.clearHighlightColor( filterName );
+       this.uriProcessor.updateURL();
+       this._trackHighlight( 'clear', filterName );
+};
+
+/**
+ * Enable or disable live updates.
+ * @param {boolean} enable True to enable, false to disable
+ */
+Controller.prototype.toggleLiveUpdate = function ( enable ) {
+       this.changesListModel.toggleLiveUpdate( enable );
+       if ( this.changesListModel.getLiveUpdate() && this.changesListModel.getNewChangesExist() ) {
+               this.updateChangesList( null, this.LIVE_UPDATE );
+       }
+};
+
+/**
+ * Set a timeout for the next live update.
+ * @private
+ */
+Controller.prototype._scheduleLiveUpdate = function () {
+       setTimeout( this._doLiveUpdate.bind( this ), this.pollingRate * 1000 );
+};
+
+/**
+ * Perform a live update.
+ * @private
+ */
+Controller.prototype._doLiveUpdate = function () {
+       if ( !this._shouldCheckForNewChanges() ) {
+               // skip this turn and check back later
+               this._scheduleLiveUpdate();
+               return;
+       }
+
+       this._checkForNewChanges()
+               .then( function ( statusCode ) {
+                       // no result is 204 with the 'peek' param
+                       // logged out is 205
+                       var newChanges = statusCode === 200;
+
+                       if ( !this._shouldCheckForNewChanges() ) {
+                               // by the time the response is received,
+                               // it may not be appropriate anymore
+                               return;
+                       }
 
-               // Only update and fetch new results if it is requested
-               if ( fetchChangesList ) {
-                       this.updateChangesList();
-               }
-       };
+                       // 205 is the status code returned from server when user's logged in/out
+                       // status is not matching while fetching live update changes.
+                       // This works only on Recent Changes page. For WL, look _extractChangesListInfo.
+                       // Bug: T177717
+                       if ( statusCode === 205 ) {
+                               location.reload( false );
+                               return;
+                       }
 
-       /**
-        * Update the list of changes and notify the model
-        *
-        * @param {Object} [params] Extra parameters to add to the API call
-        * @param {string} [updateMode='filterChange'] One of 'filterChange', 'liveUpdate', 'showNewChanges', 'markSeen'
-        * @return {jQuery.Promise} Promise that is resolved when the update is complete
-        */
-       Controller.prototype.updateChangesList = function ( params, updateMode ) {
-               updateMode = updateMode === undefined ? this.FILTER_CHANGE : updateMode;
-
-               if ( updateMode === this.FILTER_CHANGE ) {
-                       this.uriProcessor.updateURL( params );
-               }
-               if ( updateMode === this.FILTER_CHANGE || updateMode === this.SHOW_NEW_CHANGES ) {
-                       this.changesListModel.invalidate();
-               }
-               this.changesListModel.setNewChangesExist( false );
-               this.updatingChangesList = true;
-               return this._fetchChangesList()
-                       .then(
-                               // Success
-                               function ( pieces ) {
-                                       var $changesListContent = pieces.changes,
-                                               $fieldset = pieces.fieldset;
-                                       this.changesListModel.update(
-                                               $changesListContent,
-                                               $fieldset,
-                                               pieces.noResultsDetails,
-                                               false,
-                                               // separator between old and new changes
-                                               updateMode === this.SHOW_NEW_CHANGES || updateMode === this.LIVE_UPDATE
-                                       );
-                               }.bind( this )
-                               // Do nothing for failure
-                       )
-                       .always( function () {
-                               this.updatingChangesList = false;
-                       }.bind( this ) );
+                       if ( newChanges ) {
+                               if ( this.changesListModel.getLiveUpdate() ) {
+                                       return this.updateChangesList( null, this.LIVE_UPDATE );
+                               } else {
+                                       this.changesListModel.setNewChangesExist( true );
+                               }
+                       }
+               }.bind( this ) )
+               .always( this._scheduleLiveUpdate.bind( this ) );
+};
+
+/**
+ * @return {boolean} It's appropriate to check for new changes now
+ * @private
+ */
+Controller.prototype._shouldCheckForNewChanges = function () {
+       return !document.hidden &&
+               !this.filtersModel.hasConflict() &&
+               !this.changesListModel.getNewChangesExist() &&
+               !this.updatingChangesList &&
+               this.changesListModel.getNextFrom();
+};
+
+/**
+ * Check if new changes, newer than those currently shown, are available
+ *
+ * @return {jQuery.Promise} Promise object that resolves with a bool
+ *   specifying if there are new changes or not
+ *
+ * @private
+ */
+Controller.prototype._checkForNewChanges = function () {
+       var params = {
+               limit: 1,
+               peek: 1, // bypasses ChangesList specific UI
+               from: this.changesListModel.getNextFrom(),
+               isAnon: mw.user.isAnon()
        };
-
-       /**
-        * Get an object representing the default parameter state, whether
-        * it is from the model defaults or from the saved queries.
-        *
-        * @return {Object} Default parameters
-        */
-       Controller.prototype._getDefaultParams = function () {
-               if ( this.savedQueriesModel.getDefault() ) {
-                       return this.savedQueriesModel.getDefaultParams();
-               } else {
-                       return this.filtersModel.getDefaultParams();
+       return this._queryChangesList( 'liveUpdate', params ).then(
+               function ( data ) {
+                       return data.status;
                }
-       };
+       );
+};
+
+/**
+ * Show the new changes
+ *
+ * @return {jQuery.Promise} Promise object that resolves after
+ * fetching and showing the new changes
+ */
+Controller.prototype.showNewChanges = function () {
+       return this.updateChangesList( null, this.SHOW_NEW_CHANGES );
+};
+
+/**
+ * Save the current model state as a saved query
+ *
+ * @param {string} [label] Label of the saved query
+ * @param {boolean} [setAsDefault=false] This query should be set as the default
+ */
+Controller.prototype.saveCurrentQuery = function ( label, setAsDefault ) {
+       // Add item
+       this.savedQueriesModel.addNewQuery(
+               label || mw.msg( 'rcfilters-savedqueries-defaultlabel' ),
+               this.filtersModel.getCurrentParameterState( true ),
+               setAsDefault
+       );
+
+       // Save item
+       this._saveSavedQueries();
+};
+
+/**
+ * Remove a saved query
+ *
+ * @param {string} queryID Query id
+ */
+Controller.prototype.removeSavedQuery = function ( queryID ) {
+       this.savedQueriesModel.removeQuery( queryID );
+
+       this._saveSavedQueries();
+};
+
+/**
+ * Rename a saved query
+ *
+ * @param {string} queryID Query id
+ * @param {string} newLabel New label for the query
+ */
+Controller.prototype.renameSavedQuery = function ( queryID, newLabel ) {
+       var queryItem = this.savedQueriesModel.getItemByID( queryID );
+
+       if ( queryItem ) {
+               queryItem.updateLabel( newLabel );
+       }
+       this._saveSavedQueries();
+};
+
+/**
+ * Set a saved query as default
+ *
+ * @param {string} queryID Query Id. If null is given, default
+ *  query is reset.
+ */
+Controller.prototype.setDefaultSavedQuery = function ( queryID ) {
+       this.savedQueriesModel.setDefault( queryID );
+       this._saveSavedQueries();
+};
+
+/**
+ * Load a saved query
+ *
+ * @param {string} queryID Query id
+ */
+Controller.prototype.applySavedQuery = function ( queryID ) {
+       var currentMatchingQuery,
+               params = this.savedQueriesModel.getItemParams( queryID );
+
+       currentMatchingQuery = this.findQueryMatchingCurrentState();
+
+       if (
+               currentMatchingQuery &&
+               currentMatchingQuery.getID() === queryID
+       ) {
+               // If the query we want to load is the one that is already
+               // loaded, don't reload it
+               return;
+       }
+
+       if ( this.applyParamChange( params ) ) {
+               // Update changes list only if there was a difference in filter selection
+               this.updateChangesList();
+       } else {
+               this.uriProcessor.updateURL( params );
+       }
+
+       // Log filter grouping
+       this.trackFilterGroupings( 'savedfilters' );
+};
+
+/**
+ * Check whether the current filter and highlight state exists
+ * in the saved queries model.
+ *
+ * @return {mw.rcfilters.dm.SavedQueryItemModel} Matching item model
+ */
+Controller.prototype.findQueryMatchingCurrentState = function () {
+       return this.savedQueriesModel.findMatchingQuery(
+               this.filtersModel.getCurrentParameterState( true )
+       );
+};
+
+/**
+ * Save the current state of the saved queries model with all
+ * query item representation in the user settings.
+ */
+Controller.prototype._saveSavedQueries = function () {
+       var stringified, oldPrefValue,
+               backupPrefName = this.savedQueriesPreferenceName + '-versionbackup',
+               state = this.savedQueriesModel.getState();
+
+       // Stringify state
+       stringified = JSON.stringify( state );
+
+       if ( byteLength( stringified ) > 65535 ) {
+               // Sanity check, since the preference can only hold that.
+               return;
+       }
+
+       if ( !this.wereSavedQueriesSaved && this.savedQueriesModel.isConverted() ) {
+               // The queries were converted from the previous version
+               // Keep the old string in the [prefname]-versionbackup
+               oldPrefValue = mw.user.options.get( this.savedQueriesPreferenceName );
+
+               // Save the old preference in the backup preference
+               new mw.Api().saveOption( backupPrefName, oldPrefValue );
+               // Update the preference for this session
+               mw.user.options.set( backupPrefName, oldPrefValue );
+       }
+
+       // Save the preference
+       new mw.Api().saveOption( this.savedQueriesPreferenceName, stringified );
+       // Update the preference for this session
+       mw.user.options.set( this.savedQueriesPreferenceName, stringified );
+
+       // Tag as already saved so we don't do this again
+       this.wereSavedQueriesSaved = true;
+};
+
+/**
+ * Update sticky preferences with current model state
+ */
+Controller.prototype.updateStickyPreferences = function () {
+       // Update default sticky values with selected, whether they came from
+       // the initial defaults or from the URL value that is being normalized
+       this.updateDaysDefault( this.filtersModel.getGroup( 'days' ).findSelectedItems()[ 0 ].getParamName() );
+       this.updateLimitDefault( this.filtersModel.getGroup( 'limit' ).findSelectedItems()[ 0 ].getParamName() );
+
+       // TODO: Make these automatic by having the model go over sticky
+       // items and update their default values automatically
+};
+
+/**
+ * Update the limit default value
+ *
+ * @param {number} newValue New value
+ */
+Controller.prototype.updateLimitDefault = function ( newValue ) {
+       this.updateNumericPreference( this.limitPreferenceName, newValue );
+};
+
+/**
+ * Update the days default value
+ *
+ * @param {number} newValue New value
+ */
+Controller.prototype.updateDaysDefault = function ( newValue ) {
+       this.updateNumericPreference( this.daysPreferenceName, newValue );
+};
+
+/**
+ * Update the group by page default value
+ *
+ * @param {boolean} newValue New value
+ */
+Controller.prototype.updateGroupByPageDefault = function ( newValue ) {
+       this.updateNumericPreference( 'usenewrc', Number( newValue ) );
+};
+
+/**
+ * Update the collapsed state value
+ *
+ * @param {boolean} isCollapsed Filter area is collapsed
+ */
+Controller.prototype.updateCollapsedState = function ( isCollapsed ) {
+       this.updateNumericPreference( this.collapsedPreferenceName, Number( isCollapsed ) );
+};
+
+/**
+ * Update a numeric preference with a new value
+ *
+ * @param {string} prefName Preference name
+ * @param {number|string} newValue New value
+ */
+Controller.prototype.updateNumericPreference = function ( prefName, newValue ) {
+       // FIXME: $.isNumeric is deprecated
+       // eslint-disable-next-line no-jquery/no-is-numeric
+       if ( !$.isNumeric( newValue ) ) {
+               return;
+       }
+
+       newValue = Number( newValue );
+
+       if ( mw.user.options.get( prefName ) !== newValue ) {
+               // Save the preference
+               new mw.Api().saveOption( prefName, newValue );
+               // Update the preference for this session
+               mw.user.options.set( prefName, newValue );
+       }
+};
+
+/**
+ * Synchronize the URL with the current state of the filters
+ * without adding an history entry.
+ */
+Controller.prototype.replaceUrl = function () {
+       this.uriProcessor.updateURL();
+};
+
+/**
+ * Update filter state (selection and highlighting) based
+ * on current URL values.
+ *
+ * @param {boolean} [fetchChangesList=true] Fetch new results into the changes
+ *  list based on the updated model.
+ */
+Controller.prototype.updateStateFromUrl = function ( fetchChangesList ) {
+       fetchChangesList = fetchChangesList === undefined ? true : !!fetchChangesList;
+
+       this.uriProcessor.updateModelBasedOnQuery();
+
+       // Update the sticky preferences, in case we received a value
+       // from the URL
+       this.updateStickyPreferences();
+
+       // Only update and fetch new results if it is requested
+       if ( fetchChangesList ) {
+               this.updateChangesList();
+       }
+};
+
+/**
+ * Update the list of changes and notify the model
+ *
+ * @param {Object} [params] Extra parameters to add to the API call
+ * @param {string} [updateMode='filterChange'] One of 'filterChange', 'liveUpdate', 'showNewChanges', 'markSeen'
+ * @return {jQuery.Promise} Promise that is resolved when the update is complete
+ */
+Controller.prototype.updateChangesList = function ( params, updateMode ) {
+       updateMode = updateMode === undefined ? this.FILTER_CHANGE : updateMode;
+
+       if ( updateMode === this.FILTER_CHANGE ) {
+               this.uriProcessor.updateURL( params );
+       }
+       if ( updateMode === this.FILTER_CHANGE || updateMode === this.SHOW_NEW_CHANGES ) {
+               this.changesListModel.invalidate();
+       }
+       this.changesListModel.setNewChangesExist( false );
+       this.updatingChangesList = true;
+       return this._fetchChangesList()
+               .then(
+                       // Success
+                       function ( pieces ) {
+                               var $changesListContent = pieces.changes,
+                                       $fieldset = pieces.fieldset;
+                               this.changesListModel.update(
+                                       $changesListContent,
+                                       $fieldset,
+                                       pieces.noResultsDetails,
+                                       false,
+                                       // separator between old and new changes
+                                       updateMode === this.SHOW_NEW_CHANGES || updateMode === this.LIVE_UPDATE
+                               );
+                       }.bind( this )
+                       // Do nothing for failure
+               )
+               .always( function () {
+                       this.updatingChangesList = false;
+               }.bind( this ) );
+};
+
+/**
+ * Get an object representing the default parameter state, whether
+ * it is from the model defaults or from the saved queries.
+ *
+ * @return {Object} Default parameters
+ */
+Controller.prototype._getDefaultParams = function () {
+       if ( this.savedQueriesModel.getDefault() ) {
+               return this.savedQueriesModel.getDefaultParams();
+       } else {
+               return this.filtersModel.getDefaultParams();
+       }
+};
+
+/**
+ * Query the list of changes from the server for the current filters
+ *
+ * @param {string} counterId Id for this request. To allow concurrent requests
+ *  not to invalidate each other.
+ * @param {Object} [params={}] Parameters to add to the query
+ *
+ * @return {jQuery.Promise} Promise object resolved with { content, status }
+ */
+Controller.prototype._queryChangesList = function ( counterId, params ) {
+       var uri = this.uriProcessor.getUpdatedUri(),
+               stickyParams = this.filtersModel.getStickyParamsValues(),
+               requestId,
+               latestRequest;
+
+       params = params || {};
+       params.action = 'render'; // bypasses MW chrome
+
+       uri.extend( params );
+
+       this.requestCounter[ counterId ] = this.requestCounter[ counterId ] || 0;
+       requestId = ++this.requestCounter[ counterId ];
+       latestRequest = function () {
+               return requestId === this.requestCounter[ counterId ];
+       }.bind( this );
+
+       // Sticky parameters override the URL params
+       // this is to make sure that whether we represent
+       // the sticky params in the URL or not (they may
+       // be normalized out) the sticky parameters are
+       // always being sent to the server with their
+       // current/default values
+       uri.extend( stickyParams );
+
+       return $.ajax( uri.toString(), { contentType: 'html' } )
+               .then(
+                       function ( content, message, jqXHR ) {
+                               if ( !latestRequest() ) {
+                                       return $.Deferred().reject();
+                               }
+                               return {
+                                       content: content,
+                                       status: jqXHR.status
+                               };
+                       },
+                       // RC returns 404 when there is no results
+                       function ( jqXHR ) {
+                               if ( latestRequest() ) {
+                                       return $.Deferred().resolve(
+                                               {
+                                                       content: jqXHR.responseText,
+                                                       status: jqXHR.status
+                                               }
+                                       ).promise();
+                               }
+                       }
+               );
+};
+
+/**
+ * Fetch the list of changes from the server for the current filters
+ *
+ * @return {jQuery.Promise} Promise object that will resolve with the changes list
+ *  and the fieldset.
+ */
+Controller.prototype._fetchChangesList = function () {
+       return this._queryChangesList( 'updateChangesList' )
+               .then(
+                       function ( data ) {
+                               var $parsed;
 
-       /**
-        * Query the list of changes from the server for the current filters
-        *
-        * @param {string} counterId Id for this request. To allow concurrent requests
-        *  not to invalidate each other.
-        * @param {Object} [params={}] Parameters to add to the query
-        *
-        * @return {jQuery.Promise} Promise object resolved with { content, status }
-        */
-       Controller.prototype._queryChangesList = function ( counterId, params ) {
-               var uri = this.uriProcessor.getUpdatedUri(),
-                       stickyParams = this.filtersModel.getStickyParamsValues(),
-                       requestId,
-                       latestRequest;
-
-               params = params || {};
-               params.action = 'render'; // bypasses MW chrome
-
-               uri.extend( params );
-
-               this.requestCounter[ counterId ] = this.requestCounter[ counterId ] || 0;
-               requestId = ++this.requestCounter[ counterId ];
-               latestRequest = function () {
-                       return requestId === this.requestCounter[ counterId ];
-               }.bind( this );
-
-               // Sticky parameters override the URL params
-               // this is to make sure that whether we represent
-               // the sticky params in the URL or not (they may
-               // be normalized out) the sticky parameters are
-               // always being sent to the server with their
-               // current/default values
-               uri.extend( stickyParams );
-
-               return $.ajax( uri.toString(), { contentType: 'html' } )
-                       .then(
-                               function ( content, message, jqXHR ) {
-                                       if ( !latestRequest() ) {
-                                               return $.Deferred().reject();
-                                       }
+                               // Status code 0 is not HTTP status code,
+                               // but is valid value of XMLHttpRequest status.
+                               // It is used for variety of network errors, for example
+                               // when an AJAX call was cancelled before getting the response
+                               if ( data && data.status === 0 ) {
                                        return {
-                                               content: content,
-                                               status: jqXHR.status
+                                               changes: 'NO_RESULTS',
+                                               // We need empty result set, to avoid exceptions because of undefined value
+                                               fieldset: $( [] ),
+                                               noResultsDetails: 'NO_RESULTS_NETWORK_ERROR'
                                        };
-                               },
-                               // RC returns 404 when there is no results
-                               function ( jqXHR ) {
-                                       if ( latestRequest() ) {
-                                               return $.Deferred().resolve(
-                                                       {
-                                                               content: jqXHR.responseText,
-                                                               status: jqXHR.status
-                                                       }
-                                               ).promise();
-                                       }
                                }
-                       );
-       };
-
-       /**
-        * Fetch the list of changes from the server for the current filters
-        *
-        * @return {jQuery.Promise} Promise object that will resolve with the changes list
-        *  and the fieldset.
-        */
-       Controller.prototype._fetchChangesList = function () {
-               return this._queryChangesList( 'updateChangesList' )
-                       .then(
-                               function ( data ) {
-                                       var $parsed;
-
-                                       // Status code 0 is not HTTP status code,
-                                       // but is valid value of XMLHttpRequest status.
-                                       // It is used for variety of network errors, for example
-                                       // when an AJAX call was cancelled before getting the response
-                                       if ( data && data.status === 0 ) {
-                                               return {
-                                                       changes: 'NO_RESULTS',
-                                                       // We need empty result set, to avoid exceptions because of undefined value
-                                                       fieldset: $( [] ),
-                                                       noResultsDetails: 'NO_RESULTS_NETWORK_ERROR'
-                                               };
-                                       }
-
-                                       $parsed = $( '<div>' ).append( $( $.parseHTML(
-                                               data ? data.content : ''
-                                       ) ) );
 
-                                       return this._extractChangesListInfo( $parsed, data.status );
-                               }.bind( this )
-                       );
-       };
+                               $parsed = $( '<div>' ).append( $( $.parseHTML(
+                                       data ? data.content : ''
+                               ) ) );
 
-       /**
-        * Track usage of highlight feature
-        *
-        * @param {string} action
-        * @param {Array|Object|string} filters
-        */
-       Controller.prototype._trackHighlight = function ( action, filters ) {
-               filters = typeof filters === 'string' ? { name: filters } : filters;
-               filters = !Array.isArray( filters ) ? [ filters ] : filters;
-               mw.track(
-                       'event.ChangesListHighlights',
-                       {
-                               action: action,
-                               filters: filters,
-                               userId: mw.user.getId()
-                       }
+                               return this._extractChangesListInfo( $parsed, data.status );
+                       }.bind( this )
                );
-       };
-
-       /**
-        * Track filter grouping usage
-        *
-        * @param {string} action Action taken
-        */
-       Controller.prototype.trackFilterGroupings = function ( action ) {
-               var controller = this,
-                       rightNow = new Date().getTime(),
-                       randomIdentifier = String( mw.user.sessionId() ) + String( rightNow ) + String( Math.random() ),
-                       // Get all current filters
-                       filters = this.filtersModel.findSelectedItems().map( function ( item ) {
-                               return item.getName();
-                       } );
-
-               action = action || 'filtermenu';
-
-               // Check if these filters were the ones we just logged previously
-               // (Don't log the same grouping twice, in case the user opens/closes)
-               // the menu without action, or with the same result
-               if (
-                       // Only log if the two arrays are different in size
-                       filters.length !== this.prevLoggedItems.length ||
-                       // Or if any filters are not the same as the cached filters
-                       filters.some( function ( filterName ) {
-                               return controller.prevLoggedItems.indexOf( filterName ) === -1;
-                       } ) ||
-                       // Or if any cached filters are not the same as given filters
-                       this.prevLoggedItems.some( function ( filterName ) {
-                               return filters.indexOf( filterName ) === -1;
-                       } )
-               ) {
-                       filters.forEach( function ( filterName ) {
-                               mw.track(
-                                       'event.ChangesListFilterGrouping',
-                                       {
-                                               action: action,
-                                               groupIdentifier: randomIdentifier,
-                                               filter: filterName,
-                                               userId: mw.user.getId()
-                                       }
-                               );
-                       } );
-
-                       // Cache the filter names
-                       this.prevLoggedItems = filters;
+};
+
+/**
+ * Track usage of highlight feature
+ *
+ * @param {string} action
+ * @param {Array|Object|string} filters
+ */
+Controller.prototype._trackHighlight = function ( action, filters ) {
+       filters = typeof filters === 'string' ? { name: filters } : filters;
+       filters = !Array.isArray( filters ) ? [ filters ] : filters;
+       mw.track(
+               'event.ChangesListHighlights',
+               {
+                       action: action,
+                       filters: filters,
+                       userId: mw.user.getId()
                }
-       };
-
-       /**
-        * Apply a change of parameters to the model state, and check whether
-        * the new state is different than the old state.
-        *
-        * @param  {Object} newParamState New parameter state to apply
-        * @return {boolean} New applied model state is different than the previous state
-        */
-       Controller.prototype.applyParamChange = function ( newParamState ) {
-               var after,
-                       before = this.filtersModel.getSelectedState();
-
-               this.filtersModel.updateStateFromParams( newParamState );
-
-               after = this.filtersModel.getSelectedState();
-
-               return !OO.compare( before, after );
-       };
-
-       /**
-        * Mark all changes as seen on Watchlist
-        */
-       Controller.prototype.markAllChangesAsSeen = function () {
-               var api = new mw.Api();
-               api.postWithToken( 'csrf', {
-                       formatversion: 2,
-                       action: 'setnotificationtimestamp',
-                       entirewatchlist: true
-               } ).then( function () {
-                       this.updateChangesList( null, 'markSeen' );
-               }.bind( this ) );
-       };
-
-       /**
-        * Set the current search for the system.
-        *
-        * @param {string} searchQuery Search query, including triggers
-        */
-       Controller.prototype.setSearch = function ( searchQuery ) {
-               this.filtersModel.setSearch( searchQuery );
-       };
-
-       /**
-        * Switch the view by changing the search query trigger
-        * without changing the search term
-        *
-        * @param  {string} view View to change to
-        */
-       Controller.prototype.switchView = function ( view ) {
-               this.setSearch(
-                       this.filtersModel.getViewTrigger( view ) +
-                       this.filtersModel.removeViewTriggers( this.filtersModel.getSearch() )
-               );
-       };
+       );
+};
+
+/**
+ * Track filter grouping usage
+ *
+ * @param {string} action Action taken
+ */
+Controller.prototype.trackFilterGroupings = function ( action ) {
+       var controller = this,
+               rightNow = new Date().getTime(),
+               randomIdentifier = String( mw.user.sessionId() ) + String( rightNow ) + String( Math.random() ),
+               // Get all current filters
+               filters = this.filtersModel.findSelectedItems().map( function ( item ) {
+                       return item.getName();
+               } );
 
-       /**
-        * Reset the search for a specific view. This means we null the search query
-        * and replace it with the relevant trigger for the requested view
-        *
-        * @param  {string} [view='default'] View to change to
-        */
-       Controller.prototype.resetSearchForView = function ( view ) {
-               view = view || 'default';
-
-               this.setSearch(
-                       this.filtersModel.getViewTrigger( view )
-               );
-       };
+       action = action || 'filtermenu';
+
+       // Check if these filters were the ones we just logged previously
+       // (Don't log the same grouping twice, in case the user opens/closes)
+       // the menu without action, or with the same result
+       if (
+               // Only log if the two arrays are different in size
+               filters.length !== this.prevLoggedItems.length ||
+               // Or if any filters are not the same as the cached filters
+               filters.some( function ( filterName ) {
+                       return controller.prevLoggedItems.indexOf( filterName ) === -1;
+               } ) ||
+               // Or if any cached filters are not the same as given filters
+               this.prevLoggedItems.some( function ( filterName ) {
+                       return filters.indexOf( filterName ) === -1;
+               } )
+       ) {
+               filters.forEach( function ( filterName ) {
+                       mw.track(
+                               'event.ChangesListFilterGrouping',
+                               {
+                                       action: action,
+                                       groupIdentifier: randomIdentifier,
+                                       filter: filterName,
+                                       userId: mw.user.getId()
+                               }
+                       );
+               } );
 
-       module.exports = Controller;
-}() );
+               // Cache the filter names
+               this.prevLoggedItems = filters;
+       }
+};
+
+/**
+ * Apply a change of parameters to the model state, and check whether
+ * the new state is different than the old state.
+ *
+ * @param  {Object} newParamState New parameter state to apply
+ * @return {boolean} New applied model state is different than the previous state
+ */
+Controller.prototype.applyParamChange = function ( newParamState ) {
+       var after,
+               before = this.filtersModel.getSelectedState();
+
+       this.filtersModel.updateStateFromParams( newParamState );
+
+       after = this.filtersModel.getSelectedState();
+
+       return !OO.compare( before, after );
+};
+
+/**
+ * Mark all changes as seen on Watchlist
+ */
+Controller.prototype.markAllChangesAsSeen = function () {
+       var api = new mw.Api();
+       api.postWithToken( 'csrf', {
+               formatversion: 2,
+               action: 'setnotificationtimestamp',
+               entirewatchlist: true
+       } ).then( function () {
+               this.updateChangesList( null, 'markSeen' );
+       }.bind( this ) );
+};
+
+/**
+ * Set the current search for the system.
+ *
+ * @param {string} searchQuery Search query, including triggers
+ */
+Controller.prototype.setSearch = function ( searchQuery ) {
+       this.filtersModel.setSearch( searchQuery );
+};
+
+/**
+ * Switch the view by changing the search query trigger
+ * without changing the search term
+ *
+ * @param  {string} view View to change to
+ */
+Controller.prototype.switchView = function ( view ) {
+       this.setSearch(
+               this.filtersModel.getViewTrigger( view ) +
+               this.filtersModel.removeViewTriggers( this.filtersModel.getSearch() )
+       );
+};
+
+/**
+ * Reset the search for a specific view. This means we null the search query
+ * and replace it with the relevant trigger for the requested view
+ *
+ * @param  {string} [view='default'] View to change to
+ */
+Controller.prototype.resetSearchForView = function ( view ) {
+       view = view || 'default';
+
+       this.setSearch(
+               this.filtersModel.getViewTrigger( view )
+       );
+};
+
+module.exports = Controller;
index a4ef73b..42bfae6 100644 (file)
@@ -1,12 +1,10 @@
-( function () {
-       /**
-        * Supported highlight colors.
-        * Warning: These are also hardcoded in "styles/mw.rcfilters.variables.less"
-        *
-        * @member mw.rcfilters
-        * @property {string[]}
-        */
-       var HighlightColors = [ 'c1', 'c2', 'c3', 'c4', 'c5' ];
+/**
+ * Supported highlight colors.
+ * Warning: These are also hardcoded in "styles/mw.rcfilters.variables.less"
+ *
+ * @member mw.rcfilters
+ * @property {string[]}
+ */
+var HighlightColors = [ 'c1', 'c2', 'c3', 'c4', 'c5' ];
 
-       module.exports = HighlightColors;
-}() );
+module.exports = HighlightColors;
index 37874d5..3b69654 100644 (file)
-( function () {
-       /* eslint no-underscore-dangle: "off" */
-       /**
-        * URI Processor for RCFilters
-        *
-        * @class mw.rcfilters.UriProcessor
-        *
-        * @constructor
-        * @param {mw.rcfilters.dm.FiltersViewModel} filtersModel Filters view model
-        * @param {Object} [config] Configuration object
-        * @cfg {boolean} [normalizeTarget] Dictates whether or not to go through the
-        *  title normalization to separate title subpage/parts into the target= url
-        *  parameter
-        */
-       var UriProcessor = function MwRcfiltersController( filtersModel, config ) {
-               config = config || {};
-               this.filtersModel = filtersModel;
-
-               this.normalizeTarget = !!config.normalizeTarget;
-       };
-
-       /* Initialization */
-       OO.initClass( UriProcessor );
-
-       /* Static methods */
-
-       /**
-        * Replace the url history through replaceState
-        *
-        * @param {mw.Uri} newUri New URI to replace
-        */
-       UriProcessor.static.replaceState = function ( newUri ) {
-               window.history.replaceState(
-                       { tag: 'rcfilters' },
-                       document.title,
-                       newUri.toString()
-               );
-       };
-
-       /**
-        * Push the url to history through pushState
-        *
-        * @param {mw.Uri} newUri New URI to push
-        */
-       UriProcessor.static.pushState = function ( newUri ) {
-               window.history.pushState(
-                       { tag: 'rcfilters' },
-                       document.title,
-                       newUri.toString()
-               );
-       };
-
-       /* Methods */
-
-       /**
-        * Get the version that this URL query is tagged with.
-        *
-        * @param {Object} [uriQuery] URI query
-        * @return {number} URL version
-        */
-       UriProcessor.prototype.getVersion = function ( uriQuery ) {
-               uriQuery = uriQuery || new mw.Uri().query;
-
-               return Number( uriQuery.urlversion || 1 );
-       };
-
-       /**
-        * Get an updated mw.Uri object based on the model state
-        *
-        * @param {mw.Uri} [uri] An external URI to build the new uri
-        *  with. This is mainly for tests, to be able to supply external query
-        *  parameters and make sure they are retained.
-        * @return {mw.Uri} Updated Uri
-        */
-       UriProcessor.prototype.getUpdatedUri = function ( uri ) {
-               var normalizedUri = this._normalizeTargetInUri( uri || new mw.Uri() ),
-                       unrecognizedParams = this.getUnrecognizedParams( normalizedUri.query );
-
-               normalizedUri.query = this.filtersModel.getMinimizedParamRepresentation(
-                       $.extend(
-                               true,
-                               {},
-                               normalizedUri.query,
-                               // The representation must be expanded so it can
-                               // override the uri query params but we then output
-                               // a minimized version for the entire URI representation
-                               // for the method
-                               this.filtersModel.getExpandedParamRepresentation()
-                       )
-               );
-
-               // Reapply unrecognized params and url version
-               normalizedUri.query = $.extend(
+/* eslint no-underscore-dangle: "off" */
+/**
+ * URI Processor for RCFilters
+ *
+ * @class mw.rcfilters.UriProcessor
+ *
+ * @constructor
+ * @param {mw.rcfilters.dm.FiltersViewModel} filtersModel Filters view model
+ * @param {Object} [config] Configuration object
+ * @cfg {boolean} [normalizeTarget] Dictates whether or not to go through the
+ *  title normalization to separate title subpage/parts into the target= url
+ *  parameter
+ */
+var UriProcessor = function MwRcfiltersController( filtersModel, config ) {
+       config = config || {};
+       this.filtersModel = filtersModel;
+
+       this.normalizeTarget = !!config.normalizeTarget;
+};
+
+/* Initialization */
+OO.initClass( UriProcessor );
+
+/* Static methods */
+
+/**
+ * Replace the url history through replaceState
+ *
+ * @param {mw.Uri} newUri New URI to replace
+ */
+UriProcessor.static.replaceState = function ( newUri ) {
+       window.history.replaceState(
+               { tag: 'rcfilters' },
+               document.title,
+               newUri.toString()
+       );
+};
+
+/**
+ * Push the url to history through pushState
+ *
+ * @param {mw.Uri} newUri New URI to push
+ */
+UriProcessor.static.pushState = function ( newUri ) {
+       window.history.pushState(
+               { tag: 'rcfilters' },
+               document.title,
+               newUri.toString()
+       );
+};
+
+/* Methods */
+
+/**
+ * Get the version that this URL query is tagged with.
+ *
+ * @param {Object} [uriQuery] URI query
+ * @return {number} URL version
+ */
+UriProcessor.prototype.getVersion = function ( uriQuery ) {
+       uriQuery = uriQuery || new mw.Uri().query;
+
+       return Number( uriQuery.urlversion || 1 );
+};
+
+/**
+ * Get an updated mw.Uri object based on the model state
+ *
+ * @param {mw.Uri} [uri] An external URI to build the new uri
+ *  with. This is mainly for tests, to be able to supply external query
+ *  parameters and make sure they are retained.
+ * @return {mw.Uri} Updated Uri
+ */
+UriProcessor.prototype.getUpdatedUri = function ( uri ) {
+       var normalizedUri = this._normalizeTargetInUri( uri || new mw.Uri() ),
+               unrecognizedParams = this.getUnrecognizedParams( normalizedUri.query );
+
+       normalizedUri.query = this.filtersModel.getMinimizedParamRepresentation(
+               $.extend(
                        true,
                        {},
                        normalizedUri.query,
-                       unrecognizedParams,
-                       { urlversion: '2' }
-               );
-
-               return normalizedUri;
-       };
-
-       /**
-        * Move the subpage to the target parameter
-        *
-        * @param {mw.Uri} uri
-        * @return {mw.Uri}
-        * @private
-        */
-       UriProcessor.prototype._normalizeTargetInUri = function ( uri ) {
-               var parts,
-                       // matches [/wiki/]SpecialNS:RCL/[Namespace:]Title/Subpage/Subsubpage/etc
-                       re = /^((?:\/.+?\/)?.*?:.*?)\/(.*)$/;
-
-               if ( !this.normalizeTarget ) {
-                       return uri;
-               }
-
-               // target in title param
-               if ( uri.query.title ) {
-                       parts = uri.query.title.match( re );
-                       if ( parts ) {
-                               uri.query.title = parts[ 1 ];
-                               uri.query.target = parts[ 2 ];
-                       }
-               }
+                       // The representation must be expanded so it can
+                       // override the uri query params but we then output
+                       // a minimized version for the entire URI representation
+                       // for the method
+                       this.filtersModel.getExpandedParamRepresentation()
+               )
+       );
+
+       // Reapply unrecognized params and url version
+       normalizedUri.query = $.extend(
+               true,
+               {},
+               normalizedUri.query,
+               unrecognizedParams,
+               { urlversion: '2' }
+       );
+
+       return normalizedUri;
+};
+
+/**
+ * Move the subpage to the target parameter
+ *
+ * @param {mw.Uri} uri
+ * @return {mw.Uri}
+ * @private
+ */
+UriProcessor.prototype._normalizeTargetInUri = function ( uri ) {
+       var parts,
+               // matches [/wiki/]SpecialNS:RCL/[Namespace:]Title/Subpage/Subsubpage/etc
+               re = /^((?:\/.+?\/)?.*?:.*?)\/(.*)$/;
+
+       if ( !this.normalizeTarget ) {
+               return uri;
+       }
 
-               // target in path
-               parts = mw.Uri.decode( uri.path ).match( re );
+       // target in title param
+       if ( uri.query.title ) {
+               parts = uri.query.title.match( re );
                if ( parts ) {
-                       uri.path = parts[ 1 ];
+                       uri.query.title = parts[ 1 ];
                        uri.query.target = parts[ 2 ];
                }
-
-               return uri;
-       };
-
-       /**
-        * Get an object representing given parameters that are unrecognized by the model
-        *
-        * @param  {Object} params Full params object
-        * @return {Object} Unrecognized params
-        */
-       UriProcessor.prototype.getUnrecognizedParams = function ( params ) {
-               // Start with full representation
-               var givenParamNames = Object.keys( params ),
-                       unrecognizedParams = $.extend( true, {}, params );
-
-               // Extract unrecognized parameters
-               Object.keys( this.filtersModel.getEmptyParameterState() ).forEach( function ( paramName ) {
-                       // Remove recognized params
-                       if ( givenParamNames.indexOf( paramName ) > -1 ) {
-                               delete unrecognizedParams[ paramName ];
-                       }
-               } );
-
-               return unrecognizedParams;
-       };
-
-       /**
-        * Update the URL of the page to reflect current filters
-        *
-        * This should not be called directly from outside the controller.
-        * If an action requires changing the URL, it should either use the
-        * highlighting actions below, or call #updateChangesList which does
-        * the uri corrections already.
-        *
-        * @param {Object} [params] Extra parameters to add to the API call
-        */
-       UriProcessor.prototype.updateURL = function ( params ) {
-               var currentUri = new mw.Uri(),
-                       updatedUri = this.getUpdatedUri();
-
-               updatedUri.extend( params || {} );
-
-               if (
-                       this.getVersion( currentUri.query ) !== 2 ||
-                       this.isNewState( currentUri.query, updatedUri.query )
-               ) {
-                       this.constructor.static.replaceState( updatedUri );
+       }
+
+       // target in path
+       parts = mw.Uri.decode( uri.path ).match( re );
+       if ( parts ) {
+               uri.path = parts[ 1 ];
+               uri.query.target = parts[ 2 ];
+       }
+
+       return uri;
+};
+
+/**
+ * Get an object representing given parameters that are unrecognized by the model
+ *
+ * @param  {Object} params Full params object
+ * @return {Object} Unrecognized params
+ */
+UriProcessor.prototype.getUnrecognizedParams = function ( params ) {
+       // Start with full representation
+       var givenParamNames = Object.keys( params ),
+               unrecognizedParams = $.extend( true, {}, params );
+
+       // Extract unrecognized parameters
+       Object.keys( this.filtersModel.getEmptyParameterState() ).forEach( function ( paramName ) {
+               // Remove recognized params
+               if ( givenParamNames.indexOf( paramName ) > -1 ) {
+                       delete unrecognizedParams[ paramName ];
                }
-       };
-
-       /**
-        * Update the filters model based on the URI query
-        * This happens on initialization, and from this moment on,
-        * we consider the system synchronized, and the model serves
-        * as the source of truth for the URL.
-        *
-        * This methods should only be called once on initialization.
-        * After initialization, the model updates the URL, not the
-        * other way around.
-        *
-        * @param {Object} [uriQuery] URI query
-        */
-       UriProcessor.prototype.updateModelBasedOnQuery = function ( uriQuery ) {
-               uriQuery = uriQuery || this._normalizeTargetInUri( new mw.Uri() ).query;
-               this.filtersModel.updateStateFromParams(
-                       this._getNormalizedQueryParams( uriQuery )
-               );
-       };
-
-       /**
-        * Compare two URI queries to decide whether they are different
-        * enough to represent a new state.
-        *
-        * @param {Object} currentUriQuery Current Uri query
-        * @param {Object} updatedUriQuery Updated Uri query
-        * @return {boolean} This is a new state
-        */
-       UriProcessor.prototype.isNewState = function ( currentUriQuery, updatedUriQuery ) {
-               var currentParamState, updatedParamState,
-                       notEquivalent = function ( obj1, obj2 ) {
-                               var keys = Object.keys( obj1 ).concat( Object.keys( obj2 ) );
-                               return keys.some( function ( key ) {
-                                       return obj1[ key ] != obj2[ key ]; // eslint-disable-line eqeqeq
-                               } );
-                       };
-
-               // Compare states instead of parameters
-               // This will allow us to always have a proper check of whether
-               // the requested new url is one to change or not, regardless of
-               // actual parameter visibility/representation in the URL
-               currentParamState = $.extend(
-                       true,
-                       {},
-                       this.filtersModel.getMinimizedParamRepresentation( currentUriQuery ),
-                       this.getUnrecognizedParams( currentUriQuery )
-               );
-               updatedParamState = $.extend(
-                       true,
-                       {},
-                       this.filtersModel.getMinimizedParamRepresentation( updatedUriQuery ),
-                       this.getUnrecognizedParams( updatedUriQuery )
-               );
-
-               return notEquivalent( currentParamState, updatedParamState );
-       };
-
-       /**
-        * Check whether the given query has parameters that are
-        * recognized as parameters we should load the system with
-        *
-        * @param {mw.Uri} [uriQuery] Given URI query
-        * @return {boolean} Query contains valid recognized parameters
-        */
-       UriProcessor.prototype.doesQueryContainRecognizedParams = function ( uriQuery ) {
-               var anyValidInUrl,
-                       validParameterNames = Object.keys( this.filtersModel.getEmptyParameterState() );
-
-               uriQuery = uriQuery || new mw.Uri().query;
-
-               anyValidInUrl = Object.keys( uriQuery ).some( function ( parameter ) {
-                       return validParameterNames.indexOf( parameter ) > -1;
-               } );
-
-               // URL version 2 is allowed to be empty or within nonrecognized params
-               return anyValidInUrl || this.getVersion( uriQuery ) === 2;
-       };
-
-       /**
-        * Get the adjusted URI params based on the url version
-        * If the urlversion is not 2, the parameters are merged with
-        * the model's defaults.
-        * Always merge in the hidden parameter defaults.
-        *
-        * @private
-        * @param {Object} uriQuery Current URI query
-        * @return {Object} Normalized parameters
-        */
-       UriProcessor.prototype._getNormalizedQueryParams = function ( uriQuery ) {
-               // Check whether we are dealing with urlversion=2
-               // If we are, we do not merge the initial request with
-               // defaults. Not having urlversion=2 means we need to
-               // reproduce the server-side request and merge the
-               // requested parameters (or starting state) with the
-               // wiki default.
-               // Any subsequent change of the URL through the RCFilters
-               // system will receive 'urlversion=2'
-               var base = this.getVersion( uriQuery ) === 2 ?
-                       {} :
-                       this.filtersModel.getDefaultParams();
-
-               return $.extend(
-                       true,
-                       {},
-                       this.filtersModel.getMinimizedParamRepresentation(
-                               $.extend( true, {}, base, uriQuery )
-                       ),
-                       { urlversion: '2' }
-               );
-       };
-
-       module.exports = UriProcessor;
-}() );
+       } );
+
+       return unrecognizedParams;
+};
+
+/**
+ * Update the URL of the page to reflect current filters
+ *
+ * This should not be called directly from outside the controller.
+ * If an action requires changing the URL, it should either use the
+ * highlighting actions below, or call #updateChangesList which does
+ * the uri corrections already.
+ *
+ * @param {Object} [params] Extra parameters to add to the API call
+ */
+UriProcessor.prototype.updateURL = function ( params ) {
+       var currentUri = new mw.Uri(),
+               updatedUri = this.getUpdatedUri();
+
+       updatedUri.extend( params || {} );
+
+       if (
+               this.getVersion( currentUri.query ) !== 2 ||
+               this.isNewState( currentUri.query, updatedUri.query )
+       ) {
+               this.constructor.static.replaceState( updatedUri );
+       }
+};
+
+/**
+ * Update the filters model based on the URI query
+ * This happens on initialization, and from this moment on,
+ * we consider the system synchronized, and the model serves
+ * as the source of truth for the URL.
+ *
+ * This methods should only be called once on initialization.
+ * After initialization, the model updates the URL, not the
+ * other way around.
+ *
+ * @param {Object} [uriQuery] URI query
+ */
+UriProcessor.prototype.updateModelBasedOnQuery = function ( uriQuery ) {
+       uriQuery = uriQuery || this._normalizeTargetInUri( new mw.Uri() ).query;
+       this.filtersModel.updateStateFromParams(
+               this._getNormalizedQueryParams( uriQuery )
+       );
+};
+
+/**
+ * Compare two URI queries to decide whether they are different
+ * enough to represent a new state.
+ *
+ * @param {Object} currentUriQuery Current Uri query
+ * @param {Object} updatedUriQuery Updated Uri query
+ * @return {boolean} This is a new state
+ */
+UriProcessor.prototype.isNewState = function ( currentUriQuery, updatedUriQuery ) {
+       var currentParamState, updatedParamState,
+               notEquivalent = function ( obj1, obj2 ) {
+                       var keys = Object.keys( obj1 ).concat( Object.keys( obj2 ) );
+                       return keys.some( function ( key ) {
+                               return obj1[ key ] != obj2[ key ]; // eslint-disable-line eqeqeq
+                       } );
+               };
+
+       // Compare states instead of parameters
+       // This will allow us to always have a proper check of whether
+       // the requested new url is one to change or not, regardless of
+       // actual parameter visibility/representation in the URL
+       currentParamState = $.extend(
+               true,
+               {},
+               this.filtersModel.getMinimizedParamRepresentation( currentUriQuery ),
+               this.getUnrecognizedParams( currentUriQuery )
+       );
+       updatedParamState = $.extend(
+               true,
+               {},
+               this.filtersModel.getMinimizedParamRepresentation( updatedUriQuery ),
+               this.getUnrecognizedParams( updatedUriQuery )
+       );
+
+       return notEquivalent( currentParamState, updatedParamState );
+};
+
+/**
+ * Check whether the given query has parameters that are
+ * recognized as parameters we should load the system with
+ *
+ * @param {mw.Uri} [uriQuery] Given URI query
+ * @return {boolean} Query contains valid recognized parameters
+ */
+UriProcessor.prototype.doesQueryContainRecognizedParams = function ( uriQuery ) {
+       var anyValidInUrl,
+               validParameterNames = Object.keys( this.filtersModel.getEmptyParameterState() );
+
+       uriQuery = uriQuery || new mw.Uri().query;
+
+       anyValidInUrl = Object.keys( uriQuery ).some( function ( parameter ) {
+               return validParameterNames.indexOf( parameter ) > -1;
+       } );
+
+       // URL version 2 is allowed to be empty or within nonrecognized params
+       return anyValidInUrl || this.getVersion( uriQuery ) === 2;
+};
+
+/**
+ * Get the adjusted URI params based on the url version
+ * If the urlversion is not 2, the parameters are merged with
+ * the model's defaults.
+ * Always merge in the hidden parameter defaults.
+ *
+ * @private
+ * @param {Object} uriQuery Current URI query
+ * @return {Object} Normalized parameters
+ */
+UriProcessor.prototype._getNormalizedQueryParams = function ( uriQuery ) {
+       // Check whether we are dealing with urlversion=2
+       // If we are, we do not merge the initial request with
+       // defaults. Not having urlversion=2 means we need to
+       // reproduce the server-side request and merge the
+       // requested parameters (or starting state) with the
+       // wiki default.
+       // Any subsequent change of the URL through the RCFilters
+       // system will receive 'urlversion=2'
+       var base = this.getVersion( uriQuery ) === 2 ?
+               {} :
+               this.filtersModel.getDefaultParams();
+
+       return $.extend(
+               true,
+               {},
+               this.filtersModel.getMinimizedParamRepresentation(
+                       $.extend( true, {}, base, uriQuery )
+               ),
+               { urlversion: '2' }
+       );
+};
+
+module.exports = UriProcessor;
index 64d2e79..d5357e0 100644 (file)
-( function () {
-       /**
-        * View model for the changes list
-        *
-        * @class mw.rcfilters.dm.ChangesListViewModel
-        * @mixins OO.EventEmitter
-        *
-        * @param {jQuery} $initialFieldset The initial server-generated legacy form content
-        * @constructor
-        */
-       var ChangesListViewModel = function MwRcfiltersDmChangesListViewModel( $initialFieldset ) {
-               // Mixin constructor
-               OO.EventEmitter.call( this );
-
-               this.valid = true;
-               this.newChangesExist = false;
-               this.liveUpdate = false;
-               this.unseenWatchedChanges = false;
-
-               this.extractNextFrom( $initialFieldset );
-       };
-
-       /* Initialization */
-       OO.initClass( ChangesListViewModel );
-       OO.mixinClass( ChangesListViewModel, OO.EventEmitter );
-
-       /* Events */
-
-       /**
-        * @event invalidate
-        *
-        * The list of changes is now invalid (out of date)
-        */
-
-       /**
-        * @event update
-        * @param {jQuery|string} $changesListContent List of changes
-        * @param {jQuery} $fieldset Server-generated form
-        * @param {string} noResultsDetails Type of no result error
-        * @param {boolean} isInitialDOM Whether the previous dom variables are from the initial page load
-        * @param {boolean} fromLiveUpdate These are new changes fetched via Live Update
-        *
-        * The list of changes has been updated
-        */
-
-       /**
-        * @event newChangesExist
-        * @param {boolean} newChangesExist
-        *
-        * The existence of changes newer than those currently displayed has changed.
-        */
-
-       /**
-        * @event liveUpdateChange
-        * @param {boolean} enable
-        *
-        * The state of the 'live update' feature has changed.
-        */
-
-       /* Methods */
-
-       /**
-        * Invalidate the list of changes
-        *
-        * @fires invalidate
-        */
-       ChangesListViewModel.prototype.invalidate = function () {
-               if ( this.valid ) {
-                       this.valid = false;
-                       this.emit( 'invalidate' );
-               }
-       };
-
-       /**
-        * Update the model with an updated list of changes
-        *
-        * @param {jQuery|string} changesListContent
-        * @param {jQuery} $fieldset
-        * @param {string} noResultsDetails Type of no result error
-        * @param {boolean} [isInitialDOM] Using the initial (already attached) DOM elements
-        * @param {boolean} [separateOldAndNew] Whether a logical separation between old and new changes is needed
-        * @fires update
-        */
-       ChangesListViewModel.prototype.update = function ( changesListContent, $fieldset, noResultsDetails, isInitialDOM, separateOldAndNew ) {
-               var from = this.nextFrom;
-               this.valid = true;
-               this.extractNextFrom( $fieldset );
-               this.checkForUnseenWatchedChanges( changesListContent );
-               this.emit( 'update', changesListContent, $fieldset, noResultsDetails, isInitialDOM, separateOldAndNew ? from : null );
-       };
-
-       /**
-        * Specify whether new changes exist
-        *
-        * @param {boolean} newChangesExist
-        * @fires newChangesExist
-        */
-       ChangesListViewModel.prototype.setNewChangesExist = function ( newChangesExist ) {
-               if ( newChangesExist !== this.newChangesExist ) {
-                       this.newChangesExist = newChangesExist;
-                       this.emit( 'newChangesExist', newChangesExist );
-               }
-       };
-
-       /**
-        * @return {boolean} Whether new changes exist
-        */
-       ChangesListViewModel.prototype.getNewChangesExist = function () {
-               return this.newChangesExist;
-       };
-
-       /**
-        * Extract the value of the 'from' parameter from a link in the field set
-        *
-        * @param {jQuery} $fieldset
-        */
-       ChangesListViewModel.prototype.extractNextFrom = function ( $fieldset ) {
-               var data = $fieldset.find( '.rclistfrom > a, .wlinfo' ).data( 'params' );
-               if ( data && data.from ) {
-                       this.nextFrom = data.from;
-               }
-       };
-
-       /**
-        * @return {string} The 'from' parameter that can be used to query new changes
-        */
-       ChangesListViewModel.prototype.getNextFrom = function () {
-               return this.nextFrom;
-       };
-
-       /**
-        * Toggle the 'live update' feature on/off
-        *
-        * @param {boolean} enable
-        */
-       ChangesListViewModel.prototype.toggleLiveUpdate = function ( enable ) {
-               enable = enable === undefined ? !this.liveUpdate : enable;
-               if ( enable !== this.liveUpdate ) {
-                       this.liveUpdate = enable;
-                       this.emit( 'liveUpdateChange', this.liveUpdate );
-               }
-       };
-
-       /**
-        * @return {boolean} The 'live update' feature is enabled
-        */
-       ChangesListViewModel.prototype.getLiveUpdate = function () {
-               return this.liveUpdate;
-       };
-
-       /**
-        * Check if some of the given changes watched and unseen
-        *
-        * @param {jQuery|string} changeslistContent
-        */
-       ChangesListViewModel.prototype.checkForUnseenWatchedChanges = function ( changeslistContent ) {
-               this.unseenWatchedChanges = changeslistContent !== 'NO_RESULTS' &&
-                       changeslistContent.find( '.mw-changeslist-line-watched' ).length > 0;
-       };
-
-       /**
-        * @return {boolean} Whether some of the current changes are watched and unseen
-        */
-       ChangesListViewModel.prototype.hasUnseenWatchedChanges = function () {
-               return this.unseenWatchedChanges;
-       };
-
-       module.exports = ChangesListViewModel;
-}() );
+/**
+ * View model for the changes list
+ *
+ * @class mw.rcfilters.dm.ChangesListViewModel
+ * @mixins OO.EventEmitter
+ *
+ * @param {jQuery} $initialFieldset The initial server-generated legacy form content
+ * @constructor
+ */
+var ChangesListViewModel = function MwRcfiltersDmChangesListViewModel( $initialFieldset ) {
+       // Mixin constructor
+       OO.EventEmitter.call( this );
+
+       this.valid = true;
+       this.newChangesExist = false;
+       this.liveUpdate = false;
+       this.unseenWatchedChanges = false;
+
+       this.extractNextFrom( $initialFieldset );
+};
+
+/* Initialization */
+OO.initClass( ChangesListViewModel );
+OO.mixinClass( ChangesListViewModel, OO.EventEmitter );
+
+/* Events */
+
+/**
+ * @event invalidate
+ *
+ * The list of changes is now invalid (out of date)
+ */
+
+/**
+ * @event update
+ * @param {jQuery|string} $changesListContent List of changes
+ * @param {jQuery} $fieldset Server-generated form
+ * @param {string} noResultsDetails Type of no result error
+ * @param {boolean} isInitialDOM Whether the previous dom variables are from the initial page load
+ * @param {boolean} fromLiveUpdate These are new changes fetched via Live Update
+ *
+ * The list of changes has been updated
+ */
+
+/**
+ * @event newChangesExist
+ * @param {boolean} newChangesExist
+ *
+ * The existence of changes newer than those currently displayed has changed.
+ */
+
+/**
+ * @event liveUpdateChange
+ * @param {boolean} enable
+ *
+ * The state of the 'live update' feature has changed.
+ */
+
+/* Methods */
+
+/**
+ * Invalidate the list of changes
+ *
+ * @fires invalidate
+ */
+ChangesListViewModel.prototype.invalidate = function () {
+       if ( this.valid ) {
+               this.valid = false;
+               this.emit( 'invalidate' );
+       }
+};
+
+/**
+ * Update the model with an updated list of changes
+ *
+ * @param {jQuery|string} changesListContent
+ * @param {jQuery} $fieldset
+ * @param {string} noResultsDetails Type of no result error
+ * @param {boolean} [isInitialDOM] Using the initial (already attached) DOM elements
+ * @param {boolean} [separateOldAndNew] Whether a logical separation between old and new changes is needed
+ * @fires update
+ */
+ChangesListViewModel.prototype.update = function ( changesListContent, $fieldset, noResultsDetails, isInitialDOM, separateOldAndNew ) {
+       var from = this.nextFrom;
+       this.valid = true;
+       this.extractNextFrom( $fieldset );
+       this.checkForUnseenWatchedChanges( changesListContent );
+       this.emit( 'update', changesListContent, $fieldset, noResultsDetails, isInitialDOM, separateOldAndNew ? from : null );
+};
+
+/**
+ * Specify whether new changes exist
+ *
+ * @param {boolean} newChangesExist
+ * @fires newChangesExist
+ */
+ChangesListViewModel.prototype.setNewChangesExist = function ( newChangesExist ) {
+       if ( newChangesExist !== this.newChangesExist ) {
+               this.newChangesExist = newChangesExist;
+               this.emit( 'newChangesExist', newChangesExist );
+       }
+};
+
+/**
+ * @return {boolean} Whether new changes exist
+ */
+ChangesListViewModel.prototype.getNewChangesExist = function () {
+       return this.newChangesExist;
+};
+
+/**
+ * Extract the value of the 'from' parameter from a link in the field set
+ *
+ * @param {jQuery} $fieldset
+ */
+ChangesListViewModel.prototype.extractNextFrom = function ( $fieldset ) {
+       var data = $fieldset.find( '.rclistfrom > a, .wlinfo' ).data( 'params' );
+       if ( data && data.from ) {
+               this.nextFrom = data.from;
+               this.nextFromFormatted = data.fromFormatted;
+       }
+};
+
+/**
+ * @return {string} The 'from' parameter that can be used to query new changes
+ */
+ChangesListViewModel.prototype.getNextFrom = function () {
+       return this.nextFrom;
+};
+
+/**
+ * @return {string} The 'from' parameter formatted per the user's datetime format preference
+ */
+ChangesListViewModel.prototype.getNextFromFormatted = function () {
+       return this.nextFromFormatted;
+};
+
+/**
+ * Toggle the 'live update' feature on/off
+ *
+ * @param {boolean} enable
+ */
+ChangesListViewModel.prototype.toggleLiveUpdate = function ( enable ) {
+       enable = enable === undefined ? !this.liveUpdate : enable;
+       if ( enable !== this.liveUpdate ) {
+               this.liveUpdate = enable;
+               this.emit( 'liveUpdateChange', this.liveUpdate );
+       }
+};
+
+/**
+ * @return {boolean} The 'live update' feature is enabled
+ */
+ChangesListViewModel.prototype.getLiveUpdate = function () {
+       return this.liveUpdate;
+};
+
+/**
+ * Check if some of the given changes watched and unseen
+ *
+ * @param {jQuery|string} changeslistContent
+ */
+ChangesListViewModel.prototype.checkForUnseenWatchedChanges = function ( changeslistContent ) {
+       this.unseenWatchedChanges = changeslistContent !== 'NO_RESULTS' &&
+               changeslistContent.find( '.mw-changeslist-line-watched' ).length > 0;
+};
+
+/**
+ * @return {boolean} Whether some of the current changes are watched and unseen
+ */
+ChangesListViewModel.prototype.hasUnseenWatchedChanges = function () {
+       return this.unseenWatchedChanges;
+};
+
+module.exports = ChangesListViewModel;
index db504b5..d1f700c 100644 (file)
-( function () {
-       var FilterItem = require( './FilterItem.js' ),
-               FilterGroup;
-
-       /**
-        * View model for a filter group
-        *
-        * @class mw.rcfilters.dm.FilterGroup
-        * @mixins OO.EventEmitter
-        * @mixins OO.EmitterList
-        *
-        * @constructor
-        * @param {string} name Group name
-        * @param {Object} [config] Configuration options
-        * @cfg {string} [type='send_unselected_if_any'] Group type
-        * @cfg {string} [view='default'] Name of the display group this group
-        *  is a part of.
-        * @cfg {boolean} [sticky] This group is 'sticky'. It is synchronized
-        *  with a preference, does not participate in Saved Queries, and is
-        *  not shown in the active filters area.
-        * @cfg {string} [title] Group title
-        * @cfg {boolean} [hidden] This group is hidden from the regular menu views
-        *  and the active filters area.
-        * @cfg {boolean} [allowArbitrary] Allows for an arbitrary value to be added to the
-        *  group from the URL, even if it wasn't initially set up.
-        * @cfg {number} [range] An object defining minimum and maximum values for numeric
-        *  groups. { min: x, max: y }
-        * @cfg {number} [minValue] Minimum value for numeric groups
-        * @cfg {string} [separator='|'] Value separator for 'string_options' groups
-        * @cfg {boolean} [active] Group is active
-        * @cfg {boolean} [fullCoverage] This filters in this group collectively cover all results
-        * @cfg {Object} [conflicts] Defines the conflicts for this filter group
-        * @cfg {string|Object} [labelPrefixKey] An i18n key defining the prefix label for this
-        *  group. If the prefix has 'invert' state, the parameter is expected to be an object
-        *  with 'default' and 'inverted' as keys.
-        * @cfg {Object} [whatsThis] Defines the messages that should appear for the 'what's this' popup
-        * @cfg {string} [whatsThis.header] The header of the whatsThis popup message
-        * @cfg {string} [whatsThis.body] The body of the whatsThis popup message
-        * @cfg {string} [whatsThis.url] The url for the link in the whatsThis popup message
-        * @cfg {string} [whatsThis.linkMessage] The text for the link in the whatsThis popup message
-        * @cfg {boolean} [visible=true] The visibility of the group
-        */
-       FilterGroup = function MwRcfiltersDmFilterGroup( name, config ) {
-               config = config || {};
-
-               // Mixin constructor
-               OO.EventEmitter.call( this );
-               OO.EmitterList.call( this );
-
-               this.name = name;
-               this.type = config.type || 'send_unselected_if_any';
-               this.view = config.view || 'default';
-               this.sticky = !!config.sticky;
-               this.title = config.title || name;
-               this.hidden = !!config.hidden;
-               this.allowArbitrary = !!config.allowArbitrary;
-               this.numericRange = config.range;
-               this.separator = config.separator || '|';
-               this.labelPrefixKey = config.labelPrefixKey;
-               this.visible = config.visible === undefined ? true : !!config.visible;
-
-               this.currSelected = null;
-               this.active = !!config.active;
-               this.fullCoverage = !!config.fullCoverage;
-
-               this.whatsThis = config.whatsThis || {};
-
-               this.conflicts = config.conflicts || {};
-               this.defaultParams = {};
-               this.defaultFilters = {};
-
-               this.aggregate( { update: 'filterItemUpdate' } );
-               this.connect( this, { filterItemUpdate: 'onFilterItemUpdate' } );
-       };
-
-       /* Initialization */
-       OO.initClass( FilterGroup );
-       OO.mixinClass( FilterGroup, OO.EventEmitter );
-       OO.mixinClass( FilterGroup, OO.EmitterList );
-
-       /* Events */
-
-       /**
-        * @event update
-        *
-        * Group state has been updated
-        */
-
-       /* Methods */
-
-       /**
-        * Initialize the group and create its filter items
-        *
-        * @param {Object} filterDefinition Filter definition for this group
-        * @param {string|Object} [groupDefault] Definition of the group default
-        */
-       FilterGroup.prototype.initializeFilters = function ( filterDefinition, groupDefault ) {
-               var defaultParam,
-                       supersetMap = {},
-                       model = this,
-                       items = [];
-
-               filterDefinition.forEach( function ( filter ) {
-                       // Instantiate an item
-                       var subsetNames = [],
-                               filterItem = new FilterItem( filter.name, model, {
-                                       group: model.getName(),
-                                       label: filter.label || filter.name,
-                                       description: filter.description || '',
-                                       labelPrefixKey: model.labelPrefixKey,
-                                       cssClass: filter.cssClass,
-                                       identifiers: filter.identifiers,
-                                       defaultHighlightColor: filter.defaultHighlightColor
-                               } );
-
-                       if ( filter.subset ) {
-                               filter.subset = filter.subset.map( function ( el ) {
-                                       return el.filter;
-                               } );
-
-                               subsetNames = [];
-
-                               filter.subset.forEach( function ( subsetFilterName ) {
-                                       // Subsets (unlike conflicts) are always inside the same group
-                                       // We can re-map the names of the filters we are getting from
-                                       // the subsets with the group prefix
-                                       var subsetName = model.getPrefixedName( subsetFilterName );
-                                       // For convenience, we should store each filter's "supersets" -- these are
-                                       // the filters that have that item in their subset list. This will just
-                                       // make it easier to go through whether the item has any other items
-                                       // that affect it (and are selected) at any given time
-                                       supersetMap[ subsetName ] = supersetMap[ subsetName ] || [];
-                                       mw.rcfilters.utils.addArrayElementsUnique(
-                                               supersetMap[ subsetName ],
-                                               filterItem.getName()
-                                       );
-
-                                       // Translate subset param name to add the group name, so we
-                                       // get consistent naming. We know that subsets are only within
-                                       // the same group
-                                       subsetNames.push( subsetName );
-                               } );
-
-                               // Set translated subset
-                               filterItem.setSubset( subsetNames );
-                       }
-
-                       items.push( filterItem );
-
-                       // Store default parameter state; in this case, default is defined per filter
-                       if (
-                               model.getType() === 'send_unselected_if_any' ||
-                               model.getType() === 'boolean'
-                       ) {
-                               // Store the default parameter state
-                               // For this group type, parameter values are direct
-                               // We need to convert from a boolean to a string ('1' and '0')
-                               model.defaultParams[ filter.name ] = String( Number( filter.default || 0 ) );
-                       } else if ( model.getType() === 'any_value' ) {
-                               model.defaultParams[ filter.name ] = filter.default;
-                       }
-               } );
-
-               // Add items
-               this.addItems( items );
-
-               // Now that we have all items, we can apply the superset map
-               this.getItems().forEach( function ( filterItem ) {
-                       filterItem.setSuperset( supersetMap[ filterItem.getName() ] );
-               } );
-
-               // Store default parameter state; in this case, default is defined per the
-               // entire group, given by groupDefault method parameter
-               if ( this.getType() === 'string_options' ) {
-                       // Store the default parameter group state
-                       // For this group, the parameter is group name and value is the names
-                       // of selected items
-                       this.defaultParams[ this.getName() ] = mw.rcfilters.utils.normalizeParamOptions(
-                               // Current values
-                               groupDefault ?
-                                       groupDefault.split( this.getSeparator() ) :
-                                       [],
-                               // Legal values
-                               this.getItems().map( function ( item ) {
-                                       return item.getParamName();
-                               } )
-                       ).join( this.getSeparator() );
-               } else if ( this.getType() === 'single_option' ) {
-                       defaultParam = groupDefault !== undefined ?
-                               groupDefault : this.getItems()[ 0 ].getParamName();
-
-                       // For this group, the parameter is the group name,
-                       // and a single item can be selected: default or first item
-                       this.defaultParams[ this.getName() ] = defaultParam;
-               }
-
-               // add highlights to defaultParams
-               this.getItems().forEach( function ( filterItem ) {
-                       if ( filterItem.isHighlighted() ) {
-                               this.defaultParams[ filterItem.getName() + '_color' ] = filterItem.getHighlightColor();
-                       }
-               }.bind( this ) );
-
-               // Store default filter state based on default params
-               this.defaultFilters = this.getFilterRepresentation( this.getDefaultParams() );
+var FilterItem = require( './FilterItem.js' ),
+       FilterGroup;
+
+/**
+ * View model for a filter group
+ *
+ * @class mw.rcfilters.dm.FilterGroup
+ * @mixins OO.EventEmitter
+ * @mixins OO.EmitterList
+ *
+ * @constructor
+ * @param {string} name Group name
+ * @param {Object} [config] Configuration options
+ * @cfg {string} [type='send_unselected_if_any'] Group type
+ * @cfg {string} [view='default'] Name of the display group this group
+ *  is a part of.
+ * @cfg {boolean} [sticky] This group is 'sticky'. It is synchronized
+ *  with a preference, does not participate in Saved Queries, and is
+ *  not shown in the active filters area.
+ * @cfg {string} [title] Group title
+ * @cfg {boolean} [hidden] This group is hidden from the regular menu views
+ *  and the active filters area.
+ * @cfg {boolean} [allowArbitrary] Allows for an arbitrary value to be added to the
+ *  group from the URL, even if it wasn't initially set up.
+ * @cfg {number} [range] An object defining minimum and maximum values for numeric
+ *  groups. { min: x, max: y }
+ * @cfg {number} [minValue] Minimum value for numeric groups
+ * @cfg {string} [separator='|'] Value separator for 'string_options' groups
+ * @cfg {boolean} [active] Group is active
+ * @cfg {boolean} [fullCoverage] This filters in this group collectively cover all results
+ * @cfg {Object} [conflicts] Defines the conflicts for this filter group
+ * @cfg {string|Object} [labelPrefixKey] An i18n key defining the prefix label for this
+ *  group. If the prefix has 'invert' state, the parameter is expected to be an object
+ *  with 'default' and 'inverted' as keys.
+ * @cfg {Object} [whatsThis] Defines the messages that should appear for the 'what's this' popup
+ * @cfg {string} [whatsThis.header] The header of the whatsThis popup message
+ * @cfg {string} [whatsThis.body] The body of the whatsThis popup message
+ * @cfg {string} [whatsThis.url] The url for the link in the whatsThis popup message
+ * @cfg {string} [whatsThis.linkMessage] The text for the link in the whatsThis popup message
+ * @cfg {boolean} [visible=true] The visibility of the group
+ */
+FilterGroup = function MwRcfiltersDmFilterGroup( name, config ) {
+       config = config || {};
+
+       // Mixin constructor
+       OO.EventEmitter.call( this );
+       OO.EmitterList.call( this );
+
+       this.name = name;
+       this.type = config.type || 'send_unselected_if_any';
+       this.view = config.view || 'default';
+       this.sticky = !!config.sticky;
+       this.title = config.title || name;
+       this.hidden = !!config.hidden;
+       this.allowArbitrary = !!config.allowArbitrary;
+       this.numericRange = config.range;
+       this.separator = config.separator || '|';
+       this.labelPrefixKey = config.labelPrefixKey;
+       this.visible = config.visible === undefined ? true : !!config.visible;
+
+       this.currSelected = null;
+       this.active = !!config.active;
+       this.fullCoverage = !!config.fullCoverage;
+
+       this.whatsThis = config.whatsThis || {};
+
+       this.conflicts = config.conflicts || {};
+       this.defaultParams = {};
+       this.defaultFilters = {};
+
+       this.aggregate( { update: 'filterItemUpdate' } );
+       this.connect( this, { filterItemUpdate: 'onFilterItemUpdate' } );
+};
+
+/* Initialization */
+OO.initClass( FilterGroup );
+OO.mixinClass( FilterGroup, OO.EventEmitter );
+OO.mixinClass( FilterGroup, OO.EmitterList );
+
+/* Events */
+
+/**
+ * @event update
+ *
+ * Group state has been updated
+ */
+
+/* Methods */
+
+/**
+ * Initialize the group and create its filter items
+ *
+ * @param {Object} filterDefinition Filter definition for this group
+ * @param {string|Object} [groupDefault] Definition of the group default
+ */
+FilterGroup.prototype.initializeFilters = function ( filterDefinition, groupDefault ) {
+       var defaultParam,
+               supersetMap = {},
+               model = this,
+               items = [];
+
+       filterDefinition.forEach( function ( filter ) {
+               // Instantiate an item
+               var subsetNames = [],
+                       filterItem = new FilterItem( filter.name, model, {
+                               group: model.getName(),
+                               label: filter.label || filter.name,
+                               description: filter.description || '',
+                               labelPrefixKey: model.labelPrefixKey,
+                               cssClass: filter.cssClass,
+                               identifiers: filter.identifiers,
+                               defaultHighlightColor: filter.defaultHighlightColor
+                       } );
 
-               // Check for filters that should be initially selected by their default value
-               if ( this.isSticky() ) {
-                       // eslint-disable-next-line no-jquery/no-each-util
-                       $.each( this.defaultFilters, function ( filterName, filterValue ) {
-                               model.getItemByName( filterName ).toggleSelected( filterValue );
+               if ( filter.subset ) {
+                       filter.subset = filter.subset.map( function ( el ) {
+                               return el.filter;
                        } );
-               }
 
-               // Verify that single_option group has at least one item selected
-               if (
-                       this.getType() === 'single_option' &&
-                       this.findSelectedItems().length === 0
-               ) {
-                       defaultParam = groupDefault !== undefined ?
-                               groupDefault : this.getItems()[ 0 ].getParamName();
+                       subsetNames = [];
+
+                       filter.subset.forEach( function ( subsetFilterName ) {
+                               // Subsets (unlike conflicts) are always inside the same group
+                               // We can re-map the names of the filters we are getting from
+                               // the subsets with the group prefix
+                               var subsetName = model.getPrefixedName( subsetFilterName );
+                               // For convenience, we should store each filter's "supersets" -- these are
+                               // the filters that have that item in their subset list. This will just
+                               // make it easier to go through whether the item has any other items
+                               // that affect it (and are selected) at any given time
+                               supersetMap[ subsetName ] = supersetMap[ subsetName ] || [];
+                               mw.rcfilters.utils.addArrayElementsUnique(
+                                       supersetMap[ subsetName ],
+                                       filterItem.getName()
+                               );
+
+                               // Translate subset param name to add the group name, so we
+                               // get consistent naming. We know that subsets are only within
+                               // the same group
+                               subsetNames.push( subsetName );
+                       } );
 
-                       // Single option means there must be a single option
-                       // selected, so we have to either select the default
-                       // or select the first option
-                       this.selectItemByParamName( defaultParam );
-               }
-       };
-
-       /**
-        * Respond to filterItem update event
-        *
-        * @param {mw.rcfilters.dm.FilterItem} item Updated filter item
-        * @fires update
-        */
-       FilterGroup.prototype.onFilterItemUpdate = function ( item ) {
-               // Update state
-               var changed = false,
-                       active = this.areAnySelected(),
-                       model = this;
-
-               if ( this.getType() === 'single_option' ) {
-                       // This group must have one item selected always
-                       // and must never have more than one item selected at a time
-                       if ( this.findSelectedItems().length === 0 ) {
-                               // Nothing is selected anymore
-                               // Select the default or the first item
-                               this.currSelected = this.getItemByParamName( this.defaultParams[ this.getName() ] ) ||
-                                       this.getItems()[ 0 ];
-                               this.currSelected.toggleSelected( true );
-                               changed = true;
-                       } else if ( this.findSelectedItems().length > 1 ) {
-                               // There is more than one item selected
-                               // This should only happen if the item given
-                               // is the one that is selected, so unselect
-                               // all items that is not it
-                               this.findSelectedItems().forEach( function ( itemModel ) {
-                                       // Note that in case the given item is actually
-                                       // not selected, this loop will end up unselecting
-                                       // all items, which would trigger the case above
-                                       // when the last item is unselected anyways
-                                       var selected = itemModel.getName() === item.getName() &&
-                                               item.isSelected();
-
-                                       itemModel.toggleSelected( selected );
-                                       if ( selected ) {
-                                               model.currSelected = itemModel;
-                                       }
-                               } );
-                               changed = true;
-                       }
+                       // Set translated subset
+                       filterItem.setSubset( subsetNames );
                }
 
-               if ( this.isSticky() ) {
-                       // If this group is sticky, then change the default according to the
-                       // current selection.
-                       this.defaultParams = this.getParamRepresentation( this.getSelectedState() );
-               }
+               items.push( filterItem );
 
+               // Store default parameter state; in this case, default is defined per filter
                if (
-                       changed ||
-                       this.active !== active ||
-                       this.currSelected !== item
+                       model.getType() === 'send_unselected_if_any' ||
+                       model.getType() === 'boolean'
                ) {
-                       this.active = active;
-                       this.currSelected = item;
-
-                       this.emit( 'update' );
+                       // Store the default parameter state
+                       // For this group type, parameter values are direct
+                       // We need to convert from a boolean to a string ('1' and '0')
+                       model.defaultParams[ filter.name ] = String( Number( filter.default || 0 ) );
+               } else if ( model.getType() === 'any_value' ) {
+                       model.defaultParams[ filter.name ] = filter.default;
                }
-       };
-
-       /**
-        * Get group active state
-        *
-        * @return {boolean} Active state
-        */
-       FilterGroup.prototype.isActive = function () {
-               return this.active;
-       };
-
-       /**
-        * Get group hidden state
-        *
-        * @return {boolean} Hidden state
-        */
-       FilterGroup.prototype.isHidden = function () {
-               return this.hidden;
-       };
-
-       /**
-        * Get group allow arbitrary state
-        *
-        * @return {boolean} Group allows an arbitrary value from the URL
-        */
-       FilterGroup.prototype.isAllowArbitrary = function () {
-               return this.allowArbitrary;
-       };
-
-       /**
-        * Get group maximum value for numeric groups
-        *
-        * @return {number|null} Group max value
-        */
-       FilterGroup.prototype.getMaxValue = function () {
-               return this.numericRange && this.numericRange.max !== undefined ?
-                       this.numericRange.max : null;
-       };
-
-       /**
-        * Get group minimum value for numeric groups
-        *
-        * @return {number|null} Group max value
-        */
-       FilterGroup.prototype.getMinValue = function () {
-               return this.numericRange && this.numericRange.min !== undefined ?
-                       this.numericRange.min : null;
-       };
-
-       /**
-        * Get group name
-        *
-        * @return {string} Group name
-        */
-       FilterGroup.prototype.getName = function () {
-               return this.name;
-       };
-
-       /**
-        * Get the default param state of this group
-        *
-        * @return {Object} Default param state
-        */
-       FilterGroup.prototype.getDefaultParams = function () {
-               return this.defaultParams;
-       };
-
-       /**
-        * Get the default filter state of this group
-        *
-        * @return {Object} Default filter state
-        */
-       FilterGroup.prototype.getDefaultFilters = function () {
-               return this.defaultFilters;
-       };
-
-       /**
-        * This is for a single_option and string_options group types
-        * it returns the value of the default
-        *
-        * @return {string} Value of the default
-        */
-       FilterGroup.prototype.getDefaulParamValue = function () {
-               return this.defaultParams[ this.getName() ];
-       };
-       /**
-        * Get the messags defining the 'whats this' popup for this group
-        *
-        * @return {Object} What's this messages
-        */
-       FilterGroup.prototype.getWhatsThis = function () {
-               return this.whatsThis;
-       };
-
-       /**
-        * Check whether this group has a 'what's this' message
-        *
-        * @return {boolean} This group has a what's this message
-        */
-       FilterGroup.prototype.hasWhatsThis = function () {
-               return !!this.whatsThis.body;
-       };
-
-       /**
-        * Get the conflicts associated with the entire group.
-        * Conflict object is set up by filter name keys and conflict
-        * definition. For example:
-        * [
-        *     {
-        *         filterName: {
-        *             filter: filterName,
-        *             group: group1
-        *         }
-        *     },
-        *     {
-        *         filterName2: {
-        *             filter: filterName2,
-        *             group: group2
-        *         }
-        *     }
-        * ]
-        * @return {Object} Conflict definition
-        */
-       FilterGroup.prototype.getConflicts = function () {
-               return this.conflicts;
-       };
-
-       /**
-        * Set conflicts for this group. See #getConflicts for the expected
-        * structure of the definition.
-        *
-        * @param {Object} conflicts Conflicts for this group
-        */
-       FilterGroup.prototype.setConflicts = function ( conflicts ) {
-               this.conflicts = conflicts;
-       };
-
-       /**
-        * Set conflicts for each filter item in the group based on the
-        * given conflict map
-        *
-        * @param {Object} conflicts Object representing the conflict map,
-        *  keyed by the item name, where its value is an object for all its conflicts
-        */
-       FilterGroup.prototype.setFilterConflicts = function ( conflicts ) {
-               this.getItems().forEach( function ( filterItem ) {
-                       if ( conflicts[ filterItem.getName() ] ) {
-                               filterItem.setConflicts( conflicts[ filterItem.getName() ] );
-                       }
-               } );
-       };
-
-       /**
-        * Check whether this item has a potential conflict with the given item
-        *
-        * This checks whether the given item is in the list of conflicts of
-        * the current item, but makes no judgment about whether the conflict
-        * is currently at play (either one of the items may not be selected)
-        *
-        * @param {mw.rcfilters.dm.FilterItem} filterItem Filter item
-        * @return {boolean} This item has a conflict with the given item
-        */
-       FilterGroup.prototype.existsInConflicts = function ( filterItem ) {
-               return Object.prototype.hasOwnProperty.call( this.getConflicts(), filterItem.getName() );
-       };
-
-       /**
-        * Check whether there are any items selected
-        *
-        * @return {boolean} Any items in the group are selected
-        */
-       FilterGroup.prototype.areAnySelected = function () {
-               return this.getItems().some( function ( filterItem ) {
-                       return filterItem.isSelected();
-               } );
-       };
+       } );
+
+       // Add items
+       this.addItems( items );
+
+       // Now that we have all items, we can apply the superset map
+       this.getItems().forEach( function ( filterItem ) {
+               filterItem.setSuperset( supersetMap[ filterItem.getName() ] );
+       } );
+
+       // Store default parameter state; in this case, default is defined per the
+       // entire group, given by groupDefault method parameter
+       if ( this.getType() === 'string_options' ) {
+               // Store the default parameter group state
+               // For this group, the parameter is group name and value is the names
+               // of selected items
+               this.defaultParams[ this.getName() ] = mw.rcfilters.utils.normalizeParamOptions(
+                       // Current values
+                       groupDefault ?
+                               groupDefault.split( this.getSeparator() ) :
+                               [],
+                       // Legal values
+                       this.getItems().map( function ( item ) {
+                               return item.getParamName();
+                       } )
+               ).join( this.getSeparator() );
+       } else if ( this.getType() === 'single_option' ) {
+               defaultParam = groupDefault !== undefined ?
+                       groupDefault : this.getItems()[ 0 ].getParamName();
+
+               // For this group, the parameter is the group name,
+               // and a single item can be selected: default or first item
+               this.defaultParams[ this.getName() ] = defaultParam;
+       }
+
+       // add highlights to defaultParams
+       this.getItems().forEach( function ( filterItem ) {
+               if ( filterItem.isHighlighted() ) {
+                       this.defaultParams[ filterItem.getName() + '_color' ] = filterItem.getHighlightColor();
+               }
+       }.bind( this ) );
 
-       /**
-        * Check whether all items selected
-        *
-        * @return {boolean} All items are selected
-        */
-       FilterGroup.prototype.areAllSelected = function () {
-               var selected = [],
-                       unselected = [];
+       // Store default filter state based on default params
+       this.defaultFilters = this.getFilterRepresentation( this.getDefaultParams() );
 
-               this.getItems().forEach( function ( filterItem ) {
-                       if ( filterItem.isSelected() ) {
-                               selected.push( filterItem );
-                       } else {
-                               unselected.push( filterItem );
-                       }
+       // Check for filters that should be initially selected by their default value
+       if ( this.isSticky() ) {
+               // eslint-disable-next-line no-jquery/no-each-util
+               $.each( this.defaultFilters, function ( filterName, filterValue ) {
+                       model.getItemByName( filterName ).toggleSelected( filterValue );
                } );
-
-               if ( unselected.length === 0 ) {
-                       return true;
+       }
+
+       // Verify that single_option group has at least one item selected
+       if (
+               this.getType() === 'single_option' &&
+               this.findSelectedItems().length === 0
+       ) {
+               defaultParam = groupDefault !== undefined ?
+                       groupDefault : this.getItems()[ 0 ].getParamName();
+
+               // Single option means there must be a single option
+               // selected, so we have to either select the default
+               // or select the first option
+               this.selectItemByParamName( defaultParam );
+       }
+};
+
+/**
+ * Respond to filterItem update event
+ *
+ * @param {mw.rcfilters.dm.FilterItem} item Updated filter item
+ * @fires update
+ */
+FilterGroup.prototype.onFilterItemUpdate = function ( item ) {
+       // Update state
+       var changed = false,
+               active = this.areAnySelected(),
+               model = this;
+
+       if ( this.getType() === 'single_option' ) {
+               // This group must have one item selected always
+               // and must never have more than one item selected at a time
+               if ( this.findSelectedItems().length === 0 ) {
+                       // Nothing is selected anymore
+                       // Select the default or the first item
+                       this.currSelected = this.getItemByParamName( this.defaultParams[ this.getName() ] ) ||
+                               this.getItems()[ 0 ];
+                       this.currSelected.toggleSelected( true );
+                       changed = true;
+               } else if ( this.findSelectedItems().length > 1 ) {
+                       // There is more than one item selected
+                       // This should only happen if the item given
+                       // is the one that is selected, so unselect
+                       // all items that is not it
+                       this.findSelectedItems().forEach( function ( itemModel ) {
+                               // Note that in case the given item is actually
+                               // not selected, this loop will end up unselecting
+                               // all items, which would trigger the case above
+                               // when the last item is unselected anyways
+                               var selected = itemModel.getName() === item.getName() &&
+                                       item.isSelected();
+
+                               itemModel.toggleSelected( selected );
+                               if ( selected ) {
+                                       model.currSelected = itemModel;
+                               }
+                       } );
+                       changed = true;
                }
+       }
+
+       if ( this.isSticky() ) {
+               // If this group is sticky, then change the default according to the
+               // current selection.
+               this.defaultParams = this.getParamRepresentation( this.getSelectedState() );
+       }
+
+       if (
+               changed ||
+               this.active !== active ||
+               this.currSelected !== item
+       ) {
+               this.active = active;
+               this.currSelected = item;
+
+               this.emit( 'update' );
+       }
+};
+
+/**
+ * Get group active state
+ *
+ * @return {boolean} Active state
+ */
+FilterGroup.prototype.isActive = function () {
+       return this.active;
+};
+
+/**
+ * Get group hidden state
+ *
+ * @return {boolean} Hidden state
+ */
+FilterGroup.prototype.isHidden = function () {
+       return this.hidden;
+};
+
+/**
+ * Get group allow arbitrary state
+ *
+ * @return {boolean} Group allows an arbitrary value from the URL
+ */
+FilterGroup.prototype.isAllowArbitrary = function () {
+       return this.allowArbitrary;
+};
+
+/**
+ * Get group maximum value for numeric groups
+ *
+ * @return {number|null} Group max value
+ */
+FilterGroup.prototype.getMaxValue = function () {
+       return this.numericRange && this.numericRange.max !== undefined ?
+               this.numericRange.max : null;
+};
+
+/**
+ * Get group minimum value for numeric groups
+ *
+ * @return {number|null} Group max value
+ */
+FilterGroup.prototype.getMinValue = function () {
+       return this.numericRange && this.numericRange.min !== undefined ?
+               this.numericRange.min : null;
+};
+
+/**
+ * Get group name
+ *
+ * @return {string} Group name
+ */
+FilterGroup.prototype.getName = function () {
+       return this.name;
+};
+
+/**
+ * Get the default param state of this group
+ *
+ * @return {Object} Default param state
+ */
+FilterGroup.prototype.getDefaultParams = function () {
+       return this.defaultParams;
+};
+
+/**
+ * Get the default filter state of this group
+ *
+ * @return {Object} Default filter state
+ */
+FilterGroup.prototype.getDefaultFilters = function () {
+       return this.defaultFilters;
+};
+
+/**
+ * Get the messags defining the 'whats this' popup for this group
+ *
+ * @return {Object} What's this messages
+ */
+FilterGroup.prototype.getWhatsThis = function () {
+       return this.whatsThis;
+};
+
+/**
+ * Check whether this group has a 'what's this' message
+ *
+ * @return {boolean} This group has a what's this message
+ */
+FilterGroup.prototype.hasWhatsThis = function () {
+       return !!this.whatsThis.body;
+};
+
+/**
+ * Get the conflicts associated with the entire group.
+ * Conflict object is set up by filter name keys and conflict
+ * definition. For example:
+ * [
+ *     {
+ *         filterName: {
+ *             filter: filterName,
+ *             group: group1
+ *         }
+ *     },
+ *     {
+ *         filterName2: {
+ *             filter: filterName2,
+ *             group: group2
+ *         }
+ *     }
+ * ]
+ * @return {Object} Conflict definition
+ */
+FilterGroup.prototype.getConflicts = function () {
+       return this.conflicts;
+};
+
+/**
+ * Set conflicts for this group. See #getConflicts for the expected
+ * structure of the definition.
+ *
+ * @param {Object} conflicts Conflicts for this group
+ */
+FilterGroup.prototype.setConflicts = function ( conflicts ) {
+       this.conflicts = conflicts;
+};
+
+/**
+ * Check whether this item has a potential conflict with the given item
+ *
+ * This checks whether the given item is in the list of conflicts of
+ * the current item, but makes no judgment about whether the conflict
+ * is currently at play (either one of the items may not be selected)
+ *
+ * @param {mw.rcfilters.dm.FilterItem} filterItem Filter item
+ * @return {boolean} This item has a conflict with the given item
+ */
+FilterGroup.prototype.existsInConflicts = function ( filterItem ) {
+       return Object.prototype.hasOwnProperty.call( this.getConflicts(), filterItem.getName() );
+};
+
+/**
+ * Check whether there are any items selected
+ *
+ * @return {boolean} Any items in the group are selected
+ */
+FilterGroup.prototype.areAnySelected = function () {
+       return this.getItems().some( function ( filterItem ) {
+               return filterItem.isSelected();
+       } );
+};
+
+/**
+ * Check whether all items selected
+ *
+ * @return {boolean} All items are selected
+ */
+FilterGroup.prototype.areAllSelected = function () {
+       var selected = [],
+               unselected = [];
+
+       this.getItems().forEach( function ( filterItem ) {
+               if ( filterItem.isSelected() ) {
+                       selected.push( filterItem );
+               } else {
+                       unselected.push( filterItem );
+               }
+       } );
 
-               // check if every unselected is a subset of a selected
-               return unselected.every( function ( unselectedFilterItem ) {
-                       return selected.some( function ( selectedFilterItem ) {
-                               return selectedFilterItem.existsInSubset( unselectedFilterItem.getName() );
-                       } );
-               } );
-       };
-
-       /**
-        * Get all selected items in this group
-        *
-        * @param {mw.rcfilters.dm.FilterItem} [excludeItem] Item to exclude from the list
-        * @return {mw.rcfilters.dm.FilterItem[]} Selected items
-        */
-       FilterGroup.prototype.findSelectedItems = function ( excludeItem ) {
-               var excludeName = ( excludeItem && excludeItem.getName() ) || '';
-
-               return this.getItems().filter( function ( item ) {
-                       return item.getName() !== excludeName && item.isSelected();
+       if ( unselected.length === 0 ) {
+               return true;
+       }
+
+       // check if every unselected is a subset of a selected
+       return unselected.every( function ( unselectedFilterItem ) {
+               return selected.some( function ( selectedFilterItem ) {
+                       return selectedFilterItem.existsInSubset( unselectedFilterItem.getName() );
                } );
-       };
-
-       /**
-        * Check whether all selected items are in conflict with the given item
-        *
-        * @param {mw.rcfilters.dm.FilterItem} filterItem Filter item to test
-        * @return {boolean} All selected items are in conflict with this item
-        */
-       FilterGroup.prototype.areAllSelectedInConflictWith = function ( filterItem ) {
-               var selectedItems = this.findSelectedItems( filterItem );
-
-               return selectedItems.length > 0 &&
-                       (
-                               // The group as a whole is in conflict with this item
-                               this.existsInConflicts( filterItem ) ||
-                               // All selected items are in conflict individually
-                               selectedItems.every( function ( selectedFilter ) {
-                                       return selectedFilter.existsInConflicts( filterItem );
-                               } )
-                       );
-       };
-
-       /**
-        * Check whether any of the selected items are in conflict with the given item
-        *
-        * @param {mw.rcfilters.dm.FilterItem} filterItem Filter item to test
-        * @return {boolean} Any of the selected items are in conflict with this item
-        */
-       FilterGroup.prototype.areAnySelectedInConflictWith = function ( filterItem ) {
-               var selectedItems = this.findSelectedItems( filterItem );
-
-               return selectedItems.length > 0 && (
+       } );
+};
+
+/**
+ * Get all selected items in this group
+ *
+ * @param {mw.rcfilters.dm.FilterItem} [excludeItem] Item to exclude from the list
+ * @return {mw.rcfilters.dm.FilterItem[]} Selected items
+ */
+FilterGroup.prototype.findSelectedItems = function ( excludeItem ) {
+       var excludeName = ( excludeItem && excludeItem.getName() ) || '';
+
+       return this.getItems().filter( function ( item ) {
+               return item.getName() !== excludeName && item.isSelected();
+       } );
+};
+
+/**
+ * Check whether all selected items are in conflict with the given item
+ *
+ * @param {mw.rcfilters.dm.FilterItem} filterItem Filter item to test
+ * @return {boolean} All selected items are in conflict with this item
+ */
+FilterGroup.prototype.areAllSelectedInConflictWith = function ( filterItem ) {
+       var selectedItems = this.findSelectedItems( filterItem );
+
+       return selectedItems.length > 0 &&
+               (
                        // The group as a whole is in conflict with this item
                        this.existsInConflicts( filterItem ) ||
-                       // Any selected items are in conflict individually
-                       selectedItems.some( function ( selectedFilter ) {
+                       // All selected items are in conflict individually
+                       selectedItems.every( function ( selectedFilter ) {
                                return selectedFilter.existsInConflicts( filterItem );
                        } )
                );
-       };
-
-       /**
-        * Get the parameter representation from this group
-        *
-        * @param {Object} [filterRepresentation] An object defining the state
-        *  of the filters in this group, keyed by their name and current selected
-        *  state value.
-        * @return {Object} Parameter representation
-        */
-       FilterGroup.prototype.getParamRepresentation = function ( filterRepresentation ) {
-               var values,
-                       areAnySelected = false,
-                       buildFromCurrentState = !filterRepresentation,
-                       defaultFilters = this.getDefaultFilters(),
-                       result = {},
-                       model = this,
-                       filterParamNames = {},
-                       getSelectedParameter = function ( filters ) {
-                               var item,
-                                       selected = [];
-
-                               // Find if any are selected
-                               // eslint-disable-next-line no-jquery/no-each-util
-                               $.each( filters, function ( name, value ) {
-                                       if ( value ) {
-                                               selected.push( name );
-                                       }
-                               } );
-
-                               item = model.getItemByName( selected[ 0 ] );
-                               return ( item && item.getParamName() ) || '';
-                       };
-
-               filterRepresentation = filterRepresentation || {};
-
-               // Create or complete the filterRepresentation definition
-               this.getItems().forEach( function ( item ) {
-                       // Map filter names to their parameter names
-                       filterParamNames[ item.getName() ] = item.getParamName();
-
-                       if ( buildFromCurrentState ) {
-                               // This means we have not been given a filter representation
-                               // so we are building one based on current state
-                               filterRepresentation[ item.getName() ] = item.getValue();
-                       } else if ( filterRepresentation[ item.getName() ] === undefined ) {
-                               // We are given a filter representation, but we have to make
-                               // sure that we fill in the missing filters if there are any
-                               // we will assume they are all falsey
-                               if ( model.isSticky() ) {
-                                       filterRepresentation[ item.getName() ] = !!defaultFilters[ item.getName() ];
-                               } else {
-                                       filterRepresentation[ item.getName() ] = false;
-                               }
-                       }
-
-                       if ( filterRepresentation[ item.getName() ] ) {
-                               areAnySelected = true;
-                       }
-               } );
-
-               // Build result
-               if (
-                       this.getType() === 'send_unselected_if_any' ||
-                       this.getType() === 'boolean' ||
-                       this.getType() === 'any_value'
-               ) {
-                       // First, check if any of the items are selected at all.
-                       // If none is selected, we're treating it as if they are
-                       // all false
-
-                       // Go over the items and define the correct values
+};
+
+/**
+ * Check whether any of the selected items are in conflict with the given item
+ *
+ * @param {mw.rcfilters.dm.FilterItem} filterItem Filter item to test
+ * @return {boolean} Any of the selected items are in conflict with this item
+ */
+FilterGroup.prototype.areAnySelectedInConflictWith = function ( filterItem ) {
+       var selectedItems = this.findSelectedItems( filterItem );
+
+       return selectedItems.length > 0 && (
+               // The group as a whole is in conflict with this item
+               this.existsInConflicts( filterItem ) ||
+               // Any selected items are in conflict individually
+               selectedItems.some( function ( selectedFilter ) {
+                       return selectedFilter.existsInConflicts( filterItem );
+               } )
+       );
+};
+
+/**
+ * Get the parameter representation from this group
+ *
+ * @param {Object} [filterRepresentation] An object defining the state
+ *  of the filters in this group, keyed by their name and current selected
+ *  state value.
+ * @return {Object} Parameter representation
+ */
+FilterGroup.prototype.getParamRepresentation = function ( filterRepresentation ) {
+       var values,
+               areAnySelected = false,
+               buildFromCurrentState = !filterRepresentation,
+               defaultFilters = this.getDefaultFilters(),
+               result = {},
+               model = this,
+               filterParamNames = {},
+               getSelectedParameter = function ( filters ) {
+                       var item,
+                               selected = [];
+
+                       // Find if any are selected
                        // eslint-disable-next-line no-jquery/no-each-util
-                       $.each( filterRepresentation, function ( name, value ) {
-                               // We must store all parameter values as strings '0' or '1'
-                               if ( model.getType() === 'send_unselected_if_any' ) {
-                                       result[ filterParamNames[ name ] ] = areAnySelected ?
-                                               String( Number( !value ) ) :
-                                               '0';
-                               } else if ( model.getType() === 'boolean' ) {
-                                       // Representation is straight-forward and direct from
-                                       // the parameter value to the filter state
-                                       result[ filterParamNames[ name ] ] = String( Number( !!value ) );
-                               } else if ( model.getType() === 'any_value' ) {
-                                       result[ filterParamNames[ name ] ] = value;
-                               }
-                       } );
-               } else if ( this.getType() === 'string_options' ) {
-                       values = [];
-
-                       // eslint-disable-next-line no-jquery/no-each-util
-                       $.each( filterRepresentation, function ( name, value ) {
-                               // Collect values
+                       $.each( filters, function ( name, value ) {
                                if ( value ) {
-                                       values.push( filterParamNames[ name ] );
+                                       selected.push( name );
                                }
                        } );
 
-                       result[ this.getName() ] = ( values.length === Object.keys( filterRepresentation ).length ) ?
-                               'all' : values.join( this.getSeparator() );
-               } else if ( this.getType() === 'single_option' ) {
-                       result[ this.getName() ] = getSelectedParameter( filterRepresentation );
-               }
-
-               return result;
-       };
-
-       /**
-        * Get the filter representation this group would provide
-        * based on given parameter states.
-        *
-        * @param {Object} [paramRepresentation] An object defining a parameter
-        *  state to translate the filter state from. If not given, an object
-        *  representing all filters as falsey is returned; same as if the parameter
-        *  given were an empty object, or had some of the filters missing.
-        * @return {Object} Filter representation
-        */
-       FilterGroup.prototype.getFilterRepresentation = function ( paramRepresentation ) {
-               var areAnySelected, paramValues, item, currentValue,
-                       oneWasSelected = false,
-                       defaultParams = this.getDefaultParams(),
-                       expandedParams = $.extend( true, {}, paramRepresentation ),
-                       model = this,
-                       paramToFilterMap = {},
-                       result = {};
-
-               if ( this.isSticky() ) {
-                       // If the group is sticky, check if all parameters are represented
-                       // and for those that aren't represented, add them with their default
-                       // values
-                       paramRepresentation = $.extend( true, {}, this.getDefaultParams(), paramRepresentation );
+                       item = model.getItemByName( selected[ 0 ] );
+                       return ( item && item.getParamName() ) || '';
+               };
+
+       filterRepresentation = filterRepresentation || {};
+
+       // Create or complete the filterRepresentation definition
+       this.getItems().forEach( function ( item ) {
+               // Map filter names to their parameter names
+               filterParamNames[ item.getName() ] = item.getParamName();
+
+               if ( buildFromCurrentState ) {
+                       // This means we have not been given a filter representation
+                       // so we are building one based on current state
+                       filterRepresentation[ item.getName() ] = item.getValue();
+               } else if ( filterRepresentation[ item.getName() ] === undefined ) {
+                       // We are given a filter representation, but we have to make
+                       // sure that we fill in the missing filters if there are any
+                       // we will assume they are all falsey
+                       if ( model.isSticky() ) {
+                               filterRepresentation[ item.getName() ] = !!defaultFilters[ item.getName() ];
+                       } else {
+                               filterRepresentation[ item.getName() ] = false;
+                       }
                }
 
-               paramRepresentation = paramRepresentation || {};
-               if (
-                       this.getType() === 'send_unselected_if_any' ||
-                       this.getType() === 'boolean' ||
-                       this.getType() === 'any_value'
-               ) {
-                       // Go over param representation; map and check for selections
-                       this.getItems().forEach( function ( filterItem ) {
-                               var paramName = filterItem.getParamName();
-
-                               expandedParams[ paramName ] = paramRepresentation[ paramName ] || '0';
-                               paramToFilterMap[ paramName ] = filterItem;
-
-                               if ( Number( paramRepresentation[ filterItem.getParamName() ] ) ) {
-                                       areAnySelected = true;
-                               }
-                       } );
-
-                       // eslint-disable-next-line no-jquery/no-each-util
-                       $.each( expandedParams, function ( paramName, paramValue ) {
-                               var filterItem = paramToFilterMap[ paramName ];
-
-                               if ( model.getType() === 'send_unselected_if_any' ) {
-                                       // Flip the definition between the parameter
-                                       // state and the filter state
-                                       // This is what the 'toggleSelected' value of the filter is
-                                       result[ filterItem.getName() ] = areAnySelected ?
-                                               !Number( paramValue ) :
-                                               // Otherwise, there are no selected items in the
-                                               // group, which means the state is false
-                                               false;
-                               } else if ( model.getType() === 'boolean' ) {
-                                       // Straight-forward definition of state
-                                       result[ filterItem.getName() ] = !!Number( paramRepresentation[ filterItem.getParamName() ] );
-                               } else if ( model.getType() === 'any_value' ) {
-                                       result[ filterItem.getName() ] = paramRepresentation[ filterItem.getParamName() ];
-                               }
-                       } );
-               } else if ( this.getType() === 'string_options' ) {
-                       currentValue = paramRepresentation[ this.getName() ] || '';
-
-                       // Normalize the given parameter values
-                       paramValues = mw.rcfilters.utils.normalizeParamOptions(
-                               // Given
-                               currentValue.split(
-                                       this.getSeparator()
-                               ),
-                               // Allowed values
-                               this.getItems().map( function ( filterItem ) {
-                                       return filterItem.getParamName();
-                               } )
-                       );
-                       // Translate the parameter values into a filter selection state
-                       this.getItems().forEach( function ( filterItem ) {
-                               // All true (either because all values are written or the term 'all' is written)
-                               // is the same as all filters set to true
-                               result[ filterItem.getName() ] = (
-                                       // If it is the word 'all'
-                                       paramValues.length === 1 && paramValues[ 0 ] === 'all' ||
-                                       // All values are written
-                                       paramValues.length === model.getItemCount()
-                               ) ?
-                                       true :
-                                       // Otherwise, the filter is selected only if it appears in the parameter values
-                                       paramValues.indexOf( filterItem.getParamName() ) > -1;
-                       } );
-               } else if ( this.getType() === 'single_option' ) {
-                       // There is parameter that fits a single filter and if not, get the default
-                       this.getItems().forEach( function ( filterItem ) {
-                               var selected = filterItem.getParamName() === paramRepresentation[ model.getName() ];
-
-                               result[ filterItem.getName() ] = selected;
-                               oneWasSelected = oneWasSelected || selected;
-                       } );
+               if ( filterRepresentation[ item.getName() ] ) {
+                       areAnySelected = true;
                }
-
-               // Go over result and make sure all filters are represented.
-               // If any filters are missing, they will get a falsey value
-               this.getItems().forEach( function ( filterItem ) {
-                       if ( result[ filterItem.getName() ] === undefined ) {
-                               result[ filterItem.getName() ] = this.getFalsyValue();
+       } );
+
+       // Build result
+       if (
+               this.getType() === 'send_unselected_if_any' ||
+               this.getType() === 'boolean' ||
+               this.getType() === 'any_value'
+       ) {
+               // First, check if any of the items are selected at all.
+               // If none is selected, we're treating it as if they are
+               // all false
+
+               // Go over the items and define the correct values
+               // eslint-disable-next-line no-jquery/no-each-util
+               $.each( filterRepresentation, function ( name, value ) {
+                       // We must store all parameter values as strings '0' or '1'
+                       if ( model.getType() === 'send_unselected_if_any' ) {
+                               result[ filterParamNames[ name ] ] = areAnySelected ?
+                                       String( Number( !value ) ) :
+                                       '0';
+                       } else if ( model.getType() === 'boolean' ) {
+                               // Representation is straight-forward and direct from
+                               // the parameter value to the filter state
+                               result[ filterParamNames[ name ] ] = String( Number( !!value ) );
+                       } else if ( model.getType() === 'any_value' ) {
+                               result[ filterParamNames[ name ] ] = value;
                        }
-               }.bind( this ) );
-
-               // Make sure that at least one option is selected in
-               // single_option groups, no matter what path was taken
-               // If none was selected by the given definition, then
-               // we need to select the one in the base state -- either
-               // the default given, or the first item
-               if (
-                       this.getType() === 'single_option' &&
-                       !oneWasSelected
-               ) {
-                       item = this.getItems()[ 0 ];
-                       if ( defaultParams[ this.getName() ] ) {
-                               item = this.getItemByParamName( defaultParams[ this.getName() ] );
+               } );
+       } else if ( this.getType() === 'string_options' ) {
+               values = [];
+
+               // eslint-disable-next-line no-jquery/no-each-util
+               $.each( filterRepresentation, function ( name, value ) {
+                       // Collect values
+                       if ( value ) {
+                               values.push( filterParamNames[ name ] );
                        }
+               } );
 
-                       result[ item.getName() ] = true;
-               }
-
-               return result;
-       };
-
-       /**
-        * @return {*} The appropriate falsy value for this group type
-        */
-       FilterGroup.prototype.getFalsyValue = function () {
-               return this.getType() === 'any_value' ? '' : false;
-       };
+               result[ this.getName() ] = ( values.length === Object.keys( filterRepresentation ).length ) ?
+                       'all' : values.join( this.getSeparator() );
+       } else if ( this.getType() === 'single_option' ) {
+               result[ this.getName() ] = getSelectedParameter( filterRepresentation );
+       }
+
+       return result;
+};
+
+/**
+ * Get the filter representation this group would provide
+ * based on given parameter states.
+ *
+ * @param {Object} [paramRepresentation] An object defining a parameter
+ *  state to translate the filter state from. If not given, an object
+ *  representing all filters as falsey is returned; same as if the parameter
+ *  given were an empty object, or had some of the filters missing.
+ * @return {Object} Filter representation
+ */
+FilterGroup.prototype.getFilterRepresentation = function ( paramRepresentation ) {
+       var areAnySelected, paramValues, item, currentValue,
+               oneWasSelected = false,
+               defaultParams = this.getDefaultParams(),
+               expandedParams = $.extend( true, {}, paramRepresentation ),
+               model = this,
+               paramToFilterMap = {},
+               result = {};
+
+       if ( this.isSticky() ) {
+               // If the group is sticky, check if all parameters are represented
+               // and for those that aren't represented, add them with their default
+               // values
+               paramRepresentation = $.extend( true, {}, this.getDefaultParams(), paramRepresentation );
+       }
+
+       paramRepresentation = paramRepresentation || {};
+       if (
+               this.getType() === 'send_unselected_if_any' ||
+               this.getType() === 'boolean' ||
+               this.getType() === 'any_value'
+       ) {
+               // Go over param representation; map and check for selections
+               this.getItems().forEach( function ( filterItem ) {
+                       var paramName = filterItem.getParamName();
 
-       /**
-        * Get current selected state of all filter items in this group
-        *
-        * @return {Object} Selected state
-        */
-       FilterGroup.prototype.getSelectedState = function () {
-               var state = {};
+                       expandedParams[ paramName ] = paramRepresentation[ paramName ] || '0';
+                       paramToFilterMap[ paramName ] = filterItem;
 
-               this.getItems().forEach( function ( filterItem ) {
-                       state[ filterItem.getName() ] = filterItem.getValue();
+                       if ( Number( paramRepresentation[ filterItem.getParamName() ] ) ) {
+                               areAnySelected = true;
+                       }
                } );
 
-               return state;
-       };
-
-       /**
-        * Get item by its filter name
-        *
-        * @param {string} filterName Filter name
-        * @return {mw.rcfilters.dm.FilterItem} Filter item
-        */
-       FilterGroup.prototype.getItemByName = function ( filterName ) {
-               return this.getItems().filter( function ( item ) {
-                       return item.getName() === filterName;
-               } )[ 0 ];
-       };
-
-       /**
-        * Select an item by its parameter name
-        *
-        * @param {string} paramName Filter parameter name
-        */
-       FilterGroup.prototype.selectItemByParamName = function ( paramName ) {
-               this.getItems().forEach( function ( item ) {
-                       item.toggleSelected( item.getParamName() === String( paramName ) );
+               // eslint-disable-next-line no-jquery/no-each-util
+               $.each( expandedParams, function ( paramName, paramValue ) {
+                       var filterItem = paramToFilterMap[ paramName ];
+
+                       if ( model.getType() === 'send_unselected_if_any' ) {
+                               // Flip the definition between the parameter
+                               // state and the filter state
+                               // This is what the 'toggleSelected' value of the filter is
+                               result[ filterItem.getName() ] = areAnySelected ?
+                                       !Number( paramValue ) :
+                                       // Otherwise, there are no selected items in the
+                                       // group, which means the state is false
+                                       false;
+                       } else if ( model.getType() === 'boolean' ) {
+                               // Straight-forward definition of state
+                               result[ filterItem.getName() ] = !!Number( paramRepresentation[ filterItem.getParamName() ] );
+                       } else if ( model.getType() === 'any_value' ) {
+                               result[ filterItem.getName() ] = paramRepresentation[ filterItem.getParamName() ];
+                       }
                } );
-       };
-
-       /**
-        * Get item by its parameter name
-        *
-        * @param {string} paramName Parameter name
-        * @return {mw.rcfilters.dm.FilterItem} Filter item
-        */
-       FilterGroup.prototype.getItemByParamName = function ( paramName ) {
-               return this.getItems().filter( function ( item ) {
-                       return item.getParamName() === String( paramName );
-               } )[ 0 ];
-       };
-
-       /**
-        * Get group type
-        *
-        * @return {string} Group type
-        */
-       FilterGroup.prototype.getType = function () {
-               return this.type;
-       };
-
-       /**
-        * Check whether this group is represented by a single parameter
-        * or whether each item is its own parameter
-        *
-        * @return {boolean} This group is a single parameter
-        */
-       FilterGroup.prototype.isPerGroupRequestParameter = function () {
-               return (
-                       this.getType() === 'string_options' ||
-                       this.getType() === 'single_option'
+       } else if ( this.getType() === 'string_options' ) {
+               currentValue = paramRepresentation[ this.getName() ] || '';
+
+               // Normalize the given parameter values
+               paramValues = mw.rcfilters.utils.normalizeParamOptions(
+                       // Given
+                       currentValue.split(
+                               this.getSeparator()
+                       ),
+                       // Allowed values
+                       this.getItems().map( function ( filterItem ) {
+                               return filterItem.getParamName();
+                       } )
                );
-       };
-
-       /**
-        * Get display group
-        *
-        * @return {string} Display group
-        */
-       FilterGroup.prototype.getView = function () {
-               return this.view;
-       };
-
-       /**
-        * Get the prefix used for the filter names inside this group.
-        *
-        * @param {string} [name] Filter name to prefix
-        * @return {string} Group prefix
-        */
-       FilterGroup.prototype.getNamePrefix = function () {
-               return this.getName() + '__';
-       };
-
-       /**
-        * Get a filter name with the prefix used for the filter names inside this group.
-        *
-        * @param {string} name Filter name to prefix
-        * @return {string} Group prefix
-        */
-       FilterGroup.prototype.getPrefixedName = function ( name ) {
-               return this.getNamePrefix() + name;
-       };
-
-       /**
-        * Get group's title
-        *
-        * @return {string} Title
-        */
-       FilterGroup.prototype.getTitle = function () {
-               return this.title;
-       };
-
-       /**
-        * Get group's values separator
-        *
-        * @return {string} Values separator
-        */
-       FilterGroup.prototype.getSeparator = function () {
-               return this.separator;
-       };
-
-       /**
-        * Check whether the group is defined as full coverage
-        *
-        * @return {boolean} Group is full coverage
-        */
-       FilterGroup.prototype.isFullCoverage = function () {
-               return this.fullCoverage;
-       };
-
-       /**
-        * Check whether the group is defined as sticky default
-        *
-        * @return {boolean} Group is sticky default
-        */
-       FilterGroup.prototype.isSticky = function () {
-               return this.sticky;
-       };
-
-       /**
-        * Normalize a value given to this group. This is mostly for correcting
-        * arbitrary values for 'single option' groups, given by the user settings
-        * or the URL that can go outside the limits that are allowed.
-        *
-        * @param  {string} value Given value
-        * @return {string} Corrected value
-        */
-       FilterGroup.prototype.normalizeArbitraryValue = function ( value ) {
-               if (
-                       this.getType() === 'single_option' &&
-                       this.isAllowArbitrary()
-               ) {
-                       if (
-                               this.getMaxValue() !== null &&
-                               value > this.getMaxValue()
-                       ) {
-                               // Change the value to the actual max value
-                               return String( this.getMaxValue() );
-                       } else if (
-                               this.getMinValue() !== null &&
-                               value < this.getMinValue()
-                       ) {
-                               // Change the value to the actual min value
-                               return String( this.getMinValue() );
-                       }
-               }
-
-               return value;
-       };
+               // Translate the parameter values into a filter selection state
+               this.getItems().forEach( function ( filterItem ) {
+                       // All true (either because all values are written or the term 'all' is written)
+                       // is the same as all filters set to true
+                       result[ filterItem.getName() ] = (
+                               // If it is the word 'all'
+                               paramValues.length === 1 && paramValues[ 0 ] === 'all' ||
+                               // All values are written
+                               paramValues.length === model.getItemCount()
+                       ) ?
+                               true :
+                               // Otherwise, the filter is selected only if it appears in the parameter values
+                               paramValues.indexOf( filterItem.getParamName() ) > -1;
+               } );
+       } else if ( this.getType() === 'single_option' ) {
+               // There is parameter that fits a single filter and if not, get the default
+               this.getItems().forEach( function ( filterItem ) {
+                       var selected = filterItem.getParamName() === paramRepresentation[ model.getName() ];
 
-       /**
-        * Toggle the visibility of this group
-        *
-        * @param {boolean} [isVisible] Item is visible
-        */
-       FilterGroup.prototype.toggleVisible = function ( isVisible ) {
-               isVisible = isVisible === undefined ? !this.visible : isVisible;
+                       result[ filterItem.getName() ] = selected;
+                       oneWasSelected = oneWasSelected || selected;
+               } );
+       }
 
-               if ( this.visible !== isVisible ) {
-                       this.visible = isVisible;
-                       this.emit( 'update' );
+       // Go over result and make sure all filters are represented.
+       // If any filters are missing, they will get a falsey value
+       this.getItems().forEach( function ( filterItem ) {
+               if ( result[ filterItem.getName() ] === undefined ) {
+                       result[ filterItem.getName() ] = this.getFalsyValue();
+               }
+       }.bind( this ) );
+
+       // Make sure that at least one option is selected in
+       // single_option groups, no matter what path was taken
+       // If none was selected by the given definition, then
+       // we need to select the one in the base state -- either
+       // the default given, or the first item
+       if (
+               this.getType() === 'single_option' &&
+               !oneWasSelected
+       ) {
+               item = this.getItems()[ 0 ];
+               if ( defaultParams[ this.getName() ] ) {
+                       item = this.getItemByParamName( defaultParams[ this.getName() ] );
                }
-       };
-
-       /**
-        * Check whether the group is visible
-        *
-        * @return {boolean} Group is visible
-        */
-       FilterGroup.prototype.isVisible = function () {
-               return this.visible;
-       };
-
-       /**
-        * Set the visibility of the items under this group by the given items array
-        *
-        * @param {mw.rcfilters.dm.ItemModel[]} visibleItems An array of visible items
-        */
-       FilterGroup.prototype.setVisibleItems = function ( visibleItems ) {
-               this.getItems().forEach( function ( itemModel ) {
-                       itemModel.toggleVisible( visibleItems.indexOf( itemModel ) !== -1 );
-               } );
-       };
 
-       module.exports = FilterGroup;
-}() );
+               result[ item.getName() ] = true;
+       }
+
+       return result;
+};
+
+/**
+ * @return {*} The appropriate falsy value for this group type
+ */
+FilterGroup.prototype.getFalsyValue = function () {
+       return this.getType() === 'any_value' ? '' : false;
+};
+
+/**
+ * Get current selected state of all filter items in this group
+ *
+ * @return {Object} Selected state
+ */
+FilterGroup.prototype.getSelectedState = function () {
+       var state = {};
+
+       this.getItems().forEach( function ( filterItem ) {
+               state[ filterItem.getName() ] = filterItem.getValue();
+       } );
+
+       return state;
+};
+
+/**
+ * Get item by its filter name
+ *
+ * @param {string} filterName Filter name
+ * @return {mw.rcfilters.dm.FilterItem} Filter item
+ */
+FilterGroup.prototype.getItemByName = function ( filterName ) {
+       return this.getItems().filter( function ( item ) {
+               return item.getName() === filterName;
+       } )[ 0 ];
+};
+
+/**
+ * Select an item by its parameter name
+ *
+ * @param {string} paramName Filter parameter name
+ */
+FilterGroup.prototype.selectItemByParamName = function ( paramName ) {
+       this.getItems().forEach( function ( item ) {
+               item.toggleSelected( item.getParamName() === String( paramName ) );
+       } );
+};
+
+/**
+ * Get item by its parameter name
+ *
+ * @param {string} paramName Parameter name
+ * @return {mw.rcfilters.dm.FilterItem} Filter item
+ */
+FilterGroup.prototype.getItemByParamName = function ( paramName ) {
+       return this.getItems().filter( function ( item ) {
+               return item.getParamName() === String( paramName );
+       } )[ 0 ];
+};
+
+/**
+ * Get group type
+ *
+ * @return {string} Group type
+ */
+FilterGroup.prototype.getType = function () {
+       return this.type;
+};
+
+/**
+ * Check whether this group is represented by a single parameter
+ * or whether each item is its own parameter
+ *
+ * @return {boolean} This group is a single parameter
+ */
+FilterGroup.prototype.isPerGroupRequestParameter = function () {
+       return (
+               this.getType() === 'string_options' ||
+               this.getType() === 'single_option'
+       );
+};
+
+/**
+ * Get display group
+ *
+ * @return {string} Display group
+ */
+FilterGroup.prototype.getView = function () {
+       return this.view;
+};
+
+/**
+ * Get the prefix used for the filter names inside this group.
+ *
+ * @return {string} Group prefix
+ */
+FilterGroup.prototype.getNamePrefix = function () {
+       return this.getName() + '__';
+};
+
+/**
+ * Get a filter name with the prefix used for the filter names inside this group.
+ *
+ * @param {string} name Filter name to prefix
+ * @return {string} Group prefix
+ */
+FilterGroup.prototype.getPrefixedName = function ( name ) {
+       return this.getNamePrefix() + name;
+};
+
+/**
+ * Get group's title
+ *
+ * @return {string} Title
+ */
+FilterGroup.prototype.getTitle = function () {
+       return this.title;
+};
+
+/**
+ * Get group's values separator
+ *
+ * @return {string} Values separator
+ */
+FilterGroup.prototype.getSeparator = function () {
+       return this.separator;
+};
+
+/**
+ * Check whether the group is defined as full coverage
+ *
+ * @return {boolean} Group is full coverage
+ */
+FilterGroup.prototype.isFullCoverage = function () {
+       return this.fullCoverage;
+};
+
+/**
+ * Check whether the group is defined as sticky default
+ *
+ * @return {boolean} Group is sticky default
+ */
+FilterGroup.prototype.isSticky = function () {
+       return this.sticky;
+};
+
+/**
+ * Normalize a value given to this group. This is mostly for correcting
+ * arbitrary values for 'single option' groups, given by the user settings
+ * or the URL that can go outside the limits that are allowed.
+ *
+ * @param  {string} value Given value
+ * @return {string} Corrected value
+ */
+FilterGroup.prototype.normalizeArbitraryValue = function ( value ) {
+       if (
+               this.getType() === 'single_option' &&
+               this.isAllowArbitrary()
+       ) {
+               if (
+                       this.getMaxValue() !== null &&
+                       value > this.getMaxValue()
+               ) {
+                       // Change the value to the actual max value
+                       return String( this.getMaxValue() );
+               } else if (
+                       this.getMinValue() !== null &&
+                       value < this.getMinValue()
+               ) {
+                       // Change the value to the actual min value
+                       return String( this.getMinValue() );
+               }
+       }
+
+       return value;
+};
+
+/**
+ * Toggle the visibility of this group
+ *
+ * @param {boolean} [isVisible] Item is visible
+ */
+FilterGroup.prototype.toggleVisible = function ( isVisible ) {
+       isVisible = isVisible === undefined ? !this.visible : isVisible;
+
+       if ( this.visible !== isVisible ) {
+               this.visible = isVisible;
+               this.emit( 'update' );
+       }
+};
+
+/**
+ * Check whether the group is visible
+ *
+ * @return {boolean} Group is visible
+ */
+FilterGroup.prototype.isVisible = function () {
+       return this.visible;
+};
+
+/**
+ * Set the visibility of the items under this group by the given items array
+ *
+ * @param {mw.rcfilters.dm.ItemModel[]} visibleItems An array of visible items
+ */
+FilterGroup.prototype.setVisibleItems = function ( visibleItems ) {
+       this.getItems().forEach( function ( itemModel ) {
+               itemModel.toggleVisible( visibleItems.indexOf( itemModel ) !== -1 );
+       } );
+};
+
+module.exports = FilterGroup;
index 1138c4e..50057af 100644 (file)
-( function () {
-       var ItemModel = require( './ItemModel.js' ),
-               FilterItem;
-
-       /**
-        * Filter item model
-        *
-        * @class mw.rcfilters.dm.FilterItem
-        * @extends mw.rcfilters.dm.ItemModel
-        *
-        * @constructor
-        * @param {string} param Filter param name
-        * @param {mw.rcfilters.dm.FilterGroup} groupModel Filter group model
-        * @param {Object} config Configuration object
-        * @cfg {string[]} [excludes=[]] A list of filter names this filter, if
-        *  selected, makes inactive.
-        * @cfg {string[]} [subset] Defining the names of filters that are a subset of this filter
-        * @cfg {Object} [conflicts] Defines the conflicts for this filter
-        * @cfg {boolean} [visible=true] The visibility of the group
-        */
-       FilterItem = function MwRcfiltersDmFilterItem( param, groupModel, config ) {
-               config = config || {};
-
-               this.groupModel = groupModel;
-
-               // Parent
-               FilterItem.parent.call( this, param, $.extend( {
-                       namePrefix: this.groupModel.getNamePrefix()
-               }, config ) );
-               // Mixin constructor
-               OO.EventEmitter.call( this );
-
-               // Interaction definitions
-               this.subset = config.subset || [];
-               this.conflicts = config.conflicts || {};
-               this.superset = [];
-               this.visible = config.visible === undefined ? true : !!config.visible;
-
-               // Interaction states
-               this.included = false;
-               this.conflicted = false;
-               this.fullyCovered = false;
+var ItemModel = require( './ItemModel.js' ),
+       FilterItem;
+
+/**
+ * Filter item model
+ *
+ * @class mw.rcfilters.dm.FilterItem
+ * @extends mw.rcfilters.dm.ItemModel
+ *
+ * @constructor
+ * @param {string} param Filter param name
+ * @param {mw.rcfilters.dm.FilterGroup} groupModel Filter group model
+ * @param {Object} config Configuration object
+ * @cfg {string[]} [excludes=[]] A list of filter names this filter, if
+ *  selected, makes inactive.
+ * @cfg {string[]} [subset] Defining the names of filters that are a subset of this filter
+ * @cfg {Object} [conflicts] Defines the conflicts for this filter
+ * @cfg {boolean} [visible=true] The visibility of the group
+ */
+FilterItem = function MwRcfiltersDmFilterItem( param, groupModel, config ) {
+       config = config || {};
+
+       this.groupModel = groupModel;
+
+       // Parent
+       FilterItem.parent.call( this, param, $.extend( {
+               namePrefix: this.groupModel.getNamePrefix()
+       }, config ) );
+       // Mixin constructor
+       OO.EventEmitter.call( this );
+
+       // Interaction definitions
+       this.subset = config.subset || [];
+       this.conflicts = config.conflicts || {};
+       this.superset = [];
+       this.visible = config.visible === undefined ? true : !!config.visible;
+
+       // Interaction states
+       this.included = false;
+       this.conflicted = false;
+       this.fullyCovered = false;
+};
+
+/* Initialization */
+
+OO.inheritClass( FilterItem, ItemModel );
+
+/* Methods */
+
+/**
+ * Return the representation of the state of this item.
+ *
+ * @return {Object} State of the object
+ */
+FilterItem.prototype.getState = function () {
+       return {
+               selected: this.isSelected(),
+               included: this.isIncluded(),
+               conflicted: this.isConflicted(),
+               fullyCovered: this.isFullyCovered()
        };
-
-       /* Initialization */
-
-       OO.inheritClass( FilterItem, ItemModel );
-
-       /* Methods */
-
-       /**
-        * Return the representation of the state of this item.
-        *
-        * @return {Object} State of the object
-        */
-       FilterItem.prototype.getState = function () {
-               return {
-                       selected: this.isSelected(),
-                       included: this.isIncluded(),
-                       conflicted: this.isConflicted(),
-                       fullyCovered: this.isFullyCovered()
-               };
-       };
-
-       /**
-        * Get the message for the display area for the currently active conflict
-        *
-        * @private
-        * @return {string} Conflict result message key
-        */
-       FilterItem.prototype.getCurrentConflictResultMessage = function () {
-               var details = {};
-
-               // First look in filter's own conflicts
-               details = this.getConflictDetails( this.getOwnConflicts(), 'globalDescription' );
-               if ( !details.message ) {
-                       // Fall back onto conflicts in the group
-                       details = this.getConflictDetails( this.getGroupModel().getConflicts(), 'globalDescription' );
-               }
-
-               return details.message;
-       };
-
-       /**
-        * Get the details of the active conflict on this filter
-        *
-        * @private
-        * @param {Object} conflicts Conflicts to examine
-        * @param {string} [key='contextDescription'] Message key
-        * @return {Object} Object with conflict message and conflict items
-        * @return {string} return.message Conflict message
-        * @return {string[]} return.names Conflicting item labels
-        */
-       FilterItem.prototype.getConflictDetails = function ( conflicts, key ) {
-               var group,
-                       conflictMessage = '',
-                       itemLabels = [];
-
-               key = key || 'contextDescription';
-
-               // eslint-disable-next-line no-jquery/no-each-util
-               $.each( conflicts, function ( filterName, conflict ) {
-                       if ( !conflict.item.isSelected() ) {
-                               return;
-                       }
-
-                       if ( !conflictMessage ) {
-                               conflictMessage = conflict[ key ];
-                               group = conflict.group;
-                       }
-
-                       if ( group === conflict.group ) {
-                               itemLabels.push( mw.msg( 'quotation-marks', conflict.item.getLabel() ) );
-                       }
-               } );
-
-               return {
-                       message: conflictMessage,
-                       names: itemLabels
-               };
-
-       };
-
-       /**
-        * @inheritdoc
-        */
-       FilterItem.prototype.getStateMessage = function () {
-               var messageKey, details, superset,
-                       affectingItems = [];
-
-               if ( this.isSelected() ) {
-                       if ( this.isConflicted() ) {
-                               // First look in filter's own conflicts
-                               details = this.getConflictDetails( this.getOwnConflicts() );
-                               if ( !details.message ) {
-                                       // Fall back onto conflicts in the group
-                                       details = this.getConflictDetails( this.getGroupModel().getConflicts() );
-                               }
-
-                               messageKey = details.message;
-                               affectingItems = details.names;
-                       } else if ( this.isIncluded() && !this.isHighlighted() ) {
-                               // We only show the 'no effect' full-coverage message
-                               // if the item is also not highlighted. See T161273
-                               superset = this.getSuperset();
-                               // For this message we need to collect the affecting superset
-                               affectingItems = this.getGroupModel().findSelectedItems( this )
-                                       .filter( function ( item ) {
-                                               return superset.indexOf( item.getName() ) !== -1;
-                                       } )
-                                       .map( function ( item ) {
-                                               return mw.msg( 'quotation-marks', item.getLabel() );
-                                       } );
-
-                               messageKey = 'rcfilters-state-message-subset';
-                       } else if ( this.isFullyCovered() && !this.isHighlighted() ) {
-                               affectingItems = this.getGroupModel().findSelectedItems( this )
-                                       .map( function ( item ) {
-                                               return mw.msg( 'quotation-marks', item.getLabel() );
-                                       } );
-
-                               messageKey = 'rcfilters-state-message-fullcoverage';
-                       }
+};
+
+/**
+ * Get the message for the display area for the currently active conflict
+ *
+ * @return {string} Conflict result message key
+ */
+FilterItem.prototype.getCurrentConflictResultMessage = function () {
+       var details;
+
+       // First look in filter's own conflicts
+       details = this.getConflictDetails( this.getOwnConflicts(), 'globalDescription' );
+       if ( !details.message ) {
+               // Fall back onto conflicts in the group
+               details = this.getConflictDetails( this.getGroupModel().getConflicts(), 'globalDescription' );
+       }
+
+       return details.message;
+};
+
+/**
+ * Get the details of the active conflict on this filter
+ *
+ * @private
+ * @param {Object} conflicts Conflicts to examine
+ * @param {string} [key='contextDescription'] Message key
+ * @return {Object} Object with conflict message and conflict items
+ * @return {string} return.message Conflict message
+ * @return {string[]} return.names Conflicting item labels
+ */
+FilterItem.prototype.getConflictDetails = function ( conflicts, key ) {
+       var group,
+               conflictMessage = '',
+               itemLabels = [];
+
+       key = key || 'contextDescription';
+
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( conflicts, function ( filterName, conflict ) {
+               if ( !conflict.item.isSelected() ) {
+                       return;
                }
 
-               if ( messageKey ) {
-                       // Build message
-                       return mw.msg(
-                               messageKey,
-                               mw.language.listToText( affectingItems ),
-                               affectingItems.length
-                       );
+               if ( !conflictMessage ) {
+                       conflictMessage = conflict[ key ];
+                       group = conflict.group;
                }
 
-               // Display description
-               return this.getDescription();
-       };
-
-       /**
-        * Get the model of the group this filter belongs to
-        *
-        * @return {mw.rcfilters.dm.FilterGroup} Filter group model
-        */
-       FilterItem.prototype.getGroupModel = function () {
-               return this.groupModel;
-       };
-
-       /**
-        * Get the group name this filter belongs to
-        *
-        * @return {string} Filter group name
-        */
-       FilterItem.prototype.getGroupName = function () {
-               return this.groupModel.getName();
-       };
-
-       /**
-        * Get filter subset
-        * This is a list of filter names that are defined to be included
-        * when this filter is selected.
-        *
-        * @return {string[]} Filter subset
-        */
-       FilterItem.prototype.getSubset = function () {
-               return this.subset;
-       };
-
-       /**
-        * Get filter superset
-        * This is a generated list of filters that define this filter
-        * to be included when either of them is selected.
-        *
-        * @return {string[]} Filter superset
-        */
-       FilterItem.prototype.getSuperset = function () {
-               return this.superset;
-       };
-
-       /**
-        * Check whether the filter is currently in a conflict state
-        *
-        * @return {boolean} Filter is in conflict state
-        */
-       FilterItem.prototype.isConflicted = function () {
-               return this.conflicted;
-       };
-
-       /**
-        * Check whether the filter is currently in an already included subset
-        *
-        * @return {boolean} Filter is in an already-included subset
-        */
-       FilterItem.prototype.isIncluded = function () {
-               return this.included;
-       };
-
-       /**
-        * Check whether the filter is currently fully covered
-        *
-        * @return {boolean} Filter is in fully-covered state
-        */
-       FilterItem.prototype.isFullyCovered = function () {
-               return this.fullyCovered;
-       };
-
-       /**
-        * Get all conflicts associated with this filter or its group
-        *
-        * Conflict object is set up by filter name keys and conflict
-        * definition. For example:
-        *
-        *  {
-        *      filterName: {
-        *          filter: filterName,
-        *          group: group1,
-        *          label: itemLabel,
-        *          item: itemModel
-        *      }
-        *      filterName2: {
-        *          filter: filterName2,
-        *          group: group2
-        *          label: itemLabel2,
-        *          item: itemModel2
-        *      }
-        *  }
-        *
-        * @return {Object} Filter conflicts
-        */
-       FilterItem.prototype.getConflicts = function () {
-               return $.extend( {}, this.conflicts, this.getGroupModel().getConflicts() );
-       };
-
-       /**
-        * Get the conflicts associated with this filter
-        *
-        * @return {Object} Filter conflicts
-        */
-       FilterItem.prototype.getOwnConflicts = function () {
-               return this.conflicts;
-       };
-
-       /**
-        * Set conflicts for this filter. See #getConflicts for the expected
-        * structure of the definition.
-        *
-        * @param {Object} conflicts Conflicts for this filter
-        */
-       FilterItem.prototype.setConflicts = function ( conflicts ) {
-               this.conflicts = conflicts || {};
-       };
-
-       /**
-        * Set filter superset
-        *
-        * @param {string[]} superset Filter superset
-        */
-       FilterItem.prototype.setSuperset = function ( superset ) {
-               this.superset = superset || [];
-       };
-
-       /**
-        * Set filter subset
-        *
-        * @param {string[]} subset Filter subset
-        */
-       FilterItem.prototype.setSubset = function ( subset ) {
-               this.subset = subset || [];
-       };
-
-       /**
-        * Check whether a filter exists in the subset list for this filter
-        *
-        * @param {string} filterName Filter name
-        * @return {boolean} Filter name is in the subset list
-        */
-       FilterItem.prototype.existsInSubset = function ( filterName ) {
-               return this.subset.indexOf( filterName ) > -1;
-       };
-
-       /**
-        * Check whether this item has a potential conflict with the given item
-        *
-        * This checks whether the given item is in the list of conflicts of
-        * the current item, but makes no judgment about whether the conflict
-        * is currently at play (either one of the items may not be selected)
-        *
-        * @param {mw.rcfilters.dm.FilterItem} filterItem Filter item
-        * @return {boolean} This item has a conflict with the given item
-        */
-       FilterItem.prototype.existsInConflicts = function ( filterItem ) {
-               return Object.prototype.hasOwnProperty.call( this.getConflicts(), filterItem.getName() );
-       };
-
-       /**
-        * Set the state of this filter as being conflicted
-        * (This means any filters in its conflicts are selected)
-        *
-        * @param {boolean} [conflicted] Filter is in conflict state
-        * @fires update
-        */
-       FilterItem.prototype.toggleConflicted = function ( conflicted ) {
-               conflicted = conflicted === undefined ? !this.conflicted : conflicted;
-
-               if ( this.conflicted !== conflicted ) {
-                       this.conflicted = conflicted;
-                       this.emit( 'update' );
+               if ( group === conflict.group ) {
+                       itemLabels.push( mw.msg( 'quotation-marks', conflict.item.getLabel() ) );
                }
-       };
+       } );
 
-       /**
-        * Set the state of this filter as being already included
-        * (This means any filters in its superset are selected)
-        *
-        * @param {boolean} [included] Filter is included as part of a subset
-        * @fires update
-        */
-       FilterItem.prototype.toggleIncluded = function ( included ) {
-               included = included === undefined ? !this.included : included;
-
-               if ( this.included !== included ) {
-                       this.included = included;
-                       this.emit( 'update' );
-               }
+       return {
+               message: conflictMessage,
+               names: itemLabels
        };
 
-       /**
-        * Toggle the fully covered state of the item
-        *
-        * @param {boolean} [isFullyCovered] Filter is fully covered
-        * @fires update
-        */
-       FilterItem.prototype.toggleFullyCovered = function ( isFullyCovered ) {
-               isFullyCovered = isFullyCovered === undefined ? !this.fullycovered : isFullyCovered;
-
-               if ( this.fullyCovered !== isFullyCovered ) {
-                       this.fullyCovered = isFullyCovered;
-                       this.emit( 'update' );
-               }
-       };
+};
+
+/**
+ * @inheritdoc
+ */
+FilterItem.prototype.getStateMessage = function () {
+       var messageKey, details, superset,
+               affectingItems = [];
+
+       if ( this.isSelected() ) {
+               if ( this.isConflicted() ) {
+                       // First look in filter's own conflicts
+                       details = this.getConflictDetails( this.getOwnConflicts() );
+                       if ( !details.message ) {
+                               // Fall back onto conflicts in the group
+                               details = this.getConflictDetails( this.getGroupModel().getConflicts() );
+                       }
 
-       /**
-        * Toggle the visibility of this item
-        *
-        * @param {boolean} [isVisible] Item is visible
-        */
-       FilterItem.prototype.toggleVisible = function ( isVisible ) {
-               isVisible = isVisible === undefined ? !this.visible : !!isVisible;
-
-               if ( this.visible !== isVisible ) {
-                       this.visible = isVisible;
-                       this.emit( 'update' );
+                       messageKey = details.message;
+                       affectingItems = details.names;
+               } else if ( this.isIncluded() && !this.isHighlighted() ) {
+                       // We only show the 'no effect' full-coverage message
+                       // if the item is also not highlighted. See T161273
+                       superset = this.getSuperset();
+                       // For this message we need to collect the affecting superset
+                       affectingItems = this.getGroupModel().findSelectedItems( this )
+                               .filter( function ( item ) {
+                                       return superset.indexOf( item.getName() ) !== -1;
+                               } )
+                               .map( function ( item ) {
+                                       return mw.msg( 'quotation-marks', item.getLabel() );
+                               } );
+
+                       messageKey = 'rcfilters-state-message-subset';
+               } else if ( this.isFullyCovered() && !this.isHighlighted() ) {
+                       affectingItems = this.getGroupModel().findSelectedItems( this )
+                               .map( function ( item ) {
+                                       return mw.msg( 'quotation-marks', item.getLabel() );
+                               } );
+
+                       messageKey = 'rcfilters-state-message-fullcoverage';
                }
-       };
-
-       /**
-        * Check whether the item is visible
-        *
-        * @return {boolean} Item is visible
-        */
-       FilterItem.prototype.isVisible = function () {
-               return this.visible;
-       };
-
-       module.exports = FilterItem;
-
-}() );
+       }
+
+       if ( messageKey ) {
+               // Build message
+               return mw.msg(
+                       messageKey,
+                       mw.language.listToText( affectingItems ),
+                       affectingItems.length
+               );
+       }
+
+       // Display description
+       return this.getDescription();
+};
+
+/**
+ * Get the model of the group this filter belongs to
+ *
+ * @return {mw.rcfilters.dm.FilterGroup} Filter group model
+ */
+FilterItem.prototype.getGroupModel = function () {
+       return this.groupModel;
+};
+
+/**
+ * Get the group name this filter belongs to
+ *
+ * @return {string} Filter group name
+ */
+FilterItem.prototype.getGroupName = function () {
+       return this.groupModel.getName();
+};
+
+/**
+ * Get filter subset
+ * This is a list of filter names that are defined to be included
+ * when this filter is selected.
+ *
+ * @return {string[]} Filter subset
+ */
+FilterItem.prototype.getSubset = function () {
+       return this.subset;
+};
+
+/**
+ * Get filter superset
+ * This is a generated list of filters that define this filter
+ * to be included when either of them is selected.
+ *
+ * @return {string[]} Filter superset
+ */
+FilterItem.prototype.getSuperset = function () {
+       return this.superset;
+};
+
+/**
+ * Check whether the filter is currently in a conflict state
+ *
+ * @return {boolean} Filter is in conflict state
+ */
+FilterItem.prototype.isConflicted = function () {
+       return this.conflicted;
+};
+
+/**
+ * Check whether the filter is currently in an already included subset
+ *
+ * @return {boolean} Filter is in an already-included subset
+ */
+FilterItem.prototype.isIncluded = function () {
+       return this.included;
+};
+
+/**
+ * Check whether the filter is currently fully covered
+ *
+ * @return {boolean} Filter is in fully-covered state
+ */
+FilterItem.prototype.isFullyCovered = function () {
+       return this.fullyCovered;
+};
+
+/**
+ * Get all conflicts associated with this filter or its group
+ *
+ * Conflict object is set up by filter name keys and conflict
+ * definition. For example:
+ *
+ *  {
+ *      filterName: {
+ *          filter: filterName,
+ *          group: group1,
+ *          label: itemLabel,
+ *          item: itemModel
+ *      }
+ *      filterName2: {
+ *          filter: filterName2,
+ *          group: group2
+ *          label: itemLabel2,
+ *          item: itemModel2
+ *      }
+ *  }
+ *
+ * @return {Object} Filter conflicts
+ */
+FilterItem.prototype.getConflicts = function () {
+       return $.extend( {}, this.conflicts, this.getGroupModel().getConflicts() );
+};
+
+/**
+ * Get the conflicts associated with this filter
+ *
+ * @return {Object} Filter conflicts
+ */
+FilterItem.prototype.getOwnConflicts = function () {
+       return this.conflicts;
+};
+
+/**
+ * Set conflicts for this filter. See #getConflicts for the expected
+ * structure of the definition.
+ *
+ * @param {Object} conflicts Conflicts for this filter
+ */
+FilterItem.prototype.setConflicts = function ( conflicts ) {
+       this.conflicts = conflicts || {};
+};
+
+/**
+ * Set filter superset
+ *
+ * @param {string[]} superset Filter superset
+ */
+FilterItem.prototype.setSuperset = function ( superset ) {
+       this.superset = superset || [];
+};
+
+/**
+ * Set filter subset
+ *
+ * @param {string[]} subset Filter subset
+ */
+FilterItem.prototype.setSubset = function ( subset ) {
+       this.subset = subset || [];
+};
+
+/**
+ * Check whether a filter exists in the subset list for this filter
+ *
+ * @param {string} filterName Filter name
+ * @return {boolean} Filter name is in the subset list
+ */
+FilterItem.prototype.existsInSubset = function ( filterName ) {
+       return this.subset.indexOf( filterName ) > -1;
+};
+
+/**
+ * Check whether this item has a potential conflict with the given item
+ *
+ * This checks whether the given item is in the list of conflicts of
+ * the current item, but makes no judgment about whether the conflict
+ * is currently at play (either one of the items may not be selected)
+ *
+ * @param {mw.rcfilters.dm.FilterItem} filterItem Filter item
+ * @return {boolean} This item has a conflict with the given item
+ */
+FilterItem.prototype.existsInConflicts = function ( filterItem ) {
+       return Object.prototype.hasOwnProperty.call( this.getConflicts(), filterItem.getName() );
+};
+
+/**
+ * Set the state of this filter as being conflicted
+ * (This means any filters in its conflicts are selected)
+ *
+ * @param {boolean} [conflicted] Filter is in conflict state
+ * @fires update
+ */
+FilterItem.prototype.toggleConflicted = function ( conflicted ) {
+       conflicted = conflicted === undefined ? !this.conflicted : conflicted;
+
+       if ( this.conflicted !== conflicted ) {
+               this.conflicted = conflicted;
+               this.emit( 'update' );
+       }
+};
+
+/**
+ * Set the state of this filter as being already included
+ * (This means any filters in its superset are selected)
+ *
+ * @param {boolean} [included] Filter is included as part of a subset
+ * @fires update
+ */
+FilterItem.prototype.toggleIncluded = function ( included ) {
+       included = included === undefined ? !this.included : included;
+
+       if ( this.included !== included ) {
+               this.included = included;
+               this.emit( 'update' );
+       }
+};
+
+/**
+ * Toggle the fully covered state of the item
+ *
+ * @param {boolean} [isFullyCovered] Filter is fully covered
+ * @fires update
+ */
+FilterItem.prototype.toggleFullyCovered = function ( isFullyCovered ) {
+       isFullyCovered = isFullyCovered === undefined ? !this.fullycovered : isFullyCovered;
+
+       if ( this.fullyCovered !== isFullyCovered ) {
+               this.fullyCovered = isFullyCovered;
+               this.emit( 'update' );
+       }
+};
+
+/**
+ * Toggle the visibility of this item
+ *
+ * @param {boolean} [isVisible] Item is visible
+ */
+FilterItem.prototype.toggleVisible = function ( isVisible ) {
+       isVisible = isVisible === undefined ? !this.visible : !!isVisible;
+
+       if ( this.visible !== isVisible ) {
+               this.visible = isVisible;
+               this.emit( 'update' );
+       }
+};
+
+/**
+ * Check whether the item is visible
+ *
+ * @return {boolean} Item is visible
+ */
+FilterItem.prototype.isVisible = function () {
+       return this.visible;
+};
+
+module.exports = FilterItem;
index d1b9f7a..4b219de 100644 (file)
-( function () {
-       var FilterGroup = require( './FilterGroup.js' ),
-               FilterItem = require( './FilterItem.js' ),
-               FiltersViewModel;
-
-       /**
-        * View model for the filters selection and display
-        *
-        * @class mw.rcfilters.dm.FiltersViewModel
-        * @mixins OO.EventEmitter
-        * @mixins OO.EmitterList
-        *
-        * @constructor
-        */
-       FiltersViewModel = function MwRcfiltersDmFiltersViewModel() {
-               // Mixin constructor
-               OO.EventEmitter.call( this );
-               OO.EmitterList.call( this );
-
-               this.groups = {};
-               this.defaultParams = {};
-               this.highlightEnabled = false;
-               this.parameterMap = {};
-               this.emptyParameterState = null;
-
-               this.views = {};
-               this.currentView = 'default';
-               this.searchQuery = null;
-
-               // Events
-               this.aggregate( { update: 'filterItemUpdate' } );
-               this.connect( this, { filterItemUpdate: [ 'emit', 'itemUpdate' ] } );
-       };
-
-       /* Initialization */
-       OO.initClass( FiltersViewModel );
-       OO.mixinClass( FiltersViewModel, OO.EventEmitter );
-       OO.mixinClass( FiltersViewModel, OO.EmitterList );
-
-       /* Events */
-
-       /**
-        * @event initialize
-        *
-        * Filter list is initialized
-        */
-
-       /**
-        * @event update
-        *
-        * Model has been updated
-        */
-
-       /**
-        * @event itemUpdate
-        * @param {mw.rcfilters.dm.FilterItem} item Filter item updated
-        *
-        * Filter item has changed
-        */
-
-       /**
-        * @event highlightChange
-        * @param {boolean} Highlight feature is enabled
-        *
-        * Highlight feature has been toggled enabled or disabled
-        */
-
-       /* Methods */
-
-       /**
-        * Re-assess the states of filter items based on the interactions between them
-        *
-        * @param {mw.rcfilters.dm.FilterItem} [item] Changed item. If not given, the
-        *  method will go over the state of all items
-        */
-       FiltersViewModel.prototype.reassessFilterInteractions = function ( item ) {
-               var allSelected,
-                       model = this,
-                       iterationItems = item !== undefined ? [ item ] : this.getItems();
-
-               iterationItems.forEach( function ( checkedItem ) {
-                       var allCheckedItems = checkedItem.getSubset().concat( [ checkedItem.getName() ] ),
-                               groupModel = checkedItem.getGroupModel();
-
-                       // Check for subsets (included filters) plus the item itself:
-                       allCheckedItems.forEach( function ( filterItemName ) {
-                               var itemInSubset = model.getItemByName( filterItemName );
-
-                               itemInSubset.toggleIncluded(
-                                       // If any of itemInSubset's supersets are selected, this item
-                                       // is included
-                                       itemInSubset.getSuperset().some( function ( supersetName ) {
-                                               return ( model.getItemByName( supersetName ).isSelected() );
+var FilterGroup = require( './FilterGroup.js' ),
+       FilterItem = require( './FilterItem.js' ),
+       FiltersViewModel;
+
+/**
+ * View model for the filters selection and display
+ *
+ * @class mw.rcfilters.dm.FiltersViewModel
+ * @mixins OO.EventEmitter
+ * @mixins OO.EmitterList
+ *
+ * @constructor
+ */
+FiltersViewModel = function MwRcfiltersDmFiltersViewModel() {
+       // Mixin constructor
+       OO.EventEmitter.call( this );
+       OO.EmitterList.call( this );
+
+       this.groups = {};
+       this.defaultParams = {};
+       this.highlightEnabled = false;
+       this.parameterMap = {};
+       this.emptyParameterState = null;
+
+       this.views = {};
+       this.currentView = 'default';
+       this.searchQuery = null;
+
+       // Events
+       this.aggregate( { update: 'filterItemUpdate' } );
+       this.connect( this, { filterItemUpdate: [ 'emit', 'itemUpdate' ] } );
+};
+
+/* Initialization */
+OO.initClass( FiltersViewModel );
+OO.mixinClass( FiltersViewModel, OO.EventEmitter );
+OO.mixinClass( FiltersViewModel, OO.EmitterList );
+
+/* Events */
+
+/**
+ * @event initialize
+ *
+ * Filter list is initialized
+ */
+
+/**
+ * @event update
+ *
+ * Model has been updated
+ */
+
+/**
+ * @event itemUpdate
+ * @param {mw.rcfilters.dm.FilterItem} item Filter item updated
+ *
+ * Filter item has changed
+ */
+
+/**
+ * @event highlightChange
+ * @param {boolean} Highlight feature is enabled
+ *
+ * Highlight feature has been toggled enabled or disabled
+ */
+
+/* Methods */
+
+/**
+ * Re-assess the states of filter items based on the interactions between them
+ *
+ * @param {mw.rcfilters.dm.FilterItem} [item] Changed item. If not given, the
+ *  method will go over the state of all items
+ */
+FiltersViewModel.prototype.reassessFilterInteractions = function ( item ) {
+       var allSelected,
+               model = this,
+               iterationItems = item !== undefined ? [ item ] : this.getItems();
+
+       iterationItems.forEach( function ( checkedItem ) {
+               var allCheckedItems = checkedItem.getSubset().concat( [ checkedItem.getName() ] ),
+                       groupModel = checkedItem.getGroupModel();
+
+               // Check for subsets (included filters) plus the item itself:
+               allCheckedItems.forEach( function ( filterItemName ) {
+                       var itemInSubset = model.getItemByName( filterItemName );
+
+                       itemInSubset.toggleIncluded(
+                               // If any of itemInSubset's supersets are selected, this item
+                               // is included
+                               itemInSubset.getSuperset().some( function ( supersetName ) {
+                                       return ( model.getItemByName( supersetName ).isSelected() );
+                               } )
+                       );
+               } );
+
+               // Update coverage for the changed group
+               if ( groupModel.isFullCoverage() ) {
+                       allSelected = groupModel.areAllSelected();
+                       groupModel.getItems().forEach( function ( filterItem ) {
+                               filterItem.toggleFullyCovered( allSelected );
+                       } );
+               }
+       } );
+
+       // Check for conflicts
+       // In this case, we must go over all items, since
+       // conflicts are bidirectional and depend not only on
+       // individual items, but also on the selected states of
+       // the groups they're in.
+       this.getItems().forEach( function ( filterItem ) {
+               var inConflict = false,
+                       filterItemGroup = filterItem.getGroupModel();
+
+               // For each item, see if that item is still conflicting
+               // eslint-disable-next-line no-jquery/no-each-util
+               $.each( model.groups, function ( groupName, groupModel ) {
+                       if ( filterItem.getGroupName() === groupName ) {
+                               // Check inside the group
+                               inConflict = groupModel.areAnySelectedInConflictWith( filterItem );
+                       } else {
+                               // According to the spec, if two items conflict from two different
+                               // groups, the conflict only lasts if the groups **only have selected
+                               // items that are conflicting**. If a group has selected items that
+                               // are conflicting and non-conflicting, the scope of the result has
+                               // expanded enough to completely remove the conflict.
+
+                               // For example, see two groups with conflicts:
+                               // userExpLevel: [
+                               //   {
+                               //     name: 'experienced',
+                               //     conflicts: [ 'unregistered' ]
+                               //   }
+                               // ],
+                               // registration: [
+                               //   {
+                               //     name: 'registered',
+                               //   },
+                               //   {
+                               //     name: 'unregistered',
+                               //   }
+                               // ]
+                               // If we select 'experienced', then 'unregistered' is in conflict (and vice versa),
+                               // because, inherently, 'experienced' filter only includes registered users, and so
+                               // both filters are in conflict with one another.
+                               // However, the minute we select 'registered', the scope of our results
+                               // has expanded to no longer have a conflict with 'experienced' filter, and
+                               // so the conflict is removed.
+
+                               // In our case, we need to check if the entire group conflicts with
+                               // the entire item's group, so we follow the above spec
+                               inConflict = (
+                                       // The foreign group is in conflict with this item
+                                       groupModel.areAllSelectedInConflictWith( filterItem ) &&
+                                       // Every selected member of the item's own group is also
+                                       // in conflict with the other group
+                                       filterItemGroup.findSelectedItems().every( function ( otherGroupItem ) {
+                                               return groupModel.areAllSelectedInConflictWith( otherGroupItem );
                                        } )
                                );
-                       } );
-
-                       // Update coverage for the changed group
-                       if ( groupModel.isFullCoverage() ) {
-                               allSelected = groupModel.areAllSelected();
-                               groupModel.getItems().forEach( function ( filterItem ) {
-                                       filterItem.toggleFullyCovered( allSelected );
-                               } );
                        }
+
+                       // If we're in conflict, this will return 'false' which
+                       // will break the loop. Otherwise, we're not in conflict
+                       // and the loop continues
+                       return !inConflict;
                } );
 
-               // Check for conflicts
-               // In this case, we must go over all items, since
-               // conflicts are bidirectional and depend not only on
-               // individual items, but also on the selected states of
-               // the groups they're in.
-               this.getItems().forEach( function ( filterItem ) {
-                       var inConflict = false,
-                               filterItemGroup = filterItem.getGroupModel();
+               // Toggle the item state
+               filterItem.toggleConflicted( inConflict );
+       } );
+};
+
+/**
+ * Get whether the model has any conflict in its items
+ *
+ * @return {boolean} There is a conflict
+ */
+FiltersViewModel.prototype.hasConflict = function () {
+       return this.getItems().some( function ( filterItem ) {
+               return filterItem.isSelected() && filterItem.isConflicted();
+       } );
+};
+
+/**
+ * Get the first item with a current conflict
+ *
+ * @return {mw.rcfilters.dm.FilterItem|undefined} Conflicted item or undefined when not found
+ */
+FiltersViewModel.prototype.getFirstConflictedItem = function () {
+       var i, filterItem, items = this.getItems();
+       for ( i = 0; i < items.length; i++ ) {
+               filterItem = items[ i ];
+               if ( filterItem.isSelected() && filterItem.isConflicted() ) {
+                       return filterItem;
+               }
+       }
+};
+
+/**
+ * Set filters and preserve a group relationship based on
+ * the definition given by an object
+ *
+ * @param {Array} filterGroups Filters definition
+ * @param {Object} [views] Extra views definition
+ *  Expected in the following format:
+ *  {
+ *     namespaces: {
+ *       label: 'namespaces', // Message key
+ *       trigger: ':',
+ *       groups: [
+ *         {
+ *            // Group info
+ *            name: 'namespaces' // Parameter name
+ *            title: 'namespaces' // Message key
+ *            type: 'string_options',
+ *            separator: ';',
+ *            labelPrefixKey: { 'default': 'rcfilters-tag-prefix-namespace', inverted: 'rcfilters-tag-prefix-namespace-inverted' },
+ *            fullCoverage: true
+ *            items: []
+ *         }
+ *       ]
+ *     }
+ *  }
+ */
+FiltersViewModel.prototype.initializeFilters = function ( filterGroups, views ) {
+       var filterConflictResult, groupConflictResult,
+               allViews,
+               model = this,
+               items = [],
+               groupConflictMap = {},
+               filterConflictMap = {},
+               /*!
+                * Expand a conflict definition from group name to
+                * the list of all included filters in that group.
+                * We do this so that the direct relationship in the
+                * models are consistently item->items rather than
+                * mixing item->group with item->item.
+                *
+                * @param {Object} obj Conflict definition
+                * @return {Object} Expanded conflict definition
+                */
+               expandConflictDefinitions = function ( obj ) {
+                       var result = {};
 
-                       // For each item, see if that item is still conflicting
                        // eslint-disable-next-line no-jquery/no-each-util
-                       $.each( model.groups, function ( groupName, groupModel ) {
-                               if ( filterItem.getGroupName() === groupName ) {
-                                       // Check inside the group
-                                       inConflict = groupModel.areAnySelectedInConflictWith( filterItem );
-                               } else {
-                                       // According to the spec, if two items conflict from two different
-                                       // groups, the conflict only lasts if the groups **only have selected
-                                       // items that are conflicting**. If a group has selected items that
-                                       // are conflicting and non-conflicting, the scope of the result has
-                                       // expanded enough to completely remove the conflict.
-
-                                       // For example, see two groups with conflicts:
-                                       // userExpLevel: [
-                                       //   {
-                                       //     name: 'experienced',
-                                       //     conflicts: [ 'unregistered' ]
-                                       //   }
-                                       // ],
-                                       // registration: [
-                                       //   {
-                                       //     name: 'registered',
-                                       //   },
-                                       //   {
-                                       //     name: 'unregistered',
-                                       //   }
-                                       // ]
-                                       // If we select 'experienced', then 'unregistered' is in conflict (and vice versa),
-                                       // because, inherently, 'experienced' filter only includes registered users, and so
-                                       // both filters are in conflict with one another.
-                                       // However, the minute we select 'registered', the scope of our results
-                                       // has expanded to no longer have a conflict with 'experienced' filter, and
-                                       // so the conflict is removed.
-
-                                       // In our case, we need to check if the entire group conflicts with
-                                       // the entire item's group, so we follow the above spec
-                                       inConflict = (
-                                               // The foreign group is in conflict with this item
-                                               groupModel.areAllSelectedInConflictWith( filterItem ) &&
-                                               // Every selected member of the item's own group is also
-                                               // in conflict with the other group
-                                               filterItemGroup.findSelectedItems().every( function ( otherGroupItem ) {
-                                                       return groupModel.areAllSelectedInConflictWith( otherGroupItem );
-                                               } )
-                                       );
-                               }
-
-                               // If we're in conflict, this will return 'false' which
-                               // will break the loop. Otherwise, we're not in conflict
-                               // and the loop continues
-                               return !inConflict;
-                       } );
-
-                       // Toggle the item state
-                       filterItem.toggleConflicted( inConflict );
-               } );
-       };
-
-       /**
-        * Get whether the model has any conflict in its items
-        *
-        * @return {boolean} There is a conflict
-        */
-       FiltersViewModel.prototype.hasConflict = function () {
-               return this.getItems().some( function ( filterItem ) {
-                       return filterItem.isSelected() && filterItem.isConflicted();
-               } );
-       };
-
-       /**
-        * Get the first item with a current conflict
-        *
-        * @return {mw.rcfilters.dm.FilterItem|undefined} Conflicted item or undefined when not found
-        */
-       FiltersViewModel.prototype.getFirstConflictedItem = function () {
-               var i, filterItem, items = this.getItems();
-               for ( i = 0; i < items.length; i++ ) {
-                       filterItem = items[ i ];
-                       if ( filterItem.isSelected() && filterItem.isConflicted() ) {
-                               return filterItem;
-                       }
-               }
-       };
-
-       /**
-        * Set filters and preserve a group relationship based on
-        * the definition given by an object
-        *
-        * @param {Array} filterGroups Filters definition
-        * @param {Object} [views] Extra views definition
-        *  Expected in the following format:
-        *  {
-        *     namespaces: {
-        *       label: 'namespaces', // Message key
-        *       trigger: ':',
-        *       groups: [
-        *         {
-        *            // Group info
-        *            name: 'namespaces' // Parameter name
-        *            title: 'namespaces' // Message key
-        *            type: 'string_options',
-        *            separator: ';',
-        *            labelPrefixKey: { 'default': 'rcfilters-tag-prefix-namespace', inverted: 'rcfilters-tag-prefix-namespace-inverted' },
-        *            fullCoverage: true
-        *            items: []
-        *         }
-        *       ]
-        *     }
-        *  }
-        */
-       FiltersViewModel.prototype.initializeFilters = function ( filterGroups, views ) {
-               var filterConflictResult, groupConflictResult,
-                       allViews = {},
-                       model = this,
-                       items = [],
-                       groupConflictMap = {},
-                       filterConflictMap = {},
-                       /*!
-                        * Expand a conflict definition from group name to
-                        * the list of all included filters in that group.
-                        * We do this so that the direct relationship in the
-                        * models are consistently item->items rather than
-                        * mixing item->group with item->item.
-                        *
-                        * @param {Object} obj Conflict definition
-                        * @return {Object} Expanded conflict definition
-                        */
-                       expandConflictDefinitions = function ( obj ) {
-                               var result = {};
-
-                               // eslint-disable-next-line no-jquery/no-each-util
-                               $.each( obj, function ( key, conflicts ) {
-                                       var filterName,
-                                               adjustedConflicts = {};
-
-                                       conflicts.forEach( function ( conflict ) {
-                                               var filter;
-
-                                               if ( conflict.filter ) {
-                                                       filterName = model.groups[ conflict.group ].getPrefixedName( conflict.filter );
-                                                       filter = model.getItemByName( filterName );
-
-                                                       // Rename
-                                                       adjustedConflicts[ filterName ] = $.extend(
+                       $.each( obj, function ( key, conflicts ) {
+                               var filterName,
+                                       adjustedConflicts = {};
+
+                               conflicts.forEach( function ( conflict ) {
+                                       var filter;
+
+                                       if ( conflict.filter ) {
+                                               filterName = model.groups[ conflict.group ].getPrefixedName( conflict.filter );
+                                               filter = model.getItemByName( filterName );
+
+                                               // Rename
+                                               adjustedConflicts[ filterName ] = $.extend(
+                                                       {},
+                                                       conflict,
+                                                       {
+                                                               filter: filterName,
+                                                               item: filter
+                                                       }
+                                               );
+                                       } else {
+                                               // This conflict is for an entire group. Split it up to
+                                               // represent each filter
+
+                                               // Get the relevant group items
+                                               model.groups[ conflict.group ].getItems().forEach( function ( groupItem ) {
+                                                       // Rebuild the conflict
+                                                       adjustedConflicts[ groupItem.getName() ] = $.extend(
                                                                {},
                                                                conflict,
                                                                {
-                                                                       filter: filterName,
-                                                                       item: filter
+                                                                       filter: groupItem.getName(),
+                                                                       item: groupItem
                                                                }
                                                        );
-                                               } else {
-                                                       // This conflict is for an entire group. Split it up to
-                                                       // represent each filter
-
-                                                       // Get the relevant group items
-                                                       model.groups[ conflict.group ].getItems().forEach( function ( groupItem ) {
-                                                               // Rebuild the conflict
-                                                               adjustedConflicts[ groupItem.getName() ] = $.extend(
-                                                                       {},
-                                                                       conflict,
-                                                                       {
-                                                                               filter: groupItem.getName(),
-                                                                               item: groupItem
-                                                                       }
-                                                               );
-                                                       } );
-                                               }
-                                       } );
-
-                                       result[ key ] = adjustedConflicts;
-                               } );
-
-                               return result;
-                       };
-
-               // Reset
-               this.clearItems();
-               this.groups = {};
-               this.views = {};
-
-               // Clone
-               filterGroups = OO.copy( filterGroups );
-
-               // Normalize definition from the server
-               filterGroups.forEach( function ( data ) {
-                       var i;
-                       // What's this information needs to be normalized
-                       data.whatsThis = {
-                               body: data.whatsThisBody,
-                               header: data.whatsThisHeader,
-                               linkText: data.whatsThisLinkText,
-                               url: data.whatsThisUrl
-                       };
-
-                       // Title is a msg-key
-                       data.title = data.title ? mw.msg( data.title ) : data.name;
-
-                       // Filters are given to us with msg-keys, we need
-                       // to translate those before we hand them off
-                       for ( i = 0; i < data.filters.length; i++ ) {
-                               data.filters[ i ].label = data.filters[ i ].label ? mw.msg( data.filters[ i ].label ) : data.filters[ i ].name;
-                               data.filters[ i ].description = data.filters[ i ].description ? mw.msg( data.filters[ i ].description ) : '';
-                       }
-               } );
-
-               // Collect views
-               allViews = $.extend( true, {
-                       default: {
-                               title: mw.msg( 'rcfilters-filterlist-title' ),
-                               groups: filterGroups
-                       }
-               }, views );
-
-               // Go over all views
-               // eslint-disable-next-line no-jquery/no-each-util
-               $.each( allViews, function ( viewName, viewData ) {
-                       // Define the view
-                       model.views[ viewName ] = {
-                               name: viewData.name,
-                               title: viewData.title,
-                               trigger: viewData.trigger
-                       };
-
-                       // Go over groups
-                       viewData.groups.forEach( function ( groupData ) {
-                               var group = groupData.name;
-
-                               if ( !model.groups[ group ] ) {
-                                       model.groups[ group ] = new FilterGroup(
-                                               group,
-                                               $.extend( true, {}, groupData, { view: viewName } )
-                                       );
-                               }
-
-                               model.groups[ group ].initializeFilters( groupData.filters, groupData.default );
-                               items = items.concat( model.groups[ group ].getItems() );
-
-                               // Prepare conflicts
-                               if ( groupData.conflicts ) {
-                                       // Group conflicts
-                                       groupConflictMap[ group ] = groupData.conflicts;
-                               }
-
-                               groupData.filters.forEach( function ( itemData ) {
-                                       var filterItem = model.groups[ group ].getItemByParamName( itemData.name );
-                                       // Filter conflicts
-                                       if ( itemData.conflicts ) {
-                                               filterConflictMap[ filterItem.getName() ] = itemData.conflicts;
+                                               } );
                                        }
                                } );
-                       } );
-               } );
-
-               // Add item references to the model, for lookup
-               this.addItems( items );
 
-               // Expand conflicts
-               groupConflictResult = expandConflictDefinitions( groupConflictMap );
-               filterConflictResult = expandConflictDefinitions( filterConflictMap );
-
-               // Set conflicts for groups
-               // eslint-disable-next-line no-jquery/no-each-util
-               $.each( groupConflictResult, function ( group, conflicts ) {
-                       model.groups[ group ].setConflicts( conflicts );
-               } );
+                               result[ key ] = adjustedConflicts;
+                       } );
 
-               // Set conflicts for items
-               // eslint-disable-next-line no-jquery/no-each-util
-               $.each( filterConflictResult, function ( filterName, conflicts ) {
-                       var filterItem = model.getItemByName( filterName );
-                       // set conflicts for items in the group
-                       filterItem.setConflicts( conflicts );
-               } );
+                       return result;
+               };
+
+       // Reset
+       this.clearItems();
+       this.groups = {};
+       this.views = {};
+
+       // Clone
+       filterGroups = OO.copy( filterGroups );
+
+       // Normalize definition from the server
+       filterGroups.forEach( function ( data ) {
+               var i;
+               // What's this information needs to be normalized
+               data.whatsThis = {
+                       body: data.whatsThisBody,
+                       header: data.whatsThisHeader,
+                       linkText: data.whatsThisLinkText,
+                       url: data.whatsThisUrl
+               };
+
+               // Title is a msg-key
+               data.title = data.title ? mw.msg( data.title ) : data.name;
+
+               // Filters are given to us with msg-keys, we need
+               // to translate those before we hand them off
+               for ( i = 0; i < data.filters.length; i++ ) {
+                       data.filters[ i ].label = data.filters[ i ].label ? mw.msg( data.filters[ i ].label ) : data.filters[ i ].name;
+                       data.filters[ i ].description = data.filters[ i ].description ? mw.msg( data.filters[ i ].description ) : '';
+               }
+       } );
 
-               // Create a map between known parameters and their models
-               // eslint-disable-next-line no-jquery/no-each-util
-               $.each( this.groups, function ( group, groupModel ) {
-                       if (
-                               groupModel.getType() === 'send_unselected_if_any' ||
-                               groupModel.getType() === 'boolean' ||
-                               groupModel.getType() === 'any_value'
-                       ) {
-                               // Individual filters
-                               groupModel.getItems().forEach( function ( filterItem ) {
-                                       model.parameterMap[ filterItem.getParamName() ] = filterItem;
-                               } );
-                       } else if (
-                               groupModel.getType() === 'string_options' ||
-                               groupModel.getType() === 'single_option'
-                       ) {
-                               // Group
-                               model.parameterMap[ groupModel.getName() ] = groupModel;
+       // Collect views
+       allViews = $.extend( true, {
+               default: {
+                       title: mw.msg( 'rcfilters-filterlist-title' ),
+                       groups: filterGroups
+               }
+       }, views );
+
+       // Go over all views
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( allViews, function ( viewName, viewData ) {
+               // Define the view
+               model.views[ viewName ] = {
+                       name: viewData.name,
+                       title: viewData.title,
+                       trigger: viewData.trigger
+               };
+
+               // Go over groups
+               viewData.groups.forEach( function ( groupData ) {
+                       var group = groupData.name;
+
+                       if ( !model.groups[ group ] ) {
+                               model.groups[ group ] = new FilterGroup(
+                                       group,
+                                       $.extend( true, {}, groupData, { view: viewName } )
+                               );
                        }
-               } );
-
-               this.setSearch( '' );
-
-               this.updateHighlightedState();
 
-               // Finish initialization
-               this.emit( 'initialize' );
-       };
+                       model.groups[ group ].initializeFilters( groupData.filters, groupData.default );
+                       items = items.concat( model.groups[ group ].getItems() );
 
-       /**
-        * Update filter view model state based on a parameter object
-        *
-        * @param {Object} params Parameters object
-        */
-       FiltersViewModel.prototype.updateStateFromParams = function ( params ) {
-               var filtersValue;
-               // For arbitrary numeric single_option values make sure the values
-               // are normalized to fit within the limits
-               // eslint-disable-next-line no-jquery/no-each-util
-               $.each( this.getFilterGroups(), function ( groupName, groupModel ) {
-                       params[ groupName ] = groupModel.normalizeArbitraryValue( params[ groupName ] );
-               } );
-
-               // Update filter values
-               filtersValue = this.getFiltersFromParameters( params );
-               Object.keys( filtersValue ).forEach( function ( filterName ) {
-                       this.getItemByName( filterName ).setValue( filtersValue[ filterName ] );
-               }.bind( this ) );
-
-               // Update highlight state
-               this.getItemsSupportingHighlights().forEach( function ( filterItem ) {
-                       var color = params[ filterItem.getName() + '_color' ];
-                       if ( color ) {
-                               filterItem.setHighlightColor( color );
-                       } else {
-                               filterItem.clearHighlightColor();
+                       // Prepare conflicts
+                       if ( groupData.conflicts ) {
+                               // Group conflicts
+                               groupConflictMap[ group ] = groupData.conflicts;
                        }
-               } );
-               this.updateHighlightedState();
-
-               // Check all filter interactions
-               this.reassessFilterInteractions();
-       };
-
-       /**
-        * Get a representation of an empty (falsey) parameter state
-        *
-        * @return {Object} Empty parameter state
-        */
-       FiltersViewModel.prototype.getEmptyParameterState = function () {
-               if ( !this.emptyParameterState ) {
-                       this.emptyParameterState = $.extend(
-                               true,
-                               {},
-                               this.getParametersFromFilters( {} ),
-                               this.getEmptyHighlightParameters()
-                       );
-               }
-               return this.emptyParameterState;
-       };
-
-       /**
-        * Get a representation of only the non-falsey parameters
-        *
-        * @param {Object} [parameters] A given parameter state to minimize. If not given the current
-        *  state of the system will be used.
-        * @return {Object} Empty parameter state
-        */
-       FiltersViewModel.prototype.getMinimizedParamRepresentation = function ( parameters ) {
-               var result = {};
-
-               parameters = parameters ? $.extend( true, {}, parameters ) : this.getCurrentParameterState();
-
-               // Params
-               // eslint-disable-next-line no-jquery/no-each-util
-               $.each( this.getEmptyParameterState(), function ( param, value ) {
-                       if ( parameters[ param ] !== undefined && parameters[ param ] !== value ) {
-                               result[ param ] = parameters[ param ];
-                       }
-               } );
 
-               // Highlights
-               Object.keys( this.getEmptyHighlightParameters() ).forEach( function ( param ) {
-                       if ( parameters[ param ] ) {
-                               // If a highlight parameter is not undefined and not null
-                               // add it to the result
-                               result[ param ] = parameters[ param ];
-                       }
+                       groupData.filters.forEach( function ( itemData ) {
+                               var filterItem = model.groups[ group ].getItemByParamName( itemData.name );
+                               // Filter conflicts
+                               if ( itemData.conflicts ) {
+                                       filterConflictMap[ filterItem.getName() ] = itemData.conflicts;
+                               }
+                       } );
                } );
-
-               return result;
-       };
-
-       /**
-        * Get a representation of the full parameter list, including all base values
-        *
-        * @return {Object} Full parameter representation
-        */
-       FiltersViewModel.prototype.getExpandedParamRepresentation = function () {
-               return $.extend(
+       } );
+
+       // Add item references to the model, for lookup
+       this.addItems( items );
+
+       // Expand conflicts
+       groupConflictResult = expandConflictDefinitions( groupConflictMap );
+       filterConflictResult = expandConflictDefinitions( filterConflictMap );
+
+       // Set conflicts for groups
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( groupConflictResult, function ( group, conflicts ) {
+               model.groups[ group ].setConflicts( conflicts );
+       } );
+
+       // Set conflicts for items
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( filterConflictResult, function ( filterName, conflicts ) {
+               var filterItem = model.getItemByName( filterName );
+               // set conflicts for items in the group
+               filterItem.setConflicts( conflicts );
+       } );
+
+       // Create a map between known parameters and their models
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( this.groups, function ( group, groupModel ) {
+               if (
+                       groupModel.getType() === 'send_unselected_if_any' ||
+                       groupModel.getType() === 'boolean' ||
+                       groupModel.getType() === 'any_value'
+               ) {
+                       // Individual filters
+                       groupModel.getItems().forEach( function ( filterItem ) {
+                               model.parameterMap[ filterItem.getParamName() ] = filterItem;
+                       } );
+               } else if (
+                       groupModel.getType() === 'string_options' ||
+                       groupModel.getType() === 'single_option'
+               ) {
+                       // Group
+                       model.parameterMap[ groupModel.getName() ] = groupModel;
+               }
+       } );
+
+       this.setSearch( '' );
+
+       this.updateHighlightedState();
+
+       // Finish initialization
+       this.emit( 'initialize' );
+};
+
+/**
+ * Update filter view model state based on a parameter object
+ *
+ * @param {Object} params Parameters object
+ */
+FiltersViewModel.prototype.updateStateFromParams = function ( params ) {
+       var filtersValue;
+       // For arbitrary numeric single_option values make sure the values
+       // are normalized to fit within the limits
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( this.getFilterGroups(), function ( groupName, groupModel ) {
+               params[ groupName ] = groupModel.normalizeArbitraryValue( params[ groupName ] );
+       } );
+
+       // Update filter values
+       filtersValue = this.getFiltersFromParameters( params );
+       Object.keys( filtersValue ).forEach( function ( filterName ) {
+               this.getItemByName( filterName ).setValue( filtersValue[ filterName ] );
+       }.bind( this ) );
+
+       // Update highlight state
+       this.getItemsSupportingHighlights().forEach( function ( filterItem ) {
+               var color = params[ filterItem.getName() + '_color' ];
+               if ( color ) {
+                       filterItem.setHighlightColor( color );
+               } else {
+                       filterItem.clearHighlightColor();
+               }
+       } );
+       this.updateHighlightedState();
+
+       // Check all filter interactions
+       this.reassessFilterInteractions();
+};
+
+/**
+ * Get a representation of an empty (falsey) parameter state
+ *
+ * @return {Object} Empty parameter state
+ */
+FiltersViewModel.prototype.getEmptyParameterState = function () {
+       if ( !this.emptyParameterState ) {
+               this.emptyParameterState = $.extend(
                        true,
                        {},
-                       this.getEmptyParameterState(),
-                       this.getCurrentParameterState()
+                       this.getParametersFromFilters( {} ),
+                       this.getEmptyHighlightParameters()
                );
-       };
-
-       /**
-        * Get a parameter representation of the current state of the model
-        *
-        * @param {boolean} [removeStickyParams] Remove sticky filters from final result
-        * @return {Object} Parameter representation of the current state of the model
-        */
-       FiltersViewModel.prototype.getCurrentParameterState = function ( removeStickyParams ) {
-               var state = this.getMinimizedParamRepresentation( $.extend(
-                       true,
-                       {},
-                       this.getParametersFromFilters( this.getSelectedState() ),
-                       this.getHighlightParameters()
-               ) );
-
-               if ( removeStickyParams ) {
-                       state = this.removeStickyParams( state );
+       }
+       return this.emptyParameterState;
+};
+
+/**
+ * Get a representation of only the non-falsey parameters
+ *
+ * @param {Object} [parameters] A given parameter state to minimize. If not given the current
+ *  state of the system will be used.
+ * @return {Object} Empty parameter state
+ */
+FiltersViewModel.prototype.getMinimizedParamRepresentation = function ( parameters ) {
+       var result = {};
+
+       parameters = parameters ? $.extend( true, {}, parameters ) : this.getCurrentParameterState();
+
+       // Params
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( this.getEmptyParameterState(), function ( param, value ) {
+               if ( parameters[ param ] !== undefined && parameters[ param ] !== value ) {
+                       result[ param ] = parameters[ param ];
                }
-
-               return state;
-       };
-
-       /**
-        * Delete sticky parameters from given object.
-        *
-        * @param {Object} paramState Parameter state
-        * @return {Object} Parameter state without sticky parameters
-        */
-       FiltersViewModel.prototype.removeStickyParams = function ( paramState ) {
-               this.getStickyParams().forEach( function ( paramName ) {
-                       delete paramState[ paramName ];
-               } );
-
-               return paramState;
-       };
-
-       /**
-        * Turn the highlight feature on or off
-        */
-       FiltersViewModel.prototype.updateHighlightedState = function () {
-               this.toggleHighlight( this.getHighlightedItems().length > 0 );
-       };
-
-       /**
-        * Get the object that defines groups by their name.
-        *
-        * @return {Object} Filter groups
-        */
-       FiltersViewModel.prototype.getFilterGroups = function () {
-               return this.groups;
-       };
-
-       /**
-        * Get the object that defines groups that match a certain view by their name.
-        *
-        * @param {string} [view] Requested view. If not given, uses current view
-        * @return {Object} Filter groups matching a display group
-        */
-       FiltersViewModel.prototype.getFilterGroupsByView = function ( view ) {
-               var result = {};
-
-               view = view || this.getCurrentView();
-
-               // eslint-disable-next-line no-jquery/no-each-util
-               $.each( this.groups, function ( groupName, groupModel ) {
-                       if ( groupModel.getView() === view ) {
-                               result[ groupName ] = groupModel;
-                       }
-               } );
-
-               return result;
-       };
-
-       /**
-        * Get an array of filters matching the given display group.
-        *
-        * @param {string} [view] Requested view. If not given, uses current view
-        * @return {mw.rcfilters.dm.FilterItem} Filter items matching the group
-        */
-       FiltersViewModel.prototype.getFiltersByView = function ( view ) {
-               var groups,
-                       result = [];
-
-               view = view || this.getCurrentView();
-
-               groups = this.getFilterGroupsByView( view );
-
-               // eslint-disable-next-line no-jquery/no-each-util
-               $.each( groups, function ( groupName, groupModel ) {
-                       result = result.concat( groupModel.getItems() );
-               } );
-
-               return result;
-       };
-
-       /**
-        * Get the trigger for the requested view.
-        *
-        * @param {string} view View name
-        * @return {string} View trigger, if exists
-        */
-       FiltersViewModel.prototype.getViewTrigger = function ( view ) {
-               return ( this.views[ view ] && this.views[ view ].trigger ) || '';
-       };
-
-       /**
-        * Get the value of a specific parameter
-        *
-        * @param {string} name Parameter name
-        * @return {number|string} Parameter value
-        */
-       FiltersViewModel.prototype.getParamValue = function ( name ) {
-               return this.parameters[ name ];
-       };
-
-       /**
-        * Get the current selected state of the filters
-        *
-        * @param {boolean} [onlySelected] return an object containing only the filters with a value
-        * @return {Object} Filters selected state
-        */
-       FiltersViewModel.prototype.getSelectedState = function ( onlySelected ) {
-               var i,
-                       items = this.getItems(),
-                       result = {};
-
-               for ( i = 0; i < items.length; i++ ) {
-                       if ( !onlySelected || items[ i ].getValue() ) {
-                               result[ items[ i ].getName() ] = items[ i ].getValue();
-                       }
+       } );
+
+       // Highlights
+       Object.keys( this.getEmptyHighlightParameters() ).forEach( function ( param ) {
+               if ( parameters[ param ] ) {
+                       // If a highlight parameter is not undefined and not null
+                       // add it to the result
+                       result[ param ] = parameters[ param ];
                }
-
-               return result;
-       };
-
-       /**
-        * Get the current full state of the filters
-        *
-        * @return {Object} Filters full state
-        */
-       FiltersViewModel.prototype.getFullState = function () {
-               var i,
-                       items = this.getItems(),
-                       result = {};
-
-               for ( i = 0; i < items.length; i++ ) {
-                       result[ items[ i ].getName() ] = {
-                               selected: items[ i ].isSelected(),
-                               conflicted: items[ i ].isConflicted(),
-                               included: items[ i ].isIncluded()
-                       };
+       } );
+
+       return result;
+};
+
+/**
+ * Get a representation of the full parameter list, including all base values
+ *
+ * @return {Object} Full parameter representation
+ */
+FiltersViewModel.prototype.getExpandedParamRepresentation = function () {
+       return $.extend(
+               true,
+               {},
+               this.getEmptyParameterState(),
+               this.getCurrentParameterState()
+       );
+};
+
+/**
+ * Get a parameter representation of the current state of the model
+ *
+ * @param {boolean} [removeStickyParams] Remove sticky filters from final result
+ * @return {Object} Parameter representation of the current state of the model
+ */
+FiltersViewModel.prototype.getCurrentParameterState = function ( removeStickyParams ) {
+       var state = this.getMinimizedParamRepresentation( $.extend(
+               true,
+               {},
+               this.getParametersFromFilters( this.getSelectedState() ),
+               this.getHighlightParameters()
+       ) );
+
+       if ( removeStickyParams ) {
+               state = this.removeStickyParams( state );
+       }
+
+       return state;
+};
+
+/**
+ * Delete sticky parameters from given object.
+ *
+ * @param {Object} paramState Parameter state
+ * @return {Object} Parameter state without sticky parameters
+ */
+FiltersViewModel.prototype.removeStickyParams = function ( paramState ) {
+       this.getStickyParams().forEach( function ( paramName ) {
+               delete paramState[ paramName ];
+       } );
+
+       return paramState;
+};
+
+/**
+ * Turn the highlight feature on or off
+ */
+FiltersViewModel.prototype.updateHighlightedState = function () {
+       this.toggleHighlight( this.getHighlightedItems().length > 0 );
+};
+
+/**
+ * Get the object that defines groups by their name.
+ *
+ * @return {Object} Filter groups
+ */
+FiltersViewModel.prototype.getFilterGroups = function () {
+       return this.groups;
+};
+
+/**
+ * Get the object that defines groups that match a certain view by their name.
+ *
+ * @param {string} [view] Requested view. If not given, uses current view
+ * @return {Object} Filter groups matching a display group
+ */
+FiltersViewModel.prototype.getFilterGroupsByView = function ( view ) {
+       var result = {};
+
+       view = view || this.getCurrentView();
+
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( this.groups, function ( groupName, groupModel ) {
+               if ( groupModel.getView() === view ) {
+                       result[ groupName ] = groupModel;
                }
-
-               return result;
-       };
-
-       /**
-        * Get an object representing default parameters state
-        *
-        * @return {Object} Default parameter values
-        */
-       FiltersViewModel.prototype.getDefaultParams = function () {
-               var result = {};
-
-               // Get default filter state
-               // eslint-disable-next-line no-jquery/no-each-util
-               $.each( this.groups, function ( name, model ) {
-                       if ( !model.isSticky() ) {
-                               $.extend( true, result, model.getDefaultParams() );
-                       }
-               } );
-
-               return result;
-       };
-
-       /**
-        * Get a parameter representation of all sticky parameters
-        *
-        * @return {Object} Sticky parameter values
-        */
-       FiltersViewModel.prototype.getStickyParams = function () {
-               var result = [];
-
-               // eslint-disable-next-line no-jquery/no-each-util
-               $.each( this.groups, function ( name, model ) {
-                       if ( model.isSticky() ) {
-                               if ( model.isPerGroupRequestParameter() ) {
-                                       result.push( name );
-                               } else {
-                                       // Each filter is its own param
-                                       result = result.concat( model.getItems().map( function ( filterItem ) {
-                                               return filterItem.getParamName();
-                                       } ) );
-                               }
-                       }
-               } );
-
-               return result;
-       };
-
-       /**
-        * Get a parameter representation of all sticky parameters
-        *
-        * @return {Object} Sticky parameter values
-        */
-       FiltersViewModel.prototype.getStickyParamsValues = function () {
-               var result = {};
-
-               // eslint-disable-next-line no-jquery/no-each-util
-               $.each( this.groups, function ( name, model ) {
-                       if ( model.isSticky() ) {
-                               $.extend( true, result, model.getParamRepresentation() );
-                       }
-               } );
-
-               return result;
-       };
-
-       /**
-        * Analyze the groups and their filters and output an object representing
-        * the state of the parameters they represent.
-        *
-        * @param {Object} [filterDefinition] An object defining the filter values,
-        *  keyed by filter names.
-        * @return {Object} Parameter state object
-        */
-       FiltersViewModel.prototype.getParametersFromFilters = function ( filterDefinition ) {
-               var groupItemDefinition,
-                       result = {},
-                       groupItems = this.getFilterGroups();
-
-               if ( filterDefinition ) {
-                       groupItemDefinition = {};
-                       // Filter definition is "flat", but in effect
-                       // each group needs to tell us its result based
-                       // on the values in it. We need to split this list
-                       // back into groupings so we can "feed" it to the
-                       // loop below, and we need to expand it so it includes
-                       // all filters (set to false)
-                       this.getItems().forEach( function ( filterItem ) {
-                               groupItemDefinition[ filterItem.getGroupName() ] = groupItemDefinition[ filterItem.getGroupName() ] || {};
-                               groupItemDefinition[ filterItem.getGroupName() ][ filterItem.getName() ] = filterItem.coerceValue( filterDefinition[ filterItem.getName() ] );
-                       } );
+       } );
+
+       return result;
+};
+
+/**
+ * Get an array of filters matching the given display group.
+ *
+ * @param {string} [view] Requested view. If not given, uses current view
+ * @return {mw.rcfilters.dm.FilterItem} Filter items matching the group
+ */
+FiltersViewModel.prototype.getFiltersByView = function ( view ) {
+       var groups,
+               result = [];
+
+       view = view || this.getCurrentView();
+
+       groups = this.getFilterGroupsByView( view );
+
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( groups, function ( groupName, groupModel ) {
+               result = result.concat( groupModel.getItems() );
+       } );
+
+       return result;
+};
+
+/**
+ * Get the trigger for the requested view.
+ *
+ * @param {string} view View name
+ * @return {string} View trigger, if exists
+ */
+FiltersViewModel.prototype.getViewTrigger = function ( view ) {
+       return ( this.views[ view ] && this.views[ view ].trigger ) || '';
+};
+
+/**
+ * Get the value of a specific parameter
+ *
+ * @param {string} name Parameter name
+ * @return {number|string} Parameter value
+ */
+FiltersViewModel.prototype.getParamValue = function ( name ) {
+       return this.parameters[ name ];
+};
+
+/**
+ * Get the current selected state of the filters
+ *
+ * @param {boolean} [onlySelected] return an object containing only the filters with a value
+ * @return {Object} Filters selected state
+ */
+FiltersViewModel.prototype.getSelectedState = function ( onlySelected ) {
+       var i,
+               items = this.getItems(),
+               result = {};
+
+       for ( i = 0; i < items.length; i++ ) {
+               if ( !onlySelected || items[ i ].getValue() ) {
+                       result[ items[ i ].getName() ] = items[ i ].getValue();
                }
-
-               // eslint-disable-next-line no-jquery/no-each-util
-               $.each( groupItems, function ( group, model ) {
-                       $.extend(
-                               result,
-                               model.getParamRepresentation(
-                                       groupItemDefinition ?
-                                               groupItemDefinition[ group ] : null
-                               )
-                       );
-               } );
-
-               return result;
-       };
-
-       /**
-        * This is the opposite of the #getParametersFromFilters method; this goes over
-        * the given parameters and translates into a selected/unselected value in the filters.
-        *
-        * @param {Object} params Parameters query object
-        * @return {Object} Filter state object
-        */
-       FiltersViewModel.prototype.getFiltersFromParameters = function ( params ) {
-               var groupMap = {},
-                       model = this,
-                       result = {};
-
-               // Go over the given parameters, break apart to groupings
-               // The resulting object represents the group with its parameter
-               // values. For example:
-               // {
-               //    group1: {
-               //       param1: "1",
-               //       param2: "0",
-               //       param3: "1"
-               //    },
-               //    group2: "param4|param5"
-               // }
-               // eslint-disable-next-line no-jquery/no-each-util
-               $.each( params, function ( paramName, paramValue ) {
-                       var groupName,
-                               itemOrGroup = model.parameterMap[ paramName ];
-
-                       if ( itemOrGroup ) {
-                               groupName = itemOrGroup instanceof FilterItem ?
-                                       itemOrGroup.getGroupName() : itemOrGroup.getName();
-
-                               groupMap[ groupName ] = groupMap[ groupName ] || {};
-                               groupMap[ groupName ][ paramName ] = paramValue;
-                       }
-               } );
-
-               // Go over all groups, so we make sure we get the complete output
-               // even if the parameters don't include a certain group
-               // eslint-disable-next-line no-jquery/no-each-util
-               $.each( this.groups, function ( groupName, groupModel ) {
-                       result = $.extend( true, {}, result, groupModel.getFilterRepresentation( groupMap[ groupName ] ) );
-               } );
-
-               return result;
-       };
-
-       /**
-        * Get the highlight parameters based on current filter configuration
-        *
-        * @return {Object} Object where keys are `<filter name>_color` and values
-        *                  are the selected highlight colors.
-        */
-       FiltersViewModel.prototype.getHighlightParameters = function () {
-               var highlightEnabled = this.isHighlightEnabled(),
-                       result = {};
-
-               this.getItems().forEach( function ( filterItem ) {
-                       if ( filterItem.isHighlightSupported() ) {
-                               result[ filterItem.getName() + '_color' ] = highlightEnabled && filterItem.isHighlighted() ?
-                                       filterItem.getHighlightColor() :
-                                       null;
+       }
+
+       return result;
+};
+
+/**
+ * Get the current full state of the filters
+ *
+ * @return {Object} Filters full state
+ */
+FiltersViewModel.prototype.getFullState = function () {
+       var i,
+               items = this.getItems(),
+               result = {};
+
+       for ( i = 0; i < items.length; i++ ) {
+               result[ items[ i ].getName() ] = {
+                       selected: items[ i ].isSelected(),
+                       conflicted: items[ i ].isConflicted(),
+                       included: items[ i ].isIncluded()
+               };
+       }
+
+       return result;
+};
+
+/**
+ * Get an object representing default parameters state
+ *
+ * @return {Object} Default parameter values
+ */
+FiltersViewModel.prototype.getDefaultParams = function () {
+       var result = {};
+
+       // Get default filter state
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( this.groups, function ( name, model ) {
+               if ( !model.isSticky() ) {
+                       $.extend( true, result, model.getDefaultParams() );
+               }
+       } );
+
+       return result;
+};
+
+/**
+ * Get a parameter representation of all sticky parameters
+ *
+ * @return {Object} Sticky parameter values
+ */
+FiltersViewModel.prototype.getStickyParams = function () {
+       var result = [];
+
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( this.groups, function ( name, model ) {
+               if ( model.isSticky() ) {
+                       if ( model.isPerGroupRequestParameter() ) {
+                               result.push( name );
+                       } else {
+                               // Each filter is its own param
+                               result = result.concat( model.getItems().map( function ( filterItem ) {
+                                       return filterItem.getParamName();
+                               } ) );
                        }
-               } );
-
-               return result;
-       };
-
-       /**
-        * Get an object representing the complete empty state of highlights
-        *
-        * @return {Object} Object containing all the highlight parameters set to their negative value
-        */
-       FiltersViewModel.prototype.getEmptyHighlightParameters = function () {
-               var result = {};
-
+               }
+       } );
+
+       return result;
+};
+
+/**
+ * Get a parameter representation of all sticky parameters
+ *
+ * @return {Object} Sticky parameter values
+ */
+FiltersViewModel.prototype.getStickyParamsValues = function () {
+       var result = {};
+
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( this.groups, function ( name, model ) {
+               if ( model.isSticky() ) {
+                       $.extend( true, result, model.getParamRepresentation() );
+               }
+       } );
+
+       return result;
+};
+
+/**
+ * Analyze the groups and their filters and output an object representing
+ * the state of the parameters they represent.
+ *
+ * @param {Object} [filterDefinition] An object defining the filter values,
+ *  keyed by filter names.
+ * @return {Object} Parameter state object
+ */
+FiltersViewModel.prototype.getParametersFromFilters = function ( filterDefinition ) {
+       var groupItemDefinition,
+               result = {},
+               groupItems = this.getFilterGroups();
+
+       if ( filterDefinition ) {
+               groupItemDefinition = {};
+               // Filter definition is "flat", but in effect
+               // each group needs to tell us its result based
+               // on the values in it. We need to split this list
+               // back into groupings so we can "feed" it to the
+               // loop below, and we need to expand it so it includes
+               // all filters (set to false)
                this.getItems().forEach( function ( filterItem ) {
-                       if ( filterItem.isHighlightSupported() ) {
-                               result[ filterItem.getName() + '_color' ] = null;
-                       }
+                       groupItemDefinition[ filterItem.getGroupName() ] = groupItemDefinition[ filterItem.getGroupName() ] || {};
+                       groupItemDefinition[ filterItem.getGroupName() ][ filterItem.getName() ] = filterItem.coerceValue( filterDefinition[ filterItem.getName() ] );
                } );
+       }
+
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( groupItems, function ( group, model ) {
+               $.extend(
+                       result,
+                       model.getParamRepresentation(
+                               groupItemDefinition ?
+                                       groupItemDefinition[ group ] : null
+                       )
+               );
+       } );
+
+       return result;
+};
+
+/**
+ * This is the opposite of the #getParametersFromFilters method; this goes over
+ * the given parameters and translates into a selected/unselected value in the filters.
+ *
+ * @param {Object} params Parameters query object
+ * @return {Object} Filter state object
+ */
+FiltersViewModel.prototype.getFiltersFromParameters = function ( params ) {
+       var groupMap = {},
+               model = this,
+               result = {};
+
+       // Go over the given parameters, break apart to groupings
+       // The resulting object represents the group with its parameter
+       // values. For example:
+       // {
+       //    group1: {
+       //       param1: "1",
+       //       param2: "0",
+       //       param3: "1"
+       //    },
+       //    group2: "param4|param5"
+       // }
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( params, function ( paramName, paramValue ) {
+               var groupName,
+                       itemOrGroup = model.parameterMap[ paramName ];
+
+               if ( itemOrGroup ) {
+                       groupName = itemOrGroup instanceof FilterItem ?
+                               itemOrGroup.getGroupName() : itemOrGroup.getName();
+
+                       groupMap[ groupName ] = groupMap[ groupName ] || {};
+                       groupMap[ groupName ][ paramName ] = paramValue;
+               }
+       } );
+
+       // Go over all groups, so we make sure we get the complete output
+       // even if the parameters don't include a certain group
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( this.groups, function ( groupName, groupModel ) {
+               result = $.extend( true, {}, result, groupModel.getFilterRepresentation( groupMap[ groupName ] ) );
+       } );
+
+       return result;
+};
+
+/**
+ * Get the highlight parameters based on current filter configuration
+ *
+ * @return {Object} Object where keys are `<filter name>_color` and values
+ *                  are the selected highlight colors.
+ */
+FiltersViewModel.prototype.getHighlightParameters = function () {
+       var highlightEnabled = this.isHighlightEnabled(),
+               result = {};
+
+       this.getItems().forEach( function ( filterItem ) {
+               if ( filterItem.isHighlightSupported() ) {
+                       result[ filterItem.getName() + '_color' ] = highlightEnabled && filterItem.isHighlighted() ?
+                               filterItem.getHighlightColor() :
+                               null;
+               }
+       } );
+
+       return result;
+};
+
+/**
+ * Get an object representing the complete empty state of highlights
+ *
+ * @return {Object} Object containing all the highlight parameters set to their negative value
+ */
+FiltersViewModel.prototype.getEmptyHighlightParameters = function () {
+       var result = {};
+
+       this.getItems().forEach( function ( filterItem ) {
+               if ( filterItem.isHighlightSupported() ) {
+                       result[ filterItem.getName() + '_color' ] = null;
+               }
+       } );
 
-               return result;
-       };
-
-       /**
-        * Get an array of currently applied highlight colors
-        *
-        * @return {string[]} Currently applied highlight colors
-        */
-       FiltersViewModel.prototype.getCurrentlyUsedHighlightColors = function () {
-               var result = [];
+       return result;
+};
 
-               if ( this.isHighlightEnabled() ) {
-                       this.getHighlightedItems().forEach( function ( filterItem ) {
-                               var color = filterItem.getHighlightColor();
+/**
+ * Get an array of currently applied highlight colors
+ *
+ * @return {string[]} Currently applied highlight colors
+ */
+FiltersViewModel.prototype.getCurrentlyUsedHighlightColors = function () {
+       var result = [];
 
-                               if ( result.indexOf( color ) === -1 ) {
-                                       result.push( color );
-                               }
-                       } );
-               }
+       if ( this.isHighlightEnabled() ) {
+               this.getHighlightedItems().forEach( function ( filterItem ) {
+                       var color = filterItem.getHighlightColor();
 
-               return result;
-       };
-
-       /**
-        * Sanitize value group of a string_option groups type
-        * Remove duplicates and make sure to only use valid
-        * values.
-        *
-        * @private
-        * @param {string} groupName Group name
-        * @param {string[]} valueArray Array of values
-        * @return {string[]} Array of valid values
-        */
-       FiltersViewModel.prototype.sanitizeStringOptionGroup = function ( groupName, valueArray ) {
-               var validNames = this.getGroupFilters( groupName ).map( function ( filterItem ) {
-                       return filterItem.getParamName();
+                       if ( result.indexOf( color ) === -1 ) {
+                               result.push( color );
+                       }
                } );
-
-               return mw.rcfilters.utils.normalizeParamOptions( valueArray, validNames );
-       };
-
-       /**
-        * Check whether no visible filter is selected.
-        *
-        * Filter groups that are hidden or sticky are not shown in the
-        * active filters area and therefore not included in this check.
-        *
-        * @return {boolean} No visible filter is selected
-        */
-       FiltersViewModel.prototype.areVisibleFiltersEmpty = function () {
-               // Check if there are either any selected items or any items
-               // that have highlight enabled
-               return !this.getItems().some( function ( filterItem ) {
-                       var visible = !filterItem.getGroupModel().isSticky() && !filterItem.getGroupModel().isHidden(),
-                               active = ( filterItem.isSelected() || filterItem.isHighlighted() );
-                       return visible && active;
+       }
+
+       return result;
+};
+
+/**
+ * Sanitize value group of a string_option groups type
+ * Remove duplicates and make sure to only use valid
+ * values.
+ *
+ * @private
+ * @param {string} groupName Group name
+ * @param {string[]} valueArray Array of values
+ * @return {string[]} Array of valid values
+ */
+FiltersViewModel.prototype.sanitizeStringOptionGroup = function ( groupName, valueArray ) {
+       var validNames = this.getGroupFilters( groupName ).map( function ( filterItem ) {
+               return filterItem.getParamName();
+       } );
+
+       return mw.rcfilters.utils.normalizeParamOptions( valueArray, validNames );
+};
+
+/**
+ * Check whether no visible filter is selected.
+ *
+ * Filter groups that are hidden or sticky are not shown in the
+ * active filters area and therefore not included in this check.
+ *
+ * @return {boolean} No visible filter is selected
+ */
+FiltersViewModel.prototype.areVisibleFiltersEmpty = function () {
+       // Check if there are either any selected items or any items
+       // that have highlight enabled
+       return !this.getItems().some( function ( filterItem ) {
+               var visible = !filterItem.getGroupModel().isSticky() && !filterItem.getGroupModel().isHidden(),
+                       active = ( filterItem.isSelected() || filterItem.isHighlighted() );
+               return visible && active;
+       } );
+};
+
+/**
+ * Check whether the invert state is a valid one. A valid invert state is one where
+ * there are actual namespaces selected.
+ *
+ * This is done to compare states to previous ones that may have had the invert model
+ * selected but effectively had no namespaces, so are not effectively different than
+ * ones where invert is not selected.
+ *
+ * @return {boolean} Invert is effectively selected
+ */
+FiltersViewModel.prototype.areNamespacesEffectivelyInverted = function () {
+       return this.getInvertModel().isSelected() &&
+               this.findSelectedItems().some( function ( itemModel ) {
+                       return itemModel.getGroupModel().getName() === 'namespace';
                } );
-       };
-
-       /**
-        * Check whether the invert state is a valid one. A valid invert state is one where
-        * there are actual namespaces selected.
-        *
-        * This is done to compare states to previous ones that may have had the invert model
-        * selected but effectively had no namespaces, so are not effectively different than
-        * ones where invert is not selected.
-        *
-        * @return {boolean} Invert is effectively selected
-        */
-       FiltersViewModel.prototype.areNamespacesEffectivelyInverted = function () {
-               return this.getInvertModel().isSelected() &&
-                       this.findSelectedItems().some( function ( itemModel ) {
-                               return itemModel.getGroupModel().getName() === 'namespace';
-                       } );
-       };
-
-       /**
-        * Get the item that matches the given name
-        *
-        * @param {string} name Filter name
-        * @return {mw.rcfilters.dm.FilterItem} Filter item
-        */
-       FiltersViewModel.prototype.getItemByName = function ( name ) {
-               return this.getItems().filter( function ( item ) {
-                       return name === item.getName();
-               } )[ 0 ];
-       };
-
-       /**
-        * Set all filters to false or empty/all
-        * This is equivalent to display all.
-        */
-       FiltersViewModel.prototype.emptyAllFilters = function () {
-               this.getItems().forEach( function ( filterItem ) {
-                       if ( !filterItem.getGroupModel().isSticky() ) {
-                               this.toggleFilterSelected( filterItem.getName(), false );
-                       }
-               }.bind( this ) );
-       };
-
-       /**
-        * Toggle selected state of one item
-        *
-        * @param {string} name Name of the filter item
-        * @param {boolean} [isSelected] Filter selected state
-        */
-       FiltersViewModel.prototype.toggleFilterSelected = function ( name, isSelected ) {
-               var item = this.getItemByName( name );
-
-               if ( item ) {
-                       item.toggleSelected( isSelected );
+};
+
+/**
+ * Get the item that matches the given name
+ *
+ * @param {string} name Filter name
+ * @return {mw.rcfilters.dm.FilterItem} Filter item
+ */
+FiltersViewModel.prototype.getItemByName = function ( name ) {
+       return this.getItems().filter( function ( item ) {
+               return name === item.getName();
+       } )[ 0 ];
+};
+
+/**
+ * Set all filters to false or empty/all
+ * This is equivalent to display all.
+ */
+FiltersViewModel.prototype.emptyAllFilters = function () {
+       this.getItems().forEach( function ( filterItem ) {
+               if ( !filterItem.getGroupModel().isSticky() ) {
+                       this.toggleFilterSelected( filterItem.getName(), false );
                }
-       };
-
-       /**
-        * Toggle selected state of items by their names
-        *
-        * @param {Object} filterDef Filter definitions
-        */
-       FiltersViewModel.prototype.toggleFiltersSelected = function ( filterDef ) {
-               Object.keys( filterDef ).forEach( function ( name ) {
-                       this.toggleFilterSelected( name, filterDef[ name ] );
-               }.bind( this ) );
-       };
-
-       /**
-        * Get a group model from its name
-        *
-        * @param {string} groupName Group name
-        * @return {mw.rcfilters.dm.FilterGroup} Group model
-        */
-       FiltersViewModel.prototype.getGroup = function ( groupName ) {
-               return this.groups[ groupName ];
-       };
-
-       /**
-        * Get all filters within a specified group by its name
-        *
-        * @param {string} groupName Group name
-        * @return {mw.rcfilters.dm.FilterItem[]} Filters belonging to this group
-        */
-       FiltersViewModel.prototype.getGroupFilters = function ( groupName ) {
-               return ( this.getGroup( groupName ) && this.getGroup( groupName ).getItems() ) || [];
-       };
-
-       /**
-        * Find items whose labels match the given string
-        *
-        * @param {string} query Search string
-        * @param {boolean} [returnFlat] Return a flat array. If false, the result
-        *  is an object whose keys are the group names and values are an array of
-        *  filters per group. If set to true, returns an array of filters regardless
-        *  of their groups.
-        * @return {Object} An object of items to show
-        *  arranged by their group names
-        */
-       FiltersViewModel.prototype.findMatches = function ( query, returnFlat ) {
-               var i, searchIsEmpty,
-                       groupTitle,
-                       result = {},
-                       flatResult = [],
-                       view = this.getViewByTrigger( query.substr( 0, 1 ) ),
-                       items = this.getFiltersByView( view );
-
-               // Normalize so we can search strings regardless of case and view
-               query = query.trim().toLowerCase();
-               if ( view !== 'default' ) {
-                       query = query.substr( 1 );
+       }.bind( this ) );
+};
+
+/**
+ * Toggle selected state of one item
+ *
+ * @param {string} name Name of the filter item
+ * @param {boolean} [isSelected] Filter selected state
+ */
+FiltersViewModel.prototype.toggleFilterSelected = function ( name, isSelected ) {
+       var item = this.getItemByName( name );
+
+       if ( item ) {
+               item.toggleSelected( isSelected );
+       }
+};
+
+/**
+ * Toggle selected state of items by their names
+ *
+ * @param {Object} filterDef Filter definitions
+ */
+FiltersViewModel.prototype.toggleFiltersSelected = function ( filterDef ) {
+       Object.keys( filterDef ).forEach( function ( name ) {
+               this.toggleFilterSelected( name, filterDef[ name ] );
+       }.bind( this ) );
+};
+
+/**
+ * Get a group model from its name
+ *
+ * @param {string} groupName Group name
+ * @return {mw.rcfilters.dm.FilterGroup} Group model
+ */
+FiltersViewModel.prototype.getGroup = function ( groupName ) {
+       return this.groups[ groupName ];
+};
+
+/**
+ * Get all filters within a specified group by its name
+ *
+ * @param {string} groupName Group name
+ * @return {mw.rcfilters.dm.FilterItem[]} Filters belonging to this group
+ */
+FiltersViewModel.prototype.getGroupFilters = function ( groupName ) {
+       return ( this.getGroup( groupName ) && this.getGroup( groupName ).getItems() ) || [];
+};
+
+/**
+ * Find items whose labels match the given string
+ *
+ * @param {string} query Search string
+ * @param {boolean} [returnFlat] Return a flat array. If false, the result
+ *  is an object whose keys are the group names and values are an array of
+ *  filters per group. If set to true, returns an array of filters regardless
+ *  of their groups.
+ * @return {Object} An object of items to show
+ *  arranged by their group names
+ */
+FiltersViewModel.prototype.findMatches = function ( query, returnFlat ) {
+       var i, searchIsEmpty,
+               groupTitle,
+               result = {},
+               flatResult = [],
+               view = this.getViewByTrigger( query.substr( 0, 1 ) ),
+               items = this.getFiltersByView( view );
+
+       // Normalize so we can search strings regardless of case and view
+       query = query.trim().toLowerCase();
+       if ( view !== 'default' ) {
+               query = query.substr( 1 );
+       }
+       // Trim again to also intercept cases where the spaces were after the trigger
+       // eg: '#   str'
+       query = query.trim();
+
+       // Check if the search if actually empty; this can be a problem when
+       // we use prefixes to denote different views
+       searchIsEmpty = query.length === 0;
+
+       // item label starting with the query string
+       for ( i = 0; i < items.length; i++ ) {
+               if (
+                       searchIsEmpty ||
+                       items[ i ].getLabel().toLowerCase().indexOf( query ) === 0 ||
+                       (
+                               // For tags, we want the parameter name to be included in the search
+                               view === 'tags' &&
+                               items[ i ].getParamName().toLowerCase().indexOf( query ) > -1
+                       )
+               ) {
+                       result[ items[ i ].getGroupName() ] = result[ items[ i ].getGroupName() ] || [];
+                       result[ items[ i ].getGroupName() ].push( items[ i ] );
+                       flatResult.push( items[ i ] );
                }
-               // Trim again to also intercept cases where the spaces were after the trigger
-               // eg: '#   str'
-               query = query.trim();
+       }
 
-               // Check if the search if actually empty; this can be a problem when
-               // we use prefixes to denote different views
-               searchIsEmpty = query.length === 0;
-
-               // item label starting with the query string
+       if ( $.isEmptyObject( result ) ) {
+               // item containing the query string in their label, description, or group title
                for ( i = 0; i < items.length; i++ ) {
+                       groupTitle = items[ i ].getGroupModel().getTitle();
                        if (
                                searchIsEmpty ||
-                               items[ i ].getLabel().toLowerCase().indexOf( query ) === 0 ||
+                               items[ i ].getLabel().toLowerCase().indexOf( query ) > -1 ||
+                               items[ i ].getDescription().toLowerCase().indexOf( query ) > -1 ||
+                               groupTitle.toLowerCase().indexOf( query ) > -1 ||
                                (
                                        // For tags, we want the parameter name to be included in the search
                                        view === 'tags' &&
                                flatResult.push( items[ i ] );
                        }
                }
-
-               if ( $.isEmptyObject( result ) ) {
-                       // item containing the query string in their label, description, or group title
-                       for ( i = 0; i < items.length; i++ ) {
-                               groupTitle = items[ i ].getGroupModel().getTitle();
-                               if (
-                                       searchIsEmpty ||
-                                       items[ i ].getLabel().toLowerCase().indexOf( query ) > -1 ||
-                                       items[ i ].getDescription().toLowerCase().indexOf( query ) > -1 ||
-                                       groupTitle.toLowerCase().indexOf( query ) > -1 ||
-                                       (
-                                               // For tags, we want the parameter name to be included in the search
-                                               view === 'tags' &&
-                                               items[ i ].getParamName().toLowerCase().indexOf( query ) > -1
-                                       )
-                               ) {
-                                       result[ items[ i ].getGroupName() ] = result[ items[ i ].getGroupName() ] || [];
-                                       result[ items[ i ].getGroupName() ].push( items[ i ] );
-                                       flatResult.push( items[ i ] );
-                               }
-                       }
+       }
+
+       return returnFlat ? flatResult : result;
+};
+
+/**
+ * Get items that are highlighted
+ *
+ * @return {mw.rcfilters.dm.FilterItem[]} Highlighted items
+ */
+FiltersViewModel.prototype.getHighlightedItems = function () {
+       return this.getItems().filter( function ( filterItem ) {
+               return filterItem.isHighlightSupported() &&
+                       filterItem.getHighlightColor();
+       } );
+};
+
+/**
+ * Get items that allow highlights even if they're not currently highlighted
+ *
+ * @return {mw.rcfilters.dm.FilterItem[]} Items supporting highlights
+ */
+FiltersViewModel.prototype.getItemsSupportingHighlights = function () {
+       return this.getItems().filter( function ( filterItem ) {
+               return filterItem.isHighlightSupported();
+       } );
+};
+
+/**
+ * Get all selected items
+ *
+ * @return {mw.rcfilters.dm.FilterItem[]} Selected items
+ */
+FiltersViewModel.prototype.findSelectedItems = function () {
+       var allSelected = [];
+
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( this.getFilterGroups(), function ( groupName, groupModel ) {
+               allSelected = allSelected.concat( groupModel.findSelectedItems() );
+       } );
+
+       return allSelected;
+};
+
+/**
+ * Get the current view
+ *
+ * @return {string} Current view
+ */
+FiltersViewModel.prototype.getCurrentView = function () {
+       return this.currentView;
+};
+
+/**
+ * Get the label for the current view
+ *
+ * @param {string} viewName View name
+ * @return {string} Label for the current view
+ */
+FiltersViewModel.prototype.getViewTitle = function ( viewName ) {
+       viewName = viewName || this.getCurrentView();
+
+       return this.views[ viewName ] && this.views[ viewName ].title;
+};
+
+/**
+ * Get the view that fits the given trigger
+ *
+ * @param {string} trigger Trigger
+ * @return {string} Name of view
+ */
+FiltersViewModel.prototype.getViewByTrigger = function ( trigger ) {
+       var result = 'default';
+
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( this.views, function ( name, data ) {
+               if ( data.trigger === trigger ) {
+                       result = name;
                }
-
-               return returnFlat ? flatResult : result;
-       };
-
-       /**
-        * Get items that are highlighted
-        *
-        * @return {mw.rcfilters.dm.FilterItem[]} Highlighted items
-        */
-       FiltersViewModel.prototype.getHighlightedItems = function () {
-               return this.getItems().filter( function ( filterItem ) {
-                       return filterItem.isHighlightSupported() &&
-                               filterItem.getHighlightColor();
-               } );
-       };
-
-       /**
-        * Get items that allow highlights even if they're not currently highlighted
-        *
-        * @return {mw.rcfilters.dm.FilterItem[]} Items supporting highlights
-        */
-       FiltersViewModel.prototype.getItemsSupportingHighlights = function () {
-               return this.getItems().filter( function ( filterItem ) {
-                       return filterItem.isHighlightSupported();
-               } );
-       };
-
-       /**
-        * Get all selected items
-        *
-        * @return {mw.rcfilters.dm.FilterItem[]} Selected items
-        */
-       FiltersViewModel.prototype.findSelectedItems = function () {
-               var allSelected = [];
-
+       } );
+
+       return result;
+};
+
+/**
+ * Return a version of the given string that is without any
+ * view triggers.
+ *
+ * @param {string} str Given string
+ * @return {string} Result
+ */
+FiltersViewModel.prototype.removeViewTriggers = function ( str ) {
+       if ( this.getViewFromString( str ) !== 'default' ) {
+               str = str.substr( 1 );
+       }
+
+       return str;
+};
+
+/**
+ * Get the view from the given string by a trigger, if it exists
+ *
+ * @param {string} str Given string
+ * @return {string} View name
+ */
+FiltersViewModel.prototype.getViewFromString = function ( str ) {
+       return this.getViewByTrigger( str.substr( 0, 1 ) );
+};
+
+/**
+ * Set the current search for the system.
+ * This also dictates what items and groups are visible according
+ * to the search in #findMatches
+ *
+ * @param {string} searchQuery Search query, including triggers
+ * @fires searchChange
+ */
+FiltersViewModel.prototype.setSearch = function ( searchQuery ) {
+       var visibleGroups, visibleGroupNames;
+
+       if ( this.searchQuery !== searchQuery ) {
+               // Check if the view changed
+               this.switchView( this.getViewFromString( searchQuery ) );
+
+               visibleGroups = this.findMatches( searchQuery );
+               visibleGroupNames = Object.keys( visibleGroups );
+
+               // Update visibility of items and groups
                // eslint-disable-next-line no-jquery/no-each-util
                $.each( this.getFilterGroups(), function ( groupName, groupModel ) {
-                       allSelected = allSelected.concat( groupModel.findSelectedItems() );
-               } );
-
-               return allSelected;
-       };
-
-       /**
-        * Get the current view
-        *
-        * @return {string} Current view
-        */
-       FiltersViewModel.prototype.getCurrentView = function () {
-               return this.currentView;
-       };
-
-       /**
-        * Get the label for the current view
-        *
-        * @param {string} viewName View name
-        * @return {string} Label for the current view
-        */
-       FiltersViewModel.prototype.getViewTitle = function ( viewName ) {
-               viewName = viewName || this.getCurrentView();
-
-               return this.views[ viewName ] && this.views[ viewName ].title;
-       };
-
-       /**
-        * Get the view that fits the given trigger
-        *
-        * @param {string} trigger Trigger
-        * @return {string} Name of view
-        */
-       FiltersViewModel.prototype.getViewByTrigger = function ( trigger ) {
-               var result = 'default';
-
-               // eslint-disable-next-line no-jquery/no-each-util
-               $.each( this.views, function ( name, data ) {
-                       if ( data.trigger === trigger ) {
-                               result = name;
-                       }
+                       // Check if the group is visible at all
+                       groupModel.toggleVisible( visibleGroupNames.indexOf( groupName ) !== -1 );
+                       groupModel.setVisibleItems( visibleGroups[ groupName ] || [] );
                } );
 
-               return result;
-       };
-
-       /**
-        * Return a version of the given string that is without any
-        * view triggers.
-        *
-        * @param {string} str Given string
-        * @return {string} Result
-        */
-       FiltersViewModel.prototype.removeViewTriggers = function ( str ) {
-               if ( this.getViewFromString( str ) !== 'default' ) {
-                       str = str.substr( 1 );
-               }
-
-               return str;
-       };
-
-       /**
-        * Get the view from the given string by a trigger, if it exists
-        *
-        * @param {string} str Given string
-        * @return {string} View name
-        */
-       FiltersViewModel.prototype.getViewFromString = function ( str ) {
-               return this.getViewByTrigger( str.substr( 0, 1 ) );
-       };
-
-       /**
-        * Set the current search for the system.
-        * This also dictates what items and groups are visible according
-        * to the search in #findMatches
-        *
-        * @param {string} searchQuery Search query, including triggers
-        * @fires searchChange
-        */
-       FiltersViewModel.prototype.setSearch = function ( searchQuery ) {
-               var visibleGroups, visibleGroupNames;
-
-               if ( this.searchQuery !== searchQuery ) {
-                       // Check if the view changed
-                       this.switchView( this.getViewFromString( searchQuery ) );
-
-                       visibleGroups = this.findMatches( searchQuery );
-                       visibleGroupNames = Object.keys( visibleGroups );
-
-                       // Update visibility of items and groups
-                       // eslint-disable-next-line no-jquery/no-each-util
-                       $.each( this.getFilterGroups(), function ( groupName, groupModel ) {
-                               // Check if the group is visible at all
-                               groupModel.toggleVisible( visibleGroupNames.indexOf( groupName ) !== -1 );
-                               groupModel.setVisibleItems( visibleGroups[ groupName ] || [] );
-                       } );
-
-                       this.searchQuery = searchQuery;
-                       this.emit( 'searchChange', this.searchQuery );
-               }
-       };
-
-       /**
-        * Get the current search
-        *
-        * @return {string} Current search query
-        */
-       FiltersViewModel.prototype.getSearch = function () {
-               return this.searchQuery;
-       };
-
-       /**
-        * Switch the current view
-        *
-        * @private
-        * @param {string} view View name
-        */
-       FiltersViewModel.prototype.switchView = function ( view ) {
-               if ( this.views[ view ] && this.currentView !== view ) {
-                       this.currentView = view;
-               }
-       };
-
-       /**
-        * Toggle the highlight feature on and off.
-        * Propagate the change to filter items.
-        *
-        * @param {boolean} enable Highlight should be enabled
-        * @fires highlightChange
-        */
-       FiltersViewModel.prototype.toggleHighlight = function ( enable ) {
-               enable = enable === undefined ? !this.highlightEnabled : enable;
-
-               if ( this.highlightEnabled !== enable ) {
-                       this.highlightEnabled = enable;
-                       this.emit( 'highlightChange', this.highlightEnabled );
-               }
-       };
-
-       /**
-        * Check if the highlight feature is enabled
-        * @return {boolean}
-        */
-       FiltersViewModel.prototype.isHighlightEnabled = function () {
-               return !!this.highlightEnabled;
-       };
-
-       /**
-        * Toggle the inverted namespaces property on and off.
-        * Propagate the change to namespace filter items.
-        *
-        * @param {boolean} enable Inverted property is enabled
-        */
-       FiltersViewModel.prototype.toggleInvertedNamespaces = function ( enable ) {
-               this.toggleFilterSelected( this.getInvertModel().getName(), enable );
-       };
-
-       /**
-        * Get the model object that represents the 'invert' filter
-        *
-        * @return {mw.rcfilters.dm.FilterItem}
-        */
-       FiltersViewModel.prototype.getInvertModel = function () {
-               return this.getGroup( 'invertGroup' ).getItemByParamName( 'invert' );
-       };
-
-       /**
-        * Set highlight color for a specific filter item
-        *
-        * @param {string} filterName Name of the filter item
-        * @param {string} color Selected color
-        */
-       FiltersViewModel.prototype.setHighlightColor = function ( filterName, color ) {
-               this.getItemByName( filterName ).setHighlightColor( color );
-       };
-
-       /**
-        * Clear highlight for a specific filter item
-        *
-        * @param {string} filterName Name of the filter item
-        */
-       FiltersViewModel.prototype.clearHighlightColor = function ( filterName ) {
-               this.getItemByName( filterName ).clearHighlightColor();
-       };
-
-       module.exports = FiltersViewModel;
-
-}() );
+               this.searchQuery = searchQuery;
+               this.emit( 'searchChange', this.searchQuery );
+       }
+};
+
+/**
+ * Get the current search
+ *
+ * @return {string} Current search query
+ */
+FiltersViewModel.prototype.getSearch = function () {
+       return this.searchQuery;
+};
+
+/**
+ * Switch the current view
+ *
+ * @private
+ * @param {string} view View name
+ */
+FiltersViewModel.prototype.switchView = function ( view ) {
+       if ( this.views[ view ] && this.currentView !== view ) {
+               this.currentView = view;
+       }
+};
+
+/**
+ * Toggle the highlight feature on and off.
+ * Propagate the change to filter items.
+ *
+ * @param {boolean} enable Highlight should be enabled
+ * @fires highlightChange
+ */
+FiltersViewModel.prototype.toggleHighlight = function ( enable ) {
+       enable = enable === undefined ? !this.highlightEnabled : enable;
+
+       if ( this.highlightEnabled !== enable ) {
+               this.highlightEnabled = enable;
+               this.emit( 'highlightChange', this.highlightEnabled );
+       }
+};
+
+/**
+ * Check if the highlight feature is enabled
+ * @return {boolean}
+ */
+FiltersViewModel.prototype.isHighlightEnabled = function () {
+       return !!this.highlightEnabled;
+};
+
+/**
+ * Toggle the inverted namespaces property on and off.
+ * Propagate the change to namespace filter items.
+ *
+ * @param {boolean} enable Inverted property is enabled
+ */
+FiltersViewModel.prototype.toggleInvertedNamespaces = function ( enable ) {
+       this.toggleFilterSelected( this.getInvertModel().getName(), enable );
+};
+
+/**
+ * Get the model object that represents the 'invert' filter
+ *
+ * @return {mw.rcfilters.dm.FilterItem}
+ */
+FiltersViewModel.prototype.getInvertModel = function () {
+       return this.getGroup( 'invertGroup' ).getItemByParamName( 'invert' );
+};
+
+/**
+ * Set highlight color for a specific filter item
+ *
+ * @param {string} filterName Name of the filter item
+ * @param {string} color Selected color
+ */
+FiltersViewModel.prototype.setHighlightColor = function ( filterName, color ) {
+       this.getItemByName( filterName ).setHighlightColor( color );
+};
+
+/**
+ * Clear highlight for a specific filter item
+ *
+ * @param {string} filterName Name of the filter item
+ */
+FiltersViewModel.prototype.clearHighlightColor = function ( filterName ) {
+       this.getItemByName( filterName ).clearHighlightColor();
+};
+
+module.exports = FiltersViewModel;
index 2dc578e..ae8ac5f 100644 (file)
-( function () {
-       /**
-        * RCFilter base item model
-        *
-        * @class mw.rcfilters.dm.ItemModel
-        * @mixins OO.EventEmitter
-        *
-        * @constructor
-        * @param {string} param Filter param name
-        * @param {Object} config Configuration object
-        * @cfg {string} [label] The label for the filter
-        * @cfg {string} [description] The description of the filter
-        * @cfg {string|Object} [labelPrefixKey] An i18n key defining the prefix label for this
-        *  group. If the prefix has 'invert' state, the parameter is expected to be an object
-        *  with 'default' and 'inverted' as keys.
-        * @cfg {boolean} [active=true] The filter is active and affecting the result
-        * @cfg {boolean} [selected] The item is selected
-        * @cfg {*} [value] The value of this item
-        * @cfg {string} [namePrefix='item_'] A prefix to add to the param name to act as a unique
-        *  identifier
-        * @cfg {string} [cssClass] The class identifying the results that match this filter
-        * @cfg {string[]} [identifiers] An array of identifiers for this item. They will be
-        *  added and considered in the view.
-        * @cfg {string} [defaultHighlightColor=null] If set, highlight this filter by default with this color
-        */
-       var ItemModel = function MwRcfiltersDmItemModel( param, config ) {
-               config = config || {};
-
-               // Mixin constructor
-               OO.EventEmitter.call( this );
-
-               this.param = param;
-               this.namePrefix = config.namePrefix || 'item_';
-               this.name = this.namePrefix + param;
-
-               this.label = config.label || this.name;
-               this.labelPrefixKey = config.labelPrefixKey;
-               this.description = config.description || '';
-               this.setValue( config.value || config.selected );
-
-               this.identifiers = config.identifiers || [];
-
-               // Highlight
-               this.cssClass = config.cssClass;
-               this.highlightColor = config.defaultHighlightColor || null;
+/**
+ * RCFilter base item model
+ *
+ * @class mw.rcfilters.dm.ItemModel
+ * @mixins OO.EventEmitter
+ *
+ * @constructor
+ * @param {string} param Filter param name
+ * @param {Object} config Configuration object
+ * @cfg {string} [label] The label for the filter
+ * @cfg {string} [description] The description of the filter
+ * @cfg {string|Object} [labelPrefixKey] An i18n key defining the prefix label for this
+ *  group. If the prefix has 'invert' state, the parameter is expected to be an object
+ *  with 'default' and 'inverted' as keys.
+ * @cfg {boolean} [active=true] The filter is active and affecting the result
+ * @cfg {boolean} [selected] The item is selected
+ * @cfg {*} [value] The value of this item
+ * @cfg {string} [namePrefix='item_'] A prefix to add to the param name to act as a unique
+ *  identifier
+ * @cfg {string} [cssClass] The class identifying the results that match this filter
+ * @cfg {string[]} [identifiers] An array of identifiers for this item. They will be
+ *  added and considered in the view.
+ * @cfg {string} [defaultHighlightColor=null] If set, highlight this filter by default with this color
+ */
+var ItemModel = function MwRcfiltersDmItemModel( param, config ) {
+       config = config || {};
+
+       // Mixin constructor
+       OO.EventEmitter.call( this );
+
+       this.param = param;
+       this.namePrefix = config.namePrefix || 'item_';
+       this.name = this.namePrefix + param;
+
+       this.label = config.label || this.name;
+       this.labelPrefixKey = config.labelPrefixKey;
+       this.description = config.description || '';
+       this.setValue( config.value || config.selected );
+
+       this.identifiers = config.identifiers || [];
+
+       // Highlight
+       this.cssClass = config.cssClass;
+       this.highlightColor = config.defaultHighlightColor || null;
+};
+
+/* Initialization */
+
+OO.initClass( ItemModel );
+OO.mixinClass( ItemModel, OO.EventEmitter );
+
+/* Events */
+
+/**
+ * @event update
+ *
+ * The state of this filter has changed
+ */
+
+/* Methods */
+
+/**
+ * Return the representation of the state of this item.
+ *
+ * @return {Object} State of the object
+ */
+ItemModel.prototype.getState = function () {
+       return {
+               selected: this.isSelected()
        };
-
-       /* Initialization */
-
-       OO.initClass( ItemModel );
-       OO.mixinClass( ItemModel, OO.EventEmitter );
-
-       /* Events */
-
-       /**
-        * @event update
-        *
-        * The state of this filter has changed
-        */
-
-       /* Methods */
-
-       /**
-        * Return the representation of the state of this item.
-        *
-        * @return {Object} State of the object
-        */
-       ItemModel.prototype.getState = function () {
-               return {
-                       selected: this.isSelected()
-               };
-       };
-
-       /**
-        * Get the name of this filter
-        *
-        * @return {string} Filter name
-        */
-       ItemModel.prototype.getName = function () {
-               return this.name;
-       };
-
-       /**
-        * Get the message key to use to wrap the label. This message takes the label as a parameter.
-        *
-        * @param {boolean} inverted Whether this item should be considered inverted
-        * @return {string|null} Message key, or null if no message
-        */
-       ItemModel.prototype.getLabelMessageKey = function ( inverted ) {
-               if ( this.labelPrefixKey ) {
-                       if ( typeof this.labelPrefixKey === 'string' ) {
-                               return this.labelPrefixKey;
-                       }
-                       return this.labelPrefixKey[
-                               // Only use inverted-prefix if the item is selected
-                               // Highlight-only an inverted item makes no sense
-                               inverted && this.isSelected() ?
-                                       'inverted' : 'default'
-                       ];
+};
+
+/**
+ * Get the name of this filter
+ *
+ * @return {string} Filter name
+ */
+ItemModel.prototype.getName = function () {
+       return this.name;
+};
+
+/**
+ * Get the message key to use to wrap the label. This message takes the label as a parameter.
+ *
+ * @param {boolean} inverted Whether this item should be considered inverted
+ * @return {string|null} Message key, or null if no message
+ */
+ItemModel.prototype.getLabelMessageKey = function ( inverted ) {
+       if ( this.labelPrefixKey ) {
+               if ( typeof this.labelPrefixKey === 'string' ) {
+                       return this.labelPrefixKey;
                }
-               return null;
-       };
-
-       /**
-        * Get the param name or value of this filter
-        *
-        * @return {string} Filter param name
-        */
-       ItemModel.prototype.getParamName = function () {
-               return this.param;
-       };
-
-       /**
-        * Get the message representing the state of this model.
-        *
-        * @return {string} State message
-        */
-       ItemModel.prototype.getStateMessage = function () {
-               // Display description
-               return this.getDescription();
-       };
-
-       /**
-        * Get the label of this filter
-        *
-        * @return {string} Filter label
-        */
-       ItemModel.prototype.getLabel = function () {
-               return this.label;
-       };
-
-       /**
-        * Get the description of this filter
-        *
-        * @return {string} Filter description
-        */
-       ItemModel.prototype.getDescription = function () {
-               return this.description;
-       };
-
-       /**
-        * Get the default value of this filter
-        *
-        * @return {boolean} Filter default
-        */
-       ItemModel.prototype.getDefault = function () {
-               return this.default;
-       };
-
-       /**
-        * Get the selected state of this filter
-        *
-        * @return {boolean} Filter is selected
-        */
-       ItemModel.prototype.isSelected = function () {
-               return !!this.value;
-       };
-
-       /**
-        * Toggle the selected state of the item
-        *
-        * @param {boolean} [isSelected] Filter is selected
-        * @fires update
-        */
-       ItemModel.prototype.toggleSelected = function ( isSelected ) {
-               isSelected = isSelected === undefined ? !this.isSelected() : isSelected;
-               this.setValue( isSelected );
-       };
-
-       /**
-        * Get the value
-        *
-        * @return {*}
-        */
-       ItemModel.prototype.getValue = function () {
-               return this.value;
-       };
-
-       /**
-        * Convert a given value to the appropriate representation based on group type
-        *
-        * @param {*} value
-        * @return {*}
-        */
-       ItemModel.prototype.coerceValue = function ( value ) {
-               return this.getGroupModel().getType() === 'any_value' ? value : !!value;
-       };
-
-       /**
-        * Set the value
-        *
-        * @param {*} newValue
-        */
-       ItemModel.prototype.setValue = function ( newValue ) {
-               newValue = this.coerceValue( newValue );
-               if ( this.value !== newValue ) {
-                       this.value = newValue;
-                       this.emit( 'update' );
-               }
-       };
-
-       /**
-        * Set the highlight color
-        *
-        * @param {string|null} highlightColor
-        */
-       ItemModel.prototype.setHighlightColor = function ( highlightColor ) {
-               if ( !this.isHighlightSupported() ) {
-                       return;
-               }
-               // If the highlight color on the item and in the parameter is null/undefined, return early.
-               if ( !this.highlightColor && !highlightColor ) {
-                       return;
-               }
-
-               if ( this.highlightColor !== highlightColor ) {
-                       this.highlightColor = highlightColor;
-                       this.emit( 'update' );
-               }
-       };
-
-       /**
-        * Clear the highlight color
-        */
-       ItemModel.prototype.clearHighlightColor = function () {
-               this.setHighlightColor( null );
-       };
-
-       /**
-        * Get the highlight color, or null if none is configured
-        *
-        * @return {string|null}
-        */
-       ItemModel.prototype.getHighlightColor = function () {
-               return this.highlightColor;
-       };
-
-       /**
-        * Get the CSS class that matches changes that fit this filter
-        * or null if none is configured
-        *
-        * @return {string|null}
-        */
-       ItemModel.prototype.getCssClass = function () {
-               return this.cssClass;
-       };
-
-       /**
-        * Get the item's identifiers
-        *
-        * @return {string[]}
-        */
-       ItemModel.prototype.getIdentifiers = function () {
-               return this.identifiers;
-       };
-
-       /**
-        * Check if the highlight feature is supported for this filter
-        *
-        * @return {boolean}
-        */
-       ItemModel.prototype.isHighlightSupported = function () {
-               return !!this.getCssClass();
-       };
-
-       /**
-        * Check if the filter is currently highlighted
-        *
-        * @return {boolean}
-        */
-       ItemModel.prototype.isHighlighted = function () {
-               return !!this.getHighlightColor();
-       };
-
-       module.exports = ItemModel;
-}() );
+               return this.labelPrefixKey[
+                       // Only use inverted-prefix if the item is selected
+                       // Highlight-only an inverted item makes no sense
+                       inverted && this.isSelected() ?
+                               'inverted' : 'default'
+               ];
+       }
+       return null;
+};
+
+/**
+ * Get the param name or value of this filter
+ *
+ * @return {string} Filter param name
+ */
+ItemModel.prototype.getParamName = function () {
+       return this.param;
+};
+
+/**
+ * Get the message representing the state of this model.
+ *
+ * @return {string} State message
+ */
+ItemModel.prototype.getStateMessage = function () {
+       // Display description
+       return this.getDescription();
+};
+
+/**
+ * Get the label of this filter
+ *
+ * @return {string} Filter label
+ */
+ItemModel.prototype.getLabel = function () {
+       return this.label;
+};
+
+/**
+ * Get the description of this filter
+ *
+ * @return {string} Filter description
+ */
+ItemModel.prototype.getDescription = function () {
+       return this.description;
+};
+
+/**
+ * Get the default value of this filter
+ *
+ * @return {boolean} Filter default
+ */
+ItemModel.prototype.getDefault = function () {
+       return this.default;
+};
+
+/**
+ * Get the selected state of this filter
+ *
+ * @return {boolean} Filter is selected
+ */
+ItemModel.prototype.isSelected = function () {
+       return !!this.value;
+};
+
+/**
+ * Toggle the selected state of the item
+ *
+ * @param {boolean} [isSelected] Filter is selected
+ * @fires update
+ */
+ItemModel.prototype.toggleSelected = function ( isSelected ) {
+       isSelected = isSelected === undefined ? !this.isSelected() : isSelected;
+       this.setValue( isSelected );
+};
+
+/**
+ * Get the value
+ *
+ * @return {*}
+ */
+ItemModel.prototype.getValue = function () {
+       return this.value;
+};
+
+/**
+ * Convert a given value to the appropriate representation based on group type
+ *
+ * @param {*} value
+ * @return {*}
+ */
+ItemModel.prototype.coerceValue = function ( value ) {
+       return this.getGroupModel().getType() === 'any_value' ? value : !!value;
+};
+
+/**
+ * Set the value
+ *
+ * @param {*} newValue
+ */
+ItemModel.prototype.setValue = function ( newValue ) {
+       newValue = this.coerceValue( newValue );
+       if ( this.value !== newValue ) {
+               this.value = newValue;
+               this.emit( 'update' );
+       }
+};
+
+/**
+ * Set the highlight color
+ *
+ * @param {string|null} highlightColor
+ */
+ItemModel.prototype.setHighlightColor = function ( highlightColor ) {
+       if ( !this.isHighlightSupported() ) {
+               return;
+       }
+       // If the highlight color on the item and in the parameter is null/undefined, return early.
+       if ( !this.highlightColor && !highlightColor ) {
+               return;
+       }
+
+       if ( this.highlightColor !== highlightColor ) {
+               this.highlightColor = highlightColor;
+               this.emit( 'update' );
+       }
+};
+
+/**
+ * Clear the highlight color
+ */
+ItemModel.prototype.clearHighlightColor = function () {
+       this.setHighlightColor( null );
+};
+
+/**
+ * Get the highlight color, or null if none is configured
+ *
+ * @return {string|null}
+ */
+ItemModel.prototype.getHighlightColor = function () {
+       return this.highlightColor;
+};
+
+/**
+ * Get the CSS class that matches changes that fit this filter
+ * or null if none is configured
+ *
+ * @return {string|null}
+ */
+ItemModel.prototype.getCssClass = function () {
+       return this.cssClass;
+};
+
+/**
+ * Get the item's identifiers
+ *
+ * @return {string[]}
+ */
+ItemModel.prototype.getIdentifiers = function () {
+       return this.identifiers;
+};
+
+/**
+ * Check if the highlight feature is supported for this filter
+ *
+ * @return {boolean}
+ */
+ItemModel.prototype.isHighlightSupported = function () {
+       return !!this.getCssClass();
+};
+
+/**
+ * Check if the filter is currently highlighted
+ *
+ * @return {boolean}
+ */
+ItemModel.prototype.isHighlighted = function () {
+       return !!this.getHighlightColor();
+};
+
+module.exports = ItemModel;
index aa407b9..19de282 100644 (file)
-( function () {
-       var SavedQueryItemModel = require( './SavedQueryItemModel.js' ),
-               SavedQueriesModel;
-
-       /**
-        * View model for saved queries
-        *
-        * @class mw.rcfilters.dm.SavedQueriesModel
-        * @mixins OO.EventEmitter
-        * @mixins OO.EmitterList
-        *
-        * @constructor
-        * @param {mw.rcfilters.dm.FiltersViewModel} filtersModel Filters model
-        * @param {Object} [config] Configuration options
-        * @cfg {string} [default] Default query ID
-        */
-       SavedQueriesModel = function MwRcfiltersDmSavedQueriesModel( filtersModel, config ) {
-               config = config || {};
-
-               // Mixin constructor
-               OO.EventEmitter.call( this );
-               OO.EmitterList.call( this );
-
-               this.default = config.default;
-               this.filtersModel = filtersModel;
-               this.converted = false;
-
-               // Events
-               this.aggregate( { update: 'itemUpdate' } );
-       };
-
-       /* Initialization */
-
-       OO.initClass( SavedQueriesModel );
-       OO.mixinClass( SavedQueriesModel, OO.EventEmitter );
-       OO.mixinClass( SavedQueriesModel, OO.EmitterList );
-
-       /* Events */
-
-       /**
-        * @event initialize
-        *
-        * Model is initialized
-        */
-
-       /**
-        * @event itemUpdate
-        * @param {mw.rcfilters.dm.SavedQueryItemModel} Changed item
-        *
-        * An item has changed
-        */
-
-       /**
-        * @event default
-        * @param {string} New default ID
-        *
-        * The default has changed
-        */
-
-       /* Methods */
-
-       /**
-        * Initialize the saved queries model by reading it from the user's settings.
-        * The structure of the saved queries is:
-        * {
-        *    version: (string) Version number; if version 2, the query represents
-        *             parameters. Otherwise, the older version represented filters
-        *             and needs to be readjusted,
-        *    default: (string) Query ID
-        *    queries:{
-        *       query_id_1: {
-        *          data:{
-        *             filters: (Object) Minimal definition of the filters
-        *             highlights: (Object) Definition of the highlights
-        *          },
-        *          label: (optional) Name of this query
-        *       }
-        *    }
-        * }
-        *
-        * @param {Object} [savedQueries] An object with the saved queries with
-        *  the above structure.
-        * @fires initialize
-        */
-       SavedQueriesModel.prototype.initialize = function ( savedQueries ) {
-               var model = this;
-
-               savedQueries = savedQueries || {};
-
-               this.clearItems();
-               this.default = null;
-               this.converted = false;
-
-               if ( savedQueries.version !== '2' ) {
-                       // Old version dealt with filter names. We need to migrate to the new structure
-                       // The new structure:
-                       // {
-                       //   version: (string) '2',
-                       //   default: (string) Query ID,
-                       //   queries: {
-                       //     query_id: {
-                       //       label: (string) Name of the query
-                       //       data: {
-                       //         params: (object) Representing all the parameter states
-                       //         highlights: (object) Representing all the filter highlight states
-                       //     }
-                       //   }
-                       // }
-                       // eslint-disable-next-line no-jquery/no-each-util
-                       $.each( savedQueries.queries || {}, function ( id, obj ) {
-                               if ( obj.data && obj.data.filters ) {
-                                       obj.data = model.convertToParameters( obj.data );
-                               }
-                       } );
-
-                       this.converted = true;
-                       savedQueries.version = '2';
-               }
-
-               // Initialize the query items
+var SavedQueryItemModel = require( './SavedQueryItemModel.js' ),
+       SavedQueriesModel;
+
+/**
+ * View model for saved queries
+ *
+ * @class mw.rcfilters.dm.SavedQueriesModel
+ * @mixins OO.EventEmitter
+ * @mixins OO.EmitterList
+ *
+ * @constructor
+ * @param {mw.rcfilters.dm.FiltersViewModel} filtersModel Filters model
+ * @param {Object} [config] Configuration options
+ * @cfg {string} [default] Default query ID
+ */
+SavedQueriesModel = function MwRcfiltersDmSavedQueriesModel( filtersModel, config ) {
+       config = config || {};
+
+       // Mixin constructor
+       OO.EventEmitter.call( this );
+       OO.EmitterList.call( this );
+
+       this.default = config.default;
+       this.filtersModel = filtersModel;
+       this.converted = false;
+
+       // Events
+       this.aggregate( { update: 'itemUpdate' } );
+};
+
+/* Initialization */
+
+OO.initClass( SavedQueriesModel );
+OO.mixinClass( SavedQueriesModel, OO.EventEmitter );
+OO.mixinClass( SavedQueriesModel, OO.EmitterList );
+
+/* Events */
+
+/**
+ * @event initialize
+ *
+ * Model is initialized
+ */
+
+/**
+ * @event itemUpdate
+ * @param {mw.rcfilters.dm.SavedQueryItemModel} Changed item
+ *
+ * An item has changed
+ */
+
+/**
+ * @event default
+ * @param {string} New default ID
+ *
+ * The default has changed
+ */
+
+/* Methods */
+
+/**
+ * Initialize the saved queries model by reading it from the user's settings.
+ * The structure of the saved queries is:
+ * {
+ *    version: (string) Version number; if version 2, the query represents
+ *             parameters. Otherwise, the older version represented filters
+ *             and needs to be readjusted,
+ *    default: (string) Query ID
+ *    queries:{
+ *       query_id_1: {
+ *          data:{
+ *             filters: (Object) Minimal definition of the filters
+ *             highlights: (Object) Definition of the highlights
+ *          },
+ *          label: (optional) Name of this query
+ *       }
+ *    }
+ * }
+ *
+ * @param {Object} [savedQueries] An object with the saved queries with
+ *  the above structure.
+ * @fires initialize
+ */
+SavedQueriesModel.prototype.initialize = function ( savedQueries ) {
+       var model = this;
+
+       savedQueries = savedQueries || {};
+
+       this.clearItems();
+       this.default = null;
+       this.converted = false;
+
+       if ( savedQueries.version !== '2' ) {
+               // Old version dealt with filter names. We need to migrate to the new structure
+               // The new structure:
+               // {
+               //   version: (string) '2',
+               //   default: (string) Query ID,
+               //   queries: {
+               //     query_id: {
+               //       label: (string) Name of the query
+               //       data: {
+               //         params: (object) Representing all the parameter states
+               //         highlights: (object) Representing all the filter highlight states
+               //     }
+               //   }
+               // }
                // eslint-disable-next-line no-jquery/no-each-util
                $.each( savedQueries.queries || {}, function ( id, obj ) {
-                       var normalizedData = obj.data,
-                               isDefault = String( savedQueries.default ) === String( id );
-
-                       if ( normalizedData && normalizedData.params ) {
-                               // Backwards-compat fix: Remove sticky parameters from
-                               // the given data, if they exist
-                               normalizedData.params = model.filtersModel.removeStickyParams( normalizedData.params );
-
-                               // Correct the invert state for effective selection
-                               if ( normalizedData.params.invert && !normalizedData.params.namespace ) {
-                                       delete normalizedData.params.invert;
-                               }
-
-                               model.cleanupHighlights( normalizedData );
-
-                               id = String( id );
-
-                               // Skip the addNewQuery method because we don't want to unnecessarily manipulate
-                               // the given saved queries unless we literally intend to (like in backwards compat fixes)
-                               // And the addNewQuery method also uses a minimization routine that checks for the
-                               // validity of items and minimizes the query. This isn't necessary for queries loaded
-                               // from the backend, and has the risk of removing values if they're temporarily
-                               // invalid (example: if we temporarily removed a cssClass from a filter in the backend)
-                               model.addItems( [
-                                       new SavedQueryItemModel(
-                                               id,
-                                               obj.label,
-                                               normalizedData,
-                                               { default: isDefault }
-                                       )
-                               ] );
-
-                               if ( isDefault ) {
-                                       model.default = id;
-                               }
+                       if ( obj.data && obj.data.filters ) {
+                               obj.data = model.convertToParameters( obj.data );
                        }
                } );
 
-               this.emit( 'initialize' );
-       };
-
-       /**
-        * Clean up highlight parameters.
-        * 'highlight' used to be stored, it's not inferred based on the presence of absence of
-        * filter colors.
-        *
-        * @param {Object} data Saved query data
-        */
-       SavedQueriesModel.prototype.cleanupHighlights = function ( data ) {
-               if (
-                       data.params.highlight === '0' &&
-                       data.highlights && Object.keys( data.highlights ).length
-               ) {
-                       data.highlights = {};
-               }
-               delete data.params.highlight;
-       };
-
-       /**
-        * Convert from representation of filters to representation of parameters
-        *
-        * @param {Object} data Query data
-        * @return {Object} New converted query data
-        */
-       SavedQueriesModel.prototype.convertToParameters = function ( data ) {
-               var newData = {},
-                       defaultFilters = this.filtersModel.getFiltersFromParameters( this.filtersModel.getDefaultParams() ),
-                       fullFilterRepresentation = $.extend( true, {}, defaultFilters, data.filters ),
-                       highlightEnabled = data.highlights.highlight;
-
-               delete data.highlights.highlight;
-
-               // Filters
-               newData.params = this.filtersModel.getMinimizedParamRepresentation(
-                       this.filtersModel.getParametersFromFilters( fullFilterRepresentation )
-               );
+               this.converted = true;
+               savedQueries.version = '2';
+       }
 
-               // Highlights: appending _color to keys
-               newData.highlights = {};
-               // eslint-disable-next-line no-jquery/no-each-util
-               $.each( data.highlights, function ( highlightedFilterName, value ) {
-                       if ( value ) {
-                               newData.highlights[ highlightedFilterName + '_color' ] = data.highlights[ highlightedFilterName ];
-                       }
-               } );
+       // Initialize the query items
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( savedQueries.queries || {}, function ( id, obj ) {
+               var normalizedData = obj.data,
+                       isDefault = String( savedQueries.default ) === String( id );
 
-               // Add highlight
-               newData.params.highlight = String( Number( highlightEnabled || 0 ) );
-
-               return newData;
-       };
-
-       /**
-        * Add a query item
-        *
-        * @param {string} label Label for the new query
-        * @param {Object} fulldata Full data representation for the new query, combining highlights and filters
-        * @param {boolean} isDefault Item is default
-        * @param {string} [id] Query ID, if exists. If this isn't given, a random
-        *  new ID will be created.
-        * @return {string} ID of the newly added query
-        */
-       SavedQueriesModel.prototype.addNewQuery = function ( label, fulldata, isDefault, id ) {
-               var normalizedData = { params: {}, highlights: {} },
-                       highlightParamNames = Object.keys( this.filtersModel.getEmptyHighlightParameters() ),
-                       randomID = String( id || ( new Date() ).getTime() ),
-                       data = this.filtersModel.getMinimizedParamRepresentation( fulldata );
-
-               // Split highlight/params
-               // eslint-disable-next-line no-jquery/no-each-util
-               $.each( data, function ( param, value ) {
-                       if ( param !== 'highlight' && highlightParamNames.indexOf( param ) > -1 ) {
-                               normalizedData.highlights[ param ] = value;
-                       } else {
-                               normalizedData.params[ param ] = value;
+               if ( normalizedData && normalizedData.params ) {
+                       // Backwards-compat fix: Remove sticky parameters from
+                       // the given data, if they exist
+                       normalizedData.params = model.filtersModel.removeStickyParams( normalizedData.params );
+
+                       // Correct the invert state for effective selection
+                       if ( normalizedData.params.invert && !normalizedData.params.namespace ) {
+                               delete normalizedData.params.invert;
                        }
-               } );
 
-               // Correct the invert state for effective selection
-               if ( normalizedData.params.invert && !this.filtersModel.areNamespacesEffectivelyInverted() ) {
-                       delete normalizedData.params.invert;
+                       model.cleanupHighlights( normalizedData );
+
+                       id = String( id );
+
+                       // Skip the addNewQuery method because we don't want to unnecessarily manipulate
+                       // the given saved queries unless we literally intend to (like in backwards compat fixes)
+                       // And the addNewQuery method also uses a minimization routine that checks for the
+                       // validity of items and minimizes the query. This isn't necessary for queries loaded
+                       // from the backend, and has the risk of removing values if they're temporarily
+                       // invalid (example: if we temporarily removed a cssClass from a filter in the backend)
+                       model.addItems( [
+                               new SavedQueryItemModel(
+                                       id,
+                                       obj.label,
+                                       normalizedData,
+                                       { default: isDefault }
+                               )
+                       ] );
+
+                       if ( isDefault ) {
+                               model.default = id;
+                       }
                }
-
-               // Add item
-               this.addItems( [
-                       new SavedQueryItemModel(
-                               randomID,
-                               label,
-                               normalizedData,
-                               { default: isDefault }
-                       )
-               ] );
-
-               if ( isDefault ) {
-                       this.setDefault( randomID );
+       } );
+
+       this.emit( 'initialize' );
+};
+
+/**
+ * Clean up highlight parameters.
+ * 'highlight' used to be stored, it's not inferred based on the presence of absence of
+ * filter colors.
+ *
+ * @param {Object} data Saved query data
+ */
+SavedQueriesModel.prototype.cleanupHighlights = function ( data ) {
+       if (
+               data.params.highlight === '0' &&
+               data.highlights && Object.keys( data.highlights ).length
+       ) {
+               data.highlights = {};
+       }
+       delete data.params.highlight;
+};
+
+/**
+ * Convert from representation of filters to representation of parameters
+ *
+ * @param {Object} data Query data
+ * @return {Object} New converted query data
+ */
+SavedQueriesModel.prototype.convertToParameters = function ( data ) {
+       var newData = {},
+               defaultFilters = this.filtersModel.getFiltersFromParameters( this.filtersModel.getDefaultParams() ),
+               fullFilterRepresentation = $.extend( true, {}, defaultFilters, data.filters ),
+               highlightEnabled = data.highlights.highlight;
+
+       delete data.highlights.highlight;
+
+       // Filters
+       newData.params = this.filtersModel.getMinimizedParamRepresentation(
+               this.filtersModel.getParametersFromFilters( fullFilterRepresentation )
+       );
+
+       // Highlights: appending _color to keys
+       newData.highlights = {};
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( data.highlights, function ( highlightedFilterName, value ) {
+               if ( value ) {
+                       newData.highlights[ highlightedFilterName + '_color' ] = data.highlights[ highlightedFilterName ];
                }
-
-               return randomID;
-       };
-
-       /**
-        * Remove query from model
-        *
-        * @param {string} queryID Query ID
-        */
-       SavedQueriesModel.prototype.removeQuery = function ( queryID ) {
-               var query = this.getItemByID( queryID );
-
-               if ( query ) {
-                       // Check if this item was the default
-                       if ( String( this.getDefault() ) === String( queryID ) ) {
-                               // Nulify the default
-                               this.setDefault( null );
-                       }
-
-                       this.removeItems( [ query ] );
+       } );
+
+       // Add highlight
+       newData.params.highlight = String( Number( highlightEnabled || 0 ) );
+
+       return newData;
+};
+
+/**
+ * Add a query item
+ *
+ * @param {string} label Label for the new query
+ * @param {Object} fulldata Full data representation for the new query, combining highlights and filters
+ * @param {boolean} isDefault Item is default
+ * @param {string} [id] Query ID, if exists. If this isn't given, a random
+ *  new ID will be created.
+ * @return {string} ID of the newly added query
+ */
+SavedQueriesModel.prototype.addNewQuery = function ( label, fulldata, isDefault, id ) {
+       var normalizedData = { params: {}, highlights: {} },
+               highlightParamNames = Object.keys( this.filtersModel.getEmptyHighlightParameters() ),
+               randomID = String( id || ( new Date() ).getTime() ),
+               data = this.filtersModel.getMinimizedParamRepresentation( fulldata );
+
+       // Split highlight/params
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( data, function ( param, value ) {
+               if ( param !== 'highlight' && highlightParamNames.indexOf( param ) > -1 ) {
+                       normalizedData.highlights[ param ] = value;
+               } else {
+                       normalizedData.params[ param ] = value;
                }
-       };
-
-       /**
-        * Get an item that matches the requested query
-        *
-        * @param {Object} fullQueryComparison Object representing all filters and highlights to compare
-        * @return {mw.rcfilters.dm.SavedQueryItemModel} Matching item model
-        */
-       SavedQueriesModel.prototype.findMatchingQuery = function ( fullQueryComparison ) {
-               // Minimize before comparison
-               fullQueryComparison = this.filtersModel.getMinimizedParamRepresentation( fullQueryComparison );
-
-               // Correct the invert state for effective selection
-               if ( fullQueryComparison.invert && !this.filtersModel.areNamespacesEffectivelyInverted() ) {
-                       delete fullQueryComparison.invert;
+       } );
+
+       // Correct the invert state for effective selection
+       if ( normalizedData.params.invert && !this.filtersModel.areNamespacesEffectivelyInverted() ) {
+               delete normalizedData.params.invert;
+       }
+
+       // Add item
+       this.addItems( [
+               new SavedQueryItemModel(
+                       randomID,
+                       label,
+                       normalizedData,
+                       { default: isDefault }
+               )
+       ] );
+
+       if ( isDefault ) {
+               this.setDefault( randomID );
+       }
+
+       return randomID;
+};
+
+/**
+ * Remove query from model
+ *
+ * @param {string} queryID Query ID
+ */
+SavedQueriesModel.prototype.removeQuery = function ( queryID ) {
+       var query = this.getItemByID( queryID );
+
+       if ( query ) {
+               // Check if this item was the default
+               if ( String( this.getDefault() ) === String( queryID ) ) {
+                       // Nulify the default
+                       this.setDefault( null );
                }
 
-               return this.getItems().filter( function ( item ) {
-                       return OO.compare(
-                               item.getCombinedData(),
-                               fullQueryComparison
-                       );
-               } )[ 0 ];
-       };
-
-       /**
-        * Get query by its identifier
-        *
-        * @param {string} queryID Query identifier
-        * @return {mw.rcfilters.dm.SavedQueryItemModel|undefined} Item matching
-        *  the search. Undefined if not found.
-        */
-       SavedQueriesModel.prototype.getItemByID = function ( queryID ) {
-               return this.getItems().filter( function ( item ) {
-                       return item.getID() === queryID;
-               } )[ 0 ];
-       };
-
-       /**
-        * Get the full data representation of the default query, if it exists
-        *
-        * @return {Object|null} Representation of the default params if exists.
-        *  Null if default doesn't exist or if the user is not logged in.
-        */
-       SavedQueriesModel.prototype.getDefaultParams = function () {
-               return ( !mw.user.isAnon() && this.getItemParams( this.getDefault() ) ) || {};
-       };
-
-       /**
-        * Get a full parameter representation of an item data
-        *
-        * @param  {Object} queryID Query ID
-        * @return {Object} Parameter representation
-        */
-       SavedQueriesModel.prototype.getItemParams = function ( queryID ) {
-               var item = this.getItemByID( queryID ),
-                       data = item ? item.getData() : {};
-
-               return !$.isEmptyObject( data ) ? this.buildParamsFromData( data ) : {};
-       };
-
-       /**
-        * Build a full parameter representation given item data and model sticky values state
-        *
-        * @param  {Object} data Item data
-        * @return {Object} Full param representation
-        */
-       SavedQueriesModel.prototype.buildParamsFromData = function ( data ) {
-               data = data || {};
-               // Return parameter representation
-               return this.filtersModel.getMinimizedParamRepresentation( $.extend( true, {},
-                       data.params,
-                       data.highlights
-               ) );
-       };
-
-       /**
-        * Get the object representing the state of the entire model and items
-        *
-        * @return {Object} Object representing the state of the model and items
-        */
-       SavedQueriesModel.prototype.getState = function () {
-               var obj = { queries: {}, version: '2' };
-
-               // Translate the items to the saved object
+               this.removeItems( [ query ] );
+       }
+};
+
+/**
+ * Get an item that matches the requested query
+ *
+ * @param {Object} fullQueryComparison Object representing all filters and highlights to compare
+ * @return {mw.rcfilters.dm.SavedQueryItemModel} Matching item model
+ */
+SavedQueriesModel.prototype.findMatchingQuery = function ( fullQueryComparison ) {
+       // Minimize before comparison
+       fullQueryComparison = this.filtersModel.getMinimizedParamRepresentation( fullQueryComparison );
+
+       // Correct the invert state for effective selection
+       if ( fullQueryComparison.invert && !this.filtersModel.areNamespacesEffectivelyInverted() ) {
+               delete fullQueryComparison.invert;
+       }
+
+       return this.getItems().filter( function ( item ) {
+               return OO.compare(
+                       item.getCombinedData(),
+                       fullQueryComparison
+               );
+       } )[ 0 ];
+};
+
+/**
+ * Get query by its identifier
+ *
+ * @param {string} queryID Query identifier
+ * @return {mw.rcfilters.dm.SavedQueryItemModel|undefined} Item matching
+ *  the search. Undefined if not found.
+ */
+SavedQueriesModel.prototype.getItemByID = function ( queryID ) {
+       return this.getItems().filter( function ( item ) {
+               return item.getID() === queryID;
+       } )[ 0 ];
+};
+
+/**
+ * Get the full data representation of the default query, if it exists
+ *
+ * @return {Object|null} Representation of the default params if exists.
+ *  Null if default doesn't exist or if the user is not logged in.
+ */
+SavedQueriesModel.prototype.getDefaultParams = function () {
+       return ( !mw.user.isAnon() && this.getItemParams( this.getDefault() ) ) || {};
+};
+
+/**
+ * Get a full parameter representation of an item data
+ *
+ * @param  {Object} queryID Query ID
+ * @return {Object} Parameter representation
+ */
+SavedQueriesModel.prototype.getItemParams = function ( queryID ) {
+       var item = this.getItemByID( queryID ),
+               data = item ? item.getData() : {};
+
+       return !$.isEmptyObject( data ) ? this.buildParamsFromData( data ) : {};
+};
+
+/**
+ * Build a full parameter representation given item data and model sticky values state
+ *
+ * @param  {Object} data Item data
+ * @return {Object} Full param representation
+ */
+SavedQueriesModel.prototype.buildParamsFromData = function ( data ) {
+       data = data || {};
+       // Return parameter representation
+       return this.filtersModel.getMinimizedParamRepresentation( $.extend( true, {},
+               data.params,
+               data.highlights
+       ) );
+};
+
+/**
+ * Get the object representing the state of the entire model and items
+ *
+ * @return {Object} Object representing the state of the model and items
+ */
+SavedQueriesModel.prototype.getState = function () {
+       var obj = { queries: {}, version: '2' };
+
+       // Translate the items to the saved object
+       this.getItems().forEach( function ( item ) {
+               obj.queries[ item.getID() ] = item.getState();
+       } );
+
+       if ( this.getDefault() ) {
+               obj.default = this.getDefault();
+       }
+
+       return obj;
+};
+
+/**
+ * Set a default query. Null to unset default.
+ *
+ * @param {string} itemID Query identifier
+ * @fires default
+ */
+SavedQueriesModel.prototype.setDefault = function ( itemID ) {
+       if ( this.default !== itemID ) {
+               this.default = itemID;
+
+               // Set for individual itens
                this.getItems().forEach( function ( item ) {
-                       obj.queries[ item.getID() ] = item.getState();
+                       item.toggleDefault( item.getID() === itemID );
                } );
 
-               if ( this.getDefault() ) {
-                       obj.default = this.getDefault();
-               }
-
-               return obj;
-       };
-
-       /**
-        * Set a default query. Null to unset default.
-        *
-        * @param {string} itemID Query identifier
-        * @fires default
-        */
-       SavedQueriesModel.prototype.setDefault = function ( itemID ) {
-               if ( this.default !== itemID ) {
-                       this.default = itemID;
-
-                       // Set for individual itens
-                       this.getItems().forEach( function ( item ) {
-                               item.toggleDefault( item.getID() === itemID );
-                       } );
-
-                       this.emit( 'default', itemID );
-               }
-       };
-
-       /**
-        * Get the default query ID
-        *
-        * @return {string} Default query identifier
-        */
-       SavedQueriesModel.prototype.getDefault = function () {
-               return this.default;
-       };
-
-       /**
-        * Check if the saved queries were converted
-        *
-        * @return {boolean} Saved queries were converted from the previous
-        *  version to the new version
-        */
-       SavedQueriesModel.prototype.isConverted = function () {
-               return this.converted;
-       };
-
-       module.exports = SavedQueriesModel;
-}() );
+               this.emit( 'default', itemID );
+       }
+};
+
+/**
+ * Get the default query ID
+ *
+ * @return {string} Default query identifier
+ */
+SavedQueriesModel.prototype.getDefault = function () {
+       return this.default;
+};
+
+/**
+ * Check if the saved queries were converted
+ *
+ * @return {boolean} Saved queries were converted from the previous
+ *  version to the new version
+ */
+SavedQueriesModel.prototype.isConverted = function () {
+       return this.converted;
+};
+
+module.exports = SavedQueriesModel;
index 1774391..27e93e3 100644 (file)
-( function () {
-       /**
-        * View model for a single saved query
-        *
-        * @class mw.rcfilters.dm.SavedQueryItemModel
-        * @mixins OO.EventEmitter
-        *
-        * @constructor
-        * @param {string} id Unique identifier
-        * @param {string} label Saved query label
-        * @param {Object} data Saved query data
-        * @param {Object} [config] Configuration options
-        * @cfg {boolean} [default] This item is the default
-        */
-       var SavedQueryItemModel = function MwRcfiltersDmSavedQueriesModel( id, label, data, config ) {
-               config = config || {};
-
-               // Mixin constructor
-               OO.EventEmitter.call( this );
-
-               this.id = id;
-               this.label = label;
-               this.data = data;
-               this.default = !!config.default;
+/**
+ * View model for a single saved query
+ *
+ * @class mw.rcfilters.dm.SavedQueryItemModel
+ * @mixins OO.EventEmitter
+ *
+ * @constructor
+ * @param {string} id Unique identifier
+ * @param {string} label Saved query label
+ * @param {Object} data Saved query data
+ * @param {Object} [config] Configuration options
+ * @cfg {boolean} [default] This item is the default
+ */
+var SavedQueryItemModel = function MwRcfiltersDmSavedQueriesModel( id, label, data, config ) {
+       config = config || {};
+
+       // Mixin constructor
+       OO.EventEmitter.call( this );
+
+       this.id = id;
+       this.label = label;
+       this.data = data;
+       this.default = !!config.default;
+};
+
+/* Initialization */
+
+OO.initClass( SavedQueryItemModel );
+OO.mixinClass( SavedQueryItemModel, OO.EventEmitter );
+
+/* Events */
+
+/**
+ * @event update
+ *
+ * Model has been updated
+ */
+
+/* Methods */
+
+/**
+ * Get an object representing the state of this item
+ *
+ * @return {Object} Object representing the current data state
+ *  of the object
+ */
+SavedQueryItemModel.prototype.getState = function () {
+       return {
+               data: this.getData(),
+               label: this.getLabel()
        };
-
-       /* Initialization */
-
-       OO.initClass( SavedQueryItemModel );
-       OO.mixinClass( SavedQueryItemModel, OO.EventEmitter );
-
-       /* Events */
-
-       /**
-        * @event update
-        *
-        * Model has been updated
-        */
-
-       /* Methods */
-
-       /**
-        * Get an object representing the state of this item
-        *
-        * @return {Object} Object representing the current data state
-        *  of the object
-        */
-       SavedQueryItemModel.prototype.getState = function () {
-               return {
-                       data: this.getData(),
-                       label: this.getLabel()
-               };
-       };
-
-       /**
-        * Get the query's identifier
-        *
-        * @return {string} Query identifier
-        */
-       SavedQueryItemModel.prototype.getID = function () {
-               return this.id;
-       };
-
-       /**
-        * Get query label
-        *
-        * @return {string} Query label
-        */
-       SavedQueryItemModel.prototype.getLabel = function () {
-               return this.label;
-       };
-
-       /**
-        * Update the query label
-        *
-        * @param {string} newLabel New label
-        */
-       SavedQueryItemModel.prototype.updateLabel = function ( newLabel ) {
-               if ( newLabel && this.label !== newLabel ) {
-                       this.label = newLabel;
-                       this.emit( 'update' );
-               }
-       };
-
-       /**
-        * Get query data
-        *
-        * @return {Object} Object representing parameter and highlight data
-        */
-       SavedQueryItemModel.prototype.getData = function () {
-               return this.data;
-       };
-
-       /**
-        * Get the combined data of this item as a flat object of parameters
-        *
-        * @return {Object} Combined parameter data
-        */
-       SavedQueryItemModel.prototype.getCombinedData = function () {
-               return $.extend( true, {}, this.data.params, this.data.highlights );
-       };
-
-       /**
-        * Check whether this item is the default
-        *
-        * @return {boolean} Query is set to be default
-        */
-       SavedQueryItemModel.prototype.isDefault = function () {
-               return this.default;
-       };
-
-       /**
-        * Toggle the default state of this query item
-        *
-        * @param {boolean} isDefault Query is default
-        */
-       SavedQueryItemModel.prototype.toggleDefault = function ( isDefault ) {
-               isDefault = isDefault === undefined ? !this.default : isDefault;
-
-               if ( this.default !== isDefault ) {
-                       this.default = isDefault;
-                       this.emit( 'update' );
-               }
-       };
-
-       module.exports = SavedQueryItemModel;
-}() );
+};
+
+/**
+ * Get the query's identifier
+ *
+ * @return {string} Query identifier
+ */
+SavedQueryItemModel.prototype.getID = function () {
+       return this.id;
+};
+
+/**
+ * Get query label
+ *
+ * @return {string} Query label
+ */
+SavedQueryItemModel.prototype.getLabel = function () {
+       return this.label;
+};
+
+/**
+ * Update the query label
+ *
+ * @param {string} newLabel New label
+ */
+SavedQueryItemModel.prototype.updateLabel = function ( newLabel ) {
+       if ( newLabel && this.label !== newLabel ) {
+               this.label = newLabel;
+               this.emit( 'update' );
+       }
+};
+
+/**
+ * Get query data
+ *
+ * @return {Object} Object representing parameter and highlight data
+ */
+SavedQueryItemModel.prototype.getData = function () {
+       return this.data;
+};
+
+/**
+ * Get the combined data of this item as a flat object of parameters
+ *
+ * @return {Object} Combined parameter data
+ */
+SavedQueryItemModel.prototype.getCombinedData = function () {
+       return $.extend( true, {}, this.data.params, this.data.highlights );
+};
+
+/**
+ * Check whether this item is the default
+ *
+ * @return {boolean} Query is set to be default
+ */
+SavedQueryItemModel.prototype.isDefault = function () {
+       return this.default;
+};
+
+/**
+ * Toggle the default state of this query item
+ *
+ * @param {boolean} isDefault Query is default
+ */
+SavedQueryItemModel.prototype.toggleDefault = function ( isDefault ) {
+       isDefault = isDefault === undefined ? !this.default : isDefault;
+
+       if ( this.default !== isDefault ) {
+               this.default = isDefault;
+               this.emit( 'update' );
+       }
+};
+
+module.exports = SavedQueryItemModel;
index a69dc55..0ba75fb 100644 (file)
 /*!
  * JavaScript for Special:RecentChanges
  */
-( function () {
-
-       mw.rcfilters.HighlightColors = require( './HighlightColors.js' );
-       mw.rcfilters.ui.MainWrapperWidget = require( './ui/MainWrapperWidget.js' );
-
-       /**
-        * Get list of namespaces and remove unused ones
-        *
-        * @member mw.rcfilters
-        * @private
-        *
-        * @param {Array} unusedNamespaces Names of namespaces to remove
-        * @return {Array} Filtered array of namespaces
-        */
-       function getNamespaces( unusedNamespaces ) {
-               var i, length, name, id,
-                       namespaceIds = mw.config.get( 'wgNamespaceIds' ),
-                       namespaces = mw.config.get( 'wgFormattedNamespaces' );
-
-               for ( i = 0, length = unusedNamespaces.length; i < length; i++ ) {
-                       name = unusedNamespaces[ i ];
-                       id = namespaceIds[ name.toLowerCase() ];
-                       delete namespaces[ id ];
-               }
-
-               return namespaces;
+mw.rcfilters.HighlightColors = require( './HighlightColors.js' );
+mw.rcfilters.ui.MainWrapperWidget = require( './ui/MainWrapperWidget.js' );
+
+/**
+ * Get list of namespaces and remove unused ones
+ *
+ * @member mw.rcfilters
+ * @private
+ *
+ * @param {Array} unusedNamespaces Names of namespaces to remove
+ * @return {Array} Filtered array of namespaces
+ */
+function getNamespaces( unusedNamespaces ) {
+       var i, length, name, id,
+               namespaceIds = mw.config.get( 'wgNamespaceIds' ),
+               namespaces = mw.config.get( 'wgFormattedNamespaces' );
+
+       for ( i = 0, length = unusedNamespaces.length; i < length; i++ ) {
+               name = unusedNamespaces[ i ];
+               id = namespaceIds[ name.toLowerCase() ];
+               delete namespaces[ id ];
        }
 
-       /**
-        * @member mw.rcfilters
-        * @private
-        */
-       function init() {
-               var $topSection,
-                       mainWrapperWidget,
-                       conditionalViews = {},
-                       $initialFieldset = $( 'fieldset.cloptions' ),
-                       savedQueriesPreferenceName = mw.config.get( 'wgStructuredChangeFiltersSavedQueriesPreferenceName' ),
-                       daysPreferenceName = mw.config.get( 'wgStructuredChangeFiltersDaysPreferenceName' ),
-                       limitPreferenceName = mw.config.get( 'wgStructuredChangeFiltersLimitPreferenceName' ),
-                       activeFiltersCollapsedName = mw.config.get( 'wgStructuredChangeFiltersCollapsedPreferenceName' ),
-                       initialCollapsedState = mw.config.get( 'wgStructuredChangeFiltersCollapsedState' ),
-                       filtersModel = new mw.rcfilters.dm.FiltersViewModel(),
-                       changesListModel = new mw.rcfilters.dm.ChangesListViewModel( $initialFieldset ),
-                       savedQueriesModel = new mw.rcfilters.dm.SavedQueriesModel( filtersModel ),
-                       specialPage = mw.config.get( 'wgCanonicalSpecialPageName' ),
-                       controller = new mw.rcfilters.Controller(
-                               filtersModel, changesListModel, savedQueriesModel,
-                               {
-                                       savedQueriesPreferenceName: savedQueriesPreferenceName,
-                                       daysPreferenceName: daysPreferenceName,
-                                       limitPreferenceName: limitPreferenceName,
-                                       collapsedPreferenceName: activeFiltersCollapsedName,
-                                       normalizeTarget: specialPage === 'Recentchangeslinked'
-                               }
-                       );
-
-               // TODO: The changesListWrapperWidget should be able to initialize
-               // after the model is ready.
-
-               if ( specialPage === 'Recentchanges' ) {
-                       $topSection = $( '.mw-recentchanges-toplinks' ).detach();
-               } else if ( specialPage === 'Watchlist' ) {
-                       $( '#contentSub, form#mw-watchlist-resetbutton' ).remove();
-                       $topSection = $( '.watchlistDetails' ).detach().contents();
-               } else if ( specialPage === 'Recentchangeslinked' ) {
-                       conditionalViews.recentChangesLinked = {
-                               groups: [
-                                       {
-                                               name: 'page',
-                                               type: 'any_value',
-                                               title: '',
-                                               hidden: true,
-                                               sticky: true,
-                                               filters: [
-                                                       {
-                                                               name: 'target',
-                                                               default: ''
-                                                       }
-                                               ]
-                                       },
-                                       {
-                                               name: 'toOrFrom',
-                                               type: 'boolean',
-                                               title: '',
-                                               hidden: true,
-                                               sticky: true,
-                                               filters: [
-                                                       {
-                                                               name: 'showlinkedto',
-                                                               default: false
-                                                       }
-                                               ]
-                                       }
-                               ]
-                       };
-               }
+       return namespaces;
+}
 
-               mainWrapperWidget = new mw.rcfilters.ui.MainWrapperWidget(
-                       controller,
-                       filtersModel,
-                       savedQueriesModel,
-                       changesListModel,
+/**
+ * @member mw.rcfilters
+ * @private
+ */
+function init() {
+       var $topSection,
+               mainWrapperWidget,
+               conditionalViews = {},
+               $initialFieldset = $( 'fieldset.cloptions' ),
+               savedQueriesPreferenceName = mw.config.get( 'wgStructuredChangeFiltersSavedQueriesPreferenceName' ),
+               daysPreferenceName = mw.config.get( 'wgStructuredChangeFiltersDaysPreferenceName' ),
+               limitPreferenceName = mw.config.get( 'wgStructuredChangeFiltersLimitPreferenceName' ),
+               activeFiltersCollapsedName = mw.config.get( 'wgStructuredChangeFiltersCollapsedPreferenceName' ),
+               initialCollapsedState = mw.config.get( 'wgStructuredChangeFiltersCollapsedState' ),
+               filtersModel = new mw.rcfilters.dm.FiltersViewModel(),
+               changesListModel = new mw.rcfilters.dm.ChangesListViewModel( $initialFieldset ),
+               savedQueriesModel = new mw.rcfilters.dm.SavedQueriesModel( filtersModel ),
+               specialPage = mw.config.get( 'wgCanonicalSpecialPageName' ),
+               controller = new mw.rcfilters.Controller(
+                       filtersModel, changesListModel, savedQueriesModel,
                        {
-                               $wrapper: $( 'body' ),
-                               $topSection: $topSection,
-                               $filtersContainer: $( '.rcfilters-container' ),
-                               $changesListContainer: $( '.mw-changeslist, .mw-changeslist-empty' ),
-                               $formContainer: $initialFieldset,
-                               collapsed: initialCollapsedState
+                               savedQueriesPreferenceName: savedQueriesPreferenceName,
+                               daysPreferenceName: daysPreferenceName,
+                               limitPreferenceName: limitPreferenceName,
+                               collapsedPreferenceName: activeFiltersCollapsedName,
+                               normalizeTarget: specialPage === 'Recentchangeslinked'
                        }
                );
 
-               // Remove the -loading class that may have been added on the server side.
-               // If we are in fact going to load a default saved query, this .initialize()
-               // call will do that and add the -loading class right back.
-               $( 'body' ).removeClass( 'mw-rcfilters-ui-loading' );
-
-               controller.initialize(
-                       mw.config.get( 'wgStructuredChangeFilters' ),
-                       // All namespaces without Media namespace
-                       getNamespaces( [ 'Media' ] ),
-                       require( './config.json' ).RCFiltersChangeTags,
-                       conditionalViews
-               );
+       // TODO: The changesListWrapperWidget should be able to initialize
+       // after the model is ready.
+
+       if ( specialPage === 'Recentchanges' ) {
+               $topSection = $( '.mw-recentchanges-toplinks' ).detach();
+       } else if ( specialPage === 'Watchlist' ) {
+               $( '#contentSub, form#mw-watchlist-resetbutton' ).remove();
+               $topSection = $( '.watchlistDetails' ).detach().contents();
+       } else if ( specialPage === 'Recentchangeslinked' ) {
+               conditionalViews.recentChangesLinked = {
+                       groups: [
+                               {
+                                       name: 'page',
+                                       type: 'any_value',
+                                       title: '',
+                                       hidden: true,
+                                       sticky: true,
+                                       filters: [
+                                               {
+                                                       name: 'target',
+                                                       default: ''
+                                               }
+                                       ]
+                               },
+                               {
+                                       name: 'toOrFrom',
+                                       type: 'boolean',
+                                       title: '',
+                                       hidden: true,
+                                       sticky: true,
+                                       filters: [
+                                               {
+                                                       name: 'showlinkedto',
+                                                       default: false
+                                               }
+                                       ]
+                               }
+                       ]
+               };
+       }
 
-               mainWrapperWidget.initFormWidget( specialPage );
+       mainWrapperWidget = new mw.rcfilters.ui.MainWrapperWidget(
+               controller,
+               filtersModel,
+               savedQueriesModel,
+               changesListModel,
+               {
+                       $wrapper: $( 'body' ),
+                       $topSection: $topSection,
+                       $filtersContainer: $( '.mw-rcfilters-container' ),
+                       $changesListContainer: $( '.mw-changeslist, .mw-changeslist-empty' ),
+                       $formContainer: $initialFieldset,
+                       collapsed: initialCollapsedState
+               }
+       );
 
-               $( 'a.mw-helplink' ).attr(
-                       'href',
-                       'https://www.mediawiki.org/wiki/Special:MyLanguage/Help:New_filters_for_edit_review'
-               );
+       // Remove the -loading class that may have been added on the server side.
+       // If we are in fact going to load a default saved query, this .initialize()
+       // call will do that and add the -loading class right back.
+       $( 'body' ).removeClass( 'mw-rcfilters-ui-loading' );
 
-               controller.replaceUrl();
+       controller.initialize(
+               mw.config.get( 'wgStructuredChangeFilters' ),
+               // All namespaces without Media namespace
+               getNamespaces( [ 'Media' ] ),
+               require( './config.json' ).RCFiltersChangeTags,
+               conditionalViews
+       );
 
-               mainWrapperWidget.setTopSection( specialPage );
+       mainWrapperWidget.initFormWidget( specialPage );
 
-               /**
-                * Fired when initialization of the filtering interface for changes list is complete.
-                *
-                * @event structuredChangeFilters_ui_initialized
-                * @member mw.hook
-                */
-               mw.hook( 'structuredChangeFilters.ui.initialized' ).fire();
-       }
+       $( 'a.mw-helplink' ).attr(
+               'href',
+               'https://www.mediawiki.org/wiki/Special:MyLanguage/Help:New_filters_for_edit_review'
+       );
 
-       // Import i18n messages from config
-       mw.messages.set( mw.config.get( 'wgStructuredChangeFiltersMessages' ) );
+       controller.replaceUrl();
 
-       // Early execute of init
-       if ( document.readyState === 'interactive' || document.readyState === 'complete' ) {
-               init();
-       } else {
-               $( init );
-       }
+       mainWrapperWidget.setTopSection( specialPage );
+
+       /**
+        * Fired when initialization of the filtering interface for changes list is complete.
+        *
+        * @event structuredChangeFilters_ui_initialized
+        * @member mw.hook
+        */
+       mw.hook( 'structuredChangeFilters.ui.initialized' ).fire();
+}
+
+// Import i18n messages from config
+mw.messages.set( mw.config.get( 'wgStructuredChangeFiltersMessages' ) );
 
-       module.exports = mw.rcfilters;
+// Early execute of init
+if ( document.readyState === 'interactive' || document.readyState === 'complete' ) {
+       init();
+} else {
+       $( init );
+}
 
-}() );
+module.exports = mw.rcfilters;
index b32fb38..5bf9916 100644 (file)
@@ -1,61 +1,59 @@
-( function () {
-       /**
-        * @class
-        * @singleton
-        */
-       mw.rcfilters = {
-               Controller: require( './Controller.js' ),
-               UriProcessor: require( './UriProcessor.js' ),
-               dm: {
-                       ChangesListViewModel: require( './dm/ChangesListViewModel.js' ),
-                       FilterGroup: require( './dm/FilterGroup.js' ),
-                       FilterItem: require( './dm/FilterItem.js' ),
-                       FiltersViewModel: require( './dm/FiltersViewModel.js' ),
-                       ItemModel: require( './dm/ItemModel.js' ),
-                       SavedQueriesModel: require( './dm/SavedQueriesModel.js' ),
-                       SavedQueryItemModel: require( './dm/SavedQueryItemModel.js' )
-               },
-               ui: {},
-               utils: {
-                       addArrayElementsUnique: function ( arr, elements ) {
-                               elements = Array.isArray( elements ) ? elements : [ elements ];
-
-                               elements.forEach( function ( element ) {
-                                       if ( arr.indexOf( element ) === -1 ) {
-                                               arr.push( element );
-                                       }
-                               } );
+/**
+ * @class
+ * @singleton
+ */
+mw.rcfilters = {
+       Controller: require( './Controller.js' ),
+       UriProcessor: require( './UriProcessor.js' ),
+       dm: {
+               ChangesListViewModel: require( './dm/ChangesListViewModel.js' ),
+               FilterGroup: require( './dm/FilterGroup.js' ),
+               FilterItem: require( './dm/FilterItem.js' ),
+               FiltersViewModel: require( './dm/FiltersViewModel.js' ),
+               ItemModel: require( './dm/ItemModel.js' ),
+               SavedQueriesModel: require( './dm/SavedQueriesModel.js' ),
+               SavedQueryItemModel: require( './dm/SavedQueryItemModel.js' )
+       },
+       ui: {},
+       utils: {
+               addArrayElementsUnique: function ( arr, elements ) {
+                       elements = Array.isArray( elements ) ? elements : [ elements ];
 
-                               return arr;
-                       },
-                       normalizeParamOptions: function ( givenOptions, legalOptions ) {
-                               var result = [];
-
-                               if ( givenOptions.indexOf( 'all' ) > -1 ) {
-                                       // If anywhere in the values there's 'all', we
-                                       // treat it as if only 'all' was selected.
-                                       // Example: param=valid1,valid2,all
-                                       // Result: param=all
-                                       return [ 'all' ];
+                       elements.forEach( function ( element ) {
+                               if ( arr.indexOf( element ) === -1 ) {
+                                       arr.push( element );
                                }
+                       } );
 
-                               // Get rid of any dupe and invalid parameter, only output
-                               // valid ones
-                               // Example: param=valid1,valid2,invalid1,valid1
-                               // Result: param=valid1,valid2
-                               givenOptions.forEach( function ( value ) {
-                                       if (
-                                               legalOptions.indexOf( value ) > -1 &&
-                                               result.indexOf( value ) === -1
-                                       ) {
-                                               result.push( value );
-                                       }
-                               } );
+                       return arr;
+               },
+               normalizeParamOptions: function ( givenOptions, legalOptions ) {
+                       var result = [];
 
-                               return result;
+                       if ( givenOptions.indexOf( 'all' ) > -1 ) {
+                               // If anywhere in the values there's 'all', we
+                               // treat it as if only 'all' was selected.
+                               // Example: param=valid1,valid2,all
+                               // Result: param=all
+                               return [ 'all' ];
                        }
+
+                       // Get rid of any dupe and invalid parameter, only output
+                       // valid ones
+                       // Example: param=valid1,valid2,invalid1,valid1
+                       // Result: param=valid1,valid2
+                       givenOptions.forEach( function ( value ) {
+                               if (
+                                       legalOptions.indexOf( value ) > -1 &&
+                                       result.indexOf( value ) === -1
+                               ) {
+                                       result.push( value );
+                               }
+                       } );
+
+                       return result;
                }
-       };
+       }
+};
 
-       module.exports = mw.rcfilters;
-}() );
+module.exports = mw.rcfilters;
index 689f322..d3fce46 100644 (file)
 
 // Corrections for the standard special page
 .client-js {
+       /* stylelint-disable-next-line selector-class-pattern */
        .cloptions {
                border: 0;
        }
 
        // Reserve space for the UI while it loads
-       .rcfilters-head {
+       .mw-rcfilters-head {
                min-height: @rcfilters-head-min-height;
                margin-bottom: @rcfilters-head-margin-bottom;
        }
 
        // On the watchlist, reserve a bit more
-       .mw-special-Watchlist .rcfilters-head {
+       .mw-special-Watchlist .mw-rcfilters-head {
                min-height: @rcfilters-wl-head-min-height;
        }
 
        .mw-rcfilters-collapsed {
-               .rcfilters-head {
+               .mw-rcfilters-head {
                        min-height: @rcfilters-head-min-height-collapsed;
                }
 
                // On the watchlist, reserve a bit more
-               &.mw-special-Watchlist .rcfilters-head {
+               &.mw-special-Watchlist .mw-rcfilters-head {
                        min-height: @rcfilters-wl-head-min-height-collapsed;
                }
        }
                        }
                }
 
-               .rcfilters-head {
+               .mw-rcfilters-head {
                        opacity: 0.5;
                        pointer-events: none;
 
+                       /* stylelint-disable-next-line selector-class-pattern */
                        .cloptions {
                                display: none;
                        }
                display: none;
        }
 
+       /* stylelint-disable-next-line selector-class-pattern */
        .errorbox {
                display: none;
        }
                opacity: 0.5;
        }
 
-       .rcfilters-spinner {
+       .mw-rcfilters-spinner {
                display: none;
                position: absolute;
                left: 50%;
                margin-left: -3 * @rcfilters-spinner-size / 2;
                white-space: nowrap;
 
-               & .rcfilters-spinner-bounce,
+               & .mw-rcfilters-spinner-bounce,
                &:before,
                &:after {
                        content: '';
                }
        }
 
-       body:not( .mw-rcfilters-ui-initialized ) .rcfilters-spinner {
+       body:not( .mw-rcfilters-ui-initialized ) .mw-rcfilters-spinner {
                display: block;
                // When initializing, display the spinner on top of the area where the UI will appear
                margin-top: -( @rcfilters-head-min-height + @rcfilters-head-margin-bottom ) / 1.5;
        }
 
-       body.mw-rcfilters-ui-loading .rcfilters-spinner {
+       body.mw-rcfilters-ui-loading .mw-rcfilters-spinner {
                display: block;
                // When loading new results, display the spinner on top of the results area
                margin-top: -( @rcfilters-head-min-height + @rcfilters-head-margin-bottom ) / 8;
 
        // Make the watchlist-details message display while loading, but make it not take up any
        // space. This makes the min-height trick work better.
+       /* stylelint-disable-next-line selector-class-pattern */
        .watchlistDetails {
                float: left;
                // The 20em should match the min-width we are setting up
index 23b05e8..ac5bbae 100644 (file)
-( function () {
-       var ChangesLimitPopupWidget = require( './ChangesLimitPopupWidget.js' ),
-               DatePopupWidget = require( './DatePopupWidget.js' ),
-               ChangesLimitAndDateButtonWidget;
-
-       /**
-        * Widget defining the button controlling the popup for the number of results
-        *
-        * @class mw.rcfilters.ui.ChangesLimitAndDateButtonWidget
-        * @extends OO.ui.Widget
-        *
-        * @constructor
-        * @param {mw.rcfilters.Controller} controller Controller
-        * @param {mw.rcfilters.dm.FiltersViewModel} model View model
-        * @param {Object} [config] Configuration object
-        * @cfg {jQuery} [$overlay] A jQuery object serving as overlay for popups
-        */
-       ChangesLimitAndDateButtonWidget = function MwRcfiltersUiChangesLimitWidget( controller, model, config ) {
-               config = config || {};
-
-               // Parent
-               ChangesLimitAndDateButtonWidget.parent.call( this, config );
-
-               this.controller = controller;
-               this.model = model;
-
-               this.$overlay = config.$overlay || this.$element;
-
-               this.button = null;
-               this.limitGroupModel = null;
-               this.groupByPageItemModel = null;
-               this.daysGroupModel = null;
-
-               this.model.connect( this, {
-                       initialize: 'onModelInitialize'
+var ChangesLimitPopupWidget = require( './ChangesLimitPopupWidget.js' ),
+       DatePopupWidget = require( './DatePopupWidget.js' ),
+       ChangesLimitAndDateButtonWidget;
+
+/**
+ * Widget defining the button controlling the popup for the number of results
+ *
+ * @class mw.rcfilters.ui.ChangesLimitAndDateButtonWidget
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller Controller
+ * @param {mw.rcfilters.dm.FiltersViewModel} model View model
+ * @param {Object} [config] Configuration object
+ * @cfg {jQuery} [$overlay] A jQuery object serving as overlay for popups
+ */
+ChangesLimitAndDateButtonWidget = function MwRcfiltersUiChangesLimitWidget( controller, model, config ) {
+       config = config || {};
+
+       // Parent
+       ChangesLimitAndDateButtonWidget.parent.call( this, config );
+
+       this.controller = controller;
+       this.model = model;
+
+       this.$overlay = config.$overlay || this.$element;
+
+       this.button = null;
+       this.limitGroupModel = null;
+       this.groupByPageItemModel = null;
+       this.daysGroupModel = null;
+
+       this.model.connect( this, {
+               initialize: 'onModelInitialize'
+       } );
+
+       this.$element
+               .addClass( 'mw-rcfilters-ui-changesLimitAndDateButtonWidget' );
+};
+
+/* Initialization */
+
+OO.inheritClass( ChangesLimitAndDateButtonWidget, OO.ui.Widget );
+
+/**
+ * Respond to model initialize event
+ */
+ChangesLimitAndDateButtonWidget.prototype.onModelInitialize = function () {
+       var changesLimitPopupWidget, selectedItem, currentValue, datePopupWidget,
+               displayGroupModel = this.model.getGroup( 'display' );
+
+       this.limitGroupModel = this.model.getGroup( 'limit' );
+       this.groupByPageItemModel = displayGroupModel.getItemByParamName( 'enhanced' );
+       this.daysGroupModel = this.model.getGroup( 'days' );
+
+       // HACK: We need the model to be ready before we populate the button
+       // and the widget, because we require the filter items for the
+       // limit and their events. This addition is only done after the
+       // model is initialized.
+       // Note: This will be fixed soon!
+       if ( this.limitGroupModel && this.daysGroupModel ) {
+               changesLimitPopupWidget = new ChangesLimitPopupWidget(
+                       this.limitGroupModel,
+                       this.groupByPageItemModel
+               );
+
+               datePopupWidget = new DatePopupWidget(
+                       this.daysGroupModel,
+                       {
+                               label: mw.msg( 'rcfilters-date-popup-title' )
+                       }
+               );
+
+               selectedItem = this.limitGroupModel.findSelectedItems()[ 0 ];
+               currentValue = ( selectedItem && selectedItem.getLabel() ) ||
+                       mw.language.convertNumber( this.limitGroupModel.getDefaultParamValue() );
+
+               this.button = new OO.ui.PopupButtonWidget( {
+                       icon: 'settings',
+                       indicator: 'down',
+                       label: mw.msg( 'rcfilters-limit-and-date-label', currentValue ),
+                       $overlay: this.$overlay,
+                       popup: {
+                               width: 300,
+                               padded: false,
+                               anchor: false,
+                               align: 'backwards',
+                               $autoCloseIgnore: this.$overlay,
+                               $content: $( '<div>' ).append(
+                                       // TODO: Merge ChangesLimitPopupWidget with DatePopupWidget into one common widget
+                                       changesLimitPopupWidget.$element,
+                                       datePopupWidget.$element
+                               )
+                       }
                } );
-
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-changesLimitAndDateButtonWidget' );
-       };
-
-       /* Initialization */
-
-       OO.inheritClass( ChangesLimitAndDateButtonWidget, OO.ui.Widget );
-
-       /**
-        * Respond to model initialize event
-        */
-       ChangesLimitAndDateButtonWidget.prototype.onModelInitialize = function () {
-               var changesLimitPopupWidget, selectedItem, currentValue, datePopupWidget,
-                       displayGroupModel = this.model.getGroup( 'display' );
-
-               this.limitGroupModel = this.model.getGroup( 'limit' );
-               this.groupByPageItemModel = displayGroupModel.getItemByParamName( 'enhanced' );
-               this.daysGroupModel = this.model.getGroup( 'days' );
-
-               // HACK: We need the model to be ready before we populate the button
-               // and the widget, because we require the filter items for the
-               // limit and their events. This addition is only done after the
-               // model is initialized.
-               // Note: This will be fixed soon!
-               if ( this.limitGroupModel && this.daysGroupModel ) {
-                       changesLimitPopupWidget = new ChangesLimitPopupWidget(
-                               this.limitGroupModel,
-                               this.groupByPageItemModel
-                       );
-
-                       datePopupWidget = new DatePopupWidget(
-                               this.daysGroupModel,
-                               {
-                                       label: mw.msg( 'rcfilters-date-popup-title' )
-                               }
-                       );
-
-                       selectedItem = this.limitGroupModel.findSelectedItems()[ 0 ];
-                       currentValue = ( selectedItem && selectedItem.getLabel() ) ||
-                               mw.language.convertNumber( this.limitGroupModel.getDefaultParamValue() );
-
-                       this.button = new OO.ui.PopupButtonWidget( {
-                               icon: 'settings',
-                               indicator: 'down',
-                               label: mw.msg( 'rcfilters-limit-and-date-label', currentValue ),
-                               $overlay: this.$overlay,
-                               popup: {
-                                       width: 300,
-                                       padded: false,
-                                       anchor: false,
-                                       align: 'backwards',
-                                       $autoCloseIgnore: this.$overlay,
-                                       $content: $( '<div>' ).append(
-                                               // TODO: Merge ChangesLimitPopupWidget with DatePopupWidget into one common widget
-                                               changesLimitPopupWidget.$element,
-                                               datePopupWidget.$element
-                                       )
-                               }
-                       } );
-                       this.updateButtonLabel();
-
-                       // Events
-                       this.limitGroupModel.connect( this, { update: 'updateButtonLabel' } );
-                       this.daysGroupModel.connect( this, { update: 'updateButtonLabel' } );
-                       changesLimitPopupWidget.connect( this, {
-                               limit: 'onPopupLimit',
-                               groupByPage: 'onPopupGroupByPage'
-                       } );
-                       datePopupWidget.connect( this, { days: 'onPopupDays' } );
-
-                       this.$element.append( this.button.$element );
-               }
-       };
-
-       /**
-        * Respond to popup limit change event
-        *
-        * @param {string} filterName Chosen filter name
-        */
-       ChangesLimitAndDateButtonWidget.prototype.onPopupLimit = function ( filterName ) {
-               var item = this.limitGroupModel.getItemByName( filterName );
-
-               this.controller.toggleFilterSelect( filterName, true );
-               this.controller.updateLimitDefault( item.getParamName() );
-               this.button.popup.toggle( false );
-       };
-
-       /**
-        * Respond to popup limit change event
-        *
-        * @param {boolean} isGrouped The result set is grouped by page
-        */
-       ChangesLimitAndDateButtonWidget.prototype.onPopupGroupByPage = function ( isGrouped ) {
-               this.controller.toggleFilterSelect( this.groupByPageItemModel.getName(), isGrouped );
-               this.controller.updateGroupByPageDefault( isGrouped );
-               this.button.popup.toggle( false );
-       };
-
-       /**
-        * Respond to popup limit change event
-        *
-        * @param {string} filterName Chosen filter name
-        */
-       ChangesLimitAndDateButtonWidget.prototype.onPopupDays = function ( filterName ) {
-               var item = this.daysGroupModel.getItemByName( filterName );
-
-               this.controller.toggleFilterSelect( filterName, true );
-               this.controller.updateDaysDefault( item.getParamName() );
-               this.button.popup.toggle( false );
-       };
-
-       /**
-        * Respond to limit choose event
-        *
-        * @param {string} filterName Filter name
-        */
-       ChangesLimitAndDateButtonWidget.prototype.updateButtonLabel = function () {
-               var message,
-                       limit = this.limitGroupModel.findSelectedItems()[ 0 ],
-                       label = limit && limit.getLabel(),
-                       days = this.daysGroupModel.findSelectedItems()[ 0 ],
-                       daysParamName = Number( days.getParamName() ) < 1 ?
-                               'rcfilters-days-show-hours' :
-                               'rcfilters-days-show-days';
-
-               // Update the label
-               if ( label && days ) {
-                       message = mw.msg( 'rcfilters-limit-and-date-label', label,
-                               mw.msg( daysParamName, days.getLabel() )
-                       );
-                       this.button.setLabel( message );
-               }
-       };
-
-       module.exports = ChangesLimitAndDateButtonWidget;
-
-}() );
+               this.updateButtonLabel();
+
+               // Events
+               this.limitGroupModel.connect( this, { update: 'updateButtonLabel' } );
+               this.daysGroupModel.connect( this, { update: 'updateButtonLabel' } );
+               changesLimitPopupWidget.connect( this, {
+                       limit: 'onPopupLimit',
+                       groupByPage: 'onPopupGroupByPage'
+               } );
+               datePopupWidget.connect( this, { days: 'onPopupDays' } );
+
+               this.$element.append( this.button.$element );
+       }
+};
+
+/**
+ * Respond to popup limit change event
+ *
+ * @param {string} filterName Chosen filter name
+ */
+ChangesLimitAndDateButtonWidget.prototype.onPopupLimit = function ( filterName ) {
+       var item = this.limitGroupModel.getItemByName( filterName );
+
+       this.controller.toggleFilterSelect( filterName, true );
+       this.controller.updateLimitDefault( item.getParamName() );
+       this.button.popup.toggle( false );
+};
+
+/**
+ * Respond to popup limit change event
+ *
+ * @param {boolean} isGrouped The result set is grouped by page
+ */
+ChangesLimitAndDateButtonWidget.prototype.onPopupGroupByPage = function ( isGrouped ) {
+       this.controller.toggleFilterSelect( this.groupByPageItemModel.getName(), isGrouped );
+       this.controller.updateGroupByPageDefault( isGrouped );
+       this.button.popup.toggle( false );
+};
+
+/**
+ * Respond to popup limit change event
+ *
+ * @param {string} filterName Chosen filter name
+ */
+ChangesLimitAndDateButtonWidget.prototype.onPopupDays = function ( filterName ) {
+       var item = this.daysGroupModel.getItemByName( filterName );
+
+       this.controller.toggleFilterSelect( filterName, true );
+       this.controller.updateDaysDefault( item.getParamName() );
+       this.button.popup.toggle( false );
+};
+
+/**
+ * Respond to limit choose event
+ */
+ChangesLimitAndDateButtonWidget.prototype.updateButtonLabel = function () {
+       var message,
+               limit = this.limitGroupModel.findSelectedItems()[ 0 ],
+               label = limit && limit.getLabel(),
+               days = this.daysGroupModel.findSelectedItems()[ 0 ],
+               daysParamName = Number( days.getParamName() ) < 1 ?
+                       'rcfilters-days-show-hours' :
+                       'rcfilters-days-show-days';
+
+       // Update the label
+       if ( label && days ) {
+               message = mw.msg( 'rcfilters-limit-and-date-label', label,
+                       mw.msg( daysParamName, days.getLabel() )
+               );
+               this.button.setLabel( message );
+       }
+};
+
+module.exports = ChangesLimitAndDateButtonWidget;
index d78c42b..a0c0d80 100644 (file)
@@ -1,84 +1,82 @@
-( function () {
-       var ValuePickerWidget = require( './ValuePickerWidget.js' ),
-               ChangesLimitPopupWidget;
+var ValuePickerWidget = require( './ValuePickerWidget.js' ),
+       ChangesLimitPopupWidget;
 
-       /**
       * Widget defining the popup to choose number of results
       *
       * @class mw.rcfilters.ui.ChangesLimitPopupWidget
       * @extends OO.ui.Widget
       *
       * @constructor
       * @param {mw.rcfilters.dm.FilterGroup} limitModel Group model for 'limit'
       * @param {mw.rcfilters.dm.FilterItem} groupByPageItemModel Group model for 'limit'
       * @param {Object} [config] Configuration object
       */
-       ChangesLimitPopupWidget = function MwRcfiltersUiChangesLimitPopupWidget( limitModel, groupByPageItemModel, config ) {
-               config = config || {};
+/**
+ * Widget defining the popup to choose number of results
+ *
+ * @class mw.rcfilters.ui.ChangesLimitPopupWidget
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {mw.rcfilters.dm.FilterGroup} limitModel Group model for 'limit'
+ * @param {mw.rcfilters.dm.FilterItem} groupByPageItemModel Group model for 'limit'
+ * @param {Object} [config] Configuration object
+ */
+ChangesLimitPopupWidget = function MwRcfiltersUiChangesLimitPopupWidget( limitModel, groupByPageItemModel, config ) {
+       config = config || {};
 
-               // Parent
-               ChangesLimitPopupWidget.parent.call( this, config );
+       // Parent
+       ChangesLimitPopupWidget.parent.call( this, config );
 
-               this.limitModel = limitModel;
-               this.groupByPageItemModel = groupByPageItemModel;
+       this.limitModel = limitModel;
+       this.groupByPageItemModel = groupByPageItemModel;
 
-               this.valuePicker = new ValuePickerWidget(
-                       this.limitModel,
-                       {
-                               label: mw.msg( 'rcfilters-limit-title' )
-                       }
-               );
+       this.valuePicker = new ValuePickerWidget(
+               this.limitModel,
+               {
+                       label: mw.msg( 'rcfilters-limit-title' )
+               }
+       );
 
-               this.groupByPageCheckbox = new OO.ui.CheckboxInputWidget( {
-                       selected: this.groupByPageItemModel.isSelected()
-               } );
+       this.groupByPageCheckbox = new OO.ui.CheckboxInputWidget( {
+               selected: this.groupByPageItemModel.isSelected()
+       } );
 
-               // Events
-               this.valuePicker.connect( this, { choose: [ 'emit', 'limit' ] } );
-               this.groupByPageCheckbox.connect( this, { change: [ 'emit', 'groupByPage' ] } );
-               this.groupByPageItemModel.connect( this, { update: 'onGroupByPageModelUpdate' } );
+       // Events
+       this.valuePicker.connect( this, { choose: [ 'emit', 'limit' ] } );
+       this.groupByPageCheckbox.connect( this, { change: [ 'emit', 'groupByPage' ] } );
+       this.groupByPageItemModel.connect( this, { update: 'onGroupByPageModelUpdate' } );
 
-               // Initialize
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-changesLimitPopupWidget' )
-                       .append(
-                               this.valuePicker.$element,
-                               new OO.ui.FieldLayout(
-                                       this.groupByPageCheckbox,
-                                       {
-                                               align: 'inline',
-                                               label: mw.msg( 'rcfilters-group-results-by-page' )
-                                       }
-                               ).$element
-                       );
-       };
+       // Initialize
+       this.$element
+               .addClass( 'mw-rcfilters-ui-changesLimitPopupWidget' )
+               .append(
+                       this.valuePicker.$element,
+                       new OO.ui.FieldLayout(
+                               this.groupByPageCheckbox,
+                               {
+                                       align: 'inline',
+                                       label: mw.msg( 'rcfilters-group-results-by-page' )
+                               }
+                       ).$element
+               );
+};
 
-       /* Initialization */
+/* Initialization */
 
-       OO.inheritClass( ChangesLimitPopupWidget, OO.ui.Widget );
+OO.inheritClass( ChangesLimitPopupWidget, OO.ui.Widget );
 
-       /* Events */
+/* Events */
 
-       /**
       * @event limit
       * @param {string} name Item name
       *
       * A limit item was chosen
       */
+/**
+ * @event limit
+ * @param {string} name Item name
+ *
+ * A limit item was chosen
+ */
 
-       /**
       * @event groupByPage
       * @param {boolean} isGrouped The results are grouped by page
       *
       * Results are grouped by page
       */
+/**
+ * @event groupByPage
+ * @param {boolean} isGrouped The results are grouped by page
+ *
+ * Results are grouped by page
+ */
 
-       /**
       * Respond to group by page model update
       */
-       ChangesLimitPopupWidget.prototype.onGroupByPageModelUpdate = function () {
-               this.groupByPageCheckbox.setSelected( this.groupByPageItemModel.isSelected() );
-       };
+/**
+ * Respond to group by page model update
+ */
+ChangesLimitPopupWidget.prototype.onGroupByPageModelUpdate = function () {
+       this.groupByPageCheckbox.setSelected( this.groupByPageItemModel.isSelected() );
+};
 
-       module.exports = ChangesLimitPopupWidget;
-}() );
+module.exports = ChangesLimitPopupWidget;
index ba7f4d1..78cd8f4 100644 (file)
-( function () {
-       /**
-        * List of changes
-        *
-        * @class mw.rcfilters.ui.ChangesListWrapperWidget
-        * @extends OO.ui.Widget
-        *
-        * @constructor
-        * @param {mw.rcfilters.dm.FiltersViewModel} filtersViewModel View model
-        * @param {mw.rcfilters.dm.ChangesListViewModel} changesListViewModel View model
-        * @param {mw.rcfilters.Controller} controller
-        * @param {jQuery} $changesListRoot Root element of the changes list to attach to
-        * @param {Object} [config] Configuration object
-        */
-       var ChangesListWrapperWidget = function MwRcfiltersUiChangesListWrapperWidget(
-               filtersViewModel,
-               changesListViewModel,
-               controller,
-               $changesListRoot,
-               config
-       ) {
-               config = $.extend( {}, config, {
-                       $element: $changesListRoot
-               } );
-
-               // Parent
-               ChangesListWrapperWidget.parent.call( this, config );
-
-               this.filtersViewModel = filtersViewModel;
-               this.changesListViewModel = changesListViewModel;
-               this.controller = controller;
-               this.highlightClasses = null;
-
-               // Events
-               this.filtersViewModel.connect( this, {
-                       itemUpdate: 'onItemUpdate',
-                       highlightChange: 'onHighlightChange'
-               } );
-               this.changesListViewModel.connect( this, {
-                       invalidate: 'onModelInvalidate',
-                       update: 'onModelUpdate'
-               } );
-
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-changesListWrapperWidget' )
-                       // We handle our own display/hide of the empty results message
-                       // We keep the timeout class here and remove it later, since at this
-                       // stage it is still needed to identify that the timeout occurred.
-                       .removeClass( 'mw-changeslist-empty' );
-       };
-
-       /* Initialization */
-
-       OO.inheritClass( ChangesListWrapperWidget, OO.ui.Widget );
-
-       /**
-        * Get all available highlight classes
-        *
-        * @return {string[]} An array of available highlight class names
-        */
-       ChangesListWrapperWidget.prototype.getHighlightClasses = function () {
-               if ( !this.highlightClasses || !this.highlightClasses.length ) {
-                       this.highlightClasses = this.filtersViewModel.getItemsSupportingHighlights()
-                               .map( function ( filterItem ) {
-                                       return filterItem.getCssClass();
-                               } );
-               }
-
-               return this.highlightClasses;
-       };
-
-       /**
-        * Respond to the highlight feature being toggled on and off
-        *
-        * @param {boolean} highlightEnabled
-        */
-       ChangesListWrapperWidget.prototype.onHighlightChange = function ( highlightEnabled ) {
-               if ( highlightEnabled ) {
-                       this.applyHighlight();
+/**
+ * List of changes
+ *
+ * @class mw.rcfilters.ui.ChangesListWrapperWidget
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {mw.rcfilters.dm.FiltersViewModel} filtersViewModel View model
+ * @param {mw.rcfilters.dm.ChangesListViewModel} changesListViewModel View model
+ * @param {mw.rcfilters.Controller} controller
+ * @param {jQuery} $changesListRoot Root element of the changes list to attach to
+ * @param {Object} [config] Configuration object
+ */
+var ChangesListWrapperWidget = function MwRcfiltersUiChangesListWrapperWidget(
+       filtersViewModel,
+       changesListViewModel,
+       controller,
+       $changesListRoot,
+       config
+) {
+       config = $.extend( {}, config, {
+               $element: $changesListRoot
+       } );
+
+       // Parent
+       ChangesListWrapperWidget.parent.call( this, config );
+
+       this.filtersViewModel = filtersViewModel;
+       this.changesListViewModel = changesListViewModel;
+       this.controller = controller;
+
+       // Events
+       this.filtersViewModel.connect( this, {
+               itemUpdate: 'onItemUpdate',
+               highlightChange: 'onHighlightChange'
+       } );
+       this.changesListViewModel.connect( this, {
+               invalidate: 'onModelInvalidate',
+               update: 'onModelUpdate'
+       } );
+
+       this.$element
+               .addClass( 'mw-rcfilters-ui-changesListWrapperWidget' )
+               // We handle our own display/hide of the empty results message
+               // We keep the timeout class here and remove it later, since at this
+               // stage it is still needed to identify that the timeout occurred.
+               .removeClass( 'mw-changeslist-empty' );
+};
+
+/* Initialization */
+
+OO.inheritClass( ChangesListWrapperWidget, OO.ui.Widget );
+
+/**
+ * Respond to the highlight feature being toggled on and off
+ *
+ * @param {boolean} highlightEnabled
+ */
+ChangesListWrapperWidget.prototype.onHighlightChange = function ( highlightEnabled ) {
+       if ( highlightEnabled ) {
+               this.applyHighlight();
+       } else {
+               this.clearHighlight();
+       }
+};
+
+/**
+ * Respond to a filter item model update
+ */
+ChangesListWrapperWidget.prototype.onItemUpdate = function () {
+       if ( this.controller.isInitialized() && this.filtersViewModel.isHighlightEnabled() ) {
+               // this.controller.isInitialized() is still false during page load,
+               // we don't want to clear/apply highlights at this stage.
+               this.clearHighlight();
+               this.applyHighlight();
+       }
+};
+
+/**
+ * Respond to changes list model invalidate
+ */
+ChangesListWrapperWidget.prototype.onModelInvalidate = function () {
+       $( 'body' ).addClass( 'mw-rcfilters-ui-loading' );
+};
+
+/**
+ * Respond to changes list model update
+ *
+ * @param {jQuery|string} $changesListContent The content of the updated changes list
+ * @param {jQuery} $fieldset The content of the updated fieldset
+ * @param {string} noResultsDetails Type of no result error
+ * @param {boolean} isInitialDOM Whether $changesListContent is the existing (already attached) DOM
+ * @param {boolean} from Timestamp of the new changes
+ */
+ChangesListWrapperWidget.prototype.onModelUpdate = function (
+       $changesListContent, $fieldset, noResultsDetails, isInitialDOM, from
+) {
+       var conflictItem,
+               $message = $( '<div>' )
+                       .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-results' ),
+               isEmpty = $changesListContent === 'NO_RESULTS',
+               // For enhanced mode, we have to load these modules, which are
+               // not loaded for the 'regular' mode in the backend
+               loaderPromise = mw.user.options.get( 'usenewrc' ) ?
+                       mw.loader.using( [ 'mediawiki.special.changeslist.enhanced', 'mediawiki.icon' ] ) :
+                       $.Deferred().resolve(),
+               widget = this;
+
+       this.$element.toggleClass( 'mw-changeslist', !isEmpty );
+       if ( isEmpty ) {
+               this.$element.empty();
+
+               if ( this.filtersViewModel.hasConflict() ) {
+                       conflictItem = this.filtersViewModel.getFirstConflictedItem();
+
+                       $message
+                               .append(
+                                       $( '<div>' )
+                                               .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-results-conflict' )
+                                               .text( mw.message( 'rcfilters-noresults-conflict' ).text() ),
+                                       $( '<div>' )
+                                               .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-results-message' )
+                                               .text( mw.message( conflictItem.getCurrentConflictResultMessage() ).text() )
+                               );
                } else {
-                       this.clearHighlight();
-               }
-       };
+                       $message
+                               .append(
+                                       $( '<div>' )
+                                               .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-results-noresult' )
+                                               .text( mw.msg( this.getMsgKeyForNoResults( noResultsDetails ) ) )
+                               );
 
-       /**
-        * Respond to a filter item model update
-        */
-       ChangesListWrapperWidget.prototype.onItemUpdate = function () {
-               if ( this.controller.isInitialized() && this.filtersViewModel.isHighlightEnabled() ) {
-                       // this.controller.isInitialized() is still false during page load,
-                       // we don't want to clear/apply highlights at this stage.
-                       this.clearHighlight();
-                       this.applyHighlight();
+                       // remove all classes matching mw-changeslist-*
+                       this.$element.removeClass( function ( elementIndex, allClasses ) {
+                               return allClasses
+                                       .split( ' ' )
+                                       .filter( function ( className ) {
+                                               return className.indexOf( 'mw-changeslist-' ) === 0;
+                                       } )
+                                       .join( ' ' );
+                       );
                }
-       };
 
-       /**
-        * Respond to changes list model invalidate
-        */
-       ChangesListWrapperWidget.prototype.onModelInvalidate = function () {
-               $( 'body' ).addClass( 'mw-rcfilters-ui-loading' );
-       };
+               this.$element.append( $message );
+       } else {
+               if ( !isInitialDOM ) {
+                       this.$element.empty().append( $changesListContent );
 
-       /**
-        * Respond to changes list model update
-        *
-        * @param {jQuery|string} $changesListContent The content of the updated changes list
-        * @param {jQuery} $fieldset The content of the updated fieldset
-        * @param {string} noResultsDetails Type of no result error
-        * @param {boolean} isInitialDOM Whether $changesListContent is the existing (already attached) DOM
-        * @param {boolean} from Timestamp of the new changes
-        */
-       ChangesListWrapperWidget.prototype.onModelUpdate = function (
-               $changesListContent, $fieldset, noResultsDetails, isInitialDOM, from
-       ) {
-               var conflictItem,
-                       $message = $( '<div>' )
-                               .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-results' ),
-                       isEmpty = $changesListContent === 'NO_RESULTS',
-                       // For enhanced mode, we have to load these modules, which are
-                       // not loaded for the 'regular' mode in the backend
-                       loaderPromise = mw.user.options.get( 'usenewrc' ) ?
-                               mw.loader.using( [ 'mediawiki.special.changeslist.enhanced', 'mediawiki.icon' ] ) :
-                               $.Deferred().resolve(),
-                       widget = this;
-
-               this.$element.toggleClass( 'mw-changeslist', !isEmpty );
-               if ( isEmpty ) {
-                       this.$element.empty();
-
-                       if ( this.filtersViewModel.hasConflict() ) {
-                               conflictItem = this.filtersViewModel.getFirstConflictedItem();
-
-                               $message
-                                       .append(
-                                               $( '<div>' )
-                                                       .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-results-conflict' )
-                                                       .text( mw.message( 'rcfilters-noresults-conflict' ).text() ),
-                                               $( '<div>' )
-                                                       .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-results-message' )
-                                                       .text( mw.message( conflictItem.getCurrentConflictResultMessage() ).text() )
-                                       );
-                       } else {
-                               $message
-                                       .append(
-                                               $( '<div>' )
-                                                       .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-results-noresult' )
-                                                       .text( mw.msg( this.getMsgKeyForNoResults( noResultsDetails ) ) )
-                                       );
-
-                               // remove all classes matching mw-changeslist-*
-                               this.$element.removeClass( function ( elementIndex, allClasses ) {
-                                       return allClasses
-                                               .split( ' ' )
-                                               .filter( function ( className ) {
-                                                       return className.indexOf( 'mw-changeslist-' ) === 0;
-                                               } )
-                                               .join( ' ' );
-                               } );
+                       if ( from ) {
+                               this.emphasizeNewChanges( from );
                        }
-
-                       this.$element.append( $message );
-               } else {
-                       if ( !isInitialDOM ) {
-                               this.$element.empty().append( $changesListContent );
-
-                               if ( from ) {
-                                       this.emphasizeNewChanges( from );
-                               }
-                       }
-
-                       // Apply highlight
-                       this.applyHighlight();
-
                }
 
-               this.$element.prepend( $( '<div>' ).addClass( 'mw-changeslist-overlay' ) );
+               // Apply highlight
+               this.applyHighlight();
 
-               loaderPromise.done( function () {
-                       if ( !isInitialDOM && !isEmpty ) {
-                               // Make sure enhanced RC re-initializes correctly
-                               mw.hook( 'wikipage.content' ).fire( widget.$element );
-                       }
+       }
 
-                       $( 'body' ).removeClass( 'mw-rcfilters-ui-loading' );
-               } );
-       };
+       this.$element.prepend( $( '<div>' ).addClass( 'mw-changeslist-overlay' ) );
 
-       /** Toggles overlay class on changes list
-        *
-        * @param {boolean} isVisible True if overlay should be visible
-        */
-       ChangesListWrapperWidget.prototype.toggleOverlay = function ( isVisible ) {
-               this.$element.toggleClass( 'mw-rcfilters-ui-changesListWrapperWidget--overlaid', isVisible );
-       };
+       loaderPromise.done( function () {
+               if ( !isInitialDOM && !isEmpty ) {
+                       // Make sure enhanced RC re-initializes correctly
+                       mw.hook( 'wikipage.content' ).fire( widget.$element );
+               }
 
-       /**
-        * Map a reason for having no results to its message key
-        *
-        * @param {string} reason One of the NO_RESULTS_* "constant" that represent
-        *   a reason for having no results
-        * @return {string} Key for the message that explains why there is no results in this case
-        */
-       ChangesListWrapperWidget.prototype.getMsgKeyForNoResults = function ( reason ) {
-               var reasonMsgKeyMap = {
-                       NO_RESULTS_NORMAL: 'recentchanges-noresult',
-                       NO_RESULTS_TIMEOUT: 'recentchanges-timeout',
-                       NO_RESULTS_NETWORK_ERROR: 'recentchanges-network',
-                       NO_RESULTS_NO_TARGET_PAGE: 'recentchanges-notargetpage',
-                       NO_RESULTS_INVALID_TARGET_PAGE: 'allpagesbadtitle'
-               };
-               return reasonMsgKeyMap[ reason ];
+               $( 'body' ).removeClass( 'mw-rcfilters-ui-loading' );
+       } );
+};
+
+/** Toggles overlay class on changes list
+ *
+ * @param {boolean} isVisible True if overlay should be visible
+ */
+ChangesListWrapperWidget.prototype.toggleOverlay = function ( isVisible ) {
+       this.$element.toggleClass( 'mw-rcfilters-ui-changesListWrapperWidget--overlaid', isVisible );
+};
+
+/**
+ * Map a reason for having no results to its message key
+ *
+ * @param {string} reason One of the NO_RESULTS_* "constant" that represent
+ *   a reason for having no results
+ * @return {string} Key for the message that explains why there is no results in this case
+ */
+ChangesListWrapperWidget.prototype.getMsgKeyForNoResults = function ( reason ) {
+       var reasonMsgKeyMap = {
+               NO_RESULTS_NORMAL: 'recentchanges-noresult',
+               NO_RESULTS_TIMEOUT: 'recentchanges-timeout',
+               NO_RESULTS_NETWORK_ERROR: 'recentchanges-network',
+               NO_RESULTS_NO_TARGET_PAGE: 'recentchanges-notargetpage',
+               NO_RESULTS_INVALID_TARGET_PAGE: 'allpagesbadtitle'
        };
-
-       /**
-        * Emphasize the elements (or groups) newer than the 'from' parameter
-        * @param {string} from Anything newer than this is considered 'new'
-        */
-       ChangesListWrapperWidget.prototype.emphasizeNewChanges = function ( from ) {
-               var $firstNew,
-                       $indicator,
-                       $newChanges = $( [] ),
-                       selector = this.inEnhancedMode() ?
-                               'table.mw-enhanced-rc[data-mw-ts]' :
-                               'li[data-mw-ts]',
-                       set = this.$element.find( selector ),
-                       length = set.length;
-
-               set.each( function ( index ) {
-                       var $this = $( this ),
-                               ts = $this.data( 'mw-ts' );
-
-                       if ( ts >= from ) {
-                               $newChanges = $newChanges.add( $this );
-                               $firstNew = $this;
-
-                               // guards against putting the marker after the last element
-                               if ( index === ( length - 1 ) ) {
-                                       $firstNew = null;
-                               }
+       return reasonMsgKeyMap[ reason ];
+};
+
+/**
+ * Emphasize the elements (or groups) newer than the 'from' parameter
+ * @param {string} from Anything newer than this is considered 'new'
+ */
+ChangesListWrapperWidget.prototype.emphasizeNewChanges = function ( from ) {
+       var $firstNew,
+               $indicator,
+               $newChanges = $( [] ),
+               selector = this.inEnhancedMode() ?
+                       'table.mw-enhanced-rc[data-mw-ts]' :
+                       'li[data-mw-ts]',
+               set = this.$element.find( selector ),
+               length = set.length;
+
+       set.each( function ( index ) {
+               var $this = $( this ),
+                       ts = $this.data( 'mw-ts' );
+
+               if ( ts >= from ) {
+                       $newChanges = $newChanges.add( $this );
+                       $firstNew = $this;
+
+                       // guards against putting the marker after the last element
+                       if ( index === ( length - 1 ) ) {
+                               $firstNew = null;
                        }
-               } );
-
-               if ( $firstNew ) {
-                       $indicator = $( '<div>' )
-                               .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-previousChangesIndicator' );
-
-                       $firstNew.after( $indicator );
                }
-
-               // FIXME: Use CSS transition
-               // eslint-disable-next-line no-jquery/no-fade
-               $newChanges
-                       .hide()
-                       .fadeIn( 1000 );
-       };
-
-       /**
-        * In enhanced mode, we need to check whether the grouped results all have the
-        * same active highlights in order to see whether the "parent" of the group should
-        * be grey or highlighted normally.
-        *
-        * This is called every time highlights are applied.
-        */
-       ChangesListWrapperWidget.prototype.updateEnhancedParentHighlight = function () {
-               var activeHighlightClasses,
-                       $enhancedTopPageCell = this.$element.find( 'table.mw-enhanced-rc.mw-collapsible' );
-
-               activeHighlightClasses = this.filtersViewModel.getCurrentlyUsedHighlightColors().map( function ( color ) {
-                       return 'mw-rcfilters-highlight-color-' + color;
+       } );
+
+       if ( $firstNew ) {
+               $indicator = $( '<div>' )
+                       .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-previousChangesIndicator' );
+
+               $firstNew.after( $indicator );
+       }
+
+       // FIXME: Use CSS transition
+       // eslint-disable-next-line no-jquery/no-fade
+       $newChanges
+               .hide()
+               .fadeIn( 1000 );
+};
+
+/**
+ * In enhanced mode, we need to check whether the grouped results all have the
+ * same active highlights in order to see whether the "parent" of the group should
+ * be grey or highlighted normally.
+ *
+ * This is called every time highlights are applied.
+ */
+ChangesListWrapperWidget.prototype.updateEnhancedParentHighlight = function () {
+       var activeHighlightClasses,
+               $enhancedTopPageCell = this.$element.find( 'table.mw-enhanced-rc.mw-collapsible' );
+
+       activeHighlightClasses = this.filtersViewModel.getCurrentlyUsedHighlightColors().map( function ( color ) {
+               return 'mw-rcfilters-highlight-color-' + color;
+       } );
+
+       // Go over top pages and their children, and figure out if all sub-pages have the
+       // same highlights between themselves. If they do, the parent should be highlighted
+       // with all colors. If classes are different, the parent should receive a grey
+       // background
+       $enhancedTopPageCell.each( function () {
+               var firstChildClasses, $rowsWithDifferentHighlights,
+                       $table = $( this );
+
+               // Collect the relevant classes from the first nested child
+               firstChildClasses = activeHighlightClasses.filter( function ( className ) {
+                       return $table.find( 'tr:nth-child(2)' ).hasClass( className );
                } );
-
-               // Go over top pages and their children, and figure out if all sub-pages have the
-               // same highlights between themselves. If they do, the parent should be highlighted
-               // with all colors. If classes are different, the parent should receive a grey
-               // background
-               $enhancedTopPageCell.each( function () {
-                       var firstChildClasses, $rowsWithDifferentHighlights,
-                               $table = $( this );
-
-                       // Collect the relevant classes from the first nested child
-                       firstChildClasses = activeHighlightClasses.filter( function ( className ) {
-                               return $table.find( 'tr:nth-child(2)' ).hasClass( className );
+               // Filter the non-head rows and see if they all have the same classes
+               // to the first row
+               $rowsWithDifferentHighlights = $table.find( 'tr:not(:first-child)' ).filter( function () {
+                       var classesInThisRow,
+                               $this = $( this );
+
+                       classesInThisRow = activeHighlightClasses.filter( function ( className ) {
+                               return $this.hasClass( className );
                        } );
-                       // Filter the non-head rows and see if they all have the same classes
-                       // to the first row
-                       $rowsWithDifferentHighlights = $table.find( 'tr:not(:first-child)' ).filter( function () {
-                               var classesInThisRow,
-                                       $this = $( this );
 
-                               classesInThisRow = activeHighlightClasses.filter( function ( className ) {
-                                       return $this.hasClass( className );
-                               } );
-
-                               return !OO.compare( firstChildClasses, classesInThisRow );
-                       } );
-
-                       // If classes are different, tag the row for using grey color
-                       $table.find( 'tr:first-child' )
-                               .toggleClass( 'mw-rcfilters-ui-changesListWrapperWidget-enhanced-grey', $rowsWithDifferentHighlights.length > 0 );
+                       return !OO.compare( firstChildClasses, classesInThisRow );
                } );
-       };
-
-       /**
-        * @return {boolean} Whether the changes are grouped by page
-        */
-       ChangesListWrapperWidget.prototype.inEnhancedMode = function () {
-               var uri = new mw.Uri();
-               return ( uri.query.enhanced !== undefined && Number( uri.query.enhanced ) ) ||
-                       ( uri.query.enhanced === undefined && Number( mw.user.options.get( 'usenewrc' ) ) );
-       };
-
-       /**
-        * Apply color classes based on filters highlight configuration
-        */
-       ChangesListWrapperWidget.prototype.applyHighlight = function () {
-               if ( !this.filtersViewModel.isHighlightEnabled() ) {
-                       return;
-               }
-
-               this.filtersViewModel.getHighlightedItems().forEach( function ( filterItem ) {
-                       var $elements = this.$element.find( '.' + filterItem.getCssClass() );
 
-                       // Add highlight class to all highlighted list items
-                       $elements
-                               .addClass(
-                                       'mw-rcfilters-highlighted ' +
-                                       'mw-rcfilters-highlight-color-' + filterItem.getHighlightColor()
-                               );
-
-                       // Track the filters for each item in .data( 'highlightedFilters' )
-                       $elements.each( function () {
-                               var filters = $( this ).data( 'highlightedFilters' );
-                               if ( !filters ) {
-                                       filters = [];
-                                       $( this ).data( 'highlightedFilters', filters );
-                               }
-                               if ( filters.indexOf( filterItem.getLabel() ) === -1 ) {
-                                       filters.push( filterItem.getLabel() );
-                               }
-                       } );
-               }.bind( this ) );
-               // Apply a title to each highlighted item, with a list of filters
-               this.$element.find( '.mw-rcfilters-highlighted' ).each( function () {
+               // If classes are different, tag the row for using grey color
+               $table.find( 'tr:first-child' )
+                       .toggleClass( 'mw-rcfilters-ui-changesListWrapperWidget-enhanced-grey', $rowsWithDifferentHighlights.length > 0 );
+       } );
+};
+
+/**
+ * @return {boolean} Whether the changes are grouped by page
+ */
+ChangesListWrapperWidget.prototype.inEnhancedMode = function () {
+       var uri = new mw.Uri();
+       return ( uri.query.enhanced !== undefined && Number( uri.query.enhanced ) ) ||
+               ( uri.query.enhanced === undefined && Number( mw.user.options.get( 'usenewrc' ) ) );
+};
+
+/**
+ * Apply color classes based on filters highlight configuration
+ */
+ChangesListWrapperWidget.prototype.applyHighlight = function () {
+       if ( !this.filtersViewModel.isHighlightEnabled() ) {
+               return;
+       }
+
+       this.filtersViewModel.getHighlightedItems().forEach( function ( filterItem ) {
+               var $elements = this.$element.find( '.' + filterItem.getCssClass() );
+
+               // Add highlight class to all highlighted list items
+               $elements
+                       .addClass(
+                               'mw-rcfilters-highlighted ' +
+                               'mw-rcfilters-highlight-color-' + filterItem.getHighlightColor()
+                       );
+
+               // Track the filters for each item in .data( 'highlightedFilters' )
+               $elements.each( function () {
                        var filters = $( this ).data( 'highlightedFilters' );
-
-                       if ( filters && filters.length ) {
-                               $( this ).attr( 'title', mw.msg(
-                                       'rcfilters-highlighted-filters-list',
-                                       filters.join( mw.msg( 'comma-separator' ) )
-                               ) );
+                       if ( !filters ) {
+                               filters = [];
+                               $( this ).data( 'highlightedFilters', filters );
+                       }
+                       if ( filters.indexOf( filterItem.getLabel() ) === -1 ) {
+                               filters.push( filterItem.getLabel() );
                        }
-
                } );
-               if ( this.inEnhancedMode() ) {
-                       this.updateEnhancedParentHighlight();
+       }.bind( this ) );
+       // Apply a title to each highlighted item, with a list of filters
+       this.$element.find( '.mw-rcfilters-highlighted' ).each( function () {
+               var filters = $( this ).data( 'highlightedFilters' );
+
+               if ( filters && filters.length ) {
+                       $( this ).attr( 'title', mw.msg(
+                               'rcfilters-highlighted-filters-list',
+                               filters.join( mw.msg( 'comma-separator' ) )
+                       ) );
                }
 
-               // Turn on highlights
-               this.$element.addClass( 'mw-rcfilters-ui-changesListWrapperWidget-highlighted' );
-       };
+       } );
+       if ( this.inEnhancedMode() ) {
+               this.updateEnhancedParentHighlight();
+       }
+
+       // Turn on highlights
+       this.$element.addClass( 'mw-rcfilters-ui-changesListWrapperWidget-highlighted' );
+};
+
+/**
+ * Remove all color classes
+ */
+ChangesListWrapperWidget.prototype.clearHighlight = function () {
+       // Remove highlight classes
+       mw.rcfilters.HighlightColors.forEach( function ( color ) {
+               this.$element
+                       .find( '.mw-rcfilters-highlight-color-' + color )
+                       .removeClass( 'mw-rcfilters-highlight-color-' + color );
+       }.bind( this ) );
 
-       /**
-        * Remove all color classes
-        */
-       ChangesListWrapperWidget.prototype.clearHighlight = function () {
-               // Remove highlight classes
-               mw.rcfilters.HighlightColors.forEach( function ( color ) {
-                       this.$element
-                               .find( '.mw-rcfilters-highlight-color-' + color )
-                               .removeClass( 'mw-rcfilters-highlight-color-' + color );
-               }.bind( this ) );
-
-               this.$element.find( '.mw-rcfilters-highlighted' )
-                       .removeAttr( 'title' )
-                       .removeData( 'highlightedFilters' )
-                       .removeClass( 'mw-rcfilters-highlighted' );
-
-               // Remove grey from enhanced rows
-               this.$element.find( '.mw-rcfilters-ui-changesListWrapperWidget-enhanced-grey' )
-                       .removeClass( 'mw-rcfilters-ui-changesListWrapperWidget-enhanced-grey' );
-
-               // Turn off highlights
-               this.$element.removeClass( 'mw-rcfilters-ui-changesListWrapperWidget-highlighted' );
-       };
+       this.$element.find( '.mw-rcfilters-highlighted' )
+               .removeAttr( 'title' )
+               .removeData( 'highlightedFilters' )
+               .removeClass( 'mw-rcfilters-highlighted' );
+
+       // Remove grey from enhanced rows
+       this.$element.find( '.mw-rcfilters-ui-changesListWrapperWidget-enhanced-grey' )
+               .removeClass( 'mw-rcfilters-ui-changesListWrapperWidget-enhanced-grey' );
+
+       // Turn off highlights
+       this.$element.removeClass( 'mw-rcfilters-ui-changesListWrapperWidget-highlighted' );
+};
 
-       module.exports = ChangesListWrapperWidget;
-}() );
+module.exports = ChangesListWrapperWidget;
index 490d54e..b6e21cf 100644 (file)
@@ -1,66 +1,64 @@
-( function () {
-       /**
-        * A widget representing a single toggle filter
-        *
-        * @class mw.rcfilters.ui.CheckboxInputWidget
-        * @extends OO.ui.CheckboxInputWidget
-        *
-        * @constructor
-        * @param {Object} config Configuration object
-        */
-       var CheckboxInputWidget = function MwRcfiltersUiCheckboxInputWidget( config ) {
-               config = config || {};
+/**
+ * A widget representing a single toggle filter
+ *
+ * @class mw.rcfilters.ui.CheckboxInputWidget
+ * @extends OO.ui.CheckboxInputWidget
+ *
+ * @constructor
+ * @param {Object} config Configuration object
+ */
+var CheckboxInputWidget = function MwRcfiltersUiCheckboxInputWidget( config ) {
+       config = config || {};
 
-               // Parent
-               CheckboxInputWidget.parent.call( this, config );
+       // Parent
+       CheckboxInputWidget.parent.call( this, config );
 
-               // Event
-               this.$input
-                       // HACK: This widget just pretends to be a checkbox for visual purposes.
-                       // In reality, all actions - setting to true or false, etc - are
-                       // decided by the model, and executed by the controller. This means
-                       // that we want to let the controller and model make the decision
-                       // of whether to check/uncheck this checkboxInputWidget, and for that,
-                       // we have to bypass the browser action that checks/unchecks it during
-                       // click.
-                       .on( 'click', false )
-                       .on( 'change', this.onUserChange.bind( this ) );
-       };
+       // Event
+       this.$input
+               // HACK: This widget just pretends to be a checkbox for visual purposes.
+               // In reality, all actions - setting to true or false, etc - are
+               // decided by the model, and executed by the controller. This means
+               // that we want to let the controller and model make the decision
+               // of whether to check/uncheck this checkboxInputWidget, and for that,
+               // we have to bypass the browser action that checks/unchecks it during
+               // click.
+               .on( 'click', false )
+               .on( 'change', this.onUserChange.bind( this ) );
+};
 
-       /* Initialization */
+/* Initialization */
 
-       OO.inheritClass( CheckboxInputWidget, OO.ui.CheckboxInputWidget );
+OO.inheritClass( CheckboxInputWidget, OO.ui.CheckboxInputWidget );
 
-       /* Events */
+/* Events */
 
-       /**
       * @event userChange
       * @param {boolean} Current state of the checkbox
       *
       * The user has checked or unchecked this checkbox
       */
+/**
+ * @event userChange
+ * @param {boolean} Current state of the checkbox
+ *
+ * The user has checked or unchecked this checkbox
+ */
 
-       /* Methods */
+/* Methods */
 
-       /**
       * @inheritdoc
       */
-       CheckboxInputWidget.prototype.onEdit = function () {
-               // Similarly to preventing defaults in 'click' event, we want
-               // to prevent this widget from deciding anything about its own
-               // state; it emits a change event and the model and controller
-               // make a decision about what its select state is.
-               // onEdit has a widget.$input.prop( 'checked' ) inside a setTimeout()
-               // so we really want to prevent that from messing with what
-               // the model decides the state of the widget is.
-       };
+/**
+ * @inheritdoc
+ */
+CheckboxInputWidget.prototype.onEdit = function () {
+       // Similarly to preventing defaults in 'click' event, we want
+       // to prevent this widget from deciding anything about its own
+       // state; it emits a change event and the model and controller
+       // make a decision about what its select state is.
+       // onEdit has a widget.$input.prop( 'checked' ) inside a setTimeout()
+       // so we really want to prevent that from messing with what
+       // the model decides the state of the widget is.
+};
 
-       /**
       * Respond to checkbox change by a user and emit 'userChange'.
       */
-       CheckboxInputWidget.prototype.onUserChange = function () {
-               this.emit( 'userChange', this.$input.prop( 'checked' ) );
-       };
+/**
+ * Respond to checkbox change by a user and emit 'userChange'.
+ */
+CheckboxInputWidget.prototype.onUserChange = function () {
+       this.emit( 'userChange', this.$input.prop( 'checked' ) );
+};
 
-       module.exports = CheckboxInputWidget;
-}() );
+module.exports = CheckboxInputWidget;
index 1ac0d49..226821c 100644 (file)
@@ -1,72 +1,70 @@
-( function () {
-       var ValuePickerWidget = require( './ValuePickerWidget.js' ),
-               DatePopupWidget;
+var ValuePickerWidget = require( './ValuePickerWidget.js' ),
+       DatePopupWidget;
 
-       /**
       * Widget defining the popup to choose date for the results
       *
       * @class mw.rcfilters.ui.DatePopupWidget
       * @extends OO.ui.Widget
       *
       * @constructor
       * @param {mw.rcfilters.dm.FilterGroup} model Group model for 'days'
       * @param {Object} [config] Configuration object
       */
-       DatePopupWidget = function MwRcfiltersUiDatePopupWidget( model, config ) {
-               config = config || {};
+/**
+ * Widget defining the popup to choose date for the results
+ *
+ * @class mw.rcfilters.ui.DatePopupWidget
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {mw.rcfilters.dm.FilterGroup} model Group model for 'days'
+ * @param {Object} [config] Configuration object
+ */
+DatePopupWidget = function MwRcfiltersUiDatePopupWidget( model, config ) {
+       config = config || {};
 
-               // Parent
-               DatePopupWidget.parent.call( this, config );
-               // Mixin constructors
-               OO.ui.mixin.LabelElement.call( this, config );
+       // Parent
+       DatePopupWidget.parent.call( this, config );
+       // Mixin constructors
+       OO.ui.mixin.LabelElement.call( this, config );
 
-               this.model = model;
+       this.model = model;
 
-               this.hoursValuePicker = new ValuePickerWidget(
-                       this.model,
-                       {
-                               classes: [ 'mw-rcfilters-ui-datePopupWidget-hours' ],
-                               label: mw.msg( 'rcfilters-hours-title' ),
-                               itemFilter: function ( itemModel ) { return Number( itemModel.getParamName() ) < 1; }
-                       }
-               );
-               this.daysValuePicker = new ValuePickerWidget(
-                       this.model,
-                       {
-                               classes: [ 'mw-rcfilters-ui-datePopupWidget-days' ],
-                               label: mw.msg( 'rcfilters-days-title' ),
-                               itemFilter: function ( itemModel ) { return Number( itemModel.getParamName() ) >= 1; }
-                       }
-               );
+       this.hoursValuePicker = new ValuePickerWidget(
+               this.model,
+               {
+                       classes: [ 'mw-rcfilters-ui-datePopupWidget-hours' ],
+                       label: mw.msg( 'rcfilters-hours-title' ),
+                       itemFilter: function ( itemModel ) { return Number( itemModel.getParamName() ) < 1; }
+               }
+       );
+       this.daysValuePicker = new ValuePickerWidget(
+               this.model,
+               {
+                       classes: [ 'mw-rcfilters-ui-datePopupWidget-days' ],
+                       label: mw.msg( 'rcfilters-days-title' ),
+                       itemFilter: function ( itemModel ) { return Number( itemModel.getParamName() ) >= 1; }
+               }
+       );
 
-               // Events
-               this.hoursValuePicker.connect( this, { choose: [ 'emit', 'days' ] } );
-               this.daysValuePicker.connect( this, { choose: [ 'emit', 'days' ] } );
+       // Events
+       this.hoursValuePicker.connect( this, { choose: [ 'emit', 'days' ] } );
+       this.daysValuePicker.connect( this, { choose: [ 'emit', 'days' ] } );
 
-               // Initialize
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-datePopupWidget' )
-                       .append(
-                               this.$label
-                                       .addClass( 'mw-rcfilters-ui-datePopupWidget-title' ),
-                               this.hoursValuePicker.$element,
-                               this.daysValuePicker.$element
-                       );
-       };
+       // Initialize
+       this.$element
+               .addClass( 'mw-rcfilters-ui-datePopupWidget' )
+               .append(
+                       this.$label
+                               .addClass( 'mw-rcfilters-ui-datePopupWidget-title' ),
+                       this.hoursValuePicker.$element,
+                       this.daysValuePicker.$element
+               );
+};
 
-       /* Initialization */
+/* Initialization */
 
-       OO.inheritClass( DatePopupWidget, OO.ui.Widget );
-       OO.mixinClass( DatePopupWidget, OO.ui.mixin.LabelElement );
+OO.inheritClass( DatePopupWidget, OO.ui.Widget );
+OO.mixinClass( DatePopupWidget, OO.ui.mixin.LabelElement );
 
-       /* Events */
+/* Events */
 
-       /**
       * @event days
       * @param {string} name Item name
       *
       * A days item was chosen
       */
+/**
+ * @event days
+ * @param {string} name Item name
+ *
+ * A days item was chosen
+ */
 
-       module.exports = DatePopupWidget;
-}() );
+module.exports = DatePopupWidget;
index 1327755..fb591d0 100644 (file)
@@ -1,85 +1,83 @@
-( function () {
-       /**
-        * A button to configure highlight for a filter item
-        *
-        * @class mw.rcfilters.ui.FilterItemHighlightButton
-        * @extends OO.ui.PopupButtonWidget
-        *
-        * @constructor
-        * @param {mw.rcfilters.Controller} controller RCFilters controller
-        * @param {mw.rcfilters.dm.FilterItem} model Filter item model
-        * @param {mw.rcfilters.ui.HighlightPopupWidget} highlightPopup Shared highlight color picker
-        * @param {Object} [config] Configuration object
-        */
-       var FilterItemHighlightButton = function MwRcfiltersUiFilterItemHighlightButton( controller, model, highlightPopup, config ) {
-               config = config || {};
-
-               // Parent
-               FilterItemHighlightButton.parent.call( this, $.extend( true, {}, config, {
-                       icon: 'highlight',
-                       indicator: 'down'
-               } ) );
-
-               this.controller = controller;
-               this.model = model;
-               this.popup = highlightPopup;
-
-               // Event
-               this.model.connect( this, { update: 'updateUiBasedOnModel' } );
-               // This lives inside a MenuOptionWidget, which intercepts mousedown
-               // to select the item. We want to prevent that when we click the highlight
-               // button
-               this.$element.on( 'mousedown', function ( e ) {
-                       e.stopPropagation();
-               } );
-
-               this.updateUiBasedOnModel();
-
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-filterItemHighlightButton' );
-       };
-
-       /* Initialization */
-
-       OO.inheritClass( FilterItemHighlightButton, OO.ui.PopupButtonWidget );
-
-       /* Static Properties */
-
-       /**
-        * @static
-        */
-       FilterItemHighlightButton.static.cancelButtonMouseDownEvents = true;
-
-       /* Methods */
-
-       FilterItemHighlightButton.prototype.onAction = function () {
-               this.popup.setAssociatedButton( this );
-               this.popup.setFilterItem( this.model );
-
-               // Parent method
-               FilterItemHighlightButton.parent.prototype.onAction.call( this );
-       };
-
-       /**
-        * Respond to item model update event
-        */
-       FilterItemHighlightButton.prototype.updateUiBasedOnModel = function () {
-               var currentColor = this.model.getHighlightColor(),
-                       widget = this;
-
-               this.$icon.toggleClass(
-                       'mw-rcfilters-ui-filterItemHighlightButton-circle',
-                       currentColor !== null
-               );
-
-               mw.rcfilters.HighlightColors.forEach( function ( c ) {
-                       widget.$icon
-                               .toggleClass(
-                                       'mw-rcfilters-ui-filterItemHighlightButton-circle-color-' + c,
-                                       c === currentColor
-                               );
-               } );
-       };
-
-       module.exports = FilterItemHighlightButton;
-}() );
+/**
+ * A button to configure highlight for a filter item
+ *
+ * @class mw.rcfilters.ui.FilterItemHighlightButton
+ * @extends OO.ui.PopupButtonWidget
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller RCFilters controller
+ * @param {mw.rcfilters.dm.FilterItem} model Filter item model
+ * @param {mw.rcfilters.ui.HighlightPopupWidget} highlightPopup Shared highlight color picker
+ * @param {Object} [config] Configuration object
+ */
+var FilterItemHighlightButton = function MwRcfiltersUiFilterItemHighlightButton( controller, model, highlightPopup, config ) {
+       config = config || {};
+
+       // Parent
+       FilterItemHighlightButton.parent.call( this, $.extend( true, {}, config, {
+               icon: 'highlight',
+               indicator: 'down'
+       } ) );
+
+       this.controller = controller;
+       this.model = model;
+       this.popup = highlightPopup;
+
+       // Event
+       this.model.connect( this, { update: 'updateUiBasedOnModel' } );
+       // This lives inside a MenuOptionWidget, which intercepts mousedown
+       // to select the item. We want to prevent that when we click the highlight
+       // button
+       this.$element.on( 'mousedown', function ( e ) {
+               e.stopPropagation();
+       } );
+
+       this.updateUiBasedOnModel();
+
+       this.$element
+               .addClass( 'mw-rcfilters-ui-filterItemHighlightButton' );
+};
+
+/* Initialization */
+
+OO.inheritClass( FilterItemHighlightButton, OO.ui.PopupButtonWidget );
+
+/* Static Properties */
+
+/**
+ * @static
+ */
+FilterItemHighlightButton.static.cancelButtonMouseDownEvents = true;
+
+/* Methods */
+
+FilterItemHighlightButton.prototype.onAction = function () {
+       this.popup.setAssociatedButton( this );
+       this.popup.setFilterItem( this.model );
+
+       // Parent method
+       FilterItemHighlightButton.parent.prototype.onAction.call( this );
+};
+
+/**
+ * Respond to item model update event
+ */
+FilterItemHighlightButton.prototype.updateUiBasedOnModel = function () {
+       var currentColor = this.model.getHighlightColor(),
+               widget = this;
+
+       this.$icon.toggleClass(
+               'mw-rcfilters-ui-filterItemHighlightButton-circle',
+               currentColor !== null
+       );
+
+       mw.rcfilters.HighlightColors.forEach( function ( c ) {
+               widget.$icon
+                       .toggleClass(
+                               'mw-rcfilters-ui-filterItemHighlightButton-circle-color-' + c,
+                               c === currentColor
+                       );
+       } );
+};
+
+module.exports = FilterItemHighlightButton;
index 1396341..3735af2 100644 (file)
-( function () {
-       /**
-        * Menu header for the RCFilters filters menu
-        *
-        * @class mw.rcfilters.ui.FilterMenuHeaderWidget
-        * @extends OO.ui.Widget
-        *
-        * @constructor
-        * @param {mw.rcfilters.Controller} controller Controller
-        * @param {mw.rcfilters.dm.FiltersViewModel} model View model
-        * @param {Object} config Configuration object
-        * @cfg {jQuery} [$overlay] A jQuery object serving as overlay for popups
-        */
-       var FilterMenuHeaderWidget = function MwRcfiltersUiFilterMenuHeaderWidget( controller, model, config ) {
-               config = config || {};
-
-               this.controller = controller;
-               this.model = model;
-               this.$overlay = config.$overlay || this.$element;
-
-               // Parent
-               FilterMenuHeaderWidget.parent.call( this, config );
-               OO.ui.mixin.LabelElement.call( this, $.extend( {
-                       label: mw.msg( 'rcfilters-filterlist-title' ),
-                       $label: $( '<div>' )
-                               .addClass( 'mw-rcfilters-ui-filterMenuHeaderWidget-title' )
-               }, config ) );
-
-               // "Back" to default view button
-               this.backButton = new OO.ui.ButtonWidget( {
-                       icon: 'previous',
-                       framed: false,
-                       title: mw.msg( 'rcfilters-view-return-to-default-tooltip' ),
-                       classes: [ 'mw-rcfilters-ui-filterMenuHeaderWidget-backButton' ]
-               } );
-               this.backButton.toggle( this.model.getCurrentView() !== 'default' );
-
-               // Help icon for Tagged edits
-               this.helpIcon = new OO.ui.ButtonWidget( {
-                       icon: 'helpNotice',
-                       framed: false,
-                       title: mw.msg( 'rcfilters-view-tags-help-icon-tooltip' ),
-                       classes: [ 'mw-rcfilters-ui-filterMenuHeaderWidget-helpIcon' ],
-                       href: mw.util.getUrl( 'Special:Tags' ),
-                       target: '_blank'
-               } );
-               this.helpIcon.toggle( this.model.getCurrentView() === 'tags' );
-
-               // Highlight button
-               this.highlightButton = new OO.ui.ToggleButtonWidget( {
-                       icon: 'highlight',
-                       label: mw.message( 'rcfilters-highlightbutton-title' ).text(),
-                       classes: [ 'mw-rcfilters-ui-filterMenuHeaderWidget-hightlightButton' ]
-               } );
-
-               // Invert namespaces button
-               this.invertNamespacesButton = new OO.ui.ToggleButtonWidget( {
-                       icon: '',
-                       classes: [ 'mw-rcfilters-ui-filterMenuHeaderWidget-invertNamespacesButton' ]
-               } );
-               this.invertNamespacesButton.toggle( this.model.getCurrentView() === 'namespaces' );
-
-               // Events
-               this.backButton.connect( this, { click: 'onBackButtonClick' } );
-               this.highlightButton
-                       .connect( this, { click: 'onHighlightButtonClick' } );
-               this.invertNamespacesButton
-                       .connect( this, { click: 'onInvertNamespacesButtonClick' } );
-               this.model.connect( this, {
-                       highlightChange: 'onModelHighlightChange',
-                       searchChange: 'onModelSearchChange',
-                       initialize: 'onModelInitialize'
-               } );
-               this.view = this.model.getCurrentView();
-
-               // Initialize
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-filterMenuHeaderWidget' )
-                       .append(
-                               $( '<div>' )
-                                       .addClass( 'mw-rcfilters-ui-table' )
-                                       .addClass( 'mw-rcfilters-ui-filterMenuHeaderWidget-header' )
-                                       .append(
-                                               $( '<div>' )
-                                                       .addClass( 'mw-rcfilters-ui-row' )
-                                                       .append(
-                                                               $( '<div>' )
-                                                                       .addClass( 'mw-rcfilters-ui-cell' )
-                                                                       .addClass( 'mw-rcfilters-ui-filterMenuHeaderWidget-header-back' )
-                                                                       .append( this.backButton.$element ),
-                                                               $( '<div>' )
-                                                                       .addClass( 'mw-rcfilters-ui-cell' )
-                                                                       .addClass( 'mw-rcfilters-ui-filterMenuHeaderWidget-header-title' )
-                                                                       .append( this.$label, this.helpIcon.$element ),
-                                                               $( '<div>' )
-                                                                       .addClass( 'mw-rcfilters-ui-cell' )
-                                                                       .addClass( 'mw-rcfilters-ui-filterMenuHeaderWidget-header-invert' )
-                                                                       .append( this.invertNamespacesButton.$element ),
-                                                               $( '<div>' )
-                                                                       .addClass( 'mw-rcfilters-ui-cell' )
-                                                                       .addClass( 'mw-rcfilters-ui-filterMenuHeaderWidget-header-highlight' )
-                                                                       .append( this.highlightButton.$element )
-                                                       )
-                                       )
-                       );
-       };
-
-       /* Initialization */
-
-       OO.inheritClass( FilterMenuHeaderWidget, OO.ui.Widget );
-       OO.mixinClass( FilterMenuHeaderWidget, OO.ui.mixin.LabelElement );
-
-       /* Methods */
-
-       /**
-        * Respond to model initialization event
-        *
-        * Note: need to wait for initialization before getting the invertModel
-        * and registering its update event. Creating all the models before the UI
-        * would help with that.
-        */
-       FilterMenuHeaderWidget.prototype.onModelInitialize = function () {
-               this.invertModel = this.model.getInvertModel();
-               this.updateInvertButton();
-               this.invertModel.connect( this, { update: 'updateInvertButton' } );
-       };
-
-       /**
-        * Respond to model update event
-        */
-       FilterMenuHeaderWidget.prototype.onModelSearchChange = function () {
-               var currentView = this.model.getCurrentView();
-
-               if ( this.view !== currentView ) {
-                       this.setLabel( this.model.getViewTitle( currentView ) );
-
-                       this.invertNamespacesButton.toggle( currentView === 'namespaces' );
-                       this.backButton.toggle( currentView !== 'default' );
-                       this.helpIcon.toggle( currentView === 'tags' );
-                       this.view = currentView;
-               }
-       };
-
-       /**
-        * Respond to model highlight change event
-        *
-        * @param {boolean} highlightEnabled Highlight is enabled
-        */
-       FilterMenuHeaderWidget.prototype.onModelHighlightChange = function ( highlightEnabled ) {
-               this.highlightButton.setActive( highlightEnabled );
-       };
-
-       /**
-        * Update the state of the invert button
-        */
-       FilterMenuHeaderWidget.prototype.updateInvertButton = function () {
-               this.invertNamespacesButton.setActive( this.invertModel.isSelected() );
-               this.invertNamespacesButton.setLabel(
-                       this.invertModel.isSelected() ?
-                               mw.msg( 'rcfilters-exclude-button-on' ) :
-                               mw.msg( 'rcfilters-exclude-button-off' )
+/**
+ * Menu header for the RCFilters filters menu
+ *
+ * @class mw.rcfilters.ui.FilterMenuHeaderWidget
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller Controller
+ * @param {mw.rcfilters.dm.FiltersViewModel} model View model
+ * @param {Object} config Configuration object
+ * @cfg {jQuery} [$overlay] A jQuery object serving as overlay for popups
+ */
+var FilterMenuHeaderWidget = function MwRcfiltersUiFilterMenuHeaderWidget( controller, model, config ) {
+       config = config || {};
+
+       this.controller = controller;
+       this.model = model;
+       this.$overlay = config.$overlay || this.$element;
+
+       // Parent
+       FilterMenuHeaderWidget.parent.call( this, config );
+       OO.ui.mixin.LabelElement.call( this, $.extend( {
+               label: mw.msg( 'rcfilters-filterlist-title' ),
+               $label: $( '<div>' )
+                       .addClass( 'mw-rcfilters-ui-filterMenuHeaderWidget-title' )
+       }, config ) );
+
+       // "Back" to default view button
+       this.backButton = new OO.ui.ButtonWidget( {
+               icon: 'previous',
+               framed: false,
+               title: mw.msg( 'rcfilters-view-return-to-default-tooltip' ),
+               classes: [ 'mw-rcfilters-ui-filterMenuHeaderWidget-backButton' ]
+       } );
+       this.backButton.toggle( this.model.getCurrentView() !== 'default' );
+
+       // Help icon for Tagged edits
+       this.helpIcon = new OO.ui.ButtonWidget( {
+               icon: 'helpNotice',
+               framed: false,
+               title: mw.msg( 'rcfilters-view-tags-help-icon-tooltip' ),
+               classes: [ 'mw-rcfilters-ui-filterMenuHeaderWidget-helpIcon' ],
+               href: mw.util.getUrl( 'Special:Tags' ),
+               target: '_blank'
+       } );
+       this.helpIcon.toggle( this.model.getCurrentView() === 'tags' );
+
+       // Highlight button
+       this.highlightButton = new OO.ui.ToggleButtonWidget( {
+               icon: 'highlight',
+               label: mw.message( 'rcfilters-highlightbutton-title' ).text(),
+               classes: [ 'mw-rcfilters-ui-filterMenuHeaderWidget-hightlightButton' ]
+       } );
+
+       // Invert namespaces button
+       this.invertNamespacesButton = new OO.ui.ToggleButtonWidget( {
+               icon: '',
+               classes: [ 'mw-rcfilters-ui-filterMenuHeaderWidget-invertNamespacesButton' ]
+       } );
+       this.invertNamespacesButton.toggle( this.model.getCurrentView() === 'namespaces' );
+
+       // Events
+       this.backButton.connect( this, { click: 'onBackButtonClick' } );
+       this.highlightButton
+               .connect( this, { click: 'onHighlightButtonClick' } );
+       this.invertNamespacesButton
+               .connect( this, { click: 'onInvertNamespacesButtonClick' } );
+       this.model.connect( this, {
+               highlightChange: 'onModelHighlightChange',
+               searchChange: 'onModelSearchChange',
+               initialize: 'onModelInitialize'
+       } );
+       this.view = this.model.getCurrentView();
+
+       // Initialize
+       this.$element
+               .addClass( 'mw-rcfilters-ui-filterMenuHeaderWidget' )
+               .append(
+                       $( '<div>' )
+                               .addClass( 'mw-rcfilters-ui-table' )
+                               .addClass( 'mw-rcfilters-ui-filterMenuHeaderWidget-header' )
+                               .append(
+                                       $( '<div>' )
+                                               .addClass( 'mw-rcfilters-ui-row' )
+                                               .append(
+                                                       $( '<div>' )
+                                                               .addClass( 'mw-rcfilters-ui-cell' )
+                                                               .addClass( 'mw-rcfilters-ui-filterMenuHeaderWidget-header-back' )
+                                                               .append( this.backButton.$element ),
+                                                       $( '<div>' )
+                                                               .addClass( 'mw-rcfilters-ui-cell' )
+                                                               .addClass( 'mw-rcfilters-ui-filterMenuHeaderWidget-header-title' )
+                                                               .append( this.$label, this.helpIcon.$element ),
+                                                       $( '<div>' )
+                                                               .addClass( 'mw-rcfilters-ui-cell' )
+                                                               .addClass( 'mw-rcfilters-ui-filterMenuHeaderWidget-header-invert' )
+                                                               .append( this.invertNamespacesButton.$element ),
+                                                       $( '<div>' )
+                                                               .addClass( 'mw-rcfilters-ui-cell' )
+                                                               .addClass( 'mw-rcfilters-ui-filterMenuHeaderWidget-header-highlight' )
+                                                               .append( this.highlightButton.$element )
+                                               )
+                               )
                );
-       };
-
-       FilterMenuHeaderWidget.prototype.onBackButtonClick = function () {
-               this.controller.switchView( 'default' );
-       };
-
-       /**
-        * Respond to highlight button click
-        */
-       FilterMenuHeaderWidget.prototype.onHighlightButtonClick = function () {
-               this.controller.toggleHighlight();
-       };
-
-       /**
-        * Respond to highlight button click
-        */
-       FilterMenuHeaderWidget.prototype.onInvertNamespacesButtonClick = function () {
-               this.controller.toggleInvertedNamespaces();
-       };
-
-       module.exports = FilterMenuHeaderWidget;
-}() );
+};
+
+/* Initialization */
+
+OO.inheritClass( FilterMenuHeaderWidget, OO.ui.Widget );
+OO.mixinClass( FilterMenuHeaderWidget, OO.ui.mixin.LabelElement );
+
+/* Methods */
+
+/**
+ * Respond to model initialization event
+ *
+ * Note: need to wait for initialization before getting the invertModel
+ * and registering its update event. Creating all the models before the UI
+ * would help with that.
+ */
+FilterMenuHeaderWidget.prototype.onModelInitialize = function () {
+       this.invertModel = this.model.getInvertModel();
+       this.updateInvertButton();
+       this.invertModel.connect( this, { update: 'updateInvertButton' } );
+};
+
+/**
+ * Respond to model update event
+ */
+FilterMenuHeaderWidget.prototype.onModelSearchChange = function () {
+       var currentView = this.model.getCurrentView();
+
+       if ( this.view !== currentView ) {
+               this.setLabel( this.model.getViewTitle( currentView ) );
+
+               this.invertNamespacesButton.toggle( currentView === 'namespaces' );
+               this.backButton.toggle( currentView !== 'default' );
+               this.helpIcon.toggle( currentView === 'tags' );
+               this.view = currentView;
+       }
+};
+
+/**
+ * Respond to model highlight change event
+ *
+ * @param {boolean} highlightEnabled Highlight is enabled
+ */
+FilterMenuHeaderWidget.prototype.onModelHighlightChange = function ( highlightEnabled ) {
+       this.highlightButton.setActive( highlightEnabled );
+};
+
+/**
+ * Update the state of the invert button
+ */
+FilterMenuHeaderWidget.prototype.updateInvertButton = function () {
+       this.invertNamespacesButton.setActive( this.invertModel.isSelected() );
+       this.invertNamespacesButton.setLabel(
+               this.invertModel.isSelected() ?
+                       mw.msg( 'rcfilters-exclude-button-on' ) :
+                       mw.msg( 'rcfilters-exclude-button-off' )
+       );
+};
+
+FilterMenuHeaderWidget.prototype.onBackButtonClick = function () {
+       this.controller.switchView( 'default' );
+};
+
+/**
+ * Respond to highlight button click
+ */
+FilterMenuHeaderWidget.prototype.onHighlightButtonClick = function () {
+       this.controller.toggleHighlight();
+};
+
+/**
+ * Respond to highlight button click
+ */
+FilterMenuHeaderWidget.prototype.onInvertNamespacesButtonClick = function () {
+       this.controller.toggleInvertedNamespaces();
+};
+
+module.exports = FilterMenuHeaderWidget;
index 4080f4d..b4b0e9d 100644 (file)
@@ -1,96 +1,94 @@
-( function () {
-       var ItemMenuOptionWidget = require( './ItemMenuOptionWidget.js' ),
-               FilterMenuOptionWidget;
+var ItemMenuOptionWidget = require( './ItemMenuOptionWidget.js' ),
+       FilterMenuOptionWidget;
 
-       /**
       * A widget representing a single toggle filter
       *
       * @class mw.rcfilters.ui.FilterMenuOptionWidget
       * @extends mw.rcfilters.ui.ItemMenuOptionWidget
       *
       * @constructor
       * @param {mw.rcfilters.Controller} controller RCFilters controller
       * @param {mw.rcfilters.dm.FiltersViewModel} filtersViewModel
       * @param {mw.rcfilters.dm.FilterItem} invertModel
       * @param {mw.rcfilters.dm.FilterItem} itemModel Filter item model
       * @param {mw.rcfilters.ui.HighlightPopupWidget} highlightPopup Shared highlight color picker popup
       * @param {Object} config Configuration object
       */
-       FilterMenuOptionWidget = function MwRcfiltersUiFilterMenuOptionWidget(
-               controller, filtersViewModel, invertModel, itemModel, highlightPopup, config
-       ) {
-               config = config || {};
+/**
+ * A widget representing a single toggle filter
+ *
+ * @class mw.rcfilters.ui.FilterMenuOptionWidget
+ * @extends mw.rcfilters.ui.ItemMenuOptionWidget
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller RCFilters controller
+ * @param {mw.rcfilters.dm.FiltersViewModel} filtersViewModel
+ * @param {mw.rcfilters.dm.FilterItem} invertModel
+ * @param {mw.rcfilters.dm.FilterItem} itemModel Filter item model
+ * @param {mw.rcfilters.ui.HighlightPopupWidget} highlightPopup Shared highlight color picker popup
+ * @param {Object} config Configuration object
+ */
+FilterMenuOptionWidget = function MwRcfiltersUiFilterMenuOptionWidget(
+       controller, filtersViewModel, invertModel, itemModel, highlightPopup, config
+) {
+       config = config || {};
 
-               this.controller = controller;
-               this.invertModel = invertModel;
-               this.model = itemModel;
+       this.controller = controller;
+       this.invertModel = invertModel;
+       this.model = itemModel;
 
-               // Parent
-               FilterMenuOptionWidget.parent.call( this, controller, filtersViewModel, this.invertModel, itemModel, highlightPopup, config );
+       // Parent
+       FilterMenuOptionWidget.parent.call( this, controller, filtersViewModel, this.invertModel, itemModel, highlightPopup, config );
 
-               // Event
-               this.model.getGroupModel().connect( this, { update: 'onGroupModelUpdate' } );
+       // Event
+       this.model.getGroupModel().connect( this, { update: 'onGroupModelUpdate' } );
 
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-filterMenuOptionWidget' );
-       };
+       this.$element
+               .addClass( 'mw-rcfilters-ui-filterMenuOptionWidget' );
+};
 
-       /* Initialization */
-       OO.inheritClass( FilterMenuOptionWidget, ItemMenuOptionWidget );
+/* Initialization */
+OO.inheritClass( FilterMenuOptionWidget, ItemMenuOptionWidget );
 
-       /* Static properties */
+/* Static properties */
 
-       // We do our own scrolling to top
-       FilterMenuOptionWidget.static.scrollIntoViewOnSelect = false;
+// We do our own scrolling to top
+FilterMenuOptionWidget.static.scrollIntoViewOnSelect = false;
 
-       /* Methods */
+/* Methods */
 
-       /**
       * @inheritdoc
       */
-       FilterMenuOptionWidget.prototype.updateUiBasedOnState = function () {
-               // Parent
-               FilterMenuOptionWidget.parent.prototype.updateUiBasedOnState.call( this );
+/**
+ * @inheritdoc
+ */
+FilterMenuOptionWidget.prototype.updateUiBasedOnState = function () {
+       // Parent
+       FilterMenuOptionWidget.parent.prototype.updateUiBasedOnState.call( this );
 
-               this.setCurrentMuteState();
-       };
+       this.setCurrentMuteState();
+};
 
-       /**
       * Respond to item group model update event
       */
-       FilterMenuOptionWidget.prototype.onGroupModelUpdate = function () {
-               this.setCurrentMuteState();
-       };
+/**
+ * Respond to item group model update event
+ */
+FilterMenuOptionWidget.prototype.onGroupModelUpdate = function () {
+       this.setCurrentMuteState();
+};
 
-       /**
-        * Set the current muted view of the widget based on its state
-        */
-       FilterMenuOptionWidget.prototype.setCurrentMuteState = function () {
-               if (
-                       this.model.getGroupModel().getView() === 'namespaces' &&
-                       this.invertModel.isSelected()
-               ) {
-                       // This is an inverted behavior than the other rules, specifically
-                       // for inverted namespaces
-                       this.setFlags( {
-                               muted: this.model.isSelected()
-                       } );
-               } else {
-                       this.setFlags( {
-                               muted: (
-                                       this.model.isConflicted() ||
-                                       (
-                                               // Item is also muted when any of the items in its group is active
-                                               this.model.getGroupModel().isActive() &&
-                                               // But it isn't selected
-                                               !this.model.isSelected() &&
-                                               // And also not included
-                                               !this.model.isIncluded()
-                                       )
+/**
+ * Set the current muted view of the widget based on its state
+ */
+FilterMenuOptionWidget.prototype.setCurrentMuteState = function () {
+       if (
+               this.model.getGroupModel().getView() === 'namespaces' &&
+               this.invertModel.isSelected()
+       ) {
+               // This is an inverted behavior than the other rules, specifically
+               // for inverted namespaces
+               this.setFlags( {
+                       muted: this.model.isSelected()
+               } );
+       } else {
+               this.setFlags( {
+                       muted: (
+                               this.model.isConflicted() ||
+                               (
+                                       // Item is also muted when any of the items in its group is active
+                                       this.model.getGroupModel().isActive() &&
+                                       // But it isn't selected
+                                       !this.model.isSelected() &&
+                                       // And also not included
+                                       !this.model.isIncluded()
                                )
-                       } );
-               }
-       };
+                       )
+               } );
+       }
+};
 
-       module.exports = FilterMenuOptionWidget;
-}() );
+module.exports = FilterMenuOptionWidget;
index 5b9e359..abcce81 100644 (file)
-( function () {
-       /**
-        * A widget representing a menu section for filter groups
-        *
-        * @class mw.rcfilters.ui.FilterMenuSectionOptionWidget
-        * @extends OO.ui.MenuSectionOptionWidget
-        *
-        * @constructor
-        * @param {mw.rcfilters.Controller} controller RCFilters controller
-        * @param {mw.rcfilters.dm.FilterGroup} model Filter group model
-        * @param {Object} config Configuration object
-        * @cfg {jQuery} [$overlay] Overlay
-        */
-       var FilterMenuSectionOptionWidget = function MwRcfiltersUiFilterMenuSectionOptionWidget( controller, model, config ) {
-               var whatsThisMessages,
-                       $header = $( '<div>' )
-                               .addClass( 'mw-rcfilters-ui-filterMenuSectionOptionWidget-header' ),
-                       $popupContent = $( '<div>' )
-                               .addClass( 'mw-rcfilters-ui-filterMenuSectionOptionWidget-whatsThisButton-popup-content' );
-
-               config = config || {};
-
-               this.controller = controller;
-               this.model = model;
-               this.$overlay = config.$overlay || this.$element;
-
-               // Parent
-               FilterMenuSectionOptionWidget.parent.call( this, $.extend( {
-                       label: this.model.getTitle(),
-                       $label: $( '<div>' )
-                               .addClass( 'mw-rcfilters-ui-filterMenuSectionOptionWidget-header-title' )
-               }, config ) );
-
-               $header.append( this.$label );
-
-               if ( this.model.hasWhatsThis() ) {
-                       whatsThisMessages = this.model.getWhatsThis();
-
-                       // Create popup
-                       if ( whatsThisMessages.header ) {
-                               $popupContent.append(
-                                       ( new OO.ui.LabelWidget( {
-                                               label: mw.msg( whatsThisMessages.header ),
-                                               classes: [ 'mw-rcfilters-ui-filterMenuSectionOptionWidget-whatsThisButton-popup-content-header' ]
-                                       } ) ).$element
-                               );
-                       }
-                       if ( whatsThisMessages.body ) {
-                               $popupContent.append(
-                                       ( new OO.ui.LabelWidget( {
-                                               label: mw.msg( whatsThisMessages.body ),
-                                               classes: [ 'mw-rcfilters-ui-filterMenuSectionOptionWidget-whatsThisButton-popup-content-body' ]
-                                       } ) ).$element
-                               );
-                       }
-                       if ( whatsThisMessages.linkText && whatsThisMessages.url ) {
-                               $popupContent.append(
-                                       ( new OO.ui.ButtonWidget( {
-                                               framed: false,
-                                               flags: [ 'progressive' ],
-                                               href: whatsThisMessages.url,
-                                               label: mw.msg( whatsThisMessages.linkText ),
-                                               classes: [ 'mw-rcfilters-ui-filterMenuSectionOptionWidget-whatsThisButton-popup-content-link' ]
-                                       } ) ).$element
-                               );
-                       }
-
-                       // Add button
-                       this.whatsThisButton = new OO.ui.PopupButtonWidget( {
-                               framed: false,
-                               label: mw.msg( 'rcfilters-filterlist-whatsthis' ),
-                               $overlay: this.$overlay,
-                               classes: [ 'mw-rcfilters-ui-filterMenuSectionOptionWidget-whatsThisButton' ],
-                               flags: [ 'progressive' ],
-                               popup: {
-                                       padded: false,
-                                       align: 'center',
-                                       position: 'above',
-                                       $content: $popupContent,
-                                       classes: [ 'mw-rcfilters-ui-filterMenuSectionOptionWidget-whatsThisButton-popup' ]
-                               }
-                       } );
-
-                       $header
-                               .append( this.whatsThisButton.$element );
+/**
+ * A widget representing a menu section for filter groups
+ *
+ * @class mw.rcfilters.ui.FilterMenuSectionOptionWidget
+ * @extends OO.ui.MenuSectionOptionWidget
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller RCFilters controller
+ * @param {mw.rcfilters.dm.FilterGroup} model Filter group model
+ * @param {Object} config Configuration object
+ * @cfg {jQuery} [$overlay] Overlay
+ */
+var FilterMenuSectionOptionWidget = function MwRcfiltersUiFilterMenuSectionOptionWidget( controller, model, config ) {
+       var whatsThisMessages,
+               $header = $( '<div>' )
+                       .addClass( 'mw-rcfilters-ui-filterMenuSectionOptionWidget-header' ),
+               $popupContent = $( '<div>' )
+                       .addClass( 'mw-rcfilters-ui-filterMenuSectionOptionWidget-whatsThisButton-popup-content' );
+
+       config = config || {};
+
+       this.controller = controller;
+       this.model = model;
+       this.$overlay = config.$overlay || this.$element;
+
+       // Parent
+       FilterMenuSectionOptionWidget.parent.call( this, $.extend( {
+               label: this.model.getTitle(),
+               $label: $( '<div>' )
+                       .addClass( 'mw-rcfilters-ui-filterMenuSectionOptionWidget-header-title' )
+       }, config ) );
+
+       $header.append( this.$label );
+
+       if ( this.model.hasWhatsThis() ) {
+               whatsThisMessages = this.model.getWhatsThis();
+
+               // Create popup
+               if ( whatsThisMessages.header ) {
+                       $popupContent.append(
+                               ( new OO.ui.LabelWidget( {
+                                       label: mw.msg( whatsThisMessages.header ),
+                                       classes: [ 'mw-rcfilters-ui-filterMenuSectionOptionWidget-whatsThisButton-popup-content-header' ]
+                               } ) ).$element
+                       );
+               }
+               if ( whatsThisMessages.body ) {
+                       $popupContent.append(
+                               ( new OO.ui.LabelWidget( {
+                                       label: mw.msg( whatsThisMessages.body ),
+                                       classes: [ 'mw-rcfilters-ui-filterMenuSectionOptionWidget-whatsThisButton-popup-content-body' ]
+                               } ) ).$element
+                       );
+               }
+               if ( whatsThisMessages.linkText && whatsThisMessages.url ) {
+                       $popupContent.append(
+                               ( new OO.ui.ButtonWidget( {
+                                       framed: false,
+                                       flags: [ 'progressive' ],
+                                       href: whatsThisMessages.url,
+                                       label: mw.msg( whatsThisMessages.linkText ),
+                                       classes: [ 'mw-rcfilters-ui-filterMenuSectionOptionWidget-whatsThisButton-popup-content-link' ]
+                               } ) ).$element
+                       );
                }
 
-               // Events
-               this.model.connect( this, { update: 'updateUiBasedOnState' } );
-
-               // Initialize
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-filterMenuSectionOptionWidget' )
-                       .addClass( 'mw-rcfilters-ui-filterMenuSectionOptionWidget-name-' + this.model.getName() )
-                       .append( $header );
-               this.updateUiBasedOnState();
-       };
-
-       /* Initialize */
-
-       OO.inheritClass( FilterMenuSectionOptionWidget, OO.ui.MenuSectionOptionWidget );
-
-       /* Methods */
-
-       /**
-        * Respond to model update event
-        */
-       FilterMenuSectionOptionWidget.prototype.updateUiBasedOnState = function () {
-               this.$element.toggleClass(
-                       'mw-rcfilters-ui-filterMenuSectionOptionWidget-active',
-                       this.model.isActive()
-               );
-               this.toggle( this.model.isVisible() );
-       };
-
-       /**
-        * Get the group name
-        *
-        * @return {string} Group name
-        */
-       FilterMenuSectionOptionWidget.prototype.getName = function () {
-               return this.model.getName();
-       };
-
-       module.exports = FilterMenuSectionOptionWidget;
-
-}() );
+               // Add button
+               this.whatsThisButton = new OO.ui.PopupButtonWidget( {
+                       framed: false,
+                       label: mw.msg( 'rcfilters-filterlist-whatsthis' ),
+                       $overlay: this.$overlay,
+                       classes: [ 'mw-rcfilters-ui-filterMenuSectionOptionWidget-whatsThisButton' ],
+                       flags: [ 'progressive' ],
+                       popup: {
+                               padded: false,
+                               align: 'center',
+                               position: 'above',
+                               $content: $popupContent,
+                               classes: [ 'mw-rcfilters-ui-filterMenuSectionOptionWidget-whatsThisButton-popup' ]
+                       }
+               } );
+
+               $header
+                       .append( this.whatsThisButton.$element );
+       }
+
+       // Events
+       this.model.connect( this, { update: 'updateUiBasedOnState' } );
+
+       // Initialize
+       this.$element
+               .addClass( 'mw-rcfilters-ui-filterMenuSectionOptionWidget' )
+               .addClass( 'mw-rcfilters-ui-filterMenuSectionOptionWidget-name-' + this.model.getName() )
+               .append( $header );
+       this.updateUiBasedOnState();
+};
+
+/* Initialize */
+
+OO.inheritClass( FilterMenuSectionOptionWidget, OO.ui.MenuSectionOptionWidget );
+
+/* Methods */
+
+/**
+ * Respond to model update event
+ */
+FilterMenuSectionOptionWidget.prototype.updateUiBasedOnState = function () {
+       this.$element.toggleClass(
+               'mw-rcfilters-ui-filterMenuSectionOptionWidget-active',
+               this.model.isActive()
+       );
+       this.toggle( this.model.isVisible() );
+};
+
+/**
+ * Get the group name
+ *
+ * @return {string} Group name
+ */
+FilterMenuSectionOptionWidget.prototype.getName = function () {
+       return this.model.getName();
+};
+
+module.exports = FilterMenuSectionOptionWidget;
index bda898b..98eea71 100644 (file)
@@ -1,50 +1,48 @@
-( function () {
-       var TagItemWidget = require( './TagItemWidget.js' ),
-               FilterTagItemWidget;
-
-       /**
-        * Extend OOUI's FilterTagItemWidget to also display a popup on hover.
-        *
-        * @class mw.rcfilters.ui.FilterTagItemWidget
-        * @extends mw.rcfilters.ui.TagItemWidget
-        *
-        * @constructor
-        * @param {mw.rcfilters.Controller} controller
-        * @param {mw.rcfilters.dm.FiltersViewModel} filtersViewModel
-        * @param {mw.rcfilters.dm.FilterItem} invertModel
-        * @param {mw.rcfilters.dm.FilterItem} itemModel Item model
-        * @param {Object} config Configuration object
-        */
-       FilterTagItemWidget = function MwRcfiltersUiFilterTagItemWidget(
-               controller, filtersViewModel, invertModel, itemModel, config
-       ) {
-               config = config || {};
-
-               FilterTagItemWidget.parent.call( this, controller, filtersViewModel, invertModel, itemModel, config );
-
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-filterTagItemWidget' );
-       };
-
-       /* Initialization */
-
-       OO.inheritClass( FilterTagItemWidget, TagItemWidget );
-
-       /* Methods */
-
-       /**
-        * @inheritdoc
-        */
-       FilterTagItemWidget.prototype.setCurrentMuteState = function () {
-               this.setFlags( {
-                       muted: (
-                               !this.itemModel.isSelected() ||
-                               this.itemModel.isIncluded() ||
-                               this.itemModel.isFullyCovered()
-                       ),
-                       invalid: this.itemModel.isSelected() && this.itemModel.isConflicted()
-               } );
-       };
-
-       module.exports = FilterTagItemWidget;
-}() );
+var TagItemWidget = require( './TagItemWidget.js' ),
+       FilterTagItemWidget;
+
+/**
+ * Extend OOUI's FilterTagItemWidget to also display a popup on hover.
+ *
+ * @class mw.rcfilters.ui.FilterTagItemWidget
+ * @extends mw.rcfilters.ui.TagItemWidget
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller
+ * @param {mw.rcfilters.dm.FiltersViewModel} filtersViewModel
+ * @param {mw.rcfilters.dm.FilterItem} invertModel
+ * @param {mw.rcfilters.dm.FilterItem} itemModel Item model
+ * @param {Object} config Configuration object
+ */
+FilterTagItemWidget = function MwRcfiltersUiFilterTagItemWidget(
+       controller, filtersViewModel, invertModel, itemModel, config
+) {
+       config = config || {};
+
+       FilterTagItemWidget.parent.call( this, controller, filtersViewModel, invertModel, itemModel, config );
+
+       this.$element
+               .addClass( 'mw-rcfilters-ui-filterTagItemWidget' );
+};
+
+/* Initialization */
+
+OO.inheritClass( FilterTagItemWidget, TagItemWidget );
+
+/* Methods */
+
+/**
+ * @inheritdoc
+ */
+FilterTagItemWidget.prototype.setCurrentMuteState = function () {
+       this.setFlags( {
+               muted: (
+                       !this.itemModel.isSelected() ||
+                       this.itemModel.isIncluded() ||
+                       this.itemModel.isFullyCovered()
+               ),
+               invalid: this.itemModel.isSelected() && this.itemModel.isConflicted()
+       } );
+};
+
+module.exports = FilterTagItemWidget;
index dc6fc12..085e22b 100644 (file)
-( function () {
-       var ViewSwitchWidget = require( './ViewSwitchWidget.js' ),
-               SaveFiltersPopupButtonWidget = require( './SaveFiltersPopupButtonWidget.js' ),
-               MenuSelectWidget = require( './MenuSelectWidget.js' ),
-               FilterTagItemWidget = require( './FilterTagItemWidget.js' ),
-               FilterTagMultiselectWidget;
-
-       /**
-        * List displaying all filter groups
-        *
-        * @class mw.rcfilters.ui.FilterTagMultiselectWidget
-        * @extends OO.ui.MenuTagMultiselectWidget
-        * @mixins OO.ui.mixin.PendingElement
-        *
-        * @constructor
-        * @param {mw.rcfilters.Controller} controller Controller
-        * @param {mw.rcfilters.dm.FiltersViewModel} model View model
-        * @param {mw.rcfilters.dm.SavedQueriesModel} savedQueriesModel Saved queries model
-        * @param {Object} config Configuration object
-        * @cfg {jQuery} [$overlay] A jQuery object serving as overlay for popups
-        * @cfg {jQuery} [$wrapper] A jQuery object for the wrapper of the general
-        *  system. If not given, falls back to this widget's $element
-        * @cfg {boolean} [collapsed] Filter area is collapsed
-        */
-       FilterTagMultiselectWidget = function MwRcfiltersUiFilterTagMultiselectWidget( controller, model, savedQueriesModel, config ) {
-               var rcFiltersRow,
-                       title = new OO.ui.LabelWidget( {
-                               label: mw.msg( 'rcfilters-activefilters' ),
-                               classes: [ 'mw-rcfilters-ui-filterTagMultiselectWidget-wrapper-content-title' ]
-                       } ),
-                       $contentWrapper = $( '<div>' )
-                               .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-wrapper' );
-
-               config = config || {};
-
-               this.controller = controller;
-               this.model = model;
-               this.queriesModel = savedQueriesModel;
-               this.$overlay = config.$overlay || this.$element;
-               this.$wrapper = config.$wrapper || this.$element;
-               this.matchingQuery = null;
-               this.currentView = this.model.getCurrentView();
-               this.collapsed = false;
-
-               // Parent
-               FilterTagMultiselectWidget.parent.call( this, $.extend( true, {
-                       label: mw.msg( 'rcfilters-filterlist-title' ),
-                       placeholder: mw.msg( 'rcfilters-empty-filter' ),
-                       inputPosition: 'outline',
-                       allowArbitrary: false,
-                       allowDisplayInvalidTags: false,
-                       allowReordering: false,
-                       $overlay: this.$overlay,
-                       menu: {
-                               // Our filtering is done through the model
-                               filterFromInput: false,
-                               hideWhenOutOfView: false,
-                               hideOnChoose: false,
-                               width: 650,
-                               footers: [
-                                       {
-                                               name: 'viewSelect',
-                                               sticky: false,
-                                               // View select menu, appears on default view only
-                                               $element: $( '<div>' )
-                                                       .append( new ViewSwitchWidget( this.controller, this.model ).$element ),
-                                               views: [ 'default' ]
-                                       },
-                                       {
-                                               name: 'feedback',
-                                               // Feedback footer, appears on all views
-                                               $element: $( '<div>' )
-                                                       .append(
-                                                               new OO.ui.ButtonWidget( {
-                                                                       framed: false,
-                                                                       icon: 'feedback',
-                                                                       flags: [ 'progressive' ],
-                                                                       label: mw.msg( 'rcfilters-filterlist-feedbacklink' ),
-                                                                       href: 'https://www.mediawiki.org/wiki/Help_talk:New_filters_for_edit_review'
-                                                               } ).$element
-                                                       )
-                                       }
-                               ]
-                       },
-                       input: {
-                               icon: 'menu',
-                               placeholder: mw.msg( 'rcfilters-search-placeholder' )
-                       }
-               }, config ) );
-
-               this.savedQueryTitle = new OO.ui.LabelWidget( {
-                       label: '',
-                       classes: [ 'mw-rcfilters-ui-filterTagMultiselectWidget-wrapper-content-savedQueryTitle' ]
-               } );
-
-               this.resetButton = new OO.ui.ButtonWidget( {
-                       framed: false,
-                       classes: [ 'mw-rcfilters-ui-filterTagMultiselectWidget-resetButton' ]
-               } );
-
-               this.hideShowButton = new OO.ui.ButtonWidget( {
-                       framed: false,
-                       flags: [ 'progressive' ],
-                       classes: [ 'mw-rcfilters-ui-filterTagMultiselectWidget-hideshowButton' ]
-               } );
-               this.toggleCollapsed( !!config.collapsed );
-
-               if ( !mw.user.isAnon() ) {
-                       this.saveQueryButton = new SaveFiltersPopupButtonWidget(
-                               this.controller,
-                               this.queriesModel,
+var ViewSwitchWidget = require( './ViewSwitchWidget.js' ),
+       SaveFiltersPopupButtonWidget = require( './SaveFiltersPopupButtonWidget.js' ),
+       MenuSelectWidget = require( './MenuSelectWidget.js' ),
+       FilterTagItemWidget = require( './FilterTagItemWidget.js' ),
+       FilterTagMultiselectWidget;
+
+/**
+ * List displaying all filter groups
+ *
+ * @class mw.rcfilters.ui.FilterTagMultiselectWidget
+ * @extends OO.ui.MenuTagMultiselectWidget
+ * @mixins OO.ui.mixin.PendingElement
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller Controller
+ * @param {mw.rcfilters.dm.FiltersViewModel} model View model
+ * @param {mw.rcfilters.dm.SavedQueriesModel} savedQueriesModel Saved queries model
+ * @param {Object} config Configuration object
+ * @cfg {jQuery} [$overlay] A jQuery object serving as overlay for popups
+ * @cfg {jQuery} [$wrapper] A jQuery object for the wrapper of the general
+ *  system. If not given, falls back to this widget's $element
+ * @cfg {boolean} [collapsed] Filter area is collapsed
+ */
+FilterTagMultiselectWidget = function MwRcfiltersUiFilterTagMultiselectWidget( controller, model, savedQueriesModel, config ) {
+       var rcFiltersRow,
+               title = new OO.ui.LabelWidget( {
+                       label: mw.msg( 'rcfilters-activefilters' ),
+                       classes: [ 'mw-rcfilters-ui-filterTagMultiselectWidget-wrapper-content-title' ]
+               } ),
+               $contentWrapper = $( '<div>' )
+                       .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-wrapper' );
+
+       config = config || {};
+
+       this.controller = controller;
+       this.model = model;
+       this.queriesModel = savedQueriesModel;
+       this.$overlay = config.$overlay || this.$element;
+       this.$wrapper = config.$wrapper || this.$element;
+       this.matchingQuery = null;
+       this.currentView = this.model.getCurrentView();
+       this.collapsed = false;
+
+       // Parent
+       FilterTagMultiselectWidget.parent.call( this, $.extend( true, {
+               label: mw.msg( 'rcfilters-filterlist-title' ),
+               placeholder: mw.msg( 'rcfilters-empty-filter' ),
+               inputPosition: 'outline',
+               allowArbitrary: false,
+               allowDisplayInvalidTags: false,
+               allowReordering: false,
+               $overlay: this.$overlay,
+               menu: {
+                       // Our filtering is done through the model
+                       filterFromInput: false,
+                       hideWhenOutOfView: false,
+                       hideOnChoose: false,
+                       width: 650,
+                       footers: [
+                               {
+                                       name: 'viewSelect',
+                                       sticky: false,
+                                       // View select menu, appears on default view only
+                                       $element: $( '<div>' )
+                                               .append( new ViewSwitchWidget( this.controller, this.model ).$element ),
+                                       views: [ 'default' ]
+                               },
                                {
-                                       $overlay: this.$overlay
+                                       name: 'feedback',
+                                       // Feedback footer, appears on all views
+                                       $element: $( '<div>' )
+                                               .append(
+                                                       new OO.ui.ButtonWidget( {
+                                                               framed: false,
+                                                               icon: 'feedback',
+                                                               flags: [ 'progressive' ],
+                                                               label: mw.msg( 'rcfilters-filterlist-feedbacklink' ),
+                                                               href: 'https://www.mediawiki.org/wiki/Help_talk:New_filters_for_edit_review'
+                                                       } ).$element
+                                               )
                                }
-                       );
-
-                       this.saveQueryButton.$element.on( 'mousedown', function ( e ) {
-                               e.stopPropagation();
-                       } );
-
-                       this.saveQueryButton.connect( this, {
-                               click: 'onSaveQueryButtonClick',
-                               saveCurrent: 'setSavedQueryVisibility'
-                       } );
-                       this.queriesModel.connect( this, {
-                               itemUpdate: 'onSavedQueriesItemUpdate',
-                               initialize: 'onSavedQueriesInitialize',
-                               default: 'reevaluateResetRestoreState'
-                       } );
+                       ]
+               },
+               input: {
+                       icon: 'menu',
+                       placeholder: mw.msg( 'rcfilters-search-placeholder' )
                }
+       }, config ) );
+
+       this.savedQueryTitle = new OO.ui.LabelWidget( {
+               label: '',
+               classes: [ 'mw-rcfilters-ui-filterTagMultiselectWidget-wrapper-content-savedQueryTitle' ]
+       } );
+
+       this.resetButton = new OO.ui.ButtonWidget( {
+               framed: false,
+               classes: [ 'mw-rcfilters-ui-filterTagMultiselectWidget-resetButton' ]
+       } );
+
+       this.hideShowButton = new OO.ui.ButtonWidget( {
+               framed: false,
+               flags: [ 'progressive' ],
+               classes: [ 'mw-rcfilters-ui-filterTagMultiselectWidget-hideshowButton' ]
+       } );
+       this.toggleCollapsed( !!config.collapsed );
+
+       if ( !mw.user.isAnon() ) {
+               this.saveQueryButton = new SaveFiltersPopupButtonWidget(
+                       this.controller,
+                       this.queriesModel,
+                       {
+                               $overlay: this.$overlay
+                       }
+               );
 
-               this.emptyFilterMessage = new OO.ui.LabelWidget( {
-                       label: mw.msg( 'rcfilters-empty-filter' ),
-                       classes: [ 'mw-rcfilters-ui-filterTagMultiselectWidget-emptyFilters' ]
-               } );
-               this.$content.append( this.emptyFilterMessage.$element );
-
-               // Events
-               this.resetButton.connect( this, { click: 'onResetButtonClick' } );
-               this.hideShowButton.connect( this, { click: 'onHideShowButtonClick' } );
-               // Stop propagation for mousedown, so that the widget doesn't
-               // trigger the focus on the input and scrolls up when we click the reset button
-               this.resetButton.$element.on( 'mousedown', function ( e ) {
-                       e.stopPropagation();
-               } );
-               this.hideShowButton.$element.on( 'mousedown', function ( e ) {
+               this.saveQueryButton.$element.on( 'mousedown', function ( e ) {
                        e.stopPropagation();
                } );
-               this.model.connect( this, {
-                       initialize: 'onModelInitialize',
-                       update: 'onModelUpdate',
-                       searchChange: 'onModelSearchChange',
-                       itemUpdate: 'onModelItemUpdate',
-                       highlightChange: 'onModelHighlightChange'
-               } );
-               this.input.connect( this, { change: 'onInputChange' } );
-
-               // The filter list and button should appear side by side regardless of how
-               // wide the button is; the button also changes its width depending
-               // on language and its state, so the safest way to present both side
-               // by side is with a table layout
-               rcFiltersRow = $( '<div>' )
-                       .addClass( 'mw-rcfilters-ui-row' )
-                       .append(
-                               this.$content
-                                       .addClass( 'mw-rcfilters-ui-cell' )
-                                       .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-cell-filters' )
-                       );
 
-               if ( !mw.user.isAnon() ) {
-                       rcFiltersRow.append(
-                               $( '<div>' )
-                                       .addClass( 'mw-rcfilters-ui-cell' )
-                                       .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-cell-save' )
-                                       .append( this.saveQueryButton.$element )
-                       );
-               }
-
-               // Add a selector at the right of the input
-               this.viewsSelectWidget = new OO.ui.ButtonSelectWidget( {
-                       classes: [ 'mw-rcfilters-ui-filterTagMultiselectWidget-views-select-widget' ],
-                       items: [
-                               new OO.ui.ButtonOptionWidget( {
-                                       framed: false,
-                                       data: 'namespaces',
-                                       icon: 'article',
-                                       label: mw.msg( 'namespaces' ),
-                                       title: mw.msg( 'rcfilters-view-namespaces-tooltip' )
-                               } ),
-                               new OO.ui.ButtonOptionWidget( {
-                                       framed: false,
-                                       data: 'tags',
-                                       icon: 'tag',
-                                       label: mw.msg( 'tags-title' ),
-                                       title: mw.msg( 'rcfilters-view-tags-tooltip' )
-                               } )
-                       ]
+               this.saveQueryButton.connect( this, {
+                       click: 'onSaveQueryButtonClick',
+                       saveCurrent: 'setSavedQueryVisibility'
                } );
-
-               // Rearrange the UI so the select widget is at the right of the input
-               this.$element.append(
-                       $( '<div>' )
-                               .addClass( 'mw-rcfilters-ui-table' )
-                               .append(
-                                       $( '<div>' )
-                                               .addClass( 'mw-rcfilters-ui-row' )
-                                               .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-views' )
-                                               .append(
-                                                       $( '<div>' )
-                                                               .addClass( 'mw-rcfilters-ui-cell' )
-                                                               .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-views-input' )
-                                                               .append( this.input.$element ),
-                                                       $( '<div>' )
-                                                               .addClass( 'mw-rcfilters-ui-cell' )
-                                                               .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-views-select' )
-                                                               .append( this.viewsSelectWidget.$element )
-                                               )
-                               )
+               this.queriesModel.connect( this, {
+                       itemUpdate: 'onSavedQueriesItemUpdate',
+                       initialize: 'onSavedQueriesInitialize',
+                       default: 'reevaluateResetRestoreState'
+               } );
+       }
+
+       this.emptyFilterMessage = new OO.ui.LabelWidget( {
+               label: mw.msg( 'rcfilters-empty-filter' ),
+               classes: [ 'mw-rcfilters-ui-filterTagMultiselectWidget-emptyFilters' ]
+       } );
+       this.$content.append( this.emptyFilterMessage.$element );
+
+       // Events
+       this.resetButton.connect( this, { click: 'onResetButtonClick' } );
+       this.hideShowButton.connect( this, { click: 'onHideShowButtonClick' } );
+       // Stop propagation for mousedown, so that the widget doesn't
+       // trigger the focus on the input and scrolls up when we click the reset button
+       this.resetButton.$element.on( 'mousedown', function ( e ) {
+               e.stopPropagation();
+       } );
+       this.hideShowButton.$element.on( 'mousedown', function ( e ) {
+               e.stopPropagation();
+       } );
+       this.model.connect( this, {
+               initialize: 'onModelInitialize',
+               update: 'onModelUpdate',
+               searchChange: 'onModelSearchChange',
+               itemUpdate: 'onModelItemUpdate',
+               highlightChange: 'onModelHighlightChange'
+       } );
+       this.input.connect( this, { change: 'onInputChange' } );
+
+       // The filter list and button should appear side by side regardless of how
+       // wide the button is; the button also changes its width depending
+       // on language and its state, so the safest way to present both side
+       // by side is with a table layout
+       rcFiltersRow = $( '<div>' )
+               .addClass( 'mw-rcfilters-ui-row' )
+               .append(
+                       this.$content
+                               .addClass( 'mw-rcfilters-ui-cell' )
+                               .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-cell-filters' )
                );
 
-               // Event
-               this.viewsSelectWidget.connect( this, { choose: 'onViewsSelectWidgetChoose' } );
-
+       if ( !mw.user.isAnon() ) {
                rcFiltersRow.append(
                        $( '<div>' )
                                .addClass( 'mw-rcfilters-ui-cell' )
-                               .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-cell-reset' )
-                               .append( this.resetButton.$element )
+                               .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-cell-save' )
+                               .append( this.saveQueryButton.$element )
                );
-
-               // Build the content
-               $contentWrapper.append(
-                       $( '<div>' )
-                               .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-wrapper-top' )
-                               .append(
-                                       $( '<div>' )
-                                               .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-wrapper-top-title' )
-                                               .append( title.$element ),
-                                       $( '<div>' )
-                                               .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-wrapper-top-queryName' )
-                                               .append( this.savedQueryTitle.$element ),
-                                       $( '<div>' )
-                                               .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-wrapper-top-hideshow' )
-                                               .append(
-                                                       this.hideShowButton.$element
-                                               )
-                               ),
-                       $( '<div>' )
-                               .addClass( 'mw-rcfilters-ui-table' )
-                               .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-wrapper-filters' )
-                               .append( rcFiltersRow )
-               );
-
-               // Initialize
-               this.$handle.append( $contentWrapper );
-               this.emptyFilterMessage.toggle( this.isEmpty() );
-               this.savedQueryTitle.toggle( false );
-
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget' );
-
-               this.reevaluateResetRestoreState();
-       };
-
-       /* Initialization */
-
-       OO.inheritClass( FilterTagMultiselectWidget, OO.ui.MenuTagMultiselectWidget );
-
-       /* Methods */
-
-       /**
-        * Override parent method to avoid unnecessary resize events.
-        */
-       FilterTagMultiselectWidget.prototype.updateIfHeightChanged = function () { };
-
-       /**
-        * Respond to view select widget choose event
-        *
-        * @param {OO.ui.ButtonOptionWidget} buttonOptionWidget Chosen widget
-        */
-       FilterTagMultiselectWidget.prototype.onViewsSelectWidgetChoose = function ( buttonOptionWidget ) {
-               this.controller.switchView( buttonOptionWidget.getData() );
-               this.viewsSelectWidget.selectItem( null );
+       }
+
+       // Add a selector at the right of the input
+       this.viewsSelectWidget = new OO.ui.ButtonSelectWidget( {
+               classes: [ 'mw-rcfilters-ui-filterTagMultiselectWidget-views-select-widget' ],
+               items: [
+                       new OO.ui.ButtonOptionWidget( {
+                               framed: false,
+                               data: 'namespaces',
+                               icon: 'article',
+                               label: mw.msg( 'namespaces' ),
+                               title: mw.msg( 'rcfilters-view-namespaces-tooltip' )
+                       } ),
+                       new OO.ui.ButtonOptionWidget( {
+                               framed: false,
+                               data: 'tags',
+                               icon: 'tag',
+                               label: mw.msg( 'tags-title' ),
+                               title: mw.msg( 'rcfilters-view-tags-tooltip' )
+                       } )
+               ]
+       } );
+
+       // Rearrange the UI so the select widget is at the right of the input
+       this.$element.append(
+               $( '<div>' )
+                       .addClass( 'mw-rcfilters-ui-table' )
+                       .append(
+                               $( '<div>' )
+                                       .addClass( 'mw-rcfilters-ui-row' )
+                                       .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-views' )
+                                       .append(
+                                               $( '<div>' )
+                                                       .addClass( 'mw-rcfilters-ui-cell' )
+                                                       .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-views-input' )
+                                                       .append( this.input.$element ),
+                                               $( '<div>' )
+                                                       .addClass( 'mw-rcfilters-ui-cell' )
+                                                       .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-views-select' )
+                                                       .append( this.viewsSelectWidget.$element )
+                                       )
+                       )
+       );
+
+       // Event
+       this.viewsSelectWidget.connect( this, { choose: 'onViewsSelectWidgetChoose' } );
+
+       rcFiltersRow.append(
+               $( '<div>' )
+                       .addClass( 'mw-rcfilters-ui-cell' )
+                       .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-cell-reset' )
+                       .append( this.resetButton.$element )
+       );
+
+       // Build the content
+       $contentWrapper.append(
+               $( '<div>' )
+                       .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-wrapper-top' )
+                       .append(
+                               $( '<div>' )
+                                       .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-wrapper-top-title' )
+                                       .append( title.$element ),
+                               $( '<div>' )
+                                       .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-wrapper-top-queryName' )
+                                       .append( this.savedQueryTitle.$element ),
+                               $( '<div>' )
+                                       .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-wrapper-top-hideshow' )
+                                       .append(
+                                               this.hideShowButton.$element
+                                       )
+                       ),
+               $( '<div>' )
+                       .addClass( 'mw-rcfilters-ui-table' )
+                       .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-wrapper-filters' )
+                       .append( rcFiltersRow )
+       );
+
+       // Initialize
+       this.$handle.append( $contentWrapper );
+       this.emptyFilterMessage.toggle( this.isEmpty() );
+       this.savedQueryTitle.toggle( false );
+
+       this.$element
+               .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget' );
+
+       this.reevaluateResetRestoreState();
+};
+
+/* Initialization */
+
+OO.inheritClass( FilterTagMultiselectWidget, OO.ui.MenuTagMultiselectWidget );
+
+/* Methods */
+
+/**
+ * Override parent method to avoid unnecessary resize events.
+ */
+FilterTagMultiselectWidget.prototype.updateIfHeightChanged = function () { };
+
+/**
+ * Respond to view select widget choose event
+ *
+ * @param {OO.ui.ButtonOptionWidget} buttonOptionWidget Chosen widget
+ */
+FilterTagMultiselectWidget.prototype.onViewsSelectWidgetChoose = function ( buttonOptionWidget ) {
+       this.controller.switchView( buttonOptionWidget.getData() );
+       this.viewsSelectWidget.selectItem( null );
+       this.focus();
+};
+
+/**
+ * Respond to model search change event
+ *
+ * @param {string} value Search value
+ */
+FilterTagMultiselectWidget.prototype.onModelSearchChange = function ( value ) {
+       this.input.setValue( value );
+};
+
+/**
+ * Respond to input change event
+ *
+ * @param {string} value Value of the input
+ */
+FilterTagMultiselectWidget.prototype.onInputChange = function ( value ) {
+       this.controller.setSearch( value );
+};
+
+/**
+ * Respond to query button click
+ */
+FilterTagMultiselectWidget.prototype.onSaveQueryButtonClick = function () {
+       this.getMenu().toggle( false );
+};
+
+/**
+ * Respond to save query model initialization
+ */
+FilterTagMultiselectWidget.prototype.onSavedQueriesInitialize = function () {
+       this.setSavedQueryVisibility();
+};
+
+/**
+ * Respond to save query item change. Mainly this is done to update the label in case
+ * a query item has been edited
+ *
+ * @param {mw.rcfilters.dm.SavedQueryItemModel} item Saved query item
+ */
+FilterTagMultiselectWidget.prototype.onSavedQueriesItemUpdate = function ( item ) {
+       if ( this.matchingQuery === item ) {
+               // This means we just edited the item that is currently matched
+               this.savedQueryTitle.setLabel( item.getLabel() );
+       }
+};
+
+/**
+ * Respond to menu toggle
+ *
+ * @param {boolean} isVisible Menu is visible
+ */
+FilterTagMultiselectWidget.prototype.onMenuToggle = function ( isVisible ) {
+       // Parent
+       FilterTagMultiselectWidget.parent.prototype.onMenuToggle.call( this );
+
+       if ( isVisible ) {
                this.focus();
-       };
-
-       /**
-        * Respond to model search change event
-        *
-        * @param {string} value Search value
-        */
-       FilterTagMultiselectWidget.prototype.onModelSearchChange = function ( value ) {
-               this.input.setValue( value );
-       };
-
-       /**
-        * Respond to input change event
-        *
-        * @param {string} value Value of the input
-        */
-       FilterTagMultiselectWidget.prototype.onInputChange = function ( value ) {
-               this.controller.setSearch( value );
-       };
-
-       /**
-        * Respond to query button click
-        */
-       FilterTagMultiselectWidget.prototype.onSaveQueryButtonClick = function () {
-               this.getMenu().toggle( false );
-       };
-
-       /**
-        * Respond to save query model initialization
-        */
-       FilterTagMultiselectWidget.prototype.onSavedQueriesInitialize = function () {
-               this.setSavedQueryVisibility();
-       };
-
-       /**
-        * Respond to save query item change. Mainly this is done to update the label in case
-        * a query item has been edited
-        *
-        * @param {mw.rcfilters.dm.SavedQueryItemModel} item Saved query item
-        */
-       FilterTagMultiselectWidget.prototype.onSavedQueriesItemUpdate = function ( item ) {
-               if ( this.matchingQuery === item ) {
-                       // This means we just edited the item that is currently matched
-                       this.savedQueryTitle.setLabel( item.getLabel() );
-               }
-       };
-
-       /**
-        * Respond to menu toggle
-        *
-        * @param {boolean} isVisible Menu is visible
-        */
-       FilterTagMultiselectWidget.prototype.onMenuToggle = function ( isVisible ) {
-               // Parent
-               FilterTagMultiselectWidget.parent.prototype.onMenuToggle.call( this );
-
-               if ( isVisible ) {
-                       this.focus();
-
-                       mw.hook( 'RcFilters.popup.open' ).fire();
-
-                       if ( !this.getMenu().findSelectedItem() ) {
-                               // If there are no selected items, scroll menu to top
-                               // This has to be in a setTimeout so the menu has time
-                               // to be positioned and fixed
-                               setTimeout(
-                                       function () {
-                                               this.getMenu().scrollToTop();
-                                       }.bind( this )
-                               );
-                       }
-               } else {
-                       // Clear selection
-                       this.selectTag( null );
 
-                       // Clear the search
-                       this.controller.setSearch( '' );
+               mw.hook( 'RcFilters.popup.open' ).fire();
 
-                       // Log filter grouping
-                       this.controller.trackFilterGroupings( 'filtermenu' );
-
-                       this.blur();
-               }
-
-               this.input.setIcon( isVisible ? 'search' : 'menu' );
-       };
-
-       /**
-        * @inheritdoc
-        */
-       FilterTagMultiselectWidget.prototype.onInputFocus = function () {
-               // Parent
-               FilterTagMultiselectWidget.parent.prototype.onInputFocus.call( this );
-
-               // Only scroll to top of the viewport if:
-               // - The widget is more than 20px from the top
-               // - The widget is not above the top of the viewport (do not scroll downwards)
-               //   (This isn't represented because >20 is, anyways and always, bigger than 0)
-               this.scrollToTop( this.$element, 0, { min: 20, max: Infinity } );
-       };
-
-       /**
-        * @inheritdoc
-        */
-       FilterTagMultiselectWidget.prototype.doInputEscape = function () {
-               // Parent
-               FilterTagMultiselectWidget.parent.prototype.doInputEscape.call( this );
-
-               // Blur the input
-               this.input.$input.trigger( 'blur' );
-       };
-
-       /**
-        * @inheritdoc
-        */
-       FilterTagMultiselectWidget.prototype.onMouseDown = function ( e ) {
-               if ( !this.collapsed && !this.isDisabled() && e.which === OO.ui.MouseButtons.LEFT ) {
-                       this.menu.toggle();
-
-                       return false;
-               }
-       };
-
-       /**
-        * @inheritdoc
-        */
-       FilterTagMultiselectWidget.prototype.onChangeTags = function () {
-               // If initialized, call parent method.
-               if ( this.controller.isInitialized() ) {
-                       FilterTagMultiselectWidget.parent.prototype.onChangeTags.call( this );
-               }
-
-               this.emptyFilterMessage.toggle( this.isEmpty() );
-       };
-
-       /**
-        * Respond to model initialize event
-        */
-       FilterTagMultiselectWidget.prototype.onModelInitialize = function () {
-               this.setSavedQueryVisibility();
-       };
-
-       /**
-        * Respond to model update event
-        */
-       FilterTagMultiselectWidget.prototype.onModelUpdate = function () {
-               this.updateElementsForView();
-       };
-
-       /**
-        * Update the elements in the widget to the current view
-        */
-       FilterTagMultiselectWidget.prototype.updateElementsForView = function () {
-               var view = this.model.getCurrentView(),
-                       inputValue = this.input.getValue().trim(),
-                       inputView = this.model.getViewByTrigger( inputValue.substr( 0, 1 ) );
-
-               if ( inputView !== 'default' ) {
-                       // We have a prefix already, remove it
-                       inputValue = inputValue.substr( 1 );
-               }
-
-               if ( inputView !== view ) {
-                       // Add the correct prefix
-                       inputValue = this.model.getViewTrigger( view ) + inputValue;
-               }
-
-               // Update input
-               this.input.setValue( inputValue );
-
-               if ( this.currentView !== view ) {
-                       this.scrollToTop( this.$element );
-                       this.currentView = view;
-               }
-       };
-
-       /**
-        * Set the visibility of the saved query button
-        */
-       FilterTagMultiselectWidget.prototype.setSavedQueryVisibility = function () {
-               if ( mw.user.isAnon() ) {
-                       return;
-               }
-
-               this.matchingQuery = this.controller.findQueryMatchingCurrentState();
-
-               this.savedQueryTitle.setLabel(
-                       this.matchingQuery ? this.matchingQuery.getLabel() : ''
-               );
-               this.savedQueryTitle.toggle( !!this.matchingQuery );
-               this.saveQueryButton.setDisabled( !!this.matchingQuery );
-               this.saveQueryButton.setTitle( !this.matchingQuery ?
-                       mw.msg( 'rcfilters-savedqueries-add-new-title' ) :
-                       mw.msg( 'rcfilters-savedqueries-already-saved' ) );
-
-               if ( this.matchingQuery ) {
-                       this.emphasize();
+               if ( !this.getMenu().findSelectedItem() ) {
+                       // If there are no selected items, scroll menu to top
+                       // This has to be in a setTimeout so the menu has time
+                       // to be positioned and fixed
+                       setTimeout(
+                               function () {
+                                       this.getMenu().scrollToTop();
+                               }.bind( this )
+                       );
                }
-       };
-
-       /**
-        * Respond to model itemUpdate event
-        * fixme: when a new state is applied to the model this function is called 60+ times in a row
-        *
-        * @param {mw.rcfilters.dm.FilterItem} item Filter item model
-        */
-       FilterTagMultiselectWidget.prototype.onModelItemUpdate = function ( item ) {
-               if ( !item.getGroupModel().isHidden() ) {
-                       if (
-                               item.isSelected() ||
-                               (
-                                       this.model.isHighlightEnabled() &&
-                                       item.getHighlightColor()
-                               )
-                       ) {
-                               this.addTag( item.getName(), item.getLabel() );
-                       } else {
-                               // Only attempt to remove the tag if we can find an item for it (T198140, T198231)
-                               if ( this.findItemFromData( item.getName() ) !== null ) {
-                                       this.removeTagByData( item.getName() );
-                               }
+       } else {
+               // Clear selection
+               this.selectTag( null );
+
+               // Clear the search
+               this.controller.setSearch( '' );
+
+               // Log filter grouping
+               this.controller.trackFilterGroupings( 'filtermenu' );
+
+               this.blur();
+       }
+
+       this.input.setIcon( isVisible ? 'search' : 'menu' );
+};
+
+/**
+ * @inheritdoc
+ */
+FilterTagMultiselectWidget.prototype.onInputFocus = function () {
+       // Parent
+       FilterTagMultiselectWidget.parent.prototype.onInputFocus.call( this );
+
+       // Only scroll to top of the viewport if:
+       // - The widget is more than 20px from the top
+       // - The widget is not above the top of the viewport (do not scroll downwards)
+       //   (This isn't represented because >20 is, anyways and always, bigger than 0)
+       this.scrollToTop( this.$element, 0, { min: 20, max: Infinity } );
+};
+
+/**
+ * @inheritdoc
+ */
+FilterTagMultiselectWidget.prototype.doInputEscape = function () {
+       // Parent
+       FilterTagMultiselectWidget.parent.prototype.doInputEscape.call( this );
+
+       // Blur the input
+       this.input.$input.trigger( 'blur' );
+};
+
+/**
+ * @inheritdoc
+ */
+FilterTagMultiselectWidget.prototype.onMouseDown = function ( e ) {
+       if ( !this.collapsed && !this.isDisabled() && e.which === OO.ui.MouseButtons.LEFT ) {
+               this.menu.toggle();
+
+               return false;
+       }
+};
+
+/**
+ * @inheritdoc
+ */
+FilterTagMultiselectWidget.prototype.onChangeTags = function () {
+       // If initialized, call parent method.
+       if ( this.controller.isInitialized() ) {
+               FilterTagMultiselectWidget.parent.prototype.onChangeTags.call( this );
+       }
+
+       this.emptyFilterMessage.toggle( this.isEmpty() );
+};
+
+/**
+ * Respond to model initialize event
+ */
+FilterTagMultiselectWidget.prototype.onModelInitialize = function () {
+       this.setSavedQueryVisibility();
+};
+
+/**
+ * Respond to model update event
+ */
+FilterTagMultiselectWidget.prototype.onModelUpdate = function () {
+       this.updateElementsForView();
+};
+
+/**
+ * Update the elements in the widget to the current view
+ */
+FilterTagMultiselectWidget.prototype.updateElementsForView = function () {
+       var view = this.model.getCurrentView(),
+               inputValue = this.input.getValue().trim(),
+               inputView = this.model.getViewByTrigger( inputValue.substr( 0, 1 ) );
+
+       if ( inputView !== 'default' ) {
+               // We have a prefix already, remove it
+               inputValue = inputValue.substr( 1 );
+       }
+
+       if ( inputView !== view ) {
+               // Add the correct prefix
+               inputValue = this.model.getViewTrigger( view ) + inputValue;
+       }
+
+       // Update input
+       this.input.setValue( inputValue );
+
+       if ( this.currentView !== view ) {
+               this.scrollToTop( this.$element );
+               this.currentView = view;
+       }
+};
+
+/**
+ * Set the visibility of the saved query button
+ */
+FilterTagMultiselectWidget.prototype.setSavedQueryVisibility = function () {
+       if ( mw.user.isAnon() ) {
+               return;
+       }
+
+       this.matchingQuery = this.controller.findQueryMatchingCurrentState();
+
+       this.savedQueryTitle.setLabel(
+               this.matchingQuery ? this.matchingQuery.getLabel() : ''
+       );
+       this.savedQueryTitle.toggle( !!this.matchingQuery );
+       this.saveQueryButton.setDisabled( !!this.matchingQuery );
+       this.saveQueryButton.setTitle( !this.matchingQuery ?
+               mw.msg( 'rcfilters-savedqueries-add-new-title' ) :
+               mw.msg( 'rcfilters-savedqueries-already-saved' ) );
+
+       if ( this.matchingQuery ) {
+               this.emphasize();
+       }
+};
+
+/**
+ * Respond to model itemUpdate event
+ * fixme: when a new state is applied to the model this function is called 60+ times in a row
+ *
+ * @param {mw.rcfilters.dm.FilterItem} item Filter item model
+ */
+FilterTagMultiselectWidget.prototype.onModelItemUpdate = function ( item ) {
+       if ( !item.getGroupModel().isHidden() ) {
+               if (
+                       item.isSelected() ||
+                       (
+                               this.model.isHighlightEnabled() &&
+                               item.getHighlightColor()
+                       )
+               ) {
+                       this.addTag( item.getName(), item.getLabel() );
+               } else {
+                       // Only attempt to remove the tag if we can find an item for it (T198140, T198231)
+                       if ( this.findItemFromData( item.getName() ) !== null ) {
+                               this.removeTagByData( item.getName() );
                        }
                }
-
-               this.setSavedQueryVisibility();
-
-               // Re-evaluate reset state
-               this.reevaluateResetRestoreState();
-       };
-
-       /**
-        * @inheritdoc
-        */
-       FilterTagMultiselectWidget.prototype.isAllowedData = function ( data ) {
-               return (
-                       this.model.getItemByName( data ) &&
-                       !this.isDuplicateData( data )
-               );
-       };
-
-       /**
-        * @inheritdoc
-        */
-       FilterTagMultiselectWidget.prototype.onMenuChoose = function ( item ) {
-               this.controller.toggleFilterSelect( item.model.getName() );
-
-               // Select the tag if it exists, or reset selection otherwise
-               this.selectTag( this.findItemFromData( item.model.getName() ) );
-
-               this.focus();
-       };
-
-       /**
-        * Respond to highlightChange event
-        *
-        * @param {boolean} isHighlightEnabled Highlight is enabled
-        */
-       FilterTagMultiselectWidget.prototype.onModelHighlightChange = function ( isHighlightEnabled ) {
-               var highlightedItems = this.model.getHighlightedItems();
-
-               if ( isHighlightEnabled ) {
-                       // Add capsule widgets
-                       highlightedItems.forEach( function ( filterItem ) {
-                               this.addTag( filterItem.getName(), filterItem.getLabel() );
-                       }.bind( this ) );
-               } else {
-                       // Remove capsule widgets if they're not selected
-                       highlightedItems.forEach( function ( filterItem ) {
-                               if ( !filterItem.isSelected() ) {
-                                       // Only attempt to remove the tag if we can find an item for it (T198140, T198231)
-                                       if ( this.findItemFromData( filterItem.getName() ) !== null ) {
-                                               this.removeTagByData( filterItem.getName() );
-                                       }
+       }
+
+       this.setSavedQueryVisibility();
+
+       // Re-evaluate reset state
+       this.reevaluateResetRestoreState();
+};
+
+/**
+ * @inheritdoc
+ */
+FilterTagMultiselectWidget.prototype.isAllowedData = function ( data ) {
+       return (
+               this.model.getItemByName( data ) &&
+               !this.isDuplicateData( data )
+       );
+};
+
+/**
+ * @inheritdoc
+ */
+FilterTagMultiselectWidget.prototype.onMenuChoose = function ( item ) {
+       this.controller.toggleFilterSelect( item.model.getName() );
+
+       // Select the tag if it exists, or reset selection otherwise
+       this.selectTag( this.findItemFromData( item.model.getName() ) );
+
+       this.focus();
+};
+
+/**
+ * Respond to highlightChange event
+ *
+ * @param {boolean} isHighlightEnabled Highlight is enabled
+ */
+FilterTagMultiselectWidget.prototype.onModelHighlightChange = function ( isHighlightEnabled ) {
+       var highlightedItems = this.model.getHighlightedItems();
+
+       if ( isHighlightEnabled ) {
+               // Add capsule widgets
+               highlightedItems.forEach( function ( filterItem ) {
+                       this.addTag( filterItem.getName(), filterItem.getLabel() );
+               }.bind( this ) );
+       } else {
+               // Remove capsule widgets if they're not selected
+               highlightedItems.forEach( function ( filterItem ) {
+                       if ( !filterItem.isSelected() ) {
+                               // Only attempt to remove the tag if we can find an item for it (T198140, T198231)
+                               if ( this.findItemFromData( filterItem.getName() ) !== null ) {
+                                       this.removeTagByData( filterItem.getName() );
                                }
-                       }.bind( this ) );
-               }
-
-               this.setSavedQueryVisibility();
-       };
-
-       /**
-        * @inheritdoc
-        */
-       FilterTagMultiselectWidget.prototype.onTagSelect = function ( tagItem ) {
-               var menuOption = this.menu.getItemFromModel( tagItem.getModel() );
-
-               this.menu.setUserSelecting( true );
-               // Parent method
-               FilterTagMultiselectWidget.parent.prototype.onTagSelect.call( this, tagItem );
-
-               // Switch view
-               this.controller.resetSearchForView( tagItem.getView() );
-
-               this.selectTag( tagItem );
-               this.scrollToTop( menuOption.$element );
-
-               this.menu.setUserSelecting( false );
-       };
-
-       /**
-        * Select a tag by reference. This is what OO.ui.SelectWidget is doing.
-        * If no items are given, reset selection from all.
-        *
-        * @param {mw.rcfilters.ui.FilterTagItemWidget} [item] Tag to select,
-        *  omit to deselect all
-        */
-       FilterTagMultiselectWidget.prototype.selectTag = function ( item ) {
-               var i, len, selected;
-
-               for ( i = 0, len = this.items.length; i < len; i++ ) {
-                       selected = this.items[ i ] === item;
-                       if ( this.items[ i ].isSelected() !== selected ) {
-                               this.items[ i ].toggleSelected( selected );
                        }
+               }.bind( this ) );
+       }
+
+       this.setSavedQueryVisibility();
+};
+
+/**
+ * @inheritdoc
+ */
+FilterTagMultiselectWidget.prototype.onTagSelect = function ( tagItem ) {
+       var menuOption = this.menu.getItemFromModel( tagItem.getModel() );
+
+       this.menu.setUserSelecting( true );
+       // Parent method
+       FilterTagMultiselectWidget.parent.prototype.onTagSelect.call( this, tagItem );
+
+       // Switch view
+       this.controller.resetSearchForView( tagItem.getView() );
+
+       this.selectTag( tagItem );
+       this.scrollToTop( menuOption.$element );
+
+       this.menu.setUserSelecting( false );
+};
+
+/**
+ * Select a tag by reference. This is what OO.ui.SelectWidget is doing.
+ * If no items are given, reset selection from all.
+ *
+ * @param {mw.rcfilters.ui.FilterTagItemWidget} [item] Tag to select,
+ *  omit to deselect all
+ */
+FilterTagMultiselectWidget.prototype.selectTag = function ( item ) {
+       var i, len, selected;
+
+       for ( i = 0, len = this.items.length; i < len; i++ ) {
+               selected = this.items[ i ] === item;
+               if ( this.items[ i ].isSelected() !== selected ) {
+                       this.items[ i ].toggleSelected( selected );
                }
-       };
-       /**
-        * @inheritdoc
-        */
-       FilterTagMultiselectWidget.prototype.onTagRemove = function ( tagItem ) {
-               // Parent method
-               FilterTagMultiselectWidget.parent.prototype.onTagRemove.call( this, tagItem );
-
-               this.controller.clearFilter( tagItem.getName() );
-
-               tagItem.destroy();
-       };
-
-       /**
-        * Respond to click event on the reset button
-        */
-       FilterTagMultiselectWidget.prototype.onResetButtonClick = function () {
-               if ( this.model.areVisibleFiltersEmpty() ) {
-                       // Reset to default filters
-                       this.controller.resetToDefaults();
-               } else {
-                       // Reset to have no filters
-                       this.controller.emptyFilters();
-               }
-       };
-
-       /**
-        * Respond to hide/show button click
-        */
-       FilterTagMultiselectWidget.prototype.onHideShowButtonClick = function () {
-               this.toggleCollapsed();
-       };
-
-       /**
-        * Toggle the collapsed state of the filters widget
-        *
-        * @param {boolean} isCollapsed Widget is collapsed
-        */
-       FilterTagMultiselectWidget.prototype.toggleCollapsed = function ( isCollapsed ) {
-               isCollapsed = isCollapsed === undefined ? !this.collapsed : !!isCollapsed;
-
-               this.collapsed = isCollapsed;
-
-               if ( isCollapsed ) {
-                       // If we are collapsing, close the menu, in case it was open
-                       // We should make sure the menu closes before the rest of the elements
-                       // are hidden, otherwise there is an unknown error in jQuery as ooui
-                       // sets and unsets properties on the input (which is hidden at that point)
-                       this.menu.toggle( false );
-               }
-               this.input.setDisabled( isCollapsed );
-               this.hideShowButton.setLabel( mw.msg(
-                       isCollapsed ? 'rcfilters-activefilters-show' : 'rcfilters-activefilters-hide'
-               ) );
-               this.hideShowButton.setTitle( mw.msg(
-                       isCollapsed ? 'rcfilters-activefilters-show-tooltip' : 'rcfilters-activefilters-hide-tooltip'
-               ) );
-
-               // Toggle the wrapper class, so we have min height values correctly throughout
-               this.$wrapper.toggleClass( 'mw-rcfilters-collapsed', isCollapsed );
-
-               // Save the state
-               this.controller.updateCollapsedState( isCollapsed );
-       };
-
-       /**
-        * Reevaluate the restore state for the widget between setting to defaults and clearing all filters
-        */
-       FilterTagMultiselectWidget.prototype.reevaluateResetRestoreState = function () {
-               var defaultsAreEmpty = this.controller.areDefaultsEmpty(),
-                       currFiltersAreEmpty = this.model.areVisibleFiltersEmpty(),
-                       hideResetButton = currFiltersAreEmpty && defaultsAreEmpty;
-
-               this.resetButton.setIcon(
-                       currFiltersAreEmpty ? 'history' : 'trash'
-               );
-
-               this.resetButton.setLabel(
-                       currFiltersAreEmpty ? mw.msg( 'rcfilters-restore-default-filters' ) : ''
-               );
-               this.resetButton.setTitle(
-                       currFiltersAreEmpty ? null : mw.msg( 'rcfilters-clear-all-filters' )
-               );
-
-               this.resetButton.toggle( !hideResetButton );
-               this.emptyFilterMessage.toggle( currFiltersAreEmpty );
-       };
-
-       /**
-        * @inheritdoc
-        */
-       FilterTagMultiselectWidget.prototype.createMenuWidget = function ( menuConfig ) {
-               return new MenuSelectWidget(
+       }
+};
+/**
+ * @inheritdoc
+ */
+FilterTagMultiselectWidget.prototype.onTagRemove = function ( tagItem ) {
+       // Parent method
+       FilterTagMultiselectWidget.parent.prototype.onTagRemove.call( this, tagItem );
+
+       this.controller.clearFilter( tagItem.getName() );
+
+       tagItem.destroy();
+};
+
+/**
+ * Respond to click event on the reset button
+ */
+FilterTagMultiselectWidget.prototype.onResetButtonClick = function () {
+       if ( this.model.areVisibleFiltersEmpty() ) {
+               // Reset to default filters
+               this.controller.resetToDefaults();
+       } else {
+               // Reset to have no filters
+               this.controller.emptyFilters();
+       }
+};
+
+/**
+ * Respond to hide/show button click
+ */
+FilterTagMultiselectWidget.prototype.onHideShowButtonClick = function () {
+       this.toggleCollapsed();
+};
+
+/**
+ * Toggle the collapsed state of the filters widget
+ *
+ * @param {boolean} isCollapsed Widget is collapsed
+ */
+FilterTagMultiselectWidget.prototype.toggleCollapsed = function ( isCollapsed ) {
+       isCollapsed = isCollapsed === undefined ? !this.collapsed : !!isCollapsed;
+
+       this.collapsed = isCollapsed;
+
+       if ( isCollapsed ) {
+               // If we are collapsing, close the menu, in case it was open
+               // We should make sure the menu closes before the rest of the elements
+               // are hidden, otherwise there is an unknown error in jQuery as ooui
+               // sets and unsets properties on the input (which is hidden at that point)
+               this.menu.toggle( false );
+       }
+       this.input.setDisabled( isCollapsed );
+       this.hideShowButton.setLabel( mw.msg(
+               isCollapsed ? 'rcfilters-activefilters-show' : 'rcfilters-activefilters-hide'
+       ) );
+       this.hideShowButton.setTitle( mw.msg(
+               isCollapsed ? 'rcfilters-activefilters-show-tooltip' : 'rcfilters-activefilters-hide-tooltip'
+       ) );
+
+       // Toggle the wrapper class, so we have min height values correctly throughout
+       this.$wrapper.toggleClass( 'mw-rcfilters-collapsed', isCollapsed );
+
+       // Save the state
+       this.controller.updateCollapsedState( isCollapsed );
+};
+
+/**
+ * Reevaluate the restore state for the widget between setting to defaults and clearing all filters
+ */
+FilterTagMultiselectWidget.prototype.reevaluateResetRestoreState = function () {
+       var defaultsAreEmpty = this.controller.areDefaultsEmpty(),
+               currFiltersAreEmpty = this.model.areVisibleFiltersEmpty(),
+               hideResetButton = currFiltersAreEmpty && defaultsAreEmpty;
+
+       this.resetButton.setIcon(
+               currFiltersAreEmpty ? 'history' : 'trash'
+       );
+
+       this.resetButton.setLabel(
+               currFiltersAreEmpty ? mw.msg( 'rcfilters-restore-default-filters' ) : ''
+       );
+       this.resetButton.setTitle(
+               currFiltersAreEmpty ? null : mw.msg( 'rcfilters-clear-all-filters' )
+       );
+
+       this.resetButton.toggle( !hideResetButton );
+       this.emptyFilterMessage.toggle( currFiltersAreEmpty );
+};
+
+/**
+ * @inheritdoc
+ */
+FilterTagMultiselectWidget.prototype.createMenuWidget = function ( menuConfig ) {
+       return new MenuSelectWidget(
+               this.controller,
+               this.model,
+               menuConfig
+       );
+};
+
+/**
+ * @inheritdoc
+ */
+FilterTagMultiselectWidget.prototype.createTagItemWidget = function ( data ) {
+       var filterItem = this.model.getItemByName( data );
+
+       if ( filterItem ) {
+               return new FilterTagItemWidget(
                        this.controller,
                        this.model,
-                       menuConfig
+                       this.model.getInvertModel(),
+                       filterItem,
+                       {
+                               $overlay: this.$overlay
+                       }
                );
-       };
-
-       /**
-        * @inheritdoc
-        */
-       FilterTagMultiselectWidget.prototype.createTagItemWidget = function ( data ) {
-               var filterItem = this.model.getItemByName( data );
-
-               if ( filterItem ) {
-                       return new FilterTagItemWidget(
-                               this.controller,
-                               this.model,
-                               this.model.getInvertModel(),
-                               filterItem,
-                               {
-                                       $overlay: this.$overlay
-                               }
-                       );
-               }
-       };
-
-       FilterTagMultiselectWidget.prototype.emphasize = function () {
-               if (
-                       !this.$handle.hasClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-animate' )
-               ) {
+       }
+};
+
+FilterTagMultiselectWidget.prototype.emphasize = function () {
+       if (
+               !this.$handle.hasClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-animate' )
+       ) {
+               this.$handle
+                       .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-emphasize' )
+                       .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-animate' );
+
+               setTimeout( function () {
                        this.$handle
-                               .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-emphasize' )
-                               .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-animate' );
+                               .removeClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-emphasize' );
 
                        setTimeout( function () {
                                this.$handle
-                                       .removeClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-emphasize' );
-
-                               setTimeout( function () {
-                                       this.$handle
-                                               .removeClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-animate' );
-                               }.bind( this ), 1000 );
-                       }.bind( this ), 500 );
-
-               }
-       };
-       /**
-        * Scroll the element to top within its container
-        *
-        * @private
-        * @param {jQuery} $element Element to position
-        * @param {number} [marginFromTop=0] When scrolling the entire widget to the top, leave this
-        *  much space (in pixels) above the widget.
-        * @param {Object} [threshold] Minimum distance from the top of the element to scroll at all
-        * @param {number} [threshold.min] Minimum distance above the element
-        * @param {number} [threshold.max] Minimum distance below the element
-        */
-       FilterTagMultiselectWidget.prototype.scrollToTop = function ( $element, marginFromTop, threshold ) {
-               var container = OO.ui.Element.static.getClosestScrollableContainer( $element[ 0 ], 'y' ),
-                       pos = OO.ui.Element.static.getRelativePosition( $element, $( container ) ),
-                       containerScrollTop = $( container ).scrollTop(),
-                       effectiveScrollTop = $( container ).is( 'body, html' ) ? 0 : containerScrollTop,
-                       newScrollTop = effectiveScrollTop + pos.top - ( marginFromTop || 0 );
-
-               // Scroll to item
-               if (
-                       threshold === undefined ||
+                                       .removeClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-animate' );
+                       }.bind( this ), 1000 );
+               }.bind( this ), 500 );
+
+       }
+};
+/**
+ * Scroll the element to top within its container
+ *
+ * @private
+ * @param {jQuery} $element Element to position
+ * @param {number} [marginFromTop=0] When scrolling the entire widget to the top, leave this
+ *  much space (in pixels) above the widget.
+ * @param {Object} [threshold] Minimum distance from the top of the element to scroll at all
+ * @param {number} [threshold.min] Minimum distance above the element
+ * @param {number} [threshold.max] Minimum distance below the element
+ */
+FilterTagMultiselectWidget.prototype.scrollToTop = function ( $element, marginFromTop, threshold ) {
+       var container = OO.ui.Element.static.getClosestScrollableContainer( $element[ 0 ], 'y' ),
+               pos = OO.ui.Element.static.getRelativePosition( $element, $( container ) ),
+               containerScrollTop = $( container ).scrollTop(),
+               effectiveScrollTop = $( container ).is( 'body, html' ) ? 0 : containerScrollTop,
+               newScrollTop = effectiveScrollTop + pos.top - ( marginFromTop || 0 );
+
+       // Scroll to item
+       if (
+               threshold === undefined ||
+               (
+                       (
+                               threshold.min === undefined ||
+                               newScrollTop - containerScrollTop >= threshold.min
+                       ) &&
                        (
-                               (
-                                       threshold.min === undefined ||
-                                       newScrollTop - containerScrollTop >= threshold.min
-                               ) &&
-                               (
-                                       threshold.max === undefined ||
-                                       newScrollTop - containerScrollTop <= threshold.max
-                               )
+                               threshold.max === undefined ||
+                               newScrollTop - containerScrollTop <= threshold.max
                        )
-               ) {
-                       $( container ).animate( {
-                               scrollTop: newScrollTop
-                       } );
-               }
-       };
+               )
+       ) {
+               $( container ).animate( {
+                       scrollTop: newScrollTop
+               } );
+       }
+};
 
-       module.exports = FilterTagMultiselectWidget;
-}() );
+module.exports = FilterTagMultiselectWidget;
index cb297f6..a0f098c 100644 (file)
-( function () {
-       var FilterTagMultiselectWidget = require( './FilterTagMultiselectWidget.js' ),
-               LiveUpdateButtonWidget = require( './LiveUpdateButtonWidget.js' ),
-               ChangesLimitAndDateButtonWidget = require( './ChangesLimitAndDateButtonWidget.js' ),
-               FilterWrapperWidget;
-
-       /**
-        * List displaying all filter groups
-        *
-        * @class mw.rcfilters.ui.FilterWrapperWidget
-        * @extends OO.ui.Widget
-        * @mixins OO.ui.mixin.PendingElement
-        *
-        * @constructor
-        * @param {mw.rcfilters.Controller} controller Controller
-        * @param {mw.rcfilters.dm.FiltersViewModel} model View model
-        * @param {mw.rcfilters.dm.SavedQueriesModel} savedQueriesModel Saved queries model
-        * @param {mw.rcfilters.dm.ChangesListViewModel} changesListModel
-        * @param {Object} [config] Configuration object
-        * @cfg {Object} [filters] A definition of the filter groups in this list
-        * @cfg {jQuery} [$overlay] A jQuery object serving as overlay for popups
-        * @cfg {jQuery} [$wrapper] A jQuery object for the wrapper of the general
-        *  system. If not given, falls back to this widget's $element
-        * @cfg {boolean} [collapsed] Filter area is collapsed
-        */
-       FilterWrapperWidget = function MwRcfiltersUiFilterWrapperWidget(
-               controller, model, savedQueriesModel, changesListModel, config
-       ) {
-               var $bottom;
-               config = config || {};
-
-               // Parent
-               FilterWrapperWidget.parent.call( this, config );
-               // Mixin constructors
-               OO.ui.mixin.PendingElement.call( this, config );
-
-               this.controller = controller;
-               this.model = model;
-               this.queriesModel = savedQueriesModel;
-               this.changesListModel = changesListModel;
-               this.$overlay = config.$overlay || this.$element;
-               this.$wrapper = config.$wrapper || this.$element;
-
-               this.filterTagWidget = new FilterTagMultiselectWidget(
-                       this.controller,
-                       this.model,
-                       this.queriesModel,
-                       {
-                               $overlay: this.$overlay,
-                               collapsed: config.collapsed,
-                               $wrapper: this.$wrapper
-                       }
+var FilterTagMultiselectWidget = require( './FilterTagMultiselectWidget.js' ),
+       LiveUpdateButtonWidget = require( './LiveUpdateButtonWidget.js' ),
+       ChangesLimitAndDateButtonWidget = require( './ChangesLimitAndDateButtonWidget.js' ),
+       FilterWrapperWidget;
+
+/**
+ * List displaying all filter groups
+ *
+ * @class mw.rcfilters.ui.FilterWrapperWidget
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.mixin.PendingElement
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller Controller
+ * @param {mw.rcfilters.dm.FiltersViewModel} model View model
+ * @param {mw.rcfilters.dm.SavedQueriesModel} savedQueriesModel Saved queries model
+ * @param {mw.rcfilters.dm.ChangesListViewModel} changesListModel
+ * @param {Object} [config] Configuration object
+ * @cfg {Object} [filters] A definition of the filter groups in this list
+ * @cfg {jQuery} [$overlay] A jQuery object serving as overlay for popups
+ * @cfg {jQuery} [$wrapper] A jQuery object for the wrapper of the general
+ *  system. If not given, falls back to this widget's $element
+ * @cfg {boolean} [collapsed] Filter area is collapsed
+ */
+FilterWrapperWidget = function MwRcfiltersUiFilterWrapperWidget(
+       controller, model, savedQueriesModel, changesListModel, config
+) {
+       var $bottom;
+       config = config || {};
+
+       // Parent
+       FilterWrapperWidget.parent.call( this, config );
+       // Mixin constructors
+       OO.ui.mixin.PendingElement.call( this, config );
+
+       this.controller = controller;
+       this.model = model;
+       this.queriesModel = savedQueriesModel;
+       this.changesListModel = changesListModel;
+       this.$overlay = config.$overlay || this.$element;
+       this.$wrapper = config.$wrapper || this.$element;
+
+       this.filterTagWidget = new FilterTagMultiselectWidget(
+               this.controller,
+               this.model,
+               this.queriesModel,
+               {
+                       $overlay: this.$overlay,
+                       collapsed: config.collapsed,
+                       $wrapper: this.$wrapper
+               }
+       );
+
+       this.liveUpdateButton = new LiveUpdateButtonWidget(
+               this.controller,
+               this.changesListModel
+       );
+
+       this.numChangesAndDateWidget = new ChangesLimitAndDateButtonWidget(
+               this.controller,
+               this.model,
+               {
+                       $overlay: this.$overlay
+               }
+       );
+
+       this.showNewChangesLink = new OO.ui.ButtonWidget( {
+               icon: 'reload',
+               framed: false,
+               flags: [ 'progressive' ],
+               classes: [ 'mw-rcfilters-ui-filterWrapperWidget-showNewChanges' ]
+       } );
+
+       // Events
+       this.filterTagWidget.menu.connect( this, { toggle: [ 'emit', 'menuToggle' ] } );
+       this.changesListModel.connect( this, { newChangesExist: 'onNewChangesExist' } );
+       this.showNewChangesLink.connect( this, { click: 'onShowNewChangesClick' } );
+       this.showNewChangesLink.toggle( false );
+
+       // Initialize
+       this.$top = $( '<div>' )
+               .addClass( 'mw-rcfilters-ui-filterWrapperWidget-top' );
+
+       $bottom = $( '<div>' )
+               .addClass( 'mw-rcfilters-ui-filterWrapperWidget-bottom' )
+               .append(
+                       this.showNewChangesLink.$element,
+                       this.numChangesAndDateWidget.$element
                );
 
-               this.liveUpdateButton = new LiveUpdateButtonWidget(
-                       this.controller,
-                       this.changesListModel
-               );
+       if ( this.controller.pollingRate ) {
+               $bottom.prepend( this.liveUpdateButton.$element );
+       }
 
-               this.numChangesAndDateWidget = new ChangesLimitAndDateButtonWidget(
-                       this.controller,
-                       this.model,
-                       {
-                               $overlay: this.$overlay
-                       }
+       this.$element
+               .addClass( 'mw-rcfilters-ui-filterWrapperWidget' )
+               .append(
+                       this.$top,
+                       this.filterTagWidget.$element,
+                       $bottom
                );
+};
+
+/* Initialization */
+
+OO.inheritClass( FilterWrapperWidget, OO.ui.Widget );
+OO.mixinClass( FilterWrapperWidget, OO.ui.mixin.PendingElement );
+
+/* Methods */
+
+/**
+ * Set the content of the top section
+ *
+ * @param {jQuery} $topSectionElement
+ */
+FilterWrapperWidget.prototype.setTopSection = function ( $topSectionElement ) {
+       this.$top.append( $topSectionElement );
+};
+
+/**
+ * Respond to the user clicking the 'show new changes' button
+ */
+FilterWrapperWidget.prototype.onShowNewChangesClick = function () {
+       this.controller.showNewChanges();
+};
+
+/**
+ * Respond to changes list model newChangesExist
+ *
+ * @param {boolean} newChangesExist Whether new changes exist
+ */
+FilterWrapperWidget.prototype.onNewChangesExist = function ( newChangesExist ) {
+       if ( newChangesExist ) {
+               this.showNewChangesLink.setLabel(
+                       mw.message(
+                               'rcfilters-show-new-changes',
+                               this.changesListModel.getNextFromFormatted()
+                       ).text()
+               );
+       }
+       this.showNewChangesLink.toggle( newChangesExist );
+};
 
-               this.showNewChangesLink = new OO.ui.ButtonWidget( {
-                       icon: 'reload',
-                       framed: false,
-                       label: mw.msg( 'rcfilters-show-new-changes' ),
-                       flags: [ 'progressive' ],
-                       classes: [ 'mw-rcfilters-ui-filterWrapperWidget-showNewChanges' ]
-               } );
-
-               // Events
-               this.filterTagWidget.menu.connect( this, { toggle: [ 'emit', 'menuToggle' ] } );
-               this.changesListModel.connect( this, { newChangesExist: 'onNewChangesExist' } );
-               this.showNewChangesLink.connect( this, { click: 'onShowNewChangesClick' } );
-               this.showNewChangesLink.toggle( false );
-
-               // Initialize
-               this.$top = $( '<div>' )
-                       .addClass( 'mw-rcfilters-ui-filterWrapperWidget-top' );
-
-               $bottom = $( '<div>' )
-                       .addClass( 'mw-rcfilters-ui-filterWrapperWidget-bottom' )
-                       .append(
-                               this.showNewChangesLink.$element,
-                               this.numChangesAndDateWidget.$element
-                       );
-
-               if ( this.controller.pollingRate ) {
-                       $bottom.prepend( this.liveUpdateButton.$element );
-               }
-
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-filterWrapperWidget' )
-                       .append(
-                               this.$top,
-                               this.filterTagWidget.$element,
-                               $bottom
-                       );
-       };
-
-       /* Initialization */
-
-       OO.inheritClass( FilterWrapperWidget, OO.ui.Widget );
-       OO.mixinClass( FilterWrapperWidget, OO.ui.mixin.PendingElement );
-
-       /* Methods */
-
-       /**
-        * Set the content of the top section
-        *
-        * @param {jQuery} $topSectionElement
-        */
-       FilterWrapperWidget.prototype.setTopSection = function ( $topSectionElement ) {
-               this.$top.append( $topSectionElement );
-       };
-
-       /**
-        * Respond to the user clicking the 'show new changes' button
-        */
-       FilterWrapperWidget.prototype.onShowNewChangesClick = function () {
-               this.controller.showNewChanges();
-       };
-
-       /**
-        * Respond to changes list model newChangesExist
-        *
-        * @param {boolean} newChangesExist Whether new changes exist
-        */
-       FilterWrapperWidget.prototype.onNewChangesExist = function ( newChangesExist ) {
-               this.showNewChangesLink.toggle( newChangesExist );
-       };
-
-       module.exports = FilterWrapperWidget;
-}() );
+module.exports = FilterWrapperWidget;
index dbf1776..7d69fb6 100644 (file)
-( function () {
-       /**
-        * Wrapper for the RC form with hide/show links
-        * Must be constructed after the model is initialized.
-        *
-        * @class mw.rcfilters.ui.FormWrapperWidget
-        * @extends OO.ui.Widget
-        *
-        * @constructor
-        * @param {mw.rcfilters.dm.FiltersViewModel} filtersModel Changes list view model
-        * @param {mw.rcfilters.dm.ChangesListViewModel} changeListModel Changes list view model
-        * @param {mw.rcfilters.Controller} controller RCfilters controller
-        * @param {jQuery} $formRoot Root element of the form to attach to
-        * @param {Object} config Configuration object
-        */
-       var FormWrapperWidget = function MwRcfiltersUiFormWrapperWidget( filtersModel, changeListModel, controller, $formRoot, config ) {
-               config = config || {};
-
-               // Parent
-               FormWrapperWidget.parent.call( this, $.extend( {}, config, {
-                       $element: $formRoot
-               } ) );
-
-               this.changeListModel = changeListModel;
-               this.filtersModel = filtersModel;
-               this.controller = controller;
-               this.$submitButton = this.$element.find( 'form input[type=submit]' );
-
-               this.$element
-                       .on( 'click', 'a[data-params]', this.onLinkClick.bind( this ) );
-
-               this.$element
-                       .on( 'submit', 'form', this.onFormSubmit.bind( this ) );
-
-               // Events
-               this.changeListModel.connect( this, {
-                       invalidate: 'onChangesModelInvalidate',
-                       update: 'onChangesModelUpdate'
-               } );
-
-               // Initialize
-               this.cleanUpFieldset();
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-FormWrapperWidget' );
-       };
-
-       /* Initialization */
-
-       OO.inheritClass( FormWrapperWidget, OO.ui.Widget );
-
-       /**
-        * Respond to link click
-        *
-        * @param {jQuery.Event} e Event
-        * @return {boolean} false
-        */
-       FormWrapperWidget.prototype.onLinkClick = function ( e ) {
-               this.controller.updateChangesList( $( e.target ).data( 'params' ) );
-               return false;
-       };
-
-       /**
-        * Respond to form submit event
-        *
-        * @param {jQuery.Event} e Event
-        * @return {boolean} false
-        */
-       FormWrapperWidget.prototype.onFormSubmit = function ( e ) {
-               var data = {};
-
-               // Collect all data from form
-               $( e.target ).find( 'input:not([type="hidden"],[type="submit"]), select' ).each( function () {
-                       var value = '';
-
-                       if ( !$( this ).is( ':checkbox' ) || $( this ).is( ':checked' ) ) {
-                               value = $( this ).val();
-                       }
-
-                       data[ $( this ).prop( 'name' ) ] = value;
-               } );
-
-               this.controller.updateChangesList( data );
-               return false;
-       };
-
-       /**
-        * Respond to model invalidate
-        */
-       FormWrapperWidget.prototype.onChangesModelInvalidate = function () {
-               this.$submitButton.prop( 'disabled', true );
-       };
-
-       /**
-        * Respond to model update, replace the show/hide links with the ones from the
-        * server so they feature the correct state.
-        *
-        * @param {jQuery|string} $changesList Updated changes list
-        * @param {jQuery} $fieldset Updated fieldset
-        * @param {string} noResultsDetails Type of no result error
-        * @param {boolean} isInitialDOM Whether $changesListContent is the existing (already attached) DOM
-        */
-       FormWrapperWidget.prototype.onChangesModelUpdate = function ( $changesList, $fieldset, noResultsDetails, isInitialDOM ) {
-               this.$submitButton.prop( 'disabled', false );
-
-               // Replace the entire fieldset
-               this.$element.empty().append( $fieldset.contents() );
-
-               if ( !isInitialDOM ) {
-                       // Make sure enhanced RC re-initializes correctly
-                       mw.hook( 'wikipage.content' ).fire( this.$element );
+/**
+ * Wrapper for the RC form with hide/show links
+ * Must be constructed after the model is initialized.
+ *
+ * @class mw.rcfilters.ui.FormWrapperWidget
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {mw.rcfilters.dm.FiltersViewModel} filtersModel Changes list view model
+ * @param {mw.rcfilters.dm.ChangesListViewModel} changeListModel Changes list view model
+ * @param {mw.rcfilters.Controller} controller RCfilters controller
+ * @param {jQuery} $formRoot Root element of the form to attach to
+ * @param {Object} config Configuration object
+ */
+var FormWrapperWidget = function MwRcfiltersUiFormWrapperWidget( filtersModel, changeListModel, controller, $formRoot, config ) {
+       config = config || {};
+
+       // Parent
+       FormWrapperWidget.parent.call( this, $.extend( {}, config, {
+               $element: $formRoot
+       } ) );
+
+       this.changeListModel = changeListModel;
+       this.filtersModel = filtersModel;
+       this.controller = controller;
+       this.$submitButton = this.$element.find( 'form input[type=submit]' );
+
+       this.$element
+               .on( 'click', 'a[data-params]', this.onLinkClick.bind( this ) );
+
+       this.$element
+               .on( 'submit', 'form', this.onFormSubmit.bind( this ) );
+
+       // Events
+       this.changeListModel.connect( this, {
+               invalidate: 'onChangesModelInvalidate',
+               update: 'onChangesModelUpdate'
+       } );
+
+       // Initialize
+       this.cleanUpFieldset();
+       this.$element
+               .addClass( 'mw-rcfilters-ui-FormWrapperWidget' );
+};
+
+/* Initialization */
+
+OO.inheritClass( FormWrapperWidget, OO.ui.Widget );
+
+/**
+ * Respond to link click
+ *
+ * @param {jQuery.Event} e Event
+ * @return {boolean} false
+ */
+FormWrapperWidget.prototype.onLinkClick = function ( e ) {
+       this.controller.updateChangesList( $( e.target ).data( 'params' ) );
+       return false;
+};
+
+/**
+ * Respond to form submit event
+ *
+ * @param {jQuery.Event} e Event
+ * @return {boolean} false
+ */
+FormWrapperWidget.prototype.onFormSubmit = function ( e ) {
+       var data = {};
+
+       // Collect all data from form
+       $( e.target ).find( 'input:not([type="hidden"],[type="submit"]), select' ).each( function () {
+               var value = '';
+
+               if ( !$( this ).is( ':checkbox' ) || $( this ).is( ':checked' ) ) {
+                       value = $( this ).val();
                }
 
-               this.cleanUpFieldset();
-       };
-
-       /**
-        * Clean up the old-style show/hide that we have implemented in the filter list
-        */
-       FormWrapperWidget.prototype.cleanUpFieldset = function () {
-               this.$element.find( '.clshowhideoption[data-feature-in-structured-ui=1]' ).each( function () {
-                       // HACK: Remove the text node after the span.
-                       // If there isn't one, we're at the end, so remove the text node before the span.
-                       // This would be unnecessary if we added separators with CSS.
-                       if ( this.nextSibling && this.nextSibling.nodeType === Node.TEXT_NODE ) {
-                               this.parentNode.removeChild( this.nextSibling );
-                       } else if ( this.previousSibling && this.previousSibling.nodeType === Node.TEXT_NODE ) {
-                               this.parentNode.removeChild( this.previousSibling );
-                       }
-                       // Remove the span itself
-                       this.parentNode.removeChild( this );
-               } );
-
-               // Hide namespaces and tags
-               this.$element.find( '.namespaceForm' ).detach();
-               this.$element.find( '.mw-tagfilter-label' ).closest( 'tr' ).detach();
-
-               // Hide Related Changes page name form
-               this.$element.find( '.targetForm' ).detach();
-
-               // misc: limit, days, watchlist info msg
-               this.$element.find( '.rclinks, .cldays, .wlinfo' ).detach();
-
-               if ( !this.$element.find( '.mw-recentchanges-table tr' ).length ) {
-                       this.$element.find( '.mw-recentchanges-table' ).detach();
-                       this.$element.find( 'hr' ).detach();
+               data[ $( this ).prop( 'name' ) ] = value;
+       } );
+
+       this.controller.updateChangesList( data );
+       return false;
+};
+
+/**
+ * Respond to model invalidate
+ */
+FormWrapperWidget.prototype.onChangesModelInvalidate = function () {
+       this.$submitButton.prop( 'disabled', true );
+};
+
+/**
+ * Respond to model update, replace the show/hide links with the ones from the
+ * server so they feature the correct state.
+ *
+ * @param {jQuery|string} $changesList Updated changes list
+ * @param {jQuery} $fieldset Updated fieldset
+ * @param {string} noResultsDetails Type of no result error
+ * @param {boolean} isInitialDOM Whether $changesListContent is the existing (already attached) DOM
+ */
+FormWrapperWidget.prototype.onChangesModelUpdate = function ( $changesList, $fieldset, noResultsDetails, isInitialDOM ) {
+       this.$submitButton.prop( 'disabled', false );
+
+       // Replace the entire fieldset
+       this.$element.empty().append( $fieldset.contents() );
+
+       if ( !isInitialDOM ) {
+               // Make sure enhanced RC re-initializes correctly
+               mw.hook( 'wikipage.content' ).fire( this.$element );
+       }
+
+       this.cleanUpFieldset();
+};
+
+/**
+ * Clean up the old-style show/hide that we have implemented in the filter list
+ */
+FormWrapperWidget.prototype.cleanUpFieldset = function () {
+       this.$element.find( '.clshowhideoption[data-feature-in-structured-ui=1]' ).each( function () {
+               // HACK: Remove the text node after the span.
+               // If there isn't one, we're at the end, so remove the text node before the span.
+               // This would be unnecessary if we added separators with CSS.
+               if ( this.nextSibling && this.nextSibling.nodeType === Node.TEXT_NODE ) {
+                       this.parentNode.removeChild( this.nextSibling );
+               } else if ( this.previousSibling && this.previousSibling.nodeType === Node.TEXT_NODE ) {
+                       this.parentNode.removeChild( this.previousSibling );
                }
-
-               // Get rid of all <br>s, which are inside rcshowhide
-               // If we still have content in rcshowhide, the <br>s are
-               // gone. Instead, the CSS now has a rule to mark all <span>s
-               // inside .rcshowhide with display:block; to simulate newlines
-               // where they're actually needed.
-               this.$element.find( 'br' ).detach();
-               if ( !this.$element.find( '.rcshowhide' ).contents().length ) {
-                       this.$element.find( '.rcshowhide' ).detach();
-               }
-
-               if ( this.$element.find( '.cloption' ).text().trim() === '' ) {
-                       this.$element.find( '.cloption-submit' ).detach();
-               }
-
-               this.$element.find(
-                       '.rclistfrom, .rcnotefrom, .rcoptions-listfromreset'
-               ).detach();
-
-               // Get rid of the legend
-               this.$element.find( 'legend' ).detach();
-
-               // Check if the element is essentially empty, and detach it if it is
-               if ( !this.$element.text().trim().length ) {
-                       this.$element.detach();
-               }
-       };
-
-       module.exports = FormWrapperWidget;
-}() );
+               // Remove the span itself
+               this.parentNode.removeChild( this );
+       } );
+
+       // Hide namespaces and tags
+       this.$element.find( '.namespaceForm' ).detach();
+       this.$element.find( '.mw-tagfilter-label' ).closest( 'tr' ).detach();
+
+       // Hide Related Changes page name form
+       this.$element.find( '.targetForm' ).detach();
+
+       // misc: limit, days, watchlist info msg
+       this.$element.find( '.rclinks, .cldays, .wlinfo' ).detach();
+
+       if ( !this.$element.find( '.mw-recentchanges-table tr' ).length ) {
+               this.$element.find( '.mw-recentchanges-table' ).detach();
+               this.$element.find( 'hr' ).detach();
+       }
+
+       // Get rid of all <br>s, which are inside rcshowhide
+       // If we still have content in rcshowhide, the <br>s are
+       // gone. Instead, the CSS now has a rule to mark all <span>s
+       // inside .rcshowhide with display:block; to simulate newlines
+       // where they're actually needed.
+       this.$element.find( 'br' ).detach();
+       if ( !this.$element.find( '.rcshowhide' ).contents().length ) {
+               this.$element.find( '.rcshowhide' ).detach();
+       }
+
+       if ( this.$element.find( '.cloption' ).text().trim() === '' ) {
+               this.$element.find( '.cloption-submit' ).detach();
+       }
+
+       this.$element.find(
+               '.rclistfrom, .rcnotefrom, .rcoptions-listfromreset'
+       ).detach();
+
+       // Get rid of the legend
+       this.$element.find( 'legend' ).detach();
+
+       // Check if the element is essentially empty, and detach it if it is
+       if ( !this.$element.text().trim().length ) {
+               this.$element.detach();
+       }
+};
+
+module.exports = FormWrapperWidget;
index 73b874c..12d53bb 100644 (file)
@@ -1,45 +1,43 @@
-( function () {
-       /**
-        * A group widget to allow for aggregation of events
-        *
-        * @class mw.rcfilters.ui.GroupWidget
-        * @extends OO.ui.Widget
-        *
-        * @constructor
-        * @param {Object} [config] Configuration object
-        * @param {Object} [events] Events to aggregate. The object represent the
-        *  event name to aggregate and the event value to emit on aggregate for items.
-        */
-       var GroupWidget = function MwRcfiltersUiViewSwitchWidget( config ) {
-               var aggregate = {};
-
-               config = config || {};
-
-               // Parent constructor
-               GroupWidget.parent.call( this, config );
-
-               // Mixin constructors
-               OO.ui.mixin.GroupElement.call( this, $.extend( {}, config, { $group: this.$element } ) );
-
-               if ( config.events ) {
-                       // Aggregate events
-                       // eslint-disable-next-line no-jquery/no-each-util
-                       $.each( config.events, function ( eventName, eventEmit ) {
-                               aggregate[ eventName ] = eventEmit;
-                       } );
-
-                       this.aggregate( aggregate );
-               }
-
-               if ( Array.isArray( config.items ) ) {
-                       this.addItems( config.items );
-               }
-       };
-
-       /* Initialize */
-
-       OO.inheritClass( GroupWidget, OO.ui.Widget );
-       OO.mixinClass( GroupWidget, OO.ui.mixin.GroupWidget );
-
-       module.exports = GroupWidget;
-}() );
+/**
+ * A group widget to allow for aggregation of events
+ *
+ * @class mw.rcfilters.ui.GroupWidget
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration object
+ * @cfg {Object} [events] Events to aggregate. The object represent the
+ *  event name to aggregate and the event value to emit on aggregate for items.
+ */
+var GroupWidget = function MwRcfiltersUiViewSwitchWidget( config ) {
+       var aggregate = {};
+
+       config = config || {};
+
+       // Parent constructor
+       GroupWidget.parent.call( this, config );
+
+       // Mixin constructors
+       OO.ui.mixin.GroupElement.call( this, $.extend( {}, config, { $group: this.$element } ) );
+
+       if ( config.events ) {
+               // Aggregate events
+               // eslint-disable-next-line no-jquery/no-each-util
+               $.each( config.events, function ( eventName, eventEmit ) {
+                       aggregate[ eventName ] = eventEmit;
+               } );
+
+               this.aggregate( aggregate );
+       }
+
+       if ( Array.isArray( config.items ) ) {
+               this.addItems( config.items );
+       }
+};
+
+/* Initialize */
+
+OO.inheritClass( GroupWidget, OO.ui.Widget );
+OO.mixinClass( GroupWidget, OO.ui.mixin.GroupWidget );
+
+module.exports = GroupWidget;
index cb5f8eb..082b65b 100644 (file)
-( function () {
-       /**
-        * A widget representing a filter item highlight color picker
-        *
-        * @class mw.rcfilters.ui.HighlightColorPickerWidget
-        * @extends OO.ui.Widget
-        * @mixins OO.ui.mixin.LabelElement
-        *
-        * @constructor
-        * @param {mw.rcfilters.Controller} controller RCFilters controller
-        * @param {Object} [config] Configuration object
-        */
-       var HighlightColorPickerWidget = function MwRcfiltersUiHighlightColorPickerWidget( controller, config ) {
-               var colors = [ 'none' ].concat( mw.rcfilters.HighlightColors );
-               config = config || {};
-
-               // Parent
-               HighlightColorPickerWidget.parent.call( this, config );
-               // Mixin constructors
-               OO.ui.mixin.LabelElement.call( this, $.extend( {}, config, {
-                       label: mw.message( 'rcfilters-highlightmenu-title' ).text()
-               } ) );
-
-               this.controller = controller;
-
-               this.currentSelection = 'none';
-               this.buttonSelect = new OO.ui.ButtonSelectWidget( {
-                       items: colors.map( function ( color ) {
-                               return new OO.ui.ButtonOptionWidget( {
-                                       icon: color === 'none' ? 'check' : null,
-                                       data: color,
-                                       classes: [
-                                               'mw-rcfilters-ui-highlightColorPickerWidget-buttonSelect-color',
-                                               'mw-rcfilters-ui-highlightColorPickerWidget-buttonSelect-color-' + color
-                                       ],
-                                       framed: false
-                               } );
-                       } ),
-                       classes: 'mw-rcfilters-ui-highlightColorPickerWidget-buttonSelect'
-               } );
-
-               // Event
-               this.buttonSelect.connect( this, { choose: 'onChooseColor' } );
-
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-highlightColorPickerWidget' )
-                       .append(
-                               this.$label
-                                       .addClass( 'mw-rcfilters-ui-highlightColorPickerWidget-label' ),
-                               this.buttonSelect.$element
-                       );
-       };
-
-       /* Initialization */
-
-       OO.inheritClass( HighlightColorPickerWidget, OO.ui.Widget );
-       OO.mixinClass( HighlightColorPickerWidget, OO.ui.mixin.LabelElement );
-
-       /* Events */
-
-       /**
-        * @event chooseColor
-        * @param {string} The chosen color
-        *
-        * A color has been chosen
-        */
-
-       /* Methods */
-
-       /**
-        * Bind the color picker to an item
-        * @param {mw.rcfilters.dm.FilterItem} filterItem
-        */
-       HighlightColorPickerWidget.prototype.setFilterItem = function ( filterItem ) {
-               if ( this.filterItem ) {
-                       this.filterItem.disconnect( this );
+/**
+ * A widget representing a filter item highlight color picker
+ *
+ * @class mw.rcfilters.ui.HighlightColorPickerWidget
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.mixin.LabelElement
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller RCFilters controller
+ * @param {Object} [config] Configuration object
+ */
+var HighlightColorPickerWidget = function MwRcfiltersUiHighlightColorPickerWidget( controller, config ) {
+       var colors = [ 'none' ].concat( mw.rcfilters.HighlightColors );
+       config = config || {};
+
+       // Parent
+       HighlightColorPickerWidget.parent.call( this, config );
+       // Mixin constructors
+       OO.ui.mixin.LabelElement.call( this, $.extend( {}, config, {
+               label: mw.message( 'rcfilters-highlightmenu-title' ).text()
+       } ) );
+
+       this.controller = controller;
+
+       this.currentSelection = 'none';
+       this.buttonSelect = new OO.ui.ButtonSelectWidget( {
+               items: colors.map( function ( color ) {
+                       return new OO.ui.ButtonOptionWidget( {
+                               icon: color === 'none' ? 'check' : null,
+                               data: color,
+                               classes: [
+                                       'mw-rcfilters-ui-highlightColorPickerWidget-buttonSelect-color',
+                                       'mw-rcfilters-ui-highlightColorPickerWidget-buttonSelect-color-' + color
+                               ],
+                               framed: false
+                       } );
+               } ),
+               classes: 'mw-rcfilters-ui-highlightColorPickerWidget-buttonSelect'
+       } );
+
+       // Event
+       this.buttonSelect.connect( this, { choose: 'onChooseColor' } );
+
+       this.$element
+               .addClass( 'mw-rcfilters-ui-highlightColorPickerWidget' )
+               .append(
+                       this.$label
+                               .addClass( 'mw-rcfilters-ui-highlightColorPickerWidget-label' ),
+                       this.buttonSelect.$element
+               );
+};
+
+/* Initialization */
+
+OO.inheritClass( HighlightColorPickerWidget, OO.ui.Widget );
+OO.mixinClass( HighlightColorPickerWidget, OO.ui.mixin.LabelElement );
+
+/* Events */
+
+/**
+ * @event chooseColor
+ * @param {string} The chosen color
+ *
+ * A color has been chosen
+ */
+
+/* Methods */
+
+/**
+ * Bind the color picker to an item
+ * @param {mw.rcfilters.dm.FilterItem} filterItem
+ */
+HighlightColorPickerWidget.prototype.setFilterItem = function ( filterItem ) {
+       if ( this.filterItem ) {
+               this.filterItem.disconnect( this );
+       }
+
+       this.filterItem = filterItem;
+       this.filterItem.connect( this, { update: 'updateUiBasedOnModel' } );
+       this.updateUiBasedOnModel();
+};
+
+/**
+ * Respond to item model update event
+ */
+HighlightColorPickerWidget.prototype.updateUiBasedOnModel = function () {
+       this.selectColor( this.filterItem.getHighlightColor() || 'none' );
+};
+
+/**
+ * Select the color for this widget
+ *
+ * @param {string} color Selected color
+ */
+HighlightColorPickerWidget.prototype.selectColor = function ( color ) {
+       var previousItem = this.buttonSelect.findItemFromData( this.currentSelection ),
+               selectedItem = this.buttonSelect.findItemFromData( color );
+
+       if ( this.currentSelection !== color ) {
+               this.currentSelection = color;
+
+               this.buttonSelect.selectItem( selectedItem );
+               if ( previousItem ) {
+                       previousItem.setIcon( null );
                }
 
-               this.filterItem = filterItem;
-               this.filterItem.connect( this, { update: 'updateUiBasedOnModel' } );
-               this.updateUiBasedOnModel();
-       };
-
-       /**
-        * Respond to item model update event
-        */
-       HighlightColorPickerWidget.prototype.updateUiBasedOnModel = function () {
-               this.selectColor( this.filterItem.getHighlightColor() || 'none' );
-       };
-
-       /**
-        * Select the color for this widget
-        *
-        * @param {string} color Selected color
-        */
-       HighlightColorPickerWidget.prototype.selectColor = function ( color ) {
-               var previousItem = this.buttonSelect.findItemFromData( this.currentSelection ),
-                       selectedItem = this.buttonSelect.findItemFromData( color );
-
-               if ( this.currentSelection !== color ) {
-                       this.currentSelection = color;
-
-                       this.buttonSelect.selectItem( selectedItem );
-                       if ( previousItem ) {
-                               previousItem.setIcon( null );
-                       }
-
-                       if ( selectedItem ) {
-                               selectedItem.setIcon( 'check' );
-                       }
+               if ( selectedItem ) {
+                       selectedItem.setIcon( 'check' );
                }
-       };
-
-       HighlightColorPickerWidget.prototype.onChooseColor = function ( button ) {
-               var color = button.data;
-               if ( color === 'none' ) {
-                       this.controller.clearHighlightColor( this.filterItem.getName() );
-               } else {
-                       this.controller.setHighlightColor( this.filterItem.getName(), color );
-               }
-               this.emit( 'chooseColor', color );
-       };
-
-       module.exports = HighlightColorPickerWidget;
-}() );
+       }
+};
+
+HighlightColorPickerWidget.prototype.onChooseColor = function ( button ) {
+       var color = button.data;
+       if ( color === 'none' ) {
+               this.controller.clearHighlightColor( this.filterItem.getName() );
+       } else {
+               this.controller.setHighlightColor( this.filterItem.getName(), color );
+       }
+       this.emit( 'chooseColor', color );
+};
+
+module.exports = HighlightColorPickerWidget;
index 4c467df..5a69013 100644 (file)
@@ -1,68 +1,65 @@
-( function () {
-       var HighlightColorPickerWidget = require( './HighlightColorPickerWidget.js' ),
-               HighlightPopupWidget;
-       /**
-        * A popup containing a color picker, for setting highlight colors.
-        *
-        * @class mw.rcfilters.ui.HighlightPopupWidget
-        * @extends OO.ui.PopupWidget
-        *
-        * @constructor
-        * @param {mw.rcfilters.Controller} controller RCFilters controller
-        * @param {Object} [config] Configuration object
-        */
-       HighlightPopupWidget = function MwRcfiltersUiHighlightPopupWidget( controller, config ) {
-               config = config || {};
+var HighlightColorPickerWidget = require( './HighlightColorPickerWidget.js' ),
+       HighlightPopupWidget;
+/**
+ * A popup containing a color picker, for setting highlight colors.
+ *
+ * @class mw.rcfilters.ui.HighlightPopupWidget
+ * @extends OO.ui.PopupWidget
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller RCFilters controller
+ * @param {Object} [config] Configuration object
+ */
+HighlightPopupWidget = function MwRcfiltersUiHighlightPopupWidget( controller, config ) {
+       config = config || {};
 
-               // Parent
-               HighlightPopupWidget.parent.call( this, $.extend( {
-                       autoClose: true,
-                       anchor: false,
-                       padded: true,
-                       align: 'backwards',
-                       horizontalPosition: 'end',
-                       width: 290
-               }, config ) );
+       // Parent
+       HighlightPopupWidget.parent.call( this, $.extend( {
+               autoClose: true,
+               anchor: false,
+               padded: true,
+               align: 'backwards',
+               horizontalPosition: 'end',
+               width: 290
+       }, config ) );
 
-               this.colorPicker = new HighlightColorPickerWidget( controller );
+       this.colorPicker = new HighlightColorPickerWidget( controller );
 
-               this.colorPicker.connect( this, { chooseColor: 'onChooseColor' } );
+       this.colorPicker.connect( this, { chooseColor: 'onChooseColor' } );
 
-               this.$body.append( this.colorPicker.$element );
-       };
+       this.$body.append( this.colorPicker.$element );
+};
 
-       /* Initialization */
+/* Initialization */
 
-       OO.inheritClass( HighlightPopupWidget, OO.ui.PopupWidget );
+OO.inheritClass( HighlightPopupWidget, OO.ui.PopupWidget );
 
-       /* Methods */
+/* Methods */
 
-       /**
       * Set the button (or other widget) that this popup should hang off.
       *
       * @param {OO.ui.Widget} widget Widget the popup should orient itself to
       */
-       HighlightPopupWidget.prototype.setAssociatedButton = function ( widget ) {
-               this.setFloatableContainer( widget.$element );
-               this.$autoCloseIgnore = widget.$element;
-       };
+/**
+ * Set the button (or other widget) that this popup should hang off.
+ *
+ * @param {OO.ui.Widget} widget Widget the popup should orient itself to
+ */
+HighlightPopupWidget.prototype.setAssociatedButton = function ( widget ) {
+       this.setFloatableContainer( widget.$element );
+       this.$autoCloseIgnore = widget.$element;
+};
 
-       /**
       * Set the filter item that this popup should control the highlight color for.
       *
       * @param {mw.rcfilters.dm.FilterItem} item
       */
-       HighlightPopupWidget.prototype.setFilterItem = function ( item ) {
-               this.colorPicker.setFilterItem( item );
-       };
+/**
+ * Set the filter item that this popup should control the highlight color for.
+ *
+ * @param {mw.rcfilters.dm.FilterItem} item
+ */
+HighlightPopupWidget.prototype.setFilterItem = function ( item ) {
+       this.colorPicker.setFilterItem( item );
+};
 
-       /**
       * When the user chooses a color in the color picker, close the popup.
       */
-       HighlightPopupWidget.prototype.onChooseColor = function () {
-               this.toggle( false );
-       };
+/**
+ * When the user chooses a color in the color picker, close the popup.
+ */
+HighlightPopupWidget.prototype.onChooseColor = function () {
+       this.toggle( false );
+};
 
-       module.exports = HighlightPopupWidget;
-
-}() );
+module.exports = HighlightPopupWidget;
index 56ed628..710bd65 100644 (file)
-( function () {
-       var FilterItemHighlightButton = require( './FilterItemHighlightButton.js' ),
-               CheckboxInputWidget = require( './CheckboxInputWidget.js' ),
-               ItemMenuOptionWidget;
-
-       /**
-        * A widget representing a base toggle item
-        *
-        * @class mw.rcfilters.ui.ItemMenuOptionWidget
-        * @extends OO.ui.MenuOptionWidget
-        *
-        * @constructor
-        * @param {mw.rcfilters.Controller} controller RCFilters controller
-        * @param {mw.rcfilters.dm.FiltersViewModel} filtersViewModel
-        * @param {mw.rcfilters.dm.ItemModel} invertModel
-        * @param {mw.rcfilters.dm.ItemModel} itemModel Item model
-        * @param {mw.rcfilters.ui.HighlightPopupWidget} highlightPopup Shared highlight color picker
-        * @param {Object} config Configuration object
-        */
-       ItemMenuOptionWidget = function MwRcfiltersUiItemMenuOptionWidget(
-               controller, filtersViewModel, invertModel, itemModel, highlightPopup, config
-       ) {
-               var layout,
-                       classes = [],
-                       $label = $( '<div>' )
-                               .addClass( 'mw-rcfilters-ui-itemMenuOptionWidget-label' );
-
-               config = config || {};
-
-               this.controller = controller;
-               this.filtersViewModel = filtersViewModel;
-               this.invertModel = invertModel;
-               this.itemModel = itemModel;
-
-               // Parent
-               ItemMenuOptionWidget.parent.call( this, $.extend( {
-                       // Override the 'check' icon that OOUI defines
-                       icon: '',
-                       data: this.itemModel.getName(),
-                       label: this.itemModel.getLabel()
-               }, config ) );
-
-               this.checkboxWidget = new CheckboxInputWidget( {
-                       value: this.itemModel.getName(),
-                       selected: this.itemModel.isSelected()
-               } );
-
+var FilterItemHighlightButton = require( './FilterItemHighlightButton.js' ),
+       CheckboxInputWidget = require( './CheckboxInputWidget.js' ),
+       ItemMenuOptionWidget;
+
+/**
+ * A widget representing a base toggle item
+ *
+ * @class mw.rcfilters.ui.ItemMenuOptionWidget
+ * @extends OO.ui.MenuOptionWidget
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller RCFilters controller
+ * @param {mw.rcfilters.dm.FiltersViewModel} filtersViewModel
+ * @param {mw.rcfilters.dm.ItemModel} invertModel
+ * @param {mw.rcfilters.dm.ItemModel} itemModel Item model
+ * @param {mw.rcfilters.ui.HighlightPopupWidget} highlightPopup Shared highlight color picker
+ * @param {Object} config Configuration object
+ */
+ItemMenuOptionWidget = function MwRcfiltersUiItemMenuOptionWidget(
+       controller, filtersViewModel, invertModel, itemModel, highlightPopup, config
+) {
+       var layout,
+               classes = [],
+               $label = $( '<div>' )
+                       .addClass( 'mw-rcfilters-ui-itemMenuOptionWidget-label' );
+
+       config = config || {};
+
+       this.controller = controller;
+       this.filtersViewModel = filtersViewModel;
+       this.invertModel = invertModel;
+       this.itemModel = itemModel;
+
+       // Parent
+       ItemMenuOptionWidget.parent.call( this, $.extend( {
+               // Override the 'check' icon that OOUI defines
+               icon: '',
+               data: this.itemModel.getName(),
+               label: this.itemModel.getLabel()
+       }, config ) );
+
+       this.checkboxWidget = new CheckboxInputWidget( {
+               value: this.itemModel.getName(),
+               selected: this.itemModel.isSelected()
+       } );
+
+       $label.append(
+               $( '<div>' )
+                       .addClass( 'mw-rcfilters-ui-itemMenuOptionWidget-label-title' )
+                       .append( $( '<bdi>' ).append( this.$label ) )
+       );
+       if ( this.itemModel.getDescription() ) {
                $label.append(
                        $( '<div>' )
-                               .addClass( 'mw-rcfilters-ui-itemMenuOptionWidget-label-title' )
-                               .append( $( '<bdi>' ).append( this.$label ) )
+                               .addClass( 'mw-rcfilters-ui-itemMenuOptionWidget-label-desc' )
+                               .append( $( '<bdi>' ).text( this.itemModel.getDescription() ) )
                );
-               if ( this.itemModel.getDescription() ) {
-                       $label.append(
-                               $( '<div>' )
-                                       .addClass( 'mw-rcfilters-ui-itemMenuOptionWidget-label-desc' )
-                                       .append( $( '<bdi>' ).text( this.itemModel.getDescription() ) )
-                       );
+       }
+
+       this.highlightButton = new FilterItemHighlightButton(
+               this.controller,
+               this.itemModel,
+               highlightPopup,
+               {
+                       $overlay: config.$overlay || this.$element,
+                       title: mw.msg( 'rcfilters-highlightmenu-help' )
                }
-
-               this.highlightButton = new FilterItemHighlightButton(
-                       this.controller,
-                       this.itemModel,
-                       highlightPopup,
-                       {
-                               $overlay: config.$overlay || this.$element,
-                               title: mw.msg( 'rcfilters-highlightmenu-help' )
-                       }
-               );
-               this.highlightButton.toggle( this.filtersViewModel.isHighlightEnabled() );
-
-               this.excludeLabel = new OO.ui.LabelWidget( {
-                       label: mw.msg( 'rcfilters-filter-excluded' )
-               } );
-               this.excludeLabel.toggle(
-                       this.itemModel.getGroupModel().getView() === 'namespaces' &&
-                       this.itemModel.isSelected() &&
-                       this.invertModel.isSelected()
+       );
+       this.highlightButton.toggle( this.filtersViewModel.isHighlightEnabled() );
+
+       this.excludeLabel = new OO.ui.LabelWidget( {
+               label: mw.msg( 'rcfilters-filter-excluded' )
+       } );
+       this.excludeLabel.toggle(
+               this.itemModel.getGroupModel().getView() === 'namespaces' &&
+               this.itemModel.isSelected() &&
+               this.invertModel.isSelected()
+       );
+
+       layout = new OO.ui.FieldLayout( this.checkboxWidget, {
+               label: $label,
+               align: 'inline'
+       } );
+
+       // Events
+       this.filtersViewModel.connect( this, { highlightChange: 'updateUiBasedOnState' } );
+       this.invertModel.connect( this, { update: 'updateUiBasedOnState' } );
+       this.itemModel.connect( this, { update: 'updateUiBasedOnState' } );
+       // HACK: Prevent defaults on 'click' for the label so it
+       // doesn't steal the focus away from the input. This means
+       // we can continue arrow-movement after we click the label
+       // and is consistent with the checkbox *itself* also preventing
+       // defaults on 'click' as well.
+       layout.$label.on( 'click', false );
+
+       this.$element
+               .addClass( 'mw-rcfilters-ui-itemMenuOptionWidget' )
+               .addClass( 'mw-rcfilters-ui-itemMenuOptionWidget-view-' + this.itemModel.getGroupModel().getView() )
+               .append(
+                       $( '<div>' )
+                               .addClass( 'mw-rcfilters-ui-table' )
+                               .append(
+                                       $( '<div>' )
+                                               .addClass( 'mw-rcfilters-ui-row' )
+                                               .append(
+                                                       $( '<div>' )
+                                                               .addClass( 'mw-rcfilters-ui-cell mw-rcfilters-ui-itemMenuOptionWidget-itemCheckbox' )
+                                                               .append( layout.$element ),
+                                                       $( '<div>' )
+                                                               .addClass( 'mw-rcfilters-ui-cell mw-rcfilters-ui-itemMenuOptionWidget-excludeLabel' )
+                                                               .append( this.excludeLabel.$element ),
+                                                       $( '<div>' )
+                                                               .addClass( 'mw-rcfilters-ui-cell mw-rcfilters-ui-itemMenuOptionWidget-highlightButton' )
+                                                               .append( this.highlightButton.$element )
+                                               )
+                               )
                );
 
-               layout = new OO.ui.FieldLayout( this.checkboxWidget, {
-                       label: $label,
-                       align: 'inline'
+       if ( this.itemModel.getIdentifiers() ) {
+               this.itemModel.getIdentifiers().forEach( function ( ident ) {
+                       classes.push( 'mw-rcfilters-ui-itemMenuOptionWidget-identifier-' + ident );
                } );
 
-               // Events
-               this.filtersViewModel.connect( this, { highlightChange: 'updateUiBasedOnState' } );
-               this.invertModel.connect( this, { update: 'updateUiBasedOnState' } );
-               this.itemModel.connect( this, { update: 'updateUiBasedOnState' } );
-               // HACK: Prevent defaults on 'click' for the label so it
-               // doesn't steal the focus away from the input. This means
-               // we can continue arrow-movement after we click the label
-               // and is consistent with the checkbox *itself* also preventing
-               // defaults on 'click' as well.
-               layout.$label.on( 'click', false );
-
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-itemMenuOptionWidget' )
-                       .addClass( 'mw-rcfilters-ui-itemMenuOptionWidget-view-' + this.itemModel.getGroupModel().getView() )
-                       .append(
-                               $( '<div>' )
-                                       .addClass( 'mw-rcfilters-ui-table' )
-                                       .append(
-                                               $( '<div>' )
-                                                       .addClass( 'mw-rcfilters-ui-row' )
-                                                       .append(
-                                                               $( '<div>' )
-                                                                       .addClass( 'mw-rcfilters-ui-cell mw-rcfilters-ui-itemMenuOptionWidget-itemCheckbox' )
-                                                                       .append( layout.$element ),
-                                                               $( '<div>' )
-                                                                       .addClass( 'mw-rcfilters-ui-cell mw-rcfilters-ui-itemMenuOptionWidget-excludeLabel' )
-                                                                       .append( this.excludeLabel.$element ),
-                                                               $( '<div>' )
-                                                                       .addClass( 'mw-rcfilters-ui-cell mw-rcfilters-ui-itemMenuOptionWidget-highlightButton' )
-                                                                       .append( this.highlightButton.$element )
-                                                       )
-                                       )
-                       );
-
-               if ( this.itemModel.getIdentifiers() ) {
-                       this.itemModel.getIdentifiers().forEach( function ( ident ) {
-                               classes.push( 'mw-rcfilters-ui-itemMenuOptionWidget-identifier-' + ident );
-                       } );
-
-                       this.$element.addClass( classes );
-               }
+               this.$element.addClass( classes );
+       }
 
-               this.updateUiBasedOnState();
-       };
+       this.updateUiBasedOnState();
+};
 
-       /* Initialization */
+/* Initialization */
 
-       OO.inheritClass( ItemMenuOptionWidget, OO.ui.MenuOptionWidget );
+OO.inheritClass( ItemMenuOptionWidget, OO.ui.MenuOptionWidget );
 
-       /* Static properties */
+/* Static properties */
 
-       // We do our own scrolling to top
-       ItemMenuOptionWidget.static.scrollIntoViewOnSelect = false;
+// We do our own scrolling to top
+ItemMenuOptionWidget.static.scrollIntoViewOnSelect = false;
 
-       /* Methods */
+/* Methods */
 
-       /**
-        * Respond to item model update event
-        */
-       ItemMenuOptionWidget.prototype.updateUiBasedOnState = function () {
-               this.checkboxWidget.setSelected( this.itemModel.isSelected() );
-
-               this.highlightButton.toggle( this.filtersViewModel.isHighlightEnabled() );
-               this.excludeLabel.toggle(
-                       this.itemModel.getGroupModel().getView() === 'namespaces' &&
-                       this.itemModel.isSelected() &&
-                       this.invertModel.isSelected()
-               );
-               this.toggle( this.itemModel.isVisible() );
-       };
+/**
+ * Respond to item model update event
+ */
+ItemMenuOptionWidget.prototype.updateUiBasedOnState = function () {
+       this.checkboxWidget.setSelected( this.itemModel.isSelected() );
 
-       /**
-        * Get the name of this filter
-        *
-        * @return {string} Filter name
-        */
-       ItemMenuOptionWidget.prototype.getName = function () {
-               return this.itemModel.getName();
-       };
+       this.highlightButton.toggle( this.filtersViewModel.isHighlightEnabled() );
+       this.excludeLabel.toggle(
+               this.itemModel.getGroupModel().getView() === 'namespaces' &&
+               this.itemModel.isSelected() &&
+               this.invertModel.isSelected()
+       );
+       this.toggle( this.itemModel.isVisible() );
+};
 
-       ItemMenuOptionWidget.prototype.getModel = function () {
-               return this.itemModel;
-       };
+/**
+ * Get the name of this filter
+ *
+ * @return {string} Filter name
+ */
+ItemMenuOptionWidget.prototype.getName = function () {
+       return this.itemModel.getName();
+};
 
-       module.exports = ItemMenuOptionWidget;
+ItemMenuOptionWidget.prototype.getModel = function () {
+       return this.itemModel;
+};
 
-}() );
+module.exports = ItemMenuOptionWidget;
index 3ccb6e2..04289c7 100644 (file)
@@ -1,72 +1,69 @@
-( function () {
-       /**
-        * Widget for toggling live updates
-        *
-        * @class mw.rcfilters.ui.LiveUpdateButtonWidget
-        * @extends OO.ui.ToggleButtonWidget
-        *
-        * @constructor
-        * @param {mw.rcfilters.Controller} controller
-        * @param {mw.rcfilters.dm.ChangesListViewModel} changesListModel
-        * @param {Object} [config] Configuration object
-        */
-       var LiveUpdateButtonWidget = function MwRcfiltersUiLiveUpdateButtonWidget( controller, changesListModel, config ) {
-               config = config || {};
+/**
+ * Widget for toggling live updates
+ *
+ * @class mw.rcfilters.ui.LiveUpdateButtonWidget
+ * @extends OO.ui.ToggleButtonWidget
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller
+ * @param {mw.rcfilters.dm.ChangesListViewModel} changesListModel
+ * @param {Object} [config] Configuration object
+ */
+var LiveUpdateButtonWidget = function MwRcfiltersUiLiveUpdateButtonWidget( controller, changesListModel, config ) {
+       config = config || {};
 
-               // Parent
-               LiveUpdateButtonWidget.parent.call( this, $.extend( {
-                       label: mw.message( 'rcfilters-liveupdates-button' ).text()
-               }, config ) );
+       // Parent
+       LiveUpdateButtonWidget.parent.call( this, $.extend( {
+               label: mw.message( 'rcfilters-liveupdates-button' ).text()
+       }, config ) );
 
-               this.controller = controller;
-               this.model = changesListModel;
+       this.controller = controller;
+       this.model = changesListModel;
 
-               // Events
-               this.connect( this, { click: 'onClick' } );
-               this.model.connect( this, { liveUpdateChange: 'onLiveUpdateChange' } );
+       // Events
+       this.connect( this, { click: 'onClick' } );
+       this.model.connect( this, { liveUpdateChange: 'onLiveUpdateChange' } );
 
-               this.$element.addClass( 'mw-rcfilters-ui-liveUpdateButtonWidget' );
+       this.$element.addClass( 'mw-rcfilters-ui-liveUpdateButtonWidget' );
 
-               this.setState( false );
-       };
+       this.setState( false );
+};
 
-       /* Initialization */
+/* Initialization */
 
-       OO.inheritClass( LiveUpdateButtonWidget, OO.ui.ToggleButtonWidget );
+OO.inheritClass( LiveUpdateButtonWidget, OO.ui.ToggleButtonWidget );
 
-       /* Methods */
+/* Methods */
 
-       /**
       * Respond to the button being clicked
       */
-       LiveUpdateButtonWidget.prototype.onClick = function () {
-               this.controller.toggleLiveUpdate();
-       };
+/**
+ * Respond to the button being clicked
+ */
+LiveUpdateButtonWidget.prototype.onClick = function () {
+       this.controller.toggleLiveUpdate();
+};
 
-       /**
       * Set the button's state and change its appearance
       *
       * @param {boolean} enable Whether the 'live update' feature is now on/off
       */
-       LiveUpdateButtonWidget.prototype.setState = function ( enable ) {
-               this.setValue( enable );
-               this.setIcon( enable ? 'stop' : 'play' );
-               this.setTitle( mw.message(
-                       enable ?
-                               'rcfilters-liveupdates-button-title-on' :
-                               'rcfilters-liveupdates-button-title-off'
-               ).text() );
-       };
+/**
+ * Set the button's state and change its appearance
+ *
+ * @param {boolean} enable Whether the 'live update' feature is now on/off
+ */
+LiveUpdateButtonWidget.prototype.setState = function ( enable ) {
+       this.setValue( enable );
+       this.setIcon( enable ? 'stop' : 'play' );
+       this.setTitle( mw.message(
+               enable ?
+                       'rcfilters-liveupdates-button-title-on' :
+                       'rcfilters-liveupdates-button-title-off'
+       ).text() );
+};
 
-       /**
       * Respond to the 'live update' feature being turned on/off
       *
       * @param {boolean} enable Whether the 'live update' feature is now on/off
       */
-       LiveUpdateButtonWidget.prototype.onLiveUpdateChange = function ( enable ) {
-               this.setState( enable );
-       };
+/**
+ * Respond to the 'live update' feature being turned on/off
+ *
+ * @param {boolean} enable Whether the 'live update' feature is now on/off
+ */
+LiveUpdateButtonWidget.prototype.onLiveUpdateChange = function ( enable ) {
+       this.setState( enable );
+};
 
-       module.exports = LiveUpdateButtonWidget;
-
-}() );
+module.exports = LiveUpdateButtonWidget;
index bc1cac8..31edb77 100644 (file)
-( function () {
-       var SavedLinksListWidget = require( './SavedLinksListWidget.js' ),
-               FilterWrapperWidget = require( './FilterWrapperWidget.js' ),
-               ChangesListWrapperWidget = require( './ChangesListWrapperWidget.js' ),
-               RcTopSectionWidget = require( './RcTopSectionWidget.js' ),
-               RclTopSectionWidget = require( './RclTopSectionWidget.js' ),
-               WatchlistTopSectionWidget = require( './WatchlistTopSectionWidget.js' ),
-               FormWrapperWidget = require( './FormWrapperWidget.js' ),
-               MainWrapperWidget;
-
-       /**
-        * Wrapper for changes list content
-        *
-        * @class mw.rcfilters.ui.MainWrapperWidget
-        * @extends OO.ui.Widget
-        *
-        * @constructor
-        * @param {mw.rcfilters.Controller} controller Controller
-        * @param {mw.rcfilters.dm.FiltersViewModel} model View model
-        * @param {mw.rcfilters.dm.SavedQueriesModel} savedQueriesModel Saved queries model
-        * @param {mw.rcfilters.dm.ChangesListViewModel} changesListModel
-        * @param {Object} config Configuration object
-        * @cfg {jQuery} $topSection Top section container
-        * @cfg {jQuery} $filtersContainer
-        * @cfg {jQuery} $changesListContainer
-        * @cfg {jQuery} $formContainer
-        * @cfg {boolean} [collapsed] Filter area is collapsed
-        * @cfg {jQuery} [$wrapper] A jQuery object for the wrapper of the general
-        *  system. If not given, falls back to this widget's $element
-        */
-       MainWrapperWidget = function MwRcfiltersUiMainWrapperWidget(
-               controller, model, savedQueriesModel, changesListModel, config
-       ) {
-               config = $.extend( {}, config );
-
-               // Parent
-               MainWrapperWidget.parent.call( this, config );
-
-               this.controller = controller;
-               this.model = model;
-               this.changesListModel = changesListModel;
-               this.$topSection = config.$topSection;
-               this.$filtersContainer = config.$filtersContainer;
-               this.$changesListContainer = config.$changesListContainer;
-               this.$formContainer = config.$formContainer;
-               this.$overlay = $( '<div>' ).addClass( 'mw-rcfilters-ui-overlay' );
-               this.$wrapper = config.$wrapper || this.$element;
-
-               this.savedLinksListWidget = new SavedLinksListWidget(
-                       controller, savedQueriesModel, { $overlay: this.$overlay }
-               );
-
-               this.filtersWidget = new FilterWrapperWidget(
-                       controller,
-                       model,
-                       savedQueriesModel,
-                       changesListModel,
-                       {
-                               $overlay: this.$overlay,
-                               $wrapper: this.$wrapper,
-                               collapsed: config.collapsed
-                       }
-               );
-
-               this.changesListWidget = new ChangesListWrapperWidget(
-                       model, changesListModel, controller, this.$changesListContainer );
+var SavedLinksListWidget = require( './SavedLinksListWidget.js' ),
+       FilterWrapperWidget = require( './FilterWrapperWidget.js' ),
+       ChangesListWrapperWidget = require( './ChangesListWrapperWidget.js' ),
+       RcTopSectionWidget = require( './RcTopSectionWidget.js' ),
+       RclTopSectionWidget = require( './RclTopSectionWidget.js' ),
+       WatchlistTopSectionWidget = require( './WatchlistTopSectionWidget.js' ),
+       FormWrapperWidget = require( './FormWrapperWidget.js' ),
+       MainWrapperWidget;
+
+/**
+ * Wrapper for changes list content
+ *
+ * @class mw.rcfilters.ui.MainWrapperWidget
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller Controller
+ * @param {mw.rcfilters.dm.FiltersViewModel} model View model
+ * @param {mw.rcfilters.dm.SavedQueriesModel} savedQueriesModel Saved queries model
+ * @param {mw.rcfilters.dm.ChangesListViewModel} changesListModel
+ * @param {Object} config Configuration object
+ * @cfg {jQuery} $topSection Top section container
+ * @cfg {jQuery} $filtersContainer
+ * @cfg {jQuery} $changesListContainer
+ * @cfg {jQuery} $formContainer
+ * @cfg {boolean} [collapsed] Filter area is collapsed
+ * @cfg {jQuery} [$wrapper] A jQuery object for the wrapper of the general
+ *  system. If not given, falls back to this widget's $element
+ */
+MainWrapperWidget = function MwRcfiltersUiMainWrapperWidget(
+       controller, model, savedQueriesModel, changesListModel, config
+) {
+       config = $.extend( {}, config );
+
+       // Parent
+       MainWrapperWidget.parent.call( this, config );
+
+       this.controller = controller;
+       this.model = model;
+       this.changesListModel = changesListModel;
+       this.$topSection = config.$topSection;
+       this.$filtersContainer = config.$filtersContainer;
+       this.$changesListContainer = config.$changesListContainer;
+       this.$formContainer = config.$formContainer;
+       this.$overlay = $( '<div>' ).addClass( 'mw-rcfilters-ui-overlay' );
+       this.$wrapper = config.$wrapper || this.$element;
+
+       this.savedLinksListWidget = new SavedLinksListWidget(
+               controller, savedQueriesModel, { $overlay: this.$overlay }
+       );
+
+       this.filtersWidget = new FilterWrapperWidget(
+               controller,
+               model,
+               savedQueriesModel,
+               changesListModel,
+               {
+                       $overlay: this.$overlay,
+                       $wrapper: this.$wrapper,
+                       collapsed: config.collapsed
+               }
+       );
 
-               /* Events */
+       this.changesListWidget = new ChangesListWrapperWidget(
+               model, changesListModel, controller, this.$changesListContainer );
 
-               // Toggle changes list overlay when filters menu opens/closes. We use overlay on changes list
-               // to prevent users from accidentally clicking on links in results, while menu is opened.
-               // Overlay on changes list is not the same as this.$overlay
-               this.filtersWidget.connect( this, { menuToggle: this.onFilterMenuToggle.bind( this ) } );
+       /* Events */
 
-               // Initialize
-               this.$filtersContainer.append( this.filtersWidget.$element );
-               $( 'body' )
-                       .append( this.$overlay )
-                       .addClass( 'mw-rcfilters-ui-initialized' );
-       };
+       // Toggle changes list overlay when filters menu opens/closes. We use overlay on changes list
+       // to prevent users from accidentally clicking on links in results, while menu is opened.
+       // Overlay on changes list is not the same as this.$overlay
+       this.filtersWidget.connect( this, { menuToggle: this.onFilterMenuToggle.bind( this ) } );
 
-       /* Initialization */
+       // Initialize
+       this.$filtersContainer.append( this.filtersWidget.$element );
+       $( 'body' )
+               .append( this.$overlay )
+               .addClass( 'mw-rcfilters-ui-initialized' );
+};
 
-       OO.inheritClass( MainWrapperWidget, OO.ui.Widget );
+/* Initialization */
 
-       /* Methods */
+OO.inheritClass( MainWrapperWidget, OO.ui.Widget );
 
-       /**
-        * Set the content of the top section, depending on the type of special page.
-        *
-        * @param {string} specialPage
-        */
-       MainWrapperWidget.prototype.setTopSection = function ( specialPage ) {
-               var topSection;
+/* Methods */
 
-               if ( specialPage === 'Recentchanges' ) {
-                       topSection = new RcTopSectionWidget(
-                               this.savedLinksListWidget, this.$topSection
-                       );
-                       this.filtersWidget.setTopSection( topSection.$element );
-               }
+/**
+ * Set the content of the top section, depending on the type of special page.
+ *
+ * @param {string} specialPage
+ */
+MainWrapperWidget.prototype.setTopSection = function ( specialPage ) {
+       var topSection;
 
-               if ( specialPage === 'Recentchangeslinked' ) {
-                       topSection = new RclTopSectionWidget(
-                               this.savedLinksListWidget, this.controller,
-                               this.model.getGroup( 'toOrFrom' ).getItemByParamName( 'showlinkedto' ),
-                               this.model.getGroup( 'page' ).getItemByParamName( 'target' )
-                       );
+       if ( specialPage === 'Recentchanges' ) {
+               topSection = new RcTopSectionWidget(
+                       this.savedLinksListWidget, this.$topSection
+               );
+               this.filtersWidget.setTopSection( topSection.$element );
+       }
+
+       if ( specialPage === 'Recentchangeslinked' ) {
+               topSection = new RclTopSectionWidget(
+                       this.savedLinksListWidget, this.controller,
+                       this.model.getGroup( 'toOrFrom' ).getItemByParamName( 'showlinkedto' ),
+                       this.model.getGroup( 'page' ).getItemByParamName( 'target' )
+               );
 
-                       this.filtersWidget.setTopSection( topSection.$element );
-               }
+               this.filtersWidget.setTopSection( topSection.$element );
+       }
 
-               if ( specialPage === 'Watchlist' ) {
-                       topSection = new WatchlistTopSectionWidget(
-                               this.controller, this.changesListModel, this.savedLinksListWidget, this.$topSection
-                       );
+       if ( specialPage === 'Watchlist' ) {
+               topSection = new WatchlistTopSectionWidget(
+                       this.controller, this.changesListModel, this.savedLinksListWidget, this.$topSection
+               );
 
-                       this.filtersWidget.setTopSection( topSection.$element );
-               }
-       };
-
-       /**
-        * Filter menu toggle event listener
-        *
-        * @param {boolean} isVisible
-        */
-       MainWrapperWidget.prototype.onFilterMenuToggle = function ( isVisible ) {
-               this.changesListWidget.toggleOverlay( isVisible );
-       };
-
-       /**
-        * Initialize FormWrapperWidget
-        *
-        * @return {mw.rcfilters.ui.FormWrapperWidget} Form wrapper widget
-        */
-       MainWrapperWidget.prototype.initFormWidget = function () {
-               return new FormWrapperWidget(
-                       this.model, this.changesListModel, this.controller, this.$formContainer );
-       };
-
-       module.exports = MainWrapperWidget;
-}() );
+               this.filtersWidget.setTopSection( topSection.$element );
+       }
+};
+
+/**
+ * Filter menu toggle event listener
+ *
+ * @param {boolean} isVisible
+ */
+MainWrapperWidget.prototype.onFilterMenuToggle = function ( isVisible ) {
+       this.changesListWidget.toggleOverlay( isVisible );
+};
+
+/**
+ * Initialize FormWrapperWidget
+ *
+ * @return {mw.rcfilters.ui.FormWrapperWidget} Form wrapper widget
+ */
+MainWrapperWidget.prototype.initFormWidget = function () {
+       return new FormWrapperWidget(
+               this.model, this.changesListModel, this.controller, this.$formContainer );
+};
+
+module.exports = MainWrapperWidget;
index 3914337..c7fa334 100644 (file)
@@ -1,58 +1,55 @@
-( function () {
-       /**
-        * Button for marking all changes as seen on the Watchlist
-        *
-        * @class mw.rcfilters.ui.MarkSeenButtonWidget
-        * @extends OO.ui.ButtonWidget
-        *
-        * @constructor
-        * @param {mw.rcfilters.Controller} controller
-        * @param {mw.rcfilters.dm.ChangesListViewModel} model Changes list view model
-        * @param {Object} [config] Configuration object
-        */
-       var MarkSeenButtonWidget = function MwRcfiltersUiMarkSeenButtonWidget( controller, model, config ) {
-               config = config || {};
-
-               // Parent
-               MarkSeenButtonWidget.parent.call( this, $.extend( {
-                       label: mw.message( 'rcfilters-watchlist-markseen-button' ).text(),
-                       icon: 'checkAll'
-               }, config ) );
-
-               this.controller = controller;
-               this.model = model;
-
-               // Events
-               this.connect( this, { click: 'onClick' } );
-               this.model.connect( this, { update: 'onModelUpdate' } );
-
-               this.$element.addClass( 'mw-rcfilters-ui-markSeenButtonWidget' );
-
-               this.onModelUpdate();
-       };
-
-       /* Initialization */
-
-       OO.inheritClass( MarkSeenButtonWidget, OO.ui.ButtonWidget );
-
-       /* Methods */
-
-       /**
-        * Respond to the button being clicked
-        */
-       MarkSeenButtonWidget.prototype.onClick = function () {
-               this.controller.markAllChangesAsSeen();
-               // assume there's no more unseen changes until the next model update
-               this.setDisabled( true );
-       };
-
-       /**
-        * Respond to the model being updated with new changes
-        */
-       MarkSeenButtonWidget.prototype.onModelUpdate = function () {
-               this.setDisabled( !this.model.hasUnseenWatchedChanges() );
-       };
-
-       module.exports = MarkSeenButtonWidget;
-
-}() );
+/**
+ * Button for marking all changes as seen on the Watchlist
+ *
+ * @class mw.rcfilters.ui.MarkSeenButtonWidget
+ * @extends OO.ui.ButtonWidget
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller
+ * @param {mw.rcfilters.dm.ChangesListViewModel} model Changes list view model
+ * @param {Object} [config] Configuration object
+ */
+var MarkSeenButtonWidget = function MwRcfiltersUiMarkSeenButtonWidget( controller, model, config ) {
+       config = config || {};
+
+       // Parent
+       MarkSeenButtonWidget.parent.call( this, $.extend( {
+               label: mw.message( 'rcfilters-watchlist-markseen-button' ).text(),
+               icon: 'checkAll'
+       }, config ) );
+
+       this.controller = controller;
+       this.model = model;
+
+       // Events
+       this.connect( this, { click: 'onClick' } );
+       this.model.connect( this, { update: 'onModelUpdate' } );
+
+       this.$element.addClass( 'mw-rcfilters-ui-markSeenButtonWidget' );
+
+       this.onModelUpdate();
+};
+
+/* Initialization */
+
+OO.inheritClass( MarkSeenButtonWidget, OO.ui.ButtonWidget );
+
+/* Methods */
+
+/**
+ * Respond to the button being clicked
+ */
+MarkSeenButtonWidget.prototype.onClick = function () {
+       this.controller.markAllChangesAsSeen();
+       // assume there's no more unseen changes until the next model update
+       this.setDisabled( true );
+};
+
+/**
+ * Respond to the model being updated with new changes
+ */
+MarkSeenButtonWidget.prototype.onModelUpdate = function () {
+       this.setDisabled( !this.model.hasUnseenWatchedChanges() );
+};
+
+module.exports = MarkSeenButtonWidget;
index 864d0cf..1e75020 100644 (file)
-( function () {
-       var FilterMenuHeaderWidget = require( './FilterMenuHeaderWidget.js' ),
-               HighlightPopupWidget = require( './HighlightPopupWidget.js' ),
-               FilterMenuSectionOptionWidget = require( './FilterMenuSectionOptionWidget.js' ),
-               FilterMenuOptionWidget = require( './FilterMenuOptionWidget.js' ),
-               MenuSelectWidget;
-
-       /**
-        * A floating menu widget for the filter list
-        *
-        * @class mw.rcfilters.ui.MenuSelectWidget
-        * @extends OO.ui.MenuSelectWidget
-        *
-        * @constructor
-        * @param {mw.rcfilters.Controller} controller Controller
-        * @param {mw.rcfilters.dm.FiltersViewModel} model View model
-        * @param {Object} [config] Configuration object
-        * @cfg {jQuery} [$overlay] A jQuery object serving as overlay for popups
-        * @cfg {Object[]} [footers] An array of objects defining the footers for
-        *  this menu, with a definition whether they appear per specific views.
-        *  The expected structure is:
-        *  [
-        *     {
-        *        name: {string} A unique name for the footer object
-        *        $element: {jQuery} A jQuery object for the content of the footer
-        *        views: {string[]} Optional. An array stating which views this footer is
-        *               active on. Use null or omit to display this on all views.
-        *     }
-        *  ]
-        */
-       MenuSelectWidget = function MwRcfiltersUiMenuSelectWidget( controller, model, config ) {
-               var header;
-
-               config = config || {};
-
-               this.controller = controller;
-               this.model = model;
-               this.currentView = '';
-               this.views = {};
-               this.userSelecting = false;
-
-               this.menuInitialized = false;
-               this.$overlay = config.$overlay || this.$element;
-               this.$body = $( '<div>' ).addClass( 'mw-rcfilters-ui-menuSelectWidget-body' );
-               this.footers = [];
-
-               // Parent
-               MenuSelectWidget.parent.call( this, $.extend( config, {
-                       $autoCloseIgnore: this.$overlay,
-                       width: 650,
-                       // Our filtering is done through the model
-                       filterFromInput: false
-               } ) );
-               this.setGroupElement(
-                       $( '<div>' )
-                               .addClass( 'mw-rcfilters-ui-menuSelectWidget-group' )
-               );
-               this.setClippableElement( this.$body );
-               this.setClippableContainer( this.$element );
-
-               header = new FilterMenuHeaderWidget(
-                       this.controller,
-                       this.model,
-                       {
-                               $overlay: this.$overlay
-                       }
+var FilterMenuHeaderWidget = require( './FilterMenuHeaderWidget.js' ),
+       HighlightPopupWidget = require( './HighlightPopupWidget.js' ),
+       FilterMenuSectionOptionWidget = require( './FilterMenuSectionOptionWidget.js' ),
+       FilterMenuOptionWidget = require( './FilterMenuOptionWidget.js' ),
+       MenuSelectWidget;
+
+/**
+ * A floating menu widget for the filter list
+ *
+ * @class mw.rcfilters.ui.MenuSelectWidget
+ * @extends OO.ui.MenuSelectWidget
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller Controller
+ * @param {mw.rcfilters.dm.FiltersViewModel} model View model
+ * @param {Object} [config] Configuration object
+ * @cfg {jQuery} [$overlay] A jQuery object serving as overlay for popups
+ * @cfg {Object[]} [footers] An array of objects defining the footers for
+ *  this menu, with a definition whether they appear per specific views.
+ *  The expected structure is:
+ *  [
+ *     {
+ *        name: {string} A unique name for the footer object
+ *        $element: {jQuery} A jQuery object for the content of the footer
+ *        views: {string[]} Optional. An array stating which views this footer is
+ *               active on. Use null or omit to display this on all views.
+ *     }
+ *  ]
+ */
+MenuSelectWidget = function MwRcfiltersUiMenuSelectWidget( controller, model, config ) {
+       var header;
+
+       config = config || {};
+
+       this.controller = controller;
+       this.model = model;
+       this.currentView = '';
+       this.views = {};
+       this.userSelecting = false;
+
+       this.menuInitialized = false;
+       this.$overlay = config.$overlay || this.$element;
+       this.$body = $( '<div>' ).addClass( 'mw-rcfilters-ui-menuSelectWidget-body' );
+       this.footers = [];
+
+       // Parent
+       MenuSelectWidget.parent.call( this, $.extend( config, {
+               $autoCloseIgnore: this.$overlay,
+               width: 650,
+               // Our filtering is done through the model
+               filterFromInput: false
+       } ) );
+       this.setGroupElement(
+               $( '<div>' )
+                       .addClass( 'mw-rcfilters-ui-menuSelectWidget-group' )
+       );
+       this.setClippableElement( this.$body );
+       this.setClippableContainer( this.$element );
+
+       header = new FilterMenuHeaderWidget(
+               this.controller,
+               this.model,
+               {
+                       $overlay: this.$overlay
+               }
+       );
+
+       this.noResults = new OO.ui.LabelWidget( {
+               label: mw.msg( 'rcfilters-filterlist-noresults' ),
+               classes: [ 'mw-rcfilters-ui-menuSelectWidget-noresults' ]
+       } );
+
+       // Events
+       this.model.connect( this, {
+               initialize: 'onModelInitialize',
+               searchChange: 'onModelSearchChange'
+       } );
+
+       // Initialization
+       this.$element
+               .addClass( 'mw-rcfilters-ui-menuSelectWidget' )
+               .append( header.$element )
+               .append(
+                       this.$body
+                               .append( this.$group, this.noResults.$element )
                );
 
-               this.noResults = new OO.ui.LabelWidget( {
-                       label: mw.msg( 'rcfilters-filterlist-noresults' ),
-                       classes: [ 'mw-rcfilters-ui-menuSelectWidget-noresults' ]
-               } );
-
-               // Events
-               this.model.connect( this, {
-                       initialize: 'onModelInitialize',
-                       searchChange: 'onModelSearchChange'
-               } );
-
-               // Initialization
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-menuSelectWidget' )
-                       .append( header.$element )
-                       .append(
-                               this.$body
-                                       .append( this.$group, this.noResults.$element )
-                       );
-
-               // Append all footers; we will control their visibility
-               // based on view
-               config.footers = config.footers || [];
-               config.footers.forEach( function ( footerData ) {
-                       var isSticky = footerData.sticky === undefined ? true : !!footerData.sticky,
-                               adjustedData = {
-                                       // Wrap the element with our own footer wrapper
-                                       $element: $( '<div>' )
-                                               .addClass( 'mw-rcfilters-ui-menuSelectWidget-footer' )
-                                               .addClass( 'mw-rcfilters-ui-menuSelectWidget-footer-' + footerData.name )
-                                               .append( footerData.$element ),
-                                       views: footerData.views
-                               };
-
-                       if ( !footerData.disabled ) {
-                               this.footers.push( adjustedData );
-
-                               if ( isSticky ) {
-                                       this.$element.append( adjustedData.$element );
-                               } else {
-                                       this.$body.append( adjustedData.$element );
-                               }
+       // Append all footers; we will control their visibility
+       // based on view
+       config.footers = config.footers || [];
+       config.footers.forEach( function ( footerData ) {
+               var isSticky = footerData.sticky === undefined ? true : !!footerData.sticky,
+                       adjustedData = {
+                               // Wrap the element with our own footer wrapper
+                               $element: $( '<div>' )
+                                       .addClass( 'mw-rcfilters-ui-menuSelectWidget-footer' )
+                                       .addClass( 'mw-rcfilters-ui-menuSelectWidget-footer-' + footerData.name )
+                                       .append( footerData.$element ),
+                               views: footerData.views
+                       };
+
+               if ( !footerData.disabled ) {
+                       this.footers.push( adjustedData );
+
+                       if ( isSticky ) {
+                               this.$element.append( adjustedData.$element );
+                       } else {
+                               this.$body.append( adjustedData.$element );
                        }
-               }.bind( this ) );
-
-               // Switch to the correct view
-               this.updateView();
-       };
-
-       /* Initialize */
-
-       OO.inheritClass( MenuSelectWidget, OO.ui.MenuSelectWidget );
-
-       /* Events */
-
-       /* Methods */
-       MenuSelectWidget.prototype.onModelSearchChange = function () {
-               this.updateView();
-       };
-
-       /**
-        * @inheritdoc
-        */
-       MenuSelectWidget.prototype.toggle = function ( show ) {
-               this.lazyMenuCreation();
-               MenuSelectWidget.parent.prototype.toggle.call( this, show );
-               // Always open this menu downwards. FilterTagMultiselectWidget scrolls it into view.
-               this.setVerticalPosition( 'below' );
-       };
-
-       /**
-        * lazy creation of the menu
-        */
-       MenuSelectWidget.prototype.lazyMenuCreation = function () {
-               var widget = this,
-                       items = [],
-                       viewGroupCount = {},
-                       groups = this.model.getFilterGroups();
-
-               if ( this.menuInitialized ) {
-                       return;
                }
-
-               this.menuInitialized = true;
-
-               // Create shared popup for highlight buttons
-               this.highlightPopup = new HighlightPopupWidget( this.controller );
-               this.$overlay.append( this.highlightPopup.$element );
-
-               // Count groups per view
-               // eslint-disable-next-line no-jquery/no-each-util
-               $.each( groups, function ( groupName, groupModel ) {
-                       if ( !groupModel.isHidden() ) {
-                               viewGroupCount[ groupModel.getView() ] = viewGroupCount[ groupModel.getView() ] || 0;
-                               viewGroupCount[ groupModel.getView() ]++;
-                       }
-               } );
-
-               // eslint-disable-next-line no-jquery/no-each-util
-               $.each( groups, function ( groupName, groupModel ) {
-                       var currentItems = [],
-                               view = groupModel.getView();
-
-                       if ( !groupModel.isHidden() ) {
-                               if ( viewGroupCount[ view ] > 1 ) {
-                                       // Only add a section header if there is more than
-                                       // one group
-                                       currentItems.push(
-                                               // Group section
-                                               new FilterMenuSectionOptionWidget(
-                                                       widget.controller,
-                                                       groupModel,
-                                                       {
-                                                               $overlay: widget.$overlay
-                                                       }
-                                               )
-                                       );
-                               }
-
-                               // Add items
-                               widget.model.getGroupFilters( groupName ).forEach( function ( filterItem ) {
-                                       currentItems.push(
-                                               new FilterMenuOptionWidget(
-                                                       widget.controller,
-                                                       widget.model,
-                                                       widget.model.getInvertModel(),
-                                                       filterItem,
-                                                       widget.highlightPopup,
-                                                       {
-                                                               $overlay: widget.$overlay
-                                                       }
-                                               )
-                                       );
-                               } );
-
-                               // Cache the items per view, so we can switch between them
-                               // without rebuilding the widgets each time
-                               widget.views[ view ] = widget.views[ view ] || [];
-                               widget.views[ view ] = widget.views[ view ].concat( currentItems );
-                               items = items.concat( currentItems );
-                       }
-               } );
-
-               this.addItems( items );
-               this.updateView();
-       };
-
-       /**
-        * Respond to model initialize event. Populate the menu from the model
-        */
-       MenuSelectWidget.prototype.onModelInitialize = function () {
-               this.menuInitialized = false;
-               // Set timeout for the menu to lazy build.
-               setTimeout( this.lazyMenuCreation.bind( this ) );
-       };
-
-       /**
-        * Update view
-        */
-       MenuSelectWidget.prototype.updateView = function () {
-               var viewName = this.model.getCurrentView();
-
-               if ( this.views[ viewName ] && this.currentView !== viewName ) {
-                       this.updateFooterVisibility( viewName );
-
-                       this.$element
-                               .data( 'view', viewName )
-                               .removeClass( 'mw-rcfilters-ui-menuSelectWidget-view-' + this.currentView )
-                               .addClass( 'mw-rcfilters-ui-menuSelectWidget-view-' + viewName );
-
-                       this.currentView = viewName;
-                       this.scrollToTop();
+       }.bind( this ) );
+
+       // Switch to the correct view
+       this.updateView();
+};
+
+/* Initialize */
+
+OO.inheritClass( MenuSelectWidget, OO.ui.MenuSelectWidget );
+
+/* Events */
+
+/* Methods */
+MenuSelectWidget.prototype.onModelSearchChange = function () {
+       this.updateView();
+};
+
+/**
+ * @inheritdoc
+ */
+MenuSelectWidget.prototype.toggle = function ( show ) {
+       this.lazyMenuCreation();
+       MenuSelectWidget.parent.prototype.toggle.call( this, show );
+       // Always open this menu downwards. FilterTagMultiselectWidget scrolls it into view.
+       this.setVerticalPosition( 'below' );
+};
+
+/**
+ * lazy creation of the menu
+ */
+MenuSelectWidget.prototype.lazyMenuCreation = function () {
+       var widget = this,
+               items = [],
+               viewGroupCount = {},
+               groups = this.model.getFilterGroups();
+
+       if ( this.menuInitialized ) {
+               return;
+       }
+
+       this.menuInitialized = true;
+
+       // Create shared popup for highlight buttons
+       this.highlightPopup = new HighlightPopupWidget( this.controller );
+       this.$overlay.append( this.highlightPopup.$element );
+
+       // Count groups per view
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( groups, function ( groupName, groupModel ) {
+               if ( !groupModel.isHidden() ) {
+                       viewGroupCount[ groupModel.getView() ] = viewGroupCount[ groupModel.getView() ] || 0;
+                       viewGroupCount[ groupModel.getView() ]++;
                }
-
-               this.postProcessItems();
-               this.clip();
-       };
-
-       /**
-        * Go over the available footers and decide which should be visible
-        * for this view
-        *
-        * @param {string} [currentView] Current view
-        */
-       MenuSelectWidget.prototype.updateFooterVisibility = function ( currentView ) {
-               currentView = currentView || this.model.getCurrentView();
-
-               this.footers.forEach( function ( data ) {
-                       data.$element.toggle(
-                               // This footer should only be shown if it is configured
-                               // for all views or for this specific view
-                               !data.views || data.views.length === 0 || data.views.indexOf( currentView ) > -1
-                       );
-               } );
-       };
-
-       /**
-        * Post-process items after the visibility changed. Make sure
-        * that we always have an item selected, and that the no-results
-        * widget appears if the menu is empty.
-        */
-       MenuSelectWidget.prototype.postProcessItems = function () {
-               var i,
-                       itemWasSelected = false,
-                       items = this.getItems();
-
-               // If we are not already selecting an item, always make sure
-               // that the top item is selected
-               if ( !this.userSelecting ) {
-                       // Select the first item in the list
-                       for ( i = 0; i < items.length; i++ ) {
-                               if (
-                                       !( items[ i ] instanceof OO.ui.MenuSectionOptionWidget ) &&
-                                       items[ i ].isVisible()
-                               ) {
-                                       itemWasSelected = true;
-                                       this.selectItem( items[ i ] );
-                                       break;
-                               }
+       } );
+
+       // eslint-disable-next-line no-jquery/no-each-util
+       $.each( groups, function ( groupName, groupModel ) {
+               var currentItems = [],
+                       view = groupModel.getView();
+
+               if ( !groupModel.isHidden() ) {
+                       if ( viewGroupCount[ view ] > 1 ) {
+                               // Only add a section header if there is more than
+                               // one group
+                               currentItems.push(
+                                       // Group section
+                                       new FilterMenuSectionOptionWidget(
+                                               widget.controller,
+                                               groupModel,
+                                               {
+                                                       $overlay: widget.$overlay
+                                               }
+                                       )
+                               );
                        }
 
-                       if ( !itemWasSelected ) {
-                               this.selectItem( null );
-                       }
+                       // Add items
+                       widget.model.getGroupFilters( groupName ).forEach( function ( filterItem ) {
+                               currentItems.push(
+                                       new FilterMenuOptionWidget(
+                                               widget.controller,
+                                               widget.model,
+                                               widget.model.getInvertModel(),
+                                               filterItem,
+                                               widget.highlightPopup,
+                                               {
+                                                       $overlay: widget.$overlay
+                                               }
+                                       )
+                               );
+                       } );
+
+                       // Cache the items per view, so we can switch between them
+                       // without rebuilding the widgets each time
+                       widget.views[ view ] = widget.views[ view ] || [];
+                       widget.views[ view ] = widget.views[ view ].concat( currentItems );
+                       items = items.concat( currentItems );
                }
+       } );
+
+       this.addItems( items );
+       this.updateView();
+};
+
+/**
+ * Respond to model initialize event. Populate the menu from the model
+ */
+MenuSelectWidget.prototype.onModelInitialize = function () {
+       this.menuInitialized = false;
+       // Set timeout for the menu to lazy build.
+       setTimeout( this.lazyMenuCreation.bind( this ) );
+};
+
+/**
+ * Update view
+ */
+MenuSelectWidget.prototype.updateView = function () {
+       var viewName = this.model.getCurrentView();
+
+       if ( this.views[ viewName ] && this.currentView !== viewName ) {
+               this.updateFooterVisibility( viewName );
 
-               this.noResults.toggle( !this.getItems().some( function ( item ) {
-                       return item.isVisible();
-               } ) );
-       };
-
-       /**
-        * Get the option widget that matches the model given
-        *
-        * @param {mw.rcfilters.dm.ItemModel} model Item model
-        * @return {mw.rcfilters.ui.ItemMenuOptionWidget} Option widget
-        */
-       MenuSelectWidget.prototype.getItemFromModel = function ( model ) {
-               this.lazyMenuCreation();
-               return this.views[ model.getGroupModel().getView() ].filter( function ( item ) {
-                       return item.getName() === model.getName();
-               } )[ 0 ];
-       };
-
-       /**
-        * @inheritdoc
-        */
-       MenuSelectWidget.prototype.onDocumentKeyDown = function ( e ) {
-               var nextItem,
-                       currentItem = this.findHighlightedItem() || this.findSelectedItem();
-
-               // Call parent
-               MenuSelectWidget.parent.prototype.onDocumentKeyDown.call( this, e );
-
-               // We want to select the item on arrow movement
-               // rather than just highlight it, like the menu
-               // does by default
-               if ( !this.isDisabled() && this.isVisible() ) {
-                       switch ( e.keyCode ) {
-                               case OO.ui.Keys.UP:
-                               case OO.ui.Keys.LEFT:
-                                       // Get the next item
-                                       nextItem = this.findRelativeSelectableItem( currentItem, -1 );
-                                       break;
-                               case OO.ui.Keys.DOWN:
-                               case OO.ui.Keys.RIGHT:
-                                       // Get the next item
-                                       nextItem = this.findRelativeSelectableItem( currentItem, 1 );
-                                       break;
+               this.$element
+                       .data( 'view', viewName )
+                       .removeClass( 'mw-rcfilters-ui-menuSelectWidget-view-' + this.currentView )
+                       .addClass( 'mw-rcfilters-ui-menuSelectWidget-view-' + viewName );
+
+               this.currentView = viewName;
+               this.scrollToTop();
+       }
+
+       this.postProcessItems();
+       this.clip();
+};
+
+/**
+ * Go over the available footers and decide which should be visible
+ * for this view
+ *
+ * @param {string} [currentView] Current view
+ */
+MenuSelectWidget.prototype.updateFooterVisibility = function ( currentView ) {
+       currentView = currentView || this.model.getCurrentView();
+
+       this.footers.forEach( function ( data ) {
+               data.$element.toggle(
+                       // This footer should only be shown if it is configured
+                       // for all views or for this specific view
+                       !data.views || data.views.length === 0 || data.views.indexOf( currentView ) > -1
+               );
+       } );
+};
+
+/**
+ * Post-process items after the visibility changed. Make sure
+ * that we always have an item selected, and that the no-results
+ * widget appears if the menu is empty.
+ */
+MenuSelectWidget.prototype.postProcessItems = function () {
+       var i,
+               itemWasSelected = false,
+               items = this.getItems();
+
+       // If we are not already selecting an item, always make sure
+       // that the top item is selected
+       if ( !this.userSelecting ) {
+               // Select the first item in the list
+               for ( i = 0; i < items.length; i++ ) {
+                       if (
+                               !( items[ i ] instanceof OO.ui.MenuSectionOptionWidget ) &&
+                               items[ i ].isVisible()
+                       ) {
+                               itemWasSelected = true;
+                               this.selectItem( items[ i ] );
+                               break;
                        }
+               }
 
-                       nextItem = nextItem && nextItem.constructor.static.selectable ?
-                               nextItem : null;
-
-                       // Select the next item
-                       this.selectItem( nextItem );
+               if ( !itemWasSelected ) {
+                       this.selectItem( null );
                }
-       };
-
-       /**
-        * Scroll to the top of the menu
-        */
-       MenuSelectWidget.prototype.scrollToTop = function () {
-               this.$body.scrollTop( 0 );
-       };
-
-       /**
-        * Set whether the user is currently selecting an item.
-        * This is important when the user selects an item that is in between
-        * different views, and makes sure we do not re-select a different
-        * item (like the item on top) when this is happening.
-        *
-        * @param {boolean} isSelecting User is selecting
-        */
-       MenuSelectWidget.prototype.setUserSelecting = function ( isSelecting ) {
-               this.userSelecting = !!isSelecting;
-       };
-
-       module.exports = MenuSelectWidget;
-}() );
+       }
+
+       this.noResults.toggle( !this.getItems().some( function ( item ) {
+               return item.isVisible();
+       } ) );
+};
+
+/**
+ * Get the option widget that matches the model given
+ *
+ * @param {mw.rcfilters.dm.ItemModel} model Item model
+ * @return {mw.rcfilters.ui.ItemMenuOptionWidget} Option widget
+ */
+MenuSelectWidget.prototype.getItemFromModel = function ( model ) {
+       this.lazyMenuCreation();
+       return this.views[ model.getGroupModel().getView() ].filter( function ( item ) {
+               return item.getName() === model.getName();
+       } )[ 0 ];
+};
+
+/**
+ * @inheritdoc
+ */
+MenuSelectWidget.prototype.onDocumentKeyDown = function ( e ) {
+       var nextItem,
+               currentItem = this.findHighlightedItem() || this.findSelectedItem();
+
+       // Call parent
+       MenuSelectWidget.parent.prototype.onDocumentKeyDown.call( this, e );
+
+       // We want to select the item on arrow movement
+       // rather than just highlight it, like the menu
+       // does by default
+       if ( !this.isDisabled() && this.isVisible() ) {
+               switch ( e.keyCode ) {
+                       case OO.ui.Keys.UP:
+                       case OO.ui.Keys.LEFT:
+                               // Get the next item
+                               nextItem = this.findRelativeSelectableItem( currentItem, -1 );
+                               break;
+                       case OO.ui.Keys.DOWN:
+                       case OO.ui.Keys.RIGHT:
+                               // Get the next item
+                               nextItem = this.findRelativeSelectableItem( currentItem, 1 );
+                               break;
+               }
+
+               nextItem = nextItem && nextItem.constructor.static.selectable ?
+                       nextItem : null;
+
+               // Select the next item
+               this.selectItem( nextItem );
+       }
+};
+
+/**
+ * Scroll to the top of the menu
+ */
+MenuSelectWidget.prototype.scrollToTop = function () {
+       this.$body.scrollTop( 0 );
+};
+
+/**
+ * Set whether the user is currently selecting an item.
+ * This is important when the user selects an item that is in between
+ * different views, and makes sure we do not re-select a different
+ * item (like the item on top) when this is happening.
+ *
+ * @param {boolean} isSelecting User is selecting
+ */
+MenuSelectWidget.prototype.setUserSelecting = function ( isSelecting ) {
+       this.userSelecting = !!isSelecting;
+};
+
+module.exports = MenuSelectWidget;
index 6de9c40..3d56fba 100644 (file)
-( function () {
-       /**
-        * Top section (between page title and filters) on Special:Recentchanges
-        *
-        * @class mw.rcfilters.ui.RcTopSectionWidget
-        * @extends OO.ui.Widget
-        *
-        * @constructor
-        * @param {mw.rcfilters.ui.SavedLinksListWidget} savedLinksListWidget
-        * @param {jQuery} $topLinks Content of the community-defined links
-        * @param {Object} [config] Configuration object
-        */
-       var RcTopSectionWidget = function MwRcfiltersUiRcTopSectionWidget(
-               savedLinksListWidget, $topLinks, config
-       ) {
-               var toplinksTitle,
-                       topLinksCookieName = 'rcfilters-toplinks-collapsed-state',
-                       topLinksCookie = mw.cookie.get( topLinksCookieName ),
-                       topLinksCookieValue = topLinksCookie || 'collapsed',
-                       widget = this;
+/**
+ * Top section (between page title and filters) on Special:Recentchanges
+ *
+ * @class mw.rcfilters.ui.RcTopSectionWidget
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {mw.rcfilters.ui.SavedLinksListWidget} savedLinksListWidget
+ * @param {jQuery} $topLinks Content of the community-defined links
+ * @param {Object} [config] Configuration object
+ */
+var RcTopSectionWidget = function MwRcfiltersUiRcTopSectionWidget(
+       savedLinksListWidget, $topLinks, config
+) {
+       var toplinksTitle,
+               topLinksCookieName = 'rcfilters-toplinks-collapsed-state',
+               topLinksCookie = mw.cookie.get( topLinksCookieName ),
+               topLinksCookieValue = topLinksCookie || 'collapsed',
+               widget = this;
 
-               config = config || {};
+       config = config || {};
 
-               // Parent
-               RcTopSectionWidget.parent.call( this, config );
+       // Parent
+       RcTopSectionWidget.parent.call( this, config );
 
-               this.$topLinks = $topLinks;
+       this.$topLinks = $topLinks;
 
-               toplinksTitle = new OO.ui.ButtonWidget( {
-                       framed: false,
-                       indicator: topLinksCookieValue === 'collapsed' ? 'down' : 'up',
-                       flags: [ 'progressive' ],
-                       label: $( '<span>' ).append( mw.message( 'rcfilters-other-review-tools' ).parse() ).contents()
-               } );
+       toplinksTitle = new OO.ui.ButtonWidget( {
+               framed: false,
+               indicator: topLinksCookieValue === 'collapsed' ? 'down' : 'up',
+               flags: [ 'progressive' ],
+               label: $( '<span>' ).append( mw.message( 'rcfilters-other-review-tools' ).parse() ).contents()
+       } );
 
-               this.$topLinks
-                       .makeCollapsible( {
-                               collapsed: topLinksCookieValue === 'collapsed',
-                               $customTogglers: toplinksTitle.$element
-                       } )
-                       .on( 'beforeExpand.mw-collapsible', function () {
-                               mw.cookie.set( topLinksCookieName, 'expanded' );
-                               toplinksTitle.setIndicator( 'up' );
-                               widget.switchTopLinks( 'expanded' );
-                       } )
-                       .on( 'beforeCollapse.mw-collapsible', function () {
-                               mw.cookie.set( topLinksCookieName, 'collapsed' );
-                               toplinksTitle.setIndicator( 'down' );
-                               widget.switchTopLinks( 'collapsed' );
-                       } );
+       this.$topLinks
+               .makeCollapsible( {
+                       collapsed: topLinksCookieValue === 'collapsed',
+                       $customTogglers: toplinksTitle.$element
+               } )
+               .on( 'beforeExpand.mw-collapsible', function () {
+                       mw.cookie.set( topLinksCookieName, 'expanded' );
+                       toplinksTitle.setIndicator( 'up' );
+                       widget.switchTopLinks( 'expanded' );
+               } )
+               .on( 'beforeCollapse.mw-collapsible', function () {
+                       mw.cookie.set( topLinksCookieName, 'collapsed' );
+                       toplinksTitle.setIndicator( 'down' );
+                       widget.switchTopLinks( 'collapsed' );
+               } );
 
-               this.$topLinks.find( '.mw-recentchanges-toplinks-title' )
-                       .replaceWith( toplinksTitle.$element.removeAttr( 'tabIndex' ) );
+       this.$topLinks.find( '.mw-recentchanges-toplinks-title' )
+               .replaceWith( toplinksTitle.$element.removeAttr( 'tabIndex' ) );
 
-               // Create two positions for the toplinks to toggle between
-               // in the table (first cell) or up above it
-               this.$top = $( '<div>' )
-                       .addClass( 'mw-rcfilters-ui-rcTopSectionWidget-topLinks-top' );
-               this.$tableTopLinks = $( '<div>' )
-                       .addClass( 'mw-rcfilters-ui-cell' )
-                       .addClass( 'mw-rcfilters-ui-rcTopSectionWidget-topLinks-table' );
+       // Create two positions for the toplinks to toggle between
+       // in the table (first cell) or up above it
+       this.$top = $( '<div>' )
+               .addClass( 'mw-rcfilters-ui-rcTopSectionWidget-topLinks-top' );
+       this.$tableTopLinks = $( '<div>' )
+               .addClass( 'mw-rcfilters-ui-cell' )
+               .addClass( 'mw-rcfilters-ui-rcTopSectionWidget-topLinks-table' );
 
-               // Initialize
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-rcTopSectionWidget' )
-                       .append(
-                               $( '<div>' )
-                                       .addClass( 'mw-rcfilters-ui-table' )
-                                       .append(
-                                               $( '<div>' )
-                                                       .addClass( 'mw-rcfilters-ui-row' )
-                                                       .append(
-                                                               this.$tableTopLinks,
+       // Initialize
+       this.$element
+               .addClass( 'mw-rcfilters-ui-rcTopSectionWidget' )
+               .append(
+                       $( '<div>' )
+                               .addClass( 'mw-rcfilters-ui-table' )
+                               .append(
+                                       $( '<div>' )
+                                               .addClass( 'mw-rcfilters-ui-row' )
+                                               .append(
+                                                       this.$tableTopLinks,
+                                                       $( '<div>' )
+                                                               .addClass( 'mw-rcfilters-ui-table-placeholder' )
+                                                               .addClass( 'mw-rcfilters-ui-cell' ),
+                                                       !mw.user.isAnon() ?
                                                                $( '<div>' )
-                                                                       .addClass( 'mw-rcfilters-ui-table-placeholder' )
-                                                                       .addClass( 'mw-rcfilters-ui-cell' ),
-                                                               !mw.user.isAnon() ?
-                                                                       $( '<div>' )
-                                                                               .addClass( 'mw-rcfilters-ui-cell' )
-                                                                               .addClass( 'mw-rcfilters-ui-rcTopSectionWidget-savedLinks' )
-                                                                               .append( savedLinksListWidget.$element ) :
-                                                                       null
-                                                       )
-                                       )
-                       );
+                                                                       .addClass( 'mw-rcfilters-ui-cell' )
+                                                                       .addClass( 'mw-rcfilters-ui-rcTopSectionWidget-savedLinks' )
+                                                                       .append( savedLinksListWidget.$element ) :
+                                                               null
+                                               )
+                               )
+               );
 
-               // Hack: For jumpiness reasons, this should be a sibling of -head
-               $( '.rcfilters-head' ).before( this.$top );
+       // Hack: For jumpiness reasons, this should be a sibling of -head
+       $( '.rcfilters-head' ).before( this.$top );
 
-               // Initialize top links position
-               widget.switchTopLinks( topLinksCookieValue );
-       };
+       // Initialize top links position
+       widget.switchTopLinks( topLinksCookieValue );
+};
 
-       /* Initialization */
+/* Initialization */
 
-       OO.inheritClass( RcTopSectionWidget, OO.ui.Widget );
+OO.inheritClass( RcTopSectionWidget, OO.ui.Widget );
 
-       /**
       * Switch the top links widget from inside the table (when collapsed)
       * to the 'top' (when open)
       *
       * @param {string} [state] The state of the top links widget: 'expanded' or 'collapsed'
       */
-       RcTopSectionWidget.prototype.switchTopLinks = function ( state ) {
-               state = state || 'expanded';
+/**
+ * Switch the top links widget from inside the table (when collapsed)
+ * to the 'top' (when open)
+ *
+ * @param {string} [state] The state of the top links widget: 'expanded' or 'collapsed'
+ */
+RcTopSectionWidget.prototype.switchTopLinks = function ( state ) {
+       state = state || 'expanded';
 
-               if ( state === 'expanded' ) {
-                       this.$top.append( this.$topLinks );
-               } else {
-                       this.$tableTopLinks.append( this.$topLinks );
-               }
-               this.$topLinks.toggleClass( 'mw-recentchanges-toplinks-collapsed', state === 'collapsed' );
-       };
+       if ( state === 'expanded' ) {
+               this.$top.append( this.$topLinks );
+       } else {
+               this.$tableTopLinks.append( this.$topLinks );
+       }
+       this.$topLinks.toggleClass( 'mw-recentchanges-toplinks-collapsed', state === 'collapsed' );
+};
 
-       module.exports = RcTopSectionWidget;
-}() );
+module.exports = RcTopSectionWidget;
index 6eb0d5b..382b54c 100644 (file)
@@ -1,82 +1,80 @@
-( function () {
-       /**
-        * Widget to select and display target page on Special:RecentChangesLinked (AKA Related Changes)
-        *
-        * @class mw.rcfilters.ui.RclTargetPageWidget
-        * @extends OO.ui.Widget
-        *
-        * @constructor
-        * @param {mw.rcfilters.Controller} controller
-        * @param {mw.rcfilters.dm.FilterItem} targetPageModel
-        * @param {Object} [config] Configuration object
-        */
-       var RclTargetPageWidget = function MwRcfiltersUiRclTargetPageWidget(
-               controller, targetPageModel, config
-       ) {
-               config = config || {};
+/**
+ * Widget to select and display target page on Special:RecentChangesLinked (AKA Related Changes)
+ *
+ * @class mw.rcfilters.ui.RclTargetPageWidget
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller
+ * @param {mw.rcfilters.dm.FilterItem} targetPageModel
+ * @param {Object} [config] Configuration object
+ */
+var RclTargetPageWidget = function MwRcfiltersUiRclTargetPageWidget(
+       controller, targetPageModel, config
+) {
+       config = config || {};
 
-               // Parent
-               RclTargetPageWidget.parent.call( this, config );
+       // Parent
+       RclTargetPageWidget.parent.call( this, config );
 
-               this.controller = controller;
-               this.model = targetPageModel;
+       this.controller = controller;
+       this.model = targetPageModel;
 
-               this.titleSearch = new mw.widgets.TitleInputWidget( {
-                       validate: false,
-                       placeholder: mw.msg( 'rcfilters-target-page-placeholder' ),
-                       showImages: true,
-                       showDescriptions: true,
-                       addQueryInput: false
-               } );
+       this.titleSearch = new mw.widgets.TitleInputWidget( {
+               validate: false,
+               placeholder: mw.msg( 'rcfilters-target-page-placeholder' ),
+               showImages: true,
+               showDescriptions: true,
+               addQueryInput: false
+       } );
 
-               // Events
-               this.model.connect( this, { update: 'updateUiBasedOnModel' } );
+       // Events
+       this.model.connect( this, { update: 'updateUiBasedOnModel' } );
 
-               this.titleSearch.$input.on( {
-                       blur: this.onLookupInputBlur.bind( this )
-               } );
+       this.titleSearch.$input.on( {
+               blur: this.onLookupInputBlur.bind( this )
+       } );
 
-               this.titleSearch.lookupMenu.connect( this, {
-                       choose: 'onLookupMenuItemChoose'
-               } );
+       this.titleSearch.lookupMenu.connect( this, {
+               choose: 'onLookupMenuItemChoose'
+       } );
 
-               // Initialize
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-rclTargetPageWidget' )
-                       .append( this.titleSearch.$element );
+       // Initialize
+       this.$element
+               .addClass( 'mw-rcfilters-ui-rclTargetPageWidget' )
+               .append( this.titleSearch.$element );
 
-               this.updateUiBasedOnModel();
-       };
+       this.updateUiBasedOnModel();
+};
 
-       /* Initialization */
+/* Initialization */
 
-       OO.inheritClass( RclTargetPageWidget, OO.ui.Widget );
+OO.inheritClass( RclTargetPageWidget, OO.ui.Widget );
 
-       /* Methods */
+/* Methods */
 
-       /**
       * Respond to the user choosing a title
       */
-       RclTargetPageWidget.prototype.onLookupMenuItemChoose = function () {
-               this.titleSearch.$input.trigger( 'blur' );
-       };
+/**
+ * Respond to the user choosing a title
+ */
+RclTargetPageWidget.prototype.onLookupMenuItemChoose = function () {
+       this.titleSearch.$input.trigger( 'blur' );
+};
 
-       /**
       * Respond to titleSearch $input blur
       */
-       RclTargetPageWidget.prototype.onLookupInputBlur = function () {
-               this.controller.setTargetPage( this.titleSearch.getQueryValue() );
-       };
+/**
+ * Respond to titleSearch $input blur
+ */
+RclTargetPageWidget.prototype.onLookupInputBlur = function () {
+       this.controller.setTargetPage( this.titleSearch.getQueryValue() );
+};
 
-       /**
       * Respond to the model being updated
       */
-       RclTargetPageWidget.prototype.updateUiBasedOnModel = function () {
-               var title = mw.Title.newFromText( this.model.getValue() ),
-                       text = title ? title.toText() : this.model.getValue();
-               this.titleSearch.setValue( text );
-               this.titleSearch.setTitle( text );
-       };
+/**
+ * Respond to the model being updated
+ */
+RclTargetPageWidget.prototype.updateUiBasedOnModel = function () {
+       var title = mw.Title.newFromText( this.model.getValue() ),
+               text = title ? title.toText() : this.model.getValue();
+       this.titleSearch.setValue( text );
+       this.titleSearch.setTitle( text );
+};
 
-       module.exports = RclTargetPageWidget;
-}() );
+module.exports = RclTargetPageWidget;
index e2c58d0..46f2de9 100644 (file)
@@ -1,76 +1,74 @@
-( function () {
-       /**
-        * Widget to select to view changes that link TO or FROM the target page
-        * on Special:RecentChangesLinked (AKA Related Changes)
-        *
-        * @class mw.rcfilters.ui.RclToOrFromWidget
-        * @extends OO.ui.DropdownWidget
-        *
-        * @constructor
-        * @param {mw.rcfilters.Controller} controller
-        * @param {mw.rcfilters.dm.FilterItem} showLinkedToModel model this widget is bound to
-        * @param {Object} [config] Configuration object
-        */
-       var RclToOrFromWidget = function MwRcfiltersUiRclToOrFromWidget(
-               controller, showLinkedToModel, config
-       ) {
-               config = config || {};
+/**
+ * Widget to select to view changes that link TO or FROM the target page
+ * on Special:RecentChangesLinked (AKA Related Changes)
+ *
+ * @class mw.rcfilters.ui.RclToOrFromWidget
+ * @extends OO.ui.DropdownWidget
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller
+ * @param {mw.rcfilters.dm.FilterItem} showLinkedToModel model this widget is bound to
+ * @param {Object} [config] Configuration object
+ */
+var RclToOrFromWidget = function MwRcfiltersUiRclToOrFromWidget(
+       controller, showLinkedToModel, config
+) {
+       config = config || {};
 
-               this.showLinkedFrom = new OO.ui.MenuOptionWidget( {
-                       data: 'from', // default (showlinkedto=0)
-                       label: new OO.ui.HtmlSnippet( mw.msg( 'rcfilters-filter-showlinkedfrom-option-label' ) )
-               } );
-               this.showLinkedTo = new OO.ui.MenuOptionWidget( {
-                       data: 'to', // showlinkedto=1
-                       label: new OO.ui.HtmlSnippet( mw.msg( 'rcfilters-filter-showlinkedto-option-label' ) )
-               } );
+       this.showLinkedFrom = new OO.ui.MenuOptionWidget( {
+               data: 'from', // default (showlinkedto=0)
+               label: new OO.ui.HtmlSnippet( mw.msg( 'rcfilters-filter-showlinkedfrom-option-label' ) )
+       } );
+       this.showLinkedTo = new OO.ui.MenuOptionWidget( {
+               data: 'to', // showlinkedto=1
+               label: new OO.ui.HtmlSnippet( mw.msg( 'rcfilters-filter-showlinkedto-option-label' ) )
+       } );
 
-               // Parent
-               RclToOrFromWidget.parent.call( this, $.extend( {
-                       classes: [ 'mw-rcfilters-ui-rclToOrFromWidget' ],
-                       menu: { items: [ this.showLinkedFrom, this.showLinkedTo ] }
-               }, config ) );
+       // Parent
+       RclToOrFromWidget.parent.call( this, $.extend( {
+               classes: [ 'mw-rcfilters-ui-rclToOrFromWidget' ],
+               menu: { items: [ this.showLinkedFrom, this.showLinkedTo ] }
+       }, config ) );
 
-               this.controller = controller;
-               this.model = showLinkedToModel;
+       this.controller = controller;
+       this.model = showLinkedToModel;
 
-               this.getMenu().connect( this, { choose: 'onUserChooseItem' } );
-               this.model.connect( this, { update: 'onModelUpdate' } );
+       this.getMenu().connect( this, { choose: 'onUserChooseItem' } );
+       this.model.connect( this, { update: 'onModelUpdate' } );
 
-               // force an initial update of the component based on the state
-               this.onModelUpdate();
-       };
+       // force an initial update of the component based on the state
+       this.onModelUpdate();
+};
 
-       /* Initialization */
+/* Initialization */
 
-       OO.inheritClass( RclToOrFromWidget, OO.ui.DropdownWidget );
+OO.inheritClass( RclToOrFromWidget, OO.ui.DropdownWidget );
 
-       /* Methods */
+/* Methods */
 
-       /**
       * Respond to the user choosing an item in the menu
       *
       * @param {OO.ui.MenuOptionWidget} chosenItem
       */
-       RclToOrFromWidget.prototype.onUserChooseItem = function ( chosenItem ) {
-               this.controller.setShowLinkedTo( chosenItem.getData() === 'to' );
-       };
+/**
+ * Respond to the user choosing an item in the menu
+ *
+ * @param {OO.ui.MenuOptionWidget} chosenItem
+ */
+RclToOrFromWidget.prototype.onUserChooseItem = function ( chosenItem ) {
+       this.controller.setShowLinkedTo( chosenItem.getData() === 'to' );
+};
 
-       /**
       * Respond to model update
       */
-       RclToOrFromWidget.prototype.onModelUpdate = function () {
-               this.getMenu().selectItem(
-                       this.model.isSelected() ?
-                               this.showLinkedTo :
-                               this.showLinkedFrom
-               );
-               this.setLabel( mw.msg(
-                       this.model.isSelected() ?
-                               'rcfilters-filter-showlinkedto-label' :
-                               'rcfilters-filter-showlinkedfrom-label'
-               ) );
-       };
+/**
+ * Respond to model update
+ */
+RclToOrFromWidget.prototype.onModelUpdate = function () {
+       this.getMenu().selectItem(
+               this.model.isSelected() ?
+                       this.showLinkedTo :
+                       this.showLinkedFrom
+       );
+       this.setLabel( mw.msg(
+               this.model.isSelected() ?
+                       'rcfilters-filter-showlinkedto-label' :
+                       'rcfilters-filter-showlinkedfrom-label'
+       ) );
+};
 
-       module.exports = RclToOrFromWidget;
-}() );
+module.exports = RclToOrFromWidget;
index d968b9e..560f3d8 100644 (file)
@@ -1,73 +1,71 @@
-( function () {
-       var RclToOrFromWidget = require( './RclToOrFromWidget.js' ),
-               RclTargetPageWidget = require( './RclTargetPageWidget.js' ),
-               RclTopSectionWidget;
+var RclToOrFromWidget = require( './RclToOrFromWidget.js' ),
+       RclTargetPageWidget = require( './RclTargetPageWidget.js' ),
+       RclTopSectionWidget;
 
-       /**
       * Top section (between page title and filters) on Special:RecentChangesLinked (AKA RelatedChanges)
       *
       * @class mw.rcfilters.ui.RclTopSectionWidget
       * @extends OO.ui.Widget
       *
       * @constructor
       * @param {mw.rcfilters.ui.SavedLinksListWidget} savedLinksListWidget
       * @param {mw.rcfilters.Controller} controller
       * @param {mw.rcfilters.dm.FilterItem} showLinkedToModel Model for 'showlinkedto' parameter
       * @param {mw.rcfilters.dm.FilterItem} targetPageModel Model for 'target' parameter
       * @param {Object} [config] Configuration object
       */
-       RclTopSectionWidget = function MwRcfiltersUiRclTopSectionWidget(
-               savedLinksListWidget, controller, showLinkedToModel, targetPageModel, config
-       ) {
-               var toOrFromWidget,
-                       targetPage;
-               config = config || {};
+/**
+ * Top section (between page title and filters) on Special:RecentChangesLinked (AKA RelatedChanges)
+ *
+ * @class mw.rcfilters.ui.RclTopSectionWidget
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {mw.rcfilters.ui.SavedLinksListWidget} savedLinksListWidget
+ * @param {mw.rcfilters.Controller} controller
+ * @param {mw.rcfilters.dm.FilterItem} showLinkedToModel Model for 'showlinkedto' parameter
+ * @param {mw.rcfilters.dm.FilterItem} targetPageModel Model for 'target' parameter
+ * @param {Object} [config] Configuration object
+ */
+RclTopSectionWidget = function MwRcfiltersUiRclTopSectionWidget(
+       savedLinksListWidget, controller, showLinkedToModel, targetPageModel, config
+) {
+       var toOrFromWidget,
+               targetPage;
+       config = config || {};
 
-               // Parent
-               RclTopSectionWidget.parent.call( this, config );
+       // Parent
+       RclTopSectionWidget.parent.call( this, config );
 
-               this.controller = controller;
+       this.controller = controller;
 
-               toOrFromWidget = new RclToOrFromWidget( controller, showLinkedToModel );
-               targetPage = new RclTargetPageWidget( controller, targetPageModel );
+       toOrFromWidget = new RclToOrFromWidget( controller, showLinkedToModel );
+       targetPage = new RclTargetPageWidget( controller, targetPageModel );
 
-               // Initialize
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-rclTopSectionWidget' )
-                       .append(
-                               $( '<div>' )
-                                       .addClass( 'mw-rcfilters-ui-table' )
-                                       .append(
-                                               $( '<div>' )
-                                                       .addClass( 'mw-rcfilters-ui-row' )
-                                                       .append(
+       // Initialize
+       this.$element
+               .addClass( 'mw-rcfilters-ui-rclTopSectionWidget' )
+               .append(
+                       $( '<div>' )
+                               .addClass( 'mw-rcfilters-ui-table' )
+                               .append(
+                                       $( '<div>' )
+                                               .addClass( 'mw-rcfilters-ui-row' )
+                                               .append(
+                                                       $( '<div>' )
+                                                               .addClass( 'mw-rcfilters-ui-cell' )
+                                                               .append( toOrFromWidget.$element )
+                                               ),
+                                       $( '<div>' )
+                                               .addClass( 'mw-rcfilters-ui-row' )
+                                               .append(
+                                                       $( '<div>' )
+                                                               .addClass( 'mw-rcfilters-ui-cell' )
+                                                               .append( targetPage.$element ),
+                                                       $( '<div>' )
+                                                               .addClass( 'mw-rcfilters-ui-table-placeholder' )
+                                                               .addClass( 'mw-rcfilters-ui-cell' ),
+                                                       !mw.user.isAnon() ?
                                                                $( '<div>' )
                                                                        .addClass( 'mw-rcfilters-ui-cell' )
-                                                                       .append( toOrFromWidget.$element )
-                                                       ),
-                                               $( '<div>' )
-                                                       .addClass( 'mw-rcfilters-ui-row' )
-                                                       .append(
-                                                               $( '<div>' )
-                                                                       .addClass( 'mw-rcfilters-ui-cell' )
-                                                                       .append( targetPage.$element ),
-                                                               $( '<div>' )
-                                                                       .addClass( 'mw-rcfilters-ui-table-placeholder' )
-                                                                       .addClass( 'mw-rcfilters-ui-cell' ),
-                                                               !mw.user.isAnon() ?
-                                                                       $( '<div>' )
-                                                                               .addClass( 'mw-rcfilters-ui-cell' )
-                                                                               .addClass( 'mw-rcfilters-ui-rclTopSectionWidget-savedLinks' )
-                                                                               .append( savedLinksListWidget.$element ) :
-                                                                       null
-                                                       )
-                                       )
-                       );
-       };
+                                                                       .addClass( 'mw-rcfilters-ui-rclTopSectionWidget-savedLinks' )
+                                                                       .append( savedLinksListWidget.$element ) :
+                                                               null
+                                               )
+                               )
+               );
+};
 
-       /* Initialization */
+/* Initialization */
 
-       OO.inheritClass( RclTopSectionWidget, OO.ui.Widget );
+OO.inheritClass( RclTopSectionWidget, OO.ui.Widget );
 
-       module.exports = RclTopSectionWidget;
-}() );
+module.exports = RclTopSectionWidget;
index 8c3d550..1c66c6e 100644 (file)
-( function () {
-       /**
-        * Save filters widget. This widget is displayed in the tag area
-        * and allows the user to save the current state of the system
-        * as a new saved filter query they can later load or set as
-        * default.
-        *
-        * @class mw.rcfilters.ui.SaveFiltersPopupButtonWidget
-        * @extends OO.ui.PopupButtonWidget
-        *
-        * @constructor
-        * @param {mw.rcfilters.Controller} controller Controller
-        * @param {mw.rcfilters.dm.SavedQueriesModel} model View model
-        * @param {Object} [config] Configuration object
-        */
-       var SaveFiltersPopupButtonWidget = function MwRcfiltersUiSaveFiltersPopupButtonWidget( controller, model, config ) {
-               var layout,
-                       checkBoxLayout,
-                       $popupContent = $( '<div>' );
-
-               config = config || {};
-
-               this.controller = controller;
-               this.model = model;
-
-               // Parent
-               SaveFiltersPopupButtonWidget.parent.call( this, $.extend( {
-                       framed: false,
-                       icon: 'bookmark',
-                       title: mw.msg( 'rcfilters-savedqueries-add-new-title' ),
-                       popup: {
-                               classes: [ 'mw-rcfilters-ui-saveFiltersPopupButtonWidget-popup' ],
-                               padded: true,
-                               head: true,
-                               label: mw.msg( 'rcfilters-savedqueries-add-new-title' ),
-                               $content: $popupContent
-                       }
-               }, config ) );
-               // // HACK: Add an icon to the popup head label
-               this.popup.$head.prepend( ( new OO.ui.IconWidget( { icon: 'bookmark' } ) ).$element );
-
-               this.input = new OO.ui.TextInputWidget( {
-                       placeholder: mw.msg( 'rcfilters-savedqueries-new-name-placeholder' )
-               } );
-               layout = new OO.ui.FieldLayout( this.input, {
-                       label: mw.msg( 'rcfilters-savedqueries-new-name-label' ),
-                       align: 'top'
-               } );
-
-               this.setAsDefaultCheckbox = new OO.ui.CheckboxInputWidget();
-               checkBoxLayout = new OO.ui.FieldLayout( this.setAsDefaultCheckbox, {
-                       label: mw.msg( 'rcfilters-savedqueries-setdefault' ),
-                       align: 'inline'
-               } );
-
-               this.applyButton = new OO.ui.ButtonWidget( {
-                       label: mw.msg( 'rcfilters-savedqueries-apply-label' ),
-                       classes: [ 'mw-rcfilters-ui-saveFiltersPopupButtonWidget-popup-buttons-apply' ],
-                       flags: [ 'primary', 'progressive' ]
-               } );
-               this.cancelButton = new OO.ui.ButtonWidget( {
-                       label: mw.msg( 'rcfilters-savedqueries-cancel-label' ),
-                       classes: [ 'mw-rcfilters-ui-saveFiltersPopupButtonWidget-popup-buttons-cancel' ]
-               } );
-
-               $popupContent
-                       .append(
-                               $( '<div>' )
-                                       .addClass( 'mw-rcfilters-ui-saveFiltersPopupButtonWidget-popup-layout' )
-                                       .append( layout.$element ),
-                               $( '<div>' )
-                                       .addClass( 'mw-rcfilters-ui-saveFiltersPopupButtonWidget-popup-options' )
-                                       .append( checkBoxLayout.$element ),
-                               $( '<div>' )
-                                       .addClass( 'mw-rcfilters-ui-saveFiltersPopupButtonWidget-popup-buttons' )
-                                       .append(
-                                               this.cancelButton.$element,
-                                               this.applyButton.$element
-                                       )
-                       );
-
-               // Events
-               this.popup.connect( this, {
-                       ready: 'onPopupReady'
-               } );
-               this.input.connect( this, {
-                       change: 'onInputChange',
-                       enter: 'onInputEnter'
-               } );
-               this.input.$input.on( {
-                       keyup: this.onInputKeyup.bind( this )
-               } );
-               this.setAsDefaultCheckbox.connect( this, { change: 'onSetAsDefaultChange' } );
-               this.cancelButton.connect( this, { click: 'onCancelButtonClick' } );
-               this.applyButton.connect( this, { click: 'onApplyButtonClick' } );
-
-               // Initialize
-               this.applyButton.setDisabled( !this.input.getValue() );
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-saveFiltersPopupButtonWidget' );
-       };
-
-       /* Initialization */
-       OO.inheritClass( SaveFiltersPopupButtonWidget, OO.ui.PopupButtonWidget );
-
-       /**
-        * Respond to input enter event
-        */
-       SaveFiltersPopupButtonWidget.prototype.onInputEnter = function () {
-               this.apply();
-       };
-
-       /**
-        * Respond to input change event
-        *
-        * @param {string} value Input value
-        */
-       SaveFiltersPopupButtonWidget.prototype.onInputChange = function ( value ) {
-               value = value.trim();
-
-               this.applyButton.setDisabled( !value );
-       };
-
-       /**
-        * Respond to input keyup event, this is the way to intercept 'escape' key
-        *
-        * @param {jQuery.Event} e Event data
-        * @return {boolean} false
-        */
-       SaveFiltersPopupButtonWidget.prototype.onInputKeyup = function ( e ) {
-               if ( e.which === OO.ui.Keys.ESCAPE ) {
-                       this.popup.toggle( false );
-                       return false;
+/**
+ * Save filters widget. This widget is displayed in the tag area
+ * and allows the user to save the current state of the system
+ * as a new saved filter query they can later load or set as
+ * default.
+ *
+ * @class mw.rcfilters.ui.SaveFiltersPopupButtonWidget
+ * @extends OO.ui.PopupButtonWidget
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller Controller
+ * @param {mw.rcfilters.dm.SavedQueriesModel} model View model
+ * @param {Object} [config] Configuration object
+ */
+var SaveFiltersPopupButtonWidget = function MwRcfiltersUiSaveFiltersPopupButtonWidget( controller, model, config ) {
+       var layout,
+               checkBoxLayout,
+               $popupContent = $( '<div>' );
+
+       config = config || {};
+
+       this.controller = controller;
+       this.model = model;
+
+       // Parent
+       SaveFiltersPopupButtonWidget.parent.call( this, $.extend( {
+               framed: false,
+               icon: 'bookmark',
+               title: mw.msg( 'rcfilters-savedqueries-add-new-title' ),
+               popup: {
+                       classes: [ 'mw-rcfilters-ui-saveFiltersPopupButtonWidget-popup' ],
+                       padded: true,
+                       head: true,
+                       label: mw.msg( 'rcfilters-savedqueries-add-new-title' ),
+                       $content: $popupContent
                }
-       };
-
-       /**
-        * Respond to popup ready event
-        */
-       SaveFiltersPopupButtonWidget.prototype.onPopupReady = function () {
-               this.input.focus();
-       };
-
-       /**
-        * Respond to "set as default" checkbox change
-        * @param {boolean} checked State of the checkbox
-        */
-       SaveFiltersPopupButtonWidget.prototype.onSetAsDefaultChange = function ( checked ) {
-               var messageKey = checked ?
-                       'rcfilters-savedqueries-apply-and-setdefault-label' :
-                       'rcfilters-savedqueries-apply-label';
-
-               this.applyButton
-                       .setIcon( checked ? 'pushPin' : null )
-                       .setLabel( mw.msg( messageKey ) );
-       };
-
-       /**
-        * Respond to cancel button click event
-        */
-       SaveFiltersPopupButtonWidget.prototype.onCancelButtonClick = function () {
+       }, config ) );
+       // // HACK: Add an icon to the popup head label
+       this.popup.$head.prepend( ( new OO.ui.IconWidget( { icon: 'bookmark' } ) ).$element );
+
+       this.input = new OO.ui.TextInputWidget( {
+               placeholder: mw.msg( 'rcfilters-savedqueries-new-name-placeholder' )
+       } );
+       layout = new OO.ui.FieldLayout( this.input, {
+               label: mw.msg( 'rcfilters-savedqueries-new-name-label' ),
+               align: 'top'
+       } );
+
+       this.setAsDefaultCheckbox = new OO.ui.CheckboxInputWidget();
+       checkBoxLayout = new OO.ui.FieldLayout( this.setAsDefaultCheckbox, {
+               label: mw.msg( 'rcfilters-savedqueries-setdefault' ),
+               align: 'inline'
+       } );
+
+       this.applyButton = new OO.ui.ButtonWidget( {
+               label: mw.msg( 'rcfilters-savedqueries-apply-label' ),
+               classes: [ 'mw-rcfilters-ui-saveFiltersPopupButtonWidget-popup-buttons-apply' ],
+               flags: [ 'primary', 'progressive' ]
+       } );
+       this.cancelButton = new OO.ui.ButtonWidget( {
+               label: mw.msg( 'rcfilters-savedqueries-cancel-label' ),
+               classes: [ 'mw-rcfilters-ui-saveFiltersPopupButtonWidget-popup-buttons-cancel' ]
+       } );
+
+       $popupContent
+               .append(
+                       $( '<div>' )
+                               .addClass( 'mw-rcfilters-ui-saveFiltersPopupButtonWidget-popup-layout' )
+                               .append( layout.$element ),
+                       $( '<div>' )
+                               .addClass( 'mw-rcfilters-ui-saveFiltersPopupButtonWidget-popup-options' )
+                               .append( checkBoxLayout.$element ),
+                       $( '<div>' )
+                               .addClass( 'mw-rcfilters-ui-saveFiltersPopupButtonWidget-popup-buttons' )
+                               .append(
+                                       this.cancelButton.$element,
+                                       this.applyButton.$element
+                               )
+               );
+
+       // Events
+       this.popup.connect( this, {
+               ready: 'onPopupReady'
+       } );
+       this.input.connect( this, {
+               change: 'onInputChange',
+               enter: 'onInputEnter'
+       } );
+       this.input.$input.on( {
+               keyup: this.onInputKeyup.bind( this )
+       } );
+       this.setAsDefaultCheckbox.connect( this, { change: 'onSetAsDefaultChange' } );
+       this.cancelButton.connect( this, { click: 'onCancelButtonClick' } );
+       this.applyButton.connect( this, { click: 'onApplyButtonClick' } );
+
+       // Initialize
+       this.applyButton.setDisabled( !this.input.getValue() );
+       this.$element
+               .addClass( 'mw-rcfilters-ui-saveFiltersPopupButtonWidget' );
+};
+
+/* Initialization */
+OO.inheritClass( SaveFiltersPopupButtonWidget, OO.ui.PopupButtonWidget );
+
+/**
+ * Respond to input enter event
+ */
+SaveFiltersPopupButtonWidget.prototype.onInputEnter = function () {
+       this.apply();
+};
+
+/**
+ * Respond to input change event
+ *
+ * @param {string} value Input value
+ */
+SaveFiltersPopupButtonWidget.prototype.onInputChange = function ( value ) {
+       value = value.trim();
+
+       this.applyButton.setDisabled( !value );
+};
+
+/**
+ * Respond to input keyup event, this is the way to intercept 'escape' key
+ *
+ * @param {jQuery.Event} e Event data
+ * @return {boolean} false
+ */
+SaveFiltersPopupButtonWidget.prototype.onInputKeyup = function ( e ) {
+       if ( e.which === OO.ui.Keys.ESCAPE ) {
                this.popup.toggle( false );
-       };
-
-       /**
-        * Respond to apply button click event
-        */
-       SaveFiltersPopupButtonWidget.prototype.onApplyButtonClick = function () {
-               this.apply();
-       };
-
-       /**
-        * Apply and add the new quick link
-        */
-       SaveFiltersPopupButtonWidget.prototype.apply = function () {
-               var label = this.input.getValue().trim();
-
-               // This condition is more for sanity-check, since the
-               // apply button should be disabled if the label is empty
-               if ( label ) {
-                       this.controller.saveCurrentQuery( label, this.setAsDefaultCheckbox.isSelected() );
-                       this.input.setValue( '' );
-                       this.setAsDefaultCheckbox.setSelected( false );
-                       this.popup.toggle( false );
-
-                       this.emit( 'saveCurrent' );
-               }
-       };
+               return false;
+       }
+};
+
+/**
+ * Respond to popup ready event
+ */
+SaveFiltersPopupButtonWidget.prototype.onPopupReady = function () {
+       this.input.focus();
+};
+
+/**
+ * Respond to "set as default" checkbox change
+ * @param {boolean} checked State of the checkbox
+ */
+SaveFiltersPopupButtonWidget.prototype.onSetAsDefaultChange = function ( checked ) {
+       var messageKey = checked ?
+               'rcfilters-savedqueries-apply-and-setdefault-label' :
+               'rcfilters-savedqueries-apply-label';
+
+       this.applyButton
+               .setIcon( checked ? 'pushPin' : null )
+               .setLabel( mw.msg( messageKey ) );
+};
+
+/**
+ * Respond to cancel button click event
+ */
+SaveFiltersPopupButtonWidget.prototype.onCancelButtonClick = function () {
+       this.popup.toggle( false );
+};
+
+/**
+ * Respond to apply button click event
+ */
+SaveFiltersPopupButtonWidget.prototype.onApplyButtonClick = function () {
+       this.apply();
+};
+
+/**
+ * Apply and add the new quick link
+ */
+SaveFiltersPopupButtonWidget.prototype.apply = function () {
+       var label = this.input.getValue().trim();
+
+       // This condition is more for sanity-check, since the
+       // apply button should be disabled if the label is empty
+       if ( label ) {
+               this.controller.saveCurrentQuery( label, this.setAsDefaultCheckbox.isSelected() );
+               this.input.setValue( '' );
+               this.setAsDefaultCheckbox.setSelected( false );
+               this.popup.toggle( false );
+
+               this.emit( 'saveCurrent' );
+       }
+};
 
-       module.exports = SaveFiltersPopupButtonWidget;
-}() );
+module.exports = SaveFiltersPopupButtonWidget;
index ceb5ef8..806b9a3 100644 (file)
-( function () {
-       /**
-        * Quick links menu option widget
-        *
-        * @class mw.rcfilters.ui.SavedLinksListItemWidget
-        * @extends OO.ui.Widget
-        * @mixins OO.ui.mixin.LabelElement
-        * @mixins OO.ui.mixin.IconElement
-        * @mixins OO.ui.mixin.TitledElement
-        *
-        * @constructor
-        * @param {mw.rcfilters.dm.SavedQueryItemModel} model View model
-        * @param {Object} [config] Configuration object
-        * @cfg {jQuery} [$overlay] A jQuery object serving as overlay for popups
-        */
-       var SavedLinksListItemWidget = function MwRcfiltersUiSavedLinksListWidget( model, config ) {
-               config = config || {};
-
-               this.model = model;
-
-               // Parent
-               SavedLinksListItemWidget.parent.call( this, $.extend( {
-                       data: this.model.getID()
-               }, config ) );
-
-               // Mixin constructors
-               OO.ui.mixin.LabelElement.call( this, $.extend( {
-                       label: this.model.getLabel()
-               }, config ) );
-               OO.ui.mixin.IconElement.call( this, $.extend( {
-                       icon: ''
-               }, config ) );
-               OO.ui.mixin.TitledElement.call( this, $.extend( {
-                       title: this.model.getLabel()
-               }, config ) );
-
-               this.edit = false;
-               this.$overlay = config.$overlay || this.$element;
-
-               this.popupButton = new OO.ui.ButtonWidget( {
-                       classes: [ 'mw-rcfilters-ui-savedLinksListItemWidget-button' ],
-                       icon: 'ellipsis',
-                       framed: false
-               } );
-               this.menu = new OO.ui.MenuSelectWidget( {
-                       classes: [ 'mw-rcfilters-ui-savedLinksListItemWidget-menu' ],
-                       widget: this.popupButton,
-                       width: 200,
-                       horizontalPosition: 'end',
-                       $floatableContainer: this.popupButton.$element,
-                       items: [
-                               new OO.ui.MenuOptionWidget( {
-                                       data: 'edit',
-                                       icon: 'edit',
-                                       label: mw.msg( 'rcfilters-savedqueries-rename' )
-                               } ),
-                               new OO.ui.MenuOptionWidget( {
-                                       data: 'delete',
-                                       icon: 'trash',
-                                       label: mw.msg( 'rcfilters-savedqueries-remove' )
-                               } ),
-                               new OO.ui.MenuOptionWidget( {
-                                       data: 'default',
-                                       icon: 'pushPin',
-                                       label: mw.msg( 'rcfilters-savedqueries-setdefault' )
-                               } )
-                       ]
-               } );
-
-               this.editInput = new OO.ui.TextInputWidget( {
-                       classes: [ 'mw-rcfilters-ui-savedLinksListItemWidget-input' ]
-               } );
-               this.saveButton = new OO.ui.ButtonWidget( {
-                       icon: 'check',
-                       flags: [ 'primary', 'progressive' ]
-               } );
+/**
+ * Quick links menu option widget
+ *
+ * @class mw.rcfilters.ui.SavedLinksListItemWidget
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.mixin.LabelElement
+ * @mixins OO.ui.mixin.IconElement
+ * @mixins OO.ui.mixin.TitledElement
+ *
+ * @constructor
+ * @param {mw.rcfilters.dm.SavedQueryItemModel} model View model
+ * @param {Object} [config] Configuration object
+ * @cfg {jQuery} [$overlay] A jQuery object serving as overlay for popups
+ */
+var SavedLinksListItemWidget = function MwRcfiltersUiSavedLinksListWidget( model, config ) {
+       config = config || {};
+
+       this.model = model;
+
+       // Parent
+       SavedLinksListItemWidget.parent.call( this, $.extend( {
+               data: this.model.getID()
+       }, config ) );
+
+       // Mixin constructors
+       OO.ui.mixin.LabelElement.call( this, $.extend( {
+               label: this.model.getLabel()
+       }, config ) );
+       OO.ui.mixin.IconElement.call( this, $.extend( {
+               icon: ''
+       }, config ) );
+       OO.ui.mixin.TitledElement.call( this, $.extend( {
+               title: this.model.getLabel()
+       }, config ) );
+
+       this.edit = false;
+       this.$overlay = config.$overlay || this.$element;
+
+       this.popupButton = new OO.ui.ButtonWidget( {
+               classes: [ 'mw-rcfilters-ui-savedLinksListItemWidget-button' ],
+               icon: 'ellipsis',
+               framed: false
+       } );
+       this.menu = new OO.ui.MenuSelectWidget( {
+               classes: [ 'mw-rcfilters-ui-savedLinksListItemWidget-menu' ],
+               widget: this.popupButton,
+               width: 200,
+               horizontalPosition: 'end',
+               $floatableContainer: this.popupButton.$element,
+               items: [
+                       new OO.ui.MenuOptionWidget( {
+                               data: 'edit',
+                               icon: 'edit',
+                               label: mw.msg( 'rcfilters-savedqueries-rename' )
+                       } ),
+                       new OO.ui.MenuOptionWidget( {
+                               data: 'delete',
+                               icon: 'trash',
+                               label: mw.msg( 'rcfilters-savedqueries-remove' )
+                       } ),
+                       new OO.ui.MenuOptionWidget( {
+                               data: 'default',
+                               icon: 'pushPin',
+                               label: mw.msg( 'rcfilters-savedqueries-setdefault' )
+                       } )
+               ]
+       } );
+
+       this.editInput = new OO.ui.TextInputWidget( {
+               classes: [ 'mw-rcfilters-ui-savedLinksListItemWidget-input' ]
+       } );
+       this.saveButton = new OO.ui.ButtonWidget( {
+               icon: 'check',
+               flags: [ 'primary', 'progressive' ]
+       } );
+       this.toggleEdit( false );
+
+       // Events
+       this.model.connect( this, { update: 'onModelUpdate' } );
+       this.popupButton.connect( this, { click: 'onPopupButtonClick' } );
+       this.menu.connect( this, {
+               choose: 'onMenuChoose'
+       } );
+       this.saveButton.connect( this, { click: 'save' } );
+       this.editInput.connect( this, {
+               change: 'onInputChange',
+               enter: 'save'
+       } );
+       this.editInput.$input.on( {
+               blur: this.onInputBlur.bind( this ),
+               keyup: this.onInputKeyup.bind( this )
+       } );
+       this.$element.on( { click: this.onClick.bind( this ) } );
+       this.$label.on( { click: this.onClick.bind( this ) } );
+       this.$icon.on( { click: this.onDefaultIconClick.bind( this ) } );
+       // Prevent propagation on mousedown for the save button
+       // so the menu doesn't close
+       this.saveButton.$element.on( { mousedown: function () {
+               return false;
+       } } );
+
+       // Initialize
+       this.toggleDefault( !!this.model.isDefault() );
+       this.$overlay.append( this.menu.$element );
+       this.$element
+               .addClass( 'mw-rcfilters-ui-savedLinksListItemWidget' )
+               .addClass( 'mw-rcfilters-ui-savedLinksListItemWidget-query-' + this.model.getID() )
+               .append(
+                       $( '<div>' )
+                               .addClass( 'mw-rcfilters-ui-table' )
+                               .append(
+                                       $( '<div>' )
+                                               .addClass( 'mw-rcfilters-ui-row' )
+                                               .append(
+                                                       $( '<div>' )
+                                                               .addClass( 'mw-rcfilters-ui-cell' )
+                                                               .addClass( 'mw-rcfilters-ui-savedLinksListItemWidget-content' )
+                                                               .append(
+                                                                       this.$label
+                                                                               .addClass( 'mw-rcfilters-ui-savedLinksListItemWidget-label' ),
+                                                                       this.editInput.$element,
+                                                                       this.saveButton.$element
+                                                               ),
+                                                       $( '<div>' )
+                                                               .addClass( 'mw-rcfilters-ui-cell' )
+                                                               .addClass( 'mw-rcfilters-ui-savedLinksListItemWidget-icon' )
+                                                               .append( this.$icon ),
+                                                       this.popupButton.$element
+                                                               .addClass( 'mw-rcfilters-ui-cell' )
+                                               )
+                               )
+               );
+};
+
+/* Initialization */
+OO.inheritClass( SavedLinksListItemWidget, OO.ui.Widget );
+OO.mixinClass( SavedLinksListItemWidget, OO.ui.mixin.LabelElement );
+OO.mixinClass( SavedLinksListItemWidget, OO.ui.mixin.IconElement );
+OO.mixinClass( SavedLinksListItemWidget, OO.ui.mixin.TitledElement );
+
+/* Events */
+
+/**
+ * @event delete
+ *
+ * The delete option was selected for this item
+ */
+
+/**
+ * @event default
+ * @param {boolean} default Item is default
+ *
+ * The 'make default' option was selected for this item
+ */
+
+/**
+ * @event edit
+ * @param {string} newLabel New label for the query
+ *
+ * The label has been edited
+ */
+
+/* Methods */
+
+/**
+ * Respond to model update event
+ */
+SavedLinksListItemWidget.prototype.onModelUpdate = function () {
+       this.setLabel( this.model.getLabel() );
+       this.toggleDefault( this.model.isDefault() );
+};
+
+/**
+ * Respond to click on the element or label
+ *
+ * @fires click
+ */
+SavedLinksListItemWidget.prototype.onClick = function () {
+       if ( !this.editing ) {
+               this.emit( 'click' );
+       }
+};
+
+/**
+ * Respond to click on the 'default' icon. Open the submenu where the
+ * default state can be changed.
+ *
+ * @return {boolean} false
+ */
+SavedLinksListItemWidget.prototype.onDefaultIconClick = function () {
+       this.menu.toggle();
+       return false;
+};
+
+/**
+ * Respond to popup button click event
+ */
+SavedLinksListItemWidget.prototype.onPopupButtonClick = function () {
+       this.menu.toggle();
+};
+
+/**
+ * Respond to menu choose event
+ *
+ * @param {OO.ui.MenuOptionWidget} item Chosen item
+ * @fires delete
+ * @fires default
+ */
+SavedLinksListItemWidget.prototype.onMenuChoose = function ( item ) {
+       var action = item.getData();
+
+       if ( action === 'edit' ) {
+               this.toggleEdit( true );
+       } else if ( action === 'delete' ) {
+               this.emit( 'delete' );
+       } else if ( action === 'default' ) {
+               this.emit( 'default', !this.default );
+       }
+       // Reset selected
+       this.menu.selectItem( null );
+       // Close the menu
+       this.menu.toggle( false );
+};
+
+/**
+ * Respond to input keyup event, this is the way to intercept 'escape' key
+ *
+ * @param {jQuery.Event} e Event data
+ * @return {boolean} false
+ */
+SavedLinksListItemWidget.prototype.onInputKeyup = function ( e ) {
+       if ( e.which === OO.ui.Keys.ESCAPE ) {
+               // Return the input to the original label
+               this.editInput.setValue( this.getLabel() );
                this.toggleEdit( false );
-
-               // Events
-               this.model.connect( this, { update: 'onModelUpdate' } );
-               this.popupButton.connect( this, { click: 'onPopupButtonClick' } );
-               this.menu.connect( this, {
-                       choose: 'onMenuChoose'
-               } );
-               this.saveButton.connect( this, { click: 'save' } );
-               this.editInput.connect( this, {
-                       change: 'onInputChange',
-                       enter: 'save'
-               } );
-               this.editInput.$input.on( {
-                       blur: this.onInputBlur.bind( this ),
-                       keyup: this.onInputKeyup.bind( this )
-               } );
-               this.$element.on( { click: this.onClick.bind( this ) } );
-               this.$label.on( { click: this.onClick.bind( this ) } );
-               this.$icon.on( { click: this.onDefaultIconClick.bind( this ) } );
-               // Prevent propagation on mousedown for the save button
-               // so the menu doesn't close
-               this.saveButton.$element.on( { mousedown: function () {
-                       return false;
-               } } );
-
-               // Initialize
-               this.toggleDefault( !!this.model.isDefault() );
-               this.$overlay.append( this.menu.$element );
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-savedLinksListItemWidget' )
-                       .addClass( 'mw-rcfilters-ui-savedLinksListItemWidget-query-' + this.model.getID() )
-                       .append(
-                               $( '<div>' )
-                                       .addClass( 'mw-rcfilters-ui-table' )
-                                       .append(
-                                               $( '<div>' )
-                                                       .addClass( 'mw-rcfilters-ui-row' )
-                                                       .append(
-                                                               $( '<div>' )
-                                                                       .addClass( 'mw-rcfilters-ui-cell' )
-                                                                       .addClass( 'mw-rcfilters-ui-savedLinksListItemWidget-content' )
-                                                                       .append(
-                                                                               this.$label
-                                                                                       .addClass( 'mw-rcfilters-ui-savedLinksListItemWidget-label' ),
-                                                                               this.editInput.$element,
-                                                                               this.saveButton.$element
-                                                                       ),
-                                                               $( '<div>' )
-                                                                       .addClass( 'mw-rcfilters-ui-cell' )
-                                                                       .addClass( 'mw-rcfilters-ui-savedLinksListItemWidget-icon' )
-                                                                       .append( this.$icon ),
-                                                               this.popupButton.$element
-                                                                       .addClass( 'mw-rcfilters-ui-cell' )
-                                                       )
-                                       )
-                       );
-       };
-
-       /* Initialization */
-       OO.inheritClass( SavedLinksListItemWidget, OO.ui.Widget );
-       OO.mixinClass( SavedLinksListItemWidget, OO.ui.mixin.LabelElement );
-       OO.mixinClass( SavedLinksListItemWidget, OO.ui.mixin.IconElement );
-       OO.mixinClass( SavedLinksListItemWidget, OO.ui.mixin.TitledElement );
-
-       /* Events */
-
-       /**
-        * @event delete
-        *
-        * The delete option was selected for this item
-        */
-
-       /**
-        * @event default
-        * @param {boolean} default Item is default
-        *
-        * The 'make default' option was selected for this item
-        */
-
-       /**
-        * @event edit
-        * @param {string} newLabel New label for the query
-        *
-        * The label has been edited
-        */
-
-       /* Methods */
-
-       /**
-        * Respond to model update event
-        */
-       SavedLinksListItemWidget.prototype.onModelUpdate = function () {
-               this.setLabel( this.model.getLabel() );
-               this.toggleDefault( this.model.isDefault() );
-       };
-
-       /**
-        * Respond to click on the element or label
-        *
-        * @fires click
-        */
-       SavedLinksListItemWidget.prototype.onClick = function () {
-               if ( !this.editing ) {
-                       this.emit( 'click' );
-               }
-       };
-
-       /**
-        * Respond to click on the 'default' icon. Open the submenu where the
-        * default state can be changed.
-        *
-        * @return {boolean} false
-        */
-       SavedLinksListItemWidget.prototype.onDefaultIconClick = function () {
-               this.menu.toggle();
                return false;
-       };
-
-       /**
-        * Respond to popup button click event
-        */
-       SavedLinksListItemWidget.prototype.onPopupButtonClick = function () {
-               this.menu.toggle();
-       };
-
-       /**
-        * Respond to menu choose event
-        *
-        * @param {OO.ui.MenuOptionWidget} item Chosen item
-        * @fires delete
-        * @fires default
-        */
-       SavedLinksListItemWidget.prototype.onMenuChoose = function ( item ) {
-               var action = item.getData();
-
-               if ( action === 'edit' ) {
-                       this.toggleEdit( true );
-               } else if ( action === 'delete' ) {
-                       this.emit( 'delete' );
-               } else if ( action === 'default' ) {
-                       this.emit( 'default', !this.default );
-               }
-               // Reset selected
-               this.menu.selectItem( null );
-               // Close the menu
-               this.menu.toggle( false );
-       };
-
-       /**
-        * Respond to input keyup event, this is the way to intercept 'escape' key
-        *
-        * @param {jQuery.Event} e Event data
-        * @return {boolean} false
-        */
-       SavedLinksListItemWidget.prototype.onInputKeyup = function ( e ) {
-               if ( e.which === OO.ui.Keys.ESCAPE ) {
-                       // Return the input to the original label
-                       this.editInput.setValue( this.getLabel() );
-                       this.toggleEdit( false );
-                       return false;
-               }
-       };
-
-       /**
-        * Respond to blur event on the input
-        */
-       SavedLinksListItemWidget.prototype.onInputBlur = function () {
-               this.save();
-
-               // Whether the save succeeded or not, the input-blur event
-               // means we need to cancel editing mode
+       }
+};
+
+/**
+ * Respond to blur event on the input
+ */
+SavedLinksListItemWidget.prototype.onInputBlur = function () {
+       this.save();
+
+       // Whether the save succeeded or not, the input-blur event
+       // means we need to cancel editing mode
+       this.toggleEdit( false );
+};
+
+/**
+ * Respond to input change event
+ *
+ * @param {string} value Input value
+ */
+SavedLinksListItemWidget.prototype.onInputChange = function ( value ) {
+       value = value.trim();
+
+       this.saveButton.setDisabled( !value );
+};
+
+/**
+ * Save the name of the query
+ *
+ * @fires edit
+ */
+SavedLinksListItemWidget.prototype.save = function () {
+       var value = this.editInput.getValue().trim();
+
+       if ( value ) {
+               this.emit( 'edit', value );
                this.toggleEdit( false );
-       };
-
-       /**
-        * Respond to input change event
-        *
-        * @param {string} value Input value
-        */
-       SavedLinksListItemWidget.prototype.onInputChange = function ( value ) {
-               value = value.trim();
-
-               this.saveButton.setDisabled( !value );
-       };
-
-       /**
-        * Save the name of the query
-        *
-        * @param {string} [value] The value to save
-        * @fires edit
-        */
-       SavedLinksListItemWidget.prototype.save = function () {
-               var value = this.editInput.getValue().trim();
-
-               if ( value ) {
-                       this.emit( 'edit', value );
-                       this.toggleEdit( false );
-               }
-       };
-
-       /**
-        * Toggle edit mode on this widget
-        *
-        * @param {boolean} isEdit Widget is in edit mode
-        */
-       SavedLinksListItemWidget.prototype.toggleEdit = function ( isEdit ) {
-               isEdit = isEdit === undefined ? !this.editing : isEdit;
-
-               if ( this.editing !== isEdit ) {
-                       this.$element.toggleClass( 'mw-rcfilters-ui-savedLinksListItemWidget-edit', isEdit );
-                       this.editInput.setValue( this.getLabel() );
-
-                       this.editInput.toggle( isEdit );
-                       this.$label.toggleClass( 'oo-ui-element-hidden', isEdit );
-                       this.$icon.toggleClass( 'oo-ui-element-hidden', isEdit );
-                       this.popupButton.toggle( !isEdit );
-                       this.saveButton.toggle( isEdit );
-
-                       if ( isEdit ) {
-                               this.editInput.$input.trigger( 'focus' );
-                       }
-                       this.editing = isEdit;
-               }
-       };
-
-       /**
-        * Toggle default this widget
-        *
-        * @param {boolean} isDefault This item is default
-        */
-       SavedLinksListItemWidget.prototype.toggleDefault = function ( isDefault ) {
-               isDefault = isDefault === undefined ? !this.default : isDefault;
-
-               if ( this.default !== isDefault ) {
-                       this.default = isDefault;
-                       this.setIcon( this.default ? 'pushPin' : '' );
-                       this.menu.findItemFromData( 'default' ).setLabel(
-                               this.default ?
-                                       mw.msg( 'rcfilters-savedqueries-unsetdefault' ) :
-                                       mw.msg( 'rcfilters-savedqueries-setdefault' )
-                       );
+       }
+};
+
+/**
+ * Toggle edit mode on this widget
+ *
+ * @param {boolean} isEdit Widget is in edit mode
+ */
+SavedLinksListItemWidget.prototype.toggleEdit = function ( isEdit ) {
+       isEdit = isEdit === undefined ? !this.editing : isEdit;
+
+       if ( this.editing !== isEdit ) {
+               this.$element.toggleClass( 'mw-rcfilters-ui-savedLinksListItemWidget-edit', isEdit );
+               this.editInput.setValue( this.getLabel() );
+
+               this.editInput.toggle( isEdit );
+               this.$label.toggleClass( 'oo-ui-element-hidden', isEdit );
+               this.$icon.toggleClass( 'oo-ui-element-hidden', isEdit );
+               this.popupButton.toggle( !isEdit );
+               this.saveButton.toggle( isEdit );
+
+               if ( isEdit ) {
+                       this.editInput.$input.trigger( 'focus' );
                }
-       };
-
-       /**
-        * Get item ID
-        *
-        * @return {string} Query identifier
-        */
-       SavedLinksListItemWidget.prototype.getID = function () {
-               return this.model.getID();
-       };
-
-       module.exports = SavedLinksListItemWidget;
-
-}() );
+               this.editing = isEdit;
+       }
+};
+
+/**
+ * Toggle default this widget
+ *
+ * @param {boolean} isDefault This item is default
+ */
+SavedLinksListItemWidget.prototype.toggleDefault = function ( isDefault ) {
+       isDefault = isDefault === undefined ? !this.default : isDefault;
+
+       if ( this.default !== isDefault ) {
+               this.default = isDefault;
+               this.setIcon( this.default ? 'pushPin' : '' );
+               this.menu.findItemFromData( 'default' ).setLabel(
+                       this.default ?
+                               mw.msg( 'rcfilters-savedqueries-unsetdefault' ) :
+                               mw.msg( 'rcfilters-savedqueries-setdefault' )
+               );
+       }
+};
+
+/**
+ * Get item ID
+ *
+ * @return {string} Query identifier
+ */
+SavedLinksListItemWidget.prototype.getID = function () {
+       return this.model.getID();
+};
+
+module.exports = SavedLinksListItemWidget;
index 5422daf..a29a93f 100644 (file)
-( function () {
-       var GroupWidget = require( './GroupWidget.js' ),
-               SavedLinksListItemWidget = require( './SavedLinksListItemWidget.js' ),
-               SavedLinksListWidget;
-
-       /**
-        * Quick links widget
-        *
-        * @class mw.rcfilters.ui.SavedLinksListWidget
-        * @extends OO.ui.Widget
-        *
-        * @constructor
-        * @param {mw.rcfilters.Controller} controller Controller
-        * @param {mw.rcfilters.dm.SavedQueriesModel} model View model
-        * @param {Object} [config] Configuration object
-        * @cfg {jQuery} [$overlay] A jQuery object serving as overlay for popups
-        */
-       SavedLinksListWidget = function MwRcfiltersUiSavedLinksListWidget( controller, model, config ) {
-               var $labelNoEntries = $( '<div>' )
-                       .append(
-                               $( '<div>' )
-                                       .addClass( 'mw-rcfilters-ui-savedLinksListWidget-placeholder-title' )
-                                       .text( mw.msg( 'rcfilters-quickfilters-placeholder-title' ) ),
-                               $( '<div>' )
-                                       .addClass( 'mw-rcfilters-ui-savedLinksListWidget-placeholder-description' )
-                                       .text( mw.msg( 'rcfilters-quickfilters-placeholder-description' ) )
-                       );
-
-               config = config || {};
-
-               // Parent
-               SavedLinksListWidget.parent.call( this, config );
-
-               this.controller = controller;
-               this.model = model;
-               this.$overlay = config.$overlay || this.$element;
-
-               this.placeholderItem = new OO.ui.DecoratedOptionWidget( {
-                       classes: [ 'mw-rcfilters-ui-savedLinksListWidget-placeholder' ],
-                       label: $labelNoEntries,
-                       icon: 'bookmark'
-               } );
-
-               this.menu = new GroupWidget( {
-                       events: {
-                               click: 'menuItemClick',
-                               delete: 'menuItemDelete',
-                               default: 'menuItemDefault',
-                               edit: 'menuItemEdit'
-                       },
-                       classes: [ 'mw-rcfilters-ui-savedLinksListWidget-menu' ],
-                       items: [ this.placeholderItem ]
-               } );
-               this.button = new OO.ui.PopupButtonWidget( {
-                       classes: [ 'mw-rcfilters-ui-savedLinksListWidget-button' ],
-                       label: mw.msg( 'rcfilters-quickfilters' ),
-                       icon: 'bookmark',
-                       indicator: 'down',
-                       $overlay: this.$overlay,
-                       popup: {
-                               width: 300,
-                               anchor: false,
-                               align: 'backwards',
-                               $autoCloseIgnore: this.$overlay,
-                               $content: this.menu.$element
-                       }
-               } );
-
-               // Events
-               this.model.connect( this, {
-                       add: 'onModelAddItem',
-                       remove: 'onModelRemoveItem'
-               } );
-               this.menu.connect( this, {
-                       menuItemClick: 'onMenuItemClick',
-                       menuItemDelete: 'onMenuItemRemove',
-                       menuItemDefault: 'onMenuItemDefault',
-                       menuItemEdit: 'onMenuItemEdit'
-               } );
-
-               this.placeholderItem.toggle( this.model.isEmpty() );
-               // Initialize
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-savedLinksListWidget' )
-                       .append( this.button.$element );
-       };
-
-       /* Initialization */
-       OO.inheritClass( SavedLinksListWidget, OO.ui.Widget );
-
-       /* Methods */
-
-       /**
-        * Respond to menu item click event
-        *
-        * @param {mw.rcfilters.ui.SavedLinksListItemWidget} item Menu item
-        */
-       SavedLinksListWidget.prototype.onMenuItemClick = function ( item ) {
-               this.controller.applySavedQuery( item.getID() );
-               this.button.popup.toggle( false );
-       };
-
-       /**
-        * Respond to menu item remove event
-        *
-        * @param {mw.rcfilters.ui.SavedLinksListItemWidget} item Menu item
-        */
-       SavedLinksListWidget.prototype.onMenuItemRemove = function ( item ) {
-               this.controller.removeSavedQuery( item.getID() );
-       };
-
-       /**
-        * Respond to menu item default event
-        *
-        * @param {mw.rcfilters.ui.SavedLinksListItemWidget} item Menu item
-        * @param {boolean} isDefault Item is default
-        */
-       SavedLinksListWidget.prototype.onMenuItemDefault = function ( item, isDefault ) {
-               this.controller.setDefaultSavedQuery( isDefault ? item.getID() : null );
-       };
-
-       /**
-        * Respond to menu item edit event
-        *
-        * @param {mw.rcfilters.ui.SavedLinksListItemWidget} item Menu item
-        * @param {string} newLabel New label
-        */
-       SavedLinksListWidget.prototype.onMenuItemEdit = function ( item, newLabel ) {
-               this.controller.renameSavedQuery( item.getID(), newLabel );
-       };
-
-       /**
-        * Respond to menu add item event
-        *
-        * @param {mw.rcfilters.ui.SavedLinksListItemWidget} item Menu item
-        */
-       SavedLinksListWidget.prototype.onModelAddItem = function ( item ) {
-               if ( this.menu.findItemFromData( item.getID() ) ) {
-                       return;
+var GroupWidget = require( './GroupWidget.js' ),
+       SavedLinksListItemWidget = require( './SavedLinksListItemWidget.js' ),
+       SavedLinksListWidget;
+
+/**
+ * Quick links widget
+ *
+ * @class mw.rcfilters.ui.SavedLinksListWidget
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller Controller
+ * @param {mw.rcfilters.dm.SavedQueriesModel} model View model
+ * @param {Object} [config] Configuration object
+ * @cfg {jQuery} [$overlay] A jQuery object serving as overlay for popups
+ */
+SavedLinksListWidget = function MwRcfiltersUiSavedLinksListWidget( controller, model, config ) {
+       var $labelNoEntries = $( '<div>' )
+               .append(
+                       $( '<div>' )
+                               .addClass( 'mw-rcfilters-ui-savedLinksListWidget-placeholder-title' )
+                               .text( mw.msg( 'rcfilters-quickfilters-placeholder-title' ) ),
+                       $( '<div>' )
+                               .addClass( 'mw-rcfilters-ui-savedLinksListWidget-placeholder-description' )
+                               .text( mw.msg( 'rcfilters-quickfilters-placeholder-description' ) )
+               );
+
+       config = config || {};
+
+       // Parent
+       SavedLinksListWidget.parent.call( this, config );
+
+       this.controller = controller;
+       this.model = model;
+       this.$overlay = config.$overlay || this.$element;
+
+       this.placeholderItem = new OO.ui.DecoratedOptionWidget( {
+               classes: [ 'mw-rcfilters-ui-savedLinksListWidget-placeholder' ],
+               label: $labelNoEntries,
+               icon: 'bookmark'
+       } );
+
+       this.menu = new GroupWidget( {
+               events: {
+                       click: 'menuItemClick',
+                       delete: 'menuItemDelete',
+                       default: 'menuItemDefault',
+                       edit: 'menuItemEdit'
+               },
+               classes: [ 'mw-rcfilters-ui-savedLinksListWidget-menu' ],
+               items: [ this.placeholderItem ]
+       } );
+       this.button = new OO.ui.PopupButtonWidget( {
+               classes: [ 'mw-rcfilters-ui-savedLinksListWidget-button' ],
+               label: mw.msg( 'rcfilters-quickfilters' ),
+               icon: 'bookmark',
+               indicator: 'down',
+               $overlay: this.$overlay,
+               popup: {
+                       width: 300,
+                       anchor: false,
+                       align: 'backwards',
+                       $autoCloseIgnore: this.$overlay,
+                       $content: this.menu.$element
                }
-
-               this.menu.addItems( [
-                       new SavedLinksListItemWidget( item, { $overlay: this.$overlay } )
-               ] );
-               this.placeholderItem.toggle( this.model.isEmpty() );
-       };
-
-       /**
-        * Respond to menu remove item event
-        *
-        * @param {mw.rcfilters.ui.SavedLinksListItemWidget} item Menu item
-        */
-       SavedLinksListWidget.prototype.onModelRemoveItem = function ( item ) {
-               this.menu.removeItems( [ this.menu.findItemFromData( item.getID() ) ] );
-               this.placeholderItem.toggle( this.model.isEmpty() );
-       };
-
-       module.exports = SavedLinksListWidget;
-}() );
+       } );
+
+       // Events
+       this.model.connect( this, {
+               add: 'onModelAddItem',
+               remove: 'onModelRemoveItem'
+       } );
+       this.menu.connect( this, {
+               menuItemClick: 'onMenuItemClick',
+               menuItemDelete: 'onMenuItemRemove',
+               menuItemDefault: 'onMenuItemDefault',
+               menuItemEdit: 'onMenuItemEdit'
+       } );
+
+       this.placeholderItem.toggle( this.model.isEmpty() );
+       // Initialize
+       this.$element
+               .addClass( 'mw-rcfilters-ui-savedLinksListWidget' )
+               .append( this.button.$element );
+};
+
+/* Initialization */
+OO.inheritClass( SavedLinksListWidget, OO.ui.Widget );
+
+/* Methods */
+
+/**
+ * Respond to menu item click event
+ *
+ * @param {mw.rcfilters.ui.SavedLinksListItemWidget} item Menu item
+ */
+SavedLinksListWidget.prototype.onMenuItemClick = function ( item ) {
+       this.controller.applySavedQuery( item.getID() );
+       this.button.popup.toggle( false );
+};
+
+/**
+ * Respond to menu item remove event
+ *
+ * @param {mw.rcfilters.ui.SavedLinksListItemWidget} item Menu item
+ */
+SavedLinksListWidget.prototype.onMenuItemRemove = function ( item ) {
+       this.controller.removeSavedQuery( item.getID() );
+};
+
+/**
+ * Respond to menu item default event
+ *
+ * @param {mw.rcfilters.ui.SavedLinksListItemWidget} item Menu item
+ * @param {boolean} isDefault Item is default
+ */
+SavedLinksListWidget.prototype.onMenuItemDefault = function ( item, isDefault ) {
+       this.controller.setDefaultSavedQuery( isDefault ? item.getID() : null );
+};
+
+/**
+ * Respond to menu item edit event
+ *
+ * @param {mw.rcfilters.ui.SavedLinksListItemWidget} item Menu item
+ * @param {string} newLabel New label
+ */
+SavedLinksListWidget.prototype.onMenuItemEdit = function ( item, newLabel ) {
+       this.controller.renameSavedQuery( item.getID(), newLabel );
+};
+
+/**
+ * Respond to menu add item event
+ *
+ * @param {mw.rcfilters.ui.SavedLinksListItemWidget} item Menu item
+ */
+SavedLinksListWidget.prototype.onModelAddItem = function ( item ) {
+       if ( this.menu.findItemFromData( item.getID() ) ) {
+               return;
+       }
+
+       this.menu.addItems( [
+               new SavedLinksListItemWidget( item, { $overlay: this.$overlay } )
+       ] );
+       this.placeholderItem.toggle( this.model.isEmpty() );
+};
+
+/**
+ * Respond to menu remove item event
+ *
+ * @param {mw.rcfilters.ui.SavedLinksListItemWidget} item Menu item
+ */
+SavedLinksListWidget.prototype.onModelRemoveItem = function ( item ) {
+       this.menu.removeItems( [ this.menu.findItemFromData( item.getID() ) ] );
+       this.placeholderItem.toggle( this.model.isEmpty() );
+};
+
+module.exports = SavedLinksListWidget;
index d66c5b5..985e2c5 100644 (file)
-( function () {
-       /**
-        * Extend OOUI's TagItemWidget to also display a popup on hover.
-        *
-        * @class mw.rcfilters.ui.TagItemWidget
-        * @extends OO.ui.TagItemWidget
-        * @mixins OO.ui.mixin.PopupElement
-        *
-        * @constructor
-        * @param {mw.rcfilters.Controller} controller
-        * @param {mw.rcfilters.dm.FiltersViewModel} filtersViewModel
-        * @param {mw.rcfilters.dm.FilterItem} invertModel
-        * @param {mw.rcfilters.dm.FilterItem} itemModel Item model
-        * @param {Object} config Configuration object
-        * @cfg {jQuery} [$overlay] A jQuery object serving as overlay for popups
-        */
-       var TagItemWidget = function MwRcfiltersUiTagItemWidget(
-               controller, filtersViewModel, invertModel, itemModel, config
-       ) {
-               // Configuration initialization
-               config = config || {};
-
-               this.controller = controller;
-               this.invertModel = invertModel;
-               this.filtersViewModel = filtersViewModel;
-               this.itemModel = itemModel;
-               this.selected = false;
-
-               TagItemWidget.parent.call( this, $.extend( {
-                       data: this.itemModel.getName()
-               }, config ) );
-
-               this.$overlay = config.$overlay || this.$element;
-               this.popupLabel = new OO.ui.LabelWidget();
-
-               // Mixin constructors
-               OO.ui.mixin.PopupElement.call( this, $.extend( {
-                       popup: {
-                               padded: false,
-                               align: 'center',
-                               position: 'above',
-                               $content: $( '<div>' )
-                                       .addClass( 'mw-rcfilters-ui-tagItemWidget-popup-content' )
-                                       .append( this.popupLabel.$element ),
-                               $floatableContainer: this.$element,
-                               classes: [ 'mw-rcfilters-ui-tagItemWidget-popup' ]
-                       }
-               }, config ) );
-
-               this.popupTimeoutShow = null;
-               this.popupTimeoutHide = null;
-
-               this.$highlight = $( '<div>' )
-                       .addClass( 'mw-rcfilters-ui-tagItemWidget-highlight' );
-
-               // Add title attribute with the item label to 'x' button
-               this.closeButton.setTitle( mw.msg( 'rcfilters-tag-remove', this.itemModel.getLabel() ) );
-
-               // Events
-               this.filtersViewModel.connect( this, { highlightChange: 'updateUiBasedOnState' } );
-               this.invertModel.connect( this, { update: 'updateUiBasedOnState' } );
-               this.itemModel.connect( this, { update: 'updateUiBasedOnState' } );
-
-               // Initialization
-               this.$overlay.append( this.popup.$element );
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-tagItemWidget' )
-                       .prepend( this.$highlight )
-                       .attr( 'aria-haspopup', 'true' )
-                       .on( 'mouseenter', this.onMouseEnter.bind( this ) )
-                       .on( 'mouseleave', this.onMouseLeave.bind( this ) );
-
-               this.updateUiBasedOnState();
-       };
-
-       /* Initialization */
-
-       OO.inheritClass( TagItemWidget, OO.ui.TagItemWidget );
-       OO.mixinClass( TagItemWidget, OO.ui.mixin.PopupElement );
-
-       /* Methods */
-
-       /**
-        * Respond to model update event
-        */
-       TagItemWidget.prototype.updateUiBasedOnState = function () {
-               // Update label if needed
-               var labelMsg = this.itemModel.getLabelMessageKey( this.invertModel.isSelected() );
-               if ( labelMsg ) {
-                       this.setLabel( $( '<div>' ).append(
-                               $( '<bdi>' ).html(
-                                       mw.message( labelMsg, mw.html.escape( this.itemModel.getLabel() ) ).parse()
-                               )
-                       ).contents() );
-               } else {
-                       this.setLabel(
-                               $( '<bdi>' ).append(
-                                       this.itemModel.getLabel()
-                               )
-                       );
-               }
-
-               this.setCurrentMuteState();
-               this.setHighlightColor();
-       };
-
-       /**
-        * Set the current highlight color for this item
-        */
-       TagItemWidget.prototype.setHighlightColor = function () {
-               var selectedColor = this.filtersViewModel.isHighlightEnabled() && this.itemModel.isHighlighted ?
-                       this.itemModel.getHighlightColor() :
-                       null;
-
-               this.$highlight
-                       .attr( 'data-color', selectedColor )
-                       .toggleClass(
-                               'mw-rcfilters-ui-tagItemWidget-highlight-highlighted',
-                               !!selectedColor
-                       );
-       };
-
-       /**
-        * Set the current mute state for this item
-        */
-       TagItemWidget.prototype.setCurrentMuteState = function () {};
-
-       /**
-        * Respond to mouse enter event
-        */
-       TagItemWidget.prototype.onMouseEnter = function () {
-               var labelText = this.itemModel.getStateMessage();
-
-               if ( labelText ) {
-                       this.popupLabel.setLabel( labelText );
-
-                       // Set timeout for the popup to show
-                       this.popupTimeoutShow = setTimeout( function () {
-                               this.popup.toggle( true );
-                       }.bind( this ), 500 );
-
-                       // Cancel the hide timeout
-                       clearTimeout( this.popupTimeoutHide );
-                       this.popupTimeoutHide = null;
-               }
-       };
-
-       /**
-        * Respond to mouse leave event
-        */
-       TagItemWidget.prototype.onMouseLeave = function () {
-               this.popupTimeoutHide = setTimeout( function () {
-                       this.popup.toggle( false );
-               }.bind( this ), 250 );
-
-               // Clear the show timeout
-               clearTimeout( this.popupTimeoutShow );
-               this.popupTimeoutShow = null;
-       };
-
-       /**
-        * Set selected state on this widget
-        *
-        * @param {boolean} [isSelected] Widget is selected
-        */
-       TagItemWidget.prototype.toggleSelected = function ( isSelected ) {
-               isSelected = isSelected !== undefined ? isSelected : !this.selected;
-
-               if ( this.selected !== isSelected ) {
-                       this.selected = isSelected;
-
-                       this.$element.toggleClass( 'mw-rcfilters-ui-tagItemWidget-selected', this.selected );
+/**
+ * Extend OOUI's TagItemWidget to also display a popup on hover.
+ *
+ * @class mw.rcfilters.ui.TagItemWidget
+ * @extends OO.ui.TagItemWidget
+ * @mixins OO.ui.mixin.PopupElement
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller
+ * @param {mw.rcfilters.dm.FiltersViewModel} filtersViewModel
+ * @param {mw.rcfilters.dm.FilterItem} invertModel
+ * @param {mw.rcfilters.dm.FilterItem} itemModel Item model
+ * @param {Object} config Configuration object
+ * @cfg {jQuery} [$overlay] A jQuery object serving as overlay for popups
+ */
+var TagItemWidget = function MwRcfiltersUiTagItemWidget(
+       controller, filtersViewModel, invertModel, itemModel, config
+) {
+       // Configuration initialization
+       config = config || {};
+
+       this.controller = controller;
+       this.invertModel = invertModel;
+       this.filtersViewModel = filtersViewModel;
+       this.itemModel = itemModel;
+       this.selected = false;
+
+       TagItemWidget.parent.call( this, $.extend( {
+               data: this.itemModel.getName()
+       }, config ) );
+
+       this.$overlay = config.$overlay || this.$element;
+       this.popupLabel = new OO.ui.LabelWidget();
+
+       // Mixin constructors
+       OO.ui.mixin.PopupElement.call( this, $.extend( {
+               popup: {
+                       padded: false,
+                       align: 'center',
+                       position: 'above',
+                       $content: $( '<div>' )
+                               .addClass( 'mw-rcfilters-ui-tagItemWidget-popup-content' )
+                               .append( this.popupLabel.$element ),
+                       $floatableContainer: this.$element,
+                       classes: [ 'mw-rcfilters-ui-tagItemWidget-popup' ]
                }
-       };
-
-       /**
-        * Get the selected state of this widget
-        *
-        * @return {boolean} Tag is selected
-        */
-       TagItemWidget.prototype.isSelected = function () {
-               return this.selected;
-       };
-
-       /**
-        * Get item name
-        *
-        * @return {string} Filter name
-        */
-       TagItemWidget.prototype.getName = function () {
-               return this.itemModel.getName();
-       };
-
-       /**
-        * Get item model
-        *
-        * @return {string} Filter model
-        */
-       TagItemWidget.prototype.getModel = function () {
-               return this.itemModel;
-       };
-
-       /**
-        * Get item view
-        *
-        * @return {string} Filter view
-        */
-       TagItemWidget.prototype.getView = function () {
-               return this.itemModel.getGroupModel().getView();
-       };
-
-       /**
-        * Remove and destroy external elements of this widget
-        */
-       TagItemWidget.prototype.destroy = function () {
-               // Destroy the popup
-               this.popup.$element.detach();
-
-               // Disconnect events
-               this.itemModel.disconnect( this );
-               this.closeButton.disconnect( this );
-       };
-
-       module.exports = TagItemWidget;
-}() );
+       }, config ) );
+
+       this.popupTimeoutShow = null;
+       this.popupTimeoutHide = null;
+
+       this.$highlight = $( '<div>' )
+               .addClass( 'mw-rcfilters-ui-tagItemWidget-highlight' );
+
+       // Add title attribute with the item label to 'x' button
+       this.closeButton.setTitle( mw.msg( 'rcfilters-tag-remove', this.itemModel.getLabel() ) );
+
+       // Events
+       this.filtersViewModel.connect( this, { highlightChange: 'updateUiBasedOnState' } );
+       this.invertModel.connect( this, { update: 'updateUiBasedOnState' } );
+       this.itemModel.connect( this, { update: 'updateUiBasedOnState' } );
+
+       // Initialization
+       this.$overlay.append( this.popup.$element );
+       this.$element
+               .addClass( 'mw-rcfilters-ui-tagItemWidget' )
+               .prepend( this.$highlight )
+               .attr( 'aria-haspopup', 'true' )
+               .on( 'mouseenter', this.onMouseEnter.bind( this ) )
+               .on( 'mouseleave', this.onMouseLeave.bind( this ) );
+
+       this.updateUiBasedOnState();
+};
+
+/* Initialization */
+
+OO.inheritClass( TagItemWidget, OO.ui.TagItemWidget );
+OO.mixinClass( TagItemWidget, OO.ui.mixin.PopupElement );
+
+/* Methods */
+
+/**
+ * Respond to model update event
+ */
+TagItemWidget.prototype.updateUiBasedOnState = function () {
+       // Update label if needed
+       var labelMsg = this.itemModel.getLabelMessageKey( this.invertModel.isSelected() );
+       if ( labelMsg ) {
+               this.setLabel( $( '<div>' ).append(
+                       $( '<bdi>' ).html(
+                               mw.message( labelMsg, mw.html.escape( this.itemModel.getLabel() ) ).parse()
+                       )
+               ).contents() );
+       } else {
+               this.setLabel(
+                       $( '<bdi>' ).append(
+                               this.itemModel.getLabel()
+                       )
+               );
+       }
+
+       this.setCurrentMuteState();
+       this.setHighlightColor();
+};
+
+/**
+ * Set the current highlight color for this item
+ */
+TagItemWidget.prototype.setHighlightColor = function () {
+       var selectedColor = this.filtersViewModel.isHighlightEnabled() && this.itemModel.isHighlighted ?
+               this.itemModel.getHighlightColor() :
+               null;
+
+       this.$highlight
+               .attr( 'data-color', selectedColor )
+               .toggleClass(
+                       'mw-rcfilters-ui-tagItemWidget-highlight-highlighted',
+                       !!selectedColor
+               );
+};
+
+/**
+ * Set the current mute state for this item
+ */
+TagItemWidget.prototype.setCurrentMuteState = function () {};
+
+/**
+ * Respond to mouse enter event
+ */
+TagItemWidget.prototype.onMouseEnter = function () {
+       var labelText = this.itemModel.getStateMessage();
+
+       if ( labelText ) {
+               this.popupLabel.setLabel( labelText );
+
+               // Set timeout for the popup to show
+               this.popupTimeoutShow = setTimeout( function () {
+                       this.popup.toggle( true );
+               }.bind( this ), 500 );
+
+               // Cancel the hide timeout
+               clearTimeout( this.popupTimeoutHide );
+               this.popupTimeoutHide = null;
+       }
+};
+
+/**
+ * Respond to mouse leave event
+ */
+TagItemWidget.prototype.onMouseLeave = function () {
+       this.popupTimeoutHide = setTimeout( function () {
+               this.popup.toggle( false );
+       }.bind( this ), 250 );
+
+       // Clear the show timeout
+       clearTimeout( this.popupTimeoutShow );
+       this.popupTimeoutShow = null;
+};
+
+/**
+ * Set selected state on this widget
+ *
+ * @param {boolean} [isSelected] Widget is selected
+ */
+TagItemWidget.prototype.toggleSelected = function ( isSelected ) {
+       isSelected = isSelected !== undefined ? isSelected : !this.selected;
+
+       if ( this.selected !== isSelected ) {
+               this.selected = isSelected;
+
+               this.$element.toggleClass( 'mw-rcfilters-ui-tagItemWidget-selected', this.selected );
+       }
+};
+
+/**
+ * Get the selected state of this widget
+ *
+ * @return {boolean} Tag is selected
+ */
+TagItemWidget.prototype.isSelected = function () {
+       return this.selected;
+};
+
+/**
+ * Get item name
+ *
+ * @return {string} Filter name
+ */
+TagItemWidget.prototype.getName = function () {
+       return this.itemModel.getName();
+};
+
+/**
+ * Get item model
+ *
+ * @return {string} Filter model
+ */
+TagItemWidget.prototype.getModel = function () {
+       return this.itemModel;
+};
+
+/**
+ * Get item view
+ *
+ * @return {string} Filter view
+ */
+TagItemWidget.prototype.getView = function () {
+       return this.itemModel.getGroupModel().getView();
+};
+
+/**
+ * Remove and destroy external elements of this widget
+ */
+TagItemWidget.prototype.destroy = function () {
+       // Destroy the popup
+       this.popup.$element.detach();
+
+       // Disconnect events
+       this.itemModel.disconnect( this );
+       this.closeButton.disconnect( this );
+};
+
+module.exports = TagItemWidget;
index ebd81c8..3ce63ee 100644 (file)
-( function () {
-       /**
-        * Widget defining the behavior used to choose from a set of values
-        * in a single_value group
-        *
-        * @class mw.rcfilters.ui.ValuePickerWidget
-        * @extends OO.ui.Widget
-        * @mixins OO.ui.mixin.LabelElement
-        *
-        * @constructor
-        * @param {mw.rcfilters.dm.FilterGroup} model Group model
-        * @param {Object} [config] Configuration object
-        * @cfg {Function} [itemFilter] A filter function for the items from the
-        *  model. If not given, all items will be included. The function must
-        *  handle item models and return a boolean whether the item is included
-        *  or not. Example: function ( itemModel ) { return itemModel.isSelected(); }
-        */
-       var ValuePickerWidget = function MwRcfiltersUiValuePickerWidget( model, config ) {
-               config = config || {};
-
-               // Parent
-               ValuePickerWidget.parent.call( this, config );
-               // Mixin constructors
-               OO.ui.mixin.LabelElement.call( this, config );
-
-               this.model = model;
-               this.itemFilter = config.itemFilter || function () {
-                       return true;
-               };
-
-               // Build the selection from the item models
-               this.selectWidget = new OO.ui.ButtonSelectWidget();
-               this.initializeSelectWidget();
-
-               // Events
-               this.model.connect( this, { update: 'onModelUpdate' } );
-               this.selectWidget.connect( this, { choose: 'onSelectWidgetChoose' } );
-
-               // Initialize
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-valuePickerWidget' )
-                       .append(
-                               this.$label
-                                       .addClass( 'mw-rcfilters-ui-valuePickerWidget-title' ),
-                               this.selectWidget.$element
-                       );
+/**
+ * Widget defining the behavior used to choose from a set of values
+ * in a single_value group
+ *
+ * @class mw.rcfilters.ui.ValuePickerWidget
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.mixin.LabelElement
+ *
+ * @constructor
+ * @param {mw.rcfilters.dm.FilterGroup} model Group model
+ * @param {Object} [config] Configuration object
+ * @cfg {Function} [itemFilter] A filter function for the items from the
+ *  model. If not given, all items will be included. The function must
+ *  handle item models and return a boolean whether the item is included
+ *  or not. Example: function ( itemModel ) { return itemModel.isSelected(); }
+ */
+var ValuePickerWidget = function MwRcfiltersUiValuePickerWidget( model, config ) {
+       config = config || {};
+
+       // Parent
+       ValuePickerWidget.parent.call( this, config );
+       // Mixin constructors
+       OO.ui.mixin.LabelElement.call( this, config );
+
+       this.model = model;
+       this.itemFilter = config.itemFilter || function () {
+               return true;
        };
 
-       /* Initialization */
-
-       OO.inheritClass( ValuePickerWidget, OO.ui.Widget );
-       OO.mixinClass( ValuePickerWidget, OO.ui.mixin.LabelElement );
-
-       /* Events */
-
-       /**
-        * @event choose
-        * @param {string} name Item name
-        *
-        * An item has been chosen
-        */
-
-       /* Methods */
-
-       /**
-        * Respond to model update event
-        */
-       ValuePickerWidget.prototype.onModelUpdate = function () {
-               this.selectCurrentModelItem();
-       };
-
-       /**
-        * Respond to select widget choose event
-        *
-        * @param {OO.ui.ButtonOptionWidget} chosenItem Chosen item
-        * @fires choose
-        */
-       ValuePickerWidget.prototype.onSelectWidgetChoose = function ( chosenItem ) {
-               this.emit( 'choose', chosenItem.getData() );
-       };
-
-       /**
-        * Initialize the select widget
-        */
-       ValuePickerWidget.prototype.initializeSelectWidget = function () {
-               var items = this.model.getItems()
-                       .filter( this.itemFilter )
-                       .map( function ( filterItem ) {
-                               return new OO.ui.ButtonOptionWidget( {
-                                       data: filterItem.getName(),
-                                       label: filterItem.getLabel()
-                               } );
+       // Build the selection from the item models
+       this.selectWidget = new OO.ui.ButtonSelectWidget();
+       this.initializeSelectWidget();
+
+       // Events
+       this.model.connect( this, { update: 'onModelUpdate' } );
+       this.selectWidget.connect( this, { choose: 'onSelectWidgetChoose' } );
+
+       // Initialize
+       this.$element
+               .addClass( 'mw-rcfilters-ui-valuePickerWidget' )
+               .append(
+                       this.$label
+                               .addClass( 'mw-rcfilters-ui-valuePickerWidget-title' ),
+                       this.selectWidget.$element
+               );
+};
+
+/* Initialization */
+
+OO.inheritClass( ValuePickerWidget, OO.ui.Widget );
+OO.mixinClass( ValuePickerWidget, OO.ui.mixin.LabelElement );
+
+/* Events */
+
+/**
+ * @event choose
+ * @param {string} name Item name
+ *
+ * An item has been chosen
+ */
+
+/* Methods */
+
+/**
+ * Respond to model update event
+ */
+ValuePickerWidget.prototype.onModelUpdate = function () {
+       this.selectCurrentModelItem();
+};
+
+/**
+ * Respond to select widget choose event
+ *
+ * @param {OO.ui.ButtonOptionWidget} chosenItem Chosen item
+ * @fires choose
+ */
+ValuePickerWidget.prototype.onSelectWidgetChoose = function ( chosenItem ) {
+       this.emit( 'choose', chosenItem.getData() );
+};
+
+/**
+ * Initialize the select widget
+ */
+ValuePickerWidget.prototype.initializeSelectWidget = function () {
+       var items = this.model.getItems()
+               .filter( this.itemFilter )
+               .map( function ( filterItem ) {
+                       return new OO.ui.ButtonOptionWidget( {
+                               data: filterItem.getName(),
+                               label: filterItem.getLabel()
                        } );
+               } );
 
-               this.selectWidget.clearItems();
-               this.selectWidget.addItems( items );
+       this.selectWidget.clearItems();
+       this.selectWidget.addItems( items );
 
-               this.selectCurrentModelItem();
-       };
+       this.selectCurrentModelItem();
+};
 
-       /**
       * Select the current item that corresponds with the model item
       * that is currently selected
       */
-       ValuePickerWidget.prototype.selectCurrentModelItem = function () {
-               var selectedItem = this.model.findSelectedItems()[ 0 ];
+/**
+ * Select the current item that corresponds with the model item
+ * that is currently selected
+ */
+ValuePickerWidget.prototype.selectCurrentModelItem = function () {
+       var selectedItem = this.model.findSelectedItems()[ 0 ];
 
-               if ( selectedItem ) {
-                       this.selectWidget.selectItemByData( selectedItem.getName() );
-               }
-       };
+       if ( selectedItem ) {
+               this.selectWidget.selectItemByData( selectedItem.getName() );
+       }
+};
 
-       module.exports = ValuePickerWidget;
-}() );
+module.exports = ValuePickerWidget;
index c00d414..e366277 100644 (file)
@@ -1,84 +1,82 @@
-( function () {
-       var GroupWidget = require( './GroupWidget.js' ),
-               ViewSwitchWidget;
+var GroupWidget = require( './GroupWidget.js' ),
+       ViewSwitchWidget;
 
-       /**
       * A widget for the footer for the default view, allowing to switch views
       *
       * @class mw.rcfilters.ui.ViewSwitchWidget
       * @extends OO.ui.Widget
       *
       * @constructor
       * @param {mw.rcfilters.Controller} controller Controller
       * @param {mw.rcfilters.dm.FiltersViewModel} model View model
       * @param {Object} [config] Configuration object
       */
-       ViewSwitchWidget = function MwRcfiltersUiViewSwitchWidget( controller, model, config ) {
-               config = config || {};
+/**
+ * A widget for the footer for the default view, allowing to switch views
+ *
+ * @class mw.rcfilters.ui.ViewSwitchWidget
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller Controller
+ * @param {mw.rcfilters.dm.FiltersViewModel} model View model
+ * @param {Object} [config] Configuration object
+ */
+ViewSwitchWidget = function MwRcfiltersUiViewSwitchWidget( controller, model, config ) {
+       config = config || {};
 
-               // Parent
-               ViewSwitchWidget.parent.call( this, config );
+       // Parent
+       ViewSwitchWidget.parent.call( this, config );
 
-               this.controller = controller;
-               this.model = model;
+       this.controller = controller;
+       this.model = model;
 
-               this.buttons = new GroupWidget( {
-                       events: {
-                               click: 'buttonClick'
-                       },
-                       items: [
-                               new OO.ui.ButtonWidget( {
-                                       data: 'namespaces',
-                                       icon: 'article',
-                                       label: mw.msg( 'namespaces' )
-                               } ),
-                               new OO.ui.ButtonWidget( {
-                                       data: 'tags',
-                                       icon: 'tag',
-                                       label: mw.msg( 'rcfilters-view-tags' )
-                               } )
-                       ]
-               } );
+       this.buttons = new GroupWidget( {
+               events: {
+                       click: 'buttonClick'
+               },
+               items: [
+                       new OO.ui.ButtonWidget( {
+                               data: 'namespaces',
+                               icon: 'article',
+                               label: mw.msg( 'namespaces' )
+                       } ),
+                       new OO.ui.ButtonWidget( {
+                               data: 'tags',
+                               icon: 'tag',
+                               label: mw.msg( 'rcfilters-view-tags' )
+                       } )
+               ]
+       } );
 
-               // Events
-               this.model.connect( this, { update: 'onModelUpdate' } );
-               this.buttons.connect( this, { buttonClick: 'onButtonClick' } );
+       // Events
+       this.model.connect( this, { update: 'onModelUpdate' } );
+       this.buttons.connect( this, { buttonClick: 'onButtonClick' } );
 
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-viewSwitchWidget' )
-                       .append(
-                               new OO.ui.LabelWidget( {
-                                       label: mw.msg( 'rcfilters-advancedfilters' )
-                               } ).$element,
-                               $( '<div>' )
-                                       .addClass( 'mw-rcfilters-ui-viewSwitchWidget-buttons' )
-                                       .append( this.buttons.$element )
-                       );
-       };
+       this.$element
+               .addClass( 'mw-rcfilters-ui-viewSwitchWidget' )
+               .append(
+                       new OO.ui.LabelWidget( {
+                               label: mw.msg( 'rcfilters-advancedfilters' )
+                       } ).$element,
+                       $( '<div>' )
+                               .addClass( 'mw-rcfilters-ui-viewSwitchWidget-buttons' )
+                               .append( this.buttons.$element )
+               );
+};
 
-       /* Initialize */
+/* Initialize */
 
-       OO.inheritClass( ViewSwitchWidget, OO.ui.Widget );
+OO.inheritClass( ViewSwitchWidget, OO.ui.Widget );
 
-       /**
       * Respond to model update event
       */
-       ViewSwitchWidget.prototype.onModelUpdate = function () {
-               var currentView = this.model.getCurrentView();
+/**
+ * Respond to model update event
+ */
+ViewSwitchWidget.prototype.onModelUpdate = function () {
+       var currentView = this.model.getCurrentView();
 
-               this.buttons.getItems().forEach( function ( buttonWidget ) {
-                       buttonWidget.setActive( buttonWidget.getData() === currentView );
-               } );
-       };
+       this.buttons.getItems().forEach( function ( buttonWidget ) {
+               buttonWidget.setActive( buttonWidget.getData() === currentView );
+       } );
+};
 
-       /**
       * Respond to button switch click
       *
       * @param {OO.ui.ButtonWidget} buttonWidget Clicked button
       */
-       ViewSwitchWidget.prototype.onButtonClick = function ( buttonWidget ) {
-               this.controller.switchView( buttonWidget.getData() );
-       };
+/**
+ * Respond to button switch click
+ *
+ * @param {OO.ui.ButtonWidget} buttonWidget Clicked button
+ */
+ViewSwitchWidget.prototype.onButtonClick = function ( buttonWidget ) {
+       this.controller.switchView( buttonWidget.getData() );
+};
 
-       module.exports = ViewSwitchWidget;
-}() );
+module.exports = ViewSwitchWidget;
index 16c0533..7796148 100644 (file)
@@ -1,88 +1,86 @@
-( function () {
-       var MarkSeenButtonWidget = require( './MarkSeenButtonWidget.js' ),
-               WatchlistTopSectionWidget;
-       /**
-        * Top section (between page title and filters) on Special:Watchlist
-        *
-        * @class mw.rcfilters.ui.WatchlistTopSectionWidget
-        * @extends OO.ui.Widget
-        *
-        * @constructor
-        * @param {mw.rcfilters.Controller} controller
-        * @param {mw.rcfilters.dm.ChangesListViewModel} changesListModel
-        * @param {mw.rcfilters.ui.SavedLinksListWidget} savedLinksListWidget
-        * @param {jQuery} $watchlistDetails Content of the 'details' section that includes watched pages count
-        * @param {Object} [config] Configuration object
-        */
-       WatchlistTopSectionWidget = function MwRcfiltersUiWatchlistTopSectionWidget(
-               controller, changesListModel, savedLinksListWidget, $watchlistDetails, config
-       ) {
-               var editWatchlistButton,
-                       markSeenButton,
-                       $topTable,
-                       $bottomTable,
-                       $separator;
-               config = config || {};
+var MarkSeenButtonWidget = require( './MarkSeenButtonWidget.js' ),
+       WatchlistTopSectionWidget;
+/**
+ * Top section (between page title and filters) on Special:Watchlist
+ *
+ * @class mw.rcfilters.ui.WatchlistTopSectionWidget
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {mw.rcfilters.Controller} controller
+ * @param {mw.rcfilters.dm.ChangesListViewModel} changesListModel
+ * @param {mw.rcfilters.ui.SavedLinksListWidget} savedLinksListWidget
+ * @param {jQuery} $watchlistDetails Content of the 'details' section that includes watched pages count
+ * @param {Object} [config] Configuration object
+ */
+WatchlistTopSectionWidget = function MwRcfiltersUiWatchlistTopSectionWidget(
+       controller, changesListModel, savedLinksListWidget, $watchlistDetails, config
+) {
+       var editWatchlistButton,
+               markSeenButton,
+               $topTable,
+               $bottomTable,
+               $separator;
+       config = config || {};
 
-               // Parent
-               WatchlistTopSectionWidget.parent.call( this, config );
+       // Parent
+       WatchlistTopSectionWidget.parent.call( this, config );
 
-               editWatchlistButton = new OO.ui.ButtonWidget( {
-                       label: mw.msg( 'rcfilters-watchlist-edit-watchlist-button' ),
-                       icon: 'edit',
-                       href: require( '../config.json' ).StructuredChangeFiltersEditWatchlistUrl
-               } );
-               markSeenButton = new MarkSeenButtonWidget( controller, changesListModel );
+       editWatchlistButton = new OO.ui.ButtonWidget( {
+               label: mw.msg( 'rcfilters-watchlist-edit-watchlist-button' ),
+               icon: 'edit',
+               href: require( '../config.json' ).StructuredChangeFiltersEditWatchlistUrl
+       } );
+       markSeenButton = new MarkSeenButtonWidget( controller, changesListModel );
 
-               $topTable = $( '<div>' )
-                       .addClass( 'mw-rcfilters-ui-table' )
-                       .append(
-                               $( '<div>' )
-                                       .addClass( 'mw-rcfilters-ui-row' )
-                                       .append(
-                                               $( '<div>' )
-                                                       .addClass( 'mw-rcfilters-ui-cell' )
-                                                       .addClass( 'mw-rcfilters-ui-watchlistTopSectionWidget-watchlistDetails' )
-                                                       .append( $watchlistDetails )
-                                       )
-                                       .append(
-                                               $( '<div>' )
-                                                       .addClass( 'mw-rcfilters-ui-cell' )
-                                                       .addClass( 'mw-rcfilters-ui-watchlistTopSectionWidget-editWatchlistButton' )
-                                                       .append( editWatchlistButton.$element )
-                                       )
-                       );
+       $topTable = $( '<div>' )
+               .addClass( 'mw-rcfilters-ui-table' )
+               .append(
+                       $( '<div>' )
+                               .addClass( 'mw-rcfilters-ui-row' )
+                               .append(
+                                       $( '<div>' )
+                                               .addClass( 'mw-rcfilters-ui-cell' )
+                                               .addClass( 'mw-rcfilters-ui-watchlistTopSectionWidget-watchlistDetails' )
+                                               .append( $watchlistDetails )
+                               )
+                               .append(
+                                       $( '<div>' )
+                                               .addClass( 'mw-rcfilters-ui-cell' )
+                                               .addClass( 'mw-rcfilters-ui-watchlistTopSectionWidget-editWatchlistButton' )
+                                               .append( editWatchlistButton.$element )
+                               )
+               );
 
-               $bottomTable = $( '<div>' )
-                       .addClass( 'mw-rcfilters-ui-table' )
-                       .addClass( 'mw-rcfilters-ui-watchlistTopSectionWidget-savedLinksTable' )
-                       .append(
-                               $( '<div>' )
-                                       .addClass( 'mw-rcfilters-ui-row' )
-                                       .append(
-                                               $( '<div>' )
-                                                       .addClass( 'mw-rcfilters-ui-cell' )
-                                                       .append( markSeenButton.$element )
-                                       )
-                                       .append(
-                                               $( '<div>' )
-                                                       .addClass( 'mw-rcfilters-ui-cell' )
-                                                       .addClass( 'mw-rcfilters-ui-watchlistTopSectionWidget-savedLinks' )
-                                                       .append( savedLinksListWidget.$element )
-                                       )
-                       );
+       $bottomTable = $( '<div>' )
+               .addClass( 'mw-rcfilters-ui-table' )
+               .addClass( 'mw-rcfilters-ui-watchlistTopSectionWidget-savedLinksTable' )
+               .append(
+                       $( '<div>' )
+                               .addClass( 'mw-rcfilters-ui-row' )
+                               .append(
+                                       $( '<div>' )
+                                               .addClass( 'mw-rcfilters-ui-cell' )
+                                               .append( markSeenButton.$element )
+                               )
+                               .append(
+                                       $( '<div>' )
+                                               .addClass( 'mw-rcfilters-ui-cell' )
+                                               .addClass( 'mw-rcfilters-ui-watchlistTopSectionWidget-savedLinks' )
+                                               .append( savedLinksListWidget.$element )
+                               )
+               );
 
-               $separator = $( '<div>' )
-                       .addClass( 'mw-rcfilters-ui-watchlistTopSectionWidget-separator' );
+       $separator = $( '<div>' )
+               .addClass( 'mw-rcfilters-ui-watchlistTopSectionWidget-separator' );
 
-               this.$element
-                       .addClass( 'mw-rcfilters-ui-watchlistTopSectionWidget' )
-                       .append( $topTable, $separator, $bottomTable );
-       };
+       this.$element
+               .addClass( 'mw-rcfilters-ui-watchlistTopSectionWidget' )
+               .append( $topTable, $separator, $bottomTable );
+};
 
-       /* Initialization */
+/* Initialization */
 
-       OO.inheritClass( WatchlistTopSectionWidget, OO.ui.Widget );
+OO.inheritClass( WatchlistTopSectionWidget, OO.ui.Widget );
 
-       module.exports = WatchlistTopSectionWidget;
-}() );
+module.exports = WatchlistTopSectionWidget;
diff --git a/resources/src/mediawiki.rollback.confirmation.js b/resources/src/mediawiki.rollback.confirmation.js
new file mode 100644 (file)
index 0000000..5be49f0
--- /dev/null
@@ -0,0 +1,27 @@
+/*!
+ * JavaScript for rollback confirmation prompt
+ */
+( function () {
+
+       var postRollback = function ( url ) {
+               var $form = $( '<form>', {
+                       action: url,
+                       method: 'post'
+               } );
+               $form.appendTo( 'body' ).trigger( 'submit' );
+       };
+
+       $( '#mw-content-text' ).confirmable( {
+               i18n: {
+                       confirm: mw.msg( 'rollback-confirmation-confirm' ),
+                       yes: mw.msg( 'rollback-confirmation-yes' ),
+                       no: mw.msg( 'rollback-confirmation-no' )
+               },
+               delegate: '.mw-rollback-link a[data-mw="interface"]',
+               handler: function ( e ) {
+                       e.preventDefault();
+                       postRollback( $( this ).attr( 'href' ) );
+               }
+       } );
+
+}() );
index 8d56906..3907329 100644 (file)
@@ -1,3 +1,5 @@
+/* stylelint-disable selector-class-pattern */
+
 /* Make sure the links are not underlined or colored, ever. */
 /* There is already a :focus / :hover indication on the <div>. */
 .suggestions a.mw-searchSuggest-link,
index 3104a69..054bc27 100644 (file)
@@ -5,6 +5,8 @@
  * (ie: the CSS classing built into the system), like the TOC.
  */
 
+/* stylelint-disable selector-class-pattern */
+
 /* Table of Contents */
 .toc,
 .mw-warning,
index c6390c0..b01c518 100644 (file)
@@ -2,6 +2,8 @@
  * Icons and colors for external links.
  */
 
+/* stylelint-disable selector-class-pattern */
+
 @import 'mediawiki.mixins';
 
 .mw-parser-output a.external,
index 8b2657d..51018f7 100644 (file)
@@ -2,6 +2,8 @@
  * Style Parsoid HTML+RDFa output consistent with wikitext from PHP parser.
  */
 
+/* stylelint-disable selector-class-pattern */
+
 /*
  * Auto-numbered external links
  * Parsoid renders those as link without content, and lets CSS do the
index a33595c..df27f78 100644 (file)
@@ -6,6 +6,8 @@
  * This style sheet is used by the Monobook and Vector skins.
  */
 
+/* stylelint-disable selector-class-pattern */
+
 /* Links */
 a {
        text-decoration: none;
@@ -108,7 +110,6 @@ img {
 
 hr {
        height: 1px;
-       color: #a2a9b1;
        background-color: #a2a9b1;
        border: 0;
        margin: 0.2em 0;
index e9a2b08..c559048 100644 (file)
@@ -6,6 +6,8 @@
  * they are outputted by the actual MonoBook/Vector code by convention.
  */
 
+/* stylelint-disable selector-class-pattern */
+
 /* Categories */
 .catlinks {
        border: 1px solid #a2a9b1;
index d7415c9..c071199 100644 (file)
        min-width: 6em;
 }
 
+/* stylelint-disable-next-line selector-class-pattern */
 .apihelp-deprecated {
        font-weight: bold;
        color: #d33;
 }
 
+/* stylelint-disable-next-line selector-class-pattern */
 .apihelp-deprecated-value .oo-ui-labelElement-label {
        text-decoration: line-through;
 }
index 02e380a..58657db 100644 (file)
        }
 
        $( function () {
-               // This code is also loaded on the "block succeeded" page where there is no form,
-               // so username and expiry fields might also be missing.
-               var blockTargetWidget = infuseIfExists( $( '#mw-bi-target' ) ),
-                       anonOnlyField = infuseIfExists( $( '#mw-input-wpHardBlock' ).closest( '.oo-ui-fieldLayout' ) ),
-                       enableAutoblockField = infuseIfExists( $( '#mw-input-wpAutoBlock' ).closest( '.oo-ui-fieldLayout' ) ),
-                       hideUserWidget = infuseIfExists( $( '#mw-input-wpHideUser' ) ),
-                       hideUserField = infuseIfExists( $( '#mw-input-wpHideUser' ).closest( '.oo-ui-fieldLayout' ) ),
-                       watchUserField = infuseIfExists( $( '#mw-input-wpWatch' ).closest( '.oo-ui-fieldLayout' ) ),
-                       expiryWidget = infuseIfExists( $( '#mw-input-wpExpiry' ) ),
-                       editingWidget = infuseIfExists( $( '#mw-input-wpEditing' ) ),
-                       editingRestrictionWidget = infuseIfExists( $( '#mw-input-wpEditingRestriction' ) ),
-                       preventTalkPageEdit = infuseIfExists( $( '#mw-input-wpDisableUTEdit' ) ),
-                       pageRestrictionsWidget = infuseIfExists( $( '#mw-input-wpPageRestrictions' ) ),
-                       namespaceRestrictionsWidget = infuseIfExists( $( '#mw-input-wpNamespaceRestrictions' ) ),
-                       createAccountWidget = infuseIfExists( $( '#mw-input-wpCreateAccount' ) ),
-                       userChangedCreateAccount = false,
-                       updatingBlockOptions = false;
+               var blockTargetWidget, anonOnlyWidget, enableAutoblockWidget, hideUserWidget, watchUserWidget,
+                       expiryWidget, editingWidget, editingRestrictionWidget, preventTalkPageEditWidget,
+                       pageRestrictionsWidget, namespaceRestrictionsWidget, createAccountWidget, data,
+                       enablePartialBlocks, blockAllowsUTEdit, userChangedCreateAccount, updatingBlockOptions;
 
                function updateBlockOptions() {
                        var blocktarget = blockTargetWidget.getValue().trim(),
                                // infinityValues are the values the SpecialBlock class accepts as infinity (sf. wfIsInfinity)
                                infinityValues = [ 'infinite', 'indefinite', 'infinity', 'never' ],
                                isIndefinite = infinityValues.indexOf( expiryValue ) !== -1,
-                               // editingRestrictionWidget only exists if partial blocks is enabled; if not, block must be sitewide
-                               editingRestrictionValue = editingRestrictionWidget ? editingRestrictionWidget.getValue() : 'sitewide',
-                               editingIsSelected = editingWidget ? editingWidget.isSelected() : false,
+                               editingRestrictionValue = enablePartialBlocks ? editingRestrictionWidget.getValue() : 'sitewide',
+                               editingIsSelected = editingWidget.isSelected(),
                                isSitewide = editingIsSelected && editingRestrictionValue === 'sitewide';
 
-                       if ( enableAutoblockField ) {
-                               enableAutoblockField.toggle( !isNonEmptyIp );
+                       enableAutoblockWidget.setDisabled( isNonEmptyIp );
+                       if ( enableAutoblockWidget.isDisabled() ) {
+                               enableAutoblockWidget.setSelected( false );
+                       }
+
+                       anonOnlyWidget.setDisabled( !isIp && !isEmpty );
+                       if ( anonOnlyWidget.isDisabled() ) {
+                               anonOnlyWidget.setSelected( false );
                        }
-                       if ( hideUserField ) {
-                               hideUserField.toggle( !isNonEmptyIp && isIndefinite && isSitewide );
-                               if ( !hideUserField.isVisible() ) {
+
+                       if ( hideUserWidget ) {
+                               hideUserWidget.setDisabled( isNonEmptyIp || !isIndefinite || !isSitewide );
+                               if ( hideUserWidget.isDisabled() ) {
                                        hideUserWidget.setSelected( false );
                                }
                        }
-                       if ( anonOnlyField ) {
-                               anonOnlyField.toggle( isIp || isEmpty );
-                       }
-                       if ( watchUserField ) {
-                               watchUserField.toggle( !isIpRange || isEmpty );
+
+                       if ( watchUserWidget ) {
+                               watchUserWidget.setDisabled( isIpRange && !isEmpty );
+                               if ( watchUserWidget.isDisabled() ) {
+                                       watchUserWidget.setSelected( false );
+                               }
                        }
-                       if ( editingRestrictionWidget ) {
+
+                       if ( enablePartialBlocks ) {
                                editingRestrictionWidget.setDisabled( !editingIsSelected );
-                       }
-                       if ( pageRestrictionsWidget ) {
                                pageRestrictionsWidget.setDisabled( !editingIsSelected || isSitewide );
-                       }
-                       if ( namespaceRestrictionsWidget ) {
                                namespaceRestrictionsWidget.setDisabled( !editingIsSelected || isSitewide );
+                               if ( blockAllowsUTEdit ) {
+                                       // This option is disabled for partial blocks unless a namespace restriction
+                                       // for the User_talk namespace is in place.
+                                       preventTalkPageEditWidget.setDisabled(
+                                               editingIsSelected &&
+                                               editingRestrictionValue === 'partial' &&
+                                               namespaceRestrictionsWidget.getValue().indexOf(
+                                                       String( mw.config.get( 'wgNamespaceIds' ).user_talk )
+                                               ) === -1
+                                       );
+                               }
                        }
-                       if ( preventTalkPageEdit && namespaceRestrictionsWidget ) {
-                               // This option is disabled for partial blocks unless a namespace restriction
-                               // for the User_talk namespace is in place.
-                               preventTalkPageEdit.setDisabled(
-                                       editingIsSelected &&
-                                       editingRestrictionValue === 'partial' &&
-                                       namespaceRestrictionsWidget.getValue().indexOf(
-                                               String( mw.config.get( 'wgNamespaceIds' ).user_talk )
-                                       ) === -1
-                               );
-                       }
+
                        if ( !userChangedCreateAccount ) {
                                updatingBlockOptions = true;
                                createAccountWidget.setSelected( isSitewide );
 
                }
 
+               // This code is also loaded on the "block succeeded" page where there is no form,
+               // so check for block target widget; if it exists, the form is present
+               blockTargetWidget = infuseIfExists( $( '#mw-bi-target' ) );
+
                if ( blockTargetWidget ) {
-                       // Bind functions so they're checked whenever stuff changes
+                       data = require( './config.json' );
+                       enablePartialBlocks = data.EnablePartialBlocks;
+                       blockAllowsUTEdit = data.BlockAllowsUTEdit;
+                       userChangedCreateAccount = mw.config.get( 'wgCreateAccountDirty' );
+                       updatingBlockOptions = false;
+
+                       // Always present if blockTargetWidget is present
+                       editingWidget = OO.ui.infuse( $( '#mw-input-wpEditing' ) );
+                       expiryWidget = OO.ui.infuse( $( '#mw-input-wpExpiry' ) );
+                       createAccountWidget = OO.ui.infuse( $( '#mw-input-wpCreateAccount' ) );
+                       enableAutoblockWidget = OO.ui.infuse( $( '#mw-input-wpAutoBlock' ) );
+                       anonOnlyWidget = OO.ui.infuse( $( '#mw-input-wpHardBlock' ) );
                        blockTargetWidget.on( 'change', updateBlockOptions );
+                       editingWidget.on( 'change', updateBlockOptions );
                        expiryWidget.on( 'change', updateBlockOptions );
-                       if ( editingWidget ) {
-                               editingWidget.on( 'change', updateBlockOptions );
-                       }
-                       if ( editingRestrictionWidget ) {
-                               editingRestrictionWidget.on( 'change', updateBlockOptions );
-                       }
-                       if ( namespaceRestrictionsWidget ) {
-                               namespaceRestrictionsWidget.on( 'change', updateBlockOptions );
-                       }
-
                        createAccountWidget.on( 'change', function () {
                                if ( !updatingBlockOptions ) {
                                        userChangedCreateAccount = true;
                                }
                        } );
 
-                       // Call them now to set initial state (ie. Special:Block/Foobar?wpBlockExpiry=2+hours)
+                       // Present for certain rights
+                       watchUserWidget = infuseIfExists( $( '#mw-input-wpWatch' ) );
+                       hideUserWidget = infuseIfExists( $( '#mw-input-wpHideUser' ) );
+
+                       // Present for certain global configs
+                       if ( enablePartialBlocks ) {
+                               editingRestrictionWidget = OO.ui.infuse( $( '#mw-input-wpEditingRestriction' ) );
+                               pageRestrictionsWidget = OO.ui.infuse( $( '#mw-input-wpPageRestrictions' ) );
+                               namespaceRestrictionsWidget = OO.ui.infuse( $( '#mw-input-wpNamespaceRestrictions' ) );
+                               editingRestrictionWidget.on( 'change', updateBlockOptions );
+                               namespaceRestrictionsWidget.on( 'change', updateBlockOptions );
+                       }
+                       if ( blockAllowsUTEdit ) {
+                               preventTalkPageEditWidget = infuseIfExists( $( '#mw-input-wpDisableUTEdit' ) );
+                       }
+
                        updateBlockOptions();
                }
        } );
index d7923f4..f0b6913 100644 (file)
@@ -28,6 +28,7 @@ td.mw-enhanced-rc {
 }
 
 /* Show/hide arrows in enhanced changeslist */
+/* stylelint-disable-next-line selector-class-pattern */
 .mw-enhanced-rc .collapsible-expander {
        float: none;
 }
@@ -53,6 +54,7 @@ td.mw-enhanced-rc {
        font-weight: bold;
 }
 
+/* stylelint-disable-next-line selector-class-pattern */
 span.changedby {
        font-size: 95%;
 }
diff --git a/resources/src/mediawiki.special.changeslist.less b/resources/src/mediawiki.special.changeslist.less
deleted file mode 100644 (file)
index c78354b..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Styling for Special:Watchlist and Special:RecentChanges
- */
-
-.client-js .mw-input-hidden {
-       display: none;
-}
-
-/* Make sure namespace label is aligned correctly on mobile when checkboxes are displayed */
-.mw-label.mw-namespace-label {
-       vertical-align: top;
-}
-
-.mw-changeslist-line-watched .mw-title {
-       font-weight: bold;
-}
-
-/*
- * Titles, including username links, and also tag names
- * are prone to getting jumbled up
- * with other titles, usernames, etc. in mixed RTL-LTR environment.
- */
-.mw-changeslist .mw-tag-marker,
-.mw-changeslist .mw-title {
-       unicode-bidi: embed;
-}
-
-/* Colored watchlist and recent changes numbers */
-.mw-plusminus-pos {
-       color: #006400; /* dark green */
-}
-
-.mw-plusminus-neg {
-       color: #8b0000; /* dark red */
-}
-
-.mw-plusminus-null {
-       color: #a2a9b1; /* gray */
-}
-
-/*
- * Bidi-isolate these numbers.
- * See https://phabricator.wikimedia.org/T93484
- */
-.mw-plusminus-pos,
-.mw-plusminus-neg,
-.mw-plusminus-null {
-       unicode-bidi: -moz-isolate;
-       unicode-bidi: isolate;
-}
-
-/* Prevent FOUC if legend is initially collapsed */
-.mw-changeslist-legend.mw-collapsed .mw-collapsible-content {
-       display: none;
-}
-
-.mw-changeslist-legend.mw-collapsed {
-       margin-bottom: 0;
-}
-
-/* Prevent pushing down the content if legend is collapsed */
-.mw-changeslist-legend.mw-collapsed ~ ul:first-of-type > li:first-child,
-.mw-changeslist-legend.mw-collapsed + h4 + div > table.mw-changeslist-line:first-child {
-       clear: right;
-}
-
-/* Hide RCFilters highlight containers if RCFilters is not enabled.
-   This is overridden in mw.ui.rcfilters.ChangesListWrapperWidget.less if RCFilters is enabled. */
-.mw-rcfilters-ui-highlights {
-       display: none;
-}
diff --git a/resources/src/mediawiki.special.changeslist/changeslist.less b/resources/src/mediawiki.special.changeslist/changeslist.less
new file mode 100644 (file)
index 0000000..f24d1f2
--- /dev/null
@@ -0,0 +1,24 @@
+.client-js .mw-input-hidden {
+       display: none;
+}
+
+/*
+ * Titles, including username links, and also tag names
+ * are prone to getting jumbled up
+ * with other titles, usernames, etc. in mixed RTL-LTR environment.
+ */
+.mw-changeslist .mw-tag-marker,
+.mw-changeslist .mw-title {
+       unicode-bidi: embed;
+}
+
+/*
+ * Bidi-isolate these numbers.
+ * See https://phabricator.wikimedia.org/T93484
+ */
+.mw-plusminus-pos,
+.mw-plusminus-neg,
+.mw-plusminus-null {
+       unicode-bidi: -moz-isolate;
+       unicode-bidi: isolate;
+}
diff --git a/resources/src/mediawiki.special.changeslist/default.less b/resources/src/mediawiki.special.changeslist/default.less
new file mode 100644 (file)
index 0000000..203beee
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Styling for Special:Watchlist and Special:RecentChanges
+ */
+
+/* Make sure namespace label is aligned correctly on mobile when checkboxes are displayed */
+.mw-label.mw-namespace-label {
+       vertical-align: top;
+}
+
+.mw-changeslist-line-watched .mw-title {
+       font-weight: bold;
+}
+
+/* Colored watchlist and recent changes numbers */
+.mw-plusminus-pos {
+       color: #006400; /* dark green */
+}
+
+.mw-plusminus-neg {
+       color: #8b0000; /* dark red */
+}
+
+.mw-plusminus-null {
+       color: #a2a9b1; /* gray */
+}
+
+/* Prevent FOUC if legend is initially collapsed */
+.mw-changeslist-legend.mw-collapsed .mw-collapsible-content {
+       display: none;
+}
+
+.mw-changeslist-legend.mw-collapsed {
+       margin-bottom: 0;
+}
+
+/* Prevent pushing down the content if legend is collapsed */
+.mw-changeslist-legend.mw-collapsed ~ ul:first-of-type > li:first-child,
+.mw-changeslist-legend.mw-collapsed + h4 + div > table.mw-changeslist-line:first-child {
+       clear: right;
+}
+
+/* Hide RCFilters highlight containers if RCFilters is not enabled.
+   This is overridden in mw.ui.rcfilters.ChangesListWrapperWidget.less if RCFilters is enabled. */
+.mw-rcfilters-ui-highlights {
+       display: none;
+}
index ffa9e42..71b343c 100644 (file)
@@ -3,9 +3,7 @@
  */
 ( function () {
        $( function () {
-               var $preferences, tabs, wrapper, previousTab, switchingNoHash;
-
-               $preferences = $( '#preferences' );
+               var tabs, previousTab, switchingNoHash;
 
                // Make sure the accessibility tip is focussable so that keyboard users take notice,
                // but hide it by default to reduce visual clutter.
                        } )
                        .insertBefore( '.mw-htmlform-ooui-wrapper' );
 
-               tabs = new OO.ui.IndexLayout( {
-                       expanded: false,
-                       // Do not remove focus from the tabs menu after choosing a tab
-                       autoFocus: false
-               } );
-
-               mw.config.get( 'wgPreferencesTabs' ).forEach( function ( tabConfig ) {
-                       var panel, $panelContents;
-
-                       panel = new OO.ui.TabPanelLayout( tabConfig.name, {
-                               expanded: false,
-                               label: tabConfig.label
-                       } );
-                       $panelContents = $( '#mw-prefsection-' + tabConfig.name );
-
-                       // Hide the unnecessary PHP PanelLayouts
-                       // (Do not use .remove(), as that would remove event handlers for everything inside them)
-                       $panelContents.parent().detach();
+               tabs = OO.ui.infuse( $( '.mw-prefs-tabs' ) );
 
-                       panel.$element.append( $panelContents );
-                       tabs.addTabPanels( [ panel ] );
-
-                       // Remove duplicate labels
-                       // (This must be after .addTabPanels(), otherwise the tab item doesn't exist yet)
-                       $panelContents.children( 'legend' ).remove();
-                       $panelContents.attr( 'aria-labelledby', panel.getTabItem().getElementId() );
-               } );
-
-               wrapper = new OO.ui.PanelLayout( {
-                       expanded: false,
-                       padded: false,
-                       framed: true
-               } );
-               wrapper.$element.append( tabs.$element );
-               $preferences.prepend( wrapper.$element );
-               $( '.mw-prefs-faketabs' ).remove();
+               tabs.$element.addClass( 'mw-prefs-tabs-infused' );
 
                function enhancePanel( panel ) {
                        if ( !panel.$element.data( 'mw-section-infused' ) ) {
-                               // mw-htmlform-autoinfuse-lazy class has been removed by replacing faketabs
+                               panel.$element.removeClass( 'mw-htmlform-autoinfuse-lazy' );
                                mw.hook( 'htmlform.enhance' ).fire( panel.$element );
                                panel.$element.data( 'mw-section-infused', true );
                        }
@@ -75,7 +40,7 @@
                        // Changing the hash apparently causes keyboard focus to be lost?
                        // Save and restore it. This makes no sense though.
                        active = document.activeElement;
-                       location.hash = '#mw-prefsection-' + panel.getName();
+                       location.hash = '#' + panel.getName();
                        if ( active ) {
                                active.focus();
                        }
@@ -86,7 +51,7 @@
 
                /**
                 * @ignore
-                * @param {string} name the name of a tab without the prefix ("mw-prefsection-")
+                * @param {string} name The name of a tab
                 * @param {boolean} [noHash] A hash will be set according to the current
                 *  open section. Use this flag to suppress this.
                 */
                                matchedElement, parentSection;
                        if ( hash.match( /^#mw-prefsection-[\w]+$/ ) ) {
                                mw.storage.session.remove( 'mwpreferences-prevTab' );
-                               switchPrefTab( hash.replace( '#mw-prefsection-', '' ) );
+                               switchPrefTab( hash.slice( 1 ) );
                        } else if ( hash.match( /^#mw-[\w-]+$/ ) ) {
                                matchedElement = document.getElementById( hash.slice( 1 ) );
                                parentSection = $( matchedElement ).parent().closest( '[id^="mw-prefsection-"]' );
                                if ( parentSection.length ) {
                                        mw.storage.session.remove( 'mwpreferences-prevTab' );
                                        // Switch to proper tab and scroll to selected item.
-                                       switchPrefTab( parentSection.attr( 'id' ).replace( 'mw-prefsection-', '' ), true );
+                                       switchPrefTab( parentSection.attr( 'id' ), true );
                                        matchedElement.scrollIntoView();
                                }
                        }
                        if ( hash.match( /^#mw-[\w-]+/ ) ) {
                                detectHash();
                        } else if ( hash === '' ) {
-                               switchPrefTab( 'personal', true );
+                               switchPrefTab( 'mw-prefsection-personal', true );
                        }
                } )
                        // Run the function immediately to select the proper tab on startup.
index b1931f4..532b9ca 100644 (file)
        overflow: hidden;
 }
 
-/* Most outer Panellayout:
- * Decrease contrast of `border` slightly as padding/border combination is sufficient
- * accessibility wise and focus of content is more important here. */
-#preferences .oo-ui-panelLayout-framed {
-       border-color: #c8ccd1;
-}
+.mw-prefs-tabs {
+       .mw-prefs-fieldset-wrapper {
+               padding-left: 0;
+               padding-right: 0;
+
+               &:first-child {
+                       padding-top: 0;
+               }
 
-#preferences .oo-ui-menuLayout .oo-ui-panelLayout-framed .oo-ui-panelLayout-framed {
-       border-width: 0;
-       border-radius: 0;
-       padding-left: 0;
-       padding-right: 0;
-       box-shadow: none;
+               &:last-child {
+                       padding-bottom: 0;
+               }
+       }
 }
 
-.mw-prefs-faketabs > .oo-ui-menuLayout > .oo-ui-menuLayout-menu a {
-       color: inherit;
-       text-decoration: none;
+.mw-prefs-tabs-wrapper.oo-ui-panelLayout-framed,
+.mw-prefs-tabs > .oo-ui-menuLayout-content > .oo-ui-indexLayout-stackLayout > .oo-ui-tabPanelLayout {
+       /* Decrease contrast of `border` slightly as padding/border combination is sufficient
+        * accessibility wise and focus of content is more important here. */
+       border-color: #c8ccd1;
 }
 
-/* Disabled JavaScript */
+/* JavaScript disabled */
 .client-nojs {
-       /* Adjust the borders: frame each prefsection instead of the
-        * whole tabLayout wrapper */
-       #preferences .oo-ui-menuLayout .oo-ui-panelLayout-framed .oo-ui-panelLayout-framed:first-child {
-               border-color: #c8ccd1;
-               border-width: 1px 0 0;
-       }
-
-       #preferences .oo-ui-panelLayout-framed .oo-ui-panelLayout-framed:last-child {
-               padding-bottom: 0;
-               margin-bottom: 0;
-       }
-
-       /* Fake Tabs to address reflow */
-       .mw-prefs-faketabs {
+       // Disable .oo-ui-panelLayout-framed on outer wrapper
+       .mw-prefs-tabs-wrapper {
                border-width: 0;
                border-radius: 0;
-               .box-shadow( none );
+       }
 
-               > .oo-ui-menuLayout > .oo-ui-menuLayout-content > .oo-ui-stackLayout {
-                       margin-bottom: 1em;
+       .mw-prefs-tabs {
+               // Hide the tab menu when JS is disabled as we can't use this feature
+               > .oo-ui-menuLayout-menu {
+                       display: none;
                }
 
-               /* Hide the tab menu when JS is disabled as we can't use this feature */
-               > .oo-ui-menuLayout > .oo-ui-menuLayout-menu {
-                       display: none;
+               .mw-prefs-section-fieldset {
+                       // <legend> is hard to style, so apply border to top of group
+                       > .oo-ui-fieldsetLayout-group {
+                               padding-top: 1.5em;
+                               border-top: 1px solid #c8ccd1;
+                       }
+
+                       // Remove spacing between legend and underline
+                       &.oo-ui-labelElement > .oo-ui-fieldsetLayout-header > .oo-ui-labelElement-label {
+                               margin-bottom: 0;
+                       }
+               }
+
+               // Spacing between sections
+               > .oo-ui-menuLayout-content > .oo-ui-indexLayout-stackLayout > .oo-ui-tabPanelLayout {
+                       margin-bottom: 1em;
                }
        }
 }
 
-/* Enabled JavaScript
- * Hide top level legends when JS is enabled, as they will not be visible
- * when the real tabLayout is built */
-.client-js #preferences {
+/* JavaScript enabled */
+.client-js .mw-prefs-tabs {
        .oo-ui-tabPanelLayout {
-               padding-top: 0.5em;
+               // Panels don't need borders as the IndexLayout is inside a framed wrapper.
+               border: 0;
 
-               & > fieldset > legend {
+               // Hide section legend, only used in nojs mode
+               > fieldset > legend {
                        display: none;
                }
        }
 
-       .oo-ui-panelLayout-framed .oo-ui-panelLayout-framed {
-               margin-top: 2.286em; /* equals `32px` at `font-size: 14px;` */
-               margin-bottom: 0;
-               border-width: 0;
-               border-radius: 0;
-               padding: 0;
-               box-shadow: none;
-
-               &:first-child {
-                       margin-top: 0.85714286em;
-               }
-
-               .oo-ui-panelLayout-framed:first-child {
-                       margin-top: 0;
+       // Hide all but the first panel before infusion
+       &:not( .mw-prefs-tabs-infused ) {
+               .oo-ui-tabPanelLayout:not( :first-child ) {
+                       display: none;
                }
        }
-
-       > .oo-ui-panelLayout > .oo-ui-fieldsetLayout > .oo-ui-fieldsetLayout-header {
-               margin-bottom: 1em;
-       }
 }
 
 /* Make the "Basic information" section more compact */
index e9b0e6a..6552750 100644 (file)
@@ -7,7 +7,7 @@
                summaryByteLimit = mw.config.get( 'wgCommentByteLimit' ),
                $wpRevDeleteReasonList = $( '#wpRevDeleteReasonList' ),
                $wpReason = $( '#wpReason' ),
-               filterFn = function ( input ) {
+               filterFunction = function ( input ) {
                        // Should be built the same as in SpecialRevisionDelete::submit()
                        var comment = $wpRevDeleteReasonList.val();
                        if ( comment === 'other' ) {
@@ -21,9 +21,9 @@
 
        // Limit to bytes or UTF-8 codepoints, depending on MediaWiki's configuration
        if ( summaryCodePointLimit ) {
-               $wpReason.codePointLimit( summaryCodePointLimit, filterFn );
+               $wpReason.codePointLimit( summaryCodePointLimit, filterFunction );
        } else if ( summaryByteLimit ) {
-               $wpReason.byteLimit( summaryByteLimit, filterFn );
+               $wpReason.byteLimit( summaryByteLimit, filterFunction );
        }
 
 }() );
index 81c8dc9..5f99f82 100644 (file)
@@ -4,6 +4,8 @@
 @import 'mediawiki.ui/variables.less';
 @import 'mediawiki.mixins';
 
+/* stylelint-disable selector-class-pattern */
+
 .mw-searchresults-has-iw {
        .iw-headline {
                font-weight: bold;
index 0f27420..dcb51fa 100644 (file)
@@ -1,5 +1,7 @@
 /* Special:Search */
 
+/* stylelint-disable selector-class-pattern */
+
 /*
  * Fixes sister projects box moving down the extract
  * of the first result (T18886).
index 77ca848..ac2e18b 100644 (file)
                delay: 500, // ms
                timeoutID: false,
 
-               keypress: function () {
-                       if ( !ajaxUploadDestCheck ) {
-                               return;
-                       }
-
-                       // Find file to upload
-                       if ( !$( '#wpDestFile' ).length || !$( '#wpDestFile-warning' ).length ) {
-                               return;
-                       }
-
-                       this.nameToCheck = $( '#wpDestFile' ).val();
-
-                       // Clear timer
-                       if ( this.timeoutID ) {
-                               clearTimeout( this.timeoutID );
-                       }
-                       // Check response cache
-                       if ( Object.prototype.hasOwnProperty.call( this.responseCache, this.nameToCheck ) ) {
-                               this.setWarning( this.responseCache[ this.nameToCheck ] );
-                               return;
-                       }
-
-                       this.timeoutID = setTimeout( function () {
-                               uploadWarning.timeout();
-                       }, this.delay );
-               },
-
                checkNow: function ( fname ) {
                        if ( !ajaxUploadDestCheck ) {
                                return;
index 2366249..9f27150 100644 (file)
@@ -39,6 +39,8 @@ section.mw-form-header {
        margin-top: 6px;
 }
 
+/* FIXME: These should be namespaced to mw-ext-confirmedit-fancycaptcha-, and really shouldn't be in core at all */
+/* stylelint-disable-next-line selector-class-pattern */
 .fancycaptcha-captcha-container {
        background-color: #f8f9fa;
        margin-bottom: 15px;
@@ -54,6 +56,7 @@ section.mw-form-header {
 }
 
 /* Put a border around the fancycaptcha-image-container. */
+/* stylelint-disable-next-line selector-class-pattern */
 .fancycaptcha-captcha-and-reload {
        border: 1px solid #c8ccd1;
        border-radius: 2px 2px 0 0;
@@ -63,6 +66,7 @@ section.mw-form-header {
        background-color: #fff;
 }
 
+/* stylelint-disable-next-line selector-class-pattern */
 .fancycaptcha-captcha-container .mw-ui-input {
        margin-top: -1px;
        border-color: #c8ccd1;
@@ -70,6 +74,7 @@ section.mw-form-header {
 }
 
 /* Make the fancycaptcha-image-container full-width within its parent. */
+/* stylelint-disable-next-line selector-class-pattern */
 .fancycaptcha-image-container {
        width: 100%;
 }
index 3cfa5a8..d8b773c 100644 (file)
        margin-bottom: 30px;
 }
 
+/* stylelint-disable-next-line selector-class-pattern */
 .mw-number-text.icon-edits {
        /* @embed */
        background: url( images/icon-edits.png ) no-repeat left center;
 }
 
+/* stylelint-disable-next-line selector-class-pattern */
 .mw-number-text.icon-pages {
        /* @embed */
        background: url( images/icon-pages.png ) no-repeat left center;
 }
 
+/* stylelint-disable-next-line selector-class-pattern */
 .mw-number-text.icon-contributors {
        /* @embed */
        background: url( images/icon-contributors.png ) no-repeat left center;
index 4dc4c27..923b595 100644 (file)
@@ -1,3 +1,6 @@
+/*!
+ * Styles for Special:ApiSandbox
+ */
 .client-js .mw-apisandbox-nojs {
        display: none;
 }
index d7ee3da..6d12722 100644 (file)
@@ -1,10 +1,12 @@
-/* Special:Block styles */
+/*!
+ * Styles for Special:Block
+ */
 
-// OOUIHTMLForm styles
-@ooui-font-size-browser: 16; // Assumed browser default of `16px`
-@ooui-font-size-base: 0.875em; // Equals `14px` at browser default of `16px`
+// OOUIHTMLForm specifics
+@ooui-font-size-browser: 16; // Assumed browser default of `16px`.
+@ooui-font-size-base: 0.875em; // Equals `14px` at browser default of `16px`.
 
-@ooui-spacing-radio-label: 26 / @ooui-font-size-browser / @ooui-font-size-base; // Equals `1.85714286em`≈`26px`
+@ooui-spacing-radio-label: 26 / @ooui-font-size-browser / @ooui-font-size-base; // Equals `1.85714286em`≈`26px`.
 
 body.mw-special-Block {
        .mw-block-editing-restriction.oo-ui-fieldLayout {
diff --git a/resources/src/mediawiki.special/blocklist.less b/resources/src/mediawiki.special/blocklist.less
new file mode 100644 (file)
index 0000000..80a59b1
--- /dev/null
@@ -0,0 +1,19 @@
+.mw-special-BlockList {
+       .oo-ui-fieldsetLayout-group {
+               max-width: 50em;
+       }
+
+       .oo-ui-layout {
+               &.mw-field-block-type,
+               &.mw-field-limit.mw-has-field-block-type {
+                       display: inline-block;
+                       width: 50%;
+                       box-sizing: border-box;
+                       margin-top: 0;
+               }
+
+               &.mw-field-block-type {
+                       padding-right: 1em;
+               }
+       }
+}
index 87b7a8b..38b4078 100644 (file)
@@ -1,3 +1,6 @@
+/*!
+ * Styles for Special:ComparePages
+ */
 @import 'mediawiki.mixins';
 
 .mw-special-ComparePages .mw-htmlform-ooui-wrapper {
index 204009c..8964a13 100644 (file)
@@ -1,5 +1,5 @@
 /*!
- * Styling for Special:EditTags and action=editchangetags
+ * Styles for Special:EditTags and action=editchangetags
  */
 #mw-edittags-tags-selector td {
        vertical-align: top;
index 9428fed..25113ea 100644 (file)
@@ -2,6 +2,7 @@
  * Styles for Special:MovePage
  */
 
+/* stylelint-disable-next-line selector-class-pattern */
 .movepage-wrapper {
        width: 50em;
 }
index 835cab8..8d72b11 100644 (file)
@@ -1,5 +1,5 @@
 /*!
- * Styling for Special:NewPages
+ * Styles for Special:NewPages
  */
 
 // OOUIHTMLForm styles
index 7ef75d0..b0cc932 100644 (file)
@@ -1,4 +1,9 @@
-/* Distinguish actual data from information about it being hidden visually */
+/*!
+ * Styles for Special:PagesWithProp
+ */
+
+/* Distinguish actual data from information about it being hidden visually. */
+/* stylelint-disable-next-line selector-class-pattern */
 .prop-value-hidden {
        font-style: italic;
 }
index 35071be..3f76cf0 100644 (file)
@@ -1,6 +1,11 @@
-/* Special:AllMessages */
+/*!
+ * Styles shared across various special pages.
+ */
 @import 'mediawiki.mixins';
 
+/* stylelint-disable selector-class-pattern */
+
+/* Special:AllMessages */
 /* Visually hide repeating text, but leave in for better form navigation on screen readers */
 .mw-special-Allmessages .mw-htmlform-ooui .oo-ui-fieldsetLayout:first-child .oo-ui-fieldsetLayout-header {
        .mixin-screen-reader-text();
index 626a7e8..0a5796e 100644 (file)
@@ -1,5 +1,5 @@
 /*!
- * Styling for Special:Upload
+ * Styles for Special:Upload
  */
 .mw-destfile-warning {
        border: 1px solid #fde29b;
index 14ad695..06a74f5 100644 (file)
@@ -1,5 +1,5 @@
 /*!
- * Styling for Special:UserRights
+ * Styles for Special:UserRights
  */
 .mw-userrights-nested {
        margin-left: 1.2em;
index c9861c2..1660bd2 100644 (file)
@@ -1,5 +1,5 @@
 /*!
- * Styling for elements generated by JavaScript on Special:Watchlist
+ * Styles for elements generated by JavaScript on Special:Watchlist
  */
 .mw-changelist-line-inner-unwatched {
        text-decoration: line-through;
index e9b2c9d..3405ba7 100644 (file)
@@ -33,7 +33,7 @@
         *
         * @param {string} key Key of item to retrieve
         * @return {string|null|boolean} String value, null if no value exists, or false
-        *  if localStorage is not available.
+        *  if storage is not available.
         */
        SafeStorage.prototype.get = function ( key ) {
                try {
@@ -47,7 +47,7 @@
         *
         * @param {string} key Key name to store under
         * @param {string} value Value to be stored
-        * @return {boolean} Whether the save succeeded or not
+        * @return {boolean} The value was set
         */
        SafeStorage.prototype.set = function ( key, value ) {
                try {
@@ -61,7 +61,7 @@
         * Remove a value from device storage.
         *
         * @param {string} key Key of item to remove
-        * @return {boolean} Whether the save succeeded or not
+        * @return {boolean} Whether the key was removed
         */
        SafeStorage.prototype.remove = function ( key ) {
                try {
                return false;
        };
 
+       /**
+        * Retrieve JSON object from device storage.
+        *
+        * @param {string} key Key of item to retrieve
+        * @return {Object|null|boolean} Object, null if no value exists or value
+        *  is not JSON-parseable, or false if storage is not available.
+        */
+       SafeStorage.prototype.getObject = function ( key ) {
+               var json = this.get( key );
+
+               if ( json === false ) {
+                       return false;
+               }
+
+               try {
+                       return JSON.parse( json );
+               } catch ( e ) {}
+
+               return null;
+       };
+
+       /**
+        * Set an object value in device storage by JSON encoding
+        *
+        * @param {string} key Key name to store under
+        * @param {Object} value Object value to be stored
+        * @return {boolean} The value was set
+        */
+       SafeStorage.prototype.setObject = function ( key, value ) {
+               var json;
+               try {
+                       json = JSON.stringify( value );
+                       return this.set( key, json );
+               } catch ( e ) {}
+               return false;
+       };
+
        /**
         * A wrapper for the HTML5 `localStorage` interface
         * that is safe to call on all browsers.
index 31a8826..d89cc2a 100644 (file)
@@ -1,6 +1,7 @@
 /* This style is loaded on all media. */
 
 /* Hide the content of the TOC when the checkbox is checked. */
+/* stylelint-disable-next-line selector-class-pattern */
 .toctogglecheckbox:checked ~ ul {
        display: none;
 }
index e905dbe..2081d35 100644 (file)
@@ -1,4 +1,5 @@
 /* Hide the complete TOC on print when the TOC is hidden. */
+/* stylelint-disable-next-line selector-class-pattern */
 .toctogglecheckbox:checked + .toctitle {
        display: none;
 }
index ff41b5e..7d7727c 100644 (file)
@@ -1,5 +1,7 @@
 /* This style adds a toggle button with internationalized message for the TOC. */
 
+/* stylelint-disable selector-class-pattern */
+
 /* When the browser supports :checked then overwrite the style="display:none" and make the */
 /* checkbox invisible on another way to allow to focus the checkbox with keyboard. */
 :not( :checked ) > .toctogglecheckbox {
index 3490ebc..e105f4d 100644 (file)
@@ -1,47 +1,8 @@
 @import 'mediawiki.mixins';
+@import 'mediawiki.ui/mixins.buttons';
 @import 'mediawiki.ui/variables';
 
-// Buttons
-// Helper mixins
-// Primary buttons mixin
-.button-colors-primary( @bgColor, @highlightColor, @activeColor ) {
-       background-color: @bgColor;
-       color: #fff;
-       // border of the same color as background so that light background and
-       // dark background buttons are the same height and width
-       border: 1px solid @bgColor;
-
-       &:hover {
-               background-color: @highlightColor;
-               border-color: @highlightColor;
-       }
-
-       &:focus {
-               box-shadow: inset 0 0 0 1px @bgColor, inset 0 0 0 2px #fff;
-       }
-
-       &:active,
-       &.is-on {
-               background-color: @activeColor;
-               border-color: @activeColor;
-               box-shadow: none;
-       }
-
-       &:disabled {
-               background-color: @colorGray12;
-               color: #fff;
-               border-color: @colorGray12;
-
-               // Make sure disabled buttons don't have hover and active states
-               &:hover,
-               &:active {
-                       background-color: @colorGray12;
-                       color: #fff;
-                       border-color: @colorGray12;
-                       box-shadow: none;
-               }
-       }
-}
+/* stylelint-disable selector-class-pattern */
 
 // All buttons start with `.mw-ui-button` class, modified by other classes.
 // It can be any element.  Due to a lack of a CSS reset, the exact styling of
 .mw-ui-button {
        background-color: @colorGray15;
        color: @colorButtonText;
-       // Container layout
-       display: inline-block;
-       .box-sizing( border-box );
-       min-width: 4em;
-       max-width: 28.75em; // equivalent to 460px, @see T95367
-       margin: 0;
-       padding: 0.57142857em 0.9375em; // equivalent to `8px 12px`
-       border: @border-width-base @border-style-base @border-color-base;
-       border-radius: @borderRadius;
-       // Inherit the font rather than apply user agent stylesheet (T72072)
-       font-family: inherit;
-       font-size: 1em;
-       font-weight: bold;
-       line-height: 1;
-       text-align: center;
-       // Disable weird iOS styling
-       -webkit-appearance: none;
-       // IE 6 & 7 hack
-       // https://stackoverflow.com/a/5838575/365238
-       *display: inline; /* stylelint-disable-line declaration-block-no-duplicate-properties */
-       zoom: 1;
-       // Ensure that buttons and inputs are nicely aligned when they have differing heights
-       vertical-align: middle;
-       // Interaction styling
-       cursor: pointer;
-
-       // Make sure that `color` isn't inheriting from user-agent styles
-       &:visited {
-               color: @colorButtonText;
-       }
-
-       &:hover {
-               background-color: @background-color-base;
-               color: @colorGray4;
-               border-color: @colorGray10;
-       }
-
-       &:focus {
-               background-color: @background-color-base;
-               // Make sure that `color` isn't inheriting from user-agent styles
-               color: @colorButtonText;
-               border-color: @colorProgressive;
-               box-shadow: inset 0 0 0 1px @colorProgressive, inset 0 0 0 2px @background-color-base;
-               outline-width: 0;
-
-               // Remove the inner border and padding in Firefox.
-               &::-moz-focus-inner {
-                       border-color: transparent;
-                       padding: 0;
-               }
-       }
-
-       &:active,
-       &.is-on {
-               background-color: @colorGray12;
-               color: @colorGray1;
-               border-color: @colorGray7;
-               box-shadow: none;
-       }
-
-       &:disabled {
-               background-color: @colorGray12;
-               color: @colorBaseInverted;
-               border-color: @colorGray12;
-               cursor: default;
-
-               // Make sure disabled buttons don't have hover and active states
-               &:hover,
-               &:active {
-                       background-color: @colorGray12;
-                       color: @colorBaseInverted;
-                       box-shadow: none;
-                       border-color: @colorGray12;
-               }
-       }
-
-       // `:not()` is used exclusively for `transition`s as both are not supported by IE < 9
-       &:not( :disabled ) {
-               .transition( ~'background-color 100ms, color 100ms, border-color 100ms, box-shadow 100ms' );
-       }
+       .mw-ui-button();
+       .mw-ui-button-states();
 
        // Styling for specific button types
        // -----------------------------------------
        //
        // Styleguide 2.1.2.
        &.mw-ui-progressive {
-               .button-colors-primary( @colorProgressive, @colorProgressiveHighlight, @colorProgressiveActive );
+               .mw-ui-button-colors-primary( @colorProgressive, @colorProgressiveHighlight, @colorProgressiveActive );
 
                &.mw-ui-quiet {
                        color: @colorProgressive;
        //
        // Styleguide 2.1.3.
        &.mw-ui-destructive {
-               .button-colors-primary( @colorDestructive, @colorDestructiveHighlight, @colorDestructiveActive );
+               .mw-ui-button-colors-primary( @colorDestructive, @colorDestructiveHighlight, @colorDestructiveActive );
 
                &.mw-ui-quiet {
                        color: @colorDestructive;
index 08612d0..92b4b8a 100644 (file)
@@ -74,7 +74,7 @@
                        background-origin: border-box;
                        background-position: center center;
                        background-repeat: no-repeat;
-                       .background-size( 0, 0 );
+                       background-size: 0 0;
                        .box-sizing( border-box );
                        position: absolute;
                        // Ensure alignment of checkbox to middle of the text in long labels, see T85241
@@ -90,7 +90,7 @@
                // Apply a checkmark on the pseudo `:before` element when the input is checked
                &:checked + label:before {
                        .background-image-svg( 'images/checkbox-checked.svg', 'images/checkbox-checked.png' );
-                       .background-size( 90%, 90% );
+                       background-size: 90% 90%;
                }
 
                &:enabled {
index 5fa8e5a..d08fff5 100644 (file)
@@ -3,6 +3,8 @@
 @import 'mediawiki.mixins';
 @import 'mediawiki.ui/variables';
 
+/* stylelint-disable selector-class-pattern */
+
 // --------------------------------------------------------------------------
 // Layouts
 // --------------------------------------------------------------------------
index d9b1227..5f629e7 100644 (file)
                },
 
                /**
-                * Get an automatically generated random ID (persisted in sessionStorage)
+                * Retrieve a random ID persisted in sessionStorage, generating it if needed
                 *
-                * This ID is ephemeral for everyone, staying in their browser only until they
-                * close their browsing session.
+                * This ID is stored in sessionStorage and persists within a single tab,
+                * including between page views through links and form submissions,
+                * and when going forwards/backwards in browser history, and when restoring
+                * a closed tab, or restoring a closed browser session.
+                *
+                * This is different from session cookies, because it is not shared between
+                * tabs of the same browser. Two simultaneous pageviews in the same browser
+                * can have different session IDs. The ID is also not re-used when opening
+                * a new tab to a website after fully closing others.
+                *
+                * See https://phabricator.wikimedia.org/T118063#4547178 and
+                * https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage
+                * for more information.
                 *
                 * @return {string} Random session ID
                 */
                        var userGroups = mw.config.get( 'wgUserGroups', [] );
 
                        // Uses promise for backwards compatibility
-                       return $.Deferred().resolve( userGroups ).done( callback );
+                       return $.Deferred().resolve( userGroups ).then( callback );
                },
 
                /**
                        return getUserInfo().then(
                                function ( userInfo ) { return userInfo.rights; },
                                function () { return []; }
-                       ).done( callback );
+                       ).then( callback );
                }
        } );
 
index f66b0d2..753a5c7 100644 (file)
@@ -2,7 +2,7 @@
 
        /**
         * Provides various methods needed for formatting dates and times. This
-        * implementation implments the [Discordian calendar][1], mainly for testing with
+        * implementation implements the [Discordian calendar][1], mainly for testing with
         * something very different from the usual Gregorian calendar.
         *
         * Being intended mainly for testing, niceties like i18n and better
index 63da95a..453bf03 100644 (file)
         *
         * @param {OO.ui.TextInputWidget} textInputWidget Text input widget
         * @param {number} [limit] Byte limit, defaults to $input's maxlength
+        * @param {Function} [filterFunction] Function to call on the string before assessing the length.
         */
-       mw.widgets.visibleByteLimit = function ( textInputWidget, limit ) {
+       mw.widgets.visibleByteLimit = function ( textInputWidget, limit, filterFunction ) {
                limit = limit || +textInputWidget.$input.attr( 'maxlength' );
+               if ( !filterFunction || typeof filterFunction !== 'function' ) {
+                       filterFunction = undefined;
+               }
 
                function updateCount() {
-                       var remaining = limit - byteLength( textInputWidget.getValue() );
+                       var value = textInputWidget.getValue(),
+                               remaining;
+                       if ( filterFunction ) {
+                               value = filterFunction( value );
+                       }
+                       remaining = limit - byteLength( value );
                        if ( remaining > 99 ) {
                                remaining = '';
                        } else {
@@ -32,7 +41,7 @@
                updateCount();
 
                // Actually enforce limit
-               textInputWidget.$input.byteLimit( limit );
+               textInputWidget.$input.byteLimit( limit, filterFunction );
        };
 
        /**
         * Uses jQuery#codePointLimit to enforce the limit.
         *
         * @param {OO.ui.TextInputWidget} textInputWidget Text input widget
-        * @param {number} [limit] Byte limit, defaults to $input's maxlength
+        * @param {number} [limit] Code point limit, defaults to $input's maxlength
+        * @param {Function} [filterFunction] Function to call on the string before assessing the length.
         */
-       mw.widgets.visibleCodePointLimit = function ( textInputWidget, limit ) {
+       mw.widgets.visibleCodePointLimit = function ( textInputWidget, limit, filterFunction ) {
                limit = limit || +textInputWidget.$input.attr( 'maxlength' );
+               if ( !filterFunction || typeof filterFunction !== 'function' ) {
+                       filterFunction = undefined;
+               }
 
                function updateCount() {
-                       var remaining = limit - codePointLength( textInputWidget.getValue() );
+                       var value = textInputWidget.getValue(),
+                               remaining;
+                       if ( filterFunction ) {
+                               value = filterFunction( value );
+                       }
+                       remaining = limit - codePointLength( value );
                        if ( remaining > 99 ) {
                                remaining = '';
                        } else {
@@ -60,7 +78,7 @@
                updateCount();
 
                // Actually enforce limit
-               textInputWidget.$input.codePointLimit( limit );
+               textInputWidget.$input.codePointLimit( limit, filterFunction );
        };
 
 }() );
index aaa5da5..e8ac592 100644 (file)
 
                this.calculateSizing( this.data );
 
-               // Get wiki default thumbnail size
-               this.defaultThumbSize = mw.config.get( 'wgVisualEditorConfig' )
-                       .defaultUserOptions.defaultthumbsize;
-
                // Initialization
                this.setLabel( new mw.Title( this.data.title ).getNameText() );
                this.$label.addClass( 'mw-widget-mediaResultWidget-nameLabel' );
diff --git a/resources/src/mediawiki.widgets/images/page-disambiguation-ltr.svg b/resources/src/mediawiki.widgets/images/page-disambiguation-ltr.svg
deleted file mode 100644 (file)
index 0786048..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
-       <path d="M5 3v14.25C5 19.208 6.582 21 8.502 21H19V3zm8.002 3h4v4l-1.281-1.281L12.44 12l3.281 3.281L17.002 14v4h-4l1.313-1.313L10.596 13H7.002v-2h3.594l3.688-3.719z"/>
-</svg>
diff --git a/resources/src/mediawiki.widgets/images/page-disambiguation-rtl.svg b/resources/src/mediawiki.widgets/images/page-disambiguation-rtl.svg
deleted file mode 100644 (file)
index 753c9d5..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
-       <path d="M19 3v14.25c0 1.958-1.582 3.75-3.502 3.75H5V3zm-8.002 3h-4v4l1.281-1.281L11.56 12l-3.28 3.281L6.998 14v4h4l-1.313-1.313L13.404 13h3.594v-2h-3.594L9.716 7.281z"/>
-</svg>
diff --git a/resources/src/mediawiki.widgets/images/page-existing-ltr.svg b/resources/src/mediawiki.widgets/images/page-existing-ltr.svg
deleted file mode 100644 (file)
index 011a171..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
-       <path d="M12 12h5V5h-5zm-5 3v1h10v-1m0-1v-1H7v1m0 4h10v-1H7zm4-11H7v1h4zm0 3V9H7v1m0 1v1h4v-1m0-6H7v1h4zM5 3h14v18H8.692C6.602 21 5 19.373 5 17.25z"/>
-</svg>
diff --git a/resources/src/mediawiki.widgets/images/page-existing-rtl.svg b/resources/src/mediawiki.widgets/images/page-existing-rtl.svg
deleted file mode 100644 (file)
index db4ad43..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
-       <path d="M12 12H7V5h5zm5 3v1H7v-1m0-1v-1h10v1m0 4H7v-1h10zM13 7h4v1h-4zm0 3V9h4v1m0 1v1h-4v-1m0-6h4v1h-4zm6-2H5v18h10.308C17.398 21 19 19.373 19 17.25z"/>
-</svg>
diff --git a/resources/src/mediawiki.widgets/images/page-not-found-he-yi.svg b/resources/src/mediawiki.widgets/images/page-not-found-he-yi.svg
deleted file mode 100644 (file)
index d8c68a9..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
-       <path d="M5 3v18h10c2 0 4-2 4-4V3zm7.644 13.572h-1.687v-1.6h1.687zm1.982-6a2.144 2.144 0 0 1-.25.563c-.104.16-.225.3-.36.423l-.402.364-.438.396c-.134.127-.25.273-.353.428-.103.16-.18.346-.233.555-.054.215-.08.474-.08.784h-1.36c0-.378.017-.696.057-.955.036-.26.098-.488.183-.688.085-.196.188-.37.31-.52.12-.15.267-.295.433-.44l.385-.332c.12-.105.233-.214.327-.34.098-.124.17-.265.228-.42a1.67 1.67 0 0 0 .08-.55c0-.256-.044-.48-.133-.66a1.397 1.397 0 0 0-.322-.442 1.35 1.35 0 0 0-.403-.246 1.17 1.17 0 0 0-.376-.077c-.52 0-.905.173-1.15.52-.247.345-.372.81-.372 1.39H8.962c0-.468.067-.895.206-1.282a2.641 2.641 0 0 1 1.561-1.619c.37-.15.79-.223 1.252-.223.385 0 .743.06 1.078.174.33.114.622.282.868.5.246.218.443.487.586.814.143.323.215.692.215 1.1-.01.306-.04.565-.104.784z"/>
-</svg>
diff --git a/resources/src/mediawiki.widgets/images/page-not-found-ltr.svg b/resources/src/mediawiki.widgets/images/page-not-found-ltr.svg
deleted file mode 100644 (file)
index bea394a..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
-       <path d="M5 3v14c0 2.125 1.911 4 4 4h10V3zm7.644 13.572h-1.687v-1.601h1.687zm1.982-6.001a2.106 2.106 0 0 1-.609.987l-.403.364-.438.396a2.422 2.422 0 0 0-.353.428 1.881 1.881 0 0 0-.233.555 3.236 3.236 0 0 0-.081.783h-1.36c0-.378.018-.696.058-.955a2.7 2.7 0 0 1 .183-.687c.085-.196.188-.369.309-.519a3.59 3.59 0 0 1 .434-.441l.385-.332a2.15 2.15 0 0 0 .327-.341c.098-.123.17-.264.228-.419.054-.155.081-.337.081-.551a1.5 1.5 0 0 0-.134-.66 1.388 1.388 0 0 0-.322-.441 1.35 1.35 0 0 0-.403-.246 1.17 1.17 0 0 0-.376-.077c-.519 0-.904.173-1.15.519-.246.346-.371.81-.371 1.392H8.962c0-.469.067-.896.206-1.283a2.641 2.641 0 0 1 1.561-1.619 3.33 3.33 0 0 1 1.253-.223c.385 0 .743.059 1.078.173.331.114.622.282.868.5.246.218.443.487.586.814a2.7 2.7 0 0 1 .215 1.101c-.009.305-.04.564-.103.783z"/>
-</svg>
diff --git a/resources/src/mediawiki.widgets/images/page-not-found-rtl.svg b/resources/src/mediawiki.widgets/images/page-not-found-rtl.svg
deleted file mode 100644 (file)
index bb6f316..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
-       <path d="M19 3v14c0 2.125-1.911 4-4 4H5V3zm-7.644 13.572h1.687v-1.601h-1.687zm-1.982-6.001a2.106 2.106 0 0 0 .609.987l.403.364.438.396c.134.127.251.273.353.428.103.159.179.346.233.555.054.214.081.473.081.783h1.36c0-.378-.018-.696-.058-.955a2.7 2.7 0 0 0-.183-.687 2.242 2.242 0 0 0-.309-.519 3.59 3.59 0 0 0-.434-.441l-.385-.332a2.15 2.15 0 0 1-.327-.341 1.513 1.513 0 0 1-.228-.419 1.671 1.671 0 0 1-.081-.551 1.5 1.5 0 0 1 .134-.66c.089-.182.197-.332.322-.441a1.35 1.35 0 0 1 .403-.246 1.17 1.17 0 0 1 .376-.077c.519 0 .904.173 1.15.519.246.346.371.81.371 1.392h1.436a3.77 3.77 0 0 0-.206-1.283 2.641 2.641 0 0 0-1.561-1.619 3.33 3.33 0 0 0-1.253-.223c-.385 0-.743.059-1.078.173a2.548 2.548 0 0 0-.868.5 2.304 2.304 0 0 0-.586.814 2.7 2.7 0 0 0-.215 1.101c.009.305.04.564.103.783z"/>
-</svg>
diff --git a/resources/src/mediawiki.widgets/images/page-redirect-ltr.svg b/resources/src/mediawiki.widgets/images/page-redirect-ltr.svg
deleted file mode 100644 (file)
index f296ac5..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
-       <path d="M5 3v14c0 2.552 1.516 4 4 4h10V3H5zm9.375 3.781c1.384 0 2.655 1.208 2.781 2.625 0 .838-.373 1.546-.937 2.125l-1.657 1.688c-.438.517-1.12.812-1.874.812-1.133 0-1.903-.69-2.407-1.656l.813-.844c.312.709.776 1.281 1.656 1.281.378 0 .873-.178 1.125-.437l1.656-1.688a1.65 1.65 0 0 0 0-2.312c-.312-.258-.778-.469-1.156-.469-.755 0-1.247.577-1.75 1.094-.312-.13-.625-.156-.938-.156-.186 0-.374.031-.5.031.942-.905 1.869-2.094 3.188-2.094zm-3.281 2.782c1.132 0 1.903.72 2.406 1.687l-.813.813c-.312-.647-.744-1.282-1.624-1.282-.378 0-.874.21-1.126.469l-1.656 1.656c-.629.58-.629 1.666 0 2.313.312.258.748.469 1.125.469.378 0 .874-.21 1.125-.47l.563-.593c.251.13.5.156.812.156.187 0 .376 0 .563-.062l-1.156 1.219c-.942 1.096-2.712 1.033-3.72 0-1.067-1.034-1.067-2.775 0-3.876l1.626-1.656a2.454 2.454 0 0 1 1.875-.844z"/>
-</svg>
diff --git a/resources/src/mediawiki.widgets/images/page-redirect-rtl.svg b/resources/src/mediawiki.widgets/images/page-redirect-rtl.svg
deleted file mode 100644 (file)
index 6c753d6..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
-       <path d="M19 3v14c0 2.552-1.516 4-4 4H5V3h14zM9.625 6.781c-1.384 0-2.655 1.208-2.781 2.625 0 .838.373 1.546.937 2.125l1.657 1.688c.438.517 1.12.812 1.874.812 1.133 0 1.903-.69 2.407-1.656l-.813-.844c-.312.709-.776 1.281-1.656 1.281-.378 0-.873-.178-1.125-.437l-1.656-1.688a1.652 1.652 0 0 1 0-2.312c.312-.258.778-.469 1.156-.469.755 0 1.247.577 1.75 1.094.312-.13.625-.156.938-.156.186 0 .374.031.5.031-.942-.905-1.869-2.094-3.188-2.094zm3.281 2.782c-1.132 0-1.903.72-2.406 1.687l.813.813c.312-.647.744-1.282 1.624-1.282.378 0 .874.21 1.126.469l1.656 1.656c.629.58.629 1.666 0 2.313-.312.258-.748.469-1.125.469-.378 0-.874-.21-1.125-.47l-.563-.593c-.251.13-.5.156-.812.156-.187 0-.376 0-.563-.062l1.156 1.219c.942 1.096 2.712 1.033 3.72 0 1.067-1.034 1.067-2.775 0-3.876l-1.626-1.656a2.454 2.454 0 0 0-1.875-.844z"/>
-</svg>
index 3a71760..c25db2f 100644 (file)
                        focusout: this.onBlur.bind( this )
                } );
                this.calendar.$element.on( {
+                       focusout: this.onBlur.bind( this ),
                        click: this.onCalendarClick.bind( this ),
                        keypress: this.onCalendarKeyPress.bind( this )
                } );
index 3758bd7..647c983 100644 (file)
 .mw-widget-dateInputWidget {
        &.oo-ui-textInputWidget {
                display: inline-block;
-               position: relative;
-               width: 21em;
-               margin-top: 0.25em;
+               max-width: 21em;
                // .oo-ui-inline-spacing( 0.5em ); already inherited from `.oo-ui-inputWidget`
-               margin-bottom: 0.25em;
-               margin-left: 0;
+
+               .oo-ui-labelElement-label {
+                       line-height: @line-height-widget-singleline;
+               }
        }
 
        // Note that this block applies to both the PHP widget and the JS widget
index 818ad89..6a87583 100644 (file)
@@ -14,8 +14,6 @@
         *
         * @constructor
         * @param {Object} [config] Configuration options
-        * @cfg {boolean} [pushPending=false] Visually mark the input field as "pending", while
-        *  requesting suggestions.
         * @cfg {boolean} [performSearchOnClick=true] If true, the script will start a search when-
         *  ever a user hits a suggestion. If false, the text of the suggestion is inserted into the
         *  text field only.
@@ -32,6 +30,7 @@
                config = $.extend( {
                        icon: 'search',
                        maxLength: undefined,
+                       showPendingRequest: false,
                        performSearchOnClick: true,
                        dataLocation: 'header'
                }, config );
@@ -43,9 +42,6 @@
                this.$element.addClass( 'mw-widget-searchInputWidget' );
                this.lookupMenu.$element.addClass( 'mw-widget-searchWidget-menu' );
                this.lastLookupItems = [];
-               if ( !config.pushPending ) {
-                       this.pushPending = false;
-               }
                if ( config.dataLocation ) {
                        this.dataLocation = config.dataLocation;
                }
index 661f9ae..a5b71b9 100644 (file)
                if ( !config.showImages ) {
                        icon = null;
                } else if ( config.missing ) {
-                       icon = 'page-not-found';
+                       icon = 'articleNotFound';
                } else if ( config.redirect ) {
-                       icon = 'page-redirect';
+                       icon = 'articleRedirect';
                } else if ( config.disambiguation ) {
-                       icon = 'page-disambiguation';
+                       icon = 'articleDisambiguation';
                } else {
-                       icon = 'page-existing';
+                       icon = 'article';
                }
 
                // Config initialization
index 6f4c72c..22bac08 100644 (file)
@@ -24,6 +24,7 @@
         * @cfg {boolean} [showImages] Show page images
         * @cfg {boolean} [showDescriptions] Show page descriptions
         * @cfg {boolean} [showMissing=true] Show missing pages
+        * @cfg {boolean} [showInterwikis=false] Show pages with a valid interwiki prefix
         * @cfg {boolean} [addQueryInput=true] Add exact user's input query to results
         * @cfg {boolean} [excludeCurrentPage] Exclude the current page from suggestions
         * @cfg {boolean} [excludeDynamicNamespaces] Exclude pages whose namespace is negative
@@ -50,6 +51,7 @@
                this.showImages = !!config.showImages;
                this.showDescriptions = !!config.showDescriptions;
                this.showMissing = config.showMissing !== false;
+               this.showInterwikis = !!config.showInterwikis;
                this.addQueryInput = config.addQueryInput !== false;
                this.excludeCurrentPage = !!config.excludeCurrentPage;
                this.excludeDynamicNamespaces = !!config.excludeDynamicNamespaces;
        };
 
        mw.widgets.TitleWidget.prototype.getInterwikiPrefixesPromise = function () {
-               var api = this.getApi(),
-                       cache = this.constructor.static.interwikiPrefixesPromiseCache,
-                       key = api.defaults.ajax.url;
+               var api, cache, key;
+
+               if ( !this.showInterwikis ) {
+                       return $.Deferred().resolve( [] ).promise();
+               }
+
+               api = this.getApi();
+               cache = this.constructor.static.interwikiPrefixesPromiseCache;
+               key = api.defaults.ajax.url;
+
                if ( !Object.prototype.hasOwnProperty.call( cache, key ) ) {
                        cache[ key ] = api.get( {
                                action: 'query',
                }
 
                return this.getInterwikiPrefixesPromise().then( function ( interwikiPrefixes ) {
-                       var interwiki = query.substring( 0, query.indexOf( ':' ) );
-                       if (
-                               interwiki && interwiki !== '' &&
-                               interwikiPrefixes.indexOf( interwiki ) !== -1
-                       ) {
-                               return $.Deferred().resolve( { query: {
-                                       pages: [ {
-                                               title: query
-                                       } ]
-                               } } ).promise( promiseAbortObject );
-                       } else {
-                               req = api.get( widget.getApiParams( query ) );
-                               promiseAbortObject.abort = req.abort.bind( req ); // TODO ew
-                               return req.then( function ( ret ) {
-                                       if ( widget.showMissing && ret.query === undefined ) {
-                                               ret = api.get( { action: 'query', titles: query } );
-                                               promiseAbortObject.abort = ret.abort.bind( ret );
-                                       }
-                                       return ret;
-                               } );
+                       var interwiki;
+                       // Optimization: check we have any prefixes.
+                       if ( interwikiPrefixes.length ) {
+                               interwiki = query.substring( 0, query.indexOf( ':' ) );
+                               if (
+                                       interwiki && interwiki !== '' &&
+                                       interwikiPrefixes.indexOf( interwiki ) !== -1
+                               ) {
+                                       // Interwiki prefix is valid: return the original query as a valid title
+                                       // NB: This doesn't check if the title actually exists on the other wiki
+                                       return $.Deferred().resolve( { query: {
+                                               pages: [ {
+                                                       title: query
+                                               } ]
+                                       } } ).promise( promiseAbortObject );
+                               }
                        }
+                       // Not a interwiki: do an API lookup of the query
+                       req = api.get( widget.getApiParams( query ) );
+                       promiseAbortObject.abort = req.abort.bind( req ); // TODO ew
+                       return req.then( function ( ret ) {
+                               if ( widget.showMissing && ret.query === undefined ) {
+                                       ret = api.get( { action: 'query', titles: query } );
+                                       promiseAbortObject.abort = ret.abort.bind( ret );
+                               }
+                               return ret;
+                       } );
                } ).promise( promiseAbortObject );
        };
 
index e52d0cd..f087dcf 100644 (file)
@@ -39,6 +39,7 @@
                                        left: 0;
 
                                        &:not( .mw-widget-titleOptionWidget-hasImage ) {
+                                               background-size: 80%;
                                                background-color: #c8ccd1;
                                                opacity: 0.4;
                                        }
                }
        }
 }
-
-/* Icons */
-
-.oo-ui-icon-page-disambiguation {
-       /* @embed */
-       background-image: url( images/page-disambiguation-ltr.svg );
-}
-
-.oo-ui-icon-page-existing {
-       /* @embed */
-       background-image: url( images/page-existing-ltr.svg );
-}
-
-.oo-ui-icon-page-not-found {
-       /* @embed */
-       background-image: url( images/page-not-found-ltr.svg );
-}
-
-.oo-ui-icon-page-not-found:lang( he ) {
-       /* @embed */
-       background-image: url( images/page-not-found-he-yi.svg );
-}
-
-.oo-ui-icon-page-redirect {
-       /* @embed */
-       background-image: url( images/page-redirect-ltr.svg );
-}
index 5c574a2..4b65ed5 100644 (file)
                         *             'dependencies': ['required.foo', 'bar.also', ...]
                         *             'group': 'somegroup', (or) null
                         *             'source': 'local', (or) 'anotherwiki'
-                        *             'skip': 'return !!window.Example', (or) null
+                        *             'skip': 'return !!window.Example', (or) null, (or) boolean result of skip
                         *             'module': export Object
                         *
                         *             // Set from execute() or mw.loader.state()
                         *             'state': 'registered', 'loaded', 'loading', 'ready', 'error', or 'missing'
                         *
                         *             // Optionally added at run-time by mw.loader.implement()
-                        *             'skipped': true
                         *             'script': closure, array of urls, or string
                         *             'style': { ... } (see #execute)
                         *             'messages': { 'key': 'value', ... }
 
                        /**
                         * @private
-                        * @param {Array} modules List of module names
+                        * @param {string[]} modules List of module names
                         * @return {string} Hash of concatenated version hashes.
                         */
                        function getCombinedVersion( modules ) {
                         * execute the module or job now.
                         *
                         * @private
-                        * @param {Array} modules Names of modules to be checked
+                        * @param {string[]} modules Names of modules to be checked
                         * @return {boolean} True if all modules are in state 'ready', false otherwise
                         */
                        function allReady( modules ) {
                         *  dependencies, such that later modules depend on earlier modules. The array
                         *  contains the module names. If the array contains already some module names,
                         *  this function appends its result to the pre-existing array.
-                        * @param {StringSet} [unresolved] Used to track the current dependency
-                        *  chain, and to report loops in the dependency graph.
-                        * @throws {Error} If any unregistered module or a dependency loop is encountered
+                        * @param {StringSet} [unresolved] Used to detect loops in the dependency graph.
+                        * @throws {Error} If an unknown module or a circular dependency is encountered
                         */
                        function sortDependencies( module, resolved, unresolved ) {
-                               var i, deps, skip;
+                               var i, skip, deps;
 
                                if ( !( module in registry ) ) {
-                                       throw new Error( 'Unknown dependency: ' + module );
+                                       throw new Error( 'Unknown module: ' + module );
                                }
 
-                               if ( registry[ module ].skip !== null ) {
+                               if ( typeof registry[ module ].skip === 'string' ) {
                                        // eslint-disable-next-line no-new-func
-                                       skip = new Function( registry[ module ].skip );
-                                       registry[ module ].skip = null;
-                                       if ( skip() ) {
-                                               registry[ module ].skipped = true;
+                                       skip = ( new Function( registry[ module ].skip )() );
+                                       registry[ module ].skip = !!skip;
+                                       if ( skip ) {
                                                registry[ module ].dependencies = [];
                                                setAndPropagate( module, 'ready' );
                                                return;
                                        }
                                }
 
-                               if ( resolved.indexOf( module ) !== -1 ) {
-                                       // Module already resolved; nothing to do
-                                       return;
-                               }
                                // Create unresolved if not passed in
                                if ( !unresolved ) {
                                        unresolved = new StringSet();
                                }
 
-                               // Add base modules
-                               if ( baseModules.indexOf( module ) === -1 ) {
-                                       for ( i = 0; i < baseModules.length; i++ ) {
-                                               if ( resolved.indexOf( baseModules[ i ] ) === -1 ) {
-                                                       resolved.push( baseModules[ i ] );
-                                               }
-                                       }
-                               }
-
-                               // Tracks down dependencies
+                               // Track down dependencies
                                deps = registry[ module ].dependencies;
                                unresolved.add( module );
                                for ( i = 0; i < deps.length; i++ ) {
                                                sortDependencies( deps[ i ], resolved, unresolved );
                                        }
                                }
+
                                resolved.push( module );
                        }
 
                         * @throws {Error} If an unregistered module or a dependency loop is encountered
                         */
                        function resolve( modules ) {
-                               var resolved = [],
+                               // Always load base modules
+                               var resolved = baseModules.slice(),
                                        i = 0;
                                for ( ; i < modules.length; i++ ) {
                                        sortDependencies( modules[ i ], resolved );
                         */
                        function resolveStubbornly( modules ) {
                                var saved,
-                                       resolved = [],
+                                       // Always load base modules
+                                       resolved = baseModules.slice(),
                                        i = 0;
                                for ( ; i < modules.length; i++ ) {
                                        saved = resolved.slice();
                         * Utility function for execute()
                         *
                         * @ignore
-                        * @param {string} [media] Media attribute
                         * @param {string} url URL
+                        * @param {string} [media] Media attribute
+                        * @param {Node|null} [nextNode]
                         */
-                       function addLink( media, url ) {
+                       function addLink( url, media, nextNode ) {
                                var el = document.createElement( 'link' );
 
                                el.rel = 'stylesheet';
                                // see #addEmbeddedCSS, T33676, T43331, and T49277 for details.
                                el.href = url;
 
-                               if ( marker && marker.parentNode ) {
-                                       marker.parentNode.insertBefore( el, marker );
+                               if ( nextNode && nextNode.parentNode ) {
+                                       nextNode.parentNode.insertBefore( el, nextNode );
                                } else {
                                        document.head.appendChild( el );
                                }
                                                        for ( i = 0; i < value.length; i++ ) {
                                                                if ( key === 'bc-url' ) {
                                                                        // back-compat: { <media>: [url, ..] }
-                                                                       addLink( media, value[ i ] );
+                                                                       addLink( value[ i ], media, marker );
                                                                } else if ( key === 'css' ) {
                                                                        // { "css": [css, ..] }
                                                                        addEmbeddedCSS( value[ i ], cssHandle() );
                                                        for ( media in value ) {
                                                                urls = value[ media ];
                                                                for ( i = 0; i < urls.length; i++ ) {
-                                                                       addLink( media, urls[ i ] );
+                                                                       addLink( urls[ i ], media, marker );
                                                                }
                                                        }
                                                }
                         * to a query string of the form `foo.bar,baz|bar.baz,quux`.
                         *
                         * See `ResourceLoader::makePackedModulesString()` in PHP, of which this is a port.
-                        * On the server, unpacking is done by `ResourceLoaderContext::expandModuleNames()`.
+                        * On the server, unpacking is done by `ResourceLoader::expandModuleNames()`.
                         *
                         * Note: This is only half of the logic, the other half has to be in #batchRequest(),
                         * because its implementation needs to keep track of potential string size in order
                                 *  "text/javascript"; if no type is provided, text/javascript is assumed.
                                 */
                                load: function ( modules, type ) {
-                                       var filtered, l;
-
-                                       // Allow calling with a url or single dependency as a string
-                                       if ( typeof modules === 'string' ) {
-                                               // "https://example.org/x.js", "http://example.org/x.js", "//example.org/x.js", "/x.js"
-                                               if ( /^(https?:)?\/?\//.test( modules ) ) {
-                                                       if ( type === 'text/css' ) {
-                                                               l = document.createElement( 'link' );
-                                                               l.rel = 'stylesheet';
-                                                               l.href = modules;
-                                                               document.head.appendChild( l );
-                                                               return;
-                                                       }
-                                                       if ( type === 'text/javascript' || type === undefined ) {
-                                                               addScript( modules );
-                                                               return;
-                                                       }
+                                       if ( typeof modules === 'string' && /^(https?:)?\/?\//.test( modules ) ) {
+                                               // Called with a url like so:
+                                               // - "https://example.org/x.js"
+                                               // - "http://example.org/x.js"
+                                               // - "//example.org/x.js"
+                                               // - "/x.js"
+                                               if ( type === 'text/css' ) {
+                                                       addLink( modules );
+                                               } else if ( type === 'text/javascript' || type === undefined ) {
+                                                       addScript( modules );
+                                               } else {
                                                        // Unknown type
                                                        throw new Error( 'type must be text/css or text/javascript, found ' + type );
                                                }
-                                               // Called with single module
-                                               modules = [ modules ];
+                                       } else {
+                                               // One or more modules
+                                               modules = typeof modules === 'string' ? [ modules ] : modules;
+                                               // Resolve modules into flat list for internal queuing.
+                                               // This also filters out unknown modules and modules with
+                                               // unknown dependencies, allowing the rest to continue. (T36853)
+                                               enqueue( resolveStubbornly( modules ), undefined, undefined );
                                        }
-
-                                       // Filter out top-level modules that are unknown or failed to load before.
-                                       filtered = modules.filter( function ( module ) {
-                                               var state = mw.loader.getState( module );
-                                               return state !== 'error' && state !== 'missing';
-                                       } );
-                                       // Resolve remaining list using the known dependency tree.
-                                       // This also filters out modules with unknown dependencies. (T36853)
-                                       filtered = resolveStubbornly( filtered );
-                                       // Some modules are not yet ready, add to module load queue.
-                                       enqueue( filtered, undefined, undefined );
                                },
 
                                /**
index bebf4dc..c251a86 100644 (file)
@@ -3,8 +3,8 @@
  *
  * - Beware: This file MUST parse without errors on even the most ancient of browsers!
  */
-/* eslint-disable no-implicit-globals, vars-on-top, no-unmodified-loop-condition */
-/* global $VARS, $CODE */
+/* eslint-disable no-implicit-globals */
+/* global $VARS, $CODE, RLQ:true, NORLQ:true */
 
 /**
  * See <https://www.mediawiki.org/wiki/Compatibility#Browsers>
  *
  * Other browsers that pass the check are considered Grade X.
  *
- * @param {string} [str] User agent, defaults to navigator.userAgent
+ * @private
+ * @param {string} ua User agent string
  * @return {boolean} User agent is compatible with MediaWiki JS
  */
-function isCompatible( str ) {
-       var ua = str || navigator.userAgent;
+function isCompatible( ua ) {
        return !!(
                // https://caniuse.com/#feat=es5
                // https://caniuse.com/#feat=use-strict
@@ -69,31 +69,33 @@ function isCompatible( str ) {
                // https://caniuse.com/#feat=addeventlistener
                'addEventListener' in window &&
 
-               // Hardcoded exceptions for browsers that pass the requirement but we don't want to
-               // support in the modern run-time.
-               // Note: Please extend the regex instead of adding new ones
+               // Hardcoded exceptions for browsers that pass the requirement but we don't
+               // want to support in the modern run-time.
+               //
+               // Please extend the regex instead of adding new ones!
+               // And add a test case to startup.test.js
                !ua.match( /MSIE 10|webOS\/1\.[0-4]|SymbianOS|Series60|NetFront|Opera Mini|S40OviBrowser|MeeGo|Android.+Glass|^Mozilla\/5\.0 .+ Gecko\/$|googleweblight|PLAYSTATION|PlayStation/ )
        );
 }
 
-if ( !isCompatible() ) {
+if ( !isCompatible( navigator.userAgent ) ) {
        // Handle Grade C
        // Undo speculative Grade A <html> class. See ResourceLoaderClientHtml::getDocumentAttributes().
        document.documentElement.className = document.documentElement.className
                .replace( /(^|\s)client-js(\s|$)/, '$1client-nojs$2' );
 
        // Process any callbacks for Grade C
-       while ( window.NORLQ && window.NORLQ[ 0 ] ) {
-               window.NORLQ.shift()();
+       while ( window.NORLQ && NORLQ[ 0 ] ) {
+               NORLQ.shift()();
        }
-       window.NORLQ = {
+       NORLQ = {
                push: function ( fn ) {
                        fn();
                }
        };
 
        // Clear and disable the Grade A queue
-       window.RLQ = {
+       RLQ = {
                push: function () {}
        };
 } else {
@@ -116,29 +118,44 @@ if ( !isCompatible() ) {
                $CODE.registrations();
 
                mw.config.set( $VARS.configuration );
+               // For the current page
+               mw.config.set( window.RLCONF || {} );
+               mw.loader.state( window.RLSTATE || {} );
+               mw.loader.load( window.RLPAGEMODULES || [] );
 
-               // Process callbacks for Grade A
-               var queue = window.RLQ;
-               // Replace RLQ placeholder from ResourceLoaderClientHtml with an implementation
-               // that executes simple callbacks, but continues to store callbacks that require
-               // modules.
-               window.RLQ = [];
-               /* global RLQ */
+               // Process RLQ callbacks
+               //
+               // The code in these callbacks could've been exposed from load.php and
+               // requested client-side. Instead, they are pushed by the server directly
+               // (from ResourceLoaderClientHtml and other parts of MediaWiki). This
+               // saves the need for additional round trips. It also allows load.php
+               // to remain stateless and sending personal data in the HTML instead.
+               //
+               // The HTML inline script lazy-defines the 'RLQ' array. Now that we are
+               // processing it, replace it with an implementation where 'push' actually
+               // considers executing the code directly. This is to ensure any late
+               // arrivals will also be processed. Late arrival can happen because
+               // startup.js is executed asynchronously, concurrently with the streaming
+               // response of the HTML.
+               RLQ = window.RLQ || [];
                RLQ.push = function ( fn ) {
                        if ( typeof fn === 'function' ) {
                                fn();
                        } else {
-                               // This callback requires a module, handled in mediawiki.base.
+                               // If the first parameter is not a function, then it is an array
+                               // containing a list of required module names and a function.
+                               // Do an actual push for now, as this signature is handled
+                               // later by mediawiki.base.js.
                                RLQ[ RLQ.length ] = fn;
                        }
                };
-               while ( queue && queue[ 0 ] ) {
-                       // Re-use our new push() method
-                       RLQ.push( queue.shift() );
+               while ( RLQ[ 0 ] ) {
+                       // Process all values gathered so far
+                       RLQ.push( RLQ.shift() );
                }
 
                // Clear and disable the Grade C queue
-               window.NORLQ = {
+               NORLQ = {
                        push: function () {}
                };
        }() );
index 572e2f8..612fd96 100644 (file)
@@ -1,10 +1,12 @@
+== User Information ==
+
 Skins, such as the default skin Vector, are distributed separately. Drop them
 into this directory and enable as per the skin's installation instructions.
 
 You can find a list of available skins at
-<https://www.mediawiki.org/wiki/Category:All_skins>,
+<https://www.mediawiki.org/wiki/Special:MyLanguage/Category:All_skins>,
 and more information about installing and configuring skins at
-<https://www.mediawiki.org/wiki/Manual:Skin_configuration>.
+<https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Skin_configuration>.
 
 If you are a developer, you might want to fetch the skin tree in another
 directory and make a symbolic link:
index 680b8c3..861111a 100644 (file)
@@ -180,6 +180,7 @@ $wgAutoloadClasses += [
        'GenericArrayObjectTest' => "$testDir/phpunit/includes/libs/GenericArrayObjectTest.php",
 
        # tests/phpunit/maintenance
+       'MediaWiki\Tests\Maintenance\DumpAsserter' => "$testDir/phpunit/maintenance/DumpAsserter.php",
        'MediaWiki\Tests\Maintenance\DumpTestCase' => "$testDir/phpunit/maintenance/DumpTestCase.php",
        'MediaWiki\Tests\Maintenance\MaintenanceBaseTestCase' => "$testDir/phpunit/maintenance/MaintenanceBaseTestCase.php",
 
index c1884b8..3717c8b 100644 (file)
@@ -6,4 +6,311 @@
  */
 class CurlHttpRequestTest extends MWHttpRequestTestCase {
        protected static $httpEngine = 'curl';
+
+       /**
+        * Constant values are from PHP 5.3.28 using cURL 7.24.0
+        * @see https://www.php.net/manual/en/curl.constants.php
+        *
+        * All constant values are present so that developers don’t need to remember
+        * to add them if added at a later date. The commented out constants were
+        * not found anywhere in the MediaWiki core code.
+        *
+        * Commented out constants that were not available in:
+        * HipHop VM 3.3.0 (rel)
+        * Compiler: heads/master-0-g08810d920dfff59e0774cf2d651f92f13a637175
+        * Repo schema: 3214fc2c684a4520485f715ee45f33f2182324b1
+        * Extension API: 20140829
+        *
+        * Commented out constants that were removed in PHP 5.6.0
+        */
+       public function provideCurlConstants() {
+               return [
+                       [ 'CURLAUTH_ANY' ],
+                       [ 'CURLAUTH_ANYSAFE' ],
+                       [ 'CURLAUTH_BASIC' ],
+                       [ 'CURLAUTH_DIGEST' ],
+                       [ 'CURLAUTH_GSSNEGOTIATE' ],
+                       [ 'CURLAUTH_NTLM' ],
+                       // [ 'CURLCLOSEPOLICY_CALLBACK' ], // removed in PHP 5.6.0
+                       // [ 'CURLCLOSEPOLICY_LEAST_RECENTLY_USED' ], // removed in PHP 5.6.0
+                       // [ 'CURLCLOSEPOLICY_LEAST_TRAFFIC' ], // removed in PHP 5.6.0
+                       // [ 'CURLCLOSEPOLICY_OLDEST' ], // removed in PHP 5.6.0
+                       // [ 'CURLCLOSEPOLICY_SLOWEST' ], // removed in PHP 5.6.0
+                       [ 'CURLE_ABORTED_BY_CALLBACK' ],
+                       [ 'CURLE_BAD_CALLING_ORDER' ],
+                       [ 'CURLE_BAD_CONTENT_ENCODING' ],
+                       [ 'CURLE_BAD_FUNCTION_ARGUMENT' ],
+                       [ 'CURLE_BAD_PASSWORD_ENTERED' ],
+                       [ 'CURLE_COULDNT_CONNECT' ],
+                       [ 'CURLE_COULDNT_RESOLVE_HOST' ],
+                       [ 'CURLE_COULDNT_RESOLVE_PROXY' ],
+                       [ 'CURLE_FAILED_INIT' ],
+                       [ 'CURLE_FILESIZE_EXCEEDED' ],
+                       [ 'CURLE_FILE_COULDNT_READ_FILE' ],
+                       [ 'CURLE_FTP_ACCESS_DENIED' ],
+                       [ 'CURLE_FTP_BAD_DOWNLOAD_RESUME' ],
+                       [ 'CURLE_FTP_CANT_GET_HOST' ],
+                       [ 'CURLE_FTP_CANT_RECONNECT' ],
+                       [ 'CURLE_FTP_COULDNT_GET_SIZE' ],
+                       [ 'CURLE_FTP_COULDNT_RETR_FILE' ],
+                       [ 'CURLE_FTP_COULDNT_SET_ASCII' ],
+                       [ 'CURLE_FTP_COULDNT_SET_BINARY' ],
+                       [ 'CURLE_FTP_COULDNT_STOR_FILE' ],
+                       [ 'CURLE_FTP_COULDNT_USE_REST' ],
+                       [ 'CURLE_FTP_PORT_FAILED' ],
+                       [ 'CURLE_FTP_QUOTE_ERROR' ],
+                       [ 'CURLE_FTP_SSL_FAILED' ],
+                       [ 'CURLE_FTP_USER_PASSWORD_INCORRECT' ],
+                       [ 'CURLE_FTP_WEIRD_227_FORMAT' ],
+                       [ 'CURLE_FTP_WEIRD_PASS_REPLY' ],
+                       [ 'CURLE_FTP_WEIRD_PASV_REPLY' ],
+                       [ 'CURLE_FTP_WEIRD_SERVER_REPLY' ],
+                       [ 'CURLE_FTP_WEIRD_USER_REPLY' ],
+                       [ 'CURLE_FTP_WRITE_ERROR' ],
+                       [ 'CURLE_FUNCTION_NOT_FOUND' ],
+                       [ 'CURLE_GOT_NOTHING' ],
+                       [ 'CURLE_HTTP_NOT_FOUND' ],
+                       [ 'CURLE_HTTP_PORT_FAILED' ],
+                       [ 'CURLE_HTTP_POST_ERROR' ],
+                       [ 'CURLE_HTTP_RANGE_ERROR' ],
+                       [ 'CURLE_LDAP_CANNOT_BIND' ],
+                       [ 'CURLE_LDAP_INVALID_URL' ],
+                       [ 'CURLE_LDAP_SEARCH_FAILED' ],
+                       [ 'CURLE_LIBRARY_NOT_FOUND' ],
+                       [ 'CURLE_MALFORMAT_USER' ],
+                       [ 'CURLE_OBSOLETE' ],
+                       [ 'CURLE_OK' ],
+                       [ 'CURLE_OPERATION_TIMEOUTED' ],
+                       [ 'CURLE_OUT_OF_MEMORY' ],
+                       [ 'CURLE_PARTIAL_FILE' ],
+                       [ 'CURLE_READ_ERROR' ],
+                       [ 'CURLE_RECV_ERROR' ],
+                       [ 'CURLE_SEND_ERROR' ],
+                       [ 'CURLE_SHARE_IN_USE' ],
+                       // [ 'CURLE_SSH' ], // not present in HHVM 3.3.0-dev
+                       [ 'CURLE_SSL_CACERT' ],
+                       [ 'CURLE_SSL_CERTPROBLEM' ],
+                       [ 'CURLE_SSL_CIPHER' ],
+                       [ 'CURLE_SSL_CONNECT_ERROR' ],
+                       [ 'CURLE_SSL_ENGINE_NOTFOUND' ],
+                       [ 'CURLE_SSL_ENGINE_SETFAILED' ],
+                       [ 'CURLE_SSL_PEER_CERTIFICATE' ],
+                       [ 'CURLE_TELNET_OPTION_SYNTAX' ],
+                       [ 'CURLE_TOO_MANY_REDIRECTS' ],
+                       [ 'CURLE_UNKNOWN_TELNET_OPTION' ],
+                       [ 'CURLE_UNSUPPORTED_PROTOCOL' ],
+                       [ 'CURLE_URL_MALFORMAT' ],
+                       [ 'CURLE_URL_MALFORMAT_USER' ],
+                       [ 'CURLE_WRITE_ERROR' ],
+                       [ 'CURLFTPAUTH_DEFAULT' ],
+                       [ 'CURLFTPAUTH_SSL' ],
+                       [ 'CURLFTPAUTH_TLS' ],
+                       // [ 'CURLFTPMETHOD_MULTICWD' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLFTPMETHOD_NOCWD' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLFTPMETHOD_SINGLECWD' ], // not present in HHVM 3.3.0-dev
+                       [ 'CURLFTPSSL_ALL' ],
+                       [ 'CURLFTPSSL_CONTROL' ],
+                       [ 'CURLFTPSSL_NONE' ],
+                       [ 'CURLFTPSSL_TRY' ],
+                       // [ 'CURLINFO_CERTINFO' ], // not present in HHVM 3.3.0-dev
+                       [ 'CURLINFO_CONNECT_TIME' ],
+                       [ 'CURLINFO_CONTENT_LENGTH_DOWNLOAD' ],
+                       [ 'CURLINFO_CONTENT_LENGTH_UPLOAD' ],
+                       [ 'CURLINFO_CONTENT_TYPE' ],
+                       [ 'CURLINFO_EFFECTIVE_URL' ],
+                       [ 'CURLINFO_FILETIME' ],
+                       [ 'CURLINFO_HEADER_OUT' ],
+                       [ 'CURLINFO_HEADER_SIZE' ],
+                       [ 'CURLINFO_HTTP_CODE' ],
+                       [ 'CURLINFO_NAMELOOKUP_TIME' ],
+                       [ 'CURLINFO_PRETRANSFER_TIME' ],
+                       [ 'CURLINFO_PRIVATE' ],
+                       [ 'CURLINFO_REDIRECT_COUNT' ],
+                       [ 'CURLINFO_REDIRECT_TIME' ],
+                       // [ 'CURLINFO_REDIRECT_URL' ], // not present in HHVM 3.3.0-dev
+                       [ 'CURLINFO_REQUEST_SIZE' ],
+                       [ 'CURLINFO_SIZE_DOWNLOAD' ],
+                       [ 'CURLINFO_SIZE_UPLOAD' ],
+                       [ 'CURLINFO_SPEED_DOWNLOAD' ],
+                       [ 'CURLINFO_SPEED_UPLOAD' ],
+                       [ 'CURLINFO_SSL_VERIFYRESULT' ],
+                       [ 'CURLINFO_STARTTRANSFER_TIME' ],
+                       [ 'CURLINFO_TOTAL_TIME' ],
+                       [ 'CURLMSG_DONE' ],
+                       [ 'CURLM_BAD_EASY_HANDLE' ],
+                       [ 'CURLM_BAD_HANDLE' ],
+                       [ 'CURLM_CALL_MULTI_PERFORM' ],
+                       [ 'CURLM_INTERNAL_ERROR' ],
+                       [ 'CURLM_OK' ],
+                       [ 'CURLM_OUT_OF_MEMORY' ],
+                       [ 'CURLOPT_AUTOREFERER' ],
+                       [ 'CURLOPT_BINARYTRANSFER' ],
+                       [ 'CURLOPT_BUFFERSIZE' ],
+                       [ 'CURLOPT_CAINFO' ],
+                       [ 'CURLOPT_CAPATH' ],
+                       // [ 'CURLOPT_CERTINFO' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLOPT_CLOSEPOLICY' ], // removed in PHP 5.6.0
+                       [ 'CURLOPT_CONNECTTIMEOUT' ],
+                       [ 'CURLOPT_CONNECTTIMEOUT_MS' ],
+                       [ 'CURLOPT_COOKIE' ],
+                       [ 'CURLOPT_COOKIEFILE' ],
+                       [ 'CURLOPT_COOKIEJAR' ],
+                       [ 'CURLOPT_COOKIESESSION' ],
+                       [ 'CURLOPT_CRLF' ],
+                       [ 'CURLOPT_CUSTOMREQUEST' ],
+                       [ 'CURLOPT_DNS_CACHE_TIMEOUT' ],
+                       [ 'CURLOPT_DNS_USE_GLOBAL_CACHE' ],
+                       [ 'CURLOPT_EGDSOCKET' ],
+                       [ 'CURLOPT_ENCODING' ],
+                       [ 'CURLOPT_FAILONERROR' ],
+                       [ 'CURLOPT_FILE' ],
+                       [ 'CURLOPT_FILETIME' ],
+                       [ 'CURLOPT_FOLLOWLOCATION' ],
+                       [ 'CURLOPT_FORBID_REUSE' ],
+                       [ 'CURLOPT_FRESH_CONNECT' ],
+                       [ 'CURLOPT_FTPAPPEND' ],
+                       [ 'CURLOPT_FTPLISTONLY' ],
+                       [ 'CURLOPT_FTPPORT' ],
+                       [ 'CURLOPT_FTPSSLAUTH' ],
+                       [ 'CURLOPT_FTP_CREATE_MISSING_DIRS' ],
+                       // [ 'CURLOPT_FTP_FILEMETHOD' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLOPT_FTP_SKIP_PASV_IP' ], // not present in HHVM 3.3.0-dev
+                       [ 'CURLOPT_FTP_SSL' ],
+                       [ 'CURLOPT_FTP_USE_EPRT' ],
+                       [ 'CURLOPT_FTP_USE_EPSV' ],
+                       [ 'CURLOPT_HEADER' ],
+                       [ 'CURLOPT_HEADERFUNCTION' ],
+                       [ 'CURLOPT_HTTP200ALIASES' ],
+                       [ 'CURLOPT_HTTPAUTH' ],
+                       [ 'CURLOPT_HTTPGET' ],
+                       [ 'CURLOPT_HTTPHEADER' ],
+                       [ 'CURLOPT_HTTPPROXYTUNNEL' ],
+                       [ 'CURLOPT_HTTP_VERSION' ],
+                       [ 'CURLOPT_INFILE' ],
+                       [ 'CURLOPT_INFILESIZE' ],
+                       [ 'CURLOPT_INTERFACE' ],
+                       [ 'CURLOPT_IPRESOLVE' ],
+                       // [ 'CURLOPT_KEYPASSWD' ], // not present in HHVM 3.3.0-dev
+                       [ 'CURLOPT_KRB4LEVEL' ],
+                       [ 'CURLOPT_LOW_SPEED_LIMIT' ],
+                       [ 'CURLOPT_LOW_SPEED_TIME' ],
+                       [ 'CURLOPT_MAXCONNECTS' ],
+                       [ 'CURLOPT_MAXREDIRS' ],
+                       // [ 'CURLOPT_MAX_RECV_SPEED_LARGE' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLOPT_MAX_SEND_SPEED_LARGE' ], // not present in HHVM 3.3.0-dev
+                       [ 'CURLOPT_NETRC' ],
+                       [ 'CURLOPT_NOBODY' ],
+                       [ 'CURLOPT_NOPROGRESS' ],
+                       [ 'CURLOPT_NOSIGNAL' ],
+                       [ 'CURLOPT_PORT' ],
+                       [ 'CURLOPT_POST' ],
+                       [ 'CURLOPT_POSTFIELDS' ],
+                       [ 'CURLOPT_POSTQUOTE' ],
+                       [ 'CURLOPT_POSTREDIR' ],
+                       [ 'CURLOPT_PRIVATE' ],
+                       [ 'CURLOPT_PROGRESSFUNCTION' ],
+                       // [ 'CURLOPT_PROTOCOLS' ], // not present in HHVM 3.3.0-dev
+                       [ 'CURLOPT_PROXY' ],
+                       [ 'CURLOPT_PROXYAUTH' ],
+                       [ 'CURLOPT_PROXYPORT' ],
+                       [ 'CURLOPT_PROXYTYPE' ],
+                       [ 'CURLOPT_PROXYUSERPWD' ],
+                       [ 'CURLOPT_PUT' ],
+                       [ 'CURLOPT_QUOTE' ],
+                       [ 'CURLOPT_RANDOM_FILE' ],
+                       [ 'CURLOPT_RANGE' ],
+                       [ 'CURLOPT_READDATA' ],
+                       [ 'CURLOPT_READFUNCTION' ],
+                       // [ 'CURLOPT_REDIR_PROTOCOLS' ], // not present in HHVM 3.3.0-dev
+                       [ 'CURLOPT_REFERER' ],
+                       [ 'CURLOPT_RESUME_FROM' ],
+                       [ 'CURLOPT_RETURNTRANSFER' ],
+                       // [ 'CURLOPT_SSH_AUTH_TYPES' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLOPT_SSH_HOST_PUBLIC_KEY_MD5' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLOPT_SSH_PRIVATE_KEYFILE' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLOPT_SSH_PUBLIC_KEYFILE' ], // not present in HHVM 3.3.0-dev
+                       [ 'CURLOPT_SSLCERT' ],
+                       [ 'CURLOPT_SSLCERTPASSWD' ],
+                       [ 'CURLOPT_SSLCERTTYPE' ],
+                       [ 'CURLOPT_SSLENGINE' ],
+                       [ 'CURLOPT_SSLENGINE_DEFAULT' ],
+                       [ 'CURLOPT_SSLKEY' ],
+                       [ 'CURLOPT_SSLKEYPASSWD' ],
+                       [ 'CURLOPT_SSLKEYTYPE' ],
+                       [ 'CURLOPT_SSLVERSION' ],
+                       [ 'CURLOPT_SSL_CIPHER_LIST' ],
+                       [ 'CURLOPT_SSL_VERIFYHOST' ],
+                       [ 'CURLOPT_SSL_VERIFYPEER' ],
+                       [ 'CURLOPT_STDERR' ],
+                       [ 'CURLOPT_TCP_NODELAY' ],
+                       [ 'CURLOPT_TIMECONDITION' ],
+                       [ 'CURLOPT_TIMEOUT' ],
+                       [ 'CURLOPT_TIMEOUT_MS' ],
+                       [ 'CURLOPT_TIMEVALUE' ],
+                       [ 'CURLOPT_TRANSFERTEXT' ],
+                       [ 'CURLOPT_UNRESTRICTED_AUTH' ],
+                       [ 'CURLOPT_UPLOAD' ],
+                       [ 'CURLOPT_URL' ],
+                       [ 'CURLOPT_USERAGENT' ],
+                       [ 'CURLOPT_USERPWD' ],
+                       [ 'CURLOPT_VERBOSE' ],
+                       [ 'CURLOPT_WRITEFUNCTION' ],
+                       [ 'CURLOPT_WRITEHEADER' ],
+                       // [ 'CURLPROTO_ALL' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLPROTO_DICT' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLPROTO_FILE' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLPROTO_FTP' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLPROTO_FTPS' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLPROTO_HTTP' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLPROTO_HTTPS' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLPROTO_LDAP' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLPROTO_LDAPS' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLPROTO_SCP' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLPROTO_SFTP' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLPROTO_TELNET' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLPROTO_TFTP' ], // not present in HHVM 3.3.0-dev
+                       [ 'CURLPROXY_HTTP' ],
+                       // [ 'CURLPROXY_SOCKS4' ], // not present in HHVM 3.3.0-dev
+                       [ 'CURLPROXY_SOCKS5' ],
+                       // [ 'CURLSSH_AUTH_DEFAULT' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLSSH_AUTH_HOST' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLSSH_AUTH_KEYBOARD' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLSSH_AUTH_NONE' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLSSH_AUTH_PASSWORD' ], // not present in HHVM 3.3.0-dev
+                       // [ 'CURLSSH_AUTH_PUBLICKEY' ], // not present in HHVM 3.3.0-dev
+                       [ 'CURLVERSION_NOW' ],
+                       [ 'CURL_HTTP_VERSION_1_0' ],
+                       [ 'CURL_HTTP_VERSION_1_1' ],
+                       [ 'CURL_HTTP_VERSION_NONE' ],
+                       [ 'CURL_IPRESOLVE_V4' ],
+                       [ 'CURL_IPRESOLVE_V6' ],
+                       [ 'CURL_IPRESOLVE_WHATEVER' ],
+                       [ 'CURL_NETRC_IGNORED' ],
+                       [ 'CURL_NETRC_OPTIONAL' ],
+                       [ 'CURL_NETRC_REQUIRED' ],
+                       [ 'CURL_TIMECOND_IFMODSINCE' ],
+                       [ 'CURL_TIMECOND_IFUNMODSINCE' ],
+                       [ 'CURL_TIMECOND_LASTMOD' ],
+                       [ 'CURL_VERSION_IPV6' ],
+                       [ 'CURL_VERSION_KERBEROS4' ],
+                       [ 'CURL_VERSION_LIBZ' ],
+                       [ 'CURL_VERSION_SSL' ],
+               ];
+       }
+
+       /**
+        * Added this test based on an issue experienced with HHVM 3.3.0-dev
+        * where it did not define a cURL constant. T72570
+        *
+        * @dataProvider provideCurlConstants
+        * @coversNothing
+        */
+       public function testCurlConstants( $value ) {
+               $loaded = extension_loaded( 'curl' );
+               if ( !$loaded ) {
+                       $this->markTestSkipped( "PHP extension 'curl' is not loaded, skipping." );
+               }
+
+               $this->assertTrue( defined( $value ), "Is $value defined?" );
+       }
 }
diff --git a/tests/integration/includes/http/MWHttpRequestTest.php b/tests/integration/includes/http/MWHttpRequestTest.php
new file mode 100644 (file)
index 0000000..5b90b78
--- /dev/null
@@ -0,0 +1,93 @@
+<?php
+
+/**
+ * @covers MWHttpRequest
+ */
+class MWHttpRequestTest extends PHPUnit\Framework\TestCase {
+
+       public function testFactory() {
+               $this->assertInstanceOf( 'MWHttpRequest', MWHttpRequest::factory( 'http://example.test' ) );
+       }
+
+       /**
+        * Feeds URI to test a long regular expression in Http::isValidURI
+        */
+       public static function provideURI() {
+               /** Format: 'boolean expectation', 'URI to test', 'Optional message' */
+               return [
+                       [ false, '¿non sens before!! http://a', 'Allow anything before URI' ],
+
+                       # (http|https) - only two schemes allowed
+                       [ true, 'http://www.example.org/' ],
+                       [ true, 'https://www.example.org/' ],
+                       [ true, 'http://www.example.org', 'URI without directory' ],
+                       [ true, 'http://a', 'Short name' ],
+                       [ true, 'http://étoile', 'Allow UTF-8 in hostname' ], # 'étoile' is french for 'star'
+                       [ false, '\\host\directory', 'CIFS share' ],
+                       [ false, 'gopher://host/dir', 'Reject gopher scheme' ],
+                       [ false, 'telnet://host', 'Reject telnet scheme' ],
+
+                       # :\/\/ - double slashes
+                       [ false, 'http//example.org', 'Reject missing colon in protocol' ],
+                       [ false, 'http:/example.org', 'Reject missing slash in protocol' ],
+                       [ false, 'http:example.org', 'Must have two slashes' ],
+                       # Following fail since hostname can be made of anything
+                       [ false, 'http:///example.org', 'Must have exactly two slashes, not three' ],
+
+                       # (\w+:{0,1}\w*@)? - optional user:pass
+                       [ true, 'http://user@host', 'Username provided' ],
+                       [ true, 'http://user:@host', 'Username provided, no password' ],
+                       [ true, 'http://user:pass@host', 'Username and password provided' ],
+
+                       # (\S+) - host part is made of anything not whitespaces
+                       // commented these out in order to remove @group Broken
+                       // @todo are these valid tests? if so, fix Http::isValidURI so it can handle them
+                       // [ false, 'http://!"èèè¿¿¿~~\'', 'hostname is made of any non whitespace' ],
+                       // [ false, 'http://exam:ple.org/', 'hostname can not use colons!' ],
+
+                       # (:[0-9]+)? - port number
+                       [ true, 'http://example.org:80/' ],
+                       [ true, 'https://example.org:80/' ],
+                       [ true, 'http://example.org:443/' ],
+                       [ true, 'https://example.org:443/' ],
+
+                       # Part after the hostname is / or / with something else
+                       [ true, 'http://example/#' ],
+                       [ true, 'http://example/!' ],
+                       [ true, 'http://example/:' ],
+                       [ true, 'http://example/.' ],
+                       [ true, 'http://example/?' ],
+                       [ true, 'http://example/+' ],
+                       [ true, 'http://example/=' ],
+                       [ true, 'http://example/&' ],
+                       [ true, 'http://example/%' ],
+                       [ true, 'http://example/@' ],
+                       [ true, 'http://example/-' ],
+                       [ true, 'http://example//' ],
+                       [ true, 'http://example/&' ],
+
+                       # Fragment
+                       [ true, 'http://exam#ple.org', ], # This one is valid, really!
+                       [ true, 'http://example.org:80#anchor' ],
+                       [ true, 'http://example.org/?id#anchor' ],
+                       [ true, 'http://example.org/?#anchor' ],
+
+                       [ false, 'http://a ¿non !!sens after', 'Allow anything after URI' ],
+               ];
+       }
+
+       /**
+        * Test MWHttpRequest::isValidURI()
+        * T29854 : Http::isValidURI is too lax
+        * @dataProvider provideURI
+        * @covers Http::isValidURI
+        */
+       public function testIsValidUri( $expect, $URI, $message = '' ) {
+               $this->assertEquals(
+                       $expect,
+                       (bool)MWHttpRequest::isValidURI( $URI ),
+                       $message
+               );
+       }
+
+}
index 603f4c2..d17b9b3 100644 (file)
@@ -1,19 +1,26 @@
 <?php
 
+use MediaWiki\Http\HttpRequestFactory;
+use MediaWiki\MediaWikiServices;
 use Wikimedia\TestingAccessWrapper;
 
 abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase {
        protected static $httpEngine;
        protected $oldHttpEngine;
 
+       /** @var HttpRequestFactory */
+       private $factory;
+
        public function setUp() {
                parent::setUp();
                $this->oldHttpEngine = Http::$httpEngine;
                Http::$httpEngine = static::$httpEngine;
 
+               $this->factory = MediaWikiServices::getInstance()->getHttpRequestFactory();
+
                try {
-                       $request = MWHttpRequest::factory( 'null:' );
-               } catch ( DomainException $e ) {
+                       $request = $factory->create( 'null:' );
+               } catch ( RuntimeException $e ) {
                        $this->markTestSkipped( static::$httpEngine . ' engine not supported' );
                }
 
@@ -32,19 +39,19 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase {
        // --------------------
 
        public function testIsRedirect() {
-               $request = MWHttpRequest::factory( 'http://httpbin.org/get' );
+               $request = $this->factory->create( 'http://httpbin.org/get' );
                $status = $request->execute();
                $this->assertTrue( $status->isGood() );
                $this->assertFalse( $request->isRedirect() );
 
-               $request = MWHttpRequest::factory( 'http://httpbin.org/redirect/1' );
+               $request = $this->factory->create( 'http://httpbin.org/redirect/1' );
                $status = $request->execute();
                $this->assertTrue( $status->isGood() );
                $this->assertTrue( $request->isRedirect() );
        }
 
        public function testgetFinalUrl() {
-               $request = MWHttpRequest::factory( 'http://httpbin.org/redirect/3' );
+               $request = $this->factory->create( 'http://httpbin.org/redirect/3' );
                if ( !$request->canFollowRedirects() ) {
                        $this->markTestSkipped( 'cannot follow redirects' );
                }
@@ -52,14 +59,14 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase {
                $this->assertTrue( $status->isGood() );
                $this->assertNotSame( 'http://httpbin.org/get', $request->getFinalUrl() );
 
-               $request = MWHttpRequest::factory( 'http://httpbin.org/redirect/3', [ 'followRedirects'
+               $request = $this->factory->create( 'http://httpbin.org/redirect/3', [ 'followRedirects'
                        => true ] );
                $status = $request->execute();
                $this->assertTrue( $status->isGood() );
                $this->assertSame( 'http://httpbin.org/get', $request->getFinalUrl() );
                $this->assertResponseFieldValue( 'url', 'http://httpbin.org/get', $request );
 
-               $request = MWHttpRequest::factory( 'http://httpbin.org/redirect/3', [ 'followRedirects'
+               $request = $this->factory->create( 'http://httpbin.org/redirect/3', [ 'followRedirects'
                => true ] );
                $status = $request->execute();
                $this->assertTrue( $status->isGood() );
@@ -71,7 +78,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase {
                        return;
                }
 
-               $request = MWHttpRequest::factory( 'http://httpbin.org/redirect/3', [ 'followRedirects'
+               $request = $this->factory->create( 'http://httpbin.org/redirect/3', [ 'followRedirects'
                => true, 'maxRedirects' => 1 ] );
                $status = $request->execute();
                $this->assertTrue( $status->isGood() );
@@ -79,7 +86,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase {
        }
 
        public function testSetCookie() {
-               $request = MWHttpRequest::factory( 'http://httpbin.org/cookies' );
+               $request = $this->factory->create( 'http://httpbin.org/cookies' );
                $request->setCookie( 'foo', 'bar' );
                $request->setCookie( 'foo2', 'bar2', [ 'domain' => 'example.com' ] );
                $status = $request->execute();
@@ -88,7 +95,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase {
        }
 
        public function testSetCookieJar() {
-               $request = MWHttpRequest::factory( 'http://httpbin.org/cookies' );
+               $request = $this->factory->create( 'http://httpbin.org/cookies' );
                $cookieJar = new CookieJar();
                $cookieJar->setCookie( 'foo', 'bar', [ 'domain' => 'httpbin.org' ] );
                $cookieJar->setCookie( 'foo2', 'bar2', [ 'domain' => 'example.com' ] );
@@ -97,7 +104,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase {
                $this->assertTrue( $status->isGood() );
                $this->assertResponseFieldValue( 'cookies', [ 'foo' => 'bar' ], $request );
 
-               $request = MWHttpRequest::factory( 'http://httpbin.org/cookies/set?foo=bar' );
+               $request = $this->factory->create( 'http://httpbin.org/cookies/set?foo=bar' );
                $cookieJar = new CookieJar();
                $request->setCookieJar( $cookieJar );
                $status = $request->execute();
@@ -106,7 +113,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase {
 
                $this->markTestIncomplete( 'CookieJar does not handle deletion' );
 
-               // $request = MWHttpRequest::factory( 'http://httpbin.org/cookies/delete?foo' );
+               // $request = $this->factory->create( 'http://httpbin.org/cookies/delete?foo' );
                // $cookieJar = new CookieJar();
                // $cookieJar->setCookie( 'foo', 'bar', [ 'domain' => 'httpbin.org' ] );
                // $cookieJar->setCookie( 'foo2', 'bar2', [ 'domain' => 'httpbin.org' ] );
@@ -118,7 +125,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase {
        }
 
        public function testGetResponseHeaders() {
-               $request = MWHttpRequest::factory( 'http://httpbin.org/response-headers?Foo=bar' );
+               $request = $this->factory->create( 'http://httpbin.org/response-headers?Foo=bar' );
                $status = $request->execute();
                $this->assertTrue( $status->isGood() );
                $headers = array_change_key_case( $request->getResponseHeaders(), CASE_LOWER );
@@ -127,7 +134,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase {
        }
 
        public function testSetHeader() {
-               $request = MWHttpRequest::factory( 'http://httpbin.org/headers' );
+               $request = $this->factory->create( 'http://httpbin.org/headers' );
                $request->setHeader( 'Foo', 'bar' );
                $status = $request->execute();
                $this->assertTrue( $status->isGood() );
@@ -135,14 +142,14 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase {
        }
 
        public function testGetStatus() {
-               $request = MWHttpRequest::factory( 'http://httpbin.org/status/418' );
+               $request = $this->factory->create( 'http://httpbin.org/status/418' );
                $status = $request->execute();
                $this->assertFalse( $status->isOK() );
                $this->assertSame( $request->getStatus(), 418 );
        }
 
        public function testSetUserAgent() {
-               $request = MWHttpRequest::factory( 'http://httpbin.org/user-agent' );
+               $request = $this->factory->create( 'http://httpbin.org/user-agent' );
                $request->setUserAgent( 'foo' );
                $status = $request->execute();
                $this->assertTrue( $status->isGood() );
@@ -150,7 +157,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase {
        }
 
        public function testSetData() {
-               $request = MWHttpRequest::factory( 'http://httpbin.org/post', [ 'method' => 'POST' ] );
+               $request = $this->factory->create( 'http://httpbin.org/post', [ 'method' => 'POST' ] );
                $request->setData( [ 'foo' => 'bar', 'foo2' => 'bar2' ] );
                $status = $request->execute();
                $this->assertTrue( $status->isGood() );
@@ -163,7 +170,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase {
                        return;
                }
 
-               $request = MWHttpRequest::factory( 'http://httpbin.org/ip' );
+               $request = $this->factory->create( 'http://httpbin.org/ip' );
                $data = '';
                $request->setCallback( function ( $fh, $content ) use ( &$data ) {
                        $data .= $content;
@@ -177,7 +184,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase {
        }
 
        public function testBasicAuthentication() {
-               $request = MWHttpRequest::factory( 'http://httpbin.org/basic-auth/user/pass', [
+               $request = $this->factory->create( 'http://httpbin.org/basic-auth/user/pass', [
                        'username' => 'user',
                        'password' => 'pass',
                ] );
@@ -185,7 +192,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase {
                $this->assertTrue( $status->isGood() );
                $this->assertResponseFieldValue( 'authenticated', true, $request );
 
-               $request = MWHttpRequest::factory( 'http://httpbin.org/basic-auth/user/pass', [
+               $request = $this->factory->create( 'http://httpbin.org/basic-auth/user/pass', [
                        'username' => 'user',
                        'password' => 'wrongpass',
                ] );
@@ -195,7 +202,7 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase {
        }
 
        public function testFactoryDefaults() {
-               $request = MWHttpRequest::factory( 'http://acme.test' );
+               $request = $this->factory->create( 'http://acme.test' );
                $this->assertInstanceOf( MWHttpRequest::class, $request );
        }
 
@@ -247,4 +254,53 @@ abstract class MWHttpRequestTestCase extends PHPUnit\Framework\TestCase {
                        array_change_key_case( $cookieJar->cookie, CASE_LOWER ) );
        }
 
+       public static function provideRelativeRedirects() {
+               return [
+                       [
+                               'location' => [ 'http://newsite/file.ext', '/newfile.ext' ],
+                               'final' => 'http://newsite/newfile.ext',
+                               'Relative file path Location: interpreted as full URL'
+                       ],
+                       [
+                               'location' => [ 'https://oldsite/file.ext' ],
+                               'final' => 'https://oldsite/file.ext',
+                               'Location to the HTTPS version of the site'
+                       ],
+                       [
+                               'location' => [
+                                       '/anotherfile.ext',
+                                       'http://anotherfile/hoster.ext',
+                                       'https://anotherfile/hoster.ext'
+                               ],
+                               'final' => 'https://anotherfile/hoster.ext',
+                               'Relative file path Location: should keep the latest host and scheme!'
+                       ],
+                       [
+                               'location' => [ '/anotherfile.ext' ],
+                               'final' => 'http://oldsite/anotherfile.ext',
+                               'Relative Location without domain '
+                       ],
+                       [
+                               'location' => null,
+                               'final' => 'http://oldsite/file.ext',
+                               'No Location (no redirect) '
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideRelativeRedirects
+        * @covers MWHttpRequest::getFinalUrl
+        */
+       public function testRelativeRedirections( $location, $final, $message = null ) {
+               $h = $this->factory->create( 'http://oldsite/file.ext', [], __METHOD__ );
+               $h = TestingAccessWrapper::newFromObject( $h );
+
+               // Forge a Location header
+               $h->respHeaders['location'] = $location;
+
+               // Verify it correctly fixes the Location
+               $this->assertEquals( $final, $h->getFinalUrl(), $message );
+       }
+
 }
index 4730005..3c7cb14 100644 (file)
@@ -40,10 +40,10 @@ class FirejailCommandIntegrationTest extends PHPUnit\Framework\TestCase {
         * @dataProvider provideExecute
         */
        public function testExecute( $testCommand, $flag ) {
-               if ( preg_match( '/^sudo /', $testCommand ) ) {
-                       if ( Shell::command( 'sudo', '-n', 'ls', '/' )->execute()->getExitCode() ) {
-                               $this->markTestSkipped( 'need passwordless sudo' );
-                       }
+               if ( preg_match( '/^sudo /', $testCommand )
+                       && Shell::command( 'sudo', '-n', 'ls', '/' )->execute()->getExitCode()
+               ) {
+                       $this->markTestSkipped( 'need passwordless sudo' );
                }
 
                $command = new FirejailCommand( 'firejail' );
index fddee3d..34f8cd5 100644 (file)
@@ -168,14 +168,10 @@ class ParserTestPrinter extends TestRecorder {
                        $output = strtr( $output, $pairs );
                }
 
-               # Windows, or at least the fc utility, is retarded
-               $slash = wfIsWindows() ? '\\' : '/';
-               $prefix = wfTempDir() . "{$slash}mwParser-" . mt_rand();
-
-               $infile = "$prefix-$inFileTail";
+               $infile = tempnam( wfTempDir(), "mwParser-$inFileTail" );
                $this->dumpToFile( $input, $infile );
 
-               $outfile = "$prefix-$outFileTail";
+               $outfile = tempnam( wfTempDir(), "mwParser-$outFileTail" );
                $this->dumpToFile( $output, $outfile );
 
                global $wgDiff3;
index 699de95..3b63c19 100644 (file)
@@ -289,9 +289,14 @@ class ParserTestRunner {
 
                // All FileRepo changes should be done here by injecting services,
                // there should be no need to change global variables.
-               RepoGroup::setSingleton( $this->createRepoGroup() );
+               MediaWikiServices::getInstance()->disableService( 'RepoGroup' );
+               MediaWikiServices::getInstance()->redefineService( 'RepoGroup',
+                       function () {
+                               return $this->createRepoGroup();
+                       }
+               );
                $teardown[] = function () {
-                       RepoGroup::destroySingleton();
+                       MediaWikiServices::getInstance()->resetServiceForTesting( 'RepoGroup' );
                };
 
                // Set up null lock managers
@@ -388,10 +393,10 @@ class ParserTestRunner {
                        100 => 'MemoryAlpha',
                        101 => 'MemoryAlpha_talk'
                ];
-               // Changing wgExtraNamespaces invalidates caches in MWNamespace and
-               // any live Language object, both on setup and teardown
+               // Changing wgExtraNamespaces invalidates caches in NamespaceInfo and any live Language
+               // object, both on setup and teardown
                $reset = function () {
-                       MWNamespace::clearCaches();
+                       MediaWikiServices::getInstance()->resetServiceForTesting( 'NamespaceInfo' );
                        MediaWikiServices::getInstance()->getContentLanguage()->resetNamespaces();
                };
                $setup[] = $reset;
@@ -449,7 +454,8 @@ class ParserTestRunner {
                                'transformVia404' => false,
                                'backend' => $backend
                        ],
-                       []
+                       [],
+                       MediaWikiServices::getInstance()->getMainWANObjectCache()
                );
        }
 
@@ -635,6 +641,8 @@ class ParserTestRunner {
        /**
         * Reset the Title-related services that need resetting
         * for each test
+        *
+        * @todo We need to reset all services on every test
         */
        private function resetTitleServices() {
                $services = MediaWikiServices::getInstance();
@@ -643,6 +651,7 @@ class ParserTestRunner {
                $services->resetServiceForTesting( '_MediaWikiTitleCodec' );
                $services->resetServiceForTesting( 'LinkRenderer' );
                $services->resetServiceForTesting( 'LinkRendererFactory' );
+               $services->resetServiceForTesting( 'NamespaceInfo' );
        }
 
        /**
@@ -938,12 +947,7 @@ class ParserTestRunner {
         */
        private static function getOptionValue( $key, $opts, $default ) {
                $key = strtolower( $key );
-
-               if ( isset( $opts[$key] ) ) {
-                       return $opts[$key];
-               } else {
-                       return $default;
-               }
+               return $opts[$key] ?? $default;
        }
 
        /**
@@ -1076,7 +1080,8 @@ class ParserTestRunner {
                        'wgLanguageCode' => $langCode,
                        'wgRawHtml' => self::getOptionValue( 'wgRawHtml', $opts, false ),
                        'wgNamespacesWithSubpages' => array_fill_keys(
-                               MWNamespace::getValidNamespaces(), isset( $opts['subpage'] )
+                               MediaWikiServices::getInstance()->getNamespaceInfo()->getValidNamespaces(),
+                               isset( $opts['subpage'] )
                        ),
                        'wgMaxTocLevel' => $maxtoclevel,
                        'wgAllowExternalImages' => self::getOptionValue( 'wgAllowExternalImages', $opts, true ),
@@ -1724,10 +1729,10 @@ class ParserTestRunner {
         * @return bool True if tag hook is present
         */
        public function requireHook( $name ) {
-               global $wgParser;
+               $parser = MediaWikiServices::getInstance()->getParser();
 
-               $wgParser->firstCallInit(); // make sure hooks are loaded.
-               if ( isset( $wgParser->mTagHooks[$name] ) ) {
+               $parser->firstCallInit(); // make sure hooks are loaded.
+               if ( isset( $parser->mTagHooks[$name] ) ) {
                        return true;
                } else {
                        $this->recorder->warning( "   This test suite requires the '$name' hook " .
@@ -1743,11 +1748,11 @@ class ParserTestRunner {
         * @return bool True if function hook is present
         */
        public function requireFunctionHook( $name ) {
-               global $wgParser;
+               $parser = MediaWikiServices::getInstance()->getParser();
 
-               $wgParser->firstCallInit(); // make sure hooks are loaded.
+               $parser->firstCallInit(); // make sure hooks are loaded.
 
-               if ( isset( $wgParser->mFunctionHooks[$name] ) ) {
+               if ( isset( $parser->mFunctionHooks[$name] ) ) {
                        return true;
                } else {
                        $this->recorder->warning( "   This test suite requires the '$name' function " .
@@ -1763,11 +1768,11 @@ class ParserTestRunner {
         * @return bool True if function hook is present
         */
        public function requireTransparentHook( $name ) {
-               global $wgParser;
+               $parser = MediaWikiServices::getInstance()->getParser();
 
-               $wgParser->firstCallInit(); // make sure hooks are loaded.
+               $parser->firstCallInit(); // make sure hooks are loaded.
 
-               if ( isset( $wgParser->mTransparentTagHooks[$name] ) ) {
+               if ( isset( $parser->mTransparentTagHooks[$name] ) ) {
                        return true;
                } else {
                        $this->recorder->warning( "   This test suite requires the '$name' transparent " .
index ee33f1d..0facec2 100644 (file)
@@ -24146,6 +24146,49 @@ language=nl title=[[MediaWiki:Common.css]]
 </p>
 !! end
 
+!! test
+formatdate with invalid month
+!! wikitext
+{{#formatdate:2019-22-22|dmy}}
+!! html
+<p>2019-22-22
+</p>
+!! end
+
+!! test
+formatdate: dots in month name do not match any char (T220563)
+!! options
+language=de
+!! wikitext
+{{#formatdate:jun. 3|dmy}}
+{{#formatdate:junx 3|dmy}}
+!! html
+<p><span class="mw-formatted-date" title="06-03">3 Juni</span>
+junx 3
+</p>
+!! end
+
+!! test
+formatdate uses correct capitalisation in French
+!! options
+language=fr
+!! wikitext
+{{#formatdate:Juin 3|dmy}}
+!! html
+<p><span class="mw-formatted-date" title="06-03">3 juin</span>
+</p>
+!! end
+
+!! test
+formatdate uses correct capitalisation in English
+!! wikitext
+{{#formatdate:june 3|dmy}}
+!! html
+<p><span class="mw-formatted-date" title="06-03">3 June</span>
+</p>
+!! end
+
+
 #
 #
 #
index 3e80598..4f48f48 100644 (file)
@@ -106,6 +106,7 @@ class NoopSuppressor extends Suppressor {
        public function __construct( $mode ) {
                $this->mode = $mode;
        }
+
        public function suppress( $input ) {
                echo "Unsupported output mode: {$this->mode}\n$input";
                return true;
diff --git a/tests/phan/config.php b/tests/phan/config.php
deleted file mode 100644 (file)
index da5e4b3..0000000
+++ /dev/null
@@ -1,466 +0,0 @@
-<?php
-
-// If xdebug is enabled, we need to increase the nesting level for phan
-ini_set( 'xdebug.max_nesting_level', 1000 );
-
-/**
- * This configuration will be read and overlayed on top of the
- * default configuration. Command line arguments will be applied
- * after this file is read.
- *
- * @see src/Phan/Config.php
- * See Config for all configurable options.
- *
- * A Note About Paths
- * ==================
- *
- * Files referenced from this file should be defined as
- *
- * ```
- *   Config::projectPath('relative_path/to/file')
- * ```
- *
- * where the relative path is relative to the root of the
- * project which is defined as either the working directory
- * of the phan executable or a path passed in via the CLI
- * '-d' flag.
- */
-return [
-       /**
-        * A list of individual files to include in analysis
-        * with a path relative to the root directory of the
-        * project. directory_list won't find .inc files so
-        * we augment it here.
-        */
-       'file_list' => array_merge(
-               function_exists( 'register_postsend_function' ) ? [] : [ 'tests/phan/stubs/hhvm.php' ],
-               function_exists( 'wikidiff2_do_diff' ) ? [] : [ 'tests/phan/stubs/wikidiff.php' ],
-               function_exists( 'tideways_enable' ) ? [] : [ 'tests/phan/stubs/tideways.php' ],
-               class_exists( PEAR::class ) ? [] : [ 'tests/phan/stubs/mail.php' ],
-               class_exists( Memcached::class ) ? [] : [ 'tests/phan/stubs/memcached.php' ],
-               // Per composer.json, PHPUnit 6 is used for PHP 7.0+, PHPUnit 4 otherwise.
-               // Load the interface for the version of PHPUnit that isn't installed.
-               // Phan only supports PHP 7.0+ (and not HHVM), so we only need to stub PHPUnit 4.
-               class_exists( PHPUnit_TextUI_Command::class ) ? [] : [ 'tests/phan/stubs/phpunit4.php' ],
-               class_exists( ProfilerExcimer::class ) ? [] : [ 'tests/phan/stubs/excimer.php' ],
-               [
-                       'maintenance/7zip.inc',
-                       'maintenance/cleanupTable.inc',
-                       'maintenance/CodeCleanerGlobalsPass.inc',
-                       'maintenance/commandLine.inc',
-                       'maintenance/sqlite.inc',
-                       'maintenance/userDupes.inc',
-                       'maintenance/language/checkLanguage.inc',
-                       'maintenance/language/languages.inc',
-               ]
-       ),
-
-       /**
-        * A list of directories that should be parsed for class and
-        * method information. After excluding the directories
-        * defined in exclude_analysis_directory_list, the remaining
-        * files will be statically analyzed for errors.
-        *
-        * Thus, both first-party and third-party code being used by
-        * your application should be included in this list.
-        */
-       'directory_list' => [
-               'includes/',
-               'languages/',
-               'maintenance/',
-               'mw-config/',
-               'resources/',
-               'vendor/',
-       ],
-
-       /**
-        * A file list that defines files that will be excluded
-        * from parsing and analysis and will not be read at all.
-        *
-        * This is useful for excluding hopelessly unanalyzable
-        * files that can't be removed for whatever reason.
-        */
-       'exclude_file_list' => [],
-
-       /**
-        * A list of directories holding code that we want
-        * to parse, but not analyze. Also works for individual
-        * files.
-        */
-       "exclude_analysis_directory_list" => [
-               'vendor/',
-               'tests/phan/stubs/',
-               // The referenced classes are not available in vendor, only when
-               // included from composer.
-               'includes/composer/',
-               // Directly references classes that only exist in Translate extension
-               'maintenance/language/',
-               // External class
-               'includes/libs/jsminplus.php',
-       ],
-
-       /**
-        * Backwards Compatibility Checking. This is slow
-        * and expensive, but you should consider running
-        * it before upgrading your version of PHP to a
-        * new version that has backward compatibility
-        * breaks.
-        */
-       'backward_compatibility_checks' => false,
-
-       /**
-        * A set of fully qualified class-names for which
-        * a call to parent::__construct() is required
-        */
-       'parent_constructor_required' => [
-       ],
-
-       /**
-        * Run a quick version of checks that takes less
-        * time at the cost of not running as thorough
-        * an analysis. You should consider setting this
-        * to true only when you wish you had more issues
-        * to fix in your code base.
-        *
-        * In quick-mode the scanner doesn't rescan a function
-        * or a method's code block every time a call is seen.
-        * This means that the problem here won't be detected:
-        *
-        * ```php
-        * <?php
-        * function test($arg):int {
-        *    return $arg;
-        * }
-        * test("abc");
-        * ```
-        *
-        * This would normally generate:
-        *
-        * ```sh
-        * test.php:3 TypeError return string but `test()` is declared to return int
-        * ```
-        *
-        * The initial scan of the function's code block has no
-        * type information for `$arg`. It isn't until we see
-        * the call and rescan test()'s code block that we can
-        * detect that it is actually returning the passed in
-        * `string` instead of an `int` as declared.
-        */
-       'quick_mode' => false,
-
-       /**
-        * By default, Phan will not analyze all node types
-        * in order to save time. If this config is set to true,
-        * Phan will dig deeper into the AST tree and do an
-        * analysis on all nodes, possibly finding more issues.
-        *
-        * See \Phan\Analysis::shouldVisit for the set of skipped
-        * nodes.
-        */
-       'should_visit_all_nodes' => true,
-
-       /**
-        * If enabled, check all methods that override a
-        * parent method to make sure its signature is
-        * compatible with the parent's. This check
-        * can add quite a bit of time to the analysis.
-        */
-       'analyze_signature_compatibility' => true,
-
-       // Emit all issues. They are then suppressed via
-       // suppress_issue_types, rather than a minimum
-       // severity.
-       "minimum_severity" => 0,
-
-       /**
-        * If true, missing properties will be created when
-        * they are first seen. If false, we'll report an
-        * error message if there is an attempt to write
-        * to a class property that wasn't explicitly
-        * defined.
-        */
-       'allow_missing_properties' => false,
-
-       /**
-        * Allow null to be cast as any type and for any
-        * type to be cast to null. Setting this to false
-        * will cut down on false positives.
-        */
-       'null_casts_as_any_type' => true,
-
-       /**
-        * If enabled, scalars (int, float, bool, string, null)
-        * are treated as if they can cast to each other.
-        *
-        * MediaWiki is pretty lax and uses many scalar
-        * types interchangably.
-        */
-       'scalar_implicit_cast' => true,
-
-       /**
-        * If true, seemingly undeclared variables in the global
-        * scope will be ignored. This is useful for projects
-        * with complicated cross-file globals that you have no
-        * hope of fixing.
-        */
-       'ignore_undeclared_variables_in_global_scope' => true,
-
-       /**
-        * Set to true in order to attempt to detect dead
-        * (unreferenced) code. Keep in mind that the
-        * results will only be a guess given that classes,
-        * properties, constants and methods can be referenced
-        * as variables (like `$class->$property` or
-        * `$class->$method()`) in ways that we're unable
-        * to make sense of.
-        */
-       'dead_code_detection' => false,
-
-       /**
-        * If true, the dead code detection rig will
-        * prefer false negatives (not report dead code) to
-        * false positives (report dead code that is not
-        * actually dead) which is to say that the graph of
-        * references will create too many edges rather than
-        * too few edges when guesses have to be made about
-        * what references what.
-        */
-       'dead_code_detection_prefer_false_negative' => true,
-
-       /**
-        * If disabled, Phan will not read docblock type
-        * annotation comments (such as for @return, @param,
-        * @var, @suppress, @deprecated) and only rely on
-        * types expressed in code.
-        */
-       'read_type_annotations' => true,
-
-       /**
-        * If a file path is given, the code base will be
-        * read from and written to the given location in
-        * order to attempt to save some work from being
-        * done. Only changed files will get analyzed if
-        * the file is read
-        */
-       'stored_state_file_path' => null,
-
-       /**
-        * Set to true in order to ignore issue suppression.
-        * This is useful for testing the state of your code, but
-        * unlikely to be useful outside of that.
-        */
-       'disable_suppression' => false,
-
-       /**
-        * If set to true, we'll dump the AST instead of
-        * analyzing files
-        */
-       'dump_ast' => false,
-
-       /**
-        * If set to a string, we'll dump the fully qualified lowercase
-        * function and method signatures instead of analyzing files.
-        */
-       'dump_signatures_file' => null,
-
-       /**
-        * If true (and if stored_state_file_path is set) we'll
-        * look at the list of files passed in and expand the list
-        * to include files that depend on the given files
-        */
-       'expand_file_list' => false,
-
-       // Include a progress bar in the output
-       'progress_bar' => false,
-
-       /**
-        * The probability of actually emitting any progress
-        * bar update. Setting this to something very low
-        * is good for reducing network IO and filling up
-        * your terminal's buffer when running phan on a
-        * remote host.
-        */
-       'progress_bar_sample_rate' => 0.005,
-
-       /**
-        * The number of processes to fork off during the analysis
-        * phase.
-        */
-       'processes' => 1,
-
-       /**
-        * Add any issue types (such as 'PhanUndeclaredMethod')
-        * to this black-list to inhibit them from being reported.
-        */
-       'suppress_issue_types' => [
-               // approximate error count: 29
-               "PhanCommentParamOnEmptyParamList",
-               // approximate error count: 33
-               "PhanCommentParamWithoutRealParam",
-               // approximate error count: 8
-               "PhanDeprecatedClass",
-               // approximate error count: 415
-               "PhanDeprecatedFunction",
-               // approximate error count: 25
-               "PhanDeprecatedProperty",
-               // approximate error count: 17
-               "PhanNonClassMethodCall",
-               // approximate error count: 888
-               "PhanParamSignatureMismatch",
-               // approximate error count: 7
-               "PhanParamSignatureMismatchInternal",
-               // approximate error count: 1
-               "PhanParamSignatureRealMismatchTooFewParameters",
-               // approximate error count: 125
-               "PhanParamTooMany",
-               // approximate error count: 3
-               "PhanParamTooManyInternal",
-               // approximate error count: 2
-               "PhanTraitParentReference",
-               // approximate error count: 3
-               "PhanTypeComparisonFromArray",
-               // approximate error count: 2
-               "PhanTypeComparisonToArray",
-               // approximate error count: 218
-               "PhanTypeMismatchArgument",
-               // approximate error count: 13
-               "PhanTypeMismatchArgumentInternal",
-               // approximate error count: 5
-               "PhanTypeMismatchDimAssignment",
-               // approximate error count: 2
-               "PhanTypeMismatchDimEmpty",
-               // approximate error count: 1
-               "PhanTypeMismatchDimFetch",
-               // approximate error count: 14
-               "PhanTypeMismatchForeach",
-               // approximate error count: 56
-               "PhanTypeMismatchProperty",
-               // approximate error count: 74
-               "PhanTypeMismatchReturn",
-               // approximate error count: 5
-               "PhanTypeNonVarPassByRef",
-               // approximate error count: 32
-               "PhanUndeclaredConstant",
-               // approximate error count: 233
-               "PhanUndeclaredMethod",
-               // approximate error count: 1224
-               "PhanUndeclaredProperty",
-               // approximate error count: 58
-               "PhanUndeclaredVariableDim",
-       ],
-
-       /**
-        * If empty, no filter against issues types will be applied.
-        * If this white-list is non-empty, only issues within the list
-        * will be emitted by Phan.
-        */
-       'whitelist_issue_types' => [
-               // 'PhanAccessMethodPrivate',
-               // 'PhanAccessMethodProtected',
-               // 'PhanAccessNonStaticToStatic',
-               // 'PhanAccessPropertyPrivate',
-               // 'PhanAccessPropertyProtected',
-               // 'PhanAccessSignatureMismatch',
-               // 'PhanAccessSignatureMismatchInternal',
-               // 'PhanAccessStaticToNonStatic',
-               // 'PhanCompatibleExpressionPHP7',
-               // 'PhanCompatiblePHP7',
-               // 'PhanContextNotObject',
-               // 'PhanDeprecatedClass',
-               // 'PhanDeprecatedFunction',
-               // 'PhanDeprecatedProperty',
-               // 'PhanEmptyFile',
-               // 'PhanNonClassMethodCall',
-               // 'PhanNoopArray',
-               // 'PhanNoopClosure',
-               // 'PhanNoopConstant',
-               // 'PhanNoopProperty',
-               // 'PhanNoopVariable',
-               // 'PhanParamRedefined',
-               // 'PhanParamReqAfterOpt',
-               // 'PhanParamSignatureMismatch',
-               // 'PhanParamSignatureMismatchInternal',
-               // 'PhanParamSpecial1',
-               // 'PhanParamSpecial2',
-               // 'PhanParamSpecial3',
-               // 'PhanParamSpecial4',
-               // 'PhanParamTooFew',
-               // 'PhanParamTooFewInternal',
-               // 'PhanParamTooMany',
-               // 'PhanParamTooManyInternal',
-               // 'PhanParamTypeMismatch',
-               // 'PhanParentlessClass',
-               // 'PhanRedefineClass',
-               // 'PhanRedefineClassInternal',
-               // 'PhanRedefineFunction',
-               // 'PhanRedefineFunctionInternal',
-               // 'PhanStaticCallToNonStatic',
-               // 'PhanSyntaxError',
-               // 'PhanTraitParentReference',
-               // 'PhanTypeArrayOperator',
-               // 'PhanTypeArraySuspicious',
-               // 'PhanTypeComparisonFromArray',
-               // 'PhanTypeComparisonToArray',
-               // 'PhanTypeConversionFromArray',
-               // 'PhanTypeInstantiateAbstract',
-               // 'PhanTypeInstantiateInterface',
-               // 'PhanTypeInvalidLeftOperand',
-               // 'PhanTypeInvalidRightOperand',
-               // 'PhanTypeMismatchArgument',
-               // 'PhanTypeMismatchArgumentInternal',
-               // 'PhanTypeMismatchDefault',
-               // 'PhanTypeMismatchForeach',
-               // 'PhanTypeMismatchProperty',
-               // 'PhanTypeMismatchReturn',
-               // 'PhanTypeMissingReturn',
-               // 'PhanTypeNonVarPassByRef',
-               // 'PhanTypeParentConstructorCalled',
-               // 'PhanTypeVoidAssignment',
-               // 'PhanUnanalyzable',
-               // 'PhanUndeclaredClass',
-               // 'PhanUndeclaredClassCatch',
-               // 'PhanUndeclaredClassConstant',
-               // 'PhanUndeclaredClassInstanceof',
-               // 'PhanUndeclaredClassMethod',
-               // 'PhanUndeclaredClassReference',
-               // 'PhanUndeclaredConstant',
-               // 'PhanUndeclaredExtendedClass',
-               // 'PhanUndeclaredFunction',
-               // 'PhanUndeclaredInterface',
-               // 'PhanUndeclaredMethod',
-               // 'PhanUndeclaredProperty',
-               // 'PhanUndeclaredStaticMethod',
-               // 'PhanUndeclaredStaticProperty',
-               // 'PhanUndeclaredTrait',
-               // 'PhanUndeclaredTypeParameter',
-               // 'PhanUndeclaredTypeProperty',
-               // 'PhanUndeclaredVariable',
-               // 'PhanUnreferencedClass',
-               // 'PhanUnreferencedConstant',
-               // 'PhanUnreferencedMethod',
-               // 'PhanUnreferencedProperty',
-               // 'PhanVariableUseClause',
-       ],
-
-       /**
-        * Override to hardcode existence and types of (non-builtin) globals in the global scope.
-        * Class names must be prefixed with '\\'.
-        * (E.g. ['_FOO' => '\\FooClass', 'page' => '\\PageClass', 'userId' => 'int'])
-        */
-       'globals_type_map' => [
-               'IP' => 'string',
-       ],
-
-       // Emit issue messages with markdown formatting
-       'markdown_issue_messages' => false,
-
-       /**
-        * Enable or disable support for generic templated
-        * class types.
-        */
-       'generic_types_enabled' => true,
-
-       // A list of plugin files to execute
-       'plugins' => [
-       ],
-];
diff --git a/tests/phan/stubs/README b/tests/phan/stubs/README
deleted file mode 100644 (file)
index c458ab5..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-These stubs describe how code that is not available at analysis time should be
-used. No implementations are necessary, just define the classes and their
-methods and use phpdoc to describe what arguments are allowed.
diff --git a/tests/phan/stubs/excimer.php b/tests/phan/stubs/excimer.php
deleted file mode 100644 (file)
index af3a673..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-<?php
-
-// phpcs:ignoreFile
-
-class ExcimerProfiler {
-       public function __construct() {
-       }
-       public function setPeriod( $period ) {
-       }
-       public function setEventType( $event_type ) {
-       }
-       public function setMaxDepth( $maxDepth ) {
-       }
-       public function setFlushCallback( $callback, $max_samples ) {
-       }
-       public function clearFlushCallback() {
-       }
-       public function start() {
-       }
-       public function stop() {
-       }
-       public function getLog() {
-       }
-       public function flush() {
-       }
-}
-
-class ExcimerLog {
-       private final function __construct() {
-       }
-       function formatCollapsed() {
-       }
-       function aggregateByFunction() {
-       }
-       function getEventCount() {
-       }
-       function current() {
-       }
-       function key() {
-       }
-       function next() {
-       }
-       function rewind() {
-       }
-       function valid() {
-       }
-       function count() {
-       }
-       function offsetExists( $offset ) {
-       }
-       function offsetGet( $offset ) {
-       }
-       function offsetSet( $offset, $value ) {
-       }
-       function offsetUnset( $offset ) {
-       }
-
-}
-
-class ExcimerLogEntry {
-       private final function __construct() {
-       }
-       function getTimestamp() {
-       }
-       function getEventCount() {
-       }
-       function getTrace() {
-       }
-}
-
-class ExcimerTimer {
-       function setEventType( $event_type ) {
-       }
-       function setInterval( $interval ) {
-       }
-       function setPeriod( $period ) {
-       }
-       function setCallback( $callback ) {
-       }
-       function start() {
-       }
-       function stop() {
-       }
-       function getTime() {
-       }
-}
diff --git a/tests/phan/stubs/hhvm.php b/tests/phan/stubs/hhvm.php
deleted file mode 100644 (file)
index 364ebda..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-// phpcs:ignoreFile
-
-/**
- * @param callable $callback
- * @param mixed ...$parameters
- */
-function register_postsend_function( $callback ) {
-}
diff --git a/tests/phan/stubs/mail.php b/tests/phan/stubs/mail.php
deleted file mode 100644 (file)
index ba1efb9..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-<?php
-
-/**
- * Minimal set of classes necessary for UserMailer to be happy. Types
- * taken from documentation at pear.php.net.
- * phpcs:ignoreFile
- */
-
-class PEAR {
-       /**
-        * @param mixed $data
-        * @return bool
-        */
-       public static function isError( $data ) {
-       }
-}
-
-class PEAR_Error {
-       /**
-        * @return string
-        */
-       public function getMessage() {
-       }
-}
-
-class Mail {
-       /**
-        * @param string $driver
-        * @param array $params
-        * @return self
-        */
-       static public function factory( $driver, array $params = [] ) {
-       }
-
-       /**
-        * @param mixed $recipients
-        * @param array $headers
-        * @param string $body
-        * @return bool|PEAR_Error
-        */
-       public function send( $recipients, array $headers, $body ) {
-       }
-}
-
-class Mail_smtp extends Mail {
-}
-
-class Mail_mime {
-       /**
-        * @param mixed $params
-        */
-       public function __construct( $params = [] ) {
-       }
-
-       /**
-        * @param string $data
-        * @param bool $isfile
-        * @param bool $append
-        * @return bool|PEAR_Error
-        */
-       public function setTXTBody( $data, $isfile = false, $append = false ) {
-       }
-
-       /**
-        * @param string $data
-        * @param bool $isfile
-        * @return bool|PEAR_Error
-        */
-       public function setHTMLBody( $data, $isfile = false ) {
-       }
-
-       /**
-        * @param array|null $parms
-        * @param mixed $filename
-        * @param bool $skip_head
-        * @return string|bool|PEAR_Error
-        */
-       public function get( $params = null, $filename = null, $skip_head = false ) {
-       }
-
-       /**
-        * @param array|null $xtra_headers
-        * @param bool $overwrite
-        * @param bool $skip_content
-        * @return array
-        */
-       public function headers( array $xtra_headers = null, $overwrite = false, $skip_content = false ) {
-       }
-}
diff --git a/tests/phan/stubs/memcached.php b/tests/phan/stubs/memcached.php
deleted file mode 100644 (file)
index 0f8859d..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-<?php
-
-/**
- * The phpstorm stubs package includes the Memcached class with two parameters and docs saying
- * that they are optional. Phan can not detect this and thus throws an error for a usage with
- * no params. So we have this small stub just for the constructor to allow no params.
- * @see https://secure.php.net/manual/en/memcached.construct.php
- * phpcs:ignoreFile
- */
-
-class Memcached {
-
-       public function __construct() {
-       }
-
-}
diff --git a/tests/phan/stubs/phpunit4.php b/tests/phan/stubs/phpunit4.php
deleted file mode 100644 (file)
index e5e88e6..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-<?php
-
-/**
- * Some old classes from PHPUnit 4 that MediaWiki (conditionally) references.
- *
- * phpcs:ignoreFile
- */
-
-class PHPUnit_TextUI_Command {
-
-}
diff --git a/tests/phan/stubs/tideways.php b/tests/phan/stubs/tideways.php
deleted file mode 100644 (file)
index 34ac735..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<?php
-
-/**
- * Minimal set of classes necessary for Xhprof using tideways
- * phpcs:ignoreFile
- */
-
-function tideways_enable(){
-}
-
-function tideways_disable(){
-}
diff --git a/tests/phan/stubs/wikidiff.php b/tests/phan/stubs/wikidiff.php
deleted file mode 100644 (file)
index 02bcd1f..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-// phpcs:ignoreFile
-
-/**
- * @param string $text1
- * @param string $text2
- * @param int $numContextLines
- * @param int $movedParagraphDetectionCutoff
- * @return string
- */
-function wikidiff2_do_diff( $text1, $text2, $numContextLines, $movedParagraphDetectionCutoff = 0 ) {
-}
-
-/**
- * @param string $text1
- * @param string $text2
- * @param int $numContextLines
- * @param int $maxMovedLines
- * @return string
- */
-function wikidiff2_inline_diff( $text1, $text2, $numContextLines, $maxMovedLines = 25 ) {
-}
index f87afb0..8f34180 100644 (file)
@@ -83,6 +83,11 @@ class MediaWikiLoggerPHPUnitTestListener extends PHPUnit_Framework_BaseTestListe
        private function formatLogs( array $logs ) {
                $message = [];
                foreach ( $logs as $log ) {
+                       if ( $log['channel'] === 'PHPUnitCommand' ) {
+                               // Don't print the log of PHPUnit events while running PHPUnit,
+                               // because PHPUnit is already printing those already.
+                               continue;
+                       }
                        $message[] = sprintf(
                                '[%s] [%s] %s %s',
                                $log['channel'],
index 36d66fb..486b16d 100644 (file)
@@ -361,6 +361,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
        public static function resetNonServiceCaches() {
                global $wgRequest, $wgJobClasses;
 
+               User::resetGetDefaultOptionsForTestsOnly();
                foreach ( $wgJobClasses as $type => $class ) {
                        JobQueueGroup::singleton()->get( $type )->delete();
                }
@@ -400,7 +401,8 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                        self::$useTemporaryTables = !$this->getCliArg( 'use-normal-tables' );
                        self::$reuseDB = $this->getCliArg( 'reuse-db' );
 
-                       $this->db = wfGetDB( DB_MASTER );
+                       $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
+                       $this->db = $lb->getConnection( DB_MASTER );
 
                        $this->checkDbIsSupported();
 
@@ -470,7 +472,17 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
         * @return string Absolute name of the temporary file
         */
        protected function getNewTempFile() {
-               $fileName = tempnam( wfTempDir(), 'MW_PHPUnit_' . static::class . '_' );
+               $fileName = tempnam(
+                       wfTempDir(),
+                       // Avoid backslashes here as they result in inconsistent results
+                       // between Windows and other OS, as well as between functions
+                       // that try to normalise these in one or both directions.
+                       // For example, tempnam rejects directory separators in the prefix which
+                       // means it rejects any namespaced class on Windows.
+                       // And then there is, wfMkdirParents which normalises paths always
+                       // whereas most other PHP and MW functions do not.
+                       'MW_PHPUnit_' . strtr( static::class, [ '\\' => '_' ] ) . '_'
+               );
                $this->tmpFiles[] = $fileName;
 
                return $fileName;
@@ -487,14 +499,15 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
         * @return string Absolute name of the temporary directory
         */
        protected function getNewTempDirectory() {
-               // Starting of with a temporary /file/.
+               // Starting of with a temporary *file*.
                $fileName = $this->getNewTempFile();
 
-               // Converting the temporary /file/ to a /directory/
+               // Converting the temporary file to a *directory*.
                // The following is not atomic, but at least we now have a single place,
-               // where temporary directory creation is bundled and can be improved
+               // where temporary directory creation is bundled and can be improved.
                unlink( $fileName );
-               $this->assertTrue( wfMkdirParents( $fileName ) );
+               // If this fails for some reason, PHP will warn and fail the test.
+               mkdir( $fileName, 0777, /* recursive = */ true );
 
                return $fileName;
        }
@@ -542,6 +555,24 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                $this->tmpFiles = array_merge( $this->tmpFiles, (array)$files );
        }
 
+       // @todo Make const when we no longer support HHVM (T192166)
+       private static $namespaceAffectingSettings = [
+               'wgAllowImageMoving',
+               'wgCanonicalNamespaceNames',
+               'wgCapitalLinkOverrides',
+               'wgCapitalLinks',
+               'wgContentNamespaces',
+               'wgExtensionMessagesFiles',
+               'wgExtensionNamespaces',
+               'wgExtraNamespaces',
+               'wgExtraSignatureNamespaces',
+               'wgNamespaceContentModels',
+               'wgNamespaceProtection',
+               'wgNamespacesWithSubpages',
+               'wgNonincludableNamespaces',
+               'wgRestrictionLevels',
+       ];
+
        protected function tearDown() {
                global $wgRequest, $wgSQLMode;
 
@@ -586,8 +617,8 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                        ini_set( $name, $value );
                }
                if (
-                       array_key_exists( 'wgExtraNamespaces', $this->mwGlobals ) ||
-                       in_array( 'wgExtraNamespaces', $this->mwGlobalsToUnset )
+                       array_intersect( self::$namespaceAffectingSettings, array_keys( $this->mwGlobals ) ) ||
+                       array_intersect( self::$namespaceAffectingSettings, $this->mwGlobalsToUnset )
                ) {
                        $this->resetNamespaces();
                }
@@ -729,7 +760,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                        $GLOBALS[$key] = $value;
                }
 
-               if ( array_key_exists( 'wgExtraNamespaces', $pairs ) ) {
+               if ( array_intersect( self::$namespaceAffectingSettings, array_keys( $pairs ) ) ) {
                        $this->resetNamespaces();
                }
        }
@@ -760,14 +791,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                                . 'instance has been replaced by test code.' );
                }
 
-               MWNamespace::clearCaches();
                Language::clearCaches();
-
-               // We can't have the TitleFormatter holding on to an old Language object either
-               // @todo We shouldn't need to reset all the aliases here.
-               $this->localServices->resetServiceForTesting( 'TitleFormatter' );
-               $this->localServices->resetServiceForTesting( 'TitleParser' );
-               $this->localServices->resetServiceForTesting( '_MediaWikiTitleCodec' );
        }
 
        /**
@@ -793,29 +817,6 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                return false;
        }
 
-       /**
-        * Stashes the global, will be restored in tearDown()
-        *
-        * Individual test functions may override globals through the setMwGlobals() function
-        * or directly. When directly overriding globals their keys should first be passed to this
-        * method in setUp to avoid breaking global state for other tests
-        *
-        * That way all other tests are executed with the same settings (instead of using the
-        * unreliable local settings for most tests and fix it only for some tests).
-        *
-        * @param array|string $globalKeys Key to the global variable, or an array of keys.
-        *
-        * @note To allow changes to global variables to take effect on global service instances,
-        *       call overrideMwServices().
-        *
-        * @since 1.23
-        * @deprecated since 1.32, use setMwGlobals() and don't alter globals directly
-        */
-       protected function stashMwGlobals( $globalKeys ) {
-               wfDeprecated( __METHOD__, '1.32' );
-               $this->doStashMwGlobals( $globalKeys );
-       }
-
        private function doStashMwGlobals( $globalKeys ) {
                if ( is_string( $globalKeys ) ) {
                        $globalKeys = [ $globalKeys ];
@@ -953,6 +954,8 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                        $newInstance->redefineService( $name, $callback );
                }
 
+               self::resetGlobalParser();
+
                return $newInstance;
        }
 
@@ -1017,6 +1020,9 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                );
 
                MediaWikiServices::forceGlobalInstance( $newServices );
+
+               self::resetGlobalParser();
+
                return $newServices;
        }
 
@@ -1045,9 +1051,26 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                MediaWikiServices::forceGlobalInstance( self::$originalServices );
                $currentServices->destroy();
 
+               self::resetGlobalParser();
+
                return true;
        }
 
+       /**
+        * If $wgParser has been unstubbed, replace it with a fresh one so it picks up any config
+        * changes. $wgParser is deprecated, but we still support it for now.
+        */
+       private static function resetGlobalParser() {
+               // phpcs:ignore MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgParser
+               global $wgParser;
+               if ( $wgParser instanceof StubObject ) {
+                       return;
+               }
+               $wgParser = new StubObject( 'wgParser', function () {
+                       return MediaWikiServices::getInstance()->getParser();
+               } );
+       }
+
        /**
         * @since 1.27
         * @param string|Language $lang
@@ -1363,6 +1386,9 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                        JobQueueGroup::singleton()->get( $type )->delete();
                }
 
+               // T219673: close any connections from code that failed to call reuseConnection()
+               // or is still holding onto a DBConnRef instance (e.g. in a singleton).
+               MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->closeAll();
                CloneDatabase::changePrefix( self::$oldTablePrefix );
 
                self::$oldTablePrefix = false;
@@ -1453,12 +1479,12 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
         * @note this method only works when first called. Subsequent calls have no effect,
         * even if using different parameters.
         *
-        * @param Database $db The database connection
+        * @param IMaintainableDatabase $db The database connection
         * @param string $prefix The prefix to use for the new table set (aka schema).
         *
         * @throws MWException If the database table prefix is already $prefix
         */
-       public static function setupTestDB( Database $db, $prefix ) {
+       public static function setupTestDB( IMaintainableDatabase $db, $prefix ) {
                if ( self::$dbSetup ) {
                        return;
                }
@@ -1611,6 +1637,10 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
 
                if ( $tablesToRestore ) {
                        $this->recloneMockTables( $db, $tablesToRestore );
+
+                       // Reset the restored tables, mainly for the side effect of
+                       // re-calling $this->addCoreDBData() if necessary.
+                       $this->resetDB( $db, $tablesToRestore );
                }
        }
 
@@ -1625,6 +1655,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
 
                if ( $oldOverrides['alter'] || $oldOverrides['create'] || $oldOverrides['drop'] ) {
                        $this->undoSchemaOverrides( $db, $oldOverrides );
+                       unset( $db->_schemaOverrides );
                }
 
                // Determine new overrides.
@@ -1776,6 +1807,12 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                        if ( array_intersect( $tablesUsed, $userTables ) ) {
                                $tablesUsed = array_unique( array_merge( $tablesUsed, $userTables ) );
                                TestUserRegistry::clear();
+
+                               // Reset $wgUser, which is probably 127.0.0.1, as its loaded data is probably not valid
+                               // @todo Should we start setting $wgUser to something nondeterministic
+                               //  to encourage tests to be updated to not depend on it?
+                               global $wgUser;
+                               $wgUser->clearInstanceCache( $wgUser->mFrom );
                        }
                        if ( array_intersect( $tablesUsed, $pageTables ) ) {
                                $tablesUsed = array_unique( array_merge( $tablesUsed, $pageTables ) );
@@ -2206,18 +2243,19 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                }
 
                // NOTE: prefer content namespaces
+               $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
                $namespaces = array_unique( array_merge(
-                       MWNamespace::getContentNamespaces(),
+                       $nsInfo->getContentNamespaces(),
                        [ NS_MAIN, NS_HELP, NS_PROJECT ], // prefer these
-                       MWNamespace::getValidNamespaces()
+                       $nsInfo->getValidNamespaces()
                ) );
 
                $namespaces = array_diff( $namespaces, [
                        NS_FILE, NS_CATEGORY, NS_MEDIAWIKI, NS_USER // don't mess with magic namespaces
                ] );
 
-               $talk = array_filter( $namespaces, function ( $ns ) {
-                       return MWNamespace::isTalk( $ns );
+               $talk = array_filter( $namespaces, function ( $ns ) use ( $nsInfo ) {
+                       return $nsInfo->isTalk( $ns );
                } );
 
                // prefer non-talk pages
@@ -2328,7 +2366,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                if ( $createIfMissing ) {
                        if ( !file_exists( $fileName ) ) {
                                file_put_contents( $fileName, $actualData );
-                               $this->markTestSkipped( 'Data file $fileName does not exist' );
+                               $this->markTestSkipped( "Data file $fileName does not exist" );
                        }
                } else {
                        self::assertFileExists( $fileName );
@@ -2342,7 +2380,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
         * @param string $text Content of the page
         * @param string $summary Optional summary string for the revision
         * @param int $defaultNs Optional namespace id
-        * @return array Array as returned by WikiPage::doEditContent()
+        * @return Status Object as returned by WikiPage::doEditContent()
         * @throws MWException If this test cases's needsDB() method doesn't return true.
         *         Test cases can use "@group Database" to enable database test support,
         *         or list the tables under testing in $this->tablesUsed, or override the
@@ -2381,4 +2419,18 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                        'comment' => $comment,
                ] );
        }
+
+       /**
+        * Returns a PHPUnit constraint that matches anything other than a fixed set of values. This can
+        * be used to whitelist values, e.g.
+        *   $mock->expects( $this->never() )->method( $this->anythingBut( 'foo', 'bar' ) );
+        * which will throw if any unexpected method is called.
+        *
+        * @param mixed ...$values Values that are not matched
+        */
+       protected function anythingBut( ...$values ) {
+               return $this->logicalNot( $this->logicalOr(
+                       ...array_map( [ $this, 'matches' ], $values )
+               ) );
+       }
 }
index 79ce634..1ef0c91 100644 (file)
@@ -130,4 +130,18 @@ trait PHPUnit4And6Compat {
                        // ->disallowMockingUnknownTypes()
                        ->getMock();
        }
+
+       /**
+        * Marks the current test as risky. This
+        * is a forward port of the markAsRisky function that
+        * was introduced in PHPUnit 5.7.6.
+        */
+       public function markAsRisky() {
+               if ( is_callable( 'parent::markAsRisky' ) ) {
+                       return parent::markAsRisky();
+               }
+
+               // "risky" tests are not supported in phpunit 4, so just ignore
+       }
+
 }
index ca5ff6c..e9a8a1f 100644 (file)
@@ -29,7 +29,7 @@ abstract class ResourceLoaderTestCase extends MediaWikiTestCase {
                        'debug' => 'true',
                        'lang' => 'en',
                        'dir' => 'ltr',
-                       'skin' => 'vector',
+                       'skin' => 'fallback',
                        'modules' => 'startup',
                        'only' => 'scripts',
                        'safemode' => null,
@@ -60,9 +60,6 @@ abstract class ResourceLoaderTestCase extends MediaWikiTestCase {
                        // Avoid influence from wgInvalidateCacheOnLocalSettingsChange
                        'CacheEpoch' => '20140101000000',
 
-                       // For ResourceLoader::__construct()
-                       'ResourceLoaderSources' => [],
-
                        // For wfScript()
                        'ScriptPath' => '/w',
                        'Script' => '/w/index.php',
@@ -140,6 +137,7 @@ class ResourceLoaderTestModule extends ResourceLoaderModule {
        public function isRaw() {
                return $this->isRaw;
        }
+
        public function isKnownEmpty( ResourceLoaderContext $context ) {
                return $this->isKnownEmpty;
        }
index a5c8ef6..79cb5be 100644 (file)
@@ -14,16 +14,21 @@ EOF;
        require_once __DIR__ . "/phpunit.php";
 }
 
-class MediaWikiPHPUnitBootstrap {
-       public function __destruct() {
-               // Return to real wiki db, so profiling data is preserved
-               MediaWikiTestCase::teardownTestDB();
+// The PHPUnit_TextUI_TestRunner class will run each test suite and may call
+// exit() with an exit status code. As such, we cannot run code "after the last test"
+// by adding statements to PHPUnitMaintClass::execute or MediaWikiPHPUnitCommand::run.
+// Instead, we work around it by registering a shutdown callback from the bootstrap
+// file, which runs before PHPUnit starts.
+// @todo Once we use PHPUnit 8 or higher, use the 'AfterLastTestHook' feature.
+// https://phpunit.readthedocs.io/en/8.0/extending-phpunit.html#available-hook-interfaces
+register_shutdown_function( function () {
+       // This will:
+       // - clear the temporary job queue.
+       // - allow extensions to delete any temporary tables they created.
+       // - restore ability to connect to the real database,
+       //   (for logging profiling data).
+       MediaWikiTestCase::teardownTestDB();
 
-               // Log profiling data, e.g. in the database or UDP
-               wfLogProfilingData();
-       }
-
-}
-
-// This will be destructed after all tests have been run
-$mediawikiPHPUnitBootstrap = new MediaWikiPHPUnitBootstrap();
+       // Log profiling data, e.g. in the database or UDP
+       wfLogProfilingData();
+} );
index 019a13e..d20fcff 100644 (file)
@@ -34,7 +34,14 @@ class ReleaseNotesTest extends MediaWikiTestCase {
                }
 
                // Also test the README and similar files
-               $otherFiles = [ "$IP/COPYING", "$IP/FAQ", "$IP/INSTALL", "$IP/README", "$IP/SECURITY" ];
+               $otherFiles = [
+                       "$IP/COPYING",
+                       "$IP/FAQ",
+                       "$IP/HISTORY",
+                       "$IP/INSTALL",
+                       "$IP/README",
+                       "$IP/SECURITY"
+               ];
 
                foreach ( $otherFiles as $index => $fileName ) {
                        $this->assertFileLength( "Help", $fileName );
@@ -49,16 +56,13 @@ class ReleaseNotesTest extends MediaWikiTestCase {
                        "$type file '$fileName' is inaccessible."
                );
 
-               $lines = count( $file );
-
-               for ( $i = 0; $i < $lines; $i++ ) {
-                       $line = $file[$i];
-
+               foreach ( $file as $i => $line ) {
+                       $num = $i + 1;
                        $this->assertLessThanOrEqual(
                                // FILE_IGNORE_NEW_LINES drops the \n at the EOL, so max length is 80 not 81.
                                80,
                                mb_strlen( $line ),
-                               "$type file '$fileName' line $i is longer than 80 chars:\n\t'$line'"
+                               "$type file '$fileName' line $num, is longer than 80 chars:\n\t'$line'"
                        );
                }
        }
index 1f2b13c..de70f26 100644 (file)
@@ -658,14 +658,18 @@ class ActorMigrationTest extends MediaWikiLangTestCase {
                $callback( 1, [] );
        }
 
-       public function testInsertUserIdentity() {
+       /**
+        * @dataProvider provideStages
+        * @param int $stage
+        */
+       public function testInsertUserIdentity( $stage ) {
                $this->setMwGlobals( [
                        // for User::getActorId()
-                       'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
+                       'wgActorTableSchemaMigrationStage' => $stage
                ] );
                $this->overrideMwServices();
 
-               $user = $this->getTestUser()->getUser();
+               $user = $this->getMutableTestUser()->getUser();
                $userIdentity = $this->getMock( UserIdentity::class );
                $userIdentity->method( 'getId' )->willReturn( $user->getId() );
                $userIdentity->method( 'getName' )->willReturn( $user->getName() );
@@ -673,7 +677,7 @@ class ActorMigrationTest extends MediaWikiLangTestCase {
 
                list( $cFields, $cCallback ) = MediaWikiServices::getInstance()->getCommentStore()
                        ->insertWithTempTable( $this->db, 'rev_comment', '' );
-               $m = $this->makeMigration( SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW );
+               $m = $this->makeMigration( $stage );
                list( $fields, $callback ) =
                        $m->getInsertValuesWithTempTable( $this->db, 'rev_user', $userIdentity );
                $extraFields = [
@@ -692,13 +696,25 @@ class ActorMigrationTest extends MediaWikiLangTestCase {
                );
                $this->assertSame( $user->getId(), (int)$row->rev_user );
                $this->assertSame( $user->getName(), $row->rev_user_text );
-               $this->assertSame( $user->getActorId(), (int)$row->rev_actor );
+               $this->assertSame(
+                       ( $stage & SCHEMA_COMPAT_READ_NEW ) ? $user->getActorId() : 0,
+                       (int)$row->rev_actor
+               );
 
-               $m = $this->makeMigration( SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW );
+               $m = $this->makeMigration( $stage );
                $fields = $m->getInsertValues( $this->db, 'dummy_user', $userIdentity );
-               $this->assertSame( $user->getId(), $fields['dummy_user'] );
-               $this->assertSame( $user->getName(), $fields['dummy_user_text'] );
-               $this->assertSame( $user->getActorId(), $fields['dummy_actor'] );
+               if ( $stage & SCHEMA_COMPAT_WRITE_OLD ) {
+                       $this->assertSame( $user->getId(), $fields['dummy_user'] );
+                       $this->assertSame( $user->getName(), $fields['dummy_user_text'] );
+               } else {
+                       $this->assertArrayNotHasKey( 'dummy_user', $fields );
+                       $this->assertArrayNotHasKey( 'dummy_user_text', $fields );
+               }
+               if ( $stage & SCHEMA_COMPAT_WRITE_NEW ) {
+                       $this->assertSame( $user->getActorId(), $fields['dummy_actor'] );
+               } else {
+                       $this->assertArrayNotHasKey( 'dummy_actor', $fields );
+               }
        }
 
        public function testNewMigration() {
index 1f11ef2..3dc5e78 100644 (file)
@@ -1,8 +1,9 @@
 <?php
 
-use MediaWiki\Block\BlockRestriction;
+use MediaWiki\Block\BlockRestrictionStore;
 use MediaWiki\Block\Restriction\PageRestriction;
 use MediaWiki\Block\Restriction\NamespaceRestriction;
+use MediaWiki\MediaWikiServices;
 
 /**
  * @group Database
@@ -94,7 +95,7 @@ class BlockTest extends MediaWikiLangTestCase {
                $madeAt = wfTimestamp( TS_MW );
 
                // delta to stop one-off errors when things happen to go over a second mark.
-               $delta = abs( $madeAt - $block->mTimestamp );
+               $delta = abs( $madeAt - $block->getTimestamp() );
                $this->assertLessThan(
                        2,
                        $delta,
@@ -130,6 +131,78 @@ class BlockTest extends MediaWikiLangTestCase {
                ];
        }
 
+       /**
+        * @dataProvider provideNewFromTargetRangeBlocks
+        * @covers Block::newFromTarget
+        */
+       public function testNewFromTargetRangeBlocks( $targets, $ip, $expectedTarget ) {
+               $blocker = $this->getTestSysop()->getUser();
+
+               foreach ( $targets as $target ) {
+                       $block = new Block();
+                       $block->setTarget( $target );
+                       $block->setBlocker( $blocker );
+                       $block->insert();
+               }
+
+               // Should find the block with the narrowest range
+               $blockTarget = Block::newFromTarget( $this->getTestUser()->getUser(), $ip )->getTarget();
+               $this->assertSame(
+                       $blockTarget instanceof User ? $blockTarget->getName() : $blockTarget,
+                       $expectedTarget
+               );
+
+               foreach ( $targets as $target ) {
+                       $block = Block::newFromTarget( $target );
+                       $block->delete();
+               }
+       }
+
+       function provideNewFromTargetRangeBlocks() {
+               return [
+                       'Blocks to IPv4 ranges' => [
+                               [ '0.0.0.0/20', '0.0.0.0/30', '0.0.0.0/25' ],
+                               '0.0.0.0',
+                               '0.0.0.0/30'
+                       ],
+                       'Blocks to IPv6 ranges' => [
+                               [ '0:0:0:0:0:0:0:0/20', '0:0:0:0:0:0:0:0/30', '0:0:0:0:0:0:0:0/25' ],
+                               '0:0:0:0:0:0:0:0',
+                               '0:0:0:0:0:0:0:0/30'
+                       ],
+                       'Blocks to wide IPv4 range and IP' => [
+                               [ '0.0.0.0/16', '0.0.0.0' ],
+                               '0.0.0.0',
+                               '0.0.0.0'
+                       ],
+                       'Blocks to narrow IPv4 range and IP' => [
+                               [ '0.0.0.0/31', '0.0.0.0' ],
+                               '0.0.0.0',
+                               '0.0.0.0'
+                       ],
+                       'Blocks to wide IPv6 range and IP' => [
+                               [ '0:0:0:0:0:0:0:0/19', '0:0:0:0:0:0:0:0' ],
+                               '0:0:0:0:0:0:0:0',
+                               '0:0:0:0:0:0:0:0'
+                       ],
+                       'Blocks to narrow IPv6 range and IP' => [
+                               [ '0:0:0:0:0:0:0:0/127', '0:0:0:0:0:0:0:0' ],
+                               '0:0:0:0:0:0:0:0',
+                               '0:0:0:0:0:0:0:0'
+                       ],
+                       'Blocks to wide IPv6 range and IP, large numbers' => [
+                               [ '2000:DEAD:BEEF:A:0:0:0:0/19', '2000:DEAD:BEEF:A:0:0:0:0' ],
+                               '2000:DEAD:BEEF:A:0:0:0:0',
+                               '2000:DEAD:BEEF:A:0:0:0:0'
+                       ],
+                       'Blocks to narrow IPv6 range and IP, large numbers' => [
+                               [ '2000:DEAD:BEEF:A:0:0:0:0/127', '2000:DEAD:BEEF:A:0:0:0:0' ],
+                               '2000:DEAD:BEEF:A:0:0:0:0',
+                               '2000:DEAD:BEEF:A:0:0:0:0'
+                       ],
+               ];
+       }
+
        /**
         * @covers Block::appliesToRight
         */
@@ -302,8 +375,8 @@ class BlockTest extends MediaWikiLangTestCase {
                        $block = new Block();
                        $block->setTarget( $target );
                        $block->setBlocker( $blocker );
-                       $block->mReason = $insBlock['desc'];
-                       $block->mExpiry = 'infinity';
+                       $block->setReason( $insBlock['desc'] );
+                       $block->setExpiry( 'infinity' );
                        $block->isCreateAccountBlocked( $insBlock['ACDisable'] );
                        $block->isHardblock( $insBlock['isHardblock'] );
                        $block->isAutoblocking( $insBlock['isAutoBlocking'] );
@@ -369,101 +442,11 @@ class BlockTest extends MediaWikiLangTestCase {
                $xffblocks = Block::getBlocksForIPList( $list, true );
                $this->assertEquals( $exCount, count( $xffblocks ), 'Number of blocks for ' . $xff );
                $block = Block::chooseBlock( $xffblocks, $list );
-               $this->assertEquals( $exResult, $block->mReason, 'Correct block type for XFF header ' . $xff );
-       }
-
-       /**
-        * @covers Block::__construct
-        */
-       public function testDeprecatedConstructor() {
-               $this->hideDeprecated( 'Block::__construct with multiple arguments' );
-               $username = 'UnthinkablySecretRandomUsername';
-               $reason = 'being irrational';
-
-               # Set up the target
-               $u = User::newFromName( $username );
-               if ( $u->getId() == 0 ) {
-                       $u->addToDatabase();
-                       TestUser::setPasswordForUser( $u, 'TotallyObvious' );
-               }
-               unset( $u );
-
-               # Make sure the user isn't blocked
-               $this->assertNull(
-                       Block::newFromTarget( $username ),
-                       "$username should not be blocked"
-               );
-
-               # Perform the block
-               $block = new Block(
-                       /* address */ $username,
-                       /* user */ 0,
-                       /* by */ $this->getTestSysop()->getUser()->getId(),
-                       /* reason */ $reason,
-                       /* timestamp */ 0,
-                       /* auto */ false,
-                       /* expiry */ 0
-               );
-               $block->insert();
-
-               # Check target
-               $this->assertEquals(
-                       $block->getTarget()->getName(),
-                       $username,
-                       "Target should be set properly"
-               );
-
-               # Check supplied parameter
                $this->assertEquals(
-                       $block->mReason,
-                       $reason,
-                       "Reason should be non-default"
-               );
-
-               # Check default parameter
-               $this->assertFalse(
-                       (bool)$block->appliesToRight( 'createaccount' ),
-                       "Account creation should not be blocked by default"
+                       $exResult, $block->getReason(), 'Correct block type for XFF header ' . $xff
                );
        }
 
-       /**
-        * @covers Block::getSystemBlockType
-        * @covers Block::insert
-        * @covers Block::doAutoblock
-        */
-       public function testSystemBlocks() {
-               $user = $this->getUserForBlocking();
-               $this->addBlockForUser( $user );
-
-               $blockOptions = [
-                       'address' => $user->getName(),
-                       'reason' => 'test system block',
-                       'timestamp' => wfTimestampNow(),
-                       'expiry' => $this->db->getInfinity(),
-                       'byText' => 'MediaWiki default',
-                       'systemBlock' => 'test',
-                       'enableAutoblock' => true,
-               ];
-               $block = new Block( $blockOptions );
-
-               $this->assertSame( 'test', $block->getSystemBlockType() );
-
-               try {
-                       $block->insert();
-                       $this->fail( 'Expected exception not thrown' );
-               } catch ( MWException $ex ) {
-                       $this->assertSame( 'Cannot insert a system block into the database', $ex->getMessage() );
-               }
-
-               try {
-                       $block->doAutoblock( '192.0.2.2' );
-                       $this->fail( 'Expected exception not thrown' );
-               } catch ( MWException $ex ) {
-                       $this->assertSame( 'Cannot autoblock from a system block', $ex->getMessage() );
-               }
-       }
-
        /**
         * @covers Block::newFromRow
         */
@@ -665,7 +648,7 @@ class BlockTest extends MediaWikiLangTestCase {
 
                $pageRestriction = new PageRestriction( $block->getId(), $pageFoo->getId() );
                $namespaceRestriction = new NamespaceRestriction( $block->getId(), NS_USER );
-               BlockRestriction::insert( [ $pageRestriction, $namespaceRestriction ] );
+               $this->getBlockRestrictionStore()->insert( [ $pageRestriction, $namespaceRestriction ] );
 
                $this->assertTrue( $block->appliesToTitle( $pageFoo->getTitle() ) );
                $this->assertFalse( $block->appliesToTitle( $pageBar->getTitle() ) );
@@ -726,7 +709,7 @@ class BlockTest extends MediaWikiLangTestCase {
                        $block->getId(),
                        $title->getArticleID()
                );
-               BlockRestriction::insert( [ $pageRestriction ] );
+               $this->getBlockRestrictionStore()->insert( [ $pageRestriction ] );
 
                $this->assertTrue( $block->appliesToPage( $title->getArticleID() ) );
 
@@ -752,7 +735,7 @@ class BlockTest extends MediaWikiLangTestCase {
                $block->insert();
 
                $namespaceRestriction = new NamespaceRestriction( $block->getId(), NS_MAIN );
-               BlockRestriction::insert( [ $namespaceRestriction ] );
+               $this->getBlockRestrictionStore()->insert( [ $namespaceRestriction ] );
 
                $this->assertTrue( $block->appliesToNamespace( NS_MAIN ) );
                $this->assertFalse( $block->appliesToNamespace( NS_USER ) );
@@ -771,4 +754,12 @@ class BlockTest extends MediaWikiLangTestCase {
                $this->assertFalse( $block->appliesToRight( 'purge' ) );
        }
 
+       /**
+        * Get an instance of BlockRestrictionStore
+        *
+        * @return BlockRestrictionStore
+        */
+       protected function getBlockRestrictionStore() : BlockRestrictionStore {
+               return MediaWikiServices::getInstance()->getBlockRestrictionStore();
+       }
 }
diff --git a/tests/phpunit/includes/CategoryTest.php b/tests/phpunit/includes/CategoryTest.php
new file mode 100644 (file)
index 0000000..60fb144
--- /dev/null
@@ -0,0 +1,287 @@
+<?php
+
+/**
+ * @group Database
+ * @group Category
+ */
+class CategoryTest extends MediaWikiTestCase {
+       protected function setUp() {
+               parent::setUp();
+
+               $this->setMwGlobals( [
+                       'wgAllowUserJs' => false,
+                       'wgDefaultLanguageVariant' => false,
+                       'wgMetaNamespace' => 'Project',
+               ] );
+               $this->setUserLang( 'en' );
+               $this->setContentLang( 'en' );
+       }
+
+       /**
+        * @covers Category::initialize()
+        */
+       public function testInitialize_idNotExist() {
+               $category = Category::newFromID( -1 );
+               $this->assertFalse( $category->getName() );
+       }
+
+       public function provideInitializeVariants() {
+               return [
+                       // Existing title
+                       [ 'newFromName', 'Example', 'getID', 1 ],
+                       [ 'newFromName', 'Example', 'getName', 'Example' ],
+                       [ 'newFromName', 'Example', 'getPageCount', 3 ],
+                       [ 'newFromName', 'Example', 'getSubcatCount', 4 ],
+                       [ 'newFromName', 'Example', 'getFileCount', 5 ],
+
+                       // Non-existing title
+                       [ 'newFromName', 'NoExample', 'getID', 0 ],
+                       [ 'newFromName', 'NoExample', 'getName', 'NoExample' ],
+                       [ 'newFromName', 'NoExample', 'getPageCount', 0 ],
+                       [ 'newFromName', 'NoExample', 'getSubcatCount', 0 ],
+                       [ 'newFromName', 'NoExample', 'getFileCount', 0 ],
+
+                       // Existing ID
+                       [ 'newFromID', 1, 'getID', 1 ],
+                       [ 'newFromID', 1, 'getName', 'Example' ],
+                       [ 'newFromID', 1, 'getPageCount', 3 ],
+                       [ 'newFromID', 1, 'getSubcatCount', 4 ],
+                       [ 'newFromID', 1, 'getFileCount', 5 ]
+               ];
+       }
+
+       /**
+        * @covers Category::initialize()
+        * @dataProvider provideInitializeVariants
+        */
+       public function testInitialize( $createFunction, $createParam, $testFunction, $expected ) {
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->insert( 'category',
+                       [
+                               [
+                                       'cat_id' => 1,
+                                       'cat_title' => 'Example',
+                                       'cat_pages' => 3,
+                                       'cat_subcats' => 4,
+                                       'cat_files' => 5
+                               ]
+                       ],
+                       __METHOD__,
+                       [ 'IGNORE' ]
+               );
+
+               $category = Category::{$createFunction}( $createParam );
+               $this->assertEquals( $expected, $category->{$testFunction}() );
+
+               $dbw->delete( 'category', '*', __METHOD__ );
+       }
+
+       /**
+        * @covers Category::newFromName()
+        * @covers Category::getName()
+        */
+       public function testNewFromName_validTitle() {
+               $category = Category::newFromName( 'Example' );
+               $this->assertSame( 'Example', $category->getName() );
+       }
+
+       /**
+        * @covers Category::newFromName()
+        */
+       public function testNewFromName_invalidTitle() {
+               $this->assertFalse( Category::newFromName( '#' ) );
+       }
+
+       /**
+        * @covers Category::newFromTitle()
+        */
+       public function testNewFromTitle() {
+               $title = Title::newFromText( 'Category:Example' );
+               $category = Category::newFromTitle( $title );
+               $this->assertSame( 'Example', $category->getName() );
+       }
+
+       /**
+        * @covers Category::newFromID()
+        * @covers Category::getID()
+        */
+       public function testNewFromID() {
+               $category = Category::newFromID( 5 );
+               $this->assertSame( 5, $category->getID() );
+       }
+
+       /**
+        * @covers Category::newFromRow()
+        */
+       public function testNewFromRow_found() {
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->insert( 'category',
+                       [
+                               [
+                                       'cat_id' => 1,
+                                       'cat_title' => 'Example',
+                                       'cat_pages' => 3,
+                                       'cat_subcats' => 4,
+                                       'cat_files' => 5
+                               ]
+                       ],
+                       __METHOD__,
+                       [ 'IGNORE' ]
+               );
+
+               $category = Category::newFromRow( $dbw->selectRow(
+                       'category',
+                       [ 'cat_id', 'cat_title', 'cat_pages', 'cat_subcats', 'cat_files' ],
+                       [ 'cat_id' => 1 ],
+                       __METHOD__
+               ) );
+
+               $this->assertEquals( 1, $category->getID() );
+
+               $dbw->delete( 'category', '*', __METHOD__ );
+       }
+
+       /**
+        * @covers Category::newFromRow()
+        */
+       public function testNewFromRow_notFoundWithoutTitle() {
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->insert( 'category',
+                       [
+                               [
+                                       'cat_id' => 1,
+                                       'cat_title' => 'Example',
+                                       'cat_pages' => 3,
+                                       'cat_subcats' => 4,
+                                       'cat_files' => 5
+                               ]
+                       ],
+                       __METHOD__,
+                       [ 'IGNORE' ]
+               );
+
+               $row = $dbw->selectRow(
+                       'category',
+                       [ 'cat_id', 'cat_title', 'cat_pages', 'cat_subcats', 'cat_files' ],
+                       [ 'cat_id' => 1 ],
+                       __METHOD__
+               );
+               $row->cat_title = null;
+
+               $this->assertFalse( Category::newFromRow( $row ) );
+
+               $dbw->delete( 'category', '*', __METHOD__ );
+       }
+
+       /**
+        * @covers Category::newFromRow()
+        */
+       public function testNewFromRow_notFoundWithTitle() {
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->insert( 'category',
+                       [
+                               [
+                                       'cat_id' => 1,
+                                       'cat_title' => 'Example',
+                                       'cat_pages' => 3,
+                                       'cat_subcats' => 4,
+                                       'cat_files' => 5
+                               ]
+                       ],
+                       __METHOD__,
+                       [ 'IGNORE' ]
+               );
+
+               $row = $dbw->selectRow(
+                       'category',
+                       [ 'cat_id', 'cat_title', 'cat_pages', 'cat_subcats', 'cat_files' ],
+                       [ 'cat_id' => 1 ],
+                       __METHOD__
+               );
+               $row->cat_title = null;
+
+               $category = Category::newFromRow(
+                       $row,
+                       Title::newFromText( NS_CATEGORY, 'Example' )
+               );
+
+               $this->assertFalse( $category->getID() );
+
+               $dbw->delete( 'category', '*', __METHOD__ );
+       }
+
+       /**
+        * @covers Category::getPageCount()
+        */
+       public function testGetPageCount() {
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->insert( 'category',
+                       [
+                               [
+                                       'cat_id' => 1,
+                                       'cat_title' => 'Example',
+                                       'cat_pages' => 3,
+                                       'cat_subcats' => 4,
+                                       'cat_files' => 5
+                               ]
+                       ],
+                       __METHOD__,
+                       [ 'IGNORE' ]
+               );
+
+               $category = Category::newFromID( 1 );
+               $this->assertEquals( 3, $category->getPageCount() );
+
+               $dbw->delete( 'category', '*', __METHOD__ );
+       }
+
+       /**
+        * @covers Category::getSubcatCount()
+        */
+       public function testGetSubcatCount() {
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->insert( 'category',
+                       [
+                               [
+                                       'cat_id' => 1,
+                                       'cat_title' => 'Example',
+                                       'cat_pages' => 3,
+                                       'cat_subcats' => 4,
+                                       'cat_files' => 5
+                               ]
+                       ],
+                       __METHOD__,
+                       [ 'IGNORE' ]
+               );
+
+               $category = Category::newFromID( 1 );
+               $this->assertEquals( 4, $category->getSubcatCount() );
+
+               $dbw->delete( 'category', '*', __METHOD__ );
+       }
+
+       /**
+        * @covers Category::getFileCount()
+        */
+       public function testGetFileCount() {
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->insert( 'category',
+                       [
+                               [
+                                       'cat_id' => 1,
+                                       'cat_title' => 'Example',
+                                       'cat_pages' => 3,
+                                       'cat_subcats' => 4,
+                                       'cat_files' => 5
+                               ]
+                       ],
+                       __METHOD__,
+                       [ 'IGNORE' ]
+               );
+
+               $category = Category::newFromID( 1 );
+               $this->assertEquals( 5, $category->getFileCount() );
+
+               $dbw->delete( 'category', '*', __METHOD__ );
+       }
+}
index 5f0200d..a758f99 100644 (file)
@@ -37,7 +37,7 @@ class ContentSecurityPolicyTest extends MediaWikiTestCase {
                // Note, there are some obscure globals which
                // could affect the results which aren't included above.
 
-               RepoGroup::destroySingleton();
+               $this->overrideMwServices();
                $context = RequestContext::getMain();
                $resp = $context->getRequest()->response();
                $conf = $context->getConfig();
index f5fef61..d2540f6 100644 (file)
@@ -693,14 +693,6 @@ hello
         * @covers EditPage
         */
        public function testCheckDirectEditingDisallowed_forNonTextContent() {
-               $title = Title::newFromText( 'Dummy:NonTextPageForEditPage' );
-               $page = WikiPage::factory( $title );
-
-               $article = new Article( $title );
-               $article->getContext()->setTitle( $title );
-               $ep = new EditPage( $article );
-               $ep->setContextTitle( $title );
-
                $user = $GLOBALS['wgUser'];
 
                $edit = [
@@ -711,15 +703,79 @@ hello
                        'wpUnicodeCheck' => EditPage::UNICODE_CHECK,
                ];
 
-               $req = new FauxRequest( $edit, true );
-               $ep->importFormData( $req );
-
                $this->setExpectedException(
                        MWException::class,
                        'This content model is not supported: testing'
                );
 
-               $ep->internalAttemptSave( $result, false );
+               $this->doEditDummyNonTextPage( $edit );
+       }
+
+       /** @covers EditPage */
+       public function testShouldPreventChangingContentModelWhenUserCannotChangeModelForTitle() {
+               $this->setTemporaryHook( 'getUserPermissionsErrors',
+                       function ( Title $page, $user, $action, &$result ) {
+                               if ( $action === 'editcontentmodel' &&
+                                        $page->getContentModel() === CONTENT_MODEL_WIKITEXT ) {
+                                       $result = false;
+
+                                       return false;
+                               }
+                       } );
+
+               $user = $GLOBALS['wgUser'];
+
+               $status = $this->doEditDummyNonTextPage( [
+                       'wpTextbox1' => 'some text',
+                       'wpEditToken' => $user->getEditToken(),
+                       'wpEdittime' => '',
+                       'wpStarttime' => wfTimestampNow(),
+                       'wpUnicodeCheck' => EditPage::UNICODE_CHECK,
+                       'model' => CONTENT_MODEL_WIKITEXT,
+                       'format' => CONTENT_FORMAT_WIKITEXT,
+               ] );
+
+               $this->assertFalse( $status->isOK() );
+               $this->assertEquals( EditPage::AS_NO_CHANGE_CONTENT_MODEL, $status->getValue() );
        }
 
+       /** @covers EditPage */
+       public function testShouldPreventChangingContentModelWhenUserCannotEditTargetTitle() {
+               $this->setTemporaryHook( 'getUserPermissionsErrors',
+                       function ( Title $page, $user, $action, &$result ) {
+                               if ( $action === 'edit' && $page->getContentModel() === CONTENT_MODEL_WIKITEXT ) {
+                                       $result = false;
+                                       return false;
+                               }
+                       } );
+
+               $user = $GLOBALS['wgUser'];
+
+               $status = $this->doEditDummyNonTextPage( [
+                       'wpTextbox1' => 'some text',
+                       'wpEditToken' => $user->getEditToken(),
+                       'wpEdittime' => '',
+                       'wpStarttime' => wfTimestampNow(),
+                       'wpUnicodeCheck' => EditPage::UNICODE_CHECK,
+                       'model' => CONTENT_MODEL_WIKITEXT,
+                       'format' => CONTENT_FORMAT_WIKITEXT,
+               ] );
+
+               $this->assertFalse( $status->isOK() );
+               $this->assertEquals( EditPage::AS_NO_CHANGE_CONTENT_MODEL, $status->getValue() );
+       }
+
+       private function doEditDummyNonTextPage( array $edit ): Status {
+               $title = Title::newFromText( 'Dummy:NonTextPageForEditPage' );
+
+               $article = new Article( $title );
+               $article->getContext()->setTitle( $title );
+               $ep = new EditPage( $article );
+               $ep->setContextTitle( $title );
+
+               $req = new FauxRequest( $edit, true );
+               $ep->importFormData( $req );
+
+               return $ep->internalAttemptSave( $result, false );
+       }
 }
index 9e7d680..c054caa 100644 (file)
@@ -7,6 +7,16 @@ class FauxRequestTest extends PHPUnit\Framework\TestCase {
        use MediaWikiCoversValidator;
        use PHPUnit4And6Compat;
 
+       public function setUp() {
+               parent::setUp();
+               $this->orgWgServer = $GLOBALS['wgServer'];
+       }
+
+       public function tearDown() {
+               $GLOBALS['wgServer'] = $this->orgWgServer;
+               parent::tearDown();
+       }
+
        /**
         * @covers FauxRequest::__construct
         */
@@ -148,7 +158,7 @@ class FauxRequestTest extends PHPUnit\Framework\TestCase {
        /**
         * @covers FauxRequest::getRequestURL
         */
-       public function testGetRequestURL() {
+       public function testGetRequestURL_disallowed() {
                $req = new FauxRequest();
                $this->setExpectedException( MWException::class );
                $req->getRequestURL();
@@ -164,6 +174,45 @@ class FauxRequestTest extends PHPUnit\Framework\TestCase {
                $this->assertEquals( 'https://example.org', $req->getRequestURL() );
        }
 
+       /**
+        * @covers FauxRequest::getFullRequestURL
+        */
+       public function testGetFullRequestURL_disallowed() {
+               $GLOBALS['wgServer'] = '//wiki.test';
+               $req = new FauxRequest();
+
+               $this->setExpectedException( MWException::class );
+               $req->getFullRequestURL();
+       }
+
+       /**
+        * @covers FauxRequest::getFullRequestURL
+        */
+       public function testGetFullRequestURL_http() {
+               $GLOBALS['wgServer'] = '//wiki.test';
+               $req = new FauxRequest();
+               $req->setRequestURL( '/path' );
+
+               $this->assertSame(
+                       'http://wiki.test/path',
+                       $req->getFullRequestURL()
+               );
+       }
+
+       /**
+        * @covers FauxRequest::getFullRequestURL
+        */
+       public function testGetFullRequestURL_https() {
+               $GLOBALS['wgServer'] = '//wiki.test';
+               $req = new FauxRequest( [], false, null, 'https' );
+               $req->setRequestURL( '/path' );
+
+               $this->assertSame(
+                       'https://wiki.test/path',
+                       $req->getFullRequestURL()
+               );
+       }
+
        /**
         * @covers FauxRequest::__construct
         * @covers FauxRequest::getProtocol
index 2ee8b98..da08670 100644 (file)
@@ -42,15 +42,19 @@ class FormOptionsTest extends MediaWikiTestCase {
        private function assertGuessBoolean( $data ) {
                $this->guess( FormOptions::BOOL, $data );
        }
+
        private function assertGuessInt( $data ) {
                $this->guess( FormOptions::INT, $data );
        }
+
        private function assertGuessFloat( $data ) {
                $this->guess( FormOptions::FLOAT, $data );
        }
+
        private function assertGuessString( $data ) {
                $this->guess( FormOptions::STRING, $data );
        }
+
        private function assertGuessArray( $data ) {
                $this->guess( FormOptions::ARR, $data );
        }
@@ -62,6 +66,7 @@ class FormOptionsTest extends MediaWikiTestCase {
                        FormOptions::guessType( $data )
                );
        }
+
        /* @} */
 
        /**
index 22fe3ce..1210a50 100644 (file)
@@ -14,6 +14,7 @@ class GlobalTest extends MediaWikiTestCase {
                unlink( $readOnlyFile );
 
                $this->setMwGlobals( [
+                       'wgReadOnly' => null,
                        'wgReadOnlyFile' => $readOnlyFile,
                        'wgUrlProtocols' => [
                                'http://',
@@ -73,12 +74,8 @@ class GlobalTest extends MediaWikiTestCase {
                $this->assertFalse(
                        wfRandomString() == wfRandomString()
                );
-               $this->assertEquals(
-                       strlen( wfRandomString( 10 ) ), 10
-               );
-               $this->assertTrue(
-                       preg_match( '/^[0-9a-f]+$/i', wfRandomString() ) === 1
-               );
+               $this->assertSame( 10, strlen( wfRandomString( 10 ) ), 'length' );
+               $this->assertSame( 1, preg_match( '/^[0-9a-f]+$/i', wfRandomString() ), 'pattern' );
        }
 
        /**
@@ -108,10 +105,6 @@ class GlobalTest extends MediaWikiTestCase {
         * @covers ::wfReadOnly
         */
        public function testReadOnlyEmpty() {
-               global $wgReadOnly;
-               $wgReadOnly = null;
-
-               MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode()->clearCache();
                $this->assertFalse( wfReadOnly() );
                $this->assertFalse( wfReadOnly() );
        }
@@ -121,23 +114,17 @@ class GlobalTest extends MediaWikiTestCase {
         * @covers ::wfReadOnly
         */
        public function testReadOnlySet() {
-               global $wgReadOnly, $wgReadOnlyFile;
-
-               $readOnlyMode = MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode();
-               $readOnlyMode->clearCache();
+               global $wgReadOnlyFile;
 
                $f = fopen( $wgReadOnlyFile, "wt" );
                fwrite( $f, 'Message' );
                fclose( $f );
-               $wgReadOnly = null; # Check on $wgReadOnlyFile
+
+               // Reset the service to avoid cached results
+               $this->overrideMwServices();
 
                $this->assertTrue( wfReadOnly() );
                $this->assertTrue( wfReadOnly() ); # Check cached
-
-               unlink( $wgReadOnlyFile );
-               $readOnlyMode->clearCache();
-               $this->assertFalse( wfReadOnly() );
-               $this->assertFalse( wfReadOnly() );
        }
 
        /**
@@ -146,9 +133,12 @@ class GlobalTest extends MediaWikiTestCase {
         */
        public function testReadOnlyGlobalChange() {
                $this->assertFalse( wfReadOnlyReason() );
+
                $this->setMwGlobals( [
                        'wgReadOnly' => 'reason'
                ] );
+               $this->overrideMwServices();
+
                $this->assertSame( 'reason', wfReadOnlyReason() );
        }
 
diff --git a/tests/phpunit/includes/GlobalFunctions/wfArrayFilterTest.php b/tests/phpunit/includes/GlobalFunctions/wfArrayFilterTest.php
deleted file mode 100644 (file)
index bc930be..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-
-/**
- * @group GlobalFunctions
- * @covers ::wfArrayFilter
- * @covers ::wfArrayFilterByKey
- */
-class WfArrayFilterTest extends MediaWikiTestCase {
-       public function testWfArrayFilter() {
-               $this->hideDeprecated( 'wfArrayFilter' );
-               $arr = [ 'a' => 1, 'b' => 2, 'c' => 3 ];
-               $filtered = wfArrayFilter( $arr, function ( $val, $key ) {
-                       return $key !== 'b';
-               } );
-               $this->assertSame( [ 'a' => 1, 'c' => 3 ], $filtered );
-
-               $arr = [ 'a' => 1, 'b' => 2, 'c' => 3 ];
-               $filtered = wfArrayFilter( $arr, function ( $val, $key ) {
-                       return $val !== 2;
-               } );
-               $this->assertSame( [ 'a' => 1, 'c' => 3 ], $filtered );
-
-               $arr = [ 'a', 'b', 'c' ];
-               $filtered = wfArrayFilter( $arr, function ( $val, $key ) {
-                       return $key !== 0;
-               } );
-               $this->assertSame( [ 1 => 'b',  2 => 'c' ], $filtered );
-       }
-
-       public function testWfArrayFilterByKey() {
-               $this->hideDeprecated( 'wfArrayFilterByKey' );
-               $arr = [ 'a' => 1, 'b' => 2, 'c' => 3 ];
-               $filtered = wfArrayFilterByKey( $arr, function ( $key ) {
-                       return $key !== 'b';
-               } );
-               $this->assertSame( [ 'a' => 1, 'c' => 3 ], $filtered );
-
-               $arr = [ 'a', 'b', 'c' ];
-               $filtered = wfArrayFilterByKey( $arr, function ( $key ) {
-                       return $key !== 0;
-               } );
-               $this->assertSame( [ 1 => 'b',  2 => 'c' ], $filtered );
-       }
-}
index bc9bafa..d3523c3 100644 (file)
@@ -14,11 +14,16 @@ class LinkerTest extends MediaWikiLangTestCase {
                        'wgArticlePath' => '/wiki/$1',
                ] );
 
-               $this->assertEquals(
-                       $expected,
-                       Linker::userLink( $userId, $userName, $altUserName ),
-                       $msg
-               );
+               // We'd also test the warning, but injecting a mock logger into a static method is tricky.
+               if ( $userName === '' ) {
+                       Wikimedia\suppressWarnings();
+               }
+               $actual = Linker::userLink( $userId, $userName, $altUserName );
+               if ( $userName === '' ) {
+                       Wikimedia\restoreWarnings();
+               }
+
+               $this->assertEquals( $expected, $actual, $msg );
        }
 
        public static function provideCasesForUserLink() {
@@ -29,6 +34,9 @@ class LinkerTest extends MediaWikiLangTestCase {
                # - optional altUserName
                # - optional message
                return [
+                       # Empty name (T222529)
+                       'Empty username, userid 0' => [ '(no username available)', 0, '' ],
+                       'Empty username, userid > 0' => [ '(no username available)', 73, '' ],
 
                        # ## ANONYMOUS USER ########################################
                        [
@@ -87,6 +95,118 @@ class LinkerTest extends MediaWikiLangTestCase {
                ];
        }
 
+       /**
+        * @dataProvider provideUserToolLinks
+        * @covers Linker::userToolLinks
+        * @param string $expected
+        * @param int $userId
+        * @param string $userText
+        */
+       public function testUserToolLinks( $expected, $userId, $userText ) {
+               // We'd also test the warning, but injecting a mock logger into a static method is tricky.
+               if ( $userText === '' ) {
+                       Wikimedia\suppressWarnings();
+               }
+               $actual = Linker::userToolLinks( $userId, $userText );
+               if ( $userText === '' ) {
+                       Wikimedia\restoreWarnings();
+               }
+
+               $this->assertSame( $expected, $actual );
+       }
+
+       public static function provideUserToolLinks() {
+               return [
+                       // Empty name (T222529)
+                       'Empty username, userid 0' => [ ' (no username available)', 0, '' ],
+                       'Empty username, userid > 0' => [ ' (no username available)', 73, '' ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideUserTalkLink
+        * @covers Linker::userTalkLink
+        * @param string $expected
+        * @param int $userId
+        * @param string $userText
+        */
+       public function testUserTalkLink( $expected, $userId, $userText ) {
+               // We'd also test the warning, but injecting a mock logger into a static method is tricky.
+               if ( $userText === '' ) {
+                       Wikimedia\suppressWarnings();
+               }
+               $actual = Linker::userTalkLink( $userId, $userText );
+               if ( $userText === '' ) {
+                       Wikimedia\restoreWarnings();
+               }
+
+               $this->assertSame( $expected, $actual );
+       }
+
+       public static function provideUserTalkLink() {
+               return [
+                       // Empty name (T222529)
+                       'Empty username, userid 0' => [ '(no username available)', 0, '' ],
+                       'Empty username, userid > 0' => [ '(no username available)', 73, '' ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideBlockLink
+        * @covers Linker::blockLink
+        * @param string $expected
+        * @param int $userId
+        * @param string $userText
+        */
+       public function testBlockLink( $expected, $userId, $userText ) {
+               // We'd also test the warning, but injecting a mock logger into a static method is tricky.
+               if ( $userText === '' ) {
+                       Wikimedia\suppressWarnings();
+               }
+               $actual = Linker::blockLink( $userId, $userText );
+               if ( $userText === '' ) {
+                       Wikimedia\restoreWarnings();
+               }
+
+               $this->assertSame( $expected, $actual );
+       }
+
+       public static function provideBlockLink() {
+               return [
+                       // Empty name (T222529)
+                       'Empty username, userid 0' => [ '(no username available)', 0, '' ],
+                       'Empty username, userid > 0' => [ '(no username available)', 73, '' ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideEmailLink
+        * @covers Linker::emailLink
+        * @param string $expected
+        * @param int $userId
+        * @param string $userText
+        */
+       public function testEmailLink( $expected, $userId, $userText ) {
+               // We'd also test the warning, but injecting a mock logger into a static method is tricky.
+               if ( $userText === '' ) {
+                       Wikimedia\suppressWarnings();
+               }
+               $actual = Linker::emailLink( $userId, $userText );
+               if ( $userText === '' ) {
+                       Wikimedia\restoreWarnings();
+               }
+
+               $this->assertSame( $expected, $actual );
+       }
+
+       public static function provideEmailLink() {
+               return [
+                       // Empty name (T222529)
+                       'Empty username, userid 0' => [ '(no username available)', 0, '' ],
+                       'Empty username, userid > 0' => [ '(no username available)', 73, '' ],
+               ];
+       }
+
        /**
         * @dataProvider provideCasesForFormatComment
         * @covers Linker::formatComment
@@ -158,6 +278,11 @@ class LinkerTest extends MediaWikiLangTestCase {
                                '<span dir="auto"><span class="autocomment"><a href="/wiki/Special:BlankPage#linkie.3F" title="Special:BlankPage">→‎&#91;[linkie?]]</a></span></span>',
                                "/* [[linkie?]] */",
                        ],
+                       [
+                               '<span dir="auto"><span class="autocomment"><a href="/wiki/Special:BlankPage" title="Special:BlankPage">→‎</a>: </span> // Edit via via</span>',
+                               // Regression test for T222857
+                               "/*  */ // Edit via via",
+                       ],
                        [
                                '<span dir="auto"><span class="autocomment"><a href="/wiki/Special:BlankPage#autocomment" title="Special:BlankPage">→‎autocomment</a>: </span> post</span>',
                                "/* autocomment */ post",
@@ -285,6 +410,48 @@ class LinkerTest extends MediaWikiLangTestCase {
                );
        }
 
+       /**
+        * @covers Linker::generateRollback
+        * @dataProvider provideCasesForRollbackGeneration
+        */
+       public function testGenerateRollback( $rollbackEnabled, $expectedModules ) {
+               $this->markTestSkippedIfDbType( 'postgres' );
+
+               $context = RequestContext::getMain();
+               $user = $context->getUser();
+               $user->setOption( 'showrollbackconfirmation', $rollbackEnabled );
+
+               $pageData = $this->insertPage( 'Rollback_Test_Page' );
+               $page = WikiPage::factory( $pageData['title'] );
+
+               $updater = $page->newPageUpdater( $user );
+               $updater->setContent( \MediaWiki\Revision\SlotRecord::MAIN,
+                       new TextContent( 'Technical Wishes 123!' )
+               );
+               $summary = CommentStoreComment::newUnsavedComment( 'Some comment!' );
+               $updater->saveRevision( $summary );
+
+               $rollbackOutput = Linker::generateRollback( $page->getRevision(), $context );
+               $modules = $context->getOutput()->getModules();
+
+               $this->assertEquals( $expectedModules, $modules );
+               $this->assertContains( 'rollback 1 edit', $rollbackOutput );
+       }
+
+       public static function provideCasesForRollbackGeneration() {
+               return [
+                       [
+                               true,
+                               [ 'mediawiki.page.rollback.confirmation' ]
+
+                       ],
+                       [
+                               false,
+                               []
+                       ]
+               ];
+       }
+
        public static function provideCasesForFormatLinksInComment() {
                // phpcs:disable Generic.Files.LineLength
                return [
diff --git a/tests/phpunit/includes/MWNamespaceTest.php b/tests/phpunit/includes/MWNamespaceTest.php
deleted file mode 100644 (file)
index c95b1eb..0000000
+++ /dev/null
@@ -1,609 +0,0 @@
-<?php
-/**
- * @author Antoine Musso
- * @copyright Copyright © 2011, Antoine Musso
- * @file
- */
-
-class MWNamespaceTest extends MediaWikiTestCase {
-
-       protected function setUp() {
-               parent::setUp();
-
-               $this->setMwGlobals( [
-                       'wgContentNamespaces' => [ NS_MAIN ],
-                       'wgNamespacesWithSubpages' => [
-                               NS_TALK => true,
-                               NS_USER => true,
-                               NS_USER_TALK => true,
-                       ],
-                       'wgCapitalLinks' => true,
-                       'wgCapitalLinkOverrides' => [],
-                       'wgNonincludableNamespaces' => [],
-               ] );
-       }
-
-       /**
-        * @todo Write more texts, handle $wgAllowImageMoving setting
-        * @covers MWNamespace::isMovable
-        */
-       public function testIsMovable() {
-               $this->assertFalse( MWNamespace::isMovable( NS_SPECIAL ) );
-       }
-
-       private function assertIsSubject( $ns ) {
-               $this->assertTrue( MWNamespace::isSubject( $ns ) );
-       }
-
-       private function assertIsNotSubject( $ns ) {
-               $this->assertFalse( MWNamespace::isSubject( $ns ) );
-       }
-
-       /**
-        * Please make sure to change testIsTalk() if you change the assertions below
-        * @covers MWNamespace::isSubject
-        */
-       public function testIsSubject() {
-               // Special namespaces
-               $this->assertIsSubject( NS_MEDIA );
-               $this->assertIsSubject( NS_SPECIAL );
-
-               // Subject pages
-               $this->assertIsSubject( NS_MAIN );
-               $this->assertIsSubject( NS_USER );
-               $this->assertIsSubject( 100 ); # user defined
-
-               // Talk pages
-               $this->assertIsNotSubject( NS_TALK );
-               $this->assertIsNotSubject( NS_USER_TALK );
-               $this->assertIsNotSubject( 101 ); # user defined
-       }
-
-       private function assertIsTalk( $ns ) {
-               $this->assertTrue( MWNamespace::isTalk( $ns ) );
-       }
-
-       private function assertIsNotTalk( $ns ) {
-               $this->assertFalse( MWNamespace::isTalk( $ns ) );
-       }
-
-       /**
-        * Reverse of testIsSubject().
-        * Please update testIsSubject() if you change assertions below
-        * @covers MWNamespace::isTalk
-        */
-       public function testIsTalk() {
-               // Special namespaces
-               $this->assertIsNotTalk( NS_MEDIA );
-               $this->assertIsNotTalk( NS_SPECIAL );
-
-               // Subject pages
-               $this->assertIsNotTalk( NS_MAIN );
-               $this->assertIsNotTalk( NS_USER );
-               $this->assertIsNotTalk( 100 ); # user defined
-
-               // Talk pages
-               $this->assertIsTalk( NS_TALK );
-               $this->assertIsTalk( NS_USER_TALK );
-               $this->assertIsTalk( 101 ); # user defined
-       }
-
-       /**
-        * @covers MWNamespace::getSubject
-        */
-       public function testGetSubject() {
-               // Special namespaces are their own subjects
-               $this->assertEquals( NS_MEDIA, MWNamespace::getSubject( NS_MEDIA ) );
-               $this->assertEquals( NS_SPECIAL, MWNamespace::getSubject( NS_SPECIAL ) );
-
-               $this->assertEquals( NS_MAIN, MWNamespace::getSubject( NS_TALK ) );
-               $this->assertEquals( NS_USER, MWNamespace::getSubject( NS_USER_TALK ) );
-       }
-
-       /**
-        * Regular getTalk() calls
-        * Namespaces without a talk page (NS_MEDIA, NS_SPECIAL) are tested in
-        * the function testGetTalkExceptions()
-        * @covers MWNamespace::getTalk
-        */
-       public function testGetTalk() {
-               $this->assertEquals( NS_TALK, MWNamespace::getTalk( NS_MAIN ) );
-               $this->assertEquals( NS_TALK, MWNamespace::getTalk( NS_TALK ) );
-               $this->assertEquals( NS_USER_TALK, MWNamespace::getTalk( NS_USER ) );
-               $this->assertEquals( NS_USER_TALK, MWNamespace::getTalk( NS_USER_TALK ) );
-       }
-
-       /**
-        * Exceptions with getTalk()
-        * NS_MEDIA does not have talk pages. MediaWiki raise an exception for them.
-        * @expectedException MWException
-        * @covers MWNamespace::getTalk
-        */
-       public function testGetTalkExceptionsForNsMedia() {
-               $this->assertNull( MWNamespace::getTalk( NS_MEDIA ) );
-       }
-
-       /**
-        * Exceptions with getTalk()
-        * NS_SPECIAL does not have talk pages. MediaWiki raise an exception for them.
-        * @expectedException MWException
-        * @covers MWNamespace::getTalk
-        */
-       public function testGetTalkExceptionsForNsSpecial() {
-               $this->assertNull( MWNamespace::getTalk( NS_SPECIAL ) );
-       }
-
-       /**
-        * Regular getAssociated() calls
-        * Namespaces without an associated page (NS_MEDIA, NS_SPECIAL) are tested in
-        * the function testGetAssociatedExceptions()
-        * @covers MWNamespace::getAssociated
-        */
-       public function testGetAssociated() {
-               $this->assertEquals( NS_TALK, MWNamespace::getAssociated( NS_MAIN ) );
-               $this->assertEquals( NS_MAIN, MWNamespace::getAssociated( NS_TALK ) );
-       }
-
-       # ## Exceptions with getAssociated()
-       # ## NS_MEDIA and NS_SPECIAL do not have talk pages. MediaWiki raises
-       # ## an exception for them.
-       /**
-        * @expectedException MWException
-        * @covers MWNamespace::getAssociated
-        */
-       public function testGetAssociatedExceptionsForNsMedia() {
-               $this->assertNull( MWNamespace::getAssociated( NS_MEDIA ) );
-       }
-
-       /**
-        * @expectedException MWException
-        * @covers MWNamespace::getAssociated
-        */
-       public function testGetAssociatedExceptionsForNsSpecial() {
-               $this->assertNull( MWNamespace::getAssociated( NS_SPECIAL ) );
-       }
-
-       /**
-        * Test MWNamespace::equals
-        * Note if we add a namespace registration system with keys like 'MAIN'
-        * we should add tests here for equivilance on things like 'MAIN' == 0
-        * and 'MAIN' == NS_MAIN.
-        * @covers MWNamespace::equals
-        */
-       public function testEquals() {
-               $this->assertTrue( MWNamespace::equals( NS_MAIN, NS_MAIN ) );
-               $this->assertTrue( MWNamespace::equals( NS_MAIN, 0 ) ); // In case we make NS_MAIN 'MAIN'
-               $this->assertTrue( MWNamespace::equals( NS_USER, NS_USER ) );
-               $this->assertTrue( MWNamespace::equals( NS_USER, 2 ) );
-               $this->assertTrue( MWNamespace::equals( NS_USER_TALK, NS_USER_TALK ) );
-               $this->assertTrue( MWNamespace::equals( NS_SPECIAL, NS_SPECIAL ) );
-               $this->assertFalse( MWNamespace::equals( NS_MAIN, NS_TALK ) );
-               $this->assertFalse( MWNamespace::equals( NS_USER, NS_USER_TALK ) );
-               $this->assertFalse( MWNamespace::equals( NS_PROJECT, NS_TEMPLATE ) );
-       }
-
-       /**
-        * @covers MWNamespace::subjectEquals
-        */
-       public function testSubjectEquals() {
-               $this->assertSameSubject( NS_MAIN, NS_MAIN );
-               $this->assertSameSubject( NS_MAIN, 0 ); // In case we make NS_MAIN 'MAIN'
-               $this->assertSameSubject( NS_USER, NS_USER );
-               $this->assertSameSubject( NS_USER, 2 );
-               $this->assertSameSubject( NS_USER_TALK, NS_USER_TALK );
-               $this->assertSameSubject( NS_SPECIAL, NS_SPECIAL );
-               $this->assertSameSubject( NS_MAIN, NS_TALK );
-               $this->assertSameSubject( NS_USER, NS_USER_TALK );
-
-               $this->assertDifferentSubject( NS_PROJECT, NS_TEMPLATE );
-               $this->assertDifferentSubject( NS_SPECIAL, NS_MAIN );
-       }
-
-       /**
-        * @covers MWNamespace::subjectEquals
-        */
-       public function testSpecialAndMediaAreDifferentSubjects() {
-               $this->assertDifferentSubject(
-                       NS_MEDIA, NS_SPECIAL,
-                       "NS_MEDIA and NS_SPECIAL are different subject namespaces"
-               );
-               $this->assertDifferentSubject(
-                       NS_SPECIAL, NS_MEDIA,
-                       "NS_SPECIAL and NS_MEDIA are different subject namespaces"
-               );
-       }
-
-       public function provideHasTalkNamespace() {
-               return [
-                       [ NS_MEDIA, false ],
-                       [ NS_SPECIAL, false ],
-
-                       [ NS_MAIN, true ],
-                       [ NS_TALK, true ],
-                       [ NS_USER, true ],
-                       [ NS_USER_TALK, true ],
-
-                       [ 100, true ],
-                       [ 101, true ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideHasTalkNamespace
-        * @covers MWNamespace::hasTalkNamespace
-        *
-        * @param int $index
-        * @param bool $expected
-        */
-       public function testHasTalkNamespace( $index, $expected ) {
-               $actual = MWNamespace::hasTalkNamespace( $index );
-               $this->assertSame( $actual, $expected, "NS $index" );
-       }
-
-       /**
-        * @dataProvider provideHasTalkNamespace
-        * @covers MWNamespace::canTalk
-        *
-        * @param int $index
-        * @param bool $expected
-        */
-       public function testCanTalk( $index, $expected ) {
-               $this->hideDeprecated( 'MWNamespace::canTalk' );
-               $actual = MWNamespace::canTalk( $index );
-               $this->assertSame( $actual, $expected, "NS $index" );
-       }
-
-       private function assertIsContent( $ns ) {
-               $this->assertTrue( MWNamespace::isContent( $ns ) );
-       }
-
-       private function assertIsNotContent( $ns ) {
-               $this->assertFalse( MWNamespace::isContent( $ns ) );
-       }
-
-       /**
-        * @covers MWNamespace::isContent
-        */
-       public function testIsContent() {
-               // NS_MAIN is a content namespace per DefaultSettings.php
-               // and per function definition.
-
-               $this->assertIsContent( NS_MAIN );
-
-               // Other namespaces which are not expected to be content
-
-               $this->assertIsNotContent( NS_MEDIA );
-               $this->assertIsNotContent( NS_SPECIAL );
-               $this->assertIsNotContent( NS_TALK );
-               $this->assertIsNotContent( NS_USER );
-               $this->assertIsNotContent( NS_CATEGORY );
-               $this->assertIsNotContent( 100 );
-       }
-
-       /**
-        * Similar to testIsContent() but alters the $wgContentNamespaces
-        * global variable.
-        * @covers MWNamespace::isContent
-        */
-       public function testIsContentAdvanced() {
-               global $wgContentNamespaces;
-
-               // Test that user defined namespace #252 is not content
-               $this->assertIsNotContent( 252 );
-
-               // Bless namespace # 252 as a content namespace
-               $wgContentNamespaces[] = 252;
-
-               $this->assertIsContent( 252 );
-
-               // Makes sure NS_MAIN was not impacted
-               $this->assertIsContent( NS_MAIN );
-       }
-
-       private function assertIsWatchable( $ns ) {
-               $this->assertTrue( MWNamespace::isWatchable( $ns ) );
-       }
-
-       private function assertIsNotWatchable( $ns ) {
-               $this->assertFalse( MWNamespace::isWatchable( $ns ) );
-       }
-
-       /**
-        * @covers MWNamespace::isWatchable
-        */
-       public function testIsWatchable() {
-               // Specials namespaces are not watchable
-               $this->assertIsNotWatchable( NS_MEDIA );
-               $this->assertIsNotWatchable( NS_SPECIAL );
-
-               // Core defined namespaces are watchables
-               $this->assertIsWatchable( NS_MAIN );
-               $this->assertIsWatchable( NS_TALK );
-
-               // Additional, user defined namespaces are watchables
-               $this->assertIsWatchable( 100 );
-               $this->assertIsWatchable( 101 );
-       }
-
-       private function assertHasSubpages( $ns ) {
-               $this->assertTrue( MWNamespace::hasSubpages( $ns ) );
-       }
-
-       private function assertHasNotSubpages( $ns ) {
-               $this->assertFalse( MWNamespace::hasSubpages( $ns ) );
-       }
-
-       /**
-        * @covers MWNamespace::hasSubpages
-        */
-       public function testHasSubpages() {
-               global $wgNamespacesWithSubpages;
-
-               // Special namespaces:
-               $this->assertHasNotSubpages( NS_MEDIA );
-               $this->assertHasNotSubpages( NS_SPECIAL );
-
-               // Namespaces without subpages
-               $this->assertHasNotSubpages( NS_MAIN );
-
-               $wgNamespacesWithSubpages[NS_MAIN] = true;
-               $this->assertHasSubpages( NS_MAIN );
-
-               $wgNamespacesWithSubpages[NS_MAIN] = false;
-               $this->assertHasNotSubpages( NS_MAIN );
-
-               // Some namespaces with subpages
-               $this->assertHasSubpages( NS_TALK );
-               $this->assertHasSubpages( NS_USER );
-               $this->assertHasSubpages( NS_USER_TALK );
-       }
-
-       /**
-        * @covers MWNamespace::getContentNamespaces
-        */
-       public function testGetContentNamespaces() {
-               global $wgContentNamespaces;
-
-               $this->assertEquals(
-                       [ NS_MAIN ],
-                       MWNamespace::getContentNamespaces(),
-                       '$wgContentNamespaces is an array with only NS_MAIN by default'
-               );
-
-               # test !is_array( $wgcontentNamespaces )
-               $wgContentNamespaces = '';
-               $this->assertEquals( [ NS_MAIN ], MWNamespace::getContentNamespaces() );
-
-               $wgContentNamespaces = false;
-               $this->assertEquals( [ NS_MAIN ], MWNamespace::getContentNamespaces() );
-
-               $wgContentNamespaces = null;
-               $this->assertEquals( [ NS_MAIN ], MWNamespace::getContentNamespaces() );
-
-               $wgContentNamespaces = 5;
-               $this->assertEquals( [ NS_MAIN ], MWNamespace::getContentNamespaces() );
-
-               # test $wgContentNamespaces === []
-               $wgContentNamespaces = [];
-               $this->assertEquals( [ NS_MAIN ], MWNamespace::getContentNamespaces() );
-
-               # test !in_array( NS_MAIN, $wgContentNamespaces )
-               $wgContentNamespaces = [ NS_USER, NS_CATEGORY ];
-               $this->assertEquals(
-                       [ NS_MAIN, NS_USER, NS_CATEGORY ],
-                       MWNamespace::getContentNamespaces(),
-                       'NS_MAIN is forced in $wgContentNamespaces even if unwanted'
-               );
-
-               # test other cases, return $wgcontentNamespaces as is
-               $wgContentNamespaces = [ NS_MAIN ];
-               $this->assertEquals(
-                       [ NS_MAIN ],
-                       MWNamespace::getContentNamespaces()
-               );
-
-               $wgContentNamespaces = [ NS_MAIN, NS_USER, NS_CATEGORY ];
-               $this->assertEquals(
-                       [ NS_MAIN, NS_USER, NS_CATEGORY ],
-                       MWNamespace::getContentNamespaces()
-               );
-       }
-
-       /**
-        * @covers MWNamespace::getSubjectNamespaces
-        */
-       public function testGetSubjectNamespaces() {
-               $subjectsNS = MWNamespace::getSubjectNamespaces();
-               $this->assertContains( NS_MAIN, $subjectsNS,
-                       "Talk namespaces should have NS_MAIN" );
-               $this->assertNotContains( NS_TALK, $subjectsNS,
-                       "Talk namespaces should have NS_TALK" );
-
-               $this->assertNotContains( NS_MEDIA, $subjectsNS,
-                       "Talk namespaces should not have NS_MEDIA" );
-               $this->assertNotContains( NS_SPECIAL, $subjectsNS,
-                       "Talk namespaces should not have NS_SPECIAL" );
-       }
-
-       /**
-        * @covers MWNamespace::getTalkNamespaces
-        */
-       public function testGetTalkNamespaces() {
-               $talkNS = MWNamespace::getTalkNamespaces();
-               $this->assertContains( NS_TALK, $talkNS,
-                       "Subject namespaces should have NS_TALK" );
-               $this->assertNotContains( NS_MAIN, $talkNS,
-                       "Subject namespaces should not have NS_MAIN" );
-
-               $this->assertNotContains( NS_MEDIA, $talkNS,
-                       "Subject namespaces should not have NS_MEDIA" );
-               $this->assertNotContains( NS_SPECIAL, $talkNS,
-                       "Subject namespaces should not have NS_SPECIAL" );
-       }
-
-       private function assertIsCapitalized( $ns ) {
-               $this->assertTrue( MWNamespace::isCapitalized( $ns ) );
-       }
-
-       private function assertIsNotCapitalized( $ns ) {
-               $this->assertFalse( MWNamespace::isCapitalized( $ns ) );
-       }
-
-       /**
-        * Some namespaces are always capitalized per code definition
-        * in MWNamespace::$alwaysCapitalizedNamespaces
-        * @covers MWNamespace::isCapitalized
-        */
-       public function testIsCapitalizedHardcodedAssertions() {
-               // NS_MEDIA and NS_FILE are treated the same
-               $this->assertEquals(
-                       MWNamespace::isCapitalized( NS_MEDIA ),
-                       MWNamespace::isCapitalized( NS_FILE ),
-                       'NS_MEDIA and NS_FILE have same capitalization rendering'
-               );
-
-               // Boths are capitalized by default
-               $this->assertIsCapitalized( NS_MEDIA );
-               $this->assertIsCapitalized( NS_FILE );
-
-               // Always capitalized namespaces
-               // @see MWNamespace::$alwaysCapitalizedNamespaces
-               $this->assertIsCapitalized( NS_SPECIAL );
-               $this->assertIsCapitalized( NS_USER );
-               $this->assertIsCapitalized( NS_MEDIAWIKI );
-       }
-
-       /**
-        * Follows up for testIsCapitalizedHardcodedAssertions() but alter the
-        * global $wgCapitalLink setting to have extended coverage.
-        *
-        * MWNamespace::isCapitalized() rely on two global settings:
-        *   $wgCapitalLinkOverrides = []; by default
-        *   $wgCapitalLinks = true; by default
-        * This function test $wgCapitalLinks
-        *
-        * Global setting correctness is tested against the NS_PROJECT and
-        * NS_PROJECT_TALK namespaces since they are not hardcoded nor specials
-        * @covers MWNamespace::isCapitalized
-        */
-       public function testIsCapitalizedWithWgCapitalLinks() {
-               global $wgCapitalLinks;
-
-               $this->assertIsCapitalized( NS_PROJECT );
-               $this->assertIsCapitalized( NS_PROJECT_TALK );
-
-               $wgCapitalLinks = false;
-
-               // hardcoded namespaces (see above function) are still capitalized:
-               $this->assertIsCapitalized( NS_SPECIAL );
-               $this->assertIsCapitalized( NS_USER );
-               $this->assertIsCapitalized( NS_MEDIAWIKI );
-
-               // setting is correctly applied
-               $this->assertIsNotCapitalized( NS_PROJECT );
-               $this->assertIsNotCapitalized( NS_PROJECT_TALK );
-       }
-
-       /**
-        * Counter part for MWNamespace::testIsCapitalizedWithWgCapitalLinks() now
-        * testing the $wgCapitalLinkOverrides global.
-        *
-        * @todo split groups of assertions in autonomous testing functions
-        * @covers MWNamespace::isCapitalized
-        */
-       public function testIsCapitalizedWithWgCapitalLinkOverrides() {
-               global $wgCapitalLinkOverrides;
-
-               // Test default settings
-               $this->assertIsCapitalized( NS_PROJECT );
-               $this->assertIsCapitalized( NS_PROJECT_TALK );
-
-               // hardcoded namespaces (see above function) are capitalized:
-               $this->assertIsCapitalized( NS_SPECIAL );
-               $this->assertIsCapitalized( NS_USER );
-               $this->assertIsCapitalized( NS_MEDIAWIKI );
-
-               // Hardcoded namespaces remains capitalized
-               $wgCapitalLinkOverrides[NS_SPECIAL] = false;
-               $wgCapitalLinkOverrides[NS_USER] = false;
-               $wgCapitalLinkOverrides[NS_MEDIAWIKI] = false;
-
-               $this->assertIsCapitalized( NS_SPECIAL );
-               $this->assertIsCapitalized( NS_USER );
-               $this->assertIsCapitalized( NS_MEDIAWIKI );
-
-               $wgCapitalLinkOverrides[NS_PROJECT] = false;
-               $this->assertIsNotCapitalized( NS_PROJECT );
-
-               $wgCapitalLinkOverrides[NS_PROJECT] = true;
-               $this->assertIsCapitalized( NS_PROJECT );
-
-               unset( $wgCapitalLinkOverrides[NS_PROJECT] );
-               $this->assertIsCapitalized( NS_PROJECT );
-       }
-
-       /**
-        * @covers MWNamespace::hasGenderDistinction
-        */
-       public function testHasGenderDistinction() {
-               // Namespaces with gender distinctions
-               $this->assertTrue( MWNamespace::hasGenderDistinction( NS_USER ) );
-               $this->assertTrue( MWNamespace::hasGenderDistinction( NS_USER_TALK ) );
-
-               // Other ones, "genderless"
-               $this->assertFalse( MWNamespace::hasGenderDistinction( NS_MEDIA ) );
-               $this->assertFalse( MWNamespace::hasGenderDistinction( NS_SPECIAL ) );
-               $this->assertFalse( MWNamespace::hasGenderDistinction( NS_MAIN ) );
-               $this->assertFalse( MWNamespace::hasGenderDistinction( NS_TALK ) );
-       }
-
-       /**
-        * @covers MWNamespace::isNonincludable
-        */
-       public function testIsNonincludable() {
-               global $wgNonincludableNamespaces;
-
-               $wgNonincludableNamespaces = [ NS_USER ];
-
-               $this->assertTrue( MWNamespace::isNonincludable( NS_USER ) );
-               $this->assertFalse( MWNamespace::isNonincludable( NS_TEMPLATE ) );
-       }
-
-       private function assertSameSubject( $ns1, $ns2, $msg = '' ) {
-               $this->assertTrue( MWNamespace::subjectEquals( $ns1, $ns2 ), $msg );
-       }
-
-       private function assertDifferentSubject( $ns1, $ns2, $msg = '' ) {
-               $this->assertFalse( MWNamespace::subjectEquals( $ns1, $ns2 ), $msg );
-       }
-
-       public function provideGetCategoryLinkType() {
-               return [
-                       [ NS_MAIN, 'page' ],
-                       [ NS_TALK, 'page' ],
-                       [ NS_USER, 'page' ],
-                       [ NS_USER_TALK, 'page' ],
-
-                       [ NS_FILE, 'file' ],
-                       [ NS_FILE_TALK, 'page' ],
-
-                       [ NS_CATEGORY, 'subcat' ],
-                       [ NS_CATEGORY_TALK, 'page' ],
-
-                       [ 100, 'page' ],
-                       [ 101, 'page' ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideGetCategoryLinkType
-        * @covers MWNamespace::getCategoryLinkType
-        *
-        * @param int $index
-        * @param string $expected
-        */
-       public function testGetCategoryLinkType( $index, $expected ) {
-               $actual = MWNamespace::getCategoryLinkType( $index );
-               $this->assertSame( $expected, $actual, "NS $index" );
-       }
-}
index 63ca139..065024b 100644 (file)
@@ -7,10 +7,7 @@
  */
 class MagicWordFactoryTest extends MediaWikiTestCase {
        private function makeMagicWordFactory( Language $contLang = null ) {
-               if ( $contLang === null ) {
-                       return new MagicWordFactory( Language::factory( 'en' ) );
-               }
-               return new MagicWordFactory( $contLang );
+               return new MagicWordFactory( $contLang ?: Language::factory( 'en' ) );
        }
 
        public function testGetContentLanguage() {
index 1cd40ed..8fa0cd6 100644 (file)
@@ -11,7 +11,7 @@ use Wikimedia\Services\ServiceDisabledException;
  * @group MediaWiki
  */
 class MediaWikiServicesTest extends MediaWikiTestCase {
-       private $deprecatedServices = [ 'CryptRand' ];
+       private $deprecatedServices = [];
 
        /**
         * @return Config
@@ -364,7 +364,7 @@ class MediaWikiServicesTest extends MediaWikiTestCase {
                } ) );
 
                $sortedNames = $names;
-               sort( $sortedNames );
+               natcasesort( $sortedNames );
 
                $this->assertSame( $sortedNames, $names,
                        'Please keep service getters sorted alphabetically' );
index cb234b2..9803081 100644 (file)
@@ -12,8 +12,6 @@
  */
 class MediaWikiVersionFetcherTest extends MediaWikiTestCase {
 
-       use MediaWikiCoversValidator;
-
        public function testReturnsResult() {
                global $wgVersion;
                $versionFetcher = new MediaWikiVersionFetcher();
index 5d77ceb..e745960 100644 (file)
@@ -1,6 +1,5 @@
 <?php
 
-use MediaWiki\MediaWikiServices;
 use Wikimedia\TestingAccessWrapper;
 
 /**
@@ -408,8 +407,7 @@ class MessageTest extends MediaWikiLangTestCase {
                // We have to reset the core hook registration.
                // to register the html hook
                MessageCache::destroyInstance();
-               $this->setMwGlobals( 'wgParser',
-                       MediaWikiServices::getInstance()->getParserFactory()->create() );
+               $this->overrideMwServices();
 
                $msg = new RawMessage( '<html><script>alert("xss")</script></html>' );
                $txt = '<span class="error">&lt;html&gt; tags cannot be' .
index 097aef7..afc6bb5 100644 (file)
@@ -25,6 +25,7 @@ class OutputPageTest extends MediaWikiTestCase {
                parent::setUp();
                ResourceLoader::clearCache();
        }
+
        protected function tearDown() {
                parent::tearDown();
                ResourceLoader::clearCache();
@@ -2711,7 +2712,7 @@ class OutputPageTest extends MediaWikiTestCase {
                        // Single only=scripts load
                        [
                                [ 'test.foo', ResourceLoaderModule::TYPE_SCRIPTS ],
-                               "<script nonce=\"secret\">(window.RLQ=window.RLQ||[]).push(function(){"
+                               "<script nonce=\"secret\">(RLQ=window.RLQ||[]).push(function(){"
                                        . 'mw.loader.load("http://127.0.0.1:8080/w/load.php?lang=en\u0026modules=test.foo\u0026only=scripts\u0026skin=fallback");'
                                        . "});</script>"
                        ],
@@ -2724,14 +2725,14 @@ class OutputPageTest extends MediaWikiTestCase {
                        // Private embed (only=scripts)
                        [
                                [ 'test.quux', ResourceLoaderModule::TYPE_SCRIPTS ],
-                               "<script nonce=\"secret\">(window.RLQ=window.RLQ||[]).push(function(){"
+                               "<script nonce=\"secret\">(RLQ=window.RLQ||[]).push(function(){"
                                        . "mw.test.baz({token:123});\nmw.loader.state({\"test.quux\":\"ready\"});"
                                        . "});</script>"
                        ],
                        // Load private module (combined)
                        [
                                [ 'test.quux', ResourceLoaderModule::TYPE_COMBINED ],
-                               "<script nonce=\"secret\">(window.RLQ=window.RLQ||[]).push(function(){"
+                               "<script nonce=\"secret\">(RLQ=window.RLQ||[]).push(function(){"
                                        . "mw.loader.implement(\"test.quux@1ev0ijv\",function($,jQuery,require,module){"
                                        . "mw.test.baz({token:123});},{\"css\":[\".mw-icon{transition:none}"
                                        . "\"]});});</script>"
@@ -2749,7 +2750,7 @@ class OutputPageTest extends MediaWikiTestCase {
                        // Load two modules in separate groups
                        [
                                [ [ 'test.group.foo', 'test.group.bar' ], ResourceLoaderModule::TYPE_COMBINED ],
-                               "<script nonce=\"secret\">(window.RLQ=window.RLQ||[]).push(function(){"
+                               "<script nonce=\"secret\">(RLQ=window.RLQ||[]).push(function(){"
                                        . 'mw.loader.load("http://127.0.0.1:8080/w/load.php?lang=en\u0026modules=test.group.bar\u0026skin=fallback");'
                                        . 'mw.loader.load("http://127.0.0.1:8080/w/load.php?lang=en\u0026modules=test.group.foo\u0026skin=fallback");'
                                        . "});</script>"
index 646b487..222b3e3 100644 (file)
@@ -1,5 +1,7 @@
 <?php
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * @covers PageProps
  *
@@ -234,7 +236,8 @@ class PagePropsTest extends MediaWikiLangTestCase {
                                ( $model === null || $model === CONTENT_MODEL_WIKITEXT )
                        ) {
                                $ns = $this->getDefaultWikitextNS();
-                               $page = MWNamespace::getCanonicalName( $ns ) . ':' . $page;
+                               $page = MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                       getCanonicalName( $ns ) . ':' . $page;
                        }
 
                        $page = Title::newFromText( $page );
diff --git a/tests/phpunit/includes/Permissions/PermissionManagerTest.php b/tests/phpunit/includes/Permissions/PermissionManagerTest.php
new file mode 100644 (file)
index 0000000..4676fc5
--- /dev/null
@@ -0,0 +1,1411 @@
+<?php
+
+namespace MediaWiki\Tests\Permissions;
+
+use Action;
+use Block;
+use MediaWikiLangTestCase;
+use RequestContext;
+use Title;
+use User;
+use MediaWiki\Block\Restriction\NamespaceRestriction;
+use MediaWiki\Block\Restriction\PageRestriction;
+use MediaWiki\Block\SystemBlock;
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Permissions\PermissionManager;
+
+/**
+ * @group Database
+ *
+ * @covers \MediaWiki\Permissions\PermissionManager
+ */
+class PermissionManagerTest extends MediaWikiLangTestCase {
+
+       /**
+        * @var string
+        */
+       protected $userName, $altUserName;
+
+       /**
+        * @var Title
+        */
+       protected $title;
+
+       /**
+        * @var User
+        */
+       protected $user, $anonUser, $userUser, $altUser;
+
+       /**
+        * @var PermissionManager
+        */
+       protected $permissionManager;
+
+       /** Constant for self::testIsBlockedFrom */
+       const USER_TALK_PAGE = '<user talk page>';
+
+       protected function setUp() {
+               parent::setUp();
+
+               $localZone = 'UTC';
+               $localOffset = date( 'Z' ) / 60;
+
+               $this->setMwGlobals( [
+                       'wgLocaltimezone' => $localZone,
+                       'wgLocalTZoffset' => $localOffset,
+                       'wgNamespaceProtection' => [
+                               NS_MEDIAWIKI => 'editinterface',
+                       ],
+               ] );
+               // Without this testUserBlock will use a non-English context on non-English MediaWiki
+               // installations (because of how Title::checkUserBlock is implemented) and fail.
+               RequestContext::resetMain();
+
+               $this->userName = 'Useruser';
+               $this->altUserName = 'Altuseruser';
+               date_default_timezone_set( $localZone );
+
+               $this->title = Title::makeTitle( NS_MAIN, "Main Page" );
+               if ( !isset( $this->userUser ) || !( $this->userUser instanceof User ) ) {
+                       $this->userUser = User::newFromName( $this->userName );
+
+                       if ( !$this->userUser->getId() ) {
+                               $this->userUser = User::createNew( $this->userName, [
+                                       "email" => "test@example.com",
+                                       "real_name" => "Test User" ] );
+                               $this->userUser->load();
+                       }
+
+                       $this->altUser = User::newFromName( $this->altUserName );
+                       if ( !$this->altUser->getId() ) {
+                               $this->altUser = User::createNew( $this->altUserName, [
+                                       "email" => "alttest@example.com",
+                                       "real_name" => "Test User Alt" ] );
+                               $this->altUser->load();
+                       }
+
+                       $this->anonUser = User::newFromId( 0 );
+
+                       $this->user = $this->userUser;
+               }
+
+               $this->permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+
+               $this->overrideMwServices();
+       }
+
+       protected function setUserPerm( $perm ) {
+               // Setting member variables is evil!!!
+
+               if ( is_array( $perm ) ) {
+                       $this->user->mRights = $perm;
+               } else {
+                       $this->user->mRights = [ $perm ];
+               }
+       }
+
+       protected function setTitle( $ns, $title = "Main_Page" ) {
+               $this->title = Title::makeTitle( $ns, $title );
+       }
+
+       protected function setUser( $userName = null ) {
+               if ( $userName === 'anon' ) {
+                       $this->user = $this->anonUser;
+               } elseif ( $userName === null || $userName === $this->userName ) {
+                       $this->user = $this->userUser;
+               } else {
+                       $this->user = $this->altUser;
+               }
+       }
+
+       /**
+        * @todo This test method should be split up into separate test methods and
+        * data providers
+        *
+        * This test is failing per T201776.
+        *
+        * @group Broken
+        * @covers \MediaWiki\Permissions\PermissionManager::checkQuickPermissions
+        */
+       public function testQuickPermissions() {
+               $prefix = MediaWikiServices::getInstance()->getContentLanguage()->
+               getFormattedNsText( NS_PROJECT );
+
+               $this->setUser( 'anon' );
+               $this->setTitle( NS_TALK );
+               $this->setUserPerm( "createtalk" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'create', $this->user, $this->title );
+               $this->assertEquals( [], $res );
+
+               $this->setTitle( NS_TALK );
+               $this->setUserPerm( "createpage" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'create', $this->user, $this->title );
+               $this->assertEquals( [ [ "nocreatetext" ] ], $res );
+
+               $this->setTitle( NS_TALK );
+               $this->setUserPerm( "" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'create', $this->user, $this->title );
+               $this->assertEquals( [ [ 'nocreatetext' ] ], $res );
+
+               $this->setTitle( NS_MAIN );
+               $this->setUserPerm( "createpage" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'create', $this->user, $this->title );
+               $this->assertEquals( [], $res );
+
+               $this->setTitle( NS_MAIN );
+               $this->setUserPerm( "createtalk" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'create', $this->user, $this->title );
+               $this->assertEquals( [ [ 'nocreatetext' ] ], $res );
+
+               $this->setUser( $this->userName );
+               $this->setTitle( NS_TALK );
+               $this->setUserPerm( "createtalk" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'create', $this->user, $this->title );
+               $this->assertEquals( [], $res );
+
+               $this->setTitle( NS_TALK );
+               $this->setUserPerm( "createpage" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'create', $this->user, $this->title );
+               $this->assertEquals( [ [ 'nocreate-loggedin' ] ], $res );
+
+               $this->setTitle( NS_TALK );
+               $this->setUserPerm( "" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'create', $this->user, $this->title );
+               $this->assertEquals( [ [ 'nocreate-loggedin' ] ], $res );
+
+               $this->setTitle( NS_MAIN );
+               $this->setUserPerm( "createpage" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'create', $this->user, $this->title );
+               $this->assertEquals( [], $res );
+
+               $this->setTitle( NS_MAIN );
+               $this->setUserPerm( "createtalk" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'create', $this->user, $this->title );
+               $this->assertEquals( [ [ 'nocreate-loggedin' ] ], $res );
+
+               $this->setTitle( NS_MAIN );
+               $this->setUserPerm( "" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'create', $this->user, $this->title );
+               $this->assertEquals( [ [ 'nocreate-loggedin' ] ], $res );
+
+               $this->setUser( 'anon' );
+               $this->setTitle( NS_USER, $this->userName . '' );
+               $this->setUserPerm( "" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'move', $this->user, $this->title );
+               $this->assertEquals( [ [ 'cant-move-user-page' ], [ 'movenologintext' ] ], $res );
+
+               $this->setTitle( NS_USER, $this->userName . '/subpage' );
+               $this->setUserPerm( "" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'move', $this->user, $this->title );
+               $this->assertEquals( [ [ 'movenologintext' ] ], $res );
+
+               $this->setTitle( NS_USER, $this->userName . '' );
+               $this->setUserPerm( "move-rootuserpages" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'move', $this->user, $this->title );
+               $this->assertEquals( [ [ 'movenologintext' ] ], $res );
+
+               $this->setTitle( NS_USER, $this->userName . '/subpage' );
+               $this->setUserPerm( "move-rootuserpages" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'move', $this->user, $this->title );
+               $this->assertEquals( [ [ 'movenologintext' ] ], $res );
+
+               $this->setTitle( NS_USER, $this->userName . '' );
+               $this->setUserPerm( "" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'move', $this->user, $this->title );
+               $this->assertEquals( [ [ 'cant-move-user-page' ], [ 'movenologintext' ] ], $res );
+
+               $this->setTitle( NS_USER, $this->userName . '/subpage' );
+               $this->setUserPerm( "" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'move', $this->user, $this->title );
+               $this->assertEquals( [ [ 'movenologintext' ] ], $res );
+
+               $this->setTitle( NS_USER, $this->userName . '' );
+               $this->setUserPerm( "move-rootuserpages" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'move', $this->user, $this->title );
+               $this->assertEquals( [ [ 'movenologintext' ] ], $res );
+
+               $this->setTitle( NS_USER, $this->userName . '/subpage' );
+               $this->setUserPerm( "move-rootuserpages" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'move', $this->user, $this->title );
+               $this->assertEquals( [ [ 'movenologintext' ] ], $res );
+
+               $this->setUser( $this->userName );
+               $this->setTitle( NS_FILE, "img.png" );
+               $this->setUserPerm( "" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'move', $this->user, $this->title );
+               $this->assertEquals( [ [ 'movenotallowedfile' ], [ 'movenotallowed' ] ], $res );
+
+               $this->setTitle( NS_FILE, "img.png" );
+               $this->setUserPerm( "movefile" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'move', $this->user, $this->title );
+               $this->assertEquals( [ [ 'movenotallowed' ] ], $res );
+
+               $this->setUser( 'anon' );
+               $this->setTitle( NS_FILE, "img.png" );
+               $this->setUserPerm( "" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'move', $this->user, $this->title );
+               $this->assertEquals( [ [ 'movenotallowedfile' ], [ 'movenologintext' ] ], $res );
+
+               $this->setTitle( NS_FILE, "img.png" );
+               $this->setUserPerm( "movefile" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'move', $this->user, $this->title );
+               $this->assertEquals( [ [ 'movenologintext' ] ], $res );
+
+               $this->setUser( $this->userName );
+               $this->setUserPerm( "move" );
+               $this->runGroupPermissions( 'move', [ [ 'movenotallowedfile' ] ] );
+
+               $this->setUserPerm( "" );
+               $this->runGroupPermissions(
+                       'move',
+                       [ [ 'movenotallowedfile' ], [ 'movenotallowed' ] ]
+               );
+
+               $this->setUser( 'anon' );
+               $this->setUserPerm( "move" );
+               $this->runGroupPermissions( 'move', [ [ 'movenotallowedfile' ] ] );
+
+               $this->setUserPerm( "" );
+               $this->runGroupPermissions(
+                       'move',
+                       [ [ 'movenotallowedfile' ], [ 'movenotallowed' ] ],
+                       [ [ 'movenotallowedfile' ], [ 'movenologintext' ] ]
+               );
+
+               if ( $this->isWikitextNS( NS_MAIN ) ) {
+                       // NOTE: some content models don't allow moving
+                       // @todo find a Wikitext namespace for testing
+
+                       $this->setTitle( NS_MAIN );
+                       $this->setUser( 'anon' );
+                       $this->setUserPerm( "move" );
+                       $this->runGroupPermissions( 'move', [] );
+
+                       $this->setUserPerm( "" );
+                       $this->runGroupPermissions( 'move', [ [ 'movenotallowed' ] ],
+                               [ [ 'movenologintext' ] ] );
+
+                       $this->setUser( $this->userName );
+                       $this->setUserPerm( "" );
+                       $this->runGroupPermissions( 'move', [ [ 'movenotallowed' ] ] );
+
+                       $this->setUserPerm( "move" );
+                       $this->runGroupPermissions( 'move', [] );
+
+                       $this->setUser( 'anon' );
+                       $this->setUserPerm( 'move' );
+                       $res = $this->permissionManager
+                               ->getPermissionErrors( 'move-target', $this->user, $this->title );
+                       $this->assertEquals( [], $res );
+
+                       $this->setUserPerm( '' );
+                       $res = $this->permissionManager
+                               ->getPermissionErrors( 'move-target', $this->user, $this->title );
+                       $this->assertEquals( [ [ 'movenotallowed' ] ], $res );
+               }
+
+               $this->setTitle( NS_USER );
+               $this->setUser( $this->userName );
+               $this->setUserPerm( [ "move", "move-rootuserpages" ] );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'move-target', $this->user, $this->title );
+               $this->assertEquals( [], $res );
+
+               $this->setUserPerm( "move" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'move-target', $this->user, $this->title );
+               $this->assertEquals( [ [ 'cant-move-to-user-page' ] ], $res );
+
+               $this->setUser( 'anon' );
+               $this->setUserPerm( [ "move", "move-rootuserpages" ] );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'move-target', $this->user, $this->title );
+               $this->assertEquals( [], $res );
+
+               $this->setTitle( NS_USER, "User/subpage" );
+               $this->setUserPerm( [ "move", "move-rootuserpages" ] );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'move-target', $this->user, $this->title );
+               $this->assertEquals( [], $res );
+
+               $this->setUserPerm( "move" );
+               $res = $this->permissionManager
+                       ->getPermissionErrors( 'move-target', $this->user, $this->title );
+               $this->assertEquals( [], $res );
+
+               $this->setUser( 'anon' );
+               $check = [
+                       'edit' => [
+                               [ [ 'badaccess-groups', "*, [[$prefix:Users|Users]]", 2 ] ],
+                               [ [ 'badaccess-group0' ] ],
+                               [],
+                               true
+                       ],
+                       'protect' => [
+                               [ [
+                                       'badaccess-groups',
+                                       "[[$prefix:Administrators|Administrators]]", 1 ],
+                                       [ 'protect-cantedit'
+                                       ] ],
+                               [ [ 'badaccess-group0' ], [ 'protect-cantedit' ] ],
+                               [ [ 'protect-cantedit' ] ],
+                               false
+                       ],
+                       '' => [ [], [], [], true ]
+               ];
+
+               foreach ( [ "edit", "protect", "" ] as $action ) {
+                       $this->setUserPerm( null );
+                       $this->assertEquals( $check[$action][0],
+                               $this->permissionManager
+                                       ->getPermissionErrors( $action, $this->user, $this->title, true ) );
+                       $this->assertEquals( $check[$action][0],
+                               $this->permissionManager
+                                       ->getPermissionErrors( $action, $this->user, $this->title, 'full' ) );
+                       $this->assertEquals( $check[$action][0],
+                               $this->permissionManager
+                                       ->getPermissionErrors( $action, $this->user, $this->title, 'secure' ) );
+
+                       global $wgGroupPermissions;
+                       $old = $wgGroupPermissions;
+                       $wgGroupPermissions = [];
+
+                       $this->assertEquals( $check[$action][1],
+                               $this->permissionManager
+                                       ->getPermissionErrors( $action, $this->user, $this->title, true ) );
+                       $this->assertEquals( $check[$action][1],
+                               $this->permissionManager
+                                       ->getPermissionErrors( $action, $this->user, $this->title, 'full' ) );
+                       $this->assertEquals( $check[$action][1],
+                               $this->permissionManager
+                                       ->getPermissionErrors( $action, $this->user, $this->title, 'secure' ) );
+                       $wgGroupPermissions = $old;
+
+                       $this->setUserPerm( $action );
+                       $this->assertEquals( $check[$action][2],
+                               $this->permissionManager
+                                       ->getPermissionErrors( $action, $this->user, $this->title, true ) );
+                       $this->assertEquals( $check[$action][2],
+                               $this->permissionManager
+                                       ->getPermissionErrors( $action, $this->user, $this->title, 'full' ) );
+                       $this->assertEquals( $check[$action][2],
+                               $this->permissionManager
+                                       ->getPermissionErrors( $action, $this->user, $this->title, 'secure' ) );
+
+                       $this->setUserPerm( $action );
+                       $this->assertEquals( $check[$action][3],
+                               $this->permissionManager->userCan( $action, $this->user, $this->title, true ) );
+                       $this->assertEquals( $check[$action][3],
+                               $this->permissionManager->userCan( $action, $this->user, $this->title,
+                                       PermissionManager::RIGOR_QUICK ) );
+                       # count( User::getGroupsWithPermissions( $action ) ) < 1
+               }
+       }
+
+       protected function runGroupPermissions( $action, $result, $result2 = null ) {
+               global $wgGroupPermissions;
+
+               if ( $result2 === null ) {
+                       $result2 = $result;
+               }
+
+               $wgGroupPermissions['autoconfirmed']['move'] = false;
+               $wgGroupPermissions['user']['move'] = false;
+               $res = $this->permissionManager
+                       ->getPermissionErrors( $action, $this->user, $this->title );
+               $this->assertEquals( $result, $res );
+
+               $wgGroupPermissions['autoconfirmed']['move'] = true;
+               $wgGroupPermissions['user']['move'] = false;
+               $res = $this->permissionManager
+                       ->getPermissionErrors( $action, $this->user, $this->title );
+               $this->assertEquals( $result2, $res );
+
+               $wgGroupPermissions['autoconfirmed']['move'] = true;
+               $wgGroupPermissions['user']['move'] = true;
+               $res = $this->permissionManager
+                       ->getPermissionErrors( $action, $this->user, $this->title );
+               $this->assertEquals( $result2, $res );
+
+               $wgGroupPermissions['autoconfirmed']['move'] = false;
+               $wgGroupPermissions['user']['move'] = true;
+               $res = $this->permissionManager
+                       ->getPermissionErrors( $action, $this->user, $this->title );
+               $this->assertEquals( $result2, $res );
+       }
+
+       /**
+        * @todo This test method should be split up into separate test methods and
+        * data providers
+        * @covers MediaWiki\Permissions\PermissionManager::checkSpecialsAndNSPermissions
+        */
+       public function testSpecialsAndNSPermissions() {
+               global $wgNamespaceProtection;
+               $this->setUser( $this->userName );
+
+               $this->setTitle( NS_SPECIAL );
+
+               $this->assertEquals( [ [ 'badaccess-group0' ], [ 'ns-specialprotected' ] ],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
+
+               $this->setTitle( NS_MAIN );
+               $this->setUserPerm( 'bogus' );
+               $this->assertEquals( [],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
+
+               $this->setTitle( NS_MAIN );
+               $this->setUserPerm( '' );
+               $this->assertEquals( [ [ 'badaccess-group0' ] ],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
+
+               $wgNamespaceProtection[NS_USER] = [ 'bogus' ];
+
+               $this->setTitle( NS_USER );
+               $this->setUserPerm( '' );
+               $this->assertEquals( [ [ 'badaccess-group0' ],
+                       [ 'namespaceprotected', 'User', 'bogus' ] ],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
+
+               $this->setTitle( NS_MEDIAWIKI );
+               $this->setUserPerm( 'bogus' );
+               $this->assertEquals( [ [ 'protectedinterface', 'bogus' ] ],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
+
+               $this->setTitle( NS_MEDIAWIKI );
+               $this->setUserPerm( 'bogus' );
+               $this->assertEquals( [ [ 'protectedinterface', 'bogus' ] ],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
+
+               $wgNamespaceProtection = null;
+
+               $this->setUserPerm( 'bogus' );
+               $this->assertEquals( [],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
+               $this->assertEquals( true,
+                       $this->permissionManager->userCan( 'bogus', $this->user, $this->title ) );
+
+               $this->setUserPerm( '' );
+               $this->assertEquals( [ [ 'badaccess-group0' ] ],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
+               $this->assertEquals( false,
+                       $this->permissionManager->userCan( 'bogus', $this->user, $this->title ) );
+       }
+
+       /**
+        * @todo This test method should be split up into separate test methods and
+        * data providers
+        * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
+        */
+       public function testJsConfigEditPermissions() {
+               $this->setUser( $this->userName );
+
+               $this->setTitle( NS_USER, $this->userName . '/test.js' );
+               $this->runConfigEditPermissions(
+                       [ [ 'badaccess-group0' ], [ 'mycustomjsprotected', 'bogus' ] ],
+
+                       [ [ 'badaccess-group0' ], [ 'mycustomjsprotected', 'bogus' ] ],
+                       [ [ 'badaccess-group0' ], [ 'mycustomjsprotected', 'bogus' ] ],
+                       [ [ 'badaccess-group0' ] ],
+
+                       [ [ 'badaccess-group0' ], [ 'mycustomjsprotected', 'bogus' ] ],
+                       [ [ 'badaccess-group0' ], [ 'mycustomjsprotected', 'bogus' ] ],
+                       [ [ 'badaccess-group0' ] ],
+                       [ [ 'badaccess-groups' ] ]
+               );
+       }
+
+       /**
+        * @todo This test method should be split up into separate test methods and
+        * data providers
+        * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
+        */
+       public function testJsonConfigEditPermissions() {
+               $prefix = MediaWikiServices::getInstance()->getContentLanguage()->
+               getFormattedNsText( NS_PROJECT );
+               $this->setUser( $this->userName );
+
+               $this->setTitle( NS_USER, $this->userName . '/test.json' );
+               $this->runConfigEditPermissions(
+                       [ [ 'badaccess-group0' ], [ 'mycustomjsonprotected', 'bogus' ] ],
+
+                       [ [ 'badaccess-group0' ], [ 'mycustomjsonprotected', 'bogus' ] ],
+                       [ [ 'badaccess-group0' ] ],
+                       [ [ 'badaccess-group0' ], [ 'mycustomjsonprotected', 'bogus' ] ],
+
+                       [ [ 'badaccess-group0' ], [ 'mycustomjsonprotected', 'bogus' ] ],
+                       [ [ 'badaccess-group0' ] ],
+                       [ [ 'badaccess-group0' ], [ 'mycustomjsonprotected', 'bogus' ] ],
+                       [ [ 'badaccess-groups' ] ]
+               );
+       }
+
+       /**
+        * @todo This test method should be split up into separate test methods and
+        * data providers
+        * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
+        */
+       public function testCssConfigEditPermissions() {
+               $this->setUser( $this->userName );
+
+               $this->setTitle( NS_USER, $this->userName . '/test.css' );
+               $this->runConfigEditPermissions(
+                       [ [ 'badaccess-group0' ], [ 'mycustomcssprotected', 'bogus' ] ],
+
+                       [ [ 'badaccess-group0' ] ],
+                       [ [ 'badaccess-group0' ], [ 'mycustomcssprotected', 'bogus' ] ],
+                       [ [ 'badaccess-group0' ], [ 'mycustomcssprotected', 'bogus' ] ],
+
+                       [ [ 'badaccess-group0' ] ],
+                       [ [ 'badaccess-group0' ], [ 'mycustomcssprotected', 'bogus' ] ],
+                       [ [ 'badaccess-group0' ], [ 'mycustomcssprotected', 'bogus' ] ],
+                       [ [ 'badaccess-groups' ] ]
+               );
+       }
+
+       /**
+        * @todo This test method should be split up into separate test methods and
+        * data providers
+        * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
+        */
+       public function testOtherJsConfigEditPermissions() {
+               $this->setUser( $this->userName );
+
+               $this->setTitle( NS_USER, $this->altUserName . '/test.js' );
+               $this->runConfigEditPermissions(
+                       [ [ 'badaccess-group0' ], [ 'customjsprotected', 'bogus' ] ],
+
+                       [ [ 'badaccess-group0' ], [ 'customjsprotected', 'bogus' ] ],
+                       [ [ 'badaccess-group0' ], [ 'customjsprotected', 'bogus' ] ],
+                       [ [ 'badaccess-group0' ], [ 'customjsprotected', 'bogus' ] ],
+
+                       [ [ 'badaccess-group0' ], [ 'customjsprotected', 'bogus' ] ],
+                       [ [ 'badaccess-group0' ], [ 'customjsprotected', 'bogus' ] ],
+                       [ [ 'badaccess-group0' ] ],
+                       [ [ 'badaccess-groups' ] ]
+               );
+       }
+
+       /**
+        * @todo This test method should be split up into separate test methods and
+        * data providers
+        * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
+        */
+       public function testOtherJsonConfigEditPermissions() {
+               $this->setUser( $this->userName );
+
+               $this->setTitle( NS_USER, $this->altUserName . '/test.json' );
+               $this->runConfigEditPermissions(
+                       [ [ 'badaccess-group0' ], [ 'customjsonprotected', 'bogus' ] ],
+
+                       [ [ 'badaccess-group0' ], [ 'customjsonprotected', 'bogus' ] ],
+                       [ [ 'badaccess-group0' ], [ 'customjsonprotected', 'bogus' ] ],
+                       [ [ 'badaccess-group0' ], [ 'customjsonprotected', 'bogus' ] ],
+
+                       [ [ 'badaccess-group0' ], [ 'customjsonprotected', 'bogus' ] ],
+                       [ [ 'badaccess-group0' ] ],
+                       [ [ 'badaccess-group0' ], [ 'customjsonprotected', 'bogus' ] ],
+                       [ [ 'badaccess-groups' ] ]
+               );
+       }
+
+       /**
+        * @todo This test method should be split up into separate test methods and
+        * data providers
+        * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
+        */
+       public function testOtherCssConfigEditPermissions() {
+               $this->setUser( $this->userName );
+
+               $this->setTitle( NS_USER, $this->altUserName . '/test.css' );
+               $this->runConfigEditPermissions(
+                       [ [ 'badaccess-group0' ], [ 'customcssprotected', 'bogus' ] ],
+
+                       [ [ 'badaccess-group0' ], [ 'customcssprotected', 'bogus' ] ],
+                       [ [ 'badaccess-group0' ], [ 'customcssprotected', 'bogus' ] ],
+                       [ [ 'badaccess-group0' ], [ 'customcssprotected', 'bogus' ] ],
+
+                       [ [ 'badaccess-group0' ] ],
+                       [ [ 'badaccess-group0' ], [ 'customcssprotected', 'bogus' ] ],
+                       [ [ 'badaccess-group0' ], [ 'customcssprotected', 'bogus' ] ],
+                       [ [ 'badaccess-groups' ] ]
+               );
+       }
+
+       /**
+        * @todo This test method should be split up into separate test methods and
+        * data providers
+        * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
+        */
+       public function testOtherNonConfigEditPermissions() {
+               $this->setUser( $this->userName );
+
+               $this->setTitle( NS_USER, $this->altUserName . '/tempo' );
+               $this->runConfigEditPermissions(
+                       [ [ 'badaccess-group0' ] ],
+
+                       [ [ 'badaccess-group0' ] ],
+                       [ [ 'badaccess-group0' ] ],
+                       [ [ 'badaccess-group0' ] ],
+
+                       [ [ 'badaccess-group0' ] ],
+                       [ [ 'badaccess-group0' ] ],
+                       [ [ 'badaccess-group0' ] ],
+                       [ [ 'badaccess-groups' ] ]
+               );
+       }
+
+       /**
+        * @todo This should use data providers like the other methods here.
+        * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
+        */
+       public function testPatrolActionConfigEditPermissions() {
+               $this->setUser( 'anon' );
+               $this->setTitle( NS_USER, 'ToPatrolOrNotToPatrol' );
+               $this->runConfigEditPermissions(
+                       [ [ 'badaccess-group0' ] ],
+
+                       [ [ 'badaccess-group0' ] ],
+                       [ [ 'badaccess-group0' ] ],
+                       [ [ 'badaccess-group0' ] ],
+
+                       [ [ 'badaccess-group0' ] ],
+                       [ [ 'badaccess-group0' ] ],
+                       [ [ 'badaccess-group0' ] ],
+                       [ [ 'badaccess-groups' ] ]
+               );
+       }
+
+       protected function runConfigEditPermissions(
+               $resultNone,
+               $resultMyCss,
+               $resultMyJson,
+               $resultMyJs,
+               $resultUserCss,
+               $resultUserJson,
+               $resultUserJs,
+               $resultPatrol
+       ) {
+               $this->setUserPerm( '' );
+               $result = $this->permissionManager
+                       ->getPermissionErrors( 'bogus', $this->user, $this->title );
+               $this->assertEquals( $resultNone, $result );
+
+               $this->setUserPerm( 'editmyusercss' );
+               $result = $this->permissionManager
+                       ->getPermissionErrors( 'bogus', $this->user, $this->title );
+               $this->assertEquals( $resultMyCss, $result );
+
+               $this->setUserPerm( 'editmyuserjson' );
+               $result = $this->permissionManager
+                       ->getPermissionErrors( 'bogus', $this->user, $this->title );
+               $this->assertEquals( $resultMyJson, $result );
+
+               $this->setUserPerm( 'editmyuserjs' );
+               $result = $this->permissionManager
+                       ->getPermissionErrors( 'bogus', $this->user, $this->title );
+               $this->assertEquals( $resultMyJs, $result );
+
+               $this->setUserPerm( 'editusercss' );
+               $result = $this->permissionManager
+                       ->getPermissionErrors( 'bogus', $this->user, $this->title );
+               $this->assertEquals( $resultUserCss, $result );
+
+               $this->setUserPerm( 'edituserjson' );
+               $result = $this->permissionManager
+                       ->getPermissionErrors( 'bogus', $this->user, $this->title );
+               $this->assertEquals( $resultUserJson, $result );
+
+               $this->setUserPerm( 'edituserjs' );
+               $result = $this->permissionManager
+                       ->getPermissionErrors( 'bogus', $this->user, $this->title );
+               $this->assertEquals( $resultUserJs, $result );
+
+               $this->setUserPerm( '' );
+               $result = $this->permissionManager
+                       ->getPermissionErrors( 'patrol', $this->user, $this->title );
+               $this->assertEquals( reset( $resultPatrol[0] ), reset( $result[0] ) );
+
+               $this->setUserPerm( [ 'edituserjs', 'edituserjson', 'editusercss' ] );
+               $result = $this->permissionManager
+                       ->getPermissionErrors( 'bogus', $this->user, $this->title );
+               $this->assertEquals( [ [ 'badaccess-group0' ] ], $result );
+       }
+
+       /**
+        * @todo This test method should be split up into separate test methods and
+        * data providers
+        *
+        * This test is failing per T201776.
+        *
+        * @group Broken
+        * @covers \MediaWiki\Permissions\PermissionManager::checkPageRestrictions
+        */
+       public function testPageRestrictions() {
+               $prefix = MediaWikiServices::getInstance()->getContentLanguage()->
+               getFormattedNsText( NS_PROJECT );
+
+               $this->setTitle( NS_MAIN );
+               $this->title->mRestrictionsLoaded = true;
+               $this->setUserPerm( "edit" );
+               $this->title->mRestrictions = [ "bogus" => [ 'bogus', "sysop", "protect", "" ] ];
+
+               $this->assertEquals( [],
+                       $this->permissionManager->getPermissionErrors( 'edit',
+                               $this->user, $this->title ) );
+
+               $this->assertEquals( true,
+                       $this->permissionManager->userCan( 'edit', $this->user, $this->title,
+                               PermissionManager::RIGOR_QUICK ) );
+
+               $this->title->mRestrictions = [ "edit" => [ 'bogus', "sysop", "protect", "" ],
+                       "bogus" => [ 'bogus', "sysop", "protect", "" ] ];
+
+               $this->assertEquals( [ [ 'badaccess-group0' ],
+                       [ 'protectedpagetext', 'bogus', 'bogus' ],
+                       [ 'protectedpagetext', 'editprotected', 'bogus' ],
+                       [ 'protectedpagetext', 'protect', 'bogus' ] ],
+                       $this->permissionManager->getPermissionErrors( 'bogus',
+                               $this->user, $this->title ) );
+               $this->assertEquals( [ [ 'protectedpagetext', 'bogus', 'edit' ],
+                       [ 'protectedpagetext', 'editprotected', 'edit' ],
+                       [ 'protectedpagetext', 'protect', 'edit' ] ],
+                       $this->permissionManager->getPermissionErrors( 'edit',
+                               $this->user, $this->title ) );
+               $this->setUserPerm( "" );
+               $this->assertEquals( [ [ 'badaccess-group0' ],
+                       [ 'protectedpagetext', 'bogus', 'bogus' ],
+                       [ 'protectedpagetext', 'editprotected', 'bogus' ],
+                       [ 'protectedpagetext', 'protect', 'bogus' ] ],
+                       $this->permissionManager->getPermissionErrors( 'bogus',
+                               $this->user, $this->title ) );
+               $this->assertEquals( [ [ 'badaccess-groups', "*, [[$prefix:Users|Users]]", 2 ],
+                       [ 'protectedpagetext', 'bogus', 'edit' ],
+                       [ 'protectedpagetext', 'editprotected', 'edit' ],
+                       [ 'protectedpagetext', 'protect', 'edit' ] ],
+                       $this->permissionManager->getPermissionErrors( 'edit',
+                               $this->user, $this->title ) );
+               $this->setUserPerm( [ "edit", "editprotected" ] );
+               $this->assertEquals( [ [ 'badaccess-group0' ],
+                       [ 'protectedpagetext', 'bogus', 'bogus' ],
+                       [ 'protectedpagetext', 'protect', 'bogus' ] ],
+                       $this->permissionManager->getPermissionErrors( 'bogus',
+                               $this->user, $this->title ) );
+               $this->assertEquals( [
+                       [ 'protectedpagetext', 'bogus', 'edit' ],
+                       [ 'protectedpagetext', 'protect', 'edit' ] ],
+                       $this->permissionManager->getPermissionErrors( 'edit',
+                               $this->user, $this->title ) );
+
+               $this->title->mCascadeRestriction = true;
+               $this->setUserPerm( "edit" );
+
+               $this->assertEquals( false,
+                       $this->permissionManager->userCan( 'bogus', $this->user, $this->title,
+                               PermissionManager::RIGOR_QUICK ) );
+
+               $this->assertEquals( false,
+                       $this->permissionManager->userCan( 'edit', $this->user, $this->title,
+                               PermissionManager::RIGOR_QUICK ) );
+
+               $this->assertEquals( [ [ 'badaccess-group0' ],
+                       [ 'protectedpagetext', 'bogus', 'bogus' ],
+                       [ 'protectedpagetext', 'editprotected', 'bogus' ],
+                       [ 'protectedpagetext', 'protect', 'bogus' ] ],
+                       $this->permissionManager->getPermissionErrors( 'bogus',
+                               $this->user, $this->title ) );
+               $this->assertEquals( [ [ 'protectedpagetext', 'bogus', 'edit' ],
+                       [ 'protectedpagetext', 'editprotected', 'edit' ],
+                       [ 'protectedpagetext', 'protect', 'edit' ] ],
+                       $this->permissionManager->getPermissionErrors( 'edit',
+                               $this->user, $this->title ) );
+
+               $this->setUserPerm( [ "edit", "editprotected" ] );
+               $this->assertEquals( false,
+                       $this->permissionManager->userCan( 'bogus', $this->user, $this->title,
+                               PermissionManager::RIGOR_QUICK ) );
+
+               $this->assertEquals( false,
+                       $this->permissionManager->userCan( 'edit', $this->user, $this->title,
+                               PermissionManager::RIGOR_QUICK ) );
+
+               $this->assertEquals( [ [ 'badaccess-group0' ],
+                       [ 'protectedpagetext', 'bogus', 'bogus' ],
+                       [ 'protectedpagetext', 'protect', 'bogus' ],
+                       [ 'protectedpagetext', 'protect', 'bogus' ] ],
+                       $this->permissionManager->getPermissionErrors( 'bogus',
+                               $this->user, $this->title ) );
+               $this->assertEquals( [ [ 'protectedpagetext', 'bogus', 'edit' ],
+                       [ 'protectedpagetext', 'protect', 'edit' ],
+                       [ 'protectedpagetext', 'protect', 'edit' ] ],
+                       $this->permissionManager->getPermissionErrors( 'edit',
+                               $this->user, $this->title ) );
+       }
+
+       /**
+        * @covers \MediaWiki\Permissions\PermissionManager::checkCascadingSourcesRestrictions
+        */
+       public function testCascadingSourcesRestrictions() {
+               $this->setTitle( NS_MAIN, "test page" );
+               $this->setUserPerm( [ "edit", "bogus" ] );
+
+               $this->title->mCascadeSources = [
+                       Title::makeTitle( NS_MAIN, "Bogus" ),
+                       Title::makeTitle( NS_MAIN, "UnBogus" )
+               ];
+               $this->title->mCascadingRestrictions = [
+                       "bogus" => [ 'bogus', "sysop", "protect", "" ]
+               ];
+
+               $this->assertEquals( false,
+                       $this->permissionManager->userCan( 'bogus', $this->user, $this->title ) );
+               $this->assertEquals( [
+                       [ "cascadeprotected", 2, "* [[:Bogus]]\n* [[:UnBogus]]\n", 'bogus' ],
+                       [ "cascadeprotected", 2, "* [[:Bogus]]\n* [[:UnBogus]]\n", 'bogus' ],
+                       [ "cascadeprotected", 2, "* [[:Bogus]]\n* [[:UnBogus]]\n", 'bogus' ] ],
+                       $this->permissionManager->getPermissionErrors( 'bogus', $this->user, $this->title ) );
+
+               $this->assertEquals( true,
+                       $this->permissionManager->userCan( 'edit', $this->user, $this->title ) );
+               $this->assertEquals( [],
+                       $this->permissionManager->getPermissionErrors( 'edit', $this->user, $this->title ) );
+       }
+
+       /**
+        * @todo This test method should be split up into separate test methods and
+        * data providers
+        * @covers \MediaWiki\Permissions\PermissionManager::checkActionPermissions
+        */
+       public function testActionPermissions() {
+               $this->setUserPerm( [ "createpage" ] );
+               $this->setTitle( NS_MAIN, "test page" );
+               $this->title->mTitleProtection['permission'] = '';
+               $this->title->mTitleProtection['user'] = $this->user->getId();
+               $this->title->mTitleProtection['expiry'] = 'infinity';
+               $this->title->mTitleProtection['reason'] = 'test';
+               $this->title->mCascadeRestriction = false;
+
+               $this->assertEquals( [ [ 'titleprotected', 'Useruser', 'test' ] ],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'create', $this->user, $this->title ) );
+               $this->assertEquals( false,
+                       $this->permissionManager->userCan( 'create', $this->user, $this->title ) );
+
+               $this->title->mTitleProtection['permission'] = 'editprotected';
+               $this->setUserPerm( [ 'createpage', 'protect' ] );
+               $this->assertEquals( [ [ 'titleprotected', 'Useruser', 'test' ] ],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'create', $this->user, $this->title ) );
+               $this->assertEquals( false,
+                       $this->permissionManager->userCan( 'create', $this->user, $this->title ) );
+
+               $this->setUserPerm( [ 'createpage', 'editprotected' ] );
+               $this->assertEquals( [],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'create', $this->user, $this->title ) );
+               $this->assertEquals( true,
+                       $this->permissionManager->userCan( 'create', $this->user, $this->title ) );
+
+               $this->setUserPerm( [ 'createpage' ] );
+               $this->assertEquals( [ [ 'titleprotected', 'Useruser', 'test' ] ],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'create', $this->user, $this->title ) );
+               $this->assertEquals( false,
+                       $this->permissionManager->userCan( 'create', $this->user, $this->title ) );
+
+               $this->setTitle( NS_MEDIA, "test page" );
+               $this->setUserPerm( [ "move" ] );
+               $this->assertEquals( false,
+                       $this->permissionManager->userCan( 'move', $this->user, $this->title ) );
+               $this->assertEquals( [ [ 'immobile-source-namespace', 'Media' ] ],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'move', $this->user, $this->title ) );
+
+               $this->setTitle( NS_HELP, "test page" );
+               $this->assertEquals( [],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'move', $this->user, $this->title ) );
+               $this->assertEquals( true,
+                       $this->permissionManager->userCan( 'move', $this->user, $this->title ) );
+
+               $this->title->mInterwiki = "no";
+               $this->assertEquals( [ [ 'immobile-source-page' ] ],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'move', $this->user, $this->title ) );
+               $this->assertEquals( false,
+                       $this->permissionManager->userCan( 'move', $this->user, $this->title ) );
+
+               $this->setTitle( NS_MEDIA, "test page" );
+               $this->assertEquals( false,
+                       $this->permissionManager->userCan( 'move-target', $this->user, $this->title ) );
+               $this->assertEquals( [ [ 'immobile-target-namespace', 'Media' ] ],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
+
+               $this->setTitle( NS_HELP, "test page" );
+               $this->assertEquals( [],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
+               $this->assertEquals( true,
+                       $this->permissionManager->userCan( 'move-target', $this->user, $this->title ) );
+
+               $this->title->mInterwiki = "no";
+               $this->assertEquals( [ [ 'immobile-target-page' ] ],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
+               $this->assertEquals( false,
+                       $this->permissionManager->userCan( 'move-target', $this->user, $this->title ) );
+       }
+
+       /**
+        * @covers \MediaWiki\Permissions\PermissionManager::checkUserBlock
+        */
+       public function testUserBlock() {
+               $this->setMwGlobals( [
+                       'wgEmailConfirmToEdit' => true,
+                       'wgEmailAuthentication' => true,
+                       'wgBlockDisablesLogin' => false,
+               ] );
+
+               $this->overrideMwServices();
+               $this->permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+
+               $this->setUserPerm( [
+                       'createpage',
+                       'edit',
+                       'move',
+                       'rollback',
+                       'patrol',
+                       'upload',
+                       'purge'
+               ] );
+               $this->setTitle( NS_HELP, "test page" );
+
+               # $wgEmailConfirmToEdit only applies to 'edit' action
+               $this->assertEquals( [],
+                       $this->permissionManager->getPermissionErrors( 'move-target',
+                               $this->user, $this->title ) );
+               $this->assertContains( [ 'confirmedittext' ],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'edit', $this->user, $this->title ) );
+
+               $this->setMwGlobals( 'wgEmailConfirmToEdit', false );
+               $this->overrideMwServices();
+               $this->permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+
+               $this->assertNotContains( [ 'confirmedittext' ],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'edit', $this->user, $this->title ) );
+
+               # $wgEmailConfirmToEdit && !$user->isEmailConfirmed() && $action != 'createaccount'
+               $this->assertEquals( [],
+                       $this->permissionManager->getPermissionErrors( 'move-target',
+                               $this->user, $this->title ) );
+
+               global $wgLang;
+               $prev = time();
+               $now = time() + 120;
+               $this->user->mBlockedby = $this->user->getId();
+               $this->user->mBlock = new Block( [
+                       'address' => '127.0.8.1',
+                       'by' => $this->user->getId(),
+                       'reason' => 'no reason given',
+                       'timestamp' => $prev + 3600,
+                       'auto' => true,
+                       'expiry' => 0
+               ] );
+               $this->user->mBlock->mTimestamp = 0;
+               $this->assertEquals( [ [ 'autoblockedtext',
+                       '[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
+                       'Useruser', null, 'infinite', '127.0.8.1',
+                       $wgLang->timeanddate( wfTimestamp( TS_MW, $prev ), true ) ] ],
+                       $this->permissionManager->getPermissionErrors( 'move-target',
+                               $this->user, $this->title ) );
+
+               $this->assertEquals( false, $this->permissionManager
+                       ->userCan( 'move-target', $this->user, $this->title ) );
+               // quickUserCan should ignore user blocks
+               $this->assertEquals( true, $this->permissionManager
+                       ->userCan( 'move-target', $this->user, $this->title,
+                               PermissionManager::RIGOR_QUICK ) );
+
+               global $wgLocalTZoffset;
+               $wgLocalTZoffset = -60;
+               $this->user->mBlockedby = $this->user->getName();
+               $this->user->mBlock = new Block( [
+                       'address' => '127.0.8.1',
+                       'by' => $this->user->getId(),
+                       'reason' => 'no reason given',
+                       'timestamp' => $now,
+                       'auto' => false,
+                       'expiry' => 10,
+               ] );
+               $this->assertEquals( [ [ 'blockedtext',
+                       '[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
+                       'Useruser', null, '23:00, 31 December 1969', '127.0.8.1',
+                       $wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
+               # $action != 'read' && $action != 'createaccount' && $user->isBlockedFrom( $this )
+               #   $user->blockedFor() == ''
+               #   $user->mBlock->mExpiry == 'infinity'
+
+               $this->user->mBlockedby = $this->user->getName();
+               $this->user->mBlock = new SystemBlock( [
+                       'address' => '127.0.8.1',
+                       'by' => $this->user->getId(),
+                       'reason' => 'no reason given',
+                       'timestamp' => $now,
+                       'auto' => false,
+                       'systemBlock' => 'test',
+               ] );
+
+               $errors = [ [ 'systemblockedtext',
+                       '[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
+                       'Useruser', 'test', 'infinite', '127.0.8.1',
+                       $wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ];
+
+               $this->assertEquals( $errors,
+                       $this->permissionManager
+                               ->getPermissionErrors( 'edit', $this->user, $this->title ) );
+               $this->assertEquals( $errors,
+                       $this->permissionManager
+                               ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
+               $this->assertEquals( $errors,
+                       $this->permissionManager
+                               ->getPermissionErrors( 'rollback', $this->user, $this->title ) );
+               $this->assertEquals( $errors,
+                       $this->permissionManager
+                               ->getPermissionErrors( 'patrol', $this->user, $this->title ) );
+               $this->assertEquals( $errors,
+                       $this->permissionManager
+                               ->getPermissionErrors( 'upload', $this->user, $this->title ) );
+               $this->assertEquals( [],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'purge', $this->user, $this->title ) );
+
+               // partial block message test
+               $this->user->mBlockedby = $this->user->getName();
+               $this->user->mBlock = new Block( [
+                       'address' => '127.0.8.1',
+                       'by' => $this->user->getId(),
+                       'reason' => 'no reason given',
+                       'timestamp' => $now,
+                       'sitewide' => false,
+                       'expiry' => 10,
+               ] );
+
+               $this->assertEquals( [],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'edit', $this->user, $this->title ) );
+               $this->assertEquals( [],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
+               $this->assertEquals( [],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'rollback', $this->user, $this->title ) );
+               $this->assertEquals( [],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'patrol', $this->user, $this->title ) );
+               $this->assertEquals( [],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'upload', $this->user, $this->title ) );
+               $this->assertEquals( [],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'purge', $this->user, $this->title ) );
+
+               $this->user->mBlock->setRestrictions( [
+                       ( new PageRestriction( 0, $this->title->getArticleID() ) )->setTitle( $this->title ),
+               ] );
+
+               $errors = [ [ 'blockedtext-partial',
+                       '[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
+                       'Useruser', null, '23:00, 31 December 1969', '127.0.8.1',
+                       $wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ];
+
+               $this->assertEquals( $errors,
+                       $this->permissionManager
+                               ->getPermissionErrors( 'edit', $this->user, $this->title ) );
+               $this->assertEquals( $errors,
+                       $this->permissionManager
+                               ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
+               $this->assertEquals( $errors,
+                       $this->permissionManager
+                               ->getPermissionErrors( 'rollback', $this->user, $this->title ) );
+               $this->assertEquals( $errors,
+                       $this->permissionManager
+                               ->getPermissionErrors( 'patrol', $this->user, $this->title ) );
+               $this->assertEquals( [],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'upload', $this->user, $this->title ) );
+               $this->assertEquals( [],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'purge', $this->user, $this->title ) );
+
+               // Test no block.
+               $this->user->mBlockedby = null;
+               $this->user->mBlock = null;
+
+               $this->assertEquals( [],
+                       $this->permissionManager
+                               ->getPermissionErrors( 'edit', $this->user, $this->title ) );
+       }
+
+       /**
+        * @covers \MediaWiki\Permissions\PermissionManager::checkUserBlock
+        *
+        * Tests to determine that the passed in permission does not get mixed up with
+        * an action of the same name.
+        */
+       public function testUserBlockAction() {
+               global $wgLang;
+
+               $tester = $this->getMockBuilder( Action::class )
+                                          ->disableOriginalConstructor()
+                                          ->getMock();
+               $tester->method( 'getName' )
+                          ->willReturn( 'tester' );
+               $tester->method( 'getRestriction' )
+                          ->willReturn( 'test' );
+               $tester->method( 'requiresUnblock' )
+                          ->willReturn( false );
+
+               $this->setMwGlobals( [
+                       'wgActions' => [
+                               'tester' => $tester,
+                       ],
+                       'wgGroupPermissions' => [
+                               '*' => [
+                                       'tester' => true,
+                               ],
+                       ],
+               ] );
+
+               $now = time();
+               $this->user->mBlockedby = $this->user->getName();
+               $this->user->mBlock = new Block( [
+                       'address' => '127.0.8.1',
+                       'by' => $this->user->getId(),
+                       'reason' => 'no reason given',
+                       'timestamp' => $now,
+                       'auto' => false,
+                       'expiry' => 'infinity',
+               ] );
+
+               $errors = [ [ 'blockedtext',
+                       '[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
+                       'Useruser', null, 'infinite', '127.0.8.1',
+                       $wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ];
+
+               $this->assertEquals( $errors,
+                       $this->permissionManager
+                               ->getPermissionErrors( 'tester', $this->user, $this->title ) );
+       }
+
+       /**
+        * @covers \MediaWiki\Permissions\PermissionManager::isBlockedFrom
+        */
+       public function testBlockInstanceCache() {
+               // First, check the user isn't blocked
+               $user = $this->getMutableTestUser()->getUser();
+               $ut = Title::makeTitle( NS_USER_TALK, $user->getName() );
+               $this->assertNull( $user->getBlock( false ), 'sanity check' );
+               //$this->assertSame( '', $user->blockedBy(), 'sanity check' );
+               //$this->assertSame( '', $user->blockedFor(), 'sanity check' );
+               //$this->assertFalse( (bool)$user->isHidden(), 'sanity check' );
+               $this->assertFalse( $this->permissionManager
+                       ->isBlockedFrom( $user, $ut ), 'sanity check' );
+
+               // Block the user
+               $blocker = $this->getTestSysop()->getUser();
+               $block = new Block( [
+                       'hideName' => true,
+                       'allowUsertalk' => false,
+                       'reason' => 'Because',
+               ] );
+               $block->setTarget( $user );
+               $block->setBlocker( $blocker );
+               $res = $block->insert();
+               $this->assertTrue( (bool)$res['id'], 'sanity check: Failed to insert block' );
+
+               // Clear cache and confirm it loaded the block properly
+               $user->clearInstanceCache();
+               $this->assertInstanceOf( Block::class, $user->getBlock( false ) );
+               //$this->assertSame( $blocker->getName(), $user->blockedBy() );
+               //$this->assertSame( 'Because', $user->blockedFor() );
+               //$this->assertTrue( (bool)$user->isHidden() );
+               $this->assertTrue( $this->permissionManager->isBlockedFrom( $user, $ut ) );
+
+               // Unblock
+               $block->delete();
+
+               // Clear cache and confirm it loaded the not-blocked properly
+               $user->clearInstanceCache();
+               $this->assertNull( $user->getBlock( false ) );
+               //$this->assertSame( '', $user->blockedBy() );
+               //$this->assertSame( '', $user->blockedFor() );
+               //$this->assertFalse( (bool)$user->isHidden() );
+               $this->assertFalse( $this->permissionManager->isBlockedFrom( $user, $ut ) );
+       }
+
+       /**
+        * @covers \MediaWiki\Permissions\PermissionManager::isBlockedFrom
+        * @dataProvider provideIsBlockedFrom
+        * @param string|null $title Title to test.
+        * @param bool $expect Expected result from User::isBlockedFrom()
+        * @param array $options Additional test options:
+        *  - 'blockAllowsUTEdit': (bool, default true) Value for $wgBlockAllowsUTEdit
+        *  - 'allowUsertalk': (bool, default false) Passed to Block::__construct()
+        *  - 'pageRestrictions': (array|null) If non-empty, page restriction titles for the block.
+        */
+       public function testIsBlockedFrom( $title, $expect, array $options = [] ) {
+               $this->setMwGlobals( [
+                       'wgBlockAllowsUTEdit' => $options['blockAllowsUTEdit'] ?? true,
+               ] );
+
+               $user = $this->getTestUser()->getUser();
+
+               if ( $title === self::USER_TALK_PAGE ) {
+                       $title = $user->getTalkPage();
+               } else {
+                       $title = Title::newFromText( $title );
+               }
+
+               $restrictions = [];
+               foreach ( $options['pageRestrictions'] ?? [] as $pagestr ) {
+                       $page = $this->getExistingTestPage(
+                               $pagestr === self::USER_TALK_PAGE ? $user->getTalkPage() : $pagestr
+                       );
+                       $restrictions[] = new PageRestriction( 0, $page->getId() );
+               }
+               foreach ( $options['namespaceRestrictions'] ?? [] as $ns ) {
+                       $restrictions[] = new NamespaceRestriction( 0, $ns );
+               }
+
+               $block = new Block( [
+                       'expiry' => wfTimestamp( TS_MW, wfTimestamp() + ( 40 * 60 * 60 ) ),
+                       'allowUsertalk' => $options['allowUsertalk'] ?? false,
+                       'sitewide' => !$restrictions,
+               ] );
+               $block->setTarget( $user );
+               $block->setBlocker( $this->getTestSysop()->getUser() );
+               if ( $restrictions ) {
+                       $block->setRestrictions( $restrictions );
+               }
+               $block->insert();
+
+               try {
+                       $this->assertSame( $expect, $this->permissionManager->isBlockedFrom( $user, $title ) );
+               } finally {
+                       $block->delete();
+               }
+       }
+
+       public static function provideIsBlockedFrom() {
+               return [
+                       'Sitewide block, basic operation' => [ 'Test page', true ],
+                       'Sitewide block, not allowing user talk' => [
+                               self::USER_TALK_PAGE, true, [
+                                       'allowUsertalk' => false,
+                               ]
+                       ],
+                       'Sitewide block, allowing user talk' => [
+                               self::USER_TALK_PAGE, false, [
+                                       'allowUsertalk' => true,
+                               ]
+                       ],
+                       'Sitewide block, allowing user talk but $wgBlockAllowsUTEdit is false' => [
+                               self::USER_TALK_PAGE, true, [
+                                       'allowUsertalk' => true,
+                                       'blockAllowsUTEdit' => false,
+                               ]
+                       ],
+                       'Partial block, blocking the page' => [
+                               'Test page', true, [
+                                       'pageRestrictions' => [ 'Test page' ],
+                               ]
+                       ],
+                       'Partial block, not blocking the page' => [
+                               'Test page 2', false, [
+                                       'pageRestrictions' => [ 'Test page' ],
+                               ]
+                       ],
+                       'Partial block, not allowing user talk but user talk page is not blocked' => [
+                               self::USER_TALK_PAGE, false, [
+                                       'allowUsertalk' => false,
+                                       'pageRestrictions' => [ 'Test page' ],
+                               ]
+                       ],
+                       'Partial block, allowing user talk but user talk page is blocked' => [
+                               self::USER_TALK_PAGE, true, [
+                                       'allowUsertalk' => true,
+                                       'pageRestrictions' => [ self::USER_TALK_PAGE ],
+                               ]
+                       ],
+                       'Partial block, user talk page is not blocked but $wgBlockAllowsUTEdit is false' => [
+                               self::USER_TALK_PAGE, false, [
+                                       'allowUsertalk' => false,
+                                       'pageRestrictions' => [ 'Test page' ],
+                                       'blockAllowsUTEdit' => false,
+                               ]
+                       ],
+                       'Partial block, user talk page is blocked and $wgBlockAllowsUTEdit is false' => [
+                               self::USER_TALK_PAGE, true, [
+                                       'allowUsertalk' => true,
+                                       'pageRestrictions' => [ self::USER_TALK_PAGE ],
+                                       'blockAllowsUTEdit' => false,
+                               ]
+                       ],
+                       'Partial user talk namespace block, not allowing user talk' => [
+                               self::USER_TALK_PAGE, true, [
+                                       'allowUsertalk' => false,
+                                       'namespaceRestrictions' => [ NS_USER_TALK ],
+                               ]
+                       ],
+                       'Partial user talk namespace block, allowing user talk' => [
+                               self::USER_TALK_PAGE, false, [
+                                       'allowUsertalk' => true,
+                                       'namespaceRestrictions' => [ NS_USER_TALK ],
+                               ]
+                       ],
+                       'Partial user talk namespace block, where $wgBlockAllowsUTEdit is false' => [
+                               self::USER_TALK_PAGE, true, [
+                                       'allowUsertalk' => true,
+                                       'namespaceRestrictions' => [ NS_USER_TALK ],
+                                       'blockAllowsUTEdit' => false,
+                               ]
+                       ],
+               ];
+       }
+
+}
index b14424f..8a0bfad 100644 (file)
@@ -98,12 +98,7 @@ class ReadOnlyModeTest extends MediaWikiTestCase {
        }
 
        private function createMode( $params, $makeLB ) {
-               $config = new HashConfig( [
-                       'ReadOnly' => $params['confMessage'],
-                       'ReadOnlyFile' => $this->createFile( $params ),
-               ] );
-
-               $rom = new ConfiguredReadOnlyMode( $config );
+               $rom = new ConfiguredReadOnlyMode( $params['confMessage'], $this->createFile( $params ) );
 
                if ( $makeLB ) {
                        $lb = $this->createLB( $params );
@@ -167,28 +162,4 @@ class ReadOnlyModeTest extends MediaWikiTestCase {
                $rom->setReason( 'override' );
                $this->assertSame( 'override', $rom->getReason() );
        }
-
-       /**
-        * @covers ReadOnlyMode::clearCache
-        * @covers ConfiguredReadOnlyMode::clearCache
-        */
-       public function testClearCache() {
-               $fileName = $this->getNewTempFile();
-               unlink( $fileName );
-               $config = new HashConfig( [
-                       'ReadOnly' => null,
-                       'ReadOnlyFile' => $fileName,
-               ] );
-               $cro = new ConfiguredReadOnlyMode( $config );
-               $lb = $this->createLB( [ 'lbMessage' => false ] );
-               $rom = new ReadOnlyMode( $cro, $lb );
-
-               $this->assertSame( false, $rom->getReason(), 'initial' );
-
-               file_put_contents( $fileName, 'file' );
-               $this->assertSame( false, $rom->getReason(), 'stale' );
-
-               $rom->clearCache();
-               $this->assertSame( 'file', $rom->getReason(), 'fresh' );
-       }
 }
index 51c483d..3467153 100644 (file)
@@ -81,7 +81,7 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase {
                $this->setMwGlobals( [
                        'wgMultiContentRevisionSchemaMigrationStage' => $this->getMcrMigrationStage(),
                        'wgContentHandlerUseDB' => $this->getContentHandlerUseDB(),
-                       'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
+                       'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
                ] );
 
                $this->overrideMwServices();
@@ -438,9 +438,19 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase {
                $queryInfo = $store->getQueryInfo( [ 'user' ] );
 
                $row = get_object_vars( $row );
+
+               // Use aliased fields from $queryInfo, e.g. rev_user
+               $keys = array_keys( $row );
+               $keys = array_combine( $keys, $keys );
+               $fields = array_intersect_key( $queryInfo['fields'], $keys ) + $keys;
+
+               // assertSelect() fails unless the orders match.
+               ksort( $fields );
+               ksort( $row );
+
                $this->assertSelect(
                        $queryInfo['tables'],
-                       array_keys( $row ),
+                       $fields,
                        [ 'rev_id' => $rev->getId() ],
                        [ array_values( $row ) ],
                        [],
@@ -800,7 +810,7 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase {
                        'rev_page' => (string)$rev->getPage(),
                        'rev_timestamp' => $this->db->timestamp( $rev->getTimestamp() ),
                        'rev_user_text' => (string)$rev->getUserText(),
-                       'rev_user' => (string)$rev->getUser(),
+                       'rev_user' => (string)$rev->getUser() ?: null,
                        'rev_minor_edit' => $rev->isMinor() ? '1' : '0',
                        'rev_deleted' => (string)$rev->getVisibility(),
                        'rev_len' => (string)$rev->getSize(),
@@ -1406,10 +1416,7 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase {
                        ->value['revision'];
 
                $store = MediaWikiServices::getInstance()->getRevisionStore();
-               $result = $store->getTimestampFromId(
-                       $page->getTitle(),
-                       $rev->getId()
-               );
+               $result = $store->getTimestampFromId( $rev->getId() );
 
                $this->assertSame( $rev->getTimestamp(), $result );
        }
@@ -1424,10 +1431,7 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase {
                        ->value['revision'];
 
                $store = MediaWikiServices::getInstance()->getRevisionStore();
-               $result = $store->getTimestampFromId(
-                       $page->getTitle(),
-                       $rev->getId() + 1
-               );
+               $result = $store->getTimestampFromId( $rev->getId() + 1 );
 
                $this->assertFalse( $result );
        }
@@ -1808,7 +1812,10 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase {
                /** @var Revision $rev */
                $rev = $page->doEditContent(
                        new WikitextContent( $text ),
-                       __METHOD__
+                       __METHOD__,
+                       0,
+                       false,
+                       $this->getMutableTestUser()->getUser()
                )->value['revision'];
 
                $store = MediaWikiServices::getInstance()->getRevisionStore();
index 1ddc254..5246e36 100644 (file)
@@ -528,12 +528,10 @@ class RevisionStoreTest extends MediaWikiTestCase {
                                'old_text' => 'Hello World',
                                'old_flags' => 'utf-8',
                        ];
-               } else {
-                       if ( !isset( $row['content'] ) && isset( $array['old_text'] ) ) {
-                               $row['content'] = [
-                                       'main' => new WikitextContent( $array['old_text'] ),
-                               ];
-                       }
+               } elseif ( !isset( $row['content'] ) && isset( $array['old_text'] ) ) {
+                       $row['content'] = [
+                               'main' => new WikitextContent( $array['old_text'] ),
+                       ];
                }
 
                return (object)$row;
index a17d21d..7501167 100644 (file)
@@ -26,6 +26,7 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                        [
                                'page',
                                'revision',
+                               'comment',
                                'ip_changes',
                                'text',
                                'archive',
@@ -90,7 +91,7 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                $this->setMwGlobals( [
                        'wgMultiContentRevisionSchemaMigrationStage' => $this->getMcrMigrationStage(),
                        'wgContentHandlerUseDB' => $this->getContentHandlerUseDB(),
-                       'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
+                       'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
                ] );
 
                $this->overrideMwServices();
@@ -181,7 +182,8 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                        ( $model === null || $model === CONTENT_MODEL_WIKITEXT )
                ) {
                        $ns = $this->getDefaultWikitextNS();
-                       $titleString = MWNamespace::getCanonicalName( $ns ) . ':' . $titleString;
+                       $titleString = MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               getCanonicalName( $ns ) . ':' . $titleString;
                }
 
                $title = Title::newFromText( $titleString );
@@ -624,6 +626,34 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                $this->assertEquals( $latestRevision, $newRevision->getPrevious()->getId() );
        }
 
+       /**
+        * @covers Title::getPreviousRevisionID
+        * @covers Title::getRelativeRevisionID
+        * @covers MediaWiki\Revision\RevisionStore::getPreviousRevision
+        * @covers MediaWiki\Revision\RevisionStore::getRelativeRevision
+        */
+       public function testTitleGetPreviousRevisionID() {
+               $oldestId = $this->testPage->getOldestRevision()->getId();
+               $latestId = $this->testPage->getLatest();
+
+               $title = $this->testPage->getTitle();
+
+               $this->assertFalse( $title->getPreviousRevisionID( $oldestId ) );
+
+               $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
+               $newId = $this->testPage->getRevision()->getId();
+
+               $this->assertEquals( $latestId, $title->getPreviousRevisionID( $newId ) );
+       }
+
+       /**
+        * @covers Title::getPreviousRevisionID
+        * @covers Title::getRelativeRevisionID
+        */
+       public function testTitleGetPreviousRevisionID_invalid() {
+               $this->assertFalse( $this->testPage->getTitle()->getPreviousRevisionID( 123456789 ) );
+       }
+
        /**
         * @covers Revision::getNext
         */
@@ -639,6 +669,33 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                $this->assertEquals( $rev2->getId(), $rev1->getNext()->getId() );
        }
 
+       /**
+        * @covers Title::getNextRevisionID
+        * @covers Title::getRelativeRevisionID
+        * @covers MediaWiki\Revision\RevisionStore::getNextRevision
+        * @covers MediaWiki\Revision\RevisionStore::getRelativeRevision
+        */
+       public function testTitleGetNextRevisionID() {
+               $title = $this->testPage->getTitle();
+
+               $origId = $this->testPage->getLatest();
+
+               $this->assertFalse( $title->getNextRevisionID( $origId ) );
+
+               $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
+               $newId = $this->testPage->getLatest();
+
+               $this->assertSame( $this->testPage->getLatest(), $title->getNextRevisionID( $origId ) );
+       }
+
+       /**
+        * @covers Title::getNextRevisionID
+        * @covers Title::getRelativeRevisionID
+        */
+       public function testTitleGetNextRevisionID_invalid() {
+               $this->assertFalse( $this->testPage->getTitle()->getNextRevisionID( 123456789 ) );
+       }
+
        /**
         * @covers Revision::newNullRevision
         */
@@ -1396,6 +1453,9 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                $this->setService( 'MainWANObjectCache', $cache );
                $db = wfGetDB( DB_MASTER );
 
+               $now = 1553893742;
+               $cache->setMockTime( $now );
+
                // Get a fresh revision to use during testing
                $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
                $rev = $this->testPage->getRevision();
@@ -1410,6 +1470,8 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                $cache->delete( $key, WANObjectCache::HOLDOFF_NONE );
                $this->assertFalse( $cache->get( $key ) );
 
+               ++$now;
+
                // Get the new revision and make sure it is in the cache and correct
                $newRev = Revision::newKnownCurrent( $db, $rev->getPage(), $rev->getId() );
                $this->assertRevEquals( $rev, $newRev );
@@ -1579,11 +1641,7 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                $this->assertSame( $expected, $rev->getTextId() );
        }
 
-       public function provideGetRevisionText() {
-               yield [
-                       [ 'text' ]
-               ];
-       }
+       abstract public function provideGetRevisionText();
 
        /**
         * @dataProvider provideGetRevisionText
index bb62b2f..30a5484 100644 (file)
@@ -43,4 +43,9 @@ class RevisionMcrWriteBothDbTest extends RevisionDbTestBase {
                yield [ $row, 789 ];
        }
 
+       public function provideGetRevisionText() {
+               yield [
+                       [ 'text' ]
+               ];
+       }
 }
index 19eeab3..f19bc52 100644 (file)
@@ -44,4 +44,10 @@ class RevisionNoContentModelDbTest extends RevisionDbTestBase {
                yield [ $row, 789 ];
        }
 
+       public function provideGetRevisionText() {
+               yield [
+                       [ 'text' ]
+               ];
+       }
+
 }
index e520f2d..444c150 100644 (file)
@@ -44,4 +44,9 @@ class RevisionPreMcrDbTest extends RevisionDbTestBase {
                yield [ $row, 789 ];
        }
 
+       public function provideGetRevisionText() {
+               yield [
+                       [ 'text' ]
+               ];
+       }
 }
index 02a6c19..98f2980 100644 (file)
@@ -601,7 +601,7 @@ class RevisionTest extends MediaWikiTestCase {
         * @covers Revision::loadFromTitle
         */
        public function testLoadFromTitle() {
-               $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_OLD );
+               $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
                $this->overrideMwServices();
                $title = $this->getMockTitle();
 
@@ -640,6 +640,7 @@ class RevisionTest extends MediaWikiTestCase {
                                $this->equalTo( [
                                        'revision', 'page', 'user',
                                        'temp_rev_comment' => 'revision_comment_temp', 'comment_rev_comment' => 'comment',
+                                       'temp_rev_user' => 'revision_actor_temp', 'actor_rev_user' => 'actor',
                                ] ),
                                // We don't really care about the fields are they come from the selectField methods
                                $this->isType( 'array' ),
index 74e8e1b..02e06f8 100644 (file)
@@ -8,7 +8,7 @@ class ServiceWiringTest extends MediaWikiTestCase {
                global $IP;
                $services = array_keys( require "$IP/includes/ServiceWiring.php" );
                $sortedServices = $services;
-               sort( $sortedServices );
+               natcasesort( $sortedServices );
 
                $this->assertSame( $sortedServices, $services,
                        'Please keep services sorted alphabetically' );
index a6a92c6..b0d89a6 100644 (file)
@@ -10,11 +10,11 @@ class SiteStatsTest extends MediaWikiTestCase {
                $this->setService( 'MainWANObjectCache', $cache );
                $jobq = JobQueueGroup::singleton();
 
-               $jobq->push( new NullJob( Title::newMainPage(), [] ) );
+               $jobq->push( Job::factory( 'null', Title::newMainPage(), [] ) );
                $this->assertEquals( 1, SiteStats::jobs(),
                         'A single job enqueued bumps jobscount stat to 1' );
 
-               $jobq->push( new NullJob( Title::newMainPage(), [] ) );
+               $jobq->push( Job::factory( 'null', Title::newMainPage(), [] ) );
                $this->assertEquals( 1, SiteStats::jobs(),
                        'SiteStats::jobs() count does not reflect addition ' .
                        'of a second job (cached)'
index 92c6f62..cd19cca 100644 (file)
@@ -24,6 +24,7 @@ use User;
 use Wikimedia\TestingAccessWrapper;
 use WikiPage;
 use WikitextContent;
+use DeferredUpdates;
 
 /**
  * @group Database
@@ -60,16 +61,20 @@ class DerivedPageDataUpdaterTest extends MediaWikiTestCase {
 
        /**
         * @param string|Title|WikiPage $page
+        * @param RevisionRecord|null $rec
+        * @param User|null $user
         *
         * @return DerivedPageDataUpdater
         */
-       private function getDerivedPageDataUpdater( $page, RevisionRecord $rec = null ) {
+       private function getDerivedPageDataUpdater(
+               $page, RevisionRecord $rec = null, User $user = null
+       ) {
                if ( is_string( $page ) || $page instanceof Title ) {
                        $page = $this->getPage( $page );
                }
 
                $page = TestingAccessWrapper::newFromObject( $page );
-               return $page->getDerivedDataUpdater( null, $rec );
+               return $page->getDerivedDataUpdater( $user, $rec );
        }
 
        /**
@@ -78,11 +83,12 @@ class DerivedPageDataUpdaterTest extends MediaWikiTestCase {
         * @param WikiPage $page
         * @param string|Message|CommentStoreComment $summary
         * @param null|string|Content $content
+        * @param User|null $user
         *
         * @return RevisionRecord|null
         */
-       private function createRevision( WikiPage $page, $summary, $content = null ) {
-               $user = $this->getTestUser()->getUser();
+       private function createRevision( WikiPage $page, $summary, $content = null, $user = null ) {
+               $user = $user ?: $this->getTestUser()->getUser();
                $comment = CommentStoreComment::newUnsavedComment( $summary );
 
                if ( $content === null || is_string( $content ) ) {
@@ -945,6 +951,68 @@ class DerivedPageDataUpdaterTest extends MediaWikiTestCase {
                // TODO: test category membership update (with setRcWatchCategoryMembership())
        }
 
+       /**
+        * @covers \MediaWiki\Storage\DerivedPageDataUpdater::doUpdates()
+        * @covers \MediaWiki\Storage\DerivedPageDataUpdater::doSecondaryDataUpdates()
+        * @covers \MediaWiki\Storage\DerivedPageDataUpdater::doParserCacheUpdate()
+        */
+       public function testDoUpdatesCacheSaveDeferral_canonical() {
+               $page = $this->getPage( __METHOD__ );
+
+               // Case where user has canonical parser options
+               $content = [ 'main' => new WikitextContent( 'rev ID ver #1: {{REVISIONID}}' ) ];
+               $rev = $this->createRevision( $page, 'first', $content );
+               $pcache = MediaWikiServices::getInstance()->getParserCache();
+               $pcache->deleteOptionsKey( $page );
+
+               $this->db->startAtomic( __METHOD__ ); // let deferred updates queue up
+
+               $updater = $this->getDerivedPageDataUpdater( $page, $rev );
+               $updater->prepareUpdate( $rev, [] );
+               $updater->doUpdates();
+
+               $this->assertGreaterThan( 0, DeferredUpdates::pendingUpdatesCount(), 'Pending updates' );
+               $this->assertNotFalse( $pcache->get( $page, $updater->getCanonicalParserOptions() ) );
+
+               $this->db->endAtomic( __METHOD__ ); // run deferred updates
+
+               $this->assertEquals( 0, DeferredUpdates::pendingUpdatesCount(), 'No pending updates' );
+       }
+
+       /**
+        * @covers \MediaWiki\Storage\DerivedPageDataUpdater::doUpdates()
+        * @covers \MediaWiki\Storage\DerivedPageDataUpdater::doSecondaryDataUpdates()
+        * @covers \MediaWiki\Storage\DerivedPageDataUpdater::doParserCacheUpdate()
+        */
+       public function testDoUpdatesCacheSaveDeferral_noncanonical() {
+               $page = $this->getPage( __METHOD__ );
+
+               // Case where user does not have canonical parser options
+               $user = $this->getMutableTestUser()->getUser();
+               $user->setOption(
+                       'thumbsize',
+                       $user->getOption( 'thumbsize' ) + 1
+               );
+               $content = [ 'main' => new WikitextContent( 'rev ID ver #2: {{REVISIONID}}' ) ];
+               $rev = $this->createRevision( $page, 'first', $content, $user );
+               $pcache = MediaWikiServices::getInstance()->getParserCache();
+               $pcache->deleteOptionsKey( $page );
+
+               $this->db->startAtomic( __METHOD__ ); // let deferred updates queue up
+
+               $updater = $this->getDerivedPageDataUpdater( $page, $rev, $user );
+               $updater->prepareUpdate( $rev, [] );
+               $updater->doUpdates();
+
+               $this->assertGreaterThan( 1, DeferredUpdates::pendingUpdatesCount(), 'Pending updates' );
+               $this->assertFalse( $pcache->get( $page, $updater->getCanonicalParserOptions() ) );
+
+               $this->db->endAtomic( __METHOD__ ); // run deferred updates
+
+               $this->assertEquals( 0, DeferredUpdates::pendingUpdatesCount(), 'No pending updates' );
+               $this->assertNotFalse( $pcache->get( $page, $updater->getCanonicalParserOptions() ) );
+       }
+
        /**
         * @covers \MediaWiki\Storage\DerivedPageDataUpdater::doParserCacheUpdate()
         */
index 4c2494a..ca87b49 100644 (file)
@@ -62,24 +62,32 @@ class NameTableStoreTest extends MediaWikiTestCase {
                        ->getMock();
                $mock->expects( $this->exactly( $insertCalls ) )
                        ->method( 'insert' )
-                       ->willReturnCallback( function () {
-                               return call_user_func_array( [ $this->db, 'insert' ], func_get_args() );
+                       ->willReturnCallback( function ( ...$args ) {
+                               return call_user_func_array( [ $this->db, 'insert' ], $args );
                        } );
                $mock->expects( $this->exactly( $selectCalls ) )
                        ->method( 'select' )
-                       ->willReturnCallback( function () {
-                               return call_user_func_array( [ $this->db, 'select' ], func_get_args() );
+                       ->willReturnCallback( function ( ...$args ) {
+                               return call_user_func_array( [ $this->db, 'select' ], $args );
                        } );
                $mock->expects( $this->exactly( $insertCalls ) )
                        ->method( 'affectedRows' )
-                       ->willReturnCallback( function () {
-                               return call_user_func_array( [ $this->db, 'affectedRows' ], func_get_args() );
+                       ->willReturnCallback( function ( ...$args ) {
+                               return call_user_func_array( [ $this->db, 'affectedRows' ], $args );
                        } );
                $mock->expects( $this->any() )
                        ->method( 'insertId' )
-                       ->willReturnCallback( function () {
-                               return call_user_func_array( [ $this->db, 'insertId' ], func_get_args() );
+                       ->willReturnCallback( function ( ...$args ) {
+                               return call_user_func_array( [ $this->db, 'insertId' ], $args );
                        } );
+               $mock->expects( $this->any() )
+                       ->method( 'query' )
+                       ->willReturn( [] );
+               $mock->expects( $this->any() )
+                       ->method( 'isOpen' )
+                       ->willReturn( true );
+               $wrapper = TestingAccessWrapper::newFromObject( $mock );
+               $wrapper->queryLogger = new NullLogger();
                return $mock;
        }
 
@@ -216,17 +224,23 @@ class NameTableStoreTest extends MediaWikiTestCase {
        /**
         * @dataProvider provideGetName
         */
-       public function testGetName( $cacheBag, $insertCalls, $selectCalls ) {
+       public function testGetName( BagOStuff $cacheBag, $insertCalls, $selectCalls ) {
+               $now = microtime( true );
+               $cacheBag->setMockTime( $now );
                // Check for operations to in-memory cache (IMC) and persistent cache (PC)
                $store = $this->getNameTableSqlStore( $cacheBag, $insertCalls, $selectCalls );
 
                // Get 1 ID and make sure getName returns correctly
                $fooId = $store->acquireId( 'foo' ); // regen PC, set IMC, update IMC, tombstone PC
+               $now += 0.01;
                $this->assertSame( 'foo', $store->getName( $fooId ) ); // use IMC
+               $now += 0.01;
 
                // Get another ID and make sure getName returns correctly
                $barId = $store->acquireId( 'bar' ); // update IMC, tombstone PC
+               $now += 0.01;
                $this->assertSame( 'bar', $store->getName( $barId ) ); // use IMC
+               $now += 0.01;
 
                // Blitz the cache and make sure it still returns
                TestingAccessWrapper::newFromObject( $store )->tableCache = null; // clear IMC
@@ -236,6 +250,7 @@ class NameTableStoreTest extends MediaWikiTestCase {
                // Blitz the cache again and get another ID and make sure getName returns correctly
                TestingAccessWrapper::newFromObject( $store )->tableCache = null; // clear IMC
                $bazId = $store->acquireId( 'baz' ); // set IMC using interim PC, update IMC, tombstone PC
+               $now += 0.01;
                $this->assertSame( 'baz', $store->getName( $bazId ) ); // uses IMC
                $this->assertSame( 'baz', $store->getName( $bazId ) ); // uses IMC
        }
diff --git a/tests/phpunit/includes/Storage/PreparedEditTest.php b/tests/phpunit/includes/Storage/PreparedEditTest.php
new file mode 100644 (file)
index 0000000..29999ee
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+
+namespace MediaWiki\Edit;
+
+use ParserOutput;
+use MediaWikiTestCase;
+
+/**
+ * @covers \MediaWiki\Edit\PreparedEdit
+ */
+class PreparedEditTest extends MediaWikiTestCase {
+       function testCallback() {
+               $output = new ParserOutput();
+               $edit = new PreparedEdit();
+               $edit->parserOutputCallback = function () {
+                       return new ParserOutput();
+               };
+
+               $this->assertEquals( $output, $edit->getOutput() );
+               $this->assertEquals( $output, $edit->output );
+       }
+}
diff --git a/tests/phpunit/includes/SystemBlockTest.php b/tests/phpunit/includes/SystemBlockTest.php
new file mode 100644 (file)
index 0000000..321b25e
--- /dev/null
@@ -0,0 +1,21 @@
+<?php
+
+use MediaWiki\Block\SystemBlock;
+
+/**
+ * @group Blocking
+ * @coversDefaultClass \MediaWiki\Block\SystemBlock
+ */
+class SystemBlockTest extends MediaWikiLangTestCase {
+       /**
+        * @covers ::getSystemBlockType
+        */
+       public function testSystemBlockType() {
+               $block = new SystemBlock( [
+                       'systemBlock' => 'proxy',
+               ] );
+
+               $this->assertSame( 'proxy', $block->getSystemBlockType() );
+       }
+
+}
index 3064a3d..40a5dc5 100644 (file)
@@ -33,7 +33,7 @@ class TestUserRegistry {
         */
        public static function getMutableTestUser( $testName, $groups = [] ) {
                $id = self::getNextId();
-               $password = wfRandomString( 20 );
+               $password = "password_for_test_user_id_{$id}";
                $testUser = new TestUser(
                        "TestUser $testName $id",  // username
                        "Name $id",                // real name
@@ -75,7 +75,7 @@ class TestUserRegistry {
                                $password = 'UTSysopPassword';
                        } else {
                                $username = "TestUser $id";
-                               $password = wfRandomString( 20 );
+                               $password = "password_for_test_user_id_{$id}";
                        }
                        self::$testUsers[$key] = $testUser = new TestUser(
                                $username,            // username
index 25dc9b3..abd70b2 100644 (file)
@@ -31,30 +31,6 @@ class TitleMethodsTest extends MediaWikiLangTestCase {
                );
        }
 
-       public static function provideEquals() {
-               return [
-                       [ 'Main Page', 'Main Page', true ],
-                       [ 'Main Page', 'Not The Main Page', false ],
-                       [ 'Main Page', 'Project:Main Page', false ],
-                       [ 'File:Example.png', 'Image:Example.png', true ],
-                       [ 'Special:Version', 'Special:Version', true ],
-                       [ 'Special:Version', 'Special:Recentchanges', false ],
-                       [ 'Special:Version', 'Main Page', false ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideEquals
-        * @covers Title::equals
-        */
-       public function testEquals( $titleA, $titleB, $expectedBool ) {
-               $titleA = Title::newFromText( $titleA );
-               $titleB = Title::newFromText( $titleB );
-
-               $this->assertEquals( $expectedBool, $titleA->equals( $titleB ) );
-               $this->assertEquals( $expectedBool, $titleB->equals( $titleA ) );
-       }
-
        public static function provideInNamespace() {
                return [
                        [ 'Main Page', NS_MAIN, true ],
index 3d8c643..1f8011d 100644 (file)
@@ -1,13 +1,14 @@
 <?php
 
 use MediaWiki\Block\Restriction\PageRestriction;
+use MediaWiki\Block\SystemBlock;
 use MediaWiki\MediaWikiServices;
 
 /**
  * @group Database
  *
- * @covers Title::getUserPermissionsErrors
- * @covers Title::getUserPermissionsErrorsInternal
+ * @covers \MediaWiki\Permissions\PermissionManager::getPermissionErrors
+ * @covers \MediaWiki\Permissions\PermissionManager::getPermissionErrorsInternal
  */
 class TitlePermissionTest extends MediaWikiLangTestCase {
 
@@ -104,7 +105,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
         * This test is failing per T201776.
         *
         * @group Broken
-        * @covers Title::checkQuickPermissions
+        * @covers \MediaWiki\Permissions\PermissionManager::checkQuickPermissions
         */
        public function testQuickPermissions() {
                $prefix = MediaWikiServices::getInstance()->getContentLanguage()->
@@ -395,7 +396,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
        /**
         * @todo This test method should be split up into separate test methods and
         * data providers
-        * @covers Title::checkSpecialsAndNSPermissions
+        * @covers \MediaWiki\Permissions\PermissionManager::checkSpecialsAndNSPermissions
         */
        public function testSpecialsAndNSPermissions() {
                global $wgNamespaceProtection;
@@ -452,7 +453,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
        /**
         * @todo This test method should be split up into separate test methods and
         * data providers
-        * @covers Title::checkUserConfigPermissions
+        * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
         */
        public function testJsConfigEditPermissions() {
                $this->setUser( $this->userName );
@@ -475,7 +476,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
        /**
         * @todo This test method should be split up into separate test methods and
         * data providers
-        * @covers Title::checkUserConfigPermissions
+        * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
         */
        public function testJsonConfigEditPermissions() {
                $prefix = MediaWikiServices::getInstance()->getContentLanguage()->
@@ -500,7 +501,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
        /**
         * @todo This test method should be split up into separate test methods and
         * data providers
-        * @covers Title::checkUserConfigPermissions
+        * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
         */
        public function testCssConfigEditPermissions() {
                $this->setUser( $this->userName );
@@ -523,7 +524,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
        /**
         * @todo This test method should be split up into separate test methods and
         * data providers
-        * @covers Title::checkUserConfigPermissions
+        * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
         */
        public function testOtherJsConfigEditPermissions() {
                $this->setUser( $this->userName );
@@ -546,7 +547,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
        /**
         * @todo This test method should be split up into separate test methods and
         * data providers
-        * @covers Title::checkUserConfigPermissions
+        * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
         */
        public function testOtherJsonConfigEditPermissions() {
                $this->setUser( $this->userName );
@@ -569,7 +570,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
        /**
         * @todo This test method should be split up into separate test methods and
         * data providers
-        * @covers Title::checkUserConfigPermissions
+        * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
         */
        public function testOtherCssConfigEditPermissions() {
                $this->setUser( $this->userName );
@@ -592,7 +593,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
        /**
         * @todo This test method should be split up into separate test methods and
         * data providers
-        * @covers Title::checkUserConfigPermissions
+        * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
         */
        public function testOtherNonConfigEditPermissions() {
                $this->setUser( $this->userName );
@@ -614,7 +615,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
 
        /**
         * @todo This should use data providers like the other methods here.
-        * @covers Title::checkUserConfigPermissions
+        * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
         */
        public function testPatrolActionConfigEditPermissions() {
                $this->setUser( 'anon' );
@@ -687,7 +688,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
         * This test is failing per T201776.
         *
         * @group Broken
-        * @covers Title::checkPageRestrictions
+        * @covers \MediaWiki\Permissions\PermissionManager::checkPageRestrictions
         */
        public function testPageRestrictions() {
                $prefix = MediaWikiServices::getInstance()->getContentLanguage()->
@@ -780,7 +781,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
        }
 
        /**
-        * @covers Title::checkCascadingSourcesRestrictions
+        * @covers \MediaWiki\Permissions\PermissionManager::checkCascadingSourcesRestrictions
         */
        public function testCascadingSourcesRestrictions() {
                $this->setTitle( NS_MAIN, "test page" );
@@ -811,7 +812,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
        /**
         * @todo This test method should be split up into separate test methods and
         * data providers
-        * @covers Title::checkActionPermissions
+        * @covers \MediaWiki\Permissions\PermissionManager::checkActionPermissions
         */
        public function testActionPermissions() {
                $this->setUserPerm( [ "createpage" ] );
@@ -885,13 +886,15 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
        }
 
        /**
-        * @covers Title::checkUserBlock
+        * @covers \MediaWiki\Permissions\PermissionManager::checkUserBlock
         */
        public function testUserBlock() {
                $this->setMwGlobals( [
                        'wgEmailConfirmToEdit' => true,
                        'wgEmailAuthentication' => true,
+                       'wgBlockDisablesLogin' => false,
                ] );
+               $this->overrideMwServices();
 
                $this->setUserPerm( [ 'createpage', 'edit', 'move', 'rollback', 'patrol', 'upload', 'purge' ] );
                $this->setTitle( NS_HELP, "test page" );
@@ -903,6 +906,8 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
                        $this->title->getUserPermissionsErrors( 'edit', $this->user ) );
 
                $this->setMwGlobals( 'wgEmailConfirmToEdit', false );
+               $this->overrideMwServices();
+
                $this->assertNotContains( [ 'confirmedittext' ],
                        $this->title->getUserPermissionsErrors( 'edit', $this->user ) );
 
@@ -923,7 +928,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
                        'auto' => true,
                        'expiry' => 0
                ] );
-               $this->user->mBlock->mTimestamp = 0;
+               $this->user->mBlock->setTimestamp( 0 );
                $this->assertEquals( [ [ 'autoblockedtext',
                                '[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
                                'Useruser', null, 'infinite', '127.0.8.1',
@@ -956,19 +961,17 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
                #   $user->mBlock->mExpiry == 'infinity'
 
                $this->user->mBlockedby = $this->user->getName();
-               $this->user->mBlock = new Block( [
+               $this->user->mBlock = new SystemBlock( [
                        'address' => '127.0.8.1',
                        'by' => $this->user->getId(),
                        'reason' => 'no reason given',
                        'timestamp' => $now,
-                       'auto' => false,
-                       'expiry' => 10,
                        'systemBlock' => 'test',
                ] );
 
                $errors = [ [ 'systemblockedtext',
                                '[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
-                               'Useruser', 'test', '23:00, 31 December 1969', '127.0.8.1',
+                               'Useruser', 'test', 'infinite', '127.0.8.1',
                                $wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ];
 
                $this->assertEquals( $errors,
@@ -1039,7 +1042,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
        }
 
        /**
-        * @covers Title::checkUserBlock
+        * @covers \MediaWiki\Permissions\PermissionManager::checkUserBlock
         *
         * Tests to determine that the passed in permission does not get mixed up with
         * an action of the same name.
index 4af12a8..c46f69b 100644 (file)
@@ -1,6 +1,8 @@
 <?php
 
+use MediaWiki\Linker\LinkTarget;
 use MediaWiki\MediaWikiServices;
+use Wikimedia\TestingAccessWrapper;
 
 /**
  * @group Database
@@ -19,6 +21,12 @@ class TitleTest extends MediaWikiTestCase {
                $this->setContentLang( 'en' );
        }
 
+       protected function tearDown() {
+               // For testNewMainPage
+               MessageCache::destroyInstance();
+               parent::tearDown();
+       }
+
        /**
         * @covers Title::legalChars
         */
@@ -149,12 +157,8 @@ class TitleTest extends MediaWikiTestCase {
                        ]
                ] );
 
-               // Reset TitleParser since we modified $wgLocalInterwikis
-               $this->setService( 'TitleParser', new MediaWikiTitleCodec(
-                               Language::factory( 'en' ),
-                               new GenderCache(),
-                               [ 'localtestiw' ]
-               ) );
+               // Reset services since we modified $wgLocalInterwikis
+               $this->overrideMwServices();
        }
 
        /**
@@ -326,7 +330,7 @@ class TitleTest extends MediaWikiTestCase {
         * @param string $action
         * @param array|string|bool $expected Required error
         *
-        * @covers Title::checkReadPermissions
+        * @covers \Mediawiki\Permissions\PermissionManager::checkReadPermissions
         * @dataProvider dataWgWhitelistReadRegexp
         */
        public function testWgWhitelistReadRegexp( $whitelistRegexp, $source, $action, $expected ) {
@@ -564,6 +568,53 @@ class TitleTest extends MediaWikiTestCase {
                $this->assertEquals( $value->getFragment(), $title->getFragment() );
        }
 
+       /**
+        * @covers Title::newFromLinkTarget
+        * @dataProvider provideNewFromTitleValue
+        */
+       public function testNewFromLinkTarget( LinkTarget $value ) {
+               $title = Title::newFromLinkTarget( $value );
+
+               $dbkey = str_replace( ' ', '_', $value->getText() );
+               $this->assertEquals( $dbkey, $title->getDBkey() );
+               $this->assertEquals( $value->getNamespace(), $title->getNamespace() );
+               $this->assertEquals( $value->getFragment(), $title->getFragment() );
+       }
+
+       /**
+        * @covers Title::newFromLinkTarget
+        */
+       public function testNewFromLinkTarget_clone() {
+               $title = Title::newFromText( __METHOD__ );
+               $this->assertSame( $title, Title::newFromLinkTarget( $title ) );
+
+               // The Title::NEW_CLONE flag should ensure that a fresh instance is returned.
+               $clone = Title::newFromLinkTarget( $title, Title::NEW_CLONE );
+               $this->assertNotSame( $title, $clone );
+               $this->assertTrue( $clone->equals( $title ) );
+       }
+
+       public function provideCastFromLinkTarget() {
+               return array_merge( [ [ null ] ], self::provideNewFromTitleValue() );
+       }
+
+       /**
+        * @covers Title::castFromLinkTarget
+        * @dataProvider provideCastFromLinkTarget
+        */
+       public function testCastFromLinkTarget( $value ) {
+               $title = Title::castFromLinkTarget( $value );
+
+               if ( $value === null ) {
+                       $this->assertNull( $title );
+               } else {
+                       $dbkey = str_replace( ' ', '_', $value->getText() );
+                       $this->assertSame( $dbkey, $title->getDBkey() );
+                       $this->assertSame( $value->getNamespace(), $title->getNamespace() );
+                       $this->assertSame( $value->getFragment(), $title->getFragment() );
+               }
+       }
+
        public static function provideGetTitleValue() {
                return [
                        [ 'Foo' ],
@@ -735,19 +786,6 @@ class TitleTest extends MediaWikiTestCase {
                ];
        }
 
-       /**
-        * @dataProvider provideGetTalkPage_good
-        * @covers Title::getTalkPage
-        */
-       public function testGetTalkPage_good( Title $title, Title $expected ) {
-               $talk = $title->getTalkPage();
-               $this->assertSame(
-                       $expected->getPrefixedDBKey(),
-                       $talk->getPrefixedDBKey(),
-                       $title->getPrefixedDBKey()
-               );
-       }
-
        /**
         * @dataProvider provideGetTalkPage_good
         * @covers Title::getTalkPageIfDefined
@@ -981,4 +1019,121 @@ class TitleTest extends MediaWikiTestCase {
                        [ 'Main Page', false ],
                ];
        }
+
+       public function provideEquals() {
+               yield [
+                       Title::newFromText( 'Main Page' ),
+                       Title::newFromText( 'Main Page' ),
+                       true
+               ];
+               yield [
+                       Title::newFromText( 'Main Page' ),
+                       Title::newFromText( 'Not The Main Page' ),
+                       false
+               ];
+               yield [
+                       Title::newFromText( 'Main Page' ),
+                       Title::newFromText( 'Project:Main Page' ),
+                       false
+               ];
+               yield [
+                       Title::newFromText( 'File:Example.png' ),
+                       Title::newFromText( 'Image:Example.png' ),
+                       true
+               ];
+               yield [
+                       Title::newFromText( 'Special:Version' ),
+                       Title::newFromText( 'Special:Version' ),
+                       true
+               ];
+               yield [
+                       Title::newFromText( 'Special:Version' ),
+                       Title::newFromText( 'Special:Recentchanges' ),
+                       false
+               ];
+               yield [
+                       Title::newFromText( 'Special:Version' ),
+                       Title::newFromText( 'Main Page' ),
+                       false
+               ];
+               yield [
+                       Title::makeTitle( NS_MAIN, 'Foo', '', '' ),
+                       Title::makeTitle( NS_MAIN, 'Foo', '', '' ),
+                       true
+               ];
+               yield [
+                       Title::makeTitle( NS_MAIN, 'Foo', '', '' ),
+                       Title::makeTitle( NS_MAIN, 'Bar', '', '' ),
+                       false
+               ];
+               yield [
+                       Title::makeTitle( NS_MAIN, 'Foo', '', '' ),
+                       Title::makeTitle( NS_TALK, 'Foo', '', '' ),
+                       false
+               ];
+               yield [
+                       Title::makeTitle( NS_MAIN, 'Foo', 'Bar', '' ),
+                       Title::makeTitle( NS_MAIN, 'Foo', 'Bar', '' ),
+                       true
+               ];
+               yield [
+                       Title::makeTitle( NS_MAIN, 'Foo', 'Bar', '' ),
+                       Title::makeTitle( NS_MAIN, 'Foo', 'Baz', '' ),
+                       true
+               ];
+               yield [
+                       Title::makeTitle( NS_MAIN, 'Foo', 'Bar', '' ),
+                       Title::makeTitle( NS_MAIN, 'Foo', '', '' ),
+                       true
+               ];
+               yield [
+                       Title::makeTitle( NS_MAIN, 'Foo', '', 'baz' ),
+                       Title::makeTitle( NS_MAIN, 'Foo', '', 'baz' ),
+                       true
+               ];
+               yield [
+                       Title::makeTitle( NS_MAIN, 'Foo', '', '' ),
+                       Title::makeTitle( NS_MAIN, 'Foo', '', 'baz' ),
+                       false
+               ];
+       }
+
+       /**
+        * @covers Title::equals
+        * @dataProvider provideEquals
+        */
+       public function testEquals( Title $firstValue, /* LinkTarget */ $secondValue, $expectedSame ) {
+               $this->assertSame(
+                       $expectedSame,
+                       $firstValue->equals( $secondValue )
+               );
+       }
+
+       /**
+        * @covers Title::newMainPage
+        */
+       public function testNewMainPage() {
+               $msgCache = TestingAccessWrapper::newFromClass( MessageCache::class );
+               $msgCache->instance = $this->createMock( MessageCache::class );
+               $msgCache->instance->method( 'get' )->willReturn( 'Foresheet' );
+               $msgCache->instance->method( 'transform' )->willReturn( 'Foresheet' );
+
+               $this->assertSame(
+                       'Foresheet',
+                       Title::newMainPage()->getText()
+               );
+       }
+
+       /**
+        * @covers Title::newMainPage
+        */
+       public function testNewMainPageWithLocal() {
+               $local = $this->createMock( MessageLocalizer::class );
+               $local->method( 'msg' )->willReturn( new RawMessage( 'Prime Article' ) );
+
+               $this->assertSame(
+                       'Prime Article',
+                       Title::newMainPage( $local )->getText()
+               );
+       }
 }
index 07c307e..cda5660 100644 (file)
@@ -4,16 +4,19 @@
  * @group WebRequest
  */
 class WebRequestTest extends MediaWikiTestCase {
-       protected $oldServer;
 
        protected function setUp() {
                parent::setUp();
 
                $this->oldServer = $_SERVER;
+               $this->oldWgRequest = $GLOBALS['wgRequest'];
+               $this->oldWgServer = $GLOBALS['wgServer'];
        }
 
        protected function tearDown() {
                $_SERVER = $this->oldServer;
+               $GLOBALS['wgRequest'] = $this->oldWgRequest;
+               $GLOBALS['wgServer'] = $this->oldWgServer;
 
                parent::tearDown();
        }
@@ -368,6 +371,22 @@ class WebRequestTest extends MediaWikiTestCase {
                $this->assertSame( [ 'x' ], $req->getValueNames( [ 'y' ] ), 'Exclude keys' );
        }
 
+       /**
+        * @covers WebRequest
+        */
+       public function testGetFullRequestURL() {
+               // Stub this for wfGetServerUrl()
+               $GLOBALS['wgServer'] = '//wiki.test';
+               $req = $this->getMock( WebRequest::class, [ 'getRequestURL', 'getProtocol' ] );
+               $req->method( 'getRequestURL' )->willReturn( '/path' );
+               $req->method( 'getProtocol' )->willReturn( 'https' );
+
+               $this->assertSame(
+                       'https://wiki.test/path',
+                       $req->getFullRequestURL()
+               );
+       }
+
        /**
         * @dataProvider provideGetIP
         * @covers WebRequest::getIP
index e87e434..1608b9c 100644 (file)
@@ -237,13 +237,13 @@ class WikiMapTest extends MediaWikiLangTestCase {
 
        public function provideGetWikiIdFromDomain() {
                return [
-                       [ 'db-prefix', 'db-prefix' ],
+                       [ 'db-prefix_', 'db-prefix_' ],
                        [ wfWikiID(), wfWikiID() ],
-                       [ new DatabaseDomain( 'db-dash', null, 'prefix' ), 'db-dash-prefix' ],
+                       [ new DatabaseDomain( 'db-dash', null, 'prefix_' ), 'db-dash-prefix_' ],
                        [ wfWikiID(), wfWikiID() ],
-                       [ new DatabaseDomain( 'db-dash', null, 'prefix' ), 'db-dash-prefix' ],
-                       [ new DatabaseDomain( 'db', 'mediawiki', 'prefix' ), 'db-prefix' ], // schema ignored
-                       [ new DatabaseDomain( 'db', 'custom', 'prefix' ), 'db-custom-prefix' ],
+                       [ new DatabaseDomain( 'db-dash', null, 'prefix_' ), 'db-dash-prefix_' ],
+                       [ new DatabaseDomain( 'db', 'mediawiki', 'prefix_' ), 'db-prefix_' ], // schema ignored
+                       [ new DatabaseDomain( 'db', 'custom', 'prefix_' ), 'db-custom-prefix_' ],
                ];
        }
 
@@ -260,16 +260,19 @@ class WikiMapTest extends MediaWikiLangTestCase {
         * @covers WikiMap::getCurrentWikiDbDomain()
         */
        public function testIsCurrentWikiDomain() {
-               $this->assertTrue( WikiMap::isCurrentWikiDbDomain( wfWikiID() ) );
+               $this->setMwGlobals( 'wgDBmwschema', 'mediawiki' );
 
-               $localDomain = DatabaseDomain::newFromId( wfWikiID() );
+               $localDomain = WikiMap::getCurrentWikiDbDomain()->getId();
+               $this->assertTrue( WikiMap::isCurrentWikiDbDomain( $localDomain ) );
+
+               $localDomain = DatabaseDomain::newFromId( $localDomain );
                $domain1 = new DatabaseDomain(
                        $localDomain->getDatabase(), 'someschema', $localDomain->getTablePrefix() );
                $domain2 = new DatabaseDomain(
                        $localDomain->getDatabase(), null, $localDomain->getTablePrefix() );
 
-               $this->assertTrue( WikiMap::isCurrentWikiDbDomain( $domain1 ), 'Schema ignored' );
-               $this->assertTrue( WikiMap::isCurrentWikiDbDomain( $domain2 ), 'Schema ignored' );
+               $this->assertFalse( WikiMap::isCurrentWikiDbDomain( $domain1 ), 'Schema not ignored' );
+               $this->assertFalse( WikiMap::isCurrentWikiDbDomain( $domain2 ), 'Null schema not ignored' );
 
                $this->assertTrue( WikiMap::isCurrentWikiDbDomain( WikiMap::getCurrentWikiDbDomain() ) );
        }
@@ -279,15 +282,15 @@ class WikiMapTest extends MediaWikiLangTestCase {
                        [ 'db', 'db', null, '' ],
                        [ 'db-schema-','db', 'schema', '' ],
                        [ 'db','db', 'mediawiki', '' ], // common b/c case
-                       [ 'db-prefix', 'db', null, 'prefix' ],
-                       [ 'db-schema-prefix', 'db', 'schema', 'prefix' ],
-                       [ 'db-prefix', 'db', 'mediawiki', 'prefix' ], // common b/c case
+                       [ 'db-prefix_', 'db', null, 'prefix_' ],
+                       [ 'db-schema-prefix_', 'db', 'schema', 'prefix_' ],
+                       [ 'db-prefix_', 'db', 'mediawiki', 'prefix_' ], // common b/c case
                        // Bad hyphen cases (best effort support)
                        [ 'db-stuff', 'db-stuff', null, '' ],
-                       [ 'db-stuff-prefix', 'db-stuff', null, 'prefix' ],
+                       [ 'db-stuff-prefix_', 'db-stuff', null, 'prefix_' ],
                        [ 'db-stuff-schema-', 'db-stuff', 'schema', '' ],
-                       [ 'db-stuff-schema-prefix', 'db-stuff', 'schema', 'prefix' ],
-                       [ 'db-stuff-prefix', 'db-stuff', 'mediawiki', 'prefix' ] // common b/c case
+                       [ 'db-stuff-schema-prefix_', 'db-stuff', 'schema', 'prefix_' ],
+                       [ 'db-stuff-prefix_', 'db-stuff', 'mediawiki', 'prefix_' ] // common b/c case
                ];
        }
 
index 044c30a..cdd7576 100644 (file)
@@ -270,17 +270,6 @@ class WatchActionTest extends MediaWikiTestCase {
                WatchAction::getWatchToken( $this->watchAction->getTitle(), $user );
        }
 
-       /**
-        * @covers WatchAction::getUnwatchToken()
-        */
-       public function testGetUnwatchToken() {
-               $user = $this->getMock( User::class );
-               $user->expects( $this->once() )->method( 'getEditToken' );
-               $this->hideDeprecated( 'WatchAction::getUnwatchToken' );
-
-               WatchAction::getUnWatchToken( $this->watchAction->getTitle(), $user );
-       }
-
        /**
         * @covers WatchAction::doWatchOrUnwatch()
         */
index 0dc64df..64b2cd6 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 
+use MediaWiki\MediaWikiServices;
 use Wikimedia\TestingAccessWrapper;
 
 /**
@@ -643,7 +644,7 @@ class ApiBaseTest extends ApiTestCase {
                                        ApiBase::PARAM_ISMULTI => true,
                                        ApiBase::PARAM_TYPE => 'namespace',
                                ],
-                               MWNamespace::getValidNamespaces(),
+                               MediaWikiServices::getInstance()->getNamespaceInfo()->getValidNamespaces(),
                                [],
                        ],
                        // PARAM_ALL is ignored with namespace types.
@@ -654,7 +655,7 @@ class ApiBaseTest extends ApiTestCase {
                                        ApiBase::PARAM_TYPE => 'namespace',
                                        ApiBase::PARAM_ALL => false,
                                ],
-                               MWNamespace::getValidNamespaces(),
+                               MediaWikiServices::getInstance()->getNamespaceInfo()->getValidNamespaces(),
                                [],
                        ],
                        'Namespace with wildcard "x"' => [
@@ -1332,7 +1333,10 @@ class ApiBaseTest extends ApiTestCase {
                        'expiry' => time() + 100500,
                ] );
                $block->insert();
-               $blockinfo = [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $block ) ];
+               $userInfoTrait = TestingAccessWrapper::newFromObject(
+                       $this->getMockForTrait( ApiBlockInfoTrait::class )
+               );
+               $blockinfo = [ 'blockinfo' => $userInfoTrait->getBlockDetails( $block ) ];
 
                $expect = Status::newGood();
                $expect->fatal( ApiMessage::create( 'apierror-blocked', 'blocked', $blockinfo ) );
@@ -1387,7 +1391,10 @@ class ApiBaseTest extends ApiTestCase {
                        'expiry' => time() + 100500,
                ] );
                $block->insert();
-               $blockinfo = [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $block ) ];
+               $userInfoTrait = TestingAccessWrapper::newFromObject(
+                       $this->getObjectForTrait( ApiBlockInfoTrait::class )
+               );
+               $blockinfo = [ 'blockinfo' => $userInfoTrait->getBlockDetails( $block ) ];
 
                $expect = Status::newGood();
                $expect->fatal( ApiMessage::create( 'apierror-blocked', 'blocked', $blockinfo ) );
diff --git a/tests/phpunit/includes/api/ApiBlockInfoTraitTest.php b/tests/phpunit/includes/api/ApiBlockInfoTraitTest.php
new file mode 100644 (file)
index 0000000..a6e2d0d
--- /dev/null
@@ -0,0 +1,42 @@
+<?php
+
+use Wikimedia\TestingAccessWrapper;
+use MediaWiki\Block\SystemBlock;
+
+/**
+ * @covers ApiBlockInfoTrait
+ */
+class ApiBlockInfoTraitTest extends MediaWikiTestCase {
+       /**
+        * @dataProvider provideGetBlockDetails
+        */
+       public function testGetBlockDetails( $block, $expectedInfo ) {
+               $mock = $this->getMockForTrait( ApiBlockInfoTrait::class );
+               $info = TestingAccessWrapper::newFromObject( $mock )->getBlockDetails( $block );
+               $subset = array_merge( [
+                       'blockid' => null,
+                       'blockedby' => '',
+                       'blockedbyid' => 0,
+                       'blockreason' => '',
+                       'blockexpiry' => 'infinite',
+               ], $expectedInfo );
+               $this->assertArraySubset( $subset, $info );
+       }
+
+       public static function provideGetBlockDetails() {
+               return [
+                       'Sitewide block' => [
+                               new Block(),
+                               [ 'blockpartial' => false ],
+                       ],
+                       'Partial block' => [
+                               new Block( [ 'sitewide' => false ] ),
+                               [ 'blockpartial' => true ],
+                       ],
+                       'System block' => [
+                               new SystemBlock( [ 'systemBlock' => 'proxy' ] ),
+                               [ 'systemblocktype' => 'proxy' ]
+                       ],
+               ];
+       }
+}
index 01455ed..1c53147 100644 (file)
@@ -62,7 +62,7 @@ class ApiBlockTest extends ApiTestCase {
                $this->assertTrue( !is_null( $block ), 'Block is valid' );
 
                $this->assertSame( $this->mUser->getName(), (string)$block->getTarget() );
-               $this->assertSame( 'Some reason', $block->mReason );
+               $this->assertSame( 'Some reason', $block->getReason() );
 
                return $ret;
        }
@@ -175,6 +175,12 @@ class ApiBlockTest extends ApiTestCase {
        }
 
        public function testBlockWithEmailBlock() {
+               $this->setMwGlobals( [
+                       'wgEnableEmail' => true,
+                       'wgEnableUserEmail' => true,
+                       'wgSysopEmailBans' => true,
+               ] );
+
                $res = $this->doBlock( [ 'noemail' => '' ] );
 
                $dbw = wfGetDB( DB_MASTER );
@@ -187,6 +193,12 @@ class ApiBlockTest extends ApiTestCase {
        }
 
        public function testBlockWithProhibitedEmailBlock() {
+               $this->setMwGlobals( [
+                       'wgEnableEmail' => true,
+                       'wgEnableUserEmail' => true,
+                       'wgSysopEmailBans' => true,
+               ] );
+
                $this->setExpectedException( ApiUsageException::class,
                        "You don't have permission to block users from sending email through the wiki." );
 
diff --git a/tests/phpunit/includes/api/ApiLogoutTest.php b/tests/phpunit/includes/api/ApiLogoutTest.php
new file mode 100644 (file)
index 0000000..8254fdb
--- /dev/null
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * @group API
+ * @group Database
+ * @group medium
+ *
+ * @covers ApiLogout
+ */
+class ApiLogoutTest extends ApiTestCase {
+
+       protected function setUp() {
+               global $wgRequest, $wgUser;
+
+               parent::setUp();
+
+               // Link the user to the Session properly so User::doLogout() doesn't complain.
+               $wgRequest->getSession()->setUser( $wgUser );
+               $wgUser = User::newFromSession( $wgRequest );
+               $this->apiContext->setUser( $wgUser );
+       }
+
+       public function testUserLogoutBadToken() {
+               global $wgUser;
+
+               $this->setExpectedApiException( 'apierror-badtoken' );
+
+               try {
+                       $token = 'invalid token';
+                       $this->doUserLogout( $token );
+               } finally {
+                       $this->assertTrue( $wgUser->isLoggedIn(), 'not logged out' );
+               }
+       }
+
+       public function testUserLogout() {
+               global $wgUser;
+
+               $this->assertTrue( $wgUser->isLoggedIn(), 'sanity check' );
+               $token = $this->getUserCsrfTokenFromApi();
+               $this->doUserLogout( $token );
+               $this->assertFalse( $wgUser->isLoggedIn() );
+       }
+
+       public function testUserLogoutWithWebToken() {
+               global $wgUser, $wgRequest;
+
+               $this->assertTrue( $wgUser->isLoggedIn(), 'sanity check' );
+
+               // Logic copied from SkinTemplate.
+               $token = $wgUser->getEditToken( 'logoutToken', $wgRequest );
+
+               $this->doUserLogout( $token );
+               $this->assertFalse( $wgUser->isLoggedIn() );
+       }
+
+       private function getUserCsrfTokenFromApi() {
+               $retToken = $this->doApiRequest( [
+                       'action' => 'query',
+                       'meta' => 'tokens',
+                       'type' => 'csrf'
+               ] );
+
+               $this->assertArrayNotHasKey( 'warnings', $retToken );
+
+               return $retToken[0]['query']['tokens']['csrftoken'];
+       }
+
+       private function doUserLogout( $logoutToken ) {
+               return $this->doApiRequest( [
+                       'action' => 'logout',
+                       'token' => $logoutToken
+               ] );
+       }
+}
index b9c49b1..d437a52 100644 (file)
@@ -17,6 +17,7 @@ class ApiMoveTest extends ApiTestCase {
        protected function assertMoved( $from, $to, $id, $opts = null ) {
                $opts = (array)$opts;
 
+               Title::clearCaches();
                $fromTitle = Title::newFromText( $from );
                $toTitle = Title::newFromText( $to );
 
index f8399a3..0011d7a 100644 (file)
@@ -121,6 +121,7 @@ class ApiParseTest extends ApiTestCase {
 
                $this->setMwGlobals( 'wgExtraInterlanguageLinkPrefixes', [ 'madeuplanguage' ] );
                $this->tablesUsed[] = 'interwiki';
+               $this->overrideMwServices();
        }
 
        /**
@@ -581,8 +582,6 @@ class ApiParseTest extends ApiTestCase {
         * @param array $arr Extra params to add to API request
         */
        private function doTestLangLinks( array $arr = [] ) {
-               $this->setupInterwiki();
-
                $res = $this->doApiRequest( array_merge( [
                        'action' => 'parse',
                        'title' => 'Omelette',
@@ -600,10 +599,12 @@ class ApiParseTest extends ApiTestCase {
        }
 
        public function testLangLinks() {
+               $this->setupInterwiki();
                $this->doTestLangLinks();
        }
 
        public function testLangLinksWithSkin() {
+               $this->setupInterwiki();
                $this->setupSkin();
                $this->doTestLangLinks( [ 'useskin' => 'testing' ] );
        }
index a95d5c1..ff0e2e6 100644 (file)
@@ -149,16 +149,8 @@ class ApiQueryRecentChangesIntegrationTest extends ApiTestCase {
                return $response[0]['query']['recentchanges'];
        }
 
-       private function getTitleFormatter() {
-               return new MediaWikiTitleCodec(
-                       Language::factory( 'en' ),
-                       MediaWikiServices::getInstance()->getGenderCache()
-               );
-       }
-
        private function getPrefixedText( LinkTarget $target ) {
-               $formatter = $this->getTitleFormatter();
-               return $formatter->getPrefixedText( $target );
+               return MediaWikiServices::getInstance()->getTitleFormatter()->getPrefixedText( $target );
        }
 
        public function testListRecentChanges_returnsRCInfo() {
index d3a4ed4..282188d 100644 (file)
@@ -571,26 +571,26 @@ class ApiQuerySiteinfoTest extends ApiTestCase {
        }
 
        public function testExtensionTags() {
-               global $wgParser;
-
                $expected = array_map(
                        function ( $tag ) {
                                return "<$tag>";
                        },
-                       $wgParser->getTags()
+                       MediaWikiServices::getInstance()->getParser()->getTags()
                );
 
                $this->assertSame( $expected, $this->doQuery( 'extensiontags' ) );
        }
 
        public function testFunctionHooks() {
-               global $wgParser;
-
-               $this->assertSame( $wgParser->getFunctionHooks(), $this->doQuery( 'functionhooks' ) );
+               $this->assertSame( MediaWikiServices::getInstance()->getParser()->getFunctionHooks(),
+                       $this->doQuery( 'functionhooks' ) );
        }
 
        public function testVariables() {
-               $this->assertSame( MagicWord::getVariableIDs(), $this->doQuery( 'variables' ) );
+               $this->assertSame(
+                       MediaWikiServices::getInstance()->getMagicWordFactory()->getVariableIDs(),
+                       $this->doQuery( 'variables' )
+               );
        }
 
        public function testProtocols() {
index 7dcb75c..703c150 100644 (file)
@@ -6,6 +6,8 @@
  */
 class ApiQueryUserInfoTest extends ApiTestCase {
        public function testGetBlockInfo() {
+               $this->hideDeprecated( 'ApiQueryUserInfo::getBlockInfo' );
+
                $apiQueryUserInfo = new ApiQueryUserInfo(
                        new ApiQuery( new ApiMain( $this->apiContext ), 'userinfo' ),
                        'userinfo'
@@ -25,6 +27,8 @@ class ApiQueryUserInfoTest extends ApiTestCase {
        }
 
        public function testGetBlockInfoPartial() {
+               $this->hideDeprecated( 'ApiQueryUserInfo::getBlockInfo' );
+
                $apiQueryUserInfo = new ApiQueryUserInfo(
                        new ApiQuery( new ApiMain( $this->apiContext ), 'userinfo' ),
                        'userinfo'
index 41ecd52..2b08a81 100644 (file)
@@ -228,16 +228,8 @@ class ApiQueryWatchlistIntegrationTest extends ApiTestCase {
                }
        }
 
-       private function getTitleFormatter() {
-               return new MediaWikiTitleCodec(
-                       Language::factory( 'en' ),
-                       MediaWikiServices::getInstance()->getGenderCache()
-               );
-       }
-
        private function getPrefixedText( LinkTarget $target ) {
-               $formatter = $this->getTitleFormatter();
-               return $formatter->getPrefixedText( $target );
+               return MediaWikiServices::getInstance()->getTitleFormatter()->getPrefixedText( $target );
        }
 
        private function cleanTestUsersWatchlist() {
index a63f8aa..c6ed8a7 100644 (file)
@@ -1,9 +1,13 @@
 <?php
 
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Storage\PageEditStash;
 use Wikimedia\TestingAccessWrapper;
+use Psr\Log\NullLogger;
 
 /**
  * @covers ApiStashEdit
+ * @covers \MediaWiki\Storage\PageEditStash
  * @group API
  * @group medium
  * @group Database
@@ -11,12 +15,21 @@ use Wikimedia\TestingAccessWrapper;
 class ApiStashEditTest extends ApiTestCase {
        public function setUp() {
                parent::setUp();
-
-               // We need caching here, but note that the cache gets cleared in between tests, so it
-               // doesn't work with @depends
+               $this->setService( 'PageEditStash', new PageEditStash(
+                       new HashBagOStuff( [] ),
+                       MediaWikiServices::getInstance()->getDBLoadBalancer(),
+                       new NullLogger(),
+                       new NullStatsdDataFactory(),
+                       PageEditStash::INITIATOR_USER
+               ) );
+               // Clear rate-limiting cache between tests
                $this->setMwGlobals( 'wgMainCacheType', 'hash' );
        }
 
+       public function tearDown() {
+               parent::tearDown();
+       }
+
        /**
         * Make a stashedit API call with suitable default parameters
         *
@@ -24,6 +37,7 @@ class ApiStashEditTest extends ApiTestCase {
         *   sensible defaults filled in.  To make a parameter actually not passed, set to null.
         * @param User $user User to do the request
         * @param string $expectedResult 'stashed', 'editconflict'
+        * @return array
         */
        protected function doStash(
                array $params = [], User $user = null, $expectedResult = 'stashed'
@@ -88,13 +102,11 @@ class ApiStashEditTest extends ApiTestCase {
         * @return string
         */
        protected function getStashedText( $hash ) {
-               $cache = ObjectCache::getLocalClusterInstance();
-               $key = $cache->makeKey( 'stashedit', 'text', $hash );
-               return $cache->get( $key );
+               return MediaWikiServices::getInstance()->getPageEditStash()->fetchInputText( $hash );
        }
 
        /**
-        * Return a key that can be passed to the cache to obtain a PreparedEdit object.
+        * Return a key that can be passed to the cache to obtain a stashed edit object.
         *
         * @param string $title Title of page
         * @param string Content $text Content of edit
@@ -107,8 +119,10 @@ class ApiStashEditTest extends ApiTestCase {
                if ( !$user ) {
                        $user = $this->getTestSysop()->getUser();
                }
-               $wrapper = TestingAccessWrapper::newFromClass( ApiStashEdit::class );
-               return $wrapper->getStashKey( $titleObj, $wrapper->getContentHash( $content ), $user );
+               $editStash = TestingAccessWrapper::newFromObject(
+                       MediaWikiServices::getInstance()->getPageEditStash() );
+
+               return $editStash->getStashKey( $titleObj, $editStash->getContentHash( $content ), $user );
        }
 
        public function testBasicEdit() {
@@ -263,15 +277,15 @@ class ApiStashEditTest extends ApiTestCase {
        }
 
        /**
-        * Shortcut for calling ApiStashEdit::checkCache() without having to create Titles and Contents
-        * in every test.
+        * Shortcut for calling PageStashEdit::checkCache() without
+        * having to create Titles and Contents in every test.
         *
         * @param User $user
         * @param string $text The text of the article
-        * @return stdClass|bool Return value of ApiStashEdit::checkCache(), false if not in cache
+        * @return stdClass|bool Return value of PageStashEdit::checkCache(), false if not in cache
         */
        protected function doCheckCache( User $user, $text = 'Content' ) {
-               return ApiStashEdit::checkCache(
+               return MediaWikiServices::getInstance()->getPageEditStash()->checkCache(
                        Title::newFromText( __CLASS__ ),
                        new WikitextContent( $text ),
                        $user
@@ -305,11 +319,11 @@ class ApiStashEditTest extends ApiTestCase {
        }
 
        public function testCheckCacheAnon() {
-               $user = new User();
+               $user = User::newFromName( '174.5.4.6', false );
 
                $this->doStash( [], $user );
 
-               $this->assertInstanceOf( stdClass::class, $this->docheckCache( $user ) );
+               $this->assertInstanceOf( stdClass::class, $this->doCheckCache( $user ) );
        }
 
        /**
@@ -320,7 +334,7 @@ class ApiStashEditTest extends ApiTestCase {
         * @param int $howOld How many seconds is "old" (we actually set it one second before this)
         */
        protected function doStashOld(
-               User $user, $text = 'Content', $howOld = ApiStashEdit::PRESUME_FRESH_TTL_SEC
+               User $user, $text = 'Content', $howOld = PageEditStash::PRESUME_FRESH_TTL_SEC
        ) {
                $this->doStash( [ 'text' => $text ], $user );
 
@@ -328,7 +342,9 @@ class ApiStashEditTest extends ApiTestCase {
                // fake the time?
                $key = $this->getStashKey( __CLASS__, $text, $user );
 
-               $cache = ObjectCache::getLocalClusterInstance();
+               $editStash = TestingAccessWrapper::newFromObject(
+                       MediaWikiServices::getInstance()->getPageEditStash() );
+               $cache = $editStash->cache;
 
                $editInfo = $cache->get( $key );
                $outputKey = $cache->makeKey( 'stashed-edit-output', $editInfo->outputID );
@@ -350,7 +366,7 @@ class ApiStashEditTest extends ApiTestCase {
 
        public function testCheckCacheOldNoEditsAnon() {
                // Specify a made-up IP address to make sure no edits are lying around
-               $user = User::newFromName( '192.0.2.77', false );
+               $user = User::newFromName( '172.0.2.77', false );
 
                $this->doStashOld( $user );
 
@@ -379,7 +395,9 @@ class ApiStashEditTest extends ApiTestCase {
        public function testSignatureTtl( $text, $ttl ) {
                $this->doStash( [ 'text' => $text ] );
 
-               $cache = ObjectCache::getLocalClusterInstance();
+               $editStash = TestingAccessWrapper::newFromObject(
+                       MediaWikiServices::getInstance()->getPageEditStash() );
+               $cache = $editStash->cache;
                $key = $this->getStashKey( __CLASS__, $text );
 
                $wrapper = TestingAccessWrapper::newFromObject( $cache );
@@ -389,9 +407,9 @@ class ApiStashEditTest extends ApiTestCase {
 
        public function signatureProvider() {
                return [
-                       '~~~' => [ '~~~', ApiStashEdit::MAX_SIGNATURE_TTL ],
-                       '~~~~' => [ '~~~~', ApiStashEdit::MAX_SIGNATURE_TTL ],
-                       '~~~~~' => [ '~~~~~', ApiStashEdit::MAX_SIGNATURE_TTL ],
+                       '~~~' => [ '~~~', PageEditStash::MAX_SIGNATURE_TTL ],
+                       '~~~~' => [ '~~~~', PageEditStash::MAX_SIGNATURE_TTL ],
+                       '~~~~~' => [ '~~~~~', PageEditStash::MAX_SIGNATURE_TTL ],
                ];
        }
 
diff --git a/tests/phpunit/includes/api/query/ApiQueryAllRevisionsTest.php b/tests/phpunit/includes/api/query/ApiQueryAllRevisionsTest.php
new file mode 100644 (file)
index 0000000..6e4c3c0
--- /dev/null
@@ -0,0 +1,64 @@
+<?php
+
+/**
+ * @group API
+ * @group Database
+ * @group medium
+ * @covers ApiQueryAllRevisions
+ */
+class ApiQueryAllRevisionsTest extends ApiTestCase {
+
+       public function __construct( $name = null, array $data = [], $dataName = '' ) {
+               parent::__construct( $name, $data, $dataName );
+
+               $this->tablesUsed[] = 'revision';
+       }
+
+       /**
+        * @group medium
+        */
+       public function testContentComesWithContentModelAndFormat() {
+               $pageName = 'Help:' . __METHOD__;
+               $title = Title::newFromText( $pageName );
+               $page = WikiPage::factory( $title );
+
+               $page->doEditContent(
+                       ContentHandler::makeContent( 'Some text', $page->getTitle() ),
+                       'inserting content'
+               );
+               $page->doEditContent(
+                       ContentHandler::makeContent( 'Some other text', $page->getTitle() ),
+                       'adding revision'
+               );
+
+               $apiResult = $this->doApiRequest( [
+                       'action' => 'query',
+                       'list' => 'allrevisions',
+                       'arvprop' => 'content',
+                       'arvslots' => 'main',
+                       'arvdir' => 'older',
+               ] );
+
+               $this->assertArrayHasKey( 'query', $apiResult[0] );
+               $this->assertArrayHasKey( 'allrevisions', $apiResult[0]['query'] );
+               $this->assertArrayHasKey( 0, $apiResult[0]['query']['allrevisions'] );
+               $this->assertArrayHasKey( 'title', $apiResult[0]['query']['allrevisions'][0] );
+               $this->assertSame( $pageName, $apiResult[0]['query']['allrevisions'][0]['title'] );
+               $this->assertArrayHasKey( 'revisions', $apiResult[0]['query']['allrevisions'][0] );
+               $this->assertCount( 2, $apiResult[0]['query']['allrevisions'][0]['revisions'] );
+
+               foreach ( $apiResult[0]['query']['allrevisions'] as $page ) {
+                       $this->assertArrayHasKey( 'revisions', $page );
+                       foreach ( $page['revisions'] as $revision ) {
+                               $this->assertArrayHasKey( 'slots', $revision );
+                               $this->assertArrayHasKey( 'main', $revision['slots'] );
+                               $this->assertArrayHasKey( 'contentformat', $revision['slots']['main'],
+                                       'contentformat should be included when asking content so client knows how to interpret it'
+                               );
+                               $this->assertArrayHasKey( 'contentmodel', $revision['slots']['main'],
+                                       'contentmodel should be included when asking content so client knows how to interpret it'
+                               );
+                       }
+               }
+       }
+}
index 08af755..7869bbd 100644 (file)
@@ -32,14 +32,14 @@ STR;
 
        /**
         * Merges all requests parameter + expected values into one
-        * @param array $v,... List of arrays, each of which contains exactly two
+        * @param array ...$arrays List of arrays, each of which contains exactly two
         * @return array
         */
-       protected function merge( /*...*/ ) {
+       protected function merge( ...$arrays ) {
                $request = [];
                $expected = [];
-               foreach ( func_get_args() as $v ) {
-                       list( $req, $exp ) = $this->validateRequestExpectedPair( $v );
+               foreach ( $arrays as $array ) {
+                       list( $req, $exp ) = $this->validateRequestExpectedPair( $array );
                        $request = array_merge_recursive( $request, $req );
                        $this->mergeExpected( $expected, $exp );
                }
index 924a1a5..92c71bd 100644 (file)
@@ -15,7 +15,8 @@ class ApiQueryUserContribsTest extends ApiTestCase {
                        $wgActorTableSchemaMigrationStage = $v;
                        $this->overrideMwServices();
                }, [ $wgActorTableSchemaMigrationStage ] );
-               $wgActorTableSchemaMigrationStage = SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD;
+               // Needs to WRITE_BOTH so READ_OLD tests below work. READ mode here doesn't really matter.
+               $wgActorTableSchemaMigrationStage = SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW;
                $this->overrideMwServices();
 
                $users = [
index d5e1879..5cf93c9 100644 (file)
@@ -1471,10 +1471,12 @@ class AuthManagerTest extends \MediaWikiTestCase {
                        ],
                        'wgProxyWhitelist' => [],
                ] );
+               $this->overrideMwServices();
                $status = $this->manager->checkAccountCreatePermissions( new \User );
                $this->assertFalse( $status->isOK() );
                $this->assertTrue( $status->hasMessage( 'sorbs_create_account_reason' ) );
                $this->setMwGlobals( 'wgProxyWhitelist', [ '127.0.0.1' ] );
+               $this->overrideMwServices();
                $status = $this->manager->checkAccountCreatePermissions( new \User );
                $this->assertTrue( $status->isGood() );
        }
@@ -2668,7 +2670,7 @@ class AuthManagerTest extends \MediaWikiTestCase {
 
                // Test backoff
                $cache = \ObjectCache::getLocalClusterInstance();
-               $backoffKey = wfMemcKey( 'AuthManager', 'autocreate-failed', md5( $username ) );
+               $backoffKey = $cache->makeKey( 'AuthManager', 'autocreate-failed', md5( $username ) );
                $cache->set( $backoffKey, true );
                $session->clear();
                $user = \User::newFromName( $username );
@@ -2707,7 +2709,7 @@ class AuthManagerTest extends \MediaWikiTestCase {
 
                // Test addToDatabase throws an exception
                $cache = \ObjectCache::getLocalClusterInstance();
-               $backoffKey = wfMemcKey( 'AuthManager', 'autocreate-failed', md5( $username ) );
+               $backoffKey = $cache->makeKey( 'AuthManager', 'autocreate-failed', md5( $username ) );
                $this->assertFalse( $cache->get( $backoffKey ), 'sanity check' );
                $session->clear();
                $user = $this->getMockBuilder( \User::class )
index 1da4ee0..80cfbe6 100644 (file)
@@ -191,7 +191,8 @@ class TemporaryPasswordPrimaryAuthenticationProviderTest extends \MediaWikiTestC
         * @param array $expected
         */
        public function testGetAuthenticationRequests( $action, $options, $expected ) {
-               $actual = $this->getProvider()->getAuthenticationRequests( $action, $options );
+               $actual = $this->getProvider( [ 'emailEnabled' => true ] )
+                       ->getAuthenticationRequests( $action, $options );
                foreach ( $actual as $req ) {
                        if ( $req instanceof TemporaryPasswordAuthenticationRequest && $req->password !== null ) {
                                $req->password = 'random';
@@ -521,11 +522,15 @@ class TemporaryPasswordPrimaryAuthenticationProviderTest extends \MediaWikiTestC
                $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
                $this->assertEquals( \StatusValue::newFatal( 'passwordreset-emaildisabled' ), $status );
 
-               $provider = $this->getProvider( [ 'passwordReminderResendTime' => 10 ] );
+               $provider = $this->getProvider( [
+                       'emailEnabled' => true, 'passwordReminderResendTime' => 10
+               ] );
                $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
                $this->assertEquals( \StatusValue::newFatal( 'throttled-mailpassword', 10 ), $status );
 
-               $provider = $this->getProvider( [ 'passwordReminderResendTime' => 3 ] );
+               $provider = $this->getProvider( [
+                       'emailEnabled' => true, 'passwordReminderResendTime' => 3
+               ] );
                $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
                $this->assertFalse( $status->hasMessage( 'throttled-mailpassword' ) );
 
@@ -534,7 +539,9 @@ class TemporaryPasswordPrimaryAuthenticationProviderTest extends \MediaWikiTestC
                        [ 'user_newpass_time' => $dbw->timestamp( time() + 5 * 3600 ) ],
                        [ 'user_id' => $user->getId() ]
                );
-               $provider = $this->getProvider( [ 'passwordReminderResendTime' => 0 ] );
+               $provider = $this->getProvider( [
+                       'emailEnabled' => true, 'passwordReminderResendTime' => 0
+               ] );
                $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
                $this->assertFalse( $status->hasMessage( 'throttled-mailpassword' ) );
 
index cc2771c..fc1930a 100644 (file)
@@ -53,9 +53,8 @@ class UserDataAuthenticationRequestTest extends AuthenticationRequestTestCase {
         * @dataProvider provideLoadFromSubmission
         */
        public function testLoadFromSubmission(
-               array $args, array $data, $expectState /* $hiddenPref, $enableEmail */
+               array $args, array $data, $expectState, $hiddenPref = null, $enableEmail = null
        ) {
-               list( $args, $data, $expectState, $hiddenPref, $enableEmail ) = func_get_args();
                $this->setMwGlobals( 'wgHiddenPrefs', $hiddenPref );
                $this->setMwGlobals( 'wgEnableEmail', $enableEmail );
                parent::testLoadFromSubmission( $args, $data, $expectState );
diff --git a/tests/phpunit/includes/block/BlockManagerTest.php b/tests/phpunit/includes/block/BlockManagerTest.php
new file mode 100644 (file)
index 0000000..4145665
--- /dev/null
@@ -0,0 +1,226 @@
+<?php
+
+use MediaWiki\Block\BlockManager;
+
+/**
+ * @group Blocking
+ * @group Database
+ * @coversDefaultClass \MediaWiki\Block\BlockManager
+ */
+class BlockManagerTest extends MediaWikiTestCase {
+
+       /** @var User */
+       protected $user;
+
+       /** @var int */
+       protected $sysopId;
+
+       protected function setUp() {
+               parent::setUp();
+
+               $this->user = $this->getTestUser()->getUser();
+               $this->sysopId = $this->getTestSysop()->getUser()->getId();
+       }
+
+       private function getBlockManager( $overrideConfig ) {
+               $blockManagerConfig = array_merge( [
+                       'wgApplyIpBlocksToXff' => true,
+                       'wgCookieSetOnAutoblock' => true,
+                       'wgCookieSetOnIpBlock' => true,
+                       'wgDnsBlacklistUrls' => [],
+                       'wgEnableDnsBlacklist' => true,
+                       'wgProxyList' => [],
+                       'wgProxyWhitelist' => [],
+                       'wgSoftBlockRanges' => [],
+               ], $overrideConfig );
+               return new BlockManager(
+                       $this->user,
+                       $this->user->getRequest(),
+                       ...array_values( $blockManagerConfig )
+               );
+       }
+
+       /**
+        * @dataProvider provideGetBlockFromCookieValue
+        * @covers ::getBlockFromCookieValue
+        */
+       public function testGetBlockFromCookieValue( $options, $expected ) {
+               $blockManager = $this->getBlockManager( [
+                       'wgCookieSetOnAutoblock' => true,
+                       'wgCookieSetOnIpBlock' => true,
+               ] );
+
+               $block = new Block( array_merge( [
+                       'address' => $options[ 'target' ] ?: $this->user,
+                       'by' => $this->sysopId,
+               ], $options[ 'blockOptions' ] ) );
+               $block->insert();
+
+               $class = new ReflectionClass( BlockManager::class );
+               $method = $class->getMethod( 'getBlockFromCookieValue' );
+               $method->setAccessible( true );
+
+               $user = $options[ 'loggedIn' ] ? $this->user : new User();
+               $user->getRequest()->setCookie( 'BlockID', $block->getCookieValue() );
+
+               $this->assertSame( $expected, (bool)$method->invoke(
+                       $blockManager,
+                       $user,
+                       $user->getRequest()
+               ) );
+
+               $block->delete();
+       }
+
+       public static function provideGetBlockFromCookieValue() {
+               return [
+                       'Autoblocking user block' => [
+                               [
+                                       'target' => '',
+                                       'loggedIn' => true,
+                                       'blockOptions' => [
+                                               'enableAutoblock' => true
+                                       ],
+                               ],
+                               true,
+                       ],
+                       'Non-autoblocking user block' => [
+                               [
+                                       'target' => '',
+                                       'loggedIn' => true,
+                                       'blockOptions' => [],
+                               ],
+                               false,
+                       ],
+                       'IP block for anonymous user' => [
+                               [
+                                       'target' => '127.0.0.1',
+                                       'loggedIn' => false,
+                                       'blockOptions' => [],
+                               ],
+                               true,
+                       ],
+                       'IP block for logged in user' => [
+                               [
+                                       'target' => '127.0.0.1',
+                                       'loggedIn' => true,
+                                       'blockOptions' => [],
+                               ],
+                               false,
+                       ],
+                       'IP range block for anonymous user' => [
+                               [
+                                       'target' => '127.0.0.0/8',
+                                       'loggedIn' => false,
+                                       'blockOptions' => [],
+                               ],
+                               true,
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideIsLocallyBlockedProxy
+        * @covers ::isLocallyBlockedProxy
+        */
+       public function testIsLocallyBlockedProxy( $proxyList, $expected ) {
+               $class = new ReflectionClass( BlockManager::class );
+               $method = $class->getMethod( 'isLocallyBlockedProxy' );
+               $method->setAccessible( true );
+
+               $blockManager = $this->getBlockManager( [
+                       'wgProxyList' => $proxyList
+               ] );
+
+               $ip = '1.2.3.4';
+               $this->assertSame( $expected, $method->invoke( $blockManager, $ip ) );
+       }
+
+       public static function provideIsLocallyBlockedProxy() {
+               return [
+                       'Proxy list is empty' => [ [], false ],
+                       'Proxy list contains IP' => [ [ '1.2.3.4' ], true ],
+                       'Proxy list contains IP as value' => [ [ 'test' => '1.2.3.4' ], true ],
+                       'Proxy list contains range that covers IP' => [ [ '1.2.3.0/16' ], true ],
+               ];
+       }
+
+       /**
+        * @covers ::isLocallyBlockedProxy
+        */
+       public function testIsLocallyBlockedProxyDeprecated() {
+               $proxy = '1.2.3.4';
+
+               $this->hideDeprecated(
+                       'IP addresses in the keys of $wgProxyList (found the following IP ' .
+                       'addresses in keys: ' . $proxy . ', please move them to values)'
+               );
+
+               $class = new ReflectionClass( BlockManager::class );
+               $method = $class->getMethod( 'isLocallyBlockedProxy' );
+               $method->setAccessible( true );
+
+               $blockManager = $this->getBlockManager( [
+                       'wgProxyList' => [ $proxy => 'test' ]
+               ] );
+
+               $ip = '1.2.3.4';
+               $this->assertSame( true, $method->invoke( $blockManager, $ip ) );
+       }
+
+       /**
+        * @dataProvider provideIsDnsBlacklisted
+        * @covers ::isDnsBlacklisted
+        * @covers ::inDnsBlacklist
+        */
+       public function testIsDnsBlacklisted( $options, $expected ) {
+               $blockManager = $this->getBlockManager( [
+                       'wgEnableDnsBlacklist' => true,
+                       'wgDnsBlacklistUrls' => $options[ 'inBlacklist' ] ? [ 'local.wmftest.net' ] : [],
+                       'wgProxyWhitelist' => $options[ 'inWhitelist' ] ? [ '127.0.0.1' ] : [],
+               ] );
+
+               $ip = '127.0.0.1';
+               $this->assertSame(
+                       $expected,
+                       $blockManager->isDnsBlacklisted( $ip, $options[ 'check' ] )
+               );
+       }
+
+       public static function provideIsDnsBlacklisted() {
+               return [
+                       'IP is blacklisted' => [
+                               [
+                                       'inBlacklist' => true,
+                                       'inWhitelist' => false,
+                                       'check' => false,
+                               ],
+                               true,
+                       ],
+                       'IP is not blacklisted' => [
+                               [
+                                       'inBlacklist' => false,
+                                       'inWhitelist' => false,
+                                       'check' => false,
+                               ],
+                               false,
+                       ],
+                       'IP is blacklisted and whitelisted; whitelist is checked' => [
+                               [
+                                       'inBlacklist' => true,
+                                       'inWhitelist' => true,
+                                       'check' => false,
+                               ],
+                               true,
+                       ],
+                       'IP is blacklisted and whitelisted; whitelist is not checked' => [
+                               [
+                                       'inBlacklist' => true,
+                                       'inWhitelist' => true,
+                                       'check' => true,
+                               ],
+                               false,
+                       ],
+               ];
+       }
+}
diff --git a/tests/phpunit/includes/block/BlockRestrictionStoreTest.php b/tests/phpunit/includes/block/BlockRestrictionStoreTest.php
new file mode 100644 (file)
index 0000000..4eef457
--- /dev/null
@@ -0,0 +1,612 @@
+<?php
+
+namespace MediaWiki\Tests\Block;
+
+use MediaWiki\Block\BlockRestrictionStore;
+use MediaWiki\Block\Restriction\NamespaceRestriction;
+use MediaWiki\Block\Restriction\PageRestriction;
+use MediaWiki\Block\Restriction\Restriction;
+use MediaWiki\MediaWikiServices;
+
+/**
+ * @group Database
+ * @group Blocking
+ * @coversDefaultClass \MediaWiki\Block\BlockRestrictionStore
+ */
+class BlockRestrictionStoreTest extends \MediaWikiLangTestCase {
+
+       /** @var BlockRestrictionStore */
+       protected $blockRestrictionStore;
+
+       public function setUp() {
+               parent::setUp();
+
+               $this->blockRestrictionStore = MediaWikiServices::getInstance()->getBlockRestrictionStore();
+       }
+
+       public function tearDown() {
+               parent::tearDown();
+               $this->resetTables();
+       }
+
+       /**
+        * @covers ::loadByBlockId
+        * @covers ::resultToRestrictions
+        * @covers ::rowToRestriction
+        */
+       public function testLoadMultipleRestrictions() {
+               $this->setMwGlobals( [
+                       'wgBlockDisablesLogin' => false,
+               ] );
+               $block = $this->insertBlock();
+
+               $pageFoo = $this->getExistingTestPage( 'Foo' );
+               $pageBar = $this->getExistingTestPage( 'Bar' );
+
+               $this->blockRestrictionStore->insert( [
+                       new PageRestriction( $block->getId(), $pageFoo->getId() ),
+                       new PageRestriction( $block->getId(), $pageBar->getId() ),
+                       new NamespaceRestriction( $block->getId(), NS_USER ),
+               ] );
+
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $block->getId() );
+
+               $this->assertCount( 3, $restrictions );
+       }
+
+       /**
+        * @covers ::loadByBlockId
+        * @covers ::resultToRestrictions
+        * @covers ::rowToRestriction
+        */
+       public function testWithNoRestrictions() {
+               $block = $this->insertBlock();
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $block->getId() );
+               $this->assertEmpty( $restrictions );
+       }
+
+       /**
+        * @covers ::loadByBlockId
+        * @covers ::resultToRestrictions
+        * @covers ::rowToRestriction
+        */
+       public function testWithEmptyParam() {
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( [] );
+               $this->assertEmpty( $restrictions );
+       }
+
+       /**
+        * @covers ::loadByBlockId
+        * @covers ::resultToRestrictions
+        * @covers ::rowToRestriction
+        */
+       public function testIgnoreNotSupportedTypes() {
+               $block = $this->insertBlock();
+
+               $pageFoo = $this->getExistingTestPage( 'Foo' );
+               $pageBar = $this->getExistingTestPage( 'Bar' );
+
+               // valid type
+               $this->insertRestriction( $block->getId(), PageRestriction::TYPE_ID, $pageFoo->getId() );
+               $this->insertRestriction( $block->getId(), NamespaceRestriction::TYPE_ID, NS_USER );
+
+               // invalid type
+               $this->insertRestriction( $block->getId(), 9, $pageBar->getId() );
+               $this->insertRestriction( $block->getId(), 10, NS_FILE );
+
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $block->getId() );
+               $this->assertCount( 2, $restrictions );
+       }
+
+       /**
+        * @covers ::loadByBlockId
+        * @covers ::resultToRestrictions
+        * @covers ::rowToRestriction
+        */
+       public function testMappingPageRestrictionObject() {
+               $block = $this->insertBlock();
+               $title = 'Lady Macbeth';
+               $page = $this->getExistingTestPage( $title );
+
+               // Test Page Restrictions.
+               $this->blockRestrictionStore->insert( [
+                       new PageRestriction( $block->getId(), $page->getId() ),
+               ] );
+
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $block->getId() );
+
+               list( $pageRestriction ) = $restrictions;
+               $this->assertInstanceOf( PageRestriction::class, $pageRestriction );
+               $this->assertEquals( $block->getId(), $pageRestriction->getBlockId() );
+               $this->assertEquals( $page->getId(), $pageRestriction->getValue() );
+               $this->assertEquals( $pageRestriction->getType(), PageRestriction::TYPE );
+               $this->assertEquals( $pageRestriction->getTitle()->getText(), $title );
+       }
+
+       /**
+        * @covers ::loadByBlockId
+        * @covers ::resultToRestrictions
+        * @covers ::rowToRestriction
+        */
+       public function testMappingNamespaceRestrictionObject() {
+               $block = $this->insertBlock();
+
+               $this->blockRestrictionStore->insert( [
+                       new NamespaceRestriction( $block->getId(), NS_USER ),
+               ] );
+
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $block->getId() );
+
+               list( $namespaceRestriction ) = $restrictions;
+               $this->assertInstanceOf( NamespaceRestriction::class, $namespaceRestriction );
+               $this->assertEquals( $block->getId(), $namespaceRestriction->getBlockId() );
+               $this->assertSame( NS_USER, $namespaceRestriction->getValue() );
+               $this->assertEquals( $namespaceRestriction->getType(), NamespaceRestriction::TYPE );
+       }
+
+       /**
+        * @covers ::insert
+        */
+       public function testInsert() {
+               $block = $this->insertBlock();
+
+               $pageFoo = $this->getExistingTestPage( 'Foo' );
+               $pageBar = $this->getExistingTestPage( 'Bar' );
+
+               $restrictions = [
+                       new \stdClass(),
+                       new PageRestriction( $block->getId(), $pageFoo->getId() ),
+                       new PageRestriction( $block->getId(), $pageBar->getId() ),
+                       new NamespaceRestriction( $block->getId(), NS_USER )
+               ];
+
+               $result = $this->blockRestrictionStore->insert( $restrictions );
+               $this->assertTrue( $result );
+
+               $restrictions = [
+                       new \stdClass(),
+               ];
+
+               $result = $this->blockRestrictionStore->insert( $restrictions );
+               $this->assertFalse( $result );
+
+               $result = $this->blockRestrictionStore->insert( [] );
+               $this->assertFalse( $result );
+       }
+
+       /**
+        * @covers ::insert
+        */
+       public function testInsertTypes() {
+               $block = $this->insertBlock();
+
+               $pageFoo = $this->getExistingTestPage( 'Foo' );
+               $pageBar = $this->getExistingTestPage( 'Bar' );
+
+               $invalid = $this->createMock( Restriction::class );
+               $invalid->method( 'toRow' )
+                       ->willReturn( [
+                               'ir_ipb_id' => $block->getId(),
+                               'ir_type' => 9,
+                               'ir_value' => 42,
+                       ] );
+
+               $restrictions = [
+                       new \stdClass(),
+                       new PageRestriction( $block->getId(), $pageFoo->getId() ),
+                       new PageRestriction( $block->getId(), $pageBar->getId() ),
+                       new NamespaceRestriction( $block->getId(), NS_USER ),
+                       $invalid,
+               ];
+
+               $result = $this->blockRestrictionStore->insert( $restrictions );
+               $this->assertTrue( $result );
+
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $block->getId() );
+               $this->assertCount( 3, $restrictions );
+       }
+
+       /**
+        * @covers ::update
+        * @covers ::restrictionsByBlockId
+        * @covers ::restrictionsToRemove
+        */
+       public function testUpdateInsert() {
+               $block = $this->insertBlock();
+               $pageFoo = $this->getExistingTestPage( 'Foo' );
+               $pageBar = $this->getExistingTestPage( 'Bar' );
+               $this->blockRestrictionStore->insert( [
+                               new PageRestriction( $block->getId(), $pageFoo->getId() ),
+               ] );
+
+               $this->blockRestrictionStore->update( [
+                       new \stdClass(),
+                       new PageRestriction( $block->getId(), $pageBar->getId() ),
+                       new NamespaceRestriction( $block->getId(), NS_USER ),
+               ] );
+
+               $db = wfGetDb( DB_REPLICA );
+               $result = $db->select(
+                       [ 'ipblocks_restrictions' ],
+                       [ '*' ],
+                       [ 'ir_ipb_id' => $block->getId() ]
+               );
+
+               $this->assertEquals( 2, $result->numRows() );
+               $row = $result->fetchObject();
+               $this->assertEquals( $block->getId(), $row->ir_ipb_id );
+               $this->assertEquals( $pageBar->getId(), $row->ir_value );
+       }
+
+       /**
+        * @covers ::update
+        * @covers ::restrictionsByBlockId
+        * @covers ::restrictionsToRemove
+        */
+       public function testUpdateChange() {
+               $block = $this->insertBlock();
+               $page = $this->getExistingTestPage( 'Foo' );
+
+               $this->blockRestrictionStore->update( [
+                       new PageRestriction( $block->getId(), $page->getId() ),
+               ] );
+
+               $db = wfGetDb( DB_REPLICA );
+               $result = $db->select(
+                       [ 'ipblocks_restrictions' ],
+                       [ '*' ],
+                       [ 'ir_ipb_id' => $block->getId() ]
+               );
+
+               $this->assertEquals( 1, $result->numRows() );
+               $row = $result->fetchObject();
+               $this->assertEquals( $block->getId(), $row->ir_ipb_id );
+               $this->assertEquals( $page->getId(), $row->ir_value );
+       }
+
+       /**
+        * @covers ::update
+        * @covers ::restrictionsByBlockId
+        * @covers ::restrictionsToRemove
+        */
+       public function testUpdateNoRestrictions() {
+               $block = $this->insertBlock();
+
+               $this->blockRestrictionStore->update( [] );
+
+               $db = wfGetDb( DB_REPLICA );
+               $result = $db->select(
+                       [ 'ipblocks_restrictions' ],
+                       [ '*' ],
+                       [ 'ir_ipb_id' => $block->getId() ]
+               );
+
+               $this->assertEquals( 0, $result->numRows() );
+       }
+
+       /**
+        * @covers ::update
+        * @covers ::restrictionsByBlockId
+        * @covers ::restrictionsToRemove
+        */
+       public function testUpdateSame() {
+               $block = $this->insertBlock();
+               $page = $this->getExistingTestPage( 'Foo' );
+               $this->blockRestrictionStore->insert( [
+                       new PageRestriction( $block->getId(), $page->getId() ),
+               ] );
+
+               $this->blockRestrictionStore->update( [
+                       new PageRestriction( $block->getId(), $page->getId() ),
+               ] );
+
+               $db = wfGetDb( DB_REPLICA );
+               $result = $db->select(
+                       [ 'ipblocks_restrictions' ],
+                       [ '*' ],
+                       [ 'ir_ipb_id' => $block->getId() ]
+               );
+
+               $this->assertEquals( 1, $result->numRows() );
+               $row = $result->fetchObject();
+               $this->assertEquals( $block->getId(), $row->ir_ipb_id );
+               $this->assertEquals( $page->getId(), $row->ir_value );
+       }
+
+       /**
+        * @covers ::updateByParentBlockId
+        */
+       public function testDeleteAllUpdateByParentBlockId() {
+               // Create a block and an autoblock (a child block)
+               $block = $this->insertBlock();
+               $pageFoo = $this->getExistingTestPage( 'Foo' );
+               $pageBar = $this->getExistingTestPage( 'Bar' );
+               $this->blockRestrictionStore->insert( [
+                       new PageRestriction( $block->getId(), $pageFoo->getId() ),
+               ] );
+               $autoblockId = $block->doAutoblock( '127.0.0.1' );
+
+               // Ensure that the restrictions on the block have not changed.
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $block->getId() );
+               $this->assertCount( 1, $restrictions );
+               $this->assertEquals( $pageFoo->getId(), $restrictions[0]->getValue() );
+
+               // Ensure that the restrictions on the autoblock are the same as the block.
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $autoblockId );
+               $this->assertCount( 1, $restrictions );
+               $this->assertEquals( $pageFoo->getId(), $restrictions[0]->getValue() );
+
+               // Update the restrictions on the autoblock (but leave the block unchanged)
+               $this->blockRestrictionStore->updateByParentBlockId( $block->getId(), [
+                       new PageRestriction( $block->getId(), $pageBar->getId() ),
+               ] );
+
+               // Ensure that the restrictions on the block have not changed.
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $block->getId() );
+               $this->assertCount( 1, $restrictions );
+               $this->assertEquals( $pageFoo->getId(), $restrictions[0]->getValue() );
+
+               // Ensure that the restrictions on the autoblock have been updated.
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $autoblockId );
+               $this->assertCount( 1, $restrictions );
+               $this->assertEquals( $pageBar->getId(), $restrictions[0]->getValue() );
+       }
+
+       /**
+        * @covers ::updateByParentBlockId
+        */
+       public function testUpdateByParentBlockId() {
+               // Create a block and an autoblock (a child block)
+               $block = $this->insertBlock();
+               $page = $this->getExistingTestPage( 'Foo' );
+               $this->blockRestrictionStore->insert( [
+                       new PageRestriction( $block->getId(), $page->getId() ),
+               ] );
+               $autoblockId = $block->doAutoblock( '127.0.0.1' );
+
+               // Ensure that the restrictions on the block have not changed.
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $block->getId() );
+               $this->assertCount( 1, $restrictions );
+
+               // Ensure that the restrictions on the autoblock have not changed.
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $autoblockId );
+               $this->assertCount( 1, $restrictions );
+
+               // Remove the restrictions on the autoblock (but leave the block unchanged)
+               $this->blockRestrictionStore->updateByParentBlockId( $block->getId(), [] );
+
+               // Ensure that the restrictions on the block have not changed.
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $block->getId() );
+               $this->assertCount( 1, $restrictions );
+
+               // Ensure that the restrictions on the autoblock have been updated.
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $autoblockId );
+               $this->assertCount( 0, $restrictions );
+       }
+
+       /**
+        * @covers ::updateByParentBlockId
+        */
+       public function testNoAutoblocksUpdateByParentBlockId() {
+               // Create a block with no autoblock.
+               $block = $this->insertBlock();
+               $page = $this->getExistingTestPage( 'Foo' );
+               $this->blockRestrictionStore->insert( [
+                       new PageRestriction( $block->getId(), $page->getId() ),
+               ] );
+
+               // Ensure that the restrictions on the block have not changed.
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $block->getId() );
+               $this->assertCount( 1, $restrictions );
+
+               // Update the restrictions on any autoblocks (there are none).
+               $this->blockRestrictionStore->updateByParentBlockId( $block->getId(), $restrictions );
+
+               // Ensure that the restrictions on the block have not changed.
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $block->getId() );
+               $this->assertCount( 1, $restrictions );
+       }
+
+       /**
+        * @covers ::delete
+        */
+       public function testDelete() {
+               $block = $this->insertBlock();
+               $page = $this->getExistingTestPage( 'Foo' );
+               $this->blockRestrictionStore->insert( [
+                       new PageRestriction( $block->getId(), $page->getId() ),
+               ] );
+
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $block->getId() );
+               $this->assertCount( 1, $restrictions );
+
+               $result = $this->blockRestrictionStore->delete(
+                       array_merge( $restrictions, [ new \stdClass() ] )
+               );
+               $this->assertTrue( $result );
+
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $block->getId() );
+               $this->assertCount( 0, $restrictions );
+       }
+
+       /**
+        * @covers ::deleteByBlockId
+        */
+       public function testDeleteByBlockId() {
+               $block = $this->insertBlock();
+               $page = $this->getExistingTestPage( 'Foo' );
+               $this->blockRestrictionStore->insert( [
+                       new PageRestriction( $block->getId(), $page->getId() ),
+               ] );
+
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $block->getId() );
+               $this->assertCount( 1, $restrictions );
+
+               $result = $this->blockRestrictionStore->deleteByBlockId( $block->getId() );
+               $this->assertNotFalse( $result );
+
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $block->getId() );
+               $this->assertCount( 0, $restrictions );
+       }
+
+       /**
+        * @covers ::deleteByParentBlockId
+        */
+       public function testDeleteByParentBlockId() {
+               // Create a block with no autoblock.
+               $block = $this->insertBlock();
+               $page = $this->getExistingTestPage( 'Foo' );
+               $this->blockRestrictionStore->insert( [
+                       new PageRestriction( $block->getId(), $page->getId() ),
+               ] );
+               $autoblockId = $block->doAutoblock( '127.0.0.1' );
+
+               // Ensure that the restrictions on the block have not changed.
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $block->getId() );
+               $this->assertCount( 1, $restrictions );
+
+               // Ensure that the restrictions on the autoblock are the same as the block.
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $autoblockId );
+               $this->assertCount( 1, $restrictions );
+
+               // Remove all of the restrictions on the autoblock (but leave the block unchanged).
+               $result = $this->blockRestrictionStore->deleteByParentBlockId( $block->getId() );
+               // NOTE: commented out until https://gerrit.wikimedia.org/r/c/mediawiki/core/+/469324 is merged
+               //$this->assertTrue( $result );
+
+               // Ensure that the restrictions on the block have not changed.
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $block->getId() );
+               $this->assertCount( 1, $restrictions );
+
+               // Ensure that the restrictions on the autoblock have been removed.
+               $restrictions = $this->blockRestrictionStore->loadByBlockId( $autoblockId );
+               $this->assertCount( 0, $restrictions );
+       }
+
+       /**
+        * @covers ::equals
+        * @dataProvider equalsDataProvider
+        *
+        * @param array $a
+        * @param array $b
+        * @param bool $expected
+        */
+       public function testEquals( array $a, array $b, $expected ) {
+               $this->assertSame( $expected, $this->blockRestrictionStore->equals( $a, $b ) );
+       }
+
+       public function equalsDataProvider() {
+               return [
+                       [
+                               [
+                                       new \stdClass(),
+                                       new PageRestriction( 1, 1 ),
+                               ],
+                               [
+                                       new \stdClass(),
+                                       new PageRestriction( 1, 2 )
+                               ],
+                               false,
+                       ],
+                       [
+                               [
+                                       new PageRestriction( 1, 1 ),
+                               ],
+                               [
+                                       new PageRestriction( 1, 1 ),
+                                       new PageRestriction( 1, 2 )
+                               ],
+                               false,
+                       ],
+                       [
+                               [],
+                               [],
+                               true,
+                       ],
+                       [
+                               [
+                                       new PageRestriction( 1, 1 ),
+                                       new PageRestriction( 1, 2 ),
+                                       new PageRestriction( 2, 3 ),
+                               ],
+                               [
+                                       new PageRestriction( 2, 3 ),
+                                       new PageRestriction( 1, 2 ),
+                                       new PageRestriction( 1, 1 ),
+                               ],
+                               true
+                       ],
+                       [
+                               [
+                                       new NamespaceRestriction( 1, NS_USER ),
+                               ],
+                               [
+                                       new NamespaceRestriction( 1, NS_USER ),
+                               ],
+                               true
+                       ],
+                       [
+                               [
+                                       new NamespaceRestriction( 1, NS_USER ),
+                               ],
+                               [
+                                       new NamespaceRestriction( 1, NS_TALK ),
+                               ],
+                               false
+                       ],
+               ];
+       }
+
+       /**
+        * @covers ::setBlockId
+        */
+       public function testSetBlockId() {
+               $restrictions = [
+                       new \stdClass(),
+                       new PageRestriction( 1, 1 ),
+                       new PageRestriction( 1, 2 ),
+                       new NamespaceRestriction( 1, NS_USER ),
+               ];
+
+               $this->assertSame( 1, $restrictions[1]->getBlockId() );
+               $this->assertSame( 1, $restrictions[2]->getBlockId() );
+               $this->assertSame( 1, $restrictions[3]->getBlockId() );
+
+               $result = $this->blockRestrictionStore->setBlockId( 2, $restrictions );
+
+               foreach ( $result as $restriction ) {
+                       $this->assertSame( 2, $restriction->getBlockId() );
+               }
+       }
+
+       protected function insertBlock() {
+               $badActor = $this->getTestUser()->getUser();
+               $sysop = $this->getTestSysop()->getUser();
+
+               $block = new \Block( [
+                       'address' => $badActor->getName(),
+                       'user' => $badActor->getId(),
+                       'by' => $sysop->getId(),
+                       'expiry' => 'infinity',
+                       'sitewide' => 0,
+                       'enableAutoblock' => true,
+               ] );
+
+               $block->insert();
+
+               return $block;
+       }
+
+       protected function insertRestriction( $blockId, $type, $value ) {
+               $this->db->insert( 'ipblocks_restrictions', [
+                       'ir_ipb_id' => $blockId,
+                       'ir_type' => $type,
+                       'ir_value' => $value,
+               ] );
+       }
+
+       protected function resetTables() {
+               $this->db->delete( 'ipblocks', '*', __METHOD__ );
+               $this->db->delete( 'ipblocks_restrictions', '*', __METHOD__ );
+       }
+}
diff --git a/tests/phpunit/includes/block/BlockRestrictionTest.php b/tests/phpunit/includes/block/BlockRestrictionTest.php
deleted file mode 100644 (file)
index 5bbd3d0..0000000
+++ /dev/null
@@ -1,601 +0,0 @@
-<?php
-
-namespace MediaWiki\Tests\Block;
-
-use MediaWiki\Block\BlockRestriction;
-use MediaWiki\Block\Restriction\NamespaceRestriction;
-use MediaWiki\Block\Restriction\PageRestriction;
-use MediaWiki\Block\Restriction\Restriction;
-
-/**
- * @group Database
- * @group Blocking
- * @coversDefaultClass \MediaWiki\Block\BlockRestriction
- */
-class BlockRestrictionTest extends \MediaWikiLangTestCase {
-
-       public function tearDown() {
-               parent::tearDown();
-               $this->resetTables();
-       }
-
-       /**
-        * @covers ::loadByBlockId
-        * @covers ::resultToRestrictions
-        * @covers ::rowToRestriction
-        */
-       public function testLoadMultipleRestrictions() {
-               $this->setMwGlobals( [
-                       'wgBlockDisablesLogin' => false,
-               ] );
-               $block = $this->insertBlock();
-
-               $pageFoo = $this->getExistingTestPage( 'Foo' );
-               $pageBar = $this->getExistingTestPage( 'Bar' );
-
-               BlockRestriction::insert( [
-                       new PageRestriction( $block->getId(), $pageFoo->getId() ),
-                       new PageRestriction( $block->getId(), $pageBar->getId() ),
-                       new NamespaceRestriction( $block->getId(), NS_USER ),
-               ] );
-
-               $restrictions = BlockRestriction::loadByBlockId( $block->getId() );
-
-               $this->assertCount( 3, $restrictions );
-       }
-
-       /**
-        * @covers ::loadByBlockId
-        * @covers ::resultToRestrictions
-        * @covers ::rowToRestriction
-        */
-       public function testWithNoRestrictions() {
-               $block = $this->insertBlock();
-               $restrictions = BlockRestriction::loadByBlockId( $block->getId() );
-               $this->assertEmpty( $restrictions );
-       }
-
-       /**
-        * @covers ::loadByBlockId
-        * @covers ::resultToRestrictions
-        * @covers ::rowToRestriction
-        */
-       public function testWithEmptyParam() {
-               $restrictions = BlockRestriction::loadByBlockId( [] );
-
-               $this->assertEmpty( $restrictions );
-       }
-
-       /**
-        * @covers ::loadByBlockId
-        * @covers ::resultToRestrictions
-        * @covers ::rowToRestriction
-        */
-       public function testIgnoreNotSupportedTypes() {
-               $block = $this->insertBlock();
-
-               $pageFoo = $this->getExistingTestPage( 'Foo' );
-               $pageBar = $this->getExistingTestPage( 'Bar' );
-
-               // valid type
-               $this->insertRestriction( $block->getId(), PageRestriction::TYPE_ID, $pageFoo->getId() );
-               $this->insertRestriction( $block->getId(), NamespaceRestriction::TYPE_ID, NS_USER );
-
-               // invalid type
-               $this->insertRestriction( $block->getId(), 9, $pageBar->getId() );
-               $this->insertRestriction( $block->getId(), 10, NS_FILE );
-
-               $restrictions = BlockRestriction::loadByBlockId( $block->getId() );
-               $this->assertCount( 2, $restrictions );
-       }
-
-       /**
-        * @covers ::loadByBlockId
-        * @covers ::resultToRestrictions
-        * @covers ::rowToRestriction
-        */
-       public function testMappingPageRestrictionObject() {
-               $block = $this->insertBlock();
-               $title = 'Lady Macbeth';
-               $page = $this->getExistingTestPage( $title );
-
-               // Test Page Restrictions.
-               BlockRestriction::insert( [
-                       new PageRestriction( $block->getId(), $page->getId() ),
-               ] );
-
-               $restrictions = BlockRestriction::loadByBlockId( $block->getId() );
-
-               list( $pageRestriction ) = $restrictions;
-               $this->assertInstanceOf( PageRestriction::class, $pageRestriction );
-               $this->assertEquals( $block->getId(), $pageRestriction->getBlockId() );
-               $this->assertEquals( $page->getId(), $pageRestriction->getValue() );
-               $this->assertEquals( $pageRestriction->getType(), PageRestriction::TYPE );
-               $this->assertEquals( $pageRestriction->getTitle()->getText(), $title );
-       }
-
-       /**
-        * @covers ::loadByBlockId
-        * @covers ::resultToRestrictions
-        * @covers ::rowToRestriction
-        */
-       public function testMappingNamespaceRestrictionObject() {
-               $block = $this->insertBlock();
-
-               BlockRestriction::insert( [
-                       new NamespaceRestriction( $block->getId(), NS_USER ),
-               ] );
-
-               $restrictions = BlockRestriction::loadByBlockId( $block->getId() );
-
-               list( $namespaceRestriction ) = $restrictions;
-               $this->assertInstanceOf( NamespaceRestriction::class, $namespaceRestriction );
-               $this->assertEquals( $block->getId(), $namespaceRestriction->getBlockId() );
-               $this->assertSame( NS_USER, $namespaceRestriction->getValue() );
-               $this->assertEquals( $namespaceRestriction->getType(), NamespaceRestriction::TYPE );
-       }
-
-       /**
-        * @covers ::insert
-        */
-       public function testInsert() {
-               $block = $this->insertBlock();
-
-               $pageFoo = $this->getExistingTestPage( 'Foo' );
-               $pageBar = $this->getExistingTestPage( 'Bar' );
-
-               $restrictions = [
-                       new \stdClass(),
-                       new PageRestriction( $block->getId(), $pageFoo->getId() ),
-                       new PageRestriction( $block->getId(), $pageBar->getId() ),
-                       new NamespaceRestriction( $block->getId(), NS_USER )
-               ];
-
-               $result = BlockRestriction::insert( $restrictions );
-               $this->assertTrue( $result );
-
-               $restrictions = [
-                       new \stdClass(),
-               ];
-
-               $result = BlockRestriction::insert( $restrictions );
-               $this->assertFalse( $result );
-
-               $result = BlockRestriction::insert( [] );
-               $this->assertFalse( $result );
-       }
-
-       /**
-        * @covers ::insert
-        */
-       public function testInsertTypes() {
-               $block = $this->insertBlock();
-
-               $pageFoo = $this->getExistingTestPage( 'Foo' );
-               $pageBar = $this->getExistingTestPage( 'Bar' );
-
-               $invalid = $this->createMock( Restriction::class );
-               $invalid->method( 'toRow' )
-                       ->willReturn( [
-                               'ir_ipb_id' => $block->getId(),
-                               'ir_type' => 9,
-                               'ir_value' => 42,
-                       ] );
-
-               $restrictions = [
-                       new \stdClass(),
-                       new PageRestriction( $block->getId(), $pageFoo->getId() ),
-                       new PageRestriction( $block->getId(), $pageBar->getId() ),
-                       new NamespaceRestriction( $block->getId(), NS_USER ),
-                       $invalid,
-               ];
-
-               $result = BlockRestriction::insert( $restrictions );
-               $this->assertTrue( $result );
-
-               $restrictions = BlockRestriction::loadByBlockId( $block->getId() );
-               $this->assertCount( 3, $restrictions );
-       }
-
-       /**
-        * @covers ::update
-        * @covers ::restrictionsByBlockId
-        * @covers ::restrictionsToRemove
-        */
-       public function testUpdateInsert() {
-               $block = $this->insertBlock();
-               $pageFoo = $this->getExistingTestPage( 'Foo' );
-               $pageBar = $this->getExistingTestPage( 'Bar' );
-               BlockRestriction::insert( [
-                               new PageRestriction( $block->getId(), $pageFoo->getId() ),
-               ] );
-
-               BlockRestriction::update( [
-                       new \stdClass(),
-                       new PageRestriction( $block->getId(), $pageBar->getId() ),
-                       new NamespaceRestriction( $block->getId(), NS_USER ),
-               ] );
-
-               $db = wfGetDb( DB_REPLICA );
-               $result = $db->select(
-                       [ 'ipblocks_restrictions' ],
-                       [ '*' ],
-                       [ 'ir_ipb_id' => $block->getId() ]
-               );
-
-               $this->assertEquals( 2, $result->numRows() );
-               $row = $result->fetchObject();
-               $this->assertEquals( $block->getId(), $row->ir_ipb_id );
-               $this->assertEquals( $pageBar->getId(), $row->ir_value );
-       }
-
-       /**
-        * @covers ::update
-        * @covers ::restrictionsByBlockId
-        * @covers ::restrictionsToRemove
-        */
-       public function testUpdateChange() {
-               $block = $this->insertBlock();
-               $page = $this->getExistingTestPage( 'Foo' );
-
-               BlockRestriction::update( [
-                       new PageRestriction( $block->getId(), $page->getId() ),
-               ] );
-
-               $db = wfGetDb( DB_REPLICA );
-               $result = $db->select(
-                       [ 'ipblocks_restrictions' ],
-                       [ '*' ],
-                       [ 'ir_ipb_id' => $block->getId() ]
-               );
-
-               $this->assertEquals( 1, $result->numRows() );
-               $row = $result->fetchObject();
-               $this->assertEquals( $block->getId(), $row->ir_ipb_id );
-               $this->assertEquals( $page->getId(), $row->ir_value );
-       }
-
-       /**
-        * @covers ::update
-        * @covers ::restrictionsByBlockId
-        * @covers ::restrictionsToRemove
-        */
-       public function testUpdateNoRestrictions() {
-               $block = $this->insertBlock();
-
-               BlockRestriction::update( [] );
-
-               $db = wfGetDb( DB_REPLICA );
-               $result = $db->select(
-                       [ 'ipblocks_restrictions' ],
-                       [ '*' ],
-                       [ 'ir_ipb_id' => $block->getId() ]
-               );
-
-               $this->assertEquals( 0, $result->numRows() );
-       }
-
-       /**
-        * @covers ::update
-        * @covers ::restrictionsByBlockId
-        * @covers ::restrictionsToRemove
-        */
-       public function testUpdateSame() {
-               $block = $this->insertBlock();
-               $page = $this->getExistingTestPage( 'Foo' );
-               BlockRestriction::insert( [
-                       new PageRestriction( $block->getId(), $page->getId() ),
-               ] );
-
-               BlockRestriction::update( [
-                       new PageRestriction( $block->getId(), $page->getId() ),
-               ] );
-
-               $db = wfGetDb( DB_REPLICA );
-               $result = $db->select(
-                       [ 'ipblocks_restrictions' ],
-                       [ '*' ],
-                       [ 'ir_ipb_id' => $block->getId() ]
-               );
-
-               $this->assertEquals( 1, $result->numRows() );
-               $row = $result->fetchObject();
-               $this->assertEquals( $block->getId(), $row->ir_ipb_id );
-               $this->assertEquals( $page->getId(), $row->ir_value );
-       }
-
-       /**
-        * @covers ::updateByParentBlockId
-        */
-       public function testDeleteAllUpdateByParentBlockId() {
-               // Create a block and an autoblock (a child block)
-               $block = $this->insertBlock();
-               $pageFoo = $this->getExistingTestPage( 'Foo' );
-               $pageBar = $this->getExistingTestPage( 'Bar' );
-               BlockRestriction::insert( [
-                       new PageRestriction( $block->getId(), $pageFoo->getId() ),
-               ] );
-               $autoblockId = $block->doAutoblock( '127.0.0.1' );
-
-               // Ensure that the restrictions on the block have not changed.
-               $restrictions = BlockRestriction::loadByBlockId( $block->getId() );
-               $this->assertCount( 1, $restrictions );
-               $this->assertEquals( $pageFoo->getId(), $restrictions[0]->getValue() );
-
-               // Ensure that the restrictions on the autoblock are the same as the block.
-               $restrictions = BlockRestriction::loadByBlockId( $autoblockId );
-               $this->assertCount( 1, $restrictions );
-               $this->assertEquals( $pageFoo->getId(), $restrictions[0]->getValue() );
-
-               // Update the restrictions on the autoblock (but leave the block unchanged)
-               BlockRestriction::updateByParentBlockId( $block->getId(), [
-                       new PageRestriction( $block->getId(), $pageBar->getId() ),
-               ] );
-
-               // Ensure that the restrictions on the block have not changed.
-               $restrictions = BlockRestriction::loadByBlockId( $block->getId() );
-               $this->assertCount( 1, $restrictions );
-               $this->assertEquals( $pageFoo->getId(), $restrictions[0]->getValue() );
-
-               // Ensure that the restrictions on the autoblock have been updated.
-               $restrictions = BlockRestriction::loadByBlockId( $autoblockId );
-               $this->assertCount( 1, $restrictions );
-               $this->assertEquals( $pageBar->getId(), $restrictions[0]->getValue() );
-       }
-
-       /**
-        * @covers ::updateByParentBlockId
-        */
-       public function testUpdateByParentBlockId() {
-               // Create a block and an autoblock (a child block)
-               $block = $this->insertBlock();
-               $page = $this->getExistingTestPage( 'Foo' );
-               BlockRestriction::insert( [
-                       new PageRestriction( $block->getId(), $page->getId() ),
-               ] );
-               $autoblockId = $block->doAutoblock( '127.0.0.1' );
-
-               // Ensure that the restrictions on the block have not changed.
-               $restrictions = BlockRestriction::loadByBlockId( $block->getId() );
-               $this->assertCount( 1, $restrictions );
-
-               // Ensure that the restrictions on the autoblock have not changed.
-               $restrictions = BlockRestriction::loadByBlockId( $autoblockId );
-               $this->assertCount( 1, $restrictions );
-
-               // Remove the restrictions on the autoblock (but leave the block unchanged)
-               BlockRestriction::updateByParentBlockId( $block->getId(), [] );
-
-               // Ensure that the restrictions on the block have not changed.
-               $restrictions = BlockRestriction::loadByBlockId( $block->getId() );
-               $this->assertCount( 1, $restrictions );
-
-               // Ensure that the restrictions on the autoblock have been updated.
-               $restrictions = BlockRestriction::loadByBlockId( $autoblockId );
-               $this->assertCount( 0, $restrictions );
-       }
-
-       /**
-        * @covers ::updateByParentBlockId
-        */
-       public function testNoAutoblocksUpdateByParentBlockId() {
-               // Create a block with no autoblock.
-               $block = $this->insertBlock();
-               $page = $this->getExistingTestPage( 'Foo' );
-               BlockRestriction::insert( [
-                       new PageRestriction( $block->getId(), $page->getId() ),
-               ] );
-
-               // Ensure that the restrictions on the block have not changed.
-               $restrictions = BlockRestriction::loadByBlockId( $block->getId() );
-               $this->assertCount( 1, $restrictions );
-
-               // Update the restrictions on any autoblocks (there are none).
-               BlockRestriction::updateByParentBlockId( $block->getId(), $restrictions );
-
-               // Ensure that the restrictions on the block have not changed.
-               $restrictions = BlockRestriction::loadByBlockId( $block->getId() );
-               $this->assertCount( 1, $restrictions );
-       }
-
-       /**
-        * @covers ::delete
-        */
-       public function testDelete() {
-               $block = $this->insertBlock();
-               $page = $this->getExistingTestPage( 'Foo' );
-               BlockRestriction::insert( [
-                       new PageRestriction( $block->getId(), $page->getId() ),
-               ] );
-
-               $restrictions = BlockRestriction::loadByBlockId( $block->getId() );
-               $this->assertCount( 1, $restrictions );
-
-               $result = BlockRestriction::delete( array_merge( $restrictions, [ new \stdClass() ] ) );
-               $this->assertTrue( $result );
-
-               $restrictions = BlockRestriction::loadByBlockId( $block->getId() );
-               $this->assertCount( 0, $restrictions );
-       }
-
-       /**
-        * @covers ::deleteByBlockId
-        */
-       public function testDeleteByBlockId() {
-               $block = $this->insertBlock();
-               $page = $this->getExistingTestPage( 'Foo' );
-               BlockRestriction::insert( [
-                       new PageRestriction( $block->getId(), $page->getId() ),
-               ] );
-
-               $restrictions = BlockRestriction::loadByBlockId( $block->getId() );
-               $this->assertCount( 1, $restrictions );
-
-               $result = BlockRestriction::deleteByBlockId( $block->getId() );
-               $this->assertNotFalse( $result );
-
-               $restrictions = BlockRestriction::loadByBlockId( $block->getId() );
-               $this->assertCount( 0, $restrictions );
-       }
-
-       /**
-        * @covers ::deleteByParentBlockId
-        */
-       public function testDeleteByParentBlockId() {
-               // Create a block with no autoblock.
-               $block = $this->insertBlock();
-               $page = $this->getExistingTestPage( 'Foo' );
-               BlockRestriction::insert( [
-                       new PageRestriction( $block->getId(), $page->getId() ),
-               ] );
-               $autoblockId = $block->doAutoblock( '127.0.0.1' );
-
-               // Ensure that the restrictions on the block have not changed.
-               $restrictions = BlockRestriction::loadByBlockId( $block->getId() );
-               $this->assertCount( 1, $restrictions );
-
-               // Ensure that the restrictions on the autoblock are the same as the block.
-               $restrictions = BlockRestriction::loadByBlockId( $autoblockId );
-               $this->assertCount( 1, $restrictions );
-
-               // Remove all of the restrictions on the autoblock (but leave the block unchanged).
-               $result = BlockRestriction::deleteByParentBlockId( $block->getId() );
-               // NOTE: commented out until https://gerrit.wikimedia.org/r/c/mediawiki/core/+/469324 is merged
-               //$this->assertTrue( $result );
-
-               // Ensure that the restrictions on the block have not changed.
-               $restrictions = BlockRestriction::loadByBlockId( $block->getId() );
-               $this->assertCount( 1, $restrictions );
-
-               // Ensure that the restrictions on the autoblock have been removed.
-               $restrictions = BlockRestriction::loadByBlockId( $autoblockId );
-               $this->assertCount( 0, $restrictions );
-       }
-
-       /**
-        * @covers ::equals
-        * @dataProvider equalsDataProvider
-        *
-        * @param array $a
-        * @param array $b
-        * @param bool $expected
-        */
-       public function testEquals( array $a, array $b, $expected ) {
-               $this->assertSame( $expected, BlockRestriction::equals( $a, $b ) );
-       }
-
-       public function equalsDataProvider() {
-               return [
-                       [
-                               [
-                                       new \stdClass(),
-                                       new PageRestriction( 1, 1 ),
-                               ],
-                               [
-                                       new \stdClass(),
-                                       new PageRestriction( 1, 2 )
-                               ],
-                               false,
-                       ],
-                       [
-                               [
-                                       new PageRestriction( 1, 1 ),
-                               ],
-                               [
-                                       new PageRestriction( 1, 1 ),
-                                       new PageRestriction( 1, 2 )
-                               ],
-                               false,
-                       ],
-                       [
-                               [],
-                               [],
-                               true,
-                       ],
-                       [
-                               [
-                                       new PageRestriction( 1, 1 ),
-                                       new PageRestriction( 1, 2 ),
-                                       new PageRestriction( 2, 3 ),
-                               ],
-                               [
-                                       new PageRestriction( 2, 3 ),
-                                       new PageRestriction( 1, 2 ),
-                                       new PageRestriction( 1, 1 ),
-                               ],
-                               true
-                       ],
-                       [
-                               [
-                                       new NamespaceRestriction( 1, NS_USER ),
-                               ],
-                               [
-                                       new NamespaceRestriction( 1, NS_USER ),
-                               ],
-                               true
-                       ],
-                       [
-                               [
-                                       new NamespaceRestriction( 1, NS_USER ),
-                               ],
-                               [
-                                       new NamespaceRestriction( 1, NS_TALK ),
-                               ],
-                               false
-                       ],
-               ];
-       }
-
-       /**
-        * @covers ::setBlockId
-        */
-       public function testSetBlockId() {
-               $restrictions = [
-                       new \stdClass(),
-                       new PageRestriction( 1, 1 ),
-                       new PageRestriction( 1, 2 ),
-                       new NamespaceRestriction( 1, NS_USER ),
-               ];
-
-               $this->assertSame( 1, $restrictions[1]->getBlockId() );
-               $this->assertSame( 1, $restrictions[2]->getBlockId() );
-               $this->assertSame( 1, $restrictions[3]->getBlockId() );
-
-               $result = BlockRestriction::setBlockId( 2, $restrictions );
-
-               foreach ( $result as $restriction ) {
-                       $this->assertSame( 2, $restriction->getBlockId() );
-               }
-       }
-
-       protected function insertBlock() {
-               $badActor = $this->getTestUser()->getUser();
-               $sysop = $this->getTestSysop()->getUser();
-
-               $block = new \Block( [
-                       'address' => $badActor->getName(),
-                       'user' => $badActor->getId(),
-                       'by' => $sysop->getId(),
-                       'expiry' => 'infinity',
-                       'sitewide' => 0,
-                       'enableAutoblock' => true,
-               ] );
-
-               $block->insert();
-
-               return $block;
-       }
-
-       protected function insertRestriction( $blockId, $type, $value ) {
-               $this->db->insert( 'ipblocks_restrictions', [
-                       'ir_ipb_id' => $blockId,
-                       'ir_type' => $type,
-                       'ir_value' => $value,
-               ] );
-       }
-
-       protected function resetTables() {
-               $this->db->delete( 'ipblocks', '*', __METHOD__ );
-               $this->db->delete( 'ipblocks_restrictions', '*', __METHOD__ );
-       }
-}
index c340c08..2fa662b 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 
 use MediaWiki\MediaWikiServices;
+use Wikimedia\TestingAccessWrapper;
 
 /**
  * @group Database
@@ -58,6 +59,8 @@ class MessageCacheTest extends MediaWikiLangTestCase {
         * @param string $title Title of page to be created
         * @param string $lang Language and content of the created page
         * @param string|null $content Content of the created page, or null for a generic string
+        *
+        * @return Revision
         */
        protected function makePage( $title, $lang, $content = null ) {
                if ( $content === null ) {
@@ -70,7 +73,11 @@ class MessageCacheTest extends MediaWikiLangTestCase {
                $title = Title::newFromText( $title, NS_MEDIAWIKI );
                $wikiPage = new WikiPage( $title );
                $contentHandler = ContentHandler::makeContent( $content, $title );
-               $wikiPage->doEditContent( $contentHandler, "$lang translation test case" );
+               $status = $wikiPage->doEditContent( $contentHandler, "$lang translation test case" );
+
+               // sanity
+               $this->assertTrue( $status->isOK(), 'Create page ' . $title->getPrefixedDBkey() );
+               return $status->value['revision'];
        }
 
        /**
@@ -213,4 +220,42 @@ class MessageCacheTest extends MediaWikiLangTestCase {
 
                $this->assertEquals( 0, $dbr->trxLevel(), "No DB read queries" );
        }
+
+       /**
+        * Regression test for T218918
+        */
+       public function testLoadFromDB_fetchLatestRevision() {
+               // Create three revisions of the same message page.
+               // Must be an existing message key.
+               $key = 'Log';
+               $this->makePage( $key, 'de', 'Test eins' );
+               $this->makePage( $key, 'de', 'Test zwei' );
+               $r3 = $this->makePage( $key, 'de', 'Test drei' );
+
+               // Create an out-of-sequence revision by importing a
+               // revision with an old timestamp. Hacky.
+               $importRevision = new WikiRevision( new HashConfig() );
+               $importRevision->setTitle( $r3->getTitle() );
+               $importRevision->setComment( 'Imported edit' );
+               $importRevision->setTimestamp( '19991122001122' );
+               $importRevision->setText( 'IMPORTED OLD TEST' );
+               $importRevision->setUsername( 'ext>Alan Smithee' );
+
+               $importer = MediaWikiServices::getInstance()->getWikiRevisionOldRevisionImporterNoUpdates();
+               $importer->import( $importRevision );
+
+               // Now, load the message from the wiki page
+               MessageCache::destroyInstance();
+               $messageCache = MessageCache::singleton();
+               $messageCache->enable();
+               $messageCache = TestingAccessWrapper::newFromObject( $messageCache );
+
+               $cache = $messageCache->loadFromDB( 'de' );
+
+               $this->assertArrayHasKey( $key, $cache );
+
+               // Text in the cache has an extra space in front!
+               $this->assertSame( ' ' . 'Test drei', $cache[$key] );
+       }
+
 }
index ca3ac1b..7ad6541 100644 (file)
@@ -39,8 +39,8 @@ class CategoryMembershipChangeTest extends MediaWikiLangTestCase {
         */
        private static $pageName = 'CategoryMembershipChangeTestPage';
 
-       public static function newForCategorizationCallback() {
-               self::$lastNotifyArgs = func_get_args();
+       public static function newForCategorizationCallback( ...$args ) {
+               self::$lastNotifyArgs = $args;
                self::$notifyCallCounter += 1;
                return self::$mockRecentChange;
        }
index eff2c85..1511d46 100644 (file)
@@ -124,14 +124,14 @@ class EnhancedChangesListTest extends MediaWikiLangTestCase {
                $html = $this->createCategorizationLine(
                        $this->getCategorizationChange( '20150629191735', 0, 0 )
                );
-               $this->assertNotContains( '(diff | hist)', strip_tags( $html ) );
+               $this->assertNotContains( 'diffhist', strip_tags( $html ) );
        }
 
        public function testCategorizationLineFormattingWithRevision() {
                $html = $this->createCategorizationLine(
                        $this->getCategorizationChange( '20150629191735', 1025, 1024 )
                );
-               $this->assertContains( '(diff | hist)', strip_tags( $html ) );
+               $this->assertContains( 'diffhist', strip_tags( $html ) );
        }
 
        /**
index 91dc731..f4048b4 100644 (file)
@@ -143,7 +143,7 @@ class OldChangesListTest extends MediaWikiLangTestCase {
                $recentChange->numberofWatchingusers = 100;
 
                $line = $oldChangesList->recentChangesLine( $recentChange, false, 1 );
-               $this->assertRegExp( "/(number_of_watching_users_RCview: 100)/", $line );
+               $this->assertRegExp( "/(number-of-watching-users-for-recent-changes: 100)/", $line );
        }
 
        public function testRecentChangesLine_watchlistCssClass() {
index b1857cc..8f914b7 100644 (file)
@@ -156,14 +156,15 @@ class RCCacheEntryFactoryTest extends MediaWikiLangTestCase {
 
                $this->assertValidHTML( $cacheEntry->usertalklink );
                $this->assertRegExp(
-                       '#^ <span class="mw-usertoollinks">\(.*<a .+>talk</a>.*\)</span>#',
+                       '#^ <span class="mw-usertoollinks mw-changeslist-links">.*<span><a .+>talk</a></span>.*</span>#',
                        $cacheEntry->usertalklink,
                        'verify user talk link'
                );
 
                $this->assertValidHTML( $cacheEntry->usertalklink );
                $this->assertRegExp(
-                       '#^ <span class="mw-usertoollinks">\(.*<a .+>contribs</a>.*\)</span>$#',
+                       '#^ <span class="mw-usertoollinks mw-changeslist-links">.*<span><a .+>' .
+                               'contribs</a></span>.*</span>$#',
                        $cacheEntry->usertalklink,
                        'verify user tool links'
                );
index ec443e7..591f27d 100644 (file)
@@ -19,11 +19,10 @@ class GlobalVarConfigTest extends MediaWikiTestCase {
         */
        public function testConstructor( $prefix ) {
                $var = $prefix . 'GlobalVarConfigTest';
-               $rand = wfRandomString();
-               $this->setMwGlobals( $var, $rand );
+               $this->setMwGlobals( $var, 'testvalue' );
                $config = new GlobalVarConfig( $prefix );
                $this->assertInstanceOf( GlobalVarConfig::class, $config );
-               $this->assertEquals( $rand, $config->get( 'GlobalVarConfigTest' ) );
+               $this->assertEquals( 'testvalue', $config->get( 'GlobalVarConfigTest' ) );
        }
 
        public static function provideConstructor() {
@@ -41,7 +40,7 @@ class GlobalVarConfigTest extends MediaWikiTestCase {
         * @covers GlobalVarConfig::hasWithPrefix
         */
        public function testHas() {
-               $this->setMwGlobals( 'wgGlobalVarConfigTestHas', wfRandomString() );
+               $this->setMwGlobals( 'wgGlobalVarConfigTestHas', 'testvalue' );
                $config = new GlobalVarConfig();
                $this->assertTrue( $config->has( 'GlobalVarConfigTestHas' ) );
                $this->assertFalse( $config->has( 'GlobalVarConfigTestNotHas' ) );
diff --git a/tests/phpunit/includes/config/ServiceOptionsTest.php b/tests/phpunit/includes/config/ServiceOptionsTest.php
new file mode 100644 (file)
index 0000000..966cf41
--- /dev/null
@@ -0,0 +1,149 @@
+<?php
+
+use MediaWiki\Config\ServiceOptions;
+
+/**
+ * @coversDefaultClass \MediaWiki\Config\ServiceOptions
+ */
+class ServiceOptionsTest extends MediaWikiTestCase {
+       public static $testObj;
+
+       public static function setUpBeforeClass() {
+               parent::setUpBeforeClass();
+
+               self::$testObj = new stdclass();
+       }
+
+       /**
+        * @dataProvider provideConstructor
+        * @covers ::__construct
+        * @covers ::assertRequiredOptions
+        * @covers ::get
+        */
+       public function testConstructor( $expected, $keys, ...$sources ) {
+               $options = new ServiceOptions( $keys, ...$sources );
+
+               foreach ( $expected as $key => $val ) {
+                       $this->assertSame( $val, $options->get( $key ) );
+               }
+
+               // This is lumped in the same test because there's no support for depending on a test that
+               // has a data provider.
+               $options->assertRequiredOptions( array_keys( $expected ) );
+
+               // Suppress warning if no assertions were run. This is expected for empty arguments.
+               $this->assertTrue( true );
+       }
+
+       public function provideConstructor() {
+               return [
+                       'No keys' => [ [], [], [ 'a' => 'aval' ] ],
+                       'Simple array source' => [
+                               [ 'a' => 'aval', 'b' => 'bval' ],
+                               [ 'a', 'b' ],
+                               [ 'a' => 'aval', 'b' => 'bval', 'c' => 'cval' ],
+                       ],
+                       'Simple HashConfig source' => [
+                               [ 'a' => 'aval', 'b' => 'bval' ],
+                               [ 'a', 'b' ],
+                               new HashConfig( [ 'a' => 'aval', 'b' => 'bval', 'c' => 'cval' ] ),
+                       ],
+                       'Three different sources' => [
+                               [ 'a' => 'aval', 'b' => 'bval' ],
+                               [ 'a', 'b' ],
+                               [ 'z' => 'zval' ],
+                               new HashConfig( [ 'a' => 'aval', 'c' => 'cval' ] ),
+                               [ 'b' => 'bval', 'd' => 'dval' ],
+                       ],
+                       'null key' => [
+                               [ 'a' => null ],
+                               [ 'a' ],
+                               [ 'a' => null ],
+                       ],
+                       'Numeric option name' => [
+                               [ '0' => 'nothing' ],
+                               [ '0' ],
+                               [ '0' => 'nothing' ],
+                       ],
+                       'Multiple sources for one key' => [
+                               [ 'a' => 'winner' ],
+                               [ 'a' ],
+                               [ 'a' => 'winner' ],
+                               [ 'a' => 'second place' ],
+                       ],
+                       'Object value is passed by reference' => [
+                               [ 'a' => self::$testObj ],
+                               [ 'a' ],
+                               [ 'a' => self::$testObj ],
+                       ],
+               ];
+       }
+
+       /**
+        * @covers ::__construct
+        */
+       public function testKeyNotFound() {
+               $this->setExpectedException( InvalidArgumentException::class,
+                       'Key "a" not found in input sources' );
+
+               new ServiceOptions( [ 'a' ], [ 'b' => 'bval' ], [ 'c' => 'cval' ] );
+       }
+
+       /**
+        * @covers ::__construct
+        * @covers ::assertRequiredOptions
+        */
+       public function testOutOfOrderAssertRequiredOptions() {
+               $options = new ServiceOptions( [ 'a', 'b' ], [ 'a' => '', 'b' => '' ] );
+               $options->assertRequiredOptions( [ 'b', 'a' ] );
+               $this->assertTrue( true, 'No exception thrown' );
+       }
+
+       /**
+        * @covers ::__construct
+        * @covers ::get
+        */
+       public function testGetUnrecognized() {
+               $this->setExpectedException( InvalidArgumentException::class,
+                       'Unrecognized option "b"' );
+
+               $options = new ServiceOptions( [ 'a' ], [ 'a' => '' ] );
+               $options->get( 'b' );
+       }
+
+       /**
+        * @covers ::__construct
+        * @covers ::assertRequiredOptions
+        */
+       public function testExtraKeys() {
+               $this->setExpectedException( Wikimedia\Assert\PreconditionException::class,
+                       'Precondition failed: Unsupported options passed: b, c!' );
+
+               $options = new ServiceOptions( [ 'a', 'b', 'c' ], [ 'a' => '', 'b' => '', 'c' => '' ] );
+               $options->assertRequiredOptions( [ 'a' ] );
+       }
+
+       /**
+        * @covers ::__construct
+        * @covers ::assertRequiredOptions
+        */
+       public function testMissingKeys() {
+               $this->setExpectedException( Wikimedia\Assert\PreconditionException::class,
+                       'Precondition failed: Required options missing: a, b!' );
+
+               $options = new ServiceOptions( [ 'c' ], [ 'c' => '' ] );
+               $options->assertRequiredOptions( [ 'a', 'b', 'c' ] );
+       }
+
+       /**
+        * @covers ::__construct
+        * @covers ::assertRequiredOptions
+        */
+       public function testExtraAndMissingKeys() {
+               $this->setExpectedException( Wikimedia\Assert\PreconditionException::class,
+                       'Precondition failed: Unsupported options passed: b! Required options missing: c!' );
+
+               $options = new ServiceOptions( [ 'a', 'b' ], [ 'a' => '', 'b' => '' ] );
+               $options->assertRequiredOptions( [ 'a', 'c' ] );
+       }
+}
index f42f8b4..4eecd4d 100644 (file)
@@ -519,7 +519,7 @@ class ContentHandlerTest extends MediaWikiTestCase {
                $customContentHandler->expects( $this->any() )
                        ->method( 'createDifferenceEngine' )
                        ->willReturn( $customDifferenceEngine );
-               /** @var $customContentHandler ContentHandler */
+               /** @var ContentHandler $customContentHandler */
                $slotDiffRenderer = $customContentHandler->getSlotDiffRenderer( RequestContext::getMain() );
                $this->assertInstanceOf( DifferenceEngineSlotDiffRenderer::class, $slotDiffRenderer );
                $this->assertSame(
@@ -553,7 +553,7 @@ class ContentHandlerTest extends MediaWikiTestCase {
                $customContentHandler2->expects( $this->any() )
                        ->method( 'getSlotDiffRendererInternal' )
                        ->willReturn( $customSlotDiffRenderer );
-               /** @var $customContentHandler2 ContentHandler */
+               /** @var ContentHandler $customContentHandler2 */
                $slotDiffRenderer = $customContentHandler2->getSlotDiffRenderer( RequestContext::getMain() );
                $this->assertSame( $customSlotDiffRenderer, $slotDiffRenderer );
        }
@@ -577,7 +577,7 @@ class ContentHandlerTest extends MediaWikiTestCase {
                $customContentHandler->expects( $this->any() )
                        ->method( 'createDifferenceEngine' )
                        ->willReturn( $customDifferenceEngine );
-               /** @var $customContentHandler ContentHandler */
+               /** @var ContentHandler $customContentHandler */
 
                $customSlotDiffRenderer = $this->getMockBuilder( SlotDiffRenderer::class )
                        ->disableOriginalConstructor()
@@ -592,7 +592,7 @@ class ContentHandlerTest extends MediaWikiTestCase {
                $customContentHandler2->expects( $this->any() )
                        ->method( 'getSlotDiffRendererInternal' )
                        ->willReturn( $customSlotDiffRenderer );
-               /** @var $customContentHandler2 ContentHandler */
+               /** @var ContentHandler $customContentHandler2 */
 
                $customSlotDiffRenderer2 = $this->getMockBuilder( SlotDiffRenderer::class )
                        ->disableOriginalConstructor()
index 7cddbad..8d6c3ae 100644 (file)
@@ -92,6 +92,7 @@ class JsonContentTest extends MediaWikiLangTestCase {
                        ->disableOriginalConstructor()
                        ->getMock();
        }
+
        private function getMockParserOptions() {
                return $this->getMockBuilder( ParserOptions::class )
                        ->disableOriginalConstructor()
@@ -113,27 +114,27 @@ class JsonContentTest extends MediaWikiLangTestCase {
                        ],
                        [
                                (object)[ 'foo' ],
-                               '<table class="mw-json"><tbody><tr><th>0</th><td class="value">"foo"</td></tr>' .
+                               '<table class="mw-json"><tbody><tr><th>0</th><td class="mw-json-value">"foo"</td></tr>' .
                                '</tbody></table>'
                        ],
                        [
                                (object)[ 'foo', 'bar' ],
-                               '<table class="mw-json"><tbody><tr><th>0</th><td class="value">"foo"</td></tr>' .
-                               '<tr><th>1</th><td class="value">"bar"</td></tr></tbody></table>'
+                               '<table class="mw-json"><tbody><tr><th>0</th><td class="mw-json-value">"foo"</td></tr>' .
+                               '<tr><th>1</th><td class="mw-json-value">"bar"</td></tr></tbody></table>'
                        ],
                        [
                                (object)[ 'baz' => 'foo', 'bar' ],
-                               '<table class="mw-json"><tbody><tr><th>baz</th><td class="value">"foo"</td></tr>' .
-                               '<tr><th>0</th><td class="value">"bar"</td></tr></tbody></table>'
+                               '<table class="mw-json"><tbody><tr><th>baz</th><td class="mw-json-value">"foo"</td></tr>' .
+                               '<tr><th>0</th><td class="mw-json-value">"bar"</td></tr></tbody></table>'
                        ],
                        [
                                (object)[ 'baz' => 1000, 'bar' ],
-                               '<table class="mw-json"><tbody><tr><th>baz</th><td class="value">1000</td></tr>' .
-                               '<tr><th>0</th><td class="value">"bar"</td></tr></tbody></table>'
+                               '<table class="mw-json"><tbody><tr><th>baz</th><td class="mw-json-value">1000</td></tr>' .
+                               '<tr><th>0</th><td class="mw-json-value">"bar"</td></tr></tbody></table>'
                        ],
                        [
                                (object)[ '<script>alert("evil!")</script>' ],
-                               '<table class="mw-json"><tbody><tr><th>0</th><td class="value">"' .
+                               '<table class="mw-json"><tbody><tr><th>0</th><td class="mw-json-value">"' .
                                '&lt;script>alert("evil!")&lt;/script>"' .
                                '</td></tr></tbody></table>',
                        ],
index 6d0a3d5..e1281cd 100644 (file)
@@ -37,14 +37,14 @@ class TextContentHandlerTest extends MediaWikiLangTestCase {
                        } );
 
                /**
-                * @var $mockEngine SearchEngine
+                * @var SearchEngine $mockEngine
                 */
                $fields = $handler->getFieldsForSearchIndex( $mockEngine );
                $mappedFields = [];
                foreach ( $fields as $name => $field ) {
                        $this->assertInstanceOf( SearchIndexField::class, $field );
                        /**
-                        * @var $field SearchIndexField
+                        * @var SearchIndexField $field
                         */
                        $mappedFields[$name] = $field->getMapping( $mockEngine );
                }
index 6b1ed7f..e0b8111 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 
+use Wikimedia\Rdbms\Database;
 use Wikimedia\Rdbms\IDatabase;
 use Wikimedia\Rdbms\DatabasePostgres;
 use Wikimedia\ScopedCallback;
@@ -179,4 +180,10 @@ class DatabasePostgresTest extends MediaWikiTestCase {
                $this->doTestInsertSelectIgnore();
        }
 
+       /**
+        * @covers \Wikimedia\Rdbms\DatabasePostgres::getAttributes
+        */
+       public function testAttributes() {
+               $this->assertTrue( DatabasePostgres::getAttributes()[Database::ATTR_SCHEMAS_AS_TABLE_GROUPS] );
+       }
 }
index e61bd05..63b24dc 100644 (file)
@@ -164,9 +164,9 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
                $db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
                $this->assertEquals( 'foo', $db->tableName( 'foo' ) );
                $this->assertEquals( 'sqlite_master', $db->tableName( 'sqlite_master' ) );
-               $db->tablePrefix( 'foo' );
+               $db->tablePrefix( 'foo_' );
                $this->assertEquals( 'sqlite_master', $db->tableName( 'sqlite_master' ) );
-               $this->assertEquals( 'foobar', $db->tableName( 'bar' ) );
+               $this->assertEquals( 'foo_bar', $db->tableName( 'bar' ) );
        }
 
        /**
@@ -531,7 +531,7 @@ class DatabaseSqliteMock extends DatabaseSqlite {
                return Database::factory( 'SqliteMock', $p );
        }
 
-       function query( $sql, $fname = '', $tempIgnore = false ) {
+       function query( $sql, $fname = '', $flags = 0 ) {
                return true;
        }
 
index 9679c6c..fb4041d 100644 (file)
@@ -133,10 +133,10 @@ class DatabaseTestHelper extends Database {
                return $s;
        }
 
-       public function query( $sql, $fname = '', $tempIgnore = false ) {
+       public function query( $sql, $fname = '', $flags = 0 ) {
                $this->checkFunctionName( $fname );
 
-               return parent::query( $sql, $fname, $tempIgnore );
+               return parent::query( $sql, $fname, $flags );
        }
 
        public function tableExists( $table, $fname = __METHOD__ ) {
index 3d1bf59..106a13b 100644 (file)
@@ -23,7 +23,6 @@
  * @copyright © 2013 Wikimedia Foundation Inc.
  */
 
-use Wikimedia\Rdbms\Database;
 use Wikimedia\Rdbms\IDatabase;
 use Wikimedia\Rdbms\IMaintainableDatabase;
 use Wikimedia\Rdbms\LBFactory;
@@ -31,7 +30,6 @@ use Wikimedia\Rdbms\LBFactorySimple;
 use Wikimedia\Rdbms\LBFactoryMulti;
 use Wikimedia\Rdbms\LoadBalancer;
 use Wikimedia\Rdbms\ChronologyProtector;
-use Wikimedia\Rdbms\DatabaseMysqli;
 use Wikimedia\Rdbms\MySQLMasterPos;
 use Wikimedia\Rdbms\DatabaseDomain;
 
@@ -48,7 +46,7 @@ class LBFactoryTest extends MediaWikiTestCase {
         * @dataProvider getLBFactoryClassProvider
         */
        public function testGetLBFactoryClass( $expected, $deprecated ) {
-               $mockDB = $this->getMockBuilder( DatabaseMysqli::class )
+               $mockDB = $this->getMockBuilder( IDatabase::class )
                        ->disableOriginalConstructor()
                        ->getMock();
 
@@ -292,7 +290,7 @@ class LBFactoryTest extends MediaWikiTestCase {
                $m2Pos = new MySQLMasterPos( 'db1064-bin.002400/794074907', $now );
 
                // Master DB 1
-               $mockDB1 = $this->getMockBuilder( DatabaseMysqli::class )
+               $mockDB1 = $this->getMockBuilder( IDatabase::class )
                        ->disableOriginalConstructor()
                        ->getMock();
                $mockDB1->method( 'writesOrCallbacksPending' )->willReturn( true );
@@ -317,7 +315,7 @@ class LBFactoryTest extends MediaWikiTestCase {
                $lb1->method( 'getMasterPos' )->willReturn( $m1Pos );
                $lb1->method( 'getServerName' )->with( 0 )->willReturn( 'master1' );
                // Master DB 2
-               $mockDB2 = $this->getMockBuilder( DatabaseMysqli::class )
+               $mockDB2 = $this->getMockBuilder( IDatabase::class )
                        ->disableOriginalConstructor()
                        ->getMock();
                $mockDB2->method( 'writesOrCallbacksPending' )->willReturn( true );
@@ -348,7 +346,8 @@ class LBFactoryTest extends MediaWikiTestCase {
                        [
                                'ip' => '127.0.0.1',
                                'agent' => "Totally-Not-FireFox"
-                       ]
+                       ],
+                       null
                );
 
                $mockDB1->expects( $this->exactly( 1 ) )->method( 'writesOrCallbacksPending' );
@@ -438,6 +437,13 @@ class LBFactoryTest extends MediaWikiTestCase {
                ] );
        }
 
+       /**
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getConnection
+        * @covers \Wikimedia\Rdbms\DatabaseMysqlBase::doSelectDomain
+        * @covers \Wikimedia\Rdbms\DatabaseMysqlBase::selectDB
+        * @covers \Wikimedia\Rdbms\DatabaseMssql::selectDB
+        * @covers DatabaseOracle::selectDB
+        */
        public function testNiceDomains() {
                global $wgDBname;
 
@@ -518,6 +524,13 @@ class LBFactoryTest extends MediaWikiTestCase {
                $factory->destroy();
        }
 
+       /**
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getConnection
+        * @covers \Wikimedia\Rdbms\DatabaseMysqlBase::doSelectDomain
+        * @covers \Wikimedia\Rdbms\DatabaseMysqlBase::selectDB
+        * @covers \Wikimedia\Rdbms\DatabaseMssql::selectDB
+        * @covers DatabaseOracle::selectDB
+        */
        public function testTrickyDomain() {
                global $wgDBname;
 
@@ -530,7 +543,7 @@ class LBFactoryTest extends MediaWikiTestCase {
                $factory = $this->newLBFactoryMulti(
                        [ 'localDomain' => ( new DatabaseDomain( $dbname, null, '' ) )->getId() ],
                        [
-                               'dbName' => 'do_not_select_me' // explodes if DB is selected
+                               'dbname' => 'do_not_select_me' // explodes if DB is selected
                        ]
                );
                $lb = $factory->getMainLB();
@@ -584,46 +597,94 @@ class LBFactoryTest extends MediaWikiTestCase {
                $factory->destroy();
        }
 
+       /**
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getConnection
+        * @covers \Wikimedia\Rdbms\DatabaseMysqlBase::doSelectDomain
+        * @covers \Wikimedia\Rdbms\DatabaseMysqlBase::selectDB
+        * @covers \Wikimedia\Rdbms\DatabaseMssql::selectDB
+        * @covers DatabaseOracle::selectDB
+        */
        public function testInvalidSelectDB() {
-               // FIXME: fails under sqlite
-               $this->markTestSkippedIfDbType( 'sqlite' );
+               if ( wfGetDB( DB_MASTER )->databasesAreIndependent() ) {
+                       $this->markTestSkipped( "Not applicable per databasesAreIndependent()" );
+               }
+
                $dbname = 'unittest-domain'; // explodes if DB is selected
                $factory = $this->newLBFactoryMulti(
                        [ 'localDomain' => ( new DatabaseDomain( $dbname, null, '' ) )->getId() ],
                        [
-                               'dbName' => 'do_not_select_me' // explodes if DB is selected
+                               'dbname' => 'do_not_select_me' // explodes if DB is selected
                        ]
                );
                $lb = $factory->getMainLB();
                /** @var IDatabase $db */
                $db = $lb->getConnection( DB_MASTER, [], '' );
 
-               if ( $db->getType() === 'sqlite' ) {
+               \Wikimedia\suppressWarnings();
+               try {
                        $this->assertFalse( $db->selectDB( 'garbage-db' ) );
-               } elseif ( $db->databasesAreIndependent() ) {
-                       try {
-                               $e = null;
-                               $db->selectDB( 'garbage-db' );
-                       } catch ( \Wikimedia\Rdbms\DBConnectionError $e ) {
-                               // expected
-                       }
-                       $this->assertInstanceOf( \Wikimedia\Rdbms\DBConnectionError::class, $e );
-                       $this->assertFalse( $db->isOpen() );
-               } else {
-                       \Wikimedia\suppressWarnings();
-                       try {
-                               $this->assertFalse( $db->selectDB( 'garbage-db' ) );
-                               $this->fail( "No error thrown." );
-                       } catch ( \Wikimedia\Rdbms\DBExpectedError $e ) {
-                               $this->assertEquals(
-                                       "Could not select database 'garbage-db'.",
-                                       $e->getMessage()
-                               );
-                       }
-                       \Wikimedia\restoreWarnings();
+                       $this->fail( "No error thrown." );
+               } catch ( \Wikimedia\Rdbms\DBQueryError $e ) {
+                       $this->assertRegExp( '/[\'"]garbage-db[\'"]/', $e->getMessage() );
+               }
+               \Wikimedia\restoreWarnings();
+       }
+
+       /**
+        * @covers \Wikimedia\Rdbms\DatabaseSqlite::selectDB
+        * @covers \Wikimedia\Rdbms\DatabasePostgres::selectDB
+        * @expectedException \Wikimedia\Rdbms\DBConnectionError
+        */
+       public function testInvalidSelectDBIndependant() {
+               $dbname = 'unittest-domain'; // explodes if DB is selected
+               $factory = $this->newLBFactoryMulti(
+                       [ 'localDomain' => ( new DatabaseDomain( $dbname, null, '' ) )->getId() ],
+                       [
+                               'dbname' => 'do_not_select_me' // explodes if DB is selected
+                       ]
+               );
+               $lb = $factory->getMainLB();
+
+               if ( !wfGetDB( DB_MASTER )->databasesAreIndependent() ) {
+                       $this->markTestSkipped( "Not applicable per databasesAreIndependent()" );
                }
+
+               /** @var IDatabase $db */
+               $lb->getConnection( DB_MASTER, [], '' );
        }
 
+       /**
+        * @covers \Wikimedia\Rdbms\DatabaseSqlite::selectDB
+        * @covers \Wikimedia\Rdbms\DatabasePostgres::selectDB
+        * @expectedException \Wikimedia\Rdbms\DBConnectionError
+        */
+       public function testInvalidSelectDBIndependant2() {
+               $dbname = 'unittest-domain'; // explodes if DB is selected
+               $factory = $this->newLBFactoryMulti(
+                       [ 'localDomain' => ( new DatabaseDomain( $dbname, null, '' ) )->getId() ],
+                       [
+                               'dbname' => 'do_not_select_me' // explodes if DB is selected
+                       ]
+               );
+               $lb = $factory->getMainLB();
+
+               if ( !wfGetDB( DB_MASTER )->databasesAreIndependent() ) {
+                       $this->markTestSkipped( "Not applicable per databasesAreIndependent()" );
+               }
+
+               $db = $lb->getConnection( DB_MASTER );
+               \Wikimedia\suppressWarnings();
+               $db->selectDB( 'garbage-db' );
+               \Wikimedia\restoreWarnings();
+       }
+
+       /**
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getConnection
+        * @covers \Wikimedia\Rdbms\LoadBalancer::redefineLocalDomain
+        * @covers \Wikimedia\Rdbms\DatabaseMysqlBase::selectDB
+        * @covers \Wikimedia\Rdbms\DatabaseMssql::selectDB
+        * @covers DatabaseOracle::selectDB
+        */
        public function testRedefineLocalDomain() {
                global $wgDBname;
 
@@ -645,10 +706,10 @@ class LBFactoryTest extends MediaWikiTestCase {
                );
                unset( $conn1 );
 
-               $factory->redefineLocalDomain( 'somedb-prefix' );
-               $this->assertEquals( 'somedb-prefix', $factory->getLocalDomainID() );
+               $factory->redefineLocalDomain( 'somedb-prefix_' );
+               $this->assertEquals( 'somedb-prefix_', $factory->getLocalDomainID() );
 
-               $domain = new DatabaseDomain( $wgDBname, null, 'pref' );
+               $domain = new DatabaseDomain( $wgDBname, null, 'pref_' );
                $factory->redefineLocalDomain( $domain );
 
                $n = 0;
@@ -668,7 +729,7 @@ class LBFactoryTest extends MediaWikiTestCase {
                $factory->destroy();
        }
 
-       private function quoteTable( Database $db, $table ) {
+       private function quoteTable( IDatabase $db, $table ) {
                if ( $db->getType() === 'sqlite' ) {
                        return $table;
                } else {
index 2c4e6b4..4291bcc 100644 (file)
@@ -32,7 +32,7 @@ use Wikimedia\Rdbms\LoadMonitorNull;
  * @covers \Wikimedia\Rdbms\LoadBalancer
  */
 class LoadBalancerTest extends MediaWikiTestCase {
-       private function makeServerConfig() {
+       private function makeServerConfig( $flags = DBO_DEFAULT ) {
                global $wgDBserver, $wgDBname, $wgDBuser, $wgDBpassword, $wgDBtype, $wgSQLiteDataDir;
 
                return [
@@ -44,7 +44,7 @@ class LoadBalancerTest extends MediaWikiTestCase {
                        'type' => $wgDBtype,
                        'dbDirectory' => $wgSQLiteDataDir,
                        'load' => 0,
-                       'flags' => DBO_TRX // REPEATABLE-READ for consistency
+                       'flags' => $flags
                ];
        }
 
@@ -57,7 +57,8 @@ class LoadBalancerTest extends MediaWikiTestCase {
 
                $called = false;
                $lb = new LoadBalancer( [
-                       'servers' => [ $this->makeServerConfig() ],
+                       // Simulate web request with DBO_TRX
+                       'servers' => [ $this->makeServerConfig( DBO_TRX ) ],
                        'queryLogger' => MediaWiki\Logger\LoggerFactory::getInstance( 'DBQuery' ),
                        'localDomain' => new DatabaseDomain( $wgDBname, null, $this->dbPrefix() ),
                        'chronologyCallback' => function () use ( &$called ) {
@@ -71,8 +72,8 @@ class LoadBalancerTest extends MediaWikiTestCase {
                $this->assertSame( 'my_test_wiki', $lb->resolveDomainID( 'my_test_wiki' ) );
                $this->assertSame( $ld->getId(), $lb->resolveDomainID( false ) );
                $this->assertSame( $ld->getId(), $lb->resolveDomainID( $ld ) );
-
                $this->assertFalse( $called );
+
                $dbw = $lb->getConnection( DB_MASTER );
                $this->assertTrue( $called );
                $this->assertTrue( $dbw->getLBInfo( 'master' ), 'master shows as master' );
@@ -106,39 +107,10 @@ class LoadBalancerTest extends MediaWikiTestCase {
        }
 
        public function testWithReplica() {
-               global $wgDBserver, $wgDBname, $wgDBuser, $wgDBpassword, $wgDBtype, $wgSQLiteDataDir;
-
-               $servers = [
-                       [ // master
-                               'host'        => $wgDBserver,
-                               'dbname'      => $wgDBname,
-                               'tablePrefix' => $this->dbPrefix(),
-                               'user'        => $wgDBuser,
-                               'password'    => $wgDBpassword,
-                               'type'        => $wgDBtype,
-                               'dbDirectory' => $wgSQLiteDataDir,
-                               'load'        => 0,
-                               'flags'       => DBO_TRX // REPEATABLE-READ for consistency
-                       ],
-                       [ // emulated replica
-                               'host'        => $wgDBserver,
-                               'dbname'      => $wgDBname,
-                               'tablePrefix' => $this->dbPrefix(),
-                               'user'        => $wgDBuser,
-                               'password'    => $wgDBpassword,
-                               'type'        => $wgDBtype,
-                               'dbDirectory' => $wgSQLiteDataDir,
-                               'load'        => 100,
-                               'flags'       => DBO_TRX // REPEATABLE-READ for consistency
-                       ]
-               ];
+               global $wgDBserver;
 
-               $lb = new LoadBalancer( [
-                       'servers' => $servers,
-                       'localDomain' => new DatabaseDomain( $wgDBname, null, $this->dbPrefix() ),
-                       'queryLogger' => MediaWiki\Logger\LoggerFactory::getInstance( 'DBQuery' ),
-                       'loadMonitorClass' => LoadMonitorNull::class
-               ] );
+               // Simulate web request with DBO_TRX
+               $lb = $this->newMultiServerLocalLoadBalancer( DBO_TRX );
 
                $dbw = $lb->getConnection( DB_MASTER );
                $this->assertTrue( $dbw->getLBInfo( 'master' ), 'master shows as master' );
@@ -180,6 +152,51 @@ class LoadBalancerTest extends MediaWikiTestCase {
                $lb->closeAll();
        }
 
+       private function newSingleServerLocalLoadBalancer() {
+               global $wgDBname;
+
+               return new LoadBalancer( [
+                       'servers' => [ $this->makeServerConfig() ],
+                       'localDomain' => new DatabaseDomain( $wgDBname, null, $this->dbPrefix() )
+               ] );
+       }
+
+       private function newMultiServerLocalLoadBalancer( $flags = DBO_DEFAULT ) {
+               global $wgDBserver, $wgDBname, $wgDBuser, $wgDBpassword, $wgDBtype, $wgSQLiteDataDir;
+
+               $servers = [
+                       [ // master
+                               'host' => $wgDBserver,
+                               'dbname' => $wgDBname,
+                               'tablePrefix' => $this->dbPrefix(),
+                               'user' => $wgDBuser,
+                               'password' => $wgDBpassword,
+                               'type' => $wgDBtype,
+                               'dbDirectory' => $wgSQLiteDataDir,
+                               'load' => 0,
+                               'flags' => $flags
+                       ],
+                       [ // emulated replica
+                               'host' => $wgDBserver,
+                               'dbname' => $wgDBname,
+                               'tablePrefix' => $this->dbPrefix(),
+                               'user' => $wgDBuser,
+                               'password' => $wgDBpassword,
+                               'type' => $wgDBtype,
+                               'dbDirectory' => $wgSQLiteDataDir,
+                               'load' => 100,
+                               'flags' => $flags
+                       ]
+               ];
+
+               return new LoadBalancer( [
+                       'servers' => $servers,
+                       'localDomain' => new DatabaseDomain( $wgDBname, null, $this->dbPrefix() ),
+                       'queryLogger' => MediaWiki\Logger\LoggerFactory::getInstance( 'DBQuery' ),
+                       'loadMonitorClass' => LoadMonitorNull::class
+               ] );
+       }
+
        private function assertWriteForbidden( Database $db ) {
                try {
                        $db->delete( 'some_table', [ 'id' => 57634126 ], __METHOD__ );
@@ -286,20 +303,20 @@ class LoadBalancerTest extends MediaWikiTestCase {
         * @covers LoadBalancer::getAnyOpenConnection()
         */
        function testOpenConnection() {
-               global $wgDBname;
-
-               $lb = new LoadBalancer( [
-                       'servers' => [ $this->makeServerConfig() ],
-                       'localDomain' => new DatabaseDomain( $wgDBname, null, $this->dbPrefix() )
-               ] );
+               $lb = $this->newSingleServerLocalLoadBalancer();
 
                $i = $lb->getWriterIndex();
                $this->assertEquals( null, $lb->getAnyOpenConnection( $i ) );
+
                $conn1 = $lb->getConnection( $i );
                $this->assertNotEquals( null, $conn1 );
                $this->assertEquals( $conn1, $lb->getAnyOpenConnection( $i ) );
+               $this->assertFalse( $conn1->getFlag( DBO_TRX ) );
+
                $conn2 = $lb->getConnection( $i, [], false, $lb::CONN_TRX_AUTOCOMMIT );
                $this->assertNotEquals( null, $conn2 );
+               $this->assertFalse( $conn2->getFlag( DBO_TRX ) );
+
                if ( $lb->getServerAttributes( $i )[Database::ATTR_DB_LEVEL_LOCKING] ) {
                        $this->assertEquals( null,
                                $lb->getAnyOpenConnection( $i, $lb::CONN_TRX_AUTOCOMMIT ) );
@@ -343,7 +360,7 @@ class LoadBalancerTest extends MediaWikiTestCase {
                                'type' => $wgDBtype,
                                'dbDirectory' => $wgSQLiteDataDir,
                                'load' => 0,
-                               'flags' => DBO_TRX // REPEATABLE-READ for consistency
+                               'flags' => DBO_TRX // simulate a web request with DBO_TRX
                        ],
                ];
 
@@ -416,4 +433,60 @@ class LoadBalancerTest extends MediaWikiTestCase {
                $conn1->close();
                $conn2->close();
        }
+
+       public function testDBConnRefReadsMasterAndReplicaRoles() {
+               $lb = $this->newSingleServerLocalLoadBalancer();
+
+               $rConn = $lb->getConnectionRef( DB_REPLICA );
+               $wConn = $lb->getConnectionRef( DB_MASTER );
+               $wConn2 = $lb->getConnectionRef( 0 );
+
+               $v = [ 'value' => '1', '1' ];
+               $sql = 'SELECT MAX(1) AS value';
+               foreach ( [ $rConn, $wConn, $wConn2 ] as $conn ) {
+                       $conn->clearFlag( $conn::DBO_TRX );
+
+                       $res = $conn->query( $sql, __METHOD__ );
+                       $this->assertEquals( $v, $conn->fetchRow( $res ) );
+
+                       $res = $conn->query( $sql, __METHOD__, $conn::QUERY_REPLICA_ROLE );
+                       $this->assertEquals( $v, $conn->fetchRow( $res ) );
+               }
+
+               $wConn->getScopedLockAndFlush( 'key', __METHOD__, 1 );
+               $wConn2->getScopedLockAndFlush( 'key2', __METHOD__, 1 );
+       }
+
+       /**
+        * @expectedException \Wikimedia\Rdbms\DBReadOnlyRoleError
+        */
+       public function testDBConnRefWritesReplicaRole() {
+               $lb = $this->newSingleServerLocalLoadBalancer();
+
+               $rConn = $lb->getConnectionRef( DB_REPLICA );
+
+               $rConn->query( 'DELETE FROM sometesttable WHERE 1=0' );
+       }
+
+       /**
+        * @expectedException \Wikimedia\Rdbms\DBReadOnlyRoleError
+        */
+       public function testDBConnRefWritesReplicaRoleIndex() {
+               $lb = $this->newMultiServerLocalLoadBalancer();
+
+               $rConn = $lb->getConnectionRef( 1 );
+
+               $rConn->query( 'DELETE FROM sometesttable WHERE 1=0' );
+       }
+
+       /**
+        * @expectedException \Wikimedia\Rdbms\DBReadOnlyRoleError
+        */
+       public function testDBConnRefWritesReplicaRoleInsert() {
+               $lb = $this->newMultiServerLocalLoadBalancer();
+
+               $rConn = $lb->getConnectionRef( DB_REPLICA );
+
+               $rConn->insert( 'test', [ 't' => 1 ], __METHOD__ );
+       }
 }
index 6b977a3..b14d89c 100644 (file)
@@ -118,6 +118,16 @@ class DeprecationHelperTest extends MediaWikiTestCase {
                        $wrapper = TestingAccessWrapper::newFromObject( $this->testSubclass );
                        $this->assertSame( 1, $wrapper->privateNonDeprecated );
                }, E_USER_ERROR, "Cannot access non-public property $fullName" );
+
+               $fullName = 'TestDeprecatedSubclass::$subclassPrivateNondeprecated';
+               $this->assertErrorTriggered( function () {
+                       $this->assertSame( null, $this->testSubclass->subclassPrivateNondeprecated );
+               }, E_USER_ERROR, "Cannot access non-public property $fullName" );
+               $this->assertErrorTriggered( function () {
+                       $this->testSubclass->subclassPrivateNondeprecated = 0;
+                       $wrapper = TestingAccessWrapper::newFromObject( $this->testSubclass );
+                       $this->assertSame( 1, $wrapper->subclassPrivateNondeprecated );
+               }, E_USER_ERROR, "Cannot access non-public property $fullName" );
        }
 
        protected function assertErrorTriggered( callable $callback, $level, $message ) {
index 0b6c8cf..28f8fa2 100644 (file)
@@ -2,6 +2,8 @@
 
 class TestDeprecatedSubclass extends TestDeprecatedClass {
 
+       private $subclassPrivateNondeprecated = 1;
+
        public function getDeprecatedPrivateParentProperty() {
                return $this->privateDeprecated;
        }
index 4f82ff1..ba31b4f 100644 (file)
@@ -313,14 +313,14 @@ class DifferenceEngineTest extends MediaWikiTestCase {
                $customContentHandler->expects( $this->any() )
                        ->method( 'createDifferenceEngine' )
                        ->willReturn( $customDifferenceEngine );
-               /** @var $customContentHandler ContentHandler */
+               /** @var ContentHandler $customContentHandler */
                $customContent = $this->getMockBuilder( Content::class )
                        ->setMethods( [ 'getContentHandler' ] )
                        ->getMockForAbstractClass();
                $customContent->expects( $this->any() )
                        ->method( 'getContentHandler' )
                        ->willReturn( $customContentHandler );
-               /** @var $customContent Content */
+               /** @var Content $customContent */
                $customContent2 = clone $customContent;
 
                $slotDiffRenderer = $customContentHandler->getSlotDiffRenderer( RequestContext::getMain() );
index e08efac..c523561 100644 (file)
@@ -84,7 +84,6 @@ class TextSlotDiffRendererTest extends MediaWikiTestCase {
                $slotDiffRenderer = new TextSlotDiffRenderer();
                $slotDiffRenderer->setStatsdDataFactory( new NullStatsdDataFactory() );
                $slotDiffRenderer->setLanguage( Language::factory( 'en' ) );
-               $slotDiffRenderer->setWikiDiff2MovedParagraphDetectionCutoff( 0 );
                $slotDiffRenderer->setEngine( TextSlotDiffRenderer::ENGINE_PHP );
                return $slotDiffRenderer;
        }
index 4195f96..a63521a 100644 (file)
@@ -177,7 +177,7 @@ class TextboxBuilderTest extends MediaWikiTestCase {
                $expected
        ) {
                $this->setMwGlobals( [
-                       // set to trick MWNamespace::getRestrictionLevels
+                       // set to trick NamespaceInfo::getRestrictionLevels
                        'wgRestrictionLevels' => $restrictionLevels
                ] );
 
index 4dc2f9e..8548fde 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 
+use MediaWiki\MediaWikiServices;
 use Wikimedia\TestingAccessWrapper;
 
 /**
@@ -97,7 +98,7 @@ class FileBackendTest extends MediaWikiTestCase {
                        'name' => 'localtesting',
                        'lockManager' => LockManagerGroup::singleton()->get( 'fsLockManager' ),
                        'parallelize' => 'implicit',
-                       'wikiId' => wfWikiID() . wfRandomString(),
+                       'wikiId' => 'testdb',
                        'backends' => [
                                [
                                        'name' => 'localmultitesting1',
@@ -1538,7 +1539,8 @@ class FileBackendTest extends MediaWikiTestCase {
                $url = $this->backend->getFileHttpUrl( [ 'src' => $source ] );
 
                if ( $url !== null ) { // supported
-                       $data = Http::request( "GET", $url, [], __METHOD__ );
+                       $data = MediaWikiServices::getInstance()->getHttpRequestFactory()->
+                               get( $url, [], __METHOD__ );
                        $this->assertEquals( $content, $data,
                                "HTTP GET of URL has right contents ($backendName)." );
                }
@@ -2567,11 +2569,9 @@ class FileBackendTest extends MediaWikiTestCase {
                        'wikiId' => wfWikiID()
                ] ) );
 
-               $name = wfRandomString( 300 );
-
                $input = [
                        'headers' => [
-                               'content-Disposition' => FileBackend::makeContentDisposition( 'inline', $name ),
+                               'content-Disposition' => FileBackend::makeContentDisposition( 'inline', 'name' ),
                                'Content-dUration' => 25.6,
                                'X-LONG-VALUE' => str_pad( '0', 300 ),
                                'CONTENT-LENGTH' => 855055,
@@ -2579,7 +2579,7 @@ class FileBackendTest extends MediaWikiTestCase {
                ];
                $expected = [
                        'headers' => [
-                               'content-disposition' => FileBackend::makeContentDisposition( 'inline', $name ),
+                               'content-disposition' => FileBackend::makeContentDisposition( 'inline', 'name' ),
                                'content-duration' => 25.6,
                                'content-length' => 855055
                        ]
index 4c9855b..346be7a 100644 (file)
@@ -112,7 +112,7 @@ class FileBackendDBRepoWrapperTest extends MediaWikiTestCase {
        }
 
        protected function getMocks() {
-               $dbMock = $this->getMockBuilder( Wikimedia\Rdbms\DatabaseMysqli::class )
+               $dbMock = $this->getMockBuilder( Wikimedia\Rdbms\IDatabase::class )
                        ->disableOriginalClone()
                        ->disableOriginalConstructor()
                        ->getMock();
index 9beea5b..0c78c2b 100644 (file)
@@ -28,7 +28,7 @@ class MigrateFileRepoLayoutTest extends MediaWikiTestCase {
                        ]
                ] );
 
-               $dbMock = $this->getMockBuilder( Wikimedia\Rdbms\DatabaseMysqli::class )
+               $dbMock = $this->getMockBuilder( Wikimedia\Rdbms\IDatabase::class )
                        ->disableOriginalConstructor()
                        ->getMock();
 
index 5a343f6..67de698 100644 (file)
@@ -7,7 +7,7 @@ class RepoGroupTest extends MediaWikiTestCase {
 
        function testHasForeignRepoNegative() {
                $this->setMwGlobals( 'wgForeignFileRepos', [] );
-               RepoGroup::destroySingleton();
+               $this->overrideMwServices();
                FileBackendGroup::destroySingleton();
                $this->assertFalse( RepoGroup::singleton()->hasForeignRepos() );
        }
@@ -27,7 +27,7 @@ class RepoGroupTest extends MediaWikiTestCase {
 
        function testForEachForeignRepoNone() {
                $this->setMwGlobals( 'wgForeignFileRepos', [] );
-               RepoGroup::destroySingleton();
+               $this->overrideMwServices();
                FileBackendGroup::destroySingleton();
                $fakeCallback = $this->createMock( RepoGroupTestHelper::class );
                $fakeCallback->expects( $this->never() )->method( 'callback' );
@@ -48,7 +48,7 @@ class RepoGroupTest extends MediaWikiTestCase {
                        'apiThumbCacheExpiry' => 86400,
                        'directory' => $wgUploadDirectory
                ] ] );
-               RepoGroup::destroySingleton();
+               $this->overrideMwServices();
                FileBackendGroup::destroySingleton();
        }
 }
diff --git a/tests/phpunit/includes/http/HttpRequestFactoryTest.php b/tests/phpunit/includes/http/HttpRequestFactoryTest.php
new file mode 100644 (file)
index 0000000..7429dcc
--- /dev/null
@@ -0,0 +1,119 @@
+<?php
+
+use MediaWiki\Http\HttpRequestFactory;
+
+/**
+ * @covers MediaWiki\Http\HttpRequestFactory
+ */
+class HttpRequestFactoryTest extends MediaWikiTestCase {
+
+       /**
+        * @return HttpRequestFactory
+        */
+       private function newFactory() {
+               return new HttpRequestFactory();
+       }
+
+       /**
+        * @return HttpRequestFactory
+        */
+       private function newFactoryWithFakeRequest(
+               MWHttpRequest $req,
+               $expectedUrl,
+               $expectedOptions = []
+       ) {
+               $factory = $this->getMockBuilder( HttpRequestFactory::class )
+                       ->setMethods( [ 'create' ] )
+                       ->getMock();
+
+               $factory->method( 'create' )
+                       ->willReturnCallback(
+                               function ( $url, array $options = [], $caller = __METHOD__ )
+                                       use ( $req, $expectedUrl, $expectedOptions )
+                               {
+                                       $this->assertSame( $url, $expectedUrl );
+
+                                       foreach ( $expectedOptions as $opt => $exp ) {
+                                               $this->assertArrayHasKey( $opt, $options );
+                                               $this->assertSame( $exp, $options[$opt] );
+                                       }
+
+                                       return $req;
+                               }
+                       );
+
+               return $factory;
+       }
+
+       /**
+        * @return MWHttpRequest
+        */
+       private function newFakeRequest( $result ) {
+               $req = $this->getMockBuilder( MWHttpRequest::class )
+                       ->disableOriginalConstructor()
+                       ->setMethods( [ 'getContent', 'execute' ] )
+                       ->getMock();
+
+               if ( $result instanceof Status ) {
+                       $req->method( 'getContent' )
+                               ->willReturn( $result->getValue() );
+                       $req->method( 'execute' )
+                               ->willReturn( $result );
+               } else {
+                       $req->method( 'getContent' )
+                               ->willReturn( $result );
+                       $req->method( 'execute' )
+                               ->willReturn( Status::newGood( $result ) );
+               }
+
+               return $req;
+       }
+
+       public function testCreate() {
+               $factory = $this->newFactory();
+               $this->assertInstanceOf( 'MWHttpRequest', $factory->create( 'http://example.test' ) );
+       }
+
+       public function testGetUserAgent() {
+               $factory = $this->newFactory();
+               $this->assertStringStartsWith( 'MediaWiki/', $factory->getUserAgent() );
+       }
+
+       public function testGet() {
+               $req = $this->newFakeRequest( __METHOD__ );
+               $factory = $this->newFactoryWithFakeRequest(
+                       $req, 'https://example.test', [ 'method' => 'GET' ]
+               );
+
+               $this->assertSame( __METHOD__, $factory->get( 'https://example.test' ) );
+       }
+
+       public function testPost() {
+               $req = $this->newFakeRequest( __METHOD__ );
+               $factory = $this->newFactoryWithFakeRequest(
+                       $req, 'https://example.test', [ 'method' => 'POST' ]
+               );
+
+               $this->assertSame( __METHOD__, $factory->post( 'https://example.test' ) );
+       }
+
+       public function testRequest() {
+               $req = $this->newFakeRequest( __METHOD__ );
+               $factory = $this->newFactoryWithFakeRequest(
+                       $req, 'https://example.test', [ 'method' => 'GET' ]
+               );
+
+               $this->assertSame( __METHOD__, $factory->request( 'GET', 'https://example.test' ) );
+       }
+
+       public function testRequest_failed() {
+               $status = Status::newFatal( 'testing' );
+               $req = $this->newFakeRequest( $status );
+               $factory = $this->newFactoryWithFakeRequest(
+                       $req, 'https://example.test', [ 'method' => 'POST' ]
+               );
+
+               $this->assertNull( $factory->request( 'POST', 'https://example.test' ) );
+       }
+
+}
index fedfac6..09bcfc9 100644 (file)
@@ -1,53 +1,11 @@
 <?php
 
 /**
+ * @covers Http
  * @group Http
  * @group small
  */
 class HttpTest extends MediaWikiTestCase {
-       /**
-        * @dataProvider cookieDomains
-        * @covers Cookie::validateCookieDomain
-        */
-       public function testValidateCookieDomain( $expected, $domain, $origin = null ) {
-               if ( $origin ) {
-                       $ok = Cookie::validateCookieDomain( $domain, $origin );
-                       $msg = "$domain against origin $origin";
-               } else {
-                       $ok = Cookie::validateCookieDomain( $domain );
-                       $msg = "$domain";
-               }
-               $this->assertEquals( $expected, $ok, $msg );
-       }
-
-       public static function cookieDomains() {
-               return [
-                       [ false, "org" ],
-                       [ false, ".org" ],
-                       [ true, "wikipedia.org" ],
-                       [ true, ".wikipedia.org" ],
-                       [ false, "co.uk" ],
-                       [ false, ".co.uk" ],
-                       [ false, "gov.uk" ],
-                       [ false, ".gov.uk" ],
-                       [ true, "supermarket.uk" ],
-                       [ false, "uk" ],
-                       [ false, ".uk" ],
-                       [ false, "127.0.0." ],
-                       [ false, "127." ],
-                       [ false, "127.0.0.1." ],
-                       [ true, "127.0.0.1" ],
-                       [ false, "333.0.0.1" ],
-                       [ true, "example.com" ],
-                       [ false, "example.com." ],
-                       [ true, ".example.com" ],
-
-                       [ true, ".example.com", "www.example.com" ],
-                       [ false, "example.com", "www.example.com" ],
-                       [ true, "127.0.0.1", "127.0.0.1" ],
-                       [ false, "127.0.0.1", "localhost" ],
-               ];
-       }
 
        /**
         * Test Http::isValidURI()
@@ -67,6 +25,8 @@ class HttpTest extends MediaWikiTestCase {
         * @covers Http::getProxy
         */
        public function testGetProxy() {
+               $this->hideDeprecated( 'Http::getProxy' );
+
                $this->setMwGlobals( 'wgHTTPProxy', false );
                $this->assertEquals(
                        '',
@@ -148,409 +108,4 @@ class HttpTest extends MediaWikiTestCase {
                ];
        }
 
-       public static function provideRelativeRedirects() {
-               return [
-                       [
-                               'location' => [ 'http://newsite/file.ext', '/newfile.ext' ],
-                               'final' => 'http://newsite/newfile.ext',
-                               'Relative file path Location: interpreted as full URL'
-                       ],
-                       [
-                               'location' => [ 'https://oldsite/file.ext' ],
-                               'final' => 'https://oldsite/file.ext',
-                               'Location to the HTTPS version of the site'
-                       ],
-                       [
-                               'location' => [
-                                       '/anotherfile.ext',
-                                       'http://anotherfile/hoster.ext',
-                                       'https://anotherfile/hoster.ext'
-                               ],
-                               'final' => 'https://anotherfile/hoster.ext',
-                               'Relative file path Location: should keep the latest host and scheme!'
-                       ],
-                       [
-                               'location' => [ '/anotherfile.ext' ],
-                               'final' => 'http://oldsite/anotherfile.ext',
-                               'Relative Location without domain '
-                       ],
-                       [
-                               'location' => null,
-                               'final' => 'http://oldsite/file.ext',
-                               'No Location (no redirect) '
-                       ],
-               ];
-       }
-
-       /**
-        * Warning:
-        *
-        * These tests are for code that makes use of an artifact of how CURL
-        * handles header reporting on redirect pages, and will need to be
-        * rewritten when T31232 is taken care of (high-level handling of HTTP redirects).
-        *
-        * @dataProvider provideRelativeRedirects
-        * @covers MWHttpRequest::getFinalUrl
-        */
-       public function testRelativeRedirections( $location, $final, $message = null ) {
-               $h = MWHttpRequestTester::factory( 'http://oldsite/file.ext', [], __METHOD__ );
-               // Forge a Location header
-               $h->setRespHeaders( 'location', $location );
-               // Verify it correctly fixes the Location
-               $this->assertEquals( $final, $h->getFinalUrl(), $message );
-       }
-
-       /**
-        * Constant values are from PHP 5.3.28 using cURL 7.24.0
-        * @see https://secure.php.net/manual/en/curl.constants.php
-        *
-        * All constant values are present so that developers don’t need to remember
-        * to add them if added at a later date. The commented out constants were
-        * not found anywhere in the MediaWiki core code.
-        *
-        * Commented out constants that were not available in:
-        * HipHop VM 3.3.0 (rel)
-        * Compiler: heads/master-0-g08810d920dfff59e0774cf2d651f92f13a637175
-        * Repo schema: 3214fc2c684a4520485f715ee45f33f2182324b1
-        * Extension API: 20140829
-        *
-        * Commented out constants that were removed in PHP 5.6.0
-        */
-       public function provideCurlConstants() {
-               return [
-                       [ 'CURLAUTH_ANY' ],
-                       [ 'CURLAUTH_ANYSAFE' ],
-                       [ 'CURLAUTH_BASIC' ],
-                       [ 'CURLAUTH_DIGEST' ],
-                       [ 'CURLAUTH_GSSNEGOTIATE' ],
-                       [ 'CURLAUTH_NTLM' ],
-                       // [ 'CURLCLOSEPOLICY_CALLBACK' ], // removed in PHP 5.6.0
-                       // [ 'CURLCLOSEPOLICY_LEAST_RECENTLY_USED' ], // removed in PHP 5.6.0
-                       // [ 'CURLCLOSEPOLICY_LEAST_TRAFFIC' ], // removed in PHP 5.6.0
-                       // [ 'CURLCLOSEPOLICY_OLDEST' ], // removed in PHP 5.6.0
-                       // [ 'CURLCLOSEPOLICY_SLOWEST' ], // removed in PHP 5.6.0
-                       [ 'CURLE_ABORTED_BY_CALLBACK' ],
-                       [ 'CURLE_BAD_CALLING_ORDER' ],
-                       [ 'CURLE_BAD_CONTENT_ENCODING' ],
-                       [ 'CURLE_BAD_FUNCTION_ARGUMENT' ],
-                       [ 'CURLE_BAD_PASSWORD_ENTERED' ],
-                       [ 'CURLE_COULDNT_CONNECT' ],
-                       [ 'CURLE_COULDNT_RESOLVE_HOST' ],
-                       [ 'CURLE_COULDNT_RESOLVE_PROXY' ],
-                       [ 'CURLE_FAILED_INIT' ],
-                       [ 'CURLE_FILESIZE_EXCEEDED' ],
-                       [ 'CURLE_FILE_COULDNT_READ_FILE' ],
-                       [ 'CURLE_FTP_ACCESS_DENIED' ],
-                       [ 'CURLE_FTP_BAD_DOWNLOAD_RESUME' ],
-                       [ 'CURLE_FTP_CANT_GET_HOST' ],
-                       [ 'CURLE_FTP_CANT_RECONNECT' ],
-                       [ 'CURLE_FTP_COULDNT_GET_SIZE' ],
-                       [ 'CURLE_FTP_COULDNT_RETR_FILE' ],
-                       [ 'CURLE_FTP_COULDNT_SET_ASCII' ],
-                       [ 'CURLE_FTP_COULDNT_SET_BINARY' ],
-                       [ 'CURLE_FTP_COULDNT_STOR_FILE' ],
-                       [ 'CURLE_FTP_COULDNT_USE_REST' ],
-                       [ 'CURLE_FTP_PORT_FAILED' ],
-                       [ 'CURLE_FTP_QUOTE_ERROR' ],
-                       [ 'CURLE_FTP_SSL_FAILED' ],
-                       [ 'CURLE_FTP_USER_PASSWORD_INCORRECT' ],
-                       [ 'CURLE_FTP_WEIRD_227_FORMAT' ],
-                       [ 'CURLE_FTP_WEIRD_PASS_REPLY' ],
-                       [ 'CURLE_FTP_WEIRD_PASV_REPLY' ],
-                       [ 'CURLE_FTP_WEIRD_SERVER_REPLY' ],
-                       [ 'CURLE_FTP_WEIRD_USER_REPLY' ],
-                       [ 'CURLE_FTP_WRITE_ERROR' ],
-                       [ 'CURLE_FUNCTION_NOT_FOUND' ],
-                       [ 'CURLE_GOT_NOTHING' ],
-                       [ 'CURLE_HTTP_NOT_FOUND' ],
-                       [ 'CURLE_HTTP_PORT_FAILED' ],
-                       [ 'CURLE_HTTP_POST_ERROR' ],
-                       [ 'CURLE_HTTP_RANGE_ERROR' ],
-                       [ 'CURLE_LDAP_CANNOT_BIND' ],
-                       [ 'CURLE_LDAP_INVALID_URL' ],
-                       [ 'CURLE_LDAP_SEARCH_FAILED' ],
-                       [ 'CURLE_LIBRARY_NOT_FOUND' ],
-                       [ 'CURLE_MALFORMAT_USER' ],
-                       [ 'CURLE_OBSOLETE' ],
-                       [ 'CURLE_OK' ],
-                       [ 'CURLE_OPERATION_TIMEOUTED' ],
-                       [ 'CURLE_OUT_OF_MEMORY' ],
-                       [ 'CURLE_PARTIAL_FILE' ],
-                       [ 'CURLE_READ_ERROR' ],
-                       [ 'CURLE_RECV_ERROR' ],
-                       [ 'CURLE_SEND_ERROR' ],
-                       [ 'CURLE_SHARE_IN_USE' ],
-                       // [ 'CURLE_SSH' ], // not present in HHVM 3.3.0-dev
-                       [ 'CURLE_SSL_CACERT' ],
-                       [ 'CURLE_SSL_CERTPROBLEM' ],
-                       [ 'CURLE_SSL_CIPHER' ],
-                       [ 'CURLE_SSL_CONNECT_ERROR' ],
-                       [ 'CURLE_SSL_ENGINE_NOTFOUND' ],
-                       [ 'CURLE_SSL_ENGINE_SETFAILED' ],
-                       [ 'CURLE_SSL_PEER_CERTIFICATE' ],
-                       [ 'CURLE_TELNET_OPTION_SYNTAX' ],
-                       [ 'CURLE_TOO_MANY_REDIRECTS' ],
-                       [ 'CURLE_UNKNOWN_TELNET_OPTION' ],
-                       [ 'CURLE_UNSUPPORTED_PROTOCOL' ],
-                       [ 'CURLE_URL_MALFORMAT' ],
-                       [ 'CURLE_URL_MALFORMAT_USER' ],
-                       [ 'CURLE_WRITE_ERROR' ],
-                       [ 'CURLFTPAUTH_DEFAULT' ],
-                       [ 'CURLFTPAUTH_SSL' ],
-                       [ 'CURLFTPAUTH_TLS' ],
-                       // [ 'CURLFTPMETHOD_MULTICWD' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLFTPMETHOD_NOCWD' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLFTPMETHOD_SINGLECWD' ], // not present in HHVM 3.3.0-dev
-                       [ 'CURLFTPSSL_ALL' ],
-                       [ 'CURLFTPSSL_CONTROL' ],
-                       [ 'CURLFTPSSL_NONE' ],
-                       [ 'CURLFTPSSL_TRY' ],
-                       // [ 'CURLINFO_CERTINFO' ], // not present in HHVM 3.3.0-dev
-                       [ 'CURLINFO_CONNECT_TIME' ],
-                       [ 'CURLINFO_CONTENT_LENGTH_DOWNLOAD' ],
-                       [ 'CURLINFO_CONTENT_LENGTH_UPLOAD' ],
-                       [ 'CURLINFO_CONTENT_TYPE' ],
-                       [ 'CURLINFO_EFFECTIVE_URL' ],
-                       [ 'CURLINFO_FILETIME' ],
-                       [ 'CURLINFO_HEADER_OUT' ],
-                       [ 'CURLINFO_HEADER_SIZE' ],
-                       [ 'CURLINFO_HTTP_CODE' ],
-                       [ 'CURLINFO_NAMELOOKUP_TIME' ],
-                       [ 'CURLINFO_PRETRANSFER_TIME' ],
-                       [ 'CURLINFO_PRIVATE' ],
-                       [ 'CURLINFO_REDIRECT_COUNT' ],
-                       [ 'CURLINFO_REDIRECT_TIME' ],
-                       // [ 'CURLINFO_REDIRECT_URL' ], // not present in HHVM 3.3.0-dev
-                       [ 'CURLINFO_REQUEST_SIZE' ],
-                       [ 'CURLINFO_SIZE_DOWNLOAD' ],
-                       [ 'CURLINFO_SIZE_UPLOAD' ],
-                       [ 'CURLINFO_SPEED_DOWNLOAD' ],
-                       [ 'CURLINFO_SPEED_UPLOAD' ],
-                       [ 'CURLINFO_SSL_VERIFYRESULT' ],
-                       [ 'CURLINFO_STARTTRANSFER_TIME' ],
-                       [ 'CURLINFO_TOTAL_TIME' ],
-                       [ 'CURLMSG_DONE' ],
-                       [ 'CURLM_BAD_EASY_HANDLE' ],
-                       [ 'CURLM_BAD_HANDLE' ],
-                       [ 'CURLM_CALL_MULTI_PERFORM' ],
-                       [ 'CURLM_INTERNAL_ERROR' ],
-                       [ 'CURLM_OK' ],
-                       [ 'CURLM_OUT_OF_MEMORY' ],
-                       [ 'CURLOPT_AUTOREFERER' ],
-                       [ 'CURLOPT_BINARYTRANSFER' ],
-                       [ 'CURLOPT_BUFFERSIZE' ],
-                       [ 'CURLOPT_CAINFO' ],
-                       [ 'CURLOPT_CAPATH' ],
-                       // [ 'CURLOPT_CERTINFO' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLOPT_CLOSEPOLICY' ], // removed in PHP 5.6.0
-                       [ 'CURLOPT_CONNECTTIMEOUT' ],
-                       [ 'CURLOPT_CONNECTTIMEOUT_MS' ],
-                       [ 'CURLOPT_COOKIE' ],
-                       [ 'CURLOPT_COOKIEFILE' ],
-                       [ 'CURLOPT_COOKIEJAR' ],
-                       [ 'CURLOPT_COOKIESESSION' ],
-                       [ 'CURLOPT_CRLF' ],
-                       [ 'CURLOPT_CUSTOMREQUEST' ],
-                       [ 'CURLOPT_DNS_CACHE_TIMEOUT' ],
-                       [ 'CURLOPT_DNS_USE_GLOBAL_CACHE' ],
-                       [ 'CURLOPT_EGDSOCKET' ],
-                       [ 'CURLOPT_ENCODING' ],
-                       [ 'CURLOPT_FAILONERROR' ],
-                       [ 'CURLOPT_FILE' ],
-                       [ 'CURLOPT_FILETIME' ],
-                       [ 'CURLOPT_FOLLOWLOCATION' ],
-                       [ 'CURLOPT_FORBID_REUSE' ],
-                       [ 'CURLOPT_FRESH_CONNECT' ],
-                       [ 'CURLOPT_FTPAPPEND' ],
-                       [ 'CURLOPT_FTPLISTONLY' ],
-                       [ 'CURLOPT_FTPPORT' ],
-                       [ 'CURLOPT_FTPSSLAUTH' ],
-                       [ 'CURLOPT_FTP_CREATE_MISSING_DIRS' ],
-                       // [ 'CURLOPT_FTP_FILEMETHOD' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLOPT_FTP_SKIP_PASV_IP' ], // not present in HHVM 3.3.0-dev
-                       [ 'CURLOPT_FTP_SSL' ],
-                       [ 'CURLOPT_FTP_USE_EPRT' ],
-                       [ 'CURLOPT_FTP_USE_EPSV' ],
-                       [ 'CURLOPT_HEADER' ],
-                       [ 'CURLOPT_HEADERFUNCTION' ],
-                       [ 'CURLOPT_HTTP200ALIASES' ],
-                       [ 'CURLOPT_HTTPAUTH' ],
-                       [ 'CURLOPT_HTTPGET' ],
-                       [ 'CURLOPT_HTTPHEADER' ],
-                       [ 'CURLOPT_HTTPPROXYTUNNEL' ],
-                       [ 'CURLOPT_HTTP_VERSION' ],
-                       [ 'CURLOPT_INFILE' ],
-                       [ 'CURLOPT_INFILESIZE' ],
-                       [ 'CURLOPT_INTERFACE' ],
-                       [ 'CURLOPT_IPRESOLVE' ],
-                       // [ 'CURLOPT_KEYPASSWD' ], // not present in HHVM 3.3.0-dev
-                       [ 'CURLOPT_KRB4LEVEL' ],
-                       [ 'CURLOPT_LOW_SPEED_LIMIT' ],
-                       [ 'CURLOPT_LOW_SPEED_TIME' ],
-                       [ 'CURLOPT_MAXCONNECTS' ],
-                       [ 'CURLOPT_MAXREDIRS' ],
-                       // [ 'CURLOPT_MAX_RECV_SPEED_LARGE' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLOPT_MAX_SEND_SPEED_LARGE' ], // not present in HHVM 3.3.0-dev
-                       [ 'CURLOPT_NETRC' ],
-                       [ 'CURLOPT_NOBODY' ],
-                       [ 'CURLOPT_NOPROGRESS' ],
-                       [ 'CURLOPT_NOSIGNAL' ],
-                       [ 'CURLOPT_PORT' ],
-                       [ 'CURLOPT_POST' ],
-                       [ 'CURLOPT_POSTFIELDS' ],
-                       [ 'CURLOPT_POSTQUOTE' ],
-                       [ 'CURLOPT_POSTREDIR' ],
-                       [ 'CURLOPT_PRIVATE' ],
-                       [ 'CURLOPT_PROGRESSFUNCTION' ],
-                       // [ 'CURLOPT_PROTOCOLS' ], // not present in HHVM 3.3.0-dev
-                       [ 'CURLOPT_PROXY' ],
-                       [ 'CURLOPT_PROXYAUTH' ],
-                       [ 'CURLOPT_PROXYPORT' ],
-                       [ 'CURLOPT_PROXYTYPE' ],
-                       [ 'CURLOPT_PROXYUSERPWD' ],
-                       [ 'CURLOPT_PUT' ],
-                       [ 'CURLOPT_QUOTE' ],
-                       [ 'CURLOPT_RANDOM_FILE' ],
-                       [ 'CURLOPT_RANGE' ],
-                       [ 'CURLOPT_READDATA' ],
-                       [ 'CURLOPT_READFUNCTION' ],
-                       // [ 'CURLOPT_REDIR_PROTOCOLS' ], // not present in HHVM 3.3.0-dev
-                       [ 'CURLOPT_REFERER' ],
-                       [ 'CURLOPT_RESUME_FROM' ],
-                       [ 'CURLOPT_RETURNTRANSFER' ],
-                       // [ 'CURLOPT_SSH_AUTH_TYPES' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLOPT_SSH_HOST_PUBLIC_KEY_MD5' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLOPT_SSH_PRIVATE_KEYFILE' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLOPT_SSH_PUBLIC_KEYFILE' ], // not present in HHVM 3.3.0-dev
-                       [ 'CURLOPT_SSLCERT' ],
-                       [ 'CURLOPT_SSLCERTPASSWD' ],
-                       [ 'CURLOPT_SSLCERTTYPE' ],
-                       [ 'CURLOPT_SSLENGINE' ],
-                       [ 'CURLOPT_SSLENGINE_DEFAULT' ],
-                       [ 'CURLOPT_SSLKEY' ],
-                       [ 'CURLOPT_SSLKEYPASSWD' ],
-                       [ 'CURLOPT_SSLKEYTYPE' ],
-                       [ 'CURLOPT_SSLVERSION' ],
-                       [ 'CURLOPT_SSL_CIPHER_LIST' ],
-                       [ 'CURLOPT_SSL_VERIFYHOST' ],
-                       [ 'CURLOPT_SSL_VERIFYPEER' ],
-                       [ 'CURLOPT_STDERR' ],
-                       [ 'CURLOPT_TCP_NODELAY' ],
-                       [ 'CURLOPT_TIMECONDITION' ],
-                       [ 'CURLOPT_TIMEOUT' ],
-                       [ 'CURLOPT_TIMEOUT_MS' ],
-                       [ 'CURLOPT_TIMEVALUE' ],
-                       [ 'CURLOPT_TRANSFERTEXT' ],
-                       [ 'CURLOPT_UNRESTRICTED_AUTH' ],
-                       [ 'CURLOPT_UPLOAD' ],
-                       [ 'CURLOPT_URL' ],
-                       [ 'CURLOPT_USERAGENT' ],
-                       [ 'CURLOPT_USERPWD' ],
-                       [ 'CURLOPT_VERBOSE' ],
-                       [ 'CURLOPT_WRITEFUNCTION' ],
-                       [ 'CURLOPT_WRITEHEADER' ],
-                       // [ 'CURLPROTO_ALL' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLPROTO_DICT' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLPROTO_FILE' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLPROTO_FTP' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLPROTO_FTPS' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLPROTO_HTTP' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLPROTO_HTTPS' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLPROTO_LDAP' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLPROTO_LDAPS' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLPROTO_SCP' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLPROTO_SFTP' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLPROTO_TELNET' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLPROTO_TFTP' ], // not present in HHVM 3.3.0-dev
-                       [ 'CURLPROXY_HTTP' ],
-                       // [ 'CURLPROXY_SOCKS4' ], // not present in HHVM 3.3.0-dev
-                       [ 'CURLPROXY_SOCKS5' ],
-                       // [ 'CURLSSH_AUTH_DEFAULT' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLSSH_AUTH_HOST' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLSSH_AUTH_KEYBOARD' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLSSH_AUTH_NONE' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLSSH_AUTH_PASSWORD' ], // not present in HHVM 3.3.0-dev
-                       // [ 'CURLSSH_AUTH_PUBLICKEY' ], // not present in HHVM 3.3.0-dev
-                       [ 'CURLVERSION_NOW' ],
-                       [ 'CURL_HTTP_VERSION_1_0' ],
-                       [ 'CURL_HTTP_VERSION_1_1' ],
-                       [ 'CURL_HTTP_VERSION_NONE' ],
-                       [ 'CURL_IPRESOLVE_V4' ],
-                       [ 'CURL_IPRESOLVE_V6' ],
-                       [ 'CURL_IPRESOLVE_WHATEVER' ],
-                       [ 'CURL_NETRC_IGNORED' ],
-                       [ 'CURL_NETRC_OPTIONAL' ],
-                       [ 'CURL_NETRC_REQUIRED' ],
-                       [ 'CURL_TIMECOND_IFMODSINCE' ],
-                       [ 'CURL_TIMECOND_IFUNMODSINCE' ],
-                       [ 'CURL_TIMECOND_LASTMOD' ],
-                       [ 'CURL_VERSION_IPV6' ],
-                       [ 'CURL_VERSION_KERBEROS4' ],
-                       [ 'CURL_VERSION_LIBZ' ],
-                       [ 'CURL_VERSION_SSL' ],
-               ];
-       }
-
-       /**
-        * Added this test based on an issue experienced with HHVM 3.3.0-dev
-        * where it did not define a cURL constant. T72570
-        *
-        * @dataProvider provideCurlConstants
-        * @coversNothing
-        */
-       public function testCurlConstants( $value ) {
-               $this->checkPHPExtension( 'curl' );
-
-               $this->assertTrue( defined( $value ), $value . ' not defined' );
-       }
-}
-
-/**
- * Class to let us overwrite MWHttpRequest respHeaders variable
- */
-class MWHttpRequestTester extends MWHttpRequest {
-       // function derived from the MWHttpRequest factory function but
-       // returns appropriate tester class here
-       public static function factory( $url, array $options = null, $caller = __METHOD__ ) {
-               if ( !Http::$httpEngine ) {
-                       Http::$httpEngine = 'guzzle';
-               } elseif ( Http::$httpEngine == 'curl' && !function_exists( 'curl_init' ) ) {
-                       throw new DomainException( __METHOD__ . ': curl (https://secure.php.net/curl) is not ' .
-                               'installed, but Http::$httpEngine is set to "curl"' );
-               }
-
-               switch ( Http::$httpEngine ) {
-                       case 'guzzle':
-                               return new GuzzleHttpRequestTester( $url, $options, $caller );
-                       case 'curl':
-                               return new CurlHttpRequestTester( $url, $options, $caller );
-                       case 'php':
-                               if ( !wfIniGetBool( 'allow_url_fopen' ) ) {
-                                       throw new DomainException( __METHOD__ .
-                                               ': allow_url_fopen needs to be enabled for pure PHP HTTP requests to work. '
-                                                       . 'If possible, curl should be used instead. See https://secure.php.net/curl.' );
-                               }
-
-                               return new PhpHttpRequestTester( $url, $options, $caller );
-                       default:
-               }
-       }
-}
-
-class GuzzleHttpRequestTester extends GuzzleHttpRequest {
-       function setRespHeaders( $name, $value ) {
-               $this->respHeaders[$name] = $value;
-       }
-}
-
-class CurlHttpRequestTester extends CurlHttpRequest {
-       function setRespHeaders( $name, $value ) {
-               $this->respHeaders[$name] = $value;
-       }
-}
-
-class PhpHttpRequestTester extends PhpHttpRequest {
-       function setRespHeaders( $name, $value ) {
-               $this->respHeaders[$name] = $value;
-       }
 }
index b2e7ea4..232b46a 100644 (file)
@@ -18,7 +18,7 @@ class JobQueueMemoryTest extends PHPUnit\Framework\TestCase {
        private function newJobQueue() {
                return JobQueue::factory( [
                        'class' => JobQueueMemory::class,
-                       'wiki' => wfWikiID(),
+                       'domain' => WikiMap::getCurrentWikiDbDomain()->getId(),
                        'type' => 'null',
                ] );
        }
index 0421fe7..ce07f78 100644 (file)
@@ -31,7 +31,9 @@ class JobQueueTest extends MediaWikiTestCase {
                        $baseConfig = [ 'class' => JobQueueDBSingle::class ];
                }
                $baseConfig['type'] = 'null';
-               $baseConfig['wiki'] = wfWikiID();
+               $baseConfig['domain'] = WikiMap::getCurrentWikiDbDomain()->getId();
+               $baseConfig['stash'] = new HashBagOStuff();
+               $baseConfig['wanCache'] = new WANObjectCache( [ 'cache' => new HashBagOStuff() ] );
                $variants = [
                        'queueRand' => [ 'order' => 'random', 'claimTTL' => 0 ],
                        'queueRandTTL' => [ 'order' => 'random', 'claimTTL' => 10 ],
@@ -75,7 +77,10 @@ class JobQueueTest extends MediaWikiTestCase {
                        $this->markTestSkipped( $desc );
                }
                $this->assertEquals( wfWikiID(), $queue->getWiki(), "Proper wiki ID ($desc)" );
-               $this->assertEquals( wfWikiID(), $queue->getDomain(), "Proper wiki ID ($desc)" );
+               $this->assertEquals(
+                       WikiMap::getCurrentWikiDbDomain()->getId(),
+                       $queue->getDomain(),
+                       "Proper wiki ID ($desc)" );
        }
 
        /**
@@ -254,8 +259,7 @@ class JobQueueTest extends MediaWikiTestCase {
                $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
                $this->assertEquals( 0, $queue->getAcquiredCount(), "Queue is empty ($desc)" );
 
-               $id = wfRandomString( 32 );
-               $root1 = Job::newRootJobParams( "nulljobspam:$id" ); // task ID/timestamp
+               $root1 = Job::newRootJobParams( "nulljobspam:testId" ); // task ID/timestamp
                for ( $i = 0; $i < 5; ++$i ) {
                        $this->assertNull( $queue->push( $this->newJob( 0, $root1 ) ), "Push worked ($desc)" );
                }
@@ -375,12 +379,12 @@ class JobQueueTest extends MediaWikiTestCase {
        }
 
        function newJob( $i = 0, $rootJob = [] ) {
-               return new NullJob( Title::newMainPage(),
+               return Job::factory( 'null', Title::newMainPage(),
                        [ 'lives' => 0, 'usleep' => 0, 'removeDuplicates' => 0, 'i' => $i ] + $rootJob );
        }
 
        function newDedupedJob( $i = 0, $rootJob = [] ) {
-               return new NullJob( Title::newMainPage(),
+               return Job::factory( 'null', Title::newMainPage(),
                        [ 'lives' => 0, 'usleep' => 0, 'removeDuplicates' => 1, 'i' => $i ] + $rootJob );
        }
 }
index 769b193..878b895 100644 (file)
@@ -27,33 +27,29 @@ class JobTest extends MediaWikiTestCase {
                $requestId = 'requestId=' . WebRequest::getRequestId();
 
                return [
-                       [
-                               $this->getMockJob( false ),
-                               'someCommand  ' . $requestId
-                       ],
                        [
                                $this->getMockJob( [ 'key' => 'val' ] ),
-                               'someCommand  key=val ' . $requestId
+                               'someCommand Special: key=val ' . $requestId
                        ],
                        [
                                $this->getMockJob( [ 'key' => [ 'inkey' => 'inval' ] ] ),
-                               'someCommand  key={"inkey":"inval"} ' . $requestId
+                               'someCommand Special: key={"inkey":"inval"} ' . $requestId
                        ],
                        [
                                $this->getMockJob( [ 'val1' ] ),
-                               'someCommand  0=val1 ' . $requestId
+                               'someCommand Special: 0=val1 ' . $requestId
                        ],
                        [
                                $this->getMockJob( [ 'val1', 'val2' ] ),
-                               'someCommand  0=val1 1=val2 ' . $requestId
+                               'someCommand Special: 0=val1 1=val2 ' . $requestId
                        ],
                        [
                                $this->getMockJob( [ new stdClass() ] ),
-                               'someCommand  0=object(stdClass) ' . $requestId
+                               'someCommand Special: 0=object(stdClass) ' . $requestId
                        ],
                        [
                                $this->getMockJob( [ $mockToStringObj ] ),
-                               'someCommand  0={STRING_OBJ_VAL} ' . $requestId
+                               'someCommand Special: 0={STRING_OBJ_VAL} ' . $requestId
                        ],
                        [
                                $this->getMockJob( [
@@ -72,7 +68,7 @@ class JobTest extends MediaWikiTestCase {
                                        ],
                                        "triggeredRecursive" => true
                                ] ),
-                               'someCommand  pages={"932737":[0,"Robert_James_Waller"]} ' .
+                               'someCommand Special: pages={"932737":[0,"Robert_James_Waller"]} ' .
                                'rootJobSignature=45868e99bba89064e4483743ebb9b682ef95c1a7 ' .
                                'rootJobTimestamp=20160309110158 masterPos=' .
                                '{"file":"db1023-bin.001288","pos":"308257743","asOfTime":' .
@@ -87,12 +83,22 @@ class JobTest extends MediaWikiTestCase {
        public function getMockJob( $params ) {
                $mock = $this->getMockForAbstractClass(
                        Job::class,
-                       [ 'someCommand', new Title(), $params ],
+                       [ 'someCommand', $params ],
                        'SomeJob'
                );
+
                return $mock;
        }
 
+       /**
+        * @covers Job::__construct()
+        */
+       public function testInvalidParamsArgument() {
+               $params = false;
+               $this->setExpectedException( InvalidArgumentException::class, '$params must be an array' );
+               $job = $this->getMockJob( $params );
+       }
+
        /**
         * @dataProvider provideTestJobFactory
         *
@@ -115,7 +121,7 @@ class JobTest extends MediaWikiTestCase {
                return [
                        'class name' => [ 'NullJob' ],
                        'closure' => [ function ( Title $title, array $params ) {
-                               return new NullJob( $title, $params );
+                               return Job::factory( 'null', $title, $params );
                        } ],
                        'function' => [ [ $this, 'newNullJob' ] ],
                        'static function' => [ self::class . '::staticNullJob' ]
@@ -123,11 +129,91 @@ class JobTest extends MediaWikiTestCase {
        }
 
        public function newNullJob( Title $title, array $params ) {
-               return new NullJob( $title, $params );
+               return Job::factory( 'null', $title, $params );
        }
 
        public static function staticNullJob( Title $title, array $params ) {
-               return new NullJob( $title, $params );
+               return Job::factory( 'null', $title, $params );
+       }
+
+       /**
+        * @covers Job::factory
+        * @covers Job::__construct()
+        */
+       public function testJobSignatureGeneric() {
+               $testPage = Title::makeTitle( NS_PROJECT, 'x' );
+               $blankTitle = Title::makeTitle( NS_SPECIAL, '' );
+               $params = [ 'z' => 1, 'lives' => 1, 'usleep' => 0 ];
+               $paramsWithTitle = $params + [ 'namespace' => NS_PROJECT, 'title' => 'x' ];
+
+               $job = new NullJob( [ 'namespace' => NS_PROJECT, 'title' => 'x' ] + $params );
+               $this->assertEquals( $testPage->getPrefixedText(), $job->getTitle()->getPrefixedText() );
+               $this->assertJobParamsMatch( $job, $paramsWithTitle );
+
+               $job = Job::factory( 'null', $testPage, $params );
+               $this->assertEquals( $blankTitle->getPrefixedText(), $job->getTitle()->getPrefixedText() );
+               $this->assertJobParamsMatch( $job, $params );
+
+               $job = Job::factory( 'null', $paramsWithTitle );
+               $this->assertEquals( $testPage->getPrefixedText(), $job->getTitle()->getPrefixedText() );
+               $this->assertJobParamsMatch( $job, $paramsWithTitle );
+
+               $job = Job::factory( 'null', $params );
+               $this->assertTrue( $blankTitle->equals( $job->getTitle() ) );
+               $this->assertJobParamsMatch( $job, $params );
+       }
+
+       /**
+        * @covers Job::factory
+        * @covers Job::__construct()
+        */
+       public function testJobSignatureTitleBased() {
+               $testPage = Title::makeTitle( NS_PROJECT, 'x' );
+               $blankPage = Title::makeTitle( NS_SPECIAL, 'Blankpage' );
+               $params = [ 'z' => 1, 'causeAction' => 'unknown', 'causeAgent' => 'unknown' ];
+               $paramsWithTitle = $params + [ 'namespace' => NS_PROJECT, 'title' => 'x' ];
+               $paramsWithBlankpage = $params + [ 'namespace' => NS_SPECIAL, 'title' => 'Blankpage' ];
+
+               $job = new RefreshLinksJob( $testPage, $params );
+               $this->assertEquals( $testPage->getPrefixedText(), $job->getTitle()->getPrefixedText() );
+               $this->assertTrue( $testPage->equals( $job->getTitle() ) );
+               $this->assertJobParamsMatch( $job, $paramsWithTitle );
+
+               $job = Job::factory( 'refreshLinks', $testPage, $params );
+               $this->assertEquals( $testPage->getPrefixedText(), $job->getTitle()->getPrefixedText() );
+               $this->assertJobParamsMatch( $job, $paramsWithTitle );
+
+               $job = Job::factory( 'refreshLinks', $paramsWithTitle );
+               $this->assertEquals( $testPage->getPrefixedText(), $job->getTitle()->getPrefixedText() );
+               $this->assertJobParamsMatch( $job, $paramsWithTitle );
+
+               $job = Job::factory( 'refreshLinks', $params );
+               $this->assertTrue( $blankPage->equals( $job->getTitle() ) );
+               $this->assertJobParamsMatch( $job, $paramsWithBlankpage );
        }
 
+       /**
+        * @covers Job::factory
+        * @covers Job::__construct()
+        */
+       public function testJobSignatureTitleBasedIncomplete() {
+               $testPage = Title::makeTitle( NS_PROJECT, 'x' );
+               $blankTitle = Title::makeTitle( NS_SPECIAL, '' );
+               $params = [ 'z' => 1, 'causeAction' => 'unknown', 'causeAgent' => 'unknown' ];
+
+               $job = new RefreshLinksJob( $testPage, $params + [ 'namespace' => 0 ] );
+               $this->assertEquals( $blankTitle->getPrefixedText(), $job->getTitle()->getPrefixedText() );
+               $this->assertJobParamsMatch( $job, $params + [ 'namespace' => 0 ] );
+
+               $job = new RefreshLinksJob( $testPage, $params + [ 'title' => 'x' ] );
+               $this->assertEquals( $blankTitle->getPrefixedText(), $job->getTitle()->getPrefixedText() );
+               $this->assertJobParamsMatch( $job, $params + [ 'title' => 'x' ] );
+       }
+
+       private function assertJobParamsMatch( IJobSpecification $job, array $params ) {
+               $actual = $job->getParams();
+               unset( $actual['requestId'] );
+
+               $this->assertEquals( $actual, $params );
+       }
 }
index 27cae8a..1a2941d 100644 (file)
@@ -51,13 +51,9 @@ class ClearUserWatchlistJobTest extends MediaWikiTestCase {
                $this->setMwGlobals( 'wgUpdateRowsPerQuery', 2 );
 
                JobQueueGroup::singleton()->push(
-                       new ClearUserWatchlistJob(
-                               null,
-                               [
-                                       'userId' => $user->getId(),
-                                       'maxWatchlistId' => $maxId,
-                               ]
-                       )
+                       new ClearUserWatchlistJob( [
+                               'userId' => $user->getId(), 'maxWatchlistId' => $maxId,
+                       ] )
                );
 
                $this->assertEquals( 1, JobQueueGroup::singleton()->getQueueSizes()['clearUserWatchlist'] );
index d5ac77b..12b6320 100644 (file)
@@ -133,9 +133,7 @@ class ArrayUtilsTest extends PHPUnit\Framework\TestCase {
         * @covers ArrayUtils::arrayDiffAssocRecursive
         * @dataProvider provideArrayDiffAssocRecursive
         */
-       function testArrayDiffAssocRecursive( $expected ) {
-               $args = func_get_args();
-               array_shift( $args );
+       function testArrayDiffAssocRecursive( $expected, ...$args ) {
                $this->assertEquals( call_user_func_array(
                        'ArrayUtils::arrayDiffAssocRecursive', $args
                ), $expected );
index ef333f9..4c93789 100644 (file)
@@ -85,9 +85,9 @@ class CSSMinTest extends MediaWikiTestCase {
         * @covers CSSMin::getMimeType
         */
        public function testGetMimeType( $fileContents, $fileExtension, $expected ) {
-               $fileName = wfTempDir() . DIRECTORY_SEPARATOR . uniqid( 'MW_PHPUnit_CSSMinTest_' ) . '.'
-                       . $fileExtension;
-               $this->addTmpFiles( $fileName );
+               // Automatically removed when it falls out of scope (including if the test fails)
+               $file = TempFSFile::factory( 'PHPUnit_CSSMinTest_', $fileExtension, wfTempDir() );
+               $fileName = $file->getPath();
                file_put_contents( $fileName, $fileContents );
                $this->assertSame( $expected, CSSMin::getMimeType( $fileName ) );
        }
diff --git a/tests/phpunit/includes/libs/CookieTest.php b/tests/phpunit/includes/libs/CookieTest.php
new file mode 100644 (file)
index 0000000..e383be9
--- /dev/null
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * @covers Cookie
+ */
+class CookieTest extends \PHPUnit\Framework\TestCase {
+
+       /**
+        * @dataProvider cookieDomains
+        * @covers Cookie::validateCookieDomain
+        */
+       public function testValidateCookieDomain( $expected, $domain, $origin = null ) {
+               if ( $origin ) {
+                       $ok = Cookie::validateCookieDomain( $domain, $origin );
+                       $msg = "$domain against origin $origin";
+               } else {
+                       $ok = Cookie::validateCookieDomain( $domain );
+                       $msg = "$domain";
+               }
+               $this->assertEquals( $expected, $ok, $msg );
+       }
+
+       public static function cookieDomains() {
+               return [
+                       [ false, "org" ],
+                       [ false, ".org" ],
+                       [ true, "wikipedia.org" ],
+                       [ true, ".wikipedia.org" ],
+                       [ false, "co.uk" ],
+                       [ false, ".co.uk" ],
+                       [ false, "gov.uk" ],
+                       [ false, ".gov.uk" ],
+                       [ true, "supermarket.uk" ],
+                       [ false, "uk" ],
+                       [ false, ".uk" ],
+                       [ false, "127.0.0." ],
+                       [ false, "127." ],
+                       [ false, "127.0.0.1." ],
+                       [ true, "127.0.0.1" ],
+                       [ false, "333.0.0.1" ],
+                       [ true, "example.com" ],
+                       [ false, "example.com." ],
+                       [ true, ".example.com" ],
+
+                       [ true, ".example.com", "www.example.com" ],
+                       [ false, "example.com", "www.example.com" ],
+                       [ true, "127.0.0.1", "127.0.0.1" ],
+                       [ false, "127.0.0.1", "localhost" ],
+               ];
+       }
+
+}
index 695a734..e9bffe1 100644 (file)
@@ -3,9 +3,7 @@
  * PHP Unit tests for MWMessagePack
  * @covers MWMessagePack
  */
-class MWMessagePackTest extends PHPUnit\Framework\TestCase {
-
-       use MediaWikiCoversValidator;
+class MWMessagePackTest extends MediaWikiTestCase {
 
        /**
         * Provides test cases for MWMessagePackTest::testMessagePack
@@ -71,6 +69,7 @@ class MWMessagePackTest extends PHPUnit\Framework\TestCase {
         * @dataProvider providePacks
         */
        public function testPack( $type, $value, $expected ) {
+               $this->hideDeprecated( MWMessagePack::class . '::pack' );
                $actual = bin2hex( MWMessagePack::pack( $value ) );
                $this->assertEquals( $expected, $actual, $type );
        }
index b68ffaf..4a09a2e 100644 (file)
@@ -16,7 +16,7 @@ class BagOStuffTest extends MediaWikiTestCase {
                parent::setUp();
 
                // type defined through parameter
-               if ( $this->getCliArg( 'use-bagostuff' ) ) {
+               if ( $this->getCliArg( 'use-bagostuff' ) !== null ) {
                        $name = $this->getCliArg( 'use-bagostuff' );
 
                        $this->cache = ObjectCache::newFromId( $name );
@@ -65,20 +65,10 @@ class BagOStuffTest extends MediaWikiTestCase {
 
        /**
         * @covers BagOStuff::merge
-        * @covers BagOStuff::mergeViaLock
         * @covers BagOStuff::mergeViaCas
         */
        public function testMerge() {
                $key = $this->cache->makeKey( self::TEST_KEY );
-               $locks = false;
-               $checkLockingCallback = function ( BagOStuff $cache, $key, $oldVal ) use ( &$locks ) {
-                       $locks = $cache->get( "$key:lock" );
-
-                       return false;
-               };
-
-               $this->cache->merge( $key, $checkLockingCallback, 5 );
-               $this->assertFalse( $this->cache->get( $key ) );
 
                $calls = 0;
                $casRace = false; // emulate a race
@@ -103,105 +93,18 @@ class BagOStuffTest extends MediaWikiTestCase {
                $this->assertEquals( 'mergedmerged', $this->cache->get( $key ) );
 
                $calls = 0;
-               if ( $locks ) {
-                       // merge were something else already was merging (e.g. had the lock)
-                       $this->cache->lock( $key );
-                       $this->assertFalse(
-                               $this->cache->merge( $key, $callback, 5, 1 ),
-                               'Non-blocking merge (locking)'
-                       );
-                       $this->cache->unlock( $key );
-                       $this->assertEquals( 0, $calls );
-               } else {
-                       $casRace = true;
-                       $this->assertFalse(
-                               $this->cache->merge( $key, $callback, 5, 1 ),
-                               'Non-blocking merge (CAS)'
-                       );
-                       $this->assertEquals( 1, $calls );
-               }
-       }
-
-       /**
-        * @covers BagOStuff::merge
-        * @covers BagOStuff::mergeViaLock
-        * @dataProvider provideTestMerge_fork
-        */
-       public function testMerge_fork( $exists, $winsLocking, $resLocking, $resCAS ) {
-               $key = $this->cache->makeKey( self::TEST_KEY );
-               $pCallback = function ( BagOStuff $cache, $key, $oldVal ) {
-                       return ( $oldVal === false ) ? 'init-parent' : $oldVal . '-merged-parent';
-               };
-               $cCallback = function ( BagOStuff $cache, $key, $oldVal ) {
-                       return ( $oldVal === false ) ? 'init-child' : $oldVal . '-merged-child';
-               };
-
-               if ( $exists ) {
-                       $this->cache->set( $key, 'x', 5 );
-               }
-
-               /*
-                * Test concurrent merges by forking this process, if:
-                * - not manually called with --use-bagostuff
-                * - pcntl_fork is supported by the system
-                * - cache type will correctly support calls over forks
-                */
-               $fork = (bool)$this->getCliArg( 'use-bagostuff' );
-               $fork &= function_exists( 'pcntl_fork' );
-               $fork &= !$this->cache instanceof HashBagOStuff;
-               $fork &= !$this->cache instanceof EmptyBagOStuff;
-               $fork &= !$this->cache instanceof MultiWriteBagOStuff;
-               if ( $fork ) {
-                       $pid = null;
-                       $locked = false;
-                       // Function to start merge(), run another merge() midway through, then finish
-                       $func = function ( BagOStuff $cache, $key, $cur )
-                               use ( $pCallback, $cCallback, &$pid, &$locked )
-                       {
-                               $pid = pcntl_fork();
-                               if ( $pid == -1 ) {
-                                       return false;
-                               } elseif ( $pid ) {
-                                       $locked = $cache->get( "$key:lock" ); // parent has lock?
-                                       pcntl_wait( $status );
-
-                                       return $pCallback( $cache, $key, $cur );
-                               } else {
-                                       $this->cache->merge( $key, $cCallback, 0, 1 );
-                                       // Bail out of the outer merge() in the child process since it does not
-                                       // need to attempt to write anything. Success is checked by the parent.
-                                       parent::tearDown(); // avoid phpunit notices
-                                       exit;
-                               }
-                       };
-
-                       // attempt a merge - this should fail
-                       $merged = $this->cache->merge( $key, $func, 0, 1 );
-
-                       if ( $pid == -1 ) {
-                               return; // can't fork, ignore this test...
-                       }
-
-                       if ( $locked ) {
-                               // merge succeed since child was locked out
-                               $this->assertEquals( $winsLocking, $merged );
-                               $this->assertEquals( $this->cache->get( $key ), $resLocking );
-                       } else {
-                               // merge has failed because child process was merging (and we only attempted once)
-                               $this->assertEquals( !$winsLocking, $merged );
-                               $this->assertEquals( $this->cache->get( $key ), $resCAS );
-                       }
+               $casRace = true;
+               $this->assertFalse(
+                       $this->cache->merge( $key, $callback, 5, 1 ),
+                       'Non-blocking merge (CAS)'
+               );
+               if ( $this->cache instanceof MultiWriteBagOStuff ) {
+                       $wrapper = \Wikimedia\TestingAccessWrapper::newFromObject( $this->cache );
+                       $n = count( $wrapper->caches );
                } else {
-                       $this->markTestSkipped( 'No pcntl methods available' );
+                       $n = 1;
                }
-       }
-
-       function provideTestMerge_fork() {
-               return [
-                       // (already exists, parent wins if locking, result if locking, result if CAS)
-                       [ false, true, 'init-parent', 'init-child' ],
-                       [ true, true, 'x-merged-parent', 'x-merged-child' ]
-               ];
+               $this->assertEquals( $n, $calls );
        }
 
        /**
index d0360a9..f953319 100644 (file)
@@ -11,7 +11,7 @@ class CachedBagOStuffTest extends PHPUnit\Framework\TestCase {
 
        /**
         * @covers CachedBagOStuff::__construct
-        * @covers CachedBagOStuff::doGet
+        * @covers CachedBagOStuff::get
         */
        public function testGetFromBackend() {
                $backend = new HashBagOStuff;
@@ -36,6 +36,7 @@ class CachedBagOStuffTest extends PHPUnit\Framework\TestCase {
                        $cache->set( "key$i", 1 );
                        $this->assertEquals( 1, $cache->get( "key$i" ) );
                        $this->assertEquals( 1, $backend->get( "key$i" ) );
+
                        $cache->delete( "key$i" );
                        $this->assertEquals( false, $cache->get( "key$i" ) );
                        $this->assertEquals( false, $backend->get( "key$i" ) );
@@ -67,7 +68,7 @@ class CachedBagOStuffTest extends PHPUnit\Framework\TestCase {
        }
 
        /**
-        * @covers CachedBagOStuff::doGet
+        * @covers CachedBagOStuff::get
         */
        public function testCacheBackendMisses() {
                $backend = new HashBagOStuff;
index 0376803..9f88474 100644 (file)
@@ -28,8 +28,8 @@ class MultiWriteBagOStuffTest extends MediaWikiTestCase {
         * @covers MultiWriteBagOStuff::doWrite
         */
        public function testSetImmediate() {
-               $key = wfRandomString();
-               $value = wfRandomString();
+               $key = 'key';
+               $value = 'value';
                $this->cache->set( $key, $value );
 
                // Set in tier 1
@@ -42,8 +42,8 @@ class MultiWriteBagOStuffTest extends MediaWikiTestCase {
         * @covers MultiWriteBagOStuff
         */
        public function testSyncMerge() {
-               $key = wfRandomString();
-               $value = wfRandomString();
+               $key = 'keyA';
+               $value = 'value';
                $func = function () use ( $value ) {
                        return $value;
                };
@@ -56,14 +56,14 @@ class MultiWriteBagOStuffTest extends MediaWikiTestCase {
                // Set in tier 1
                $this->assertEquals( $value, $this->cache1->get( $key ), 'Written to tier 1' );
                // Not yet set in tier 2
-               $this->assertEquals( false, $this->cache2->get( $key ), 'Not written to tier 2' );
+               $this->assertFalse( $this->cache2->get( $key ), 'Not written to tier 2' );
 
                $dbw->commit();
 
                // Set in tier 2
                $this->assertEquals( $value, $this->cache2->get( $key ), 'Written to tier 2' );
 
-               $key = wfRandomString();
+               $key = 'keyB';
 
                $dbw->begin();
                $this->cache->merge( $key, $func, 0, 1, BagOStuff::WRITE_SYNC );
@@ -80,8 +80,8 @@ class MultiWriteBagOStuffTest extends MediaWikiTestCase {
         * @covers MultiWriteBagOStuff::set
         */
        public function testSetDelayed() {
-               $key = wfRandomString();
-               $value = (object)[ 'v' => wfRandomString() ];
+               $key = 'key';
+               $value = (object)[ 'v' => 'saved value' ];
                $expectValue = clone $value;
 
                // XXX: DeferredUpdates bound to transactions in CLI mode
@@ -90,12 +90,12 @@ class MultiWriteBagOStuffTest extends MediaWikiTestCase {
                $this->cache->set( $key, $value );
 
                // Test that later changes to $value don't affect the saved value (e.g. T168040)
-               $value->v = 'bogus';
+               $value->v = 'other value';
 
                // Set in tier 1
                $this->assertEquals( $expectValue, $this->cache1->get( $key ), 'Written to tier 1' );
                // Not yet set in tier 2
-               $this->assertEquals( false, $this->cache2->get( $key ), 'Not written to tier 2' );
+               $this->assertFalse( $this->cache2->get( $key ), 'Not written to tier 2' );
 
                $dbw->commit();
 
index b7f22ec..550ec0b 100644 (file)
@@ -23,40 +23,40 @@ class ReplicatedBagOStuffTest extends MediaWikiTestCase {
         * @covers ReplicatedBagOStuff::set
         */
        public function testSet() {
-               $key = wfRandomString();
-               $value = wfRandomString();
+               $key = 'a key';
+               $value = 'a value';
                $this->cache->set( $key, $value );
 
                // Write to master.
-               $this->assertEquals( $this->writeCache->get( $key ), $value );
+               $this->assertEquals( $value, $this->writeCache->get( $key ) );
                // Don't write to replica. Replication is deferred to backend.
-               $this->assertEquals( $this->readCache->get( $key ), false );
+               $this->assertFalse( $this->readCache->get( $key ) );
        }
 
        /**
         * @covers ReplicatedBagOStuff::get
         */
        public function testGet() {
-               $key = wfRandomString();
+               $key = 'a key';
 
-               $write = wfRandomString();
+               $write = 'one value';
                $this->writeCache->set( $key, $write );
-               $read = wfRandomString();
+               $read = 'another value';
                $this->readCache->set( $key, $read );
 
                // Read from replica.
-               $this->assertEquals( $this->cache->get( $key ), $read );
+               $this->assertEquals( $read, $this->cache->get( $key ) );
        }
 
        /**
         * @covers ReplicatedBagOStuff::get
         */
        public function testGetAbsent() {
-               $key = wfRandomString();
-               $value = wfRandomString();
+               $key = 'a key';
+               $value = 'a value';
                $this->writeCache->set( $key, $value );
 
                // Don't read from master. No failover if value is absent.
-               $this->assertEquals( $this->cache->get( $key ), false );
+               $this->assertFalse( $this->cache->get( $key ) );
        }
 }
index e130b23..33e5c3b 100644 (file)
@@ -44,7 +44,27 @@ class DBConnRefTest extends PHPUnit\Framework\TestCase {
                        ->disableOriginalConstructor()
                        ->getMock();
 
-               $db->method( 'select' )->willReturn( new FakeResultWrapper( [] ) );
+               $open = true;
+               $db->method( 'select' )->willReturnCallback( function () use ( &$open ) {
+                       if ( !$open ) {
+                               throw new LogicException( "Not open" );
+                       }
+
+                       return new FakeResultWrapper( [] );
+               } );
+               $db->method( 'close' )->willReturnCallback( function () use ( &$open ) {
+                       $open = false;
+
+                       return true;
+               } );
+               $db->method( 'isOpen' )->willReturnCallback( function () use ( &$open ) {
+                       return $open;
+               } );
+               $db->method( 'open' )->willReturnCallback( function () use ( &$open ) {
+                       $open = true;
+
+                       return $open;
+               } );
                $db->method( '__toString' )->willReturn( 'MOCK_DB' );
 
                return $db;
@@ -55,12 +75,12 @@ class DBConnRefTest extends PHPUnit\Framework\TestCase {
         */
        private function getDBConnRef( ILoadBalancer $lb = null ) {
                $lb = $lb ?: $this->getLoadBalancerMock();
-               return new DBConnRef( $lb, $this->getDatabaseMock() );
+               return new DBConnRef( $lb, $this->getDatabaseMock(), DB_MASTER );
        }
 
        public function testConstruct() {
                $lb = $this->getLoadBalancerMock();
-               $ref = new DBConnRef( $lb, $this->getDatabaseMock() );
+               $ref = new DBConnRef( $lb, $this->getDatabaseMock(), DB_MASTER );
 
                $this->assertInstanceOf( ResultWrapper::class, $ref->select( 'whatever', '*' ) );
        }
@@ -79,10 +99,19 @@ class DBConnRefTest extends PHPUnit\Framework\TestCase {
 
                $ref = new DBConnRef(
                        $lb,
-                       [ DB_MASTER, [ 'test' ], 'dummy', ILoadBalancer::CONN_TRX_AUTOCOMMIT ]
+                       [ DB_MASTER, [ 'test' ], 'dummy', ILoadBalancer::CONN_TRX_AUTOCOMMIT ],
+                       DB_MASTER
                );
 
                $this->assertInstanceOf( ResultWrapper::class, $ref->select( 'whatever', '*' ) );
+               $this->assertEquals( DB_MASTER, $ref->getReferenceRole() );
+
+               $ref2 = new DBConnRef(
+                       $lb,
+                       [ DB_MASTER, [ 'test' ], 'dummy', ILoadBalancer::CONN_TRX_AUTOCOMMIT ],
+                       DB_REPLICA
+               );
+               $this->assertEquals( DB_REPLICA, $ref2->getReferenceRole() );
        }
 
        public function testDestruct() {
@@ -104,7 +133,7 @@ class DBConnRefTest extends PHPUnit\Framework\TestCase {
                $this->setExpectedException( InvalidArgumentException::class, '' );
 
                $lb = $this->getLoadBalancerMock();
-               new DBConnRef( $lb, 17 ); // bad constructor argument
+               new DBConnRef( $lb, 17, DB_REPLICA ); // bad constructor argument
        }
 
        /**
@@ -117,11 +146,14 @@ class DBConnRefTest extends PHPUnit\Framework\TestCase {
                $lb->expects( $this->never() )
                        ->method( 'getConnection' );
 
-               $ref = new DBConnRef( $lb, [ DB_REPLICA, [], 'dummy', 0 ] );
+               $ref = new DBConnRef( $lb, [ DB_REPLICA, [], 'dummy', 0 ], DB_REPLICA );
 
                $this->assertSame( 'dummy', $ref->getDomainID() );
        }
 
+       /**
+        * @covers Wikimedia\Rdbms\DBConnRef::select
+        */
        public function testSelect() {
                // select should get passed through normally
                $ref = $this->getDBConnRef();
@@ -133,8 +165,59 @@ class DBConnRefTest extends PHPUnit\Framework\TestCase {
                $this->assertInternalType( 'string', $ref->__toString() );
 
                $lb = $this->getLoadBalancerMock();
-               $ref = new DBConnRef( $lb, [ DB_MASTER, [], 'test', 0 ] );
+               $ref = new DBConnRef( $lb, [ DB_MASTER, [], 'test', 0 ], DB_MASTER );
                $this->assertInternalType( 'string', $ref->__toString() );
        }
 
+       /**
+        * @covers Wikimedia\Rdbms\DBConnRef::close
+        * @expectedException \Wikimedia\Rdbms\DBUnexpectedError
+        */
+       public function testClose() {
+               $lb = $this->getLoadBalancerMock();
+               $ref = new DBConnRef( $lb, [ DB_REPLICA, [], 'dummy', 0 ], DB_MASTER );
+               $ref->close();
+       }
+
+       /**
+        * @covers Wikimedia\Rdbms\DBConnRef::getReferenceRole
+        */
+       public function testGetReferenceRole() {
+               $lb = $this->getLoadBalancerMock();
+               $ref = new DBConnRef( $lb, [ DB_REPLICA, [], 'dummy', 0 ], DB_REPLICA );
+               $this->assertSame( DB_REPLICA, $ref->getReferenceRole() );
+
+               $ref = new DBConnRef( $lb, [ DB_MASTER, [], 'dummy', 0 ], DB_MASTER );
+               $this->assertSame( DB_MASTER, $ref->getReferenceRole() );
+
+               $ref = new DBConnRef( $lb, [ 1, [], 'dummy', 0 ], DB_REPLICA );
+               $this->assertSame( DB_REPLICA, $ref->getReferenceRole() );
+
+               $ref = new DBConnRef( $lb, [ 0, [], 'dummy', 0 ], DB_MASTER );
+               $this->assertSame( DB_MASTER, $ref->getReferenceRole() );
+       }
+
+       /**
+        * @covers Wikimedia\Rdbms\DBConnRef::getReferenceRole
+        * @expectedException Wikimedia\Rdbms\DBReadOnlyRoleError
+        * @dataProvider provideRoleExceptions
+        */
+       public function testRoleExceptions( $method, $args ) {
+               $lb = $this->getLoadBalancerMock();
+               $ref = new DBConnRef( $lb, [ DB_REPLICA, [], 'dummy', 0 ], DB_REPLICA );
+               $ref->$method( ...$args );
+       }
+
+       function provideRoleExceptions() {
+               return [
+                       [ 'insert', [ 'table', [ 'a' => 1 ] ] ],
+                       [ 'update', [ 'table', [ 'a' => 1 ], [ 'a' => 2 ] ] ],
+                       [ 'delete', [ 'table', [ 'a' => 1 ] ] ],
+                       [ 'replace', [ 'table', [ 'a' ], [ 'a' => 1 ] ] ],
+                       [ 'upsert', [ 'table', [ 'a' => 1 ], [ 'a' ], [ 'a = a + 1' ] ] ],
+                       [ 'lock', [ 'k', 'method' ] ],
+                       [ 'unlock', [ 'k', 'method' ] ],
+                       [ 'getScopedLockAndFlush', [ 'k', 'method', 1 ] ]
+               ];
+       }
 }
index b36fe11..b1d4fad 100644 (file)
@@ -13,7 +13,7 @@ class DatabaseDomainTest extends PHPUnit\Framework\TestCase {
        public static function provideConstruct() {
                return [
                        'All strings' =>
-                               [ 'foo', 'bar', 'baz', 'foo-bar-baz' ],
+                               [ 'foo', 'bar', 'baz_', 'foo-bar-baz_' ],
                        'Nothing' =>
                                [ null, null, '', '' ],
                        'Invalid $database' =>
@@ -23,9 +23,9 @@ class DatabaseDomainTest extends PHPUnit\Framework\TestCase {
                        'Invalid $prefix' =>
                                [ 'foo', 'bar', 0, '', true ],
                        'Dash' =>
-                               [ 'foo-bar', 'baz', 'baa', 'foo?hbar-baz-baa' ],
+                               [ 'foo-bar', 'baz', 'baa_', 'foo?hbar-baz-baa_' ],
                        'Question mark' =>
-                               [ 'foo?bar', 'baz', 'baa', 'foo??bar-baz-baa' ],
+                               [ 'foo?bar', 'baz', 'baa_', 'foo??bar-baz-baa_' ],
                ];
        }
 
@@ -53,17 +53,17 @@ class DatabaseDomainTest extends PHPUnit\Framework\TestCase {
                        'Basic' =>
                                [ 'foo', 'foo', null, '' ],
                        'db+prefix' =>
-                               [ 'foo-bar', 'foo', null, 'bar' ],
+                               [ 'foo-bar_', 'foo', null, 'bar_' ],
                        'db+schema+prefix' =>
-                               [ 'foo-bar-baz', 'foo', 'bar', 'baz' ],
+                               [ 'foo-bar-baz_', 'foo', 'bar', 'baz_' ],
                        '?h -> -' =>
-                               [ 'foo?hbar-baz-baa', 'foo-bar', 'baz', 'baa' ],
+                               [ 'foo?hbar-baz-baa_', 'foo-bar', 'baz', 'baa_' ],
                        '?? -> ?' =>
-                               [ 'foo??bar-baz-baa', 'foo?bar', 'baz', 'baa' ],
+                               [ 'foo??bar-baz-baa_', 'foo?bar', 'baz', 'baa_' ],
                        '? is left alone' =>
-                               [ 'foo?bar-baz-baa', 'foo?bar', 'baz', 'baa' ],
+                               [ 'foo?bar-baz-baa_', 'foo?bar', 'baz', 'baa_' ],
                        'too many parts' =>
-                               [ 'foo-bar-baz-baa', '', '', '', true ],
+                               [ 'foo-bar-baz-baa_', '', '', '', true ],
                        'from instance' =>
                                [ DatabaseDomain::newUnspecified(), null, null, '' ],
                ];
@@ -90,13 +90,13 @@ class DatabaseDomainTest extends PHPUnit\Framework\TestCase {
                        'Basic' =>
                                [ 'foo', 'foo', null, '' ],
                        'db+prefix' =>
-                               [ 'foo-bar', 'foo', null, 'bar' ],
+                               [ 'foo-bar_', 'foo', null, 'bar_' ],
                        'db+schema+prefix' =>
-                               [ 'foo-bar-baz', 'foo', 'bar', 'baz' ],
+                               [ 'foo-bar-baz_', 'foo', 'bar', 'baz_' ],
                        '?h -> -' =>
-                               [ 'foo?hbar-baz-baa', 'foo-bar', 'baz', 'baa' ],
+                               [ 'foo?hbar-baz-baa_', 'foo-bar', 'baz', 'baa_' ],
                        '?? -> ?' =>
-                               [ 'foo??bar-baz-baa', 'foo?bar', 'baz', 'baa' ],
+                               [ 'foo??bar-baz-baa_', 'foo?bar', 'baz', 'baa_' ],
                        'Nothing' =>
                                [ '', null, null, '' ],
                ];
@@ -136,23 +136,21 @@ class DatabaseDomainTest extends PHPUnit\Framework\TestCase {
                        'Basic' =>
                                [ 'foo', 'foo', null, '', true ],
                        'db+prefix' =>
-                               [ 'foo-bar', 'foo', null, 'bar', true ],
+                               [ 'foo-bar_', 'foo', null, 'bar_', true ],
                        'db+schema+prefix' =>
-                               [ 'foo-bar-baz', 'foo', 'bar', 'baz', true ],
+                               [ 'foo-bar-baz_', 'foo', 'bar', 'baz_', true ],
                        'db+dontcare_schema+prefix' =>
-                               [ 'foo-bar-baz', 'foo', null, 'baz', false ],
+                               [ 'foo-bar-baz_', 'foo', null, 'baz_', false ],
                        '?h -> -' =>
-                               [ 'foo?hbar-baz-baa', 'foo-bar', 'baz', 'baa', true ],
+                               [ 'foo?hbar-baz-baa_', 'foo-bar', 'baz', 'baa_', true ],
                        '?? -> ?' =>
-                               [ 'foo??bar-baz-baa', 'foo?bar', 'baz', 'baa', true ],
+                               [ 'foo??bar-baz-baa_', 'foo?bar', 'baz', 'baa_', true ],
                        'Nothing' =>
                                [ '', null, null, '', true ],
                        'dontcaredb+dontcaredbschema+prefix' =>
-                               [ 'mywiki-mediawiki-prefix', null, null, 'prefix', false ],
-                       'dontcaredb+schema+prefix' =>
-                               [ 'mywiki-schema-prefix', null, 'schema', 'prefix', false ],
+                               [ 'mywiki-mediawiki-prefix_', null, null, 'prefix_', false ],
                        'db+dontcareschema+prefix' =>
-                               [ 'mywiki-schema-prefix', 'mywiki', null, 'prefix', false ],
+                               [ 'mywiki-schema-prefix_', 'mywiki', null, 'prefix_', false ],
                        'postgres-db-jobqueue' =>
                                [ 'postgres-mediawiki-', 'postgres', null, '', false ]
                ];
@@ -178,13 +176,11 @@ class DatabaseDomainTest extends PHPUnit\Framework\TestCase {
        public static function provideIsCompatible2() {
                return [
                        'db+schema+prefix' =>
-                               [ 'mywiki-schema-prefix', 'thatwiki', 'schema', 'prefix' ],
+                               [ 'mywiki-schema-prefix_', 'thatwiki', 'schema', 'prefix_' ],
                        'dontcaredb+dontcaredbschema+prefix' =>
-                               [ 'thatwiki-mediawiki-otherprefix', null, null, 'prefix' ],
-                       'dontcaredb+schema+prefix' =>
-                               [ 'mywiki-otherschema-prefix', null, 'schema', 'prefix' ],
+                               [ 'thatwiki-mediawiki-otherprefix_', null, null, 'prefix_' ],
                        'db+dontcareschema+prefix' =>
-                               [ 'notmywiki-schema-prefix', 'mywiki', null, 'prefix' ],
+                               [ 'notmywiki-schema-prefix_', 'mywiki', null, 'prefix_' ],
                ];
        }
 
@@ -202,6 +198,20 @@ class DatabaseDomainTest extends PHPUnit\Framework\TestCase {
                $this->assertFalse( $fromId->isCompatible( $compareIdObj ), 'fromId equals string' );
        }
 
+       /**
+        * @expectedException InvalidArgumentException
+        */
+       public function testSchemaWithNoDB1() {
+               new DatabaseDomain( null, 'schema', '' );
+       }
+
+       /**
+        * @expectedException InvalidArgumentException
+        */
+       public function testSchemaWithNoDB2() {
+               DatabaseDomain::newFromId( '-schema-prefix' );
+       }
+
        /**
         * @covers Wikimedia\Rdbms\DatabaseDomain::isUnspecified
         */
index b28a5b9..414042d 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 
+use Wikimedia\Rdbms\Database;
 use Wikimedia\Rdbms\DatabaseMssql;
 
 class DatabaseMssqlTest extends PHPUnit\Framework\TestCase {
@@ -52,4 +53,10 @@ class DatabaseMssqlTest extends PHPUnit\Framework\TestCase {
                $mockDb->buildSubstring( 'foo', $start, $length );
        }
 
+       /**
+        * @covers \Wikimedia\Rdbms\DatabaseMssql::getAttributes
+        */
+       public function testAttributes() {
+               $this->assertTrue( DatabaseMssql::getAttributes()[Database::ATTR_SCHEMAS_AS_TABLE_GROUPS] );
+       }
 }
index 40c260c..c0d2555 100644 (file)
@@ -1343,7 +1343,7 @@ class DatabaseSQLTest extends PHPUnit\Framework\TestCase {
        }
 
        /**
-        * @covers Wikimedia\Rdbms\Database::registerTempTableOperation
+        * @covers Wikimedia\Rdbms\Database::registerTempTableWrite
         */
        public function testSessionTempTables() {
                $temp1 = $this->database->tableName( 'tmp_table_1' );
index bd1c112..8b24791 100644 (file)
@@ -13,6 +13,8 @@ use Wikimedia\Rdbms\DatabaseMssql;
 use Wikimedia\Rdbms\DBUnexpectedError;
 
 class DatabaseTest extends PHPUnit\Framework\TestCase {
+       /** @var DatabaseTestHelper */
+       private $db;
 
        use MediaWikiCoversValidator;
 
@@ -629,25 +631,45 @@ class DatabaseTest extends PHPUnit\Framework\TestCase {
         * @covers Wikimedia\Rdbms\Database::dbSchema
         */
        public function testSchemaAndPrefixMutators() {
+               $ud = DatabaseDomain::newUnspecified();
+
+               $this->assertEquals( $ud->getId(), $this->db->getDomainID() );
+
                $old = $this->db->tablePrefix();
                $oldDomain = $this->db->getDomainId();
                $this->assertInternalType( 'string', $old, 'Prefix is string' );
                $this->assertSame( $old, $this->db->tablePrefix(), "Prefix unchanged" );
-               $this->assertSame( $old, $this->db->tablePrefix( 'xxx' ) );
-               $this->assertSame( 'xxx', $this->db->tablePrefix(), "Prefix set" );
+               $this->assertSame( $old, $this->db->tablePrefix( 'xxx_' ) );
+               $this->assertSame( 'xxx_', $this->db->tablePrefix(), "Prefix set" );
                $this->db->tablePrefix( $old );
-               $this->assertNotEquals( 'xxx', $this->db->tablePrefix() );
+               $this->assertNotEquals( 'xxx_', $this->db->tablePrefix() );
                $this->assertSame( $oldDomain, $this->db->getDomainId() );
 
                $old = $this->db->dbSchema();
                $oldDomain = $this->db->getDomainId();
                $this->assertInternalType( 'string', $old, 'Schema is string' );
                $this->assertSame( $old, $this->db->dbSchema(), "Schema unchanged" );
+
+               $this->db->selectDB( 'y' );
                $this->assertSame( $old, $this->db->dbSchema( 'xxx' ) );
                $this->assertSame( 'xxx', $this->db->dbSchema(), "Schema set" );
                $this->db->dbSchema( $old );
                $this->assertNotEquals( 'xxx', $this->db->dbSchema() );
-               $this->assertSame( $oldDomain, $this->db->getDomainId() );
+               $this->assertSame( "y", $this->db->getDomainId() );
+       }
+
+       /**
+        * @covers Wikimedia\Rdbms\Database::tablePrefix
+        * @covers Wikimedia\Rdbms\Database::dbSchema
+        * @expectedException DBUnexpectedError
+        */
+       public function testSchemaWithNoDB() {
+               $ud = DatabaseDomain::newUnspecified();
+
+               $this->assertEquals( $ud->getId(), $this->db->getDomainID() );
+               $this->assertSame( '', $this->db->dbSchema() );
+
+               $this->db->dbSchema( 'xxx' );
        }
 
        /**
@@ -659,10 +681,10 @@ class DatabaseTest extends PHPUnit\Framework\TestCase {
                $oldSchema = $this->db->dbSchema();
                $oldPrefix = $this->db->tablePrefix();
 
-               $this->db->selectDomain( 'testselectdb-xxx' );
+               $this->db->selectDomain( 'testselectdb-xxx_' );
                $this->assertSame( 'testselectdb', $this->db->getDBname() );
                $this->assertSame( '', $this->db->dbSchema() );
-               $this->assertSame( 'xxx', $this->db->tablePrefix() );
+               $this->assertSame( 'xxx_', $this->db->tablePrefix() );
 
                $this->db->selectDomain( $oldDomain );
                $this->assertSame( $oldDatabase, $this->db->getDBname() );
@@ -670,10 +692,10 @@ class DatabaseTest extends PHPUnit\Framework\TestCase {
                $this->assertSame( $oldPrefix, $this->db->tablePrefix() );
                $this->assertSame( $oldDomain, $this->db->getDomainId() );
 
-               $this->db->selectDomain( 'testselectdb-schema-xxx' );
+               $this->db->selectDomain( 'testselectdb-schema-xxx_' );
                $this->assertSame( 'testselectdb', $this->db->getDBname() );
                $this->assertSame( 'schema', $this->db->dbSchema() );
-               $this->assertSame( 'xxx', $this->db->tablePrefix() );
+               $this->assertSame( 'xxx_', $this->db->tablePrefix() );
 
                $this->db->selectDomain( $oldDomain );
                $this->assertSame( $oldDatabase, $this->db->getDBname() );
index ad0c3d1..e3a200b 100644 (file)
@@ -4,7 +4,7 @@
  * @covers PageDataRequestHandler
  * @group PageData
  */
-class PageDataRequestHandlerTest extends \MediaWikiTestCase {
+class PageDataRequestHandlerTest extends \MediaWikiLangTestCase {
 
        /**
         * @var Title
@@ -19,9 +19,10 @@ class PageDataRequestHandlerTest extends \MediaWikiTestCase {
        protected function setUp() {
                parent::setUp();
 
-               $this->interfaceTitle = Title::newFromText( "Special:PageDataRequestHandlerTest" );
-
+               $this->interfaceTitle = Title::newFromText( __CLASS__ );
                $this->obLevel = ob_get_level();
+
+               $this->setMwGlobals( 'wgArticlePath', '/wiki/$1' );
        }
 
        protected function tearDown() {
@@ -44,7 +45,7 @@ class PageDataRequestHandlerTest extends \MediaWikiTestCase {
         * @return PageDataRequestHandler
         */
        protected function newHandler() {
-               return new PageDataRequestHandler( 'json' );
+               return new PageDataRequestHandler();
        }
 
        /**
@@ -76,9 +77,16 @@ class PageDataRequestHandlerTest extends \MediaWikiTestCase {
        public function handleRequestProvider() {
                $cases = [];
 
-               $cases[] = [ '', [], [], '!!', 400 ];
+               $cases[] = [ '', [], [], 'Invalid title', 400 ];
 
-               $cases[] = [ '', [ 'target' => 'Helsinki' ], [], '!!', 303,  [ 'Location' => '!.+!' ] ];
+               $cases[] = [
+                       '',
+                       [ 'target' => 'Helsinki' ],
+                       [],
+                       '',
+                       303,
+                       [ 'Location' => '?title=Helsinki&action=raw' ]
+               ];
 
                $subpageCases = [];
                foreach ( $cases as $c ) {
@@ -99,9 +107,9 @@ class PageDataRequestHandlerTest extends \MediaWikiTestCase {
                        '',
                        [ 'target' => 'Helsinki' ],
                        [ 'Accept' => 'text/HTML' ],
-                       '!!',
+                       '',
                        303,
-                       [ 'Location' => '!Helsinki$!' ]
+                       [ 'Location' => '/wiki/Helsinki' ]
                ];
 
                $cases[] = [
@@ -111,18 +119,18 @@ class PageDataRequestHandlerTest extends \MediaWikiTestCase {
                                'revision' => '4242',
                        ],
                        [ 'Accept' => 'text/HTML' ],
-                       '!!',
+                       '',
                        303,
-                       [ 'Location' => '!Helsinki(\?|&)oldid=4242!' ]
+                       [ 'Location' => '?title=Helsinki&oldid=4242' ]
                ];
 
                $cases[] = [
                        '/Helsinki',
                        [],
                        [],
-                       '!!',
+                       '',
                        303,
-                       [ 'Location' => '!Helsinki&action=raw!' ]
+                       [ 'Location' => '?title=Helsinki&action=raw' ]
                ];
 
                // #31: /Q5 with "Accept: text/foobar" triggers a 406
@@ -130,36 +138,59 @@ class PageDataRequestHandlerTest extends \MediaWikiTestCase {
                        'main/Helsinki',
                        [],
                        [ 'Accept' => 'text/foobar' ],
-                       '!!',
+                       'No matching format found',
                        406,
+               ];
+
+               $cases[] = [
+                       'no slash',
                        [],
+                       [ 'Accept' => 'text/HTML' ],
+                       'Invalid title',
+                       400,
+               ];
+
+               $cases[] = [
+                       'main',
+                       [],
+                       [ 'Accept' => 'text/HTML' ],
+                       'Invalid title',
+                       400,
+               ];
+
+               $cases[] = [
+                       'xyz/Helsinki',
+                       [],
+                       [ 'Accept' => 'text/HTML' ],
+                       'Invalid title',
+                       400,
                ];
 
                $cases[] = [
                        'main/Helsinki',
                        [],
                        [ 'Accept' => 'text/HTML' ],
-                       '!!',
+                       '',
                        303,
-                       [ 'Location' => '!Helsinki$!' ]
+                       [ 'Location' => '/wiki/Helsinki' ]
                ];
 
                $cases[] = [
                        '/Helsinki',
                        [],
                        [ 'Accept' => 'text/HTML' ],
-                       '!!',
+                       '',
                        303,
-                       [ 'Location' => '!Helsinki$!' ]
+                       [ 'Location' => '/wiki/Helsinki' ]
                ];
 
                $cases[] = [
                        'main/AC/DC',
                        [],
                        [ 'Accept' => 'text/HTML' ],
-                       '!!',
+                       '',
                        303,
-                       [ 'Location' => '!AC/DC$!' ]
+                       [ 'Location' => '/wiki/AC/DC' ]
                ];
 
                return $cases;
@@ -171,7 +202,7 @@ class PageDataRequestHandlerTest extends \MediaWikiTestCase {
         * @param string $subpage The subpage to request (or '')
         * @param array  $params  Request parameters
         * @param array  $headers  Request headers
-        * @param string $expectedOutput Regex to match the output against.
+        * @param string $expectedOutput
         * @param int $expectedStatusCode Expected HTTP status code.
         * @param string[] $expectedHeaders Expected HTTP response headers.
         */
@@ -179,7 +210,7 @@ class PageDataRequestHandlerTest extends \MediaWikiTestCase {
                $subpage,
                array $params,
                array $headers,
-               $expectedOutput,
+               $expectedOutput = '',
                $expectedStatusCode = 200,
                array $expectedHeaders = []
        ) {
@@ -201,22 +232,21 @@ class PageDataRequestHandlerTest extends \MediaWikiTestCase {
                                $output->output();
                        }
 
-                       $text = ob_get_contents();
-                       ob_end_clean();
+                       $text = ob_get_clean();
 
                        $this->assertEquals( $expectedStatusCode, $response->getStatusCode(), 'status code' );
-                       $this->assertRegExp( $expectedOutput, $text, 'output' );
+                       $this->assertSame( $expectedOutput, $text, 'output' );
 
                        foreach ( $expectedHeaders as $name => $exp ) {
                                $value = $response->getHeader( $name );
                                $this->assertNotNull( $value, "header: $name" );
                                $this->assertInternalType( 'string', $value, "header: $name" );
-                               $this->assertRegExp( $exp, $value, "header: $name" );
+                               $this->assertStringEndsWith( $exp, $value, "header: $name" );
                        }
                } catch ( HttpError $e ) {
                        ob_end_clean();
                        $this->assertEquals( $expectedStatusCode, $e->getStatusCode(), 'status code' );
-                       $this->assertRegExp( $expectedOutput, $e->getHTML(), 'error output' );
+                       $this->assertContains( $expectedOutput, $e->getHTML(), 'error output' );
                }
 
                // We always set "Access-Control-Allow-Origin: *"
index 27e5a65..83ce3d2 100644 (file)
@@ -19,10 +19,18 @@ class LinkRendererFactoryTest extends MediaWikiLangTestCase {
         */
        private $linkCache;
 
+       /**
+        * @var NamespaceInfo
+        */
+       private $nsInfo;
+
        public function setUp() {
                parent::setUp();
-               $this->titleFormatter = MediaWikiServices::getInstance()->getTitleFormatter();
-               $this->linkCache = MediaWikiServices::getInstance()->getLinkCache();
+
+               $services = MediaWikiServices::getInstance();
+               $this->titleFormatter = $services->getTitleFormatter();
+               $this->linkCache = $services->getLinkCache();
+               $this->nsInfo = $services->getNamespaceInfo();
        }
 
        public static function provideCreateFromLegacyOptions() {
@@ -54,7 +62,8 @@ class LinkRendererFactoryTest extends MediaWikiLangTestCase {
         * @dataProvider provideCreateFromLegacyOptions
         */
        public function testCreateFromLegacyOptions( $options, $func, $val ) {
-               $factory = new LinkRendererFactory( $this->titleFormatter, $this->linkCache );
+               $factory =
+                       new LinkRendererFactory( $this->titleFormatter, $this->linkCache, $this->nsInfo );
                $linkRenderer = $factory->createFromLegacyOptions(
                        $options
                );
@@ -63,7 +72,8 @@ class LinkRendererFactoryTest extends MediaWikiLangTestCase {
        }
 
        public function testCreate() {
-               $factory = new LinkRendererFactory( $this->titleFormatter, $this->linkCache );
+               $factory =
+                       new LinkRendererFactory( $this->titleFormatter, $this->linkCache, $this->nsInfo );
                $this->assertInstanceOf( LinkRenderer::class, $factory->create() );
        }
 
@@ -74,7 +84,8 @@ class LinkRendererFactoryTest extends MediaWikiLangTestCase {
                $user->expects( $this->once() )
                        ->method( 'getStubThreshold' )
                        ->willReturn( 15 );
-               $factory = new LinkRendererFactory( $this->titleFormatter, $this->linkCache );
+               $factory =
+                       new LinkRendererFactory( $this->titleFormatter, $this->linkCache, $this->nsInfo );
                $linkRenderer = $factory->createForUser( $user );
                $this->assertInstanceOf( LinkRenderer::class, $linkRenderer );
                $this->assertEquals( 15, $linkRenderer->getStubThreshold() );
index 91ee276..d4e1961 100644 (file)
@@ -140,7 +140,8 @@ class LinkRendererTest extends MediaWikiLangTestCase {
        public function testGetLinkClasses() {
                $wanCache = ObjectCache::getMainWANInstance();
                $titleFormatter = MediaWikiServices::getInstance()->getTitleFormatter();
-               $linkCache = new LinkCache( $titleFormatter, $wanCache );
+               $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
+               $linkCache = new LinkCache( $titleFormatter, $wanCache, $nsInfo );
                $foobarTitle = new TitleValue( NS_MAIN, 'FooBar' );
                $redirectTitle = new TitleValue( NS_MAIN, 'Redirect' );
                $userTitle = new TitleValue( NS_USER, 'Someuser' );
@@ -164,7 +165,7 @@ class LinkRendererTest extends MediaWikiLangTestCase {
                        0 // redir
                );
 
-               $linkRenderer = new LinkRenderer( $titleFormatter, $linkCache );
+               $linkRenderer = new LinkRenderer( $titleFormatter, $linkCache, $nsInfo );
                $linkRenderer->setStubThreshold( 0 );
                $this->assertEquals(
                        '',
index 91ce9ea..f444d40 100644 (file)
@@ -105,7 +105,8 @@ class LogFormatterTest extends MediaWikiLangTestCase {
                $userTools = Linker::userToolLinksRedContribs(
                        $this->user->getId(),
                        $this->user->getName(),
-                       $this->user->getEditCount()
+                       $this->user->getEditCount(),
+                       false
                );
 
                $titleLink = Linker::link( $this->title, null, [], [] );
index 7a536df..2e9acfa 100644 (file)
@@ -70,16 +70,10 @@ abstract class MediaWikiMediaTestCase extends MediaWikiTestCase {
         *
         * File must be in the path returned by getFilePath()
         * @param string $name File name
-        * @param string|null $type MIME type [optional]
+        * @param string|false $type MIME type [optional]
         * @return UnregisteredLocalFile
         */
-       protected function dataFile( $name, $type = null ) {
-               if ( !$type ) {
-                       // Autodetect by file extension for the lazy.
-                       $magic = MediaWiki\MediaWikiServices::getInstance()->getMimeAnalyzer();
-                       $parts = explode( $name, '.' );
-                       $type = $magic->guessTypesForExtension( $parts[count( $parts ) - 1] );
-               }
+       protected function dataFile( $name, $type = false ) {
                return new UnregisteredLocalFile( false, $this->repo,
                        "mwstore://localtesting/data/$name", $type );
        }
index 66754fc..dfbca70 100644 (file)
@@ -28,9 +28,10 @@ class RESTBagOStuffTest extends MediaWikiTestCase {
        public function testGet() {
                $this->client->expects( $this->once() )->method( 'run' )->with( [
                        'method' => 'GET',
-                       'url' => 'http://test/rest/42xyz42'
+                       'url' => 'http://test/rest/42xyz42',
+                       'headers' => []
                        // list( $rcode, $rdesc, $rhdrs, $rbody, $rerr )
-               ] )->willReturn( [ 200, 'OK', [], 's:8:"somedata";', 0 ] );
+               ] )->willReturn( [ 200, 'OK', [], '"somedata"', 0 ] );
                $result = $this->bag->get( '42xyz42' );
                $this->assertEquals( 'somedata', $result );
        }
@@ -38,7 +39,8 @@ class RESTBagOStuffTest extends MediaWikiTestCase {
        public function testGetNotExist() {
                $this->client->expects( $this->once() )->method( 'run' )->with( [
                        'method' => 'GET',
-                       'url' => 'http://test/rest/42xyz42'
+                       'url' => 'http://test/rest/42xyz42',
+                       'headers' => []
                        // list( $rcode, $rdesc, $rhdrs, $rbody, $rerr )
                ] )->willReturn( [ 404, 'Not found', [], 'Nothing to see here', 0 ] );
                $result = $this->bag->get( '42xyz42' );
@@ -48,7 +50,8 @@ class RESTBagOStuffTest extends MediaWikiTestCase {
        public function testGetBadClient() {
                $this->client->expects( $this->once() )->method( 'run' )->with( [
                        'method' => 'GET',
-                       'url' => 'http://test/rest/42xyz42'
+                       'url' => 'http://test/rest/42xyz42',
+                       'headers' => []
                        // list( $rcode, $rdesc, $rhdrs, $rbody, $rerr )
                ] )->willReturn( [ 0, '', [], '', 'cURL has failed you today' ] );
                $result = $this->bag->get( '42xyz42' );
@@ -59,7 +62,8 @@ class RESTBagOStuffTest extends MediaWikiTestCase {
        public function testGetBadServer() {
                $this->client->expects( $this->once() )->method( 'run' )->with( [
                        'method' => 'GET',
-                       'url' => 'http://test/rest/42xyz42'
+                       'url' => 'http://test/rest/42xyz42',
+                       'headers' => []
                        // list( $rcode, $rdesc, $rhdrs, $rbody, $rerr )
                ] )->willReturn( [ 500, 'Too busy', [], 'Server is too busy', '' ] );
                $result = $this->bag->get( '42xyz42' );
@@ -71,7 +75,8 @@ class RESTBagOStuffTest extends MediaWikiTestCase {
                $this->client->expects( $this->once() )->method( 'run' )->with( [
                        'method' => 'PUT',
                        'url' => 'http://test/rest/42xyz42',
-                       'body' => 's:8:"postdata";'
+                       'body' => '"postdata"',
+                       'headers' => []
                        // list( $rcode, $rdesc, $rhdrs, $rbody, $rerr )
                ] )->willReturn( [ 200, 'OK', [], 'Done', 0 ] );
                $result = $this->bag->set( '42xyz42', 'postdata' );
@@ -82,6 +87,7 @@ class RESTBagOStuffTest extends MediaWikiTestCase {
                $this->client->expects( $this->once() )->method( 'run' )->with( [
                        'method' => 'DELETE',
                        'url' => 'http://test/rest/42xyz42',
+                       'headers' => []
                        // list( $rcode, $rdesc, $rhdrs, $rbody, $rerr )
                ] )->willReturn( [ 200, 'OK', [], 'Done', 0 ] );
                $result = $this->bag->delete( '42xyz42' );
index ba4b2e2..3ff677e 100644 (file)
@@ -41,9 +41,9 @@ class PageArchiveMcrTest extends PageArchiveTestBase {
                return [
                        [
                                'ar_minor_edit' => '0',
-                               'ar_user' => '0',
+                               'ar_user' => null,
                                'ar_user_text' => $this->ipEditor,
-                               'ar_actor' => null,
+                               'ar_actor' => (string)User::newFromName( $this->ipEditor, false )->getActorId( $this->db ),
                                'ar_len' => '11',
                                'ar_deleted' => '0',
                                'ar_rev_id' => strval( $this->ipRev->getId() ),
@@ -63,7 +63,7 @@ class PageArchiveMcrTest extends PageArchiveTestBase {
                                'ar_minor_edit' => '0',
                                'ar_user' => (string)$this->getTestUser()->getUser()->getId(),
                                'ar_user_text' => $this->getTestUser()->getUser()->getName(),
-                               'ar_actor' => null,
+                               'ar_actor' => (string)$this->getTestUser()->getUser()->getActorId(),
                                'ar_len' => '7',
                                'ar_deleted' => '0',
                                'ar_rev_id' => strval( $this->firstRev->getId() ),
index f8d4ef9..fcb10e7 100644 (file)
@@ -18,24 +18,6 @@ class PageArchivePreMcrTest extends PageArchiveTestBase {
 
        use PreMcrSchemaOverride;
 
-       /**
-        * @covers PageArchive::getTextFromRow
-        */
-       public function testGetTextFromRow() {
-               $this->hideDeprecated( PageArchive::class . '::getTextFromRow' );
-
-               /** @var SqlBlobStore $blobStore */
-               $blobStore = MediaWikiServices::getInstance()->getBlobStore();
-
-               $textId = $blobStore->getTextIdFromAddress(
-                       $this->firstRev->getSlot( SlotRecord::MAIN )->getAddress()
-               );
-
-               $row = (object)[ 'ar_text_id' => $textId ];
-               $text = $this->archivedPage->getTextFromRow( $row );
-               $this->assertSame( 'testing', $text );
-       }
-
        protected function getExpectedArchiveRows() {
                /** @var SqlBlobStore $blobStore */
                $blobStore = MediaWikiServices::getInstance()->getBlobStore();
@@ -43,9 +25,9 @@ class PageArchivePreMcrTest extends PageArchiveTestBase {
                return [
                        [
                                'ar_minor_edit' => '0',
-                               'ar_user' => '0',
+                               'ar_user' => null,
                                'ar_user_text' => $this->ipEditor,
-                               'ar_actor' => null,
+                               'ar_actor' => (string)User::newFromName( $this->ipEditor, false )->getActorId( $this->db ),
                                'ar_len' => '11',
                                'ar_deleted' => '0',
                                'ar_rev_id' => strval( $this->ipRev->getId() ),
@@ -70,7 +52,7 @@ class PageArchivePreMcrTest extends PageArchiveTestBase {
                                'ar_minor_edit' => '0',
                                'ar_user' => (string)$this->getTestUser()->getUser()->getId(),
                                'ar_user_text' => $this->getTestUser()->getUser()->getName(),
-                               'ar_actor' => null,
+                               'ar_actor' => (string)$this->getTestUser()->getUser()->getActorId(),
                                'ar_len' => '7',
                                'ar_deleted' => '0',
                                'ar_rev_id' => strval( $this->firstRev->getId() ),
index 06c0456..15c64a9 100644 (file)
@@ -82,7 +82,7 @@ abstract class PageArchiveTestBase extends MediaWikiTestCase {
 
                $this->tablesUsed += $this->getMcrTablesToReset();
 
-               $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_OLD );
+               $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
                $this->setMwGlobals( 'wgContentHandlerUseDB', $this->getContentHandlerUseDB() );
                $this->setMwGlobals(
                        'wgMultiContentRevisionSchemaMigrationStage',
@@ -252,27 +252,6 @@ abstract class PageArchiveTestBase extends MediaWikiTestCase {
                yield 'ar_text_id is "0"' => [ [ 'ar_text_id' => '0' ] ];
        }
 
-       /**
-        * @dataProvider provideGetTextFromRowThrowsInvalidArgumentException
-        * @covers PageArchive::getTextFromRow
-        */
-       public function testGetTextFromRowThrowsInvalidArgumentException( array $row ) {
-               $this->hideDeprecated( PageArchive::class . '::getTextFromRow' );
-               $this->setExpectedException( InvalidArgumentException::class );
-
-               $this->archivedPage->getTextFromRow( (object)$row );
-       }
-
-       /**
-        * @covers PageArchive::getLastRevisionText
-        */
-       public function testGetLastRevisionText() {
-               $this->hideDeprecated( PageArchive::class . '::getLastRevisionText' );
-
-               $text = $this->archivedPage->getLastRevisionText();
-               $this->assertSame( 'Lorem Ipsum', $text );
-       }
-
        /**
         * @covers PageArchive::getLastRevisionId
         */
index ac5fef9..3a3feee 100644 (file)
@@ -71,7 +71,7 @@ abstract class WikiPageDbTestBase extends MediaWikiLangTestCase {
 
        protected function tearDown() {
                foreach ( $this->pagesToDelete as $p ) {
-                       /* @var $p WikiPage */
+                       /* @var WikiPage $p */
 
                        try {
                                if ( $p->exists() ) {
@@ -483,7 +483,7 @@ abstract class WikiPageDbTestBase extends MediaWikiLangTestCase {
                                'delete',
                                'delete',
                                'testing user 0 deletion',
-                               '0',
+                               null,
                                '127.0.0.1',
                                (string)$page->getTitle()->getNamespace(),
                                $page->getTitle()->getDBkey(),
index f37bdfc..048256d 100644 (file)
@@ -22,9 +22,11 @@ class ParserFactoryTest extends MediaWikiTestCase {
        public function testAllArgumentsWerePassed() {
                $factoryConstructor = new ReflectionMethod( 'ParserFactory', '__construct' );
                $mocks = [];
-               foreach ( $factoryConstructor->getParameters() as $param ) {
+               foreach ( $factoryConstructor->getParameters() as $index => $param ) {
                        $type = (string)$param->getType();
-                       if ( $type === 'array' ) {
+                       if ( $index === 0 ) {
+                               $val = $this->createMock( 'MediaWiki\Config\ServiceOptions' );
+                       } elseif ( $type === 'array' ) {
                                $val = [ 'porcupines will tell me your secrets' . count( $mocks ) ];
                        } elseif ( class_exists( $type ) || interface_exists( $type ) ) {
                                $val = $this->createMock( $type );
@@ -52,4 +54,54 @@ class ParserFactoryTest extends MediaWikiTestCase {
                $this->assertCount( 0, $mocks, 'Not all arguments to the ParserFactory constructor were ' .
                        'found in Parser member variables' );
        }
+
+       public function provideConstructorArguments() {
+               // Create a mock Config object that will satisfy ServiceOptions::__construct
+               $mockConfig = $this->createMock( 'Config' );
+               $mockConfig->method( 'has' )->willReturn( true );
+               $mockConfig->method( 'get' )->willReturn( 'I like otters.' );
+
+               $mocks = [
+                       [ 'the plural of platypus...' ],
+                       $this->createMock( 'MagicWordFactory' ),
+                       $this->createMock( 'Language' ),
+                       '...is platypodes',
+                       $this->createMock( 'MediaWiki\Special\SpecialPageFactory' ),
+                       $mockConfig,
+                       $this->createMock( 'MediaWiki\Linker\LinkRendererFactory' ),
+               ];
+
+               yield 'args_without_namespace_info' => [
+                       $mocks,
+               ];
+               yield 'args_with_namespace_info' => [
+                       array_merge( $mocks, [ $this->createMock( 'NamespaceInfo' ) ] ),
+               ];
+       }
+
+       /**
+        * @dataProvider provideConstructorArguments
+        * @covers ParserFactory::__construct
+        */
+       public function testBackwardsCompatibleConstructorArguments( $args ) {
+               $this->hideDeprecated( 'ParserFactory::__construct with Config parameter' );
+               $factory = new ParserFactory( ...$args );
+               $parser = $factory->create();
+
+               // It is expected that these are not present on the parser.
+               unset( $args[5] );
+               unset( $args[0] );
+
+               foreach ( ( new ReflectionObject( $parser ) )->getProperties() as $prop ) {
+                       $prop->setAccessible( true );
+                       foreach ( $args as $idx => $mockTest ) {
+                               if ( $prop->getValue( $parser ) === $mockTest ) {
+                                       unset( $args[$idx] );
+                               }
+                       }
+               }
+
+               $this->assertCount( 0, $args, 'Not all arguments to the ParserFactory constructor were ' .
+                       'found in Parser member variables' );
+       }
 }
index e102b9b..cf0b650 100644 (file)
@@ -1,4 +1,5 @@
 <?php
+use MediaWiki\MediaWikiServices;
 use MediaWiki\Revision\MutableRevisionRecord;
 use MediaWiki\Revision\RevisionStore;
 use MediaWiki\Revision\SlotRecord;
@@ -26,13 +27,12 @@ class ParserMethodsTest extends MediaWikiLangTestCase {
         * @dataProvider providePreSaveTransform
         */
        public function testPreSaveTransform( $text, $expected ) {
-               global $wgParser;
-
                $title = Title::newFromText( str_replace( '::', '__', __METHOD__ ) );
                $user = new User();
                $user->setName( "127.0.0.1" );
                $popts = ParserOptions::newFromUser( $user );
-               $text = $wgParser->preSaveTransform( $text, $title, $user, $popts );
+               $text = MediaWikiServices::getInstance()->getParser()
+                       ->preSaveTransform( $text, $title, $user, $popts );
 
                $this->assertEquals( $expected, $text );
        }
@@ -78,11 +78,11 @@ class ParserMethodsTest extends MediaWikiLangTestCase {
         *  Did you call Parser::parse recursively?
         */
        public function testRecursiveParse() {
-               global $wgParser;
                $title = Title::newFromText( 'foo' );
+               $parser = MediaWikiServices::getInstance()->getParser();
                $po = new ParserOptions;
-               $wgParser->setHook( 'recursivecallparser', [ $this, 'helperParserFunc' ] );
-               $wgParser->parse( '<recursivecallparser>baz</recursivecallparser>', $title, $po );
+               $parser->setHook( 'recursivecallparser', [ $this, 'helperParserFunc' ] );
+               $parser->parse( '<recursivecallparser>baz</recursivecallparser>', $title, $po );
        }
 
        public function helperParserFunc( $input, $args, $parser ) {
@@ -93,16 +93,15 @@ class ParserMethodsTest extends MediaWikiLangTestCase {
        }
 
        public function testCallParserFunction() {
-               global $wgParser;
-
                // Normal parses test passing PPNodes. Test passing an array.
                $title = Title::newFromText( str_replace( '::', '__', __METHOD__ ) );
-               $wgParser->startExternalParse( $title, new ParserOptions(), Parser::OT_HTML );
-               $frame = $wgParser->getPreprocessor()->newFrame();
-               $ret = $wgParser->callParserFunction( $frame, '#tag',
+               $parser = MediaWikiServices::getInstance()->getParser();
+               $parser->startExternalParse( $title, new ParserOptions(), Parser::OT_HTML );
+               $frame = $parser->getPreprocessor()->newFrame();
+               $ret = $parser->callParserFunction( $frame, '#tag',
                        [ 'pre', 'foo', 'style' => 'margin-left: 1.6em' ]
                );
-               $ret['text'] = $wgParser->mStripState->unstripBoth( $ret['text'] );
+               $ret['text'] = $parser->mStripState->unstripBoth( $ret['text'] );
                $this->assertSame( [
                        'found' => true,
                        'text' => '<pre style="margin-left: 1.6em">foo</pre>',
@@ -114,10 +113,9 @@ class ParserMethodsTest extends MediaWikiLangTestCase {
         * @covers ParserOutput::getSections
         */
        public function testGetSections() {
-               global $wgParser;
-
                $title = Title::newFromText( str_replace( '::', '__', __METHOD__ ) );
-               $out = $wgParser->parse( "==foo==\n<h2>bar</h2>\n==baz==\n", $title, new ParserOptions() );
+               $out = MediaWikiServices::getInstance()->getParser()
+                       ->parse( "==foo==\n<h2>bar</h2>\n==baz==\n", $title, new ParserOptions() );
                $this->assertSame( [
                        [
                                'toclevel' => 1,
@@ -195,11 +193,11 @@ class ParserMethodsTest extends MediaWikiLangTestCase {
        }
 
        public function testWrapOutput() {
-               global $wgParser;
                $title = Title::newFromText( 'foo' );
                $po = new ParserOptions();
-               $wgParser->parse( 'Hello World', $title, $po );
-               $text = $wgParser->getOutput()->getText();
+               $parser = MediaWikiServices::getInstance()->getParser();
+               $parser->parse( 'Hello World', $title, $po );
+               $text = $parser->getOutput()->getText();
 
                $this->assertContains( 'Hello World', $text );
                $this->assertContains( '<div', $text );
@@ -330,8 +328,6 @@ class ParserMethodsTest extends MediaWikiLangTestCase {
                $expectedInHtml,
                $expectedInPst = null
        ) {
-               global $wgParser;
-
                $title = $this->getMockTitle( 'ParserRevisionAccessTest' );
 
                $po->enableLimitReport( false );
@@ -369,13 +365,14 @@ class ParserMethodsTest extends MediaWikiLangTestCase {
 
                $this->setService( 'RevisionStore', $revisionStore );
 
-               $wgParser->parse( $text, $title, $po, true, true, $revId );
-               $html = $wgParser->getOutput()->getText();
+               $parser = MediaWikiServices::getInstance()->getParser();
+               $parser->parse( $text, $title, $po, true, true, $revId );
+               $html = $parser->getOutput()->getText();
 
                $this->assertContains( $expectedInHtml, $html, 'In HTML' );
 
                if ( $expectedInPst !== null ) {
-                       $pst = $wgParser->preSaveTransform( $text, $title, $po->getUser(), $po );
+                       $pst = $parser->preSaveTransform( $text, $title, $po->getUser(), $po );
                        $this->assertContains( $expectedInPst, $pst, 'After Pre-Safe Transform' );
                }
        }
@@ -390,8 +387,8 @@ class ParserMethodsTest extends MediaWikiLangTestCase {
        /** @dataProvider provideGuessSectionNameFromWikiText */
        public function testGuessSectionNameFromWikiText( $input, $mode, $expected ) {
                $this->setMwGlobals( [ 'wgFragmentMode' => [ $mode ] ] );
-               global $wgParser;
-               $result = $wgParser->guessSectionNameFromWikiText( $input );
+               $result = MediaWikiServices::getInstance()->getParser()
+                       ->guessSectionNameFromWikiText( $input );
                $this->assertEquals( $result, $expected );
        }
 
index 6413ddd..01fde35 100644 (file)
@@ -284,6 +284,31 @@ class ParserOptionsTest extends MediaWikiTestCase {
                ScopedCallback::consume( $reset );
        }
 
+       public function testMatchesForCacheKey() {
+               $cOpts = ParserOptions::newCanonical( null, 'en' );
+
+               $uOpts = ParserOptions::newFromAnon();
+               $this->assertTrue( $cOpts->matchesForCacheKey( $uOpts ) );
+
+               $user = new User();
+               $uOpts = ParserOptions::newFromUser( $user );
+               $this->assertTrue( $cOpts->matchesForCacheKey( $uOpts ) );
+
+               $user = new User();
+               $user->setOption( 'thumbsize', 251 );
+               $uOpts = ParserOptions::newFromUser( $user );
+               $this->assertFalse( $cOpts->matchesForCacheKey( $uOpts ) );
+
+               $user = new User();
+               $user->setOption( 'stubthreshold', 800 );
+               $uOpts = ParserOptions::newFromUser( $user );
+               $this->assertFalse( $cOpts->matchesForCacheKey( $uOpts ) );
+
+               $user = new User();
+               $uOpts = ParserOptions::newFromUserAndLang( $user, Language::factory( 'zh' ) );
+               $this->assertFalse( $cOpts->matchesForCacheKey( $uOpts ) );
+       }
+
        public function testAllCacheVaryingOptions() {
                $this->setTemporaryHook( 'ParserOptionsRegister', null );
                $this->assertSame( [
diff --git a/tests/phpunit/includes/parser/ParserTest.php b/tests/phpunit/includes/parser/ParserTest.php
new file mode 100644 (file)
index 0000000..19341f5
--- /dev/null
@@ -0,0 +1,98 @@
+<?php
+
+/**
+ * @covers Parser::__construct
+ */
+class ParserTest extends MediaWikiTestCase {
+       public function provideConstructorArguments() {
+               // Create a mock Config object that will satisfy ServiceOptions::__construct
+               $mockConfig = $this->createMock( 'Config' );
+               $mockConfig->method( 'has' )->willReturn( true );
+               $mockConfig->method( 'get' )->willReturn( 'I like otters.' );
+
+               $newArgs = [
+                       $this->createMock( 'MediaWiki\Config\ServiceOptions' ),
+                       $this->createMock( 'MagicWordFactory' ),
+                       $this->createMock( 'Language' ),
+                       $this->createMock( 'ParserFactory' ),
+                       'a snail can sleep for three years',
+                       $this->createMock( 'MediaWiki\Special\SpecialPageFactory' ),
+                       $this->createMock( 'MediaWiki\Linker\LinkRendererFactory' ),
+                       $this->createMock( 'NamespaceInfo' )
+               ];
+
+               $oldArgs = [
+                       [],
+                       $this->createMock( 'MagicWordFactory' ),
+                       $this->createMock( 'Language' ),
+                       $this->createMock( 'ParserFactory' ),
+                       'a snail can sleep for three years',
+                       $this->createMock( 'MediaWiki\Special\SpecialPageFactory' )
+               ];
+
+               yield 'current_args_without_namespace_info' => [
+                       $newArgs,
+               ];
+
+               yield 'backward_compatible_args_minimal' => [
+                       array_merge( $oldArgs ),
+               ];
+
+               yield 'backward_compatible_args_with_config' => [
+                       array_merge( $oldArgs, [ $mockConfig ] ),
+               ];
+
+               yield 'backward_compatible_args_with_link_renderer' => [
+                       array_merge( $oldArgs, [
+                               $mockConfig,
+                               $this->createMock( 'MediaWiki\Linker\LinkRendererFactory' )
+                       ] ),
+               ];
+
+               yield 'backward_compatible_args_with_ns_info' => [
+                       array_merge( $oldArgs, [
+                               $mockConfig,
+                               $this->createMock( 'MediaWiki\Linker\LinkRendererFactory' ),
+                               $this->createMock( 'NamespaceInfo' )
+                       ] ),
+               ];
+       }
+
+       /**
+        * @dataProvider provideConstructorArguments
+        * @covers Parser::__construct
+        */
+       public function testBackwardsCompatibleConstructorArguments( $args ) {
+               $parser = new Parser( ...$args );
+
+               $refObject = new ReflectionObject( $parser );
+
+               // If testing backwards compatibility, test service options separately
+               if ( is_array( $args[0] ) ) {
+                       $svcOptionsProp = $refObject->getProperty( 'svcOptions' );
+                       $svcOptionsProp->setAccessible( true );
+                       $this->assertType( 'MediaWiki\Config\ServiceOptions',
+                               $svcOptionsProp->getValue( $parser )
+                       );
+                       unset( $args[0] );
+
+                       // If a Config is passed, the fact that we were able to create a ServiceOptions
+                       // instance without error from it proves that this argument works.
+                       if ( isset( $args[6] ) ) {
+                               unset( $args[6] );
+                       }
+               }
+
+               foreach ( $refObject->getProperties() as $prop ) {
+                       $prop->setAccessible( true );
+                       foreach ( $args as $idx => $mockTest ) {
+                               if ( $prop->getValue( $parser ) === $mockTest ) {
+                                       unset( $args[$idx] );
+                               }
+                       }
+               }
+
+               $this->assertCount( 0, $args, 'Not all arguments to the Parser constructor were ' .
+                       'found on the Parser object' );
+       }
+}
index d1e2578..4557ace 100644 (file)
@@ -82,8 +82,6 @@ abstract class PasswordTestCase extends MediaWikiTestCase {
                $invalid = $this->passwordFactory->newFromCiphertext( null );
                $normal = $this->passwordFactory->newFromCiphertext( $hash );
 
-               $this->assertFalse( $invalid->equals( $normal ) );
-               $this->assertFalse( $normal->equals( $invalid ) );
                $this->assertFalse( $invalid->verify( $hash ) );
        }
 
index 19baf5a..28cd503 100644 (file)
@@ -78,7 +78,7 @@ class PoolCounterTest extends MediaWikiTestCase {
 // That call will die if the contructor is not public, unless we use disableOriginalConstructor(),
 // in which case we could not test the constructor.
 abstract class PoolCounterAbstractMock extends PoolCounter {
-       public function __construct() {
-               call_user_func_array( 'parent::__construct', func_get_args() );
+       public function __construct( ...$args ) {
+               call_user_func_array( 'parent::__construct', $args );
        }
 }
index 8142f39..a00eb3f 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 
 use MediaWiki\Auth\AuthManager;
+use MediaWiki\Config\ServiceOptions;
 use MediaWiki\MediaWikiServices;
 use MediaWiki\Preferences\DefaultPreferencesFactory;
 use Wikimedia\TestingAccessWrapper;
@@ -51,11 +52,19 @@ class DefaultPreferencesFactoryTest extends \MediaWikiTestCase {
         * @return DefaultPreferencesFactory
         */
        protected function getPreferencesFactory() {
+               $mockNsInfo = $this->createMock( NamespaceInfo::class );
+               $mockNsInfo->method( 'getValidNamespaces' )->willReturn( [
+                       NS_MAIN, NS_TALK, NS_USER, NS_USER_TALK
+               ] );
+               $mockNsInfo->expects( $this->never() )
+                       ->method( $this->anythingBut( 'getValidNamespaces', '__destruct' ) );
+
                return new DefaultPreferencesFactory(
-                       $this->config,
+                       new ServiceOptions( DefaultPreferencesFactory::$constructorOptions, $this->config ),
                        new Language(),
                        AuthManager::singleton(),
-                       MediaWikiServices::getInstance()->getLinkRenderer()
+                       MediaWikiServices::getInstance()->getLinkRenderer(),
+                       $mockNsInfo
                );
        }
 
@@ -67,7 +76,7 @@ class DefaultPreferencesFactoryTest extends \MediaWikiTestCase {
 
                $testUser = $this->getTestUser();
                $form = $this->getPreferencesFactory()->getForm( $testUser->getUser(), $this->context );
-               $this->assertInstanceOf( PreferencesFormLegacy::class, $form );
+               $this->assertInstanceOf( PreferencesFormOOUI::class, $form );
                $this->assertCount( 5, $form->getPreferenceSections() );
        }
 
@@ -87,8 +96,6 @@ class DefaultPreferencesFactoryTest extends \MediaWikiTestCase {
         * @covers MediaWiki\Preferences\DefaultPreferencesFactory::renderingPreferences()
         */
        public function testShowRollbackConfIsHiddenForUsersWithoutRollbackRights() {
-               // TODO Remove temporary skip marker once feature is added back in
-               $this->markTestSkipped();
                $userMock = $this->getMockBuilder( User::class )
                        ->disableOriginalConstructor()
                        ->getMock();
@@ -109,8 +116,6 @@ class DefaultPreferencesFactoryTest extends \MediaWikiTestCase {
         * @covers MediaWiki\Preferences\DefaultPreferencesFactory::renderingPreferences()
         */
        public function testShowRollbackConfIsShownForUsersWithRollbackRights() {
-               // TODO Remove temporary skip marker once feature is added back in
-               $this->markTestSkipped();
                $userMock = $this->getMockBuilder( User::class )
                        ->disableOriginalConstructor()
                        ->getMock();
@@ -166,7 +171,7 @@ class DefaultPreferencesFactoryTest extends \MediaWikiTestCase {
                $configMock = new HashConfig( [
                        'HiddenPrefs' => []
                ] );
-               $form = $this->getMockBuilder( PreferencesFormLegacy::class )
+               $form = $this->getMockBuilder( PreferencesFormOOUI::class )
                        ->disableOriginalConstructor()
                        ->getMock();
 
index 6b92444..e824e3f 100644 (file)
@@ -101,7 +101,21 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase {
         * @dataProvider provideType
         */
        public function testType( $given, $expected ) {
-               $checker = new VersionChecker( '1.0.0', '7.0.0', [ 'phpLoadedExtension' ] );
+               $checker = new VersionChecker(
+                       '1.0.0',
+                       '7.0.0',
+                       [ 'phpLoadedExtension' ],
+                       [
+                               'presentAbility' => true,
+                               'presentAbilityWithMessage' => true,
+                               'missingAbility' => false,
+                               'missingAbilityWithMessage' => false,
+                       ],
+                       [
+                               'presentAbilityWithMessage' => 'Present.',
+                               'missingAbilityWithMessage' => 'Missing.',
+                       ]
+               );
                $checker->setLoadedExtensionsAndSkins( [
                                'FakeDependency' => [
                                        'version' => '1.0.0',
@@ -218,6 +232,83 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase {
                                        ],
                                ],
                        ],
+                       [
+                               [
+                                       'platform' => [
+                                               'ability-presentAbility' => true,
+                                       ],
+                               ],
+                               [],
+                       ],
+                       [
+                               [
+                                       'platform' => [
+                                               'ability-presentAbilityWithMessage' => true,
+                                       ],
+                               ],
+                               [],
+                       ],
+                       [
+                               [
+                                       'platform' => [
+                                               'ability-presentAbility' => false,
+                                       ],
+                               ],
+                               [],
+                       ],
+                       [
+                               [
+                                       'platform' => [
+                                               'ability-presentAbilityWithMessage' => false,
+                                       ],
+                               ],
+                               [],
+                       ],
+                       [
+                               [
+                                       'platform' => [
+                                               'ability-missingAbility' => true,
+                                       ],
+                               ],
+                               [
+                                       [
+                                               'missing' => 'missingAbility',
+                                               'type' => 'missing-ability',
+                                               'msg' => 'FakeExtension requires "missingAbility" ability',
+                                       ],
+                               ],
+                       ],
+                       [
+                               [
+                                       'platform' => [
+                                               'ability-missingAbilityWithMessage' => true,
+                                       ],
+                               ],
+                               [
+                                       [
+                                               'missing' => 'missingAbilityWithMessage',
+                                               'type' => 'missing-ability',
+                                               // phpcs:ignore Generic.Files.LineLength.TooLong
+                                               'msg' => 'FakeExtension requires "missingAbilityWithMessage" ability: Missing.',
+                                       ],
+                               ],
+                       ],
+                       [
+                               [
+                                       'platform' => [
+                                               'ability-missingAbility' => false,
+                                       ],
+                               ],
+                               [],
+                       ],
+                       [
+                               [
+                                       'platform' => [
+                                               'ability-missingAbilityWithMessage' => false,
+                                       ],
+                               ],
+                               [],
+                       ],
                ];
        }
 
@@ -282,6 +373,26 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase {
                                ],
                                'phpLoadedExtension',
                        ],
+                       [
+                               [
+                                       'FakeExtension' => [
+                                               'platform' => [
+                                                       'ability-invalidAbility' => true,
+                                               ],
+                                       ],
+                               ],
+                               'ability-invalidAbility',
+                       ],
+                       [
+                               [
+                                       'FakeExtension' => [
+                                               'platform' => [
+                                                       'presentAbility' => true,
+                                               ],
+                                       ],
+                               ],
+                               'presentAbility',
+                       ],
                        [
                                [
                                        'FakeExtension' => [
@@ -308,7 +419,15 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase {
         * @dataProvider provideInvalidDependency
         */
        public function testInvalidDependency( $depencency, $type ) {
-               $checker = new VersionChecker( '1.0.0', '7.0.0', [ 'phpLoadedExtension' ] );
+               $checker = new VersionChecker(
+                       '1.0.0',
+                       '7.0.0',
+                       [ 'phpLoadedExtension' ],
+                       [
+                               'presentAbility' => true,
+                               'missingAbility' => false,
+                       ]
+               );
                $this->setExpectedException(
                        UnexpectedValueException::class,
                        "Dependency type $type unknown in FakeExtension"
@@ -330,4 +449,31 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase {
                        ],
                ] );
        }
+
+       /**
+        * @dataProvider provideInvalidAbilityType
+        */
+       public function testInvalidAbilityType( $value ) {
+               $checker = new VersionChecker( '1.0.0', '7.0.0', [], [ 'presentAbility' => true ] );
+               $this->setExpectedException(
+                       UnexpectedValueException::class,
+                       'Only booleans are allowed to to indicate the presence of abilities in FakeExtension'
+               );
+               $checker->checkArray( [
+                       'FakeExtension' => [
+                               'platform' => [
+                                       'ability-presentAbility' => $value,
+                               ],
+                       ],
+               ] );
+       }
+
+       public function provideInvalidAbilityType() {
+               return [
+                       [ null ],
+                       [ 1 ],
+                       [ '1' ],
+               ];
+       }
+
 }
index 97ffd94..c210061 100644 (file)
@@ -8,10 +8,10 @@ class DerivativeResourceLoaderContextTest extends PHPUnit\Framework\TestCase {
 
        use MediaWikiCoversValidator;
 
-       protected static function getContext() {
+       protected static function makeContext() {
                $request = new FauxRequest( [
-                               'lang' => 'zh',
-                               'modules' => 'test.context',
+                               'lang' => 'qqx',
+                               'modules' => 'test.default',
                                'only' => 'scripts',
                                'skin' => 'fallback',
                                'target' => 'test',
@@ -19,123 +19,114 @@ class DerivativeResourceLoaderContextTest extends PHPUnit\Framework\TestCase {
                return new ResourceLoaderContext( new ResourceLoader(), $request );
        }
 
-       public function testGetInherited() {
-               $derived = new DerivativeResourceLoaderContext( self::getContext() );
-
-               // Request parameters
-               $this->assertEquals( $derived->getDebug(), false );
-               $this->assertEquals( $derived->getLanguage(), 'zh' );
-               $this->assertEquals( $derived->getModules(), [ 'test.context' ] );
-               $this->assertEquals( $derived->getOnly(), 'scripts' );
-               $this->assertEquals( $derived->getSkin(), 'fallback' );
-               $this->assertEquals( $derived->getUser(), null );
-
-               // Misc
-               $this->assertEquals( $derived->getDirection(), 'ltr' );
-               $this->assertEquals( $derived->getHash(), 'zh|fallback|||scripts|||||' );
-       }
-
-       public function testModules() {
-               $derived = new DerivativeResourceLoaderContext( self::getContext() );
+       public function testChangeModules() {
+               $derived = new DerivativeResourceLoaderContext( self::makeContext() );
+               $this->assertSame( $derived->getModules(), [ 'test.default' ], 'inherit from parent' );
 
                $derived->setModules( [ 'test.override' ] );
-               $this->assertEquals( $derived->getModules(), [ 'test.override' ] );
-       }
-
-       public function testLanguage() {
-               $context = self::getContext();
-               $derived = new DerivativeResourceLoaderContext( $context );
-
-               $derived->setLanguage( 'nl' );
-               $this->assertEquals( $derived->getLanguage(), 'nl' );
+               $this->assertSame( $derived->getModules(), [ 'test.override' ] );
        }
 
-       public function testDirection() {
-               $derived = new DerivativeResourceLoaderContext( self::getContext() );
+       public function testChangeLanguageAndDirection() {
+               $derived = new DerivativeResourceLoaderContext( self::makeContext() );
+               $this->assertSame( $derived->getLanguage(), 'qqx', 'inherit from parent' );
 
                $derived->setLanguage( 'nl' );
-               $this->assertEquals( $derived->getDirection(), 'ltr' );
+               $this->assertSame( $derived->getLanguage(), 'nl' );
+               $this->assertSame( $derived->getDirection(), 'ltr' );
 
+               // Changing the language must clear cache of computed direction
                $derived->setLanguage( 'he' );
-               $this->assertEquals( $derived->getDirection(), 'rtl' );
+               $this->assertSame( $derived->getDirection(), 'rtl' );
+               $this->assertSame( $derived->getLanguage(), 'he' );
 
+               // Overriding the direction explicitly is allowed
                $derived->setDirection( 'ltr' );
-               $this->assertEquals( $derived->getDirection(), 'ltr' );
+               $this->assertSame( $derived->getDirection(), 'ltr' );
+               $this->assertSame( $derived->getLanguage(), 'he' );
        }
 
-       public function testSkin() {
-               $derived = new DerivativeResourceLoaderContext( self::getContext() );
+       public function testChangeSkin() {
+               $derived = new DerivativeResourceLoaderContext( self::makeContext() );
+               $this->assertSame( $derived->getSkin(), 'fallback', 'inherit from parent' );
 
-               $derived->setSkin( 'override' );
-               $this->assertEquals( $derived->getSkin(), 'override' );
+               $derived->setSkin( 'myskin' );
+               $this->assertSame( $derived->getSkin(), 'myskin' );
        }
 
-       public function testUser() {
-               $derived = new DerivativeResourceLoaderContext( self::getContext() );
+       public function testChangeUser() {
+               $derived = new DerivativeResourceLoaderContext( self::makeContext() );
+               $this->assertSame( $derived->getUser(), null, 'inherit from parent' );
 
-               $derived->setUser( 'Example' );
-               $this->assertEquals( $derived->getUser(), 'Example' );
+               $derived->setUser( 'MyUser' );
+               $this->assertSame( $derived->getUser(), 'MyUser' );
        }
 
-       public function testDebug() {
-               $derived = new DerivativeResourceLoaderContext( self::getContext() );
+       public function testChangeDebug() {
+               $derived = new DerivativeResourceLoaderContext( self::makeContext() );
+               $this->assertSame( $derived->getDebug(), false, 'inherit from parent' );
 
                $derived->setDebug( true );
-               $this->assertEquals( $derived->getDebug(), true );
+               $this->assertSame( $derived->getDebug(), true );
        }
 
-       public function testOnly() {
-               $derived = new DerivativeResourceLoaderContext( self::getContext() );
+       public function testChangeOnly() {
+               $derived = new DerivativeResourceLoaderContext( self::makeContext() );
+               $this->assertSame( $derived->getOnly(), 'scripts', 'inherit from parent' );
 
                $derived->setOnly( 'styles' );
-               $this->assertEquals( $derived->getOnly(), 'styles' );
+               $this->assertSame( $derived->getOnly(), 'styles' );
 
                $derived->setOnly( null );
-               $this->assertEquals( $derived->getOnly(), null );
+               $this->assertSame( $derived->getOnly(), null );
        }
 
-       public function testVersion() {
-               $derived = new DerivativeResourceLoaderContext( self::getContext() );
+       public function testChangeVersion() {
+               $derived = new DerivativeResourceLoaderContext( self::makeContext() );
+               $this->assertSame( $derived->getVersion(), null );
 
                $derived->setVersion( 'hw1' );
-               $this->assertEquals( $derived->getVersion(), 'hw1' );
+               $this->assertSame( $derived->getVersion(), 'hw1' );
        }
 
-       public function testRaw() {
-               $derived = new DerivativeResourceLoaderContext( self::getContext() );
+       public function testChangeRaw() {
+               $derived = new DerivativeResourceLoaderContext( self::makeContext() );
+               $this->assertSame( $derived->getRaw(), false, 'inherit from parent' );
 
                $derived->setRaw( true );
-               $this->assertEquals( $derived->getRaw(), true );
+               $this->assertSame( $derived->getRaw(), true );
        }
 
-       public function testGetHash() {
-               $derived = new DerivativeResourceLoaderContext( self::getContext() );
-
-               $this->assertEquals( $derived->getHash(), 'zh|fallback|||scripts|||||' );
+       public function testChangeHash() {
+               $derived = new DerivativeResourceLoaderContext( self::makeContext() );
+               $this->assertSame( $derived->getHash(), 'qqx|fallback|||scripts|||||', 'inherit' );
 
                $derived->setLanguage( 'nl' );
                $derived->setUser( 'Example' );
                // Assert that subclass is able to clear parent class "hash" member
-               $this->assertEquals( $derived->getHash(), 'nl|fallback||Example|scripts|||||' );
+               $this->assertSame( $derived->getHash(), 'nl|fallback||Example|scripts|||||' );
        }
 
-       public function testContentOverrides() {
-               $derived = new DerivativeResourceLoaderContext( self::getContext() );
-
-               $this->assertNull( $derived->getContentOverrideCallback() );
+       public function testChangeContentOverrides() {
+               $derived = new DerivativeResourceLoaderContext( self::makeContext() );
+               $this->assertNull( $derived->getContentOverrideCallback(), 'default' );
 
                $override = function ( Title $t ) {
                        return null;
                };
                $derived->setContentOverrideCallback( $override );
-               $this->assertSame( $override, $derived->getContentOverrideCallback() );
+               $this->assertSame( $override, $derived->getContentOverrideCallback(), 'changed' );
 
                $derived2 = new DerivativeResourceLoaderContext( $derived );
-               $this->assertSame( $override, $derived2->getContentOverrideCallback() );
+               $this->assertSame(
+                       $override,
+                       $derived2->getContentOverrideCallback(),
+                       'change via a second derivative layer'
+               );
        }
 
-       public function testAccessors() {
-               $context = self::getContext();
+       public function testImmutableAccessors() {
+               $context = self::makeContext();
                $derived = new DerivativeResourceLoaderContext( $context );
                $this->assertSame( $derived->getRequest(), $context->getRequest() );
                $this->assertSame( $derived->getResourceLoader(), $context->getResourceLoader() );
index 70bf39f..9afa232 100644 (file)
@@ -3,7 +3,7 @@
 use Wikimedia\TestingAccessWrapper;
 
 /**
- * @group Cache
+ * @group ResourceLoader
  * @covers MessageBlobStore
  */
 class MessageBlobStoreTest extends PHPUnit\Framework\TestCase {
@@ -13,64 +13,17 @@ class MessageBlobStoreTest extends PHPUnit\Framework\TestCase {
 
        protected function setUp() {
                parent::setUp();
-               // MediaWiki tests defaults $wgMainWANCache to CACHE_NONE.
-               // Use hash instead so that caching is observed
-               $this->wanCache = $this->getMockBuilder( WANObjectCache::class )
-                       ->setConstructorArgs( [ [
-                               'cache' => new HashBagOStuff(),
-                               'pool' => 'test',
-                               'relayer' => new EventRelayerNull( [] )
-                       ] ] )
-                       ->setMethods( [ 'makePurgeValue' ] )
-                       ->getMock();
-
-               $this->wanCache->expects( $this->any() )
-                       ->method( 'makePurgeValue' )
-                       ->will( $this->returnCallback( function ( $timestamp, $holdoff ) {
-                               // Disable holdoff as it messes with testing. Aside from a 0-second holdoff,
-                               // make sure that "time" passes between getMulti() check init and the set()
-                               // in recacheMessageBlob(). This especially matters for Windows clocks.
-                               $ts = (float)$timestamp - 0.0001;
-
-                               return WANObjectCache::PURGE_VAL_PREFIX . $ts . ':0';
-                       } ) );
-       }
-
-       protected function makeBlobStore( $methods = null, $rl = null ) {
-               $blobStore = $this->getMockBuilder( MessageBlobStore::class )
-                       ->setConstructorArgs( [ $rl ?? $this->createMock( ResourceLoader::class ) ] )
-                       ->setMethods( $methods )
-                       ->getMock();
-
-               $access = TestingAccessWrapper::newFromObject( $blobStore );
-               $access->wanCache = $this->wanCache;
-               return $blobStore;
-       }
-
-       protected function makeModule( array $messages ) {
-               $module = new ResourceLoaderTestModule( [ 'messages' => $messages ] );
-               $module->setName( 'test.blobstore' );
-               return $module;
-       }
-
-       /** @covers MessageBlobStore::setLogger */
-       public function testSetLogger() {
-               $blobStore = $this->makeBlobStore();
-               $this->assertSame( null, $blobStore->setLogger( new Psr\Log\NullLogger() ) );
+               // MediaWiki's test wrapper sets $wgMainWANCache to CACHE_NONE.
+               // Use HashBagOStuff here so that we can observe caching.
+               $this->wanCache = new WANObjectCache( [
+                       'cache' => new HashBagOStuff()
+               ] );
+
+               $this->clock = 1301655600.000;
+               $this->wanCache->setMockTime( $this->clock );
        }
 
-       /** @covers MessageBlobStore::getResourceLoader */
-       public function testGetResourceLoader() {
-               // Call protected method
-               $blobStore = TestingAccessWrapper::newFromObject( $this->makeBlobStore() );
-               $this->assertInstanceOf(
-                       ResourceLoader::class,
-                       $blobStore->getResourceLoader()
-               );
-       }
-
-       /** @covers MessageBlobStore::fetchMessage */
-       public function testFetchMessage() {
+       public function testBlobCreation() {
                $module = $this->makeModule( [ 'mainpage' ] );
                $rl = new ResourceLoader();
                $rl->register( $module->getName(), $module );
@@ -81,140 +34,164 @@ class MessageBlobStoreTest extends PHPUnit\Framework\TestCase {
                $this->assertEquals( '{"mainpage":"Main Page"}', $blob, 'Generated blob' );
        }
 
-       /** @covers MessageBlobStore::fetchMessage */
-       public function testFetchMessageFail() {
-               $module = $this->makeModule( [ 'i-dont-exist' ] );
+       public function testBlobCreation_empty() {
+               $module = $this->makeModule( [] );
                $rl = new ResourceLoader();
                $rl->register( $module->getName(), $module );
 
                $blobStore = $this->makeBlobStore( null, $rl );
                $blob = $blobStore->getBlob( $module, 'en' );
 
-               $this->assertEquals( '{"i-dont-exist":"\u29fci-dont-exist\u29fd"}', $blob, 'Generated blob' );
+               $this->assertEquals( '{}', $blob, 'Generated blob' );
        }
 
-       public function testGetBlob() {
-               $module = $this->makeModule( [ 'foo' ] );
+       public function testBlobCreation_unknownMessage() {
+               $module = $this->makeModule( [ 'i-dont-exist', 'mainpage', 'i-dont-exist2' ] );
                $rl = new ResourceLoader();
                $rl->register( $module->getName(), $module );
+               $blobStore = $this->makeBlobStore( null, $rl );
 
-               $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
-               $blobStore->expects( $this->once() )
-                       ->method( 'fetchMessage' )
-                       ->will( $this->returnValue( 'Example' ) );
-
+               // Generating a blob should continue without errors,
+               // with keys of unknown messages excluded from the blob.
                $blob = $blobStore->getBlob( $module, 'en' );
-
-               $this->assertEquals( '{"foo":"Example"}', $blob, 'Generated blob' );
+               $this->assertEquals( '{"mainpage":"Main Page"}', $blob, 'Generated blob' );
        }
 
-       public function testGetBlobCached() {
+       public function testMessageCachingAndPurging() {
                $module = $this->makeModule( [ 'example' ] );
                $rl = new ResourceLoader();
                $rl->register( $module->getName(), $module );
-
                $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
+
+               // Advance this new WANObjectCache instance to a normal state,
+               // by doing one "get" and letting its hold off period expire.
+               // Without this, the first real "get" would lazy-initialise the
+               // checkKey and thus reject the first "set".
+               $blobStore->getBlob( $module, 'en' );
+               $this->clock += 20;
+
+               // Arrange version 1 of a message
                $blobStore->expects( $this->once() )
                        ->method( 'fetchMessage' )
-                       ->will( $this->returnValue( 'First' ) );
+                       ->will( $this->returnValue( 'First version' ) );
 
-               $module = $this->makeModule( [ 'example' ] );
+               // Assert
                $blob = $blobStore->getBlob( $module, 'en' );
-               $this->assertEquals( '{"example":"First"}', $blob, 'Generated blob' );
+               $this->assertEquals( '{"example":"First version"}', $blob, 'Blob for v1' );
 
+               // Arrange version 2
                $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
-               $blobStore->expects( $this->never() )
+               $blobStore->expects( $this->once() )
                        ->method( 'fetchMessage' )
-                       ->will( $this->returnValue( 'Second' ) );
+                       ->will( $this->returnValue( 'Second version' ) );
+               $this->clock += 20;
 
-               $module = $this->makeModule( [ 'example' ] );
+               // Assert
+               // We do not validate whether a cached message is up-to-date.
+               // Instead, changes to messages will send us a purge.
+               // When cache is not purged or expired, it must be used.
                $blob = $blobStore->getBlob( $module, 'en' );
-               $this->assertEquals( '{"example":"First"}', $blob, 'Cache hit' );
+               $this->assertEquals( '{"example":"First version"}', $blob, 'Reuse cached v1 blob' );
+
+               // Purge cache
+               $blobStore->updateMessage( 'example' );
+               $this->clock += 20;
+
+               // Assert
+               $blob = $blobStore->getBlob( $module, 'en' );
+               $this->assertEquals( '{"example":"Second version"}', $blob, 'Updated blob for v2' );
        }
 
-       public function testUpdateMessage() {
+       public function testPurgeEverything() {
                $module = $this->makeModule( [ 'example' ] );
                $rl = new ResourceLoader();
                $rl->register( $module->getName(), $module );
                $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
-               $blobStore->expects( $this->once() )
+               // Advance this new WANObjectCache instance to a normal state.
+               $blobStore->getBlob( $module, 'en' );
+               $this->clock += 20;
+
+               // Arrange version 1 and 2
+               $blobStore->expects( $this->exactly( 2 ) )
                        ->method( 'fetchMessage' )
-                       ->will( $this->returnValue( 'First' ) );
+                       ->will( $this->onConsecutiveCalls( 'First', 'Second' ) );
 
+               // Assert
                $blob = $blobStore->getBlob( $module, 'en' );
-               $this->assertEquals( '{"example":"First"}', $blob, 'Generated blob' );
+               $this->assertEquals( '{"example":"First"}', $blob, 'Blob for v1' );
 
-               $blobStore->updateMessage( 'example' );
+               $this->clock += 20;
 
-               $module = $this->makeModule( [ 'example' ] );
-               $rl = new ResourceLoader();
-               $rl->register( $module->getName(), $module );
-               $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
-               $blobStore->expects( $this->once() )
-                       ->method( 'fetchMessage' )
-                       ->will( $this->returnValue( 'Second' ) );
+               // Assert
+               $blob = $blobStore->getBlob( $module, 'en' );
+               $this->assertEquals( '{"example":"First"}', $blob, 'Blob for v1 again' );
 
+               // Purge everything
+               $blobStore->clear();
+               $this->clock += 20;
+
+               // Assert
                $blob = $blobStore->getBlob( $module, 'en' );
-               $this->assertEquals( '{"example":"Second"}', $blob, 'Updated blob' );
+               $this->assertEquals( '{"example":"Second"}', $blob, 'Blob for v2' );
        }
 
-       public function testValidation() {
+       public function testValidateAgainstModuleRegistry() {
+               // Arrange version 1 of a module
                $module = $this->makeModule( [ 'foo' ] );
                $rl = new ResourceLoader();
                $rl->register( $module->getName(), $module );
-
                $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
                $blobStore->expects( $this->once() )
                        ->method( 'fetchMessage' )
                        ->will( $this->returnValueMap( [
+                               // message key, language code, message value
                                [ 'foo', 'en', 'Hello' ],
                        ] ) );
 
+               // Assert
                $blob = $blobStore->getBlob( $module, 'en' );
-               $this->assertEquals( '{"foo":"Hello"}', $blob, 'Generated blob' );
+               $this->assertEquals( '{"foo":"Hello"}', $blob, 'Blob for v1' );
 
-               // Now, imagine a change to the module is deployed. The module now contains
-               // message 'foo' and 'bar'. While updateMessage() was not called (since no
-               // message values were changed) it should detect the change in list of
-               // message keys.
+               // Arrange version 2 of module
+               // While message values may be out of date, the set of messages returned
+               // must always match the set of message keys required by the module.
+               // We do not receive purges for this because no messages were changed.
                $module = $this->makeModule( [ 'foo', 'bar' ] );
                $rl = new ResourceLoader();
                $rl->register( $module->getName(), $module );
-
                $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
                $blobStore->expects( $this->exactly( 2 ) )
                        ->method( 'fetchMessage' )
                        ->will( $this->returnValueMap( [
+                               // message key, language code, message value
                                [ 'foo', 'en', 'Hello' ],
                                [ 'bar', 'en', 'World' ],
                        ] ) );
 
+               // Assert
                $blob = $blobStore->getBlob( $module, 'en' );
-               $this->assertEquals( '{"foo":"Hello","bar":"World"}', $blob, 'Updated blob' );
+               $this->assertEquals( '{"foo":"Hello","bar":"World"}', $blob, 'Blob for v2' );
        }
 
-       public function testClear() {
-               $module = $this->makeModule( [ 'example' ] );
-               $rl = new ResourceLoader();
-               $rl->register( $module->getName(), $module );
-               $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
-               $blobStore->expects( $this->exactly( 2 ) )
-                       ->method( 'fetchMessage' )
-                       ->will( $this->onConsecutiveCalls( 'First', 'Second' ) );
-
-               $now = microtime( true );
-               $this->wanCache->setMockTime( $now );
-
-               $blob = $blobStore->getBlob( $module, 'en' );
-               $this->assertEquals( '{"example":"First"}', $blob, 'Generated blob' );
+       public function testSetLoggedIsVoid() {
+               $blobStore = $this->makeBlobStore();
+               $this->assertSame( null, $blobStore->setLogger( new Psr\Log\NullLogger() ) );
+       }
 
-               $blob = $blobStore->getBlob( $module, 'en' );
-               $this->assertEquals( '{"example":"First"}', $blob, 'Cache-hit' );
+       private function makeBlobStore( $methods = null, $rl = null ) {
+               $blobStore = $this->getMockBuilder( MessageBlobStore::class )
+                       ->setConstructorArgs( [ $rl ?? $this->createMock( ResourceLoader::class ) ] )
+                       ->setMethods( $methods )
+                       ->getMock();
 
-               $now += 1;
-               $blobStore->clear();
+               $access = TestingAccessWrapper::newFromObject( $blobStore );
+               $access->wanCache = $this->wanCache;
+               return $blobStore;
+       }
 
-               $blob = $blobStore->getBlob( $module, 'en' );
-               $this->assertEquals( '{"example":"Second"}', $blob, 'Updated blob' );
+       private function makeModule( array $messages ) {
+               $module = new ResourceLoaderTestModule( [ 'messages' => $messages ] );
+               $module->setName( 'test.blobstore' );
+               return $module;
        }
 }
index 50b9421..206160c 100644 (file)
@@ -4,110 +4,12 @@ use Wikimedia\TestingAccessWrapper;
 
 /**
  * @group ResourceLoader
+ * @covers ResourceLoaderClientHtml
  */
 class ResourceLoaderClientHtmlTest extends PHPUnit\Framework\TestCase {
 
        use MediaWikiCoversValidator;
 
-       protected static function expandVariables( $text ) {
-               return strtr( $text, [
-                       '{blankVer}' => ResourceLoaderTestCase::BLANK_VERSION
-               ] );
-       }
-
-       protected static function makeContext( $extraQuery = [] ) {
-               $conf = new HashConfig( [
-                       'ResourceLoaderSources' => [],
-                       'ResourceModuleSkinStyles' => [],
-                       'ResourceModules' => [],
-                       'EnableJavaScriptTest' => false,
-                       'LoadScript' => '/w/load.php',
-               ] );
-               return new ResourceLoaderContext(
-                       new ResourceLoader( $conf ),
-                       new FauxRequest( array_merge( [
-                               'lang' => 'nl',
-                               'skin' => 'fallback',
-                               'user' => 'Example',
-                               'target' => 'phpunit',
-                       ], $extraQuery ) )
-               );
-       }
-
-       protected static function makeModule( array $options = [] ) {
-               return new ResourceLoaderTestModule( $options );
-       }
-
-       protected static function makeSampleModules() {
-               $modules = [
-                       'test' => [],
-                       'test.private' => [ 'group' => 'private' ],
-                       'test.shouldembed.empty' => [ 'shouldEmbed' => true, 'isKnownEmpty' => true ],
-                       'test.shouldembed' => [ 'shouldEmbed' => true ],
-                       'test.user' => [ 'group' => 'user' ],
-
-                       'test.styles.pure' => [ 'type' => ResourceLoaderModule::LOAD_STYLES ],
-                       'test.styles.mixed' => [],
-                       'test.styles.noscript' => [
-                               'type' => ResourceLoaderModule::LOAD_STYLES,
-                               'group' => 'noscript',
-                       ],
-                       'test.styles.user' => [
-                               'type' => ResourceLoaderModule::LOAD_STYLES,
-                               'group' => 'user',
-                       ],
-                       'test.styles.user.empty' => [
-                               'type' => ResourceLoaderModule::LOAD_STYLES,
-                               'group' => 'user',
-                               'isKnownEmpty' => true,
-                       ],
-                       'test.styles.private' => [
-                               'type' => ResourceLoaderModule::LOAD_STYLES,
-                               'group' => 'private',
-                               'styles' => '.private{}',
-                       ],
-                       'test.styles.shouldembed' => [
-                               'type' => ResourceLoaderModule::LOAD_STYLES,
-                               'shouldEmbed' => true,
-                               'styles' => '.shouldembed{}',
-                       ],
-                       'test.styles.deprecated' => [
-                               'type' => ResourceLoaderModule::LOAD_STYLES,
-                               'deprecated' => 'Deprecation message.',
-                       ],
-
-                       'test.scripts' => [],
-                       'test.scripts.user' => [ 'group' => 'user' ],
-                       'test.scripts.user.empty' => [ 'group' => 'user', 'isKnownEmpty' => true ],
-                       'test.scripts.raw' => [ 'isRaw' => true ],
-                       'test.scripts.shouldembed' => [ 'shouldEmbed' => true ],
-
-                       'test.ordering.a' => [ 'shouldEmbed' => false ],
-                       'test.ordering.b' => [ 'shouldEmbed' => false ],
-                       'test.ordering.c' => [ 'shouldEmbed' => true, 'styles' => '.orderingC{}' ],
-                       'test.ordering.d' => [ 'shouldEmbed' => true, 'styles' => '.orderingD{}' ],
-                       'test.ordering.e' => [ 'shouldEmbed' => false ],
-               ];
-               return array_map( function ( $options ) {
-                       return self::makeModule( $options );
-               }, $modules );
-       }
-
-       /**
-        * @covers ResourceLoaderClientHtml::getDocumentAttributes
-        */
-       public function testGetDocumentAttributes() {
-               $client = new ResourceLoaderClientHtml( self::makeContext() );
-               $this->assertInternalType( 'array', $client->getDocumentAttributes() );
-       }
-
-       /**
-        * @covers ResourceLoaderClientHtml::__construct
-        * @covers ResourceLoaderClientHtml::setModules
-        * @covers ResourceLoaderClientHtml::setModuleStyles
-        * @covers ResourceLoaderClientHtml::getData
-        * @covers ResourceLoaderClientHtml::getContext
-        */
        public function testGetData() {
                $context = self::makeContext();
                $context->getResourceLoader()->register( self::makeSampleModules() );
@@ -133,10 +35,22 @@ class ResourceLoaderClientHtmlTest extends PHPUnit\Framework\TestCase {
 
                $expected = [
                        'states' => [
+                               // The below are NOT queued for loading via `mw.loader.load(Array)`.
+                               // Instead we tell the client to set their state to "loading" so that
+                               // if they are needed as dependencies, the client will not try to
+                               // load them on-demand, because the server is taking care of them already.
+                               // Either:
+                               // - Embedded as inline scripts in the HTML (e.g. user-private code, and
+                               //   previews). Once that script tag is reached, the state is "loaded".
+                               // - Loaded directly from the HTML with a dedicated HTTP request (e.g.
+                               //   user scripts, which vary by a 'user' and 'version' parameter that
+                               //   the static user-agnostic startup module won't have).
                                'test.private' => 'loading',
-                               'test.shouldembed.empty' => 'ready',
                                'test.shouldembed' => 'loading',
                                'test.user' => 'loading',
+                               // The below are known to the server to be empty scripts, or to be
+                               // synchronously loaded stylesheets. These start in the "ready" state.
+                               'test.shouldembed.empty' => 'ready',
                                'test.styles.pure' => 'ready',
                                'test.styles.user.empty' => 'ready',
                                'test.styles.private' => 'ready',
@@ -171,13 +85,6 @@ Deprecation message.' ]
                $this->assertEquals( $expected, $access->getData() );
        }
 
-       /**
-        * @covers ResourceLoaderClientHtml::setConfig
-        * @covers ResourceLoaderClientHtml::setExemptStates
-        * @covers ResourceLoaderClientHtml::getHeadHtml
-        * @covers ResourceLoaderClientHtml::getLoad
-        * @covers ResourceLoader::makeLoaderStateScript
-        */
        public function testGetHeadHtml() {
                $context = self::makeContext();
                $context->getResourceLoader()->register( self::makeSampleModules() );
@@ -200,12 +107,14 @@ Deprecation message.' ]
                ] );
 
                // phpcs:disable Generic.Files.LineLength
-               $expected = '<script>document.documentElement.className = document.documentElement.className.replace( /(^|\s)client-nojs(\s|$)/, "$1client-js$2" );</script>' . "\n"
-                       . '<script>(window.RLQ=window.RLQ||[]).push(function(){'
-                       . 'mw.config.set({"key":"value"});'
-                       . 'mw.loader.state({"test.exempt":"ready","test.private":"loading","test.styles.pure":"ready","test.styles.private":"ready","test.styles.deprecated":"ready"});'
+               $expected = '<script>'
+                       . 'document.documentElement.className=document.documentElement.className.replace(/(^|\s)client-nojs(\s|$)/,"$1client-js$2");'
+                       . 'RLCONF={"key":"value"};'
+                       . 'RLSTATE={"test.exempt":"ready","test.private":"loading","test.styles.pure":"ready","test.styles.private":"ready","test.styles.deprecated":"ready"};'
+                       . 'RLPAGEMODULES=["test"];'
+                       . '</script>' . "\n"
+                       . '<script>(RLQ=window.RLQ||[]).push(function(){'
                        . 'mw.loader.implement("test.private@{blankVer}",null,{"css":[]});'
-                       . 'RLPAGEMODULES=["test"];mw.loader.load(RLPAGEMODULES);'
                        . '});</script>' . "\n"
                        . '<link rel="stylesheet" href="/w/load.php?lang=nl&amp;modules=test.styles.deprecated%2Cpure&amp;only=styles&amp;skin=fallback"/>' . "\n"
                        . '<style>.private{}</style>' . "\n"
@@ -213,13 +122,11 @@ Deprecation message.' ]
                // phpcs:enable
                $expected = self::expandVariables( $expected );
 
-               $this->assertEquals( $expected, $client->getHeadHtml() );
+               $this->assertSame( $expected, (string)$client->getHeadHtml() );
        }
 
        /**
         * Confirm that 'target' is passed down to the startup module's load url.
-        *
-        * @covers ResourceLoaderClientHtml::getHeadHtml
         */
        public function testGetHeadHtmlWithTarget() {
                $client = new ResourceLoaderClientHtml(
@@ -228,17 +135,15 @@ Deprecation message.' ]
                );
 
                // phpcs:disable Generic.Files.LineLength
-               $expected = '<script>document.documentElement.className = document.documentElement.className.replace( /(^|\s)client-nojs(\s|$)/, "$1client-js$2" );</script>' . "\n"
+               $expected = '<script>document.documentElement.className=document.documentElement.className.replace(/(^|\s)client-nojs(\s|$)/,"$1client-js$2");</script>' . "\n"
                        . '<script async="" src="/w/load.php?lang=nl&amp;modules=startup&amp;only=scripts&amp;skin=fallback&amp;target=example"></script>';
                // phpcs:enable
 
-               $this->assertEquals( $expected, $client->getHeadHtml() );
+               $this->assertSame( $expected, (string)$client->getHeadHtml() );
        }
 
        /**
         * Confirm that 'safemode' is passed down to startup.
-        *
-        * @covers ResourceLoaderClientHtml::getHeadHtml
         */
        public function testGetHeadHtmlWithSafemode() {
                $client = new ResourceLoaderClientHtml(
@@ -247,17 +152,15 @@ Deprecation message.' ]
                );
 
                // phpcs:disable Generic.Files.LineLength
-               $expected = '<script>document.documentElement.className = document.documentElement.className.replace( /(^|\s)client-nojs(\s|$)/, "$1client-js$2" );</script>' . "\n"
+               $expected = '<script>document.documentElement.className=document.documentElement.className.replace(/(^|\s)client-nojs(\s|$)/,"$1client-js$2");</script>' . "\n"
                        . '<script async="" src="/w/load.php?lang=nl&amp;modules=startup&amp;only=scripts&amp;safemode=1&amp;skin=fallback"></script>';
                // phpcs:enable
 
-               $this->assertEquals( $expected, $client->getHeadHtml() );
+               $this->assertSame( $expected, (string)$client->getHeadHtml() );
        }
 
        /**
         * Confirm that a null 'target' is the same as no target.
-        *
-        * @covers ResourceLoaderClientHtml::getHeadHtml
         */
        public function testGetHeadHtmlWithNullTarget() {
                $client = new ResourceLoaderClientHtml(
@@ -266,17 +169,13 @@ Deprecation message.' ]
                );
 
                // phpcs:disable Generic.Files.LineLength
-               $expected = '<script>document.documentElement.className = document.documentElement.className.replace( /(^|\s)client-nojs(\s|$)/, "$1client-js$2" );</script>' . "\n"
+               $expected = '<script>document.documentElement.className=document.documentElement.className.replace(/(^|\s)client-nojs(\s|$)/,"$1client-js$2");</script>' . "\n"
                        . '<script async="" src="/w/load.php?lang=nl&amp;modules=startup&amp;only=scripts&amp;skin=fallback"></script>';
                // phpcs:enable
 
-               $this->assertEquals( $expected, $client->getHeadHtml() );
+               $this->assertSame( $expected, (string)$client->getHeadHtml() );
        }
 
-       /**
-        * @covers ResourceLoaderClientHtml::getBodyHtml
-        * @covers ResourceLoaderClientHtml::getLoad
-        */
        public function testGetBodyHtml() {
                $context = self::makeContext();
                $context->getResourceLoader()->register( self::makeSampleModules() );
@@ -291,12 +190,12 @@ Deprecation message.' ]
                        'test.styles.deprecated',
                ] );
                // phpcs:disable Generic.Files.LineLength
-               $expected = '<script>(window.RLQ=window.RLQ||[]).push(function(){'
+               $expected = '<script>(RLQ=window.RLQ||[]).push(function(){'
                        . 'mw.log.warn("This page is using the deprecated ResourceLoader module \"test.styles.deprecated\".\nDeprecation message.");'
                        . '});</script>';
                // phpcs:enable
 
-               $this->assertEquals( $expected, $client->getBodyHtml() );
+               $this->assertSame( $expected, (string)$client->getBodyHtml() );
        }
 
        public static function provideMakeLoad() {
@@ -321,7 +220,7 @@ Deprecation message.' ]
                                'modules' => [ 'test.private' ],
                                'only' => ResourceLoaderModule::TYPE_COMBINED,
                                'extra' => [],
-                               'output' => '<script>(window.RLQ=window.RLQ||[]).push(function(){mw.loader.implement("test.private@{blankVer}",null,{"css":[]});});</script>',
+                               'output' => '<script>(RLQ=window.RLQ||[]).push(function(){mw.loader.implement("test.private@{blankVer}",null,{"css":[]});});</script>',
                        ],
                        [
                                'context' => [],
@@ -343,14 +242,14 @@ Deprecation message.' ]
                                'modules' => [ 'test.scripts.user' ],
                                'only' => ResourceLoaderModule::TYPE_SCRIPTS,
                                'extra' => [],
-                               'output' => '<script>(window.RLQ=window.RLQ||[]).push(function(){mw.loader.load("/w/load.php?lang=nl\u0026modules=test.scripts.user\u0026only=scripts\u0026skin=fallback\u0026user=Example\u0026version=0a56zyi");});</script>',
+                               'output' => '<script>(RLQ=window.RLQ||[]).push(function(){mw.loader.load("/w/load.php?lang=nl\u0026modules=test.scripts.user\u0026only=scripts\u0026skin=fallback\u0026user=Example\u0026version=0a56zyi");});</script>',
                        ],
                        [
                                'context' => [],
                                'modules' => [ 'test.user' ],
                                'only' => ResourceLoaderModule::TYPE_COMBINED,
                                'extra' => [],
-                               'output' => '<script>(window.RLQ=window.RLQ||[]).push(function(){mw.loader.load("/w/load.php?lang=nl\u0026modules=test.user\u0026skin=fallback\u0026user=Example\u0026version=0a56zyi");});</script>',
+                               'output' => '<script>(RLQ=window.RLQ||[]).push(function(){mw.loader.load("/w/load.php?lang=nl\u0026modules=test.user\u0026skin=fallback\u0026user=Example\u0026version=0a56zyi");});</script>',
                        ],
                        [
                                'context' => [ 'debug' => 'true' ],
@@ -379,7 +278,7 @@ Deprecation message.' ]
                                'modules' => [ 'test.shouldembed' ],
                                'only' => ResourceLoaderModule::TYPE_COMBINED,
                                'extra' => [],
-                               'output' => '<script>(window.RLQ=window.RLQ||[]).push(function(){mw.loader.implement("test.shouldembed@09p30q0",null,{"css":[]});});</script>',
+                               'output' => '<script>(RLQ=window.RLQ||[]).push(function(){mw.loader.implement("test.shouldembed@09p30q0",null,{"css":[]});});</script>',
                        ],
                        [
                                'context' => [],
@@ -393,14 +292,14 @@ Deprecation message.' ]
                                'modules' => [ 'test.scripts.shouldembed' ],
                                'only' => ResourceLoaderModule::TYPE_SCRIPTS,
                                'extra' => [],
-                               'output' => '<script>(window.RLQ=window.RLQ||[]).push(function(){mw.loader.state({"test.scripts.shouldembed":"ready"});});</script>',
+                               'output' => '<script>(RLQ=window.RLQ||[]).push(function(){mw.loader.state({"test.scripts.shouldembed":"ready"});});</script>',
                        ],
                        [
                                'context' => [],
                                'modules' => [ 'test', 'test.shouldembed' ],
                                'only' => ResourceLoaderModule::TYPE_COMBINED,
                                'extra' => [],
-                               'output' => '<script>(window.RLQ=window.RLQ||[]).push(function(){mw.loader.load("/w/load.php?lang=nl\u0026modules=test\u0026skin=fallback");mw.loader.implement("test.shouldembed@09p30q0",null,{"css":[]});});</script>',
+                               'output' => '<script>(RLQ=window.RLQ||[]).push(function(){mw.loader.load("/w/load.php?lang=nl\u0026modules=test\u0026skin=fallback");mw.loader.implement("test.shouldembed@09p30q0",null,{"css":[]});});</script>',
                        ],
                        [
                                'context' => [],
@@ -427,15 +326,9 @@ Deprecation message.' ]
 
        /**
         * @dataProvider provideMakeLoad
-        * @covers ResourceLoaderClientHtml::makeLoad
-        * @covers ResourceLoaderClientHtml::makeContext
-        * @covers ResourceLoader::makeModuleResponse
+        * @covers ResourceLoaderClientHtml
         * @covers ResourceLoaderModule::getModuleContent
-        * @covers ResourceLoader::getCombinedVersion
-        * @covers ResourceLoader::createLoaderURL
-        * @covers ResourceLoader::createLoaderQuery
-        * @covers ResourceLoader::makeLoaderQuery
-        * @covers ResourceLoader::makeInlineScript
+        * @covers ResourceLoader
         */
        public function testMakeLoad(
                array $contextQuery,
@@ -448,6 +341,94 @@ Deprecation message.' ]
                $context->getResourceLoader()->register( self::makeSampleModules() );
                $actual = ResourceLoaderClientHtml::makeLoad( $context, $modules, $type, $extraQuery, false );
                $expected = self::expandVariables( $expected );
-               $this->assertEquals( $expected, (string)$actual );
+               $this->assertSame( $expected, (string)$actual );
+       }
+
+       public function testGetDocumentAttributes() {
+               $client = new ResourceLoaderClientHtml( self::makeContext() );
+               $this->assertInternalType( 'array', $client->getDocumentAttributes() );
+       }
+
+       private static function expandVariables( $text ) {
+               return strtr( $text, [
+                       '{blankVer}' => ResourceLoaderTestCase::BLANK_VERSION
+               ] );
+       }
+
+       private static function makeContext( $extraQuery = [] ) {
+               $conf = new HashConfig( [
+                       'ResourceModuleSkinStyles' => [],
+                       'ResourceModules' => [],
+                       'EnableJavaScriptTest' => false,
+                       'LoadScript' => '/w/load.php',
+               ] );
+               return new ResourceLoaderContext(
+                       new ResourceLoader( $conf ),
+                       new FauxRequest( array_merge( [
+                               'lang' => 'nl',
+                               'skin' => 'fallback',
+                               'user' => 'Example',
+                               'target' => 'phpunit',
+                       ], $extraQuery ) )
+               );
+       }
+
+       private static function makeModule( array $options = [] ) {
+               return new ResourceLoaderTestModule( $options );
+       }
+
+       private static function makeSampleModules() {
+               $modules = [
+                       'test' => [],
+                       'test.private' => [ 'group' => 'private' ],
+                       'test.shouldembed.empty' => [ 'shouldEmbed' => true, 'isKnownEmpty' => true ],
+                       'test.shouldembed' => [ 'shouldEmbed' => true ],
+                       'test.user' => [ 'group' => 'user' ],
+
+                       'test.styles.pure' => [ 'type' => ResourceLoaderModule::LOAD_STYLES ],
+                       'test.styles.mixed' => [],
+                       'test.styles.noscript' => [
+                               'type' => ResourceLoaderModule::LOAD_STYLES,
+                               'group' => 'noscript',
+                       ],
+                       'test.styles.user' => [
+                               'type' => ResourceLoaderModule::LOAD_STYLES,
+                               'group' => 'user',
+                       ],
+                       'test.styles.user.empty' => [
+                               'type' => ResourceLoaderModule::LOAD_STYLES,
+                               'group' => 'user',
+                               'isKnownEmpty' => true,
+                       ],
+                       'test.styles.private' => [
+                               'type' => ResourceLoaderModule::LOAD_STYLES,
+                               'group' => 'private',
+                               'styles' => '.private{}',
+                       ],
+                       'test.styles.shouldembed' => [
+                               'type' => ResourceLoaderModule::LOAD_STYLES,
+                               'shouldEmbed' => true,
+                               'styles' => '.shouldembed{}',
+                       ],
+                       'test.styles.deprecated' => [
+                               'type' => ResourceLoaderModule::LOAD_STYLES,
+                               'deprecated' => 'Deprecation message.',
+                       ],
+
+                       'test.scripts' => [],
+                       'test.scripts.user' => [ 'group' => 'user' ],
+                       'test.scripts.user.empty' => [ 'group' => 'user', 'isKnownEmpty' => true ],
+                       'test.scripts.raw' => [ 'isRaw' => true ],
+                       'test.scripts.shouldembed' => [ 'shouldEmbed' => true ],
+
+                       'test.ordering.a' => [ 'shouldEmbed' => false ],
+                       'test.ordering.b' => [ 'shouldEmbed' => false ],
+                       'test.ordering.c' => [ 'shouldEmbed' => true, 'styles' => '.orderingC{}' ],
+                       'test.ordering.d' => [ 'shouldEmbed' => true, 'styles' => '.orderingD{}' ],
+                       'test.ordering.e' => [ 'shouldEmbed' => false ],
+               ];
+               return array_map( function ( $options ) {
+                       return self::makeModule( $options );
+               }, $modules );
        }
 }
index 1b7e0fe..60cd4a8 100644 (file)
@@ -2,10 +2,9 @@
 
 /**
  * See also:
- * - ResourceLoaderTest::testExpandModuleNames
  * - ResourceLoaderImageModuleTest::testContext
  *
- * @group Cache
+ * @group ResourceLoader
  * @covers ResourceLoaderContext
  */
 class ResourceLoaderContextTest extends PHPUnit\Framework\TestCase {
@@ -15,8 +14,6 @@ class ResourceLoaderContextTest extends PHPUnit\Framework\TestCase {
        protected static function getResourceLoader() {
                return new EmptyResourceLoader( new HashConfig( [
                        'ResourceLoaderDebug' => false,
-                       'DefaultSkin' => 'fallback',
-                       'LanguageCode' => 'nl',
                        'LoadScript' => '/w/load.php',
                ] ) );
        }
@@ -26,7 +23,7 @@ class ResourceLoaderContextTest extends PHPUnit\Framework\TestCase {
 
                // Request parameters
                $this->assertEquals( [], $ctx->getModules() );
-               $this->assertEquals( 'nl', $ctx->getLanguage() );
+               $this->assertEquals( 'qqx', $ctx->getLanguage() );
                $this->assertEquals( false, $ctx->getDebug() );
                $this->assertEquals( null, $ctx->getOnly() );
                $this->assertEquals( 'fallback', $ctx->getSkin() );
@@ -35,7 +32,7 @@ class ResourceLoaderContextTest extends PHPUnit\Framework\TestCase {
 
                // Misc
                $this->assertEquals( 'ltr', $ctx->getDirection() );
-               $this->assertEquals( 'nl|fallback||||||||', $ctx->getHash() );
+               $this->assertEquals( 'qqx|fallback||||||||', $ctx->getHash() );
                $this->assertInstanceOf( User::class, $ctx->getUserObj() );
        }
 
index 35c3ef6..b0512fa 100644 (file)
@@ -129,6 +129,7 @@ class ResourceLoaderImageTestable extends ResourceLoaderImage {
        public function massageSvgPathdata( $svg ) {
                return parent::massageSvgPathdata( $svg );
        }
+
        // Stub, since we don't know if we even have a SVG handler, much less what exactly it'll output
        public function rasterize( $svg ) {
                return 'RASTERIZESTUB';
index ea220f1..30e9f30 100644 (file)
@@ -56,9 +56,9 @@ class ResourceLoaderOOUIImageModuleTest extends ResourceLoaderTestCase {
                        'Generated styles use the default image (embed)'
                );
                $this->assertRegExp(
-                       '/vector/',
+                       '/fallback/',
                        $styles['all'],
-                       'Generated styles use the default image (link)'
+                       'Generated styles use the default skin (link)'
                );
        }
 
index 231979d..23b0cb9 100644 (file)
@@ -7,8 +7,6 @@ use Wikimedia\TestingAccessWrapper;
  */
 class ResourceLoaderSkinModuleTest extends MediaWikiTestCase {
 
-       use MediaWikiCoversValidator;
-
        public static function provideGetStyles() {
                // phpcs:disable Generic.Files.LineLength
                return [
index 2ee85b5..d4b5ed6 100644 (file)
@@ -459,13 +459,12 @@ mw.loader.register( [
         * @covers ResourceLoader::makeLoaderRegisterScript
         */
        public function testGetModuleRegistrations( $case ) {
-               if ( isset( $case['sources'] ) ) {
-                       $this->setMwGlobals( 'wgResourceLoaderSources', $case['sources'] );
-               }
-
                $extraQuery = $case['extraQuery'] ?? [];
                $context = $this->getResourceLoaderContext( $extraQuery );
                $rl = $context->getResourceLoader();
+               if ( isset( $case['sources'] ) ) {
+                       $rl->addSource( $case['sources'] );
+               }
                $rl->register( $case['modules'] );
                $module = new ResourceLoaderStartUpModule();
                $out = ltrim( $case['out'], "\n" );
index 5941c6e..85a47de 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 
 use Wikimedia\TestingAccessWrapper;
+use MediaWiki\MediaWikiServices;
 
 class ResourceLoaderTest extends ResourceLoaderTestCase {
 
@@ -14,25 +15,23 @@ class ResourceLoaderTest extends ResourceLoaderTestCase {
 
        /**
         * Ensure the ResourceLoaderRegisterModules hook is called.
-        *
-        * @covers ResourceLoader::__construct
+        * @coversNothing
         */
-       public function testConstructRegistrationHook() {
-               $resourceLoaderRegisterModulesHook = false;
+       public function testServiceWiring() {
+               $this->overrideMwServices();
 
+               $ranHook = 0;
                $this->setMwGlobals( 'wgHooks', [
                        'ResourceLoaderRegisterModules' => [
-                               function ( &$resourceLoader ) use ( &$resourceLoaderRegisterModulesHook ) {
-                                       $resourceLoaderRegisterModulesHook = true;
+                               function ( &$resourceLoader ) use ( &$ranHook ) {
+                                       $ranHook++;
                                }
                        ]
                ] );
 
-               $unused = new ResourceLoader();
-               $this->assertTrue(
-                       $resourceLoaderRegisterModulesHook,
-                       'Hook ResourceLoaderRegisterModules called'
-               );
+               MediaWikiServices::getInstance()->getResourceLoader();
+
+               $this->assertSame( 1, $ranHook, 'Hook was called' );
        }
 
        /**
@@ -288,12 +287,12 @@ class ResourceLoaderTest extends ResourceLoaderTestCase {
 
        /**
         * @dataProvider providePackedModules
-        * @covers ResourceLoaderContext::expandModuleNames
+        * @covers ResourceLoader::expandModuleNames
         */
        public function testExpandModuleNames( $desc, $modules, $packed, $unpacked = null ) {
                $this->assertEquals(
                        $unpacked ?: $modules,
-                       ResourceLoaderContext::expandModuleNames( $packed ),
+                       ResourceLoader::expandModuleNames( $packed ),
                        $desc
                );
        }
@@ -624,7 +623,6 @@ END
         * @covers ResourceLoader::getLoadScript
         */
        public function testGetLoadScript() {
-               $this->setMwGlobals( 'wgResourceLoaderSources', [] );
                $rl = new ResourceLoader();
                $sources = self::fakeSources();
                $rl->addSource( $sources );
index ad8fa78..c1bdebe 100644 (file)
@@ -451,6 +451,7 @@ class ResourceLoaderWikiModuleTest extends ResourceLoaderTestCase {
 
 class TestResourceLoaderWikiModule extends ResourceLoaderWikiModule {
        public static $returnFetchTitleInfo = null;
+
        protected static function fetchTitleInfo( IDatabase $db, array $pages, $fname = null ) {
                $ret = self::$returnFetchTitleInfo;
                self::$returnFetchTitleInfo = null;
index d86e63d..0c6520e 100644 (file)
@@ -271,7 +271,7 @@ class SearchEngineTest extends MediaWikiLangTestCase {
         */
        public function testSearchIndexFields() {
                /**
-                * @var $mockEngine SearchEngine
+                * @var SearchEngine $mockEngine
                 */
                $mockEngine = $this->getMockBuilder( SearchEngine::class )
                        ->setMethods( [ 'makeSearchFieldMapping' ] )->getMock();
index 052c016..6ff6a97 100644 (file)
@@ -134,7 +134,7 @@ class SessionProviderTest extends MediaWikiTestCase {
                        $this->fail( 'Expected exception not thrown' );
                } catch ( \BadMethodCallException $ex ) {
                        $this->assertSame(
-                               'MediaWiki\\Session\\SessionProvider::preventSessionsForUser must be implmented ' .
+                               'MediaWiki\\Session\\SessionProvider::preventSessionsForUser must be implemented ' .
                                        'when canChangeUser() is false',
                                $ex->getMessage()
                        );
index 3c05583..5fb3ac0 100644 (file)
@@ -10,8 +10,6 @@ use Wikimedia\TestingAccessWrapper;
  */
 class ShellTest extends MediaWikiTestCase {
 
-       use MediaWikiCoversValidator;
-
        public function testIsDisabled() {
                $this->assertInternalType( 'bool', Shell::isDisabled() ); // sanity
        }
index 0fdcf6d..f04d35c 100644 (file)
@@ -37,7 +37,7 @@ class CachingSiteStoreTest extends MediaWikiTestCase {
 
                $store = new CachingSiteStore(
                        $this->getHashSiteStore( $testSites ),
-                       wfGetMainCache()
+                       ObjectCache::getLocalClusterInstance()
                );
 
                $sites = $store->getSites();
@@ -62,7 +62,9 @@ class CachingSiteStoreTest extends MediaWikiTestCase {
         * @covers CachingSiteStore::saveSites
         */
        public function testSaveSites() {
-               $store = new CachingSiteStore( new HashSiteStore(), wfGetMainCache() );
+               $store = new CachingSiteStore(
+                       new HashSiteStore(), ObjectCache::getLocalClusterInstance()
+               );
 
                $sites = [];
 
@@ -108,7 +110,7 @@ class CachingSiteStoreTest extends MediaWikiTestCase {
                                return $siteList;
                        } ) );
 
-               $store = new CachingSiteStore( $dbSiteStore, wfGetMainCache() );
+               $store = new CachingSiteStore( $dbSiteStore, ObjectCache::getLocalClusterInstance() );
 
                // initialize internal cache
                $this->assertGreaterThan( 0, $store->getSites()->count(), 'count sites' );
@@ -138,7 +140,9 @@ class CachingSiteStoreTest extends MediaWikiTestCase {
         * @covers CachingSiteStore::clear
         */
        public function testClear() {
-               $store = new CachingSiteStore( new HashSiteStore(), wfGetMainCache() );
+               $store = new CachingSiteStore(
+                       new HashSiteStore(), ObjectCache::getLocalClusterInstance()
+               );
                $this->assertTrue( $store->clear() );
 
                $site = $store->getSite( 'enwiki' );
index 2ce097b..968db42 100644 (file)
@@ -197,6 +197,37 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
        }
 
        public function testRcHidemyselfFilter() {
+               $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
+               $this->overrideMwServices();
+
+               $user = $this->getTestUser()->getUser();
+               $user->getActorId( wfGetDB( DB_MASTER ) );
+               $this->assertConditions(
+                       [ # expected
+                               "NOT((rc_actor = '{$user->getActorId()}'))",
+                       ],
+                       [
+                               'hidemyself' => 1,
+                       ],
+                       "rc conditions: hidemyself=1 (logged in)",
+                       $user
+               );
+
+               $user = User::newFromName( '10.11.12.13', false );
+               $id = $user->getActorId( wfGetDB( DB_MASTER ) );
+               $this->assertConditions(
+                       [ # expected
+                               "NOT((rc_actor = '{$user->getActorId()}'))",
+                       ],
+                       [
+                               'hidemyself' => 1,
+                       ],
+                       "rc conditions: hidemyself=1 (anon)",
+                       $user
+               );
+       }
+
+       public function testRcHidemyselfFilter_old() {
                $this->setMwGlobals(
                        'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
                );
@@ -230,6 +261,37 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
        }
 
        public function testRcHidebyothersFilter() {
+               $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
+               $this->overrideMwServices();
+
+               $user = $this->getTestUser()->getUser();
+               $user->getActorId( wfGetDB( DB_MASTER ) );
+               $this->assertConditions(
+                       [ # expected
+                               "(rc_actor = '{$user->getActorId()}')",
+                       ],
+                       [
+                               'hidebyothers' => 1,
+                       ],
+                       "rc conditions: hidebyothers=1 (logged in)",
+                       $user
+               );
+
+               $user = User::newFromName( '10.11.12.13', false );
+               $id = $user->getActorId( wfGetDB( DB_MASTER ) );
+               $this->assertConditions(
+                       [ # expected
+                               "(rc_actor = '{$user->getActorId()}')",
+                       ],
+                       [
+                               'hidebyothers' => 1,
+                       ],
+                       "rc conditions: hidebyothers=1 (anon)",
+                       $user
+               );
+       }
+
+       public function testRcHidebyothersFilter_old() {
                $this->setMwGlobals(
                        'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
                );
@@ -338,6 +400,7 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
                        $user
                );
        }
+
        public function testRcHidepatrolledFilter() {
                $user = $this->getTestSysop()->getUser();
                $this->assertConditions(
@@ -464,6 +527,22 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
        }
 
        public function testFilterUserExpLevelAllExperienceLevels() {
+               $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
+               $this->overrideMwServices();
+
+               $this->assertConditions(
+                       [
+                               # expected
+                               'actor_rc_user.actor_user IS NOT NULL',
+                       ],
+                       [
+                               'userExpLevel' => 'newcomer;learner;experienced',
+                       ],
+                       "rc conditions: userExpLevel=newcomer;learner;experienced"
+               );
+       }
+
+       public function testFilterUserExpLevelAllExperienceLevels_old() {
                $this->setMwGlobals(
                        'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
                );
@@ -482,6 +561,22 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
        }
 
        public function testFilterUserExpLevelRegistrered() {
+               $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
+               $this->overrideMwServices();
+
+               $this->assertConditions(
+                       [
+                               # expected
+                               'actor_rc_user.actor_user IS NOT NULL',
+                       ],
+                       [
+                               'userExpLevel' => 'registered',
+                       ],
+                       "rc conditions: userExpLevel=registered"
+               );
+       }
+
+       public function testFilterUserExpLevelRegistrered_old() {
                $this->setMwGlobals(
                        'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
                );
@@ -500,6 +595,22 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
        }
 
        public function testFilterUserExpLevelUnregistrered() {
+               $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
+               $this->overrideMwServices();
+
+               $this->assertConditions(
+                       [
+                               # expected
+                               'actor_rc_user.actor_user IS NULL',
+                       ],
+                       [
+                               'userExpLevel' => 'unregistered',
+                       ],
+                       "rc conditions: userExpLevel=unregistered"
+               );
+       }
+
+       public function testFilterUserExpLevelUnregistrered_old() {
                $this->setMwGlobals(
                        'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
                );
@@ -518,6 +629,22 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
        }
 
        public function testFilterUserExpLevelRegistreredOrLearner() {
+               $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
+               $this->overrideMwServices();
+
+               $this->assertConditions(
+                       [
+                               # expected
+                               'actor_rc_user.actor_user IS NOT NULL',
+                       ],
+                       [
+                               'userExpLevel' => 'registered;learner',
+                       ],
+                       "rc conditions: userExpLevel=registered;learner"
+               );
+       }
+
+       public function testFilterUserExpLevelRegistreredOrLearner_old() {
                $this->setMwGlobals(
                        'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
                );
@@ -536,6 +663,20 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
        }
 
        public function testFilterUserExpLevelUnregistreredOrExperienced() {
+               $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
+               $this->overrideMwServices();
+
+               $conds = $this->buildQuery( [ 'userExpLevel' => 'unregistered;experienced' ] );
+
+               $this->assertRegExp(
+                       '/\(actor_rc_user\.actor_user IS NULL\) OR '
+                               . '\(\(user_editcount >= 500\) AND \(user_registration <= \'[^\']+\'\)\)/',
+                       reset( $conds ),
+                       "rc conditions: userExpLevel=unregistered;experienced"
+               );
+       }
+
+       public function testFilterUserExpLevelUnregistreredOrExperienced_old() {
                $this->setMwGlobals(
                        'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
                );
index 2eddb01..ec4bf0f 100644 (file)
@@ -1,5 +1,7 @@
 <?php
 
+use Wikimedia\TestingAccessWrapper;
+
 /**
  * @covers SpecialPage
  *
@@ -101,4 +103,82 @@ class SpecialPageTest extends MediaWikiTestCase {
                $this->assertTrue( true );
        }
 
+       public function provideBuildPrevNextNavigation() {
+               yield [ 0, 20, false, false ];
+               yield [ 17, 20, false, false ];
+               yield [ 0, 17, false, false ];
+               yield [ 0, 20, true, 'Foo' ];
+               yield [ 17, 20, true, 'Föö_Bär' ];
+       }
+
+       /**
+        * @dataProvider provideBuildPrevNextNavigation
+        */
+       public function testBuildPrevNextNavigation( $offset, $limit, $atEnd, $subPage ) {
+               $this->setUserLang( Language::factory( 'qqx' ) ); // disable i18n
+
+               $specialPage = new SpecialPage( 'Watchlist' );
+               $specialPage = TestingAccessWrapper::newFromObject( $specialPage );
+
+               $html = $specialPage->buildPrevNextNavigation(
+                       $offset,
+                       $limit,
+                       [ 'x' => 25 ],
+                       $atEnd,
+                       $subPage
+               );
+
+               $this->assertStringStartsWith( '(viewprevnext:', $html );
+
+               preg_match_all( '!<a.*?</a>!', $html, $m, PREG_PATTERN_ORDER );
+               $links = $m[0];
+
+               foreach ( $links as $a ) {
+                       if ( $subPage ) {
+                               $this->assertContains( 'Special:Watchlist/' . wfUrlencode( $subPage ), $a );
+                       } else {
+                               $this->assertContains( 'Special:Watchlist', $a );
+                               $this->assertNotContains( 'Special:Watchlist/', $a );
+                       }
+                       $this->assertContains( 'x=25', $a );
+               }
+
+               $i = 0;
+
+               if ( $offset > 0 ) {
+                       $this->assertContains(
+                               'limit=' . $limit . '&amp;offset=' . max( 0, $offset - $limit ) . '&amp;',
+                               $links[ $i ]
+                       );
+                       $this->assertContains( 'title="(prevn-title: ' . $limit . ')"', $links[$i] );
+                       $this->assertContains( 'class="mw-prevlink"', $links[$i] );
+                       $this->assertContains( '>(prevn: ' . $limit . ')<', $links[$i] );
+                       $i += 1;
+               }
+
+               if ( !$atEnd ) {
+                       $this->assertContains(
+                               'limit=' . $limit . '&amp;offset=' . ( $offset + $limit ) . '&amp;',
+                               $links[ $i ]
+                       );
+                       $this->assertContains( 'title="(nextn-title: ' . $limit . ')"', $links[$i] );
+                       $this->assertContains( 'class="mw-nextlink"', $links[$i] );
+                       $this->assertContains( '>(nextn: ' . $limit . ')<', $links[$i] );
+                       $i += 1;
+               }
+
+               $this->assertCount( 5 + $i, $links );
+
+               $this->assertContains( 'limit=20&amp;offset=' . $offset, $links[$i] );
+               $this->assertContains( 'title="(shown-title: 20)"', $links[$i] );
+               $this->assertContains( 'class="mw-numlink"', $links[$i] );
+               $this->assertContains( '>20<', $links[$i] );
+               $i += 4;
+
+               $this->assertContains( 'limit=500&amp;offset=' . $offset, $links[$i] );
+               $this->assertContains( 'title="(shown-title: 500)"', $links[$i] );
+               $this->assertContains( 'class="mw-numlink"', $links[$i] );
+               $this->assertContains( '>500<', $links[$i] );
+       }
+
 }
index dc02922..e881611 100644 (file)
@@ -158,9 +158,7 @@ class ContribsPagerTest extends MediaWikiTestCase {
 
                $this->assertContains( 'ip_changes', $queryInfo[0] );
                $this->assertArrayHasKey( 'ip_changes', $queryInfo[5] );
-               $this->assertSame( 'ipc_rev_timestamp', $queryInfo[1]['rev_timestamp'] );
-               $this->assertSame( 'ipc_rev_id', $queryInfo[1]['rev_id'] );
-               $this->assertSame( [ 'rev_timestamp DESC', 'rev_id DESC' ], $queryInfo[4]['ORDER BY'] );
+               $this->assertSame( [ 'ipc_rev_timestamp DESC', 'ipc_rev_id DESC' ], $queryInfo[4]['ORDER BY'] );
        }
 
 }
index 4a171df..58f83de 100644 (file)
@@ -42,8 +42,7 @@ class QueryAllSpecialPagesTest extends MediaWikiTestCase {
                parent::__construct();
 
                foreach ( QueryPage::getPages() as $page ) {
-                       $class = $page[0];
-                       $name = $page[1];
+                       list( $class, $name ) = $page;
                        if ( !in_array( $class, $this->manualTest ) ) {
                                $this->queryPages[$class] =
                                        MediaWikiServices::getInstance()->getSpecialPageFactory()->getPage( $name );
index 91f12f4..c1f2e42 100644 (file)
@@ -1,9 +1,10 @@
 <?php
 
-use MediaWiki\Block\BlockRestriction;
+use MediaWiki\Block\BlockRestrictionStore;
 use MediaWiki\Block\Restriction\PageRestriction;
 use MediaWiki\Block\Restriction\NamespaceRestriction;
 use Wikimedia\TestingAccessWrapper;
+use Wikimedia\Rdbms\LoadBalancer;
 
 /**
  * @group Blocking
@@ -91,7 +92,7 @@ class SpecialBlockTest extends SpecialPageTestBase {
                $this->assertSame( $block->isCreateAccountBlocked(), $fields['CreateAccount']['default'] );
                $this->assertSame( $block->isAutoblocking(), $fields['AutoBlock']['default'] );
                $this->assertSame( !$block->isUsertalkEditAllowed(), $fields['DisableUTEdit']['default'] );
-               $this->assertSame( $block->mReason, $fields['Reason']['default'] );
+               $this->assertSame( $block->getReason(), $fields['Reason']['default'] );
                $this->assertSame( 'infinite', $fields['Expiry']['default'] );
        }
 
@@ -179,7 +180,7 @@ class SpecialBlockTest extends SpecialPageTestBase {
                $this->assertTrue( $result );
 
                $block = Block::newFromTarget( $badActor );
-               $this->assertSame( $reason, $block->mReason );
+               $this->assertSame( $reason, $block->getReason() );
                $this->assertSame( $expiry, $block->getExpiry() );
        }
 
@@ -228,7 +229,7 @@ class SpecialBlockTest extends SpecialPageTestBase {
                $this->assertTrue( $result );
 
                $block = Block::newFromTarget( $badActor );
-               $this->assertSame( $reason, $block->mReason );
+               $this->assertSame( $reason, $block->getReason() );
                $this->assertSame( $expiry, $block->getExpiry() );
                $this->assertSame( '1', $block->isAutoblocking() );
        }
@@ -277,10 +278,10 @@ class SpecialBlockTest extends SpecialPageTestBase {
                $this->assertTrue( $result );
 
                $block = Block::newFromTarget( $badActor );
-               $this->assertSame( $reason, $block->mReason );
+               $this->assertSame( $reason, $block->getReason() );
                $this->assertSame( $expiry, $block->getExpiry() );
                $this->assertCount( 2, $block->getRestrictions() );
-               $this->assertTrue( BlockRestriction::equals( $block->getRestrictions(), [
+               $this->assertTrue( $this->getBlockRestrictionStore()->equals( $block->getRestrictions(), [
                        new PageRestriction( $block->getId(), $pageMars->getId() ),
                        new PageRestriction( $block->getId(), $pageSaturn->getId() ),
                ] ) );
@@ -331,11 +332,11 @@ class SpecialBlockTest extends SpecialPageTestBase {
                $this->assertTrue( $result );
 
                $block = Block::newFromTarget( $badActor );
-               $this->assertSame( $reason, $block->mReason );
+               $this->assertSame( $reason, $block->getReason() );
                $this->assertSame( $expiry, $block->getExpiry() );
                $this->assertFalse( $block->isSitewide() );
                $this->assertCount( 2, $block->getRestrictions() );
-               $this->assertTrue( BlockRestriction::equals( $block->getRestrictions(), [
+               $this->assertTrue( $this->getBlockRestrictionStore()->equals( $block->getRestrictions(), [
                        new PageRestriction( $block->getId(), $pageMars->getId() ),
                        new PageRestriction( $block->getId(), $pageSaturn->getId() ),
                ] ) );
@@ -347,11 +348,11 @@ class SpecialBlockTest extends SpecialPageTestBase {
                $this->assertTrue( $result );
 
                $block = Block::newFromTarget( $badActor );
-               $this->assertSame( $reason, $block->mReason );
+               $this->assertSame( $reason, $block->getReason() );
                $this->assertSame( $expiry, $block->getExpiry() );
                $this->assertFalse( $block->isSitewide() );
                $this->assertCount( 1, $block->getRestrictions() );
-               $this->assertTrue( BlockRestriction::equals( $block->getRestrictions(), [
+               $this->assertTrue( $this->getBlockRestrictionStore()->equals( $block->getRestrictions(), [
                        new PageRestriction( $block->getId(), $pageMars->getId() ),
                ] ) );
 
@@ -362,7 +363,7 @@ class SpecialBlockTest extends SpecialPageTestBase {
                $this->assertTrue( $result );
 
                $block = Block::newFromTarget( $badActor );
-               $this->assertSame( $reason, $block->mReason );
+               $this->assertSame( $reason, $block->getReason() );
                $this->assertSame( $expiry, $block->getExpiry() );
                $this->assertFalse( $block->isSitewide() );
                $this->assertCount( 0, $block->getRestrictions() );
@@ -374,7 +375,7 @@ class SpecialBlockTest extends SpecialPageTestBase {
                $this->assertTrue( $result );
 
                $block = Block::newFromTarget( $badActor );
-               $this->assertSame( $reason, $block->mReason );
+               $this->assertSame( $reason, $block->getReason() );
                $this->assertSame( $expiry, $block->getExpiry() );
                $this->assertTrue( $block->isSitewide() );
                $this->assertCount( 0, $block->getRestrictions() );
@@ -471,4 +472,17 @@ class SpecialBlockTest extends SpecialPageTestBase {
                $this->db->delete( 'ipblocks', '*', __METHOD__ );
                $this->db->delete( 'ipblocks_restrictions', '*', __METHOD__ );
        }
+
+       /**
+        * Get a BlockRestrictionStore instance
+        *
+        * @return BlockRestrictionStore
+        */
+       private function getBlockRestrictionStore() : BlockRestrictionStore {
+               $loadBalancer = $this->getMockBuilder( LoadBalancer::class )
+                                          ->disableOriginalConstructor()
+                                          ->getMock();
+
+               return new BlockRestrictionStore( $loadBalancer );
+       }
 }
index 28e26a0..642ae3e 100644 (file)
@@ -59,7 +59,44 @@ class SpecialWatchlistTest extends SpecialPageTestBase {
        /**
         * @dataProvider provideFetchOptionsFromRequest
         */
-       public function testFetchOptionsFromRequest( $expectedValues, $preferences, $inputParams ) {
+       public function testFetchOptionsFromRequest(
+               $expectedValuesDefaults, $expectedValues, $preferences, $inputParams
+       ) {
+               // $defaults and $allFalse are just to make the expected values below
+               // shorter by hiding the background.
+
+               $page = TestingAccessWrapper::newFromObject(
+                       $this->newSpecialPage()
+               );
+
+               $page->registerFilters();
+
+               // Does not consider $preferences, just wiki's defaults
+               $wikiDefaults = $page->getDefaultOptions()->getAllValues();
+
+               switch ( $expectedValuesDefaults ) {
+               case 'allFalse':
+                       $allFalse = $wikiDefaults;
+
+                       foreach ( $allFalse as $key => $value ) {
+                               if ( $value === true ) {
+                                       $allFalse[$key] = false;
+                               }
+                       }
+
+                       // This is not exposed on the form (only in preferences) so it
+                       // respects the preference.
+                       $allFalse['extended'] = true;
+
+                       $expectedValues += $allFalse;
+                       break;
+               case 'wikiDefaults':
+                       $expectedValues += $wikiDefaults;
+                       break;
+               default:
+                       $this->fail( "Unknown \$expectedValuesDefaults: $expectedValuesDefaults" );
+               }
+
                $page = TestingAccessWrapper::newFromObject(
                        $this->newSpecialPage()
                );
@@ -90,43 +127,21 @@ class SpecialWatchlistTest extends SpecialPageTestBase {
        }
 
        public function provideFetchOptionsFromRequest() {
-               // $defaults and $allFalse are just to make the expected values below
-               // shorter by hiding the background.
-
-               $page = TestingAccessWrapper::newFromObject(
-                       $this->newSpecialPage()
-               );
-
-               $page->registerFilters();
-
-               // Does not consider $preferences, just wiki's defaults
-               $wikiDefaults = $page->getDefaultOptions()->getAllValues();
-
-               $allFalse = $wikiDefaults;
-
-               foreach ( $allFalse as $key => &$value ) {
-                       if ( $value === true ) {
-                               $value = false;
-                       }
-               }
-
-               // This is not exposed on the form (only in preferences) so it
-               // respects the preference.
-               $allFalse['extended'] = true;
-
                return [
-                       [
-                               [
+                       'ignores casing' => [
+                               'expectedValuesDefaults' => 'wikiDefaults',
+                               'expectedValues' => [
                                        'hideminor' => true,
-                               ] + $wikiDefaults,
-                               [],
-                               [
+                               ],
+                               'preferences' => [],
+                               'inputParams' => [
                                        'hideMinor' => 1,
                                ],
                        ],
 
-                       [
-                               [
+                       'first two same as prefs, second two overriden' => [
+                               'expectedValuesDefaults' => 'wikiDefaults',
+                               'expectedValues' => [
                                        // First two same as prefs
                                        'hideminor' => true,
                                        'hidebots' => false,
@@ -135,38 +150,38 @@ class SpecialWatchlistTest extends SpecialPageTestBase {
                                        'hideanons' => false,
                                        'hideliu' => true,
                                        'userExpLevel' => 'registered'
-                               ] + $wikiDefaults,
-                               [
+                               ],
+                               'preferences' => [
                                        'watchlisthideminor' => 1,
                                        'watchlisthidebots' => 0,
 
                                        'watchlisthideanons' => 1,
                                        'watchlisthideliu' => 0,
                                ],
-                               [
+                               'inputParams' => [
                                        'hideanons' => 0,
                                        'hideliu' => 1,
                                ],
                        ],
 
-                       // Defaults/preferences for form elements are entirely ignored for
-                       // action=submit and omitted elements become false
-                       [
-                               [
+                       'Defaults/preferences for form elements are entirely ignored for '
+                       . 'action=submit and omitted elements become false' => [
+                               'expectedValuesDefaults' => 'allFalse',
+                               'expectedValues' => [
                                        'hideminor' => false,
                                        'hidebots' => true,
                                        'hideanons' => false,
                                        'hideliu' => true,
                                        'userExpLevel' => 'unregistered'
-                               ] + $allFalse,
-                               [
+                               ],
+                               'preferences' => [
                                        'watchlisthideminor' => 0,
                                        'watchlisthidebots' => 1,
 
                                        'watchlisthideanons' => 0,
                                        'watchlisthideliu' => 1,
                                ],
-                               [
+                               'inputParams' => [
                                        'hidebots' => 1,
                                        'hideliu' => 1,
                                        'action' => 'submit',
index 1810ef8..bd37c04 100644 (file)
@@ -16,13 +16,18 @@ class BlockListPagerTest extends MediaWikiTestCase {
         * @dataProvider formatValueEmptyProvider
         * @dataProvider formatValueDefaultProvider
         * @param string $name
-        * @param string $value
         * @param string $expected
         */
-       public function testFormatValue( $name, $value, $expected, $row = null ) {
+       public function testFormatValue( $name, $expected = null, $row = null ) {
                $this->setMwGlobals( [
                        'wgEnablePartialBlocks' => false,
                ] );
+               // Set the time to now so it does not get off during the test.
+               MWTimestamp::setFakeTime( MWTimestamp::time() );
+
+               $value = $name === 'ipb_timestamp' ? MWTimestamp::time() : '';
+               $expected = $expected ?? MWTimestamp::getInstance()->format( 'H:i, j F Y' );
+
                $row = $row ?: new stdClass;
                $pager = new BlockListPager( new SpecialPage(),  [] );
                $wrappedPager = TestingAccessWrapper::newFromObject( $pager );
@@ -30,6 +35,9 @@ class BlockListPagerTest extends MediaWikiTestCase {
 
                $formatted = $pager->formatValue( $name, $value );
                $this->assertEquals( $expected, $formatted );
+
+               // Reset the time.
+               MWTimestamp::setFakeTime( false );
        }
 
        /**
@@ -39,17 +47,13 @@ class BlockListPagerTest extends MediaWikiTestCase {
                return [
                        [
                                'test',
-                               '',
                                'Unable to format test',
                        ],
                        [
                                'ipb_timestamp',
-                               wfTimestamp( TS_UNIX ),
-                               date( 'H:i, j F Y' ),
                        ],
                        [
                                'ipb_expiry',
-                               '',
                                'infinite<br />0 minutes left',
                        ],
                ];
@@ -77,31 +81,26 @@ class BlockListPagerTest extends MediaWikiTestCase {
                return [
                        [
                                'test',
-                               '',
                                'Unable to format test',
                                $row,
                        ],
                        [
                                'ipb_timestamp',
-                               wfTimestamp( TS_UNIX ),
-                               date( 'H:i, j F Y' ),
+                               null,
                                $row,
                        ],
                        [
                                'ipb_expiry',
-                               '',
                                'infinite<br />0 minutes left',
                                $row,
                        ],
                        [
                                'ipb_by',
-                               '',
                                $row->ipb_by_text,
                                $row,
                        ],
                        [
                                'ipb_params',
-                               '',
                                '<ul><li>account creation disabled</li><li>cannot edit own talk page</li></ul>',
                                $row,
                        ]
index 20f0039..b8bf087 100644 (file)
@@ -19,6 +19,8 @@
  * @author Daniel Kinzler
  */
 
+use MediaWiki\Interwiki\InterwikiLookup;
+
 /**
  * @covers MediaWikiTitleCodec
  *
@@ -37,21 +39,6 @@ class MediaWikiTitleCodecTest extends MediaWikiTestCase {
                        'wgMetaNamespace' => 'Project',
                        'wgLocalInterwikis' => [ 'localtestiw' ],
                        'wgCapitalLinks' => true,
-
-                       // NOTE: this is why global state is evil.
-                       // TODO: refactor access to the interwiki codes so it can be injected.
-                       'wgHooks' => [
-                               'InterwikiLoadPrefix' => [
-                                       function ( $prefix, &$data ) {
-                                               if ( $prefix === 'localtestiw' ) {
-                                                       $data = [ 'iw_url' => 'localtestiw' ];
-                                               } elseif ( $prefix === 'remotetestiw' ) {
-                                                       $data = [ 'iw_url' => 'remotetestiw' ];
-                                               }
-                                               return false;
-                                       }
-                               ]
-                       ]
                ] );
                $this->setUserLang( 'en' );
                $this->setContentLang( 'en' );
@@ -77,12 +64,60 @@ class MediaWikiTitleCodecTest extends MediaWikiTestCase {
                return $genderCache;
        }
 
+       /**
+        * Returns a mock InterwikiLookup that only has an isValidInterwiki() method, which recognizes
+        * 'localtestiw' and 'remotetestiw'. All other methods throw.
+        *
+        * @return InterwikiLookup
+        */
+       private function getInterwikiLookup() : InterwikiLookup {
+               $iwLookup = $this->createMock( InterwikiLookup::class );
+
+               $iwLookup->expects( $this->any() )
+                       ->method( 'isValidInterwiki' )
+                       ->will( $this->returnCallback( function ( $prefix ) {
+                               return $prefix === 'localtestiw' || $prefix === 'remotetestiw';
+                       } ) );
+
+               $iwLookup->expects( $this->never() )
+                       ->method( $this->callback( function ( $name ) {
+                               return $name !== 'isValidInterwiki';
+                       } ) );
+
+               return $iwLookup;
+       }
+
+       /**
+        * Returns a mock NamespaceInfo that has only a hasGenderDistinction() method, which assumes
+        * only NS_USER and NS_USER_TALK have a gender distinction. All other methods throw.
+        *
+        * @return NamespaceInfo
+        */
+       private function getNamespaceInfo() : NamespaceInfo {
+               $nsInfo = $this->createMock( NamespaceInfo::class );
+
+               $nsInfo->expects( $this->any() )
+                       ->method( 'hasGenderDistinction' )
+                       ->will( $this->returnCallback( function ( $ns ) {
+                               return $ns === NS_USER || $ns === NS_USER_TALK;
+                       } ) );
+
+               $nsInfo->expects( $this->never() )
+                       ->method( $this->callback( function ( $name ) {
+                               return $name !== 'hasGenderDistinction';
+                       } ) );
+
+               return $nsInfo;
+       }
+
        protected function makeCodec( $lang ) {
-               $gender = $this->getGenderCache();
-               $lang = Language::factory( $lang );
-               // language object can came from cache, which does not respect test settings
-               $lang->resetNamespaces();
-               return new MediaWikiTitleCodec( $lang, $gender );
+               return new MediaWikiTitleCodec(
+                       Language::factory( $lang ),
+                       $this->getGenderCache(),
+                       [],
+                       $this->getInterwikiLookup(),
+                       $this->getNamespaceInfo()
+               );
        }
 
        public static function provideFormat() {
@@ -298,7 +333,9 @@ class MediaWikiTitleCodecTest extends MediaWikiTestCase {
                                new TitleValue( NS_CATEGORY,
                                        'X' . str_repeat( 'x', 247 ) ) ],
                        [ str_repeat( 'x', 252 ), NS_MAIN, 'en',
-                               'X' . str_repeat( 'x', 251 ) ]
+                               'X' . str_repeat( 'x', 251 ) ],
+                       // Test decoding and normalization
+                       [ '&quot;n&#x303;&#34;', NS_MAIN, 'en', new TitleValue( NS_MAIN, '"ñ"' ) ],
                ];
        }
 
diff --git a/tests/phpunit/includes/title/NamespaceInfoTest.php b/tests/phpunit/includes/title/NamespaceInfoTest.php
new file mode 100644 (file)
index 0000000..b1262a3
--- /dev/null
@@ -0,0 +1,1334 @@
+<?php
+/**
+ * @author Antoine Musso
+ * @copyright Copyright © 2011, Antoine Musso
+ * @file
+ */
+
+use MediaWiki\Config\ServiceOptions;
+
+class NamespaceInfoTest extends MediaWikiTestCase {
+       /**********************************************************************************************
+        * Shared code
+        * %{
+        */
+       private $scopedCallback;
+
+       public function setUp() {
+               parent::setUp();
+
+               // Boo, there's still some global state in the class :(
+               global $wgHooks;
+               $hooks = $wgHooks;
+               unset( $hooks['CanonicalNamespaces'] );
+               $this->setMwGlobals( 'wgHooks', $hooks );
+
+               $this->scopedCallback =
+                       ExtensionRegistry::getInstance()->setAttributeForTest( 'ExtensionNamespaces', [] );
+       }
+
+       public function tearDown() {
+               $this->scopedCallback = null;
+
+               parent::tearDown();
+       }
+
+       /**
+        * TODO Make this a const once HHVM support is dropped (T192166)
+        */
+       private static $defaultOptions = [
+               'AllowImageMoving' => true,
+               'CanonicalNamespaceNames' => [
+                       NS_TALK => 'Talk',
+                       NS_USER => 'User',
+                       NS_USER_TALK => 'User_talk',
+                       NS_SPECIAL => 'Special',
+                       NS_MEDIA => 'Media',
+               ],
+               'CapitalLinkOverrides' => [],
+               'CapitalLinks' => true,
+               'ContentNamespaces' => [ NS_MAIN ],
+               'ExtraNamespaces' => [],
+               'ExtraSignatureNamespaces' => [],
+               'NamespaceContentModels' => [],
+               'NamespaceProtection' => [],
+               'NamespacesWithSubpages' => [
+                       NS_TALK => true,
+                       NS_USER => true,
+                       NS_USER_TALK => true,
+               ],
+               'NonincludableNamespaces' => [],
+               'RestrictionLevels' => [ '', 'autoconfirmed', 'sysop' ],
+       ];
+
+       private function newObj( array $options = [] ) : NamespaceInfo {
+               return new NamespaceInfo( new ServiceOptions( NamespaceInfo::$constructorOptions,
+                       $options, self::$defaultOptions ) );
+       }
+
+       // %} End shared code
+
+       /**********************************************************************************************
+        * Basic methods
+        * %{
+        */
+
+       /**
+        * @covers NamespaceInfo::__construct
+        * @dataProvider provideConstructor
+        * @param ServiceOptions $options
+        * @param string|null $expectedExceptionText
+        */
+       public function testConstructor( ServiceOptions $options, $expectedExceptionText = null ) {
+               if ( $expectedExceptionText !== null ) {
+                       $this->setExpectedException( \Wikimedia\Assert\PreconditionException::class,
+                               $expectedExceptionText );
+               }
+               new NamespaceInfo( $options );
+               $this->assertTrue( true );
+       }
+
+       public function provideConstructor() {
+               return [
+                       [ new ServiceOptions( NamespaceInfo::$constructorOptions, self::$defaultOptions ) ],
+                       [ new ServiceOptions( [], [] ), 'Required options missing: ' ],
+                       [ new ServiceOptions(
+                               array_merge( NamespaceInfo::$constructorOptions, [ 'invalid' ] ),
+                               self::$defaultOptions,
+                               [ 'invalid' => '' ]
+                       ), 'Unsupported options passed: invalid' ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideIsMovable
+        * @covers NamespaceInfo::isMovable
+        *
+        * @param bool $expected
+        * @param int $ns
+        * @param bool $allowImageMoving
+        */
+       public function testIsMovable( $expected, $ns, $allowImageMoving = true ) {
+               $obj = $this->newObj( [ 'AllowImageMoving' => $allowImageMoving ] );
+               $this->assertSame( $expected, $obj->isMovable( $ns ) );
+       }
+
+       public function provideIsMovable() {
+               return [
+                       'Main' => [ true, NS_MAIN ],
+                       'Talk' => [ true, NS_TALK ],
+                       'Special' => [ false, NS_SPECIAL ],
+                       'Nonexistent even namespace' => [ true, 1234 ],
+                       'Nonexistent odd namespace' => [ true, 12345 ],
+
+                       'Media with image moving' => [ false, NS_MEDIA, true ],
+                       'Media with no image moving' => [ false, NS_MEDIA, false ],
+                       'File with image moving' => [ true, NS_FILE, true ],
+                       'File with no image moving' => [ false, NS_FILE, false ],
+               ];
+       }
+
+       /**
+        * @param int $ns
+        * @param bool $expected
+        * @dataProvider provideIsSubject
+        * @covers NamespaceInfo::isSubject
+        */
+       public function testIsSubject( $ns, $expected ) {
+               $this->assertSame( $expected, $this->newObj()->isSubject( $ns ) );
+       }
+
+       /**
+        * @param int $ns
+        * @param bool $expected
+        * @dataProvider provideIsSubject
+        * @covers NamespaceInfo::isTalk
+        */
+       public function testIsTalk( $ns, $expected ) {
+               $this->assertSame( !$expected, $this->newObj()->isTalk( $ns ) );
+       }
+
+       public function provideIsSubject() {
+               return [
+                       // Special namespaces
+                       [ NS_MEDIA, true ],
+                       [ NS_SPECIAL, true ],
+
+                       // Subject pages
+                       [ NS_MAIN, true ],
+                       [ NS_USER, true ],
+                       [ 100, true ],
+
+                       // Talk pages
+                       [ NS_TALK, false ],
+                       [ NS_USER_TALK, false ],
+                       [ 101, false ],
+               ];
+       }
+
+       /**
+        * @covers NamespaceInfo::exists
+        * @dataProvider provideExists
+        * @param int $ns
+        * @param bool $expected
+        */
+       public function testExists( $ns, $expected ) {
+               $this->assertSame( $expected, $this->newObj()->exists( $ns ) );
+       }
+
+       public function provideExists() {
+               return [
+                       'Main' => [ NS_MAIN, true ],
+                       'Talk' => [ NS_TALK, true ],
+                       'Media' => [ NS_MEDIA, true ],
+                       'Special' => [ NS_SPECIAL, true ],
+                       'Nonexistent' => [ 12345, false ],
+                       'Negative nonexistent' => [ -12345, false ],
+               ];
+       }
+
+       /**
+        * Note if we add a namespace registration system with keys like 'MAIN'
+        * we should add tests here for equivalence on things like 'MAIN' == 0
+        * and 'MAIN' == NS_MAIN.
+        * @covers NamespaceInfo::equals
+        */
+       public function testEquals() {
+               $obj = $this->newObj();
+               $this->assertTrue( $obj->equals( NS_MAIN, NS_MAIN ) );
+               $this->assertTrue( $obj->equals( NS_MAIN, 0 ) ); // In case we make NS_MAIN 'MAIN'
+               $this->assertTrue( $obj->equals( NS_USER, NS_USER ) );
+               $this->assertTrue( $obj->equals( NS_USER, 2 ) );
+               $this->assertTrue( $obj->equals( NS_USER_TALK, NS_USER_TALK ) );
+               $this->assertTrue( $obj->equals( NS_SPECIAL, NS_SPECIAL ) );
+               $this->assertFalse( $obj->equals( NS_MAIN, NS_TALK ) );
+               $this->assertFalse( $obj->equals( NS_USER, NS_USER_TALK ) );
+               $this->assertFalse( $obj->equals( NS_PROJECT, NS_TEMPLATE ) );
+       }
+
+       /**
+        * @param int $ns1
+        * @param int $ns2
+        * @param bool $expected
+        * @dataProvider provideSubjectEquals
+        * @covers NamespaceInfo::subjectEquals
+        */
+       public function testSubjectEquals( $ns1, $ns2, $expected ) {
+               $this->assertSame( $expected, $this->newObj()->subjectEquals( $ns1, $ns2 ) );
+       }
+
+       public function provideSubjectEquals() {
+               return [
+                       [ NS_MAIN, NS_MAIN, true ],
+                       // In case we make NS_MAIN 'MAIN'
+                       [ NS_MAIN, 0, true ],
+                       [ NS_USER, NS_USER, true ],
+                       [ NS_USER, 2, true ],
+                       [ NS_USER_TALK, NS_USER_TALK, true ],
+                       [ NS_SPECIAL, NS_SPECIAL, true ],
+                       [ NS_MAIN, NS_TALK, true ],
+                       [ NS_USER, NS_USER_TALK, true ],
+
+                       [ NS_PROJECT, NS_TEMPLATE, false ],
+                       [ NS_SPECIAL, NS_MAIN, false ],
+                       [ NS_MEDIA, NS_SPECIAL, false ],
+                       [ NS_SPECIAL, NS_MEDIA, false ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideHasTalkNamespace
+        * @covers NamespaceInfo::hasTalkNamespace
+        *
+        * @param int $ns
+        * @param bool $expected
+        */
+       public function testHasTalkNamespace( $ns, $expected ) {
+               $this->assertSame( $expected, $this->newObj()->hasTalkNamespace( $ns ) );
+       }
+
+       public function provideHasTalkNamespace() {
+               return [
+                       [ NS_MEDIA, false ],
+                       [ NS_SPECIAL, false ],
+
+                       [ NS_MAIN, true ],
+                       [ NS_TALK, true ],
+                       [ NS_USER, true ],
+                       [ NS_USER_TALK, true ],
+
+                       [ 100, true ],
+                       [ 101, true ],
+               ];
+       }
+
+       /**
+        * @param int $ns
+        * @param bool $expected
+        * @param array $contentNamespaces
+        * @covers NamespaceInfo::isContent
+        * @dataProvider provideIsContent
+        */
+       public function testIsContent( $ns, $expected, $contentNamespaces = [ NS_MAIN ] ) {
+               $obj = $this->newObj( [ 'ContentNamespaces' => $contentNamespaces ] );
+               $this->assertSame( $expected, $obj->isContent( $ns ) );
+       }
+
+       public function provideIsContent() {
+               return [
+                       [ NS_MAIN, true ],
+                       [ NS_MEDIA, false ],
+                       [ NS_SPECIAL, false ],
+                       [ NS_TALK, false ],
+                       [ NS_USER, false ],
+                       [ NS_CATEGORY, false ],
+                       [ 100, false ],
+                       [ 100, true, [ NS_MAIN, 100, 252 ] ],
+                       [ 252, true, [ NS_MAIN, 100, 252 ] ],
+                       [ NS_MAIN, true, [ NS_MAIN, 100, 252 ] ],
+                       // NS_MAIN is always content
+                       [ NS_MAIN, true, [] ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideWantSignatures
+        * @covers NamespaceInfo::wantSignatures
+        *
+        * @param int $index
+        * @param bool $expected
+        */
+       public function testWantSignatures( $index, $expected ) {
+               $this->assertSame( $expected, $this->newObj()->wantSignatures( $index ) );
+       }
+
+       public function provideWantSignatures() {
+               return [
+                       'Main' => [ NS_MAIN, false ],
+                       'Talk' => [ NS_TALK, true ],
+                       'User' => [ NS_USER, false ],
+                       'User talk' => [ NS_USER_TALK, true ],
+                       'Special' => [ NS_SPECIAL, false ],
+                       'Media' => [ NS_MEDIA, false ],
+                       'Nonexistent talk' => [ 12345, true ],
+                       'Nonexistent subject' => [ 123456, false ],
+                       'Nonexistent negative odd' => [ -12345, false ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideWantSignatures_ExtraSignatureNamespaces
+        * @covers NamespaceInfo::wantSignatures
+        *
+        * @param int $index
+        * @param int $expected
+        */
+       public function testWantSignatures_ExtraSignatureNamespaces( $index, $expected ) {
+               $obj = $this->newObj( [ 'ExtraSignatureNamespaces' =>
+                       [ NS_MAIN, NS_USER, NS_SPECIAL, NS_MEDIA, 123456, -12345 ] ] );
+               $this->assertSame( $expected, $obj->wantSignatures( $index ) );
+       }
+
+       public function provideWantSignatures_ExtraSignatureNamespaces() {
+               $ret = array_map(
+                       function ( $arr ) {
+                               // We've added all these as extra signature namespaces, so expect true
+                               return [ $arr[0], true ];
+                       },
+                       self::provideWantSignatures()
+               );
+
+               // Add one more that's false
+               $ret['Another nonexistent subject'] = [ 12345678, false ];
+               return $ret;
+       }
+
+       /**
+        * @param int $ns
+        * @param bool $expected
+        * @covers NamespaceInfo::isWatchable
+        * @dataProvider provideIsWatchable
+        */
+       public function testIsWatchable( $ns, $expected ) {
+               $this->assertSame( $expected, $this->newObj()->isWatchable( $ns ) );
+       }
+
+       public function provideIsWatchable() {
+               return [
+                       // Specials namespaces are not watchable
+                       [ NS_MEDIA, false ],
+                       [ NS_SPECIAL, false ],
+
+                       // Core defined namespaces are watchables
+                       [ NS_MAIN, true ],
+                       [ NS_TALK, true ],
+
+                       // Additional, user defined namespaces are watchables
+                       [ 100, true ],
+                       [ 101, true ],
+               ];
+       }
+
+       /**
+        * @param int $ns
+        * @param int $expected
+        * @param array|null $namespacesWithSubpages To pass to constructor
+        * @covers NamespaceInfo::hasSubpages
+        * @dataProvider provideHasSubpages
+        */
+       public function testHasSubpages( $ns, $expected, array $namespacesWithSubpages = null ) {
+               $obj = $this->newObj( $namespacesWithSubpages
+                       ? [ 'NamespacesWithSubpages' => $namespacesWithSubpages ]
+                       : [] );
+               $this->assertSame( $expected, $obj->hasSubpages( $ns ) );
+       }
+
+       public function provideHasSubpages() {
+               return [
+                       // Special namespaces:
+                       [ NS_MEDIA, false ],
+                       [ NS_SPECIAL, false ],
+
+                       // Namespaces without subpages
+                       [ NS_MAIN, false ],
+                       [ NS_MAIN, true, [ NS_MAIN => true ] ],
+                       [ NS_MAIN, false, [ NS_MAIN => false ] ],
+
+                       // Some namespaces with subpages
+                       [ NS_TALK, true ],
+                       [ NS_USER, true ],
+                       [ NS_USER_TALK, true ],
+               ];
+       }
+
+       /**
+        * @param $contentNamespaces To pass to constructor
+        * @param array $expected
+        * @dataProvider provideGetContentNamespaces
+        * @covers NamespaceInfo::getContentNamespaces
+        */
+       public function testGetContentNamespaces( $contentNamespaces, array $expected ) {
+               $obj = $this->newObj( [ 'ContentNamespaces' => $contentNamespaces ] );
+               $this->assertSame( $expected, $obj->getContentNamespaces() );
+       }
+
+       public function provideGetContentNamespaces() {
+               return [
+                       // Non-array
+                       [ '', [ NS_MAIN ] ],
+                       [ false, [ NS_MAIN ] ],
+                       [ null, [ NS_MAIN ] ],
+                       [ 5, [ NS_MAIN ] ],
+
+                       // Empty array
+                       [ [], [ NS_MAIN ] ],
+
+                       // NS_MAIN is forced to be content even if unwanted
+                       [ [ NS_USER, NS_CATEGORY ], [ NS_MAIN, NS_USER, NS_CATEGORY ] ],
+
+                       // In other cases, return as-is
+                       [ [ NS_MAIN ], [ NS_MAIN ] ],
+                       [ [ NS_MAIN, NS_USER, NS_CATEGORY ], [ NS_MAIN, NS_USER, NS_CATEGORY ] ],
+               ];
+       }
+
+       /**
+        * @covers NamespaceInfo::getSubjectNamespaces
+        */
+       public function testGetSubjectNamespaces() {
+               $subjectsNS = $this->newObj()->getSubjectNamespaces();
+               $this->assertContains( NS_MAIN, $subjectsNS,
+                       "Talk namespaces should have NS_MAIN" );
+               $this->assertNotContains( NS_TALK, $subjectsNS,
+                       "Talk namespaces should have NS_TALK" );
+
+               $this->assertNotContains( NS_MEDIA, $subjectsNS,
+                       "Talk namespaces should not have NS_MEDIA" );
+               $this->assertNotContains( NS_SPECIAL, $subjectsNS,
+                       "Talk namespaces should not have NS_SPECIAL" );
+       }
+
+       /**
+        * @covers NamespaceInfo::getTalkNamespaces
+        */
+       public function testGetTalkNamespaces() {
+               $talkNS = $this->newObj()->getTalkNamespaces();
+               $this->assertContains( NS_TALK, $talkNS,
+                       "Subject namespaces should have NS_TALK" );
+               $this->assertNotContains( NS_MAIN, $talkNS,
+                       "Subject namespaces should not have NS_MAIN" );
+
+               $this->assertNotContains( NS_MEDIA, $talkNS,
+                       "Subject namespaces should not have NS_MEDIA" );
+               $this->assertNotContains( NS_SPECIAL, $talkNS,
+                       "Subject namespaces should not have NS_SPECIAL" );
+       }
+
+       /**
+        * @param int $ns
+        * @param bool $expected
+        * @param bool $capitalLinks To pass to constructor
+        * @param array $capitalLinkOverrides To pass to constructor
+        * @dataProvider provideIsCapitalized
+        * @covers NamespaceInfo::isCapitalized
+        */
+       public function testIsCapitalized(
+               $ns, $expected, $capitalLinks = true, array $capitalLinkOverrides = []
+       ) {
+               $obj = $this->newObj( [
+                       'CapitalLinks' => $capitalLinks,
+                       'CapitalLinkOverrides' => $capitalLinkOverrides,
+               ] );
+               $this->assertSame( $expected, $obj->isCapitalized( $ns ) );
+       }
+
+       public function provideIsCapitalized() {
+               return [
+                       // Test default settings
+                       [ NS_PROJECT, true ],
+                       [ NS_PROJECT_TALK, true ],
+                       [ NS_MEDIA, true ],
+                       [ NS_FILE, true ],
+
+                       // Always capitalized no matter what
+                       [ NS_SPECIAL, true, false ],
+                       [ NS_USER, true, false ],
+                       [ NS_MEDIAWIKI, true, false ],
+
+                       // Even with an override too
+                       [ NS_SPECIAL, true, false, [ NS_SPECIAL => false ] ],
+                       [ NS_USER, true, false, [ NS_USER => false ] ],
+                       [ NS_MEDIAWIKI, true, false, [ NS_MEDIAWIKI => false ] ],
+
+                       // Overrides work for other namespaces
+                       [ NS_PROJECT, false, true, [ NS_PROJECT => false ] ],
+                       [ NS_PROJECT, true, false, [ NS_PROJECT => true ] ],
+
+                       // NS_MEDIA is treated like NS_FILE, and ignores NS_MEDIA overrides
+                       [ NS_MEDIA, false, true, [ NS_FILE => false, NS_MEDIA => true ] ],
+                       [ NS_MEDIA, true, false, [ NS_FILE => true, NS_MEDIA => false ] ],
+                       [ NS_FILE, false, true, [ NS_FILE => false, NS_MEDIA => true ] ],
+                       [ NS_FILE, true, false, [ NS_FILE => true, NS_MEDIA => false ] ],
+               ];
+       }
+
+       /**
+        * @covers NamespaceInfo::hasGenderDistinction
+        */
+       public function testHasGenderDistinction() {
+               $obj = $this->newObj();
+
+               // Namespaces with gender distinctions
+               $this->assertTrue( $obj->hasGenderDistinction( NS_USER ) );
+               $this->assertTrue( $obj->hasGenderDistinction( NS_USER_TALK ) );
+
+               // Other ones, "genderless"
+               $this->assertFalse( $obj->hasGenderDistinction( NS_MEDIA ) );
+               $this->assertFalse( $obj->hasGenderDistinction( NS_SPECIAL ) );
+               $this->assertFalse( $obj->hasGenderDistinction( NS_MAIN ) );
+               $this->assertFalse( $obj->hasGenderDistinction( NS_TALK ) );
+       }
+
+       /**
+        * @covers NamespaceInfo::isNonincludable
+        */
+       public function testIsNonincludable() {
+               $obj = $this->newObj( [ 'NonincludableNamespaces' => [ NS_USER ] ] );
+               $this->assertTrue( $obj->isNonincludable( NS_USER ) );
+               $this->assertFalse( $obj->isNonincludable( NS_TEMPLATE ) );
+       }
+
+       /**
+        * @dataProvider provideGetNamespaceContentModel
+        * @covers NamespaceInfo::getNamespaceContentModel
+        *
+        * @param int $ns
+        * @param string $expected
+        */
+       public function testGetNamespaceContentModel( $ns, $expected ) {
+               $obj = $this->newObj( [ 'NamespaceContentModels' =>
+                       [ NS_USER => CONTENT_MODEL_WIKITEXT, 123 => CONTENT_MODEL_JSON, 1234 => 'abcdef' ],
+               ] );
+               $this->assertSame( $expected, $obj->getNamespaceContentModel( $ns ) );
+       }
+
+       public function provideGetNamespaceContentModel() {
+               return [
+                       [ NS_MAIN, null ],
+                       [ NS_TALK, null ],
+                       [ NS_USER, CONTENT_MODEL_WIKITEXT ],
+                       [ NS_USER_TALK, null ],
+                       [ NS_SPECIAL, null ],
+                       [ 122, null ],
+                       [ 123, CONTENT_MODEL_JSON ],
+                       [ 1234, 'abcdef' ],
+                       [ 1235, null ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideGetCategoryLinkType
+        * @covers NamespaceInfo::getCategoryLinkType
+        *
+        * @param int $ns
+        * @param string $expected
+        */
+       public function testGetCategoryLinkType( $ns, $expected ) {
+               $this->assertSame( $expected, $this->newObj()->getCategoryLinkType( $ns ) );
+       }
+
+       public function provideGetCategoryLinkType() {
+               return [
+                       [ NS_MAIN, 'page' ],
+                       [ NS_TALK, 'page' ],
+                       [ NS_USER, 'page' ],
+                       [ NS_USER_TALK, 'page' ],
+
+                       [ NS_FILE, 'file' ],
+                       [ NS_FILE_TALK, 'page' ],
+
+                       [ NS_CATEGORY, 'subcat' ],
+                       [ NS_CATEGORY_TALK, 'page' ],
+
+                       [ 100, 'page' ],
+                       [ 101, 'page' ],
+               ];
+       }
+
+       // %} End basic methods
+
+       /**********************************************************************************************
+        * getSubject/Talk/Associated
+        * %{
+        */
+
+       /**
+        * @dataProvider provideSubjectTalk
+        * @covers NamespaceInfo::getSubject
+        * @covers NamespaceInfo::getSubjectPage
+        * @covers NamespaceInfo::isMethodValidFor
+        * @covers Title::getSubjectPage
+        *
+        * @param int $subject
+        * @param int $talk
+        */
+       public function testGetSubject( $subject, $talk ) {
+               $obj = $this->newObj();
+               $this->assertSame( $subject, $obj->getSubject( $subject ) );
+               $this->assertSame( $subject, $obj->getSubject( $talk ) );
+
+               $subjectTitleVal = new TitleValue( $subject, 'A' );
+               $talkTitleVal = new TitleValue( $talk, 'A' );
+               // Object will be the same one passed in if it's a subject, different but equal object if
+               // it's talk
+               $this->assertSame( $subjectTitleVal, $obj->getSubjectPage( $subjectTitleVal ) );
+               $this->assertEquals( $subjectTitleVal, $obj->getSubjectPage( $talkTitleVal ) );
+
+               $subjectTitle = Title::makeTitle( $subject, 'A' );
+               $talkTitle = Title::makeTitle( $talk, 'A' );
+               $this->assertSame( $subjectTitle, $subjectTitle->getSubjectPage() );
+               $this->assertEquals( $subjectTitle, $talkTitle->getSubjectPage() );
+       }
+
+       /**
+        * @dataProvider provideSpecialNamespaces
+        * @covers NamespaceInfo::getSubject
+        * @covers NamespaceInfo::getSubjectPage
+        *
+        * @param int $ns
+        */
+       public function testGetSubject_special( $ns ) {
+               $obj = $this->newObj();
+               $this->assertSame( $ns, $obj->getSubject( $ns ) );
+
+               $title = new TitleValue( $ns, 'A' );
+               $this->assertSame( $title, $obj->getSubjectPage( $title ) );
+       }
+
+       /**
+        * @dataProvider provideSubjectTalk
+        * @covers NamespaceInfo::getTalk
+        * @covers NamespaceInfo::getTalkPage
+        * @covers NamespaceInfo::isMethodValidFor
+        * @covers Title::getTalkPage
+        *
+        * @param int $subject
+        * @param int $talk
+        */
+       public function testGetTalk( $subject, $talk ) {
+               $obj = $this->newObj();
+               $this->assertSame( $talk, $obj->getTalk( $subject ) );
+               $this->assertSame( $talk, $obj->getTalk( $talk ) );
+
+               $subjectTitleVal = new TitleValue( $subject, 'A' );
+               $talkTitleVal = new TitleValue( $talk, 'A' );
+               // Object will be the same one passed in if it's a talk, different but equal object if it's
+               // subject
+               $this->assertEquals( $talkTitleVal, $obj->getTalkPage( $subjectTitleVal ) );
+               $this->assertSame( $talkTitleVal, $obj->getTalkPage( $talkTitleVal ) );
+
+               $subjectTitle = Title::makeTitle( $subject, 'A' );
+               $talkTitle = Title::makeTitle( $talk, 'A' );
+               $this->assertEquals( $talkTitle, $subjectTitle->getTalkPage() );
+               $this->assertSame( $talkTitle, $talkTitle->getTalkPage() );
+       }
+
+       /**
+        * @dataProvider provideSpecialNamespaces
+        * @covers NamespaceInfo::getTalk
+        * @covers NamespaceInfo::isMethodValidFor
+        *
+        * @param int $ns
+        */
+       public function testGetTalk_special( $ns ) {
+               $this->setExpectedException( MWException::class,
+                       "NamespaceInfo::getTalk does not make any sense for given namespace $ns" );
+               $this->newObj()->getTalk( $ns );
+       }
+
+       /**
+        * @dataProvider provideSpecialNamespaces
+        * @covers NamespaceInfo::getTalk
+        * @covers NamespaceInfo::getTalkPage
+        * @covers NamespaceInfo::isMethodValidFor
+        *
+        * @param int $ns
+        */
+       public function testGetTalkPage_special( $ns ) {
+               $this->setExpectedException( MWException::class,
+                       "NamespaceInfo::getTalk does not make any sense for given namespace $ns" );
+               $this->newObj()->getTalkPage( new TitleValue( $ns, 'A' ) );
+       }
+
+       /**
+        * @dataProvider provideSpecialNamespaces
+        * @covers NamespaceInfo::getTalk
+        * @covers NamespaceInfo::getTalkPage
+        * @covers NamespaceInfo::isMethodValidFor
+        * @covers Title::getTalkPage
+        *
+        * @param int $ns
+        */
+       public function testTitleGetTalkPage_special( $ns ) {
+               $this->setExpectedException( MWException::class,
+                       "NamespaceInfo::getTalk does not make any sense for given namespace $ns" );
+               Title::makeTitle( $ns, 'A' )->getTalkPage();
+       }
+
+       /**
+        * @dataProvider provideSpecialNamespaces
+        * @covers NamespaceInfo::getAssociated
+        * @covers NamespaceInfo::isMethodValidFor
+        *
+        * @param int $ns
+        */
+       public function testGetAssociated_special( $ns ) {
+               $this->setExpectedException( MWException::class,
+                       "NamespaceInfo::getAssociated does not make any sense for given namespace $ns" );
+               $this->newObj()->getAssociated( $ns );
+       }
+
+       /**
+        * @dataProvider provideSpecialNamespaces
+        * @covers NamespaceInfo::getAssociated
+        * @covers NamespaceInfo::getAssociatedPage
+        * @covers NamespaceInfo::isMethodValidFor
+        *
+        * @param int $ns
+        */
+       public function testGetAssociatedPage_special( $ns ) {
+               $this->setExpectedException( MWException::class,
+                       "NamespaceInfo::getAssociated does not make any sense for given namespace $ns" );
+               $this->newObj()->getAssociatedPage( new TitleValue( $ns, 'A' ) );
+       }
+
+       /**
+        * @dataProvider provideSpecialNamespaces
+        * @covers NamespaceInfo::getAssociated
+        * @covers NamespaceInfo::getAssociatedPage
+        * @covers NamespaceInfo::isMethodValidFor
+        * @covers Title::getOtherPage
+        *
+        * @param int $ns
+        */
+       public function testTitleGetOtherPage_special( $ns ) {
+               $this->setExpectedException( MWException::class,
+                       "NamespaceInfo::getAssociated does not make any sense for given namespace $ns" );
+               Title::makeTitle( $ns, 'A' )->getOtherPage();
+       }
+
+       /**
+        * @dataProvider provideSubjectTalk
+        * @covers NamespaceInfo::getAssociated
+        * @covers NamespaceInfo::getAssociatedPage
+        * @covers Title::getOtherPage
+        *
+        * @param int $subject
+        * @param int $talk
+        */
+       public function testGetAssociated( $subject, $talk ) {
+               $obj = $this->newObj();
+               $this->assertSame( $talk, $obj->getAssociated( $subject ) );
+               $this->assertSame( $subject, $obj->getAssociated( $talk ) );
+
+               $subjectTitle = new TitleValue( $subject, 'A' );
+               $talkTitle = new TitleValue( $talk, 'A' );
+               // Object will not be the same
+               $this->assertEquals( $talkTitle, $obj->getAssociatedPage( $subjectTitle ) );
+               $this->assertEquals( $subjectTitle, $obj->getAssociatedPage( $talkTitle ) );
+
+               $subjectTitle = Title::makeTitle( $subject, 'A' );
+               $talkTitle = Title::makeTitle( $talk, 'A' );
+               $this->assertEquals( $talkTitle, $subjectTitle->getOtherPage() );
+               $this->assertEquals( $subjectTitle, $talkTitle->getOtherPage() );
+       }
+
+       public static function provideSubjectTalk() {
+               return [
+                       // Format: [ subject, talk ]
+                       'Main/talk' => [ NS_MAIN, NS_TALK ],
+                       'User/user talk' => [ NS_USER, NS_USER_TALK ],
+                       'Unknown namespaces also supported' => [ 106, 107 ],
+               ];
+       }
+
+       public static function provideSpecialNamespaces() {
+               return [
+                       'Special' => [ NS_SPECIAL ],
+                       'Media' => [ NS_MEDIA ],
+                       'Unknown negative index' => [ -613 ],
+               ];
+       }
+
+       // %} End getSubject/Talk/Associated
+
+       /**********************************************************************************************
+        * Canonical namespaces
+        * %{
+        */
+
+       // Default canonical namespaces
+       // %{
+       private function getDefaultNamespaces() {
+               return [ NS_MAIN => '' ] + self::$defaultOptions['CanonicalNamespaceNames'];
+       }
+
+       /**
+        * @covers NamespaceInfo::getCanonicalNamespaces
+        */
+       public function testGetCanonicalNamespaces() {
+               $this->assertSame(
+                       $this->getDefaultNamespaces(),
+                       $this->newObj()->getCanonicalNamespaces()
+               );
+       }
+
+       /**
+        * @dataProvider provideGetCanonicalName
+        * @covers NamespaceInfo::getCanonicalName
+        *
+        * @param int $index
+        * @param string|bool $expected
+        */
+       public function testGetCanonicalName( $index, $expected ) {
+               $this->assertSame( $expected, $this->newObj()->getCanonicalName( $index ) );
+       }
+
+       public function provideGetCanonicalName() {
+               return [
+                       'Main' => [ NS_MAIN, '' ],
+                       'Talk' => [ NS_TALK, 'Talk' ],
+                       'With underscore not space' => [ NS_USER_TALK, 'User_talk' ],
+                       'Special' => [ NS_SPECIAL, 'Special' ],
+                       'Nonexistent' => [ 12345, false ],
+                       'Nonexistent negative' => [ -12345, false ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideGetCanonicalIndex
+        * @covers NamespaceInfo::getCanonicalIndex
+        *
+        * @param string $name
+        * @param int|null $expected
+        */
+       public function testGetCanonicalIndex( $name, $expected ) {
+               $this->assertSame( $expected, $this->newObj()->getCanonicalIndex( $name ) );
+       }
+
+       public function provideGetCanonicalIndex() {
+               return [
+                       'Main' => [ '', NS_MAIN ],
+                       'Talk' => [ 'talk', NS_TALK ],
+                       'Not lowercase' => [ 'Talk', null ],
+                       'With underscore' => [ 'user_talk', NS_USER_TALK ],
+                       'Space is not recognized for underscore' => [ 'user talk', null ],
+                       '0' => [ '0', null ],
+               ];
+       }
+
+       /**
+        * @covers NamespaceInfo::getValidNamespaces
+        */
+       public function testGetValidNamespaces() {
+               $this->assertSame(
+                       [ NS_MAIN, NS_TALK, NS_USER, NS_USER_TALK ],
+                       $this->newObj()->getValidNamespaces()
+               );
+       }
+
+       // %} End default canonical namespaces
+
+       // No canonical namespace names
+       // %{
+
+       /**
+        * @covers NamespaceInfo::getCanonicalNamespaces
+        */
+       public function testGetCanonicalNamespaces_NoCanonicalNamespaceNames() {
+               $obj = $this->newObj( [ 'CanonicalNamespaceNames' => [] ] );
+
+               $this->assertSame( [ NS_MAIN => '' ], $obj->getCanonicalNamespaces() );
+       }
+
+       /**
+        * @covers NamespaceInfo::getCanonicalName
+        */
+       public function testGetCanonicalName_NoCanonicalNamespaceNames() {
+               $obj = $this->newObj( [ 'CanonicalNamespaceNames' => [] ] );
+
+               $this->assertSame( '', $obj->getCanonicalName( NS_MAIN ) );
+               $this->assertFalse( $obj->getCanonicalName( NS_TALK ) );
+       }
+
+       /**
+        * @covers NamespaceInfo::getCanonicalIndex
+        */
+       public function testGetCanonicalIndex_NoCanonicalNamespaceNames() {
+               $obj = $this->newObj( [ 'CanonicalNamespaceNames' => [] ] );
+
+               $this->assertSame( NS_MAIN, $obj->getCanonicalIndex( '' ) );
+               $this->assertNull( $obj->getCanonicalIndex( 'talk' ) );
+       }
+
+       /**
+        * @covers NamespaceInfo::getValidNamespaces
+        */
+       public function testGetValidNamespaces_NoCanonicalNamespaceNames() {
+               $obj = $this->newObj( [ 'CanonicalNamespaceNames' => [] ] );
+
+               $this->assertSame( [ NS_MAIN ], $obj->getValidNamespaces() );
+       }
+
+       // %} End no canonical namespace names
+
+       // Test extension namespaces
+       // %{
+       private function setupExtensionNamespaces() {
+               $this->scopedCallback = null;
+               $this->scopedCallback = ExtensionRegistry::getInstance()->setAttributeForTest(
+                       'ExtensionNamespaces',
+                       [ NS_MAIN => 'No effect', NS_TALK => 'No effect', 12345 => 'Extended' ]
+               );
+       }
+
+       /**
+        * @covers NamespaceInfo::getCanonicalNamespaces
+        */
+       public function testGetCanonicalNamespaces_ExtensionNamespaces() {
+               $this->setupExtensionNamespaces();
+
+               $this->assertSame(
+                       $this->getDefaultNamespaces() + [ 12345 => 'Extended' ],
+                       $this->newObj()->getCanonicalNamespaces()
+               );
+       }
+
+       /**
+        * @covers NamespaceInfo::getCanonicalName
+        */
+       public function testGetCanonicalName_ExtensionNamespaces() {
+               $this->setupExtensionNamespaces();
+               $obj = $this->newObj();
+
+               $this->assertSame( '', $obj->getCanonicalName( NS_MAIN ) );
+               $this->assertSame( 'Talk', $obj->getCanonicalName( NS_TALK ) );
+               $this->assertSame( 'Extended', $obj->getCanonicalName( 12345 ) );
+       }
+
+       /**
+        * @covers NamespaceInfo::getCanonicalIndex
+        */
+       public function testGetCanonicalIndex_ExtensionNamespaces() {
+               $this->setupExtensionNamespaces();
+               $obj = $this->newObj();
+
+               $this->assertSame( NS_MAIN, $obj->getCanonicalIndex( '' ) );
+               $this->assertSame( NS_TALK, $obj->getCanonicalIndex( 'talk' ) );
+               $this->assertSame( 12345, $obj->getCanonicalIndex( 'extended' ) );
+       }
+
+       /**
+        * @covers NamespaceInfo::getValidNamespaces
+        */
+       public function testGetValidNamespaces_ExtensionNamespaces() {
+               $this->setupExtensionNamespaces();
+
+               $this->assertSame(
+                       [ NS_MAIN, NS_TALK, NS_USER, NS_USER_TALK, 12345 ],
+                       $this->newObj()->getValidNamespaces()
+               );
+       }
+
+       // %} End extension namespaces
+
+       // Hook namespaces
+       // %{
+
+       /**
+        * @return array Expected canonical namespaces
+        */
+       private function setupHookNamespaces() {
+               $callback =
+                       function ( &$canonicalNamespaces ) {
+                               $canonicalNamespaces[NS_MAIN] = 'Main';
+                               unset( $canonicalNamespaces[NS_MEDIA] );
+                               $canonicalNamespaces[123456] = 'Hooked';
+                       };
+               $this->setTemporaryHook( 'CanonicalNamespaces', $callback );
+               $expected = $this->getDefaultNamespaces();
+               ( $callback )( $expected );
+               return $expected;
+       }
+
+       /**
+        * @covers NamespaceInfo::getCanonicalNamespaces
+        */
+       public function testGetCanonicalNamespaces_HookNamespaces() {
+               $expected = $this->setupHookNamespaces();
+
+               $this->assertSame( $expected, $this->newObj()->getCanonicalNamespaces() );
+       }
+
+       /**
+        * @covers NamespaceInfo::getCanonicalName
+        */
+       public function testGetCanonicalName_HookNamespaces() {
+               $this->setupHookNamespaces();
+               $obj = $this->newObj();
+
+               $this->assertSame( 'Main', $obj->getCanonicalName( NS_MAIN ) );
+               $this->assertFalse( $obj->getCanonicalName( NS_MEDIA ) );
+               $this->assertSame( 'Hooked', $obj->getCanonicalName( 123456 ) );
+       }
+
+       /**
+        * @covers NamespaceInfo::getCanonicalIndex
+        */
+       public function testGetCanonicalIndex_HookNamespaces() {
+               $this->setupHookNamespaces();
+               $obj = $this->newObj();
+
+               $this->assertSame( NS_MAIN, $obj->getCanonicalIndex( 'main' ) );
+               $this->assertNull( $obj->getCanonicalIndex( 'media' ) );
+               $this->assertSame( 123456, $obj->getCanonicalIndex( 'hooked' ) );
+       }
+
+       /**
+        * @covers NamespaceInfo::getValidNamespaces
+        */
+       public function testGetValidNamespaces_HookNamespaces() {
+               $this->setupHookNamespaces();
+
+               $this->assertSame(
+                       [ NS_MAIN, NS_TALK, NS_USER, NS_USER_TALK, 123456 ],
+                       $this->newObj()->getValidNamespaces()
+               );
+       }
+
+       // %} End hook namespaces
+
+       // Extra namespaces
+       // %{
+
+       /**
+        * @return NamespaceInfo
+        */
+       private function setupExtraNamespaces() {
+               return $this->newObj( [ 'ExtraNamespaces' =>
+                       [ NS_MAIN => 'No effect', NS_TALK => 'No effect', 1234567 => 'Extra' ]
+               ] );
+       }
+
+       /**
+        * @covers NamespaceInfo::getCanonicalNamespaces
+        */
+       public function testGetCanonicalNamespaces_ExtraNamespaces() {
+               $this->assertSame(
+                       $this->getDefaultNamespaces() + [ 1234567 => 'Extra' ],
+                       $this->setupExtraNamespaces()->getCanonicalNamespaces()
+               );
+       }
+
+       /**
+        * @covers NamespaceInfo::getCanonicalName
+        */
+       public function testGetCanonicalName_ExtraNamespaces() {
+               $obj = $this->setupExtraNamespaces();
+
+               $this->assertSame( '', $obj->getCanonicalName( NS_MAIN ) );
+               $this->assertSame( 'Talk', $obj->getCanonicalName( NS_TALK ) );
+               $this->assertSame( 'Extra', $obj->getCanonicalName( 1234567 ) );
+       }
+
+       /**
+        * @covers NamespaceInfo::getCanonicalIndex
+        */
+       public function testGetCanonicalIndex_ExtraNamespaces() {
+               $obj = $this->setupExtraNamespaces();
+
+               $this->assertNull( $obj->getCanonicalIndex( 'no effect' ) );
+               $this->assertNull( $obj->getCanonicalIndex( 'no_effect' ) );
+               $this->assertSame( 1234567, $obj->getCanonicalIndex( 'extra' ) );
+       }
+
+       /**
+        * @covers NamespaceInfo::getValidNamespaces
+        */
+       public function testGetValidNamespaces_ExtraNamespaces() {
+               $this->assertSame(
+                       [ NS_MAIN, NS_TALK, NS_USER, NS_USER_TALK, 1234567 ],
+                       $this->setupExtraNamespaces()->getValidNamespaces()
+               );
+       }
+
+       // %} End extra namespaces
+
+       // Canonical namespace caching
+       // %{
+
+       /**
+        * @covers NamespaceInfo::getCanonicalNamespaces
+        */
+       public function testGetCanonicalNamespaces_caching() {
+               $obj = $this->newObj();
+
+               // This should cache the values
+               $obj->getCanonicalNamespaces();
+
+               // Now try to alter them through nefarious means
+               $this->setupExtensionNamespaces();
+               $this->setupHookNamespaces();
+
+               // Should have no effect
+               $this->assertSame( $this->getDefaultNamespaces(), $obj->getCanonicalNamespaces() );
+       }
+
+       /**
+        * @covers NamespaceInfo::getCanonicalName
+        */
+       public function testGetCanonicalName_caching() {
+               $obj = $this->newObj();
+
+               // This should cache the values
+               $obj->getCanonicalName( NS_MAIN );
+
+               // Now try to alter them through nefarious means
+               $this->setupExtensionNamespaces();
+               $this->setupHookNamespaces();
+
+               // Should have no effect
+               $this->assertSame( '', $obj->getCanonicalName( NS_MAIN ) );
+               $this->assertSame( 'Media', $obj->getCanonicalName( NS_MEDIA ) );
+               $this->assertFalse( $obj->getCanonicalName( 12345 ) );
+               $this->assertFalse( $obj->getCanonicalName( 123456 ) );
+       }
+
+       /**
+        * @covers NamespaceInfo::getCanonicalIndex
+        */
+       public function testGetCanonicalIndex_caching() {
+               $obj = $this->newObj();
+
+               // This should cache the values
+               $obj->getCanonicalIndex( '' );
+
+               // Now try to alter them through nefarious means
+               $this->setupExtensionNamespaces();
+               $this->setupHookNamespaces();
+
+               // Should have no effect
+               $this->assertSame( NS_MAIN, $obj->getCanonicalIndex( '' ) );
+               $this->assertSame( NS_MEDIA, $obj->getCanonicalIndex( 'media' ) );
+               $this->assertNull( $obj->getCanonicalIndex( 'extended' ) );
+               $this->assertNull( $obj->getCanonicalIndex( 'hooked' ) );
+       }
+
+       /**
+        * @covers NamespaceInfo::getValidNamespaces
+        */
+       public function testGetValidNamespaces_caching() {
+               $obj = $this->newObj();
+
+               // This should cache the values
+               $obj->getValidNamespaces();
+
+               // Now try to alter through nefarious means
+               $this->setupExtensionNamespaces();
+               $this->setupHookNamespaces();
+
+               // Should have no effect
+               $this->assertSame(
+                       [ NS_MAIN, NS_TALK, NS_USER, NS_USER_TALK ],
+                       $obj->getValidNamespaces()
+               );
+       }
+
+       // %} End canonical namespace caching
+
+       // Miscellaneous
+       // %{
+
+       /**
+        * @dataProvider provideGetValidNamespaces_misc
+        * @covers NamespaceInfo::getValidNamespaces
+        *
+        * @param array $namespaces List of namespace indices to return from getCanonicalNamespaces()
+        *   (list is overwritten by a hook, so NS_MAIN doesn't have to be present)
+        * @param array $expected
+        */
+       public function testGetValidNamespaces_misc( array $namespaces, array $expected ) {
+               // Each namespace's name is just its index
+               $this->setTemporaryHook( 'CanonicalNamespaces',
+                       function ( &$canonicalNamespaces ) use ( $namespaces ) {
+                               $canonicalNamespaces = array_combine( $namespaces, $namespaces );
+                       }
+               );
+               $this->assertSame( $expected, $this->newObj()->getValidNamespaces() );
+       }
+
+       public function provideGetValidNamespaces_misc() {
+               return [
+                       'Out of order (T109137)' => [ [ 1, 0 ], [ 0, 1 ] ],
+                       'Alphabetical order' => [ [ 10, 2 ], [ 2, 10 ] ],
+                       'Negative' => [ [ -1000, -500, -2, 0 ], [ 0 ] ],
+               ];
+       }
+
+       // %} End miscellaneous
+       // %} End canonical namespaces
+
+       /**********************************************************************************************
+        * Restriction levels
+        * %{
+        */
+
+       /**
+        * This mock user can only have isAllowed() called on it.
+        *
+        * @param array $groups Groups for the mock user to have
+        * @return User
+        */
+       private function getMockUser( array $groups = [] ) : User {
+               $groups[] = '*';
+
+               $mock = $this->createMock( User::class );
+               $mock->method( 'isAllowed' )->will( $this->returnCallback(
+                       function ( $action ) use ( $groups ) {
+                               global $wgGroupPermissions, $wgRevokePermissions;
+                               if ( $action == '' ) {
+                                       return true;
+                               }
+                               foreach ( $wgRevokePermissions as $group => $rights ) {
+                                       if ( !in_array( $group, $groups ) ) {
+                                               continue;
+                                       }
+                                       if ( isset( $rights[$action] ) && $rights[$action] ) {
+                                               return false;
+                                       }
+                               }
+                               foreach ( $wgGroupPermissions as $group => $rights ) {
+                                       if ( !in_array( $group, $groups ) ) {
+                                               continue;
+                                       }
+                                       if ( isset( $rights[$action] ) && $rights[$action] ) {
+                                               return true;
+                                       }
+                               }
+                               return false;
+                       }
+               ) );
+               $mock->expects( $this->never() )->method( $this->anythingBut( 'isAllowed' ) );
+               return $mock;
+       }
+
+       /**
+        * @dataProvider provideGetRestrictionLevels
+        * @covers NamespaceInfo::getRestrictionLevels
+        *
+        * @param array $expected
+        * @param int $ns
+        * @param User|null $user
+        */
+       public function testGetRestrictionLevels( array $expected, $ns, User $user = null ) {
+               $this->setMwGlobals( [
+                       'wgGroupPermissions' => [
+                               '*' => [ 'edit' => true ],
+                               'autoconfirmed' => [ 'editsemiprotected' => true ],
+                               'sysop' => [
+                                       'editsemiprotected' => true,
+                                       'editprotected' => true,
+                               ],
+                               'privileged' => [ 'privileged' => true ],
+                       ],
+                       'wgRevokePermissions' => [
+                               'noeditsemiprotected' => [ 'editsemiprotected' => true ],
+                       ],
+               ] );
+               $obj = $this->newObj( [
+                       'NamespaceProtection' => [
+                               NS_MAIN => 'autoconfirmed',
+                               NS_USER => 'sysop',
+                               101 => [ 'editsemiprotected', 'privileged' ],
+                       ],
+               ] );
+               $this->assertSame( $expected, $obj->getRestrictionLevels( $ns, $user ) );
+       }
+
+       public function provideGetRestrictionLevels() {
+               return [
+                       'No namespace restriction' => [ [ '', 'autoconfirmed', 'sysop' ], NS_TALK ],
+                       'Restricted to autoconfirmed' => [ [ '', 'sysop' ], NS_MAIN ],
+                       'Restricted to sysop' => [ [ '' ], NS_USER ],
+                       'Restricted to someone in two groups' => [ [ '', 'sysop' ], 101 ],
+                       'No special permissions' => [ [ '' ], NS_TALK, $this->getMockUser() ],
+                       'autoconfirmed' => [
+                               [ '', 'autoconfirmed' ],
+                               NS_TALK,
+                               $this->getMockUser( [ 'autoconfirmed' ] )
+                       ],
+                       'autoconfirmed revoked' => [
+                               [ '' ],
+                               NS_TALK,
+                               $this->getMockUser( [ 'autoconfirmed', 'noeditsemiprotected' ] )
+                       ],
+                       'sysop' => [
+                               [ '', 'autoconfirmed', 'sysop' ],
+                               NS_TALK,
+                               $this->getMockUser( [ 'sysop' ] )
+                       ],
+                       'sysop with autoconfirmed revoked (a bit silly)' => [
+                               [ '', 'sysop' ],
+                               NS_TALK,
+                               $this->getMockUser( [ 'sysop', 'noeditsemiprotected' ] )
+                       ],
+               ];
+       }
+
+       // %} End restriction levels
+}
+
+/**
+ * For really cool vim folding this needs to be at the end:
+ * vim: foldmarker=%{,%} foldmethod=marker
+ */
index d221b43..bbeb068 100644 (file)
@@ -28,6 +28,7 @@ class TitleValueTest extends MediaWikiTestCase {
 
        public function goodConstructorProvider() {
                return [
+                       [ NS_MAIN, '', 'fragment', '', true, false ],
                        [ NS_USER, 'TestThis', 'stuff', '', true, false ],
                        [ NS_USER, 'TestThis', '', 'baz', false, true ],
                ];
@@ -58,7 +59,7 @@ class TitleValueTest extends MediaWikiTestCase {
 
                        [ NS_MAIN, 5, 'fragment', '' ],
                        [ NS_MAIN, null, 'fragment', '' ],
-                       [ NS_MAIN, '', 'fragment', '' ],
+                       [ NS_USER, '', 'fragment', '' ],
                        [ NS_MAIN, 'foo bar', '', '' ],
                        [ NS_MAIN, 'bar_', '', '' ],
                        [ NS_MAIN, '_foo', '', '' ],
index bc0946f..4ef8ea9 100644 (file)
@@ -184,11 +184,12 @@ class BotPasswordTest extends MediaWikiTestCase {
        }
 
        public function testGetPassword() {
+               /** @var BotPassword $bp */
                $bp = TestingAccessWrapper::newFromObject( BotPassword::newFromCentralId( 42, 'BotPassword' ) );
 
                $password = $bp->getPassword();
                $this->assertInstanceOf( Password::class, $password );
-               $this->assertTrue( $password->equals( 'foobaz' ) );
+               $this->assertTrue( $password->verify( 'foobaz' ) );
 
                $bp->centralId = 44;
                $password = $bp->getPassword();
@@ -373,11 +374,12 @@ class BotPasswordTest extends MediaWikiTestCase {
                $this->assertEquals( $bp->getToken(), $bp2->getToken() );
                $this->assertEquals( $bp->getRestrictions(), $bp2->getRestrictions() );
                $this->assertEquals( $bp->getGrants(), $bp2->getGrants() );
+               /** @var Password $pw */
                $pw = TestingAccessWrapper::newFromObject( $bp )->getPassword();
                if ( $password === null ) {
                        $this->assertInstanceOf( InvalidPassword::class, $pw );
                } else {
-                       $this->assertTrue( $pw->equals( $password ) );
+                       $this->assertTrue( $pw->verify( $password ) );
                }
 
                $token = $bp->getToken();
@@ -389,19 +391,21 @@ class BotPasswordTest extends MediaWikiTestCase {
                $bp2 = BotPassword::newFromCentralId( 42, 'TestSave', BotPassword::READ_LATEST );
                $this->assertInstanceOf( BotPassword::class, $bp2 );
                $this->assertEquals( $bp->getToken(), $bp2->getToken() );
+               /** @var Password $pw */
                $pw = TestingAccessWrapper::newFromObject( $bp )->getPassword();
                if ( $password === null ) {
                        $this->assertInstanceOf( InvalidPassword::class, $pw );
                } else {
-                       $this->assertTrue( $pw->equals( $password ) );
+                       $this->assertTrue( $pw->verify( $password ) );
                }
 
                $passwordHash = $passwordFactory->newFromPlaintext( 'XXX' );
                $token = $bp->getToken();
                $this->assertTrue( $bp->save( 'update', $passwordHash ) );
                $this->assertNotEquals( $token, $bp->getToken() );
+               /** @var Password $pw */
                $pw = TestingAccessWrapper::newFromObject( $bp )->getPassword();
-               $this->assertTrue( $pw->equals( 'XXX' ) );
+               $this->assertTrue( $pw->verify( 'XXX' ) );
 
                $this->assertTrue( $bp->delete() );
                $this->assertFalse( $bp->isSaved() );
index 4978b72..ca57c10 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 
 use MediaWiki\Auth\AuthManager;
+use MediaWiki\Block\SystemBlock;
 
 /**
  * @covers PasswordReset
@@ -102,36 +103,42 @@ class PasswordResetTest extends MediaWikiTestCase {
                                'enableEmail' => true,
                                'allowsAuthenticationDataChange' => true,
                                'canEditPrivate' => true,
-                               'block' => new Block( [ 'systemBlock' => 'proxy' ] ),
+                               'block' => new SystemBlock(
+                                       [ 'systemBlock' => 'proxy' ]
+                               ),
                                'globalBlock' => null,
                                'isAllowed' => false,
                        ],
-                       'globally blocked with account creation disabled' => [
+                       'globally blocked with account creation not disabled' => [
                                'passwordResetRoutes' => [ 'username' => true ],
                                'enableEmail' => true,
                                'allowsAuthenticationDataChange' => true,
                                'canEditPrivate' => true,
                                'block' => null,
-                               'globalBlock' => new Block( [ 'systemBlock' => 'global-block', 'createAccount' => true ] ),
-                               'isAllowed' => false,
+                               'globalBlock' => new SystemBlock(
+                                       [ 'systemBlock' => 'global-block' ]
+                               ),
+                               'isAllowed' => true,
                        ],
-                       'globally blocked with account creation not disabled' => [
+                       'blocked via wgSoftBlockRanges' => [
                                'passwordResetRoutes' => [ 'username' => true ],
                                'enableEmail' => true,
                                'allowsAuthenticationDataChange' => true,
                                'canEditPrivate' => true,
-                               'block' => null,
-                               'globalBlock' => new Block( [ 'systemBlock' => 'global-block', 'createAccount' => false ] ),
+                               'block' => new SystemBlock(
+                                       [ 'systemBlock' => 'wgSoftBlockRanges', 'anonOnly' => true ]
+                               ),
+                               'globalBlock' => null,
                                'isAllowed' => true,
                        ],
-                       'blocked via wgSoftBlockRanges' => [
+                       'blocked with an unknown system block type' => [
                                'passwordResetRoutes' => [ 'username' => true ],
                                'enableEmail' => true,
                                'allowsAuthenticationDataChange' => true,
                                'canEditPrivate' => true,
-                               'block' => new Block( [ 'systemBlock' => 'wgSoftBlockRanges', 'anonOnly' => true ] ),
+                               'block' => new SystemBlock( [ 'systemBlock' => 'unknown' ] ),
                                'globalBlock' => null,
-                               'isAllowed' => true,
+                               'isAllowed' => false,
                        ],
                        'all OK' => [
                                'passwordResetRoutes' => [ 'username' => true ],
index 642e8b4..c90e988 100644 (file)
@@ -5,6 +5,7 @@ define( 'NS_UNITTEST_TALK', 5601 );
 
 use MediaWiki\Block\Restriction\PageRestriction;
 use MediaWiki\Block\Restriction\NamespaceRestriction;
+use MediaWiki\Block\SystemBlock;
 use MediaWiki\MediaWikiServices;
 use MediaWiki\User\UserIdentityValue;
 use Wikimedia\TestingAccessWrapper;
@@ -28,7 +29,7 @@ class UserTest extends MediaWikiTestCase {
                $this->setMwGlobals( [
                        'wgGroupPermissions' => [],
                        'wgRevokePermissions' => [],
-                       'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
+                       'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
                ] );
                $this->overrideMwServices();
 
@@ -365,7 +366,6 @@ class UserTest extends MediaWikiTestCase {
         *      - ensure the password is not the same as the username
         *      - ensure the username/password combo isn't forbidden
         * @covers User::checkPasswordValidity()
-        * @covers User::getPasswordValidity()
         * @covers User::isValidPassword()
         */
        public function testCheckPasswordValidity() {
@@ -393,7 +393,6 @@ class UserTest extends MediaWikiTestCase {
                                ],
                        ],
                ] );
-               $this->hideDeprecated( 'User::getPasswordValidity' );
 
                $user = static::getTestUser()->getUser();
 
@@ -404,24 +403,20 @@ class UserTest extends MediaWikiTestCase {
                $this->assertFalse( $user->isValidPassword( 'a' ) );
                $this->assertFalse( $user->checkPasswordValidity( 'a' )->isGood() );
                $this->assertTrue( $user->checkPasswordValidity( 'a' )->isOK() );
-               $this->assertEquals( 'passwordtooshort', $user->getPasswordValidity( 'a' ) );
 
                // Maximum length
                $longPass = str_repeat( 'a', 41 );
                $this->assertFalse( $user->isValidPassword( $longPass ) );
                $this->assertFalse( $user->checkPasswordValidity( $longPass )->isGood() );
                $this->assertFalse( $user->checkPasswordValidity( $longPass )->isOK() );
-               $this->assertEquals( 'passwordtoolong', $user->getPasswordValidity( $longPass ) );
 
                // Matches username
                $this->assertFalse( $user->checkPasswordValidity( $user->getName() )->isGood() );
                $this->assertTrue( $user->checkPasswordValidity( $user->getName() )->isOK() );
-               $this->assertEquals( 'password-name-match', $user->getPasswordValidity( $user->getName() ) );
 
                // On the forbidden list
                $user = User::newFromName( 'Useruser' );
                $this->assertFalse( $user->checkPasswordValidity( 'Passpass' )->isGood() );
-               $this->assertEquals( 'password-login-forbidden', $user->getPasswordValidity( 'Passpass' ) );
        }
 
        /**
@@ -504,20 +499,24 @@ class UserTest extends MediaWikiTestCase {
        }
 
        /**
+        * @covers User::isRegistered
         * @covers User::isLoggedIn
         * @covers User::isAnon
         */
        public function testLoggedIn() {
                $user = $this->getMutableTestUser()->getUser();
+               $this->assertTrue( $user->isRegistered() );
                $this->assertTrue( $user->isLoggedIn() );
                $this->assertFalse( $user->isAnon() );
 
                // Non-existent users are perceived as anonymous
                $user = User::newFromName( 'UTNonexistent' );
+               $this->assertFalse( $user->isRegistered() );
                $this->assertFalse( $user->isLoggedIn() );
                $this->assertTrue( $user->isAnon() );
 
                $user = new User;
+               $this->assertFalse( $user->isRegistered() );
                $this->assertFalse( $user->isLoggedIn() );
                $this->assertTrue( $user->isAnon() );
        }
@@ -617,7 +616,7 @@ class UserTest extends MediaWikiTestCase {
 
                // Confirm that the block has been applied as required.
                $this->assertTrue( $user1->isLoggedIn() );
-               $this->assertTrue( $user1->isBlocked() );
+               $this->assertInstanceOf( Block::class, $user1->getBlock() );
                $this->assertEquals( Block::TYPE_USER, $block->getType() );
                $this->assertTrue( $block->isAutoblocking() );
                $this->assertGreaterThanOrEqual( 1, $block->getId() );
@@ -638,7 +637,7 @@ class UserTest extends MediaWikiTestCase {
                $this->assertNotEquals( $user1->getToken(), $user2->getToken() );
                $this->assertTrue( $user2->isAnon() );
                $this->assertFalse( $user2->isLoggedIn() );
-               $this->assertTrue( $user2->isBlocked() );
+               $this->assertInstanceOf( Block::class, $user2->getBlock() );
                // Non-strict type-check.
                $this->assertEquals( true, $user2->getBlock()->isAutoblocking(), 'Autoblock does not work' );
                // Can't directly compare the objects because of member type differences.
@@ -654,7 +653,7 @@ class UserTest extends MediaWikiTestCase {
                $user3 = User::newFromSession( $request3 );
                $user3->load();
                $this->assertTrue( $user3->isLoggedIn() );
-               $this->assertTrue( $user3->isBlocked() );
+               $this->assertInstanceOf( Block::class, $user3->getBlock() );
                $this->assertEquals( true, $user3->getBlock()->isAutoblocking() ); // Non-strict type-check.
 
                // Clean up.
@@ -694,7 +693,7 @@ class UserTest extends MediaWikiTestCase {
 
                // 2. Test that the cookie IS NOT present.
                $this->assertTrue( $user->isLoggedIn() );
-               $this->assertTrue( $user->isBlocked() );
+               $this->assertInstanceOf( Block::class, $user->getBlock() );
                $this->assertEquals( Block::TYPE_USER, $block->getType() );
                $this->assertTrue( $block->isAutoblocking() );
                $this->assertGreaterThanOrEqual( 1, $user->getBlockId() );
@@ -739,7 +738,7 @@ class UserTest extends MediaWikiTestCase {
 
                // 2. Test the cookie's expiry timestamp.
                $this->assertTrue( $user1->isLoggedIn() );
-               $this->assertTrue( $user1->isBlocked() );
+               $this->assertInstanceOf( Block::class, $user1->getBlock() );
                $this->assertEquals( Block::TYPE_USER, $block->getType() );
                $this->assertTrue( $block->isAutoblocking() );
                $this->assertGreaterThanOrEqual( 1, $user1->getBlockId() );
@@ -757,7 +756,7 @@ class UserTest extends MediaWikiTestCase {
 
                // 3. Change the block's expiry (to 2 hours), and the cookie's should be changed also.
                $newExpiry = wfTimestamp() + 2 * 60 * 60;
-               $block->mExpiry = wfTimestamp( TS_MW, $newExpiry );
+               $block->setExpiry( wfTimestamp( TS_MW, $newExpiry ) );
                $block->update();
                $user2tmp = $this->getTestUser()->getUser();
                $request2 = new FauxRequest();
@@ -783,6 +782,7 @@ class UserTest extends MediaWikiTestCase {
                        RequestContext::getMain()->setRequest( $request );
                        TestingAccessWrapper::newFromObject( $user )->mRequest = $request;
                        $request->getSession()->setUser( $user );
+                       $this->overrideMwServices();
                };
                $this->setMwGlobals( 'wgSoftBlockRanges', [ '10.0.0.0/8' ] );
 
@@ -799,7 +799,7 @@ class UserTest extends MediaWikiTestCase {
                $request->setIP( '10.20.30.40' );
                $setSessionUser( $wgUser, $request );
                $block = $wgUser->getBlock();
-               $this->assertInstanceOf( Block::class, $block );
+               $this->assertInstanceOf( SystemBlock::class, $block );
                $this->assertSame( 'wgSoftBlockRanges', $block->getSystemBlockType() );
 
                // Make sure the block is really soft
@@ -849,7 +849,7 @@ class UserTest extends MediaWikiTestCase {
                $user2->load();
                $this->assertTrue( $user2->isAnon() );
                $this->assertFalse( $user2->isLoggedIn() );
-               $this->assertFalse( $user2->isBlocked() );
+               $this->assertNull( $user2->getBlock() );
 
                // Clean up.
                $block->delete();
@@ -885,7 +885,7 @@ class UserTest extends MediaWikiTestCase {
                $user1 = User::newFromSession( $request1 );
                $user1->mBlock = $block;
                $user1->load();
-               $this->assertTrue( $user1->isBlocked() );
+               $this->assertInstanceOf( Block::class, $user1->getBlock() );
 
                // 2. Create a new request, set the cookie to just the block ID, and the user should
                // still get blocked when they log in again.
@@ -897,7 +897,7 @@ class UserTest extends MediaWikiTestCase {
                $this->assertNotEquals( $user1->getToken(), $user2->getToken() );
                $this->assertTrue( $user2->isAnon() );
                $this->assertFalse( $user2->isLoggedIn() );
-               $this->assertTrue( $user2->isBlocked() );
+               $this->assertInstanceOf( Block::class, $user2->getBlock() );
                $this->assertEquals( true, $user2->getBlock()->isAutoblocking() ); // Non-strict type-check.
 
                // Clean up.
@@ -980,7 +980,7 @@ class UserTest extends MediaWikiTestCase {
                $this->assertFalse( $user->getExperienceLevel() );
        }
 
-       public static function provideIsLocallBlockedProxy() {
+       public static function provideIsLocallyBlockedProxy() {
                return [
                        [ '1.2.3.4', '1.2.3.4' ],
                        [ '1.2.3.4', '1.2.3.0/16' ],
@@ -988,10 +988,12 @@ class UserTest extends MediaWikiTestCase {
        }
 
        /**
-        * @dataProvider provideIsLocallBlockedProxy
+        * @dataProvider provideIsLocallyBlockedProxy
         * @covers User::isLocallyBlockedProxy
         */
        public function testIsLocallyBlockedProxy( $ip, $blockListEntry ) {
+               $this->hideDeprecated( 'User::isLocallyBlockedProxy' );
+
                $this->setMwGlobals(
                        'wgProxyList', []
                );
@@ -1048,6 +1050,75 @@ class UserTest extends MediaWikiTestCase {
                $user = User::newFromId( $id );
                $this->assertTrue( $user->getActorId() > 0, 'Actor ID can be retrieved for user loaded by ID' );
 
+               $user2 = User::newFromActorId( $user->getActorId() );
+               $this->assertEquals( $user->getId(), $user2->getId(),
+                       'User::newFromActorId works for an existing user' );
+
+               $row = $this->db->selectRow( 'user', User::selectFields(), [ 'user_id' => $id ], __METHOD__ );
+               $user = User::newFromRow( $row );
+               $this->assertTrue( $user->getActorId() > 0,
+                       'Actor ID can be retrieved for user loaded with User::selectFields()' );
+
+               $user = User::newFromId( $id );
+               $user->setName( 'UserTestActorId4-renamed' );
+               $user->saveSettings();
+               $this->assertEquals(
+                       $user->getName(),
+                       $this->db->selectField(
+                               'actor', 'actor_name', [ 'actor_id' => $user->getActorId() ], __METHOD__
+                       ),
+                       'User::saveSettings updates actor table for name change'
+               );
+
+               // For sanity
+               $ip = '192.168.12.34';
+               $this->db->delete( 'actor', [ 'actor_name' => $ip ], __METHOD__ );
+
+               $user = User::newFromName( $ip, false );
+               $this->assertFalse( $user->getActorId() > 0, 'Anonymous user has no actor ID by default' );
+               $this->assertTrue( $user->getActorId( $this->db ) > 0,
+                       'Actor ID can be created for an anonymous user' );
+
+               $user = User::newFromName( $ip, false );
+               $this->assertTrue( $user->getActorId() > 0, 'Actor ID can be loaded for an anonymous user' );
+               $user2 = User::newFromActorId( $user->getActorId() );
+               $this->assertEquals( $user->getName(), $user2->getName(),
+                       'User::newFromActorId works for an anonymous user' );
+       }
+
+       /**
+        * Actor tests with SCHEMA_COMPAT_READ_OLD
+        *
+        * The only thing different from testActorId() is the behavior if the actor
+        * row doesn't exist in the DB, since with SCHEMA_COMPAT_READ_NEW that
+        * situation can't happen. But we copy all the other tests too just for good measure.
+        *
+        * @covers User::newFromActorId
+        */
+       public function testActorId_old() {
+               $this->setMwGlobals( [
+                       'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
+               ] );
+               $this->overrideMwServices();
+
+               $domain = MediaWikiServices::getInstance()->getDBLoadBalancer()->getLocalDomainID();
+               $this->hideDeprecated( 'User::selectFields' );
+
+               // Newly-created user has an actor ID
+               $user = User::createNew( 'UserTestActorIdOld1' );
+               $id = $user->getId();
+               $this->assertTrue( $user->getActorId() > 0, 'User::createNew sets an actor ID' );
+
+               $user = User::newFromName( 'UserTestActorIdOld2' );
+               $user->addToDatabase();
+               $this->assertTrue( $user->getActorId() > 0, 'User::addToDatabase sets an actor ID' );
+
+               $user = User::newFromName( 'UserTestActorIdOld1' );
+               $this->assertTrue( $user->getActorId() > 0, 'Actor ID can be retrieved for user loaded by name' );
+
+               $user = User::newFromId( $id );
+               $this->assertTrue( $user->getActorId() > 0, 'Actor ID can be retrieved for user loaded by ID' );
+
                $user2 = User::newFromActorId( $user->getActorId() );
                $this->assertEquals( $user->getId(), $user2->getId(),
                        'User::newFromActorId works for an existing user' );
@@ -1066,7 +1137,7 @@ class UserTest extends MediaWikiTestCase {
                $this->assertFalse( $user->getActorId() > 0, 'No Actor ID by default if none in database' );
                $this->assertTrue( $user->getActorId( $this->db ) > 0, 'Actor ID can be created if none in db' );
 
-               $user->setName( 'UserTestActorId4-renamed' );
+               $user->setName( 'UserTestActorIdOld4-renamed' );
                $user->saveSettings();
                $this->assertEquals(
                        $user->getName(),
@@ -1129,6 +1200,15 @@ class UserTest extends MediaWikiTestCase {
                $this->assertSame( 'Bogus', $test->getName() );
                $this->assertSame( 654321, $test->getActorId() );
 
+               // Loading remote user by name from remote wiki should succeed
+               $test = User::newFromAnyId( null, 'Bogus', null, 'foo' );
+               $this->assertSame( 0, $test->getId() );
+               $this->assertSame( 'Bogus', $test->getName() );
+               $this->assertSame( 0, $test->getActorId() );
+               $test = User::newFromAnyId( 123456, 'Bogus', 654321, 'foo' );
+               $this->assertSame( 0, $test->getId() );
+               $this->assertSame( 0, $test->getActorId() );
+
                // Exceptional cases
                try {
                        User::newFromAnyId( null, null, null );
@@ -1140,6 +1220,13 @@ class UserTest extends MediaWikiTestCase {
                        $this->fail( 'Expected exception not thrown' );
                } catch ( InvalidArgumentException $ex ) {
                }
+
+               // Loading remote user by id from remote wiki should fail
+               try {
+                       User::newFromAnyId( 123456, null, 654321, 'foo' );
+                       $this->fail( 'Expected exception not thrown' );
+               } catch ( InvalidArgumentException $ex ) {
+               }
        }
 
        /**
@@ -1459,7 +1546,7 @@ class UserTest extends MediaWikiTestCase {
                $user = User::newFromSession( $request );
 
                // logged in users should be inmune to cookie block of type ip/range
-               $this->assertFalse( $user->isBlocked() );
+               $this->assertNull( $user->getBlock() );
 
                // cookie is being cleared
                $cookies = $request->response()->getCookies();
@@ -1506,4 +1593,38 @@ class UserTest extends MediaWikiTestCase {
                $updater->setContent( 'main', $content );
                return $updater->saveRevision( CommentStoreComment::newUnsavedComment( $comment ) );
        }
+
+       /**
+        * @covers User::idFromName
+        */
+       public function testExistingIdFromName() {
+               $this->assertTrue(
+                       array_key_exists( $this->user->getName(), User::$idCacheByName ),
+                       'Test user should already be in the id cache.'
+               );
+               $this->assertSame(
+                       $this->user->getId(), User::idFromName( $this->user->getName() ),
+                       'Id is correctly retreived from the cache.'
+               );
+               $this->assertSame(
+                       $this->user->getId(), User::idFromName( $this->user->getName(), User::READ_LATEST ),
+                       'Id is correctly retreived from the database.'
+               );
+       }
+
+       /**
+        * @covers User::idFromName
+        */
+       public function testNonExistingIdFromName() {
+               $this->assertFalse(
+                       array_key_exists( 'NotExisitngUser', User::$idCacheByName ),
+                       'Non exisitng user should not be in the id cache.'
+               );
+               $this->assertSame( null, User::idFromName( 'NotExisitngUser' ) );
+               $this->assertTrue(
+                       array_key_exists( 'NotExisitngUser', User::$idCacheByName ),
+                       'Username will be cached when requested once.'
+               );
+               $this->assertSame( null, User::idFromName( 'NotExisitngUser' ) );
+       }
 }
index a8761e3..f424b21 100644 (file)
@@ -1,5 +1,7 @@
 <?php
 
+use MediaWiki\User\UserIdentityValue;
+
 /**
  * @author Addshore
  *
@@ -14,7 +16,8 @@ class NoWriteWatchedItemStoreUnitTest extends MediaWikiTestCase {
                $noWriteService = new NoWriteWatchedItemStore( $innerService );
 
                $this->setExpectedException( DBReadOnlyError::class );
-               $noWriteService->addWatch( $this->getTestSysop()->getUser(), new TitleValue( 0, 'Foo' ) );
+               $noWriteService->addWatch(
+                       new UserIdentityValue( 1, 'MockUser', 0 ), new TitleValue( 0, 'Foo' ) );
        }
 
        public function testAddWatchBatchForUser() {
@@ -24,7 +27,7 @@ class NoWriteWatchedItemStoreUnitTest extends MediaWikiTestCase {
                $noWriteService = new NoWriteWatchedItemStore( $innerService );
 
                $this->setExpectedException( DBReadOnlyError::class );
-               $noWriteService->addWatchBatchForUser( $this->getTestSysop()->getUser(), [] );
+               $noWriteService->addWatchBatchForUser( new UserIdentityValue( 1, 'MockUser', 0 ), [] );
        }
 
        public function testRemoveWatch() {
@@ -34,7 +37,8 @@ class NoWriteWatchedItemStoreUnitTest extends MediaWikiTestCase {
                $noWriteService = new NoWriteWatchedItemStore( $innerService );
 
                $this->setExpectedException( DBReadOnlyError::class );
-               $noWriteService->removeWatch( $this->getTestSysop()->getUser(), new TitleValue( 0, 'Foo' ) );
+               $noWriteService->removeWatch(
+                       new UserIdentityValue( 1, 'MockUser', 0 ), new TitleValue( 0, 'Foo' ) );
        }
 
        public function testSetNotificationTimestampsForUser() {
@@ -45,7 +49,7 @@ class NoWriteWatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $this->setExpectedException( DBReadOnlyError::class );
                $noWriteService->setNotificationTimestampsForUser(
-                       $this->getTestSysop()->getUser(),
+                       new UserIdentityValue( 1, 'MockUser', 0 ),
                        'timestamp',
                        []
                );
@@ -59,7 +63,7 @@ class NoWriteWatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $this->setExpectedException( DBReadOnlyError::class );
                $noWriteService->updateNotificationTimestamp(
-                       $this->getTestSysop()->getUser(),
+                       new UserIdentityValue( 1, 'MockUser', 0 ),
                        new TitleValue( 0, 'Foo' ),
                        'timestamp'
                );
@@ -73,8 +77,8 @@ class NoWriteWatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $this->setExpectedException( DBReadOnlyError::class );
                $noWriteService->resetNotificationTimestamp(
-                       $this->getTestSysop()->getUser(),
-                       Title::newFromText( 'Foo' )
+                       new UserIdentityValue( 1, 'MockUser', 0 ),
+                       new TitleValue( 0, 'Foo' )
                );
        }
 
@@ -85,7 +89,7 @@ class NoWriteWatchedItemStoreUnitTest extends MediaWikiTestCase {
                $noWriteService = new NoWriteWatchedItemStore( $innerService );
 
                $return = $noWriteService->countWatchedItems(
-                       $this->getTestSysop()->getUser()
+                       new UserIdentityValue( 1, 'MockUser', 0 )
                );
                $this->assertEquals( __METHOD__, $return );
        }
@@ -154,7 +158,7 @@ class NoWriteWatchedItemStoreUnitTest extends MediaWikiTestCase {
                $noWriteService = new NoWriteWatchedItemStore( $innerService );
 
                $return = $noWriteService->getWatchedItem(
-                       $this->getTestSysop()->getUser(),
+                       new UserIdentityValue( 1, 'MockUser', 0 ),
                        new TitleValue( 0, 'Foo' )
                );
                $this->assertEquals( __METHOD__, $return );
@@ -167,7 +171,7 @@ class NoWriteWatchedItemStoreUnitTest extends MediaWikiTestCase {
                $noWriteService = new NoWriteWatchedItemStore( $innerService );
 
                $return = $noWriteService->loadWatchedItem(
-                       $this->getTestSysop()->getUser(),
+                       new UserIdentityValue( 1, 'MockUser', 0 ),
                        new TitleValue( 0, 'Foo' )
                );
                $this->assertEquals( __METHOD__, $return );
@@ -182,7 +186,7 @@ class NoWriteWatchedItemStoreUnitTest extends MediaWikiTestCase {
                $noWriteService = new NoWriteWatchedItemStore( $innerService );
 
                $return = $noWriteService->getWatchedItemsForUser(
-                       $this->getTestSysop()->getUser(),
+                       new UserIdentityValue( 1, 'MockUser', 0 ),
                        []
                );
                $this->assertEquals( __METHOD__, $return );
@@ -195,7 +199,7 @@ class NoWriteWatchedItemStoreUnitTest extends MediaWikiTestCase {
                $noWriteService = new NoWriteWatchedItemStore( $innerService );
 
                $return = $noWriteService->isWatched(
-                       $this->getTestSysop()->getUser(),
+                       new UserIdentityValue( 1, 'MockUser', 0 ),
                        new TitleValue( 0, 'Foo' )
                );
                $this->assertEquals( __METHOD__, $return );
@@ -210,7 +214,7 @@ class NoWriteWatchedItemStoreUnitTest extends MediaWikiTestCase {
                $noWriteService = new NoWriteWatchedItemStore( $innerService );
 
                $return = $noWriteService->getNotificationTimestampsBatch(
-                       $this->getTestSysop()->getUser(),
+                       new UserIdentityValue( 1, 'MockUser', 0 ),
                        [ new TitleValue( 0, 'Foo' ) ]
                );
                $this->assertEquals( __METHOD__, $return );
@@ -225,7 +229,7 @@ class NoWriteWatchedItemStoreUnitTest extends MediaWikiTestCase {
                $noWriteService = new NoWriteWatchedItemStore( $innerService );
 
                $return = $noWriteService->countUnreadNotifications(
-                       $this->getTestSysop()->getUser(),
+                       new UserIdentityValue( 1, 'MockUser', 0 ),
                        88
                );
                $this->assertEquals( __METHOD__, $return );
index 16f2367..0b1d013 100644 (file)
@@ -1,5 +1,7 @@
 <?php
 
+use MediaWiki\User\UserIdentityValue;
+use Wikimedia\Rdbms\IDatabase;
 use Wikimedia\Rdbms\LoadBalancer;
 use Wikimedia\TestingAccessWrapper;
 
@@ -8,8 +10,6 @@ use Wikimedia\TestingAccessWrapper;
  */
 class WatchedItemQueryServiceUnitTest extends MediaWikiTestCase {
 
-       use MediaWikiCoversValidator;
-
        /**
         * @return PHPUnit_Framework_MockObject_MockObject|CommentStore
         */
@@ -78,12 +78,10 @@ class WatchedItemQueryServiceUnitTest extends MediaWikiTestCase {
        }
 
        /**
-        * @return PHPUnit_Framework_MockObject_MockObject|Database
+        * @return PHPUnit_Framework_MockObject_MockObject|IDatabase
         */
        private function getMockDb() {
-               $mock = $this->getMockBuilder( Database::class )
-                       ->disableOriginalConstructor()
-                       ->getMock();
+               $mock = $this->createMock( IDatabase::class );
 
                $mock->expects( $this->any() )
                        ->method( 'makeList' )
@@ -126,7 +124,7 @@ class WatchedItemQueryServiceUnitTest extends MediaWikiTestCase {
        }
 
        /**
-        * @param PHPUnit_Framework_MockObject_MockObject|Database $mockDb
+        * @param PHPUnit_Framework_MockObject_MockObject|IDatabase $mockDb
         * @return PHPUnit_Framework_MockObject_MockObject|LoadBalancer
         */
        private function getMockLoadBalancer( $mockDb ) {
@@ -141,7 +139,6 @@ class WatchedItemQueryServiceUnitTest extends MediaWikiTestCase {
        }
 
        /**
-        * @param PHPUnit_Framework_MockObject_MockObject|Database $mockDb
         * @return PHPUnit_Framework_MockObject_MockObject|WatchedItemStore
         */
        private function getMockWatchedItemStore() {
@@ -158,34 +155,32 @@ class WatchedItemQueryServiceUnitTest extends MediaWikiTestCase {
 
        /**
         * @param int $id
+        * @param string[] $extraMethods Extra methods that are expected might be called
         * @return PHPUnit_Framework_MockObject_MockObject|User
         */
-       private function getMockNonAnonUserWithId( $id ) {
+       private function getMockNonAnonUserWithId( $id, array $extraMethods = [] ) {
                $mock = $this->getMockBuilder( User::class )->getMock();
-               $mock->expects( $this->any() )
-                       ->method( 'isAnon' )
-                       ->will( $this->returnValue( false ) );
-               $mock->expects( $this->any() )
-                       ->method( 'getId' )
-                       ->will( $this->returnValue( $id ) );
+               $mock->method( 'isRegistered' )->willReturn( true );
+               $mock->method( 'getId' )->willReturn( $id );
+               $methods = array_merge( [
+                       'isRegistered',
+                       'getId',
+               ], $extraMethods );
+               $mock->expects( $this->never() )->method( $this->anythingBut( ...$methods ) );
                return $mock;
        }
 
        /**
         * @param int $id
+        * @param string[] $extraMethods Extra methods that are expected might be called
         * @return PHPUnit_Framework_MockObject_MockObject|User
         */
-       private function getMockUnrestrictedNonAnonUserWithId( $id ) {
-               $mock = $this->getMockNonAnonUserWithId( $id );
-               $mock->expects( $this->any() )
-                       ->method( 'isAllowed' )
-                       ->will( $this->returnValue( true ) );
-               $mock->expects( $this->any() )
-                       ->method( 'isAllowedAny' )
-                       ->will( $this->returnValue( true ) );
-               $mock->expects( $this->any() )
-                       ->method( 'useRCPatrol' )
-                       ->will( $this->returnValue( true ) );
+       private function getMockUnrestrictedNonAnonUserWithId( $id, array $extraMethods = [] ) {
+               $mock = $this->getMockNonAnonUserWithId( $id,
+                       array_merge( [ 'isAllowed', 'isAllowedAny', 'useRCPatrol' ], $extraMethods ) );
+               $mock->method( 'isAllowed' )->willReturn( true );
+               $mock->method( 'isAllowedAny' )->willReturn( true );
+               $mock->method( 'useRCPatrol' )->willReturn( true );
                return $mock;
        }
 
@@ -195,19 +190,19 @@ class WatchedItemQueryServiceUnitTest extends MediaWikiTestCase {
         * @return PHPUnit_Framework_MockObject_MockObject|User
         */
        private function getMockNonAnonUserWithIdAndRestrictedPermissions( $id, $notAllowedAction ) {
-               $mock = $this->getMockNonAnonUserWithId( $id );
+               $mock = $this->getMockNonAnonUserWithId( $id,
+                       [ 'isAllowed', 'isAllowedAny', 'useRCPatrol', 'useNPPatrol' ] );
 
-               $mock->expects( $this->any() )
-                       ->method( 'isAllowed' )
+               $mock->method( 'isAllowed' )
                        ->will( $this->returnCallback( function ( $action ) use ( $notAllowedAction ) {
                                return $action !== $notAllowedAction;
                        } ) );
-               $mock->expects( $this->any() )
-                       ->method( 'isAllowedAny' )
-                       ->will( $this->returnCallback( function () use ( $notAllowedAction ) {
-                               $actions = func_get_args();
+               $mock->method( 'isAllowedAny' )
+                       ->will( $this->returnCallback( function ( ...$actions ) use ( $notAllowedAction ) {
                                return !in_array( $notAllowedAction, $actions );
                        } ) );
+               $mock->method( 'useRCPatrol' )->willReturn( false );
+               $mock->method( 'useNPPatrol' )->willReturn( false );
 
                return $mock;
        }
@@ -217,7 +212,8 @@ class WatchedItemQueryServiceUnitTest extends MediaWikiTestCase {
         * @return PHPUnit_Framework_MockObject_MockObject|User
         */
        private function getMockNonAnonUserWithIdAndNoPatrolRights( $id ) {
-               $mock = $this->getMockNonAnonUserWithId( $id );
+               $mock = $this->getMockNonAnonUserWithId( $id,
+                       [ 'isAllowed', 'isAllowedAny', 'useRCPatrol', 'useNPPatrol' ] );
 
                $mock->expects( $this->any() )
                        ->method( 'isAllowed' )
@@ -236,14 +232,6 @@ class WatchedItemQueryServiceUnitTest extends MediaWikiTestCase {
                return $mock;
        }
 
-       private function getMockAnonUser() {
-               $mock = $this->getMockBuilder( User::class )->getMock();
-               $mock->expects( $this->any() )
-                       ->method( 'isAnon' )
-                       ->will( $this->returnValue( true ) );
-               return $mock;
-       }
-
        private function getFakeRow( array $rowValues ) {
                $fakeRow = new stdClass();
                foreach ( $rowValues as $valueName => $value ) {
@@ -1385,7 +1373,7 @@ class WatchedItemQueryServiceUnitTest extends MediaWikiTestCase {
 
                $queryService = $this->newService( $mockDb );
                $user = $this->getMockUnrestrictedNonAnonUserWithId( 1 );
-               $otherUser = $this->getMockUnrestrictedNonAnonUserWithId( 2 );
+               $otherUser = $this->getMockUnrestrictedNonAnonUserWithId( 2, [ 'getOption' ] );
                $otherUser->expects( $this->once() )
                        ->method( 'getOption' )
                        ->with( 'watchlisttoken' )
@@ -1416,7 +1404,7 @@ class WatchedItemQueryServiceUnitTest extends MediaWikiTestCase {
 
                $queryService = $this->newService( $mockDb );
                $user = $this->getMockUnrestrictedNonAnonUserWithId( 1 );
-               $otherUser = $this->getMockUnrestrictedNonAnonUserWithId( 2 );
+               $otherUser = $this->getMockUnrestrictedNonAnonUserWithId( 2, [ 'getOption' ] );
                $otherUser->expects( $this->once() )
                        ->method( 'getOption' )
                        ->with( 'watchlisttoken' )
@@ -1716,7 +1704,8 @@ class WatchedItemQueryServiceUnitTest extends MediaWikiTestCase {
 
                $queryService = $this->newService( $mockDb );
 
-               $items = $queryService->getWatchedItemsForUser( $this->getMockAnonUser() );
+               $items = $queryService->getWatchedItemsForUser(
+                       new UserIdentityValue( 0, 'AnonUser', 0 ) );
                $this->assertEmpty( $items );
        }
 
index 6a383a2..20dbedb 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 
 use MediaWiki\MediaWikiServices;
+use Wikimedia\TestingAccessWrapper;
 
 /**
  * @author Addshore
@@ -199,19 +200,28 @@ class WatchedItemStoreIntegrationTest extends MediaWikiTestCase {
 
                // setNotificationTimestampsForUser specifying a title
                $this->assertTrue(
-                       $store->setNotificationTimestampsForUser( $user, '20200202020202', [ $title ] )
+                       $store->setNotificationTimestampsForUser( $user, '20100202020202', [ $title ] )
                );
                $this->assertEquals(
-                       '20200202020202',
+                       '20100202020202',
                        $store->getWatchedItem( $user, $title )->getNotificationTimestamp()
                );
 
                // setNotificationTimestampsForUser not specifying a title
+               // This will try to use a DeferredUpdate; disable that
+               $mockCallback = function ( $callback ) {
+                       $callback();
+               };
+               $scopedOverride = $store->overrideDeferredUpdatesAddCallableUpdateCallback( $mockCallback );
                $this->assertTrue(
-                       $store->setNotificationTimestampsForUser( $user, '20210202020202' )
+                       $store->setNotificationTimestampsForUser( $user, '20110202020202' )
                );
+               // Because the operation above is normally deferred, it doesn't clear the cache
+               // Clear the cache manually
+               $wrappedStore = TestingAccessWrapper::newFromObject( $store );
+               $wrappedStore->uncacheUser( $user );
                $this->assertEquals(
-                       '20210202020202',
+                       '20110202020202',
                        $store->getWatchedItem( $user, $title )->getNotificationTimestamp()
                );
        }
index 6249c49..82308de 100644 (file)
@@ -1,8 +1,10 @@
 <?php
 use MediaWiki\Linker\LinkTarget;
+use MediaWiki\Revision\RevisionLookup;
+use MediaWiki\Revision\RevisionRecord;
+use MediaWiki\User\UserIdentityValue;
 use Wikimedia\Rdbms\LBFactory;
 use Wikimedia\Rdbms\LoadBalancer;
-use Wikimedia\ScopedCallback;
 use Wikimedia\TestingAccessWrapper;
 
 /**
@@ -89,8 +91,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                        ->getMock();
                $mock->expects( $this->any() )
                        ->method( 'makeKey' )
-                       ->will( $this->returnCallback( function () {
-                               return implode( ':', func_get_args() );
+                       ->will( $this->returnCallback( function ( ...$args ) {
+                               return implode( ':', $args );
                        } ) );
                return $mock;
        }
@@ -109,25 +111,42 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
        }
 
        /**
-        * @param int $id
-        * @return PHPUnit_Framework_MockObject_MockObject|User
+        * Assumes that only getSubjectPage and getTalkPage will ever be called, and everything passed
+        * to them will have namespace 0.
         */
-       private function getMockNonAnonUserWithId( $id ) {
-               $mock = $this->createMock( User::class );
-               $mock->expects( $this->any() )
-                       ->method( 'isAnon' )
-                       ->will( $this->returnValue( false ) );
-               $mock->expects( $this->any() )
-                       ->method( 'getId' )
-                       ->will( $this->returnValue( $id ) );
+       private function getMockNsInfo() : NamespaceInfo {
+               $mock = $this->createMock( NamespaceInfo::class );
+               $mock->method( 'getSubjectPage' )->will( $this->returnArgument( 0 ) );
+               $mock->method( 'getTalkPage' )->will( $this->returnCallback(
+                               function ( $target ) {
+                                       return new TitleValue( 1, $target->getDbKey() );
+                               }
+                       ) );
+               $mock->expects( $this->never() )
+                       ->method( $this->anythingBut( 'getSubjectPage', 'getTalkPage' ) );
                return $mock;
        }
 
        /**
-        * @return User
+        * No methods may be called except provided callbacks, if any.
+        *
+        * @param array $callbacks Keys are method names, values are callbacks
+        * @param array $counts Keys are method names, values are expected number of times to be called
+        *   (default is any number is okay)
         */
-       private function getAnonUser() {
-               return User::newFromName( 'Anon_User' );
+       private function getMockRevisionLookup(
+               array $callbacks = [], array $counts = []
+       ) : RevisionLookup {
+               $mock = $this->createMock( RevisionLookup::class );
+               foreach ( $callbacks as $method => $callback ) {
+                       $count = isset( $counts[$method] ) ? $this->exactly( $counts[$method] ) : $this->any();
+                       $mock->expects( $count )
+                               ->method( $method )
+                               ->will( $this->returnCallback( $callbacks[$method] ) );
+               }
+               $mock->expects( $this->never() )
+                       ->method( $this->anythingBut( ...array_keys( $callbacks ) ) );
+               return $mock;
        }
 
        private function getFakeRow( array $rowValues ) {
@@ -138,24 +157,33 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                return $fakeRow;
        }
 
-       private function newWatchedItemStore(
-               LBFactory $lbFactory,
-               JobQueueGroup $queueGroup,
-               HashBagOStuff $cache,
-               ReadOnlyMode $readOnlyMode
-       ) {
+       /**
+        * @param array $mocks Associative array providing mocks to use when constructing the
+        *   WatchedItemStore. Anything not provided will fall back to a default. Valid keys:
+        *     * lbFactory
+        *     * db
+        *     * queueGroup
+        *     * cache
+        *     * readOnlyMode
+        *     * nsInfo
+        *     * revisionLookup
+        */
+       private function newWatchedItemStore( array $mocks = [] ) : WatchedItemStore {
                return new WatchedItemStore(
-                       $lbFactory,
-                       $queueGroup,
+                       $mocks['lbFactory'] ??
+                               $this->getMockLBFactory( $mocks['db'] ?? $this->getMockDb() ),
+                       $mocks['queueGroup'] ?? $this->getMockJobQueueGroup(),
                        new HashBagOStuff(),
-                       $cache,
-                       $readOnlyMode,
-                       1000
+                       $mocks['cache'] ?? $this->getMockCache(),
+                       $mocks['readOnlyMode'] ?? $this->getMockReadOnlyMode(),
+                       1000,
+                       $mocks['nsInfo'] ?? $this->getMockNsInfo(),
+                       $mocks['revisionLookup'] ?? $this->getMockRevisionLookup()
                );
        }
 
        public function testClearWatchedItems() {
-               $user = $this->getMockNonAnonUserWithId( 7 );
+               $user = new UserIdentityValue( 7, 'MockUser', 0 );
 
                $mockDb = $this->getMockDb();
                $mockDb->expects( $this->once() )
@@ -184,12 +212,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                        ->method( 'delete' )
                        ->with( 'RM-KEY' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
                TestingAccessWrapper::newFromObject( $store )
                        ->cacheIndex = [ 0 => [ 'F' => [ 7 => 'RM-KEY', 9 => 'KEEP-KEY' ] ] ];
 
@@ -197,7 +220,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
        }
 
        public function testClearWatchedItems_tooManyItemsWatched() {
-               $user = $this->getMockNonAnonUserWithId( 7 );
+               $user = new UserIdentityValue( 7, 'MockUser', 0 );
 
                $mockDb = $this->getMockDb();
                $mockDb->expects( $this->once() )
@@ -217,18 +240,13 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'set' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertFalse( $store->clearUserWatchedItems( $user ) );
        }
 
        public function testCountWatchedItems() {
-               $user = $this->getMockNonAnonUserWithId( 1 );
+               $user = new UserIdentityValue( 1, 'MockUser', 0 );
 
                $mockDb = $this->getMockDb();
                $mockDb->expects( $this->exactly( 1 ) )
@@ -248,12 +266,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'set' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertEquals( 12, $store->countWatchedItems( $user ) );
        }
@@ -280,12 +293,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'set' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertEquals( 7, $store->countWatchers( $titleValue ) );
        }
@@ -333,12 +341,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'set' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $expected = [
                        0 => [ 'SomeDbKey' => 100, 'OtherDbKey' => 300 ],
@@ -401,12 +404,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'set' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $expected = [
                        0 => [ 'SomeDbKey' => 100, 'OtherDbKey' => 300 ],
@@ -451,12 +449,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'get' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertEquals( 7, $store->countVisitingWatchers( $titleValue, '111' ) );
        }
@@ -534,12 +527,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'set' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $expected = [
                        0 => [ 'SomeDbKey' => 100, 'OtherDbKey' => 300 ],
@@ -640,12 +628,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'set' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $expected = [
                        0 => [
@@ -695,12 +678,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'set' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $expected = [
                        0 => [ 'SomeDbKey' => 0, 'OtherDbKey' => 0 ],
@@ -713,7 +691,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
        }
 
        public function testCountUnreadNotifications() {
-               $user = $this->getMockNonAnonUserWithId( 1 );
+               $user = new UserIdentityValue( 1, 'MockUser', 0 );
 
                $mockDb = $this->getMockDb();
                $mockDb->expects( $this->exactly( 1 ) )
@@ -734,12 +712,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'get' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertEquals( 9, $store->countUnreadNotifications( $user ) );
        }
@@ -748,7 +721,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
         * @dataProvider provideIntWithDbUnsafeVersion
         */
        public function testCountUnreadNotifications_withUnreadLimit_overLimit( $limit ) {
-               $user = $this->getMockNonAnonUserWithId( 1 );
+               $user = new UserIdentityValue( 1, 'MockUser', 0 );
 
                $mockDb = $this->getMockDb();
                $mockDb->expects( $this->exactly( 1 ) )
@@ -770,12 +743,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'get' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertSame(
                        true,
@@ -787,7 +755,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
         * @dataProvider provideIntWithDbUnsafeVersion
         */
        public function testCountUnreadNotifications_withUnreadLimit_underLimit( $limit ) {
-               $user = $this->getMockNonAnonUserWithId( 1 );
+               $user = new UserIdentityValue( 1, 'MockUser', 0 );
 
                $mockDb = $this->getMockDb();
                $mockDb->expects( $this->exactly( 1 ) )
@@ -809,12 +777,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'get' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertEquals(
                        9,
@@ -841,16 +804,11 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                        )
                        ->will( $this->returnValue( new FakeResultWrapper( [] ) ) );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $this->getMockCache(),
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb ] );
 
                $store->duplicateEntry(
-                       Title::newFromText( 'Old_Title' ),
-                       Title::newFromText( 'New_Title' )
+                       new TitleValue( 0, 'Old_Title' ),
+                       new TitleValue( 0, 'New_Title' )
                );
        }
 
@@ -901,16 +859,11 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'get' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $store->duplicateEntry(
-                       Title::newFromText( 'Old_Title' ),
-                       Title::newFromText( 'New_Title' )
+                       new TitleValue( 0, 'Old_Title' ),
+                       new TitleValue( 0, 'New_Title' )
                );
        }
 
@@ -949,22 +902,17 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'get' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $store->duplicateAllAssociatedEntries(
-                       Title::newFromText( 'Old_Title' ),
-                       Title::newFromText( 'New_Title' )
+                       new TitleValue( 0, 'Old_Title' ),
+                       new TitleValue( 0, 'New_Title' )
                );
        }
 
        public function provideLinkTargetPairs() {
                return [
-                       [ Title::newFromText( 'Old_Title' ), Title::newFromText( 'New_Title' ) ],
+                       [ new TitleValue( 0, 'Old_Title' ), new TitleValue( 0, 'New_Title' ) ],
                        [ new TitleValue( 0, 'Old_Title' ),  new TitleValue( 0, 'New_Title' ) ],
                ];
        }
@@ -1044,12 +992,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'get' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $store->duplicateAllAssociatedEntries(
                        $oldTarget,
@@ -1078,16 +1021,11 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                        ->method( 'delete' )
                        ->with( '0:Some_Page:1' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $store->addWatch(
-                       $this->getMockNonAnonUserWithId( 1 ),
-                       Title::newFromText( 'Some_Page' )
+                       new UserIdentityValue( 1, 'MockUser', 0 ),
+                       new TitleValue( 0, 'Some_Page' )
                );
        }
 
@@ -1100,30 +1038,21 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )
                        ->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $store->addWatch(
-                       $this->getAnonUser(),
-                       Title::newFromText( 'Some_Page' )
+                       new UserIdentityValue( 0, 'AnonUser', 0 ),
+                       new TitleValue( 0, 'Some_Page' )
                );
        }
 
        public function testAddWatchBatchForUser_readOnlyDBReturnsFalse() {
                $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $this->getMockDb() ),
-                       $this->getMockJobQueueGroup(),
-                       $this->getMockCache(),
-                       $this->getMockReadOnlyMode( true )
-               );
+                       [ 'readOnlyMode' => $this->getMockReadOnlyMode( true ) ] );
 
                $this->assertFalse(
                        $store->addWatchBatchForUser(
-                               $this->getMockNonAnonUserWithId( 1 ),
+                               new UserIdentityValue( 1, 'MockUser', 0 ),
                                [ new TitleValue( 0, 'Some_Page' ), new TitleValue( 1, 'Some_Page' ) ]
                        )
                );
@@ -1165,14 +1094,9 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                        ->method( 'delete' )
                        ->with( '1:Some_Page:1' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
-               $mockUser = $this->getMockNonAnonUserWithId( 1 );
+               $mockUser = new UserIdentityValue( 1, 'MockUser', 0 );
 
                $this->assertTrue(
                        $store->addWatchBatchForUser(
@@ -1191,23 +1115,18 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )
                        ->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertFalse(
                        $store->addWatchBatchForUser(
-                               $this->getAnonUser(),
+                               new UserIdentityValue( 0, 'AnonUser', 0 ),
                                [ new TitleValue( 0, 'Other_Page' ) ]
                        )
                );
        }
 
        public function testAddWatchBatchReturnsTrue_whenGivenEmptyList() {
-               $user = $this->getMockNonAnonUserWithId( 1 );
+               $user = new UserIdentityValue( 1, 'MockUser', 0 );
                $mockDb = $this->getMockDb();
                $mockDb->expects( $this->never() )
                        ->method( 'insert' );
@@ -1216,12 +1135,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )
                        ->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertTrue(
                        $store->addWatchBatchForUser( $user, [] )
@@ -1252,15 +1166,10 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                                '0:SomeDbKey:1'
                        );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $watchedItem = $store->loadWatchedItem(
-                       $this->getMockNonAnonUserWithId( 1 ),
+                       new UserIdentityValue( 1, 'MockUser', 0 ),
                        new TitleValue( 0, 'SomeDbKey' )
                );
                $this->assertInstanceOf( WatchedItem::class, $watchedItem );
@@ -1288,16 +1197,11 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'get' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertFalse(
                        $store->loadWatchedItem(
-                               $this->getMockNonAnonUserWithId( 1 ),
+                               new UserIdentityValue( 1, 'MockUser', 0 ),
                                new TitleValue( 0, 'SomeDbKey' )
                        )
                );
@@ -1312,16 +1216,11 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'get' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertFalse(
                        $store->loadWatchedItem(
-                               $this->getAnonUser(),
+                               new UserIdentityValue( 0, 'AnonUser', 0 ),
                                new TitleValue( 0, 'SomeDbKey' )
                        )
                );
@@ -1362,18 +1261,12 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                                [ '1:SomeDbKey:1' ]
                        );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
-               $titleValue = new TitleValue( 0, 'SomeDbKey' );
                $this->assertTrue(
                        $store->removeWatch(
-                               $this->getMockNonAnonUserWithId( 1 ),
-                               Title::newFromTitleValue( $titleValue )
+                               new UserIdentityValue( 1, 'MockUser', 0 ),
+                               new TitleValue( 0, 'SomeDbKey' )
                        )
                );
        }
@@ -1414,18 +1307,12 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                                [ '1:SomeDbKey:1' ]
                        );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
-               $titleValue = new TitleValue( 0, 'SomeDbKey' );
                $this->assertFalse(
                        $store->removeWatch(
-                               $this->getMockNonAnonUserWithId( 1 ),
-                               Title::newFromTitleValue( $titleValue )
+                               new UserIdentityValue( 1, 'MockUser', 0 ),
+                               new TitleValue( 0, 'SomeDbKey' )
                        )
                );
        }
@@ -1440,16 +1327,11 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )
                        ->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertFalse(
                        $store->removeWatch(
-                               $this->getAnonUser(),
+                               new UserIdentityValue( 0, 'AnonUser', 0 ),
                                new TitleValue( 0, 'SomeDbKey' )
                        )
                );
@@ -1486,15 +1368,10 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                                '0:SomeDbKey:1'
                        );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $watchedItem = $store->getWatchedItem(
-                       $this->getMockNonAnonUserWithId( 1 ),
+                       new UserIdentityValue( 1, 'MockUser', 0 ),
                        new TitleValue( 0, 'SomeDbKey' )
                );
                $this->assertInstanceOf( WatchedItem::class, $watchedItem );
@@ -1508,7 +1385,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockDb->expects( $this->never() )
                        ->method( 'selectRow' );
 
-               $mockUser = $this->getMockNonAnonUserWithId( 1 );
+               $mockUser = new UserIdentityValue( 1, 'MockUser', 0 );
                $linkTarget = new TitleValue( 0, 'SomeDbKey' );
                $cachedItem = new WatchedItem( $mockUser, $linkTarget, '20151212010101' );
 
@@ -1522,12 +1399,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                        )
                        ->will( $this->returnValue( $cachedItem ) );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertEquals(
                        $cachedItem,
@@ -1561,16 +1433,11 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                        ->with( '0:SomeDbKey:1' )
                        ->will( $this->returnValue( false ) );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertFalse(
                        $store->getWatchedItem(
-                               $this->getMockNonAnonUserWithId( 1 ),
+                               new UserIdentityValue( 1, 'MockUser', 0 ),
                                new TitleValue( 0, 'SomeDbKey' )
                        )
                );
@@ -1586,16 +1453,11 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'get' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertFalse(
                        $store->getWatchedItem(
-                               $this->getAnonUser(),
+                               new UserIdentityValue( 0, 'AnonUser', 0 ),
                                new TitleValue( 0, 'SomeDbKey' )
                        )
                );
@@ -1628,13 +1490,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'get' );
                $mockCache->expects( $this->never() )->method( 'set' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
-               $user = $this->getMockNonAnonUserWithId( 1 );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
+               $user = new UserIdentityValue( 1, 'MockUser', 0 );
 
                $watchedItems = $store->getWatchedItemsForUser( $user );
 
@@ -1667,7 +1524,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockDb = $this->getMockDb();
                $mockCache = $this->getMockCache();
                $mockLoadBalancer = $this->getMockLBFactory( $mockDb, $dbType );
-               $user = $this->getMockNonAnonUserWithId( 1 );
+               $user = new UserIdentityValue( 1, 'MockUser', 0 );
 
                $mockDb->expects( $this->once() )
                        ->method( 'select' )
@@ -1681,11 +1538,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                        ->will( $this->returnValue( [] ) );
 
                $store = $this->newWatchedItemStore(
-                       $mockLoadBalancer,
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+                       [ 'lbFactory' => $mockLoadBalancer, 'cache' => $mockCache ] );
 
                $watchedItems = $store->getWatchedItemsForUser(
                        $user,
@@ -1695,16 +1548,11 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
        }
 
        public function testGetWatchedItemsForUser_badSortOptionThrowsException() {
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $this->getMockDb() ),
-                       $this->getMockJobQueueGroup(),
-                       $this->getMockCache(),
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore();
 
                $this->setExpectedException( InvalidArgumentException::class );
                $store->getWatchedItemsForUser(
-                       $this->getMockNonAnonUserWithId( 1 ),
+                       new UserIdentityValue( 1, 'MockUser', 0 ),
                        [ 'sort' => 'foo' ]
                );
        }
@@ -1738,16 +1586,11 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                                '0:SomeDbKey:1'
                        );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertTrue(
                        $store->isWatched(
-                               $this->getMockNonAnonUserWithId( 1 ),
+                               new UserIdentityValue( 1, 'MockUser', 0 ),
                                new TitleValue( 0, 'SomeDbKey' )
                        )
                );
@@ -1776,16 +1619,11 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                        ->with( '0:SomeDbKey:1' )
                        ->will( $this->returnValue( false ) );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertFalse(
                        $store->isWatched(
-                               $this->getMockNonAnonUserWithId( 1 ),
+                               new UserIdentityValue( 1, 'MockUser', 0 ),
                                new TitleValue( 0, 'SomeDbKey' )
                        )
                );
@@ -1801,16 +1639,11 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'get' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertFalse(
                        $store->isWatched(
-                               $this->getAnonUser(),
+                               new UserIdentityValue( 0, 'AnonUser', 0 ),
                                new TitleValue( 0, 'SomeDbKey' )
                        )
                );
@@ -1870,19 +1703,15 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'set' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertEquals(
                        [
                                0 => [ 'SomeDbKey' => '20151212010101', ],
                                1 => [ 'AnotherDbKey' => null, ],
                        ],
-                       $store->getNotificationTimestampsBatch( $this->getMockNonAnonUserWithId( 1 ), $targets )
+                       $store->getNotificationTimestampsBatch(
+                               new UserIdentityValue( 1, 'MockUser', 0 ), $targets )
                );
        }
 
@@ -1922,18 +1751,14 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'set' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertEquals(
                        [
                                0 => [ 'OtherDbKey' => false, ],
                        ],
-                       $store->getNotificationTimestampsBatch( $this->getMockNonAnonUserWithId( 1 ), $targets )
+                       $store->getNotificationTimestampsBatch(
+                               new UserIdentityValue( 1, 'MockUser', 0 ), $targets )
                );
        }
 
@@ -1943,7 +1768,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                        new TitleValue( 1, 'AnotherDbKey' ),
                ];
 
-               $user = $this->getMockNonAnonUserWithId( 1 );
+               $user = new UserIdentityValue( 1, 'MockUser', 0 );
                $cachedItem = new WatchedItem( $user, $targets[0], '20151212010101' );
 
                $mockDb = $this->getMockDb();
@@ -1985,12 +1810,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'set' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertEquals(
                        [
@@ -2007,7 +1827,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                        new TitleValue( 1, 'AnotherDbKey' ),
                ];
 
-               $user = $this->getMockNonAnonUserWithId( 1 );
+               $user = new UserIdentityValue( 1, 'MockUser', 0 );
                $cachedItems = [
                        new WatchedItem( $user, $targets[0], '20151212010101' ),
                        new WatchedItem( $user, $targets[1], null ),
@@ -2027,12 +1847,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'set' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertEquals(
                        [
@@ -2055,19 +1870,15 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache = $this->getMockCache();
                $mockCache->expects( $this->never() )->method( $this->anything() );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertEquals(
                        [
                                0 => [ 'SomeDbKey' => false, ],
                                1 => [ 'AnotherDbKey' => false, ],
                        ],
-                       $store->getNotificationTimestampsBatch( $this->getAnonUser(), $targets )
+                       $store->getNotificationTimestampsBatch(
+                               new UserIdentityValue( 0, 'AnonUser', 0 ), $targets )
                );
        }
 
@@ -2081,17 +1892,12 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'set' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertFalse(
                        $store->resetNotificationTimestamp(
-                               $this->getAnonUser(),
-                               Title::newFromText( 'SomeDbKey' )
+                               new UserIdentityValue( 0, 'AnonUser', 0 ),
+                               new TitleValue( 0, 'SomeDbKey' )
                        )
                );
        }
@@ -2116,24 +1922,19 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'set' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertFalse(
                        $store->resetNotificationTimestamp(
-                               $this->getMockNonAnonUserWithId( 1 ),
-                               Title::newFromText( 'SomeDbKey' )
+                               new UserIdentityValue( 1, 'MockUser', 0 ),
+                               new TitleValue( 0, 'SomeDbKey' )
                        )
                );
        }
 
        public function testResetNotificationTimestamp_item() {
-               $user = $this->getMockNonAnonUserWithId( 1 );
-               $title = Title::newFromText( 'SomeDbKey' );
+               $user = new UserIdentityValue( 1, 'MockUser', 0 );
+               $title = new TitleValue( 0, 'SomeDbKey' );
 
                $mockDb = $this->getMockDb();
                $mockDb->expects( $this->once() )
@@ -2170,12 +1971,22 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                                // don't run
                        } );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $mockQueueGroup,
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               // We don't care if these methods actually do anything here
+               $mockRevisionLookup = $this->getMockRevisionLookup( [
+                       'getRevisionByTitle' => function () {
+                               return null;
+                       },
+                       'getTimestampFromId' => function () {
+                               return '00000000000000';
+                       },
+               ] );
+
+               $store = $this->newWatchedItemStore( [
+                       'db' => $mockDb,
+                       'queueGroup' => $mockQueueGroup,
+                       'cache' => $mockCache,
+                       'revisionLookup' => $mockRevisionLookup,
+               ] );
 
                $this->assertTrue(
                        $store->resetNotificationTimestamp(
@@ -2186,8 +1997,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
        }
 
        public function testResetNotificationTimestamp_noItemForced() {
-               $user = $this->getMockNonAnonUserWithId( 1 );
-               $title = Title::newFromText( 'SomeDbKey' );
+               $user = new UserIdentityValue( 1, 'MockUser', 0 );
+               $title = new TitleValue( 0, 'SomeDbKey' );
 
                $mockDb = $this->getMockDb();
                $mockDb->expects( $this->never() )
@@ -2201,12 +2012,23 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                        ->with( '0:SomeDbKey:1' );
 
                $mockQueueGroup = $this->getMockJobQueueGroup();
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $mockQueueGroup,
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+
+               // We don't care if these methods actually do anything here
+               $mockRevisionLookup = $this->getMockRevisionLookup( [
+                       'getRevisionByTitle' => function () {
+                               return null;
+                       },
+                       'getTimestampFromId' => function () {
+                               return '00000000000000';
+                       },
+               ] );
+
+               $store = $this->newWatchedItemStore( [
+                       'db' => $mockDb,
+                       'queueGroup' => $mockQueueGroup,
+                       'cache' => $mockCache,
+                       'revisionLookup' => $mockRevisionLookup,
+               ] );
 
                $mockQueueGroup->expects( $this->any() )
                        ->method( 'lazyPush' )
@@ -2223,26 +2045,6 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                );
        }
 
-       /**
-        * @param string $text
-        * @param int $ns
-        *
-        * @return PHPUnit_Framework_MockObject_MockObject|Title
-        */
-       private function getMockTitle( $text, $ns = 0 ) {
-               $title = $this->createMock( Title::class );
-               $title->expects( $this->any() )
-                       ->method( 'getText' )
-                       ->will( $this->returnValue( str_replace( '_', ' ', $text ) ) );
-               $title->expects( $this->any() )
-                       ->method( 'getDbKey' )
-                       ->will( $this->returnValue( str_replace( '_', ' ', $text ) ) );
-               $title->expects( $this->any() )
-                       ->method( 'getNamespace' )
-                       ->will( $this->returnValue( $ns ) );
-               return $title;
-       }
-
        private function verifyCallbackJob(
                ActivityUpdateJob $job,
                LinkTarget $expectedTitle,
@@ -2262,13 +2064,9 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
        }
 
        public function testResetNotificationTimestamp_oldidSpecifiedLatestRevisionForced() {
-               $user = $this->getMockNonAnonUserWithId( 1 );
+               $user = new UserIdentityValue( 1, 'MockUser', 0 );
                $oldid = 22;
-               $title = $this->getMockTitle( 'SomeTitle' );
-               $title->expects( $this->once() )
-                       ->method( 'getNextRevisionID' )
-                       ->with( $oldid )
-                       ->will( $this->returnValue( false ) );
+               $title = new TitleValue( 0, 'SomeTitle' );
 
                $mockDb = $this->getMockDb();
                $mockDb->expects( $this->never() )
@@ -2282,12 +2080,35 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                        ->with( '0:SomeTitle:1' );
 
                $mockQueueGroup = $this->getMockJobQueueGroup();
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $mockQueueGroup,
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+
+               $mockRevisionRecord = $this->createMock( RevisionRecord::class );
+               $mockRevisionRecord->expects( $this->never() )->method( $this->anything() );
+
+               $mockRevisionLookup = $this->getMockRevisionLookup( [
+                       'getTimestampFromId' => function () {
+                               return '00000000000000';
+                       },
+                       'getRevisionById' => function ( $id, $flags ) use ( $oldid, $mockRevisionRecord ) {
+                               $this->assertSame( $oldid, $id );
+                               $this->assertSame( 0, $flags );
+                               return $mockRevisionRecord;
+                       },
+                       'getNextRevision' =>
+                       function ( $oldRev, $titleArg ) use ( $mockRevisionRecord, $title ) {
+                               $this->assertSame( $mockRevisionRecord, $oldRev );
+                               $this->assertSame( $title, $titleArg );
+                               return false;
+                       },
+               ], [
+                       'getNextRevision' => 1,
+               ] );
+
+               $store = $this->newWatchedItemStore( [
+                       'db' => $mockDb,
+                       'queueGroup' => $mockQueueGroup,
+                       'cache' => $mockCache,
+                       'revisionLookup' => $mockRevisionLookup,
+               ] );
 
                $mockQueueGroup->expects( $this->any() )
                        ->method( 'lazyPush' )
@@ -2315,13 +2136,15 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
        }
 
        public function testResetNotificationTimestamp_oldidSpecifiedNotLatestRevisionForced() {
-               $user = $this->getMockNonAnonUserWithId( 1 );
+               $user = new UserIdentityValue( 1, 'MockUser', 0 );
                $oldid = 22;
-               $title = $this->getMockTitle( 'SomeDbKey' );
-               $title->expects( $this->once() )
-                       ->method( 'getNextRevisionID' )
-                       ->with( $oldid )
-                       ->will( $this->returnValue( 33 ) );
+               $title = new TitleValue( 0, 'SomeDbKey' );
+
+               $mockRevision = $this->createMock( RevisionRecord::class );
+               $mockRevision->expects( $this->never() )->method( $this->anything() );
+
+               $mockNextRevision = $this->createMock( RevisionRecord::class );
+               $mockNextRevision->expects( $this->never() )->method( $this->anything() );
 
                $mockDb = $this->getMockDb();
                $mockDb->expects( $this->once() )
@@ -2349,12 +2172,34 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                        ->with( '0:SomeDbKey:1' );
 
                $mockQueueGroup = $this->getMockJobQueueGroup();
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $mockQueueGroup,
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+
+               $mockRevisionLookup = $this->getMockRevisionLookup(
+                       [
+                               'getTimestampFromId' => function ( $oldidParam ) use ( $oldid ) {
+                                       $this->assertSame( $oldid, $oldidParam );
+                               },
+                               'getRevisionById' => function ( $id ) use ( $oldid, $mockRevision ) {
+                                       $this->assertSame( $oldid, $id );
+                                       return $mockRevision;
+                               },
+                               'getNextRevision' =>
+                               function ( RevisionRecord $rev ) use ( $mockRevision, $mockNextRevision ) {
+                                       $this->assertSame( $mockRevision, $rev );
+                                       return $mockNextRevision;
+                               },
+                       ],
+                       [
+                               'getTimestampFromId' => 2,
+                               'getRevisionById' => 1,
+                               'getNextRevision' => 1,
+                       ]
+               );
+               $store = $this->newWatchedItemStore( [
+                       'db' => $mockDb,
+                       'queueGroup' => $mockQueueGroup,
+                       'cache' => $mockCache,
+                       'revisionLookup' => $mockRevisionLookup,
+               ] );
 
                $mockQueueGroup->expects( $this->any() )
                        ->method( 'lazyPush' )
@@ -2371,15 +2216,6 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                                }
                        ) );
 
-               $getTimestampCallCounter = 0;
-               $scopedOverrideRevision = $store->overrideRevisionGetTimestampFromIdCallback(
-                       function ( $titleParam, $oldidParam ) use ( &$getTimestampCallCounter, $title, $oldid ) {
-                               $getTimestampCallCounter++;
-                               $this->assertEquals( $title, $titleParam );
-                               $this->assertEquals( $oldid, $oldidParam );
-                       }
-               );
-
                $this->assertTrue(
                        $store->resetNotificationTimestamp(
                                $user,
@@ -2388,19 +2224,12 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                                $oldid
                        )
                );
-               $this->assertEquals( 2, $getTimestampCallCounter );
-
-               ScopedCallback::consume( $scopedOverrideRevision );
        }
 
        public function testResetNotificationTimestamp_notWatchedPageForced() {
-               $user = $this->getMockNonAnonUserWithId( 1 );
+               $user = new UserIdentityValue( 1, 'MockUser', 0 );
                $oldid = 22;
-               $title = $this->getMockTitle( 'SomeDbKey' );
-               $title->expects( $this->once() )
-                       ->method( 'getNextRevisionID' )
-                       ->with( $oldid )
-                       ->will( $this->returnValue( 33 ) );
+               $title = new TitleValue( 0, 'SomeDbKey' );
 
                $mockDb = $this->getMockDb();
                $mockDb->expects( $this->once() )
@@ -2424,13 +2253,42 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                        ->with( '0:SomeDbKey:1' );
 
                $mockQueueGroup = $this->getMockJobQueueGroup();
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $mockQueueGroup,
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
+
+               $mockRevision = $this->createMock( RevisionRecord::class );
+               $mockRevision->expects( $this->never() )->method( $this->anything() );
+
+               $mockNextRevision = $this->createMock( RevisionRecord::class );
+               $mockNextRevision->expects( $this->never() )->method( $this->anything() );
+
+               $mockRevisionLookup = $this->getMockRevisionLookup(
+                       [
+                               'getTimestampFromId' => function ( $oldidParam ) use ( $oldid ) {
+                                       $this->assertSame( $oldid, $oldidParam );
+                               },
+                               'getRevisionById' => function ( $id ) use ( $oldid, $mockRevision ) {
+                                       $this->assertSame( $oldid, $id );
+                                       return $mockRevision;
+                               },
+                               'getNextRevision' =>
+                               function ( RevisionRecord $rev ) use ( $mockRevision, $mockNextRevision ) {
+                                       $this->assertSame( $mockRevision, $rev );
+                                       return $mockNextRevision;
+                               },
+                       ],
+                       [
+                               'getTimestampFromId' => 1,
+                               'getRevisionById' => 1,
+                               'getNextRevision' => 1,
+                       ]
                );
 
+               $store = $this->newWatchedItemStore( [
+                       'db' => $mockDb,
+                       'queueGroup' => $mockQueueGroup,
+                       'cache' => $mockCache,
+                       'revisionLookup' => $mockRevisionLookup,
+               ] );
+
                $mockQueueGroup->expects( $this->any() )
                        ->method( 'lazyPush' )
                        ->will( $this->returnCallback(
@@ -2457,13 +2315,9 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
        }
 
        public function testResetNotificationTimestamp_futureNotificationTimestampForced() {
-               $user = $this->getMockNonAnonUserWithId( 1 );
+               $user = new UserIdentityValue( 1, 'MockUser', 0 );
                $oldid = 22;
-               $title = $this->getMockTitle( 'SomeDbKey' );
-               $title->expects( $this->once() )
-                       ->method( 'getNextRevisionID' )
-                       ->with( $oldid )
-                       ->will( $this->returnValue( 33 ) );
+               $title = new TitleValue( 0, 'SomeDbKey' );
 
                $mockDb = $this->getMockDb();
                $mockDb->expects( $this->once() )
@@ -2491,13 +2345,42 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                        ->with( '0:SomeDbKey:1' );
 
                $mockQueueGroup = $this->getMockJobQueueGroup();
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $mockQueueGroup,
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
+
+               $mockRevision = $this->createMock( RevisionRecord::class );
+               $mockRevision->expects( $this->never() )->method( $this->anything() );
+
+               $mockNextRevision = $this->createMock( RevisionRecord::class );
+               $mockNextRevision->expects( $this->never() )->method( $this->anything() );
+
+               $mockRevisionLookup = $this->getMockRevisionLookup(
+                       [
+                               'getTimestampFromId' => function ( $oldidParam ) use ( $oldid ) {
+                                       $this->assertEquals( $oldid, $oldidParam );
+                               },
+                               'getRevisionById' => function ( $id ) use ( $oldid, $mockRevision ) {
+                                       $this->assertSame( $oldid, $id );
+                                       return $mockRevision;
+                               },
+                               'getNextRevision' =>
+                               function ( RevisionRecord $rev ) use ( $mockRevision, $mockNextRevision ) {
+                                       $this->assertSame( $mockRevision, $rev );
+                                       return $mockNextRevision;
+                               },
+                       ],
+                       [
+                               'getTimestampFromId' => 2,
+                               'getRevisionById' => 1,
+                               'getNextRevision' => 1,
+                       ]
                );
 
+               $store = $this->newWatchedItemStore( [
+                       'db' => $mockDb,
+                       'queueGroup' => $mockQueueGroup,
+                       'cache' => $mockCache,
+                       'revisionLookup' => $mockRevisionLookup,
+               ] );
+
                $mockQueueGroup->expects( $this->any() )
                        ->method( 'lazyPush' )
                        ->will( $this->returnCallback(
@@ -2513,15 +2396,6 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                                }
                        ) );
 
-               $getTimestampCallCounter = 0;
-               $scopedOverrideRevision = $store->overrideRevisionGetTimestampFromIdCallback(
-                       function ( $titleParam, $oldidParam ) use ( &$getTimestampCallCounter, $title, $oldid ) {
-                               $getTimestampCallCounter++;
-                               $this->assertEquals( $title, $titleParam );
-                               $this->assertEquals( $oldid, $oldidParam );
-                       }
-               );
-
                $this->assertTrue(
                        $store->resetNotificationTimestamp(
                                $user,
@@ -2530,19 +2404,12 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                                $oldid
                        )
                );
-               $this->assertEquals( 2, $getTimestampCallCounter );
-
-               ScopedCallback::consume( $scopedOverrideRevision );
        }
 
        public function testResetNotificationTimestamp_futureNotificationTimestampNotForced() {
-               $user = $this->getMockNonAnonUserWithId( 1 );
+               $user = new UserIdentityValue( 1, 'MockUser', 0 );
                $oldid = 22;
-               $title = $this->getMockTitle( 'SomeDbKey' );
-               $title->expects( $this->once() )
-                       ->method( 'getNextRevisionID' )
-                       ->with( $oldid )
-                       ->will( $this->returnValue( 33 ) );
+               $title = new TitleValue( 0, 'SomeDbKey' );
 
                $mockDb = $this->getMockDb();
                $mockDb->expects( $this->once() )
@@ -2570,12 +2437,40 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                        ->with( '0:SomeDbKey:1' );
 
                $mockQueueGroup = $this->getMockJobQueueGroup();
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $mockQueueGroup,
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+
+               $mockRevision = $this->createMock( RevisionRecord::class );
+               $mockRevision->expects( $this->never() )->method( $this->anything() );
+
+               $mockNextRevision = $this->createMock( RevisionRecord::class );
+               $mockNextRevision->expects( $this->never() )->method( $this->anything() );
+
+               $mockRevisionLookup = $this->getMockRevisionLookup(
+                       [
+                               'getTimestampFromId' => function ( $oldidParam ) use ( $oldid ) {
+                                       $this->assertEquals( $oldid, $oldidParam );
+                               },
+                               'getRevisionById' => function ( $id ) use ( $oldid, $mockRevision ) {
+                                       $this->assertSame( $oldid, $id );
+                                       return $mockRevision;
+                               },
+                               'getNextRevision' =>
+                               function ( RevisionRecord $rev ) use ( $mockRevision, $mockNextRevision ) {
+                                       $this->assertSame( $mockRevision, $rev );
+                                       return $mockNextRevision;
+                               },
+                       ],
+                       [
+                               'getTimestampFromId' => 2,
+                               'getRevisionById' => 1,
+                               'getNextRevision' => 1,
+                       ]
+               );
+               $store = $this->newWatchedItemStore( [
+                       'db' => $mockDb,
+                       'queueGroup' => $mockQueueGroup,
+                       'cache' => $mockCache,
+                       'revisionLookup' => $mockRevisionLookup,
+               ] );
 
                $mockQueueGroup->expects( $this->any() )
                        ->method( 'lazyPush' )
@@ -2592,15 +2487,6 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                                }
                        ) );
 
-               $getTimestampCallCounter = 0;
-               $scopedOverrideRevision = $store->overrideRevisionGetTimestampFromIdCallback(
-                       function ( $titleParam, $oldidParam ) use ( &$getTimestampCallCounter, $title, $oldid ) {
-                               $getTimestampCallCounter++;
-                               $this->assertEquals( $title, $titleParam );
-                               $this->assertEquals( $oldid, $oldidParam );
-                       }
-               );
-
                $this->assertTrue(
                        $store->resetNotificationTimestamp(
                                $user,
@@ -2609,77 +2495,47 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                                $oldid
                        )
                );
-               $this->assertEquals( 2, $getTimestampCallCounter );
-
-               ScopedCallback::consume( $scopedOverrideRevision );
        }
 
        public function testSetNotificationTimestampsForUser_anonUser() {
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $this->getMockDb() ),
-                       $this->getMockJobQueueGroup(),
-                       $this->getMockCache(),
-                       $this->getMockReadOnlyMode()
-               );
-               $this->assertFalse( $store->setNotificationTimestampsForUser( $this->getAnonUser(), '' ) );
+               $store = $this->newWatchedItemStore();
+               $this->assertFalse( $store->setNotificationTimestampsForUser(
+                       new UserIdentityValue( 0, 'AnonUser', 0 ), '' ) );
        }
 
        public function testSetNotificationTimestampsForUser_allRows() {
-               $user = $this->getMockNonAnonUserWithId( 1 );
+               $user = new UserIdentityValue( 1, 'MockUser', 0 );
                $timestamp = '20100101010101';
 
-               $mockDb = $this->getMockDb();
-               $mockDb->expects( $this->once() )
-                       ->method( 'update' )
-                       ->with(
-                               'watchlist',
-                               [ 'wl_notificationtimestamp' => 'TS' . $timestamp . 'TS' ],
-                               [ 'wl_user' => 1 ]
-                       )
-                       ->will( $this->returnValue( true ) );
-               $mockDb->expects( $this->exactly( 1 ) )
-                       ->method( 'timestamp' )
-                       ->will( $this->returnCallback( function ( $value ) {
-                               return 'TS' . $value . 'TS';
-                       } ) );
+               $store = $this->newWatchedItemStore();
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $this->getMockCache(),
-                       $this->getMockReadOnlyMode()
-               );
+               // Note: This does not actually assert the job is correct
+               $callableCallCounter = 0;
+               $mockCallback = function ( $callable ) use ( &$callableCallCounter ) {
+                       $callableCallCounter++;
+                       $this->assertInternalType( 'callable', $callable );
+               };
+               $scopedOverride = $store->overrideDeferredUpdatesAddCallableUpdateCallback( $mockCallback );
 
                $this->assertTrue(
                        $store->setNotificationTimestampsForUser( $user, $timestamp )
                );
+               $this->assertEquals( 1, $callableCallCounter );
        }
 
        public function testSetNotificationTimestampsForUser_nullTimestamp() {
-               $user = $this->getMockNonAnonUserWithId( 1 );
+               $user = new UserIdentityValue( 1, 'MockUser', 0 );
                $timestamp = null;
 
-               $mockDb = $this->getMockDb();
-               $mockDb->expects( $this->once() )
-                       ->method( 'update' )
-                       ->with(
-                               'watchlist',
-                               [ 'wl_notificationtimestamp' => null ],
-                               [ 'wl_user' => 1 ]
-                       )
-                       ->will( $this->returnValue( true ) );
-               $mockDb->expects( $this->exactly( 0 ) )
-                       ->method( 'timestamp' )
-                       ->will( $this->returnCallback( function ( $value ) {
-                               return 'TS' . $value . 'TS';
-                       } ) );
+               $store = $this->newWatchedItemStore();
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $this->getMockCache(),
-                       $this->getMockReadOnlyMode()
-               );
+               // Note: This does not actually assert the job is correct
+               $callableCallCounter = 0;
+               $mockCallback = function ( $callable ) use ( &$callableCallCounter ) {
+                       $callableCallCounter++;
+                       $this->assertInternalType( 'callable', $callable );
+               };
+               $scopedOverride = $store->overrideDeferredUpdatesAddCallableUpdateCallback( $mockCallback );
 
                $this->assertTrue(
                        $store->setNotificationTimestampsForUser( $user, $timestamp )
@@ -2687,7 +2543,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
        }
 
        public function testSetNotificationTimestampsForUser_specificTargets() {
-               $user = $this->getMockNonAnonUserWithId( 1 );
+               $user = new UserIdentityValue( 1, 'MockUser', 0 );
                $timestamp = '20100101010101';
                $targets = [ new TitleValue( 0, 'Foo' ), new TitleValue( 0, 'Bar' ) ];
 
@@ -2697,7 +2553,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                        ->with(
                                'watchlist',
                                [ 'wl_notificationtimestamp' => 'TS' . $timestamp . 'TS' ],
-                               [ 'wl_user' => 1, 0 => 'makeWhereFrom2d return value' ]
+                               [ 'wl_user' => 1, 'wl_namespace' => 0, 'wl_title' => [ 'Foo', 'Bar' ] ]
                        )
                        ->will( $this->returnValue( true ) );
                $mockDb->expects( $this->exactly( 1 ) )
@@ -2706,20 +2562,10 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                                return 'TS' . $value . 'TS';
                        } ) );
                $mockDb->expects( $this->once() )
-                       ->method( 'makeWhereFrom2d' )
-                       ->with(
-                               [ [ 'Foo' => 1, 'Bar' => 1 ] ],
-                               $this->isType( 'string' ),
-                               $this->isType( 'string' )
-                       )
-                       ->will( $this->returnValue( 'makeWhereFrom2d return value' ) );
+                       ->method( 'affectedRows' )
+                       ->will( $this->returnValue( 2 ) );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $this->getMockCache(),
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb ] );
 
                $this->assertTrue(
                        $store->setNotificationTimestampsForUser( $user, $timestamp, $targets )
@@ -2758,17 +2604,12 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'get' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $this->assertEquals(
                        [ 2, 3 ],
                        $store->updateNotificationTimestamp(
-                               $this->getMockNonAnonUserWithId( 1 ),
+                               new UserIdentityValue( 1, 'MockUser', 0 ),
                                new TitleValue( 0, 'SomeDbKey' ),
                                '20151212010101'
                        )
@@ -2800,15 +2641,10 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                $mockCache->expects( $this->never() )->method( 'get' );
                $mockCache->expects( $this->never() )->method( 'delete' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                $watchers = $store->updateNotificationTimestamp(
-                       $this->getMockNonAnonUserWithId( 1 ),
+                       new UserIdentityValue( 1, 'MockUser', 0 ),
                        new TitleValue( 0, 'SomeDbKey' ),
                        '20151212010101'
                );
@@ -2817,7 +2653,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
        }
 
        public function testUpdateNotificationTimestamp_clearsCachedItems() {
-               $user = $this->getMockNonAnonUserWithId( 1 );
+               $user = new UserIdentityValue( 1, 'MockUser', 0 );
                $titleValue = new TitleValue( 0, 'SomeDbKey' );
 
                $mockDb = $this->getMockDb();
@@ -2845,18 +2681,13 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                        ->method( 'delete' )
                        ->with( '0:SomeDbKey:1' );
 
-               $store = $this->newWatchedItemStore(
-                       $this->getMockLBFactory( $mockDb ),
-                       $this->getMockJobQueueGroup(),
-                       $mockCache,
-                       $this->getMockReadOnlyMode()
-               );
+               $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] );
 
                // This will add the item to the cache
                $store->getWatchedItem( $user, $titleValue );
 
                $store->updateNotificationTimestamp(
-                       $this->getMockNonAnonUserWithId( 1 ),
+                       new UserIdentityValue( 1, 'MockUser', 0 ),
                        $titleValue,
                        '20151212010101'
                );
index dca1363..2f6fa39 100644 (file)
@@ -135,6 +135,18 @@ class LanguageTest extends LanguageClassesTestCase {
                                '48 hours 0 minutes',
                                'formatTimePeriod() rounding (=48h), avoidseconds'
                        ],
+                       [
+                               259199.55,
+                               'avoidhours',
+                               '3 d',
+                               'formatTimePeriod() rounding (>48h), avoidhours'
+                       ],
+                       [
+                               259199.55,
+                               [ 'avoid' => 'avoidhours', 'noabbrevs' => true ],
+                               '3 days',
+                               'formatTimePeriod() rounding (>48h), avoidhours'
+                       ],
                        [
                                259199.55,
                                'avoidminutes',
@@ -1052,6 +1064,27 @@ class LanguageTest extends LanguageClassesTestCase {
                                '平成24',
                                'nengo'
                        ],
+                       [
+                               'xtY',
+                               '20190430235959',
+                               '平成31',
+                               '平成31',
+                               'nengo - last day of heisei'
+                       ],
+                       [
+                               'xtY',
+                               '20190501000000',
+                               '令和元',
+                               '令和元',
+                               'nengo - first day of reiwa'
+                       ],
+                       [
+                               'xtY',
+                               '20200501000000',
+                               '令和2',
+                               '令和2',
+                               'nengo - second year of reiwa'
+                       ],
                        [
                                'xrxkYY',
                                '20120102090705',
@@ -1909,4 +1942,27 @@ class LanguageTest extends LanguageClassesTestCase {
                $ar2 = new LanguageAr();
                $this->assertTrue( $ar1->equals( $ar2 ), 'ar equals ar' );
        }
+
+       /**
+        * @dataProvider provideUcfirst
+        * @covers Language::ucfirst
+        */
+       public function testUcfirst( $orig, $expected, $desc, $overrides = false ) {
+               $lang = new Language();
+               if ( is_array( $overrides ) ) {
+                       $this->setMwGlobals( [ 'wgOverrideUcfirstCharacters' => $overrides ] );
+               }
+               $this->assertSame( $lang->ucfirst( $orig ), $expected, $desc );
+       }
+
+       public static function provideUcfirst() {
+               return [
+                       [ 'alice', 'Alice', 'simple ASCII string', false ],
+                       [ 'århus',  'Århus', 'unicode string', false ],
+                       //overrides do not affect ASCII characters
+                       [ 'foo', 'Foo', 'ASCII is not overriden', [ 'f' => 'b' ] ],
+                       // but they do affect non-ascii ones
+                       [ 'èl', 'Ll' , 'Non-ASCII is overridden', [ 'è' => 'L' ] ],
+               ];
+       }
 }
index c9f2f3e..8da7602 100644 (file)
@@ -238,6 +238,7 @@ class LanguageSrTest extends LanguageClassesTestCase {
        }
 
        # #### HELPERS #####################################################
+
        /**
         *Wrapper to verify text stay the same after applying conversion
         * @param string $text Text to convert
index 18b2031..abc63ee 100644 (file)
@@ -60,6 +60,7 @@ class LanguageUzTest extends LanguageClassesTestCase {
        }
 
        # #### HELPERS #####################################################
+
        /**
         * Wrapper to verify text stay the same after applying conversion
         * @param string $text Text to convert
diff --git a/tests/phpunit/maintenance/DumpAsserter.php b/tests/phpunit/maintenance/DumpAsserter.php
new file mode 100644 (file)
index 0000000..ad33f6e
--- /dev/null
@@ -0,0 +1,348 @@
+<?php
+
+namespace MediaWiki\Tests\Maintenance;
+
+use PHPUnit\Framework\Assert;
+use XMLReader;
+
+/**
+ * Helper for asserting the structure of an XML dump stream.
+ */
+class DumpAsserter {
+
+       /**
+        * Holds the XMLReader used for analyzing an XML dump
+        *
+        * @var XMLReader|null
+        */
+       protected $xml = null;
+
+       /**
+        * XML dump schema version
+        *
+        * @var string
+        */
+       protected $schemaVersion;
+
+       /**
+        * DumpAsserts constructor.
+        *
+        * @param string $schemaVersion see XML_DUMP_SCHEMA_VERSION_XX
+        */
+       public function __construct( $schemaVersion ) {
+               $this->schemaVersion = $schemaVersion;
+       }
+
+       /**
+        * Step the current XML reader until node end of given name is found.
+        *
+        * @param string $name Name of the closing element to look for
+        *   (e.g.: "mediawiki" when looking for </mediawiki>)
+        *
+        * @return bool True if the end node could be found. false otherwise.
+        */
+       public function skipToNodeEnd( $name ) {
+               while ( $this->xml->read() ) {
+                       if ( $this->xml->nodeType == XMLReader::END_ELEMENT &&
+                               $this->xml->name == $name
+                       ) {
+                               return true;
+                       }
+               }
+
+               return false;
+       }
+
+       /**
+        * Step the current XML reader to the first element start after the node
+        * end of a given name.
+        *
+        * @param string $name Name of the closing element to look for
+        *   (e.g.: "mediawiki" when looking for </mediawiki>)
+        *
+        * @return bool True if new element after the closing of $name could be
+        *   found. false otherwise.
+        */
+       public function skipPastNodeEnd( $name ) {
+               Assert::assertTrue( $this->skipToNodeEnd( $name ),
+                       "Skipping to end of $name" );
+               while ( $this->xml->read() ) {
+                       if ( $this->xml->nodeType == XMLReader::ELEMENT ) {
+                               return true;
+                       }
+               }
+
+               return false;
+       }
+
+       /**
+        * Opens an XML file to analyze and optionally skips past siteinfo.
+        *
+        * @param string $fname Name of file to analyze
+        * @param bool $skip_siteinfo (optional) If true, step the xml reader
+        *   to the first element after </siteinfo>
+        */
+       public function assertDumpStart( $fname, $skip_siteinfo = true ) {
+               $this->xml = new XMLReader();
+
+               Assert::assertTrue( $this->xml->open( $fname ),
+                       "Opening temporary file $fname via XMLReader failed" );
+               if ( $skip_siteinfo ) {
+                       Assert::assertTrue( $this->skipPastNodeEnd( "siteinfo" ),
+                               "Skipping past end of siteinfo" );
+               }
+       }
+
+       /**
+        * Asserts that the xml reader is at the final closing tag of an xml file and
+        * closes the reader.
+        *
+        * @param string $name (optional) the name of the final tag
+        *   (e.g.: "mediawiki" for </mediawiki>)
+        */
+       public function assertDumpEnd( $name = "mediawiki" ) {
+               $this->assertNodeEnd( $name, false );
+               if ( $this->xml->read() ) {
+                       $this->skipWhitespace();
+               }
+               Assert::assertEquals( $this->xml->nodeType, XMLReader::NONE,
+                       "No proper entity left to parse" );
+               $this->xml->close();
+       }
+
+       /**
+        * Steps the xml reader over white space
+        */
+       public function skipWhitespace() {
+               $cont = true;
+               while ( $cont && ( ( $this->xml->nodeType == XMLReader::WHITESPACE )
+                       || ( $this->xml->nodeType == XMLReader::SIGNIFICANT_WHITESPACE ) ) ) {
+                       $cont = $this->xml->read();
+               }
+       }
+
+       /**
+        * Asserts that the xml reader is at an element of given name, and optionally
+        * skips past it.
+        *
+        * @param string $name The name of the element to check for
+        *   (e.g.: "mediawiki" for <mediawiki>)
+        * @param bool $skip (optional) if true, skip past the found element
+        */
+       public function assertNodeStart( $name, $skip = true ) {
+               Assert::assertEquals( $name, $this->xml->name, "Node name" );
+               Assert::assertEquals( XMLReader::ELEMENT, $this->xml->nodeType, "Node type" );
+               if ( $skip ) {
+                       Assert::assertTrue( $this->xml->read(), "Skipping past start tag" );
+               }
+       }
+
+       /**
+        * Asserts that the xml reader is at an closing element of given name, and optionally
+        * skips past it.
+        *
+        * @param string $name The name of the closing element to check for
+        *   (e.g.: "mediawiki" for </mediawiki>)
+        * @param bool $skip (optional) if true, skip past the found element
+        */
+       public function assertNodeEnd( $name, $skip = true ) {
+               Assert::assertEquals( $name, $this->xml->name, "Node name" );
+               Assert::assertEquals( XMLReader::END_ELEMENT, $this->xml->nodeType, "Node type" );
+               if ( $skip ) {
+                       Assert::assertTrue( $this->xml->read(), "Skipping past end tag" );
+               }
+       }
+
+       /**
+        * Asserts that the xml reader is at an element of given tag that contains a given text,
+        * and skips over the element.
+        *
+        * @param string $name The name of the element to check for
+        *   (e.g.: "mediawiki" for <mediawiki>...</mediawiki>)
+        * @param string|bool $text If string, check if it equals the elements text.
+        *   If false, ignore the element's text
+        * @param bool $skip_ws (optional) if true, skip past white spaces that trail the
+        *   closing element.
+        */
+       public function assertTextNode( $name, $text, $skip_ws = true ) {
+               $this->assertNodeStart( $name );
+
+               if ( $text !== false ) {
+                       Assert::assertEquals( $text, $this->xml->value, "Text of node " . $name );
+               }
+               Assert::assertTrue( $this->xml->read(), "Skipping past processed text of " . $name );
+               $this->assertNodeEnd( $name );
+
+               if ( $skip_ws ) {
+                       $this->skipWhitespace();
+               }
+       }
+
+       /**
+        * Asserts that the xml reader is at the start of a page element and skips over the first
+        * tags, after checking them.
+        *
+        * Besides the opening page element, this function also checks for and skips over the
+        * title, ns, and id tags. Hence after this function, the xml reader is at the first
+        * revision of the current page.
+        *
+        * @param int $id Id of the page to assert
+        * @param int $ns Number of namespage to assert
+        * @param string $name Title of the current page
+        */
+       public function assertPageStart( $id, $ns, $name ) {
+               $this->assertNodeStart( "page" );
+               $this->skipWhitespace();
+
+               $this->assertTextNode( "title", $name );
+               $this->assertTextNode( "ns", $ns );
+               $this->assertTextNode( "id", $id );
+       }
+
+       /**
+        * Asserts that the xml reader is at the page's closing element and skips to the next
+        * element.
+        */
+       public function assertPageEnd() {
+               $this->assertNodeEnd( "page" );
+               $this->skipWhitespace();
+       }
+
+       /**
+        * Asserts that the xml reader is at a revision and checks its representation before
+        * skipping over it.
+        *
+        * @param int $id Id of the revision
+        * @param string $summary Summary of the revision
+        * @param int $text_id Id of the revision's text
+        * @param int $text_bytes Number of bytes in the revision's text
+        * @param string $text_sha1 The base36 SHA-1 of the revision's text
+        * @param string|bool $text (optional) The revision's string, or false to check for a
+        *            revision stub
+        * @param int|bool $parentid (optional) id of the parent revision
+        * @param string $model The expected content model id (default: CONTENT_MODEL_WIKITEXT)
+        * @param string $format The expected format model id (default: CONTENT_FORMAT_WIKITEXT)
+        */
+       public function assertRevision( $id, $summary, $text_id, $text_bytes,
+               $text_sha1, $text = false, $parentid = false,
+               $model = CONTENT_MODEL_WIKITEXT, $format = CONTENT_FORMAT_WIKITEXT
+       ) {
+               $this->assertNodeStart( "revision" );
+               $this->skipWhitespace();
+
+               $this->assertTextNode( "id", $id );
+               if ( $parentid !== false ) {
+                       $this->assertTextNode( "parentid", $parentid );
+               }
+               $this->assertTextNode( "timestamp", false );
+
+               $this->assertNodeStart( "contributor" );
+               $this->skipWhitespace();
+               $this->assertTextNode( "username", false );
+               $this->assertTextNode( "id", false );
+               $this->assertNodeEnd( "contributor" );
+               $this->skipWhitespace();
+
+               $this->assertTextNode( "comment", $summary );
+               $this->skipWhitespace();
+
+               $this->assertTextNode( "model", $model );
+               $this->skipWhitespace();
+
+               $this->assertTextNode( "format", $format );
+               $this->skipWhitespace();
+
+               if ( $this->xml->name == "text" ) {
+                       // note: <text> tag may occur here or at the very end.
+                       $text_found = true;
+                       $this->assertText( $id, $text_id, $text_bytes, $text );
+               } else {
+                       $text_found = false;
+               }
+
+               $this->assertTextNode( "sha1", $text_sha1 );
+
+               if ( !$text_found ) {
+                       $this->assertText( $id, $text_id, $text_bytes, $text );
+               }
+
+               $this->assertNodeEnd( "revision" );
+               $this->skipWhitespace();
+       }
+
+       public function assertText( $id, $text_id, $text_bytes, $text ) {
+               $this->assertNodeStart( "text", false );
+               if ( $text_bytes !== false ) {
+                       Assert::assertEquals( $this->xml->getAttribute( "bytes" ), $text_bytes,
+                               "Attribute 'bytes' of revision " . $id );
+               }
+
+               if ( $text === false ) {
+                       // Testing for a stub
+                       Assert::assertEquals( $this->xml->getAttribute( "id" ), $text_id,
+                               "Text id of revision " . $id );
+                       Assert::assertFalse( $this->xml->hasValue, "Revision has text" );
+                       Assert::assertTrue( $this->xml->read(), "Skipping text start tag" );
+                       if ( ( $this->xml->nodeType == XMLReader::END_ELEMENT )
+                               && ( $this->xml->name == "text" )
+                       ) {
+                               $this->xml->read();
+                       }
+                       $this->skipWhitespace();
+               } else {
+                       // Testing for a real dump
+                       Assert::assertTrue( $this->xml->read(), "Skipping text start tag" );
+                       Assert::assertEquals( $text, $this->xml->value, "Text of revision " . $id );
+                       Assert::assertTrue( $this->xml->read(), "Skipping past text" );
+                       $this->assertNodeEnd( "text" );
+                       $this->skipWhitespace();
+               }
+       }
+
+       /**
+        * asserts that the xml reader is at the beginning of a log entry and skips over
+        * it while analyzing it.
+        *
+        * @param int $id Id of the log entry
+        * @param string $user_name User name of the log entry's performer
+        * @param int $user_id User id of the log entry 's performer
+        * @param string|null $comment Comment of the log entry. If null, the comment text is ignored.
+        * @param string $type Type of the log entry
+        * @param string $subtype Subtype of the log entry
+        * @param string $title Title of the log entry's target
+        * @param array $parameters (optional) unserialized data accompanying the log entry
+        */
+       public function assertLogItem( $id, $user_name, $user_id, $comment, $type,
+               $subtype, $title, $parameters = []
+       ) {
+               $this->assertNodeStart( "logitem" );
+               $this->skipWhitespace();
+
+               $this->assertTextNode( "id", $id );
+               $this->assertTextNode( "timestamp", false );
+
+               $this->assertNodeStart( "contributor" );
+               $this->skipWhitespace();
+               $this->assertTextNode( "username", $user_name );
+               $this->assertTextNode( "id", $user_id );
+               $this->assertNodeEnd( "contributor" );
+               $this->skipWhitespace();
+
+               if ( $comment !== null ) {
+                       $this->assertTextNode( "comment", $comment );
+               }
+               $this->assertTextNode( "type", $type );
+               $this->assertTextNode( "action", $subtype );
+               $this->assertTextNode( "logtitle", $title );
+
+               $this->assertNodeStart( "params" );
+               $parameters_xml = unserialize( $this->xml->value );
+               Assert::assertEquals( $parameters, $parameters_xml );
+               Assert::assertTrue( $this->xml->read(), "Skipping past processed text of params" );
+               $this->assertNodeEnd( "params" );
+               $this->skipWhitespace();
+
+               $this->assertNodeEnd( "logitem" );
+               $this->skipWhitespace();
+       }
+}
index 4b7a7eb..7647915 100644 (file)
@@ -3,11 +3,12 @@
 namespace MediaWiki\Tests\Maintenance;
 
 use ContentHandler;
+use DOMDocument;
 use ExecutableFinder;
 use MediaWikiLangTestCase;
-use Page;
 use User;
-use XMLReader;
+use WikiExporter;
+use WikiPage;
 use MWException;
 
 /**
@@ -28,13 +29,6 @@ abstract class DumpTestCase extends MediaWikiLangTestCase {
         */
        protected $exceptionFromAddDBData = null;
 
-       /**
-        * Holds the XMLReader used for analyzing an XML dump
-        *
-        * @var XMLReader|null
-        */
-       protected $xml = null;
-
        /** @var bool|null Whether the 'gzip' utility is available */
        protected static $hasGzip = null;
 
@@ -58,7 +52,7 @@ abstract class DumpTestCase extends MediaWikiLangTestCase {
        /**
         * Adds a revision to a page, while returning the resuting revision's id
         *
-        * @param Page $page Page to add the revision to
+        * @param WikiPage $page Page to add the revision to
         * @param string $text Revisions text
         * @param string $summary Revisions summary
         * @param string $model The model ID (defaults to wikitext)
@@ -66,10 +60,15 @@ abstract class DumpTestCase extends MediaWikiLangTestCase {
         * @throws MWException
         * @return array
         */
-       protected function addRevision( Page $page, $text, $summary, $model = CONTENT_MODEL_WIKITEXT ) {
+       protected function addRevision(
+               WikiPage $page,
+               $text,
+               $summary,
+               $model = CONTENT_MODEL_WIKITEXT
+       ) {
                $status = $page->doEditContent(
                        ContentHandler::makeContent( $text, $page->getTitle(), $model ),
-                       $summary
+                       $summary, 0, false, $this->getTestUser()->getUser()
                );
 
                if ( $status->isGood() ) {
@@ -108,6 +107,36 @@ abstract class DumpTestCase extends MediaWikiLangTestCase {
                );
        }
 
+       public static function setUpBeforeClass() {
+               parent::setUpBeforeClass();
+
+               if ( !function_exists( 'libxml_set_external_entity_loader' ) ) {
+                       return;
+               }
+
+               // The W3C is intentionally slow about returning schema files,
+               // see <https://www.w3.org/Help/Webmaster#slowdtd>.
+               // To work around that, we keep our own copies of the relevant schema files.
+               libxml_set_external_entity_loader(
+                       function ( $public, $system, $context ) {
+                               switch ( $system ) {
+                                       // if more schema files are needed, add them here.
+                                       case 'http://www.w3.org/2001/xml.xsd':
+                                               $file = __DIR__ . '/xml.xsd';
+                                               break;
+                                       default:
+                                               if ( is_file( $system ) ) {
+                                                       $file = $system;
+                                               } else {
+                                                       return null;
+                                               }
+                               }
+
+                               return $file;
+                       }
+               );
+       }
+
        /**
         * Default set up function.
         *
@@ -125,6 +154,21 @@ abstract class DumpTestCase extends MediaWikiLangTestCase {
                $this->setMwGlobals( 'wgUser', new User() );
        }
 
+       /**
+        * Returns the path to the XML schema file for the given schema version.
+        *
+        * @param string|null $schemaVersion
+        *
+        * @return string
+        */
+       protected function getXmlSchemaPath( $schemaVersion = null ) {
+               global $IP, $wgXmlDumpSchemaVersion;
+
+               $schemaVersion = $schemaVersion ?: $wgXmlDumpSchemaVersion;
+
+               return "$IP/docs/export-$schemaVersion.xsd";
+       }
+
        /**
         * Checks for test output consisting only of lines containing ETA announcements
         */
@@ -152,266 +196,62 @@ abstract class DumpTestCase extends MediaWikiLangTestCase {
        }
 
        /**
-        * Step the current XML reader until node end of given name is found.
-        *
-        * @param string $name Name of the closing element to look for
-        *   (e.g.: "mediawiki" when looking for </mediawiki>)
+        * @param null|string $schemaVersion
         *
-        * @return bool True if the end node could be found. false otherwise.
+        * @return DumpAsserter
         */
-       protected function skipToNodeEnd( $name ) {
-               while ( $this->xml->read() ) {
-                       if ( $this->xml->nodeType == XMLReader::END_ELEMENT &&
-                               $this->xml->name == $name
-                       ) {
-                               return true;
-                       }
-               }
-
-               return false;
+       protected function getDumpAsserter( $schemaVersion = null ) {
+               $schemaVersion = $schemaVersion ?: WikiExporter::schemaVersion();
+               return new DumpAsserter( $schemaVersion );
        }
 
        /**
-        * Step the current XML reader to the first element start after the node
-        * end of a given name.
-        *
-        * @param string $name Name of the closing element to look for
-        *   (e.g.: "mediawiki" when looking for </mediawiki>)
-        *
-        * @return bool True if new element after the closing of $name could be
-        *   found. false otherwise.
+        * Checks an XML file against an XSD schema.
         */
-       protected function skipPastNodeEnd( $name ) {
-               $this->assertTrue( $this->skipToNodeEnd( $name ),
-                       "Skipping to end of $name" );
-               while ( $this->xml->read() ) {
-                       if ( $this->xml->nodeType == XMLReader::ELEMENT ) {
-                               return true;
-                       }
+       protected function assertDumpSchema( $fname, $schemaFile ) {
+               if ( !function_exists( 'libxml_use_internal_errors' ) ) {
+                       // Would be nice to leave a warning somehow.
+                       // We don't want to skip all of the test case that calls this, though.
+                       $this->markAsRisky();
+                       return;
                }
-
-               return false;
-       }
-
-       /**
-        * Opens an XML file to analyze and optionally skips past siteinfo.
-        *
-        * @param string $fname Name of file to analyze
-        * @param bool $skip_siteinfo (optional) If true, step the xml reader
-        *   to the first element after </siteinfo>
-        */
-       protected function assertDumpStart( $fname, $skip_siteinfo = true ) {
-               $this->xml = new XMLReader();
-               $this->assertTrue( $this->xml->open( $fname ),
-                       "Opening temporary file $fname via XMLReader failed" );
-               if ( $skip_siteinfo ) {
-                       $this->assertTrue( $this->skipPastNodeEnd( "siteinfo" ),
-                               "Skipping past end of siteinfo" );
+               if ( defined( 'HHVM_VERSION' ) ) {
+                       // In HHVM, loading a schema from a file is disabled per default.
+                       // This is controlled by hhvm.libxml.ext_entity_whitelist which
+                       // cannot be read with ini_get(), see
+                       // <https://docs.hhvm.com/hhvm/configuration/INI-settings#xml>.
+                       // Would be nice to leave a warning somehow.
+                       // We don't want to skip all of the test case that calls this, though.
+                       $this->markAsRisky();
+                       return;
                }
-       }
 
-       /**
-        * Asserts that the xml reader is at the final closing tag of an xml file and
-        * closes the reader.
-        *
-        * @param string $name (optional) the name of the final tag
-        *   (e.g.: "mediawiki" for </mediawiki>)
-        */
-       protected function assertDumpEnd( $name = "mediawiki" ) {
-               $this->assertNodeEnd( $name, false );
-               if ( $this->xml->read() ) {
-                       $this->skipWhitespace();
-               }
-               $this->assertEquals( $this->xml->nodeType, XMLReader::NONE,
-                       "No proper entity left to parse" );
-               $this->xml->close();
-       }
+               $xml = new DOMDocument();
+               $this->assertTrue( $xml->load( $fname ),
+                       "Opening temporary file $fname via DOMDocument failed" );
 
-       /**
-        * Steps the xml reader over white space
-        */
-       protected function skipWhitespace() {
-               $cont = true;
-               while ( $cont && ( ( $this->xml->nodeType == XMLReader::WHITESPACE )
-                       || ( $this->xml->nodeType == XMLReader::SIGNIFICANT_WHITESPACE ) ) ) {
-                       $cont = $this->xml->read();
-               }
-       }
+               // Don't throw
+               $oldLibXmlInternalErrors = libxml_use_internal_errors( true );
 
-       /**
-        * Asserts that the xml reader is at an element of given name, and optionally
-        * skips past it.
-        *
-        * @param string $name The name of the element to check for
-        *   (e.g.: "mediawiki" for <mediawiki>)
-        * @param bool $skip (optional) if true, skip past the found element
-        */
-       protected function assertNodeStart( $name, $skip = true ) {
-               $this->assertEquals( $name, $this->xml->name, "Node name" );
-               $this->assertEquals( XMLReader::ELEMENT, $this->xml->nodeType, "Node type" );
-               if ( $skip ) {
-                       $this->assertTrue( $this->xml->read(), "Skipping past start tag" );
-               }
-       }
-
-       /**
-        * Asserts that the xml reader is at an closing element of given name, and optionally
-        * skips past it.
-        *
-        * @param string $name The name of the closing element to check for
-        *   (e.g.: "mediawiki" for </mediawiki>)
-        * @param bool $skip (optional) if true, skip past the found element
-        */
-       protected function assertNodeEnd( $name, $skip = true ) {
-               $this->assertEquals( $name, $this->xml->name, "Node name" );
-               $this->assertEquals( XMLReader::END_ELEMENT, $this->xml->nodeType, "Node type" );
-               if ( $skip ) {
-                       $this->assertTrue( $this->xml->read(), "Skipping past end tag" );
-               }
-       }
-
-       /**
-        * Asserts that the xml reader is at an element of given tag that contains a given text,
-        * and skips over the element.
-        *
-        * @param string $name The name of the element to check for
-        *   (e.g.: "mediawiki" for <mediawiki>...</mediawiki>)
-        * @param string|bool $text If string, check if it equals the elements text.
-        *   If false, ignore the element's text
-        * @param bool $skip_ws (optional) if true, skip past white spaces that trail the
-        *   closing element.
-        */
-       protected function assertTextNode( $name, $text, $skip_ws = true ) {
-               $this->assertNodeStart( $name );
-
-               if ( $text !== false ) {
-                       $this->assertEquals( $text, $this->xml->value, "Text of node " . $name );
-               }
-               $this->assertTrue( $this->xml->read(), "Skipping past processed text of " . $name );
-               $this->assertNodeEnd( $name );
-
-               if ( $skip_ws ) {
-                       $this->skipWhitespace();
-               }
-       }
-
-       /**
-        * Asserts that the xml reader is at the start of a page element and skips over the first
-        * tags, after checking them.
-        *
-        * Besides the opening page element, this function also checks for and skips over the
-        * title, ns, and id tags. Hence after this function, the xml reader is at the first
-        * revision of the current page.
-        *
-        * @param int $id Id of the page to assert
-        * @param int $ns Number of namespage to assert
-        * @param string $name Title of the current page
-        */
-       protected function assertPageStart( $id, $ns, $name ) {
-               $this->assertNodeStart( "page" );
-               $this->skipWhitespace();
-
-               $this->assertTextNode( "title", $name );
-               $this->assertTextNode( "ns", $ns );
-               $this->assertTextNode( "id", $id );
-       }
+               // NOTE: if this reports "Invalid Schema", the schema may be referencing an external
+               // entity (typically, another schema) that needs to be mapped in the
+               // libxml_set_external_entity_loader callback defined in setUpBeforeClass() above!
+               // Or $schemaFile doesn't point to a schema file, or the schema is indeed just broken.
+               if ( !$xml->schemaValidate( $schemaFile ) ) {
+                       $errorText = '';
 
-       /**
-        * Asserts that the xml reader is at the page's closing element and skips to the next
-        * element.
-        */
-       protected function assertPageEnd() {
-               $this->assertNodeEnd( "page" );
-               $this->skipWhitespace();
-       }
-
-       /**
-        * Asserts that the xml reader is at a revision and checks its representation before
-        * skipping over it.
-        *
-        * @param int $id Id of the revision
-        * @param string $summary Summary of the revision
-        * @param int $text_id Id of the revision's text
-        * @param int $text_bytes Number of bytes in the revision's text
-        * @param string $text_sha1 The base36 SHA-1 of the revision's text
-        * @param string|bool $text (optional) The revision's string, or false to check for a
-        *            revision stub
-        * @param int|bool $parentid (optional) id of the parent revision
-        * @param string $model The expected content model id (default: CONTENT_MODEL_WIKITEXT)
-        * @param string $format The expected format model id (default: CONTENT_FORMAT_WIKITEXT)
-        */
-       protected function assertRevision( $id, $summary, $text_id, $text_bytes,
-               $text_sha1, $text = false, $parentid = false,
-               $model = CONTENT_MODEL_WIKITEXT, $format = CONTENT_FORMAT_WIKITEXT
-       ) {
-               $this->assertNodeStart( "revision" );
-               $this->skipWhitespace();
-
-               $this->assertTextNode( "id", $id );
-               if ( $parentid !== false ) {
-                       $this->assertTextNode( "parentid", $parentid );
-               }
-               $this->assertTextNode( "timestamp", false );
-
-               $this->assertNodeStart( "contributor" );
-               $this->skipWhitespace();
-               $this->assertTextNode( "ip", false );
-               $this->assertNodeEnd( "contributor" );
-               $this->skipWhitespace();
-
-               $this->assertTextNode( "comment", $summary );
-               $this->skipWhitespace();
-
-               $this->assertTextNode( "model", $model );
-               $this->skipWhitespace();
-
-               $this->assertTextNode( "format", $format );
-               $this->skipWhitespace();
-
-               if ( $this->xml->name == "text" ) {
-                       // note: <text> tag may occur here or at the very end.
-                       $text_found = true;
-                       $this->assertText( $id, $text_id, $text_bytes, $text );
-               } else {
-                       $text_found = false;
-               }
+                       foreach ( libxml_get_errors() as $error ) {
+                               $errorText .= "\nline {$error->line}: {$error->message}";
+                       }
 
-               $this->assertTextNode( "sha1", $text_sha1 );
+                       libxml_clear_errors();
 
-               if ( !$text_found ) {
-                       $this->assertText( $id, $text_id, $text_bytes, $text );
+                       $this->fail(
+                               "Failed asserting that $fname conforms to the schema in $schemaFile:\n$errorText"
+                       );
                }
 
-               $this->assertNodeEnd( "revision" );
-               $this->skipWhitespace();
+               libxml_use_internal_errors( $oldLibXmlInternalErrors );
        }
 
-       protected function assertText( $id, $text_id, $text_bytes, $text ) {
-               $this->assertNodeStart( "text", false );
-               if ( $text_bytes !== false ) {
-                       $this->assertEquals( $this->xml->getAttribute( "bytes" ), $text_bytes,
-                               "Attribute 'bytes' of revision " . $id );
-               }
-
-               if ( $text === false ) {
-                       // Testing for a stub
-                       $this->assertEquals( $this->xml->getAttribute( "id" ), $text_id,
-                               "Text id of revision " . $id );
-                       $this->assertFalse( $this->xml->hasValue, "Revision has text" );
-                       $this->assertTrue( $this->xml->read(), "Skipping text start tag" );
-                       if ( ( $this->xml->nodeType == XMLReader::END_ELEMENT )
-                               && ( $this->xml->name == "text" )
-                       ) {
-                               $this->xml->read();
-                       }
-                       $this->skipWhitespace();
-               } else {
-                       // Testing for a real dump
-                       $this->assertTrue( $this->xml->read(), "Skipping text start tag" );
-                       $this->assertEquals( $text, $this->xml->value, "Text of revision " . $id );
-                       $this->assertTrue( $this->xml->read(), "Skipping past text" );
-                       $this->assertNodeEnd( "text" );
-                       $this->skipWhitespace();
-               }
-       }
 }
index 38a513e..e059834 100644 (file)
@@ -130,45 +130,46 @@ class TextPassDumperDatabaseTest extends DumpTestCase {
                $dumper->dump( WikiExporter::FULL, WikiExporter::TEXT );
 
                // Checking for correctness of the dumped data
-               $this->assertDumpStart( $nameFull );
+               $asserter = $this->getDumpAsserter();
+               $asserter->assertDumpStart( $nameFull );
 
                // Page 1
-               $this->assertPageStart( $this->pageId1, NS_MAIN, "BackupDumperTestP1" );
-               $this->assertRevision( $this->revId1_1, "BackupDumperTestP1Summary1",
+               $asserter->assertPageStart( $this->pageId1, NS_MAIN, "BackupDumperTestP1" );
+               $asserter->assertRevision( $this->revId1_1, "BackupDumperTestP1Summary1",
                        $this->textId1_1, false, "0bolhl6ol7i6x0e7yq91gxgaan39j87",
                        "BackupDumperTestP1Text1" );
-               $this->assertPageEnd();
+               $asserter->assertPageEnd();
 
                // Page 2
-               $this->assertPageStart( $this->pageId2, NS_MAIN, "BackupDumperTestP2" );
-               $this->assertRevision( $this->revId2_1, "BackupDumperTestP2Summary1",
+               $asserter->assertPageStart( $this->pageId2, NS_MAIN, "BackupDumperTestP2" );
+               $asserter->assertRevision( $this->revId2_1, "BackupDumperTestP2Summary1",
                        $this->textId2_1, false, "jprywrymfhysqllua29tj3sc7z39dl2",
                        "BackupDumperTestP2Text1" );
-               $this->assertRevision( $this->revId2_2, "BackupDumperTestP2Summary2",
+               $asserter->assertRevision( $this->revId2_2, "BackupDumperTestP2Summary2",
                        $this->textId2_2, false, "b7vj5ks32po5m1z1t1br4o7scdwwy95",
                        "BackupDumperTestP2Text2", $this->revId2_1 );
-               $this->assertRevision( $this->revId2_3, "BackupDumperTestP2Summary3",
+               $asserter->assertRevision( $this->revId2_3, "BackupDumperTestP2Summary3",
                        $this->textId2_3, false, "jfunqmh1ssfb8rs43r19w98k28gg56r",
                        "BackupDumperTestP2Text3", $this->revId2_2 );
-               $this->assertRevision( $this->revId2_4, "BackupDumperTestP2Summary4 extra",
+               $asserter->assertRevision( $this->revId2_4, "BackupDumperTestP2Summary4 extra",
                        $this->textId2_4, false, "6o1ciaxa6pybnqprmungwofc4lv00wv",
                        "BackupDumperTestP2Text4 some additional Text", $this->revId2_3 );
-               $this->assertPageEnd();
+               $asserter->assertPageEnd();
 
                // Page 3
                // -> Page is marked deleted. Hence not visible
 
                // Page 4
-               $this->assertPageStart( $this->pageId4, NS_TALK, "Talk:BackupDumperTestP1" );
-               $this->assertRevision( $this->revId4_1, "Talk BackupDumperTestP1 Summary1",
+               $asserter->assertPageStart( $this->pageId4, NS_TALK, "Talk:BackupDumperTestP1" );
+               $asserter->assertRevision( $this->revId4_1, "Talk BackupDumperTestP1 Summary1",
                        $this->textId4_1, false, "nktofwzd0tl192k3zfepmlzxoax1lpe",
                        "TALK ABOUT BACKUPDUMPERTESTP1 TEXT1",
                        false,
                        "BackupTextPassTestModel",
                        "text/plain" );
-               $this->assertPageEnd();
+               $asserter->assertPageEnd();
 
-               $this->assertDumpEnd();
+               $asserter->assertDumpEnd();
        }
 
        function testPrefetchPlain() {
@@ -202,49 +203,50 @@ class TextPassDumperDatabaseTest extends DumpTestCase {
                $dumper->dump( WikiExporter::FULL, WikiExporter::TEXT );
 
                // Checking for correctness of the dumped data
-               $this->assertDumpStart( $nameFull );
+               $asserter = $this->getDumpAsserter();
+               $asserter->assertDumpStart( $nameFull );
 
                // Page 1
-               $this->assertPageStart( $this->pageId1, NS_MAIN, "BackupDumperTestP1" );
+               $asserter->assertPageStart( $this->pageId1, NS_MAIN, "BackupDumperTestP1" );
                // Prefetch kicks in. This is still the SHA-1 of the original text,
                // But the actual text (with different SHA-1) comes from prefetch.
-               $this->assertRevision( $this->revId1_1, "BackupDumperTestP1Summary1",
+               $asserter->assertRevision( $this->revId1_1, "BackupDumperTestP1Summary1",
                        $this->textId1_1, false, "0bolhl6ol7i6x0e7yq91gxgaan39j87",
                        "Prefetch_________1Text1" );
-               $this->assertPageEnd();
+               $asserter->assertPageEnd();
 
                // Page 2
-               $this->assertPageStart( $this->pageId2, NS_MAIN, "BackupDumperTestP2" );
-               $this->assertRevision( $this->revId2_1, "BackupDumperTestP2Summary1",
+               $asserter->assertPageStart( $this->pageId2, NS_MAIN, "BackupDumperTestP2" );
+               $asserter->assertRevision( $this->revId2_1, "BackupDumperTestP2Summary1",
                        $this->textId2_1, false, "jprywrymfhysqllua29tj3sc7z39dl2",
                        "BackupDumperTestP2Text1" );
-               $this->assertRevision( $this->revId2_2, "BackupDumperTestP2Summary2",
+               $asserter->assertRevision( $this->revId2_2, "BackupDumperTestP2Summary2",
                        $this->textId2_2, false, "b7vj5ks32po5m1z1t1br4o7scdwwy95",
                        "BackupDumperTestP2Text2", $this->revId2_1 );
                // Prefetch kicks in. This is still the SHA-1 of the original text,
                // But the actual text (with different SHA-1) comes from prefetch.
-               $this->assertRevision( $this->revId2_3, "BackupDumperTestP2Summary3",
+               $asserter->assertRevision( $this->revId2_3, "BackupDumperTestP2Summary3",
                        $this->textId2_3, false, "jfunqmh1ssfb8rs43r19w98k28gg56r",
                        "Prefetch_________2Text3", $this->revId2_2 );
-               $this->assertRevision( $this->revId2_4, "BackupDumperTestP2Summary4 extra",
+               $asserter->assertRevision( $this->revId2_4, "BackupDumperTestP2Summary4 extra",
                        $this->textId2_4, false, "6o1ciaxa6pybnqprmungwofc4lv00wv",
                        "BackupDumperTestP2Text4 some additional Text", $this->revId2_3 );
-               $this->assertPageEnd();
+               $asserter->assertPageEnd();
 
                // Page 3
                // -> Page is marked deleted. Hence not visible
 
                // Page 4
-               $this->assertPageStart( $this->pageId4, NS_TALK, "Talk:BackupDumperTestP1" );
-               $this->assertRevision( $this->revId4_1, "Talk BackupDumperTestP1 Summary1",
+               $asserter->assertPageStart( $this->pageId4, NS_TALK, "Talk:BackupDumperTestP1" );
+               $asserter->assertRevision( $this->revId4_1, "Talk BackupDumperTestP1 Summary1",
                        $this->textId4_1, false, "nktofwzd0tl192k3zfepmlzxoax1lpe",
                        "TALK ABOUT BACKUPDUMPERTESTP1 TEXT1",
                        false,
                        "BackupTextPassTestModel",
                        "text/plain" );
-               $this->assertPageEnd();
+               $asserter->assertPageEnd();
 
-               $this->assertDumpEnd();
+               $asserter->assertDumpEnd();
        }
 
        /**
@@ -329,6 +331,8 @@ class TextPassDumperDatabaseTest extends DumpTestCase {
                $lookingForPage = 1;
                $checkpointFiles = 0;
 
+               $asserter = $this->getDumpAsserter();
+
                // Each run of the following loop body tries to handle exactly 1 /page/ (not
                // iteration of stub content). $i is only increased after having treated page 4.
                for ( $i = 0; $i < $iterations; ) {
@@ -346,7 +350,7 @@ class TextPassDumperDatabaseTest extends DumpTestCase {
                                if ( $checkpointFormat == "gzip" ) {
                                        $this->gunzip( $nameOutputDir . "/" . $fname );
                                }
-                               $this->assertDumpStart( $nameOutputDir . "/" . $fname );
+                               $asserter->assertDumpStart( $nameOutputDir . "/" . $fname );
                                $fileOpened = true;
                                $checkpointFiles++;
                        }
@@ -355,51 +359,90 @@ class TextPassDumperDatabaseTest extends DumpTestCase {
                        switch ( $lookingForPage ) {
                                case 1:
                                        // Page 1
-                                       $this->assertPageStart( $this->pageId1 + $i * self::$numOfPages, NS_MAIN,
-                                               "BackupDumperTestP1" );
-                                       $this->assertRevision( $this->revId1_1 + $i * self::$numOfRevs, "BackupDumperTestP1Summary1",
-                                               $this->textId1_1, false, "0bolhl6ol7i6x0e7yq91gxgaan39j87",
-                                               "BackupDumperTestP1Text1" );
-                                       $this->assertPageEnd();
+                                       $asserter->assertPageStart(
+                                               $this->pageId1 + $i * self::$numOfPages,
+                                               NS_MAIN,
+                                               "BackupDumperTestP1"
+                                       );
+                                       $asserter->assertRevision(
+                                               $this->revId1_1 + $i * self::$numOfRevs,
+                                               "BackupDumperTestP1Summary1",
+                                               $this->textId1_1,
+                                               false,
+                                               "0bolhl6ol7i6x0e7yq91gxgaan39j87",
+                                               "BackupDumperTestP1Text1"
+                                       );
+                                       $asserter->assertPageEnd();
 
                                        $lookingForPage = 2;
                                        break;
 
                                case 2:
                                        // Page 2
-                                       $this->assertPageStart( $this->pageId2 + $i * self::$numOfPages, NS_MAIN,
-                                               "BackupDumperTestP2" );
-                                       $this->assertRevision( $this->revId2_1 + $i * self::$numOfRevs, "BackupDumperTestP2Summary1",
-                                               $this->textId2_1, false, "jprywrymfhysqllua29tj3sc7z39dl2",
-                                               "BackupDumperTestP2Text1" );
-                                       $this->assertRevision( $this->revId2_2 + $i * self::$numOfRevs, "BackupDumperTestP2Summary2",
-                                               $this->textId2_2, false, "b7vj5ks32po5m1z1t1br4o7scdwwy95",
-                                               "BackupDumperTestP2Text2", $this->revId2_1 + $i * self::$numOfRevs );
-                                       $this->assertRevision( $this->revId2_3 + $i * self::$numOfRevs, "BackupDumperTestP2Summary3",
-                                               $this->textId2_3, false, "jfunqmh1ssfb8rs43r19w98k28gg56r",
-                                               "BackupDumperTestP2Text3", $this->revId2_2 + $i * self::$numOfRevs );
-                                       $this->assertRevision( $this->revId2_4 + $i * self::$numOfRevs,
+                                       $asserter->assertPageStart(
+                                               $this->pageId2 + $i * self::$numOfPages,
+                                               NS_MAIN,
+                                               "BackupDumperTestP2"
+                                       );
+                                       $asserter->assertRevision(
+                                               $this->revId2_1 + $i * self::$numOfRevs,
+                                               "BackupDumperTestP2Summary1",
+                                               $this->textId2_1,
+                                               false,
+                                               "jprywrymfhysqllua29tj3sc7z39dl2",
+                                               "BackupDumperTestP2Text1"
+                                       );
+                                       $asserter->assertRevision(
+                                               $this->revId2_2 + $i * self::$numOfRevs,
+                                               "BackupDumperTestP2Summary2",
+                                               $this->textId2_2,
+                                               false,
+                                               "b7vj5ks32po5m1z1t1br4o7scdwwy95",
+                                               "BackupDumperTestP2Text2",
+                                               $this->revId2_1 + $i * self::$numOfRevs
+                                       );
+                                       $asserter->assertRevision(
+                                               $this->revId2_3 + $i * self::$numOfRevs,
+                                               "BackupDumperTestP2Summary3",
+                                               $this->textId2_3,
+                                               false,
+                                               "jfunqmh1ssfb8rs43r19w98k28gg56r",
+                                               "BackupDumperTestP2Text3",
+                                               $this->revId2_2 + $i * self::$numOfRevs
+                                       );
+                                       $asserter->assertRevision(
+                                               $this->revId2_4 + $i * self::$numOfRevs,
                                                "BackupDumperTestP2Summary4 extra",
-                                               $this->textId2_4, false, "6o1ciaxa6pybnqprmungwofc4lv00wv",
+                                               $this->textId2_4,
+                                               false,
+                                               "6o1ciaxa6pybnqprmungwofc4lv00wv",
                                                "BackupDumperTestP2Text4 some additional Text",
-                                               $this->revId2_3 + $i * self::$numOfRevs );
-                                       $this->assertPageEnd();
+                                               $this->revId2_3 + $i * self::$numOfRevs
+                                       );
+                                       $asserter->assertPageEnd();
 
                                        $lookingForPage = 4;
                                        break;
 
                                case 4:
                                        // Page 4
-                                       $this->assertPageStart( $this->pageId4 + $i * self::$numOfPages, NS_TALK,
-                                               "Talk:BackupDumperTestP1" );
-                                       $this->assertRevision( $this->revId4_1 + $i * self::$numOfRevs,
+                                       $asserter->assertPageStart(
+                                               $this->pageId4 + $i * self::$numOfPages,
+                                               NS_TALK,
+                                               "Talk:BackupDumperTestP1"
+                                       );
+                                       $asserter->assertRevision(
+                                               $this->revId4_1 + $i * self::$numOfRevs,
                                                "Talk BackupDumperTestP1 Summary1",
-                                               $this->textId4_1, false, "nktofwzd0tl192k3zfepmlzxoax1lpe",
+                                               $this->textId4_1,
+                                               false,
+                                               "nktofwzd0tl192k3zfepmlzxoax1lpe",
                                                "TALK ABOUT BACKUPDUMPERTESTP1 TEXT1",
                                                false,
                                                "BackupTextPassTestModel",
-                                               "text/plain" );
-                                       $this->assertPageEnd();
+                                               "text/plain"
+                                       );
+                                       $asserter->assertPageEnd();
 
                                        $lookingForPage = 1;
 
@@ -415,7 +458,7 @@ class TextPassDumperDatabaseTest extends DumpTestCase {
                        if ( $this->xml->nodeType == XMLReader::END_ELEMENT
                                && $this->xml->name == "mediawiki"
                        ) {
-                               $this->assertDumpEnd();
+                               $asserter->assertDumpEnd();
                                $fileOpened = false;
                        }
                }
@@ -518,6 +561,8 @@ class TextPassDumperDatabaseTest extends DumpTestCase {
 
                $content = $header;
                $iterations = intval( $iterations );
+               $username = $this->getTestUser()->getUser()->getName();
+               $userid = $this->getTestUser()->getUser()->getId();
                for ( $i = 0; $i < $iterations; $i++ ) {
                        $page1 = '  <page>
     <title>BackupDumperTestP1</title>
@@ -527,7 +572,8 @@ class TextPassDumperDatabaseTest extends DumpTestCase {
       <id>' . ( $this->revId1_1 + $i * self::$numOfRevs ) . '</id>
       <timestamp>2012-04-01T16:46:05Z</timestamp>
       <contributor>
-        <ip>127.0.0.1</ip>
+        <username>' . $username . '</username>
+        <id>' . $userid . '</id>
       </contributor>
       <comment>BackupDumperTestP1Summary1</comment>
       <model>wikitext</model>
@@ -545,7 +591,8 @@ class TextPassDumperDatabaseTest extends DumpTestCase {
       <id>' . ( $this->revId2_1 + $i * self::$numOfRevs ) . '</id>
       <timestamp>2012-04-01T16:46:05Z</timestamp>
       <contributor>
-        <ip>127.0.0.1</ip>
+        <username>' . $username . '</username>
+        <id>' . $userid . '</id>
       </contributor>
       <comment>BackupDumperTestP2Summary1</comment>
       <model>wikitext</model>
@@ -558,7 +605,8 @@ class TextPassDumperDatabaseTest extends DumpTestCase {
       <parentid>' . ( $this->revId2_1 + $i * self::$numOfRevs ) . '</parentid>
       <timestamp>2012-04-01T16:46:05Z</timestamp>
       <contributor>
-        <ip>127.0.0.1</ip>
+        <username>' . $username . '</username>
+        <id>' . $userid . '</id>
       </contributor>
       <comment>BackupDumperTestP2Summary2</comment>
       <model>wikitext</model>
@@ -571,7 +619,8 @@ class TextPassDumperDatabaseTest extends DumpTestCase {
       <parentid>' . ( $this->revId2_2 + $i * self::$numOfRevs ) . '</parentid>
       <timestamp>2012-04-01T16:46:05Z</timestamp>
       <contributor>
-        <ip>127.0.0.1</ip>
+        <username>' . $username . '</username>
+        <id>' . $userid . '</id>
       </contributor>
       <comment>BackupDumperTestP2Summary3</comment>
       <model>wikitext</model>
@@ -584,7 +633,8 @@ class TextPassDumperDatabaseTest extends DumpTestCase {
       <parentid>' . ( $this->revId2_3 + $i * self::$numOfRevs ) . '</parentid>
       <timestamp>2012-04-01T16:46:05Z</timestamp>
       <contributor>
-        <ip>127.0.0.1</ip>
+        <username>' . $username . '</username>
+        <id>' . $userid . '</id>
       </contributor>
       <comment>BackupDumperTestP2Summary4 extra</comment>
       <model>wikitext</model>
@@ -604,7 +654,8 @@ class TextPassDumperDatabaseTest extends DumpTestCase {
       <id>' . ( $this->revId4_1 + $i * self::$numOfRevs ) . '</id>
       <timestamp>2012-04-01T16:46:05Z</timestamp>
       <contributor>
-        <ip>127.0.0.1</ip>
+        <username>' . $username . '</username>
+        <id>' . $userid . '</id>
       </contributor>
       <comment>Talk BackupDumperTestP1 Summary1</comment>
       <model>BackupTextPassTestModel</model>
index 9357451..811f1ee 100644 (file)
@@ -2,6 +2,7 @@
 
 namespace MediaWiki\Tests\Maintenance;
 
+use Exception;
 use MediaWiki\MediaWikiServices;
 use DumpBackup;
 use ManualLogEntry;
@@ -98,53 +99,6 @@ class BackupDumperLoggerTest extends DumpTestCase {
                }
        }
 
-       /**
-        * asserts that the xml reader is at the beginning of a log entry and skips over
-        * it while analyzing it.
-        *
-        * @param int $id Id of the log entry
-        * @param string $user_name User name of the log entry's performer
-        * @param int $user_id User id of the log entry 's performer
-        * @param string|null $comment Comment of the log entry. If null, the comment text is ignored.
-        * @param string $type Type of the log entry
-        * @param string $subtype Subtype of the log entry
-        * @param string $title Title of the log entry's target
-        * @param array $parameters (optional) unserialized data accompanying the log entry
-        */
-       private function assertLogItem( $id, $user_name, $user_id, $comment, $type,
-               $subtype, $title, $parameters = []
-       ) {
-               $this->assertNodeStart( "logitem" );
-               $this->skipWhitespace();
-
-               $this->assertTextNode( "id", $id );
-               $this->assertTextNode( "timestamp", false );
-
-               $this->assertNodeStart( "contributor" );
-               $this->skipWhitespace();
-               $this->assertTextNode( "username", $user_name );
-               $this->assertTextNode( "id", $user_id );
-               $this->assertNodeEnd( "contributor" );
-               $this->skipWhitespace();
-
-               if ( $comment !== null ) {
-                       $this->assertTextNode( "comment", $comment );
-               }
-               $this->assertTextNode( "type", $type );
-               $this->assertTextNode( "action", $subtype );
-               $this->assertTextNode( "logtitle", $title );
-
-               $this->assertNodeStart( "params" );
-               $parameters_xml = unserialize( $this->xml->value );
-               $this->assertEquals( $parameters, $parameters_xml );
-               $this->assertTrue( $this->xml->read(), "Skipping past processed text of params" );
-               $this->assertNodeEnd( "params" );
-               $this->skipWhitespace();
-
-               $this->assertNodeEnd( "logitem" );
-               $this->skipWhitespace();
-       }
-
        function testPlain() {
                // Preparing the dump
                $fname = $this->getNewTempFile();
@@ -159,9 +113,12 @@ class BackupDumperLoggerTest extends DumpTestCase {
                $dumper->dump( WikiExporter::LOGS, WikiExporter::TEXT );
 
                // Analyzing the dumped data
-               $this->assertDumpStart( $fname );
+               $this->assertDumpSchema( $fname, $this->getXmlSchemaPath() );
+
+               $asserter = $this->getDumpAsserter();
+               $asserter->assertDumpStart( $fname );
 
-               $this->assertLogItem( $this->logId1, "BackupDumperLogUserA",
+               $asserter->assertLogItem( $this->logId1, "BackupDumperLogUserA",
                        $this->userId1, null, "type", "subtype", "PageA" );
 
                $contLang = MediaWikiServices::getInstance()->getContentLanguage();
@@ -169,15 +126,15 @@ class BackupDumperLoggerTest extends DumpTestCase {
                $namespace = $contLang->getNsText( NS_TALK );
                $this->assertInternalType( 'string', $namespace );
                $this->assertGreaterThan( 0, strlen( $namespace ) );
-               $this->assertLogItem( $this->logId2, "BackupDumperLogUserB",
+               $asserter->assertLogItem( $this->logId2, "BackupDumperLogUserB",
                        $this->userId2, "SomeComment", "supress", "delete",
                        $namespace . ":PageB" );
 
-               $this->assertLogItem( $this->logId3, "BackupDumperLogUserB",
+               $asserter->assertLogItem( $this->logId3, "BackupDumperLogUserB",
                        $this->userId2, "SomeOtherComment", "move", "delete",
                        "PageA", [ 'key1' => 1, 3 => 'value3' ] );
 
-               $this->assertDumpEnd();
+               $asserter->assertDumpEnd();
        }
 
        function testXmlDumpsBackupUseCaseLogging() {
@@ -211,9 +168,12 @@ class BackupDumperLoggerTest extends DumpTestCase {
                // Analyzing the dumped data
                $this->gunzip( $fname );
 
-               $this->assertDumpStart( $fname );
+               $this->assertDumpSchema( $fname, $this->getXmlSchemaPath() );
+
+               $asserter = $this->getDumpAsserter();
+               $asserter->assertDumpStart( $fname );
 
-               $this->assertLogItem( $this->logId1, "BackupDumperLogUserA",
+               $asserter->assertLogItem( $this->logId1, "BackupDumperLogUserA",
                        $this->userId1, null, "type", "subtype", "PageA" );
 
                $contLang = MediaWikiServices::getInstance()->getContentLanguage();
@@ -221,15 +181,15 @@ class BackupDumperLoggerTest extends DumpTestCase {
                $namespace = $contLang->getNsText( NS_TALK );
                $this->assertInternalType( 'string', $namespace );
                $this->assertGreaterThan( 0, strlen( $namespace ) );
-               $this->assertLogItem( $this->logId2, "BackupDumperLogUserB",
+               $asserter->assertLogItem( $this->logId2, "BackupDumperLogUserB",
                        $this->userId2, "SomeComment", "supress", "delete",
                        $namespace . ":PageB" );
 
-               $this->assertLogItem( $this->logId3, "BackupDumperLogUserB",
+               $asserter->assertLogItem( $this->logId3, "BackupDumperLogUserB",
                        $this->userId2, "SomeOtherComment", "move", "delete",
                        "PageA", [ 'key1' => 1, 3 => 'value3' ] );
 
-               $this->assertDumpEnd();
+               $asserter->assertDumpEnd();
 
                // Currently, no reporting is implemented. Alert via failure, once
                // this changes.
index c37be4e..17c8757 100644 (file)
@@ -3,6 +3,7 @@
 namespace MediaWiki\Tests\Maintenance;
 
 use DumpBackup;
+use Exception;
 use MediaWiki\MediaWikiServices;
 use MediaWikiTestCase;
 use MWException;
@@ -11,6 +12,7 @@ use WikiExporter;
 use Wikimedia\Rdbms\IDatabase;
 use Wikimedia\Rdbms\LoadBalancer;
 use WikiPage;
+use XmlDumpWriter;
 
 /**
  * Tests for page dumps of BackupDumper
@@ -169,12 +171,21 @@ class BackupDumperPageTest extends DumpTestCase {
                return $dumper;
        }
 
-       function testFullTextPlain() {
+       public function schemaVersionProvider() {
+               foreach ( XmlDumpWriter::$supportedSchemas as $schemaVersion ) {
+                       yield [ $schemaVersion ];
+               }
+       }
+
+       /**
+        * @dataProvider schemaVersionProvider
+        */
+       function testFullTextPlain( $schemaVersion ) {
                // Preparing the dump
                $fname = $this->getNewTempFile();
 
                $dumper = $this->newDumpBackup(
-                       [ '--full', '--quiet', '--output', 'file:' . $fname ],
+                       [ '--full', '--quiet', '--output', 'file:' . $fname, '--schema-version', $schemaVersion ],
                        $this->pageId1,
                        $this->pageId4 + 1
                );
@@ -183,54 +194,114 @@ class BackupDumperPageTest extends DumpTestCase {
                $dumper->execute();
 
                // Checking the dumped data
-               $this->assertDumpStart( $fname );
+               $this->assertDumpSchema( $fname, $this->getXmlSchemaPath( $schemaVersion ) );
+               $asserter = $this->getDumpAsserter( $schemaVersion );
+
+               $asserter->assertDumpStart( $fname );
 
                // Page 1
-               $this->assertPageStart( $this->pageId1, $this->namespace, $this->pageTitle1->getPrefixedText() );
-               $this->assertRevision( $this->revId1_1, "BackupDumperTestP1Summary1",
-                       $this->textId1_1, 23, "0bolhl6ol7i6x0e7yq91gxgaan39j87",
-                       "BackupDumperTestP1Text1" );
-               $this->assertPageEnd();
+               $asserter->assertPageStart(
+                       $this->pageId1,
+                       $this->namespace,
+                       $this->pageTitle1->getPrefixedText()
+               );
+               $asserter->assertRevision(
+                       $this->revId1_1,
+                       "BackupDumperTestP1Summary1",
+                       $this->textId1_1,
+                       23,
+                       "0bolhl6ol7i6x0e7yq91gxgaan39j87",
+                       "BackupDumperTestP1Text1"
+               );
+               $asserter->assertPageEnd();
 
                // Page 2
-               $this->assertPageStart( $this->pageId2, $this->namespace, $this->pageTitle2->getPrefixedText() );
-               $this->assertRevision( $this->revId2_1, "BackupDumperTestP2Summary1",
-                       $this->textId2_1, 23, "jprywrymfhysqllua29tj3sc7z39dl2",
-                       "BackupDumperTestP2Text1" );
-               $this->assertRevision( $this->revId2_2, "BackupDumperTestP2Summary2",
-                       $this->textId2_2, 23, "b7vj5ks32po5m1z1t1br4o7scdwwy95",
-                       "BackupDumperTestP2Text2", $this->revId2_1 );
-               $this->assertRevision( $this->revId2_3, "BackupDumperTestP2Summary3",
-                       $this->textId2_3, 23, "jfunqmh1ssfb8rs43r19w98k28gg56r",
-                       "BackupDumperTestP2Text3", $this->revId2_2 );
-               $this->assertRevision( $this->revId2_4, "BackupDumperTestP2Summary4 extra",
-                       $this->textId2_4, 44, "6o1ciaxa6pybnqprmungwofc4lv00wv",
-                       "BackupDumperTestP2Text4 some additional Text", $this->revId2_3 );
-               $this->assertPageEnd();
+               $asserter->assertPageStart(
+                       $this->pageId2,
+                       $this->namespace,
+                       $this->pageTitle2->getPrefixedText()
+               );
+               $asserter->assertRevision(
+                       $this->revId2_1,
+                       "BackupDumperTestP2Summary1",
+                       $this->textId2_1,
+                       23,
+                       "jprywrymfhysqllua29tj3sc7z39dl2",
+                       "BackupDumperTestP2Text1"
+               );
+               $asserter->assertRevision(
+                       $this->revId2_2,
+                       "BackupDumperTestP2Summary2",
+                       $this->textId2_2,
+                       23,
+                       "b7vj5ks32po5m1z1t1br4o7scdwwy95",
+                       "BackupDumperTestP2Text2",
+                       $this->revId2_1
+               );
+               $asserter->assertRevision(
+                       $this->revId2_3,
+                       "BackupDumperTestP2Summary3",
+                       $this->textId2_3,
+                       23,
+                       "jfunqmh1ssfb8rs43r19w98k28gg56r",
+                       "BackupDumperTestP2Text3",
+                       $this->revId2_2
+               );
+               $asserter->assertRevision(
+                       $this->revId2_4,
+                       "BackupDumperTestP2Summary4 extra",
+                       $this->textId2_4,
+                       44,
+                       "6o1ciaxa6pybnqprmungwofc4lv00wv",
+                       "BackupDumperTestP2Text4 some additional Text",
+                       $this->revId2_3
+               );
+               $asserter->assertPageEnd();
 
                // Page 3
                // -> Page is marked deleted. Hence not visible
 
                // Page 4
-               $this->assertPageStart(
+               $asserter->assertPageStart(
                        $this->pageId4,
                        $this->talk_namespace,
                        $this->pageTitle4->getPrefixedText()
                );
-               $this->assertRevision( $this->revId4_1, "Talk BackupDumperTestP1 Summary1",
-                       $this->textId4_1, 35, "nktofwzd0tl192k3zfepmlzxoax1lpe",
-                       "Talk about BackupDumperTestP1 Text1" );
-               $this->assertPageEnd();
+               $asserter->assertRevision(
+                       $this->revId4_1,
+                       "Talk BackupDumperTestP1 Summary1",
+                       $this->textId4_1,
+                       35,
+                       "nktofwzd0tl192k3zfepmlzxoax1lpe",
+                       "Talk about BackupDumperTestP1 Text1",
+                       false,
+                       CONTENT_MODEL_WIKITEXT,
+                       CONTENT_FORMAT_WIKITEXT,
+                       $schemaVersion
+               );
+               $asserter->assertPageEnd();
 
-               $this->assertDumpEnd();
+               $asserter->assertDumpEnd();
+
+               // FIXME: add multi-slot test case!
        }
 
-       function testFullStubPlain() {
+       /**
+        * @dataProvider schemaVersionProvider
+        */
+       function testFullStubPlain( $schemaVersion ) {
                // Preparing the dump
                $fname = $this->getNewTempFile();
 
                $dumper = $this->newDumpBackup(
-                       [ '--full', '--quiet', '--output', 'file:' . $fname, '--stub' ],
+                       [
+                               '--full',
+                               '--quiet',
+                               '--output',
+                               'file:' . $fname,
+                               '--stub',
+                               '--schema-version', $schemaVersion,
+                       ],
                        $this->pageId1,
                        $this->pageId4 + 1
                );
@@ -239,48 +310,98 @@ class BackupDumperPageTest extends DumpTestCase {
                $dumper->execute();
 
                // Checking the dumped data
-               $this->assertDumpStart( $fname );
+               $this->assertDumpSchema( $fname, $this->getXmlSchemaPath( $schemaVersion ) );
+               $asserter = $this->getDumpAsserter( $schemaVersion );
+
+               $asserter->assertDumpStart( $fname );
 
                // Page 1
-               $this->assertPageStart( $this->pageId1, $this->namespace, $this->pageTitle1->getPrefixedText() );
-               $this->assertRevision( $this->revId1_1, "BackupDumperTestP1Summary1",
-                       $this->textId1_1, 23, "0bolhl6ol7i6x0e7yq91gxgaan39j87" );
-               $this->assertPageEnd();
+               $asserter->assertPageStart(
+                       $this->pageId1,
+                       $this->namespace,
+                       $this->pageTitle1->getPrefixedText()
+               );
+               $asserter->assertRevision(
+                       $this->revId1_1,
+                       "BackupDumperTestP1Summary1",
+                       $this->textId1_1,
+                       23,
+                       "0bolhl6ol7i6x0e7yq91gxgaan39j87"
+               );
+               $asserter->assertPageEnd();
 
                // Page 2
-               $this->assertPageStart( $this->pageId2, $this->namespace, $this->pageTitle2->getPrefixedText() );
-               $this->assertRevision( $this->revId2_1, "BackupDumperTestP2Summary1",
-                       $this->textId2_1, 23, "jprywrymfhysqllua29tj3sc7z39dl2" );
-               $this->assertRevision( $this->revId2_2, "BackupDumperTestP2Summary2",
-                       $this->textId2_2, 23, "b7vj5ks32po5m1z1t1br4o7scdwwy95", false, $this->revId2_1 );
-               $this->assertRevision( $this->revId2_3, "BackupDumperTestP2Summary3",
-                       $this->textId2_3, 23, "jfunqmh1ssfb8rs43r19w98k28gg56r", false, $this->revId2_2 );
-               $this->assertRevision( $this->revId2_4, "BackupDumperTestP2Summary4 extra",
-                       $this->textId2_4, 44, "6o1ciaxa6pybnqprmungwofc4lv00wv", false, $this->revId2_3 );
-               $this->assertPageEnd();
+               $asserter->assertPageStart(
+                       $this->pageId2,
+                       $this->namespace,
+                       $this->pageTitle2->getPrefixedText()
+               );
+               $asserter->assertRevision(
+                       $this->revId2_1,
+                       "BackupDumperTestP2Summary1",
+                       $this->textId2_1,
+                       23,
+                       "jprywrymfhysqllua29tj3sc7z39dl2"
+               );
+               $asserter->assertRevision(
+                       $this->revId2_2,
+                       "BackupDumperTestP2Summary2",
+                       $this->textId2_2,
+                       23,
+                       "b7vj5ks32po5m1z1t1br4o7scdwwy95",
+                       false,
+                       $this->revId2_1
+               );
+               $asserter->assertRevision(
+                       $this->revId2_3,
+                       "BackupDumperTestP2Summary3",
+                       $this->textId2_3,
+                       23,
+                       "jfunqmh1ssfb8rs43r19w98k28gg56r",
+                       false,
+                       $this->revId2_2
+               );
+               $asserter->assertRevision(
+                       $this->revId2_4,
+                       "BackupDumperTestP2Summary4 extra",
+                       $this->textId2_4,
+                       44,
+                       "6o1ciaxa6pybnqprmungwofc4lv00wv",
+                       false,
+                       $this->revId2_3
+               );
+               $asserter->assertPageEnd();
 
                // Page 3
                // -> Page is marked deleted. Hence not visible
 
                // Page 4
-               $this->assertPageStart(
+               $asserter->assertPageStart(
                        $this->pageId4,
                        $this->talk_namespace,
                        $this->pageTitle4->getPrefixedText()
                );
-               $this->assertRevision( $this->revId4_1, "Talk BackupDumperTestP1 Summary1",
-                       $this->textId4_1, 35, "nktofwzd0tl192k3zfepmlzxoax1lpe" );
-               $this->assertPageEnd();
+               $asserter->assertRevision(
+                       $this->revId4_1,
+                       "Talk BackupDumperTestP1 Summary1",
+                       $this->textId4_1,
+                       35,
+                       "nktofwzd0tl192k3zfepmlzxoax1lpe"
+               );
+               $asserter->assertPageEnd();
 
-               $this->assertDumpEnd();
+               $asserter->assertDumpEnd();
        }
 
-       function testCurrentStubPlain() {
+       /**
+        * @dataProvider schemaVersionProvider
+        */
+       function testCurrentStubPlain( $schemaVersion ) {
                // Preparing the dump
                $fname = $this->getNewTempFile();
 
                $dumper = $this->newDumpBackup(
-                       [ '--output', 'file:' . $fname ],
+                       [ '--output', 'file:' . $fname, '--schema-version', $schemaVersion ],
                        $this->pageId1,
                        $this->pageId4 + 1
                );
@@ -289,34 +410,62 @@ class BackupDumperPageTest extends DumpTestCase {
                $dumper->dump( WikiExporter::CURRENT, WikiExporter::STUB );
 
                // Checking the dumped data
-               $this->assertDumpStart( $fname );
+               $this->assertDumpSchema( $fname, $this->getXmlSchemaPath( $schemaVersion ) );
+
+               $asserter = $this->getDumpAsserter( $schemaVersion );
+               $asserter->assertDumpStart( $fname );
 
                // Page 1
-               $this->assertPageStart( $this->pageId1, $this->namespace, $this->pageTitle1->getPrefixedText() );
-               $this->assertRevision( $this->revId1_1, "BackupDumperTestP1Summary1",
-                       $this->textId1_1, 23, "0bolhl6ol7i6x0e7yq91gxgaan39j87" );
-               $this->assertPageEnd();
+               $asserter->assertPageStart(
+                       $this->pageId1,
+                       $this->namespace,
+                       $this->pageTitle1->getPrefixedText()
+               );
+               $asserter->assertRevision(
+                       $this->revId1_1,
+                       "BackupDumperTestP1Summary1",
+                       $this->textId1_1,
+                       23,
+                       "0bolhl6ol7i6x0e7yq91gxgaan39j87"
+               );
+               $asserter->assertPageEnd();
 
                // Page 2
-               $this->assertPageStart( $this->pageId2, $this->namespace, $this->pageTitle2->getPrefixedText() );
-               $this->assertRevision( $this->revId2_4, "BackupDumperTestP2Summary4 extra",
-                       $this->textId2_4, 44, "6o1ciaxa6pybnqprmungwofc4lv00wv", false, $this->revId2_3 );
-               $this->assertPageEnd();
+               $asserter->assertPageStart(
+                       $this->pageId2,
+                       $this->namespace,
+                       $this->pageTitle2->getPrefixedText()
+               );
+               $asserter->assertRevision(
+                       $this->revId2_4,
+                       "BackupDumperTestP2Summary4 extra",
+                       $this->textId2_4,
+                       44,
+                       "6o1ciaxa6pybnqprmungwofc4lv00wv",
+                       false,
+                       $this->revId2_3
+               );
+               $asserter->assertPageEnd();
 
                // Page 3
                // -> Page is marked deleted. Hence not visible
 
                // Page 4
-               $this->assertPageStart(
+               $asserter->assertPageStart(
                        $this->pageId4,
                        $this->talk_namespace,
                        $this->pageTitle4->getPrefixedText()
                );
-               $this->assertRevision( $this->revId4_1, "Talk BackupDumperTestP1 Summary1",
-                       $this->textId4_1, 35, "nktofwzd0tl192k3zfepmlzxoax1lpe" );
-               $this->assertPageEnd();
+               $asserter->assertRevision(
+                       $this->revId4_1,
+                       "Talk BackupDumperTestP1 Summary1",
+                       $this->textId4_1,
+                       35,
+                       "nktofwzd0tl192k3zfepmlzxoax1lpe"
+               );
+               $asserter->assertPageEnd();
 
-               $this->assertDumpEnd();
+               $asserter->assertDumpEnd();
        }
 
        function testCurrentStubGzip() {
@@ -336,34 +485,56 @@ class BackupDumperPageTest extends DumpTestCase {
 
                // Checking the dumped data
                $this->gunzip( $fname );
-               $this->assertDumpStart( $fname );
+
+               $asserter = $this->getDumpAsserter();
+               $asserter->assertDumpStart( $fname );
 
                // Page 1
-               $this->assertPageStart( $this->pageId1, $this->namespace, $this->pageTitle1->getPrefixedText() );
-               $this->assertRevision( $this->revId1_1, "BackupDumperTestP1Summary1",
-                       $this->textId1_1, 23, "0bolhl6ol7i6x0e7yq91gxgaan39j87" );
-               $this->assertPageEnd();
+               $asserter->assertPageStart(
+                       $this->pageId1,
+                       $this->namespace,
+                       $this->pageTitle1->getPrefixedText()
+               );
+               $asserter->assertRevision(
+                       $this->revId1_1,
+                       "BackupDumperTestP1Summary1",
+                       $this->textId1_1,
+                       23,
+                       "0bolhl6ol7i6x0e7yq91gxgaan39j87"
+               );
+               $asserter->assertPageEnd();
 
                // Page 2
-               $this->assertPageStart( $this->pageId2, $this->namespace, $this->pageTitle2->getPrefixedText() );
-               $this->assertRevision( $this->revId2_4, "BackupDumperTestP2Summary4 extra",
-                       $this->textId2_4, 44, "6o1ciaxa6pybnqprmungwofc4lv00wv", false, $this->revId2_3 );
-               $this->assertPageEnd();
+               $asserter->assertPageStart(
+                       $this->pageId2,
+                       $this->namespace,
+                       $this->pageTitle2->getPrefixedText()
+               );
+               $asserter->assertRevision(
+                       $this->revId2_4,
+                       "BackupDumperTestP2Summary4 extra",
+                       $this->textId2_4,
+                       44,
+                       "6o1ciaxa6pybnqprmungwofc4lv00wv",
+                       false,
+                       $this->revId2_3
+               );
+               $asserter->assertPageEnd();
 
                // Page 3
                // -> Page is marked deleted. Hence not visible
 
                // Page 4
-               $this->assertPageStart(
+               $asserter->assertPageStart(
                        $this->pageId4,
                        $this->talk_namespace,
                        $this->pageTitle4->getPrefixedText()
                );
-               $this->assertRevision( $this->revId4_1, "Talk BackupDumperTestP1 Summary1",
+               $asserter->assertRevision( $this->revId4_1, "Talk BackupDumperTestP1 Summary1",
                        $this->textId4_1, 35, "nktofwzd0tl192k3zfepmlzxoax1lpe" );
-               $this->assertPageEnd();
+               $asserter->assertPageEnd();
 
-               $this->assertDumpEnd();
+               $asserter->assertDumpEnd();
        }
 
        /**
@@ -376,8 +547,10 @@ class BackupDumperPageTest extends DumpTestCase {
         *
         * We reproduce such a setup with our mini fixture, although we omit
         * chunks, and all the other gimmicks of xmldumps-backup.
+        *
+        * @dataProvider schemaVersionProvider
         */
-       function testXmlDumpsBackupUseCase() {
+       function testXmlDumpsBackupUseCase( $schemaVersion ) {
                $this->checkHasGzip();
 
                $fnameMetaHistory = $this->getNewTempFile();
@@ -389,7 +562,7 @@ class BackupDumperPageTest extends DumpTestCase {
                                "--output=gzip:" . $fnameMetaCurrent, "--filter=latest",
                                "--output=gzip:" . $fnameArticles, "--filter=latest",
                                "--filter=notalk", "--filter=namespace:!NS_USER",
-                               "--reporting=1000"
+                               "--reporting=1000", '--schema-version', $schemaVersion
                        ],
                        $this->pageId1,
                        $this->pageId4 + 1
@@ -413,89 +586,187 @@ class BackupDumperPageTest extends DumpTestCase {
                // Checking meta-history -------------------------------------------------
 
                $this->gunzip( $fnameMetaHistory );
-               $this->assertDumpStart( $fnameMetaHistory );
+               $this->assertDumpSchema( $fnameMetaHistory, $this->getXmlSchemaPath( $schemaVersion ) );
+
+               $asserter = $this->getDumpAsserter( $schemaVersion );
+               $asserter->assertDumpStart( $fnameMetaHistory );
 
                // Page 1
-               $this->assertPageStart( $this->pageId1, $this->namespace, $this->pageTitle1->getPrefixedText() );
-               $this->assertRevision( $this->revId1_1, "BackupDumperTestP1Summary1",
-                       $this->textId1_1, 23, "0bolhl6ol7i6x0e7yq91gxgaan39j87" );
-               $this->assertPageEnd();
+               $asserter->assertPageStart(
+                       $this->pageId1,
+                       $this->namespace,
+                       $this->pageTitle1->getPrefixedText()
+               );
+               $asserter->assertRevision(
+                       $this->revId1_1,
+                       "BackupDumperTestP1Summary1",
+                       $this->textId1_1,
+                       23,
+                       "0bolhl6ol7i6x0e7yq91gxgaan39j87"
+               );
+               $asserter->assertPageEnd();
 
                // Page 2
-               $this->assertPageStart( $this->pageId2, $this->namespace, $this->pageTitle2->getPrefixedText() );
-               $this->assertRevision( $this->revId2_1, "BackupDumperTestP2Summary1",
-                       $this->textId2_1, 23, "jprywrymfhysqllua29tj3sc7z39dl2" );
-               $this->assertRevision( $this->revId2_2, "BackupDumperTestP2Summary2",
-                       $this->textId2_2, 23, "b7vj5ks32po5m1z1t1br4o7scdwwy95", false, $this->revId2_1 );
-               $this->assertRevision( $this->revId2_3, "BackupDumperTestP2Summary3",
-                       $this->textId2_3, 23, "jfunqmh1ssfb8rs43r19w98k28gg56r", false, $this->revId2_2 );
-               $this->assertRevision( $this->revId2_4, "BackupDumperTestP2Summary4 extra",
-                       $this->textId2_4, 44, "6o1ciaxa6pybnqprmungwofc4lv00wv", false, $this->revId2_3 );
-               $this->assertPageEnd();
+               $asserter->assertPageStart(
+                       $this->pageId2,
+                       $this->namespace,
+                       $this->pageTitle2->getPrefixedText()
+               );
+               $asserter->assertRevision(
+                       $this->revId2_1,
+                       "BackupDumperTestP2Summary1",
+                       $this->textId2_1,
+                       23,
+                       "jprywrymfhysqllua29tj3sc7z39dl2"
+               );
+               $asserter->assertRevision(
+                       $this->revId2_2,
+                       "BackupDumperTestP2Summary2",
+                       $this->textId2_2,
+                       23,
+                       "b7vj5ks32po5m1z1t1br4o7scdwwy95",
+                       false,
+                       $this->revId2_1
+               );
+               $asserter->assertRevision(
+                       $this->revId2_3,
+                       "BackupDumperTestP2Summary3",
+                       $this->textId2_3,
+                       23,
+                       "jfunqmh1ssfb8rs43r19w98k28gg56r",
+                       false,
+                       $this->revId2_2
+               );
+               $asserter->assertRevision(
+                       $this->revId2_4,
+                       "BackupDumperTestP2Summary4 extra",
+                       $this->textId2_4,
+                       44,
+                       "6o1ciaxa6pybnqprmungwofc4lv00wv",
+                       false,
+                       $this->revId2_3
+               );
+               $asserter->assertPageEnd();
 
                // Page 3
                // -> Page is marked deleted. Hence not visible
 
                // Page 4
-               $this->assertPageStart(
+               $asserter->assertPageStart(
                        $this->pageId4,
                        $this->talk_namespace,
-                       $this->pageTitle4->getPrefixedText()
+                       $this->pageTitle4->getPrefixedText( $schemaVersion )
                );
-               $this->assertRevision( $this->revId4_1, "Talk BackupDumperTestP1 Summary1",
-                       $this->textId4_1, 35, "nktofwzd0tl192k3zfepmlzxoax1lpe" );
-               $this->assertPageEnd();
+               $asserter->assertRevision(
+                       $this->revId4_1,
+                       "Talk BackupDumperTestP1 Summary1",
+                       $this->textId4_1,
+                       35,
+                       "nktofwzd0tl192k3zfepmlzxoax1lpe"
+               );
+               $asserter->assertPageEnd();
 
-               $this->assertDumpEnd();
+               $asserter->assertDumpEnd();
 
                // Checking meta-current -------------------------------------------------
 
                $this->gunzip( $fnameMetaCurrent );
-               $this->assertDumpStart( $fnameMetaCurrent );
+               $this->assertDumpSchema( $fnameMetaCurrent, $this->getXmlSchemaPath( $schemaVersion ) );
+
+               $asserter = $this->getDumpAsserter( $schemaVersion );
+               $asserter->assertDumpStart( $fnameMetaCurrent );
 
                // Page 1
-               $this->assertPageStart( $this->pageId1, $this->namespace, $this->pageTitle1->getPrefixedText() );
-               $this->assertRevision( $this->revId1_1, "BackupDumperTestP1Summary1",
-                       $this->textId1_1, 23, "0bolhl6ol7i6x0e7yq91gxgaan39j87" );
-               $this->assertPageEnd();
+               $asserter->assertPageStart(
+                       $this->pageId1,
+                       $this->namespace,
+                       $this->pageTitle1->getPrefixedText()
+               );
+               $asserter->assertRevision(
+                       $this->revId1_1,
+                       "BackupDumperTestP1Summary1",
+                       $this->textId1_1,
+                       23,
+                       "0bolhl6ol7i6x0e7yq91gxgaan39j87"
+               );
+               $asserter->assertPageEnd();
 
                // Page 2
-               $this->assertPageStart( $this->pageId2, $this->namespace, $this->pageTitle2->getPrefixedText() );
-               $this->assertRevision( $this->revId2_4, "BackupDumperTestP2Summary4 extra",
-                       $this->textId2_4, 44, "6o1ciaxa6pybnqprmungwofc4lv00wv", false, $this->revId2_3 );
-               $this->assertPageEnd();
+               $asserter->assertPageStart(
+                       $this->pageId2,
+                       $this->namespace,
+                       $this->pageTitle2->getPrefixedText()
+               );
+               $asserter->assertRevision(
+                       $this->revId2_4,
+                       "BackupDumperTestP2Summary4 extra",
+                       $this->textId2_4,
+                       44,
+                       "6o1ciaxa6pybnqprmungwofc4lv00wv",
+                       false,
+                       $this->revId2_3
+               );
+               $asserter->assertPageEnd();
 
                // Page 3
                // -> Page is marked deleted. Hence not visible
 
                // Page 4
-               $this->assertPageStart(
+               $asserter->assertPageStart(
                        $this->pageId4,
                        $this->talk_namespace,
                        $this->pageTitle4->getPrefixedText()
                );
-               $this->assertRevision( $this->revId4_1, "Talk BackupDumperTestP1 Summary1",
-                       $this->textId4_1, 35, "nktofwzd0tl192k3zfepmlzxoax1lpe" );
-               $this->assertPageEnd();
+               $asserter->assertRevision(
+                       $this->revId4_1,
+                       "Talk BackupDumperTestP1 Summary1",
+                       $this->textId4_1,
+                       35,
+                       "nktofwzd0tl192k3zfepmlzxoax1lpe"
+               );
+               $asserter->assertPageEnd();
 
-               $this->assertDumpEnd();
+               $asserter->assertDumpEnd();
 
                // Checking articles -------------------------------------------------
 
                $this->gunzip( $fnameArticles );
-               $this->assertDumpStart( $fnameArticles );
+               $this->assertDumpSchema( $fnameArticles, $this->getXmlSchemaPath( $schemaVersion ) );
+
+               $asserter = $this->getDumpAsserter( $schemaVersion );
+               $asserter->assertDumpStart( $fnameArticles );
 
                // Page 1
-               $this->assertPageStart( $this->pageId1, $this->namespace, $this->pageTitle1->getPrefixedText() );
-               $this->assertRevision( $this->revId1_1, "BackupDumperTestP1Summary1",
-                       $this->textId1_1, 23, "0bolhl6ol7i6x0e7yq91gxgaan39j87" );
-               $this->assertPageEnd();
+               $asserter->assertPageStart(
+                       $this->pageId1,
+                       $this->namespace,
+                       $this->pageTitle1->getPrefixedText()
+               );
+               $asserter->assertRevision(
+                       $this->revId1_1,
+                       "BackupDumperTestP1Summary1",
+                       $this->textId1_1,
+                       23,
+                       "0bolhl6ol7i6x0e7yq91gxgaan39j87"
+               );
+               $asserter->assertPageEnd();
 
                // Page 2
-               $this->assertPageStart( $this->pageId2, $this->namespace, $this->pageTitle2->getPrefixedText() );
-               $this->assertRevision( $this->revId2_4, "BackupDumperTestP2Summary4 extra",
-                       $this->textId2_4, 44, "6o1ciaxa6pybnqprmungwofc4lv00wv", false, $this->revId2_3 );
-               $this->assertPageEnd();
+               $asserter->assertPageStart(
+                       $this->pageId2,
+                       $this->namespace,
+                       $this->pageTitle2->getPrefixedText()
+               );
+               $asserter->assertRevision(
+                       $this->revId2_4,
+                       "BackupDumperTestP2Summary4 extra",
+                       $this->textId2_4,
+                       44,
+                       "6o1ciaxa6pybnqprmungwofc4lv00wv",
+                       false,
+                       $this->revId2_3
+               );
+               $asserter->assertPageEnd();
 
                // Page 3
                // -> Page is marked deleted. Hence not visible
@@ -503,7 +774,7 @@ class BackupDumperPageTest extends DumpTestCase {
                // Page 4
                // -> Page is not in $this->namespace. Hence not visible
 
-               $this->assertDumpEnd();
+               $asserter->assertDumpEnd();
 
                $this->expectETAOutput();
        }
diff --git a/tests/phpunit/maintenance/xml.xsd b/tests/phpunit/maintenance/xml.xsd
new file mode 100644 (file)
index 0000000..aea7d0d
--- /dev/null
@@ -0,0 +1,287 @@
+<?xml version='1.0'?>
+<?xml-stylesheet href="../2008/09/xsd.xsl" type="text/xsl"?>
+<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace" 
+  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
+  xmlns   ="http://www.w3.org/1999/xhtml"
+  xml:lang="en">
+
+ <xs:annotation>
+  <xs:documentation>
+   <div>
+    <h1>About the XML namespace</h1>
+
+    <div class="bodytext">
+     <p>
+      This schema document describes the XML namespace, in a form
+      suitable for import by other schema documents.
+     </p>
+     <p>
+      See <a href="http://www.w3.org/XML/1998/namespace.html">
+      http://www.w3.org/XML/1998/namespace.html</a> and
+      <a href="http://www.w3.org/TR/REC-xml">
+      http://www.w3.org/TR/REC-xml</a> for information 
+      about this namespace.
+     </p>
+     <p>
+      Note that local names in this namespace are intended to be
+      defined only by the World Wide Web Consortium or its subgroups.
+      The names currently defined in this namespace are listed below.
+      They should not be used with conflicting semantics by any Working
+      Group, specification, or document instance.
+     </p>
+     <p>   
+      See further below in this document for more information about <a
+      href="#usage">how to refer to this schema document from your own
+      XSD schema documents</a> and about <a href="#nsversioning">the
+      namespace-versioning policy governing this schema document</a>.
+     </p>
+    </div>
+   </div>
+  </xs:documentation>
+ </xs:annotation>
+
+ <xs:attribute name="lang">
+  <xs:annotation>
+   <xs:documentation>
+    <div>
+     
+      <h3>lang (as an attribute name)</h3>
+      <p>
+       denotes an attribute whose value
+       is a language code for the natural language of the content of
+       any element; its value is inherited.  This name is reserved
+       by virtue of its definition in the XML specification.</p>
+     
+    </div>
+    <div>
+     <h4>Notes</h4>
+     <p>
+      Attempting to install the relevant ISO 2- and 3-letter
+      codes as the enumerated possible values is probably never
+      going to be a realistic possibility.  
+     </p>
+     <p>
+      See BCP 47 at <a href="http://www.rfc-editor.org/rfc/bcp/bcp47.txt">
+       http://www.rfc-editor.org/rfc/bcp/bcp47.txt</a>
+      and the IANA language subtag registry at
+      <a href="http://www.iana.org/assignments/language-subtag-registry">
+       http://www.iana.org/assignments/language-subtag-registry</a>
+      for further information.
+     </p>
+     <p>
+      The union allows for the 'un-declaration' of xml:lang with
+      the empty string.
+     </p>
+    </div>
+   </xs:documentation>
+  </xs:annotation>
+  <xs:simpleType>
+   <xs:union memberTypes="xs:language">
+    <xs:simpleType>    
+     <xs:restriction base="xs:string">
+      <xs:enumeration value=""/>
+     </xs:restriction>
+    </xs:simpleType>
+   </xs:union>
+  </xs:simpleType>
+ </xs:attribute>
+
+ <xs:attribute name="space">
+  <xs:annotation>
+   <xs:documentation>
+    <div>
+     
+      <h3>space (as an attribute name)</h3>
+      <p>
+       denotes an attribute whose
+       value is a keyword indicating what whitespace processing
+       discipline is intended for the content of the element; its
+       value is inherited.  This name is reserved by virtue of its
+       definition in the XML specification.</p>
+     
+    </div>
+   </xs:documentation>
+  </xs:annotation>
+  <xs:simpleType>
+   <xs:restriction base="xs:NCName">
+    <xs:enumeration value="default"/>
+    <xs:enumeration value="preserve"/>
+   </xs:restriction>
+  </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="base" type="xs:anyURI"> <xs:annotation>
+   <xs:documentation>
+    <div>
+     
+      <h3>base (as an attribute name)</h3>
+      <p>
+       denotes an attribute whose value
+       provides a URI to be used as the base for interpreting any
+       relative URIs in the scope of the element on which it
+       appears; its value is inherited.  This name is reserved
+       by virtue of its definition in the XML Base specification.</p>
+     
+     <p>
+      See <a
+      href="http://www.w3.org/TR/xmlbase/">http://www.w3.org/TR/xmlbase/</a>
+      for information about this attribute.
+     </p>
+    </div>
+   </xs:documentation>
+  </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="id" type="xs:ID">
+  <xs:annotation>
+   <xs:documentation>
+    <div>
+     
+      <h3>id (as an attribute name)</h3> 
+      <p>
+       denotes an attribute whose value
+       should be interpreted as if declared to be of type ID.
+       This name is reserved by virtue of its definition in the
+       xml:id specification.</p>
+     
+     <p>
+      See <a
+      href="http://www.w3.org/TR/xml-id/">http://www.w3.org/TR/xml-id/</a>
+      for information about this attribute.
+     </p>
+    </div>
+   </xs:documentation>
+  </xs:annotation>
+ </xs:attribute>
+
+ <xs:attributeGroup name="specialAttrs">
+  <xs:attribute ref="xml:base"/>
+  <xs:attribute ref="xml:lang"/>
+  <xs:attribute ref="xml:space"/>
+  <xs:attribute ref="xml:id"/>
+ </xs:attributeGroup>
+
+ <xs:annotation>
+  <xs:documentation>
+   <div>
+   
+    <h3>Father (in any context at all)</h3> 
+
+    <div class="bodytext">
+     <p>
+      denotes Jon Bosak, the chair of 
+      the original XML Working Group.  This name is reserved by 
+      the following decision of the W3C XML Plenary and 
+      XML Coordination groups:
+     </p>
+     <blockquote>
+       <p>
+       In appreciation for his vision, leadership and
+       dedication the W3C XML Plenary on this 10th day of
+       February, 2000, reserves for Jon Bosak in perpetuity
+       the XML name "xml:Father".
+       </p>
+     </blockquote>
+    </div>
+   </div>
+  </xs:documentation>
+ </xs:annotation>
+
+ <xs:annotation>
+  <xs:documentation>
+   <div xml:id="usage" id="usage">
+    <h2><a name="usage">About this schema document</a></h2>
+
+    <div class="bodytext">
+     <p>
+      This schema defines attributes and an attribute group suitable
+      for use by schemas wishing to allow <code>xml:base</code>,
+      <code>xml:lang</code>, <code>xml:space</code> or
+      <code>xml:id</code> attributes on elements they define.
+     </p>
+     <p>
+      To enable this, such a schema must import this schema for
+      the XML namespace, e.g. as follows:
+     </p>
+     <pre>
+          &lt;schema . . .>
+           . . .
+           &lt;import namespace="http://www.w3.org/XML/1998/namespace"
+                      schemaLocation="http://www.w3.org/2001/xml.xsd"/>
+     </pre>
+     <p>
+      or
+     </p>
+     <pre>
+           &lt;import namespace="http://www.w3.org/XML/1998/namespace"
+                      schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
+     </pre>
+     <p>
+      Subsequently, qualified reference to any of the attributes or the
+      group defined below will have the desired effect, e.g.
+     </p>
+     <pre>
+          &lt;type . . .>
+           . . .
+           &lt;attributeGroup ref="xml:specialAttrs"/>
+     </pre>
+     <p>
+      will define a type which will schema-validate an instance element
+      with any of those attributes.
+     </p>
+    </div>
+   </div>
+  </xs:documentation>
+ </xs:annotation>
+
+ <xs:annotation>
+  <xs:documentation>
+   <div id="nsversioning" xml:id="nsversioning">
+    <h2><a name="nsversioning">Versioning policy for this schema document</a></h2>
+    <div class="bodytext">
+     <p>
+      In keeping with the XML Schema WG's standard versioning
+      policy, this schema document will persist at
+      <a href="http://www.w3.org/2009/01/xml.xsd">
+       http://www.w3.org/2009/01/xml.xsd</a>.
+     </p>
+     <p>
+      At the date of issue it can also be found at
+      <a href="http://www.w3.org/2001/xml.xsd">
+       http://www.w3.org/2001/xml.xsd</a>.
+     </p>
+     <p>
+      The schema document at that URI may however change in the future,
+      in order to remain compatible with the latest version of XML
+      Schema itself, or with the XML namespace itself.  In other words,
+      if the XML Schema or XML namespaces change, the version of this
+      document at <a href="http://www.w3.org/2001/xml.xsd">
+       http://www.w3.org/2001/xml.xsd 
+      </a> 
+      will change accordingly; the version at 
+      <a href="http://www.w3.org/2009/01/xml.xsd">
+       http://www.w3.org/2009/01/xml.xsd 
+      </a> 
+      will not change.
+     </p>
+     <p>
+      Previous dated (and unchanging) versions of this schema 
+      document are at:
+     </p>
+     <ul>
+      <li><a href="http://www.w3.org/2009/01/xml.xsd">
+       http://www.w3.org/2009/01/xml.xsd</a></li>
+      <li><a href="http://www.w3.org/2007/08/xml.xsd">
+       http://www.w3.org/2007/08/xml.xsd</a></li>
+      <li><a href="http://www.w3.org/2004/10/xml.xsd">
+       http://www.w3.org/2004/10/xml.xsd</a></li>
+      <li><a href="http://www.w3.org/2001/03/xml.xsd">
+       http://www.w3.org/2001/03/xml.xsd</a></li>
+     </ul>
+    </div>
+   </div>
+  </xs:documentation>
+ </xs:annotation>
+
+</xs:schema>
+
index 0a04993..a1bdbad 100644 (file)
@@ -32,7 +32,7 @@ class MockFileBackend extends MemoryFileBackend {
        protected function doGetLocalCopyMulti( array $params ) {
                $tmpFiles = []; // (path => MockFSFile)
                foreach ( $params['srcs'] as $src ) {
-                       $tmpFiles[$src] = new MockFSFile( wfTempDir() . '/' . wfRandomString( 32 ) );
+                       $tmpFiles[$src] = new MockFSFile( "Fake path for $src" );
                }
                return $tmpFiles;
        }
index eeaf05a..b2c51ca 100644 (file)
@@ -7,17 +7,16 @@
  * @since 1.28
  */
 class MockLocalRepo extends LocalRepo {
-       function getLocalCopy( $virtualUrl ) {
-               return new MockFSFile( wfTempDir() . '/' . wfRandomString( 32 ) );
+       public function getLocalCopy( $virtualUrl ) {
+               return new MockFSFile( "Fake path for $virtualUrl" );
        }
 
-       function getLocalReference( $virtualUrl ) {
-               return new MockFSFile( wfTempDir() . '/' . wfRandomString( 32 ) );
+       public function getLocalReference( $virtualUrl ) {
+               return new MockFSFile( "Fake path for $virtualUrl" );
        }
 
-       function getFileProps( $virtualUrl ) {
+       public function getFileProps( $virtualUrl ) {
                $fsFile = $this->getLocalReference( $virtualUrl );
-
                return $fsFile->getProps();
        }
 }
index d92d39a..e92eb56 100644 (file)
@@ -7,6 +7,7 @@ class MockSearchResult extends SearchResult {
        public function isMissingRevision() {
                return $this->isMissingRevision;
        }
+
        public function setMissingRevision( $isMissingRevision ) {
                $this->isMissingRevision = $isMissingRevision;
                return $this;
index 4c64291..0d10a20 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 
+use MediaWiki\MediaWikiServices;
 use Wikimedia\TestingAccessWrapper;
 
 /**
@@ -500,10 +501,8 @@ class ApiStructureTest extends MediaWikiTestCase {
                                                if ( $value instanceof $type ) {
                                                        return;
                                                }
-                                       } else {
-                                               if ( gettype( $value ) === $type ) {
-                                                       return;
-                                               }
+                                       } elseif ( gettype( $value ) === $type ) {
+                                               return;
                                        }
                                } else {
                                        // Array whose values have specified types, recurse
@@ -568,7 +567,8 @@ class ApiStructureTest extends MediaWikiTestCase {
                                break;
 
                        case 'namespace':
-                               $validValues = MWNamespace::getValidNamespaces();
+                               $validValues = MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                       getValidNamespaces();
                                if (
                                        isset( $config[ApiBase::PARAM_EXTRA_NAMESPACES] ) &&
                                        is_array( $config[ApiBase::PARAM_EXTRA_NAMESPACES] )
index 75e21ae..2ae6a78 100644 (file)
@@ -112,14 +112,12 @@ class AutoLoaderStructureTest extends MediaWikiTestCase {
                                // 'class Foo {}'
                                $class = $fileNamespace . $match['class'];
                                $classesInFile[$class] = true;
+                       } elseif ( !empty( $match['original'] ) ) {
+                               // 'class_alias( "Foo", "Bar" );'
+                               $aliasesInFile[$match['alias']] = $match['original'];
                        } else {
-                               if ( !empty( $match['original'] ) ) {
-                                       // 'class_alias( "Foo", "Bar" );'
-                                       $aliasesInFile[$match['alias']] = $match['original'];
-                               } else {
-                                       // 'class_alias( Foo::class, "Bar" );'
-                                       $aliasesInFile[$match['aliasString']] = $fileNamespace . $match['originalStatic'];
-                               }
+                               // 'class_alias( Foo::class, "Bar" );'
+                               $aliasesInFile[$match['aliasString']] = $fileNamespace . $match['originalStatic'];
                        }
                }
 
index a7d947e..57b063d 100644 (file)
@@ -54,6 +54,17 @@ class AvailableRightsTest extends PHPUnit\Framework\TestCase {
                );
        }
 
+       /**
+        * Test, if for all rights an action- message exist,
+        * which is used on Special:ListGroupRights as help text
+        * Extensions and core
+        *
+        * @coversNothing
+        */
+       public function testAllActionsWithMessages() {
+               $this->checkMessagesExist( 'action-' );
+       }
+
        /**
         * Test, if for all rights a right- message exist,
         * which is used on Special:ListGroupRights as help text
@@ -62,27 +73,34 @@ class AvailableRightsTest extends PHPUnit\Framework\TestCase {
         * @coversNothing
         */
        public function testAllRightsWithMessage() {
+               $this->checkMessagesExist( 'right-' );
+       }
+
+       /**
+        * @param string $prefix
+        */
+       private function checkMessagesExist( $prefix ) {
                // Getting all user rights, for core: User::$mCoreRights, for extensions: $wgAvailableRights
                $allRights = User::getAllRights();
                $allMessageKeys = Language::getMessageKeysFor( 'en' );
 
-               $rightsWithMessage = [];
+               $messagesToCheck = [];
                foreach ( $allMessageKeys as $message ) {
                        // === 0: must be at beginning of string (position 0)
-                       if ( strpos( $message, 'right-' ) === 0 ) {
-                               $rightsWithMessage[] = substr( $message, strlen( 'right-' ) );
+                       if ( strpos( $message, $prefix ) === 0 ) {
+                               $messagesToCheck[] = substr( $message, strlen( $prefix ) );
                        }
                }
 
                $missing = array_diff(
                        $allRights,
-                       $rightsWithMessage
+                       $messagesToCheck
                );
 
                $this->assertEquals(
                        [],
                        $missing,
-                       'Each user rights (core/extensions) has a corresponding right- message.'
+                       "Each user right (core/extensions) has a corresponding $prefix message."
                );
        }
 }
index c08fe2f..026b903 100644 (file)
@@ -32,8 +32,17 @@ class SpecialPageFatalTest extends MediaWikiTestCase {
 
                try {
                        $executor->executeSpecialPage( $page, '', null, null, $user );
+               } catch ( \PHPUnit\Framework\Error\Deprecated $deprecated ) {
+                       // Allow deprecation,
+                       // this test want to check fatals or other things breaking the extension
+               } catch ( \PHPUnit\Framework\Error\Error $error ) {
+                       // Let phpunit settings working:
+                       // - convertErrorsToExceptions="true"
+                       // - convertNoticesToExceptions="true"
+                       // - convertWarningsToExceptions="true"
+                       throw $error;
                } catch ( Exception $e ) {
-                       // Exceptions are allowed
+                       // Other exceptions are allowed
                }
 
                // If the page fataled phpunit will have already died
index 77461c5..28547d1 100644 (file)
@@ -113,7 +113,7 @@ class ParserTestTopLevelSuite extends PHPUnit_Framework_TestSuite {
                        $testsName = $extensionName . '__' . basename( $fileName, '.txt' );
                        $parserTestClassName = ucfirst( $testsName );
 
-                       // Official spec for class names: https://secure.php.net/manual/en/language.oop5.basic.php
+                       // Official spec for class names: https://www.php.net/manual/en/language.oop5.basic.php
                        // Prepend 'ParserTest_' to be paranoid about it not starting with a number
                        $parserTestClassName = 'ParserTest_' .
                                preg_replace( '/[^a-zA-Z0-9_\x7f-\xff]/', '_', $parserTestClassName );
index 556c754..d340221 100644 (file)
@@ -1,5 +1,7 @@
 <?php
 
+use MediaWiki\MediaWikiServices;
+
 require_once dirname( __DIR__ ) . '/includes/upload/UploadFromUrlTest.php';
 
 class UploadFromUrlTestSuite extends PHPUnit_Framework_TestSuite {
@@ -16,8 +18,7 @@ class UploadFromUrlTestSuite extends PHPUnit_Framework_TestSuite {
        }
 
        protected function setUp() {
-               global $wgParser, $wgParserConf, $IP, $messageMemc, $wgMemc, $wgUser,
-                       $wgLang, $wgOut, $wgRequest, $wgStyleDirectory,
+               global $IP, $messageMemc, $wgMemc, $wgUser, $wgLang, $wgOut, $wgRequest, $wgStyleDirectory,
                        $wgParserCacheType, $wgNamespaceAliases, $wgNamespaceProtection;
 
                $tmpDir = $this->getNewTempDirectory();
@@ -58,7 +59,7 @@ class UploadFromUrlTestSuite extends PHPUnit_Framework_TestSuite {
 
                $wgParserCacheType = CACHE_NONE;
                DeferredUpdates::clearPendingUpdates();
-               $wgMemc = wfGetMainCache();
+               $wgMemc = ObjectCache::getLocalClusterInstance();
                $messageMemc = wfGetMessageCacheStorage();
 
                RequestContext::resetMain();
@@ -66,14 +67,13 @@ class UploadFromUrlTestSuite extends PHPUnit_Framework_TestSuite {
                $wgUser = new User;
                $wgLang = $context->getLanguage();
                $wgOut = $context->getOutput();
-               $wgParser = new StubObject( 'wgParser', $wgParserConf['class'], [ $wgParserConf ] );
                $wgRequest = $context->getRequest();
 
                if ( $wgStyleDirectory === false ) {
                        $wgStyleDirectory = "$IP/skins";
                }
 
-               RepoGroup::destroySingleton();
+               MediaWikiServices::getInstance()->resetServiceForTesting( 'RepoGroup' );
                FileBackendGroup::destroySingleton();
        }
 
@@ -82,7 +82,7 @@ class UploadFromUrlTestSuite extends PHPUnit_Framework_TestSuite {
                        $GLOBALS[$var] = $val;
                }
                // Restore backends
-               RepoGroup::destroySingleton();
+               MediaWikiServices::getInstance()->resetServiceForTesting( 'RepoGroup' );
                FileBackendGroup::destroySingleton();
 
                parent::tearDown();
index 6b5a487..cfc01ea 100644 (file)
@@ -67,32 +67,7 @@ class MediaWikiTestCaseTest extends MediaWikiTestCase {
        }
 
        /**
-        * @dataProvider provideExistingKeysAndNewValues
-        *
-        * @covers MediaWikiTestCase::stashMwGlobals
-        * @covers MediaWikiTestCase::tearDown
-        */
-       public function testStashedGlobalsAreRestoredOnTearDown( $globalKey, $newValue ) {
-               $this->hideDeprecated( 'MediaWikiTestCase::stashMwGlobals' );
-               $this->stashMwGlobals( $globalKey );
-               $GLOBALS[$globalKey] = $newValue;
-               $this->assertEquals(
-                       $newValue,
-                       $GLOBALS[$globalKey],
-                       'Global failed to correctly set'
-               );
-
-               $this->tearDown();
-
-               $this->assertEquals(
-                       self::$startGlobals[$globalKey],
-                       $GLOBALS[$globalKey],
-                       'Global failed to be restored on tearDown'
-               );
-       }
-
-       /**
-        * @covers MediaWikiTestCase::stashMwGlobals
+        * @covers MediaWikiTestCase::setMwGlobals
         * @covers MediaWikiTestCase::tearDown
         */
        public function testSetNonExistentGlobalsAreUnsetOnTearDown() {
index 2238fce..9f57190 100644 (file)
@@ -77,8 +77,8 @@ mw.loader.implement( 'testUrlOrder.b', function () {} );
 
 $response = '';
 
-// Does not support the full behaviour of ResourceLoaderContext::expandModuleNames(),
-// Only supports dotless module names joined by comma,
+// Does not support the full behaviour of the real load.php.
+// This only supports dotless module names joined by comma,
 // with the exception of the hardcoded cases for testUrl*.
 if ( isset( $_GET['modules'] ) ) {
        if ( $_GET['modules'] === 'testUrlInc,testUrlIncDump|testUrlInc.a,b' ) {
index 0bcce12..29cffaf 100644 (file)
@@ -7,7 +7,7 @@
        } ) );
 
        QUnit.test( '.parse( string )', function ( assert ) {
-               this.server.respondWith( /action=parse.*&text='''Hello(\+|%20)world'''/, [ 200,
+               this.server.respondWith( 'POST', /api.php/, [ 200,
                        { 'Content-Type': 'application/json' },
                        '{ "parse": { "text": "<p><b>Hello world</b></p>" } }'
                ] );
@@ -18,7 +18,7 @@
        } );
 
        QUnit.test( '.parse( Object.toString )', function ( assert ) {
-               this.server.respondWith( /action=parse.*&text='''Hello(\+|%20)world'''/, [ 200,
+               this.server.respondWith( 'POST', /api.php/, [ 200,
                        { 'Content-Type': 'application/json' },
                        '{ "parse": { "text": "<p><b>Hello world</b></p>" } }'
                ] );
@@ -33,7 +33,7 @@
        } );
 
        QUnit.test( '.parse( mw.Title )', function ( assert ) {
-               this.server.respondWith( /action=parse.*&page=Earth/, [ 200,
+               this.server.respondWith( 'GET', /action=parse.*&page=Earth/, [ 200,
                        { 'Content-Type': 'application/json' },
                        '{ "parse": { "text": "<p><b>Earth</b> is a planet.</p>" } }'
                ] );
index 1c7d8ee..2fcf61e 100644 (file)
                );
 
                mw.config.set( 'wgUserLanguage', 'qqx' );
+
                $bar = $( '<b>' ).text( 'bar' );
-               assert.strictEqual( mw.message( 'foo', $bar, 'baz' ).parse(), '(foo: <b>bar</b>, baz)', 'qqx message with parameters' );
+               mw.messages.set( 'qqx-message', '(qqx-message)' );
+               mw.messages.set( 'non-qqx-message', '<b>hello world</b>' );
+
+               assert.strictEqual( mw.message( 'missing-message' ).parse(), '(missing-message)', 'qqx message (missing)' );
+               assert.strictEqual( mw.message( 'missing-message', $bar, 'baz' ).parse(), '(missing-message: <b>bar</b>, baz)', 'qqx message (missing) with parameters' );
+               assert.strictEqual( mw.message( 'qqx-message' ).parse(), '(qqx-message)', 'qqx message (defined)' );
+               assert.strictEqual( mw.message( 'qqx-message', $bar, 'baz' ).parse(), '(qqx-message: <b>bar</b>, baz)', 'qqx message (defined) with parameters' );
+               assert.strictEqual( mw.message( 'non-qqx-message' ).parse(), '<b>hello world</b>', 'non-qqx message in qqx mode' );
        } );
 
        QUnit.test( 'setParserDefaults', function ( assert ) {
index e17c78d..ed1288b 100644 (file)
                assert.deepEqual(
                        [ {
                                topic: 'resourceloader.exception',
-                               error: 'Unknown dependency: test.load.unreg',
+                               error: 'Unknown module: test.load.unreg',
                                source: 'resolve'
                        } ],
                        capture
                assert.deepEqual(
                        [ {
                                topic: 'resourceloader.exception',
-                               error: 'Unknown dependency: test.load.missingdep2',
+                               error: 'Unknown module: test.load.missingdep2',
                                source: 'resolve'
                        } ],
                        capture
 
        QUnit.test( '.implement( package files )', function ( assert ) {
                var done = assert.async(),
-                       initJsRan = false;
+                       initJsRan = false,
+                       counter = 41;
                mw.loader.implement(
                        'test.implement.packageFiles',
                        {
                                files: {
                                        'resources/src/foo/data/hello.json': { hello: 'world' },
                                        'resources/src/foo/foo.js': function ( require, module ) {
-                                               window.mwTestFooJsCounter = window.mwTestFooJsCounter || 41;
-                                               window.mwTestFooJsCounter++;
-                                               module.exports = { answer: window.mwTestFooJsCounter };
+                                               counter++;
+                                               module.exports = { answer: counter };
                                        },
                                        'resources/src/bar/bar.js': function ( require, module ) {
                                                var core = require( './core.js' );
index fab7e1f..82d5ea5 100644 (file)
@@ -1,23 +1,44 @@
 ( function () {
        QUnit.module( 'mediawiki.storage' );
 
-       QUnit.test( 'set/get with storage support', function ( assert ) {
-               var stub = {
-                       setItem: this.sandbox.spy(),
-                       getItem: this.sandbox.stub()
-               };
-               stub.getItem.withArgs( 'foo' ).returns( 'test' );
-               stub.getItem.returns( null );
+       QUnit.test( 'set/get(Object) with storage support', function ( assert ) {
+               var data = {},
+                       object = { test: 'value' },
+                       stub = {
+                               setItem: function ( k, v ) {
+                                       data[ k ] = v;
+                                       return true;
+                               },
+                               getItem: function ( k ) {
+                                       return Object.prototype.hasOwnProperty.call( data, k ) ? data[ k ] : null;
+                               },
+                               removeItem: function ( k ) {
+                                       delete data[ k ];
+                                       return true;
+                               }
+                       };
+
                this.sandbox.stub( mw.storage, 'store', stub );
 
-               mw.storage.set( 'foo', 'test' );
-               assert.ok( stub.setItem.calledOnce );
+               assert.strictEqual( mw.storage.set( 'foo', 'test' ), true, 'set returns true' );
+               assert.strictEqual( mw.storage.get( 'foo' ), 'test', 'Check value gets stored' );
+               assert.strictEqual( mw.storage.get( 'bar' ), null, 'Unset values are null' );
+               assert.strictEqual( mw.storage.remove( 'foo' ), true, 'remove returns true' );
+               assert.strictEqual( mw.storage.get( 'foo' ), null, 'Removed item is null' );
+
+               assert.strictEqual( mw.storage.setObject( 'baz', object ), true, 'setObject returns true' );
+               assert.deepEqual( mw.storage.getObject( 'baz' ), object, 'Check value gets stored' );
+               assert.notStrictEqual( mw.storage.getObject( 'baz' ), object, 'Retrieved value is a new object' );
+               assert.strictEqual( mw.storage.getObject( 'quux' ), null, 'Unset values are null' );
+               assert.strictEqual( mw.storage.remove( 'baz' ), true, 'remove returns true' );
+               assert.strictEqual( mw.storage.getObject( 'baz' ), null, 'Removed item is null' );
+
+               mw.storage.set( 'baz', 'Non-JSON' );
+               assert.strictEqual( mw.storage.getObject( 'baz' ), null, 'Non-JSON values are null' );
 
-               assert.strictEqual( mw.storage.get( 'foo' ), 'test', 'Check value gets stored.' );
-               assert.strictEqual( mw.storage.get( 'bar' ), null, 'Unset values are null.' );
        } );
 
-       QUnit.test( 'set/get with storage methods disabled', function ( assert ) {
+       QUnit.test( 'set/get(Object) with storage methods disabled', function ( assert ) {
                // This covers browsers where storage is disabled
                // (quota full, or security/privacy settings).
                // On most browsers, these interface will be accessible with
 
                assert.strictEqual( mw.storage.get( 'foo' ), false );
                assert.strictEqual( mw.storage.set( 'foo', 'test' ), false );
-               assert.strictEqual( mw.storage.remove( 'foo', 'test' ), false );
+               assert.strictEqual( mw.storage.remove( 'foo' ), false );
+
+               assert.strictEqual( mw.storage.getObject( 'bar' ), false );
+               assert.strictEqual( mw.storage.setObject( 'bar', { test: 'value' } ), false );
+               assert.strictEqual( mw.storage.remove( 'bar' ), false );
        } );
 
-       QUnit.test( 'set/get with storage object disabled', function ( assert ) {
+       QUnit.test( 'set/get(Object) with storage object disabled', function ( assert ) {
                // On other browsers, these entire object is disabled.
                // `'localStorage' in window` would be true (and pass feature test)
                // but trying to read the object as window.localStorage would throw
                assert.strictEqual( mw.storage.set( 'foo', 'test' ), false );
                assert.strictEqual( mw.storage.remove( 'foo', 'test' ), false );
 
+               assert.strictEqual( mw.storage.getObject( 'bar' ), false );
+               assert.strictEqual( mw.storage.setObject( 'bar', { test: 'value' } ), false );
+               assert.strictEqual( mw.storage.remove( 'bar' ), false );
+
                mw.storage.store = old;
        } );
 
index 425e18e..08262b2 100644 (file)
                );
 
                mw.config.set( 'wgUserLanguage', 'qqx' );
-               assert.strictEqual( mw.message( 'foo' ).plain(), '(foo)', 'qqx message' );
-               assert.strictEqual( mw.message( 'foo', 'bar', 'baz' ).plain(), '(foo: bar, baz)', 'qqx message with parameters' );
+
+               mw.messages.set( 'qqx-message', '(qqx-message)' );
+               mw.messages.set( 'non-qqx-message', 'hello world' );
+
+               assert.strictEqual( mw.message( 'missing-message' ).plain(), '(missing-message)', 'qqx message (missing)' );
+               assert.strictEqual( mw.message( 'missing-message', 'bar', 'baz' ).plain(), '(missing-message: bar, baz)', 'qqx message (missing) with parameters' );
+               assert.strictEqual( mw.message( 'qqx-message' ).plain(), '(qqx-message)', 'qqx message (defined)' );
+               assert.strictEqual( mw.message( 'qqx-message', 'bar', 'baz' ).plain(), '(qqx-message: bar, baz)', 'qqx message (defined) with parameters' );
+               assert.strictEqual( mw.message( 'non-qqx-message' ).plain(), 'hello world', 'non-qqx message in qqx mode' );
        } );
 
        QUnit.test( 'mw.msg', function ( assert ) {
index 1e35211..2487672 100644 (file)
@@ -2,6 +2,7 @@
        QUnit.module( 'mediawiki.user', QUnit.newMwEnvironment( {
                setup: function () {
                        this.server = this.sandbox.useFakeServer();
+                       this.server.respondImmediately = true;
                        // Cannot stub by simple assignment because read-only.
                        // Instead, stub in tests by using 'delete', and re-create
                        // in teardown using the original descriptor (including its
                assert.strictEqual( mw.user.id(), 'John', 'user.id()' );
        } );
 
-       QUnit.test( 'getUserInfo', function ( assert ) {
+       QUnit.test( 'getGroups (callback)', function ( assert ) {
+               var done = assert.async();
                mw.config.set( 'wgUserGroups', [ '*', 'user' ] );
 
                mw.user.getGroups( function ( groups ) {
                        assert.deepEqual( groups, [ '*', 'user' ], 'Result' );
+                       done();
                } );
+       } );
+
+       QUnit.test( 'getGroups (Promise)', function ( assert ) {
+               mw.config.set( 'wgUserGroups', [ '*', 'user' ] );
+
+               return mw.user.getGroups().then( function ( groups ) {
+                       assert.deepEqual( groups, [ '*', 'user' ], 'Result' );
+               } );
+       } );
+
+       QUnit.test( 'getRights (callback)', function ( assert ) {
+               var done = assert.async();
+
+               this.server.respond( [ 200, { 'Content-Type': 'application/json' },
+                       '{ "query": { "userinfo": { "groups": [ "unused" ], "rights": [ "read", "edit", "createtalk" ] } } }'
+               ] );
 
                mw.user.getRights( function ( rights ) {
                        assert.deepEqual( rights, [ 'read', 'edit', 'createtalk' ], 'Result (callback)' );
+                       done();
                } );
+       } );
 
-               mw.user.getRights().done( function ( rights ) {
-                       assert.deepEqual( rights, [ 'read', 'edit', 'createtalk' ], 'Result (promise)' );
-               } );
+       QUnit.test( 'getRights (Promise)', function ( assert ) {
+               this.server.respond( [ 200, { 'Content-Type': 'application/json' },
+                       '{ "query": { "userinfo": { "groups": [ "unused" ], "rights": [ "read", "edit", "createtalk" ] } } }'
+               ] );
 
-               this.server.respondWith( /meta=userinfo/, function ( request ) {
-                       request.respond( 200, { 'Content-Type': 'application/json' },
-                               '{ "query": { "userinfo": { "groups": [ "unused" ], "rights": [ "read", "edit", "createtalk" ] } } }'
-                       );
+               return mw.user.getRights().then( function ( rights ) {
+                       assert.deepEqual( rights, [ 'read', 'edit', 'createtalk' ], 'Result (promise)' );
                } );
-
-               this.server.respond();
        } );
 
        QUnit.test( 'generateRandomSessionId', function ( assert ) {
index 6a704b5..e286dd8 100644 (file)
 /* global isCompatible: true */
 ( function () {
-       var testcases = {
-               tested: [
-                       /* Grade A */
+       var featureTestable, blacklisted;
 
-                       // Chrome
-                       'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.205 Safari/534.16',
-                       // Firefox 4+
-                       'Mozilla/5.0 (Windows NT 6.1.1; rv:5.0) Gecko/20100101 Firefox/5.0',
-                       'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0',
-                       'Mozilla/5.0 (Macintosh; I; Intel Mac OS X 11_7_9; de-LI; rv:1.9b4) Gecko/2012010317 Firefox/10.0a4',
-                       'Mozilla/5.0 (X11; Linux i686; rv:10.0) Gecko/20100101 Firefox/10.0',
-                       'Mozilla/5.0 (Windows NT 6.1; rv:12.0) Gecko/20120403211507 Firefox/12.0',
-                       'Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:16.0.1) Gecko/20121011 Firefox/16.0.1',
-                       // Kindle Fire
-                       'Mozilla/5.0 (Linux; U; Android 2.3.4; en-us; Kindle Fire Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Safari/533.1',
-                       // Safari 5.0+
-                       'Mozilla/5.0 (Macintosh; I; Intel Mac OS X 10_6_7; ru-ru) AppleWebKit/534.31+ (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1',
-                       // Opera 15+ (Chromium-based)
-                       'Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36 OPR/15.0.1147.153',
-                       'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.57 Safari/537.36 OPR/16.0.1196.62',
-                       'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36 OPR/23.0.1522.75',
-                       // Internet Explorer 11
-                       'Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko',
-                       // Edge
-                       'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246',
-                       // Edge Mobile
-                       'Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 640 XL LTE) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Mobile Safari/537.36 Edge/12.10166',
-                       // BlackBerry 6+
-                       'Mozilla/5.0 (BlackBerry; U; BlackBerry 9300; en) AppleWebKit/534.8+ (KHTML, like Gecko) Version/6.0.0.570 Mobile Safari/534.8+',
-                       'Mozilla/5.0 (BlackBerry; U; BlackBerry 9900; en) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.1.0.346 Mobile Safari/534.11+',
-                       'Mozilla/5.0 (BB10; Touch) AppleWebKit/537.3+ (KHTML, like Gecko) Version/10.0.9.386 Mobile Safari/537.3+',
-                       // Open WebOS 1.4+ (HP Veer 4G)
-                       'Mozilla/5.0 (webOS/2.1.2; U; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Version/1.0 Safari/532.2 P160UNA/1.0',
-                       // Firefox Mobile
-                       'Mozilla/5.0 (Mobile; rv:14.0) Gecko/14.0 Firefox/14.0',
-                       // iOS
-                       'Mozilla/5.0 (ipod: U;CPU iPhone OS 2_2 like Mac OS X: es_es) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.0 Mobile/3B48b Safari/419.3',
-                       'Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420.1 (KHTML, like Gecko) Version/3.0 Mobile/3B48b Safari/419.3',
-                       // Android
-                       'Mozilla/5.0 (Linux; U; Android 2.1; en-us; Nexus One Build/ERD62) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17',
-                       // UC Mini (speed mode off)
-                       'Mozilla/5.0 (Linux; U; Android 6.0.1; en-US; Nexus_5 Build/MMB29S) AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1 UCBrowser/10.7.6.805 Mobile',
+       // Browsers that pass or fail the feature test and get bucketed
+       // correctly as Grade A and Grade C. This is tested here to make
+       // sure they don't get caught in any bad UX-snif regexes
+       featureTestable = [
+               /* Grade A */
 
-                       /* Grade C */
+               // Chrome
+               'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.205 Safari/534.16',
+               // Firefox 4+
+               'Mozilla/5.0 (Windows NT 6.1.1; rv:5.0) Gecko/20100101 Firefox/5.0',
+               'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0',
+               'Mozilla/5.0 (Macintosh; I; Intel Mac OS X 11_7_9; de-LI; rv:1.9b4) Gecko/2012010317 Firefox/10.0a4',
+               'Mozilla/5.0 (X11; Linux i686; rv:10.0) Gecko/20100101 Firefox/10.0',
+               'Mozilla/5.0 (Windows NT 6.1; rv:12.0) Gecko/20120403211507 Firefox/12.0',
+               'Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:16.0.1) Gecko/20121011 Firefox/16.0.1',
+               // Kindle Fire
+               'Mozilla/5.0 (Linux; U; Android 2.3.4; en-us; Kindle Fire Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Safari/533.1',
+               // Safari 5.0+
+               'Mozilla/5.0 (Macintosh; I; Intel Mac OS X 10_6_7; ru-ru) AppleWebKit/534.31+ (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1',
+               // Opera 15+ (Chromium-based)
+               'Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36 OPR/15.0.1147.153',
+               'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.57 Safari/537.36 OPR/16.0.1196.62',
+               'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36 OPR/23.0.1522.75',
+               // Internet Explorer 11
+               'Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko',
+               // Edge
+               'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246',
+               // Edge Mobile
+               'Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 640 XL LTE) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Mobile Safari/537.36 Edge/12.10166',
+               // BlackBerry 6+
+               'Mozilla/5.0 (BlackBerry; U; BlackBerry 9300; en) AppleWebKit/534.8+ (KHTML, like Gecko) Version/6.0.0.570 Mobile Safari/534.8+',
+               'Mozilla/5.0 (BlackBerry; U; BlackBerry 9900; en) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.1.0.346 Mobile Safari/534.11+',
+               'Mozilla/5.0 (BB10; Touch) AppleWebKit/537.3+ (KHTML, like Gecko) Version/10.0.9.386 Mobile Safari/537.3+',
+               // Open WebOS 1.4+ (HP Veer 4G)
+               'Mozilla/5.0 (webOS/2.1.2; U; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Version/1.0 Safari/532.2 P160UNA/1.0',
+               // Firefox Mobile
+               'Mozilla/5.0 (Mobile; rv:14.0) Gecko/14.0 Firefox/14.0',
+               // iOS
+               'Mozilla/5.0 (ipod: U;CPU iPhone OS 2_2 like Mac OS X: es_es) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.0 Mobile/3B48b Safari/419.3',
+               'Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420.1 (KHTML, like Gecko) Version/3.0 Mobile/3B48b Safari/419.3',
+               // Android
+               'Mozilla/5.0 (Linux; U; Android 2.1; en-us; Nexus One Build/ERD62) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17',
+               // UC Mini (speed mode off)
+               'Mozilla/5.0 (Linux; U; Android 6.0.1; en-US; Nexus_5 Build/MMB29S) AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1 UCBrowser/10.7.6.805 Mobile',
 
-                       // Internet Explorer < 10
-                       'Mozilla/2.0 (compatible; MSIE 3.03; Windows 3.1)',
-                       'Mozilla/4.0 (compatible; MSIE 4.01; Windows 95)',
-                       'Mozilla/4.0 (compatible; MSIE 5.0; Windows 98;)',
-                       'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)',
-                       'Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1)',
-                       'Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 6.0; en-US)',
-                       'Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; Media Center PC 4.0; SLCC1; .NET CLR 3.0.04320)',
-                       'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 7.1; Trident/5.0)',
-                       // Firefox < 4
-                       'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.2) Gecko/20060308 Firefox/1.5.0.2',
-                       'Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.8.1.1) Gecko/20070311 Firefox/2.0.0.1',
-                       'Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3',
-                       // Opera < 15 (Presto-based)
-                       'Mozilla/5.0 (Windows NT 5.0; U) Opera 7.54 [en]',
-                       'Opera/7.54 (Windows NT 5.0; U) [en]',
-                       'Mozilla/5.0 (Windows NT 5.1; U; en) Opera 8.0',
-                       'Opera/8.0 (X11; Linux i686; U; cs)',
-                       'Opera/9.00 (X11; Linux i686; U; de)',
-                       'Opera/9.62 (X11; Linux i686; U; en) Presto/2.1.1',
-                       'Opera/9.80 (Windows NT 6.1; U; en) Presto/2.2.15 Version/10.00',
-                       'Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.8.131 Version/11.10',
-                       'Opera/9.80 (Windows NT 6.1; WOW64; U; pt) Presto/2.10.229 Version/11.62',
-                       'Opera/9.80 (Windows NT 6.1; U; es-ES) Presto/2.9.181 Version/12.00',
-                       'Opera/9.80 (Windows NT 5.1) Presto/2.12.388 Version/12.17',
-                       // BlackBerry < 6
-                       'BlackBerry9300/5.0.0.716 Profile/MIDP-2.1 Configuration/CLDC-1.1 VendorID/133',
-                       'BlackBerry7250/4.0.0 Profile/MIDP-2.0 Configuration/CLDC-1.1',
+               /* Grade C */
 
-                       /* Grade X */
+               // Internet Explorer < 10
+               'Mozilla/2.0 (compatible; MSIE 3.03; Windows 3.1)',
+               'Mozilla/4.0 (compatible; MSIE 4.01; Windows 95)',
+               'Mozilla/4.0 (compatible; MSIE 5.0; Windows 98;)',
+               'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)',
+               'Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1)',
+               'Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 6.0; en-US)',
+               'Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; Media Center PC 4.0; SLCC1; .NET CLR 3.0.04320)',
+               'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 7.1; Trident/5.0)',
+               // Firefox < 4
+               'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.2) Gecko/20060308 Firefox/1.5.0.2',
+               'Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.8.1.1) Gecko/20070311 Firefox/2.0.0.1',
+               'Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3',
+               // Opera < 15 (Presto-based)
+               'Mozilla/5.0 (Windows NT 5.0; U) Opera 7.54 [en]',
+               'Opera/7.54 (Windows NT 5.0; U) [en]',
+               'Mozilla/5.0 (Windows NT 5.1; U; en) Opera 8.0',
+               'Opera/8.0 (X11; Linux i686; U; cs)',
+               'Opera/9.00 (X11; Linux i686; U; de)',
+               'Opera/9.62 (X11; Linux i686; U; en) Presto/2.1.1',
+               'Opera/9.80 (Windows NT 6.1; U; en) Presto/2.2.15 Version/10.00',
+               'Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.8.131 Version/11.10',
+               'Opera/9.80 (Windows NT 6.1; WOW64; U; pt) Presto/2.10.229 Version/11.62',
+               'Opera/9.80 (Windows NT 6.1; U; es-ES) Presto/2.9.181 Version/12.00',
+               'Opera/9.80 (Windows NT 5.1) Presto/2.12.388 Version/12.17',
+               // BlackBerry < 6
+               'BlackBerry9300/5.0.0.716 Profile/MIDP-2.1 Configuration/CLDC-1.1 VendorID/133',
+               'BlackBerry7250/4.0.0 Profile/MIDP-2.0 Configuration/CLDC-1.1',
 
-                       // Gecko
-                       'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.7) Gecko/20060928 (Debian|Debian-1.8.0.7-1) Epiphany/2.14',
-                       'Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.6) Gecko/20070817 IceWeasel/2.0.0.6-g2',
-                       // KHTML
-                       'Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.4 (like Gecko)',
-                       'Mozilla/5.0 (compatible; Konqueror/4.3; Linux) KHTML/4.3.5 (like Gecko)',
-                       // Text browsers
-                       'Links (2.1pre33; Darwin 8.11.0 Power Macintosh; x)',
-                       'Links (6.9; Unix 6.9-astral sparc; 80x25)',
-                       'Lynx/2.8.6rel.4 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.8g',
-                       'w3m/0.5.1',
-                       // Bots
-                       'Googlebot/2.1 (+http://www.google.com/bot.html)',
-                       'Mozilla/5.0 (compatible; googlebot/2.1; +http://www.google.com/bot.html)',
-                       'Mozilla/5.0 (compatible; YandexBot/3.0)',
-                       // Scripts
-                       'curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5',
-                       'Wget/1.9',
-                       'Wget/1.10.1 (Red Hat modified)',
-                       // Unknown
-                       'I\'m an unknown browser',
-                       'I\'m an unknown Glass browser',
-                       // Empty
-                       ''
-               ],
-               blacklisted: [
-                       /* Grade C */
+               /* Grade X */
 
-                       // Internet Explorer 10
-                       'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)',
-                       // IE Mobile 10
-                       'Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; HTC; Windows Phone 8X by HTC)',
-                       // PlayStation
-                       'Mozilla/5.0 (PLAYSTATION 3; 1.10)',
-                       'Mozilla/5.0 (PLAYSTATION 3; 3.55)',
-                       'Mozilla/5.0 (PLAYSTATION 3 4.21) AppleWebKit/531.22.8 (KHTML, like Gecko)',
-                       'Mozilla/5.0 (PlayStation 4 1.70) AppleWebKit/536.26 (KHTML, like Gecko)',
-                       // Open WebOS < 1.5 (Palm Pre, Palm Pixi)
-                       'Mozilla/5.0 (webOS/1.0; U; en-US) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/1.0 Safari/525.27.1 Pre/1.0',
-                       'Mozilla/5.0 (webOS/1.4.0; U; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Version/1.0 Safari/532.2 Pixi/1.1 ',
-                       // SymbianOS
-                       'NokiaN95_8GB-3;Mozilla/5.0 SymbianOS/9.2;U;Series60/3.1 NokiaN95_8GB-3/11.2.011 Profile/MIDP-2.0 Configuration/CLDC-1.1 AppleWebKit/413 (KHTML, like Gecko)',
-                       'Nokia7610/2.0 (5.0509.0) SymbianOS/7.0s Series60/2.1 Profile/MIDP-2.0 Configuration/CLDC-1.0 ',
-                       'Mozilla/5.0 (SymbianOS/9.1; U; [en]; SymbianOS/91 Series60/3.0) AppleWebKit/413 (KHTML, like Gecko) Safari/413',
-                       'Mozilla/5.0 (SymbianOS/9.3; Series60/3.2 NokiaE52-2/091.003; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.3.1.34 Mobile Safari/533.4',
-                       // NetFront
-                       'Mozilla/4.0 (compatible; Linux 2.6.10) NetFront/3.3 Kindle/1.0 (screen 600x800)',
-                       'Mozilla/4.0 (compatible; Linux 2.6.22) NetFront/3.4 Kindle/2.0 (screen 824x1200; rotate)',
-                       'Mozilla/4.08 (Windows; Mobile Content Viewer/1.0) NetFront/3.2',
-                       // Opera Mini
-                       'Opera/9.80 (J2ME/MIDP; Opera Mini/3.1.10423/22.387; U; en) Presto/2.5.25 Version/10.54',
-                       'Opera/9.50 (J2ME/MIDP; Opera Mini/4.0.10031/298; U; en)',
-                       'Opera/9.80 (J2ME/MIDP; Opera Mini/6.24093/26.1305; U; en) Presto/2.8.119 Version/10.54',
-                       'Opera/9.80 (Android; Opera Mini/7.29530/27.1407; U; en) Presto/2.8.119 Version/11.10',
-                       // Ovi Browser
-                       'Mozilla/5.0 (Series40; NokiaX3-02/05.60; Profile/MIDP-2.1 Configuration/CLDC-1.1) Gecko/20100401 S40OviBrowser/3.2.0.0.6',
-                       'Mozilla/5.0 (Series40; Nokia305/05.92; Profile/MIDP-2.1 Configuration/CLDC-1.1) Gecko/20100401 S40OviBrowser/3.7.0.0.11',
-                       // Google Glass
-                       'Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; Glass 1 Build/IMM76L; XE11) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30',
-                       // MeeGo
-                       'Mozilla/5.0 (MeeGo; NokiaN9) AppleWebKit/534.13 (KHTML, like Gecko) NokiaBrowser/8.5.0 Mobile Safari/534.13',
-                       // UC Mini (speed mode on)
-                       'Mozilla/5.0 (X11; U; Linux i686; zh-CN; r:1.2.3.4) Gecko/',
-                       // Google Web Light proxy
-                       'Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 5 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko; googleweblight) Chrome/38.0.1025.166 Mobile Safari/535.19'
-               ]
-       };
+               // Gecko
+               'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.7) Gecko/20060928 (Debian|Debian-1.8.0.7-1) Epiphany/2.14',
+               'Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.6) Gecko/20070817 IceWeasel/2.0.0.6-g2',
+               // KHTML
+               'Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.4 (like Gecko)',
+               'Mozilla/5.0 (compatible; Konqueror/4.3; Linux) KHTML/4.3.5 (like Gecko)',
+               // Text browsers
+               'Links (2.1pre33; Darwin 8.11.0 Power Macintosh; x)',
+               'Links (6.9; Unix 6.9-astral sparc; 80x25)',
+               'Lynx/2.8.6rel.4 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.8g',
+               'w3m/0.5.1',
+               // Bots
+               'Googlebot/2.1 (+http://www.google.com/bot.html)',
+               'Mozilla/5.0 (compatible; googlebot/2.1; +http://www.google.com/bot.html)',
+               'Mozilla/5.0 (compatible; YandexBot/3.0)',
+               // Scripts
+               'curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5',
+               'Wget/1.9',
+               'Wget/1.10.1 (Red Hat modified)',
+               // Unknown
+               'I\'m an unknown browser',
+               'I\'m an unknown Glass browser',
+               // Empty
+               ''
+       ];
+
+       // Browsers that pass the feature test but for which we chose to serve
+       // a Grade C experience instead. E.g. they have implementation bugs
+       // for which support would be more expensive than deem worthwhile.
+       blacklisted = [
+               /* Grade C */
+
+               // Internet Explorer 10
+               'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)',
+               // IE Mobile 10
+               'Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; HTC; Windows Phone 8X by HTC)',
+               // Open WebOS < 1.5 (Palm Pre, Palm Pixi)
+               'Mozilla/5.0 (webOS/1.0; U; en-US) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/1.0 Safari/525.27.1 Pre/1.0',
+               'Mozilla/5.0 (webOS/1.4.0; U; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Version/1.0 Safari/532.2 Pixi/1.1 ',
+               // SymbianOS
+               'NokiaN95_8GB-3;Mozilla/5.0 SymbianOS/9.2;U;Series60/3.1 NokiaN95_8GB-3/11.2.011 Profile/MIDP-2.0 Configuration/CLDC-1.1 AppleWebKit/413 (KHTML, like Gecko)',
+               'Nokia7610/2.0 (5.0509.0) SymbianOS/7.0s Series60/2.1 Profile/MIDP-2.0 Configuration/CLDC-1.0 ',
+               'Mozilla/5.0 (SymbianOS/9.1; U; [en]; SymbianOS/91 Series60/3.0) AppleWebKit/413 (KHTML, like Gecko) Safari/413',
+               'Mozilla/5.0 (SymbianOS/9.3; Series60/3.2 NokiaE52-2/091.003; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.3.1.34 Mobile Safari/533.4',
+               // NetFront
+               'Mozilla/4.0 (compatible; Linux 2.6.10) NetFront/3.3 Kindle/1.0 (screen 600x800)',
+               'Mozilla/4.0 (compatible; Linux 2.6.22) NetFront/3.4 Kindle/2.0 (screen 824x1200; rotate)',
+               'Mozilla/4.08 (Windows; Mobile Content Viewer/1.0) NetFront/3.2',
+               // Opera Mini
+               'Opera/9.80 (J2ME/MIDP; Opera Mini/3.1.10423/22.387; U; en) Presto/2.5.25 Version/10.54',
+               'Opera/9.50 (J2ME/MIDP; Opera Mini/4.0.10031/298; U; en)',
+               'Opera/9.80 (J2ME/MIDP; Opera Mini/6.24093/26.1305; U; en) Presto/2.8.119 Version/10.54',
+               'Opera/9.80 (Android; Opera Mini/7.29530/27.1407; U; en) Presto/2.8.119 Version/11.10',
+               // Ovi Browser
+               'Mozilla/5.0 (Series40; NokiaX3-02/05.60; Profile/MIDP-2.1 Configuration/CLDC-1.1) Gecko/20100401 S40OviBrowser/3.2.0.0.6',
+               'Mozilla/5.0 (Series40; Nokia305/05.92; Profile/MIDP-2.1 Configuration/CLDC-1.1) Gecko/20100401 S40OviBrowser/3.7.0.0.11',
+               // Google Glass
+               'Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; Glass 1 Build/IMM76L; XE11) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30',
+               // MeeGo
+               'Mozilla/5.0 (MeeGo; NokiaN9) AppleWebKit/534.13 (KHTML, like Gecko) NokiaBrowser/8.5.0 Mobile Safari/534.13',
+               // UC Mini (speed mode on)
+               'Mozilla/5.0 (X11; U; Linux i686; zh-CN; r:1.2.3.4) Gecko/',
+               // Google Web Light proxy
+               'Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 5 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko; googleweblight) Chrome/38.0.1025.166 Mobile Safari/535.19',
+               // PlayStation
+               'Mozilla/5.0 (PLAYSTATION 3; 1.10)',
+               'Mozilla/5.0 (PLAYSTATION 3; 3.55)',
+               'Mozilla/5.0 (PLAYSTATION 3 4.21) AppleWebKit/531.22.8 (KHTML, like Gecko)',
+               'Mozilla/5.0 (PlayStation 4 1.70) AppleWebKit/536.26 (KHTML, like Gecko)'
+       ];
 
        QUnit.module( 'startup', QUnit.newMwEnvironment() );
 
        QUnit.test( 'isCompatible( featureTestable )', function ( assert ) {
-               testcases.tested.forEach( function ( ua ) {
+               featureTestable.forEach( function ( ua ) {
                        assert.strictEqual( isCompatible( ua ), true, ua );
                } );
        } );
 
        QUnit.test( 'isCompatible( blacklisted )', function ( assert ) {
-               testcases.blacklisted.forEach( function ( ua ) {
+               blacklisted.forEach( function ( ua ) {
                        assert.strictEqual( isCompatible( ua ), false, ua );
                } );
        } );
index 38cd062..dd766c8 100644 (file)
@@ -7,7 +7,8 @@
                "mocha": true
        },
        "globals": {
-               "browser": false
+               "browser": false,
+               "mw": false
        },
        "rules": {
                "no-console": 0
index acaf3ea..52d614f 100644 (file)
@@ -1,11 +1,54 @@
-const Page = require( 'wdio-mediawiki/Page' );
+const Page = require( 'wdio-mediawiki/Page' ),
+       Api = require( 'wdio-mediawiki/Api' ),
+       Util = require( 'wdio-mediawiki/Util' );
 
 class HistoryPage extends Page {
+       get heading() { return browser.element( '#firstHeading' ); }
+       get headingText() { return browser.getText( '#firstHeading' ); }
        get comment() { return browser.element( '#pagehistory .comment' ); }
+       get rollback() { return browser.element( '.mw-rollback-link' ); }
+       get rollbackLink() { return browser.element( '.mw-rollback-link a' ); }
+       get rollbackConfirmable() { return browser.element( '.mw-rollback-link .jquery-confirmable-text' ); }
+       get rollbackConfirmableYes() { return browser.element( '.mw-rollback-link .jquery-confirmable-button-yes' ); }
+       get rollbackConfirmableNo() { return browser.element( '.mw-rollback-link .jquery-confirmable-button-no' ); }
+       get rollbackNonJsConfirmable() { return browser.element( '.mw-htmlform .oo-ui-fieldsetLayout-header .oo-ui-labelElement-label' ); }
+       get rollbackNonJsConfirmableYes() { return browser.element( '.mw-htmlform .mw-htmlform-submit-buttons button' ); }
 
        open( title ) {
                super.openTitle( title, { action: 'history' } );
        }
+
+       toggleRollbackConfirmationSetting( enable ) {
+               Util.waitForModuleState( 'mediawiki.api', 'ready', 5000 );
+               return browser.execute( function ( enable ) {
+                       return new mw.Api().saveOption(
+                               'showrollbackconfirmation',
+                               enable ? '1' : '0'
+                       );
+               }, enable );
+       }
+
+       vandalizePage( name, content ) {
+               let vandalUsername = 'Evil_' + browser.options.username;
+
+               browser.call( function () {
+                       return Api.edit( name, content );
+               } );
+
+               browser.call( function () {
+                       return Api.createAccount(
+                               vandalUsername, browser.options.password
+                       );
+               } );
+
+               browser.call( function () {
+                       return Api.edit(
+                               name,
+                               'Vandalized: ' + content,
+                               vandalUsername
+                       );
+               } );
+       }
 }
 
 module.exports = new HistoryPage();
index 3b24298..93e0b87 100644 (file)
@@ -5,7 +5,7 @@ const assert = require( 'assert' ),
        EditPage = require( '../pageobjects/edit.page' ),
        HistoryPage = require( '../pageobjects/history.page' ),
        UndoPage = require( '../pageobjects/undo.page' ),
-       UserLoginPage = require( '../pageobjects/userlogin.page' ),
+       UserLoginPage = require( 'wdio-mediawiki/LoginPage' ),
        Util = require( 'wdio-mediawiki/Util' );
 
 describe( 'Page', function () {
@@ -80,7 +80,8 @@ describe( 'Page', function () {
 
                // check
                assert.strictEqual( EditPage.heading.getText(), name );
-               assert.strictEqual( EditPage.displayedContent.getText(), editContent );
+               // eslint-disable-next-line no-restricted-syntax
+               assert( EditPage.displayedContent.getText().includes( editContent ) );
        } );
 
        it( 'should have history @daily', function () {
@@ -91,7 +92,7 @@ describe( 'Page', function () {
 
                // check
                HistoryPage.open( name );
-               assert.strictEqual( HistoryPage.comment.getText(), `(Created page with "${content}")` );
+               assert.strictEqual( HistoryPage.comment.getText(), `Created or updated page with "${content}"` );
        } );
 
        it( 'should be deletable', function () {
diff --git a/tests/selenium/specs/rollback.js b/tests/selenium/specs/rollback.js
new file mode 100644 (file)
index 0000000..2a79467
--- /dev/null
@@ -0,0 +1,131 @@
+const assert = require( 'assert' ),
+       HistoryPage = require( '../pageobjects/history.page' ),
+       UserLoginPage = require( 'wdio-mediawiki/LoginPage' ),
+       Util = require( 'wdio-mediawiki/Util' );
+
+describe( 'Rollback with confirmation', function () {
+       var content,
+               name;
+
+       before( function () {
+               // disable VisualEditor welcome dialog
+               browser.deleteCookie();
+               UserLoginPage.open();
+               browser.localStorage( 'POST', { key: 've-beta-welcome-dialog', value: '1' } );
+
+               // Enable rollback confirmation for admin user
+               // Requires user to log in again, handled by deleteCookie() call in beforeEach function
+               UserLoginPage.loginAdmin();
+               HistoryPage.toggleRollbackConfirmationSetting( true );
+       } );
+
+       beforeEach( function () {
+               browser.deleteCookie();
+
+               content = Util.getTestString( 'beforeEach-content-' );
+               name = Util.getTestString( 'BeforeEach-name-' );
+
+               HistoryPage.vandalizePage( name, content );
+
+               UserLoginPage.loginAdmin();
+               HistoryPage.open( name );
+       } );
+
+       it( 'should offer rollback options for admin users', function () {
+               assert.strictEqual( HistoryPage.rollback.getText(), 'rollback 1 edit' );
+
+               HistoryPage.rollback.click();
+
+               assert.strictEqual( HistoryPage.rollbackConfirmable.getText(), 'Please confirm:' );
+               assert.strictEqual( HistoryPage.rollbackConfirmableYes.getText(), 'Rollback' );
+               assert.strictEqual( HistoryPage.rollbackConfirmableNo.getText(), 'Cancel' );
+       } );
+
+       it( 'should offer a way to cancel rollbacks', function () {
+               HistoryPage.rollback.click();
+
+               HistoryPage.rollbackConfirmableNo.waitForVisible( 5000 );
+
+               HistoryPage.rollbackConfirmableNo.click();
+
+               browser.pause( 1000 ); // Waiting to ensure we are NOT redirected and stay on the same page
+
+               assert.strictEqual( HistoryPage.heading.getText(), 'Revision history of "' + name + '"' );
+       } );
+
+       it.skip( 'should perform rollbacks after confirming intention', function () {
+               HistoryPage.rollback.click();
+
+               HistoryPage.rollbackConfirmableYes.waitForVisible( 5000 );
+
+               HistoryPage.rollbackConfirmableYes.click();
+
+               // waitUntil indirectly asserts that the content we are looking for is present
+               browser.waitUntil( function () {
+                       return browser.getText( '#firstHeading' ) === 'Action complete';
+               }, 5000, 'Expected rollback page to appear.' );
+       } );
+
+       it( 'should verify rollbacks via GET requests are confirmed on a follow-up page', function () {
+               var rollbackActionUrl = HistoryPage.rollbackLink.getAttribute( 'href' );
+               browser.url( rollbackActionUrl );
+
+               browser.waitUntil( function () {
+                       return HistoryPage.rollbackNonJsConfirmable.getText() === 'Revert edits to this page?';
+               }, 5000, 'Expected rollback confirmation page to appear for GET-based rollbacks.' );
+
+               HistoryPage.rollbackNonJsConfirmableYes.click();
+
+               browser.waitUntil( function () {
+                       return browser.getText( '#firstHeading' ) === 'Action complete';
+               }, 5000, 'Expected rollback page to appear.' );
+       } );
+
+} );
+
+describe( 'Rollback without confirmation', function () {
+       var content,
+               name;
+
+       before( function () {
+               // disable VisualEditor welcome dialog
+               browser.deleteCookie();
+               UserLoginPage.open();
+               browser.localStorage( 'POST', { key: 've-beta-welcome-dialog', value: '1' } );
+
+               // Disable rollback confirmation for admin user
+               // Requires user to log in again, handled by deleteCookie() call in beforeEach function
+               UserLoginPage.loginAdmin();
+               HistoryPage.toggleRollbackConfirmationSetting( false );
+       } );
+
+       beforeEach( function () {
+               browser.deleteCookie();
+
+               content = Util.getTestString( 'beforeEach-content-' );
+               name = Util.getTestString( 'BeforeEach-name-' );
+
+               HistoryPage.vandalizePage( name, content );
+
+               UserLoginPage.loginAdmin();
+               HistoryPage.open( name );
+       } );
+
+       it( 'should perform rollback via POST request without asking the user to confirm', function () {
+               HistoryPage.rollback.click();
+
+               // waitUntil indirectly asserts that the content we are looking for is present
+               browser.waitUntil( function () {
+                       return HistoryPage.headingText === 'Action complete';
+               }, 5000, 'Expected rollback page to appear.' );
+       } );
+
+       it( 'should perform rollback via GET request without asking the user to confirm', function () {
+               var rollbackActionUrl = HistoryPage.rollbackLink.getAttribute( 'href' );
+               browser.url( rollbackActionUrl );
+
+               browser.waitUntil( function () {
+                       return browser.getText( '#firstHeading' ) === 'Action complete';
+               }, 5000, 'Expected rollback page to appear.' );
+       } );
+} );
index f68fee9..7947ff5 100644 (file)
@@ -5,22 +5,31 @@ const MWBot = require( 'mwbot' );
 module.exports = {
        /**
         * Shortcut for `MWBot#edit( .. )`.
+        * Default username, password and base URL is used unless specified
         *
         * @since 1.0.0
         * @see <https://www.mediawiki.org/wiki/API:Edit>
         * @param {string} title
         * @param {string} content
+        * @param {string} username - Optional
+        * @param {string} password - Optional
+        * @param {baseUrl} baseUrl - Optional
         * @return {Object} Promise for API action=edit response data.
         */
-       edit( title, content ) {
+       edit( title,
+               content,
+               username = browser.options.username,
+               password = browser.options.password,
+               baseUrl = browser.options.baseUrl
+       ) {
                let bot = new MWBot();
 
                return bot.loginGetEditToken( {
-                       apiUrl: `${browser.options.baseUrl}/api.php`,
-                       username: browser.options.username,
-                       password: browser.options.password
+                       apiUrl: `${baseUrl}/api.php`,
+                       username: username,
+                       password: password
                } ).then( function () {
-                       return bot.edit( title, content, `Created page with "${content}"` );
+                       return bot.edit( title, content, `Created or updated page with "${content}"` );
                } );
        },
 
index 247c958..dd08ee9 100644 (file)
@@ -1,5 +1,21 @@
 module.exports = {
        getTestString( prefix = '' ) {
                return prefix + Math.random().toString() + '-Iñtërnâtiônàlizætiøn';
+       },
+
+       /**
+        * Wait for a given module to reach a specific state
+        * @param {string} moduleName The name of the module to wait for
+        * @param {string} moduleStatus 'registered', 'loaded', 'loading', 'ready', 'error', 'missing'
+        * @param {int} timeout The wait time in milliseconds before the wait fails
+        */
+       waitForModuleState( moduleName, moduleStatus = 'ready', timeout = 2000 ) {
+               browser.waitUntil( () => {
+                       const result = browser.execute( ( module ) => {
+                               return typeof mw !== 'undefined' &&
+                                       mw.loader.getState( module.name ) === module.status;
+                       }, { status: moduleStatus, name: moduleName } );
+                       return result.value;
+               }, timeout, 'Failed to wait for ' + moduleName + ' to be ' + moduleStatus + ' after ' + timeout + ' ms.' );
        }
 };
index bdabdbf..56e4934 100644 (file)
@@ -52,6 +52,7 @@ exports.config = {
 
        // ==================
        // Test Files
+       // FIXME: The non-core patterns to be removed once T199116 is fixed.
        // ==================
        specs: [
                relPath( './tests/selenium/wdio-mediawiki/specs/*.js' ),
@@ -63,7 +64,11 @@ exports.config = {
        ],
        // Patterns to exclude
        exclude: [
-               relPath( './extensions/CirrusSearch/tests/selenium/specs/**/*.js' )
+               relPath( './extensions/CirrusSearch/tests/selenium/specs/**/*.js' ),
+               // Disabled because these tests modify LocalSettings.php, see T199116 for the long-term fix.
+               relPath( './extensions/FileImporter/tests/selenium/specs/**/*.js' ),
+               // Disabled per T222517
+               relPath( './skins/MinervaNeue/tests/selenium/specs/**/*.js' )
        ],
 
        // ============